@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,759 @@
1
+ /**
2
+ * SecureDownloader - Reusable utility for safe content downloads
3
+ *
4
+ * Implements the validate-before-write pattern with comprehensive security features:
5
+ * - Content validation hooks (customizable validators)
6
+ * - Atomic file operations with temp files
7
+ * - Guaranteed cleanup on failure
8
+ * - Memory-efficient streaming for large files
9
+ * - Size limits to prevent DoS attacks
10
+ * - Path validation to prevent traversal
11
+ * - Timeout handling for network operations
12
+ * - Content type validation
13
+ *
14
+ * Usage Examples:
15
+ *
16
+ * // Basic download with validation
17
+ * const downloader = new SecureDownloader();
18
+ * await downloader.downloadToFile(
19
+ * 'https://example.com/file.md',
20
+ * './downloads/file.md',
21
+ * {
22
+ * validator: async (content) => ({
23
+ * isValid: !content.includes('malicious'),
24
+ * errorMessage: content.includes('malicious') ? 'Malicious content detected' : undefined
25
+ * }),
26
+ * maxSize: 1024 * 1024, // 1MB limit
27
+ * timeout: 30000 // 30 second timeout
28
+ * }
29
+ * );
30
+ *
31
+ * // Download to memory with validation
32
+ * const content = await downloader.downloadToMemory(
33
+ * 'https://example.com/data.json',
34
+ * {
35
+ * validator: async (content) => {
36
+ * try {
37
+ * JSON.parse(content);
38
+ * return { isValid: true };
39
+ * } catch {
40
+ * return { isValid: false, errorMessage: 'Invalid JSON format' };
41
+ * }
42
+ * }
43
+ * }
44
+ * );
45
+ *
46
+ * // Streaming download for large files
47
+ * await downloader.downloadStream(
48
+ * 'https://example.com/large-file.zip',
49
+ * './downloads/large-file.zip',
50
+ * {
51
+ * streamValidator: (chunk) => !chunk.includes(Buffer.from('VIRUS')),
52
+ * maxSize: 100 * 1024 * 1024, // 100MB limit
53
+ * timeout: 300000 // 5 minute timeout
54
+ * }
55
+ * );
56
+ */
57
+ import * as fs from 'fs/promises';
58
+ import * as path from 'path';
59
+ import { randomBytes, createHash } from 'crypto';
60
+ import { Readable } from 'stream';
61
+ import { pipeline } from 'stream/promises';
62
+ import { createWriteStream } from 'fs';
63
+ import { SecurityError } from '../errors/SecurityError.js';
64
+ import { SECURITY_LIMITS } from '../security/constants.js';
65
+ import { ContentValidator as SecurityContentValidator } from '../security/contentValidator.js';
66
+ import { PathValidator } from '../security/pathValidator.js';
67
+ import { FileLockManager } from '../security/fileLockManager.js';
68
+ import { SecurityMonitor } from '../security/securityMonitor.js';
69
+ import { UnicodeValidator } from '../security/validators/unicodeValidator.js';
70
+ import { RateLimiter } from './RateLimiter.js';
71
+ import { logger } from './logger.js';
72
+ /**
73
+ * Custom error types for different failure scenarios
74
+ */
75
+ export class DownloadError extends Error {
76
+ code;
77
+ originalError;
78
+ constructor(message, code, originalError) {
79
+ super(message);
80
+ this.code = code;
81
+ this.originalError = originalError;
82
+ this.name = 'DownloadError';
83
+ }
84
+ static networkError(message, originalError) {
85
+ return new DownloadError(message, 'NETWORK_ERROR', originalError);
86
+ }
87
+ static validationError(message) {
88
+ return new DownloadError(message, 'VALIDATION_ERROR');
89
+ }
90
+ static securityError(message) {
91
+ return new DownloadError(message, 'SECURITY_ERROR');
92
+ }
93
+ static timeoutError(message) {
94
+ return new DownloadError(message, 'TIMEOUT_ERROR');
95
+ }
96
+ static filesystemError(message, originalError) {
97
+ return new DownloadError(message, 'FILESYSTEM_ERROR', originalError);
98
+ }
99
+ }
100
+ /**
101
+ * SecureDownloader - Implements validate-before-write pattern for safe downloads
102
+ *
103
+ * Key Security Features:
104
+ * 1. VALIDATE-BEFORE-WRITE: All content validation occurs before any disk operations
105
+ * 2. ATOMIC OPERATIONS: Uses temporary files with atomic rename to prevent corruption
106
+ * 3. GUARANTEED CLEANUP: Automatic cleanup of temporary files on any failure
107
+ * 4. SIZE LIMITS: Prevents DoS attacks through large file downloads
108
+ * 5. PATH VALIDATION: Prevents directory traversal attacks
109
+ * 6. TIMEOUT PROTECTION: Prevents hanging network operations
110
+ * 7. CONTENT VALIDATION: Extensible validation system for different content types
111
+ */
112
+ export class SecureDownloader {
113
+ defaultTimeout;
114
+ defaultMaxSize;
115
+ tempDir;
116
+ globalRateLimiter;
117
+ urlRateLimiters;
118
+ constructor(options) {
119
+ this.defaultTimeout = options?.defaultTimeout || 30000; // 30 seconds
120
+ this.defaultMaxSize = options?.defaultMaxSize || SECURITY_LIMITS.MAX_FILE_SIZE;
121
+ this.tempDir = options?.tempDir || '.tmp';
122
+ // Initialize rate limiters
123
+ const rateLimitConfig = options?.rateLimitOptions || {};
124
+ this.globalRateLimiter = new RateLimiter({
125
+ maxRequests: rateLimitConfig.maxGlobalRequests || 100, // 100 downloads per hour globally
126
+ windowMs: rateLimitConfig.windowMs || 60 * 60 * 1000, // 1 hour
127
+ minDelayMs: 1000 // Minimum 1 second between requests
128
+ });
129
+ this.urlRateLimiters = new Map();
130
+ }
131
+ /**
132
+ * Download content to a file with validation
133
+ *
134
+ * SECURITY: Implements validate-before-write pattern:
135
+ * 1. Download content to memory
136
+ * 2. Validate all content
137
+ * 3. Only then write to disk atomically
138
+ *
139
+ * @param url - URL to download from
140
+ * @param destinationPath - Local file path to save to
141
+ * @param options - Download and validation options
142
+ */
143
+ async downloadToFile(url, destinationPath, options = {}) {
144
+ const startTime = Date.now();
145
+ logger.debug(`Starting secure download from ${url} to ${destinationPath}`);
146
+ try {
147
+ // SECURITY: Validate URL and destination path first
148
+ this.validateUrl(url);
149
+ const validatedPath = await this.validateDestinationPath(destinationPath);
150
+ // SECURITY: Check if file already exists (prevent accidental overwrites)
151
+ try {
152
+ await fs.access(validatedPath);
153
+ throw DownloadError.filesystemError(`File already exists: ${destinationPath}`);
154
+ }
155
+ catch (error) {
156
+ if (error.code !== 'ENOENT') {
157
+ throw error; // Re-throw if it's not a "file not found" error
158
+ }
159
+ // File doesn't exist, proceed with download
160
+ }
161
+ // STEP 1: Check rate limits before download
162
+ await this.checkRateLimit(url);
163
+ // STEP 2: Download content to memory (no disk operations yet)
164
+ const content = await this.downloadToMemory(url, options);
165
+ // STEP 3: Validate checksum if provided
166
+ if (options.expectedChecksum) {
167
+ await this.validateChecksum(content, options.expectedChecksum);
168
+ }
169
+ // STEP 4: All validation is complete, now write atomically
170
+ const useAtomic = options.atomic !== false; // Default to true
171
+ if (useAtomic) {
172
+ await this.atomicWriteFile(validatedPath, content);
173
+ }
174
+ else {
175
+ await this.directWriteFile(validatedPath, content);
176
+ }
177
+ const duration = Date.now() - startTime;
178
+ logger.info(`Secure download completed: ${destinationPath} (${content.length} bytes, ${duration}ms)`);
179
+ // Log successful download for security monitoring
180
+ SecurityMonitor.logSecurityEvent({
181
+ type: 'FILE_COPIED',
182
+ severity: 'LOW',
183
+ source: 'secure_downloader',
184
+ details: `Downloaded ${content.length} bytes from ${url} to ${destinationPath}`,
185
+ metadata: {
186
+ url,
187
+ destinationPath,
188
+ contentLength: content.length,
189
+ duration
190
+ }
191
+ });
192
+ }
193
+ catch (error) {
194
+ const duration = Date.now() - startTime;
195
+ logger.error(`Secure download failed: ${error instanceof Error ? error.message : String(error)}`);
196
+ // Log failed download for security monitoring
197
+ SecurityMonitor.logSecurityEvent({
198
+ type: 'PATH_TRAVERSAL_ATTEMPT',
199
+ severity: 'MEDIUM',
200
+ source: 'secure_downloader',
201
+ details: `Download failed: ${error instanceof Error ? error.message : String(error)}`,
202
+ metadata: {
203
+ url,
204
+ destinationPath,
205
+ duration,
206
+ errorType: error instanceof DownloadError ? error.code : 'UNKNOWN'
207
+ }
208
+ });
209
+ throw error;
210
+ }
211
+ }
212
+ /**
213
+ * Download content to memory with validation
214
+ *
215
+ * @param url - URL to download from
216
+ * @param options - Download and validation options
217
+ * @returns Validated content as string
218
+ */
219
+ async downloadToMemory(url, options = {}) {
220
+ const timeout = options.timeout || this.defaultTimeout;
221
+ const maxSize = options.maxSize || this.defaultMaxSize;
222
+ logger.debug(`Downloading content from ${url} (max: ${maxSize} bytes, timeout: ${timeout}ms)`);
223
+ try {
224
+ // SECURITY: Validate URL format
225
+ this.validateUrl(url);
226
+ // STEP 1: Check rate limits before download
227
+ await this.checkRateLimit(url);
228
+ // STEP 2: Fetch content with size and timeout protection
229
+ const content = await this.fetchWithLimits(url, maxSize, timeout, options.headers);
230
+ // STEP 3: Validate content type if specified
231
+ if (options.expectedContentType) {
232
+ await this.validateContentType(content, options.expectedContentType);
233
+ }
234
+ // STEP 4: Validate checksum if provided
235
+ if (options.expectedChecksum) {
236
+ await this.validateChecksum(content, options.expectedChecksum);
237
+ }
238
+ // STEP 5: Run built-in security validation
239
+ const securityResult = SecurityContentValidator.validateAndSanitize(content);
240
+ if (!securityResult.isValid && securityResult.severity === 'critical') {
241
+ throw DownloadError.securityError(`Critical security threat detected: ${securityResult.detectedPatterns?.join(', ')}`);
242
+ }
243
+ // STEP 6: Run custom validator if provided
244
+ if (options.validator) {
245
+ logger.debug('Running custom content validation');
246
+ const validationResult = await options.validator(content);
247
+ if (!validationResult.isValid) {
248
+ throw DownloadError.validationError(validationResult.errorMessage || 'Content validation failed');
249
+ }
250
+ }
251
+ logger.debug(`Content validation passed (${content.length} bytes)`);
252
+ return securityResult.sanitizedContent || content;
253
+ }
254
+ catch (error) {
255
+ if (error instanceof DownloadError) {
256
+ throw error;
257
+ }
258
+ throw DownloadError.networkError(`Failed to download content from ${url}: ${error instanceof Error ? error.message : String(error)}`, error instanceof Error ? error : undefined);
259
+ }
260
+ }
261
+ /**
262
+ * Download large files using streaming with chunk-level validation
263
+ *
264
+ * @param url - URL to download from
265
+ * @param destinationPath - Local file path to save to
266
+ * @param options - Streaming download options
267
+ */
268
+ async downloadStream(url, destinationPath, options = {}) {
269
+ const startTime = Date.now();
270
+ const maxSize = options.maxSize || this.defaultMaxSize;
271
+ const timeout = options.timeout || this.defaultTimeout;
272
+ logger.debug(`Starting streaming download from ${url} to ${destinationPath}`);
273
+ try {
274
+ // SECURITY: Check rate limits before download
275
+ await this.checkRateLimit(url);
276
+ // SECURITY: Validate URL and destination path
277
+ this.validateUrl(url);
278
+ const validatedPath = await this.validateDestinationPath(destinationPath);
279
+ // Generate temporary file path for atomic operation
280
+ const tempPath = await this.getTempFilePath(validatedPath);
281
+ let downloadedSize = 0;
282
+ let timeoutHandle;
283
+ // Create abort controller for timeout handling
284
+ const abortController = new AbortController();
285
+ timeoutHandle = setTimeout(() => {
286
+ abortController.abort();
287
+ }, timeout);
288
+ try {
289
+ // SECURITY: Fetch with abort signal for timeout
290
+ const response = await fetch(url, {
291
+ signal: abortController.signal,
292
+ headers: options.headers
293
+ });
294
+ if (!response.ok) {
295
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
296
+ }
297
+ if (!response.body) {
298
+ throw new Error('Response body is null');
299
+ }
300
+ // Ensure temp directory exists
301
+ await fs.mkdir(path.dirname(tempPath), { recursive: true });
302
+ // Create write stream to temporary file
303
+ const writeStream = createWriteStream(tempPath);
304
+ // Create a transform stream for validation and size checking
305
+ const validationStream = new Readable({
306
+ async read() {
307
+ // This stream will be fed by the pipeline
308
+ }
309
+ });
310
+ // Set up chunk validation and size checking
311
+ const reader = response.body.getReader();
312
+ const pump = async () => {
313
+ try {
314
+ while (true) {
315
+ const { done, value } = await reader.read();
316
+ if (done)
317
+ break;
318
+ // SECURITY: Check size limit
319
+ downloadedSize += value.length;
320
+ if (downloadedSize > maxSize) {
321
+ throw DownloadError.securityError(`File size exceeds limit: ${downloadedSize} > ${maxSize} bytes`);
322
+ }
323
+ // SECURITY: Run chunk validator if provided
324
+ if (options.streamValidator && !options.streamValidator(value)) {
325
+ throw DownloadError.validationError('Chunk validation failed');
326
+ }
327
+ validationStream.push(value);
328
+ }
329
+ validationStream.push(null); // End stream
330
+ }
331
+ catch (error) {
332
+ validationStream.destroy(error instanceof Error ? error : new Error(String(error)));
333
+ }
334
+ };
335
+ // Start the pump and pipeline concurrently
336
+ const [pumpResult] = await Promise.all([
337
+ pump(),
338
+ pipeline(validationStream, writeStream)
339
+ ]);
340
+ // Clear timeout
341
+ if (timeoutHandle) {
342
+ clearTimeout(timeoutHandle);
343
+ timeoutHandle = undefined;
344
+ }
345
+ // SECURITY: Atomic rename to final destination
346
+ await fs.rename(tempPath, validatedPath);
347
+ const duration = Date.now() - startTime;
348
+ logger.info(`Streaming download completed: ${destinationPath} (${downloadedSize} bytes, ${duration}ms)`);
349
+ // Log successful streaming download
350
+ SecurityMonitor.logSecurityEvent({
351
+ type: 'FILE_COPIED',
352
+ severity: 'LOW',
353
+ source: 'secure_downloader',
354
+ details: `Streamed ${downloadedSize} bytes from ${url} to ${destinationPath}`,
355
+ metadata: {
356
+ url,
357
+ destinationPath,
358
+ contentLength: downloadedSize,
359
+ duration
360
+ }
361
+ });
362
+ }
363
+ catch (error) {
364
+ // SECURITY: Guaranteed cleanup of temporary file
365
+ try {
366
+ await fs.unlink(tempPath);
367
+ logger.debug(`Cleaned up temp file: ${tempPath}`);
368
+ }
369
+ catch (cleanupError) {
370
+ logger.warn(`Failed to clean up temp file ${tempPath}: ${cleanupError}`);
371
+ }
372
+ throw error;
373
+ }
374
+ finally {
375
+ if (timeoutHandle) {
376
+ clearTimeout(timeoutHandle);
377
+ }
378
+ }
379
+ }
380
+ catch (error) {
381
+ const duration = Date.now() - startTime;
382
+ logger.error(`Streaming download failed: ${error instanceof Error ? error.message : String(error)}`);
383
+ // Log failed streaming download
384
+ SecurityMonitor.logSecurityEvent({
385
+ type: 'PATH_TRAVERSAL_ATTEMPT',
386
+ severity: 'MEDIUM',
387
+ source: 'secure_downloader',
388
+ details: `Streaming download failed: ${error instanceof Error ? error.message : String(error)}`,
389
+ metadata: {
390
+ url,
391
+ destinationPath,
392
+ duration,
393
+ errorType: error instanceof DownloadError ? error.code : 'UNKNOWN'
394
+ }
395
+ });
396
+ if (error instanceof Error && error.name === 'AbortError') {
397
+ throw DownloadError.timeoutError(`Download timed out after ${timeout}ms`);
398
+ }
399
+ if (error instanceof DownloadError) {
400
+ throw error;
401
+ }
402
+ throw DownloadError.networkError(`Streaming download failed: ${error instanceof Error ? error.message : String(error)}`, error instanceof Error ? error : undefined);
403
+ }
404
+ }
405
+ /**
406
+ * Validate URL format and security with Unicode normalization
407
+ */
408
+ validateUrl(url) {
409
+ if (!url || typeof url !== 'string') {
410
+ throw DownloadError.validationError('URL must be a non-empty string');
411
+ }
412
+ // SECURITY FIX: DMCP-SEC-004 - Unicode normalization on user input
413
+ const unicodeValidation = UnicodeValidator.normalize(url);
414
+ const normalizedUrl = unicodeValidation.normalizedContent;
415
+ if (!unicodeValidation.isValid) {
416
+ SecurityMonitor.logSecurityEvent({
417
+ type: 'UNICODE_VALIDATION_ERROR',
418
+ severity: 'MEDIUM',
419
+ source: 'secure_downloader',
420
+ details: `URL contains suspicious Unicode patterns: ${unicodeValidation.detectedIssues?.join(', ')}`,
421
+ metadata: { originalUrl: url, normalizedUrl }
422
+ });
423
+ }
424
+ // Use normalized URL for further validation
425
+ url = normalizedUrl;
426
+ let parsedUrl;
427
+ try {
428
+ parsedUrl = new URL(url);
429
+ }
430
+ catch (error) {
431
+ throw DownloadError.validationError(`Invalid URL format: ${url}`);
432
+ }
433
+ // SECURITY: Only allow HTTPS and HTTP protocols
434
+ if (!['https:', 'http:'].includes(parsedUrl.protocol)) {
435
+ throw DownloadError.securityError(`Unsupported protocol: ${parsedUrl.protocol}. Only HTTP/HTTPS allowed.`);
436
+ }
437
+ // SECURITY: Prevent requests to localhost/private networks
438
+ const hostname = parsedUrl.hostname.toLowerCase();
439
+ if (hostname === 'localhost' || hostname === '127.0.0.1' || hostname === '::1') {
440
+ throw DownloadError.securityError('Downloads from localhost are not allowed');
441
+ }
442
+ // SECURITY: Check for private IP ranges (basic protection)
443
+ if (hostname.startsWith('192.168.') || hostname.startsWith('10.') || hostname.startsWith('172.')) {
444
+ throw DownloadError.securityError('Downloads from private IP ranges are not allowed');
445
+ }
446
+ }
447
+ /**
448
+ * Validate destination path for security
449
+ */
450
+ async validateDestinationPath(filePath) {
451
+ try {
452
+ // Use existing PathValidator for comprehensive path validation
453
+ return await PathValidator.validatePersonaPath(filePath);
454
+ }
455
+ catch (error) {
456
+ throw DownloadError.securityError(`Invalid destination path: ${error instanceof Error ? error.message : String(error)}`);
457
+ }
458
+ }
459
+ /**
460
+ * Fetch content with size and timeout limits
461
+ */
462
+ async fetchWithLimits(url, maxSize, timeout, headers) {
463
+ const abortController = new AbortController();
464
+ const timeoutHandle = setTimeout(() => abortController.abort(), timeout);
465
+ try {
466
+ const response = await fetch(url, {
467
+ signal: abortController.signal,
468
+ headers: {
469
+ 'User-Agent': 'DollhouseMCP-SecureDownloader/1.0',
470
+ ...headers
471
+ }
472
+ });
473
+ if (!response.ok) {
474
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
475
+ }
476
+ // SECURITY: Check Content-Length header if available
477
+ const contentLength = response.headers.get('content-length');
478
+ if (contentLength && parseInt(contentLength, 10) > maxSize) {
479
+ throw DownloadError.securityError(`Content size ${contentLength} exceeds limit of ${maxSize} bytes`);
480
+ }
481
+ // Read content with size checking
482
+ const chunks = [];
483
+ let totalSize = 0;
484
+ if (!response.body) {
485
+ throw new Error('Response body is null');
486
+ }
487
+ const reader = response.body.getReader();
488
+ try {
489
+ while (true) {
490
+ const { done, value } = await reader.read();
491
+ if (done)
492
+ break;
493
+ totalSize += value.length;
494
+ if (totalSize > maxSize) {
495
+ throw DownloadError.securityError(`Content size ${totalSize} exceeds limit of ${maxSize} bytes`);
496
+ }
497
+ chunks.push(value);
498
+ }
499
+ }
500
+ finally {
501
+ reader.releaseLock();
502
+ }
503
+ // Combine chunks and decode
504
+ const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
505
+ const combined = new Uint8Array(totalLength);
506
+ let offset = 0;
507
+ for (const chunk of chunks) {
508
+ combined.set(chunk, offset);
509
+ offset += chunk.length;
510
+ }
511
+ return new TextDecoder('utf-8').decode(combined);
512
+ }
513
+ catch (error) {
514
+ if (error instanceof Error && error.name === 'AbortError') {
515
+ throw DownloadError.timeoutError(`Request timed out after ${timeout}ms`);
516
+ }
517
+ throw error;
518
+ }
519
+ finally {
520
+ clearTimeout(timeoutHandle);
521
+ }
522
+ }
523
+ /**
524
+ * Validate content type if specified
525
+ */
526
+ async validateContentType(content, expectedType) {
527
+ // Basic content type validation based on content analysis
528
+ switch (expectedType.toLowerCase()) {
529
+ case 'json':
530
+ try {
531
+ JSON.parse(content);
532
+ }
533
+ catch {
534
+ throw DownloadError.validationError('Content is not valid JSON');
535
+ }
536
+ break;
537
+ case 'yaml':
538
+ case 'yml':
539
+ // Use existing YAML validation
540
+ if (!SecurityContentValidator.validateYamlContent(content)) {
541
+ throw DownloadError.validationError('Content is not valid YAML');
542
+ }
543
+ break;
544
+ case 'markdown':
545
+ case 'md':
546
+ // Basic markdown validation (check for frontmatter format)
547
+ if (content.startsWith('---')) {
548
+ const frontmatterEnd = content.indexOf('\n---\n', 3);
549
+ if (frontmatterEnd === -1) {
550
+ throw DownloadError.validationError('Invalid markdown frontmatter format');
551
+ }
552
+ }
553
+ break;
554
+ default:
555
+ logger.debug(`No specific validation for content type: ${expectedType}`);
556
+ }
557
+ }
558
+ /**
559
+ * Atomic file write using FileLockManager
560
+ */
561
+ async atomicWriteFile(filePath, content) {
562
+ const resource = `download:${filePath}`;
563
+ await FileLockManager.withLock(resource, async () => {
564
+ // Ensure directory exists
565
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
566
+ // Use FileLockManager's atomic write
567
+ await FileLockManager.atomicWriteFile(filePath, content, { encoding: 'utf-8' });
568
+ });
569
+ }
570
+ /**
571
+ * Direct file write (non-atomic, for when atomic is disabled)
572
+ */
573
+ async directWriteFile(filePath, content) {
574
+ // Ensure directory exists
575
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
576
+ // Direct write
577
+ await fs.writeFile(filePath, content, 'utf-8');
578
+ }
579
+ /**
580
+ * Generate temporary file path for atomic operations
581
+ */
582
+ async getTempFilePath(originalPath) {
583
+ const dir = path.dirname(originalPath);
584
+ const basename = path.basename(originalPath);
585
+ const random = randomBytes(8).toString('hex');
586
+ const tempDir = path.join(dir, this.tempDir);
587
+ // Ensure temp directory exists
588
+ await fs.mkdir(tempDir, { recursive: true });
589
+ return path.join(tempDir, `${basename}.${random}.tmp`);
590
+ }
591
+ /**
592
+ * Check rate limits for downloads
593
+ */
594
+ async checkRateLimit(url) {
595
+ // Check global rate limit
596
+ const globalStatus = this.globalRateLimiter.checkLimit();
597
+ if (!globalStatus.allowed) {
598
+ SecurityMonitor.logSecurityEvent({
599
+ type: 'RATE_LIMIT_EXCEEDED',
600
+ severity: 'MEDIUM',
601
+ source: 'secure_downloader',
602
+ details: `Global download rate limit exceeded. Retry after ${globalStatus.retryAfterMs}ms`,
603
+ metadata: { url, retryAfterMs: globalStatus.retryAfterMs }
604
+ });
605
+ throw DownloadError.securityError(`Download rate limit exceeded. Please retry after ${Math.ceil(globalStatus.retryAfterMs / 1000)} seconds`);
606
+ }
607
+ // Check per-URL rate limit
608
+ const parsedUrl = new URL(url);
609
+ const urlKey = `${parsedUrl.hostname}:${parsedUrl.port || (parsedUrl.protocol === 'https:' ? '443' : '80')}`;
610
+ if (!this.urlRateLimiters.has(urlKey)) {
611
+ this.urlRateLimiters.set(urlKey, new RateLimiter({
612
+ maxRequests: 10, // 10 requests per hour per URL
613
+ windowMs: 60 * 60 * 1000,
614
+ minDelayMs: 5000 // 5 second minimum delay between requests to same URL
615
+ }));
616
+ }
617
+ const urlLimiter = this.urlRateLimiters.get(urlKey);
618
+ const urlStatus = urlLimiter.checkLimit();
619
+ if (!urlStatus.allowed) {
620
+ SecurityMonitor.logSecurityEvent({
621
+ type: 'RATE_LIMIT_EXCEEDED',
622
+ severity: 'MEDIUM',
623
+ source: 'secure_downloader',
624
+ details: `Per-URL download rate limit exceeded for ${urlKey}. Retry after ${urlStatus.retryAfterMs}ms`,
625
+ metadata: { url, urlKey, retryAfterMs: urlStatus.retryAfterMs }
626
+ });
627
+ throw DownloadError.securityError(`Too many requests to ${urlKey}. Please retry after ${Math.ceil(urlStatus.retryAfterMs / 1000)} seconds`);
628
+ }
629
+ // Consume rate limit tokens
630
+ this.globalRateLimiter.consumeToken();
631
+ urlLimiter.consumeToken();
632
+ }
633
+ /**
634
+ * Validate content checksum for integrity verification
635
+ */
636
+ async validateChecksum(content, expectedChecksum) {
637
+ const normalizedExpected = expectedChecksum.toLowerCase().trim();
638
+ // Validate checksum format (SHA-256 should be 64 hex characters)
639
+ if (!/^[a-f0-9]{64}$/.test(normalizedExpected)) {
640
+ throw DownloadError.validationError('Invalid checksum format. Expected SHA-256 (64 hex characters)');
641
+ }
642
+ const contentBuffer = Buffer.from(content, 'utf-8');
643
+ const actualChecksum = createHash('sha256').update(contentBuffer).digest('hex');
644
+ if (actualChecksum !== normalizedExpected) {
645
+ SecurityMonitor.logSecurityEvent({
646
+ type: 'CONTENT_INJECTION_ATTEMPT',
647
+ severity: 'HIGH',
648
+ source: 'secure_downloader',
649
+ details: `Checksum mismatch detected - possible content tampering`,
650
+ metadata: {
651
+ expectedChecksum: normalizedExpected,
652
+ actualChecksum,
653
+ contentLength: content.length
654
+ }
655
+ });
656
+ throw DownloadError.securityError(`Content checksum verification failed. Expected: ${normalizedExpected}, Got: ${actualChecksum}`);
657
+ }
658
+ logger.debug(`Checksum validation passed: ${actualChecksum}`);
659
+ }
660
+ /**
661
+ * Create a content validator that combines multiple validators
662
+ */
663
+ static combineValidators(...validators) {
664
+ return async (content) => {
665
+ for (const validator of validators) {
666
+ const result = await validator(content);
667
+ if (!result.isValid) {
668
+ return result;
669
+ }
670
+ }
671
+ return { isValid: true };
672
+ };
673
+ }
674
+ /**
675
+ * Create a content validator for JSON content
676
+ */
677
+ static jsonValidator() {
678
+ return async (content) => {
679
+ try {
680
+ JSON.parse(content);
681
+ return { isValid: true };
682
+ }
683
+ catch (error) {
684
+ return {
685
+ isValid: false,
686
+ errorMessage: `Invalid JSON: ${error instanceof Error ? error.message : String(error)}`,
687
+ severity: 'medium'
688
+ };
689
+ }
690
+ };
691
+ }
692
+ /**
693
+ * Create a content validator for YAML content
694
+ */
695
+ static yamlValidator() {
696
+ return async (content) => {
697
+ const isValid = SecurityContentValidator.validateYamlContent(content);
698
+ return {
699
+ isValid,
700
+ errorMessage: isValid ? undefined : 'Invalid or malicious YAML content',
701
+ severity: isValid ? 'low' : 'high'
702
+ };
703
+ };
704
+ }
705
+ /**
706
+ * Create a content validator for markdown content
707
+ */
708
+ static markdownValidator() {
709
+ return async (content) => {
710
+ try {
711
+ // Use existing persona content sanitization for markdown
712
+ SecurityContentValidator.sanitizePersonaContent(content);
713
+ return { isValid: true };
714
+ }
715
+ catch (error) {
716
+ return {
717
+ isValid: false,
718
+ errorMessage: `Invalid markdown: ${error instanceof Error ? error.message : String(error)}`,
719
+ severity: error instanceof SecurityError ? 'critical' : 'medium'
720
+ };
721
+ }
722
+ };
723
+ }
724
+ /**
725
+ * Create a content validator with size limits
726
+ */
727
+ static sizeValidator(maxSize) {
728
+ return async (content) => {
729
+ const size = Buffer.byteLength(content, 'utf-8');
730
+ if (size > maxSize) {
731
+ return {
732
+ isValid: false,
733
+ errorMessage: `Content size ${size} exceeds limit of ${maxSize} bytes`,
734
+ severity: 'high'
735
+ };
736
+ }
737
+ return { isValid: true };
738
+ };
739
+ }
740
+ /**
741
+ * Create a content validator that checks for forbidden patterns
742
+ */
743
+ static patternValidator(forbiddenPatterns, errorMessage = 'Forbidden pattern detected') {
744
+ return async (content) => {
745
+ for (const pattern of forbiddenPatterns) {
746
+ if (pattern.test(content)) {
747
+ return {
748
+ isValid: false,
749
+ errorMessage,
750
+ severity: 'high',
751
+ metadata: { pattern: pattern.source }
752
+ };
753
+ }
754
+ }
755
+ return { isValid: true };
756
+ };
757
+ }
758
+ }
759
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU2VjdXJlRG93bmxvYWRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy91dGlscy9TZWN1cmVEb3dubG9hZGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBdURHO0FBRUgsT0FBTyxLQUFLLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDbEMsT0FBTyxLQUFLLElBQUksTUFBTSxNQUFNLENBQUM7QUFDN0IsT0FBTyxFQUFFLFdBQVcsRUFBRSxVQUFVLEVBQUUsTUFBTSxRQUFRLENBQUM7QUFDakQsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLFFBQVEsQ0FBQztBQUNsQyxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDM0MsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sSUFBSSxDQUFDO0FBRXZDLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUMzRCxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDM0QsT0FBTyxFQUFFLGdCQUFnQixJQUFJLHdCQUF3QixFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDL0YsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBQzdELE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUNqRSxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFDakUsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sNENBQTRDLENBQUM7QUFDOUUsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQy9DLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxhQUFhLENBQUM7QUE0RHJDOztHQUVHO0FBQ0gsTUFBTSxPQUFPLGFBQWMsU0FBUSxLQUFLO0lBR3BCO0lBQ0E7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SyxFQUFFLE9BQWUsRUFBNkIsRUFBRTtZQUMxRCxLQUFLLE1BQU0sT0FBTyxJQUFJLGlCQUFpQixFQUFFLENBQUM7Z0JBQ3hDLElBQUksT0FBTyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDO29CQUMxQixPQUFPO3dCQUNMLE9BQU8sRUFBRSxLQUFLO3dCQUNkLFlBQVk7d0JBQ1osUUFBUSxFQUFFLE1BQU07d0JBQ2hCLFFBQVEsRUFBRSxFQUFFLE9BQU8sRUFBRSxPQUFPLENBQUMsTUFBTSxFQUFFO3FCQUN0QyxDQUFDO2dCQUNKLENBQUM7WUFDSCxDQUFDO1lBQ0QsT0FBTyxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsQ0FBQztRQUMzQixDQUFDLENBQUM7SUFDSixDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFNlY3VyZURvd25sb2FkZXIgLSBSZXVzYWJsZSB1dGlsaXR5IGZvciBzYWZlIGNvbnRlbnQgZG93bmxvYWRzXG4gKiBcbiAqIEltcGxlbWVudHMgdGhlIHZhbGlkYXRlLWJlZm9yZS13cml0ZSBwYXR0ZXJuIHdpdGggY29tcHJlaGVuc2l2ZSBzZWN1cml0eSBmZWF0dXJlczpcbiAqIC0gQ29udGVudCB2YWxpZGF0aW9uIGhvb2tzIChjdXN0b21pemFibGUgdmFsaWRhdG9ycylcbiAqIC0gQXRvbWljIGZpbGUgb3BlcmF0aW9ucyB3aXRoIHRlbXAgZmlsZXNcbiAqIC0gR3VhcmFudGVlZCBjbGVhbnVwIG9uIGZhaWx1cmVcbiAqIC0gTWVtb3J5LWVmZmljaWVudCBzdHJlYW1pbmcgZm9yIGxhcmdlIGZpbGVzXG4gKiAtIFNpemUgbGltaXRzIHRvIHByZXZlbnQgRG9TIGF0dGFja3NcbiAqIC0gUGF0aCB2YWxpZGF0aW9uIHRvIHByZXZlbnQgdHJhdmVyc2FsXG4gKiAtIFRpbWVvdXQgaGFuZGxpbmcgZm9yIG5ldHdvcmsgb3BlcmF0aW9uc1xuICogLSBDb250ZW50IHR5cGUgdmFsaWRhdGlvblxuICogXG4gKiBVc2FnZSBFeGFtcGxlczpcbiAqIFxuICogLy8gQmFzaWMgZG93bmxvYWQgd2l0aCB2YWxpZGF0aW9uXG4gKiBjb25zdCBkb3dubG9hZGVyID0gbmV3IFNlY3VyZURvd25sb2FkZXIoKTtcbiAqIGF3YWl0IGRvd25sb2FkZXIuZG93bmxvYWRUb0ZpbGUoXG4gKiAgICdodHRwczovL2V4YW1wbGUuY29tL2ZpbGUubWQnLFxuICogICAnLi9kb3dubG9hZHMvZmlsZS5tZCcsXG4gKiAgIHtcbiAqICAgICB2YWxpZGF0b3I6IGFzeW5jIChjb250ZW50KSA9PiAoe1xuICogICAgICAgaXNWYWxpZDogIWNvbnRlbnQuaW5jbHVkZXMoJ21hbGljaW91cycpLFxuICogICAgICAgZXJyb3JNZXNzYWdlOiBjb250ZW50LmluY2x1ZGVzKCdtYWxpY2lvdXMnKSA/ICdNYWxpY2lvdXMgY29udGVudCBkZXRlY3RlZCcgOiB1bmRlZmluZWRcbiAqICAgICB9KSxcbiAqICAgICBtYXhTaXplOiAxMDI0ICogMTAyNCwgLy8gMU1CIGxpbWl0XG4gKiAgICAgdGltZW91dDogMzAwMDAgLy8gMzAgc2Vjb25kIHRpbWVvdXRcbiAqICAgfVxuICogKTtcbiAqIFxuICogLy8gRG93bmxvYWQgdG8gbWVtb3J5IHdpdGggdmFsaWRhdGlvblxuICogY29uc3QgY29udGVudCA9IGF3YWl0IGRvd25sb2FkZXIuZG93bmxvYWRUb01lbW9yeShcbiAqICAgJ2h0dHBzOi8vZXhhbXBsZS5jb20vZGF0YS5qc29uJyxcbiAqICAge1xuICogICAgIHZhbGlkYXRvcjogYXN5bmMgKGNvbnRlbnQpID0+IHtcbiAqICAgICAgIHRyeSB7XG4gKiAgICAgICAgIEpTT04ucGFyc2UoY29udGVudCk7XG4gKiAgICAgICAgIHJldHVybiB7IGlzVmFsaWQ6IHRydWUgfTtcbiAqICAgICAgIH0gY2F0Y2gge1xuICogICAgICAgICByZXR1cm4geyBpc1ZhbGlkOiBmYWxzZSwgZXJyb3JNZXNzYWdlOiAnSW52YWxpZCBKU09OIGZvcm1hdCcgfTtcbiAqICAgICAgIH1cbiAqICAgICB9XG4gKiAgIH1cbiAqICk7XG4gKiBcbiAqIC8vIFN0cmVhbWluZyBkb3dubG9hZCBmb3IgbGFyZ2UgZmlsZXNcbiAqIGF3YWl0IGRvd25sb2FkZXIuZG93bmxvYWRTdHJlYW0oXG4gKiAgICdodHRwczovL2V4YW1wbGUuY29tL2xhcmdlLWZpbGUuemlwJyxcbiAqICAgJy4vZG93bmxvYWRzL2xhcmdlLWZpbGUuemlwJyxcbiAqICAge1xuICogICAgIHN0cmVhbVZhbGlkYXRvcjogKGNodW5rKSA9PiAhY2h1bmsuaW5jbHVkZXMoQnVmZmVyLmZyb20oJ1ZJUlVTJykpLFxuICogICAgIG1heFNpemU6IDEwMCAqIDEwMjQgKiAxMDI0LCAvLyAxMDBNQiBsaW1pdFxuICogICAgIHRpbWVvdXQ6IDMwMDAwMCAvLyA1IG1pbnV0ZSB0aW1lb3V0XG4gKiAgIH1cbiAqICk7XG4gKi9cblxuaW1wb3J0ICogYXMgZnMgZnJvbSAnZnMvcHJvbWlzZXMnO1xuaW1wb3J0ICogYXMgcGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCB7IHJhbmRvbUJ5dGVzLCBjcmVhdGVIYXNoIH0gZnJvbSAnY3J5cHRvJztcbmltcG9ydCB7IFJlYWRhYmxlIH0gZnJvbSAnc3RyZWFtJztcbmltcG9ydCB7IHBpcGVsaW5lIH0gZnJvbSAnc3RyZWFtL3Byb21pc2VzJztcbmltcG9ydCB7IGNyZWF0ZVdyaXRlU3RyZWFtIH0gZnJvbSAnZnMnO1xuXG5pbXBvcnQgeyBTZWN1cml0eUVycm9yIH0gZnJvbSAnLi4vZXJyb3JzL1NlY3VyaXR5RXJyb3IuanMnO1xuaW1wb3J0IHsgU0VDVVJJVFlfTElNSVRTIH0gZnJvbSAnLi4vc2VjdXJpdHkvY29uc3RhbnRzLmpzJztcbmltcG9ydCB7IENvbnRlbnRWYWxpZGF0b3IgYXMgU2VjdXJpdHlDb250ZW50VmFsaWRhdG9yIH0gZnJvbSAnLi4vc2VjdXJpdHkvY29udGVudFZhbGlkYXRvci5qcyc7XG5pbXBvcnQgeyBQYXRoVmFsaWRhdG9yIH0gZnJvbSAnLi4vc2VjdXJpdHkvcGF0aFZhbGlkYXRvci5qcyc7XG5pbXBvcnQgeyBGaWxlTG9ja01hbmFnZXIgfSBmcm9tICcuLi9zZWN1cml0eS9maWxlTG9ja01hbmFnZXIuanMnO1xuaW1wb3J0IHsgU2VjdXJpdHlNb25pdG9yIH0gZnJvbSAnLi4vc2VjdXJpdHkvc2VjdXJpdHlNb25pdG9yLmpzJztcbmltcG9ydCB7IFVuaWNvZGVWYWxpZGF0b3IgfSBmcm9tICcuLi9zZWN1cml0eS92YWxpZGF0b3JzL3VuaWNvZGVWYWxpZGF0b3IuanMnO1xuaW1wb3J0IHsgUmF0ZUxpbWl0ZXIgfSBmcm9tICcuL1JhdGVMaW1pdGVyLmpzJztcbmltcG9ydCB7IGxvZ2dlciB9IGZyb20gJy4vbG9nZ2VyLmpzJztcblxuLyoqXG4gKiBSZXN1bHQgb2YgY29udGVudCB2YWxpZGF0aW9uXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgVmFsaWRhdGlvblJlc3VsdCB7XG4gIC8qKiBXaGV0aGVyIHRoZSBjb250ZW50IGlzIHZhbGlkIGFuZCBzYWZlICovXG4gIGlzVmFsaWQ6IGJvb2xlYW47XG4gIC8qKiBFcnJvciBtZXNzYWdlIGlmIHZhbGlkYXRpb24gZmFpbGVkICovXG4gIGVycm9yTWVzc2FnZT86IHN0cmluZztcbiAgLyoqIFNldmVyaXR5IG9mIGFueSBkZXRlY3RlZCBpc3N1ZXMgKi9cbiAgc2V2ZXJpdHk/OiAnbG93JyB8ICdtZWRpdW0nIHwgJ2hpZ2gnIHwgJ2NyaXRpY2FsJztcbiAgLyoqIEFkZGl0aW9uYWwgbWV0YWRhdGEgYWJvdXQgdmFsaWRhdGlvbiAqL1xuICBtZXRhZGF0YT86IFJlY29yZDxzdHJpbmcsIGFueT47XG59XG5cbi8qKlxuICogQ29udGVudCB2YWxpZGF0b3IgZnVuY3Rpb24gdHlwZVxuICovXG5leHBvcnQgdHlwZSBDb250ZW50VmFsaWRhdG9yRnVuY3Rpb24gPSAoY29udGVudDogc3RyaW5nKSA9PiBQcm9taXNlPFZhbGlkYXRpb25SZXN1bHQ+O1xuXG4vKipcbiAqIFN0cmVhbSBjaHVuayB2YWxpZGF0b3IgZnVuY3Rpb24gdHlwZVxuICovXG5leHBvcnQgdHlwZSBTdHJlYW1WYWxpZGF0b3IgPSAoY2h1bms6IFVpbnQ4QXJyYXkpID0+IGJvb2xlYW47XG5cbi8qKlxuICogT3B0aW9ucyBmb3IgZG93bmxvYWQgb3BlcmF0aW9uc1xuICovXG5leHBvcnQgaW50ZXJmYWNlIERvd25sb2FkT3B0aW9ucyB7XG4gIC8qKiBDdXN0b20gY29udGVudCB2YWxpZGF0b3IgZnVuY3Rpb24gKi9cbiAgdmFsaWRhdG9yPzogQ29udGVudFZhbGlkYXRvckZ1bmN0aW9uO1xuICAvKiogTWF4aW11bSBmaWxlIHNpemUgaW4gYnl0ZXMgKGRlZmF1bHQ6IFNFQ1VSSVRZX0xJTUlUUy5NQVhfRklMRV9TSVpFKSAqL1xuICBtYXhTaXplPzogbnVtYmVyO1xuICAvKiogTmV0d29yayB0aW1lb3V0IGluIG1pbGxpc2Vjb25kcyAoZGVmYXVsdDogMzAwMDApICovXG4gIHRpbWVvdXQ/OiBudW1iZXI7XG4gIC8qKiBXaGV0aGVyIHRvIHVzZSBhdG9taWMgZmlsZSBvcGVyYXRpb25zIChkZWZhdWx0OiB0cnVlKSAqL1xuICBhdG9taWM/OiBib29sZWFuO1xuICAvKiogRXhwZWN0ZWQgY29udGVudCB0eXBlIChmb3IgdmFsaWRhdGlvbikgKi9cbiAgZXhwZWN0ZWRDb250ZW50VHlwZT86IHN0cmluZztcbiAgLyoqIEN1c3RvbSBIVFRQIGhlYWRlcnMgKi9cbiAgaGVhZGVycz86IFJlY29yZDxzdHJpbmcsIHN0cmluZz47XG4gIC8qKiBFeHBlY3RlZCBTSEEtMjU2IGNoZWNrc3VtIGZvciBpbnRlZ3JpdHkgdmFsaWRhdGlvbiAqL1xuICBleHBlY3RlZENoZWNrc3VtPzogc3RyaW5nO1xufVxuXG4vKipcbiAqIE9wdGlvbnMgZm9yIHN0cmVhbWluZyBkb3dubG9hZHNcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBTdHJlYW1Eb3dubG9hZE9wdGlvbnMge1xuICAvKiogQ2h1bmstbGV2ZWwgdmFsaWRhdG9yIGZvciBzdHJlYW1pbmcgdmFsaWRhdGlvbiAqL1xuICBzdHJlYW1WYWxpZGF0b3I/OiBTdHJlYW1WYWxpZGF0b3I7XG4gIC8qKiBNYXhpbXVtIGZpbGUgc2l6ZSBpbiBieXRlcyAoZGVmYXVsdDogU0VDVVJJVFlfTElNSVRTLk1BWF9GSUxFX1NJWkUpICovXG4gIG1heFNpemU/OiBudW1iZXI7XG4gIC8qKiBOZXR3b3JrIHRpbWVvdXQgaW4gbWlsbGlzZWNvbmRzIChkZWZhdWx0OiAzMDAwMCkgKi9cbiAgdGltZW91dD86IG51bWJlcjtcbiAgLyoqIEN1c3RvbSBIVFRQIGhlYWRlcnMgKi9cbiAgaGVhZGVycz86IFJlY29yZDxzdHJpbmcsIHN0cmluZz47XG59XG5cbi8qKlxuICogQ3VzdG9tIGVycm9yIHR5cGVzIGZvciBkaWZmZXJlbnQgZmFpbHVyZSBzY2VuYXJpb3NcbiAqL1xuZXhwb3J0IGNsYXNzIERvd25sb2FkRXJyb3IgZXh0ZW5kcyBFcnJvciB7XG4gIGNvbnN0cnVjdG9yKFxuICAgIG1lc3NhZ2U6IHN0cmluZyxcbiAgICBwdWJsaWMgcmVhZG9ubHkgY29kZTogc3RyaW5nLFxuICAgIHB1YmxpYyByZWFkb25seSBvcmlnaW5hbEVycm9yPzogRXJyb3JcbiAgKSB7XG4gICAgc3VwZXIobWVzc2FnZSk7XG4gICAgdGhpcy5uYW1lID0gJ0Rvd25sb2FkRXJyb3InO1xuICB9XG5cbiAgc3RhdGljIG5ldHdvcmtFcnJvcihtZXNzYWdlOiBzdHJpbmcsIG9yaWdpbmFsRXJyb3I/OiBFcnJvcik6IERvd25sb2FkRXJyb3Ige1xuICAgIHJldHVybiBuZXcgRG93bmxvYWRFcnJvcihtZXNzYWdlLCAnTkVUV09SS19FUlJPUicsIG9yaWdpbmFsRXJyb3IpO1xuICB9XG5cbiAgc3RhdGljIHZhbGlkYXRpb25FcnJvcihtZXNzYWdlOiBzdHJpbmcpOiBEb3dubG9hZEVycm9yIHtcbiAgICByZXR1cm4gbmV3IERvd25sb2FkRXJyb3IobWVzc2FnZSwgJ1ZBTElEQVRJT05fRVJST1InKTtcbiAgfVxuXG4gIHN0YXRpYyBzZWN1cml0eUVycm9yKG1lc3NhZ2U6IHN0cmluZyk6IERvd25sb2FkRXJyb3Ige1xuICAgIHJldHVybiBuZXcgRG93bmxvYWRFcnJvcihtZXNzYWdlLCAnU0VDVVJJVFlfRVJST1InKTtcbiAgfVxuXG4gIHN0YXRpYyB0aW1lb3V0RXJyb3IobWVzc2FnZTogc3RyaW5nKTogRG93bmxvYWRFcnJvciB7XG4gICAgcmV0dXJuIG5ldyBEb3dubG9hZEVycm9yKG1lc3NhZ2UsICdUSU1FT1VUX0VSUk9SJyk7XG4gIH1cblxuICBzdGF0aWMgZmlsZXN5c3RlbUVycm9yKG1lc3NhZ2U6IHN0cmluZywgb3JpZ2luYWxFcnJvcj86IEVycm9yKTogRG93bmxvYWRFcnJvciB7XG4gICAgcmV0dXJuIG5ldyBEb3dubG9hZEVycm9yKG1lc3NhZ2UsICdGSUxFU1lTVEVNX0VSUk9SJywgb3JpZ2luYWxFcnJvcik7XG4gIH1cbn1cblxuLyoqXG4gKiBTZWN1cmVEb3dubG9hZGVyIC0gSW1wbGVtZW50cyB2YWxpZGF0ZS1iZWZvcmUtd3JpdGUgcGF0dGVybiBmb3Igc2FmZSBkb3dubG9hZHNcbiAqIFxuICogS2V5IFNlY3VyaXR5IEZlYXR1cmVzOlxuICogMS4gVkFMSURBVEUtQkVGT1JFLVdSSVRFOiBBbGwgY29udGVudCB2YWxpZGF0aW9uIG9jY3VycyBiZWZvcmUgYW55IGRpc2sgb3BlcmF0aW9uc1xuICogMi4gQVRPTUlDIE9QRVJBVElPTlM6IFVzZXMgdGVtcG9yYXJ5IGZpbGVzIHdpdGggYXRvbWljIHJlbmFtZSB0byBwcmV2ZW50IGNvcnJ1cHRpb25cbiAqIDMuIEdVQVJBTlRFRUQgQ0xFQU5VUDogQXV0b21hdGljIGNsZWFudXAgb2YgdGVtcG9yYXJ5IGZpbGVzIG9uIGFueSBmYWlsdXJlXG4gKiA0LiBTSVpFIExJTUlUUzogUHJldmVudHMgRG9TIGF0dGFja3MgdGhyb3VnaCBsYXJnZSBmaWxlIGRvd25sb2Fkc1xuICogNS4gUEFUSCBWQUxJREFUSU9OOiBQcmV2ZW50cyBkaXJlY3RvcnkgdHJhdmVyc2FsIGF0dGFja3NcbiAqIDYuIFRJTUVPVVQgUFJPVEVDVElPTjogUHJldmVudHMgaGFuZ2luZyBuZXR3b3JrIG9wZXJhdGlvbnNcbiAqIDcuIENPTlRFTlQgVkFMSURBVElPTjogRXh0ZW5zaWJsZSB2YWxpZGF0aW9uIHN5c3RlbSBmb3IgZGlmZmVyZW50IGNvbnRlbnQgdHlwZXNcbiAqL1xuZXhwb3J0IGNsYXNzIFNlY3VyZURvd25sb2FkZXIge1xuICBwcml2YXRlIHJlYWRvbmx5IGRlZmF1bHRUaW1lb3V0OiBudW1iZXI7XG4gIHByaXZhdGUgcmVhZG9ubHkgZGVmYXVsdE1heFNpemU6IG51bWJlcjtcbiAgcHJpdmF0ZSByZWFkb25seSB0ZW1wRGlyOiBzdHJpbmc7XG4gIHByaXZhdGUgcmVhZG9ubHkgZ2xvYmFsUmF0ZUxpbWl0ZXI6IFJhdGVMaW1pdGVyO1xuICBwcml2YXRlIHJlYWRvbmx5IHVybFJhdGVMaW1pdGVyczogTWFwPHN0cmluZywgUmF0ZUxpbWl0ZXI+O1xuXG4gIGNvbnN0cnVjdG9yKG9wdGlvbnM/OiB7XG4gICAgZGVmYXVsdFRpbWVvdXQ/OiBudW1iZXI7XG4gICAgZGVmYXVsdE1heFNpemU/OiBudW1iZXI7XG4gICAgdGVtcERpcj86IHN0cmluZztcbiAgICByYXRlTGltaXRPcHRpb25zPzoge1xuICAgICAgbWF4UmVxdWVzdHNQZXJVcmw/OiBudW1iZXI7XG4gICAgICBtYXhHbG9iYWxSZXF1ZXN0cz86IG51bWJlcjtcbiAgICAgIHdpbmRvd01zPzogbnVtYmVyO1xuICAgIH07XG4gIH0pIHtcbiAgICB0aGlzLmRlZmF1bHRUaW1lb3V0ID0gb3B0aW9ucz8uZGVmYXVsdFRpbWVvdXQgfHwgMzAwMDA7IC8vIDMwIHNlY29uZHNcbiAgICB0aGlzLmRlZmF1bHRNYXhTaXplID0gb3B0aW9ucz8uZGVmYXVsdE1heFNpemUgfHwgU0VDVVJJVFlfTElNSVRTLk1BWF9GSUxFX1NJWkU7XG4gICAgdGhpcy50ZW1wRGlyID0gb3B0aW9ucz8udGVtcERpciB8fCAnLnRtcCc7XG4gICAgXG4gICAgLy8gSW5pdGlhbGl6ZSByYXRlIGxpbWl0ZXJzXG4gICAgY29uc3QgcmF0ZUxpbWl0Q29uZmlnID0gb3B0aW9ucz8ucmF0ZUxpbWl0T3B0aW9ucyB8fCB7fTtcbiAgICB0aGlzLmdsb2JhbFJhdGVMaW1pdGVyID0gbmV3IFJhdGVMaW1pdGVyKHtcbiAgICAgIG1heFJlcXVlc3RzOiByYXRlTGltaXRDb25maWcubWF4R2xvYmFsUmVxdWVzdHMgfHwgMTAwLCAvLyAxMDAgZG93bmxvYWRzIHBlciBob3VyIGdsb2JhbGx5XG4gICAgICB3aW5kb3dNczogcmF0ZUxpbWl0Q29uZmlnLndpbmRvd01zIHx8IDYwICogNjAgKiAxMDAwLCAvLyAxIGhvdXJcbiAgICAgIG1pbkRlbGF5TXM6IDEwMDAgLy8gTWluaW11bSAxIHNlY29uZCBiZXR3ZWVuIHJlcXVlc3RzXG4gICAgfSk7XG4gICAgdGhpcy51cmxSYXRlTGltaXRlcnMgPSBuZXcgTWFwKCk7XG4gIH1cblxuICAvKipcbiAgICogRG93bmxvYWQgY29udGVudCB0byBhIGZpbGUgd2l0aCB2YWxpZGF0aW9uXG4gICAqIFxuICAgKiBTRUNVUklUWTogSW1wbGVtZW50cyB2YWxpZGF0ZS1iZWZvcmUtd3JpdGUgcGF0dGVybjpcbiAgICogMS4gRG93bmxvYWQgY29udGVudCB0byBtZW1vcnlcbiAgICogMi4gVmFsaWRhdGUgYWxsIGNvbnRlbnRcbiAgICogMy4gT25seSB0aGVuIHdyaXRlIHRvIGRpc2sgYXRvbWljYWxseVxuICAgKiBcbiAgICogQHBhcmFtIHVybCAtIFVSTCB0byBkb3dubG9hZCBmcm9tXG4gICAqIEBwYXJhbSBkZXN0aW5hdGlvblBhdGggLSBMb2NhbCBmaWxlIHBhdGggdG8gc2F2ZSB0b1xuICAgKiBAcGFyYW0gb3B0aW9ucyAtIERvd25sb2FkIGFuZCB2YWxpZGF0aW9uIG9wdGlvbnNcbiAgICovXG4gIGFzeW5jIGRvd25sb2FkVG9GaWxlKFxuICAgIHVybDogc3RyaW5nLFxuICAgIGRlc3RpbmF0aW9uUGF0aDogc3RyaW5nLFxuICAgIG9wdGlvbnM6IERvd25sb2FkT3B0aW9ucyA9IHt9XG4gICk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IHN0YXJ0VGltZSA9IERhdGUubm93KCk7XG4gICAgbG9nZ2VyLmRlYnVnKGBTdGFydGluZyBzZWN1cmUgZG93bmxvYWQgZnJvbSAke3VybH0gdG8gJHtkZXN0aW5hdGlvblBhdGh9YCk7XG5cbiAgICB0cnkge1xuICAgICAgLy8gU0VDVVJJVFk6IFZhbGlkYXRlIFVSTCBhbmQgZGVzdGluYXRpb24gcGF0aCBmaXJzdFxuICAgICAgdGhpcy52YWxpZGF0ZVVybCh1cmwpO1xuICAgICAgY29uc3QgdmFsaWRhdGVkUGF0aCA9IGF3YWl0IHRoaXMudmFsaWRhdGVEZXN0aW5hdGlvblBhdGgoZGVzdGluYXRpb25QYXRoKTtcblxuICAgICAgLy8gU0VDVVJJVFk6IENoZWNrIGlmIGZpbGUgYWxyZWFkeSBleGlzdHMgKHByZXZlbnQgYWNjaWRlbnRhbCBvdmVyd3JpdGVzKVxuICAgICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgZnMuYWNjZXNzKHZhbGlkYXRlZFBhdGgpO1xuICAgICAgICB0aHJvdyBEb3dubG9hZEVycm9yLmZpbGVzeXN0ZW1FcnJvcihgRmlsZSBhbHJlYWR5IGV4aXN0czogJHtkZXN0aW5hdGlvblBhdGh9YCk7XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBpZiAoKGVycm9yIGFzIE5vZGVKUy5FcnJub0V4Y2VwdGlvbikuY29kZSAhPT0gJ0VOT0VOVCcpIHtcbiAgICAgICAgICB0aHJvdyBlcnJvcjsgLy8gUmUtdGhyb3cgaWYgaXQncyBub3QgYSBcImZpbGUgbm90IGZvdW5kXCIgZXJyb3JcbiAgICAgICAgfVxuICAgICAgICAvLyBGaWxlIGRvZXNuJ3QgZXhpc3QsIHByb2NlZWQgd2l0aCBkb3dubG9hZFxuICAgICAgfVxuXG4gICAgICAvLyBTVEVQIDE6IENoZWNrIHJhdGUgbGltaXRzIGJlZm9yZSBkb3dubG9hZFxuICAgICAgYXdhaXQgdGhpcy5jaGVja1JhdGVMaW1pdCh1cmwpO1xuXG4gICAgICAvLyBTVEVQIDI6IERvd25sb2FkIGNvbnRlbnQgdG8gbWVtb3J5IChubyBkaXNrIG9wZXJhdGlvbnMgeWV0KVxuICAgICAgY29uc3QgY29udGVudCA9IGF3YWl0IHRoaXMuZG93bmxvYWRUb01lbW9yeSh1cmwsIG9wdGlvbnMpO1xuXG4gICAgICAvLyBTVEVQIDM6IFZhbGlkYXRlIGNoZWNrc3VtIGlmIHByb3ZpZGVkXG4gICAgICBpZiAob3B0aW9ucy5leHBlY3RlZENoZWNrc3VtKSB7XG4gICAgICAgIGF3YWl0IHRoaXMudmFsaWRhdGVDaGVja3N1bShjb250ZW50LCBvcHRpb25zLmV4cGVjdGVkQ2hlY2tzdW0pO1xuICAgICAgfVxuXG4gICAgICAvLyBTVEVQIDQ6IEFsbCB2YWxpZGF0aW9uIGlzIGNvbXBsZXRlLCBub3cgd3JpdGUgYXRvbWljYWxseVxuICAgICAgY29uc3QgdXNlQXRvbWljID0gb3B0aW9ucy5hdG9taWMgIT09IGZhbHNlOyAvLyBEZWZhdWx0IHRvIHRydWVcbiAgICAgIGlmICh1c2VBdG9taWMpIHtcbiAgICAgICAgYXdhaXQgdGhpcy5hdG9taWNXcml0ZUZpbGUodmFsaWRhdGVkUGF0aCwgY29udGVudCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBhd2FpdCB0aGlzLmRpcmVjdFdyaXRlRmlsZSh2YWxpZGF0ZWRQYXRoLCBjb250ZW50KTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgZHVyYXRpb24gPSBEYXRlLm5vdygpIC0gc3RhcnRUaW1lO1xuICAgICAgbG9nZ2VyLmluZm8oYFNlY3VyZSBkb3dubG9hZCBjb21wbGV0ZWQ6ICR7ZGVzdGluYXRpb25QYXRofSAoJHtjb250ZW50Lmxlbmd0aH0gYnl0ZXMsICR7ZHVyYXRpb259bXMpYCk7XG5cbiAgICAgIC8vIExvZyBzdWNjZXNzZnVsIGRvd25sb2FkIGZvciBzZWN1cml0eSBtb25pdG9yaW5nXG4gICAgICBTZWN1cml0eU1vbml0b3IubG9nU2VjdXJpdHlFdmVudCh7XG4gICAgICAgIHR5cGU6ICdGSUxFX0NPUElFRCcsXG4gICAgICAgIHNldmVyaXR5OiAnTE9XJyxcbiAgICAgICAgc291cmNlOiAnc2VjdXJlX2Rvd25sb2FkZXInLFxuICAgICAgICBkZXRhaWxzOiBgRG93bmxvYWRlZCAke2NvbnRlbnQubGVuZ3RofSBieXRlcyBmcm9tICR7dXJsfSB0byAke2Rlc3RpbmF0aW9uUGF0aH1gLFxuICAgICAgICBtZXRhZGF0YToge1xuICAgICAgICAgIHVybCxcbiAgICAgICAgICBkZXN0aW5hdGlvblBhdGgsXG4gICAgICAgICAgY29udGVudExlbmd0aDogY29udGVudC5sZW5ndGgsXG4gICAgICAgICAgZHVyYXRpb25cbiAgICAgICAgfVxuICAgICAgfSk7XG5cbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgY29uc3QgZHVyYXRpb24gPSBEYXRlLm5vdygpIC0gc3RhcnRUaW1lO1xuICAgICAgbG9nZ2VyLmVycm9yKGBTZWN1cmUgZG93bmxvYWQgZmFpbGVkOiAke2Vycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKX1gKTtcblxuICAgICAgLy8gTG9nIGZhaWxlZCBkb3dubG9hZCBmb3Igc2VjdXJpdHkgbW9uaXRvcmluZ1xuICAgICAgU2VjdXJpdHlNb25pdG9yLmxvZ1NlY3VyaXR5RXZlbnQoe1xuICAgICAgICB0eXBlOiAnUEFUSF9UUkFWRVJTQUxfQVRURU1QVCcsXG4gICAgICAgIHNldmVyaXR5OiAnTUVESVVNJyxcbiAgICAgICAgc291cmNlOiAnc2VjdXJlX2Rvd25sb2FkZXInLFxuICAgICAgICBkZXRhaWxzOiBgRG93bmxvYWQgZmFpbGVkOiAke2Vycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKX1gLFxuICAgICAgICBtZXRhZGF0YToge1xuICAgICAgICAgIHVybCxcbiAgICAgICAgICBkZXN0aW5hdGlvblBhdGgsXG4gICAgICAgICAgZHVyYXRpb24sXG4gICAgICAgICAgZXJyb3JUeXBlOiBlcnJvciBpbnN0YW5jZW9mIERvd25sb2FkRXJyb3IgPyBlcnJvci5jb2RlIDogJ1VOS05PV04nXG4gICAgICAgIH1cbiAgICAgIH0pO1xuXG4gICAgICB0aHJvdyBlcnJvcjtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogRG93bmxvYWQgY29udGVudCB0byBtZW1vcnkgd2l0aCB2YWxpZGF0aW9uXG4gICAqIFxuICAgKiBAcGFyYW0gdXJsIC0gVVJMIHRvIGRvd25sb2FkIGZyb21cbiAgICogQHBhcmFtIG9wdGlvbnMgLSBEb3dubG9hZCBhbmQgdmFsaWRhdGlvbiBvcHRpb25zXG4gICAqIEByZXR1cm5zIFZhbGlkYXRlZCBjb250ZW50IGFzIHN0cmluZ1xuICAgKi9cbiAgYXN5bmMgZG93bmxvYWRUb01lbW9yeShcbiAgICB1cmw6IHN0cmluZyxcbiAgICBvcHRpb25zOiBEb3dubG9hZE9wdGlvbnMgPSB7fVxuICApOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIGNvbnN0IHRpbWVvdXQgPSBvcHRpb25zLnRpbWVvdXQgfHwgdGhpcy5kZWZhdWx0VGltZW91dDtcbiAgICBjb25zdCBtYXhTaXplID0gb3B0aW9ucy5tYXhTaXplIHx8IHRoaXMuZGVmYXVsdE1heFNpemU7XG5cbiAgICBsb2dnZXIuZGVidWcoYERvd25sb2FkaW5nIGNvbnRlbnQgZnJvbSAke3VybH0gKG1heDogJHttYXhTaXplfSBieXRlcywgdGltZW91dDogJHt0aW1lb3V0fW1zKWApO1xuXG4gICAgdHJ5IHtcbiAgICAgIC8vIFNFQ1VSSVRZOiBWYWxpZGF0ZSBVUkwgZm9ybWF0XG4gICAgICB0aGlzLnZhbGlkYXRlVXJsKHVybCk7XG5cbiAgICAgIC8vIFNURVAgMTogQ2hlY2sgcmF0ZSBsaW1pdHMgYmVmb3JlIGRvd25sb2FkXG4gICAgICBhd2FpdCB0aGlzLmNoZWNrUmF0ZUxpbWl0KHVybCk7XG5cbiAgICAgIC8vIFNURVAgMjogRmV0Y2ggY29udGVudCB3aXRoIHNpemUgYW5kIHRpbWVvdXQgcHJvdGVjdGlvblxuICAgICAgY29uc3QgY29udGVudCA9IGF3YWl0IHRoaXMuZmV0Y2hXaXRoTGltaXRzKHVybCwgbWF4U2l6ZSwgdGltZW91dCwgb3B0aW9ucy5oZWFkZXJzKTtcblxuICAgICAgLy8gU1RFUCAzOiBWYWxpZGF0ZSBjb250ZW50IHR5cGUgaWYgc3BlY2lmaWVkXG4gICAgICBpZiAob3B0aW9ucy5leHBlY3RlZENvbnRlbnRUeXBlKSB7XG4gICAgICAgIGF3YWl0IHRoaXMudmFsaWRhdGVDb250ZW50VHlwZShjb250ZW50LCBvcHRpb25zLmV4cGVjdGVkQ29udGVudFR5cGUpO1xuICAgICAgfVxuXG4gICAgICAvLyBTVEVQIDQ6IFZhbGlkYXRlIGNoZWNrc3VtIGlmIHByb3ZpZGVkXG4gICAgICBpZiAob3B0aW9ucy5leHBlY3RlZENoZWNrc3VtKSB7XG4gICAgICAgIGF3YWl0IHRoaXMudmFsaWRhdGVDaGVja3N1bShjb250ZW50LCBvcHRpb25zLmV4cGVjdGVkQ2hlY2tzdW0pO1xuICAgICAgfVxuXG4gICAgICAvLyBTVEVQIDU6IFJ1biBidWlsdC1pbiBzZWN1cml0eSB2YWxpZGF0aW9uXG4gICAgICBjb25zdCBzZWN1cml0eVJlc3VsdCA9IFNlY3VyaXR5Q29udGVudFZhbGlkYXRvci52YWxpZGF0ZUFuZFNhbml0aXplKGNvbnRlbnQpO1xuICAgICAgaWYgKCFzZWN1cml0eVJlc3VsdC5pc1ZhbGlkICYmIHNlY3VyaXR5UmVzdWx0LnNldmVyaXR5ID09PSAnY3JpdGljYWwnKSB7XG4gICAgICAgIHRocm93IERvd25sb2FkRXJyb3Iuc2VjdXJpdHlFcnJvcihcbiAgICAgICAgICBgQ3JpdGljYWwgc2VjdXJpdHkgdGhyZWF0IGRldGVjdGVkOiAke3NlY3VyaXR5UmVzdWx0LmRldGVjdGVkUGF0dGVybnM/LmpvaW4oJywgJyl9YFxuICAgICAgICApO1xuICAgICAgfVxuXG4gICAgICAvLyBTVEVQIDY6IFJ1biBjdXN0b20gdmFsaWRhdG9yIGlmIHByb3ZpZGVkXG4gICAgICBpZiAob3B0aW9ucy52YWxpZGF0b3IpIHtcbiAgICAgICAgbG9nZ2VyLmRlYnVnKCdSdW5uaW5nIGN1c3RvbSBjb250ZW50IHZhbGlkYXRpb24nKTtcbiAgICAgICAgY29uc3QgdmFsaWRhdGlvblJlc3VsdCA9IGF3YWl0IG9wdGlvbnMudmFsaWRhdG9yKGNvbnRlbnQpO1xuICAgICAgICBpZiAoIXZhbGlkYXRpb25SZXN1bHQuaXNWYWxpZCkge1xuICAgICAgICAgIHRocm93IERvd25sb2FkRXJyb3IudmFsaWRhdGlvbkVycm9yKFxuICAgICAgICAgICAgdmFsaWRhdGlvblJlc3VsdC5lcnJvck1lc3NhZ2UgfHwgJ0NvbnRlbnQgdmFsaWRhdGlvbiBmYWlsZWQnXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBsb2dnZXIuZGVidWcoYENvbnRlbnQgdmFsaWRhdGlvbiBwYXNzZWQgKCR7Y29udGVudC5sZW5ndGh9IGJ5dGVzKWApO1xuICAgICAgcmV0dXJuIHNlY3VyaXR5UmVzdWx0LnNhbml0aXplZENvbnRlbnQgfHwgY29udGVudDtcblxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBEb3dubG9hZEVycm9yKSB7XG4gICAgICAgIHRocm93IGVycm9yO1xuICAgICAgfVxuICAgICAgdGhyb3cgRG93bmxvYWRFcnJvci5uZXR3b3JrRXJyb3IoXG4gICAgICAgIGBGYWlsZWQgdG8gZG93bmxvYWQgY29udGVudCBmcm9tICR7dXJsfTogJHtlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcil9YCxcbiAgICAgICAgZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yIDogdW5kZWZpbmVkXG4gICAgICApO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBEb3dubG9hZCBsYXJnZSBmaWxlcyB1c2luZyBzdHJlYW1pbmcgd2l0aCBjaHVuay1sZXZlbCB2YWxpZGF0aW9uXG4gICAqIFxuICAgKiBAcGFyYW0gdXJsIC0gVVJMIHRvIGRvd25sb2FkIGZyb21cbiAgICogQHBhcmFtIGRlc3RpbmF0aW9uUGF0aCAtIExvY2FsIGZpbGUgcGF0aCB0byBzYXZlIHRvXG4gICAqIEBwYXJhbSBvcHRpb25zIC0gU3RyZWFtaW5nIGRvd25sb2FkIG9wdGlvbnNcbiAgICovXG4gIGFzeW5jIGRvd25sb2FkU3RyZWFtKFxuICAgIHVybDogc3RyaW5nLFxuICAgIGRlc3RpbmF0aW9uUGF0aDogc3RyaW5nLFxuICAgIG9wdGlvbnM6IFN0cmVhbURvd25sb2FkT3B0aW9ucyA9IHt9XG4gICk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IHN0YXJ0VGltZSA9IERhdGUubm93KCk7XG4gICAgY29uc3QgbWF4U2l6ZSA9IG9wdGlvbnMubWF4U2l6ZSB8fCB0aGlzLmRlZmF1bHRNYXhTaXplO1xuICAgIGNvbnN0IHRpbWVvdXQgPSBvcHRpb25zLnRpbWVvdXQgfHwgdGhpcy5kZWZhdWx0VGltZW91dDtcblxuICAgIGxvZ2dlci5kZWJ1ZyhgU3RhcnRpbmcgc3RyZWFtaW5nIGRvd25sb2FkIGZyb20gJHt1cmx9IHRvICR7ZGVzdGluYXRpb25QYXRofWApO1xuXG4gICAgdHJ5IHtcbiAgICAgIC8vIFNFQ1VSSVRZOiBDaGVjayByYXRlIGxpbWl0cyBiZWZvcmUgZG93bmxvYWRcbiAgICAgIGF3YWl0IHRoaXMuY2hlY2tSYXRlTGltaXQodXJsKTtcblxuICAgICAgLy8gU0VDVVJJVFk6IFZhbGlkYXRlIFVSTCBhbmQgZGVzdGluYXRpb24gcGF0aFxuICAgICAgdGhpcy52YWxpZGF0ZVVybCh1cmwpO1xuICAgICAgY29uc3QgdmFsaWRhdGVkUGF0aCA9IGF3YWl0IHRoaXMudmFsaWRhdGVEZXN0aW5hdGlvblBhdGgoZGVzdGluYXRpb25QYXRoKTtcblxuICAgICAgLy8gR2VuZXJhdGUgdGVtcG9yYXJ5IGZpbGUgcGF0aCBmb3IgYXRvbWljIG9wZXJhdGlvblxuICAgICAgY29uc3QgdGVtcFBhdGggPSBhd2FpdCB0aGlzLmdldFRlbXBGaWxlUGF0aCh2YWxpZGF0ZWRQYXRoKTtcblxuICAgICAgbGV0IGRvd25sb2FkZWRTaXplID0gMDtcbiAgICAgIGxldCB0aW1lb3V0SGFuZGxlOiBOb2RlSlMuVGltZW91dCB8IHVuZGVmaW5lZDtcblxuICAgICAgLy8gQ3JlYXRlIGFib3J0IGNvbnRyb2xsZXIgZm9yIHRpbWVvdXQgaGFuZGxpbmdcbiAgICAgIGNvbnN0IGFib3J0Q29udHJvbGxlciA9IG5ldyBBYm9ydENvbnRyb2xsZXIoKTtcbiAgICAgIHRpbWVvdXRIYW5kbGUgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgYWJvcnRDb250cm9sbGVyLmFib3J0KCk7XG4gICAgICB9LCB0aW1lb3V0KTtcblxuICAgICAgdHJ5IHtcbiAgICAgICAgLy8gU0VDVVJJVFk6IEZldGNoIHdpdGggYWJvcnQgc2lnbmFsIGZvciB0aW1lb3V0XG4gICAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2godXJsLCB7XG4gICAgICAgICAgc2lnbmFsOiBhYm9ydENvbnRyb2xsZXIuc2lnbmFsLFxuICAgICAgICAgIGhlYWRlcnM6IG9wdGlvbnMuaGVhZGVyc1xuICAgICAgICB9KTtcblxuICAgICAgICBpZiAoIXJlc3BvbnNlLm9rKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBIVFRQICR7cmVzcG9uc2Uuc3RhdHVzfTogJHtyZXNwb25zZS5zdGF0dXNUZXh0fWApO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCFyZXNwb25zZS5ib2R5KSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdSZXNwb25zZSBib2R5IGlzIG51bGwnKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEVuc3VyZSB0ZW1wIGRpcmVjdG9yeSBleGlzdHNcbiAgICAgICAgYXdhaXQgZnMubWtkaXIocGF0aC5kaXJuYW1lKHRlbXBQYXRoKSwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG5cbiAgICAgICAgLy8gQ3JlYXRlIHdyaXRlIHN0cmVhbSB0byB0ZW1wb3JhcnkgZmlsZVxuICAgICAgICBjb25zdCB3cml0ZVN0cmVhbSA9IGNyZWF0ZVdyaXRlU3RyZWFtKHRlbXBQYXRoKTtcblxuICAgICAgICAvLyBDcmVhdGUgYSB0cmFuc2Zvcm0gc3RyZWFtIGZvciB2YWxpZGF0aW9uIGFuZCBzaXplIGNoZWNraW5nXG4gICAgICAgIGNvbnN0IHZhbGlkYXRpb25TdHJlYW0gPSBuZXcgUmVhZGFibGUoe1xuICAgICAgICAgIGFzeW5jIHJlYWQoKSB7XG4gICAgICAgICAgICAvLyBUaGlzIHN0cmVhbSB3aWxsIGJlIGZlZCBieSB0aGUgcGlwZWxpbmVcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICAgIC8vIFNldCB1cCBjaHVuayB2YWxpZGF0aW9uIGFuZCBzaXplIGNoZWNraW5nXG4gICAgICAgIGNvbnN0IHJlYWRlciA9IHJlc3BvbnNlLmJvZHkuZ2V0UmVhZGVyKCk7XG4gICAgICAgIGNvbnN0IHB1bXAgPSBhc3luYyAoKSA9PiB7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIHdoaWxlICh0cnVlKSB7XG4gICAgICAgICAgICAgIGNvbnN0IHsgZG9uZSwgdmFsdWUgfSA9IGF3YWl0IHJlYWRlci5yZWFkKCk7XG4gICAgICAgICAgICAgIGlmIChkb25lKSBicmVhaztcblxuICAgICAgICAgICAgICAvLyBTRUNVUklUWTogQ2hlY2sgc2l6ZSBsaW1pdFxuICAgICAgICAgICAgICBkb3dubG9hZGVkU2l6ZSArPSB2YWx1ZS5sZW5ndGg7XG4gICAgICAgICAgICAgIGlmIChkb3dubG9hZGVkU2l6ZSA+IG1heFNpemUpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBEb3dubG9hZEVycm9yLnNlY3VyaXR5RXJyb3IoXG4gICAgICAgICAgICAgICAgICBgRmlsZSBzaXplIGV4Y2VlZHMgbGltaXQ6ICR7ZG93bmxvYWRlZFNpemV9ID4gJHttYXhTaXplfSBieXRlc2BcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgLy8gU0VDVVJJVFk6IFJ1biBjaHVuayB2YWxpZGF0b3IgaWYgcHJvdmlkZWRcbiAgICAgICAgICAgICAgaWYgKG9wdGlvbnMuc3RyZWFtVmFsaWRhdG9yICYmICFvcHRpb25zLnN0cmVhbVZhbGlkYXRvcih2YWx1ZSkpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBEb3dubG9hZEVycm9yLnZhbGlkYXRpb25FcnJvcignQ2h1bmsgdmFsaWRhdGlvbiBmYWlsZWQnKTtcbiAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgIHZhbGlkYXRpb25TdHJlYW0ucHVzaCh2YWx1ZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YWxpZGF0aW9uU3RyZWFtLnB1c2gobnVsbCk7IC8vIEVuZCBzdHJlYW1cbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgICAgdmFsaWRhdGlvblN0cmVhbS5kZXN0cm95KGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvciA6IG5ldyBFcnJvcihTdHJpbmcoZXJyb3IpKSk7XG4gICAgICAgICAgfVxuICAgICAgICB9O1xuXG4gICAgICAgIC8vIFN0YXJ0IHRoZSBwdW1wIGFuZCBwaXBlbGluZSBjb25jdXJyZW50bHlcbiAgICAgICAgY29uc3QgW3B1bXBSZXN1bHRdID0gYXdhaXQgUHJvbWlzZS5hbGwoW1xuICAgICAgICAgIHB1bXAoKSxcbiAgICAgICAgICBwaXBlbGluZSh2YWxpZGF0aW9uU3RyZWFtLCB3cml0ZVN0cmVhbSlcbiAgICAgICAgXSk7XG5cbiAgICAgICAgLy8gQ2xlYXIgdGltZW91dFxuICAgICAgICBpZiAodGltZW91dEhhbmRsZSkge1xuICAgICAgICAgIGNsZWFyVGltZW91dCh0aW1lb3V0SGFuZGxlKTtcbiAgICAgICAgICB0aW1lb3V0SGFuZGxlID0gdW5kZWZpbmVkO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gU0VDVVJJVFk6IEF0b21pYyByZW5hbWUgdG8gZmluYWwgZGVzdGluYXRpb25cbiAgICAgICAgYXdhaXQgZnMucmVuYW1lKHRlbXBQYXRoLCB2YWxpZGF0ZWRQYXRoKTtcblxuICAgICAgICBjb25zdCBkdXJhdGlvbiA9IERhdGUubm93KCkgLSBzdGFydFRpbWU7XG4gICAgICAgIGxvZ2dlci5pbmZvKGBTdHJlYW1pbmcgZG93bmxvYWQgY29tcGxldGVkOiAke2Rlc3RpbmF0aW9uUGF0aH0gKCR7ZG93bmxvYWRlZFNpemV9IGJ5dGVzLCAke2R1cmF0aW9ufW1zKWApO1xuXG4gICAgICAgIC8vIExvZyBzdWNjZXNzZnVsIHN0cmVhbWluZyBkb3dubG9hZFxuICAgICAgICBTZWN1cml0eU1vbml0b3IubG9nU2VjdXJpdHlFdmVudCh7XG4gICAgICAgICAgdHlwZTogJ0ZJTEVfQ09QSUVEJyxcbiAgICAgICAgICBzZXZlcml0eTogJ0xPVycsXG4gICAgICAgICAgc291cmNlOiAnc2VjdXJlX2Rvd25sb2FkZXInLFxuICAgICAgICAgIGRldGFpbHM6IGBTdHJlYW1lZCAke2Rvd25sb2FkZWRTaXplfSBieXRlcyBmcm9tICR7dXJsfSB0byAke2Rlc3RpbmF0aW9uUGF0aH1gLFxuICAgICAgICAgIG1ldGFkYXRhOiB7XG4gICAgICAgICAgICB1cmwsXG4gICAgICAgICAgICBkZXN0aW5hdGlvblBhdGgsXG4gICAgICAgICAgICBjb250ZW50TGVuZ3RoOiBkb3dubG9hZGVkU2l6ZSxcbiAgICAgICAgICAgIGR1cmF0aW9uXG4gICAgICAgICAgfVxuICAgICAgICB9KTtcblxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgLy8gU0VDVVJJVFk6IEd1YXJhbnRlZWQgY2xlYW51cCBvZiB0ZW1wb3JhcnkgZmlsZVxuICAgICAgICB0cnkge1xuICAgICAgICAgIGF3YWl0IGZzLnVubGluayh0ZW1wUGF0aCk7XG4gICAgICAgICAgbG9nZ2VyLmRlYnVnKGBDbGVhbmVkIHVwIHRlbXAgZmlsZTogJHt0ZW1wUGF0aH1gKTtcbiAgICAgICAgfSBjYXRjaCAoY2xlYW51cEVycm9yKSB7XG4gICAgICAgICAgbG9nZ2VyLndhcm4oYEZhaWxlZCB0byBjbGVhbiB1cCB0ZW1wIGZpbGUgJHt0ZW1wUGF0aH06ICR7Y2xlYW51cEVycm9yfWApO1xuICAgICAgICB9XG4gICAgICAgIHRocm93IGVycm9yO1xuICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgaWYgKHRpbWVvdXRIYW5kbGUpIHtcbiAgICAgICAgICBjbGVhclRpbWVvdXQodGltZW91dEhhbmRsZSk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBjb25zdCBkdXJhdGlvbiA9IERhdGUubm93KCkgLSBzdGFydFRpbWU7XG4gICAgICBsb2dnZXIuZXJyb3IoYFN0cmVhbWluZyBkb3dubG9hZCBmYWlsZWQ6ICR7ZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpfWApO1xuXG4gICAgICAvLyBMb2cgZmFpbGVkIHN0cmVhbWluZyBkb3dubG9hZFxuICAgICAgU2VjdXJpdHlNb25pdG9yLmxvZ1NlY3VyaXR5RXZlbnQoe1xuICAgICAgICB0eXBlOiAnUEFUSF9UUkFWRVJTQUxfQVRURU1QVCcsXG4gICAgICAgIHNldmVyaXR5OiAnTUVESVVNJyxcbiAgICAgICAgc291cmNlOiAnc2VjdXJlX2Rvd25sb2FkZXInLFxuICAgICAgICBkZXRhaWxzOiBgU3RyZWFtaW5nIGRvd25sb2FkIGZhaWxlZDogJHtlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcil9YCxcbiAgICAgICAgbWV0YWRhdGE6IHtcbiAgICAgICAgICB1cmwsXG4gICAgICAgICAgZGVzdGluYXRpb25QYXRoLFxuICAgICAgICAgIGR1cmF0aW9uLFxuICAgICAgICAgIGVycm9yVHlwZTogZXJyb3IgaW5zdGFuY2VvZiBEb3dubG9hZEVycm9yID8gZXJyb3IuY29kZSA6ICdVTktOT1dOJ1xuICAgICAgICB9XG4gICAgICB9KTtcblxuICAgICAgaWYgKGVycm9yIGluc3RhbmNlb2YgRXJyb3IgJiYgZXJyb3IubmFtZSA9PT0gJ0Fib3J0RXJyb3InKSB7XG4gICAgICAgIHRocm93IERvd25sb2FkRXJyb3IudGltZW91dEVycm9yKGBEb3dubG9hZCB0aW1lZCBvdXQgYWZ0ZXIgJHt0aW1lb3V0fW1zYCk7XG4gICAgICB9XG5cbiAgICAgIGlmIChlcnJvciBpbnN0YW5jZW9mIERvd25sb2FkRXJyb3IpIHtcbiAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICB9XG5cbiAgICAgIHRocm93IERvd25sb2FkRXJyb3IubmV0d29ya0Vycm9yKFxuICAgICAgICBgU3RyZWFtaW5nIGRvd25sb2FkIGZhaWxlZDogJHtlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcil9YCxcbiAgICAgICAgZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yIDogdW5kZWZpbmVkXG4gICAgICApO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZSBVUkwgZm9ybWF0IGFuZCBzZWN1cml0eSB3aXRoIFVuaWNvZGUgbm9ybWFsaXphdGlvblxuICAgKi9cbiAgcHJpdmF0ZSB2YWxpZGF0ZVVybCh1cmw6IHN0cmluZyk6IHZvaWQge1xuICAgIGlmICghdXJsIHx8IHR5cGVvZiB1cmwgIT09ICdzdHJpbmcnKSB7XG4gICAgICB0aHJvdyBEb3dubG9hZEVycm9yLnZhbGlkYXRpb25FcnJvcignVVJMIG11c3QgYmUgYSBub24tZW1wdHkgc3RyaW5nJyk7XG4gICAgfVxuXG4gICAgLy8gU0VDVVJJVFkgRklYOiBETUNQLVNFQy0wMDQgLSBVbmljb2RlIG5vcm1hbGl6YXRpb24gb24gdXNlciBpbnB1dFxuICAgIGNvbnN0IHVuaWNvZGVWYWxpZGF0aW9uID0gVW5pY29kZVZhbGlkYXRvci5ub3JtYWxpemUodXJsKTtcbiAgICBjb25zdCBub3JtYWxpemVkVXJsID0gdW5pY29kZVZhbGlkYXRpb24ubm9ybWFsaXplZENvbnRlbnQ7XG4gICAgXG4gICAgaWYgKCF1bmljb2RlVmFsaWRhdGlvbi5pc1ZhbGlkKSB7XG4gICAgICBTZWN1cml0eU1vbml0b3IubG9nU2VjdXJpdHlFdmVudCh7XG4gICAgICAgIHR5cGU6ICdVTklDT0RFX1ZBTElEQVRJT05fRVJST1InLFxuICAgICAgICBzZXZlcml0eTogJ01FRElVTScsXG4gICAgICAgIHNvdXJjZTogJ3NlY3VyZV9kb3dubG9hZGVyJyxcbiAgICAgICAgZGV0YWlsczogYFVSTCBjb250YWlucyBzdXNwaWNpb3VzIFVuaWNvZGUgcGF0dGVybnM6ICR7dW5pY29kZVZhbGlkYXRpb24uZGV0ZWN0ZWRJc3N1ZXM/LmpvaW4oJywgJyl9YCxcbiAgICAgICAgbWV0YWRhdGE6IHsgb3JpZ2luYWxVcmw6IHVybCwgbm9ybWFsaXplZFVybCB9XG4gICAgICB9KTtcbiAgICB9XG4gICAgXG4gICAgLy8gVXNlIG5vcm1hbGl6ZWQgVVJMIGZvciBmdXJ0aGVyIHZhbGlkYXRpb25cbiAgICB1cmwgPSBub3JtYWxpemVkVXJsO1xuXG4gICAgbGV0IHBhcnNlZFVybDogVVJMO1xuICAgIHRyeSB7XG4gICAgICBwYXJzZWRVcmwgPSBuZXcgVVJMKHVybCk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHRocm93IERvd25sb2FkRXJyb3IudmFsaWRhdGlvbkVycm9yKGBJbnZhbGlkIFVSTCBmb3JtYXQ6ICR7dXJsfWApO1xuICAgIH1cblxuICAgIC8vIFNFQ1VSSVRZOiBPbmx5IGFsbG93IEhUVFBTIGFuZCBIVFRQIHByb3RvY29sc1xuICAgIGlmICghWydodHRwczonLCAnaHR0cDonXS5pbmNsdWRlcyhwYXJzZWRVcmwucHJvdG9jb2wpKSB7XG4gICAgICB0aHJvdyBEb3dubG9hZEVycm9yLnNlY3VyaXR5RXJyb3IoYFVuc3VwcG9ydGVkIHByb3RvY29sOiAke3BhcnNlZFVybC5wcm90b2NvbH0uIE9ubHkgSFRUUC9IVFRQUyBhbGxvd2VkLmApO1xuICAgIH1cblxuICAgIC8vIFNFQ1VSSVRZOiBQcmV2ZW50IHJlcXVlc3RzIHRvIGxvY2FsaG9zdC9wcml2YXRlIG5ldHdvcmtzXG4gICAgY29uc3QgaG9zdG5hbWUgPSBwYXJzZWRVcmwuaG9zdG5hbWUudG9Mb3dlckNhc2UoKTtcbiAgICBpZiAoaG9zdG5hbWUgPT09ICdsb2NhbGhvc3QnIHx8IGhvc3RuYW1lID09PSAnMTI3LjAuMC4xJyB8fCBob3N0bmFtZSA9PT0gJzo6MScpIHtcbiAgICAgIHRocm93IERvd25sb2FkRXJyb3Iuc2VjdXJpdHlFcnJvcignRG93bmxvYWRzIGZyb20gbG9jYWxob3N0IGFyZSBub3QgYWxsb3dlZCcpO1xuICAgIH1cblxuICAgIC8vIFNFQ1VSSVRZOiBDaGVjayBmb3IgcHJpdmF0ZSBJUCByYW5nZXMgKGJhc2ljIHByb3RlY3Rpb24pXG4gICAgaWYgKGhvc3RuYW1lLnN0YXJ0c1dpdGgoJzE5Mi4xNjguJykgfHwgaG9zdG5hbWUuc3RhcnRzV2l0aCgnMTAuJykgfHwgaG9zdG5hbWUuc3RhcnRzV2l0aCgnMTcyLicpKSB7XG4gICAgICB0aHJvdyBEb3dubG9hZEVycm9yLnNlY3VyaXR5RXJyb3IoJ0Rvd25sb2FkcyBmcm9tIHByaXZhdGUgSVAgcmFuZ2VzIGFyZSBub3QgYWxsb3dlZCcpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZSBkZXN0aW5hdGlvbiBwYXRoIGZvciBzZWN1cml0eVxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyB2YWxpZGF0ZURlc3RpbmF0aW9uUGF0aChmaWxlUGF0aDogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICB0cnkge1xuICAgICAgLy8gVXNlIGV4aXN0aW5nIFBhdGhWYWxpZGF0b3IgZm9yIGNvbXByZWhlbnNpdmUgcGF0aCB2YWxpZGF0aW9uXG4gICAgICByZXR1cm4gYXdhaXQgUGF0aFZhbGlkYXRvci52YWxpZGF0ZVBlcnNvbmFQYXRoKGZpbGVQYXRoKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgdGhyb3cgRG93bmxvYWRFcnJvci5zZWN1cml0eUVycm9yKFxuICAgICAgICBgSW52YWxpZCBkZXN0aW5hdGlvbiBwYXRoOiAke2Vycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKX1gXG4gICAgICApO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBGZXRjaCBjb250ZW50IHdpdGggc2l6ZSBhbmQgdGltZW91dCBsaW1pdHNcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgZmV0Y2hXaXRoTGltaXRzKFxuICAgIHVybDogc3RyaW5nLFxuICAgIG1heFNpemU6IG51bWJlcixcbiAgICB0aW1lb3V0OiBudW1iZXIsXG4gICAgaGVhZGVycz86IFJlY29yZDxzdHJpbmcsIHN0cmluZz5cbiAgKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBjb25zdCBhYm9ydENvbnRyb2xsZXIgPSBuZXcgQWJvcnRDb250cm9sbGVyKCk7XG4gICAgY29uc3QgdGltZW91dEhhbmRsZSA9IHNldFRpbWVvdXQoKCkgPT4gYWJvcnRDb250cm9sbGVyLmFib3J0KCksIHRpbWVvdXQpO1xuXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2godXJsLCB7XG4gICAgICAgIHNpZ25hbDogYWJvcnRDb250cm9sbGVyLnNpZ25hbCxcbiAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgICdVc2VyLUFnZW50JzogJ0RvbGxob3VzZU1DUC1TZWN1cmVEb3dubG9hZGVyLzEuMCcsXG4gICAgICAgICAgLi4uaGVhZGVyc1xuICAgICAgICB9XG4gICAgICB9KTtcblxuICAgICAgaWYgKCFyZXNwb25zZS5vaykge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEhUVFAgJHtyZXNwb25zZS5zdGF0dXN9OiAke3Jlc3BvbnNlLnN0YXR1c1RleHR9YCk7XG4gICAgICB9XG5cbiAgICAgIC8vIFNFQ1VSSVRZOiBDaGVjayBDb250ZW50LUxlbmd0aCBoZWFkZXIgaWYgYXZhaWxhYmxlXG4gICAgICBjb25zdCBjb250ZW50TGVuZ3RoID0gcmVzcG9uc2UuaGVhZGVycy5nZXQoJ2NvbnRlbnQtbGVuZ3RoJyk7XG4gICAgICBpZiAoY29udGVudExlbmd0aCAmJiBwYXJzZUludChjb250ZW50TGVuZ3RoLCAxMCkgPiBtYXhTaXplKSB7XG4gICAgICAgIHRocm93IERvd25sb2FkRXJyb3Iuc2VjdXJpdHlFcnJvcihcbiAgICAgICAgICBgQ29udGVudCBzaXplICR7Y29udGVudExlbmd0aH0gZXhjZWVkcyBsaW1pdCBvZiAke21heFNpemV9IGJ5dGVzYFxuICAgICAgICApO1xuICAgICAgfVxuXG4gICAgICAvLyBSZWFkIGNvbnRlbnQgd2l0aCBzaXplIGNoZWNraW5nXG4gICAgICBjb25zdCBjaHVua3M6IFVpbnQ4QXJyYXlbXSA9IFtdO1xuICAgICAgbGV0IHRvdGFsU2l6ZSA9IDA7XG5cbiAgICAgIGlmICghcmVzcG9uc2UuYm9keSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1Jlc3BvbnNlIGJvZHkgaXMgbnVsbCcpO1xuICAgICAgfVxuXG4gICAgICBjb25zdCByZWFkZXIgPSByZXNwb25zZS5ib2R5LmdldFJlYWRlcigpO1xuICAgICAgdHJ5IHtcbiAgICAgICAgd2hpbGUgKHRydWUpIHtcbiAgICAgICAgICBjb25zdCB7IGRvbmUsIHZhbHVlIH0gPSBhd2FpdCByZWFkZXIucmVhZCgpO1xuICAgICAgICAgIGlmIChkb25lKSBicmVhaztcblxuICAgICAgICAgIHRvdGFsU2l6ZSArPSB2YWx1ZS5sZW5ndGg7XG4gICAgICAgICAgaWYgKHRvdGFsU2l6ZSA+IG1heFNpemUpIHtcbiAgICAgICAgICAgIHRocm93IERvd25sb2FkRXJyb3Iuc2VjdXJpdHlFcnJvcihcbiAgICAgICAgICAgICAgYENvbnRlbnQgc2l6ZSAke3RvdGFsU2l6ZX0gZXhjZWVkcyBsaW1pdCBvZiAke21heFNpemV9IGJ5dGVzYFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBjaHVua3MucHVzaCh2YWx1ZSk7XG4gICAgICAgIH1cbiAgICAgIH0gZmluYWxseSB7XG4gICAgICAgIHJlYWRlci5yZWxlYXNlTG9jaygpO1xuICAgICAgfVxuXG4gICAgICAvLyBDb21iaW5lIGNodW5rcyBhbmQgZGVjb2RlXG4gICAgICBjb25zdCB0b3RhbExlbmd0aCA9IGNodW5rcy5yZWR1Y2UoKHN1bSwgY2h1bmspID0+IHN1bSArIGNodW5rLmxlbmd0aCwgMCk7XG4gICAgICBjb25zdCBjb21iaW5lZCA9IG5ldyBVaW50OEFycmF5KHRvdGFsTGVuZ3RoKTtcbiAgICAgIGxldCBvZmZzZXQgPSAwO1xuICAgICAgZm9yIChjb25zdCBjaHVuayBvZiBjaHVua3MpIHtcbiAgICAgICAgY29tYmluZWQuc2V0KGNodW5rLCBvZmZzZXQpO1xuICAgICAgICBvZmZzZXQgKz0gY2h1bmsubGVuZ3RoO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gbmV3IFRleHREZWNvZGVyKCd1dGYtOCcpLmRlY29kZShjb21iaW5lZCk7XG5cbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgaWYgKGVycm9yIGluc3RhbmNlb2YgRXJyb3IgJiYgZXJyb3IubmFtZSA9PT0gJ0Fib3J0RXJyb3InKSB7XG4gICAgICAgIHRocm93IERvd25sb2FkRXJyb3IudGltZW91dEVycm9yKGBSZXF1ZXN0IHRpbWVkIG91dCBhZnRlciAke3RpbWVvdXR9bXNgKTtcbiAgICAgIH1cbiAgICAgIHRocm93IGVycm9yO1xuICAgIH0gZmluYWxseSB7XG4gICAgICBjbGVhclRpbWVvdXQodGltZW91dEhhbmRsZSk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFZhbGlkYXRlIGNvbnRlbnQgdHlwZSBpZiBzcGVjaWZpZWRcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgdmFsaWRhdGVDb250ZW50VHlwZShjb250ZW50OiBzdHJpbmcsIGV4cGVjdGVkVHlwZTogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgLy8gQmFzaWMgY29udGVudCB0eXBlIHZhbGlkYXRpb24gYmFzZWQgb24gY29udGVudCBhbmFseXNpc1xuICAgIHN3aXRjaCAoZXhwZWN0ZWRUeXBlLnRvTG93ZXJDYXNlKCkpIHtcbiAgICAgIGNhc2UgJ2pzb24nOlxuICAgICAgICB0cnkge1xuICAgICAgICAgIEpTT04ucGFyc2UoY29udGVudCk7XG4gICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgIHRocm93IERvd25sb2FkRXJyb3IudmFsaWRhdGlvbkVycm9yKCdDb250ZW50IGlzIG5vdCB2YWxpZCBKU09OJyk7XG4gICAgICAgIH1cbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlICd5YW1sJzpcbiAgICAgIGNhc2UgJ3ltbCc6XG4gICAgICAgIC8vIFVzZSBleGlzdGluZyBZQU1MIHZhbGlkYXRpb25cbiAgICAgICAgaWYgKCFTZWN1cml0eUNvbnRlbnRWYWxpZGF0b3IudmFsaWRhdGVZYW1sQ29udGVudChjb250ZW50KSkge1xuICAgICAgICAgIHRocm93IERvd25sb2FkRXJyb3IudmFsaWRhdGlvbkVycm9yKCdDb250ZW50IGlzIG5vdCB2YWxpZCBZQU1MJyk7XG4gICAgICAgIH1cbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlICdtYXJrZG93bic6XG4gICAgICBjYXNlICdtZCc6XG4gICAgICAgIC8vIEJhc2ljIG1hcmtkb3duIHZhbGlkYXRpb24gKGNoZWNrIGZvciBmcm9udG1hdHRlciBmb3JtYXQpXG4gICAgICAgIGlmIChjb250ZW50LnN0YXJ0c1dpdGgoJy0tLScpKSB7XG4gICAgICAgICAgY29uc3QgZnJvbnRtYXR0ZXJFbmQgPSBjb250ZW50LmluZGV4T2YoJ1xcbi0tLVxcbicsIDMpO1xuICAgICAgICAgIGlmIChmcm9udG1hdHRlckVuZCA9PT0gLTEpIHtcbiAgICAgICAgICAgIHRocm93IERvd25sb2FkRXJyb3IudmFsaWRhdGlvbkVycm9yKCdJbnZhbGlkIG1hcmtkb3duIGZyb250bWF0dGVyIGZvcm1hdCcpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBicmVhaztcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIGxvZ2dlci5kZWJ1ZyhgTm8gc3BlY2lmaWMgdmFsaWRhdGlvbiBmb3IgY29udGVudCB0eXBlOiAke2V4cGVjdGVkVHlwZX1gKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQXRvbWljIGZpbGUgd3JpdGUgdXNpbmcgRmlsZUxvY2tNYW5hZ2VyXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGF0b21pY1dyaXRlRmlsZShmaWxlUGF0aDogc3RyaW5nLCBjb250ZW50OiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCByZXNvdXJjZSA9IGBkb3dubG9hZDoke2ZpbGVQYXRofWA7XG4gICAgXG4gICAgYXdhaXQgRmlsZUxvY2tNYW5hZ2VyLndpdGhMb2NrKHJlc291cmNlLCBhc3luYyAoKSA9PiB7XG4gICAgICAvLyBFbnN1cmUgZGlyZWN0b3J5IGV4aXN0c1xuICAgICAgYXdhaXQgZnMubWtkaXIocGF0aC5kaXJuYW1lKGZpbGVQYXRoKSwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gICAgICBcbiAgICAgIC8vIFVzZSBGaWxlTG9ja01hbmFnZXIncyBhdG9taWMgd3JpdGVcbiAgICAgIGF3YWl0IEZpbGVMb2NrTWFuYWdlci5hdG9taWNXcml0ZUZpbGUoZmlsZVBhdGgsIGNvbnRlbnQsIHsgZW5jb2Rpbmc6ICd1dGYtOCcgfSk7XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogRGlyZWN0IGZpbGUgd3JpdGUgKG5vbi1hdG9taWMsIGZvciB3aGVuIGF0b21pYyBpcyBkaXNhYmxlZClcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgZGlyZWN0V3JpdGVGaWxlKGZpbGVQYXRoOiBzdHJpbmcsIGNvbnRlbnQ6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgIC8vIEVuc3VyZSBkaXJlY3RvcnkgZXhpc3RzXG4gICAgYXdhaXQgZnMubWtkaXIocGF0aC5kaXJuYW1lKGZpbGVQYXRoKSwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gICAgXG4gICAgLy8gRGlyZWN0IHdyaXRlXG4gICAgYXdhaXQgZnMud3JpdGVGaWxlKGZpbGVQYXRoLCBjb250ZW50LCAndXRmLTgnKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZW5lcmF0ZSB0ZW1wb3JhcnkgZmlsZSBwYXRoIGZvciBhdG9taWMgb3BlcmF0aW9uc1xuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBnZXRUZW1wRmlsZVBhdGgob3JpZ2luYWxQYXRoOiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIGNvbnN0IGRpciA9IHBhdGguZGlybmFtZShvcmlnaW5hbFBhdGgpO1xuICAgIGNvbnN0IGJhc2VuYW1lID0gcGF0aC5iYXNlbmFtZShvcmlnaW5hbFBhdGgpO1xuICAgIGNvbnN0IHJhbmRvbSA9IHJhbmRvbUJ5dGVzKDgpLnRvU3RyaW5nKCdoZXgnKTtcbiAgICBjb25zdCB0ZW1wRGlyID0gcGF0aC5qb2luKGRpciwgdGhpcy50ZW1wRGlyKTtcbiAgICBcbiAgICAvLyBFbnN1cmUgdGVtcCBkaXJlY3RvcnkgZXhpc3RzXG4gICAgYXdhaXQgZnMubWtkaXIodGVtcERpciwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gICAgXG4gICAgcmV0dXJuIHBhdGguam9pbih0ZW1wRGlyLCBgJHtiYXNlbmFtZX0uJHtyYW5kb219LnRtcGApO1xuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrIHJhdGUgbGltaXRzIGZvciBkb3dubG9hZHNcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgY2hlY2tSYXRlTGltaXQodXJsOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAvLyBDaGVjayBnbG9iYWwgcmF0ZSBsaW1pdFxuICAgIGNvbnN0IGdsb2JhbFN0YXR1cyA9IHRoaXMuZ2xvYmFsUmF0ZUxpbWl0ZXIuY2hlY2tMaW1pdCgpO1xuICAgIGlmICghZ2xvYmFsU3RhdHVzLmFsbG93ZWQpIHtcbiAgICAgIFNlY3VyaXR5TW9uaXRvci5sb2dTZWN1cml0eUV2ZW50KHtcbiAgICAgICAgdHlwZTogJ1JBVEVfTElNSVRfRVhDRUVERUQnLFxuICAgICAgICBzZXZlcml0eTogJ01FRElVTScsXG4gICAgICAgIHNvdXJjZTogJ3NlY3VyZV9kb3dubG9hZGVyJyxcbiAgICAgICAgZGV0YWlsczogYEdsb2JhbCBkb3dubG9hZCByYXRlIGxpbWl0IGV4Y2VlZGVkLiBSZXRyeSBhZnRlciAke2dsb2JhbFN0YXR1cy5yZXRyeUFmdGVyTXN9bXNgLFxuICAgICAgICBtZXRhZGF0YTogeyB1cmwsIHJldHJ5QWZ0ZXJNczogZ2xvYmFsU3RhdHVzLnJldHJ5QWZ0ZXJNcyB9XG4gICAgICB9KTtcbiAgICAgIHRocm93IERvd25sb2FkRXJyb3Iuc2VjdXJpdHlFcnJvcihcbiAgICAgICAgYERvd25sb2FkIHJhdGUgbGltaXQgZXhjZWVkZWQuIFBsZWFzZSByZXRyeSBhZnRlciAke01hdGguY2VpbChnbG9iYWxTdGF0dXMucmV0cnlBZnRlck1zISAvIDEwMDApfSBzZWNvbmRzYFxuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyBDaGVjayBwZXItVVJMIHJhdGUgbGltaXRcbiAgICBjb25zdCBwYXJzZWRVcmwgPSBuZXcgVVJMKHVybCk7XG4gICAgY29uc3QgdXJsS2V5ID0gYCR7cGFyc2VkVXJsLmhvc3RuYW1lfToke3BhcnNlZFVybC5wb3J0IHx8IChwYXJzZWRVcmwucHJvdG9jb2wgPT09ICdodHRwczonID8gJzQ0MycgOiAnODAnKX1gO1xuICAgIFxuICAgIGlmICghdGhpcy51cmxSYXRlTGltaXRlcnMuaGFzKHVybEtleSkpIHtcbiAgICAgIHRoaXMudXJsUmF0ZUxpbWl0ZXJzLnNldCh1cmxLZXksIG5ldyBSYXRlTGltaXRlcih7XG4gICAgICAgIG1heFJlcXVlc3RzOiAxMCwgLy8gMTAgcmVxdWVzdHMgcGVyIGhvdXIgcGVyIFVSTFxuICAgICAgICB3aW5kb3dNczogNjAgKiA2MCAqIDEwMDAsXG4gICAgICAgIG1pbkRlbGF5TXM6IDUwMDAgLy8gNSBzZWNvbmQgbWluaW11bSBkZWxheSBiZXR3ZWVuIHJlcXVlc3RzIHRvIHNhbWUgVVJMXG4gICAgICB9KSk7XG4gICAgfVxuICAgIFxuICAgIGNvbnN0IHVybExpbWl0ZXIgPSB0aGlzLnVybFJhdGVMaW1pdGVycy5nZXQodXJsS2V5KSE7XG4gICAgY29uc3QgdXJsU3RhdHVzID0gdXJsTGltaXRlci5jaGVja0xpbWl0KCk7XG4gICAgaWYgKCF1cmxTdGF0dXMuYWxsb3dlZCkge1xuICAgICAgU2VjdXJpdHlNb25pdG9yLmxvZ1NlY3VyaXR5RXZlbnQoe1xuICAgICAgICB0eXBlOiAnUkFURV9MSU1JVF9FWENFRURFRCcsXG4gICAgICAgIHNldmVyaXR5OiAnTUVESVVNJyxcbiAgICAgICAgc291cmNlOiAnc2VjdXJlX2Rvd25sb2FkZXInLFxuICAgICAgICBkZXRhaWxzOiBgUGVyLVVSTCBkb3dubG9hZCByYXRlIGxpbWl0IGV4Y2VlZGVkIGZvciAke3VybEtleX0uIFJldHJ5IGFmdGVyICR7dXJsU3RhdHVzLnJldHJ5QWZ0ZXJNc31tc2AsXG4gICAgICAgIG1ldGFkYXRhOiB7IHVybCwgdXJsS2V5LCByZXRyeUFmdGVyTXM6IHVybFN0YXR1cy5yZXRyeUFmdGVyTXMgfVxuICAgICAgfSk7XG4gICAgICB0aHJvdyBEb3dubG9hZEVycm9yLnNlY3VyaXR5RXJyb3IoXG4gICAgICAgIGBUb28gbWFueSByZXF1ZXN0cyB0byAke3VybEtleX0uIFBsZWFzZSByZXRyeSBhZnRlciAke01hdGguY2VpbCh1cmxTdGF0dXMucmV0cnlBZnRlck1zISAvIDEwMDApfSBzZWNvbmRzYFxuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyBDb25zdW1lIHJhdGUgbGltaXQgdG9rZW5zXG4gICAgdGhpcy5nbG9iYWxSYXRlTGltaXRlci5jb25zdW1lVG9rZW4oKTtcbiAgICB1cmxMaW1pdGVyLmNvbnN1bWVUb2tlbigpO1xuICB9XG5cbiAgLyoqXG4gICAqIFZhbGlkYXRlIGNvbnRlbnQgY2hlY2tzdW0gZm9yIGludGVncml0eSB2ZXJpZmljYXRpb25cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgdmFsaWRhdGVDaGVja3N1bShjb250ZW50OiBzdHJpbmcsIGV4cGVjdGVkQ2hlY2tzdW06IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IG5vcm1hbGl6ZWRFeHBlY3RlZCA9IGV4cGVjdGVkQ2hlY2tzdW0udG9Mb3dlckNhc2UoKS50cmltKCk7XG4gICAgXG4gICAgLy8gVmFsaWRhdGUgY2hlY2tzdW0gZm9ybWF0IChTSEEtMjU2IHNob3VsZCBiZSA2NCBoZXggY2hhcmFjdGVycylcbiAgICBpZiAoIS9eW2EtZjAtOV17NjR9JC8udGVzdChub3JtYWxpemVkRXhwZWN0ZWQpKSB7XG4gICAgICB0aHJvdyBEb3dubG9hZEVycm9yLnZhbGlkYXRpb25FcnJvcignSW52YWxpZCBjaGVja3N1bSBmb3JtYXQuIEV4cGVjdGVkIFNIQS0yNTYgKDY0IGhleCBjaGFyYWN0ZXJzKScpO1xuICAgIH1cblxuICAgIGNvbnN0IGNvbnRlbnRCdWZmZXIgPSBCdWZmZXIuZnJvbShjb250ZW50LCAndXRmLTgnKTtcbiAgICBjb25zdCBhY3R1YWxDaGVja3N1bSA9IGNyZWF0ZUhhc2goJ3NoYTI1NicpLnVwZGF0ZShjb250ZW50QnVmZmVyKS5kaWdlc3QoJ2hleCcpO1xuICAgIFxuICAgIGlmIChhY3R1YWxDaGVja3N1bSAhPT0gbm9ybWFsaXplZEV4cGVjdGVkKSB7XG4gICAgICBTZWN1cml0eU1vbml0b3IubG9nU2VjdXJpdHlFdmVudCh7XG4gICAgICAgIHR5cGU6ICdDT05URU5UX0lOSkVDVElPTl9BVFRFTVBUJyxcbiAgICAgICAgc2V2ZXJpdHk6ICdISUdIJyxcbiAgICAgICAgc291cmNlOiAnc2VjdXJlX2Rvd25sb2FkZXInLFxuICAgICAgICBkZXRhaWxzOiBgQ2hlY2tzdW0gbWlzbWF0Y2ggZGV0ZWN0ZWQgLSBwb3NzaWJsZSBjb250ZW50IHRhbXBlcmluZ2AsXG4gICAgICAgIG1ldGFkYXRhOiB7IFxuICAgICAgICAgIGV4cGVjdGVkQ2hlY2tzdW06IG5vcm1hbGl6ZWRFeHBlY3RlZCxcbiAgICAgICAgICBhY3R1YWxDaGVja3N1bSxcbiAgICAgICAgICBjb250ZW50TGVuZ3RoOiBjb250ZW50Lmxlbmd0aFxuICAgICAgICB9XG4gICAgICB9KTtcbiAgICAgIHRocm93IERvd25sb2FkRXJyb3Iuc2VjdXJpdHlFcnJvcihcbiAgICAgICAgYENvbnRlbnQgY2hlY2tzdW0gdmVyaWZpY2F0aW9uIGZhaWxlZC4gRXhwZWN0ZWQ6ICR7bm9ybWFsaXplZEV4cGVjdGVkfSwgR290OiAke2FjdHVhbENoZWNrc3VtfWBcbiAgICAgICk7XG4gICAgfVxuXG4gICAgbG9nZ2VyLmRlYnVnKGBDaGVja3N1bSB2YWxpZGF0aW9uIHBhc3NlZDogJHthY3R1YWxDaGVja3N1bX1gKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGUgYSBjb250ZW50IHZhbGlkYXRvciB0aGF0IGNvbWJpbmVzIG11bHRpcGxlIHZhbGlkYXRvcnNcbiAgICovXG4gIHN0YXRpYyBjb21iaW5lVmFsaWRhdG9ycyguLi52YWxpZGF0b3JzOiBDb250ZW50VmFsaWRhdG9yRnVuY3Rpb25bXSk6IENvbnRlbnRWYWxpZGF0b3JGdW5jdGlvbiB7XG4gICAgcmV0dXJuIGFzeW5jIChjb250ZW50OiBzdHJpbmcpOiBQcm9taXNlPFZhbGlkYXRpb25SZXN1bHQ+ID0+IHtcbiAgICAgIGZvciAoY29uc3QgdmFsaWRhdG9yIG9mIHZhbGlkYXRvcnMpIHtcbiAgICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgdmFsaWRhdG9yKGNvbnRlbnQpO1xuICAgICAgICBpZiAoIXJlc3VsdC5pc1ZhbGlkKSB7XG4gICAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgcmV0dXJuIHsgaXNWYWxpZDogdHJ1ZSB9O1xuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlIGEgY29udGVudCB2YWxpZGF0b3IgZm9yIEpTT04gY29udGVudFxuICAgKi9cbiAgc3RhdGljIGpzb25WYWxpZGF0b3IoKTogQ29udGVudFZhbGlkYXRvckZ1bmN0aW9uIHtcbiAgICByZXR1cm4gYXN5bmMgKGNvbnRlbnQ6IHN0cmluZyk6IFByb21pc2U8VmFsaWRhdGlvblJlc3VsdD4gPT4ge1xuICAgICAgdHJ5IHtcbiAgICAgICAgSlNPTi5wYXJzZShjb250ZW50KTtcbiAgICAgICAgcmV0dXJuIHsgaXNWYWxpZDogdHJ1ZSB9O1xuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBpc1ZhbGlkOiBmYWxzZSxcbiAgICAgICAgICBlcnJvck1lc3NhZ2U6IGBJbnZhbGlkIEpTT046ICR7ZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpfWAsXG4gICAgICAgICAgc2V2ZXJpdHk6ICdtZWRpdW0nXG4gICAgICAgIH07XG4gICAgICB9XG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGUgYSBjb250ZW50IHZhbGlkYXRvciBmb3IgWUFNTCBjb250ZW50XG4gICAqL1xuICBzdGF0aWMgeWFtbFZhbGlkYXRvcigpOiBDb250ZW50VmFsaWRhdG9yRnVuY3Rpb24ge1xuICAgIHJldHVybiBhc3luYyAoY29udGVudDogc3RyaW5nKTogUHJvbWlzZTxWYWxpZGF0aW9uUmVzdWx0PiA9PiB7XG4gICAgICBjb25zdCBpc1ZhbGlkID0gU2VjdXJpdHlDb250ZW50VmFsaWRhdG9yLnZhbGlkYXRlWWFtbENvbnRlbnQoY29udGVudCk7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBpc1ZhbGlkLFxuICAgICAgICBlcnJvck1lc3NhZ2U6IGlzVmFsaWQgPyB1bmRlZmluZWQgOiAnSW52YWxpZCBvciBtYWxpY2lvdXMgWUFNTCBjb250ZW50JyxcbiAgICAgICAgc2V2ZXJpdHk6IGlzVmFsaWQgPyAnbG93JyA6ICdoaWdoJ1xuICAgICAgfTtcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZSBhIGNvbnRlbnQgdmFsaWRhdG9yIGZvciBtYXJrZG93biBjb250ZW50XG4gICAqL1xuICBzdGF0aWMgbWFya2Rvd25WYWxpZGF0b3IoKTogQ29udGVudFZhbGlkYXRvckZ1bmN0aW9uIHtcbiAgICByZXR1cm4gYXN5bmMgKGNvbnRlbnQ6IHN0cmluZyk6IFByb21pc2U8VmFsaWRhdGlvblJlc3VsdD4gPT4ge1xuICAgICAgdHJ5IHtcbiAgICAgICAgLy8gVXNlIGV4aXN0aW5nIHBlcnNvbmEgY29udGVudCBzYW5pdGl6YXRpb24gZm9yIG1hcmtkb3duXG4gICAgICAgIFNlY3VyaXR5Q29udGVudFZhbGlkYXRvci5zYW5pdGl6ZVBlcnNvbmFDb250ZW50KGNvbnRlbnQpO1xuICAgICAgICByZXR1cm4geyBpc1ZhbGlkOiB0cnVlIH07XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIGlzVmFsaWQ6IGZhbHNlLFxuICAgICAgICAgIGVycm9yTWVzc2FnZTogYEludmFsaWQgbWFya2Rvd246ICR7ZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpfWAsXG4gICAgICAgICAgc2V2ZXJpdHk6IGVycm9yIGluc3RhbmNlb2YgU2VjdXJpdHlFcnJvciA/ICdjcml0aWNhbCcgOiAnbWVkaXVtJ1xuICAgICAgICB9O1xuICAgICAgfVxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlIGEgY29udGVudCB2YWxpZGF0b3Igd2l0aCBzaXplIGxpbWl0c1xuICAgKi9cbiAgc3RhdGljIHNpemVWYWxpZGF0b3IobWF4U2l6ZTogbnVtYmVyKTogQ29udGVudFZhbGlkYXRvckZ1bmN0aW9uIHtcbiAgICByZXR1cm4gYXN5bmMgKGNvbnRlbnQ6IHN0cmluZyk6IFByb21pc2U8VmFsaWRhdGlvblJlc3VsdD4gPT4ge1xuICAgICAgY29uc3Qgc2l6ZSA9IEJ1ZmZlci5ieXRlTGVuZ3RoKGNvbnRlbnQsICd1dGYtOCcpO1xuICAgICAgaWYgKHNpemUgPiBtYXhTaXplKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgaXNWYWxpZDogZmFsc2UsXG4gICAgICAgICAgZXJyb3JNZXNzYWdlOiBgQ29udGVudCBzaXplICR7c2l6ZX0gZXhjZWVkcyBsaW1pdCBvZiAke21heFNpemV9IGJ5dGVzYCxcbiAgICAgICAgICBzZXZlcml0eTogJ2hpZ2gnXG4gICAgICAgIH07XG4gICAgICB9XG4gICAgICByZXR1cm4geyBpc1ZhbGlkOiB0cnVlIH07XG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGUgYSBjb250ZW50IHZhbGlkYXRvciB0aGF0IGNoZWNrcyBmb3IgZm9yYmlkZGVuIHBhdHRlcm5zXG4gICAqL1xuICBzdGF0aWMgcGF0dGVyblZhbGlkYXRvcihcbiAgICBmb3JiaWRkZW5QYXR0ZXJuczogUmVnRXhwW10sXG4gICAgZXJyb3JNZXNzYWdlOiBzdHJpbmcgPSAnRm9yYmlkZGVuIHBhdHRlcm4gZGV0ZWN0ZWQnXG4gICk6IENvbnRlbnRWYWxpZGF0b3JGdW5jdGlvbiB7XG4gICAgcmV0dXJuIGFzeW5jIChjb250ZW50OiBzdHJpbmcpOiBQcm9taXNlPFZhbGlkYXRpb25SZXN1bHQ+ID0+IHtcbiAgICAgIGZvciAoY29uc3QgcGF0dGVybiBvZiBmb3JiaWRkZW5QYXR0ZXJucykge1xuICAgICAgICBpZiAocGF0dGVybi50ZXN0KGNvbnRlbnQpKSB7XG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIGlzVmFsaWQ6IGZhbHNlLFxuICAgICAgICAgICAgZXJyb3JNZXNzYWdlLFxuICAgICAgICAgICAgc2V2ZXJpdHk6ICdoaWdoJyxcbiAgICAgICAgICAgIG1ldGFkYXRhOiB7IHBhdHRlcm46IHBhdHRlcm4uc291cmNlIH1cbiAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICByZXR1cm4geyBpc1ZhbGlkOiB0cnVlIH07XG4gICAgfTtcbiAgfVxufSJdfQ==