UNPKG

@dollhousemcp/mcp-server

Version:

DollhouseMCP - A Model Context Protocol (MCP) server that enables dynamic AI persona management from markdown files, allowing Claude and other compatible AI assistants to activate and switch between different behavioral personas.

121 lines 15.7 kB
/** * In-memory ring buffer sink for metric snapshots. * * Stores snapshots in an EvictingQueue and provides a query interface * for the MCP query_metrics tool. Follows the same query pattern as * MemoryLogSink (see src/logging/sinks/MemoryLogSink.ts). */ import { EvictingQueue } from '../../utils/EvictingQueue.js'; export class MemoryMetricsSink { name = 'MemoryMetricsSink'; queue; constructor(maxSnapshots = 240) { this.queue = new EvictingQueue(maxSnapshots); } onSnapshot(snapshot) { this.queue.push(snapshot); } async flush() { // No-op — in-memory, nothing to flush. } async close() { this.queue.clear(); } query(options) { const latest = options?.latest ?? true; const limit = Math.min(Math.max(options?.limit ?? 1, 0), 100); const offset = Math.max(options?.offset ?? 0, 0); const allSnapshots = this.queue.toArray(); // Compute availability bounds BEFORE filtering const oldestAvailable = allSnapshots.length > 0 ? allSnapshots[0].timestamp : ''; const newestAvailable = allSnapshots.length > 0 ? allSnapshots.at(-1).timestamp : ''; // If limit is 0, return empty result with bounds if (limit === 0) { return { snapshots: [], total: 0, hasMore: false, limit, offset, oldestAvailable, newestAvailable, }; } // 1. Select snapshots based on latest flag let snapshots; if (latest) { snapshots = allSnapshots.length > 0 ? [allSnapshots.at(-1)] : []; } else { snapshots = [...allSnapshots]; } // 2. Filter by time range if (options?.since) { const since = options.since; snapshots = snapshots.filter(s => s.timestamp > since); } if (options?.until) { const until = options.until; snapshots = snapshots.filter(s => s.timestamp < until); } // 3. Filter metrics within each snapshot by name/source/type if (options?.names || options?.source || options?.type) { const filtered = []; for (const snapshot of snapshots) { const matchedMetrics = snapshot.metrics.filter(metric => matchesMetricFilters(metric, options)); if (matchedMetrics.length > 0) { filtered.push({ ...snapshot, metrics: matchedMetrics }); } } snapshots = filtered; } // 4. Sort newest-first (descending timestamp) snapshots.sort((a, b) => b.timestamp.localeCompare(a.timestamp)); // 5. Count total before pagination const total = snapshots.length; // 6. Paginate snapshots = snapshots.slice(offset, offset + limit); return { snapshots, total, hasMore: offset + limit < total, limit, offset, oldestAvailable, newestAvailable, }; } getStats() { return { size: this.queue.size, capacity: this.queue.capacity }; } } // --------------------------------------------------------------------------- // Internal helpers // --------------------------------------------------------------------------- function matchesMetricFilters(metric, options) { // Name filter: prefix match if ends with '.' or '.*', else exact match if (options.names && options.names.length > 0) { const matched = options.names.some(name => { if (name.endsWith('.') || name.endsWith('.*')) { const prefix = name.endsWith('.*') ? name.slice(0, -1) : name; return metric.name.startsWith(prefix); } return metric.name === name; }); if (!matched) return false; } // Source filter: case-insensitive substring match if (options.source) { const needle = options.source.toLowerCase(); if (!metric.source.toLowerCase().includes(needle)) return false; } // Type filter: exact match if (options.type) { if (metric.type !== options.type) return false; } return true; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTWVtb3J5TWV0cmljc1NpbmsuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbWV0cmljcy9zaW5rcy9NZW1vcnlNZXRyaWNzU2luay50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7O0dBTUc7QUFFSCxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFTN0QsTUFBTSxPQUFPLGlCQUFpQjtJQUNuQixJQUFJLEdBQUcsbUJBQW1CLENBQUM7SUFDbkIsS0FBSyxDQUFnQztJQUV0RCxZQUFZLGVBQXVCLEdBQUc7UUFDcEMsSUFBSSxDQUFDLEtBQUssR0FBRyxJQUFJLGFBQWEsQ0FBaUIsWUFBWSxDQUFDLENBQUM7SUFDL0QsQ0FBQztJQUVELFVBQVUsQ0FBQyxRQUF3QjtRQUNqQyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUM1QixDQUFDO0lBRUQsS0FBSyxDQUFDLEtBQUs7UUFDVCx1Q0FBdUM7SUFDekMsQ0FBQztJQUVELEtBQUssQ0FBQyxLQUFLO1FBQ1QsSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLLEVBQUUsQ0FBQztJQUNyQixDQUFDO0lBRUQsS0FBSyxDQUFDLE9BQTRCO1FBQ2hDLE1BQU0sTUFBTSxHQUFHLE9BQU8sRUFBRSxNQUFNLElBQUksSUFBSSxDQUFDO1FBQ3ZDLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsS0FBSyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQztRQUM5RCxNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxNQUFNLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBRWpELE1BQU0sWUFBWSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxFQUFFLENBQUM7UUFFMUMsK0NBQStDO1FBQy9DLE1BQU0sZUFBZSxHQUFHLFlBQVksQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7UUFDakYsTUFBTSxlQUFlLEdBQUcsWUFBWSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLFlBQVksQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUUsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUV0RixpREFBaUQ7UUFDakQsSUFBSSxLQUFLLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDaEIsT0FBTztnQkFDTCxTQUFTLEVBQUUsRUFBRTtnQkFDYixLQUFLLEVBQUUsQ0FBQztnQkFDUixPQUFPLEVBQUUsS0FBSztnQkFDZCxLQUFLO2dCQUNMLE1BQU07Z0JBQ04sZUFBZTtnQkFDZixlQUFlO2FBQ2hCLENBQUM7UUFDSixDQUFDO1FBRUQsMkNBQTJDO1FBQzNDLElBQUksU0FBMkIsQ0FBQztRQUNoQyxJQUFJLE1BQU0sRUFBRSxDQUFDO1lBQ1gsU0FBUyxHQUFHLFlBQVksQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLFlBQVksQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7UUFDcEUsQ0FBQzthQUFNLENBQUM7WUFDTixTQUFTLEdBQUcsQ0FBQyxHQUFHLFlBQVksQ0FBQyxDQUFDO1FBQ2hDLENBQUM7UUFFRCwwQkFBMEI7UUFDMUIsSUFBSSxPQUFPLEVBQUUsS0FBSyxFQUFFLENBQUM7WUFDbkIsTUFBTSxLQUFLLEdBQUcsT0FBTyxDQUFDLEtBQUssQ0FBQztZQUM1QixTQUFTLEdBQUcsU0FBUyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxTQUFTLEdBQUcsS0FBSyxDQUFDLENBQUM7UUFDekQsQ0FBQztRQUNELElBQUksT0FBTyxFQUFFLEtBQUssRUFBRSxDQUFDO1lBQ25CLE1BQU0sS0FBSyxHQUFHLE9BQU8sQ0FBQyxLQUFLLENBQUM7WUFDNUIsU0FBUyxHQUFHLFNBQVMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsU0FBUyxHQUFHLEtBQUssQ0FBQyxDQUFDO1FBQ3pELENBQUM7UUFFRCw2REFBNkQ7UUFDN0QsSUFBSSxPQUFPLEVBQUUsS0FBSyxJQUFJLE9BQU8sRUFBRSxNQUFNLElBQUksT0FBTyxFQUFFLElBQUksRUFBRSxDQUFDO1lBQ3ZELE1BQU0sUUFBUSxHQUFxQixFQUFFLENBQUM7WUFDdEMsS0FBSyxNQUFNLFFBQVEsSUFBSSxTQUFTLEVBQUUsQ0FBQztnQkFDakMsTUFBTSxjQUFjLEdBQUcsUUFBUSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FDdEQsb0JBQW9CLENBQUMsTUFBTSxFQUFFLE9BQU8sQ0FBQyxDQUN0QyxDQUFDO2dCQUNGLElBQUksY0FBYyxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztvQkFDOUIsUUFBUSxDQUFDLElBQUksQ0FBQyxFQUFFLEdBQUcsUUFBUSxFQUFFLE9BQU8sRUFBRSxjQUFjLEVBQUUsQ0FBQyxDQUFDO2dCQUMxRCxDQUFDO1lBQ0gsQ0FBQztZQUNELFNBQVMsR0FBRyxRQUFRLENBQUM7UUFDdkIsQ0FBQztRQUVELDhDQUE4QztRQUM5QyxTQUFTLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxhQUFhLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUM7UUFFakUsbUNBQW1DO1FBQ25DLE1BQU0sS0FBSyxHQUFHLFNBQVMsQ0FBQyxNQUFNLENBQUM7UUFFL0IsY0FBYztRQUNkLFNBQVMsR0FBRyxTQUFTLENBQUMsS0FBSyxDQUFDLE1BQU0sRUFBRSxNQUFNLEdBQUcsS0FBSyxDQUFDLENBQUM7UUFFcEQsT0FBTztZQUNMLFNBQVM7WUFDVCxLQUFLO1lBQ0wsT0FBTyxFQUFFLE1BQU0sR0FBRyxLQUFLLEdBQUcsS0FBSztZQUMvQixLQUFLO1lBQ0wsTUFBTTtZQUNOLGVBQWU7WUFDZixlQUFlO1NBQ2hCLENBQUM7SUFDSixDQUFDO0lBRUQsUUFBUTtRQUNOLE9BQU8sRUFBRSxJQUFJLEVBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLEVBQUUsUUFBUSxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsUUFBUSxFQUFFLENBQUM7SUFDbEUsQ0FBQztDQUNGO0FBRUQsOEVBQThFO0FBQzlFLG1CQUFtQjtBQUNuQiw4RUFBOEU7QUFFOUUsU0FBUyxvQkFBb0IsQ0FDM0IsTUFBbUIsRUFDbkIsT0FBMkI7SUFFM0IsdUVBQXVFO0lBQ3ZFLElBQUksT0FBTyxDQUFDLEtBQUssSUFBSSxPQUFPLENBQUMsS0FBSyxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztRQUM5QyxNQUFNLE9BQU8sR0FBRyxPQUFPLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsRUFBRTtZQUN4QyxJQUFJLElBQUksQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLElBQUksSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO2dCQUM5QyxNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUM7Z0JBQzlELE9BQU8sTUFBTSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLENBQUM7WUFDeEMsQ0FBQztZQUNELE9BQU8sTUFBTSxDQUFDLElBQUksS0FBSyxJQUFJLENBQUM7UUFDOUIsQ0FBQyxDQUFDLENBQUM7UUFDSCxJQUFJLENBQUMsT0FBTztZQUFFLE9BQU8sS0FBSyxDQUFDO0lBQzdCLENBQUM7SUFFRCxrREFBa0Q7SUFDbEQsSUFBSSxPQUFPLENBQUMsTUFBTSxFQUFFLENBQUM7UUFDbkIsTUFBTSxNQUFNLEdBQUcsT0FBTyxDQUFDLE1BQU0sQ0FBQyxXQUFXLEVBQUUsQ0FBQztRQUM1QyxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxXQUFXLEVBQUUsQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDO1lBQUUsT0FBTyxLQUFLLENBQUM7SUFDbEUsQ0FBQztJQUVELDJCQUEyQjtJQUMzQixJQUFJLE9BQU8sQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUNqQixJQUFJLE1BQU0sQ0FBQyxJQUFJLEtBQUssT0FBTyxDQUFDLElBQUk7WUFBRSxPQUFPLEtBQUssQ0FBQztJQUNqRCxDQUFDO0lBRUQsT0FBTyxJQUFJLENBQUM7QUFDZCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBJbi1tZW1vcnkgcmluZyBidWZmZXIgc2luayBmb3IgbWV0cmljIHNuYXBzaG90cy5cbiAqXG4gKiBTdG9yZXMgc25hcHNob3RzIGluIGFuIEV2aWN0aW5nUXVldWUgYW5kIHByb3ZpZGVzIGEgcXVlcnkgaW50ZXJmYWNlXG4gKiBmb3IgdGhlIE1DUCBxdWVyeV9tZXRyaWNzIHRvb2wuIEZvbGxvd3MgdGhlIHNhbWUgcXVlcnkgcGF0dGVybiBhc1xuICogTWVtb3J5TG9nU2luayAoc2VlIHNyYy9sb2dnaW5nL3NpbmtzL01lbW9yeUxvZ1NpbmsudHMpLlxuICovXG5cbmltcG9ydCB7IEV2aWN0aW5nUXVldWUgfSBmcm9tICcuLi8uLi91dGlscy9FdmljdGluZ1F1ZXVlLmpzJztcbmltcG9ydCB0eXBlIHtcbiAgSU1ldHJpY3NTaW5rLFxuICBNZXRyaWNFbnRyeSxcbiAgTWV0cmljUXVlcnlPcHRpb25zLFxuICBNZXRyaWNRdWVyeVJlc3VsdCxcbiAgTWV0cmljU25hcHNob3QsXG59IGZyb20gJy4uL3R5cGVzLmpzJztcblxuZXhwb3J0IGNsYXNzIE1lbW9yeU1ldHJpY3NTaW5rIGltcGxlbWVudHMgSU1ldHJpY3NTaW5rIHtcbiAgcmVhZG9ubHkgbmFtZSA9ICdNZW1vcnlNZXRyaWNzU2luayc7XG4gIHByaXZhdGUgcmVhZG9ubHkgcXVldWU6IEV2aWN0aW5nUXVldWU8TWV0cmljU25hcHNob3Q+O1xuXG4gIGNvbnN0cnVjdG9yKG1heFNuYXBzaG90czogbnVtYmVyID0gMjQwKSB7XG4gICAgdGhpcy5xdWV1ZSA9IG5ldyBFdmljdGluZ1F1ZXVlPE1ldHJpY1NuYXBzaG90PihtYXhTbmFwc2hvdHMpO1xuICB9XG5cbiAgb25TbmFwc2hvdChzbmFwc2hvdDogTWV0cmljU25hcHNob3QpOiB2b2lkIHtcbiAgICB0aGlzLnF1ZXVlLnB1c2goc25hcHNob3QpO1xuICB9XG5cbiAgYXN5bmMgZmx1c2goKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgLy8gTm8tb3Ag4oCUIGluLW1lbW9yeSwgbm90aGluZyB0byBmbHVzaC5cbiAgfVxuXG4gIGFzeW5jIGNsb3NlKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRoaXMucXVldWUuY2xlYXIoKTtcbiAgfVxuXG4gIHF1ZXJ5KG9wdGlvbnM/OiBNZXRyaWNRdWVyeU9wdGlvbnMpOiBNZXRyaWNRdWVyeVJlc3VsdCB7XG4gICAgY29uc3QgbGF0ZXN0ID0gb3B0aW9ucz8ubGF0ZXN0ID8/IHRydWU7XG4gICAgY29uc3QgbGltaXQgPSBNYXRoLm1pbihNYXRoLm1heChvcHRpb25zPy5saW1pdCA/PyAxLCAwKSwgMTAwKTtcbiAgICBjb25zdCBvZmZzZXQgPSBNYXRoLm1heChvcHRpb25zPy5vZmZzZXQgPz8gMCwgMCk7XG5cbiAgICBjb25zdCBhbGxTbmFwc2hvdHMgPSB0aGlzLnF1ZXVlLnRvQXJyYXkoKTtcblxuICAgIC8vIENvbXB1dGUgYXZhaWxhYmlsaXR5IGJvdW5kcyBCRUZPUkUgZmlsdGVyaW5nXG4gICAgY29uc3Qgb2xkZXN0QXZhaWxhYmxlID0gYWxsU25hcHNob3RzLmxlbmd0aCA+IDAgPyBhbGxTbmFwc2hvdHNbMF0udGltZXN0YW1wIDogJyc7XG4gICAgY29uc3QgbmV3ZXN0QXZhaWxhYmxlID0gYWxsU25hcHNob3RzLmxlbmd0aCA+IDAgPyBhbGxTbmFwc2hvdHMuYXQoLTEpIS50aW1lc3RhbXAgOiAnJztcblxuICAgIC8vIElmIGxpbWl0IGlzIDAsIHJldHVybiBlbXB0eSByZXN1bHQgd2l0aCBib3VuZHNcbiAgICBpZiAobGltaXQgPT09IDApIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHNuYXBzaG90czogW10sXG4gICAgICAgIHRvdGFsOiAwLFxuICAgICAgICBoYXNNb3JlOiBmYWxzZSxcbiAgICAgICAgbGltaXQsXG4gICAgICAgIG9mZnNldCxcbiAgICAgICAgb2xkZXN0QXZhaWxhYmxlLFxuICAgICAgICBuZXdlc3RBdmFpbGFibGUsXG4gICAgICB9O1xuICAgIH1cblxuICAgIC8vIDEuIFNlbGVjdCBzbmFwc2hvdHMgYmFzZWQgb24gbGF0ZXN0IGZsYWdcbiAgICBsZXQgc25hcHNob3RzOiBNZXRyaWNTbmFwc2hvdFtdO1xuICAgIGlmIChsYXRlc3QpIHtcbiAgICAgIHNuYXBzaG90cyA9IGFsbFNuYXBzaG90cy5sZW5ndGggPiAwID8gW2FsbFNuYXBzaG90cy5hdCgtMSkhXSA6IFtdO1xuICAgIH0gZWxzZSB7XG4gICAgICBzbmFwc2hvdHMgPSBbLi4uYWxsU25hcHNob3RzXTtcbiAgICB9XG5cbiAgICAvLyAyLiBGaWx0ZXIgYnkgdGltZSByYW5nZVxuICAgIGlmIChvcHRpb25zPy5zaW5jZSkge1xuICAgICAgY29uc3Qgc2luY2UgPSBvcHRpb25zLnNpbmNlO1xuICAgICAgc25hcHNob3RzID0gc25hcHNob3RzLmZpbHRlcihzID0+IHMudGltZXN0YW1wID4gc2luY2UpO1xuICAgIH1cbiAgICBpZiAob3B0aW9ucz8udW50aWwpIHtcbiAgICAgIGNvbnN0IHVudGlsID0gb3B0aW9ucy51bnRpbDtcbiAgICAgIHNuYXBzaG90cyA9IHNuYXBzaG90cy5maWx0ZXIocyA9PiBzLnRpbWVzdGFtcCA8IHVudGlsKTtcbiAgICB9XG5cbiAgICAvLyAzLiBGaWx0ZXIgbWV0cmljcyB3aXRoaW4gZWFjaCBzbmFwc2hvdCBieSBuYW1lL3NvdXJjZS90eXBlXG4gICAgaWYgKG9wdGlvbnM/Lm5hbWVzIHx8IG9wdGlvbnM/LnNvdXJjZSB8fCBvcHRpb25zPy50eXBlKSB7XG4gICAgICBjb25zdCBmaWx0ZXJlZDogTWV0cmljU25hcHNob3RbXSA9IFtdO1xuICAgICAgZm9yIChjb25zdCBzbmFwc2hvdCBvZiBzbmFwc2hvdHMpIHtcbiAgICAgICAgY29uc3QgbWF0Y2hlZE1ldHJpY3MgPSBzbmFwc2hvdC5tZXRyaWNzLmZpbHRlcihtZXRyaWMgPT5cbiAgICAgICAgICBtYXRjaGVzTWV0cmljRmlsdGVycyhtZXRyaWMsIG9wdGlvbnMpLFxuICAgICAgICApO1xuICAgICAgICBpZiAobWF0Y2hlZE1ldHJpY3MubGVuZ3RoID4gMCkge1xuICAgICAgICAgIGZpbHRlcmVkLnB1c2goeyAuLi5zbmFwc2hvdCwgbWV0cmljczogbWF0Y2hlZE1ldHJpY3MgfSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHNuYXBzaG90cyA9IGZpbHRlcmVkO1xuICAgIH1cblxuICAgIC8vIDQuIFNvcnQgbmV3ZXN0LWZpcnN0IChkZXNjZW5kaW5nIHRpbWVzdGFtcClcbiAgICBzbmFwc2hvdHMuc29ydCgoYSwgYikgPT4gYi50aW1lc3RhbXAubG9jYWxlQ29tcGFyZShhLnRpbWVzdGFtcCkpO1xuXG4gICAgLy8gNS4gQ291bnQgdG90YWwgYmVmb3JlIHBhZ2luYXRpb25cbiAgICBjb25zdCB0b3RhbCA9IHNuYXBzaG90cy5sZW5ndGg7XG5cbiAgICAvLyA2LiBQYWdpbmF0ZVxuICAgIHNuYXBzaG90cyA9IHNuYXBzaG90cy5zbGljZShvZmZzZXQsIG9mZnNldCArIGxpbWl0KTtcblxuICAgIHJldHVybiB7XG4gICAgICBzbmFwc2hvdHMsXG4gICAgICB0b3RhbCxcbiAgICAgIGhhc01vcmU6IG9mZnNldCArIGxpbWl0IDwgdG90YWwsXG4gICAgICBsaW1pdCxcbiAgICAgIG9mZnNldCxcbiAgICAgIG9sZGVzdEF2YWlsYWJsZSxcbiAgICAgIG5ld2VzdEF2YWlsYWJsZSxcbiAgICB9O1xuICB9XG5cbiAgZ2V0U3RhdHMoKTogeyBzaXplOiBudW1iZXI7IGNhcGFjaXR5OiBudW1iZXIgfSB7XG4gICAgcmV0dXJuIHsgc2l6ZTogdGhpcy5xdWV1ZS5zaXplLCBjYXBhY2l0eTogdGhpcy5xdWV1ZS5jYXBhY2l0eSB9O1xuICB9XG59XG5cbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuLy8gSW50ZXJuYWwgaGVscGVyc1xuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbmZ1bmN0aW9uIG1hdGNoZXNNZXRyaWNGaWx0ZXJzKFxuICBtZXRyaWM6IE1ldHJpY0VudHJ5LFxuICBvcHRpb25zOiBNZXRyaWNRdWVyeU9wdGlvbnMsXG4pOiBib29sZWFuIHtcbiAgLy8gTmFtZSBmaWx0ZXI6IHByZWZpeCBtYXRjaCBpZiBlbmRzIHdpdGggJy4nIG9yICcuKicsIGVsc2UgZXhhY3QgbWF0Y2hcbiAgaWYgKG9wdGlvbnMubmFtZXMgJiYgb3B0aW9ucy5uYW1lcy5sZW5ndGggPiAwKSB7XG4gICAgY29uc3QgbWF0Y2hlZCA9IG9wdGlvbnMubmFtZXMuc29tZShuYW1lID0+IHtcbiAgICAgIGlmIChuYW1lLmVuZHNXaXRoKCcuJykgfHwgbmFtZS5lbmRzV2l0aCgnLionKSkge1xuICAgICAgICBjb25zdCBwcmVmaXggPSBuYW1lLmVuZHNXaXRoKCcuKicpID8gbmFtZS5zbGljZSgwLCAtMSkgOiBuYW1lO1xuICAgICAgICByZXR1cm4gbWV0cmljLm5hbWUuc3RhcnRzV2l0aChwcmVmaXgpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIG1ldHJpYy5uYW1lID09PSBuYW1lO1xuICAgIH0pO1xuICAgIGlmICghbWF0Y2hlZCkgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgLy8gU291cmNlIGZpbHRlcjogY2FzZS1pbnNlbnNpdGl2ZSBzdWJzdHJpbmcgbWF0Y2hcbiAgaWYgKG9wdGlvbnMuc291cmNlKSB7XG4gICAgY29uc3QgbmVlZGxlID0gb3B0aW9ucy5zb3VyY2UudG9Mb3dlckNhc2UoKTtcbiAgICBpZiAoIW1ldHJpYy5zb3VyY2UudG9Mb3dlckNhc2UoKS5pbmNsdWRlcyhuZWVkbGUpKSByZXR1cm4gZmFsc2U7XG4gIH1cblxuICAvLyBUeXBlIGZpbHRlcjogZXhhY3QgbWF0Y2hcbiAgaWYgKG9wdGlvbnMudHlwZSkge1xuICAgIGlmIChtZXRyaWMudHlwZSAhPT0gb3B0aW9ucy50eXBlKSByZXR1cm4gZmFsc2U7XG4gIH1cblxuICByZXR1cm4gdHJ1ZTtcbn1cbiJdfQ==