@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.
639 lines • 66.9 kB
JavaScript
/**
* Performance Configuration Constants
*
* Centralized configuration for performance-related magic numbers including
* lock timeouts, metrics batching, cache memory estimation, and other
* performance-critical constants.
*
* All values can be overridden via environment variables for flexibility.
*
* @module performance-constants
*/
/**
* File locking configuration
*
* Lock timeout is based on p95 operation time analysis:
* - Measured p95 operation time: 2.5 seconds
* - Safety buffer: 4x multiplier
* - Default timeout: 10 seconds (2.5s * 4)
*
* This provides enough time for operations to complete while preventing
* deadlocks from hung processes.
*/
export const FILE_LOCK_CONFIG = {
/**
* Default timeout for lock acquisition (milliseconds)
*
* Based on empirical analysis:
* - P95 file operation time: 2.5s
* - Buffer multiplier: 4x for safety
* - Total: 10,000ms (10 seconds)
*
* Environment: DOLLHOUSE_LOCK_TIMEOUT
*/
DEFAULT_TIMEOUT_MS: Number.parseInt(process.env.DOLLHOUSE_LOCK_TIMEOUT || '10000'),
/**
* Minimum allowed lock timeout (1 second)
* Prevents misconfiguration that could cause spurious timeouts
*/
MIN_TIMEOUT_MS: 1000,
/**
* Maximum allowed lock timeout (60 seconds)
* Prevents indefinite hangs while allowing for slow operations
*/
MAX_TIMEOUT_MS: 60000,
/**
* Stale lock cleanup threshold (milliseconds)
* Locks older than this are considered abandoned and can be forcibly released
*
* Environment: DOLLHOUSE_LOCK_STALE_THRESHOLD
*/
STALE_THRESHOLD_MS: Number.parseInt(process.env.DOLLHOUSE_LOCK_STALE_THRESHOLD || '60000'),
/**
* Lock retry configuration
*/
RETRY: {
/**
* Maximum number of retry attempts for lock acquisition
*
* Environment: DOLLHOUSE_LOCK_MAX_RETRIES
*/
MAX_ATTEMPTS: Number.parseInt(process.env.DOLLHOUSE_LOCK_MAX_RETRIES || '3'),
/**
* Initial delay between retries (milliseconds)
* Uses exponential backoff from this base
*
* Environment: DOLLHOUSE_LOCK_RETRY_DELAY
*/
INITIAL_DELAY_MS: Number.parseInt(process.env.DOLLHOUSE_LOCK_RETRY_DELAY || '100'),
}
};
/**
* Metrics batching configuration
*
* Optimizes write performance by batching metrics updates:
* - Batch size tuned for memory vs. latency trade-off
* - Small batches = lower latency, higher overhead
* - Large batches = higher latency, lower overhead
*
* Current values provide good balance for typical workloads.
*/
export const METRICS_CONFIG = {
/**
* Number of metrics to batch before flushing to disk
*
* Trade-offs:
* - Size 10: ~50ms flush latency, minimal memory (chosen for balance)
* - Size 100: ~200ms flush latency, 10x more memory
* - Size 1: No batching, highest overhead
*
* Environment: DOLLHOUSE_METRICS_BATCH_SIZE
*/
BATCH_SIZE: Number.parseInt(process.env.DOLLHOUSE_METRICS_BATCH_SIZE || '10'),
/**
* Minimum batch size (no batching)
*/
MIN_BATCH_SIZE: 1,
/**
* Maximum batch size to prevent memory issues
*/
MAX_BATCH_SIZE: 1000,
/**
* Time interval to force flush even if batch not full (milliseconds)
*
* Ensures metrics are persisted within reasonable time:
* - 5 seconds provides good balance between freshness and efficiency
* - Prevents unbounded delay for low-traffic scenarios
*
* Environment: DOLLHOUSE_METRICS_FLUSH_INTERVAL
*/
FLUSH_INTERVAL_MS: Number.parseInt(process.env.DOLLHOUSE_METRICS_FLUSH_INTERVAL || '5000'),
/**
* Minimum flush interval (100ms)
* Prevents excessive disk I/O
*/
MIN_FLUSH_INTERVAL_MS: 100,
/**
* Maximum flush interval (5 minutes)
* Ensures timely metric persistence
*/
MAX_FLUSH_INTERVAL_MS: 300000,
};
/**
* Cache size estimation configuration
*
* Fast byte-based heuristics for memory estimation based on V8 memory layout analysis.
* These values are derived from empirical measurements of V8 object representations.
*
* Accuracy vs. Speed trade-offs:
* - Fast mode: 2-5x faster than JSON.stringify, 50-200% accuracy
* - Balanced mode: Samples first 10 elements, better accuracy
* - Accurate mode: Uses JSON.stringify, slowest but most precise
*/
export const CACHE_SIZE_ESTIMATION_CONFIG = {
/**
* Size of primitive values in V8 (bytes)
* Covers numbers, booleans, small integers
*
* Based on V8 Smi (Small Integer) representation
*/
PRIMITIVE_SIZE: 8,
/**
* Base memory overhead for JavaScript objects (bytes)
*
* Includes:
* - Object header: ~32 bytes
* - Hidden class pointer: ~8 bytes
* - Properties backing store: ~24 bytes
* - Total: ~64 bytes
*/
OBJECT_BASE_OVERHEAD: 64,
/**
* Base memory overhead for JavaScript arrays (bytes)
*
* Includes:
* - Array header: ~16 bytes
* - Length property: ~8 bytes
* - Elements backing store pointer: ~8 bytes
* - Total: ~32 bytes
*/
ARRAY_BASE_OVERHEAD: 32,
/**
* Memory overhead per object field/property (bytes)
*
* Includes:
* - Property name string: ~24 bytes average
* - Property value pointer: ~8 bytes
* - Property descriptor: ~16 bytes
* - Total: ~48 bytes
*/
FIELD_OVERHEAD: 48,
/**
* Average element size estimate for arrays (bytes)
*
* Conservative estimate for mixed content:
* - Small objects: ~32 bytes
* - Strings: ~64 bytes average
* - Numbers: ~8 bytes
* - Average: ~64 bytes
*/
ELEMENT_ESTIMATE: 64,
/**
* Number of elements to sample in balanced mode
*
* Sampling first 10 elements provides:
* - ~85% accuracy for homogeneous arrays
* - ~70% accuracy for mixed content
* - 2-3x speedup over full traversal
*/
BALANCED_SAMPLE_SIZE: Number.parseInt(process.env.DOLLHOUSE_CACHE_SAMPLE_SIZE || '10'),
/**
* Minimum sample size for balanced mode
*/
MIN_SAMPLE_SIZE: 1,
/**
* Maximum sample size for balanced mode
* Prevents excessive sampling overhead
*/
MAX_SAMPLE_SIZE: 100,
};
/**
* Memory limits for various cache types
*
* These limits prevent unbounded memory growth and provide
* reasonable defaults for different use cases.
*/
export const MEMORY_LIMITS = {
/**
* Cache limits for persona data
*/
PERSONA_CACHE: {
/**
* Maximum number of cached persona entries
* Environment: DOLLHOUSE_MAX_PERSONA_CACHE_SIZE
*/
MAX_SIZE: Number.parseInt(process.env.DOLLHOUSE_MAX_PERSONA_CACHE_SIZE || '50'),
/**
* Maximum memory for persona cache (MB)
* Environment: DOLLHOUSE_MAX_PERSONA_CACHE_MEMORY
*/
MAX_MEMORY_MB: Number.parseInt(process.env.DOLLHOUSE_MAX_PERSONA_CACHE_MEMORY || '25'),
},
/**
* Cache limits for metrics data
*/
METRICS_CACHE: {
/**
* Maximum number of cached metrics entries
* Environment: DOLLHOUSE_MAX_METRICS_CACHE_SIZE
*/
MAX_SIZE: Number.parseInt(process.env.DOLLHOUSE_MAX_METRICS_CACHE_SIZE || '100'),
/**
* Maximum memory for metrics cache (MB)
* Environment: DOLLHOUSE_MAX_METRICS_CACHE_MEMORY
*/
MAX_MEMORY_MB: Number.parseInt(process.env.DOLLHOUSE_MAX_METRICS_CACHE_MEMORY || '1'),
},
/**
* Cache limits for search results
*/
SEARCH_CACHE: {
/**
* Maximum number of cached search results
* Environment: DOLLHOUSE_MAX_SEARCH_CACHE_SIZE
*/
MAX_SIZE: Number.parseInt(process.env.DOLLHOUSE_MAX_SEARCH_CACHE_SIZE || '100'),
/**
* Maximum memory for search cache (MB)
* Environment: DOLLHOUSE_MAX_SEARCH_CACHE_MEMORY
*/
MAX_MEMORY_MB: Number.parseInt(process.env.DOLLHOUSE_MAX_SEARCH_CACHE_MEMORY || '10'),
},
/**
* Cache limits for index data
*/
INDEX_CACHE: {
/**
* Maximum number of cached index entries
* Environment: DOLLHOUSE_MAX_INDEX_CACHE_SIZE
*/
MAX_SIZE: Number.parseInt(process.env.DOLLHOUSE_MAX_INDEX_CACHE_SIZE || '50'),
/**
* Maximum memory for index cache (MB)
* Environment: DOLLHOUSE_MAX_INDEX_CACHE_MEMORY
*/
MAX_MEMORY_MB: Number.parseInt(process.env.DOLLHOUSE_MAX_INDEX_CACHE_MEMORY || '25'),
},
/**
* Cache limits for API responses
*/
API_CACHE: {
/**
* Maximum number of cached API responses
* Environment: DOLLHOUSE_MAX_API_CACHE_SIZE
*/
MAX_SIZE: Number.parseInt(process.env.DOLLHOUSE_MAX_API_CACHE_SIZE || '200'),
/**
* Maximum memory for API cache (MB)
* Environment: DOLLHOUSE_MAX_API_CACHE_MEMORY
*/
MAX_MEMORY_MB: Number.parseInt(process.env.DOLLHOUSE_MAX_API_CACHE_MEMORY || '5'),
},
};
/**
* Storage layer configuration
*
* Centralizes TTL, cooldown, and debounce values used by ElementStorageLayer,
* MemoryStorageLayer, and tool discovery caching. Each constant supports a
* DOLLHOUSE_* env var with a legacy fallback for backward compatibility.
*/
export const STORAGE_LAYER_CONFIG = {
/**
* Minimum interval between full directory scans (milliseconds)
* Prevents excessive I/O on rapid list() calls.
*
* Environment: DOLLHOUSE_SCAN_COOLDOWN_MS (legacy: ELEMENT_SCAN_COOLDOWN_MS)
*/
SCAN_COOLDOWN_MS: Number.parseInt(process.env.DOLLHOUSE_SCAN_COOLDOWN_MS ?? process.env.ELEMENT_SCAN_COOLDOWN_MS ?? '1000'),
MIN_SCAN_COOLDOWN_MS: 100,
MAX_SCAN_COOLDOWN_MS: 60000,
/**
* Debounce interval for persisting _index.json in MemoryStorageLayer (milliseconds)
*
* Environment: DOLLHOUSE_INDEX_DEBOUNCE_MS (legacy: MEMORY_INDEX_DEBOUNCE_MS)
*/
INDEX_DEBOUNCE_MS: Number.parseInt(process.env.DOLLHOUSE_INDEX_DEBOUNCE_MS ?? process.env.MEMORY_INDEX_DEBOUNCE_MS ?? '2000'),
MIN_INDEX_DEBOUNCE_MS: 100,
MAX_INDEX_DEBOUNCE_MS: 30000,
/**
* TTL for element LRU caches in BaseElementManager (milliseconds)
* Default: 1 hour. This is a safety net only — the storage layer's mtime-based
* scanning handles real freshness detection. Set to 0 to disable TTL entirely.
*
* Environment: DOLLHOUSE_ELEMENT_CACHE_TTL_MS (legacy: ELEMENT_CACHE_TTL_MS)
*/
ELEMENT_CACHE_TTL_MS: Number.parseInt(process.env.DOLLHOUSE_ELEMENT_CACHE_TTL_MS ?? process.env.ELEMENT_CACHE_TTL_MS ?? '3600000'),
MIN_ELEMENT_CACHE_TTL_MS: 0,
MAX_ELEMENT_CACHE_TTL_MS: 3600000,
/**
* TTL for file-path-to-ID reverse index caches (milliseconds)
* Default: 1 hour. Set to 0 to disable TTL (rely on storage layer mtime scanning).
*
* Environment: DOLLHOUSE_PATH_CACHE_TTL_MS (legacy: ELEMENT_PATH_CACHE_TTL_MS)
*/
PATH_CACHE_TTL_MS: Number.parseInt(process.env.DOLLHOUSE_PATH_CACHE_TTL_MS ?? process.env.ELEMENT_PATH_CACHE_TTL_MS ?? '3600000'),
MIN_PATH_CACHE_TTL_MS: 0,
MAX_PATH_CACHE_TTL_MS: 3600000,
/**
* TTL for tool discovery cache in ServerSetup (milliseconds)
*
* Environment: DOLLHOUSE_TOOL_CACHE_TTL_MS
*/
TOOL_CACHE_TTL_MS: Number.parseInt(process.env.DOLLHOUSE_TOOL_CACHE_TTL_MS ?? '60000'),
MIN_TOOL_CACHE_TTL_MS: 5000,
MAX_TOOL_CACHE_TTL_MS: 600000,
/**
* Global memory budget for all registered LRU caches (bytes)
* Provides a cross-cache ceiling that triggers eviction from the least-active
* cache when the aggregate memory usage exceeds this limit.
*
* Environment: DOLLHOUSE_GLOBAL_CACHE_MEMORY_MB (default: 150 MB)
*/
GLOBAL_CACHE_MEMORY_BYTES: Number.parseInt(process.env.DOLLHOUSE_GLOBAL_CACHE_MEMORY_MB ?? '150') * 1024 * 1024,
MIN_GLOBAL_CACHE_MEMORY_MB: 20,
MAX_GLOBAL_CACHE_MEMORY_MB: 1000,
/**
* Maximum backup files to keep per memory name per date folder.
* When a new backup is created and the count exceeds this limit,
* the oldest backups for that memory are deleted.
*
* Environment: DOLLHOUSE_MAX_BACKUPS_PER_MEMORY (default: 3)
*/
MAX_BACKUPS_PER_MEMORY: Number.parseInt(process.env.DOLLHOUSE_MAX_BACKUPS_PER_MEMORY ?? '3'),
MIN_BACKUPS_PER_MEMORY: 1,
MAX_BACKUPS_PER_MEMORY_LIMIT: 50,
/**
* Maximum backup files to keep per element per date folder (all non-memory types).
* When a new backup is created and the count exceeds this limit,
* the oldest backups for that element are deleted.
*
* Environment: DOLLHOUSE_MAX_BACKUPS_PER_ELEMENT (default: 3)
*/
MAX_BACKUPS_PER_ELEMENT: Number.parseInt(process.env.DOLLHOUSE_MAX_BACKUPS_PER_ELEMENT ?? '3'),
MIN_BACKUPS_PER_ELEMENT: 1,
MAX_BACKUPS_PER_ELEMENT_LIMIT: 50,
/**
* Whether element backups are enabled.
* Set to 'false' to disable automatic pre-save and pre-delete backups.
*
* Environment: DOLLHOUSE_BACKUPS_ENABLED (default: true)
*/
BACKUPS_ENABLED: process.env.DOLLHOUSE_BACKUPS_ENABLED !== 'false',
/**
* Maximum age in days for backup date folders.
* Date folders older than this are eligible for automatic cleanup.
* Set to 0 to disable age-based cleanup.
*
* Environment: DOLLHOUSE_BACKUP_RETENTION_DAYS (default: 7)
*/
BACKUP_RETENTION_DAYS: Number.parseInt(process.env.DOLLHOUSE_BACKUP_RETENTION_DAYS ?? '7'),
MIN_BACKUP_RETENTION_DAYS: 1,
MAX_BACKUP_RETENTION_DAYS: 365,
/**
* Debounce window for memory saves (milliseconds).
* When addEntry is called rapidly, saves are coalesced — only the latest
* state is written to disk after this delay. Prevents FD exhaustion from
* high-frequency memory updates (Issue #656).
*
* Environment: DOLLHOUSE_MEMORY_SAVE_DEBOUNCE_MS (default: 2000)
*/
MEMORY_SAVE_DEBOUNCE_MS: Number.parseInt(process.env.DOLLHOUSE_MEMORY_SAVE_DEBOUNCE_MS ?? '2000'),
MIN_MEMORY_SAVE_DEBOUNCE_MS: 500,
MAX_MEMORY_SAVE_DEBOUNCE_MS: 30000,
/**
* Save frequency monitoring window (milliseconds).
* Tracks addEntry calls per memory within this window.
* When a memory exceeds MEMORY_SAVE_FREQUENCY_WARN_THRESHOLD
* calls in this window, a warning is logged.
*
* Issue #657: Detect runaway save loops before they exhaust resources.
*
* Environment: DOLLHOUSE_MEMORY_SAVE_MONITOR_WINDOW_MS (default: 60000 = 1 minute)
*/
MEMORY_SAVE_MONITOR_WINDOW_MS: Math.max(5000, Math.min(300000, Number.parseInt(process.env.DOLLHOUSE_MEMORY_SAVE_MONITOR_WINDOW_MS ?? '60000'))),
/**
* Warn threshold: number of addEntry calls per memory per monitor window.
* If exceeded, log a warning. Default: 50 calls/minute. Range: 5–10000.
*
* Environment: DOLLHOUSE_MEMORY_SAVE_FREQUENCY_WARN (default: 50)
*/
MEMORY_SAVE_FREQUENCY_WARN_THRESHOLD: Math.max(5, Math.min(10000, Number.parseInt(process.env.DOLLHOUSE_MEMORY_SAVE_FREQUENCY_WARN ?? '50'))),
/**
* Critical threshold: number of addEntry calls per memory per monitor window.
* If exceeded, log an error-level alert. Default: 200 calls/minute. Range: 10–50000.
*
* Environment: DOLLHOUSE_MEMORY_SAVE_FREQUENCY_CRITICAL (default: 200)
*/
MEMORY_SAVE_FREQUENCY_CRITICAL_THRESHOLD: Math.max(10, Math.min(50000, Number.parseInt(process.env.DOLLHOUSE_MEMORY_SAVE_FREQUENCY_CRITICAL ?? '200'))),
};
/**
* Get validated scan cooldown within acceptable bounds
*/
export function getValidatedScanCooldown() {
const value = STORAGE_LAYER_CONFIG.SCAN_COOLDOWN_MS;
if (value < STORAGE_LAYER_CONFIG.MIN_SCAN_COOLDOWN_MS)
return STORAGE_LAYER_CONFIG.MIN_SCAN_COOLDOWN_MS;
if (value > STORAGE_LAYER_CONFIG.MAX_SCAN_COOLDOWN_MS)
return STORAGE_LAYER_CONFIG.MAX_SCAN_COOLDOWN_MS;
return value;
}
/**
* Get validated index debounce within acceptable bounds
*/
export function getValidatedIndexDebounce() {
const value = STORAGE_LAYER_CONFIG.INDEX_DEBOUNCE_MS;
if (value < STORAGE_LAYER_CONFIG.MIN_INDEX_DEBOUNCE_MS)
return STORAGE_LAYER_CONFIG.MIN_INDEX_DEBOUNCE_MS;
if (value > STORAGE_LAYER_CONFIG.MAX_INDEX_DEBOUNCE_MS)
return STORAGE_LAYER_CONFIG.MAX_INDEX_DEBOUNCE_MS;
return value;
}
/**
* Get validated element cache TTL within acceptable bounds
*/
export function getValidatedElementCacheTTL() {
const value = STORAGE_LAYER_CONFIG.ELEMENT_CACHE_TTL_MS;
if (value < STORAGE_LAYER_CONFIG.MIN_ELEMENT_CACHE_TTL_MS)
return STORAGE_LAYER_CONFIG.MIN_ELEMENT_CACHE_TTL_MS;
if (value > STORAGE_LAYER_CONFIG.MAX_ELEMENT_CACHE_TTL_MS)
return STORAGE_LAYER_CONFIG.MAX_ELEMENT_CACHE_TTL_MS;
return value;
}
/**
* Get validated path cache TTL within acceptable bounds
*/
export function getValidatedPathCacheTTL() {
const value = STORAGE_LAYER_CONFIG.PATH_CACHE_TTL_MS;
if (value < STORAGE_LAYER_CONFIG.MIN_PATH_CACHE_TTL_MS)
return STORAGE_LAYER_CONFIG.MIN_PATH_CACHE_TTL_MS;
if (value > STORAGE_LAYER_CONFIG.MAX_PATH_CACHE_TTL_MS)
return STORAGE_LAYER_CONFIG.MAX_PATH_CACHE_TTL_MS;
return value;
}
/**
* Get validated tool cache TTL within acceptable bounds
*/
export function getValidatedToolCacheTTL() {
const value = STORAGE_LAYER_CONFIG.TOOL_CACHE_TTL_MS;
if (value < STORAGE_LAYER_CONFIG.MIN_TOOL_CACHE_TTL_MS)
return STORAGE_LAYER_CONFIG.MIN_TOOL_CACHE_TTL_MS;
if (value > STORAGE_LAYER_CONFIG.MAX_TOOL_CACHE_TTL_MS)
return STORAGE_LAYER_CONFIG.MAX_TOOL_CACHE_TTL_MS;
return value;
}
/**
* Get validated max backups per element within acceptable bounds
*/
export function getValidatedMaxBackupsPerElement() {
const value = STORAGE_LAYER_CONFIG.MAX_BACKUPS_PER_ELEMENT;
if (value < STORAGE_LAYER_CONFIG.MIN_BACKUPS_PER_ELEMENT)
return STORAGE_LAYER_CONFIG.MIN_BACKUPS_PER_ELEMENT;
if (value > STORAGE_LAYER_CONFIG.MAX_BACKUPS_PER_ELEMENT_LIMIT)
return STORAGE_LAYER_CONFIG.MAX_BACKUPS_PER_ELEMENT_LIMIT;
return value;
}
/**
* Get validated global cache memory budget in bytes
*/
export function getValidatedGlobalCacheMemoryBytes() {
const valueMB = Number.parseInt(process.env.DOLLHOUSE_GLOBAL_CACHE_MEMORY_MB ?? '150');
if (valueMB < STORAGE_LAYER_CONFIG.MIN_GLOBAL_CACHE_MEMORY_MB) {
return STORAGE_LAYER_CONFIG.MIN_GLOBAL_CACHE_MEMORY_MB * 1024 * 1024;
}
if (valueMB > STORAGE_LAYER_CONFIG.MAX_GLOBAL_CACHE_MEMORY_MB) {
return STORAGE_LAYER_CONFIG.MAX_GLOBAL_CACHE_MEMORY_MB * 1024 * 1024;
}
return valueMB * 1024 * 1024;
}
/**
* Environment variable names for documentation and tooling
*/
export const ENV_VARS = {
// File lock configuration
LOCK_TIMEOUT: 'DOLLHOUSE_LOCK_TIMEOUT',
LOCK_STALE_THRESHOLD: 'DOLLHOUSE_LOCK_STALE_THRESHOLD',
LOCK_MAX_RETRIES: 'DOLLHOUSE_LOCK_MAX_RETRIES',
LOCK_RETRY_DELAY: 'DOLLHOUSE_LOCK_RETRY_DELAY',
// Metrics configuration
METRICS_BATCH_SIZE: 'DOLLHOUSE_METRICS_BATCH_SIZE',
METRICS_FLUSH_INTERVAL: 'DOLLHOUSE_METRICS_FLUSH_INTERVAL',
// Cache configuration
CACHE_SAMPLE_SIZE: 'DOLLHOUSE_CACHE_SAMPLE_SIZE',
// Storage layer configuration
SCAN_COOLDOWN: 'DOLLHOUSE_SCAN_COOLDOWN_MS',
INDEX_DEBOUNCE: 'DOLLHOUSE_INDEX_DEBOUNCE_MS',
ELEMENT_CACHE_TTL: 'DOLLHOUSE_ELEMENT_CACHE_TTL_MS',
PATH_CACHE_TTL: 'DOLLHOUSE_PATH_CACHE_TTL_MS',
TOOL_CACHE_TTL: 'DOLLHOUSE_TOOL_CACHE_TTL_MS',
GLOBAL_CACHE_MEMORY: 'DOLLHOUSE_GLOBAL_CACHE_MEMORY_MB',
// Backup configuration
MAX_BACKUPS_PER_ELEMENT: 'DOLLHOUSE_MAX_BACKUPS_PER_ELEMENT',
BACKUPS_ENABLED: 'DOLLHOUSE_BACKUPS_ENABLED',
// Memory limits
MAX_PERSONA_CACHE_SIZE: 'DOLLHOUSE_MAX_PERSONA_CACHE_SIZE',
MAX_PERSONA_CACHE_MEMORY: 'DOLLHOUSE_MAX_PERSONA_CACHE_MEMORY',
MAX_METRICS_CACHE_SIZE: 'DOLLHOUSE_MAX_METRICS_CACHE_SIZE',
MAX_METRICS_CACHE_MEMORY: 'DOLLHOUSE_MAX_METRICS_CACHE_MEMORY',
MAX_SEARCH_CACHE_SIZE: 'DOLLHOUSE_MAX_SEARCH_CACHE_SIZE',
MAX_SEARCH_CACHE_MEMORY: 'DOLLHOUSE_MAX_SEARCH_CACHE_MEMORY',
MAX_INDEX_CACHE_SIZE: 'DOLLHOUSE_MAX_INDEX_CACHE_SIZE',
MAX_INDEX_CACHE_MEMORY: 'DOLLHOUSE_MAX_INDEX_CACHE_MEMORY',
MAX_API_CACHE_SIZE: 'DOLLHOUSE_MAX_API_CACHE_SIZE',
MAX_API_CACHE_MEMORY: 'DOLLHOUSE_MAX_API_CACHE_MEMORY',
};
/**
* Validation Helpers
*/
/**
* Get validated lock timeout within acceptable bounds
*
* @returns Validated timeout in milliseconds (1s - 60s)
*
* @example
* ```typescript
* const timeout = getValidatedLockTimeout();
* // Returns value between 1000 and 60000
* ```
*/
export function getValidatedLockTimeout() {
const timeout = FILE_LOCK_CONFIG.DEFAULT_TIMEOUT_MS;
if (timeout < FILE_LOCK_CONFIG.MIN_TIMEOUT_MS) {
return FILE_LOCK_CONFIG.MIN_TIMEOUT_MS;
}
if (timeout > FILE_LOCK_CONFIG.MAX_TIMEOUT_MS) {
return FILE_LOCK_CONFIG.MAX_TIMEOUT_MS;
}
return timeout;
}
/**
* Get validated metrics batch size within acceptable bounds
*
* @returns Validated batch size (1 - 1000)
*
* @example
* ```typescript
* const batchSize = getValidatedBatchSize();
* // Returns value between 1 and 1000
* ```
*/
export function getValidatedBatchSize() {
const batchSize = METRICS_CONFIG.BATCH_SIZE;
if (batchSize < METRICS_CONFIG.MIN_BATCH_SIZE) {
return METRICS_CONFIG.MIN_BATCH_SIZE;
}
if (batchSize > METRICS_CONFIG.MAX_BATCH_SIZE) {
return METRICS_CONFIG.MAX_BATCH_SIZE;
}
return batchSize;
}
/**
* Get validated metrics flush interval within acceptable bounds
*
* @returns Validated flush interval in milliseconds (100ms - 5min)
*
* @example
* ```typescript
* const interval = getValidatedFlushInterval();
* // Returns value between 100 and 300000
* ```
*/
export function getValidatedFlushInterval() {
const interval = METRICS_CONFIG.FLUSH_INTERVAL_MS;
if (interval < METRICS_CONFIG.MIN_FLUSH_INTERVAL_MS) {
return METRICS_CONFIG.MIN_FLUSH_INTERVAL_MS;
}
if (interval > METRICS_CONFIG.MAX_FLUSH_INTERVAL_MS) {
return METRICS_CONFIG.MAX_FLUSH_INTERVAL_MS;
}
return interval;
}
/**
* Get validated cache sample size for balanced estimation mode
*
* @returns Validated sample size (1 - 100)
*
* @example
* ```typescript
* const sampleSize = getValidatedSampleSize();
* // Returns value between 1 and 100
* ```
*/
export function getValidatedSampleSize() {
const sampleSize = CACHE_SIZE_ESTIMATION_CONFIG.BALANCED_SAMPLE_SIZE;
if (sampleSize < CACHE_SIZE_ESTIMATION_CONFIG.MIN_SAMPLE_SIZE) {
return CACHE_SIZE_ESTIMATION_CONFIG.MIN_SAMPLE_SIZE;
}
if (sampleSize > CACHE_SIZE_ESTIMATION_CONFIG.MAX_SAMPLE_SIZE) {
return CACHE_SIZE_ESTIMATION_CONFIG.MAX_SAMPLE_SIZE;
}
return sampleSize;
}
/**
* Calculate retry delay using exponential backoff
*
* @param attempt - Current retry attempt number (1-based)
* @returns Delay in milliseconds for this attempt
*
* @example
* ```typescript
* const delay = calculateLockRetryDelay(3);
* // Returns 400ms (100 * 2^2)
* ```
*/
export function calculateLockRetryDelay(attempt) {
const backoffMultiplier = 2;
const delay = FILE_LOCK_CONFIG.RETRY.INITIAL_DELAY_MS * Math.pow(backoffMultiplier, attempt - 1);
// Cap at max timeout to prevent excessive delays
return Math.min(delay, FILE_LOCK_CONFIG.MAX_TIMEOUT_MS);
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGVyZm9ybWFuY2UtY29uc3RhbnRzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvbmZpZy9wZXJmb3JtYW5jZS1jb25zdGFudHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7R0FVRztBQUVIOzs7Ozs7Ozs7O0dBVUc7QUFDSCxNQUFNLENBQUMsTUFBTSxnQkFBZ0IsR0FBRztJQUM5Qjs7Ozs7Ozs7O09BU0c7SUFDSCxrQkFBa0IsRUFBRSxNQUFNLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsc0JBQXNCLElBQUksT0FBTyxDQUFDO0lBRWxGOzs7T0FHRztJQUNILGNBQWMsRUFBRSxJQUFJO0lBRXBCOzs7T0FHRztJQUNILGNBQWMsRUFBRSxLQUFLO0lBRXJCOzs7OztPQUtHO0lBQ0gsa0JBQWtCLEVBQUUsTUFBTSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLDhCQUE4QixJQUFJLE9BQU8sQ0FBQztJQUUxRjs7T0FFRztJQUNILEtBQUssRUFBRTtRQUNMOzs7O1dBSUc7UUFDSCxZQUFZLEVBQUUsTUFBTSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLDBCQUEwQixJQUFJLEdBQUcsQ0FBQztRQUU1RTs7Ozs7V0FLRztRQUNILGdCQUFnQixFQUFFLE1BQU0sQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQywwQkFBMEIsSUFBSSxLQUFLLENBQUM7S0FDbkY7Q0FDTyxDQUFDO0FBRVg7Ozs7Ozs7OztHQVNHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sY0FBYyxHQUFHO0lBQzVCOzs7Ozs7Ozs7T0FTRztJQUNILFVBQVUsRUFBRSxNQUFNLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsNEJBQTRCLElBQUksSUFBSSxDQUFDO0lBRTdFOztPQUVHO0lBQ0gsY0FBYyxFQUFFLENBQUM7SUFFakI7O09BRUc7SUFDSCxjQUFjLEVBQUUsSUFBSTtJQUVwQjs7Ozs7Ozs7T0FRRztJQUNILGlCQUFpQixFQUFFLE1BQU0sQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxnQ0FBZ0MsSUFBSSxNQUFNLENBQUM7SUFFMUY7OztPQUdHO0lBQ0gscUJBQXFCLEVBQUUsR0FBRztJQUUxQjs7O09BR0c7SUFDSCxxQkFBcUIsRUFBRSxNQUFNO0NBQ3JCLENBQUM7QUFFWDs7Ozs7Ozs7OztHQVVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sNEJBQTRCLEdBQUc7SUFDMUM7Ozs7O09BS0c7SUFDSCxjQUFjLEVBQUUsQ0FBQztJQUVqQjs7Ozs7Ozs7T0FRRztJQUNILG9CQUFvQixFQUFFLEVBQUU7SUFFeEI7Ozs7Ozs7O09BUUc7SUFDSCxtQkFBbUIsRUFBRSxFQUFFO0lBRXZCOzs7Ozs7OztPQVFHO0lBQ0gsY0FBYyxFQUFFLEVBQUU7SUFFbEI7Ozs7Ozs7O09BUUc7SUFDSCxnQkFBZ0IsRUFBRSxFQUFFO0lBRXBCOzs7Ozs7O09BT0c7SUFDSCxvQkFBb0IsRUFBRSxNQUFNLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsMkJBQTJCLElBQUksSUFBSSxDQUFDO0lBRXRGOztPQUVHO0lBQ0gsZUFBZSxFQUFFLENBQUM7SUFFbEI7OztPQUdHO0lBQ0gsZUFBZSxFQUFFLEdBQUc7Q0FDWixDQUFDO0FBRVg7Ozs7O0dBS0c7QUFDSCxNQUFNLENBQUMsTUFBTSxhQUFhLEdBQUc7SUFDM0I7O09BRUc7SUFDSCxhQUFhLEVBQUU7UUFDYjs7O1dBR0c7UUFDSCxRQUFRLEVBQUUsTUFBTSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLGdDQUFnQyxJQUFJLElBQUksQ0FBQztRQUUvRTs7O1dBR0c7UUFDSCxhQUFhLEVBQUUsTUFBTSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLGtDQUFrQyxJQUFJLElBQUksQ0FBQztLQUN2RjtJQUVEOztPQUVHO0lBQ0gsYUFBYSxFQUFFO1FBQ2I7OztXQUdHO1FBQ0gsUUFBUSxFQUFFLE1BQU0sQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxnQ0FBZ0MsSUFBSSxLQUFLLENBQUM7UUFFaEY7OztXQUdHO1FBQ0gsYUFBYSxFQUFFLE1BQU0sQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxrQ0FBa0MsSUFBSSxHQUFHLENBQUM7S0FDdEY7SUFFRDs7T0FFRztJQUNILFlBQVksRUFBRTtRQUNaOzs7V0FHRztRQUNILFFBQVEsRUFBRSxNQUFNLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsK0JBQStCLElBQUksS0FBSyxDQUFDO1FBRS9FOzs7V0FHRztRQUNILGFBQWEsRUFBRSxNQUFNLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsaUNBQWlDLElBQUksSUFBSSxDQUFDO0tBQ3RGO0lBRUQ7O09BRUc7SUFDSCxXQUFXLEVBQUU7UUFDWDs7O1dBR0c7UUFDSCxRQUFRLEVBQUUsTUFBTSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLDhCQUE4QixJQUFJLElBQUksQ0FBQztRQUU3RTs7O1dBR0c7UUFDSCxhQUFhLEVBQUUsTUFBTSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLGdDQUFnQyxJQUFJLElBQUksQ0FBQztLQUNyRjtJQUVEOztPQUVHO0lBQ0gsU0FBUyxFQUFFO1FBQ1Q7OztXQUdHO1FBQ0gsUUFBUSxFQUFFLE1BQU0sQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyw0QkFBNEIsSUFBSSxLQUFLLENBQUM7UUFFNUU7OztXQUdHO1FBQ0gsYUFBYSxFQUFFLE1BQU0sQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyw4QkFBOEIsSUFBSSxHQUFHLENBQUM7S0FDbEY7Q0FDTyxDQUFDO0FBRVg7Ozs7OztHQU1HO0FBQ0gsTUFBTSxDQUFDLE1BQU0sb0JBQW9CLEdBQUc7SUFDbEM7Ozs7O09BS0c7SUFDSCxnQkFBZ0IsRUFBRSxNQUFNLENBQUMsUUFBUSxDQUMvQixPQUFPLENBQUMsR0FBRyxDQUFDLDBCQUEwQixJQUFJLE9BQU8sQ0FBQyxHQUFHLENBQUMsd0JBQXdCLElBQUksTUFBTSxDQUN6RjtJQUNELG9CQUFvQixFQUFFLEdBQUc7SUFDekIsb0JBQW9CLEVBQUUsS0FBSztJQUUzQjs7OztPQUlHO0lBQ0gsaUJBQWlCLEVBQUUsTUFBTSxDQUFDLFFBQVEsQ0FDaEMsT0FBTyxDQUFDLEdBQUcsQ0FBQywyQkFBMkIsSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLHdCQUF3QixJQUFJLE1BQU0sQ0FDMUY7SUFDRCxxQkFBcUIsRUFBRSxHQUFHO0lBQzFCLHFCQUFxQixFQUFFLEtBQUs7SUFFNUI7Ozs7OztPQU1HO0lBQ0gsb0JBQW9CLEVBQUUsTUFBTSxDQUFDLFFBQVEsQ0FDbkMsT0FBTyxDQUFDLEdBQUcsQ0FBQyw4QkFBOEIsSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLG9CQUFvQixJQUFJLFNBQVMsQ0FDNUY7SUFDRCx3QkFBd0IsRUFBRSxDQUFDO0lBQzNCLHdCQUF3QixFQUFFLE9BQU87SUFFakM7Ozs7O09BS0c7SUFDSCxpQkFBaUIsRUFBRSxNQUFNLENBQUMsUUFBUSxDQUNoQyxPQUFPLENBQUMsR0FBRyxDQUFDLDJCQUEyQixJQUFJLE9BQU8sQ0FBQyxHQUFHLENBQUMseUJBQXlCLElBQUksU0FBUyxDQUM5RjtJQUNELHFCQUFxQixFQUFFLENBQUM7SUFDeEIscUJBQXFCLEVBQUUsT0FBTztJQUU5Qjs7OztPQUlHO0lBQ0gsaUJBQWlCLEVBQUUsTUFBTSxDQUFDLFFBQVEsQ0FDaEMsT0FBTyxDQUFDLEdBQUcsQ0FBQywyQkFBMkIsSUFBSSxPQUFPLENBQ25EO0lBQ0QscUJBQXFCLEVBQUUsSUFBSTtJQUMzQixxQkFBcUIsRUFBRSxNQUFNO0lBRTdCOzs7Ozs7T0FNRztJQUNILHlCQUF5QixFQUFFLE1BQU0sQ0FBQyxRQUFRLENBQ3hDLE9BQU8sQ0FBQyxHQUFHLENBQUMsZ0NBQWdDLElBQUksS0FBSyxDQUN0RCxHQUFHLElBQUksR0FBRyxJQUFJO0lBQ2YsMEJBQTBCLEVBQUUsRUFBRTtJQUM5QiwwQkFBMEIsRUFBRSxJQUFJO0lBRWhDOzs7Ozs7T0FNRztJQUNILHNCQUFzQixFQUFFLE1BQU0sQ0FBQyxRQUFRLENBQ3JDLE9BQU8sQ0FBQyxHQUFHLENBQUMsZ0NBQWdDLElBQUksR0FBRyxDQUNwRDtJQUNELHNCQUFzQixFQUFFLENBQUM7SUFDekIsNEJBQTRCLEVBQUUsRUFBRTtJQUVoQzs7Ozs7O09BTUc7SUFDSCx1QkFBdUIsRUFBRSxNQUFNLENBQUMsUUFBUSxDQUN0QyxPQUFPLENBQUMsR0FBRyxDQUFDLGlDQUFpQyxJQUFJLEdBQUcsQ0FDckQ7SUFDRCx1QkFBdUIsRUFBRSxDQUFDO0lBQzFCLDZCQUE2QixFQUFFLEVBQUU7SUFFakM7Ozs7O09BS0c7SUFDSCxlQUFlLEVBQUUsT0FBTyxDQUFDLEdBQUcsQ0FBQyx5QkFBeUIsS0FBSyxPQUFPO0lBRWxFOzs7Ozs7T0FNRztJQUNILHFCQUFxQixFQUFFLE1BQU0sQ0FBQyxRQUFRLENBQ3BDLE9BQU8sQ0FBQyxHQUFHLENBQUMsK0JBQStCLElBQUksR0FBRyxDQUNuRDtJQUNELHlCQUF5QixFQUFFLENBQUM7SUFDNUIseUJBQXlCLEVBQUUsR0FBRztJQUU5Qjs7Ozs7OztPQU9HO0lBQ0gsdUJBQXVCLEVBQUUsTUFBTSxDQUFDLFFBQVEsQ0FDdEMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxpQ0FBaUMsSUFBSSxNQUFNLENBQ3hEO0lBQ0QsMkJBQTJCLEVBQUUsR0FBRztJQUNoQywyQkFBMkIsRUFBRSxLQUFLO0lBRWxDOzs7Ozs7Ozs7T0FTRztJQUNILDZCQUE2QixFQUFFLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxHQUFHLENBQUMsTUFBTSxFQUMzRCxNQUFNLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsdUNBQXVDLElBQUksT0FBTyxDQUFDLENBQ2hGLENBQUM7SUFFRjs7Ozs7T0FLRztJQUNILG9DQUFvQyxFQUFFLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxHQUFHLENBQUMsS0FBSyxFQUM5RCxNQUFNLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsb0NBQW9DLElBQUksSUFBSSxDQUFDLENBQzFFLENBQUM7SUFFRjs7Ozs7T0FLRztJQUNILHdDQUF3QyxFQUFFLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLElBQUksQ0FBQyxHQUFHLENBQUMsS0FBSyxFQUNuRSxNQUFNLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsd0NBQXdDLElBQUksS0FBSyxDQUFDLENBQy9FLENBQUM7Q0FDTSxDQUFDO0FBRVg7O0dBRUc7QUFDSCxNQUFNLFVBQVUsd0JBQXdCO0lBQ3RDLE1BQU0sS0FBSyxHQUFHLG9CQUFvQixDQUFDLGdCQUFnQixDQUFDO0lBQ3BELElBQUksS0FBSyxHQUFHLG9CQUFvQixDQUFDLG9CQUFvQjtRQUFFLE9BQU8sb0JBQW9CLENBQUMsb0JBQW9CLENBQUM7SUFDeEcsSUFBSSxLQUFLLEdBQUcsb0JBQW9CLENBQUMsb0JBQW9CO1FBQUUsT0FBTyxvQkFBb0IsQ0FBQyxvQkFBb0IsQ0FBQztJQUN4RyxPQUFPLEtBQUssQ0FBQztBQUNmLENBQUM7QUFFRDs7R0FFRztBQUNILE1BQU0sVUFBVSx5QkFBeUI7SUFDdkMsTUFBTSxLQUFLLEdBQUcsb0JBQW9CLENBQUMsaUJBQWlCLENBQUM7SUFDckQsSUFBSSxLQUFLLEdBQUcsb0JBQW9CLENBQUMscUJBQXFCO1FBQUUsT0FBTyxvQkFBb0IsQ0FBQyxxQkFBcUIsQ0FBQztJQUMxRyxJQUFJLEtBQUssR0FBRyxvQkFBb0IsQ0FBQyxxQkFBcUI7UUFBRSxPQUFPLG9CQUFvQixDQUFDLHFCQUFxQixDQUFDO0lBQzFHLE9BQU8sS0FBSyxDQUFDO0FBQ2YsQ0FBQztBQUVEOztHQUVHO0FBQ0gsTUFBTSxVQUFVLDJCQUEyQjtJQUN6QyxNQUFNLEtBQUssR0FBRyxvQkFBb0IsQ0FBQyxvQkFBb0IsQ0FBQztJQUN4RCxJQUFJLEtBQUssR0FBRyxvQkFBb0IsQ0FBQyx3QkFBd0I7UUFBRSxPQUFPLG9CQUFvQixDQUFDLHdCQUF3QixDQUFDO0lBQ2hILElBQUksS0FBSyxHQUFHLG9CQUFvQixDQUFDLHdCQUF3QjtRQUFFLE9BQU8sb0JBQW9CLENBQUMsd0JBQXdCLENBQUM7SUFDaEgsT0FBTyxLQUFLLENBQUM7QUFDZixDQUFDO0FBRUQ7O0dBRUc7QUFDSCxNQUFNLFVBQVUsd0JBQXdCO0lBQ3RDLE1BQU0sS0FBSyxHQUFHLG9CQUFvQixDQUFDLGlCQUFpQixDQUFDO0lBQ3JELElBQUksS0FBSyxHQUFHLG9CQUFvQixDQUFDLHFCQUFxQjtRQUFFLE9BQU8sb0JBQW9CLENBQUMscUJBQXFCLENBQUM7SUFDMUcsSUFBSSxLQUFLLEdBQUcsb0JBQW9CLENBQUMscUJBQXFCO1FBQUUsT0FBTyxvQkFBb0IsQ0FBQyxxQkFBcUIsQ0FBQztJQUMxRyxPQUFPLEtBQUssQ0FBQztBQUNmLENBQUM7QUFFRDs7R0FFRztBQUNILE1BQU0sVUFBVSx3QkFBd0I7SUFDdEMsTUFBTSxLQUFLLEdBQUcsb0JBQW9CLENBQUMsaUJBQWlCLENBQUM7SUFDckQsSUFBSSxLQUFLLEdBQUcsb0JBQW9CLENBQUMscUJBQXFCO1FBQUUsT0FBTyxvQkFBb0IsQ0FBQyxxQkFBcUIsQ0FBQztJQUMxRyxJQUFJLEtBQUssR0FBRyxvQkFBb0IsQ0FBQyxxQkFBcUI7UUFBRSxPQUFPLG9CQUFvQixDQUFDLHFCQUFxQixDQUFDO0lBQzFHLE9BQU8sS0FBSyxDQUFDO0FBQ2YsQ0FBQztBQUVEOztHQUVHO0FBQ0gsTUFBTSxVQUFVLGdDQUFnQztJQUM5QyxNQUFNLEtBQUssR0FBRyxvQkFBb0IsQ0FBQyx1QkFBdUIsQ0FBQztJQUMzRCxJQUFJLEtBQUssR0FBRyxvQkFBb0IsQ0FBQyx1QkFBdUI7UUFBRSxPQUFPLG9CQUFvQixDQUFDLHVCQUF1QixDQUFDO0lBQzlHLElBQUksS0FBSyxHQUFHLG9CQUFvQixDQUFDLDZCQUE2QjtRQUFFLE9BQU8sb0JBQW9CLENBQUMsNkJBQTZCLENBQUM7SUFDMUgsT0FBTyxLQUFLLENBQUM7QUFDZixDQUFDO0FBRUQ7O0dBRUc7QUFDSCxNQUFNLFVBQVUsa0NBQWtDO0lBQ2hELE1BQU0sT0FBTyxHQUFHLE1BQU0sQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxnQ0FBZ0MsSUFBSSxLQUFLLENBQUMsQ0FBQztJQUN2RixJQUFJLE9BQU8sR0FBRyxvQkFBb0IsQ0FBQywwQkFBMEIsRUFBRSxDQUFDO1FBQzlELE9BQU8sb0JBQW9CLENBQUMsMEJBQTBCLEdBQUcsSUFBSSxHQUFHLElBQUksQ0FBQztJQUN2RSxDQUFDO0lBQ0QsSUFBSSxPQUFPLEdBQUcsb0JBQW9CLENBQUMsMEJBQTBCLEVBQUUsQ0FBQztRQUM5RCxPQUFPLG9CQUFvQixDQUFDLDBCQUEwQixHQUFHLElBQUksR0FBRyxJQUFJLENBQUM7SUFDdkUsQ0FBQztJQUNELE9BQU8sT0FBTyxHQUFHLElBQUksR0FBRyxJQUFJLENBQUM7QUFDL0IsQ0FBQztBQUVEOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sUUFBUSxHQUFHO0lBQ3RCLDBCQUEwQjtJQUMxQixZQUFZLEVBQUUsd0JBQXdCO0lBQ3RDLG9CQUFvQixFQUFFLGdDQUFnQztJQUN0RCxnQkFBZ0IsRUFBRSw0QkFBNEI7SUFDOUMsZ0JBQWdCLEVBQUUsNEJBQTRCO0lBRTlDLHdCQUF3QjtJQUN4QixrQkFBa0IsRUFBRSw4QkFBOEI7SUFDbEQsc0JBQXNCLEVBQUUsa0NBQWtDO0lBRTFELHNCQUFzQjtJQUN0QixpQkFBaUIsRUFBRSw2QkFBNkI7SUFFaEQsOEJBQThCO0lBQzlCLGFBQWEsRUFBRSw0QkFBNEI7SUFDM0MsY0FBYyxFQUFFLDZCQUE2QjtJQUM3QyxpQkFBaUIsRUFBRSxnQ0FBZ0M7SUFDbkQsY0FBYyxFQUFFLDZCQUE2QjtJQUM3QyxjQUFjLEVBQUUsNkJBQTZCO0lBQzdDLG1CQUFtQixFQUFFLGtDQUFrQztJQUV2RCx1QkFBdUI7SUFDdkIsdUJBQXVCLEVBQUUsbUNBQW1DO0lBQzVELGVBQWUsRUFBRSwyQkFBMkI7SUFFNUMsZ0JBQWdCO0lBQ2hCLHNCQUFzQixFQUFFLGtDQUFrQztJQUMxRCx3QkFBd0IsRUFBRSxvQ0FBb0M7SUFDOUQsc0JBQXNCLEVBQUUsa0NBQWtDO0lBQzFELHdCQUF3QixFQUFFLG9DQUFvQztJQUM5RCxxQkFBcUIsRUFBRSxpQ0FBaUM7SUFDeEQsdUJBQXVCLEVBQUUsbUNBQW1DO0lBQzVELG9CQUFvQixFQUFFLGdDQUFnQztJQUN0RCxzQkFBc0IsRUFBRSxrQ0FBa0M7SUFDMUQsa0JBQWtCLEVBQUUsOEJBQThCO0lBQ2xELG9CQUFvQixFQUFFLGdDQUFnQztDQUM5QyxDQUFDO0FBRVg7O0dBRUc7QUFFSDs7Ozs7Ozs7OztHQVVHO0FBQ0gsTUFBTSxVQUFVLHVCQUF1QjtJQUNyQyxNQUFNLE9BQU8sR0FBRyxnQkFBZ0IsQ0FBQyxrQkFBa0IsQ0FBQztJQUVwRCxJQUFJLE9BQU8sR0FBRyxnQkFBZ0IsQ0FBQyxjQUFjLEVBQUUsQ0FBQztRQUM5QyxPQUFPLGdCQUFnQixDQUFDLGNBQWMsQ0FBQztJQUN6QyxDQUFDO0lBRUQsSUFBSSxPQUFPLEdBQUcsZ0JBQWdCLENBQUMsY0FBYyxFQUFFLENBQUM7UUFDOUMsT0FBTyxnQkFBZ0IsQ0FBQyxjQUFjLENBQUM7SUFDekMsQ0FBQztJQUVELE9BQU8sT0FBTyxDQUFDO0FBQ2pCLENBQUM7QUFFRDs7Ozs7Ozs7OztHQVVHO0FBQ0gsTUFBTSxVQUFVLHFCQUFxQjtJQUNuQyxNQUFNLFNBQVMsR0FBRyxjQUFjLENBQUMsVUFBVSxDQUFDO0lBRTVDLElBQUksU0FBUyxHQUFHLGNBQWMsQ0FBQyxjQUFjLEVBQUUsQ0FBQztRQUM5QyxPQUFPLGNBQWMsQ0FBQyxjQUFjLENBQUM7SUFDdkMsQ0FBQztJQUVELElBQUksU0FBUyxHQUFHLGNBQWMsQ0FBQyxjQUFjLEVBQUUsQ0FBQztRQUM5QyxPQUFPLGNBQWMsQ0FBQyxjQUFjLENBQUM7SUFDdkMsQ0FBQztJQUVELE9BQU8sU0FBUyxDQUFDO0FBQ25CLENBQUM7QUFFRDs7Ozs7Ozs7OztHQVVHO0FBQ0gsTUFBTSxVQUFVLHlCQUF5QjtJQUN2QyxNQUFNLFFBQVEsR0FBRyxjQUFjLENBQUMsaUJBQWlCLENBQUM7SUFFbEQsSUFBSSxRQUFRLEdBQUcsY0FBYyxDQUFDLHFCQUFxQixFQUFFLENBQUM7UUFDcEQsT0FBTyxjQUFjLENBQUMscUJBQXFCLENBQUM7SUFDOUMsQ0FBQztJQUVELElBQUksUUFBUSxHQUFHLGNBQWMsQ0FBQyxxQkFBcUIsRUFBRSxDQUFDO1FBQ3BELE9BQU8sY0FBYyxDQUFDLHFCQUFxQixDQUFDO0lBQzlDLENBQUM7SUFFRCxPQUFPLFFBQVEsQ0FBQztBQUNsQixDQUFDO0FBRUQ7Ozs7Ozs7Ozs7R0FVRztBQUNILE1BQU0sVUFBVSxzQkFBc0I7SUFDcEMsTUFBTSxVQUFVLEdBQUcsNEJBQTRCLENBQUMsb0JBQW9CLENBQUM7SUFFckUsSUFBSSxVQUFVLEdBQUcsNEJBQTRCLENBQUMsZUFBZSxFQUFFLENBQUM7UUFDOUQsT0FBTyw0QkFBNEIsQ0FBQyxlQUFlLENBQUM7SUFDdEQsQ0FBQztJQUVELElBQUksVUFBVSxHQUFHLDRCQUE0QixDQUFDLGVBQWUsRUFBRSxDQUFDO1FBQzlELE9BQU8sNEJBQTRCLENBQUMsZUFBZSxDQUFDO0lBQ3RELENBQUM7SUFFRCxPQUFPLFVBQVUsQ0FBQztBQUNwQixDQUFDO0FBRUQ7Ozs7Ozs7Ozs7O0dBV0c7QUFDSCxNQUFNLFVBQVUsdUJBQXVCLENBQUMsT0FBZTtJQUNyRCxNQUFNLGlCQUFpQixHQUFHLENBQUMsQ0FBQztJQUM1QixNQUFNLEtBQUssR0FBRyxnQkFBZ0IsQ0FBQyxLQUFLLENBQUMsZ0JBQWdCLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxpQkFBaUIsRUFBRSxPQUFPLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFFakcsaURBQWlEO0lBQ2pELE9BQU8sSUFBSSxDQUFDLEdBQUcsQ0FBQyxLQUFLLEVBQUUsZ0JBQWdCLENBQUMsY0FBYyxDQUFDLENBQUM7QUFDMUQsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogUGVyZm9ybWFuY2UgQ29uZmlndXJhdGlvbiBDb25zdGFudHNcbiAqXG4gKiBDZW50cmFsaXplZCBjb25maWd1cmF0aW9uIGZvciBwZXJmb3JtYW5jZS1yZWxhdGVkIG1hZ2ljIG51bWJlcnMgaW5jbHVkaW5nXG4gKiBsb2NrIHRpbWVvdXRzLCBtZXRyaWNzIGJhdGNoaW5nLCBjYWNoZSBtZW1vcnkgZXN0aW1hdGlvbiwgYW5kIG90aGVyXG4gKiBwZXJmb3JtYW5jZS1jcml0aWNhbCBjb25zdGFudHMuXG4gKlxuICogQWxsIHZhbHVlcyBjYW4gYmUgb3ZlcnJpZGRlbiB2aWEgZW52aXJvbm1lbnQgdmFyaWFibGVzIGZvciBmbGV4aWJpbGl0eS5cbiAqXG4gKiBAbW9kdWxlIHBlcmZvcm1hbmNlLWNvbnN0YW50c1xuICovXG5cbi8qKlxuICogRmlsZSBsb2NraW5nIGNvbmZpZ3VyYXRpb25cbiAqXG4gKiBMb2NrIHRpbWVvdXQgaXMgYmFzZWQgb24gcDk1IG9wZXJhdGlvbiB0aW1lIGFuYWx5c2lzOlxuICogLSBNZWFzdXJlZCBwOTUgb3BlcmF0aW9uIHRpbWU6IDIuNSBzZWNvbmRzXG4gKiAtIFNhZmV0eSBidWZmZXI6IDR4IG11bHRpcGxpZXJcbiAqIC0gRGVmYXVsdCB0aW1lb3V0OiAxMCBzZWNvbmRzICgyLjVzICogNClcbiAqXG4gKiBUaGlzIHByb3ZpZGVzIGVub3VnaCB0aW1lIGZvciBvcGVyYXRpb25zIHRvIGNvbXBsZXRlIHdoaWxlIHByZXZlbnRpbmdcbiAqIGRlYWRsb2NrcyBmcm9tIGh1bmcgcHJvY2Vzc2VzLlxuICovXG5leHBvcnQgY29uc3QgRklMRV9MT0NLX0NPTkZJRyA9IHtcbiAgLyoqXG4gICAqIERlZmF1bHQgdGltZW91dCBmb3IgbG9jayBhY3F1aXNpdGlvbiAobWlsbGlzZWNvbmRzKVxuICAgKlxuICAgKiBCYXNlZCBvbiBlbXBpcmljYWwgYW5hbHlzaXM6XG4gICAqIC0gUDk1IGZpbGUgb3BlcmF0aW9uIHRpbWU6IDIuNXNcbiAgICogLSBCdWZmZXIgbXVsdGlwbGllcjogNHggZm9yIHNhZmV0eVxuICAgKiAtIFRvdGFsOiAxMCwwMDBtcyAoMTAgc2Vjb25kcylcbiAgICpcbiAgICogRW52aXJvbm1lbnQ6IERPTExIT1VTRV9MT0NLX1RJTUVPVVRcbiAgICovXG4gIERFRkFVTFRfVElNRU9VVF9NUzogTnVtYmVyLnBhcnNlSW50KHByb2Nlc3MuZW52LkRPTExIT1VTRV9MT0NLX1RJTUVPVVQgfHwgJzEwMDAwJyksXG5cbiAgLyoqXG4gICAqIE1pbmltdW0gYWxsb3dlZCBsb2NrIHRpbWVvdXQgKDEgc2Vjb25kKVxuICAgKiBQcmV2ZW50cyBtaXNjb25maWd1cmF0aW9uIHRoYXQgY291bGQgY2F1c2Ugc3B1cmlvdXMgdGltZW91dHNcbiAgICovXG4gIE1JTl9USU1FT1VUX01TOiAxMDAwLFxuXG4gIC8qKlxuICAgKiBNYXhpbXVtIGFsbG93ZWQgbG9jayB0aW1lb3V0ICg2MCBzZWNvbmRzKVxuICAgKiBQcmV2ZW50cyBpbmRlZmluaXRlIGhhbmdzIHdoaWxlIGFsbG93aW5nIGZvciBzbG93IG9wZXJhdGlvbnNcbiAgICovXG4gIE1BWF9USU1FT1VUX01TOiA2MDAwMCxcblxuICAvKipcbiAgICogU3RhbGUgbG9jayBjbGVhbnVwIHRocmVzaG9sZCAobWlsbGlzZWNvbmRzKVxuICAgKiBMb2NrcyBvbGRlciB0aGFuIHRoaXMgYXJlIGNvbnNpZGVyZWQgYWJhbmRvbmVkIGFuZCBjYW4gYmUgZm9yY2libHkgcmVsZWFzZWRcbiAgICpcbiAgICogRW52aXJvbm1lbnQ6IERPTExIT1VTRV9MT0NLX1NUQUxFX1RIUkVTSE9MRFxuICAgKi9cbiAgU1RBTEVfVEhSRVNIT0xEX01TOiBOdW1iZXIucGFyc2VJbnQocHJvY2Vzcy5lbnYuRE9MTEhPVVNFX0xPQ0tfU1RBTEVfVEhSRVNIT0xEIHx8ICc2MDAwMCcpLFxuXG4gIC8qKlxuICAgKiBMb2NrIHJldHJ5IGNvbmZpZ3VyYXRpb25cbiAgICovXG4gIFJFVFJZOiB7XG4gICAgLyoqXG4gICAgICogTWF4aW11bSBudW1iZXIgb2YgcmV0cnkgYXR0ZW1wdHMgZm9yIGxvY2sgYWNxdWlzaXRpb25cbiAgICAgKlxuICAgICAqIEVudmlyb25tZW50OiBET0xMSE9VU0VfTE9DS19NQVhfUkVUUklFU1xuICAgICAqL1xuICAgIE1BWF9BVFRFTVBUUzogTnVtYmVyLnBhcnNlSW50KHByb2Nlc3MuZW52LkRPTExIT1VTRV9MT0NLX01BWF9SRVRSSUVTIHx8ICczJyksXG5cbiAgICAvKipcbiAgICAgKiBJbml0aWFsIGRlbGF5IGJldHdlZW4gcmV0cmllcyAobWlsbGlzZWNvbmRzKVxuICAgICAqIFVzZXMgZXhwb25lbnRpYWwgYmFja29mZiBmcm9tIHRoaXMgYmFzZVxuICAgICAqXG4gICAgICogRW52aXJvbm1lbnQ6IERPTExIT1VTRV9MT0NLX1JFVFJZX0RFTEFZXG4gICAgICovXG4gICAgSU5JVElBTF9ERUxBWV9NUzogTnVtYmVyLnBhcnNlSW50KHByb2Nlc3MuZW52LkRPTExIT1VTRV9MT0NLX1JFVFJZX0RFTEFZIHx8ICcxMDAnKSxcbiAgfVxufSBhcyBjb25zdDtcblxuLyoqXG4gKiBNZXRyaWNzIGJhdGNoaW5nIGNvbmZpZ3VyYXRpb25cbiAqXG4gKiBPcHRpbWl6ZXMgd3JpdGUgcGVyZm9ybWFuY2UgYnkgYmF0Y2hpbmcgbWV0cmljcyB1cGRhdGVzOlxuICogLSBCYXRjaCBzaXplIHR1bmVkIGZvciBtZW1vcnkgdnMuIGxhdGVuY3kgdHJhZGUtb2ZmXG4gKiAtIFNtYWxsIGJhdGNoZXMgPSBsb3dlciBsYXRlbmN5LCBoaWdoZXIgb3ZlcmhlYWRcbiAqIC0gTGFyZ2UgYmF0Y2hlcyA9IGhpZ2hlciBsYXRlbmN5LCBsb3dlciBvdmVyaGVhZFxuICpcbiAqIEN1cnJlbnQgdmFsdWVzIHByb3ZpZGUgZ29vZCBiYWxhbmNlIGZvciB0eXBpY2FsIHdvcmtsb2Fkcy5cbiAqL1xuZXhwb3J0IGNvbnN0IE1FVFJJQ1NfQ09ORklHID0ge1xuICAvKipcbiAgICogTnVtYmVyIG9mIG1ldHJpY3MgdG8gYmF0Y2ggYmVmb3JlIGZsdXNoaW5nIHRvIGRpc2tcbiAgICpcbiAgICogVHJhZGUtb2ZmczpcbiAgICogLSBTaXplIDEwOiB+NTBtcyBmbHVzaCBsYXRlbmN5LCBtaW5pbWFsIG1lbW9yeSAoY2hvc2VuIGZvciBiYWxhbmNlKVxuICAgKiAtIFNpemUgMTAwOiB+MjAwbXMgZmx1c2ggbGF0ZW5jeSwgMTB4IG1vcmUgbWVtb3J5XG4gICAqIC0gU2l6ZSAxOiBObyBiYXRjaGluZywgaGlnaGVzdCBvdmVyaGVhZFxuICAgKlxuICAgKiBFbnZpcm9ubWVudDogRE9MTEhPVVNFX01FVFJJQ1NfQkFUQ0hfU0laRVxuICAgKi9cbiAgQkFUQ0hfU0laRTogTnVtYmVyLnBhcnNlSW50KHByb2Nlc3MuZW52LkRPTExIT1VTRV9NRVRSSUNTX0JBVENIX1NJWkUgfHwgJzEwJyksXG5cbiAgLyoqXG4gICAqIE1pbmltdW0gYmF0Y2ggc2l6ZSAobm8gYmF0Y2hpbmcpXG4gICAqL1xuICBNSU5fQkFUQ0hfU0laRTogMSxcblxuICAvKipcbiAgICogTWF4aW11bSBiYXRjaCBzaXplIHRvIHByZXZlbnQgbWVtb3J5IGlzc3Vlc1xuICAgKi9cbiAgTUFYX0JBVENIX1NJWkU6IDEwMDAsXG5cbiAgLyoqXG4gICAqIFRpbWUgaW50ZXJ2YWwgdG8gZm9yY2UgZmx1c2ggZXZlbiBpZiBiYXRjaCBub3QgZnVsbCAobWlsbGlzZWNvbmRzKVxuICAgKlxuICAgKiBFbnN1cmVzIG1ldHJpY3MgYXJlIHBlcnNpc3RlZCB3aXRoaW4gcmVhc29uYWJsZSB0aW1lOlxuICAgKiAtIDUgc2Vjb25kcyBwcm92aWRlcyBnb29kIGJhbGFuY2UgYmV0d2VlbiBmcmVzaG5lc3MgYW5kIGVmZmljaWVuY3lcbiAgICogLSBQcmV2ZW50cyB1bmJvdW5kZWQgZGVsYXkgZm9yIGxvdy10cmFmZmljIHNjZW5hcmlvc1xuICAgKlxuICAgKiBFbnZpcm9ubWVudDogRE9MTEhPVVNFX01FVFJJQ1NfRkxVU0hfSU5URVJWQUxcbiAgICovXG4gIEZMVVNIX0lOVEVSVkFMX01TOiBOdW1iZXIucGFyc2VJbnQocHJvY2Vzcy5lbnYuRE9MTEhPVVNFX01FVFJJQ1NfRkxVU0hfSU5URVJWQUwgfHwgJzUwMDAnKSxcblxuICAvKipcbiAgICogTWluaW11bSBmbHVzaCBpbnRlcnZhbCAoMTAwbXMpXG4gICAqIFByZXZlbnRzIGV4Y2Vzc2l2ZSBkaXNrIEkvT1xuICAgKi9cbiAgTUlOX0ZMVVNIX0lOVEVSVkFMX01TOiAxMDAsXG5cbiAgLyoqXG4gICAqIE1heGltdW0gZmx1c2ggaW50ZXJ2YWwgKDUgbWludXRlcylcbiAgICogRW5zdXJlcyB0aW1lbHkgbWV0cmljIHBlcnNpc3RlbmNlXG4gICAqL1xuICBNQVhfRkxVU0hfSU5URVJWQUxfTVM6IDMwMDAwMCxcbn0gYXMgY29uc3Q7XG5cbi8qKlxuICogQ2FjaGUgc2l6ZSBlc3RpbWF0aW9uIGNvbmZpZ3VyYXRpb25cbiAqXG4gKiBGYXN0IGJ5dGUtYmFzZWQgaGV1cmlzdGljcyBmb3IgbWVtb3J5IGVzdGltYXRpb24gYmFzZWQgb24gVjggbWVtb3J5IGxheW91dCBhbmFseXNpcy5cbiAqIFRoZXNlIHZhbHVlcyBhcmUgZGVyaXZlZCBmcm9tIGVtcGlyaWNhbCBtZWFzdXJlbWVudHMgb2YgVjggb2JqZWN0IHJlcHJlc2VudGF0aW9ucy5cbiAqXG4gKiBBY2N1cmFjeSB2cy4gU3BlZWQgdHJhZGUtb2ZmczpcbiAqIC0gRmFzdCBtb2RlOiAyLTV4IGZhc3RlciB0aGFuIEpTT04uc3RyaW5naWZ5LCA1MC0yMDAlIGFjY3VyYWN5XG4gKiAtIEJhbGFuY2VkIG1vZGU6IFNhbXBsZXMgZmlyc3QgMTAgZWxlbWVudHMsIGJldHRlciBhY2N1cmFjeVxuICogLSBBY2N1cmF0ZSBtb2RlOiBVc2VzIEpTT04uc3RyaW5naWZ5LCBzbG93ZXN0IGJ1dCBtb3N0IHByZWNpc2VcbiAqL1xuZXhwb3J0IGNvbnN0IENBQ0hFX1NJWkVfRVNUSU1BVElPTl9DT05GSUcgPSB7XG4gIC8qKlxuICAgKiBTaXplIG9mIHByaW1pdGl2ZSB2YWx1ZXMgaW4gVjggKGJ5dGVzKVxuICAgKiBDb3ZlcnMgbnVtYmVycywgYm9vbGVhbnMsIHNtYWxsIGludGVnZXJzXG4gICAqXG4gICAqIEJhc2VkIG9uIFY4IFNtaSAoU21hbGwgSW50ZWdlcikgcmVwcmVzZW50YXRpb25cbiAgICovXG4gIFBSSU1JVElWRV9TSVpFOiA4LFxuXG4gIC8qKlxuICAgKiBCYXNlIG1lbW9yeSBvdmVyaGVhZCBmb3IgSmF2YVNjcmlwdCBvYmplY3RzIChieXRlcylcbiAgICpcbiAgICogSW5jbHVkZXM6XG4gICAqIC0gT2JqZWN0IGhlYWRlcjogfjMyIGJ5dGVzXG4gICAqIC0gSGlkZGVuIGNsYXNzIHBvaW50ZXI6IH44IGJ5dGVzXG4gICAqIC0gUHJvcGVydGllcyBiYWNraW5nIHN0b3JlOiB+MjQgYnl0ZXNcbiAgICogLSBUb3RhbDogfjY0IGJ5dGVzXG4gICAqL1xuICBPQkpFQ1RfQkFTRV9PVkVSSEVBRDogNjQsXG5cbiAgLyoqXG4gICAqIEJhc2UgbWVtb3J5IG92ZXJoZWFkIGZvciBKYXZhU2NyaXB0IGFycmF5cyAoYnl0ZXMpXG4gICAqXG4gICAqIEluY2x1ZGVzOlxuICAgKiAtIEFycmF5IGhlYWRlcjogfjE2IGJ5dGVzXG4gICAqIC0gTGVuZ3RoIHByb3BlcnR5OiB+OCBieXRlc1xuICAgKiAtIEVsZW1lbnRzIGJhY2tpbmcgc3RvcmUgcG9pbnRlcjogfjggYnl0ZXNcbiAgICogLSBUb3RhbDogfjMyIGJ5dGVzXG4gICAqL1xuICBBUlJBWV9CQVNFX09WRVJIRUFEOiAzMixcblxuICAvKipcbiAgICogTWVtb3J5IG92ZXJoZWFkIHBlciBvYmplY3QgZmllbGQvcHJvcGVydHkgKGJ5dGVzKVxuICAgKlxuICAgKiBJbmNsdWRlczpcbiAgICogLSBQcm9wZXJ0eSBuYW1lIHN0cmluZzogfjI0IGJ5dGVzIGF2ZXJhZ2VcbiAgICogLSBQcm9wZXJ0eSB2YWx1ZSBwb2ludGVyOiB+OCBieXRlc1xuICAgKiAtIFByb3BlcnR5IGRlc2NyaXB0b3I6IH4xNiBieXRlc1xuICAgKiAtIFRvdGFsOiB+NDggYnl0ZXNcbiAgICovXG4gIEZJRUxEX09WRVJIRUFEOiA0OCxcblxuICAvKipcbiAgICogQXZlcmFnZSBlbGVtZW50IHNpemUgZXN0aW1hdGUgZm9yIGFycmF5cyAoYnl0ZXMpXG4gICAqXG4gICAqIENvbnNlcnZhdGl2ZSBlc3RpbWF0ZSBmb3IgbWl4ZWQgY29udGVudDpcbiAgICogLSBTbWFsbCBvYmplY3RzOiB+MzIgYnl0ZXNcbiAgICogLSBTdHJpbmdzOiB+NjQgYnl0ZXMgYXZlcmFnZVxuICAgKiAtIE51bWJlcnM6IH44IGJ5dGVzXG4gICAqIC0gQXZlcmFnZTogfjY0IGJ5dGVzXG4gICAqL1xuICBFTEVNRU5UX0VTVElNQVRFOiA2NCxcblxuICAvKipcbiAgICogTnVtYmVyIG9mIGVsZW1lbnRzIHRvIHNhbXBsZSBpbiBiYWxhbmNlZCBtb2RlXG4gICAqXG4gICAqIFNhbXBsaW5nIGZpcnN0IDEwIGVsZW1lbnRzIHByb3ZpZGVzOlxuICAgKiAtIH44NSUgYWNjdXJhY3kgZm9yIGhvbW9nZW5lb3VzIGFycmF5c1xuICAgKiAtIH43MCUgYWNjdXJhY3kgZm9yIG1peGVkIGNvbnRlbnRcbiAgICogLSAyLTN4IHNwZWVkdXAgb3ZlciBmdWxsIHRyYXZlcnNhbFxuICAgKi9cbiAgQkFMQU5DRURfU0FNUExFX1NJWkU6IE51bWJlci5wYXJzZUludChwcm9jZXNzLmVudi5ET0xMSE9VU0VfQ0FDSEVfU0FNUExFX1NJWkUgfHwgJzEwJyksXG5cbiAgLyoqXG4gICAqIE1pbmltdW0gc2FtcGxlIHNpemUgZm9yIGJhbGFuY2VkIG1vZGVcbiAgICovXG4gIE1JTl9TQU1QTEVfU0laRTogMSxcblxuICAvKipcbiAgICogTWF4aW11bSBzYW1wbGUgc2l6ZSBmb3IgYmFsYW5jZWQgbW9kZVxuICAgKiBQcmV2ZW50cyBleGNlc3NpdmUgc2FtcGxpbmcgb3ZlcmhlYWRcbiAgICovXG4gIE1BWF9TQU1QTEVfU0laRTogMTAwLFxufSBhcyBjb25zdDtcblxuLyoqXG4gKiBNZW1vcnkgbGltaXRzIGZvciB2YXJpb3VzIGNhY2hlIHR5cGVzXG4gKlxuICogVGhlc2UgbGltaXRzIHByZXZlbnQgdW5ib3VuZGVkIG1lbW9yeSBncm93dGggYW5kIHByb3ZpZGVcbiAqIHJlYXNvbmFibGUgZGVmYXVsdHMgZm9yIGRpZmZlcmVudCB1c2UgY2FzZXMuXG4gKi9cbmV4cG9ydCBjb25zdCBNRU1PUllfTElNSVRTID0ge1xuICAvKipcbiAgICogQ2FjaGUgbGltaXRzIGZvciBwZXJzb25hIGRhdGFcbiAgICovXG4gIFBFUlNPTkFfQ0FDSEU6IHtcbiAgICAvKipcbiAgICAgKiBNYXhpbXVtIG51bWJlciBvZiBjYWNoZWQgcGVyc29uYSBlbnRyaWVzXG4gICAgICogRW52aXJvbm1lbnQ6IERPTExIT1VTRV9NQVhfUEVSU09OQV9DQUNIRV9TSVpFXG4gICAgICovXG4gICAgTUFYX1NJWkU6IE51bWJlci5wYXJzZUludChwcm9jZXNzLmVudi5ET0xMSE9VU0VfTUFYX1BFUlNPTkFfQ0FDSEVfU0laRSB8fCAnNTAnKSxcblxuICAgIC8qKlxuICAgICAqIE1heGltdW0gbWVtb3J5IGZvciBwZXJzb25hIGNhY2hlIChNQilcbiAgICAgKiBFbnZpcm9ubWVudDogRE9MTEhPVVNFX01BWF9QRVJTT05BX0NBQ0hFX01FTU9SWVxuICAgICAqL1xuICAgIE1BWF9NRU1PUllfTUI6IE51bWJlci5wYXJzZUludChwcm9jZXNzLmVudi5ET0xMSE9VU0VfTUFYX1BFUlNPTkFfQ0FDSEVfTUVNT1JZIHx8ICcyNScpLFxuICB9LFxuXG4gIC8qKlxuICAgKiBDYWNoZSBsaW1pdHMgZm9yIG1ldHJpY3MgZGF0YVxuICAgKi9cbiAgTUVUUklDU19DQUNIRToge1xuICAgIC8qKlxuICAgICAqIE1heGltdW0gbnVtYmVyIG9mIGNhY2hlZCBtZXRyaWNzIGVudHJpZXNcbiAgICAgKiBFbnZpcm9ubWVudDogRE9MTEhPVVNFX01BWF9NRVRSSUNTX0NBQ0hFX1NJWkVcbiAgICAgKi9cbiAgICBNQVhfU0laRTogTnVtYmVyLnBhcnNlSW50KHByb2Nlc3MuZW52LkRPTExIT1VTRV9NQVhfTUVUUklDU19DQUNIRV9TSVpFIHx8ICcxMDAnKSxcblxuICAgIC8qKlxuICAgICAqIE1heGltdW0gbWVtb3J5IGZvciBtZXRyaWNzIGNhY2hlIChNQilcbiAgICAgKiBFbnZpcm9ubWVudDogRE9MTEhPVVNFX01BWF9NRVRSSUNTX0NBQ0hFX01FTU9SWVxuICAgICAqL1xuICAgIE1BWF9NRU1PUllfTUI6IE51bWJlci5wYXJzZUludChwcm9jZXNzLmVudi5ET0xMSE9VU0VfTUFYX01FVFJJQ1NfQ0FDSEVfTUVNT1JZIHx8ICcxJyksXG4gIH0sXG5cbiAgLyoqXG4gICAqIENhY2hlIGxpbWl0cyBmb3Igc2VhcmNoIHJlc3VsdHNcbiAgICovXG4gIFNFQVJDSF9DQUNIRToge1xuICAgIC8qKlxuICAgICAqIE1heGltdW0gbnVtYmVyIG9mIGNhY2hlZCBzZWFyY2ggcmVzdWx0c1xuICAgICAqIEVudmlyb25tZW50OiBET0xMSE9VU0VfTUFYX1NFQVJDSF9DQUNIRV9TSVpFXG4gICAgICovXG4gICAgTUFYX1NJWkU6IE51bWJlci5wYXJzZUludChwcm9jZXNzLmVudi5ET0xMSE9VU0VfTUFYX1NFQVJDSF9DQUNIRV9TSVpFIHx8ICcxMDAnKSxcblxuICAgIC8qKlxuICAgICAqIE1heGltdW0gbWVtb3J5IGZvciBzZWFyY2ggY2FjaGUgKE1CKVxuICAgICAqIEVudmlyb25tZW50OiBET0xMSE9VU0VfTUFYX1NFQVJDSF9DQUNIRV9NRU1PUllcbiAgICAgKi9cbiAgICBNQVhfTUVNT1JZX01COiBOdW1iZXIucGFyc2VJbnQocHJvY2Vzcy5lbnYuRE9MTEhPVVNFX01BWF9TRUFSQ0hfQ0FDSEVfTUVNT1JZIHx8ICcxMCcpLFxuICB9LFxuXG4gIC8qKlxuICAgKiBDYWNoZSBsaW1pdHMgZm9yIGluZGV4IGRhdGFcbiAgICovXG4gIElOREVYX0NBQ0hFOiB7XG4gICAgLyoqXG4gICAgICogTWF4aW11bSBudW1iZXIgb2YgY2FjaGVkIGluZGV4IGVudHJpZXNcbiAgICAgKiBFbnZpcm9ubWVudDogRE9MTEhPVVNFX01BWF9JTkRFWF9DQUNIRV9TSVpFXG4gICAgICovXG4gICAgTUFYX1NJWkU6IE51bWJlci5wYXJzZUludChwcm9jZXNzLmVudi5ET0xMSE9VU0VfTUFYX0lOREVYX0NBQ0hFX1NJWkUgfHwgJzUwJyksXG5cbiAgICAvKipcbiAgICAgKiBNYXhpbXVtIG1lbW9yeSBmb3IgaW5kZXggY2FjaGUgKE1CKVxuICAgICAqIEVudmlyb25tZW50OiBET0xMSE9VU0VfTUFYX0lOREVYX0NBQ0hFX01FTU9SWVxuICAgICAqL1xuICAgIE1BWF9NRU1PUllfTUI6IE51bWJlci5wYXJzZUludChwcm9jZXNzLmVudi5ET0xMSE9VU0VfTUFYX0lOREVYX0NBQ0hFX01FTU9SWSB8fCAnMjUnKSxcbiAgfSxcblxuICAvKipcbiAgICogQ2FjaGUgbGltaXRzIGZvciBBUEkgcmVzcG9uc2VzXG4gICAqL1xuICBBUElfQ0FDSEU6IHtcbiAgICAvKipcbiAgICAgKiBNYXhpbXVtIG51bWJlciBvZiBjYWNoZWQgQVBJIHJlc3BvbnNlc1xuICAgICAqIEVudmlyb25tZW50OiBET0xMSE9VU0VfTUFYX0FQSV9DQUNIRV9TSVpFXG4gICAgICovXG4gICAgTUFYX1NJWkU6IE51bWJlci5wYXJzZUludChwcm9jZXNzLmVudi5ET0xMSE9VU0VfTUFYX0FQSV9DQUNIRV9TSVpFIHx8ICcyMDAnKSxcblxuICAgIC8qKlxuICAgICAqIE1heGltdW0gbWVtb3J5IGZvciBBUEkgY2FjaGUgKE1CKVxuICAgICAqIEVudmlyb25tZW50OiBET0xMSE9VU0VfTUFYX0FQSV9DQUNIRV9NRU1PUllcbiAgICAgKi9cbiAgICBNQVhfTUVNT1JZX01COiBOdW1iZXIucGFyc2VJbnQocHJvY2Vzcy5lbnYuRE9MTEhPVVNFX01BWF9BUElfQ0FDSEVfTUVNT1JZIHx8ICc1JyksXG4gIH0sXG59IGFzIGNvbnN0O1xuXG4vKipcbiAqIFN0b3JhZ2UgbGF5ZXIgY29uZmlndXJhdGlvblxuICpcbiAqIENlbnRyYWxpemVzIFRUTCwgY29vbGRvd24sIGFuZCBkZWJvdW5jZSB2YWx1ZXMgdXNlZCBieSBFbGVtZW50U3RvcmFnZUxheWVyLFxuICogTWVtb3J5U3RvcmFnZUxheWVyLCBhbmQgdG9vbCBkaXNjb3ZlcnkgY2FjaGluZy4gRWFjaCBjb25zdGFudCBzdXBwb3J0cyBhXG4gKiBET0xMSE9VU0VfKiBlbnYgdmFyIHdpdGggYSBsZWdhY3kgZmFsbGJhY2sgZm9yIGJhY2t3YXJkIGNvbXBhdGliaWxpdHkuXG4gKi9cbmV4cG9ydCBjb25zdCBTVE9SQUdFX0xBWUVSX0NPTkZJRyA9IHtcbiAgLyoqXG4gICAqIE1pbmltdW0gaW50ZXJ2YWwgYmV0d2VlbiBmdWxsIGRpcmVjdG9yeSBzY2FucyAobWlsbGlzZWNvbmRzKVxuICAgKiBQcmV2ZW50cyBleGNlc3NpdmUgSS9PIG9uIHJhcGlkIGxpc3QoKSBjYWxscy5cbiAgICpcbiAgICogRW52aXJvbm1lbnQ6IERPTExIT1VTRV9TQ0FOX0NPT0xET1dOX01TIChsZWdhY3k6IEVMRU1FTlRfU0NBTl9DT09MRE9XTl9NUylcbiAgICovXG4gIFNDQU5fQ09PTERPV05fTVM6IE51bWJlci5wYXJzZUludChcbiAgICBwcm9jZXNzLmVudi5ET0xMSE9VU0VfU0NBTl9DT09MRE9XTl9NUyA/PyBwcm9jZXNzLmVudi5FTEVNRU5UX1NDQU5fQ09PTERPV05fTVMgPz8gJzEwMDAnXG4gICksXG4gIE1JTl9TQ0FOX0NPT0xET1dOX01TOiAxMDAsXG4gIE1BWF9TQ0FOX0NPT0xET1dOX01TOiA2MDAwMCxcblxuICAvKipcbiAgICogRGVib3VuY2UgaW50ZXJ2YWwgZm9yIHBlcnNpc3RpbmcgX2luZGV4Lmpzb24gaW4gTWVtb3J5U3RvcmFnZUxheWVyIChtaWxsaXNlY29uZHMpXG4gICAqXG4gICAqIEVudmlyb25tZW50OiBET0xMSE9VU0VfSU5ERVhfREVCT1VOQ0VfTVMgKGxlZ2FjeTogTUVNT1JZX0lOREVYX0RFQk9VTkNFX01TKVxuICAgKi9cbiAgSU5ERVhfREVCT1VOQ0VfTVM6IE51bWJlci5wYXJzZUludChcbiAgICBwcm9jZXNzLmVudi5ET0xMSE9VU0VfSU5ERVhfREVCT1VOQ0VfTVMgPz8gcHJvY2Vzcy5lbnYuTUVNT1JZX0lOREVYX0RFQk9VTkNFX01TID8/ICcyMDAwJ1xuICApLFxuICBNSU5fSU5ERVhfREVCT1VOQ0VfTVM6IDEwMCxcbiAgTUFYX0lOREVYX0RFQk9VTkNFX01TOiAzMDAwMCxcblxuICAvKipcbiAgICogVFRMIGZvciBlbGVtZW50IExSVSBjYWNoZXMgaW4gQmFzZUVsZW1lbnRNYW5hZ2VyIChtaWxsaXNlY29uZHMpXG4gICAqIERlZmF1bHQ6IDEgaG91ci4gVGhpcyBpcyBhIHNhZmV0eSBuZXQgb25seSDigJQgdGhlIHN0b3JhZ2UgbGF5ZXIncyBtdGltZS1iYXNlZFxuICAgKiBzY2FubmluZyBoYW5kbGVzIHJlYWwgZnJlc2huZXNzIGRldGVjdGlvbi4gU2V0IHRvIDAgdG8gZGlzYWJsZSBUVEwgZW50aXJlbHkuXG4gICAqXG4gICAqIEVudmlyb25tZW50OiBET0xMSE9VU0VfRUxFTUVOVF9DQUNIRV9UVExfTVMgKGxlZ2FjeTogRUxFTUVOVF9DQUNIRV9UVExfTVMpXG4gICAqL1xuICBFTEVNRU5UX0NBQ0hFX1RUTF9NUzogTnVtYmVyLnBhcnNlSW50KFxuICAgIHByb2Nlc3MuZW52LkRPTExIT1VTRV9FTEVNRU5UX0NBQ0hFX1RUTF9NUyA/PyBwcm9jZXNzLmVudi5FTEVNRU5UX0NBQ0hFX1RUTF9NUyA/PyAnMzYwMDAwMCdcbiAgKSxcbiAgTUlOX0VMRU1FTlRfQ0FDSEVfVFRMX01TOiAwLFxuICBNQVhfRUxFTUVOVF9DQUNIRV9UVExfTVM6IDM2MDAwMDAsXG5cbiAgLyoqXG4gICAqIFRUTCBmb3IgZmlsZS1wYXRoLXRvLUlEIHJldmVyc2UgaW5kZXggY2FjaGVzIChtaWxsaXNlY29uZHMpXG4gICAqIERlZmF1bHQ6IDEgaG91ci4gU2V0IHRvIDAgdG8gZGlzYWJsZSBUVEwgKHJlbHkgb24gc3RvcmFnZSBsYXllciBtdGltZSBzY2FubmluZykuXG4gICAqXG4gICAqIEVudmlyb25tZW50Oi