@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.
232 lines • 29.5 kB
JavaScript
/**
* Central coordinator for the Metrics Collection System.
*
* Registers collectors and sinks, runs periodic collection cycles,
* assembles immutable MetricSnapshot objects, and dispatches them
* to all registered sinks.
*/
export class MetricsManager {
collectors = [];
sinks = [];
config;
logger;
timer = null;
snapshotCounter = 0;
collectionsCompleted = 0;
collectorErrorsTotal = 0;
sinkErrorsTotal = 0;
lastCollectionDurationMs = 0;
closed = false;
processStartTime;
constructor(config, logger) {
this.config = config;
this.logger = logger;
this.processStartTime = new Date().toISOString();
}
// ---------------------------------------------------------------------------
// Public API
// ---------------------------------------------------------------------------
registerCollector(collector) {
this.assertOpen();
this.collectors.push({
collector,
consecutiveFailures: 0,
disabled: false,
});
}
registerSink(sink) {
this.assertOpen();
this.sinks.push(sink);
}
start() {
this.assertOpen();
if (this.timer !== null) {
this.logger.warn('MetricsManager.start() called but timer already running');
return;
}
if (this.config.collectionIntervalMs > 0) {
this.timer = setInterval(() => {
void this.collectNow();
}, this.config.collectionIntervalMs);
// Allow the process to exit even if the timer is still running
if (this.timer && typeof this.timer === 'object' && 'unref' in this.timer) {
this.timer.unref();
}
}
}
async collectNow() {
this.assertOpen();
const startTime = performance.now();
const { entries, errors } = await this.collectFromCollectors();
entries.push(...this.buildSelfMonitoringMetrics());
const durationMs = performance.now() - startTime;
const snapshot = {
id: `SNAP-${Date.now()}-${this.snapshotCounter++}`,
timestamp: new Date().toISOString(),
metrics: entries,
errors,
durationMs,
};
this.warnIfOversized(snapshot);
this.warnIfSlow(snapshot, durationMs);
this.deepFreezeSnapshot(snapshot);
this.dispatchToSinks(snapshot);
this.collectionsCompleted++;
this.lastCollectionDurationMs = durationMs;
return snapshot;
}
async collectFromCollectors() {
const entries = [];
const errors = [];
for (const record of this.collectors) {
if (record.disabled)
continue;
try {
const result = await Promise.resolve(record.collector.collect());
record.consecutiveFailures = 0;
entries.push(...result);
}
catch (err) {
record.consecutiveFailures++;
this.collectorErrorsTotal++;
const message = err instanceof Error ? err.message : String(err);
errors.push(`${record.collector.name}: ${message}`);
this.logger.warn(`Collector "${record.collector.name}" failed (${record.consecutiveFailures}/${this.config.collectorFailureThreshold})`, { error: message });
if (record.consecutiveFailures >= this.config.collectorFailureThreshold) {
record.disabled = true;
this.logger.error(`Collector "${record.collector.name}" disabled after ${record.consecutiveFailures} consecutive failures`);
}
}
}
return { entries, errors };
}
warnIfOversized(snapshot) {
const serializedSize = JSON.stringify(snapshot).length;
if (serializedSize > this.config.maxSnapshotSize) {
this.logger.warn(`Snapshot size ${serializedSize} bytes exceeds limit ${this.config.maxSnapshotSize}`, { snapshotId: snapshot.id, size: serializedSize });
}
}
warnIfSlow(snapshot, durationMs) {
if (durationMs > this.config.collectionDurationWarnMs && this.collectionsCompleted >= 3) {
this.logger.warn(`Collection took ${durationMs.toFixed(1)}ms (threshold: ${this.config.collectionDurationWarnMs}ms)`, { snapshotId: snapshot.id });
}
}
deepFreezeSnapshot(snapshot) {
Object.freeze(snapshot.metrics);
for (const entry of snapshot.metrics) {
if (entry.value !== null && typeof entry.value === 'object') {
Object.freeze(entry.value);
}
Object.freeze(entry);
}
Object.freeze(snapshot.errors);
Object.freeze(snapshot);
}
dispatchToSinks(snapshot) {
for (const sink of this.sinks) {
try {
sink.onSnapshot(snapshot);
}
catch (err) {
this.sinkErrorsTotal++;
const message = err instanceof Error ? err.message : String(err);
this.logger.warn(`Sink "${sink.name}" failed: ${message}`);
}
}
}
async close() {
if (this.closed)
return;
// Stop timer
if (this.timer !== null) {
clearInterval(this.timer);
this.timer = null;
}
try {
// Final collection — best-effort, should not prevent cleanup
await this.collectNow();
}
finally {
this.closed = true;
// Flush and close all sinks
await Promise.allSettled(this.sinks.map(s => s.flush()));
await Promise.allSettled(this.sinks.map(s => s.close()));
}
}
getManagerStats() {
return {
collectionsCompleted: this.collectionsCompleted,
collectorErrorsTotal: this.collectorErrorsTotal,
sinkErrorsTotal: this.sinkErrorsTotal,
lastCollectionDurationMs: this.lastCollectionDurationMs,
collectorsRegistered: this.collectors.length,
sinksRegistered: this.sinks.length,
disabledCollectors: this.collectors.filter(r => r.disabled).length,
processStartTime: this.processStartTime,
};
}
// ---------------------------------------------------------------------------
// Internals
// ---------------------------------------------------------------------------
assertOpen() {
if (this.closed) {
throw new Error('MetricsManager is closed');
}
}
buildSelfMonitoringMetrics() {
const source = 'MetricsManager';
const unit = 'count';
return [
{
type: 'gauge',
name: 'metrics.manager.collectors_registered',
source,
unit,
value: this.collectors.length,
},
{
type: 'gauge',
name: 'metrics.manager.sinks_registered',
source,
unit,
value: this.sinks.length,
},
{
type: 'counter',
name: 'metrics.manager.collector_errors_total',
source,
unit,
value: this.collectorErrorsTotal,
},
{
type: 'counter',
name: 'metrics.manager.sink_errors_total',
source,
unit,
value: this.sinkErrorsTotal,
},
{
type: 'gauge',
name: 'metrics.manager.last_collection_duration_ms',
source,
unit: 'milliseconds',
value: this.lastCollectionDurationMs,
},
{
type: 'counter',
name: 'metrics.manager.snapshots_taken_total',
source,
unit,
value: this.snapshotCounter,
},
{
type: 'gauge',
name: 'metrics.manager.disabled_collectors',
source,
unit,
value: this.collectors.filter(r => r.disabled).length,
},
];
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTWV0cmljc01hbmFnZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvbWV0cmljcy9NZXRyaWNzTWFuYWdlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7O0dBTUc7QUFpQkgsTUFBTSxPQUFPLGNBQWM7SUFDUixVQUFVLEdBQXNCLEVBQUUsQ0FBQztJQUNuQyxLQUFLLEdBQW1CLEVBQUUsQ0FBQztJQUMzQixNQUFNLENBQXVCO0lBQzdCLE1BQU0sQ0FBVTtJQUV6QixLQUFLLEdBQTBDLElBQUksQ0FBQztJQUNwRCxlQUFlLEdBQUcsQ0FBQyxDQUFDO0lBQ3BCLG9CQUFvQixHQUFHLENBQUMsQ0FBQztJQUN6QixvQkFBb0IsR0FBRyxDQUFDLENBQUM7SUFDekIsZUFBZSxHQUFHLENBQUMsQ0FBQztJQUNwQix3QkFBd0IsR0FBRyxDQUFDLENBQUM7SUFDN0IsTUFBTSxHQUFHLEtBQUssQ0FBQztJQUNOLGdCQUFnQixDQUFTO0lBRTFDLFlBQVksTUFBNEIsRUFBRSxNQUFlO1FBQ3ZELElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDO1FBQ3JCLElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDO1FBQ3JCLElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxJQUFJLElBQUksRUFBRSxDQUFDLFdBQVcsRUFBRSxDQUFDO0lBQ25ELENBQUM7SUFFRCw4RUFBOEU7SUFDOUUsYUFBYTtJQUNiLDhFQUE4RTtJQUU5RSxpQkFBaUIsQ0FBQyxTQUEyQjtRQUMzQyxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7UUFDbEIsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUM7WUFDbkIsU0FBUztZQUNULG1CQUFtQixFQUFFLENBQUM7WUFDdEIsUUFBUSxFQUFFLEtBQUs7U0FDaEIsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVELFlBQVksQ0FBQyxJQUFrQjtRQUM3QixJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7UUFDbEIsSUFBSSxD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RUFBRSxTQUFrQjtnQkFDeEIsSUFBSSxFQUFFLHdDQUF3QztnQkFDOUMsTUFBTTtnQkFDTixJQUFJO2dCQUNKLEtBQUssRUFBRSxJQUFJLENBQUMsb0JBQW9CO2FBQ2pDO1lBQ0Q7Z0JBQ0UsSUFBSSxFQUFFLFNBQWtCO2dCQUN4QixJQUFJLEVBQUUsbUNBQW1DO2dCQUN6QyxNQUFNO2dCQUNOLElBQUk7Z0JBQ0osS0FBSyxFQUFFLElBQUksQ0FBQyxlQUFlO2FBQzVCO1lBQ0Q7Z0JBQ0UsSUFBSSxFQUFFLE9BQWdCO2dCQUN0QixJQUFJLEVBQUUsNkNBQTZDO2dCQUNuRCxNQUFNO2dCQUNOLElBQUksRUFBRSxjQUF1QjtnQkFDN0IsS0FBSyxFQUFFLElBQUksQ0FBQyx3QkFBd0I7YUFDckM7WUFDRDtnQkFDRSxJQUFJLEVBQUUsU0FBa0I7Z0JBQ3hCLElBQUksRUFBRSx1Q0FBdUM7Z0JBQzdDLE1BQU07Z0JBQ04sSUFBSTtnQkFDSixLQUFLLEVBQUUsSUFBSSxDQUFDLGVBQWU7YUFDNUI7WUFDRDtnQkFDRSxJQUFJLEVBQUUsT0FBZ0I7Z0JBQ3RCLElBQUksRUFBRSxxQ0FBcUM7Z0JBQzNDLE1BQU07Z0JBQ04sSUFBSTtnQkFDSixLQUFLLEVBQUUsSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLENBQUMsTUFBTTthQUN0RDtTQUNGLENBQUM7SUFDSixDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIENlbnRyYWwgY29vcmRpbmF0b3IgZm9yIHRoZSBNZXRyaWNzIENvbGxlY3Rpb24gU3lzdGVtLlxuICpcbiAqIFJlZ2lzdGVycyBjb2xsZWN0b3JzIGFuZCBzaW5rcywgcnVucyBwZXJpb2RpYyBjb2xsZWN0aW9uIGN5Y2xlcyxcbiAqIGFzc2VtYmxlcyBpbW11dGFibGUgTWV0cmljU25hcHNob3Qgb2JqZWN0cywgYW5kIGRpc3BhdGNoZXMgdGhlbVxuICogdG8gYWxsIHJlZ2lzdGVyZWQgc2lua3MuXG4gKi9cblxuaW1wb3J0IHR5cGUgeyBJTG9nZ2VyIH0gZnJvbSAnLi4vdHlwZXMvSUxvZ2dlci5qcyc7XG5pbXBvcnQgdHlwZSB7XG4gIElNZXRyaWNDb2xsZWN0b3IsXG4gIElNZXRyaWNzU2luayxcbiAgTWV0cmljRW50cnksXG4gIE1ldHJpY1NuYXBzaG90LFxuICBNZXRyaWNzTWFuYWdlckNvbmZpZyxcbn0gZnJvbSAnLi90eXBlcy5qcyc7XG5cbmludGVyZmFjZSBDb2xsZWN0b3JSZWNvcmQge1xuICBjb2xsZWN0b3I6IElNZXRyaWNDb2xsZWN0b3I7XG4gIGNvbnNlY3V0aXZlRmFpbHVyZXM6IG51bWJlcjtcbiAgZGlzYWJsZWQ6IGJvb2xlYW47XG59XG5cbmV4cG9ydCBjbGFzcyBNZXRyaWNzTWFuYWdlciB7XG4gIHByaXZhdGUgcmVhZG9ubHkgY29sbGVjdG9yczogQ29sbGVjdG9yUmVjb3JkW10gPSBbXTtcbiAgcHJpdmF0ZSByZWFkb25seSBzaW5rczogSU1ldHJpY3NTaW5rW10gPSBbXTtcbiAgcHJpdmF0ZSByZWFkb25seSBjb25maWc6IE1ldHJpY3NNYW5hZ2VyQ29uZmlnO1xuICBwcml2YXRlIHJlYWRvbmx5IGxvZ2dlcjogSUxvZ2dlcjtcblxuICBwcml2YXRlIHRpbWVyOiBSZXR1cm5UeXBlPHR5cGVvZiBzZXRJbnRlcnZhbD4gfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSBzbmFwc2hvdENvdW50ZXIgPSAwO1xuICBwcml2YXRlIGNvbGxlY3Rpb25zQ29tcGxldGVkID0gMDtcbiAgcHJpdmF0ZSBjb2xsZWN0b3JFcnJvcnNUb3RhbCA9IDA7XG4gIHByaXZhdGUgc2lua0Vycm9yc1RvdGFsID0gMDtcbiAgcHJpdmF0ZSBsYXN0Q29sbGVjdGlvbkR1cmF0aW9uTXMgPSAwO1xuICBwcml2YXRlIGNsb3NlZCA9IGZhbHNlO1xuICBwcml2YXRlIHJlYWRvbmx5IHByb2Nlc3NTdGFydFRpbWU6IHN0cmluZztcblxuICBjb25zdHJ1Y3Rvcihjb25maWc6IE1ldHJpY3NNYW5hZ2VyQ29uZmlnLCBsb2dnZXI6IElMb2dnZXIpIHtcbiAgICB0aGlzLmNvbmZpZyA9IGNvbmZpZztcbiAgICB0aGlzLmxvZ2dlciA9IGxvZ2dlcjtcbiAgICB0aGlzLnByb2Nlc3NTdGFydFRpbWUgPSBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCk7XG4gIH1cblxuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgLy8gUHVibGljIEFQSVxuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuICByZWdpc3RlckNvbGxlY3Rvcihjb2xsZWN0b3I6IElNZXRyaWNDb2xsZWN0b3IpOiB2b2lkIHtcbiAgICB0aGlzLmFzc2VydE9wZW4oKTtcbiAgICB0aGlzLmNvbGxlY3RvcnMucHVzaCh7XG4gICAgICBjb2xsZWN0b3IsXG4gICAgICBjb25zZWN1dGl2ZUZhaWx1cmVzOiAwLFxuICAgICAgZGlzYWJsZWQ6IGZhbHNlLFxuICAgIH0pO1xuICB9XG5cbiAgcmVnaXN0ZXJTaW5rKHNpbms6IElNZXRyaWNzU2luayk6IHZvaWQge1xuICAgIHRoaXMuYXNzZXJ0T3BlbigpO1xuICAgIHRoaXMuc2lua3MucHVzaChzaW5rKTtcbiAgfVxuXG4gIHN0YXJ0KCk6IHZvaWQge1xuICAgIHRoaXMuYXNzZXJ0T3BlbigpO1xuICAgIGlmICh0aGlzLnRpbWVyICE9PSBudWxsKSB7XG4gICAgICB0aGlzLmxvZ2dlci53YXJuKCdNZXRyaWNzTWFuYWdlci5zdGFydCgpIGNhbGxlZCBidXQgdGltZXIgYWxyZWFkeSBydW5uaW5nJyk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuY29uZmlnLmNvbGxlY3Rpb25JbnRlcnZhbE1zID4gMCkge1xuICAgICAgdGhpcy50aW1lciA9IHNldEludGVydmFsKCgpID0+IHtcbiAgICAgICAgdm9pZCB0aGlzLmNvbGxlY3ROb3coKTtcbiAgICAgIH0sIHRoaXMuY29uZmlnLmNvbGxlY3Rpb25JbnRlcnZhbE1zKTtcblxuICAgICAgLy8gQWxsb3cgdGhlIHByb2Nlc3MgdG8gZXhpdCBldmVuIGlmIHRoZSB0aW1lciBpcyBzdGlsbCBydW5uaW5nXG4gICAgICBpZiAodGhpcy50aW1lciAmJiB0eXBlb2YgdGhpcy50aW1lciA9PT0gJ29iamVjdCcgJiYgJ3VucmVmJyBpbiB0aGlzLnRpbWVyKSB7XG4gICAgICAgIHRoaXMudGltZXIudW5yZWYoKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBhc3luYyBjb2xsZWN0Tm93KCk6IFByb21pc2U8TWV0cmljU25hcHNob3Q+IHtcbiAgICB0aGlzLmFzc2VydE9wZW4oKTtcblxuICAgIGNvbnN0IHN0YXJ0VGltZSA9IHBlcmZvcm1hbmNlLm5vdygpO1xuICAgIGNvbnN0IHsgZW50cmllcywgZXJyb3JzIH0gPSBhd2FpdCB0aGlzLmNvbGxlY3RGcm9tQ29sbGVjdG9ycygpO1xuICAgIGVudHJpZXMucHVzaCguLi50aGlzLmJ1aWxkU2VsZk1vbml0b3JpbmdNZXRyaWNzKCkpO1xuXG4gICAgY29uc3QgZHVyYXRpb25NcyA9IHBlcmZvcm1hbmNlLm5vdygpIC0gc3RhcnRUaW1lO1xuICAgIGNvbnN0IHNuYXBzaG90OiBNZXRyaWNTbmFwc2hvdCA9IHtcbiAgICAgIGlkOiBgU05BUC0ke0RhdGUubm93KCl9LSR7dGhpcy5zbmFwc2hvdENvdW50ZXIrK31gLFxuICAgICAgdGltZXN0YW1wOiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCksXG4gICAgICBtZXRyaWNzOiBlbnRyaWVzLFxuICAgICAgZXJyb3JzLFxuICAgICAgZHVyYXRpb25NcyxcbiAgICB9O1xuXG4gICAgdGhpcy53YXJuSWZPdmVyc2l6ZWQoc25hcHNob3QpO1xuICAgIHRoaXMud2FybklmU2xvdyhzbmFwc2hvdCwgZHVyYXRpb25Ncyk7XG4gICAgdGhpcy5kZWVwRnJlZXplU25hcHNob3Qoc25hcHNob3QpO1xuICAgIHRoaXMuZGlzcGF0Y2hUb1NpbmtzKHNuYXBzaG90KTtcblxuICAgIHRoaXMuY29sbGVjdGlvbnNDb21wbGV0ZWQrKztcbiAgICB0aGlzLmxhc3RDb2xsZWN0aW9uRHVyYXRpb25NcyA9IGR1cmF0aW9uTXM7XG5cbiAgICByZXR1cm4gc25hcHNob3Q7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGNvbGxlY3RGcm9tQ29sbGVjdG9ycygpOiBQcm9taXNlPHsgZW50cmllczogTWV0cmljRW50cnlbXTsgZXJyb3JzOiBzdHJpbmdbXSB9PiB7XG4gICAgY29uc3QgZW50cmllczogTWV0cmljRW50cnlbXSA9IFtdO1xuICAgIGNvbnN0IGVycm9yczogc3RyaW5nW10gPSBbXTtcblxuICAgIGZvciAoY29uc3QgcmVjb3JkIG9mIHRoaXMuY29sbGVjdG9ycykge1xuICAgICAgaWYgKHJlY29yZC5kaXNhYmxlZCkgY29udGludWU7XG5cbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IFByb21pc2UucmVzb2x2ZShyZWNvcmQuY29sbGVjdG9yLmNvbGxlY3QoKSk7XG4gICAgICAgIHJlY29yZC5jb25zZWN1dGl2ZUZhaWx1cmVzID0gMDtcbiAgICAgICAgZW50cmllcy5wdXNoKC4uLnJlc3VsdCk7XG4gICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgcmVjb3JkLmNvbnNlY3V0aXZlRmFpbHVyZXMrKztcbiAgICAgICAgdGhpcy5jb2xsZWN0b3JFcnJvcnNUb3RhbCsrO1xuICAgICAgICBjb25zdCBtZXNzYWdlID0gZXJyIGluc3RhbmNlb2YgRXJyb3IgPyBlcnIubWVzc2FnZSA6IFN0cmluZyhlcnIpO1xuICAgICAgICBlcnJvcnMucHVzaChgJHtyZWNvcmQuY29sbGVjdG9yLm5hbWV9OiAke21lc3NhZ2V9YCk7XG5cbiAgICAgICAgdGhpcy5sb2dnZXIud2FybihcbiAgICAgICAgICBgQ29sbGVjdG9yIFwiJHtyZWNvcmQuY29sbGVjdG9yLm5hbWV9XCIgZmFpbGVkICgke3JlY29yZC5jb25zZWN1dGl2ZUZhaWx1cmVzfS8ke3RoaXMuY29uZmlnLmNvbGxlY3RvckZhaWx1cmVUaHJlc2hvbGR9KWAsXG4gICAgICAgICAgeyBlcnJvcjogbWVzc2FnZSB9LFxuICAgICAgICApO1xuXG4gICAgICAgIGlmIChyZWNvcmQuY29uc2VjdXRpdmVGYWlsdXJlcyA+PSB0aGlzLmNvbmZpZy5jb2xsZWN0b3JGYWlsdXJlVGhyZXNob2xkKSB7XG4gICAgICAgICAgcmVjb3JkLmRpc2FibGVkID0gdHJ1ZTtcbiAgICAgICAgICB0aGlzLmxvZ2dlci5lcnJvcihcbiAgICAgICAgICAgIGBDb2xsZWN0b3IgXCIke3JlY29yZC5jb2xsZWN0b3IubmFtZX1cIiBkaXNhYmxlZCBhZnRlciAke3JlY29yZC5jb25zZWN1dGl2ZUZhaWx1cmVzfSBjb25zZWN1dGl2ZSBmYWlsdXJlc2AsXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB7IGVudHJpZXMsIGVycm9ycyB9O1xuICB9XG5cbiAgcHJpdmF0ZSB3YXJuSWZPdmVyc2l6ZWQoc25hcHNob3Q6IE1ldHJpY1NuYXBzaG90KTogdm9pZCB7XG4gICAgY29uc3Qgc2VyaWFsaXplZFNpemUgPSBKU09OLnN0cmluZ2lmeShzbmFwc2hvdCkubGVuZ3RoO1xuICAgIGlmIChzZXJpYWxpemVkU2l6ZSA+IHRoaXMuY29uZmlnLm1heFNuYXBzaG90U2l6ZSkge1xuICAgICAgdGhpcy5sb2dnZXIud2FybihcbiAgICAgICAgYFNuYXBzaG90IHNpemUgJHtzZXJpYWxpemVkU2l6ZX0gYnl0ZXMgZXhjZWVkcyBsaW1pdCAke3RoaXMuY29uZmlnLm1heFNuYXBzaG90U2l6ZX1gLFxuICAgICAgICB7IHNuYXBzaG90SWQ6IHNuYXBzaG90LmlkLCBzaXplOiBzZXJpYWxpemVkU2l6ZSB9LFxuICAgICAgKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHdhcm5JZlNsb3coc25hcHNob3Q6IE1ldHJpY1NuYXBzaG90LCBkdXJhdGlvbk1zOiBudW1iZXIpOiB2b2lkIHtcbiAgICBpZiAoZHVyYXRpb25NcyA+IHRoaXMuY29uZmlnLmNvbGxlY3Rpb25EdXJhdGlvbldhcm5NcyAmJiB0aGlzLmNvbGxlY3Rpb25zQ29tcGxldGVkID49IDMpIHtcbiAgICAgIHRoaXMubG9nZ2VyLndhcm4oXG4gICAgICAgIGBDb2xsZWN0aW9uIHRvb2sgJHtkdXJhdGlvbk1zLnRvRml4ZWQoMSl9bXMgKHRocmVzaG9sZDogJHt0aGlzLmNvbmZpZy5jb2xsZWN0aW9uRHVyYXRpb25XYXJuTXN9bXMpYCxcbiAgICAgICAgeyBzbmFwc2hvdElkOiBzbmFwc2hvdC5pZCB9LFxuICAgICAgKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGRlZXBGcmVlemVTbmFwc2hvdChzbmFwc2hvdDogTWV0cmljU25hcHNob3QpOiB2b2lkIHtcbiAgICBPYmplY3QuZnJlZXplKHNuYXBzaG90Lm1ldHJpY3MpO1xuICAgIGZvciAoY29uc3QgZW50cnkgb2Ygc25hcHNob3QubWV0cmljcykge1xuICAgICAgaWYgKGVudHJ5LnZhbHVlICE9PSBudWxsICYmIHR5cGVvZiBlbnRyeS52YWx1ZSA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgT2JqZWN0LmZyZWV6ZShlbnRyeS52YWx1ZSk7XG4gICAgICB9XG4gICAgICBPYmplY3QuZnJlZXplKGVudHJ5KTtcbiAgICB9XG4gICAgT2JqZWN0LmZyZWV6ZShzbmFwc2hvdC5lcnJvcnMpO1xuICAgIE9iamVjdC5mcmVlemUoc25hcHNob3QpO1xuICB9XG5cbiAgcHJpdmF0ZSBkaXNwYXRjaFRvU2lua3Moc25hcHNob3Q6IE1ldHJpY1NuYXBzaG90KTogdm9pZCB7XG4gICAgZm9yIChjb25zdCBzaW5rIG9mIHRoaXMuc2lua3MpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIHNpbmsub25TbmFwc2hvdChzbmFwc2hvdCk7XG4gICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgdGhpcy5zaW5rRXJyb3JzVG90YWwrKztcbiAgICAgICAgY29uc3QgbWVzc2FnZSA9IGVyciBpbnN0YW5jZW9mIEVycm9yID8gZXJyLm1lc3NhZ2UgOiBTdHJpbmcoZXJyKTtcbiAgICAgICAgdGhpcy5sb2dnZXIud2FybihgU2luayBcIiR7c2luay5uYW1lfVwiIGZhaWxlZDogJHttZXNzYWdlfWApO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGFzeW5jIGNsb3NlKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICh0aGlzLmNsb3NlZCkgcmV0dXJuO1xuXG4gICAgLy8gU3RvcCB0aW1lclxuICAgIGlmICh0aGlzLnRpbWVyICE9PSBudWxsKSB7XG4gICAgICBjbGVhckludGVydmFsKHRoaXMudGltZXIpO1xuICAgICAgdGhpcy50aW1lciA9IG51bGw7XG4gICAgfVxuXG4gICAgdHJ5IHtcbiAgICAgIC8vIEZpbmFsIGNvbGxlY3Rpb24g4oCUIGJlc3QtZWZmb3J0LCBzaG91bGQgbm90IHByZXZlbnQgY2xlYW51cFxuICAgICAgYXdhaXQgdGhpcy5jb2xsZWN0Tm93KCk7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIHRoaXMuY2xvc2VkID0gdHJ1ZTtcblxuICAgICAgLy8gRmx1c2ggYW5kIGNsb3NlIGFsbCBzaW5rc1xuICAgICAgYXdhaXQgUHJvbWlzZS5hbGxTZXR0bGVkKHRoaXMuc2lua3MubWFwKHMgPT4gcy5mbHVzaCgpKSk7XG4gICAgICBhd2FpdCBQcm9taXNlLmFsbFNldHRsZWQodGhpcy5zaW5rcy5tYXAocyA9PiBzLmNsb3NlKCkpKTtcbiAgICB9XG4gIH1cblxuICBnZXRNYW5hZ2VyU3RhdHMoKToge1xuICAgIGNvbGxlY3Rpb25zQ29tcGxldGVkOiBudW1iZXI7XG4gICAgY29sbGVjdG9yRXJyb3JzVG90YWw6IG51bWJlcjtcbiAgICBzaW5rRXJyb3JzVG90YWw6IG51bWJlcjtcbiAgICBsYXN0Q29sbGVjdGlvbkR1cmF0aW9uTXM6IG51bWJlcjtcbiAgICBjb2xsZWN0b3JzUmVnaXN0ZXJlZDogbnVtYmVyO1xuICAgIHNpbmtzUmVnaXN0ZXJlZDogbnVtYmVyO1xuICAgIGRpc2FibGVkQ29sbGVjdG9yczogbnVtYmVyO1xuICAgIHByb2Nlc3NTdGFydFRpbWU6IHN0cmluZztcbiAgfSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGNvbGxlY3Rpb25zQ29tcGxldGVkOiB0aGlzLmNvbGxlY3Rpb25zQ29tcGxldGVkLFxuICAgICAgY29sbGVjdG9yRXJyb3JzVG90YWw6IHRoaXMuY29sbGVjdG9yRXJyb3JzVG90YWwsXG4gICAgICBzaW5rRXJyb3JzVG90YWw6IHRoaXMuc2lua0Vycm9yc1RvdGFsLFxuICAgICAgbGFzdENvbGxlY3Rpb25EdXJhdGlvbk1zOiB0aGlzLmxhc3RDb2xsZWN0aW9uRHVyYXRpb25NcyxcbiAgICAgIGNvbGxlY3RvcnNSZWdpc3RlcmVkOiB0aGlzLmNvbGxlY3RvcnMubGVuZ3RoLFxuICAgICAgc2lua3NSZWdpc3RlcmVkOiB0aGlzLnNpbmtzLmxlbmd0aCxcbiAgICAgIGRpc2FibGVkQ29sbGVjdG9yczogdGhpcy5jb2xsZWN0b3JzLmZpbHRlcihyID0+IHIuZGlzYWJsZWQpLmxlbmd0aCxcbiAgICAgIHByb2Nlc3NTdGFydFRpbWU6IHRoaXMucHJvY2Vzc1N0YXJ0VGltZSxcbiAgICB9O1xuICB9XG5cbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gIC8vIEludGVybmFsc1xuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuICBwcml2YXRlIGFzc2VydE9wZW4oKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuY2xvc2VkKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ01ldHJpY3NNYW5hZ2VyIGlzIGNsb3NlZCcpO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgYnVpbGRTZWxmTW9uaXRvcmluZ01ldHJpY3MoKTogTWV0cmljRW50cnlbXSB7XG4gICAgY29uc3Qgc291cmNlID0gJ01ldHJpY3NNYW5hZ2VyJztcbiAgICBjb25zdCB1bml0ID0gJ2NvdW50JyBhcyBjb25zdDtcblxuICAgIHJldHVybiBbXG4gICAgICB7XG4gICAgICAgIHR5cGU6ICdnYXVnZScgYXMgY29uc3QsXG4gICAgICAgIG5hbWU6ICdtZXRyaWNzLm1hbmFnZXIuY29sbGVjdG9yc19yZWdpc3RlcmVkJyxcbiAgICAgICAgc291cmNlLFxuICAgICAgICB1bml0LFxuICAgICAgICB2YWx1ZTogdGhpcy5jb2xsZWN0b3JzLmxlbmd0aCxcbiAgICAgIH0sXG4gICAgICB7XG4gICAgICAgIHR5cGU6ICdnYXVnZScgYXMgY29uc3QsXG4gICAgICAgIG5hbWU6ICdtZXRyaWNzLm1hbmFnZXIuc2lua3NfcmVnaXN0ZXJlZCcsXG4gICAgICAgIHNvdXJjZSxcbiAgICAgICAgdW5pdCxcbiAgICAgICAgdmFsdWU6IHRoaXMuc2lua3MubGVuZ3RoLFxuICAgICAgfSxcbiAgICAgIHtcbiAgICAgICAgdHlwZTogJ2NvdW50ZXInIGFzIGNvbnN0LFxuICAgICAgICBuYW1lOiAnbWV0cmljcy5tYW5hZ2VyLmNvbGxlY3Rvcl9lcnJvcnNfdG90YWwnLFxuICAgICAgICBzb3VyY2UsXG4gICAgICAgIHVuaXQsXG4gICAgICAgIHZhbHVlOiB0aGlzLmNvbGxlY3RvckVycm9yc1RvdGFsLFxuICAgICAgfSxcbiAgICAgIHtcbiAgICAgICAgdHlwZTogJ2NvdW50ZXInIGFzIGNvbnN0LFxuICAgICAgICBuYW1lOiAnbWV0cmljcy5tYW5hZ2VyLnNpbmtfZXJyb3JzX3RvdGFsJyxcbiAgICAgICAgc291cmNlLFxuICAgICAgICB1bml0LFxuICAgICAgICB2YWx1ZTogdGhpcy5zaW5rRXJyb3JzVG90YWwsXG4gICAgICB9LFxuICAgICAge1xuICAgICAgICB0eXBlOiAnZ2F1Z2UnIGFzIGNvbnN0LFxuICAgICAgICBuYW1lOiAnbWV0cmljcy5tYW5hZ2VyLmxhc3RfY29sbGVjdGlvbl9kdXJhdGlvbl9tcycsXG4gICAgICAgIHNvdXJjZSxcbiAgICAgICAgdW5pdDogJ21pbGxpc2Vjb25kcycgYXMgY29uc3QsXG4gICAgICAgIHZhbHVlOiB0aGlzLmxhc3RDb2xsZWN0aW9uRHVyYXRpb25NcyxcbiAgICAgIH0sXG4gICAgICB7XG4gICAgICAgIHR5cGU6ICdjb3VudGVyJyBhcyBjb25zdCxcbiAgICAgICAgbmFtZTogJ21ldHJpY3MubWFuYWdlci5zbmFwc2hvdHNfdGFrZW5fdG90YWwnLFxuICAgICAgICBzb3VyY2UsXG4gICAgICAgIHVuaXQsXG4gICAgICAgIHZhbHVlOiB0aGlzLnNuYXBzaG90Q291bnRlcixcbiAgICAgIH0sXG4gICAgICB7XG4gICAgICAgIHR5cGU6ICdnYXVnZScgYXMgY29uc3QsXG4gICAgICAgIG5hbWU6ICdtZXRyaWNzLm1hbmFnZXIuZGlzYWJsZWRfY29sbGVjdG9ycycsXG4gICAgICAgIHNvdXJjZSxcbiAgICAgICAgdW5pdCxcbiAgICAgICAgdmFsdWU6IHRoaXMuY29sbGVjdG9ycy5maWx0ZXIociA9PiByLmRpc2FibGVkKS5sZW5ndGgsXG4gICAgICB9LFxuICAgIF07XG4gIH1cbn1cbiJdfQ==