@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.
Files changed (272) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/README.md +494 -111
  3. package/data/agents/code-reviewer.md +8 -1
  4. package/data/agents/research-assistant.md +8 -1
  5. package/data/agents/task-manager.md +8 -1
  6. package/data/ensembles/business-advisor.md +8 -1
  7. package/data/ensembles/creative-studio.md +8 -1
  8. package/data/ensembles/development-team.md +8 -1
  9. package/data/ensembles/security-analysis-team.md +8 -1
  10. package/data/memories/conversation-history.md +8 -1
  11. package/data/memories/learning-progress.md +8 -1
  12. package/data/memories/project-context.md +8 -1
  13. package/data/personas/business-consultant.md +8 -1
  14. package/data/personas/creative-writer.md +8 -1
  15. package/data/personas/debug-detective.md +8 -1
  16. package/data/personas/eli5-explainer.md +8 -1
  17. package/data/personas/security-analyst.md +8 -1
  18. package/data/personas/technical-analyst.md +8 -1
  19. package/data/skills/code-review.md +8 -1
  20. package/data/skills/creative-writing.md +8 -1
  21. package/data/skills/data-analysis.md +8 -1
  22. package/data/skills/penetration-testing.md +8 -1
  23. package/data/skills/research.md +8 -1
  24. package/data/skills/threat-modeling.md +8 -1
  25. package/data/skills/translation.md +8 -1
  26. package/data/templates/code-documentation.md +8 -1
  27. package/data/templates/email-professional.md +8 -1
  28. package/data/templates/meeting-notes.md +8 -1
  29. package/data/templates/penetration-test-report.md +8 -1
  30. package/data/templates/project-brief.md +8 -1
  31. package/data/templates/report-executive.md +8 -1
  32. package/data/templates/security-vulnerability-report.md +8 -1
  33. package/data/templates/threat-assessment-report.md +8 -1
  34. package/dist/auth/GitHubAuthManager.d.ts +6 -1
  35. package/dist/auth/GitHubAuthManager.d.ts.map +1 -1
  36. package/dist/auth/GitHubAuthManager.js +45 -18
  37. package/dist/benchmarks/IndexPerformanceBenchmark.d.ts +98 -0
  38. package/dist/benchmarks/IndexPerformanceBenchmark.d.ts.map +1 -0
  39. package/dist/benchmarks/IndexPerformanceBenchmark.js +531 -0
  40. package/dist/cache/CollectionCache.d.ts.map +1 -1
  41. package/dist/cache/CollectionCache.js +13 -3
  42. package/dist/cache/CollectionIndexCache.d.ts +77 -0
  43. package/dist/cache/CollectionIndexCache.d.ts.map +1 -0
  44. package/dist/cache/CollectionIndexCache.js +349 -0
  45. package/dist/cache/LRUCache.d.ts +93 -0
  46. package/dist/cache/LRUCache.d.ts.map +1 -0
  47. package/dist/cache/LRUCache.js +299 -0
  48. package/dist/cache/index.d.ts +1 -0
  49. package/dist/cache/index.d.ts.map +1 -1
  50. package/dist/cache/index.js +2 -1
  51. package/dist/collection/CollectionBrowser.d.ts +21 -1
  52. package/dist/collection/CollectionBrowser.d.ts.map +1 -1
  53. package/dist/collection/CollectionBrowser.js +130 -10
  54. package/dist/collection/CollectionIndexManager.d.ts +151 -0
  55. package/dist/collection/CollectionIndexManager.d.ts.map +1 -0
  56. package/dist/collection/CollectionIndexManager.js +499 -0
  57. package/dist/collection/CollectionSearch.d.ts +55 -0
  58. package/dist/collection/CollectionSearch.d.ts.map +1 -1
  59. package/dist/collection/CollectionSearch.js +338 -13
  60. package/dist/collection/CollectionSeeder.d.ts.map +1 -1
  61. package/dist/collection/CollectionSeeder.js +38 -1
  62. package/dist/collection/ElementInstaller.d.ts +31 -0
  63. package/dist/collection/ElementInstaller.d.ts.map +1 -1
  64. package/dist/collection/ElementInstaller.js +77 -15
  65. package/dist/collection/PersonaSubmitter.d.ts +1 -1
  66. package/dist/collection/PersonaSubmitter.d.ts.map +1 -1
  67. package/dist/collection/PersonaSubmitter.js +2 -2
  68. package/dist/collection/index.d.ts +1 -0
  69. package/dist/collection/index.d.ts.map +1 -1
  70. package/dist/collection/index.js +2 -1
  71. package/dist/config/ConfigManager.d.ts +78 -0
  72. package/dist/config/ConfigManager.d.ts.map +1 -0
  73. package/dist/config/ConfigManager.js +216 -0
  74. package/dist/config/element-types.d.ts +135 -0
  75. package/dist/config/element-types.d.ts.map +1 -0
  76. package/dist/config/element-types.js +108 -0
  77. package/dist/config/index.d.ts +2 -0
  78. package/dist/config/index.d.ts.map +1 -1
  79. package/dist/config/index.js +3 -1
  80. package/dist/config/portfolio-constants.d.ts +83 -0
  81. package/dist/config/portfolio-constants.d.ts.map +1 -0
  82. package/dist/config/portfolio-constants.js +99 -0
  83. package/dist/elements/BaseElement.d.ts +14 -2
  84. package/dist/elements/BaseElement.d.ts.map +1 -1
  85. package/dist/elements/BaseElement.js +88 -6
  86. package/dist/elements/agents/Agent.d.ts +10 -1
  87. package/dist/elements/agents/Agent.d.ts.map +1 -1
  88. package/dist/elements/agents/Agent.js +66 -19
  89. package/dist/elements/agents/AgentManager.d.ts +2 -0
  90. package/dist/elements/agents/AgentManager.d.ts.map +1 -1
  91. package/dist/elements/agents/AgentManager.js +12 -10
  92. package/dist/elements/skills/Skill.d.ts +10 -1
  93. package/dist/elements/skills/Skill.d.ts.map +1 -1
  94. package/dist/elements/skills/Skill.js +40 -3
  95. package/dist/elements/skills/SkillManager.d.ts +1 -0
  96. package/dist/elements/skills/SkillManager.d.ts.map +1 -1
  97. package/dist/elements/skills/SkillManager.js +10 -4
  98. package/dist/elements/templates/Template.d.ts +10 -1
  99. package/dist/elements/templates/Template.d.ts.map +1 -1
  100. package/dist/elements/templates/Template.js +35 -18
  101. package/dist/elements/templates/TemplateManager.d.ts +1 -1
  102. package/dist/elements/templates/TemplateManager.d.ts.map +1 -1
  103. package/dist/elements/templates/TemplateManager.js +6 -5
  104. package/dist/generated/version.d.ts +2 -2
  105. package/dist/generated/version.js +3 -3
  106. package/dist/index.barrel.d.ts +1 -2
  107. package/dist/index.barrel.d.ts.map +1 -1
  108. package/dist/index.barrel.js +2 -4
  109. package/dist/index.d.ts +143 -25
  110. package/dist/index.d.ts.map +1 -1
  111. package/dist/index.js +1883 -310
  112. package/dist/persona/PersonaElement.d.ts +10 -0
  113. package/dist/persona/PersonaElement.d.ts.map +1 -1
  114. package/dist/persona/PersonaElement.js +55 -32
  115. package/dist/persona/PersonaElementManager.d.ts.map +1 -1
  116. package/dist/persona/PersonaElementManager.js +13 -11
  117. package/dist/persona/PersonaLoader.d.ts.map +1 -1
  118. package/dist/persona/PersonaLoader.js +8 -2
  119. package/dist/persona/export-import/PersonaImporter.d.ts.map +1 -1
  120. package/dist/persona/export-import/PersonaImporter.js +24 -5
  121. package/dist/persona/export-import/PersonaSharer.d.ts +21 -0
  122. package/dist/persona/export-import/PersonaSharer.d.ts.map +1 -1
  123. package/dist/persona/export-import/PersonaSharer.js +198 -22
  124. package/dist/portfolio/DefaultElementProvider.d.ts +90 -0
  125. package/dist/portfolio/DefaultElementProvider.d.ts.map +1 -1
  126. package/dist/portfolio/DefaultElementProvider.js +499 -7
  127. package/dist/portfolio/GitHubPortfolioIndexer.d.ts +129 -0
  128. package/dist/portfolio/GitHubPortfolioIndexer.d.ts.map +1 -0
  129. package/dist/portfolio/GitHubPortfolioIndexer.js +475 -0
  130. package/dist/portfolio/MigrationManager.d.ts.map +1 -1
  131. package/dist/portfolio/MigrationManager.js +136 -3
  132. package/dist/portfolio/PortfolioIndexManager.d.ts +130 -0
  133. package/dist/portfolio/PortfolioIndexManager.d.ts.map +1 -0
  134. package/dist/portfolio/PortfolioIndexManager.js +478 -0
  135. package/dist/portfolio/PortfolioManager.d.ts +5 -0
  136. package/dist/portfolio/PortfolioManager.d.ts.map +1 -1
  137. package/dist/portfolio/PortfolioManager.js +61 -20
  138. package/dist/portfolio/PortfolioRepoManager.d.ts +75 -0
  139. package/dist/portfolio/PortfolioRepoManager.d.ts.map +1 -0
  140. package/dist/portfolio/PortfolioRepoManager.js +337 -0
  141. package/dist/portfolio/UnifiedIndexManager.d.ts +388 -0
  142. package/dist/portfolio/UnifiedIndexManager.d.ts.map +1 -0
  143. package/dist/portfolio/UnifiedIndexManager.js +1434 -0
  144. package/dist/portfolio/index.d.ts +15 -0
  145. package/dist/portfolio/index.d.ts.map +1 -0
  146. package/dist/portfolio/index.js +15 -0
  147. package/dist/portfolio/types.d.ts +7 -0
  148. package/dist/portfolio/types.d.ts.map +1 -1
  149. package/dist/portfolio/types.js +6 -1
  150. package/dist/security/InputValidator.d.ts.map +1 -1
  151. package/dist/security/InputValidator.js +50 -48
  152. package/dist/security/audit/SecurityAuditor.d.ts.map +1 -1
  153. package/dist/security/audit/SecurityAuditor.js +17 -9
  154. package/dist/security/audit/config/suppressions.d.ts.map +1 -1
  155. package/dist/security/audit/config/suppressions.js +19 -3
  156. package/dist/security/contentValidator.d.ts +2 -0
  157. package/dist/security/contentValidator.d.ts.map +1 -1
  158. package/dist/security/contentValidator.js +115 -4
  159. package/dist/security/secureYamlParser.d.ts +1 -0
  160. package/dist/security/secureYamlParser.d.ts.map +1 -1
  161. package/dist/security/secureYamlParser.js +29 -7
  162. package/dist/security/securityMonitor.d.ts +1 -1
  163. package/dist/security/securityMonitor.d.ts.map +1 -1
  164. package/dist/security/securityMonitor.js +1 -1
  165. package/dist/security/tokenManager.d.ts +1 -1
  166. package/dist/security/tokenManager.d.ts.map +1 -1
  167. package/dist/security/tokenManager.js +30 -10
  168. package/dist/server/ServerSetup.d.ts +22 -2
  169. package/dist/server/ServerSetup.d.ts.map +1 -1
  170. package/dist/server/ServerSetup.js +77 -12
  171. package/dist/server/tools/AuthTools.d.ts.map +1 -1
  172. package/dist/server/tools/AuthTools.js +33 -1
  173. package/dist/server/tools/BuildInfoTools.d.ts +25 -0
  174. package/dist/server/tools/BuildInfoTools.d.ts.map +1 -0
  175. package/dist/server/tools/BuildInfoTools.js +36 -0
  176. package/dist/server/tools/CollectionTools.d.ts.map +1 -1
  177. package/dist/server/tools/CollectionTools.js +55 -46
  178. package/dist/server/tools/ConfigTools.d.ts.map +1 -1
  179. package/dist/server/tools/ConfigTools.js +29 -1
  180. package/dist/server/tools/PersonaTools.d.ts +4 -2
  181. package/dist/server/tools/PersonaTools.d.ts.map +1 -1
  182. package/dist/server/tools/PersonaTools.js +5 -152
  183. package/dist/server/tools/PortfolioTools.d.ts +12 -0
  184. package/dist/server/tools/PortfolioTools.d.ts.map +1 -0
  185. package/dist/server/tools/PortfolioTools.js +221 -0
  186. package/dist/server/tools/index.d.ts +3 -1
  187. package/dist/server/tools/index.d.ts.map +1 -1
  188. package/dist/server/tools/index.js +4 -2
  189. package/dist/server/types.d.ts +40 -5
  190. package/dist/server/types.d.ts.map +1 -1
  191. package/dist/server/types.js +1 -1
  192. package/dist/services/BuildInfoService.d.ts +84 -0
  193. package/dist/services/BuildInfoService.d.ts.map +1 -0
  194. package/dist/services/BuildInfoService.js +271 -0
  195. package/dist/tools/portfolio/PortfolioElementAdapter.d.ts +54 -0
  196. package/dist/tools/portfolio/PortfolioElementAdapter.d.ts.map +1 -0
  197. package/dist/tools/portfolio/PortfolioElementAdapter.js +229 -0
  198. package/dist/tools/portfolio/submitToPortfolioTool.d.ts +164 -0
  199. package/dist/tools/portfolio/submitToPortfolioTool.d.ts.map +1 -0
  200. package/dist/tools/portfolio/submitToPortfolioTool.js +1523 -0
  201. package/dist/tools/portfolio/types.d.ts +41 -0
  202. package/dist/tools/portfolio/types.d.ts.map +1 -0
  203. package/dist/tools/portfolio/types.js +15 -0
  204. package/dist/types/collection.d.ts +51 -0
  205. package/dist/types/collection.d.ts.map +1 -1
  206. package/dist/types/collection.js +1 -1
  207. package/dist/utils/EarlyTerminationSearch.d.ts +41 -0
  208. package/dist/utils/EarlyTerminationSearch.d.ts.map +1 -0
  209. package/dist/utils/EarlyTerminationSearch.js +164 -0
  210. package/dist/utils/ErrorHandler.d.ts +86 -0
  211. package/dist/utils/ErrorHandler.d.ts.map +1 -0
  212. package/dist/utils/ErrorHandler.js +201 -0
  213. package/dist/utils/FileDiscoveryUtil.d.ts +53 -0
  214. package/dist/utils/FileDiscoveryUtil.d.ts.map +1 -0
  215. package/dist/utils/FileDiscoveryUtil.js +169 -0
  216. package/dist/utils/GitHubRateLimiter.d.ts +88 -0
  217. package/dist/utils/GitHubRateLimiter.d.ts.map +1 -0
  218. package/dist/utils/GitHubRateLimiter.js +315 -0
  219. package/dist/utils/PerformanceMonitor.d.ts +134 -0
  220. package/dist/utils/PerformanceMonitor.d.ts.map +1 -0
  221. package/dist/utils/PerformanceMonitor.js +347 -0
  222. package/dist/utils/RateLimiter.d.ts.map +1 -0
  223. package/dist/utils/RateLimiter.js +172 -0
  224. package/dist/utils/SecureDownloader.d.ts +241 -0
  225. package/dist/utils/SecureDownloader.d.ts.map +1 -0
  226. package/dist/utils/SecureDownloader.js +759 -0
  227. package/dist/utils/ToolCache.d.ts +82 -0
  228. package/dist/utils/ToolCache.d.ts.map +1 -0
  229. package/dist/utils/ToolCache.js +196 -0
  230. package/dist/utils/errorCodes.d.ts +136 -0
  231. package/dist/utils/errorCodes.d.ts.map +1 -0
  232. package/dist/utils/errorCodes.js +87 -0
  233. package/dist/utils/index.d.ts +3 -0
  234. package/dist/utils/index.d.ts.map +1 -1
  235. package/dist/utils/index.js +4 -1
  236. package/dist/utils/installation.d.ts +1 -1
  237. package/dist/utils/installation.d.ts.map +1 -1
  238. package/dist/utils/installation.js +9 -8
  239. package/dist/utils/searchUtils.d.ts +31 -0
  240. package/dist/utils/searchUtils.d.ts.map +1 -1
  241. package/dist/utils/searchUtils.js +62 -1
  242. package/package.json +17 -7
  243. package/dist/config/updateConfig.d.ts +0 -84
  244. package/dist/config/updateConfig.d.ts.map +0 -1
  245. package/dist/config/updateConfig.js +0 -148
  246. package/dist/server/tools/UpdateTools.d.ts +0 -10
  247. package/dist/server/tools/UpdateTools.d.ts.map +0 -1
  248. package/dist/server/tools/UpdateTools.js +0 -85
  249. package/dist/update/BackupManager.d.ts +0 -63
  250. package/dist/update/BackupManager.d.ts.map +0 -1
  251. package/dist/update/BackupManager.js +0 -370
  252. package/dist/update/DependencyChecker.d.ts +0 -41
  253. package/dist/update/DependencyChecker.d.ts.map +0 -1
  254. package/dist/update/DependencyChecker.js +0 -132
  255. package/dist/update/RateLimiter.d.ts.map +0 -1
  256. package/dist/update/RateLimiter.js +0 -172
  257. package/dist/update/SignatureVerifier.d.ts +0 -71
  258. package/dist/update/SignatureVerifier.d.ts.map +0 -1
  259. package/dist/update/SignatureVerifier.js +0 -214
  260. package/dist/update/UpdateChecker.d.ts +0 -132
  261. package/dist/update/UpdateChecker.d.ts.map +0 -1
  262. package/dist/update/UpdateChecker.js +0 -506
  263. package/dist/update/UpdateManager.d.ts +0 -60
  264. package/dist/update/UpdateManager.d.ts.map +0 -1
  265. package/dist/update/UpdateManager.js +0 -730
  266. package/dist/update/VersionManager.d.ts +0 -31
  267. package/dist/update/VersionManager.d.ts.map +0 -1
  268. package/dist/update/VersionManager.js +0 -181
  269. package/dist/update/index.d.ts +0 -9
  270. package/dist/update/index.d.ts.map +0 -1
  271. package/dist/update/index.js +0 -9
  272. /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=