UNPKG

matrix-react-sdk

Version:
327 lines (313 loc) 46.2 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.DEFAULT_THEME = void 0; exports.enumerateThemes = enumerateThemes; exports.findHighContrastTheme = findHighContrastTheme; exports.findNonHighContrastTheme = findNonHighContrastTheme; exports.getCustomTheme = getCustomTheme; exports.getOrderedThemes = getOrderedThemes; exports.isHighContrastTheme = isHighContrastTheme; exports.setTheme = setTheme; var _logger = require("matrix-js-sdk/src/logger"); var _languageHandler = require("./languageHandler"); var _SettingsStore = _interopRequireDefault(require("./settings/SettingsStore")); var _ThemeWatcher = _interopRequireDefault(require("./settings/watchers/ThemeWatcher")); /* Copyright 2024 New Vector Ltd. Copyright 2019 Michael Telatynski <7t3chguy@gmail.com> Copyright 2019 The Matrix.org Foundation C.I.C. SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only Please see LICENSE files in the repository root for full details. */ const DEFAULT_THEME = exports.DEFAULT_THEME = "light"; const HIGH_CONTRAST_THEMES = { light: "light-high-contrast" }; /** * Given a non-high-contrast theme, find the corresponding high-contrast one * if it exists, or return undefined if not. */ function findHighContrastTheme(theme) { return HIGH_CONTRAST_THEMES[theme]; } /** * Given a high-contrast theme, find the corresponding non-high-contrast one * if it exists, or return undefined if not. */ function findNonHighContrastTheme(hcTheme) { for (const theme in HIGH_CONTRAST_THEMES) { if (HIGH_CONTRAST_THEMES[theme] === hcTheme) { return theme; } } } /** * Decide whether the supplied theme is high contrast. */ function isHighContrastTheme(theme) { return Object.values(HIGH_CONTRAST_THEMES).includes(theme); } function enumerateThemes() { const BUILTIN_THEMES = { "light": (0, _languageHandler._t)("common|light"), "light-high-contrast": (0, _languageHandler._t)("theme|light_high_contrast"), "dark": (0, _languageHandler._t)("common|dark") }; const customThemes = _SettingsStore.default.getValue("custom_themes") || []; const customThemeNames = {}; try { for (const { name } of customThemes) { customThemeNames[`custom-${name}`] = name; } } catch (err) { _logger.logger.warn("Error loading custom themes", { err, customThemes }); } return Object.assign({}, customThemeNames, BUILTIN_THEMES); } function getOrderedThemes() { const themes = Object.entries(enumerateThemes()).map(p => ({ id: p[0], name: p[1] })) // convert pairs to objects for code readability .filter(p => !isHighContrastTheme(p.id)); const builtInThemes = themes.filter(p => !p.id.startsWith("custom-")); const collator = new Intl.Collator(); const customThemes = themes.filter(p => !builtInThemes.includes(p)).sort((a, b) => collator.compare(a.name, b.name)); return [...builtInThemes, ...customThemes]; } 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); } } // remove the custom style sheets document.querySelector("head > style[title='custom-theme-font-faces']")?.remove(); document.querySelector("head > style[title='custom-theme-compound']")?.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?.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"); } const COMPOUND_TOKEN = /^--cpd-[a-z0-9-]+$/; /** * Generates a style sheet to override Compound design tokens as specified in * the given theme. */ function generateCustomCompoundCSS(theme) { const properties = []; for (const [token, value] of Object.entries(theme)) if (COMPOUND_TOKEN.test(token)) properties.push(`${token}: ${value};`);else _logger.logger.warn(`'${token}' is not a valid Compound token`); // Insert the design token overrides into the 'custom' cascade layer as // documented at https://compound.element.io/?path=/docs/develop-theming--docs return `@layer compound.custom { :root, [class*="cpd-theme-"] { ${properties.join(" ")} } }`; } 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); } } if (customTheme.compound) { const css = generateCustomCompoundCSS(customTheme.compound); const style = document.createElement("style"); style.setAttribute("title", "custom-theme-compound"); style.setAttribute("type", "text/css"); style.appendChild(document.createTextNode(css)); document.head.appendChild(style); } } 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.slice(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 = new Map(); const themes = Array.from(document.querySelectorAll("[data-mx-theme]")); themes.forEach(theme => { styleElements.set(theme.dataset.mxTheme.toLowerCase(), theme); }); if (!styleElements.has(stylesheetName)) { 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. const styleSheet = styleElements.get(stylesheetName); styleSheet.disabled = false; /** * Adds the Compound theme class to the top-most element in the document * This will automatically refresh the colour scales based on the OS or user * preferences */ document.body.classList.remove("cpd-theme-light", "cpd-theme-dark", "cpd-theme-light-hc", "cpd-theme-dark-hc"); let compoundThemeClassName = `cpd-theme-` + (stylesheetName.includes("light") ? "light" : "dark"); // Always respect user OS preference! if (isHighContrastTheme(theme) || window.matchMedia("(prefers-contrast: more)").matches) { compoundThemeClassName += "-hc"; } document.body.classList.add(compoundThemeClassName); return new Promise((resolve, reject) => { 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. styleSheet.disabled = false; styleElements.forEach(a => { if (a == styleSheet) return; a.disabled = true; }); const bodyStyles = global.getComputedStyle(document.body); if (bodyStyles.backgroundColor) { const metaElement = document.querySelector('meta[name="theme-color"]'); metaElement.content = bodyStyles.backgroundColor; } resolve(); }; const isStyleSheetLoaded = () => Boolean([...document.styleSheets].find(_styleSheet => _styleSheet?.href === styleSheet.href)); function waitForStyleSheetLoading() { // turns out that Firefox preloads the CSS for link elements with // the disabled attribute, but Chrome doesn't. if (isStyleSheetLoaded()) { switchTheme(); return; } let counter = 0; // In case of theme toggling (white => black => white) // Chrome doesn't fire the `load` event when the white theme is selected the second times const intervalId = window.setInterval(() => { if (isStyleSheetLoaded()) { clearInterval(intervalId); styleSheet.onload = null; styleSheet.onerror = null; switchTheme(); } // Avoid to be stuck in an endless loop if there is an issue in the stylesheet loading counter++; if (counter === 10) { clearInterval(intervalId); reject(); } }, 200); styleSheet.onload = () => { clearInterval(intervalId); switchTheme(); }; styleSheet.onerror = e => { clearInterval(intervalId); reject(e); }; } waitForStyleSheetLoading(); }); } //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfbG9nZ2VyIiwicmVxdWlyZSIsIl9sYW5ndWFnZUhhbmRsZXIiLCJfU2V0dGluZ3NTdG9yZSIsIl9pbnRlcm9wUmVxdWlyZURlZmF1bHQiLCJfVGhlbWVXYXRjaGVyIiwiREVGQVVMVF9USEVNRSIsImV4cG9ydHMiLCJISUdIX0NPTlRSQVNUX1RIRU1FUyIsImxpZ2h0IiwiZmluZEhpZ2hDb250cmFzdFRoZW1lIiwidGhlbWUiLCJmaW5kTm9uSGlnaENvbnRyYXN0VGhlbWUiLCJoY1RoZW1lIiwiaXNIaWdoQ29udHJhc3RUaGVtZSIsIk9iamVjdCIsInZhbHVlcyIsImluY2x1ZGVzIiwiZW51bWVyYXRlVGhlbWVzIiwiQlVJTFRJTl9USEVNRVMiLCJfdCIsImN1c3RvbVRoZW1lcyIsIlNldHRpbmdzU3RvcmUiLCJnZXRWYWx1ZSIsImN1c3RvbVRoZW1lTmFtZXMiLCJuYW1lIiwiZXJyIiwibG9nZ2VyIiwid2FybiIsImFzc2lnbiIsImdldE9yZGVyZWRUaGVtZXMiLCJ0aGVtZXMiLCJlbnRyaWVzIiwibWFwIiwicCIsImlkIiwiZmlsdGVyIiwiYnVpbHRJblRoZW1lcyIsInN0YXJ0c1dpdGgiLCJjb2xsYXRvciIsIkludGwiLCJDb2xsYXRvciIsInNvcnQiLCJhIiwiYiIsImNvbXBhcmUiLCJjbGVhckN1c3RvbVRoZW1lIiwiaW5saW5lU3R5bGVQcm9wcyIsImRvY3VtZW50IiwiYm9keSIsInN0eWxlIiwicHJvcCIsInJlbW92ZVByb3BlcnR5IiwicXVlcnlTZWxlY3RvciIsInJlbW92ZSIsImFsbG93ZWRGb250RmFjZVByb3BzIiwiZ2VuZXJhdGVDdXN0b21Gb250RmFjZUNTUyIsImZhY2VzIiwiZmFjZSIsInNyYyIsInNyY0VsZW1lbnQiLCJmb3JtYXQiLCJ1cmwiLCJsb2NhbCIsImpvaW4iLCJwcm9wcyIsImtleXMiLCJ2YWx1ZSIsIkNPTVBPVU5EX1RPS0VOIiwiZ2VuZXJhdGVDdXN0b21Db21wb3VuZENTUyIsInByb3BlcnRpZXMiLCJ0b2tlbiIsInRlc3QiLCJwdXNoIiwic2V0Q3VzdG9tVGhlbWVWYXJzIiwiY3VzdG9tVGhlbWUiLCJzZXRDU1NDb2xvclZhcmlhYmxlIiwiaGV4Q29sb3IiLCJkb1BjdCIsInNldFByb3BlcnR5IiwiY29sb3JzIiwiQXJyYXkiLCJpc0FycmF5IiwiaSIsImxlbmd0aCIsImZvbnRzIiwiY3NzIiwiY3JlYXRlRWxlbWVudCIsInNldEF0dHJpYnV0ZSIsImFwcGVuZENoaWxkIiwiY3JlYXRlVGV4dE5vZGUiLCJoZWFkIiwiZ2VuZXJhbCIsIm1vbm9zcGFjZSIsImNvbXBvdW5kIiwiZ2V0Q3VzdG9tVGhlbWUiLCJ0aGVtZU5hbWUiLCJFcnJvciIsImZpbmQiLCJ0Iiwia25vd25OYW1lcyIsInNldFRoZW1lIiwidGhlbWVXYXRjaGVyIiwiVGhlbWVXYXRjaGVyIiwiZ2V0RWZmZWN0aXZlVGhlbWUiLCJzdHlsZXNoZWV0TmFtZSIsInNsaWNlIiwiaXNfZGFyayIsInN0eWxlRWxlbWVudHMiLCJNYXAiLCJmcm9tIiwicXVlcnlTZWxlY3RvckFsbCIsImZvckVhY2giLCJzZXQiLCJkYXRhc2V0IiwibXhUaGVtZSIsInRvTG93ZXJDYXNlIiwiaGFzIiwic3R5bGVTaGVldCIsImdldCIsImRpc2FibGVkIiwiY2xhc3NMaXN0IiwiY29tcG91bmRUaGVtZUNsYXNzTmFtZSIsIndpbmRvdyIsIm1hdGNoTWVkaWEiLCJtYXRjaGVzIiwiYWRkIiwiUHJvbWlzZSIsInJlc29sdmUiLCJyZWplY3QiLCJzd2l0Y2hUaGVtZSIsImJvZHlTdHlsZXMiLCJnbG9iYWwiLCJnZXRDb21wdXRlZFN0eWxlIiwiYmFja2dyb3VuZENvbG9yIiwibWV0YUVsZW1lbnQiLCJjb250ZW50IiwiaXNTdHlsZVNoZWV0TG9hZGVkIiwiQm9vbGVhbiIsInN0eWxlU2hlZXRzIiwiX3N0eWxlU2hlZXQiLCJocmVmIiwid2FpdEZvclN0eWxlU2hlZXRMb2FkaW5nIiwiY291bnRlciIsImludGVydmFsSWQiLCJzZXRJbnRlcnZhbCIsImNsZWFySW50ZXJ2YWwiLCJvbmxvYWQiLCJvbmVycm9yIiwiZSJdLCJzb3VyY2VzIjpbIi4uL3NyYy90aGVtZS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuQ29weXJpZ2h0IDIwMjQgTmV3IFZlY3RvciBMdGQuXG5Db3B5cmlnaHQgMjAxOSBNaWNoYWVsIFRlbGF0eW5za2kgPDd0M2NoZ3V5QGdtYWlsLmNvbT5cbkNvcHlyaWdodCAyMDE5IFRoZSBNYXRyaXgub3JnIEZvdW5kYXRpb24gQy5JLkMuXG5cblNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBR1BMLTMuMC1vbmx5IE9SIEdQTC0zLjAtb25seVxuUGxlYXNlIHNlZSBMSUNFTlNFIGZpbGVzIGluIHRoZSByZXBvc2l0b3J5IHJvb3QgZm9yIGZ1bGwgZGV0YWlscy5cbiovXG5cbmltcG9ydCB7IGxvZ2dlciB9IGZyb20gXCJtYXRyaXgtanMtc2RrL3NyYy9sb2dnZXJcIjtcblxuaW1wb3J0IHsgX3QgfSBmcm9tIFwiLi9sYW5ndWFnZUhhbmRsZXJcIjtcbmltcG9ydCBTZXR0aW5nc1N0b3JlIGZyb20gXCIuL3NldHRpbmdzL1NldHRpbmdzU3RvcmVcIjtcbmltcG9ydCBUaGVtZVdhdGNoZXIgZnJvbSBcIi4vc2V0dGluZ3Mvd2F0Y2hlcnMvVGhlbWVXYXRjaGVyXCI7XG5cbmV4cG9ydCBjb25zdCBERUZBVUxUX1RIRU1FID0gXCJsaWdodFwiO1xuY29uc3QgSElHSF9DT05UUkFTVF9USEVNRVM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7XG4gICAgbGlnaHQ6IFwibGlnaHQtaGlnaC1jb250cmFzdFwiLFxufTtcblxuaW50ZXJmYWNlIElGb250RmFjZXMgZXh0ZW5kcyBPbWl0PFJlY29yZDwodHlwZW9mIGFsbG93ZWRGb250RmFjZVByb3BzKVtudW1iZXJdLCBzdHJpbmc+LCBcInNyY1wiPiB7XG4gICAgc3JjOiB7XG4gICAgICAgIGZvcm1hdDogc3RyaW5nO1xuICAgICAgICB1cmw6IHN0cmluZztcbiAgICAgICAgbG9jYWw6IHN0cmluZztcbiAgICB9W107XG59XG5cbmludGVyZmFjZSBDb21wb3VuZFRoZW1lIHtcbiAgICBbdG9rZW46IHN0cmluZ106IHN0cmluZztcbn1cblxuZXhwb3J0IHR5cGUgQ3VzdG9tVGhlbWUgPSB7XG4gICAgbmFtZTogc3RyaW5nO1xuICAgIGlzX2Rhcms/OiBib29sZWFuOyAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIGNhbWVsY2FzZVxuICAgIGNvbG9ycz86IHtcbiAgICAgICAgW2tleTogc3RyaW5nXTogc3RyaW5nO1xuICAgIH07XG4gICAgZm9udHM/OiB7XG4gICAgICAgIGZhY2VzOiBJRm9udEZhY2VzW107XG4gICAgICAgIGdlbmVyYWw6IHN0cmluZztcbiAgICAgICAgbW9ub3NwYWNlOiBzdHJpbmc7XG4gICAgfTtcbiAgICBjb21wb3VuZD86IENvbXBvdW5kVGhlbWU7XG59O1xuXG4vKipcbiAqIEdpdmVuIGEgbm9uLWhpZ2gtY29udHJhc3QgdGhlbWUsIGZpbmQgdGhlIGNvcnJlc3BvbmRpbmcgaGlnaC1jb250cmFzdCBvbmVcbiAqIGlmIGl0IGV4aXN0cywgb3IgcmV0dXJuIHVuZGVmaW5lZCBpZiBub3QuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmaW5kSGlnaENvbnRyYXN0VGhlbWUodGhlbWU6IHN0cmluZyk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIEhJR0hfQ09OVFJBU1RfVEhFTUVTW3RoZW1lXTtcbn1cblxuLyoqXG4gKiBHaXZlbiBhIGhpZ2gtY29udHJhc3QgdGhlbWUsIGZpbmQgdGhlIGNvcnJlc3BvbmRpbmcgbm9uLWhpZ2gtY29udHJhc3Qgb25lXG4gKiBpZiBpdCBleGlzdHMsIG9yIHJldHVybiB1bmRlZmluZWQgaWYgbm90LlxuICovXG5leHBvcnQgZnVuY3Rpb24gZmluZE5vbkhpZ2hDb250cmFzdFRoZW1lKGhjVGhlbWU6IHN0cmluZyk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gICAgZm9yIChjb25zdCB0aGVtZSBpbiBISUdIX0NPTlRSQVNUX1RIRU1FUykge1xuICAgICAgICBpZiAoSElHSF9DT05UUkFTVF9USEVNRVNbdGhlbWVdID09PSBoY1RoZW1lKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhlbWU7XG4gICAgICAgIH1cbiAgICB9XG59XG5cbi8qKlxuICogRGVjaWRlIHdoZXRoZXIgdGhlIHN1cHBsaWVkIHRoZW1lIGlzIGhpZ2ggY29udHJhc3QuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc0hpZ2hDb250cmFzdFRoZW1lKHRoZW1lOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICByZXR1cm4gT2JqZWN0LnZhbHVlcyhISUdIX0NPTlRSQVNUX1RIRU1FUykuaW5jbHVkZXModGhlbWUpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZW51bWVyYXRlVGhlbWVzKCk6IHsgW2tleTogc3RyaW5nXTogc3RyaW5nIH0ge1xuICAgIGNvbnN0IEJVSUxUSU5fVEhFTUVTID0ge1xuICAgICAgICBcImxpZ2h0XCI6IF90KFwiY29tbW9ufGxpZ2h0XCIpLFxuICAgICAgICBcImxpZ2h0LWhpZ2gtY29udHJhc3RcIjogX3QoXCJ0aGVtZXxsaWdodF9oaWdoX2NvbnRyYXN0XCIpLFxuICAgICAgICBcImRhcmtcIjogX3QoXCJjb21tb258ZGFya1wiKSxcbiAgICB9O1xuICAgIGNvbnN0IGN1c3RvbVRoZW1lcyA9IFNldHRpbmdzU3RvcmUuZ2V0VmFsdWUoXCJjdXN0b21fdGhlbWVzXCIpIHx8IFtdO1xuICAgIGNvbnN0IGN1c3RvbVRoZW1lTmFtZXM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7fTtcblxuICAgIHRyeSB7XG4gICAgICAgIGZvciAoY29uc3QgeyBuYW1lIH0gb2YgY3VzdG9tVGhlbWVzKSB7XG4gICAgICAgICAgICBjdXN0b21UaGVtZU5hbWVzW2BjdXN0b20tJHtuYW1lfWBdID0gbmFtZTtcbiAgICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICBsb2dnZXIud2FybihcIkVycm9yIGxvYWRpbmcgY3VzdG9tIHRoZW1lc1wiLCB7XG4gICAgICAgICAgICBlcnIsXG4gICAgICAgICAgICBjdXN0b21UaGVtZXMsXG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIHJldHVybiBPYmplY3QuYXNzaWduKHt9LCBjdXN0b21UaGVtZU5hbWVzLCBCVUlMVElOX1RIRU1FUyk7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgSVRoZW1lIHtcbiAgICBpZDogc3RyaW5nO1xuICAgIG5hbWU6IHN0cmluZztcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldE9yZGVyZWRUaGVtZXMoKTogSVRoZW1lW10ge1xuICAgIGNvbnN0IHRoZW1lcyA9IE9iamVjdC5lbnRyaWVzKGVudW1lcmF0ZVRoZW1lcygpKVxuICAgICAgICAubWFwKChwKSA9PiAoeyBpZDogcFswXSwgbmFtZTogcFsxXSB9KSkgLy8gY29udmVydCBwYWlycyB0byBvYmplY3RzIGZvciBjb2RlIHJlYWRhYmlsaXR5XG4gICAgICAgIC5maWx0ZXIoKHApID0+ICFpc0hpZ2hDb250cmFzdFRoZW1lKHAuaWQpKTtcbiAgICBjb25zdCBidWlsdEluVGhlbWVzID0gdGhlbWVzLmZpbHRlcigocCkgPT4gIXAuaWQuc3RhcnRzV2l0aChcImN1c3RvbS1cIikpO1xuICAgIGNvbnN0IGNvbGxhdG9yID0gbmV3IEludGwuQ29sbGF0b3IoKTtcbiAgICBjb25zdCBjdXN0b21UaGVtZXMgPSB0aGVtZXNcbiAgICAgICAgLmZpbHRlcigocCkgPT4gIWJ1aWx0SW5UaGVtZXMuaW5jbHVkZXMocCkpXG4gICAgICAgIC5zb3J0KChhLCBiKSA9PiBjb2xsYXRvci5jb21wYXJlKGEubmFtZSwgYi5uYW1lKSk7XG4gICAgcmV0dXJuIFsuLi5idWlsdEluVGhlbWVzLCAuLi5jdXN0b21UaGVtZXNdO1xufVxuXG5mdW5jdGlvbiBjbGVhckN1c3RvbVRoZW1lKCk6IHZvaWQge1xuICAgIC8vIHJlbW92ZSBhbGwgY3NzIHZhcmlhYmxlcywgd2UgYXNzdW1lIHRoZXNlIGFyZSB0aGVyZSBiZWNhdXNlIG9mIHRoZSBjdXN0b20gdGhlbWVcbiAgICBjb25zdCBpbmxpbmVTdHlsZVByb3BzID0gT2JqZWN0LnZhbHVlcyhkb2N1bWVudC5ib2R5LnN0eWxlKTtcbiAgICBmb3IgKGNvbnN0IHByb3Agb2YgaW5saW5lU3R5bGVQcm9wcykge1xuICAgICAgICBpZiAocHJvcC5zdGFydHNXaXRoKFwiLS1cIikpIHtcbiAgICAgICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUucmVtb3ZlUHJvcGVydHkocHJvcCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvLyByZW1vdmUgdGhlIGN1c3RvbSBzdHlsZSBzaGVldHNcbiAgICBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKFwiaGVhZCA+IHN0eWxlW3RpdGxlPSdjdXN0b20tdGhlbWUtZm9udC1mYWNlcyddXCIpPy5yZW1vdmUoKTtcbiAgICBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKFwiaGVhZCA+IHN0eWxlW3RpdGxlPSdjdXN0b20tdGhlbWUtY29tcG91bmQnXVwiKT8ucmVtb3ZlKCk7XG59XG5cbmNvbnN0IGFsbG93ZWRGb250RmFjZVByb3BzID0gW1xuICAgIFwiZm9udC1kaXNwbGF5XCIsXG4gICAgXCJmb250LWZhbWlseVwiLFxuICAgIFwiZm9udC1zdHJldGNoXCIsXG4gICAgXCJmb250LXN0eWxlXCIsXG4gICAgXCJmb250LXdlaWdodFwiLFxuICAgIFwiZm9udC12YXJpYW50XCIsXG4gICAgXCJmb250LWZlYXR1cmUtc2V0dGluZ3NcIixcbiAgICBcImZvbnQtdmFyaWF0aW9uLXNldHRpbmdzXCIsXG4gICAgXCJzcmNcIixcbiAgICBcInVuaWNvZGUtcmFuZ2VcIixcbl0gYXMgY29uc3Q7XG5cbmZ1bmN0aW9uIGdlbmVyYXRlQ3VzdG9tRm9udEZhY2VDU1MoZmFjZXM6IElGb250RmFjZXNbXSk6IHN0cmluZyB7XG4gICAgcmV0dXJuIGZhY2VzXG4gICAgICAgIC5tYXAoKGZhY2UpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IHNyYyA9IGZhY2Uuc3JjXG4gICAgICAgICAgICAgICAgPy5tYXAoKHNyY0VsZW1lbnQpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgbGV0IGZvcm1hdCA9IFwiXCI7XG4gICAgICAgICAgICAgICAgICAgIGlmIChzcmNFbGVtZW50LmZvcm1hdCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgZm9ybWF0ID0gYGZvcm1hdChcIiR7c3JjRWxlbWVudC5mb3JtYXR9XCIpYDtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBpZiAoc3JjRWxlbWVudC51cmwpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBgdXJsKFwiJHtzcmNFbGVtZW50LnVybH1cIikgJHtmb3JtYXR9YDtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmIChzcmNFbGVtZW50LmxvY2FsKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gYGxvY2FsKFwiJHtzcmNFbGVtZW50LmxvY2FsfVwiKSAke2Zvcm1hdH1gO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBcIlwiO1xuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgLmpvaW4oXCIsIFwiKTtcbiAgICAgICAgICAgIGNvbnN0IHByb3BzID0gT2JqZWN0LmtleXMoZmFjZSkuZmlsdGVyKChwcm9wKSA9PlxuICAgICAgICAgICAgICAgIGFsbG93ZWRGb250RmFjZVByb3BzLmluY2x1ZGVzKHByb3AgYXMgKHR5cGVvZiBhbGxvd2VkRm9udEZhY2VQcm9wcylbbnVtYmVyXSksXG4gICAgICAgICAgICApIGFzIEFycmF5PCh0eXBlb2YgYWxsb3dlZEZvbnRGYWNlUHJvcHMpW251bWJlcl0+O1xuICAgICAgICAgICAgY29uc3QgYm9keSA9IHByb3BzXG4gICAgICAgICAgICAgICAgLm1hcCgocHJvcCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICBsZXQgdmFsdWU6IHN0cmluZztcbiAgICAgICAgICAgICAgICAgICAgaWYgKHByb3AgPT09IFwic3JjXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlID0gc3JjO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHByb3AgPT09IFwiZm9udC1mYW1pbHlcIikge1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSBgXCIke2ZhY2VbcHJvcF19XCJgO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSBmYWNlW3Byb3BdO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBgJHtwcm9wfTogJHt2YWx1ZX1gO1xuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgLmpvaW4oXCI7XCIpO1xuICAgICAgICAgICAgcmV0dXJuIGBAZm9udC1mYWNlIHske2JvZHl9fWA7XG4gICAgICAgIH0pXG4gICAgICAgIC5qb2luKFwiXFxuXCIpO1xufVxuXG5jb25zdCBDT01QT1VORF9UT0tFTiA9IC9eLS1jcGQtW2EtejAtOS1dKyQvO1xuXG4vKipcbiAqIEdlbmVyYXRlcyBhIHN0eWxlIHNoZWV0IHRvIG92ZXJyaWRlIENvbXBvdW5kIGRlc2lnbiB0b2tlbnMgYXMgc3BlY2lmaWVkIGluXG4gKiB0aGUgZ2l2ZW4gdGhlbWUuXG4gKi9cbmZ1bmN0aW9uIGdlbmVyYXRlQ3VzdG9tQ29tcG91bmRDU1ModGhlbWU6IENvbXBvdW5kVGhlbWUpOiBzdHJpbmcge1xuICAgIGNvbnN0IHByb3BlcnRpZXM6IHN0cmluZ1tdID0gW107XG4gICAgZm9yIChjb25zdCBbdG9rZW4sIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyh0aGVtZSkpXG4gICAgICAgIGlmIChDT01QT1VORF9UT0tFTi50ZXN0KHRva2VuKSkgcHJvcGVydGllcy5wdXNoKGAke3Rva2VufTogJHt2YWx1ZX07YCk7XG4gICAgICAgIGVsc2UgbG9nZ2VyLndhcm4oYCcke3Rva2VufScgaXMgbm90IGEgdmFsaWQgQ29tcG91bmQgdG9rZW5gKTtcbiAgICAvLyBJbnNlcnQgdGhlIGRlc2lnbiB0b2tlbiBvdmVycmlkZXMgaW50byB0aGUgJ2N1c3RvbScgY2FzY2FkZSBsYXllciBhc1xuICAgIC8vIGRvY3VtZW50ZWQgYXQgaHR0cHM6Ly9jb21wb3VuZC5lbGVtZW50LmlvLz9wYXRoPS9kb2NzL2RldmVsb3AtdGhlbWluZy0tZG9jc1xuICAgIHJldHVybiBgQGxheWVyIGNvbXBvdW5kLmN1c3RvbSB7IDpyb290LCBbY2xhc3MqPVwiY3BkLXRoZW1lLVwiXSB7ICR7cHJvcGVydGllcy5qb2luKFwiIFwiKX0gfSB9YDtcbn1cblxuZnVuY3Rpb24gc2V0Q3VzdG9tVGhlbWVWYXJzKGN1c3RvbVRoZW1lOiBDdXN0b21UaGVtZSk6IHZvaWQge1xuICAgIGNvbnN0IHsgc3R5bGUgfSA9IGRvY3VtZW50LmJvZHk7XG5cbiAgICBmdW5jdGlvbiBzZXRDU1NDb2xvclZhcmlhYmxlKG5hbWU6IHN0cmluZywgaGV4Q29sb3I6IHN0cmluZywgZG9QY3QgPSB0cnVlKTogdm9pZCB7XG4gICAgICAgIHN0eWxlLnNldFByb3BlcnR5KGAtLSR7bmFtZX1gLCBoZXhDb2xvcik7XG4gICAgICAgIGlmIChkb1BjdCkge1xuICAgICAgICAgICAgLy8gdXNlcyAjcnJnZ2JiYWEgdG8gZGVmaW5lIHRoZSBjb2xvciB3aXRoIGFscGhhIHZhbHVlcyBhdCAwJSwgMTUlIGFuZCA1MCVcbiAgICAgICAgICAgIHN0eWxlLnNldFByb3BlcnR5KGAtLSR7bmFtZX0tMHBjdGAsIGhleENvbG9yICsgXCIwMFwiKTtcbiAgICAgICAgICAgIHN0eWxlLnNldFByb3BlcnR5KGAtLSR7bmFtZX0tMTVwY3RgLCBoZXhDb2xvciArIFwiMjZcIik7XG4gICAgICAgICAgICBzdHlsZS5zZXRQcm9wZXJ0eShgLS0ke25hbWV9LTUwcGN0YCwgaGV4Q29sb3IgKyBcIjdGXCIpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgaWYgKGN1c3RvbVRoZW1lLmNvbG9ycykge1xuICAgICAgICBmb3IgKGNvbnN0IFtuYW1lLCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMoY3VzdG9tVGhlbWUuY29sb3JzKSkge1xuICAgICAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkodmFsdWUpKSB7XG4gICAgICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB2YWx1ZS5sZW5ndGg7IGkgKz0gMSkge1xuICAgICAgICAgICAgICAgICAgICBzZXRDU1NDb2xvclZhcmlhYmxlKGAke25hbWV9XyR7aX1gLCB2YWx1ZVtpXSwgZmFsc2UpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgc2V0Q1NTQ29sb3JWYXJpYWJsZShuYW1lLCB2YWx1ZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG4gICAgaWYgKGN1c3RvbVRoZW1lLmZvbnRzKSB7XG4gICAgICAgIGNvbnN0IHsgZm9udHMgfSA9IGN1c3RvbVRoZW1lO1xuICAgICAgICBpZiAoZm9udHMuZmFjZXMpIHtcbiAgICAgICAgICAgIGNvbnN0IGNzcyA9IGdlbmVyYXRlQ3VzdG9tRm9udEZhY2VDU1MoZm9udHMuZmFjZXMpO1xuICAgICAgICAgICAgY29uc3Qgc3R5bGUgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KFwic3R5bGVcIik7XG4gICAgICAgICAgICBzdHlsZS5zZXRBdHRyaWJ1dGUoXCJ0aXRsZVwiLCBcImN1c3RvbS10aGVtZS1mb250LWZhY2VzXCIpO1xuICAgICAgICAgICAgc3R5bGUuc2V0QXR0cmlidXRlKFwidHlwZVwiLCBcInRleHQvY3NzXCIpO1xuICAgICAgICAgICAgc3R5bGUuYXBwZW5kQ2hpbGQoZG9jdW1lbnQuY3JlYXRlVGV4dE5vZGUoY3NzKSk7XG4gICAgICAgICAgICBkb2N1bWVudC5oZWFkLmFwcGVuZENoaWxkKHN0eWxlKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoZm9udHMuZ2VuZXJhbCkge1xuICAgICAgICAgICAgc3R5bGUuc2V0UHJvcGVydHkoXCItLWZvbnQtZmFtaWx5XCIsIGZvbnRzLmdlbmVyYWwpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChmb250cy5tb25vc3BhY2UpIHtcbiAgICAgICAgICAgIHN0eWxlLnNldFByb3BlcnR5KFwiLS1mb250LWZhbWlseS1tb25vc3BhY2VcIiwgZm9udHMubW9ub3NwYWNlKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBpZiAoY3VzdG9tVGhlbWUuY29tcG91bmQpIHtcbiAgICAgICAgY29uc3QgY3NzID0gZ2VuZXJhdGVDdXN0b21Db21wb3VuZENTUyhjdXN0b21UaGVtZS5jb21wb3VuZCk7XG4gICAgICAgIGNvbnN0IHN0eWxlID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcInN0eWxlXCIpO1xuICAgICAgICBzdHlsZS5zZXRBdHRyaWJ1dGUoXCJ0aXRsZVwiLCBcImN1c3RvbS10aGVtZS1jb21wb3VuZFwiKTtcbiAgICAgICAgc3R5bGUuc2V0QXR0cmlidXRlKFwidHlwZVwiLCBcInRleHQvY3NzXCIpO1xuICAgICAgICBzdHlsZS5hcHBlbmRDaGlsZChkb2N1bWVudC5jcmVhdGVUZXh0Tm9kZShjc3MpKTtcbiAgICAgICAgZG9jdW1lbnQuaGVhZC5hcHBlbmRDaGlsZChzdHlsZSk7XG4gICAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0Q3VzdG9tVGhlbWUodGhlbWVOYW1lOiBzdHJpbmcpOiBDdXN0b21UaGVtZSB7XG4gICAgLy8gc2V0IGNzcyB2YXJpYWJsZXNcbiAgICBjb25zdCBjdXN0b21UaGVtZXMgPSBTZXR0aW5nc1N0b3JlLmdldFZhbHVlKFwiY3VzdG9tX3RoZW1lc1wiKTtcbiAgICBpZiAoIWN1c3RvbVRoZW1lcykge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYE5vIGN1c3RvbSB0aGVtZXMgc2V0LCBjYW4ndCBzZXQgY3VzdG9tIHRoZW1lIFwiJHt0aGVtZU5hbWV9XCJgKTtcbiAgICB9XG4gICAgY29uc3QgY3VzdG9tVGhlbWUgPSBjdXN0b21UaGVtZXMuZmluZCgodDogSVRoZW1lKSA9PiB0Lm5hbWUgPT09IHRoZW1lTmFtZSk7XG4gICAgaWYgKCFjdXN0b21UaGVtZSkge1xuICAgICAgICBjb25zdCBrbm93bk5hbWVzID0gY3VzdG9tVGhlbWVzLm1hcCgodDogSVRoZW1lKSA9PiB0Lm5hbWUpLmpvaW4oXCIsIFwiKTtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBDYW4ndCBmaW5kIGN1c3RvbSB0aGVtZSBcIiR7dGhlbWVOYW1lfVwiLCBvbmx5IGtub3cgJHtrbm93bk5hbWVzfWApO1xuICAgIH1cbiAgICByZXR1cm4gY3VzdG9tVGhlbWU7XG59XG5cbi8qKlxuICogQ2FsbGVkIHdoZW5ldmVyIHNvbWVvbmUgY2hhbmdlcyB0aGUgdGhlbWVcbiAqIEFzeW5jIGZ1bmN0aW9uIHRoYXQgcmV0dXJucyBvbmNlIHRoZSB0aGVtZSBoYXMgYmVlbiBzZXRcbiAqIChpZS4gdGhlIENTUyBoYXMgYmVlbiBsb2FkZWQpXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IHRoZW1lIG5ldyB0aGVtZVxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc2V0VGhlbWUodGhlbWU/OiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAoIXRoZW1lKSB7XG4gICAgICAgIGNvbnN0IHRoZW1lV2F0Y2hlciA9IG5ldyBUaGVtZVdhdGNoZXIoKTtcbiAgICAgICAgdGhlbWUgPSB0aGVtZVdhdGNoZXIuZ2V0RWZmZWN0aXZlVGhlbWUoKTtcbiAgICB9XG4gICAgY2xlYXJDdXN0b21UaGVtZSgpO1xuICAgIGxldCBzdHlsZXNoZWV0TmFtZSA9IHRoZW1lO1xuICAgIGlmICh0aGVtZS5zdGFydHNXaXRoKFwiY3VzdG9tLVwiKSkge1xuICAgICAgICBjb25zdCBjdXN0b21UaGVtZSA9IGdldEN1c3RvbVRoZW1lKHRoZW1lLnNsaWNlKDcpKTtcbiAgICAgICAgc3R5bGVzaGVldE5hbWUgPSBjdXN0b21UaGVtZS5pc19kYXJrID8gXCJkYXJrLWN1c3RvbVwiIDogXCJsaWdodC1jdXN0b21cIjtcbiAgICAgICAgc2V0Q3VzdG9tVGhlbWVWYXJzKGN1c3RvbVRoZW1lKTtcbiAgICB9XG5cbiAgICAvLyBsb29rIGZvciB0aGUgc3R5bGVzaGVldCBlbGVtZW50cy5cbiAgICAvLyBzdHlsZUVsZW1lbnRzIGlzIGEgbWFwIGZyb20gc3R5bGUgbmFtZSB0byBIVE1MTGlua0VsZW1lbnQuXG4gICAgY29uc3Qgc3R5bGVFbGVtZW50cyA9IG5ldyBNYXA8c3RyaW5nLCBIVE1MTGlua0VsZW1lbnQ+KCk7XG4gICAgY29uc3QgdGhlbWVzID0gQXJyYXkuZnJvbShkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsPEhUTUxMaW5rRWxlbWVudD4oXCJbZGF0YS1teC10aGVtZV1cIikpO1xuICAgIHRoZW1lcy5mb3JFYWNoKCh0aGVtZSkgPT4ge1xuICAgICAgICBzdHlsZUVsZW1lbnRzLnNldCh0aGVtZS5kYXRhc2V0Lm14VGhlbWUhLnRvTG93ZXJDYXNlKCksIHRoZW1lKTtcbiAgICB9KTtcblxuICAgIGlmICghc3R5bGVFbGVtZW50cy5oYXMoc3R5bGVzaGVldE5hbWUpKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIlVua25vd24gdGhlbWUgXCIgKyBzdHlsZXNoZWV0TmFtZSk7XG4gICAgfVxuXG4gICAgLy8gZGlzYWJsZSBhbGwgb2YgdGhlbSBmaXJzdCwgdGhlbiBlbmFibGUgdGhlIG9uZSB3ZSB3YW50LiBDaHJvbWUgb25seVxuICAgIC8vIGJvdGhlcnMgdG8gZG8gYW4gdXBkYXRlIG9uIGEgdHJ1ZS0+ZmFsc2UgdHJhbnNpdGlvbiwgc28gdGhpcyBlbnN1cmVzXG4gICAgLy8gdGhhdCB3ZSBnZXQgZXhhY3RseSBvbmUgdXBkYXRlLCBhdCB0aGUgcmlnaHQgdGltZS5cbiAgICAvL1xuICAgIC8vIF4gVGhpcyBjb21tZW50IHdhcyB0cnVlIHdoZW4gd2UgdXNlZCB0byB1c2UgYWx0ZXJuYXRpdmUgc3R5bGVzaGVldHNcbiAgICAvLyBmb3IgdGhlIENTUy4gIE5vd2FkYXlzIHdlIGp1c3Qgc2V0IHRoZW0gYWxsIGFzIGRpc2FibGVkIGluIGluZGV4Lmh0bWxcbiAgICAvLyBhbmQgZW5hYmxlIHRoZW0gYXMgbmVlZGVkLiAgSXQgbWlnaHQgYmUgY2xlYW5lciB0byBkaXNhYmxlIHRoZW0gYWxsXG4gICAgLy8gYXQgdGhlIHNhbWUgdGltZSB0byBwcmV2ZW50IGxvYWRpbmcgdHdvIHRoZW1lcyBzaW11bHRhbmVvdXNseSBhbmRcbiAgICAvLyBoYXZpbmcgdGhlbSBpbnRlcmFjdCBiYWRseS4uLiBidXQgdGhpcyBjYXVzZXMgYSBmbGFzaCBvZiB1bnN0eWxlZCBhcHBcbiAgICAvLyB3aGljaCBpcyBldmVuIHVnbGllci4gIFNvIHdlIGRvbid0LlxuXG4gICAgY29uc3Qgc3R5bGVTaGVldCA9IHN0eWxlRWxlbWVudHMuZ2V0KHN0eWxlc2hlZXROYW1lKSE7XG4gICAgc3R5bGVTaGVldC5kaXNhYmxlZCA9IGZhbHNlO1xuXG4gICAgLyoqXG4gICAgICogQWRkcyB0aGUgQ29tcG91bmQgdGhlbWUgY2xhc3MgdG8gdGhlIHRvcC1tb3N0IGVsZW1lbnQgaW4gdGhlIGRvY3VtZW50XG4gICAgICogVGhpcyB3aWxsIGF1dG9tYXRpY2FsbHkgcmVmcmVzaCB0aGUgY29sb3VyIHNjYWxlcyBiYXNlZCBvbiB0aGUgT1Mgb3IgdXNlclxuICAgICAqIHByZWZlcmVuY2VzXG4gICAgICovXG4gICAgZG9jdW1lbnQuYm9keS5jbGFzc0xpc3QucmVtb3ZlKFwiY3BkLXRoZW1lLWxpZ2h0XCIsIFwiY3BkLXRoZW1lLWRhcmtcIiwgXCJjcGQtdGhlbWUtbGlnaHQtaGNcIiwgXCJjcGQtdGhlbWUtZGFyay1oY1wiKTtcblxuICAgIGxldCBjb21wb3VuZFRoZW1lQ2xhc3NOYW1lID0gYGNwZC10aGVtZS1gICsgKHN0eWxlc2hlZXROYW1lLmluY2x1ZGVzKFwibGlnaHRcIikgPyBcImxpZ2h0XCIgOiBcImRhcmtcIik7XG4gICAgLy8gQWx3YXlzIHJlc3BlY3QgdXNlciBPUyBwcmVmZXJlbmNlIVxuICAgIGlmIChpc0hpZ2hDb250cmFzdFRoZW1lKHRoZW1lKSB8fCB3aW5kb3cubWF0Y2hNZWRpYShcIihwcmVmZXJzLWNvbnRyYXN0OiBtb3JlKVwiKS5tYXRjaGVzKSB7XG4gICAgICAgIGNvbXBvdW5kVGhlbWVDbGFzc05hbWUgKz0gXCItaGNcIjtcbiAgICB9XG5cbiAgICBkb2N1bWVudC5ib2R5LmNsYXNzTGlzdC5hZGQoY29tcG91bmRUaGVtZUNsYXNzTmFtZSk7XG5cbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICBjb25zdCBzd2l0Y2hUaGVtZSA9IGZ1bmN0aW9uICgpOiB2b2lkIHtcbiAgICAgICAgICAgIC8vIHdlIHJlLWVuYWJsZSBvdXIgdGhlbWUgaGVyZSBqdXN0IGluIGNhc2Ugd2UgcmFjZWQgd2l0aCBhbm90aGVyXG4gICAgICAgICAgICAvLyB0aGVtZSBzZXQgcmVxdWVzdCBhcyBwZXIgaHR0cHM6Ly9naXRodWIuY29tL3ZlY3Rvci1pbS9lbGVtZW50LXdlYi9pc3N1ZXMvNTYwMS5cbiAgICAgICAgICAgIC8vIFdlIGNvdWxkIGFsdGVybmF0aXZlbHkgbG9jayBvciBzaW1pbGFyIHRvIHN0b3AgdGhlIHJhY2UsIGJ1dFxuICAgICAgICAgICAgLy8gdGhpcyBpcyBwcm9iYWJseSBnb29kIGVub3VnaCBmb3Igbm93LlxuICAgICAgICAgICAgc3R5bGVTaGVldC5kaXNhYmxlZCA9IGZhbHNlO1xuICAgICAgICAgICAgc3R5bGVFbGVtZW50cy5mb3JFYWNoKChhKSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKGEgPT0gc3R5bGVTaGVldCkgcmV0dXJuO1xuICAgICAgICAgICAgICAgIGEuZGlzYWJsZWQgPSB0cnVlO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBjb25zdCBib2R5U3R5bGVzID0gZ2xvYmFsLmdldENvbXB1dGVkU3R5bGUoZG9jdW1lbnQuYm9keSk7XG4gICAgICAgICAgICBpZiAoYm9keVN0eWxlcy5iYWNrZ3JvdW5kQ29sb3IpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBtZXRhRWxlbWVudCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3I8SFRNTE1ldGFFbGVtZW50PignbWV0YVtuYW1lPVwidGhlbWUtY29sb3JcIl0nKSE7XG4gICAgICAgICAgICAgICAgbWV0YUVsZW1lbnQuY29udGVudCA9IGJvZHlTdHlsZXMuYmFja2dyb3VuZENvbG9yO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmVzb2x2ZSgpO1xuICAgICAgICB9O1xuXG4gICAgICAgIGNvbnN0IGlzU3R5bGVTaGVldExvYWRlZCA9ICgpOiBib29sZWFuID0+XG4gICAgICAgICAgICBCb29sZWFuKFsuLi5kb2N1bWVudC5zdHlsZVNoZWV0c10uZmluZCgoX3N0eWxlU2hlZXQpID0+IF9zdHlsZVNoZWV0Py5ocmVmID09PSBzdHlsZVNoZWV0LmhyZWYpKTtcblxuICAgICAgICBmdW5jdGlvbiB3YWl0Rm9yU3R5bGVTaGVldExvYWRpbmcoKTogdm9pZCB7XG4gICAgICAgICAgICAvLyB0dXJucyBvdXQgdGhhdCBGaXJlZm94IHByZWxvYWRzIHRoZSBDU1MgZm9yIGxpbmsgZWxlbWVudHMgd2l0aFxuICAgICAgICAgICAgLy8gdGhlIGRpc2FibGVkIGF0dHJpYnV0ZSwgYnV0IENocm9tZSBkb2Vzbid0LlxuICAgICAgICAgICAgaWYgKGlzU3R5bGVTaGVldExvYWRlZCgpKSB7XG4gICAgICAgICAgICAgICAgc3dpdGNoVGhlbWUoKTtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGxldCBjb3VudGVyID0gMDtcblxuICAgICAgICAgICAgLy8gSW4gY2FzZSBvZiB0aGVtZSB0b2dnbGluZyAod2hpdGUgPT4gYmxhY2sgPT4gd2hpdGUpXG4gICAgICAgICAgICAvLyBDaHJvbWUgZG9lc24ndCBmaXJlIHRoZSBgbG9hZGAgZXZlbnQgd2hlbiB0aGUgd2hpdGUgdGhlbWUgaXMgc2VsZWN0ZWQgdGhlIHNlY29uZCB0aW1lc1xuICAgICAgICAgICAgY29uc3QgaW50ZXJ2YWxJZCA9IHdpbmRvdy5zZXRJbnRlcnZhbCgoKSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKGlzU3R5bGVTaGVldExvYWRlZCgpKSB7XG4gICAgICAgICAgICAgICAgICAgIGNsZWFySW50ZXJ2YWwoaW50ZXJ2YWxJZCk7XG4gICAgICAgICAgICAgICAgICAgIHN0eWxlU2hlZXQub25sb2FkID0gbnVsbDtcbiAgICAgICAgICAgICAgICAgICAgc3R5bGVTaGVldC5vbmVycm9yID0gbnVsbDtcbiAgICAgICAgICAgICAgICAgICAgc3dpdGNoVGhlbWUoKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAvLyBBdm9pZCB0byBiZSBzdHVjayBpbiBhbiBlbmRsZXNzIGxvb3AgaWYgdGhlcmUgaXMgYW4gaXNzdWUgaW4gdGhlIHN0eWxlc2hlZXQgbG9hZGluZ1xuICAgICAgICAgICAgICAgIGNvdW50ZXIrKztcbiAgICAgICAgICAgICAgICBpZiAoY291bnRlciA9PT0gMTApIHtcbiAgICAgICAgICAgICAgICAgICAgY2xlYXJJbnRlcnZhbChpbnRlcnZhbElkKTtcbiAgICAgICAgICAgICAgICAgICAgcmVqZWN0KCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSwgMjAwKTtcblxuICAgICAgICAgICAgc3R5bGVTaGVldC5vbmxvYWQgPSAoKSA9PiB7XG4gICAgICAgICAgICAgICAgY2xlYXJJbnRlcnZhbChpbnRlcnZhbElkKTtcbiAgICAgICAgICAgICAgICBzd2l0Y2hUaGVtZSgpO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgc3R5bGVTaGVldC5vbmVycm9yID0gKGUpID0+IHtcbiAgICAgICAgICAgICAgICBjbGVhckludGVydmFsKGludGVydmFsSWQpO1xuICAgICAgICAgICAgICAgIHJlamVjdChlKTtcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cblxuICAgICAgICB3YWl0Rm9y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