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.

255 lines 39.1 kB
import { promises as fs } from 'fs'; import * as path from 'path'; import { SecurityMonitor } from '../security/securityMonitor.js'; import { logger } from '../utils/logger.js'; import { validatePath } from '../security/InputValidator.js'; export class FileOperationsService { fileLockManager; defaultMaxFileSize; config; constructor(fileLockManager, config) { this.fileLockManager = fileLockManager; this.config = config ?? { verboseAudit: false }; this.defaultMaxFileSize = config?.maxFileSize ?? (10 * 1024 * 1024); // 10MB default } async readFile(filePath, options = {}) { try { const content = await this.fileLockManager.atomicReadFile(filePath, { encoding: options.encoding ?? 'utf-8' }); const maxSize = options.maxSize ?? this.defaultMaxFileSize; if (content.length > maxSize) { throw new Error(`File exceeds maximum size of ${maxSize} bytes`); } return content; } catch (error) { if (error.code === 'ENOENT') { logger.debug(`File not found: ${filePath}`); } else { logger.error(`Failed to read file: ${filePath}`, error); } throw error; } } async readElementFile(filePath, elementType, options = {}) { const content = await this.readFile(filePath, options); // Log security event for element access when verbose audit is enabled // This is configurable to avoid log spam in production while allowing // detailed audit trails when needed (e.g., for compliance or debugging) if (this.config.verboseAudit) { SecurityMonitor.logSecurityEvent({ type: 'FILE_READ', severity: 'LOW', source: options.source ?? 'FileOperationsService.readElementFile', details: `Read ${elementType} file: ${path.basename(filePath)}` }); } return content; } async writeFile(filePath, content, options = {}) { try { const maxSize = options.maxSize ?? this.defaultMaxFileSize; if (content.length > maxSize) { throw new Error(`Content exceeds maximum size of ${maxSize} bytes`); } await this.fileLockManager.atomicWriteFile(filePath, content, { encoding: options.encoding ?? 'utf-8' }); SecurityMonitor.logSecurityEvent({ type: 'FILE_WRITTEN', severity: 'LOW', source: options.source ?? 'FileOperationsService.writeFile', details: `File written successfully: ${path.basename(filePath)}` }); } catch (error) { logger.error(`Failed to write file: ${filePath}`, error); throw error; } } async deleteFile(filePath, elementType, options = {}) { try { await fs.unlink(filePath); if (elementType) { SecurityMonitor.logSecurityEvent({ type: 'FILE_DELETED', severity: 'MEDIUM', source: options.source ?? 'FileOperationsService.deleteFile', details: `Deleted ${elementType} file: ${path.basename(filePath)}` }); } } catch (error) { if (error.code === 'ENOENT') { // File doesn't exist, which is fine for delete return; } logger.error(`Failed to delete file: ${filePath}`, error); throw error; } } async createDirectory(directoryPath) { try { await fs.mkdir(directoryPath, { recursive: true }); } catch (error) { logger.error(`Failed to create directory: ${directoryPath}`, error); throw error; } } async exists(filePath) { try { await fs.access(filePath); return true; } catch { return false; } } /** * Get file statistics * @param filePath - Absolute path to the file * @returns File statistics */ async stat(filePath) { return await fs.stat(filePath); } async listDirectory(directoryPath) { try { return await fs.readdir(directoryPath); } catch (error) { logger.error(`Failed to list directory: ${directoryPath}`, error); throw error; } } async listDirectoryWithTypes(directoryPath) { try { const entries = await fs.readdir(directoryPath, { withFileTypes: true }); return entries.map(entry => ({ name: entry.name, isDirectory: entry.isDirectory(), isFile: entry.isFile() })); } catch (error) { logger.error(`Failed to list directory with types: ${directoryPath}`, error); throw error; } } async renameFile(oldPath, newPath) { try { await fs.rename(oldPath, newPath); } catch (error) { logger.error(`Failed to rename file from ${oldPath} to ${newPath}`, error); throw error; } } resolvePath(relativePath, baseDirectory) { // Use the existing validatePath utility which handles resolution and traversal checks // But here we just want resolution + validation try { // validatePath from InputValidator throws if invalid validatePath(relativePath, baseDirectory); return path.resolve(baseDirectory, relativePath); } catch (error) { throw new Error(`Invalid path resolution: ${error instanceof Error ? error.message : 'Unknown error'}`); } } validatePath(filePath, baseDirectory) { try { validatePath(filePath, baseDirectory); return true; } catch { return false; } } async createFileExclusive(filePath, content, options = {}) { try { const maxSize = options.maxSize ?? this.defaultMaxFileSize; if (content.length > maxSize) { throw new Error(`Content exceeds maximum size of ${maxSize} bytes`); } // Use 'wx' flag for atomic creation - fails if file already exists // This prevents TOCTOU race conditions const fileHandle = await fs.open(filePath, 'wx'); try { await fileHandle.writeFile(content, { encoding: options.encoding ?? 'utf-8' }); } finally { await fileHandle.close(); } SecurityMonitor.logSecurityEvent({ type: 'FILE_WRITTEN', severity: 'LOW', source: options.source ?? 'FileOperationsService.createFileExclusive', details: `File created exclusively: ${path.basename(filePath)}` }); return true; } catch (error) { if (error.code === 'EEXIST') { // File already exists - this is expected in race condition scenarios return false; } logger.error(`Failed to create file exclusively: ${filePath}`, error); throw error; } } async copyFile(sourcePath, destPath, options = {}) { try { // Ensure destination directory exists await this.createDirectory(path.dirname(destPath)); await fs.copyFile(sourcePath, destPath); SecurityMonitor.logSecurityEvent({ type: 'FILE_WRITTEN', severity: 'LOW', source: options.source ?? 'FileOperationsService.copyFile', details: `File copied: ${path.basename(sourcePath)} -> ${path.basename(destPath)}` }); } catch (error) { logger.error(`Failed to copy file from ${sourcePath} to ${destPath}`, error); throw error; } } async chmod(filePath, mode, options = {}) { try { await fs.chmod(filePath, mode); SecurityMonitor.logSecurityEvent({ type: 'FILE_WRITTEN', severity: 'LOW', source: options.source ?? 'FileOperationsService.chmod', details: `File permissions changed: ${path.basename(filePath)} to ${mode.toString(8)}` }); } catch (error) { logger.error(`Failed to change permissions for ${filePath}`, error); throw error; } } async appendFile(filePath, content, options = {}) { try { await fs.appendFile(filePath, content, { encoding: options.encoding ?? 'utf-8' }); // Only log if verbose audit is enabled to avoid log spam for telemetry if (this.config.verboseAudit) { SecurityMonitor.logSecurityEvent({ type: 'FILE_WRITTEN', severity: 'LOW', source: options.source ?? 'FileOperationsService.appendFile', details: `Content appended to file: ${path.basename(filePath)}` }); } } catch (error) { logger.error(`Failed to append to file: ${filePath}`, error); throw error; } } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRmlsZU9wZXJhdGlvbnNTZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3NlcnZpY2VzL0ZpbGVPcGVyYXRpb25zU2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsUUFBUSxJQUFJLEVBQUUsRUFBUyxNQUFNLElBQUksQ0FBQztBQUMzQyxPQUFPLEtBQUssSUFBSSxNQUFNLE1BQU0sQ0FBQztBQUU3QixPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFDakUsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBRTVDLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQztBQW9KN0QsTUFBTSxPQUFPLHFCQUFxQjtJQUN4QixlQUFlLENBQWtCO0lBQ3hCLGtCQUFrQixDQUFTO0lBQ3BDLE1BQU0sQ0FBdUI7SUFFckMsWUFBWSxlQUFnQyxFQUFFLE1BQTZCO1FBQ3pFLElBQUksQ0FBQyxlQUFlLEdBQUcsZUFBZSxDQUFDO1FBQ3ZDLElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxJQUFJLEVBQUUsWUFBWSxFQUFFLEtBQUssRUFBRSxDQUFDO1FBQ2hELElBQUksQ0FBQyxrQkFBa0IsR0FBRyxNQUFNLEVBQUUsV0FBVyxJQUFJLENBQUMsRUFBRSxHQUFHLElBQUksR0FBRyxJQUFJLENBQUMsQ0FBQyxDQUFDLGVBQWU7SUFDdEYsQ0FBQztJQUVELEtBQUssQ0FBQyxRQUFRLENBQUMsUUFBZ0IsRUFBRSxVQUEyQixFQUFFO1FBQzVELElBQUksQ0FBQztZQUNILE1BQU0sT0FBTyxHQUFHLE1BQU0sSUFBSSxDQUFDLGVBQWUsQ0FBQyxjQUFjLENBQUMsUUFBUSxFQUFFO2dCQUNsRSxRQUFRLEVBQUUsT0FBTyxDQUFDLFFBQVEsSUFBSSxPQUFPO2FBQ3RDLENBQUMsQ0FBQztZQUVILE1BQU0sT0FBTyxHQUFHLE9BQU8sQ0FBQyxPQUFPLElBQUksSUFBSSxDQUFDLGtCQUFrQixDQUFDO1lBQzNELElBQUksT0FBTyxDQUFDLE1BQU0sR0FBRyxPQUFPLEVBQUUsQ0FBQztnQkFDN0IsTUFBTSxJQUFJLEtBQUssQ0FBQyxnQ0FBZ0MsT0FBTyxRQUFRLENBQUMsQ0FBQztZQUNuRSxDQUFDO1lBRUQsT0FBTyxPQUFPLENBQUM7UUFDakIsQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixJQUFLLEtBQStCLENBQUMsSUFBSSxLQUFLLFFBQVEsRUFBRSxDQUFDO2dCQUN2RCxNQUFNLENBQUMsS0FBSyxDQUFDLG1CQUFtQixRQUFRLEVBQUUsQ0FBQyxDQUFDO1lBQzlDLENBQUM7aUJBQU0sQ0FBQztnQkFDTixNQUFNLENBQUMsS0FBSyxDQUFDLHdCQUF3QixRQUFRLEVBQUUsRUFBRSxLQUFLLENBQUMsQ0FBQztZQUMxRCxDQUFDO1lBQ0QsTUFBTSxLQUFLLENBQUM7UUFDZCxDQUFDO0lBQ0gsQ0FBQztJQUVELEtBQUssQ0FBQyxlQUFlLENBQUMsUUFBZ0IsRUFBRSxXQUF3QixFQUFFLFVBQTJCLEVBQUU7UUFDN0YsTUFBTSxPQUFPLEdBQUcsTUFBTSxJQUFJLENBQUMsUUFBUSxDQUFDLFFBQVEsRUFBRSxPQUFPLENBQUMsQ0FBQztRQUV2RCxzRUFBc0U7UUFDdEUsc0VBQXNFO1FBQ3RFLHdFQUF3RTtRQUN4RSxJQUFJLElBQUksQ0FBQyxNQUFNLENBQUMsWUFBWSxFQUFFLENBQUM7WUFDN0IsZUFBZSxDQUFDLGdCQUFnQixDQUFDO2dCQUMvQixJQUFJLEVBQUUsV0FBVztnQkFDakIsUUFBUSxFQUFFLEtBQUs7Z0JBQ2YsTUFBTSxFQUFFLE9BQU8sQ0FBQyxNQUFNLElBQUksdUNBQXVDO2dCQUNqRSxPQUFPLEVBQUUsUUFBUSxXQUFXLFVBQVUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsRUFBRTthQUNoRSxDQUFDLENBQUM7UUFDTCxDQUFDO1FBRUQsT0FBTyxPQUFPLENBQUM7SUFDakIsQ0FBQztJQUVELEtBQUssQ0FBQyxTQUFTLENBQUMsUUFBZ0IsRUFBRSxPQUFlLEVBQUUsVUFBNEIsRUFBRTtRQUMvRSxJQUFJLENBQUM7WUFDSCxNQUFNLE9BQU8sR0FBRyxPQUFPLENBQUMsT0FBTyxJQUFJLElBQUksQ0FBQyxrQkFBa0IsQ0FBQztZQUMzRCxJQUFJLE9BQU8sQ0FBQyxNQUFNLEdBQUcsT0FBTyxFQUFFLENBQUM7Z0JBQzdCLE1BQU0sSUFBSSxLQUFLLENBQUMsbUNBQW1DLE9BQU8sUUFBUSxDQUFDLENBQUM7WUFDdEUsQ0FBQztZQUVELE1BQU0sSUFBSSxDQUFDLGVBQWUsQ0FBQyxlQUFlLENBQUMsUUFBUSxFQUFFLE9BQU8sRUFBRTtnQkFDNUQsUUFBUSxFQUFFLE9BQU8sQ0FBQyxRQUFRLElBQUksT0FBTzthQUN0QyxDQUFDLENBQUM7WUFFSCxlQUFlLENBQUMsZ0JBQWdCLENBQUM7Z0JBQy9CLElBQUksRUFBRSxjQUFjO2dCQUNwQixRQUFRLEVBQUUsS0FBSztnQkFDZixNQUFNLEVBQUUsT0FBTyxDQUFDLE1BQU0sSUFBSSxpQ0FBaUM7Z0JBQzNELE9BQU8sRUFBRSw4QkFBOEIsSUFBSSxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsRUFBRTthQUNqRSxDQUFDLENBQUM7UUFDTCxDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNmLE1BQU0sQ0FBQyxLQUFLLENBQUMseUJBQXlCLFFBQVEsRUFBRSxFQUFFLEtBQUssQ0FBQyxDQUFDO1lBQ3pELE1BQU0sS0FBSyxDQUFDO1FBQ2QsQ0FBQztJQUNILENBQUM7SUFFRCxLQUFLLENBQUMsVUFBVSxDQUFDLFFBQWdCLEVBQUUsV0FBeUIsRUFBRSxVQUFnQyxFQUFFO1FBQzlGLElBQUksQ0FBQztZQUNILE1BQU0sRUFBRSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQztZQUUxQixJQUFJLFdBQVcsRUFBRSxDQUFDO2dCQUNoQixlQUFlLENBQUMsZ0JBQWdCLENBQUM7b0JBQy9CLElBQUksRUFBRSxjQUFjO29CQUNwQixRQUFRLEVBQUUsUUFBUTtvQkFDbEIsTUFBTSxFQUFFLE9BQU8sQ0FBQyxNQUFNLElBQUksa0NBQWtDO29CQUM1RCxPQUFPLEVBQUUsV0FBVyxXQUFXLFVBQVUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsRUFBRTtpQkFDbkUsQ0FBQyxDQUFDO1lBQ0wsQ0FBQztRQUNILENBQUM7UUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1lBQ2YsSUFBSyxLQUErQixDQUFDLElBQUksS0FBSyxRQUFRLEVBQUUsQ0FBQztnQkFDdkQsK0NBQStDO2dCQUMvQyxPQUFPO1lBQ1QsQ0FBQztZQUNELE1BQU0sQ0FBQyxLQUFLLENBQUMsMEJBQTBCLFFBQVEsRUFBRSxFQUFFLEtBQUssQ0FBQyxDQUFDO1lBQzFELE1BQU0sS0FBSyxDQUFDO1FBQ2QsQ0FBQztJQUNILENBQUM7SUFFRCxLQUFLLENBQUMsZUFBZSxDQUFDLGFBQXFCO1FBQ3pDLElBQUksQ0FBQztZQUNILE1BQU0sRUFBRSxDQUFDLEtBQUssQ0FBQyxhQUFhLEVBQUUsRUFBRSxTQUFTLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztRQUNyRCxDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNmLE1BQU0sQ0FBQyxLQUFLLENBQUMsK0JBQStCLGFBQWEsRUFBRSxFQUFFLEtBQUssQ0FBQyxDQUFDO1lBQ3BFLE1BQU0sS0FBSyxDQUFDO1FBQ2QsQ0FBQztJQUNILENBQUM7SUFFRCxLQUFLLENBQUMsTUFBTSxDQUFDLFFBQWdCO1FBQzNCLElBQUksQ0FBQztZQUNILE1BQU0sRUFBRSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQztZQUMxQixPQUFPLElBQUksQ0FBQztRQUNkLENBQUM7UUFBQyxNQUFNLENBQUM7WUFDUCxPQUFPLEtBQUssQ0FBQztRQUNmLENBQUM7SUFDSCxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILEtBQUssQ0FBQyxJQUFJLENBQUMsUUFBZ0I7UUFDekIsT0FBTyxNQUFNLEVBQUUsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDakMsQ0FBQztJQUVELEtBQUssQ0FBQyxhQUFhLENBQUMsYUFBcUI7UUFDdkMsSUFBSSxDQUFDO1lBQ0gsT0FBTyxNQUFNLEVBQUUsQ0FBQyxPQUFPLENBQUMsYUFBYSxDQUFDLENBQUM7UUFDekMsQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixNQUFNLENBQUMsS0FBSyxDQUFDLDZCQUE2QixhQUFhLEVBQUUsRUFBRSxLQUFLLENBQUMsQ0FBQztZQUNsRSxNQUFNLEtBQUssQ0FBQztRQUNkLENBQUM7SUFDSCxDQUFDO0lBRUQsS0FBSyxDQUFDLHNCQUFzQixDQUFDLGFBQXFCO1FBQ2hELElBQUksQ0FBQztZQUNILE1BQU0sT0FBTyxHQUFHLE1BQU0sRUFBRSxDQUFDLE9BQU8sQ0FBQyxhQUFhLEVBQUUsRUFBRSxhQUFhLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztZQUN6RSxPQUFPLE9BQU8sQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDO2dCQUMzQixJQUFJLEVBQUUsS0FBSyxDQUFDLElBQUk7Z0JBQ2hCLFdBQVcsRUFBRSxLQUFLLENBQUMsV0FBVyxFQUFFO2dCQUNoQyxNQUFNLEVBQUUsS0FBSyxDQUFDLE1BQU0sRUFBRTthQUN2QixDQUFDLENBQUMsQ0FBQztRQUNOLENBQUM7UUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1lBQ2YsTUFBTSxDQUFDLEtBQUssQ0FBQyx3Q0FBd0MsYUFBYSxFQUFFLEVBQUUsS0FBSyxDQUFDLENBQUM7WUFDN0UsTUFBTSxLQUFLLENBQUM7UUFDZCxDQUFDO0lBQ0gsQ0FBQztJQUVELEtBQUssQ0FBQyxVQUFVLENBQUMsT0FBZSxFQUFFLE9BQWU7UUFDL0MsSUFBSSxDQUFDO1lBQ0gsTUFBTSxFQUFFLENBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRSxPQUFPLENBQUMsQ0FBQztRQUNwQyxDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNmLE1BQU0sQ0FBQyxLQUFLLENBQUMsOEJBQThCLE9BQU8sT0FBTyxPQUFPLEVBQUUsRUFBRSxLQUFLLENBQUMsQ0FBQztZQUMzRSxNQUFNLEtBQUssQ0FBQztRQUNkLENBQUM7SUFDSCxDQUFDO0lBRUQsV0FBVyxDQUFDLFlBQW9CLEVBQUUsYUFBcUI7UUFDckQsc0ZBQXNGO1FBQ3RGLGdEQUFnRDtRQUNoRCxJQUFJLENBQUM7WUFDRixxREFBcUQ7WUFDckQsWUFBWSxDQUFDLFlBQVksRUFBRSxhQUFhLENBQUMsQ0FBQztZQUMxQyxPQUFPLElBQUksQ0FBQyxPQUFPLENBQUMsYUFBYSxFQUFFLFlBQVksQ0FBQyxDQUFDO1FBQ3BELENBQUM7UUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1lBQ2YsTUFBTSxJQUFJLEtBQUssQ0FBQyw0QkFBNEIsS0FBSyxZQUFZLEtBQUssQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsZUFBZSxFQUFFLENBQUMsQ0FBQztRQUMxRyxDQUFDO0lBQ0gsQ0FBQztJQUVELFlBQVksQ0FBQyxRQUFnQixFQUFFLGFBQXFCO1FBQ2xELElBQUksQ0FBQztZQUNILFlBQVksQ0FBQyxRQUFRLEVBQUUsYUFBYSxDQUFDLENBQUM7WUFDdEMsT0FBTyxJQUFJLENBQUM7UUFDZCxDQUFDO1FBQUMsTUFBTSxDQUFDO1lBQ1AsT0FBTyxLQUFLLENBQUM7UUFDZixDQUFDO0lBQ0gsQ0FBQztJQUVELEtBQUssQ0FBQyxtQkFBbUIsQ0FBQyxRQUFnQixFQUFFLE9BQWUsRUFBRSxVQUE0QixFQUFFO1FBQ3pGLElBQUksQ0FBQztZQUNILE1BQU0sT0FBTyxHQUFHLE9BQU8sQ0FBQyxPQUFPLElBQUksSUFBSSxDQUFDLGtCQUFrQixDQUFDO1lBQzNELElBQUksT0FBTyxDQUFDLE1BQU0sR0FBRyxPQUFPLEVBQUUsQ0FBQztnQkFDN0IsTUFBTSxJQUFJLEtBQUssQ0FBQyxtQ0FBbUMsT0FBTyxRQUFRLENBQUMsQ0FBQztZQUN0RSxDQUFDO1lBRUQsbUVBQW1FO1lBQ25FLHVDQUF1QztZQUN2QyxNQUFNLFVBQVUsR0FBRyxNQUFNLEVBQUUsQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLElBQUksQ0FBQyxDQUFDO1lBQ2pELElBQUksQ0FBQztnQkFDSCxNQUFNLFVBQVUsQ0FBQyxTQUFTLENBQUMsT0FBTyxFQUFFLEVBQUUsUUFBUSxFQUFFLE9BQU8sQ0FBQyxRQUFRLElBQUksT0FBTyxFQUFFLENBQUMsQ0FBQztZQUNqRixDQUFDO29CQUFTLENBQUM7Z0JBQ1QsTUFBTSxVQUFVLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDM0IsQ0FBQztZQUVELGVBQWUsQ0FBQyxnQkFBZ0IsQ0FBQztnQkFDL0IsSUFBSSxFQUFFLGNBQWM7Z0JBQ3BCLFFBQVEsRUFBRSxLQUFLO2dCQUNmLE1BQU0sRUFBRSxPQUFPLENBQUMsTUFBTSxJQUFJLDJDQUEyQztnQkFDckUsT0FBTyxFQUFFLDZCQUE2QixJQUFJLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxFQUFFO2FBQ2hFLENBQUMsQ0FBQztZQUVILE9BQU8sSUFBSSxDQUFDO1FBQ2QsQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixJQUFLLEtBQStCLENBQUMsSUFBSSxLQUFLLFFBQVEsRUFBRSxDQUFDO2dCQUN2RCxxRUFBcUU7Z0JBQ3JFLE9BQU8sS0FBSyxDQUFDO1lBQ2YsQ0FBQztZQUNELE1BQU0sQ0FBQyxLQUFLLENBQUMsc0NBQXNDLFFBQVEsRUFBRSxFQUFFLEtBQUssQ0FBQyxDQUFDO1lBQ3RFLE1BQU0sS0FBSyxDQUFDO1FBQ2QsQ0FBQztJQUNILENBQUM7SUFFRCxLQUFLLENBQUMsUUFBUSxDQUFDLFVBQWtCLEVBQUUsUUFBZ0IsRUFBRSxVQUFnQyxFQUFFO1FBQ3JGLElBQUksQ0FBQztZQUNILHNDQUFzQztZQUN0QyxNQUFNLElBQUksQ0FBQyxlQUFlLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDO1lBRW5ELE1BQU0sRUFBRSxDQUFDLFFBQVEsQ0FBQyxVQUFVLEVBQUUsUUFBUSxDQUFDLENBQUM7WUFFeEMsZUFBZSxDQUFDLGdCQUFnQixDQUFDO2dCQUMvQixJQUFJLEVBQUUsY0FBYztnQkFDcEIsUUFBUSxFQUFFLEtBQUs7Z0JBQ2YsTUFBTSxFQUFFLE9BQU8sQ0FBQyxNQUFNLElBQUksZ0NBQWdDO2dCQUMxRCxPQUFPLEVBQUUsZ0JBQWdCLElBQUksQ0FBQyxRQUFRLENBQUMsVUFBVSxDQUFDLE9BQU8sSUFBSSxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsRUFBRTthQUNuRixDQUFDLENBQUM7UUFDTCxDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNmLE1BQU0sQ0FBQyxLQUFLLENBQUMsNEJBQTRCLFVBQVUsT0FBTyxRQUFRLEVBQUUsRUFBRSxLQUFLLENBQUMsQ0FBQztZQUM3RSxNQUFNLEtBQUssQ0FBQztRQUNkLENBQUM7SUFDSCxDQUFDO0lBRUQsS0FBSyxDQUFDLEtBQUssQ0FBQyxRQUFnQixFQUFFLElBQVksRUFBRSxVQUFnQyxFQUFFO1FBQzVFLElBQUksQ0FBQztZQUNILE1BQU0sRUFBRSxDQUFDLEtBQUssQ0FBQyxRQUFRLEVBQUUsSUFBSSxDQUFDLENBQUM7WUFFL0IsZUFBZSxDQUFDLGdCQUFnQixDQUFDO2dCQUMvQixJQUFJLEVBQUUsY0FBYztnQkFDcEIsUUFBUSxFQUFFLEtBQUs7Z0JBQ2YsTUFBTSxFQUFFLE9BQU8sQ0FBQyxNQUFNLElBQUksNkJBQTZCO2dCQUN2RCxPQUFPLEVBQUUsNkJBQTZCLElBQUksQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLE9BQU8sSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsRUFBRTthQUN2RixDQUFDLENBQUM7UUFDTCxDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNmLE1BQU0sQ0FBQyxLQUFLLENBQUMsb0NBQW9DLFFBQVEsRUFBRSxFQUFFLEtBQUssQ0FBQyxDQUFDO1lBQ3BFLE1BQU0sS0FBSyxDQUFDO1FBQ2QsQ0FBQztJQUNILENBQUM7SUFFRCxLQUFLLENBQUMsVUFBVSxDQUFDLFFBQWdCLEVBQUUsT0FBZSxFQUFFLFVBQTRCLEVBQUU7UUFDaEYsSUFBSSxDQUFDO1lBQ0gsTUFBTSxFQUFFLENBQUMsVUFBVSxDQUFDLFFBQVEsRUFBRSxPQUFPLEVBQUUsRUFBRSxRQUFRLEVBQUUsT0FBTyxDQUFDLFFBQVEsSUFBSSxPQUFPLEVBQUUsQ0FBQyxDQUFDO1lBRWxGLHVFQUF1RTtZQUN2RSxJQUFJLElBQUksQ0FBQyxNQUFNLENBQUMsWUFBWSxFQUFFLENBQUM7Z0JBQzdCLGVBQWUsQ0FBQyxnQkFBZ0IsQ0FBQztvQkFDL0IsSUFBSSxFQUFFLGNBQWM7b0JBQ3BCLFFBQVEsRUFBRSxLQUFLO29CQUNmLE1BQU0sRUFBRSxPQUFPLENBQUMsTUFBTSxJQUFJLGtDQUFrQztvQkFDNUQsT0FBTyxFQUFFLDZCQUE2QixJQUFJLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxFQUFFO2lCQUNoRSxDQUFDLENBQUM7WUFDTCxDQUFDO1FBQ0gsQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixNQUFNLENBQUMsS0FBSyxDQUFDLDZCQUE2QixRQUFRLEVBQUUsRUFBRSxLQUFLLENBQUMsQ0FBQztZQUM3RCxNQUFNLEtBQUssQ0FBQztRQUNkLENBQUM7SUFDSCxDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBwcm9taXNlcyBhcyBmcywgU3RhdHMgfSBmcm9tICdmcyc7XG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0IHsgRmlsZUxvY2tNYW5hZ2VyIH0gZnJvbSAnLi4vc2VjdXJpdHkvZmlsZUxvY2tNYW5hZ2VyLmpzJztcbmltcG9ydCB7IFNlY3VyaXR5TW9uaXRvciB9IGZyb20gJy4uL3NlY3VyaXR5L3NlY3VyaXR5TW9uaXRvci5qcyc7XG5pbXBvcnQgeyBsb2dnZXIgfSBmcm9tICcuLi91dGlscy9sb2dnZXIuanMnO1xuaW1wb3J0IHsgRWxlbWVudFR5cGUgfSBmcm9tICcuLi9wb3J0Zm9saW8vdHlwZXMuanMnO1xuaW1wb3J0IHsgdmFsaWRhdGVQYXRoIH0gZnJvbSAnLi4vc2VjdXJpdHkvSW5wdXRWYWxpZGF0b3IuanMnO1xuXG5leHBvcnQgaW50ZXJmYWNlIEZpbGVSZWFkT3B0aW9ucyB7XG4gIGVuY29kaW5nPzogQnVmZmVyRW5jb2Rpbmc7XG4gIHNvdXJjZT86IHN0cmluZztcbiAgLyoqIE92ZXJyaWRlIG1heGltdW0gZmlsZSBzaXplIGZvciB0aGlzIG9wZXJhdGlvbiAoaW4gYnl0ZXMpICovXG4gIG1heFNpemU/OiBudW1iZXI7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgRmlsZVdyaXRlT3B0aW9ucyB7XG4gIGVuY29kaW5nPzogQnVmZmVyRW5jb2Rpbmc7XG4gIHNvdXJjZT86IHN0cmluZztcbiAgYXRvbWljPzogYm9vbGVhbjtcbiAgLyoqIE92ZXJyaWRlIG1heGltdW0gZmlsZSBzaXplIGZvciB0aGlzIG9wZXJhdGlvbiAoaW4gYnl0ZXMpICovXG4gIG1heFNpemU/OiBudW1iZXI7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgRmlsZU9wZXJhdGlvbk9wdGlvbnMge1xuICBzb3VyY2U/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgRmlsZU9wZXJhdGlvbnNDb25maWcge1xuICAvKiogRW5hYmxlIHZlcmJvc2UgYXVkaXQgbG9nZ2luZyBmb3IgcmVhZCBvcGVyYXRpb25zIChkZWZhdWx0OiBmYWxzZSkgKi9cbiAgdmVyYm9zZUF1ZGl0PzogYm9vbGVhbjtcbiAgLyoqIE1heGltdW0gZmlsZSBzaXplIGluIGJ5dGVzIChkZWZhdWx0OiAxME1CKSAqL1xuICBtYXhGaWxlU2l6ZT86IG51bWJlcjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBJRmlsZU9wZXJhdGlvbnNTZXJ2aWNlIHtcbiAgLyoqXG4gICAqIFJlYWQgYSBmaWxlIHNlY3VyZWx5IHdpdGggYXRvbWljIGxvY2tpbmdcbiAgICogQHBhcmFtIGZpbGVQYXRoIC0gQWJzb2x1dGUgcGF0aCB0byBmaWxlXG4gICAqIEBwYXJhbSBlbGVtZW50VHlwZSAtIEVsZW1lbnQgdHlwZSBmb3IgY29udGV4dCAob3B0aW9uYWwgZm9yIGdlbmVyaWMgZmlsZXMpXG4gICAqIEBwYXJhbSBvcHRpb25zIC0gUmVhZCBvcHRpb25zXG4gICAqL1xuICByZWFkRmlsZShmaWxlUGF0aDogc3RyaW5nLCBvcHRpb25zPzogRmlsZVJlYWRPcHRpb25zKTogUHJvbWlzZTxzdHJpbmc+O1xuXG4gIC8qKlxuICAgKiBSZWFkIGFuIGVsZW1lbnQgZmlsZSAod3JhcHBlciBhcm91bmQgcmVhZEZpbGUgd2l0aCBzcGVjaWZpYyBsb2dnaW5nKVxuICAgKiBAcGFyYW0gZmlsZVBhdGggLSBBYnNvbHV0ZSBwYXRoIHRvIGZpbGVcbiAgICogQHBhcmFtIGVsZW1lbnRUeXBlIC0gRWxlbWVudCB0eXBlXG4gICAqIEBwYXJhbSBvcHRpb25zIC0gUmVhZCBvcHRpb25zXG4gICAqL1xuICByZWFkRWxlbWVudEZpbGUoZmlsZVBhdGg6IHN0cmluZywgZWxlbWVudFR5cGU6IEVsZW1lbnRUeXBlLCBvcHRpb25zPzogRmlsZVJlYWRPcHRpb25zKTogUHJvbWlzZTxzdHJpbmc+O1xuXG4gIC8qKlxuICAgKiBXcml0ZSBhIGZpbGUgc2VjdXJlbHkgd2l0aCBhdG9taWMgbG9ja2luZ1xuICAgKiBAcGFyYW0gZmlsZVBhdGggLSBBYnNvbHV0ZSBwYXRoIHRvIGZpbGVcbiAgICogQHBhcmFtIGNvbnRlbnQgLSBDb250ZW50IHRvIHdyaXRlXG4gICAqIEBwYXJhbSBvcHRpb25zIC0gV3JpdGUgb3B0aW9uc1xuICAgKi9cbiAgd3JpdGVGaWxlKGZpbGVQYXRoOiBzdHJpbmcsIGNvbnRlbnQ6IHN0cmluZywgb3B0aW9ucz86IEZpbGVXcml0ZU9wdGlvbnMpOiBQcm9taXNlPHZvaWQ+O1xuXG4gIC8qKlxuICAgKiBEZWxldGUgYSBmaWxlIHNlY3VyZWx5XG4gICAqIEBwYXJhbSBmaWxlUGF0aCAtIEFic29sdXRlIHBhdGggdG8gZmlsZVxuICAgKiBAcGFyYW0gZWxlbWVudFR5cGUgLSBFbGVtZW50IHR5cGUgZm9yIGNvbnRleHQgKG9wdGlvbmFsKVxuICAgKiBAcGFyYW0gb3B0aW9ucyAtIE9wZXJhdGlvbiBvcHRpb25zXG4gICAqL1xuICBkZWxldGVGaWxlKGZpbGVQYXRoOiBzdHJpbmcsIGVsZW1lbnRUeXBlPzogRWxlbWVudFR5cGUsIG9wdGlvbnM/OiBGaWxlT3BlcmF0aW9uT3B0aW9ucyk6IFByb21pc2U8dm9pZD47XG5cbiAgLyoqXG4gICAqIENyZWF0ZSBhIGRpcmVjdG9yeSBpZiBpdCBkb2Vzbid0IGV4aXN0XG4gICAqIEBwYXJhbSBkaXJlY3RvcnlQYXRoIC0gQWJzb2x1dGUgcGF0aCB0byBkaXJlY3RvcnlcbiAgICovXG4gIGNyZWF0ZURpcmVjdG9yeShkaXJlY3RvcnlQYXRoOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+O1xuXG4gIC8qKlxuICAgKiBMaXN0IGZpbGVzIGluIGEgZGlyZWN0b3J5XG4gICAqIEBwYXJhbSBkaXJlY3RvcnlQYXRoIC0gQWJzb2x1dGUgcGF0aCB0byBkaXJlY3RvcnlcbiAgICovXG4gIGxpc3REaXJlY3RvcnkoZGlyZWN0b3J5UGF0aDogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmdbXT47XG5cbiAgLyoqXG4gICAqIExpc3QgZGlyZWN0b3J5IGNvbnRlbnRzIHdpdGggdHlwZSBpbmZvcm1hdGlvblxuICAgKiBAcGFyYW0gZGlyZWN0b3J5UGF0aCAtIEFic29sdXRlIHBhdGggdG8gZGlyZWN0b3J5XG4gICAqIEByZXR1cm5zIEFycmF5IG9mIGVudHJpZXMgd2l0aCBuYW1lIGFuZCB0eXBlIGluZm9cbiAgICovXG4gIGxpc3REaXJlY3RvcnlXaXRoVHlwZXMoZGlyZWN0b3J5UGF0aDogc3RyaW5nKTogUHJvbWlzZTxBcnJheTx7bmFtZTogc3RyaW5nLCBpc0RpcmVjdG9yeTogYm9vbGVhbiwgaXNGaWxlOiBib29sZWFufT4+O1xuXG4gIC8qKlxuICAgKiBSZW5hbWUvTW92ZSBhIGZpbGUgb3IgZGlyZWN0b3J5XG4gICAqIEBwYXJhbSBvbGRQYXRoIC0gQ3VycmVudCBhYnNvbHV0ZSBwYXRoXG4gICAqIEBwYXJhbSBuZXdQYXRoIC0gTmV3IGFic29sdXRlIHBhdGhcbiAgICovXG4gIHJlbmFtZUZpbGUob2xkUGF0aDogc3RyaW5nLCBuZXdQYXRoOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+O1xuICBcbiAgLyoqXG4gICAqIENoZWNrIGlmIGEgZmlsZSBvciBkaXJlY3RvcnkgZXhpc3RzXG4gICAqIEBwYXJhbSBmaWxlUGF0aCAtIEFic29sdXRlIHBhdGggdG8gY2hlY2tcbiAgICovXG4gIGV4aXN0cyhmaWxlUGF0aDogc3RyaW5nKTogUHJvbWlzZTxib29sZWFuPjtcblxuICAvKipcbiAgICogR2V0IGZpbGUgc3RhdGlzdGljc1xuICAgKiBAcGFyYW0gZmlsZVBhdGggLSBBYnNvbHV0ZSBwYXRoIHRvIHRoZSBmaWxlXG4gICAqIEByZXR1cm5zIEZpbGUgc3RhdGlzdGljc1xuICAgKi9cbiAgc3RhdChmaWxlUGF0aDogc3RyaW5nKTogUHJvbWlzZTxTdGF0cz47XG5cbiAgLyoqXG4gICAqIFJlc29sdmUgYSByZWxhdGl2ZSBwYXRoIHRvIGFic29sdXRlIHBhdGggd2l0aGluIGEgYmFzZSBkaXJlY3RvcnlcbiAgICogQHBhcmFtIHJlbGF0aXZlUGF0aCAtIFJlbGF0aXZlIHBhdGggdG8gcmVzb2x2ZVxuICAgKiBAcGFyYW0gYmFzZURpcmVjdG9yeSAtIEJhc2UgZGlyZWN0b3J5IGZvciByZXNvbHV0aW9uXG4gICAqL1xuICByZXNvbHZlUGF0aChyZWxhdGl2ZVBhdGg6IHN0cmluZywgYmFzZURpcmVjdG9yeTogc3RyaW5nKTogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZSBhIHBhdGggZG9lc24ndCBjb250YWluIHRyYXZlcnNhbCBhdHRlbXB0c1xuICAgKiBAcGFyYW0gZmlsZVBhdGggLSBQYXRoIHRvIHZhbGlkYXRlXG4gICAqIEBwYXJhbSBiYXNlRGlyZWN0b3J5IC0gQmFzZSBkaXJlY3RvcnkgdG8gY29uc3RyYWluIHRvXG4gICAqL1xuICB2YWxpZGF0ZVBhdGgoZmlsZVBhdGg6IHN0cmluZywgYmFzZURpcmVjdG9yeTogc3RyaW5nKTogYm9vbGVhbjtcblxuICAvKipcbiAgICogQ3JlYXRlIGEgZmlsZSBhdG9taWNhbGx5IC0gZmFpbHMgaWYgZmlsZSBhbHJlYWR5IGV4aXN0cyAocHJldmVudHMgVE9DVE9VIHJhY2UgY29uZGl0aW9ucylcbiAgICogQHBhcmFtIGZpbGVQYXRoIC0gQWJzb2x1dGUgcGF0aCB0byBmaWxlXG4gICAqIEBwYXJhbSBjb250ZW50IC0gQ29udGVudCB0byB3cml0ZVxuICAgKiBAcGFyYW0gb3B0aW9ucyAtIFdyaXRlIG9wdGlvbnNcbiAgICogQHJldHVybnMgdHJ1ZSBpZiBjcmVhdGVkLCBmYWxzZSBpZiBmaWxlIGFscmVhZHkgZXhpc3RlZFxuICAgKi9cbiAgY3JlYXRlRmlsZUV4Y2x1c2l2ZShmaWxlUGF0aDogc3RyaW5nLCBjb250ZW50OiBzdHJpbmcsIG9wdGlvbnM/OiBGaWxlV3JpdGVPcHRpb25zKTogUHJvbWlzZTxib29sZWFuPjtcblxuICAvKipcbiAgICogQ29weSBhIGZpbGUgZnJvbSBzb3VyY2UgdG8gZGVzdGluYXRpb25cbiAgICogQHBhcmFtIHNvdXJjZVBhdGggLSBBYnNvbHV0ZSBwYXRoIHRvIHNvdXJjZSBmaWxlXG4gICAqIEBwYXJhbSBkZXN0UGF0aCAtIEFic29sdXRlIHBhdGggdG8gZGVzdGluYXRpb25cbiAgICogQHBhcmFtIG9wdGlvbnMgLSBPcGVyYXRpb24gb3B0aW9uc1xuICAgKi9cbiAgY29weUZpbGUoc291cmNlUGF0aDogc3RyaW5nLCBkZXN0UGF0aDogc3RyaW5nLCBvcHRpb25zPzogRmlsZU9wZXJhdGlvbk9wdGlvbnMpOiBQcm9taXNlPHZvaWQ+O1xuXG4gIC8qKlxuICAgKiBDaGFuZ2UgZmlsZSBwZXJtaXNzaW9uc1xuICAgKiBAcGFyYW0gZmlsZVBhdGggLSBBYnNvbHV0ZSBwYXRoIHRvIGZpbGVcbiAgICogQHBhcmFtIG1vZGUgLSBQZXJtaXNzaW9uIG1vZGUgKGUuZy4sIDBvNjQ0KVxuICAgKiBAcGFyYW0gb3B0aW9ucyAtIE9wZXJhdGlvbiBvcHRpb25zXG4gICAqL1xuICBjaG1vZChmaWxlUGF0aDogc3RyaW5nLCBtb2RlOiBudW1iZXIsIG9wdGlvbnM/OiBGaWxlT3BlcmF0aW9uT3B0aW9ucyk6IFByb21pc2U8dm9pZD47XG5cbiAgLyoqXG4gICAqIEFwcGVuZCBjb250ZW50IHRvIGEgZmlsZVxuICAgKiBAcGFyYW0gZmlsZVBhdGggLSBBYnNvbHV0ZSBwYXRoIHRvIGZpbGVcbiAgICogQHBhcmFtIGNvbnRlbnQgLSBDb250ZW50IHRvIGFwcGVuZFxuICAgKiBAcGFyYW0gb3B0aW9ucyAtIFdyaXRlIG9wdGlvbnNcbiAgICovXG4gIGFwcGVuZEZpbGUoZmlsZVBhdGg6IHN0cmluZywgY29udGVudDogc3RyaW5nLCBvcHRpb25zPzogRmlsZVdyaXRlT3B0aW9ucyk6IFByb21pc2U8dm9pZD47XG59XG5cbmV4cG9ydCBjbGFzcyBGaWxlT3BlcmF0aW9uc1NlcnZpY2UgaW1wbGVtZW50cyBJRmlsZU9wZXJhdGlvbnNTZXJ2aWNlIHtcbiAgcHJpdmF0ZSBmaWxlTG9ja01hbmFnZXI6IEZpbGVMb2NrTWFuYWdlcjtcbiAgcHJpdmF0ZSByZWFkb25seSBkZWZhdWx0TWF4RmlsZVNpemU6IG51bWJlcjtcbiAgcHJpdmF0ZSBjb25maWc6IEZpbGVPcGVyYXRpb25zQ29uZmlnO1xuXG4gIGNvbnN0cnVjdG9yKGZpbGVMb2NrTWFuYWdlcjogRmlsZUxvY2tNYW5hZ2VyLCBjb25maWc/OiBGaWxlT3BlcmF0aW9uc0NvbmZpZykge1xuICAgIHRoaXMuZmlsZUxvY2tNYW5hZ2VyID0gZmlsZUxvY2tNYW5hZ2VyO1xuICAgIHRoaXMuY29uZmlnID0gY29uZmlnID8/IHsgdmVyYm9zZUF1ZGl0OiBmYWxzZSB9O1xuICAgIHRoaXMuZGVmYXVsdE1heEZpbGVTaXplID0gY29uZmlnPy5tYXhGaWxlU2l6ZSA/PyAoMTAgKiAxMDI0ICogMTAyNCk7IC8vIDEwTUIgZGVmYXVsdFxuICB9XG5cbiAgYXN5bmMgcmVhZEZpbGUoZmlsZVBhdGg6IHN0cmluZywgb3B0aW9uczogRmlsZVJlYWRPcHRpb25zID0ge30pOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBjb250ZW50ID0gYXdhaXQgdGhpcy5maWxlTG9ja01hbmFnZXIuYXRvbWljUmVhZEZpbGUoZmlsZVBhdGgsIHtcbiAgICAgICAgZW5jb2Rpbmc6IG9wdGlvbnMuZW5jb2RpbmcgPz8gJ3V0Zi04J1xuICAgICAgfSk7XG5cbiAgICAgIGNvbnN0IG1heFNpemUgPSBvcHRpb25zLm1heFNpemUgPz8gdGhpcy5kZWZhdWx0TWF4RmlsZVNpemU7XG4gICAgICBpZiAoY29udGVudC5sZW5ndGggPiBtYXhTaXplKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgRmlsZSBleGNlZWRzIG1heGltdW0gc2l6ZSBvZiAke21heFNpemV9IGJ5dGVzYCk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBjb250ZW50O1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBpZiAoKGVycm9yIGFzIE5vZGVKUy5FcnJub0V4Y2VwdGlvbikuY29kZSA9PT0gJ0VOT0VOVCcpIHtcbiAgICAgICAgbG9nZ2VyLmRlYnVnKGBGaWxlIG5vdCBmb3VuZDogJHtmaWxlUGF0aH1gKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGxvZ2dlci5lcnJvcihgRmFpbGVkIHRvIHJlYWQgZmlsZTogJHtmaWxlUGF0aH1gLCBlcnJvcik7XG4gICAgICB9XG4gICAgICB0aHJvdyBlcnJvcjtcbiAgICB9XG4gIH1cblxuICBhc3luYyByZWFkRWxlbWVudEZpbGUoZmlsZVBhdGg6IHN0cmluZywgZWxlbWVudFR5cGU6IEVsZW1lbnRUeXBlLCBvcHRpb25zOiBGaWxlUmVhZE9wdGlvbnMgPSB7fSk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgY29uc3QgY29udGVudCA9IGF3YWl0IHRoaXMucmVhZEZpbGUoZmlsZVBhdGgsIG9wdGlvbnMpO1xuXG4gICAgLy8gTG9nIHNlY3VyaXR5IGV2ZW50IGZvciBlbGVtZW50IGFjY2VzcyB3aGVuIHZlcmJvc2UgYXVkaXQgaXMgZW5hYmxlZFxuICAgIC8vIFRoaXMgaXMgY29uZmlndXJhYmxlIHRvIGF2b2lkIGxvZyBzcGFtIGluIHByb2R1Y3Rpb24gd2hpbGUgYWxsb3dpbmdcbiAgICAvLyBkZXRhaWxlZCBhdWRpdCB0cmFpbHMgd2hlbiBuZWVkZWQgKGUuZy4sIGZvciBjb21wbGlhbmNlIG9yIGRlYnVnZ2luZylcbiAgICBpZiAodGhpcy5jb25maWcudmVyYm9zZUF1ZGl0KSB7XG4gICAgICBTZWN1cml0eU1vbml0b3IubG9nU2VjdXJpdHlFdmVudCh7XG4gICAgICAgIHR5cGU6ICdGSUxFX1JFQUQnLFxuICAgICAgICBzZXZlcml0eTogJ0xPVycsXG4gICAgICAgIHNvdXJjZTogb3B0aW9ucy5zb3VyY2UgPz8gJ0ZpbGVPcGVyYXRpb25zU2VydmljZS5yZWFkRWxlbWVudEZpbGUnLFxuICAgICAgICBkZXRhaWxzOiBgUmVhZCAke2VsZW1lbnRUeXBlfSBmaWxlOiAke3BhdGguYmFzZW5hbWUoZmlsZVBhdGgpfWBcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIHJldHVybiBjb250ZW50O1xuICB9XG5cbiAgYXN5bmMgd3JpdGVGaWxlKGZpbGVQYXRoOiBzdHJpbmcsIGNvbnRlbnQ6IHN0cmluZywgb3B0aW9uczogRmlsZVdyaXRlT3B0aW9ucyA9IHt9KTogUHJvbWlzZTx2b2lkPiB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IG1heFNpemUgPSBvcHRpb25zLm1heFNpemUgPz8gdGhpcy5kZWZhdWx0TWF4RmlsZVNpemU7XG4gICAgICBpZiAoY29udGVudC5sZW5ndGggPiBtYXhTaXplKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgQ29udGVudCBleGNlZWRzIG1heGltdW0gc2l6ZSBvZiAke21heFNpemV9IGJ5dGVzYCk7XG4gICAgICB9XG5cbiAgICAgIGF3YWl0IHRoaXMuZmlsZUxvY2tNYW5hZ2VyLmF0b21pY1dyaXRlRmlsZShmaWxlUGF0aCwgY29udGVudCwge1xuICAgICAgICBlbmNvZGluZzogb3B0aW9ucy5lbmNvZGluZyA/PyAndXRmLTgnXG4gICAgICB9KTtcblxuICAgICAgU2VjdXJpdHlNb25pdG9yLmxvZ1NlY3VyaXR5RXZlbnQoe1xuICAgICAgICB0eXBlOiAnRklMRV9XUklUVEVOJyxcbiAgICAgICAgc2V2ZXJpdHk6ICdMT1cnLFxuICAgICAgICBzb3VyY2U6IG9wdGlvbnMuc291cmNlID8/ICdGaWxlT3BlcmF0aW9uc1NlcnZpY2Uud3JpdGVGaWxlJyxcbiAgICAgICAgZGV0YWlsczogYEZpbGUgd3JpdHRlbiBzdWNjZXNzZnVsbHk6ICR7cGF0aC5iYXNlbmFtZShmaWxlUGF0aCl9YFxuICAgICAgfSk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGxvZ2dlci5lcnJvcihgRmFpbGVkIHRvIHdyaXRlIGZpbGU6ICR7ZmlsZVBhdGh9YCwgZXJyb3IpO1xuICAgICAgdGhyb3cgZXJyb3I7XG4gICAgfVxuICB9XG5cbiAgYXN5bmMgZGVsZXRlRmlsZShmaWxlUGF0aDogc3RyaW5nLCBlbGVtZW50VHlwZT86IEVsZW1lbnRUeXBlLCBvcHRpb25zOiBGaWxlT3BlcmF0aW9uT3B0aW9ucyA9IHt9KTogUHJvbWlzZTx2b2lkPiB7XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IGZzLnVubGluayhmaWxlUGF0aCk7XG4gICAgICBcbiAgICAgIGlmIChlbGVtZW50VHlwZSkge1xuICAgICAgICBTZWN1cml0eU1vbml0b3IubG9nU2VjdXJpdHlFdmVudCh7XG4gICAgICAgICAgdHlwZTogJ0ZJTEVfREVMRVRFRCcsXG4gICAgICAgICAgc2V2ZXJpdHk6ICdNRURJVU0nLFxuICAgICAgICAgIHNvdXJjZTogb3B0aW9ucy5zb3VyY2UgPz8gJ0ZpbGVPcGVyYXRpb25zU2VydmljZS5kZWxldGVGaWxlJyxcbiAgICAgICAgICBkZXRhaWxzOiBgRGVsZXRlZCAke2VsZW1lbnRUeXBlfSBmaWxlOiAke3BhdGguYmFzZW5hbWUoZmlsZVBhdGgpfWBcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGlmICgoZXJyb3IgYXMgTm9kZUpTLkVycm5vRXhjZXB0aW9uKS5jb2RlID09PSAnRU5PRU5UJykge1xuICAgICAgICAvLyBGaWxlIGRvZXNuJ3QgZXhpc3QsIHdoaWNoIGlzIGZpbmUgZm9yIGRlbGV0ZVxuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICBsb2dnZXIuZXJyb3IoYEZhaWxlZCB0byBkZWxldGUgZmlsZTogJHtmaWxlUGF0aH1gLCBlcnJvcik7XG4gICAgICB0aHJvdyBlcnJvcjtcbiAgICB9XG4gIH1cblxuICBhc3luYyBjcmVhdGVEaXJlY3RvcnkoZGlyZWN0b3J5UGF0aDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IGZzLm1rZGlyKGRpcmVjdG9yeVBhdGgsIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBsb2dnZXIuZXJyb3IoYEZhaWxlZCB0byBjcmVhdGUgZGlyZWN0b3J5OiAke2RpcmVjdG9yeVBhdGh9YCwgZXJyb3IpO1xuICAgICAgdGhyb3cgZXJyb3I7XG4gICAgfVxuICB9XG5cbiAgYXN5bmMgZXhpc3RzKGZpbGVQYXRoOiBzdHJpbmcpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICB0cnkge1xuICAgICAgYXdhaXQgZnMuYWNjZXNzKGZpbGVQYXRoKTtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH0gY2F0Y2gge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgZmlsZSBzdGF0aXN0aWNzXG4gICAqIEBwYXJhbSBmaWxlUGF0aCAtIEFic29sdXRlIHBhdGggdG8gdGhlIGZpbGVcbiAgICogQHJldHVybnMgRmlsZSBzdGF0aXN0aWNzXG4gICAqL1xuICBhc3luYyBzdGF0KGZpbGVQYXRoOiBzdHJpbmcpOiBQcm9taXNlPFN0YXRzPiB7XG4gICAgcmV0dXJuIGF3YWl0IGZzLnN0YXQoZmlsZVBhdGgpO1xuICB9XG5cbiAgYXN5bmMgbGlzdERpcmVjdG9yeShkaXJlY3RvcnlQYXRoOiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZ1tdPiB7XG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiBhd2FpdCBmcy5yZWFkZGlyKGRpcmVjdG9yeVBhdGgpO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBsb2dnZXIuZXJyb3IoYEZhaWxlZCB0byBsaXN0IGRpcmVjdG9yeTogJHtkaXJlY3RvcnlQYXRofWAsIGVycm9yKTtcbiAgICAgIHRocm93IGVycm9yO1xuICAgIH1cbiAgfVxuXG4gIGFzeW5jIGxpc3REaXJlY3RvcnlXaXRoVHlwZXMoZGlyZWN0b3J5UGF0aDogc3RyaW5nKTogUHJvbWlzZTxBcnJheTx7bmFtZTogc3RyaW5nLCBpc0RpcmVjdG9yeTogYm9vbGVhbiwgaXNGaWxlOiBib29sZWFufT4+IHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgZW50cmllcyA9IGF3YWl0IGZzLnJlYWRkaXIoZGlyZWN0b3J5UGF0aCwgeyB3aXRoRmlsZVR5cGVzOiB0cnVlIH0pO1xuICAgICAgcmV0dXJuIGVudHJpZXMubWFwKGVudHJ5ID0+ICh7XG4gICAgICAgIG5hbWU6IGVudHJ5Lm5hbWUsXG4gICAgICAgIGlzRGlyZWN0b3J5OiBlbnRyeS5pc0RpcmVjdG9yeSgpLFxuICAgICAgICBpc0ZpbGU6IGVudHJ5LmlzRmlsZSgpXG4gICAgICB9KSk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGxvZ2dlci5lcnJvcihgRmFpbGVkIHRvIGxpc3QgZGlyZWN0b3J5IHdpdGggdHlwZXM6ICR7ZGlyZWN0b3J5UGF0aH1gLCBlcnJvcik7XG4gICAgICB0aHJvdyBlcnJvcjtcbiAgICB9XG4gIH1cblxuICBhc3luYyByZW5hbWVGaWxlKG9sZFBhdGg6IHN0cmluZywgbmV3UGF0aDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IGZzLnJlbmFtZShvbGRQYXRoLCBuZXdQYXRoKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgbG9nZ2VyLmVycm9yKGBGYWlsZWQgdG8gcmVuYW1lIGZpbGUgZnJvbSAke29sZFBhdGh9IHRvICR7bmV3UGF0aH1gLCBlcnJvcik7XG4gICAgICB0aHJvdyBlcnJvcjtcbiAgICB9XG4gIH1cblxuICByZXNvbHZlUGF0aChyZWxhdGl2ZVBhdGg6IHN0cmluZywgYmFzZURpcmVjdG9yeTogc3RyaW5nKTogc3RyaW5nIHtcbiAgICAvLyBVc2UgdGhlIGV4aXN0aW5nIHZhbGlkYXRlUGF0aCB1dGlsaXR5IHdoaWNoIGhhbmRsZXMgcmVzb2x1dGlvbiBhbmQgdHJhdmVyc2FsIGNoZWNrc1xuICAgIC8vIEJ1dCBoZXJlIHdlIGp1c3Qgd2FudCByZXNvbHV0aW9uICsgdmFsaWRhdGlvblxuICAgIHRyeSB7XG4gICAgICAgLy8gdmFsaWRhdGVQYXRoIGZyb20gSW5wdXRWYWxpZGF0b3IgdGhyb3dzIGlmIGludmFsaWRcbiAgICAgICB2YWxpZGF0ZVBhdGgocmVsYXRpdmVQYXRoLCBiYXNlRGlyZWN0b3J5KTtcbiAgICAgICByZXR1cm4gcGF0aC5yZXNvbHZlKGJhc2VEaXJlY3RvcnksIHJlbGF0aXZlUGF0aCk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCBwYXRoIHJlc29sdXRpb246ICR7ZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiAnVW5rbm93biBlcnJvcid9YCk7XG4gICAgfVxuICB9XG5cbiAgdmFsaWRhdGVQYXRoKGZpbGVQYXRoOiBzdHJpbmcsIGJhc2VEaXJlY3Rvcnk6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIHRyeSB7XG4gICAgICB2YWxpZGF0ZVBhdGgoZmlsZVBhdGgsIGJhc2VEaXJlY3RvcnkpO1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfSBjYXRjaCB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICB9XG5cbiAgYXN5bmMgY3JlYXRlRmlsZUV4Y2x1c2l2ZShmaWxlUGF0aDogc3RyaW5nLCBjb250ZW50OiBzdHJpbmcsIG9wdGlvbnM6IEZpbGVXcml0ZU9wdGlvbnMgPSB7fSk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBtYXhTaXplID0gb3B0aW9ucy5tYXhTaXplID8/IHRoaXMuZGVmYXVsdE1heEZpbGVTaXplO1xuICAgICAgaWYgKGNvbnRlbnQubGVuZ3RoID4gbWF4U2l6ZSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYENvbnRlbnQgZXhjZWVkcyBtYXhpbXVtIHNpemUgb2YgJHttYXhTaXplfSBieXRlc2ApO1xuICAgICAgfVxuXG4gICAgICAvLyBVc2UgJ3d4JyBmbGFnIGZvciBhdG9taWMgY3JlYXRpb24gLSBmYWlscyBpZiBmaWxlIGFscmVhZHkgZXhpc3RzXG4gICAgICAvLyBUaGlzIHByZXZlbnRzIFRPQ1RPVSByYWNlIGNvbmRpdGlvbnNcbiAgICAgIGNvbnN0IGZpbGVIYW5kbGUgPSBhd2FpdCBmcy5vcGVuKGZpbGVQYXRoLCAnd3gnKTtcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IGZpbGVIYW5kbGUud3JpdGVGaWxlKGNvbnRlbnQsIHsgZW5jb2Rpbmc6IG9wdGlvbnMuZW5jb2RpbmcgPz8gJ3V0Zi04JyB9KTtcbiAgICAgIH0gZmluYWxseSB7XG4gICAgICAgIGF3YWl0IGZpbGVIYW5kbGUuY2xvc2UoKTtcbiAgICAgIH1cblxuICAgICAgU2VjdXJpdHlNb25pdG9yLmxvZ1NlY3VyaXR5RXZlbnQoe1xuICAgICAgICB0eXBlOiAnRklMRV9XUklUVEVOJyxcbiAgICAgICAgc2V2ZXJpdHk6ICdMT1cnLFxuICAgICAgICBzb3VyY2U6IG9wdGlvbnMuc291cmNlID8/ICdGaWxlT3BlcmF0aW9uc1NlcnZpY2UuY3JlYXRlRmlsZUV4Y2x1c2l2ZScsXG4gICAgICAgIGRldGFpbHM6IGBGaWxlIGNyZWF0ZWQgZXhjbHVzaXZlbHk6ICR7cGF0aC5iYXNlbmFtZShmaWxlUGF0aCl9YFxuICAgICAgfSk7XG5cbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBpZiAoKGVycm9yIGFzIE5vZGVKUy5FcnJub0V4Y2VwdGlvbikuY29kZSA9PT0gJ0VFWElTVCcpIHtcbiAgICAgICAgLy8gRmlsZSBhbHJlYWR5IGV4aXN0cyAtIHRoaXMgaXMgZXhwZWN0ZWQgaW4gcmFjZSBjb25kaXRpb24gc2NlbmFyaW9zXG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH1cbiAgICAgIGxvZ2dlci5lcnJvcihgRmFpbGVkIHRvIGNyZWF0ZSBmaWxlIGV4Y2x1c2l2ZWx5OiAke2ZpbGVQYXRofWAsIGVycm9yKTtcbiAgICAgIHRocm93IGVycm9yO1xuICAgIH1cbiAgfVxuXG4gIGFzeW5jIGNvcHlGaWxlKHNvdXJjZVBhdGg6IHN0cmluZywgZGVzdFBhdGg6IHN0cmluZywgb3B0aW9uczogRmlsZU9wZXJhdGlvbk9wdGlvbnMgPSB7fSk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRyeSB7XG4gICAgICAvLyBFbnN1cmUgZGVzdGluYXRpb24gZGlyZWN0b3J5IGV4aXN0c1xuICAgICAgYXdhaXQgdGhpcy5jcmVhdGVEaXJlY3RvcnkocGF0aC5kaXJuYW1lKGRlc3RQYXRoKSk7XG5cbiAgICAgIGF3YWl0IGZzLmNvcHlGaWxlKHNvdXJjZVBhdGgsIGRlc3RQYXRoKTtcblxuICAgICAgU2VjdXJpdHlNb25pdG9yLmxvZ1NlY3VyaXR5RXZlbnQoe1xuICAgICAgICB0eXBlOiAnRklMRV9XUklUVEVOJyxcbiAgICAgICAgc2V2ZXJpdHk6ICdMT1cnLFxuICAgICAgICBzb3VyY2U6IG9wdGlvbnMuc291cmNlID8/ICdGaWxlT3BlcmF0aW9uc1NlcnZpY2UuY29weUZpbGUnLFxuICAgICAgICBkZXRhaWxzOiBgRmlsZSBjb3BpZWQ6ICR7cGF0aC5iYXNlbmFtZShzb3VyY2VQYXRoKX0gLT4gJHtwYXRoLmJhc2VuYW1lKGRlc3RQYXRoKX1gXG4gICAgICB9KTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgbG9nZ2VyLmVycm9yKGBGYWlsZWQgdG8gY29weSBmaWxlIGZyb20gJHtzb3VyY2VQYXRofSB0byAke2Rlc3RQYXRofWAsIGVycm9yKTtcbiAgICAgIHRocm93IGVycm9yO1xuICAgIH1cbiAgfVxuXG4gIGFzeW5jIGNobW9kKGZpbGVQYXRoOiBzdHJpbmcsIG1vZGU6IG51bWJlciwgb3B0aW9uczogRmlsZU9wZXJhdGlvbk9wdGlvbnMgPSB7fSk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCBmcy5jaG1vZChmaWxlUGF0aCwgbW9kZSk7XG5cbiAgICAgIFNlY3VyaXR5TW9uaXRvci5sb2dTZWN1cml0eUV2ZW50KHtcbiAgICAgICAgdHlwZTogJ0ZJTEVfV1JJVFRFTicsXG4gICAgICAgIHNldmVyaXR5OiAnTE9XJyxcbiAgICAgICAgc291cmNlOiBvcHRpb25zLnNvdXJjZSA/PyAnRmlsZU9wZXJhdGlvbnNTZXJ2aWNlLmNobW9kJyxcbiAgICAgICAgZGV0YWlsczogYEZpbGUgcGVybWlzc2lvbnMgY2hhbmdlZDogJHtwYXRoLmJhc2VuYW1lKGZpbGVQYXRoKX0gdG8gJHttb2RlLnRvU3RyaW5nKDgpfWBcbiAgICAgIH0pO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBsb2dnZXIuZXJyb3IoYEZhaWxlZCB0byBjaGFuZ2UgcGVybWlzc2lvbnMgZm9yICR7ZmlsZVBhdGh9YCwgZXJyb3IpO1xuICAgICAgdGhyb3cgZXJyb3I7XG4gICAgfVxuICB9XG5cbiAgYXN5bmMgYXBwZW5kRmlsZShmaWxlUGF0aDogc3RyaW5nLCBjb250ZW50OiBzdHJpbmcsIG9wdGlvbnM6IEZpbGVXcml0ZU9wdGlvbnMgPSB7fSk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCBmcy5hcHBlbmRGaWxlKGZpbGVQYXRoLCBjb250ZW50LCB7IGVuY29kaW5nOiBvcHRpb25zLmVuY29kaW5nID8/ICd1dGYtOCcgfSk7XG5cbiAgICAgIC8vIE9ubHkgbG9nIGlmIHZlcmJvc2UgYXVkaXQgaXMgZW5hYmxlZCB0byBhdm9pZCBsb2cgc3BhbSBmb3IgdGVsZW1ldHJ5XG4gICAgICBpZiAodGhpcy5jb25maWcudmVyYm9zZUF1ZGl0KSB7XG4gICAgICAgIFNlY3VyaXR5TW9uaXRvci5sb2dTZWN1cml0eUV2ZW50KHtcbiAgICAgICAgICB0eXBlOiAnRklMRV9XUklUVEVOJyxcbiAgICAgICAgICBzZXZlcml0eTogJ0xPVycsXG4gICAgICAgICAgc291cmNlOiBvcHRpb25zLnNvdXJjZSA/PyAnRmlsZU9wZXJhdGlvbnNTZXJ2aWNlLmFwcGVuZEZpbGUnLFxuICAgICAgICAgIGRldGFpbHM6IGBDb250ZW50IGFwcGVuZGVkIHRvIGZpbGU6ICR7cGF0aC5iYXNlbmFtZShmaWxlUGF0aCl9YFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgbG9nZ2VyLmVycm9yKGBGYWlsZWQgdG8gYXBwZW5kIHRvIGZpbGU6ICR7ZmlsZVBhdGh9YCwgZXJyb3IpO1xuICAgICAgdGhyb3cgZXJyb3I7XG4gICAgfVxuICB9XG59XG4iXX0=