@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
JavaScript
/**
* 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