@dollhousemcp/mcp-server 1.5.2 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +56 -0
- package/README.md +494 -111
- package/data/agents/code-reviewer.md +8 -1
- package/data/agents/research-assistant.md +8 -1
- package/data/agents/task-manager.md +8 -1
- package/data/ensembles/business-advisor.md +8 -1
- package/data/ensembles/creative-studio.md +8 -1
- package/data/ensembles/development-team.md +8 -1
- package/data/ensembles/security-analysis-team.md +8 -1
- package/data/memories/conversation-history.md +8 -1
- package/data/memories/learning-progress.md +8 -1
- package/data/memories/project-context.md +8 -1
- package/data/personas/business-consultant.md +8 -1
- package/data/personas/creative-writer.md +8 -1
- package/data/personas/debug-detective.md +8 -1
- package/data/personas/eli5-explainer.md +8 -1
- package/data/personas/security-analyst.md +8 -1
- package/data/personas/technical-analyst.md +8 -1
- package/data/skills/code-review.md +8 -1
- package/data/skills/creative-writing.md +8 -1
- package/data/skills/data-analysis.md +8 -1
- package/data/skills/penetration-testing.md +8 -1
- package/data/skills/research.md +8 -1
- package/data/skills/threat-modeling.md +8 -1
- package/data/skills/translation.md +8 -1
- package/data/templates/code-documentation.md +8 -1
- package/data/templates/email-professional.md +8 -1
- package/data/templates/meeting-notes.md +8 -1
- package/data/templates/penetration-test-report.md +8 -1
- package/data/templates/project-brief.md +8 -1
- package/data/templates/report-executive.md +8 -1
- package/data/templates/security-vulnerability-report.md +8 -1
- package/data/templates/threat-assessment-report.md +8 -1
- package/dist/auth/GitHubAuthManager.d.ts +6 -1
- package/dist/auth/GitHubAuthManager.d.ts.map +1 -1
- package/dist/auth/GitHubAuthManager.js +45 -18
- package/dist/benchmarks/IndexPerformanceBenchmark.d.ts +98 -0
- package/dist/benchmarks/IndexPerformanceBenchmark.d.ts.map +1 -0
- package/dist/benchmarks/IndexPerformanceBenchmark.js +531 -0
- package/dist/cache/CollectionCache.d.ts.map +1 -1
- package/dist/cache/CollectionCache.js +13 -3
- package/dist/cache/CollectionIndexCache.d.ts +77 -0
- package/dist/cache/CollectionIndexCache.d.ts.map +1 -0
- package/dist/cache/CollectionIndexCache.js +349 -0
- package/dist/cache/LRUCache.d.ts +93 -0
- package/dist/cache/LRUCache.d.ts.map +1 -0
- package/dist/cache/LRUCache.js +299 -0
- package/dist/cache/index.d.ts +1 -0
- package/dist/cache/index.d.ts.map +1 -1
- package/dist/cache/index.js +2 -1
- package/dist/collection/CollectionBrowser.d.ts +21 -1
- package/dist/collection/CollectionBrowser.d.ts.map +1 -1
- package/dist/collection/CollectionBrowser.js +130 -10
- package/dist/collection/CollectionIndexManager.d.ts +151 -0
- package/dist/collection/CollectionIndexManager.d.ts.map +1 -0
- package/dist/collection/CollectionIndexManager.js +499 -0
- package/dist/collection/CollectionSearch.d.ts +55 -0
- package/dist/collection/CollectionSearch.d.ts.map +1 -1
- package/dist/collection/CollectionSearch.js +338 -13
- package/dist/collection/CollectionSeeder.d.ts.map +1 -1
- package/dist/collection/CollectionSeeder.js +38 -1
- package/dist/collection/ElementInstaller.d.ts +31 -0
- package/dist/collection/ElementInstaller.d.ts.map +1 -1
- package/dist/collection/ElementInstaller.js +77 -15
- package/dist/collection/PersonaSubmitter.d.ts +1 -1
- package/dist/collection/PersonaSubmitter.d.ts.map +1 -1
- package/dist/collection/PersonaSubmitter.js +2 -2
- package/dist/collection/index.d.ts +1 -0
- package/dist/collection/index.d.ts.map +1 -1
- package/dist/collection/index.js +2 -1
- package/dist/config/ConfigManager.d.ts +78 -0
- package/dist/config/ConfigManager.d.ts.map +1 -0
- package/dist/config/ConfigManager.js +216 -0
- package/dist/config/element-types.d.ts +135 -0
- package/dist/config/element-types.d.ts.map +1 -0
- package/dist/config/element-types.js +108 -0
- package/dist/config/index.d.ts +2 -0
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +3 -1
- package/dist/config/portfolio-constants.d.ts +83 -0
- package/dist/config/portfolio-constants.d.ts.map +1 -0
- package/dist/config/portfolio-constants.js +99 -0
- package/dist/elements/BaseElement.d.ts +14 -2
- package/dist/elements/BaseElement.d.ts.map +1 -1
- package/dist/elements/BaseElement.js +88 -6
- package/dist/elements/agents/Agent.d.ts +10 -1
- package/dist/elements/agents/Agent.d.ts.map +1 -1
- package/dist/elements/agents/Agent.js +66 -19
- package/dist/elements/agents/AgentManager.d.ts +2 -0
- package/dist/elements/agents/AgentManager.d.ts.map +1 -1
- package/dist/elements/agents/AgentManager.js +12 -10
- package/dist/elements/skills/Skill.d.ts +10 -1
- package/dist/elements/skills/Skill.d.ts.map +1 -1
- package/dist/elements/skills/Skill.js +40 -3
- package/dist/elements/skills/SkillManager.d.ts +1 -0
- package/dist/elements/skills/SkillManager.d.ts.map +1 -1
- package/dist/elements/skills/SkillManager.js +10 -4
- package/dist/elements/templates/Template.d.ts +10 -1
- package/dist/elements/templates/Template.d.ts.map +1 -1
- package/dist/elements/templates/Template.js +35 -18
- package/dist/elements/templates/TemplateManager.d.ts +1 -1
- package/dist/elements/templates/TemplateManager.d.ts.map +1 -1
- package/dist/elements/templates/TemplateManager.js +6 -5
- package/dist/generated/version.d.ts +2 -2
- package/dist/generated/version.js +3 -3
- package/dist/index.barrel.d.ts +1 -2
- package/dist/index.barrel.d.ts.map +1 -1
- package/dist/index.barrel.js +2 -4
- package/dist/index.d.ts +143 -25
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1883 -310
- package/dist/persona/PersonaElement.d.ts +10 -0
- package/dist/persona/PersonaElement.d.ts.map +1 -1
- package/dist/persona/PersonaElement.js +55 -32
- package/dist/persona/PersonaElementManager.d.ts.map +1 -1
- package/dist/persona/PersonaElementManager.js +13 -11
- package/dist/persona/PersonaLoader.d.ts.map +1 -1
- package/dist/persona/PersonaLoader.js +8 -2
- package/dist/persona/export-import/PersonaImporter.d.ts.map +1 -1
- package/dist/persona/export-import/PersonaImporter.js +24 -5
- package/dist/persona/export-import/PersonaSharer.d.ts +21 -0
- package/dist/persona/export-import/PersonaSharer.d.ts.map +1 -1
- package/dist/persona/export-import/PersonaSharer.js +198 -22
- package/dist/portfolio/DefaultElementProvider.d.ts +90 -0
- package/dist/portfolio/DefaultElementProvider.d.ts.map +1 -1
- package/dist/portfolio/DefaultElementProvider.js +499 -7
- package/dist/portfolio/GitHubPortfolioIndexer.d.ts +129 -0
- package/dist/portfolio/GitHubPortfolioIndexer.d.ts.map +1 -0
- package/dist/portfolio/GitHubPortfolioIndexer.js +475 -0
- package/dist/portfolio/MigrationManager.d.ts.map +1 -1
- package/dist/portfolio/MigrationManager.js +136 -3
- package/dist/portfolio/PortfolioIndexManager.d.ts +130 -0
- package/dist/portfolio/PortfolioIndexManager.d.ts.map +1 -0
- package/dist/portfolio/PortfolioIndexManager.js +478 -0
- package/dist/portfolio/PortfolioManager.d.ts +5 -0
- package/dist/portfolio/PortfolioManager.d.ts.map +1 -1
- package/dist/portfolio/PortfolioManager.js +61 -20
- package/dist/portfolio/PortfolioRepoManager.d.ts +75 -0
- package/dist/portfolio/PortfolioRepoManager.d.ts.map +1 -0
- package/dist/portfolio/PortfolioRepoManager.js +337 -0
- package/dist/portfolio/UnifiedIndexManager.d.ts +388 -0
- package/dist/portfolio/UnifiedIndexManager.d.ts.map +1 -0
- package/dist/portfolio/UnifiedIndexManager.js +1434 -0
- package/dist/portfolio/index.d.ts +15 -0
- package/dist/portfolio/index.d.ts.map +1 -0
- package/dist/portfolio/index.js +15 -0
- package/dist/portfolio/types.d.ts +7 -0
- package/dist/portfolio/types.d.ts.map +1 -1
- package/dist/portfolio/types.js +6 -1
- package/dist/security/InputValidator.d.ts.map +1 -1
- package/dist/security/InputValidator.js +50 -48
- package/dist/security/audit/SecurityAuditor.d.ts.map +1 -1
- package/dist/security/audit/SecurityAuditor.js +17 -9
- package/dist/security/audit/config/suppressions.d.ts.map +1 -1
- package/dist/security/audit/config/suppressions.js +19 -3
- package/dist/security/contentValidator.d.ts +2 -0
- package/dist/security/contentValidator.d.ts.map +1 -1
- package/dist/security/contentValidator.js +115 -4
- package/dist/security/secureYamlParser.d.ts +1 -0
- package/dist/security/secureYamlParser.d.ts.map +1 -1
- package/dist/security/secureYamlParser.js +29 -7
- package/dist/security/securityMonitor.d.ts +1 -1
- package/dist/security/securityMonitor.d.ts.map +1 -1
- package/dist/security/securityMonitor.js +1 -1
- package/dist/security/tokenManager.d.ts +1 -1
- package/dist/security/tokenManager.d.ts.map +1 -1
- package/dist/security/tokenManager.js +30 -10
- package/dist/server/ServerSetup.d.ts +22 -2
- package/dist/server/ServerSetup.d.ts.map +1 -1
- package/dist/server/ServerSetup.js +77 -12
- package/dist/server/tools/AuthTools.d.ts.map +1 -1
- package/dist/server/tools/AuthTools.js +33 -1
- package/dist/server/tools/BuildInfoTools.d.ts +25 -0
- package/dist/server/tools/BuildInfoTools.d.ts.map +1 -0
- package/dist/server/tools/BuildInfoTools.js +36 -0
- package/dist/server/tools/CollectionTools.d.ts.map +1 -1
- package/dist/server/tools/CollectionTools.js +55 -46
- package/dist/server/tools/ConfigTools.d.ts.map +1 -1
- package/dist/server/tools/ConfigTools.js +29 -1
- package/dist/server/tools/PersonaTools.d.ts +4 -2
- package/dist/server/tools/PersonaTools.d.ts.map +1 -1
- package/dist/server/tools/PersonaTools.js +5 -152
- package/dist/server/tools/PortfolioTools.d.ts +12 -0
- package/dist/server/tools/PortfolioTools.d.ts.map +1 -0
- package/dist/server/tools/PortfolioTools.js +221 -0
- package/dist/server/tools/index.d.ts +3 -1
- package/dist/server/tools/index.d.ts.map +1 -1
- package/dist/server/tools/index.js +4 -2
- package/dist/server/types.d.ts +40 -5
- package/dist/server/types.d.ts.map +1 -1
- package/dist/server/types.js +1 -1
- package/dist/services/BuildInfoService.d.ts +84 -0
- package/dist/services/BuildInfoService.d.ts.map +1 -0
- package/dist/services/BuildInfoService.js +271 -0
- package/dist/tools/portfolio/PortfolioElementAdapter.d.ts +54 -0
- package/dist/tools/portfolio/PortfolioElementAdapter.d.ts.map +1 -0
- package/dist/tools/portfolio/PortfolioElementAdapter.js +229 -0
- package/dist/tools/portfolio/submitToPortfolioTool.d.ts +164 -0
- package/dist/tools/portfolio/submitToPortfolioTool.d.ts.map +1 -0
- package/dist/tools/portfolio/submitToPortfolioTool.js +1523 -0
- package/dist/tools/portfolio/types.d.ts +41 -0
- package/dist/tools/portfolio/types.d.ts.map +1 -0
- package/dist/tools/portfolio/types.js +15 -0
- package/dist/types/collection.d.ts +51 -0
- package/dist/types/collection.d.ts.map +1 -1
- package/dist/types/collection.js +1 -1
- package/dist/utils/EarlyTerminationSearch.d.ts +41 -0
- package/dist/utils/EarlyTerminationSearch.d.ts.map +1 -0
- package/dist/utils/EarlyTerminationSearch.js +164 -0
- package/dist/utils/ErrorHandler.d.ts +86 -0
- package/dist/utils/ErrorHandler.d.ts.map +1 -0
- package/dist/utils/ErrorHandler.js +201 -0
- package/dist/utils/FileDiscoveryUtil.d.ts +53 -0
- package/dist/utils/FileDiscoveryUtil.d.ts.map +1 -0
- package/dist/utils/FileDiscoveryUtil.js +169 -0
- package/dist/utils/GitHubRateLimiter.d.ts +88 -0
- package/dist/utils/GitHubRateLimiter.d.ts.map +1 -0
- package/dist/utils/GitHubRateLimiter.js +315 -0
- package/dist/utils/PerformanceMonitor.d.ts +134 -0
- package/dist/utils/PerformanceMonitor.d.ts.map +1 -0
- package/dist/utils/PerformanceMonitor.js +347 -0
- package/dist/utils/RateLimiter.d.ts.map +1 -0
- package/dist/utils/RateLimiter.js +172 -0
- package/dist/utils/SecureDownloader.d.ts +241 -0
- package/dist/utils/SecureDownloader.d.ts.map +1 -0
- package/dist/utils/SecureDownloader.js +759 -0
- package/dist/utils/ToolCache.d.ts +82 -0
- package/dist/utils/ToolCache.d.ts.map +1 -0
- package/dist/utils/ToolCache.js +196 -0
- package/dist/utils/errorCodes.d.ts +136 -0
- package/dist/utils/errorCodes.d.ts.map +1 -0
- package/dist/utils/errorCodes.js +87 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +4 -1
- package/dist/utils/installation.d.ts +1 -1
- package/dist/utils/installation.d.ts.map +1 -1
- package/dist/utils/installation.js +9 -8
- package/dist/utils/searchUtils.d.ts +31 -0
- package/dist/utils/searchUtils.d.ts.map +1 -1
- package/dist/utils/searchUtils.js +62 -1
- package/package.json +17 -7
- package/dist/config/updateConfig.d.ts +0 -84
- package/dist/config/updateConfig.d.ts.map +0 -1
- package/dist/config/updateConfig.js +0 -148
- package/dist/server/tools/UpdateTools.d.ts +0 -10
- package/dist/server/tools/UpdateTools.d.ts.map +0 -1
- package/dist/server/tools/UpdateTools.js +0 -85
- package/dist/update/BackupManager.d.ts +0 -63
- package/dist/update/BackupManager.d.ts.map +0 -1
- package/dist/update/BackupManager.js +0 -370
- package/dist/update/DependencyChecker.d.ts +0 -41
- package/dist/update/DependencyChecker.d.ts.map +0 -1
- package/dist/update/DependencyChecker.js +0 -132
- package/dist/update/RateLimiter.d.ts.map +0 -1
- package/dist/update/RateLimiter.js +0 -172
- package/dist/update/SignatureVerifier.d.ts +0 -71
- package/dist/update/SignatureVerifier.d.ts.map +0 -1
- package/dist/update/SignatureVerifier.js +0 -214
- package/dist/update/UpdateChecker.d.ts +0 -132
- package/dist/update/UpdateChecker.d.ts.map +0 -1
- package/dist/update/UpdateChecker.js +0 -506
- package/dist/update/UpdateManager.d.ts +0 -60
- package/dist/update/UpdateManager.d.ts.map +0 -1
- package/dist/update/UpdateManager.js +0 -730
- package/dist/update/VersionManager.d.ts +0 -31
- package/dist/update/VersionManager.d.ts.map +0 -1
- package/dist/update/VersionManager.js +0 -181
- package/dist/update/index.d.ts +0 -9
- package/dist/update/index.d.ts.map +0 -1
- package/dist/update/index.js +0 -9
- /package/dist/{update → utils}/RateLimiter.d.ts +0 -0
|
@@ -0,0 +1,1434 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified Index Manager - Combines local, GitHub, and collection portfolio indexing
|
|
3
|
+
*
|
|
4
|
+
* Features:
|
|
5
|
+
* - Unified search across local, GitHub, and collection portfolios
|
|
6
|
+
* - Intelligent result merging and deduplication
|
|
7
|
+
* - Version conflict detection and resolution
|
|
8
|
+
* - Performance optimization with parallel indexing
|
|
9
|
+
* - Advanced fallback strategies for resilient operation
|
|
10
|
+
* - Comprehensive search capabilities with pagination
|
|
11
|
+
* - Smart result ranking and duplicate detection
|
|
12
|
+
*/
|
|
13
|
+
import { PortfolioIndexManager } from './PortfolioIndexManager.js';
|
|
14
|
+
import { GitHubPortfolioIndexer } from './GitHubPortfolioIndexer.js';
|
|
15
|
+
import { CollectionIndexCache } from '../cache/CollectionIndexCache.js';
|
|
16
|
+
import { GitHubClient } from '../collection/GitHubClient.js';
|
|
17
|
+
import { APICache } from '../cache/APICache.js';
|
|
18
|
+
import { ElementType } from './types.js';
|
|
19
|
+
import { logger } from '../utils/logger.js';
|
|
20
|
+
import { ErrorHandler, ErrorCategory } from '../utils/ErrorHandler.js';
|
|
21
|
+
import { CacheFactory } from '../cache/LRUCache.js';
|
|
22
|
+
import { PerformanceMonitor } from '../utils/PerformanceMonitor.js';
|
|
23
|
+
import { UnicodeValidator } from '../security/validators/unicodeValidator.js';
|
|
24
|
+
import { SecurityMonitor } from '../security/securityMonitor.js';
|
|
25
|
+
export class UnifiedIndexManager {
|
|
26
|
+
static instance = null;
|
|
27
|
+
localIndexManager;
|
|
28
|
+
githubIndexer;
|
|
29
|
+
collectionIndexCache;
|
|
30
|
+
githubClient;
|
|
31
|
+
// Performance monitoring and caching
|
|
32
|
+
performanceMonitor;
|
|
33
|
+
resultCache;
|
|
34
|
+
indexCache;
|
|
35
|
+
BATCH_SIZE = 50; // For streaming results
|
|
36
|
+
MAX_CONCURRENT_SOURCES = 3;
|
|
37
|
+
constructor() {
|
|
38
|
+
this.localIndexManager = PortfolioIndexManager.getInstance();
|
|
39
|
+
this.githubIndexer = GitHubPortfolioIndexer.getInstance();
|
|
40
|
+
// Initialize GitHubClient with required dependencies
|
|
41
|
+
const apiCache = new APICache();
|
|
42
|
+
const rateLimitTracker = new Map();
|
|
43
|
+
this.githubClient = new GitHubClient(apiCache, rateLimitTracker);
|
|
44
|
+
this.collectionIndexCache = new CollectionIndexCache(this.githubClient);
|
|
45
|
+
// Initialize performance monitoring and caching
|
|
46
|
+
this.performanceMonitor = PerformanceMonitor.getInstance();
|
|
47
|
+
this.performanceMonitor.startMonitoring();
|
|
48
|
+
this.resultCache = CacheFactory.createSearchResultCache({
|
|
49
|
+
maxSize: 200,
|
|
50
|
+
maxMemoryMB: 15,
|
|
51
|
+
ttlMs: 5 * 60 * 1000, // 5 minutes
|
|
52
|
+
onEviction: (key, value) => {
|
|
53
|
+
logger.debug('Search result cache eviction', { key, resultCount: value.length });
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
this.indexCache = CacheFactory.createIndexCache({
|
|
57
|
+
maxSize: 100,
|
|
58
|
+
maxMemoryMB: 20,
|
|
59
|
+
ttlMs: 15 * 60 * 1000, // 15 minutes
|
|
60
|
+
onEviction: (key, value) => {
|
|
61
|
+
logger.debug('Index cache eviction', { key });
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
logger.debug('UnifiedIndexManager created with performance optimization');
|
|
65
|
+
}
|
|
66
|
+
static getInstance() {
|
|
67
|
+
if (!this.instance) {
|
|
68
|
+
this.instance = new UnifiedIndexManager();
|
|
69
|
+
}
|
|
70
|
+
return this.instance;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Enhanced search across local, GitHub, and collection portfolios with performance optimization
|
|
74
|
+
*/
|
|
75
|
+
async search(searchOptions) {
|
|
76
|
+
const startTime = Date.now();
|
|
77
|
+
const memoryBefore = process.memoryUsage().heapUsed;
|
|
78
|
+
const { query, includeLocal = true, includeGitHub = true, includeCollection = false } = searchOptions;
|
|
79
|
+
// Normalize query to prevent Unicode-based attacks
|
|
80
|
+
const validationResult = UnicodeValidator.normalize(query);
|
|
81
|
+
const normalizedQuery = validationResult.normalizedContent;
|
|
82
|
+
// Use normalized query in all subsequent operations
|
|
83
|
+
const normalizedSearchOptions = {
|
|
84
|
+
...searchOptions,
|
|
85
|
+
query: normalizedQuery
|
|
86
|
+
};
|
|
87
|
+
// SECURITY FIX (DMCP-SEC-006): Add audit logging for security monitoring
|
|
88
|
+
// Log unified search operations for security audit trail
|
|
89
|
+
SecurityMonitor.logSecurityEvent({
|
|
90
|
+
type: 'PORTFOLIO_FETCH_SUCCESS',
|
|
91
|
+
severity: 'LOW',
|
|
92
|
+
source: 'UnifiedIndexManager.search',
|
|
93
|
+
details: `Unified search performed with query length: ${normalizedQuery.length}, sources: ${JSON.stringify({
|
|
94
|
+
local: includeLocal,
|
|
95
|
+
github: includeGitHub,
|
|
96
|
+
collection: includeCollection
|
|
97
|
+
})}`
|
|
98
|
+
});
|
|
99
|
+
logger.debug('Starting optimized unified portfolio search', normalizedSearchOptions);
|
|
100
|
+
// Check cache first (use normalized search options)
|
|
101
|
+
const cacheKey = this.createCacheKey(normalizedSearchOptions);
|
|
102
|
+
const cached = this.resultCache.get(cacheKey);
|
|
103
|
+
if (cached) {
|
|
104
|
+
const duration = Date.now() - startTime;
|
|
105
|
+
this.recordSearchMetrics({
|
|
106
|
+
query: normalizedQuery,
|
|
107
|
+
duration,
|
|
108
|
+
resultCount: cached.length,
|
|
109
|
+
sources: this.getEnabledSources(normalizedSearchOptions),
|
|
110
|
+
cacheHit: true,
|
|
111
|
+
memoryBefore,
|
|
112
|
+
memoryAfter: process.memoryUsage().heapUsed,
|
|
113
|
+
timestamp: new Date()
|
|
114
|
+
});
|
|
115
|
+
logger.debug('Using cached search results', { resultCount: cached.length });
|
|
116
|
+
return cached;
|
|
117
|
+
}
|
|
118
|
+
try {
|
|
119
|
+
// Use streaming search for better performance with large result sets
|
|
120
|
+
if (normalizedSearchOptions.streamResults) {
|
|
121
|
+
return await this.streamSearch(normalizedSearchOptions);
|
|
122
|
+
}
|
|
123
|
+
// Lazy loading: Only load indices when needed
|
|
124
|
+
const searchPromises = [];
|
|
125
|
+
const enabledSources = this.getEnabledSources(normalizedSearchOptions);
|
|
126
|
+
// Limit concurrent source searches for memory efficiency
|
|
127
|
+
const concurrentLimit = Math.min(this.MAX_CONCURRENT_SOURCES, enabledSources.length);
|
|
128
|
+
const sourceBatches = this.batchSources(enabledSources, concurrentLimit);
|
|
129
|
+
const allResults = [];
|
|
130
|
+
const sourceCount = { local: 0, github: 0, collection: 0 };
|
|
131
|
+
// Process sources in batches to control memory usage
|
|
132
|
+
for (const batch of sourceBatches) {
|
|
133
|
+
const batchPromises = batch.map(source => this.searchWithFallback(source, normalizedQuery, normalizedSearchOptions));
|
|
134
|
+
const batchResults = await Promise.allSettled(batchPromises);
|
|
135
|
+
batchResults.forEach((result, index) => {
|
|
136
|
+
const sourceName = batch[index];
|
|
137
|
+
if (result.status === 'fulfilled') {
|
|
138
|
+
sourceCount[sourceName] += result.value.length;
|
|
139
|
+
allResults.push(...result.value);
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
logger.warn(`Search failed for source ${sourceName}`, {
|
|
143
|
+
error: result.reason instanceof Error ? result.reason.message : String(result.reason)
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
// Memory check between batches
|
|
148
|
+
const currentMemory = process.memoryUsage().heapUsed / (1024 * 1024);
|
|
149
|
+
if (currentMemory > 200) { // 200MB threshold
|
|
150
|
+
logger.warn('High memory usage during search, triggering cleanup', {
|
|
151
|
+
memoryMB: currentMemory
|
|
152
|
+
});
|
|
153
|
+
this.triggerMemoryCleanup();
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
// Apply advanced processing with memory-efficient batching
|
|
157
|
+
const processedResults = await this.processSearchResultsOptimized(allResults, normalizedSearchOptions);
|
|
158
|
+
// Apply pagination
|
|
159
|
+
const paginatedResults = this.applyPagination(processedResults, normalizedSearchOptions);
|
|
160
|
+
// Cache results with memory limit check
|
|
161
|
+
if (paginatedResults.length < 1000) { // Don't cache very large result sets
|
|
162
|
+
this.resultCache.set(cacheKey, paginatedResults);
|
|
163
|
+
}
|
|
164
|
+
const duration = Date.now() - startTime;
|
|
165
|
+
const memoryAfter = process.memoryUsage().heapUsed;
|
|
166
|
+
this.recordSearchMetrics({
|
|
167
|
+
query: normalizedQuery,
|
|
168
|
+
duration,
|
|
169
|
+
resultCount: paginatedResults.length,
|
|
170
|
+
sources: enabledSources,
|
|
171
|
+
cacheHit: false,
|
|
172
|
+
memoryBefore,
|
|
173
|
+
memoryAfter,
|
|
174
|
+
timestamp: new Date()
|
|
175
|
+
});
|
|
176
|
+
logger.info('Optimized unified portfolio search completed', {
|
|
177
|
+
query: normalizedQuery.substring(0, 50),
|
|
178
|
+
sources: { ...sourceCount, total: allResults.length },
|
|
179
|
+
finalResults: paginatedResults.length,
|
|
180
|
+
duration: `${duration}ms`,
|
|
181
|
+
memoryUsageMB: (memoryAfter - memoryBefore) / (1024 * 1024)
|
|
182
|
+
});
|
|
183
|
+
return paginatedResults;
|
|
184
|
+
}
|
|
185
|
+
catch (error) {
|
|
186
|
+
const duration = Date.now() - startTime;
|
|
187
|
+
ErrorHandler.logError('UnifiedIndexManager.search', error, { query: normalizedSearchOptions, duration });
|
|
188
|
+
throw ErrorHandler.wrapError(error, 'Failed to perform unified portfolio search', ErrorCategory.SYSTEM_ERROR);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Find element by name across all portfolios
|
|
193
|
+
*/
|
|
194
|
+
async findByName(name, options = {}) {
|
|
195
|
+
try {
|
|
196
|
+
const searchOptions = {
|
|
197
|
+
query: name,
|
|
198
|
+
includeLocal: options.includeLocal ?? true,
|
|
199
|
+
includeGitHub: options.includeGitHub ?? true,
|
|
200
|
+
includeCollection: options.includeCollection ?? false,
|
|
201
|
+
pageSize: 1,
|
|
202
|
+
...options
|
|
203
|
+
};
|
|
204
|
+
const results = await this.search(searchOptions);
|
|
205
|
+
// Return exact name match first, then best match
|
|
206
|
+
const exactMatch = results.find(result => result.entry.name.toLowerCase() === name.toLowerCase());
|
|
207
|
+
return exactMatch?.entry || results[0]?.entry || null;
|
|
208
|
+
}
|
|
209
|
+
catch (error) {
|
|
210
|
+
ErrorHandler.logError('UnifiedIndexManager.findByName', error, { name });
|
|
211
|
+
return null;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Get elements by type from all portfolios
|
|
216
|
+
*/
|
|
217
|
+
async getElementsByType(elementType, options = {}) {
|
|
218
|
+
try {
|
|
219
|
+
const searchOptions = {
|
|
220
|
+
query: '', // Empty query to get all elements
|
|
221
|
+
elementType,
|
|
222
|
+
includeLocal: options.includeLocal ?? true,
|
|
223
|
+
includeGitHub: options.includeGitHub ?? true,
|
|
224
|
+
includeCollection: options.includeCollection ?? false,
|
|
225
|
+
pageSize: 1000, // Large page size to get all
|
|
226
|
+
...options
|
|
227
|
+
};
|
|
228
|
+
const results = await this.getAllElementsByType(elementType, searchOptions);
|
|
229
|
+
return this.deduplicateEntries(results.map(r => r.entry));
|
|
230
|
+
}
|
|
231
|
+
catch (error) {
|
|
232
|
+
ErrorHandler.logError('UnifiedIndexManager.getElementsByType', error, { elementType });
|
|
233
|
+
return [];
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Check for duplicates across all sources
|
|
238
|
+
*/
|
|
239
|
+
async checkDuplicates(name) {
|
|
240
|
+
try {
|
|
241
|
+
const searchOptions = {
|
|
242
|
+
query: name,
|
|
243
|
+
includeLocal: true,
|
|
244
|
+
includeGitHub: true,
|
|
245
|
+
includeCollection: true,
|
|
246
|
+
pageSize: 100
|
|
247
|
+
};
|
|
248
|
+
const results = await this.search(searchOptions);
|
|
249
|
+
const duplicateMap = new Map();
|
|
250
|
+
for (const result of results) {
|
|
251
|
+
const key = `${result.entry.elementType}:${result.entry.name.toLowerCase()}`;
|
|
252
|
+
if (!duplicateMap.has(key)) {
|
|
253
|
+
duplicateMap.set(key, {
|
|
254
|
+
name: result.entry.name,
|
|
255
|
+
elementType: result.entry.elementType,
|
|
256
|
+
sources: [],
|
|
257
|
+
hasVersionConflict: false
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
const duplicate = duplicateMap.get(key);
|
|
261
|
+
duplicate.sources.push({
|
|
262
|
+
source: result.source,
|
|
263
|
+
version: result.entry.version,
|
|
264
|
+
lastModified: result.entry.lastModified,
|
|
265
|
+
path: this.getPathFromEntry(result.entry)
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
// Filter to only items with multiple sources and check version conflicts
|
|
269
|
+
const actualDuplicates = Array.from(duplicateMap.values())
|
|
270
|
+
.filter(item => item.sources.length > 1)
|
|
271
|
+
.map(item => {
|
|
272
|
+
const versionConflict = this.detectVersionConflict(item.sources);
|
|
273
|
+
return {
|
|
274
|
+
...item,
|
|
275
|
+
hasVersionConflict: !!versionConflict,
|
|
276
|
+
versionConflict
|
|
277
|
+
};
|
|
278
|
+
});
|
|
279
|
+
return actualDuplicates;
|
|
280
|
+
}
|
|
281
|
+
catch (error) {
|
|
282
|
+
ErrorHandler.logError('UnifiedIndexManager.checkDuplicates', error, { name });
|
|
283
|
+
return [];
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Get version comparison across all sources
|
|
288
|
+
*/
|
|
289
|
+
async getVersionComparison(name) {
|
|
290
|
+
try {
|
|
291
|
+
const duplicates = await this.checkDuplicates(name);
|
|
292
|
+
if (duplicates.length === 0) {
|
|
293
|
+
return null;
|
|
294
|
+
}
|
|
295
|
+
const duplicate = duplicates[0];
|
|
296
|
+
const versions = {};
|
|
297
|
+
// Build version info
|
|
298
|
+
for (const source of duplicate.sources) {
|
|
299
|
+
if (source.source === 'local') {
|
|
300
|
+
versions.local = {
|
|
301
|
+
version: source.version || 'unknown',
|
|
302
|
+
lastModified: source.lastModified,
|
|
303
|
+
path: source.path || 'unknown'
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
else if (source.source === 'github') {
|
|
307
|
+
versions.github = {
|
|
308
|
+
version: source.version || 'unknown',
|
|
309
|
+
lastModified: source.lastModified,
|
|
310
|
+
path: source.path || 'unknown'
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
else if (source.source === 'collection') {
|
|
314
|
+
versions.collection = {
|
|
315
|
+
version: source.version || 'unknown',
|
|
316
|
+
lastModified: source.lastModified,
|
|
317
|
+
path: source.path || 'unknown'
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
// Determine recommendation
|
|
322
|
+
const recommendation = this.determineVersionRecommendation(versions);
|
|
323
|
+
return {
|
|
324
|
+
name: duplicate.name,
|
|
325
|
+
elementType: duplicate.elementType,
|
|
326
|
+
versions,
|
|
327
|
+
recommended: recommendation,
|
|
328
|
+
updateAvailable: recommendation.source !== 'local' && !!versions.local,
|
|
329
|
+
updateFrom: recommendation.source !== 'local' ? recommendation.source : undefined
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
catch (error) {
|
|
333
|
+
ErrorHandler.logError('UnifiedIndexManager.getVersionComparison', error, { name });
|
|
334
|
+
return null;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Get comprehensive statistics across all sources
|
|
339
|
+
*/
|
|
340
|
+
async getStats() {
|
|
341
|
+
try {
|
|
342
|
+
const [localStats, githubStats, collectionStats] = await Promise.allSettled([
|
|
343
|
+
this.getLocalStats(),
|
|
344
|
+
this.getGitHubStats(),
|
|
345
|
+
this.getCollectionStats()
|
|
346
|
+
]);
|
|
347
|
+
const local = localStats.status === 'fulfilled' ? localStats.value : {
|
|
348
|
+
totalElements: 0,
|
|
349
|
+
elementsByType: {},
|
|
350
|
+
lastBuilt: null,
|
|
351
|
+
isStale: true
|
|
352
|
+
};
|
|
353
|
+
const github = githubStats.status === 'fulfilled' ? githubStats.value : {
|
|
354
|
+
totalElements: 0,
|
|
355
|
+
elementsByType: {},
|
|
356
|
+
lastFetched: null,
|
|
357
|
+
isStale: true
|
|
358
|
+
};
|
|
359
|
+
const collection = collectionStats.status === 'fulfilled' ? collectionStats.value : {
|
|
360
|
+
totalElements: 0,
|
|
361
|
+
elementsByType: {},
|
|
362
|
+
lastFetched: null,
|
|
363
|
+
isStale: true
|
|
364
|
+
};
|
|
365
|
+
// Calculate combined statistics
|
|
366
|
+
const totalElements = local.totalElements + github.totalElements + collection.totalElements;
|
|
367
|
+
const duplicatesCount = await this.calculateDuplicatesCount();
|
|
368
|
+
const uniqueElements = totalElements - duplicatesCount;
|
|
369
|
+
return {
|
|
370
|
+
local,
|
|
371
|
+
github,
|
|
372
|
+
collection,
|
|
373
|
+
combined: {
|
|
374
|
+
totalElements,
|
|
375
|
+
uniqueElements,
|
|
376
|
+
duplicates: duplicatesCount
|
|
377
|
+
},
|
|
378
|
+
performance: {
|
|
379
|
+
averageSearchTime: this.getPerformanceStats().searchStats.averageTime || 0,
|
|
380
|
+
cacheHitRate: this.getPerformanceStats().searchStats.cacheHitRate || 0,
|
|
381
|
+
lastOptimized: null
|
|
382
|
+
}
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
catch (error) {
|
|
386
|
+
ErrorHandler.logError('UnifiedIndexManager.getStats', error);
|
|
387
|
+
throw error;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Invalidate caches after user actions with performance monitoring
|
|
392
|
+
*/
|
|
393
|
+
invalidateAfterAction(action) {
|
|
394
|
+
logger.info('Invalidating unified portfolio caches after user action', { action });
|
|
395
|
+
// Clear result and index caches
|
|
396
|
+
this.resultCache.clear();
|
|
397
|
+
this.indexCache.clear();
|
|
398
|
+
// Invalidate local cache
|
|
399
|
+
this.localIndexManager.rebuildIndex().catch(error => {
|
|
400
|
+
logger.warn('Failed to rebuild local index after action', {
|
|
401
|
+
action,
|
|
402
|
+
error: error instanceof Error ? error.message : String(error)
|
|
403
|
+
});
|
|
404
|
+
});
|
|
405
|
+
// Invalidate GitHub cache
|
|
406
|
+
this.githubIndexer.invalidateAfterAction(action);
|
|
407
|
+
// Invalidate collection cache
|
|
408
|
+
this.collectionIndexCache.clearCache().catch(error => {
|
|
409
|
+
logger.warn('Failed to clear collection cache after action', {
|
|
410
|
+
action,
|
|
411
|
+
error: error instanceof Error ? error.message : String(error)
|
|
412
|
+
});
|
|
413
|
+
});
|
|
414
|
+
// Trigger garbage collection if memory usage is high
|
|
415
|
+
this.triggerMemoryCleanup();
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* Force rebuild of all indexes with performance optimization
|
|
419
|
+
*/
|
|
420
|
+
async rebuildAll() {
|
|
421
|
+
const startTime = Date.now();
|
|
422
|
+
logger.info('Rebuilding all portfolio indexes with optimization...');
|
|
423
|
+
try {
|
|
424
|
+
// Clear all caches
|
|
425
|
+
this.resultCache.clear();
|
|
426
|
+
this.indexCache.clear();
|
|
427
|
+
// Reset performance counters
|
|
428
|
+
this.performanceMonitor.reset();
|
|
429
|
+
// Rebuild in parallel with memory monitoring
|
|
430
|
+
const rebuildPromises = [
|
|
431
|
+
this.localIndexManager.rebuildIndex(),
|
|
432
|
+
this.githubIndexer.clearCache(),
|
|
433
|
+
this.collectionIndexCache.clearCache()
|
|
434
|
+
];
|
|
435
|
+
await Promise.all(rebuildPromises);
|
|
436
|
+
// Trigger cleanup
|
|
437
|
+
this.triggerMemoryCleanup();
|
|
438
|
+
const duration = Date.now() - startTime;
|
|
439
|
+
logger.info('All portfolio indexes rebuilt successfully', {
|
|
440
|
+
duration: `${duration}ms`,
|
|
441
|
+
memoryUsageMB: process.memoryUsage().heapUsed / (1024 * 1024)
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
catch (error) {
|
|
445
|
+
ErrorHandler.logError('UnifiedIndexManager.rebuildAll', error);
|
|
446
|
+
throw error;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
// =====================================================
|
|
450
|
+
// PRIVATE HELPER METHODS
|
|
451
|
+
// =====================================================
|
|
452
|
+
/**
|
|
453
|
+
* Search with fallback strategies for resilient operation
|
|
454
|
+
*/
|
|
455
|
+
async searchWithFallback(source, query, options) {
|
|
456
|
+
const startTime = Date.now();
|
|
457
|
+
try {
|
|
458
|
+
let results = [];
|
|
459
|
+
switch (source) {
|
|
460
|
+
case 'local':
|
|
461
|
+
results = await this.searchLocal(query, options);
|
|
462
|
+
break;
|
|
463
|
+
case 'github':
|
|
464
|
+
results = await this.searchGitHub(query, options);
|
|
465
|
+
break;
|
|
466
|
+
case 'collection':
|
|
467
|
+
results = await this.searchCollection(query, options);
|
|
468
|
+
break;
|
|
469
|
+
}
|
|
470
|
+
logger.debug(`${source} search completed in ${Date.now() - startTime}ms with ${results.length} results`);
|
|
471
|
+
return results;
|
|
472
|
+
}
|
|
473
|
+
catch (error) {
|
|
474
|
+
logger.debug(`${source} search failed, attempting fallback`, {
|
|
475
|
+
error: error instanceof Error ? error.message : String(error)
|
|
476
|
+
});
|
|
477
|
+
// Fallback strategies
|
|
478
|
+
return await this.handleSearchFallback(source, query, options, error);
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
/**
|
|
482
|
+
* Handle search fallback strategies
|
|
483
|
+
*/
|
|
484
|
+
async handleSearchFallback(source, query, options, originalError) {
|
|
485
|
+
try {
|
|
486
|
+
switch (source) {
|
|
487
|
+
case 'local':
|
|
488
|
+
// Try to use stale local index
|
|
489
|
+
logger.debug('Attempting to use stale local index');
|
|
490
|
+
return await this.searchLocalStale(query, options);
|
|
491
|
+
case 'github':
|
|
492
|
+
// Try cached GitHub data
|
|
493
|
+
logger.debug('Attempting to use cached GitHub data');
|
|
494
|
+
return await this.searchGitHubCached(query, options);
|
|
495
|
+
case 'collection':
|
|
496
|
+
// Try cached collection data
|
|
497
|
+
logger.debug('Attempting to use cached collection data');
|
|
498
|
+
return await this.searchCollectionCached(query, options);
|
|
499
|
+
default:
|
|
500
|
+
return [];
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
catch (fallbackError) {
|
|
504
|
+
logger.warn(`All fallback strategies failed for ${source}`, {
|
|
505
|
+
originalError: originalError instanceof Error ? originalError.message : String(originalError),
|
|
506
|
+
fallbackError: fallbackError instanceof Error ? fallbackError.message : String(fallbackError)
|
|
507
|
+
});
|
|
508
|
+
return [];
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
/**
|
|
512
|
+
* Search local portfolio
|
|
513
|
+
*/
|
|
514
|
+
async searchLocal(query, options) {
|
|
515
|
+
const localOptions = this.convertToLocalOptions(options);
|
|
516
|
+
const results = await this.localIndexManager.search(query, localOptions);
|
|
517
|
+
return results.map(result => ({
|
|
518
|
+
source: 'local',
|
|
519
|
+
entry: this.convertLocalEntry(result.entry),
|
|
520
|
+
matchType: result.matchType,
|
|
521
|
+
score: result.score,
|
|
522
|
+
version: result.entry.metadata.version
|
|
523
|
+
}));
|
|
524
|
+
}
|
|
525
|
+
/**
|
|
526
|
+
* Search local with stale data fallback
|
|
527
|
+
*/
|
|
528
|
+
async searchLocalStale(query, options) {
|
|
529
|
+
try {
|
|
530
|
+
// Try to get any local data, even stale
|
|
531
|
+
const localOptions = this.convertToLocalOptions(options);
|
|
532
|
+
const results = await this.localIndexManager.search(query, localOptions);
|
|
533
|
+
return results.map(result => ({
|
|
534
|
+
source: 'local',
|
|
535
|
+
entry: this.convertLocalEntry(result.entry),
|
|
536
|
+
matchType: result.matchType,
|
|
537
|
+
score: result.score * 0.8, // Reduce score for stale data
|
|
538
|
+
version: result.entry.metadata.version
|
|
539
|
+
}));
|
|
540
|
+
}
|
|
541
|
+
catch {
|
|
542
|
+
return [];
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
/**
|
|
546
|
+
* Search GitHub portfolio
|
|
547
|
+
*/
|
|
548
|
+
async searchGitHub(query, options) {
|
|
549
|
+
try {
|
|
550
|
+
const githubIndex = await this.githubIndexer.getIndex();
|
|
551
|
+
const results = [];
|
|
552
|
+
const queryLower = query.toLowerCase();
|
|
553
|
+
const queryTokens = queryLower.split(/\s+/).filter(token => token.length > 0);
|
|
554
|
+
if (queryTokens.length === 0 && query.trim() !== '') {
|
|
555
|
+
return results;
|
|
556
|
+
}
|
|
557
|
+
// Search across all GitHub elements
|
|
558
|
+
for (const [elementType, entries] of githubIndex.elements) {
|
|
559
|
+
// Filter by element type if specified
|
|
560
|
+
if (options.elementType && elementType !== options.elementType) {
|
|
561
|
+
continue;
|
|
562
|
+
}
|
|
563
|
+
for (const entry of entries) {
|
|
564
|
+
const score = this.calculateGitHubMatchScore(entry, queryTokens, query);
|
|
565
|
+
if (score > 0 || query.trim() === '') {
|
|
566
|
+
results.push({
|
|
567
|
+
source: 'github',
|
|
568
|
+
entry: this.convertGitHubEntry(entry),
|
|
569
|
+
matchType: this.determineMatchType(entry, queryTokens),
|
|
570
|
+
score: query.trim() === '' ? 1 : score, // Default score for empty query
|
|
571
|
+
version: entry.version
|
|
572
|
+
});
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
return results.sort((a, b) => b.score - a.score);
|
|
577
|
+
}
|
|
578
|
+
catch (error) {
|
|
579
|
+
logger.debug('GitHub search failed', {
|
|
580
|
+
error: error instanceof Error ? error.message : String(error)
|
|
581
|
+
});
|
|
582
|
+
throw error; // Re-throw to trigger fallback
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
/**
|
|
586
|
+
* Search GitHub with cached data fallback
|
|
587
|
+
*/
|
|
588
|
+
async searchGitHubCached(query, options) {
|
|
589
|
+
try {
|
|
590
|
+
// Try to use stale GitHub data
|
|
591
|
+
const cacheStats = this.githubIndexer.getCacheStats();
|
|
592
|
+
if (!cacheStats.isStale) {
|
|
593
|
+
return await this.searchGitHub(query, options);
|
|
594
|
+
}
|
|
595
|
+
// Use stale data with reduced scores
|
|
596
|
+
const results = await this.searchGitHub(query, options);
|
|
597
|
+
return results.map(result => ({
|
|
598
|
+
...result,
|
|
599
|
+
score: result.score * 0.7 // Reduce score for stale data
|
|
600
|
+
}));
|
|
601
|
+
}
|
|
602
|
+
catch {
|
|
603
|
+
return [];
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
/**
|
|
607
|
+
* Search collection portfolio
|
|
608
|
+
*/
|
|
609
|
+
async searchCollection(query, options) {
|
|
610
|
+
try {
|
|
611
|
+
const collectionIndex = await this.collectionIndexCache.getIndex();
|
|
612
|
+
const results = [];
|
|
613
|
+
const queryLower = query.toLowerCase();
|
|
614
|
+
const queryTokens = queryLower.split(/\s+/).filter(token => token.length > 0);
|
|
615
|
+
if (queryTokens.length === 0 && query.trim() !== '') {
|
|
616
|
+
return results;
|
|
617
|
+
}
|
|
618
|
+
// Search across all collection elements
|
|
619
|
+
for (const [elementType, entries] of Object.entries(collectionIndex.index)) {
|
|
620
|
+
// Filter by element type if specified
|
|
621
|
+
if (options.elementType && elementType !== options.elementType.toString()) {
|
|
622
|
+
continue;
|
|
623
|
+
}
|
|
624
|
+
for (const entry of entries) {
|
|
625
|
+
const score = this.calculateCollectionMatchScore(entry, queryTokens, query);
|
|
626
|
+
if (score > 0 || query.trim() === '') {
|
|
627
|
+
results.push({
|
|
628
|
+
source: 'collection',
|
|
629
|
+
entry: this.convertCollectionEntry(entry, elementType),
|
|
630
|
+
matchType: this.determineCollectionMatchType(entry, queryTokens),
|
|
631
|
+
score: query.trim() === '' ? 1 : score, // Default score for empty query
|
|
632
|
+
version: entry.version
|
|
633
|
+
});
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
return results.sort((a, b) => b.score - a.score);
|
|
638
|
+
}
|
|
639
|
+
catch (error) {
|
|
640
|
+
logger.debug('Collection search failed', {
|
|
641
|
+
error: error instanceof Error ? error.message : String(error)
|
|
642
|
+
});
|
|
643
|
+
throw error; // Re-throw to trigger fallback
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
/**
|
|
647
|
+
* Search collection with cached data fallback
|
|
648
|
+
*/
|
|
649
|
+
async searchCollectionCached(query, options) {
|
|
650
|
+
try {
|
|
651
|
+
// Try to use stale collection data
|
|
652
|
+
const cacheStats = this.collectionIndexCache.getCacheStats();
|
|
653
|
+
if (cacheStats.isValid) {
|
|
654
|
+
return await this.searchCollection(query, options);
|
|
655
|
+
}
|
|
656
|
+
// Use stale data with reduced scores
|
|
657
|
+
const results = await this.searchCollection(query, options);
|
|
658
|
+
return results.map(result => ({
|
|
659
|
+
...result,
|
|
660
|
+
score: result.score * 0.6 // Reduce score for stale collection data
|
|
661
|
+
}));
|
|
662
|
+
}
|
|
663
|
+
catch {
|
|
664
|
+
return [];
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
/**
|
|
668
|
+
* Process search results with advanced features
|
|
669
|
+
*/
|
|
670
|
+
async processSearchResults(results, options) {
|
|
671
|
+
// Apply smart ranking
|
|
672
|
+
const rankedResults = this.applySmartRanking(results, options);
|
|
673
|
+
// Detect duplicates and version conflicts
|
|
674
|
+
const processedResults = await this.detectDuplicatesAndConflicts(rankedResults);
|
|
675
|
+
// Apply sorting
|
|
676
|
+
const sortedResults = this.applySorting(processedResults, options.sortBy || 'relevance', options.query);
|
|
677
|
+
return sortedResults;
|
|
678
|
+
}
|
|
679
|
+
/**
|
|
680
|
+
* Apply smart result ranking
|
|
681
|
+
*/
|
|
682
|
+
applySmartRanking(results, options) {
|
|
683
|
+
return results.map(result => {
|
|
684
|
+
let adjustedScore = result.score;
|
|
685
|
+
// No location-based scoring - score should be based on relevance only
|
|
686
|
+
// Source location doesn't affect the intrinsic value of an element
|
|
687
|
+
// Consider version freshness (newer versions get small bonus)
|
|
688
|
+
if (result.version && result.version !== 'unknown') {
|
|
689
|
+
const versionParts = result.version.split('.');
|
|
690
|
+
if (versionParts.length >= 2) {
|
|
691
|
+
const major = parseInt(versionParts[0]) || 0;
|
|
692
|
+
const minor = parseInt(versionParts[1]) || 0;
|
|
693
|
+
adjustedScore += (major * 0.1) + (minor * 0.01);
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
// Boost exact matches
|
|
697
|
+
if (result.entry.name.toLowerCase() === options.query.toLowerCase()) {
|
|
698
|
+
adjustedScore *= 2.0;
|
|
699
|
+
}
|
|
700
|
+
return {
|
|
701
|
+
...result,
|
|
702
|
+
score: adjustedScore
|
|
703
|
+
};
|
|
704
|
+
});
|
|
705
|
+
}
|
|
706
|
+
/**
|
|
707
|
+
* Detect duplicates and version conflicts
|
|
708
|
+
*/
|
|
709
|
+
async detectDuplicatesAndConflicts(results) {
|
|
710
|
+
const nameMap = new Map();
|
|
711
|
+
// Group by name and element type
|
|
712
|
+
for (const result of results) {
|
|
713
|
+
const key = `${result.entry.elementType}:${result.entry.name.toLowerCase()}`;
|
|
714
|
+
if (!nameMap.has(key)) {
|
|
715
|
+
nameMap.set(key, []);
|
|
716
|
+
}
|
|
717
|
+
nameMap.get(key).push(result);
|
|
718
|
+
}
|
|
719
|
+
const processedResults = [];
|
|
720
|
+
// Process each group
|
|
721
|
+
for (const [key, groupResults] of nameMap) {
|
|
722
|
+
if (groupResults.length === 1) {
|
|
723
|
+
// No duplicates
|
|
724
|
+
processedResults.push(groupResults[0]);
|
|
725
|
+
}
|
|
726
|
+
else {
|
|
727
|
+
// Has duplicates - detect version conflicts
|
|
728
|
+
const versionConflict = this.detectVersionConflictFromResults(groupResults);
|
|
729
|
+
// Mark all results as duplicates and add conflict info
|
|
730
|
+
for (const result of groupResults) {
|
|
731
|
+
processedResults.push({
|
|
732
|
+
...result,
|
|
733
|
+
isDuplicate: true,
|
|
734
|
+
versionConflict
|
|
735
|
+
});
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
return processedResults;
|
|
740
|
+
}
|
|
741
|
+
/**
|
|
742
|
+
* Apply pagination to results
|
|
743
|
+
*/
|
|
744
|
+
applyPagination(results, options) {
|
|
745
|
+
const page = options.page || 1;
|
|
746
|
+
const pageSize = options.pageSize || 20;
|
|
747
|
+
const startIndex = (page - 1) * pageSize;
|
|
748
|
+
const endIndex = startIndex + pageSize;
|
|
749
|
+
return results.slice(startIndex, endIndex);
|
|
750
|
+
}
|
|
751
|
+
/**
|
|
752
|
+
* Apply sorting to results
|
|
753
|
+
*/
|
|
754
|
+
applySorting(results, sortBy, query) {
|
|
755
|
+
const sorted = [...results];
|
|
756
|
+
switch (sortBy) {
|
|
757
|
+
case 'name':
|
|
758
|
+
sorted.sort((a, b) => a.entry.name.localeCompare(b.entry.name));
|
|
759
|
+
break;
|
|
760
|
+
case 'source':
|
|
761
|
+
sorted.sort((a, b) => {
|
|
762
|
+
const sourceOrder = { 'local': 0, 'github': 1, 'collection': 2 };
|
|
763
|
+
return sourceOrder[a.source] - sourceOrder[b.source];
|
|
764
|
+
});
|
|
765
|
+
break;
|
|
766
|
+
case 'version':
|
|
767
|
+
sorted.sort((a, b) => this.compareVersions(b.version || '0', a.version || '0'));
|
|
768
|
+
break;
|
|
769
|
+
case 'relevance':
|
|
770
|
+
default:
|
|
771
|
+
sorted.sort((a, b) => b.score - a.score);
|
|
772
|
+
break;
|
|
773
|
+
}
|
|
774
|
+
return sorted;
|
|
775
|
+
}
|
|
776
|
+
/**
|
|
777
|
+
* Calculate match score for GitHub entries
|
|
778
|
+
*/
|
|
779
|
+
calculateGitHubMatchScore(entry, queryTokens, query) {
|
|
780
|
+
if (queryTokens.length === 0)
|
|
781
|
+
return 1; // Default score for empty query
|
|
782
|
+
let score = 0;
|
|
783
|
+
const name = entry.name.toLowerCase();
|
|
784
|
+
const description = (entry.description || '').toLowerCase();
|
|
785
|
+
const path = (entry.path || '').toLowerCase();
|
|
786
|
+
// Check name matches
|
|
787
|
+
for (const token of queryTokens) {
|
|
788
|
+
if (name.includes(token)) {
|
|
789
|
+
score += name === token ? 10 : (name.startsWith(token) ? 5 : 2);
|
|
790
|
+
}
|
|
791
|
+
if (description.includes(token)) {
|
|
792
|
+
score += 3;
|
|
793
|
+
}
|
|
794
|
+
if (path.includes(token)) {
|
|
795
|
+
score += 1;
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
// Exact query match bonus
|
|
799
|
+
if (name.includes(query.toLowerCase())) {
|
|
800
|
+
score += query.length > 3 ? 15 : 10;
|
|
801
|
+
}
|
|
802
|
+
return score;
|
|
803
|
+
}
|
|
804
|
+
/**
|
|
805
|
+
* Calculate match score for collection entries
|
|
806
|
+
*/
|
|
807
|
+
calculateCollectionMatchScore(entry, queryTokens, query) {
|
|
808
|
+
if (queryTokens.length === 0)
|
|
809
|
+
return 1; // Default score for empty query
|
|
810
|
+
let score = 0;
|
|
811
|
+
const name = entry.name.toLowerCase();
|
|
812
|
+
const description = (entry.description || '').toLowerCase();
|
|
813
|
+
const path = (entry.path || '').toLowerCase();
|
|
814
|
+
const tags = entry.tags.map(tag => tag.toLowerCase()).join(' ');
|
|
815
|
+
// Check matches across all fields
|
|
816
|
+
for (const token of queryTokens) {
|
|
817
|
+
if (name.includes(token)) {
|
|
818
|
+
score += name === token ? 10 : (name.startsWith(token) ? 5 : 2);
|
|
819
|
+
}
|
|
820
|
+
if (description.includes(token)) {
|
|
821
|
+
score += 3;
|
|
822
|
+
}
|
|
823
|
+
if (path.includes(token)) {
|
|
824
|
+
score += 1;
|
|
825
|
+
}
|
|
826
|
+
if (tags.includes(token)) {
|
|
827
|
+
score += 4;
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
// Exact query match bonus
|
|
831
|
+
if (name.includes(query.toLowerCase())) {
|
|
832
|
+
score += query.length > 3 ? 15 : 10;
|
|
833
|
+
}
|
|
834
|
+
return score;
|
|
835
|
+
}
|
|
836
|
+
/**
|
|
837
|
+
* Get all elements by type across sources
|
|
838
|
+
*/
|
|
839
|
+
async getAllElementsByType(elementType, options) {
|
|
840
|
+
const promises = [];
|
|
841
|
+
if (options.includeLocal) {
|
|
842
|
+
promises.push(this.getLocalElementsByType(elementType));
|
|
843
|
+
}
|
|
844
|
+
if (options.includeGitHub) {
|
|
845
|
+
promises.push(this.getGitHubElementsByType(elementType));
|
|
846
|
+
}
|
|
847
|
+
if (options.includeCollection) {
|
|
848
|
+
promises.push(this.getCollectionElementsByType(elementType));
|
|
849
|
+
}
|
|
850
|
+
const results = await Promise.allSettled(promises);
|
|
851
|
+
const allResults = [];
|
|
852
|
+
results.forEach(result => {
|
|
853
|
+
if (result.status === 'fulfilled') {
|
|
854
|
+
allResults.push(...result.value);
|
|
855
|
+
}
|
|
856
|
+
});
|
|
857
|
+
return allResults;
|
|
858
|
+
}
|
|
859
|
+
/**
|
|
860
|
+
* Get local elements by type
|
|
861
|
+
*/
|
|
862
|
+
async getLocalElementsByType(elementType) {
|
|
863
|
+
try {
|
|
864
|
+
const elements = await this.localIndexManager.getElementsByType(elementType);
|
|
865
|
+
return elements.map(entry => ({
|
|
866
|
+
source: 'local',
|
|
867
|
+
entry: this.convertLocalEntry(entry),
|
|
868
|
+
matchType: 'type',
|
|
869
|
+
score: 1,
|
|
870
|
+
version: entry.metadata.version
|
|
871
|
+
}));
|
|
872
|
+
}
|
|
873
|
+
catch {
|
|
874
|
+
return [];
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
/**
|
|
878
|
+
* Get GitHub elements by type
|
|
879
|
+
*/
|
|
880
|
+
async getGitHubElementsByType(elementType) {
|
|
881
|
+
try {
|
|
882
|
+
const githubIndex = await this.githubIndexer.getIndex();
|
|
883
|
+
const entries = githubIndex.elements.get(elementType) || [];
|
|
884
|
+
return entries.map(entry => ({
|
|
885
|
+
source: 'github',
|
|
886
|
+
entry: this.convertGitHubEntry(entry),
|
|
887
|
+
matchType: 'type',
|
|
888
|
+
score: 1,
|
|
889
|
+
version: entry.version
|
|
890
|
+
}));
|
|
891
|
+
}
|
|
892
|
+
catch {
|
|
893
|
+
return [];
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
/**
|
|
897
|
+
* Get collection elements by type
|
|
898
|
+
*/
|
|
899
|
+
async getCollectionElementsByType(elementType) {
|
|
900
|
+
try {
|
|
901
|
+
const collectionIndex = await this.collectionIndexCache.getIndex();
|
|
902
|
+
const entries = collectionIndex.index[elementType.toString()] || [];
|
|
903
|
+
return entries.map(entry => ({
|
|
904
|
+
source: 'collection',
|
|
905
|
+
entry: this.convertCollectionEntry(entry, elementType.toString()),
|
|
906
|
+
matchType: 'type',
|
|
907
|
+
score: 1,
|
|
908
|
+
version: entry.version
|
|
909
|
+
}));
|
|
910
|
+
}
|
|
911
|
+
catch {
|
|
912
|
+
return [];
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
/**
|
|
916
|
+
* Get local portfolio statistics
|
|
917
|
+
*/
|
|
918
|
+
async getLocalStats() {
|
|
919
|
+
return await this.localIndexManager.getStats();
|
|
920
|
+
}
|
|
921
|
+
/**
|
|
922
|
+
* Get GitHub portfolio statistics
|
|
923
|
+
*/
|
|
924
|
+
async getGitHubStats() {
|
|
925
|
+
const cacheStats = this.githubIndexer.getCacheStats();
|
|
926
|
+
const githubIndex = await this.githubIndexer.getIndex();
|
|
927
|
+
const elementsByType = {};
|
|
928
|
+
for (const elementType of Object.values(ElementType)) {
|
|
929
|
+
elementsByType[elementType] = (githubIndex.elements.get(elementType) || []).length;
|
|
930
|
+
}
|
|
931
|
+
return {
|
|
932
|
+
totalElements: githubIndex.totalElements,
|
|
933
|
+
elementsByType,
|
|
934
|
+
lastFetched: cacheStats.lastFetch,
|
|
935
|
+
isStale: cacheStats.isStale,
|
|
936
|
+
username: githubIndex.username,
|
|
937
|
+
repository: githubIndex.repository
|
|
938
|
+
};
|
|
939
|
+
}
|
|
940
|
+
/**
|
|
941
|
+
* Get collection portfolio statistics
|
|
942
|
+
*/
|
|
943
|
+
async getCollectionStats() {
|
|
944
|
+
const cacheStats = this.collectionIndexCache.getCacheStats();
|
|
945
|
+
const collectionIndex = await this.collectionIndexCache.getIndex();
|
|
946
|
+
const elementsByType = {};
|
|
947
|
+
for (const [elementType, entries] of Object.entries(collectionIndex.index)) {
|
|
948
|
+
elementsByType[elementType] = entries.length;
|
|
949
|
+
}
|
|
950
|
+
return {
|
|
951
|
+
totalElements: collectionIndex.total_elements,
|
|
952
|
+
elementsByType,
|
|
953
|
+
lastFetched: cacheStats.hasCache ? new Date(Date.now() - cacheStats.age) : null,
|
|
954
|
+
isStale: !cacheStats.isValid,
|
|
955
|
+
version: collectionIndex.version
|
|
956
|
+
};
|
|
957
|
+
}
|
|
958
|
+
/**
|
|
959
|
+
* Calculate duplicates count across all sources
|
|
960
|
+
*/
|
|
961
|
+
async calculateDuplicatesCount() {
|
|
962
|
+
try {
|
|
963
|
+
// This is a placeholder - actual implementation would need optimization
|
|
964
|
+
// For now, return 0 to avoid the expensive operation during stats calculation
|
|
965
|
+
return 0;
|
|
966
|
+
}
|
|
967
|
+
catch {
|
|
968
|
+
return 0;
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
/**
|
|
972
|
+
* Convert local index entry to unified format
|
|
973
|
+
*/
|
|
974
|
+
convertLocalEntry(entry) {
|
|
975
|
+
return {
|
|
976
|
+
name: entry.metadata.name,
|
|
977
|
+
description: entry.metadata.description,
|
|
978
|
+
version: entry.metadata.version,
|
|
979
|
+
author: entry.metadata.author,
|
|
980
|
+
elementType: entry.elementType,
|
|
981
|
+
lastModified: entry.lastModified,
|
|
982
|
+
source: 'local',
|
|
983
|
+
localFilePath: entry.filePath,
|
|
984
|
+
filename: entry.filename,
|
|
985
|
+
tags: entry.metadata.tags,
|
|
986
|
+
keywords: entry.metadata.keywords,
|
|
987
|
+
triggers: entry.metadata.triggers,
|
|
988
|
+
category: entry.metadata.category
|
|
989
|
+
};
|
|
990
|
+
}
|
|
991
|
+
/**
|
|
992
|
+
* Convert GitHub index entry to unified format
|
|
993
|
+
*/
|
|
994
|
+
convertGitHubEntry(entry) {
|
|
995
|
+
return {
|
|
996
|
+
name: entry.name,
|
|
997
|
+
description: entry.description,
|
|
998
|
+
version: entry.version,
|
|
999
|
+
author: entry.author,
|
|
1000
|
+
elementType: entry.elementType,
|
|
1001
|
+
lastModified: entry.lastModified,
|
|
1002
|
+
source: 'github',
|
|
1003
|
+
githubPath: entry.path,
|
|
1004
|
+
githubSha: entry.sha,
|
|
1005
|
+
githubHtmlUrl: entry.htmlUrl,
|
|
1006
|
+
githubDownloadUrl: entry.downloadUrl,
|
|
1007
|
+
githubSize: entry.size
|
|
1008
|
+
};
|
|
1009
|
+
}
|
|
1010
|
+
/**
|
|
1011
|
+
* Convert collection index entry to unified format
|
|
1012
|
+
*/
|
|
1013
|
+
convertCollectionEntry(entry, elementType) {
|
|
1014
|
+
return {
|
|
1015
|
+
name: entry.name,
|
|
1016
|
+
description: entry.description,
|
|
1017
|
+
version: entry.version,
|
|
1018
|
+
author: entry.author,
|
|
1019
|
+
elementType: this.mapStringToElementType(elementType),
|
|
1020
|
+
lastModified: new Date(entry.created),
|
|
1021
|
+
source: 'collection',
|
|
1022
|
+
collectionPath: entry.path,
|
|
1023
|
+
collectionSha: entry.sha,
|
|
1024
|
+
collectionTags: entry.tags,
|
|
1025
|
+
collectionCategory: entry.category,
|
|
1026
|
+
collectionLicense: entry.license
|
|
1027
|
+
};
|
|
1028
|
+
}
|
|
1029
|
+
/**
|
|
1030
|
+
* Map string to ElementType enum
|
|
1031
|
+
*/
|
|
1032
|
+
mapStringToElementType(elementType) {
|
|
1033
|
+
// Handle mapping from collection element types to our ElementType enum
|
|
1034
|
+
switch (elementType.toLowerCase()) {
|
|
1035
|
+
case 'personas':
|
|
1036
|
+
return ElementType.PERSONA;
|
|
1037
|
+
case 'skills':
|
|
1038
|
+
return ElementType.SKILL;
|
|
1039
|
+
case 'agents':
|
|
1040
|
+
return ElementType.AGENT;
|
|
1041
|
+
case 'prompts':
|
|
1042
|
+
case 'templates':
|
|
1043
|
+
return ElementType.TEMPLATE; // Map prompts and templates to TEMPLATE
|
|
1044
|
+
case 'tools':
|
|
1045
|
+
return ElementType.SKILL; // Map tools to SKILL as fallback
|
|
1046
|
+
case 'ensembles':
|
|
1047
|
+
return ElementType.ENSEMBLE;
|
|
1048
|
+
case 'memories':
|
|
1049
|
+
return ElementType.MEMORY;
|
|
1050
|
+
default:
|
|
1051
|
+
return ElementType.SKILL; // Default fallback
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
/**
|
|
1055
|
+
* Convert unified search options to local search options
|
|
1056
|
+
*/
|
|
1057
|
+
convertToLocalOptions(options) {
|
|
1058
|
+
return {
|
|
1059
|
+
elementType: options.elementType,
|
|
1060
|
+
maxResults: options.pageSize || 20
|
|
1061
|
+
};
|
|
1062
|
+
}
|
|
1063
|
+
/**
|
|
1064
|
+
* Determine match type for GitHub entries
|
|
1065
|
+
*/
|
|
1066
|
+
determineMatchType(entry, queryTokens) {
|
|
1067
|
+
const name = entry.name.toLowerCase();
|
|
1068
|
+
const description = (entry.description || '').toLowerCase();
|
|
1069
|
+
// Check what matched
|
|
1070
|
+
for (const token of queryTokens) {
|
|
1071
|
+
if (name.includes(token)) {
|
|
1072
|
+
return name === token ? 'exact_name' : 'name';
|
|
1073
|
+
}
|
|
1074
|
+
if (description.includes(token)) {
|
|
1075
|
+
return 'description';
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
return 'content';
|
|
1079
|
+
}
|
|
1080
|
+
/**
|
|
1081
|
+
* Determine match type for collection entries
|
|
1082
|
+
*/
|
|
1083
|
+
determineCollectionMatchType(entry, queryTokens) {
|
|
1084
|
+
const name = entry.name.toLowerCase();
|
|
1085
|
+
const description = (entry.description || '').toLowerCase();
|
|
1086
|
+
const tags = entry.tags.map(tag => tag.toLowerCase()).join(' ');
|
|
1087
|
+
// Check what matched
|
|
1088
|
+
for (const token of queryTokens) {
|
|
1089
|
+
if (name.includes(token)) {
|
|
1090
|
+
return name === token ? 'exact_name' : 'name';
|
|
1091
|
+
}
|
|
1092
|
+
if (description.includes(token)) {
|
|
1093
|
+
return 'description';
|
|
1094
|
+
}
|
|
1095
|
+
if (tags.includes(token)) {
|
|
1096
|
+
return 'tag';
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
return 'content';
|
|
1100
|
+
}
|
|
1101
|
+
/**
|
|
1102
|
+
* Get path from unified entry
|
|
1103
|
+
*/
|
|
1104
|
+
getPathFromEntry(entry) {
|
|
1105
|
+
switch (entry.source) {
|
|
1106
|
+
case 'local':
|
|
1107
|
+
return entry.localFilePath || entry.filename || 'unknown';
|
|
1108
|
+
case 'github':
|
|
1109
|
+
return entry.githubPath || 'unknown';
|
|
1110
|
+
case 'collection':
|
|
1111
|
+
return entry.collectionPath || 'unknown';
|
|
1112
|
+
default:
|
|
1113
|
+
return 'unknown';
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
/**
|
|
1117
|
+
* Detect version conflict from sources
|
|
1118
|
+
*/
|
|
1119
|
+
detectVersionConflict(sources) {
|
|
1120
|
+
const versions = new Map();
|
|
1121
|
+
for (const source of sources) {
|
|
1122
|
+
if (source.version && source.version !== 'unknown') {
|
|
1123
|
+
versions.set(source.version, source.source);
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
if (versions.size <= 1) {
|
|
1127
|
+
return undefined; // No conflict if all versions are the same or missing
|
|
1128
|
+
}
|
|
1129
|
+
// Build version conflict info
|
|
1130
|
+
const versionConflict = {
|
|
1131
|
+
recommended: 'local',
|
|
1132
|
+
reason: 'Multiple versions detected'
|
|
1133
|
+
};
|
|
1134
|
+
for (const source of sources) {
|
|
1135
|
+
if (source.version) {
|
|
1136
|
+
versionConflict[source.source] = source.version;
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
// Determine recommendation
|
|
1140
|
+
const recommendation = this.determineVersionRecommendationFromSources(sources);
|
|
1141
|
+
versionConflict.recommended = recommendation.source;
|
|
1142
|
+
versionConflict.reason = recommendation.reason;
|
|
1143
|
+
return versionConflict;
|
|
1144
|
+
}
|
|
1145
|
+
/**
|
|
1146
|
+
* Detect version conflict from search results
|
|
1147
|
+
*/
|
|
1148
|
+
detectVersionConflictFromResults(results) {
|
|
1149
|
+
const sources = results.map(result => ({
|
|
1150
|
+
source: result.source,
|
|
1151
|
+
version: result.version,
|
|
1152
|
+
lastModified: result.entry.lastModified,
|
|
1153
|
+
path: this.getPathFromEntry(result.entry)
|
|
1154
|
+
}));
|
|
1155
|
+
return this.detectVersionConflict(sources);
|
|
1156
|
+
}
|
|
1157
|
+
/**
|
|
1158
|
+
* Determine version recommendation from version info
|
|
1159
|
+
*/
|
|
1160
|
+
determineVersionRecommendation(versions) {
|
|
1161
|
+
// Prefer local if available and not too old
|
|
1162
|
+
if (versions.local) {
|
|
1163
|
+
const localAge = Date.now() - versions.local.lastModified.getTime();
|
|
1164
|
+
const sevenDays = 7 * 24 * 60 * 60 * 1000;
|
|
1165
|
+
if (localAge < sevenDays) {
|
|
1166
|
+
return { source: 'local', reason: 'Local version is recent and authoritative' };
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
// Compare versions if available
|
|
1170
|
+
const versionEntries = Object.entries(versions).filter(([_, info]) => info?.version);
|
|
1171
|
+
if (versionEntries.length > 1) {
|
|
1172
|
+
// Find highest version
|
|
1173
|
+
let highest = {
|
|
1174
|
+
source: 'local',
|
|
1175
|
+
version: '0.0.0'
|
|
1176
|
+
};
|
|
1177
|
+
for (const [source, info] of versionEntries) {
|
|
1178
|
+
if (info && this.compareVersions(info.version, highest.version) > 0) {
|
|
1179
|
+
highest = {
|
|
1180
|
+
source: source,
|
|
1181
|
+
version: info.version
|
|
1182
|
+
};
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
return { source: highest.source, reason: `Highest version (${highest.version})` };
|
|
1186
|
+
}
|
|
1187
|
+
// Fallback to most recent
|
|
1188
|
+
let mostRecent = {
|
|
1189
|
+
source: 'local',
|
|
1190
|
+
date: new Date(0)
|
|
1191
|
+
};
|
|
1192
|
+
for (const [source, info] of Object.entries(versions)) {
|
|
1193
|
+
if (info && info.lastModified > mostRecent.date) {
|
|
1194
|
+
mostRecent = {
|
|
1195
|
+
source: source,
|
|
1196
|
+
date: info.lastModified
|
|
1197
|
+
};
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
return { source: mostRecent.source, reason: 'Most recently modified' };
|
|
1201
|
+
}
|
|
1202
|
+
/**
|
|
1203
|
+
* Determine version recommendation from sources
|
|
1204
|
+
*/
|
|
1205
|
+
determineVersionRecommendationFromSources(sources) {
|
|
1206
|
+
// Convert sources to versions format
|
|
1207
|
+
const versions = {};
|
|
1208
|
+
for (const source of sources) {
|
|
1209
|
+
if (source.source === 'local') {
|
|
1210
|
+
versions.local = {
|
|
1211
|
+
version: source.version || 'unknown',
|
|
1212
|
+
lastModified: source.lastModified,
|
|
1213
|
+
path: source.path || 'unknown'
|
|
1214
|
+
};
|
|
1215
|
+
}
|
|
1216
|
+
else if (source.source === 'github') {
|
|
1217
|
+
versions.github = {
|
|
1218
|
+
version: source.version || 'unknown',
|
|
1219
|
+
lastModified: source.lastModified,
|
|
1220
|
+
path: source.path || 'unknown'
|
|
1221
|
+
};
|
|
1222
|
+
}
|
|
1223
|
+
else if (source.source === 'collection') {
|
|
1224
|
+
versions.collection = {
|
|
1225
|
+
version: source.version || 'unknown',
|
|
1226
|
+
lastModified: source.lastModified,
|
|
1227
|
+
path: source.path || 'unknown'
|
|
1228
|
+
};
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
return this.determineVersionRecommendation(versions);
|
|
1232
|
+
}
|
|
1233
|
+
/**
|
|
1234
|
+
* Compare semantic versions
|
|
1235
|
+
*/
|
|
1236
|
+
compareVersions(a, b) {
|
|
1237
|
+
const parseVersion = (version) => {
|
|
1238
|
+
const parts = version.split('.').map(part => parseInt(part) || 0);
|
|
1239
|
+
return [parts[0] || 0, parts[1] || 0, parts[2] || 0];
|
|
1240
|
+
};
|
|
1241
|
+
const [aMajor, aMinor, aPatch] = parseVersion(a);
|
|
1242
|
+
const [bMajor, bMinor, bPatch] = parseVersion(b);
|
|
1243
|
+
if (aMajor !== bMajor)
|
|
1244
|
+
return aMajor - bMajor;
|
|
1245
|
+
if (aMinor !== bMinor)
|
|
1246
|
+
return aMinor - bMinor;
|
|
1247
|
+
return aPatch - bPatch;
|
|
1248
|
+
}
|
|
1249
|
+
/**
|
|
1250
|
+
* Remove duplicate results based on name and type
|
|
1251
|
+
*/
|
|
1252
|
+
deduplicateResults(results) {
|
|
1253
|
+
const seen = new Set();
|
|
1254
|
+
const deduplicated = [];
|
|
1255
|
+
for (const result of results) {
|
|
1256
|
+
const key = `${result.entry.elementType}:${result.entry.name.toLowerCase()}`;
|
|
1257
|
+
if (!seen.has(key)) {
|
|
1258
|
+
seen.add(key);
|
|
1259
|
+
deduplicated.push(result);
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
1262
|
+
return deduplicated;
|
|
1263
|
+
}
|
|
1264
|
+
/**
|
|
1265
|
+
* Remove duplicate entries based on name and type
|
|
1266
|
+
*/
|
|
1267
|
+
deduplicateEntries(entries) {
|
|
1268
|
+
const seen = new Set();
|
|
1269
|
+
const deduplicated = [];
|
|
1270
|
+
for (const entry of entries) {
|
|
1271
|
+
const key = `${entry.elementType}:${entry.name.toLowerCase()}`;
|
|
1272
|
+
if (!seen.has(key)) {
|
|
1273
|
+
seen.add(key);
|
|
1274
|
+
deduplicated.push(entry);
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
return deduplicated;
|
|
1278
|
+
}
|
|
1279
|
+
// =====================================================
|
|
1280
|
+
// PERFORMANCE MONITORING AND OPTIMIZATION
|
|
1281
|
+
// =====================================================
|
|
1282
|
+
/**
|
|
1283
|
+
* Stream search results for better performance with large datasets
|
|
1284
|
+
*/
|
|
1285
|
+
async streamSearch(options) {
|
|
1286
|
+
const { query, cursor, maxResults = 1000 } = options;
|
|
1287
|
+
const startTime = Date.now();
|
|
1288
|
+
logger.debug('Starting streaming search', { query: query.substring(0, 50), cursor, maxResults });
|
|
1289
|
+
const results = [];
|
|
1290
|
+
const sources = this.getEnabledSources(options);
|
|
1291
|
+
// Process sources in sequence for memory efficiency
|
|
1292
|
+
for (const source of sources) {
|
|
1293
|
+
if (results.length >= maxResults) {
|
|
1294
|
+
break;
|
|
1295
|
+
}
|
|
1296
|
+
try {
|
|
1297
|
+
const sourceResults = await this.searchWithFallback(source, query, {
|
|
1298
|
+
...options,
|
|
1299
|
+
pageSize: Math.min(this.BATCH_SIZE, maxResults - results.length)
|
|
1300
|
+
});
|
|
1301
|
+
results.push(...sourceResults);
|
|
1302
|
+
// Add cursor information for pagination
|
|
1303
|
+
sourceResults.forEach((result, index) => {
|
|
1304
|
+
result.cursor = this.generateCursor(source, index);
|
|
1305
|
+
});
|
|
1306
|
+
}
|
|
1307
|
+
catch (error) {
|
|
1308
|
+
logger.warn(`Streaming search failed for source ${source}`, {
|
|
1309
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1310
|
+
});
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1313
|
+
logger.debug('Streaming search completed', {
|
|
1314
|
+
resultCount: results.length,
|
|
1315
|
+
duration: `${Date.now() - startTime}ms`
|
|
1316
|
+
});
|
|
1317
|
+
return results;
|
|
1318
|
+
}
|
|
1319
|
+
/**
|
|
1320
|
+
* Process search results with memory-efficient batching
|
|
1321
|
+
*/
|
|
1322
|
+
async processSearchResultsOptimized(results, options) {
|
|
1323
|
+
if (results.length === 0) {
|
|
1324
|
+
return results;
|
|
1325
|
+
}
|
|
1326
|
+
// Process in batches to avoid memory spikes with large result sets
|
|
1327
|
+
const batchSize = Math.min(this.BATCH_SIZE, results.length);
|
|
1328
|
+
const processedResults = [];
|
|
1329
|
+
for (let i = 0; i < results.length; i += batchSize) {
|
|
1330
|
+
const batch = results.slice(i, i + batchSize);
|
|
1331
|
+
// Apply smart ranking
|
|
1332
|
+
const rankedBatch = this.applySmartRanking(batch, options);
|
|
1333
|
+
// Detect duplicates and conflicts
|
|
1334
|
+
const processedBatch = await this.detectDuplicatesAndConflicts(rankedBatch);
|
|
1335
|
+
processedResults.push(...processedBatch);
|
|
1336
|
+
// Yield control to prevent blocking
|
|
1337
|
+
if (i % (batchSize * 4) === 0) {
|
|
1338
|
+
await new Promise(resolve => setImmediate(resolve));
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
// Apply final sorting
|
|
1342
|
+
return this.applySorting(processedResults, options.sortBy || 'relevance', options.query);
|
|
1343
|
+
}
|
|
1344
|
+
/**
|
|
1345
|
+
* Get enabled search sources
|
|
1346
|
+
*/
|
|
1347
|
+
getEnabledSources(options) {
|
|
1348
|
+
const sources = [];
|
|
1349
|
+
if (options.includeLocal !== false)
|
|
1350
|
+
sources.push('local');
|
|
1351
|
+
if (options.includeGitHub !== false)
|
|
1352
|
+
sources.push('github');
|
|
1353
|
+
if (options.includeCollection === true)
|
|
1354
|
+
sources.push('collection');
|
|
1355
|
+
return sources;
|
|
1356
|
+
}
|
|
1357
|
+
/**
|
|
1358
|
+
* Batch sources for concurrent processing
|
|
1359
|
+
*/
|
|
1360
|
+
batchSources(sources, batchSize) {
|
|
1361
|
+
const batches = [];
|
|
1362
|
+
for (let i = 0; i < sources.length; i += batchSize) {
|
|
1363
|
+
batches.push(sources.slice(i, i + batchSize));
|
|
1364
|
+
}
|
|
1365
|
+
return batches;
|
|
1366
|
+
}
|
|
1367
|
+
/**
|
|
1368
|
+
* Generate cursor for pagination
|
|
1369
|
+
*/
|
|
1370
|
+
generateCursor(source, index) {
|
|
1371
|
+
const timestamp = Date.now();
|
|
1372
|
+
return Buffer.from(`${source}:${index}:${timestamp}`).toString('base64');
|
|
1373
|
+
}
|
|
1374
|
+
/**
|
|
1375
|
+
* Trigger memory cleanup when usage is high
|
|
1376
|
+
*/
|
|
1377
|
+
triggerMemoryCleanup() {
|
|
1378
|
+
// Force cache cleanup
|
|
1379
|
+
this.resultCache.cleanup();
|
|
1380
|
+
this.indexCache.cleanup();
|
|
1381
|
+
// Suggest garbage collection
|
|
1382
|
+
if (global.gc) {
|
|
1383
|
+
global.gc();
|
|
1384
|
+
logger.debug('Triggered garbage collection');
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
/**
|
|
1388
|
+
* Record search performance metrics
|
|
1389
|
+
*/
|
|
1390
|
+
recordSearchMetrics(metrics) {
|
|
1391
|
+
this.performanceMonitor.recordSearch(metrics);
|
|
1392
|
+
// Update cache performance metrics
|
|
1393
|
+
const cacheStats = this.resultCache.getStats();
|
|
1394
|
+
this.performanceMonitor.recordCachePerformance('searchResults', {
|
|
1395
|
+
hitRate: cacheStats.hitRate,
|
|
1396
|
+
avgHitTime: 1, // Placeholder
|
|
1397
|
+
avgMissTime: 5, // Placeholder
|
|
1398
|
+
totalHits: cacheStats.hitCount,
|
|
1399
|
+
totalMisses: cacheStats.missCount,
|
|
1400
|
+
evictions: cacheStats.evictionCount
|
|
1401
|
+
});
|
|
1402
|
+
}
|
|
1403
|
+
/**
|
|
1404
|
+
* Create cache key for search options
|
|
1405
|
+
*/
|
|
1406
|
+
createCacheKey(options) {
|
|
1407
|
+
return JSON.stringify({
|
|
1408
|
+
query: options.query,
|
|
1409
|
+
includeLocal: options.includeLocal,
|
|
1410
|
+
includeGitHub: options.includeGitHub,
|
|
1411
|
+
includeCollection: options.includeCollection,
|
|
1412
|
+
elementType: options.elementType,
|
|
1413
|
+
page: options.page,
|
|
1414
|
+
pageSize: options.pageSize,
|
|
1415
|
+
sortBy: options.sortBy,
|
|
1416
|
+
lazyLoad: options.lazyLoad
|
|
1417
|
+
});
|
|
1418
|
+
}
|
|
1419
|
+
/**
|
|
1420
|
+
* Get performance statistics
|
|
1421
|
+
*/
|
|
1422
|
+
getPerformanceStats() {
|
|
1423
|
+
return {
|
|
1424
|
+
searchStats: this.performanceMonitor.getSearchStats(),
|
|
1425
|
+
memoryStats: this.performanceMonitor.getMemoryStats(),
|
|
1426
|
+
cacheStats: {
|
|
1427
|
+
searchResults: this.resultCache.getStats(),
|
|
1428
|
+
indexCache: this.indexCache.getStats()
|
|
1429
|
+
},
|
|
1430
|
+
trends: this.performanceMonitor.analyzeTrends()
|
|
1431
|
+
};
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVW5pZmllZEluZGV4TWFuYWdlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9wb3J0Zm9saW8vVW5pZmllZEluZGV4TWFuYWdlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7R0FXRztBQUVILE9BQU8sRUFBRSxxQkFBcUIsRUFBMkMsTUFBTSw0QkFBNEIsQ0FBQztBQUM1RyxPQUFPLEVBQUUsc0JBQXNCLEVBQTBDLE1BQU0sNkJBQTZCLENBQUM7QUFDN0csT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sa0NBQWtDLENBQUM7QUFDeEUsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBQzdELE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUNoRCxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sWUFBWSxDQUFDO0FBQ3pDLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUM1QyxPQUFPLEVBQUUsWUFBWSxFQUFFLGFBQWEsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQ3ZFLE9BQU8sRUFBWSxZQUFZLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUM5RCxPQUFPLEVBQUUsa0JBQWtCLEVBQWlCLE1BQU0sZ0NBQWdDLENBQUM7QUFFbkYsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sNENBQTRDLENBQUM7QUFDOUUsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBOElqRSxNQUFNLE9BQU8sbUJBQW1CO0lBQ3RCLE1BQU0sQ0FBQyxRQUFRLEdBQStCLElBQUksQ0FBQztJQUVuRCxpQkFBaUIsQ0FBd0I7SUFDekMsYUFBYSxDQUF5QjtJQUN0QyxvQkFBb0IsQ0FBdUI7SUFDM0MsWUFBWSxDQUFlO0lBRW5DLHFDQUFxQztJQUM3QixrQkFBa0IsQ0FBcUI7SUFDdkMsV0FBVyxDQUFrQztJQUM3QyxVQUFVLENBQWdCO0lBQ2pC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RUFBRSxJQUFJLENBQUMsVUFBVSxDQUFDLFFBQVEsRUFBRTthQUN2QztZQUNELE1BQU0sRUFBRSxJQUFJLENBQUMsa0JBQWtCLENBQUMsYUFBYSxFQUFFO1NBQ2hELENBQUM7SUFDSixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBVbmlmaWVkIEluZGV4IE1hbmFnZXIgLSBDb21iaW5lcyBsb2NhbCwgR2l0SHViLCBhbmQgY29sbGVjdGlvbiBwb3J0Zm9saW8gaW5kZXhpbmdcbiAqIFxuICogRmVhdHVyZXM6XG4gKiAtIFVuaWZpZWQgc2VhcmNoIGFjcm9zcyBsb2NhbCwgR2l0SHViLCBhbmQgY29sbGVjdGlvbiBwb3J0Zm9saW9zXG4gKiAtIEludGVsbGlnZW50IHJlc3VsdCBtZXJnaW5nIGFuZCBkZWR1cGxpY2F0aW9uXG4gKiAtIFZlcnNpb24gY29uZmxpY3QgZGV0ZWN0aW9uIGFuZCByZXNvbHV0aW9uXG4gKiAtIFBlcmZvcm1hbmNlIG9wdGltaXphdGlvbiB3aXRoIHBhcmFsbGVsIGluZGV4aW5nXG4gKiAtIEFkdmFuY2VkIGZhbGxiYWNrIHN0cmF0ZWdpZXMgZm9yIHJlc2lsaWVudCBvcGVyYXRpb25cbiAqIC0gQ29tcHJlaGVuc2l2ZSBzZWFyY2ggY2FwYWJpbGl0aWVzIHdpdGggcGFnaW5hdGlvblxuICogLSBTbWFydCByZXN1bHQgcmFua2luZyBhbmQgZHVwbGljYXRlIGRldGVjdGlvblxuICovXG5cbmltcG9ydCB7IFBvcnRmb2xpb0luZGV4TWFuYWdlciwgSW5kZXhFbnRyeSwgU2VhcmNoUmVzdWx0LCBTZWFyY2hPcHRpb25zIH0gZnJvbSAnLi9Qb3J0Zm9saW9JbmRleE1hbmFnZXIuanMnO1xuaW1wb3J0IHsgR2l0SHViUG9ydGZvbGlvSW5kZXhlciwgR2l0SHViSW5kZXhFbnRyeSwgR2l0SHViUG9ydGZvbGlvSW5kZXggfSBmcm9tICcuL0dpdEh1YlBvcnRmb2xpb0luZGV4ZXIuanMnO1xuaW1wb3J0IHsgQ29sbGVjdGlvbkluZGV4Q2FjaGUgfSBmcm9tICcuLi9jYWNoZS9Db2xsZWN0aW9uSW5kZXhDYWNoZS5qcyc7XG5pbXBvcnQgeyBHaXRIdWJDbGllbnQgfSBmcm9tICcuLi9jb2xsZWN0aW9uL0dpdEh1YkNsaWVudC5qcyc7XG5pbXBvcnQgeyBBUElDYWNoZSB9IGZyb20gJy4uL2NhY2hlL0FQSUNhY2hlLmpzJztcbmltcG9ydCB7IEVsZW1lbnRUeXBlIH0gZnJvbSAnLi90eXBlcy5qcyc7XG5pbXBvcnQgeyBsb2dnZXIgfSBmcm9tICcuLi91dGlscy9sb2dnZXIuanMnO1xuaW1wb3J0IHsgRXJyb3JIYW5kbGVyLCBFcnJvckNhdGVnb3J5IH0gZnJvbSAnLi4vdXRpbHMvRXJyb3JIYW5kbGVyLmpzJztcbmltcG9ydCB7IExSVUNhY2hlLCBDYWNoZUZhY3RvcnkgfSBmcm9tICcuLi9jYWNoZS9MUlVDYWNoZS5qcyc7XG5pbXBvcnQgeyBQZXJmb3JtYW5jZU1vbml0b3IsIFNlYXJjaE1ldHJpY3MgfSBmcm9tICcuLi91dGlscy9QZXJmb3JtYW5jZU1vbml0b3IuanMnO1xuaW1wb3J0IHsgSW5kZXhFbnRyeSBhcyBDb2xsZWN0aW9uSW5kZXhFbnRyeSwgQ29sbGVjdGlvbkluZGV4IH0gZnJvbSAnLi4vdHlwZXMvY29sbGVjdGlvbi5qcyc7XG5pbXBvcnQgeyBVbmljb2RlVmFsaWRhdG9yIH0gZnJvbSAnLi4vc2VjdXJpdHkvdmFsaWRhdG9ycy91bmljb2RlVmFsaWRhdG9yLmpzJztcbmltcG9ydCB7IFNlY3VyaXR5TW9uaXRvciB9IGZyb20gJy4uL3NlY3VyaXR5L3NlY3VyaXR5TW9uaXRvci5qcyc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgVW5pZmllZFNlYXJjaE9wdGlvbnMge1xuICBxdWVyeTogc3RyaW5nO1xuICBpbmNsdWRlTG9jYWw/OiBib29sZWFuOyAgICAgLy8gZGVmYXVsdCB0cnVlXG4gIGluY2x1ZGVHaXRIdWI/OiBib29sZWFuOyAgICAvLyBkZWZhdWx0IHRydWVcbiAgaW5jbHVkZUNvbGxlY3Rpb24/OiBib29sZWFuOyAvLyBkZWZhdWx0IGZhbHNlXG4gIGVsZW1lbnRUeXBlPzogRWxlbWVudFR5cGU7XG4gIHBhZ2U/OiBudW1iZXI7XG4gIHBhZ2VTaXplPzogbnVtYmVyO1xuICBzb3J0Qnk/OiAncmVsZXZhbmNlJyB8ICdzb3VyY2UnIHwgJ25hbWUnIHwgJ3ZlcnNpb24nO1xuICBzdHJlYW1SZXN1bHRzPzogYm9vbGVhbjsgLy8gRW5hYmxlIHJlc3VsdCBzdHJlYW1pbmdcbiAgY3Vyc29yPzogc3RyaW5nOyAvLyBGb3IgcGFnaW5hdGlvbiBjdXJzb3JcbiAgbWF4UmVzdWx0cz86IG51bWJlcjsgLy8gSGFyZCBsaW1pdCBvbiByZXN1bHRzXG4gIGxhenlMb2FkPzogYm9vbGVhbjsgLy8gRW5hYmxlIGxhenkgbG9hZGluZ1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFZlcnNpb25Db25mbGljdCB7XG4gIGxvY2FsPzogc3RyaW5nO1xuICBnaXRodWI/OiBzdHJpbmc7XG4gIGNvbGxlY3Rpb24/OiBzdHJpbmc7XG4gIHJlY29tbWVuZGVkOiAnbG9jYWwnIHwgJ2dpdGh1YicgfCAnY29sbGVjdGlvbic7XG4gIHJlYXNvbjogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIER1cGxpY2F0ZUluZm8ge1xuICBuYW1lOiBzdHJpbmc7XG4gIGVsZW1lbnRUeXBlOiBFbGVtZW50VHlwZTtcbiAgc291cmNlczogQXJyYXk8e1xuICAgIHNvdXJjZTogJ2xvY2FsJyB8ICdnaXRodWInIHwgJ2NvbGxlY3Rpb24nO1xuICAgIHZlcnNpb24/OiBzdHJpbmc7XG4gICAgbGFzdE1vZGlmaWVkOiBEYXRlO1xuICAgIHBhdGg/OiBzdHJpbmc7XG4gIH0+O1xuICBoYXNWZXJzaW9uQ29uZmxpY3Q6IGJvb2xlYW47XG4gIHZlcnNpb25Db25mbGljdD86IFZlcnNpb25Db25mbGljdDtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBWZXJzaW9uSW5mbyB7XG4gIG5hbWU6IHN0cmluZztcbiAgZWxlbWVudFR5cGU6IEVsZW1lbnRUeXBlO1xuICB2ZXJzaW9uczoge1xuICAgIGxvY2FsPzogeyB2ZXJzaW9uOiBzdHJpbmc7IGxhc3RNb2RpZmllZDogRGF0ZTsgcGF0aDogc3RyaW5nIH07XG4gICAgZ2l0aHViPzogeyB2ZXJzaW9uOiBzdHJpbmc7IGxhc3RNb2RpZmllZDogRGF0ZTsgcGF0aDogc3RyaW5nIH07XG4gICAgY29sbGVjdGlvbj86IHsgdmVyc2lvbjogc3RyaW5nOyBsYXN0TW9kaWZpZWQ6IERhdGU7IHBhdGg6IHN0cmluZyB9O1xuICB9O1xuICByZWNvbW1lbmRlZDoge1xuICAgIHNvdXJjZTogJ2xvY2FsJyB8ICdnaXRodWInIHwgJ2NvbGxlY3Rpb24nO1xuICAgIHJlYXNvbjogc3RyaW5nO1xuICB9O1xuICB1cGRhdGVBdmFpbGFibGU6IGJvb2xlYW47XG4gIHVwZGF0ZUZyb20/OiAnbG9jYWwnIHwgJ2dpdGh1YicgfCAnY29sbGVjdGlvbic7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgVW5pZmllZEluZGV4RW50cnkge1xuICAvLyBDb21tb24gcHJvcGVydGllc1xuICBuYW1lOiBzdHJpbmc7XG4gIGRlc2NyaXB0aW9uPzogc3RyaW5nO1xuICB2ZXJzaW9uPzogc3RyaW5nO1xuICBhdXRob3I/OiBzdHJpbmc7XG4gIGVsZW1lbnRUeXBlOiBFbGVtZW50VHlwZTtcbiAgbGFzdE1vZGlmaWVkOiBEYXRlO1xuICBcbiAgLy8gU291cmNlIGluZm9ybWF0aW9uXG4gIHNvdXJjZTogJ2xvY2FsJyB8ICdnaXRodWInIHwgJ2NvbGxlY3Rpb24nO1xuICBcbiAgLy8gTG9jYWwgcHJvcGVydGllcyAod2hlbiBzb3VyY2UgPT09ICdsb2NhbCcpXG4gIGxvY2FsRmlsZVBhdGg/OiBzdHJpbmc7XG4gIGZpbGVuYW1lPzogc3RyaW5nO1xuICB0YWdzPzogc3RyaW5nW107XG4gIGtleXdvcmRzPzogc3RyaW5nW107XG4gIHRyaWdnZXJzPzogc3RyaW5nW107XG4gIGNhdGVnb3J5Pzogc3RyaW5nO1xuICBcbiAgLy8gR2l0SHViIHByb3BlcnRpZXMgKHdoZW4gc291cmNlID09PSAnZ2l0aHViJylcbiAgZ2l0aHViUGF0aD86IHN0cmluZztcbiAgZ2l0aHViU2hhPzogc3RyaW5nO1xuICBnaXRodWJIdG1sVXJsPzogc3RyaW5nO1xuICBnaXRodWJEb3dubG9hZFVybD86IHN0cmluZztcbiAgZ2l0aHViU2l6ZT86IG51bWJlcjtcbiAgXG4gIC8vIENvbGxlY3Rpb24gcHJvcGVydGllcyAod2hlbiBzb3VyY2UgPT09ICdjb2xsZWN0aW9uJylcbiAgY29sbGVjdGlvblBhdGg/OiBzdHJpbmc7XG4gIGNvbGxlY3Rpb25TaGE/OiBzdHJpbmc7XG4gIGNvbGxlY3Rpb25UYWdzPzogc3RyaW5nW107XG4gIGNvbGxlY3Rpb25DYXRlZ29yeT86IHN0cmluZztcbiAgY29sbGVjdGlvbkxpY2Vuc2U/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgVW5pZmllZFNlYXJjaFJlc3VsdCB7XG4gIHNvdXJjZTogJ2xvY2FsJyB8ICdnaXRodWInIHwgJ2NvbGxlY3Rpb24nO1xuICBlbnRyeTogVW5pZmllZEluZGV4RW50cnk7XG4gIG1hdGNoVHlwZTogc3RyaW5nO1xuICBzY29yZTogbnVtYmVyO1xuICB2ZXJzaW9uPzogc3RyaW5nO1xuICBpc0R1cGxpY2F0ZT86IGJvb2xlYW47XG4gIHZlcnNpb25Db25mbGljdD86IFZlcnNpb25Db25mbGljdDtcbiAgY3Vyc29yPzogc3RyaW5nOyAvLyBGb3Igc3RyZWFtaW5nIHBhZ2luYXRpb25cbn1cblxuZXhwb3J0IGludGVyZmFjZSBTdHJlYW1lZFNlYXJjaFJlc3VsdCB7XG4gIHJlc3VsdHM6IFVuaWZpZWRTZWFyY2hSZXN1bHRbXTtcbiAgaGFzTW9yZTogYm9vbGVhbjtcbiAgbmV4dEN1cnNvcj86IHN0cmluZztcbiAgdG90YWxFc3RpbWF0ZT86IG51bWJlcjtcbiAgcHJvY2Vzc2luZ1RpbWVNczogbnVtYmVyO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFVuaWZpZWRJbmRleFN0YXRzIHtcbiAgbG9jYWw6IHtcbiAgICB0b3RhbEVsZW1lbnRzOiBudW1iZXI7XG4gICAgZWxlbWVudHNCeVR5cGU6IFJlY29yZDxFbGVtZW50VHlwZSwgbnVtYmVyPjtcbiAgICBsYXN0QnVpbHQ6IERhdGUgfCBudWxsO1xuICAgIGlzU3RhbGU6IGJvb2xlYW47XG4gIH07XG4gIGdpdGh1Yjoge1xuICAgIHRvdGFsRWxlbWVudHM6IG51bWJlcjtcbiAgICBlbGVtZW50c0J5VHlwZTogUmVjb3JkPEVsZW1lbnRUeXBlLCBudW1iZXI+O1xuICAgIGxhc3RGZXRjaGVkOiBEYXRlIHwgbnVsbDtcbiAgICBpc1N0YWxlOiBib29sZWFuO1xuICAgIHVzZXJuYW1lPzogc3RyaW5nO1xuICAgIHJlcG9zaXRvcnk/OiBzdHJpbmc7XG4gIH07XG4gIGNvbGxlY3Rpb246IHtcbiAgICB0b3RhbEVsZW1lbnRzOiBudW1iZXI7XG4gICAgZWxlbWVudHNCeVR5cGU6IFJlY29yZDxzdHJpbmcsIG51bWJlcj47XG4gICAgbGFzdEZldGNoZWQ6IERhdGUgfCBudWxsO1xuICAgIGlzU3RhbGU6IGJvb2xlYW47XG4gICAgdmVyc2lvbj86IHN0cmluZztcbiAgfTtcbiAgY29tYmluZWQ6IHtcbiAgICB0b3RhbEVsZW1lbnRzOiBudW1iZXI7XG4gICAgdW5pcXVlRWxlbWVudHM6IG51bWJlcjtcbiAgICBkdXBsaWNhdGVzOiBudW1iZXI7XG4gIH07XG4gIHBlcmZvcm1hbmNlOiB7XG4gICAgYXZlcmFnZVNlYXJjaFRpbWU6IG51bWJlcjtcbiAgICBjYWNoZUhpdFJhdGU6IG51bWJlcjtcbiAgICBsYXN0T3B0aW1pemVkOiBEYXRlIHwgbnVsbDtcbiAgfTtcbn1cblxuZXhwb3J0IGNsYXNzIFVuaWZpZWRJbmRleE1hbmFnZXIge1xuICBwcml2YXRlIHN0YXRpYyBpbnN0YW5jZTogVW5pZmllZEluZGV4TWFuYWdlciB8IG51bGwgPSBudWxsO1xuICBcbiAgcHJpdmF0ZSBsb2NhbEluZGV4TWFuYWdlcjogUG9ydGZvbGlvSW5kZXhNYW5hZ2VyO1xuICBwcml2YXRlIGdpdGh1YkluZGV4ZXI6IEdpdEh1YlBvcnRmb2xpb0luZGV4ZXI7XG4gIHByaXZhdGUgY29sbGVjdGlvbkluZGV4Q2FjaGU6IENvbGxlY3Rpb25JbmRleENhY2hlO1xuICBwcml2YXRlIGdpdGh1YkNsaWVudDogR2l0SHViQ2xpZW50O1xuICBcbiAgLy8gUGVyZm9ybWFuY2UgbW9uaXRvcmluZyBhbmQgY2FjaGluZ1xuICBwcml2YXRlIHBlcmZvcm1hbmNlTW9uaXRvcjogUGVyZm9ybWFuY2VNb25pdG9yO1xuICBwcml2YXRlIHJlc3VsdENhY2hlOiBMUlVDYWNoZTxVbmlmaWVkU2VhcmNoUmVzdWx0W10+O1xuICBwcml2YXRlIGluZGV4Q2FjaGU6IExSVUNhY2hlPGFueT47XG4gIHByaXZhdGUgcmVhZG9ubHkgQkFUQ0hfU0laRSA9IDUwOyAvLyBGb3Igc3RyZWFtaW5nIHJlc3VsdHNcbiAgcHJpdmF0ZSByZWFkb25seSBNQVhfQ09OQ1VSUkVOVF9TT1VSQ0VTID0gMztcbiAgXG4gIHByaXZhdGUgY29uc3RydWN0b3IoKSB7XG4gICAgdGhpcy5sb2NhbEluZGV4TWFuYWdlciA9IFBvcnRmb2xpb0luZGV4TWFuYWdlci5nZXRJbnN0YW5jZSgpO1xuICAgIHRoaXMuZ2l0aHViSW5kZXhlciA9IEdpdEh1YlBvcnRmb2xpb0luZGV4ZXIuZ2V0SW5zdGFuY2UoKTtcbiAgICBcbiAgICAvLyBJbml0aWFsaXplIEdpdEh1YkNsaWVudCB3aXRoIHJlcXVpcmVkIGRlcGVuZGVuY2llc1xuICAgIGNvbnN0IGFwaUNhY2hlID0gbmV3IEFQSUNhY2hlKCk7XG4gICAgY29uc3QgcmF0ZUxpbWl0VHJhY2tlciA9IG5ldyBNYXA8c3RyaW5nLCBudW1iZXJbXT4oKTtcbiAgICB0aGlzLmdpdGh1YkNsaWVudCA9IG5ldyBHaXRIdWJDbGllbnQoYXBpQ2FjaGUsIHJhdGVMaW1pdFRyYWNrZXIpO1xuICAgIHRoaXMuY29sbGVjdGlvbkluZGV4Q2FjaGUgPSBuZXcgQ29sbGVjdGlvbkluZGV4Q2FjaGUodGhpcy5naXRodWJDbGllbnQpO1xuICAgIFxuICAgIC8vIEluaXRpYWxpemUgcGVyZm9ybWFuY2UgbW9uaXRvcmluZyBhbmQgY2FjaGluZ1xuICAgIHRoaXMucGVyZm9ybWFuY2VNb25pdG9yID0gUGVyZm9ybWFuY2VNb25pdG9yLmdldEluc3RhbmNlKCk7XG4gICAgdGhpcy5wZXJmb3JtYW5jZU1vbml0b3Iuc3RhcnRNb25pdG9yaW5nKCk7XG4gICAgXG4gICAgdGhpcy5yZXN1bHRDYWNoZSA9IENhY2hlRmFjdG9yeS5jcmVhdGVTZWFyY2hSZXN1bHRDYWNoZSh7XG4gICAgICBtYXhTaXplOiAyMDAsXG4gICAgICBtYXhNZW1vcnlNQjogMTUsXG4gICAgICB0dGxNczogNSAqIDYwICogMTAwMCwgLy8gNSBtaW51dGVzXG4gICAgICBvbkV2aWN0aW9uOiAoa2V5LCB2YWx1ZSkgPT4ge1xuICAgICAgICBsb2dnZXIuZGVidWcoJ1NlYXJjaCByZXN1bHQgY2FjaGUgZXZpY3Rpb24nLCB7IGtleSwgcmVzdWx0Q291bnQ6IHZhbHVlLmxlbmd0aCB9KTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICBcbiAgICB0aGlzLmluZGV4Q2FjaGUgPSBDYWNoZUZhY3RvcnkuY3JlYXRlSW5kZXhDYWNoZSh7XG4gICAgICBtYXhTaXplOiAxMDAsXG4gICAgICBtYXhNZW1vcnlNQjogMjAsXG4gICAgICB0dGxNczogMTUgKiA2MCAqIDEwMDAsIC8vIDE1IG1pbnV0ZXNcbiAgICAgIG9uRXZpY3Rpb246IChrZXksIHZhbHVlKSA9PiB7XG4gICAgICAgIGxvZ2dlci5kZWJ1ZygnSW5kZXggY2FjaGUgZXZpY3Rpb24nLCB7IGtleSB9KTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICBcbiAgICBsb2dnZXIuZGVidWcoJ1VuaWZpZWRJbmRleE1hbmFnZXIgY3JlYXRlZCB3aXRoIHBlcmZvcm1hbmNlIG9wdGltaXphdGlvbicpO1xuICB9XG5cbiAgcHVibGljIHN0YXRpYyBnZXRJbnN0YW5jZSgpOiBVbmlmaWVkSW5kZXhNYW5hZ2VyIHtcbiAgICBpZiAoIXRoaXMuaW5zdGFuY2UpIHtcbiAgICAgIHRoaXMuaW5zdGFuY2UgPSBuZXcgVW5pZmllZEluZGV4TWFuYWdlcigpO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5pbnN0YW5jZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBFbmhhbmNlZCBzZWFyY2ggYWNyb3NzIGxvY2FsLCBHaXRIdWIsIGFuZCBjb2xsZWN0aW9uIHBvcnRmb2xpb3Mgd2l0aCBwZXJmb3JtYW5jZSBvcHRpbWl6YXRpb25cbiAgICovXG4gIHB1YmxpYyBhc3luYyBzZWFyY2goc2VhcmNoT3B0aW9uczogVW5pZmllZFNlYXJjaE9wdGlvbnMpOiBQcm9taXNlPFVuaWZpZWRTZWFyY2hSZXN1bHRbXT4ge1xuICAgIGNvbnN0IHN0YXJ0VGltZSA9IERhdGUubm93KCk7XG4gICAgY29uc3QgbWVtb3J5QmVmb3JlID0gcHJvY2Vzcy5tZW1vcnlVc2FnZSgpLmhlYXBVc2VkO1xuICAgIGNvbnN0IHsgcXVlcnksIGluY2x1ZGVMb2NhbCA9IHRydWUsIGluY2x1ZGVHaXRIdWIgPSB0cnVlLCBpbmNsdWRlQ29sbGVjdGlvbiA9IGZhbHNlIH0gPSBzZWFyY2hPcHRpb25zO1xuICAgIFxuICAgIC8vIE5vcm1hbGl6ZSBxdWVyeSB0byBwcmV2ZW50IFVuaWNvZGUtYmFzZWQgYXR0YWNrc1xuICAgIGNvbnN0IHZhbGlkYXRpb25SZXN1bHQgPSBVbmljb2RlVmFsaWRhdG9yLm5vcm1hbGl6ZShxdWVyeSk7XG4gICAgY29uc3Qgbm9ybWFsaXplZFF1ZXJ5ID0gdmFsaWRhdGlvblJlc3VsdC5ub3JtYWxpemVkQ29udGVudDtcbiAgICBcbiAgICAvLyBVc2Ugbm9ybWFsaXplZCBxdWVyeSBpbiBhbGwgc3Vic2VxdWVudCBvcGVyYXRpb25zXG4gICAgY29uc3Qgbm9ybWFsaXplZFNlYXJjaE9wdGlvbnMgPSB7XG4gICAgICAuLi5zZWFyY2hPcHRpb25zLFxuICAgICAgcXVlcnk6IG5vcm1hbGl6ZWRRdWVyeVxuICAgIH07XG4gICAgXG4gICAgLy8gU0VDVVJJVFkgRklYIChETUNQLVNFQy0wMDYpOiBBZGQgYXVkaXQgbG9nZ2luZyBmb3Igc2VjdXJpdHkgbW9uaXRvcmluZ1xuICAgIC8vIExvZyB1bmlmaWVkIHNlYXJjaCBvcGVyYXRpb25zIGZvciBzZWN1cml0eSBhdWRpdCB0cmFpbFxuICAgIFNlY3VyaXR5TW9uaXRvci5sb2dTZWN1cml0eUV2ZW50KHtcbiAgICAgIHR5cGU6ICdQT1JURk9MSU9fRkVUQ0hfU1VDQ0VTUycsXG4gICAgICBzZXZlcml0eTogJ0xPVycsXG4gICAgICBzb3VyY2U6ICdVbmlmaWVkSW5kZXhNYW5hZ2VyLnNlYXJjaCcsXG4gICAgICBkZXRhaWxzOiBgVW5pZmllZCBzZWFyY2ggcGVyZm9ybWVkIHdpdGggcXVlcnkgbGVuZ3RoOiAke25vcm1hbGl6ZWRRdWVyeS5sZW5ndGh9LCBzb3VyY2VzOiAke0pTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgbG9jYWw6IGluY2x1ZGVMb2NhbCxcbiAgICAgICAgZ2l0aHViOiBpbmNsdWRlR2l0SHViLFxuICAgICAgICBjb2xsZWN0aW9uOiBpbmNsdWRlQ29sbGVjdGlvblxuICAgICAgfSl9YFxuICAgIH0pO1xuICAgIFxuICAgIGxvZ2dlci5kZWJ1ZygnU3RhcnRpbmcgb3B0aW1pemVkIHVuaWZpZWQgcG9ydGZvbGlvIHNlYXJjaCcsIG5vcm1hbGl6ZWRTZWFyY2hPcHRpb25zKTtcbiAgICBcbiAgICAvLyBDaGVjayBjYWNoZSBmaXJzdCAodXNlIG5vcm1hbGl6ZWQgc2VhcmNoIG9wdGlvbnMpXG4gICAgY29uc3QgY2FjaGVLZXkgPSB0aGlzLmNyZWF0ZUNhY2hlS2V5KG5vcm1hbGl6ZWRTZWFyY2hPcHRpb25zKTtcbiAgICBjb25zdCBjYWNoZWQgPSB0aGlzLnJlc3VsdENhY2hlLmdldChjYWNoZUtleSk7XG4gICAgaWYgKGNhY2hlZCkge1xuICAgICAgY29uc3QgZHVyYXRpb24gPSBEYXRlLm5vdygpIC0gc3RhcnRUaW1lO1xuICAgICAgdGhpcy5yZWNvcmRTZWFyY2hNZXRyaWNzKHtcbiAgICAgICAgcXVlcnk6IG5vcm1hbGl6ZWRRdWVyeSxcbiAgICAgICAgZHVyYXRpb24sXG4gICAgICAgIHJlc3VsdENvdW50OiBjYWNoZWQubGVuZ3RoLFxuICAgICAgICBzb3VyY2VzOiB0aGlzLmdldEVuYWJsZWRTb3VyY2VzKG5vcm1hbGl6ZWRTZWFyY2hPcHRpb25zKSxcbiAgICAgICAgY2FjaGVIaXQ6IHRydWUsXG4gICAgICAgIG1lbW9yeUJlZm9yZSxcbiAgICAgICAgbWVtb3J5QWZ0ZXI6IHByb2Nlc3MubWVtb3J5VXNhZ2UoKS5oZWFwVXNlZCxcbiAgICAgICAgdGltZXN0YW1wOiBuZXcgRGF0ZSgpXG4gICAgICB9KTtcbiAgICAgIGxvZ2dlci5kZWJ1ZygnVXNpbmcgY2FjaGVkIHNlYXJjaCByZXN1bHRzJywgeyByZXN1bHRDb3VudDogY2FjaGVkLmxlbmd0aCB9KTtcbiAgICAgIHJldHVybiBjYWNoZWQ7XG4gICAgfVxuICAgIFxuICAgIHRyeSB7XG4gICAgICAvLyBVc2Ugc3RyZWFtaW5nIHNlYXJjaCBmb3IgYmV0dGVyIHBlcmZvcm1hbmNlIHdpdGggbGFyZ2UgcmVzdWx0IHNldHNcbiAgICAgIGlmIChub3JtYWxpemVkU2VhcmNoT3B0aW9ucy5zdHJlYW1SZXN1bHRzKSB7XG4gICAgICAgIHJldHVybiBhd2FpdCB0aGlzLnN0cmVhbVNlYXJjaChub3JtYWxpemVkU2VhcmNoT3B0aW9ucyk7XG4gICAgICB9XG4gICAgICBcbiAgICAgIC8vIExhenkgbG9hZGluZzogT25seSBsb2FkIGluZGljZXMgd2hlbiBuZWVkZWRcbiAgICAgIGNvbnN0IHNlYXJjaFByb21pc2VzOiBQcm9taXNlPFVuaWZpZWRTZWFyY2hSZXN1bHRbXT5bXSA9IFtdO1xuICAgICAgY29uc3QgZW5hYmxlZFNvdXJjZXMgPSB0aGlzLmdldEVuYWJsZWRTb3VyY2VzKG5vcm1hbGl6ZWRTZWFyY2hPcHRpb25zKTtcbiAgICAgIFxuICAgICAgLy8gTGltaXQgY29uY3VycmVudCBzb3VyY2Ugc2VhcmNoZXMgZm9yIG1lbW9yeSBlZmZpY2llbmN5XG4gICAgICBjb25zdCBjb25jdXJyZW50TGltaXQgPSBNYXRoLm1pbih0aGlzLk1BWF9DT05DVVJSRU5UX1NPVVJDRVMsIGVuYWJsZWRTb3VyY2VzLmxlbmd0aCk7XG4gICAgICBjb25zdCBzb3VyY2VCYXRjaGVzID0gdGhpcy5iYXRjaFNvdXJjZXMoZW5hYmxlZFNvdXJjZXMsIGNvbmN1cnJlbnRMaW1pdCk7XG4gICAgICBcbiAgICAgIGNvbnN0IGFsbFJlc3VsdHM6IFVuaWZpZWRTZWFyY2hSZXN1bHRbXSA9IFtdO1xuICAgICAgY29uc3Qgc291cmNlQ291bnQgPSB7IGxvY2FsOiAwLCBnaXRodWI6IDAsIGNvbGxlY3Rpb246IDAgfTtcbiAgICAgIFxuICAgICAgLy8gUHJvY2VzcyBzb3VyY2VzIGluIGJhdGNoZXMgdG8gY29udHJvbCBtZW1vcnkgdXNhZ2VcbiAgICAgIGZvciAoY29uc3QgYmF0Y2ggb2Ygc291cmNlQmF0Y2hlcykge1xuICAgICAgICBjb25zdCBiYXRjaFByb21pc2VzID0gYmF0Y2gubWFwKHNvdXJjZSA9PiBcbiAgICAgICAgICB0aGlzLnNlYXJjaFdpdGhGYWxsYmFjayhzb3VyY2UgYXMgJ2xvY2FsJyB8ICdnaXRodWInIHwgJ2NvbGxlY3Rpb24nLCBub3JtYWxpemVkUXVlcnksIG5vcm1hbGl6ZWRTZWFyY2hPcHRpb25zKVxuICAgICAgICApO1xuICAgICAgICBcbiAgICAgICAgY29uc3QgYmF0Y2hSZXN1bHRzID0gYXdhaXQgUHJvbWlzZS5hbGxTZXR0bGVkKGJhdGNoUHJvbWlzZXMpO1xuICAgICAgICBcbiAgICAgICAgYmF0Y2hSZXN1bHRzLmZvckVhY2goKHJlc3VsdCwgaW5kZXgpID0+IHtcbiAgICAgICAgICBjb25zdCBzb3VyY2VOYW1lID0gYmF0Y2hbaW5kZXhdIGFzICdsb2NhbCcgfCAnZ2l0aHViJyB8ICdjb2xsZWN0aW9uJztcbiAgICAgICAgICBpZiAocmVzdWx0LnN0YXR1cyA9PT0gJ2Z1bGZpbGxlZCcpIHtcbiAgICAgICAgICAgIHNvdXJjZUNvdW50W3NvdXJjZU5hbWVdICs9IHJlc3VsdC52YWx1ZS5sZW5ndGg7XG4gICAgICAgICAgICBhbGxSZXN1bHRzLnB1c2goLi4ucmVzdWx0LnZhbHVlKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgbG9nZ2VyLndhcm4oYFNlYXJjaCBmYWlsZWQgZm9yIHNvdXJjZSAke3NvdXJjZU5hbWV9YCwge1xuICAgICAgICAgICAgICBlcnJvcjogcmVzdWx0LnJlYXNvbiBpbnN0YW5jZW9mIEVycm9yID8gcmVzdWx0LnJlYXNvbi5tZXNzYWdlIDogU3RyaW5nKHJlc3VsdC5yZWFzb24pXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgICBcbiAgICAgICAgLy8gTWVtb3J5IGNoZWNrIGJldHdlZW4gYmF0Y2hlc1xuICAgICAgICBjb25zdCBjdXJyZW50TWVtb3J5ID0gcHJvY2Vzcy5tZW1vcnlVc2FnZSgpLmhlYXBVc2VkIC8gKDEwMjQgKiAxMDI0KTtcbiAgICAgICAgaWYgKGN1cnJlbnRNZW1vcnkgPiAyMDApIHsgLy8gMjAwTUIgdGhyZXNob2xkXG4gICAgICAgICAgbG9nZ2VyLndhcm4oJ0hpZ2ggbWVtb3J5IHVzYWdlIGR1cmluZyBzZWFyY2gsIHRyaWdnZXJpbmcgY2xlYW51cCcsIHtcbiAgICAgICAgICAgIG1lbW9yeU1COiBjdXJyZW50TWVtb3J5XG4gICAgICAgICAgfSk7XG4gICAgICAgICAgdGhpcy50cmlnZ2VyTWVtb3J5Q2xlYW51cCgpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBcbiAgICAgIC8vIEFwcGx5IGFkdmFuY2VkIHByb2Nlc3Npbmcgd2l0aCBtZW1vcnktZWZmaWNpZW50IGJhdGNoaW5nXG4gICAgICBjb25zdCBwcm9jZXNzZWRSZXN1bHRzID0gYXdhaXQgdGhpcy5wcm9jZXNzU2VhcmNoUmVzdWx0c09wdGltaXplZChhbGxSZXN1bHRzLCBub3JtYWxpemVkU2VhcmNoT3B0aW9ucyk7XG4gICAgICBcbiAgICAgIC8vIEFwcGx5IHBhZ2luYXRpb25cbiAgICAgIGNvbnN0IHBhZ2luYXRlZFJlc3VsdHMgPSB0aGlzLmFwcGx5UGFnaW5hdGlvbihwcm9jZXNzZWRSZXN1bHRzLCBub3JtYWxpemVkU2VhcmNoT3B0aW9ucyk7XG4gICAgICBcbiAgICAgIC8vIENhY2hlIHJlc3VsdHMgd2l0aCBtZW1vcnkgbGltaXQgY2hlY2tcbiAgICAgIGlmIChwYWdpbmF0ZWRSZXN1bHRzLmxlbmd0aCA8IDEwMDApIHsgLy8gRG9uJ3QgY2FjaGUgdmVyeSBsYXJnZSByZXN1bHQgc2V0c1xuICAgICAgICB0aGlzLnJlc3VsdENhY2hlLnNldChjYWNoZUtleSwgcGFnaW5hdGVkUmVzdWx0cyk7XG4gICAgICB9XG4gICAgICBcbiAgICAgIGNvbnN0IGR1cmF0aW9uID0gRGF0ZS5ub3coKSAtIHN0YXJ0VGltZTtcbiAgICAgIGNvbnN0IG1lbW9yeUFmdGVyID0gcHJvY2Vzcy5tZW1vcnlVc2FnZSgpLmhlYXBVc2VkO1xuICAgICAgXG4gICAgICB0aGlzLnJlY29yZFNlYXJjaE1ldHJpY3Moe1xuICAgICAgICBxdWVyeTogbm9ybWFsaXplZFF1ZXJ5LFxuICAgICAgICBkdXJhdGlvbixcbiAgICAgICAgcmVzdWx0Q291bnQ6IHBhZ2luYXRlZFJlc3VsdHMubGVuZ3RoLFxuICAgICAgICBzb3VyY2VzOiBlbmFibGVkU291cmNlcyxcbiAgICAgICAgY2FjaGVIaXQ6IGZhbHNlLFxuICAgICAgICBtZW1vcnlCZWZvcmUsXG4gICAgICAgIG1lbW9yeUFmdGVyLFxuICAgICAgICB0aW1lc3RhbXA6IG5ldyBEYXRlKClcbiAgICAgIH0pO1xuICAgICAgXG4gICAgICBsb2dnZXIuaW5mbygnT3B0aW1pemVkIHVuaWZpZWQgcG9ydGZvbGlvIHNlYXJjaCBjb21wbGV0ZWQnLCB7XG4gICAgICAgIHF1ZXJ5OiBub3JtYWxpemVkUXVlcnkuc3Vic3RyaW5nKDAsIDUwKSxcbiAgICAgICAgc291cmNlczogeyAuLi5zb3VyY2VDb3VudCwgdG90YWw6IGFsbFJlc3VsdHMubGVuZ3RoIH0sXG4gICAgICAgIGZpbmFsUmVzdWx0czogcGFnaW5hdGVkUmVzdWx0cy5sZW5ndGgsXG4gICAgICAgIGR1cmF0aW9uOiBgJHtkdXJhdGlvbn1tc2AsXG4gICAgICAgIG1lbW9yeVVzYWdlTUI6IChtZW1vcnlBZnRlciAtIG1lbW9yeUJlZm9yZSkgLyAoMTAyNCAqIDEwMjQpXG4gICAgICB9KTtcbiAgICAgIFxuICAgICAgcmV0dXJuIHBhZ2luYXRlZFJlc3VsdHM7XG4gICAgICBcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgY29uc3QgZHVyYXRpb24gPSBEYXRlLm5vdygpIC0gc3RhcnRUaW1lO1xuICAgICAgRXJyb3JIYW5kbGVyLmxvZ0Vycm9yKCdVbmlmaWVkSW5kZXhNYW5hZ2VyLnNlYXJjaCcsIGVycm9yLCB7IHF1ZXJ5OiBub3JtYWxpemVkU2VhcmNoT3B0aW9ucywgZHVyYXRpb24gfSk7XG4gICAgICB0aHJvdyBFcnJvckhhbmRsZXIud3JhcEVycm9yKGVycm9yLCAnRmFpbGVkIHRvIHBlcmZvcm0gdW5pZmllZCBwb3J0Zm9saW8gc2VhcmNoJywgRXJyb3JDYXRlZ29yeS5TWVNURU1fRVJST1IpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBGaW5kIGVsZW1lbnQgYnkgbmFtZSBhY3Jvc3MgYWxsIHBvcnRmb2xpb3NcbiAgICovXG4gIHB1YmxpYyBhc3luYyBmaW5kQnlOYW1lKG5hbWU6IHN0cmluZywgb3B0aW9uczogUGFydGlhbDxVbmlmaWVkU2VhcmNoT3B0aW9ucz4gPSB7fSk6IFByb21pc2U8VW5pZmllZEluZGV4RW50cnkgfCBudWxsPiB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHNlYXJjaE9wdGlvbnM6IFVuaWZpZWRTZWFyY2hPcHRpb25zID0ge1xuICAgICAgICBxdWVyeTogbmFtZSxcbiAgICAgICAgaW5jbHVkZUxvY2FsOiBvcHRpb25zLmluY2x1ZGVMb2NhbCA/PyB0cnVlLFxuICAgICAgICBpbmNsdWRlR2l0SHViOiBvcHRpb25zLmluY2x1ZGVHaXRIdWIgPz8gdHJ1ZSxcbiAgICAgICAgaW5jbHVkZUNvbGxlY3Rpb246IG9wdGlvbnMuaW5jbHVkZUNvbGxlY3Rpb24gPz8gZmFsc2UsXG4gICAgICAgIHBhZ2VTaXplOiAxLFxuICAgICAgICAuLi5vcHRpb25zXG4gICAgICB9O1xuICAgICAgXG4gICAgICBjb25zdCByZXN1bHRzID0gYXdhaXQgdGhpcy5zZWFyY2goc2VhcmNoT3B0aW9ucyk7XG4gICAgICBcbiAgICAgIC8vIFJldHVybiBleGFjdCBuYW1lIG1hdGNoIGZpcnN0LCB0aGVuIGJlc3QgbWF0Y2hcbiAgICAgIGNvbnN0IGV4YWN0TWF0Y2ggPSByZXN1bHRzLmZpbmQocmVzdWx0ID0+IFxuICAgICAgICByZXN1bHQuZW50cnkubmFtZS50b0xvd2VyQ2FzZSgpID09PSBuYW1lLnRvTG93ZXJDYXNlKClcbiAgICAgICk7XG4gICAgICBcbiAgICAgIHJldHVybiBleGFjdE1hdGNoPy5lbnRyeSB8fCByZXN1bHRzWzBdPy5lbnRyeSB8fCBudWxsO1xuICAgICAgXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIEVycm9ySGFuZGxlci5sb2dFcnJvcignVW5pZmllZEluZGV4TWFuYWdlci5maW5kQnlOYW1lJywgZXJyb3IsIHsgbmFtZSB9KTtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgZWxlbWVudHMgYnkgdHlwZSBmcm9tIGFsbCBwb3J0Zm9saW9zXG4gICAqL1xuICBwdWJsaWMgYXN5bmMgZ2V0RWxlbWVudHNCeVR5cGUoZWxlbWVudFR5cGU6IEVsZW1lbnRUeXBlLCBvcHRpb25zOiBQYXJ0aWFsPFVuaWZpZWRTZWFyY2hPcHRpb25zPiA9IHt9KTogUHJvbWlzZTxVbmlmaWVkSW5kZXhFbnRyeVtdPiB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHNlYXJjaE9wdGlvbnM6IFVuaWZpZWRTZWFyY2hPcHRpb25zID0ge1xuICAgICAgICBxdWVyeTogJycsIC8vIEVtcHR5IHF1ZXJ5IHRvIGdldCBhbGwgZWxlbWVudHNcbiAgICAgICAgZWxlbWVudFR5cGUsXG4gICAgICAgIGluY2x1ZGVMb2NhbDogb3B0aW9ucy5pbmNsdWRlTG9jYWwgPz8gdHJ1ZSxcbiAgICAgICAgaW5jbHVkZUdpdEh1Yjogb3B0aW9ucy5pbmNsdWRlR2l0SHViID8/IHRydWUsXG4gICAgICAgIGluY2x1ZGVDb2xsZWN0aW9uOiBvcHRpb25zLmluY2x1ZGVDb2xsZWN0aW9uID8/IGZhbHNlLFxuICAgICAgICBwYWdlU2l6ZTogMTAwMCwgLy8gTGFyZ2UgcGFnZSBzaXplIHRvIGdldCBhbGxcbiAgICAgICAgLi4ub3B0aW9uc1xuICAgICAgfTtcbiAgICAgIFxuICAgICAgY29uc3QgcmVzdWx0cyA9IGF3YWl0IHRoaXMuZ2V0QWxsRWxlbWVudHNCeVR5cGUoZWxlbWVudFR5cGUsIHNlYXJjaE9wdGlvbnMpO1xuICAgICAgXG4gICAgICByZXR1cm4gdGhpcy5kZWR1cGxpY2F0ZUVudHJpZXMocmVzdWx0cy5tYXAociA9PiByLmVudHJ5KSk7XG4gICAgICBcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgRXJyb3JIYW5kbGVyLmxvZ0Vycm9yKCdVbmlmaWVkSW5kZXhNYW5hZ2VyLmdldEVsZW1lbnRzQnlUeXBlJywgZXJyb3IsIHsgZWxlbWVudFR5cGUgfSk7XG4gICAgICByZXR1cm4gW107XG4gICAgfVxuICB9XG4gIFxuICAvKipcbiAgICogQ2hlY2sgZm9yIGR1cGxpY2F0ZXMgYWNyb3NzIGFsbCBzb3VyY2VzXG4gICAqL1xuICBwdWJsaWMgYXN5bmMgY2hlY2tEdXBsaWNhdGVzKG5hbWU6IHN0cmluZyk6IFByb21pc2U8RHVwbGljYXRlSW5mb1tdPiB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHNlYXJjaE9wdGlvbnM6IFVuaWZpZWRTZWFyY2hPcHRpb25zID0ge1xuICAgICAgICBxdWVyeTogbmFtZSxcbiAgICAgICAgaW5jbHVkZUxvY2FsOiB0cnVlLFxuICAgICAgICBpbmNsdWRlR2l0SHViOiB0cnVlLFxuICAgICAgICBpbmNsdWRlQ29sbGVjdGlvbjogdHJ1ZSxcbiAgICAgICAgcGFnZVNpemU6IDEwMFxuICAgICAgfTtcbiAgICAgIFxuICAgICAgY29uc3QgcmVzdWx0cyA9IGF3YWl0IHRoaXMuc2VhcmNoKHNlYXJjaE9wdGlvbnMpO1xuICAgICAgY29uc3QgZHVwbGljYXRlTWFwID0gbmV3IE1hcDxzdHJpbmcsIER1cGxpY2F0ZUluZm8+KCk7XG4gICAgICBcbiAgICAgIGZvciAoY29uc3QgcmVzdWx0IG9mIHJlc3VsdHMpIHtcbiAgICAgICAgY29uc3Qga2V5ID0gYCR7cmVzdWx0LmVudHJ5LmVsZW1lbnRUeXBlfToke3Jlc3VsdC5lbnRyeS5uYW1lLnRvTG93ZXJDYXNlKCl9YDtcbiAgICAgICAgXG4gICAgICAgIGlmICghZHVwbGljYXRlTWFwLmhhcyhrZXkpKSB7XG4gICAgICAgICAgZHVwbGljYXRlTWFwLnNldChrZXksIHtcbiAgICAgICAgICAgIG5hbWU6IHJlc3VsdC5lbnRyeS5uYW1lLFxuICAgICAgICAgICAgZWxlbWVudFR5cGU6IHJlc3VsdC5lbnRyeS5lbGVtZW50VHlwZSxcbiAgICAgICAgICAgIHNvdXJjZXM6IFtdLFxuICAgICAgICAgICAgaGFzVmVyc2lvbkNvbmZsaWN0OiBmYWxzZVxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICAgIFxuICAgICAgICBjb25zdCBkdXBsaWNhdGUgPSBkdXBsaWNhdGVNYXAuZ2V0KGtleSkhO1xuICAgICAgICBkdXBsaWNhdGUuc291cmNlcy5wdXNoKHtcbiAgICAgICAgICBzb3VyY2U6IHJlc3VsdC5zb3VyY2UsXG4gICAgICAgICAgdmVyc2lvbjogcmVzdWx0LmVudHJ5LnZlcnNpb24sXG4gICAgICAgICAgbGFzdE1vZGlmaWVkOiByZXN1bHQuZW50cnkubGFzdE1vZGlmaWVkLFxuICAgICAgICAgIHBhdGg6IHRoaXMuZ2V0UGF0aEZyb21FbnRyeShyZXN1bHQuZW50cnkpXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgICAgXG4gICAgICAvLyBGaWx0ZXIgdG8gb25seSBpdGVtcyB3aXRoIG11bHRpcGxlIHNvdXJjZXMgYW5kIGNoZWNrIHZlcnNpb24gY29uZmxpY3RzXG4gICAgICBjb25zdCBhY3R1YWxEdXBsaWNhdGVzID0gQXJyYXkuZnJvbShkdXBsaWNhdGVNYXAudmFsdWVzKCkpXG4gICAgICAgIC5maWx0ZXIoaXRlbSA9PiBpdGVtLnNvdXJjZXMubGVuZ3RoID4gMSlcbiAgICAgICAgLm1hcChpdGVtID0+IHtcbiAgICAgICAgICBjb25zdCB2ZXJzaW9uQ29uZmxpY3QgPSB0aGlzLmRldGVjdFZlcnNpb25Db25mbGljdChpdGVtLnNvdXJjZXMpO1xuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAuLi5pdGVtLFxuICAgICAgICAgICAgaGFzVmVyc2lvbkNvbmZsaWN0OiAhIXZlcnNpb25Db25mbGljdCxcbiAgICAgICAgICAgIHZlcnNpb25Db25mbGljdFxuICAgICAgICAgIH07XG4gICAgICAgIH0pO1xuICAgICAgXG4gICAgICByZXR1cm4gYWN0dWFsRHVwbGljYXRlcztcbiAgICAgIFxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBFcnJvckhhbmRsZXIubG9nRXJyb3IoJ1VuaWZpZWRJbmRleE1hbmFnZXIuY2hlY2tEdXBsaWNhdGVzJywgZXJyb3IsIHsgbmFtZSB9KTtcbiAgICAgIHJldHVybiBbXTtcbiAgICB9XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZXQgdmVyc2lvbiBjb21wYXJpc29uIGFjcm9zcyBhbGwgc291cmNlc1xuICAgKi9cbiAgcHVibGljIGFzeW5jIGdldFZlcnNpb25Db21wYXJpc29uKG5hbWU6IHN0cmluZyk6IFByb21pc2U8VmVyc2lvbkluZm8gfCBudWxsPiB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGR1cGxpY2F0ZXMgPSBhd2FpdCB0aGlzLmNoZWNrRHVwbGljYXRlcyhuYW1lKTtcbiAgICAgIFxuICAgICAgaWYgKGR1cGxpY2F0ZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgICAgfVxuICAgICAgXG4gICAgICBjb25zdCBkdXBsaWNhdGUgPSBkdXBsaWNhdGVzWzBdO1xuICAgICAgY29uc3QgdmVyc2lvbnM6IFZlcnNpb25JbmZvWyd2ZXJzaW9ucyddID0ge307XG4gICAgICBcbiAgICAgIC8vIEJ1aWxkIHZlcnNpb24gaW5mb1xuICAgICAgZm9yIChjb25zdCBzb3VyY2Ugb2YgZHVwbGljYXRlLnNvdXJjZXMpIHtcbiAgICAgICAgaWYgKHNvdXJjZS5zb3VyY2UgPT09ICdsb2NhbCcpIHtcbiAgICAgICAgICB2ZXJzaW9ucy5sb2NhbCA9IHtcbiAgICAgICAgICAgIHZlcnNpb246IHNvdXJjZS52ZXJzaW9uIHx8ICd1bmtub3duJyxcbiAgICAgICAgICAgIGxhc3RNb2RpZmllZDogc291cmNlLmxhc3RNb2RpZmllZCxcbiAgICAgICAgICAgIHBhdGg6IHNvdXJjZS5wYXRoIHx8ICd1bmtub3duJ1xuICAgICAgICAgIH07XG4gICAgICAgIH0gZWxzZSBpZiAoc291cmNlLnNvdXJjZSA9PT0gJ2dpdGh1YicpIHtcbiAgICAgICAgICB2ZXJzaW9ucy5naXRodWIgPSB7XG4gICAgICAgICAgICB2ZXJzaW9uOiBzb3VyY2UudmVyc2lvbiB8fCAndW5rbm93bicsXG4gICAgICAgICAgICBsYXN0TW9kaWZpZWQ6IHNvdXJjZS5sYXN0TW9kaWZpZWQsXG4gICAgICAgICAgICBwYXRoOiBzb3VyY2UucGF0aCB8fCAndW5rbm93bidcbiAgICAgICAgICB9O1xuICAgICAgICB9IGVsc2UgaWYgKHNvdXJjZS5zb3VyY2UgPT09ICdjb2xsZWN0aW9uJykge1xuICAgICAgICAgIHZlcnNpb25zLmNvbGxlY3Rpb24gPSB7XG4gICAgICAgICAgICB2ZXJzaW9uOiBzb3VyY2UudmVyc2lvbiB8fCAndW5rbm93bicsXG4gICAgICAgICAgICBsYXN0TW9kaWZpZWQ6IHNvdXJjZS5sYXN0TW9kaWZpZWQsXG4gICAgICAgICAgICBwYXRoOiBzb3VyY2UucGF0aCB8fCAndW5rbm93bidcbiAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBcbiAgICAgIC8vIERldGVybWluZSByZWNvbW1lbmRhdGlvblxuICAgICAgY29uc3QgcmVjb21tZW5kYXRpb24gPSB0aGlzLmRldGVybWluZVZlcnNpb25SZWNvbW1lbmRhdGlvbih2ZXJzaW9ucyk7XG4gICAgICBcbiAgICAgIHJldHVybiB7XG4gICAgICAgIG5hbWU6IGR1cGxpY2F0ZS5uYW1lLFxuICAgICAgICBlbGVtZW50VHlwZTogZHVwbGljYXRlLmVsZW1lbnRUeXBlLFxuICAgICAgICB2ZXJzaW9ucyxcbiAgICAgICAgcmVjb21tZW5kZWQ6IHJlY29tbWVuZGF0aW9uLFxuICAgICAgICB1cGRhdGVBdmFpbGFibGU6IHJlY29tbWVuZGF0aW9uLnNvdXJjZSAhPT0gJ2xvY2FsJyAmJiAhIXZlcnNpb25zLmxvY2FsLFxuICAgICAgICB1cGRhdGVGcm9tOiByZWNvbW1lbmRhdGlvbi5zb3VyY2UgIT09ICdsb2NhbCcgPyByZWNvbW1lbmRhdGlvbi5zb3VyY2UgOiB1bmRlZmluZWRcbiAgICAgIH07XG4gICAgICBcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgRXJyb3JIYW5kbGVyLmxvZ0Vycm9yKCdVbmlmaWVkSW5kZXhNYW5hZ2VyLmdldFZlcnNpb25Db21wYXJpc29uJywgZXJyb3IsIHsgbmFtZSB9KTtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgY29tcHJlaGVuc2l2ZSBzdGF0aXN0aWNzIGFjcm9zcyBhbGwgc291cmNlc1xuICAgKi9cbiAgcHVibGljIGFzeW5jIGdldFN0YXRzKCk6IFByb21pc2U8VW5pZmllZEluZGV4U3RhdHM+IHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgW2xvY2FsU3RhdHMsIGdpdGh1YlN0YXRzLCBjb2xsZWN0aW9uU3RhdHNdID0gYXdhaXQgUHJvbWlzZS5hbGxTZXR0bGVkKFtcbiAgICAgICAgdGhpcy5nZXRMb2NhbFN0YXRzKCksXG4gICAgICAgIHRoaXMuZ2V0R2l0SHViU3RhdHMoKSxcbiAgICAgICAgdGhpcy5nZXRDb2xsZWN0aW9uU3RhdHMoKVxuICAgICAgXSk7XG4gICAgICBcbiAgICAgIGNvbnN0IGxvY2FsID0gbG9jYWxTdGF0cy5zdGF0dXMgPT09ICdmdWxmaWxsZWQnID8gbG9jYWxTdGF0cy52YWx1ZSA6IHtcbiAgICAgICAgdG90YWxFbGVtZW50czogMCxcbiAgICAgICAgZWxlbWVudHNCeVR5cGU6IHt9IGFzIFJlY29yZDxFbGVtZW50VHlwZSwgbnVtYmVyPixcbiAgICAgICAgbGFzdEJ1aWx0OiBudWxsLFxuICAgICAgICBpc1N0YWxlOiB0cnVlXG4gICAgICB9O1xuICAgICAgXG4gICAgICBjb25zdCBnaXRodWIgPSBnaXRodWJTdGF0cy5zdGF0dXMgPT09ICdmdWxmaWxsZWQnID8gZ2l0aHViU3RhdHMudmFsdWUgOiB7XG4gICAgICAgIHRvdGFsRWxlbWVudHM6IDAsXG4gICAgICAgIGVsZW1lbnRzQnlUeXBlOiB7fSBhcyBSZWNvcmQ8RWxlbWVudFR5cGUsIG51bWJlcj4sXG4gICAgICAgIGxhc3RGZXRjaGVkOiBudWxsLFxuICAgICAgICBpc1N0YWxlOiB0cnVlXG4gICAgICB9O1xuICAgICAgXG4gICAgICBjb25zdCBjb2xsZWN0aW9uID0gY29sbGVjdGlvblN0YXRzLnN0YXR1cyA9PT0gJ2Z1bGZpbGxlZCcgPyBjb2xsZWN0aW9uU3RhdHMudmFsdWUgOiB7XG4gICAgICAgIHRvdGFsRWxlbWVudHM6IDAsXG4gICAgICAgIGVsZW1lbnRzQnlUeXBlOiB7fSBhcyBSZWNvcmQ8c3RyaW5nLCBudW1iZXI+LFxuICAgICAgICBsYXN0RmV0Y2hlZDogbnVsbCxcbiAgICAgICAgaXNTdGFsZTogdHJ1ZVxuICAgICAgfTtcbiAgICAgIFxuICAgICAgLy8gQ2FsY3VsYXRlIGNvbWJpbmVkIHN0YXRpc3RpY3NcbiAgICAgIGNvbnN0IHRvdGFsRWxlbWVudHMgPSBsb2NhbC50b3RhbEVsZW1lbnRzICsgZ2l0aHViLnRvdGFsRWxlbWVudHMgKyBjb2xsZWN0aW9uLnRvdGFsRWxlbWVudHM7XG4gICAgICBjb25zdCBkdXBsaWNhdGVzQ291bnQgPSBhd2FpdCB0aGlzLmNhbGN1bGF0ZUR1cGxpY2F0ZXNDb3VudCgpO1xuICAgICAgY29uc3QgdW5pcXVlRWxlbWVudHMgPSB0b3RhbEVsZW1lbnRzIC0gZHVwbGljYXRlc0NvdW50O1xuICAgICAgXG4gICAgICByZXR1cm4ge1xuICAgICAgICBsb2NhbCxcbiAgICAgICAgZ2l0aHViLFxuICAgICAgICBjb2xsZWN0aW9uLFxuICAgICAgICBjb21iaW5lZDoge1xuICAgICAgICAgIHRvdGFsRWxlbWVudHMsXG4gICAgICAgICAgdW5pcXVlRWxlbWVudHMsXG4gICAgICAgICAgZHVwbGljYXRlczogZHVwbGljYXRlc0NvdW50XG4gICAgICAgIH0sXG4gICAgICAgIHBlcmZvcm1hbmNlOiB7XG4gICAgICAgICAgYXZlcmFnZVNlYXJjaFRpbWU6IHRoaXMuZ2V0UGVyZm9ybWFuY2VTdGF0cygpLnNlYXJjaFN0YXRzLmF2ZXJhZ2VUaW1lIHx8IDAsXG4gICAgICAgICAgY2FjaGVIaXRSYXRlOiB0aGlzLmdldFBlcmZvcm1hbmNlU3RhdHMoKS5zZWFyY2hTdGF0cy5jYWNoZUhpdFJhdGUgfHwgMCxcbiAgICAgICAgICBsYXN0T3B0aW1pemVkOiBudWxsXG4gICAgICAgIH1cbiAgICAgIH07XG4gICAgICBcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgRXJyb3JIYW5kbGVyLmxvZ0Vycm9yKCdVbmlmaWVkSW5kZXhNYW5hZ2VyLmdldFN0YXRzJywgZXJyb3IpO1xuICAgICAgdGhyb3cgZXJyb3I7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEludmFsaWRhdGUgY2FjaGVzIGFmdGVyIHVzZXIgYWN0aW9ucyB3aXRoIHBlcmZvcm1hbmNlIG1vbml0b3JpbmdcbiAgICovXG4gIHB1YmxpYyBpbnZhbGlkYXRlQWZ0ZXJBY3Rpb24oYWN0aW9uOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBsb2dnZXIuaW5mbygnSW52YWxpZGF0aW5nIHVuaWZpZWQgcG9ydGZvbGlvIGNhY2hlcyBhZnRlciB1c2VyIGFjdGlvbicsIHsgYWN0aW9uIH0pO1xuICAgIFxuICAgIC8vIENsZWFyIHJlc3VsdCBhbmQgaW5kZXggY2FjaGVzXG4gICAgdGhpcy5yZXN1bHRDYWNoZS5jbGVhcigpO1xuICAgIHRoaXMuaW5kZXhDYWNoZS5jbGVhcigpO1xuICAgIFxuICAgIC8vIEludmFsaWRhdGUgbG9jYWwgY2FjaGVcbiAgICB0aGlzLmxvY2FsSW5kZXhNYW5hZ2VyLnJlYnVpbGRJbmRleCgpLmNhdGNoKGVycm9yID0+IHtcbiAgICAgIGxvZ2dlci53YXJuKCdGYWlsZWQgdG8gcmVidWlsZCBsb2NhbCBpbmRleCBhZnRlciBhY3Rpb24nLCB7XG4gICAgICAgIGFjdGlvbixcbiAgICAgICAgZXJyb3I6IGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKVxuICAgICAgfSk7XG4gICAgfSk7XG4gICAgXG4gICAgLy8gSW52YWxpZGF0ZSBHaXRIdWIgY2FjaGVcbiAgICB0aGlzLmdpdGh1YkluZGV4ZXIuaW52YWxpZGF0ZUFmdGVyQWN0aW9uKGFjdGlvbik7XG4gICAgXG4gICAgLy8gSW52YWxpZGF0ZSBjb2xsZWN0aW9uIGNhY2hlXG4gICAgdGhpcy5jb2xsZWN0aW9uSW5kZXhDYWNoZS5jbGVhckNhY2hlKCkuY2F0Y2goZXJyb3IgPT4ge1xuICAgICAgbG9nZ2VyLndhcm4oJ0ZhaWxlZCB0byBjbGVhciBjb2xsZWN0aW9uIGNhY2hlIGFmdGVyIGFjdGlvbicsIHtcbiAgICAgICAgYWN0aW9uLFxuICAgICAgICBlcnJvcjogZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpXG4gICAgICB9KTtcbiAgICB9KTtcbiAgICBcbiAgICAvLyBUcmlnZ2VyIGdhcmJhZ2UgY29sbGVjdGlvbiBpZiBtZW1vcnkgdXNhZ2UgaXMgaGlnaFxuICAgIHRoaXMudHJpZ2dlck1lbW9yeUNsZWFudXAoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGb3JjZSByZWJ1aWxkIG9mIGFsbCBpbmRleGVzIHdpdGggcGVyZm9ybWFuY2Ugb3B0aW1pemF0aW9uXG4gICAqL1xuICBwdWJsaWMgYXN5bmMgcmVidWlsZEFsbCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCBzdGFydFRpbWUgPSBEYXRlLm5vdygpO1xuICAgIGxvZ2dlci5pbmZvKCdSZWJ1aWxkaW5nIGFsbCBwb3J0Zm9saW8gaW5kZXhlcyB3aXRoIG9wdGltaXphdGlvbi4uLicpO1xuICAgIFxuICAgIHRyeSB7XG4gICAgICAvLyBDbGVhciBhbGwgY2FjaGVzXG4gICAgICB0aGlzLnJlc3VsdENhY2hlLmNsZWFyKCk7XG4gICAgICB0aGlzLmluZGV4Q2FjaGUuY2xlYXIoKTtcbiAgICAgIFxuICAgICAgLy8gUmVzZXQgcGVyZm9ybWFuY2UgY291bnRlcnNcbiAgICAgIHRoaXMucGVyZm9ybWFuY2VNb25pdG9yLnJlc2V0KCk7XG4gICAgICBcbiAgICAgIC8vIFJlYnVpbGQgaW4gcGFyYWxsZWwgd2l0aCBtZW1vcnkgbW9uaXRvcmluZ1xuICAgICAgY29uc3QgcmVidWlsZFByb21pc2VzID0gW1xuICAgICAgICB0aGlzLmxvY2FsSW5kZXhNYW5hZ2VyLnJlYnVpbGRJbmRleCgpLFxuICAgICAgICB0aGlzLmdpdGh1YkluZGV4ZXIuY2xlYXJDYWNoZSgpLFxuICAgICAgICB0aGlzLmNvbGxlY3Rpb25JbmRleENhY2hlLmNsZWFyQ2FjaGUoKVxuICAgICAgXTtcbiAgICAgIFxuICAgICAgYXdhaXQgUHJvbWlzZS5hbGwocmVidWlsZFByb21pc2VzKTtcbiAgICAgIFxuICAgICAgLy8gVHJpZ2dlciBjbGVhbnVwXG4gICAgICB0aGlzLnRyaWdnZXJNZW1vcnlDbGVhbnVwKCk7XG4gICAgICBcbiAgICAgIGNvbnN0IGR1cmF0aW9uID0gRGF0ZS5ub3coKSAtIHN0YXJ0VGltZTtcbiAgICAgIGxvZ2dlci5pbmZvKCdBbGwgcG9ydGZvbGlvIGluZGV4ZXMgcmVidWlsdCBzdWNjZXNzZnVsbHknLCB7XG4gICAgICAgIGR1cmF0aW9uOiBgJHtkdXJhdGlvbn1tc2AsXG4gICAgICAgIG1lbW9yeVVzYWdlTUI6IHByb2Nlc3MubWVtb3J5VXNhZ2UoKS5oZWFwVXNlZCAvICgxMDI0ICogMTAyNClcbiAgICAgIH0pO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBFcnJvckhhbmRsZXIubG9nRXJyb3IoJ1VuaWZpZWRJbmRleE1hbmFnZXIucmVidWlsZEFsbCcsIGVycm9yKTtcbiAgICAgIHRocm93IGVycm9yO1xuICAgIH1cbiAgfVxuXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gIC8vIFBSSVZBVEUgSEVMUEVSIE1FVEhPRFNcbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAgXG4gIC8qKlxuICAgKiBTZWFyY2ggd2l0aCBmYWxsYmFjayBzdHJhdGVnaWVzIGZvciByZXNpbGllbnQgb3BlcmF0aW9uXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHNlYXJjaFdpdGhGYWxsYmFjayhzb3VyY2U6ICdsb2NhbCcgfCAnZ2l0aHViJyB8ICdjb2xsZWN0aW9uJywgcXVlcnk6IHN0cmluZywgb3B0aW9uczogVW5pZmllZFNlYXJjaE9wdGlvbnMpOiBQcm9taXNlPFVuaWZpZWRTZWFyY2hSZXN1bHRbXT4ge1xuICAgIGNvbnN0IHN0YXJ0VGltZSA9IERhdGUubm93KCk7XG4gICAgXG4gICAgdHJ5IHtcbiAgICAgIGxldCByZXN1bHRzOiBVbmlmaWVkU2VhcmNoUmVzdWx0W10gPSBbXTtcbiAgICAgIFxuICAgICAgc3dpdGNoIChzb3VyY2UpIHtcbiAgICAgICAgY2FzZSAnbG9jYWwnOlxuICAgICAgICAgIHJlc3VsdHMgPSBhd2FpdCB0aGlzLnNlYXJjaExvY2FsKHF1ZXJ5LCBvcHRpb25zKTtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSAnZ2l0aHViJzpcbiAgICAgICAgICByZXN1bHRzID0gYXdhaXQgdGhpcy5zZWFyY2hHaXRIdWIocXVlcnksIG9wdGlvbnMpO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlICdjb2xsZWN0aW9uJzpcbiAgICAgICAgICByZXN1bHRzID0gYXdhaXQgdGhpcy5zZWFyY2hDb2xsZWN0aW9uKHF1ZXJ5LCBvcHRpb25zKTtcbiAgICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICAgIFxuICAgICAgbG9nZ2VyLmRlYnVnKGAke3NvdXJjZX0gc2VhcmNoIGNvbXBsZXRlZCBpbiAke0RhdGUubm93KCkgLSBzdGFydFRpbWV9bXMgd2l0aCAke3Jlc3VsdHMubGVuZ3RofSByZXN1bHRzYCk7XG4gICAgICByZXR1cm4gcmVzdWx0cztcbiAgICAgIFxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBsb2dnZXIuZGVidWcoYCR7c291cmNlfSBzZWFyY2ggZmFpbGVkLCBhdHRlbXB0aW5nIGZhbGxiYWNrYCwge1xuICAgICAgICBlcnJvcjogZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpXG4gICAgICB9KTtcbiAgICAgIFxuICAgICAgLy8gRmFsbGJhY2sgc3RyYXRlZ2llc1xuICAgICAgcmV0dXJuIGF3YWl0IHRoaXMuaGFuZGxlU2VhcmNoRmFsbGJhY2soc291cmNlLCBxdWVyeSwgb3B0aW9ucywgZXJyb3IpO1xuICAgIH1cbiAgfVxuICBcbiAgLyoqXG4gICAqIEhhbmRsZSBzZWFyY2ggZmFsbGJhY2sgc3RyYXRlZ2llc1xuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBoYW5kbGVTZWFyY2hGYWxsYmFjayhzb3VyY2U6ICdsb2NhbCcgfCAnZ2l0aHViJyB8ICdjb2xsZWN0aW9uJywgcXVlcnk6IHN0cmluZywgb3B0aW9uczogVW5pZmllZFNlYXJjaE9wdGlvbnMsIG9yaWdpbmFsRXJyb3I6IGFueSk6IFByb21pc2U8VW5pZmllZFNlYXJjaFJlc3VsdFtdPiB7XG4gICAgdHJ5IHtcbiAgICAgIHN3aXRjaCAoc291cmNlKSB7XG4gICAgICAgIGNhc2UgJ2xvY2FsJzpcbiAgICAgICAgICAvLyBUcnkgdG8gdXNlIHN0YWxlIGxvY2FsIGluZGV4XG4gICAgICAgICAgbG9nZ2VyLmRlYnVnKCdBdHRlbXB0aW5nIHRvIHVzZSBzdGFsZSBsb2NhbCBpbmRleCcpO1xuICAgICAgICAgIHJldHVybiBhd2FpdCB0aGlzLnNlYXJjaExvY2FsU3RhbGUocXVlcnksIG9wdGlvbnMpO1xuICAgICAgICAgIFxuICAgICAgICBjYXNlICdnaXRodWInOlxuICAgICAgICAgIC8vIFRyeSBjYWNoZWQgR2l0SHViIGRhdGFcbiAgICAgICAgICBsb2dnZXIuZGVidWcoJ0F0dGVtcHRpbmcgdG8gdXNlIGNhY2hlZCBHaXRIdWIgZGF0YScpO1xuICAgICAgICAgIHJldHVybiBhd2FpdCB0aGlzLnNlYXJjaEdpdEh1YkNhY2hlZChxdWVyeSwgb3B0aW9ucyk7XG4gICAgICAgICAgXG4gICAgICAgIGNhc2UgJ2NvbGxlY3Rpb24nOlxuICAgICAgICAgIC8vIFRyeSBjYWNoZWQgY29sbGVjdGlvbiBkYXRhXG4gICAgICAgICAgbG9nZ2VyLmRlYnVnKCdBdHRlbXB0aW5nIHRvIHVzZSBjYWNoZWQgY29sbGVjdGlvbiBkYXRhJyk7XG4gICAgICAgICAgcmV0dXJuIGF3YWl0IHRoaXMuc2VhcmNoQ29sbGVjdGlvbkNhY2hlZChxdWVyeSwgb3B0aW9ucyk7XG4gICAgICAgICAgXG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgcmV0dXJuIFtdO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGZhbGxiYWNrRXJyb3IpIHtcbiAgICAgIGxvZ2dlci53YXJuKGBBbGwgZmFsbGJhY2sgc3RyYXRlZ2llcyBmYWlsZWQgZm9yICR7c291cmNlfWAsIHtcbiAgICAgICAgb3JpZ2luYWxFcnJvcjogb3JpZ2luYWxFcnJvciBpbnN0YW5jZW9mIEVycm9yID8gb3JpZ2luYWxFcnJvci5tZXNzYWdlIDogU3RyaW5nKG9yaWdpbmFsRXJyb3IpLFxuICAgICAgICBmYWxsYmFja0Vycm9yOiBmYWxsYmFja0Vycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBmYWxsYmFja0Vycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZmFsbGJhY2tFcnJvcilcbiAgICAgIH0pO1xuICAgICAgcmV0dXJuIFtdO1xuICAgIH1cbiAgfVxuICBcbiAgLyoqXG4gICAqIFNlYXJjaCBsb2NhbCBwb3J0Zm9saW9cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgc2VhcmNoTG9jYWwocXVlcnk6IHN0cmluZywgb3B0aW9uczogVW5pZmllZFNlYXJjaE9wdGlvbnMpOiBQcm9taXNlPFVuaWZpZWRTZWFyY2hSZXN1bHRbXT4ge1xuICAgIGNvbnN0IGxvY2FsT3B0aW9ucyA9IHRoaXMuY29udmVydFRvTG9jYWxPcHRpb25zKG9wdGlvbnMpO1xuICAgIGNvbnN0IHJlc3VsdHMgPSBhd2FpdCB0aGlzLmxvY2FsSW5kZXhNYW5hZ2VyLnNlYXJjaChxdWVyeSwgbG9jYWxPcHRpb25zKTtcbiAgICBcbiAgICByZXR1cm4gcmVzdWx0cy5tYXAocmVzdWx0ID0+ICh7XG4gICAgICBzb3VyY2U6ICdsb2NhbCcgYXMgY29uc3QsXG4gICAgICBlbnRyeTogdGhpcy5jb252ZXJ0TG9jYWxFbnRyeShyZXN1bHQuZW50cnkpLFxuICAgICAgbWF0Y2hUeXBlOiByZXN1bHQubWF0Y2hUeXBlLFxuICAgICAgc2NvcmU6IHJlc3VsdC5zY29yZSxcbiAgICAgIHZlcnNpb246IHJlc3VsdC5lbnRyeS5tZXRhZGF0YS52ZXJzaW9uXG4gICAgfSkpO1xuICB9XG4gIFxuICAvKipcbiAgICogU2VhcmNoIGxvY2FsIHdpdGggc3RhbGUgZGF0YSBmYWxsYmFja1xuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBzZWFyY2hMb2NhbFN0YWxlKHF1ZXJ5OiBzdHJpbmcsIG9wdGlvbnM6IFVuaWZpZWRTZWFyY2hPcHRpb25zKTogUHJvbWlzZTxVbmlmaWVkU2VhcmNoUmVzdWx0W10+IHtcbiAgICB0cnkge1xuICAgICAgLy8gVHJ5IHRvIGdldCBhbnkgbG9jYWwgZGF0YSwgZXZlbiBzdGFsZVxuICAgICAgY29uc3QgbG9jYWxPcHRpb25zID0gdGhpcy5jb252ZXJ0VG9Mb2NhbE9wdGlvbnMob3B0aW9ucyk7XG4gICAgICBjb25zdCByZXN1bHRzID0gYXdhaXQgdGhpcy5sb2NhbEluZGV4TWFuYWdlci5zZWFyY2gocXVlcnksIGxvY2FsT3B0aW9ucyk7XG4gICAgICBcbiAgICAgIHJldHVybiByZXN1bHRzLm1hcChyZXN1bHQgPT4gKHtcbiAgICAgICAgc291cmNlOiAnbG9jYWwnIGFzIGNvbnN0LFxuICAgICAgICBlbnRyeTogdGhpcy5jb252ZXJ0TG9jYWxFbnRyeShyZXN1bHQuZW50cnkpLFxuICAgICAgICBtYXRjaFR5cGU6IHJlc3VsdC5tYXRjaFR5cGUsXG4gICAgICAgIHNjb3JlOiByZXN1bHQuc2NvcmUgKiAwLjgsIC8vIFJlZHVjZSBzY29yZSBmb3Igc3RhbGUgZGF0YVxuICAgICAgICB2ZXJzaW9uOiByZXN1bHQuZW50cnkubWV0YWRhdGEudmVyc2lvblxuICAgICAgfSkpO1xuICAgIH0gY2F0Y2gge1xuICAgICAgcmV0dXJuIFtdO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBTZWFyY2ggR2l0SHViIHBvcnRmb2xpb1xuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBzZWFyY2hHaXRIdWIocXVlcnk6IHN0cmluZywgb3B0aW9uczogVW5pZmllZFNlYXJjaE9wdGlvbnMpOiBQcm9taXNlPFVuaWZpZWRTZWFyY2hSZXN1bHRbXT4ge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBnaXRodWJJbmRleCA9IGF3YWl0IHRoaXMuZ2l0aHViSW5kZXhlci5nZXRJbmRleCgpO1xuICAgICAgY29uc3QgcmVzdWx0czogVW5pZmllZFNlYXJjaFJlc3VsdFtdID0gW107XG4gICAgICBcbiAgICAgIGNvbnN0IHF1ZXJ5TG93ZXIgPSBxdWVyeS50b0xvd2VyQ2FzZSgpO1xuICAgICAgY29uc3QgcXVlcnlUb2tlbnMgPSBxdWVyeUxvd2VyLnNwbGl0KC9cXHMrLykuZmlsdGVyKHRva2VuID0+IHRva2VuLmxlbmd0aCA+IDApO1xuICAgICAgXG4gICAgICBpZiAocXVlcnlUb2tlbnMubGVuZ3RoID09PSAwICYmIHF1ZXJ5LnRyaW0oKSAhPT0gJycpIHtcbiAgICAgICAgcmV0dXJuIHJlc3VsdHM7XG4gICAgICB9XG4gICAgICBcbiAgICAgIC8vIFNlYXJjaCBhY3Jvc3MgYWxsIEdpdEh1YiBlbGVtZW50c1xuICAgICAgZm9yIChjb25zdCBbZWxlbWVudFR5cGUsIGVudHJpZXNdIG9mIGdpdGh1YkluZGV4LmVsZW1lbnRzKSB7XG4gICAgICAgIC8vIEZpbHRlciBieSBlbGVtZW50IHR5cGUgaWYgc3BlY2lmaWVkXG4gICAgICAgIGlmIChvcHRpb25zLmVsZW1lbnRUeXBlICYmIGVsZW1lbnRUeXBlICE9PSBvcHRpb25zLmVsZW1lbnRUeXBlKSB7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cbiAgICAgICAgXG4gICAgICAgIGZvciAoY29uc3QgZW50cnkgb2YgZW50cmllcykge1xuICAgICAgICAgIGNvbnN0IHNjb3JlID0gdGhpcy5jYWxjdWxhdGVHaXRIdWJNYXRjaFNjb3JlKGVudHJ5LCBxdWVyeVRva2VucywgcXVlcnkpO1xuICAgICAgICAgIGlmIChzY29yZSA+IDAgfHwgcXVlcnkudHJpbSgpID09PSAnJykge1xuICAgICAgICAgICAgcmVzdWx0cy5wdXNoKHtcbiAgICAgICAgICAgICAgc291cmNlOiAnZ2l0aHViJyBhcyBjb25zdCxcbiAgICAgICAgICAgICAgZW50cnk6IHRoaXMuY29udmVydEdpdEh1YkVudHJ5KGVudHJ5KSxcbiAgICAgICAgICAgICAgbWF0Y2hUeXBlOiB0aGlzLmRldGVybWluZU1hdGNoVHlwZShlbnRyeSwgcXVlcnlUb2tlbnMpLFxuICAgICAgICAgICAgICBzY29yZTogcXVlcnkudHJpbSgpID09PSAnJyA/IDEgOiBzY29yZSwgLy8gRGVmYXVsdCBzY29yZSBmb3IgZW1wdHkgcXVlcnlcbiAgICAgICAgICAgICAgdmVyc2lvbjogZW50cnkudmVyc2lvblxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgICBcbiAgICAgIHJldHVybiByZXN1bHRzLnNvcnQoKGEsIGIpID0+IGIuc2NvcmUgLSBhLnNjb3JlKTtcbiAgICAgIFxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBsb2dnZXIuZGVidWcoJ0dpdEh1YiBzZWFyY2ggZmFpbGVkJywge1xuICAgICAgICBlcnJvcjogZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpXG4gICAgICB9KTtcbiAgICAgIHRocm93IGVycm9yOyAvLyBSZS10aHJvdyB0byB0cmlnZ2VyIGZhbGxiYWNrXG4gICAgfVxuICB9XG4gIFxuICAvKipcbiAgICogU2VhcmNoIEdpdEh1YiB3aXRoIGNhY2hlZCBkYXRhIGZhbGxiYWNrXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHNlYXJjaEdpdEh1YkNhY2hlZChxdWVyeTogc3RyaW5nLCBvcHRpb25zOiBVbmlmaWVkU2VhcmNoT3B0aW9ucyk6IFByb21pc2U8VW5pZmllZFNlYXJjaFJlc3VsdFtdPiB7XG4gICAgdHJ5IHtcbiAgICAgIC8vIFRyeSB0byB1c2Ugc3RhbGUgR2l0SHViIGRhdGFcbiAgICAgIGNvbnN0IGNhY2hlU3RhdHMgPSB0aGlzLmdpdGh1YkluZGV4ZXIuZ2V0Q2FjaGVTdGF0cygpO1xuICAgICAgaWYgKCFjYWNoZVN0YXRzLmlzU3RhbGUpIHtcbiAgICAgICAgcmV0dXJuIGF3YWl0IHRoaXMuc2VhcmNoR2l0SHViKHF1ZXJ5LCBvcHRpb25zKTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgLy8gVXNlIHN0YWxlIGRhdGEgd2l0aCByZWR1Y2VkIHNjb3Jlc1xuICAgICAgY29uc3QgcmVzdWx0cyA9IGF3YWl0IHRoaXMuc2VhcmNoR2l0SHViKHF1ZXJ5LCBvcHRpb25zKTtcbiAgICAgIHJldHVybiByZXN1bHRzLm1hcChyZXN1bHQgPT4gKHtcbiAgICAgICAgLi4ucmVzdWx0LFxuICAgICAgICBzY29yZTogcmVzdWx0LnNjb3JlICogMC43IC8vIFJlZHVjZSBzY29yZSBmb3Igc3RhbGUgZGF0YVxuICAgICAgfSkpO1xuICAgICAgXG4gICAgfSBjYXRjaCB7XG4gICAgICByZXR1cm4gW107XG4gICAgfVxuICB9XG4gIFxuICAvKipcbiAgICogU2VhcmNoIGNvbGxlY3Rpb24gcG9ydGZvbGlvXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHNlYXJjaENvbGxlY3Rpb24ocXVlcnk6IHN0cmluZywgb3B0aW9uczogVW5pZmllZFNlYXJjaE9wdGlvbnMpOiBQcm9taXNlPFVuaWZpZWRTZWFyY2hSZXN1bHRbXT4ge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBjb2xsZWN0aW9uSW5kZXggPSBhd2FpdCB0aGlzLmNvbGxlY3Rpb25JbmRleENhY2hlLmdldEluZGV4KCk7XG4gICAgICBjb25zdCByZXN1bHRzOiBVbmlmaWVkU2VhcmNoUmVzdWx0W10gPSBbXTtcbiAgICAgIFxuICAgICAgY29uc3QgcXVlcnlMb3dlciA9IHF1ZXJ5LnRvTG93ZXJDYXNlKCk7XG4gICAgICBjb25zdCBxdWVyeVRva2VucyA9IHF1ZXJ5TG93ZXIuc3BsaXQoL1xccysvKS5maWx0ZXIodG9rZW4gPT4gdG9rZW4ubGVuZ3RoID4gMCk7XG4gICAgICBcbiAgICAgIGlmIChxdWVyeVRva2Vucy5sZW5ndGggPT09IDAgJiYgcXVlcnkudHJpbSgpICE9PSAnJykge1xuICAgICAgICByZXR1cm4gcmVzdWx0cztcbiAgICAgIH1cbiAgICAgIFxuICAgICAgLy8gU2VhcmNoIGFjcm9zcyBhbGwgY29sbGVjdGlvbiBlbGVtZW50c1xuICAgICAgZm9yIChjb25zdCBbZWxlbWVudFR5cGUsIGVudHJpZXNdIG9mIE9iamVjdC5lbnRyaWVzKGNvbGxlY3Rpb25JbmRleC5pbmRleCkpIHtcbiAgICAgICAgLy8gRmlsdGVyIGJ5IGVsZW1lbnQgdHlwZSBpZiBzcGVjaWZpZWRcbiAgICAgICAgaWYgKG9wdGlvbnMuZWxlbWVudFR5cGUgJiYgZWxlbWVudFR5cGUgIT09IG9wdGlvbnMuZWxlbWVudFR5cGUudG9TdHJpbmcoKSkge1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG4gICAgICAgIFxuICAgICAgICBmb3IgKGNvbnN0IGVudHJ5IG9mIGVudHJpZXMpIHtcbiAgICAgICAgICBjb25zdCBzY29yZSA9IHRoaXMuY2FsY3VsYXRlQ29sbGVjdGlvbk1hdGNoU2NvcmUoZW50cnksIHF1ZXJ5VG9rZW5zLCBxdWVyeSk7XG4gICAgICAgICAgaWYgKHNjb3JlID4gMCB8fCBxdWVyeS50cmltKCkgPT09ICcnKSB7XG4gICAgICAgICAgICByZXN1bHRzLnB1c2goe1xuICAgICAgICAgICAgICBzb3VyY2U6ICdjb2xsZWN0aW9uJyBhcyBjb25zdCxcbiAgICAgICAgICAgICAgZW50cnk6IHRoaXMuY29udmVydENvbGxlY3Rpb25FbnRyeShlbnRyeSwgZWxlbWVudFR5cGUpLFxuICAgICAgICAgICAgICBtYXRjaFR5cGU6IHRoaXMuZGV0ZXJtaW5lQ29sbGVjdGlvbk1hdGNoVHlwZShlbnRyeSwgcXVlcnlUb2tlbnMpLFxuICAgICAgICAgICAgICBzY29yZTogcXVlcnkudHJpbSgpID09PSAnJyA/IDEgOiBzY29yZSwgLy8gRGVmYXVsdCBzY29yZSBmb3IgZW1wdHkgcXVlcnlcbiAgICAgICAgICAgICAgdmVyc2lvbjogZW50cnkudmVyc2lvblxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgICBcbiAgICAgIHJldHVybiByZXN1bHRzLnNvcnQoKGEsIGIpID0+IGIuc2NvcmUgLSBhLnNjb3JlKTtcbiAgICAgIFxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBsb2dnZXIuZGVidWcoJ0NvbGxlY3Rpb24gc2VhcmNoIGZhaWxlZCcsIHtcbiAgICAgICAgZXJyb3I6IGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKVxuICAgICAgfSk7XG4gICAgICB0aHJvdyBlcnJvcjsgLy8gUmUtdGhyb3cgdG8gdHJpZ2dlciBmYWxsYmFja1xuICAgIH1cbiAgfVxuICBcbiAgLyoqXG4gICAqIFNlYXJjaCBjb2xsZWN0aW9uIHdpdGggY2FjaGVkIGRhdGEgZmFsbGJhY2tcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgc2VhcmNoQ29sbGVjdGlvbkNhY2hlZChxdWVyeTogc3RyaW5nLCBvcHRpb25zOiBVbmlmaWVkU2VhcmNoT3B0aW9ucyk6IFByb21pc2U8VW5pZmllZFNlYXJjaFJlc3VsdFtdPiB7XG4gICAgdHJ5IHtcbiAgICAgIC8vIFRyeSB0byB1c2Ugc3RhbGUgY29sbGVjdGlvbiBkYXRhXG4gICAgICBjb25zdCBjYWNoZVN0YXRzID0gdGhpcy5jb2xsZWN0aW9uSW5kZXhDYWNoZS5nZXRDYWNoZVN0YXRzKCk7XG4gICAgICBpZiAoY2FjaGVTdGF0cy5pc1ZhbGlkKSB7XG4gICAgICAgIHJldHVybiBhd2FpdCB0aGlzLnNlYXJjaENvbGxlY3Rpb24ocXVlcnksIG9wdGlvbnMpO1xuICAgICAgfVxuICAgICAgXG4gICAgICAvLyBVc2Ugc3RhbGUgZGF0YSB3aXRoIHJlZHVjZWQgc2NvcmVzXG4gICAgICBjb25zdCByZXN1bHRzID0gYXdhaXQgdGhpcy5zZWFyY2hDb2xsZWN0aW9uKHF1ZXJ5LCBvcHRpb25zKTtcbiAgICAgIHJldHVybiByZXN1bHRzLm1hcChyZXN1bHQgPT4gKHtcbiAgICAgICAgLi4ucmVzdWx0LFxuICAgICAgICBzY29yZTogcmVzdWx0LnNjb3JlICogMC42IC8vIFJlZHVjZSBzY29yZSBmb3Igc3RhbGUgY29sbGVjdGlvbiBkYXRhXG4gICAgICB9KSk7XG4gICAgICBcbiAgICB9IGNhdGNoIHtcbiAgICAgIHJldHVybiBbXTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUHJvY2VzcyBzZWFyY2ggcmVzdWx0cyB3aXRoIGFkdmFuY2VkIGZlYXR1cmVzXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHByb2Nlc3NTZWFyY2hSZXN1bHRzKHJlc3VsdHM6IFVuaWZpZWRTZWFyY2hSZXN1bHRbXSwgb3B0aW9uczogVW5pZmllZFNlYXJjaE9wdGlvbnMpOiBQcm9taXNlPFVuaWZpZWRTZWFyY2hSZXN1bHRbXT4ge1xuICAgIC8vIEFwcGx5IHNtYXJ0IHJhbmtpbmdcbiAgICBjb25zdCByYW5rZWRSZXN1bHRzID0gdGhpcy5hcHBseVNtYXJ0UmFua2luZyhyZXN1bHRzLCBvcHRpb25zKTtcbiAgICBcbiAgICAvLyBEZXRlY3QgZHVwbGljYXRlcyBhbmQgdmVyc2lvbiBjb25mbGljdHNcbiAgICBjb25zdCBwcm9jZXNzZWRSZXN1bHRzID0gYXdhaXQgdGhpcy5kZXRlY3REdXBsaWNhdGVzQW5kQ29uZmxpY3RzKHJhbmtlZFJlc3VsdHMpO1xuICAgIFxuICAgIC8vIEFwcGx5IHNvcnRpbmdcbiAgICBjb25zdCBzb3J0ZWRSZXN1bHRzID0gdGhpcy5hcHBseVNvcnRpbmcocHJvY2Vzc2VkUmVzdWx0cywgb3B0aW9ucy5zb3J0QnkgfHwgJ3JlbGV2YW5jZScsIG9wdGlvbnMucXVlcnkpO1xuICAgIFxuICAgIHJldHVybiBzb3J0ZWRSZXN1bHRzO1xuICB9XG4gIFxuICAvKipcbiAgICogQXBwbHkgc21hcnQgcmVzdWx0IHJhbmtpbmdcbiAgICovXG4gIHByaXZhdGUgYXBwbHlTbWFydFJhbmtpbmcocmVzdWx0czogVW5pZmllZFNlYXJjaFJlc3VsdFtdLCBvcHRpb25zOiBVbmlmaWVkU2VhcmNoT3B0aW9ucyk6IFVuaWZpZWRTZWFyY2hSZXN1bHRbXSB7XG4gICAgcmV0dXJuIHJlc3VsdHMubWFwKHJlc3VsdCA9PiB7XG4gICAgICBsZXQgYWRqdXN0ZWRTY29yZSA9IHJlc3VsdC5zY29yZTtcbiAgICAgIFxuICAgICAgLy8gTm8gbG9jYXRpb24tYmFzZWQgc2NvcmluZyAtIHNjb3JlIHNob3VsZCBiZSBiYXNlZCBvbiByZWxldmFuY2Ugb25seVxuICAgICAgLy8gU291cmNlIGxvY2F0aW9uIGRvZXNuJ3QgYWZmZWN0IHRoZSBpbnRyaW5zaWMgdmFsdWUgb2YgYW4gZWxlbWVudFxuICAgICAgXG4gICAgICAvLyBDb25zaWRlciB2ZXJzaW9uIGZyZXNobmVzcyAobmV3ZXIgdmVyc2lvbnMgZ2V0IHNtYWxsIGJvbnVzKVxuICAgICAgaWYgKHJlc3VsdC52ZXJzaW9uICYmIHJlc3VsdC52ZXJzaW9uICE9PSAndW5rbm93bicpIHtcbiAgICAgICAgY29uc3QgdmVyc2lvblBhcnRzID0gcmVzdWx0LnZlcnNpb24uc3BsaXQoJy4nKTtcbiAgICAgICAgaWYgKHZlcnNpb25QYXJ0cy5sZW5ndGggPj0gMikge1xuICAgICAgICAgIGNvbnN0IG1ham9yID0gcGFyc2VJbnQodmVyc2lvblBhcnRzWzBdKSB8fCAwO1xuICAgICAgICAgIGNvbnN0IG1pbm9yID0gcGFyc2VJbnQodmVyc2lvblBhcnRzWzFdKSB8fCAwO1xuICAgICAgICAgIGFkanVzdGVkU2NvcmUgKz0gKG1ham9yICogMC4xKSArIChtaW5vciAqIDAuMDEpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBcbiAgICAgIC8vIEJvb3N0IGV4YWN0IG1hdGNoZXNcbiAgICAgIGlmIChyZXN1bHQuZW50cnkubmFtZS50b0xvd2VyQ2FzZSgpID09PSBvcHRpb25zLnF1ZXJ5LnRvTG93ZXJDYXNlKCkpIHtcbiAgICAgICAgYWRqdXN0ZWRTY29yZSAqPSAyLjA7XG4gICAgICB9XG4gICAgICBcbiAgICAgIHJldHVybiB7XG4gICAgICAgIC4uLnJlc3VsdCxcbiAgICAgICAgc2NvcmU6IGFkanVzdGVkU2NvcmVcbiAgICAgIH07XG4gICAgfSk7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBEZXRlY3QgZHVwbGljYXRlcyBhbmQgdmVyc2lvbiBjb25mbGljdHNcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgZGV0ZWN0RHVwbGljYXRlc0FuZENvbmZsaWN0cyhyZXN1bHRzOiBVbmlmaWVkU2VhcmNoUmVzdWx0W10pOiBQcm9taXNlPFVuaWZpZWRTZWFyY2hSZXN1bHRbXT4ge1xuICAgIGNvbnN0IG5hbWVNYXAgPSBuZXcgTWFwPHN0cmluZywgVW5pZmllZFNlYXJjaFJlc3VsdFtdPigpO1xuICAgIFxuICAgIC8vIEdyb3VwIGJ5IG5hbWUgYW5kIGVsZW1lbnQgdHlwZVxuICAgIGZvciAoY29uc3QgcmVzdWx0IG9mIHJlc3VsdHMpIHtcbiAgICAgIGNvbnN0IGtleSA9IGAke3Jlc3VsdC5lbnRyeS5lbGVtZW50VHlwZX06JHtyZXN1bHQuZW50cnkubmFtZS50b0xvd2VyQ2FzZSgpfWA7XG4gICAgICBpZiAoIW5hbWVNYXAuaGFzKGtleSkpIHtcbiAgICAgICAgbmFtZU1hcC5zZXQoa2V5LCBbXSk7XG4gICAgICB9XG4gICAgICBuYW1lTWFwLmdldChrZXkpIS5wdXNoKHJlc3VsdCk7XG4gICAgfVxuICAgIFxuICAgIGNvbnN0IHByb2Nlc3NlZFJlc3VsdHM6IFVuaWZpZWRTZWFyY2hSZXN1bHRbXSA9IFtdO1xuICAgIFxuICAgIC8vIFByb2Nlc3MgZWFjaCBncm91cFxuICAgIGZvciAoY29uc3QgW2tleSwgZ3JvdXBSZXN1bHRzXSBvZiBuYW1lTWFwKSB7XG4gICAgICBpZiAoZ3JvdXBSZXN1bHRzLmxlbmd0aCA9PT0gMSkge1xuICAgICAgICAvLyBObyBkdXBsaWNhdGVzXG4gICAgICAgIHByb2Nlc3NlZFJlc3VsdHMucHVzaChncm91cFJlc3VsdHNbMF0pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gSGFzIGR1cGxpY2F0ZXMgLSBkZXRlY3QgdmVyc2lvbiBjb25mbGljdHNcbiAgICAgICAgY29uc3QgdmVyc2lvbkNvbmZsaWN0ID0gdGhpcy5kZXRlY3RWZXJzaW9uQ29uZmxpY3RGcm9tUmVzdWx0cyhncm91cFJlc3VsdHMpO1xuICAgICAgICBcbiAgICAgICAgLy8gTWFyayBhbGwgcmVzdWx0cyBhcyBkdXBsaWNhdGVzIGFuZCBhZGQgY29uZmxpY3QgaW5mb1xuICAgICAgICBmb3IgKGNvbnN0IHJlc3VsdCBvZiBncm91cFJlc3VsdHMpIHtcbiAgICAgICAgICBwcm9jZXNzZWRSZXN1bHRzLnB1c2goe1xuICAgICAgICAgICAgLi4ucmVzdWx0LFxuICAgICAgICAgICAgaXNEdXBsaWNhdGU6IHRydWUsXG4gICAgICAgICAgICB2ZXJzaW9uQ29uZmxpY3RcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgICBcbiAgICByZXR1cm4gcHJvY2Vzc2VkUmVzdWx0cztcbiAgfVxuICBcbiAgLyoqXG4gICAqIEFwcGx5IHBhZ2luYXRpb24gdG8gcmVzdWx0c1xuICAgKi9cbiAgcHJpdmF0ZSBhcHBseVBhZ2luYXRpb24ocmVzdWx0czogVW5pZmllZFNlYXJjaFJlc3VsdFtdLCBvcHRpb25zOiBVbmlmaWVkU2VhcmNoT3B0aW9ucyk6IFVuaWZpZWRTZWFyY2hSZXN1bHRbXSB7XG4gICAgY29uc3QgcGFnZSA9IG9wdGlvbnMucGFnZSB8fCAxO1xuICAgIGNvbnN0IHBhZ2VTaXplID0gb3B0aW9ucy5wYWdlU2l6ZSB8fCAyMDtcbiAgICBjb25zdCBzdGFydEluZGV4ID0gKHBhZ2UgLSAxKSAqIHBhZ2VTaXplO1xuICAgIGNvbnN0IGVuZEluZGV4ID0gc3RhcnRJbmRleCArIHBhZ2VTaXplO1xuICAgIFxuICAgIHJldHVybiByZXN1bHRzLnNsaWNlKHN0YXJ0SW5kZXgsIGVuZEluZGV4KTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEFwcGx5IHNvcnRpbmcgdG8gcmVzdWx0c1xuICAgKi9cbiAgcHJpdmF0ZSBhcHBseVNvcnRpbmcocmVzdWx0czogVW5pZmllZFNlYXJjaFJlc3VsdFtdLCBzb3J0Qnk6ICdyZWxldmFuY2UnIHwgJ3NvdXJjZScgfCAnbmFtZScgfCAndmVyc2lvbicsIHF1ZXJ5OiBzdHJpbmcpOiBVbmlmaWVkU2VhcmNoUmVzdWx0W10ge1xuICAgIGNvbnN0IHNvcnRlZCA9IFsuLi5yZXN1bHRzXTtcbiAgICBcbiAgICBzd2l0Y2ggKHNvcnRCeSkge1xuICAgICAgY2FzZSAnbmFtZSc6XG4gICAgICAgIHNvcnRlZC5zb3J0KChhLCBiKSA9PiBhLmVudHJ5Lm5hbWUubG9jYWxlQ29tcGFyZShiLmVudHJ5Lm5hbWUpKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlICdzb3VyY2UnOlxuICAgICAgICBzb3J0ZWQuc29ydCgoYSwgYikgPT4ge1xuICAgICAgICAgIGNvbnN0IHNvdXJjZU9yZGVyID0geyAnbG9jYWwnOiAwLCAnZ2l0aHViJzogMSwgJ2NvbGxlY3Rpb24nOiAyIH07XG4gICAgICAgICAgcmV0dXJuIHNvdXJjZU9yZGVyW2Euc291cmNlXSAtIHNvdXJjZU9yZGVyW2Iuc291cmNlXTtcbiAgICAgICAgfSk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAndmVyc2lvbic6XG4gICAgICAgIHNvcnRlZC5zb3J0KChhLCBiKSA9PiB0aGlzLmNvbXBhcmVWZXJzaW9ucyhiLnZlcnNpb24gfHwgJzAnLCBhLnZlcnNpb24gfHwgJzAnKSk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAncmVsZXZhbmNlJzpcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHNvcnRlZC5zb3J0KChhLCBiKSA9PiBiLnNjb3JlIC0gYS5zY29yZSk7XG4gICAgICAgIGJyZWFrO1xuICAgIH1cbiAgICBcbiAgICByZXR1cm4gc29ydGVkO1xuICB9XG4gIFxuICAvKipcbiAgICogQ2FsY3VsYXRlIG1hdGNoIHNjb3JlIGZvciBHaXRIdWIgZW50cmllc1xuICAgKi9cbiAgcHJpdmF0ZSBjYWxjdWxhdGVHaXRIdWJNYXRjaFNjb3JlKGVudHJ5OiBHaXRIdWJJbmRleEVudHJ5LCBxdWVyeVRva2Vuczogc3RyaW5nW10sIHF1ZXJ5OiBzdHJpbmcpOiBudW1iZXIge1xuICAgIGlmIChxdWVyeVRva2Vucy5sZW5ndGggPT09IDApIHJldHVybiAxOyAvLyBEZWZhdWx0IHNjb3JlIGZvciBlbXB0eSBxdWVyeVxuICAgIFxuICAgIGxldCBzY29yZSA9IDA7XG4gICAgXG4gICAgY29uc3QgbmFtZSA9IGVudHJ5Lm5hbWUudG9Mb3dlckNhc2UoKTtcbiAgICBjb25zdCBkZXNjcmlwdGlvbiA9IChlbnRyeS5kZXNjcmlwdGlvbiB8fCAnJykudG9Mb3dlckNhc2UoKTtcbiAgICBjb25zdCBwYXRoID0gKGVudHJ5LnBhdGggfHwgJycpLnRvTG93ZXJDYXNlKCk7XG4gICAgXG4gICAgLy8gQ2hlY2sgbmFtZSBtYXRjaGVzXG4gICAgZm9yIChjb25zdCB0b2tlbiBvZiBxdWVyeVRva2Vucykge1xuICAgICAgaWYgKG5hbWUuaW5jbHVkZXModG9rZW4pKSB7XG4gICAgICAgIHNjb3JlICs9IG5hbWUgPT09IHRva2VuID8gMTAgOiAobmFtZS5zdGFydHNXaXRoKHRva2VuKSA/IDUgOiAyKTtcbiAgICAgIH1cbiAgICAgIGlmIChkZXNjcmlwdGlvbi5pbmNsdWRlcyh0b2tlbikpIHtcbiAgICAgICAgc2NvcmUgKz0gMztcbiAgICAgIH1cbiAgICAgIGlmIChwYXRoLmluY2x1ZGVzKHRva2VuKSkge1xuICAgICAgICBzY29yZSArPSAxO1xuICAgICAgfVxuICAgIH1cbiAgICBcbiAgICAvLyBFeGFjdCBxdWVyeSBtYXRjaCBib251c1xuICAgIGlmIChuYW1lLmluY2x1ZGVzKHF1ZXJ5LnRvTG93ZXJDYXNlKCkpKSB7XG4gICAgICBzY29yZSArPSBxdWVyeS5sZW5ndGggPiAzID8gMTUgOiAxMDtcbiAgICB9XG4gICAgXG4gICAgcmV0dXJuIHNjb3JlO1xuICB9XG4gIFxuICAvKipcbiAgICogQ2FsY3VsYXRlIG1hdGNoIHNjb3JlIGZvciBjb2xsZWN0aW9uIGVudHJpZXNcbiAgICovXG4gIHByaXZhdGUgY2FsY3VsYXRlQ29sbGVjdGlvbk1hdGNoU2NvcmUoZW50cnk6IENvbGxlY3Rpb25JbmRleEVudHJ5LCBxdWVyeVRva2Vuczogc3RyaW5nW10sIHF1ZXJ5OiBzdHJpbmcpOiBudW1iZXIge1xuICAgIGlmIChxdWVyeVRva2Vucy5sZW5ndGggPT09IDApIHJldHVybiAxOyAvLyBEZWZhdWx0IHNjb3JlIGZvciBlbXB0eSBxdWVyeVxuICAgIFxuICAgIGxldCBzY29yZSA9IDA7XG4gICAgXG4gICAgY29uc3QgbmFtZSA9IGVudHJ5Lm5hbWUudG9Mb3dlckNhc2UoKTtcbiAgICBjb25zdCBkZXNjcmlwdGlvbiA9IChlbnRyeS5kZXNjcmlwdGlvbiB8fCAnJykudG9Mb3dlckNhc2UoKTtcbiAgICBjb25zdCBwYXRoID0gKGVudHJ5LnBhdGggfHwgJycpLnRvTG93ZXJDYXNlKCk7XG4gICAgY29uc3QgdGFncyA9IGVudHJ5LnRhZ3MubWFwKHRhZyA9PiB0YWcudG9Mb3dlckNhc2UoKSkuam9pbignICcpO1xuICAgIFxuICAgIC8vIENoZWNrIG1hdGNoZXMgYWNyb3NzIGFsbCBmaWVsZHNcbiAgICBmb3IgKGNvbnN0IHRva2VuIG9mIHF1ZXJ5VG9rZW5zKSB7XG4gICAgICBpZiAobmFtZS5pbmNsdWRlcyh0b2tlbikpIHtcbiAgICAgICAgc2NvcmUgKz0gbmFtZSA9PT0gdG9rZW4gPyAxMCA6IChuYW1lLnN0YXJ0c1dpdGgodG9rZW4pID8gNSA6IDIpO1xuICAgICAgfVxuICAgICAgaWYgKGRlc2NyaXB0aW9uLmluY2x1ZGVzKHRva2VuKSkge1xuICAgICAgICBzY29yZSArPSAzO1xuICAgICAgfVxuICAgICAgaWYgKHBhdGguaW5jbHVkZXModG9rZW4pKSB7XG4gICAgICAgIHNjb3JlICs9IDE7XG4gICAgICB9XG4gICAgICBpZiAodGFncy5pbmNsdWRlcyh0b2tlbikpIHtcbiAgICAgICAgc2NvcmUgKz0gNDtcbiAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgLy8gRXhhY3QgcXVlcnkgbWF0Y2ggYm9udXNcbiAgICBpZiAobmFtZS5pbmNsdWRlcyhxdWVyeS50b0xvd2VyQ2FzZSgpKSkge1xuICAgICAgc2NvcmUgKz0gcXVlcnkubGVuZ3RoID4gMyA/IDE1IDogMTA7XG4gICAgfVxuICAgIFxuICAgIHJldHVybiBzY29yZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgYWxsIGVsZW1lbnRzIGJ5IHR5cGUgYWNyb3NzIHNvdXJjZXNcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgZ2V0QWxsRWxlbWVudHNCeVR5cGUoZWxlbWVudFR5cGU6IEVsZW1lbnRUeXBlLCBvcHRpb25zOiBVbmlmaWVkU2VhcmNoT3B0aW9ucyk6IFByb21pc2U8VW5pZmllZFNlYXJjaFJlc3VsdFtdPiB7XG4gICAgY29uc3QgcHJvbWlzZXM6IFByb21pc2U8VW5pZmllZFNlYXJjaFJlc3VsdFtdPltdID0gW107XG4gICAgXG4gICAgaWYgKG9wdGlvbnMuaW5jbHVkZUxvY2FsKSB7XG4gICAgICBwcm9taXNlcy5wdXNoKHRoaXMuZ2V0TG9jYWxFbGVtZW50c0J5VHlwZShlbGVtZW50VHlwZSkpO1xuICAgIH1cbiAgICBpZiAob3B0aW9ucy5pbmNsdWRlR2l0SHViKSB7XG4gICAgICBwcm9taXNlcy5wdXNoKHRoaXMuZ2V0R2l0SHViRWxlbWVudHNCeVR5cGUoZWxlbWVudFR5cGUpKTtcbiAgICB9XG4gICAgaWYgKG9wdGlvbnMuaW5jbHVkZUNvbGxlY3Rpb24pIHtcbiAgICAgIHByb21pc2VzLnB1c2godGhpcy5nZXRDb2xsZWN0aW9uRWxlbWVudHNCeVR5cGUoZWxlbWVudFR5cGUpKTtcbiAgICB9XG4gICAgXG4gICAgY29uc3QgcmVzdWx0cyA9IGF3YWl0IFByb21pc2UuYWxsU2V0dGxlZChwcm9taXNlcyk7XG4gICAgY29uc3QgYWxsUmVzdWx0czogVW5pZmllZFNlYXJjaFJlc3VsdFtdID0gW107XG4gICAgXG4gICAgcmVzdWx0cy5mb3JFYWNoKHJlc3VsdCA9PiB7XG4gICAgICBpZiAocmVzdWx0LnN0YXR1cyA9PT0gJ2Z1bGZpbGxlZCcpIHtcbiAgICAgICAgYWxsUmVzdWx0cy5wdXNoKC4uLnJlc3VsdC52YWx1ZSk7XG4gICAgICB9XG4gICAgfSk7XG4gICAgXG4gICAgcmV0dXJuIGFsbFJlc3VsdHM7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZXQgbG9jYWwgZWxlbWVudHMgYnkgdHlwZVxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBnZXRMb2NhbEVsZW1lbnRzQnlUeXBlKGVsZW1lbnRUeXBlOiBFbGVtZW50VHlwZSk6IFByb21pc2U8VW5pZmllZFNlYXJjaFJlc3VsdFtdPiB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGVsZW1lbnRzID0gYXdhaXQgdGhpcy5sb2NhbEluZGV4TWFuYWdlci5nZXRFbGVtZW50c0J5VHlwZShlbGVtZW50VHlwZSk7XG4gICAgICByZXR1cm4gZWxlbWVudHMubWFwKGVudHJ5ID0+ICh7XG4gICAgICAgIHNvdXJjZTogJ2xvY2FsJyBhcyBjb25zdCxcbiAgICAgICAgZW50cnk6IHRoaXMuY29udmVydExvY2FsRW50cnkoZW50cnkpLFxuICAgICAgICBtYXRjaFR5cGU6ICd0eXBlJyxcbiAgICAgICAgc2NvcmU6IDEsXG4gICAgICAgIHZlcnNpb246IGVudHJ5Lm1ldGFkYXRhLnZlcnNpb25cbiAgICAgIH0pKTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIHJldHVybiBbXTtcbiAgICB9XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZXQgR2l0SHViIGVsZW1lbnRzIGJ5IHR5cGVcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgZ2V0R2l0SHViRWxlbWVudHNCeVR5cGUoZWxlbWVudFR5cGU6IEVsZW1lbnRUeXBlKTogUHJvbWlzZTxVbmlmaWVkU2VhcmNoUmVzdWx0W10+IHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgZ2l0aHViSW5kZXggPSBhd2FpdCB0aGlzLmdpdGh1YkluZGV4ZXIuZ2V0SW5kZXgoKTtcbiAgICAgIGNvbnN0IGVudHJpZXMgPSBnaXRodWJJbmRleC5lbGVtZW50cy5nZXQoZWxlbWVudFR5cGUpIHx8IFtdO1xuICAgICAgXG4gICAgICByZXR1cm4gZW50cmllcy5tYXAoZW50cnkgPT4gKHtcbiAgICAgICAgc291cmNlOiAnZ2l0aHViJyBhcyBjb25zdCxcbiAgICAgICAgZW50cnk6IHRoaXMuY29udmVydEdpdEh1YkVudHJ5KGVudHJ5KSxcbiAgICAgICAgbWF0Y2hUeXBlOiAndHlwZScsXG4gICAgICAgIHNjb3JlOiAxLFxuICAgICAgICB2ZXJzaW9uOiBlbnRyeS52ZXJzaW9uXG4gICAgICB9KSk7XG4gICAgfSBjYXRjaCB7XG4gICAgICByZXR1cm4gW107XG4gICAgfVxuICB9XG4gIFxuICAvKipcbiAgICogR2V0IGNvbGxlY3Rpb24gZWxlbWVudHMgYnkgdHlwZVxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBnZXRDb2xsZWN0aW9uRWxlbWVudHNCeVR5cGUoZWxlbWVudFR5cGU6IEVsZW1lbnRUeXBlKTogUHJvbWlzZTxVbmlmaWVkU2VhcmNoUmVzdWx0W10+IHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgY29sbGVjdGlvbkluZGV4ID0gYXdhaXQgdGhpcy5jb2xsZWN0aW9uSW5kZXhDYWNoZS5nZXRJbmRleCgpO1xuICAgICAgY29uc3QgZW50cmllcyA9IGNvbGxlY3Rpb25JbmRleC5pbmRleFtlbGVtZW50VHlwZS50b1N0cmluZygpXSB8fCBbXTtcbiAgICAgIFxuICAgICAgcmV0dXJuIGVudHJpZXMubWFwKGVudHJ5ID0+ICh7XG4gICAgICAgIHNvdXJjZTogJ2NvbGxlY3Rpb24nIGFzIGNvbnN0LFxuICAgICAgICBlbnRyeTogdGhpcy5jb252ZXJ0Q29sbGVjdGlvbkVudHJ5KGVudHJ5LCBlbGVtZW50VHlwZS50b1N0cmluZygpKSxcbiAgICAgICAgbWF0Y2hUeXBlOiAndHlwZScsXG4gICAgICAgIHNjb3JlOiAxLFxuICAgICAgICB2ZXJzaW9uOiBlbnRyeS52ZXJzaW9uXG4gICAgICB9KSk7XG4gICAgfSBjYXRjaCB7XG4gICAgICByZXR1cm4gW107XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEdldCBsb2NhbCBwb3J0Zm9saW8gc3RhdGlzdGljc1xuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBnZXRMb2NhbFN0YXRzKCk6IFByb21pc2U8VW5pZmllZEluZGV4U3RhdHNbJ2xvY2FsJ10+IHtcbiAgICByZXR1cm4gYXdhaXQgdGhpcy5sb2NhbEluZGV4TWFuYWdlci5nZXRTdGF0cygpO1xuICB9XG4gIFxuICAvKipcbiAgICogR2V0IEdpdEh1YiBwb3J0Zm9saW8gc3RhdGlzdGljc1xuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBnZXRHaXRIdWJTdGF0cygpOiBQcm9taXNlPFVuaWZpZWRJbmRleFN0YXRzWydnaXRodWInXT4ge1xuICAgIGNvbnN0IGNhY2hlU3RhdHMgPSB0aGlzLmdpdGh1YkluZGV4ZXIuZ2V0Q2FjaGVTdGF0cygpO1xuICAgIGNvbnN0IGdpdGh1YkluZGV4ID0gYXdhaXQgdGhpcy5naXRodWJJbmRleGVyLmdldEluZGV4KCk7XG4gICAgXG4gICAgY29uc3QgZWxlbWVudHNCeVR5cGU6IFJlY29yZDxFbGVtZW50VHlwZSwgbnVtYmVyPiA9IHt9IGFzIFJlY29yZDxFbGVtZW50VHlwZSwgbnVtYmVyPjtcbiAgICBmb3IgKGNvbnN0IGVsZW1lbnRUeXBlIG9mIE9iamVjdC52YWx1ZXMoRWxlbWVudFR5cGUpKSB7XG4gICAgICBlbGVtZW50c0J5VHlwZVtlbGVtZW50VHlwZV0gPSAoZ2l0aHViSW5kZXguZWxlbWVudHMuZ2V0KGVsZW1lbnRUeXBlKSB8fCBbXSkubGVuZ3RoO1xuICAgIH1cbiAgICBcbiAgICByZXR1cm4ge1xuICAgICAgdG90YWxFbGVtZW50czogZ2l0aHViSW5kZXgudG90YWxFbGVtZW50cyxcbiAgICAgIGVsZW1lbnRzQnlUeXBlLFxuICAgICAgbGFzdEZldGNoZWQ6IGNhY2hlU3RhdHMubGFzdEZldGNoLFxuICAgICAgaXNTdGFsZTogY2FjaGVTdGF0cy5pc1N0YWxlLFxuICAgICAgdXNlcm5hbWU6IGdpdGh1YkluZGV4LnVzZXJuYW1lLFxuICAgICAgcmVwb3NpdG9yeTogZ2l0aHViSW5kZXgucmVwb3NpdG9yeVxuICAgIH07XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZXQgY29sbGVjdGlvbiBwb3J0Zm9saW8gc3RhdGlzdGljc1xuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBnZXRDb2xsZWN0aW9uU3RhdHMoKTogUHJvbWlzZTxVbmlmaWVkSW5kZXhTdGF0c1snY29sbGVjdGlvbiddPiB7XG4gICAgY29uc3QgY2FjaGVTdGF0cyA9IHRoaXMuY29sbGVjdGlvbkluZGV4Q2FjaGUuZ2V0Q2FjaGVTdGF0cygpO1xuICAgIGNvbnN0IGNvbGxlY3Rpb25JbmRleCA9IGF3YWl0IHRoaXMuY29sbGVjdGlvbkluZGV4Q2FjaGUuZ2V0SW5kZXgoKTtcbiAgICBcbiAgICBjb25zdCBlbGVtZW50c0J5VHlwZTogUmVjb3JkPHN0cmluZywgbnVtYmVyPiA9IHt9O1xuICAgIGZvciAoY29uc3QgW2VsZW1lbnRUeXBlLCBlbnRyaWVzXSBvZiBPYmplY3QuZW50cmllcyhjb2xsZWN0aW9uSW5kZXguaW5kZXgpKSB7XG4gICAgICBlbGVtZW50c0J5VHlwZVtlbGVtZW50VHlwZV0gPSBlbnRyaWVzLmxlbmd0aDtcbiAgICB9XG4gICAgXG4gICAgcmV0dXJuIHtcbiAgICAgIHRvdGFsRWxlbWVudHM6IGNvbGxlY3Rpb25JbmRleC50b3RhbF9lbGVtZW50cyxcbiAgICAgIGVsZW1lbnRzQnlUeXBlLFxuICAgICAgbGFzdEZldGNoZWQ6IGNhY2hlU3RhdHMuaGFzQ2FjaGUgPyBuZXcgRGF0ZShEYXRlLm5vdygpIC0gY2FjaGVTdGF0cy5hZ2UpIDogbnVsbCxcbiAgICAgIGlzU3RhbGU6ICFjYWNoZVN0YXRzLmlzVmFsaWQsXG4gICAgICB2ZXJzaW9uOiBjb2xsZWN0aW9uSW5kZXgudmVyc2lvblxuICAgIH07XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBDYWxjdWxhdGUgZHVwbGljYXRlcyBjb3VudCBhY3Jvc3MgYWxsIHNvdXJjZXNcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgY2FsY3VsYXRlRHVwbGljYXRlc0NvdW50KCk6IFByb21pc2U8bnVtYmVyPiB7XG4gICAgdHJ5IHtcbiAgICAgIC8vIFRoaXMgaXMgYSBwbGFjZWhvbGRlciAtIGFjdHVhbCBpbXBsZW1lbnRhdGlvbiB3b3VsZCBuZWVkIG9wdGltaXphdGlvblxuICAgICAgLy8gRm9yIG5vdywgcmV0dXJuIDAgdG8gYXZvaWQgdGhlIGV4cGVuc2l2ZSBvcGVyYXRpb24gZHVyaW5nIHN0YXRzIGNhbGN1bGF0aW9uXG4gICAgICByZXR1cm4gMDtcbiAgICB9IGNhdGNoIHtcbiAgICAgIHJldHVybiAwO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBDb252ZXJ0IGxvY2FsIGluZGV4IGVudHJ5IHRvIHVuaWZpZWQgZm9ybWF0XG4gICAqL1xuICBwcml2YXRlIGNvbnZlcnRMb2NhbEVudHJ5KGVudHJ5OiBJbmRleEVudHJ5KTogVW5pZmllZEluZGV4RW50cnkge1xuICAgIHJldHVybiB7XG4gICAgICBuYW1lOiBlbnRyeS5tZXRhZGF0YS5uYW1lLFxuICAgICAgZGVzY3JpcHRpb246IGVudHJ5Lm1ldGFkYXRhLmRlc2NyaXB0aW9uLFxuICAgICAgdmVyc2lvbjogZW50cnkubWV0YWRhdGEudmVyc2lvbixcbiAgICAgIGF1dGhvcjogZW50cnkubWV0YWRhdGEuYXV0aG9yLFxuICAgICAgZWxlbWVudFR5cGU6IGVudHJ5LmVsZW1lbnRUeXBlLFxuICAgICAgbGFzdE1vZGlmaWVkOiBlbnRyeS5sYXN0TW9kaWZpZWQsXG4gICAgICBzb3VyY2U6ICdsb2NhbCcsXG4gICAgICBsb2NhbEZpbGVQYXRoOiBlbnRyeS5maWxlUGF0aCxcbiAgICAgIGZpbGVuYW1lOiBlbnRyeS5maWxlbmFtZSxcbiAgICAgIHRhZ3M6IGVudHJ5Lm1ldGFkYXRhLnRhZ3MsXG4gICAgICBrZXl3b3JkczogZW50cnkubWV0YWRhdGEua2V5d29yZHMsXG4gICAgICB0cmlnZ2VyczogZW50cnkubWV0YWRhdGEudHJpZ2dlcnMsXG4gICAgICBjYXRlZ29yeTogZW50cnkubWV0YWRhdGEuY2F0ZWdvcnlcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIENvbnZlcnQgR2l0SHViIGluZGV4IGVudHJ5IHRvIHVuaWZpZWQgZm9ybWF0XG4gICAqL1xuICBwcml2YXRlIGNvbnZlcnRHaXRIdWJFbnRyeShlbnRyeTogR2l0SHViSW5kZXhFbnRyeSk6IFVuaWZpZWRJbmRleEVudHJ5IHtcbiAgICByZXR1cm4ge1xuICAgICAgbmFtZTogZW50cnkubmFtZSxcbiAgICAgIGRlc2NyaXB0aW9uOiBlbnRyeS5kZXNjcmlwdGlvbixcbiAgICAgIHZlcnNpb246IGVudHJ5LnZlcnNpb24sXG4gICAgICBhdXRob3I6IGVudHJ5LmF1dGhvcixcbiAgICAgIGVsZW1lbnRUeXBlOiBlbnRyeS5lbGVtZW50VHlwZSxcbiAgICAgIGxhc3RNb2RpZmllZDogZW50cnkubGFzdE1vZGlmaWVkLFxuICAgICAgc291cmNlOiAnZ2l0aHViJyxcbiAgICAgIGdpdGh1YlBhdGg6IGVudHJ5LnBhdGgsXG4gICAgICBnaXRodWJTaGE6IGVudHJ5LnNoYSxcbiAgICAgIGdpdGh1Ykh0bWxVcmw6IGVudHJ5Lmh0bWxVcmwsXG4gICAgICBnaXRodWJEb3dubG9hZFVybDogZW50cnkuZG93bmxvYWRVcmwsXG4gICAgICBnaXRodWJTaXplOiBlbnRyeS5zaXplXG4gICAgfTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIENvbnZlcnQgY29sbGVjdGlvbiBpbmRleCBlbnRyeSB0byB1bmlmaWVkIGZvcm1hdFxuICAgKi9cbiAgcHJpdmF0ZSBjb252ZXJ0Q29sbGVjdGlvbkVudHJ5KGVudHJ5OiBDb2xsZWN0aW9uSW5kZXhFbnRyeSwgZWxlbWVudFR5cGU6IHN0cmluZyk6IFVuaWZpZWRJbmRleEVudHJ5IHtcbiAgICByZXR1cm4ge1xuICAgICAgbmFtZTogZW50cnkubmFtZSxcbiAgICAgIGRlc2NyaXB0aW9uOiBlbnRyeS5kZXNjcmlwdGlvbixcbiAgICAgIHZlcnNpb246IGVudHJ5LnZlcnNpb24sXG4gICAgICBhdXRob3I6IGVudHJ5LmF1dGhvcixcbiAgICAgIGVsZW1lbnRUeXBlOiB0aGlzLm1hcFN0cmluZ1RvRWxlbWVudFR5cGUoZWxlbWVudFR5cGUpLFxuICAgICAgbGFzdE1vZGlmaWVkOiBuZXcgRGF0ZShlbnRyeS5jcmVhdGVkKSxcbiAgICAgIHNvdXJjZTogJ2NvbGxlY3Rpb24nLFxuICAgICAgY29sbGVjdGlvblBhdGg6IGVudHJ5LnBhdGgsXG4gICAgICBjb2xsZWN0aW9uU2hhOiBlbnRyeS5zaGEsXG4gICAgICBjb2xsZWN0aW9uVGFnczogZW50cnkudGFncyxcbiAgICAgIGNvbGxlY3Rpb25DYXRlZ29yeTogZW50cnkuY2F0ZWdvcnksXG4gICAgICBjb2xsZWN0aW9uTGljZW5zZTogZW50cnkubGljZW5zZVxuICAgIH07XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBNYXAgc3RyaW5nIHRvIEVsZW1lbnRUeXBlIGVudW1cbiAgICovXG4gIHByaXZhdGUgbWFwU3RyaW5nVG9FbGVtZW50VHlwZShlbGVtZW50VHlwZTogc3RyaW5nKTogRWxlbWVudFR5cGUge1xuICAgIC8vIEhhbmRsZSBtYXBwaW5nIGZyb20gY29sbGVjdGlvbiBlbGVtZW50IHR5cGVzIHRvIG91ciBFbGVtZW50VHlwZSBlbnVtXG4gICAgc3dpdGNoIChlbGVtZW50VHlwZS50b0xvd2VyQ2FzZSgpKSB7XG4gICAgICBjYXNlICdwZXJzb25hcyc6XG4gICAgICAgIHJldHVybiBFbGVtZW50VHlwZS5QRVJTT05BO1xuICAgICAgY2FzZSAnc2tpbGxzJzpcbiAgICAgICAgcmV0dXJuIEVsZW1lbnRUeXBlLlNLSUxMO1xuICAgICAgY2FzZSAnYWdlbnRzJzpcbiAgICAgICAgcmV0dXJuIEVsZW1lbnRUeXBlLkFHRU5UO1xuICAgICAgY2FzZSAncHJvbXB0cyc6XG4gICAgICBjYXNlICd0ZW1wbGF0ZXMnOlxuICAgICAgICByZXR1cm4gRWxlbWVudFR5cGUuVEVNUExBVEU7IC8vIE1hcCBwcm9tcHRzIGFuZCB0ZW1wbGF0ZXMgdG8gVEVNUExBVEVcbiAgICAgIGNhc2UgJ3Rvb2xzJzpcbiAgICAgICAgcmV0dXJuIEVsZW1lbnRUeXBlLlNLSUxMOyAvLyBNYXAgdG9vbHMgdG8gU0tJTEwgYXMgZmFsbGJhY2tcbiAgICAgIGNhc2UgJ2Vuc2VtYmxlcyc6XG4gICAgICAgIHJldHVybiBFbGVtZW50VHlwZS5FTlNFTUJMRTtcbiAgICAgIGNhc2UgJ21lbW9yaWVzJzpcbiAgICAgICAgcmV0dXJuIEVsZW1lbnRUeXBlLk1FTU9SWTtcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHJldHVybiBFbGVtZW50VHlwZS5TS0lMTDsgLy8gRGVmYXVsdCBmYWxsYmFja1xuICAgIH1cbiAgfVxuICBcbiAgLyoqXG4gICAqIENvbnZlcnQgdW5pZmllZCBzZWFyY2ggb3B0aW9ucyB0byBsb2NhbCBzZWFyY2ggb3B0aW9uc1xuICAgKi9cbiAgcHJpdmF0ZSBjb252ZXJ0VG9Mb2NhbE9wdGlvbnMob3B0aW9uczogVW5pZmllZFNlYXJjaE9wdGlvbnMpOiBTZWFyY2hPcHRpb25zIHtcbiAgICByZXR1cm4ge1xuICAgICAgZWxlbWVudFR5cGU6IG9wdGlvbnMuZWxlbWVudFR5cGUsXG4gICAgICBtYXhSZXN1bHRzOiBvcHRpb25zLnBhZ2VTaXplIHx8IDIwXG4gICAgfTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIERldGVybWluZSBtYXRjaCB0eXBlIGZvciBHaXRIdWIgZW50cmllc1xuICAgKi9cbiAgcHJpdmF0ZSBkZXRlcm1pbmVNYXRjaFR5cGUoZW50cnk6IEdpdEh1YkluZGV4RW50cnksIHF1ZXJ5VG9rZW5zOiBzdHJpbmdbXSk6IHN0cmluZyB7XG4gICAgY29uc3QgbmFtZSA9IGVudHJ5Lm5hbWUudG9Mb3dlckNhc2UoKTtcbiAgICBjb25zdCBkZXNjcmlwdGlvbiA9IChlbnRyeS5kZXNjcmlwdGlvbiB8fCAnJykudG9Mb3dlckNhc2UoKTtcbiAgICBcbiAgICAvLyBDaGVjayB3aGF0IG1hdGNoZWRcbiAgICBmb3IgKGNvbnN0IHRva2VuIG9mIHF1ZXJ5VG9rZW5zKSB7XG4gICAgICBpZiAobmFtZS5pbmNsdWRlcyh0b2tlbikpIHtcbiAgICAgICAgcmV0dXJuIG5hbWUgPT09IHRva2VuID8gJ2V4YWN0X25hbWUnIDogJ25hbWUnO1xuICAgICAgfVxuICAgICAgaWYgKGRlc2NyaXB0aW9uLmluY2x1ZGVzKHRva2VuKSkge1xuICAgICAgICByZXR1cm4gJ2Rlc2NyaXB0aW9uJztcbiAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgcmV0dXJuICdjb250ZW50JztcbiAgfVxuICBcbiAgLyoqXG4gICAqIERldGVybWluZSBtYXRjaCB0eXBlIGZvciBjb2xsZWN0aW9uIGVudHJpZXNcbiAgICovXG4gIHByaXZhdGUgZGV0ZXJtaW5lQ29sbGVjdGlvbk1hdGNoVHlwZShlbnRyeTogQ29sbGVjdGlvbkluZGV4RW50cnksIHF1ZXJ5VG9rZW5zOiBzdHJpbmdbXSk6IHN0cmluZyB7XG4gICAgY29uc3QgbmFtZSA9IGVudHJ5Lm5hbWUudG9Mb3dlckNhc2UoKTtcbiAgICBjb25zdCBkZXNjcmlwdGlvbiA9IChlbnRyeS5kZXNjcmlwdGlvbiB8fCAnJykudG9Mb3dlckNhc2UoKTtcbiAgICBjb25zdCB0YWdzID0gZW50cnkudGFncy5tYXAodGFnID0+IHRhZy50b0xvd2VyQ2FzZSgpKS5qb2luKCcgJyk7XG4gICAgXG4gICAgLy8gQ2hlY2sgd2hhdCBtYXRjaGVkXG4gICAgZm9yIChjb25zdCB0b2tlbiBvZiBxdWVyeVRva2Vucykge1xuICAgICAgaWYgKG5hbWUuaW5jbHVkZXModG9rZW4pKSB7XG4gICAgICAgIHJldHVybiBuYW1lID09PSB0b2tlbiA/ICdleGFjdF9uYW1lJyA6ICduYW1lJztcbiAgICAgIH1cbiAgICAgIGlmIChkZXNjcmlwdGlvbi5pbmNsdWRlcyh0b2tlbikpIHtcbiAgICAgICAgcmV0dXJuICdkZXNjcmlwdGlvbic7XG4gICAgICB9XG4gICAgICBpZiAodGFncy5pbmNsdWRlcyh0b2tlbikpIHtcbiAgICAgICAgcmV0dXJuICd0YWcnO1xuICAgICAgfVxuICAgIH1cbiAgICBcbiAgICByZXR1cm4gJ2NvbnRlbnQnO1xuICB9XG4gIFxuICAvKipcbiAgICogR2V0IHBhdGggZnJvbSB1bmlmaWVkIGVudHJ5XG4gICAqL1xuICBwcml2YXRlIGdldFBhdGhGcm9tRW50cnkoZW50cnk6IFVuaWZpZWRJbmRleEVudHJ5KTogc3RyaW5nIHtcbiAgICBzd2l0Y2ggKGVudHJ5LnNvdXJjZSkge1xuICAgICAgY2FzZSAnbG9jYWwnOlxuICAgICAgICByZXR1cm4gZW50cnkubG9jYWxGaWxlUGF0aCB8fCBlbnRyeS5maWxlbmFtZSB8fCAndW5rbm93bic7XG4gICAgICBjYXNlICdnaXRodWInOlxuICAgICAgICByZXR1cm4gZW50cnkuZ2l0aHViUGF0aCB8fCAndW5rbm93bic7XG4gICAgICBjYXNlICdjb2xsZWN0aW9uJzpcbiAgICAgICAgcmV0dXJuIGVudHJ5LmNvbGxlY3Rpb25QYXRoIHx8ICd1bmtub3duJztcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHJldHVybiAndW5rbm93bic7XG4gICAgfVxuICB9XG4gIFxuICAvKipcbiAgICogRGV0ZWN0IHZlcnNpb24gY29uZmxpY3QgZnJvbSBzb3VyY2VzXG4gICAqL1xuICBwcml2YXRlIGRldGVjdFZlcnNpb25Db25mbGljdChzb3VyY2VzOiBEdXBsaWNhdGVJbmZvWydzb3VyY2VzJ10pOiBWZXJzaW9uQ29uZmxpY3QgfCB1bmRlZmluZWQge1xuICAgIGNvbnN0IHZlcnNpb25zID0gbmV3IE1hcDxzdHJpbmcsICdsb2NhbCcgfCAnZ2l0aHViJyB8ICdjb2xsZWN0aW9uJz4oKTtcbiAgICBcbiAgICBmb3IgKGNvbnN0IHNvdXJjZSBvZiBzb3VyY2VzKSB7XG4gICAgICBpZiAoc291cmNlLnZlcnNpb24gJiYgc291cmNlLnZlcnNpb24gIT09ICd1bmtub3duJykge1xuICAgICAgICB2ZXJzaW9ucy5zZXQoc291cmNlLnZlcnNpb24sIHNvdXJjZS5zb3VyY2UpO1xuICAgICAgfVxuICAgIH1cbiAgICBcbiAgICBpZiAodmVyc2lvbnMuc2l6ZSA8PSAxKSB7XG4gICAgICByZXR1cm4gdW5kZWZpbmVkOyAvLyBObyBjb25mbGljdCBpZiBhbGwgdmVyc2lvbnMgYXJlIHRoZSBzYW1lIG9yIG1pc3NpbmdcbiAgICB9XG4gICAgXG4gICAgLy8gQnVpbGQgdmVyc2lvbiBjb25mbGljdCBpbmZvXG4gICAgY29uc3QgdmVyc2lvbkNvbmZsaWN0OiBWZXJzaW9uQ29uZmxpY3QgPSB7XG4gICAgICByZWNvbW1lbmRlZDogJ2xvY2FsJyxcbiAgICAgIHJlYXNvbjogJ011bHRpcGxlIHZlcnNpb25zIGRldGVjdGVkJ1xuICAgIH07XG4gICAgXG4gICAgZm9yIChjb25zdCBzb3VyY2Ugb2Ygc291cmNlcykge1xuICAgICAgaWYgKHNvdXJjZS52ZXJzaW9uKSB7XG4gICAgICAgIHZlcnNpb25Db25mbGljdFtzb3VyY2Uuc291cmNlXSA9IHNvdXJjZS52ZXJzaW9uO1xuICAgICAgfVxuICAgIH1cbiAgICBcbiAgICAvLyBEZXRlcm1pbmUgcmVjb21tZW5kYXRpb25cbiAgICBjb25zdCByZWNvbW1lbmRhdGlvbiA9IHRoaXMuZGV0ZXJtaW5lVmVyc2lvblJlY29tbWVuZGF0aW9uRnJvbVNvdXJjZXMoc291cmNlcyk7XG4gICAgdmVyc2lvbkNvbmZsaWN0LnJlY29tbWVuZGVkID0gcmVjb21tZW5kYXRpb24uc291cmNlO1xuICAgIHZlcnNpb25Db25mbGljdC5yZWFzb24gPSByZWNvbW1lbmRhdGlvbi5yZWFzb247XG4gICAgXG4gICAgcmV0dXJuIHZlcnNpb25Db25mbGljdDtcbiAgfVxuICBcbiAgLyoqXG4gICAqIERldGVjdCB2ZXJzaW9uIGNvbmZsaWN0IGZyb20gc2VhcmNoIHJlc3VsdHNcbiAgICovXG4gIHByaXZhdGUgZGV0ZWN0VmVyc2lvbkNvbmZsaWN0RnJvbVJlc3VsdHMocmVzdWx0czogVW5pZmllZFNlYXJjaFJlc3VsdFtdKTogVmVyc2lvbkNvbmZsaWN0IHwgdW5kZWZpbmVkIHtcbiAgICBjb25zdCBzb3VyY2VzID0gcmVzdWx0cy5tYXAocmVzdWx0ID0+ICh7XG4gICAgICBzb3VyY2U6IHJlc3VsdC5zb3VyY2UsXG4gICAgICB2ZXJzaW9uOiByZXN1bHQudmVyc2lvbixcbiAgICAgIGxhc3RNb2RpZmllZDogcmVzdWx0LmVudHJ5Lmxhc3RNb2RpZmllZCxcbiAgICAgIHBhdGg6IHRoaXMuZ2V0UGF0aEZyb21FbnRyeShyZXN1bHQuZW50cnkpXG4gICAgfSkpO1xuICAgIFxuICAgIHJldHVybiB0aGlzLmRldGVjdFZlcnNpb25Db25mbGljdChzb3VyY2VzKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIERldGVybWluZSB2ZXJzaW9uIHJlY29tbWVuZGF0aW9uIGZyb20gdmVyc2lvbiBpbmZvXG4gICAqL1xuICBwcml2YXRlIGRldGVybWluZVZlcnNpb25SZWNvbW1lbmRhdGlvbih2ZXJzaW9uczogVmVyc2lvbkluZm9bJ3ZlcnNpb25zJ10pOiB7IHNvdXJjZTogJ2xvY2FsJyB8ICdnaXRodWInIHwgJ2NvbGxlY3Rpb24nOyByZWFzb246IHN0cmluZyB9IHtcbiAgICAvLyBQcmVmZXIgbG9jYWwgaWYgYXZhaWxhYmxlIGFuZCBub3QgdG9vIG9sZFxuICAgIGlmICh2ZXJzaW9ucy5sb2NhbCkge1xuICAgICAgY29uc3QgbG9jYWxBZ2UgPSBEYXRlLm5vdygpIC0gdmVyc2lvbnMubG9jYWwubGFzdE1vZGlmaWVkLmdldFRpbWUoKTtcbiAgICAgIGNvbnN0IHNldmVuRGF5cyA9IDcgKiAyNCAqIDYwICogNjAgKiAxMDAwO1xuICAgICAgXG4gICAgICBpZiAobG9jYWxBZ2UgPCBzZXZlbkRheXMpIHtcbiAgICAgICAgcmV0dXJuIHsgc291cmNlOiAnbG9jYWwnLCByZWFzb246ICdMb2NhbCB2ZXJzaW9uIGlzIHJlY2VudCBhbmQgYXV0aG9yaXRhdGl2ZScgfTtcbiAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgLy8gQ29tcGFyZSB2ZXJzaW9ucyBpZiBhdmFpbGFibGVcbiAgICBjb25zdCB2ZXJzaW9uRW50cmllcyA9IE9iamVjdC5lbnRyaWVzKHZlcnNpb25zKS5maWx0ZXIoKFtfLCBpbmZvXSkgPT4gaW5mbz8udmVyc2lvbik7XG4gICAgXG4gICAgaWYgKHZlcnNpb25FbnRyaWVzLmxlbmd0aCA+IDEpIHtcbiAgICAgIC8vIEZpbmQgaGlnaGVzdCB2ZXJzaW9uXG4gICAgICBsZXQgaGlnaGVzdDogeyBzb3VyY2U6ICdsb2NhbCcgfCAnZ2l0aHViJyB8ICdjb2xsZWN0aW9uJzsgdmVyc2lvbjogc3RyaW5nIH0gPSB7XG4gICAgICAgIHNvdXJjZTogJ2xvY2FsJyxcbiAgICAgICAgdmVyc2lvbjogJzAuMC4wJ1xuICAgICAgfTtcbiAgICAgIFxuICAgICAgZm9yIChjb25zdCBbc291cmNlLCBpbmZvXSBvZiB2ZXJzaW9uRW50cmllcykge1xuICAgICAgICBpZiAoaW5mbyAmJiB0aGlzLmNvbXBhcmVWZXJzaW9ucyhpbmZvLnZlcnNpb24sIGhpZ2hlc3QudmVyc2lvbikgPiAwKSB7XG4gICAgICAgICAgaGlnaGVzdCA9IHtcbiAgICAgICAgICAgIHNvdXJjZTogc291cmNlIGFzICdsb2NhbCcgfCAnZ2l0aHViJyB8ICdjb2xsZWN0aW9uJyxcbiAgICAgICAgICAgIHZlcnNpb246IGluZm8udmVyc2lvblxuICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIFxuICAgICAgcmV0dXJuIHsgc291cmNlOiBoaWdoZXN0LnNvdXJjZSwgcmVhc29uOiBgSGlnaGVzdCB2ZXJzaW9uICgke2hpZ2hlc3QudmVyc2lvbn0pYCB9O1xuICAgIH1cbiAgICBcbiAgICAvLyBGYWxsYmFjayB0byBtb3N0IHJlY2VudFxuICAgIGxldCBtb3N0UmVjZW50OiB7IHNvdXJjZTogJ2xvY2FsJyB8ICdnaXRodWInIHwgJ2NvbGxlY3Rpb24nOyBkYXRlOiBEYXRlIH0gPSB7XG4gICAgICBzb3VyY2U6ICdsb2NhbCcsXG4gICAgICBkYXRlOiBuZXcgRGF0ZSgwKVxuICAgIH07XG4gICAgXG4gICAgZm9yIChjb25zdCBbc291cmNlLCBpbmZvXSBvZiBPYmplY3QuZW50cmllcyh2ZXJzaW9ucykpIHtcbiAgICAgIGlmIChpbmZvICYmIGluZm8ubGFzdE1vZGlmaWVkID4gbW9zdFJlY2VudC5kYXRlKSB7XG4gICAgICAgIG1vc3RSZWNlbnQgPSB7XG4gICAgICAgICAgc291cmNlOiBzb3VyY2UgYXMgJ2xvY2FsJyB8ICdnaXRodWInIHwgJ2NvbGxlY3Rpb24nLFxuICAgICAgICAgIGRhdGU6IGluZm8ubGFzdE1vZGlmaWVkXG4gICAgICAgIH07XG4gICAgICB9XG4gICAgfVxuICAgIFxuICAgIHJldHVybiB7IHNvdXJjZTogbW9zdFJlY2VudC5zb3VyY2UsIHJlYXNvbjogJ01vc3QgcmVjZW50bHkgbW9kaWZpZWQnIH07XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBEZXRlcm1pbmUgdmVyc2lvbiByZWNvbW1lbmRhdGlvbiBmcm9tIHNvdXJjZXNcbiAgICovXG4gIHByaXZhdGUgZGV0ZXJtaW5lVmVyc2lvblJlY29tbWVuZGF0aW9uRnJvbVNvdXJjZXMoc291cmNlczogRHVwbGljYXRlSW5mb1snc291cmNlcyddKTogeyBzb3VyY2U6ICdsb2NhbCcgfCAnZ2l0aHViJyB8ICdjb2xsZWN0aW9uJzsgcmVhc29uOiBzdHJpbmcgfSB7XG4gICAgLy8gQ29udmVydCBzb3VyY2VzIHRvIHZlcnNpb25zIGZvcm1hdFxuICAgIGNvbnN0IHZlcnNpb25zOiBWZXJzaW9uSW5mb1sndmVyc2lvbnMnXSA9IHt9O1xuICAgIFxuICAgIGZvciAoY29uc3Qgc291cmNlIG9mIHNvdXJjZXMpIHtcbiAgICAgIGlmIChzb3VyY2Uuc291cmNlID09PSAnbG9jYWwnKSB7XG4gICAgICAgIHZlcnNpb25zLmxvY2FsID0ge1xuICAgICAgICAgIHZlcnNpb246IHNvdXJjZS52ZXJzaW9uIHx8ICd1bmtub3duJyxcbiAgICAgICAgICBsYXN0TW9kaWZpZWQ6IHNvdXJjZS5sYXN0TW9kaWZpZWQsXG4gICAgICAgICAgcGF0aDogc291cmNlLnBhdGggfHwgJ3Vua25vd24nXG4gICAgICAgIH07XG4gICAgICB9IGVsc2UgaWYgKHNvdXJjZS5zb3VyY2UgPT09ICdnaXRodWInKSB7XG4gICAgICAgIHZlcnNpb25zLmdpdGh1YiA9IHtcbiAgICAgICAgICB2ZXJzaW9uOiBzb3VyY2UudmVyc2lvbiB8fCAndW5rbm93bicsXG4gICAgICAgICAgbGFzdE1vZGlmaWVkOiBzb3VyY2UubGFzdE1vZGlmaWVkLFxuICAgICAgICAgIHBhdGg6IHNvdXJjZS5wYXRoIHx8ICd1bmtub3duJ1xuICAgICAgICB9O1xuICAgICAgfSBlbHNlIGlmIChzb3VyY2Uuc291cmNlID09PSAnY29sbGVjdGlvbicpIHtcbiAgICAgICAgdmVyc2lvbnMuY29sbGVjdGlvbiA9IHtcbiAgICAgICAgICB2ZXJzaW9uOiBzb3VyY2UudmVyc2lvbiB8fCAndW5rbm93bicsXG4gICAgICAgICAgbGFzdE1vZGlmaWVkOiBzb3VyY2UubGFzdE1vZGlmaWVkLFxuICAgICAgICAgIHBhdGg6IHNvdXJjZS5wYXRoIHx8ICd1bmtub3duJ1xuICAgICAgICB9O1xuICAgICAgfVxuICAgIH1cbiAgICBcbiAgICByZXR1cm4gdGhpcy5kZXRlcm1pbmVWZXJzaW9uUmVjb21tZW5kYXRpb24odmVyc2lvbnMpO1xuICB9XG4gIFxuICAvKipcbiAgICogQ29tcGFyZSBzZW1hbnRpYyB2ZXJzaW9uc1xuICAgKi9cbiAgcHJpdmF0ZSBjb21wYXJlVmVyc2lvbnMoYTogc3RyaW5nLCBiOiBzdHJpbmcpOiBudW1iZXIge1xuICAgIGNvbnN0IHBhcnNlVmVyc2lvbiA9ICh2ZXJzaW9uOiBzdHJpbmcpID0+IHtcbiAgICAgIGNvbnN0IHBhcnRzID0gdmVyc2lvbi5zcGxpdCgnLicpLm1hcChwYXJ0ID0+IHBhcnNlSW50KHBhcnQpIHx8IDApO1xuICAgICAgcmV0dXJuIFtwYXJ0c1swXSB8fCAwLCBwYXJ0c1sxXSB8fCAwLCBwYXJ0c1syXSB8fCAwXTtcbiAgICB9O1xuICAgIFxuICAgIGNvbnN0IFthTWFqb3IsIGFNaW5vciwgYVBhdGNoXSA9IHBhcnNlVmVyc2lvbihhKTtcbiAgICBjb25zdCBbYk1ham9yLCBiTWlub3IsIGJQYXRjaF0gPSBwYXJzZVZlcnNpb24oYik7XG4gICAgXG4gICAgaWYgKGFNYWpvciAhPT0gYk1ham9yKSByZXR1cm4gYU1ham9yIC0gYk1ham9yO1xuICAgIGlmIChhTWlub3IgIT09IGJNaW5vcikgcmV0dXJuIGFNaW5vciAtIGJNaW5vcjtcbiAgICByZXR1cm4gYVBhdGNoIC0gYlBhdGNoO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlbW92ZSBkdXBsaWNhdGUgcmVzdWx0cyBiYXNlZCBvbiBuYW1lIGFuZCB0eXBlXG4gICAqL1xuICBwcml2YXRlIGRlZHVwbGljYXRlUmVzdWx0cyhyZXN1bHRzOiBVbmlmaWVkU2VhcmNoUmVzdWx0W10pOiBVbmlmaWVkU2VhcmNoUmVzdWx0W10ge1xuICAgIGNvbnN0IHNlZW4gPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgICBjb25zdCBkZWR1cGxpY2F0ZWQ6IFVuaWZpZWRTZWFyY2hSZXN1bHRbXSA9IFtdO1xuICAgIFxuICAgIGZvciAoY29uc3QgcmVzdWx0IG9mIHJlc3VsdHMpIHtcbiAgICAgIGNvbnN0IGtleSA9IGAke3Jlc3VsdC5lbnRyeS5lbGVtZW50VHlwZX06JHtyZXN1bHQuZW50cnkubmFtZS50b0xvd2VyQ2FzZSgpfWA7XG4gICAgICBpZiAoIXNlZW4uaGFzKGtleSkpIHtcbiAgICAgICAgc2Vlbi5hZGQoa2V5KTtcbiAgICAgICAgZGVkdXBsaWNhdGVkLnB1c2gocmVzdWx0KTtcbiAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgcmV0dXJuIGRlZHVwbGljYXRlZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZW1vdmUgZHVwbGljYXRlIGVudHJpZXMgYmFzZWQgb24gbmFtZSBhbmQgdHlwZVxuICAgKi9cbiAgcHJpdmF0ZSBkZWR1cGxpY2F0ZUVudHJpZXMoZW50cmllczogVW5pZmllZEluZGV4RW50cnlbXSk6IFVuaWZpZWRJbmRleEVudHJ5W10ge1xuICAgIGNvbnN0IHNlZW4gPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgICBjb25zdCBkZWR1cGxpY2F0ZWQ6IFVuaWZpZWRJbmRleEVudHJ5W10gPSBbXTtcbiAgICBcbiAgICBmb3IgKGNvbnN0IGVudHJ5IG9mIGVudHJpZXMpIHtcbiAgICAgIGNvbnN0IGtleSA9IGAke2VudHJ5LmVsZW1lbnRUeXBlfToke2VudHJ5Lm5hbWUudG9Mb3dlckNhc2UoKX1gO1xuICAgICAgaWYgKCFzZWVuLmhhcyhrZXkpKSB7XG4gICAgICAgIHNlZW4uYWRkKGtleSk7XG4gICAgICAgIGRlZHVwbGljYXRlZC5wdXNoKGVudHJ5KTtcbiAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgcmV0dXJuIGRlZHVwbGljYXRlZDtcbiAgfVxuICBcbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAgLy8gUEVSRk9STUFOQ0UgTU9OSVRPUklORyBBTkQgT1BUSU1JWkFUSU9OXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gIFxuICAvKipcbiAgICogU3RyZWFtIHNlYXJjaCByZXN1bHRzIGZvciBiZXR0ZXIgcGVyZm9ybWFuY2Ugd2l0aCBsYXJnZSBkYXRhc2V0c1xuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBzdHJlYW1TZWFyY2gob3B0aW9uczogVW5pZmllZFNlYXJjaE9wdGlvbnMpOiBQcm9taXNlPFVuaWZpZWRTZWFyY2hSZXN1bHRbXT4ge1xuICAgIGNvbnN0IHsgcXVlcnksIGN1cnNvciwgbWF4UmVzdWx0cyA9IDEwMDAgfSA9IG9wdGlvbnM7XG4gICAgY29uc3Qgc3RhcnRUaW1lID0gRGF0ZS5ub3coKTtcbiAgICBcbiAgICBsb2dnZXIuZGVidWcoJ1N0YXJ0aW5nIHN0cmVhbWluZyBzZWFyY2gnLCB7IHF1ZXJ5OiBxdWVyeS5zdWJzdHJpbmcoMCwgNTApLCBjdXJzb3IsIG1heFJlc3VsdHMgfSk7XG4gICAgXG4gICAgY29uc3QgcmVzdWx0czogVW5pZmllZFNlYXJjaFJlc3VsdFtdID0gW107XG4gICAgY29uc3Qgc291cmNlcyA9IHRoaXMuZ2V0RW5hYmxlZFNvdXJjZXMob3B0aW9ucyk7XG4gICAgXG4gICAgLy8gUHJvY2VzcyBzb3VyY2VzIGluIHNlcXVlbmNlIGZvciBtZW1vcnkgZWZmaWNpZW5jeVxuICAgIGZvciAoY29uc3Qgc291cmNlIG9mIHNvdXJjZXMpIHtcbiAgICAgIGlmIChyZXN1bHRzLmxlbmd0aCA+PSBtYXhSZXN1bHRzKSB7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgICAgXG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCBzb3VyY2VSZXN1bHRzID0gYXdhaXQgdGhpcy5zZWFyY2hXaXRoRmFsbGJhY2soc291cmNlLCBxdWVyeSwge1xuICAgICAgICAgIC4uLm9wdGlvbnMsXG4gICAgICAgICAgcGFnZVNpemU6IE1hdGgubWluKHRoaXMuQkFUQ0hfU0laRSwgbWF4UmVzdWx0cyAtIHJlc3VsdHMubGVuZ3RoKVxuICAgICAgICB9KTtcbiAgICAgICAgXG4gICAgICAgIHJlc3VsdHMucHVzaCguLi5zb3VyY2VSZXN1bHRzKTtcbiAgICAgICAgXG4gICAgICAgIC8vIEFkZCBjdXJzb3IgaW5mb3JtYXRpb24gZm9yIHBhZ2luYXRpb25cbiAgICAgICAgc291cmNlUmVzdWx0cy5mb3JFYWNoKChyZXN1bHQsIGluZGV4KSA9PiB7XG4gICAgICAgICAgcmVzdWx0LmN1cnNvciA9IHRoaXMuZ2VuZXJhdGVDdXJzb3Ioc291cmNlLCBpbmRleCk7XG4gICAgICAgIH0pO1xuICAgICAgICBcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIGxvZ2dlci53YXJuKGBTdHJlYW1pbmcgc2VhcmNoIGZhaWxlZCBmb3Igc291cmNlICR7c291cmNlfWAsIHtcbiAgICAgICAgICBlcnJvcjogZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH1cbiAgICBcbiAgICBsb2dnZXIuZGVidWcoJ1N0cmVhbWluZyBzZWFyY2ggY29tcGxldGVkJywge1xuICAgICAgcmVzdWx0Q291bnQ6IHJlc3VsdHMubGVuZ3RoLFxuICAgICAgZHVyYXRpb246IGAke0RhdGUubm93KCkgLSBzdGFydFRpbWV9bXNgXG4gICAgfSk7XG4gICAgXG4gICAgcmV0dXJuIHJlc3VsdHM7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBQcm9jZXNzIHNlYXJjaCByZXN1bHRzIHdpdGggbWVtb3J5LWVmZmljaWVudCBiYXRjaGluZ1xuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBwcm9jZXNzU2VhcmNoUmVzdWx0c09wdGltaXplZChyZXN1bHRzOiBVbmlmaWVkU2VhcmNoUmVzdWx0W10sIG9wdGlvbnM6IFVuaWZpZWRTZWFyY2hPcHRpb25zKTogUHJvbWlzZTxVbmlmaWVkU2VhcmNoUmVzdWx0W10+IHtcbiAgICBpZiAocmVzdWx0cy5sZW5ndGggPT09IDApIHtcbiAgICAgIHJldHVybiByZXN1bHRzO1xuICAgIH1cbiAgICBcbiAgICAvLyBQcm9jZXNzIGluIGJhdGNoZXMgdG8gYXZvaWQgbWVtb3J5IHNwaWtlcyB3aXRoIGxhcmdlIHJlc3VsdCBzZXRzXG4gICAgY29uc3QgYmF0Y2hTaXplID0gTWF0aC5taW4odGhpcy5CQVRDSF9TSVpFLCByZXN1bHRzLmxlbmd0aCk7XG4gICAgY29uc3QgcHJvY2Vzc2VkUmVzdWx0czogVW5pZmllZFNlYXJjaFJlc3VsdFtdID0gW107XG4gICAgXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCByZXN1bHRzLmxlbmd0aDsgaSArPSBiYXRjaFNpemUpIHtcbiAgICAgIGNvbnN0IGJhdGNoID0gcmVzdWx0cy5zbGljZShpLCBpICsgYmF0Y2hTaXplKTtcbiAgICAgIFxuICAgICAgLy8gQXBwbHkgc21hcnQgcmFua2luZ1xuICAgICAgY29uc3QgcmFua2VkQmF0Y2ggPSB0aGlzLmFwcGx5U21hcnRSYW5raW5nKGJhdGNoLCBvcHRpb25zKTtcbiAgICAgIFxuICAgICAgLy8gRGV0ZWN0IGR1cGxpY2F0ZXMgYW5kIGNvbmZsaWN0c1xuICAgICAgY29uc3QgcHJvY2Vzc2VkQmF0Y2ggPSBhd2FpdCB0aGlzLmRldGVjdER1cGxpY2F0ZXNBbmRDb25mbGljdHMocmFua2VkQmF0Y2gpO1xuICAgICAgXG4gICAgICBwcm9jZXNzZWRSZXN1bHRzLnB1c2goLi4ucHJvY2Vzc2VkQmF0Y2gpO1xuICAgICAgXG4gICAgICAvLyBZaWVsZCBjb250cm9sIHRvIHByZXZlbnQgYmxvY2tpbmdcbiAgICAgIGlmIChpICUgKGJhdGNoU2l6ZSAqIDQpID09PSAwKSB7XG4gICAgICAgIGF3YWl0IG5ldyBQcm9taXNlKHJlc29sdmUgPT4gc2V0SW1tZWRpYXRlKHJlc29sdmUpKTtcbiAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgLy8gQXBwbHkgZmluYWwgc29ydGluZ1xuICAgIHJldHVybiB0aGlzLmFwcGx5U29ydGluZyhwcm9jZXNzZWRSZXN1bHRzLCBvcHRpb25zLnNvcnRCeSB8fCAncmVsZXZhbmNlJywgb3B0aW9ucy5xdWVyeSk7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZXQgZW5hYmxlZCBzZWFyY2ggc291cmNlc1xuICAgKi9cbiAgcHJpdmF0ZSBnZXRFbmFibGVkU291cmNlcyhvcHRpb25zOiBVbmlmaWVkU2VhcmNoT3B0aW9ucyk6ICgnbG9jYWwnIHwgJ2dpdGh1YicgfCAnY29sbGVjdGlvbicpW10ge1xuICAgIGNvbnN0IHNvdXJjZXM6ICgnbG9jYWwnIHwgJ2dpdGh1YicgfCAnY29sbGVjdGlvbicpW10gPSBbXTtcbiAgICBcbiAgICBpZiAob3B0aW9ucy5pbmNsdWRlTG9jYWwgIT09IGZhbHNlKSBzb3VyY2VzLnB1c2goJ2xvY2FsJyk7XG4gICAgaWYgKG9wdGlvbnMuaW5jbHVkZUdpdEh1YiAhPT0gZmFsc2UpIHNvdXJjZXMucHVzaCgnZ2l0aHViJyk7XG4gICAgaWYgKG9wdGlvbnMuaW5jbHVkZUNvbGxlY3Rpb24gPT09IHRydWUpIHNvdXJjZXMucHVzaCgnY29sbGVjdGlvbicpO1xuICAgIFxuICAgIHJldHVybiBzb3VyY2VzO1xuICB9XG4gIFxuICAvKipcbiAgICogQmF0Y2ggc291cmNlcyBmb3IgY29uY3VycmVudCBwcm9jZXNzaW5nXG4gICAqL1xuICBwcml2YXRlIGJhdGNoU291cmNlcyhzb3VyY2VzOiAoJ2xvY2FsJyB8ICdnaXRodWInIHwgJ2NvbGxlY3Rpb24nKVtdLCBiYXRjaFNpemU6IG51bWJlcik6ICgnbG9jYWwnIHwgJ2dpdGh1YicgfCAnY29sbGVjdGlvbicpW11bXSB7XG4gICAgY29uc3QgYmF0Y2hlczogKCdsb2NhbCcgfCAnZ2l0aHViJyB8ICdjb2xsZWN0aW9uJylbXVtdID0gW107XG4gICAgXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBzb3VyY2VzLmxlbmd0aDsgaSArPSBiYXRjaFNpemUpIHtcbiAgICAgIGJhdGNoZXMucHVzaChzb3VyY2VzLnNsaWNlKGksIGkgKyBiYXRjaFNpemUpKTtcbiAgICB9XG4gICAgXG4gICAgcmV0dXJuIGJhdGNoZXM7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZW5lcmF0ZSBjdXJzb3IgZm9yIHBhZ2luYXRpb25cbiAgICovXG4gIHByaXZhdGUgZ2VuZXJhdGVDdXJzb3Ioc291cmNlOiBzdHJpbmcsIGluZGV4OiBudW1iZXIpOiBzdHJpbmcge1xuICAgIGNvbnN0IHRpbWVzdGFtcCA9IERhdGUubm93KCk7XG4gICAgcmV0dXJuIEJ1ZmZlci5mcm9tKGAke3NvdXJjZX06JHtpbmRleH06JHt0aW1lc3RhbXB9YCkudG9TdHJpbmcoJ2Jhc2U2NCcpO1xuICB9XG4gIFxuICAvKipcbiAgICogVHJpZ2dlciBtZW1vcnkgY2xlYW51cCB3aGVuIHVzYWdlIGlzIGhpZ2hcbiAgICovXG4gIHByaXZhdGUgdHJpZ2dlck1lbW9yeUNsZWFudXAoKTogdm9pZCB7XG4gICAgLy8gRm9yY2UgY2FjaGUgY2xlYW51cFxuICAgIHRoaXMucmVzdWx0Q2FjaGUuY2xlYW51cCgpO1xuICAgIHRoaXMuaW5kZXhDYWNoZS5jbGVhbnVwKCk7XG4gICAgXG4gICAgLy8gU3VnZ2VzdCBnYXJiYWdlIGNvbGxlY3Rpb25cbiAgICBpZiAoZ2xvYmFsLmdjKSB7XG4gICAgICBnbG9iYWwuZ2MoKTtcbiAgICAgIGxvZ2dlci5kZWJ1ZygnVHJpZ2dlcmVkIGdhcmJhZ2UgY29sbGVjdGlvbicpO1xuICAgIH1cbiAgfVxuICBcbiAgLyoqXG4gICAqIFJlY29yZCBzZWFyY2ggcGVyZm9ybWFuY2UgbWV0cmljc1xuICAgKi9cbiAgcHJpdmF0ZSByZWNvcmRTZWFyY2hNZXRyaWNzKG1ldHJpY3M6IFNlYXJjaE1ldHJpY3MpOiB2b2lkIHtcbiAgICB0aGlzLnBlcmZvcm1hbmNlTW9uaXRvci5yZWNvcmRTZWFyY2gobWV0cmljcyk7XG4gICAgXG4gICAgLy8gVXBkYXRlIGNhY2hlIHBlcmZvcm1hbmNlIG1ldHJpY3NcbiAgICBjb25zdCBjYWNoZVN0YXRzID0gdGhpcy5yZXN1bHRDYWNoZS5nZXRTdGF0cygpO1xuICAgIHRoaXMucGVyZm9ybWFuY2VNb25pdG9yLnJlY29yZENhY2hlUGVyZm9ybWFuY2UoJ3NlYXJjaFJlc3VsdHMnLCB7XG4gICAgICBoaXRSYXRlOiBjYWNoZVN0YXRzLmhpdFJhdGUsXG4gICAgICBhdmdIaXRUaW1lOiAxLCAvLyBQbGFjZWhvbGRlclxuICAgICAgYXZnTWlzc1RpbWU6IDUsIC8vIFBsYWNlaG9sZGVyXG4gICAgICB0b3RhbEhpdHM6IGNhY2hlU3RhdHMuaGl0Q291bnQsXG4gICAgICB0b3RhbE1pc3NlczogY2FjaGVTdGF0cy5taXNzQ291bnQsXG4gICAgICBldmljdGlvbnM6IGNhY2hlU3RhdHMuZXZpY3Rpb25Db3VudFxuICAgIH0pO1xuICB9XG4gIFxuICAvKipcbiAgICogQ3JlYXRlIGNhY2hlIGtleSBmb3Igc2VhcmNoIG9wdGlvbnNcbiAgICovXG4gIHByaXZhdGUgY3JlYXRlQ2FjaGVLZXkob3B0aW9uczogVW5pZmllZFNlYXJjaE9wdGlvbnMpOiBzdHJpbmcge1xuICAgIHJldHVybiBKU09OLnN0cmluZ2lmeSh7XG4gICAgICBxdWVyeTogb3B0aW9ucy5xdWVyeSxcbiAgICAgIGluY2x1ZGVMb2NhbDogb3B0aW9ucy5pbmNsdWRlTG9jYWwsXG4gICAgICBpbmNsdWRlR2l0SHViOiBvcHRpb25zLmluY2x1ZGVHaXRIdWIsXG4gICAgICBpbmNsdWRlQ29sbGVjdGlvbjogb3B0aW9ucy5pbmNsdWRlQ29sbGVjdGlvbixcbiAgICAgIGVsZW1lbnRUeXBlOiBvcHRpb25zLmVsZW1lbnRUeXBlLFxuICAgICAgcGFnZTogb3B0aW9ucy5wYWdlLFxuICAgICAgcGFnZVNpemU6IG9wdGlvbnMucGFnZVNpemUsXG4gICAgICBzb3J0Qnk6IG9wdGlvbnMuc29ydEJ5LFxuICAgICAgbGF6eUxvYWQ6IG9wdGlvbnMubGF6eUxvYWRcbiAgICB9KTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEdldCBwZXJmb3JtYW5jZSBzdGF0aXN0aWNzXG4gICAqL1xuICBwdWJsaWMgZ2V0UGVyZm9ybWFuY2VTdGF0cygpOiB7XG4gICAgc2VhcmNoU3RhdHM6IGFueTtcbiAgICBtZW1vcnlTdGF0czogYW55O1xuICAgIGNhY2hlU3RhdHM6IGFueTtcbiAgICB0cmVuZHM6IGFueTtcbiAgfSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHNlYXJjaFN0YXRzOiB0aGlzLnBlcmZvcm1hbmNlTW9uaXRvci5nZXRTZWFyY2hTdGF0cygpLFxuICAgICAgbWVtb3J5U3RhdHM6IHRoaXMucGVyZm9ybWFuY2VNb25pdG9yLmdldE1lbW9yeVN0YXRzKCksXG4gICAgICBjYWNoZVN0YXRzOiB7XG4gICAgICAgIHNlYXJjaFJlc3VsdHM6IHRoaXMucmVzdWx0Q2FjaGUuZ2V0U3RhdHMoKSxcbiAgICAgICAgaW5kZXhDYWNoZTogdGhpcy5pbmRleENhY2hlLmdldFN0YXRzKClcbiAgICAgIH0sXG4gICAgICB0cmVuZHM6IHRoaXMucGVyZm9ybWFuY2VNb25pdG9yLmFuYWx5emVUcmVuZHMoKVxuICAgIH07XG4gIH1cbn0iXX0=
|