UNPKG

matrix-react-sdk

Version:
392 lines (385 loc) 66 kB
"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 _react = _interopRequireDefault(require("react")); var _cryptoApi = require("matrix-js-sdk/src/crypto-api"); var _logger = require("matrix-js-sdk/src/logger"); var _types = require("matrix-js-sdk/src/types"); var _MatrixClientPeg = require("../../../MatrixClientPeg"); var _VerificationQRCode = _interopRequireDefault(require("../elements/crypto/VerificationQRCode")); var _languageHandler = require("../../../languageHandler"); var _SdkConfig = _interopRequireDefault(require("../../../SdkConfig")); var _E2EIcon = _interopRequireWildcard(require("../rooms/E2EIcon")); var _Spinner = _interopRequireDefault(require("../elements/Spinner")); var _AccessibleButton = _interopRequireDefault(require("../elements/AccessibleButton")); var _VerificationShowSas = _interopRequireDefault(require("../verification/VerificationShowSas")); var _deviceInfo = require("../../../utils/crypto/deviceInfo"); function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } /* Copyright 2024 New Vector Ltd. Copyright 2019, 2020 The Matrix.org Foundation C.I.C. SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only Please see LICENSE files in the repository root for full details. */ class VerificationPanel extends _react.default.PureComponent { constructor(props) { super(props); (0, _defineProperty2.default)(this, "hasVerifier", void 0); /** have we yet tried to check the other device's info */ (0, _defineProperty2.default)(this, "haveCheckedDevice", false); /** have we yet tried to get the QR code */ (0, _defineProperty2.default)(this, "haveFetchedQRCode", false); (0, _defineProperty2.default)(this, "onReciprocateYesClick", () => { if (!this.state.reciprocateQREvent) return; this.setState({ reciprocateButtonClicked: true }); this.state.reciprocateQREvent?.confirm(); }); (0, _defineProperty2.default)(this, "onReciprocateNoClick", () => { if (!this.state.reciprocateQREvent) return; this.setState({ reciprocateButtonClicked: true }); this.state.reciprocateQREvent?.cancel(); }); (0, _defineProperty2.default)(this, "startSAS", async () => { this.setState({ emojiButtonClicked: true }); await this.props.request.startVerification(_types.VerificationMethod.Sas); }); (0, _defineProperty2.default)(this, "onSasMatchesClick", () => { this.state.sasEvent?.confirm(); }); (0, _defineProperty2.default)(this, "onSasMismatchesClick", () => { this.state.sasEvent?.mismatch(); }); (0, _defineProperty2.default)(this, "updateVerifierState", () => { // this method is only called once we know there is a verifier. const verifier = this.props.request.verifier; const sasEvent = verifier.getShowSasCallbacks(); const reciprocateQREvent = verifier.getReciprocateQrCodeCallbacks(); verifier.off(_cryptoApi.VerifierEvent.ShowSas, this.updateVerifierState); verifier.off(_cryptoApi.VerifierEvent.ShowReciprocateQr, this.updateVerifierState); this.setState({ sasEvent, reciprocateQREvent }); }); (0, _defineProperty2.default)(this, "onRequestChange", async () => { const { request } = this.props; // if we have a device ID and did not have one before, fetch the device's details this.maybeGetOtherDevice(); // if we have had a reply from the other side (ie, the phase is "ready") and we have not // yet done so, fetch the QR code if (request.phase === _cryptoApi.VerificationPhase.Ready && !this.haveFetchedQRCode) { this.haveFetchedQRCode = true; request.generateQRCode().then(buf => { this.setState({ qrCodeBytes: buf }); }, error => { console.error("Error generating QR code:", error); }); } const hadVerifier = this.hasVerifier; this.hasVerifier = !!request.verifier; if (!hadVerifier && this.hasVerifier) { request.verifier?.on(_cryptoApi.VerifierEvent.ShowSas, this.updateVerifierState); request.verifier?.on(_cryptoApi.VerifierEvent.ShowReciprocateQr, 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) { _logger.logger.error("error verify", err); } } }); this.state = { qrCodeBytes: undefined, sasEvent: null, reciprocateQREvent: null }; this.hasVerifier = false; } renderQRPhase() { const { member, request } = this.props; const showSAS = request.otherPartySupportsMethod(_types.VerificationMethod.Sas); const showQR = request.otherPartySupportsMethod(_types.VerificationMethod.ScanQrCode); const brand = _SdkConfig.default.get().brand; const noCommonMethodError = !showSAS && !showQR ? /*#__PURE__*/_react.default.createElement("p", null, (0, _languageHandler._t)("encryption|verification|no_support_qr_emoji", { brand })) : null; if (this.props.layout === "dialog") { // HACK: This is a terrible idea. let qrBlockDialog; let sasBlockDialog; if (showQR) { qrBlockDialog = /*#__PURE__*/_react.default.createElement("div", { className: "mx_VerificationPanel_QRPhase_startOption" }, /*#__PURE__*/_react.default.createElement("p", null, (0, _languageHandler._t)("encryption|verification|qr_prompt")), /*#__PURE__*/_react.default.createElement(_VerificationQRCode.default, { qrCodeBytes: this.state.qrCodeBytes })); } if (showSAS) { sasBlockDialog = /*#__PURE__*/_react.default.createElement("div", { className: "mx_VerificationPanel_QRPhase_startOption" }, /*#__PURE__*/_react.default.createElement("p", null, (0, _languageHandler._t)("encryption|verification|sas_prompt")), /*#__PURE__*/_react.default.createElement("span", { className: "mx_VerificationPanel_QRPhase_helpText" }, (0, _languageHandler._t)("encryption|verification|sas_description")), /*#__PURE__*/_react.default.createElement(_AccessibleButton.default, { disabled: this.state.emojiButtonClicked, onClick: this.startSAS, kind: "primary" }, (0, _languageHandler._t)("action|start"))); } const or = qrBlockDialog && sasBlockDialog ? /*#__PURE__*/_react.default.createElement("div", { className: "mx_VerificationPanel_QRPhase_betweenText" }, (0, _languageHandler._t)("encryption|verification|qr_or_sas", { emojiCompare: "", qrCode: "" })) : null; return /*#__PURE__*/_react.default.createElement("div", null, (0, _languageHandler._t)("encryption|verification|qr_or_sas_header"), /*#__PURE__*/_react.default.createElement("div", { className: "mx_VerificationPanel_QRPhase_startOptions" }, qrBlockDialog, or, sasBlockDialog, noCommonMethodError)); } let qrBlock; if (showQR) { qrBlock = /*#__PURE__*/_react.default.createElement("div", { className: "mx_UserInfo_container" }, /*#__PURE__*/_react.default.createElement("h3", null, (0, _languageHandler._t)("encryption|verification|scan_qr")), /*#__PURE__*/_react.default.createElement("p", null, (0, _languageHandler._t)("encryption|verification|scan_qr_explainer", { displayName: member.displayName || member.name || member.userId })), /*#__PURE__*/_react.default.createElement("div", { className: "mx_VerificationPanel_qrCode" }, /*#__PURE__*/_react.default.createElement(_VerificationQRCode.default, { qrCodeBytes: this.state.qrCodeBytes }))); } let sasBlock; if (showSAS) { const disabled = this.state.emojiButtonClicked; const sasLabel = showQR ? (0, _languageHandler._t)("encryption|verification|verify_emoji_prompt_qr") : (0, _languageHandler._t)("encryption|verification|verify_emoji_prompt"); // 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)("encryption|verification|verify_emoji")), /*#__PURE__*/_react.default.createElement("p", null, sasLabel), /*#__PURE__*/_react.default.createElement(_AccessibleButton.default, { disabled: disabled, kind: "primary", className: "mx_UserInfo_wideButton mx_VerificationPanel_verifyByEmojiButton", onClick: this.startSAS }, (0, _languageHandler._t)("encryption|verification|verify_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); } /** * Get details of the other device involved in the verification, if we haven't before, and store in the state. */ async maybeGetOtherDevice() { if (this.haveCheckedDevice) return; const client = _MatrixClientPeg.MatrixClientPeg.safeGet(); const deviceId = this.props.request?.otherDeviceId; const userId = client.getUserId(); if (!deviceId || !userId) { return; } this.haveCheckedDevice = true; this.setState({ otherDeviceDetails: await (0, _deviceInfo.getDeviceCryptoInfo)(client, userId, deviceId) }); } renderQRReciprocatePhase() { const { member, request } = this.props; const description = request.isSelfVerification ? (0, _languageHandler._t)("encryption|verification|qr_reciprocate_same_shield_device") : (0, _languageHandler._t)("encryption|verification|qr_reciprocate_same_shield_user", { displayName: member.displayName || member.name || member.userId }); let body; if (this.state.reciprocateQREvent) { // Element Web doesn't support scanning yet, so assume here we're the client being scanned. 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: _E2EIcon.E2EState.Verified, size: 128, hideTooltip: true }), /*#__PURE__*/_react.default.createElement("div", { className: "mx_VerificationPanel_reciprocateButtons" }, /*#__PURE__*/_react.default.createElement(_AccessibleButton.default, { kind: "danger", disabled: this.state.reciprocateButtonClicked, onClick: this.onReciprocateNoClick }, (0, _languageHandler._t)("action|no")), /*#__PURE__*/_react.default.createElement(_AccessibleButton.default, { kind: "primary", disabled: this.state.reciprocateButtonClicked, onClick: this.onReciprocateYesClick }, (0, _languageHandler._t)("action|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)("encryption|verification|scan_qr")), body); } renderVerifiedPhase() { const { member, request } = this.props; let text; if (!request.isSelfVerification) { if (this.props.isRoomEncrypted) { text = (0, _languageHandler._t)("encryption|verification|prompt_encrypted"); } else { text = (0, _languageHandler._t)("encryption|verification|prompt_unencrypted"); } } let description; if (request.isSelfVerification) { const device = this.state.otherDeviceDetails; if (!device) { // This can happen if the device is logged out while we're still showing verification // UI for it. _logger.logger.warn("Verified device we don't know about: " + this.props.request.otherDeviceId); description = (0, _languageHandler._t)("encryption|verification|successful_own_device"); } else { description = (0, _languageHandler._t)("encryption|verification|successful_device", { deviceName: device.displayName, deviceId: device.deviceId }); } } else { description = (0, _languageHandler._t)("encryption|verification|successful_user", { displayName: member.displayName || member.name || member.userId }); } return /*#__PURE__*/_react.default.createElement("div", { className: "mx_UserInfo_container mx_VerificationPanel_verified_section" }, /*#__PURE__*/_react.default.createElement("p", null, description), /*#__PURE__*/_react.default.createElement(_E2EIcon.default, { isUser: true, status: _E2EIcon.E2EState.Verified, size: 128, hideTooltip: true }), text ? /*#__PURE__*/_react.default.createElement("p", null, text) : null, /*#__PURE__*/_react.default.createElement(_AccessibleButton.default, { kind: "primary", className: "mx_UserInfo_wideButton", onClick: this.props.onClose }, (0, _languageHandler._t)("action|got_it"))); } renderCancelledPhase() { const { member, request } = this.props; let startAgainInstruction; if (request.isSelfVerification) { startAgainInstruction = (0, _languageHandler._t)("encryption|verification|prompt_self"); } else { startAgainInstruction = (0, _languageHandler._t)("encryption|verification|prompt_user"); } let text; if (request.cancellationCode === "m.timeout") { text = (0, _languageHandler._t)("encryption|verification|timed_out") + ` ${startAgainInstruction}`; } else if (request.cancellingUserId === request.otherUserId) { if (request.isSelfVerification) { text = (0, _languageHandler._t)("encryption|verification|cancelled_self"); } else { text = (0, _languageHandler._t)("encryption|verification|cancelled_user", { displayName: member.displayName || member.name || member.userId }); } text = `${text} ${startAgainInstruction}`; } else { text = (0, _languageHandler._t)("encryption|verification|cancelled") + ` ${startAgainInstruction}`; } return /*#__PURE__*/_react.default.createElement("div", { className: "mx_UserInfo_container" }, /*#__PURE__*/_react.default.createElement("h3", null, (0, _languageHandler._t)("common|verification_cancelled")), /*#__PURE__*/_react.default.createElement("p", null, text), /*#__PURE__*/_react.default.createElement(_AccessibleButton.default, { kind: "primary", className: "mx_UserInfo_wideButton", onClick: this.props.onClose }, (0, _languageHandler._t)("action|got_it"))); } render() { const { member, phase, request } = this.props; const displayName = member.displayName || member.name || member.userId; switch (phase) { case _cryptoApi.VerificationPhase.Ready: return this.renderQRPhase(); case _cryptoApi.VerificationPhase.Started: switch (request.chosenMethod) { case _types.VerificationMethod.Reciprocate: return this.renderQRReciprocatePhase(); case _types.VerificationMethod.Sas: { const emojis = this.state.sasEvent ? /*#__PURE__*/_react.default.createElement(_VerificationShowSas.default, { displayName: displayName, otherDeviceDetails: this.state.otherDeviceDetails, 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" }, emojis); } default: return null; } case _cryptoApi.VerificationPhase.Done: return this.renderVerifiedPhase(); case _cryptoApi.VerificationPhase.Cancelled: return this.renderCancelledPhase(); } _logger.logger.error("VerificationPanel unhandled phase:", phase); return null; } componentDidMount() { const { request } = this.props; request.on(_cryptoApi.VerificationRequestEvent.Change, this.onRequestChange); if (request.verifier) { const sasEvent = request.verifier.getShowSasCallbacks(); const reciprocateQREvent = request.verifier.getReciprocateQrCodeCallbacks(); this.setState({ sasEvent, reciprocateQREvent }); } this.onRequestChange(); } componentWillUnmount() { const { request } = this.props; if (request.verifier) { request.verifier.off(_cryptoApi.VerifierEvent.ShowSas, this.updateVerifierState); request.verifier.off(_cryptoApi.VerifierEvent.ShowReciprocateQr, this.updateVerifierState); } request.off(_cryptoApi.VerificationRequestEvent.Change, this.onRequestChange); } } exports.default = VerificationPanel; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfcmVhY3QiLCJfaW50ZXJvcFJlcXVpcmVEZWZhdWx0IiwicmVxdWlyZSIsIl9jcnlwdG9BcGkiLCJfbG9nZ2VyIiwiX3R5cGVzIiwiX01hdHJpeENsaWVudFBlZyIsIl9WZXJpZmljYXRpb25RUkNvZGUiLCJfbGFuZ3VhZ2VIYW5kbGVyIiwiX1Nka0NvbmZpZyIsIl9FMkVJY29uIiwiX2ludGVyb3BSZXF1aXJlV2lsZGNhcmQiLCJfU3Bpbm5lciIsIl9BY2Nlc3NpYmxlQnV0dG9uIiwiX1ZlcmlmaWNhdGlvblNob3dTYXMiLCJfZGV2aWNlSW5mbyIsIl9nZXRSZXF1aXJlV2lsZGNhcmRDYWNoZSIsImUiLCJXZWFrTWFwIiwiciIsInQiLCJfX2VzTW9kdWxlIiwiZGVmYXVsdCIsImhhcyIsImdldCIsIm4iLCJfX3Byb3RvX18iLCJhIiwiT2JqZWN0IiwiZGVmaW5lUHJvcGVydHkiLCJnZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IiLCJ1IiwiaGFzT3duUHJvcGVydHkiLCJjYWxsIiwiaSIsInNldCIsIlZlcmlmaWNhdGlvblBhbmVsIiwiUmVhY3QiLCJQdXJlQ29tcG9uZW50IiwiY29uc3RydWN0b3IiLCJwcm9wcyIsIl9kZWZpbmVQcm9wZXJ0eTIiLCJzdGF0ZSIsInJlY2lwcm9jYXRlUVJFdmVudCIsInNldFN0YXRlIiwicmVjaXByb2NhdGVCdXR0b25DbGlja2VkIiwiY29uZmlybSIsImNhbmNlbCIsImVtb2ppQnV0dG9uQ2xpY2tlZCIsInJlcXVlc3QiLCJzdGFydFZlcmlmaWNhdGlvbiIsIlZlcmlmaWNhdGlvbk1ldGhvZCIsIlNhcyIsInNhc0V2ZW50IiwibWlzbWF0Y2giLCJ2ZXJpZmllciIsImdldFNob3dTYXNDYWxsYmFja3MiLCJnZXRSZWNpcHJvY2F0ZVFyQ29kZUNhbGxiYWNrcyIsIm9mZiIsIlZlcmlmaWVyRXZlbnQiLCJTaG93U2FzIiwidXBkYXRlVmVyaWZpZXJTdGF0ZSIsIlNob3dSZWNpcHJvY2F0ZVFyIiwibWF5YmVHZXRPdGhlckRldmljZSIsInBoYXNlIiwiUGhhc2UiLCJSZWFkeSIsImhhdmVGZXRjaGVkUVJDb2RlIiwiZ2VuZXJhdGVRUkNvZGUiLCJ0aGVuIiwiYnVmIiwicXJDb2RlQnl0ZXMiLCJlcnJvciIsImNvbnNvbGUiLCJoYWRWZXJpZmllciIsImhhc1ZlcmlmaWVyIiwib24iLCJ2ZXJpZnkiLCJlcnIiLCJsb2dnZXIiLCJ1bmRlZmluZWQiLCJyZW5kZXJRUlBoYXNlIiwibWVtYmVyIiwic2hvd1NBUyIsIm90aGVyUGFydHlTdXBwb3J0c01ldGhvZCIsInNob3dRUiIsIlNjYW5RckNvZGUiLCJicmFuZCIsIlNka0NvbmZpZyIsIm5vQ29tbW9uTWV0aG9kRXJyb3IiLCJjcmVhdGVFbGVtZW50IiwiX3QiLCJsYXlvdXQiLCJxckJsb2NrRGlhbG9nIiwic2FzQmxvY2tEaWFsb2ciLCJjbGFzc05hbWUiLCJkaXNhYmxlZCIsIm9uQ2xpY2siLCJzdGFydFNBUyIsImtpbmQiLCJvciIsImVtb2ppQ29tcGFyZSIsInFyQ29kZSIsInFyQmxvY2siLCJkaXNwbGF5TmFtZSIsIm5hbWUiLCJ1c2VySWQiLCJzYXNCbG9jayIsInNhc0xhYmVsIiwibm9Db21tb25NZXRob2RCbG9jayIsIkZyYWdtZW50IiwiaGF2ZUNoZWNrZWREZXZpY2UiLCJjbGllbnQiLCJNYXRyaXhDbGllbnRQZWciLCJzYWZlR2V0IiwiZGV2aWNlSWQiLCJvdGhlckRldmljZUlkIiwiZ2V0VXNlcklkIiwib3RoZXJEZXZpY2VEZXRhaWxzIiwiZ2V0RGV2aWNlQ3J5cHRvSW5mbyIsInJlbmRlclFSUmVjaXByb2NhdGVQaGFzZSIsImRlc2NyaXB0aW9uIiwiaXNTZWxmVmVyaWZpY2F0aW9uIiwiYm9keSIsImlzVXNlciIsInN0YXR1cyIsIkUyRVN0YXRlIiwiVmVyaWZpZWQiLCJzaXplIiwiaGlkZVRvb2x0aXAiLCJvblJlY2lwcm9jYXRlTm9DbGljayIsIm9uUmVjaXByb2NhdGVZZXNDbGljayIsInJlbmRlclZlcmlmaWVkUGhhc2UiLCJ0ZXh0IiwiaXNSb29tRW5jcnlwdGVkIiwiZGV2aWNlIiwid2FybiIsImRldmljZU5hbWUiLCJvbkNsb3NlIiwicmVuZGVyQ2FuY2VsbGVkUGhhc2UiLCJzdGFydEFnYWluSW5zdHJ1Y3Rpb24iLCJjYW5jZWxsYXRpb25Db2RlIiwiY2FuY2VsbGluZ1VzZXJJZCIsIm90aGVyVXNlcklkIiwicmVuZGVyIiwiU3RhcnRlZCIsImNob3Nlbk1ldGhvZCIsIlJlY2lwcm9jYXRlIiwiZW1vamlzIiwic2FzIiwib25DYW5jZWwiLCJvblNhc01pc21hdGNoZXNDbGljayIsIm9uRG9uZSIsIm9uU2FzTWF0Y2hlc0NsaWNrIiwiaW5EaWFsb2ciLCJpc1NlbGYiLCJEb25lIiwiQ2FuY2VsbGVkIiwiY29tcG9uZW50RGlkTW91bnQiLCJWZXJpZmljYXRpb25SZXF1ZXN0RXZlbnQiLCJDaGFuZ2UiLCJvblJlcXVlc3RDaGFuZ2UiLCJjb21wb25lbnRXaWxsVW5tb3VudCIsImV4cG9ydHMiXSwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvY29tcG9uZW50cy92aWV3cy9yaWdodF9wYW5lbC9WZXJpZmljYXRpb25QYW5lbC50c3giXSwic291cmNlc0NvbnRlbnQiOlsiLypcbkNvcHlyaWdodCAyMDI0IE5ldyBWZWN0b3IgTHRkLlxuQ29weXJpZ2h0IDIwMTksIDIwMjAgVGhlIE1hdHJpeC5vcmcgRm91bmRhdGlvbiBDLkkuQy5cblxuU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFHUEwtMy4wLW9ubHkgT1IgR1BMLTMuMC1vbmx5XG5QbGVhc2Ugc2VlIExJQ0VOU0UgZmlsZXMgaW4gdGhlIHJlcG9zaXRvcnkgcm9vdCBmb3IgZnVsbCBkZXRhaWxzLlxuKi9cblxuaW1wb3J0IFJlYWN0IGZyb20gXCJyZWFjdFwiO1xuaW1wb3J0IHtcbiAgICBTaG93UXJDb2RlQ2FsbGJhY2tzLFxuICAgIFNob3dTYXNDYWxsYmFja3MsXG4gICAgVmVyaWZpY2F0aW9uUGhhc2UgYXMgUGhhc2UsXG4gICAgVmVyaWZpY2F0aW9uUmVxdWVzdCxcbiAgICBWZXJpZmljYXRpb25SZXF1ZXN0RXZlbnQsXG4gICAgVmVyaWZpZXJFdmVudCxcbn0gZnJvbSBcIm1hdHJpeC1qcy1zZGsvc3JjL2NyeXB0by1hcGlcIjtcbmltcG9ydCB7IERldmljZSwgUm9vbU1lbWJlciwgVXNlciB9IGZyb20gXCJtYXRyaXgtanMtc2RrL3NyYy9tYXRyaXhcIjtcbmltcG9ydCB7IGxvZ2dlciB9IGZyb20gXCJtYXRyaXgtanMtc2RrL3NyYy9sb2dnZXJcIjtcbmltcG9ydCB7IFZlcmlmaWNhdGlvbk1ldGhvZCB9IGZyb20gXCJtYXRyaXgtanMtc2RrL3NyYy90eXBlc1wiO1xuXG5pbXBvcnQgeyBNYXRyaXhDbGllbnRQZWcgfSBmcm9tIFwiLi4vLi4vLi4vTWF0cml4Q2xpZW50UGVnXCI7XG5pbXBvcnQgVmVyaWZpY2F0aW9uUVJDb2RlIGZyb20gXCIuLi9lbGVtZW50cy9jcnlwdG8vVmVyaWZpY2F0aW9uUVJDb2RlXCI7XG5pbXBvcnQgeyBfdCB9IGZyb20gXCIuLi8uLi8uLi9sYW5ndWFnZUhhbmRsZXJcIjtcbmltcG9ydCBTZGtDb25maWcgZnJvbSBcIi4uLy4uLy4uL1Nka0NvbmZpZ1wiO1xuaW1wb3J0IEUyRUljb24sIHsgRTJFU3RhdGUgfSBmcm9tIFwiLi4vcm9vbXMvRTJFSWNvblwiO1xuaW1wb3J0IFNwaW5uZXIgZnJvbSBcIi4uL2VsZW1lbnRzL1NwaW5uZXJcIjtcbmltcG9ydCBBY2Nlc3NpYmxlQnV0dG9uIGZyb20gXCIuLi9lbGVtZW50cy9BY2Nlc3NpYmxlQnV0dG9uXCI7XG5pbXBvcnQgVmVyaWZpY2F0aW9uU2hvd1NhcyBmcm9tIFwiLi4vdmVyaWZpY2F0aW9uL1ZlcmlmaWNhdGlvblNob3dTYXNcIjtcbmltcG9ydCB7IGdldERldmljZUNyeXB0b0luZm8gfSBmcm9tIFwiLi4vLi4vLi4vdXRpbHMvY3J5cHRvL2RldmljZUluZm9cIjtcblxuaW50ZXJmYWNlIElQcm9wcyB7XG4gICAgbGF5b3V0OiBzdHJpbmc7XG4gICAgcmVxdWVzdDogVmVyaWZpY2F0aW9uUmVxdWVzdDtcbiAgICBtZW1iZXI6IFJvb21NZW1iZXIgfCBVc2VyO1xuICAgIHBoYXNlPzogUGhhc2U7XG4gICAgb25DbG9zZTogKCkgPT4gdm9pZDtcbiAgICBpc1Jvb21FbmNyeXB0ZWQ6IGJvb2xlYW47XG4gICAgaW5EaWFsb2c6IGJvb2xlYW47XG59XG5cbmludGVyZmFjZSBJU3RhdGUge1xuICAgIC8qKlxuICAgICAqIFRoZSBkYXRhIGZvciB0aGUgUVIgY29kZSB0byBkaXNwbGF5LlxuICAgICAqXG4gICAgICogV2UgYXR0ZW1wdCB0byBjYWxjdWxhdGUgdGhpcyBvbmNlIHRoZSB2ZXJpZmljYXRpb24gcmVxdWVzdCB0cmFuc2l0aW9ucyBpbnRvIHRoZSBcIlJlYWR5XCIgcGhhc2UuIElmIHRoZSBvdGhlclxuICAgICAqIHNpZGUgY2Fubm90IHNjYW4gUVIgY29kZXMsIGl0IHdpbGwgcmVtYWluIGB1bmRlZmluZWRgLlxuICAgICAqL1xuICAgIHFyQ29kZUJ5dGVzOiBCdWZmZXIgfCB1bmRlZmluZWQ7XG5cbiAgICBzYXNFdmVudDogU2hvd1Nhc0NhbGxiYWNrcyB8IG51bGw7XG4gICAgZW1vamlCdXR0b25DbGlja2VkPzogYm9vbGVhbjtcbiAgICByZWNpcHJvY2F0ZUJ1dHRvbkNsaWNrZWQ/OiBib29sZWFuO1xuICAgIHJlY2lwcm9jYXRlUVJFdmVudDogU2hvd1FyQ29kZUNhbGxiYWNrcyB8IG51bGw7XG5cbiAgICAvKipcbiAgICAgKiBEZXRhaWxzIG9mIHRoZSBvdGhlciBkZXZpY2UgaW52b2x2ZWQgaW4gdGhlIHRyYW5zYWN0aW9uLlxuICAgICAqXG4gICAgICogYHVuZGVmaW5lZGAgaWYgdGhlcmUgaXMgbm90ICh5ZXQpIGFub3RoZXIgZGV2aWNlIGluIHRoZSB0cmFuc2FjdGlvbiwgb3IgaWYgd2UgZG8gbm90IGtub3cgYWJvdXQgaXQuXG4gICAgICovXG4gICAgb3RoZXJEZXZpY2VEZXRhaWxzPzogRGV2aWNlO1xufVxuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBWZXJpZmljYXRpb25QYW5lbCBleHRlbmRzIFJlYWN0LlB1cmVDb21wb25lbnQ8SVByb3BzLCBJU3RhdGU+IHtcbiAgICBwcml2YXRlIGhhc1ZlcmlmaWVyOiBib29sZWFuO1xuXG4gICAgLyoqIGhhdmUgd2UgeWV0IHRyaWVkIHRvIGNoZWNrIHRoZSBvdGhlciBkZXZpY2UncyBpbmZvICovXG4gICAgcHJpdmF0ZSBoYXZlQ2hlY2tlZERldmljZSA9IGZhbHNlO1xuXG4gICAgLyoqIGhhdmUgd2UgeWV0IHRyaWVkIHRvIGdldCB0aGUgUVIgY29kZSAqL1xuICAgIHByaXZhdGUgaGF2ZUZldGNoZWRRUkNvZGUgPSBmYWxzZTtcblxuICAgIHB1YmxpYyBjb25zdHJ1Y3Rvcihwcm9wczogSVByb3BzKSB7XG4gICAgICAgIHN1cGVyKHByb3BzKTtcbiAgICAgICAgdGhpcy5zdGF0ZSA9IHsgcXJDb2RlQnl0ZXM6IHVuZGVmaW5lZCwgc2FzRXZlbnQ6IG51bGwsIHJlY2lwcm9jYXRlUVJFdmVudDogbnVsbCB9O1xuICAgICAgICB0aGlzLmhhc1ZlcmlmaWVyID0gZmFsc2U7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSByZW5kZXJRUlBoYXNlKCk6IEpTWC5FbGVtZW50IHtcbiAgICAgICAgY29uc3QgeyBtZW1iZXIsIHJlcXVlc3QgfSA9IHRoaXMucHJvcHM7XG4gICAgICAgIGNvbnN0IHNob3dTQVM6IGJvb2xlYW4gPSByZXF1ZXN0Lm90aGVyUGFydHlTdXBwb3J0c01ldGhvZChWZXJpZmljYXRpb25NZXRob2QuU2FzKTtcbiAgICAgICAgY29uc3Qgc2hvd1FSOiBib29sZWFuID0gcmVxdWVzdC5vdGhlclBhcnR5U3VwcG9ydHNNZXRob2QoVmVyaWZpY2F0aW9uTWV0aG9kLlNjYW5RckNvZGUpO1xuICAgICAgICBjb25zdCBicmFuZCA9IFNka0NvbmZpZy5nZXQoKS5icmFuZDtcblxuICAgICAgICBjb25zdCBub0NvbW1vbk1ldGhvZEVycm9yOiBKU1guRWxlbWVudCB8IG51bGwgPVxuICAgICAgICAgICAgIXNob3dTQVMgJiYgIXNob3dRUiA/IDxwPntfdChcImVuY3J5cHRpb258dmVyaWZpY2F0aW9ufG5vX3N1cHBvcnRfcXJfZW1vamlcIiwgeyBicmFuZCB9KX08L3A+IDogbnVsbDtcblxuICAgICAgICBpZiAodGhpcy5wcm9wcy5sYXlvdXQgPT09IFwiZGlhbG9nXCIpIHtcbiAgICAgICAgICAgIC8vIEhBQ0s6IFRoaXMgaXMgYSB0ZXJyaWJsZSBpZGVhLlxuICAgICAgICAgICAgbGV0IHFyQmxvY2tEaWFsb2c6IEpTWC5FbGVtZW50IHwgdW5kZWZpbmVkO1xuICAgICAgICAgICAgbGV0IHNhc0Jsb2NrRGlhbG9nOiBKU1guRWxlbWVudCB8IHVuZGVmaW5lZDtcbiAgICAgICAgICAgIGlmIChzaG93UVIpIHtcbiAgICAgICAgICAgICAgICBxckJsb2NrRGlhbG9nID0gKFxuICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzTmFtZT1cIm14X1ZlcmlmaWNhdGlvblBhbmVsX1FSUGhhc2Vfc3RhcnRPcHRpb25cIj5cbiAgICAgICAgICAgICAgICAgICAgICAgIDxwPntfdChcImVuY3J5cHRpb258dmVyaWZpY2F0aW9ufHFyX3Byb21wdFwiKX08L3A+XG4gICAgICAgICAgICAgICAgICAgICAgICA8VmVyaWZpY2F0aW9uUVJDb2RlIHFyQ29kZUJ5dGVzPXt0aGlzLnN0YXRlLnFyQ29kZUJ5dGVzfSAvPlxuICAgICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHNob3dTQVMpIHtcbiAgICAgICAgICAgICAgICBzYXNCbG9ja0RpYWxvZyA9IChcbiAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzc05hbWU9XCJteF9WZXJpZmljYXRpb25QYW5lbF9RUlBoYXNlX3N0YXJ0T3B0aW9uXCI+XG4gICAgICAgICAgICAgICAgICAgICAgICA8cD57X3QoXCJlbmNyeXB0aW9ufHZlcmlmaWNhdGlvbnxzYXNfcHJvbXB0XCIpfTwvcD5cbiAgICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzTmFtZT1cIm14X1ZlcmlmaWNhdGlvblBhbmVsX1FSUGhhc2VfaGVscFRleHRcIj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB7X3QoXCJlbmNyeXB0aW9ufHZlcmlmaWNhdGlvbnxzYXNfZGVzY3JpcHRpb25cIil9XG4gICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4+XG4gICAgICAgICAgICAgICAgICAgICAgICA8QWNjZXNzaWJsZUJ1dHRvblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpc2FibGVkPXt0aGlzLnN0YXRlLmVtb2ppQnV0dG9uQ2xpY2tlZH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbkNsaWNrPXt0aGlzLnN0YXJ0U0FTfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtpbmQ9XCJwcmltYXJ5XCJcbiAgICAgICAgICAgICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB7X3QoXCJhY3Rpb258c3RhcnRcIil9XG4gICAgICAgICAgICAgICAgICAgICAgICA8L0FjY2Vzc2libGVCdXR0b24+XG4gICAgICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25zdCBvciA9XG4gICAgICAgICAgICAgICAgcXJCbG9ja0RpYWxvZyAmJiBzYXNCbG9ja0RpYWxvZyA/IChcbiAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzc05hbWU9XCJteF9WZXJpZmljYXRpb25QYW5lbF9RUlBoYXNlX2JldHdlZW5UZXh0XCI+XG4gICAgICAgICAgICAgICAgICAgICAgICB7X3QoXCJlbmNyeXB0aW9ufHZlcmlmaWNhdGlvbnxxcl9vcl9zYXNcIiwge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVtb2ppQ29tcGFyZTogXCJcIixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBxckNvZGU6IFwiXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICB9KX1cbiAgICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgKSA6IG51bGw7XG4gICAgICAgICAgICByZXR1cm4gKFxuICAgICAgICAgICAgICAgIDxkaXY+XG4gICAgICAgICAgICAgICAgICAgIHtfdChcImVuY3J5cHRpb258dmVyaWZpY2F0aW9ufHFyX29yX3Nhc19oZWFkZXJcIil9XG4gICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3NOYW1lPVwibXhfVmVyaWZpY2F0aW9uUGFuZWxfUVJQaGFzZV9zdGFydE9wdGlvbnNcIj5cbiAgICAgICAgICAgICAgICAgICAgICAgIHtxckJsb2NrRGlhbG9nfVxuICAgICAgICAgICAgICAgICAgICAgICAge29yfVxuICAgICAgICAgICAgICAgICAgICAgICAge3Nhc0Jsb2NrRGlhbG9nfVxuICAgICAgICAgICAgICAgICAgICAgICAge25vQ29tbW9uTWV0aG9kRXJyb3J9XG4gICAgICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGxldCBxckJsb2NrOiBKU1guRWxlbWVudCB8IHVuZGVmaW5lZDtcbiAgICAgICAgaWYgKHNob3dRUikge1xuICAgICAgICAgICAgcXJCbG9jayA9IChcbiAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzTmFtZT1cIm14X1VzZXJJbmZvX2NvbnRhaW5lclwiPlxuICAgICAgICAgICAgICAgICAgICA8aDM+e190KFwiZW5jcnlwdGlvbnx2ZXJpZmljYXRpb258c2Nhbl9xclwiKX08L2gzPlxuICAgICAgICAgICAgICAgICAgICA8cD5cbiAgICAgICAgICAgICAgICAgICAgICAgIHtfdChcImVuY3J5cHRpb258dmVyaWZpY2F0aW9ufHNjYW5fcXJfZXhwbGFpbmVyXCIsIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXNwbGF5TmFtZTogKG1lbWJlciBhcyBVc2VyKS5kaXNwbGF5TmFtZSB8fCAobWVtYmVyIGFzIFJvb21NZW1iZXIpLm5hbWUgfHwgbWVtYmVyLnVzZXJJZCxcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pfVxuICAgICAgICAgICAgICAgICAgICA8L3A+XG5cbiAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzc05hbWU9XCJteF9WZXJpZmljYXRpb25QYW5lbF9xckNvZGVcIj5cbiAgICAgICAgICAgICAgICAgICAgICAgIDxWZXJpZmljYXRpb25RUkNvZGUgcXJDb2RlQnl0ZXM9e3RoaXMuc3RhdGUucXJDb2RlQnl0ZXN9IC8+XG4gICAgICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGxldCBzYXNCbG9jazogSlNYLkVsZW1lbnQgfCB1bmRlZmluZWQ7XG4gICAgICAgIGlmIChzaG93U0FTKSB7XG4gICAgICAgICAgICBjb25zdCBkaXNhYmxlZCA9IHRoaXMuc3RhdGUuZW1vamlCdXR0b25DbGlja2VkO1xuICAgICAgICAgICAgY29uc3Qgc2FzTGFiZWwgPSBzaG93UVJcbiAgICAgICAgICAgICAgICA/IF90KFwiZW5jcnlwdGlvbnx2ZXJpZmljYXRpb258dmVyaWZ5X2Vtb2ppX3Byb21wdF9xclwiKVxuICAgICAgICAgICAgICAgIDogX3QoXCJlbmNyeXB0aW9ufHZlcmlmaWNhdGlvbnx2ZXJpZnlfZW1vamlfcHJvbXB0XCIpO1xuXG4gICAgICAgICAgICAvLyBOb3RlOiBteF9WZXJpZmljYXRpb25QYW5lbF92ZXJpZnlCeUVtb2ppQnV0dG9uIGlzIGZvciB0aGUgZW5kLXRvLWVuZCB0ZXN0c1xuICAgICAgICAgICAgc2FzQmxvY2sgPSAoXG4gICAgICAgICAgICAgICAgPGRpdiBjbGFzc05hbWU9XCJteF9Vc2VySW5mb19jb250YWluZXJcIj5cbiAgICAgICAgICAgICAgICAgICAgPGgzPntfdChcImVuY3J5cHRpb258dmVyaWZpY2F0aW9ufHZlcmlmeV9lbW9qaVwiKX08L2gzPlxuICAgICAgICAgICAgICAgICAgICA8cD57c2FzTGFiZWx9PC9wPlxuICAgICAgICAgICAgICAgICAgICA8QWNjZXNzaWJsZUJ1dHRvblxuICAgICAgICAgICAgICAgICAgICAgICAgZGlzYWJsZWQ9e2Rpc2FibGVkfVxuICAgICAgICAgICAgICAgICAgICAgICAga2luZD1cInByaW1hcnlcIlxuICAgICAgICAgICAgICAgICAgICAgICAgY2xhc3NOYW1lPVwibXhfVXNlckluZm9fd2lkZUJ1dHRvbiBteF9WZXJpZmljYXRpb25QYW5lbF92ZXJpZnlCeUVtb2ppQnV0dG9uXCJcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uQ2xpY2s9e3RoaXMuc3RhcnRTQVN9XG4gICAgICAgICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICAgICAgICAgIHtfdChcImVuY3J5cHRpb258dmVyaWZpY2F0aW9ufHZlcmlmeV9lbW9qaVwiKX1cbiAgICAgICAgICAgICAgICAgICAgPC9BY2Nlc3NpYmxlQnV0dG9uPlxuICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IG5vQ29tbW9uTWV0aG9kQmxvY2sgPSBub0NvbW1vbk1ldGhvZEVycm9yID8gKFxuICAgICAgICAgICAgPGRpdiBjbGFzc05hbWU9XCJteF9Vc2VySW5mb19jb250YWluZXJcIj57bm9Db21tb25NZXRob2RFcnJvcn08L2Rpdj5cbiAgICAgICAgKSA6IG51bGw7XG5cbiAgICAgICAgLy8gVE9ETzogYWRkIHdheSB0byBvcGVuIGNhbWVyYSB0byBzY2FuIGEgUVIgY29kZVxuICAgICAgICByZXR1cm4gKFxuICAgICAgICAgICAgPFJlYWN0LkZyYWdtZW50PlxuICAgICAgICAgICAgICAgIHtxckJsb2NrfVxuICAgICAgICAgICAgICAgIHtzYXNCbG9ja31cbiAgICAgICAgICAgICAgICB7bm9Db21tb25NZXRob2RCbG9ja31cbiAgICAgICAgICAgIDwvUmVhY3QuRnJhZ21lbnQ+XG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBvblJlY2lwcm9jYXRlWWVzQ2xpY2sgPSAoKTogdm9pZCA9PiB7XG4gICAgICAgIGlmICghdGhpcy5zdGF0ZS5yZWNpcHJvY2F0ZVFSRXZlbnQpIHJldHVybjtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7IHJlY2lwcm9jYXRlQnV0dG9uQ2xpY2tlZDogdHJ1ZSB9KTtcbiAgICAgICAgdGhpcy5zdGF0ZS5yZWNpcHJvY2F0ZVFSRXZlbnQ/LmNvbmZpcm0oKTtcbiAgICB9O1xuXG4gICAgcHJpdmF0ZSBvblJlY2lwcm9jYXRlTm9DbGljayA9ICgpOiB2b2lkID0+IHtcbiAgICAgICAgaWYgKCF0aGlzLnN0YXRlLnJlY2lwcm9jYXRlUVJFdmVudCkgcmV0dXJuO1xuICAgICAgICB0aGlzLnNldFN0YXRlKHsgcmVjaXByb2NhdGVCdXR0b25DbGlja2VkOiB0cnVlIH0pO1xuICAgICAgICB0aGlzLnN0YXRlLnJlY2lwcm9jYXRlUVJFdmVudD8uY2FuY2VsKCk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIEdldCBkZXRhaWxzIG9mIHRoZSBvdGhlciBkZXZpY2UgaW52b2x2ZWQgaW4gdGhlIHZlcmlmaWNhdGlvbiwgaWYgd2UgaGF2ZW4ndCBiZWZvcmUsIGFuZCBzdG9yZSBpbiB0aGUgc3RhdGUuXG4gICAgICovXG4gICAgcHJpdmF0ZSBhc3luYyBtYXliZUdldE90aGVyRGV2aWNlKCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBpZiAodGhpcy5oYXZlQ2hlY2tlZERldmljZSkgcmV0dXJuO1xuXG4gICAgICAgIGNvbnN0IGNsaWVudCA9IE1hdHJpeENsaWVudFBlZy5zYWZlR2V0KCk7XG4gICAgICAgIGNvbnN0IGRldmljZUlkID0gdGhpcy5wcm9wcy5yZXF1ZXN0Py5vdGhlckRldmljZUlkO1xuICAgICAgICBjb25zdCB1c2VySWQgPSBjbGllbnQuZ2V0VXNlcklkKCk7XG4gICAgICAgIGlmICghZGV2aWNlSWQgfHwgIXVzZXJJZCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuaGF2ZUNoZWNrZWREZXZpY2UgPSB0cnVlO1xuICAgICAgICB0aGlzLnNldFN0YXRlKHsgb3RoZXJEZXZpY2VEZXRhaWxzOiBhd2FpdCBnZXREZXZpY2VDcnlwdG9JbmZvKGNsaWVudCwgdXNlcklkLCBkZXZpY2VJZCkgfSk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSByZW5kZXJRUlJlY2lwcm9jYXRlUGhhc2UoKTogSlNYLkVsZW1lbnQge1xuICAgICAgICBjb25zdCB7IG1lbWJlciwgcmVxdWVzdCB9ID0gdGhpcy5wcm9wcztcbiAgICAgICAgY29uc3QgZGVzY3JpcHRpb24gPSByZXF1ZXN0LmlzU2VsZlZlcmlmaWNhdGlvblxuICAgICAgICAgICAgPyBfdChcImVuY3J5cHRpb258dmVyaWZpY2F0aW9ufHFyX3JlY2lwcm9jYXRlX3NhbWVfc2hpZWxkX2RldmljZVwiKVxuICAgICAgICAgICAgOiBfdChcImVuY3J5cHRpb258dmVyaWZpY2F0aW9ufHFyX3JlY2lwcm9jYXRlX3NhbWVfc2hpZWxkX3VzZXJcIiwge1xuICAgICAgICAgICAgICAgICAgZGlzcGxheU5hbWU6IChtZW1iZXIgYXMgVXNlcikuZGlzcGxheU5hbWUgfHwgKG1lbWJlciBhcyBSb29tTWVtYmVyKS5uYW1lIHx8IG1lbWJlci51c2VySWQsXG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICBsZXQgYm9keTogSlNYLkVsZW1lbnQ7XG4gICAgICAgIGlmICh0aGlzLnN0YXRlLnJlY2lwcm9jYXRlUVJFdmVudCkge1xuICAgICAgICAgICAgLy8gRWxlbWVudCBXZWIgZG9lc24ndCBzdXBwb3J0IHNjYW5uaW5nIHlldCwgc28gYXNzdW1lIGhlcmUgd2UncmUgdGhlIGNsaWVudCBiZWluZyBzY2FubmVkLlxuICAgICAgICAgICAgYm9keSA9IChcbiAgICAgICAgICAgICAgICA8UmVhY3QuRnJhZ21lbnQ+XG4gICAgICAgICAgICAgICAgICAgIDxwPntkZXNjcmlwdGlvbn08L3A+XG4gICAgICAgICAgICAgICAgICAgIDxFMkVJY29uIGlzVXNlcj17dHJ1ZX0gc3RhdHVzPXtFMkVTdGF0ZS5WZXJpZmllZH0gc2l6ZT17MTI4fSBoaWRlVG9vbHRpcD17dHJ1ZX0gLz5cbiAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzc05hbWU9XCJteF9WZXJpZmljYXRpb25QYW5lbF9yZWNpcHJvY2F0ZUJ1dHRvbnNcIj5cbiAgICAgICAgICAgICAgICAgICAgICAgIDxBY2Nlc3NpYmxlQnV0dG9uXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAga2luZD1cImRhbmdlclwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlzYWJsZWQ9e3RoaXMuc3RhdGUucmVjaXByb2NhdGVCdXR0b25DbGlja2VkfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9uQ2xpY2s9e3RoaXMub25SZWNpcHJvY2F0ZU5vQ2xpY2t9XG4gICAgICAgICAgICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAge190KFwiYWN0aW9ufG5vXCIpfVxuICAgICAgICAgICAgICAgICAgICAgICAgPC9BY2Nlc3NpYmxlQnV0dG9uPlxuICAgICAgICAgICAgICAgICAgICAgICAgPEFjY2Vzc2libGVCdXR0b25cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBraW5kPVwicHJpbWFyeVwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlzYWJsZWQ9e3RoaXMuc3RhdGUucmVjaXByb2NhdGVCdXR0b25DbGlja2VkfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9uQ2xpY2s9e3RoaXMub25SZWNpcHJvY2F0ZVllc0NsaWNrfVxuICAgICAgICAgICAgICAgICAgICAgICAgPlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHtfdChcImFjdGlvbnx5ZXNcIil9XG4gICAgICAgICAgICAgICAgICAgICAgICA8L0FjY2Vzc2libGVCdXR0b24+XG4gICAgICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgICAgIDwvUmVhY3QuRnJhZ21lbnQ+XG4gICAgICAgICAgICApO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgYm9keSA9IChcbiAgICAgICAgICAgICAgICA8cD5cbiAgICAgICAgICAgICAgICAgICAgPFNwaW5uZXIgLz5cbiAgICAgICAgICAgICAgICA8L3A+XG4gICAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiAoXG4gICAgICAgICAgICA8ZGl2IGNsYXNzTmFtZT1cIm14X1VzZXJJbmZvX2NvbnRhaW5lciBteF9WZXJpZmljYXRpb25QYW5lbF9yZWNpcHJvY2F0ZV9zZWN0aW9uXCI+XG4gICAgICAgICAgICAgICAgPGgzPntfdChcImVuY3J5cHRpb258dmVyaWZpY2F0aW9ufHNjYW5fcXJcIil9PC9oMz5cbiAgICAgICAgICAgICAgICB7Ym9keX1cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICApO1xuICAgIH1cblxuICAgIHByaXZhdGUgcmVuZGVyVmVyaWZpZWRQaGFzZSgpOiBKU1guRWxlbWVudCB7XG4gICAgICAgIGNvbnN0IHsgbWVtYmVyLCByZXF1ZXN0IH0gPSB0aGlzLnByb3BzO1xuXG4gICAgICAgIGxldCB0ZXh0OiBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gICAgICAgIGlmICghcmVxdWVzdC5pc1NlbGZWZXJpZmljYXRpb24pIHtcbiAgICAgICAgICAgIGlmICh0aGlzLnByb3BzLmlzUm9vbUVuY3J5cHRlZCkge1xuICAgICAgICAgICAgICAgIHRleHQgPSBfdChcImVuY3J5cHRpb258dmVyaWZpY2F0aW9ufHByb21wdF9lbmNyeXB0ZWRcIik7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRleHQgPSBfdChcImVuY3J5cHRpb258dmVyaWZpY2F0aW9ufHByb21wdF91bmVuY3J5cHRlZFwiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGxldCBkZXNjcmlwdGlvbjogc3RyaW5nO1xuICAgICAgICBpZiAocmVxdWVzdC5pc1NlbGZWZXJpZmljYXRpb24pIHtcbiAgICAgICAgICAgIGNvbnN0IGRldmljZSA9IHRoaXMuc3RhdGUub3RoZXJEZXZpY2VEZXRhaWxzO1xuICAgICAgICAgICAgaWYgKCFkZXZpY2UpIHtcbiAgICAgICAgICAgICAgICAvLyBUaGlzIGNhbiBoYXBwZW4gaWYgdGhlIGRldmljZSBpcyBsb2dnZWQgb3V0IHdoaWxlIHdlJ3JlIHN0aWxsIHNob3dpbmcgdmVyaWZpY2F0aW9uXG4gICAgICAgICAgICAgICAgLy8gVUkgZm9yIGl0LlxuICAgICAgICAgICAgICAgIGxvZ2dlci53YXJuKFwiVmVyaWZpZWQgZGV2aWNlIHdlIGRvbid0IGtub3cgYWJvdXQ6IFwiICsgdGhpcy5wcm9wcy5yZXF1ZXN0Lm90aGVyRGV2aWNlSWQpO1xuICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uID0gX3QoXCJlbmNyeXB0aW9ufHZlcmlmaWNhdGlvbnxzdWNjZXNzZnVsX293bl9kZXZpY2VcIik7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uID0gX3QoXCJlbmNyeXB0aW9ufHZlcmlmaWNhdGlvbnxzdWNjZXNzZnVsX2RldmljZVwiLCB7XG4gICAgICAgICAgICAgICAgICAgIGRldmljZU5hbWU6IGRldmljZS5kaXNwbGF5TmFtZSxcbiAgICAgICAgICAgICAgICAgICAgZGV2aWNlSWQ6IGRldmljZS5kZXZpY2VJZCxcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGRlc2NyaXB0aW9uID0gX3QoXCJlbmNyeXB0aW9ufHZlcmlmaWNhdGlvbnxzdWNjZXNzZnVsX3VzZXJcIiwge1xuICAgICAgICAgICAgICAgIGRpc3BsYXlOYW1lOiAobWVtYmVyIGFzIFVzZXIpLmRpc3BsYXlOYW1lIHx8IChtZW1iZXIgYXMgUm9vbU1lbWJlcikubmFtZSB8fCBtZW1iZXIudXNlcklkLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gKFxuICAgICAgICAgICAgPGRpdiBjbGFzc05hbWU9XCJteF9Vc2VySW5mb19jb250YWluZXIgbXhfVmVyaWZpY2F0aW9uUGFuZWxfdmVyaWZpZWRfc2VjdGlvblwiPlxuICAgICAgICAgICAgICAgIDxwPntkZXNjcmlwdGlvbn08L3A+XG4gICAgICAgICAgICAgICAgPEUyRUljb24gaXNVc2VyPXt0cnVlfSBzdGF0dXM9e0UyRVN0YXRlLlZlcmlmaWVkfSBzaXplPXsxMjh9IGhpZGVUb29sdGlwPXt0cnVlfSAvPlxuICAgICAgICAgICAgICAgIHt0ZXh0ID8gPHA+e3RleHR9PC9wPiA6IG51bGx9XG4gICAgICAgICAgICAgICAgPEFjY2Vzc2libGVCdXR0b24ga2luZD1cInByaW1hcnlcIiBjbGFzc05hbWU9XCJteF9Vc2VySW5mb193aWRlQnV0dG9uXCIgb25DbGljaz17dGhpcy5wcm9wcy5vbkNsb3NlfT5cbiAgICAgICAgICAgICAgICAgICAge190KFwiYWN0aW9ufGdvdF9pdFwiKX1cbiAgICAgICAgICAgICAgICA8L0FjY2Vzc2libGVCdXR0b24+XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIHJlbmRlckNhbmNlbGxlZFBoYXNlKCk6IEpTWC5FbGVtZW50IHtcbiAgICAgICAgY29uc3QgeyBtZW1iZXIsIHJlcXVlc3QgfSA9IHRoaXMucHJvcHM7XG5cbiAgICAgICAgbGV0IHN0YXJ0QWdhaW5JbnN0cnVjdGlvbjogc3RyaW5nO1xuICAgICAgICBpZiAocmVxdWVzdC5pc1NlbGZWZXJpZmljYXRpb24pIHtcbiAgICAgICAgICAgIHN0YXJ0QWdhaW5JbnN0cnVjdGlvbiA9IF90KFwiZW5jcnlwdGlvbnx2ZXJpZmljYXRpb258cHJvbXB0X3NlbGZcIik7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBzdGFydEFnYWluSW5zdHJ1Y3Rpb24gPSBfdChcImVuY3J5cHRpb258dmVyaWZpY2F0aW9ufHByb21wdF91c2VyXCIpO1xuICAgICAgICB9XG5cbiAgICAgICAgbGV0IHRleHQ6IHN0cmluZztcbiAgICAgICAgaWYgKHJlcXVlc3QuY2FuY2VsbGF0aW9uQ29kZSA9PT0gXCJtLnRpbWVvdXRcIikge1xuICAgICAgICAgICAgdGV4dCA9IF90KFwiZW5jcnlwdGlvbnx2ZXJpZmljYXRpb258dGltZWRfb3V0XCIpICsgYCAke3N0YXJ0QWdhaW5JbnN0cnVjdGlvbn1gO1xuICAgICAgICB9IGVsc2UgaWYgKHJlcXVlc3QuY2FuY2VsbGluZ1VzZXJJZCA9PT0gcmVxdWVzdC5vdGhlclVzZXJJZCkge1xuICAgICAgICAgICAgaWYgKHJlcXVlc3QuaXNTZWxmVmVyaWZpY2F0aW9uKSB7XG4gICAgICAgICAgICAgICAgdGV4dCA9IF90KFwiZW5jcnlwdGlvbnx2ZXJpZmljYXRpb258Y2FuY2VsbGVkX3NlbGZcIik7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRleHQgPSBfdChcImVuY3J5cHRpb258dmVyaWZpY2F0aW9ufGNhbmNlbGxlZF91c2VyXCIsIHtcbiAgICAgICAgICAgICAgICAgICAgZGlzcGxheU5hbWU6IChtZW1iZXIgYXMgVXNlcikuZGlzcGxheU5hbWUgfHwgKG1lbWJlciBhcyBSb29tTWVtYmVyKS5uYW1lIHx8IG1lbWJlci51c2VySWQsXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0ZXh0ID0gYCR7dGV4dH0gJHtzdGFydEFnYWluSW5zdHJ1Y3Rpb259YDtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRleHQgPSBfdChcImVuY3J5cHRpb258dmVyaWZpY2F0aW9ufGNhbmNlbGxlZFwiKSArIGAgJHtzdGFydEFnYWluSW5zdHJ1Y3Rpb259YDtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiAoXG4gICAgICAgICAgICA8ZGl2IGNsYXNzTmFtZT1cIm14X1VzZXJJbmZvX2NvbnRhaW5lclwiPlxuICAgICAgICAgICAgICAgIDxoMz57X3QoXCJjb21tb258dmVyaWZpY2F0aW9uX2NhbmNlbGxlZFwiKX08L2gzPlxuICAgICAgICAgICAgICAgIDxwPnt0ZXh0fTwvcD5cblxuICAgICAgICAgICAgICAgIDxBY2Nlc3NpYmxlQnV0dG9uIGtpbmQ9XCJwcmltYXJ5XCIgY2xhc3NOYW1lPVwibXhfVXNlckluZm9fd2lkZUJ1dHRvblwiIG9uQ2xpY2s9e3RoaXMucHJvcHMub25DbG9zZX0+XG4gICAgICAgICAgICAgICAgICAgIHtfdChcImFjdGlvbnxnb3RfaXRcIil9XG4gICAgICAgICAgICAgICAgPC9BY2Nlc3NpYmxlQnV0dG9uPlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgcHVibGljIHJlbmRlcigpOiBSZWFjdC5SZWFjdE5vZGUge1xuICAgICAgICBjb25zdCB7IG1lbWJlciwgcGhhc2UsIHJlcXVlc3QgfSA9IHRoaXMucHJvcHM7XG5cbiAgICAgICAgY29uc3QgZGlzcGxheU5hbWUgPSAobWVtYmVyIGFzIFVzZXIpLmRpc3BsYXlOYW1lIHx8IChtZW1iZXIgYXMgUm9vbU1lbWJlcikubmFtZSB8fCBtZW1iZXIudXNlcklkO1xuXG4gICAgICAgIHN3aXRjaCAocGhhc2UpIHtcbiAgICAgICAgICAgIGNhc2UgUGhhc2UuUmVhZHk6XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMucmVuZGVyUVJQaGFzZSgpO1xuICAgICAgICAgICAgY2FzZSBQaGFzZS5TdGFydGVkOlxuICAgICAgICAgICAgICAgIHN3aXRjaCAocmVxdWVzdC5jaG9zZW5NZXRob2QpIHtcbiAgICAgICAgICAgICAgICAgICAgY2FzZSBWZXJpZmljYXRpb25NZXRob2QuUmVjaXByb2NhdGU6XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5yZW5kZXJRUlJlY2lwcm9jYXRlUGhhc2UoKTtcbiAgICAgICAgICAgICAgICAgICAgY2FzZSBWZXJpZmljYXRpb25NZXRob2QuU2FzOiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBlbW9qaXMgPSB0aGlzLnN0YXRlLnNhc0V2ZW50ID8gKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxWZXJpZmljYXRpb25TaG93U2FzXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpc3BsYXlOYW1lPXtkaXNwbGF5TmFtZX1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3RoZXJEZXZpY2VEZXRhaWxzPXt0aGlzLnN0YXRlLm90aGVyRGV2aWNlRGV0YWlsc31cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2FzPXt0aGlzLnN0YXRlLnNhc0V2ZW50LnNhc31cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb25DYW5jZWw9e3RoaXMub25TYXNNaXNtYXRjaGVzQ2xpY2t9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9uRG9uZT17dGhpcy5vblNhc01hdGNoZXNDbGlja31cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5EaWFsb2c9e3RoaXMucHJvcHMuaW5EaWFsb2d9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlzU2VsZj17cmVxdWVzdC5pc1NlbGZWZXJpZmljYXRpb259XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLz5cbiAgICAgICAgICAgICAgICAgICAgICAgICkgOiAoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPFNwaW5uZXIgLz5cbiAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gPGRpdiBjbGFzc05hbWU9XCJteF9Vc2VySW5mb19jb250YWluZXJcIj57ZW1vamlzfTwvZGl2PjtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgY2FzZSBQaGFzZS5Eb25lOlxuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLnJlbmRlclZlcmlmaWVkUGhhc2UoKTtcbiAgICAgICAgICAgIGNhc2UgUGhhc2UuQ2FuY2VsbGVkOlxuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLnJlbmRlckNhbmNlbGxlZFBoYXNlKCk7XG4gICAgICAgIH1cbiAgICAgICAgbG9nZ2VyLmVycm9yKFwiVmVyaWZpY2F0aW9uUGFuZWwgdW5oYW5kbGVkIHBoYXNlOlwiLCBwaGFzZSk7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIHByaXZhdGUgc3RhcnRTQVMgPSBhc3luYyAoKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoeyBlbW9qaUJ1dHRvbkNsaWNrZWQ6IHRydWUgfSk7XG4gICAgICAgIGF3YWl0IHRoaXMucHJvcHMucmVxdWVzdC5zdGFydFZlcmlmaWNhdGlvbihWZXJpZmljYXRpb25NZXRob2QuU2FzKTtcbiAgICB9O1xuXG4gICAgcHJpdmF0ZSBvblNhc01hdGNoZXNDbGljayA9ICgpOiB2b2lkID0+IHtcbiAgICAgICAgdGhpcy5zdGF0ZS5zYXNFdmVudD8uY29uZmlybSgpO1xuICAgIH07XG5cbiAgICBwcml2YXRlIG9uU2FzTWlzbWF0Y2hlc0NsaWNrID0gKCk6IHZvaWQgPT4ge1xuICAgICAgICB0aGlzLnN0YXRlLnNhc0V2ZW50Py5taXNtYXRjaCgpO1xuICAgIH07XG5cbiAgICBwcml2YXRlIHVwZGF0ZVZlcmlmaWVyU3RhdGUgPSAoKTogdm9pZCA9PiB7XG4gICAgICAgIC8vIHRoaXMgbWV0aG9kIGlzIG9ubHkgY2FsbGVkIG9uY2Ugd2Uga25vdyB0aGVyZSBpcyBhIHZlcmlmaWVyLlxuICAgICAgICBjb25zdCB2ZXJpZmllciA9IHRoaXMucHJvcHMucmVxdWVzdC52ZXJpZmllciE7XG4gICAgICAgIGNvbnN0IHNhc0V2ZW50ID0gdmVyaWZpZXIuZ2V0U2hvd1Nhc0NhbGxiYWNrcygpO1xuICAgICAgICBjb25zdCByZWNpcHJvY2F0ZVFSRXZlbnQgPSB2ZXJpZmllci5nZXRSZWNpcHJvY2F0ZVFyQ29kZUNhbGxiYWNrcygpO1xuICAgICAgICB2ZXJpZmllci5vZmYoVmVyaWZpZXJFdmVudC5TaG93U2FzLCB0aGlzLnVwZGF0ZVZlcmlmaWVyU3RhdGUpO1xuICAgICAgICB2ZXJpZmllci5vZmYoVmVyaWZpZXJFdmVudC5TaG93UmVjaXByb2NhdGVRciwgdGhpcy51cGRhdGVWZXJpZmllclN0YXRlKTtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7IHNhc0V2ZW50LCByZWNpcHJvY2F0ZVFSRXZlbnQgfSk7XG4gICAgfTtcblxuICAgIHByaXZhdGUgb25SZXF1ZXN0Q2hhbmdlID0gYXN5bmMgKCk6IFByb21pc2U8dm9pZD4gPT4ge1xuICAgICAgICBjb25zdCB7IHJlcXVlc3QgfSA9IHRoaXMucHJvcHM7XG5cbiAgICAgICAgLy8gaWYgd2UgaGF2ZSBhIGRldmljZSBJRCBhbmQgZGlkIG5vdCBoYXZlIG9uZSBiZWZvcmUsIGZldGNoIHRoZSBkZXZpY2UncyBkZXRhaWxzXG4gICAgICAgIHRoaXMubWF5YmVHZXRPdGhlckRldmljZSgpO1xuXG4gICAgICAgIC8vIGlmIHdlIGhhdmUgaGFkIGEgcmVwbHkgZnJvbSB0aGUgb3RoZXIgc2lkZSAoaWUsIHRoZSBwaGFzZSBpcyBcInJlYWR5XCIpIGFuZCB3ZSBoYXZlIG5vdFxuICAgICAgICAvLyB5ZXQgZG9uZSBzbywgZmV0Y2ggdGhlIFFSIGNvZGVcbiAgICAgICAgaWYgKHJlcXVlc3QucGhhc2UgPT09IFBoYXNlLlJlYWR5ICYmICF0aGlzLmhhdmVGZXRjaGVkUVJDb2RlKSB7XG4gICAgICAgICAgICB0aGlzLmhhdmVGZXRjaGVkUVJDb2RlID0gdHJ1ZTtcbiAgICAgICAgICAgIHJlcXVlc3QuZ2VuZXJhdGVRUkNvZGUoKS50aGVuKFxuICAgICAgICAgICAgICAgIChidWYpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7IHFyQ29kZUJ5dGVzOiBidWYgfSk7XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAoZXJyb3IpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihcIkVycm9yIGdlbmVyYXRpbmcgUVIgY29kZTpcIiwgZXJyb3IpO1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICApO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgaGFkVmVyaWZpZXIgPSB0aGlzLmhhc1ZlcmlmaWVyO1xuICAgICAgICB0aGlzLmhhc1ZlcmlmaWVyID0gISFyZXF1ZXN0LnZlcmlmaWVyO1xuICAgICAgICBpZiAoIWhhZFZlcmlmaWVyICYmIHRoaXMuaGFzVmVyaWZpZXIpIHtcbiAgICAgICAgICAgIHJlcXVlc3QudmVyaWZpZXI/Lm9uKFZlcmlmaWVyRXZlbnQuU2hvd1NhcywgdGhpcy51cGRhdGVWZXJpZmllclN0YXRlKTtcbiAgICAgICAgICAgIHJlcXVlc3QudmVyaWZpZXI/Lm9uKFZlcmlmaWVyRXZlbnQuU2hvd1JlY2lwcm9jYXRlUXIsIHRoaXMudXBkYXRlVmVyaWZpZXJTdGF0ZSk7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIC8vIG9uIHRoZSByZXF1ZXN0ZXIgc2lkZSwgdGhpcyBpcyBhbHNvIGF3YWl0ZWQgaW4gc3RhcnRTQVMsXG4gICAgICAgICAgICAgICAgLy8gYnV0IHRoYXQncyBvayBhcyB2ZXJpZnkgc2hvdWxkIHJldHVybiB0aGUgc2FtZSBwcm9taXNlLlxuICAgICAgICAgICAgICAgIGF3YWl0IHJlcXVlc3QudmVyaWZpZXI/LnZlcmlmeSgpO1xuICAgICAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICAgICAgbG9nZ2VyLmVycm9yKFwiZXJyb3IgdmVyaWZ5XCIsIGVycik7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgcHVibGljIGNvbXBvbmVudERpZE1vdW50KCk6IHZvaWQge1xuICAgICAgICBjb25zdCB7IHJlcXVlc3QgfSA9IHRoaXMucHJvcHM7XG4gICAgICAgIHJlcXVlc3Qub24oVmVyaWZpY2F0aW9uUmVxdWVzdEV2ZW50LkNoYW5nZSwgdGhpcy5vblJlcXVlc3RDaGFuZ2UpO1xuICAgICAgICBpZiAocmVxdWVzdC52ZXJpZmllcikge1xuICAgICAgICAgICAgY29uc3Qgc2FzRXZlbnQgPSByZXF1ZXN0LnZlcmlmaWVyLmdldFNob3dTYXNDYWxsYmFja3MoKTtcbiAgICAgICAgICAgIGNvbnN0IHJlY2lwcm9jYXRlUVJFdmVudCA9IHJlcXVlc3QudmVyaWZpZXIuZ2V0UmVjaXByb2NhdGVRckNvZGVDYWxsYmFja3MoKTtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoeyBzYXNFdmVudCwgcmVjaXByb2NhdGVRUkV2ZW50IH0pO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMub25SZXF1ZXN0Q2hhbmdlKCk7XG4gICAgfVxuXG4gICAgcHVibGljIGNvbXBvbmVudFdpbGxVbm1vdW50KCk6IHZvaWQge1xuICAgICAgICBjb25zdCB7IHJlcXVlc3QgfSA9IHRoaXMucHJvcHM7XG4gICAgICAgIGlmIChyZXF1ZXN0LnZlcmlmaWVyKSB7XG4gICAgICAgICAgICByZXF1ZXN0LnZlcmlmaWVyLm9mZihWZXJpZmllckV2ZW50LlNob3dTYXMsIHRoaXMudXBkYXRlVmVyaWZpZXJTdGF0ZSk7XG4gICAgICAgICAgICByZXF1ZXN0LnZlcmlmaWVyLm9mZihWZXJpZmllckV2ZW50LlNob3dSZWNpcHJvY2F0ZVFyLCB0aGlzLnVwZGF0ZVZlcmlmaWVyU3RhdGUpO1xuICAgICAgICB9XG4gICAgICAgIHJlcXVlc3Qub2ZmKFZlcmlmaWNhdGlv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