matrix-react-sdk
Version:
SDK for matrix.org using React
281 lines (221 loc) • 31.1 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.enumerateThemes = enumerateThemes;
exports.getCustomTheme = getCustomTheme;
exports.setTheme = setTheme;
exports.DEFAULT_THEME = void 0;
var _languageHandler = require("./languageHandler");
var _Tinter = _interopRequireDefault(require("./Tinter"));
var _SettingsStore = _interopRequireDefault(require("./settings/SettingsStore"));
var _ThemeWatcher = _interopRequireDefault(require("./settings/watchers/ThemeWatcher"));
/*
Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
Copyright 2019 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const DEFAULT_THEME = "light";
exports.DEFAULT_THEME = DEFAULT_THEME;
function enumerateThemes() {
const BUILTIN_THEMES = {
"light": (0, _languageHandler._t)("Light"),
"dark": (0, _languageHandler._t)("Dark")
};
const customThemes = _SettingsStore.default.getValue("custom_themes");
const customThemeNames = {};
for (const {
name
} of customThemes) {
customThemeNames[`custom-${name}`] = name;
}
return Object.assign({}, customThemeNames, BUILTIN_THEMES);
}
function clearCustomTheme() {
// remove all css variables, we assume these are there because of the custom theme
const inlineStyleProps = Object.values(document.body.style);
for (const prop of inlineStyleProps) {
if (prop.startsWith("--")) {
document.body.style.removeProperty(prop);
}
}
const customFontFaceStyle = document.querySelector("head > style[title='custom-theme-font-faces']");
if (customFontFaceStyle) {
customFontFaceStyle.remove();
}
}
const allowedFontFaceProps = ["font-display", "font-family", "font-stretch", "font-style", "font-weight", "font-variant", "font-feature-settings", "font-variation-settings", "src", "unicode-range"];
function generateCustomFontFaceCSS(faces) {
return faces.map(face => {
const src = face.src && face.src.map(srcElement => {
let format;
if (srcElement.format) {
format = `format("${srcElement.format}")`;
}
if (srcElement.url) {
return `url("${srcElement.url}") ${format}`;
} else if (srcElement.local) {
return `local("${srcElement.local}") ${format}`;
}
return "";
}).join(", ");
const props = Object.keys(face).filter(prop => allowedFontFaceProps.includes(prop));
const body = props.map(prop => {
let value;
if (prop === "src") {
value = src;
} else if (prop === "font-family") {
value = `"${face[prop]}"`;
} else {
value = face[prop];
}
return `${prop}: ${value}`;
}).join(";");
return `@font-face {${body}}`;
}).join("\n");
}
function setCustomThemeVars(customTheme) {
const {
style
} = document.body;
function setCSSColorVariable(name, hexColor, doPct = true) {
style.setProperty(`--${name}`, hexColor);
if (doPct) {
// uses #rrggbbaa to define the color with alpha values at 0%, 15% and 50%
style.setProperty(`--${name}-0pct`, hexColor + "00");
style.setProperty(`--${name}-15pct`, hexColor + "26");
style.setProperty(`--${name}-50pct`, hexColor + "7F");
}
}
if (customTheme.colors) {
for (const [name, value] of Object.entries(customTheme.colors)) {
if (Array.isArray(value)) {
for (let i = 0; i < value.length; i += 1) {
setCSSColorVariable(`${name}_${i}`, value[i], false);
}
} else {
setCSSColorVariable(name, value);
}
}
}
if (customTheme.fonts) {
const {
fonts
} = customTheme;
if (fonts.faces) {
const css = generateCustomFontFaceCSS(fonts.faces);
const style = document.createElement("style");
style.setAttribute("title", "custom-theme-font-faces");
style.setAttribute("type", "text/css");
style.appendChild(document.createTextNode(css));
document.head.appendChild(style);
}
if (fonts.general) {
style.setProperty("--font-family", fonts.general);
}
if (fonts.monospace) {
style.setProperty("--font-family-monospace", fonts.monospace);
}
}
}
function getCustomTheme(themeName) {
// set css variables
const customThemes = _SettingsStore.default.getValue("custom_themes");
if (!customThemes) {
throw new Error(`No custom themes set, can't set custom theme "${themeName}"`);
}
const customTheme = customThemes.find(t => t.name === themeName);
if (!customTheme) {
const knownNames = customThemes.map(t => t.name).join(", ");
throw new Error(`Can't find custom theme "${themeName}", only know ${knownNames}`);
}
return customTheme;
}
/**
* Called whenever someone changes the theme
* Async function that returns once the theme has been set
* (ie. the CSS has been loaded)
*
* @param {string} theme new theme
*/
async function setTheme(theme) {
if (!theme) {
const themeWatcher = new _ThemeWatcher.default();
theme = themeWatcher.getEffectiveTheme();
}
clearCustomTheme();
let stylesheetName = theme;
if (theme.startsWith("custom-")) {
const customTheme = getCustomTheme(theme.substr(7));
stylesheetName = customTheme.is_dark ? "dark-custom" : "light-custom";
setCustomThemeVars(customTheme);
} // look for the stylesheet elements.
// styleElements is a map from style name to HTMLLinkElement.
const styleElements = Object.create(null);
let a;
for (let i = 0; a = document.getElementsByTagName("link")[i]; i++) {
const href = a.getAttribute("href"); // shouldn't we be using the 'title' tag rather than the href?
const match = href && href.match(/^bundles\/.*\/theme-(.*)\.css$/);
if (match) {
styleElements[match[1]] = a;
}
}
if (!(stylesheetName in styleElements)) {
throw new Error("Unknown theme " + stylesheetName);
} // disable all of them first, then enable the one we want. Chrome only
// bothers to do an update on a true->false transition, so this ensures
// that we get exactly one update, at the right time.
//
// ^ This comment was true when we used to use alternative stylesheets
// for the CSS. Nowadays we just set them all as disabled in index.html
// and enable them as needed. It might be cleaner to disable them all
// at the same time to prevent loading two themes simultaneously and
// having them interact badly... but this causes a flash of unstyled app
// which is even uglier. So we don't.
styleElements[stylesheetName].disabled = false;
return new Promise(resolve => {
const switchTheme = function () {
// we re-enable our theme here just in case we raced with another
// theme set request as per https://github.com/vector-im/element-web/issues/5601.
// We could alternatively lock or similar to stop the race, but
// this is probably good enough for now.
styleElements[stylesheetName].disabled = false;
Object.values(styleElements).forEach(a => {
if (a == styleElements[stylesheetName]) return;
a.disabled = true;
});
const bodyStyles = global.getComputedStyle(document.body);
if (bodyStyles.backgroundColor) {
document.querySelector('meta[name="theme-color"]').content = bodyStyles.backgroundColor;
}
_Tinter.default.setTheme(theme);
resolve();
}; // turns out that Firefox preloads the CSS for link elements with
// the disabled attribute, but Chrome doesn't.
let cssLoaded = false;
styleElements[stylesheetName].onload = () => {
switchTheme();
};
for (let i = 0; i < document.styleSheets.length; i++) {
const ss = document.styleSheets[i];
if (ss && ss.href === styleElements[stylesheetName].href) {
cssLoaded = true;
break;
}
}
if (cssLoaded) {
styleElements[stylesheetName].onload = undefined;
switchTheme();
}
});
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy90aGVtZS5qcyJdLCJuYW1lcyI6WyJERUZBVUxUX1RIRU1FIiwiZW51bWVyYXRlVGhlbWVzIiwiQlVJTFRJTl9USEVNRVMiLCJjdXN0b21UaGVtZXMiLCJTZXR0aW5nc1N0b3JlIiwiZ2V0VmFsdWUiLCJjdXN0b21UaGVtZU5hbWVzIiwibmFtZSIsIk9iamVjdCIsImFzc2lnbiIsImNsZWFyQ3VzdG9tVGhlbWUiLCJpbmxpbmVTdHlsZVByb3BzIiwidmFsdWVzIiwiZG9jdW1lbnQiLCJib2R5Iiwic3R5bGUiLCJwcm9wIiwic3RhcnRzV2l0aCIsInJlbW92ZVByb3BlcnR5IiwiY3VzdG9tRm9udEZhY2VTdHlsZSIsInF1ZXJ5U2VsZWN0b3IiLCJyZW1vdmUiLCJhbGxvd2VkRm9udEZhY2VQcm9wcyIsImdlbmVyYXRlQ3VzdG9tRm9udEZhY2VDU1MiLCJmYWNlcyIsIm1hcCIsImZhY2UiLCJzcmMiLCJzcmNFbGVtZW50IiwiZm9ybWF0IiwidXJsIiwibG9jYWwiLCJqb2luIiwicHJvcHMiLCJrZXlzIiwiZmlsdGVyIiwiaW5jbHVkZXMiLCJ2YWx1ZSIsInNldEN1c3RvbVRoZW1lVmFycyIsImN1c3RvbVRoZW1lIiwic2V0Q1NTQ29sb3JWYXJpYWJsZSIsImhleENvbG9yIiwiZG9QY3QiLCJzZXRQcm9wZXJ0eSIsImNvbG9ycyIsImVudHJpZXMiLCJBcnJheSIsImlzQXJyYXkiLCJpIiwibGVuZ3RoIiwiZm9udHMiLCJjc3MiLCJjcmVhdGVFbGVtZW50Iiwic2V0QXR0cmlidXRlIiwiYXBwZW5kQ2hpbGQiLCJjcmVhdGVUZXh0Tm9kZSIsImhlYWQiLCJnZW5lcmFsIiwibW9ub3NwYWNlIiwiZ2V0Q3VzdG9tVGhlbWUiLCJ0aGVtZU5hbWUiLCJFcnJvciIsImZpbmQiLCJ0Iiwia25vd25OYW1lcyIsInNldFRoZW1lIiwidGhlbWUiLCJ0aGVtZVdhdGNoZXIiLCJUaGVtZVdhdGNoZXIiLCJnZXRFZmZlY3RpdmVUaGVtZSIsInN0eWxlc2hlZXROYW1lIiwic3Vic3RyIiwiaXNfZGFyayIsInN0eWxlRWxlbWVudHMiLCJjcmVhdGUiLCJhIiwiZ2V0RWxlbWVudHNCeVRhZ05hbWUiLCJocmVmIiwiZ2V0QXR0cmlidXRlIiwibWF0Y2giLCJkaXNhYmxlZCIsIlByb21pc2UiLCJyZXNvbHZlIiwic3dpdGNoVGhlbWUiLCJmb3JFYWNoIiwiYm9keVN0eWxlcyIsImdsb2JhbCIsImdldENvbXB1dGVkU3R5bGUiLCJiYWNrZ3JvdW5kQ29sb3IiLCJjb250ZW50IiwiVGludGVyIiwiY3NzTG9hZGVkIiwib25sb2FkIiwic3R5bGVTaGVldHMiLCJzcyIsInVuZGVmaW5lZCJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7O0FBaUJBOztBQUdBOztBQUNBOztBQUNBOztBQXRCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUlPLE1BQU1BLGFBQWEsR0FBRyxPQUF0Qjs7O0FBS0EsU0FBU0MsZUFBVCxHQUEyQjtBQUM5QixRQUFNQyxjQUFjLEdBQUc7QUFDbkIsYUFBUyx5QkFBRyxPQUFILENBRFU7QUFFbkIsWUFBUSx5QkFBRyxNQUFIO0FBRlcsR0FBdkI7O0FBSUEsUUFBTUMsWUFBWSxHQUFHQyx1QkFBY0MsUUFBZCxDQUF1QixlQUF2QixDQUFyQjs7QUFDQSxRQUFNQyxnQkFBZ0IsR0FBRyxFQUF6Qjs7QUFDQSxPQUFLLE1BQU07QUFBQ0MsSUFBQUE7QUFBRCxHQUFYLElBQXFCSixZQUFyQixFQUFtQztBQUMvQkcsSUFBQUEsZ0JBQWdCLENBQUUsVUFBU0MsSUFBSyxFQUFoQixDQUFoQixHQUFxQ0EsSUFBckM7QUFDSDs7QUFDRCxTQUFPQyxNQUFNLENBQUNDLE1BQVAsQ0FBYyxFQUFkLEVBQWtCSCxnQkFBbEIsRUFBb0NKLGNBQXBDLENBQVA7QUFDSDs7QUFFRCxTQUFTUSxnQkFBVCxHQUE0QjtBQUN4QjtBQUNBLFFBQU1DLGdCQUFnQixHQUFHSCxNQUFNLENBQUNJLE1B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QUNERSxzQkFBT3pCLFFBQVAsQ0FBZ0JDLEtBQWhCOztBQUNBZ0IsTUFBQUEsT0FBTztBQUNWLEtBaEJELENBRDRCLENBbUI1QjtBQUNBOzs7QUFFQSxRQUFJUyxTQUFTLEdBQUcsS0FBaEI7O0FBRUFsQixJQUFBQSxhQUFhLENBQUNILGNBQUQsQ0FBYixDQUE4QnNCLE1BQTlCLEdBQXVDLE1BQU07QUFDekNULE1BQUFBLFdBQVc7QUFDZCxLQUZEOztBQUlBLFNBQUssSUFBSW5DLENBQUMsR0FBRyxDQUFiLEVBQWdCQSxDQUFDLEdBQUduQyxRQUFRLENBQUNnRixXQUFULENBQXFCNUMsTUFBekMsRUFBaURELENBQUMsRUFBbEQsRUFBc0Q7QUFDbEQsWUFBTThDLEVBQUUsR0FBR2pGLFFBQVEsQ0FBQ2dGLFdBQVQsQ0FBcUI3QyxDQUFyQixDQUFYOztBQUNBLFVBQUk4QyxFQUFFLElBQUlBLEVBQUUsQ0FBQ2pCLElBQUgsS0FBWUosYUFBYSxDQUFDSCxjQUFELENBQWIsQ0FBOEJPLElBQXBELEVBQTBEO0FBQ3REYyxRQUFBQSxTQUFTLEdBQUcsSUFBWjtBQUNBO0FBQ0g7QUFDSjs7QUFFRCxRQUFJQSxTQUFKLEVBQWU7QUFDWGxCLE1BQUFBLGFBQWEsQ0FBQ0gsY0FBRCxDQUFiLENBQThCc0IsTUFBOUIsR0FBdUNHLFNBQXZDO0FBQ0FaLE1BQUFBLFdBQVc7QUFDZDtBQUNKLEdBeENNLENBQVA7QUF5Q0giLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuQ29weXJpZ2h0IDIwMTkgTWljaGFlbCBUZWxhdHluc2tpIDw3dDNjaGd1eUBnbWFpbC5jb20+XG5Db3B5cmlnaHQgMjAxOSBUaGUgTWF0cml4Lm9yZyBGb3VuZGF0aW9uIEMuSS5DLlxuXG5MaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgXCJMaWNlbnNlXCIpO1xueW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLlxuWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0XG5cbiAgICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjBcblxuVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZVxuZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gXCJBUyBJU1wiIEJBU0lTLFxuV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuXG5TZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kXG5saW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS5cbiovXG5cbmltcG9ydCB7X3R9IGZyb20gXCIuL2xhbmd1YWdlSGFuZGxlclwiO1xuXG5leHBvcnQgY29uc3QgREVGQVVMVF9USEVNRSA9IFwibGlnaHRcIjtcbmltcG9ydCBUaW50ZXIgZnJvbSBcIi4vVGludGVyXCI7XG5pbXBvcnQgU2V0dGluZ3NTdG9yZSBmcm9tIFwiLi9zZXR0aW5ncy9TZXR0aW5nc1N0b3JlXCI7XG5pbXBvcnQgVGhlbWVXYXRjaGVyIGZyb20gXCIuL3NldHRpbmdzL3dhdGNoZXJzL1RoZW1lV2F0Y2hlclwiO1xuXG5leHBvcnQgZnVuY3Rpb24gZW51bWVyYXRlVGhlbWVzKCkge1xuICAgIGNvbnN0IEJVSUxUSU5fVEhFTUVTID0ge1xuICAgICAgICBcImxpZ2h0XCI6IF90KFwiTGlnaHRcIiksXG4gICAgICAgIFwiZGFya1wiOiBfdChcIkRhcmtcIiksXG4gICAgfTtcbiAgICBjb25zdCBjdXN0b21UaGVtZXMgPSBTZXR0aW5nc1N0b3JlLmdldFZhbHVlKFwiY3VzdG9tX3RoZW1lc1wiKTtcbiAgICBjb25zdCBjdXN0b21UaGVtZU5hbWVzID0ge307XG4gICAgZm9yIChjb25zdCB7bmFtZX0gb2YgY3VzdG9tVGhlbWVzKSB7XG4gICAgICAgIGN1c3RvbVRoZW1lTmFtZXNbYGN1c3RvbS0ke25hbWV9YF0gPSBuYW1lO1xuICAgIH1cbiAgICByZXR1cm4gT2JqZWN0LmFzc2lnbih7fSwgY3VzdG9tVGhlbWVOYW1lcywgQlVJTFRJTl9USEVNRVMpO1xufVxuXG5mdW5jdGlvbiBjbGVhckN1c3RvbVRoZW1lKCkge1xuICAgIC8vIHJlbW92ZSBhbGwgY3NzIHZhcmlhYmxlcywgd2UgYXNzdW1lIHRoZXNlIGFyZSB0aGVyZSBiZWNhdXNlIG9mIHRoZSBjdXN0b20gdGhlbWVcbiAgICBjb25zdCBpbmxpbmVTdHlsZVByb3BzID0gT2JqZWN0LnZhbHVlcyhkb2N1bWVudC5ib2R5LnN0eWxlKTtcbiAgICBmb3IgKGNvbnN0IHByb3Agb2YgaW5saW5lU3R5bGVQcm9wcykge1xuICAgICAgICBpZiAocHJvcC5zdGFydHNXaXRoKFwiLS1cIikpIHtcbiAgICAgICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUucmVtb3ZlUHJvcGVydHkocHJvcCk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgY29uc3QgY3VzdG9tRm9udEZhY2VTdHlsZSA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoXCJoZWFkID4gc3R5bGVbdGl0bGU9J2N1c3RvbS10aGVtZS1mb250LWZhY2VzJ11cIik7XG4gICAgaWYgKGN1c3RvbUZvbnRGYWNlU3R5bGUpIHtcbiAgICAgICAgY3VzdG9tRm9udEZhY2VTdHlsZS5yZW1vdmUoKTtcbiAgICB9XG59XG5cbmNvbnN0IGFsbG93ZWRGb250RmFjZVByb3BzID0gW1xuICAgIFwiZm9udC1kaXNwbGF5XCIsXG4gICAgXCJmb250LWZhbWlseVwiLFxuICAgIFwiZm9udC1zdHJldGNoXCIsXG4gICAgXCJmb250LXN0eWxlXCIsXG4gICAgXCJmb250LXdlaWdodFwiLFxuICAgIFwiZm9udC12YXJpYW50XCIsXG4gICAgXCJmb250LWZlYXR1cmUtc2V0dGluZ3NcIixcbiAgICBcImZvbnQtdmFyaWF0aW9uLXNldHRpbmdzXCIsXG4gICAgXCJzcmNcIixcbiAgICBcInVuaWNvZGUtcmFuZ2VcIixcbl07XG5cbmZ1bmN0aW9uIGdlbmVyYXRlQ3VzdG9tRm9udEZhY2VDU1MoZmFjZXMpIHtcbiAgICByZXR1cm4gZmFjZXMubWFwKGZhY2UgPT4ge1xuICAgICAgICBjb25zdCBzcmMgPSBmYWNlLnNyYyAmJiBmYWNlLnNyYy5tYXAoc3JjRWxlbWVudCA9PiB7XG4gICAgICAgICAgICBsZXQgZm9ybWF0O1xuICAgICAgICAgICAgaWYgKHNyY0VsZW1lbnQuZm9ybWF0KSB7XG4gICAgICAgICAgICAgICAgZm9ybWF0ID0gYGZvcm1hdChcIiR7c3JjRWxlbWVudC5mb3JtYXR9XCIpYDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChzcmNFbGVtZW50LnVybCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBgdXJsKFwiJHtzcmNFbGVtZW50LnVybH1cIikgJHtmb3JtYXR9YDtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoc3JjRWxlbWVudC5sb2NhbCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBgbG9jYWwoXCIke3NyY0VsZW1lbnQubG9jYWx9XCIpICR7Zm9ybWF0fWA7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gXCJcIjtcbiAgICAgICAgfSkuam9pbihcIiwgXCIpO1xuICAgICAgICBjb25zdCBwcm9wcyA9IE9iamVjdC5rZXlzKGZhY2UpLmZpbHRlcihwcm9wID0+IGFsbG93ZWRGb250RmFjZVByb3BzLmluY2x1ZGVzKHByb3ApKTtcbiAgICAgICAgY29uc3QgYm9keSA9IHByb3BzLm1hcChwcm9wID0+IHtcbiAgICAgICAgICAgIGxldCB2YWx1ZTtcbiAgICAgICAgICAgIGlmIChwcm9wID09PSBcInNyY1wiKSB7XG4gICAgICAgICAgICAgICAgdmFsdWUgPSBzcmM7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKHByb3AgPT09IFwiZm9udC1mYW1pbHlcIikge1xuICAgICAgICAgICAgICAgIHZhbHVlID0gYFwiJHtmYWNlW3Byb3BdfVwiYDtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgdmFsdWUgPSBmYWNlW3Byb3BdO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIGAke3Byb3B9OiAke3ZhbHVlfWA7XG4gICAgICAgIH0pLmpvaW4oXCI7XCIpO1xuICAgICAgICByZXR1cm4gYEBmb250LWZhY2UgeyR7Ym9keX19YDtcbiAgICB9KS5qb2luKFwiXFxuXCIpO1xufVxuXG5mdW5jdGlvbiBzZXRDdXN0b21UaGVtZVZhcnMoY3VzdG9tVGhlbWUpIHtcbiAgICBjb25zdCB7c3R5bGV9ID0gZG9jdW1lbnQuYm9keTtcblxuICAgIGZ1bmN0aW9uIHNldENTU0NvbG9yVmFyaWFibGUobmFtZSwgaGV4Q29sb3IsIGRvUGN0ID0gdHJ1ZSkge1xuICAgICAgICBzdHlsZS5zZXRQcm9wZXJ0eShgLS0ke25hbWV9YCwgaGV4Q29sb3IpO1xuICAgICAgICBpZiAoZG9QY3QpIHtcbiAgICAgICAgICAgIC8vIHVzZXMgI3JyZ2diYmFhIHRvIGRlZmluZSB0aGUgY29sb3Igd2l0aCBhbHBoYSB2YWx1ZXMgYXQgMCUsIDE1JSBhbmQgNTAlXG4gICAgICAgICAgICBzdHlsZS5zZXRQcm9wZXJ0eShgLS0ke25hbWV9LTBwY3RgLCBoZXhDb2xvciArIFwiMDBcIik7XG4gICAgICAgICAgICBzdHlsZS5zZXRQcm9wZXJ0eShgLS0ke25hbWV9LTE1cGN0YCwgaGV4Q29sb3IgKyBcIjI2XCIpO1xuICAgICAgICAgICAgc3R5bGUuc2V0UHJvcGVydHkoYC0tJHtuYW1lfS01MHBjdGAsIGhleENvbG9yICsgXCI3RlwiKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGlmIChjdXN0b21UaGVtZS5jb2xvcnMpIHtcbiAgICAgICAgZm9yIChjb25zdCBbbmFtZSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKGN1c3RvbVRoZW1lLmNvbG9ycykpIHtcbiAgICAgICAgICAgIGlmIChBcnJheS5pc0FycmF5KHZhbHVlKSkge1xuICAgICAgICAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdmFsdWUubGVuZ3RoOyBpICs9IDEpIHtcbiAgICAgICAgICAgICAgICAgICAgc2V0Q1NTQ29sb3JWYXJpYWJsZShgJHtuYW1lfV8ke2l9YCwgdmFsdWVbaV0sIGZhbHNlKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHNldENTU0NvbG9yVmFyaWFibGUobmFtZSwgdmFsdWUpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuICAgIGlmIChjdXN0b21UaGVtZS5mb250cykge1xuICAgICAgICBjb25zdCB7Zm9udHN9ID0gY3VzdG9tVGhlbWU7XG4gICAgICAgIGlmIChmb250cy5mYWNlcykge1xuICAgICAgICAgICAgY29uc3QgY3NzID0gZ2VuZXJhdGVDdXN0b21Gb250RmFjZUNTUyhmb250cy5mYWNlcyk7XG4gICAgICAgICAgICBjb25zdCBzdHlsZSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJzdHlsZVwiKTtcbiAgICAgICAgICAgIHN0eWxlLnNldEF0dHJpYnV0ZShcInRpdGxlXCIsIFwiY3VzdG9tLXRoZW1lLWZvbnQtZmFjZXNcIik7XG4gICAgICAgICAgICBzdHlsZS5zZXRBdHRyaWJ1dGUoXCJ0eXBlXCIsIFwidGV4dC9jc3NcIik7XG4gICAgICAgICAgICBzdHlsZS5hcHBlbmRDaGlsZChkb2N1bWVudC5jcmVhdGVUZXh0Tm9kZShjc3MpKTtcbiAgICAgICAgICAgIGRvY3VtZW50LmhlYWQuYXBwZW5kQ2hpbGQoc3R5bGUpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChmb250cy5nZW5lcmFsKSB7XG4gICAgICAgICAgICBzdHlsZS5zZXRQcm9wZXJ0eShcIi0tZm9udC1mYW1pbHlcIiwgZm9udHMuZ2VuZXJhbCk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGZvbnRzLm1vbm9zcGFjZSkge1xuICAgICAgICAgICAgc3R5bGUuc2V0UHJvcGVydHkoXCItLWZvbnQtZmFtaWx5LW1vbm9zcGFjZVwiLCBmb250cy5tb25vc3BhY2UpO1xuICAgICAgICB9XG4gICAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0Q3VzdG9tVGhlbWUodGhlbWVOYW1lKSB7XG4gICAgLy8gc2V0IGNzcyB2YXJpYWJsZXNcbiAgICBjb25zdCBjdXN0b21UaGVtZXMgPSBTZXR0aW5nc1N0b3JlLmdldFZhbHVlKFwiY3VzdG9tX3RoZW1lc1wiKTtcbiAgICBpZiAoIWN1c3RvbVRoZW1lcykge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYE5vIGN1c3RvbSB0aGVtZXMgc2V0LCBjYW4ndCBzZXQgY3VzdG9tIHRoZW1lIFwiJHt0aGVtZU5hbWV9XCJgKTtcbiAgICB9XG4gICAgY29uc3QgY3VzdG9tVGhlbWUgPSBjdXN0b21UaGVtZXMuZmluZCh0ID0+IHQubmFtZSA9PT0gdGhlbWVOYW1lKTtcbiAgICBpZiAoIWN1c3RvbVRoZW1lKSB7XG4gICAgICAgIGNvbnN0IGtub3duTmFtZXMgPSBjdXN0b21UaGVtZXMubWFwKHQgPT4gdC5uYW1lKS5qb2luKFwiLCBcIik7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgQ2FuJ3QgZmluZCBjdXN0b20gdGhlbWUgXCIke3RoZW1lTmFtZX1cIiwgb25seSBrbm93ICR7a25vd25OYW1lc31gKTtcbiAgICB9XG4gICAgcmV0dXJuIGN1c3RvbVRoZW1lO1xufVxuXG4vKipcbiAqIENhbGxlZCB3aGVuZXZlciBzb21lb25lIGNoYW5nZXMgdGhlIHRoZW1lXG4gKiBBc3luYyBmdW5jdGlvbiB0aGF0IHJldHVybnMgb25jZSB0aGUgdGhlbWUgaGFzIGJlZW4gc2V0XG4gKiAoaWUuIHRoZSBDU1MgaGFzIGJlZW4gbG9hZGVkKVxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSB0aGVtZSBuZXcgdGhlbWVcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHNldFRoZW1lKHRoZW1lKSB7XG4gICAgaWYgKCF0aGVtZSkge1xuICAgICAgICBjb25zdCB0aGVtZVdhdGNoZXIgPSBuZXcgVGhlbWVXYXRjaGVyKCk7XG4gICAgICAgIHRoZW1lID0gdGhlbWVXYXRjaGVyLmdldEVmZmVjdGl2ZVRoZW1lKCk7XG4gICAgfVxuICAgIGNsZWFyQ3VzdG9tVGhlbWUoKTtcbiAgICBsZXQgc3R5bGVzaGVldE5hbWUgPSB0aGVtZTtcbiAgICBpZiAodGhlbWUuc3RhcnRzV2l0aChcImN1c3RvbS1cIikpIHtcbiAgICAgICAgY29uc3QgY3VzdG9tVGhlbWUgPSBnZXRDdXN0b21UaGVtZSh0aGVtZS5zdWJzdHIoNykpO1xuICAgICAgICBzdHlsZXNoZWV0TmFtZSA9IGN1c3RvbVRoZW1lLmlzX2RhcmsgPyBcImRhcmstY3VzdG9tXCIgOiBcImxpZ2h0LWN1c3RvbVwiO1xuICAgICAgICBzZXRDdXN0b21UaGVtZVZhcnMoY3VzdG9tVGhlbWUpO1xuICAgIH1cblxuICAgIC8vIGxvb2sgZm9yIHRoZSBzdHlsZXNoZWV0IGVsZW1lbnRzLlxuICAgIC8vIHN0eWxlRWxlbWVudHMgaXMgYSBtYXAgZnJvbSBzdHlsZSBuYW1lIHRvIEhUTUxMaW5rRWxlbWVudC5cbiAgICBjb25zdCBzdHlsZUVsZW1lbnRzID0gT2JqZWN0LmNyZWF0ZShudWxsKTtcbiAgICBsZXQgYTtcbiAgICBmb3IgKGxldCBpID0gMDsgKGEgPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZShcImxpbmtcIilbaV0pOyBpKyspIHtcbiAgICAgICAgY29uc3QgaHJlZiA9IGEuZ2V0QXR0cmlidXRlKFwiaHJlZlwiKTtcbiAgICAgICAgLy8gc2hvdWxkbid0IHdlIGJlIHVzaW5nIHRoZSAndGl0bGUnIHRhZyByYXRoZXIgdGhhbiB0aGUgaHJlZj9cbiAgICAgICAgY29uc3QgbWF0Y2ggPSBocmVmICYmIGhyZWYubWF0Y2goL15idW5kbGVzXFwvLipcXC90aGVtZS0oLiopXFwuY3NzJC8pO1xuICAgICAgICBpZiAobWF0Y2gpIHtcbiAgICAgICAgICAgIHN0eWxlRWxlbWVudHNbbWF0Y2hbMV1dID0gYTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGlmICghKHN0eWxlc2hlZXROYW1lIGluIHN0eWxlRWxlbWVudHMpKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIlVua25vd24gdGhlbWUgXCIgKyBzdHlsZXNoZWV0TmFtZSk7XG4gICAgfVxuXG4gICAgLy8gZGlzYWJsZSBhbGwgb2YgdGhlbSBmaXJzdCwgdGhlbiBlbmFibGUgdGhlIG9uZSB3ZSB3YW50LiBDaHJvbWUgb25seVxuICAgIC8vIGJvdGhlcnMgdG8gZG8gYW4gdXBkYXRlIG9uIGEgdHJ1ZS0+ZmFsc2UgdHJhbnNpdGlvbiwgc28gdGhpcyBlbnN1cmVzXG4gICAgLy8gdGhhdCB3ZSBnZXQgZXhhY3RseSBvbmUgdXBkYXRlLCBhdCB0aGUgcmlnaHQgdGltZS5cbiAgICAvL1xuICAgIC8vIF4gVGhpcyBjb21tZW50IHdhcyB0cnVlIHdoZW4gd2UgdXNlZCB0byB1c2UgYWx0ZXJuYXRpdmUgc3R5bGVzaGVldHNcbiAgICAvLyBmb3IgdGhlIENTUy4gIE5vd2FkYXlzIHdlIGp1c3Qgc2V0IHRoZW0gYWxsIGFzIGRpc2FibGVkIGluIGluZGV4Lmh0bWxcbiAgICAvLyBhbmQgZW5hYmxlIHRoZW0gYXMgbmVlZGVkLiAgSXQgbWlnaHQgYmUgY2xlYW5lciB0byBkaXNhYmxlIHRoZW0gYWxsXG4gICAgLy8gYXQgdGhlIHNhbWUgdGltZSB0byBwcmV2ZW50IGxvYWRpbmcgdHdvIHRoZW1lcyBzaW11bHRhbmVvdXNseSBhbmRcbiAgICAvLyBoYXZpbmcgdGhlbSBpbnRlcmFjdCBiYWRseS4uLiBidXQgdGhpcyBjYXVzZXMgYSBmbGFzaCBvZiB1bnN0eWxlZCBhcHBcbiAgICAvLyB3aGljaCBpcyBldmVuIHVnbGllci4gIFNvIHdlIGRvbid0LlxuXG4gICAgc3R5bGVFbGVtZW50c1tzdHlsZXNoZWV0TmFtZV0uZGlzYWJsZWQgPSBmYWxzZTtcblxuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4ge1xuICAgICAgICBjb25zdCBzd2l0Y2hUaGVtZSA9IGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgLy8gd2UgcmUtZW5hYmxlIG91ciB0aGVtZSBoZXJlIGp1c3QgaW4gY2FzZSB3ZSByYWNlZCB3aXRoIGFub3RoZXJcbiAgICAgICAgICAgIC8vIHRoZW1lIHNldCByZXF1ZXN0IGFzIHBlciBodHRwczovL2dpdGh1Yi5jb20vdmVjdG9yLWltL2VsZW1lbnQtd2ViL2lzc3Vlcy81NjAxLlxuICAgICAgICAgICAgLy8gV2UgY291bGQgYWx0ZXJuYXRpdmVseSBsb2NrIG9yIHNpbWlsYXIgdG8gc3RvcCB0aGUgcmFjZSwgYnV0XG4gICAgICAgICAgICAvLyB0aGlzIGlzIHByb2JhYmx5IGdvb2QgZW5vdWdoIGZvciBub3cuXG4gICAgICAgICAgICBzdHlsZUVsZW1lbnRzW3N0eWxlc2hlZXROYW1lXS5kaXNhYmxlZCA9IGZhbHNlO1xuICAgICAgICAgICAgT2JqZWN0LnZhbHVlcyhzdHlsZUVsZW1lbnRzKS5mb3JFYWNoKChhKSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKGEgPT0gc3R5bGVFbGVtZW50c1tzdHlsZXNoZWV0TmFtZV0pIHJldHVybjtcbiAgICAgICAgICAgICAgICBhLmRpc2FibGVkID0gdHJ1ZTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgY29uc3QgYm9keVN0eWxlcyA9IGdsb2JhbC5nZXRDb21wdXRlZFN0eWxlKGRvY3VtZW50LmJvZHkpO1xuICAgICAgICAgICAgaWYgKGJvZHlTdHlsZXMuYmFja2dyb3VuZENvbG9yKSB7XG4gICAgICAgICAgICAgICAgZG9jdW1lbnQucXVlcnlTZWxlY3RvcignbWV0YVtuYW1lPVwidGhlbWUtY29sb3JcIl0nKS5jb250ZW50ID0gYm9keVN0eWxlcy5iYWNrZ3JvdW5kQ29sb3I7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBUaW50ZXIuc2V0VGhlbWUodGhlbWUpO1xuICAgICAgICAgICAgcmVzb2x2ZSgpO1xuICAgICAgICB9O1xuXG4gICAgICAgIC8vIHR1cm5zIG91dCB0aGF0IEZpcmVmb3ggcHJlbG9hZHMgdGhlIENTUyBmb3IgbGluayBlbGVtZW50cyB3aXRoXG4gICAgICAgIC8vIHRoZSBkaXNhYmxlZCBhdHRyaWJ1dGUsIGJ1dCBDaHJvbWUgZG9lc24ndC5cblxuICAgICAgICBsZXQgY3NzTG9hZGVkID0gZmFsc2U7XG5cbiAgICAgICAgc3R5bGVFbGVtZW50c1tzdHlsZXNoZWV0TmFtZV0ub25sb2FkID0gKCkgPT4ge1xuICAgICAgICAgICAgc3dpdGNoVGhlbWUoKTtcbiAgICAgICAgfTtcblxuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGRvY3VtZW50LnN0eWxlU2hlZXRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBjb25zdCBzcyA9IGRvY3VtZW50LnN0eWxlU2hlZXRzW2ldO1xuICAgICAgICAgICAgaWYgKHNzICYmIHNzLmhyZWYgPT09IHN0eWxlRWxlbWVudHNbc3R5bGVzaGVldE5hbWVdLmhyZWYpIHtcbiAgICAgICAgICAgICAgICBjc3NMb2FkZWQgPSB0cnVlO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGNzc0xvYWRlZCkge1xuICAgICAgICAgICAgc3R5bGVFbGVtZW50c1tzdHlsZXNoZWV0TmFtZV0ub25sb2FkID0gdW5kZWZpbmVkO1xuICAgICAgICAgICAgc3dpdGNoVGhlbWUoKTtcbiAgICAgICAgfVxuICAgIH0pO1xufVxuIl19