@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
@@ -6,6 +6,7 @@
6
6
  * It ensures users have example content to work with immediately after installation.
7
7
  */
8
8
  import * as fs from 'fs/promises';
9
+ import * as fsSync from 'fs';
9
10
  import * as path from 'path';
10
11
  import { fileURLToPath } from 'url';
11
12
  import { createHash } from 'crypto';
@@ -13,6 +14,7 @@ import { logger } from '../utils/logger.js';
13
14
  import { ElementType } from './types.js';
14
15
  import { UnicodeValidator } from '../security/validators/unicodeValidator.js';
15
16
  import { SecurityMonitor } from '../security/securityMonitor.js';
17
+ import { SecureYamlParser } from '../security/secureYamlParser.js';
16
18
  // File operation constants
17
19
  export const FILE_CONSTANTS = {
18
20
  ELEMENT_EXTENSION: '.md',
@@ -24,6 +26,18 @@ export const FILE_CONSTANTS = {
24
26
  FILE_PERMISSIONS: 0o644,
25
27
  CHUNK_SIZE: 64 * 1024 // 64KB chunks for reading large files
26
28
  };
29
+ // Development mode detection
30
+ // When running from a git clone, we don't want to auto-load test data
31
+ const IS_DEVELOPMENT_MODE = (() => {
32
+ try {
33
+ // Check if we're in a git repository (development mode)
34
+ const gitDir = path.join(process.cwd(), '.git');
35
+ return fsSync.existsSync(gitDir);
36
+ }
37
+ catch {
38
+ return false;
39
+ }
40
+ })();
27
41
  // Internal constants
28
42
  const DATA_DIR_CACHE_KEY = 'dollhouse_data_dir';
29
43
  const COPY_RETRY_ATTEMPTS = 3;
@@ -33,13 +47,66 @@ export class DefaultElementProvider {
33
47
  static cachedDataDir = null;
34
48
  static populateInProgress = new Map();
35
49
  config;
50
+ // PERFORMANCE OPTIMIZATION: Cache metadata with file mtime for invalidation
51
+ static metadataCache = new Map();
52
+ static MAX_CACHE_SIZE = 20; // MEMORY LEAK FIX: Further reduced cache size to prevent accumulation during performance tests
36
53
  constructor(config) {
37
54
  const __filename = fileURLToPath(import.meta.url);
38
55
  this.__dirname = path.dirname(__filename);
56
+ // Check environment variable for test data loading
57
+ const envLoadTestData = process.env.DOLLHOUSE_LOAD_TEST_DATA;
58
+ const loadTestDataFromEnv = envLoadTestData === 'true' || envLoadTestData === '1';
59
+ const disableTestDataFromEnv = envLoadTestData === 'false' || envLoadTestData === '0';
60
+ // Check if we're in development mode (with respect to FORCE_PRODUCTION_MODE override)
61
+ const isDevMode = (() => {
62
+ // Respect FORCE_PRODUCTION_MODE override first
63
+ if (process.env.FORCE_PRODUCTION_MODE === 'true') {
64
+ return false; // Force production mode
65
+ }
66
+ if (process.env.FORCE_PRODUCTION_MODE === 'false') {
67
+ return true; // Force development mode
68
+ }
69
+ // Fall back to git detection
70
+ return IS_DEVELOPMENT_MODE;
71
+ })();
72
+ // Determine loadTestData value
73
+ let computedLoadTestData;
74
+ if (loadTestDataFromEnv) {
75
+ // Environment explicitly enables test data
76
+ computedLoadTestData = true;
77
+ }
78
+ else if (disableTestDataFromEnv) {
79
+ // Environment explicitly disables test data
80
+ computedLoadTestData = false;
81
+ }
82
+ else {
83
+ // Default logic: enable in production, disable in development unless config overrides
84
+ computedLoadTestData = !isDevMode && (config?.loadTestData ?? true);
85
+ }
39
86
  this.config = {
40
87
  useDefaultPaths: true,
41
- ...config
88
+ ...config,
89
+ // Apply final loadTestData logic - environment variables and development mode take precedence
90
+ loadTestData: loadTestDataFromEnv ? true : disableTestDataFromEnv ? false : computedLoadTestData
42
91
  };
92
+ if (isDevMode && !this.config.loadTestData) {
93
+ logger.info('[DefaultElementProvider] Development mode detected - test data loading disabled');
94
+ logger.info('[DefaultElementProvider] To enable test data, set DOLLHOUSE_LOAD_TEST_DATA=true');
95
+ }
96
+ }
97
+ /**
98
+ * Get the current loadTestData configuration value
99
+ * @returns Whether test data loading is enabled
100
+ */
101
+ get isTestDataLoadingEnabled() {
102
+ return this.config.loadTestData ?? false;
103
+ }
104
+ /**
105
+ * Get whether the system is in development mode
106
+ * @returns Whether running in development mode
107
+ */
108
+ get isDevelopmentMode() {
109
+ return IS_DEVELOPMENT_MODE;
43
110
  }
44
111
  /**
45
112
  * Search paths for bundled data directory
@@ -53,9 +120,15 @@ export class DefaultElementProvider {
53
120
  }
54
121
  // Add default paths if enabled
55
122
  if (this.config.useDefaultPaths !== false) {
123
+ // Skip development/repository data paths unless test data loading is enabled
124
+ if (this.config.loadTestData) {
125
+ // Development/Git installation (relative to this file)
126
+ paths.push(path.join(this.__dirname, '../../data'), path.join(this.__dirname, '../../../data'),
127
+ // Current working directory (last resort)
128
+ path.join(process.cwd(), 'data'));
129
+ }
130
+ // Always include NPM installation paths (these would have production data)
56
131
  paths.push(
57
- // Development/Git installation (relative to this file)
58
- path.join(this.__dirname, '../../data'), path.join(this.__dirname, '../../../data'),
59
132
  // NPM installations - macOS Homebrew
60
133
  '/opt/homebrew/lib/node_modules/@dollhousemcp/mcp-server/data',
61
134
  // NPM installations - standard Unix/Linux
@@ -63,9 +136,7 @@ export class DefaultElementProvider {
63
136
  // NPM installations - Windows
64
137
  'C:\\Program Files\\nodejs\\node_modules\\@dollhousemcp\\mcp-server\\data', 'C:\\Program Files (x86)\\nodejs\\node_modules\\@dollhousemcp\\mcp-server\\data',
65
138
  // NPM installations - Windows with nvm
66
- path.join(process.env.APPDATA || '', 'npm', 'node_modules', '@dollhousemcp', 'mcp-server', 'data'),
67
- // Current working directory (last resort)
68
- path.join(process.cwd(), 'data'));
139
+ path.join(process.env.APPDATA || '', 'npm', 'node_modules', '@dollhousemcp', 'mcp-server', 'data'));
69
140
  }
70
141
  return paths;
71
142
  }
@@ -122,6 +193,380 @@ export class DefaultElementProvider {
122
193
  return false;
123
194
  }
124
195
  }
196
+ /**
197
+ * Validate file path to prevent path traversal attacks
198
+ * SECURITY FIX: Added file path validation to prevent directory traversal
199
+ * Previously: File paths were used without validation, allowing potential ../../../ attacks
200
+ * Now: Strict validation ensures paths stay within allowed directories
201
+ * @param filePath The file path to validate
202
+ * @param allowedBasePaths Array of allowed base paths (optional)
203
+ * @returns true if path is safe, false otherwise
204
+ */
205
+ validateFilePath(filePath, allowedBasePaths) {
206
+ try {
207
+ // SECURITY: Normalize path to prevent traversal attempts
208
+ const normalizedPath = path.normalize(filePath);
209
+ // SECURITY: Reject paths containing traversal patterns
210
+ if (normalizedPath.includes('..')) {
211
+ logger.warn(`[DefaultElementProvider] Path traversal attempt blocked: ${filePath}`);
212
+ return false;
213
+ }
214
+ // SECURITY: Check for home directory expansion attempts, but allow Windows 8.3 short path names
215
+ // Windows short path names use ~ followed by a digit (e.g., RUNNER~1), which should be allowed
216
+ // Only block ~ followed by / or \ (home directory expansion patterns)
217
+ if (normalizedPath.includes('~/') || normalizedPath.includes('~\\')) {
218
+ logger.warn(`[DefaultElementProvider] Home directory expansion attempt blocked: ${filePath}`);
219
+ return false;
220
+ }
221
+ // SECURITY: Reject absolute paths outside allowed directories
222
+ if (path.isAbsolute(normalizedPath) && allowedBasePaths) {
223
+ const isAllowed = allowedBasePaths.some(basePath => {
224
+ const normalizedBase = path.normalize(basePath);
225
+ return normalizedPath.startsWith(normalizedBase);
226
+ });
227
+ if (!isAllowed) {
228
+ logger.warn(`[DefaultElementProvider] Absolute path outside allowed directories: ${filePath}`);
229
+ return false;
230
+ }
231
+ }
232
+ // SECURITY: Reject null bytes and other dangerous characters
233
+ if (normalizedPath.includes('\0') || normalizedPath.includes('\x00')) {
234
+ logger.warn(`[DefaultElementProvider] Null byte in path blocked: ${filePath}`);
235
+ return false;
236
+ }
237
+ return true;
238
+ }
239
+ catch (error) {
240
+ logger.warn(`[DefaultElementProvider] Path validation error: ${error}`);
241
+ return false;
242
+ }
243
+ }
244
+ // DEPRECATED: Commented out filename pattern detection - replaced with metadata-based detection
245
+ /**
246
+ * Cached compiled regex patterns for performance optimization
247
+ * @deprecated Use metadata-based detection instead
248
+ */
249
+ // private static compiledTestPatterns: RegExp[] | null = null;
250
+ /**
251
+ * Get compiled test patterns with caching for better performance
252
+ * @deprecated Use metadata-based detection instead
253
+ * @returns Array of compiled regex patterns
254
+ */
255
+ // private getCompiledTestPatterns(): RegExp[] {
256
+ // // Use cached patterns if available
257
+ // if (DefaultElementProvider.compiledTestPatterns) {
258
+ // return DefaultElementProvider.compiledTestPatterns;
259
+ // }
260
+ //
261
+ // // Compile and cache patterns on first use
262
+ // // CRITICAL FIX: Removed overly broad /^test-/i pattern that was blocking legitimate use
263
+ // // Users should be able to create personas like "test-driven-developer" or "test-automation-expert"
264
+ // // We only block specific test patterns that are clearly from our test suite
265
+ // DefaultElementProvider.compiledTestPatterns = [
266
+ // /^testpersona/i, // Our test suite pattern
267
+ // /^yamltest/i, // Security test pattern
268
+ // /^yamlbomb/i, // Security test pattern
269
+ // /^memory-test-/i, // Performance test pattern
270
+ // /^perf-test-/i, // Performance test pattern
271
+ // /^test-fixture-/i, // Test fixture pattern (more specific)
272
+ // /^test-data-/i, // Test data pattern (more specific)
273
+ // /bin-sh|rm-rf|pwned/i, // Malicious patterns
274
+ // /concurrent-\d+/i, // Concurrent test pattern
275
+ // /legacy\.md$/i, // Legacy test pattern
276
+ // /performance-test/i, // Performance test pattern
277
+ // /-\d{13}-[a-z0-9]+\.md$/i, // Timestamp-based test files
278
+ // /^unittest-/i, // Unit test pattern
279
+ // /^integrationtest-/i, // Integration test pattern
280
+ // ];
281
+ //
282
+ // return DefaultElementProvider.compiledTestPatterns;
283
+ // }
284
+ /**
285
+ * Check if a filename matches test data patterns that should never be copied to production
286
+ * @deprecated Use isDollhouseMCPTestElement() for metadata-based detection instead
287
+ * @param filename The filename to check
288
+ * @returns true if the filename matches test patterns that should be blocked
289
+ */
290
+ // private isTestDataPattern(filename: string): boolean {
291
+ // const patterns = this.getCompiledTestPatterns();
292
+ // return patterns.some(pattern => pattern.test(filename));
293
+ // }
294
+ /**
295
+ * Read metadata from YAML frontmatter only (never reads content body)
296
+ * Uses a small buffer to safely extract only the frontmatter between --- markers
297
+ * @param filePath Path to the file to read metadata from
298
+ * @returns Parsed metadata object or null if no frontmatter found
299
+ */
300
+ // PERFORMANCE OPTIMIZATION: Reusable buffer pool to reduce allocations
301
+ static bufferPool = [];
302
+ static MAX_POOL_SIZE = 20; // MEMORY LEAK FIX: Reduced buffer pool size to match cache size for consistent memory management
303
+ static bufferPoolStats = { hits: 0, misses: 0, created: 0 };
304
+ getBuffer() {
305
+ // PERFORMANCE: Track buffer pool usage for optimization monitoring
306
+ let buffer = DefaultElementProvider.bufferPool.pop();
307
+ if (buffer) {
308
+ DefaultElementProvider.bufferPoolStats.hits++;
309
+ return buffer;
310
+ }
311
+ else {
312
+ DefaultElementProvider.bufferPoolStats.misses++;
313
+ DefaultElementProvider.bufferPoolStats.created++;
314
+ buffer = Buffer.alloc(4096);
315
+ logger.debug(`[DefaultElementProvider] Created new buffer (pool empty), total created: ${DefaultElementProvider.bufferPoolStats.created}`);
316
+ return buffer;
317
+ }
318
+ }
319
+ releaseBuffer(buffer) {
320
+ // CRITICAL FIX: Always attempt to return buffer to pool for reuse
321
+ if (DefaultElementProvider.bufferPool.length < DefaultElementProvider.MAX_POOL_SIZE) {
322
+ buffer.fill(0); // SECURITY: Clear buffer before reuse to prevent data leakage
323
+ DefaultElementProvider.bufferPool.push(buffer);
324
+ }
325
+ else {
326
+ // PERFORMANCE: If pool is full, clear the buffer to help GC
327
+ buffer.fill(0);
328
+ logger.debug('[DefaultElementProvider] Buffer pool full, discarding buffer');
329
+ }
330
+ }
331
+ /**
332
+ * Clean up buffer pool and cache to free memory
333
+ * PERFORMANCE FIX: Added cleanup method to prevent memory leaks
334
+ * This should be called during application shutdown or periodic cleanup
335
+ */
336
+ static cleanup() {
337
+ // Clear buffer pool
338
+ DefaultElementProvider.bufferPool.length = 0;
339
+ // Clear metadata cache
340
+ DefaultElementProvider.metadataCache.clear();
341
+ // Clear cached data directory
342
+ DefaultElementProvider.cachedDataDir = null;
343
+ // Clear population promises
344
+ DefaultElementProvider.populateInProgress.clear();
345
+ logger.info('[DefaultElementProvider] Memory cleanup completed', {
346
+ bufferStats: DefaultElementProvider.bufferPoolStats,
347
+ cacheCleared: true
348
+ });
349
+ // Reset stats
350
+ DefaultElementProvider.bufferPoolStats = { hits: 0, misses: 0, created: 0 };
351
+ }
352
+ /**
353
+ * Get performance statistics for monitoring
354
+ * PERFORMANCE MONITORING: Added statistics method for performance tracking
355
+ * This provides insights into buffer pool efficiency and cache performance
356
+ * @returns Object containing performance metrics
357
+ */
358
+ static getPerformanceStats() {
359
+ const bufferHits = DefaultElementProvider.bufferPoolStats.hits;
360
+ const bufferMisses = DefaultElementProvider.bufferPoolStats.misses;
361
+ const totalRequests = bufferHits + bufferMisses;
362
+ return {
363
+ bufferPool: {
364
+ hits: bufferHits,
365
+ misses: bufferMisses,
366
+ created: DefaultElementProvider.bufferPoolStats.created,
367
+ hitRate: totalRequests > 0 ? bufferHits / totalRequests : 0,
368
+ poolSize: DefaultElementProvider.bufferPool.length,
369
+ maxPoolSize: DefaultElementProvider.MAX_POOL_SIZE
370
+ },
371
+ metadataCache: {
372
+ size: DefaultElementProvider.metadataCache.size,
373
+ maxSize: DefaultElementProvider.MAX_CACHE_SIZE
374
+ }
375
+ };
376
+ }
377
+ async readMetadataOnly(filePath, retries = 2) {
378
+ // PERFORMANCE: Check cache first before reading file
379
+ try {
380
+ const stats = await fs.stat(filePath);
381
+ const cacheKey = filePath;
382
+ const cached = DefaultElementProvider.metadataCache.get(cacheKey);
383
+ // Return cached metadata if file hasn't changed
384
+ // CRITICAL FIX: Use integer mtime comparison to avoid floating-point precision issues
385
+ if (cached && Math.floor(cached.mtime) === Math.floor(stats.mtimeMs) && cached.size === stats.size) {
386
+ logger.debug(`[DefaultElementProvider] Cache hit for ${filePath}`);
387
+ return cached.metadata;
388
+ }
389
+ }
390
+ catch {
391
+ // File doesn't exist, proceed with normal flow
392
+ }
393
+ try {
394
+ // Open file and read only first 4KB to avoid reading dangerous content
395
+ const fd = await fs.open(filePath, 'r');
396
+ // PERFORMANCE: Use buffer pool instead of allocating new buffer each time
397
+ const buffer = this.getBuffer();
398
+ try {
399
+ const result = await fd.read(buffer, 0, 4096, 0);
400
+ const header = buffer.subarray(0, result.bytesRead).toString('utf-8');
401
+ // Look for YAML frontmatter between --- markers
402
+ // Support both Unix (\n) and Windows (\r\n) line endings
403
+ const match = header.match(/^---\r?\n([\s\S]*?)\r?\n---/);
404
+ if (!match) {
405
+ return null; // No frontmatter found
406
+ }
407
+ // Parse the YAML frontmatter safely
408
+ try {
409
+ // SECURITY FIX: Replace direct YAML parsing function with SecureYamlParser for enhanced security
410
+ // SecureYamlParser provides additional validation, injection prevention, and content sanitization
411
+ // It expects full YAML with --- markers, so we reconstruct the frontmatter block
412
+ // We disable specific field validation as this is general metadata parsing, not persona-specific
413
+ const fullYaml = `---\n${match[1]}\n---`;
414
+ const parseResult = SecureYamlParser.parse(fullYaml, {
415
+ validateContent: false,
416
+ validateFields: false
417
+ });
418
+ const metadata = parseResult.data;
419
+ // PERFORMANCE: Cache the metadata with file stats for future reads
420
+ if (typeof metadata === 'object' && metadata !== null) {
421
+ try {
422
+ const stats = await fs.stat(filePath);
423
+ const cacheEntry = {
424
+ metadata,
425
+ mtime: stats.mtimeMs,
426
+ size: stats.size
427
+ };
428
+ // CRITICAL MEMORY LEAK FIX: More aggressive cache management to prevent unbounded growth
429
+ // Check if this entry already exists and just update it instead of adding new
430
+ if (DefaultElementProvider.metadataCache.has(filePath)) {
431
+ // Update existing entry - no eviction needed
432
+ DefaultElementProvider.metadataCache.set(filePath, cacheEntry);
433
+ logger.debug(`[DefaultElementProvider] Updated existing cache entry for ${filePath}`);
434
+ }
435
+ else {
436
+ // New entry - check if we need to evict first
437
+ // Use > instead of >= to ensure we never exceed MAX_CACHE_SIZE
438
+ if (DefaultElementProvider.metadataCache.size >= DefaultElementProvider.MAX_CACHE_SIZE) {
439
+ // More aggressive eviction: remove enough entries to stay well under limit
440
+ const entriesToEvict = Math.max(1, Math.floor(DefaultElementProvider.MAX_CACHE_SIZE * 0.4));
441
+ const keysToEvict = Array.from(DefaultElementProvider.metadataCache.keys()).slice(0, entriesToEvict);
442
+ for (const key of keysToEvict) {
443
+ DefaultElementProvider.metadataCache.delete(key);
444
+ }
445
+ logger.debug(`[DefaultElementProvider] Evicted ${keysToEvict.length} cache entries to manage memory (cache size was ${DefaultElementProvider.metadataCache.size + keysToEvict.length})`);
446
+ }
447
+ DefaultElementProvider.metadataCache.set(filePath, cacheEntry);
448
+ logger.debug(`[DefaultElementProvider] Added new cache entry for ${filePath} (cache size now: ${DefaultElementProvider.metadataCache.size})`);
449
+ }
450
+ }
451
+ catch {
452
+ // Ignore cache errors, return metadata anyway
453
+ }
454
+ return metadata;
455
+ }
456
+ return null;
457
+ }
458
+ catch (yamlError) {
459
+ // Invalid YAML, return null
460
+ // ENHANCEMENT: Include error type for better debugging
461
+ const yamlErrorType = yamlError?.constructor?.name || 'YAMLError';
462
+ logger.debug(`[DefaultElementProvider] Invalid YAML in ${filePath}: ${yamlErrorType} - ${yamlError}`);
463
+ return null;
464
+ }
465
+ }
466
+ finally {
467
+ // CRITICAL FIX: Ensure file descriptor is closed and buffer is released in ALL paths
468
+ try {
469
+ await fd.close();
470
+ }
471
+ catch (closeError) {
472
+ logger.debug(`[DefaultElementProvider] Error closing file descriptor for ${filePath}: ${closeError}`);
473
+ }
474
+ // PERFORMANCE: Return buffer to pool for reuse
475
+ this.releaseBuffer(buffer);
476
+ }
477
+ }
478
+ catch (error) {
479
+ // ENHANCEMENT: Include error type in debug logs for better debugging
480
+ const errorType = error?.constructor?.name || 'UnknownError';
481
+ const errorCode = error?.code || 'NO_CODE';
482
+ // RELIABILITY: Add retry logic for transient failures
483
+ if (retries > 0 && (errorCode === 'EBUSY' || errorCode === 'EAGAIN')) {
484
+ logger.debug(`[DefaultElementProvider] Retrying read for ${filePath} after ${errorType}:${errorCode}`);
485
+ await new Promise(resolve => setTimeout(resolve, 50)); // Brief delay before retry
486
+ return this.readMetadataOnly(filePath, retries - 1);
487
+ }
488
+ logger.debug(`[DefaultElementProvider] Could not read metadata from ${filePath}: ${errorType}:${errorCode} - ${error?.message || error}`);
489
+ return null;
490
+ }
491
+ }
492
+ /**
493
+ * Check if a file is a DollhouseMCP test element based on metadata
494
+ * This replaces filename pattern detection with accurate metadata-based detection
495
+ * @param filePath Path to the file to check
496
+ * @returns true if the file contains _dollhouseMCPTest: true metadata
497
+ */
498
+ async isDollhouseMCPTestElement(filePath) {
499
+ try {
500
+ const metadata = await this.readMetadataOnly(filePath);
501
+ const isTest = !!(metadata && metadata._dollhouseMCPTest === true);
502
+ return isTest;
503
+ }
504
+ catch (error) {
505
+ // If we can't read the metadata, assume it's not a test file
506
+ logger.debug(`[DefaultElementProvider] Error checking test metadata for ${filePath}: ${error}`);
507
+ return false;
508
+ }
509
+ }
510
+ /**
511
+ * Detect if we're in a production environment by checking for production indicators
512
+ * Uses a confidence-based approach requiring multiple indicators for better accuracy
513
+ * @returns true if this appears to be a production environment
514
+ */
515
+ isProductionEnvironment() {
516
+ // Allow tests to explicitly override production mode detection
517
+ if (process.env.FORCE_PRODUCTION_MODE === 'true') {
518
+ return true;
519
+ }
520
+ if (process.env.FORCE_PRODUCTION_MODE === 'false') {
521
+ return false;
522
+ }
523
+ // Weighted indicators for production detection
524
+ const indicators = {
525
+ // Strong indicators (weight: 2)
526
+ hasUserHomeDir: (process.env.HOME && (process.env.HOME.includes('/Users/') || process.env.HOME.includes('/home/'))) ||
527
+ !!process.env.USERPROFILE,
528
+ isProductionNode: process.env.NODE_ENV === 'production',
529
+ notInTestDir: (() => {
530
+ const cwd = process.cwd().toLowerCase();
531
+ // Normalize path separators for cross-platform checking (Windows uses \ but checks use /)
532
+ const normalizedCwd = cwd.replace(/\\/g, '/');
533
+ return !normalizedCwd.includes('/test') &&
534
+ !normalizedCwd.includes('/__tests__') &&
535
+ !normalizedCwd.includes('/temp') &&
536
+ !normalizedCwd.includes('/dist/test');
537
+ })(),
538
+ // Moderate indicators (weight: 1)
539
+ notInCI: !process.env.CI,
540
+ noTestEnv: process.env.NODE_ENV !== 'test',
541
+ noDevEnv: process.env.NODE_ENV !== 'development',
542
+ };
543
+ // Calculate weighted score
544
+ let score = 0;
545
+ if (indicators.hasUserHomeDir)
546
+ score += 2;
547
+ if (indicators.isProductionNode)
548
+ score += 2;
549
+ if (indicators.notInTestDir)
550
+ score += 2;
551
+ if (indicators.notInCI)
552
+ score += 1;
553
+ if (indicators.noTestEnv)
554
+ score += 1;
555
+ if (indicators.noDevEnv)
556
+ score += 1;
557
+ // Log detection details for debugging
558
+ const activeIndicators = Object.entries(indicators)
559
+ .filter(([_, value]) => value)
560
+ .map(([key]) => key);
561
+ // TYPESCRIPT FIX: Removed logger.isDebugEnabled() check as this method doesn't exist on MCPLogger
562
+ // The logger already handles debug level internally, so we can call debug() directly
563
+ if (score >= 3) {
564
+ logger.debug('[DefaultElementProvider] Production environment detected', { score, activeIndicators, forceMode: 'not set' });
565
+ }
566
+ // Require a score of at least 3 for production detection (more confident)
567
+ // This prevents false positives in edge cases while maintaining security
568
+ return score >= 3;
569
+ }
125
570
  /**
126
571
  * Copy all files from source directory to destination directory
127
572
  * Skips files that already exist to preserve user modifications
@@ -146,6 +591,40 @@ export class DefaultElementProvider {
146
591
  }
147
592
  const sourcePath = path.join(sourceDir, normalizedFile.normalizedContent);
148
593
  const destPath = path.join(destDir, normalizedFile.normalizedContent);
594
+ // SECURITY FIX: Validate file paths to prevent path traversal attacks
595
+ // This prevents malicious files from escaping the intended directory structure
596
+ const sourceValid = this.validateFilePath(sourcePath, [sourceDir]);
597
+ const destValid = this.validateFilePath(destPath, [destDir]);
598
+ if (!sourceValid || !destValid) {
599
+ logger.warn(`[DefaultElementProvider] Skipping file with invalid path: ${normalizedFile.normalizedContent}`, { sourcePath, destPath, elementType });
600
+ continue;
601
+ }
602
+ // Production safety check: Block DollhouseMCP test elements in production environments
603
+ // Skip this check if loadTestData is explicitly enabled (for testing scenarios)
604
+ if (!this.config.loadTestData && this.isProductionEnvironment()) {
605
+ const isDollhouseTest = await this.isDollhouseMCPTestElement(sourcePath);
606
+ if (isDollhouseTest) {
607
+ logger.warn(`[DefaultElementProvider] SECURITY: Blocking DollhouseMCP test element in production: ${normalizedFile.normalizedContent}`, {
608
+ file: normalizedFile.normalizedContent,
609
+ reason: 'DollhouseMCP test element detected in production environment',
610
+ elementType
611
+ });
612
+ // Log security event for blocked test data
613
+ SecurityMonitor.logSecurityEvent({
614
+ type: 'TEST_DATA_BLOCKED',
615
+ severity: 'MEDIUM',
616
+ source: 'DefaultElementProvider.copyElementFiles',
617
+ details: `Blocked DollhouseMCP test element in production: ${normalizedFile.normalizedContent}`,
618
+ metadata: {
619
+ filename: normalizedFile.normalizedContent,
620
+ elementType,
621
+ reason: 'DollhouseMCP test element detected in production environment',
622
+ detectionMethod: 'metadata-based'
623
+ }
624
+ });
625
+ continue;
626
+ }
627
+ }
149
628
  try {
150
629
  // Check if destination file already exists
151
630
  await fs.access(destPath);
@@ -322,6 +801,19 @@ export class DefaultElementProvider {
322
801
  * @param portfolioBaseDir Base directory of the portfolio
323
802
  */
324
803
  async performPopulation(portfolioBaseDir) {
804
+ // Check if test data loading is disabled
805
+ // Note: This check is needed even though constructor sets config, because
806
+ // config can be overridden after construction
807
+ // Use production environment detection that respects FORCE_PRODUCTION_MODE
808
+ const isDevelopmentMode = !this.isProductionEnvironment();
809
+ if (isDevelopmentMode && !this.config.loadTestData) {
810
+ logger.info('[DefaultElementProvider] Skipping default element population in development mode', {
811
+ portfolioBaseDir,
812
+ reason: 'Test data loading disabled',
813
+ enableWith: 'Set DOLLHOUSE_LOAD_TEST_DATA=true to enable'
814
+ });
815
+ return;
816
+ }
325
817
  logger.info('[DefaultElementProvider] Starting default element population', { portfolioBaseDir });
326
818
  // Log security event for portfolio initialization
327
819
  SecurityMonitor.logSecurityEvent({
@@ -383,4 +875,4 @@ export class DefaultElementProvider {
383
875
  }
384
876
  }
385
877
  }
386
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRGVmYXVsdEVsZW1lbnRQcm92aWRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9wb3J0Zm9saW8vRGVmYXVsdEVsZW1lbnRQcm92aWRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7O0dBTUc7QUFFSCxPQUFPLEtBQUssRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUNsQyxPQUFPLEtBQUssSUFBSSxNQUFNLE1BQU0sQ0FBQztBQUM3QixPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sS0FBSyxDQUFDO0FBQ3BDLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxRQUFRLENBQUM7QUFDcEMsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQzVDLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFDekMsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sNENBQTRDLENBQUM7QUFDOUUsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBRWpFLDJCQUEyQjtBQUMzQixNQUFNLENBQUMsTUFBTSxjQUFjLEdBQUc7SUFDNUIsaUJBQWlCLEVBQUUsS0FBSztJQUN4QixjQUFjLEVBQUUsT0FBTztJQUN2QixhQUFhLEVBQUUsTUFBTTtJQUNyQixjQUFjLEVBQUUsT0FBTztJQUN2QixhQUFhLEVBQUUsRUFBRSxHQUFHLElBQUksR0FBRyxJQUFJLEVBQUUsZ0NBQWdDO0lBQ2pFLGtCQUFrQixFQUFFLFFBQVE7SUFDNUIsZ0JBQWdCLEVBQUUsS0FBSztJQUN2QixVQUFVLEVBQUUsRUFBRSxHQUFHLElBQUksQ0FBQyxzQ0FBc0M7Q0FDcEQsQ0FBQztBQUVYLHFCQUFxQjtBQUNyQixNQUFNLGtCQUFrQixHQUFHLG9CQUFvQixDQUFDO0FBQ2hELE1BQU0sbUJBQW1CLEdBQUcsQ0FBQyxDQUFDO0FBQzlCLE1BQU0sZ0JBQWdCLEdBQUcsR0FBRyxDQUFDLENBQUMsS0FBSztBQVNuQyxN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biAqIERlZmF1bHRFbGVtZW50UHJvdmlkZXIgLSBQb3B1bGF0ZXMgcG9ydGZvbGlvIHdpdGggZGVmYXVsdCBlbGVtZW50cyBmcm9tIGJ1bmRsZWQgZGF0YVxuICogXG4gKiBUaGlzIGNsYXNzIGhhbmRsZXMgY29weWluZyBkZWZhdWx0IHBlcnNvbmFzLCBza2lsbHMsIHRlbXBsYXRlcywgYW5kIG90aGVyIGVsZW1lbnRzXG4gKiBmcm9tIHRoZSBOUE0gcGFja2FnZSBvciBHaXQgcmVwb3NpdG9yeSB0byB0aGUgdXNlcidzIHBvcnRmb2xpbyBvbiBmaXJzdCBydW4uXG4gKiBJdCBlbnN1cmVzIHVzZXJzIGhhdmUgZXhhbXBsZSBjb250ZW50IHRvIHdvcmsgd2l0aCBpbW1lZGlhdGVseSBhZnRlciBpbnN0YWxsYXRpb24uXG4gKi9cblxuaW1wb3J0ICogYXMgZnMgZnJvbSAnZnMvcHJvbWlzZXMnO1xuaW1wb3J0ICogYXMgcGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCB7IGZpbGVVUkxUb1BhdGggfSBmcm9tICd1cmwnO1xuaW1wb3J0IHsgY3JlYXRlSGFzaCB9IGZyb20gJ2NyeXB0byc7XG5pbXBvcnQgeyBsb2dnZXIgfSBmcm9tICcuLi91dGlscy9sb2dnZXIuanMnO1xuaW1wb3J0IHsgRWxlbWVudFR5cGUgfSBmcm9tICcuL3R5cGVzLmpzJztcbmltcG9ydCB7IFVuaWNvZGVWYWxpZGF0b3IgfSBmcm9tICcuLi9zZWN1cml0eS92YWxpZGF0b3JzL3VuaWNvZGVWYWxpZGF0b3IuanMnO1xuaW1wb3J0IHsgU2VjdXJpdHlNb25pdG9yIH0gZnJvbSAnLi4vc2VjdXJpdHkvc2VjdXJpdHlNb25pdG9yLmpzJztcblxuLy8gRmlsZSBvcGVyYXRpb24gY29uc3RhbnRzXG5leHBvcnQgY29uc3QgRklMRV9DT05TVEFOVFMgPSB7XG4gIEVMRU1FTlRfRVhURU5TSU9OOiAnLm1kJyxcbiAgWUFNTF9FWFRFTlNJT046ICcueWFtbCcsXG4gIFlNTF9FWFRFTlNJT046ICcueW1sJyxcbiAgSlNPTl9FWFRFTlNJT046ICcuanNvbicsXG4gIE1BWF9GSUxFX1NJWkU6IDEwICogMTAyNCAqIDEwMjQsIC8vIDEwTUIgbWF4IGZpbGUgc2l6ZSBmb3Igc2FmZXR5XG4gIENIRUNLU1VNX0FMR09SSVRITTogJ3NoYTI1NicsXG4gIEZJTEVfUEVSTUlTU0lPTlM6IDBvNjQ0LFxuICBDSFVOS19TSVpFOiA2NCAqIDEwMjQgLy8gNjRLQiBjaHVua3MgZm9yIHJlYWRpbmcgbGFyZ2UgZmlsZXNcbn0gYXMgY29uc3Q7XG5cbi8vIEludGVybmFsIGNvbnN0YW50c1xuY29uc3QgREFUQV9ESVJfQ0FDSEVfS0VZID0gJ2RvbGxob3VzZV9kYXRhX2Rpcic7XG5jb25zdCBDT1BZX1JFVFJZX0FUVEVNUFRTID0gMztcbmNvbnN0IENPUFlfUkVUUllfREVMQVkgPSAxMDA7IC8vIG1zXG5cbmV4cG9ydCBpbnRlcmZhY2UgRGVmYXVsdEVsZW1lbnRQcm92aWRlckNvbmZpZyB7XG4gIC8qKiBDdXN0b20gZGF0YSBkaXJlY3RvcnkgcGF0aHMgdG8gc2VhcmNoIChjaGVja2VkIGJlZm9yZSBkZWZhdWx0IHBhdGhzKSAqL1xuICBjdXN0b21EYXRhUGF0aHM/OiBzdHJpbmdbXTtcbiAgLyoqIFdoZXRoZXIgdG8gdXNlIGRlZmF1bHQgc2VhcmNoIHBhdGhzIGFmdGVyIGN1c3RvbSBwYXRocyAqL1xuICB1c2VEZWZhdWx0UGF0aHM/OiBib29sZWFuO1xufVxuXG5leHBvcnQgY2xhc3MgRGVmYXVsdEVsZW1lbnRQcm92aWRlciB7XG4gIHByaXZhdGUgcmVhZG9ubHkgX19kaXJuYW1lOiBzdHJpbmc7XG4gIHByaXZhdGUgc3RhdGljIGNhY2hlZERhdGFEaXI6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIHN0YXRpYyBwb3B1bGF0ZUluUHJvZ3Jlc3M6IE1hcDxzdHJpbmcsIFByb21pc2U8dm9pZD4+ID0gbmV3IE1hcCgpO1xuICBwcml2YXRlIHJlYWRvbmx5IGNvbmZpZzogRGVmYXVsdEVsZW1lbnRQcm92aWRlckNvbmZpZztcbiAgXG4gIGNvbnN0cnVjdG9yKGNvbmZpZz86IERlZmF1bHRFbGVtZW50UHJvdmlkZXJDb25maWcpIHtcbiAgICBjb25zdCBfX2ZpbGVuYW1lID0gZmlsZVVSTFRvUGF0aChpbXBvcnQubWV0YS51cmwpO1xuICAgIHRoaXMuX19kaXJuYW1lID0gcGF0aC5kaXJuYW1lKF9fZmlsZW5hbWUpO1xuICAgIHRoaXMuY29uZmlnID0ge1xuICAgICAgdXNlRGVmYXVsdFBhdGhzOiB0cnVlLFxuICAgICAgLi4uY29uZmlnXG4gICAgfTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIFNlYXJjaCBwYXRocyBmb3IgYnVuZGxlZCBkYXRhIGRpcmVjdG9yeVxuICAgKiBPcmRlcmVkIGJ5IHByaW9yaXR5IC0gY3VzdG9tIHBhdGhzIGZpcnN0LCB0aGVuIGRldmVsb3BtZW50L2dpdCwgdGhlbiBOUE0gbG9jYXRpb25zXG4gICAqL1xuICBwcml2YXRlIGdldCBkYXRhU2VhcmNoUGF0aHMoKTogc3RyaW5nW10ge1xuICAgIGNvbnN0IHBhdGhzOiBzdHJpbmdbXSA9IFtdO1xuICAgIFxuICAgIC8vIEFkZCBjdXN0b20gcGF0aHMgZmlyc3QgKGhpZ2hlc3QgcHJpb3JpdHkpXG4gICAgaWYgKHRoaXMuY29uZmlnLmN1c3RvbURhdGFQYXRocykge1xuICAgICAgcGF0aHMucHVzaCguLi50aGlzLmNvbmZpZy5jdXN0b21EYXRhUGF0aHMpO1xuICAgIH1cbiAgICBcbiAgICAvLyBBZGQgZGVmYXVsdCBwYXRocyBpZiBlbmFibGVkXG4gICAgaWYgKHRoaXMuY29uZmlnLnVzZURlZmF1bHRQYXRocyAhPT0gZmFsc2UpIHtcbiAgICAgIHBhdGhzLnB1c2goXG4gICAgICAgIC8vIERldmVsb3BtZW50L0dpdCBpbnN0YWxsYXRpb24gKHJlbGF0aXZlIHRvIHRoaXMgZmlsZSlcbiAgICAgICAgcGF0aC5qb2luKHRoaXMuX19kaXJuYW1lLCAnLi4vLi4vZGF0YScpLFxuICAgICAgICBwYXRoLmpvaW4odGhpcy5fX2Rpcm5hbWUsICcuLi8uLi8uLi9kYXRhJyksXG4gICAgICAgIFxuICAgICAgICAvLyBOUE0gaW5zdGFsbGF0aW9ucyAtIG1hY09TIEhvbWVicmV3XG4gICAgICAgICcvb3B0L2hvbWVicmV3L2xpYi9ub2RlX21vZHVsZXMvQGRvbGxob3VzZW1jcC9tY3Atc2VydmVyL2RhdGEnLFxuICAgICAgICBcbiAgICAgICAgLy8gTlBNIGluc3RhbGxhdGlvbnMgLSBzdGFuZGFyZCBVbml4L0xpbnV4XG4gICAgICAgICcvdXNyL2xvY2FsL2xpYi9ub2RlX21vZHVsZXMvQGRvbGxob3VzZW1jcC9tY3Atc2VydmVyL2RhdGEnLFxuICAgICAgICAnL3Vzci9saWIvbm9kZV9tb2R1bGVzL0Bkb2xsaG91c2VtY3AvbWNwLXNlcnZlci9kYXRhJyxcbiAgICAgICAgXG4gICAgICAgIC8vIE5QTSBpbnN0YWxsYXRpb25zIC0gV2luZG93c1xuICAgICAgICAnQzpcXFxcUHJvZ3JhbSBGaWxlc1xcXFxub2RlanNcXFxcbm9kZV9tb2R1bGVzXFxcXEBkb2xsaG91c2VtY3BcXFxcbWNwLXNlcnZlclxcXFxkYXRhJyxcbiAgICAgICAgJ0M6XFxcXFByb2dyYW0gRmlsZXMgKHg4NilcXFxcbm9kZWpzXFxcXG5vZGVfbW9kdWxlc1xcXFxAZG9sbGhvdXNlbWNwXFxcXG1jcC1zZXJ2ZXJcXFxcZGF0YScsXG4gICAgICAgIFxuICAgICAgICAvLyBOUE0gaW5zdGFsbGF0aW9ucyAtIFdpbmRvd3Mgd2l0aCBudm1cbiAgICAgICAgcGF0aC5qb2luKHByb2Nlc3MuZW52LkFQUERBVEEgfHwgJycsICducG0nLCAnbm9kZV9tb2R1bGVzJywgJ0Bkb2xsaG91c2VtY3AnLCAnbWNwLXNlcnZlcicsICdkYXRhJyksXG4gICAgICAgIFxuICAgICAgICAvLyBDdXJyZW50IHdvcmtpbmcgZGlyZWN0b3J5IChsYXN0IHJlc29ydClcbiAgICAgICAgcGF0aC5qb2luKHByb2Nlc3MuY3dkKCksICdkYXRhJylcbiAgICAgICk7XG4gICAgfVxuICAgIFxuICAgIHJldHVybiBwYXRocztcbiAgfVxuICBcbiAgLyoqXG4gICAqIEZpbmQgdGhlIGJ1bmRsZWQgZGF0YSBkaXJlY3RvcnkgYnkgY2hlY2tpbmcgZWFjaCBzZWFyY2ggcGF0aFxuICAgKiBVc2VzIFByb21pc2UuYWxsU2V0dGxlZCBmb3IgYmV0dGVyIHBlcmZvcm1hbmNlIGFuZCBjYWNoZXMgdGhlIHJlc3VsdFxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBmaW5kRGF0YURpcmVjdG9yeSgpOiBQcm9taXNlPHN0cmluZyB8IG51bGw+IHtcbiAgICAvLyBSZXR1cm4gY2FjaGVkIHZhbHVlIGlmIGF2YWlsYWJsZVxuICAgIGlmIChEZWZhdWx0RWxlbWVudFByb3ZpZGVyLmNhY2hlZERhdGFEaXIgIT09IG51bGwpIHtcbiAgICAgIHJldHVybiBEZWZhdWx0RWxlbWVudFByb3ZpZGVyLmNhY2hlZERhdGFEaXI7XG4gICAgfVxuICAgIFxuICAgIC8vIENoZWNrIGFsbCBwYXRocyBpbiBwYXJhbGxlbCBmb3IgYmV0dGVyIHBlcmZvcm1hbmNlXG4gICAgY29uc3QgY2hlY2tQcm9taXNlcyA9IHRoaXMuZGF0YVNlYXJjaFBhdGhzLm1hcChhc3luYyAoc2VhcmNoUGF0aCkgPT4ge1xuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3Qgc3RhdHMgPSBhd2FpdCBmcy5zdGF0KHNlYXJjaFBhdGgpO1xuICAgICAgICBpZiAoc3RhdHMuaXNEaXJlY3RvcnkoKSkge1xuICAgICAgICAgIC8vIFZlcmlmeSBpdCBjb250YWlucyBleHBlY3RlZCBzdWJkaXJlY3Rvcmllc1xuICAgICAgICAgIGNvbnN0IGhhc1BlcnNvbmFzID0gYXdhaXQgdGhpcy5kaXJlY3RvcnlFeGlzdHMocGF0aC5qb2luKHNlYXJjaFBhdGgsICdwZXJzb25hcycpKTtcbiAgICAgICAgICBjb25zdCBoYXNTa2lsbHMgPSBhd2FpdCB0aGlzLmRpcmVjdG9yeUV4aXN0cyhwYXRoLmpvaW4oc2VhcmNoUGF0aCwgJ3NraWxscycpKTtcbiAgICAgICAgICBpZiAoaGFzUGVyc29uYXMgfHwgaGFzU2tpbGxzKSB7XG4gICAgICAgICAgICByZXR1cm4gc2VhcmNoUGF0aDtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIC8vIERpcmVjdG9yeSBkb2Vzbid0IGV4aXN0IG9yIGNhbid0IGJlIGFjY2Vzc2VkXG4gICAgICAgIHJldHVybiBudWxsO1xuICAgICAgfVxuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfSk7XG4gICAgXG4gICAgY29uc3QgcmVzdWx0cyA9IGF3YWl0IFByb21pc2UuYWxsU2V0dGxlZChjaGVja1Byb21pc2VzKTtcbiAgICBcbiAgICAvLyBGaW5kIHRoZSBmaXJzdCBzdWNjZXNzZnVsIHJlc3VsdFxuICAgIGZvciAoY29uc3QgcmVzdWx0IG9mIHJlc3VsdHMpIHtcbiAgICAgIGlmIChyZXN1bHQuc3RhdHVzID09PSAnZnVsZmlsbGVkJyAmJiByZXN1bHQudmFsdWUgIT09IG51bGwpIHtcbiAgICAgICAgbG9nZ2VyLmluZm8oYFtEZWZhdWx0RWxlbWVudFByb3ZpZGVyXSBGb3VuZCBkYXRhIGRpcmVjdG9yeSBhdDogJHtyZXN1bHQudmFsdWV9YCk7XG4gICAgICAgIC8vIENhY2hlIHRoZSByZXN1bHRcbiAgICAgICAgRGVmYXVsdEVsZW1lbnRQcm92aWRlci5jYWNoZWREYXRhRGlyID0gcmVzdWx0LnZhbHVlO1xuICAgICAgICByZXR1cm4gcmVzdWx0LnZhbHVlO1xuICAgICAgfVxuICAgIH1cbiAgICBcbiAgICBsb2dnZXIud2FybignW0RlZmF1bHRFbGVtZW50UHJvdmlkZXJdIE5vIGJ1bmRsZWQgZGF0YSBkaXJlY3RvcnkgZm91bmQgaW4gYW55IHNlYXJjaCBwYXRoJyk7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBIZWxwZXIgdG8gY2hlY2sgaWYgYSBkaXJlY3RvcnkgZXhpc3RzXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGRpcmVjdG9yeUV4aXN0cyhkaXJQYXRoOiBzdHJpbmcpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICB0cnkge1xuICAgICAgY29uc3Qgc3RhdHMgPSBhd2FpdCBmcy5zdGF0KGRpclBhdGgpO1xuICAgICAgcmV0dXJuIHN0YXRzLmlzRGlyZWN0b3J5KCk7XG4gICAgfSBjYXRjaCB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICB9XG4gIFxuICAvKipcbiAgICogQ29weSBhbGwgZmlsZXMgZnJvbSBzb3VyY2UgZGlyZWN0b3J5IHRvIGRlc3RpbmF0aW9uIGRpcmVjdG9yeVxuICAgKiBTa2lwcyBmaWxlcyB0aGF0IGFscmVhZHkgZXhpc3QgdG8gcHJlc2VydmUgdXNlciBtb2RpZmljYXRpb25zXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGNvcHlFbGVtZW50RmlsZXMoc291cmNlRGlyOiBzdHJpbmcsIGRlc3REaXI6IHN0cmluZywgZWxlbWVudFR5cGU6IHN0cmluZyk6IFByb21pc2U8bnVtYmVyPiB7XG4gICAgbGV0IGNvcGllZENvdW50ID0gMDtcbiAgICBcbiAgICB0cnkge1xuICAgICAgLy8gRW5zdXJlIGRlc3RpbmF0aW9uIGRpcmVjdG9yeSBleGlzdHNcbiAgICAgIGF3YWl0IGZzLm1rZGlyKGRlc3REaXIsIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xuICAgICAgXG4gICAgICAvLyBSZWFkIHNvdXJjZSBkaXJlY3RvcnlcbiAgICAgIGNvbnN0IGZpbGVzID0gYXdhaXQgZnMucmVhZGRpcihzb3VyY2VEaXIpO1xuICAgICAgXG4gICAgICBmb3IgKGNvbnN0IGZpbGUgb2YgZmlsZXMpIHtcbiAgICAgICAgLy8gT25seSBjb3B5IG1hcmtkb3duIGZpbGVzXG4gICAgICAgIGlmICghZmlsZS5lbmRzV2l0aChGSUxFX0NPTlNUQU5UUy5FTEVNRU5UX0VYVEVOU0lPTikpIHtcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuICAgICAgICBcbiAgICAgICAgLy8gTm9ybWFsaXplIGZpbGVuYW1lIGZvciBzZWN1cml0eVxuICAgICAgICBjb25zdCBub3JtYWxpemVkRmlsZSA9IFVuaWNvZGVWYWxpZGF0b3Iubm9ybWFsaXplKGZpbGUpO1xuICAgICAgICBpZiAoIW5vcm1hbGl6ZWRGaWxlLmlzVmFsaWQpIHtcbiAgICAgICAgICBsb2dnZXIud2FybihgW0RlZmF1bHRFbGVtZW50UHJvdmlkZXJdIFNraXBwaW5nIGZpbGUgd2l0aCBpbnZhbGlkIFVuaWNvZGU6ICR7ZmlsZX1gKTtcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuICAgICAgICBcbiAgICAgICAgY29uc3Qgc291cmNlUGF0aCA9IHBhdGguam9pbihzb3VyY2VEaXIsIG5vcm1hbGl6ZWRGaWxlLm5vcm1hbGl6ZWRDb250ZW50KTtcbiAgICAgICAgY29uc3QgZGVzdFBhdGggPSBwYXRoLmpvaW4oZGVzdERpciwgbm9ybWFsaXplZEZpbGUubm9ybWFsaXplZENvbnRlbnQpO1xuICAgICAgICBcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAvLyBDaGVjayBpZiBkZXN0aW5hdGlvbiBmaWxlIGFscmVhZHkgZXhpc3RzXG4gICAgICAgICAgYXdhaXQgZnMuYWNjZXNzKGRlc3RQYXRoKTtcbiAgICAgICAgICBsb2dnZXIuZGVidWcoYFtEZWZhdWx0RWxlbWVudFByb3ZpZGVyXSBTa2lwcGluZyBleGlzdGluZyBmaWxlOiAke25vcm1hbGl6ZWRGaWxlLm5vcm1hbGl6ZWRDb250ZW50fWApO1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9IGNhdGNoIHtcbiAgICAgICAgICAvLyBGaWxlIGRvZXNuJ3QgZXhpc3QsIHByb2NlZWQgd2l0aCBjb3B5XG4gICAgICAgIH1cbiAgICAgICAgXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgLy8gVmFsaWRhdGUgc291cmNlIGZpbGUgYmVmb3JlIGNvcHlpbmdcbiAgICAgICAgICBjb25zdCBzb3VyY2VTdGF0cyA9IGF3YWl0IGZzLnN0YXQoc291cmNlUGF0aCk7XG4gICAgICAgICAgXG4gICAgICAgICAgLy8gQ2hlY2sgZmlsZSBzaXplIGxpbWl0XG4gICAgICAgICAgaWYgKHNvdXJjZVN0YXRzLnNpemUgPiBGSUxFX0NPTlNUQU5UUy5NQVhfRklMRV9TSVpFKSB7XG4gICAgICAgICAgICBsb2dnZXIud2FybihcbiAgICAgICAgICAgICAgYFtEZWZhdWx0RWxlbWVudFByb3ZpZGVyXSBTa2lwcGluZyBvdmVyc2l6ZWQgZmlsZSAke25vcm1hbGl6ZWRGaWxlLm5vcm1hbGl6ZWRDb250ZW50fTogYCArXG4gICAgICAgICAgICAgIGAke3NvdXJjZVN0YXRzLnNpemV9IGJ5dGVzIChtYXg6ICR7RklMRV9DT05TVEFOVFMuTUFYX0ZJTEVfU0laRX0gYnl0ZXMpYCxcbiAgICAgICAgICAgICAgeyBcbiAgICAgICAgICAgICAgICBmaWxlOiBub3JtYWxpemVkRmlsZS5ub3JtYWxpemVkQ29udGVudCwgXG4gICAgICAgICAgICAgICAgc2l6ZTogc291cmNlU3RhdHMuc2l6ZSxcbiAgICAgICAgICAgICAgICBtYXhTaXplOiBGSUxFX0NPTlNUQU5UUy5NQVhfRklMRV9TSVpFLFxuICAgICAgICAgICAgICAgIGVsZW1lbnRUeXBlIFxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgfVxuICAgICAgICAgIFxuICAgICAgICAgIC8vIENvcHkgdGhlIGZpbGUgd2l0aCB2ZXJpZmljYXRpb25cbiAgICAgICAgICBhd2FpdCB0aGlzLmNvcHlGaWxlV2l0aFZlcmlmaWNhdGlvbihzb3VyY2VQYXRoLCBkZXN0UGF0aCk7XG4gICAgICAgICAgY29waWVkQ291bnQrKztcbiAgICAgICAgICBsb2dnZXIuZGVidWcoYFtEZWZhdWx0RWxlbWVudFByb3ZpZGVyXSBDb3BpZWQgJHtlbGVtZW50VHlwZX06ICR7bm9ybWFsaXplZEZpbGUubm9ybWFsaXplZENvbnRlbnR9YCk7XG4gICAgICAgICAgXG4gICAgICAgICAgLy8gTG9nIHNlY3VyaXR5IGV2ZW50IGZvciBlYWNoIGZpbGUgY29waWVkXG4gICAgICAgICAgU2VjdXJpdHlNb25pdG9yLmxvZ1NlY3VyaXR5RXZlbnQoe1xuICAgICAgICAgICAgdHlwZTogJ0ZJTEVfQ09QSUVEJyxcbiAgICAgICAgICAgIHNldmVyaXR5OiAnTE9XJyxcbiAgICAgICAgICAgIHNvdXJjZTogJ0RlZmF1bHRFbGVtZW50UHJvdmlkZXIuY29weUVsZW1lbnRGaWxlcycsXG4gICAgICAgICAgICBkZXRhaWxzOiBgQ29waWVkIGRlZmF1bHQgJHtlbGVtZW50VHlwZX0gZmlsZTogJHtub3JtYWxpemVkRmlsZS5ub3JtYWxpemVkQ29udGVudH1gLFxuICAgICAgICAgICAgbWV0YWRhdGE6IHtcbiAgICAgICAgICAgICAgc291cmNlUGF0aCxcbiAgICAgICAgICAgICAgZGVzdFBhdGgsXG4gICAgICAgICAgICAgIGVsZW1lbnRUeXBlLFxuICAgICAgICAgICAgICBmaWxlU2l6ZTogKGF3YWl0IGZzLnN0YXQoZGVzdFBhdGgpKS5zaXplXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgY29uc3QgZXJyID0gZXJyb3IgYXMgRXJyb3I7XG4gICAgICAgICAgbG9nZ2VyLmVycm9yKFxuICAgICAgICAgICAgYFtEZWZhdWx0RWxlbWVudFByb3ZpZGVyXSBGYWlsZWQgdG8gY29weSAke25vcm1hbGl6ZWRGaWxlLm5vcm1hbGl6ZWRDb250ZW50fWAsXG4gICAgICAgICAgICB7IFxuICAgICAgICAgICAgICBlcnJvcjogZXJyLm1lc3NhZ2UsXG4gICAgICAgICAgICAgIHN0YWNrOiBlcnIuc3RhY2ssXG4gICAgICAgICAgICAgIHNvdXJjZVBhdGgsXG4gICAgICAgICAgICAgIGRlc3RQYXRoLFxuICAgICAgICAgICAgICBlbGVtZW50VHlwZVxuICAgICAgICAgICAgfVxuICAgICAgICAgICk7XG4gICAgICAgICAgLy8gQ29udGludWUgd2l0aCBvdGhlciBmaWxlcyBpbnN0ZWFkIG9mIGZhaWxpbmcgY29tcGxldGVseVxuICAgICAgICB9XG4gICAgICB9XG4gICAgICBcbiAgICAgIGlmIChjb3BpZWRDb3VudCA+IDApIHtcbiAgICAgICAgbG9nZ2VyLmluZm8oYFtEZWZhdWx0RWxlbWVudFByb3ZpZGVyXSBDb3BpZWQgJHtjb3BpZWRDb3VudH0gJHtlbGVtZW50VHlwZX0gZmlsZShzKWApO1xuICAgICAgfVxuICAgICAgXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGxvZ2dlci5lcnJvcihgW0RlZmF1bHRFbGVtZW50UHJvdmlkZXJdIEVycm9yIGNvcHlpbmcgJHtlbGVtZW50VHlwZX0gZmlsZXM6YCwgZXJyb3IpO1xuICAgIH1cbiAgICBcbiAgICByZXR1cm4gY29waWVkQ291bnQ7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBDb3B5IGEgZmlsZSB3aXRoIGludGVncml0eSB2ZXJpZmljYXRpb25cbiAgICogRW5zdXJlcyB0aGUgZmlsZSB3YXMgY29waWVkIGNvcnJlY3RseSBieSBjb21wYXJpbmcgc2l6ZXNcbiAgICovXG4gIC8qKlxuICAgKiBDYWxjdWxhdGUgY2hlY2tzdW0gb2YgYSBmaWxlIGZvciBpbnRlZ3JpdHkgdmVyaWZpY2F0aW9uXG4gICAqIEBwYXJhbSBmaWxlUGF0aCBQYXRoIHRvIHRoZSBmaWxlXG4gICAqIEByZXR1cm5zIEhleC1lbmNvZGVkIGNoZWNrc3VtXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGNhbGN1bGF0ZUNoZWNrc3VtKGZpbGVQYXRoOiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIGNvbnN0IGhhc2ggPSBjcmVhdGVIYXNoKEZJTEVfQ09OU1RBTlRTLkNIRUNLU1VNX0FMR09SSVRITSk7XG4gICAgY29uc3Qgc3RyZWFtID0gYXdhaXQgZnMub3BlbihmaWxlUGF0aCwgJ3InKTtcbiAgICBcbiAgICB0cnkge1xuICAgICAgY29uc3QgYnVmZmVyID0gQnVmZmVyLmFsbG9jKEZJTEVfQ09OU1RBTlRTLkNIVU5LX1NJWkUpO1xuICAgICAgbGV0IGJ5dGVzUmVhZDogbnVtYmVyO1xuICAgICAgXG4gICAgICBkbyB7XG4gICAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHN0cmVhbS5yZWFkKGJ1ZmZlciwgMCwgRklMRV9DT05TVEFOVFMuQ0hVTktfU0laRSk7XG4gICAgICAgIGJ5dGVzUmVhZCA9IHJlc3VsdC5ieXRlc1JlYWQ7XG4gICAgICAgIFxuICAgICAgICBpZiAoYnl0ZXNSZWFkID4gMCkge1xuICAgICAgICAgIGhhc2gudXBkYXRlKGJ1ZmZlci5zdWJhcnJheSgwLCBieXRlc1JlYWQpKTtcbiAgICAgICAgfVxuICAgICAgfSB3aGlsZSAoYnl0ZXNSZWFkID4gMCk7XG4gICAgICBcbiAgICAgIHJldHVybiBoYXNoLmRpZ2VzdCgnaGV4Jyk7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIGF3YWl0IHN0cmVhbS5jbG9zZSgpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBDb3B5IGZpbGUgd2l0aCBpbnRlZ3JpdHkgdmVyaWZpY2F0aW9uIGFuZCByZXRyeSBsb2dpY1xuICAgKiBAcGFyYW0gc291cmNlUGF0aCBTb3VyY2UgZmlsZSBwYXRoXG4gICAqIEBwYXJhbSBkZXN0UGF0aCBEZXN0aW5hdGlvbiBmaWxlIHBhdGhcbiAgICogQHRocm93cyBFcnJvciBpZiBjb3B5IGZhaWxzIGFmdGVyIGFsbCByZXRyeSBhdHRlbXB0c1xuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBjb3B5RmlsZVdpdGhWZXJpZmljYXRpb24oc291cmNlUGF0aDogc3RyaW5nLCBkZXN0UGF0aDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgbGV0IGxhc3RFcnJvcjogRXJyb3IgfCBudWxsID0gbnVsbDtcbiAgICBcbiAgICBmb3IgKGxldCBhdHRlbXB0ID0gMTsgYXR0ZW1wdCA8PSBDT1BZX1JFVFJZX0FUVEVNUFRTOyBhdHRlbXB0KyspIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIC8vIENvcHkgdGhlIGZpbGVcbiAgICAgICAgYXdhaXQgZnMuY29weUZpbGUoc291cmNlUGF0aCwgZGVzdFBhdGgpO1xuICAgICAgICBcbiAgICAgICAgLy8gVmVyaWZ5IHNpemUgbWF0Y2hlc1xuICAgICAgICBjb25zdCBbc291cmNlU3RhdHMsIGRlc3RTdGF0c10gPSBhd2FpdCBQcm9taXNlLmFsbChbXG4gICAgICAgICAgZnMuc3RhdChzb3VyY2VQYXRoKSxcbiAgICAgICAgICBmcy5zdGF0KGRlc3RQYXRoKVxuICAgICAgICBdKTtcbiAgICAgICAgXG4gICAgICAgIGlmIChzb3VyY2VTdGF0cy5zaXplICE9PSBkZXN0U3RhdHMuc2l6ZSkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICAgIGBTaXplIG1pc21hdGNoIGFmdGVyIGNvcHkgLSBzb3VyY2U6ICR7c291cmNlU3RhdHMuc2l6ZX0gYnl0ZXMsIGAgK1xuICAgICAgICAgICAgYGRlc3RpbmF0aW9uOiAke2Rlc3RTdGF0cy5zaXplfSBieXRlc2BcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICAgIFxuICAgICAgICAvLyBWZXJpZnkgY2hlY2tzdW0gbWF0Y2hlcyBmb3IgY29tcGxldGUgaW50ZWdyaXR5XG4gICAgICAgIGNvbnN0IFtzb3VyY2VDaGVja3N1bSwgZGVzdENoZWNrc3VtXSA9IGF3YWl0IFByb21pc2UuYWxsKFtcbiAgICAgICAgICB0aGlzLmNhbGN1bGF0ZUNoZWNrc3VtKHNvdXJjZVBhdGgpLFxuICAgICAgICAgIHRoaXMuY2FsY3VsYXRlQ2hlY2tzdW0oZGVzdFBhdGgpXG4gICAgICAgIF0pO1xuICAgICAgICBcbiAgICAgICAgaWYgKHNvdXJjZUNoZWNrc3VtICE9PSBkZXN0Q2hlY2tzdW0pIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgICBgQ2hlY2tzdW0gbWlzbWF0Y2ggYWZ0ZXIgY29weSAtIHNvdXJjZTogJHtzb3VyY2VDaGVja3N1bX0sIGAgK1xuICAgICAgICAgICAgYGRlc3RpbmF0aW9uOiAke2Rlc3RDaGVja3N1bX1gXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgICBcbiAgICAgICAgLy8gU2V0IHByb3BlciBwZXJtaXNzaW9uc1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGF3YWl0IGZzLmNobW9kKGRlc3RQYXRoLCBGSUxFX0NPTlNUQU5UUy5GSUxFX1BFUk1JU1NJT05TKTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICBsb2dnZXIuZGVidWcoXG4gICAgICAgICAgICBgW0RlZmF1bHRFbGVtZW50UHJvdmlkZXJdIENvdWxkIG5vdCBzZXQgcGVybWlzc2lvbnMgb24gJHtkZXN0UGF0aH06ICR7ZXJyb3J9YCxcbiAgICAgICAgICAgIHsgc291cmNlUGF0aCwgZGVzdFBhdGgsIGF0dGVtcHQgfVxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgICAgXG4gICAgICAgIC8vIFN1Y2Nlc3MgLSBmaWxlIGNvcGllZCBhbmQgdmVyaWZpZWRcbiAgICAgICAgbG9nZ2VyLmRlYnVnKFxuICAgICAgICAgIGBbRGVmYXVsdEVsZW1lbnRQcm92aWRlcl0gU3VjY2Vzc2Z1bGx5IGNvcGllZCBhbmQgdmVyaWZpZWQ6ICR7cGF0aC5iYXNlbmFtZShzb3VyY2VQYXRoKX1gLFxuICAgICAgICAgIHsgc2l6ZTogc291cmNlU3RhdHMuc2l6ZSwgY2hlY2tzdW06IHNvdXJjZUNoZWNrc3VtLnN1YnN0cmluZygwLCA4KSB9XG4gICAgICAgICk7XG4gICAgICAgIHJldHVybjtcbiAgICAgICAgXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBsYXN0RXJyb3IgPSBlcnJvciBhcyBFcnJvcjtcbiAgICAgICAgXG4gICAgICAgIC8vIENsZWFuIHVwIGZhaWxlZCBjb3B5XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgYXdhaXQgZnMudW5saW5rKGRlc3RQYXRoKTtcbiAgICAgICAgfSBjYXRjaCB7XG4gICAgICAgICAgLy8gSWdub3JlIGNsZWFudXAgZXJyb3JzXG4gICAgICAgIH1cbiAgICAgICAgXG4gICAgICAgIGlmIChhdHRlbXB0IDwgQ09QWV9SRVRSWV9BVFRFTVBUUykge1xuICAgICAgICAgIGxvZ2dlci5kZWJ1ZyhcbiAgICAgICAgICAgIGBbRGVmYXVsdEVsZW1lbnRQcm92aWRlcl0gQ29weSBhdHRlbXB0ICR7YXR0ZW1wdH0gZmFpbGVkLCByZXRyeWluZy4uLmAsXG4gICAgICAgICAgICB7IGVycm9yOiBsYXN0RXJyb3IubWVzc2FnZSwgc291cmNlUGF0aCwgZGVzdFBhdGggfVxuICAgICAgICAgICk7XG4gICAgICAgICAgYXdhaXQgbmV3IFByb21pc2UocmVzb2x2ZSA9PiBzZXRUaW1lb3V0KHJlc29sdmUsIENPUFlfUkVUUllfREVMQVkgKiBhdHRlbXB0KSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgLy8gQWxsIGF0dGVtcHRzIGZhaWxlZFxuICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgIGBGYWlsZWQgdG8gY29weSAke3BhdGguYmFzZW5hbWUoc291cmNlUGF0aCl9IGFmdGVyICR7Q09QWV9SRVRSWV9BVFRFTVBUU30gYXR0ZW1wdHM6IGAgK1xuICAgICAgYCR7bGFzdEVycm9yPy5tZXNzYWdlIHx8ICdVbmtub3duIGVycm9yJ31gXG4gICAgKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIFBvcHVsYXRlIHRoZSBwb3J0Zm9saW8gd2l0aCBkZWZhdWx0IGVsZW1lbnRzIGZyb20gYnVuZGxlZCBkYXRhXG4gICAqIFRoaXMgaXMgY2FsbGVkIGR1cmluZyBwb3J0Zm9saW8gaW5pdGlhbGl6YXRpb24gZm9yIG5ldyBpbnN0YWxsYXRpb25zXG4gICAqIFByb3RlY3RlZCBhZ2FpbnN0IGNvbmN1cnJlbnQgY2FsbHMgdG8gcHJldmVudCByYWNlIGNvbmRpdGlvbnNcbiAgICovXG4gIHB1YmxpYyBhc3luYyBwb3B1bGF0ZURlZmF1bHRzKHBvcnRmb2xpb0Jhc2VEaXI6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgIC8vIENoZWNrIGlmIHBvcHVsYXRpb24gaXMgYWxyZWFkeSBpbiBwcm9ncmVzcyBmb3IgdGhpcyBwb3J0Zm9saW9cbiAgICBjb25zdCBleGlzdGluZ1BvcHVsYXRpb24gPSBEZWZhdWx0RWxlbWVudFByb3ZpZGVyLnBvcHVsYXRlSW5Qcm9ncmVzcy5nZXQocG9ydGZvbGlvQmFzZURpcik7XG4gICAgaWYgKGV4aXN0aW5nUG9wdWxhdGlvbikge1xuICAgICAgbG9nZ2VyLmRlYnVnKFxuICAgICAgICAnW0RlZmF1bHRFbGVtZW50UHJvdmlkZXJdIFBvcHVsYXRpb24gYWxyZWFkeSBpbiBwcm9ncmVzcyBmb3IgcG9ydGZvbGlvLCB3YWl0aW5nLi4uJyxcbiAgICAgICAgeyBwb3J0Zm9saW9CYXNlRGlyIH1cbiAgICAgICk7XG4gICAgICByZXR1cm4gZXhpc3RpbmdQb3B1bGF0aW9uO1xuICAgIH1cbiAgICBcbiAgICAvLyBDcmVhdGUgbmV3IHBvcHVsYXRpb24gcHJvbWlzZVxuICAgIGNvbnN0IHBvcHVsYXRpb25Qcm9taXNlID0gdGhpcy5wZXJmb3JtUG9wdWxhdGlvbihwb3J0Zm9saW9CYXNlRGlyKVxuICAgICAgLmZpbmFsbHkoKCkgPT4ge1xuICAgICAgICAvLyBDbGVhbiB1cCB3aGVuIGRvbmVcbiAgICAgICAgRGVmYXVsdEVsZW1lbnRQcm92aWRlci5wb3B1bGF0ZUluUHJvZ3Jlc3MuZGVsZXRlKHBvcnRmb2xpb0Jhc2VEaXIpO1xuICAgICAgfSk7XG4gICAgXG4gICAgRGVmYXVsdEVsZW1lbnRQcm92aWRlci5wb3B1bGF0ZUluUHJvZ3Jlc3Muc2V0KHBvcnRmb2xpb0Jhc2VEaXIsIHBvcHVsYXRpb25Qcm9taXNlKTtcbiAgICByZXR1cm4gcG9wdWxhdGlvblByb21pc2U7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBQZXJmb3JtIHRoZSBhY3R1YWwgcG9wdWxhdGlvbiBvZiBkZWZhdWx0IGVsZW1lbnRzXG4gICAqIEBwYXJhbSBwb3J0Zm9saW9CYXNlRGlyIEJhc2UgZGlyZWN0b3J5IG9mIHRoZSBwb3J0Zm9saW9cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgcGVyZm9ybVBvcHVsYXRpb24ocG9ydGZvbGlvQmFzZURpcjogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgbG9nZ2VyLmluZm8oXG4gICAgICAnW0RlZmF1bHRFbGVtZW50UHJvdmlkZXJdIFN0YXJ0aW5nIGRlZmF1bHQgZWxlbWVudCBwb3B1bGF0aW9uJyxcbiAgICAgIHsgcG9ydGZvbGlvQmFzZURpciB9XG4gICAgKTtcbiAgICBcbiAgICAvLyBMb2cgc2VjdXJpdHkgZXZlbnQgZm9yIHBvcnRmb2xpbyBpbml0aWFsaXphdGlvblxuICAgIFNlY3VyaXR5TW9uaXRvci5sb2dTZWN1cml0eUV2ZW50KHtcbiAgICAgIHR5cGU6ICdQT1JURk9MSU9fSU5JVElBTElaQVRJT04nLFxuICAgICAgc2V2ZXJpdHk6ICdMT1cnLFxuICAgICAgc291cmNlOiAnRGVmYXVsdEVsZW1lbnRQcm92aWRlci5wZXJmb3JtUG9wdWxhdGlvbicsXG4gICAgICBkZXRhaWxzOiBgU3RhcnRpbmcgZGVmYXVsdCBlbGVtZW50IHBvcHVsYXRpb24gZm9yIHBvcnRmb2xpbzogJHtwb3J0Zm9saW9CYXNlRGlyfWBcbiAgICB9KTtcbiAgICBcbiAgICAvLyBGaW5kIHRoZSBidW5kbGVkIGRhdGEgZGlyZWN0b3J5XG4gICAgY29uc3QgZGF0YURpciA9IGF3YWl0IHRoaXMuZmluZERhdGFEaXJlY3RvcnkoKTtcbiAgICBpZiAoIWRhdGFEaXIpIHtcbiAgICAgIGxvZ2dlci53YXJuKFxuICAgICAgICAnW0RlZmF1bHRFbGVtZW50UHJvdmlkZXJdIE5vIGJ1bmRsZWQgZGF0YSBkaXJlY3RvcnkgZm91bmQgLSBwb3J0Zm9saW8gd2lsbCBzdGFydCBlbXB0eScsXG4gICAgICAgIHsgXG4gICAgICAgICAgc2VhcmNoUGF0aHM6IHRoaXMuZGF0YVNlYXJjaFBhdGhzLnNsaWNlKDAsIDMpLCAvLyBMb2cgZmlyc3QgZmV3IHBhdGhzIGZvciBkZWJ1Z2dpbmdcbiAgICAgICAgICBjd2Q6IHByb2Nlc3MuY3dkKCksXG4gICAgICAgICAgZGlybmFtZTogdGhpcy5fX2Rpcm5hbWVcbiAgICAgICAgfVxuICAgICAgKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgXG4gICAgLy8gVHJhY2sgdG90YWwgZmlsZXMgY29waWVkXG4gICAgbGV0IHRvdGFsQ29waWVkID0gMDtcbiAgICBjb25zdCBjb3BpZWRDb3VudHM6IFJlY29yZDxzdHJpbmcsIG51bWJlcj4gPSB7fTtcbiAgICBcbiAgICAvLyBDb3B5IGVhY2ggZWxlbWVudCB0eXBlIC0gZGlyZWN0b3JpZXMgbm93IG1hdGNoIGVudW0gdmFsdWVzIChhbGwgcGx1cmFsKVxuICAgIGZvciAoY29uc3QgZWxlbWVudFR5cGUgb2YgT2JqZWN0LnZhbHVlcyhFbGVtZW50VHlwZSkpIHtcbiAgICAgIGNvbnN0IHNvdXJjZURpciA9IHBhdGguam9pbihkYXRhRGlyLCBlbGVtZW50VHlwZSk7XG4gICAgICBjb25zdCBkZXN0RGlyID0gcGF0aC5qb2luKHBvcnRmb2xpb0Jhc2VEaXIsIGVsZW1lbnRUeXBlKTtcbiAgICAgIFxuICAgICAgdHJ5IHtcbiAgICAgICAgLy8gQ2hlY2sgaWYgc291cmNlIGRpcmVjdG9yeSBleGlzdHNcbiAgICAgICAgYXdhaXQgZnMuYWNjZXNzKHNvdXJjZURpcik7XG4gICAgICAgIGNvbnN0IGNvcGllZENvdW50ID0gYXdhaXQgdGhpcy5jb3B5RWxlbWVudEZpbGVzKHNvdXJjZURpciwgZGVzdERpciwgZWxlbWVudFR5cGUpO1xuICAgICAgICBjb3BpZWRDb3VudHNbZWxlbWVudFR5cGVdID0gY29waWVkQ291bnQ7XG4gICAgICAgIHRvdGFsQ29waWVkICs9IGNvcGllZENvdW50O1xuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgLy8gU291cmNlIGRpcmVjdG9yeSBkb2Vzbid0IGV4aXN0LCBza2lwXG4gICAgICAgIGxvZ2dlci5kZWJ1ZyhgW0RlZmF1bHRFbGVtZW50UHJvdmlkZXJdIE5vICR7ZWxlbWVudFR5cGV9IGRpcmVjdG9yeSBpbiBidW5kbGVkIGRhdGFgKTtcbiAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgaWYgKHRvdGFsQ29waWVkID4gMCkge1xuICAgICAgbG9nZ2VyLmluZm8oXG4gICAgICAgIGBbRGVmYXVsdEVsZW1lbnRQcm92aWRlcl0gU3VjY2Vzc2Z1bGx5IHBvcHVsYXRlZCBwb3J0Zm9saW8gd2l0aCAke3RvdGFsQ29waWVkfSBkZWZhdWx0IGVsZW1lbnQocylgLFxuICAgICAgICB7XG4gICAgICAgICAgcG9ydGZvbGlvQmFzZURpcixcbiAgICAgICAgICBkYXRhRGlyLFxuICAgICAgICAgIGJyZWFrZG93bjogY29waWVkQ291bnRzXG4gICAgICAgIH1cbiAgICAgICk7XG4gICAgICBcbiAgICAgIC8vIExvZyBzZWN1cml0eSBldmVudCBmb3Igc3VjY2Vzc2Z1bCBwb3B1bGF0aW9uXG4gICAgICBTZWN1cml0eU1vbml0b3IubG9nU2VjdXJpdHlFdmVudCh7XG4gICAgICAgIHR5cGU6ICdQT1JURk9MSU9fUE9QVUxBVEVEJyxcbiAgICAgICAgc2V2ZXJpdHk6ICdMT1cnLFxuICAgICAgICBzb3VyY2U6ICdEZWZhdWx0RWxlbWVudFByb3ZpZGVyLnBlcmZvcm1Qb3B1bGF0aW9uJyxcbiAgICAgICAgZGV0YWlsczogYFN1Y2Nlc3NmdWxseSBwb3B1bGF0ZWQgcG9ydGZvbGlvIHdpdGggJHt0b3RhbENvcGllZH0gZGVmYXVsdCBlbGVtZW50c2AsXG4gICAgICAgIG1ldGFkYXRhOiB7XG4gICAgICAgICAgcG9ydGZvbGlvQmFzZURpcixcbiAgICAgICAgICBkYXRhRGlyLFxuICAgICAgICAgIGNvcGllZENvdW50c1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9IGVsc2Uge1xuICAgICAgbG9nZ2VyLmluZm8oJ1tEZWZhdWx0RWxlbWVudFByb3ZpZGVyXSBObyBuZXcgZWxlbWVudHMgdG8gY29weSAtIHBvcnRmb2xpbyBtYXkgYWxyZWFkeSBoYXZlIGNvbnRlbnQnKTtcbiAgICB9XG4gIH1cbn0iXX0=
878
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRGVmYXVsdEVsZW1lbnRQcm92aWRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9wb3J0Zm9saW8vRGVmYXVsdEVsZW1lbnRQcm92aWRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7O0dBTUc7QUFFSCxPQUFPLEtBQUssRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUNsQyxPQUFPLEtBQUssTUFBTSxNQUFNLElBQUksQ0FBQztBQUM3QixPQUFPLEtBQUssSUFBSSxNQUFNLE1BQU0sQ0FBQztBQUM3QixPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sS0FBSyxDQUFDO0FBQ3BDLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxRQUFRLENBQUM7QUFFcEMsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQzVDLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFDekMsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sNENBQTRDLENBQUM7QUFDOUUsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBQ2pFLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBRW5FLDJCQUEyQjtBQUMzQixNQUFNLENBQUMsTUFBTSxjQUFjLEdBQUc7SUFDNUIsaUJBQWlCLEVBQUUsS0FBSztJQUN4QixjQUFjLEVBQUUsT0FBTztJQUN2QixhQUFhLEVBQUUsTUFBTTtJQUNyQixjQUFjLEVBQUUsT0FBTztJQUN2QixhQUFhLEVBQUUsRUFBRSxHQUFHLElBQUksR0FBRyxJQUFJLEVBQUUsZ0NBQWdDO0lBQ2pFLGtCQUFrQixFQUFFLFFBQVE7SUFDNUIsZ0JBQWdCLEVBQUUsS0FBSztJQUN2QixVQUFVLEVBQUUsRUFBRSxHQUFHLElBQUksQ0FBQyxzQ0FBc0M7Q0FDcEQsQ0FBQztBQUVYLDZCQUE2QjtBQUM3QixzRUFBc0U7QUFDdEUsTUFBTSxtQkFBbUIsR0FBRyxD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WUFDdkYsQ0FBQztRQUNILENBQUM7UUFFRCxJQUFJLFdBQVcsR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUNwQixNQUFNLENBQUMsSUFBSSxDQUNULGtFQUFrRSxXQUFXLHFCQUFxQixFQUNsRztnQkFDRSxnQkFBZ0I7Z0JBQ2hCLE9BQU87Z0JBQ1AsU0FBUyxFQUFFLFlBQVk7YUFDeEIsQ0FDRixDQUFDO1lBRUYsK0NBQStDO1lBQy9DLGVBQWUsQ0FBQyxnQkFBZ0IsQ0FBQztnQkFDL0IsSUFBSSxFQUFFLHFCQUFxQjtnQkFDM0IsUUFBUSxFQUFFLEtBQUs7Z0JBQ2YsTUFBTSxFQUFFLDBDQUEwQztnQkFDbEQsT0FBTyxFQUFFLHlDQUF5QyxXQUFXLG1CQUFtQjtnQkFDaEYsUUFBUSxFQUFFO29CQUNSLGdCQUFnQjtvQkFDaEIsT0FBTztvQkFDUCxZQUFZO2lCQUNiO2FBQ0YsQ0FBQyxDQUFDO1FBQ0wsQ0FBQzthQUFNLENBQUM7WUFDTixNQUFNLENBQUMsSUFBSSxDQUFDLHVGQUF1RixDQUFDLENBQUM7UUFDdkcsQ0FBQztJQUNILENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIERlZmF1bHRFbGVtZW50UHJvdmlkZXIgLSBQb3B1bGF0ZXMgcG9ydGZvbGlvIHdpdGggZGVmYXVsdCBlbGVtZW50cyBmcm9tIGJ1bmRsZWQgZGF0YVxuICogXG4gKiBUaGlzIGNsYXNzIGhhbmRsZXMgY29weWluZyBkZWZhdWx0IHBlcnNvbmFzLCBza2lsbHMsIHRlbXBsYXRlcywgYW5kIG90aGVyIGVsZW1lbnRzXG4gKiBmcm9tIHRoZSBOUE0gcGFja2FnZSBvciBHaXQgcmVwb3NpdG9yeSB0byB0aGUgdXNlcidzIHBvcnRmb2xpbyBvbiBmaXJzdCBydW4uXG4gKiBJdCBlbnN1cmVzIHVzZXJzIGhhdmUgZXhhbXBsZSBjb250ZW50IHRvIHdvcmsgd2l0aCBpbW1lZGlhdGVseSBhZnRlciBpbnN0YWxsYXRpb24uXG4gKi9cblxuaW1wb3J0ICogYXMgZnMgZnJvbSAnZnMvcHJvbWlzZXMnO1xuaW1wb3J0ICogYXMgZnNTeW5jIGZyb20gJ2ZzJztcbmltcG9ydCAqIGFzIHBhdGggZnJvbSAncGF0aCc7XG5pbXBvcnQgeyBmaWxlVVJMVG9QYXRoIH0gZnJvbSAndXJsJztcbmltcG9ydCB7IGNyZWF0ZUhhc2ggfSBmcm9tICdjcnlwdG8nO1xuaW1wb3J0ICogYXMgeWFtbCBmcm9tICdqcy15YW1sJztcbmltcG9ydCB7IGxvZ2dlciB9IGZyb20gJy4uL3V0aWxzL2xvZ2dlci5qcyc7XG5pbXBvcnQgeyBFbGVtZW50VHlwZSB9IGZyb20gJy4vdHlwZXMuanMnO1xuaW1wb3J0IHsgVW5pY29kZVZhbGlkYXRvciB9IGZyb20gJy4uL3NlY3VyaXR5L3ZhbGlkYXRvcnMvdW5pY29kZVZhbGlkYXRvci5qcyc7XG5pbXBvcnQgeyBTZWN1cml0eU1vbml0b3IgfSBmcm9tICcuLi9zZWN1cml0eS9zZWN1cml0eU1vbml0b3IuanMnO1xuaW1wb3J0IHsgU2VjdXJlWWFtbFBhcnNlciB9IGZyb20gJy4uL3NlY3VyaXR5L3NlY3VyZVlhbWxQYXJzZXIuanMnO1xuXG4vLyBGaWxlIG9wZXJhdGlvbiBjb25zdGFudHNcbmV4cG9ydCBjb25zdCBGSUxFX0NPTlNUQU5UUyA9IHtcbiAgRUxFTUVOVF9FWFRFTlNJT046ICcubWQnLFxuICBZQU1MX0VYVEVOU0lPTjogJy55YW1sJyxcbiAgWU1MX0VYVEVOU0lPTjogJy55bWwnLFxuICBKU09OX0VYVEVOU0lPTjogJy5qc29uJyxcbiAgTUFYX0ZJTEVfU0laRTogMTAgKiAxMDI0ICogMTAyNCwgLy8gMTBNQiBtYXggZmlsZSBzaXplIGZvciBzYWZldHlcbiAgQ0hFQ0tTVU1fQUxHT1JJVEhNOiAnc2hhMjU2JyxcbiAgRklMRV9QRVJNSVNTSU9OUzogMG82NDQsXG4gIENIVU5LX1NJWkU6IDY0ICogMTAyNCAvLyA2NEtCIGNodW5rcyBmb3IgcmVhZGluZyBsYXJnZSBmaWxlc1xufSBhcyBjb25zdDtcblxuLy8gRGV2ZWxvcG1lbnQgbW9kZSBkZXRlY3Rpb25cbi8vIFdoZW4gcnVubmluZyBmcm9tIGEgZ2l0IGNsb25lLCB3ZSBkb24ndCB3YW50IHRvIGF1dG8tbG9hZCB0ZXN0IGRhdGFcbmNvbnN0IElTX0RFVkVMT1BNRU5UX01PREUgPSAoKCkgPT4ge1xuICB0cnkge1xuICAgIC8vIENoZWNrIGlmIHdlJ3JlIGluIGEgZ2l0IHJlcG9zaXRvcnkgKGRldmVsb3BtZW50IG1vZGUpXG4gICAgY29uc3QgZ2l0RGlyID0gcGF0aC5qb2luKHByb2Nlc3MuY3dkKCksICcuZ2l0Jyk7XG4gICAgcmV0dXJuIGZzU3luYy5leGlzdHNTeW5jKGdpdERpcik7XG4gIH0gY2F0Y2gge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxufSkoKTtcblxuLy8gSW50ZXJuYWwgY29uc3RhbnRzXG5jb25zdCBEQVRBX0RJUl9DQUNIRV9LRVkgPSAnZG9sbGhvdXNlX2RhdGFfZGlyJztcbmNvbnN0IENPUFlfUkVUUllfQVRURU1QVFMgPSAzO1xuY29uc3QgQ09QWV9SRVRSWV9ERUxBWSA9IDEwMDsgLy8gbXNcblxuZXhwb3J0IGludGVyZmFjZSBEZWZhdWx0RWxlbWVudFByb3ZpZGVyQ29uZmlnIHtcbiAgLyoqIEN1c3RvbSBkYXRhIGRpcmVjdG9yeSBwYXRocyB0byBzZWFyY2ggKGNoZWNrZWQgYmVmb3JlIGRlZmF1bHQgcGF0aHMpICovXG4gIGN1c3RvbURhdGFQYXRocz86IHN0cmluZ1tdO1xuICAvKiogV2hldGhlciB0byB1c2UgZGVmYXVsdCBzZWFyY2ggcGF0aHMgYWZ0ZXIgY3VzdG9tIHBhdGhzICovXG4gIHVzZURlZmF1bHRQYXRocz86IGJvb2xlYW47XG4gIC8qKiBXaGV0aGVyIHRvIGxvYWQgdGVzdC9leGFtcGxlIGRhdGEgZnJvbSByZXBvc2l0b3J5IChkZWZhdWx0OiBmYWxzZSBpbiBkZXYgbW9kZSkgKi9cbiAgbG9hZFRlc3REYXRhPzogYm9vbGVhbjtcbn1cblxuLy8gUEVSRk9STUFOQ0U6IE1ldGFkYXRhIGNhY2hlIHdpdGggbXRpbWUtYmFzZWQgaW52YWxpZGF0aW9uXG5pbnRlcmZhY2UgTWV0YWRhdGFDYWNoZUVudHJ5IHtcbiAgbWV0YWRhdGE6IGFueTtcbiAgbXRpbWU6IG51bWJlcjtcbiAgc2l6ZTogbnVtYmVyO1xufVxuXG5leHBvcnQgY2xhc3MgRGVmYXVsdEVsZW1lbnRQcm92aWRlciB7XG4gIHByaXZhdGUgcmVhZG9ubHkgX19kaXJuYW1lOiBzdHJpbmc7XG4gIHByaXZhdGUgc3RhdGljIGNhY2hlZERhdGFEaXI6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIHN0YXRpYyBwb3B1bGF0ZUluUHJvZ3Jlc3M6IE1hcDxzdHJpbmcsIFByb21pc2U8dm9pZD4+ID0gbmV3IE1hcCgpO1xuICBwcml2YXRlIHJlYWRvbmx5IGNvbmZpZzogRGVmYXVsdEVsZW1lbnRQcm92aWRlckNvbmZpZztcbiAgXG4gIC8vIFBFUkZPUk1BTkNFIE9QVElNSVpBVElPTjogQ2FjaGUgbWV0YWRhdGEgd2l0aCBmaWxlIG10aW1lIGZvciBpbnZhbGlkYXRpb25cbiAgcHJpdmF0ZSBzdGF0aWMgbWV0YWRhdGFDYWNoZTogTWFwPHN0cmluZywgTWV0YWRhdGFDYWNoZUVudHJ5PiA9IG5ldyBNYXAoKTtcbiAgcHJpdmF0ZSBzdGF0aWMgcmVhZG9ubHkgTUFYX0NBQ0hFX1NJWkUgPSAyMDsgLy8gTUVNT1JZIExFQUsgRklYOiBGdXJ0aGVyIHJlZHVjZWQgY2FjaGUgc2l6ZSB0byBwcmV2ZW50IGFjY3VtdWxhdGlvbiBkdXJpbmcgcGVyZm9ybWFuY2UgdGVzdHNcbiAgXG4gIGNvbnN0cnVjdG9yKGNvbmZpZz86IERlZmF1bHRFbGVtZW50UHJvdmlkZXJDb25maWcpIHtcbiAgICBjb25zdCBfX2ZpbGVuYW1lID0gZmlsZVVSTFRvUGF0aChpbXBvcnQubWV0YS51cmwpO1xuICAgIHRoaXMuX19kaXJuYW1lID0gcGF0aC5kaXJuYW1lKF9fZmlsZW5hbWUpO1xuICAgIFxuICAgIC8vIENoZWNrIGVudmlyb25tZW50IHZhcmlhYmxlIGZvciB0ZXN0IGRhdGEgbG9hZGluZ1xuICAgIGNvbnN0IGVudkxvYWRUZXN0RGF0YSA9IHByb2Nlc3MuZW52LkRPTExIT1VTRV9MT0FEX1RFU1RfREFUQTtcbiAgICBjb25zdCBsb2FkVGVzdERhdGFGcm9tRW52ID0gZW52TG9hZFRlc3REYXRhID09PSAndHJ1ZScgfHwgZW52TG9hZFRlc3REYXRhID09PSAnMSc7XG4gICAgY29uc3QgZGlzYWJsZVRlc3REYXRhRnJvbUVudiA9IGVudkxvYWRUZXN0RGF0YSA9PT0gJ2ZhbHNlJyB8fCBlbnZMb2FkVGVzdERhdGEgPT09ICcwJztcbiAgICBcbiAgICAvLyBDaGVjayBpZiB3ZSdyZSBpbiBkZXZlbG9wbWVudCBtb2RlICh3aXRoIHJlc3BlY3QgdG8gRk9SQ0VfUFJPRFVDVElPTl9NT0RFIG92ZXJyaWRlKVxuICAgIGNvbnN0IGlzRGV2TW9kZSA9ICgoKSA9PiB7XG4gICAgICAvLyBSZXNwZWN0IEZPUkNFX1BST0RVQ1RJT05fTU9ERSBvdmVycmlkZSBmaXJzdFxuICAgICAgaWYgKHByb2Nlc3MuZW52LkZPUkNFX1BST0RVQ1RJT05fTU9ERSA9PT0gJ3RydWUnKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTsgLy8gRm9yY2UgcHJvZHVjdGlvbiBtb2RlXG4gICAgICB9XG4gICAgICBpZiAocHJvY2Vzcy5lbnYuRk9SQ0VfUFJPRFVDVElPTl9NT0RFID09PSAnZmFsc2UnKSB7XG4gICAgICAgIHJldHVybiB0cnVlOyAvLyBGb3JjZSBkZXZlbG9wbWVudCBtb2RlXG4gICAgICB9XG4gICAgICAvLyBGYWxsIGJhY2sgdG8gZ2l0IGRldGVjdGlvblxuICAgICAgcmV0dXJuIElTX0RFVkVMT1BNRU5UX01PREU7XG4gICAgfSkoKTtcbiAgICBcbiAgICAvLyBEZXRlcm1pbmUgbG9hZFRlc3REYXRhIHZhbHVlXG4gICAgbGV0IGNvbXB1dGVkTG9hZFRlc3REYXRhOiBib29sZWFuO1xuICAgIGlmIChsb2FkVGVzdERhdGFGcm9tRW52KSB7XG4gICAgICAvLyBFbnZpcm9ubWVudCBleHBsaWNpdGx5IGVuYWJsZXMgdGVzdCBkYXRhXG4gICAgICBjb21wdXRlZExvYWRUZXN0RGF0YSA9IHRydWU7XG4gICAgfSBlbHNlIGlmIChkaXNhYmxlVGVzdERhdGFGcm9tRW52KSB7XG4gICAgICAvLyBFbnZpcm9ubWVudCBleHBsaWNpdGx5IGRpc2FibGVzIHRlc3QgZGF0YVxuICAgICAgY29tcHV0ZWRMb2FkVGVzdERhdGEgPSBmYWxzZTtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gRGVmYXVsdCBsb2dpYzogZW5hYmxlIGluIHByb2R1Y3Rpb24sIGRpc2FibGUgaW4gZGV2ZWxvcG1lbnQgdW5sZXNzIGNvbmZpZyBvdmVycmlkZXNcbiAgICAgIGNvbXB1dGVkTG9hZFRlc3REYXRhID0gIWlzRGV2TW9kZSAmJiAoY29uZmlnPy5sb2FkVGVzdERhdGEgPz8gdHJ1ZSk7XG4gICAgfVxuICAgIFxuICAgIHRoaXMuY29uZmlnID0ge1xuICAgICAgdXNlRGVmYXVsdFBhdGhzOiB0cnVlLFxuICAgICAgLi4uY29uZmlnLFxuICAgICAgLy8gQXBwbHkgZmluYWwgbG9hZFRlc3REYXRhIGxvZ2ljIC0gZW52aXJvbm1lbnQgdmFyaWFibGVzIGFuZCBkZXZlbG9wbWVudCBtb2RlIHRha2UgcHJlY2VkZW5jZVxuICAgICAgbG9hZFRlc3REYXRhOiBsb2FkVGVzdERhdGFGcm9tRW52ID8gdHJ1ZSA6IGRpc2FibGVUZXN0RGF0YUZyb21FbnYgPyBmYWxzZSA6IGNvbXB1dGVkTG9hZFRlc3REYXRhXG4gICAgfTtcbiAgICBcbiAgICBpZiAoaXNEZXZNb2RlICYmICF0aGlzLmNvbmZpZy5sb2FkVGVzdERhdGEpIHtcbiAgICAgIGxvZ2dlci5pbmZvKCdbRGVmYXVsdEVsZW1lbnRQcm92aWRlcl0gRGV2ZWxvcG1lbnQgbW9kZSBkZXRlY3RlZCAtIHRlc3QgZGF0YSBsb2FkaW5nIGRpc2FibGVkJyk7XG4gICAgICBsb2dnZXIuaW5mbygnW0RlZmF1bHRFbGVtZW50UHJvdmlkZXJdIFRvIGVuYWJsZSB0ZXN0IGRhdGEsIHNldCBET0xMSE9VU0VfTE9BRF9URVNUX0RBVEE9dHJ1ZScpO1xuICAgIH1cbiAgfVxuICBcbiAgLyoqXG4gICAqIEdldCB0aGUgY3VycmVudCBsb2FkVGVzdERhdGEgY29uZmlndXJhdGlvbiB2YWx1ZVxuICAgKiBAcmV0dXJucyBXaGV0aGVyIHRlc3QgZGF0YSBsb2FkaW5nIGlzIGVuYWJsZWRcbiAgICovXG4gIHB1YmxpYyBnZXQgaXNUZXN0RGF0YUxvYWRpbmdFbmFibGVkKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmNvbmZpZy5sb2FkVGVzdERhdGEgPz8gZmFsc2U7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZXQgd2hldGhlciB0aGUgc3lzdGVtIGlzIGluIGRldmVsb3BtZW50IG1vZGVcbiAgICogQHJldHVybnMgV2hldGhlciBydW5uaW5nIGluIGRldmVsb3BtZW50IG1vZGVcbiAgICovXG4gIHB1YmxpYyBnZXQgaXNEZXZlbG9wbWVudE1vZGUoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIElTX0RFVkVMT1BNRU5UX01PREU7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBTZWFyY2ggcGF0aHMgZm9yIGJ1bmRsZWQgZGF0YSBkaXJlY3RvcnlcbiAgICogT3JkZXJlZCBieSBwcmlvcml0eSAtIGN1c3RvbSBwYXRocyBmaXJzdCwgdGhlbiBkZXZlbG9wbWVudC9naXQsIHRoZW4gTlBNIGxvY2F0aW9uc1xuICAgKi9cbiAgcHJpdmF0ZSBnZXQgZGF0YVNlYXJjaFBhdGhzKCk6IHN0cmluZ1tdIHtcbiAgICBjb25zdCBwYXRoczogc3RyaW5nW10gPSBbXTtcbiAgICBcbiAgICAvLyBBZGQgY3VzdG9tIHBhdGhzIGZpcnN0IChoaWdoZXN0IHByaW9yaXR5KVxuICAgIGlmICh0aGlzLmNvbmZpZy5jdXN0b21EYXRhUGF0aHMpIHtcbiAgICAgIHBhdGhzLnB1c2goLi4udGhpcy5jb25maWcuY3VzdG9tRGF0YVBhdGhzKTtcbiAgICB9XG4gICAgXG4gICAgLy8gQWRkIGRlZmF1bHQgcGF0aHMgaWYgZW5hYmxlZFxuICAgIGlmICh0aGlzLmNvbmZpZy51c2VEZWZhdWx0UGF0aHMgIT09IGZhbHNlKSB7XG4gICAgICAvLyBTa2lwIGRldmVsb3BtZW50L3JlcG9zaXRvcnkgZGF0YSBwYXRocyB1bmxlc3MgdGVzdCBkYXRhIGxvYWRpbmcgaXMgZW5hYmxlZFxuICAgICAgaWYgKHRoaXMuY29uZmlnLmxvYWRUZXN0RGF0YSkge1xuICAgICAgICAvLyBEZXZlbG9wbWVudC9HaXQgaW5zdGFsbGF0aW9uIChyZWxhdGl2ZSB0byB0aGlzIGZpbGUpXG4gICAgICAgIHBhdGhzLnB1c2goXG4gICAgICAgICAgcGF0aC5qb2luKHRoaXMuX19kaXJuYW1lLCAnLi4vLi4vZGF0YScpLFxuICAgICAgICAgIHBhdGguam9pbih0aGlzLl9fZGlybmFtZSwgJy4uLy4uLy4uL2RhdGEnKSxcbiAgICAgICAgICAvLyBDdXJyZW50IHdvcmtpbmcgZGlyZWN0b3J5IChsYXN0IHJlc29ydClcbiAgICAgICAgICBwYXRoLmpvaW4ocHJvY2Vzcy5jd2QoKSwgJ2RhdGEnKVxuICAgICAgICApO1xuICAgICAgfVxuICAgICAgXG4gICAgICAvLyBBbHdheXMgaW5jbHVkZSBOUE0gaW5zdGFsbGF0aW9uIHBhdGhzICh0aGVzZSB3b3VsZCBoYXZlIHByb2R1Y3Rpb24gZGF0YSlcbiAgICAgIHBhdGhzLnB1c2goXG4gICAgICAgIC8vIE5QTSBpbnN0YWxsYXRpb25zIC0gbWFjT1MgSG9tZWJyZXdcbiAgICAgICAgJy9vcHQvaG9tZWJyZXcvbGliL25vZGVfbW9kdWxlcy9AZG9sbGhvdXNlbWNwL21jcC1zZXJ2ZXIvZGF0YScsXG4gICAgICAgIFxuICAgICAgICAvLyBOUE0gaW5zdGFsbGF0aW9ucyAtIHN0YW5kYXJkIFVuaXgvTGludXhcbiAgICAgICAgJy91c3IvbG9jYWwvbGliL25vZGVfbW9kdWxlcy9AZG9sbGhvdXNlbWNwL21jcC1zZXJ2ZXIvZGF0YScsXG4gICAgICAgICcvdXNyL2xpYi9ub2RlX21vZHVsZXMvQGRvbGxob3VzZW1jcC9tY3Atc2VydmVyL2RhdGEnLFxuICAgICAgICBcbiAgICAgICAgLy8gTlBNIGluc3RhbGxhdGlvbnMgLSBXaW5kb3dzXG4gICAgICAgICdDOlxcXFxQcm9ncmFtIEZpbGVzXFxcXG5vZGVqc1xcXFxub2RlX21vZHVsZXNcXFxcQGRvbGxob3VzZW1jcFxcXFxtY3Atc2VydmVyXFxcXGRhdGEnLFxuICAgICAgICAnQzpcXFxcUHJvZ3JhbSBGaWxlcyAoeDg2KVxcXFxub2RlanNcXFxcbm9kZV9tb2R1bGVzXFxcXEBkb2xsaG91c2VtY3BcXFxcbWNwLXNlcnZlclxcXFxkYXRhJyxcbiAgICAgICAgXG4gICAgICAgIC8vIE5QTSBpbnN0YWxsYXRpb25zIC0gV2luZG93cyB3aXRoIG52bVxuICAgICAgICBwYXRoLmpvaW4ocHJvY2Vzcy5lbnYuQVBQREFUQSB8fCAnJywgJ25wbScsICdub2RlX21vZHVsZXMnLCAnQGRvbGxob3VzZW1jcCcsICdtY3Atc2VydmVyJywgJ2RhdGEnKVxuICAgICAgKTtcbiAgICB9XG4gICAgXG4gICAgcmV0dXJuIHBhdGhzO1xuICB9XG4gIFxuICAvKipcbiAgICogRmluZCB0aGUgYnVuZGxlZCBkYXRhIGRpcmVjdG9yeSBieSBjaGVja2luZyBlYWNoIHNlYXJjaCBwYXRoXG4gICAqIFVzZXMgUHJvbWlzZS5hbGxTZXR0bGVkIGZvciBiZXR0ZXIgcGVyZm9ybWFuY2UgYW5kIGNhY2hlcyB0aGUgcmVzdWx0XG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGZpbmREYXRhRGlyZWN0b3J5KCk6IFByb21pc2U8c3RyaW5nIHwgbnVsbD4ge1xuICAgIC8vIFJldHVybiBjYWNoZWQgdmFsdWUgaWYgYXZhaWxhYmxlXG4gICAgaWYgKERlZmF1bHRFbGVtZW50UHJvdmlkZXIuY2FjaGVkRGF0YURpciAhPT0gbnVsbCkge1xuICAgICAgcmV0dXJuIERlZmF1bHRFbGVtZW50UHJvdmlkZXIuY2FjaGVkRGF0YURpcjtcbiAgICB9XG4gICAgXG4gICAgLy8gQ2hlY2sgYWxsIHBhdGhzIGluIHBhcmFsbGVsIGZvciBiZXR0ZXIgcGVyZm9ybWFuY2VcbiAgICBjb25zdCBjaGVja1Byb21pc2VzID0gdGhpcy5kYXRhU2VhcmNoUGF0aHMubWFwKGFzeW5jIChzZWFyY2hQYXRoKSA9PiB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCBzdGF0cyA9IGF3YWl0IGZzLnN0YXQoc2VhcmNoUGF0aCk7XG4gICAgICAgIGlmIChzdGF0cy5pc0RpcmVjdG9yeSgpKSB7XG4gICAgICAgICAgLy8gVmVyaWZ5IGl0IGNvbnRhaW5zIGV4cGVjdGVkIHN1YmRpcmVjdG9yaWVzXG4gICAgICAgICAgY29uc3QgaGFzUGVyc29uYXMgPSBhd2FpdCB0aGlzLmRpcmVjdG9yeUV4aXN0cyhwYXRoLmpvaW4oc2VhcmNoUGF0aCwgJ3BlcnNvbmFzJykpO1xuICAgICAgICAgIGNvbnN0IGhhc1NraWxscyA9IGF3YWl0IHRoaXMuZGlyZWN0b3J5RXhpc3RzKHBhdGguam9pbihzZWFyY2hQYXRoLCAnc2tpbGxzJykpO1xuICAgICAgICAgIGlmIChoYXNQZXJzb25hcyB8fCBoYXNTa2lsbHMpIHtcbiAgICAgICAgICAgIHJldHVybiBzZWFyY2hQYXRoO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgLy8gRGlyZWN0b3J5IGRvZXNuJ3QgZXhpc3Qgb3IgY2FuJ3QgYmUgYWNjZXNzZWRcbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICB9XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9KTtcbiAgICBcbiAgICBjb25zdCByZXN1bHRzID0gYXdhaXQgUHJvbWlzZS5hbGxTZXR0bGVkKGNoZWNrUHJvbWlzZXMpO1xuICAgIFxuICAgIC8vIEZpbmQgdGhlIGZpcnN0IHN1Y2Nlc3NmdWwgcmVzdWx0XG4gICAgZm9yIChjb25zdCByZXN1bHQgb2YgcmVzdWx0cykge1xuICAgICAgaWYgKHJlc3VsdC5zdGF0dXMgPT09ICdmdWxmaWxsZWQnICYmIHJlc3VsdC52YWx1ZSAhPT0gbnVsbCkge1xuICAgICAgICBsb2dnZXIuaW5mbyhgW0RlZmF1bHRFbGVtZW50UHJvdmlkZXJdIEZvdW5kIGRhdGEgZGlyZWN0b3J5IGF0OiAke3Jlc3VsdC52YWx1ZX1gKTtcbiAgICAgICAgLy8gQ2FjaGUgdGhlIHJlc3VsdFxuICAgICAgICBEZWZhdWx0RWxlbWVudFByb3ZpZGVyLmNhY2hlZERhdGFEaXIgPSByZXN1bHQudmFsdWU7XG4gICAgICAgIHJldHVybiByZXN1bHQudmFsdWU7XG4gICAgICB9XG4gICAgfVxuICAgIFxuICAgIGxvZ2dlci53YXJuKCdbRGVmYXVsdEVsZW1lbnRQcm92aWRlcl0gTm8gYnVuZGxlZCBkYXRhIGRpcmVjdG9yeSBmb3VuZCBpbiBhbnkgc2VhcmNoIHBhdGgnKTtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEhlbHBlciB0byBjaGVjayBpZiBhIGRpcmVjdG9yeSBleGlzdHNcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgZGlyZWN0b3J5RXhpc3RzKGRpclBhdGg6IHN0cmluZyk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBzdGF0cyA9IGF3YWl0IGZzLnN0YXQoZGlyUGF0aCk7XG4gICAgICByZXR1cm4gc3RhdHMuaXNEaXJlY3RvcnkoKTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogVmFsaWRhdGUgZmlsZSBwYXRoIHRvIHByZXZlbnQgcGF0aCB0cmF2ZXJzYWwgYXR0YWNrc1xuICAgKiBTRUNVUklUWSBGSVg6IEFkZGVkIGZpbGUgcGF0aCB2YWxpZGF0aW9uIHRvIHByZXZlbnQgZGlyZWN0b3J5IHRyYXZlcnNhbFxuICAgKiBQcmV2aW91c2x5OiBGaWxlIHBhdGhzIHdlcmUgdXNlZCB3aXRob3V0IHZhbGlkYXRpb24sIGFsbG93aW5nIHBvdGVudGlhbCAuLi8uLi8uLi8gYXR0YWNrc1xuICAgKiBOb3c6IFN0cmljdCB2YWxpZGF0aW9uIGVuc3VyZXMgcGF0aHMgc3RheSB3aXRoaW4gYWxsb3dlZCBkaXJlY3Rvcmllc1xuICAgKiBAcGFyYW0gZmlsZVBhdGggVGhlIGZpbGUgcGF0aCB0byB2YWxpZGF0ZVxuICAgKiBAcGFyYW0gYWxsb3dlZEJhc2VQYXRocyBBcnJheSBvZiBhbGxvd2VkIGJhc2UgcGF0aHMgKG9wdGlvbmFsKVxuICAgKiBAcmV0dXJucyB0cnVlIGlmIHBhdGggaXMgc2FmZSwgZmFsc2Ugb3RoZXJ3aXNlXG4gICAqL1xuICBwcml2YXRlIHZhbGlkYXRlRmlsZVBhdGgoZmlsZVBhdGg6IHN0cmluZywgYWxsb3dlZEJhc2VQYXRocz86IHN0cmluZ1tdKTogYm9vbGVhbiB7XG4gICAgdHJ5IHtcbiAgICAgIC8vIFNFQ1VSSVRZOiBOb3JtYWxpemUgcGF0aCB0byBwcmV2ZW50IHRyYXZlcnNhbCBhdHRlbXB0c1xuICAgICAgY29uc3Qgbm9ybWFsaXplZFBhdGggPSBwYXRoLm5vcm1hbGl6ZShmaWxlUGF0aCk7XG4gICAgICBcbiAgICAgIC8vIFNFQ1VSSVRZOiBSZWplY3QgcGF0aHMgY29udGFpbmluZyB0cmF2ZXJzYWwgcGF0dGVybnNcbiAgICAgIGlmIChub3JtYWxpemVkUGF0aC5pbmNsdWRlcygnLi4nKSkge1xuICAgICAgICBsb2dnZXIud2FybihgW0RlZmF1bHRFbGVtZW50UHJvdmlkZXJdIFBhdGggdHJhdmVyc2FsIGF0dGVtcHQgYmxvY2tlZDogJHtmaWxlUGF0aH1gKTtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgfVxuICAgICAgXG4gICAgICAvLyBTRUNVUklUWTogQ2hlY2sgZm9yIGhvbWUgZGlyZWN0b3J5IGV4cGFuc2lvbiBhdHRlbXB0cywgYnV0IGFsbG93IFdpbmRvd3MgOC4zIHNob3J0IHBhdGggbmFtZXNcbiAgICAgIC8vIFdpbmRvd3Mgc2hvcnQgcGF0aCBuYW1lcyB1c2UgfiBmb2xsb3dlZCBieSBhIGRpZ2l0IChlLmcuLCBSVU5ORVJ+MSksIHdoaWNoIHNob3VsZCBiZSBhbGxvd2VkXG4gICAgICAvLyBPbmx5IGJsb2NrIH4gZm9sbG93ZWQgYnkgLyBvciBcXCAoaG9tZSBkaXJlY3RvcnkgZXhwYW5zaW9uIHBhdHRlcm5zKVxuICAgICAgaWYgKG5vcm1hbGl6ZWRQYXRoLmluY2x1ZGVzKCd+LycpIHx8IG5vcm1hbGl6ZWRQYXRoLmluY2x1ZGVzKCd+XFxcXCcpKSB7XG4gICAgICAgIGxvZ2dlci53YXJuKGBbRGVmYXVsdEVsZW1lbnRQcm92aWRlcl0gSG9tZSBkaXJlY3RvcnkgZXhwYW5zaW9uIGF0dGVtcHQgYmxvY2tlZDogJHtmaWxlUGF0aH1gKTtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgfVxuICAgICAgXG4gICAgICAvLyBTRUNVUklUWTogUmVqZWN0IGFic29sdXRlIHBhdGhzIG91dHNpZGUgYWxsb3dlZCBkaXJlY3Rvcmllc1xuICAgICAgaWYgKHBhdGguaXNBYnNvbHV0ZShub3JtYWxpemVkUGF0aCkgJiYgYWxsb3dlZEJhc2VQYXRocykge1xuICAgICAgICBjb25zdCBpc0FsbG93ZWQgPSBhbGxvd2VkQmFzZVBhdGhzLnNvbWUoYmFzZVBhdGggPT4ge1xuICAgICAgICAgIGNvbnN0IG5vcm1hbGl6ZWRCYXNlID0gcGF0aC5ub3JtYWxpemUoYmFzZVBhdGgpO1xuICAgICAgICAgIHJldHVybiBub3JtYWxpemVkUGF0aC5zdGFydHNXaXRoKG5vcm1hbGl6ZWRCYXNlKTtcbiAgICAgICAgfSk7XG4gICAgICAgIFxuICAgICAgICBpZiAoIWlzQWxsb3dlZCkge1xuICAgICAgICAgIGxvZ2dlci53YXJuKGBbRGVmYXVsdEVsZW1lbnRQcm92aWRlcl0gQWJzb2x1dGUgcGF0aCBvdXRzaWRlIGFsbG93ZWQgZGlyZWN0b3JpZXM6ICR7ZmlsZVBhdGh9YCk7XG4gICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBcbiAgICAgIC8vIFNFQ1VSSVRZOiBSZWplY3QgbnVsbCBieXRlcyBhbmQgb3RoZXIgZGFuZ2Vyb3VzIGNoYXJhY3RlcnNcbiAgICAgIGlmIChub3JtYWxpemVkUGF0aC5pbmNsdWRlcygnXFwwJykgfHwgbm9ybWFsaXplZFBhdGguaW5jbHVkZXMoJ1xceDAwJykpIHtcbiAgICAgICAgbG9nZ2VyLndhcm4oYFtEZWZhdWx0RWxlbWVudFByb3ZpZGVyXSBOdWxsIGJ5dGUgaW4gcGF0aCBibG9ja2VkOiAke2ZpbGVQYXRofWApO1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9XG4gICAgICBcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBsb2dnZXIud2FybihgW0RlZmF1bHRFbGVtZW50UHJvdmlkZXJdIFBhdGggdmFsaWRhdGlvbiBlcnJvcjogJHtlcnJvcn1gKTtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH1cblxuICAvLyBERVBSRUNBVEVEOiBDb21tZW50ZWQgb3V0IGZpbGVuYW1lIHBhdHRlcm4gZGV0ZWN0aW9uIC0gcmVwbGFjZWQgd2l0aCBtZXRhZGF0YS1iYXNlZCBkZXRlY3Rpb25cbiAgLyoqXG4gICAqIENhY2hlZCBjb21waWxlZCByZWdleCBwYXR0ZXJucyBmb3IgcGVyZm9ybWFuY2Ugb3B0aW1pemF0aW9uXG4gICAqIEBkZXByZWNhdGVkIFVzZSBtZXRhZGF0YS1iYXNlZCBkZXRlY3Rpb24gaW5zdGVhZFxuICAgKi9cbiAgLy8gcHJpdmF0ZSBzdGF0aWMgY29tcGlsZWRUZXN0UGF0dGVybnM6IFJlZ0V4cFtdIHwgbnVsbCA9IG51bGw7XG5cbiAgLyoqXG4gICAqIEdldCBjb21waWxlZCB0ZXN0IHBhdHRlcm5zIHdpdGggY2FjaGluZyBmb3IgYmV0dGVyIHBlcmZvcm1hbmNlXG4gICAqIEBkZXByZWNhdGVkIFVzZSBtZXRhZGF0YS1iYXNlZCBkZXRlY3Rpb24gaW5zdGVhZFxuICAgKiBAcmV0dXJucyBBcnJheSBvZiBjb21waWxlZCByZWdleCBwYXR0ZXJuc1xuICAgKi9cbiAgLy8gcHJpdmF0ZSBnZXRDb21waWxlZFRlc3RQYXR0ZXJucygpOiBSZWdFeHBbXSB7XG4gIC8vICAgLy8gVXNlIGNhY2hlZCBwYXR0ZXJucyBpZiBhdmFpbGFibGVcbiAgLy8gICBpZiAoRGVmYXVsdEVsZW1lbnRQcm92aWRlci5jb21waWxlZFRlc3RQYXR0ZXJucykge1xuICAvLyAgICAgcmV0dXJuIERlZmF1bHRFbGVtZW50UHJvdmlkZXIuY29tcGlsZWRUZXN0UGF0dGVybnM7XG4gIC8vICAgfVxuICAvLyAgIFxuICAvLyAgIC8vIENvbXBpbGUgYW5kIGNhY2hlIHBhdHRlcm5zIG9uIGZpcnN0IHVzZVxuICAvLyAgIC8vIENSSVRJQ0FMIEZJWDogUmVtb3ZlZCBvdmVybHkgYnJvYWQgL150ZXN0LS9pIHBhdHRlcm4gdGhhdCB3YXMgYmxvY2tpbmcgbGVnaXRpbWF0ZSB1c2VcbiAgLy8gICAvLyBVc2VycyBzaG91bGQgYmUgYWJsZSB0byBjcmVhdGUgcGVyc29uYXMgbGlrZSBcInRlc3QtZHJpdmVuLWRldmVsb3BlclwiIG9yIFwidGVzdC1hdXRvbWF0aW9uLWV4cGVydFwiXG4gIC8vICAgLy8gV2Ugb25seSBibG9jayBzcGVjaWZpYyB0ZXN0IHBhdHRlcm5zIHRoYXQgYXJlIGNsZWFybHkgZnJvbSBvdXIgdGVzdCBzdWl0ZVxuICAvLyAgIERlZmF1bHRFbGVtZW50UHJvdmlkZXIuY29tcGlsZWRUZXN0UGF0dGVybnMgPSBbXG4gIC8vICAgICAvXnRlc3RwZXJzb25hL2ksICAgICAgICAgICAgICAvLyBPdXIgdGVzdCBzdWl0ZSBwYXR0ZXJuXG4gIC8vICAgICAvXnlhbWx0ZXN0L2ksICAgICAgICAgICAgICAgICAvLyBTZWN1cml0eSB0ZXN0IHBhdHRlcm5cbiAgLy8gICAgIC9eeWFtbGJvbWIvaSwgICAgICAgICAgICAgICAgIC8vIFNlY3VyaXR5IHRlc3QgcGF0dGVyblxuICAvLyAgICAgL15tZW1vcnktdGVzdC0vaSwgICAgICAgICAgICAgLy8gUGVyZm9ybWFuY2UgdGVzdCBwYXR0ZXJuXG4gIC8vICAgICAvXnBlcmYtdGVzdC0vaSwgICAgICAgICAgICAgICAvLyBQZXJmb3JtYW5jZSB0ZXN0IHBhdHRlcm5cbiAgLy8gICAgIC9edGVzdC1maXh0dXJlLS9pLCAgICAgICAgICAgIC8vIFRlc3QgZml4dHVyZSBwYXR0ZXJuIChtb3JlIHNwZWNpZmljKVxuICAvLyAgICAgL150ZXN0LWRhdGEtL2ksICAgICAgICAgICAgICAgLy8gVGVzdCBkYXRhIHBhdHRlcm4gKG1vcmUgc3BlY2lmaWMpXG4gIC8vICAgICAvYmluLXNofHJtLXJmfHB3bmVkL2ksICAgICAgICAvLyBNYWxpY2lvdXMgcGF0dGVybnNcbiAgLy8gICAgIC9jb25jdXJyZW50LVxcZCsvaSwgICAgICAgICAgICAvLyBDb25jdXJyZW50IHRlc3QgcGF0dGVyblxuICAvLyAgICAgL2xlZ2FjeVxcLm1kJC9pLCAgICAgICAgICAgICAgIC8vIExlZ2FjeSB0ZXN0IHBhdHRlcm5cbiAgLy8gICAgIC9wZXJmb3JtYW5jZS10ZXN0L2ksICAgICAgICAgIC8vIFBlcmZvcm1hbmNlIHRlc3QgcGF0dGVyblxuICAvLyAgICAgLy1cXGR7MTN9LVthLXowLTldK1xcLm1kJC9pLCAgICAvLyBUaW1lc3RhbXAtYmFzZWQgdGVzdCBmaWxlc1xuICAvLyAgICAgL151bml0dGVzdC0vaSwgICAgICAgICAgICAgICAgLy8gVW5pdCB0ZXN0IHBhdHRlcm5cbiAgLy8gICAgIC9eaW50ZWdyYXRpb250ZXN0LS9pLCAgICAgICAgIC8vIEludGVncmF0aW9uIHRlc3QgcGF0dGVyblxuICAvLyAgIF07XG4gIC8vICAgXG4gIC8vICAgcmV0dXJuIERlZmF1bHRFbGVtZW50UHJvdmlkZXIuY29tcGlsZWRUZXN0UGF0dGVybnM7XG4gIC8vIH1cblxuICAvKipcbiAgICogQ2hlY2sgaWYgYSBmaWxlbmFtZSBtYXRjaGVzIHRlc3QgZGF0YSBwYXR0ZXJucyB0aGF0IHNob3VsZCBuZXZlciBiZSBjb3BpZWQgdG8gcHJvZHVjdGlvblxuICAgKiBAZGVwcmVjYXRlZCBVc2UgaXNEb2xsaG91c2VNQ1BUZXN0RWxlbWVudCgpIGZvciBtZXRhZGF0YS1iYXNlZCBkZXRlY3Rpb24gaW5zdGVhZFxuICAgKiBAcGFyYW0gZmlsZW5hbWUgVGhlIGZpbGVuYW1lIHRvIGNoZWNrXG4gICAqIEByZXR1cm5zIHRydWUgaWYgdGhlIGZpbGVuYW1lIG1hdGNoZXMgdGVzdCBwYXR0ZXJucyB0aGF0IHNob3VsZCBiZSBibG9ja2VkXG4gICAqL1xuICAvLyBwcml2YXRlIGlzVGVzdERhdGFQYXR0ZXJuKGZpbGVuYW1lOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgLy8gICBjb25zdCBwYXR0ZXJucyA9IHRoaXMuZ2V0Q29tcGlsZWRUZXN0UGF0dGVybnMoKTtcbiAgLy8gICByZXR1cm4gcGF0dGVybnMuc29tZShwYXR0ZXJuID0+IHBhdHRlcm4udGVzdChmaWxlbmFtZSkpO1xuICAvLyB9XG5cbiAgLyoqXG4gICAqIFJlYWQgbWV0YWRhdGEgZnJvbSBZQU1MIGZyb250bWF0dGVyIG9ubHkgKG5ldmVyIHJlYWRzIGNvbnRlbnQgYm9keSlcbiAgICogVXNlcyBhIHNtYWxsIGJ1ZmZlciB0byBzYWZlbHkgZXh0cmFjdCBvbmx5IHRoZSBmcm9udG1hdHRlciBiZXR3ZWVuIC0tLSBtYXJrZXJzXG4gICAqIEBwYXJhbSBmaWxlUGF0aCBQYXRoIHRvIHRoZSBmaWxlIHRvIHJlYWQgbWV0YWRhdGEgZnJvbVxuICAgKiBAcmV0dXJucyBQYXJzZWQgbWV0YWRhdGEgb2JqZWN0IG9yIG51bGwgaWYgbm8gZnJvbnRtYXR0ZXIgZm91bmRcbiAgICovXG4gIC8vIFBFUkZPUk1BTkNFIE9QVElNSVpBVElPTjogUmV1c2FibGUgYnVmZmVyIHBvb2wgdG8gcmVkdWNlIGFsbG9jYXRpb25zXG4gIHByaXZhdGUgc3RhdGljIHJlYWRvbmx5IGJ1ZmZlclBvb2w6IEJ1ZmZlcltdID0gW107XG4gIHByaXZhdGUgc3RhdGljIHJlYWRvbmx5IE1BWF9QT09MX1NJWkUgPSAyMDsgLy8gTUVNT1JZIExFQUsgRklYOiBSZWR1Y2VkIGJ1ZmZlciBwb29sIHNpemUgdG8gbWF0Y2ggY2FjaGUgc2l6ZSBmb3IgY29uc2lzdGVudCBtZW1vcnkgbWFuYWdlbWVudFxuICBwcml2YXRlIHN0YXRpYyBidWZmZXJQb29sU3RhdHMgPSB7IGhpdHM6IDAsIG1pc3NlczogMCwgY3JlYXRlZDogMCB9O1xuICBcbiAgcHJpdmF0ZSBnZXRCdWZmZXIoKTogQnVmZmVyIHtcbiAgICAvLyBQRVJGT1JNQU5DRTogVHJhY2sgYnVmZmVyIHBvb2wgdXNhZ2UgZm9yIG9wdGltaXphdGlvbiBtb25pdG9yaW5nXG4gICAgbGV0IGJ1ZmZlciA9IERlZmF1bHRFbGVtZW50UHJvdmlkZXIuYnVmZmVyUG9vbC5wb3AoKTtcbiAgICBpZiAoYnVmZmVyKSB7XG4gICAgICBEZWZhdWx0RWxlbWVudFByb3ZpZGVyLmJ1ZmZlclBvb2xTdGF0cy5oaXRzKys7XG4gICAgICByZXR1cm4gYnVmZmVyO1xuICAgIH0gZWxzZSB7XG4gICAgICBEZWZhdWx0RWxlbWVudFByb3ZpZGVyLmJ1ZmZlclBvb2xTdGF0cy5taXNzZXMrKztcbiAgICAgIERlZmF1bHRFbGVtZW50UHJvdmlkZXIuYnVmZmVyUG9vbFN0YXRzLmNyZWF0ZWQrKztcbiAgICAgIGJ1ZmZlciA9IEJ1ZmZlci5hbGxvYyg0MDk2KTtcbiAgICAgIGxvZ2dlci5kZWJ1ZyhgW0RlZmF1bHRFbGVtZW50UHJvdmlkZXJdIENyZWF0ZWQgbmV3IGJ1ZmZlciAocG9vbCBlbXB0eSksIHRvdGFsIGNyZWF0ZWQ6ICR7RGVmYXVsdEVsZW1lbnRQcm92aWRlci5idWZmZXJQb29sU3RhdHMuY3JlYXRlZH1gKTtcbiAgICAgIHJldHVybiBidWZmZXI7XG4gICAgfVxuICB9XG4gIFxuICBwcml2YXRlIHJlbGVhc2VCdWZmZXIoYnVmZmVyOiBCdWZmZXIpOiB2b2lkIHtcbiAgICAvLyBDUklUSUNBTCBGSVg6IEFsd2F5cyBhdHRlbXB0IHRvIHJldHVybiBidWZmZXIgdG8gcG9vbCBmb3IgcmV1c2VcbiAgICBpZiAoRGVmYXVsdEVsZW1lbnRQcm92aWRlci5idWZmZXJQb29sLmxlbmd0aCA8IERlZmF1bHRFbGVtZW50UHJvdmlkZXIuTUFYX1BPT0xfU0laRSkge1xuICAgICAgYnVmZmVyLmZpbGwoMCk7IC8vIFNFQ1VSSVRZOiBDbGVhciBidWZmZXIgYmVmb3JlIHJldXNlIHRvIHByZXZlbnQgZGF0YSBsZWFrYWdlXG4gICAgICBEZWZhdWx0RWxlbWVudFByb3ZpZGVyLmJ1ZmZlclBvb2wucHVzaChidWZmZXIpO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBQRVJGT1JNQU5DRTogSWYgcG9vbCBpcyBmdWxsLCBjbGVhciB0aGUgYnVmZmVyIHRvIGhlbHAgR0NcbiAgICAgIGJ1ZmZlci5maWxsKDApO1xuICAgICAgbG9nZ2VyLmRlYnVnKCdbRGVmYXVsdEVsZW1lbnRQcm92aWRlcl0gQnVmZmVyIHBvb2wgZnVsbCwgZGlzY2FyZGluZyBidWZmZXInKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQ2xlYW4gdXAgYnVmZmVyIHBvb2wgYW5kIGNhY2hlIHRvIGZyZWUgbWVtb3J5XG4gICAqIFBFUkZPUk1BTkNFIEZJWDogQWRkZWQgY2xlYW51cCBtZXRob2QgdG8gcHJldmVudCBtZW1vcnkgbGVha3NcbiAgICogVGhpcyBzaG91bGQgYmUgY2FsbGVkIGR1cmluZyBhcHBsaWNhdGlvbiBzaHV0ZG93biBvciBwZXJpb2RpYyBjbGVhbnVwXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIGNsZWFudXAoKTogdm9pZCB7XG4gICAgLy8gQ2xlYXIgYnVmZmVyIHBvb2xcbiAgICBEZWZhdWx0RWxlbWVudFByb3ZpZGVyLmJ1ZmZlclBvb2wubGVuZ3RoID0gMDtcbiAgICBcbiAgICAvLyBDbGVhciBtZXRhZGF0YSBjYWNoZVxuICAgIERlZmF1bHRFbGVtZW50UHJvdmlkZXIubWV0YWRhdGFDYWNoZS5jbGVhcigpO1xuICAgIFxuICAgIC8vIENsZWFyIGNhY2hlZCBkYXRhIGRpcmVjdG9yeVxuICAgIERlZmF1bHRFbGVtZW50UHJvdmlkZXIuY2FjaGVkRGF0YURpciA9IG51bGw7XG4gICAgXG4gICAgLy8gQ2xlYXIgcG9wdWxhdGlvbiBwcm9taXNlc1xuICAgIERlZmF1bHRFbGVtZW50UHJvdmlkZXIucG9wdWxhdGVJblByb2dyZXNzLmNsZWFyKCk7XG4gICAgXG4gICAgbG9nZ2VyLmluZm8oJ1tEZWZhdWx0RWxlbWVudFByb3ZpZGVyXSBNZW1vcnkgY2xlYW51cCBjb21wbGV0ZWQnLCB7XG4gICAgICBidWZmZXJTdGF0czogRGVmYXVsdEVsZW1lbnRQcm92aWRlci5idWZmZXJQb29sU3RhdHMsXG4gICAgICBjYWNoZUNsZWFyZWQ6IHRydWVcbiAgICB9KTtcbiAgICBcbiAgICAvLyBSZXNldCBzdGF0c1xuICAgIERlZmF1bHRFbGVtZW50UHJvdmlkZXIuYnVmZmVyUG9vbFN0YXRzID0geyBoaXRzOiAwLCBtaXNzZXM6IDAsIGNyZWF0ZWQ6IDAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgcGVyZm9ybWFuY2Ugc3RhdGlzdGljcyBmb3IgbW9uaXRvcmluZ1xuICAgKiBQRVJGT1JNQU5DRSBNT05JVE9SSU5HOiBBZGRlZCBzdGF0aXN0aWNzIG1ldGhvZCBmb3IgcGVyZm9ybWFuY2UgdHJhY2tpbmdcbiAgICogVGhpcyBwcm92aWRlcyBpbnNpZ2h0cyBpbnRvIGJ1ZmZlciBwb29sIGVmZmljaWVuY3kgYW5kIGNhY2hlIHBlcmZvcm1hbmNlXG4gICAqIEByZXR1cm5zIE9iamVjdCBjb250YWluaW5nIHBlcmZvcm1hbmNlIG1ldHJpY3NcbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgZ2V0UGVyZm9ybWFuY2VTdGF0cygpOiB7XG4gICAgYnVmZmVyUG9vbDoge1xuICAgICAgaGl0czogbnVtYmVyO1xuICAgICAgbWlzc2VzOiBudW1iZXI7IFxuICAgICAgY3JlYXRlZDogbnVtYmVyO1xuICAgICAgaGl0UmF0ZTogbnVtYmVyO1xuICAgICAgcG9vbFNpemU6IG51bWJlcjtcbiAgICAgIG1heFBvb2xTaXplOiBudW1iZXI7XG4gICAgfTtcbiAgICBtZXRhZGF0YUNhY2hlOiB7XG4gICAgICBzaXplOiBudW1iZXI7XG4gICAgICBtYXhTaXplOiBudW1iZXI7XG4gICAgfTtcbiAgfSB7XG4gICAgY29uc3QgYnVmZmVySGl0cyA9IERlZmF1bHRFbGVtZW50UHJvdmlkZXIuYnVmZmVyUG9vbFN0YXRzLmhpdHM7XG4gICAgY29uc3QgYnVmZmVyTWlzc2VzID0gRGVmYXVsdEVsZW1lbnRQcm92aWRlci5idWZmZXJQb29sU3RhdHMubWlzc2VzO1xuICAgIGNvbnN0IHRvdGFsUmVxdWVzdHMgPSBidWZmZXJIaXRzICsgYnVmZmVyTWlzc2VzO1xuICAgIFxuICAgIHJldHVybiB7XG4gICAgICBidWZmZXJQb29sOiB7XG4gICAgICAgIGhpdHM6IGJ1ZmZlckhpdHMsXG4gICAgICAgIG1pc3NlczogYnVmZmVyTWlzc2VzLFxuICAgICAgICBjcmVhdGVkOiBEZWZhdWx0RWxlbWVudFByb3ZpZGVyLmJ1ZmZlclBvb2xTdGF0cy5jcmVhdGVkLFxuICAgICAgICBoaXRSYXRlOiB0b3RhbFJlcXVlc3RzID4gMCA/IGJ1ZmZlckhpdHMgLyB0b3RhbFJlcXVlc3RzIDogMCxcbiAgICAgICAgcG9vbFNpemU6IERlZmF1bHRFbGVtZW50UHJvdmlkZXIuYnVmZmVyUG9vbC5sZW5ndGgsXG4gICAgICAgIG1heFBvb2xTaXplOiBEZWZhdWx0RWxlbWVudFByb3ZpZGVyLk1BWF9QT09MX1NJWkVcbiAgICAgIH0sXG4gICAgICBtZXRhZGF0YUNhY2hlOiB7XG4gICAgICAgIHNpemU6IERlZmF1bHRFbGVtZW50UHJvdmlkZXIubWV0YWRhdGFDYWNoZS5zaXplLFxuICAgICAgICBtYXhTaXplOiBEZWZhdWx0RWxlbWVudFByb3ZpZGVyLk1BWF9DQUNIRV9TSVpFXG4gICAgICB9XG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgcmVhZE1ldGFkYXRhT25seShmaWxlUGF0aDogc3RyaW5nLCByZXRyaWVzID0gMik6IFByb21pc2U8YW55IHwgbnVsbD4ge1xuICAgIC8vIFBFUkZPUk1BTkNFOiBDaGVjayBjYWNoZSBmaXJzdCBiZWZvcmUgcmVhZGluZyBmaWxlXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHN0YXRzID0gYXdhaXQgZnMuc3RhdChmaWxlUGF0aCk7XG4gICAgICBjb25zdCBjYWNoZUtleSA9IGZpbGVQYXRoO1xuICAgICAgY29uc3QgY2FjaGVkID0gRGVmYXVsdEVsZW1lbnRQcm92aWRlci5tZXRhZGF0YUNhY2hlLmdldChjYWNoZUtleSk7XG4gICAgICBcbiAgICAgIC8vIFJldHVybiBjYWNoZWQgbWV0YWRhdGEgaWYgZmlsZSBoYXNuJ3QgY2hhbmdlZCBcbiAgICAgIC8vIENSSVRJQ0FMIEZJWDogVXNlIGludGVnZXIgbXRpbWUgY29tcGFyaXNvbiB0byBhdm9pZCBmbG9hdGluZy1wb2ludCBwcmVjaXNpb24gaXNzdWVzXG4gICAgICBpZiAoY2FjaGVkICYmIE1hdGguZmxvb3IoY2FjaGVkLm10aW1lKSA9PT0gTWF0aC5mbG9vcihzdGF0cy5tdGltZU1zKSAmJiBjYWNoZWQuc2l6ZSA9PT0gc3RhdHMuc2l6ZSkge1xuICAgICAgICBsb2dnZXIuZGVidWcoYFtEZWZhdWx0RWxlbWVudFByb3ZpZGVyXSBDYWNoZSBoaXQgZm9yICR7ZmlsZVBhdGh9YCk7XG4gICAgICAgIHJldHVybiBjYWNoZWQubWV0YWRhdGE7XG4gICAgICB9XG4gICAgfSBjYXRjaCB7XG4gICAgICAvLyBGaWxlIGRvZXNuJ3QgZXhpc3QsIHByb2NlZWQgd2l0aCBub3JtYWwgZmxvd1xuICAgIH1cbiAgICBcbiAgICB0cnkge1xuICAgICAgLy8gT3BlbiBmaWxlIGFuZCByZWFkIG9ubHkgZmlyc3QgNEtCIHRvIGF2b2lkIHJlYWRpbmcgZGFuZ2Vyb3VzIGNvbnRlbnRcbiAgICAgIGNvbnN0IGZkID0gYXdhaXQgZnMub3BlbihmaWxlUGF0aCwgJ3InKTtcbiAgICAgIC8vIFBFUkZPUk1BTkNFOiBVc2UgYnVmZmVyIHBvb2wgaW5zdGVhZCBvZiBhbGxvY2F0aW5nIG5ldyBidWZmZXIgZWFjaCB0aW1lXG4gICAgICBjb25zdCBidWZmZXIgPSB0aGlzLmdldEJ1ZmZlcigpO1xuICAgICAgXG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBmZC5yZWFkKGJ1ZmZlciwgMCwgNDA5NiwgMCk7XG4gICAgICAgIGNvbnN0IGhlYWRlciA9IGJ1ZmZlci5zdWJhcnJheSgwLCByZXN1bHQuYnl0ZXNSZWFkKS50b1N0cmluZygndXRmLTgnKTtcbiAgICAgICAgXG4gICAgICAgIC8vIExvb2sgZm9yIFlBTUwgZnJvbnRtYXR0ZXIgYmV0d2VlbiAtLS0gbWFya2Vyc1xuICAgICAgICAvLyBTdXBwb3J0IGJvdGggVW5peCAoXFxuKSBhbmQgV2luZG93cyAoXFxyXFxuKSBsaW5lIGVuZGluZ3NcbiAgICAgICAgY29uc3QgbWF0Y2ggPSBoZWFkZXIubWF0Y2goL14tLS1cXHI/XFxuKFtcXHNcXFNdKj8pXFxyP1xcbi0tLS8pO1xuICAgICAgICBpZiAoIW1hdGNoKSB7XG4gICAgICAgICAgcmV0dXJuIG51bGw7IC8vIE5vIGZyb250bWF0dGVyIGZvdW5kXG4gICAgICAgIH1cbiAgICAgICAgXG4gICAgICAgIC8vIFBhcnNlIHRoZSBZQU1MIGZyb250bWF0dGVyIHNhZmVseVxuICAgICAgICB0cnkge1xuICAgICAgICAgIC8vIFNFQ1VSSVRZIEZJWDogUmVwbGFjZSBkaXJlY3QgWUFNTCBwYXJzaW5nIGZ1bmN0aW9uIHdpdGggU2VjdXJlWWFtbFBhcnNlciBmb3IgZW5oYW5jZWQgc2VjdXJpdHlcbiAgICAgICAgICAvLyBTZWN1cmVZYW1sUGFyc2VyIHByb3ZpZGVzIGFkZGl0aW9uYWwgdmFsaWRhdGlvbiwgaW5qZWN0aW9uIHByZXZlbnRpb24sIGFuZCBjb250ZW50IHNhbml0aXphdGlvblxuICAgICAgICAgIC8vIEl0IGV4cGVjdHMgZnVsbCBZQU1MIHdpdGggLS0tIG1hcmtlcnMsIHNvIHdlIHJlY29uc3RydWN0IHRoZSBmcm9udG1hdHRlciBibG9ja1xuICAgICAgICAgIC8vIFdlIGRpc2FibGUgc3BlY2lmaWMgZmllbGQgdmFsaWRhdGlvbiBhcyB0aGlzIGlzIGdlbmVyYWwgbWV0YWRhdGEgcGFyc2luZywgbm90IHBlcnNvbmEtc3BlY2lmaWNcbiAgICAgICAgICBjb25zdCBmdWxsWWFtbCA9IGAtLS1cXG4ke21hdGNoWzFdfVxcbi0tLWA7XG4gICAgICAgICAgY29uc3QgcGFyc2VSZXN1bHQgPSBTZWN1cmVZYW1sUGFyc2VyLnBhcnNlKGZ1bGxZYW1sLCB7IFxuICAgICAgICAgICAgdmFsaWRhdGVDb250ZW50OiBmYWxzZSwgXG4gICAgICAgICAgICB2YWxpZGF0ZUZpZWxkczogZmFsc2UgXG4gICAgICAgICAgfSk7XG4gICAgICAgICAgY29uc3QgbWV0YWRhdGEgPSBwYXJzZVJlc3VsdC5kYXRhO1xuICAgICAgICAgIFxuICAgICAgICAgIC8vIFBFUkZPUk1BTkNFOiBDYWNoZSB0aGUgbWV0YWRhdGEgd2l0aCBmaWxlIHN0YXRzIGZvciBmdXR1cmUgcmVhZHNcbiAgICAgICAgICBpZiAodHlwZW9mIG1ldGFkYXRhID09PSAnb2JqZWN0JyAmJiBtZXRhZGF0YSAhPT0gbnVsbCkge1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgY29uc3Qgc3RhdHMgPSBhd2FpdCBmcy5zdGF0KGZpbGVQYXRoKTtcbiAgICAgICAgICAgICAgY29uc3QgY2FjaGVFbnRyeTogTWV0YWRhdGFDYWNoZUVudHJ5ID0ge1xuICAgICAgICAgICAgICAgIG1ldGFkYXRhLFxuICAgICAgICAgICAgICAgIG10aW1lOiBzdGF0cy5tdGltZU1zLFxuICAgICAgICAgICAgICAgIHNpemU6IHN0YXRzLnNpemVcbiAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgXG4gICAgICAgICAgICAgIC8vIENSSVRJQ0FMIE1FTU9SWSBMRUFLIEZJWDogTW9yZSBhZ2dyZXNzaXZlIGNhY2hlIG1hbmFnZW1lbnQgdG8gcHJldmVudCB1bmJvdW5kZWQgZ3Jvd3RoXG4gICAgICAgICAgICAgIC8vIENoZWNrIGlmIHRoaXMgZW50cnkgYWxyZWFkeSBleGlzdHMgYW5kIGp1c3QgdXBkYXRlIGl0IGluc3RlYWQgb2YgYWRkaW5nIG5ld1xuICAgICAgICAgICAgICBpZiAoRGVmYXVsdEVsZW1lbnRQcm92aWRlci5tZXRhZGF0YUNhY2hlLmhhcyhmaWxlUGF0aCkpIHtcbiAgICAgICAgICAgICAgICAvLyBVcGRhdGUgZXhpc3RpbmcgZW50cnkgLSBubyBldmljdGlvbiBuZWVkZWRcbiAgICAgICAgICAgICAgICBEZWZhdWx0RWxlbWVudFByb3ZpZGVyLm1ldGFkYXRhQ2FjaGUuc2V0KGZpbGVQYXRoLCBjYWNoZUVudHJ5KTtcbiAgICAgICAgICAgICAgICBsb2dnZXIuZGVidWcoYFtEZWZhdWx0RWxlbWVudFByb3ZpZGVyXSBVcGRhdGVkIGV4aXN0aW5nIGNhY2hlIGVudHJ5IGZvciAke2ZpbGVQYXRofWApO1xuICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIC8vIE5ldyBlbnRyeSAtIGNoZWNrIGlmIHdlIG5lZWQgdG8gZXZpY3QgZmlyc3RcbiAgICAgICAgICAgICAgICAvLyBVc2UgPiBpbnN0ZWFkIG9mID49IHRvIGVuc3VyZSB3ZSBuZXZlciBleGNlZWQgTUFYX0NBQ0hFX1NJWkVcbiAgICAgICAgICAgICAgICBpZiAoRGVmYXVsdEVsZW1lbnRQcm92aWRlci5tZXRhZGF0YUNhY2hlLnNpemUgPj0gRGVmYXVsdEVsZW1lbnRQcm92aWRlci5NQVhfQ0FDSEVfU0laRSkge1xuICAgICAgICAgICAgICAgICAgLy8gTW9yZSBhZ2dyZXNzaXZlIGV2aWN0aW9uOiByZW1vdmUgZW5vdWdoIGVudHJpZXMgdG8gc3RheSB3ZWxsIHVuZGVyIGxpbWl0XG4gICAgICAgICAgICAgICAgICBjb25zdCBlbnRyaWVzVG9FdmljdCA9IE1hdGgubWF4KDEsIE1hdGguZmxvb3IoRGVmYXVsdEVsZW1lbnRQcm92aWRlci5NQVhfQ0FDSEVfU0laRSAqIDAuNCkpO1xuICAgICAgICAgICAgICAgICAgY29uc3Qga2V5c1RvRXZpY3QgPSBBcnJheS5mcm9tKERlZmF1bHRFbGVtZW50UHJvdmlkZXIubWV0YWRhdGFDYWNoZS5rZXlzKCkpLnNsaWNlKDAsIGVudHJpZXNUb0V2aWN0KTtcbiAgICAgICAgICAgICAgICAgIGZvciAoY29uc3Qga2V5IG9mIGtleXNUb0V2aWN0KSB7XG4gICAgICAgICAgICAgICAgICAgIERlZmF1bHRFbGVtZW50UHJvdmlkZXIubWV0YWRhdGFDYWNoZS5kZWxldGUoa2V5KTtcbiAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgIGxvZ2dlci5kZWJ1ZyhgW0RlZmF1bHRFbGVtZW50UHJvdmlkZXJdIEV2aWN0ZWQgJHtrZXlzVG9FdmljdC5sZW5ndGh9IGNhY2hlIGVudHJpZXMgdG8gbWFuYWdlIG1lbW9yeSAoY2FjaGUgc2l6ZSB3YXMgJHtEZWZhdWx0RWxlbWVudFByb3ZpZGVyLm1ldGFkYXRhQ2FjaGUuc2l6ZSArIGtleXNUb0V2aWN0Lmxlbmd0aH0pYCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIFxuICAgICAgICAgICAgICAgIERlZmF1bHRFbGVtZW50UHJvdmlkZXIubWV0YWRhdGFDYWNoZS5zZXQoZmlsZVBhdGgsIGNhY2hlRW50cnkpO1xuICAgICAgICAgICAgICAgIGxvZ2dlci5kZWJ1ZyhgW0RlZmF1bHRFbGVtZW50UHJvdmlkZXJdIEFkZGVkIG5ldyBjYWNoZSBlbnRyeSBmb3IgJHtmaWxlUGF0aH0gKGNhY2hlIHNpemUgbm93OiAke0RlZmF1bHRFbGVtZW50UHJvdmlkZXIubWV0YWRhdGFDYWNoZS5zaXplfSlgKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBjYXRjaCB7XG4gICAgICAgICAgICAgIC8vIElnbm9yZSBjYWNoZSBlcnJvcnMsIHJldHVybiBtZXRhZGF0YSBhbnl3YXlcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBtZXRhZGF0YTtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH0gY2F0Y2ggKHlhbWxFcnJvcikge1xuICAgICAgICAgIC8vIEludmFsaWQgWUFNTCwgcmV0dXJuIG51bGxcbiAgICAgICAgICAvLyBFTkhBTkNFTUVOVDogSW5jbHVkZSBlcnJvciB0eXBlIGZvciBiZXR0ZXIgZGVidWdnaW5nXG4gICAgICAgICAgY29uc3QgeWFtbEVycm9yVHlwZSA9ICh5YW1sRXJyb3IgYXMgYW55KT8uY29uc3RydWN0b3I/Lm5hbWUgfHwgJ1lBTUxFcnJvcic7XG4gICAgICAgICAgbG9nZ2VyLmRlYnVnKGBbRGVmYXVsdEVsZW1lbnRQcm92aWRlcl0gSW52YWxpZCBZQU1MIGluICR7ZmlsZVBhdGh9OiAke3lhbWxFcnJvclR5cGV9IC0gJHt5YW1sRXJyb3J9YCk7XG4gICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cbiAgICAgIH0gZmluYWxseSB7XG4gICAgICAgIC8vIENSSVRJQ0FMIEZJWDogRW5zdXJlIGZpbGUgZGVzY3JpcHRvciBpcyBjbG9zZWQgYW5kIGJ1ZmZlciBpcyByZWxlYXNlZCBpbiBBTEwgcGF0aHNcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBhd2FpdCBmZC5jbG9zZSgpO1xuICAgICAgICB9IGNhdGNoIChjbG9zZUVycm9yKSB7XG4gICAgICAgICAgbG9nZ2VyLmRlYnVnKGBbRGVmYXVsdEVsZW1lbnRQcm92aWRlcl0gRXJyb3IgY2xvc2luZyBmaWxlIGRlc2NyaXB0b3IgZm9yICR7ZmlsZVBhdGh9OiAke2Nsb3NlRXJyb3J9YCk7XG4gICAgICAgIH1cbiAgICAgICAgLy8gUEVSRk9STUFOQ0U6IFJldHVybiBidWZmZXIgdG8gcG9vbCBmb3IgcmV1c2VcbiAgICAgICAgdGhpcy5yZWxlYXNlQnVmZmVyKGJ1ZmZlcik7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXJyb3I6IGFueSkge1xuICAgICAgLy8gRU5IQU5DRU1FTlQ6IEluY2x1ZGUgZXJyb3IgdHlwZSBpbiBkZWJ1ZyBsb2dzIGZvciBiZXR0ZXIgZGVidWdnaW5nXG4gICAgICBjb25zdCBlcnJvclR5cGUgPSBlcnJvcj8uY29uc3RydWN0b3I/Lm5hbWUgfHwgJ1Vua25vd25FcnJvcic7XG4gICAgICBjb25zdCBlcnJvckNvZGUgPSBlcnJvcj8uY29kZSB8fCAnTk9fQ09ERSc7XG4gICAgICBcbiAgICAgIC8vIFJFTElBQklMSVRZOiBBZGQgcmV0cnkgbG9naWMgZm9yIHRyYW5zaWVudCBmYWlsdXJlc1xuICAgICAgaWYgKHJldHJpZXMgPiAwICYmIChlcnJvckNvZGUgPT09ICdFQlVTWScgfHwgZXJyb3JDb2RlID09PSAnRUFHQUlOJykpIHtcbiAgICAgICAgbG9nZ2VyLmRlYnVnKGBbRGVmYXVsdEVsZW1lbnRQcm92aWRlcl0gUmV0cnlpbmcgcmVhZCBmb3IgJHtmaWxlUGF0aH0gYWZ0ZXIgJHtlcnJvclR5cGV9OiR7ZXJyb3JDb2RlfWApO1xuICAgICAgICBhd2FpdCBuZXcgUHJvbWlzZShyZXNvbHZlID0+IHNldFRpbWVvdXQocmVzb2x2ZSwgNTApKTsgLy8gQnJpZWYgZGVsYXkgYmVmb3JlIHJldHJ5XG4gICAgICAgIHJldHVybiB0aGlzLnJlYWRNZXRhZGF0YU9ubHkoZmlsZVBhdGgsIHJldHJpZXMgLSAxKTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgbG9nZ2VyLmRlYnVnKGBbRGVmYXVsdEVsZW1lbnRQcm92aWRlcl0gQ291bGQgbm90IHJlYWQgbWV0YWRhdGEgZnJvbSAke2ZpbGVQYXRofTogJHtlcnJvclR5cGV9OiR7ZXJyb3JDb2RlfSAtICR7ZXJyb3I/Lm1lc3NhZ2UgfHwgZXJyb3J9YCk7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2sgaWYgYSBmaWxlIGlzIGEgRG9sbGhvdXNlTUNQIHRlc3QgZWxlbWVudCBiYXNlZCBvbiBtZXRhZGF0YVxuICAgKiBUaGlzIHJlcGxhY2VzIGZpbGVuYW1lIHBhdHRlcm4gZGV0ZWN0aW9uIHdpdGggYWNjdXJhdGUgbWV0YWRhdGEtYmFzZWQgZGV0ZWN0aW9uXG4gICAqIEBwYXJhbSBmaWxlUGF0aCBQYXRoIHRvIHRoZSBmaWxlIHRvIGNoZWNrXG4gICAqIEByZXR1cm5zIHRydWUgaWYgdGhlIGZpbGUgY29udGFpbnMgX2RvbGxob3VzZU1DUFRlc3Q6IHRydWUgbWV0YWRhdGFcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgaXNEb2xsaG91c2VNQ1BUZXN0RWxlbWVudChmaWxlUGF0aDogc3RyaW5nKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IG1ldGFkYXRhID0gYXdhaXQgdGhpcy5yZWFkTWV0YWRhdGFPbmx5KGZpbGVQYXRoKTtcbiAgICAgIGNvbnN0IGlzVGVzdCA9ICEhKG1ldGFkYXRhICYmIG1ldGFkYXRhLl9kb2xsaG91c2VNQ1BUZXN0ID09PSB0cnVlKTtcbiAgICAgIFxuICAgICAgXG4gICAgICByZXR1cm4gaXNUZXN0O1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAvLyBJZiB3ZSBjYW4ndCByZWFkIHRoZSBtZXRhZGF0YSwgYXNzdW1lIGl0J3Mgbm90IGEgdGVzdCBmaWxlXG4gICAgICBsb2dnZXIuZGVidWcoYFtEZWZhdWx0RWxlbWVudFByb3ZpZGVyXSBFcnJvciBjaGVja2luZyB0ZXN0IG1ldGFkYXRhIGZvciAke2ZpbGVQYXRofTogJHtlcnJvcn1gKTtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogRGV0ZWN0IGlmIHdlJ3JlIGluIGEgcHJvZHVjdGlvbiBlbnZpcm9ubWVudCBieSBjaGVja2luZyBmb3IgcHJvZHVjdGlvbiBpbmRpY2F0b3JzXG4gICAqIFVzZXMgYSBjb25maWRlbmNlLWJhc2VkIGFwcHJvYWNoIHJlcXVpcmluZyBtdWx0aXBsZSBpbmRpY2F0b3JzIGZvciBiZXR0ZXIgYWNjdXJhY3lcbiAgICogQHJldHVybnMgdHJ1ZSBpZiB0aGlzIGFwcGVhcnMgdG8gYmUgYSBwcm9kdWN0aW9uIGVudmlyb25tZW50XG4gICAqL1xuICBwcml2YXRlIGlzUHJvZHVjdGlvbkVudmlyb25tZW50KCk6IGJvb2xlYW4ge1xuICAgIC8vIEFsbG93IHRlc3RzIHRvIGV4cGxpY2l0bHkgb3ZlcnJpZGUgcHJvZHVjdGlvbiBtb2RlIGRldGVjdGlvblxuICAgIGlmIChwcm9jZXNzLmVudi5GT1JDRV9QUk9EVUNUSU9OX01PREUgPT09ICd0cnVlJykge1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIGlmIChwcm9jZXNzLmVudi5GT1JDRV9QUk9EVUNUSU9OX01PREUgPT09ICdmYWxzZScpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgXG4gICAgLy8gV2VpZ2h0ZWQgaW5kaWNhdG9ycyBmb3IgcHJvZHVjdGlvbiBkZXRlY3Rpb25cbiAgICBjb25zdCBpbmRpY2F0b3JzID0ge1xuICAgICAgLy8gU3Ryb25nIGluZGljYXRvcnMgKHdlaWdodDogMilcbiAgICAgIGhhc1VzZXJIb21lRGlyOiAocHJvY2Vzcy5lbnYuSE9NRSAmJiAocHJvY2Vzcy5lbnYuSE9NRS5pbmNsdWRlcygnL1VzZXJzLycpIHx8IHByb2Nlc3MuZW52LkhPTUUuaW5jbHVkZXMoJy9ob21lLycpKSkgfHwgXG4gICAgICAgICAgICAgICAgICAgICAgISFwcm9jZXNzLmVudi5VU0VSUFJPRklMRSxcbiAgICAgIGlzUHJvZHVjdGlvbk5vZGU6IHByb2Nlc3MuZW52Lk5PREVfRU5WID09PSAncHJvZHVjdGlvbicsXG4gICAgICBub3RJblRlc3REaXI6ICgoKSA9PiB7XG4gICAgICAgIGNvbnN0IGN3ZCA9IHByb2Nlc3MuY3dkKCkudG9Mb3dlckNhc2UoKTtcbiAgICAgICAgLy8gTm9ybWFsaXplIHBhdGggc2VwYXJhdG9ycyBmb3IgY3Jvc3MtcGxhdGZvcm0gY2hlY2tpbmcgKFdpbmRvd3MgdXNlcyBcXCBidXQgY2hlY2tzIHVzZSAvKVxuICAgICAgICBjb25zdCBub3JtYWxpemVkQ3dkID0gY3dkLnJlcGxhY2UoL1xcXFwvZywgJy8nKTtcbiAgICAgICAgcmV0dXJuICFub3JtYWxpemVkQ3dkLmluY2x1ZGVzKCcvdGVzdCcpICYmIFxuICAgICAgICAgICAgICAgIW5vcm1hbGl6ZWRDd2QuaW5jbHVkZXMoJy9fX3Rlc3RzX18nKSAmJiBcbiAgICAgICAgICAgICAgICFub3JtYWxpemVkQ3dkLmluY2x1ZGVzKCcvdGVtcCcpICYmXG4gICAgICAgICAgICAgICAhbm9ybWFsaXplZEN3ZC5pbmNsdWRlcygnL2Rpc3QvdGVzdCcpO1xuICAgICAgfSkoKSxcbiAgICAgIFxuICAgICAgLy8gTW9kZXJhdGUgaW5kaWNhdG9ycyAod2VpZ2h0OiAxKVxuICAgICAgbm90SW5DSTogIXByb2Nlc3MuZW52LkNJLFxuICAgICAgbm9UZXN0RW52OiBwcm9jZXNzLmVudi5OT0RFX0VOViAhPT0gJ3Rlc3QnLFxuICAgICAgbm9EZXZFbnY6IHByb2Nlc3MuZW52Lk5PREVfRU5WICE9PSAnZGV2ZWxvcG1lbnQnLFxuICAgIH07XG4gICAgXG4gICAgLy8gQ2FsY3VsYXRlIHdlaWdodGVkIHNjb3JlXG4gICAgbGV0IHNjb3JlID0gMDtcbiAgICBpZiAoaW5kaWNhdG9ycy5oYXNVc2VySG9tZURpcikgc2NvcmUgKz0gMjtcbiAgICBpZiAoaW5kaWNhdG9ycy5pc1Byb2R1Y3Rpb25Ob2RlKSBzY29yZSArPSAyO1xuICAgIGlmIChpbmRpY2F0b3JzLm5vdEluVGVzdERpcikgc2NvcmUgKz0gMjtcbiAgICBpZiAoaW5kaWNhdG9ycy5ub3RJbkNJKSBzY29yZSArPSAxO1xuICAgIGlmIChpbmRpY2F0b3JzLm5vVGVzdEVudikgc2NvcmUgKz0gMTtcbiAgICBpZiAoaW5kaWNhdG9ycy5ub0RldkVudikgc2NvcmUgKz0gMTtcbiAgICBcbiAgICAvLyBMb2cgZGV0ZWN0aW9uIGRldGFpbHMgZm9yIGRlYnVnZ2luZ1xuICAgIGNvbnN0IGFjdGl2ZUluZGljYXRvcnMgPSBPYmplY3QuZW50cmllcyhpbmRpY2F0b3JzKVxuICAgICAgLmZpbHRlcigoW18sIHZhbHVlXSkgPT4gdmFsdWUpXG4gICAgICAubWFwKChba2V5XSkgPT4ga2V5KTtcbiAgICBcbiAgICAvLyBUWVBFU0NSSVBUIEZJWDogUmVtb3ZlZCBsb2dnZXIuaXNEZWJ1Z0VuYWJsZWQoKSBjaGVjayBhcyB0aGlzIG1ldGhvZCBkb2Vzbid0IGV4aXN0IG9uIE1DUExvZ2dlclxuICAgIC8vIFRoZSBsb2dnZXIgYWxyZWFkeSBoYW5kbGVzIGRlYnVnIGxldmVsIGludGVybmFsbHksIHNvIHdlIGNhbiBjYWxsIGRlYnVnKCkgZGlyZWN0bHlcbiAgICBpZiAoc2NvcmUgPj0gMykge1xuICAgICAgbG9nZ2VyLmRlYnVnKFxuICAgICAgICAnW0RlZmF1bHRFbGVtZW50UHJvdmlkZXJdIFByb2R1Y3Rpb24gZW52aXJvbm1lbnQgZGV0ZWN0ZWQnLFxuICAgICAgICB7IHNjb3JlLCBhY3RpdmVJbmRpY2F0b3JzLCBmb3JjZU1vZGU6ICdub3Qgc2V0JyB9XG4gICAgICApO1xuICAgIH1cbiAgICBcbiAgICAvLyBSZXF1aXJlIGEgc2NvcmUgb2YgYXQgbGVhc3QgMyBmb3IgcHJvZHVjdGlvbiBkZXRlY3Rpb24gKG1vcmUgY29uZmlkZW50KVxuICAgIC8vIFRoaXMgcHJldmVudHMgZmFsc2UgcG9zaXRpdmVzIGluIGVkZ2UgY2FzZXMgd2hpbGUgbWFpbnRhaW5pbmcgc2VjdXJpdHlcbiAgICByZXR1cm4gc2NvcmUgPj0gMztcbiAgfVxuICBcbiAgLyoqXG4gICAqIENvcHkgYWxsIGZpbGVzIGZyb20gc291cmNlIGRpcmVjdG9yeSB0byBkZXN0aW5hdGlvbiBkaXJlY3RvcnlcbiAgICogU2tpcHMgZmlsZXMgdGhhdCBhbHJlYWR5IGV4aXN0IHRvIHByZXNlcnZlIHVzZXIgbW9kaWZpY2F0aW9uc1xuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBjb3B5RWxlbWVudEZpbGVzKHNvdXJjZURpcjogc3RyaW5nLCBkZXN0RGlyOiBzdHJpbmcsIGVsZW1lbnRUeXBlOiBzdHJpbmcpOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIGxldCBjb3BpZWRDb3VudCA9IDA7XG4gICAgXG4gICAgXG4gICAgdHJ5IHtcbiAgICAgIC8vIEVuc3VyZSBkZXN0aW5hdGlvbiBkaXJlY3RvcnkgZXhpc3RzXG4gICAgICBhd2FpdCBmcy5ta2RpcihkZXN0RGlyLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcbiAgICAgIFxuICAgICAgLy8gUmVhZCBzb3VyY2UgZGlyZWN0b3J5XG4gICAgICBjb25zdCBmaWxlcyA9IGF3YWl0IGZzLnJlYWRkaXIoc291cmNlRGlyKTtcbiAgICAgIFxuICAgICAgXG4gICAgICBmb3IgKGNvbnN0IGZpbGUgb2YgZmlsZXMpIHtcbiAgICAgICAgXG4gICAgICAgIC8vIE9ubHkgY29weSBtYXJrZG93biBmaWxlc1xuICAgICAgICBpZiAoIWZpbGUuZW5kc1dpdGgoRklMRV9DT05TVEFOVFMuRUxFTUVOVF9FWFRFTlNJT04pKSB7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cbiAgICAgICAgXG4gICAgICAgIC8vIE5vcm1hbGl6ZSBmaWxlbmFtZSBmb3Igc2VjdXJpdHlcbiAgICAgICAgY29uc3Qgbm9ybWFsaXplZEZpbGUgPSBVbmljb2RlVmFsaWRhdG9yLm5vcm1hbGl6ZShmaWxlKTtcbiAgICAgICAgaWYgKCFub3JtYWxpemVkRmlsZS5pc1ZhbGlkKSB7XG4gICAgICAgICAgbG9nZ2VyLndhcm4oYFtEZWZhdWx0RWxlbWVudFByb3ZpZGVyXSBTa2lwcGluZyBmaWxlIHdpdGggaW52YWxpZCBVbmljb2RlOiAke2ZpbGV9YCk7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBzb3VyY2VQYXRoID0gcGF0aC5qb2luKHNvdXJjZURpciwgbm9ybWFsaXplZEZpbGUubm9ybWFsaXplZENvbnRlbnQpO1xuICAgICAgICBjb25zdCBkZXN0UGF0aCA9IHBhdGguam9pbihkZXN0RGlyLCBub3JtYWxpemVkRmlsZS5ub3JtYWxpemVkQ29udGVudCk7XG4gICAgICAgIFxuICAgICAgICBcbiAgICAgICAgLy8gU0VDVVJJVFkgRklYOiBWYWxpZGF0ZSBmaWxlIHBhdGhzIHRvIHByZXZlbnQgcGF0aCB0cmF2ZXJzYWwgYXR0YWNrc1xuICAgICAgICAvLyBUaGlzIHByZXZlbnRzIG1hbGljaW91cyBmaWxlcyBmcm9tIGVzY2FwaW5nIHRoZSBpbnRlbmRlZCBkaXJlY3Rvcnkgc3RydWN0dXJlXG4gICAgICAgIGNvbnN0IHNvdXJjZVZhbGlkID0gdGhpcy52YWxpZGF0ZUZpbGVQYXRoKHNvdXJjZVBhdGgsIFtzb3VyY2VEaXJdKTtcbiAgICAgICAgY29uc3QgZGVzdFZhbGlkID0gdGhpcy52YWxpZGF0ZUZpbGVQYXRoKGRlc3RQYXRoLCBbZGVzdERpcl0pO1xuICAgICAgICBcbiAgICAgICAgaWYgKCFzb3VyY2VWYWxpZCB8fCAhZGVzdFZhbGlkKSB7XG4gICAgICAgICAgbG9nZ2VyLndhcm4oXG4gICAgICAgICAgICBgW0RlZmF1bHRFbGVtZW50UHJvdmlkZXJdIFNraXBwaW5nIGZpbGUgd2l0aCBpbnZhbGlkIHBhdGg6ICR7bm9ybWFsaXplZEZpbGUubm9ybWFsaXplZENvbnRlbnR9YCxcbiAgICAgICAgICAgIHsgc291cmNlUGF0aCwgZGVzdFBhdGgsIGVsZW1lbnRUeXBlIH1cbiAgICAgICAgICApO1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG4gICAgICAgIFxuICAgICAgICAvLyBQcm9kdWN0aW9uIHNhZmV0eSBjaGVjazogQmxvY2sgRG9sbGhvdXNlTUNQIHRlc3QgZWxlbWVudHMgaW4gcHJvZHVjdGlvbiBlbnZpcm9ubWVudHNcbiAgICAgICAgLy8gU2tpcCB0aGlzIGNoZWNrIGlmIGxvYWRUZXN0RGF0YSBpcyBleHBsaWNpdGx5IGVuYWJsZWQgKGZvciB0ZXN0aW5nIHNjZW5hcmlvcylcbiAgICAgICAgaWYgKCF0aGlzLmNvbmZpZy5sb2FkVGVzdERhdGEgJiYgdGhpcy5pc1Byb2R1Y3Rpb25FbnZpcm9ubWVudCgpKSB7XG4gICAgICAgICAgY29uc3QgaXNEb2xsaG91c2VUZXN0ID0gYXdhaXQgdGhpcy5pc0RvbGxob3VzZU1DUFRlc3RFbGVtZW50KHNvdXJjZVBhdGgpO1xuICAgICAgICAgIFxuICAgICAgICAgIGlmIChpc0RvbGxob3VzZVRlc3QpIHtcbiAgICAgICAgICAgIGxvZ2dlci53YXJuKFxuICAgICAgICAgICAgICBgW0RlZmF1bHRFbGVtZW50UHJvdmlkZXJdIFNFQ1VSSVRZOiBCbG9ja2luZyBEb2xsaG91c2VNQ1AgdGVzdCBlbGVtZW50IGluIHByb2R1Y3Rpb246ICR7bm9ybWFsaXplZEZpbGUubm9ybWFsaXplZENvbnRlbnR9YCxcbiAgICAgICAgICAgICAgeyBcbiAgICAgICAgICAgICAgICBmaWxlOiBub3JtYWxpemVkRmlsZS5ub3JtYWxpemVkQ29udGVudCxcbiAgICAgICAgICAgICAgICByZWFzb246ICdEb2xsaG91c2VNQ1AgdGVzdCBlbGVtZW50IGRldGVjdGVkIGluIHByb2R1Y3Rpb24gZW52aXJvbm1lbnQnLFxuICAgICAgICAgICAgICAgIGVsZW1lbnRUeXBlXG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICBcbiAgICAgICAgICAgIC8vIExvZyBzZWN1cml0eSBldmVudCBmb3IgYmxvY2tlZCB0ZXN0IGRhdGFcbiAgICAgICAgICAgIFNlY3VyaXR5TW9uaXRvci5sb2dTZWN1cml0eUV2ZW50KHtcbiAgICAgICAgICAgICAgdHlwZTogJ1RFU1RfREFUQV9CTE9DS0VEJyxcbiAgICAgICAgICAgICAgc2V2ZXJpdHk6ICdNRURJVU0nLFxuICAgICAgICAgICAgICBzb3VyY2U6ICdEZWZhdWx0RWxlbWVudFByb3ZpZGVyLmNvcHlFbGVtZW50RmlsZXMnLFxuICAgICAgICAgICAgICBkZXRhaWxzOiBgQmxvY2tlZCBEb2xsaG91c2VNQ1AgdGVzdCBlbGVtZW50IGluIHByb2R1Y3Rpb246ICR7bm9ybWFsaXplZEZpbGUubm9ybWFsaXplZENvbnRlbnR9YCxcbiAgICAgICAgICAgICAgbWV0YWRhdGE6IHtcbiAgICAgICAgICAgICAgICBmaWxlbmFtZTogbm9ybWFsaXplZEZpbGUubm9ybWFsaXplZENvbnRlbnQsXG4gICAgICAgICAgICAgICAgZWxlbWVudFR5cGUsXG4gICAgICAgICAgICAgICAgcmVhc29uOiAnRG9sbGhvdXNlTUNQIHRlc3QgZWxlbWVudCBkZXRlY3RlZCBpbiBwcm9kdWN0aW9uIGVudmlyb25tZW50JyxcbiAgICAgICAgICAgICAgICBkZXRlY3Rpb25NZXRob2Q6ICdtZXRhZGF0YS1iYXNlZCdcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAvLyBDaGVjayBpZiBkZXN0aW5hdGlvbiBmaWxlIGFscmVhZHkgZXhpc3RzXG4gICAgICAgICAgYXdhaXQgZnMuYWNjZXNzKGRlc3RQYXRoKTtcbiAgICAgICAgICBsb2dnZXIuZGVidWcoYFtEZWZhdWx0RWxlbWVudFByb3ZpZGVyXSBTa2lwcGluZyBleGlzdGluZyBmaWxlOiAke25vcm1hbGl6ZWRGaWxlLm5vcm1hbGl6ZWRDb250ZW50fWApO1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9IGNhdGNoIHtcbiAgICAgICAgICAvLyBGaWxlIGRvZXNuJ3QgZXhpc3QsIHByb2NlZWQgd2l0aCBjb3B5XG4gICAgICAgIH1cbiAgICAgICAgXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgLy8gVmFsaWRhdGUgc291cmNlIGZpbGUgYmVmb3JlIGNvcHlpbmdcbiAgICAgICAgICBjb25zdCBzb3VyY2VTdGF0cyA9IGF3YWl0IGZzLnN0YXQoc291cmNlUGF0aCk7XG4gICAgICAgICAgXG4gICAgICAgICAgLy8gQ2hlY2sgZmlsZSBzaXplIGxpbWl0XG4gICAgICAgICAgaWYgKHNvdXJjZVN0YXRzLnNpemUgPiBGSUxFX0NPTlNUQU5UUy5NQVhfRklMRV9TSVpFKSB7XG4gICAgICAgICAgICBsb2dnZXIud2FybihcbiAgICAgICAgICAgICAgYFtEZWZhdWx0RWxlbWVudFByb3ZpZGVyXSBTa2lwcGluZyBvdmVyc2l6ZWQgZmlsZSAke25vcm1hbGl6ZWRGaWxlLm5vcm1hbGl6ZWRDb250ZW50fTogYCArXG4gICAgICAgICAgICAgIGAke3NvdXJjZVN0YXRzLnNpemV9IGJ5dGVzIChtYXg6ICR7RklMRV9DT05TVEFOVFMuTUFYX0ZJTEVfU0laRX0gYnl0ZXMpYCxcbiAgICAgICAgICAgICAgeyBcbiAgICAgICAgICAgICAgICBmaWxlOiBub3JtYWxpemVkRmlsZS5ub3JtYWxpemVkQ29udGVudCwgXG4gICAgICAgICAgICAgICAgc2l6ZTogc291cmNlU3RhdHMuc2l6ZSxcbiAgICAgICAgICAgICAgICBtYXhTaXplOiBGSUxFX0NPTlNUQU5UUy5NQVhfRklMRV9TSVpFLFxuICAgICAgICAgICAgICAgIGVsZW1lbnRUeXBlIFxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgfVxuICAgICAgICAgIFxuICAgICAgICAgIC8vIENvcHkgdGhlIGZpbGUgd2l0aCB2ZXJpZmljYXRpb25cbiAgICAgICAgICBcbiAgICAgICAgICBhd2FpdCB0aGlzLmNvcHlGaWxlV2l0aFZlcmlmaWNhdGlvbihzb3VyY2VQYXRoLCBkZXN0UGF0aCk7XG4gICAgICAgICAgY29waWVkQ291bnQrKztcbiAgICAgICAgICBcbiAgICAgICAgICBsb2dnZXIuZGVidWcoYFtEZWZhdWx0RWxlbWVudFByb3ZpZGVyXSBDb3BpZWQgJHtlbGVtZW50VHlwZX06ICR7bm9ybWFsaXplZEZpbGUubm9ybWFsaXplZENvbnRlbnR9YCk7XG4gICAgICAgICAgXG4gICAgICAgICAgLy8gTG9nIHNlY3VyaXR5IGV2ZW50IGZvciBlYWNoIGZpbGUgY29waWVkXG4gICAgICAgICAgU2VjdXJpdHlNb25pdG9yLmxvZ1NlY3VyaXR5RXZlbnQoe1xuICAgICAgICAgICAgdHlwZTogJ0ZJTEVfQ09QSUVEJyxcbiAgICAgICAgICAgIHNldmVyaXR5OiAnTE9XJyxcbiAgICAgICAgICAgIHNvdXJjZTogJ0RlZmF1bHRFbGVtZW50UHJvdmlkZXIuY29weUVsZW1lbnRGaWxlcycsXG4gICAgICAgICAgICBkZXRhaWxzOiBgQ29waWVkIGRlZmF1bHQgJHtlbGVtZW50VHlwZX0gZmlsZTogJHtub3JtYWxpemVkRmlsZS5ub3JtYWxpemVkQ29udGVudH1gLFxuICAgICAgICAgICAgbWV0YWRhdGE6IHtcbiAgICAgICAgICAgICAgc291cmNlUGF0aCxcbiAgICAgICAgICAgICAgZGVzdFBhdGgsXG4gICAgICAgICAgICAgIGVsZW1lbnRUeXBlLFxuICAgICAgICAgICAgICBmaWxlU2l6ZTogKGF3YWl0IGZzLnN0YXQoZGVzdFBhdGgpKS5zaXplXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgY29uc3QgZXJyID0gZXJyb3IgYXMgRXJyb3I7XG4gICAgICAgICAgbG9nZ2VyLmVycm9yKFxuICAgICAgICAgICAgYFtEZWZhdWx0RWxlbWVudFByb3ZpZGVyXSBGYWlsZWQgdG8gY29weSAke25vcm1hbGl6ZWRGaWxlLm5vcm1hbGl6ZWRDb250ZW50fWAsXG4gICAgICAgICAgICB7IFxuICAgICAgICAgICAgICBlcnJvcjogZXJyLm1lc3NhZ2UsXG4gICAgICAgICAgICAgIHN0YWNrOiBlcnIuc3RhY2ssXG4gICAgICAgICAgICAgIHNvdXJjZVBhdGgsXG4gICAgICAgICAgICAgIGRlc3RQYXRoLFxuICAgICAgICAgICAgICBlbGVtZW50VHlwZVxuICAgICAgICAgICAgfVxuICAgICAgICAgICk7XG4gICAgICAgICAgLy8gQ29udGludWUgd2l0aCBvdGhlciBmaWxlcyBpbnN0ZWFkIG9mIGZhaWxpbmcgY29tcGxldGVseVxuICAgICAgICB9XG4gICAgICB9XG4gICAgICBcbiAgICAgIGlmIChjb3BpZWRDb3VudCA+IDApIHtcbiAgICAgICAgbG9nZ2VyLmluZm8oYFtEZWZhdWx0RWxlbWVudFByb3ZpZGVyXSBDb3BpZWQgJHtjb3BpZWRDb3VudH0gJHtlbGVtZW50VHlwZX0gZmlsZShzKWApO1xuICAgICAgfVxuICAgICAgXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGxvZ2dlci5lcnJvcihgW0RlZmF1bHRFbGVtZW50UHJvdmlkZXJdIEVycm9yIGNvcHlpbmcgJHtlbGVtZW50VHlwZX0gZmlsZXM6YCwgZXJyb3IpO1xuICAgIH1cbiAgICBcbiAgICByZXR1cm4gY29waWVkQ291bnQ7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBDb3B5IGEgZmlsZSB3aXRoIGludGVncml0eSB2ZXJpZmljYXRpb25cbiAgICogRW5zdXJlcyB0aGUgZmlsZSB3YXMgY29waWVkIGNvcnJlY3RseSBieSBjb21wYXJpbmcgc2l6ZXNcbiAgICovXG4gIC8qKlxuICAgKiBDYWxjdWxhdGUgY2hlY2tzdW0gb2YgYSBmaWxlIGZvciBpbnRlZ3JpdHkgdmVyaWZpY2F0aW9uXG4gICAqIEBwYXJhbSBmaWxlUGF0aCBQYXRoIHRvIHRoZSBmaWxlXG4gICAqIEByZXR1cm5zIEhleC1lbmNvZGVkIGNoZWNrc3VtXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGNhbGN1bGF0ZUNoZWNrc3VtKGZpbGVQYXRoOiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIGNvbnN0IGhhc2ggPSBjcmVhdGVIYXNoKEZJTEVfQ09OU1RBTlRTLkNIRUNLU1VNX0FMR09SSVRITSk7XG4gICAgY29uc3Qgc3RyZWFtID0gYXdhaXQgZnMub3BlbihmaWxlUGF0aCwgJ3InKTtcbiAgICBcbiAgICB0cnkge1xuICAgICAgY29uc3QgYnVmZmVyID0gQnVmZmVyLmFsbG9jKEZJTEVfQ09OU1RBTlRTLkNIVU5LX1NJWkUpO1xuICAgICAgbGV0IGJ5dGVzUmVhZDogbnVtYmVyO1xuICAgICAgXG4gICAgICBkbyB7XG4gICAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHN0cmVhbS5yZWFkKGJ1ZmZlciwgMCwgRklMRV9DT05TVEFOVFMuQ0hVTktfU0laRSk7XG4gICAgICAgIGJ5dGVzUmVhZCA9IHJlc3VsdC5ieXRlc1JlYWQ7XG4gICAgICAgIFxuICAgICAgICBpZiAoYnl0ZXNSZWFkID4gMCkge1xuICAgICAgICAgIGhhc2gudXBkYXRlKGJ1ZmZlci5zdWJhcnJheSgwLCBieXRlc1JlYWQpKTtcbiAgICAgICAgfVxuICAgICAgfSB3aGlsZSAoYnl0ZXNSZWFkID4gMCk7XG4gICAgICBcbiAgICAgIHJldHVybiBoYXNoLmRpZ2VzdCgnaGV4Jyk7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIGF3YWl0IHN0cmVhbS5jbG9zZSgpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBDb3B5IGZpbGUgd2l0aCBpbnRlZ3JpdHkgdmVyaWZpY2F0aW9uIGFuZCByZXRyeSBsb2dpY1xuICAgKiBAcGFyYW0gc291cmNlUGF0aCBTb3VyY2UgZmlsZSBwYXRoXG4gICAqIEBwYXJhbSBkZXN0UGF0aCBEZXN0aW5hdGlvbiBmaWxlIHBhdGhcbiAgICogQHRocm93cyBFcnJvciBpZiBjb3B5IGZhaWxzIGFmdGVyIGFsbCByZXRyeSBhdHRlbXB0c1xuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBjb3B5RmlsZVdpdGhWZXJpZmljYXRpb24oc291cmNlUGF0aDogc3RyaW5nLCBkZXN0UGF0aDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgbGV0IGxhc3RFcnJvcjogRXJyb3IgfCBudWxsID0gbnVsbDtcbiAgICBcbiAgICBmb3IgKGxldCBhdHRlbXB0ID0gMTsgYXR0ZW1wdCA8PSBDT1BZX1JFVFJZX0FUVEVNUFRTOyBhdHRlbXB0KyspIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIC8vIENvcHkgdGhlIGZpbGVcbiAgICAgICAgYXdhaXQgZnMuY29weUZpbGUoc291cmNlUGF0aCwgZGVzdFBhdGgpO1xuICAgICAgICBcbiAgICAgICAgLy8gVmVyaWZ5IHNpemUgbWF0Y2hlc1xuICAgICAgICBjb25zdCBbc291cmNlU3RhdHMsIGRlc3RTdGF0c10gPSBhd2FpdCBQcm9taXNlLmFsbChbXG4gICAgICAgICAgZnMuc3RhdChzb3VyY2VQYXRoKSxcbiAgICAgICAgICBmcy5zdGF0KGRlc3RQYXRoKVxuICAgICAgICBdKTtcbiAgICAgICAgXG4gICAgICAgIGlmIChzb3VyY2VTdGF0cy5zaXplICE9PSBkZXN0U3RhdHMuc2l6ZSkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICAgIGBTaXplIG1pc21hdGNoIGFmdGVyIGNvcHkgLSBzb3VyY2U6ICR7c291cmNlU3RhdHMuc2l6ZX0gYnl0ZXMsIGAgK1xuICAgICAgICAgICAgYGRlc3RpbmF0aW9uOiAke2Rlc3RTdGF0cy5zaXplfSBieXRlc2BcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICAgIFxuICAgICAgICAvLyBWZXJpZnkgY2hlY2tzdW0gbWF0Y2hlcyBmb3IgY29tcGxldGUgaW50ZWdyaXR5XG4gICAgICAgIGNvbnN0IFtzb3VyY2VDaGVja3N1bSwgZGVzdENoZWNrc3VtXSA9IGF3YWl0IFByb21pc2UuYWxsKFtcbiAgICAgICAgICB0aGlzLmNhbGN1bGF0ZUNoZWNrc3VtKHNvdXJjZVBhdGgpLFxuICAgICAgICAgIHRoaXMuY2FsY3VsYXRlQ2hlY2tzdW0oZGVzdFBhdGgpXG4gICAgICAgIF0pO1xuICAgICAgICBcbiAgICAgICAgaWYgKHNvdXJjZUNoZWNrc3VtICE9PSBkZXN0Q2hlY2tzdW0pIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgICBgQ2hlY2tzdW0gbWlzbWF0Y2ggYWZ0ZXIgY29weSAtIHNvdXJjZTogJHtzb3VyY2VDaGVja3N1bX0sIGAgK1xuICAgICAgICAgICAgYGRlc3RpbmF0aW9uOiAke2Rlc3RDaGVja3N1bX1gXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgICBcbiAgICAgICAgLy8gU2V0IHByb3BlciBwZXJtaXNzaW9uc1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGF3YWl0IGZzLmNobW9kKGRlc3RQYXRoLCBGSUxFX0NPTlNUQU5UUy5GSUxFX1BFUk1JU1NJT05TKTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICBsb2dnZXIuZGVidWcoXG4gICAgICAgICAgICBgW0RlZmF1bHRFbGVtZW50UHJvdmlkZXJdIENvdWxkIG5vdCBzZXQgcGVybWlzc2lvbnMgb24gJHtkZXN0UGF0aH06ICR7ZXJyb3J9YCxcbiAgICAgICAgICAgIHsgc291cmNlUGF0aCwgZGVzdFBhdGgsIGF0dGVtcHQgfVxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgICAgXG4gICAgICAgIC8vIFN1Y2Nlc3MgLSBmaWxlIGNvcGllZCBhbmQgdmVyaWZpZWRcbiAgICAgICAgbG9nZ2VyLmRlYnVnKFxuICAgICAgICAgIGBbRGVmYXVsdEVsZW1lbnRQcm92aWRlcl0gU3VjY2Vzc2Z1bGx5IGNvcGllZCBhbmQgdmVyaWZpZWQ6ICR7cGF0aC5iYXNlbmFtZShzb3VyY2VQYXRoKX1gLFxuICAgICAgICAgIHsgc2l6ZTogc291cmNlU3RhdHMuc2l6ZSwgY2hlY2tzdW06IHNvdXJjZUNoZWNrc3VtLnN1YnN0cmluZygwLCA4KSB9XG4gICAgICAgICk7XG4gICAgICAgIHJldHVybjtcbiAgICAgICAgXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBsYXN0RXJyb3IgPSBlcnJvciBhcyBFcnJvcjtcbiAgICAgICAgXG4gICAgICAgIC8vIENsZWFuIHVwIGZhaWxlZCBjb3B5XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgYXdhaXQgZnMudW5saW5rKGRlc3RQYXRoKTtcbiAgICAgICAgfSBjYXRjaCB7XG4gICAgICAgICAgLy8gSWdub3JlIGNsZWFudXAgZXJyb3JzXG4gICAgICAgIH1cbiAgICAgICAgXG4gICAgICAgIGlmIChhdHRlbXB0IDwgQ09QWV9SRVRSWV9BVFRFTVBUUykge1xuICAgICAgICAgIGxvZ2dlci5kZWJ1ZyhcbiAgICAgICAgICAgIGBbRGVmYXVsdEVsZW1lbnRQcm92aWRlcl0gQ29weSBhdHRlbXB0ICR7YXR0ZW1wdH0gZmFpbGVkLCByZXRyeWluZy4uLmAsXG4gICAgICAgICAgICB7IGVycm9yOiBsYXN0RXJyb3IubWVzc2FnZSwgc291cmNlUGF0aCwgZGVzdFBhdGggfVxuICAgICAgICAgICk7XG4gICAgICAgICAgYXdhaXQgbmV3IFByb21pc2UocmVzb2x2ZSA9PiBzZXRUaW1lb3V0KHJlc29sdmUsIENPUFlfUkVUUllfREVMQVkgKiBhdHRlbXB0KSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgLy8gQWxsIGF0dGVtcHRzIGZhaWxlZFxuICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgIGBGYWlsZWQgdG8gY29weSAke3BhdGguYmFzZW5hbWUoc291cmNlUGF0aCl9IGFmdGVyICR7Q09QWV9SRVRSWV9BVFRFTVBUU30gYXR0ZW1wdHM6IGAgK1xuICAgICAgYCR7bGFzdEVycm9yPy5tZXNzYWdlIHx8ICdVbmtub3duIGVycm9yJ31gXG4gICAgKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIFBvcHVsYXRlIHRoZSBwb3J0Zm9saW8gd2l0aCBkZWZhdWx0IGVsZW1lbnRzIGZyb20gYnVuZGxlZCBkYXRhXG4gICAqIFRoaXMgaXMgY2FsbGVkIGR1cmluZyBwb3J0Zm9saW8gaW5pdGlhbGl6YXRpb24gZm9yIG5ldyBpbnN0YWxsYXRpb25zXG4gICAqIFByb3RlY3RlZCBhZ2FpbnN0IGNvbmN1cnJlbnQgY2FsbHMgdG8gcHJldmVudCByYWNlIGNvbmRpdGlvbnNcbiAgICovXG4gIHB1YmxpYyBhc3luYyBwb3B1bGF0ZURlZmF1bHRzKHBvcnRmb2xpb0Jhc2VEaXI6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgIC8vIENoZWNrIGlmIHBvcHVsYXRpb24gaXMgYWxyZWFkeSBpbiBwcm9ncmVzcyBmb3IgdGhpcyBwb3J0Zm9saW9cbiAgICBjb25zdCBleGlzdGluZ1BvcHVsYXRpb24gPSBEZWZhdWx0RWxlbWVudFByb3ZpZGVyLnBvcHVsYXRlSW5Qcm9ncmVzcy5nZXQocG9ydGZvbGlvQmFzZURpcik7XG4gICAgaWYgKGV4aXN0aW5nUG9wdWxhdGlvbikge1xuICAgICAgbG9nZ2VyLmRlYnVnKFxuICAgICAgICAnW0RlZmF1bHRFbGVtZW50UHJvdmlkZXJdIFBvcHVsYXRpb24gYWxyZWFkeSBpbiBwcm9ncmVzcyBmb3IgcG9ydGZvbGlvLCB3YWl0aW5nLi4uJyxcbiAgICAgICAgeyBwb3J0Zm9saW9CYXNlRGlyIH1cbiAgICAgICk7XG4gICAgICByZXR1cm4gZXhpc3RpbmdQb3B1bGF0aW9uO1xuICAgIH1cbiAgICBcbiAgICAvLyBDcmVhdGUgbmV3IHBvcHVsYXRpb24gcHJvbWlzZVxuICAgIGNvbnN0IHBvcHVsYXRpb25Qcm9taXNlID0gdGhpcy5wZXJmb3JtUG9wdWxhdGlvbihwb3J0Zm9saW9CYXNlRGlyKVxuICAgICAgLmZpbmFsbHkoKCkgPT4ge1xuICAgICAgICAvLyBDbGVhbiB1cCB3aGVuIGRvbmVcbiAgICAgICAgRGVmYXVsdEVsZW1lbnRQcm92aWRlci5wb3B1bGF0ZUluUHJvZ3Jlc3MuZGVsZXRlKHBvcnRmb2xpb0Jhc2VEaXIpO1xuICAgICAgfSk7XG4gICAgXG4gICAgRGVmYXVsdEVsZW1lbnRQcm92aWRlci5wb3B1bGF0ZUluUHJvZ3Jlc3Muc2V0KHBvcnRmb2xpb0Jhc2VEaXIsIHBvcHVsYXRpb25Qcm9taXNlKTtcbiAgICByZXR1cm4gcG9wdWxhdGlvblByb21pc2U7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBQZXJmb3JtIHRoZSBhY3R1YWwgcG9wdWxhdGlvbiBvZiBkZWZhdWx0IGVsZW1lbnRzXG4gICAqIEBwYXJhbSBwb3J0Zm9saW9CYXNlRGlyIEJhc2UgZGlyZWN0b3J5IG9mIHRoZSBwb3J0Zm9saW9cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgcGVyZm9ybVBvcHVsYXRpb24ocG9ydGZvbGlvQmFzZURpcjogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgLy8gQ2hlY2sgaWYgdGVzdCBkYXRhIGxvYWRpbmcgaXMgZGlzYWJsZWRcbiAgICAvLyBOb3RlOiBUaGlzIGNoZWNrIGlzIG5lZWRlZCBldmVuIHRob3VnaCBjb25zdHJ1Y3RvciBzZXRzIGNvbmZpZywgYmVjYXVzZVxuICAgIC8vIGNvbmZpZyBjYW4gYmUgb3ZlcnJpZGRlbiBhZnRlciBjb25zdHJ1Y3Rpb25cbiAgICBcbiAgICAvLyBVc2UgcHJvZHVjdGlvbiBlbnZpcm9ubWVudCBkZXRlY3Rpb24gdGhhdCByZXNwZWN0cyBGT1JDRV9QUk9EVUNUSU9OX01PREVcbiAgICBjb25zdCBpc0RldmVsb3BtZW50TW9kZSA9ICF0aGlzLmlzUHJvZHVjdGlvbkVudmlyb25tZW50KCk7XG4gICAgXG4gICAgaWYgKGlzRGV2ZWxvcG1lbnRNb2RlICYmICF0aGlzLmNvbmZpZy5sb2FkVGVzdERhdGEpIHtcbiAgICAgIGxvZ2dlci5pbmZvKFxuICAgICAgICAnW0RlZmF1bHRFbGVtZW50UHJvdmlkZXJdIFNraXBwaW5nIGRlZmF1bHQgZWxlbWVudCBwb3B1bGF0aW9uIGluIGRldmVsb3BtZW50IG1vZGUnLFxuICAgICAgICB7IFxuICAgICAgICAgIHBvcnRmb2xpb0Jhc2VEaXIsXG4gICAgICAgICAgcmVhc29uOiAnVGVzdCBkYXRhIGxvYWRpbmcgZGlzYWJsZWQnLFxuICAgICAgICAgIGVuYWJsZVdpdGg6ICdTZXQgRE9MTEhPVVNFX0xPQURfVEVTVF9EQVRBPXRydWUgdG8gZW5hYmxlJ1xuICAgICAgICB9XG4gICAgICApO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBcbiAgICBsb2dnZXIuaW5mbyhcbiAgICAgICdbRGVmYXVsdEVsZW1lbnRQcm92aWRlcl0gU3RhcnRpbmcgZGVmYXVsdCBlbGVtZW50IHBvcHVsYXRpb24nLFxuICAgICAgeyBwb3J0Zm9saW9CYXNlRGlyIH1cbiAgICApO1xuICAgIFxuICAgIC8vIExvZyBzZWN1cml0eSBldmVudCBmb3IgcG9ydGZvbGlvIGluaXRpYWxpemF0aW9uXG4gICAgU2VjdXJpdHlNb25pdG9yLmxvZ1NlY3VyaXR5RXZlbnQoe1xuICAgICAgdHlwZTogJ1BPUlRGT0xJT19JTklUSUFMSVpBVElPTicsXG4gICAgICBzZXZlcml0eTogJ0xPVycsXG4gICAgICBzb3VyY2U6ICdEZWZhdWx0RWxlbWVudFByb3ZpZGVyLnBlcmZvcm1Qb3B1bGF0aW9uJyxcbiAgICAgIGRldGFpbHM6IGBTdGFydGluZyBkZWZhdWx0IGVsZW1lbnQgcG9wdWxhdGlvbiBmb3IgcG9ydGZvbGlvOiAke3BvcnRmb2xpb0Jhc2VEaXJ9YFxuICAgIH0pO1xuICAgIFxuICAgIC8vIEZpbmQgdGhlIGJ1bmRsZWQgZGF0YSBkaXJlY3RvcnlcbiAgICBjb25zdCBkYXRhRGlyID0gYXdhaXQgdGhpcy5maW5kRGF0YURpcmVjdG9yeSgpO1xuICAgIGlmICghZGF0YURpcikge1xuICAgICAgbG9nZ2VyLndhcm4oXG4gICAgICAgICdbRGVmYXVsdEVsZW1lbnRQcm92aWRlcl0gTm8gYnVuZGxlZCBkYXRhIGRpcmVjdG9yeSBmb3VuZCAtIHBvcnRmb2xpbyB3aWxsIHN0YXJ0IGVtcHR5JyxcbiAgICAgICAgeyBcbiAgICAgICAgICBzZWFyY2hQYXRoczogdGhpcy5kYXRhU2VhcmNoUGF0aHMuc2xpY2UoMCwgMyksIC8vIExvZyBmaXJzdCBmZXcgcGF0aHMgZm9yIGRlYnVnZ2luZ1xuICAgICAgICAgIGN3ZDogcHJvY2Vzcy5jd2QoKSxcbiAgICAgICAgICBkaXJuYW1lOiB0aGlzLl9fZGlybmFtZVxuICAgICAgICB9XG4gICAgICApO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBcbiAgICAvLyBUcmFjayB0b3RhbCBmaWxlcyBjb3BpZWRcbiAgICBsZXQgdG90YWxDb3BpZWQgPSAwO1xuICAgIGNvbnN0IGNvcGllZENvdW50czogUmVjb3JkPHN0cmluZywgbnVtYmVyPiA9IHt9O1xuICAgIFxuICAgIC8vIENvcHkgZWFjaCBlbGVtZW50IHR5cGUgLSBkaXJlY3RvcmllcyBub3cgbWF0Y2ggZW51bSB2YWx1ZXMgKGFsbCBwbHVyYWwpXG4gICAgZm9yIChjb25zdCBlbGVtZW50VHlwZSBvZiBPYmplY3QudmFsdWVzKEVsZW1lbnRUeXBlKSkge1xuICAgICAgY29uc3Qgc291cmNlRGlyID0gcGF0aC5qb2luKGRhdGFEaXIsIGVsZW1lbnRUeXBlKTtcbiAgICAgIGNvbnN0IGRlc3REaXIgPSBwYXRoLmpvaW4ocG9ydGZvbGlvQmFzZURpciwgZWxlbWVudFR5cGUpO1xuICAgICAgXG4gICAgICB0cnkge1xuICAgICAgICAvLyBDaGVjayBpZiBzb3VyY2UgZGlyZWN0b3J5IGV4aXN0c1xuICAgICAgICBhd2FpdCBmcy5hY2Nlc3Moc291cmNlRGlyKTtcbiAgICAgICAgY29uc3QgY29waWVkQ291bnQgPSBhd2FpdCB0aGlzLmNvcHlFbGVtZW50RmlsZXMoc291cmNlRGlyLCBkZXN0RGlyLCBlbGVtZW50VHlwZSk7XG4gICAgICAgIGNvcGllZENvdW50c1tlbGVtZW50VHlwZV0gPSBjb3BpZWRDb3VudDtcbiAgICAgICAgdG90YWxDb3BpZWQgKz0gY29waWVkQ291bnQ7XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAvLyBTb3VyY2UgZGlyZWN0b3J5IGRvZXNuJ3QgZXhpc3QsIHNraXBcbiAgICAgICAgbG9nZ2VyLmRlYnVnKGBbRGVmYXVsdEVsZW1lbnRQcm92aWRlcl0gTm8gJHtlbGVtZW50VHlwZX0gZGlyZWN0b3J5IGluIGJ1bmRsZWQgZGF0YWApO1xuICAgICAgfVxuICAgIH1cbiAgICBcbiAgICBpZiAodG90YWxDb3BpZWQgPiAwKSB7XG4gICAgICBsb2dnZXIuaW5mbyhcbiAgICAgICAgYFtEZWZhdWx0RWxlbWVudFByb3ZpZGVyXSBTdWNjZXNzZnVsbHkgcG9wdWxhdGVkIHBvcnRmb2xpbyB3aXRoICR7dG90YWxDb3BpZWR9IGRlZmF1bHQgZWxlbWVudChzKWAsXG4gICAgICAgIHtcbiAgICAgICAgICBwb3J0Zm9saW9CYXNlRGlyLFxuICAgICAgICAgIGRhdGFEaXIsXG4gICAgICAgICAgYnJlYWtkb3duOiBjb3BpZWRDb3VudHNcbiAgICAgICAgfVxuICAgICAgKTtcbiAgICAgIFxuICAgICAgLy8gTG9nIHNlY3VyaXR5IGV2ZW50IGZvciBzdWNjZXNzZnVsIHBvcHVsYXRpb25cbiAgICAgIFNlY3VyaXR5TW9uaXRvci5sb2dTZWN1cml0eUV2ZW50KHtcbiAgICAgICAgdHlwZTogJ1BPUlRGT0xJT19QT1BVTEFURUQnLFxuICAgICAgICBzZXZlcml0eTogJ0xPVycsXG4gICAgICAgIHNvdXJjZTogJ0RlZmF1bHRFbGVtZW50UHJvdmlkZXIucGVyZm9ybVBvcHVsYXRpb24nLFxuICAgICAgICBkZXRhaWxzOiBgU3VjY2Vzc2Z1bGx5IHBvcHVsYXRlZCBwb3J0Zm9saW8gd2l0aCAke3RvdGFsQ29waWVkfSBkZWZhdWx0IGVsZW1lbnRzYCxcbiAgICAgICAgbWV0YWRhdGE6IHtcbiAgICAgICAgICBwb3J0Zm9saW9CYXNlRGlyLFxuICAgICAgICAgIGRhdGFEaXIsXG4gICAgICAgICAgY29waWVkQ291bnRzXG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH0gZWxzZSB7XG4gICAgICBsb2dnZXIuaW5mbygnW0RlZmF1bHRFbGVtZW50UHJvdmlkZXJdIE5vIG5ldyBlbGVtZW50cyB0byBjb3B5IC0gcG9ydGZvbGlvIG1heSBhbHJlYWR5IGhhdmUgY29udGVudCcpO1xuICAgIH1cbiAgfVxufSJdfQ==