matrix-react-sdk
Version:
SDK for matrix.org using React
214 lines (199 loc) • 19.1 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.LruCache = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _logger = require("matrix-js-sdk/src/logger");
/*
Copyright 2024 New Vector Ltd.
Copyright 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.
*/
/**
* Least Recently Used cache.
* Can be initialised with a capacity and drops the least recently used items.
* This cache should be error robust: Cache miss on error.
*
* Implemented via a key lookup map and a double linked list:
* head tail
* a next → b next → c → next null
* null ← prev a ← prev b ← prev c
*
* @template K - Type of the key used to look up the values inside the cache
* @template V - Type of the values inside the cache
*/
class LruCache {
/**
* @param capacity - Cache capcity.
* @throws {Error} - Raises an error if the cache capacity is less than 1.
*/
constructor(capacity) {
/** Head of the list. */
(0, _defineProperty2.default)(this, "head", null);
/** Tail of the list */
(0, _defineProperty2.default)(this, "tail", null);
/** Key lookup map */
(0, _defineProperty2.default)(this, "map", void 0);
this.capacity = capacity;
if (this.capacity < 1) {
throw new Error("Cache capacity must be at least 1");
}
this.map = new Map();
}
/**
* Whether the cache contains an item under this key.
* Marks the item as most recently used.
*
* @param key - Key of the item
* @returns true: item in cache, else false
*/
has(key) {
try {
return this.getItem(key) !== undefined;
} catch (e) {
// Should not happen but makes it more robust to the unknown.
this.onError(e);
return false;
}
}
/**
* Returns an item from the cache.
* Marks the item as most recently used.
*
* @param key - Key of the item
* @returns The value if found, else undefined
*/
get(key) {
try {
return this.getItem(key)?.value;
} catch (e) {
// Should not happen but makes it more robust to the unknown.
this.onError(e);
return undefined;
}
}
/**
* Adds an item to the cache.
* A newly added item will be the set as the most recently used.
*
* @param key - Key of the item
* @param value - Item value
*/
set(key, value) {
try {
this.safeSet(key, value);
} catch (e) {
// Should not happen but makes it more robust to the unknown.
this.onError(e);
}
}
/**
* Deletes an item from the cache.
*
* @param key - Key of the item to be removed
*/
delete(key) {
const item = this.map.get(key);
// Unknown item.
if (!item) return;
try {
this.removeItemFromList(item);
this.map.delete(key);
} catch (e) {
// Should not happen but makes it more robust to the unknown.
this.onError(e);
}
}
/**
* Clears the cache.
*/
clear() {
this.map = new Map();
this.head = null;
this.tail = null;
}
/**
* Returns an iterator over the cached values.
*/
*values() {
for (const item of this.map.values()) {
yield item.value;
}
}
safeSet(key, value) {
const item = this.getItem(key);
if (item) {
// The item is already stored under this key. Update the value.
item.value = value;
return;
}
const newItem = {
key,
value,
next: null,
prev: null
};
if (this.head) {
// Put item in front of the list.
this.head.prev = newItem;
newItem.next = this.head;
}
this.setHeadTail(newItem);
// Store item in lookup map.
this.map.set(key, newItem);
if (this.tail && this.map.size > this.capacity) {
// Map size exceeded cache capcity. Drop tail item.
this.delete(this.tail.key);
}
}
onError(e) {
_logger.logger.warn("LruCache error", e);
this.clear();
}
getItem(key) {
const item = this.map.get(key);
// Not in cache.
if (!item) return undefined;
// Item is already at the head of the list.
// No update required.
if (item === this.head) return item;
this.removeItemFromList(item);
// Put item to the front.
if (this.head) {
this.head.prev = item;
}
item.prev = null;
item.next = this.head;
this.setHeadTail(item);
return item;
}
setHeadTail(item) {
if (item.prev === null) {
// Item has no previous item → head
this.head = item;
}
if (item.next === null) {
// Item has no next item → tail
this.tail = item;
}
}
removeItemFromList(item) {
if (item === this.head) {
this.head = item.next;
}
if (item === this.tail) {
this.tail = item.prev;
}
if (item.prev) {
item.prev.next = item.next;
}
if (item.next) {
item.next.prev = item.prev;
}
}
}
exports.LruCache = LruCache;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfbG9nZ2VyIiwicmVxdWlyZSIsIkxydUNhY2hlIiwiY29uc3RydWN0b3IiLCJjYXBhY2l0eSIsIl9kZWZpbmVQcm9wZXJ0eTIiLCJkZWZhdWx0IiwiRXJyb3IiLCJtYXAiLCJNYXAiLCJoYXMiLCJrZXkiLCJnZXRJdGVtIiwidW5kZWZpbmVkIiwiZSIsIm9uRXJyb3IiLCJnZXQiLCJ2YWx1ZSIsInNldCIsInNhZmVTZXQiLCJkZWxldGUiLCJpdGVtIiwicmVtb3ZlSXRlbUZyb21MaXN0IiwiY2xlYXIiLCJoZWFkIiwidGFpbCIsInZhbHVlcyIsIm5ld0l0ZW0iLCJuZXh0IiwicHJldiIsInNldEhlYWRUYWlsIiwic2l6ZSIsImxvZ2dlciIsIndhcm4iLCJleHBvcnRzIl0sInNvdXJjZXMiOlsiLi4vLi4vc3JjL3V0aWxzL0xydUNhY2hlLnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qXG5Db3B5cmlnaHQgMjAyNCBOZXcgVmVjdG9yIEx0ZC5cbkNvcHlyaWdodCAyMDIzIFRoZSBNYXRyaXgub3JnIEZvdW5kYXRpb24gQy5JLkMuXG5cblNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBR1BMLTMuMC1vbmx5IE9SIEdQTC0zLjAtb25seVxuUGxlYXNlIHNlZSBMSUNFTlNFIGZpbGVzIGluIHRoZSByZXBvc2l0b3J5IHJvb3QgZm9yIGZ1bGwgZGV0YWlscy5cbiovXG5cbmltcG9ydCB7IGxvZ2dlciB9IGZyb20gXCJtYXRyaXgtanMtc2RrL3NyYy9sb2dnZXJcIjtcblxuaW50ZXJmYWNlIENhY2hlSXRlbTxLLCBWPiB7XG4gICAga2V5OiBLO1xuICAgIHZhbHVlOiBWO1xuICAgIC8qKiBOZXh0IGl0ZW0gaW4gdGhlIGxpc3QgKi9cbiAgICBuZXh0OiBDYWNoZUl0ZW08SywgVj4gfCBudWxsO1xuICAgIC8qKiBQcmV2aW91cyBpdGVtIGluIHRoZSBsaXN0ICovXG4gICAgcHJldjogQ2FjaGVJdGVtPEssIFY+IHwgbnVsbDtcbn1cblxuLyoqXG4gKiBMZWFzdCBSZWNlbnRseSBVc2VkIGNhY2hlLlxuICogQ2FuIGJlIGluaXRpYWxpc2VkIHdpdGggYSBjYXBhY2l0eSBhbmQgZHJvcHMgdGhlIGxlYXN0IHJlY2VudGx5IHVzZWQgaXRlbXMuXG4gKiBUaGlzIGNhY2hlIHNob3VsZCBiZSBlcnJvciByb2J1c3Q6IENhY2hlIG1pc3Mgb24gZXJyb3IuXG4gKlxuICogSW1wbGVtZW50ZWQgdmlhIGEga2V5IGxvb2t1cCBtYXAgYW5kIGEgZG91YmxlIGxpbmtlZCBsaXN0OlxuICogICAgICAgICAgICAgaGVhZCAgICAgICAgICAgICAgdGFpbFxuICogICAgICAgICAgICAgIGEgbmV4dCDihpIgYiBuZXh0IOKGkiBjIOKGkiBuZXh0IG51bGxcbiAqICBudWxsIOKGkCBwcmV2IGEg4oaQIHByZXYgYiDihpAgcHJldiBjXG4gKlxuICogQHRlbXBsYXRlIEsgLSBUeXBlIG9mIHRoZSBrZXkgdXNlZCB0byBsb29rIHVwIHRoZSB2YWx1ZXMgaW5zaWRlIHRoZSBjYWNoZVxuICogQHRlbXBsYXRlIFYgLSBUeXBlIG9mIHRoZSB2YWx1ZXMgaW5zaWRlIHRoZSBjYWNoZVxuICovXG5leHBvcnQgY2xhc3MgTHJ1Q2FjaGU8SywgVj4ge1xuICAgIC8qKiBIZWFkIG9mIHRoZSBsaXN0LiAqL1xuICAgIHByaXZhdGUgaGVhZDogQ2FjaGVJdGVtPEssIFY+IHwgbnVsbCA9IG51bGw7XG4gICAgLyoqIFRhaWwgb2YgdGhlIGxpc3QgKi9cbiAgICBwcml2YXRlIHRhaWw6IENhY2hlSXRlbTxLLCBWPiB8IG51bGwgPSBudWxsO1xuICAgIC8qKiBLZXkgbG9va3VwIG1hcCAqL1xuICAgIHByaXZhdGUgbWFwOiBNYXA8SywgQ2FjaGVJdGVtPEssIFY+PjtcblxuICAgIC8qKlxuICAgICAqIEBwYXJhbSBjYXBhY2l0eSAtIENhY2hlIGNhcGNpdHkuXG4gICAgICogQHRocm93cyB7RXJyb3J9IC0gUmFpc2VzIGFuIGVycm9yIGlmIHRoZSBjYWNoZSBjYXBhY2l0eSBpcyBsZXNzIHRoYW4gMS5cbiAgICAgKi9cbiAgICBwdWJsaWMgY29uc3RydWN0b3IocHJpdmF0ZSBjYXBhY2l0eTogbnVtYmVyKSB7XG4gICAgICAgIGlmICh0aGlzLmNhcGFjaXR5IDwgMSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQ2FjaGUgY2FwYWNpdHkgbXVzdCBiZSBhdCBsZWFzdCAxXCIpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5tYXAgPSBuZXcgTWFwKCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogV2hldGhlciB0aGUgY2FjaGUgY29udGFpbnMgYW4gaXRlbSB1bmRlciB0aGlzIGtleS5cbiAgICAgKiBNYXJrcyB0aGUgaXRlbSBhcyBtb3N0IHJlY2VudGx5IHVzZWQuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ga2V5IC0gS2V5IG9mIHRoZSBpdGVtXG4gICAgICogQHJldHVybnMgdHJ1ZTogaXRlbSBpbiBjYWNoZSwgZWxzZSBmYWxzZVxuICAgICAqL1xuICAgIHB1YmxpYyBoYXMoa2V5OiBLKTogYm9vbGVhbiB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5nZXRJdGVtKGtleSkgIT09IHVuZGVmaW5lZDtcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgLy8gU2hvdWxkIG5vdCBoYXBwZW4gYnV0IG1ha2VzIGl0IG1vcmUgcm9idXN0IHRvIHRoZSB1bmtub3duLlxuICAgICAgICAgICAgdGhpcy5vbkVycm9yKGUpO1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyBhbiBpdGVtIGZyb20gdGhlIGNhY2hlLlxuICAgICAqIE1hcmtzIHRoZSBpdGVtIGFzIG1vc3QgcmVjZW50bHkgdXNlZC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSBrZXkgLSBLZXkgb2YgdGhlIGl0ZW1cbiAgICAgKiBAcmV0dXJucyBUaGUgdmFsdWUgaWYgZm91bmQsIGVsc2UgdW5kZWZpbmVkXG4gICAgICovXG4gICAgcHVibGljIGdldChrZXk6IEspOiBWIHwgdW5kZWZpbmVkIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmdldEl0ZW0oa2V5KT8udmFsdWU7XG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIC8vIFNob3VsZCBub3QgaGFwcGVuIGJ1dCBtYWtlcyBpdCBtb3JlIHJvYnVzdCB0byB0aGUgdW5rbm93bi5cbiAgICAgICAgICAgIHRoaXMub25FcnJvcihlKTtcbiAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBBZGRzIGFuIGl0ZW0gdG8gdGhlIGNhY2hlLlxuICAgICAqIEEgbmV3bHkgYWRkZWQgaXRlbSB3aWxsIGJlIHRoZSBzZXQgYXMgdGhlIG1vc3QgcmVjZW50bHkgdXNlZC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSBrZXkgLSBLZXkgb2YgdGhlIGl0ZW1cbiAgICAgKiBAcGFyYW0gdmFsdWUgLSBJdGVtIHZhbHVlXG4gICAgICovXG4gICAgcHVibGljIHNldChrZXk6IEssIHZhbHVlOiBWKTogdm9pZCB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICB0aGlzLnNhZmVTZXQoa2V5LCB2YWx1ZSk7XG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIC8vIFNob3VsZCBub3QgaGFwcGVuIGJ1dCBtYWtlcyBpdCBtb3JlIHJvYnVzdCB0byB0aGUgdW5rbm93bi5cbiAgICAgICAgICAgIHRoaXMub25FcnJvcihlKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIERlbGV0ZXMgYW4gaXRlbSBmcm9tIHRoZSBjYWNoZS5cbiAgICAgKlxuICAgICAqIEBwYXJhbSBrZXkgLSBLZXkgb2YgdGhlIGl0ZW0gdG8gYmUgcmVtb3ZlZFxuICAgICAqL1xuICAgIHB1YmxpYyBkZWxldGUoa2V5OiBLKTogdm9pZCB7XG4gICAgICAgIGNvbnN0IGl0ZW0gPSB0aGlzLm1hcC5nZXQoa2V5KTtcblxuICAgICAgICAvLyBVbmtub3duIGl0ZW0uXG4gICAgICAgIGlmICghaXRlbSkgcmV0dXJuO1xuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICB0aGlzLnJlbW92ZUl0ZW1Gcm9tTGlzdChpdGVtKTtcbiAgICAgICAgICAgIHRoaXMubWFwLmRlbGV0ZShrZXkpO1xuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICAvLyBTaG91bGQgbm90IGhhcHBlbiBidXQgbWFrZXMgaXQgbW9yZSByb2J1c3QgdG8gdGhlIHVua25vd24uXG4gICAgICAgICAgICB0aGlzLm9uRXJyb3IoZSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDbGVhcnMgdGhlIGNhY2hlLlxuICAgICAqL1xuICAgIHB1YmxpYyBjbGVhcigpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5tYXAgPSBuZXcgTWFwKCk7XG4gICAgICAgIHRoaXMuaGVhZCA9IG51bGw7XG4gICAgICAgIHRoaXMudGFpbCA9IG51bGw7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyBhbiBpdGVyYXRvciBvdmVyIHRoZSBjYWNoZWQgdmFsdWVzLlxuICAgICAqL1xuICAgIHB1YmxpYyAqdmFsdWVzKCk6IEl0ZXJhYmxlSXRlcmF0b3I8Vj4ge1xuICAgICAgICBmb3IgKGNvbnN0IGl0ZW0gb2YgdGhpcy5tYXAudmFsdWVzKCkpIHtcbiAgICAgICAgICAgIHlpZWxkIGl0ZW0udmFsdWU7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIHNhZmVTZXQoa2V5OiBLLCB2YWx1ZTogVik6IHZvaWQge1xuICAgICAgICBjb25zdCBpdGVtID0gdGhpcy5nZXRJdGVtKGtleSk7XG5cbiAgICAgICAgaWYgKGl0ZW0pIHtcbiAgICAgICAgICAgIC8vIFRoZSBpdGVtIGlzIGFscmVhZHkgc3RvcmVkIHVuZGVyIHRoaXMga2V5LiBVcGRhdGUgdGhlIHZhbHVlLlxuICAgICAgICAgICAgaXRlbS52YWx1ZSA9IHZhbHVlO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgbmV3SXRlbTogQ2FjaGVJdGVtPEssIFY+ID0ge1xuICAgICAgICAgICAga2V5LFxuICAgICAgICAgICAgdmFsdWUsXG4gICAgICAgICAgICBuZXh0OiBudWxsLFxuICAgICAgICAgICAgcHJldjogbnVsbCxcbiAgICAgICAgfTtcblxuICAgICAgICBpZiAodGhpcy5oZWFkKSB7XG4gICAgICAgICAgICAvLyBQdXQgaXRlbSBpbiBmcm9udCBvZiB0aGUgbGlzdC5cbiAgICAgICAgICAgIHRoaXMuaGVhZC5wcmV2ID0gbmV3SXRlbTtcbiAgICAgICAgICAgIG5ld0l0ZW0ubmV4dCA9IHRoaXMuaGVhZDtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuc2V0SGVhZFRhaWwobmV3SXRlbSk7XG5cbiAgICAgICAgLy8gU3RvcmUgaXRlbSBpbiBsb29rdXAgbWFwLlxuICAgICAgICB0aGlzLm1hcC5zZXQoa2V5LCBuZXdJdGVtKTtcblxuICAgICAgICBpZiAodGhpcy50YWlsICYmIHRoaXMubWFwLnNpemUgPiB0aGlzLmNhcGFjaXR5KSB7XG4gICAgICAgICAgICAvLyBNYXAgc2l6ZSBleGNlZWRlZCBjYWNoZSBjYXBjaXR5LiBEcm9wIHRhaWwgaXRlbS5cbiAgICAgICAgICAgIHRoaXMuZGVsZXRlKHRoaXMudGFpbC5rZXkpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBvbkVycm9yKGU6IHVua25vd24pOiB2b2lkIHtcbiAgICAgICAgbG9nZ2VyLndhcm4oXCJMcnVDYWNoZSBlcnJvclwiLCBlKTtcbiAgICAgICAgdGhpcy5jbGVhcigpO1xuICAgIH1cblxuICAgIHByaXZhdGUgZ2V0SXRlbShrZXk6IEspOiBDYWNoZUl0ZW08SywgVj4gfCB1bmRlZmluZWQge1xuICAgICAgICBjb25zdCBpdGVtID0gdGhpcy5tYXAuZ2V0KGtleSk7XG5cbiAgICAgICAgLy8gTm90IGluIGNhY2hlLlxuICAgICAgICBpZiAoIWl0ZW0pIHJldHVybiB1bmRlZmluZWQ7XG5cbiAgICAgICAgLy8gSXRlbSBpcyBhbHJlYWR5IGF0IHRoZSBoZWFkIG9mIHRoZSBsaXN0LlxuICAgICAgICAvLyBObyB1cGRhdGUgcmVxdWlyZWQuXG4gICAgICAgIGlmIChpdGVtID09PSB0aGlzLmhlYWQpIHJldHVybiBpdGVtO1xuXG4gICAgICAgIHRoaXMucmVtb3ZlSXRlbUZyb21MaXN0KGl0ZW0pO1xuXG4gICAgICAgIC8vIFB1dCBpdGVtIHRvIHRoZSBmcm9udC5cblxuICAgICAgICBpZiAodGhpcy5oZWFkKSB7XG4gICAgICAgICAgICB0aGlzLmhlYWQucHJldiA9IGl0ZW07XG4gICAgICAgIH1cblxuICAgICAgICBpdGVtLnByZXYgPSBudWxsO1xuICAgICAgICBpdGVtLm5leHQgPSB0aGlzLmhlYWQ7XG5cbiAgICAgICAgdGhpcy5zZXRIZWFkVGFpbChpdGVtKTtcblxuICAgICAgICByZXR1cm4gaXRlbTtcbiAgICB9XG5cbiAgICBwcml2YXRlIHNldEhlYWRUYWlsKGl0ZW06IENhY2hlSXRlbTxLLCBWPik6IHZvaWQge1xuICAgICAgICBpZiAoaXRlbS5wcmV2ID09PSBudWxsKSB7XG4gICAgICAgICAgICAvLyBJdGVtIGhhcyBubyBwcmV2aW91cyBpdGVtIOKGkiBoZWFkXG4gICAgICAgICAgICB0aGlzLmhlYWQgPSBpdGVtO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGl0ZW0ubmV4dCA9PT0gbnVsbCkge1xuICAgICAgICAgICAgLy8gSXRlbSBoYXMgbm8gbmV4dCBpdGVtIOKGkiB0YWlsXG4gICAgICAgICAgICB0aGlzLnRhaWwgPSBpdGVtO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSByZW1vdmVJdGVtRnJvbUxpc3QoaXRlbTogQ2FjaGVJdGVtPEssIFY+KTogdm9pZCB7XG4gICAgICAgIGlmIChpdGVtID09PSB0aGlzLmhlYWQpIHtcbiAgICAgICAgICAgIHRoaXMuaGVhZCA9IGl0ZW0ubmV4dDtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChpdGVtID09PSB0aGlzLnRhaWwpIHtcbiAgICAgICAgICAgIHRoaXMudGFpbCA9IGl0ZW0ucHJldjtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChpdGVtLnByZXYpIHtcbiAgICAgICAgICAgIGl0ZW0ucHJldi5uZXh0ID0gaXRlbS5uZXh0O1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGl0ZW0ubmV4dCkge1xuICAgICAgICAgICAgaXRlbS5uZXh0LnByZXYgPSBpdGVtLnByZXY7XG4gICAgICAgIH1cbiAgICB9XG59XG4iXSwibWFwcGluZ3MiOiI7Ozs7Ozs7O0FBUUEsSUFBQUEsT0FBQSxHQUFBQyxPQUFBO0FBUkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBYUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDTyxNQUFNQyxRQUFRLENBQU87RUFReEI7QUFDSjtBQUNBO0FBQ0E7RUFDV0MsV0FBV0EsQ0FBU0MsUUFBZ0IsRUFBRTtJQVg3QztJQUFBLElBQUFDLGdCQUFBLENBQUFDLE9BQUEsZ0JBQ3VDLElBQUk7SUFDM0M7SUFBQSxJQUFBRCxnQkFBQSxDQUFBQyxPQUFBLGdCQUN1QyxJQUFJO0lBQzNDO0lBQUEsSUFBQUQsZ0JBQUEsQ0FBQUMsT0FBQTtJQUFBLEtBTzJCRixRQUFnQixHQUFoQkEsUUFBZ0I7SUFDdkMsSUFBSSxJQUFJLENBQUNBLFFBQVEsR0FBRyxDQUFDLEVBQUU7TUFDbkIsTUFBTSxJQUFJRyxLQUFLLENBQUMsbUNBQW1DLENBQUM7SUFDeEQ7SUFFQSxJQUFJLENBQUNDLEdBQUcsR0FBRyxJQUFJQyxHQUFHLENBQUMsQ0FBQztFQUN4Qjs7RUFFQTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtFQUNXQyxHQUFHQSxDQUFDQyxHQUFNLEVBQVc7SUFDeEIsSUFBSTtNQUNBLE9BQU8sSUFBSSxDQUFDQyxPQUFPLENBQUNELEdBQUcsQ0FBQyxLQUFLRSxTQUFTO0lBQzFDLENBQUMsQ0FBQyxPQUFPQyxDQUFDLEVBQUU7TUFDUjtNQUNBLElBQUksQ0FBQ0MsT0FBTyxDQUFDRCxDQUFDLENBQUM7TUFDZixPQUFPLEtBQUs7SUFDaEI7RUFDSjs7RUFFQTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtFQUNXRSxHQUFHQSxDQUFDTCxHQUFNLEVBQWlCO0lBQzlCLElBQUk7TUFDQSxPQUFPLElBQUksQ0FBQ0MsT0FBTyxDQUFDRCxHQUFHLENBQUMsRUFBRU0sS0FBSztJQUNuQyxDQUFDLENBQUMsT0FBT0gsQ0FBQyxFQUFFO01BQ1I7TUFDQSxJQUFJLENBQUNDLE9BQU8sQ0FBQ0QsQ0FBQyxDQUFDO01BQ2YsT0FBT0QsU0FBUztJQUNwQjtFQUNKOztFQUVBO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0VBQ1dLLEdBQUdBLENBQUNQLEdBQU0sRUFBRU0sS0FBUSxFQUFRO0lBQy9CLElBQUk7TUFDQSxJQUFJLENBQUNFLE9BQU8sQ0FBQ1IsR0FBRyxFQUFFTSxLQUFLLENBQUM7SUFDNUIsQ0FBQyxDQUFDLE9BQU9ILENBQUMsRUFBRTtNQUNSO01BQ0EsSUFBSSxDQUFDQyxPQUFPLENBQUNELENBQUMsQ0FBQztJQUNuQjtFQUNKOztFQUVBO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7RUFDV00sTUFBTUEsQ0FBQ1QsR0FBTSxFQUFRO0lBQ3hCLE1BQU1VLElBQUksR0FBRyxJQUFJLENBQUNiLEdBQUcsQ0FBQ1EsR0FBRyxDQUFDTCxHQUFHLENBQUM7O0lBRTlCO0lBQ0EsSUFBSSxDQUFDVSxJQUFJLEVBQUU7SUFFWCxJQUFJO01BQ0EsSUFBSSxDQUFDQyxrQkFBa0IsQ0FBQ0QsSUFBSSxDQUFDO01BQzdCLElBQUksQ0FBQ2IsR0FBRyxDQUFDWSxNQUFNLENBQUNULEdBQUcsQ0FBQztJQUN4QixDQUFDLENBQUMsT0FBT0csQ0FBQyxFQUFFO01BQ1I7TUFDQSxJQUFJLENBQUNDLE9BQU8sQ0FBQ0QsQ0FBQyxDQUFDO0lBQ25CO0VBQ0o7O0VBRUE7QUFDSjtBQUNBO0VBQ1dTLEtBQUtBLENBQUEsRUFBUztJQUNqQixJQUFJLENBQUNmLEdBQUcsR0FBRyxJQUFJQyxHQUFHLENBQUMsQ0FBQztJQUNwQixJQUFJLENBQUNlLElBQUksR0FBRyxJQUFJO0lBQ2hCLElBQUksQ0FBQ0MsSUFBSSxHQUFHLElBQUk7RUFDcEI7O0VBRUE7QUFDSjtBQUNBO0VBQ0ksQ0FBUUMsTUFBTUEsQ0FBQSxFQUF3QjtJQUNsQyxLQUFLLE1BQU1MLElBQUksSUFBSSxJQUFJLENBQUNiLEdBQUcsQ0FBQ2tCLE1BQU0sQ0FBQyxDQUFDLEVBQUU7TUFDbEMsTUFBTUwsSUFBSSxDQUFDSixLQUFLO0lBQ3BCO0VBQ0o7RUFFUUUsT0FBT0EsQ0FBQ1IsR0FBTSxFQUFFTSxLQUFRLEVBQVE7SUFDcEMsTUFBTUksSUFBSSxHQUFHLElBQUksQ0FBQ1QsT0FBTyxDQUFDRCxHQUFHLENBQUM7SUFFOUIsSUFBSVUsSUFBSSxFQUFFO01BQ047TUFDQUEsSUFBSSxDQUFDSixLQUFLLEdBQUdBLEtBQUs7TUFDbEI7SUFDSjtJQUVBLE1BQU1VLE9BQXdCLEdBQUc7TUFDN0JoQixHQUFHO01BQ0hNLEtBQUs7TUFDTFcsSUFBSSxFQUFFLElBQUk7TUFDVkMsSUFBSSxFQUFFO0lBQ1YsQ0FBQztJQUVELElBQUksSUFBSSxDQUFDTCxJQUFJLEVBQUU7TUFDWDtNQUNBLElBQUksQ0FBQ0EsSUFBSSxDQUFDSyxJQUFJLEdBQUdGLE9BQU87TUFDeEJBLE9BQU8sQ0FBQ0MsSUFBSSxHQUFHLElBQUksQ0FBQ0osSUFBSTtJQUM1QjtJQUVBLElBQUksQ0FBQ00sV0FBVyxDQUFDSCxPQUFPLENBQUM7O0lBRXpCO0lBQ0EsSUFBSSxDQUFDbkIsR0FBRyxDQUFDVSxHQUFHLENBQUNQLEdBQUcsRUFBRWdCLE9BQU8sQ0FBQztJQUUxQixJQUFJLElBQUksQ0FBQ0YsSUFBSSxJQUFJLElBQUksQ0FBQ2pCLEdBQUcsQ0FBQ3VCLElBQUksR0FBRyxJQUFJLENBQUMzQixRQUFRLEVBQUU7TUFDNUM7TUFDQSxJQUFJLENBQUNnQixNQUFNLENBQUMsSUFBSSxDQUFDSyxJQUFJLENBQUNkLEdBQUcsQ0FBQztJQUM5QjtFQUNKO0VBRVFJLE9BQU9BLENBQUNELENBQVUsRUFBUTtJQUM5QmtCLGNBQU0sQ0FBQ0MsSUFBSSxDQUFDLGdCQUFnQixFQUFFbkIsQ0FBQyxDQUFDO0lBQ2hDLElBQUksQ0FBQ1MsS0FBSyxDQUFDLENBQUM7RUFDaEI7RUFFUVgsT0FBT0EsQ0FBQ0QsR0FBTSxFQUErQjtJQUNqRCxNQUFNVSxJQUFJLEdBQUcsSUFBSSxDQUFDYixHQUFHLENBQUNRLEdBQUcsQ0FBQ0wsR0FBRyxDQUFDOztJQUU5QjtJQUNBLElBQUksQ0FBQ1UsSUFBSSxFQUFFLE9BQU9SLFNBQVM7O0lBRTNCO0lBQ0E7SUFDQSxJQUFJUSxJQUFJLEtBQUssSUFBSSxDQUFDRyxJQUFJLEVBQUUsT0FBT0gsSUFBSTtJQUVuQyxJQUFJLENBQUNDLGtCQUFrQixDQUFDRCxJQUFJLENBQUM7O0lBRTdCOztJQUVBLElBQUksSUFBSSxDQUFDRyxJQUFJLEVBQUU7TUFDWCxJQUFJLENBQUNBLElBQUksQ0FBQ0ssSUFBSSxHQUFHUixJQUFJO0lBQ3pCO0lBRUFBLElBQUksQ0FBQ1EsSUFBSSxHQUFHLElBQUk7SUFDaEJSLElBQUksQ0FBQ08sSUFBSSxHQUFHLElBQUksQ0FBQ0osSUFBSTtJQUVyQixJQUFJLENBQUNNLFdBQVcsQ0FBQ1QsSUFBSSxDQUFDO0lBRXRCLE9BQU9BLElBQUk7RUFDZjtFQUVRUyxXQUFXQSxDQUFDVCxJQUFxQixFQUFRO0lBQzdDLElBQUlBLElBQUksQ0FBQ1EsSUFBSSxLQUFLLElBQUksRUFBRTtNQUNwQjtNQUNBLElBQUksQ0FBQ0wsSUFBSSxHQUFHSCxJQUFJO0lBQ3BCO0lBRUEsSUFBSUEsSUFBSSxDQUFDTyxJQUFJLEtBQUssSUFBSSxFQUFFO01BQ3BCO01BQ0EsSUFBSSxDQUFDSCxJQUFJLEdBQUdKLElBQUk7SUFDcEI7RUFDSjtFQUVRQyxrQkFBa0JBLENBQUNELElBQXFCLEVBQVE7SUFDcEQsSUFBSUEsSUFBSSxLQUFLLElBQUksQ0FBQ0csSUFBSSxFQUFFO01BQ3BCLElBQUksQ0FBQ0EsSUFBSSxHQUFHSCxJQUFJLENBQUNPLElBQUk7SUFDekI7SUFFQSxJQUFJUCxJQUFJLEtBQUssSUFBSSxDQUFDSSxJQUFJLEVBQUU7TUFDcEIsSUFBSSxDQUFDQSxJQUFJLEdBQUdKLElBQUksQ0FBQ1EsSUFBSTtJQUN6QjtJQUVBLElBQUlSLElBQUksQ0FBQ1EsSUFBSSxFQUFFO01BQ1hSLElBQUksQ0FBQ1EsSUFBSSxDQUFDRCxJQUFJLEdBQUdQLElBQUksQ0FBQ08sSUFBSTtJQUM5QjtJQUVBLElBQUlQLElBQUksQ0FBQ08sSUFBSSxFQUFFO01BQ1hQLElBQUksQ0FBQ08sSUFBSSxDQUFDQyxJQUFJLEdBQUdSLElBQUksQ0FBQ1EsSUFBSTtJQUM5QjtFQUNKO0FBQ0o7QUFBQ0ssT0FBQSxDQUFBaEMsUUFBQSxHQUFBQSxRQUFBIiwiaWdub3JlTGlzdCI6W119