UNPKG

@dollhousemcp/mcp-server

Version:

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

312 lines 47.8 kB
/** * Migration Manager - Handles migration from legacy structure to portfolio structure */ import * as path from 'path'; import { ElementType } from './types.js'; import { logger } from '../utils/logger.js'; import { UnicodeValidator } from '../security/validators/unicodeValidator.js'; import { ContentValidator } from '../security/contentValidator.js'; import { SecurityMonitor } from '../security/securityMonitor.js'; import { SECURITY_LIMITS } from '../security/constants.js'; export class MigrationManager { portfolioManager; fileLockManager; fileOperations; constructor(portfolioManager, fileLockManager, fileOperationsService) { this.portfolioManager = portfolioManager; this.fileLockManager = fileLockManager; this.fileOperations = fileOperationsService; } /** * Check if migration is needed */ async needsMigration() { const hasLegacy = await this.portfolioManager.hasLegacyPersonas(); const portfolioExists = await this.portfolioManager.exists(); // Need migration if we have legacy personas but no portfolio yet return hasLegacy && !portfolioExists; } /** * Perform migration from legacy to portfolio structure */ async migrate(options) { const result = { success: true, migratedCount: 0, errors: [], backedUp: false }; try { // Check if migration is needed if (!await this.needsMigration()) { logger.info('[MigrationManager] No migration needed'); return result; } logger.info('[MigrationManager] Starting migration from legacy personas to portfolio structure'); // SECURITY FIX: DMCP-SEC-006 - Add security audit logging SecurityMonitor.logSecurityEvent({ type: 'PORTFOLIO_INITIALIZATION', severity: 'LOW', source: 'migration_manager', details: 'Starting migration from legacy personas to portfolio structure', metadata: { backup: !!options?.backup } }); // Create backup if requested if (options?.backup) { const backupPath = await this.createBackup(); result.backedUp = true; result.backupPath = backupPath; logger.info(`[MigrationManager] Created backup at: ${backupPath}`); // SECURITY FIX: DMCP-SEC-006 - Log backup creation for audit trail SecurityMonitor.logSecurityEvent({ type: 'FILE_COPIED', severity: 'LOW', source: 'migration_manager', details: `Created backup during migration: ${backupPath}`, metadata: { backupPath, operation: 'migration_backup' } }); } // Initialize portfolio structure await this.portfolioManager.initialize(); // Get legacy personas const legacyDir = this.portfolioManager.getLegacyPersonasDir(); const files = await this.fileOperations.listDirectory(legacyDir); const personaFiles = files.filter(file => file.endsWith('.md')); logger.info(`[MigrationManager] Found ${personaFiles.length} personas to migrate`); // Migrate each persona for (const file of personaFiles) { try { await this.migratePersona(file); result.migratedCount++; // SECURITY FIX: DMCP-SEC-006 - Log each successful migration for audit trail SecurityMonitor.logSecurityEvent({ type: 'FILE_COPIED', severity: 'LOW', source: 'migration_manager', details: `Successfully migrated persona: ${file}`, metadata: { filename: file, operation: 'persona_migration' } }); } catch (error) { const errorMsg = `Failed to migrate ${file}: ${error instanceof Error ? error.message : String(error)}`; logger.error(`[MigrationManager] ${errorMsg}`); result.errors.push(errorMsg); result.success = false; // SECURITY FIX: DMCP-SEC-006 - Log individual migration failures for audit trail SecurityMonitor.logSecurityEvent({ type: 'FILE_COPIED', severity: 'MEDIUM', source: 'migration_manager', details: `Failed to migrate persona: ${errorMsg}`, metadata: { filename: file, operation: 'persona_migration_failed', errorType: error instanceof Error ? error.name : 'unknown' } }); } } // If all migrations successful, optionally clean up legacy directory if (result.success && result.migratedCount > 0) { logger.info(`[MigrationManager] Successfully migrated ${result.migratedCount} personas`); // SECURITY FIX: DMCP-SEC-006 - Log successful migration completion for audit trail SecurityMonitor.logSecurityEvent({ type: 'PORTFOLIO_POPULATED', severity: 'LOW', source: 'migration_manager', details: `Migration completed successfully: ${result.migratedCount} personas migrated`, metadata: { migratedCount: result.migratedCount, backedUp: result.backedUp, backupPath: result.backupPath } }); // Note: We don't automatically delete the legacy directory // User should manually remove it after confirming migration success } } catch (error) { result.success = false; const errorMsg = `Migration failed: ${error instanceof Error ? error.message : String(error)}`; result.errors.push(errorMsg); // SECURITY FIX: DMCP-SEC-006 - Log migration failures for security audit trail SecurityMonitor.logSecurityEvent({ type: 'DIRECTORY_MIGRATION', severity: 'HIGH', source: 'migration_manager', details: `Migration failed: ${errorMsg}`, metadata: { errorType: error instanceof Error ? error.name : 'unknown', migratedCount: result.migratedCount, errorCount: result.errors.length } }); // Log with full error details including stack trace if (error instanceof Error) { logger.error(`[MigrationManager] ${errorMsg}`, { stack: error.stack, name: error.name, cause: error.cause }); } else { logger.error(`[MigrationManager] ${errorMsg}`, { rawError: error }); } } return result; } /** * Migrate a single persona file */ async migratePersona(filename) { // Normalize filename to prevent Unicode attacks const filenameValidation = UnicodeValidator.normalize(filename); const normalizedFilename = filenameValidation.normalizedContent; if (normalizedFilename !== filename) { logger.warn(`[MigrationManager] Filename normalized from "${filename}" to "${normalizedFilename}"`); } if (!filenameValidation.isValid) { logger.warn(`[MigrationManager] Filename has Unicode issues: ${filenameValidation.detectedIssues?.join(', ')}`); // SECURITY FIX: DMCP-SEC-006 - Log Unicode issues for security audit trail SecurityMonitor.logSecurityEvent({ type: 'UNICODE_VALIDATION_ERROR', severity: 'MEDIUM', source: 'migration_manager', details: `Unicode issues detected in filename during migration: ${filenameValidation.detectedIssues?.join(', ')}`, metadata: { originalFilename: filename, normalizedFilename, detectedIssues: filenameValidation.detectedIssues } }); } const legacyPath = path.join(this.portfolioManager.getLegacyPersonasDir(), filename); const newPath = this.portfolioManager.getElementPath(ElementType.PERSONA, normalizedFilename); // Read the content const content = await this.fileOperations.readFile(legacyPath, { source: 'MigrationManager.migratePersona' }); // Validate content size before processing const contentSize = Buffer.byteLength(content, 'utf8'); if (contentSize > SECURITY_LIMITS.MAX_PERSONA_SIZE_BYTES) { const maxSizeKB = Math.round(SECURITY_LIMITS.MAX_PERSONA_SIZE_BYTES / 1024); const actualSizeKB = Math.round(contentSize / 1024); throw new Error(`Content size (${actualSizeKB}KB) exceeds maximum allowed size (${maxSizeKB}KB) for persona files`); } // Normalize content to prevent Unicode issues const contentValidation = UnicodeValidator.normalize(content); const normalizedContent = contentValidation.normalizedContent; if (!contentValidation.isValid) { logger.warn(`[MigrationManager] Content has Unicode issues in ${filename}: ${contentValidation.detectedIssues?.join(', ')}`); // SECURITY FIX: DMCP-SEC-006 - Log Unicode content issues for security audit trail SecurityMonitor.logSecurityEvent({ type: 'UNICODE_VALIDATION_ERROR', severity: 'MEDIUM', source: 'migration_manager', details: `Unicode issues detected in content during migration: ${contentValidation.detectedIssues?.join(', ')}`, metadata: { filename, detectedIssues: contentValidation.detectedIssues, contentLength: content.length } }); } // SECURITY FIX: Add comprehensive content validation before write // FIXED: CVE-2025-XXXX - Direct file write without security validation in migration // Original issue: Line 147 used direct fs.writeFile without comprehensive validation // Security impact: Could allow malicious content to be written during migration // Fix: Added ContentValidator.validateAndSanitize with critical threat blocking const validationResult = ContentValidator.validateAndSanitize(normalizedContent); if (!validationResult.isValid && validationResult.severity === 'critical') { const patterns = validationResult.detectedPatterns?.join(', ') || 'unknown patterns'; throw new Error(`Critical security threat in migrated content for ${filename}: ${patterns}`); } const validatedContent = validationResult.sanitizedContent || normalizedContent; // SECURITY FIX: Replace direct write with atomic operation // FIXED: Race condition vulnerability in file writes during migration // Original issue: Line 147 used non-atomic fs.writeFile operation // Security impact: Race conditions could cause data corruption or partial writes // Fix: Replaced with FileOperationsService.writeFile for guaranteed atomicity await this.fileOperations.writeFile(newPath, validatedContent, { source: 'MigrationManager.migratePersona' }); // SECURITY FIX: DMCP-SEC-006 - Log file operations for security audit trail SecurityMonitor.logSecurityEvent({ type: 'FILE_COPIED', severity: 'LOW', source: 'migration_manager', details: `Persona file migrated with security validation: ${normalizedFilename}`, metadata: { originalFilename: filename, normalizedFilename, sourcePath: legacyPath, destinationPath: newPath, contentLength: validatedContent.length, unicodeNormalized: normalizedFilename !== filename, unicodeIssues: !contentValidation.isValid } }); logger.debug(`[MigrationManager] Migrated: ${filename}`); } /** * Create backup of legacy personas */ async createBackup() { const legacyDir = this.portfolioManager.getLegacyPersonasDir(); const timestamp = new Date().toISOString().replaceAll(/[:.]/g, '-'); const backupDir = `${legacyDir}_backup_${timestamp}`; // Create backup directory await this.fileOperations.createDirectory(backupDir); // Copy all files const files = await this.fileOperations.listDirectory(legacyDir); let copiedCount = 0; for (const file of files) { const srcPath = path.join(legacyDir, file); const destPath = path.join(backupDir, file); const stats = await this.fileOperations.stat(srcPath); if (stats.isFile()) { await this.fileOperations.copyFile(srcPath, destPath, { source: 'MigrationManager.createBackup' }); copiedCount++; } } // SECURITY FIX: DMCP-SEC-006 - Log backup operation details for audit trail SecurityMonitor.logSecurityEvent({ type: 'FILE_COPIED', severity: 'LOW', source: 'migration_manager', details: `Backup created: ${copiedCount} files copied to ${backupDir}`, metadata: { backupDir, legacyDir, filesCopied: copiedCount, operation: 'backup_creation' } }); return backupDir; } /** * Get migration status report */ async getMigrationStatus() { const hasLegacyPersonas = await this.portfolioManager.hasLegacyPersonas(); let legacyPersonaCount = 0; if (hasLegacyPersonas) { const legacyDir = this.portfolioManager.getLegacyPersonasDir(); const files = await this.fileOperations.listDirectory(legacyDir); legacyPersonaCount = files.filter(file => file.endsWith('.md')).length; } const portfolioExists = await this.portfolioManager.exists(); const portfolioStats = portfolioExists ? await this.portfolioManager.getStatistics() : Object.values(ElementType).reduce((acc, type) => ({ ...acc, [type]: 0 }), {}); return { hasLegacyPersonas, legacyPersonaCount, portfolioExists, portfolioStats }; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTWlncmF0aW9uTWFuYWdlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9wb3J0Zm9saW8vTWlncmF0aW9uTWFuYWdlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQUVILE9BQU8sS0FBSyxJQUFJLE1BQU0sTUFBTSxDQUFDO0FBRTdCLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFDekMsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQzVDLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLDRDQUE0QyxDQUFDO0FBQzlFLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBRW5FLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUVqRSxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFVM0QsTUFBTSxPQUFPLGdCQUFnQjtJQUNuQixnQkFBZ0IsQ0FBbUI7SUFDbkMsZUFBZSxDQUFrQjtJQUNqQyxjQUFjLENBQXdCO0lBRTlDLFlBQ0UsZ0JBQWtDLEVBQ2xDLGVBQWdDLEVBQ2hDLHFCQUE0QztRQUU1QyxJQUFJLENBQUMsZ0JBQWdCLEdBQUcsZ0JBQWdCLENBQUM7UUFDekMsSUFBSSxDQUFDLGVBQWUsR0FBRyxlQUFlLENBQUM7UUFDdkMsSUFBSSxDQUFDLGNBQWMsR0FBRyxxQkFBcUIsQ0FBQztJQUM5QyxDQUFDO0lBRUQ7O09BRUc7SUFDSSxLQUFLLENBQUMsY0FBYztRQUN6QixNQUFNLFNBQVMsR0FBRyxNQUFNLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1FBQ2xFLE1BQU0sZUFBZSxHQUFHLE1BQU0sSUFBSSxDQUFDLGdCQUFnQixDQUFDLE1BQU0sRUFBRSxDQUFDO1FBRTdELGlFQUFpRTtRQUNqRSxPQUFPLFNBQVMsSUFBSSxDQUFDLGVBQWUsQ0FBQztJQUN2QyxD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LG9CQUFvQixFQUFFLENBQUM7WUFDL0QsTUFBTSxLQUFLLEdBQUcsTUFBTSxJQUFJLENBQUMsY0FBYyxDQUFDLGFBQWEsQ0FBQyxTQUFTLENBQUMsQ0FBQztZQUNqRSxrQkFBa0IsR0FBRyxLQUFLLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQztRQUN6RSxDQUFDO1FBRUQsTUFBTSxlQUFlLEdBQUcsTUFBTSxJQUFJLENBQUMsZ0JBQWdCLENBQUMsTUFBTSxFQUFFLENBQUM7UUFDN0QsTUFBTSxjQUFjLEdBQUcsZUFBZTtZQUNwQyxDQUFDLENBQUMsTUFBTSxJQUFJLENBQUMsZ0JBQWdCLENBQUMsYUFBYSxFQUFFO1lBQzdDLENBQUMsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLFdBQVcsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLEdBQUcsRUFBRSxJQUFJLEVBQUUsRUFBRSxDQUFDLENBQUMsRUFBRSxHQUFHLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFnQyxDQUFDO1FBRWpILE9BQU87WUFDTCxpQkFBaUI7WUFDakIsa0JBQWtCO1lBQ2xCLGVBQWU7WUFDZixjQUFjO1NBQ2YsQ0FBQztJQUNKLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogTWlncmF0aW9uIE1hbmFnZXIgLSBIYW5kbGVzIG1pZ3JhdGlvbiBmcm9tIGxlZ2FjeSBzdHJ1Y3R1cmUgdG8gcG9ydGZvbGlvIHN0cnVjdHVyZVxuICovXG5cbmltcG9ydCAqIGFzIHBhdGggZnJvbSAncGF0aCc7XG5pbXBvcnQgeyBQb3J0Zm9saW9NYW5hZ2VyIH0gZnJvbSAnLi9Qb3J0Zm9saW9NYW5hZ2VyLmpzJztcbmltcG9ydCB7IEVsZW1lbnRUeXBlIH0gZnJvbSAnLi90eXBlcy5qcyc7XG5pbXBvcnQgeyBsb2dnZXIgfSBmcm9tICcuLi91dGlscy9sb2dnZXIuanMnO1xuaW1wb3J0IHsgVW5pY29kZVZhbGlkYXRvciB9IGZyb20gJy4uL3NlY3VyaXR5L3ZhbGlkYXRvcnMvdW5pY29kZVZhbGlkYXRvci5qcyc7XG5pbXBvcnQgeyBDb250ZW50VmFsaWRhdG9yIH0gZnJvbSAnLi4vc2VjdXJpdHkvY29udGVudFZhbGlkYXRvci5qcyc7XG5pbXBvcnQgeyBGaWxlTG9ja01hbmFnZXIgfSBmcm9tICcuLi9zZWN1cml0eS9maWxlTG9ja01hbmFnZXIuanMnO1xuaW1wb3J0IHsgU2VjdXJpdHlNb25pdG9yIH0gZnJvbSAnLi4vc2VjdXJpdHkvc2VjdXJpdHlNb25pdG9yLmpzJztcbmltcG9ydCB7IEZpbGVPcGVyYXRpb25zU2VydmljZSB9IGZyb20gJy4uL3NlcnZpY2VzL0ZpbGVPcGVyYXRpb25zU2VydmljZS5qcyc7XG5pbXBvcnQgeyBTRUNVUklUWV9MSU1JVFMgfSBmcm9tICcuLi9zZWN1cml0eS9jb25zdGFudHMuanMnO1xuXG5leHBvcnQgaW50ZXJmYWNlIE1pZ3JhdGlvblJlc3VsdCB7XG4gIHN1Y2Nlc3M6IGJvb2xlYW47XG4gIG1pZ3JhdGVkQ291bnQ6IG51bWJlcjtcbiAgZXJyb3JzOiBzdHJpbmdbXTtcbiAgYmFja2VkVXA6IGJvb2xlYW47XG4gIGJhY2t1cFBhdGg/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCBjbGFzcyBNaWdyYXRpb25NYW5hZ2VyIHtcbiAgcHJpdmF0ZSBwb3J0Zm9saW9NYW5hZ2VyOiBQb3J0Zm9saW9NYW5hZ2VyO1xuICBwcml2YXRlIGZpbGVMb2NrTWFuYWdlcjogRmlsZUxvY2tNYW5hZ2VyO1xuICBwcml2YXRlIGZpbGVPcGVyYXRpb25zOiBGaWxlT3BlcmF0aW9uc1NlcnZpY2U7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcG9ydGZvbGlvTWFuYWdlcjogUG9ydGZvbGlvTWFuYWdlcixcbiAgICBmaWxlTG9ja01hbmFnZXI6IEZpbGVMb2NrTWFuYWdlcixcbiAgICBmaWxlT3BlcmF0aW9uc1NlcnZpY2U6IEZpbGVPcGVyYXRpb25zU2VydmljZVxuICApIHtcbiAgICB0aGlzLnBvcnRmb2xpb01hbmFnZXIgPSBwb3J0Zm9saW9NYW5hZ2VyO1xuICAgIHRoaXMuZmlsZUxvY2tNYW5hZ2VyID0gZmlsZUxvY2tNYW5hZ2VyO1xuICAgIHRoaXMuZmlsZU9wZXJhdGlvbnMgPSBmaWxlT3BlcmF0aW9uc1NlcnZpY2U7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBDaGVjayBpZiBtaWdyYXRpb24gaXMgbmVlZGVkXG4gICAqL1xuICBwdWJsaWMgYXN5bmMgbmVlZHNNaWdyYXRpb24oKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgY29uc3QgaGFzTGVnYWN5ID0gYXdhaXQgdGhpcy5wb3J0Zm9saW9NYW5hZ2VyLmhhc0xlZ2FjeVBlcnNvbmFzKCk7XG4gICAgY29uc3QgcG9ydGZvbGlvRXhpc3RzID0gYXdhaXQgdGhpcy5wb3J0Zm9saW9NYW5hZ2VyLmV4aXN0cygpO1xuICAgIFxuICAgIC8vIE5lZWQgbWlncmF0aW9uIGlmIHdlIGhhdmUgbGVnYWN5IHBlcnNvbmFzIGJ1dCBubyBwb3J0Zm9saW8geWV0XG4gICAgcmV0dXJuIGhhc0xlZ2FjeSAmJiAhcG9ydGZvbGlvRXhpc3RzO1xuICB9XG4gIFxuICAvKipcbiAgICogUGVyZm9ybSBtaWdyYXRpb24gZnJvbSBsZWdhY3kgdG8gcG9ydGZvbGlvIHN0cnVjdHVyZVxuICAgKi9cbiAgcHVibGljIGFzeW5jIG1pZ3JhdGUob3B0aW9ucz86IHsgYmFja3VwPzogYm9vbGVhbiB9KTogUHJvbWlzZTxNaWdyYXRpb25SZXN1bHQ+IHtcbiAgICBjb25zdCByZXN1bHQ6IE1pZ3JhdGlvblJlc3VsdCA9IHtcbiAgICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgICBtaWdyYXRlZENvdW50OiAwLFxuICAgICAgZXJyb3JzOiBbXSxcbiAgICAgIGJhY2tlZFVwOiBmYWxzZVxuICAgIH07XG4gICAgXG4gICAgdHJ5IHtcbiAgICAgIC8vIENoZWNrIGlmIG1pZ3JhdGlvbiBpcyBuZWVkZWRcbiAgICAgIGlmICghYXdhaXQgdGhpcy5uZWVkc01pZ3JhdGlvbigpKSB7XG4gICAgICAgIGxvZ2dlci5pbmZvKCdbTWlncmF0aW9uTWFuYWdlcl0gTm8gbWlncmF0aW9uIG5lZWRlZCcpO1xuICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgfVxuICAgICAgXG4gICAgICBsb2dnZXIuaW5mbygnW01pZ3JhdGlvbk1hbmFnZXJdIFN0YXJ0aW5nIG1pZ3JhdGlvbiBmcm9tIGxlZ2FjeSBwZXJzb25hcyB0byBwb3J0Zm9saW8gc3RydWN0dXJlJyk7XG4gICAgICBcbiAgICAgIC8vIFNFQ1VSSVRZIEZJWDogRE1DUC1TRUMtMDA2IC0gQWRkIHNlY3VyaXR5IGF1ZGl0IGxvZ2dpbmdcbiAgICAgIFNlY3VyaXR5TW9uaXRvci5sb2dTZWN1cml0eUV2ZW50KHtcbiAgICAgICAgdHlwZTogJ1BPUlRGT0xJT19JTklUSUFMSVpBVElPTicsXG4gICAgICAgIHNldmVyaXR5OiAnTE9XJyxcbiAgICAgICAgc291cmNlOiAnbWlncmF0aW9uX21hbmFnZXInLFxuICAgICAgICBkZXRhaWxzOiAnU3RhcnRpbmcgbWlncmF0aW9uIGZyb20gbGVnYWN5IHBlcnNvbmFzIHRvIHBvcnRmb2xpbyBzdHJ1Y3R1cmUnLFxuICAgICAgICBtZXRhZGF0YTogeyBiYWNrdXA6ICEhb3B0aW9ucz8uYmFja3VwIH1cbiAgICAgIH0pO1xuICAgICAgXG4gICAgICAvLyBDcmVhdGUgYmFja3VwIGlmIHJlcXVlc3RlZFxuICAgICAgaWYgKG9wdGlvbnM/LmJhY2t1cCkge1xuICAgICAgICBjb25zdCBiYWNrdXBQYXRoID0gYXdhaXQgdGhpcy5jcmVhdGVCYWNrdXAoKTtcbiAgICAgICAgcmVzdWx0LmJhY2tlZFVwID0gdHJ1ZTtcbiAgICAgICAgcmVzdWx0LmJhY2t1cFBhdGggPSBiYWNrdXBQYXRoO1xuICAgICAgICBsb2dnZXIuaW5mbyhgW01pZ3JhdGlvbk1hbmFnZXJdIENyZWF0ZWQgYmFja3VwIGF0OiAke2JhY2t1cFBhdGh9YCk7XG4gICAgICAgIFxuICAgICAgICAvLyBTRUNVUklUWSBGSVg6IERNQ1AtU0VDLTAwNiAtIExvZyBiYWNrdXAgY3JlYXRpb24gZm9yIGF1ZGl0IHRyYWlsXG4gICAgICAgIFNlY3VyaXR5TW9uaXRvci5sb2dTZWN1cml0eUV2ZW50KHtcbiAgICAgICAgICB0eXBlOiAnRklMRV9DT1BJRUQnLFxuICAgICAgICAgIHNldmVyaXR5OiAnTE9XJyxcbiAgICAgICAgICBzb3VyY2U6ICdtaWdyYXRpb25fbWFuYWdlcicsXG4gICAgICAgICAgZGV0YWlsczogYENyZWF0ZWQgYmFja3VwIGR1cmluZyBtaWdyYXRpb246ICR7YmFja3VwUGF0aH1gLFxuICAgICAgICAgIG1ldGFkYXRhOiB7IGJhY2t1cFBhdGgsIG9wZXJhdGlvbjogJ21pZ3JhdGlvbl9iYWNrdXAnIH1cbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgICBcbiAgICAgIC8vIEluaXRpYWxpemUgcG9ydGZvbGlvIHN0cnVjdHVyZVxuICAgICAgYXdhaXQgdGhpcy5wb3J0Zm9saW9NYW5hZ2VyLmluaXRpYWxpemUoKTtcbiAgICAgIFxuICAgICAgLy8gR2V0IGxlZ2FjeSBwZXJzb25hc1xuICAgICAgY29uc3QgbGVnYWN5RGlyID0gdGhpcy5wb3J0Zm9saW9NYW5hZ2VyLmdldExlZ2FjeVBlcnNvbmFzRGlyKCk7XG4gICAgICBjb25zdCBmaWxlcyA9IGF3YWl0IHRoaXMuZmlsZU9wZXJhdGlvbnMubGlzdERpcmVjdG9yeShsZWdhY3lEaXIpO1xuICAgICAgY29uc3QgcGVyc29uYUZpbGVzID0gZmlsZXMuZmlsdGVyKGZpbGUgPT4gZmlsZS5lbmRzV2l0aCgnLm1kJykpO1xuICAgICAgXG4gICAgICBsb2dnZXIuaW5mbyhgW01pZ3JhdGlvbk1hbmFnZXJdIEZvdW5kICR7cGVyc29uYUZpbGVzLmxlbmd0aH0gcGVyc29uYXMgdG8gbWlncmF0ZWApO1xuICAgICAgXG4gICAgICAvLyBNaWdyYXRlIGVhY2ggcGVyc29uYVxuICAgICAgZm9yIChjb25zdCBmaWxlIG9mIHBlcnNvbmFGaWxlcykge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGF3YWl0IHRoaXMubWlncmF0ZVBlcnNvbmEoZmlsZSk7XG4gICAgICAgICAgcmVzdWx0Lm1pZ3JhdGVkQ291bnQrKztcbiAgICAgICAgICBcbiAgICAgICAgICAvLyBTRUNVUklUWSBGSVg6IERNQ1AtU0VDLTAwNiAtIExvZyBlYWNoIHN1Y2Nlc3NmdWwgbWlncmF0aW9uIGZvciBhdWRpdCB0cmFpbFxuICAgICAgICAgIFNlY3VyaXR5TW9uaXRvci5sb2dTZWN1cml0eUV2ZW50KHtcbiAgICAgICAgICAgIHR5cGU6ICdGSUxFX0NPUElFRCcsXG4gICAgICAgICAgICBzZXZlcml0eTogJ0xPVycsXG4gICAgICAgICAgICBzb3VyY2U6ICdtaWdyYXRpb25fbWFuYWdlcicsXG4gICAgICAgICAgICBkZXRhaWxzOiBgU3VjY2Vzc2Z1bGx5IG1pZ3JhdGVkIHBlcnNvbmE6ICR7ZmlsZX1gLFxuICAgICAgICAgICAgbWV0YWRhdGE6IHsgZmlsZW5hbWU6IGZpbGUsIG9wZXJhdGlvbjogJ3BlcnNvbmFfbWlncmF0aW9uJyB9XG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgY29uc3QgZXJyb3JNc2cgPSBgRmFpbGVkIHRvIG1pZ3JhdGUgJHtmaWxlfTogJHtlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcil9YDtcbiAgICAgICAgICBsb2dnZXIuZXJyb3IoYFtNaWdyYXRpb25NYW5hZ2VyXSAke2Vycm9yTXNnfWApO1xuICAgICAgICAgIHJlc3VsdC5lcnJvcnMucHVzaChlcnJvck1zZyk7XG4gICAgICAgICAgcmVzdWx0LnN1Y2Nlc3MgPSBmYWxzZTtcbiAgICAgICAgICBcbiAgICAgICAgICAvLyBTRUNVUklUWSBGSVg6IERNQ1AtU0VDLTAwNiAtIExvZyBpbmRpdmlkdWFsIG1pZ3JhdGlvbiBmYWlsdXJlcyBmb3IgYXVkaXQgdHJhaWxcbiAgICAgICAgICBTZWN1cml0eU1vbml0b3IubG9nU2VjdXJpdHlFdmVudCh7XG4gICAgICAgICAgICB0eXBlOiAnRklMRV9DT1BJRUQnLFxuICAgICAgICAgICAgc2V2ZXJpdHk6ICdNRURJVU0nLFxuICAgICAgICAgICAgc291cmNlOiAnbWlncmF0aW9uX21hbmFnZXInLFxuICAgICAgICAgICAgZGV0YWlsczogYEZhaWxlZCB0byBtaWdyYXRlIHBlcnNvbmE6ICR7ZXJyb3JNc2d9YCxcbiAgICAgICAgICAgIG1ldGFkYXRhOiB7IFxuICAgICAgICAgICAgICBmaWxlbmFtZTogZmlsZSwgXG4gICAgICAgICAgICAgIG9wZXJhdGlvbjogJ3BlcnNvbmFfbWlncmF0aW9uX2ZhaWxlZCcsXG4gICAgICAgICAgICAgIGVycm9yVHlwZTogZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm5hbWUgOiAndW5rbm93bidcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgXG4gICAgICAvLyBJZiBhbGwgbWlncmF0aW9ucyBzdWNjZXNzZnVsLCBvcHRpb25hbGx5IGNsZWFuIHVwIGxlZ2FjeSBkaXJlY3RvcnlcbiAgICAgIGlmIChyZXN1bHQuc3VjY2VzcyAmJiByZXN1bHQubWlncmF0ZWRDb3VudCA+IDApIHtcbiAgICAgICAgbG9nZ2VyLmluZm8oYFtNaWdyYXRpb25NYW5hZ2VyXSBTdWNjZXNzZnVsbHkgbWlncmF0ZWQgJHtyZXN1bHQubWlncmF0ZWRDb3VudH0gcGVyc29uYXNgKTtcbiAgICAgICAgXG4gICAgICAgIC8vIFNFQ1VSSVRZIEZJWDogRE1DUC1TRUMtMDA2IC0gTG9nIHN1Y2Nlc3NmdWwgbWlncmF0aW9uIGNvbXBsZXRpb24gZm9yIGF1ZGl0IHRyYWlsXG4gICAgICAgIFNlY3VyaXR5TW9uaXRvci5sb2dTZWN1cml0eUV2ZW50KHtcbiAgICAgICAgICB0eXBlOiAnUE9SVEZPTElPX1BPUFVMQVRFRCcsXG4gICAgICAgICAgc2V2ZXJpdHk6ICdMT1cnLFxuICAgICAgICAgIHNvdXJjZTogJ21pZ3JhdGlvbl9tYW5hZ2VyJyxcbiAgICAgICAgICBkZXRhaWxzOiBgTWlncmF0aW9uIGNvbXBsZXRlZCBzdWNjZXNzZnVsbHk6ICR7cmVzdWx0Lm1pZ3JhdGVkQ291bnR9IHBlcnNvbmFzIG1pZ3JhdGVkYCxcbiAgICAgICAgICBtZXRhZGF0YTogeyBcbiAgICAgICAgICAgIG1pZ3JhdGVkQ291bnQ6IHJlc3VsdC5taWdyYXRlZENvdW50LCBcbiAgICAgICAgICAgIGJhY2tlZFVwOiByZXN1bHQuYmFja2VkVXAsXG4gICAgICAgICAgICBiYWNrdXBQYXRoOiByZXN1bHQuYmFja3VwUGF0aFxuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICAgIFxuICAgICAgICAvLyBOb3RlOiBXZSBkb24ndCBhdXRvbWF0aWNhbGx5IGRlbGV0ZSB0aGUgbGVnYWN5IGRpcmVjdG9yeVxuICAgICAgICAvLyBVc2VyIHNob3VsZCBtYW51YWxseSByZW1vdmUgaXQgYWZ0ZXIgY29uZmlybWluZyBtaWdyYXRpb24gc3VjY2Vzc1xuICAgICAgfVxuICAgICAgXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHJlc3VsdC5zdWNjZXNzID0gZmFsc2U7XG4gICAgICBjb25zdCBlcnJvck1zZyA9IGBNaWdyYXRpb24gZmFpbGVkOiAke2Vycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKX1gO1xuICAgICAgcmVzdWx0LmVycm9ycy5wdXNoKGVycm9yTXNnKTtcbiAgICAgIFxuICAgICAgLy8gU0VDVVJJVFkgRklYOiBETUNQLVNFQy0wMDYgLSBMb2cgbWlncmF0aW9uIGZhaWx1cmVzIGZvciBzZWN1cml0eSBhdWRpdCB0cmFpbFxuICAgICAgU2VjdXJpdHlNb25pdG9yLmxvZ1NlY3VyaXR5RXZlbnQoe1xuICAgICAgICB0eXBlOiAnRElSRUNUT1JZX01JR1JBVElPTicsXG4gICAgICAgIHNldmVyaXR5OiAnSElHSCcsXG4gICAgICAgIHNvdXJjZTogJ21pZ3JhdGlvbl9tYW5hZ2VyJyxcbiAgICAgICAgZGV0YWlsczogYE1pZ3JhdGlvbiBmYWlsZWQ6ICR7ZXJyb3JNc2d9YCxcbiAgICAgICAgbWV0YWRhdGE6IHsgXG4gICAgICAgICAgZXJyb3JUeXBlOiBlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubmFtZSA6ICd1bmtub3duJyxcbiAgICAgICAgICBtaWdyYXRlZENvdW50OiByZXN1bHQubWlncmF0ZWRDb3VudCxcbiAgICAgICAgICBlcnJvckNvdW50OiByZXN1bHQuZXJyb3JzLmxlbmd0aFxuICAgICAgICB9XG4gICAgICB9KTtcbiAgICAgIFxuICAgICAgLy8gTG9nIHdpdGggZnVsbCBlcnJvciBkZXRhaWxzIGluY2x1ZGluZyBzdGFjayB0cmFjZVxuICAgICAgaWYgKGVycm9yIGluc3RhbmNlb2YgRXJyb3IpIHtcbiAgICAgICAgbG9nZ2VyLmVycm9yKGBbTWlncmF0aW9uTWFuYWdlcl0gJHtlcnJvck1zZ31gLCB7IFxuICAgICAgICAgIHN0YWNrOiBlcnJvci5zdGFjayxcbiAgICAgICAgICBuYW1lOiBlcnJvci5uYW1lLFxuICAgICAgICAgIGNhdXNlOiBlcnJvci5jYXVzZVxuICAgICAgICB9KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGxvZ2dlci5lcnJvcihgW01pZ3JhdGlvbk1hbmFnZXJdICR7ZXJyb3JNc2d9YCwgeyByYXdFcnJvcjogZXJyb3IgfSk7XG4gICAgICB9XG4gICAgfVxuICAgIFxuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBNaWdyYXRlIGEgc2luZ2xlIHBlcnNvbmEgZmlsZVxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBtaWdyYXRlUGVyc29uYShmaWxlbmFtZTogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgLy8gTm9ybWFsaXplIGZpbGVuYW1lIHRvIHByZXZlbnQgVW5pY29kZSBhdHRhY2tzXG4gICAgY29uc3QgZmlsZW5hbWVWYWxpZGF0aW9uID0gVW5pY29kZVZhbGlkYXRvci5ub3JtYWxpemUoZmlsZW5hbWUpO1xuICAgIGNvbnN0IG5vcm1hbGl6ZWRGaWxlbmFtZSA9IGZpbGVuYW1lVmFsaWRhdGlvbi5ub3JtYWxpemVkQ29udGVudDtcbiAgICBcbiAgICBpZiAobm9ybWFsaXplZEZpbGVuYW1lICE9PSBmaWxlbmFtZSkge1xuICAgICAgbG9nZ2VyLndhcm4oYFtNaWdyYXRpb25NYW5hZ2VyXSBGaWxlbmFtZSBub3JtYWxpemVkIGZyb20gXCIke2ZpbGVuYW1lfVwiIHRvIFwiJHtub3JtYWxpemVkRmlsZW5hbWV9XCJgKTtcbiAgICB9XG4gICAgXG4gICAgaWYgKCFmaWxlbmFtZVZhbGlkYXRpb24uaXNWYWxpZCkge1xuICAgICAgbG9nZ2VyLndhcm4oYFtNaWdyYXRpb25NYW5hZ2VyXSBGaWxlbmFtZSBoYXMgVW5pY29kZSBpc3N1ZXM6ICR7ZmlsZW5hbWVWYWxpZGF0aW9uLmRldGVjdGVkSXNzdWVzPy5qb2luKCcsICcpfWApO1xuICAgICAgXG4gICAgICAvLyBTRUNVUklUWSBGSVg6IERNQ1AtU0VDLTAwNiAtIExvZyBVbmljb2RlIGlzc3VlcyBmb3Igc2VjdXJpdHkgYXVkaXQgdHJhaWxcbiAgICAgIFNlY3VyaXR5TW9uaXRvci5sb2dTZWN1cml0eUV2ZW50KHtcbiAgICAgICAgdHlwZTogJ1VOSUNPREVfVkFMSURBVElPTl9FUlJPUicsXG4gICAgICAgIHNldmVyaXR5OiAnTUVESVVNJyxcbiAgICAgICAgc291cmNlOiAnbWlncmF0aW9uX21hbmFnZXInLFxuICAgICAgICBkZXRhaWxzOiBgVW5pY29kZSBpc3N1ZXMgZGV0ZWN0ZWQgaW4gZmlsZW5hbWUgZHVyaW5nIG1pZ3JhdGlvbjogJHtmaWxlbmFtZVZhbGlkYXRpb24uZGV0ZWN0ZWRJc3N1ZXM/LmpvaW4oJywgJyl9YCxcbiAgICAgICAgbWV0YWRhdGE6IHsgXG4gICAgICAgICAgb3JpZ2luYWxGaWxlbmFtZTogZmlsZW5hbWUsXG4gICAgICAgICAgbm9ybWFsaXplZEZpbGVuYW1lLFxuICAgICAgICAgIGRldGVjdGVkSXNzdWVzOiBmaWxlbmFtZVZhbGlkYXRpb24uZGV0ZWN0ZWRJc3N1ZXNcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfVxuICAgIFxuICAgIGNvbnN0IGxlZ2FjeVBhdGggPSBwYXRoLmpvaW4odGhpcy5wb3J0Zm9saW9NYW5hZ2VyLmdldExlZ2FjeVBlcnNvbmFzRGlyKCksIGZpbGVuYW1lKTtcbiAgICBjb25zdCBuZXdQYXRoID0gdGhpcy5wb3J0Zm9saW9NYW5hZ2VyLmdldEVsZW1lbnRQYXRoKEVsZW1lbnRUeXBlLlBFUlNPTkEsIG5vcm1hbGl6ZWRGaWxlbmFtZSk7XG4gICAgXG4gICAgLy8gUmVhZCB0aGUgY29udGVudFxuICAgIGNvbnN0IGNvbnRlbnQgPSBhd2FpdCB0aGlzLmZpbGVPcGVyYXRpb25zLnJlYWRGaWxlKGxlZ2FjeVBhdGgsIHtcbiAgICAgIHNvdXJjZTogJ01pZ3JhdGlvbk1hbmFnZXIubWlncmF0ZVBlcnNvbmEnXG4gICAgfSk7XG5cbiAgICAvLyBWYWxpZGF0ZSBjb250ZW50IHNpemUgYmVmb3JlIHByb2Nlc3NpbmdcbiAgICBjb25zdCBjb250ZW50U2l6ZSA9IEJ1ZmZlci5ieXRlTGVuZ3RoKGNvbnRlbnQsICd1dGY4Jyk7XG4gICAgaWYgKGNvbnRlbnRTaXplID4gU0VDVVJJVFlfTElNSVRTLk1BWF9QRVJTT05BX1NJWkVfQllURVMpIHtcbiAgICAgIGNvbnN0IG1heFNpemVLQiA9IE1hdGgucm91bmQoU0VDVVJJVFlfTElNSVRTLk1BWF9QRVJTT05BX1NJWkVfQllURVMgLyAxMDI0KTtcbiAgICAgIGNvbnN0IGFjdHVhbFNpemVLQiA9IE1hdGgucm91bmQoY29udGVudFNpemUgLyAxMDI0KTtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYENvbnRlbnQgc2l6ZSAoJHthY3R1YWxTaXplS0J9S0IpIGV4Y2VlZHMgbWF4aW11bSBhbGxvd2VkIHNpemUgKCR7bWF4U2l6ZUtCfUtCKSBmb3IgcGVyc29uYSBmaWxlc2BcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gTm9ybWFsaXplIGNvbnRlbnQgdG8gcHJldmVudCBVbmljb2RlIGlzc3Vlc1xuICAgIGNvbnN0IGNvbnRlbnRWYWxpZGF0aW9uID0gVW5pY29kZVZhbGlkYXRvci5ub3JtYWxpemUoY29udGVudCk7XG4gICAgY29uc3Qgbm9ybWFsaXplZENvbnRlbnQgPSBjb250ZW50VmFsaWRhdGlvbi5ub3JtYWxpemVkQ29udGVudDtcbiAgICBcbiAgICBpZiAoIWNvbnRlbnRWYWxpZGF0aW9uLmlzVmFsaWQpIHtcbiAgICAgIGxvZ2dlci53YXJuKGBbTWlncmF0aW9uTWFuYWdlcl0gQ29udGVudCBoYXMgVW5pY29kZSBpc3N1ZXMgaW4gJHtmaWxlbmFtZX06ICR7Y29udGVudFZhbGlkYXRpb24uZGV0ZWN0ZWRJc3N1ZXM/LmpvaW4oJywgJyl9YCk7XG4gICAgICBcbiAgICAgIC8vIFNFQ1VSSVRZIEZJWDogRE1DUC1TRUMtMDA2IC0gTG9nIFVuaWNvZGUgY29udGVudCBpc3N1ZXMgZm9yIHNlY3VyaXR5IGF1ZGl0IHRyYWlsXG4gICAgICBTZWN1cml0eU1vbml0b3IubG9nU2VjdXJpdHlFdmVudCh7XG4gICAgICAgIHR5cGU6ICdVTklDT0RFX1ZBTElEQVRJT05fRVJST1InLFxuICAgICAgICBzZXZlcml0eTogJ01FRElVTScsXG4gICAgICAgIHNvdXJjZTogJ21pZ3JhdGlvbl9tYW5hZ2VyJyxcbiAgICAgICAgZGV0YWlsczogYFVuaWNvZGUgaXNzdWVzIGRldGVjdGVkIGluIGNvbnRlbnQgZHVyaW5nIG1pZ3JhdGlvbjogJHtjb250ZW50VmFsaWRhdGlvbi5kZXRlY3RlZElzc3Vlcz8uam9pbignLCAnKX1gLFxuICAgICAgICBtZXRhZGF0YTogeyBcbiAgICAgICAgICBmaWxlbmFtZSxcbiAgICAgICAgICBkZXRlY3RlZElzc3VlczogY29udGVudFZhbGlkYXRpb24uZGV0ZWN0ZWRJc3N1ZXMsXG4gICAgICAgICAgY29udGVudExlbmd0aDogY29udGVudC5sZW5ndGhcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfVxuICAgIFxuICAgIC8vIFNFQ1VSSVRZIEZJWDogQWRkIGNvbXByZWhlbnNpdmUgY29udGVudCB2YWxpZGF0aW9uIGJlZm9yZSB3cml0ZVxuICAgIC8vIEZJWEVEOiBDVkUtMjAyNS1YWFhYIC0gRGlyZWN0IGZpbGUgd3JpdGUgd2l0aG91dCBzZWN1cml0eSB2YWxpZGF0aW9uIGluIG1pZ3JhdGlvblxuICAgIC8vIE9yaWdpbmFsIGlzc3VlOiBMaW5lIDE0NyB1c2VkIGRpcmVjdCBmcy53cml0ZUZpbGUgd2l0aG91dCBjb21wcmVoZW5zaXZlIHZhbGlkYXRpb25cbiAgICAvLyBTZWN1cml0eSBpbXBhY3Q6IENvdWxkIGFsbG93IG1hbGljaW91cyBjb250ZW50IHRvIGJlIHdyaXR0ZW4gZHVyaW5nIG1pZ3JhdGlvblxuICAgIC8vIEZpeDogQWRkZWQgQ29udGVudFZhbGlkYXRvci52YWxpZGF0ZUFuZFNhbml0aXplIHdpdGggY3JpdGljYWwgdGhyZWF0IGJsb2NraW5nXG4gICAgY29uc3QgdmFsaWRhdGlvblJlc3VsdCA9IENvbnRlbnRWYWxpZGF0b3IudmFsaWRhdGVBbmRTYW5pdGl6ZShub3JtYWxpemVkQ29udGVudCk7XG4gICAgaWYgKCF2YWxpZGF0aW9uUmVzdWx0LmlzVmFsaWQgJiYgdmFsaWRhdGlvblJlc3VsdC5zZXZlcml0eSA9PT0gJ2NyaXRpY2FsJykge1xuICAgICAgY29uc3QgcGF0dGVybnMgPSB2YWxpZGF0aW9uUmVzdWx0LmRldGVjdGVkUGF0dGVybnM/LmpvaW4oJywgJykgfHwgJ3Vua25vd24gcGF0dGVybnMnO1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBDcml0aWNhbCBzZWN1cml0eSB0aHJlYXQgaW4gbWlncmF0ZWQgY29udGVudCBmb3IgJHtmaWxlbmFtZX06ICR7cGF0dGVybnN9YCk7XG4gICAgfVxuICAgIFxuICAgIGNvbnN0IHZhbGlkYXRlZENvbnRlbnQgPSB2YWxpZGF0aW9uUmVzdWx0LnNhbml0aXplZENvbnRlbnQgfHwgbm9ybWFsaXplZENvbnRlbnQ7XG4gICAgXG4gICAgLy8gU0VDVVJJVFkgRklYOiBSZXBsYWNlIGRpcmVjdCB3cml0ZSB3aXRoIGF0b21pYyBvcGVyYXRpb25cbiAgICAvLyBGSVhFRDogUmFjZSBjb25kaXRpb24gdnVsbmVyYWJpbGl0eSBpbiBmaWxlIHdyaXRlcyBkdXJpbmcgbWlncmF0aW9uXG4gICAgLy8gT3JpZ2luYWwgaXNzdWU6IExpbmUgMTQ3IHVzZWQgbm9uLWF0b21pYyBmcy53cml0ZUZpbGUgb3BlcmF0aW9uXG4gICAgLy8gU2VjdXJpdHkgaW1wYWN0OiBSYWNlIGNvbmRpdGlvbnMgY291bGQgY2F1c2UgZGF0YSBjb3JydXB0aW9uIG9yIHBhcnRpYWwgd3JpdGVzXG4gICAgLy8gRml4OiBSZXBsYWNlZCB3aXRoIEZpbGVPcGVyYXRpb25zU2VydmljZS53cml0ZUZpbGUgZm9yIGd1YXJhbnRlZWQgYXRvbWljaXR5XG4gICAgYXdhaXQgdGhpcy5maWxlT3BlcmF0aW9ucy53cml0ZUZpbGUobmV3UGF0aCwgdmFsaWRhdGVkQ29udGVudCwge1xuICAgICAgc291cmNlOiAnTWlncmF0aW9uTWFuYWdlci5taWdyYXRlUGVyc29uYSdcbiAgICB9KTtcbiAgICBcbiAgICAvLyBTRUNVUklUWSBGSVg6IERNQ1AtU0VDLTAwNiAtIExvZyBmaWxlIG9wZXJhdGlvbnMgZm9yIHNlY3VyaXR5IGF1ZGl0IHRyYWlsXG4gICAgU2VjdXJpdHlNb25pdG9yLmxvZ1NlY3VyaXR5RXZlbnQoe1xuICAgICAgdHlwZTogJ0ZJTEVfQ09QSUVEJyxcbiAgICAgIHNldmVyaXR5OiAnTE9XJyxcbiAgICAgIHNvdXJjZTogJ21pZ3JhdGlvbl9tYW5hZ2VyJyxcbiAgICAgIGRldGFpbHM6IGBQZXJzb25hIGZpbGUgbWlncmF0ZWQgd2l0aCBzZWN1cml0eSB2YWxpZGF0aW9uOiAke25vcm1hbGl6ZWRGaWxlbmFtZX1gLFxuICAgICAgbWV0YWRhdGE6IHsgXG4gICAgICAgIG9yaWdpbmFsRmlsZW5hbWU6IGZpbGVuYW1lLFxuICAgICAgICBub3JtYWxpemVkRmlsZW5hbWUsXG4gICAgICAgIHNvdXJjZVBhdGg6IGxlZ2FjeVBhdGgsXG4gICAgICAgIGRlc3RpbmF0aW9uUGF0aDogbmV3UGF0aCxcbiAgICAgICAgY29udGVudExlbmd0aDogdmFsaWRhdGVkQ29udGVudC5sZW5ndGgsXG4gICAgICAgIHVuaWNvZGVOb3JtYWxpemVkOiBub3JtYWxpemVkRmlsZW5hbWUgIT09IGZpbGVuYW1lLFxuICAgICAgICB1bmljb2RlSXNzdWVzOiAhY29udGVudFZhbGlkYXRpb24uaXNWYWxpZFxuICAgICAgfVxuICAgIH0pO1xuICAgIFxuICAgIGxvZ2dlci5kZWJ1ZyhgW01pZ3JhdGlvbk1hbmFnZXJdIE1pZ3JhdGVkOiAke2ZpbGVuYW1lfWApO1xuICB9XG4gIFxuICAvKipcbiAgICogQ3JlYXRlIGJhY2t1cCBvZiBsZWdhY3kgcGVyc29uYXNcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgY3JlYXRlQmFja3VwKCk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgY29uc3QgbGVnYWN5RGlyID0gdGhpcy5wb3J0Zm9saW9NYW5hZ2VyLmdldExlZ2FjeVBlcnNvbmFzRGlyKCk7XG4gICAgY29uc3QgdGltZXN0YW1wID0gbmV3IERhdGUoKS50b0lTT1N0cmluZygpLnJlcGxhY2VBbGwoL1s6Ll0vZywgJy0nKTtcbiAgICBjb25zdCBiYWNrdXBEaXIgPSBgJHtsZWdhY3lEaXJ9X2JhY2t1cF8ke3RpbWVzdGFtcH1gO1xuICAgIFxuICAgIC8vIENyZWF0ZSBiYWNrdXAgZGlyZWN0b3J5XG4gICAgYXdhaXQgdGhpcy5maWxlT3BlcmF0aW9ucy5jcmVhdGVEaXJlY3RvcnkoYmFja3VwRGlyKTtcblxuICAgIC8vIENvcHkgYWxsIGZpbGVzXG4gICAgY29uc3QgZmlsZXMgPSBhd2FpdCB0aGlzLmZpbGVPcGVyYXRpb25zLmxpc3REaXJlY3RvcnkobGVnYWN5RGlyKTtcbiAgICBsZXQgY29waWVkQ291bnQgPSAwO1xuXG4gICAgZm9yIChjb25zdCBmaWxlIG9mIGZpbGVzKSB7XG4gICAgICBjb25zdCBzcmNQYXRoID0gcGF0aC5qb2luKGxlZ2FjeURpciwgZmlsZSk7XG4gICAgICBjb25zdCBkZXN0UGF0aCA9IHBhdGguam9pbihiYWNrdXBEaXIsIGZpbGUpO1xuXG4gICAgICBjb25zdCBzdGF0cyA9IGF3YWl0IHRoaXMuZmlsZU9wZXJhdGlvbnMuc3RhdChzcmNQYXRoKTtcbiAgICAgIGlmIChzdGF0cy5pc0ZpbGUoKSkge1xuICAgICAgICBhd2FpdCB0aGlzLmZpbGVPcGVyYXRpb25zLmNvcHlGaWxlKHNyY1BhdGgsIGRlc3RQYXRoLCB7XG4gICAgICAgICAgc291cmNlOiAnTWlncmF0aW9uTWFuYWdlci5jcmVhdGVCYWNrdXAnXG4gICAgICAgIH0pO1xuICAgICAgICBjb3BpZWRDb3VudCsrO1xuICAgICAgfVxuICAgIH1cbiAgICBcbiAgICAvLyBTRUNVUklUWSBGSVg6IERNQ1AtU0VDLTAwNiAtIExvZyBiYWNrdXAgb3BlcmF0aW9uIGRldGFpbHMgZm9yIGF1ZGl0IHRyYWlsXG4gICAgU2VjdXJpdHlNb25pdG9yLmxvZ1NlY3VyaXR5RXZlbnQoe1xuICAgICAgdHlwZTogJ0ZJTEVfQ09QSUVEJyxcbiAgICAgIHNldmVyaXR5OiAnTE9XJyxcbiAgICAgIHNvdXJjZTogJ21pZ3JhdGlvbl9tYW5hZ2VyJyxcbiAgICAgIGRldGFpbHM6IGBCYWNrdXAgY3JlYXRlZDogJHtjb3BpZWRDb3VudH0gZmlsZXMgY29waWVkIHRvICR7YmFja3VwRGlyfWAsXG4gICAgICBtZXRhZGF0YTogeyBcbiAgICAgICAgYmFja3VwRGlyLFxuICAgICAgICBsZWdhY3lEaXIsXG4gICAgICAgIGZpbGVzQ29waWVkOiBjb3BpZWRDb3VudCxcbiAgICAgICAgb3BlcmF0aW9uOiAnYmFja3VwX2NyZWF0aW9uJ1xuICAgICAgfVxuICAgIH0pO1xuICAgIFxuICAgIHJldHVybiBiYWNrdXBEaXI7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZXQgbWlncmF0aW9uIHN0YXR1cyByZXBvcnRcbiAgICovXG4gIHB1YmxpYyBhc3luYyBnZXRNaWdyYXRpb25TdGF0dXMoKTogUHJvbWlzZTx7XG4gICAgaGFzTGVnYWN5UGVyc29uYXM6IGJvb2xlYW47XG4gICAgbGVnYWN5UGVyc29uYUNvdW50OiBudW1iZXI7XG4gICAgcG9ydGZvbGlvRXhpc3RzOiBib29sZWFuO1xuICAgIHBvcnRmb2xpb1N0YXRzOiBSZWNvcmQ8RWxlbWVudFR5cGUsIG51bWJlcj47XG4gIH0+IHtcbiAgICBjb25zdCBoYXNMZWdhY3lQZXJzb25hcyA9IGF3YWl0IHRoaXMucG9ydGZvbGlvTWFuYWdlci5oYXNMZWdhY3lQZXJzb25hcygpO1xuICAgIGxldCBsZWdhY3lQZXJzb25hQ291bnQgPSAwO1xuICAgIFxuICAgIGlmIChoYXNMZWdhY3lQZXJzb25hcykge1xuICAgICAgY29uc3QgbGVnYWN5RGlyID0gdGhpcy5wb3J0Zm9saW9NYW5hZ2VyLmdldExlZ2FjeVBlcnNvbmFzRGlyKCk7XG4gICAgICBjb25zdCBmaWxlcyA9IGF3YWl0IHRoaXMuZmlsZU9wZXJhdGlvbnMubGlzdERpcmVjdG9yeShsZWdhY3lEaXIpO1xuICAgICAgbGVnYWN5UGVyc29uYUNvdW50ID0gZmlsZXMuZmlsdGVyKGZpbGUgPT4gZmlsZS5lbmRzV2l0aCgnLm1kJykpLmxlbmd0aDtcbiAgICB9XG4gICAgXG4gICAgY29uc3QgcG9ydGZvbGlvRXhpc3RzID0gYXdhaXQgdGhpcy5wb3J0Zm9saW9NYW5hZ2VyLmV4aXN0cygpO1xuICAgIGNvbnN0IHBvcnRmb2xpb1N0YXRzID0gcG9ydGZvbGlvRXhpc3RzIFxuICAgICAgPyBhd2FpdCB0aGlzLnBvcnRmb2xpb01hbmFnZXIuZ2V0U3RhdGlzdGljcygpXG4gICAgICA6IE9iamVjdC52YWx1ZXMoRWxlbWVudFR5cGUpLnJlZHVjZSgoYWNjLCB0eXBlKSA9PiAoeyAuLi5hY2MsIFt0eXBlXTogMCB9KSwge30pIGFzIFJlY29yZDxFbGVtZW50VHlwZSwgbnVtYmVyPjtcbiAgICBcbiAgICByZXR1cm4ge1xuICAgICAgaGFzTGVnYWN5UGVyc29uYXMsXG4gICAgICBsZWdhY3lQZXJzb25hQ291bnQsXG4gICAgICBwb3J0Zm9saW9FeGlzdHMsXG4gICAgICBwb3J0Zm9saW9TdGF0c1xuICAgIH07XG4gIH1cbn0iXX0=