matrix-react-sdk
Version:
SDK for matrix.org using React
153 lines (144 loc) • 18.3 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "PerformanceEntryNames", {
enumerable: true,
get: function () {
return _entryNames.PerformanceEntryNames;
}
});
exports.default = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _logger = require("matrix-js-sdk/src/logger");
var _entryNames = require("./entry-names");
/*
Copyright 2024 New Vector Ltd.
Copyright 2021 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 PerformanceMonitor {
constructor() {
(0, _defineProperty2.default)(this, "START_PREFIX", "start:");
(0, _defineProperty2.default)(this, "STOP_PREFIX", "stop:");
(0, _defineProperty2.default)(this, "listeners", []);
(0, _defineProperty2.default)(this, "entries", []);
}
static get instance() {
if (!PerformanceMonitor._instance) {
PerformanceMonitor._instance = new PerformanceMonitor();
}
return PerformanceMonitor._instance;
}
/**
* Starts a performance recording
* @param name Name of the recording
* @param id Specify an identifier appended to the measurement name
* @returns {void}
*/
start(name, id) {
if (!this.supportsPerformanceApi()) {
return;
}
const key = this.buildKey(name, id);
if (performance.getEntriesByName(this.START_PREFIX + key).length > 0) {
_logger.logger.warn(`Recording already started for: ${name}`);
return;
}
performance.mark(this.START_PREFIX + key);
}
/**
* Stops a performance recording and stores delta duration
* with the start marker
* @param name Name of the recording
* @param id Specify an identifier appended to the measurement name
* @returns The measurement
*/
stop(name, id) {
if (!this.supportsPerformanceApi()) {
return;
}
const key = this.buildKey(name, id);
if (performance.getEntriesByName(this.START_PREFIX + key).length === 0) {
_logger.logger.warn(`No recording started for: ${name}`);
return;
}
performance.mark(this.STOP_PREFIX + key);
performance.measure(key, this.START_PREFIX + key, this.STOP_PREFIX + key);
this.clear(name, id);
const measurement = performance.getEntriesByName(key).pop();
// Keeping a reference to all PerformanceEntry created
// by this abstraction for historical events collection
// when adding a data callback
this.entries.push(measurement);
this.listeners.forEach(listener => {
if (this.shouldEmit(listener, measurement)) {
listener.callback([measurement]);
}
});
return measurement;
}
clear(name, id) {
if (!this.supportsPerformanceApi()) {
return;
}
const key = this.buildKey(name, id);
performance.clearMarks(this.START_PREFIX + key);
performance.clearMarks(this.STOP_PREFIX + key);
}
getEntries({
name,
type
} = {}) {
return this.entries.filter(entry => {
const satisfiesName = !name || entry.name === name;
const satisfiedType = !type || entry.entryType === type;
return satisfiesName && satisfiedType;
});
}
addPerformanceDataCallback(listener, buffer = false) {
this.listeners.push(listener);
if (buffer) {
const toEmit = this.entries.filter(entry => this.shouldEmit(listener, entry));
if (toEmit.length > 0) {
listener.callback(toEmit);
}
}
}
removePerformanceDataCallback(callback) {
if (!callback) {
this.listeners = [];
} else {
this.listeners.splice(this.listeners.findIndex(listener => listener.callback === callback), 1);
}
}
/**
* Tor browser does not support the Performance API
* @returns {boolean} true if the Performance API is supported
*/
supportsPerformanceApi() {
return performance !== undefined && performance.mark !== undefined;
}
shouldEmit(listener, entry) {
return !listener.entryNames || listener.entryNames.includes(entry.name);
}
/**
* Internal utility to ensure consistent name for the recording
* @param name Name of the recording
* @param id Specify an identifier appended to the measurement name
* @returns {string} a compound of the name and identifier if present
*/
buildKey(name, id) {
const suffix = id ? `:${id}` : "";
return `${name}${suffix}`;
}
}
// Convenience exports
exports.default = PerformanceMonitor;
(0, _defineProperty2.default)(PerformanceMonitor, "_instance", void 0);
// Exposing those to the window object to bridge them from tests
window.mxPerformanceMonitor = PerformanceMonitor.instance;
window.mxPerformanceEntryNames = _entryNames.PerformanceEntryNames;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfbG9nZ2VyIiwicmVxdWlyZSIsIl9lbnRyeU5hbWVzIiwiUGVyZm9ybWFuY2VNb25pdG9yIiwiY29uc3RydWN0b3IiLCJfZGVmaW5lUHJvcGVydHkyIiwiZGVmYXVsdCIsImluc3RhbmNlIiwiX2luc3RhbmNlIiwic3RhcnQiLCJuYW1lIiwiaWQiLCJzdXBwb3J0c1BlcmZvcm1hbmNlQXBpIiwia2V5IiwiYnVpbGRLZXkiLCJwZXJmb3JtYW5jZSIsImdldEVudHJpZXNCeU5hbWUiLCJTVEFSVF9QUkVGSVgiLCJsZW5ndGgiLCJsb2dnZXIiLCJ3YXJuIiwibWFyayIsInN0b3AiLCJTVE9QX1BSRUZJWCIsIm1lYXN1cmUiLCJjbGVhciIsIm1lYXN1cmVtZW50IiwicG9wIiwiZW50cmllcyIsInB1c2giLCJsaXN0ZW5lcnMiLCJmb3JFYWNoIiwibGlzdGVuZXIiLCJzaG91bGRFbWl0IiwiY2FsbGJhY2siLCJjbGVhck1hcmtzIiwiZ2V0RW50cmllcyIsInR5cGUiLCJmaWx0ZXIiLCJlbnRyeSIsInNhdGlzZmllc05hbWUiLCJzYXRpc2ZpZWRUeXBlIiwiZW50cnlUeXBlIiwiYWRkUGVyZm9ybWFuY2VEYXRhQ2FsbGJhY2siLCJidWZmZXIiLCJ0b0VtaXQiLCJyZW1vdmVQZXJmb3JtYW5jZURhdGFDYWxsYmFjayIsInNwbGljZSIsImZpbmRJbmRleCIsInVuZGVmaW5lZCIsImVudHJ5TmFtZXMiLCJpbmNsdWRlcyIsInN1ZmZpeCIsImV4cG9ydHMiLCJ3aW5kb3ciLCJteFBlcmZvcm1hbmNlTW9uaXRvciIsIm14UGVyZm9ybWFuY2VFbnRyeU5hbWVzIiwiUGVyZm9ybWFuY2VFbnRyeU5hbWVzIl0sInNvdXJjZXMiOlsiLi4vLi4vc3JjL3BlcmZvcm1hbmNlL2luZGV4LnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qXG5Db3B5cmlnaHQgMjAyNCBOZXcgVmVjdG9yIEx0ZC5cbkNvcHlyaWdodCAyMDIxIFRoZSBNYXRyaXgub3JnIEZvdW5kYXRpb24gQy5JLkMuXG5cblNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBR1BMLTMuMC1vbmx5IE9SIEdQTC0zLjAtb25seVxuUGxlYXNlIHNlZSBMSUNFTlNFIGZpbGVzIGluIHRoZSByZXBvc2l0b3J5IHJvb3QgZm9yIGZ1bGwgZGV0YWlscy5cbiovXG5cbmltcG9ydCB7IGxvZ2dlciB9IGZyb20gXCJtYXRyaXgtanMtc2RrL3NyYy9sb2dnZXJcIjtcblxuaW1wb3J0IHsgUGVyZm9ybWFuY2VFbnRyeU5hbWVzIH0gZnJvbSBcIi4vZW50cnktbmFtZXNcIjtcblxuaW50ZXJmYWNlIEdldEVudHJpZXNPcHRpb25zIHtcbiAgICBuYW1lPzogc3RyaW5nO1xuICAgIHR5cGU/OiBzdHJpbmc7XG59XG5cbnR5cGUgUGVyZm9ybWFuY2VDYWxsYmFja0Z1bmN0aW9uID0gKGVudHJ5OiBQZXJmb3JtYW5jZUVudHJ5W10pID0+IHZvaWQ7XG5cbmludGVyZmFjZSBQZXJmb3JtYW5jZURhdGFMaXN0ZW5lciB7XG4gICAgZW50cnlOYW1lcz86IHN0cmluZ1tdO1xuICAgIGNhbGxiYWNrOiBQZXJmb3JtYW5jZUNhbGxiYWNrRnVuY3Rpb247XG59XG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIFBlcmZvcm1hbmNlTW9uaXRvciB7XG4gICAgcHJpdmF0ZSBzdGF0aWMgX2luc3RhbmNlOiBQZXJmb3JtYW5jZU1vbml0b3I7XG5cbiAgICBwcml2YXRlIFNUQVJUX1BSRUZJWCA9IFwic3RhcnQ6XCI7XG4gICAgcHJpdmF0ZSBTVE9QX1BSRUZJWCA9IFwic3RvcDpcIjtcblxuICAgIHByaXZhdGUgbGlzdGVuZXJzOiBQZXJmb3JtYW5jZURhdGFMaXN0ZW5lcltdID0gW107XG4gICAgcHJpdmF0ZSBlbnRyaWVzOiBQZXJmb3JtYW5jZUVudHJ5W10gPSBbXTtcblxuICAgIHB1YmxpYyBzdGF0aWMgZ2V0IGluc3RhbmNlKCk6IFBlcmZvcm1hbmNlTW9uaXRvciB7XG4gICAgICAgIGlmICghUGVyZm9ybWFuY2VNb25pdG9yLl9pbnN0YW5jZSkge1xuICAgICAgICAgICAgUGVyZm9ybWFuY2VNb25pdG9yLl9pbnN0YW5jZSA9IG5ldyBQZXJmb3JtYW5jZU1vbml0b3IoKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gUGVyZm9ybWFuY2VNb25pdG9yLl9pbnN0YW5jZTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTdGFydHMgYSBwZXJmb3JtYW5jZSByZWNvcmRpbmdcbiAgICAgKiBAcGFyYW0gbmFtZSBOYW1lIG9mIHRoZSByZWNvcmRpbmdcbiAgICAgKiBAcGFyYW0gaWQgU3BlY2lmeSBhbiBpZGVudGlmaWVyIGFwcGVuZGVkIHRvIHRoZSBtZWFzdXJlbWVudCBuYW1lXG4gICAgICogQHJldHVybnMge3ZvaWR9XG4gICAgICovXG4gICAgcHVibGljIHN0YXJ0KG5hbWU6IHN0cmluZywgaWQ/OiBzdHJpbmcpOiB2b2lkIHtcbiAgICAgICAgaWYgKCF0aGlzLnN1cHBvcnRzUGVyZm9ybWFuY2VBcGkoKSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGtleSA9IHRoaXMuYnVpbGRLZXkobmFtZSwgaWQpO1xuXG4gICAgICAgIGlmIChwZXJmb3JtYW5jZS5nZXRFbnRyaWVzQnlOYW1lKHRoaXMuU1RBUlRfUFJFRklYICsga2V5KS5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICBsb2dnZXIud2FybihgUmVjb3JkaW5nIGFscmVhZHkgc3RhcnRlZCBmb3I6ICR7bmFtZX1gKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHBlcmZvcm1hbmNlLm1hcmsodGhpcy5TVEFSVF9QUkVGSVggKyBrZXkpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFN0b3BzIGEgcGVyZm9ybWFuY2UgcmVjb3JkaW5nIGFuZCBzdG9yZXMgZGVsdGEgZHVyYXRpb25cbiAgICAgKiB3aXRoIHRoZSBzdGFydCBtYXJrZXJcbiAgICAgKiBAcGFyYW0gbmFtZSBOYW1lIG9mIHRoZSByZWNvcmRpbmdcbiAgICAgKiBAcGFyYW0gaWQgU3BlY2lmeSBhbiBpZGVudGlmaWVyIGFwcGVuZGVkIHRvIHRoZSBtZWFzdXJlbWVudCBuYW1lXG4gICAgICogQHJldHVybnMgVGhlIG1lYXN1cmVtZW50XG4gICAgICovXG4gICAgcHVibGljIHN0b3AobmFtZTogc3RyaW5nLCBpZD86IHN0cmluZyk6IFBlcmZvcm1hbmNlRW50cnkgfCB1bmRlZmluZWQge1xuICAgICAgICBpZiAoIXRoaXMuc3VwcG9ydHNQZXJmb3JtYW5jZUFwaSgpKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgY29uc3Qga2V5ID0gdGhpcy5idWlsZEtleShuYW1lLCBpZCk7XG4gICAgICAgIGlmIChwZXJmb3JtYW5jZS5nZXRFbnRyaWVzQnlOYW1lKHRoaXMuU1RBUlRfUFJFRklYICsga2V5KS5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgIGxvZ2dlci53YXJuKGBObyByZWNvcmRpbmcgc3RhcnRlZCBmb3I6ICR7bmFtZX1gKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHBlcmZvcm1hbmNlLm1hcmsodGhpcy5TVE9QX1BSRUZJWCArIGtleSk7XG4gICAgICAgIHBlcmZvcm1hbmNlLm1lYXN1cmUoa2V5LCB0aGlzLlNUQVJUX1BSRUZJWCArIGtleSwgdGhpcy5TVE9QX1BSRUZJWCArIGtleSk7XG5cbiAgICAgICAgdGhpcy5jbGVhcihuYW1lLCBpZCk7XG5cbiAgICAgICAgY29uc3QgbWVhc3VyZW1lbnQgPSBwZXJmb3JtYW5jZS5nZXRFbnRyaWVzQnlOYW1lKGtleSkucG9wKCkhO1xuXG4gICAgICAgIC8vIEtlZXBpbmcgYSByZWZlcmVuY2UgdG8gYWxsIFBlcmZvcm1hbmNlRW50cnkgY3JlYXRlZFxuICAgICAgICAvLyBieSB0aGlzIGFic3RyYWN0aW9uIGZvciBoaXN0b3JpY2FsIGV2ZW50cyBjb2xsZWN0aW9uXG4gICAgICAgIC8vIHdoZW4gYWRkaW5nIGEgZGF0YSBjYWxsYmFja1xuICAgICAgICB0aGlzLmVudHJpZXMucHVzaChtZWFzdXJlbWVudCk7XG5cbiAgICAgICAgdGhpcy5saXN0ZW5lcnMuZm9yRWFjaCgobGlzdGVuZXIpID0+IHtcbiAgICAgICAgICAgIGlmICh0aGlzLnNob3VsZEVtaXQobGlzdGVuZXIsIG1lYXN1cmVtZW50KSkge1xuICAgICAgICAgICAgICAgIGxpc3RlbmVyLmNhbGxiYWNrKFttZWFzdXJlbWVudF0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcblxuICAgICAgICByZXR1cm4gbWVhc3VyZW1lbnQ7XG4gICAgfVxuXG4gICAgcHVibGljIGNsZWFyKG5hbWU6IHN0cmluZywgaWQ/OiBzdHJpbmcpOiB2b2lkIHtcbiAgICAgICAgaWYgKCF0aGlzLnN1cHBvcnRzUGVyZm9ybWFuY2VBcGkoKSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGtleSA9IHRoaXMuYnVpbGRLZXkobmFtZSwgaWQpO1xuICAgICAgICBwZXJmb3JtYW5jZS5jbGVhck1hcmtzKHRoaXMuU1RBUlRfUFJFRklYICsga2V5KTtcbiAgICAgICAgcGVyZm9ybWFuY2UuY2xlYXJNYXJrcyh0aGlzLlNUT1BfUFJFRklYICsga2V5KTtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0RW50cmllcyh7IG5hbWUsIHR5cGUgfTogR2V0RW50cmllc09wdGlvbnMgPSB7fSk6IFBlcmZvcm1hbmNlRW50cnlbXSB7XG4gICAgICAgIHJldHVybiB0aGlzLmVudHJpZXMuZmlsdGVyKChlbnRyeSkgPT4ge1xuICAgICAgICAgICAgY29uc3Qgc2F0aXNmaWVzTmFtZSA9ICFuYW1lIHx8IGVudHJ5Lm5hbWUgPT09IG5hbWU7XG4gICAgICAgICAgICBjb25zdCBzYXRpc2ZpZWRUeXBlID0gIXR5cGUgfHwgZW50cnkuZW50cnlUeXBlID09PSB0eXBlO1xuICAgICAgICAgICAgcmV0dXJuIHNhdGlzZmllc05hbWUgJiYgc2F0aXNmaWVkVHlwZTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgcHVibGljIGFkZFBlcmZvcm1hbmNlRGF0YUNhbGxiYWNrKGxpc3RlbmVyOiBQZXJmb3JtYW5jZURhdGFMaXN0ZW5lciwgYnVmZmVyID0gZmFsc2UpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5saXN0ZW5lcnMucHVzaChsaXN0ZW5lcik7XG4gICAgICAgIGlmIChidWZmZXIpIHtcbiAgICAgICAgICAgIGNvbnN0IHRvRW1pdCA9IHRoaXMuZW50cmllcy5maWx0ZXIoKGVudHJ5KSA9PiB0aGlzLnNob3VsZEVtaXQobGlzdGVuZXIsIGVudHJ5KSk7XG4gICAgICAgICAgICBpZiAodG9FbWl0Lmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgICAgICBsaXN0ZW5lci5jYWxsYmFjayh0b0VtaXQpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHVibGljIHJlbW92ZVBlcmZvcm1hbmNlRGF0YUNhbGxiYWNrKGNhbGxiYWNrPzogUGVyZm9ybWFuY2VDYWxsYmFja0Z1bmN0aW9uKTogdm9pZCB7XG4gICAgICAgIGlmICghY2FsbGJhY2spIHtcbiAgICAgICAgICAgIHRoaXMubGlzdGVuZXJzID0gW107XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLmxpc3RlbmVycy5zcGxpY2UoXG4gICAgICAgICAgICAgICAgdGhpcy5saXN0ZW5lcnMuZmluZEluZGV4KChsaXN0ZW5lcikgPT4gbGlzdGVuZXIuY2FsbGJhY2sgPT09IGNhbGxiYWNrKSxcbiAgICAgICAgICAgICAgICAxLFxuICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFRvciBicm93c2VyIGRvZXMgbm90IHN1cHBvcnQgdGhlIFBlcmZvcm1hbmNlIEFQSVxuICAgICAqIEByZXR1cm5zIHtib29sZWFufSB0cnVlIGlmIHRoZSBQZXJmb3JtYW5jZSBBUEkgaXMgc3VwcG9ydGVkXG4gICAgICovXG4gICAgcHJpdmF0ZSBzdXBwb3J0c1BlcmZvcm1hbmNlQXBpKCk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gcGVyZm9ybWFuY2UgIT09IHVuZGVmaW5lZCAmJiBwZXJmb3JtYW5jZS5tYXJrICE9PSB1bmRlZmluZWQ7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBzaG91bGRFbWl0KGxpc3RlbmVyOiBQZXJmb3JtYW5jZURhdGFMaXN0ZW5lciwgZW50cnk6IFBlcmZvcm1hbmNlRW50cnkpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuICFsaXN0ZW5lci5lbnRyeU5hbWVzIHx8IGxpc3RlbmVyLmVudHJ5TmFtZXMuaW5jbHVkZXMoZW50cnkubmFtZSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogSW50ZXJuYWwgdXRpbGl0eSB0byBlbnN1cmUgY29uc2lzdGVudCBuYW1lIGZvciB0aGUgcmVjb3JkaW5nXG4gICAgICogQHBhcmFtIG5hbWUgTmFtZSBvZiB0aGUgcmVjb3JkaW5nXG4gICAgICogQHBhcmFtIGlkIFNwZWNpZnkgYW4gaWRlbnRpZmllciBhcHBlbmRlZCB0byB0aGUgbWVhc3VyZW1lbnQgbmFtZVxuICAgICAqIEByZXR1cm5zIHtzdHJpbmd9IGEgY29tcG91bmQgb2YgdGhlIG5hbWUgYW5kIGlkZW50aWZpZXIgaWYgcHJlc2VudFxuICAgICAqL1xuICAgIHByaXZhdGUgYnVpbGRLZXkobmFtZTogc3RyaW5nLCBpZD86IHN0cmluZyk6IHN0cmluZyB7XG4gICAgICAgIGNvbnN0IHN1ZmZpeCA9IGlkID8gYDoke2lkfWAgOiBcIlwiO1xuICAgICAgICByZXR1cm4gYCR7bmFtZX0ke3N1ZmZpeH1gO1xuICAgIH1cbn1cblxuLy8gQ29udmVuaWVuY2UgZXhwb3J0c1xuZXhwb3J0IHsgUGVyZm9ybWFuY2VFbnRyeU5hbWVzIH07XG5cbi8vIEV4cG9zaW5nIHRob3NlIHRvIHRoZSB3aW5kb3cgb2JqZWN0IHRvIGJyaWRnZSB0aGVtIGZyb20gdGVzdHNcbndpbmRvdy5teFBlcmZvcm1hbmNlTW9uaXRvciA9IFBlcmZvcm1hbmNlTW9uaXRvci5pbnN0YW5jZTtcbndpbmRvdy5teFBlcmZvcm1hbmNlRW50cnlOYW1lcyA9IFBlcmZvcm1hbmNlRW50cnlOYW1lcztcbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7QUFRQSxJQUFBQSxPQUFBLEdBQUFDLE9BQUE7QUFFQSxJQUFBQyxXQUFBLEdBQUFELE9BQUE7QUFWQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFrQmUsTUFBTUUsa0JBQWtCLENBQUM7RUFBQUMsWUFBQTtJQUFBLElBQUFDLGdCQUFBLENBQUFDLE9BQUEsd0JBR2IsUUFBUTtJQUFBLElBQUFELGdCQUFBLENBQUFDLE9BQUEsdUJBQ1QsT0FBTztJQUFBLElBQUFELGdCQUFBLENBQUFDLE9BQUEscUJBRWtCLEVBQUU7SUFBQSxJQUFBRCxnQkFBQSxDQUFBQyxPQUFBLG1CQUNYLEVBQUU7RUFBQTtFQUV4QyxXQUFrQkMsUUFBUUEsQ0FBQSxFQUF1QjtJQUM3QyxJQUFJLENBQUNKLGtCQUFrQixDQUFDSyxTQUFTLEVBQUU7TUFDL0JMLGtCQUFrQixDQUFDSyxTQUFTLEdBQUcsSUFBSUwsa0JBQWtCLENBQUMsQ0FBQztJQUMzRDtJQUNBLE9BQU9BLGtCQUFrQixDQUFDSyxTQUFTO0VBQ3ZDOztFQUVBO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtFQUNXQyxLQUFLQSxDQUFDQyxJQUFZLEVBQUVDLEVBQVcsRUFBUTtJQUMxQyxJQUFJLENBQUMsSUFBSSxDQUFDQyxzQkFBc0IsQ0FBQyxDQUFDLEVBQUU7TUFDaEM7SUFDSjtJQUNBLE1BQU1DLEdBQUcsR0FBRyxJQUFJLENBQUNDLFFBQVEsQ0FBQ0osSUFBSSxFQUFFQyxFQUFFLENBQUM7SUFFbkMsSUFBSUksV0FBVyxDQUFDQyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUNDLFlBQVksR0FBR0osR0FBRyxDQUFDLENBQUNLLE1BQU0sR0FBRyxDQUFDLEVBQUU7TUFDbEVDLGNBQU0sQ0FBQ0MsSUFBSSxDQUFDLGtDQUFrQ1YsSUFBSSxFQUFFLENBQUM7TUFDckQ7SUFDSjtJQUVBSyxXQUFXLENBQUNNLElBQUksQ0FBQyxJQUFJLENBQUNKLFlBQVksR0FBR0osR0FBRyxDQUFDO0VBQzdDOztFQUVBO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0VBQ1dTLElBQUlBLENBQUNaLElBQVksRUFBRUMsRUFBVyxFQUFnQztJQUNqRSxJQUFJLENBQUMsSUFBSSxDQUFDQyxzQkFBc0IsQ0FBQyxDQUFDLEVBQUU7TUFDaEM7SUFDSjtJQUNBLE1BQU1DLEdBQUcsR0FBRyxJQUFJLENBQUNDLFFBQVEsQ0FBQ0osSUFBSSxFQUFFQyxFQUFFLENBQUM7SUFDbkMsSUFBSUksV0FBVyxDQUFDQyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUNDLFlBQVksR0FBR0osR0FBRyxDQUFDLENBQUNLLE1BQU0sS0FBSyxDQUFDLEVBQUU7TUFDcEVDLGNBQU0sQ0FBQ0MsSUFBSSxDQUFDLDZCQUE2QlYsSUFBSSxFQUFFLENBQUM7TUFDaEQ7SUFDSjtJQUVBSyxXQUFXLENBQUNNLElBQUksQ0FBQyxJQUFJLENBQUNFLFdBQVcsR0FBR1YsR0FBRyxDQUFDO0lBQ3hDRSxXQUFXLENBQUNTLE9BQU8sQ0FBQ1gsR0FBRyxFQUFFLElBQUksQ0FBQ0ksWUFBWSxHQUFHSixHQUFHLEVBQUUsSUFBSSxDQUFDVSxXQUFXLEdBQUdWLEdBQUcsQ0FBQztJQUV6RSxJQUFJLENBQUNZLEtBQUssQ0FBQ2YsSUFBSSxFQUFFQyxFQUFFLENBQUM7SUFFcEIsTUFBTWUsV0FBVyxHQUFHWCxXQUFXLENBQUNDLGdCQUFnQixDQUFDSCxHQUFHLENBQUMsQ0FBQ2MsR0FBRyxDQUFDLENBQUU7O0lBRTVEO0lBQ0E7SUFDQTtJQUNBLElBQUksQ0FBQ0MsT0FBTyxDQUFDQyxJQUFJLENBQUNILFdBQVcsQ0FBQztJQUU5QixJQUFJLENBQUNJLFNBQVMsQ0FBQ0MsT0FBTyxDQUFFQyxRQUFRLElBQUs7TUFDakMsSUFBSSxJQUFJLENBQUNDLFVBQVUsQ0FBQ0QsUUFBUSxFQUFFTixXQUFXLENBQUMsRUFBRTtRQUN4Q00sUUFBUSxDQUFDRSxRQUFRLENBQUMsQ0FBQ1IsV0FBVyxDQUFDLENBQUM7TUFDcEM7SUFDSixDQUFDLENBQUM7SUFFRixPQUFPQSxXQUFXO0VBQ3RCO0VBRU9ELEtBQUtBLENBQUNmLElBQVksRUFBRUMsRUFBVyxFQUFRO0lBQzFDLElBQUksQ0FBQyxJQUFJLENBQUNDLHNCQUFzQixDQUFDLENBQUMsRUFBRTtNQUNoQztJQUNKO0lBQ0EsTUFBTUMsR0FBRyxHQUFHLElBQUksQ0FBQ0MsUUFBUSxDQUFDSixJQUFJLEVBQUVDLEVBQUUsQ0FBQztJQUNuQ0ksV0FBVyxDQUFDb0IsVUFBVSxDQUFDLElBQUksQ0FBQ2xCLFlBQVksR0FBR0osR0FBRyxDQUFDO0lBQy9DRSxXQUFXLENBQUNvQixVQUFVLENBQUMsSUFBSSxDQUFDWixXQUFXLEdBQUdWLEdBQUcsQ0FBQztFQUNsRDtFQUVPdUIsVUFBVUEsQ0FBQztJQUFFMUIsSUFBSTtJQUFFMkI7RUFBd0IsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFzQjtJQUMxRSxPQUFPLElBQUksQ0FBQ1QsT0FBTyxDQUFDVSxNQUFNLENBQUVDLEtBQUssSUFBSztNQUNsQyxNQUFNQyxhQUFhLEdBQUcsQ0FBQzlCLElBQUksSUFBSTZCLEtBQUssQ0FBQzdCLElBQUksS0FBS0EsSUFBSTtNQUNsRCxNQUFNK0IsYUFBYSxHQUFHLENBQUNKLElBQUksSUFBSUUsS0FBSyxDQUFDRyxTQUFTLEtBQUtMLElBQUk7TUFDdkQsT0FBT0csYUFBYSxJQUFJQyxhQUFhO0lBQ3pDLENBQUMsQ0FBQztFQUNOO0VBRU9FLDBCQUEwQkEsQ0FBQ1gsUUFBaUMsRUFBRVksTUFBTSxHQUFHLEtBQUssRUFBUTtJQUN2RixJQUFJLENBQUNkLFNBQVMsQ0FBQ0QsSUFBSSxDQUFDRyxRQUFRLENBQUM7SUFDN0IsSUFBSVksTUFBTSxFQUFFO01BQ1IsTUFBTUMsTUFBTSxHQUFHLElBQUksQ0FBQ2pCLE9BQU8sQ0FBQ1UsTUFBTSxDQUFFQyxLQUFLLElBQUssSUFBSSxDQUFDTixVQUFVLENBQUNELFFBQVEsRUFBRU8sS0FBSyxDQUFDLENBQUM7TUFDL0UsSUFBSU0sTUFBTSxDQUFDM0IsTUFBTSxHQUFHLENBQUMsRUFBRTtRQUNuQmMsUUFBUSxDQUFDRSxRQUFRLENBQUNXLE1BQU0sQ0FBQztNQUM3QjtJQUNKO0VBQ0o7RUFFT0MsNkJBQTZCQSxDQUFDWixRQUFzQyxFQUFRO0lBQy9FLElBQUksQ0FBQ0EsUUFBUSxFQUFFO01BQ1gsSUFBSSxDQUFDSixTQUFTLEdBQUcsRUFBRTtJQUN2QixDQUFDLE1BQU07TUFDSCxJQUFJLENBQUNBLFNBQVMsQ0FBQ2lCLE1BQU0sQ0FDakIsSUFBSSxDQUFDakIsU0FBUyxDQUFDa0IsU0FBUyxDQUFFaEIsUUFBUSxJQUFLQSxRQUFRLENBQUNFLFFBQVEsS0FBS0EsUUFBUSxDQUFDLEVBQ3RFLENBQ0osQ0FBQztJQUNMO0VBQ0o7O0VBRUE7QUFDSjtBQUNBO0FBQ0E7RUFDWXRCLHNCQUFzQkEsQ0FBQSxFQUFZO0lBQ3RDLE9BQU9HLFdBQVcsS0FBS2tDLFNBQVMsSUFBSWxDLFdBQVcsQ0FBQ00sSUFBSSxLQUFLNEIsU0FBUztFQUN0RTtFQUVRaEIsVUFBVUEsQ0FBQ0QsUUFBaUMsRUFBRU8sS0FBdUIsRUFBVztJQUNwRixPQUFPLENBQUNQLFFBQVEsQ0FBQ2tCLFVBQVUsSUFBSWxCLFFBQVEsQ0FBQ2tCLFVBQVUsQ0FBQ0MsUUFBUSxDQUFDWixLQUFLLENBQUM3QixJQUFJLENBQUM7RUFDM0U7O0VBRUE7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0VBQ1lJLFFBQVFBLENBQUNKLElBQVksRUFBRUMsRUFBVyxFQUFVO0lBQ2hELE1BQU15QyxNQUFNLEdBQUd6QyxFQUFFLEdBQUcsSUFBSUEsRUFBRSxFQUFFLEdBQUcsRUFBRTtJQUNqQyxPQUFPLEdBQUdELElBQUksR0FBRzBDLE1BQU0sRUFBRTtFQUM3QjtBQUNKOztBQUVBO0FBQUFDLE9BQUEsQ0FBQS9DLE9BQUEsR0FBQUgsa0JBQUE7QUFBQSxJQUFBRSxnQkFBQSxDQUFBQyxPQUFBLEVBeElxQkgsa0JBQWtCO0FBMkl2QztBQUNBbUQsTUFBTSxDQUFDQyxvQkFBb0IsR0FBR3BELGtCQUFrQixDQUFDSSxRQUFRO0FBQ3pEK0MsTUFBTSxDQUFDRSx1QkFBdUIsR0FBR0MsaUNBQXFCIiwiaWdub3JlTGlzdCI6W119