UNPKG

matrix-react-sdk

Version:
388 lines (380 loc) 58 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 _logger = require("matrix-js-sdk/src/logger"); var _utils = require("matrix-js-sdk/src/utils"); var _icons = require("@vector-im/compound-design-tokens/assets/web/icons"); var _languageHandler = require("../../../languageHandler"); var _Modal = _interopRequireDefault(require("../../../Modal")); var _PasswordReset = _interopRequireDefault(require("../../../PasswordReset")); var _AuthPage = _interopRequireDefault(require("../../views/auth/AuthPage")); var _PassphraseField = _interopRequireDefault(require("../../views/auth/PassphraseField")); var _RegistrationForm = require("../../views/auth/RegistrationForm"); var _AuthHeader = _interopRequireDefault(require("../../views/auth/AuthHeader")); var _AuthBody = _interopRequireDefault(require("../../views/auth/AuthBody")); var _PassphraseConfirmField = _interopRequireDefault(require("../../views/auth/PassphraseConfirmField")); var _StyledCheckbox = _interopRequireDefault(require("../../views/elements/StyledCheckbox")); var _QuestionDialog = _interopRequireDefault(require("../../views/dialogs/QuestionDialog")); var _EnterEmail = require("./forgot-password/EnterEmail"); var _CheckEmail = require("./forgot-password/CheckEmail"); var _ErrorMessage = require("../ErrorMessage"); var _VerifyEmailModal = require("./forgot-password/VerifyEmailModal"); var _Spinner = _interopRequireDefault(require("../../views/elements/Spinner")); var _DateUtils = require("../../../DateUtils"); var _AutoDiscoveryUtils = _interopRequireDefault(require("../../../utils/AutoDiscoveryUtils")); /* Copyright 2024 New Vector Ltd. Copyright 2019 The Matrix.org Foundation C.I.C. Copyright 2017, 2018 , 2019 New Vector Ltd Copyright 2015, 2016 OpenMarket Ltd SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only Please see LICENSE files in the repository root for full details. */ const emailCheckInterval = 2000; var Phase = /*#__PURE__*/function (Phase) { Phase[Phase["EnterEmail"] = 1] = "EnterEmail"; Phase[Phase["SendingEmail"] = 2] = "SendingEmail"; Phase[Phase["EmailSent"] = 3] = "EmailSent"; Phase[Phase["PasswordInput"] = 4] = "PasswordInput"; Phase[Phase["ResettingPassword"] = 5] = "ResettingPassword"; Phase[Phase["Done"] = 6] = "Done"; return Phase; }(Phase || {}); class ForgotPassword extends _react.default.Component { constructor(props) { super(props); (0, _defineProperty2.default)(this, "reset", void 0); (0, _defineProperty2.default)(this, "fieldPassword", null); (0, _defineProperty2.default)(this, "fieldPasswordConfirm", null); (0, _defineProperty2.default)(this, "sendVerificationMail", async () => { try { await this.reset.requestResetToken(this.state.email); return true; } catch (err) { this.handleError(err); } return false; }); (0, _defineProperty2.default)(this, "onSubmitForm", async ev => { ev.preventDefault(); // Should not happen because of disabled forms, but just return if currently doing an action. if ([Phase.SendingEmail, Phase.ResettingPassword].includes(this.state.phase)) return; this.setState({ errorText: "" }); // Refresh the server errors. Just in case the server came back online of went offline. await this.checkServerLiveliness(this.props.serverConfig); // Server error if (!this.state.serverIsAlive) return; switch (this.state.phase) { case Phase.EnterEmail: this.onPhaseEmailInputSubmit(); break; case Phase.EmailSent: this.onPhaseEmailSentSubmit(); break; case Phase.PasswordInput: this.onPhasePasswordInputSubmit(); break; } }); (0, _defineProperty2.default)(this, "onInputChanged", (stateKey, ev) => { let value = ev.currentTarget.value; if (stateKey === "email") value = value.trim(); this.setState({ [stateKey]: value }); }); this.state = { phase: Phase.EnterEmail, email: "", password: "", password2: "", errorText: null, // We perform liveliness checks later, but for now suppress the errors. // We also track the server dead errors independently of the regular errors so // that we can render it differently, and override any other error the user may // be seeing. serverIsAlive: true, serverDeadError: "", logoutDevices: false }; this.reset = new _PasswordReset.default(this.props.serverConfig.hsUrl, this.props.serverConfig.isUrl); } componentDidUpdate(prevProps) { if (prevProps.serverConfig.hsUrl !== this.props.serverConfig.hsUrl || prevProps.serverConfig.isUrl !== this.props.serverConfig.isUrl) { // Do a liveliness check on the new URLs this.checkServerLiveliness(this.props.serverConfig); } } async checkServerLiveliness(serverConfig) { try { await _AutoDiscoveryUtils.default.validateServerConfigWithStaticUrls(serverConfig.hsUrl, serverConfig.isUrl); this.setState({ serverIsAlive: true }); } catch (e) { const { serverIsAlive, serverDeadError } = _AutoDiscoveryUtils.default.authComponentStateForError(e, "forgot_password"); this.setState({ serverIsAlive, errorText: serverDeadError }); } } async onPhaseEmailInputSubmit() { this.phase = Phase.SendingEmail; if (await this.sendVerificationMail()) { this.phase = Phase.EmailSent; return; } this.phase = Phase.EnterEmail; } handleError(err) { if (err?.httpStatus === 429) { // 429: rate limit const retryAfterMs = parseInt(err?.data?.retry_after_ms, 10); const errorText = isNaN(retryAfterMs) ? (0, _languageHandler._t)("auth|reset_password|rate_limit_error") : (0, _languageHandler._t)("auth|reset_password|rate_limit_error_with_time", { timeout: (0, _DateUtils.formatSeconds)(retryAfterMs / 1000) }); this.setState({ errorText }); return; } if (err?.name === "ConnectionError") { this.setState({ errorText: (0, _languageHandler._t)("cannot_reach_homeserver") + ": " + (0, _languageHandler._t)("cannot_reach_homeserver_detail") }); return; } this.setState({ errorText: err.message }); } async onPhaseEmailSentSubmit() { this.setState({ phase: Phase.PasswordInput }); } set phase(phase) { this.setState({ phase }); } async verifyFieldsBeforeSubmit() { const fieldIdsInDisplayOrder = [this.fieldPassword, this.fieldPasswordConfirm]; const invalidFields = []; for (const field of fieldIdsInDisplayOrder) { if (!field) continue; const valid = await field.validate({ allowEmpty: false }); if (!valid) { invalidFields.push(field); } } if (invalidFields.length === 0) { return true; } // Focus on the first invalid field, then re-validate, // which will result in the error tooltip being displayed for that field. invalidFields[0].focus(); invalidFields[0].validate({ allowEmpty: false, focused: true }); return false; } async onPhasePasswordInputSubmit() { if (!(await this.verifyFieldsBeforeSubmit())) return; if (this.state.logoutDevices) { const logoutDevicesConfirmation = await this.renderConfirmLogoutDevicesDialog(); if (!logoutDevicesConfirmation) return; } this.phase = Phase.ResettingPassword; this.reset.setLogoutDevices(this.state.logoutDevices); try { await this.reset.setNewPassword(this.state.password); this.setState({ phase: Phase.Done }); return; } catch (err) { if (err.httpStatus !== 401) { // 401 = waiting for email verification, else unknown error this.handleError(err); return; } } const modal = _Modal.default.createDialog(_VerifyEmailModal.VerifyEmailModal, { email: this.state.email, errorText: this.state.errorText, onCloseClick: () => { modal.close(); this.setState({ phase: Phase.PasswordInput }); }, onReEnterEmailClick: () => { modal.close(); this.setState({ phase: Phase.EnterEmail }); }, onResendClick: this.sendVerificationMail }, "mx_VerifyEMailDialog", false, false, { onBeforeClose: async reason => { if (reason === "backgroundClick") { // Modal dismissed by clicking the background. // Go one phase back. this.setState({ phase: Phase.PasswordInput }); } return true; } }); // Don't retry if the phase changed. For example when going back to email input. while (this.state.phase === Phase.ResettingPassword) { try { await this.reset.setNewPassword(this.state.password); this.setState({ phase: Phase.Done }); modal.close(); } catch (e) { // Email not confirmed, yet. Retry after a while. await (0, _utils.sleep)(emailCheckInterval); } } } renderEnterEmail() { return /*#__PURE__*/_react.default.createElement(_EnterEmail.EnterEmail, { email: this.state.email, errorText: this.state.errorText, homeserver: this.props.serverConfig.hsName, loading: this.state.phase === Phase.SendingEmail, onInputChanged: this.onInputChanged, onLoginClick: this.props.onLoginClick // set by default props , onSubmitForm: this.onSubmitForm }); } async renderConfirmLogoutDevicesDialog() { const { finished } = _Modal.default.createDialog(_QuestionDialog.default, { title: (0, _languageHandler._t)("common|warning"), description: /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement("p", null, (0, _languageHandler._t)("auth|reset_password|other_devices_logout_warning_1")), /*#__PURE__*/_react.default.createElement("p", null, (0, _languageHandler._t)("auth|reset_password|other_devices_logout_warning_2"))), button: (0, _languageHandler._t)("action|continue") }); const [confirmed] = await finished; return !!confirmed; } renderCheckEmail() { return /*#__PURE__*/_react.default.createElement(_CheckEmail.CheckEmail, { email: this.state.email, errorText: this.state.errorText, onReEnterEmailClick: () => this.setState({ phase: Phase.EnterEmail }), onResendClick: this.sendVerificationMail, onSubmitForm: this.onSubmitForm }); } renderSetPassword() { const submitButtonChild = this.state.phase === Phase.ResettingPassword ? /*#__PURE__*/_react.default.createElement(_Spinner.default, { w: 16, h: 16 }) : (0, _languageHandler._t)("auth|reset_password_action"); return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_icons.LockSolidIcon, { className: "mx_AuthBody_lockIcon" }), /*#__PURE__*/_react.default.createElement("h1", null, (0, _languageHandler._t)("auth|reset_password_title")), /*#__PURE__*/_react.default.createElement("form", { onSubmit: this.onSubmitForm }, /*#__PURE__*/_react.default.createElement("fieldset", { disabled: this.state.phase === Phase.ResettingPassword }, /*#__PURE__*/_react.default.createElement("div", { className: "mx_AuthBody_fieldRow" }, /*#__PURE__*/_react.default.createElement(_PassphraseField.default, { name: "reset_password", type: "password", label: (0, _languageHandler._td)("auth|change_password_new_label"), value: this.state.password, minScore: _RegistrationForm.PASSWORD_MIN_SCORE, fieldRef: field => this.fieldPassword = field, onChange: this.onInputChanged.bind(this, "password"), autoComplete: "new-password" }), /*#__PURE__*/_react.default.createElement(_PassphraseConfirmField.default, { name: "reset_password_confirm", label: (0, _languageHandler._td)("auth|reset_password|confirm_new_password"), labelRequired: (0, _languageHandler._td)("auth|reset_password|password_not_entered"), labelInvalid: (0, _languageHandler._td)("auth|reset_password|passwords_mismatch"), value: this.state.password2, password: this.state.password, fieldRef: field => this.fieldPasswordConfirm = field, onChange: this.onInputChanged.bind(this, "password2"), autoComplete: "new-password" })), /*#__PURE__*/_react.default.createElement("div", { className: "mx_AuthBody_fieldRow" }, /*#__PURE__*/_react.default.createElement(_StyledCheckbox.default, { onChange: () => this.setState({ logoutDevices: !this.state.logoutDevices }), checked: this.state.logoutDevices }, (0, _languageHandler._t)("auth|reset_password|sign_out_other_devices"))), this.state.errorText && /*#__PURE__*/_react.default.createElement(_ErrorMessage.ErrorMessage, { message: this.state.errorText }), /*#__PURE__*/_react.default.createElement("button", { type: "submit", className: "mx_Login_submit" }, submitButtonChild)))); } renderDone() { return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_icons.CheckIcon, { className: "mx_Icon mx_Icon_32 mx_Icon_accent" }), /*#__PURE__*/_react.default.createElement("h1", null, (0, _languageHandler._t)("auth|reset_password|reset_successful")), this.state.logoutDevices ? /*#__PURE__*/_react.default.createElement("p", null, (0, _languageHandler._t)("auth|reset_password|devices_logout_success")) : null, /*#__PURE__*/_react.default.createElement("input", { className: "mx_Login_submit", type: "button", onClick: this.props.onComplete, value: (0, _languageHandler._t)("auth|reset_password|return_to_login") })); } render() { let resetPasswordJsx; switch (this.state.phase) { case Phase.EnterEmail: case Phase.SendingEmail: resetPasswordJsx = this.renderEnterEmail(); break; case Phase.EmailSent: resetPasswordJsx = this.renderCheckEmail(); break; case Phase.PasswordInput: case Phase.ResettingPassword: resetPasswordJsx = this.renderSetPassword(); break; case Phase.Done: resetPasswordJsx = this.renderDone(); break; default: // This should not happen. However, it is logged and the user is sent to the start. _logger.logger.warn(`unknown forgot password phase ${this.state.phase}`); this.setState({ phase: Phase.EnterEmail }); return; } return /*#__PURE__*/_react.default.createElement(_AuthPage.default, null, /*#__PURE__*/_react.default.createElement(_AuthHeader.default, null), /*#__PURE__*/_react.default.createElement(_AuthBody.default, { className: "mx_AuthBody_forgot-password" }, resetPasswordJsx)); } } exports.default = ForgotPassword; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfcmVhY3QiLCJfaW50ZXJvcFJlcXVpcmVEZWZhdWx0IiwicmVxdWlyZSIsIl9sb2dnZXIiLCJfdXRpbHMiLCJfaWNvbnMiLCJfbGFuZ3VhZ2VIYW5kbGVyIiwiX01vZGFsIiwiX1Bhc3N3b3JkUmVzZXQiLCJfQXV0aFBhZ2UiLCJfUGFzc3BocmFzZUZpZWxkIiwiX1JlZ2lzdHJhdGlvbkZvcm0iLCJfQXV0aEhlYWRlciIsIl9BdXRoQm9keSIsIl9QYXNzcGhyYXNlQ29uZmlybUZpZWxkIiwiX1N0eWxlZENoZWNrYm94IiwiX1F1ZXN0aW9uRGlhbG9nIiwiX0VudGVyRW1haWwiLCJfQ2hlY2tFbWFpbCIsIl9FcnJvck1lc3NhZ2UiLCJfVmVyaWZ5RW1haWxNb2RhbCIsIl9TcGlubmVyIiwiX0RhdGVVdGlscyIsIl9BdXRvRGlzY292ZXJ5VXRpbHMiLCJlbWFpbENoZWNrSW50ZXJ2YWwiLCJQaGFzZSIsIkZvcmdvdFBhc3N3b3JkIiwiUmVhY3QiLCJDb21wb25lbnQiLCJjb25zdHJ1Y3RvciIsInByb3BzIiwiX2RlZmluZVByb3BlcnR5MiIsImRlZmF1bHQiLCJyZXNldCIsInJlcXVlc3RSZXNldFRva2VuIiwic3RhdGUiLCJlbWFpbCIsImVyciIsImhhbmRsZUVycm9yIiwiZXYiLCJwcmV2ZW50RGVmYXVsdCIsIlNlbmRpbmdFbWFpbCIsIlJlc2V0dGluZ1Bhc3N3b3JkIiwiaW5jbHVkZXMiLCJwaGFzZSIsInNldFN0YXRlIiwiZXJyb3JUZXh0IiwiY2hlY2tTZXJ2ZXJMaXZlbGluZXNzIiwic2VydmVyQ29uZmlnIiwic2VydmVySXNBbGl2ZSIsIkVudGVyRW1haWwiLCJvblBoYXNlRW1haWxJbnB1dFN1Ym1pdCIsIkVtYWlsU2VudCIsIm9uUGhhc2VFbWFpbFNlbnRTdWJtaXQiLCJQYXNzd29yZElucHV0Iiwib25QaGFzZVBhc3N3b3JkSW5wdXRTdWJtaXQiLCJzdGF0ZUtleSIsInZhbHVlIiwiY3VycmVudFRhcmdldCIsInRyaW0iLCJwYXNzd29yZCIsInBhc3N3b3JkMiIsInNlcnZlckRlYWRFcnJvciIsImxvZ291dERldmljZXMiLCJQYXNzd29yZFJlc2V0IiwiaHNVcmwiLCJpc1VybCIsImNvbXBvbmVudERpZFVwZGF0ZSIsInByZXZQcm9wcyIsIkF1dG9EaXNjb3ZlcnlVdGlscyIsInZhbGlkYXRlU2VydmVyQ29uZmlnV2l0aFN0YXRpY1VybHMiLCJlIiwiYXV0aENvbXBvbmVudFN0YXRlRm9yRXJyb3IiLCJzZW5kVmVyaWZpY2F0aW9uTWFpbCIsImh0dHBTdGF0dXMiLCJyZXRyeUFmdGVyTXMiLCJwYXJzZUludCIsImRhdGEiLCJyZXRyeV9hZnRlcl9tcyIsImlzTmFOIiwiX3QiLCJ0aW1lb3V0IiwiZm9ybWF0U2Vjb25kcyIsIm5hbWUiLCJtZXNzYWdlIiwidmVyaWZ5RmllbGRzQmVmb3JlU3VibWl0IiwiZmllbGRJZHNJbkRpc3BsYXlPcmRlciIsImZpZWxkUGFzc3dvcmQiLCJmaWVsZFBhc3N3b3JkQ29uZmlybSIsImludmFsaWRGaWVsZHMiLCJmaWVsZCIsInZhbGlkIiwidmFsaWRhdGUiLCJhbGxvd0VtcHR5IiwicHVzaCIsImxlbmd0aCIsImZvY3VzIiwiZm9jdXNlZCIsImxvZ291dERldmljZXNDb25maXJtYXRpb24iLCJyZW5kZXJDb25maXJtTG9nb3V0RGV2aWNlc0RpYWxvZyIsInNldExvZ291dERldmljZXMiLCJzZXROZXdQYXNzd29yZCIsIkRvbmUiLCJtb2RhbCIsIk1vZGFsIiwiY3JlYXRlRGlhbG9nIiwiVmVyaWZ5RW1haWxNb2RhbCIsIm9uQ2xvc2VDbGljayIsImNsb3NlIiwib25SZUVudGVyRW1haWxDbGljayIsIm9uUmVzZW5kQ2xpY2siLCJvbkJlZm9yZUNsb3NlIiwicmVhc29uIiwic2xlZXAiLCJyZW5kZXJFbnRlckVtYWlsIiwiY3JlYXRlRWxlbWVudCIsImhvbWVzZXJ2ZXIiLCJoc05hbWUiLCJsb2FkaW5nIiwib25JbnB1dENoYW5nZWQiLCJvbkxvZ2luQ2xpY2siLCJvblN1Ym1pdEZvcm0iLCJmaW5pc2hlZCIsIlF1ZXN0aW9uRGlhbG9nIiwidGl0bGUiLCJkZXNjcmlwdGlvbiIsImJ1dHRvbiIsImNvbmZpcm1lZCIsInJlbmRlckNoZWNrRW1haWwiLCJDaGVja0VtYWlsIiwicmVuZGVyU2V0UGFzc3dvcmQiLCJzdWJtaXRCdXR0b25DaGlsZCIsInciLCJoIiwiRnJhZ21lbnQiLCJMb2NrU29saWRJY29uIiwiY2xhc3NOYW1lIiwib25TdWJtaXQiLCJkaXNhYmxlZCIsInR5cGUiLCJsYWJlbCIsIl90ZCIsIm1pblNjb3JlIiwiUEFTU1dPUkRfTUlOX1NDT1JFIiwiZmllbGRSZWYiLCJvbkNoYW5nZSIsImJpbmQiLCJhdXRvQ29tcGxldGUiLCJsYWJlbFJlcXVpcmVkIiwibGFiZWxJbnZhbGlkIiwiY2hlY2tlZCIsIkVycm9yTWVzc2FnZSIsInJlbmRlckRvbmUiLCJDaGVja0ljb24iLCJvbkNsaWNrIiwib25Db21wbGV0ZSIsInJlbmRlciIsInJlc2V0UGFzc3dvcmRKc3giLCJsb2dnZXIiLCJ3YXJuIiwiZXhwb3J0cyJdLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9jb21wb25lbnRzL3N0cnVjdHVyZXMvYXV0aC9Gb3Jnb3RQYXNzd29yZC50c3giXSwic291cmNlc0NvbnRlbnQiOlsiLypcbkNvcHlyaWdodCAyMDI0IE5ldyBWZWN0b3IgTHRkLlxuQ29weXJpZ2h0IDIwMTkgVGhlIE1hdHJpeC5vcmcgRm91bmRhdGlvbiBDLkkuQy5cbkNvcHlyaWdodCAyMDE3LCAyMDE4ICwgMjAxOSBOZXcgVmVjdG9yIEx0ZFxuQ29weXJpZ2h0IDIwMTUsIDIwMTYgT3Blbk1hcmtldCBMdGRcblxuU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFHUEwtMy4wLW9ubHkgT1IgR1BMLTMuMC1vbmx5XG5QbGVhc2Ugc2VlIExJQ0VOU0UgZmlsZXMgaW4gdGhlIHJlcG9zaXRvcnkgcm9vdCBmb3IgZnVsbCBkZXRhaWxzLlxuKi9cblxuaW1wb3J0IFJlYWN0LCB7IFJlYWN0Tm9kZSB9IGZyb20gXCJyZWFjdFwiO1xuaW1wb3J0IHsgbG9nZ2VyIH0gZnJvbSBcIm1hdHJpeC1qcy1zZGsvc3JjL2xvZ2dlclwiO1xuaW1wb3J0IHsgc2xlZXAgfSBmcm9tIFwibWF0cml4LWpzLXNkay9zcmMvdXRpbHNcIjtcbmltcG9ydCB7IExvY2tTb2xpZEljb24sIENoZWNrSWNvbiB9IGZyb20gXCJAdmVjdG9yLWltL2NvbXBvdW5kLWRlc2lnbi10b2tlbnMvYXNzZXRzL3dlYi9pY29uc1wiO1xuXG5pbXBvcnQgeyBfdCwgX3RkIH0gZnJvbSBcIi4uLy4uLy4uL2xhbmd1YWdlSGFuZGxlclwiO1xuaW1wb3J0IE1vZGFsIGZyb20gXCIuLi8uLi8uLi9Nb2RhbFwiO1xuaW1wb3J0IFBhc3N3b3JkUmVzZXQgZnJvbSBcIi4uLy4uLy4uL1Bhc3N3b3JkUmVzZXRcIjtcbmltcG9ydCBBdXRoUGFnZSBmcm9tIFwiLi4vLi4vdmlld3MvYXV0aC9BdXRoUGFnZVwiO1xuaW1wb3J0IFBhc3NwaHJhc2VGaWVsZCBmcm9tIFwiLi4vLi4vdmlld3MvYXV0aC9QYXNzcGhyYXNlRmllbGRcIjtcbmltcG9ydCB7IFBBU1NXT1JEX01JTl9TQ09SRSB9IGZyb20gXCIuLi8uLi92aWV3cy9hdXRoL1JlZ2lzdHJhdGlvbkZvcm1cIjtcbmltcG9ydCBBdXRoSGVhZGVyIGZyb20gXCIuLi8uLi92aWV3cy9hdXRoL0F1dGhIZWFkZXJcIjtcbmltcG9ydCBBdXRoQm9keSBmcm9tIFwiLi4vLi4vdmlld3MvYXV0aC9BdXRoQm9keVwiO1xuaW1wb3J0IFBhc3NwaHJhc2VDb25maXJtRmllbGQgZnJvbSBcIi4uLy4uL3ZpZXdzL2F1dGgvUGFzc3BocmFzZUNvbmZpcm1GaWVsZFwiO1xuaW1wb3J0IFN0eWxlZENoZWNrYm94IGZyb20gXCIuLi8uLi92aWV3cy9lbGVtZW50cy9TdHlsZWRDaGVja2JveFwiO1xuaW1wb3J0IHsgVmFsaWRhdGVkU2VydmVyQ29uZmlnIH0gZnJvbSBcIi4uLy4uLy4uL3V0aWxzL1ZhbGlkYXRlZFNlcnZlckNvbmZpZ1wiO1xuaW1wb3J0IFF1ZXN0aW9uRGlhbG9nIGZyb20gXCIuLi8uLi92aWV3cy9kaWFsb2dzL1F1ZXN0aW9uRGlhbG9nXCI7XG5pbXBvcnQgeyBFbnRlckVtYWlsIH0gZnJvbSBcIi4vZm9yZ290LXBhc3N3b3JkL0VudGVyRW1haWxcIjtcbmltcG9ydCB7IENoZWNrRW1haWwgfSBmcm9tIFwiLi9mb3Jnb3QtcGFzc3dvcmQvQ2hlY2tFbWFpbFwiO1xuaW1wb3J0IEZpZWxkIGZyb20gXCIuLi8uLi92aWV3cy9lbGVtZW50cy9GaWVsZFwiO1xuaW1wb3J0IHsgRXJyb3JNZXNzYWdlIH0gZnJvbSBcIi4uL0Vycm9yTWVzc2FnZVwiO1xuaW1wb3J0IHsgVmVyaWZ5RW1haWxNb2RhbCB9IGZyb20gXCIuL2ZvcmdvdC1wYXNzd29yZC9WZXJpZnlFbWFpbE1vZGFsXCI7XG5pbXBvcnQgU3Bpbm5lciBmcm9tIFwiLi4vLi4vdmlld3MvZWxlbWVudHMvU3Bpbm5lclwiO1xuaW1wb3J0IHsgZm9ybWF0U2Vjb25kcyB9IGZyb20gXCIuLi8uLi8uLi9EYXRlVXRpbHNcIjtcbmltcG9ydCBBdXRvRGlzY292ZXJ5VXRpbHMgZnJvbSBcIi4uLy4uLy4uL3V0aWxzL0F1dG9EaXNjb3ZlcnlVdGlsc1wiO1xuXG5jb25zdCBlbWFpbENoZWNrSW50ZXJ2YWwgPSAyMDAwO1xuXG5lbnVtIFBoYXNlIHtcbiAgICAvLyBTaG93IGVtYWlsIGlucHV0XG4gICAgRW50ZXJFbWFpbCA9IDEsXG4gICAgLy8gRW1haWwgaXMgaW4gdGhlIHByb2Nlc3Mgb2YgYmVpbmcgc2VudFxuICAgIFNlbmRpbmdFbWFpbCA9IDIsXG4gICAgLy8gRW1haWwgaGFzIGJlZW4gc2VudFxuICAgIEVtYWlsU2VudCA9IDMsXG4gICAgLy8gU2hvdyBuZXcgcGFzc3dvcmQgaW5wdXRcbiAgICBQYXNzd29yZElucHV0ID0gNCxcbiAgICAvLyBQYXNzd29yZCBpcyBpbiB0aGUgcHJvY2VzcyBvZiBiZWluZyByZXNldFxuICAgIFJlc2V0dGluZ1Bhc3N3b3JkID0gNSxcbiAgICAvLyBBbGwgZG9uZVxuICAgIERvbmUgPSA2LFxufVxuXG5pbnRlcmZhY2UgUHJvcHMge1xuICAgIHNlcnZlckNvbmZpZzogVmFsaWRhdGVkU2VydmVyQ29uZmlnO1xuICAgIG9uTG9naW5DbGljazogKCkgPT4gdm9pZDtcbiAgICBvbkNvbXBsZXRlOiAoKSA9PiB2b2lkO1xufVxuXG5pbnRlcmZhY2UgU3RhdGUge1xuICAgIHBoYXNlOiBQaGFzZTtcbiAgICBlbWFpbDogc3RyaW5nO1xuICAgIHBhc3N3b3JkOiBzdHJpbmc7XG4gICAgcGFzc3dvcmQyOiBzdHJpbmc7XG4gICAgZXJyb3JUZXh0OiBzdHJpbmcgfCBSZWFjdE5vZGUgfCBudWxsO1xuXG4gICAgLy8gV2UgcGVyZm9ybSBsaXZlbGluZXNzIGNoZWNrcyBsYXRlciwgYnV0IGZvciBub3cgc3VwcHJlc3MgdGhlIGVycm9ycy5cbiAgICAvLyBXZSBhbHNvIHRyYWNrIHRoZSBzZXJ2ZXIgZGVhZCBlcnJvcnMgaW5kZXBlbmRlbnRseSBvZiB0aGUgcmVndWxhciBlcnJvcnMgc29cbiAgICAvLyB0aGF0IHdlIGNhbiByZW5kZXIgaXQgZGlmZmVyZW50bHksIGFuZCBvdmVycmlkZSBhbnkgb3RoZXIgZXJyb3IgdGhlIHVzZXIgbWF5XG4gICAgLy8gYmUgc2VlaW5nLlxuICAgIHNlcnZlcklzQWxpdmU6IGJvb2xlYW47XG4gICAgc2VydmVyRGVhZEVycm9yOiBzdHJpbmc7XG5cbiAgICBsb2dvdXREZXZpY2VzOiBib29sZWFuO1xufVxuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBGb3Jnb3RQYXNzd29yZCBleHRlbmRzIFJlYWN0LkNvbXBvbmVudDxQcm9wcywgU3RhdGU+IHtcbiAgICBwcml2YXRlIHJlc2V0OiBQYXNzd29yZFJlc2V0O1xuICAgIHByaXZhdGUgZmllbGRQYXNzd29yZDogRmllbGQgfCBudWxsID0gbnVsbDtcbiAgICBwcml2YXRlIGZpZWxkUGFzc3dvcmRDb25maXJtOiBGaWVsZCB8IG51bGwgPSBudWxsO1xuXG4gICAgcHVibGljIGNvbnN0cnVjdG9yKHByb3BzOiBQcm9wcykge1xuICAgICAgICBzdXBlcihwcm9wcyk7XG4gICAgICAgIHRoaXMuc3RhdGUgPSB7XG4gICAgICAgICAgICBwaGFzZTogUGhhc2UuRW50ZXJFbWFpbCxcbiAgICAgICAgICAgIGVtYWlsOiBcIlwiLFxuICAgICAgICAgICAgcGFzc3dvcmQ6IFwiXCIsXG4gICAgICAgICAgICBwYXNzd29yZDI6IFwiXCIsXG4gICAgICAgICAgICBlcnJvclRleHQ6IG51bGwsXG4gICAgICAgICAgICAvLyBXZSBwZXJmb3JtIGxpdmVsaW5lc3MgY2hlY2tzIGxhdGVyLCBidXQgZm9yIG5vdyBzdXBwcmVzcyB0aGUgZXJyb3JzLlxuICAgICAgICAgICAgLy8gV2UgYWxzbyB0cmFjayB0aGUgc2VydmVyIGRlYWQgZXJyb3JzIGluZGVwZW5kZW50bHkgb2YgdGhlIHJlZ3VsYXIgZXJyb3JzIHNvXG4gICAgICAgICAgICAvLyB0aGF0IHdlIGNhbiByZW5kZXIgaXQgZGlmZmVyZW50bHksIGFuZCBvdmVycmlkZSBhbnkgb3RoZXIgZXJyb3IgdGhlIHVzZXIgbWF5XG4gICAgICAgICAgICAvLyBiZSBzZWVpbmcuXG4gICAgICAgICAgICBzZXJ2ZXJJc0FsaXZlOiB0cnVlLFxuICAgICAgICAgICAgc2VydmVyRGVhZEVycm9yOiBcIlwiLFxuICAgICAgICAgICAgbG9nb3V0RGV2aWNlczogZmFsc2UsXG4gICAgICAgIH07XG4gICAgICAgIHRoaXMucmVzZXQgPSBuZXcgUGFzc3dvcmRSZXNldCh0aGlzLnByb3BzLnNlcnZlckNvbmZpZy5oc1VybCwgdGhpcy5wcm9wcy5zZXJ2ZXJDb25maWcuaXNVcmwpO1xuICAgIH1cblxuICAgIHB1YmxpYyBjb21wb25lbnREaWRVcGRhdGUocHJldlByb3BzOiBSZWFkb25seTxQcm9wcz4pOiB2b2lkIHtcbiAgICAgICAgaWYgKFxuICAgICAgICAgICAgcHJldlByb3BzLnNlcnZlckNvbmZpZy5oc1VybCAhPT0gdGhpcy5wcm9wcy5zZXJ2ZXJDb25maWcuaHNVcmwgfHxcbiAgICAgICAgICAgIHByZXZQcm9wcy5zZXJ2ZXJDb25maWcuaXNVcmwgIT09IHRoaXMucHJvcHMuc2VydmVyQ29uZmlnLmlzVXJsXG4gICAgICAgICkge1xuICAgICAgICAgICAgLy8gRG8gYSBsaXZlbGluZXNzIGNoZWNrIG9uIHRoZSBuZXcgVVJMc1xuICAgICAgICAgICAgdGhpcy5jaGVja1NlcnZlckxpdmVsaW5lc3ModGhpcy5wcm9wcy5zZXJ2ZXJDb25maWcpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBjaGVja1NlcnZlckxpdmVsaW5lc3Moc2VydmVyQ29uZmlnOiBWYWxpZGF0ZWRTZXJ2ZXJDb25maWcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGF3YWl0IEF1dG9EaXNjb3ZlcnlVdGlscy52YWxpZGF0ZVNlcnZlckNvbmZpZ1dpdGhTdGF0aWNVcmxzKHNlcnZlckNvbmZpZy5oc1VybCwgc2VydmVyQ29uZmlnLmlzVXJsKTtcblxuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgICAgc2VydmVySXNBbGl2ZTogdHJ1ZSxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9IGNhdGNoIChlOiBhbnkpIHtcbiAgICAgICAgICAgIGNvbnN0IHsgc2VydmVySXNBbGl2ZSwgc2VydmVyRGVhZEVycm9yIH0gPSBBdXRvRGlzY292ZXJ5VXRpbHMuYXV0aENvbXBvbmVudFN0YXRlRm9yRXJyb3IoXG4gICAgICAgICAgICAgICAgZSxcbiAgICAgICAgICAgICAgICBcImZvcmdvdF9wYXNzd29yZFwiLFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICAgIHNlcnZlcklzQWxpdmUsXG4gICAgICAgICAgICAgICAgZXJyb3JUZXh0OiBzZXJ2ZXJEZWFkRXJyb3IsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgb25QaGFzZUVtYWlsSW5wdXRTdWJtaXQoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIHRoaXMucGhhc2UgPSBQaGFzZS5TZW5kaW5nRW1haWw7XG5cbiAgICAgICAgaWYgKGF3YWl0IHRoaXMuc2VuZFZlcmlmaWNhdGlvbk1haWwoKSkge1xuICAgICAgICAgICAgdGhpcy5waGFzZSA9IFBoYXNlLkVtYWlsU2VudDtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMucGhhc2UgPSBQaGFzZS5FbnRlckVtYWlsO1xuICAgIH1cblxuICAgIHByaXZhdGUgc2VuZFZlcmlmaWNhdGlvbk1haWwgPSBhc3luYyAoKTogUHJvbWlzZTxib29sZWFuPiA9PiB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLnJlc2V0LnJlcXVlc3RSZXNldFRva2VuKHRoaXMuc3RhdGUuZW1haWwpO1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH0gY2F0Y2ggKGVycjogYW55KSB7XG4gICAgICAgICAgICB0aGlzLmhhbmRsZUVycm9yKGVycik7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfTtcblxuICAgIHByaXZhdGUgaGFuZGxlRXJyb3IoZXJyOiBhbnkpOiB2b2lkIHtcbiAgICAgICAgaWYgKGVycj8uaHR0cFN0YXR1cyA9PT0gNDI5KSB7XG4gICAgICAgICAgICAvLyA0Mjk6IHJhdGUgbGltaXRcbiAgICAgICAgICAgIGNvbnN0IHJldHJ5QWZ0ZXJNcyA9IHBhcnNlSW50KGVycj8uZGF0YT8ucmV0cnlfYWZ0ZXJfbXMsIDEwKTtcblxuICAgICAgICAgICAgY29uc3QgZXJyb3JUZXh0ID0gaXNOYU4ocmV0cnlBZnRlck1zKVxuICAgICAgICAgICAgICAgID8gX3QoXCJhdXRofHJlc2V0X3Bhc3N3b3JkfHJhdGVfbGltaXRfZXJyb3JcIilcbiAgICAgICAgICAgICAgICA6IF90KFwiYXV0aHxyZXNldF9wYXNzd29yZHxyYXRlX2xpbWl0X2Vycm9yX3dpdGhfdGltZVwiLCB7XG4gICAgICAgICAgICAgICAgICAgICAgdGltZW91dDogZm9ybWF0U2Vjb25kcyhyZXRyeUFmdGVyTXMgLyAxMDAwKSxcbiAgICAgICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgICAgICBlcnJvclRleHQsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChlcnI/Lm5hbWUgPT09IFwiQ29ubmVjdGlvbkVycm9yXCIpIHtcbiAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICAgIGVycm9yVGV4dDogX3QoXCJjYW5ub3RfcmVhY2hfaG9tZXNlcnZlclwiKSArIFwiOiBcIiArIF90KFwiY2Fubm90X3JlYWNoX2hvbWVzZXJ2ZXJfZGV0YWlsXCIpLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIGVycm9yVGV4dDogZXJyLm1lc3NhZ2UsXG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgb25QaGFzZUVtYWlsU2VudFN1Ym1pdCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBwaGFzZTogUGhhc2UuUGFzc3dvcmRJbnB1dCxcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBzZXQgcGhhc2UocGhhc2U6IFBoYXNlKSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoeyBwaGFzZSB9KTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIHZlcmlmeUZpZWxkc0JlZm9yZVN1Ym1pdCgpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICAgICAgY29uc3QgZmllbGRJZHNJbkRpc3BsYXlPcmRlciA9IFt0aGlzLmZpZWxkUGFzc3dvcmQsIHRoaXMuZmllbGRQYXNzd29yZENvbmZpcm1dO1xuXG4gICAgICAgIGNvbnN0IGludmFsaWRGaWVsZHM6IEZpZWxkW10gPSBbXTtcblxuICAgICAgICBmb3IgKGNvbnN0IGZpZWxkIG9mIGZpZWxkSWRzSW5EaXNwbGF5T3JkZXIpIHtcbiAgICAgICAgICAgIGlmICghZmllbGQpIGNvbnRpbnVlO1xuXG4gICAgICAgICAgICBjb25zdCB2YWxpZCA9IGF3YWl0IGZpZWxkLnZhbGlkYXRlKHsgYWxsb3dFbXB0eTogZmFsc2UgfSk7XG4gICAgICAgICAgICBpZiAoIXZhbGlkKSB7XG4gICAgICAgICAgICAgICAgaW52YWxpZEZpZWxkcy5wdXNoKGZpZWxkKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChpbnZhbGlkRmllbGRzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBGb2N1cyBvbiB0aGUgZmlyc3QgaW52YWxpZCBmaWVsZCwgdGhlbiByZS12YWxpZGF0ZSxcbiAgICAgICAgLy8gd2hpY2ggd2lsbCByZXN1bHQgaW4gdGhlIGVycm9yIHRvb2x0aXAgYmVpbmcgZGlzcGxheWVkIGZvciB0aGF0IGZpZWxkLlxuICAgICAgICBpbnZhbGlkRmllbGRzWzBdLmZvY3VzKCk7XG4gICAgICAgIGludmFsaWRGaWVsZHNbMF0udmFsaWRhdGUoeyBhbGxvd0VtcHR5OiBmYWxzZSwgZm9jdXNlZDogdHJ1ZSB9KTtcblxuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBvblBoYXNlUGFzc3dvcmRJbnB1dFN1Ym1pdCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgaWYgKCEoYXdhaXQgdGhpcy52ZXJpZnlGaWVsZHNCZWZvcmVTdWJtaXQoKSkpIHJldHVybjtcblxuICAgICAgICBpZiAodGhpcy5zdGF0ZS5sb2dvdXREZXZpY2VzKSB7XG4gICAgICAgICAgICBjb25zdCBsb2dvdXREZXZpY2VzQ29uZmlybWF0aW9uID0gYXdhaXQgdGhpcy5yZW5kZXJDb25maXJtTG9nb3V0RGV2aWNlc0RpYWxvZygpO1xuICAgICAgICAgICAgaWYgKCFsb2dvdXREZXZpY2VzQ29uZmlybWF0aW9uKSByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnBoYXNlID0gUGhhc2UuUmVzZXR0aW5nUGFzc3dvcmQ7XG4gICAgICAgIHRoaXMucmVzZXQuc2V0TG9nb3V0RGV2aWNlcyh0aGlzLnN0YXRlLmxvZ291dERldmljZXMpO1xuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLnJlc2V0LnNldE5ld1Bhc3N3b3JkKHRoaXMuc3RhdGUucGFzc3dvcmQpO1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7IHBoYXNlOiBQaGFzZS5Eb25lIH0pO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9IGNhdGNoIChlcnI6IGFueSkge1xuICAgICAgICAgICAgaWYgKGVyci5odHRwU3RhdHVzICE9PSA0MDEpIHtcbiAgICAgICAgICAgICAgICAvLyA0MDEgPSB3YWl0aW5nIGZvciBlbWFpbCB2ZXJpZmljYXRpb24sIGVsc2UgdW5rbm93biBlcnJvclxuICAgICAgICAgICAgICAgIHRoaXMuaGFuZGxlRXJyb3IoZXJyKTtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBtb2RhbCA9IE1vZGFsLmNyZWF0ZURpYWxvZyhcbiAgICAgICAgICAgIFZlcmlmeUVtYWlsTW9kYWwsXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgZW1haWw6IHRoaXMuc3RhdGUuZW1haWwsXG4gICAgICAgICAgICAgICAgZXJyb3JUZXh0OiB0aGlzLnN0YXRlLmVycm9yVGV4dCxcbiAgICAgICAgICAgICAgICBvbkNsb3NlQ2xpY2s6ICgpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgbW9kYWwuY2xvc2UoKTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7IHBoYXNlOiBQaGFzZS5QYXNzd29yZElucHV0IH0pO1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgb25SZUVudGVyRW1haWxDbGljazogKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICBtb2RhbC5jbG9zZSgpO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnNldFN0YXRlKHsgcGhhc2U6IFBoYXNlLkVudGVyRW1haWwgfSk7XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBvblJlc2VuZENsaWNrOiB0aGlzLnNlbmRWZXJpZmljYXRpb25NYWlsLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwibXhfVmVyaWZ5RU1haWxEaWFsb2dcIixcbiAgICAgICAgICAgIGZhbHNlLFxuICAgICAgICAgICAgZmFsc2UsXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgb25CZWZvcmVDbG9zZTogYXN5bmMgKHJlYXNvbj86IHN0cmluZyk6IFByb21pc2U8Ym9vbGVhbj4gPT4ge1xuICAgICAgICAgICAgICAgICAgICBpZiAocmVhc29uID09PSBcImJhY2tncm91bmRDbGlja1wiKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBNb2RhbCBkaXNtaXNzZWQgYnkgY2xpY2tpbmcgdGhlIGJhY2tncm91bmQuXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBHbyBvbmUgcGhhc2UgYmFjay5cbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoeyBwaGFzZTogUGhhc2UuUGFzc3dvcmRJbnB1dCB9KTtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB9LFxuICAgICAgICApO1xuXG4gICAgICAgIC8vIERvbid0IHJldHJ5IGlmIHRoZSBwaGFzZSBjaGFuZ2VkLiBGb3IgZXhhbXBsZSB3aGVuIGdvaW5nIGJhY2sgdG8gZW1haWwgaW5wdXQuXG4gICAgICAgIHdoaWxlICh0aGlzLnN0YXRlLnBoYXNlID09PSBQaGFzZS5SZXNldHRpbmdQYXNzd29yZCkge1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLnJlc2V0LnNldE5ld1Bhc3N3b3JkKHRoaXMuc3RhdGUucGFzc3dvcmQpO1xuICAgICAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoeyBwaGFzZTogUGhhc2UuRG9uZSB9KTtcbiAgICAgICAgICAgICAgICBtb2RhbC5jbG9zZSgpO1xuICAgICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICAgIC8vIEVtYWlsIG5vdCBjb25maXJtZWQsIHlldC4gUmV0cnkgYWZ0ZXIgYSB3aGlsZS5cbiAgICAgICAgICAgICAgICBhd2FpdCBzbGVlcChlbWFpbENoZWNrSW50ZXJ2YWwpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBvblN1Ym1pdEZvcm0gPSBhc3luYyAoZXY6IFJlYWN0LkZvcm1FdmVudCk6IFByb21pc2U8dm9pZD4gPT4ge1xuICAgICAgICBldi5wcmV2ZW50RGVmYXVsdCgpO1xuXG4gICAgICAgIC8vIFNob3VsZCBub3QgaGFwcGVuIGJlY2F1c2Ugb2YgZGlzYWJsZWQgZm9ybXMsIGJ1dCBqdXN0IHJldHVybiBpZiBjdXJyZW50bHkgZG9pbmcgYW4gYWN0aW9uLlxuICAgICAgICBpZiAoW1BoYXNlLlNlbmRpbmdFbWFpbCwgUGhhc2UuUmVzZXR0aW5nUGFzc3dvcmRdLmluY2x1ZGVzKHRoaXMuc3RhdGUucGhhc2UpKSByZXR1cm47XG5cbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBlcnJvclRleHQ6IFwiXCIsXG4gICAgICAgIH0pO1xuXG4gICAgICAgIC8vIFJlZnJlc2ggdGhlIHNlcnZlciBlcnJvcnMuIEp1c3QgaW4gY2FzZSB0aGUgc2VydmVyIGNhbWUgYmFjayBvbmxpbmUgb2Ygd2VudCBvZmZsaW5lLlxuICAgICAgICBhd2FpdCB0aGlzLmNoZWNrU2VydmVyTGl2ZWxpbmVzcyh0aGlzLnByb3BzLnNlcnZlckNvbmZpZyk7XG5cbiAgICAgICAgLy8gU2VydmVyIGVycm9yXG4gICAgICAgIGlmICghdGhpcy5zdGF0ZS5zZXJ2ZXJJc0FsaXZlKSByZXR1cm47XG5cbiAgICAgICAgc3dpdGNoICh0aGlzLnN0YXRlLnBoYXNlKSB7XG4gICAgICAgICAgICBjYXNlIFBoYXNlLkVudGVyRW1haWw6XG4gICAgICAgICAgICAgICAgdGhpcy5vblBoYXNlRW1haWxJbnB1dFN1Ym1pdCgpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSBQaGFzZS5FbWFpbFNlbnQ6XG4gICAgICAgICAgICAgICAgdGhpcy5vblBoYXNlRW1haWxTZW50U3VibWl0KCk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIFBoYXNlLlBhc3N3b3JkSW5wdXQ6XG4gICAgICAgICAgICAgICAgdGhpcy5vblBoYXNlUGFzc3dvcmRJbnB1dFN1Ym1pdCgpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHByaXZhdGUgb25JbnB1dENoYW5nZWQgPSAoXG4gICAgICAgIHN0YXRlS2V5OiBcImVtYWlsXCIgfCBcInBhc3N3b3JkXCIgfCBcInBhc3N3b3JkMlwiLFxuICAgICAgICBldjogUmVhY3QuRm9ybUV2ZW50PEhUTUxJbnB1dEVsZW1lbnQ+LFxuICAgICk6IHZvaWQgPT4ge1xuICAgICAgICBsZXQgdmFsdWUgPSBldi5jdXJyZW50VGFyZ2V0LnZhbHVlO1xuICAgICAgICBpZiAoc3RhdGVLZXkgPT09IFwiZW1haWxcIikgdmFsdWUgPSB2YWx1ZS50cmltKCk7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgW3N0YXRlS2V5XTogdmFsdWUsXG4gICAgICAgIH0gYXMgUGljazxTdGF0ZSwgdHlwZW9mIHN0YXRlS2V5Pik7XG4gICAgfTtcblxuICAgIHB1YmxpYyByZW5kZXJFbnRlckVtYWlsKCk6IEpTWC5FbGVtZW50IHtcbiAgICAgICAgcmV0dXJuIChcbiAgICAgICAgICAgIDxFbnRlckVtYWlsXG4gICAgICAgICAgICAgICAgZW1haWw9e3RoaXMuc3RhdGUuZW1haWx9XG4gICAgICAgICAgICAgICAgZXJyb3JUZXh0PXt0aGlzLnN0YXRlLmVycm9yVGV4dH1cbiAgICAgICAgICAgICAgICBob21lc2VydmVyPXt0aGlzLnByb3BzLnNlcnZlckNvbmZpZy5oc05hbWV9XG4gICAgICAgICAgICAgICAgbG9hZGluZz17dGhpcy5zdGF0ZS5waGFzZSA9PT0gUGhhc2UuU2VuZGluZ0VtYWlsfVxuICAgICAgICAgICAgICAgIG9uSW5wdXRDaGFuZ2VkPXt0aGlzLm9uSW5wdXRDaGFuZ2VkfVxuICAgICAgICAgICAgICAgIG9uTG9naW5DbGljaz17dGhpcy5wcm9wcy5vbkxvZ2luQ2xpY2shfSAvLyBzZXQgYnkgZGVmYXVsdCBwcm9wc1xuICAgICAgICAgICAgICAgIG9uU3VibWl0Rm9ybT17dGhpcy5vblN1Ym1pdEZvcm19XG4gICAgICAgICAgICAvPlxuICAgICAgICApO1xuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyByZW5kZXJDb25maXJtTG9nb3V0RGV2aWNlc0RpYWxvZygpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICAgICAgY29uc3QgeyBmaW5pc2hlZCB9ID0gTW9kYWwuY3JlYXRlRGlhbG9nKFF1ZXN0aW9uRGlhbG9nLCB7XG4gICAgICAgICAgICB0aXRsZTogX3QoXCJjb21tb258d2FybmluZ1wiKSxcbiAgICAgICAgICAgIGRlc2NyaXB0aW9uOiAoXG4gICAgICAgICAgICAgICAgPGRpdj5cbiAgICAgICAgICAgICAgICAgICAgPHA+e190KFwiYXV0aHxyZXNldF9wYXNzd29yZHxvdGhlcl9kZXZpY2VzX2xvZ291dF93YXJuaW5nXzFcIil9PC9wPlxuICAgICAgICAgICAgICAgICAgICA8cD57X3QoXCJhdXRofHJlc2V0X3Bhc3N3b3JkfG90aGVyX2RldmljZXNfbG9nb3V0X3dhcm5pbmdfMlwiKX08L3A+XG4gICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICApLFxuICAgICAgICAgICAgYnV0dG9uOiBfdChcImFjdGlvbnxjb250aW51ZVwiKSxcbiAgICAgICAgfSk7XG4gICAgICAgIGNvbnN0IFtjb25maXJtZWRdID0gYXdhaXQgZmluaXNoZWQ7XG4gICAgICAgIHJldHVybiAhIWNvbmZpcm1lZDtcbiAgICB9XG5cbiAgICBwdWJsaWMgcmVuZGVyQ2hlY2tFbWFpbCgpOiBKU1guRWxlbWVudCB7XG4gICAgICAgIHJldHVybiAoXG4gICAgICAgICAgICA8Q2hlY2tFbWFpbFxuICAgICAgICAgICAgICAgIGVtYWlsPXt0aGlzLnN0YXRlLmVtYWlsfVxuICAgICAgICAgICAgICAgIGVycm9yVGV4dD17dGhpcy5zdGF0ZS5lcnJvclRleHR9XG4gICAgICAgICAgICAgICAgb25SZUVudGVyRW1haWxDbGljaz17KCkgPT4gdGhpcy5zZXRTdGF0ZSh7IHBoYXNlOiBQaGFzZS5FbnRlckVtYWlsIH0pfVxuICAgICAgICAgICAgICAgIG9uUmVzZW5kQ2xpY2s9e3RoaXMuc2VuZFZlcmlmaWNhdGlvbk1haWx9XG4gICAgICAgICAgICAgICAgb25TdWJtaXRGb3JtPXt0aGlzLm9uU3VibWl0Rm9ybX1cbiAgICAgICAgICAgIC8+XG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgcHVibGljIHJlbmRlclNldFBhc3N3b3JkKCk6IEpTWC5FbGVtZW50IHtcbiAgICAgICAgY29uc3Qgc3VibWl0QnV0dG9uQ2hpbGQgPVxuICAgICAgICAgICAgdGhpcy5zdGF0ZS5waGFzZSA9PT0gUGhhc2UuUmVzZXR0aW5nUGFzc3dvcmQgPyA8U3Bpbm5lciB3PXsxNn0gaD17MTZ9IC8+IDogX3QoXCJhdXRofHJlc2V0X3Bhc3N3b3JkX2FjdGlvblwiKTtcblxuICAgICAgICByZXR1cm4gKFxuICAgICAgICAgICAgPD5cbiAgICAgICAgICAgICAgICA8TG9ja1NvbGlkSWNvbiBjbGFzc05hbWU9XCJteF9BdXRoQm9keV9sb2NrSWNvblwiIC8+XG4gICAgICAgICAgICAgICAgPGgxPntfdChcImF1dGh8cmVzZXRfcGFzc3dvcmRfdGl0bGVcIil9PC9oMT5cbiAgICAgICAgICAgICAgICA8Zm9ybSBvblN1Ym1pdD17dGhpcy5vblN1Ym1pdEZvcm19PlxuICAgICAgICAgICAgICAgICAgICA8ZmllbGRzZXQgZGlzYWJsZWQ9e3RoaXMuc3RhdGUucGhhc2UgPT09IFBoYXNlLlJlc2V0dGluZ1Bhc3N3b3JkfT5cbiAgICAgICAgICAgICAgICAgICAgICAgIDxkaXYgY2xhc3NOYW1lPVwibXhfQXV0aEJvZHlfZmllbGRSb3dcIj5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8UGFzc3BocmFzZUZpZWxkXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWU9XCJyZXNldF9wYXNzd29yZFwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU9XCJwYXNzd29yZFwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPXtfdGQoXCJhdXRofGNoYW5nZV9wYXNzd29yZF9uZXdfbGFiZWxcIil9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlPXt0aGlzLnN0YXRlLnBhc3N3b3JkfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaW5TY29yZT17UEFTU1dPUkRfTUlOX1NDT1JFfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWVsZFJlZj17KGZpZWxkKSA9PiAodGhpcy5maWVsZFBhc3N3b3JkID0gZmllbGQpfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbkNoYW5nZT17dGhpcy5vbklucHV0Q2hhbmdlZC5iaW5kKHRoaXMsIFwicGFzc3dvcmRcIil9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF1dG9Db21wbGV0ZT1cIm5ldy1wYXNzd29yZFwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLz5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8UGFzc3BocmFzZUNvbmZpcm1GaWVsZFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lPVwicmVzZXRfcGFzc3dvcmRfY29uZmlybVwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPXtfdGQoXCJhdXRofHJlc2V0X3Bhc3N3b3JkfGNvbmZpcm1fbmV3X3Bhc3N3b3JkXCIpfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbFJlcXVpcmVkPXtfdGQoXCJhdXRofHJlc2V0X3Bhc3N3b3JkfHBhc3N3b3JkX25vdF9lbnRlcmVkXCIpfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbEludmFsaWQ9e190ZChcImF1dGh8cmVzZXRfcGFzc3dvcmR8cGFzc3dvcmRzX21pc21hdGNoXCIpfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZT17dGhpcy5zdGF0ZS5wYXNzd29yZDJ9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3N3b3JkPXt0aGlzLnN0YXRlLnBhc3N3b3JkfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWVsZFJlZj17KGZpZWxkKSA9PiAodGhpcy5maWVsZFBhc3N3b3JkQ29uZmlybSA9IGZpZWxkKX1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb25DaGFuZ2U9e3RoaXMub25JbnB1dENoYW5nZWQuYmluZCh0aGlzLCBcInBhc3N3b3JkMlwiKX1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXV0b0NvbXBsZXRlPVwibmV3LXBhc3N3b3JkXCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvPlxuICAgICAgICAgICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzTmFtZT1cIm14X0F1dGhCb2R5X2ZpZWxkUm93XCI+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPFN0eWxlZENoZWNrYm94XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9uQ2hhbmdlPXsoKSA9PiB0aGlzLnNldFN0YXRlKHsgbG9nb3V0RGV2aWNlczogIXRoaXMuc3RhdGUubG9nb3V0RGV2aWNlcyB9KX1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2hlY2tlZD17dGhpcy5zdGF0ZS5sb2dvdXREZXZpY2VzfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAge190KFwiYXV0aHxyZXNldF9wYXNzd29yZHxzaWduX291dF9vdGhlcl9kZXZpY2VzXCIpfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwvU3R5bGVkQ2hlY2tib3g+XG4gICAgICAgICAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICAgICAgICAgICAgIHt0aGlzLnN0YXRlLmVycm9yVGV4dCAmJiA8RXJyb3JNZXNzYWdlIG1lc3NhZ2U9e3RoaXMuc3RhdGUuZXJyb3JUZXh0fSAvPn1cbiAgICAgICAgICAgICAgICAgICAgICAgIDxidXR0b24gdHlwZT1cInN1Ym1pdFwiIGNsYXNzTmFtZT1cIm14X0xvZ2luX3N1Ym1pdFwiPlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHtzdWJtaXRCdXR0b25DaGlsZH1cbiAgICAgICAgICAgICAgICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgICAgICAgICAgICA8L2ZpZWxkc2V0PlxuICAgICAgICAgICAgICAgIDwvZm9ybT5cbiAgICAgICAgICAgIDwvPlxuICAgICAgICApO1xuICAgIH1cblxuICAgIHB1YmxpYyByZW5kZXJEb25lKCk6IEpTWC5FbGVtZW50IHtcbiAgICAgICAgcmV0dXJuIChcbiAgICAgICAgICAgIDw+XG4gICAgICAgICAgICAgICAgPENoZWNrSWNvbiBjbGFzc05hbWU9XCJteF9JY29uIG14X0ljb25fMzIgbXhfSWNvbl9hY2NlbnRcIiAvPlxuICAgICAgICAgICAgICAgIDxoMT57X3QoXCJhdXRofHJlc2V0X3Bhc3N3b3JkfHJlc2V0X3N1Y2Nlc3NmdWxcIil9PC9oMT5cbiAgICAgICAgICAgICAgICB7dGhpcy5zdGF0ZS5sb2dvdXREZXZpY2VzID8gPHA+e190KFwiYXV0aHxyZXNldF9wYXNzd29yZHxkZXZpY2VzX2xvZ291dF9zdWNjZXNzXCIpfTwvcD4gOiBudWxsfVxuICAgICAgICAgICAgICAgIDxpbnB1dFxuICAgICAgICAgICAgICAgICAgICBjbGFzc05hbWU9XCJteF9Mb2dpbl9zdWJtaXRcIlxuICAgICAgICAgICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICAgICAgICAgICAgb25DbGljaz17dGhpcy5wcm9wcy5vbkNvbXBsZXRlfVxuICAgICAgICAgICAgICAgICAgICB2YWx1ZT17X3QoXCJhdXRofHJlc2V0X3Bhc3N3b3JkfHJldHVybl90b19sb2dpblwiKX1cbiAgICAgICAgICAgICAgICAvPlxuICAgICAgICAgICAgPC8+XG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgcHVibGljIHJlbmRlcigpOiBSZWFjdC5SZWFjdE5vZGUge1xuICAgICAgICBsZXQgcmVzZXRQYXNzd29yZEpzeDogSlNYLkVsZW1lbnQ7XG5cbiAgICAgICAgc3dpdGNoICh0aGlzLnN0YXRlLnBoYXNlKSB7XG4gICAgICAgICAgICBjYXNlIFBoYXNlLkVudGVyRW1haWw6XG4gICAgICAgICAgICBjYXNlIFBoYXNlLlNlbmRpbmdFbWFpbDpcbiAgICAgICAgICAgICAgICByZXNldFBhc3N3b3JkSnN4ID0gdGhpcy5yZW5kZXJFbnRlckVtYWlsKCk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIFBoYXNlLkVtYWlsU2VudDpcbiAgICAgICAgICAgICAgICByZXNldFBhc3N3b3JkSnN4ID0gdGhpcy5yZW5kZXJDaGVja0VtYWlsKCk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIFBoYXNlLlBhc3N3b3JkSW5wdXQ6XG4gICAgICAgICAgICBjYXNlIFBoYXNlLlJlc2V0dGluZ1Bhc3N3b3JkOlxuICAgICAgICAgICAgICAgIHJlc2V0UGFzc3dvcmRKc3ggPSB0aGlzLnJlbmRlclNldFBhc3N3b3JkKCk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIFBoYXNlLkRvbmU6XG4gICAgICAgICAgICAgICAgcmVzZXRQYXNzd29yZEpzeCA9IHRoaXMucmVuZGVyRG9uZSgpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICAvLyBUaGlzIHNob3VsZCBub3QgaGFwcGVuLiBIb3dldmVyLCBpdCBpcyBsb2dnZWQgYW5kIHRoZSB1c2VyIGlzIHNlbnQgdG8gdGhlIHN0YXJ0LlxuICAgICAgICAgICAgICAgIGxvZ2dlci53YXJuKGB1bmtub3duIGZvcmdvdCBwYXNzd29yZCBwaGFzZSAke3RoaXMuc3RhdGUucGhhc2V9YCk7XG4gICAgICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICAgICAgICAgIHBoYXNlOiBQaGFzZS5FbnRlckVtYWlsLFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiAoXG4gICAgICAgICAgICA8QXV0aFBhZ2U+XG4gICAgICAgICAgICAgICAgPEF1dGhIZWFkZXIgLz5cbiAgICAgICAgICAgICAgICA8QXV0aEJvZHkgY2xhc3NOYW1lPVwibXhfQXV0aEJvZHlfZm9yZ290LXBhc3N3b3JkXCI+e3Jlc2V0UGFzc3dvcmRKc3h9PC9BdXRoQm9keT5cbiAgICAgICAgICAgIDwvQXV0aFBhZ2U+XG4gICAgICAgICk7XG4gICAgfVxufVxuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7OztBQVVBLElBQUFBLE1BQUEsR0FBQUMsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFDLE9BQUEsR0FBQUQsT0FBQTtBQUNBLElBQUFFLE1BQUEsR0FBQUYsT0FBQTtBQUNBLElBQUFHLE1BQUEsR0FBQUgsT0FBQTtBQUVBLElBQUFJLGdCQUFBLEdBQUFKLE9BQUE7QUFDQSxJQUFBSyxNQUFBLEdBQUFOLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBTSxjQUFBLEdBQUFQLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBTyxTQUFBLEdBQUFSLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBUSxnQkFBQSxHQUFBVCxzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQVMsaUJBQUEsR0FBQVQsT0FBQTtBQUNBLElBQUFVLFdBQUEsR0FBQVgsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFXLFNBQUEsR0FBQVosc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFZLHVCQUFBLEdBQUFiLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBYSxlQUFBLEdBQUFkLHNCQUFBLENBQUFDLE9BQUE7QUFFQSxJQUFBYyxlQUFBLEdBQUFmLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBZSxXQUFBLEdBQUFmLE9BQUE7QUFDQSxJQUFBZ0IsV0FBQSxHQUFBaEIsT0FBQTtBQUVBLElBQUFpQixhQUFBLEdBQUFqQixPQUFBO0FBQ0EsSUFBQWtCLGlCQUFBLEdBQUFsQixPQUFBO0FBQ0EsSUFBQW1CLFFBQUEsR0FBQXBCLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBb0IsVUFBQSxHQUFBcEIsT0FBQTtBQUNBLElBQUFxQixtQkFBQSxHQUFBdEIsc0JBQUEsQ0FBQUMsT0FBQTtBQWxDQTtBQUNBO0FBQ0E7QUFDQTtBQUNB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