@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.
297 lines • 50 kB
JavaScript
/**
* Centralized Environment Configuration
*
* This module provides type-safe access to environment variables with validation.
* All environment variables should be accessed through this module rather than
* directly via process.env to ensure type safety and validation.
*
* Usage:
* ```typescript
* import { env } from './config/env';
* const token = env.GITHUB_TOKEN; // Type: string
* ```
*/
import { z } from 'zod';
import dotenv from 'dotenv';
import { logger } from '../utils/logger.js';
// Load .env files with priority: .env.local (personal) > .env (shared defaults)
// Both files are optional - no error if either doesn't exist
//
// MCP Protocol Compliance: Suppress dotenv's stdout output
// The MCP protocol requires that ONLY JSON-RPC messages go to stdout.
// dotenv may output version info to stdout, which breaks Claude Desktop connection.
// Solution: Temporarily redirect stdout to stderr during dotenv initialization.
// In --web mode, suppress both stdout AND stderr — the user only needs the
// console URL banner, not dotenv's injection summary. Logs go to the web viewer.
const isWebSilent = process.argv.includes('--web')
&& !process.env.DOLLHOUSE_DEBUG && !process.env.ENABLE_DEBUG;
const originalStdoutWrite = process.stdout.write.bind(process.stdout);
const originalStderrWrite = process.stderr.write.bind(process.stderr);
process.stdout.write = (isWebSilent ? (() => true) : process.stderr.write.bind(process.stderr));
if (isWebSilent)
process.stderr.write = (() => true);
dotenv.config({ path: ['.env.local', '.env'] });
process.stdout.write = originalStdoutWrite;
if (isWebSilent)
process.stderr.write = originalStderrWrite;
/**
* Environment variable schema with validation
*/
const envSchema = z.object({
// ============================================================================
// Environment
// ============================================================================
NODE_ENV: z.enum(['development', 'test', 'production']).default('development'),
// ============================================================================
// Production GitHub Credentials
// ============================================================================
// Used by production code (src/) for real GitHub operations
// Optional: Features requiring GitHub will fail gracefully if not set
GITHUB_TOKEN: z.string().optional(),
GITHUB_USERNAME: z.string().optional(),
GITHUB_REPOSITORY: z.string().optional(),
// ============================================================================
// Test GitHub Credentials (SEPARATE account!)
// ============================================================================
// Used by test code (tests/) - tests will skip if not provided
// IMPORTANT: Use a different GitHub account for testing!
GITHUB_TEST_TOKEN: z.string().optional(),
GITHUB_TEST_USERNAME: z.string().optional(),
GITHUB_TEST_REPOSITORY: z.string().optional(),
// ============================================================================
// Server Configuration
// ============================================================================
PORT: z.coerce.number().default(3000),
LOG_LEVEL: z.enum(['error', 'warn', 'info', 'debug']).default('info'),
// ============================================================================
// Test Configuration
// ============================================================================
TEST_BASE_DIR: z.string().optional(),
TEST_PERSONAS_DIR: z.string().optional(),
TEST_CACHE_DIR: z.string().optional(),
TEST_CONFIG_DIR: z.string().optional(),
// ============================================================================
// Feature Flags
// ============================================================================
DOLLHOUSE_AUTO_SUBMIT_TO_COLLECTION: z.coerce.boolean().default(false),
ENABLE_DEBUG: z.coerce.boolean().default(false),
TEST_VERBOSE_LOGGING: z.coerce.boolean().default(false),
// ============================================================================
// MCP Interface Configuration (Issue #237)
// ============================================================================
/**
* MCP interface mode - controls which tool interface is exposed to LLMs:
* - 'discrete': ~40 individual tools (list_elements, create_element, etc.) - ~3,000 tokens
* - 'mcpaql': Consolidated MCP-AQL interface - uses MCP_AQL_ENDPOINT_MODE for style
*
* Default: 'mcpaql' - recommended for token efficiency and cleaner tool discovery
*/
MCP_INTERFACE_MODE: z.enum(['discrete', 'mcpaql']).default('mcpaql'),
/**
* MCP-AQL endpoint mode (only applies when MCP_INTERFACE_MODE='mcpaql'):
* - 'crude': 5 CRUDE tools (Create, Read, Update, Delete, Execute) - ~4,300 tokens
* - 'single': 1 tool (mcp_aql) - ~350 tokens, ideal for multi-server deployments
*/
MCP_AQL_ENDPOINT_MODE: z.enum(['crude', 'single']).default('crude'),
// Backward compatibility alias for MCP_AQL_MODE (deprecated, use MCP_AQL_ENDPOINT_MODE)
MCP_AQL_MODE: z.enum(['crude', 'single']).optional(),
// ============================================================================
// Unified Logging Configuration (docs/LOGGING-DESIGN.md)
// ============================================================================
DOLLHOUSE_LOG_DIR: z.string().default('~/.dollhouse/logs/'),
DOLLHOUSE_LOG_FORMAT: z.enum(['text', 'jsonl']).default('text'),
DOLLHOUSE_LOG_RETENTION_DAYS: z.coerce.number().default(30),
DOLLHOUSE_LOG_SECURITY_RETENTION_DAYS: z.coerce.number().default(7),
DOLLHOUSE_LOG_FLUSH_INTERVAL_MS: z.coerce.number().default(5000),
// Buffer raised to 2000 to support the web console log viewer — the higher capacity
// reduces flush frequency and keeps more entries available for SSE backfill on connect.
DOLLHOUSE_LOG_BUFFER_SIZE: z.coerce.number().default(2000),
DOLLHOUSE_LOG_MEMORY_CAPACITY: z.coerce.number().default(5000),
DOLLHOUSE_LOG_MEMORY_APP_CAPACITY: z.coerce.number().default(10000),
DOLLHOUSE_LOG_MEMORY_SECURITY_CAPACITY: z.coerce.number().default(5000),
DOLLHOUSE_LOG_MEMORY_PERF_CAPACITY: z.coerce.number().default(2000),
DOLLHOUSE_LOG_MEMORY_TELEMETRY_CAPACITY: z.coerce.number().default(1000),
DOLLHOUSE_LOG_MAX_ENTRY_SIZE: z.coerce.number().default(16384),
DOLLHOUSE_LOG_IMMEDIATE_FLUSH_RATE: z.coerce.number().default(50),
DOLLHOUSE_LOG_FILE_MAX_SIZE: z.coerce.number().default(104857600),
DOLLHOUSE_LOG_MAX_DIR_SIZE_BYTES: z.coerce.number().default(0),
DOLLHOUSE_LOG_MAX_FILES_PER_CATEGORY: z.coerce.number().default(100),
// ============================================================================
// Permission Server Configuration
// ============================================================================
/**
* Enable the HTTP permission evaluation server for PreToolUse hooks.
* When true, starts an HTTP endpoint on a dynamic port after deferred
* setup completes. Writes port to ~/.dollhouse/run/permission-server.port
* for hook script discovery. Required for autonomous agent permission
* management via Claude Code hooks.
*/
DOLLHOUSE_PERMISSION_SERVER: z.coerce.boolean().default(true),
// Web Console Configuration
// ============================================================================
/** Enable the unified web console (logs + metrics tabs) */
DOLLHOUSE_WEB_CONSOLE: z.coerce.boolean().default(true),
/**
* Port the web console leader binds to (#1794, #1798).
*
* Default: 41715 — "AILIS" on a phone keypad, after the AI Layer
* Interface Specification that DollhouseMCP implements. Also "Alice"
* in Gaelic.
*
* Port selection criteria (verified 2026-04-06):
* - Not registered with IANA (no entry in the service name registry)
* - Not in nmap services database (never observed in the wild)
* - No known application, security tool, or malware associations
* - Below the macOS ephemeral range (49152-65535), so `bind()`
* does not race with kernel-allocated source ports
* - In the IANA user port range (1024-49151)
* - Not adjacent to the pre-authentication default (3939)
*
* Previous default was 5907 ("LOGS" upside down on a calculator),
* which conflicted with Stellar Cyber's HTTP GKE log parser.
*
* Override via env var if 41715 collides with something in your
* environment — every runtime reference reads from this single value.
*/
DOLLHOUSE_WEB_CONSOLE_PORT: z.coerce.number().int().min(1024).max(65535).default(41715),
/**
* Issue #1780: Enforce Bearer token authentication on the web console API.
* When true, all protected endpoints require a valid token from the
* console token file. When false (the pre-Phase-2 default), the token
* file is still generated but the middleware does not enforce — this
* lets the infrastructure land without breaking existing consumers.
* Will flip to default `true` in a follow-up PR once all consumers
* (browser, followers, bridge) have been updated to attach tokens.
*/
DOLLHOUSE_WEB_AUTH_ENABLED: z.coerce.boolean().default(false),
/**
* Issue #1780: Optional override for the console token file location.
* When unset, `ConsoleTokenStore` falls back to its built-in default
* under `~/.dollhouse/run/`. Mainly useful for tests and for enterprise
* deployments that mount a shared token file from a secrets volume.
*/
DOLLHOUSE_CONSOLE_TOKEN_FILE: z.string().optional(),
/**
* Optional override for the console leader lock file location (#1794).
* When unset, `LeaderElection` falls back to its built-in default under
* `~/.dollhouse/run/`. Primarily useful for tests that need isolation
* between runs and for deployments that split runtime state across
* multiple installations on the same machine.
*/
DOLLHOUSE_CONSOLE_LEADER_LOCK_FILE: z.string().optional(),
// Leader/Follower Recovery (#1850)
// ============================================================================
/**
* Issue #1850: Retry delays (in ms) when the leader fails to bind the console
* port due to EADDRINUSE. Each value is a successive backoff delay.
* Default: 1s, 2s, 4s (7s total). Increase for slow or remote environments.
*/
DOLLHOUSE_CONSOLE_BIND_RETRY_DELAYS: z.string()
.optional()
.transform(v => v ? v.split(',').map(Number).filter(n => !Number.isNaN(n) && n > 0) : undefined),
/**
* Issue #1850: Number of consecutive forwarding failures before a follower
* declares the leader dead and attempts self-promotion. Higher values reduce
* false positives in high-latency environments but delay recovery.
* Default: 10.
*/
DOLLHOUSE_CONSOLE_MAX_FORWARD_FAILURES: z.coerce.number().int().min(1).max(100).default(10),
/**
* Issue #1780: Phase 2 — require a confirmation code (OS dialog or TOTP)
* for privileged actions like token rotation. Default is true for safety;
* set to false for headless CI and scripted deployments that need to rotate
* without human interaction.
*/
DOLLHOUSE_CONSOLE_ROTATION_REQUIRE_CONFIRMATION: z.coerce.boolean().default(true),
// ============================================================================
// Security Configuration
// ============================================================================
/**
* Issue #452: Gatekeeper policy enforcement.
* When true (default), all MCP-AQL operations go through the 4-layer Gatekeeper
* enforce() pipeline. When false, falls back to route validation only.
* This is a user/operator setting — the LLM cannot bypass it.
*/
DOLLHOUSE_GATEKEEPER_ENABLED: z.coerce.boolean().default(true),
/**
* Issue #679: Element policy layer kill switch.
* When true (default), active element gatekeeper policies (allow/confirm/deny/scopeRestrictions)
* can override default operation permission levels. When false, Layer 2 of Gatekeeper.enforce()
* is bypassed entirely — only route validation and default permission levels apply.
* Use for emergency lockdown, hardened deployments, or policy debugging.
* This is an operator/infrastructure setting — the LLM cannot bypass it.
*/
DOLLHOUSE_GATEKEEPER_ELEMENT_POLICY_OVERRIDES: z.coerce.boolean().default(true),
/**
* Issue #799: Policy export opt-in flag.
* When true (default), PolicyExportService writes the security policy blueprint to
* ~/.dollhouse/bridge/imports/policies/ on activation changes. The DollhouseBridge
* permission-prompt server watches this file to evaluate permissions locally.
* Set to false to disable policy file export entirely.
*/
DOLLHOUSE_POLICY_EXPORT_ENABLED: z.coerce.boolean().default(true),
// ============================================================================
// Storage Layer Configuration
// ============================================================================
DOLLHOUSE_SCAN_COOLDOWN_MS: z.coerce.number().default(1000),
DOLLHOUSE_INDEX_DEBOUNCE_MS: z.coerce.number().default(2000),
DOLLHOUSE_ELEMENT_CACHE_TTL_MS: z.coerce.number().default(3600000),
DOLLHOUSE_PATH_CACHE_TTL_MS: z.coerce.number().default(3600000),
DOLLHOUSE_TOOL_CACHE_TTL_MS: z.coerce.number().default(60000),
DOLLHOUSE_GLOBAL_CACHE_MEMORY_MB: z.coerce.number().default(150),
// ============================================================================
// Permission Prompt Configuration (Issue #625)
// ============================================================================
/** Maximum CLI approval records before LRU eviction (default: 50) */
DOLLHOUSE_CLI_APPROVAL_MAX: z.coerce.number().default(50),
/** Default TTL for CLI approval records in ms (default: 300000 = 5 min) */
DOLLHOUSE_CLI_APPROVAL_TTL_MS: z.coerce.number().default(300_000),
/** Permission prompt rate limit: max requests per window (default: 100) */
DOLLHOUSE_PERMISSION_PROMPT_RATE_LIMIT: z.coerce.number().default(100),
/** CLI approval creation rate limit: max requests per window (default: 20) */
DOLLHOUSE_CLI_APPROVAL_RATE_LIMIT: z.coerce.number().default(20),
/** Rate limit window in ms for permission prompt and CLI approvals (default: 60000 = 60s) */
DOLLHOUSE_PERMISSION_RATE_WINDOW_MS: z.coerce.number().default(60_000),
// ============================================================================
// Metrics Collection Configuration
// ============================================================================
DOLLHOUSE_METRICS_ENABLED: z.coerce.boolean().default(true),
DOLLHOUSE_METRICS_COLLECTION_INTERVAL_MS: z.coerce.number().min(1000).max(300000).default(15000),
DOLLHOUSE_METRICS_MAX_SNAPSHOT_SIZE: z.coerce.number().default(102400),
DOLLHOUSE_METRICS_COLLECTOR_FAILURE_THRESHOLD: z.coerce.number().min(1).max(100).default(10),
DOLLHOUSE_METRICS_COLLECTION_DURATION_WARN_MS: z.coerce.number().min(100).max(60000).default(5000),
DOLLHOUSE_METRICS_MEMORY_SNAPSHOT_CAPACITY: z.coerce.number().min(10).max(10000).default(240),
// Pattern encryption settings for Memory Security (Issue #1321)
DOLLHOUSE_DISABLE_ENCRYPTION: z.coerce.boolean().default(false),
DOLLHOUSE_ENCRYPTION_SECRET: z.string().optional(),
DOLLHOUSE_ENCRYPTION_SALT: z.string().optional(),
// Token encryption secret (SEC-01, #1735)
// When set, replaces the predictable machine-derived passphrase for token encryption.
// Strongly recommended for any shared or multi-user environment.
// Minimum 32 characters enforced to prevent weak passphrases.
DOLLHOUSE_TOKEN_SECRET: z.string().min(32).optional(),
});
/**
* Validated environment variables
* Type is automatically inferred from the schema
*/
export const env = envSchema.parse(process.env);
/**
* Convenience helpers for environment detection
*/
export const isTest = env.NODE_ENV === 'test';
export const isDevelopment = env.NODE_ENV === 'development';
export const isProduction = env.NODE_ENV === 'production';
/**
* Log environment configuration (without secrets)
*/
if (isDevelopment || isTest) {
logger.debug('Environment configuration loaded:', {
NODE_ENV: env.NODE_ENV,
PORT: env.PORT,
LOG_LEVEL: env.LOG_LEVEL,
HAS_GITHUB_TOKEN: !!env.GITHUB_TOKEN,
HAS_GITHUB_TEST_TOKEN: !!env.GITHUB_TEST_TOKEN,
});
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW52LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvbmZpZy9lbnYudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7OztHQVlHO0FBRUgsT0FBTyxFQUFFLENBQUMsRUFBRSxNQUFNLEtBQUssQ0FBQztBQUN4QixPQUFPLE1BQU0sTUFBTSxRQUFRLENBQUM7QUFDNUIsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBRTVDLGdGQUFnRjtBQUNoRiw2REFBNkQ7QUFDN0QsRUFBRTtBQUNGLDJEQUEyRDtBQUMzRCxzRUFBc0U7QUFDdEUsb0ZBQW9GO0FBQ3BGLGdGQUFnRjtBQUNoRiwyRUFBMkU7QUFDM0UsaUZBQWlGO0FBQ2pGLE1BQU0sV0FBVyxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQztPQUM3QyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsZUFBZSxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxZQUFZLENBQUM7QUFDL0QsTUFBTSxtQkFBbUIsR0FBRyxPQUFPLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFDO0FBQ3RFLE1BQU0sbUJBQW1CLEdBQUcsT0FBTyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQztBQUN0RSxPQUFPLENBQUMsTUFBTSxDQUFDLEtBQUssR0FBRyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBUSxDQUFDO0FBQ3ZHLElBQUksV0FBVztJQUFFLE9BQU8sQ0FBQyxNQUFNLENBQUMsS0FBSyxHQUFHLENBQUMs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LCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIENlbnRyYWxpemVkIEVudmlyb25tZW50IENvbmZpZ3VyYXRpb25cbiAqXG4gKiBUaGlzIG1vZHVsZSBwcm92aWRlcyB0eXBlLXNhZmUgYWNjZXNzIHRvIGVudmlyb25tZW50IHZhcmlhYmxlcyB3aXRoIHZhbGlkYXRpb24uXG4gKiBBbGwgZW52aXJvbm1lbnQgdmFyaWFibGVzIHNob3VsZCBiZSBhY2Nlc3NlZCB0aHJvdWdoIHRoaXMgbW9kdWxlIHJhdGhlciB0aGFuXG4gKiBkaXJlY3RseSB2aWEgcHJvY2Vzcy5lbnYgdG8gZW5zdXJlIHR5cGUgc2FmZXR5IGFuZCB2YWxpZGF0aW9uLlxuICpcbiAqIFVzYWdlOlxuICogYGBgdHlwZXNjcmlwdFxuICogaW1wb3J0IHsgZW52IH0gZnJvbSAnLi9jb25maWcvZW52JztcbiAqIGNvbnN0IHRva2VuID0gZW52LkdJVEhVQl9UT0tFTjsgIC8vIFR5cGU6IHN0cmluZ1xuICogYGBgXG4gKi9cblxuaW1wb3J0IHsgeiB9IGZyb20gJ3pvZCc7XG5pbXBvcnQgZG90ZW52IGZyb20gJ2RvdGVudic7XG5pbXBvcnQgeyBsb2dnZXIgfSBmcm9tICcuLi91dGlscy9sb2dnZXIuanMnO1xuXG4vLyBMb2FkIC5lbnYgZmlsZXMgd2l0aCBwcmlvcml0eTogLmVudi5sb2NhbCAocGVyc29uYWwpID4gLmVudiAoc2hhcmVkIGRlZmF1bHRzKVxuLy8gQm90aCBmaWxlcyBhcmUgb3B0aW9uYWwgLSBubyBlcnJvciBpZiBlaXRoZXIgZG9lc24ndCBleGlzdFxuLy9cbi8vIE1DUCBQcm90b2NvbCBDb21wbGlhbmNlOiBTdXBwcmVzcyBkb3RlbnYncyBzdGRvdXQgb3V0cHV0XG4vLyBUaGUgTUNQIHByb3RvY29sIHJlcXVpcmVzIHRoYXQgT05MWSBKU09OLVJQQyBtZXNzYWdlcyBnbyB0byBzdGRvdXQuXG4vLyBkb3RlbnYgbWF5IG91dHB1dCB2ZXJzaW9uIGluZm8gdG8gc3Rkb3V0LCB3aGljaCBicmVha3MgQ2xhdWRlIERlc2t0b3AgY29ubmVjdGlvbi5cbi8vIFNvbHV0aW9uOiBUZW1wb3JhcmlseSByZWRpcmVjdCBzdGRvdXQgdG8gc3RkZXJyIGR1cmluZyBkb3RlbnYgaW5pdGlhbGl6YXRpb24uXG4vLyBJbiAtLXdlYiBtb2RlLCBzdXBwcmVzcyBib3RoIHN0ZG91dCBBTkQgc3RkZXJyIOKAlCB0aGUgdXNlciBvbmx5IG5lZWRzIHRoZVxuLy8gY29uc29sZSBVUkwgYmFubmVyLCBub3QgZG90ZW52J3MgaW5qZWN0aW9uIHN1bW1hcnkuIExvZ3MgZ28gdG8gdGhlIHdlYiB2aWV3ZXIuXG5jb25zdCBpc1dlYlNpbGVudCA9IHByb2Nlc3MuYXJndi5pbmNsdWRlcygnLS13ZWInKVxuICAmJiAhcHJvY2Vzcy5lbnYuRE9MTEhPVVNFX0RFQlVHICYmICFwcm9jZXNzLmVudi5FTkFCTEVfREVCVUc7XG5jb25zdCBvcmlnaW5hbFN0ZG91dFdyaXRlID0gcHJvY2Vzcy5zdGRvdXQud3JpdGUuYmluZChwcm9jZXNzLnN0ZG91dCk7XG5jb25zdCBvcmlnaW5hbFN0ZGVycldyaXRlID0gcHJvY2Vzcy5zdGRlcnIud3JpdGUuYmluZChwcm9jZXNzLnN0ZGVycik7XG5wcm9jZXNzLnN0ZG91dC53cml0ZSA9IChpc1dlYlNpbGVudCA/ICgoKSA9PiB0cnVlKSA6IHByb2Nlc3Muc3RkZXJyLndyaXRlLmJpbmQocHJvY2Vzcy5zdGRlcnIpKSBhcyBhbnk7XG5pZiAoaXNXZWJTaWxlbnQpIHByb2Nlc3Muc3RkZXJyLndyaXRlID0gKCgpID0+IHRydWUpIGFzIGFueTtcbmRvdGVudi5jb25maWcoeyBwYXRoOiBbJy5lbnYubG9jYWwnLCAnLmVudiddIH0pO1xucHJvY2Vzcy5zdGRvdXQud3JpdGUgPSBvcmlnaW5hbFN0ZG91dFdyaXRlO1xuaWYgKGlzV2ViU2lsZW50KSBwcm9jZXNzLnN0ZGVyci53cml0ZSA9IG9yaWdpbmFsU3RkZXJyV3JpdGU7XG5cbi8qKlxuICogRW52aXJvbm1lbnQgdmFyaWFibGUgc2NoZW1hIHdpdGggdmFsaWRhdGlvblxuICovXG5jb25zdCBlbnZTY2hlbWEgPSB6Lm9iamVjdCh7XG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAgLy8gRW52aXJvbm1lbnRcbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICBOT0RFX0VOVjogei5lbnVtKFsnZGV2ZWxvcG1lbnQnLCAndGVzdCcsICdwcm9kdWN0aW9uJ10pLmRlZmF1bHQoJ2RldmVsb3BtZW50JyksXG5cbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICAvLyBQcm9kdWN0aW9uIEdpdEh1YiBDcmVkZW50aWFsc1xuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gIC8vIFVzZWQgYnkgcHJvZHVjdGlvbiBjb2RlIChzcmMvKSBmb3IgcmVhbCBHaXRIdWIgb3BlcmF0aW9uc1xuICAvLyBPcHRpb25hbDogRmVhdHVyZXMgcmVxdWlyaW5nIEdpdEh1YiB3aWxsIGZhaWwgZ3JhY2VmdWxseSBpZiBub3Qgc2V0XG4gIEdJVEhVQl9UT0tFTjogei5zdHJpbmcoKS5vcHRpb25hbCgpLFxuICBHSVRIVUJfVVNFUk5BTUU6IHouc3RyaW5nKCkub3B0aW9uYWwoKSxcbiAgR0lUSFVCX1JFUE9TSVRPUlk6IHouc3RyaW5nKCkub3B0aW9uYWwoKSxcblxuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gIC8vIFRlc3QgR2l0SHViIENyZWRlbnRpYWxzIChTRVBBUkFURSBhY2NvdW50ISlcbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICAvLyBVc2VkIGJ5IHRlc3QgY29kZSAodGVzdHMvKSAtIHRlc3RzIHdpbGwgc2tpcCBpZiBub3QgcHJvdmlkZWRcbiAgLy8gSU1QT1JUQU5UOiBVc2UgYSBkaWZmZXJlbnQgR2l0SHViIGFjY291bnQgZm9yIHRlc3RpbmchXG4gIEdJVEhVQl9URVNUX1RPS0VOOiB6LnN0cmluZygpLm9wdGlvbmFsKCksXG4gIEdJVEhVQl9URVNUX1VTRVJOQU1FOiB6LnN0cmluZygpLm9wdGlvbmFsKCksXG4gIEdJVEhVQl9URVNUX1JFUE9TSVRPUlk6IHouc3RyaW5nKCkub3B0aW9uYWwoKSxcblxuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gIC8vIFNlcnZlciBDb25maWd1cmF0aW9uXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAgUE9SVDogei5jb2VyY2UubnVtYmVyKCkuZGVmYXVsdCgzMDAwKSxcbiAgTE9HX0xFVkVMOiB6LmVudW0oWydlcnJvcicsICd3YXJuJywgJ2luZm8nLCAnZGVidWcnXSkuZGVmYXVsdCgnaW5mbycpLFxuXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAgLy8gVGVzdCBDb25maWd1cmF0aW9uXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAgVEVTVF9CQVNFX0RJUjogei5zdHJpbmcoKS5vcHRpb25hbCgpLFxuICBURVNUX1BFUlNPTkFTX0RJUjogei5zdHJpbmcoKS5vcHRpb25hbCgpLFxuICBURVNUX0NBQ0hFX0RJUjogei5zdHJpbmcoKS5vcHRpb25hbCgpLFxuICBURVNUX0NPTkZJR19ESVI6IHouc3RyaW5nKCkub3B0aW9uYWwoKSxcblxuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gIC8vIEZlYXR1cmUgRmxhZ3NcbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICBET0xMSE9VU0VfQVVUT19TVUJNSVRfVE9fQ09MTEVDVElPTjogei5jb2VyY2UuYm9vbGVhbigpLmRlZmF1bHQoZmFsc2UpLFxuICBFTkFCTEVfREVCVUc6IHouY29lcmNlLmJvb2xlYW4oKS5kZWZhdWx0KGZhbHNlKSxcbiAgVEVTVF9WRVJCT1NFX0xPR0dJTkc6IHouY29lcmNlLmJvb2xlYW4oKS5kZWZhdWx0KGZhbHNlKSxcblxuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gIC8vIE1DUCBJbnRlcmZhY2UgQ29uZmlndXJhdGlvbiAoSXNzdWUgIzIzNylcbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICAvKipcbiAgICogTUNQIGludGVyZmFjZSBtb2RlIC0gY29udHJvbHMgd2hpY2ggdG9vbCBpbnRlcmZhY2UgaXMgZXhwb3NlZCB0byBMTE1zOlxuICAgKiAtICdkaXNjcmV0ZSc6IH40MCBpbmRpdmlkdWFsIHRvb2xzIChsaXN0X2VsZW1lbnRzLCBjcmVhdGVfZWxlbWVudCwgZXRjLikgLSB+MywwMDAgdG9rZW5zXG4gICAqIC0gJ21jcGFxbCc6IENvbnNvbGlkYXRlZCBNQ1AtQVFMIGludGVyZmFjZSAtIHVzZXMgTUNQX0FRTF9FTkRQT0lOVF9NT0RFIGZvciBzdHlsZVxuICAgKlxuICAgKiBEZWZhdWx0OiAnbWNwYXFsJyAtIHJlY29tbWVuZGVkIGZvciB0b2tlbiBlZmZpY2llbmN5IGFuZCBjbGVhbmVyIHRvb2wgZGlzY292ZXJ5XG4gICAqL1xuICBNQ1BfSU5URVJGQUNFX01PREU6IHouZW51bShbJ2Rpc2NyZXRlJywgJ21jcGFxbCddKS5kZWZhdWx0KCdtY3BhcWwnKSxcblxuICAvKipcbiAgICogTUNQLUFRTCBlbmRwb2ludCBtb2RlIChvbmx5IGFwcGxpZXMgd2hlbiBNQ1BfSU5URVJGQUNFX01PREU9J21jcGFxbCcpOlxuICAgKiAtICdjcnVkZSc6IDUgQ1JVREUgdG9vbHMgKENyZWF0ZSwgUmVhZCwgVXBkYXRlLCBEZWxldGUsIEV4ZWN1dGUpIC0gfjQsMzAwIHRva2Vuc1xuICAgKiAtICdzaW5nbGUnOiAxIHRvb2wgKG1jcF9hcWwpIC0gfjM1MCB0b2tlbnMsIGlkZWFsIGZvciBtdWx0aS1zZXJ2ZXIgZGVwbG95bWVudHNcbiAgICovXG4gIE1DUF9BUUxfRU5EUE9JTlRfTU9ERTogei5lbnVtKFsnY3J1ZGUnLCAnc2luZ2xlJ10pLmRlZmF1bHQoJ2NydWRlJyksXG5cbiAgLy8gQmFja3dhcmQgY29tcGF0aWJpbGl0eSBhbGlhcyBmb3IgTUNQX0FRTF9NT0RFIChkZXByZWNhdGVkLCB1c2UgTUNQX0FRTF9FTkRQT0lOVF9NT0RFKVxuICBNQ1BfQVFMX01PREU6IHouZW51bShbJ2NydWRlJywgJ3NpbmdsZSddKS5vcHRpb25hbCgpLFxuXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAgLy8gVW5pZmllZCBMb2dnaW5nIENvbmZpZ3VyYXRpb24gKGRvY3MvTE9HR0lORy1ERVNJR04ubWQpXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAgRE9MTEhPVVNFX0xPR19ESVI6IHouc3RyaW5nKCkuZGVmYXVsdCgnfi8uZG9sbGhvdXNlL2xvZ3MvJyksXG4gIERPTExIT1VTRV9MT0dfRk9STUFUOiB6LmVudW0oWyd0ZXh0JywgJ2pzb25sJ10pLmRlZmF1bHQoJ3RleHQnKSxcbiAgRE9MTEhPVVNFX0xPR19SRVRFTlRJT05fREFZUzogei5jb2VyY2UubnVtYmVyKCkuZGVmYXVsdCgzMCksXG4gIERPTExIT1VTRV9MT0dfU0VDVVJJVFlfUkVURU5USU9OX0RBWVM6IHouY29lcmNlLm51bWJlcigpLmRlZmF1bHQoNyksXG4gIERPTExIT1VTRV9MT0dfRkxVU0hfSU5URVJWQUxfTVM6IHouY29lcmNlLm51bWJlcigpLmRlZmF1bHQoNTAwMCksXG4gIC8vIEJ1ZmZlciByYWlzZWQgdG8gMjAwMCB0byBzdXBwb3J0IHRoZSB3ZWIgY29uc29sZSBsb2cgdmlld2VyIOKAlCB0aGUgaGlnaGVyIGNhcGFjaXR5XG4gIC8vIHJlZHVjZXMgZmx1c2ggZnJlcXVlbmN5IGFuZCBrZWVwcyBtb3JlIGVudHJpZXMgYXZhaWxhYmxlIGZvciBTU0UgYmFja2ZpbGwgb24gY29ubmVjdC5cbiAgRE9MTEhPVVNFX0xPR19CVUZGRVJfU0laRTogei5jb2VyY2UubnVtYmVyKCkuZGVmYXVsdCgyMDAwKSxcbiAgRE9MTEhPVVNFX0xPR19NRU1PUllfQ0FQQUNJVFk6IHouY29lcmNlLm51bWJlcigpLmRlZmF1bHQoNTAwMCksXG4gIERPTExIT1VTRV9MT0dfTUVNT1JZX0FQUF9DQVBBQ0lUWTogei5jb2VyY2UubnVtYmVyKCkuZGVmYXVsdCgxMDAwMCksXG4gIERPTExIT1VTRV9MT0dfTUVNT1JZX1NFQ1VSSVRZX0NBUEFDSVRZOiB6LmNvZXJjZS5udW1iZXIoKS5kZWZhdWx0KDUwMDApLFxuICBET0xMSE9VU0VfTE9HX01FTU9SWV9QRVJGX0NBUEFDSVRZOiB6LmNvZXJjZS5udW1iZXIoKS5kZWZhdWx0KDIwMDApLFxuICBET0xMSE9VU0VfTE9HX01FTU9SWV9URUxFTUVUUllfQ0FQQUNJVFk6IHouY29lcmNlLm51bWJlcigpLmRlZmF1bHQoMTAwMCksXG4gIERPTExIT1VTRV9MT0dfTUFYX0VOVFJZX1NJWkU6IHouY29lcmNlLm51bWJlcigpLmRlZmF1bHQoMTYzODQpLFxuICBET0xMSE9VU0VfTE9HX0lNTUVESUFURV9GTFVTSF9SQVRFOiB6LmNvZXJjZS5udW1iZXIoKS5kZWZhdWx0KDUwKSxcbiAgRE9MTEhPVVNFX0xPR19GSUxFX01BWF9TSVpFOiB6LmNvZXJjZS5udW1iZXIoKS5kZWZhdWx0KDEwNDg1NzYwMCksXG4gIERPTExIT1VTRV9MT0dfTUFYX0RJUl9TSVpFX0JZVEVTOiB6LmNvZXJjZS5udW1iZXIoKS5kZWZhdWx0KDApLFxuICBET0xMSE9VU0VfTE9HX01BWF9GSUxFU19QRVJfQ0FURUdPUlk6IHouY29lcmNlLm51bWJlcigpLmRlZmF1bHQoMTAwKSxcblxuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gIC8vIFBlcm1pc3Npb24gU2VydmVyIENvbmZpZ3VyYXRpb25cbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICAvKipcbiAgICogRW5hYmxlIHRoZSBIVFRQIHBlcm1pc3Npb24gZXZhbHVhdGlvbiBzZXJ2ZXIgZm9yIFByZVRvb2xVc2UgaG9va3MuXG4gICAqIFdoZW4gdHJ1ZSwgc3RhcnRzIGFuIEhUVFAgZW5kcG9pbnQgb24gYSBkeW5hbWljIHBvcnQgYWZ0ZXIgZGVmZXJyZWRcbiAgICogc2V0dXAgY29tcGxldGVzLiBXcml0ZXMgcG9ydCB0byB+Ly5kb2xsaG91c2UvcnVuL3Blcm1pc3Npb24tc2VydmVyLnBvcnRcbiAgICogZm9yIGhvb2sgc2NyaXB0IGRpc2NvdmVyeS4gUmVxdWlyZWQgZm9yIGF1dG9ub21vdXMgYWdlbnQgcGVybWlzc2lvblxuICAgKiBtYW5hZ2VtZW50IHZpYSBDbGF1ZGUgQ29kZSBob29rcy5cbiAgICovXG4gIERPTExIT1VTRV9QRVJNSVNTSU9OX1NFUlZFUjogei5jb2VyY2UuYm9vbGVhbigpLmRlZmF1bHQodHJ1ZSksXG5cbiAgLy8gV2ViIENvbnNvbGUgQ29uZmlndXJhdGlvblxuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gIC8qKiBFbmFibGUgdGhlIHVuaWZpZWQgd2ViIGNvbnNvbGUgKGxvZ3MgKyBtZXRyaWNzIHRhYnMpICovXG4gIERPTExIT1VTRV9XRUJfQ09OU09MRTogei5jb2VyY2UuYm9vbGVhbigpLmRlZmF1bHQodHJ1ZSksXG5cbiAgLyoqXG4gICAqIFBvcnQgdGhlIHdlYiBjb25zb2xlIGxlYWRlciBiaW5kcyB0byAoIzE3OTQsICMxNzk4KS5cbiAgICpcbiAgICogRGVmYXVsdDogNDE3MTUg4oCUIFwiQUlMSVNcIiBvbiBhIHBob25lIGtleXBhZCwgYWZ0ZXIgdGhlIEFJIExheWVyXG4gICAqIEludGVyZmFjZSBTcGVjaWZpY2F0aW9uIHRoYXQgRG9sbGhvdXNlTUNQIGltcGxlbWVudHMuIEFsc28gXCJBbGljZVwiXG4gICAqIGluIEdhZWxpYy5cbiAgICpcbiAgICogUG9ydCBzZWxlY3Rpb24gY3JpdGVyaWEgKHZlcmlmaWVkIDIwMjYtMDQtMDYpOlxuICAgKiAgIC0gTm90IHJlZ2lzdGVyZWQgd2l0aCBJQU5BIChubyBlbnRyeSBpbiB0aGUgc2VydmljZSBuYW1lIHJlZ2lzdHJ5KVxuICAgKiAgIC0gTm90IGluIG5tYXAgc2VydmljZXMgZGF0YWJhc2UgKG5ldmVyIG9ic2VydmVkIGluIHRoZSB3aWxkKVxuICAgKiAgIC0gTm8ga25vd24gYXBwbGljYXRpb24sIHNlY3VyaXR5IHRvb2wsIG9yIG1hbHdhcmUgYXNzb2NpYXRpb25zXG4gICAqICAgLSBCZWxvdyB0aGUgbWFjT1MgZXBoZW1lcmFsIHJhbmdlICg0OTE1Mi02NTUzNSksIHNvIGBiaW5kKClgXG4gICAqICAgICBkb2VzIG5vdCByYWNlIHdpdGgga2VybmVsLWFsbG9jYXRlZCBzb3VyY2UgcG9ydHNcbiAgICogICAtIEluIHRoZSBJQU5BIHVzZXIgcG9ydCByYW5nZSAoMTAyNC00OTE1MSlcbiAgICogICAtIE5vdCBhZGphY2VudCB0byB0aGUgcHJlLWF1dGhlbnRpY2F0aW9uIGRlZmF1bHQgKDM5MzkpXG4gICAqXG4gICAqIFByZXZpb3VzIGRlZmF1bHQgd2FzIDU5MDcgKFwiTE9HU1wiIHVwc2lkZSBkb3duIG9uIGEgY2FsY3VsYXRvciksXG4gICAqIHdoaWNoIGNvbmZsaWN0ZWQgd2l0aCBTdGVsbGFyIEN5YmVyJ3MgSFRUUCBHS0UgbG9nIHBhcnNlci5cbiAgICpcbiAgICogT3ZlcnJpZGUgdmlhIGVudiB2YXIgaWYgNDE3MTUgY29sbGlkZXMgd2l0aCBzb21ldGhpbmcgaW4geW91clxuICAgKiBlbnZpcm9ubWVudCDigJQgZXZlcnkgcnVudGltZSByZWZlcmVuY2UgcmVhZHMgZnJvbSB0aGlzIHNpbmdsZSB2YWx1ZS5cbiAgICovXG4gIERPTExIT1VTRV9XRUJfQ09OU09MRV9QT1JUOiB6LmNvZXJjZS5udW1iZXIoKS5pbnQoKS5taW4oMTAyNCkubWF4KDY1NTM1KS5kZWZhdWx0KDQxNzE1KSxcblxuICAvKipcbiAgICogSXNzdWUgIzE3ODA6IEVuZm9yY2UgQmVhcmVyIHRva2VuIGF1dGhlbnRpY2F0aW9uIG9uIHRoZSB3ZWIgY29uc29sZSBBUEkuXG4gICAqIFdoZW4gdHJ1ZSwgYWxsIHByb3RlY3RlZCBlbmRwb2ludHMgcmVxdWlyZSBhIHZhbGlkIHRva2VuIGZyb20gdGhlXG4gICAqIGNvbnNvbGUgdG9rZW4gZmlsZS4gV2hlbiBmYWxzZSAodGhlIHByZS1QaGFzZS0yIGRlZmF1bHQpLCB0aGUgdG9rZW5cbiAgICogZmlsZSBpcyBzdGlsbCBnZW5lcmF0ZWQgYnV0IHRoZSBtaWRkbGV3YXJlIGRvZXMgbm90IGVuZm9yY2Ug4oCUIHRoaXNcbiAgICogbGV0cyB0aGUgaW5mcmFzdHJ1Y3R1cmUgbGFuZCB3aXRob3V0IGJyZWFraW5nIGV4aXN0aW5nIGNvbnN1bWVycy5cbiAgICogV2lsbCBmbGlwIHRvIGRlZmF1bHQgYHRydWVgIGluIGEgZm9sbG93LXVwIFBSIG9uY2UgYWxsIGNvbnN1bWVyc1xuICAgKiAoYnJvd3NlciwgZm9sbG93ZXJzLCBicmlkZ2UpIGhhdmUgYmVlbiB1cGRhdGVkIHRvIGF0dGFjaCB0b2tlbnMuXG4gICAqL1xuICBET0xMSE9VU0VfV0VCX0FVVEhfRU5BQkxFRDogei5jb2VyY2UuYm9vbGVhbigpLmRlZmF1bHQoZmFsc2UpLFxuXG4gIC8qKlxuICAgKiBJc3N1ZSAjMTc4MDogT3B0aW9uYWwgb3ZlcnJpZGUgZm9yIHRoZSBjb25zb2xlIHRva2VuIGZpbGUgbG9jYXRpb24uXG4gICAqIFdoZW4gdW5zZXQsIGBDb25zb2xlVG9rZW5TdG9yZWAgZmFsbHMgYmFjayB0byBpdHMgYnVpbHQtaW4gZGVmYXVsdFxuICAgKiB1bmRlciBgfi8uZG9sbGhvdXNlL3J1bi9gLiBNYWlubHkgdXNlZnVsIGZvciB0ZXN0cyBhbmQgZm9yIGVudGVycHJpc2VcbiAgICogZGVwbG95bWVudHMgdGhhdCBtb3VudCBhIHNoYXJlZCB0b2tlbiBmaWxlIGZyb20gYSBzZWNyZXRzIHZvbHVtZS5cbiAgICovXG4gIERPTExIT1VTRV9DT05TT0xFX1RPS0VOX0ZJTEU6IHouc3RyaW5nKCkub3B0aW9uYWwoKSxcblxuICAvKipcbiAgICogT3B0aW9uYWwgb3ZlcnJpZGUgZm9yIHRoZSBjb25zb2xlIGxlYWRlciBsb2NrIGZpbGUgbG9jYXRpb24gKCMxNzk0KS5cbiAgICogV2hlbiB1bnNldCwgYExlYWRlckVsZWN0aW9uYCBmYWxscyBiYWNrIHRvIGl0cyBidWlsdC1pbiBkZWZhdWx0IHVuZGVyXG4gICAqIGB+Ly5kb2xsaG91c2UvcnVuL2AuIFByaW1hcmlseSB1c2VmdWwgZm9yIHRlc3RzIHRoYXQgbmVlZCBpc29sYXRpb25cbiAgICogYmV0d2VlbiBydW5zIGFuZCBmb3IgZGVwbG95bWVudHMgdGhhdCBzcGxpdCBydW50aW1lIHN0YXRlIGFjcm9zc1xuICAgKiBtdWx0aXBsZSBpbnN0YWxsYXRpb25zIG9uIHRoZSBzYW1lIG1hY2hpbmUuXG4gICAqL1xuICBET0xMSE9VU0VfQ09OU09MRV9MRUFERVJfTE9DS19GSUxFOiB6LnN0cmluZygpLm9wdGlvbmFsKCksXG5cbiAgLy8gTGVhZGVyL0ZvbGxvd2VyIFJlY292ZXJ5ICgjMTg1MClcbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4gIC8qKlxuICAgKiBJc3N1ZSAjMTg1MDogUmV0cnkgZGVsYXlzIChpbiBtcykgd2hlbiB0aGUgbGVhZGVyIGZhaWxzIHRvIGJpbmQgdGhlIGNvbnNvbGVcbiAgICogcG9ydCBkdWUgdG8gRUFERFJJTlVTRS4gRWFjaCB2YWx1ZSBpcyBhIHN1Y2Nlc3NpdmUgYmFja29mZiBkZWxheS5cbiAgICogRGVmYXVsdDogMXMsIDJzLCA0cyAoN3MgdG90YWwpLiBJbmNyZWFzZSBmb3Igc2xvdyBvciByZW1vdGUgZW52aXJvbm1lbnRzLlxuICAgKi9cbiAgRE9MTEhPVVNFX0NPTlNPTEVfQklORF9SRVRSWV9ERUxBWVM6IHouc3RyaW5nKClcbiAgICAub3B0aW9uYWwoKVxuICAgIC50cmFuc2Zvcm0odiA9PiB2ID8gdi5zcGxpdCgnLCcpLm1hcChOdW1iZXIpLmZpbHRlcihuID0+ICFOdW1iZXIuaXNOYU4obikgJiYgbiA+IDApIDogdW5kZWZpbmVkKSxcblxuICAvKipcbiAgICogSXNzdWUgIzE4NTA6IE51bWJlciBvZiBjb25zZWN1dGl2ZSBmb3J3YXJkaW5nIGZhaWx1cmVzIGJlZm9yZSBhIGZvbGxvd2VyXG4gICAqIGRlY2xhcmVzIHRoZSBsZWFkZXIgZGVhZCBhbmQgYXR0ZW1wdHMgc2VsZi1wcm9tb3Rpb24uIEhpZ2hlciB2YWx1ZXMgcmVkdWNlXG4gICAqIGZhbHNlIHBvc2l0aXZlcyBpbiBoaWdoLWxhdGVuY3kgZW52aXJvbm1lbnRzIGJ1dCBkZWxheSByZWNvdmVyeS5cbiAgICogRGVmYXVsdDogMTAuXG4gICAqL1xuICBET0xMSE9VU0VfQ09OU09MRV9NQVhfRk9SV0FSRF9GQUlMVVJFUzogei5jb2VyY2UubnVtYmVyKCkuaW50KCkubWluKDEpLm1heCgxMDApLmRlZmF1bHQoMTApLFxuXG4gIC8qKlxuICAgKiBJc3N1ZSAjMTc4MDogUGhhc2UgMiDigJQgcmVxdWlyZSBhIGNvbmZpcm1hdGlvbiBjb2RlIChPUyBkaWFsb2cgb3IgVE9UUClcbiAgICogZm9yIHByaXZpbGVnZWQgYWN0aW9ucyBsaWtlIHRva2VuIHJvdGF0aW9uLiBEZWZhdWx0IGlzIHRydWUgZm9yIHNhZmV0eTtcbiAgICogc2V0IHRvIGZhbHNlIGZvciBoZWFkbGVzcyBDSSBhbmQgc2NyaXB0ZWQgZGVwbG95bWVudHMgdGhhdCBuZWVkIHRvIHJvdGF0ZVxuICAgKiB3aXRob3V0IGh1bWFuIGludGVyYWN0aW9uLlxuICAgKi9cbiAgRE9MTEhPVVNFX0NPTlNPTEVfUk9UQVRJT05fUkVRVUlSRV9DT05GSVJNQVRJT046IHouY29lcmNlLmJvb2xlYW4oKS5kZWZhdWx0KHRydWUpLFxuXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAgLy8gU2VjdXJpdHkgQ29uZmlndXJhdGlvblxuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gIC8qKlxuICAgKiBJc3N1ZSAjNDUyOiBHYXRla2VlcGVyIHBvbGljeSBlbmZvcmNlbWVudC5cbiAgICogV2hlbiB0cnVlIChkZWZhdWx0KSwgYWxsIE1DUC1BUUwgb3BlcmF0aW9ucyBnbyB0aHJvdWdoIHRoZSA0LWxheWVyIEdhdGVrZWVwZXJcbiAgICogZW5mb3JjZSgpIHBpcGVsaW5lLiBXaGVuIGZhbHNlLCBmYWxscyBiYWNrIHRvIHJvdXRlIHZhbGlkYXRpb24gb25seS5cbiAgICogVGhpcyBpcyBhIHVzZXIvb3BlcmF0b3Igc2V0dGluZyDigJQgdGhlIExMTSBjYW5ub3QgYnlwYXNzIGl0LlxuICAgKi9cbiAgRE9MTEhPVVNFX0dBVEVLRUVQRVJfRU5BQkxFRDogei5jb2VyY2UuYm9vbGVhbigpLmRlZmF1bHQodHJ1ZSksXG4gIC8qKlxuICAgKiBJc3N1ZSAjNjc5OiBFbGVtZW50IHBvbGljeSBsYXllciBraWxsIHN3aXRjaC5cbiAgICogV2hlbiB0cnVlIChkZWZhdWx0KSwgYWN0aXZlIGVsZW1lbnQgZ2F0ZWtlZXBlciBwb2xpY2llcyAoYWxsb3cvY29uZmlybS9kZW55L3Njb3BlUmVzdHJpY3Rpb25zKVxuICAgKiBjYW4gb3ZlcnJpZGUgZGVmYXVsdCBvcGVyYXRpb24gcGVybWlzc2lvbiBsZXZlbHMuIFdoZW4gZmFsc2UsIExheWVyIDIgb2YgR2F0ZWtlZXBlci5lbmZvcmNlKClcbiAgICogaXMgYnlwYXNzZWQgZW50aXJlbHkg4oCUIG9ubHkgcm91dGUgdmFsaWRhdGlvbiBhbmQgZGVmYXVsdCBwZXJtaXNzaW9uIGxldmVscyBhcHBseS5cbiAgICogVXNlIGZvciBlbWVyZ2VuY3kgbG9ja2Rvd24sIGhhcmRlbmVkIGRlcGxveW1lbnRzLCBvciBwb2xpY3kgZGVidWdnaW5nLlxuICAgKiBUaGlzIGlzIGFuIG9wZXJhdG9yL2luZnJhc3RydWN0dXJlIHNldHRpbmcg4oCUIHRoZSBMTE0gY2Fubm90IGJ5cGFzcyBpdC5cbiAgICovXG4gIERPTExIT1VTRV9HQVRFS0VFUEVSX0VMRU1FTlRfUE9MSUNZX09WRVJSSURFUzogei5jb2VyY2UuYm9vbGVhbigpLmRlZmF1bHQodHJ1ZSksXG4gIC8qKlxuICAgKiBJc3N1ZSAjNzk5OiBQb2xpY3kgZXhwb3J0IG9wdC1pbiBmbGFnLlxuICAgKiBXaGVuIHRydWUgKGRlZmF1bHQpLCBQb2xpY3lFeHBvcnRTZXJ2aWNlIHdyaXRlcyB0aGUgc2VjdXJpdHkgcG9saWN5IGJsdWVwcmludCB0b1xuICAgKiB+Ly5kb2xsaG91c2UvYnJpZGdlL2ltcG9ydHMvcG9saWNpZXMvIG9uIGFjdGl2YXRpb24gY2hhbmdlcy4gVGhlIERvbGxob3VzZUJyaWRnZVxuICAgKiBwZXJtaXNzaW9uLXByb21wdCBzZXJ2ZXIgd2F0Y2hlcyB0aGlzIGZpbGUgdG8gZXZhbHVhdGUgcGVybWlzc2lvbnMgbG9jYWxseS5cbiAgICogU2V0IHRvIGZhbHNlIHRvIGRpc2FibGUgcG9saWN5IGZpbGUgZXhwb3J0IGVudGlyZWx5LlxuICAgKi9cbiAgRE9MTEhPVVNFX1BPTElDWV9FWFBPUlRfRU5BQkxFRDogei5jb2VyY2UuYm9vbGVhbigpLmRlZmF1bHQodHJ1ZSksXG5cbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICAvLyBTdG9yYWdlIExheWVyIENvbmZpZ3VyYXRpb25cbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICBET0xMSE9VU0VfU0NBTl9DT09MRE9XTl9NUzogei5jb2VyY2UubnVtYmVyKCkuZGVmYXVsdCgxMDAwKSxcbiAgRE9MTEhPVVNFX0lOREVYX0RFQk9VTkNFX01TOiB6LmNvZXJjZS5udW1iZXIoKS5kZWZhdWx0KDIwMDApLFxuICBET0xMSE9VU0VfRUxFTUVOVF9DQUNIRV9UVExfTVM6IHouY29lcmNlLm51bWJlcigpLmRlZmF1bHQoMzYwMDAwMCksXG4gIERPTExIT1VTRV9QQVRIX0NBQ0hFX1RUTF9NUzogei5jb2VyY2UubnVtYmVyKCkuZGVmYXVsdCgzNjAwMDAwKSxcbiAgRE9MTEhPVVNFX1RPT0xfQ0FDSEVfVFRMX01TOiB6LmNvZXJjZS5udW1iZXIoKS5kZWZhdWx0KDYwMDAwKSxcbiAgRE9MTEhPVVNFX0dMT0JBTF9DQUNIRV9NRU1PUllfTUI6IHouY29lcmNlLm51bWJlcigpLmRlZmF1bHQoMTUwKSxcblxuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gIC8vIFBlcm1pc3Npb24gUHJvbXB0IENvbmZpZ3VyYXRpb24gKElzc3VlICM2MjUpXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuICAvKiogTWF4aW11bSBDTEkgYXBwcm92YWwgcmVjb3JkcyBiZWZvcmUgTFJVIGV2aWN0aW9uIChkZWZhdWx0OiA1MCkgKi9cbiAgRE9MTEhPVVNFX0NMSV9BUFBST1ZBTF9NQVg6IHouY29lcmNlLm51bWJlcigpLmRlZmF1bHQoNTApLFxuXG4gIC8qKiBEZWZhdWx0IFRUTCBmb3IgQ0xJIGFwcHJvdmFsIHJlY29yZHMgaW4gbXMgKGRlZmF1bHQ6IDMwMDAwMCA9IDUgbWluKSAqL1xuICBET0xMSE9VU0VfQ0xJX0FQUFJPVkFMX1RUTF9NUzogei5jb2VyY2UubnVtYmVyKCkuZGVmYXVsdCgzMDBfMDAwKSxcblxuICAvKiogUGVybWlzc2lvbiBwcm9tcHQgcmF0ZSBsaW1pdDogbWF4IHJlcXVlc3RzIHBlciB3aW5kb3cgKGRlZmF1bHQ6IDEwMCkgKi9cbiAgRE9MTEhPVVNFX1BFUk1JU1NJT05fUFJPTVBUX1JBVEVfTElNSVQ6IHouY29lcmNlLm51bWJlcigpLmRlZmF1bHQoMTAwKSxcblxuICAvKiogQ0xJIGFwcHJvdmFsIGNyZWF0aW9uIHJhdGUgbGltaXQ6IG1heCByZXF1ZXN0cyBwZXIgd2luZG93IChkZWZhdWx0OiAyMCkgKi9cbiAgRE9MTEhPVVNFX0NMSV9BUFBST1ZBTF9SQVRFX0xJTUlUOiB6LmNvZXJjZS5udW1iZXIoKS5kZWZhdWx0KDIwKSxcblxuICAvKiogUmF0ZSBsaW1pdCB3aW5kb3cgaW4gbXMgZm9yIHBlcm1pc3Npb24gcHJvbXB0IGFuZCBDTEkgYXBwcm92YWxzIChkZWZhdWx0OiA2MDAwMCA9IDYwcykgKi9cbiAgRE9MTEhPVVNFX1BFUk1JU1NJT05fUkFURV9XSU5ET1dfTVM6IHouY29lcmNlLm51bWJlcigpLmRlZmF1bHQoNjBfMDAwKSxcblxuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gIC8vIE1ldHJpY3MgQ29sbGVjdGlvbiBDb25maWd1cmF0aW9uXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAgRE9MTEhPVVNFX01FVFJJQ1NfRU5BQkxFRDogei5jb2VyY2UuYm9vbGVhbigpLmRlZmF1bHQodHJ1ZSksXG4gIERPTExIT1VTRV9NRVRSSUNTX0NPTExFQ1RJT05fSU5URVJWQUxfTVM6IHouY29lcmNlLm51bWJlcigpLm1pbigxMDAwKS5tYXgoMzAwMDAwKS5kZWZhdWx0KDE1MDAwKSxcbiAgRE9MTEhPVVNFX01FVFJJQ1NfTUFYX1NOQVBTSE9UX1NJWkU6IHouY29lcmNlLm51bWJlcigpLmRlZmF1bHQoMTAyNDAwKSxcbiAgRE9MTEhPVVNFX01FVFJJQ1NfQ09MTEVDVE9SX0ZBSUxVUkVfVEhSRVNIT0xEOiB6LmNvZXJjZS5udW1iZXIoKS5taW4oMSkubWF4KDEwMCkuZGVmYXVsdCgxMCksXG4gIERPTExIT1VTRV9NRVRSSUNTX0NPTExFQ1RJT05fRFVSQVRJT05fV0FSTl9NUzogei5jb2VyY2UubnVtYmVyKCkubWluKDEwMCkubWF4KDYwMDAwKS5kZWZhdWx0KDUwMDApLFxuICBET0xMSE9VU0VfTUVUUklDU19NRU1PUllfU05BUFNIT1RfQ0FQQUNJVFk6IHouY29lcmNlLm51bWJlcigpLm1pbigxMCkubWF4KDEwMDAwKS5kZWZhdWx0KDI0MCksXG5cbiAgLy8gUGF0dGVybiBlbmNyeXB0aW9uIHNldHRpbmdzIGZvciBNZW1vcnkgU2VjdXJpdHkgKElzc3VlICMxMzIxKVxuICBET0xMSE9VU0VfRElTQUJMRV9FTkNSWVBUSU9OOiB6LmNvZXJjZS5ib29sZWFuKCkuZGVmYXVsdChmYWxzZSksXG4gIERPTExIT1VTRV9FTkNSWVBUSU9OX1NFQ1JFVDogei5zdHJpbmcoKS5vcHRpb25hbCgpLFxuICBET0xMSE9VU0VfRU5DUllQVElPTl9TQUxUOiB6LnN0cmluZygpLm9wdGlvbmFsKCksXG5cbiAgLy8gVG9rZW4gZW5jcnlwdGlvbiBzZWNyZXQgKFNFQy0wMSwgIzE3MzUpXG4gIC8vIFdoZW4gc2V0LCByZXBsYWNlcyB0aGUgcHJlZGljdGFibGUgbWFjaGluZS1kZXJpdmVkIHBhc3NwaHJhc2UgZm9yIHRva2VuIGVuY3J5cHRpb24uXG4gIC8vIFN0cm9uZ2x5IHJlY29tbWVuZGVkIGZvciBhbnkgc2hhcmVkIG9yIG11bHRpLXVzZXIgZW52aXJvbm1lbnQuXG4gIC8vIE1pbmltdW0gMzIgY2hhcmFjdGVycyBlbmZvcmNlZCB0byBwcmV2ZW50IHdlYWsgcGFzc3BocmFzZXMuXG4gIERPTExIT1VTRV9UT0tFTl9TRUNSRVQ6IHouc3RyaW5nKCkubWluKDMyKS5vcHRpb25hbCgpLFxufSk7XG5cbi8qKlxuICogVmFsaWRhdGVkIGVudmlyb25tZW50IHZhcmlhYmxlc1xuICogVHlwZSBpcyBhdXRvbWF0aWNhbGx5IGluZmVycmVkIGZyb20gdGhlIHNjaGVtYVxuICovXG5leHBvcnQgY29uc3QgZW52ID0gZW52U2NoZW1hLnBhcnNlKHByb2Nlc3MuZW52KTtcblxuLyoqXG4gKiBFbnZpcm9ubWVudCB0eXBlIChpbmZlcnJlZCBmcm9tIHNjaGVtYSlcbiAqL1xuZXhwb3J0IHR5cGUgRW52ID0gei5pbmZlcjx0eXBlb2YgZW52U2NoZW1hPjtcblxuLyoqXG4gKiBDb252ZW5pZW5jZSBoZWxwZXJzIGZvciBlbnZpcm9ubWVudCBkZXRlY3Rpb25cbiAqL1xuZXhwb3J0IGNvbnN0IGlzVGVzdCA9IGVudi5OT0RFX0VOViA9PT0gJ3Rlc3QnO1xuZXhwb3J0IGNvbnN0IGlzRGV2ZWxvcG1lbnQgPSBlbnYuTk9ERV9FTlYgPT09ICdkZXZlbG9wbWVudCc7XG5leHBvcnQgY29uc3QgaXNQcm9kdWN0aW9uID0gZW52Lk5PREVfRU5WID09PSAncHJvZHVjdGlvbic7XG5cbi8qKlxuICogTG9nIGVudmlyb25tZW50IGNvbmZpZ3VyYXRpb24gKHdpdGhvdXQgc2VjcmV0cylcbiAqL1xuaWYgKGlzRGV2ZWxvcG1lbnQgfHwgaXNUZXN0KSB7XG4gIGxvZ2dlci5kZWJ1ZygnRW52aXJvbm1lbnQgY29uZmlndXJhdGlvbiBsb2FkZWQ6Jywge1xuICAgIE5PREVfRU5WOiBlbnYuTk9ERV9FTlYsXG4gICAgUE9SVDogZW52LlBPUlQsXG4gICAgTE9HX0xFVkVMOiBlbnYuTE9HX0xFVkVMLFxuICAgIEhBU19HSVRIVUJfVE9LRU46ICEhZW52LkdJVEhVQl9UT0tFTixcbiAgICBIQVNfR0lUSFVCX1RFU1RfVE9LRU46ICEhZW52LkdJVEhVQl9URVNUX1RPS0VOLFxuICB9KT