@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.
349 lines • 53.2 kB
JavaScript
/**
* Configuration for Enhanced Index system
*
* Centralizes all tunable parameters for the index, NLP scoring,
* and relationship discovery systems.
*
* FIXES IMPLEMENTED (Issue #1100):
* - Added all magic numbers from Enhanced Index to configuration
* - Centralized thresholds, limits, and timeouts
*/
import * as fs from 'fs/promises';
import * as fsSync from 'fs';
import * as path from 'path';
import { logger } from '../../utils/logger.js';
import { SecurityMonitor } from '../../security/securityMonitor.js';
import { deepMerge } from '../../utils/deepMerge.js';
export class IndexConfigManager {
config;
configPath;
defaultConfig = {
index: {
ttlMinutes: 5,
rebuildOnStartup: false,
persistToDisk: true,
lockTimeoutMs: 5000,
maxConcurrentBuilds: 1
},
performance: {
maxElementsForFullMatrix: 100,
maxSimilarityComparisons: 10000,
maxRelationshipComparisons: 100,
similarityBatchSize: 50,
similarityThreshold: 0.5,
defaultSimilarityThreshold: 0.5,
defaultSimilarLimit: 10,
defaultVerbSearchLimit: 20,
parallelProcessing: true,
circuitBreakerTimeoutMs: 5000
},
sampling: {
baseSampleSize: 10,
sampleRatio: 0.1,
clusterSampleLimit: 20
},
nlp: {
cacheExpiryMinutes: 5,
minTokenLength: 2,
entropyBands: {
low: 3.0,
moderate: 4.5,
high: 6.0
},
jaccardThresholds: {
low: 0.2,
moderate: 0.4,
high: 0.6
}
},
verbs: {
confidenceThreshold: 0.5,
maxRecursionDepth: 3,
maxElementsPerVerb: 10,
includeSynonyms: true
},
memory: {
maxCacheSize: 1000,
enableGarbageCollection: true,
gcIntervalMinutes: 30,
cleanupIntervalMinutes: 5,
staleIndexMultiplier: 2
}
};
constructor() {
const portfolioPath = path.join(process.env.HOME || '', '.dollhouse', 'portfolio');
this.configPath = path.join(portfolioPath, '.config', 'index-config.json');
this.config = { ...this.defaultConfig };
// FIX: Race condition - loadConfig is async but called sync in constructor
// Now using synchronous loading in constructor
this.loadConfigSync();
}
/**
* Load configuration from disk synchronously (for constructor)
*/
loadConfigSync() {
try {
// Check if file exists
if (!fsSync.existsSync(this.configPath)) {
logger.info('No config file found, using defaults', { path: this.configPath });
return;
}
const configData = fsSync.readFileSync(this.configPath, 'utf-8');
const loadedConfig = JSON.parse(configData);
// Deep merge with defaults to handle missing fields
// FIX: Loaded config should override defaults
this.config = deepMerge(this.defaultConfig, loadedConfig);
logger.info('Index configuration loaded', { path: this.configPath });
}
catch (error) {
logger.warn('Failed to load index config, using defaults', {
error: error instanceof Error ? error.message : String(error),
path: this.configPath
});
}
}
/**
* Save current configuration to disk
*/
async saveConfig() {
try {
const configDir = path.dirname(this.configPath);
await fs.mkdir(configDir, { recursive: true });
await fs.writeFile(this.configPath, JSON.stringify(this.config, null, 2), 'utf-8');
logger.debug('Index configuration saved', { path: this.configPath });
}
catch (error) {
logger.error('Failed to save index config', { error });
}
}
/**
* Get the current configuration
*/
getConfig() {
return { ...this.config };
}
/**
* Update configuration with validation
*/
async updateConfig(updates) {
// Validate the updates before applying
this.validateConfig(updates);
this.config = deepMerge(this.config, updates);
await this.saveConfig();
logger.info('Index configuration updated', { updates });
// Log successful update
SecurityMonitor.logSecurityEvent({
type: 'RULE_ENGINE_CONFIG_UPDATE',
severity: 'LOW',
source: 'IndexConfigManager.updateConfig',
details: 'Index configuration update successful',
additionalData: {
configType: 'index',
updatedFields: Object.keys(updates)
}
});
}
/**
* Validate configuration values
* Throws an error if any value is invalid
*/
validateConfig(config) {
// Validate performance thresholds (0-1 range)
if (config.performance) {
const perf = config.performance;
// Similarity thresholds must be between 0 and 1
if (perf.similarityThreshold !== undefined) {
if (perf.similarityThreshold < 0 || perf.similarityThreshold > 1) {
throw new Error(`similarityThreshold must be between 0 and 1, got ${perf.similarityThreshold}`);
}
}
if (perf.defaultSimilarityThreshold !== undefined) {
if (perf.defaultSimilarityThreshold < 0 || perf.defaultSimilarityThreshold > 1) {
throw new Error(`defaultSimilarityThreshold must be between 0 and 1, got ${perf.defaultSimilarityThreshold}`);
}
}
// Positive integer validations
if (perf.maxElementsForFullMatrix !== undefined && perf.maxElementsForFullMatrix <= 0) {
throw new Error(`maxElementsForFullMatrix must be positive, got ${perf.maxElementsForFullMatrix}`);
}
if (perf.maxSimilarityComparisons !== undefined && perf.maxSimilarityComparisons <= 0) {
throw new Error(`maxSimilarityComparisons must be positive, got ${perf.maxSimilarityComparisons}`);
}
if (perf.maxRelationshipComparisons !== undefined && perf.maxRelationshipComparisons <= 0) {
throw new Error(`maxRelationshipComparisons must be positive, got ${perf.maxRelationshipComparisons}`);
}
if (perf.similarityBatchSize !== undefined && perf.similarityBatchSize <= 0) {
throw new Error(`similarityBatchSize must be positive, got ${perf.similarityBatchSize}`);
}
if (perf.defaultSimilarLimit !== undefined && perf.defaultSimilarLimit <= 0) {
throw new Error(`defaultSimilarLimit must be positive, got ${perf.defaultSimilarLimit}`);
}
if (perf.defaultVerbSearchLimit !== undefined && perf.defaultVerbSearchLimit <= 0) {
throw new Error(`defaultVerbSearchLimit must be positive, got ${perf.defaultVerbSearchLimit}`);
}
if (perf.circuitBreakerTimeoutMs !== undefined && perf.circuitBreakerTimeoutMs <= 0) {
throw new Error(`circuitBreakerTimeoutMs must be positive, got ${perf.circuitBreakerTimeoutMs}`);
}
}
// Validate sampling configuration
if (config.sampling) {
const sampling = config.sampling;
// Sample ratio must be between 0 and 1
if (sampling.sampleRatio !== undefined) {
if (sampling.sampleRatio <= 0 || sampling.sampleRatio > 1) {
throw new Error(`sampleRatio must be between 0 and 1, got ${sampling.sampleRatio}`);
}
}
if (sampling.baseSampleSize !== undefined && sampling.baseSampleSize <= 0) {
throw new Error(`baseSampleSize must be positive, got ${sampling.baseSampleSize}`);
}
if (sampling.clusterSampleLimit !== undefined && sampling.clusterSampleLimit <= 0) {
throw new Error(`clusterSampleLimit must be positive, got ${sampling.clusterSampleLimit}`);
}
}
// Validate NLP configuration
if (config.nlp) {
const nlp = config.nlp;
// Jaccard thresholds must be between 0 and 1
if (nlp.jaccardThresholds) {
const jaccard = nlp.jaccardThresholds;
if (jaccard.low !== undefined && (jaccard.low < 0 || jaccard.low > 1)) {
throw new Error(`jaccardThresholds.low must be between 0 and 1, got ${jaccard.low}`);
}
if (jaccard.moderate !== undefined && (jaccard.moderate < 0 || jaccard.moderate > 1)) {
throw new Error(`jaccardThresholds.moderate must be between 0 and 1, got ${jaccard.moderate}`);
}
if (jaccard.high !== undefined && (jaccard.high < 0 || jaccard.high > 1)) {
throw new Error(`jaccardThresholds.high must be between 0 and 1, got ${jaccard.high}`);
}
}
// Entropy bands must be positive
if (nlp.entropyBands) {
const entropy = nlp.entropyBands;
if (entropy.low !== undefined && entropy.low < 0) {
throw new Error(`entropyBands.low must be non-negative, got ${entropy.low}`);
}
if (entropy.moderate !== undefined && entropy.moderate < 0) {
throw new Error(`entropyBands.moderate must be non-negative, got ${entropy.moderate}`);
}
if (entropy.high !== undefined && entropy.high < 0) {
throw new Error(`entropyBands.high must be non-negative, got ${entropy.high}`);
}
}
if (nlp.cacheExpiryMinutes !== undefined && nlp.cacheExpiryMinutes <= 0) {
throw new Error(`cacheExpiryMinutes must be positive, got ${nlp.cacheExpiryMinutes}`);
}
if (nlp.minTokenLength !== undefined && nlp.minTokenLength < 1) {
throw new Error(`minTokenLength must be at least 1, got ${nlp.minTokenLength}`);
}
}
// Validate verb configuration
if (config.verbs) {
const verbs = config.verbs;
if (verbs.confidenceThreshold !== undefined) {
if (verbs.confidenceThreshold < 0 || verbs.confidenceThreshold > 1) {
throw new Error(`confidenceThreshold must be between 0 and 1, got ${verbs.confidenceThreshold}`);
}
}
if (verbs.maxRecursionDepth !== undefined && verbs.maxRecursionDepth <= 0) {
throw new Error(`maxRecursionDepth must be positive, got ${verbs.maxRecursionDepth}`);
}
if (verbs.maxElementsPerVerb !== undefined && verbs.maxElementsPerVerb <= 0) {
throw new Error(`maxElementsPerVerb must be positive, got ${verbs.maxElementsPerVerb}`);
}
}
// Validate memory configuration
if (config.memory) {
const memory = config.memory;
if (memory.maxCacheSize !== undefined && memory.maxCacheSize <= 0) {
throw new Error(`maxCacheSize must be positive, got ${memory.maxCacheSize}`);
}
if (memory.gcIntervalMinutes !== undefined && memory.gcIntervalMinutes <= 0) {
throw new Error(`gcIntervalMinutes must be positive, got ${memory.gcIntervalMinutes}`);
}
if (memory.cleanupIntervalMinutes !== undefined && memory.cleanupIntervalMinutes <= 0) {
throw new Error(`cleanupIntervalMinutes must be positive, got ${memory.cleanupIntervalMinutes}`);
}
if (memory.staleIndexMultiplier !== undefined && memory.staleIndexMultiplier <= 0) {
throw new Error(`staleIndexMultiplier must be positive, got ${memory.staleIndexMultiplier}`);
}
}
// Validate index configuration
if (config.index) {
const index = config.index;
if (index.ttlMinutes !== undefined && index.ttlMinutes <= 0) {
throw new Error(`ttlMinutes must be positive, got ${index.ttlMinutes}`);
}
if (index.lockTimeoutMs !== undefined && index.lockTimeoutMs <= 0) {
throw new Error(`lockTimeoutMs must be positive, got ${index.lockTimeoutMs}`);
}
if (index.maxConcurrentBuilds !== undefined && index.maxConcurrentBuilds <= 0) {
throw new Error(`maxConcurrentBuilds must be positive, got ${index.maxConcurrentBuilds}`);
}
}
}
/**
* Reset to default configuration
*/
async resetToDefaults() {
// SECURITY FIX: Add audit logging for configuration reset (DMCP-SEC-006)
SecurityMonitor.logSecurityEvent({
type: 'RULE_ENGINE_CONFIG_UPDATE',
severity: 'MEDIUM', // Higher severity for full reset
source: 'IndexConfigManager.resetToDefaults',
details: 'Index configuration reset to defaults',
additionalData: {
configType: 'index',
action: 'reset'
}
});
this.config = { ...this.defaultConfig };
await this.saveConfig();
logger.info('Index configuration reset to defaults');
}
/**
* Get specific configuration value by path
*/
get(path) {
const parts = path.split('.');
let result = this.config;
for (const part of parts) {
if (result && typeof result === 'object' && part in result) {
result = result[part];
}
else {
return undefined;
}
}
return result;
}
/**
* Set specific configuration value by path
*/
async set(path, value) {
// SECURITY FIX: Add audit logging for direct config modifications (DMCP-SEC-006)
SecurityMonitor.logSecurityEvent({
type: 'RULE_ENGINE_CONFIG_UPDATE',
severity: 'LOW',
source: 'IndexConfigManager.set',
details: `Index configuration value set: ${path}`,
additionalData: {
configType: 'index',
path,
valueType: typeof value
}
});
const parts = path.split('.');
const lastPart = parts.pop();
let target = this.config;
for (const part of parts) {
if (!(part in target) || typeof target[part] !== 'object') {
target[part] = {};
}
target = target[part];
}
target[lastPart] = value;
await this.saveConfig();
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiSW5kZXhDb25maWcuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvcG9ydGZvbGlvL2NvbmZpZy9JbmRleENvbmZpZy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7O0dBU0c7QUFFSCxPQUFPLEtBQUssRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUNsQyxPQUFPLEtBQUssTUFBTSxNQUFNLElBQUksQ0FBQztBQUM3QixPQUFPLEtBQUssSUFBSSxNQUFNLE1BQU0sQ0FBQztBQUM3QixPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDL0MsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLG1DQUFtQyxDQUFDO0FBQ3BFLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQW1FckQsTUFBTSxPQUFPLGtCQUFrQjtJQUNyQixNQUFNLENBQXFCO0lBQzNCLFVBQVUsQ0FBUztJQUNuQixhQUFhLEdBQXVCO1FBQzFDLEtBQUssRUFBRTtZQUNMLFVBQVUsRUFBRSxDQUFDO1lBQ2IsZ0JBQWdCLEVBQUUsS0FBSztZQUN2QixhQUFhLEVBQUUsSUFBSTtZQUNuQixhQUFhLEVBQUUsSUFBSTtZQUNuQixtQkFBbUIsRUFBRSxDQUFDO1NBQ3ZCO1FBQ0QsV0FBVyxFQUFFO1lBQ1gsd0JBQXdCLEVBQUUsR0FBRztZQUM3Qix3QkFBd0IsRUFBRSxLQUFLO1lBQy9CLDBCQUEwQixFQUFFLEdBQUc7WUFDL0IsbUJBQW1CLEVBQUUsRUFBRTtZQUN2QixtQkFBbUIsRUFBRSxHQUFHO1lBQ3hCLDBCQUEwQixFQUFFLEdBQUc7WUFDL0IsbUJBQW1CLEVBQUUsRUFBRTtZQUN2QixzQkFBc0IsRUFBRSxFQUFFO1lBQzFCLGtCQUFrQixFQUFFLElBQUk7WUFDeEIsdUJBQXVCLEVBQUUsSUFBSTtTQUM5QjtRQUNELFFBQVEsRUFBRTtZQUNSLGNBQWMsRUFBRSxFQUFFO1lBQ2xCLFdBQVcsRUFBRSxHQUFHO1lB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Q0FBQyxLQUFLLFFBQVEsRUFBRSxDQUFDO2dCQUMxRCxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO1lBQ3BCLENBQUM7WUFDRCxNQUFNLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ3hCLENBQUM7UUFFRCxNQUFNLENBQUMsUUFBUSxDQUFDLEdBQUcsS0FBSyxDQUFDO1FBQ3pCLE1BQU0sSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO0lBQzFCLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQ29uZmlndXJhdGlvbiBmb3IgRW5oYW5jZWQgSW5kZXggc3lzdGVtXG4gKlxuICogQ2VudHJhbGl6ZXMgYWxsIHR1bmFibGUgcGFyYW1ldGVycyBmb3IgdGhlIGluZGV4LCBOTFAgc2NvcmluZyxcbiAqIGFuZCByZWxhdGlvbnNoaXAgZGlzY292ZXJ5IHN5c3RlbXMuXG4gKlxuICogRklYRVMgSU1QTEVNRU5URUQgKElzc3VlICMxMTAwKTpcbiAqIC0gQWRkZWQgYWxsIG1hZ2ljIG51bWJlcnMgZnJvbSBFbmhhbmNlZCBJbmRleCB0byBjb25maWd1cmF0aW9uXG4gKiAtIENlbnRyYWxpemVkIHRocmVzaG9sZHMsIGxpbWl0cywgYW5kIHRpbWVvdXRzXG4gKi9cblxuaW1wb3J0ICogYXMgZnMgZnJvbSAnZnMvcHJvbWlzZXMnO1xuaW1wb3J0ICogYXMgZnNTeW5jIGZyb20gJ2ZzJztcbmltcG9ydCAqIGFzIHBhdGggZnJvbSAncGF0aCc7XG5pbXBvcnQgeyBsb2dnZXIgfSBmcm9tICcuLi8uLi91dGlscy9sb2dnZXIuanMnO1xuaW1wb3J0IHsgU2VjdXJpdHlNb25pdG9yIH0gZnJvbSAnLi4vLi4vc2VjdXJpdHkvc2VjdXJpdHlNb25pdG9yLmpzJztcbmltcG9ydCB7IGRlZXBNZXJnZSB9IGZyb20gJy4uLy4uL3V0aWxzL2RlZXBNZXJnZS5qcyc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgSW5kZXhDb25maWd1cmF0aW9uIHtcbiAgLy8gSW5kZXggTWFuYWdlbWVudFxuICBpbmRleDoge1xuICAgIHR0bE1pbnV0ZXM6IG51bWJlcjsgICAgICAgICAgICAgICAgICAgIC8vIENhY2hlIFRUTCBmb3IgaW5kZXggKGRlZmF1bHQ6IDUpXG4gICAgcmVidWlsZE9uU3RhcnR1cDogYm9vbGVhbjsgICAgICAgICAgICAgLy8gRm9yY2UgcmVidWlsZCBvbiBzdGFydHVwIChkZWZhdWx0OiBmYWxzZSlcbiAgICBwZXJzaXN0VG9EaXNrOiBib29sZWFuOyAgICAgICAgICAgICAgICAvLyBTYXZlIGluZGV4IHRvIGRpc2sgKGRlZmF1bHQ6IHRydWUpXG4gICAgbG9ja1RpbWVvdXRNczogbnVtYmVyOyAgICAgICAgICAgICAgICAgLy8gRmlsZSBsb2NrIHRpbWVvdXQgKGRlZmF1bHQ6IDUwMDApXG4gICAgbWF4Q29uY3VycmVudEJ1aWxkczogbnVtYmVyOyAgICAgICAgICAgLy8gTWF4IGNvbmN1cnJlbnQgYnVpbGRzIChkZWZhdWx0OiAxKVxuICB9O1xuXG4gIC8vIFBlcmZvcm1hbmNlIExpbWl0c1xuICBwZXJmb3JtYW5jZToge1xuICAgIG1heEVsZW1lbnRzRm9yRnVsbE1hdHJpeDogbnVtYmVyOyAgICAgIC8vIE1heCBlbGVtZW50cyBmb3IgZnVsbCBzaW1pbGFyaXR5IG1hdHJpeCAoZGVmYXVsdDogMTAwKVxuICAgIG1heFNpbWlsYXJpdHlDb21wYXJpc29uczogbnVtYmVyOyAgICAgIC8vIE1heCB0b3RhbCBjb21wYXJpc29ucyAoZGVmYXVsdDogMTAwMDApXG4gICAgbWF4UmVsYXRpb25zaGlwQ29tcGFyaXNvbnM6IG51bWJlcjsgICAgLy8gTWF4IGNvbXBhcmlzb25zIGZvciByZWxhdGlvbnNoaXAgZGlzY292ZXJ5IChkZWZhdWx0OiAxMDApXG4gICAgc2ltaWxhcml0eUJhdGNoU2l6ZTogbnVtYmVyOyAgICAgICAgICAgLy8gQmF0Y2ggc2l6ZSBmb3IgYXN5bmMgcHJvY2Vzc2luZyAoZGVmYXVsdDogNTApXG4gICAgc2ltaWxhcml0eVRocmVzaG9sZDogbnVtYmVyOyAgICAgICAgICAgLy8gTWluIHNjb3JlIHRvIHN0b3JlIHJlbGF0aW9uc2hpcCAoZGVmYXVsdDogMC41KVxuICAgIGRlZmF1bHRTaW1pbGFyaXR5VGhyZXNob2xkOiBudW1iZXI7ICAgIC8vIERlZmF1bHQgc2ltaWxhcml0eSB0aHJlc2hvbGQgZm9yIHF1ZXJpZXMgKGRlZmF1bHQ6IDAuMylcbiAgICBkZWZhdWx0U2ltaWxhckxpbWl0OiBudW1iZXI7ICAgICAgICAgICAvLyBEZWZhdWx0IGxpbWl0IGZvciBzaW1pbGFyIGVsZW1lbnRzIChkZWZhdWx0OiA1KVxuICAgIGRlZmF1bHRWZXJiU2VhcmNoTGltaXQ6IG51bWJlcjsgICAgICAgIC8vIERlZmF1bHQgbGltaXQgZm9yIHZlcmIgc2VhcmNoIChkZWZhdWx0OiAxMClcbiAgICBwYXJhbGxlbFByb2Nlc3Npbmc6IGJvb2xlYW47ICAgICAgICAgICAvLyBVc2UgcGFyYWxsZWwgcHJvY2Vzc2luZyAoZGVmYXVsdDogdHJ1ZSlcbiAgICBjaXJjdWl0QnJlYWtlclRpbWVvdXRNczogbnVtYmVyOyAgICAgICAvLyBDaXJjdWl0IGJyZWFrZXIgdGltZW91dCAoZGVmYXVsdDogNTAwMClcbiAgfTtcblxuICAvLyBTYW1wbGluZyBDb25maWd1cmF0aW9uXG4gIHNhbXBsaW5nOiB7XG4gICAgYmFzZVNhbXBsZVNpemU6IG51bWJlcjsgICAgICAgICAgICAgICAgLy8gQmFzZSBzYW1wbGUgc2l6ZSBmb3IgcmVsYXRpb25zaGlwcyAoZGVmYXVsdDogMTApXG4gICAgc2FtcGxlUmF0aW86IG51bWJlcjsgICAgICAgICAgICAgICAgICAgLy8gU2FtcGxlIHJhdGlvIGZvciBsYXJnZSBkYXRhc2V0cyAoZGVmYXVsdDogMC4xKVxuICAgIGNsdXN0ZXJTYW1wbGVMaW1pdDogbnVtYmVyOyAgICAgICAgICAgIC8vIE1heCBzYW1wbGUgc2l6ZSB3aXRoaW4gY2x1c3RlcnMgKGRlZmF1bHQ6IDIwKVxuICB9O1xuXG4gIC8vIE5MUCBTY29yaW5nXG4gIG5scDoge1xuICAgIGNhY2hlRXhwaXJ5TWludXRlczogbnVtYmVyOyAgICAgICAgICAgLy8gTkxQIGNhY2hlIGV4cGlyeSAoZGVmYXVsdDogNSlcbiAgICBtaW5Ub2tlbkxlbmd0aDogbnVtYmVyOyAgICAgICAgICAgICAgIC8vIE1pbiB0b2tlbiBsZW5ndGggKGRlZmF1bHQ6IDIpXG4gICAgZW50cm9weUJhbmRzOiB7XG4gICAgICBsb3c6IG51bWJlcjsgICAgICAgICAgICAgICAgICAgICAgICAvLyBMb3cgZW50cm9weSB0aHJlc2hvbGQgKGRlZmF1bHQ6IDMuMClcbiAgICAgIG1vZGVyYXRlOiBudW1iZXI7ICAgICAgICAgICAgICAgICAgIC8vIE1vZGVyYXRlIGVudHJvcHkgKGRlZmF1bHQ6IDQuNSlcbiAgICAgIGhpZ2g6IG51bWJlcjsgICAgICAgICAgICAgICAgICAgICAgIC8vIEhpZ2ggZW50cm9weSAoZGVmYXVsdDogNi4wKVxuICAgIH07XG4gICAgamFjY2FyZFRocmVzaG9sZHM6IHtcbiAgICAgIGxvdzogbnVtYmVyOyAgICAgICAgICAgICAgICAgICAgICAgIC8vIExvdyBzaW1pbGFyaXR5IChkZWZhdWx0OiAwLjIpXG4gICAgICBtb2RlcmF0ZTogbnVtYmVyOyAgICAgICAgICAgICAgICAgICAvLyBNb2RlcmF0ZSBzaW1pbGFyaXR5IChkZWZhdWx0OiAwLjQpXG4gICAgICBoaWdoOiBudW1iZXI7ICAgICAgICAgICAgICAgICAgICAgICAvLyBIaWdoIHNpbWlsYXJpdHkgKGRlZmF1bHQ6IDAuNilcbiAgICB9O1xuICB9O1xuXG4gIC8vIFZlcmIgVHJpZ2dlcnNcbiAgdmVyYnM6IHtcbiAgICBjb25maWRlbmNlVGhyZXNob2xkOiBudW1iZXI7ICAgICAgICAgIC8vIE1pbiBjb25maWRlbmNlIGZvciB2ZXJiIG1hdGNoIChkZWZhdWx0OiAwLjUpXG4gICAgbWF4UmVjdXJzaW9uRGVwdGg6IG51bWJlcjsgICAgICAgICAgICAvLyBNYXggc3lub255bSByZWN1cnNpb24gZGVwdGggKGRlZmF1bHQ6IDMpXG4gICAgbWF4RWxlbWVudHNQZXJWZXJiOiBudW1iZXI7ICAgICAgICAgICAvLyBNYXggZWxlbWVudHMgcGVyIHZlcmIgKGRlZmF1bHQ6IDEwKVxuICAgIGluY2x1ZGVTeW5vbnltczogYm9vbGVhbjsgICAgICAgICAgICAgLy8gSW5jbHVkZSBzeW5vbnltIGV4cGFuc2lvbiAoZGVmYXVsdDogdHJ1ZSlcbiAgfTtcblxuICAvLyBNZW1vcnkgTWFuYWdlbWVudFxuICBtZW1vcnk6IHtcbiAgICBtYXhDYWNoZVNpemU6IG51bWJlcjsgICAgICAgICAgICAgICAgIC8vIE1heCBjYWNoZSBlbnRyaWVzIChkZWZhdWx0OiAxMDAwKVxuICAgIGVuYWJsZUdhcmJhZ2VDb2xsZWN0aW9uOiBib29sZWFuOyAgICAgLy8gRW5hYmxlIHBlcmlvZGljIEdDIChkZWZhdWx0OiB0cnVlKVxuICAgIGdjSW50ZXJ2YWxNaW51dGVzOiBudW1iZXI7ICAgICAgICAgICAgLy8gR0MgaW50ZXJ2YWwgKGRlZmF1bHQ6IDMwKVxuICAgIGNsZWFudXBJbnRlcnZhbE1pbnV0ZXM6IG51bWJlcjsgICAgICAgLy8gTWVtb3J5IGNsZWFudXAgaW50ZXJ2YWwgKGRlZmF1bHQ6IDUpXG4gICAgc3RhbGVJbmRleE11bHRpcGxpZXI6IG51bWJlcjsgICAgICAgICAvLyBNdWx0aXBsaWVyIGZvciBzdGFsZSBpbmRleCBjbGVhbnVwIChkZWZhdWx0OiAyKVxuICB9O1xufVxuXG5leHBvcnQgY2xhc3MgSW5kZXhDb25maWdNYW5hZ2VyIHtcbiAgcHJpdmF0ZSBjb25maWc6IEluZGV4Q29uZmlndXJhdGlvbjtcbiAgcHJpdmF0ZSBjb25maWdQYXRoOiBzdHJpbmc7XG4gIHByaXZhdGUgZGVmYXVsdENvbmZpZzogSW5kZXhDb25maWd1cmF0aW9uID0ge1xuICAgIGluZGV4OiB7XG4gICAgICB0dGxNaW51dGVzOiA1LFxuICAgICAgcmVidWlsZE9uU3RhcnR1cDogZmFsc2UsXG4gICAgICBwZXJzaXN0VG9EaXNrOiB0cnVlLFxuICAgICAgbG9ja1RpbWVvdXRNczogNTAwMCxcbiAgICAgIG1heENvbmN1cnJlbnRCdWlsZHM6IDFcbiAgICB9LFxuICAgIHBlcmZvcm1hbmNlOiB7XG4gICAgICBtYXhFbGVtZW50c0ZvckZ1bGxNYXRyaXg6IDEwMCxcbiAgICAgIG1heFNpbWlsYXJpdHlDb21wYXJpc29uczogMTAwMDAsXG4gICAgICBtYXhSZWxhdGlvbnNoaXBDb21wYXJpc29uczogMTAwLFxuICAgICAgc2ltaWxhcml0eUJhdGNoU2l6ZTogNTAsXG4gICAgICBzaW1pbGFyaXR5VGhyZXNob2xkOiAwLjUsXG4gICAgICBkZWZhdWx0U2ltaWxhcml0eVRocmVzaG9sZDogMC41LFxuICAgICAgZGVmYXVsdFNpbWlsYXJMaW1pdDogMTAsXG4gICAgICBkZWZhdWx0VmVyYlNlYXJjaExpbWl0OiAyMCxcbiAgICAgIHBhcmFsbGVsUHJvY2Vzc2luZzogdHJ1ZSxcbiAgICAgIGNpcmN1aXRCcmVha2VyVGltZW91dE1zOiA1MDAwXG4gICAgfSxcbiAgICBzYW1wbGluZzoge1xuICAgICAgYmFzZVNhbXBsZVNpemU6IDEwLFxuICAgICAgc2FtcGxlUmF0aW86IDAuMSxcbiAgICAgIGNsdXN0ZXJTYW1wbGVMaW1pdDogMjBcbiAgICB9LFxuICAgIG5scDoge1xuICAgICAgY2FjaGVFeHBpcnlNaW51dGVzOiA1LFxuICAgICAgbWluVG9rZW5MZW5ndGg6IDIsXG4gICAgICBlbnRyb3B5QmFuZHM6IHtcbiAgICAgICAgbG93OiAzLjAsXG4gICAgICAgIG1vZGVyYXRlOiA0LjUsXG4gICAgICAgIGhpZ2g6IDYuMFxuICAgICAgfSxcbiAgICAgIGphY2NhcmRUaHJlc2hvbGRzOiB7XG4gICAgICAgIGxvdzogMC4yLFxuICAgICAgICBtb2RlcmF0ZTogMC40LFxuICAgICAgICBoaWdoOiAwLjZcbiAgICAgIH1cbiAgICB9LFxuICAgIHZlcmJzOiB7XG4gICAgICBjb25maWRlbmNlVGhyZXNob2xkOiAwLjUsXG4gICAgICBtYXhSZWN1cnNpb25EZXB0aDogMyxcbiAgICAgIG1heEVsZW1lbnRzUGVyVmVyYjogMTAsXG4gICAgICBpbmNsdWRlU3lub255bXM6IHRydWVcbiAgICB9LFxuICAgIG1lbW9yeToge1xuICAgICAgbWF4Q2FjaGVTaXplOiAxMDAwLFxuICAgICAgZW5hYmxlR2FyYmFnZUNvbGxlY3Rpb246IHRydWUsXG4gICAgICBnY0ludGVydmFsTWludXRlczogMzAsXG4gICAgICBjbGVhbnVwSW50ZXJ2YWxNaW51dGVzOiA1LFxuICAgICAgc3RhbGVJbmRleE11bHRpcGxpZXI6IDJcbiAgICB9XG4gIH07XG5cbiAgY29uc3RydWN0b3IoKSB7XG4gICAgY29uc3QgcG9ydGZvbGlvUGF0aCA9IHBhdGguam9pbihwcm9jZXNzLmVudi5IT01FIHx8ICcnLCAnLmRvbGxob3VzZScsICdwb3J0Zm9saW8nKTtcbiAgICB0aGlzLmNvbmZpZ1BhdGggPSBwYXRoLmpvaW4ocG9ydGZvbGlvUGF0aCwgJy5jb25maWcnLCAnaW5kZXgtY29uZmlnLmpzb24nKTtcbiAgICB0aGlzLmNvbmZpZyA9IHsgLi4udGhpcy5kZWZhdWx0Q29uZmlnIH07XG4gICAgLy8gRklYOiBSYWNlIGNvbmRpdGlvbiAtIGxvYWRDb25maWcgaXMgYXN5bmMgYnV0IGNhbGxlZCBzeW5jIGluIGNvbnN0cnVjdG9yXG4gICAgLy8gTm93IHVzaW5nIHN5bmNocm9ub3VzIGxvYWRpbmcgaW4gY29uc3RydWN0b3JcbiAgICB0aGlzLmxvYWRDb25maWdTeW5jKCk7XG4gIH1cblxuICAvKipcbiAgICogTG9hZCBjb25maWd1cmF0aW9uIGZyb20gZGlzayBzeW5jaHJvbm91c2x5IChmb3IgY29uc3RydWN0b3IpXG4gICAqL1xuICBwcml2YXRlIGxvYWRDb25maWdTeW5jKCk6IHZvaWQge1xuICAgIHRyeSB7XG4gICAgICAvLyBDaGVjayBpZiBmaWxlIGV4aXN0c1xuICAgICAgaWYgKCFmc1N5bmMuZXhpc3RzU3luYyh0aGlzLmNvbmZpZ1BhdGgpKSB7XG4gICAgICAgIGxvZ2dlci5pbmZvKCdObyBjb25maWcgZmlsZSBmb3VuZCwgdXNpbmcgZGVmYXVsdHMnLCB7IHBhdGg6IHRoaXMuY29uZmlnUGF0aCB9KTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBjb25maWdEYXRhID0gZnNTeW5jLnJlYWRGaWxlU3luYyh0aGlzLmNvbmZpZ1BhdGgsICd1dGYtOCcpO1xuICAgICAgY29uc3QgbG9hZGVkQ29uZmlnID0gSlNPTi5wYXJzZShjb25maWdEYXRhKTtcblxuICAgICAgLy8gRGVlcCBtZXJnZSB3aXRoIGRlZmF1bHRzIHRvIGhhbmRsZSBtaXNzaW5nIGZpZWxkc1xuICAgICAgLy8gRklYOiBMb2FkZWQgY29uZmlnIHNob3VsZCBvdmVycmlkZSBkZWZhdWx0c1xuICAgICAgdGhpcy5jb25maWcgPSBkZWVwTWVyZ2U8SW5kZXhDb25maWd1cmF0aW9uPih0aGlzLmRlZmF1bHRDb25maWcsIGxvYWRlZENvbmZpZyk7XG5cbiAgICAgIGxvZ2dlci5pbmZvKCdJbmRleCBjb25maWd1cmF0aW9uIGxvYWRlZCcsIHsgcGF0aDogdGhpcy5jb25maWdQYXRoIH0pO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBsb2dnZXIud2FybignRmFpbGVkIHRvIGxvYWQgaW5kZXggY29uZmlnLCB1c2luZyBkZWZhdWx0cycsIHtcbiAgICAgICAgZXJyb3I6IGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKSxcbiAgICAgICAgcGF0aDogdGhpcy5jb25maWdQYXRoXG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuXG4gIC8qKlxuICAgKiBTYXZlIGN1cnJlbnQgY29uZmlndXJhdGlvbiB0byBkaXNrXG4gICAqL1xuICBwdWJsaWMgYXN5bmMgc2F2ZUNvbmZpZygpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgY29uZmlnRGlyID0gcGF0aC5kaXJuYW1lKHRoaXMuY29uZmlnUGF0aCk7XG4gICAgICBhd2FpdCBmcy5ta2Rpcihjb25maWdEaXIsIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xuXG4gICAgICBhd2FpdCBmcy53cml0ZUZpbGUoXG4gICAgICAgIHRoaXMuY29uZmlnUGF0aCxcbiAgICAgICAgSlNPTi5zdHJpbmdpZnkodGhpcy5jb25maWcsIG51bGwsIDIpLFxuICAgICAgICAndXRmLTgnXG4gICAgICApO1xuXG4gICAgICBsb2dnZXIuZGVidWcoJ0luZGV4IGNvbmZpZ3VyYXRpb24gc2F2ZWQnLCB7IHBhdGg6IHRoaXMuY29uZmlnUGF0aCB9KTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgbG9nZ2VyLmVycm9yKCdGYWlsZWQgdG8gc2F2ZSBpbmRleCBjb25maWcnLCB7IGVycm9yIH0pO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgdGhlIGN1cnJlbnQgY29uZmlndXJhdGlvblxuICAgKi9cbiAgcHVibGljIGdldENvbmZpZygpOiBJbmRleENvbmZpZ3VyYXRpb24ge1xuICAgIHJldHVybiB7IC4uLnRoaXMuY29uZmlnIH07XG4gIH1cblxuICAvKipcbiAgICogVXBkYXRlIGNvbmZpZ3VyYXRpb24gd2l0aCB2YWxpZGF0aW9uXG4gICAqL1xuICBwdWJsaWMgYXN5bmMgdXBkYXRlQ29uZmlnKHVwZGF0ZXM6IFBhcnRpYWw8SW5kZXhDb25maWd1cmF0aW9uPik6IFByb21pc2U8dm9pZD4ge1xuICAgIC8vIFZhbGlkYXRlIHRoZSB1cGRhdGVzIGJlZm9yZSBhcHBseWluZ1xuICAgIHRoaXMudmFsaWRhdGVDb25maWcodXBkYXRlcyk7XG5cbiAgICB0aGlzLmNvbmZpZyA9IGRlZXBNZXJnZTxJbmRleENvbmZpZ3VyYXRpb24+KHRoaXMuY29uZmlnLCB1cGRhdGVzKTtcbiAgICBhd2FpdCB0aGlzLnNhdmVDb25maWcoKTtcblxuICAgIGxvZ2dlci5pbmZvKCdJbmRleCBjb25maWd1cmF0aW9uIHVwZGF0ZWQnLCB7IHVwZGF0ZXMgfSk7XG5cbiAgICAvLyBMb2cgc3VjY2Vzc2Z1bCB1cGRhdGVcbiAgICBTZWN1cml0eU1vbml0b3IubG9nU2VjdXJpdHlFdmVudCh7XG4gICAgICB0eXBlOiAnUlVMRV9FTkdJTkVfQ09ORklHX1VQREFURScgYXMgYW55LFxuICAgICAgc2V2ZXJpdHk6ICdMT1cnLFxuICAgICAgc291cmNlOiAnSW5kZXhDb25maWdNYW5hZ2VyLnVwZGF0ZUNvbmZpZycsXG4gICAgICBkZXRhaWxzOiAnSW5kZXggY29uZmlndXJhdGlvbiB1cGRhdGUgc3VjY2Vzc2Z1bCcsXG4gICAgICBhZGRpdGlvbmFsRGF0YToge1xuICAgICAgICBjb25maWdUeXBlOiAnaW5kZXgnLFxuICAgICAgICB1cGRhdGVkRmllbGRzOiBPYmplY3Qua2V5cyh1cGRhdGVzKVxuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFZhbGlkYXRlIGNvbmZpZ3VyYXRpb24gdmFsdWVzXG4gICAqIFRocm93cyBhbiBlcnJvciBpZiBhbnkgdmFsdWUgaXMgaW52YWxpZFxuICAgKi9cbiAgcHJpdmF0ZSB2YWxpZGF0ZUNvbmZpZyhjb25maWc6IFBhcnRpYWw8SW5kZXhDb25maWd1cmF0aW9uPik6IHZvaWQge1xuICAgIC8vIFZhbGlkYXRlIHBlcmZvcm1hbmNlIHRocmVzaG9sZHMgKDAtMSByYW5nZSlcbiAgICBpZiAoY29uZmlnLnBlcmZvcm1hbmNlKSB7XG4gICAgICBjb25zdCBwZXJmID0gY29uZmlnLnBlcmZvcm1hbmNlO1xuXG4gICAgICAvLyBTaW1pbGFyaXR5IHRocmVzaG9sZHMgbXVzdCBiZSBiZXR3ZWVuIDAgYW5kIDFcbiAgICAgIGlmIChwZXJmLnNpbWlsYXJpdHlUaHJlc2hvbGQgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICBpZiAocGVyZi5zaW1pbGFyaXR5VGhyZXNob2xkIDwgMCB8fCBwZXJmLnNpbWlsYXJpdHlUaHJlc2hvbGQgPiAxKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBzaW1pbGFyaXR5VGhyZXNob2xkIG11c3QgYmUgYmV0d2VlbiAwIGFuZCAxLCBnb3QgJHtwZXJmLnNpbWlsYXJpdHlUaHJlc2hvbGR9YCk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKHBlcmYuZGVmYXVsdFNpbWlsYXJpdHlUaHJlc2hvbGQgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICBpZiAocGVyZi5kZWZhdWx0U2ltaWxhcml0eVRocmVzaG9sZCA8IDAgfHwgcGVyZi5kZWZhdWx0U2ltaWxhcml0eVRocmVzaG9sZCA+IDEpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYGRlZmF1bHRTaW1pbGFyaXR5VGhyZXNob2xkIG11c3QgYmUgYmV0d2VlbiAwIGFuZCAxLCBnb3QgJHtwZXJmLmRlZmF1bHRTaW1pbGFyaXR5VGhyZXNob2xkfWApO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIC8vIFBvc2l0aXZlIGludGVnZXIgdmFsaWRhdGlvbnNcbiAgICAgIGlmIChwZXJmLm1heEVsZW1lbnRzRm9yRnVsbE1hdHJpeCAhPT0gdW5kZWZpbmVkICYmIHBlcmYubWF4RWxlbWVudHNGb3JGdWxsTWF0cml4IDw9IDApIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBtYXhFbGVtZW50c0ZvckZ1bGxNYXRyaXggbXVzdCBiZSBwb3NpdGl2ZSwgZ290ICR7cGVyZi5tYXhFbGVtZW50c0ZvckZ1bGxNYXRyaXh9YCk7XG4gICAgICB9XG5cbiAgICAgIGlmIChwZXJmLm1heFNpbWlsYXJpdHlDb21wYXJpc29ucyAhPT0gdW5kZWZpbmVkICYmIHBlcmYubWF4U2ltaWxhcml0eUNvbXBhcmlzb25zIDw9IDApIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBtYXhTaW1pbGFyaXR5Q29tcGFyaXNvbnMgbXVzdCBiZSBwb3NpdGl2ZSwgZ290ICR7cGVyZi5tYXhTaW1pbGFyaXR5Q29tcGFyaXNvbnN9YCk7XG4gICAgICB9XG5cbiAgICAgIGlmIChwZXJmLm1heFJlbGF0aW9uc2hpcENvbXBhcmlzb25zICE9PSB1bmRlZmluZWQgJiYgcGVyZi5tYXhSZWxhdGlvbnNoaXBDb21wYXJpc29ucyA8PSAwKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgbWF4UmVsYXRpb25zaGlwQ29tcGFyaXNvbnMgbXVzdCBiZSBwb3NpdGl2ZSwgZ290ICR7cGVyZi5tYXhSZWxhdGlvbnNoaXBDb21wYXJpc29uc31gKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHBlcmYuc2ltaWxhcml0eUJhdGNoU2l6ZSAhPT0gdW5kZWZpbmVkICYmIHBlcmYuc2ltaWxhcml0eUJhdGNoU2l6ZSA8PSAwKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgc2ltaWxhcml0eUJhdGNoU2l6ZSBtdXN0IGJlIHBvc2l0aXZlLCBnb3QgJHtwZXJmLnNpbWlsYXJpdHlCYXRjaFNpemV9YCk7XG4gICAgICB9XG5cbiAgICAgIGlmIChwZXJmLmRlZmF1bHRTaW1pbGFyTGltaXQgIT09IHVuZGVmaW5lZCAmJiBwZXJmLmRlZmF1bHRTaW1pbGFyTGltaXQgPD0gMCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYGRlZmF1bHRTaW1pbGFyTGltaXQgbXVzdCBiZSBwb3NpdGl2ZSwgZ290ICR7cGVyZi5kZWZhdWx0U2ltaWxhckxpbWl0fWApO1xuICAgICAgfVxuXG4gICAgICBpZiAocGVyZi5kZWZhdWx0VmVyYlNlYXJjaExpbWl0ICE9PSB1bmRlZmluZWQgJiYgcGVyZi5kZWZhdWx0VmVyYlNlYXJjaExpbWl0IDw9IDApIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBkZWZhdWx0VmVyYlNlYXJjaExpbWl0IG11c3QgYmUgcG9zaXRpdmUsIGdvdCAke3BlcmYuZGVmYXVsdFZlcmJTZWFyY2hMaW1pdH1gKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHBlcmYuY2lyY3VpdEJyZWFrZXJUaW1lb3V0TXMgIT09IHVuZGVmaW5lZCAmJiBwZXJmLmNpcmN1aXRCcmVha2VyVGltZW91dE1zIDw9IDApIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBjaXJjdWl0QnJlYWtlclRpbWVvdXRNcyBtdXN0IGJlIHBvc2l0aXZlLCBnb3QgJHtwZXJmLmNpcmN1aXRCcmVha2VyVGltZW91dE1zfWApO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIFZhbGlkYXRlIHNhbXBsaW5nIGNvbmZpZ3VyYXRpb25cbiAgICBpZiAoY29uZmlnLnNhbXBsaW5nKSB7XG4gICAgICBjb25zdCBzYW1wbGluZyA9IGNvbmZpZy5zYW1wbGluZztcblxuICAgICAgLy8gU2FtcGxlIHJhdGlvIG11c3QgYmUgYmV0d2VlbiAwIGFuZCAxXG4gICAgICBpZiAoc2FtcGxpbmcuc2FtcGxlUmF0aW8gIT09IHVuZGVmaW5lZCkge1xuICAgICAgICBpZiAoc2FtcGxpbmcuc2FtcGxlUmF0aW8gPD0gMCB8fCBzYW1wbGluZy5zYW1wbGVSYXRpbyA+IDEpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYHNhbXBsZVJhdGlvIG11c3QgYmUgYmV0d2VlbiAwIGFuZCAxLCBnb3QgJHtzYW1wbGluZy5zYW1wbGVSYXRpb31gKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAoc2FtcGxpbmcuYmFzZVNhbXBsZVNpemUgIT09IHVuZGVmaW5lZCAmJiBzYW1wbGluZy5iYXNlU2FtcGxlU2l6ZSA8PSAwKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgYmFzZVNhbXBsZVNpemUgbXVzdCBiZSBwb3NpdGl2ZSwgZ290ICR7c2FtcGxpbmcuYmFzZVNhbXBsZVNpemV9YCk7XG4gICAgICB9XG5cbiAgICAgIGlmIChzYW1wbGluZy5jbHVzdGVyU2FtcGxlTGltaXQgIT09IHVuZGVmaW5lZCAmJiBzYW1wbGluZy5jbHVzdGVyU2FtcGxlTGltaXQgPD0gMCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYGNsdXN0ZXJTYW1wbGVMaW1pdCBtdXN0IGJlIHBvc2l0aXZlLCBnb3QgJHtzYW1wbGluZy5jbHVzdGVyU2FtcGxlTGltaXR9YCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gVmFsaWRhdGUgTkxQIGNvbmZpZ3VyYXRpb25cbiAgICBpZiAoY29uZmlnLm5scCkge1xuICAgICAgY29uc3QgbmxwID0gY29uZmlnLm5scDtcblxuICAgICAgLy8gSmFjY2FyZCB0aHJlc2hvbGRzIG11c3QgYmUgYmV0d2VlbiAwIGFuZCAxXG4gICAgICBpZiAobmxwLmphY2NhcmRUaHJlc2hvbGRzKSB7XG4gICAgICAgIGNvbnN0IGphY2NhcmQgPSBubHAuamFjY2FyZFRocmVzaG9sZHM7XG4gICAgICAgIGlmIChqYWNjYXJkLmxvdyAhPT0gdW5kZWZpbmVkICYmIChqYWNjYXJkLmxvdyA8IDAgfHwgamFjY2FyZC5sb3cgPiAxKSkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgamFjY2FyZFRocmVzaG9sZHMubG93IG11c3QgYmUgYmV0d2VlbiAwIGFuZCAxLCBnb3QgJHtqYWNjYXJkLmxvd31gKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoamFjY2FyZC5tb2RlcmF0ZSAhPT0gdW5kZWZpbmVkICYmIChqYWNjYXJkLm1vZGVyYXRlIDwgMCB8fCBqYWNjYXJkLm1vZGVyYXRlID4gMSkpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYGphY2NhcmRUaHJlc2hvbGRzLm1vZGVyYXRlIG11c3QgYmUgYmV0d2VlbiAwIGFuZCAxLCBnb3QgJHtqYWNjYXJkLm1vZGVyYXRlfWApO1xuICAgICAgICB9XG4gICAgICAgIGlmIChqYWNjYXJkLmhpZ2ggIT09IHVuZGVmaW5lZCAmJiAoamFjY2FyZC5oaWdoIDwgMCB8fCBqYWNjYXJkLmhpZ2ggPiAxKSkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgamFjY2FyZFRocmVzaG9sZHMuaGlnaCBtdXN0IGJlIGJldHdlZW4gMCBhbmQgMSwgZ290ICR7amFjY2FyZC5oaWdofWApO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIC8vIEVudHJvcHkgYmFuZHMgbXVzdCBiZSBwb3NpdGl2ZVxuICAgICAgaWYgKG5scC5lbnRyb3B5QmFuZHMpIHtcbiAgICAgICAgY29uc3QgZW50cm9weSA9IG5scC5lbnRyb3B5QmFuZHM7XG4gICAgICAgIGlmIChlbnRyb3B5LmxvdyAhPT0gdW5kZWZpbmVkICYmIGVudHJvcHkubG93IDwgMCkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgZW50cm9weUJhbmRzLmxvdyBtdXN0IGJlIG5vbi1uZWdhdGl2ZSwgZ290ICR7ZW50cm9weS5sb3d9YCk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGVudHJvcHkubW9kZXJhdGUgIT09IHVuZGVmaW5lZCAmJiBlbnRyb3B5Lm1vZGVyYXRlIDwgMCkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgZW50cm9weUJhbmRzLm1vZGVyYXRlIG11c3QgYmUgbm9uLW5lZ2F0aXZlLCBnb3QgJHtlbnRyb3B5Lm1vZGVyYXRlfWApO1xuICAgICAgICB9XG4gICAgICAgIGlmIChlbnRyb3B5LmhpZ2ggIT09IHVuZGVmaW5lZCAmJiBlbnRyb3B5LmhpZ2ggPCAwKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBlbnRyb3B5QmFuZHMuaGlnaCBtdXN0IGJlIG5vbi1uZWdhdGl2ZSwgZ290ICR7ZW50cm9weS5oaWdofWApO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmIChubHAuY2FjaGVFeHBpcnlNaW51dGVzICE9PSB1bmRlZmluZWQgJiYgbmxwLmNhY2hlRXhwaXJ5TWludXRlcyA8PSAwKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgY2FjaGVFeHBpcnlNaW51dGVzIG11c3QgYmUgcG9zaXRpdmUsIGdvdCAke25scC5jYWNoZUV4cGlyeU1pbnV0ZXN9YCk7XG4gICAgICB9XG5cbiAgICAgIGlmIChubHAubWluVG9rZW5MZW5ndGggIT09IHVuZGVmaW5lZCAmJiBubHAubWluVG9rZW5MZW5ndGggPCAxKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgbWluVG9rZW5MZW5ndGggbXVzdCBiZSBhdCBsZWFzdCAxLCBnb3QgJHtubHAubWluVG9rZW5MZW5ndGh9YCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gVmFsaWRhdGUgdmVyYiBjb25maWd1cmF0aW9uXG4gICAgaWYgKGNvbmZpZy52ZXJicykge1xuICAgICAgY29uc3QgdmVyYnMgPSBjb25maWcudmVyYnM7XG5cbiAgICAgIGlmICh2ZXJicy5jb25maWRlbmNlVGhyZXNob2xkICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgaWYgKHZlcmJzLmNvbmZpZGVuY2VUaHJlc2hvbGQgPCAwIHx8IHZlcmJzLmNvbmZpZGVuY2VUaHJlc2hvbGQgPiAxKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBjb25maWRlbmNlVGhyZXNob2xkIG11c3QgYmUgYmV0d2VlbiAwIGFuZCAxLCBnb3QgJHt2ZXJicy5jb25maWRlbmNlVGhyZXNob2xkfWApO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmICh2ZXJicy5tYXhSZWN1cnNpb25EZXB0aCAhPT0gdW5kZWZpbmVkICYmIHZlcmJzLm1heFJlY3Vyc2lvbkRlcHRoIDw9IDApIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBtYXhSZWN1cnNpb25EZXB0aCBtdXN0IGJlIHBvc2l0aXZlLCBnb3QgJHt2ZXJicy5tYXhSZWN1cnNpb25EZXB0aH1gKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHZlcmJzLm1heEVsZW1lbnRzUGVyVmVyYiAhPT0gdW5kZWZpbmVkICYmIHZlcmJzLm1heEVsZW1lbnRzUGVyVmVyYiA8PSAwKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgbWF4RWxlbWVudHNQZXJWZXJiIG11c3QgYmUgcG9zaXRpdmUsIGdvdCAke3ZlcmJzLm1heEVsZW1lbnRzUGVyVmVyYn1gKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBWYWxpZGF0ZSBtZW1vcnkgY29uZmlndXJhdGlvblxuICAgIGlmIChjb25maWcubWVtb3J5KSB7XG4gICAgICBjb25zdCBtZW1vcnkgPSBjb25maWcubWVtb3J5O1xuXG4gICAgICBpZiAobWVtb3J5Lm1heENhY2hlU2l6ZSAhPT0gdW5kZWZpbmVkICYmIG1lbW9yeS5tYXhDYWNoZVNpemUgPD0gMCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYG1heENhY2hlU2l6ZSBtdXN0IGJlIHBvc2l0aXZlLCBnb3QgJHttZW1vcnkubWF4Q2FjaGVTaXplfWApO1xuICAgICAgfVxuXG4gICAgICBpZiAobWVtb3J5LmdjSW50ZXJ2YWxNaW51dGVzICE9PSB1bmRlZmluZWQgJiYgbWVtb3J5LmdjSW50ZXJ2YWxNaW51dGVzIDw9IDApIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBnY0ludGVydmFsTWludXRlcyBtdXN0IGJlIHBvc2l0aXZlLCBnb3QgJHttZW1vcnkuZ2NJbnRlcnZhbE1pbnV0ZXN9YCk7XG4gICAgICB9XG5cbiAgICAgIGlmIChtZW1vcnkuY2xlYW51cEludGVydmFsTWludXRlcyAhPT0gdW5kZWZpbmVkICYmIG1lbW9yeS5jbGVhbnVwSW50ZXJ2YWxNaW51dGVzIDw9IDApIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBjbGVhbnVwSW50ZXJ2YWxNaW51dGVzIG11c3QgYmUgcG9zaXRpdmUsIGdvdCAke21lbW9yeS5jbGVhbnVwSW50ZXJ2YWxNaW51dGVzfWApO1xuICAgICAgfVxuXG4gICAgICBpZiAobWVtb3J5LnN0YWxlSW5kZXhNdWx0aXBsaWVyICE9PSB1bmRlZmluZWQgJiYgbWVtb3J5LnN0YWxlSW5kZXhNdWx0aXBsaWVyIDw9IDApIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBzdGFsZUluZGV4TXVsdGlwbGllciBtdXN0IGJlIHBvc2l0aXZlLCBnb3QgJHttZW1vcnkuc3RhbGVJbmRleE11bHRpcGxpZXJ9YCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gVmFsaWRhdGUgaW5kZXggY29uZmlndXJhdGlvblxuICAgIGlmIChjb25maWcuaW5kZXgpIHtcbiAgICAgIGNvbnN0IGluZGV4ID0gY29uZmlnLmluZGV4O1xuXG4gICAgICBpZiAoaW5kZXgudHRsTWludXRlcyAhPT0gdW5kZWZpbmVkICYmIGluZGV4LnR0bE1pbnV0ZXMgPD0gMCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYHR0bE1pbnV0ZXMgbXVzdCBi