matrix-react-sdk
Version:
SDK for matrix.org using React
541 lines (460 loc) • 63.5 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = exports.PASSWORD_MIN_SCORE = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _react = _interopRequireDefault(require("react"));
var sdk = _interopRequireWildcard(require("../../../index"));
var Email = _interopRequireWildcard(require("../../../email"));
var _phonenumber = require("../../../phonenumber");
var _Modal = _interopRequireDefault(require("../../../Modal"));
var _languageHandler = require("../../../languageHandler");
var _SdkConfig = _interopRequireDefault(require("../../../SdkConfig"));
var _Registration = require("../../../Registration");
var _Validation = _interopRequireDefault(require("../elements/Validation"));
var _PassphraseField = _interopRequireDefault(require("./PassphraseField"));
var _CountlyAnalytics = _interopRequireDefault(require("../../../CountlyAnalytics"));
var _Field = _interopRequireDefault(require("../elements/Field"));
var _RegistrationEmailPromptDialog = _interopRequireDefault(require("../dialogs/RegistrationEmailPromptDialog"));
var _replaceableComponent = require("../../../utils/replaceableComponent");
var _dec, _class, _class2, _temp;
var RegistrationField;
(function (RegistrationField) {
RegistrationField["Email"] = "field_email";
RegistrationField["PhoneNumber"] = "field_phone_number";
RegistrationField["Username"] = "field_username";
RegistrationField["Password"] = "field_password";
RegistrationField["PasswordConfirm"] = "field_password_confirm";
})(RegistrationField || (RegistrationField = {}));
const PASSWORD_MIN_SCORE = 3; // safely unguessable: moderate protection from offline slow-hash scenario.
exports.PASSWORD_MIN_SCORE = PASSWORD_MIN_SCORE;
let RegistrationForm = (
/*
* A pure UI component which displays a registration form.
*/
_dec = (0, _replaceableComponent.replaceableComponent)("views.auth.RegistrationForm"), _dec(_class = (_temp = _class2 = class RegistrationForm extends _react.default.PureComponent
/*:: <IProps, IState>*/
{
constructor(props) {
super(props);
(0, _defineProperty2.default)(this, "onSubmit", async ev => {
ev.preventDefault();
ev.persist();
if (!this.props.canSubmit) return;
const allFieldsValid = await this.verifyFieldsBeforeSubmit();
if (!allFieldsValid) {
_CountlyAnalytics.default.instance.track("onboarding_registration_submit_failed");
return;
}
if (this.state.email === '') {
if (this.showEmail()) {
_CountlyAnalytics.default.instance.track("onboarding_registration_submit_warn");
_Modal.default.createTrackedDialog("Email prompt dialog", '', _RegistrationEmailPromptDialog.default, {
onFinished: async (confirmed
/*: boolean*/
, email
/*: string*/
) => {
if (confirmed) {
this.setState({
email
}, () => {
this.doSubmit(ev);
});
}
}
});
} else {
// user can't set an e-mail so don't prompt them to
this.doSubmit(ev);
return;
}
} else {
this.doSubmit(ev);
}
});
(0, _defineProperty2.default)(this, "onEmailChange", ev => {
this.setState({
email: ev.target.value
});
});
(0, _defineProperty2.default)(this, "onEmailValidate", async fieldState => {
const result = await this.validateEmailRules(fieldState);
this.markFieldValid(RegistrationField.Email, result.valid);
return result;
});
(0, _defineProperty2.default)(this, "validateEmailRules", (0, _Validation.default)({
description: () => (0, _languageHandler._t)("Use an email address to recover your account"),
hideDescriptionIfValid: true,
rules: [{
key: "required",
test({
value,
allowEmpty
}) {
return allowEmpty || !this.authStepIsRequired('m.login.email.identity') || !!value;
},
invalid: () => (0, _languageHandler._t)("Enter email address (required on this homeserver)")
}, {
key: "email",
test: ({
value
}) => !value || Email.looksValid(value),
invalid: () => (0, _languageHandler._t)("Doesn't look like a valid email address")
}]
}));
(0, _defineProperty2.default)(this, "onPasswordChange", ev => {
this.setState({
password: ev.target.value
});
});
(0, _defineProperty2.default)(this, "onPasswordValidate", result => {
this.markFieldValid(RegistrationField.Password, result.valid);
});
(0, _defineProperty2.default)(this, "onPasswordConfirmChange", ev => {
this.setState({
passwordConfirm: ev.target.value
});
});
(0, _defineProperty2.default)(this, "onPasswordConfirmValidate", async fieldState => {
const result = await this.validatePasswordConfirmRules(fieldState);
this.markFieldValid(RegistrationField.PasswordConfirm, result.valid);
return result;
});
(0, _defineProperty2.default)(this, "validatePasswordConfirmRules", (0, _Validation.default)({
rules: [{
key: "required",
test: ({
value,
allowEmpty
}) => allowEmpty || !!value,
invalid: () => (0, _languageHandler._t)("Confirm password")
}, {
key: "match",
test({
value
}) {
return !value || value === this.state.password;
},
invalid: () => (0, _languageHandler._t)("Passwords don't match")
}]
}));
(0, _defineProperty2.default)(this, "onPhoneCountryChange", newVal => {
this.setState({
phoneCountry: newVal.iso2
});
});
(0, _defineProperty2.default)(this, "onPhoneNumberChange", ev => {
this.setState({
phoneNumber: ev.target.value
});
});
(0, _defineProperty2.default)(this, "onPhoneNumberValidate", async fieldState => {
const result = await this.validatePhoneNumberRules(fieldState);
this.markFieldValid(RegistrationField.PhoneNumber, result.valid);
return result;
});
(0, _defineProperty2.default)(this, "validatePhoneNumberRules", (0, _Validation.default)({
description: () => (0, _languageHandler._t)("Other users can invite you to rooms using your contact details"),
hideDescriptionIfValid: true,
rules: [{
key: "required",
test({
value,
allowEmpty
}) {
return allowEmpty || !this.authStepIsRequired('m.login.msisdn') || !!value;
},
invalid: () => (0, _languageHandler._t)("Enter phone number (required on this homeserver)")
}, {
key: "email",
test: ({
value
}) => !value || (0, _phonenumber.looksValid)(value),
invalid: () => (0, _languageHandler._t)("That phone number doesn't look quite right, please check and try again")
}]
}));
(0, _defineProperty2.default)(this, "onUsernameChange", ev => {
this.setState({
username: ev.target.value
});
});
(0, _defineProperty2.default)(this, "onUsernameValidate", async fieldState => {
const result = await this.validateUsernameRules(fieldState);
this.markFieldValid(RegistrationField.Username, result.valid);
return result;
});
(0, _defineProperty2.default)(this, "validateUsernameRules", (0, _Validation.default)({
description: () => (0, _languageHandler._t)("Use lowercase letters, numbers, dashes and underscores only"),
hideDescriptionIfValid: true,
rules: [{
key: "required",
test: ({
value,
allowEmpty
}) => allowEmpty || !!value,
invalid: () => (0, _languageHandler._t)("Enter username")
}, {
key: "safeLocalpart",
test: ({
value
}) => !value || _Registration.SAFE_LOCALPART_REGEX.test(value),
invalid: () => (0, _languageHandler._t)("Some characters not allowed")
}]
}));
this.state = {
fieldValid: {},
phoneCountry: this.props.defaultPhoneCountry,
username: this.props.defaultUsername || "",
email: this.props.defaultEmail || "",
phoneNumber: this.props.defaultPhoneNumber || "",
password: this.props.defaultPassword || "",
passwordConfirm: this.props.defaultPassword || "",
passwordComplexity: null
};
_CountlyAnalytics.default.instance.track("onboarding_registration_begin");
}
doSubmit(ev) {
const email = this.state.email.trim();
_CountlyAnalytics.default.instance.track("onboarding_registration_submit_ok", {
email: !!email
});
const promise = this.props.onRegisterClick({
username: this.state.username.trim(),
password: this.state.password.trim(),
email: email,
phoneCountry: this.state.phoneCountry,
phoneNumber: this.state.phoneNumber
});
if (promise) {
ev.target.disabled = true;
promise.finally(function () {
ev.target.disabled = false;
});
}
}
async verifyFieldsBeforeSubmit() {
// Blur the active element if any, so we first run its blur validation,
// which is less strict than the pass we're about to do below for all fields.
const activeElement = document.activeElement;
if (activeElement) {
activeElement.blur();
}
const fieldIDsInDisplayOrder = [RegistrationField.Username, RegistrationField.Password, RegistrationField.PasswordConfirm, RegistrationField.Email, RegistrationField.PhoneNumber]; // Run all fields with stricter validation that no longer allows empty
// values for required fields.
for (const fieldID of fieldIDsInDisplayOrder) {
const field = this[fieldID];
if (!field) {
continue;
} // We must wait for these validations to finish before queueing
// up the setState below so our setState goes in the queue after
// all the setStates from these validate calls (that's how we
// know they've finished).
await field.validate({
allowEmpty: false
});
} // Validation and state updates are async, so we need to wait for them to complete
// first. Queue a `setState` callback and wait for it to resolve.
await new Promise(resolve => this.setState({}, resolve));
if (this.allFieldsValid()) {
return true;
}
const invalidField = this.findFirstInvalidField(fieldIDsInDisplayOrder);
if (!invalidField) {
return true;
} // Focus the first invalid field and show feedback in the stricter mode
// that no longer allows empty values for required fields.
invalidField.focus();
invalidField.validate({
allowEmpty: false,
focused: true
});
return false;
}
/**
* @returns {boolean} true if all fields were valid last time they were validated.
*/
allFieldsValid() {
const keys = Object.keys(this.state.fieldValid);
for (let i = 0; i < keys.length; ++i) {
if (!this.state.fieldValid[keys[i]]) {
return false;
}
}
return true;
}
findFirstInvalidField(fieldIDs
/*: RegistrationField[]*/
) {
for (const fieldID of fieldIDs) {
if (!this.state.fieldValid[fieldID] && this[fieldID]) {
return this[fieldID];
}
}
return null;
}
markFieldValid(fieldID
/*: RegistrationField*/
, valid
/*: boolean*/
) {
const {
fieldValid
} = this.state;
fieldValid[fieldID] = valid;
this.setState({
fieldValid
});
}
/**
* A step is required if all flows include that step.
*
* @param {string} step A stage name to check
* @returns {boolean} Whether it is required
*/
authStepIsRequired(step
/*: string*/
) {
return this.props.flows.every(flow => {
return flow.stages.includes(step);
});
}
/**
* A step is used if any flows include that step.
*
* @param {string} step A stage name to check
* @returns {boolean} Whether it is used
*/
authStepIsUsed(step
/*: string*/
) {
return this.props.flows.some(flow => {
return flow.stages.includes(step);
});
}
showEmail() {
if (!this.authStepIsUsed('m.login.email.identity')) {
return false;
}
return true;
}
showPhoneNumber() {
const threePidLogin = !_SdkConfig.default.get().disable_3pid_login;
if (!threePidLogin || !this.authStepIsUsed('m.login.msisdn')) {
return false;
}
return true;
}
renderEmail() {
if (!this.showEmail()) {
return null;
}
const emailPlaceholder = this.authStepIsRequired('m.login.email.identity') ? (0, _languageHandler._t)("Email") : (0, _languageHandler._t)("Email (optional)");
return /*#__PURE__*/_react.default.createElement(_Field.default, {
ref: field => this[RegistrationField.Email] = field,
type: "text",
label: emailPlaceholder,
value: this.state.email,
onChange: this.onEmailChange,
onValidate: this.onEmailValidate,
onFocus: () => _CountlyAnalytics.default.instance.track("onboarding_registration_email_focus"),
onBlur: () => _CountlyAnalytics.default.instance.track("onboarding_registration_email_blur")
});
}
renderPassword() {
return /*#__PURE__*/_react.default.createElement(_PassphraseField.default, {
id: "mx_RegistrationForm_password",
fieldRef: field => this[RegistrationField.Password] = field,
minScore: PASSWORD_MIN_SCORE,
value: this.state.password,
onChange: this.onPasswordChange,
onValidate: this.onPasswordValidate,
onFocus: () => _CountlyAnalytics.default.instance.track("onboarding_registration_password_focus"),
onBlur: () => _CountlyAnalytics.default.instance.track("onboarding_registration_password_blur")
});
}
renderPasswordConfirm() {
return /*#__PURE__*/_react.default.createElement(_Field.default, {
id: "mx_RegistrationForm_passwordConfirm",
ref: field => this[RegistrationField.PasswordConfirm] = field,
type: "password",
autoComplete: "new-password",
label: (0, _languageHandler._t)("Confirm password"),
value: this.state.passwordConfirm,
onChange: this.onPasswordConfirmChange,
onValidate: this.onPasswordConfirmValidate,
onFocus: () => _CountlyAnalytics.default.instance.track("onboarding_registration_passwordConfirm_focus"),
onBlur: () => _CountlyAnalytics.default.instance.track("onboarding_registration_passwordConfirm_blur")
});
}
renderPhoneNumber() {
if (!this.showPhoneNumber()) {
return null;
}
const CountryDropdown = sdk.getComponent('views.auth.CountryDropdown');
const phoneLabel = this.authStepIsRequired('m.login.msisdn') ? (0, _languageHandler._t)("Phone") : (0, _languageHandler._t)("Phone (optional)");
const phoneCountry = /*#__PURE__*/_react.default.createElement(CountryDropdown, {
value: this.state.phoneCountry,
isSmall: true,
showPrefix: true,
onOptionChange: this.onPhoneCountryChange
});
return /*#__PURE__*/_react.default.createElement(_Field.default, {
ref: field => this[RegistrationField.PhoneNumber] = field,
type: "text",
label: phoneLabel,
value: this.state.phoneNumber,
prefixComponent: phoneCountry,
onChange: this.onPhoneNumberChange,
onValidate: this.onPhoneNumberValidate
});
}
renderUsername() {
return /*#__PURE__*/_react.default.createElement(_Field.default, {
id: "mx_RegistrationForm_username",
ref: field => this[RegistrationField.Username] = field,
type: "text",
autoFocus: true,
label: (0, _languageHandler._t)("Username"),
placeholder: (0, _languageHandler._t)("Username").toLocaleLowerCase(),
value: this.state.username,
onChange: this.onUsernameChange,
onValidate: this.onUsernameValidate,
onFocus: () => _CountlyAnalytics.default.instance.track("onboarding_registration_username_focus"),
onBlur: () => _CountlyAnalytics.default.instance.track("onboarding_registration_username_blur")
});
}
render() {
const registerButton = /*#__PURE__*/_react.default.createElement("input", {
className: "mx_Login_submit",
type: "submit",
value: (0, _languageHandler._t)("Register"),
disabled: !this.props.canSubmit
});
let emailHelperText = null;
if (this.showEmail()) {
if (this.showPhoneNumber()) {
emailHelperText = /*#__PURE__*/_react.default.createElement("div", null, (0, _languageHandler._t)("Add an email to be able to reset your password."), " ", (0, _languageHandler._t)("Use email or phone to optionally be discoverable by existing contacts."));
} else {
emailHelperText = /*#__PURE__*/_react.default.createElement("div", null, (0, _languageHandler._t)("Add an email to be able to reset your password."), " ", (0, _languageHandler._t)("Use email to optionally be discoverable by existing contacts."));
}
}
return /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement("form", {
onSubmit: this.onSubmit
}, /*#__PURE__*/_react.default.createElement("div", {
className: "mx_AuthBody_fieldRow"
}, this.renderUsername()), /*#__PURE__*/_react.default.createElement("div", {
className: "mx_AuthBody_fieldRow"
}, this.renderPassword(), this.renderPasswordConfirm()), /*#__PURE__*/_react.default.createElement("div", {
className: "mx_AuthBody_fieldRow"
}, this.renderEmail(), this.renderPhoneNumber()), emailHelperText, registerButton));
}
}, (0, _defineProperty2.default)(_class2, "defaultProps", {
onValidationChange: console.error,
canSubmit: true
}), _temp)) || _class);
exports.default = RegistrationForm;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9jb21wb25lbnRzL3ZpZXdzL2F1dGgvUmVnaXN0cmF0aW9uRm9ybS50c3giXSwibmFtZXMiOlsiUmVnaXN0cmF0aW9uRmllbGQiLCJQQVNTV09SRF9NSU5fU0NPUkUiLCJSZWdpc3RyYXRpb25Gb3JtIiwiUmVhY3QiLCJQdXJlQ29tcG9uZW50IiwiY29uc3RydWN0b3IiLCJwcm9wcyIsImV2IiwicHJldmVudERlZmF1bHQiLCJwZXJzaXN0IiwiY2FuU3VibWl0IiwiYWxsRmllbGRzVmFsaWQiLCJ2ZXJpZnlGaWVsZHNCZWZvcmVTdWJtaXQiLCJDb3VudGx5QW5hbHl0aWNzIiwiaW5zdGFuY2UiLCJ0cmFjayIsInN0YXRlIiwiZW1haWwiLCJzaG93RW1haWwiLCJNb2RhbCIsImNyZWF0ZVRyYWNrZWREaWFsb2ciLCJSZWdpc3RyYXRpb25FbWFpbFByb21wdERpYWxvZyIsIm9uRmluaXNoZWQiLCJjb25maXJtZWQiLCJzZXRTdGF0ZSIsImRvU3VibWl0IiwidGFyZ2V0IiwidmFsdWUiLCJmaWVsZFN0YXRlIiwicmVzdWx0IiwidmFsaWRhdGVFbWFpbFJ1bGVzIiwibWFya0ZpZWxkVmFsaWQiLCJFbWFpbCIsInZhbGlkIiwiZGVzY3JpcHRpb24iLCJoaWRlRGVzY3JpcHRpb25JZlZhbGlkIiwicnVsZXMiLCJrZXkiLCJ0ZXN0IiwiYWxsb3dFbXB0eSIsImF1dGhTdGVwSXNSZXF1aXJlZCIsImludmFsaWQiLCJsb29rc1ZhbGlkIiwicGFzc3dvcmQiLCJQYXNzd29yZCIsInBhc3N3b3JkQ29uZmlybSIsInZhbGlkYXRlUGFzc3dvcmRDb25maXJtUnVsZXMiLCJQYXNzd29yZENvbmZpcm0iLCJuZXdWYWwiLCJwaG9uZUNvdW50cnkiLCJpc28yIiwicGhvbmVOdW1iZXIiLCJ2YWxpZGF0ZVBob25lTnVtYmVyUnVsZXMiLCJQaG9uZU51bWJlciIsInVzZXJuYW1lIiwidmFsaWRhdGVVc2VybmFtZVJ1bGVzIiwiVXNlcm5hbWUiLCJTQUZFX0xPQ0FMUEFSVF9SRUdFWCIsImZpZWxkVmFsaWQiLCJkZWZhdWx0UGhvbmVDb3VudHJ5IiwiZGVmYXVsdFVzZXJuYW1lIiwiZGVmYXVsdEVtYWlsIiwiZGVmYXVsdFBob25lTnVtYmVyIiwiZGVmYXVsdFBhc3N3b3JkIiwicGFzc3dvcmRDb21wbGV4aXR5IiwidHJpbSIsInByb21pc2UiLCJvblJlZ2lzdGVyQ2xpY2siLCJkaXNhYmxlZCIsImZpbmFsbHkiLCJhY3RpdmVFbGVtZW50IiwiZG9jdW1lbnQiLCJibHVyIiwiZmllbGRJRHNJbkRpc3BsYXlPcmRlciIsImZpZWxkSUQiLCJmaWVsZCIsInZhbGlkYXRlIiwiUHJvbWlzZSIsInJlc29sdmUiLCJpbnZhbGlkRmllbGQiLCJmaW5kRmlyc3RJbnZhbGlkRmllbGQiLCJmb2N1cyIsImZvY3VzZWQiLCJrZXlzIiwiT2JqZWN0IiwiaSIsImxlbmd0aCIsImZpZWxkSURzIiwic3RlcCIsImZsb3dzIiwiZXZlcnkiLCJmbG93Iiwic3RhZ2VzIiwiaW5jbHVkZXMiLCJhdXRoU3RlcElzVXNlZCIsInNvbWUiLCJzaG93UGhvbmVOdW1iZXIiLCJ0aHJlZVBpZExvZ2luIiwiU2RrQ29uZmlnIiwiZ2V0IiwiZGlzYWJsZV8zcGlkX2xvZ2luIiwicmVuZGVyRW1haWwiLCJlbWFpbFBsYWNlaG9sZGVyIiwib25FbWFpbENoYW5nZSIsIm9uRW1haWxWYWxpZGF0ZSIsInJlbmRlclBhc3N3b3JkIiwib25QYXNzd29yZENoYW5nZSIsIm9uUGFzc3dvcmRWYWxpZGF0ZSIsInJlbmRlclBhc3N3b3JkQ29uZmlybSIsIm9uUGFzc3dvcmRDb25maXJtQ2hhbmdlIiwib25QYXNzd29yZENvbmZpcm1WYWxpZGF0ZSIsInJlbmRlclBob25lTnVtYmVyIiwiQ291bnRyeURyb3Bkb3duIiwic2RrIiwiZ2V0Q29tcG9uZW50IiwicGhvbmVMYWJlbCIsIm9uUGhvbmVDb3VudHJ5Q2hhbmdlIiwib25QaG9uZU51bWJlckNoYW5nZSIsIm9uUGhvbmVOdW1iZXJWYWxpZGF0ZSIsInJlbmRlclVzZXJuYW1lIiwidG9Mb2NhbGVMb3dlckNhc2UiLCJvblVzZXJuYW1lQ2hhbmdlIiwib25Vc2VybmFtZVZhbGlkYXRlIiwicmVuZGVyIiwicmVnaXN0ZXJCdXR0b24iLCJlbWFpbEhlbHBlclRleHQiLCJvblN1Ym1pdCIsIm9uVmFsaWRhdGlvbkNoYW5nZSIsImNvbnNvbGUiLCJlcnJvciJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7OztBQWlCQTs7QUFFQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFFQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7OztJQUVLQSxpQjs7V0FBQUEsaUI7QUFBQUEsRUFBQUEsaUI7QUFBQUEsRUFBQUEsaUI7QUFBQUEsRUFBQUEsaUI7QUFBQUEsRUFBQUEsaUI7QUFBQUEsRUFBQUEsaUI7R0FBQUEsaUIsS0FBQUEsaUI7O0FBUUUsTUFBTUMsa0JBQWtCLEdBQUcsQ0FBM0IsQyxDQUE4Qjs7O0lBMENoQkMsZ0I7QUFKckI7QUFDQTtBQUNBO09BQ0MsZ0RBQXFCLDZCQUFyQixDLG1DQUFELE1BQ3FCQSxnQkFEckIsU0FDOENDLGVBQU1DO0FBRHBEO0FBQ2tGO0FBTTlFQyxFQUFBQSxXQUFXLENBQUNDLEtBQUQsRUFBUTtBQUNmLFVBQU1BLEtBQU47QUFEZSxvREFpQkEsTUFBTUMsRUFBTixJQUFZO0FBQzNCQSxNQUFBQSxFQUFFLENBQUNDLGNBQUg7QUFDQUQsTUFBQUEsRUFBRSxDQUFDRSxPQUFIO0FBRUEsVUFBSSxDQUFDLEtBQUtILEtBQUwsQ0FBV0ksU0FBaEIsRUFBMkI7QUFFM0IsWUFBTUMsY0FBYyxHQUFHLE1BQU0sS0FBS0Msd0JBQUwsRUFBN0I7O0FBQ0EsVUFBSSxDQUFDRCxjQUFMLEVBQXFCO0FBQ2pCRSxrQ0FBaUJDLFFBQWpCLENBQTBCQyxLQUExQixDQUFnQyx1Q0FBaEM7O0FBQ0E7QUFDSDs7QUFFRCxVQUFJLEtBQUtDLEtBQUwsQ0FBV0MsS0FBWCxLQUFxQixFQUF6QixFQUE2QjtBQUN6QixZQUFJLEtB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eEI2QixRQUFBQSxlQUFlLGdCQUFHLDBDQUVWLHlCQUFHLGlEQUFILENBRlUsT0FJVix5QkFBRyx3RUFBSCxDQUpVLENBQWxCO0FBT0gsT0FSRCxNQVFPO0FBQ0hBLFFBQUFBLGVBQWUsZ0JBQUcsMENBRVYseUJBQUcsaURBQUgsQ0FGVSxPQUlWLHlCQUFHLCtEQUFILENBSlUsQ0FBbEI7QUFPSDtBQUNKOztBQUVELHdCQUNJLHVEQUNJO0FBQU0sTUFBQSxRQUFRLEVBQUUsS0FBS0M7QUFBckIsb0JBQ0k7QUFBSyxNQUFBLFNBQVMsRUFBQztBQUFmLE9BQ0ssS0FBS1AsY0FBTCxFQURMLENBREosZUFJSTtBQUFLLE1BQUEsU0FBUyxFQUFDO0FBQWYsT0FDSyxLQUFLZCxjQUFMLEVBREwsRUFFSyxLQUFLRyxxQkFBTCxFQUZMLENBSkosZUFRSTtBQUFLLE1BQUEsU0FBUyxFQUFDO0FBQWYsT0FDSyxLQUFLUCxXQUFMLEVBREwsRUFFSyxLQUFLVSxpQkFBTCxFQUZMLENBUkosRUFZTWMsZUFaTixFQWFNRCxjQWJOLENBREosQ0FESjtBQW1CSDs7QUF2ZDZFLEMseURBQ3hEO0FBQ2xCRyxFQUFBQSxrQkFBa0IsRUFBRUMsT0FBTyxDQUFDQyxLQURWO0FBRWxCdkgsRUFBQUEsU0FBUyxFQUFFO0FBRk8sQyIsInNvdXJjZXNDb250ZW50IjpbIi8qXG5Db3B5cmlnaHQgMjAxOSBNaWNoYWVsIFRlbGF0eW5za2kgPDd0M2NoZ3V5QGdtYWlsLmNvbT5cbkNvcHlyaWdodCAyMDE1LCAyMDE2LCAyMDE3LCAyMDE4LCAyMDE5LCAyMDIwIFRoZSBNYXRyaXgub3JnIEZvdW5kYXRpb24gQy5JLkMuXG5cbkxpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIik7XG55b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuXG5Zb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXRcblxuICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxuXG5Vbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlXG5kaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiBcIkFTIElTXCIgQkFTSVMsXG5XSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC5cblNlZSB0aGUgTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmRcbmxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLlxuKi9cblxuaW1wb3J0IFJlYWN0IGZyb20gJ3JlYWN0JztcblxuaW1wb3J0ICogYXMgc2RrIGZyb20gJy4uLy4uLy4uL2luZGV4JztcbmltcG9ydCAqIGFzIEVtYWlsIGZyb20gJy4uLy4uLy4uL2VtYWlsJztcbmltcG9ydCB7IGxvb2tzVmFsaWQgYXMgcGhvbmVOdW1iZXJMb29rc1ZhbGlkIH0gZnJvbSAnLi4vLi4vLi4vcGhvbmVudW1iZXInO1xuaW1wb3J0IE1vZGFsIGZyb20gJy4uLy4uLy4uL01vZGFsJztcbmltcG9ydCB7IF90IH0gZnJvbSAnLi4vLi4vLi4vbGFuZ3VhZ2VIYW5kbGVyJztcbmltcG9ydCBTZGtDb25maWcgZnJvbSAnLi4vLi4vLi4vU2RrQ29uZmlnJztcbmltcG9ydCB7IFNBRkVfTE9DQUxQQVJUX1JFR0VYIH0gZnJvbSAnLi4vLi4vLi4vUmVnaXN0cmF0aW9uJztcbmltcG9ydCB3aXRoVmFsaWRhdGlvbiBmcm9tICcuLi9lbGVtZW50cy9WYWxpZGF0aW9uJztcbmltcG9ydCB7VmFsaWRhdGVkU2VydmVyQ29uZmlnfSBmcm9tIFwiLi4vLi4vLi4vdXRpbHMvQXV0b0Rpc2NvdmVyeVV0aWxzXCI7XG5pbXBvcnQgUGFzc3BocmFzZUZpZWxkIGZyb20gXCIuL1Bhc3NwaHJhc2VGaWVsZFwiO1xuaW1wb3J0IENvdW50bHlBbmFseXRpY3MgZnJvbSBcIi4uLy4uLy4uL0NvdW50bHlBbmFseXRpY3NcIjtcbmltcG9ydCBGaWVsZCBmcm9tICcuLi9lbGVtZW50cy9GaWVsZCc7XG5pbXBvcnQgUmVnaXN0cmF0aW9uRW1haWxQcm9tcHREaWFsb2cgZnJvbSAnLi4vZGlhbG9ncy9SZWdpc3RyYXRpb25FbWFpbFByb21wdERpYWxvZyc7XG5pbXBvcnQge3JlcGxhY2VhYmxlQ29tcG9uZW50fSBmcm9tIFwiLi4vLi4vLi4vdXRpbHMvcmVwbGFjZWFibGVDb21wb25lbnRcIjtcblxuZW51bSBSZWdpc3RyYXRpb25GaWVsZCB7XG4gICAgRW1haWwgPSBcImZpZWxkX2VtYWlsXCIsXG4gICAgUGhvbmVOdW1iZXIgPSBcImZpZWxkX3Bob25lX251bWJlclwiLFxuICAgIFVzZXJuYW1lID0gXCJmaWVsZF91c2VybmFtZVwiLFxuICAgIFBhc3N3b3JkID0gXCJmaWVsZF9wYXNzd29yZFwiLFxuICAgIFBhc3N3b3JkQ29uZmlybSA9IFwiZmllbGRfcGFzc3dvcmRfY29uZmlybVwiLFxufVxuXG5leHBvcnQgY29uc3QgUEFTU1dPUkRfTUlOX1NDT1JFID0gMzsgLy8gc2FmZWx5IHVuZ3Vlc3NhYmxlOiBtb2RlcmF0ZSBwcm90ZWN0aW9uIGZyb20gb2ZmbGluZSBzbG93LWhhc2ggc2NlbmFyaW8uXG5cbmludGVyZmFjZSBJUHJvcHMge1xuICAgIC8vIFZhbHVlcyBwcmUtZmlsbGVkIGluIHRoZSBpbnB1dCBib3hlcyB3aGVuIHRoZSBjb21wb25lbnQgbG9hZHNcbiAgICBkZWZhdWx0RW1haWw/OiBzdHJpbmc7XG4gICAgZGVmYXVsdFBob25lQ291bnRyeT86IHN0cmluZztcbiAgICBkZWZhdWx0UGhvbmVOdW1iZXI/OiBzdHJpbmc7XG4gICAgZGVmYXVsdFVzZXJuYW1lPzogc3RyaW5nO1xuICAgIGRlZmF1bHRQYXNzd29yZD86IHN0cmluZztcbiAgICBmbG93czoge1xuICAgICAgICBzdGFnZXM6IHN0cmluZ1tdO1xuICAgIH1bXTtcbiAgICBzZXJ2ZXJDb25maWc6IFZhbGlkYXRlZFNlcnZlckNvbmZpZztcbiAgICBjYW5TdWJtaXQ/OiBib29sZWFuO1xuXG4gICAgb25SZWdpc3RlckNsaWNrKHBhcmFtczoge1xuICAgICAgICB1c2VybmFtZTogc3RyaW5nO1xuICAgICAgICBwYXNzd29yZDogc3RyaW5nO1xuICAgICAgICBlbWFpbD86IHN0cmluZztcbiAgICAgICAgcGhvbmVDb3VudHJ5Pzogc3RyaW5nO1xuICAgICAgICBwaG9uZU51bWJlcj86IHN0cmluZztcbiAgICB9KTogUHJvbWlzZTx2b2lkPjtcbiAgICBvbkVkaXRTZXJ2ZXJEZXRhaWxzQ2xpY2s/KCk6IHZvaWQ7XG59XG5cbmludGVyZmFjZSBJU3RhdGUge1xuICAgIC8vIEZpZWxkIGVycm9yIGNvZGVzIGJ5IGZpZWxkIElEXG4gICAgZmllbGRWYWxpZDogUGFydGlhbDxSZWNvcmQ8UmVnaXN0cmF0aW9uRmllbGQsIGJvb2xlYW4+PjtcbiAgICAvLyBUaGUgSVNPMiBjb3VudHJ5IGNvZGUgc2VsZWN0ZWQgaW4gdGhlIHBob25lIG51bWJlciBlbnRyeVxuICAgIHBob25lQ291bnRyeTogc3RyaW5nO1xuICAgIHVzZXJuYW1lOiBzdHJpbmc7XG4gICAgZW1haWw6IHN0cmluZztcbiAgICBwaG9uZU51bWJlcjogc3RyaW5nO1xuICAgIHBhc3N3b3JkOiBzdHJpbmc7XG4gICAgcGFzc3dvcmRDb25maXJtOiBzdHJpbmc7XG4gICAgcGFzc3dvcmRDb21wbGV4aXR5PzogbnVtYmVyO1xufVxuXG4vKlxuICogQSBwdXJlIFVJIGNvbXBvbmVudCB3aGljaCBkaXNwbGF5cyBhIHJlZ2lzdHJhdGlvbiBmb3JtLlxuICovXG5AcmVwbGFjZWFibGVDb21wb25lbnQoXCJ2aWV3cy5hdXRoLlJlZ2lzdHJhdGlvbkZvcm1cIilcbmV4cG9ydCBkZWZhdWx0IGNsYXNzIFJlZ2lzdHJhdGlvbkZvcm0gZXh0ZW5kcyBSZWFjdC5QdXJlQ29tcG9uZW50PElQcm9wcywgSVN0YXRlPiB7XG4gICAgc3RhdGljIGRlZmF1bHRQcm9wcyA9IHtcbiAgICAgICAgb25WYWxpZGF0aW9uQ2hhbmdlOiBjb25zb2xlLmVycm9yLFxuICAgICAgICBjYW5TdWJtaXQ6IHRydWUsXG4gICAgfTtcblxuICAgIGNvbnN0cnVjdG9yKHByb3BzKSB7XG4gICAgICAgIHN1cGVyKHByb3BzKTtcblxuICAgICAgICB0aGlzLnN0YXRlID0ge1xuICAgICAgICAgICAgZmllbGRWYWxpZDoge30sXG4gICAgICAgICAgICBwaG9uZUNvdW50cnk6IHRoaXMucHJvcHMuZGVmYXVsdFBob25lQ291bnRyeSxcbiAgICAgICAgICAgIHVzZXJuYW1lOiB0aGlzLnByb3BzLmRlZmF1bHRVc2VybmFtZSB8fCBcIlwiLFxuICAgICAgICAgICAgZW1haWw6IHRoaXMucHJvcHMuZGVmYXVsdEVtYWlsIHx8IFwiXCIsXG4gICAgICAgICAgICBwaG9uZU51bWJlcjogdGhpcy5wcm9wcy5kZWZhdWx0UGhvbmVOdW1iZXIgfHwgXCJcIixcbiAgICAgICAgICAgIHBhc3N3b3JkOiB0aGlzLnByb3BzLmRlZmF1bHRQYXNzd29yZCB8fCBcIlwiLFxuICAgICAgICAgICAgcGFzc3dvcmRDb25maXJtOiB0aGlzLnByb3BzLmRlZmF1bHRQYXNzd29yZCB8fCBcIlwiLFxuICAgICAgICAgICAgcGFzc3dvcmRDb21wbGV4aXR5OiBudWxsLFxuICAgICAgICB9O1xuXG4gICAgICAgIENvdW50bHlBbmFseXRpY3MuaW5zdGFuY2UudHJhY2soXCJvbmJvYXJkaW5nX3JlZ2lzdHJhdGlvbl9iZWdpblwiKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIG9uU3VibWl0ID0gYXN5bmMgZXYgPT4ge1xuICAgICAgICBldi5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICBldi5wZXJzaXN0KCk7XG5cbiAgICAgICAgaWYgKCF0aGlzLnByb3BzLmNhblN1Ym1pdCkgcmV0dXJuO1xuXG4gICAgICAgIGNvbnN0IGFsbEZpZWxkc1ZhbGlkID0gYXdhaXQgdGhpcy52ZXJpZnlGaWVsZHNCZWZvcmVTdWJtaXQoKTtcbiAgICAgICAgaWYgKCFhbGxGaWVsZHNWYWxpZCkge1xuICAgICAgICAgICAgQ291bnRseUFuYWx5dGljcy5pbnN0YW5jZS50cmFjayhcIm9uYm9hcmRpbmdfcmVnaXN0cmF0aW9uX3N1Ym1pdF9mYWlsZWRcIik7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodGhpcy5zdGF0ZS5lbWFpbCA9PT0gJycpIHtcbiAgICAgICAgICAgIGlmICh0aGlzLnNob3dFbWFpbCgpKSB7XG4gICAgICAgICAgICAgICAgQ291bnRseUFuYWx5dGljcy5pbnN0YW5jZS50cmFjayhcIm9uYm9hcmRpbmdfcmVnaXN0cmF0aW9uX3N1Ym1pdF93YXJuXCIpO1xuICAgICAgICAgICAgICAgIE1vZGFsLmNyZWF0ZVRyYWNrZWREaWFsb2coXCJFbWFpbCBwcm9tcHQgZGlhbG9nXCIsICcnLCBSZWdpc3RyYXRpb25FbWFpbFByb21wdERpYWxvZywge1xuICAgICAgICAgICAgICAgICAgICBvbkZpbmlzaGVkOiBhc3luYyAoY29uZmlybWVkOiBib29sZWFuLCBlbWFpbD86IHN0cmluZykgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGNvbmZpcm1lZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbWFpbCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9LCAoKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuZG9TdWJtaXQoZXYpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAvLyB1c2VyIGNhbid0IHNldCBhbiBlLW1haWwgc28gZG9uJ3QgcHJvbXB0IHRoZW0gdG9cbiAgICAgICAgICAgICAgICB0aGlzLmRvU3VibWl0KGV2KTtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLmRvU3VibWl0KGV2KTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBwcml2YXRlIGRvU3VibWl0KGV2KSB7XG4gICAgICAgIGNvbnN0IGVtYWlsID0gdGhpcy5zdGF0ZS5lbWFpbC50cmltKCk7XG5cbiAgICAgICAgQ291bnRseUFuYWx5dGljcy5pbnN0YW5jZS50cmFjayhcIm9uYm9hcmRpbmdfcmVnaXN0cmF0aW9uX3N1Ym1pdF9va1wiLCB7XG4gICAgICAgICAgICBlbWFpbDogISFlbWFpbCxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgY29uc3QgcHJvbWlzZSA9IHRoaXMucHJvcHMub25SZWdpc3RlckNsaWNrKHtcbiAgICAgICAgICAgIHVzZXJuYW1lOiB0aGlzLnN0YXRlLnVzZXJuYW1lLnRyaW0oKSxcbiAgICAgICAgICAgIHBhc3N3b3JkOiB0aGlzLnN0YXRlLnBhc3N3b3JkLnRyaW0oKSxcbiAgICAgICAgICAgIGVtYWlsOiBlbWFpbCxcbiAgICAgICAgICAgIHBob25lQ291bnRyeTogdGhpcy5zdGF0ZS5waG9uZUNvdW50cnksXG4gICAgICAgICAgICBwaG9uZU51bWJlcjogdGhpcy5zdGF0ZS5waG9uZU51bWJlcixcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaWYgKHByb21pc2UpIHtcbiAgICAgICAgICAgIGV2LnRhcmdldC5kaXNhYmxlZCA9IHRydWU7XG4gICAgICAgICAgICBwcm9taXNlLmZpbmFsbHkoZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICAgICAgZXYudGFyZ2V0LmRpc2FibGVkID0gZmFsc2U7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgdmVyaWZ5RmllbGRzQmVmb3JlU3VibWl0KCkge1xuICAgICAgICAvLyBCbHVyIHRoZSBhY3RpdmUgZWxlbWVudCBpZiBhbnksIHNvIHdlIGZpcnN0IHJ1biBpdHMgYmx1ciB2YWxpZGF0aW9uLFxuICAgICAgICAvLyB3aGljaCBpcyBsZXNzIHN0cmljdCB0aGFuIHRoZSBwYXNzIHdlJ3JlIGFib3V0IHRvIGRvIGJlbG93IGZvciBhbGwgZmllbGRzLlxuICAgICAgICBjb25zdCBhY3RpdmVFbGVtZW50ID0gZG9jdW1lbnQuYWN0aXZlRWxlbWVudCBhcyBIVE1MRWxlbWVudDtcbiAgICAgICAgaWYgKGFjdGl2ZUVsZW1lbnQpIHtcbiAgICAgICAgICAgIGFjdGl2ZUVsZW1lbnQuYmx1cigpO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgZmllbGRJRHNJbkRpc3BsYXlPcmRlciA9IFtcbiAgICAgICAgICAgIFJlZ2lzdHJhdGlvbkZpZWxkLlVzZXJuYW1lLFxuICAgICAgICAgICAgUmVnaXN0cmF0aW9uRmllbGQuUGFzc3dvcmQsXG4gICAgICAgICAgICBSZWdpc3RyYXRpb25GaWVsZC5QYXNzd29yZENvbmZpcm0sXG4gICAgICAgICAgICBSZWdpc3RyYXRpb25GaWVsZC5FbWFpbCxcbiAgICAgICAgICAgIFJlZ2lzdHJhdGlvbkZpZWxkLlBob25lTnVtYmVyLFxuICAgICAgICBdO1xuXG4gICAgICAgIC8vIFJ1biBhbGwgZmllbGRzIHdpdGggc3RyaWN0ZXIgdmFsaWRhdGlvbiB0aGF0IG5vIGxvbmdlciBhbGxvd3MgZW1wdHlcbiAgICAgICAgLy8gdmFsdWVzIGZvciByZXF1aXJlZCBmaWVsZHMuXG4gICAgICAgIGZvciAoY29uc3QgZmllbGRJRCBvZiBmaWVsZElEc0luRGlzcGxheU9yZGVyKSB7XG4gICAgICAgICAgICBjb25zdCBmaWVsZCA9IHRoaXNbZmllbGRJRF07XG4gICAgICAgICAgICBpZiAoIWZpZWxkKSB7XG4gICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBXZSBtdXN0IHdhaXQgZm9yIHRoZXNlIHZhbGlkYXRpb25zIHRvIGZpbmlzaCBiZWZvcmUgcXVldWVpbmdcbiAgICAgICAgICAgIC8vIHVwIHRoZSBzZXRTdGF0ZSBiZWxvdyBzbyBvdXIgc2V0U3RhdGUgZ29lcyBpbiB0aGUgcXVldWUgYWZ0ZXJcbiAgICAgICAgICAgIC8vIGFsbCB0aGUgc2V0U3RhdGVzIGZyb20gdGhlc2UgdmFsaWRhdGUgY2FsbHMgKHRoYXQncyBob3cgd2VcbiAgICAgICAgICAgIC8vIGtub3cgdGhleSd2ZSBmaW5pc2hlZCkuXG4gICAgICAgICAgICBhd2FpdCBmaWVsZC52YWxpZGF0ZSh7IGFsbG93RW1wdHk6IGZhbHNlIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gVmFsaWRhdGlvbiBhbmQgc3RhdGUgdXBkYXRlcyBhcmUgYXN5bmMsIHNvIHdlIG5lZWQgdG8gd2FpdCBmb3IgdGhlbSB0byBjb21wbGV0ZVxuICAgICAgICAvLyBmaXJzdC4gUXVldWUgYSBgc2V0U3RhdGVgIGNhbGxiYWNrIGFuZCB3YWl0IGZvciBpdCB0byByZXNvbHZlLlxuICAgICAgICBhd2FpdCBuZXcgUHJvbWlzZTx2b2lkPihyZXNvbHZlID0+IHRoaXMuc2V0U3RhdGUoe30sIHJlc29sdmUpKTtcblxuICAgICAgICBpZiAodGhpcy5hbGxGaWVsZHNWYWxpZCgpKSB7XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGludmFsaWRGaWVsZCA9IHRoaXMuZmluZEZpcnN0SW52YWxpZEZpZWxkKGZpZWxkSURzSW5EaXNwbGF5T3JkZXIpO1xuXG4gICAgICAgIGlmICghaW52YWxpZEZpZWxkKSB7XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEZvY3VzIHRoZSBmaXJzdCBpbnZhbGlkIGZpZWxkIGFuZCBzaG93IGZlZWRiYWNrIGluIHRoZSBzdHJpY3RlciBtb2RlXG4gICAgICAgIC8vIHRoYXQgbm8gbG9uZ2VyIGFsbG93cyBlbXB0eSB2YWx1ZXMgZm9yIHJlcXVpcmVkIGZpZWxkcy5cbiAgICAgICAgaW52YWxpZEZpZWxkLmZvY3VzKCk7XG4gICAgICAgIGludmFsaWRGaWVsZC52YWxpZGF0ZSh7IGFsbG93RW1wdHk6IGZhbHNlLCBmb2N1c2VkOiB0cnVlIH0pO1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQHJldHVybnMge2Jvb2xlYW59IHRydWUgaWYgYWxsIGZpZWxkcyB3ZXJlIHZhbGlkIGxhc3QgdGltZSB0aGV5IHdlcmUgdmFsaWRhdGVkLlxuICAgICAqL1xuICAgIHByaXZhdGUgYWxsRmllbGRzVmFsaWQoKSB7XG4gICAgICAgIGNvbnN0IGtleXMgPSBPYmplY3Qua2V5cyh0aGlzLnN0YXRlLmZpZWxkVmFsaWQpO1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGtleXMubGVuZ3RoOyArK2kpIHtcbiAgICAgICAgICAgIGlmICghdGhpcy5zdGF0ZS5maWVsZFZhbGlkW2tleXNbaV1dKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cblxuICAgIHByaXZhdGUgZmluZEZpcnN0SW52YWxpZEZpZWxkKGZpZWxkSURzOiBSZWdpc3RyYXRpb25GaWVsZFtdKSB7XG4gICAgICAgIGZvciAoY29uc3QgZmllbGRJRCBvZiBmaWVsZElEcykge1xuICAgICAgICAgICAgaWYgKCF0aGlzLnN0YXRlLmZpZWxkVmFsaWRbZmllbGRJRF0gJiYgdGhpc1tmaWVsZElEXSkge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzW2ZpZWxkSURdO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIHByaXZhdGUgbWFya0ZpZWxkVmFsaWQoZmllbGRJRDogUmVnaXN0cmF0aW9uRmllbGQsIHZhbGlkOiBib29sZWFuKSB7XG4gICAgICAgIGNvbnN0IHsgZmllbGRWYWxpZCB9ID0gdGhpcy5zdGF0ZTtcbiAgICAgICAgZmllbGRWYWxpZFtmaWVsZElEXSA9IHZhbGlkO1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIGZpZWxkVmFsaWQsXG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIHByaXZhdGUgb25FbWFpbENoYW5nZSA9IGV2ID0+IHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBlbWFpbDogZXYudGFyZ2V0LnZhbHVlLFxuICAgICAgICB9KTtcbiAgICB9O1xuXG4gICAgcHJpdmF0ZSBvbkVtYWlsVmFsaWRhdGUgPSBhc3luYyBmaWVsZFN0YXRlID0+IHtcbiAgICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgdGhpcy52YWxpZGF0ZUVtYWlsUnVsZXMoZmllbGRTdGF0ZSk7XG4gICAgICAgIHRoaXMubWFya0ZpZWxkVmFsaWQoUmVnaXN0cmF0aW9uRmllbGQuRW1haWwsIHJlc3VsdC52YWxpZCk7XG4gICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfTtcblxuICAgIHByaXZhdGUgdmFsaWRhdGVFbWFpbFJ1bGVzID0gd2l0aFZhbGlkYXRpb24oe1xuICAgICAgICBkZXNjcmlwdGlvbjogKCkgPT4gX3QoXCJVc2UgYW4gZW1haWwgYWRkcmVzcyB0byByZWNvdmVyIHlvdXIgYWNjb3VudFwiKSxcbiAgICAgICAgaGlkZURlc2NyaXB0aW9uSWZWYWxpZDogdHJ1ZSxcbiAgICAgICAgcnVsZXM6IFtcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBrZXk6IFwicmVxdWlyZWRcIixcbiAgICAgICAgICAgICAgICB0ZXN0KHRoaXM6IFJlZ2lzdHJhdGlvbkZvcm0sIHsgdmFsdWUsIGFsbG93RW1wdHkgfSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gYWxsb3dFbXB0eSB8fCAhdGhpcy5hdXRoU3RlcElzUmVxdWlyZWQoJ20ubG9naW4uZW1haWwuaWRlbnRpdHknKSB8fCAhIXZhbHVlO1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgaW52YWxpZDogKCkgPT4gX3QoXCJFbnRlciBlbWFpbCBhZGRyZXNzIChyZXF1aXJlZCBvbiB0aGlzIGhvbWVzZXJ2ZXIpXCIpLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBrZXk6IFwiZW1haWxcIixcbiAgICAgICAgICAgICAgICB0ZXN0OiAoeyB2YWx1ZSB9KSA9PiAhdmFsdWUgfHwgRW1haWwubG9va3NWYWxpZCh2YWx1ZSksXG4gICAgICAgICAgICAgICAgaW52YWxpZDogKCkgPT4gX3QoXCJEb2Vzbid0IGxvb2sgbGlrZSBhIHZhbGlkIGVtYWlsIGFkZHJlc3NcIiksXG4gICAgICAgICAgICB9LFxuICAgICAgICBdLFxuICAgIH