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.

344 lines • 52.9 kB
/** * PortfolioPullHandler - Handles pulling portfolio elements from GitHub * * This handler implements the pull functionality for sync_portfolio, * enabling users to download their portfolio from GitHub to local storage. * Supports multiple sync modes (additive, mirror, backup) and dry-run. */ import { ElementType } from '../portfolio/types.js'; import { logger } from '../utils/logger.js'; import { UnicodeValidator } from '../security/validators/unicodeValidator.js'; import { SecurityMonitor } from '../security/securityMonitor.js'; import * as path from 'path'; export class PortfolioPullHandler { portfolioRepoManager; githubIndexer; portfolioManager; indexManager; syncComparer; downloader; fileOperations; tokenManager; constructor(dependencies) { if (!dependencies.portfolioManager) { throw new Error('PortfolioPullHandler requires a PortfolioManager instance'); } if (!dependencies.githubIndexer) { throw new Error('PortfolioPullHandler requires a GitHubPortfolioIndexer instance'); } if (!dependencies.indexManager) { throw new Error('PortfolioPullHandler requires a PortfolioIndexManager instance'); } this.portfolioRepoManager = dependencies.portfolioRepoManager; this.githubIndexer = dependencies.githubIndexer; this.portfolioManager = dependencies.portfolioManager; this.indexManager = dependencies.indexManager; this.syncComparer = dependencies.syncComparer; this.downloader = dependencies.downloader; this.fileOperations = dependencies.fileOperations; this.tokenManager = dependencies.tokenManager; } /** * Execute the pull operation from GitHub to local portfolio */ async executePull(options, personaIndicator) { try { logger.info('Starting portfolio pull operation', { options }); // Step 0: Ensure portfolio directory structure exists await this.portfolioManager.initialize(); // Step 1: Validate sync mode const syncMode = this.validateSyncMode(options.mode); // Step 2: Fetch GitHub portfolio index const progressMessages = []; progressMessages.push('šŸ” Fetching portfolio from GitHub...'); const githubIndex = await this.githubIndexer.getIndex(true); if (!githubIndex || githubIndex.totalElements === 0) { return { content: [{ type: "text", text: `${personaIndicator}āš ļø No elements found in GitHub portfolio. Nothing to pull.` }] }; } progressMessages.push(`šŸ“Š Found ${githubIndex.totalElements} elements on GitHub`); // Step 3: Get local portfolio state await this.indexManager.rebuildIndex(); const localElements = await this.getAllLocalElements(); progressMessages.push(`šŸ“ Found ${this.countElements(localElements)} local elements`); // Step 4: Compare and determine sync actions const syncActions = this.syncComparer.compareElements(githubIndex.elements, localElements, syncMode); // Step 5: Handle dry-run mode if (options.dryRun) { return this.formatDryRunResults(syncActions, progressMessages, personaIndicator); } // Step 6: Check for deletions requiring confirmation if (syncActions.toDelete.length > 0 && syncMode === 'mirror' && !options.force && options.confirmDeletions !== false) { return { content: [{ type: "text", text: `${personaIndicator}āš ļø Pull operation would delete ${syncActions.toDelete.length} local elements.\n\n` + `Elements to delete:\n${syncActions.toDelete.map(a => ` - ${a.name}`).join('\n')}\n\n` + `To proceed, run with \`force: true\` or \`confirmDeletions: false\`` }] }; } // Step 7: Execute sync actions const results = await this.executeSyncActions(syncActions, githubIndex.username, githubIndex.repository, progressMessages); // Step 8: Return success summary return { content: [{ type: "text", text: `${personaIndicator}āœ… **Portfolio Pull Complete**\n\n` + progressMessages.join('\n') + '\n\n' + `**Summary:**\n` + ` šŸ“„ Added: ${results.added}\n` + ` šŸ”„ Updated: ${results.updated}\n` + ` šŸ”— Skipped: ${results.skipped}\n` + (results.deleted > 0 ? ` šŸ—‘ļø Deleted: ${results.deleted}\n` : '') + `\nYour local portfolio is now synchronized with GitHub!` }] }; } catch (error) { logger.error('Portfolio pull failed', { error }); return { content: [{ type: "text", text: `${personaIndicator}āŒ Failed to pull portfolio: ${error instanceof Error ? error.message : String(error)}` }] }; } } /** * Validate and normalize sync mode * SECURITY FIX: Added Unicode normalization to prevent homograph attacks */ validateSyncMode(mode) { const validModes = ['additive', 'mirror', 'backup']; // SECURITY FIX: Normalize Unicode to prevent homograph attacks const normalizedMode = mode ? UnicodeValidator.normalize(mode).normalizedContent : 'additive'; const syncMode = normalizedMode.toLowerCase(); if (!validModes.includes(syncMode)) { throw new Error(`Invalid sync mode: ${mode}. Valid modes are: ${validModes.join(', ')}`); } return syncMode; } /** * Get all local elements organized by type */ async getAllLocalElements() { const elements = new Map(); const elementTypes = Object.values(ElementType); for (const type of elementTypes) { const typeElements = await this.indexManager.getElementsByType(type); if (typeElements.length > 0) { elements.set(type, typeElements); } } return elements; } /** * Count total elements in a map */ countElements(elements) { let count = 0; for (const typeElements of elements.values()) { count += typeElements.length; } return count; } /** * Format dry-run results for display */ formatDryRunResults(syncActions, progressMessages, personaIndicator) { const lines = [ `${personaIndicator}šŸ” **Dry Run Results**`, '', ...progressMessages, '', '**Planned Actions:**' ]; if (syncActions.toAdd.length > 0) { lines.push(`\nšŸ“„ **To Add (${syncActions.toAdd.length}):**`); syncActions.toAdd.forEach(action => { lines.push(` - ${action.type}/${action.name}`); }); } if (syncActions.toUpdate.length > 0) { lines.push(`\nšŸ”„ **To Update (${syncActions.toUpdate.length}):**`); syncActions.toUpdate.forEach(action => { lines.push(` - ${action.type}/${action.name}`); }); } if (syncActions.toDelete.length > 0) { lines.push(`\nšŸ—‘ļø **To Delete (${syncActions.toDelete.length}):**`); syncActions.toDelete.forEach(action => { lines.push(` - ${action.type}/${action.name}`); }); } if (syncActions.toSkip.length > 0) { lines.push(`\nšŸ”— **To Skip (${syncActions.toSkip.length}):**`); syncActions.toSkip.forEach(action => { lines.push(` - ${action.type}/${action.name} (${action.reason})`); }); } lines.push('', 'Run without `dryRun: true` to execute these changes.'); return { content: [{ type: "text", text: lines.join('\n') }] }; } /** * Execute the sync actions */ async executeSyncActions(syncActions, username, repository, progressMessages) { const results = { added: 0, updated: 0, deleted: 0, skipped: syncActions.toSkip.length }; // PERFORMANCE: Process downloads in parallel batches for improved speed const BATCH_SIZE = 5; // Process 5 downloads at a time to avoid rate limiting // Helper function to process a batch of actions const processBatch = async (actions, operation) => { const results = await Promise.allSettled(actions.map(async (action) => { progressMessages.push(`${operation}: ${action.type}/${action.name}`); await this.downloadAndSaveElement(action, username, repository); return action; })); return results.map((result, index) => ({ action: actions[index], success: result.status === 'fulfilled', error: result.status === 'rejected' ? result.reason : null })); }; // Process additions in batches for (let i = 0; i < syncActions.toAdd.length; i += BATCH_SIZE) { const batch = syncActions.toAdd.slice(i, i + BATCH_SIZE); const batchResults = await processBatch(batch, 'šŸ“„ Downloading'); for (const result of batchResults) { if (result.success) { results.added++; } else { logger.error(`Failed to add ${result.action.type}/${result.action.name}`, { error: result.error }); progressMessages.push(`āŒ Failed to add: ${result.action.type}/${result.action.name}`); } } } // Process updates in batches for (let i = 0; i < syncActions.toUpdate.length; i += BATCH_SIZE) { const batch = syncActions.toUpdate.slice(i, i + BATCH_SIZE); const batchResults = await processBatch(batch, 'šŸ”„ Updating'); for (const result of batchResults) { if (result.success) { results.updated++; } else { logger.error(`Failed to update ${result.action.type}/${result.action.name}`, { error: result.error }); progressMessages.push(`āŒ Failed to update: ${result.action.type}/${result.action.name}`); } } } // Process deletions for (const action of syncActions.toDelete) { try { progressMessages.push(`šŸ—‘ļø Deleting: ${action.type}/${action.name}`); await this.deleteLocalElement(action); results.deleted++; } catch (error) { logger.error(`Failed to delete ${action.type}/${action.name}`, { error }); progressMessages.push(`āŒ Failed to delete: ${action.type}/${action.name}`); } } // PERFORMANCE: Batch rebuild index after all operations complete if (results.added > 0 || results.updated > 0 || results.deleted > 0) { progressMessages.push('šŸ”„ Rebuilding index...'); await this.indexManager.rebuildIndex(); } return results; } /** * Download element from GitHub and save locally * SECURITY: Added audit logging for GitHub operations */ async downloadAndSaveElement(action, username, repository) { // NOTE: Token should already be set on portfolioRepoManager (passed as dependency) // Don't re-fetch token here - it breaks dependency injection and test environments // SECURITY: Log the download operation for audit trail SecurityMonitor.logSecurityEvent({ type: 'PORTFOLIO_FETCH_SUCCESS', severity: 'LOW', source: 'PortfolioPullHandler.downloadAndSaveElement', details: `Downloading element: ${action.type}/${action.name} from ${username}/${repository}` }); // Download the element content const elementData = await this.downloader.downloadFromGitHub(this.portfolioRepoManager, action.path, username, repository); // Save to local portfolio const elementDir = this.portfolioManager.getElementDir(action.type); const fileName = path.basename(action.path); const filePath = path.join(elementDir, fileName); // Ensure parent directory exists before writing (defensive check) await this.fileOperations.createDirectory(elementDir); await this.fileOperations.writeFile(filePath, elementData.content, { encoding: 'utf-8', source: 'PortfolioPullHandler.downloadAndSaveElement' }); // SECURITY: Log successful save for audit trail SecurityMonitor.logSecurityEvent({ type: 'ELEMENT_CREATED', severity: 'LOW', source: 'PortfolioPullHandler.downloadAndSaveElement', details: `Saved element to: ${action.type}/${fileName}` }); // PERFORMANCE: Skip individual index rebuild - will batch rebuild after all operations } /** * Delete local element * SECURITY: Added audit logging for deletion operations */ async deleteLocalElement(action) { const elementDir = this.portfolioManager.getElementDir(action.type); // Use the original filename from the path to preserve extension const fileName = path.basename(action.path) || `${action.name}.md`; const filePath = path.join(elementDir, fileName); // SECURITY: Log deletion attempt for audit trail SecurityMonitor.logSecurityEvent({ type: 'ELEMENT_DELETED', severity: 'MEDIUM', source: 'PortfolioPullHandler.deleteLocalElement', details: `Attempting to delete: ${action.type}/${fileName}` }); await this.fileOperations.deleteFile(filePath, action.type, { source: 'PortfolioPullHandler.deleteLocalElement' }); // PERFORMANCE: Skip individual index rebuild - will batch rebuild after all operations // SECURITY: Log successful deletion SecurityMonitor.logSecurityEvent({ type: 'ELEMENT_DELETED', severity: 'MEDIUM', source: 'PortfolioPullHandler.deleteLocalElement', details: `Successfully deleted: ${action.type}/${fileName}` }); } /** * Get GitHub token from auth manager */ async getGitHubToken() { const token = await this.tokenManager.getGitHubTokenAsync(); if (!token) { throw new Error('GitHub authentication required. Please run setup_github_auth first.'); } return token; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUG9ydGZvbGlvUHVsbEhhbmRsZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaGFuZGxlcnMvUG9ydGZvbGlvUHVsbEhhbmRsZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7OztHQU1HO0FBTUgsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQ3BELE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUc1QyxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSw0Q0FBNEMsQ0FBQztBQUM5RSxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFHakUsT0FBTyxLQUFLLElBQUksTUFBTSxNQUFNLENBQUM7QUE0QjdCLE1BQU0sT0FBTyxvQkFBb0I7SUFDdkIsb0JBQW9CLENBQXVCO0lBQzNDLGFBQWEsQ0FBeUI7SUFDdEMsZ0JBQWdCLENBQW1CO0lBQ25DLFlBQVksQ0FBd0I7SUFDcEMsWUFBWSxDQUF3QjtJQUNwQyxVQUFVLENBQXNCO0lBQ3ZCLGNBQWMsQ0FBeUI7SUFDdkMsWUFBWSxDQUFlO0lBRTVDLFlBQVksWUFBOEM7UUFDeEQsSUFBSSxDQUFDLFlBQVksQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO1lBQ25DLE1BQU0sSUFBSSxLQUFLLENBQUMsMkRBQTJELENBQUMsQ0FBQztRQUMvRSxDQUFDO1FBQ0QsSUFBSSxDQUFDLFlBQVksQ0FBQyxhQUFhLEVBQUUsQ0FBQztZQUNoQyxNQUFNLElBQUksS0FBSyxDQUFDLGlFQUFpRSxDQUFDLENBQUM7UUFDckYsQ0FBQztRQUNELElBQUksQ0FBQyxZQUFZLENBQUMsWUFBWSxFQUFFLENBQUM7WUFDL0IsTUFBTSxJQUFJLEtBQUssQ0FBQyxnRUFBZ0UsQ0FBQyxDQUFDO1FBQ3BGLENBQUM7UUFFRCxJQUFJLENBQUMsb0JBQW9CLEdBQUcsWUFBWSxDQUFDLG9CQUFvQixDQUFDO1FBQzlELElBQUksQ0FBQyxhQUFh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RSxNQUFNLENBQUMsSUFBSSxFQUFFO1lBQzFELE1BQU0sRUFBRSx5Q0FBeUM7U0FDbEQsQ0FBQyxDQUFDO1FBQ0gsdUZBQXVGO1FBRXZGLG9DQUFvQztRQUNwQyxlQUFlLENBQUMsZ0JBQWdCLENBQUM7WUFDL0IsSUFBSSxFQUFFLGlCQUFpQjtZQUN2QixRQUFRLEVBQUUsUUFBUTtZQUNsQixNQUFNLEVBQUUseUNBQXlDO1lBQ2pELE9BQU8sRUFBRSx5QkFBeUIsTUFBTSxDQUFDLElBQUksSUFBSSxRQUFRLEVBQUU7U0FDNUQsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVEOztPQUVHO0lBQ0ssS0FBSyxDQUFDLGNBQWM7UUFDMUIsTUFBTSxLQUFLLEdBQUcsTUFBTSxJQUFJLENBQUMsWUFBWSxDQUFDLG1CQUFtQixFQUFFLENBQUM7UUFDNUQsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQ1gsTUFBTSxJQUFJLEtBQUssQ0FBQyxxRUFBcUUsQ0FBQyxDQUFDO1FBQ3pGLENBQUM7UUFDRCxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogUG9ydGZvbGlvUHVsbEhhbmRsZXIgLSBIYW5kbGVzIHB1bGxpbmcgcG9ydGZvbGlvIGVsZW1lbnRzIGZyb20gR2l0SHViXG4gKiBcbiAqIFRoaXMgaGFuZGxlciBpbXBsZW1lbnRzIHRoZSBwdWxsIGZ1bmN0aW9uYWxpdHkgZm9yIHN5bmNfcG9ydGZvbGlvLFxuICogZW5hYmxpbmcgdXNlcnMgdG8gZG93bmxvYWQgdGhlaXIgcG9ydGZvbGlvIGZyb20gR2l0SHViIHRvIGxvY2FsIHN0b3JhZ2UuXG4gKiBTdXBwb3J0cyBtdWx0aXBsZSBzeW5jIG1vZGVzIChhZGRpdGl2ZSwgbWlycm9yLCBiYWNrdXApIGFuZCBkcnktcnVuLlxuICovXG5cbmltcG9ydCB7IFBvcnRmb2xpb1JlcG9NYW5hZ2VyIH0gZnJvbSAnLi4vcG9ydGZvbGlvL1BvcnRmb2xpb1JlcG9NYW5hZ2VyLmpzJztcbmltcG9ydCB7IEdpdEh1YlBvcnRmb2xpb0luZGV4ZXIgfSBmcm9tICcuLi9wb3J0Zm9saW8vR2l0SHViUG9ydGZvbGlvSW5kZXhlci5qcyc7XG5pbXBvcnQgeyBQb3J0Zm9saW9NYW5hZ2VyIH0gZnJvbSAnLi4vcG9ydGZvbGlvL1BvcnRmb2xpb01hbmFnZXIuanMnO1xuaW1wb3J0IHsgUG9ydGZvbGlvSW5kZXhNYW5hZ2VyIH0gZnJvbSAnLi4vcG9ydGZvbGlvL1BvcnRmb2xpb0luZGV4TWFuYWdlci5qcyc7XG5pbXBvcnQgeyBFbGVtZW50VHlwZSB9IGZyb20gJy4uL3BvcnRmb2xpby90eXBlcy5qcyc7XG5pbXBvcnQgeyBsb2dnZXIgfSBmcm9tICcuLi91dGlscy9sb2dnZXIuanMnO1xuaW1wb3J0IHsgUG9ydGZvbGlvU3luY0NvbXBhcmVyLCBTeW5jTW9kZSwgU3luY0FjdGlvbiB9IGZyb20gJy4uL3N5bmMvUG9ydGZvbGlvU3luY0NvbXBhcmVyLmpzJztcbmltcG9ydCB7IFBvcnRmb2xpb0Rvd25sb2FkZXIgfSBmcm9tICcuLi9zeW5jL1BvcnRmb2xpb0Rvd25sb2FkZXIuanMnO1xuaW1wb3J0IHsgVW5pY29kZVZhbGlkYXRvciB9IGZyb20gJy4uL3NlY3VyaXR5L3ZhbGlkYXRvcnMvdW5pY29kZVZhbGlkYXRvci5qcyc7XG5pbXBvcnQgeyBTZWN1cml0eU1vbml0b3IgfSBmcm9tICcuLi9zZWN1cml0eS9zZWN1cml0eU1vbml0b3IuanMnO1xuaW1wb3J0IHsgSUZpbGVPcGVyYXRpb25zU2VydmljZSB9IGZyb20gJy4uL3NlcnZpY2VzL0ZpbGVPcGVyYXRpb25zU2VydmljZS5qcyc7XG5pbXBvcnQgeyBUb2tlbk1hbmFnZXIgfSBmcm9tICcuLi9zZWN1cml0eS90b2tlbk1hbmFnZXIuanMnO1xuaW1wb3J0ICogYXMgcGF0aCBmcm9tICdwYXRoJztcblxuZXhwb3J0IGludGVyZmFjZSBQdWxsT3B0aW9ucyB7XG4gIGRpcmVjdGlvbjogc3RyaW5nO1xuICBtb2RlPzogc3RyaW5nO1xuICBmb3JjZT86IGJvb2xlYW47XG4gIGRyeVJ1bj86IGJvb2xlYW47XG4gIGNvbmZpcm1EZWxldGlvbnM/OiBib29sZWFuO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFB1bGxSZXN1bHQge1xuICBjb250ZW50OiBBcnJheTx7XG4gICAgdHlwZTogc3RyaW5nO1xuICAgIHRleHQ6IHN0cmluZztcbiAgfT47XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUG9ydGZvbGlvUHVsbEhhbmRsZXJEZXBlbmRlbmNpZXMge1xuICBwb3J0Zm9saW9SZXBvTWFuYWdlcjogUG9ydGZvbGlvUmVwb01hbmFnZXI7XG4gIGdpdGh1YkluZGV4ZXI6IEdpdEh1YlBvcnRmb2xpb0luZGV4ZXI7XG4gIHBvcnRmb2xpb01hbmFnZXI6IFBvcnRmb2xpb01hbmFnZXI7XG4gIGluZGV4TWFuYWdlcjogUG9ydGZvbGlvSW5kZXhNYW5hZ2VyO1xuICBzeW5jQ29tcGFyZXI6IFBvcnRmb2xpb1N5bmNDb21wYXJlcjtcbiAgZG93bmxvYWRlcjogUG9ydGZvbGlvRG93bmxvYWRlcjtcbiAgZmlsZU9wZXJhdGlvbnM6IElGaWxlT3BlcmF0aW9uc1NlcnZpY2U7XG4gIHRva2VuTWFuYWdlcjogVG9rZW5NYW5hZ2VyO1xufVxuXG5leHBvcnQgY2xhc3MgUG9ydGZvbGlvUHVsbEhhbmRsZXIge1xuICBwcml2YXRlIHBvcnRmb2xpb1JlcG9NYW5hZ2VyOiBQb3J0Zm9saW9SZXBvTWFuYWdlcjtcbiAgcHJpdmF0ZSBnaXRodWJJbmRleGVyOiBHaXRIdWJQb3J0Zm9saW9JbmRleGVyO1xuICBwcml2YXRlIHBvcnRmb2xpb01hbmFnZXI6IFBvcnRmb2xpb01hbmFnZXI7XG4gIHByaXZhdGUgaW5kZXhNYW5hZ2VyOiBQb3J0Zm9saW9JbmRleE1hbmFnZXI7XG4gIHByaXZhdGUgc3luY0NvbXBhcmVyOiBQb3J0Zm9saW9TeW5jQ29tcGFyZXI7XG4gIHByaXZhdGUgZG93bmxvYWRlcjogUG9ydGZvbGlvRG93bmxvYWRlcjtcbiAgcHJpdmF0ZSByZWFkb25seSBmaWxlT3BlcmF0aW9uczogSUZpbGVPcGVyYXRpb25zU2VydmljZTtcbiAgcHJpdmF0ZSByZWFkb25seSB0b2tlbk1hbmFnZXI6IFRva2VuTWFuYWdlcjtcblxuICBjb25zdHJ1Y3RvcihkZXBlbmRlbmNpZXM6IFBvcnRmb2xpb1B1bGxIYW5kbGVyRGVwZW5kZW5jaWVzKSB7XG4gICAgaWYgKCFkZXBlbmRlbmNpZXMucG9ydGZvbGlvTWFuYWdlcikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdQb3J0Zm9saW9QdWxsSGFuZGxlciByZXF1aXJlcyBhIFBvcnRmb2xpb01hbmFnZXIgaW5zdGFuY2UnKTtcbiAgICB9XG4gICAgaWYgKCFkZXBlbmRlbmNpZXMuZ2l0aHViSW5kZXhlcikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdQb3J0Zm9saW9QdWxsSGFuZGxlciByZXF1aXJlcyBhIEdpdEh1YlBvcnRmb2xpb0luZGV4ZXIgaW5zdGFuY2UnKTtcbiAgICB9XG4gICAgaWYgKCFkZXBlbmRlbmNpZXMuaW5kZXhNYW5hZ2VyKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ1BvcnRmb2xpb1B1bGxIYW5kbGVyIHJlcXVpcmVzIGEgUG9ydGZvbGlvSW5kZXhNYW5hZ2VyIGluc3RhbmNlJyk7XG4gICAgfVxuXG4gICAgdGhpcy5wb3J0Zm9saW9SZXBvTWFuYWdlciA9IGRlcGVuZGVuY2llcy5wb3J0Zm9saW9SZXBvTWFuYWdlcjtcbiAgICB0aGlzLmdpdGh1YkluZGV4ZXIgPSBkZXBlbmRlbmNpZXMuZ2l0aHViSW5kZXhlcjtcbiAgICB0aGlzLnBvcnRmb2xpb01hbmFnZXIgPSBkZXBlbmRlbmNpZXMucG9ydGZvbGlvTWFuYWdlcjtcbiAgICB0aGlzLmluZGV4TWFuYWdlciA9IGRlcGVuZGVuY2llcy5pbmRleE1hbmFnZXI7XG4gICAgdGhpcy5zeW5jQ29tcGFyZXIgPSBkZXBlbmRlbmNpZXMuc3luY0NvbXBhcmVyO1xuICAgIHRoaXMuZG93bmxvYWRlciA9IGRlcGVuZGVuY2llcy5kb3dubG9hZGVyO1xuICAgIHRoaXMuZmlsZU9wZXJhdGlvbnMgPSBkZXBlbmRlbmNpZXMuZmlsZU9wZXJhdGlvbnM7XG4gICAgdGhpcy50b2tlbk1hbmFnZXIgPSBkZXBlbmRlbmNpZXMudG9rZW5NYW5hZ2VyO1xuICB9XG5cbiAgLyoqXG4gICAqIEV4ZWN1dGUgdGhlIHB1bGwgb3BlcmF0aW9uIGZyb20gR2l0SHViIHRvIGxvY2FsIHBvcnRmb2xpb1xuICAgKi9cbiAgYXN5bmMgZXhlY3V0ZVB1bGwob3B0aW9uczogUHVsbE9wdGlvbnMsIHBlcnNvbmFJbmRpY2F0b3I6IHN0cmluZyk6IFByb21pc2U8UHVsbFJlc3VsdD4ge1xuICAgIHRyeSB7XG4gICAgICBsb2dnZXIuaW5mbygnU3RhcnRpbmcgcG9ydGZvbGlvIHB1bGwgb3BlcmF0aW9uJywgeyBvcHRpb25zIH0pO1xuXG4gICAgICAvLyBTdGVwIDA6IEVuc3VyZSBwb3J0Zm9saW8gZGlyZWN0b3J5IHN0cnVjdHVyZSBleGlzdHNcbiAgICAgIGF3YWl0IHRoaXMucG9ydGZvbGlvTWFuYWdlci5pbml0aWFsaXplKCk7XG5cbiAgICAgIC8vIFN0ZXAgMTogVmFsaWRhdGUgc3luYyBtb2RlXG4gICAgICBjb25zdCBzeW5jTW9kZSA9IHRoaXMudmFsaWRhdGVTeW5jTW9kZShvcHRpb25zLm1vZGUpO1xuICAgICAgXG4gICAgICAvLyBTdGVwIDI6IEZldGNoIEdpdEh1YiBwb3J0Zm9saW8gaW5kZXhcbiAgICAgIGNvbnN0IHByb2dyZXNzTWVzc2FnZXM6IHN0cmluZ1tdID0gW107XG4gICAgICBwcm9ncmVzc01lc3NhZ2VzLnB1c2goJ/CflI0gRmV0Y2hpbmcgcG9ydGZvbGlvIGZyb20gR2l0SHViLi4uJyk7XG4gICAgICBcbiAgICAgIGNvbnN0IGdpdGh1YkluZGV4ID0gYXdhaXQgdGhpcy5naXRodWJJbmRleGVyLmdldEluZGV4KHRydWUpO1xuICAgICAgXG4gICAgICBpZiAoIWdpdGh1YkluZGV4IHx8IGdpdGh1YkluZGV4LnRvdGFsRWxlbWVudHMgPT09IDApIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBjb250ZW50OiBbe1xuICAgICAgICAgICAgdHlwZTogXCJ0ZXh0XCIsXG4gICAgICAgICAgICB0ZXh0OiBgJHtwZXJzb25hSW5kaWNhdG9yfeKaoO+4jyBObyBlbGVtZW50cyBmb3VuZCBpbiBHaXRIdWIgcG9ydGZvbGlvLiBOb3RoaW5nIHRvIHB1bGwuYFxuICAgICAgICAgIH1dXG4gICAgICAgIH07XG4gICAgICB9XG4gICAgICBcbiAgICAgIHByb2dyZXNzTWVzc2FnZXMucHVzaChg8J+TiiBGb3VuZCAke2dpdGh1YkluZGV4LnRvdGFsRWxlbWVudHN9IGVsZW1lbnRzIG9uIEdpdEh1YmApO1xuICAgICAgXG4gICAgICAvLyBTdGVwIDM6IEdldCBsb2NhbCBwb3J0Zm9saW8gc3RhdGVcbiAgICAgIGF3YWl0IHRoaXMuaW5kZXhNYW5hZ2VyLnJlYnVpbGRJbmRleCgpO1xuICAgICAgY29uc3QgbG9jYWxFbGVtZW50cyA9IGF3YWl0IHRoaXMuZ2V0QWxsTG9jYWxFbGVtZW50cygpO1xuICAgICAgcHJvZ3Jlc3NNZXNzYWdlcy5wdXNoKGDwn5OBIEZvdW5kICR7dGhpcy5jb3VudEVsZW1lbnRzKGxvY2FsRWxlbWVudHMpfSBsb2NhbCBlbGVtZW50c2ApO1xuICAgICAgXG4gICAgICAvLyBTdGVwIDQ6IENvbXBhcmUgYW5kIGRldGVybWluZSBzeW5jIGFjdGlvbnNcbiAgICAgIGNvbnN0IHN5bmNBY3Rpb25zID0gdGhpcy5zeW5jQ29tcGFyZXIuY29tcGFyZUVsZW1lbnRzKFxuICAgICAgICBnaXRodWJJbmRleC5lbGVtZW50cyxcbiAgICAgICAgbG9jYWxFbGVtZW50cyxcbiAgICAgICAgc3luY01vZGVcbiAgICAgICk7XG4gICAgICBcbiAgICAgIC8vIFN0ZXAgNTogSGFuZGxlIGRyeS1ydW4gbW9kZVxuICAgICAgaWYgKG9wdGlvbnMuZHJ5UnVuKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmZvcm1hdERyeVJ1blJlc3VsdHMoc3luY0FjdGlvbnMsIHByb2dyZXNzTWVzc2FnZXMsIHBlcnNvbmFJbmRpY2F0b3IpO1xuICAgICAgfVxuICAgICAgXG4gICAgICAvLyBTdGVwIDY6IENoZWNrIGZvciBkZWxldGlvbnMgcmVxdWlyaW5nIGNvbmZpcm1hdGlvblxuICAgICAgaWYgKHN5bmNBY3Rpb25zLnRvRGVsZXRlLmxlbmd0aCA+IDAgJiYgXG4gICAgICAgICAgc3luY01vZGUgPT09ICdtaXJyb3InICYmIFxuICAgICAgICAgICFvcHRpb25zLmZvcmNlICYmIFxuICAgICAgICAgIG9wdGlvbnMuY29uZmlybURlbGV0aW9ucyAhPT0gZmFsc2UpIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBjb250ZW50OiBbe1xuICAgICAgICAgICAgdHlwZTogXCJ0ZXh0XCIsXG4gICAgICAgICAgICB0ZXh0OiBgJHtwZXJzb25hSW5kaWNhdG9yfeKaoO+4jyBQdWxsIG9wZXJhdGlvbiB3b3VsZCBkZWxldGUgJHtzeW5jQWN0aW9ucy50b0RlbGV0ZS5sZW5ndGh9IGxvY2FsIGVsZW1lbnRzLlxcblxcbmAgK1xuICAgICAgICAgICAgICAgICAgYEVsZW1lbnRzIHRvIGRlbGV0ZTpcXG4ke3N5bmNBY3Rpb25zLnRvRGVsZXRlLm1hcChhID0+IGAgIC0gJHthLm5hbWV9YCkuam9pbignXFxuJyl9XFxuXFxuYCArXG4gICAgICAgICAgICAgICAgICBgVG8gcHJvY2VlZCwgcnVuIHdpdGggXFxgZm9yY2U6IHRydWVcXGAgb3IgXFxgY29uZmlybURlbGV0aW9uczogZmFsc2VcXGBgXG4gICAgICAgICAgfV1cbiAgICAgICAgfTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgLy8gU3RlcCA3OiBFeGVjdXRlIHN5bmMgYWN0aW9uc1xuICAgICAgY29uc3QgcmVzdWx0cyA9IGF3YWl0IHRoaXMuZXhlY3V0ZVN5bmNBY3Rpb25zKFxuICAgICAgICBzeW5jQWN0aW9ucywgXG4gICAgICAgIGdpdGh1YkluZGV4LnVzZXJuYW1lLCBcbiAgICAgICAgZ2l0aHViSW5kZXgucmVwb3NpdG9yeSxcbiAgICAgICAgcHJvZ3Jlc3NNZXNzYWdlc1xuICAgICAgKTtcbiAgICAgIFxuICAgICAgLy8gU3RlcCA4OiBSZXR1cm4gc3VjY2VzcyBzdW1tYXJ5XG4gICAgICByZXR1cm4ge1xuICAgICAgICBjb250ZW50OiBbe1xuICAgICAgICAgIHR5cGU6IFwidGV4dFwiLFxuICAgICAgICAgIHRleHQ6IGAke3BlcnNvbmFJbmRpY2F0b3J94pyFICoqUG9ydGZvbGlvIFB1bGwgQ29tcGxldGUqKlxcblxcbmAgK1xuICAgICAgICAgICAgICAgIHByb2dyZXNzTWVzc2FnZXMuam9pbignXFxuJykgKyAnXFxuXFxuJyArXG4gICAgICAgICAgICAgICAgYCoqU3VtbWFyeToqKlxcbmAgK1xuICAgICAgICAgICAgICAgIGAgIPCfk6UgQWRkZWQ6ICR7cmVzdWx0cy5hZGRlZH1cXG5gICtcbiAgICAgICAgICAgICAgICBgICDwn5SEIFVwZGF0ZWQ6ICR7cmVzdWx0cy51cGRhdGVkfVxcbmAgK1xuICAgICAgICAgICAgICAgIGAgIPCflJcgU2tpcHBlZDogJHtyZXN1bHRzLnNraXBwZWR9XFxuYCArXG4gICAgICAgICAgICAgICAgKHJlc3VsdHMuZGVsZXRlZCA+IDAgPyBgICDwn5eR77iPIERlbGV0ZWQ6ICR7cmVzdWx0cy5kZWxldGVkfVxcbmAgOiAnJykgK1xuICAgICAgICAgICAgICAgIGBcXG5Zb3VyIGxvY2FsIHBvcnRmb2xpbyBpcyBub3cgc3luY2hyb25pemVkIHdpdGggR2l0SHViIWBcbiAgICAgICAgfV1cbiAgICAgIH07XG4gICAgICBcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgbG9nZ2VyLmVycm9yKCdQb3J0Zm9saW8gcHVsbCBmYWlsZWQnLCB7IGVycm9yIH0pO1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgY29udGVudDogW3tcbiAgICAgICAgICB0eXBlOiBcInRleHRcIixcbiAgICAgICAgICB0ZXh0OiBgJHtwZXJzb25hSW5kaWNhdG9yfeKdjCBGYWlsZWQgdG8gcHVsbCBwb3J0Zm9saW86ICR7ZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpfWBcbiAgICAgICAgfV1cbiAgICAgIH07XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFZhbGlkYXRlIGFuZCBub3JtYWxpemUgc3luYyBtb2RlXG4gICAqIFNFQ1VSSVRZIEZJWDogQWRkZWQgVW5pY29kZSBub3JtYWxpemF0aW9uIHRvIHByZXZlbnQgaG9tb2dyYXBoIGF0dGFja3NcbiAgICovXG4gIHByaXZhdGUgdmFsaWRhdGVTeW5jTW9kZShtb2RlPzogc3RyaW5nKTogU3luY01vZGUge1xuICAgIGNvbnN0IHZhbGlkTW9kZXM6IFN5bmNNb2RlW10gPSBbJ2FkZGl0aXZlJywgJ21pcnJvcicsICdiYWNrdXAnXTtcbiAgICBcbiAgICAvLyBTRUNVUklUWSBGSVg6IE5vcm1hbGl6ZSBVbmljb2RlIHRvIHByZXZlbnQgaG9tb2dyYXBoIGF0dGFja3NcbiAgICBjb25zdCBub3JtYWxpemVkTW9kZSA9IG1vZGUgPyBcbiAgICAgIFVuaWNvZGVWYWxpZGF0b3Iubm9ybWFsaXplKG1vZGUpLm5vcm1hbGl6ZWRDb250ZW50IDogXG4gICAgICAnYWRkaXRpdmUnO1xuICAgIFxuICAgIGNvbnN0IHN5bmNNb2RlID0gbm9ybWFsaXplZE1vZGUudG9Mb3dlckNhc2UoKSBhcyBTeW5jTW9kZTtcbiAgICBcbiAgICBpZiAoIXZhbGlkTW9kZXMuaW5jbHVkZXMoc3luY01vZGUpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgc3luYyBtb2RlOiAke21vZGV9LiBWYWxpZCBtb2RlcyBhcmU6ICR7dmFsaWRNb2Rlcy5qb2luKCcsICcpfWApO1xuICAgIH1cbiAgICBcbiAgICByZXR1cm4gc3luY01vZGU7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGFsbCBsb2NhbCBlbGVtZW50cyBvcmdhbml6ZWQgYnkgdHlwZVxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBnZXRBbGxMb2NhbEVsZW1lbnRzKCk6IFByb21pc2U8TWFwPEVsZW1lbnRUeXBlLCBhbnlbXT4+IHtcbiAgICBjb25zdCBlbGVtZW50cyA9IG5ldyBNYXA8RWxlbWVudFR5cGUsIGFueVtdPigpO1xuICAgIGNvbnN0IGVsZW1lbnRUeXBlcyA9IE9iamVjdC52YWx1ZXMoRWxlbWVudFR5cGUpO1xuICAgIFxuICAgIGZvciAoY29uc3QgdHlwZSBvZiBlbGVtZW50VHlwZXMpIHtcbiAgICAgIGNvbnN0IHR5cGVFbGVtZW50cyA9IGF3YWl0IHRoaXMuaW5kZXhNYW5hZ2VyLmdldEVsZW1lbnRzQnlUeXBlKHR5cGUpO1xuICAgICAgaWYgKHR5cGVFbGVtZW50cy5sZW5ndGggPiAwKSB7XG4gICAgICAgIGVsZW1lbnRzLnNldCh0eXBlLCB0eXBlRWxlbWVudHMpO1xuICAgICAgfVxuICAgIH1cbiAgICBcbiAgICByZXR1cm4gZWxlbWVudHM7XG4gIH1cblxuICAvKipcbiAgICogQ291bnQgdG90YWwgZWxlbWVudHMgaW4gYSBtYXBcbiAgICovXG4gIHByaXZhdGUgY291bnRFbGVtZW50cyhlbGVtZW50czogTWFwPEVsZW1lbnRUeXBlLCBhbnlbXT4pOiBudW1iZXIge1xuICAgIGxldCBjb3VudCA9IDA7XG4gICAgZm9yIChjb25zdCB0eXBlRWxlbWVudHMgb2YgZWxlbWVudHMudmFsdWVzKCkpIHtcbiAgICAgIGNvdW50ICs9IHR5cGVFbGVtZW50cy5sZW5ndGg7XG4gICAgfVxuICAgIHJldHVybiBjb3VudDtcbiAgfVxuXG4gIC8qKlxuICAgKiBGb3JtYXQgZHJ5LXJ1biByZXN1bHRzIGZvciBkaXNwbGF5XG4gICAqL1xuICBwcml2YXRlIGZvcm1hdERyeVJ1blJlc3VsdHMoXG4gICAgc3luY0FjdGlvbnM6IHsgdG9BZGQ6IFN5bmNBY3Rpb25bXSwgdG9VcGRhdGU6IFN5bmNBY3Rpb25bXSwgdG9EZWxldGU6IFN5bmNBY3Rpb25bXSwgdG9Ta2lwOiBTeW5jQWN0aW9uW10gfSxcbiAgICBwcm9ncmVzc01lc3NhZ2VzOiBzdHJpbmdbXSxcbiAgICBwZXJzb25hSW5kaWNhdG9yOiBzdHJpbmdcbiAgKTogUHVsbFJlc3VsdCB7XG4gICAgY29uc3QgbGluZXMgPSBbXG4gICAgICBgJHtwZXJzb25hSW5kaWNhdG9yffCflI0gKipEcnkgUnVuIFJlc3VsdHMqKmAsXG4gICAgICAnJyxcbiAgICAgIC4uLnByb2dyZXNzTWVzc2FnZXMsXG4gICAgICAnJyxcbiAgICAgICcqKlBsYW5uZWQgQWN0aW9uczoqKidcbiAgICBdO1xuICAgIFxuICAgIGlmIChzeW5jQWN0aW9ucy50b0FkZC5sZW5ndGggPiAwKSB7XG4gICAgICBsaW5lcy5wdXNoKGBcXG7wn5OlICoqVG8gQWRkICgke3N5bmNBY3Rpb25zLnRvQWRkLmxlbmd0aH0pOioqYCk7XG4gICAgICBzeW5jQWN0aW9ucy50b0FkZC5mb3JFYWNoKGFjdGlvbiA9PiB7XG4gICAgICAgIGxpbmVzLnB1c2goYCAgLSAke2FjdGlvbi50eXBlfS8ke2FjdGlvbi5uYW1lfWApO1xuICAgICAgfSk7XG4gICAgfVxuICAgIFxuICAgIGlmIChzeW5jQWN0aW9ucy50b1VwZGF0ZS5sZW5ndGggPiAwKSB7XG4gICAgICBsaW5lcy5wdXNoKGBcXG7wn5SEICoqVG8gVXBkYXRlICgke3N5bmNBY3Rpb25zLnRvVXBkYXRlLmxlbmd0aH0pOioqYCk7XG4gICAgICBzeW5jQWN0aW9ucy50b1VwZGF0ZS5mb3JFYWNoKGFjdGlvbiA9PiB7XG4gICAgICAgIGxpbmVzLnB1c2goYCAgLSAke2FjdGlvbi50eXBlfS8ke2FjdGlvbi5uYW1lfWApO1xuICAgICAgfSk7XG4gICAgfVxuICAgIFxuICAgIGlmIChzeW5jQWN0aW9ucy50b0RlbGV0ZS5sZW5ndGggPiAwKSB7XG4gICAgICBsaW5lcy5wdXNoKGBcXG7wn5eR77iPICoqVG8gRGVsZXRlICgke3N5bmNBY3Rpb25zLnRvRGVsZXRlLmxlbmd0aH0pOioqYCk7XG4gICAgICBzeW5jQWN0aW9ucy50b0RlbGV0ZS5mb3JFYWNoKGFjdGlvbiA9PiB7XG4gICAgICAgIGxpbmVzLnB1c2goYCAgLSAke2FjdGlvbi50eXBlfS8ke2FjdGlvbi5uYW1lfWApO1xuICAgICAgfSk7XG4gICAgfVxuICAgIFxuICAgIGlmIChzeW5jQWN0aW9ucy50b1NraXAubGVuZ3RoID4gMCkge1xuICAgICAgbGluZXMucHVzaChgXFxu8J+UlyAqKlRvIFNraXAgKCR7c3luY0FjdGlvbnMudG9Ta2lwLmxlbmd0aH0pOioqYCk7XG4gICAgICBzeW5jQWN0aW9ucy50b1NraXAuZm9yRWFjaChhY3Rpb24gPT4ge1xuICAgICAgICBsaW5lcy5wdXNoKGAgIC0gJHthY3Rpb24udHlwZX0vJHthY3Rpb24ubmFtZX0gKCR7YWN0aW9uLnJlYXNvbn0pYCk7XG4gICAgICB9KTtcbiAgICB9XG4gICAgXG4gICAgbGluZXMucHVzaCgnJywgJ1J1biB3aXRob3V0IGBkcnlSdW46IHRydWVgIHRvIGV4ZWN1dGUgdGhlc2UgY2hhbmdlcy4nKTtcbiAgICBcbiAgICByZXR1cm4ge1xuICAgICAgY29udGVudDogW3tcbiAgICAgICAgdHlwZTogXCJ0ZXh0XCIsXG4gICAgICAgIHRleHQ6IGxpbmVzLmpvaW4oJ1xcbicpXG4gICAgICB9XVxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogRXhlY3V0ZSB0aGUgc3luYyBhY3Rpb25zXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGV4ZWN1dGVTeW5jQWN0aW9ucyhcbiAgICBzeW5jQWN0aW9uczogeyB0b0FkZDogU3luY0FjdGlvbltdLCB0b1VwZGF0ZTogU3luY0FjdGlvbltdLCB0b0RlbGV0ZTogU3luY0FjdGlvbltdLCB0b1NraXA6IFN5bmNBY3Rpb25bXSB9LFxuICAgIHVzZXJuYW1lOiBzdHJpbmcsXG4gICAgcmVwb3NpdG9yeTogc3RyaW5nLFxuICAgIHByb2dyZXNzTWVzc2FnZXM6IHN0cmluZ1tdXG4gICk6IFByb21pc2U8eyBhZGRlZDogbnVtYmVyLCB1cGRhdGVkOiBudW1iZXIsIGRlbGV0ZWQ6IG51bWJlciwgc2tpcHBlZDogbnVtYmVyIH0+IHtcbiAgICBjb25zdCByZXN1bHRzID0ge1xuICAgICAgYWRkZWQ6IDAsXG4gICAgICB1cGRhdGVkOiAwLFxuICAgICAgZGVsZXRlZDogMCxcbiAgICAgIHNraXBwZWQ6IHN5bmNBY3Rpb25zLnRvU2tpcC5sZW5ndGhcbiAgICB9O1xuICAgIFxuICAgIC8vIFBFUkZPUk1BTkNFOiBQcm9jZXNzIGRvd25sb2FkcyBpbiBwYXJhbGxlbCBiYXRjaGVzIGZvciBpbXByb3ZlZCBzcGVlZFxuICAgIGNvbnN0IEJBVENIX1NJWkUgPSA1OyAvLyBQcm9jZXNzIDUgZG93bmxvYWRzIGF0IGEgdGltZSB0byBhdm9pZCByYXRlIGxpbWl0aW5nXG4gICAgXG4gICAgLy8gSGVscGVyIGZ1bmN0aW9uIHRvIHByb2Nlc3MgYSBiYXRjaCBvZiBhY3Rpb25zXG4gICAgY29uc3QgcHJvY2Vzc0JhdGNoID0gYXN5bmMgKGFjdGlvbnM6IFN5bmNBY3Rpb25bXSwgb3BlcmF0aW9uOiBzdHJpbmcpID0+IHtcbiAgICAgIGNvbnN0IHJlc3VsdHMgPSBhd2FpdCBQcm9taXNlLmFsbFNldHRsZWQoXG4gICAgICAgIGFjdGlvbnMubWFwKGFzeW5jIChhY3Rpb24pID0+IHtcbiAgICAgICAgICBwcm9ncmVzc01lc3NhZ2VzLnB1c2goYCR7b3BlcmF0aW9ufTogJHthY3Rpb24udHlwZX0vJHthY3Rpb24ubmFtZX1gKTtcbiAgICAgICAgICBhd2FpdCB0aGlzLmRvd25sb2FkQW5kU2F2ZUVsZW1lbnQoYWN0aW9uLCB1c2VybmFtZSwgcmVwb3NpdG9yeSk7XG4gICAgICAgICAgcmV0dXJuIGFjdGlvbjtcbiAgICAgICAgfSlcbiAgICAgICk7XG4gICAgICBcbiAgICAgIHJldHVybiByZXN1bHRzLm1hcCgocmVzdWx0LCBpbmRleCkgPT4gKHtcbiAgICAgICAgYWN0aW9uOiBhY3Rpb25zW2luZGV4XSxcbiAgICAgICAgc3VjY2VzczogcmVzdWx0LnN0YXR1cyA9PT0gJ2Z1bGZpbGxlZCcsXG4gICAgICAgIGVycm9yOiByZXN1bHQuc3RhdHVzID09PSAncmVqZWN0ZWQnID8gcmVzdWx0LnJlYXNvbiA6IG51bGxcbiAgICAgIH0pKTtcbiAgICB9O1xuICAgIFxuICAgIC8vIFByb2Nlc3MgYWRkaXRpb25zIGluIGJhdGNoZXNcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHN5bmNBY3Rpb25zLnRvQWRkLmxlbmd0aDsgaSArPSBCQVRDSF9TSVpFKSB7XG4gICAgICBjb25zdCBiYXRjaCA9IHN5bmNBY3Rpb25zLnRvQWRkLnNsaWNlKGksIGkgKyBCQVRDSF9TSVpFKTtcbiAgICAgIGNvbnN0IGJhdGNoUmVzdWx0cyA9IGF3YWl0IHByb2Nlc3NCYXRjaChiYXRjaCwgJ/Cfk6UgRG93bmxvYWRpbmcnKTtcbiAgICAgIFxuICAgICAgZm9yIChjb25zdCByZXN1bHQgb2YgYmF0Y2hSZXN1bHRzKSB7XG4gICAgICAgIGlmIChyZXN1bHQuc3VjY2Vzcykge1xuICAgICAgICAgIHJlc3VsdHMuYWRkZWQrKztcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBsb2dnZXIuZXJyb3IoYEZhaWxlZCB0byBhZGQgJHtyZXN1bHQuYWN0aW9uLnR5cGV9LyR7cmVzdWx0LmFjdGlvbi5uYW1lfWAsIHsgZXJyb3I6IHJlc3VsdC5lcnJvciB9KTtcbiAgICAgICAgICBwcm9ncmVzc01lc3NhZ2VzLnB1c2goYOKdjCBGYWlsZWQgdG8gYWRkOiAke3Jlc3VsdC5hY3Rpb24udHlwZX0vJHtyZXN1bHQuYWN0aW9uLm5hbWV9YCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgLy8gUHJvY2VzcyB1cGRhdGVzIGluIGJhdGNoZXNcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHN5bmNBY3Rpb25zLnRvVXBkYXRlLmxlbmd0aDsgaSArPSBCQVRDSF9TSVpFKSB7XG4gICAgICBjb25zdCBiYXRjaCA9IHN5bmNBY3Rpb25zLnRvVXBkYXRlLnNsaWNlKGksIGkgKyBCQVRDSF9TSVpFKTtcbiAgICAgIGNvbnN0IGJhdGNoUmVzdWx0cyA9IGF3YWl0IHByb2Nlc3NCYXRjaChiYXRjaCwgJ/CflIQgVXBkYXRpbmcnKTtcbiAgICAgIFxuICAgICAgZm9yIChjb25zdCByZXN1bHQgb2YgYmF0Y2hSZXN1bHRzKSB7XG4gICAgICAgIGlmIChyZXN1bHQuc3VjY2Vzcykge1xuICAgICAgICAgIHJlc3VsdHMudXBkYXRlZCsrO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGxvZ2dlci5lcnJvcihgRmFpbGVkIHRvIHVwZGF0ZSAke3Jlc3VsdC5hY3Rpb24udHlwZX0vJHtyZXN1bHQuYWN0aW9uLm5hbWV9YCwgeyBlcnJvcjogcmVzdWx0LmVycm9yIH0pO1xuICAgICAgICAgIHByb2dyZXNzTWVzc2FnZXMucHVzaChg4p2MIEZhaWxlZCB0byB1cGRhdGU6ICR7cmVzdWx0LmFjdGlvbi50eXBlfS8ke3Jlc3VsdC5hY3Rpb24ubmFtZX1gKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgICBcbiAgICAvLyBQcm9jZXNzIGRlbGV0aW9uc1xuICAgIGZvciAoY29uc3QgYWN0aW9uIG9mIHN5bmNBY3Rpb25zLnRvRGVsZXRlKSB7XG4gICAgICB0cnkge1xuICAgICAgICBwcm9ncmVzc01lc3NhZ2VzLnB1c2goYPCfl5HvuI8gRGVsZXRpbmc6ICR7YWN0aW9uLnR5cGV9LyR7YWN0aW9uLm5hbWV9YCk7XG4gICAgICAgIGF3YWl0IHRoaXMuZGVsZXRlTG9jYWxFbGVtZW50KGFjdGlvbik7XG4gICAgICAgIHJlc3VsdHMuZGVsZXRlZCsrO1xuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgbG9nZ2VyLmVycm9yKGBGYWlsZWQgdG8gZGVsZXRlICR7YWN0aW9uLnR5cGV9LyR7YWN0aW9uLm5hbWV9YCwgeyBlcnJvciB9KTtcbiAgICAgICAgcHJvZ3Jlc3NNZXNzYWdlcy5wdXNoKGDinYwgRmFpbGVkIHRvIGRlbGV0ZTogJHthY3Rpb24udHlwZX0vJHthY3Rpb24ubmFtZX1gKTtcbiAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgLy8gUEVSRk9STUFOQ0U6IEJhdGNoIHJlYnVpbGQgaW5kZXggYWZ0ZXIgYWxsIG9wZXJhdGlvbnMgY29tcGxldGVcbiAgICBpZiAocmVzdWx0cy5hZGRlZCA+IDAgfHwgcmVzdWx0cy51cGRhdGVkID4gMCB8fCByZXN1bHRzLmRlbGV0ZWQgPiAwKSB7XG4gICAgICBwcm9ncmVzc01lc3NhZ2VzLnB1c2goJ/CflIQgUmVidWlsZGluZyBpbmRleC4uLicpO1xuICAgICAgYXdhaXQgdGhpcy5pbmRleE1hbmFnZXIucmVidWlsZEluZGV4KCk7XG4gICAgfVxuICAgIFxuICAgIHJldHVybiByZXN1bHRzO1xuICB9XG5cbiAgLyoqXG4gICAqIERvd25sb2FkIGVsZW1lbnQgZnJvbSBHaXRIdWIgYW5kIHNhdmUgbG9jYWxseVxuICAgKiBTRUNVUklUWTogQWRkZWQgYXVkaXQgbG9nZ2luZyBmb3IgR2l0SHViIG9wZXJhdGlvbnNcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgZG93bmxvYWRBbmRTYXZlRWxlbWVudChcbiAgICBhY3Rpb246IFN5bmNBY3Rpb24sXG4gICAgdXNlcm5hbWU6IHN0cmluZyxcbiAgICByZXBvc2l0b3J5OiBzdHJpbmdcbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgLy8gTk9URTogVG9rZW4gc2hvdWxkIGFscmVhZHkgYmUgc2V0IG9uIHBvcnRmb2xpb1JlcG9NYW5hZ2VyIChwYXNzZWQgYXMgZGVwZW5kZW5jeSlcbiAgICAvLyBEb24ndCByZS1mZXRjaCB0b2tlbiBoZXJlIC0gaXQgYnJlYWtzIGRlcGVuZGVuY3kgaW5qZWN0aW9uIGFuZCB0ZXN0IGVudmlyb25tZW50c1xuXG4gICAgLy8gU0VDVVJJVFk6IExvZyB0aGUgZG93bmxvYWQgb3BlcmF0aW9uIGZvciBhdWRpdCB0cmFpbFxuICAgIFNlY3VyaXR5TW9uaXRvci5sb2dTZWN1cml0eUV2ZW50KHtcbiAgICAgIHR5cGU6ICdQT1JURk9MSU9fRkVUQ0hfU1VDQ0VTUycsXG4gICAgICBzZXZlcml0eTogJ0xPVycsXG4gICAgICBzb3VyY2U6ICdQb3J0Zm9saW9QdWxsSGFuZGxlci5kb3dubG9hZEFuZFNhdmVFbGVtZW50JyxcbiAgICAgIGRldGFpbHM6IGBEb3dubG9hZGluZyBlbGVtZW50OiAke2FjdGlvbi50eXBlfS8ke2FjdGlvbi5uYW1lfSBmcm9tICR7dXNlcm5hbWV9LyR7cmVwb3NpdG9yeX1gXG4gICAgfSk7XG4gICAgXG4gICAgLy8gRG93bmxvYWQgdGhlIGVsZW1lbnQgY29udGVudFxuICAgIGNvbnN0IGVsZW1lbnREYXRhID0gYXdhaXQgdGhpcy5kb3dubG9hZGVyLmRvd25sb2FkRnJvbUdpdEh1YihcbiAgICAgIHRoaXMucG9ydGZvbGlvUmVwb01hbmFnZXIsXG4gICAgICBhY3Rpb24ucGF0aCxcbiAgICAgIHVzZXJuYW1lLFxuICAgICAgcmVwb3NpdG9yeVxuICAgICk7XG4gICAgXG4gICAgLy8gU2F2ZSB0byBsb2NhbCBwb3J0Zm9saW9cbiAgICBjb25zdCBlbGVtZW50RGlyID0gdGhpcy5wb3J0Zm9saW9NYW5hZ2VyLmdldEVsZW1lbnREaXIoYWN0aW9uLnR5cGUpO1xuICAgIGNvbnN0IGZpbGVOYW1lID0gcGF0aC5iYXNlbmFtZShhY3Rpb24ucGF0aCk7XG4gICAgY29uc3QgZmlsZVBhdGggPSBwYXRoLmpvaW4oZWxlbWVudERpciwgZmlsZU5hbWUpO1xuXG4gICAgLy8gRW5zdXJlIHBhcmVudCBkaXJlY3RvcnkgZXhpc3RzIGJlZm9yZSB3cml0aW5nIChkZWZlbnNpdmUgY2hlY2spXG4gICAgYXdhaXQgdGhpcy5maWxlT3BlcmF0aW9ucy5jcmVhdGVEaXJlY3RvcnkoZWxlbWVudERpcik7XG5cbiAgICBhd2FpdCB0aGlzLmZpbGVPcGVyYXRpb25zLndyaXRlR