@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
@@ -1,730 +0,0 @@
1
- /**
2
- * Manage server updates and rollbacks
3
- */
4
- import * as path from 'path';
5
- import * as fs from 'fs/promises';
6
- import { safeExec } from '../utils/git.js';
7
- import { VersionManager } from './VersionManager.js';
8
- import { UpdateChecker } from './UpdateChecker.js';
9
- import { DependencyChecker } from './DependencyChecker.js';
10
- import { BackupManager } from './BackupManager.js';
11
- import { InstallationDetector } from '../utils/installation.js';
12
- import { logger } from '../utils/logger.js';
13
- import { compareVersions } from '../utils/version.js';
14
- import { FileOperations } from '../utils/fileOperations.js';
15
- import { UpdateConfigManager } from '../config/updateConfig.js';
16
- export class UpdateManager {
17
- versionManager;
18
- updateChecker;
19
- dependencyChecker;
20
- backupManager;
21
- rootDir;
22
- constructor(rootDir) {
23
- this.rootDir = rootDir || process.cwd();
24
- this.versionManager = new VersionManager();
25
- this.updateChecker = new UpdateChecker(this.versionManager);
26
- this.dependencyChecker = new DependencyChecker(this.versionManager);
27
- this.backupManager = new BackupManager(this.rootDir);
28
- }
29
- /**
30
- * Check for available updates
31
- */
32
- async checkForUpdates() {
33
- try {
34
- const result = await this.updateChecker.checkForUpdates();
35
- const text = this.updateChecker.formatUpdateCheckResult(result);
36
- return { text };
37
- }
38
- catch (error) {
39
- const text = this.updateChecker.formatUpdateCheckResult(null, error);
40
- return { text };
41
- }
42
- }
43
- /**
44
- * Perform server update
45
- */
46
- async updateServer(createBackup = true, personaIndicator = '') {
47
- const progress = [];
48
- try {
49
- // Detect installation type
50
- const installationType = InstallationDetector.getInstallationType();
51
- logger.info(`[UpdateManager] Detected installation type: ${installationType}`);
52
- // Handle npm installations differently
53
- if (installationType === 'npm') {
54
- return this.updateNpmInstallation(createBackup, personaIndicator);
55
- }
56
- // For git installations, proceed with existing logic
57
- // Step 1: Check dependencies
58
- progress.push({ step: 'dependencies', message: 'Checking system dependencies...', isComplete: false });
59
- const dependencies = await this.dependencyChecker.checkDependencies();
60
- if (!dependencies.git.installed || dependencies.git.error) {
61
- return {
62
- text: personaIndicator + '❌ **Update Failed**\n\n' +
63
- 'Git is required for updates but is not available.\n' +
64
- dependencies.git.error || 'Git is not installed.'
65
- };
66
- }
67
- if (!dependencies.npm.installed || dependencies.npm.error) {
68
- return {
69
- text: personaIndicator + '❌ **Update Failed**\n\n' +
70
- 'npm is required for updates but is not available.\n' +
71
- dependencies.npm.error || 'npm is not installed.'
72
- };
73
- }
74
- progress[0].isComplete = true;
75
- // Step 2: Create backup if requested
76
- if (createBackup) {
77
- progress.push({ step: 'backup', message: 'Creating backup...', isComplete: false });
78
- const currentVersion = await this.versionManager.getCurrentVersion();
79
- const backup = await this.backupManager.createBackup(currentVersion);
80
- progress[1].isComplete = true;
81
- progress[1].message = `Backup created at: ${backup.timestamp}`;
82
- }
83
- // Step 3: Git fetch
84
- progress.push({ step: 'fetch', message: 'Fetching latest changes...', isComplete: false });
85
- await safeExec('git', ['fetch', 'origin'], { cwd: this.rootDir });
86
- progress[progress.length - 1].isComplete = true;
87
- // Step 4: Check for uncommitted changes
88
- progress.push({ step: 'check', message: 'Checking for uncommitted changes...', isComplete: false });
89
- const { stdout: statusOutput } = await safeExec('git', ['status', '--porcelain'], { cwd: this.rootDir });
90
- if (statusOutput.trim()) {
91
- return {
92
- text: personaIndicator + '❌ **Update Failed**\n\n' +
93
- 'You have uncommitted changes. Please commit or stash them before updating.\n\n' +
94
- 'Modified files:\n' + statusOutput
95
- };
96
- }
97
- progress[progress.length - 1].isComplete = true;
98
- // Step 5: Git pull
99
- progress.push({ step: 'pull', message: 'Pulling latest changes...', isComplete: false });
100
- const { stdout: pullOutput } = await safeExec('git', ['pull', 'origin', 'main'], { cwd: this.rootDir });
101
- progress[progress.length - 1].isComplete = true;
102
- // Check if already up to date
103
- if (pullOutput.includes('Already up to date')) {
104
- return {
105
- text: personaIndicator + '✅ **Already Up to Date**\n\n' +
106
- 'Your DollhouseMCP installation is already at the latest version.\n\n' +
107
- 'No changes were pulled from the repository.'
108
- };
109
- }
110
- // Step 6: npm install
111
- progress.push({ step: 'install', message: 'Installing dependencies...', isComplete: false });
112
- await safeExec('npm', ['install'], { cwd: this.rootDir });
113
- progress[progress.length - 1].isComplete = true;
114
- // Step 7: Build
115
- progress.push({ step: 'build', message: 'Building TypeScript...', isComplete: false });
116
- await safeExec('npm', ['run', 'build'], { cwd: this.rootDir });
117
- progress[progress.length - 1].isComplete = true;
118
- // Step 8: Cleanup old backups
119
- if (createBackup) {
120
- progress.push({ step: 'cleanup', message: 'Cleaning up old backups...', isComplete: false });
121
- const deletedCount = await this.backupManager.cleanupOldBackups();
122
- progress[progress.length - 1].isComplete = true;
123
- progress[progress.length - 1].message = `Cleaned up ${deletedCount} old backup(s)`;
124
- }
125
- // Format success message
126
- const successParts = [
127
- personaIndicator + '✅ **Update Complete!**\n\n',
128
- '**Update Summary:**\n'
129
- ];
130
- progress.forEach(p => {
131
- successParts.push(`${p.isComplete ? '✅' : '❌'} ${p.message}\n`);
132
- });
133
- successParts.push('\n**Next Steps:**\n', '1. The server will restart automatically\n', '2. All personas will be reloaded\n', '3. Check `get_server_status` to verify the new version\n\n', '💡 **Tip:** If you encounter issues, use `rollback_update true` to restore the previous version.');
134
- return { text: successParts.join('') };
135
- }
136
- catch (error) {
137
- const errorMessage = error instanceof Error ? error.message : String(error);
138
- return {
139
- text: personaIndicator + '❌ **Update Failed**\n\n' +
140
- 'Error: ' + errorMessage + '\n\n' +
141
- '**Progress:**\n' +
142
- progress.map(p => `${p.isComplete ? '✅' : '❌'} ${p.message}`).join('\n') + '\n\n' +
143
- '**Recovery Options:**\n' +
144
- '• Try running the update again\n' +
145
- '• Check your internet connection\n' +
146
- '• Ensure you have proper permissions\n' +
147
- '• If a backup was created, use `rollback_update true` to restore'
148
- };
149
- }
150
- }
151
- /**
152
- * Rollback to previous version
153
- */
154
- async rollbackUpdate(force = false, personaIndicator = '') {
155
- try {
156
- // Check installation type
157
- const installationType = InstallationDetector.getInstallationType();
158
- if (installationType === 'npm') {
159
- return this.rollbackNpmInstallation(force, personaIndicator);
160
- }
161
- // For git installations, use existing logic
162
- // Get latest backup
163
- const latestBackup = await this.backupManager.getLatestBackup();
164
- if (!latestBackup) {
165
- return {
166
- text: personaIndicator + '❌ **No Backups Found**\n\n' +
167
- 'There are no backups available to restore.\n\n' +
168
- 'Backups are created automatically when you run `update_server true`.'
169
- };
170
- }
171
- // Check if rollback is needed
172
- if (!force) {
173
- try {
174
- // Test if the server is working by checking version
175
- await this.versionManager.getCurrentVersion();
176
- return {
177
- text: personaIndicator + '⚠️ **Rollback Confirmation Required**\n\n' +
178
- 'The server appears to be working normally.\n\n' +
179
- `**Latest Backup:** ${latestBackup.timestamp}\n` +
180
- `**Backup Version:** ${latestBackup.version || 'Unknown'}\n\n` +
181
- 'To force rollback anyway, use: `rollback_update true`\n\n' +
182
- '⚠️ **Warning:** This will restore all files to the backup state.'
183
- };
184
- }
185
- catch {
186
- // Server is broken, proceed with rollback
187
- }
188
- }
189
- // Perform rollback
190
- await this.backupManager.restoreBackup(latestBackup.path);
191
- // Reinstall dependencies
192
- await safeExec('npm', ['install'], { cwd: this.rootDir });
193
- // Rebuild
194
- await safeExec('npm', ['run', 'build'], { cwd: this.rootDir });
195
- return {
196
- text: personaIndicator + '✅ **Rollback Complete!**\n\n' +
197
- `Restored from backup: ${latestBackup.timestamp}\n` +
198
- `Backup version: ${latestBackup.version || 'Unknown'}\n\n` +
199
- '**What was restored:**\n' +
200
- '• All source files\n' +
201
- '• Configuration files\n' +
202
- '• Dependencies reinstalled\n' +
203
- '• TypeScript rebuilt\n\n' +
204
- '**Next Steps:**\n' +
205
- '1. The server will restart automatically\n' +
206
- '2. Check `get_server_status` to verify the version\n' +
207
- '3. Test your personas to ensure everything works'
208
- };
209
- }
210
- catch (error) {
211
- const errorMessage = error instanceof Error ? error.message : String(error);
212
- return {
213
- text: personaIndicator + '❌ **Rollback Failed**\n\n' +
214
- 'Error: ' + errorMessage + '\n\n' +
215
- '**Manual Recovery:**\n' +
216
- '1. Check the backups directory: ../dollhousemcp-backups/\n' +
217
- '2. Manually restore files if needed\n' +
218
- '3. Run `npm install` and `npm run build`\n' +
219
- '4. Contact support if issues persist'
220
- };
221
- }
222
- }
223
- /**
224
- * Update npm installation
225
- */
226
- async updateNpmInstallation(createBackup, personaIndicator = '') {
227
- try {
228
- logger.info('[UpdateManager] Starting npm update process');
229
- // Check npm is available
230
- const dependencies = await this.dependencyChecker.checkDependencies();
231
- if (!dependencies.npm.installed || dependencies.npm.error) {
232
- return {
233
- text: personaIndicator + '❌ **Update Failed**\n\n' +
234
- 'npm is required for updates but is not available.\n' +
235
- dependencies.npm.error || 'npm is not installed.'
236
- };
237
- }
238
- // Get current version
239
- const currentVersion = await this.versionManager.getCurrentVersion();
240
- logger.info(`[UpdateManager] Current version: ${currentVersion}`);
241
- // Check latest version from npm registry
242
- logger.info('[UpdateManager] Checking npm registry for latest version');
243
- // Security: Validate package name to prevent any potential injection
244
- const packageName = '@dollhousemcp/mcp-server';
245
- if (!/^@[a-z0-9-]+\/[a-z0-9-]+$/.test(packageName)) {
246
- throw new Error('Invalid package name format');
247
- }
248
- const { stdout: npmViewOutput } = await safeExec('npm', ['view', packageName, 'version'], {
249
- cwd: this.rootDir,
250
- timeout: 30000
251
- });
252
- const latestVersion = npmViewOutput.trim();
253
- logger.info(`[UpdateManager] Latest npm version: ${latestVersion}`);
254
- // Compare versions
255
- const comparison = compareVersions(currentVersion, latestVersion);
256
- if (comparison >= 0) {
257
- return {
258
- text: personaIndicator + '✅ **Already up to date!**\n\n' +
259
- `Current version: ${currentVersion}\n` +
260
- `Latest version: ${latestVersion}\n\n` +
261
- 'No update needed.'
262
- };
263
- }
264
- // Get configuration
265
- const config = UpdateConfigManager.getInstance();
266
- // Progress tracking
267
- let progressMessage = personaIndicator + '🔄 **NPM Update in Progress**\n\n';
268
- progressMessage += '**Steps:**\n';
269
- progressMessage += '✅ Version check complete\n';
270
- progressMessage += '⏳ Creating backup...\n';
271
- // For npm installations, backup is mandatory for safety
272
- logger.info('[UpdateManager] Creating backup before npm update');
273
- try {
274
- // For npm installations, we backup the global installation directory
275
- const npmGlobalPath = InstallationDetector.getNpmGlobalPath();
276
- if (!npmGlobalPath) {
277
- throw new Error('Could not determine npm global installation path');
278
- }
279
- // Create npm-specific backup with progress
280
- const backupPath = await this.backupManager.createNpmBackup(npmGlobalPath, currentVersion);
281
- logger.info(`[UpdateManager] Backup created at: ${backupPath}`);
282
- progressMessage = progressMessage.replace('⏳ Creating backup...', '✅ Backup created');
283
- progressMessage += '⏳ Downloading and installing update...\n';
284
- }
285
- catch (backupError) {
286
- logger.error('[UpdateManager] Backup failed:', backupError);
287
- return {
288
- text: personaIndicator + '❌ **Update Failed**\n\n' +
289
- 'Failed to create backup before update.\n' +
290
- 'Error: ' + (backupError instanceof Error ? backupError.message : String(backupError)) + '\n\n' +
291
- '**Note:** Backup is mandatory for npm installations to ensure safe rollback.\n' +
292
- 'Please check disk space and permissions.'
293
- };
294
- }
295
- // Perform npm update with progress
296
- logger.info('[UpdateManager] Running npm update -g @dollhousemcp/mcp-server');
297
- progressMessage += '\n**Progress:**\n';
298
- progressMessage += '```\n';
299
- progressMessage += 'Running: npm update -g @dollhousemcp/mcp-server\n';
300
- progressMessage += 'This may take a few minutes...\n';
301
- progressMessage += '```\n';
302
- const updateResult = await safeExec('npm', ['update', '-g', '@dollhousemcp/mcp-server'], {
303
- cwd: this.rootDir,
304
- timeout: config.getNpmUpdateTimeout()
305
- });
306
- logger.info('[UpdateManager] npm update completed', updateResult);
307
- // Verify update succeeded
308
- const { stdout: verifyOutput } = await safeExec('npm', ['list', '-g', '@dollhousemcp/mcp-server', '--depth=0'], {
309
- cwd: this.rootDir,
310
- timeout: 30000
311
- });
312
- const versionMatch = verifyOutput.match(/@dollhousemcp\/mcp-server@(\d+\.\d+\.\d+)/);
313
- const installedVersion = versionMatch ? versionMatch[1] : 'unknown';
314
- if (installedVersion !== latestVersion) {
315
- logger.warn(`[UpdateManager] Version mismatch after update. Expected: ${latestVersion}, Got: ${installedVersion}`);
316
- }
317
- return {
318
- text: personaIndicator + '✅ **Update Complete!**\n\n' +
319
- `Updated from v${currentVersion} to v${latestVersion}\n\n` +
320
- '**What was updated:**\n' +
321
- '• DollhouseMCP server package\n' +
322
- '• All dependencies\n\n' +
323
- '**Next Steps:**\n' +
324
- '1. The server will restart automatically\n' +
325
- '2. Check `get_server_status` to verify the new version\n' +
326
- '3. Test your personas to ensure everything works\n\n' +
327
- '💡 **Tip:** If you encounter issues, use `rollback_update true` to restore the previous version.'
328
- };
329
- }
330
- catch (error) {
331
- logger.error('[UpdateManager] npm update failed:', error);
332
- const errorMessage = error instanceof Error ? error.message : String(error);
333
- return {
334
- text: personaIndicator + '❌ **Update Failed**\n\n' +
335
- 'Error: ' + errorMessage + '\n\n' +
336
- '**Troubleshooting:**\n' +
337
- '1. Ensure you have permission to update global npm packages\n' +
338
- '2. Try running with sudo if on macOS/Linux\n' +
339
- '3. Check your internet connection\n' +
340
- '4. Verify npm registry is accessible\n\n' +
341
- '**Manual Update:**\n' +
342
- '```\n' +
343
- 'npm update -g @dollhousemcp/mcp-server\n' +
344
- '```'
345
- };
346
- }
347
- }
348
- /**
349
- * Rollback npm installation
350
- */
351
- async rollbackNpmInstallation(force, personaIndicator = '') {
352
- try {
353
- logger.info('[UpdateManager] Starting npm rollback process');
354
- // Get npm backup manifest from configuration
355
- const config = UpdateConfigManager.getInstance();
356
- const npmBackupsDir = config.getNpmBackupDir();
357
- const manifestPath = path.join(npmBackupsDir, 'manifest.json');
358
- let manifest;
359
- try {
360
- const content = await fs.readFile(manifestPath, 'utf-8');
361
- manifest = JSON.parse(content);
362
- }
363
- catch (error) {
364
- return {
365
- text: personaIndicator + '❌ **No NPM Backups Found**\n\n' +
366
- 'There are no npm backups available to restore.\n\n' +
367
- 'Backups are created automatically when you run `update_server true` with npm installations.'
368
- };
369
- }
370
- if (!manifest.backups || manifest.backups.length === 0) {
371
- return {
372
- text: personaIndicator + '❌ **No NPM Backups Found**\n\n' +
373
- 'The backup manifest is empty.\n\n' +
374
- 'Backups are created automatically when you run `update_server true`.'
375
- };
376
- }
377
- // Get latest backup
378
- const latestBackup = manifest.backups[0];
379
- // Check if rollback is needed
380
- if (!force) {
381
- try {
382
- // Test if the server is working
383
- await this.versionManager.getCurrentVersion();
384
- return {
385
- text: personaIndicator + '⚠️ **Rollback Confirmation Required**\n\n' +
386
- 'The server appears to be working normally.\n\n' +
387
- `**Latest Backup:** ${latestBackup.timestamp}\n` +
388
- `**Backup Version:** ${latestBackup.version || 'Unknown'}\n\n` +
389
- 'To force rollback anyway, use: `rollback_update true`\n\n' +
390
- '⚠️ **Warning:** This will restore the npm package to the backup state.'
391
- };
392
- }
393
- catch {
394
- // Server is broken, proceed with rollback
395
- }
396
- }
397
- // Get npm global path
398
- const npmGlobalPath = InstallationDetector.getNpmGlobalPath();
399
- if (!npmGlobalPath) {
400
- return {
401
- text: personaIndicator + '❌ **Rollback Failed**\n\n' +
402
- 'Could not determine npm global installation path.\n\n' +
403
- 'Please reinstall manually:\n' +
404
- '```\n' +
405
- 'npm install -g @dollhousemcp/mcp-server@' + (latestBackup.version || 'latest') + '\n' +
406
- '```'
407
- };
408
- }
409
- logger.info(`[UpdateManager] Restoring npm backup from: ${latestBackup.path}`);
410
- // First validate that the backup is restorable
411
- const backupPackagePath = path.join(latestBackup.path, 'package');
412
- try {
413
- await fs.access(backupPackagePath);
414
- const packageJsonPath = path.join(backupPackagePath, 'package.json');
415
- await fs.access(packageJsonPath);
416
- }
417
- catch (error) {
418
- return {
419
- text: personaIndicator + '❌ **Backup Validation Failed**\n\n' +
420
- 'The backup appears to be corrupted or incomplete.\n\n' +
421
- '**Details:**\n' +
422
- `Backup path: ${latestBackup.path}\n` +
423
- `Error: ${error instanceof Error ? error.message : String(error)}\n\n` +
424
- '**Manual Recovery:**\n' +
425
- 'Try another backup or reinstall manually:\n' +
426
- '```bash\n' +
427
- 'npm install -g @dollhousemcp/mcp-server@' + (latestBackup.version || '1.4.0') + '\n' +
428
- '```'
429
- };
430
- }
431
- // Use transaction for atomic operations
432
- const tempPath = `${npmGlobalPath}.tmp-${Date.now()}`;
433
- const backupPath = `${npmGlobalPath}.backup-${Date.now()}`;
434
- const transaction = FileOperations.createTransaction();
435
- try {
436
- // Step 1: Copy backup to temporary location
437
- await transaction.addCopy(backupPackagePath, tempPath);
438
- // Step 2: Move current installation to backup (atomic)
439
- await transaction.addMove(npmGlobalPath, backupPath);
440
- // Step 3: Move temp to final location (atomic)
441
- await transaction.addMove(tempPath, npmGlobalPath);
442
- // All operations successful, commit the transaction
443
- transaction.commit();
444
- // Step 4: Clean up old backup (not part of transaction)
445
- await fs.rm(backupPath, { recursive: true, force: true }).catch(() => {
446
- logger.warn(`[UpdateManager] Failed to cleanup backup at: ${backupPath}`);
447
- });
448
- }
449
- catch (rollbackError) {
450
- logger.error('[UpdateManager] Rollback operation failed, attempting recovery:', rollbackError);
451
- // Rollback all operations
452
- if (transaction.hasOperations()) {
453
- await transaction.rollback();
454
- }
455
- // Additional recovery attempt
456
- try {
457
- // Check if npm path exists and is accessible
458
- await fs.access(npmGlobalPath);
459
- logger.info('[UpdateManager] NPM installation appears intact after rollback');
460
- }
461
- catch {
462
- // Try to restore from backup if main path is missing
463
- try {
464
- await fs.rename(backupPath, npmGlobalPath);
465
- logger.info('[UpdateManager] Restored from backup path');
466
- }
467
- catch {
468
- logger.error('[UpdateManager] Complete rollback failure - manual intervention required');
469
- }
470
- }
471
- throw rollbackError;
472
- }
473
- return {
474
- text: personaIndicator + '✅ **NPM Rollback Complete!**\n\n' +
475
- `Restored from backup: ${latestBackup.timestamp}\n` +
476
- `Backup version: ${latestBackup.version || 'Unknown'}\n\n` +
477
- '**What was restored:**\n' +
478
- '• NPM package files\n' +
479
- '• All dependencies\n\n' +
480
- '**Next Steps:**\n' +
481
- '1. The server will restart automatically\n' +
482
- '2. Check `get_server_status` to verify the version\n' +
483
- '3. Test your personas to ensure everything works'
484
- };
485
- }
486
- catch (error) {
487
- logger.error('[UpdateManager] npm rollback failed:', error);
488
- const errorMessage = error instanceof Error ? error.message : String(error);
489
- return {
490
- text: personaIndicator + '❌ **NPM Rollback Failed**\n\n' +
491
- 'Error: ' + errorMessage + '\n\n' +
492
- '**Manual Recovery:**\n' +
493
- '1. Check the backups directory: ~/.dollhouse/backups/npm/\n' +
494
- '2. Reinstall a specific version:\n' +
495
- ' ```\n' +
496
- ' npm install -g @dollhousemcp/mcp-server@1.4.0\n' +
497
- ' ```\n' +
498
- '3. Contact support if issues persist'
499
- };
500
- }
501
- }
502
- /**
503
- * Copy directory recursively with progress reporting
504
- * @deprecated Use FileOperations.copyDirectory instead
505
- */
506
- async copyDirectory(src, dest) {
507
- await FileOperations.copyDirectory(src, dest, {
508
- excludePatterns: ['.git', 'node_modules'],
509
- onProgress: (copied, total, file) => {
510
- logger.debug(`[UpdateManager] Copying files: ${copied}/${total} - ${path.basename(file)}`);
511
- }
512
- });
513
- }
514
- /**
515
- * Convert npm installation to git installation
516
- */
517
- async convertToGitInstallation(targetDir, confirm = false, personaIndicator = '') {
518
- try {
519
- const installationType = InstallationDetector.getInstallationType();
520
- if (installationType === 'git') {
521
- return {
522
- text: personaIndicator + '⚠️ **Already a Git Installation**\n\n' +
523
- 'This server is already running from a git installation.\n' +
524
- 'No conversion needed.'
525
- };
526
- }
527
- if (installationType === 'unknown') {
528
- return {
529
- text: personaIndicator + '❌ **Installation Type Unknown**\n\n' +
530
- 'Cannot determine the current installation type.\n' +
531
- 'Please check your installation manually.'
532
- };
533
- }
534
- // Default target directory
535
- const defaultTargetDir = path.join(process.env.HOME || '', '.dollhouse', 'mcp-server-git');
536
- const gitTargetDir = targetDir || defaultTargetDir;
537
- if (!confirm) {
538
- return {
539
- text: personaIndicator + '🔄 **Convert to Git Installation**\n\n' +
540
- '**This will:**\n' +
541
- `1. Clone DollhouseMCP to: ${gitTargetDir}\n` +
542
- '2. Copy your portfolio and settings\n' +
543
- '3. Build the TypeScript code\n' +
544
- '4. Provide Claude Desktop configuration\n\n' +
545
- '**Benefits of Git Installation:**\n' +
546
- '• Full control over updates\n' +
547
- '• Access to development branches\n' +
548
- '• Ability to contribute changes\n' +
549
- '• Rollback to any commit\n\n' +
550
- '**To proceed:**\n' +
551
- '`convert_to_git_installation true`\n\n' +
552
- '**To use custom directory:**\n' +
553
- '`convert_to_git_installation "/path/to/dir" true`'
554
- };
555
- }
556
- logger.info(`[UpdateManager] Starting conversion to git installation at: ${gitTargetDir}`);
557
- // Check if target directory already exists
558
- try {
559
- await fs.access(gitTargetDir);
560
- return {
561
- text: personaIndicator + '❌ **Target Directory Exists**\n\n' +
562
- `The directory ${gitTargetDir} already exists.\n\n` +
563
- '**Options:**\n' +
564
- '1. Remove the existing directory first\n' +
565
- '2. Choose a different target directory\n' +
566
- '3. Use the existing git installation'
567
- };
568
- }
569
- catch {
570
- // Directory doesn't exist, good to proceed
571
- }
572
- // Progress message builder
573
- let progressSteps = personaIndicator + '🔄 **Git Installation Progress**\n\n';
574
- progressSteps += '**Steps:**\n';
575
- progressSteps += '⏳ Cloning repository...\n';
576
- progressSteps += '⏳ Installing dependencies...\n';
577
- progressSteps += '⏳ Building TypeScript...\n';
578
- progressSteps += '⏳ Setting up configuration...\n\n';
579
- progressSteps += '**Current Step:** Cloning repository\n';
580
- progressSteps += '```\n';
581
- progressSteps += `Target: ${gitTargetDir}\n`;
582
- progressSteps += 'This may take a few minutes depending on your connection...\n';
583
- progressSteps += '```\n';
584
- // Get configuration
585
- const config = UpdateConfigManager.getInstance();
586
- // Step 1: Clone the repository
587
- logger.info('[UpdateManager] Cloning repository...');
588
- // SECURITY FIX: Validate gitTargetDir to prevent command injection
589
- // Previously: gitTargetDir passed directly to git clone command
590
- // Now: Reject paths starting with '--' to prevent git option injection
591
- if (gitTargetDir.startsWith('--')) {
592
- throw new Error('Invalid target directory: cannot start with git options');
593
- }
594
- await safeExec('git', ['clone', 'https://github.com/DollhouseMCP/mcp-server.git', gitTargetDir], {
595
- timeout: config.getGitCloneTimeout()
596
- });
597
- progressSteps = progressSteps.replace('⏳ Cloning repository...', '✅ Repository cloned');
598
- progressSteps = progressSteps.replace('**Current Step:** Cloning repository', '**Current Step:** Installing dependencies');
599
- // Step 2: Install dependencies
600
- logger.info('[UpdateManager] Installing dependencies...');
601
- await safeExec('npm', ['install'], {
602
- cwd: gitTargetDir,
603
- timeout: config.getNpmInstallTimeout()
604
- });
605
- progressSteps = progressSteps.replace('⏳ Installing dependencies...', '✅ Dependencies installed');
606
- progressSteps = progressSteps.replace('**Current Step:** Installing dependencies', '**Current Step:** Building TypeScript');
607
- // Step 3: Build TypeScript
608
- logger.info('[UpdateManager] Building TypeScript...');
609
- await safeExec('npm', ['run', 'build'], {
610
- cwd: gitTargetDir,
611
- timeout: config.getBuildTimeout()
612
- });
613
- progressSteps = progressSteps.replace('⏳ Building TypeScript...', '✅ TypeScript built');
614
- progressSteps = progressSteps.replace('**Current Step:** Building TypeScript', '**Current Step:** Configuration');
615
- // Step 4: Copy portfolio
616
- const portfolioSource = path.join(process.env.HOME || '', '.dollhouse', 'portfolio');
617
- const portfolioTarget = path.join(process.env.HOME || '', '.dollhouse', 'portfolio');
618
- logger.info('[UpdateManager] Portfolio will remain at: ' + portfolioTarget);
619
- // Step 5: Generate Claude Desktop config
620
- const configPath = path.join(gitTargetDir, 'dist', 'index.js');
621
- const claudeConfig = {
622
- mcpServers: {
623
- dollhousemcp: {
624
- command: 'node',
625
- args: [configPath]
626
- }
627
- }
628
- };
629
- return {
630
- text: personaIndicator + '✅ **Git Installation Complete!**\n\n' +
631
- `**Installation Location:** ${gitTargetDir}\n\n` +
632
- '**Next Steps:**\n\n' +
633
- '1. **Update Claude Desktop configuration:**\n' +
634
- ' ```json\n' +
635
- JSON.stringify(claudeConfig, null, 2) + '\n' +
636
- ' ```\n\n' +
637
- '2. **Restart Claude Desktop**\n\n' +
638
- '3. **Verify installation:**\n' +
639
- ' After restart, run `get_server_status` to confirm\n\n' +
640
- '**Your portfolio remains at:**\n' +
641
- ` ${portfolioTarget}\n\n` +
642
- '**To update in the future:**\n' +
643
- ' ```bash\n' +
644
- ` cd ${gitTargetDir}\n` +
645
- ' git pull\n' +
646
- ' npm install\n' +
647
- ' npm run build\n' +
648
- ' ```\n\n' +
649
- '💡 **Tip:** You can now use `update_server` to update via git!'
650
- };
651
- }
652
- catch (error) {
653
- logger.error('[UpdateManager] Git conversion failed:', error);
654
- const errorMessage = error instanceof Error ? error.message : String(error);
655
- return {
656
- text: personaIndicator + '❌ **Conversion Failed**\n\n' +
657
- 'Error: ' + errorMessage + '\n\n' +
658
- '**Troubleshooting:**\n' +
659
- '1. Ensure git is installed\n' +
660
- '2. Check internet connection\n' +
661
- '3. Verify you have write permissions\n' +
662
- '4. Try a different target directory'
663
- };
664
- }
665
- }
666
- /**
667
- * Get current server status
668
- */
669
- async getServerStatus(personaIndicator = '') {
670
- try {
671
- const currentVersion = await this.versionManager.getCurrentVersion();
672
- const dependencies = await this.dependencyChecker.checkDependencies();
673
- const backups = await this.backupManager.listBackups();
674
- const rateLimitStatus = this.updateChecker.getRateLimitStatus();
675
- // Get installation type
676
- const installationType = InstallationDetector.getInstallationType();
677
- const installationDesc = InstallationDetector.getInstallationDescription();
678
- // Get git status (only for git installations)
679
- let gitStatus = 'N/A';
680
- let gitBranch = 'N/A';
681
- let lastCommit = 'N/A';
682
- if (installationType === 'git') {
683
- try {
684
- const { stdout: branchOutput } = await safeExec('git', ['branch', '--show-current'], { cwd: this.rootDir });
685
- gitBranch = branchOutput.trim() || 'detached';
686
- const { stdout: statusOutput } = await safeExec('git', ['status', '--porcelain'], { cwd: this.rootDir });
687
- gitStatus = statusOutput.trim() ? 'Modified' : 'Clean';
688
- const { stdout: logOutput } = await safeExec('git', ['log', '-1', '--oneline'], { cwd: this.rootDir });
689
- lastCommit = logOutput.trim();
690
- }
691
- catch {
692
- // Git commands failed, use defaults
693
- }
694
- }
695
- const statusParts = [
696
- personaIndicator + '📊 **DollhouseMCP Server Status**\n\n',
697
- '**Version Information:**\n',
698
- `• Current Version: ${currentVersion}\n`,
699
- `• Installation Type: ${installationType} (${installationDesc})\n`,
700
- `• Git Branch: ${gitBranch}\n`,
701
- `• Git Status: ${gitStatus}\n`,
702
- `• Last Commit: ${lastCommit}\n\n`,
703
- '**Dependencies:**\n',
704
- this.dependencyChecker.formatDependencyStatus(dependencies),
705
- '\n\n**Backups:**\n',
706
- `• Total Backups: ${backups.length}\n`
707
- ];
708
- if (backups.length > 0) {
709
- statusParts.push(`• Latest Backup: ${backups[0].timestamp} (v${backups[0].version || 'unknown'})\n`);
710
- statusParts.push(`• Oldest Backup: ${backups[backups.length - 1].timestamp}\n`);
711
- }
712
- statusParts.push('\n**Rate Limit Status:**\n', `• Update Checks Remaining: ${rateLimitStatus.remainingRequests}/10 per hour\n`, `• Rate Limit Resets: ${rateLimitStatus.resetTime.toLocaleTimeString()}\n`);
713
- if (!rateLimitStatus.allowed && rateLimitStatus.waitTimeSeconds) {
714
- statusParts.push(`• ⏳ Wait ${rateLimitStatus.waitTimeSeconds} seconds before next check\n`);
715
- }
716
- statusParts.push('\n**Available Commands:**\n', '• `check_for_updates` - Check for new versions\n', '• `update_server true` - Update to latest version\n', '• `rollback_update true` - Restore from backup\n');
717
- return { text: statusParts.join('') };
718
- }
719
- catch (error) {
720
- const errorMessage = error instanceof Error ? error.message : String(error);
721
- return {
722
- text: personaIndicator + '❌ **Status Check Failed**\n\n' +
723
- 'Error: ' + errorMessage + '\n\n' +
724
- 'The server may be in an inconsistent state.\n' +
725
- 'Try running `update_server true` to fix issues.'
726
- };
727
- }
728
- }
729
- }
730
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVXBkYXRlTWFuYWdlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy91cGRhdGUvVXBkYXRlTWFuYWdlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQUVILE9BQU8sS0FBSyxJQUFJLE1BQU0sTUFBTSxDQUFDO0FBQzdCLE9BQU8sS0FBSyxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQ2xDLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUMzQyxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDckQsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ25ELE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQzNELE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUNuRCxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUNoRSxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDNUMsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ3RELE9BQU8sRUFBRSxjQUFjLEVBQW1CLE1BQU0sNEJBQTRCLENBQUM7QUFDN0UsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFRaEUsTUFBTSxPQUFPLGFBQWE7SUFDaEIsY0FBYyxDQUFpQjtJQUMvQixhQUFhLENBQWdCO0lBQzdCLGlCQUFpQixDQUFvQjtJQUNyQyxhQUFhLENBQWdCO0lBQzdCLE9BQU8sQ0FBUztJQUV4QixZQUFZLE9BQWdCO1FBQzFCLElBQUksQ0FBQyxPQUFPLEdBQUcsT0FBTyxJQUFJLE9BQU8sQ0FBQyxHQUFHLEVBQUUsQ0FBQztRQUN4QyxJQUFJLENBQUMsY0FBYyxHQUFHLElBQUksY0FBYyxFQUFFLENBQUM7UUFDM0MsSUFBSSxDQUFDLGFBQWEsR0FBRyxJQUFJLGFBQWEsQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLENBQUM7UUFDNUQsSUFBSSxDQUFDLGlCQUFpQixHQUFHLElBQUksaUJBQWlCLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxDQUFDO1FBQ3BFLElBQUksQ0FBQyxhQUFhLEdBQUcsSUFBSSxhQUFhLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQ3ZELENBQUM7SUFFRDs7T0FFRztJQUNILEtBQUssQ0FBQyxlQUFlO1FBQ25CLElBQUksQ0FBQztZQUNILE1BQU0sTUFBTSxHQUFHLE1BQU0sSUFBSSxDQUFDLGFBQWEsQ0FBQyxlQUFlLEVBQUUsQ0FBQztZQUMxRCxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLHVCQUF1QixDQUFDLE1BQU0sQ0FBQyxDQUFDO1lBQ2hFLE9BQU8sRUFBRSxJQUFJLEVBQUUsQ0FBQztRQUNsQixDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNmLE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxhQUFhLENBQUMsdUJBQXVCLENBQUMsSUFBSSxFQUFFLEtBQWMsQ0FBQyxDQUFDO1lBQzlFLE9BQU8sRUFBRSxJQUFJLEVBQUUsQ0FBQztRQUNsQixDQUFDO0lBQ0gsQ0FBQztJQUVEOztPQUVHO0lBQ0gsS0FBSyxDQUFDLFlBQVksQ0FBQyxlQUF3QixJQUFJLEVBQUUsbUJBQTJCLEVBQUU7UUFDNUUsTUFBTSxRQUFRLEdBQXFCLEVBQUUsQ0FBQztRQUV0QyxJQUFJLENBQUM7WUFDSCwyQkFBMkI7WUFDM0IsTUFBTSxnQkFBZ0IsR0FBRyxvQkFBb0IsQ0FBQyxtQkFBbUIsRUFBRSxDQUFDO1lBQ3BFLE1BQU0sQ0FBQyxJQUFJLENBQUMsK0NBQStDLGdCQUFnQixFQUFFLENBQUMsQ0FBQztZQUUvRSx1Q0FBdUM7WUFDdkMsSUFBSSxnQkFBZ0IsS0FBSyxLQUFLLEVBQUUsQ0FBQztnQkFDL0IsT0FBTyxJQUFJLENBQUMscUJBQXFCLENBQUMsWUFBWSxFQUFFLGdCQUFnQixDQUFDLENBQUM7WUFDcEUsQ0FBQztZQUVELHFEQUFxRDtZQUNyRCw2QkFBNkI7WUFDN0IsUUFBUSxDQUFDLElBQUksQ0FBQyxFQUFFLElBQUksRUFBRSxjQUFjLEVBQUUsT0FBTyxFQUFFLGlDQUFpQyxFQUFFLFVBQVUsRUFBRSxLQUFLLEVBQUUsQ0FBQyxDQUFDO1lBQ3ZHLE1BQU0sWUFBWSxHQUFHLE1BQU0sSUFBSSxDQUFDLGlCQUFpQixDQUFDLGlCQUFpQixFQUFFLENBQUM7WUFFdEUsSUFBSSxDQUFDLFlBQVksQ0FBQyxHQUFHLENBQUMsU0FBUyxJQUFJLFlBQVksQ0FBQyxHQUFHLENBQUMsS0FBSyxFQUFFLENBQUM7Z0JBQzFELE9BQU87b0JBQ0wsSUFBSSxFQUFFLGdCQUFnQixHQUFHLHlCQUF5Qjt3QkFDaEQscURBQXFEO3dCQUNyRCxZQUFZLENBQUMsR0FBRyxDQUFDLEtBQUssSUFBSSx1QkFBdUI7aUJBQ3BELENBQUM7WUFDSixDQUFDO1lBRUQsSUFBSSxDQUFDLFlBQVksQ0FBQyxHQUFHLENBQUMsU0FBUyxJQUFJLFlBQVksQ0FBQyxHQUFHLENBQUMsS0FBSyxFQUFFLENBQUM7Z0JBQzFELE9BQU87b0JBQ0wsSUFBSSxFQUFFLGdCQUFnQixHQUFHLHlCQUF5Qjt3QkFDaEQscURBQXFEO3dCQUNyRCxZQUFZLENBQUMsR0FBRyxDQUFDLEtBQUssSUFBSSx1QkFBdUI7aUJBQ3BELENBQUM7WUFDSixDQUFDO1lBRUQsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLFVBQVUsR0FBRyxJQUFJLENBQUM7WUFFOUIscUNBQXFDO1lBQ3JDLElBQUksWUFBWSxFQUFFLENBQUM7Z0JBQ2pCLFFBQVEsQ0FBQyxJQUFJLENBQUMsRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxVQUFVLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztnQkFFcEYsTUFBTSxjQUFjLEdBQUcsTUFBTSxJQUFJLENBQUMsY0FBYyxDQUFDLGlCQUFpQixFQUFFLENBQUM7Z0JBQ3JFLE1BQU0sTUFBTSxHQUFHLE1BQU0sSUFBSSxDQUFDLGFBQWEsQ0FBQyxZQUFZLENBQUMsY0FBYyxDQUFDLENBQUM7Z0JBRXJFLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxVQUFVLEdBQUcsSUFBSSxDQUFDO2dCQUM5QixRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxHQUFHLHNCQUFzQixNQUFNLENBQUMsU0FBUyxFQUFFLENBQUM7WUFDakUsQ0FBQztZQUVELG9CQUFvQjtZQUNwQixRQUFRLENBQUMsSUFBSSxDQUFDLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRSxPQUFPLEVBQUUsNEJBQTRCLEVBQUUsVUFBVSxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUM7WUFDM0YsTUFBTSxRQUFRLENBQUMsS0FBSyxFQUFFLENBQUMsT0FBTyxFQUFFLFFBQVEsQ0FBQyxFQUFFLEVBQUUsR0FBRyxFQUFFLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDO1lBQ2xFLFFBQVEsQ0FBQyxRQUFRLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDLFVBQVUsR0FBRyxJQUFJLENBQUM7WUFFaEQsd0NBQXdDO1lBQ3hDLFFBQVEsQ0FBQyxJQUFJLENBQUMsRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLE9BQU8sRUFBRSxxQ0FBcUMsRUFBRSxVQUFVLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztZQUNwRyxNQUFNLEVBQUUsTUFBTSxFQUFFLFlBQVksRUFBRSxHQUFHLE1BQU0sUUFBUSxDQUFDLEtBQUssRUFBRSxDQUFDLFFBQVEsRUFBRSxhQUFhLENBQUMsRUFBRSxFQUFFLEdBQUcsRUFBRSxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQztZQUV6RyxJQUFJLFlBQVksQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDO2dCQUN4QixPQUFPO29CQUNMLElBQUksRUFBRSxnQkFBZ0IsR0FBRyx5QkFBeUI7d0JBQ2hELGdGQUFnRjt3QkFDaEYsbUJBQW1CLEdBQUcsWUFBWTtpQkFDckMsQ0FBQztZQUNKLENBQUM7WUFDRCxRQUFRLENBQUMsUUFBUSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxVQUFVLEdBQUcsSUFBSSxDQUFDO1lBRWhELG1CQUFtQjtZQUNuQixRQUFRLENBQUMsSUFBSSxDQUFDLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRSxPQUFPLEVBQUUsMkJBQTJCLEVBQUUsVUFBVSxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUM7WUFDekYsTUFBTSxFQUFFLE1BQU0sRUFBRSxVQUFVLEVBQUUsR0FBRyxNQUFNLFFBQVEsQ0FBQyxLQUFLLEVBQUUsQ0FBQyxNQUFNLEVBQUUsUUFBUSxFQUFFLE1BQU0sQ0FBQyxFQUFFLEVBQUUsR0FBRyxFQUFFLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDO1lBQ3hHLFFBQVEsQ0FBQyxRQUFRLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDLFVBQVUsR0FBRyxJQUFJLENBQUM7WUFFaEQsOEJBQThCO1lBQzlCLElBQUksVUFBVSxDQUFDLFFBQVEsQ0FBQyxvQkFBb0IsQ0FBQyxFQUFFLENBQUM7Z0JBQzlDLE9BQU87b0JBQ0wsSUFBSSxFQUFFLGdCQUFnQixHQUFHLDhCQUE4Qjt3QkFDckQsc0VBQXNFO3dCQUN0RSw2Q0FBNkM7aUJBQ2hELENBQUM7WUFDSixDQUFDO1lBRUQsc0JBQXNCO1lBQ3RCLFFBQVEsQ0FBQyxJQUFJLENBQUMsRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFLE9BQU8sRUFBRSw0QkFBNEIsRUFBRSxVQUFVLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztZQUM3RixNQUFNLFFBQVEsQ0FBQyxLQUFLLEVBQUUsQ0FBQyxTQUFTLENBQUMsRUFBRSxFQUFFLEdBQUcsRUFBRSxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQztZQUMxRCxRQUFRLENBQUMsUUFBUSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxVQUFVLEdBQUcsSUFBSSxDQUFDO1lBRWhELGdCQUFnQjtZQUNoQixRQUFRLENBQUMsSUFBSSxDQUFDLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRSxPQUFPLEVBQUUsd0JBQXdCLEVBQUUsVUFBVSxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUM7WUFDdkYsTUFBTSxRQUFRLENBQUMsS0FBSyxFQUFFLENBQUMsS0FBSyxFQUFFLE9BQU8sQ0FBQyxFQUFFLEVBQUUsR0FBRyxFQUFFLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDO1lBQy9ELFFBQVEsQ0FBQyxRQUFRLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDLFVBQVUsR0FBRyxJQUFJLENBQUM7WUFFaEQsOEJBQThCO1lBQzlCLElBQUksWUFBWSxFQUFFLENBQUM7Z0JBQ2pCLFFBQVEsQ0FBQyxJQUFJLENBQUMsRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFLE9BQU8sRUFBRSw0QkFBNEIsRUFBRSxVQUFVLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztnQkFDN0YsTUFBTSxZQUFZLEdBQUcsTUFBTSxJQUFJLENBQUMsYUFBYSxDQUFDLGlCQUFpQixFQUFFLENBQUM7Z0JBQ2xFLFFBQVEsQ0FBQyxRQUFRLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDLFVBQVUsR0FBRyxJQUFJLENBQUM7Z0JBQ2hELFFBQVEsQ0FBQyxRQUFRLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDLE9BQU8sR0FBRyxjQUFjLFlBQVksZ0JBQWdCLENBQUM7WUFDckYsQ0FBQztZQUVELHlCQUF5QjtZQUN6QixNQUFNLFlBQVksR0FBRztnQkFDbkIsZ0JBQWdCLEdBQUcsNEJBQTRCO2dCQUMvQyx1QkFBdUI7YUFDeEIsQ0FBQztZQUVGLFFBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEVBQUU7Z0JBQ25CLFlBQVksQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLENBQUMsT0FBTyxJQUFJLENBQUMsQ0FBQztZQUNsRSxDQUFDLENBQUMsQ0FBQztZQUVILFlBQVksQ0FBQyxJQUFJLENBQ2YscUJBQXFCLEVBQ3JCLDRDQUE0QyxFQUM1QyxvQ0FBb0MsRUFDcEMsNERBQTRELEVBQzVELGtHQUFrRyxDQUNuRyxDQUFDO1lBRUYsT0FBTyxFQUFFLElBQUksRUFBRSxZQUFZLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUM7UUFFekMsQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixNQUFNLFlBQVksR0FBRyxLQUFLLFlBQVksS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUM7WUFFNUUsT0FBTztnQkFDTCxJQUFJLEVBQUUsZ0JBQWdCLEdBQUcseUJBQXlCO29CQUNoRCxTQUFTLEdBQUcsWUFBWSxHQUFHLE1BQU07b0JBQ2pDLGlCQUFpQjtvQkFDakIsUUFBUSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLE1BQU07b0JBQ2pGLHlCQUF5QjtvQkFDekIsa0NBQWtDO29CQUNsQyxvQ0FBb0M7b0JBQ3BDLHdDQUF3QztvQkFDeEMsa0VBQWtFO2FBQ3JFLENBQUM7UUFDSixDQUFDO0lBQ0gsQ0FBQztJQUVEOztPQUVHO0lBQ0gsS0FBSyxDQUFDLGNBQWMsQ0FBQyxRQUFpQixLQUFLLEVBQUUsbUJBQTJCLEVBQUU7UUFDeEUsSUFBSSxDQUFDO1lBQ0gsMEJBQTBCO1lBQzFCLE1BQU0sZ0JBQWdCLEdBQUcsb0JBQW9CLENBQUMsbUJBQW1CLEVBQUUsQ0FBQztZQUVwRSxJQUFJLGdCQUFnQixLQUFLLEtBQUssRUFBRSxDQUFDO2dCQUMvQixPQUFPLElBQUksQ0FBQyx1QkFBdUIsQ0FBQyxLQUFLLEVBQUUsZ0JBQWdCLENBQUMsQ0FBQztZQUMvRCxDQUFDO1lBRUQsNENBQTRDO1lBQzVDLG9CQUFvQjtZQUNwQixNQUFNLFlBQVksR0FBRyxNQUFNLElBQUksQ0FBQyxhQUFhLENBQUMsZUFBZSxFQUFFLENBQUM7WUFFaEUsSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDO2dCQUNsQixPQUFPO29CQUNMLElBQUksRUFBRSxnQkFBZ0IsR0FBRyw0QkFBNEI7d0JBQ25ELGdEQUFnRDt3QkFDaEQsc0VBQXNFO2lCQUN6RSxDQUFDO1lBQ0osQ0FBQztZQUVELDhCQUE4QjtZQUM5QixJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7Z0JBQ1gsSUFBSSxDQUFDO29CQUNILG9EQUFvRDtvQkFDcEQsTUFBTSxJQUFJLENBQUMsY0FBYyxDQUFDLGlCQUFpQixFQUFFLENBQUM7b0JBRTlDLE9BQU87d0JBQ0wsSUFBSSxFQUFFLGdCQUFnQixHQUFHLDJDQUEyQzs0QkFDbEUsZ0RBQWdEOzRCQUNoRCxzQkFBc0IsWUFBWSxDQUFDLFNBQVMsSUFBSTs0QkFDaEQsdUJBQXVCLFlBQVksQ0FBQyxPQUFPLElBQUksU0FBUyxNQUFNOzRCQUM5RCwyREFBMkQ7NEJBQzNELGtFQUFrRTtxQkFDckUsQ0FBQztnQkFDSixDQUFDO2dCQUFDLE1BQU0sQ0FBQztvQkFDUCwwQ0FBMEM7Z0JBQzVDLENBQUM7WUFDSCxDQUFDO1lBRUQsbUJBQW1CO1lBQ25CLE1BQU0sSUFBSSxDQUFDLGFBQWEsQ0FBQyxhQUFhLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxDQUFDO1lBRTFELHlCQUF5QjtZQUN6QixNQUFNLFFBQVEsQ0FBQyxLQUFLLEVBQUUsQ0FBQyxTQUFTLENBQUMsRUFBRSxFQUFFLEdBQUcsRUFBRSxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQztZQUUxRCxVQUFVO1lBQ1YsTUFBTSxRQUFRLENBQUMsS0FBSyxFQUFFLENBQUMsS0FBSyxFQUFFLE9BQU8sQ0FBQyxFQUFFLEVBQUUsR0FBRyxFQUFFLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDO1lBRS9ELE9BQU87Z0JBQ0wsSUFBSSxFQUFFLGdCQUFnQixHQUFHLDhCQUE4QjtvQkFDckQseUJBQXlCLFlBQVksQ0FBQyxTQUFTLElBQUk7b0JBQ25ELG1CQUFtQixZQUFZLENBQUMsT0FBTyxJQUFJLFNBQVMsTUFBTTtvQkFDMUQsMEJBQTBCO29CQUMxQixzQkFBc0I7b0JBQ3RCLHlCQUF5QjtvQkFDekIsOEJBQThCO29CQUM5QiwwQkFBMEI7b0JBQzFCLG1CQUFtQjtvQkFDbkIsNENBQTRDO29CQUM1QyxzREFBc0Q7b0JBQ3RELGtEQUFrRDthQUNyRCxDQUFDO1FBRUosQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixNQUFNLFlBQVksR0FBRyxLQUFLLFlBQVksS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUM7WUFFNUUsT0FBTztnQkFDTCxJQUFJLEVBQUUsZ0JBQWdCLEdBQUcsMkJBQTJCO29CQUNsRCxTQUFTLEdBQUcsWUFBWSxHQUFHLE1BQU07b0JBQ2pDLHdCQUF3QjtvQkFDeEIsNERBQTREO29CQUM1RCx1Q0FBdUM7b0JBQ3ZDLDRDQUE0QztvQkFDNUMsc0NBQXNDO2FBQ3pDLENBQUM7UUFDSixDQUFDO0lBQ0gsQ0FBQztJQUVEOztPQUVHO0lBQ0ssS0FBSyxDQUFDLHFCQUFxQixDQUFDLFlBQXFCLEVBQUUsbUJBQTJCLEVBQUU7UUFDdEYsSUFBSSxDQUFDO1lBQ0gsTUFBTSxDQUFDLElBQUksQ0FBQyw2Q0FBNkMsQ0FBQyxDQUFDO1lBRTNELHlCQUF5QjtZQUN6QixNQUFNLFlBQVksR0FBRyxNQUFNLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1lBQ3RFLElBQUksQ0FBQyxZQUFZLENBQUMsR0FBRyxDQUFDLFNBQVMsSUFBSSxZQUFZLENBQUMsR0FBRyxDQUFDLEtBQUssRUFBRSxDQUFDO2dCQUMxRCxPQUFPO29CQUNMLElBQUksRUFBRSxnQkFBZ0IsR0FBRyx5QkFBeUI7d0JBQ2hELHFEQUFxRDt3QkFDckQsWUFBWSxDQUFDLEdBQUcsQ0FBQyxLQUFLLElBQUksdUJBQXVCO2lCQUNwRCxDQUFDO1lBQ0osQ0FBQztZQUVELHNCQUFzQjtZQUN0QixNQUFNLGNBQWMsR0FBRyxNQUFNLElBQUksQ0FBQyxjQUFjLENBQUMsaUJBQWlCLEVBQUUsQ0FBQztZQUNyRSxNQUFNLENBQUMsSUFBSSxDQUFDLG9DQUFvQyxjQUFjLEVBQUUsQ0FBQyxDQUFDO1lBRWxFLHlDQUF5QztZQUN6QyxNQUFNLENBQUMsSUFBSSxDQUFDLDBEQUEwRCxDQUFDLENBQUM7WUFFeEUscUVBQXFFO1lBQ3JFLE1BQU0sV0FBVyxHQUFHLDBCQUEwQixDQUFDO1lBQy9DLElBQUksQ0FBQywyQkFBMkIsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQztnQkFDbkQsTUFBTSxJQUFJLEtBQUssQ0FBQyw2QkFBNkIsQ0FBQyxDQUFDO1lBQ2pELENBQUM7WUFFRCxNQUFNLEVBQUUsTUFBTSxFQUFFLGFBQWEsRUFBRSxHQUFHLE1BQU0sUUFBUSxDQUFDLEtBQUssRUFBRSxDQUFDLE1BQU0sRUFBRSxXQUFXLEVBQUUsU0FBUyxDQUFDLEVBQUU7Z0JBQ3hGLEdBQUcsRUFBRSxJQUFJLENBQUMsT0FBTztnQkFDakIsT0FBTyxFQUFFLEtBQUs7YUFDZixDQUFDLENBQUM7WUFFSCxNQUFNLGFBQWEsR0FBRyxhQUFhLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDM0MsTUFBTSxDQUFDLElBQUksQ0FBQyx1Q0FBdUMsYUFBYSxFQUFFLENBQUMsQ0FBQztZQUVwRSxtQkFBbUI7WUFDbkIsTUFBTSxVQUFVLEdBQUcsZUFBZSxDQUFDLGNBQWMsRUFBRSxhQUFhLENBQUMsQ0FBQztZQUVsRSxJQUFJLFVBQVUsSUFBSSxDQUFDLEVBQUUsQ0FBQztnQkFDcEIsT0FBTztvQkFDTCxJQUFJLEVBQUUsZ0JBQWdCLEdBQUcsK0JBQStCO3dCQUN0RCxvQkFBb0IsY0FBYyxJQUFJO3dCQUN0QyxtQkFBbUIsYUFBYSxNQUFNO3dCQUN0QyxtQkFBbUI7aUJBQ3RCLENBQUM7WUFDSixDQUFDO1lBRUQsb0JBQW9CO1lBQ3BCLE1BQU0sTUFBTSxHQUFHLG1CQUFtQixDQUFDLFdBQVcsRUFBRSxDQUFDO1lBRWpELG9CQUFvQjtZQUNwQixJQUFJLGVBQWUsR0FBRyxnQkFBZ0IsR0FBRyxtQ0FBbUMsQ0FBQztZQUM3RSxlQUFlLElBQUksY0FBYyxDQUFDO1lBQ2xDLGVBQWUsSUFBSSw0QkFBNEIsQ0FBQztZQUNoRCxlQUFlLElBQUksd0JBQXdCLENBQUM7WUFFNUMsd0RBQXdEO1lBQ3hELE1BQU0sQ0FBQyxJQUFJLENBQUMsbURBQW1ELENBQUMsQ0FBQztZQUNqRSxJQUFJLENBQUM7Z0JBQ0gscUVBQXFFO2dCQUNyRSxNQUFNLGFBQWEsR0FBRyxvQkFBb0IsQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO2dCQUM5RCxJQUFJLENBQUMsYUFBYSxFQUFFLENBQUM7b0JBQ25CLE1BQU0sSUFBSSxLQUFLLENBQUMsa0RBQWtELENBQUMsQ0FBQztnQkFDdEUsQ0FBQztnQkFFRCwyQ0FBMkM7Z0JBQzNDLE1BQU0sVUFBVSxHQUFHLE1BQU0sSUFBSSxDQUFDLGFBQWEsQ0FBQyxlQUFlLENBQUMsYUFBYSxFQUFFLGNBQWMsQ0FBQyxDQUFDO2dCQUMzRixNQUFNLENBQUMsSUFBSSxDQUFDLHNDQUFzQyxVQUFVLEVBQUUsQ0FBQyxDQUFDO2dCQUVoRSxlQUFlLEdBQUcsZUFBZSxDQUFDLE9BQU8sQ0FBQyxzQkFBc0IsRUFBRSxrQkFBa0IsQ0FBQyxDQUFDO2dCQUN0RixlQUFlLElBQUksMENBQTBDLENBQUM7WUFFaEUsQ0FBQztZQUFDLE9BQU8sV0FBVyxFQUFFLENBQUM7Z0JBQ3JCLE1BQU0sQ0FBQyxLQUFLLENBQUMsZ0NBQWdDLEVBQUUsV0FBVyxDQUFDLENBQUM7Z0JBQzVELE9BQU87b0JBQ0wsSUFBSSxFQUFFLGdCQUFnQixHQUFHLHlCQUF5Qjt3QkFDaEQsMENBQTBDO3dCQUMxQyxTQUFTLEdBQUcsQ0FBQyxXQUFXLFlBQVksS0FBSyxDQUFDLENBQUMsQ0FBQyxXQUFXLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDLENBQUMsR0FBRyxNQUFNO3dCQUMvRixnRkFBZ0Y7d0JBQ2hGLDBDQUEwQztpQkFDN0MsQ0FBQztZQUNKLENBQUM7WUFFRCxtQ0FBbUM7WUFDbkMsTUFBTSxDQUFDLElBQUksQ0FBQyxnRUFBZ0UsQ0FBQyxDQUFDO1lBQzlFLGVBQWUsSUFBSSxtQkFBbUIsQ0FBQztZQUN2QyxlQUFlLElBQUksT0FBTyxDQUFDO1lBQzNCLGVBQWUsSUFBSSxtREFBbUQsQ0FBQztZQUN2RSxlQUFlLElBQUksa0NBQWtDLENBQUM7WUFDdEQsZUFBZSxJQUFJLE9BQU8sQ0FBQztZQUUzQixNQUFNLFlBQVksR0FBRyxNQUFNLFFBQVEsQ0FBQyxLQUFLLEVBQUUsQ0FBQyxRQUFRLEVBQUUsSUFBSSxFQUFFLDBCQUEwQixDQUFDLEVBQUU7Z0JBQ3ZGLEdBQUcsRUFBRSxJQUFJLENBQUMsT0FBTztnQkFDakIsT0FBTyxFQUFFLE1BQU0sQ0FBQyxtQkFBbUIsRUFBRTthQUN0QyxDQUFDLENBQUM7WUFFSCxNQUFNLENBQUMsSUFBSSxDQUFDLHNDQUFzQyxFQUFFLFlBQVksQ0FBQyxDQUFDO1lBRWxFLDBCQUEwQjtZQUMxQixNQUFNLEVBQUUsTUFBTSxFQUFFLFlBQVksRUFBRSxHQUFHLE1BQU0sUUFBUSxDQUFDLEtBQUssRUFBRSxDQUFDLE1BQU0sRUFBRSxJQUFJLEVBQUUsMEJBQTBCLEVBQUUsV0FBVyxDQUFDLEVBQUU7Z0JBQzlHLEdBQUcsRUFBRSxJQUFJLENBQUMsT0FBTztnQkFDakIsT0FBTyxFQUFFLEtBQUs7YUFDZixDQUFDLENBQUM7WUFFSCxNQUFNLFlBQVksR0FBRyxZQUFZLENBQUMsS0FBSyxDQUFDLDJDQUEyQyxDQUFDLENBQUM7WUFDckYsTUFBTSxnQkFBZ0IsR0FBRyxZQUFZLENBQUMsQ0FBQyxDQUFDLFlBQVksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDO1lBRXBFLElBQUksZ0JBQWdCLEtBQUssYUFBYSxFQUFFLENBQUM7Z0JBQ3ZDLE1BQU0sQ0FBQyxJQUFJLENBQUMsNERBQTRELGFBQWEsVUFBVSxnQkFBZ0IsRUFBRSxDQUFDLENBQUM7WUFDckgsQ0FBQztZQUVELE9BQU87Z0JBQ0wsSUFBSSxFQUFFLGdCQUFnQixHQUFHLDRCQUE0QjtvQkFDbkQsaUJBQWlCLGNBQWMsUUFBUSxhQUFhLE1BQU07b0JBQzFELHlCQUF5QjtvQkFDekIsaUNBQWlDO29CQUNqQyx3QkFBd0I7b0JBQ3hCLG1CQUFtQjtvQkFDbkIsNENBQTRDO29CQUM1QywwREFBMEQ7b0JBQzFELHNEQUFzRDtvQkFDdEQsa0dBQWtHO2FBQ3JHLENBQUM7UUFFSixDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNmLE1BQU0sQ0FBQyxLQUFLLENBQUMsb0NBQW9DLEVBQUUsS0FBSyxDQUFDLENBQUM7WUFDMUQsTUFBTSxZQUFZLEdBQUcsS0FBSyxZQUFZLEtBQUssQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBRTVFLE9BQU87Z0JBQ0wsSUFBSSxFQUFFLGdCQUFnQixHQUFHLHlCQUF5QjtvQkFDaEQsU0FBUyxHQUFHLFlBQVksR0FBRyxNQUFNO29CQUNqQyx3QkFBd0I7b0JBQ3hCLCtEQUErRDtvQkFDL0QsOENBQThDO29CQUM5QyxxQ0FBcUM7b0JBQ3JDLDBDQUEwQztvQkFDMUMsc0JBQXNCO29CQUN0QixPQUFPO29CQUNQLDBDQUEwQztvQkFDMUMsS0FBSzthQUNSLENBQUM7UUFDSixDQUFDO0lBQ0gsQ0FBQztJQUVEOztPQUVHO0lBQ0ssS0FBSyxDQUFDLHVCQUF1QixDQUFDLEtBQWMsRUFBRSxtQkFBMkIsRUFBRTtRQUNqRixJQUFJLENBQUM7WUFDSCxNQUFNLENBQUMsSUFBSSxDQUFDLCtDQUErQyxDQUFDLENBQUM7WUFFN0QsNkNBQTZDO1lBQzdDLE1BQU0sTUFBTSxHQUFHLG1CQUFtQixDQUFDLFdBQVcsRUFBRSxDQUFDO1lBQ2pELE1BQU0sYUFBYSxHQUFHLE1BQU0sQ0FBQyxlQUFlLEVBQUUsQ0FBQztZQUMvQyxNQUFNLFlBQVksR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLGFBQWEsRUFBRSxlQUFlLENBQUMsQ0FBQztZQUUvRCxJQUFJLFFBQVEsQ0FBQztZQUNiLElBQUksQ0FBQztnQkFDSCxNQUFNLE9BQU8sR0FBRyxNQUFNLEVBQUUsQ0FBQyxRQUFRLENBQUMsWUFBWSxFQUFFLE9BQU8sQ0FBQyxDQUFDO2dCQUN6RCxRQUFRLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUNqQyxDQUFDO1lBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztnQkFDZixPQUFPO29CQUNMLElBQUksRUFBRSxnQkFBZ0IsR0FBRyxnQ0FBZ0M7d0JBQ3ZELG9EQUFvRDt3QkFDcEQsNkZBQTZGO2lCQUNoRyxDQUFDO1lBQ0osQ0FBQztZQUVELElBQUksQ0FBQyxRQUFRLENBQUMsT0FBTyxJQUFJLFFBQVEsQ0FBQyxPQUFPLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO2dCQUN2RCxPQUFPO29CQUNMLElBQUksRUFBRSxnQkFBZ0IsR0FBRyxnQ0FBZ0M7d0JBQ3ZELG1DQUFtQzt3QkFDbkMsc0VBQXNFO2lCQUN6RSxDQUFDO1lBQ0osQ0FBQztZQUVELG9CQUFvQjtZQUNwQixNQUFNLFlBQVksR0FBRyxRQUFRLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBRXpDLDhCQUE4QjtZQUM5QixJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7Z0JBQ1gsSUFBSSxDQUFDO29CQUNILGdDQUFnQztvQkFDaEMsTUFBTSxJQUFJLENBQUMsY0FBYyxDQUFDLGlCQUFpQixFQUFFLENBQUM7b0JBRTlDLE9BQU87d0JBQ0wsSUFBSSxFQUFFLGdCQUFnQixHQUFHLDJDQUEyQzs0QkFDbEUsZ0RBQWdEOzRCQUNoRCxzQkFBc0IsWUFBWSxDQUFDLFNBQVMsSUFBSTs0QkFDaEQsdUJBQXVCLFlBQVksQ0FBQyxPQUFPLElBQUksU0FBUyxNQUFNOzRCQUM5RCwyREFBMkQ7NEJBQzNELHdFQUF3RTtxQkFDM0UsQ0FBQztnQkFDSixDQUFDO2dCQUFDLE1BQU0sQ0FBQztvQkFDUCwwQ0FBMEM7Z0JBQzVDLENBQUM7WUFDSCxDQUFDO1lBRUQsc0JBQXNCO1lBQ3RCLE1BQU0sYUFBYSxHQUFHLG9CQUFvQixDQUFDLGdCQUFnQixFQUFFLENBQUM7WUFDOUQsSUFBSSxDQUFDLGFBQWEsRUFBRSxDQUFDO2dCQUNuQixPQUFPO29CQUNMLElBQUksRUFBRSxnQkFBZ0IsR0FBRywyQkFBMkI7d0JBQ2xELHVEQUF1RDt3QkFDdkQsOEJBQThCO3dCQUM5QixPQUFPO3dCQUNQLDBDQUEwQyxHQUFHLENBQUMsWUFBWSxDQUFDLE9BQU8sSUFBSSxRQUFRLENBQUMsR0FBRyxJQUFJO3dCQUN0RixLQUFLO2lCQUNSLENBQUM7WUFDSixDQUFDO1lBRUQsTUFBTSxDQUFDLElBQUksQ0FBQyw4Q0FBOEMsWUFBWSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7WUFFL0UsK0NBQStDO1lBQy9DLE1BQU0saUJBQWlCLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxFQUFFLFNBQVMsQ0FBQyxDQUFDO1lBQ2xFLElBQUksQ0FBQztnQkFDSCxNQUFNLEVBQUUsQ0FBQyxNQUFNLENBQUMsaUJBQWlCLENBQUMsQ0FBQztnQkFDbkMsTUFBTSxlQUFlLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxpQkFBaUIsRUFBRSxjQUFjLENBQUMsQ0FBQztnQkFDckUsTUFBTSxFQUFFLENBQUMsTUFBTSxDQUFDLGVBQWUsQ0FBQyxDQUFDO1lBQ25DLENBQUM7WUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO2dCQUNmLE9BQU87b0JBQ0wsSUFBSSxFQUFFLGdCQUFnQixHQUFHLG9DQUFvQzt3QkFDM0QsdURBQXVEO3dCQUN2RCxnQkFBZ0I7d0JBQ2hCLGdCQUFnQixZQUFZLENBQUMsSUFBSSxJQUFJO3dCQUNyQyxVQUFVLEtBQUssWUFBWSxLQUFLLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsTUFBTTt3QkFDdEUsd0JBQXdCO3dCQUN4Qiw2Q0FBNkM7d0JBQzdDLFdBQVc7d0JBQ1gsMENBQTBDLEdBQUcsQ0FBQyxZQUFZLENBQUMsT0FBTyxJQUFJLE9BQU8sQ0FBQyxHQUFHLElBQUk7d0JBQ3JGLEtBQUs7aUJBQ1IsQ0FBQztZQUNKLENBQUM7WUFFRCx3Q0FBd0M7WUFDeEMsTUFBTSxRQUFRLEdBQUcsR0FBRyxhQUFhLFFBQVEsSUFBSSxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUM7WUFDdEQsTUFBTSxVQUFVLEdBQUcsR0FBRyxhQUFhLFdBQVcsSUFBSSxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUM7WUFDM0QsTUFBTSxXQUFXLEdBQUcsY0FBYyxDQUFDLGlCQUFpQixFQUFFLENBQUM7WUFFdkQsSUFBSSxDQUFDO2dCQUNILDRDQUE0QztnQkFDNUMsTUFBTSxXQUFXLENBQUMsT0FBTyxDQUFDLGlCQUFpQixFQUFFLFFBQVEsQ0FBQyxDQUFDO2dCQUV2RCx1REFBdUQ7Z0JBQ3ZELE1BQU0sV0FBVyxDQUFDLE9BQU8sQ0FBQyxhQUFhLEVBQUUsVUFBVSxDQUFDLENBQUM7Z0JBRXJELCtDQUErQztnQkFDL0MsTUFBTSxXQUFXLENBQUMsT0FBTyxDQUFDLFFBQVEsRUFBRSxhQUFhLENBQUMsQ0FBQztnQkFFbkQsb0RBQW9EO2dCQUNwRCxXQUFXLENBQUMsTUFBTSxFQUFFLENBQUM7Z0JBRXJCLHdEQUF3RDtnQkFDeEQsTUFBTSxFQUFFLENBQUMsRUFBRSxDQUFDLFVBQVUsRUFBRSxFQUFFLFNBQVMsRUFBRSxJQUFJLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUMsS0FBSyxDQUFDLEdBQUcsRUFBRTtvQkFDbkUsTUFBTSxDQUFDLElBQUksQ0FBQyxnREFBZ0QsVUFBVSxFQUFFLENBQUMsQ0FBQztnQkFDNUUsQ0FBQyxDQUFDLENBQUM7WUFDTCxDQUFDO1lBQUMsT0FBTyxhQUFhLEVBQUUsQ0FBQztnQkFDdkIsTUFBTSxDQUFDLEtBQUssQ0FBQyxpRUFBaUUsRUFBRSxhQUFhLENBQUMsQ0FBQztnQkFFL0YsMEJBQTBCO2dCQUMxQixJQUFJLFdBQVcsQ0FBQyxhQUFhLEVBQUUsRUFBRSxDQUFDO29CQUNoQyxNQUFNLFdBQVcsQ0FBQyxRQUFRLEVBQUUsQ0FBQztnQkFDL0IsQ0FBQztnQkFFRCw4QkFBOEI7Z0JBQzlCLElBQUksQ0FBQztvQkFDSCw2Q0FBNkM7b0JBQzdDLE1BQU0sRUFBRSxDQUFDLE1BQU0sQ0FBQyxhQUFhLENBQUMsQ0FBQztvQkFDL0IsTUFBTSxDQUFDLElBQUksQ0FBQyxnRUFBZ0UsQ0FBQyxDQUFDO2dCQUNoRixDQUFDO2dCQUFDLE1BQU0sQ0FBQztvQkFDUCxxREFBcUQ7b0JBQ3JELElBQUksQ0FBQzt3QkFDSCxNQUFNLEVBQUUsQ0FBQyxNQUFNLENBQUMsVUFBVSxFQUFFLGFBQWEsQ0FBQyxDQUFDO3dCQUMzQyxNQUFNLENBQUMsSUFBSSxDQUFDLDJDQUEyQyxDQUFDLENBQUM7b0JBQzNELENBQUM7b0JBQUMsTUFBTSxDQUFDO3dCQUNQLE1BQU0sQ0FBQyxLQUFLLENBQUMsMEVBQTBFLENBQUMsQ0FBQztvQkFDM0YsQ0FBQztnQkFDSCxDQUFDO2dCQUVELE1BQU0sYUFBYSxDQUFDO1lBQ3RCLENBQUM7WUFFRCxPQUFPO2dCQUNMLElBQUksRUFBRSxnQkFBZ0IsR0FBRyxrQ0FBa0M7b0JBQ3pELHlCQUF5QixZQUFZLENBQUMsU0FBUyxJQUFJO29CQUNuRCxtQkFBbUIsWUFBWSxDQUFDLE9BQU8sSUFBSSxTQUFTLE1BQU07b0JBQzFELDBCQUEwQjtvQkFDMUIsdUJBQXVCO29CQUN2Qix3QkFBd0I7b0JBQ3hCLG1CQUFtQjtvQkFDbkIsNENBQTRDO29CQUM1QyxzREFBc0Q7b0JBQ3RELGtEQUFrRDthQUNyRCxDQUFDO1FBRUosQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixNQUFNLENBQUMsS0FBSyxDQUFDLHNDQUFzQyxFQUFFLEtBQUssQ0FBQyxDQUFDO1lBQzVELE1BQU0sWUFBWSxHQUFHLEtBQUssWUFBWSxLQUFLLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUU1RSxPQUFPO2dCQUNMLElBQUksRUFBRSxnQkFBZ0IsR0FBRywrQkFBK0I7b0JBQ3RELFNBQVMsR0FBRyxZQUFZLEdBQUcsTUFBTTtvQkFDakMsd0JBQXdCO29CQUN4Qiw2REFBNkQ7b0JBQzdELG9DQUFvQztvQkFDcEMsVUFBVTtvQkFDVixvREFBb0Q7b0JBQ3BELFVBQVU7b0JBQ1Ysc0NBQXNDO2FBQ3pDLENBQUM7UUFDSixDQUFDO0lBQ0gsQ0FBQztJQUVEOzs7T0FHRztJQUNLLEtBQUssQ0FBQyxhQUFhLENBQUMsR0FBVyxFQUFFLElBQVk7UUFDbkQsTUFBTSxjQUFjLENBQUMsYUFBYSxDQUFDLEdBQUcsRUFBRSxJQUFJLEVBQUU7WUFDNUMsZUFBZSxFQUFFLENBQUMsTUFBTSxFQUFFLGNBQWMsQ0FBQztZQUN6QyxVQUFVLEVBQUUsQ0FBQyxNQUFNLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxFQUFFO2dCQUNsQyxNQUFNLENBQUMsS0FBSyxDQUFDLGtDQUFrQyxNQUFNLElBQUksS0FBSyxNQUFNLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1lBQzdGLENBQUM7U0FDRixDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxLQUFLLENBQUMsd0JBQXdCLENBQUMsU0FBa0IsRUFBRSxVQUFtQixLQUFLLEVBQUUsbUJBQTJCLEVBQUU7UUFDeEcsSUFBSSxDQUFDO1lBQ0gsTUFBTSxnQkFBZ0IsR0FBRyxvQkFBb0IsQ0FBQyxtQkFBbUIsRUFBRSxDQUFDO1lBRXBFLElBQUksZ0JBQWdCLEtBQUssS0FBSyxFQUFFLENBQUM7Z0JBQy9CLE9BQU87b0JBQ0wsSUFBSSxFQUFFLGdCQUFnQixHQUFHLHVDQUF1Qzt3QkFDOUQsMkRBQTJEO3dCQUMzRCx1QkFBdUI7aUJBQzFCLENBQUM7WUFDSixDQUFDO1lBRUQsSUFBSSxnQkFBZ0IsS0FBSyxTQUFTLEVBQUUsQ0FBQztnQkFDbkMsT0FBTztvQkFDTCxJQUFJLEVBQUUsZ0JBQWdCLEdBQUcscUNBQXFDO3dCQUM1RCxtREFBbUQ7d0JBQ25ELDBDQUEwQztpQkFDN0MsQ0FBQztZQUNKLENBQUM7WUFFRCwyQkFBMkI7WUFDM0IsTUFBTSxnQkFBZ0IsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsSUFBSSxJQUFJLEVBQUUsRUFBRSxZQUFZLEVBQUUsZ0JBQWdCLENBQUMsQ0FBQztZQUMzRixNQUFNLFlBQVksR0FBRyxTQUFTLElBQUksZ0JBQWdCLENBQUM7WUFFbkQsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO2dCQUNiLE9BQU87b0JBQ0wsSUFBSSxFQUFFLGdCQUFnQixHQUFHLHdDQUF3Qzt3QkFDL0Qsa0JBQWtCO3dCQUNsQiw2QkFBNkIsWUFBWSxJQUFJO3dCQUM3Qyx1Q0FBdUM7d0JBQ3ZDLGdDQUFnQzt3QkFDaEMsNkNBQTZDO3dCQUM3QyxxQ0FBcUM7d0JBQ3JDLCtCQUErQjt3QkFDL0Isb0NBQW9DO3dCQUNwQyxtQ0FBbUM7d0JBQ25DLDhCQUE4Qjt3QkFDOUIsbUJBQW1CO3dCQUNuQix3Q0FBd0M7d0JBQ3hDLGdDQUFnQzt3QkFDaEMsbURBQW1EO2lCQUN0RCxDQUFDO1lBQ0osQ0FBQztZQUVELE1BQU0sQ0FBQyxJQUFJLENBQUMsK0RBQStELFlBQVksRUFBRSxDQUFDLENBQUM7WUFFM0YsMkNBQTJDO1lBQzNDLElBQUksQ0FBQztnQkFDSCxNQUFNLEVBQUUsQ0FBQyxNQUFNLENBQUMsWUFBWSxDQUFDLENBQUM7Z0JBQzlCLE9BQU87b0JBQ0wsSUFBSSxFQUFFLGdCQUFnQixHQUFHLG1DQUFtQzt3QkFDMUQsaUJBQWlCLFlBQVksc0JBQXNCO3dCQUNuRCxnQkFBZ0I7d0JBQ2hCLDBDQUEwQzt3QkFDMUMsMENBQTBDO3dCQUMxQyxzQ0FBc0M7aUJBQ3pDLENBQUM7WUFDSixDQUFDO1lBQUMsTUFBTSxDQUFDO2dCQUNQLDJDQUEyQztZQUM3QyxDQUFDO1lBRUQsMkJBQTJCO1lBQzNCLElBQUksYUFBYSxHQUFHLGdCQUFnQixHQUFHLHNDQUFzQyxDQUFDO1lBQzlFLGFBQWEsSUFBSSxjQUFjLENBQUM7WUFDaEMsYUFBYSxJQUFJLDJCQUEyQixDQUFDO1lBQzdDLGFBQWEsSUFBSSxnQ0FBZ0MsQ0FBQztZQUNsRCxhQUFhLElBQUksNEJBQTRCLENBQUM7WUFDOUMsYUFBYSxJQUFJLG1DQUFtQyxDQUFDO1lBQ3JELGFBQWEsSUFBSSx3Q0FBd0MsQ0FBQztZQUMxRCxhQUFhLElBQUksT0FBTyxDQUFDO1lBQ3pCLGFBQWEsSUFBSSxXQUFXLFlBQVksSUFBSSxDQUFDO1lBQzdDLGFBQWEsSUFBSSwrREFBK0QsQ0FBQztZQUNqRixhQUFhLElBQUksT0FBTyxDQUFDO1lBRXpCLG9CQUFvQjtZQUNwQixNQUFNLE1BQU0sR0FBRyxtQkFBbUIsQ0FBQyxXQUFXLEVBQUUsQ0FBQztZQUVqRCwrQkFBK0I7WUFDL0IsTUFBTSxDQUFDLElBQUksQ0FBQyx1Q0FBdUMsQ0FBQyxDQUFDO1lBRXJELG1FQUFtRTtZQUNuRSxnRUFBZ0U7WUFDaEUsdUVBQXVFO1lBQ3ZFLElBQUksWUFBWSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO2dCQUNsQyxNQUFNLElBQUksS0FBSyxDQUFDLHlEQUF5RCxDQUFDLENBQUM7WUFDN0UsQ0FBQztZQUVELE1BQU0sUUFBUSxDQUFDLEtBQUssRUFBRSxDQUFDLE9BQU8sRUFBRSxnREFBZ0QsRUFBRSxZQUFZLENBQUMsRUFBRTtnQkFDL0YsT0FBTyxFQUFFLE1BQU0sQ0FBQyxrQkFBa0IsRUFBRTthQUNyQyxDQUFDLENBQUM7WUFFSCxhQUFhLEdBQUcsYUFBYSxDQUFDLE9BQU8sQ0FBQyx5QkFBeUIsRUFBRSxxQkFBcUIsQ0FBQyxDQUFDO1lBQ3hGLGFBQWEsR0FBRyxhQUFhLENBQUMsT0FBTyxDQUFDLHNDQUFzQyxFQUFFLDJDQUEyQyxDQUFDLENBQUM7WUFFM0gsK0JBQStCO1lBQy9CLE1BQU0sQ0FBQyxJQUFJLENBQUMsNENBQTRDLENBQUMsQ0FBQztZQUMxRCxNQUFNLFFBQVEsQ0FBQyxLQUFLLEVBQUUsQ0FBQyxTQUFTLENBQUMsRUFBRTtnQkFDakMsR0FBRyxFQUFFLFlBQVk7Z0JBQ2pCLE9BQU8sRUFBRSxNQUFNLENBQUMsb0JBQW9CLEVBQUU7YUFDdkMsQ0FBQyxDQUFDO1lBRUgsYUFBYSxHQUFHLGFBQWEsQ0FBQyxPQUFPLENBQUMsOEJBQThCLEVBQUUsMEJBQTBCLENBQUMsQ0FBQztZQUNsRyxhQUFhLEdBQUcsYUFBYSxDQUFDLE9BQU8sQ0FBQywyQ0FBMkMsRUFBRSx1Q0FBdUMsQ0FBQyxDQUFDO1lBRTVILDJCQUEyQjtZQUMzQixNQUFNLENBQUMsSUFBSSxDQUFDLHdDQUF3QyxDQUFDLENBQUM7WUFDdEQsTUFBTSxRQUFRLENBQUMsS0FBSyxFQUFFLENBQUMsS0FBSyxFQUFFLE9BQU8sQ0FBQyxFQUFFO2dCQUN0QyxHQUFHLEVBQUUsWUFBWTtnQkFDakIsT0FBTyxFQUFFLE1BQU0sQ0FBQyxlQUFlLEVBQUU7YUFDbEMsQ0FBQyxDQUFDO1lBRUgsYUFBYSxHQUFHLGFBQWEsQ0FBQyxPQUFPLENBQUMsMEJBQTBCLEVBQUUsb0JBQW9CLENBQUMsQ0FBQztZQUN4RixhQUFhLEdBQUcsYUFBYSxDQUFDLE9BQU8sQ0FBQyx1Q0FBdUMsRUFBRSxpQ0FBaUMsQ0FBQyxDQUFDO1lBRWxILHlCQUF5QjtZQUN6QixNQUFNLGVBQWUsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsSUFBSSxJQUFJLEVBQUUsRUFBRSxZQUFZLEVBQUUsV0FBVyxDQUFDLENBQUM7WUFDckYsTUFBTSxlQUFlLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLElBQUksSUFBSSxFQUFFLEVBQUUsWUFBWSxFQUFFLFdBQVcsQ0FBQyxDQUFDO1lBRXJGLE1BQU0sQ0FBQyxJQUFJLENBQUMsNENBQTRDLEdBQUcsZUFBZSxDQUFDLENBQUM7WUFFNUUseUNBQXlDO1lBQ3pDLE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsWUFBWSxFQUFFLE1BQU0sRUFBRSxVQUFVLENBQUMsQ0FBQztZQUMvRCxNQUFNLFlBQVksR0FBRztnQkFDbkIsVUFBVSxFQUFFO29CQUNWLFlBQVksRUFBRTt3QkFDWixPQUFPLEVBQUUsTUFBTTt3QkFDZixJQUFJLEVBQUUsQ0FBQyxVQUFVLENBQUM7cUJBQ25CO2lCQUNGO2FBQ0YsQ0FBQztZQUVGLE9BQU87Z0JBQ0wsSUFBSSxFQUFFLGdCQUFnQixHQUFHLHNDQUFzQztvQkFDN0QsOEJBQThCLFlBQVksTUFBTTtvQkFDaEQscUJBQXFCO29CQUNyQiwrQ0FBK0M7b0JBQy9DLGNBQWM7b0JBQ2QsSUFBSSxDQUFDLFNBQVMsQ0FBQyxZQUFZLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQyxHQUFHLElBQUk7b0JBQzVDLFlBQVk7b0JBQ1osbUNBQW1DO29CQUNuQywrQkFBK0I7b0JBQy9CLDBEQUEwRDtvQkFDMUQsa0NBQWtDO29CQUNsQyxNQUFNLGVBQWUsTUFBTTtvQkFDM0IsZ0NBQWdDO29CQUNoQyxjQUFjO29CQUNkLFNBQVMsWUFBWSxJQUFJO29CQUN6QixlQUFlO29CQUNmLGtCQUFrQjtvQkFDbEIsb0JBQW9CO29CQUNwQixZQUFZO29CQUNaLGdFQUFnRTthQUNuRSxDQUFDO1FBRUosQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixNQUFNLENBQUMsS0FBSyxDQUFDLHdDQUF3QyxFQUFFLEtBQUssQ0FBQyxDQUFDO1lBQzlELE1BQU0sWUFBWSxHQUFHLEtBQUssWUFBWSxLQUFLLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUU1RSxPQUFPO2dCQUNMLElBQUksRUFBRSxnQkFBZ0IsR0FBRyw2QkFBNkI7b0JBQ3BELFNBQVMsR0FBRyxZQUFZLEdBQUcsTUFBTTtvQkFDakMsd0JBQXdCO29CQUN4Qiw4QkFBOEI7b0JBQzlCLGdDQUFnQztvQkFDaEMsd0NBQXdDO29CQUN4QyxxQ0FBcUM7YUFDeEMsQ0FBQztRQUNKLENBQUM7SUFDSCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxLQUFLLENBQUMsZUFBZSxDQUFDLG1CQUEyQixFQUFFO1FBQ2pELElBQUksQ0FBQztZQUNILE1BQU0sY0FBYyxHQUFHLE1BQU0sSUFBSSxDQUFDLGNBQWMsQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1lBQ3JFLE1BQU0sWUFBWSxHQUFHLE1BQU0sSUFBSSxDQUFDLGlCQUFpQixDQUFDLGlCQUFpQixFQUFFLENBQUM7WUFDdEUsTUFBTSxPQUFPLEdBQUcsTUFBTSxJQUFJLENBQUMsYUFBYSxDQUFDLFdBQVcsRUFBRSxDQUFDO1lBQ3ZELE1BQU0sZUFBZSxHQUFHLElBQUksQ0FBQyxhQUFhLENBQUMsa0JBQWtCLEVBQUUsQ0FBQztZQUVoRSx3QkFBd0I7WUFDeEIsTUFBTSxnQkFBZ0IsR0FBRyxvQkFBb0IsQ0FBQyxtQkFBbUIsRUFBRSxDQUFDO1lBQ3BFLE1BQU0sZ0JBQWdCLEdBQUcsb0JBQW9CLENBQUMsMEJBQTBCLEVBQUUsQ0FBQztZQUUzRSw4Q0FBOEM7WUFDOUMsSUFBSSxTQUFTLEdBQUcsS0FBSyxDQUFDO1lBQ3RCLElBQUksU0FBUyxHQUFHLEtBQUssQ0FBQztZQUN0QixJQUFJLFVBQVUsR0FBRyxLQUFLLENBQUM7WUFFdkIsSUFBSSxnQkFBZ0IsS0FBSyxLQUFLLEVBQUUsQ0FBQztnQkFDL0IsSUFBSSxDQUFDO29CQUNILE1BQU0sRUFBRSxNQUFNLEVBQUUsWUFBWSxFQUFFLEdBQUcsTUFBTSxRQUFRLENBQUMsS0FBSyxFQUFFLENBQUMsUUFBUSxFQUFFLGdCQUFnQixDQUFDLEVBQUUsRUFBRSxHQUFHLEVBQUUsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUM7b0JBQzVHLFNBQVMsR0FBRyxZQUFZLENBQUMsSUFBSSxFQUFFLElBQUksVUFBVSxDQUFDO29CQUU5QyxNQUFNLEVBQUUsTUFBTSxFQUFFLFlBQVksRUFBRSxHQUFHLE1BQU0sUUFBUSxDQUFDLEtBQUssRUFBRSxDQUFDLFFBQVEsRUFBRSxhQUFhLENBQUMsRUFBRSxFQUFFLEdBQUcsRUFBRSxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQztvQkFDekcsU0FBUyxHQUFHLFlBQVksQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUM7b0JBRXZELE1BQU0sRUFBRSxNQUFNLEVBQUUsU0FBUyxFQUFFLEdBQUcsTUFBTSxRQUFRLENBQUMsS0FBSyxFQUFFLENBQUMsS0FBSyxFQUFFLElBQUksRUFBRSxXQUFXLENBQUMsRUFBRSxFQUFFLEdBQUcsRUFBRSxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQztvQkFDdkcsVUFBVSxHQUFHLFNBQVMsQ0FBQyxJQUFJLEVBQUUsQ0FBQztnQkFDaEMsQ0FBQztnQkFBQyxNQUFNLENBQUM7b0JBQ1Asb0NBQW9DO2dCQUN0QyxDQUFDO1lBQ0gsQ0FBQztZQUVELE1BQU0sV0FBVyxHQUFHO2dCQUNsQixnQkFBZ0IsR0FBRyx1Q0FBdUM7Z0JBQzFELDRCQUE0QjtnQkFDNUIsc0JBQXNCLGNBQWMsSUFBSTtnQkFDeEMsd0JBQXdCLGdCQUFnQixLQUFLLGdCQUFnQixLQUFLO2dCQUNsRSxpQkFBaUIsU0FBUyxJQUFJO2dCQUM5QixpQkFBaUIsU0FBUyxJQUFJO2dCQUM5QixrQkFBa0IsVUFBVSxNQUFNO2dCQUNsQyxxQkFBcUI7Z0JBQ3JCLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxzQkFBc0IsQ0FBQyxZQUFZLENBQUM7Z0JBQzNELG9CQUFvQjtnQkFDcEIsb0JBQW9CLE9BQU8sQ0FBQyxNQUFNLElBQUk7YUFDdkMsQ0FBQztZQUVGLElBQUksT0FBTyxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztnQkFDdkIsV0FBVyxDQUFDLElBQUksQ0FBQyxvQkFBb0IsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsTUFBTSxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxJQUFJLFNBQVMsS0FBSyxDQUFDLENBQUM7Z0JBQ3JHLFdBQVcsQ0FBQyxJQUFJLENBQUMsb0JBQW9CLE9BQU8sQ0FBQyxPQUFPLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDLFNBQVMsSUFBSSxDQUFDLENBQUM7WUFDbEYsQ0FBQztZQUVELFdBQVcsQ0FBQyxJQUFJLENBQ2QsNEJBQTRCLEVBQzVCLDhCQUE4QixlQUFlLENBQUMsaUJBQWlCLGdCQUFnQixFQUMvRSx3QkFBd0IsZUFBZSxDQUFDLFNBQVMsQ0FBQyxrQkFBa0IsRUFBRSxJQUFJLENBQzNFLENBQUM7WUFFRixJQUFJLENBQUMsZUFBZSxDQUFDLE9BQU8sSUFBSSxlQUFlLENBQUMsZUFBZSxFQUFFLENBQUM7Z0JBQ2hFLFdBQVcsQ0FBQyxJQUFJLENBQUMsWUFBWSxlQUFlLENBQUMsZUFBZSw4QkFBOEIsQ0FBQyxDQUFDO1lBQzlGLENBQUM7WUFFRCxXQUFXLENBQUMsSUFBSSxDQUNkLDZCQUE2QixFQUM3QixrREFBa0QsRUFDbEQscURBQXFELEVBQ3JELGtEQUFrRCxDQUNuRCxDQUFDO1lBRUYsT0FBTyxFQUFFLElBQUksRUFBRSxXQUFXLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUM7UUFFeEMsQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixNQUFNLFlBQVksR0FBRyxLQUFLLFlBQVksS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUM7WUFFNUUsT0FBTztnQkFDTCxJQUFJLEVBQUUsZ0JBQWdCLEdBQUcsK0JBQStCO29CQUN0RCxTQUFTLEdBQUcsWUFBWSxHQUFHLE1BQU07b0JBQ2pDLCtDQUErQztvQkFDL0MsaURBQWlEO2FBQ3BELENBQUM7UUFDSixDQUFDO0lBQ0gsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBNYW5hZ2Ugc2VydmVyIHVwZGF0ZXMgYW5kIHJvbGxiYWNrc1xuICovXG5cbmltcG9ydCAqIGFzIHBhdGggZnJvbSAncGF0aCc7XG5pbXBvcnQgKiBhcyBmcyBmcm9tICdmcy9wcm9taXNlcyc7XG5pbXBvcnQgeyBzYWZlRXhlYyB9IGZyb20gJy4uL3V0aWxzL2dpdC5qcyc7XG5pbXBvcnQgeyBWZXJzaW9uTWFuYWdlciB9IGZyb20gJy4vVmVyc2lvbk1hbmFnZXIuanMnO1xuaW1wb3J0IHsgVXBkYXRlQ2hlY2tlciB9IGZyb20gJy4vVXBkYXRlQ2hlY2tlci5qcyc7XG5pbXBvcnQgeyBEZXBlbmRlbmN5Q2hlY2tlciB9IGZyb20gJy4vRGVwZW5kZW5jeUNoZWNrZXIuanMnO1xuaW1wb3J0IHsgQmFja3VwTWFuYWdlciB9IGZyb20gJy4vQmFja3VwTWFuYWdlci5qcyc7XG5pbXBvcnQgeyBJbnN0YWxsYXRpb25EZXRlY3RvciB9IGZyb20gJy4uL3V0aWxzL2luc3RhbGxhdGlvbi5qcyc7XG5pbXBvcnQgeyBsb2dnZXIgfSBmcm9tICcuLi91dGlscy9sb2dnZXIuanMnO1xuaW1wb3J0IHsgY29tcGFyZVZlcnNpb25zIH0gZnJvbSAnLi4vdXRpbHMvdmVyc2lvbi5qcyc7XG5pbXBvcnQgeyBGaWxlT3BlcmF0aW9ucywgRmlsZVRyYW5zYWN0aW9uIH0gZnJvbSAnLi4vdXRpbHMvZmlsZU9wZXJhdGlvbnMuanMnO1xuaW1wb3J0IHsgVXBkYXRlQ29uZmlnTWFuYWdlciB9IGZyb20gJy4uL2NvbmZpZy91cGRhdGVDb25maWcuanMnO1xuXG5leHBvcnQgaW50ZXJmYWNlIFVwZGF0ZVByb2dyZXNzIHtcbiAgc3RlcDogc3RyaW5nO1xuICBtZXNzYWdlOiBzdHJpbmc7XG4gIGlzQ29tcGxldGU6IGJvb2xlYW47XG59XG5cbmV4cG9ydCBjbGFzcyBVcGRhdGVNYW5hZ2VyIHtcbiAgcHJpdmF0ZSB2ZXJzaW9uTWFuYWdlcjogVmVyc2lvbk1hbmFnZXI7XG4gIHByaXZhdGUgdXBkYXRlQ2hlY2tlcjogVXBkYXRlQ2hlY2tlcjtcbiAgcHJpdmF0ZSBkZXBlbmRlbmN5Q2hlY2tlcjogRGVwZW5kZW5jeUNoZWNrZXI7XG4gIHByaXZhdGUgYmFja3VwTWFuYWdlcjogQmFja3VwTWFuYWdlcjtcbiAgcHJpdmF0ZSByb290RGlyOiBzdHJpbmc7XG4gIFxuICBjb25zdHJ1Y3Rvcihyb290RGlyPzogc3RyaW5nKSB7XG4gICAgdGhpcy5yb290RGlyID0gcm9vdERpciB8fCBwcm9jZXNzLmN3ZCgpO1xuICAgIHRoaXMudmVyc2lvbk1hbmFnZXIgPSBuZXcgVmVyc2lvbk1hbmFnZXIoKTtcbiAgICB0aGlzLnVwZGF0ZUNoZWNrZXIgPSBuZXcgVXBkYXRlQ2hlY2tlcih0aGlzLnZlcnNpb25NYW5hZ2VyKTtcbiAgICB0aGlzLmRlcGVuZGVuY3lDaGVja2VyID0gbmV3IERlcGVuZGVuY3lDaGVja2VyKHRoaXMudmVyc2lvbk1hbmFnZXIpO1xuICAgIHRoaXMuYmFja3VwTWFuYWdlciA9IG5ldyBCYWNrdXBNYW5hZ2VyKHRoaXMucm9vdERpcik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBDaGVjayBmb3IgYXZhaWxhYmxlIHVwZGF0ZXNcbiAgICovXG4gIGFzeW5jIGNoZWNrRm9yVXBkYXRlcygpOiBQcm9taXNlPHsgdGV4dDogc3RyaW5nIH0+IHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgdGhpcy51cGRhdGVDaGVja2VyLmNoZWNrRm9yVXBkYXRlcygpO1xuICAgICAgY29uc3QgdGV4dCA9IHRoaXMudXBkYXRlQ2hlY2tlci5mb3JtYXRVcGRhdGVDaGVja1Jlc3VsdChyZXN1bHQpO1xuICAgICAgcmV0dXJuIHsgdGV4dCB9O1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBjb25zdCB0ZXh0ID0gdGhpcy51cGRhdGVDaGVja2VyLmZvcm1hdFVwZGF0ZUNoZWNrUmVzdWx0KG51bGwsIGVycm9yIGFzIEVycm9yKTtcbiAgICAgIHJldHVybiB7IHRleHQgfTtcbiAgICB9XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBQZXJmb3JtIHNlcnZlciB1cGRhdGVcbiAgICovXG4gIGFzeW5jIHVwZGF0ZVNlcnZlcihjcmVhdGVCYWNrdXA6IGJvb2xlYW4gPSB0cnVlLCBwZXJzb25hSW5kaWNhdG9yOiBzdHJpbmcgPSAnJyk6IFByb21pc2U8eyB0ZXh0OiBzdHJpbmcgfT4ge1xuICAgIGNvbnN0IHByb2dyZXNzOiBVcGRhdGVQcm9ncmVzc1tdID0gW107XG4gICAgXG4gICAgdHJ5IHtcbiAgICAgIC8vIERldGVjdCBpbnN0YWxsYXRpb24gdHlwZVxuICAgICAgY29uc3QgaW5zdGFsbGF0aW9uVHlwZSA9IEluc3RhbGxhdGlvbkRldGVjdG9yLmdldEluc3RhbGxhdGlvblR5cGUoKTtcbiAgICAgIGxvZ2dlci5pbmZvKGBbVXBkYXRlTWFuYWdlcl0gRGV0ZWN0ZWQgaW5zdGFsbGF0aW9uIHR5cGU6ICR7aW5zdGFsbGF0aW9uVHlwZX1gKTtcbiAgICAgIFxuICAgICAgLy8gSGFuZGxlIG5wbSBpbnN0YWxsYXRpb25zIGRpZmZlcmVudGx5XG4gICAgICBpZiAoaW5zdGFsbGF0aW9uVHlwZSA9PT0gJ25wbScpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMudXBkYXRlTnBtSW5zdGFsbGF0aW9uKGNyZWF0ZUJhY2t1cCwgcGVyc29uYUluZGljYXRvcik7XG4gICAgICB9XG4gICAgICBcbiAgICAgIC8vIEZvciBnaXQgaW5zdGFsbGF0aW9ucywgcHJvY2VlZCB3aXRoIGV4aXN0aW5nIGxvZ2ljXG4gICAgICAvLyBTdGVwIDE6IENoZWNrIGRlcGVuZGVuY2llc1xuICAgICAgcHJvZ3Jlc3MucHVzaCh7IHN0ZXA6ICdkZXBlbmRlbmNpZXMnLCBtZXNzYWdlOiAnQ2hlY2tpbmcgc3lzdGVtIGRlcGVuZGVuY2llcy4uLicsIGlzQ29tcGxldGU6IGZhbHNlIH0pO1xuICAgICAgY29uc3QgZGVwZW5kZW5jaWVzID0gYXdhaXQgdGhpcy5kZXBlbmRlbmN5Q2hlY2tlci5jaGVja0RlcGVuZGVuY2llcygpO1xuICAgICAgXG4gICAgICBpZiAoIWRlcGVuZGVuY2llcy5naXQuaW5zdGFsbGVkIHx8IGRlcGVuZGVuY2llcy5naXQuZXJyb3IpIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICB0ZXh0OiBwZXJzb25hSW5kaWNhdG9yICsgJ+KdjCAqKlVwZGF0ZSBGYWlsZWQqKlxcblxcbicgK1xuICAgICAgICAgICAgJ0dpdCBpcyByZXF1aXJlZCBmb3IgdXBkYXRlcyBidXQgaXMgbm90IGF2YWlsYWJsZS5cXG4nICtcbiAgICAgICAgICAgIGRlcGVuZGVuY2llcy5naXQuZXJyb3IgfHwgJ0dpdCBpcyBub3QgaW5zdGFsbGVkLidcbiAgICAgICAgfTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgaWYgKCFkZXBlbmRlbmNpZXMubnBtLmluc3RhbGxlZCB8fCBkZXBlbmRlbmNpZXMubnBtLmVycm9yKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgdGV4dDogcGVyc29uYUluZGljYXRvciArICfinYwgKipVcGRhdGUgRmFpbGVkKipcXG5cXG4nICtcbiAgICAgICAgICAgICducG0gaXMgcmVxdWlyZWQgZm9yIHVwZGF0ZXMgYnV0IGlzIG5vdCBhdmFpbGFibGUuXFxuJyArXG4gICAgICAgICAgICBkZXBlbmRlbmNpZXMubnBtLmVycm9yIHx8ICducG0gaXMgbm90IGluc3RhbGxlZC4nXG4gICAgICAgIH07XG4gICAgICB9XG4gICAgICBcbiAgICAgIHByb2dyZXNzWzBdLmlzQ29tcGxldGUgPSB0cnVlO1xuICAgICAgXG4gICAgICAvLyBTdGVwIDI6IENyZWF0ZSBiYWNrdXAgaWYgcmVxdWVzdGVkXG4gICAgICBpZiAoY3JlYXRlQmFja3VwKSB7XG4gICAgICAgIHByb2dyZXNzLnB1c2goeyBzdGVwOiAnYmFja3VwJywgbWVzc2FnZTogJ0NyZWF0aW5nIGJhY2t1cC4uLicsIGlzQ29tcGxldGU6IGZhbHNlIH0pO1xuICAgICAgICBcbiAgICAgICAgY29uc3QgY3VycmVudFZlcnNpb24gPSBhd2FpdCB0aGlzLnZlcnNpb25NYW5hZ2VyLmdldEN1cnJlbnRWZXJzaW9uKCk7XG4gICAgICAgIGNvbnN0IGJhY2t1cCA9IGF3YWl0IHRoaXMuYmFja3VwTWFuYWdlci5jcmVhdGVCYWNrdXAoY3VycmVudFZlcnNpb24pO1xuICAgICAgICBcbiAgICAgICAgcHJvZ3Jlc3NbMV0uaXNDb21wbGV0ZSA9IHRydWU7XG4gICAgICAgIHByb2dyZXNzWzFdLm1lc3NhZ2UgPSBgQmFja3VwIGNyZWF0ZWQgYXQ6ICR7YmFja3VwLnRpbWVzdGFtcH1gO1xuICAgICAgfVxuICAgICAgXG4gICAgICAvLyBTdGVwIDM6IEdpdCBmZXRjaFxuICAgICAgcHJvZ3Jlc3MucHVzaCh7IHN0ZXA6ICdmZXRjaCcsIG1lc3NhZ2U6ICdGZXRjaGluZyBsYXRlc3QgY2hhbmdlcy4uLicsIGlzQ29tcGxldGU6IGZhbHNlIH0pO1xuICAgICAgYXdhaXQgc2FmZUV4ZWMoJ2dpdCcsIFsnZmV0Y2gnLCAnb3JpZ2luJ10sIHsgY3dkOiB0aGlzLnJvb3REaXIgfSk7XG4gICAgICBwcm9ncmVzc1twcm9ncmVzcy5sZW5ndGggLSAxXS5pc0NvbXBsZXRlID0gdHJ1ZTtcbiAgICAgIFxuICAgICAgLy8gU3RlcCA0OiBDaGVjayBmb3IgdW5jb21taXR0ZWQgY2hhbmdlc1xuICAgICAgcHJvZ3Jlc3MucHVzaCh7IHN0ZXA6ICdjaGVjaycsIG1lc3NhZ2U6ICdDaGVja2luZyBmb3IgdW5jb21taXR0ZWQgY2hhbmdlcy4uLicsIGlzQ29tcGxldGU6IGZhbHNlIH0pO1xuICAgICAgY29uc3QgeyBzdGRvdXQ6IHN0YXR1c091dHB1dCB9ID0gYXdhaXQgc2FmZUV4ZWMoJ2dpdCcsIFsnc3RhdHVzJywgJy0tcG9yY2VsYWluJ10sIHsgY3dkOiB0aGlzLnJvb3REaXIgfSk7XG4gICAgICBcbiAgICAgIGlmIChzdGF0dXNPdXRwdXQudHJpbSgpKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgdGV4dDogcGVyc29uYUluZGljYXRvciArICfinYwgKipVcGRhdGUgRmFpbGVkKipcXG5cXG4nICtcbiAgICAgICAgICAgICdZb3UgaGF2ZSB1bmNvbW1pdHRlZCBjaGFuZ2VzLiBQbGVhc2UgY29tbWl0IG9yIHN0YXNoIHRoZW0gYmVmb3JlIHVwZGF0aW5nLlxcblxcbicgK1xuICAgICAgICAgICAgJ01vZGlmaWVkIGZpbGVzOlxcbicgKyBzdGF0dXNPdXRwdXRcbiAgICAgICAgfTtcbiAgICAgIH1cbiAgICAgIHByb2dyZXNzW3Byb2dyZXNzLmxlbmd0aCAtIDFdLmlzQ29tcGxldGUgPSB0cnVlO1xuICAgICAgXG4gICAgICAvLyBTdGVwIDU6IEdpdCBwdWxsXG4gICAgICBwcm9ncmVzcy5wdXNoKHsgc3RlcDogJ3B1bGwnLCBtZXNzYWdlOiAnUHVsbGluZyBsYXRlc3QgY2hhbmdlcy4uLicsIGlzQ29tcGxldGU6IGZhbHNlIH0pO1xuICAgICAgY29uc3QgeyBzdGRvdXQ6IHB1bGxPdXRwdXQgfSA9IGF3YWl0IHNhZmVFeGVjKCdnaXQnLCBbJ3B1bGwnLCAnb3JpZ2luJywgJ21haW4nXSwgeyBjd2Q6IHRoaXMucm9vdERpciB9KTtcbiAgICAgIHByb2dyZXNzW3Byb2dyZXNzLmxlbmd0aCAtIDFdLmlzQ29tcGxldGUgPSB0cnVlO1xuICAgICAgXG4gICAgICAvLyBDaGVjayBpZiBhbHJlYWR5IHVwIHRvIGRhdGVcbiAgICAgIGlmIChwdWxsT3V0cHV0LmluY2x1ZGVzKCdBbHJlYWR5IHVwIHRvIGRhdGUnKSkge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIHRleHQ6IHBlcnNvbmFJbmRpY2F0b3IgKyAn4pyFICoqQWxyZWFkeSBVcCB0byBEYXRlKipcXG5cXG4nICtcbiAgICAgICAgICAgICdZb3VyIERvbGxob3VzZU1DUCBpbnN0YWxsYXRpb24gaXMgYWxyZWFkeSBhdCB0aGUgbGF0ZXN0IHZlcnNpb24uXFxuXFxuJyArXG4gICAgICAgICAgICAnTm8gY2hhbmdlcyB3ZXJlIHB1bGxlZCBmcm9tIHRoZSByZXBvc2l0b3J5LidcbiAgICAgICAgfTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgLy8gU3RlcCA2OiBucG0gaW5zdGFsbFxuICAgICAgcHJvZ3Jlc3MucHVzaCh7IHN0ZXA6ICdpbnN0YWxsJywgbWVzc2FnZTogJ0luc3RhbGxpbmcgZGVwZW5kZW5jaWVzLi4uJywgaXNDb21wbGV0ZTogZmFsc2UgfSk7XG4gICAgICBhd2FpdCBzYWZlRXhlYygnbnBtJywgWydpbnN0YWxsJ10sIHsgY3dkOiB0aGlzLnJvb3REaXIgfSk7XG4gICAgICBwcm9ncmVzc1twcm9ncmVzcy5sZW5ndGggLSAxXS5pc0NvbXBsZXRlID0gdHJ1ZTtcbiAgICAgIFxuICAgICAgLy8gU3RlcCA3OiBCdWlsZFxuICAgICAgcHJvZ3Jlc3MucHVzaCh7IHN0ZXA6ICdidWlsZCcsIG1lc3NhZ2U6ICdCdWlsZGluZyBUeXBlU2NyaXB0Li4uJywgaXNDb21wbGV0ZTogZmFsc2UgfSk7XG4gICAgICBhd2FpdCBzYWZlRXhlYygnbnBtJywgWydydW4nLCAnYnVpbGQnXSwgeyBjd2Q6IHRoaXMucm9vdERpciB9KTtcbiAgICAgIHByb2dyZXNzW3Byb2dyZXNzLmxlbmd0aCAtIDFdLmlzQ29tcGxldGUgPSB0cnVlO1xuICAgICAgXG4gICAgICAvLyBTdGVwIDg6IENsZWFudXAgb2xkIGJhY2t1cHNcbiAgICAgIGlmIChjcmVhdGVCYWNrdXApIHtcbiAgICAgICAgcHJvZ3Jlc3MucHVzaCh7IHN0ZXA6ICdjbGVhbnVwJywgbWVzc2FnZTogJ0NsZWFuaW5nIHVwIG9sZCBiYWNrdXBzLi4uJywgaXNDb21wbGV0ZTogZmFsc2UgfSk7XG4gICAgICAgIGNvbnN0IGRlbGV0ZWRDb3VudCA9IGF3YWl0IHRoaXMuYmFja3VwTWFuYWdlci5jbGVhbnVwT2xkQmFja3VwcygpO1xuICAgICAgICBwcm9ncmVzc1twcm9ncmVzcy5sZW5ndGggLSAxXS5pc0NvbXBsZXRlID0gdHJ1ZTtcbiAgICAgICAgcHJvZ3Jlc3NbcHJvZ3Jlc3MubGVuZ3RoIC0gMV0ubWVzc2FnZSA9IGBDbGVhbmVkIHVwICR7ZGVsZXRlZENvdW50fSBvbGQgYmFja3VwKHMpYDtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgLy8gRm9ybWF0IHN1Y2Nlc3MgbWVzc2FnZVxuICAgICAgY29uc3Qgc3VjY2Vzc1BhcnRzID0gW1xuICAgICAgICBwZXJzb25hSW5kaWNhdG9yICsgJ+KchSAqKlVwZGF0ZSBDb21wbGV0ZSEqKlxcblxcbicsXG4gICAgICAgICcqKlVwZGF0ZSBTdW1tYXJ5OioqXFxuJ1xuICAgICAgXTtcbiAgICAgIFxuICAgICAgcHJvZ3Jlc3MuZm9yRWFjaChwID0+IHtcbiAgICAgICAgc3VjY2Vzc1BhcnRzLnB1c2goYCR7cC5pc0NvbXBsZXRlID8gJ+KchScgOiAn4p2MJ30gJHtwLm1lc3NhZ2V9XFxuYCk7XG4gICAgICB9KTtcbiAgICAgIFxuICAgICAgc3VjY2Vzc1BhcnRzLnB1c2goXG4gICAgICAgICdcXG4qKk5leHQgU3RlcHM6KipcXG4nLFxuICAgICAgICAnMS4gVGhlIHNlcnZlciB3aWxsIHJlc3RhcnQgYXV0b21hdGljYWxseVxcbicsXG4gICAgICAgICcyLiBBbGwgcGVyc29uYXMgd2lsbCBiZSByZWxvYWRlZFxcbicsXG4gICAgICAgICczLiBDaGVjayBgZ2V0X3NlcnZlcl9zdGF0dXNgIHRvIHZlcmlmeSB0aGUgbmV3IHZlcnNpb25cXG5cXG4nLFxuICAgICAgICAn8J+SoSAqKlRpcDoqKiBJZiB5b3UgZW5jb3VudGVyIGlzc3VlcywgdXNlIGByb2xsYmFja191cGRhdGUgdHJ1ZWAgdG8gcmVzdG9yZSB0aGUgcHJldmlvdXMgdmVyc2lvbi4nXG4gICAgICApO1xuICAgICAgXG4gICAgICByZXR1cm4geyB0ZXh0OiBzdWNjZXNzUGFydHMuam9pbignJykgfTtcbiAgICAgIFxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBjb25zdCBlcnJvck1lc3NhZ2UgPSBlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcik7XG4gICAgICBcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHRleHQ6IHBlcnNvbmFJbmRpY2F0b3IgKyAn4p2MICoqVXBkYXRlIEZhaWxlZCoqXFxuXFxuJyArXG4gICAgICAgICAgJ0Vycm9yOiAnICsgZXJyb3JNZXNzYWdlICsgJ1xcblxcbicgK1xuICAgICAgICAgICcqKlByb2dyZXNzOioqXFxuJyArIFxuICAgICAgICAgIHByb2dyZXNzLm1hcChwID0+IGAke3AuaXNDb21wbGV0ZSA/ICfinIUnIDogJ+KdjCd9ICR7cC5tZXNzYWdlfWApLmpvaW4oJ1xcbicpICsgJ1xcblxcbicgK1xuICAgICAgICAgICcqKlJlY292ZXJ5IE9wdGlvbnM6KipcXG4nICtcbiAgICAgICAgICAn4oCiIFRyeSBydW5uaW5nIHRoZSB1cGRhdGUgYWdhaW5cXG4nICtcbiAgICAgICAgICAn4oCiIENoZWNrIHlvdXIgaW50ZXJuZXQgY29ubmVjdGlvblxcbicgK1xuICAgICAgICAgICfigKIgRW5zdXJlIHlvdSBoYXZlIHByb3BlciBwZXJtaXNzaW9uc1xcbicgK1xuICAgICAgICAgICfigKIgSWYgYSBiYWNrdXAgd2FzIGNyZWF0ZWQsIHVzZSBgcm9sbGJhY2tfdXBkYXRlIHRydWVgIHRvIHJlc3RvcmUnXG4gICAgICB9O1xuICAgIH1cbiAgfVxuICBcbiAgLyoqXG4gICAqIFJvbGxiYWNrIHRvIHByZXZpb3VzIHZlcnNpb25cbiAgICovXG4gIGFzeW5jIHJvbGxiYWNrVXBkYXRlKGZvcmNlOiBib29sZWFuID0gZmFsc2UsIHBlcnNvbmFJbmRpY2F0b3I6IHN0cmluZyA9ICcnKTogUHJvbWlzZTx7IHRleHQ6IHN0cmluZyB9PiB7XG4gICAgdHJ5IHtcbiAgICAgIC8vIENoZWNrIGluc3RhbGxhdGlvbiB0eXBlXG4gICAgICBjb25zdCBpbnN0YWxsYXRpb25UeXBlID0gSW5zdGFsbGF0aW9uRGV0ZWN0b3IuZ2V0SW5zdGFsbGF0aW9uVHlwZSgpO1xuICAgICAgXG4gICAgICBpZiAoaW5zdGFsbGF0aW9uVHlwZSA9PT0gJ25wbScpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMucm9sbGJhY2tOcG1JbnN0YWxsYXRpb24oZm9yY2UsIHBlcnNvbmFJbmRpY2F0b3IpO1xuICAgICAgfVxuICAgICAgXG4gICAgICAvLyBGb3IgZ2l0IGluc3RhbGxhdGlvbnMsIHVzZSBleGlzdGluZyBsb2dpY1xuICAgICAgLy8gR2V0IGxhdGVzdCBiYWNrdXBcbiAgICAgIGNvbnN0IGxhdGVzdEJhY2t1cCA9IGF3YWl0IHRoaXMuYmFja3VwTWFuYWdlci5nZXRMYXRlc3RCYWNrdXAoKTtcbiAgICAgIFxuICAgICAgaWYgKCFsYXRlc3RCYWNrdXApIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICB0ZXh0OiBwZXJzb25hSW5kaWNhdG9yICsgJ+KdjCAqKk5vIEJhY2t1cHMgRm91bmQqKlxcblxcbicgK1xuICAgICAgICAgICAgJ1RoZXJlIGFyZSBubyBiYWNrdXBzIGF2YWlsYWJsZSB0byByZXN0b3JlLlxcblxcbicgK1xuICAgICAgICAgICAgJ0JhY2t1cHMgYXJlIGNyZWF0ZWQgYXV0b21hdGljYWxseSB3aGVuIHlvdSBydW4gYHVwZGF0ZV9zZXJ2ZXIgdHJ1ZWAuJ1xuICAgICAgICB9O1xuICAgICAgfVxuICAgICAgXG4gICAgICAvLyBDaGVjayBpZiByb2xsYmFjayBpcyBuZWVkZWRcbiAgICAgIGlmICghZm9yY2UpIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAvLyBUZXN0IGlmIHRoZSBzZXJ2ZXIgaXMgd29ya2luZyBieSBjaGVja2luZyB2ZXJzaW9uXG4gICAgICAgICAgYXdhaXQgdGhpcy52ZXJzaW9uTWFuYWdlci5nZXRDdXJyZW50VmVyc2lvbigpO1xuICAgICAgICAgIFxuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICB0ZXh0OiBwZXJzb25hSW5kaWNhdG9yICsgJ+KaoO+4jyAqKlJvbGxiYWNrIENvbmZpcm1hdGlvbiBSZXF1aXJlZCoqXFxuXFxuJyArXG4gICAgICAgICAgICAgICdUaGUgc2VydmVyIGFwcGVhcnMgdG8gYmUgd29ya2luZyBub3JtYWxseS5cXG5cXG4nICtcbiAgICAgICAgICAgICAgYCoqTGF0ZXN0IEJhY2t1cDoqKiAke2xhdGVzdEJhY2t1cC50aW1lc3RhbXB9XFxuYCArXG4gICAgICAgICAgICAgIGAqKkJhY2t1cCBWZXJzaW9uOioqICR7bGF0ZXN0QmFja3VwLnZlcnNpb24gfHwgJ1Vua25vd24nfVxcblxcbmAgK1xuICAgICAgICAgICAgICAnVG8gZm9yY2Ugcm9sbGJhY2sgYW55d2F5LCB1c2U6IGByb2xsYmFja191cGRhdGUgdHJ1ZWBcXG5cXG4nICtcbiAgICAgICAgICAgICAgJ+KaoO+4jyAqKldhcm5pbmc6KiogVGhpcyB3aWxsIHJlc3RvcmUgYWxsIGZpbGVzIHRvIHRoZSBiYWNrdXAgc3RhdGUuJ1xuICAgICAgICAgIH07XG4gICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgIC8vIFNlcnZlciBpcyBicm9rZW4sIHByb2NlZWQgd2l0aCByb2xsYmFja1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBcbiAgICAgIC8vIFBlcmZvcm0gcm9sbGJhY2tcbiAgICAgIGF3YWl0IHRoaXMuYmFja3VwTWFuYWdlci5yZXN0b3JlQmFja3VwKGxhdGVzdEJhY2t1cC5wYXRoKTtcbiAgICAgIFxuICAgICAgLy8gUmVpbnN0YWxsIGRlcGVuZGVuY2llc1xuICAgICAgYXdhaXQgc2FmZUV4ZWMoJ25wbScsIFsnaW5zdGFsbCddLCB7IGN3ZDogdGhpcy5yb290RGlyIH0pO1xuICAgICAgXG4gICAgICAvLyBSZWJ1aWxkXG4gICAgICBhd2FpdCBzYWZlRXhlYygnbnBtJywgWydydW4nLCAnYnVpbGQnXSwgeyBjd2Q6IHRoaXMucm9vdERpciB9KTtcbiAgICAgIFxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgdGV4dDogcGVyc29uYUluZGljYXRvciArICfinIUgKipSb2xsYmFjayBDb21wbGV0ZSEqKlxcblxcbicgK1xuICAgICAgICAgIGBSZXN0b3JlZCBmcm9tIGJhY2t1cDogJHtsYXRlc3RCYWNrdXAudGltZXN0YW1wfVxcbmAgK1xuICAgICAgICAgIGBCYWNrdXAgdmVyc2lvbjogJHtsYXRlc3RCYWNrdXAudmVyc2lvbiB8fCAnVW5rbm93bid9XFxuXFxuYCArXG4gICAgICAgICAgJyoqV2hhdCB3YXMgcmVzdG9yZWQ6KipcXG4nICtcbiAgICAgICAgICAn4oCiIEFsbCBzb3VyY2UgZmlsZXNcXG4nICtcbiAgICAgICAgICAn4oCiIENvbmZpZ3VyYXRpb24gZmlsZXNcXG4nICtcbiAgICAgICAgICAn4oCiIERlcGVuZGVuY2llcyByZWluc3RhbGxlZFxcbicgK1xuICAgICAgICAgICfigKIgVHlwZVNjcmlwdCByZWJ1aWx0XFxuXFxuJyArXG4gICAgICAgICAgJyoqTmV4dCBTdGVwczoqKlxcbicgK1xuICAgICAgICAgICcxLiBUaGUgc2VydmVyIHdpbGwgcmVzdGFydCBhdXRvbWF0aWNhbGx5XFxuJyArXG4gICAgICAgICAgJzIuIENoZWNrIGBnZXRfc2VydmVyX3N0YXR1c2AgdG8gdmVyaWZ5IHRoZSB2ZXJzaW9uXFxuJyArXG4gICAgICAgICAgJzMuIFRlc3QgeW91ciBwZXJzb25hcyB0byBlbnN1cmUgZXZlcnl0aGluZyB3b3JrcydcbiAgICAgIH07XG4gICAgICBcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgY29uc3QgZXJyb3JNZXNzYWdlID0gZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpO1xuICAgICAgXG4gICAgICByZXR1cm4ge1xuICAgICAgICB0ZXh0OiBwZXJzb25hSW5kaWNhdG9yICsgJ+KdjCAqKlJvbGxiYWNrIEZhaWxlZCoqXFxuXFxuJyArXG4gICAgICAgICAgJ0Vycm9yOiAnICsgZXJyb3JNZXNzYWdlICsgJ1xcblxcbicgK1xuICAgICAgICAgICcqKk1hbnVhbCBSZWNvdmVyeToqKlxcbicgK1xuICAgICAgICAgICcxLiBDaGVjayB0aGUgYmFja3VwcyBkaXJlY3Rvcnk6IC4uL2RvbGxob3VzZW1jcC1iYWNrdXBzL1xcbicgK1xuICAgICAgICAgICcyLiBNYW51YWxseSByZXN0b3JlIGZpbGVzIGlmIG5lZWRlZFxcbicgK1xuICAgICAgICAgICczLiBSdW4gYG5wbSBpbnN0YWxsYCBhbmQgYG5wbSBydW4gYnVpbGRgXFxuJyArXG4gICAgICAgICAgJzQuIENvbnRhY3Qgc3VwcG9ydCBpZiBpc3N1ZXMgcGVyc2lzdCdcbiAgICAgIH07XG4gICAgfVxuICB9XG4gIFxuICAvKipcbiAgICogVXBkYXRlIG5wbSBpbnN0YWxsYXRpb25cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgdXBkYXRlTnBtSW5zdGFsbGF0aW9uKGNyZWF0ZUJhY2t1cDogYm9vbGVhbiwgcGVyc29uYUluZGljYXRvcjogc3RyaW5nID0gJycpOiBQcm9taXNlPHsgdGV4dDogc3RyaW5nIH0+IHtcbiAgICB0cnkge1xuICAgICAgbG9nZ2VyLmluZm8oJ1tVcGRhdGVNYW5hZ2VyXSBTdGFydGluZyBucG0gdXBkYXRlIHByb2Nlc3MnKTtcbiAgICAgIFxuICAgICAgLy8gQ2hlY2sgbnBtIGlzIGF2YWlsYWJsZVxuICAgICAgY29uc3QgZGVwZW5kZW5jaWVzID0gYXdhaXQgdGhpcy5kZXBlbmRlbmN5Q2hlY2tlci5jaGVja0RlcGVuZGVuY2llcygpO1xuICAgICAgaWYgKCFkZXBlbmRlbmNpZXMubnBtLmluc3RhbGxlZCB8fCBkZXBlbmRlbmNpZXMubnBtLmVycm9yKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgdGV4dDogcGVyc29uYUluZGljYXRvciArICfinYwgKipVcGRhdGUgRmFpbGVkKipcXG5cXG4nICtcbiAgICAgICAgICAgICducG0gaXMgcmVxdWlyZWQgZm9yIHVwZGF0ZXMgYnV0IGlzIG5vdCBhdmFpbGFibGUuXFxuJyArXG4gICAgICAgICAgICBkZXBlbmRlbmNpZXMubnBtLmVycm9yIHx8ICducG0gaXMgbm90IGluc3RhbGxlZC4nXG4gICAgICAgIH07XG4gICAgICB9XG4gICAgICBcbiAgICAgIC8vIEdldCBjdXJyZW50IHZlcnNpb25cbiAgICAgIGNvbnN0IGN1cnJlbnRWZXJzaW9uID0gYXdhaXQgdGhpcy52ZXJzaW9uTWFuYWdlci5nZXRDdXJyZW50VmVyc2lvbigpO1xuICAgICAgbG9nZ2VyLmluZm8oYFtVcGRhdGVNYW5hZ2VyXSBDdXJyZW50IHZlcnNpb246ICR7Y3VycmVudFZlcnNpb259YCk7XG4gICAgICBcbiAgICAgIC8vIENoZWNrIGxhdGVzdCB2ZXJzaW9uIGZyb20gbnBtIHJlZ2lzdHJ5XG4gICAgICBsb2dnZXIuaW5mbygnW1VwZGF0ZU1hbmFnZXJdIENoZWNraW5nIG5wbSByZWdpc3RyeSBmb3IgbGF0ZXN0IHZlcnNpb24nKTtcbiAgICAgIFxuICAgICAgLy8gU2VjdXJpdHk6IFZhbGlkYXRlIHBhY2thZ2UgbmFtZSB0byBwcmV2ZW50IGFueSBwb3RlbnRpYWwgaW5qZWN0aW9uXG4gICAgICBjb25zdCBwYWNrYWdlTmFtZSA9ICdAZG9sbGhvdXNlbWNwL21jcC1zZXJ2ZXInO1xuICAgICAgaWYgKCEvXkBbYS16MC05LV0rXFwvW2EtejAtOS1dKyQvLnRlc3QocGFja2FnZU5hbWUpKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBwYWNrYWdlIG5hbWUgZm9ybWF0Jyk7XG4gICAgICB9XG4gICAgICBcbiAgICAgIGNvbnN0IHsgc3Rkb3V0OiBucG1WaWV3T3V0cHV0IH0gPSBhd2FpdCBzYWZlRXhlYygnbnBtJywgWyd2aWV3JywgcGFja2FnZU5hbWUsICd2ZXJzaW9uJ10sIHtcbiAgICAgICAgY3dkOiB0aGlzLnJvb3REaXIsXG4gICAgICAgIHRpbWVvdXQ6IDMwMDAwXG4gICAgICB9KTtcbiAgICAgIFxuICAgICAgY29uc3QgbGF0ZXN0VmVyc2lvbiA9IG5wbVZpZXdPdXRwdXQudHJpbSgpO1xuICAgICAgbG9nZ2VyLmluZm8oYFtVcGRhdGVNYW5hZ2VyXSBMYXRlc3QgbnBtIHZlcnNpb246ICR7bGF0ZXN0VmVyc2lvbn1gKTtcbiAgICAgIFxuICAgICAgLy8gQ29tcGFyZSB2ZXJzaW9uc1xuICAgICAgY29uc3QgY29tcGFyaXNvbiA9IGNvbXBhcmVWZXJzaW9ucyhjdXJyZW50VmVyc2lvbiwgbGF0ZXN0VmVyc2lvbik7XG4gICAgICBcbiAgICAgIGlmIChjb21wYXJpc29uID49IDApIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICB0ZXh0OiBwZXJzb25hSW5kaWNhdG9yICsgJ+KchSAqKkFscmVhZHkgdXAgdG8gZGF0ZSEqKlxcblxcbicgK1xuICAgICAgICAgICAgYEN1cnJlbnQgdmVyc2lvbjogJHtjdXJyZW50VmVyc2lvbn1cXG5gICtcbiAgICAgICAgICAgIGBMYXRlc3QgdmVyc2lvbjogJHtsYXRlc3RWZXJzaW9ufVxcblxcbmAgK1xuICAgICAgICAgICAgJ05vIHVwZGF0ZSBuZWVkZWQuJ1xuICAgICAgICB9O1xuICAgICAgfVxuICAgICAgXG4gICAgICAvLyBHZXQgY29uZmlndXJhdGlvblxuICAgICAgY29uc3QgY29uZmlnID0gVXBkYXRlQ29uZmlnTWFuYWdlci5nZXRJbnN0YW5jZSgpO1xuICAgICAgXG4gICAgICAvLyBQcm9ncmVzcyB0cmFja2luZ1xuICAgICAgbGV0IHByb2dyZXNzTWVzc2FnZSA9IHBlcnNvbmFJbmRpY2F0b3IgKyAn8J+UhCAqKk5QTSBVcGRhdGUgaW4gUHJvZ3Jlc3MqKlxcblxcbic7XG4gICAgICBwcm9ncmVzc01lc3NhZ2UgKz0gJyoqU3RlcHM6KipcXG4nO1xuICAgICAgcHJvZ3Jlc3NNZXNzYWdlICs9ICfinIUgVmVyc2lvbiBjaGVjayBjb21wbGV0ZVxcbic7XG4gICAgICBwcm9ncmVzc01lc3NhZ2UgKz0gJ+KPsyBDcmVhdGluZyBiYWNrdXAuLi5cXG4nO1xuICAgICAgXG4gICAgICAvLyBGb3IgbnBtIGluc3RhbGxhdGlvbnMsIGJhY2t1cCBpcyBtYW5kYXRvcnkgZm9yIHNhZmV0eVxuICAgICAgbG9nZ2VyLmluZm8oJ1tVcGRhdGVNYW5hZ2VyXSBDcmVhdGluZyBiYWNrdXAgYmVmb3JlIG5wbSB1cGRhdGUnKTtcbiAgICAgIHRyeSB7XG4gICAgICAgIC8vIEZvciBucG0gaW5zdGFsbGF0aW9ucywgd2UgYmFja3VwIHRoZSBnbG9iYWwgaW5zdGFsbGF0aW9uIGRpcmVjdG9yeVxuICAgICAgICBjb25zdCBucG1HbG9iYWxQYXRoID0gSW5zdGFsbGF0aW9uRGV0ZWN0b3IuZ2V0TnBtR2xvYmFsUGF0aCgpO1xuICAgICAgICBpZiAoIW5wbUdsb2JhbFBhdGgpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0NvdWxkIG5vdCBkZXRlcm1pbmUgbnBtIGdsb2JhbCBpbnN0YWxsYXRpb24gcGF0aCcpO1xuICAgICAgICB9XG4gICAgICAgIFxuICAgICAgICAvLyBDcmVhdGUgbnBtLXNwZWNpZmljIGJhY2t1cCB3aXRoIHByb2dyZXNzXG4gICAgICAgIGNvbnN0IGJhY2t1cFBhdGggPSBhd2FpdCB0aGlzLmJhY2t1cE1hbmFnZXIuY3JlYXRlTnBtQmFja3VwKG5wbUdsb2JhbFBhdGgsIGN1cnJlbnRWZXJzaW9uKTtcbiAgICAgICAgbG9nZ2VyLmluZm8oYFtVcGRhdGVNYW5hZ2VyXSBCYWNrdXAgY3JlYXRlZCBhdDogJHtiYWNrdXBQYXRofWApO1xuICAgICAgICBcbiAgICAgICAgcHJvZ3Jlc3NNZXNzYWdlID0gcHJvZ3Jlc3NNZXNzYWdlLnJlcGxhY2UoJ+KPsyBDcmVhdGluZyBiYWNrdXAuLi4nLCAn4pyFIEJhY2t1cCBjcmVhdGVkJyk7XG4gICAgICAgIHByb2dyZXNzTWVzc2FnZSArPSAn4o+zIERvd25sb2FkaW5nIGFuZCBpbnN0YWxsaW5nIHVwZGF0ZS4uLlxcbic7XG4gICAgICAgIFxuICAgICAgfSBjYXRjaCAoYmFja3VwRXJyb3IpIHtcbiAgICAgICAgbG9nZ2VyLmVycm9yKCdbVXBkYXRlTWFuYWdlcl0gQmFja3VwIGZhaWxlZDonLCBiYWNrdXBFcnJvcik7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgdGV4dDogcGVyc29uYUluZGljYXRvciArICfinYwgKipVcGRhdGUgRmFpbGVkKipcXG5cXG4nICtcbiAgICAgICAgICAgICdGYWlsZWQgdG8gY3JlYXRlIGJhY2t1cCBiZWZvcmUgdXBkYXRlLlxcbicgK1xuICAgICAgICAgICAgJ0Vycm9yOiAnICsgKGJhY2t1cEVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBiYWNrdXBFcnJvci5tZXNzYWdlIDogU3RyaW5nKGJhY2t1cEVycm9yKSkgKyAnXFxuXFxuJyArXG4gICAgICAgICAgICAnKipOb3RlOioqIEJhY2t1cCBpcyBtYW5kYXRvcnkgZm9yIG5wbSBpbnN0YWxsYXRpb25zIHRvIGVuc3VyZSBzYWZlIHJvbGxiYWNrLlxcbicgK1xuICAgICAgICAgICAgJ1BsZWFzZSBjaGVjayBkaXNrIHNwYWNlIGFuZCBwZXJtaXNzaW9ucy4nXG4gICAgICAgIH07XG4gICAgICB9XG4gICAgICBcbiAgICAgIC8vIFBlcmZvcm0gbnBtIHVwZGF0ZSB3aXRoIHByb2dyZXNzXG4gICAgICBsb2dnZXIuaW5mbygnW1VwZGF0ZU1hbmFnZXJdIFJ1bm5pbmcgbnBtIHVwZGF0ZSAtZyBAZG9sbGhvdXNlbWNwL21jcC1zZXJ2ZXInKTtcbiAgICAgIHByb2dyZXNzTWVzc2FnZSArPSAnXFxuKipQcm9ncmVzczoqKlxcbic7XG4gICAgICBwcm9ncmVzc01lc3NhZ2UgKz0gJ2BgYFxcbic7XG4gICAgICBwcm9ncmVzc01lc3NhZ2UgKz0gJ1J1bm5pbmc6IG5wbSB1cGRhdGUgLWcgQGRvbGxob3VzZW1jcC9tY3Atc2VydmVyXFxuJztcbiAgICAgIHByb2dyZXNzTWVzc2FnZSArPSAnVGhpcyBtYXkgdGFrZSBhIGZldyBtaW51dGVzLi4uXFxuJztcbiAgICAgIHByb2dyZXNzTWVzc2FnZSArPSAnYGBgXFxuJztcbiAgICAgIFxuICAgICAgY29uc3QgdXBkYXRlUmVzdWx0ID0gYXdhaXQgc2FmZUV4ZWMoJ25wbScsIFsndXBkYXRlJywgJy1nJywgJ0Bkb2xsaG91c2VtY3AvbWNwLXNlcnZlciddLCB7XG4gICAgICAgIGN3ZDogdGhpcy5yb290RGlyLFxuICAgICAgICB0aW1lb3V0OiBjb25maWcuZ2V0TnBtVXBkYXRlVGltZW91dCgpXG4gICAgICB9KTtcbiAgICAgIFxuICAgICAgbG9nZ2VyLmluZm8oJ1tVcGRhdGVNYW5hZ2VyXSBucG0gdXBkYXRlIGNvbXBsZXRlZCcsIHVwZGF0ZVJlc3VsdCk7XG4gICAgICBcbiAgICAgIC8vIFZlcmlmeSB1cGRhdGUgc3VjY2VlZGVkXG4gICAgICBjb25zdCB7IHN0ZG91dDogdmVyaWZ5T3V0cHV0IH0gPSBhd2FpdCBzYWZlRXhlYygnbnBtJywgWydsaXN0JywgJy1nJywgJ0Bkb2xsaG91c2VtY3AvbWNwLXNlcnZlcicsICctLWRlcHRoPTAnXSwge1xuICAgICAgICBjd2Q6IHRoaXMucm9vdERpcixcbiAgICAgICAgdGltZW91dDogMzAwMDBcbiAgICAgIH0pO1xuICAgICAgXG4gICAgICBjb25zdCB2ZXJzaW9uTWF0Y2ggPSB2ZXJpZnlPdXRwdXQubWF0Y2goL0Bkb2xsaG91c2VtY3BcXC9tY3Atc2VydmVyQChcXGQrXFwuXFxkK1xcLlxcZCspLyk7XG4gICAgICBjb25zdCBpbnN0YWxsZWRWZXJzaW9uID0gdmVyc2lvbk1hdGNoID8gdmVyc2lvbk1hdGNoWzFdIDogJ3Vua25vd24nO1xuICAgICAgXG4gICAgICBpZiAoaW5zdGFsbGVkVmVyc2lvbiAhPT0gbGF0ZXN0VmVyc2lvbikge1xuICAgICAgICBsb2dnZXIud2FybihgW1VwZGF0ZU1hbmFnZXJdIFZlcnNpb24gbWlzbWF0Y2ggYWZ0ZXIgdXBkYXRlLiBFeHBlY3RlZDogJHtsYXRlc3RWZXJzaW9ufSwgR290OiAke2luc3RhbGxlZFZlcnNpb259YCk7XG4gICAgICB9XG4gICAgICBcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHRleHQ6IHBlcnNvbmFJbmRpY2F0b3IgKyAn4pyFICoqVXBkYXRlIENvbXBsZXRlISoqXFxuXFxuJyArXG4gICAgICAgICAgYFVwZGF0ZWQgZnJvbSB2JHtjdXJyZW50VmVyc2lvbn0gdG8gdiR7bGF0ZXN0VmVyc2lvbn1cXG5cXG5gICtcbiAgICAgICAgICAnKipXaGF0IHdhcyB1cGRhdGVkOioqXFxuJyArXG4gICAgICAgICAgJ+KAoiBEb2xsaG91c2VNQ1Agc2VydmVyIHBhY2thZ2VcXG4nICtcbiAgICAgICAgICAn4oCiIEFsbCBkZXBlbmRlbmNpZXNcXG5cXG4nICtcbiAgICAgICAgICAnKipOZXh0IFN0ZXBzOioqXFxuJyArXG4gICAgICAgICAgJzEuIFRoZSBzZXJ2ZXIgd2lsbCByZXN0YXJ0IGF1dG9tYXRpY2FsbHlcXG4nICtcbiAgICAgICAgICAnMi4gQ2hlY2sgYGdldF9zZXJ2ZXJfc3RhdHVzYCB0byB2ZXJpZnkgdGhlIG5ldyB2ZXJzaW9uXFxuJyArXG4gICAgICAgICAgJzMuIFRlc3QgeW91ciBwZXJzb25hcyB0byBlbnN1cmUgZXZlcnl0aGluZyB3b3Jrc1xcblxcbicgK1xuICAgICAgICAgICfwn5KhICoqVGlwOioqIElmIHlvdSBlbmNvdW50ZXIgaXNzdWVzLCB1c2UgYHJvbGxiYWNrX3VwZGF0ZSB0cnVlYCB0byByZXN0b3JlIHRoZSBwcmV2aW91cyB2ZXJzaW9uLidcbiAgICAgIH07XG4gICAgICBcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgbG9nZ2VyLmVycm9yKCdbVXBkYXRlTWFuYWdlcl0gbnBtIHVwZGF0ZSBmYWlsZWQ6JywgZXJyb3IpO1xuICAgICAgY29uc3QgZXJyb3JNZXNzYWdlID0gZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpO1xuICAgICAgXG4gICAgICByZXR1cm4ge1xuICAgICAgICB0ZXh0OiBwZXJzb25hSW5kaWNhdG9yICsgJ+KdjCAqKlVwZGF0ZSBGYWlsZWQqKlxcblxcbicgK1xuICAgICAgICAgICdFcnJvcjogJyArIGVycm9yTWVzc2FnZSArICdcXG5cXG4nICtcbiAgICAgICAgICAnKipUcm91Ymxlc2hvb3Rpbmc6KipcXG4nICtcbiAgICAgICAgICAnMS4gRW5zdXJlIHlvdSBoYXZlIHBlcm1pc3Npb24gdG8gdXBkYXRlIGdsb2JhbCBucG0gcGFja2FnZXNcXG4nICtcbiAgICAgICAgICAnMi4gVHJ5IHJ1bm5pbmcgd2l0aCBzdWRvIGlmIG9uIG1hY09TL0xpbnV4XFxuJyArXG4gICAgICAgICAgJzMuIENoZWNrIHlvdXIgaW50ZXJuZXQgY29ubmVjdGlvblxcbicgK1xuICAgICAgICAgICc0LiBWZXJpZnkgbnBtIHJlZ2lzdHJ5IGlzIGFjY2Vzc2libGVcXG5cXG4nICtcbiAgICAgICAgICAnKipNYW51YWwgVXBkYXRlOioqXFxuJyArXG4gICAgICAgICAgJ2BgYFxcbicgK1xuICAgICAgICAgICducG0gdXBkYXRlIC1nIEBkb2xsaG91c2VtY3AvbWNwLXNlcnZlclxcbicgK1xuICAgICAgICAgICdgYGAnXG4gICAgICB9O1xuICAgIH1cbiAgfVxuICBcbiAgLyoqXG4gICAqIFJvbGxiYWNrIG5wbSBpbnN0YWxsYXRpb25cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgcm9sbGJhY2tOcG1JbnN0YWxsYXRpb24oZm9yY2U6IGJvb2xlYW4sIHBlcnNvbmFJbmRpY2F0b3I6IHN0cmluZyA9ICcnKTogUHJvbWlzZTx7IHRleHQ6IHN0cmluZyB9PiB7XG4gICAgdHJ5IHtcbiAgICAgIGxvZ2dlci5pbmZvKCdbVXBkYXRlTWFuYWdlcl0gU3RhcnRpbmcgbnBtIHJvbGxiYWNrIHByb2Nlc3MnKTtcbiAgICAgIFxuICAgICAgLy8gR2V0IG5wbSBiYWNrdXAgbWFuaWZlc3QgZnJvbSBjb25maWd1cmF0aW9uXG4gICAgICBjb25zdCBjb25maWcgPSBVcGRhdGVDb25maWdNYW5hZ2VyLmdldEluc3RhbmNlKCk7XG4gICAgICBjb25zdCBucG1CYWNrdXBzRGlyID0gY29uZmlnLmdldE5wbUJhY2t1cERpcigpO1xuICAgICAgY29uc3QgbWFuaWZlc3RQYXRoID0gcGF0aC5qb2luKG5wbUJhY2t1cHNEaXIsICdtYW5pZmVzdC5qc29uJyk7XG4gICAgICBcbiAgICAgIGxldCBtYW5pZmVzdDtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IGNvbnRlbnQgPSBhd2FpdCBmcy5yZWFkRmlsZShtYW5pZmVzdFBhdGgsICd1dGYtOCcpO1xuICAgICAgICBtYW5pZmVzdCA9IEpTT04ucGFyc2UoY29udGVudCk7XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIHRleHQ6IHBlcnNvbmFJbmRpY2F0b3IgKyAn4p2MICoqTm8gTlBNIEJhY2t1cHMgRm91bmQqKlxcblxcbicgK1xuICAgICAgICAgICAgJ1RoZXJlIGFyZSBubyBucG0gYmFja3VwcyBhdmFpbGFibGUgdG8gcmVzdG9yZS5cXG5cXG4nICtcbiAgICAgICAgICAgICdCYWNrdXBzIGFyZSBjcmVhdGVkIGF1dG9tYXRpY2FsbHkgd2hlbiB5b3UgcnVuIGB1cGRhdGVfc2VydmVyIHRydWVgIHdpdGggbnBtIGluc3RhbGxhdGlvbnMuJ1xuICAgICAgICB9O1xuICAgICAgfVxuICAgICAgXG4gICAgICBpZiAoIW1hbmlmZXN0LmJhY2t1cHMgfHwgbWFuaWZlc3QuYmFja3Vwcy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICB0ZXh0OiBwZXJzb25hSW5kaWNhdG9yICsgJ+KdjCAqKk5vIE5QTSBCYWNrdXBzIEZvdW5kKipcXG5cXG4nICtcbiAgICAgICAgICAgICdUaGUgYmFja3VwIG1hbmlmZXN0IGlzIGVtcHR5LlxcblxcbicgK1xuICAgICAgICAgICAgJ0JhY2t1cHMgYXJlIGNyZWF0ZWQgYXV0b21hdGljYWxseSB3aGVuIHlvdSBydW4gYHVwZGF0ZV9zZXJ2ZXIgdHJ1ZWAuJ1xuICAgICAgICB9O1xuICAgICAgfVxuICAgICAgXG4gICAgICAvLyBHZXQgbGF0ZXN0IGJhY2t1cFxuICAgICAgY29uc3QgbGF0ZXN0QmFja3VwID0gbWFuaWZlc3QuYmFja3Vwc1swXTtcbiAgICAgIFxuICAgICAgLy8gQ2hlY2sgaWYgcm9sbGJhY2sgaXMgbmVlZGVkXG4gICAgICBpZiAoIWZvcmNlKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgLy8gVGVzdCBpZiB0aGUgc2VydmVyIGlzIHdvcmtpbmdcbiAgICAgICAgICBhd2FpdCB0aGlzLnZlcnNpb25NYW5hZ2VyLmdldEN1cnJlbnRWZXJzaW9uKCk7XG4gICAgICAgICAgXG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHRleHQ6IHBlcnNvbmFJbmRpY2F0b3IgKyAn4pqg77iPICoqUm9sbGJhY2sgQ29uZmlybWF0aW9uIFJlcXVpcmVkKipcXG5cXG4nICtcbiAgICAgICAgICAgICAgJ1RoZSBzZXJ2ZXIgYXBwZWFycyB0byBiZSB3b3JraW5nIG5vcm1hbGx5LlxcblxcbicgK1xuICAgICAgICAgICAgICBgKipMYXRlc3QgQmFja3VwOioqICR7bGF0ZXN0QmFja3VwLnRpbWVzdGFtcH1cXG5gICtcbiAgICAgICAgICAgICAgYCoqQmFja3VwIFZlcnNpb246KiogJHtsYXRlc3RCYWNrdXAudmVyc2lvbiB8fCAnVW5rbm93bid9XFxuXFxuYCArXG4gICAgICAgICAgICAgICdUbyBmb3JjZSByb2xsYmFjayBhbnl3YXksIHVzZTogYHJvbGxiYWNrX3VwZGF0ZSB0cnVlYFxcblxcbicgK1xuICAgICAgICAgICAgICAn4pqg77iPICoqV2FybmluZzoqKiBUaGlzIHdpbGwgcmVzdG9yZSB0aGUgbnBtIHBhY2thZ2UgdG8gdGhlIGJhY2t1cCBzdGF0ZS4nXG4gICAgICAgICAgfTtcbiAgICAgICAgfSBjYXRjaCB7XG4gICAgICAgICAgLy8gU2VydmVyIGlzIGJyb2tlbiwgcHJvY2VlZCB3aXRoIHJvbGxiYWNrXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIFxuICAgICAgLy8gR2V0IG5wbSBnbG9iYWwgcGF0aFxuICAgICAgY29uc3QgbnBtR2xvYmFsUGF0aCA9IEluc3RhbGxhdGlvbkRldGVjdG9yLmdldE5wbUdsb2JhbFBhdGgoKTtcbiAgICAgIGlmICghbnBtR2xvYmFsUGF0aCkge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIHRleHQ6IHBlcnNvbmFJbmRpY2F0b3IgKyAn4p2MICoqUm9sbGJhY2sgRmFpbGVkKipcXG5cXG4nICtcbiAgICAgICAgICAgICdDb3VsZCBub3QgZGV0ZXJtaW5lIG5wbSBnbG9iYWwgaW5zdGFsbGF0aW9uIHBhdGguXFxuXFxuJyArXG4gICAgICAgICAgICAnUGxlYXNlIHJlaW5zdGFsbCBtYW51YWxseTpcXG4nICtcbiAgICAgICAgICAgICdgYGBcXG4nICtcbiAgICAgICAgICAgICducG0gaW5zdGFsbCAtZyBAZG9sbGhvdXNlbWNwL21jcC1zZXJ2ZXJAJyArIChsYXRlc3RCYWNrdXAudmVyc2lvbiB8fCAnbGF0ZXN0JykgKyAnXFxuJyArXG4gICAgICAgICAgICAnYGBgJ1xuICAgICAgICB9O1xuICAgICAgfVxuICAgICAgXG4gICAgICBsb2dnZXIuaW5mbyhgW1VwZGF0ZU1hbmFnZXJdIFJlc3RvcmluZyBucG0gYmFja3VwIGZyb206ICR7bGF0ZXN0QmFja3VwLnBhdGh9YCk7XG4gICAgICBcbiAgICAgIC8vIEZpcnN0IHZhbGlkYXRlIHRoYXQgdGhlIGJhY2t1cCBpcyByZXN0b3JhYmxlXG4gICAgICBjb25zdCBiYWNrdXBQYWNrYWdlUGF0aCA9IHBhdGguam9pbihsYXRlc3RCYWNrdXAucGF0aCwgJ3BhY2thZ2UnKTtcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IGZzLmFjY2VzcyhiYWNrdXBQYWNrYWdlUGF0aCk7XG4gICAgICAgIGNvbnN0IHBhY2thZ2VKc29uUGF0aCA9IHBhdGguam9pbihiYWNrdXBQYWNrYWdlUGF0aCwgJ3BhY2thZ2UuanNvbicpO1xuICAgICAgICBhd2FpdCBmcy5hY2Nlc3MocGFja2FnZUpzb25QYXRoKTtcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgdGV4dDogcGVyc29uYUluZGljYXRvciArICfinYwgKipCYWNrdXAgVmFsaWRhdGlvbiBGYWlsZWQqKlxcblxcbicgK1xuICAgICAgICAgICAgJ1RoZSBiYWNrdXAgYXBwZWFycyB0byBiZSBjb3JydXB0ZWQgb3IgaW5jb21wbGV0ZS5cXG5cXG4nICtcbiAgICAgICAgICAgICcqKkRldGFpbHM6KipcXG4nICtcbiAgICAgICAgICAgIGBCYWNrdXAgcGF0aDogJHtsYXRlc3RCYWNrdXAucGF0aH1cXG5gICtcbiAgICAgICAgICAgIGBFcnJvcjogJHtlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcil9XFxuXFxuYCArXG4gICAgICAgICAgICAnKipNYW51YWwgUmVjb3Zlcnk6KipcXG4nICtcbiAgICAgICAgICAgICdUcnkgYW5vdGhlciBiYWNrdXAgb3IgcmVpbnN0YWxsIG1hbnVhbGx5OlxcbicgK1xuICAgICAgICAgICAgJ2BgYGJhc2hcXG4nICtcbiAgICAgICAgICAgICducG0gaW5zdGFsbCAtZyBAZG9sbGhvdXNlbWNwL21jcC1zZXJ2ZXJAJyArIChsYXRlc3RCYWNrdXAudmVyc2lvbiB8fCAnMS40LjAnKSArICdcXG4nICtcbiAgICAgICAgICAgICdgYGAnXG4gICAgICAgIH07XG4gICAgICB9XG4gICAgICBcbiAgICAgIC8vIFVzZSB0cmFuc2FjdGlvbiBmb3IgYXRvbWljIG9wZXJhdGlvbnNcbiAgICAgIGNvbnN0IHRlbXBQYXRoID0gYCR7bnBtR2xvYmFsUGF0aH0udG1wLSR7RGF0ZS5ub3coKX1gO1xuICAgICAgY29uc3QgYmFja3VwUGF0aCA9IGAke25wbUdsb2JhbFBhdGh9LmJhY2t1cC0ke0RhdGUubm93KCl9YDtcbiAgICAgIGNvbnN0IHRyYW5zYWN0aW9uID0gRmlsZU9wZXJhdGlvbnMuY3JlYXRlVHJhbnNhY3Rpb24oKTtcbiAgICAgIFxuICAgICAgdHJ5IHtcbiAgICAgICAgLy8gU3RlcCAxOiBDb3B5IGJhY2t1cCB0byB0ZW1wb3JhcnkgbG9jYXRpb25cbiAgICAgICAgYXdhaXQgdHJhbnNhY3Rpb24uYWRkQ29weShiYWNrdXBQYWNrYWdlUGF0aCwgdGVtcFBhdGgpO1xuICAgICAgICBcbiAgICAgICAgLy8gU3RlcCAyOiBNb3ZlIGN1cnJlbnQgaW5zdGFsbGF0aW9uIHRvIGJhY2t1cCAoYXRvbWljKVxuICAgICAgICBhd2FpdCB0cmFuc2FjdGlvbi5hZGRNb3ZlKG5wbUdsb2JhbFBhdGgsIGJhY2t1cFBhdGgpO1xuICAgICAgICBcbiAgICAgICAgLy8gU3RlcCAzOiBNb3ZlIHRlbXAgdG8gZmluYWwgbG9jYXRpb24gKGF0b21pYylcbiAgICAgICAgYXdhaXQgdHJhbnNhY3Rpb24uYWRkTW92ZSh0ZW1wUGF0aCwgbnBtR2xvYmFsUGF0aCk7XG4gICAgICAgIFxuICAgICAgICAvLyBBbGwgb3BlcmF0aW9ucyBzdWNjZXNzZnVsLCBjb21taXQgdGhlIHRyYW5zYWN0aW9uXG4gICAgICAgIHRyYW5zYWN0aW9uLmNvbW1pdCgpO1xuICAgICAgICBcbiAgICAgICAgLy8gU3RlcCA0OiBDbGVhbiB1cCBvbGQgYmFja3VwIChub3QgcGFydCBvZiB0cmFuc2FjdGlvbilcbiAgICAgICAgYXdhaXQgZnMucm0oYmFja3VwUGF0aCwgeyByZWN1cnNpdmU6IHRydWUsIGZvcmNlOiB0cnVlIH0pLmNhdGNoKCgpID0+IHtcbiAgICAgICAgICBsb2dnZXIud2FybihgW1VwZGF0ZU1hbmFnZXJdIEZhaWxlZCB0byBjbGVhbnVwIGJhY2t1cCBhdDogJHtiYWNrdXBQYXRofWApO1xuICAgICAgICB9KTtcbiAgICAgIH0gY2F0Y2ggKHJvbGxiYWNrRXJyb3IpIHtcbiAgICAgICAgbG9nZ2VyLmVycm9yKCdbVXBkYXRlTWFuYWdlcl0gUm9sbGJhY2sgb3BlcmF0aW9uIGZhaWxlZCwgYXR0ZW1wdGluZyByZWNvdmVyeTonLCByb2xsYmFja0Vycm9yKTtcbiAgICAgICAgXG4gICAgICAgIC8vIFJvbGxiYWNrIGFsbCBvcGVyYXRpb25zXG4gICAgICAgIGlmICh0cmFuc2FjdGlvbi5oYXNPcGVyYXRpb25zKCkpIHtcbiAgICAgICAgICBhd2FpdCB0cmFuc2FjdGlvbi5yb2xsYmFjaygpO1xuICAgICAgICB9XG4gICAgICAgIFxuICAgICAgICAvLyBBZGRpdGlvbmFsIHJlY292ZXJ5IGF0dGVtcHRcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAvLyBDaGVjayBpZiBucG0gcGF0aCBleGlzdHMgYW5kIGlzIGFjY2Vzc2libGVcbiAgICAgICAgICBhd2FpdCBmcy5hY2Nlc3MobnBtR2xvYmFsUGF0aCk7XG4gICAgICAgICAgbG9nZ2VyLmluZm8oJ1tVcGRhdGVNYW5hZ2VyXSBOUE0gaW5zdGFsbGF0aW9uIGFwcGVhcnMgaW50YWN0IGFmdGVyIHJvbGxiYWNrJyk7XG4gICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgIC8vIFRyeSB0byByZXN0b3JlIGZyb20gYmFja3VwIGlmIG1haW4gcGF0aCBpcyBtaXNzaW5nXG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGF3YWl0IGZzLnJlbmFtZShiYWNrdXBQYXRoLCBucG1HbG9iYWxQYXRoKTtcbiAgICAgICAgICAgIGxvZ2dlci5pbmZvKCdbVXBkYXRlTWFuYWdlcl0gUmVzdG9yZWQgZnJvbSBiYWNrdXAgcGF0aCcpO1xuICAgICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgICAgbG9nZ2VyLmVycm9yKCdbVXBkYXRlTWFuYWdlcl0gQ29tcGxldGUgcm9sbGJhY2sgZmFpbHVyZSAtIG1hbnVhbCBpbnRlcnZlbnRpb24gcmVxdWlyZWQnKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgXG4gICAgICAgIHRocm93IHJvbGxiYWNrRXJyb3I7XG4gICAgICB9XG4gICAgICBcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHRleHQ6IHBlcnNvbmFJbmRpY2F0b3IgKyAn4pyFICoqTlBNIFJvbGxiYWNrIENvbXBsZXRlISoqXFxuXFxuJyArXG4gICAgICAgICAgYFJlc3RvcmVkIGZyb20gYmFja3VwOiAke2xhdGVzdEJhY2t1cC50aW1lc3RhbXB9XFxuYCArXG4gICAgICAgICAgYEJhY2t1cCB2ZXJzaW9uOiAke2xhdGVzdEJhY2t1cC52ZXJzaW9uIHx8ICdVbmtub3duJ31cXG5cXG5gICtcbiAgICAgICAgICAnKipXaGF0IHdhcyByZXN0b3JlZDoqKlxcbicgK1xuICAgICAgICAgICfigKIgTlBNIHBhY2thZ2UgZmlsZXNcXG4nICtcbiAgICAgICAgICAn4oCiIEFsbCBkZXBlbmRlbmNpZXNcXG5cXG4nICtcbiAgICAgICAgICAnKipOZXh0IFN0ZXBzOioqXFxuJyArXG4gICAgICAgICAgJzEuIFRoZSBzZXJ2ZXIgd2lsbCByZXN0YXJ0IGF1dG9tYXRpY2FsbHlcXG4nICtcbiAgICAgICAgICAnMi4gQ2hlY2sgYGdldF9zZXJ2ZXJfc3RhdHVzYCB0byB2ZXJpZnkgdGhlIHZlcnNpb25cXG4nICtcbiAgICAgICAgICAnMy4gVGVzdCB5b3VyIHBlcnNvbmFzIHRvIGVuc3VyZSBldmVyeXRoaW5nIHdvcmtzJ1xuICAgICAgfTtcbiAgICAgIFxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBsb2dnZXIuZXJyb3IoJ1tVcGRhdGVNYW5hZ2VyXSBucG0gcm9sbGJhY2sgZmFpbGVkOicsIGVycm9yKTtcbiAgICAgIGNvbnN0IGVycm9yTWVzc2FnZSA9IGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKTtcbiAgICAgIFxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgdGV4dDogcGVyc29uYUluZGljYXRvciArICfinYwgKipOUE0gUm9sbGJhY2sgRmFpbGVkKipcXG5cXG4nICtcbiAgICAgICAgICAnRXJyb3I6ICcgKyBlcnJvck1lc3NhZ2UgKyAnXFxuXFxuJyArXG4gICAgICAgICAgJyoqTWFudWFsIFJlY292ZXJ5OioqXFxuJyArXG4gICAgICAgICAgJzEuIENoZWNrIHRoZSBiYWNrdXBzIGRpcmVjdG9yeTogfi8uZG9sbGhvdXNlL2JhY2t1cHMvbnBtL1xcbicgK1xuICAgICAgICAgICcyLiBSZWluc3RhbGwgYSBzcGVjaWZpYyB2ZXJzaW9uOlxcbicgK1xuICAgICAgICAgICcgICBgYGBcXG4nICtcbiAgICAgICAgICAnICAgbnBtIGluc3RhbGwgLWcgQGRvbGxob3VzZW1jcC9tY3Atc2VydmVyQDEuNC4wXFxuJyArXG4gICAgICAgICAgJyAgIGBgYFxcbicgK1xuICAgICAgICAgICczLiBDb250YWN0IHN1cHBvcnQgaWYgaXNzdWVzIHBlcnNpc3QnXG4gICAgICB9O1xuICAgIH1cbiAgfVxuICBcbiAgLyoqXG4gICAqIENvcHkgZGlyZWN0b3J5IHJlY3Vyc2l2ZWx5IHdpdGggcHJvZ3Jlc3MgcmVwb3J0aW5nXG4gICAqIEBkZXByZWNhdGVkIFVzZSBGaWxlT3BlcmF0aW9ucy5jb3B5RGlyZWN0b3J5IGluc3RlYWRcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgY29weURpcmVjdG9yeShzcmM6IHN0cmluZywgZGVzdDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgYXdhaXQgRmlsZU9wZXJhdGlvbnMuY29weURpcmVjdG9yeShzcmMsIGRlc3QsIHtcbiAgICAgIGV4Y2x1ZGVQYXR0ZXJuczogWycuZ2l0JywgJ25vZGVfbW9kdWxlcyddLFxuICAgICAgb25Qcm9ncmVzczogKGNvcGllZCwgdG90YWwsIGZpbGUpID0+IHtcbiAgICAgICAgbG9nZ2VyLmRlYnVnKGBbVXBkYXRlTWFuYWdlcl0gQ29weWluZyBmaWxlczogJHtjb3BpZWR9LyR7dG90YWx9IC0gJHtwYXRoLmJhc2VuYW1lKGZpbGUpfWApO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG4gIFxuICAvKipcbiAgICogQ29udmVydCBucG0gaW5zdGFsbGF0aW9uIHRvIGdpdCBpbnN0YWxsYXRpb25cbiAgICovXG4gIGFzeW5jIGNvbnZlcnRUb0dpdEluc3RhbGxhdGlvbih0YXJnZXREaXI/OiBzdHJpbmcsIGNvbmZpcm06IGJvb2xlYW4gPSBmYWxzZSwgcGVyc29uYUluZGljYXRvcjogc3RyaW5nID0gJycpOiBQcm9taXNlPHsgdGV4dDogc3RyaW5nIH0+IHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgaW5zdGFsbGF0aW9uVHlwZSA9IEluc3RhbGxhdGlvbkRldGVjdG9yLmdldEluc3RhbGxhdGlvblR5cGUoKTtcbiAgICAgIFxuICAgICAgaWYgKGluc3RhbGxhdGlvblR5cGUgPT09ICdnaXQnKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgdGV4dDogcGVyc29uYUluZGljYXRvciArICfimqDvuI8gKipBbHJlYWR5IGEgR2l0IEluc3RhbGxhdGlvbioqXFxuXFxuJyArXG4gICAgICAgICAgICAnVGhpcyBzZXJ2ZXIgaXMgYWxyZWFkeSBydW5uaW5nIGZyb20gYSBnaXQgaW5zdGFsbGF0aW9uLlxcbicgK1xuICAgICAgICAgICAgJ05vIGNvbnZlcnNpb24gbmVlZGVkLidcbiAgICAgICAgfTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgaWYgKGluc3RhbGxhdGlvblR5cGUgPT09ICd1bmtub3duJykge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIHRleHQ6IHBlcnNvbmFJbmRpY2F0b3IgKyAn4p2MICoqSW5zdGFsbGF0aW9uIFR5cGUgVW5rbm93bioqXFxuXFxuJyArXG4gICAgICAgICAgICAnQ2Fubm90IGRldGVybWluZSB0aGUgY3VycmVudCBpbnN0YWxsYXRpb24gdHlwZS5cXG4nICtcbiAgICAgICAgICAgICdQbGVhc2UgY2hlY2sgeW91ciBpbnN0YWxsYXRpb24gbWFudWFsbHkuJ1xuICAgICAgICB9O1xuICAgICAgfVxuICAgICAgXG4gICAgICAvLyBEZWZhdWx0IHRhcmdldCBkaXJlY3RvcnlcbiAgICAgIGNvbnN0IGRlZmF1bHRUYXJnZXREaXIgPSBwYXRoLmpvaW4ocHJvY2Vzcy5lbnYuSE9NRSB8fCAnJywgJy5kb2xsaG91c2UnLCAnbWNwLXNlcnZlci1naXQnKTtcbiAgICAgIGNvbnN0IGdpdFRhcmdldERpciA9IHRhcmdldERpciB8fCBkZWZhdWx0VGFyZ2V0RGlyO1xuICAgICAgXG4gICAgICBpZiAoIWNvbmZpcm0pIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICB0ZXh0OiBwZXJzb25hSW5kaWNhdG9yICsgJ/CflIQgKipDb252ZXJ0IHRvIEdpdCBJbnN0YWxsYXRpb24qKlxcblxcbicgK1xuICAgICAgICAgICAgJyoqVGhpcyB3aWxsOioqXFxuJyArXG4gICAgICAgICAgICBgMS4gQ2xvbmUgRG9sbGhvdXNlTUNQIHRvOiAke2dpdFRhcmdldERpcn1cXG5gICtcbiAgICAgICAgICAgICcyLiBDb3B5IHlvdXIgcG9ydGZvbGlvIGFuZCBzZXR0aW5nc1xcbicgK1xuICAgICAgICAgICAgJzMuIEJ1aWxkIHRoZSBUeXBlU2NyaXB0IGNvZGVcXG4nICtcbiAgICAgICAgICAgICc0LiBQcm92aWRlIENsYXVkZSBEZXNrdG9wIGNvbmZpZ3VyYXRpb25cXG5cXG4nICtcbiAgICAgICAgICAgICcqKkJlbmVmaXRzIG9mIEdpdCBJbnN0YWxsYXRpb246KipcXG4nICtcbiAgICAgICAgICAgICfigKIgRnVsbCBjb250cm9sIG92ZXIgdXBkYXRlc1xcbicgK1xuICAgICAgICAgICAgJ+KAoiBBY2Nlc3MgdG8gZGV2ZWxvcG1lbnQgYnJhbmNoZXNcXG4nICtcbiAgICAgICAgICAgICfigKIgQWJpbGl0eSB0byBjb250cmlidXRlIGNoYW5nZXNcXG4nICtcbiAgICAgICAgICAgICfigKIgUm9sbGJhY2sgdG8gYW55IGNvbW1pdFxcblxcbicgK1xuICAgICAgICAgICAgJyoqVG8gcHJvY2VlZDoqKlxcbicgK1xuICAgICAgICAgICAgJ2Bjb252ZXJ0X3RvX2dpdF9pbnN0YWxsYXRpb24gdHJ1ZWBcXG5cXG4nICtcbiAgICAgICAgICAgICcqKlRvIHVzZSBjdXN0b20gZGlyZWN0b3J5OioqXFxuJyArXG4gICAgICAgICAgICAnYGNvbnZlcnRfdG9fZ2l0X2luc3RhbGxhdGlvbiBcIi9wYXRoL3RvL2RpclwiIHRydWVgJ1xuICAgICAgICB9O1xuICAgICAgfVxuICAgICAgXG4gICAgICBsb2dnZXIuaW5mbyhgW1VwZGF0ZU1hbmFnZXJdIFN0YXJ0aW5nIGNvbnZlcnNpb24gdG8gZ2l0IGluc3RhbGxhdGlvbiBhdDogJHtnaXRUYXJnZXREaXJ9YCk7XG4gICAgICBcbiAgICAgIC8vIENoZWNrIGlmIHRhcmdldCBkaXJlY3RvcnkgYWxyZWFkeSBleGlzdHNcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IGZzLmFjY2VzcyhnaXRUYXJnZXREaXIpO1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIHRleHQ6IHBlcnNvbmFJbmRpY2F0b3IgKyAn4p2MICoqVGFyZ2V0IERpcmVjdG9yeSBFeGlzdHMqKlxcblxcbicgK1xuICAgICAgICAgICAgYFRoZSBkaXJlY3RvcnkgJHtnaXRUYXJnZXREaXJ9IGFscmVhZHkgZXhpc3RzLlxcblxcbmAgK1xuICAgICAgICAgICAgJyoqT3B0aW9uczoqKlxcbicgK1xuICAgICAgICAgICAgJzEuIFJlbW92ZSB0aGUgZXhpc3RpbmcgZGlyZWN0b3J5IGZpcnN0XFxuJyArXG4gICAgICAgICAgICAnMi4gQ2hvb3NlIGEgZGlmZmVyZW50IHRhcmdldCBkaXJlY3RvcnlcXG4nICtcbiAgICAgICAgICAgICczLiBVc2UgdGhlIGV4aXN0aW5nIGdpdCBpbnN0YWxsYXRpb24nXG4gICAgICAgIH07XG4gICAgICB9IGNhdGNoIHtcbiAgICAgICAgLy8gRGlyZWN0b3J5IGRvZXNuJ3QgZXhpc3QsIGdvb2QgdG8gcHJvY2VlZFxuICAgICAgfVxuICAgICAgXG4gICAgICAvLyBQcm9ncmVzcyBtZXNzYWdlIGJ1aWxkZXJcbiAgICAgIGxldCBwcm9ncmVzc1N0ZXBzID0gcGVyc29uYUluZGljYXRvciArICfwn5SEICoqR2l0IEluc3RhbGxhdGlvbiBQcm9ncmVzcyoqXFxuXFxuJztcbiAgICAgIHByb2dyZXNzU3RlcHMgKz0gJyoqU3RlcHM6KipcXG4nO1xuICAgICAgcHJvZ3Jlc3NTdGVwcyArPSAn4o+zIENsb25pbmcgcmVwb3NpdG9yeS4uLlxcbic7XG4gICAgICBwcm9ncmVzc1N0ZXBzICs9ICfij7MgSW5zdGFsbGluZyBkZXBlbmRlbmNpZXMuLi5cXG4nO1xuICAgICAgcHJvZ3Jlc3NTdGVwcyArPSAn4o+zIEJ1aWxkaW5nIFR5cGVTY3JpcHQuLi5cXG4nO1xuICAgICAgcHJvZ3Jlc3NTdGVwcyArPSAn4o+zIFNldHRpbmcgdXAgY29uZmlndXJhdGlvbi4uLlxcblxcbic7XG4gICAgICBwcm9ncmVzc1N0ZXBzICs9ICcqKkN1cnJlbnQgU3RlcDoqKiBDbG9uaW5nIHJlcG9zaXRvcnlcXG4nO1xuICAgICAgcHJvZ3Jlc3NTdGVwcyArPSAnYGBgXFxuJztcbiAgICAgIHByb2dyZXNzU3RlcHMgKz0gYFRhcmdldDogJHtnaXRUYXJnZXREaXJ9XFxuYDtcbiAgICAgIHByb2dyZXNzU3RlcHMgKz0gJ1RoaXMgbWF5IHRha2UgYSBmZXcgbWludXRlcyBkZXBlbmRpbmcgb24geW91ciBjb25uZWN0aW9uLi4uXFxuJztcbiAgICAgIHByb2dyZXNzU3RlcHMgKz0gJ2BgYFxcbic7XG4gICAgICBcbiAgICAgIC8vIEdldCBjb25maWd1cmF0aW9uXG4gICAgICBjb25zdCBjb25maWcgPSBVcGRhdGVDb25maWdNYW5hZ2VyLmdldEluc3RhbmNlKCk7XG4gICAgICBcbiAgICAgIC8vIFN0ZXAgMTogQ2xvbmUgdGhlIHJlcG9zaXRvcnlcbiAgICAgIGxvZ2dlci5pbmZvKCdbVXBkYXRlTWFuYWdlcl0gQ2xvbmluZyByZXBvc2l0b3J5Li4uJyk7XG4gICAgICBcbiAgICAgIC8vIFNFQ1VSSVRZIEZJWDogVmFsaWRhdGUgZ2l0VGFyZ2V0RGlyIHRvIHByZXZlbnQgY29tbWFuZCBpbmplY3Rpb25cbiAgICAgIC8vIFByZXZpb3VzbHk6IGdpdFRhcmdldERpciBwYXNzZWQgZGlyZWN0bHkgdG8gZ2l0IGNsb25lIGNvbW1hbmRcbiAgICAgIC8vIE5vdzogUmVqZWN0IHBhdGhzIHN0YXJ0aW5nIHdpdGggJy0tJyB0byBwcmV2ZW50IGdpdCBvcHRpb24gaW5qZWN0aW9uXG4gICAgICBpZiAoZ2l0VGFyZ2V0RGlyLnN0YXJ0c1dpdGgoJy0tJykpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIHRhcmdldCBkaXJlY3Rvcnk6IGNhbm5vdCBzdGFydCB3aXRoIGdpdCBvcHRpb25zJyk7XG4gICAgICB9XG4gICAgICBcbiAgICAgIGF3YWl0IHNhZmVFeGVjKCdnaXQnLCBbJ2Nsb25lJywgJ2h0dHBzOi8vZ2l0aHViLmNvbS9Eb2xsaG91c2VNQ1AvbWNwLXNlcnZlci5naXQnLCBnaXRUYXJnZXREaXJdLCB7XG4gICAgICAgIHRpbWVvdXQ6IGNvbmZpZy5nZXRHaXRDbG9uZVRpbWVvdXQoKVxuICAgICAgfSk7XG4gICAgICBcbiAgICAgIHByb2dyZXNzU3RlcHMgPSBwcm9ncmVzc1N0ZXBzLnJlcGxhY2UoJ+KPsyBDbG9uaW5nIHJlcG9zaXRvcnkuLi4nLCAn4pyFIFJlcG9zaXRvcnkgY2xvbmVkJyk7XG4gICAgICBwcm9ncmVzc1N0ZXBzID0gcHJvZ3Jlc3NTdGVwcy5yZXBsYWNlKCcqKkN1cnJlbnQgU3RlcDoqKiBDbG9uaW5nIHJlcG9zaXRvcnknLCAnKipDdXJyZW50IFN0ZXA6KiogSW5zdGFsbGluZyBkZXBlbmRlbmNpZXMnKTtcbiAgICAgIFxuICAgICAgLy8gU3RlcCAyOiBJbnN0YWxsIGRlcGVuZGVuY2llc1xuICAgICAgbG9nZ2VyLmluZm8oJ1tVcGRhdGVNYW5hZ2VyXSBJbnN0YWxsaW5nIGRlcGVuZGVuY2llcy4uLicpO1xuICAgICAgYXdhaXQgc2FmZUV4ZWMoJ25wbScsIFsnaW5zdGFsbCddLCB7XG4gICAgICAgIGN3ZDogZ2l0VGFyZ2V0RGlyLFxuICAgICAgICB0aW1lb3V0OiBjb25maWcuZ2V0TnBtSW5zdGFsbFRpbWVvdXQoKVxuICAgICAgfSk7XG4gICAgICBcbiAgICAgIHByb2dyZXNzU3RlcHMgPSBwcm9ncmVzc1N0ZXBzLnJlcGxhY2UoJ+KPsyBJbnN0YWxsaW5nIGRlcGVuZGVuY2llcy4uLicsICfinIUgRGVwZW5kZW5jaWVzIGluc3RhbGxlZCcpO1xuICAgICAgcHJvZ3Jlc3NTdGVwcyA9IHByb2dyZXNzU3RlcHMucmVwbGFjZSgnKipDdXJyZW50IFN0ZXA6KiogSW5zdGFsbGluZyBkZXBlbmRlbmNpZXMnLCAnKipDdXJyZW50IFN0ZXA6KiogQnVpbGRpbmcgVHlwZVNjcmlwdCcpO1xuICAgICAgXG4gICAgICAvLyBTdGVwIDM6IEJ1aWxkIFR5cGVTY3JpcHRcbiAgICAgIGxvZ2dlci5pbmZvKCdbVXBkYXRlTWFuYWdlcl0gQnVpbGRpbmcgVHlwZVNjcmlwdC4uLicpO1xuICAgICAgYXdhaXQgc2FmZUV4ZWMoJ25wbScsIFsncnVuJywgJ2J1aWxkJ10sIHtcbiAgICAgICAgY3dkOiBnaXRUYXJnZXREaXIsXG4gICAgICAgIHRpbWVvdXQ6IGNvbmZpZy5nZXRCdWlsZFRpbWVvdXQoKVxuICAgICAgfSk7XG4gICAgICBcbiAgICAgIHByb2dyZXNzU3RlcHMgPSBwcm9ncmVzc1N0ZXBzLnJlcGxhY2UoJ+KPsyBCdWlsZGluZyBUeXBlU2NyaXB0Li4uJywgJ+KchSBUeXBlU2NyaXB0IGJ1aWx0Jyk7XG4gICAgICBwcm9ncmVzc1N0ZXBzID0gcHJvZ3Jlc3NTdGVwcy5yZXBsYWNlKCcqKkN1cnJlbnQgU3RlcDoqKiBCdWlsZGluZyBUeXBlU2NyaXB0JywgJyoqQ3VycmVudCBTdGVwOioqIENvbmZpZ3VyYXRpb24nKTtcbiAgICAgIFxuICAgICAgLy8gU3RlcCA0OiBDb3B5IHBvcnRmb2xpb1xuICAgICAgY29uc3QgcG9ydGZvbGlvU291cmNlID0gcGF0aC5qb2luKHByb2Nlc3MuZW52LkhPTUUgfHwgJycsICcuZG9sbGhvdXNlJywgJ3BvcnRmb2xpbycpO1xuICAgICAgY29uc3QgcG9ydGZvbGlvVGFyZ2V0ID0gcGF0aC5qb2luKHByb2Nlc3MuZW52LkhPTUUgfHwgJycsICcuZG9sbGhvdXNlJywgJ3BvcnRmb2xpbycpO1xuICAgICAgXG4gICAgICBsb2dnZXIuaW5mbygnW1VwZGF0ZU1hbmFnZXJdIFBvcnRmb2xpbyB3aWxsIHJlbWFpbiBhdDogJyArIHBvcnRmb2xpb1RhcmdldCk7XG4gICAgICBcbiAgICAgIC8vIFN0ZXAgNTogR2VuZXJhdGUgQ2xhdWRlIERlc2t0b3AgY29uZmlnXG4gICAgICBjb25zdCBjb25maWdQYXRoID0gcGF0aC5qb2luKGdpdFRhcmdldERpciwgJ2Rpc3QnLCAnaW5kZXguanMnKTtcbiAgICAgIGNvbnN0IGNsYXVkZUNvbmZpZyA9IHtcbiAgICAgICAgbWNwU2VydmVyczoge1xuICAgICAgICAgIGRvbGxob3VzZW1jcDoge1xuICAgICAgICAgICAgY29tbWFuZDogJ25vZGUnLFxuICAgICAgICAgICAgYXJnczogW2NvbmZpZ1BhdGhdXG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9O1xuICAgICAgXG4gICAgICByZXR1cm4ge1xuICAgICAgICB0ZXh0OiBwZXJzb25hSW5kaWNhdG9yICsgJ+KchSAqKkdpdCBJbnN0YWxsYXRpb24gQ29tcGxldGUhKipcXG5cXG4nICtcbiAgICAgICAgICBgKipJbnN0YWxsYXRpb24gTG9jYXRpb246KiogJHtnaXRUYXJnZXREaXJ9XFxuXFxuYCArXG4gICAgICAgICAgJyoqTmV4dCBTdGVwczoqKlxcblxcbicgK1xuICAgICAgICAgICcxLiAqKlVwZGF0ZSBDbGF1ZGUgRGVza3RvcCBjb25maWd1cmF0aW9uOioqXFxuJyArXG4gICAgICAgICAgJyAgIGBgYGpzb25cXG4nICtcbiAgICAgICAgICBKU09OLnN0cmluZ2lmeShjbGF1ZGVDb25maWcsIG51bGwsIDIpICsgJ1xcbicgK1xuICAgICAgICAgICcgICBgYGBcXG5cXG4nICtcbiAgICAgICAgICAnMi4gKipSZXN0YXJ0IENsYXVkZSBEZXNrdG9wKipcXG5cXG4nICtcbiAgICAgICAgICAnMy4gKipWZXJpZnkgaW5zdGFsbGF0aW9uOioqXFxuJyArXG4gICAgICAgICAgJyAgIEFmdGVyIHJlc3RhcnQsIHJ1biBgZ2V0X3NlcnZlcl9zdGF0dXNgIHRvIGNvbmZpcm1cXG5cXG4nICtcbiAgICAgICAgICAnKipZb3VyIHBvcnRmb2xpbyByZW1haW5zIGF0OioqXFxuJyArXG4gICAgICAgICAgYCAgICR7cG9ydGZvbGlvVGFyZ2V0fVxcblxcbmAgK1xuICAgICAgICAgICcqKlRvIHVwZGF0ZSBpbiB0aGUgZnV0dXJlOioqXFxuJyArXG4gICAgICAgICAgJyAgIGBgYGJhc2hcXG4nICtcbiAgICAgICAgICBgICAgY2QgJHtnaXRUYXJnZXREaXJ9XFxuYCArXG4gICAgICAgICAgJyAgIGdpdCBwdWxsXFxuJyArXG4gICAgICAgICAgJyAgIG5wbSBpbnN0YWxsXFxuJyArXG4gICAgICAgICAgJyAgIG5wbSBydW4gYnVpbGRcXG4nICtcbiAgICAgICAgICAnICAgYGBgXFxuXFxuJyArXG4gICAgICAgICAgJ/CfkqEgKipUaXA6KiogWW91IGNhbiBub3cgdXNlIGB1cGRhdGVfc2VydmVyYCB0byB1cGRhdGUgdmlhIGdpdCEnXG4gICAgICB9O1xuICAgICAgXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGxvZ2dlci5lcnJvcignW1VwZGF0ZU1hbmFnZXJdIEdpdCBjb252ZXJzaW9uIGZhaWxlZDonLCBlcnJvcik7XG4gICAgICBjb25zdCBlcnJvck1lc3NhZ2UgPSBlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcik7XG4gICAgICBcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHRleHQ6IHBlcnNvbmFJbmRpY2F0b3IgKyAn4p2MICoqQ29udmVyc2lvbiBGYWlsZWQqKlxcblxcbicgK1xuICAgICAgICAgICdFcnJvcjogJyArIGVycm9yTWVzc2FnZSArICdcXG5cXG4nICtcbiAgICAgICAgICAnKipUcm91Ymxlc2hvb3Rpbmc6KipcXG4nICtcbiAgICAgICAgICAnMS4gRW5zdXJlIGdpdCBpcyBpbnN0YWxsZWRcXG4nICtcbiAgICAgICAgICAnMi4gQ2hlY2sgaW50ZXJuZXQgY29ubmVjdGlvblxcbicgK1xuICAgICAgICAgICczLiBWZXJpZnkgeW91IGhhdmUgd3JpdGUgcGVybWlzc2lvbnNcXG4nICtcbiAgICAgICAgICAnNC4gVHJ5IGEgZGlmZmVyZW50IHRhcmdldCBkaXJlY3RvcnknXG4gICAgICB9O1xuICAgIH1cbiAgfVxuICBcbiAgLyoqXG4gICAqIEdldCBjdXJyZW50IHNlcnZlciBzdGF0dXNcbiAgICovXG4gIGFzeW5jIGdldFNlcnZlclN0YXR1cyhwZXJzb25hSW5kaWNhdG9yOiBzdHJpbmcgPSAnJyk6IFByb21pc2U8eyB0ZXh0OiBzdHJpbmcgfT4ge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBjdXJyZW50VmVyc2lvbiA9IGF3YWl0IHRoaXMudmVyc2lvbk1hbmFnZXIuZ2V0Q3VycmVudFZlcnNpb24oKTtcbiAgICAgIGNvbnN0IGRlcGVuZGVuY2llcyA9IGF3YWl0IHRoaXMuZGVwZW5kZW5jeUNoZWNrZXIuY2hlY2tEZXBlbmRlbmNpZXMoKTtcbiAgICAgIGNvbnN0IGJhY2t1cHMgPSBhd2FpdCB0aGlzLmJhY2t1cE1hbmFnZXIubGlzdEJhY2t1cHMoKTtcbiAgICAgIGNvbnN0IHJhdGVMaW1pdFN0YXR1cyA9IHRoaXMudXBkYXRlQ2hlY2tlci5nZXRSYXRlTGltaXRTdGF0dXMoKTtcbiAgICAgIFxuICAgICAgLy8gR2V0IGluc3RhbGxhdGlvbiB0eXBlXG4gICAgICBjb25zdCBpbnN0YWxsYXRpb25UeXBlID0gSW5zdGFsbGF0aW9uRGV0ZWN0b3IuZ2V0SW5zdGFsbGF0aW9uVHlwZSgpO1xuICAgICAgY29uc3QgaW5zdGFsbGF0aW9uRGVzYyA9IEluc3RhbGxhdGlvbkRldGVjdG9yLmdldEluc3RhbGxhdGlvbkRlc2NyaXB0aW9uKCk7XG4gICAgICBcbiAgICAgIC8vIEdldCBnaXQgc3RhdHVzIChvbmx5IGZvciBnaXQgaW5zdGFsbGF0aW9ucylcbiAgICAgIGxldCBnaXRTdGF0dXMgPSAnTi9BJztcbiAgICAgIGxldCBnaXRCcmFuY2ggPSAnTi9BJztcbiAgICAgIGxldCBsYXN0Q29tbWl0ID0gJ04vQSc7XG4gICAgICBcbiAgICAgIGlmIChpbnN0YWxsYXRpb25UeXBlID09PSAnZ2l0Jykge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGNvbnN0IHsgc3Rkb3V0OiBicmFuY2hPdXRwdXQgfSA9IGF3YWl0IHNhZmVFeGVjKCdnaXQnLCBbJ2JyYW5jaCcsICctLXNob3ctY3VycmVudCddLCB7IGN3ZDogdGhpcy5yb290RGlyIH0pO1xuICAgICAgICAgIGdpdEJyYW5jaCA9IGJyYW5jaE91dHB1dC50cmltKCkgfHwgJ2RldGFjaGVkJztcbiAgICAgICAgICBcbiAgICAgICAgICBjb25zdCB7IHN0ZG91dDogc3RhdHVzT3V0cHV0IH0gPSBhd2FpdCBzYWZlRXhlYygnZ2l0JywgWydzdGF0dXMnLCAnLS1wb3JjZWxhaW4nXSwgeyBjd2Q6IHRoaXMucm9vdERpciB9KTtcbiAgICAgICAgICBnaXRTdGF0dXMgPSBzdGF0dXNPdXRwdXQudHJpbSgpID8gJ01vZGlmaWVkJyA6ICdDbGVhbic7XG4gICAgICAgICAgXG4gICAgICAgICAgY29uc3QgeyBzdGRvdXQ6IGxvZ091dHB1dCB9ID0gYXdhaXQgc2FmZUV4ZWMoJ2dpdCcsIFsnbG9nJywgJy0xJywgJy0tb25lbGluZSddLCB7IGN3ZDogdGhpcy5yb290RGlyIH0pO1xuICAgICAgICAgIGxhc3RDb21taXQgPSBsb2dPdXRwdXQudHJpbSgpO1xuICAgICAgICB9IGNhdGNoIHtcbiAgICAgICAgICAvLyBHaXQgY29tbWFuZHMgZmFpbGVkLCB1c2UgZGVmYXVsdHNcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgXG4gICAgICBjb25zdCBzdGF0dXNQYXJ0cyA9IFtcbiAgICAgICAgcGVyc29uYUluZGljYXRvciArICfwn5OKICoqRG9sbGhvdXNlTUNQIFNlcnZlciBTdGF0dXMqKlxcblxcbicsXG4gICAgICAgICcqKlZlcnNpb24gSW5mb3JtYXRpb246KipcXG4nLFxuICAgICAgICBg4oCiIEN1cnJlbnQgVmVyc2lvbjogJHtjdXJyZW50VmVyc2lvbn1cXG5gLFxuICAgICAgICBg4oCiIEluc3RhbGxhdGlvbiBUeXBlOiAke2luc3RhbGxhdGlvblR5cGV9ICgke2luc3RhbGxhdGlvbkRlc2N9KVxcbmAsXG4gICAgICAgIGDigKIgR2l0IEJyYW5jaDogJHtnaXRCcmFuY2h9XFxuYCxcbiAgICAgICAgYOKAoiBHaXQgU3RhdHVzOiAke2dpdFN0YXR1c31cXG5gLFxuICAgICAgICBg4oCiIExhc3QgQ29tbWl0OiAke2xhc3RDb21taXR9XFxuXFxuYCxcbiAgICAgICAgJyoqRGVwZW5kZW5jaWVzOioqXFxuJyxcbiAgICAgICAgdGhpcy5kZXBlbmRlbmN5Q2hlY2tlci5mb3JtYXREZXBlbmRlbmN5U3RhdHVzKGRlcGVuZGVuY2llcyksXG4gICAgICAgICdcXG5cXG4qKkJhY2t1cHM6KipcXG4nLFxuICAgICAgICBg4oCiIFRvdGFsIEJhY2t1cHM6ICR7YmFja3Vwcy5sZW5ndGh9XFxuYFxuICAgICAgXTtcbiAgICAgIFxuICAgICAgaWYgKGJhY2t1cHMubGVuZ3RoID4gMCkge1xuICAgICAgICBzdGF0dXNQYXJ0cy5wdXNoKGDigKIgTGF0ZXN0IEJhY2t1cDogJHtiYWNrdXBzWzBdLnRpbWVzdGFtcH0gKHYke2JhY2t1cHNbMF0udmVyc2lvbiB8fCAndW5rbm93bid9KVxcbmApO1xuICAgICAgICBzdGF0dXNQYXJ0cy5wdXNoKGDigKIgT2xkZXN0IEJhY2t1cDogJHtiYWNrdXBzW2JhY2t1cHMubGVuZ3RoIC0gMV0udGltZXN0YW1wfVxcbmApO1xuICAgICAgfVxuICAgICAgXG4gICAgICBzdGF0dXNQYXJ0cy5wdXNoKFxuICAgICAgICAnXFxuKipSYXRlIExpbWl0IFN0YXR1czoqKlxcbicsXG4gICAgICAgIGDigKIgVXBkYXRlIENoZWNrcyBSZW1haW5pbmc6ICR7cmF0ZUxpbWl0U3RhdHVzLnJlbWFpbmluZ1JlcXVlc3RzfS8xMCBwZXIgaG91clxcbmAsXG4gICAgICAgIGDigKIgUmF0ZSBMaW1pdCBSZXNldHM6ICR7cmF0ZUxpbWl0U3RhdHVzLnJlc2V0VGltZS50b0xvY2FsZVRpbWVTdHJpbmcoKX1cXG5gXG4gICAgICApO1xuICAgICAgXG4gICAgICBpZiAoIXJhdGVMaW1pdFN0YXR1cy5hbGxvd2VkICYmIHJhdGVMaW1pdFN0YXR1cy53YWl0VGltZVNlY29uZHMpIHtcbiAgICAgICAgc3RhdHVzUGFydHMucHVzaChg4oCiIOKPsyBXYWl0ICR7cmF0ZUxpbWl0U3RhdHVzLndhaXRUaW1lU2Vjb25kc30gc2Vjb25kcyBiZWZvcmUgbmV4dCBjaGVja1xcbmApO1xuICAgICAgfVxuICAgICAgXG4gICAgICBzdGF0dXNQYXJ0cy5wdXNoKFxuICAgICAgICAnXFxuKipBdmFpbGFibGUgQ29tbWFuZHM6KipcXG4nLFxuICAgICAgICAn4oCiIGBjaGVja19mb3JfdXBkYXRlc2AgLSBDaGVjayBmb3IgbmV3IHZlcnNpb25zXFxuJyxcbiAgICAgICAgJ+KAoiBgdXBkYXRlX3NlcnZlciB0cnVlYCAtIFVwZGF0ZSB0byBsYXRlc3QgdmVyc2lvblxcbicsXG4gICAgICAgICfigKIgYHJvbGxiYWNrX3VwZGF0ZSB0cnVlYCAtIFJlc3RvcmUgZnJvbSBiYWNrdXBcXG4nXG4gICAgICApO1xuICAgICAgXG4gICAgICByZXR1cm4geyB0ZXh0OiBzdGF0dXNQYXJ0cy5qb2luKCcnKSB9O1xuICAgICAgXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGNvbnN0IGVycm9yTWVzc2FnZSA9IGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKTtcbiAgICAgIFxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgdGV4dDogcGVyc29uYUluZGljYXRvciArICfinYwgKipTdGF0dXMgQ2hlY2sgRmFpbGVkKipcXG5cXG4nICtcbiAgICAgICAgICAnRXJyb3I6ICcgKyBlcnJvck1lc3NhZ2UgKyAnXFxuXFxuJyArXG4gICAgICAgICAgJ1RoZSBzZXJ2ZXIgbWF5IGJlIGluIGFuIGluY29uc2lzdGVudCBzdGF0ZS5cXG4nICtcbiAgICAgICAgICAnVHJ5IHJ1bm5pbmcgYHVwZGF0ZV9zZXJ2ZXIgdHJ1ZWAgdG8gZml4IGlzc3Vlcy4nXG4gICAgICB9O1xuICAgIH1cbiAgfVxufSJdfQ==