158 lines
20 KiB
Plaintext
158 lines
20 KiB
Plaintext
export class MemoryCacheItem {
|
|
item;
|
|
expiresAt; // Timestamp in ms
|
|
constructor(item, expiresAt) {
|
|
this.item = item;
|
|
this.expiresAt = expiresAt;
|
|
}
|
|
isExpired(now) {
|
|
return now > this.expiresAt;
|
|
}
|
|
setAccess(now, ttl) {
|
|
this.expiresAt = now + ttl;
|
|
}
|
|
getItem() {
|
|
return this.item;
|
|
}
|
|
done(now) {
|
|
if (this.isExpired(now)) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
export class MemoryCache {
|
|
isGathered = new Map();
|
|
references = new Map();
|
|
cache = new Map();
|
|
options;
|
|
logger;
|
|
disposed = false;
|
|
currentSize = 0;
|
|
timer;
|
|
constructor(options, logger) {
|
|
this.options = options;
|
|
this.logger = logger;
|
|
this.resetGlobalTimer();
|
|
}
|
|
add(item, requestItem, testNow) {
|
|
if (this.disposed)
|
|
throw new Error('MemoryCache is disposed');
|
|
this.currentSize += item.size || 0;
|
|
this.cache.set(item.baseId, new MemoryCacheItem(item, (testNow || this.now()) + this.options.ttlms));
|
|
if (!this.isGathered.has(item.baseId)) {
|
|
this.isGathered.set(item.baseId, true);
|
|
this.scanForReferences(item.base, requestItem);
|
|
}
|
|
}
|
|
get(id) {
|
|
if (this.disposed)
|
|
throw new Error('MemoryCache is disposed');
|
|
const item = this.cache.get(id);
|
|
if (item) {
|
|
item.setAccess(this.now(), this.options.ttlms);
|
|
return item.getItem();
|
|
}
|
|
return undefined;
|
|
}
|
|
scanForReferences(data, requestItem) {
|
|
const scan = (item) => {
|
|
// Stop if the item is null or not an object (i.e., primitive)
|
|
if (item === null || typeof item !== 'object') {
|
|
return;
|
|
}
|
|
// If it's an array, scan each element
|
|
if (Array.isArray(item)) {
|
|
for (const element of item) {
|
|
scan(element);
|
|
}
|
|
return;
|
|
}
|
|
// If it's an object, scan its properties
|
|
for (const key in item) {
|
|
if (Object.prototype.hasOwnProperty.call(item, key)) {
|
|
// We found the target property!
|
|
if (key === 'referencedId') {
|
|
const value = item.referencedId;
|
|
// Ensure the value is a string before adding it
|
|
if (typeof value === 'string') {
|
|
this.references.set(value, (this.references.get(value) || 0) + 1);
|
|
if (!this.cache.has(value)) {
|
|
requestItem(value);
|
|
}
|
|
}
|
|
}
|
|
// Continue scanning deeper into the object's properties
|
|
scan(item[key]);
|
|
}
|
|
}
|
|
};
|
|
scan(data);
|
|
}
|
|
resetGlobalTimer() {
|
|
const run = () => {
|
|
this.cleanCache();
|
|
this.timer = setTimeout(run, this.options.ttlms);
|
|
};
|
|
this.timer = setTimeout(run, this.options.ttlms);
|
|
}
|
|
now() {
|
|
return Date.now();
|
|
}
|
|
cleanCache(testNow) {
|
|
const maxSizeBytes = this.options.maxSizeInMb * 1024 * 1024;
|
|
if (this.currentSize < maxSizeBytes) {
|
|
this.logger(`cache size (${this.currentSize} < ${maxSizeBytes}) is ok, no need to clean`);
|
|
return;
|
|
}
|
|
const now = testNow || this.now();
|
|
let cleaned = 0;
|
|
const start = performance.now();
|
|
for (const deferredBase of Array.from(this.cache.values())
|
|
.filter((x) => x.isExpired(now))
|
|
.sort((a, b) => this.compareMaybeBasesByReferences(a.getItem().baseId, b.getItem().baseId))) {
|
|
if (deferredBase.done(now)) {
|
|
const id = deferredBase.getItem().baseId;
|
|
const referenceCount = this.references.get(id) || 0;
|
|
if (referenceCount > 0) {
|
|
// Skip eviction for items with reference counts greater than 0,
|
|
// as they are still in use and should not be removed from the cache.
|
|
continue;
|
|
}
|
|
this.currentSize -= deferredBase.getItem().size || 0;
|
|
this.cache.delete(id);
|
|
cleaned++;
|
|
if (this.currentSize < maxSizeBytes) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
this.logger(`cleaned cache: cleaned ${cleaned}, cached ${this.cache.size}, time ${performance.now() - start}`);
|
|
return;
|
|
}
|
|
compareMaybeBasesByReferences(id1, id2) {
|
|
const a = this.references.get(id1);
|
|
const b = this.references.get(id2);
|
|
if (a === undefined && b === undefined)
|
|
return 0;
|
|
if (a === undefined)
|
|
return -1;
|
|
if (b === undefined)
|
|
return 1;
|
|
return a - b;
|
|
}
|
|
dispose() {
|
|
if (this.disposed)
|
|
return;
|
|
this.disposed = true;
|
|
if (this.timer) {
|
|
clearTimeout(this.timer);
|
|
this.timer = undefined;
|
|
}
|
|
this.cache.clear();
|
|
this.isGathered.clear();
|
|
this.references.clear();
|
|
}
|
|
}
|
|
|
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTWVtb3J5Q2FjaGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvZGVmZXJtZW50L01lbW9yeUNhY2hlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQVFBLE1BQU0sT0FBTyxlQUFlO0lBQ2xCLElBQUksQ0FBTTtJQUNWLFNBQVMsQ0FBUSxDQUFDLGtCQUFrQjtJQUU1QyxZQUFZLElBQVUsRUFBRSxTQUFpQjtRQUN2QyxJQUFJLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQTtRQUNoQixJQUFJLENBQUMsU0FBUyxHQUFHLFNBQVMsQ0FBQTtJQUM1QixDQUFDO0lBRUQsU0FBUyxDQUFDLEdBQVc7UUFDbkIsT0FBTyxHQUFHLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQTtJQUM3QixDQUFDO0lBQ0QsU0FBUyxDQUFDLEdBQVcsRUFBRSxHQUFXO1FBQ2hDLElBQUksQ0FBQyxTQUFTLEdBQUcsR0FBRyxHQUFHLEdBQUcsQ0FBQTtJQUM1QixDQUFDO0lBRUQsT0FBTztRQUNMLE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQTtJQUNsQixDQUFDO0lBRUQsSUFBSSxDQUFDLEdBQVc7UUFDZCxJQUFJLElBQUksQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUN4QixPQUFPLElBQUksQ0FBQTtRQUNiLENBQUM7UUFDRCxPQUFPLEtBQUssQ0FBQTtJQUNkLENBQUM7Q0FDRjtBQUVELE1BQU0sT0FBTyxXQUFXO0lBQ2QsVUFBVSxHQUF5QixJQUFJLEdBQUcsRUFBRSxDQUFBO0lBQzVDLFVBQVUsR0FBd0IsSUFBSSxHQUFHLEVBQUUsQ0FBQTtJQUMzQyxLQUFLLEdBQWlDLElBQUksR0FBRyxFQUFFLENBQUE7SUFFL0MsT0FBTyxDQUFvQjtJQUMzQixNQUFNLENBQWM7SUFDcEIsUUFBUSxHQUFHLEtBQUssQ0FBQTtJQUNoQixXQUFXLEdBQUcsQ0FBQyxDQUFBO0lBQ2YsS0FBSyxDQUFnQztJQUU3QyxZQUFZLE9BQTJCLEVBQUUs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QUFDLEtBQUssQ0FBQyxJQUFJLFVBQzFELFdBQVcsQ0FBQyxHQUFHLEVBQUUsR0FBRyxLQUN0QixFQUFFLENBQ0gsQ0FBQTtRQUNELE9BQU07SUFDUixDQUFDO0lBRUQsNkJBQTZCLENBQUMsR0FBVyxFQUFFLEdBQVc7UUFDcEQsTUFBTSxDQUFDLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUE7UUFDbEMsTUFBTSxDQUFDLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUE7UUFDbEMsSUFBSSxDQUFDLEtBQUssU0FBUyxJQUFJLENBQUMsS0FBSyxTQUFTO1lBQUUsT0FBTyxDQUFDLENBQUE7UUFDaEQsSUFBSSxDQUFDLEtBQUssU0FBUztZQUFFLE9BQU8sQ0FBQyxDQUFDLENBQUE7UUFDOUIsSUFBSSxDQUFDLEtBQUssU0FBUztZQUFFLE9BQU8sQ0FBQyxDQUFBO1FBQzdCLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQTtJQUNkLENBQUM7SUFFRCxPQUFPO1FBQ0wsSUFBSSxJQUFJLENBQUMsUUFBUTtZQUFFLE9BQU07UUFDekIsSUFBSSxDQUFDLFFBQVEsR0FBRyxJQUFJLENBQUE7UUFDcEIsSUFBSSxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDZixZQUFZLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFBO1lBQ3hCLElBQUksQ0FBQyxLQUFLLEdBQUcsU0FBUyxDQUFBO1FBQ3hCLENBQUM7UUFDRCxJQUFJLENBQUMsS0FBSyxDQUFDLEtBQUssRUFBRSxDQUFBO1FBQ2xCLElBQUksQ0FBQyxVQUFVLENBQUMsS0FBSyxFQUFFLENBQUE7UUFDdkIsSUFBSSxDQUFDLFVBQVUsQ0FBQyxLQUFLLEVBQUUsQ0FBQTtJQUN6QixDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDdXN0b21Mb2dnZXIgfSBmcm9tICcuLi90eXBlcy9mdW5jdGlvbnMuanMnXHJcbmltcG9ydCB7IEl0ZW0gfSBmcm9tICcuLi90eXBlcy90eXBlcy5qcydcclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgTWVtb3J5Q2FjaGVPcHRpb25zIHtcclxuICBtYXhTaXplSW5NYjogbnVtYmVyXHJcbiAgdHRsbXM6IG51bWJlclxyXG59XHJcblxyXG5leHBvcnQgY2xhc3MgTWVtb3J5Q2FjaGVJdGVtIHtcclxuICBwcml2YXRlIGl0ZW06IEl0ZW1cclxuICBwcml2YXRlIGV4cGlyZXNBdDogbnVtYmVyIC8vIFRpbWVzdGFtcCBpbiBtc1xyXG5cclxuICBjb25zdHJ1Y3RvcihpdGVtOiBJdGVtLCBleHBpcmVzQXQ6IG51bWJlcikge1xyXG4gICAgdGhpcy5pdGVtID0gaXRlbVxyXG4gICAgdGhpcy5leHBpcmVzQXQgPSBleHBpcmVzQXRcclxuICB9XHJcblxyXG4gIGlzRXhwaXJlZChub3c6IG51bWJlcik6IGJvb2xlYW4ge1xyXG4gICAgcmV0dXJuIG5vdyA+IHRoaXMuZXhwaXJlc0F0XHJcbiAgfVxyXG4gIHNldEFjY2Vzcyhub3c6IG51bWJlciwgdHRsOiBudW1iZXIpOiB2b2lkIHtcclxuICAgIHRoaXMuZXhwaXJlc0F0ID0gbm93ICsgdHRsXHJcbiAgfVxyXG5cclxuICBnZXRJdGVtKCk6IEl0ZW0ge1xyXG4gICAgcmV0dXJuIHRoaXMuaXRlbVxyXG4gIH1cclxuXHJcbiAgZG9uZShub3c6IG51bWJlcik6IGJvb2xlYW4ge1xyXG4gICAgaWYgKHRoaXMuaXNFeHBpcmVkKG5vdykpIHtcclxuICAgICAgcmV0dXJuIHRydWVcclxuICAgIH1cclxuICAgIHJldHVybiBmYWxzZVxyXG4gIH1cclxufVxyXG5cclxuZXhwb3J0IGNsYXNzIE1lbW9yeUNhY2hlIHtcclxuICBwcml2YXRlIGlzR2F0aGVyZWQ6IE1hcDxzdHJpbmcsIGJvb2xlYW4+ID0gbmV3IE1hcCgpXHJcbiAgcHJpdmF0ZSByZWZlcmVuY2VzOiBNYXA8c3RyaW5nLCBudW1iZXI+ID0gbmV3IE1hcCgpXHJcbiAgcHJpdmF0ZSBjYWNoZTogTWFwPHN0cmluZywgTWVtb3J5Q2FjaGVJdGVtPiA9IG5ldyBNYXAoKVxyXG5cclxuICBwcml2YXRlIG9wdGlvbnM6IE1lbW9yeUNhY2hlT3B0aW9uc1xyXG4gIHByaXZhdGUgbG9nZ2VyOiBDdXN0b21Mb2dnZXJcclxuICBwcml2YXRlIGRpc3Bvc2VkID0gZmFsc2VcclxuICBwcml2YXRlIGN1cnJlbnRTaXplID0gMFxyXG4gIHByaXZhdGUgdGltZXI/OiBSZXR1cm5UeXBlPHR5cGVvZiBzZXRUaW1lb3V0PlxyXG5cclxuICBjb25zdHJ1Y3RvcihvcHRpb25zOiBNZW1vcnlDYWNoZU9wdGlvbnMsIGxvZ2dlcjogQ3VzdG9tTG9nZ2VyKSB7XHJcbiAgICB0aGlzLm9wdGlvbnMgPSBvcHRpb25zXHJcbiAgICB0aGlzLmxvZ2dlciA9IGxvZ2dlclxyXG4gICAgdGhpcy5yZXNldEdsb2JhbFRpbWVyKClcclxuICB9XHJcblxyXG4gIGFkZChpdGVtOiBJdGVtLCByZXF1ZXN0SXRlbTogKGlkOiBzdHJpbmcpID0+IHZvaWQsIHRlc3ROb3c/OiBudW1iZXIpOiB2b2lkIHtcclxuICAgIGlmICh0aGlzLmRpc3Bvc2VkKSB0aHJvdyBuZXcgRXJyb3IoJ01lbW9yeUNhY2hlIGlzIGRpc3Bvc2VkJylcclxuICAgIHRoaXMuY3VycmVudFNpemUgKz0gaXRlbS5zaXplIHx8IDBcclxuICAgIHRoaXMuY2FjaGUuc2V0KFxyXG4gICAgICBpdGVtLmJhc2VJZCxcclxuICAgICAgbmV3IE1lbW9yeUNhY2hlSXRlbShpdGVtLCAodGVzdE5vdyB8fCB0aGlzLm5vdygpKSArIHRoaXMub3B0aW9ucy50dGxtcylcclxuICAgIClcclxuXHJcbiAgICBpZiAoIXRoaXMuaXNHYXRoZXJlZC5oYXMoaXRlbS5iYXNlSWQpKSB7XHJcbiAgICAgIHRoaXMuaXNHYXRoZXJlZC5zZXQoaXRlbS5iYXNlSWQsIHRydWUpXHJcbiAgICAgIHRoaXMuc2NhbkZvclJlZmVyZW5jZXMoaXRlbS5iYXNlISwgcmVxdWVzdEl0ZW0pXHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBnZXQoaWQ6IHN0cmluZyk6IEl0ZW0gfCB1bmRlZmluZWQge1xyXG4gICAgaWYgKHRoaXMuZGlzcG9zZWQpIHRocm93IG5ldyBFcnJvcignTWVtb3J5Q2FjaGUgaXMgZGlzcG9zZWQnKVxyXG4gICAgY29uc3QgaXRlbSA9IHRoaXMuY2FjaGUuZ2V0KGlkKVxyXG4gICAgaWYgKGl0ZW0pIHtcclxuICAgICAgaXRlbS5zZXRBY2Nlc3ModGhpcy5ub3coKSwgdGhpcy5vcHRpb25zLnR0bG1zKVxyXG4gICAgICByZXR1cm4gaXRlbS5nZXRJdGVtKClcclxuICAgIH1cclxuICAgIHJldHVybiB1bmRlZmluZWRcclxuICB9XHJcblxyXG4gIHNjYW5Gb3JSZWZlcmVuY2VzKGRhdGE6IHVua25vd24sIHJlcXVlc3RJdGVtOiAoaWQ6IHN0cmluZykgPT4gdm9pZCk6IHZvaWQge1xyXG4gICAgY29uc3Qgc2NhbiA9IChpdGVtOiB1bmtub3duKTogdm9pZCA9PiB7XHJcbiAgICAgIC8vIFN0b3AgaWYgdGhlIGl0ZW0gaXMgbnVsbCBvciBub3QgYW4gb2JqZWN0IChpLmUuLCBwcmltaXRpdmUpXHJcbiAgICAgIGlmIChpdGVtID09PSBudWxsIHx8IHR5cGVvZiBpdGVtICE9PSAnb2JqZWN0Jykge1xyXG4gICAgICAgIHJldHVyblxyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBJZiBpdCdzIGFuIGFycmF5LCBzY2FuIGVhY2ggZWxlbWVudFxyXG4gICAgICBpZiAoQXJyYXkuaXNBcnJheShpdGVtKSkge1xyXG4gICAgICAgIGZvciAoY29uc3QgZWxlbWVudCBvZiBpdGVtKSB7XHJcbiAgICAgICAgICBzY2FuKGVsZW1lbnQpXHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVyblxyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBJZiBpdCdzIGFuIG9iamVjdCwgc2NhbiBpdHMgcHJvcGVydGllc1xyXG4gICAgICBmb3IgKGNvbnN0IGtleSBpbiBpdGVtKSB7XHJcbiAgICAgICAgaWYgKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChpdGVtLCBrZXkpKSB7XHJcbiAgICAgICAgICAvLyBXZSBmb3VuZCB0aGUgdGFyZ2V0IHByb3BlcnR5IVxyXG4gICAgICAgICAgaWYgKGtleSA9PT0gJ3JlZmVyZW5jZWRJZCcpIHtcclxuICAgICAgICAgICAgY29uc3QgdmFsdWUgPSAoaXRlbSBhcyB7IHJlZmVyZW5jZWRJZDogdW5rbm93biB9KS5yZWZlcmVuY2VkSWRcclxuICAgICAgICAgICAgLy8gRW5zdXJlIHRoZSB2YWx1ZSBpcyBhIHN0cmluZyBiZWZvcmUgYWRkaW5nIGl0XHJcbiAgICAgICAgICAgIGlmICh0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnKSB7XHJcbiAgICAgICAgICAgICAgdGhpcy5yZWZlcmVuY2VzLnNldCh2YWx1ZSwgKHRoaXMucmVmZXJlbmNlcy5nZXQodmFsdWUpIHx8IDApICsgMSlcclxuICAgICAgICAgICAgICBpZiAoIXRoaXMuY2FjaGUuaGFzKHZhbHVlKSkge1xyXG4gICAgICAgICAgICAgICAgcmVxdWVzdEl0ZW0odmFsdWUpXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgLy8gQ29udGludWUgc2Nhbm5pbmcgZGVlcGVyIGludG8gdGhlIG9iamVjdCdzIHByb3BlcnRpZXNcclxuICAgICAgICAgIHNjYW4oKGl0ZW0gYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4pW2tleV0pXHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgc2NhbihkYXRhKVxyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSByZXNldEdsb2JhbFRpbWVyKCk6IHZvaWQge1xyXG4gICAgY29uc3QgcnVuID0gKCk6IHZvaWQgPT4ge1xyXG4gICAgICB0aGlzLmNsZWFuQ2FjaGUoKVxyXG4gICAgICB0aGlzLnRpbWVyID0gc2V0VGltZW91dChydW4sIHRoaXMub3B0aW9ucy50dGxtcylcclxuICAgIH1cclxuICAgIHRoaXMudGltZXIgPSBzZXRUaW1lb3V0KHJ1biwgdGhpcy5vcHRpb25zLnR0bG1zKVxyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBub3coKTogbnVtYmVyIHtcclxuICAgIHJldHVybiBEYXRlLm5vdygpXHJcbiAgfVxyXG5cclxuICBjbGVhbkNhY2hlKHRlc3ROb3c/OiBudW1iZXIpOiB2b2lkIHtcclxuICAgIGNvbnN0IG1heFNpemVCeXRlcyA9IHRoaXMub3B0aW9ucy5tYXhTaXplSW5NYiAqIDEwMjQgKiAxMDI0XHJcbiAgICBpZiAodGhpcy5jdXJyZW50U2l6ZSA8IG1heFNpemVCeXRlcykge1xyXG4gICAgICB0aGlzLmxvZ2dlcihcclxuICAgICAgICBgY2FjaGUgc2l6ZSAoJHt0aGlzLmN1cnJlbnRTaXplfSA8ICR7bWF4U2l6ZUJ5dGVzfSkgaXMgb2ssIG5vIG5lZWQgdG8gY2xlYW5gXHJcbiAgICAgIClcclxuICAgICAgcmV0dXJuXHJcbiAgICB9XHJcbiAgICBjb25zdCBub3cgPSB0ZXN0Tm93IHx8IHRoaXMubm93KClcclxuICAgIGxldCBjbGVhbmVkID0gMFxyXG4gICAgY29uc3Qgc3RhcnQgPSBwZXJmb3JtYW5jZS5ub3coKVxyXG4gICAgZm9yIChjb25zdCBkZWZlcnJlZEJhc2Ugb2YgQXJyYXkuZnJvbSh0aGlzLmNhY2hlLnZhbHVlcygpKVxyXG4gICAgICAuZmlsdGVyKCh4KSA9PiB4LmlzRXhwaXJlZChub3cpKVxyXG4gICAgICAuc29ydCgoYSwgYikgPT5cclxuICAgICAgICB0aGlzLmNvbXBhcmVNYXliZUJhc2VzQnlSZWZlcmVuY2VzKGEuZ2V0SXRlbSgpLmJhc2VJZCwgYi5nZXRJdGVtKCkuYmFzZUlkKVxyXG4gICAgICApKSB7XHJcbiAgICAgIGlmIChkZWZlcnJlZEJhc2UuZG9uZShub3cpKSB7XHJcbiAgICAgICAgY29uc3QgaWQgPSBkZWZlcnJlZEJhc2UuZ2V0SXRlbSgpLmJhc2VJZFxyXG4gICAgICAgIGNvbnN0IHJlZmVyZW5jZUNvdW50ID0gdGhpcy5yZWZlcmVuY2VzLmdldChpZCkgfHwgMFxyXG4gICAgICAgIGlmIChyZWZlcmVuY2VDb3VudCA+IDApIHtcclxuICAgICAgICAgIC8vIFNraXAgZXZpY3Rpb24gZm9yIGl0ZW1zIHdpdGggcmVmZXJlbmNlIGNvdW50cyBncmVhdGVyIHRoYW4gMCxcclxuICAgICAgICAgIC8vIGFzIHRoZXkgYXJlIHN0aWxsIGluIHVzZSBhbmQgc2hvdWxkIG5vdCBiZSByZW1vdmVkIGZyb20gdGhlIGNhY2hlLlxyXG4gICAgICAgICAgY29udGludWVcclxuICAgICAgICB9XHJcbiAgICAgICAgdGhpcy5jdXJyZW50U2l6ZSAtPSBkZWZlcnJlZEJhc2UuZ2V0SXRlbSgpLnNpemUgfHwgMFxyXG4gICAgICAgIHRoaXMuY2FjaGUuZGVsZXRlKGlkKVxyXG4gICAgICAgIGNsZWFuZWQrK1xyXG4gICAgICAgIGlmICh0aGlzLmN1cnJlbnRTaXplIDwgbWF4U2l6ZUJ5dGVzKSB7XHJcbiAgICAgICAgICBicmVha1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG4gICAgdGhpcy5sb2dnZXIoXHJcbiAgICAgIGBjbGVhbmVkIGNhY2hlOiBjbGVhbmVkICR7Y2xlYW5lZH0sIGNhY2hlZCAke3RoaXMuY2FjaGUuc2l6ZX0sIHRpbWUgJHtcclxuICAgICAgICBwZXJmb3JtYW5jZS5ub3coKSAtIHN0YXJ0XHJcbiAgICAgIH1gXHJcbiAgICApXHJcbiAgICByZXR1cm5cclxuICB9XHJcblxyXG4gIGNvbXBhcmVNYXliZUJhc2VzQnlSZWZlcmVuY2VzKGlkMTogc3RyaW5nLCBpZDI6IHN0cmluZyk6IG51bWJlciB7XHJcbiAgICBjb25zdCBhID0gdGhpcy5yZWZlcmVuY2VzLmdldChpZDEpXHJcbiAgICBjb25zdCBiID0gdGhpcy5yZWZlcmVuY2VzLmdldChpZDIpXHJcbiAgICBpZiAoYSA9PT0gdW5kZWZpbmVkICYmIGIgPT09IHVuZGVmaW5lZCkgcmV0dXJuIDBcclxuICAgIGlmIChhID09PSB1bmRlZmluZWQpIHJldHVybiAtMVxyXG4gICAgaWYgKGIgPT09IHVuZGVmaW5lZCkgcmV0dXJuIDFcclxuICAgIHJldHVybiBhIC0gYlxyXG4gIH1cclxuXHJcbiAgZGlzcG9zZSgpOiB2b2lkIHtcclxuICAgIGlmICh0aGlzLmRpc3Bvc2VkKSByZXR1cm5cclxuICAgIHRoaXMuZGlzcG9zZWQgPSB0cnVlXHJcbiAgICBpZiAodGhpcy50aW1lcikge1xyXG4gICAgICBjbGVhclRpbWVvdXQodGhpcy50aW1lcilcclxuICAgICAgdGhpcy50aW1lciA9IHVuZGVmaW5lZFxyXG4gICAgfVxyXG4gICAgdGhpcy5jYWNoZS5jbGVhcigpXHJcbiAgICB0aGlzLmlzR2F0aGVyZWQuY2xlYXIoKVxyXG4gICAgdGhpcy5yZWZlcmVuY2VzLmNsZWFyKClcclxuICB9XHJcbn1cclxuIl19 |