UNPKG

matrix-react-sdk

Version:
471 lines (401 loc) 57.6 kB
"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 _MatrixClientPeg = require("../../../MatrixClientPeg"); var sdk = _interopRequireWildcard(require("../../../index")); var _crypto = require("matrix-js-sdk/src/crypto"); var _QRCode = require("matrix-js-sdk/src/crypto/verification/QRCode"); var _VerificationQRCode = _interopRequireDefault(require("../elements/crypto/VerificationQRCode")); var _languageHandler = require("../../../languageHandler"); var _SdkConfig = _interopRequireDefault(require("../../../SdkConfig")); var _E2EIcon = _interopRequireDefault(require("../rooms/E2EIcon")); var _VerificationRequest = require("matrix-js-sdk/src/crypto/verification/request/VerificationRequest"); var _Spinner = _interopRequireDefault(require("../elements/Spinner")); var _replaceableComponent = require("../../../utils/replaceableComponent"); var _dec, _class, _temp; // XXX: Should be defined in matrix-js-sdk var VerificationPhase; (function (VerificationPhase) { VerificationPhase[VerificationPhase["PHASE_UNSENT"] = 0] = "PHASE_UNSENT"; VerificationPhase[VerificationPhase["PHASE_REQUESTED"] = 1] = "PHASE_REQUESTED"; VerificationPhase[VerificationPhase["PHASE_READY"] = 2] = "PHASE_READY"; VerificationPhase[VerificationPhase["PHASE_DONE"] = 3] = "PHASE_DONE"; VerificationPhase[VerificationPhase["PHASE_STARTED"] = 4] = "PHASE_STARTED"; VerificationPhase[VerificationPhase["PHASE_CANCELLED"] = 5] = "PHASE_CANCELLED"; })(VerificationPhase || (VerificationPhase = {})); let VerificationPanel = (_dec = (0, _replaceableComponent.replaceableComponent)("views.right_panel.VerificationPanel"), _dec(_class = (_temp = class VerificationPanel extends _react.default.PureComponent /*:: <IProps, IState>*/ { constructor(props /*: IProps*/ ) { super(props); (0, _defineProperty2.default)(this, "hasVerifier", void 0); (0, _defineProperty2.default)(this, "onReciprocateYesClick", () => { this.setState({ reciprocateButtonClicked: true }); this.state.reciprocateQREvent.confirm(); }); (0, _defineProperty2.default)(this, "onReciprocateNoClick", () => { this.setState({ reciprocateButtonClicked: true }); this.state.reciprocateQREvent.cancel(); }); (0, _defineProperty2.default)(this, "startSAS", async () => { this.setState({ emojiButtonClicked: true }); const verifier = this.props.request.beginKeyVerification(_crypto.verificationMethods.SAS); try { await verifier.verify(); } catch (err) { console.error(err); } }); (0, _defineProperty2.default)(this, "onSasMatchesClick", () => { this.state.sasEvent.confirm(); }); (0, _defineProperty2.default)(this, "onSasMismatchesClick", () => { this.state.sasEvent.mismatch(); }); (0, _defineProperty2.default)(this, "updateVerifierState", () => { const { request } = this.props; const { sasEvent, reciprocateQREvent } = request.verifier; request.verifier.off('show_sas', this.updateVerifierState); request.verifier.off('show_reciprocate_qr', this.updateVerifierState); this.setState({ sasEvent, reciprocateQREvent }); }); (0, _defineProperty2.default)(this, "onRequestChange", async () => { const { request } = this.props; const hadVerifier = this.hasVerifier; this.hasVerifier = !!request.verifier; if (!hadVerifier && this.hasVerifier) { request.verifier.on('show_sas', this.updateVerifierState); request.verifier.on('show_reciprocate_qr', this.updateVerifierState); try { // on the requester side, this is also awaited in startSAS, // but that's ok as verify should return the same promise. await request.verifier.verify(); } catch (err) { console.error("error verify", err); } } }); this.state = {}; this.hasVerifier = false; } renderQRPhase() { const { member, request } = this.props; const showSAS /*: boolean*/ = request.otherPartySupportsMethod(_crypto.verificationMethods.SAS); const showQR /*: boolean*/ = request.otherPartySupportsMethod(_QRCode.SCAN_QR_CODE_METHOD); const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); const brand = _SdkConfig.default.get().brand; const noCommonMethodError /*: JSX.Element*/ = !showSAS && !showQR ? /*#__PURE__*/_react.default.createElement("p", null, (0, _languageHandler._t)("The session you are trying to verify doesn't support scanning a " + "QR code or emoji verification, which is what %(brand)s supports. Try " + "with a different client.", { brand })) : null; if (this.props.layout === 'dialog') { // HACK: This is a terrible idea. let qrBlockDialog /*: JSX.Element*/ ; let sasBlockDialog /*: JSX.Element*/ ; if (showQR) { qrBlockDialog = /*#__PURE__*/_react.default.createElement("div", { className: "mx_VerificationPanel_QRPhase_startOption" }, /*#__PURE__*/_react.default.createElement("p", null, (0, _languageHandler._t)("Scan this unique code")), /*#__PURE__*/_react.default.createElement(_VerificationQRCode.default, { qrCodeData: request.qrCodeData })); } if (showSAS) { sasBlockDialog = /*#__PURE__*/_react.default.createElement("div", { className: "mx_VerificationPanel_QRPhase_startOption" }, /*#__PURE__*/_react.default.createElement("p", null, (0, _languageHandler._t)("Compare unique emoji")), /*#__PURE__*/_react.default.createElement("span", { className: "mx_VerificationPanel_QRPhase_helpText" }, (0, _languageHandler._t)("Compare a unique set of emoji if you don't have a camera on either device")), /*#__PURE__*/_react.default.createElement(AccessibleButton, { disabled: this.state.emojiButtonClicked, onClick: this.startSAS, kind: "primary" }, (0, _languageHandler._t)("Start"))); } const or = qrBlockDialog && sasBlockDialog ? /*#__PURE__*/_react.default.createElement("div", { className: "mx_VerificationPanel_QRPhase_betweenText" }, (0, _languageHandler._t)("or")) : null; return /*#__PURE__*/_react.default.createElement("div", null, (0, _languageHandler._t)("Verify this session by completing one of the following:"), /*#__PURE__*/_react.default.createElement("div", { className: "mx_VerificationPanel_QRPhase_startOptions" }, qrBlockDialog, or, sasBlockDialog, noCommonMethodError)); } let qrBlock /*: JSX.Element*/ ; if (showQR) { qrBlock = /*#__PURE__*/_react.default.createElement("div", { className: "mx_UserInfo_container" }, /*#__PURE__*/_react.default.createElement("h3", null, (0, _languageHandler._t)("Verify by scanning")), /*#__PURE__*/_react.default.createElement("p", null, (0, _languageHandler._t)("Ask %(displayName)s to scan your code:", { displayName: member.displayName || member.name || member.userId })), /*#__PURE__*/_react.default.createElement("div", { className: "mx_VerificationPanel_qrCode" }, /*#__PURE__*/_react.default.createElement(_VerificationQRCode.default, { qrCodeData: request.qrCodeData }))); } let sasBlock /*: JSX.Element*/ ; if (showSAS) { const disabled = this.state.emojiButtonClicked; const sasLabel = showQR ? (0, _languageHandler._t)("If you can't scan the code above, verify by comparing unique emoji.") : (0, _languageHandler._t)("Verify by comparing unique emoji."); // Note: mx_VerificationPanel_verifyByEmojiButton is for the end-to-end tests sasBlock = /*#__PURE__*/_react.default.createElement("div", { className: "mx_UserInfo_container" }, /*#__PURE__*/_react.default.createElement("h3", null, (0, _languageHandler._t)("Verify by emoji")), /*#__PURE__*/_react.default.createElement("p", null, sasLabel), /*#__PURE__*/_react.default.createElement(AccessibleButton, { disabled: disabled, kind: "primary", className: "mx_UserInfo_wideButton mx_VerificationPanel_verifyByEmojiButton", onClick: this.startSAS }, (0, _languageHandler._t)("Verify by emoji"))); } const noCommonMethodBlock = noCommonMethodError ? /*#__PURE__*/_react.default.createElement("div", { className: "mx_UserInfo_container" }, noCommonMethodError) : null; // TODO: add way to open camera to scan a QR code return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, qrBlock, sasBlock, noCommonMethodBlock); } getDevice() { const deviceId = this.props.request && this.props.request.channel.deviceId; return _MatrixClientPeg.MatrixClientPeg.get().getStoredDevice(_MatrixClientPeg.MatrixClientPeg.get().getUserId(), deviceId); } renderQRReciprocatePhase() { const { member, request } = this.props; let Button; // a bit of a hack, but the FormButton should only be used in the right panel // they should probably just be the same component with a css class applied to it? if (this.props.inDialog) { Button = sdk.getComponent("elements.AccessibleButton"); } else { Button = sdk.getComponent("elements.FormButton"); } const description = request.isSelfVerification ? (0, _languageHandler._t)("Almost there! Is your other session showing the same shield?") : (0, _languageHandler._t)("Almost there! Is %(displayName)s showing the same shield?", { displayName: member.displayName || member.name || member.userId }); let body /*: JSX.Element*/ ; if (this.state.reciprocateQREvent) { // Element Web doesn't support scanning yet, so assume here we're the client being scanned. // // we're passing both a label and a child string to Button as // FormButton and AccessibleButton expect this differently body = /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement("p", null, description), /*#__PURE__*/_react.default.createElement(_E2EIcon.default, { isUser: true, status: "verified", size: 128, hideTooltip: true }), /*#__PURE__*/_react.default.createElement("div", { className: "mx_VerificationPanel_reciprocateButtons" }, /*#__PURE__*/_react.default.createElement(Button, { label: (0, _languageHandler._t)("No"), kind: "danger", disabled: this.state.reciprocateButtonClicked, onClick: this.onReciprocateNoClick }, (0, _languageHandler._t)("No")), /*#__PURE__*/_react.default.createElement(Button, { label: (0, _languageHandler._t)("Yes"), kind: "primary", disabled: this.state.reciprocateButtonClicked, onClick: this.onReciprocateYesClick }, (0, _languageHandler._t)("Yes")))); } else { body = /*#__PURE__*/_react.default.createElement("p", null, /*#__PURE__*/_react.default.createElement(_Spinner.default, null)); } return /*#__PURE__*/_react.default.createElement("div", { className: "mx_UserInfo_container mx_VerificationPanel_reciprocate_section" }, /*#__PURE__*/_react.default.createElement("h3", null, (0, _languageHandler._t)("Verify by scanning")), body); } renderVerifiedPhase() { const { member, request } = this.props; let text /*: string*/ ; if (!request.isSelfVerification) { if (this.props.isRoomEncrypted) { text = (0, _languageHandler._t)("Verify all users in a room to ensure it's secure."); } else { text = (0, _languageHandler._t)("In encrypted rooms, verify all users to ensure it’s secure."); } } let description /*: string*/ ; if (request.isSelfVerification) { const device = this.getDevice(); if (!device) { // This can happen if the device is logged out while we're still showing verification // UI for it. console.warn("Verified device we don't know about: " + this.props.request.channel.deviceId); description = (0, _languageHandler._t)("You've successfully verified your device!"); } else { description = (0, _languageHandler._t)("You've successfully verified %(deviceName)s (%(deviceId)s)!", { deviceName: device ? device.getDisplayName() : '', deviceId: this.props.request.channel.deviceId }); } } else { description = (0, _languageHandler._t)("You've successfully verified %(displayName)s!", { displayName: member.displayName || member.name || member.userId }); } const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); return /*#__PURE__*/_react.default.createElement("div", { className: "mx_UserInfo_container mx_VerificationPanel_verified_section" }, /*#__PURE__*/_react.default.createElement("h3", null, (0, _languageHandler._t)("Verified")), /*#__PURE__*/_react.default.createElement("p", null, description), /*#__PURE__*/_react.default.createElement(_E2EIcon.default, { isUser: true, status: "verified", size: 128, hideTooltip: true }), text ? /*#__PURE__*/_react.default.createElement("p", null, text) : null, /*#__PURE__*/_react.default.createElement(AccessibleButton, { kind: "primary", className: "mx_UserInfo_wideButton", onClick: this.props.onClose }, (0, _languageHandler._t)("Got it"))); } renderCancelledPhase() { const { member, request } = this.props; const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); let startAgainInstruction /*: string*/ ; if (request.isSelfVerification) { startAgainInstruction = (0, _languageHandler._t)("Start verification again from the notification."); } else { startAgainInstruction = (0, _languageHandler._t)("Start verification again from their profile."); } let text /*: string*/ ; if (request.cancellationCode === "m.timeout") { text = (0, _languageHandler._t)("Verification timed out.") + ` ${startAgainInstruction}`; } else if (request.cancellingUserId === request.otherUserId) { if (request.isSelfVerification) { text = (0, _languageHandler._t)("You cancelled verification on your other session."); } else { text = (0, _languageHandler._t)("%(displayName)s cancelled verification.", { displayName: member.displayName || member.name || member.userId }); } text = `${text} ${startAgainInstruction}`; } else { text = (0, _languageHandler._t)("You cancelled verification.") + ` ${startAgainInstruction}`; } return /*#__PURE__*/_react.default.createElement("div", { className: "mx_UserInfo_container" }, /*#__PURE__*/_react.default.createElement("h3", null, (0, _languageHandler._t)("Verification cancelled")), /*#__PURE__*/_react.default.createElement("p", null, text), /*#__PURE__*/_react.default.createElement(AccessibleButton, { kind: "primary", className: "mx_UserInfo_wideButton", onClick: this.props.onClose }, (0, _languageHandler._t)("Got it"))); } render() { const { member, phase, request } = this.props; const displayName = member.displayName || member.name || member.userId; switch (phase) { case _VerificationRequest.PHASE_READY: return this.renderQRPhase(); case _VerificationRequest.PHASE_STARTED: switch (request.chosenMethod) { case _crypto.verificationMethods.RECIPROCATE_QR_CODE: return this.renderQRReciprocatePhase(); case _crypto.verificationMethods.SAS: { const VerificationShowSas = sdk.getComponent('views.verification.VerificationShowSas'); const emojis = this.state.sasEvent ? /*#__PURE__*/_react.default.createElement(VerificationShowSas, { displayName: displayName, device: this.getDevice(), sas: this.state.sasEvent.sas, onCancel: this.onSasMismatchesClick, onDone: this.onSasMatchesClick, inDialog: this.props.inDialog, isSelf: request.isSelfVerification }) : /*#__PURE__*/_react.default.createElement(_Spinner.default, null); return /*#__PURE__*/_react.default.createElement("div", { className: "mx_UserInfo_container" }, /*#__PURE__*/_react.default.createElement("h3", null, (0, _languageHandler._t)("Compare emoji")), emojis); } default: return null; } case _VerificationRequest.PHASE_DONE: return this.renderVerifiedPhase(); case _VerificationRequest.PHASE_CANCELLED: return this.renderCancelledPhase(); } console.error("VerificationPanel unhandled phase:", phase); return null; } componentDidMount() { const { request } = this.props; request.on("change", this.onRequestChange); if (request.verifier) { const { sasEvent, reciprocateQREvent } = request.verifier; this.setState({ sasEvent, reciprocateQREvent }); } this.onRequestChange(); } componentWillUnmount() { const { request } = this.props; if (request.verifier) { request.verifier.off('show_sas', this.updateVerifierState); request.verifier.off('show_reciprocate_qr', this.updateVerifierState); } request.off("change", this.onRequestChange); } }, _temp)) || _class); exports.default = VerificationPanel; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9jb21wb25lbnRzL3ZpZXdzL3JpZ2h0X3BhbmVsL1ZlcmlmaWNhdGlvblBhbmVsLnRzeCJdLCJuYW1lcyI6WyJWZXJpZmljYXRpb25QaGFzZSIsIlZlcmlmaWNhdGlvblBhbmVsIiwiUmVhY3QiLCJQdXJlQ29tcG9uZW50IiwiY29uc3RydWN0b3IiLCJwcm9wcyIsInNldFN0YXRlIiwicmVjaXByb2NhdGVCdXR0b25DbGlja2VkIiwic3RhdGUiLCJyZWNpcHJvY2F0ZVFSRXZlbnQiLCJjb25maXJtIiwiY2FuY2VsIiwiZW1vamlCdXR0b25DbGlja2VkIiwidmVyaWZpZXIiLCJyZXF1ZXN0IiwiYmVnaW5LZXlWZXJpZmljYXRpb24iLCJ2ZXJpZmljYXRpb25NZXRob2RzIiwiU0FTIiwidmVyaWZ5IiwiZXJyIiwiY29uc29sZSIsImVycm9yIiwic2FzRXZlbnQiLCJtaXNtYXRjaCIsIm9mZiIsInVwZGF0ZVZlcmlmaWVyU3RhdGUiLCJoYWRWZXJpZmllciIsImhhc1ZlcmlmaWVyIiwib24iLCJyZW5kZXJRUlBoYXNlIiwibWVtYmVyIiwic2hvd1NBUyIsIm90aGVyUGFydHlTdXBwb3J0c01ldGhvZCIsInNob3dRUiIsIlNDQU5fUVJfQ09ERV9NRVRIT0QiLCJBY2Nlc3NpYmxlQnV0dG9uIiwic2RrIiwiZ2V0Q29tcG9uZW50IiwiYnJhbmQiLCJTZGtDb25maWciLCJnZXQiLCJub0NvbW1vbk1ldGhvZEVycm9yIiwibGF5b3V0IiwicXJCbG9ja0RpYWxvZyIsInNhc0Jsb2NrRGlhbG9nIiwicXJDb2RlRGF0YSIsInN0YXJ0U0FTIiwib3IiLCJxckJsb2NrIiwiZGlzcGxheU5hbWUiLCJuYW1lIiwidXNlcklkIiwic2FzQmxvY2siLCJkaXNhYmxlZCIsInNhc0xhYmVsIiwibm9Db21tb25NZXRob2RCbG9jayIsImdldERldmljZSIsImRldmljZUlkIiwiY2hhbm5lbCIsIk1hdHJpeENsaWVudFBlZyIsImdldFN0b3JlZERldmljZSIsImdldFVzZXJJZCIsInJlbmRlclFSUmVjaXByb2NhdGVQaGFzZSIsIkJ1dHRvbiIsImluRGlhbG9nIiwiZGVzY3JpcHRpb24iLCJpc1NlbGZWZXJpZmljYXRpb24iLCJib2R5Iiwib25SZWNpcHJvY2F0ZU5vQ2xpY2siLCJvblJlY2lwcm9jYXRlWWVzQ2xpY2siLCJyZW5kZXJWZXJpZmllZFBoYXNlIiwidGV4dCIsImlzUm9vbUVuY3J5cHRlZCIsImRldmljZSIsIndhcm4iLCJkZXZpY2VOYW1lIiwiZ2V0RGlzcGxheU5hbWUiLCJvbkNsb3NlIiwicmVuZGVyQ2FuY2VsbGVkUGhhc2UiLCJzdGFydEFnYWluSW5zdHJ1Y3Rpb24iLCJjYW5jZWxsYXRpb25Db2RlIiwiY2FuY2VsbGluZ1VzZXJJZCIsIm90aGVyVXNlcklkIiwicmVuZGVyIiwicGhhc2UiLCJQSEFTRV9SRUFEWSIsIlBIQVNFX1NUQVJURUQiLCJjaG9zZW5NZXRob2QiLCJSRUNJUFJPQ0FURV9RUl9DT0RFIiwiVmVyaWZpY2F0aW9uU2hvd1NhcyIsImVtb2ppcyIsInNhcyIsIm9uU2FzTWlzbWF0Y2hlc0NsaWNrIiwib25TYXNNYXRjaGVzQ2xpY2siLCJQSEFTRV9ET05FIiwiUEhBU0VfQ0FOQ0VMTEVEIiwiY29tcG9uZW50RGlkTW91bnQiLCJvblJlcXVlc3RDaGFuZ2UiLCJjb21wb25lbnRXaWxsVW5tb3VudCJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7OztBQWdCQTs7QUFFQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFNQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFNQTs7QUFDQTs7OztBQUVBO0lBQ0tBLGlCOztXQUFBQSxpQjtBQUFBQSxFQUFBQSxpQixDQUFBQSxpQjtBQUFBQSxFQUFBQSxpQixDQUFBQSxpQjtBQUFBQSxFQUFBQSxpQixDQUFBQSxpQjtBQUFBQSxFQUFBQSxpQixDQUFBQSxpQjtBQUFBQSxFQUFBQSxpQixDQUFBQSxpQjtBQUFBQSxFQUFBQSxpQixDQUFBQSxpQjtHQUFBQSxpQixLQUFBQSxpQjs7SUE0QmdC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QWpCLENBQXFCLHFCQUFyQixFQUE0QyxLQUFLQyxtQkFBakQ7QUFDSDs7QUFDRFgsSUFBQUEsT0FBTyxDQUFDVSxHQUFSLENBQVksUUFBWixFQUFzQixLQUFLeUUsZUFBM0I7QUFDSDs7QUFwVzhFLEMiLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuQ29weXJpZ2h0IDIwMTksIDIwMjAgVGhlIE1hdHJpeC5vcmcgRm91bmRhdGlvbiBDLkkuQy5cblxuTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKTtcbnlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS5cbllvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdFxuXG4gICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXG5cblVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmVcbmRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuIFwiQVMgSVNcIiBCQVNJUyxcbldJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLlxuU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZFxubGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXG4qL1xuXG5pbXBvcnQgUmVhY3QgZnJvbSBcInJlYWN0XCI7XG5cbmltcG9ydCB7TWF0cml4Q2xpZW50UGVnfSBmcm9tIFwiLi4vLi4vLi4vTWF0cml4Q2xpZW50UGVnXCI7XG5pbXBvcnQgKiBhcyBzZGsgZnJvbSAnLi4vLi4vLi4vaW5kZXgnO1xuaW1wb3J0IHt2ZXJpZmljYXRpb25NZXRob2RzfSBmcm9tICdtYXRyaXgtanMtc2RrL3NyYy9jcnlwdG8nO1xuaW1wb3J0IHtTQ0FOX1FSX0NPREVfTUVUSE9EfSBmcm9tIFwibWF0cml4LWpzLXNkay9zcmMvY3J5cHRvL3ZlcmlmaWNhdGlvbi9RUkNvZGVcIjtcbmltcG9ydCB7VmVyaWZpY2F0aW9uUmVxdWVzdH0gZnJvbSBcIm1hdHJpeC1qcy1zZGsvc3JjL2NyeXB0by92ZXJpZmljYXRpb24vcmVxdWVzdC9WZXJpZmljYXRpb25SZXF1ZXN0XCI7XG5pbXBvcnQge1Jvb21NZW1iZXJ9IGZyb20gXCJtYXRyaXgtanMtc2RrL3NyYy9tb2RlbHMvcm9vbS1tZW1iZXJcIjtcbmltcG9ydCB7UmVjaXByb2NhdGVRUkNvZGV9IGZyb20gXCJtYXRyaXgtanMtc2RrL3NyYy9jcnlwdG8vdmVyaWZpY2F0aW9uL1FSQ29kZVwiO1xuaW1wb3J0IHtTQVN9IGZyb20gXCJtYXRyaXgtanMtc2RrL3NyYy9jcnlwdG8vdmVyaWZpY2F0aW9uL1NBU1wiO1xuXG5pbXBvcnQgVmVyaWZpY2F0aW9uUVJDb2RlIGZyb20gXCIuLi9lbGVtZW50cy9jcnlwdG8vVmVyaWZpY2F0aW9uUVJDb2RlXCI7XG5pbXBvcnQge190fSBmcm9tIFwiLi4vLi4vLi4vbGFuZ3VhZ2VIYW5kbGVyXCI7XG5pbXBvcnQgU2RrQ29uZmlnIGZyb20gXCIuLi8uLi8uLi9TZGtDb25maWdcIjtcbmltcG9ydCBFMkVJY29uIGZyb20gXCIuLi9yb29tcy9FMkVJY29uXCI7XG5pbXBvcnQge1xuICAgIFBIQVNFX1JFQURZLFxuICAgIFBIQVNFX0RPTkUsXG4gICAgUEhBU0VfU1RBUlRFRCxcbiAgICBQSEFTRV9DQU5DRUxMRUQsXG59IGZyb20gXCJtYXRyaXgtanMtc2RrL3NyYy9jcnlwdG8vdmVyaWZpY2F0aW9uL3JlcXVlc3QvVmVyaWZpY2F0aW9uUmVxdWVzdFwiO1xuaW1wb3J0IFNwaW5uZXIgZnJvbSBcIi4uL2VsZW1lbnRzL1NwaW5uZXJcIjtcbmltcG9ydCB7cmVwbGFjZWFibGVDb21wb25lbnR9IGZyb20gXCIuLi8uLi8uLi91dGlscy9yZXBsYWNlYWJsZUNvbXBvbmVudFwiO1xuXG4vLyBYWFg6IFNob3VsZCBiZSBkZWZpbmVkIGluIG1hdHJpeC1qcy1zZGtcbmVudW0gVmVyaWZpY2F0aW9uUGhhc2Uge1xuICAgIFBIQVNFX1VOU0VOVCxcbiAgICBQSEFTRV9SRVFVRVNURUQsXG4gICAgUEhBU0VfUkVBRFksXG4gICAgUEhBU0VfRE9ORSxcbiAgICBQSEFTRV9TVEFSVEVELFxuICAgIFBIQVNFX0NBTkNFTExFRCxcbn1cblxuaW50ZXJmYWNlIElQcm9wcyB7XG4gICAgbGF5b3V0OiBzdHJpbmc7XG4gICAgcmVxdWVzdDogVmVyaWZpY2F0aW9uUmVxdWVzdDtcbiAgICBtZW1iZXI6IFJvb21NZW1iZXI7XG4gICAgcGhhc2U6IFZlcmlmaWNhdGlvblBoYXNlO1xuICAgIG9uQ2xvc2U6ICgpID0+IHZvaWQ7XG4gICAgaXNSb29tRW5jcnlwdGVkOiBib29sZWFuO1xuICAgIGluRGlhbG9nOiBib29sZWFuO1xuICAgIGtleTogbnVtYmVyO1xufVxuXG5pbnRlcmZhY2UgSVN0YXRlIHtcbiAgICBzYXNFdmVudD86IFNBUztcbiAgICBlbW9qaUJ1dHRvbkNsaWNrZWQ/OiBib29sZWFuO1xuICAgIHJlY2lwcm9jYXRlQnV0dG9uQ2xpY2tlZD86IGJvb2xlYW47XG4gICAgcmVjaXByb2NhdGVRUkV2ZW50PzogUmVjaXByb2NhdGVRUkNvZGU7XG59XG5cbkByZXBsYWNlYWJsZUNvbXBvbmVudChcInZpZXdzLnJpZ2h0X3BhbmVsLlZlcmlmaWNhdGlvblBhbmVsXCIpXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBWZXJpZmljYXRpb25QYW5lbCBleHRlbmRzIFJlYWN0LlB1cmVDb21wb25lbnQ8SVByb3BzLCBJU3RhdGU+IHtcbiAgICBwcml2YXRlIGhhc1ZlcmlmaWVyOiBib29sZWFuO1xuXG4gICAgY29uc3RydWN0b3IocHJvcHM6IElQcm9wcykge1xuICAgICAgICBzdXBlcihwcm9wcyk7XG4gICAgICAgIHRoaXMuc3RhdGUgPSB7fTtcbiAgICAgICAgdGhpcy5oYXNWZXJpZmllciA9IGZhbHNlO1xuICAgIH1cblxuICAgIHByaXZhdGUgcmVuZGVyUVJQaGFzZSgpIHtcbiAgICAgICAgY29uc3Qge21lbWJlciwgcmVxdWVzdH0gPSB0aGlzLnByb3BzO1xuICAgICAgICBjb25zdCBzaG93U0FTOiBib29sZWFuID0gcmVxdWVzdC5vdGhlclBhcnR5U3VwcG9ydHNNZXRob2QodmVyaWZpY2F0aW9uTWV0aG9kcy5TQVMpO1xuICAgICAgICBjb25zdCBzaG93UVI6IGJvb2xlYW4gPSByZXF1ZXN0Lm90aGVyUGFydHlTdXBwb3J0c01ldGhvZChTQ0FOX1FSX0NPREVfTUVUSE9EKTtcbiAgICAgICAgY29uc3QgQWNjZXNzaWJsZUJ1dHRvbiA9IHNkay5nZXRDb21wb25lbnQoJ2VsZW1lbnRzLkFjY2Vzc2libGVCdXR0b24nKTtcbiAgICAgICAgY29uc3QgYnJhbmQgPSBTZGtDb25maWcuZ2V0KCkuYnJhbmQ7XG5cbiAgICAgICAgY29uc3Qgbm9Db21tb25NZXRob2RFcnJvcjogSlNYLkVsZW1lbnQgPSAhc2hvd1NBUyAmJiAhc2hvd1FSID9cbiAgICAgICAgICAgIDxwPntfdChcbiAgICAgICAgICAgICAgICBcIlRoZSBzZXNzaW9uIHlvdSBhcmUgdHJ5aW5nIHRvIHZlcmlmeSBkb2Vzbid0IHN1cHBvcnQgc2Nhbm5pbmcgYSBcIiArXG4gICAgICAgICAgICAgICAgXCJRUiBjb2RlIG9yIGVtb2ppIHZlcmlmaWNhdGlvbiwgd2hpY2ggaXMgd2hhdCAlKGJyYW5kKXMgc3VwcG9ydHMuIFRyeSBcIiArXG4gICAgICAgICAgICAgICAgXCJ3aXRoIGEgZGlmZmVyZW50IGNsaWVudC5cIixcbiAgICAgICAgICAgICAgICB7IGJyYW5kIH0sXG4gICAgICAgICAgICApfTwvcD4gOlxuICAgICAgICAgICAgbnVsbDtcblxuICAgICAgICBpZiAodGhpcy5wcm9wcy5sYXlvdXQgPT09ICdkaWFsb2cnKSB7XG4gICAgICAgICAgICAvLyBIQUNLOiBUaGlzIGlzIGEgdGVycmlibGUgaWRlYS5cbiAgICAgICAgICAgIGxldCBxckJsb2NrRGlhbG9nOiBKU1guRWxlbWVudDtcbiAgICAgICAgICAgIGxldCBzYXNCbG9ja0RpYWxvZzogSlNYLkVsZW1lbnQ7XG4gICAgICAgICAgICBpZiAoc2hvd1FSKSB7XG4gICAgICAgICAgICAgICAgcXJCbG9ja0RpYWxvZyA9XG4gICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3NOYW1lPSdteF9WZXJpZmljYXRpb25QYW5lbF9RUlBoYXNlX3N0YXJ0T3B0aW9uJz5cbiAgICAgICAgICAgICAgICAgICAgICAgIDxwPntfdChcIlNjYW4gdGhpcyB1bmlxdWUgY29kZVwiKX08L3A+XG4gICAgICAgICAgICAgICAgICAgICAgICA8VmVyaWZpY2F0aW9uUVJDb2RlIHFyQ29kZURhdGE9e3JlcXVlc3QucXJDb2RlRGF0YX0gLz5cbiAgICAgICAgICAgICAgICAgICAgPC9kaXY+O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHNob3dTQVMpIHtcbiAgICAgICAgICAgICAgICBzYXNCbG9ja0RpYWxvZyA9IDxkaXYgY2xhc3NOYW1lPSdteF9WZXJpZmljYXRpb25QYW5lbF9RUlBoYXNlX3N0YXJ0T3B0aW9uJz5cbiAgICAgICAgICAgICAgICAgICAgPHA+e190KFwiQ29tcGFyZSB1bmlxdWUgZW1vamlcIil9PC9wPlxuICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzc05hbWU9J214X1ZlcmlmaWNhdGlvblBhbmVsX1FSUGhhc2VfaGVscFRleHQnPlxuICAgICAgICAgICAgICAgICAgICAgICAge190KFwiQ29tcGFyZSBhIHVuaXF1ZSBzZXQgb2YgZW1vamkgaWYgeW91IGRvbid0IGhhdmUgYSBjYW1lcmEgb24gZWl0aGVyIGRldmljZVwiKX1cbiAgICAgICAgICAgICAgICAgICAgPC9zcGFuPlxuICAgICAgICAgICAgICAgICAgICA8QWNjZXNzaWJsZUJ1dHRvbiBkaXNhYmxlZD17dGhpcy5zdGF0ZS5lbW9qaUJ1dHRvbkNsaWNrZWR9IG9uQ2xpY2s9e3RoaXMuc3RhcnRTQVN9IGtpbmQ9J3ByaW1hcnknPlxuICAgICAgICAgICAgICAgICAgICAgICAge190KFwiU3RhcnRcIil9XG4gICAgICAgICAgICAgICAgICAgIDwvQWNjZXNzaWJsZUJ1dHRvbj5cbiAgICAgICAgICAgICAgICA8L2Rpdj47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25zdCBvciA9IHFyQmxvY2tEaWFsb2cgJiYgc2FzQmxvY2tEaWFsb2cgP1xuICAgICAgICAgICAgICAgIDxkaXYgY2xhc3NOYW1lPSdteF9WZXJpZmljYXRpb25QYW5lbF9RUlBoYXNlX2JldHdlZW5UZXh0Jz57X3QoXCJvclwiKX08L2Rpdj4gOiBudWxsO1xuICAgICAgICAgICAgcmV0dXJuIChcbiAgICAgICAgICAgICAgICA8ZGl2PlxuICAgICAgICAgICAgICAgICAgICB7X3QoXCJWZXJpZnkgdGhpcyBzZXNzaW9uIGJ5IGNvbXBsZXRpbmcgb25lIG9mIHRoZSBmb2xsb3dpbmc6XCIpfVxuICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzTmFtZT0nbXhfVmVyaWZpY2F0aW9uUGFuZWxfUVJQaGFzZV9zdGFydE9wdGlvbnMnPlxuICAgICAgICAgICAgICAgICAgICAgICAge3FyQmxvY2tEaWFsb2d9XG4gICAgICAgICAgICAgICAgICAgICAgICB7b3J9XG4gICAgICAgICAgICAgICAgICAgICAgICB7c2FzQmxvY2tEaWFsb2d9XG4gICAgICAgICAgICAgICAgICAgICAgICB7bm9Db21tb25NZXRob2RFcnJvcn1cbiAgICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICApO1xuICAgICAgICB9XG5cbiAgICAgICAgbGV0IHFyQmxvY2s6IEpTWC5FbGVtZW50O1xuICAgICAgICBpZiAoc2hvd1FSKSB7XG4gICAgICAgICAgICBxckJsb2NrID0gPGRpdiBjbGFzc05hbWU9XCJteF9Vc2VySW5mb19jb250YWluZXJcIj5cbiAgICAgICAgICAgICAgICA8aDM+e190KFwiVmVyaWZ5IGJ5IHNjYW5uaW5nXCIpfTwvaDM+XG4gICAgICAgICAgICAgICAgPHA+e190KFwiQXNrICUoZGlzcGxheU5hbWUpcyB0byBzY2FuIHlvdXIgY29kZTpcIiwge1xuICAgICAgICAgICAgICAgICAgICBkaXNwbGF5TmFtZTogbWVtYmVyLmRpc3BsYXlOYW1lIHx8IG1lbWJlci5uYW1lIHx8IG1lbWJlci51c2VySWQsXG4gICAgICAgICAgICAgICAgfSl9PC9wPlxuXG4gICAgICAgICAgICAgICAgPGRpdiBjbGFzc05hbWU9XCJteF9WZXJpZmljYXRpb25QYW5lbF9xckNvZGVcIj5cbiAgICAgICAgICAgICAgICAgICAgPFZlcmlmaWNhdGlvblFSQ29kZSBxckNvZGVEYXRhPXtyZXF1ZXN0LnFyQ29kZURhdGF9IC8+XG4gICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICA8L2Rpdj47XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgc2FzQmxvY2s6IEpTWC5FbGVtZW50O1xuICAgICAgICBpZiAoc2hvd1NBUykge1xuICAgICAgICAgICAgY29uc3QgZGlzYWJsZWQgPSB0aGlzLnN0YXRlLmVtb2ppQnV0dG9uQ2xpY2tlZDtcbiAgICAgICAgICAgIGNvbnN0IHNhc0xhYmVsID0gc2hvd1FSID9cbiAgICAgICAgICAgICAgICBfdChcIklmIHlvdSBjYW4ndCBzY2FuIHRoZSBjb2RlIGFib3ZlLCB2ZXJpZnkgYnkgY29tcGFyaW5nIHVuaXF1ZSBlbW9qaS5cIikgOlxuICAgICAgICAgICAgICAgIF90KFwiVmVyaWZ5IGJ5IGNvbXBhcmluZyB1bmlxdWUgZW1vamkuXCIpO1xuXG4gICAgICAgICAgICAvLyBOb3RlOiBteF9WZXJpZmljYXRpb25QYW5lbF92ZXJpZnlCeUVtb2ppQnV0dG9uIGlzIGZvciB0aGUgZW5kLXRvLWVuZCB0ZXN0c1xuICAgICAgICAgICAgc2FzQmxvY2sgPSA8ZGl2IGNsYXNzTmFtZT1cIm14X1VzZXJJbmZvX2NvbnRhaW5lclwiPlxuICAgICAgICAgICAgICAgIDxoMz57X3QoXCJWZXJpZnkgYnkgZW1vamlcIil9PC9oMz5cbiAgICAgICAgICAgICAgICA8cD57c2FzTGFiZWx9PC9wPlxuICAgICAgICAgICAgICAgIDxBY2Nlc3NpYmxlQnV0dG9uXG4gICAgICAgICAgICAgICAgICAgIGRpc2FibGVkPXtkaXNhYmxlZH1cbiAgICAgICAgICAgICAgICAgICAga2luZD1cInByaW1hcnlcIlxuICAgICAgICAgICAgICAgICAgICBjbGFzc05hbWU9XCJteF9Vc2VySW5mb193aWRlQnV0dG9uIG14X1ZlcmlmaWNhdGlvblBhbmVsX3ZlcmlmeUJ5RW1vamlCdXR0b25cIlxuICAgICAgICAgICAgICAgICAgICBvbkNsaWNrPXt0aGlzLnN0YXJ0U0FTfVxuICAgICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICAgICAge190KFwiVmVyaWZ5IGJ5IGVtb2ppXCIpfVxuICAgICAgICAgICAgICAgIDwvQWNjZXNzaWJsZUJ1dHRvbj5cbiAgICAgICAgICAgIDwvZGl2PjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IG5vQ29tbW9uTWV0aG9kQmxvY2sgPSBub0NvbW1vbk1ldGhvZEVycm9yID9cbiAgICAgICAgICAgIDxkaXYgY2xhc3NOYW1lPVwibXhfVXNlckluZm9fY29udGFpbmVyXCI+e25vQ29tbW9uTWV0aG9kRXJyb3J9PC9kaXY+IDpcbiAgICAgICAgICAgIG51bGw7XG5cbiAgICAgICAgLy8gVE9ETzogYWRkIHdheSB0byBvcGVuIGNhbWVyYSB0byBzY2FuIGEgUVIgY29kZVxuICAgICAgICByZXR1cm4gPFJlYWN0LkZyYWdtZW50PlxuICAgICAgICAgICAge3FyQmxvY2t9XG4gICAgICAgICAgICB7c2FzQmxvY2t9XG4gICAgICAgICAgICB7bm9Db21tb25NZXRob2RCbG9ja31cbiAgICAgICAgPC9SZWFjdC5GcmFnbWVudD47XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBvblJlY2lwcm9jYXRlWWVzQ2xpY2sgPSAoKSA9PiB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe3JlY2lwcm9jYXRlQnV0dG9uQ2xpY2tlZDogdHJ1ZX0pO1xuICAgICAgICB0aGlzLnN0YXRlLnJlY2lwcm9jYXRlUVJFdmVudC5jb25maXJtKCk7XG4gICAgfTtcblxuICAgIHByaXZhdGUgb25SZWNpcHJvY2F0ZU5vQ2xpY2sgPSAoKSA9PiB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe3JlY2lwcm9jYXRlQnV0dG9uQ2xpY2tlZDogdHJ1ZX0pO1xuICAgICAgICB0aGlzLnN0YXRlLnJlY2lwcm9jYXRlUVJFdmVudC5jYW5jZWwoKTtcbiAgICB9O1xuXG4gICAgcHJpdmF0ZSBnZXREZXZpY2UoKSB7XG4gICAgICAgIGNvbnN0IGRldmljZUlkID0gdGhpcy5wcm9wcy5yZXF1ZXN0ICYmIHRoaXMucHJvcHMucmVxdWVzdC5jaGFubmVsLmRldmljZUlkO1xuICAgICAgICByZXR1cm4gTWF0cml4Q2xpZW50UGVnLmdldCgpLmdldFN0b3JlZERldmljZShNYXRyaXhDbGllbnRQZWcuZ2V0KCkuZ2V0VXNlcklkKCksIGRldmljZUlkKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIHJlbmRlclFSUmVjaXByb2NhdGVQaGFzZSgpIHtcbiAgICAgICAgY29uc3Qge21lbWJlciwgcmVxdWVzdH0gPSB0aGlzLnByb3BzO1xuICAgICAgICBsZXQgQnV0dG9uO1xuICAgICAgICAvLyBhIGJpdCBvZiBhIGhhY2ssIGJ1dCB0aGUgRm9ybUJ1dHRvbiBzaG91bGQgb25seSBiZSB1c2VkIGluIHRoZSByaWdodCBwYW5lbFxuICAgICAgICAvLyB0aGV5IHNob3VsZCBwcm9iYWJseSBqdXN0IGJlIHRoZSBzYW1lIGNvbXBvbmVudCB3aXRoIGEgY3NzIGNsYXNzIGFwcGxpZWQgdG8gaXQ/XG4gICAgICAgIGlmICh0aGlzLnByb3BzLmluRGlhbG9nKSB7XG4gICAgICAgICAgICBCdXR0b24gPSBzZGsuZ2V0Q29tcG9uZW50KFwiZWxlbWVudHMuQWNjZXNzaWJsZUJ1dHRvblwiKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIEJ1dHRvbiA9IHNkay5nZXRDb21wb25lbnQoXCJlbGVtZW50cy5Gb3JtQnV0dG9uXCIpO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGRlc2NyaXB0aW9uID0gcmVxdWVzdC5pc1NlbGZWZXJpZmljYXRpb24gP1xuICAgICAgICAgICAgX3QoXCJBbG1vc3QgdGhlcmUhIElzIHlvdXIgb3RoZXIgc2Vzc2lvbiBzaG93aW5nIHRoZSBzYW1lIHNoaWVsZD9cIikgOlxuICAgICAgICAgICAgX3QoXCJBbG1vc3QgdGhlcmUhIElzICUoZGlzcGxheU5hbWUpcyBzaG93aW5nIHRoZSBzYW1lIHNoaWVsZD9cIiwge1xuICAgICAgICAgICAgICAgIGRpc3BsYXlOYW1lOiBtZW1iZXIuZGlzcGxheU5hbWUgfHwgbWVtYmVyLm5hbWUgfHwgbWVtYmVyLnVzZXJJZCxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICBsZXQgYm9keTogSlNYLkVsZW1lbnQ7XG4gICAgICAgIGlmICh0aGlzLnN0YXRlLnJlY2lwcm9jYXRlUVJFdmVudCkge1xuICAgICAgICAgICAgLy8gRWxlbWVudCBXZWIgZG9lc24ndCBzdXBwb3J0IHNjYW5uaW5nIHlldCwgc28gYXNzdW1lIGhlcmUgd2UncmUgdGhlIGNsaWVudCBiZWluZyBzY2FubmVkLlxuICAgICAgICAgICAgLy9cbiAgICAgICAgICAgIC8vIHdlJ3JlIHBhc3NpbmcgYm90aCBhIGxhYmVsIGFuZCBhIGNoaWxkIHN0cmluZyB0byBCdXR0b24gYXNcbiAgICAgICAgICAgIC8vIEZvcm1CdXR0b24gYW5kIEFjY2Vzc2libGVCdXR0b24gZXhwZWN0IHRoaXMgZGlmZmVyZW50bHlcbiAgICAgICAgICAgIGJvZHkgPSA8UmVhY3QuRnJhZ21lbnQ+XG4gICAgICAgICAgICAgICAgPHA+e2Rlc2NyaXB0aW9ufTwvcD5cbiAgICAgICAgICAgICAgICA8RTJFSWNvbiBpc1VzZXI9e3RydWV9IHN0YXR1cz1cInZlcmlmaWVkXCIgc2l6ZT17MTI4fSBoaWRlVG9vbHRpcD17dHJ1ZX0gLz5cbiAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzTmFtZT1cIm14X1ZlcmlmaWNhdGlvblBhbmVsX3JlY2lwcm9jYXRlQnV0dG9uc1wiPlxuICAgICAgICAgICAgICAgICAgICA8QnV0dG9uXG4gICAgICAgICAgICAgICAgICAgICAgICBsYWJlbD17X3QoXCJOb1wiKX0ga2luZD1cImRhbmdlclwiXG4gICAgICAgICAgICAgICAgICAgICAgICBkaXNhYmxlZD17dGhpcy5zdGF0ZS5yZWNpcHJvY2F0ZUJ1dHRvbkNsaWNrZWR9XG4gICAgICAgICAgICAgICAgICAgICAgICBvbkNsaWNrPXt0aGlzLm9uUmVjaXByb2NhdGVOb0NsaWNrfT57X3QoXCJOb1wiKX08L0J1dHRvbj5cbiAgICAgICAgICAgICAgICAgICAgPEJ1dHRvblxuICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWw9e190KFwiWWVzXCIpfSBraW5kPVwicHJpbWFyeVwiXG4gICAgICAgICAgICAgICAgICAgICAgICBkaXNhYmxlZD17dGhpcy5zdGF0ZS5yZWNpcHJvY2F0ZUJ1dHRvbkNsaWNrZWR9XG4gICAgICAgICAgICAgICAgICAgICAgICBvbkNsaWNrPXt0aGlzLm9uUmVjaXByb2NhdGVZZXNDbGlja30+e190KFwiWWVzXCIpfTwvQnV0dG9uPlxuICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgPC9SZWFjdC5GcmFnbWVudD47XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBib2R5ID0gPHA+PFNwaW5uZXIgLz48L3A+O1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiA8ZGl2IGNsYXNzTmFtZT1cIm14X1VzZXJJbmZvX2NvbnRhaW5lciBteF9WZXJpZmljYXRpb25QYW5lbF9yZWNpcHJvY2F0ZV9zZWN0aW9uXCI+XG4gICAgICAgICAgICA8aDM+e190KFwiVmVyaWZ5IGJ5IHNjYW5uaW5nXCIpfTwvaDM+XG4gICAgICAgICAgICB7IGJvZHkgfVxuICAgICAgICA8L2Rpdj47XG4gICAgfVxuXG4gICAgcHJpdmF0ZSByZW5kZXJWZXJpZmllZFBoYXNlKCkge1xuICAgICAgICBjb25zdCB7bWVtYmVyLCByZXF1ZXN0fSA9IHRoaXMucHJvcHM7XG5cbiAgICAgICAgbGV0IHRleHQ6IHN0cmluZztcbiAgICAgICAgaWYgKCFyZXF1ZXN0LmlzU2VsZlZlcmlmaWNhdGlvbikge1xuICAgICAgICAgICAgaWYgKHRoaXMucHJvcHMuaXNSb29tRW5jcnlwdGVkKSB7XG4gICAgICAgICAgICAgICAgdGV4dCA9IF90KFwiVmVyaWZ5IGFsbCB1c2VycyBpbiBhIHJvb20gdG8gZW5zdXJlIGl0J3Mgc2VjdXJlLlwiKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgdGV4dCA9IF90KFwiSW4gZW5jcnlwdGVkIHJvb21zLCB2ZXJpZnkgYWxsIHVzZXJzIHRvIGVuc3VyZSBpdOKAmXMgc2VjdXJlLlwiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGxldCBkZXNjcmlwdGlvbjogc3RyaW5nO1xuICAgICAgICBpZiAocmVxdWVzdC5pc1NlbGZWZXJpZmljYXRpb24pIHtcbiAgICAgICAgICAgIGNvbnN0IGRldmljZSA9IHRoaXMuZ2V0RGV2aWNlKCk7XG4gICAgICAgICAgICBpZiAoIWRldmljZSkge1xuICAgICAgICAgICAgICAgIC8vIFRoaXMgY2FuIGhhcHBlbiBpZiB0aGUgZGV2aWNlIGlzIGxvZ2dlZCBvdXQgd2hpbGUgd2UncmUgc3RpbGwgc2hvd2luZyB2ZXJpZmljYXRpb25cbiAgICAgICAgICAgICAgICAvLyBVSSBmb3IgaXQuXG4gICAgICAgICAgICAgICAgY29uc29sZS53YXJuKFwiVmVyaWZpZWQgZGV2aWNlIHdlIGRvbid0IGtub3cgYWJvdXQ6IFwiICsgdGhpcy5wcm9wcy5yZXF1ZXN0LmNoYW5uZWwuZGV2aWNlSWQpO1xuICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uID0gX3QoXCJZb3UndmUgc3VjY2Vzc2Z1bGx5IHZlcmlmaWVkIHlvdXIgZGV2aWNlIVwiKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gPSBfdChcIllvdSd2ZSBzdWNjZXNzZnVsbHkgdmVyaWZpZWQgJShkZXZpY2VOYW1lKXMgKCUoZGV2aWNlSWQpcykhXCIsIHtcbiAgICAgICAgICAgICAgICAgICAgZGV2aWNlTmFtZTogZGV2aWNlID8gZGV2aWNlLmdldERpc3BsYXlOYW1lKCkgOiAnJyxcbiAgICAgICAgICAgICAgICAgICAgZGV2aWNlSWQ6IHRoaXMucHJvcHMucmVxdWVzdC5jaGFubmVsLmRldmljZUlkLFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgZGVzY3JpcHRpb24gPSBfdChcIllvdSd2ZSBzdWNjZXNzZnVsbHkgdmVyaWZpZWQgJShkaXNwbGF5TmFtZSlzIVwiLCB7XG4gICAgICAgICAgICAgICAgZGlzcGxheU5hbWU6IG1lbWJlci5kaXNwbGF5TmFtZSB8fCBtZW1iZXIubmFtZSB8fCBtZW1iZXIudXNlcklkLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBBY2Nlc3NpYmxlQnV0dG9uID0gc2RrLmdldENvbXBvbmVudCgnZWxlbWVudHMuQWNjZXNzaWJsZUJ1dHRvbicpO1xuICAgICAgICByZXR1cm4gKFxuICAgICAgICAgICAgPGRpdiBjbGFzc05hbWU9XCJteF9Vc2VySW5mb19jb250YWluZXIgbXhfVmVyaWZpY2F0aW9uUGFuZWxfdmVyaWZpZWRfc2VjdGlvblwiPlxuICAgICAgICAgICAgICAgIDxoMz57X3QoXCJWZXJpZmllZFwiKX08L2gzPlxuICAgICAgICAgICAgICAgIDxwPntkZXNjcmlwdGlvbn08L3A+XG4gICAgICAgICAgICAgICAgPEUyRUljb24gaXNVc2VyPXt0cnVlfSBzdGF0dXM9XCJ2ZXJpZmllZFwiIHNpemU9ezEyOH0gaGlkZVRvb2x0aXA9e3RydWV9IC8+XG4gICAgICAgICAgICAgICAgeyB0ZXh0ID8gPHA+eyB0ZXh0IH08L3A+IDogbnVsbCB9XG4gICAgICAgICAgICAgICAgPEFjY2Vzc2libGVCdXR0b24ga2luZD1cInByaW1hcnlcIiBjbGFzc05hbWU9XCJteF9Vc2VySW5mb193aWRlQnV0dG9uXCIgb25DbGljaz17dGhpcy5wcm9wcy5vbkNsb3NlfT5cbiAgICAgICAgICAgICAgICAgICAge190KFwiR290IGl0XCIpfVxuICAgICAgICAgICAgICAgIDwvQWNjZXNzaWJsZUJ1dHRvbj5cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICApO1xuICAgIH1cblxuICAgIHByaXZhdGUgcmVuZGVyQ2FuY2VsbGVkUGhhc2UoKSB7XG4gICAgICAgIGNvbnN0IHttZW1