matrix-react-sdk
Version:
SDK for matrix.org using React
245 lines (189 loc) • 29.3 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _AccessibleTooltipButton = _interopRequireDefault(require("../elements/AccessibleTooltipButton"));
var _languageHandler = require("../../../languageHandler");
var _react = _interopRequireDefault(require("react"));
var _VoiceRecording = require("../../../voice/VoiceRecording");
var _MatrixClientPeg = require("../../../MatrixClientPeg");
var _classnames = _interopRequireDefault(require("classnames"));
var _LiveRecordingWaveform = _interopRequireDefault(require("../voice_messages/LiveRecordingWaveform"));
var _replaceableComponent = require("../../../utils/replaceableComponent");
var _LiveRecordingClock = _interopRequireDefault(require("../voice_messages/LiveRecordingClock"));
var _VoiceRecordingStore = require("../../../stores/VoiceRecordingStore");
var _AsyncStore = require("../../../stores/AsyncStore");
var _RecordingPlayback = _interopRequireDefault(require("../voice_messages/RecordingPlayback"));
var _event = require("matrix-js-sdk/src/@types/event");
var _Modal = _interopRequireDefault(require("../../../Modal"));
var _ErrorDialog = _interopRequireDefault(require("../dialogs/ErrorDialog"));
var _CallMediaHandler = _interopRequireDefault(require("../../../CallMediaHandler"));
var _dec, _class, _temp;
let VoiceRecordComposerTile = (
/**
* Container tile for rendering the voice message recorder in the composer.
*/
_dec = (0, _replaceableComponent.replaceableComponent)("views.rooms.VoiceRecordComposerTile"), _dec(_class = (_temp = class VoiceRecordComposerTile extends _react.default.PureComponent
/*:: <IProps, IState>*/
{
constructor(props) {
super(props);
(0, _defineProperty2.default)(this, "onCancel", async () => {
await this.disposeRecording();
});
(0, _defineProperty2.default)(this, "onRecordStartEndClick", async () => {
if (this.state.recorder) {
await this.state.recorder.stop();
return;
} // The "microphone access error" dialogs are used a lot, so let's functionify them
const accessError = () => {
_Modal.default.createTrackedDialog('Microphone Access Error', '', _ErrorDialog.default, {
title: (0, _languageHandler._t)("Unable to access your microphone"),
description: /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement("p", null, (0, _languageHandler._t)("We were unable to access your microphone. Please check your browser settings and try again.")))
});
}; // Do a sanity test to ensure we're about to grab a valid microphone reference. Things might
// change between this and recording, but at least we will have tried.
try {
const devices = await _CallMediaHandler.default.getDevices();
if (!devices?.['audioinput']?.length) {
_Modal.default.createTrackedDialog('No Microphone Error', '', _ErrorDialog.default, {
title: (0, _languageHandler._t)("No microphone found"),
description: /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement("p", null, (0, _languageHandler._t)("We didn't find a microphone on your device. Please check your settings and try again.")))
});
return;
} // else we probably have a device that is good enough
} catch (e) {
console.error("Error getting devices: ", e);
accessError();
return;
}
try {
const recorder = _VoiceRecordingStore.VoiceRecordingStore.instance.startRecording();
await recorder.start(); // We don't need to remove the listener: the recorder will clean that up for us.
recorder.on(_AsyncStore.UPDATE_EVENT, (ev
/*: RecordingState*/
) => {
if (ev === _VoiceRecording.RecordingState.EndingSoon) return; // ignore this state: it has no UI purpose here
this.setState({
recordingPhase: ev
});
});
this.setState({
recorder,
recordingPhase: _VoiceRecording.RecordingState.Started
});
} catch (e) {
console.error("Error starting recording: ", e);
accessError(); // noinspection ES6MissingAwait - if this goes wrong we don't want it to affect the call stack
_VoiceRecordingStore.VoiceRecordingStore.instance.disposeRecording();
}
});
this.state = {
recorder: null // no recording started by default
};
}
async componentWillUnmount() {
await _VoiceRecordingStore.VoiceRecordingStore.instance.disposeRecording();
} // called by composer
async send() {
if (!this.state.recorder) {
throw new Error("No recording started - cannot send anything");
}
await this.state.recorder.stop();
const mxc = await this.state.recorder.upload();
_MatrixClientPeg.MatrixClientPeg.get().sendMessage(this.props.room.roomId, {
"body": "Voice message",
//"msgtype": "org.matrix.msc2516.voice",
"msgtype": _event.MsgType.Audio,
"url": mxc,
"info": {
duration: Math.round(this.state.recorder.durationSeconds * 1000),
mimetype: this.state.recorder.contentType,
size: this.state.recorder.contentLength
},
// MSC1767 experiment
"org.matrix.msc1767.text": "Voice message",
"org.matrix.msc1767.file": {
url: mxc,
name: "Voice message.ogg",
mimetype: this.state.recorder.contentType,
size: this.state.recorder.contentLength
},
"org.matrix.msc1767.audio": {
duration: Math.round(this.state.recorder.durationSeconds * 1000),
// Events can't have floats, so we try to maintain resolution by using 1024
// as a maximum value. The waveform contains values between zero and 1, so this
// should come out largely sane.
//
// We're expecting about one data point per second of audio.
waveform: this.state.recorder.getPlayback().waveform.map(v => Math.round(v * 1024))
},
"org.matrix.msc2516.voice": {} // No content, this is a rendering hint
});
await this.disposeRecording();
}
async disposeRecording() {
await _VoiceRecordingStore.VoiceRecordingStore.instance.disposeRecording(); // Reset back to no recording, which means no phase (ie: restart component entirely)
this.setState({
recorder: null,
recordingPhase: null
});
}
renderWaveformArea()
/*: ReactNode*/
{
if (!this.state.recorder) return null; // no recorder means we're not recording: no waveform
if (this.state.recordingPhase !== _VoiceRecording.RecordingState.Started) {
// TODO: @@ TR: Should we disable this during upload? What does a failed upload look like?
return /*#__PURE__*/_react.default.createElement(_RecordingPlayback.default, {
playback: this.state.recorder.getPlayback()
});
} // only other UI is the recording-in-progress UI
return /*#__PURE__*/_react.default.createElement("div", {
className: "mx_VoiceMessagePrimaryContainer mx_VoiceRecordComposerTile_recording"
}, /*#__PURE__*/_react.default.createElement(_LiveRecordingClock.default, {
recorder: this.state.recorder
}), /*#__PURE__*/_react.default.createElement(_LiveRecordingWaveform.default, {
recorder: this.state.recorder
}));
}
render()
/*: ReactNode*/
{
let recordingInfo;
let deleteButton;
if (!this.state.recordingPhase || this.state.recordingPhase === _VoiceRecording.RecordingState.Started) {
const classes = (0, _classnames.default)({
'mx_MessageComposer_button': !this.state.recorder,
'mx_MessageComposer_voiceMessage': !this.state.recorder,
'mx_VoiceRecordComposerTile_stop': this.state.recorder?.isRecording
});
let tooltip = (0, _languageHandler._t)("Record a voice message");
if (!!this.state.recorder) {
tooltip = (0, _languageHandler._t)("Stop the recording");
}
let stopOrRecordBtn = /*#__PURE__*/_react.default.createElement(_AccessibleTooltipButton.default, {
className: classes,
onClick: this.onRecordStartEndClick,
title: tooltip
});
if (this.state.recorder && !this.state.recorder?.isRecording) {
stopOrRecordBtn = null;
}
recordingInfo = stopOrRecordBtn;
}
if (this.state.recorder && this.state.recordingPhase !== _VoiceRecording.RecordingState.Uploading) {
deleteButton = /*#__PURE__*/_react.default.createElement(_AccessibleTooltipButton.default, {
className: "mx_VoiceRecordComposerTile_delete",
title: (0, _languageHandler._t)("Delete recording"),
onClick: this.onCancel
});
}
return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, deleteButton, this.renderWaveformArea(), recordingInfo);
}
}, _temp)) || _class);
exports.default = VoiceRecordComposerTile;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9jb21wb25lbnRzL3ZpZXdzL3Jvb21zL1ZvaWNlUmVjb3JkQ29tcG9zZXJUaWxlLnRzeCJdLCJuYW1lcyI6WyJWb2ljZVJlY29yZENvbXBvc2VyVGlsZSIsIlJlYWN0IiwiUHVyZUNvbXBvbmVudCIsImNvbnN0cnVjdG9yIiwicHJvcHMiLCJkaXNwb3NlUmVjb3JkaW5nIiwic3RhdGUiLCJyZWNvcmRlciIsInN0b3AiLCJhY2Nlc3NFcnJvciIsIk1vZGFsIiwiY3JlYXRlVHJhY2tlZERpYWxvZyIsIkVycm9yRGlhbG9nIiwidGl0bGUiLCJkZXNjcmlwdGlvbiIsImRldmljZXMiLCJDYWxsTWVkaWFIYW5kbGVyIiwiZ2V0RGV2aWNlcyIsImxlbmd0aCIsImUiLCJjb25zb2xlIiwiZXJyb3IiLCJWb2ljZVJlY29yZGluZ1N0b3JlIiwiaW5zdGFuY2UiLCJzdGFydFJlY29yZGluZyIsInN0YXJ0Iiwib24iLCJVUERBVEVfRVZFTlQiLCJldiIsIlJlY29yZGluZ1N0YXRlIiwiRW5kaW5nU29vbiIsInNldFN0YXRlIiwicmVjb3JkaW5nUGhhc2UiLCJTdGFydGVkIiwiY29tcG9uZW50V2lsbFVubW91bnQiLCJzZW5kIiwiRXJyb3IiLCJteGMiLCJ1cGxvYWQiLCJNYXRyaXhDbGllbnRQZWciLCJnZXQiLCJzZW5kTWVzc2FnZSIsInJvb20iLCJyb29tSWQiLCJNc2dUeXBlIiwiQXVkaW8iLCJkdXJhdGlvbiIsIk1hdGgiLCJyb3VuZCIsImR1cmF0aW9uU2Vjb25kcyIsIm1pbWV0eXBlIiwiY29udGVudFR5cGUiLCJzaXplIiwiY29udGVudExlbmd0aCIsInVybCIsIm5hbWUiLCJ3YXZlZm9ybSIsImdldFBsYXliYWNrIiwibWFwIiwidiIsInJlbmRlcldhdmVmb3JtQXJlYSIsInJlbmRlciIsInJlY29yZGluZ0luZm8iLCJkZWxldGVCdXR0b24iLCJjbGFzc2VzIiwiaXNSZWNvcmRpbmciLCJ0b29sdGlwIiwic3RvcE9yUmVjb3JkQnRu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RCxLQUFMLENBQVcwQixjQUFYLEtBQThCSCwrQkFBZXdDLFNBQXhFLEVBQW1GO0FBQy9FTixNQUFBQSxZQUFZLGdCQUFHLDZCQUFDLGdDQUFEO0FBQ1gsUUFBQSxTQUFTLEVBQUMsbUNBREM7QUFFWCxRQUFBLEtBQUssRUFBRSx5QkFBRyxrQkFBSCxDQUZJO0FBR1gsUUFBQSxPQUFPLEVBQUUsS0FBS087QUFISCxRQUFmO0FBS0g7O0FBRUQsd0JBQVEsNERBQ0hQLFlBREcsRUFFSCxLQUFLSCxrQkFBTCxFQUZHLEVBR0hFLGFBSEcsQ0FBUjtBQUtIOztBQXJMb0YsQyIsInNvdXJjZXNDb250ZW50IjpbIi8qXG5Db3B5cmlnaHQgMjAyMSBUaGUgTWF0cml4Lm9yZyBGb3VuZGF0aW9uIEMuSS5DLlxuXG5MaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgXCJMaWNlbnNlXCIpO1xueW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLlxuWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0XG5cbiAgICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjBcblxuVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZVxuZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gXCJBUyBJU1wiIEJBU0lTLFxuV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuXG5TZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kXG5saW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS5cbiovXG5cbmltcG9ydCBBY2Nlc3NpYmxlVG9vbHRpcEJ1dHRvbiBmcm9tIFwiLi4vZWxlbWVudHMvQWNjZXNzaWJsZVRvb2x0aXBCdXR0b25cIjtcbmltcG9ydCB7X3R9IGZyb20gXCIuLi8uLi8uLi9sYW5ndWFnZUhhbmRsZXJcIjtcbmltcG9ydCBSZWFjdCwge1JlYWN0Tm9kZX0gZnJvbSBcInJlYWN0XCI7XG5pbXBvcnQge1JlY29yZGluZ1N0YXRlLCBWb2ljZVJlY29yZGluZ30gZnJvbSBcIi4uLy4uLy4uL3ZvaWNlL1ZvaWNlUmVjb3JkaW5nXCI7XG5pbXBvcnQge1Jvb219IGZyb20gXCJtYXRyaXgtanMtc2RrL3NyYy9tb2RlbHMvcm9vbVwiO1xuaW1wb3J0IHtNYXRyaXhDbGllbnRQZWd9IGZyb20gXCIuLi8uLi8uLi9NYXRyaXhDbGllbnRQZWdcIjtcbmltcG9ydCBjbGFzc05hbWVzIGZyb20gXCJjbGFzc25hbWVzXCI7XG5pbXBvcnQgTGl2ZVJlY29yZGluZ1dhdmVmb3JtIGZyb20gXCIuLi92b2ljZV9tZXNzYWdlcy9MaXZlUmVjb3JkaW5nV2F2ZWZvcm1cIjtcbmltcG9ydCB7cmVwbGFjZWFibGVDb21wb25lbnR9IGZyb20gXCIuLi8uLi8uLi91dGlscy9yZXBsYWNlYWJsZUNvbXBvbmVudFwiO1xuaW1wb3J0IExpdmVSZWNvcmRpbmdDbG9jayBmcm9tIFwiLi4vdm9pY2VfbWVzc2FnZXMvTGl2ZVJlY29yZGluZ0Nsb2NrXCI7XG5pbXBvcnQge1ZvaWNlUmVjb3JkaW5nU3RvcmV9IGZyb20gXCIuLi8uLi8uLi9zdG9yZXMvVm9pY2VSZWNvcmRpbmdTdG9yZVwiO1xuaW1wb3J0IHtVUERBVEVfRVZFTlR9IGZyb20gXCIuLi8uLi8uLi9zdG9yZXMvQXN5bmNTdG9yZVwiO1xuaW1wb3J0IFJlY29yZGluZ1BsYXliYWNrIGZyb20gXCIuLi92b2ljZV9tZXNzYWdlcy9SZWNvcmRpbmdQbGF5YmFja1wiO1xuaW1wb3J0IHtNc2dUeXBlfSBmcm9tIFwibWF0cml4LWpzLXNkay9zcmMvQHR5cGVzL2V2ZW50XCI7XG5pbXBvcnQgTW9kYWwgZnJvbSBcIi4uLy4uLy4uL01vZGFsXCI7XG5pbXBvcnQgRXJyb3JEaWFsb2cgZnJvbSBcIi4uL2RpYWxvZ3MvRXJyb3JEaWFsb2dcIjtcbmltcG9ydCBDYWxsTWVkaWFIYW5kbGVyIGZyb20gXCIuLi8uLi8uLi9DYWxsTWVkaWFIYW5kbGVyXCI7XG5cbmludGVyZmFjZSBJUHJvcHMge1xuICAgIHJvb206IFJvb207XG59XG5cbmludGVyZmFjZSBJU3RhdGUge1xuICAgIHJlY29yZGVyPzogVm9pY2VSZWNvcmRpbmc7XG4gICAgcmVjb3JkaW5nUGhhc2U/OiBSZWNvcmRpbmdTdGF0ZTtcbn1cblxuLyoqXG4gKiBDb250YWluZXIgdGlsZSBmb3IgcmVuZGVyaW5nIHRoZSB2b2ljZSBtZXNzYWdlIHJlY29yZGVyIGluIHRoZSBjb21wb3Nlci5cbiAqL1xuQHJlcGxhY2VhYmxlQ29tcG9uZW50KFwidmlld3Mucm9vbXMuVm9pY2VSZWNvcmRDb21wb3NlclRpbGVcIilcbmV4cG9ydCBkZWZhdWx0IGNsYXNzIFZvaWNlUmVjb3JkQ29tcG9zZXJUaWxlIGV4dGVuZHMgUmVhY3QuUHVyZUNvbXBvbmVudDxJUHJvcHMsIElTdGF0ZT4ge1xuICAgIHB1YmxpYyBjb25zdHJ1Y3Rvcihwcm9wcykge1xuICAgICAgICBzdXBlcihwcm9wcyk7XG5cbiAgICAgICAgdGhpcy5zdGF0ZSA9IHtcbiAgICAgICAgICAgIHJlY29yZGVyOiBudWxsLCAvLyBubyByZWNvcmRpbmcgc3RhcnRlZCBieSBkZWZhdWx0XG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIGNvbXBvbmVudFdpbGxVbm1vdW50KCkge1xuICAgICAgICBhd2FpdCBWb2ljZVJlY29yZGluZ1N0b3JlLmluc3RhbmNlLmRpc3Bvc2VSZWNvcmRpbmcoKTtcbiAgICB9XG5cbiAgICAvLyBjYWxsZWQgYnkgY29tcG9zZXJcbiAgICBwdWJsaWMgYXN5bmMgc2VuZCgpIHtcbiAgICAgICAgaWYgKCF0aGlzLnN0YXRlLnJlY29yZGVyKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJObyByZWNvcmRpbmcgc3RhcnRlZCAtIGNhbm5vdCBzZW5kIGFueXRoaW5nXCIpO1xuICAgICAgICB9XG5cbiAgICAgICAgYXdhaXQgdGhpcy5zdGF0ZS5yZWNvcmRlci5zdG9wKCk7XG4gICAgICAgIGNvbnN0IG14YyA9IGF3YWl0IHRoaXMuc3RhdGUucmVjb3JkZXIudXBsb2FkKCk7XG4gICAgICAgIE1hdHJpeENsaWVudFBlZy5nZXQoKS5zZW5kTWVzc2FnZSh0aGlzLnByb3BzLnJvb20ucm9vbUlkLCB7XG4gICAgICAgICAgICBcImJvZHlcIjogXCJWb2ljZSBtZXNzYWdlXCIsXG4gICAgICAgICAgICAvL1wibXNndHlwZVwiOiBcIm9yZy5tYXRyaXgubXNjMjUxNi52b2ljZVwiLFxuICAgICAgICAgICAgXCJtc2d0eXBlXCI6IE1zZ1R5cGUuQXVkaW8sXG4gICAgICAgICAgICBcInVybFwiOiBteGMsXG4gICAgICAgICAgICBcImluZm9cIjoge1xuICAgICAgICAgICAgICAgIGR1cmF0aW9uOiBNYXRoLnJvdW5kKHRoaXMuc3RhdGUucmVjb3JkZXIuZHVyYXRpb25TZWNvbmRzICogMTAwMCksXG4gICAgICAgICAgICAgICAgbWltZXR5cGU6IHRoaXMuc3RhdGUucmVjb3JkZXIuY29udGVudFR5cGUsXG4gICAgICAgICAgICAgICAgc2l6ZTogdGhpcy5zdGF0ZS5yZWNvcmRlci5jb250ZW50TGVuZ3RoLFxuICAgICAgICAgICAgfSxcblxuICAgICAgICAgICAgLy8gTVNDMTc2NyBleHBlcmltZW50XG4gICAgICAgICAgICBcIm9yZy5tYXRyaXgubXNjMTc2Ny50ZXh0XCI6IFwiVm9pY2UgbWVzc2FnZVwiLFxuICAgICAgICAgICAgXCJvcmcubWF0cml4Lm1zYzE3NjcuZmlsZVwiOiB7XG4gICAgICAgICAgICAgICAgdXJsOiBteGMsXG4gICAgICAgICAgICAgICAgbmFtZTogXCJWb2ljZSBtZXNzYWdlLm9nZ1wiLFxuICAgICAgICAgICAgICAgIG1pbWV0eXBlOiB0aGlzLnN0YXRlLnJlY29yZGVyLmNvbnRlbnRUeXBlLFxuICAgICAgICAgICAgICAgIHNpemU6IHRoaXMuc3RhdGUucmVjb3JkZXIuY29udGVudExlbmd0aCxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcIm9yZy5tYXRyaXgubXNjMTc2Ny5hdWRpb1wiOiB7XG4gICAgICAgICAgICAgICAgZHVyYXRpb246IE1hdGgucm91bmQodGhpcy5zdGF0ZS5yZWNvcmRlci5kdXJhdGlvblNlY29uZHMgKiAxMDAwKSxcblxuICAgICAgICAgICAgICAgIC8vIEV2ZW50cyBjYW4ndCBoYXZlIGZsb2F0cywgc28gd2UgdHJ5IHRvIG1haW50YWluIHJlc29sdXRpb24gYnkgdXNpbmcgMTAyNFxuICAgICAgICAgICAgICAgIC8vIGFzIGEgbWF4aW11bSB2YWx1ZS4gVGhlIHdhdmVmb3JtIGNvbnRhaW5zIHZhbHVlcyBiZXR3ZWVuIHplcm8gYW5kIDEsIHNvIHRoaXNcbiAgICAgICAgICAgICAgICAvLyBzaG91bGQgY29tZSBvdXQgbGFyZ2VseSBzYW5lLlxuICAgICAgICAgICAgICAgIC8vXG4gICAgICAgICAgICAgICAgLy8gV2UncmUgZXhwZWN0aW5nIGFib3V0IG9uZSBkYXRhIHBvaW50IHBlciBzZWNvbmQgb2YgYXVkaW8uXG4gICAgICAgICAgICAgICAgd2F2ZWZvcm06IHRoaXMuc3RhdGUucmVjb3JkZXIuZ2V0UGxheWJhY2soKS53YXZlZm9ybS5tYXAodiA9PiBNYXRoLnJvdW5kKHYgKiAxMDI0KSksXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJvcmcubWF0cml4Lm1zYzI1MTYudm9pY2VcIjoge30sIC8vIE5vIGNvbnRlbnQsIHRoaXMgaXMgYSByZW5kZXJpbmcgaGludFxuICAgICAgICB9KTtcbiAgICAgICAgYXdhaXQgdGhpcy5kaXNwb3NlUmVjb3JkaW5nKCk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBkaXNwb3NlUmVjb3JkaW5nKCkge1xuICAgICAgICBhd2FpdCBWb2ljZVJlY29yZGluZ1N0b3JlLmluc3RhbmNlLmRpc3Bvc2VSZWNvcmRpbmcoKTtcblxuICAgICAgICAvLyBSZXNldCBiYWNrIHRvIG5vIHJlY29yZGluZywgd2hpY2ggbWVhbnMgbm8gcGhhc2UgKGllOiByZXN0YXJ0IGNvbXBvbmVudCBlbnRpcmVseSlcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7cmVjb3JkZXI6IG51bGwsIHJlY29yZGluZ1BoYXNlOiBudWxsfSk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBvbkNhbmNlbCA9IGFzeW5jICgpID0+IHtcbiAgICAgICAgYXdhaXQgdGhpcy5kaXNwb3NlUmVjb3JkaW5nKCk7XG4gICAgfTtcblxuICAgIHByaXZhdGUgb25SZWNvcmRTdGFydEVuZENsaWNrID0gYXN5bmMgKCkgPT4ge1xuICAgICAgICBpZiAodGhpcy5zdGF0ZS5yZWNvcmRlcikge1xuICAgICAgICAgICAgYXdhaXQgdGhpcy5zdGF0ZS5yZWNvcmRlci5zdG9wKCk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICAvLyBUaGUgXCJtaWNyb3Bob25lIGFjY2VzcyBlcnJvclwiIGRpYWxvZ3MgYXJlIHVzZWQgYSBsb3QsIHNvIGxldCdzIGZ1bmN0aW9uaWZ5IHRoZW1cbiAgICAgICAgY29uc3QgYWNjZXNzRXJyb3IgPSAoKSA9PiB7XG4gICAgICAgICAgICBNb2RhbC5jcmVhdGVUcmFja2VkRGlhbG9nKCdNaWNyb3Bob25lIEFjY2VzcyBFcnJvcicsICcnLCBFcnJvckRpYWxvZywge1xuICAgICAgICAgICAgICAgIHRpdGxlOiBfdChcIlVuYWJsZSB0byBhY2Nlc3MgeW91ciBtaWNyb3Bob25lXCIpLFxuICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uOiA8PlxuICAgICAgICAgICAgICAgICAgICA8cD57X3QoXG4gICAgICAgICAgICAgICAgICAgICAgICBcIldlIHdlcmUgdW5hYmxlIHRvIGFjY2VzcyB5b3VyIG1pY3JvcGhvbmUuIFBsZWFzZSBjaGVjayB5b3VyIGJyb3dzZXIgc2V0dGluZ3MgYW5kIHRyeSBhZ2Fpbi5cIixcbiAgICAgICAgICAgICAgICAgICAgKX08L3A+XG4gICAgICAgICAgICAgICAgPC8+LFxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH07XG5cbiAgICAgICAgLy8gRG8gYSBzYW5pdHkgdGVzdCB0byBlbnN1cmUgd2UncmUgYWJvdXQgdG8gZ3JhYiBhIHZhbGlkIG1pY3JvcGhvbmUgcmVmZXJlbmNlLiBUaGluZ3MgbWlnaHRcbiAgICAgICAgLy8gY2hhbmdlIGJldHdlZW4gdGhpcyBhbmQgcmVjb3JkaW5nLCBidXQgYXQgbGVhc3Qgd2Ugd2lsbCBoYXZlIHRyaWVkLlxuICAgICAgICB0cnkge1xuICAgICAgICAgICAgY29uc3QgZGV2aWNlcyA9IGF3YWl0IENhbGxNZWRpYUhhbmRsZXIuZ2V0RGV2aWNlcygpO1xuICAgICAgICAgICAgaWYgKCFkZXZpY2VzPy5bJ2F1ZGlvaW5wdXQnXT8ubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgTW9kYWwuY3JlYXRlVHJhY2tlZERpYWxvZygnTm8gTWljcm9waG9uZSBFcnJvcicsICcnLCBFcnJvckRpYWxvZywge1xuICAgICAgICAgICAgICAgICAgICB0aXRsZTogX3QoXCJObyBtaWNyb3Bob25lIGZvdW5kXCIpLFxuICAgICAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbjogPD5cbiAgICAgICAgICAgICAgICAgICAgICAgIDxwPntfdChcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBcIldlIGRpZG4ndCBmaW5kIGEgbWljcm9waG9uZSBvbiB5b3VyIGRldmljZS4gUGxlYXNlIGNoZWNrIHlvdXIgc2V0dGluZ3MgYW5kIHRyeSBhZ2Fpbi5cIixcbiAgICAgICAgICAgICAgICAgICAgICAgICl9PC9wPlxuICAgICAgICAgICAgICAgICAgICA8Lz4sXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gZWxzZSB3ZSBwcm9iYWJseSBoYXZlIGEgZGV2aWNlIHRoYXQgaXMgZ29vZCBlbm91Z2hcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcihcIkVycm9yIGdldHRpbmcgZGV2aWNlczogXCIsIGUpO1xuICAgICAgICAgICAgYWNjZXNzRXJyb3IoKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjb25zdCByZWNvcmRlciA9IFZvaWNlUmVjb3JkaW5nU3RvcmUuaW5zdGFuY2Uuc3RhcnRSZWNvcmRpbmcoKTtcbiAgICAgICAgICAgIGF3YWl0IHJlY29yZGVyLnN0YXJ0KCk7XG5cbiAgICAgICAgICAgIC8vIFdlIGRvbid0IG5lZWQgdG8gcmVtb3ZlIHRoZSBsaXN0ZW5lcjogdGhlIHJlY29yZGVyIHdpbGwgY2xlYW4gdGhhdCB1cCBmb3IgdXMuXG4gICAgICAgICAgICByZWNvcmRlci5vbihVUERBVEVfRVZFTlQsIChldjogUmVjb3JkaW5nU3RhdGUpID0+IHtcbiAgICAgICAgICAgICAgICBpZiAoZXYgPT09IFJlY29yZGluZ1N0YXRlLkVuZGluZ1Nvb24pIHJldHVybjsgLy8gaWdub3JlIHRoaXMgc3RhdGU6IGl0IGhhcyBubyBVSSBwdXJwb3NlIGhlcmVcbiAgICAgICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtyZWNvcmRpbmdQaGFzZTogZXZ9KTtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtyZWNvcmRlciwgcmVjb3JkaW5nUGhhc2U6IFJlY29yZGluZ1N0YXRlLlN0YXJ0ZWR9KTtcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcihcIkVycm9yIHN0YXJ0aW5nIHJlY29yZGluZzogXCIsIGUpO1xuICAgICAgICAgICAgYWNjZXNzRXJyb3IoKTtcblxuICAgICAgICAgICAgLy8gbm9pbnNwZWN0aW9uIEVTNk1pc3NpbmdBd2FpdCAtIGlmIHRoaXMgZ29lcyB3cm9uZyB3ZSBkb24ndCB3YW50IGl0IHRvIGFmZmVjdCB0aGUgY2FsbCBzdGFja1xuICAgICAgICAgICAgVm9pY2VSZWNvcmRpbmdTdG9yZS5pbnN0YW5jZS5kaXNwb3NlUmVjb3JkaW5nKCk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgcHJpdmF0ZSByZW5kZXJXYXZlZm9ybUFyZWEoKTogUmVhY3ROb2RlIHtcbiAgICAgICAgaWYgKCF0aGlzLnN0YXRlLnJlY29yZGVyKSByZXR1cm4gbnVsbDsgLy8gbm8gcmVjb3JkZXIgbWVhbnMgd2UncmUgbm90IHJlY29yZGluZzogbm8gd2F2ZWZvcm1cblxuICAgICAgICBpZiAodGhpcy5zdGF0ZS5yZWNvcmRpbmdQaGFzZSAhPT0gUmVjb3JkaW5nU3RhdGUuU3RhcnRlZCkge1xuICAgICAgICAgICAgLy8gVE9ETzogQEAgVFI6IFNob3VsZCB3ZSBkaXNhYmxlIHRoaXMgZHVyaW5nIHVwbG9hZD8gV2hhdCBkb2VzIGEgZmFpbGVkIHVwbG9hZCBsb29rIGxpa2U/XG4gICAgICAgICAgICByZXR1cm4gPFJlY29yZGluZ1BsYXliYWNrIHBsYXliYWNrPXt0aGlzLnN0YXRlLnJlY29yZGVyLmdldFBsYXliYWNrKCl9IC8+O1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gb25seSBvdGhlciBVSSBpcyB0aGUgcmVjb3JkaW5nLWluLXByb2dyZXNzIFVJXG4gICAgICAgIHJldHVybiA8ZGl2IGNsYXNzTmFtZT1cIm14X1ZvaWNlTWVzc2FnZVByaW1hcnlDb250YWluZXIgbXhfVm9pY2VSZWNvcmRDb21wb3NlclRpbGVfcmVjb3JkaW5nXCI+XG4gICAgICAgICAgICA8TGl2ZVJlY29yZGluZ0Nsb2NrIHJlY29yZGVyPXt0aGlzLnN0YXRlLnJlY29yZGVyfSAvPlxuICAgICAgICAgICAgPExpdmVSZWNvcmRpbmdXYXZlZm9ybSByZWNvcmRlcj17dGhpcy5zdGF0ZS5yZWNvcmRlcn0gLz5cbiAgICAgICAgPC9kaXY+O1xuICAgIH1cblxuICAgIHB1YmxpYyByZW5kZXIoKTogUmVhY3ROb2RlIHtcbiAgICAgICAgbGV0IHJlY29yZGluZ0luZm87XG4gICAgICAgIGxldCBkZWxldGVCdXR0b247XG4gICAgICAgIGlmICghdGhpcy5zdGF0ZS5yZWNvcmRpbmdQaGFzZSB8fCB0aGlzLnN0YXRlLnJlY29yZGluZ1BoYXNlID09PSBSZWNvcmRpbmdTdGF0ZS5TdGFydGVkKSB7XG4gICAgICAgICAgICBjb25zdCBjbGFzc2VzID0gY2xhc3NOYW1lcyh7XG4gICAgICAgICAgICAgICAgJ214X01lc3NhZ2VDb21wb3Nlcl9idXR0b24nOiAhdGhpcy5zdGF0ZS5yZWNvcmRlcixcbiAgICAgICAgICAgICAgICAnbXhfTWVzc2FnZUNvbXBvc2VyX3ZvaWNlTWVzc2FnZSc6ICF0aGlzLnN0YXRlLnJlY29yZGVyLFxuICAgICAgICAgICAgICAgICdteF9Wb2ljZVJlY29yZENvbXBvc2VyVGlsZV9zdG9wJzogdGhpcy5zdGF0ZS5yZWNvcmRlcj8uaXNSZWNvcmRpbmcsXG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgbGV0IHRvb2x0aXAgPSBfdChcIlJlY29yZCBhIHZvaWNlIG1lc3NhZ2VcIik7XG4gICAgICAgICAgICBpZiAoISF0aGlzLnN0YXRlLnJlY29yZGVyKSB7XG4gICAgICAgICAgICAgICAgdG9vbHRpcCA9IF90KFwiU3RvcCB0aGUgcmVjb3JkaW5nXCIpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBsZXQgc3RvcE9yUmVjb3JkQnRuID0gPEFjY2Vzc2libGVUb29sdGlwQnV0dG9uXG4gICAgICAgICAgICAgICAgY2xhc3NOYW1lPXtjbGFzc2VzfVxuICAgICAgICAgICAgICAgIG9uQ2xpY2s9e3RoaXMub25SZWNvcmRTdGFydEVuZENsaWNrfVxuICAgICAgICAgICAgICAgIHRpdGxlPXt0b29sdGlwfVxuICAgICAgICAgICAgLz47XG4gICAgICAgICAgICBpZiAodGhpcy5zdGF0ZS5yZWNvcmRlciAmJiAhdGhpcy5zdGF0ZS5yZWNvcmRlcj8uaXNSZWNvcmRpbmcpIHtcbiAgICAgICAgICAgICAgICBzdG9wT3JSZWNvcmRCdG4gPSBudWxsO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZWNvcmRpbmdJbmZvID0gc3RvcE9yUmVjb3JkQnRuO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRoaXMuc3RhdGUucmVjb3JkZXIgJiYgdGhpcy5zdGF0ZS5yZWNvcmRpbmdQaGFzZSAhPT0gUmVjb3JkaW5nU3RhdGUuVXBsb2FkaW5nKSB7XG4gICAgICAgICAgICBkZWxldGVCdXR0b24gPSA8QWNjZXNzaWJsZVRvb2x0aXBCdXR0b25cbiAgICAgICAgICAgICAgICBjbGFzc05hbWU9J214X1ZvaWNlUmVjb3JkQ29tcG9zZXJUaWxlX2RlbGV0ZSdcbiAgICAgICAgICAgICAgICB0aXRsZT17X3QoXCJEZWxldGUgcmVjb3JkaW5nXCIpfVxuICAgICAgICAgICAgICAgIG9uQ2xpY2s9e3RoaXMub25DYW5jZWx9XG4gICAgICAgICAgICAvPjtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiAoPD5cbiAgICAgICAgICAgIHtkZWxldGVCdXR0b259XG4gICAgICAgICAgICB7dGhpcy5yZW5kZXJXYXZlZm9ybUFyZWEoKX1cbiAgICAgICAgICAgIHtyZWNvcmRpbmdJbmZvfVxuICAgICAgICA8Lz4pO1xuICAgIH1cbn1cbiJdfQ==