matrix-react-sdk
Version:
SDK for matrix.org using React
525 lines (445 loc) • 63.2 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _react = _interopRequireDefault(require("react"));
var _languageHandler = require("../../../../../languageHandler");
var _SdkConfig = _interopRequireDefault(require("../../../../../SdkConfig"));
var _MatrixClientPeg = require("../../../../../MatrixClientPeg");
var _SettingsStore = _interopRequireDefault(require("../../../../../settings/SettingsStore"));
var _theme = require("../../../../../theme");
var _ThemeWatcher = _interopRequireDefault(require("../../../../../settings/watchers/ThemeWatcher"));
var _Slider = _interopRequireDefault(require("../../../elements/Slider"));
var _AccessibleButton = _interopRequireDefault(require("../../../elements/AccessibleButton"));
var _dispatcher = _interopRequireDefault(require("../../../../../dispatcher/dispatcher"));
var _FontWatcher = require("../../../../../settings/watchers/FontWatcher");
var _actions = require("../../../../../dispatcher/actions");
var _StyledCheckbox = _interopRequireDefault(require("../../../elements/StyledCheckbox"));
var _SettingsFlag = _interopRequireDefault(require("../../../elements/SettingsFlag"));
var _Field = _interopRequireDefault(require("../../../elements/Field"));
var _EventTilePreview = _interopRequireDefault(require("../../../elements/EventTilePreview"));
var _StyledRadioGroup = _interopRequireDefault(require("../../../elements/StyledRadioGroup"));
var _SettingLevel = require("../../../../../settings/SettingLevel");
var _UIFeature = require("../../../../../settings/UIFeature");
var _Layout = require("../../../../../settings/Layout");
var _replaceableComponent = require("../../../../../utils/replaceableComponent");
var _dec, _class, _temp;
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2.default)(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
let AppearanceUserSettingsTab = (_dec = (0, _replaceableComponent.replaceableComponent)("views.settings.tabs.user.AppearanceUserSettingsTab"), _dec(_class = (_temp = class AppearanceUserSettingsTab extends _react.default.Component
/*:: <IProps, IState>*/
{
constructor(props
/*: IProps*/
) {
super(props);
(0, _defineProperty2.default)(this, "MESSAGE_PREVIEW_TEXT", (0, _languageHandler._t)("Hey you. You're the best!"));
(0, _defineProperty2.default)(this, "themeTimer", void 0);
(0, _defineProperty2.default)(this, "onThemeChange", (newTheme
/*: string*/
) =>
/*: void*/
{
if (this.state.theme === newTheme) return; // doing getValue in the .catch will still return the value we failed to set,
// so remember what the value was before we tried to set it so we can revert
const oldTheme
/*: string*/
= _SettingsStore.default.getValue('theme');
_SettingsStore.default.setValue("theme", null, _SettingLevel.SettingLevel.DEVICE, newTheme).catch(() => {
_dispatcher.default.dispatch({
action: _actions.Action.RecheckTheme
});
this.setState({
theme: oldTheme
});
});
this.setState({
theme: newTheme
}); // The settings watcher doesn't fire until the echo comes back from the
// server, so to make the theme change immediately we need to manually
// do the dispatch now
// XXX: The local echoed value appears to be unreliable, in particular
// when settings custom themes(!) so adding forceTheme to override
// the value from settings.
_dispatcher.default.dispatch({
action: _actions.Action.RecheckTheme,
forceTheme: newTheme
});
});
(0, _defineProperty2.default)(this, "onUseSystemThemeChanged", (checked
/*: boolean*/
) =>
/*: void*/
{
this.setState({
useSystemTheme: checked
});
_SettingsStore.default.setValue("use_system_theme", null, _SettingLevel.SettingLevel.DEVICE, checked);
_dispatcher.default.dispatch({
action: _actions.Action.RecheckTheme
});
});
(0, _defineProperty2.default)(this, "onFontSizeChanged", (size
/*: number*/
) =>
/*: void*/
{
this.setState({
fontSize: size.toString()
});
_SettingsStore.default.setValue("baseFontSize", null, _SettingLevel.SettingLevel.DEVICE, size - _FontWatcher.FontWatcher.SIZE_DIFF);
});
(0, _defineProperty2.default)(this, "onValidateFontSize", async ({
value
}
/*: Pick<IFieldState, "value">*/
) =>
/*: Promise<IValidationResult>*/
{
const parsedSize = parseFloat(value);
const min = _FontWatcher.FontWatcher.MIN_SIZE + _FontWatcher.FontWatcher.SIZE_DIFF;
const max = _FontWatcher.FontWatcher.MAX_SIZE + _FontWatcher.FontWatcher.SIZE_DIFF;
if (isNaN(parsedSize)) {
return {
valid: false,
feedback: (0, _languageHandler._t)("Size must be a number")
};
}
if (!(min <= parsedSize && parsedSize <= max)) {
return {
valid: false,
feedback: (0, _languageHandler._t)('Custom font size can only be between %(min)s pt and %(max)s pt', {
min,
max
})
};
}
_SettingsStore.default.setValue("baseFontSize", null, _SettingLevel.SettingLevel.DEVICE, parseInt(value, 10) - _FontWatcher.FontWatcher.SIZE_DIFF);
return {
valid: true,
feedback: (0, _languageHandler._t)('Use between %(min)s pt and %(max)s pt', {
min,
max
})
};
});
(0, _defineProperty2.default)(this, "onAddCustomTheme", async () =>
/*: Promise<void>*/
{
let currentThemes
/*: string[]*/
= _SettingsStore.default.getValue("custom_themes");
if (!currentThemes) currentThemes = [];
currentThemes = currentThemes.map(c => c); // cheap clone
if (this.themeTimer) {
clearTimeout(this.themeTimer);
}
try {
const r = await fetch(this.state.customThemeUrl); // XXX: need some schema for this
const themeInfo = await r.json();
if (!themeInfo || typeof themeInfo['name'] !== 'string' || typeof themeInfo['colors'] !== 'object') {
this.setState({
customThemeMessage: {
text: (0, _languageHandler._t)("Invalid theme schema."),
isError: true
}
});
return;
}
currentThemes.push(themeInfo);
} catch (e) {
console.error(e);
this.setState({
customThemeMessage: {
text: (0, _languageHandler._t)("Error downloading theme information."),
isError: true
}
});
return; // Don't continue on error
}
await _SettingsStore.default.setValue("custom_themes", null, _SettingLevel.SettingLevel.ACCOUNT, currentThemes);
this.setState({
customThemeUrl: "",
customThemeMessage: {
text: (0, _languageHandler._t)("Theme added!"),
isError: false
}
});
this.themeTimer = setTimeout(() => {
this.setState({
customThemeMessage: {
text: "",
isError: false
}
});
}, 3000);
});
(0, _defineProperty2.default)(this, "onCustomThemeChange", (e
/*: React.ChangeEvent<HTMLSelectElement | HTMLInputElement>*/
) =>
/*: void*/
{
this.setState({
customThemeUrl: e.target.value
});
});
(0, _defineProperty2.default)(this, "onIRCLayoutChange", (enabled
/*: boolean*/
) => {
if (enabled) {
this.setState({
layout: _Layout.Layout.IRC
});
_SettingsStore.default.setValue("layout", null, _SettingLevel.SettingLevel.DEVICE, _Layout.Layout.IRC);
} else {
this.setState({
layout: _Layout.Layout.Group
});
_SettingsStore.default.setValue("layout", null, _SettingLevel.SettingLevel.DEVICE, _Layout.Layout.Group);
}
});
this.state = _objectSpread(_objectSpread({
fontSize: (_SettingsStore.default.getValue("baseFontSize", null) + _FontWatcher.FontWatcher.SIZE_DIFF).toString()
}, this.calculateThemeState()), {}, {
customThemeUrl: "",
customThemeMessage: {
isError: false,
text: ""
},
useCustomFontSize: _SettingsStore.default.getValue("useCustomFontSize"),
useSystemFont: _SettingsStore.default.getValue("useSystemFont"),
systemFont: _SettingsStore.default.getValue("systemFont"),
showAdvanced: false,
layout: _SettingsStore.default.getValue("layout"),
userId: "@erim:fink.fink",
displayName: "Erimayas Fink",
avatarUrl: null
});
}
async componentDidMount() {
// Fetch the current user profile for the message preview
const client = _MatrixClientPeg.MatrixClientPeg.get();
const userId = client.getUserId();
const profileInfo = await client.getProfileInfo(userId);
this.setState({
userId,
displayName: profileInfo.displayname,
avatarUrl: profileInfo.avatar_url
});
}
calculateThemeState()
/*: IThemeState*/
{
// We have to mirror the logic from ThemeWatcher.getEffectiveTheme so we
// show the right values for things.
const themeChoice
/*: string*/
= _SettingsStore.default.getValue("theme");
const systemThemeExplicit
/*: boolean*/
= _SettingsStore.default.getValueAt(_SettingLevel.SettingLevel.DEVICE, "use_system_theme", null, false, true);
const themeExplicit
/*: string*/
= _SettingsStore.default.getValueAt(_SettingLevel.SettingLevel.DEVICE, "theme", null, false, true); // If the user has enabled system theme matching, use that.
if (systemThemeExplicit) {
return {
theme: themeChoice,
useSystemTheme: true
};
} // If the user has set a theme explicitly, use that (no system theme matching)
if (themeExplicit) {
return {
theme: themeChoice,
useSystemTheme: false
};
} // Otherwise assume the defaults for the settings
return {
theme: themeChoice,
useSystemTheme: _SettingsStore.default.getValueAt(_SettingLevel.SettingLevel.DEVICE, "use_system_theme")
};
}
renderThemeSection() {
const themeWatcher = new _ThemeWatcher.default();
let systemThemeSection
/*: JSX.Element*/
;
if (themeWatcher.isSystemThemeSupported()) {
systemThemeSection = /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement(_StyledCheckbox.default, {
checked: this.state.useSystemTheme,
onChange: e => this.onUseSystemThemeChanged(e.target.checked)
}, _SettingsStore.default.getDisplayName("use_system_theme")));
}
let customThemeForm
/*: JSX.Element*/
;
if (_SettingsStore.default.getValue("feature_custom_themes")) {
let messageElement = null;
if (this.state.customThemeMessage.text) {
if (this.state.customThemeMessage.isError) {
messageElement = /*#__PURE__*/_react.default.createElement("div", {
className: "text-error"
}, this.state.customThemeMessage.text);
} else {
messageElement = /*#__PURE__*/_react.default.createElement("div", {
className: "text-success"
}, this.state.customThemeMessage.text);
}
}
customThemeForm = /*#__PURE__*/_react.default.createElement("div", {
className: "mx_SettingsTab_section"
}, /*#__PURE__*/_react.default.createElement("form", {
onSubmit: this.onAddCustomTheme
}, /*#__PURE__*/_react.default.createElement(_Field.default, {
label: (0, _languageHandler._t)("Custom theme URL"),
type: "text",
id: "mx_GeneralUserSettingsTab_customThemeInput",
autoComplete: "off",
onChange: this.onCustomThemeChange,
value: this.state.customThemeUrl
}), /*#__PURE__*/_react.default.createElement(_AccessibleButton.default, {
onClick: this.onAddCustomTheme,
type: "submit",
kind: "primary_sm",
disabled: !this.state.customThemeUrl.trim()
}, (0, _languageHandler._t)("Add theme")), messageElement));
} // XXX: replace any type here
const themes = Object.entries((0, _theme.enumerateThemes)()).map(p => ({
id: p[0],
name: p[1]
})); // convert pairs to objects for code readability
const builtInThemes = themes.filter(p => !p.id.startsWith("custom-"));
const customThemes = themes.filter(p => !builtInThemes.includes(p)).sort((a, b) => a.name.localeCompare(b.name));
const orderedThemes = [...builtInThemes, ...customThemes];
return /*#__PURE__*/_react.default.createElement("div", {
className: "mx_SettingsTab_section mx_AppearanceUserSettingsTab_themeSection"
}, /*#__PURE__*/_react.default.createElement("span", {
className: "mx_SettingsTab_subheading"
}, (0, _languageHandler._t)("Theme")), systemThemeSection, /*#__PURE__*/_react.default.createElement("div", {
className: "mx_ThemeSelectors"
}, /*#__PURE__*/_react.default.createElement(_StyledRadioGroup.default, {
name: "theme",
definitions: orderedThemes.map(t => ({
value: t.id,
label: t.name,
disabled: this.state.useSystemTheme,
className: "mx_ThemeSelector_" + t.id
})),
onChange: this.onThemeChange,
value: this.state.useSystemTheme ? undefined : this.state.theme,
outlined: true
})), customThemeForm);
}
renderFontSection() {
return /*#__PURE__*/_react.default.createElement("div", {
className: "mx_SettingsTab_section mx_AppearanceUserSettingsTab_fontScaling"
}, /*#__PURE__*/_react.default.createElement("span", {
className: "mx_SettingsTab_subheading"
}, (0, _languageHandler._t)("Font size")), /*#__PURE__*/_react.default.createElement(_EventTilePreview.default, {
className: "mx_AppearanceUserSettingsTab_fontSlider_preview",
message: this.MESSAGE_PREVIEW_TEXT,
layout: this.state.layout,
userId: this.state.userId,
displayName: this.state.displayName,
avatarUrl: this.state.avatarUrl
}), /*#__PURE__*/_react.default.createElement("div", {
className: "mx_AppearanceUserSettingsTab_fontSlider"
}, /*#__PURE__*/_react.default.createElement("div", {
className: "mx_AppearanceUserSettingsTab_fontSlider_smallText"
}, "Aa"), /*#__PURE__*/_react.default.createElement(_Slider.default, {
values: [13, 14, 15, 16, 18],
value: parseInt(this.state.fontSize, 10),
onSelectionChange: this.onFontSizeChanged,
displayFunc: _ => "",
disabled: this.state.useCustomFontSize
}), /*#__PURE__*/_react.default.createElement("div", {
className: "mx_AppearanceUserSettingsTab_fontSlider_largeText"
}, "Aa")), /*#__PURE__*/_react.default.createElement(_SettingsFlag.default, {
name: "useCustomFontSize",
level: _SettingLevel.SettingLevel.ACCOUNT,
onChange: checked => this.setState({
useCustomFontSize: checked
}),
useCheckbox: true
}), /*#__PURE__*/_react.default.createElement(_Field.default, {
type: "number",
label: (0, _languageHandler._t)("Font size"),
autoComplete: "off",
placeholder: this.state.fontSize.toString(),
value: this.state.fontSize.toString(),
id: "font_size_field",
onValidate: this.onValidateFontSize,
onChange: value => this.setState({
fontSize: value.target.value
}),
disabled: !this.state.useCustomFontSize,
className: "mx_SettingsTab_customFontSizeField"
}));
}
renderAdvancedSection() {
if (!_SettingsStore.default.getValue(_UIFeature.UIFeature.AdvancedSettings)) return null;
const brand = _SdkConfig.default.get().brand;
const toggle = /*#__PURE__*/_react.default.createElement("div", {
className: "mx_AppearanceUserSettingsTab_AdvancedToggle",
onClick: () => this.setState({
showAdvanced: !this.state.showAdvanced
})
}, this.state.showAdvanced ? (0, _languageHandler._t)("Hide advanced") : (0, _languageHandler._t)("Show advanced"));
let advanced
/*: React.ReactNode*/
;
if (this.state.showAdvanced) {
const tooltipContent = (0, _languageHandler._t)("Set the name of a font installed on your system & %(brand)s will attempt to use it.", {
brand
});
advanced = /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_SettingsFlag.default, {
name: "useCompactLayout",
level: _SettingLevel.SettingLevel.DEVICE,
useCheckbox: true,
disabled: this.state.layout == _Layout.Layout.IRC
}), /*#__PURE__*/_react.default.createElement(_StyledCheckbox.default, {
checked: this.state.layout == _Layout.Layout.IRC,
onChange: ev => this.onIRCLayoutChange(ev.target.checked)
}, (0, _languageHandler._t)("Enable experimental, compact IRC style layout")), /*#__PURE__*/_react.default.createElement(_SettingsFlag.default, {
name: "useSystemFont",
level: _SettingLevel.SettingLevel.DEVICE,
useCheckbox: true,
onChange: checked => this.setState({
useSystemFont: checked
})
}), /*#__PURE__*/_react.default.createElement(_Field.default, {
className: "mx_AppearanceUserSettingsTab_systemFont",
label: _SettingsStore.default.getDisplayName("systemFont"),
onChange: value => {
this.setState({
systemFont: value.target.value
});
_SettingsStore.default.setValue("systemFont", null, _SettingLevel.SettingLevel.DEVICE, value.target.value);
},
tooltipContent: tooltipContent,
forceTooltipVisible: true,
disabled: !this.state.useSystemFont,
value: this.state.systemFont
}));
}
return /*#__PURE__*/_react.default.createElement("div", {
className: "mx_SettingsTab_section mx_AppearanceUserSettingsTab_Advanced"
}, toggle, advanced);
}
render() {
const brand = _SdkConfig.default.get().brand;
return /*#__PURE__*/_react.default.createElement("div", {
className: "mx_SettingsTab mx_AppearanceUserSettingsTab"
}, /*#__PURE__*/_react.default.createElement("div", {
className: "mx_SettingsTab_heading"
}, (0, _languageHandler._t)("Customise your appearance")), /*#__PURE__*/_react.default.createElement("div", {
className: "mx_SettingsTab_SubHeading"
}, (0, _languageHandler._t)("Appearance Settings only affect this %(brand)s session.", {
brand
})), this.renderThemeSection(), this.renderFontSection(), this.renderAdvancedSection());
}
}, _temp)) || _class);
exports.default = AppearanceUserSettingsTab;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9jb21wb25lbnRzL3ZpZXdzL3NldHRpbmdzL3RhYnMvdXNlci9BcHBlYXJhbmNlVXNlclNldHRpbmdzVGFiLnRzeCJdLCJuYW1lcyI6WyJBcHBlYXJhbmNlVXNlclNldHRpbmdzVGFiIiwiUmVhY3QiLCJDb21wb25lbnQiLCJjb25zdHJ1Y3RvciIsInByb3BzIiwibmV3VGhlbWUiLCJzdGF0ZSIsInRoZW1lIiwib2xkVGhlbWUiLCJTZXR0aW5nc1N0b3JlIiwiZ2V0VmFsdWUiLCJzZXRWYWx1ZSIsIlNldHRpbmdMZXZlbCIsIkRFVklDRSIsImNhdGNoIiwiZGlzIiwiZGlzcGF0Y2giLCJhY3Rpb24iLCJBY3Rpb24iLCJSZWNoZWNrVGhlbWUiLCJzZXRTdGF0ZSIsImZvcmNlVGhlbWUiLCJjaGVja2VkIiwidXNlU3lzdGVtVGhlbWUiLCJzaXplIiwiZm9udFNpemUiLCJ0b1N0cmluZyIsIkZvbnRXYXRjaGVyIiwiU0laRV9ESUZGIiwidmFsdWUiLCJwYXJzZWRTaXplIiwicGFyc2VGbG9hdCIsIm1pbiIsIk1JTl9TSVpFIiwibWF4IiwiTUFYX1NJWkUiLCJpc05hTiIsInZhbGlkIiwiZmVlZGJhY2siLCJwYXJzZUludCIsImN1cnJlbnRUaGVtZXMiLCJtYXAiLCJjIiwidGhlbWVUaW1lciIsImNsZWFyVGltZW91dCIsInIiLCJmZXRjaCIsImN1c3RvbVRoZW1lVXJsIiwidGhlbWVJbmZvIiwianNvbiIsImN1c3RvbVRoZW1lTWVzc2FnZSIsInRleHQiLCJpc0Vycm9yIiwicHVzaCIsImUiLCJjb25zb2xlIiwiZXJyb3IiLCJBQ0NPVU5UIiwic2V0VGltZW91dCIsInRhcmdldCIsImVuYWJsZWQiLCJsYXlvdXQiLCJMYXlvdXQiLCJJUkMiLCJHcm91cCIsImNhbGN1bGF0ZVRoZW1lU3RhdGUiLCJ1c2VDdXN0b21Gb250U2l6ZSIsInVzZVN5c3RlbUZvbnQiLCJzeXN0ZW1Gb250Iiwic2hvd0FkdmFuY2VkIiwidXNlcklkIiwiZGlzcGxheU5hbWUiLCJhdmF0YXJVcmwiLCJjb21wb25lbnREaWRNb3VudCIsImNsaWVudCIsIk1hdHJpeENsaWVudFBlZyIsImdldCIsImdldFVzZXJJZCIsInByb2ZpbGVJbmZvIiwiZ2V0UHJvZmlsZUluZm8iLCJkaXNwbGF5bmFtZSIsImF2YXRhcl91cmwiLCJ0aGVtZUNob2ljZSIsInN5c3RlbVRoZW1lRXhwbGljaXQiLCJnZXRWYWx1ZUF0IiwidGhlbWVFeHBsaWNpdCIsInJlbmRlclRoZW1lU2VjdGlvbiIsInRoZW1lV2F0Y2hlciIsIlRoZW1lV2F0Y2hlciIsInN5c3RlbVRoZW1lU2VjdGlvbiIsImlzU3lzdGVtVGhlbWVTdXBwb3J0ZWQiLCJvblVzZVN5c3RlbVRoZW1lQ2hhbmdlZCIsImdldERpc3BsYXlOYW1lIiwiY3VzdG9tVGhlbWVGb3JtIiwibWVzc2FnZUVsZW1lbnQiLCJvbkFkZEN1c3RvbVRoZW1lIiwib25DdXN0b21UaGVtZUNoYW5nZSIsInRyaW0iLCJ0aGVtZXMiLCJPYmplY3QiLCJlbnRyaWVzIiwicCIsImlkIiwibmFtZSIsImJ1aWx0SW5UaGVtZXMiLCJmaWx0ZXIiLCJzdGFydHNXaXRoIiwiY3VzdG9tVGhlbWVzIiwiaW5jbHVkZXMiLCJzb3J0IiwiYSIsImIiLCJsb2NhbGVDb21wYXJlIiwib3JkZXJlZFRoZW1lcyIsInQiLCJsYWJlbCIsImRpc2FibGVkIiwiY2xhc3NOYW1lIiwib25UaGVtZUNoYW5nZSIsInVuZGVmaW5lZCIsInJlbmRlckZvbnRTZWN0aW9uIiwiTUVTU0FHRV9QUkVWSUVXX1RFWFQiLCJvbkZvbnRTaXplQ2hhbmdlZCIsIl8iLCJvblZhbGlkYXRlRm9udFNpemUiLCJyZW5kZXJBZHZhbmNlZFNlY3Rpb24iLCJVSUZlYXR1cmUiLCJBZHZhbmNlZFNldHRpbmdzIiwiYnJhbmQiLCJTZGtDb25maWciLCJ0b2dnbGUiLCJhZHZhbmNlZCIsInRvb2x0aXBDb250ZW50IiwiZXYiLCJvbklSQ0xheW91dENoYW5nZSIsInJlbmRlciJdLCJtYXBwaW5n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Ii8qXG5Db3B5cmlnaHQgMjAxOSBOZXcgVmVjdG9yIEx0ZFxuQ29weXJpZ2h0IDIwMTksIDIwMjAgVGhlIE1hdHJpeC5vcmcgRm91bmRhdGlvbiBDLkkuQy5cblxuTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKTtcbnlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS5cbllvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdFxuXG4gICAgaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXG5cblVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmVcbmRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuIFwiQVMgSVNcIiBCQVNJUyxcbldJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLlxuU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZFxubGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXG4qL1xuXG5pbXBvcnQgUmVhY3QgZnJvbSAncmVhY3QnO1xuaW1wb3J0IHtfdH0gZnJvbSBcIi4uLy4uLy4uLy4uLy4uL2xhbmd1YWdlSGFuZGxlclwiO1xuaW1wb3J0IFNka0NvbmZpZyBmcm9tIFwiLi4vLi4vLi4vLi4vLi4vU2RrQ29uZmlnXCI7XG5pbXBvcnQgeyBNYXRyaXhDbGllbnRQZWcgfSBmcm9tICcuLi8uLi8uLi8uLi8uLi9NYXRyaXhDbGllbnRQZWcnO1xuaW1wb3J0IFNldHRpbmdzU3RvcmUgZnJvbSBcIi4uLy4uLy4uLy4uLy4uL3NldHRpbmdzL1NldHRpbmdzU3RvcmVcIjtcbmltcG9ydCB7IGVudW1lcmF0ZVRoZW1lcyB9IGZyb20gXCIuLi8uLi8uLi8uLi8uLi90aGVtZVwiO1xuaW1wb3J0IFRoZW1lV2F0Y2hlciBmcm9tIFwiLi4vLi4vLi4vLi4vLi4vc2V0dGluZ3Mvd2F0Y2hlcnMvVGhlbWVXYXRjaGVyXCI7XG5pbXBvcnQgU2xpZGVyIGZyb20gXCIuLi8uLi8uLi9lbGVtZW50cy9TbGlkZXJcIjtcbmltcG9ydCBBY2Nlc3NpYmxlQnV0dG9uIGZyb20gXCIuLi8uLi8uLi9lbGVtZW50cy9BY2Nlc3NpYmxlQnV0dG9uXCI7XG5pbXBvcnQgZGlzIGZyb20gXCIuLi8uLi8uLi8uLi8uLi9kaXNwYXRjaGVyL2Rpc3BhdGNoZXJcIjtcbmltcG9ydCB7IEZvbnRXYXRjaGVyIH0gZnJvbSBcIi4uLy4uLy4uLy4uLy4uL3NldHRpbmdzL3dhdGNoZXJzL0ZvbnRXYXRjaGVyXCI7XG5pbXBvcnQgeyBSZWNoZWNrVGhlbWVQYXlsb2FkIH0gZnJvbSAnLi4vLi4vLi4vLi4vLi4vZGlzcGF0Y2hlci9wYXlsb2Fkcy9SZWNoZWNrVGhlbWVQYXlsb2FkJztcbmltcG9ydCB7IEFjdGlvbiB9IGZyb20gJy4uLy4uLy4uLy4uLy4uL2Rpc3BhdGNoZXIvYWN0aW9ucyc7XG5pbXBvcnQgeyBJVmFsaWRhdGlvblJlc3VsdCwgSUZpZWxkU3RhdGUgfSBmcm9tICcuLi8uLi8uLi9lbGVtZW50cy9WYWxpZGF0aW9uJztcbmltcG9ydCBTdHlsZWRDaGVja2JveCBmcm9tICcuLi8uLi8uLi9lbGVtZW50cy9TdHlsZWRDaGVja2JveCc7XG5pbXBvcnQgU2V0dGluZ3NGbGFnIGZyb20gJy4uLy4uLy4uL2VsZW1lbnRzL1NldHRpbmdzRmxhZyc7XG5pbXBvcnQgRmllbGQgZnJvbSAnLi4vLi4vLi4vZWxlbWVudHMvRmllbGQnO1xuaW1wb3J0IEV2ZW50VGlsZVByZXZpZXcgZnJvbSAnLi4vLi4vLi4vZWxlbWVudHMvRXZlbnRUaWxlUHJldmlldyc7XG5pbXBvcnQgU3R5bGVkUmFkaW9Hcm91cCBmcm9tIFwiLi4vLi4vLi4vZWxlbWVudHMvU3R5bGVkUmFkaW9Hcm91cFwiO1xuaW1wb3J0IHsgU2V0dGluZ0xldmVsIH0gZnJvbSBcIi4uLy4uLy4uLy4uLy4uL3NldHRpbmdzL1NldHRpbmdMZXZlbFwiO1xuaW1wb3J0IHtVSUZlYXR1cmV9IGZyb20gXCIuLi8uLi8uLi8uLi8uLi9zZXR0aW5ncy9VSUZlYXR1cmVcIjtcbmltcG9ydCB7TGF5b3V0fSBmcm9tIFwiLi4vLi4vLi4vLi4vLi4vc2V0dGluZ3MvTGF5b3V0XCI7XG5pbXBvcnQge3JlcGxhY2VhYmxlQ29tcG9uZW50fSBmcm9tIFwiLi4vLi4vLi4vLi4vLi4vdXRpbHMvcmVwbGFjZWFibGVDb21wb25lbnRcIjtcblxuaW50ZXJmYWNlIElQcm9wcyB7XG59XG5cbmludGVyZmFjZSBJVGhlbWVTdGF0ZSB7XG4gICAgdGhlbWU6IHN0cmluZztcbiAgICB1c2VTeXN0ZW1UaGVtZTogYm9vbGVhbjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBDdXN0b21UaGVtZU1lc3NhZ2Uge1xuICAgIGlzRXJyb3I6IGJvb2xlYW47XG4gICAgdGV4dDogc3RyaW5nO1xufVxuXG5pbnRlcmZhY2UgSVN0YXRlIGV4dGVuZHMgSVRoZW1lU3RhdGUge1xuICAgIC8vIFN0cmluZyBkaXNwbGF5aW5nIHRoZSBjdXJyZW50IHNlbGVjdGVkIGZvbnRTaXplLlxuICAgIC8vIE5lZWRzIHRvIGJlIHN0cmluZyBmb3IgdGhpbmdzIGxpa2UgJzE3Licgd2l0aG91dFxuICAgIC8vIHRyYWlsaW5nIDBzLlxuICAgIGZvbnRTaXplOiBzdHJpbmc7XG4gICAgY3VzdG9tVGhlbWVVcmw6IHN0cmluZztcbiAgICBjdXN0b21UaGVtZU1lc3NhZ2U6IEN1c3RvbVRoZW1lTWVzc2FnZTtcbiAgICB1c2VDdXN0b21Gb250U2l6ZTogYm9vbGVhbjtcbiAgICB1c2VTeXN0ZW1Gb250OiBib29sZWFuO1xuICAgIHN5c3RlbUZvbnQ6IHN0cmluZztcbiAgICBzaG93QWR2YW5jZWQ6IGJvb2xlYW47XG4gICAgbGF5b3V0OiBMYXlvdXQ7XG4gICAgLy8gVXNlciBwcm9maWxlIGRhdGEgZm9yIHRoZSBtZXNzYWdlIHByZXZpZXdcbiAgICB1c2VySWQ6IHN0cmluZztcbiAgICBkaXNwbGF5TmFtZTogc3RyaW5nO1xuICAgIGF2YXRhclVybDogc3RyaW5nO1xufVxuXG5AcmVwbGFjZWFibGVDb21wb25lbnQoXCJ2aWV3cy5zZXR0aW5ncy50YWJzLnVzZXIuQXBwZWFyYW5jZVVzZXJTZXR0aW5nc1RhYlwiKVxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgQXBwZWFyYW5jZVVzZXJTZXR0aW5nc1RhYiBleHRlbmRzIFJlYWN0LkNvbXBvbmVudDxJUHJvcHMsIElTdGF0ZT4ge1xuICAgIHByaXZhdGUgcmVhZG9ubHkgTUVTU0FHRV9QUkVWSUVXX1RFWFQgPSBfdChcIkhleSB5b3UuIFlvdSdyZSB0aGUgYmVzdCFcIik7XG5cbiAgICBwcml2YXRlIHRoZW1lVGltZXI6IE5vZGVKUy5UaW1lb3V0O1xuXG4gICAgY29uc3RydWN0b3IocHJvcHM6IElQcm9wcykge1xuICAgICAgICBzdXBlcihwcm9wcyk7XG5cbiAgICAgICAgdGhpcy5zdGF0ZSA9IHtcbiAgICAgICAgICAgIGZvbnRTaXplOiAoU2V0dGluZ3NTdG9yZS5nZXRWYWx1ZShcImJhc2VGb250U2l6ZVwiLCBudWxsKSArIEZvbnRXYXRjaGVyLlNJWkVfRElGRikudG9TdHJpbmcoKSxcbiAgICAgICAgICAgIC4uLnRoaXMuY2FsY3VsYXRlVGhlbWVTdGF0ZSgpLFxuICAgICAgICAgICAgY3VzdG9tVGhlbWVVcmw6IFwiXCIsXG4gICAgICAgICAgICBjdXN0b21UaGVtZU1lc3NhZ2U6IHtpc0Vycm9yOiBmYWxzZSwgdGV4dDogXCJcIn0sXG4gICAgICAgICAgICB1c2VDdXN0b21Gb250U2l6ZTogU2V0dGluZ3NTdG9yZS5nZXRWYWx1ZShcInVzZUN1c3RvbUZvbnRTaXplXCIpLFxuICAgICAgICAgICAgdXNlU3lzdGVtRm9udDogU2V0dGluZ3NTdG9yZS5nZXRWYWx1ZShcInVzZVN5c3RlbUZvbnRcIiksXG4gICAgICAgICAgICBzeXN0ZW1Gb250OiBTZXR0aW5nc1N0b3JlLmdldFZhbHVlKFwic3lzdGVtRm9udFwiKSxcbiAgICAgICAgICAgIHNob3dBZHZhbmNlZDogZmFsc2UsXG4gICAgICAgICAgICBsYXlvdXQ6IFNldHRpbmdzU3RvcmUuZ2V0VmFsdWUoXCJsYXlvdXRcIiksXG4gICAgICAgICAgICB1c2VySWQ6IFwiQGVyaW06Zmluay5maW5rXCIsXG4gICAgICAgICAgICBkaXNwbGF5TmFtZTogXCJFcmltYXlhcyBGaW5rXCIsXG4gICAgICAgICAgICBhdmF0YXJVcmw6IG51bGwsXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgYXN5bmMgY29tcG9uZW50RGlkTW91bnQoKSB7XG4gICAgICAgIC8vIEZldGNoIHRoZSBjdXJyZW50IHVzZXIgcHJvZmlsZSBmb3IgdGhlIG1lc3NhZ2UgcHJldmlld1xuICAgICAgICBjb25zdCBjbGllbnQgPSBNYXRyaXhDbGllbnRQZWcuZ2V0KCk7XG4gICAgICAgIGNvbnN0IHVzZXJJZCA9IGNsaWVudC5nZXRVc2VySWQoKTtcbiAgICAgICAgY29uc3QgcHJvZmlsZUluZm8gPSBhd2FpdCBjbGllbnQuZ2V0UHJvZmlsZUluZm8odXNlcklkKTtcblxuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICAgIHVzZXJJZCxcbiAgICAgICAgICAgIGRpc3BsYXlOYW1lOiBwcm9maWxlSW5mby5kaXNwbGF5bmFtZSxcbiAgICAgICAgICAgIGF2YXRhclVybDogcHJvZmlsZUluZm8uYXZhdGFyX3VybCxcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBjYWxjdWxhdGVUaGVtZVN0YXRlKCk6IElUaGVtZVN0YXRlIHtcbiAgICAgICAgLy8gV2UgaGF2ZSB0byBtaXJyb3IgdGhlIGxvZ2ljIGZyb20gVGhlbWVXYXRjaGVyLmdldEVmZmVjdGl2ZVRoZW1lIHNvIHdlXG4gICAgICAgIC8vIHNob3cgdGhlIHJpZ2h0IHZhbHVlcyBmb3IgdGhpbmdzLlxuXG4gICAgICAgIGNvbnN0IHRoZW1lQ2hvaWNlOiBzdHJpbmcgPSBTZXR0aW5nc1N0b3JlLmdldFZhbHVlKFwidGhlbWVcIik7XG4gICAgICAgIGNvbnN0IHN5c3RlbVRoZW1lRXhwbGljaXQ6IGJvb2xlYW4gPSBTZXR0aW5nc1N0b3JlLmdldFZhbHVlQXQoXG4gICAgICAgICAgICBTZXR0aW5nTGV2ZWwuREVWSUNFLCBcInVzZV9zeXN0ZW1fdGhlbWVcIiwgbnVsbCwgZmFsc2UsIHRydWUpO1xuICAgICAgICBjb25zdCB0aGVtZUV4cGxpY2l0OiBzdHJpbmcgPSBTZXR0aW5nc1N0b3JlLmdldFZhbHVlQXQoXG4gICAgICAgICAgICBTZXR0aW5nTGV2ZWwuREVWSUNFLCBcInRoZW1lXCIsIG51bGwsIGZhbHNlLCB0cnVlKTtcblxuICAgICAgICAvLyBJZiB0aGUgdXNlciBoYXMgZW5hYmxlZCBzeXN0ZW0gdGhlbWUgbWF0Y2hpbmcsIHVzZSB0aGF0LlxuICAgICAgICBpZiAoc3lzdGVtVGhlbWVFeHBsaWNpdCkge1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICB0aGVtZTogdGhlbWVDaG9pY2UsXG4gICAgICAgICAgICAgICAgdXNlU3lzdGVtVGhlbWU6IHRydWUsXG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gSWYgdGhlIHVzZXIgaGFzIHNldCBhIHRoZW1lIGV4cGxpY2l0bHksIHVzZSB0aGF0IChubyBzeXN0ZW0gdGhlbWUgbWF0Y2hpbmcpXG4gICAgICAgIGlmICh0aGVtZUV4cGxpY2l0KSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIHRoZW1lOiB0aGVtZUNob2ljZSxcbiAgICAgICAgICAgICAgICB1c2VTeXN0ZW1UaGVtZTogZmFsc2UsXG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gT3RoZXJ3aXNlIGFzc3VtZSB0aGUgZGVmYXVsdHMgZm9yIHRoZSBzZXR0aW5nc1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgdGhlbWU6IHRoZW1lQ2hvaWNlLFxuICAgICAgICAgICAgdXNlU3lzdGVtVGhlbWU6IFNldHRpbmdzU3RvcmUuZ2V0VmFsdWVBdChTZXR0aW5nTGV2ZWwuREVWSUNFLCBcInVzZV9zeXN0ZW1fdGhlbWVcIiksXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBvblRoZW1lQ2hhbmdlID0gKG5ld1RoZW1lOiBzdHJpbmcpOiB2b2lkID0+IHtcbiAgICAgICAgaWYgKHRoaXMuc3RhdGUudGhlbWUgPT09IG5ld1RoZW1lKSByZXR1cm47XG5cbiAgICAgICAgLy8gZG9pbmcgZ2V0VmFsdWUgaW4gdGhlIC5jYXRjaCB3aWxsIHN0aWxsIHJldHVybiB0aGUgdmFsdWUgd2UgZmFpbGVkIHRvIHNldCxcbiAgICAgICAgLy8gc28gcmVtZW1iZXIgd2hhdCB0aGUgdmFsdWUgd2FzIGJlZm9yZSB3ZSB0cmllZCB0byBzZXQgaXQgc28gd2UgY2FuIHJldmVydFxuICAgICAgICBjb25zdCBvbGRUaGVtZTogc3RyaW5nID0gU2V0dGluZ3NTdG9yZS5nZXRWYWx1ZSgndGhlbWUnKTtcbiAgICAgICAgU2V0dGluZ3NTdG9yZS5zZXRWYWx1ZShcInRoZW1lXCIsIG51bGwsIFNldHRpbmdMZXZlbC5ERVZJQ0UsIG5ld1RoZW1lKS5jYXRjaCgoKSA9PiB7XG4gICAgICAgICAgICBkaXMuZGlzcGF0Y2g8UmVjaGVja1RoZW1lUGF5bG9hZD4oe2FjdGlvbjogQWN0aW9uLlJlY2hlY2tUaGVtZX0pO1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7dGhlbWU6IG9sZFRoZW1lfSk7XG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLnNldFN0YXRlKHt0aGVtZTogbmV3VGhlbWV9KTtcbiAgICAgICAgLy8gVGhlIHNldHRpbmdzIHdhdGNoZXIgZG9lc24ndCBmaXJlIHVudGlsIHRoZSBlY2hvIGNvbWVzIGJhY2sgZnJvbSB0aGVcbiAgICAgICAgLy8gc2VydmVyLCBzbyB0byBtYWtlIHRoZSB0aGVtZSBjaGFuZ2UgaW1tZWRpYXRlbHkgd2UgbmVlZCB0byBtYW51YWxseVxuICAgICAgICAvLyBkbyB0aGUgZGlzcGF0Y2ggbm93XG4gICAgICAgIC8vIFhYWDogVGhlIGxvY2FsIGVjaG9lZCB2YWx1ZSBhcHBlYXJzIHRvIGJlIHVucmVsaWFibGUsIGluIHBhcnRpY3VsYXJcbiAgICAgICAgLy8gd2hlbiBzZXR0aW5ncyBjdXN0b20gdGhlbWVzKCEpIHNvIGFkZGluZyBmb3JjZVRoZW1lIHRvIG92ZXJyaWRlXG4gICAgICAgIC8vIHRoZSB2YWx1ZSBmcm9tIHNldHRpbmdzLlxuICAgICAgICBkaXMuZGlzcGF0Y2g8UmVjaGVja1RoZW1lUGF5bG9hZD4oe2FjdGlvbjogQWN0aW9uLlJlY2hlY2tUaGVtZSwgZm9yY2VUaGVtZTogbmV3VGhlbWV9KTtcbiAgICB9O1xuXG4gICAgcHJpdmF0ZSBvblVzZVN5c3RlbVRoZW1lQ2hhbmdlZCA9IChjaGVja2VkOiBib29sZWFuKTogdm9pZCA9PiB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe3VzZVN5c3RlbVRoZW1lOiBjaGVja2VkfSk7XG4gICAgICAgIFNldHRpbmdzU3RvcmUuc2V0VmFsdWUoXCJ1c2Vfc3lzdGVtX3RoZW1lXCIsIG51bGwsIFNldHRpbmdMZXZlbC5ERVZJQ0UsIGNoZWNrZWQpO1xuICAgICAgICBkaXMuZGlzcGF0Y2g8UmVjaGVja1RoZW1lUGF5bG9hZD4oe2FjdGlvbjogQWN0aW9uLlJlY2hlY2tUaGVtZX0pO1xuICAgIH07XG5cbiAgICBwcml2YXRlIG9uRm9udFNpemVDaGFuZ2VkID0gKHNpemU6IG51bWJlcik6IHZvaWQgPT4ge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtmb250U2l6ZTogc2l6ZS50b1N0cmluZygpfSk7XG4gICAgICAgIFNldHRpbmdzU3RvcmUuc2V0VmFsdWUoXCJiYXNlRm9udFNpemVcIiwgbnVsbCwgU2V0dGluZ0xldmVsLkRFVklDRSwgc2l6ZSAtIEZvbnRXYXRjaGVyLlNJWkVfRElGRik7XG4gICAgfTtcblxuICAgIHByaXZhdGUgb25WYWxpZGF0ZUZvbnRTaXplID0gYXN5bmMgKHt2YWx1ZX06IFBpY2s8SUZpZWxkU3RhdGUsIFwidmFsdWVcIj4pOiBQcm9taXNlPElWYWxpZGF0aW9uUmVzdWx0PiA9PiB7XG4gICAgICAgIGNvbnN0IHBhcnNlZFNpemUgPSBwYXJzZUZsb2F0KHZhbHVlKTtcbiAgICAgICAgY29uc3QgbWluID0gRm9udFdhdGNoZXIuTUlOX1NJWkUgKyBGb250V2F0Y2hlci5TSVpFX0RJRkY7XG4gICAgICAgIGNvbnN0IG1heCA9IEZvbnRXYXRjaGVyLk1BWF9TSVpFICsgRm9udFdhdGNoZXIuU0laRV9ESUZGO1xuXG4gICAgICAgIGlmIChpc05hTihwYXJzZWRTaXplKSkge1xuICAgICAgICAgICAgcmV0dXJuIHt2YWxpZDogZmFsc2UsIGZlZWRiYWNrOiBfdChcIlNpemUgbXVzdCBiZSBhIG51bWJlclwiKX07XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoIShtaW4gPD0gcGFyc2VkU2l6ZSAmJiBwYXJzZWRTaXplIDw9IG1heCkpIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgdmFsaWQ6IGZhbHNlLFxuICAgICAgICAgICAgICAgIGZlZWRiYWNrOiBfdCgnQ3VzdG9tIGZvbnQgc2l6ZSBjYW4gb25seSBiZSBiZXR3ZWVuICUobWluKXMgcHQgYW5kICUobWF4KXMgcHQnLCB7bWluLCBtYXh9KSxcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cblxuICAgICAgICBTZXR0aW5nc1N0b3JlLnNldFZhbHVlKFxuICAgICAgICAgICAgXCJiYXNlRm9udFNpemVcIixcbiAgICAgICAgICAgIG51bGwsXG4gICAgICAgICAgICBTZXR0aW5nTGV2ZWwuREVWSUNFLFxuICAgICAgICAgICAgcGFyc2VJbnQodmFsdWUsIDEwKSAtIEZvbnRXYXRjaGVyLlNJWkVfRElGRixcbiAgICAgICAgKTtcblxuICAgICAgICByZXR1cm4ge3ZhbGlkOiB0cnVlLCBmZWVkYmFjazogX3QoJ1VzZSBiZXR3ZWVuICUobWluKXMgcHQgYW5kICUobWF4KXMgcHQnLCB7bWluLCBtYXh9KX07XG4gICAgfTtcblxuICAgIHByaXZhdGUgb25BZGRDdXN0b21UaGVtZSA9IGFzeW5jICgpOiBQcm9taXNlPHZvaWQ+ID0+IHtcbiAgICAgICAgbGV0IGN1cnJlbnRUaGVtZXM6IHN0cmluZ1tdID0gU2V0dGluZ3NTdG9yZS5nZXRWYWx1ZShcImN1c3RvbV90aGVtZXNcIik7XG4gICAgICAgIGlmICghY3VycmVudFRoZW1lcykgY3VycmVudFRoZW1lcyA9IFtdO1xuICAgICAgICBjdXJyZW50VGhlbWVzID0gY3VycmVudFRoZW1lcy5tYXAoYyA9PiBjKTsgLy8gY2hlYXAgY2xvbmVcblxuICAgICAgICBpZiAodGhpcy50aGVtZVRpbWVyKSB7XG4gICAgICAgICAgICBjbGVhclRpbWVvdXQodGhpcy50aGVtZVRpbWVyKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjb25zdCByID0gYXdhaXQgZmV0Y2godGhpcy5zdGF0ZS5jdXN0b21UaGVtZVVybCk7XG4gICAgICAgICAgICAvLyBYWFg6IG5lZWQgc29tZSBzY2hlbWEgZm9yIHRoaXNcbiAgICAgICAgICAgIGNvbnN0IHRoZW1lSW5mbyA9IGF3YWl0IHIuanNvbigpO1xuICAgICAgICAgICAgaWYgKCF0aGVtZUluZm8gfHwgdHlwZW9mKHRoZW1lSW5mb1snbmFtZSddKSAhPT0gJ3N0cmluZycgfHwgdHlwZW9mKHRoZW1lSW5mb1snY29sb3JzJ10pICE9PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoe2N1c3RvbVRoZW1lTWVzc2FnZToge3RleHQ6IF90KFwiSW52YWxpZCB0aGVtZSBzY2hlbWEuXCIpLCBpc0Vycm9yOiB0cnVlfX0pO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGN1cnJlbnRUaGVtZXMucHVzaCh0aGVtZUluZm8pO1xuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKGUpO1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0