matrix-react-sdk
Version:
SDK for matrix.org using React
219 lines (202 loc) • 30.4 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.FontWatcher = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _dispatcher = _interopRequireDefault(require("../../dispatcher/dispatcher"));
var _SettingsStore = _interopRequireDefault(require("../SettingsStore"));
var _units = require("../../utils/units");
var _actions = require("../../dispatcher/actions");
var _SettingLevel = require("../SettingLevel");
/*
Copyright 2024 New Vector Ltd.
Copyright 2020-2023 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.
*/
class FontWatcher {
constructor() {
(0, _defineProperty2.default)(this, "dispatcherRef", void 0);
(0, _defineProperty2.default)(this, "onAction", payload => {
if (payload.action === _actions.Action.MigrateBaseFontSize) {
this.migrateBaseFontSize();
} else if (payload.action === _actions.Action.UpdateFontSizeDelta) {
this.setRootFontSize(payload.delta);
} else if (payload.action === _actions.Action.UpdateSystemFont) {
this.setSystemFont(payload);
} else if (payload.action === _actions.Action.OnLoggedOut) {
// Clear font overrides when logging out
this.setRootFontSize(FontWatcher.DEFAULT_DELTA);
this.setSystemFont({
useBundledEmojiFont: false,
useSystemFont: false,
font: ""
});
} else if (payload.action === _actions.Action.OnLoggedIn) {
// Font size can be saved on the account, so grab value when logging in
this.updateFont();
}
});
/**
* Set the root font size of the document
* @param delta {number} the delta to add to the default font size
*/
(0, _defineProperty2.default)(this, "setRootFontSize", async delta => {
// Add the delta to the browser default font size
document.querySelector(":root").style.fontSize = `calc(${FontWatcher.DEFAULT_SIZE} + ${(0, _units.toPx)(delta)})`;
});
(0, _defineProperty2.default)(this, "setSystemFont", ({
useBundledEmojiFont,
useSystemFont,
font
}) => {
if (useSystemFont) {
let fontString = font.split(",").map(font => {
font = font.trim();
if (!font.startsWith('"') && !font.endsWith('"')) {
font = `"${font}"`;
}
return font;
}).join(",");
if (useBundledEmojiFont) {
fontString += ", " + FontWatcher.BUNDLED_EMOJI_FONT;
}
/**
* Overrides the default font family from Compound
* Make sure that fonts with spaces in their names get interpreted properly
*/
document.body.style.setProperty(FontWatcher.FONT_FAMILY_CUSTOM_PROPERTY, fontString);
} else {
document.body.style.removeProperty(FontWatcher.FONT_FAMILY_CUSTOM_PROPERTY);
if (useBundledEmojiFont) {
document.body.style.setProperty(FontWatcher.EMOJI_FONT_FAMILY_CUSTOM_PROPERTY, FontWatcher.BUNDLED_EMOJI_FONT);
} else {
document.body.style.removeProperty(FontWatcher.EMOJI_FONT_FAMILY_CUSTOM_PROPERTY);
}
}
});
this.dispatcherRef = null;
}
async start() {
this.updateFont();
this.dispatcherRef = _dispatcher.default.register(this.onAction);
/**
* baseFontSize is an account level setting which is loaded after the initial
* sync. Hence why we can't do that in the `constructor`
*/
await this.migrateBaseFontSize();
}
/**
* Migrate the base font size from the V1 and V2 version to the V3 version
* @private
*/
async migrateBaseFontSize() {
await this.migrateBaseFontV1toFontSizeDelta();
await this.migrateBaseFontV2toFontSizeDelta();
}
/**
* Migrating from the V1 version of the base font size to the new delta system.
* The delta system is using the default browser font size as a base
* Everything will become slightly larger, and getting rid of the `SIZE_DIFF`
* weirdness for locally persisted values
* @private
*/
async migrateBaseFontV1toFontSizeDelta() {
const legacyBaseFontSize = _SettingsStore.default.getValue("baseFontSize");
// No baseFontV1 found, nothing to migrate
if (!legacyBaseFontSize) return;
console.log("Migrating base font size -> base font size V2 -> font size delta for Compound, current value", legacyBaseFontSize);
// Compute the V1 to V2 version before migrating to fontSizeDelta
const baseFontSizeV2 = this.computeBaseFontSizeV1toV2(legacyBaseFontSize);
// Compute the difference between the V2 and the fontSizeDelta
const delta = this.computeFontSizeDeltaFromV2BaseFontSize(baseFontSizeV2);
await _SettingsStore.default.setValue("fontSizeDelta", null, _SettingLevel.SettingLevel.DEVICE, delta);
await _SettingsStore.default.setValue("baseFontSize", null, _SettingLevel.SettingLevel.DEVICE, 0);
console.log("Migration complete, deleting legacy `baseFontSize`");
}
/**
* Migrating from the V2 version of the base font size to the new delta system
* @private
*/
async migrateBaseFontV2toFontSizeDelta() {
const legacyBaseFontV2Size = _SettingsStore.default.getValue("baseFontSizeV2");
// No baseFontV2 found, nothing to migrate
if (!legacyBaseFontV2Size) return;
console.log("Migrating base font size V2 for Compound, current value", legacyBaseFontV2Size);
// Compute the difference between the V2 and the fontSizeDelta
const delta = this.computeFontSizeDeltaFromV2BaseFontSize(legacyBaseFontV2Size);
await _SettingsStore.default.setValue("fontSizeDelta", null, _SettingLevel.SettingLevel.DEVICE, delta);
await _SettingsStore.default.setValue("baseFontSizeV2", null, _SettingLevel.SettingLevel.DEVICE, 0);
console.log("Migration complete, deleting legacy `baseFontSizeV2`");
}
/**
* Compute the V2 font size from the V1 font size
* @param legacyBaseFontSize
* @private
*/
computeBaseFontSizeV1toV2(legacyBaseFontSize) {
// For some odd reason, the persisted value in user storage has an offset
// of 5 pixels for all values stored under `baseFontSize`
const LEGACY_SIZE_DIFF = 5;
// Compound uses a base font size of `16px`, whereas the old Element
// styles based their calculations off a `15px` root font size.
const ROOT_FONT_SIZE_INCREASE = 1;
// Compute the font size of the V2 version before migrating to V3
return legacyBaseFontSize + ROOT_FONT_SIZE_INCREASE + LEGACY_SIZE_DIFF;
}
/**
* Compute the difference between the V2 font size and the default browser font size
* @param legacyBaseFontV2Size
* @private
*/
computeFontSizeDeltaFromV2BaseFontSize(legacyBaseFontV2Size) {
const browserDefaultFontSize = FontWatcher.getRootFontSize();
// Compute the difference between the V2 font size and the default browser font size
return legacyBaseFontV2Size - browserDefaultFontSize;
}
/**
* Get the root font size of the document
* Fallback to 16px if the value is not found
* @returns {number}
*/
static getRootFontSize() {
return parseInt(window.getComputedStyle(document.documentElement).getPropertyValue("font-size"), 10) || 16;
}
/**
* Get the browser default font size
* @returns {number} the default font size of the browser
*/
static getBrowserDefaultFontSize() {
return this.getRootFontSize() - _SettingsStore.default.getValue("fontSizeDelta");
}
stop() {
if (!this.dispatcherRef) return;
_dispatcher.default.unregister(this.dispatcherRef);
}
updateFont() {
this.setRootFontSize(_SettingsStore.default.getValue("fontSizeDelta"));
this.setSystemFont({
useBundledEmojiFont: _SettingsStore.default.getValue("useBundledEmojiFont"),
useSystemFont: _SettingsStore.default.getValue("useSystemFont"),
font: _SettingsStore.default.getValue("systemFont")
});
}
}
exports.FontWatcher = FontWatcher;
/**
* This Compound value is using `100%` of the default browser font size.
* It allows EW to use the browser's default font size instead of a fixed value.
* All the Compound font size are using `rem`, they are relative to the root font size
* and therefore of the browser font size.
*/
(0, _defineProperty2.default)(FontWatcher, "DEFAULT_SIZE", "var(--cpd-font-size-root)");
/**
* Default delta added to the ${@link DEFAULT_SIZE}
*/
(0, _defineProperty2.default)(FontWatcher, "DEFAULT_DELTA", 0);
(0, _defineProperty2.default)(FontWatcher, "FONT_FAMILY_CUSTOM_PROPERTY", "--cpd-font-family-sans");
(0, _defineProperty2.default)(FontWatcher, "EMOJI_FONT_FAMILY_CUSTOM_PROPERTY", "--emoji-font-family");
(0, _defineProperty2.default)(FontWatcher, "BUNDLED_EMOJI_FONT", "Twemoji");
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfZGlzcGF0Y2hlciIsIl9pbnRlcm9wUmVxdWlyZURlZmF1bHQiLCJyZXF1aXJlIiwiX1NldHRpbmdzU3RvcmUiLCJfdW5pdHMiLCJfYWN0aW9ucyIsIl9TZXR0aW5nTGV2ZWwiLCJGb250V2F0Y2hlciIsImNvbnN0cnVjdG9yIiwiX2RlZmluZVByb3BlcnR5MiIsImRlZmF1bHQiLCJwYXlsb2FkIiwiYWN0aW9uIiwiQWN0aW9uIiwiTWlncmF0ZUJhc2VGb250U2l6ZSIsIm1pZ3JhdGVCYXNlRm9udFNpemUiLCJVcGRhdGVGb250U2l6ZURlbHRhIiwic2V0Um9vdEZvbnRTaXplIiwiZGVsdGEiLCJVcGRhdGVTeXN0ZW1Gb250Iiwic2V0U3lzdGVtRm9udCIsIk9uTG9nZ2VkT3V0IiwiREVGQVVMVF9ERUxUQSIsInVzZUJ1bmRsZWRFbW9qaUZvbnQiLCJ1c2VTeXN0ZW1Gb250IiwiZm9udCIsIk9uTG9nZ2VkSW4iLCJ1cGRhdGVGb250IiwiZG9jdW1lbnQiLCJxdWVyeVNlbGVjdG9yIiwic3R5bGUiLCJmb250U2l6ZSIsIkRFRkFVTFRfU0laRSIsInRvUHgiLCJmb250U3RyaW5nIiwic3BsaXQiLCJtYXAiLCJ0cmltIiwic3RhcnRzV2l0aCIsImVuZHNXaXRoIiwiam9pbiIsIkJVTkRMRURfRU1PSklfRk9OVCIsImJvZHkiLCJzZXRQcm9wZXJ0eSIsIkZPTlRfRkFNSUxZX0NVU1RPTV9QUk9QRVJUWSIsInJlbW92ZVByb3BlcnR5IiwiRU1PSklfRk9OVF9GQU1JTFlfQ1VTVE9NX1BST1BFUlRZIiwiZGlzcGF0Y2hlclJlZiIsInN0YXJ0IiwiZGlzIiwicmVnaXN0ZXIiLCJvbkFjdGlvbiIsIm1pZ3JhdGVCYXNlRm9udFYxdG9Gb250U2l6ZURlbHRhIiwibWlncmF0ZUJhc2VGb250VjJ0b0ZvbnRTaXplRGVsdGEiLCJsZWdhY3lCYXNlRm9udFNpemUiLCJTZXR0aW5nc1N0b3JlIiwiZ2V0VmFsdWUiLCJjb25zb2xlIiwibG9nIiwiYmFzZUZvbnRTaXplVjIiLCJjb21wdXRlQmFzZUZvbnRTaXplVjF0b1YyIiwiY29tcHV0ZUZvbnRTaXplRGVsdGFGcm9tVjJCYXNlRm9udFNpemUiLCJzZXRWYWx1ZSIsIlNldHRpbmdMZXZlbCIsIkRFVklDRSIsImxlZ2FjeUJhc2VGb250VjJTaXplIiwiTEVHQUNZX1NJWkVfRElGRiIsIlJPT1RfRk9OVF9TSVpFX0lOQ1JFQVNFIiwiYnJvd3NlckRlZmF1bHRGb250U2l6ZSIsImdldFJvb3RGb250U2l6ZSIsInBhcnNlSW50Iiwid2luZG93IiwiZ2V0Q29tcHV0ZWRTdHlsZSIsImRvY3VtZW50RWxlbWVudCIsImdldFByb3BlcnR5VmFsdWUiLCJnZXRCcm93c2VyRGVmYXVsdEZvbnRTaXplIiwic3RvcCIsInVucmVnaXN0ZXIiLCJleHBvcnRzIl0sInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3NldHRpbmdzL3dhdGNoZXJzL0ZvbnRXYXRjaGVyLnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qXG5Db3B5cmlnaHQgMjAyNCBOZXcgVmVjdG9yIEx0ZC5cbkNvcHlyaWdodCAyMDIwLTIwMjMgVGhlIE1hdHJpeC5vcmcgRm91bmRhdGlvbiBDLkkuQy5cblxuU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFHUEwtMy4wLW9ubHkgT1IgR1BMLTMuMC1vbmx5XG5QbGVhc2Ugc2VlIExJQ0VOU0UgZmlsZXMgaW4gdGhlIHJlcG9zaXRvcnkgcm9vdCBmb3IgZnVsbCBkZXRhaWxzLlxuKi9cblxuaW1wb3J0IGRpcyBmcm9tIFwiLi4vLi4vZGlzcGF0Y2hlci9kaXNwYXRjaGVyXCI7XG5pbXBvcnQgU2V0dGluZ3NTdG9yZSBmcm9tIFwiLi4vU2V0dGluZ3NTdG9yZVwiO1xuaW1wb3J0IElXYXRjaGVyIGZyb20gXCIuL1dhdGNoZXJcIjtcbmltcG9ydCB7IHRvUHggfSBmcm9tIFwiLi4vLi4vdXRpbHMvdW5pdHNcIjtcbmltcG9ydCB7IEFjdGlvbiB9IGZyb20gXCIuLi8uLi9kaXNwYXRjaGVyL2FjdGlvbnNcIjtcbmltcG9ydCB7IFNldHRpbmdMZXZlbCB9IGZyb20gXCIuLi9TZXR0aW5nTGV2ZWxcIjtcbmltcG9ydCB7IFVwZGF0ZVN5c3RlbUZvbnRQYXlsb2FkIH0gZnJvbSBcIi4uLy4uL2Rpc3BhdGNoZXIvcGF5bG9hZHMvVXBkYXRlU3lzdGVtRm9udFBheWxvYWRcIjtcbmltcG9ydCB7IEFjdGlvblBheWxvYWQgfSBmcm9tIFwiLi4vLi4vZGlzcGF0Y2hlci9wYXlsb2Fkc1wiO1xuXG5leHBvcnQgY2xhc3MgRm9udFdhdGNoZXIgaW1wbGVtZW50cyBJV2F0Y2hlciB7XG4gICAgLyoqXG4gICAgICogVGhpcyBDb21wb3VuZCB2YWx1ZSBpcyB1c2luZyBgMTAwJWAgb2YgdGhlIGRlZmF1bHQgYnJvd3NlciBmb250IHNpemUuXG4gICAgICogSXQgYWxsb3dzIEVXIHRvIHVzZSB0aGUgYnJvd3NlcidzIGRlZmF1bHQgZm9udCBzaXplIGluc3RlYWQgb2YgYSBmaXhlZCB2YWx1ZS5cbiAgICAgKiBBbGwgdGhlIENvbXBvdW5kIGZvbnQgc2l6ZSBhcmUgdXNpbmcgYHJlbWAsIHRoZXkgYXJlIHJlbGF0aXZlIHRvIHRoZSByb290IGZvbnQgc2l6ZVxuICAgICAqIGFuZCB0aGVyZWZvcmUgb2YgdGhlIGJyb3dzZXIgZm9udCBzaXplLlxuICAgICAqL1xuICAgIHByaXZhdGUgc3RhdGljIHJlYWRvbmx5IERFRkFVTFRfU0laRSA9IFwidmFyKC0tY3BkLWZvbnQtc2l6ZS1yb290KVwiO1xuICAgIC8qKlxuICAgICAqIERlZmF1bHQgZGVsdGEgYWRkZWQgdG8gdGhlICR7QGxpbmsgREVGQVVMVF9TSVpFfVxuICAgICAqL1xuICAgIHB1YmxpYyBzdGF0aWMgcmVhZG9ubHkgREVGQVVMVF9ERUxUQSA9IDA7XG5cbiAgICBwcml2YXRlIGRpc3BhdGNoZXJSZWY6IHN0cmluZyB8IG51bGw7XG5cbiAgICBwdWJsaWMgY29uc3RydWN0b3IoKSB7XG4gICAgICAgIHRoaXMuZGlzcGF0Y2hlclJlZiA9IG51bGw7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIHN0YXJ0KCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICB0aGlzLnVwZGF0ZUZvbnQoKTtcbiAgICAgICAgdGhpcy5kaXNwYXRjaGVyUmVmID0gZGlzLnJlZ2lzdGVyKHRoaXMub25BY3Rpb24pO1xuICAgICAgICAvKipcbiAgICAgICAgICogYmFzZUZvbnRTaXplIGlzIGFuIGFjY291bnQgbGV2ZWwgc2V0dGluZyB3aGljaCBpcyBsb2FkZWQgYWZ0ZXIgdGhlIGluaXRpYWxcbiAgICAgICAgICogc3luYy4gSGVuY2Ugd2h5IHdlIGNhbid0IGRvIHRoYXQgaW4gdGhlIGBjb25zdHJ1Y3RvcmBcbiAgICAgICAgICovXG4gICAgICAgIGF3YWl0IHRoaXMubWlncmF0ZUJhc2VGb250U2l6ZSgpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIE1pZ3JhdGUgdGhlIGJhc2UgZm9udCBzaXplIGZyb20gdGhlIFYxIGFuZCBWMiB2ZXJzaW9uIHRvIHRoZSBWMyB2ZXJzaW9uXG4gICAgICogQHByaXZhdGVcbiAgICAgKi9cbiAgICBwcml2YXRlIGFzeW5jIG1pZ3JhdGVCYXNlRm9udFNpemUoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGF3YWl0IHRoaXMubWlncmF0ZUJhc2VGb250VjF0b0ZvbnRTaXplRGVsdGEoKTtcbiAgICAgICAgYXdhaXQgdGhpcy5taWdyYXRlQmFzZUZvbnRWMnRvRm9udFNpemVEZWx0YSgpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIE1pZ3JhdGluZyBmcm9tIHRoZSBWMSB2ZXJzaW9uIG9mIHRoZSBiYXNlIGZvbnQgc2l6ZSB0byB0aGUgbmV3IGRlbHRhIHN5c3RlbS5cbiAgICAgKiBUaGUgZGVsdGEgc3lzdGVtIGlzIHVzaW5nIHRoZSBkZWZhdWx0IGJyb3dzZXIgZm9udCBzaXplIGFzIGEgYmFzZVxuICAgICAqIEV2ZXJ5dGhpbmcgd2lsbCBiZWNvbWUgc2xpZ2h0bHkgbGFyZ2VyLCBhbmQgZ2V0dGluZyByaWQgb2YgdGhlIGBTSVpFX0RJRkZgXG4gICAgICogd2VpcmRuZXNzIGZvciBsb2NhbGx5IHBlcnNpc3RlZCB2YWx1ZXNcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHByaXZhdGUgYXN5bmMgbWlncmF0ZUJhc2VGb250VjF0b0ZvbnRTaXplRGVsdGEoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGNvbnN0IGxlZ2FjeUJhc2VGb250U2l6ZSA9IFNldHRpbmdzU3RvcmUuZ2V0VmFsdWU8bnVtYmVyPihcImJhc2VGb250U2l6ZVwiKTtcbiAgICAgICAgLy8gTm8gYmFzZUZvbnRWMSBmb3VuZCwgbm90aGluZyB0byBtaWdyYXRlXG4gICAgICAgIGlmICghbGVnYWN5QmFzZUZvbnRTaXplKSByZXR1cm47XG5cbiAgICAgICAgY29uc29sZS5sb2coXG4gICAgICAgICAgICBcIk1pZ3JhdGluZyBiYXNlIGZvbnQgc2l6ZSAtPiBiYXNlIGZvbnQgc2l6ZSBWMiAtPiBmb250IHNpemUgZGVsdGEgZm9yIENvbXBvdW5kLCBjdXJyZW50IHZhbHVlXCIsXG4gICAgICAgICAgICBsZWdhY3lCYXNlRm9udFNpemUsXG4gICAgICAgICk7XG5cbiAgICAgICAgLy8gQ29tcHV0ZSB0aGUgVjEgdG8gVjIgdmVyc2lvbiBiZWZvcmUgbWlncmF0aW5nIHRvIGZvbnRTaXplRGVsdGFcbiAgICAgICAgY29uc3QgYmFzZUZvbnRTaXplVjIgPSB0aGlzLmNvbXB1dGVCYXNlRm9udFNpemVWMXRvVjIobGVnYWN5QmFzZUZvbnRTaXplKTtcblxuICAgICAgICAvLyBDb21wdXRlIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIFYyIGFuZCB0aGUgZm9udFNpemVEZWx0YVxuICAgICAgICBjb25zdCBkZWx0YSA9IHRoaXMuY29tcHV0ZUZvbnRTaXplRGVsdGFGcm9tVjJCYXNlRm9udFNpemUoYmFzZUZvbnRTaXplVjIpO1xuXG4gICAgICAgIGF3YWl0IFNldHRpbmdzU3RvcmUuc2V0VmFsdWUoXCJmb250U2l6ZURlbHRhXCIsIG51bGwsIFNldHRpbmdMZXZlbC5ERVZJQ0UsIGRlbHRhKTtcbiAgICAgICAgYXdhaXQgU2V0dGluZ3NTdG9yZS5zZXRWYWx1ZShcImJhc2VGb250U2l6ZVwiLCBudWxsLCBTZXR0aW5nTGV2ZWwuREVWSUNFLCAwKTtcbiAgICAgICAgY29uc29sZS5sb2coXCJNaWdyYXRpb24gY29tcGxldGUsIGRlbGV0aW5nIGxlZ2FjeSBgYmFzZUZvbnRTaXplYFwiKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBNaWdyYXRpbmcgZnJvbSB0aGUgVjIgdmVyc2lvbiBvZiB0aGUgYmFzZSBmb250IHNpemUgdG8gdGhlIG5ldyBkZWx0YSBzeXN0ZW1cbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHByaXZhdGUgYXN5bmMgbWlncmF0ZUJhc2VGb250VjJ0b0ZvbnRTaXplRGVsdGEoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGNvbnN0IGxlZ2FjeUJhc2VGb250VjJTaXplID0gU2V0dGluZ3NTdG9yZS5nZXRWYWx1ZTxudW1iZXI+KFwiYmFzZUZvbnRTaXplVjJcIik7XG4gICAgICAgIC8vIE5vIGJhc2VGb250VjIgZm91bmQsIG5vdGhpbmcgdG8gbWlncmF0ZVxuICAgICAgICBpZiAoIWxlZ2FjeUJhc2VGb250VjJTaXplKSByZXR1cm47XG5cbiAgICAgICAgY29uc29sZS5sb2coXCJNaWdyYXRpbmcgYmFzZSBmb250IHNpemUgVjIgZm9yIENvbXBvdW5kLCBjdXJyZW50IHZhbHVlXCIsIGxlZ2FjeUJhc2VGb250VjJTaXplKTtcblxuICAgICAgICAvLyBDb21wdXRlIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIFYyIGFuZCB0aGUgZm9udFNpemVEZWx0YVxuICAgICAgICBjb25zdCBkZWx0YSA9IHRoaXMuY29tcHV0ZUZvbnRTaXplRGVsdGFGcm9tVjJCYXNlRm9udFNpemUobGVnYWN5QmFzZUZvbnRWMlNpemUpO1xuXG4gICAgICAgIGF3YWl0IFNldHRpbmdzU3RvcmUuc2V0VmFsdWUoXCJmb250U2l6ZURlbHRhXCIsIG51bGwsIFNldHRpbmdMZXZlbC5ERVZJQ0UsIGRlbHRhKTtcbiAgICAgICAgYXdhaXQgU2V0dGluZ3NTdG9yZS5zZXRWYWx1ZShcImJhc2VGb250U2l6ZVYyXCIsIG51bGwsIFNldHRpbmdMZXZlbC5ERVZJQ0UsIDApO1xuICAgICAgICBjb25zb2xlLmxvZyhcIk1pZ3JhdGlvbiBjb21wbGV0ZSwgZGVsZXRpbmcgbGVnYWN5IGBiYXNlRm9udFNpemVWMmBcIik7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ29tcHV0ZSB0aGUgVjIgZm9udCBzaXplIGZyb20gdGhlIFYxIGZvbnQgc2l6ZVxuICAgICAqIEBwYXJhbSBsZWdhY3lCYXNlRm9udFNpemVcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHByaXZhdGUgY29tcHV0ZUJhc2VGb250U2l6ZVYxdG9WMihsZWdhY3lCYXNlRm9udFNpemU6IG51bWJlcik6IG51bWJlciB7XG4gICAgICAgIC8vIEZvciBzb21lIG9kZCByZWFzb24sIHRoZSBwZXJzaXN0ZWQgdmFsdWUgaW4gdXNlciBzdG9yYWdlIGhhcyBhbiBvZmZzZXRcbiAgICAgICAgLy8gb2YgNSBwaXhlbHMgZm9yIGFsbCB2YWx1ZXMgc3RvcmVkIHVuZGVyIGBiYXNlRm9udFNpemVgXG4gICAgICAgIGNvbnN0IExFR0FDWV9TSVpFX0RJRkYgPSA1O1xuXG4gICAgICAgIC8vIENvbXBvdW5kIHVzZXMgYSBiYXNlIGZvbnQgc2l6ZSBvZiBgMTZweGAsIHdoZXJlYXMgdGhlIG9sZCBFbGVtZW50XG4gICAgICAgIC8vIHN0eWxlcyBiYXNlZCB0aGVpciBjYWxjdWxhdGlvbnMgb2ZmIGEgYDE1cHhgIHJvb3QgZm9udCBzaXplLlxuICAgICAgICBjb25zdCBST09UX0ZPTlRfU0laRV9JTkNSRUFTRSA9IDE7XG5cbiAgICAgICAgLy8gQ29tcHV0ZSB0aGUgZm9udCBzaXplIG9mIHRoZSBWMiB2ZXJzaW9uIGJlZm9yZSBtaWdyYXRpbmcgdG8gVjNcbiAgICAgICAgcmV0dXJuIGxlZ2FjeUJhc2VGb250U2l6ZSArIFJPT1RfRk9OVF9TSVpFX0lOQ1JFQVNFICsgTEVHQUNZX1NJWkVfRElGRjtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDb21wdXRlIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIFYyIGZvbnQgc2l6ZSBhbmQgdGhlIGRlZmF1bHQgYnJvd3NlciBmb250IHNpemVcbiAgICAgKiBAcGFyYW0gbGVnYWN5QmFzZUZvbnRWMlNpemVcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHByaXZhdGUgY29tcHV0ZUZvbnRTaXplRGVsdGFGcm9tVjJCYXNlRm9udFNpemUobGVnYWN5QmFzZUZvbnRWMlNpemU6IG51bWJlcik6IG51bWJlciB7XG4gICAgICAgIGNvbnN0IGJyb3dzZXJEZWZhdWx0Rm9udFNpemUgPSBGb250V2F0Y2hlci5nZXRSb290Rm9udFNpemUoKTtcblxuICAgICAgICAvLyBDb21wdXRlIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIFYyIGZvbnQgc2l6ZSBhbmQgdGhlIGRlZmF1bHQgYnJvd3NlciBmb250IHNpemVcbiAgICAgICAgcmV0dXJuIGxlZ2FjeUJhc2VGb250VjJTaXplIC0gYnJvd3NlckRlZmF1bHRGb250U2l6ZTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBHZXQgdGhlIHJvb3QgZm9udCBzaXplIG9mIHRoZSBkb2N1bWVudFxuICAgICAqIEZhbGxiYWNrIHRvIDE2cHggaWYgdGhlIHZhbHVlIGlzIG5vdCBmb3VuZFxuICAgICAqIEByZXR1cm5zIHtudW1iZXJ9XG4gICAgICovXG4gICAgcHVibGljIHN0YXRpYyBnZXRSb290Rm9udFNpemUoKTogbnVtYmVyIHtcbiAgICAgICAgcmV0dXJuIHBhcnNlSW50KHdpbmRvdy5nZXRDb21wdXRlZFN0eWxlKGRvY3VtZW50LmRvY3VtZW50RWxlbWVudCkuZ2V0UHJvcGVydHlWYWx1ZShcImZvbnQtc2l6ZVwiKSwgMTApIHx8IDE2O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdldCB0aGUgYnJvd3NlciBkZWZhdWx0IGZvbnQgc2l6ZVxuICAgICAqIEByZXR1cm5zIHtudW1iZXJ9IHRoZSBkZWZhdWx0IGZvbnQgc2l6ZSBvZiB0aGUgYnJvd3NlclxuICAgICAqL1xuICAgIHB1YmxpYyBzdGF0aWMgZ2V0QnJvd3NlckRlZmF1bHRGb250U2l6ZSgpOiBudW1iZXIge1xuICAgICAgICByZXR1cm4gdGhpcy5nZXRSb290Rm9udFNpemUoKSAtIFNldHRpbmdzU3RvcmUuZ2V0VmFsdWU8bnVtYmVyPihcImZvbnRTaXplRGVsdGFcIik7XG4gICAgfVxuXG4gICAgcHVibGljIHN0b3AoKTogdm9pZCB7XG4gICAgICAgIGlmICghdGhpcy5kaXNwYXRjaGVyUmVmKSByZXR1cm47XG4gICAgICAgIGRpcy51bnJlZ2lzdGVyKHRoaXMuZGlzcGF0Y2hlclJlZik7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSB1cGRhdGVGb250KCk6IHZvaWQge1xuICAgICAgICB0aGlzLnNldFJvb3RGb250U2l6ZShTZXR0aW5nc1N0b3JlLmdldFZhbHVlPG51bWJlcj4oXCJmb250U2l6ZURlbHRhXCIpKTtcbiAgICAgICAgdGhpcy5zZXRTeXN0ZW1Gb250KHtcbiAgICAgICAgICAgIHVzZUJ1bmRsZWRFbW9qaUZvbnQ6IFNldHRpbmdzU3RvcmUuZ2V0VmFsdWUoXCJ1c2VCdW5kbGVkRW1vamlGb250XCIpLFxuICAgICAgICAgICAgdXNlU3lzdGVtRm9udDogU2V0dGluZ3NTdG9yZS5nZXRWYWx1ZShcInVzZVN5c3RlbUZvbnRcIiksXG4gICAgICAgICAgICBmb250OiBTZXR0aW5nc1N0b3JlLmdldFZhbHVlKFwic3lzdGVtRm9udFwiKSxcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBvbkFjdGlvbiA9IChwYXlsb2FkOiBBY3Rpb25QYXlsb2FkKTogdm9pZCA9PiB7XG4gICAgICAgIGlmIChwYXlsb2FkLmFjdGlvbiA9PT0gQWN0aW9uLk1pZ3JhdGVCYXNlRm9udFNpemUpIHtcbiAgICAgICAgICAgIHRoaXMubWlncmF0ZUJhc2VGb250U2l6ZSgpO1xuICAgICAgICB9IGVsc2UgaWYgKHBheWxvYWQuYWN0aW9uID09PSBBY3Rpb24uVXBkYXRlRm9udFNpemVEZWx0YSkge1xuICAgICAgICAgICAgdGhpcy5zZXRSb290Rm9udFNpemUocGF5bG9hZC5kZWx0YSk7XG4gICAgICAgIH0gZWxzZSBpZiAocGF5bG9hZC5hY3Rpb24gPT09IEFjdGlvbi5VcGRhdGVTeXN0ZW1Gb250KSB7XG4gICAgICAgICAgICB0aGlzLnNldFN5c3RlbUZvbnQocGF5bG9hZCBhcyBVcGRhdGVTeXN0ZW1Gb250UGF5bG9hZCk7XG4gICAgICAgIH0gZWxzZSBpZiAocGF5bG9hZC5hY3Rpb24gPT09IEFjdGlvbi5PbkxvZ2dlZE91dCkge1xuICAgICAgICAgICAgLy8gQ2xlYXIgZm9udCBvdmVycmlkZXMgd2hlbiBsb2dnaW5nIG91dFxuICAgICAgICAgICAgdGhpcy5zZXRSb290Rm9udFNpemUoRm9udFdhdGNoZXIuREVGQVVMVF9ERUxUQSk7XG4gICAgICAgICAgICB0aGlzLnNldFN5c3RlbUZvbnQoe1xuICAgICAgICAgICAgICAgIHVzZUJ1bmRsZWRFbW9qaUZvbnQ6IGZhbHNlLFxuICAgICAgICAgICAgICAgIHVzZVN5c3RlbUZvbnQ6IGZhbHNlLFxuICAgICAgICAgICAgICAgIGZvbnQ6IFwiXCIsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIGlmIChwYXlsb2FkLmFjdGlvbiA9PT0gQWN0aW9uLk9uTG9nZ2VkSW4pIHtcbiAgICAgICAgICAgIC8vIEZvbnQgc2l6ZSBjYW4gYmUgc2F2ZWQgb24gdGhlIGFjY291bnQsIHNvIGdyYWIgdmFsdWUgd2hlbiBsb2dnaW5nIGluXG4gICAgICAgICAgICB0aGlzLnVwZGF0ZUZvbnQoKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBTZXQgdGhlIHJvb3QgZm9udCBzaXplIG9mIHRoZSBkb2N1bWVudFxuICAgICAqIEBwYXJhbSBkZWx0YSB7bnVtYmVyfSB0aGUgZGVsdGEgdG8gYWRkIHRvIHRoZSBkZWZhdWx0IGZvbnQgc2l6ZVxuICAgICAqL1xuICAgIHByaXZhdGUgc2V0Um9vdEZvbnRTaXplID0gYXN5bmMgKGRlbHRhOiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+ID0+IHtcbiAgICAgICAgLy8gQWRkIHRoZSBkZWx0YSB0byB0aGUgYnJvd3NlciBkZWZhdWx0IGZvbnQgc2l6ZVxuICAgICAgICBkb2N1bWVudC5xdWVyeVNlbGVjdG9yPEhUTUxFbGVtZW50PihcIjpyb290XCIpIS5zdHlsZS5mb250U2l6ZSA9XG4gICAgICAgICAgICBgY2FsYygke0ZvbnRXYXRjaGVyLkRFRkFVTFRfU0laRX0gKyAke3RvUHgoZGVsdGEpfSlgO1xuICAgIH07XG5cbiAgICBwdWJsaWMgc3RhdGljIHJlYWRvbmx5IEZPTlRfRkFNSUxZX0NVU1RPTV9QUk9QRVJUWSA9IFwiLS1jcGQtZm9udC1mYW1pbHktc2Fuc1wiO1xuICAgIHB1YmxpYyBzdGF0aWMgcmVhZG9ubHkgRU1PSklfRk9OVF9GQU1JTFlfQ1VTVE9NX1BST1BFUlRZID0gXCItLWVtb2ppLWZvbnQtZmFtaWx5XCI7XG4gICAgcHVibGljIHN0YXRpYyByZWFkb25seSBCVU5ETEVEX0VNT0pJX0ZPTlQgPSBcIlR3ZW1vamlcIjtcblxuICAgIHByaXZhdGUgc2V0U3lzdGVtRm9udCA9ICh7XG4gICAgICAgIHVzZUJ1bmRsZWRFbW9qaUZvbnQsXG4gICAgICAgIHVzZVN5c3RlbUZvbnQsXG4gICAgICAgIGZvbnQsXG4gICAgfTogUGljazxVcGRhdGVTeXN0ZW1Gb250UGF5bG9hZCwgXCJ1c2VCdW5kbGVkRW1vamlGb250XCIgfCBcInVzZVN5c3RlbUZvbnRcIiB8IFwiZm9udFwiPik6IHZvaWQgPT4ge1xuICAgICAgICBpZiAodXNlU3lzdGVtRm9udCkge1xuICAgICAgICAgICAgbGV0IGZvbnRTdHJpbmcgPSBmb250XG4gICAgICAgICAgICAgICAgLnNwbGl0KFwiLFwiKVxuICAgICAgICAgICAgICAgIC5tYXAoKGZvbnQpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgZm9udCA9IGZvbnQudHJpbSgpO1xuICAgICAgICAgICAgICAgICAgICBpZiAoIWZvbnQuc3RhcnRzV2l0aCgnXCInKSAmJiAhZm9udC5lbmRzV2l0aCgnXCInKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgZm9udCA9IGBcIiR7Zm9udH1cImA7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZvbnQ7XG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAuam9pbihcIixcIik7XG5cbiAgICAgICAgICAgIGlmICh1c2VCdW5kbGVkRW1vamlGb250KSB7XG4gICAgICAgICAgICAgICAgZm9udFN0cmluZyArPSBcIiwgXCIgKyBGb250V2F0Y2hlci5CVU5ETEVEX0VNT0pJX0ZPTlQ7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8qKlxuICAgICAgICAgICAgICogT3ZlcnJpZGVzIHRoZSBkZWZhdWx0IGZvbnQgZmFtaWx5IGZyb20gQ29tcG91bmRcbiAgICAgICAgICAgICAqIE1ha2Ugc3VyZSB0aGF0IGZvbnRzIHdpdGggc3BhY2VzIGluIHRoZWlyIG5hbWVzIGdldCBpbnRlcnByZXRlZCBwcm9wZXJseVxuICAgICAgICAgICAgICovXG4gICAgICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLnNldFByb3BlcnR5KEZvbnRXYXRjaGVyLkZPTlRfRkFNSUxZX0NVU1RPTV9QUk9QRVJUWSwgZm9udFN0cmluZyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLnJlbW92ZVByb3BlcnR5KEZvbnRXYXRjaGVyLkZPTlRfRkFNSUxZX0NVU1RPTV9QUk9QRVJUWSk7XG5cbiAgICAgICAgICAgIGlmICh1c2VCdW5kbGVkRW1vamlGb250KSB7XG4gICAgICAgICAgICAgICAgZG9jdW1lbnQuYm9keS5zdHlsZS5zZXRQcm9wZXJ0eShcbiAgICAgICAgICAgICAgICAgICAgRm9udFdhdGNoZXIuRU1PSklfRk9OVF9GQU1JTFlfQ1VTVE9NX1BST1BFUlRZLFxuICAgICAgICAgICAgICAgICAgICBGb250V2F0Y2hlci5CVU5ETEVEX0VNT0pJX0ZPTlQsXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgZG9jdW1lbnQuYm9keS5zdHlsZS5yZW1vdmVQcm9wZXJ0eShGb250V2F0Y2hlci5FTU9KSV9GT05UX0ZBTUlMWV9DVVNUT01fUFJPUEVSVFkpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfTtcbn1cbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7QUFRQSxJQUFBQSxXQUFBLEdBQUFDLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBQyxjQUFBLEdBQUFGLHNCQUFBLENBQUFDLE9BQUE7QUFFQSxJQUFBRSxNQUFBLEdBQUFGLE9BQUE7QUFDQSxJQUFBRyxRQUFBLEdBQUFILE9BQUE7QUFDQSxJQUFBSSxhQUFBLEdBQUFKLE9BQUE7QUFiQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFXTyxNQUFNSyxXQUFXLENBQXFCO0VBZWxDQyxXQUFXQSxDQUFBLEVBQUc7SUFBQSxJQUFBQyxnQkFBQSxDQUFBQyxPQUFBO0lBQUEsSUFBQUQsZ0JBQUEsQ0FBQUMsT0FBQSxvQkFtSURDLE9BQXNCLElBQVc7TUFDakQsSUFBSUEsT0FBTyxDQUFDQyxNQUFNLEtBQUtDLGVBQU0sQ0FBQ0MsbUJBQW1CLEVBQUU7UUFDL0MsSUFBSSxDQUFDQyxtQkFBbUIsQ0FBQyxDQUFDO01BQzlCLENBQUMsTUFBTSxJQUFJSixPQUFPLENBQUNDLE1BQU0sS0FBS0MsZUFBTSxDQUFDRyxtQkFBbUIsRUFBRTtRQUN0RCxJQUFJLENBQUNDLGVBQWUsQ0FBQ04sT0FBTyxDQUFDTyxLQUFLLENBQUM7TUFDdkMsQ0FBQyxNQUFNLElBQUlQLE9BQU8sQ0FBQ0MsTUFBTSxLQUFLQyxlQUFNLENBQUNNLGdCQUFnQixFQUFFO1FBQ25E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