@dollhousemcp/mcp-server 1.5.1 → 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 (274) hide show
  1. package/CHANGELOG.md +90 -0
  2. package/README.md +497 -110
  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 +65 -0
  41. package/dist/cache/CollectionCache.d.ts.map +1 -0
  42. package/dist/cache/CollectionCache.js +172 -0
  43. package/dist/cache/CollectionIndexCache.d.ts +77 -0
  44. package/dist/cache/CollectionIndexCache.d.ts.map +1 -0
  45. package/dist/cache/CollectionIndexCache.js +349 -0
  46. package/dist/cache/LRUCache.d.ts +93 -0
  47. package/dist/cache/LRUCache.d.ts.map +1 -0
  48. package/dist/cache/LRUCache.js +299 -0
  49. package/dist/cache/index.d.ts +2 -0
  50. package/dist/cache/index.d.ts.map +1 -1
  51. package/dist/cache/index.js +3 -1
  52. package/dist/collection/CollectionBrowser.d.ts +44 -1
  53. package/dist/collection/CollectionBrowser.d.ts.map +1 -1
  54. package/dist/collection/CollectionBrowser.js +260 -28
  55. package/dist/collection/CollectionIndexManager.d.ts +151 -0
  56. package/dist/collection/CollectionIndexManager.d.ts.map +1 -0
  57. package/dist/collection/CollectionIndexManager.js +499 -0
  58. package/dist/collection/CollectionSearch.d.ts +75 -1
  59. package/dist/collection/CollectionSearch.d.ts.map +1 -1
  60. package/dist/collection/CollectionSearch.js +435 -6
  61. package/dist/collection/CollectionSeeder.d.ts +36 -0
  62. package/dist/collection/CollectionSeeder.d.ts.map +1 -0
  63. package/dist/collection/CollectionSeeder.js +267 -0
  64. package/dist/collection/ElementInstaller.d.ts +31 -0
  65. package/dist/collection/ElementInstaller.d.ts.map +1 -1
  66. package/dist/collection/ElementInstaller.js +77 -15
  67. package/dist/collection/PersonaSubmitter.d.ts +48 -1
  68. package/dist/collection/PersonaSubmitter.d.ts.map +1 -1
  69. package/dist/collection/PersonaSubmitter.js +170 -34
  70. package/dist/collection/index.d.ts +2 -0
  71. package/dist/collection/index.d.ts.map +1 -1
  72. package/dist/collection/index.js +3 -1
  73. package/dist/config/ConfigManager.d.ts +78 -0
  74. package/dist/config/ConfigManager.d.ts.map +1 -0
  75. package/dist/config/ConfigManager.js +216 -0
  76. package/dist/config/element-types.d.ts +135 -0
  77. package/dist/config/element-types.d.ts.map +1 -0
  78. package/dist/config/element-types.js +108 -0
  79. package/dist/config/index.d.ts +2 -0
  80. package/dist/config/index.d.ts.map +1 -1
  81. package/dist/config/index.js +3 -1
  82. package/dist/config/portfolio-constants.d.ts +83 -0
  83. package/dist/config/portfolio-constants.d.ts.map +1 -0
  84. package/dist/config/portfolio-constants.js +99 -0
  85. package/dist/elements/BaseElement.d.ts +14 -2
  86. package/dist/elements/BaseElement.d.ts.map +1 -1
  87. package/dist/elements/BaseElement.js +88 -6
  88. package/dist/elements/agents/Agent.d.ts +10 -1
  89. package/dist/elements/agents/Agent.d.ts.map +1 -1
  90. package/dist/elements/agents/Agent.js +66 -19
  91. package/dist/elements/agents/AgentManager.d.ts +2 -0
  92. package/dist/elements/agents/AgentManager.d.ts.map +1 -1
  93. package/dist/elements/agents/AgentManager.js +12 -10
  94. package/dist/elements/skills/Skill.d.ts +10 -1
  95. package/dist/elements/skills/Skill.d.ts.map +1 -1
  96. package/dist/elements/skills/Skill.js +40 -3
  97. package/dist/elements/skills/SkillManager.d.ts +1 -0
  98. package/dist/elements/skills/SkillManager.d.ts.map +1 -1
  99. package/dist/elements/skills/SkillManager.js +10 -4
  100. package/dist/elements/templates/Template.d.ts +10 -1
  101. package/dist/elements/templates/Template.d.ts.map +1 -1
  102. package/dist/elements/templates/Template.js +35 -18
  103. package/dist/elements/templates/TemplateManager.d.ts +1 -1
  104. package/dist/elements/templates/TemplateManager.d.ts.map +1 -1
  105. package/dist/elements/templates/TemplateManager.js +6 -5
  106. package/dist/generated/version.d.ts +2 -2
  107. package/dist/generated/version.js +3 -3
  108. package/dist/index.barrel.d.ts +1 -2
  109. package/dist/index.barrel.d.ts.map +1 -1
  110. package/dist/index.barrel.js +2 -4
  111. package/dist/index.d.ts +154 -25
  112. package/dist/index.d.ts.map +1 -1
  113. package/dist/index.js +1951 -264
  114. package/dist/persona/PersonaElement.d.ts +10 -0
  115. package/dist/persona/PersonaElement.d.ts.map +1 -1
  116. package/dist/persona/PersonaElement.js +55 -32
  117. package/dist/persona/PersonaElementManager.d.ts.map +1 -1
  118. package/dist/persona/PersonaElementManager.js +13 -11
  119. package/dist/persona/PersonaLoader.d.ts.map +1 -1
  120. package/dist/persona/PersonaLoader.js +8 -2
  121. package/dist/persona/export-import/PersonaImporter.d.ts.map +1 -1
  122. package/dist/persona/export-import/PersonaImporter.js +24 -5
  123. package/dist/persona/export-import/PersonaSharer.d.ts +21 -0
  124. package/dist/persona/export-import/PersonaSharer.d.ts.map +1 -1
  125. package/dist/persona/export-import/PersonaSharer.js +198 -22
  126. package/dist/portfolio/DefaultElementProvider.d.ts +90 -0
  127. package/dist/portfolio/DefaultElementProvider.d.ts.map +1 -1
  128. package/dist/portfolio/DefaultElementProvider.js +499 -7
  129. package/dist/portfolio/GitHubPortfolioIndexer.d.ts +129 -0
  130. package/dist/portfolio/GitHubPortfolioIndexer.d.ts.map +1 -0
  131. package/dist/portfolio/GitHubPortfolioIndexer.js +475 -0
  132. package/dist/portfolio/MigrationManager.d.ts.map +1 -1
  133. package/dist/portfolio/MigrationManager.js +136 -3
  134. package/dist/portfolio/PortfolioIndexManager.d.ts +130 -0
  135. package/dist/portfolio/PortfolioIndexManager.d.ts.map +1 -0
  136. package/dist/portfolio/PortfolioIndexManager.js +478 -0
  137. package/dist/portfolio/PortfolioManager.d.ts +5 -0
  138. package/dist/portfolio/PortfolioManager.d.ts.map +1 -1
  139. package/dist/portfolio/PortfolioManager.js +61 -20
  140. package/dist/portfolio/PortfolioRepoManager.d.ts +75 -0
  141. package/dist/portfolio/PortfolioRepoManager.d.ts.map +1 -0
  142. package/dist/portfolio/PortfolioRepoManager.js +337 -0
  143. package/dist/portfolio/UnifiedIndexManager.d.ts +388 -0
  144. package/dist/portfolio/UnifiedIndexManager.d.ts.map +1 -0
  145. package/dist/portfolio/UnifiedIndexManager.js +1434 -0
  146. package/dist/portfolio/index.d.ts +15 -0
  147. package/dist/portfolio/index.d.ts.map +1 -0
  148. package/dist/portfolio/index.js +15 -0
  149. package/dist/portfolio/types.d.ts +7 -0
  150. package/dist/portfolio/types.d.ts.map +1 -1
  151. package/dist/portfolio/types.js +6 -1
  152. package/dist/security/InputValidator.d.ts.map +1 -1
  153. package/dist/security/InputValidator.js +50 -48
  154. package/dist/security/audit/SecurityAuditor.d.ts.map +1 -1
  155. package/dist/security/audit/SecurityAuditor.js +17 -9
  156. package/dist/security/audit/config/suppressions.d.ts.map +1 -1
  157. package/dist/security/audit/config/suppressions.js +19 -3
  158. package/dist/security/contentValidator.d.ts +2 -0
  159. package/dist/security/contentValidator.d.ts.map +1 -1
  160. package/dist/security/contentValidator.js +115 -4
  161. package/dist/security/secureYamlParser.d.ts +1 -0
  162. package/dist/security/secureYamlParser.d.ts.map +1 -1
  163. package/dist/security/secureYamlParser.js +29 -7
  164. package/dist/security/securityMonitor.d.ts +1 -1
  165. package/dist/security/securityMonitor.d.ts.map +1 -1
  166. package/dist/security/securityMonitor.js +1 -1
  167. package/dist/security/tokenManager.d.ts +1 -1
  168. package/dist/security/tokenManager.d.ts.map +1 -1
  169. package/dist/security/tokenManager.js +30 -10
  170. package/dist/server/ServerSetup.d.ts +22 -2
  171. package/dist/server/ServerSetup.d.ts.map +1 -1
  172. package/dist/server/ServerSetup.js +77 -12
  173. package/dist/server/tools/AuthTools.d.ts.map +1 -1
  174. package/dist/server/tools/AuthTools.js +33 -1
  175. package/dist/server/tools/BuildInfoTools.d.ts +25 -0
  176. package/dist/server/tools/BuildInfoTools.d.ts.map +1 -0
  177. package/dist/server/tools/BuildInfoTools.js +36 -0
  178. package/dist/server/tools/CollectionTools.d.ts.map +1 -1
  179. package/dist/server/tools/CollectionTools.js +62 -42
  180. package/dist/server/tools/ConfigTools.d.ts.map +1 -1
  181. package/dist/server/tools/ConfigTools.js +29 -1
  182. package/dist/server/tools/PersonaTools.d.ts +4 -2
  183. package/dist/server/tools/PersonaTools.d.ts.map +1 -1
  184. package/dist/server/tools/PersonaTools.js +5 -152
  185. package/dist/server/tools/PortfolioTools.d.ts +12 -0
  186. package/dist/server/tools/PortfolioTools.d.ts.map +1 -0
  187. package/dist/server/tools/PortfolioTools.js +221 -0
  188. package/dist/server/tools/index.d.ts +3 -1
  189. package/dist/server/tools/index.d.ts.map +1 -1
  190. package/dist/server/tools/index.js +4 -2
  191. package/dist/server/types.d.ts +41 -5
  192. package/dist/server/types.d.ts.map +1 -1
  193. package/dist/server/types.js +1 -1
  194. package/dist/services/BuildInfoService.d.ts +84 -0
  195. package/dist/services/BuildInfoService.d.ts.map +1 -0
  196. package/dist/services/BuildInfoService.js +271 -0
  197. package/dist/tools/portfolio/PortfolioElementAdapter.d.ts +54 -0
  198. package/dist/tools/portfolio/PortfolioElementAdapter.d.ts.map +1 -0
  199. package/dist/tools/portfolio/PortfolioElementAdapter.js +229 -0
  200. package/dist/tools/portfolio/submitToPortfolioTool.d.ts +164 -0
  201. package/dist/tools/portfolio/submitToPortfolioTool.d.ts.map +1 -0
  202. package/dist/tools/portfolio/submitToPortfolioTool.js +1523 -0
  203. package/dist/tools/portfolio/types.d.ts +41 -0
  204. package/dist/tools/portfolio/types.d.ts.map +1 -0
  205. package/dist/tools/portfolio/types.js +15 -0
  206. package/dist/types/collection.d.ts +51 -0
  207. package/dist/types/collection.d.ts.map +1 -1
  208. package/dist/types/collection.js +1 -1
  209. package/dist/utils/EarlyTerminationSearch.d.ts +41 -0
  210. package/dist/utils/EarlyTerminationSearch.d.ts.map +1 -0
  211. package/dist/utils/EarlyTerminationSearch.js +164 -0
  212. package/dist/utils/ErrorHandler.d.ts +86 -0
  213. package/dist/utils/ErrorHandler.d.ts.map +1 -0
  214. package/dist/utils/ErrorHandler.js +201 -0
  215. package/dist/utils/FileDiscoveryUtil.d.ts +53 -0
  216. package/dist/utils/FileDiscoveryUtil.d.ts.map +1 -0
  217. package/dist/utils/FileDiscoveryUtil.js +169 -0
  218. package/dist/utils/GitHubRateLimiter.d.ts +88 -0
  219. package/dist/utils/GitHubRateLimiter.d.ts.map +1 -0
  220. package/dist/utils/GitHubRateLimiter.js +315 -0
  221. package/dist/utils/PerformanceMonitor.d.ts +134 -0
  222. package/dist/utils/PerformanceMonitor.d.ts.map +1 -0
  223. package/dist/utils/PerformanceMonitor.js +347 -0
  224. package/dist/utils/RateLimiter.d.ts.map +1 -0
  225. package/dist/utils/RateLimiter.js +172 -0
  226. package/dist/utils/SecureDownloader.d.ts +241 -0
  227. package/dist/utils/SecureDownloader.d.ts.map +1 -0
  228. package/dist/utils/SecureDownloader.js +759 -0
  229. package/dist/utils/ToolCache.d.ts +82 -0
  230. package/dist/utils/ToolCache.d.ts.map +1 -0
  231. package/dist/utils/ToolCache.js +196 -0
  232. package/dist/utils/errorCodes.d.ts +136 -0
  233. package/dist/utils/errorCodes.d.ts.map +1 -0
  234. package/dist/utils/errorCodes.js +87 -0
  235. package/dist/utils/index.d.ts +3 -0
  236. package/dist/utils/index.d.ts.map +1 -1
  237. package/dist/utils/index.js +4 -1
  238. package/dist/utils/installation.d.ts +1 -1
  239. package/dist/utils/installation.d.ts.map +1 -1
  240. package/dist/utils/installation.js +9 -8
  241. package/dist/utils/searchUtils.d.ts +54 -0
  242. package/dist/utils/searchUtils.d.ts.map +1 -0
  243. package/dist/utils/searchUtils.js +118 -0
  244. package/package.json +17 -7
  245. package/dist/config/updateConfig.d.ts +0 -84
  246. package/dist/config/updateConfig.d.ts.map +0 -1
  247. package/dist/config/updateConfig.js +0 -148
  248. package/dist/server/tools/UpdateTools.d.ts +0 -10
  249. package/dist/server/tools/UpdateTools.d.ts.map +0 -1
  250. package/dist/server/tools/UpdateTools.js +0 -85
  251. package/dist/update/BackupManager.d.ts +0 -63
  252. package/dist/update/BackupManager.d.ts.map +0 -1
  253. package/dist/update/BackupManager.js +0 -370
  254. package/dist/update/DependencyChecker.d.ts +0 -41
  255. package/dist/update/DependencyChecker.d.ts.map +0 -1
  256. package/dist/update/DependencyChecker.js +0 -132
  257. package/dist/update/RateLimiter.d.ts.map +0 -1
  258. package/dist/update/RateLimiter.js +0 -172
  259. package/dist/update/SignatureVerifier.d.ts +0 -71
  260. package/dist/update/SignatureVerifier.d.ts.map +0 -1
  261. package/dist/update/SignatureVerifier.js +0 -214
  262. package/dist/update/UpdateChecker.d.ts +0 -132
  263. package/dist/update/UpdateChecker.d.ts.map +0 -1
  264. package/dist/update/UpdateChecker.js +0 -506
  265. package/dist/update/UpdateManager.d.ts +0 -60
  266. package/dist/update/UpdateManager.d.ts.map +0 -1
  267. package/dist/update/UpdateManager.js +0 -730
  268. package/dist/update/VersionManager.d.ts +0 -31
  269. package/dist/update/VersionManager.d.ts.map +0 -1
  270. package/dist/update/VersionManager.js +0 -181
  271. package/dist/update/index.d.ts +0 -9
  272. package/dist/update/index.d.ts.map +0 -1
  273. package/dist/update/index.js +0 -9
  274. /package/dist/{update → utils}/RateLimiter.d.ts +0 -0
@@ -0,0 +1,349 @@
1
+ /**
2
+ * Smart cache for collection index with conditional fetching and performance optimization
3
+ */
4
+ import * as fs from 'fs/promises';
5
+ import * as path from 'path';
6
+ import { logger } from '../utils/logger.js';
7
+ import { SecurityMonitor } from '../security/securityMonitor.js';
8
+ import { CacheFactory } from './LRUCache.js';
9
+ import { PerformanceMonitor } from '../utils/PerformanceMonitor.js';
10
+ export class CollectionIndexCache {
11
+ cache = null;
12
+ TTL = 15 * 60 * 1000; // 15 minutes in milliseconds
13
+ INDEX_URL = 'https://raw.githubusercontent.com/DollhouseMCP/collection/main/public/collection-index.json';
14
+ cacheDir;
15
+ cacheFile;
16
+ githubClient;
17
+ performanceMonitor;
18
+ memoryCache;
19
+ fetchPromise = null; // Prevent concurrent fetches
20
+ constructor(githubClient, baseDir = process.cwd()) {
21
+ this.githubClient = githubClient;
22
+ this.cacheDir = path.join(baseDir, '.dollhousemcp', 'cache');
23
+ this.cacheFile = path.join(this.cacheDir, 'collection-index-cache.json');
24
+ this.performanceMonitor = PerformanceMonitor.getInstance();
25
+ // Initialize memory cache for frequently accessed data
26
+ this.memoryCache = CacheFactory.createAPICache({
27
+ maxSize: 50,
28
+ maxMemoryMB: 10,
29
+ ttlMs: 5 * 60 * 1000, // 5 minutes
30
+ onEviction: (key, value) => {
31
+ logger.debug('Collection memory cache eviction', { key });
32
+ }
33
+ });
34
+ }
35
+ /**
36
+ * Get the collection index with performance optimization and lazy loading
37
+ */
38
+ async getIndex(lazyLoad = false) {
39
+ const startTime = Date.now();
40
+ const memoryBefore = process.memoryUsage().heapUsed;
41
+ try {
42
+ // Check memory cache first for fastest access
43
+ const memoryCached = this.memoryCache.get('collection-index');
44
+ if (memoryCached && this.isValid()) {
45
+ logger.debug('Using memory cached collection index');
46
+ this.recordPerformanceMetrics(startTime, memoryBefore, 'memory-hit');
47
+ return memoryCached;
48
+ }
49
+ // Check if we have valid disk cached data
50
+ if (this.isValid()) {
51
+ logger.debug('Using valid disk cached collection index');
52
+ const result = this.cache.data;
53
+ this.memoryCache.set('collection-index', result);
54
+ this.recordPerformanceMetrics(startTime, memoryBefore, 'disk-hit');
55
+ return result;
56
+ }
57
+ // Prevent concurrent fetches
58
+ if (this.fetchPromise) {
59
+ logger.debug('Waiting for ongoing collection index fetch');
60
+ return await this.fetchPromise;
61
+ }
62
+ // Lazy loading: Only fetch if not in lazy mode or absolutely necessary
63
+ if (lazyLoad && this.cache?.data) {
64
+ logger.debug('Using stale cache in lazy load mode');
65
+ this.recordPerformanceMetrics(startTime, memoryBefore, 'lazy-stale');
66
+ return this.cache.data;
67
+ }
68
+ // Create fetch promise to prevent concurrent requests
69
+ this.fetchPromise = this.fetchFreshWithFallback();
70
+ try {
71
+ const result = await this.fetchPromise;
72
+ this.memoryCache.set('collection-index', result);
73
+ this.recordPerformanceMetrics(startTime, memoryBefore, 'fresh-fetch');
74
+ return result;
75
+ }
76
+ finally {
77
+ this.fetchPromise = null;
78
+ }
79
+ }
80
+ catch (error) {
81
+ logger.error('Failed to get collection index:', error);
82
+ // Try loading from persistent cache as last resort
83
+ const persistentCache = await this.loadFromDisk();
84
+ if (persistentCache) {
85
+ logger.debug('Using persistent cache as last resort');
86
+ this.cache = persistentCache;
87
+ const result = persistentCache.data;
88
+ this.memoryCache.set('collection-index', result);
89
+ this.recordPerformanceMetrics(startTime, memoryBefore, 'disk-fallback');
90
+ return result;
91
+ }
92
+ throw error;
93
+ }
94
+ }
95
+ /**
96
+ * Check if current cache is valid (within TTL)
97
+ */
98
+ isValid() {
99
+ if (!this.cache) {
100
+ return false;
101
+ }
102
+ const age = Date.now() - this.cache.fetchedAt.getTime();
103
+ return age < this.TTL;
104
+ }
105
+ /**
106
+ * Fetch fresh index from GitHub with conditional requests
107
+ */
108
+ async fetchFresh() {
109
+ try {
110
+ // Build headers for conditional request
111
+ const headers = {
112
+ 'Accept': 'application/json',
113
+ 'User-Agent': 'DollhouseMCP/1.0'
114
+ };
115
+ // Add conditional headers if we have cache
116
+ if (this.cache?.etag) {
117
+ headers['If-None-Match'] = this.cache.etag;
118
+ }
119
+ if (this.cache?.lastModified) {
120
+ headers['If-Modified-Since'] = this.cache.lastModified;
121
+ }
122
+ // Use fetch directly for better control over conditional requests
123
+ const response = await fetch(this.INDEX_URL, { headers });
124
+ // 304 Not Modified - use cached data
125
+ if (response.status === 304) {
126
+ if (this.cache) {
127
+ // Update timestamp to extend cache validity
128
+ this.cache.fetchedAt = new Date();
129
+ await this.saveToDisk(this.cache);
130
+ logger.debug('Collection index not modified - refreshed cache timestamp');
131
+ return this.cache.data;
132
+ }
133
+ }
134
+ if (!response.ok) {
135
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
136
+ }
137
+ const indexData = await response.json();
138
+ // Validate the index structure
139
+ if (!this.validateIndexStructure(indexData)) {
140
+ throw new Error('Invalid collection index structure received');
141
+ }
142
+ // Create new cache entry
143
+ const newCache = {
144
+ data: indexData,
145
+ fetchedAt: new Date(),
146
+ etag: response.headers.get('etag') || undefined,
147
+ lastModified: response.headers.get('last-modified') || undefined
148
+ };
149
+ this.cache = newCache;
150
+ // Save to persistent cache in background
151
+ this.saveToDisk(newCache).catch(error => {
152
+ logger.debug('Failed to save index cache to disk:', error);
153
+ });
154
+ logger.debug(`Fresh collection index fetched with ${indexData.total_elements} elements`);
155
+ return indexData;
156
+ }
157
+ catch (error) {
158
+ logger.debug('Failed to fetch fresh collection index:', error);
159
+ return null;
160
+ }
161
+ }
162
+ /**
163
+ * Validate the structure of a collection index
164
+ */
165
+ validateIndexStructure(index) {
166
+ return (index &&
167
+ typeof index === 'object' &&
168
+ typeof index.version === 'string' &&
169
+ typeof index.generated === 'string' &&
170
+ typeof index.total_elements === 'number' &&
171
+ index.index &&
172
+ typeof index.index === 'object' &&
173
+ index.metadata &&
174
+ typeof index.metadata === 'object');
175
+ }
176
+ /**
177
+ * Save cache to persistent storage
178
+ */
179
+ async saveToDisk(cache) {
180
+ try {
181
+ await this.ensureCacheDir();
182
+ const cacheData = {
183
+ ...cache,
184
+ fetchedAt: cache.fetchedAt.toISOString() // Serialize date
185
+ };
186
+ const data = JSON.stringify(cacheData, null, 2);
187
+ await fs.writeFile(this.cacheFile, data, 'utf8');
188
+ logger.debug('Collection index cache saved to disk');
189
+ }
190
+ catch (error) {
191
+ logger.debug('Failed to save collection index cache:', error);
192
+ // Don't throw - cache persistence failures shouldn't break functionality
193
+ }
194
+ }
195
+ /**
196
+ * Load cache from persistent storage
197
+ */
198
+ async loadFromDisk() {
199
+ try {
200
+ // Basic security check for path traversal
201
+ if (this.cacheFile.includes('..') || this.cacheFile.includes('\0')) {
202
+ SecurityMonitor.logSecurityEvent({
203
+ type: 'PATH_TRAVERSAL_ATTEMPT',
204
+ severity: 'HIGH',
205
+ source: 'CollectionIndexCache.loadFromDisk',
206
+ details: `Potential path traversal attempt detected: ${this.cacheFile.substring(0, 100)}`
207
+ });
208
+ return null;
209
+ }
210
+ const data = await fs.readFile(this.cacheFile, 'utf8');
211
+ const cacheData = JSON.parse(data);
212
+ return {
213
+ ...cacheData,
214
+ fetchedAt: new Date(cacheData.fetchedAt) // Deserialize date
215
+ };
216
+ }
217
+ catch (error) {
218
+ if (error.code !== 'ENOENT') {
219
+ logger.debug('Failed to load collection index cache from disk:', error);
220
+ }
221
+ return null;
222
+ }
223
+ }
224
+ /**
225
+ * Ensure cache directory exists
226
+ */
227
+ async ensureCacheDir() {
228
+ try {
229
+ await fs.mkdir(this.cacheDir, { recursive: true });
230
+ }
231
+ catch (error) {
232
+ logger.error('Failed to create cache directory:', error);
233
+ throw error;
234
+ }
235
+ }
236
+ /**
237
+ * Clear all cache data with performance monitoring
238
+ */
239
+ async clearCache() {
240
+ const startTime = Date.now();
241
+ this.cache = null;
242
+ this.memoryCache.clear();
243
+ // Cancel any ongoing fetch
244
+ this.fetchPromise = null;
245
+ try {
246
+ await fs.unlink(this.cacheFile);
247
+ logger.debug('Collection index cache cleared from disk');
248
+ }
249
+ catch (error) {
250
+ if (error.code !== 'ENOENT') {
251
+ logger.debug('Failed to clear collection index cache:', error);
252
+ }
253
+ }
254
+ logger.debug('Collection cache cleared', {
255
+ duration: Date.now() - startTime,
256
+ memoryFreed: this.memoryCache.getMemoryUsageMB()
257
+ });
258
+ }
259
+ /**
260
+ * Get comprehensive cache statistics for debugging and monitoring
261
+ */
262
+ getCacheStats() {
263
+ if (!this.cache) {
264
+ return {
265
+ isValid: false,
266
+ age: 0,
267
+ hasCache: false,
268
+ elements: 0,
269
+ memoryCache: this.memoryCache.getStats(),
270
+ performanceMetrics: null
271
+ };
272
+ }
273
+ const age = Date.now() - this.cache.fetchedAt.getTime();
274
+ return {
275
+ isValid: this.isValid(),
276
+ age,
277
+ hasCache: true,
278
+ elements: this.cache.data.total_elements,
279
+ memoryCache: this.memoryCache.getStats(),
280
+ performanceMetrics: {
281
+ cacheHitRate: this.calculateCacheHitRate(),
282
+ averageAccessTime: this.calculateAverageAccessTime()
283
+ }
284
+ };
285
+ }
286
+ // =====================================================
287
+ // PRIVATE HELPER METHODS FOR PERFORMANCE
288
+ // =====================================================
289
+ /**
290
+ * Fetch fresh index with comprehensive fallback strategy
291
+ */
292
+ async fetchFreshWithFallback() {
293
+ try {
294
+ // Try to fetch fresh index
295
+ const freshIndex = await this.fetchFresh();
296
+ if (freshIndex) {
297
+ logger.debug('Collection index fetched successfully');
298
+ return freshIndex;
299
+ }
300
+ }
301
+ catch (error) {
302
+ logger.warn('Fresh fetch failed, trying fallback', {
303
+ error: error instanceof Error ? error.message : String(error)
304
+ });
305
+ }
306
+ // Fall back to stale cache if available
307
+ if (this.cache?.data) {
308
+ logger.debug('Using stale cached collection index as fallback');
309
+ return this.cache.data;
310
+ }
311
+ throw new Error('No collection index available - fresh fetch failed and no cache exists');
312
+ }
313
+ /**
314
+ * Record performance metrics for cache operations
315
+ */
316
+ recordPerformanceMetrics(startTime, memoryBefore, operation) {
317
+ const duration = Date.now() - startTime;
318
+ const memoryAfter = process.memoryUsage().heapUsed;
319
+ logger.debug('Collection cache operation completed', {
320
+ operation,
321
+ duration,
322
+ memoryUsageMB: (memoryAfter - memoryBefore) / (1024 * 1024)
323
+ });
324
+ // Record cache performance metrics
325
+ this.performanceMonitor.recordCachePerformance('collectionIndex', {
326
+ hitRate: operation.includes('hit') ? 1 : 0,
327
+ avgHitTime: operation.includes('hit') ? duration : 0,
328
+ avgMissTime: operation.includes('hit') ? 0 : duration,
329
+ totalHits: operation.includes('hit') ? 1 : 0,
330
+ totalMisses: operation.includes('hit') ? 0 : 1,
331
+ evictions: 0
332
+ });
333
+ }
334
+ /**
335
+ * Calculate cache hit rate (placeholder for future implementation)
336
+ */
337
+ calculateCacheHitRate() {
338
+ // This would be implemented with actual metrics tracking
339
+ return this.memoryCache.getStats().hitRate;
340
+ }
341
+ /**
342
+ * Calculate average access time (placeholder for future implementation)
343
+ */
344
+ calculateAverageAccessTime() {
345
+ // This would be implemented with actual timing metrics
346
+ return 5; // Placeholder value
347
+ }
348
+ }
349
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ29sbGVjdGlvbkluZGV4Q2FjaGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY2FjaGUvQ29sbGVjdGlvbkluZGV4Q2FjaGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7O0dBRUc7QUFFSCxPQUFPLEtBQUssRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUNsQyxPQUFPLEtBQUssSUFBSSxNQUFNLE1BQU0sQ0FBQztBQUU3QixPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFFNUMsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBQ2pFLE9BQU8sRUFBWSxZQUFZLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDdkQsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFFcEUsTUFBTSxPQUFPLG9CQUFvQjtJQUN2QixLQUFLLEdBQXVCLElBQUksQ0FBQztJQUN4QixHQUFHLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUMsQ0FBQyw2QkFBNkI7SUFDbkQsU0FBUyxHQUFHLDZGQUE2RixDQUFDO0lBQ25ILFFBQVEsQ0FBUztJQUNqQixTQUFTLENBQVM7SUFDbEIsWUFBWSxDQUFlO0lBQzNCLGtCQUFrQixDQUFxQjtJQUN2QyxXQUFXLENBQWdCO0lBQzNCLFlBQVksR0FBb0MsSUFBSSxDQUFDLENBQUMsNkJBQTZCO0lBRTNGLFlBQVksWUFBMEIsRUFBRSxVQUFrQixPQUFPLENBQUMsR0FBRyxFQUFFO1FBQ3JFLElBQUksQ0FBQyxZQUFZLEdBQUcsWUFBWSxDQUFDO1FBQ2pDLElBQUksQ0FBQyxRQUFRLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsZUFBZSxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQzdELElBQUksQ0FBQyxTQUFTLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLDZCQUE2QixDQUFDLENBQUM7UUFDekUsSUFBSSxDQUFDLGtCQUFrQixHQUFHLGtCQUFrQixDQUFDLFdBQVcsRUFBRSxDQUFDO1FBRTNELHVEQUF1RDtRQUN2RCxJQUFJLENBQUMsV0FBVyxHQUFHLFlBQVksQ0FBQyxjQUFjLENBQUM7WUFDN0MsT0FBTyxFQUFFLEVBQUU7WUFDWCxXQUFXLEVBQUUsRUFBRTtZQUNmLEtBQUssRUFBRSxDQUFDLEdBQUcsRUFBRSxHQUFHLElBQUksRUFBRSxZQUFZO1lBQ2xDLFVBQVUsRUFBRSxDQUFDLEdBQUcsRUFBRSxLQUFLLEVBQUUsRUFBRTtnQkFDekIsTUFBTSxDQUFDLEtBQUssQ0FBQyxrQ0FBa0MsRUFBRSxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUM7WUFDNUQsQ0FBQztTQUNGLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRDs7T0FFRztJQUNILEtBQUssQ0FBQyxRQUFRLENBQUMsV0FBb0IsS0FBSztRQUN0QyxNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7UUFDN0IsTUFBTSxZQUFZLEdBQUcsT0FBTyxDQUFDLFdBQVcsRUFBRSxDQUFDLFFBQVEsQ0FBQztRQUVwRCxJQUFJLENBQUM7WUFDSCw4Q0FBOEM7WUFDOUMsTUFBTSxZQUFZLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQyxHQUFHLENBQUMsa0JBQWtCLENBQUMsQ0FBQztZQUM5RCxJQUFJLFlBQVksSUFBSSxJQUFJLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQztnQkFDbkMsTUFBTSxDQUFDLEtBQUssQ0FBQyxzQ0FBc0MsQ0FBQyxDQUFDO2dCQUNyRCxJQUFJLENBQUMsd0JBQXdCLENBQUMsU0FBUyxFQUFFLFlBQVksRUFBRSxZQUFZLENBQUMsQ0FBQztnQkFDckUsT0FBTyxZQUFZLENBQUM7WUFDdEIsQ0FBQztZQUVELDBDQUEwQztZQUMxQyxJQUFJLElBQUksQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDO2dCQUNuQixNQUFNLENBQUMsS0FBSyxDQUFDLDBDQUEwQyxDQUFDLENBQUM7Z0JBQ3pELE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxLQUFNLENBQUMsSUFBSSxDQUFDO2dCQUNoQyxJQUFJLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxrQkFBa0IsRUFBRSxNQUFNLENBQUMsQ0FBQztnQkFDakQsSUFBSSxDQUFDLHdCQUF3QixDQUFDLFNBQVMsRUFBRSxZQUFZLEVBQUUsVUFBVSxDQUFDLENBQUM7Z0JBQ25FLE9BQU8sTUFBTSxDQUFDO1lBQ2hCLENBQUM7WUFFRCw2QkFBNkI7WUFDN0IsSUFBSSxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUM7Z0JBQ3RCLE1BQU0sQ0FBQyxLQUFLLENBQUMsNENBQTRDLENBQUMsQ0FBQztnQkFDM0QsT0FBTyxNQUFNLElBQUksQ0FBQyxZQUFZLENBQUM7WUFDakMsQ0FBQztZQUVELHVFQUF1RTtZQUN2RSxJQUFJLFFBQVEsSUFBSSxJQUFJLENBQUMsS0FBSyxFQUFFLElBQUksRUFBRSxDQUFDO2dCQUNqQyxNQUFNLENBQUMsS0FBSyxDQUFDLHFDQUFxQyxDQUFDLENBQUM7Z0JBQ3BELElBQUksQ0FBQyx3QkFBd0IsQ0FBQyxTQUFTLEVBQUUsWUFBWSxFQUFFLFlBQVksQ0FBQyxDQUFDO2dCQUNyRSxPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDO1lBQ3pCLENBQUM7WUFFRCxzREFBc0Q7WUFDdEQsSUFBSSxDQUFDLFlBQVksR0FBRyxJQUFJLENBQUMsc0JBQXNCLEVBQUUsQ0FBQztZQUVsRCxJQUFJLENBQUM7Z0JBQ0gsTUFBTSxNQUFNLEdBQUcsTUFBTSxJQUFJLENBQUMsWUFBWSxDQUFDO2dCQUN2QyxJQUFJLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxrQkFBa0IsRUFBRSxNQUFNLENBQUMsQ0FBQztnQkFDakQsSUFBSSxDQUFDLHdCQUF3QixDQUFDLFNBQVMsRUFBRSxZQUFZLEVBQUUsYUFBYSxDQUFDLENBQUM7Z0JBQ3RFLE9BQU8sTUFBTSxDQUFDO1lBQ2hCLENBQUM7b0JBQVMsQ0FBQztnQkFDVCxJQUFJLENBQUMsWUFBWSxHQUFHLElBQUksQ0FBQztZQUMzQixDQUFDO1FBRUgsQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixNQUFNLENBQUMsS0FBSyxDQUFDLGlDQUFpQyxFQUFFLEtBQUssQ0FBQyxDQUFDO1lBRXZELG1EQUFtRDtZQUNuRCxNQUFNLGVBQWUsR0FBRyxNQUFNLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQztZQUNsRCxJQUFJLGVBQWUsRUFBRSxDQUFDO2dCQUNwQixNQUFNLENBQUMsS0FBSyxDQUFDLHVDQUF1QyxDQUFDLENBQUM7Z0JBQ3RELElBQUksQ0FBQyxLQUFLLEdBQUcsZUFBZSxDQUFDO2dCQUM3QixNQUFNLE1BQU0sR0FBRyxlQUFlLENBQUMsSUFBSSxDQUFDO2dCQUNwQyxJQUFJLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxrQkFBa0IsRUFBRSxNQUFNLENBQUMsQ0FBQztnQkFDakQsSUFBSSxDQUFDLHdCQUF3QixDQUFDLFNBQVMsRUFBRSxZQUFZLEVBQUUsZUFBZSxDQUFDLENBQUM7Z0JBQ3hFLE9BQU8sTUFBTSxDQUFDO1lBQ2hCLENBQUM7WUFFRCxNQUFNLEtBQUssQ0FBQztRQUNkLENBQUM7SUFDSCxDQUFDO0lBRUQ7O09BRUc7SUFDSyxPQUFPO1FBQ2IsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztZQUNoQixPQUFPLEtBQUssQ0FBQztRQUNmLENBQUM7UUFFRCxNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDeEQsT0FBTyxHQUFHLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQztJQUN4QixDQUFDO0lBRUQ7O09BRUc7SUFDSyxLQUFLLENBQUMsVUFBVTtRQUN0QixJQUFJLENBQUM7WUFDSCx3Q0FBd0M7WUFDeEMsTUFBTSxPQUFPLEdBQTJCO2dCQUN0QyxRQUFRLEVBQUUsa0JBQWtCO2dCQUM1QixZQUFZLEVBQUUsa0JBQWtCO2FBQ2pDLENBQUM7WUFFRiwyQ0FBMkM7WUFDM0MsSUFBSSxJQUFJLENBQUMsS0FBSyxFQUFFLElBQUksRUFBRSxDQUFDO2dCQUNyQixPQUFPLENBQUMsZUFBZSxDQUFDLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUM7WUFDN0MsQ0FBQztZQUNELElBQUksSUFBSSxDQUFDLEtBQUssRUFBRSxZQUFZLEVBQUUsQ0FBQztnQkFDN0IsT0FBTyxDQUFDLG1CQUFtQixDQUFDLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxZQUFZLENBQUM7WUFDekQsQ0FBQztZQUVELGtFQUFrRTtZQUNsRSxNQUFNLFFBQVEsR0FBRyxNQUFNLEtBQUssQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQztZQUUxRCxxQ0FBcUM7WUFDckMsSUFBSSxRQUFRLENBQUMsTUFBTSxLQUFLLEdBQUcsRUFBRSxDQUFDO2dCQUM1QixJQUFJLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztvQkFDZiw0Q0FBNEM7b0JBQzVDLElBQUksQ0FBQyxLQUFLLENBQUMsU0FBUyxHQUFHLElBQUksSUFBSSxFQUFFLENBQUM7b0JBQ2xDLE1BQU0sSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7b0JBQ2xDLE1BQU0sQ0FBQyxLQUFLLENBQUMsMkRBQTJELENBQUMsQ0FBQztvQkFDMUUsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQztnQkFDekIsQ0FBQztZQUNILENBQUM7WUFFRCxJQUFJLENBQUMsUUFBUSxDQUFDLEVBQUUsRUFBRSxDQUFDO2dCQUNqQixNQUFNLElBQUksS0FBSyxDQUFDLFFBQVEsUUFBUSxDQUFDLE1BQU0sS0FBSyxRQUFRLENBQUMsVUFBVSxFQUFFLENBQUMsQ0FBQztZQUNyRSxDQUFDO1lBRUQsTUFBTSxTQUFTLEdBQUcsTUFBTSxRQUFRLENBQUMsSUFBSSxFQUFxQixDQUFDO1lBRTNELCtCQUErQjtZQUMvQixJQUFJLENBQUMsSUFBSSxDQUFDLHNCQUFzQixDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUM7Z0JBQzVDLE1BQU0sSUFBSSxLQUFLLENBQUMsNkNBQTZDLENBQUMsQ0FBQztZQUNqRSxDQUFDO1lBRUQseUJBQXlCO1lBQ3pCLE1BQU0sUUFBUSxHQUFnQjtnQkFDNUIsSUFBSSxFQUFFLFNBQVM7Z0JBQ2YsU0FBUyxFQUFFLElBQUksSUFBSSxFQUFFO2dCQUNyQixJQUFJLEVBQUUsUUFBUSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLElBQUksU0FBUztnQkFDL0MsWUFBWSxFQUFFLFFBQVEsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLGVBQWUsQ0FBQyxJQUFJLFNBQVM7YUFDakUsQ0FBQztZQUVGLElBQUksQ0FBQyxLQUFLLEdBQUcsUUFBUSxDQUFDO1lBRXRCLHlDQUF5QztZQUN6QyxJQUFJLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsRUFBRTtnQkFDdEMsTUFBTSxDQUFDLEtBQUssQ0FBQyxxQ0FBcUMsRUFBRSxLQUFLLENBQUMsQ0FBQztZQUM3RCxDQUFDLENBQUMsQ0FBQztZQUVILE1BQU0sQ0FBQyxLQUFLLENBQUMsdUNBQXVDLFNBQVMsQ0FBQyxjQUFjLFdBQVcsQ0FBQyxDQUFDO1lBQ3pGLE9BQU8sU0FBUyxDQUFDO1FBRW5CLENBQUM7UUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1lBQ2YsTUFBTSxDQUFDLEtBQUssQ0FBQyx5Q0FBeUMsRUFBRSxLQUFLLENBQUMsQ0FBQztZQUMvRCxPQUFPLElBQUksQ0FBQztRQUNkLENBQUM7SUFDSCxDQUFDO0lBRUQ7O09BRUc7SUFDSyxzQkFBc0IsQ0FBQyxLQUFVO1FBQ3ZDLE9BQU8sQ0FDTCxLQUFLO1lBQ0wsT0FBTyxLQUFLLEtBQUssUUFBUTtZQUN6QixPQUFPLEtBQUssQ0FBQyxPQUFPLEtBQUssUUFBUTtZQUNqQyxPQUFPLEtBQUssQ0FBQyxTQUFTLEtBQUssUUFBUTtZQUNuQyxPQUFPLEtBQUssQ0FBQyxjQUFjLEtBQUssUUFBUTtZQUN4QyxLQUFLLENBQUMsS0FBSztZQUNYLE9BQU8sS0FBSyxDQUFDLEtBQUssS0FBSyxRQUFRO1lBQy9CLEtBQUssQ0FBQyxRQUFRO1lBQ2QsT0FBTyxLQUFLLENBQUMsUUFBUSxLQUFLLFFBQVEsQ0FDbkMsQ0FBQztJQUNKLENBQUM7SUFFRDs7T0FFRztJQUNLLEtBQUssQ0FBQyxVQUFVLENBQUMsS0FBa0I7UUFDekMsSUFBSSxDQUFDO1lBQ0gsTUFBTSxJQUFJLENBQUMsY0FBYyxFQUFFLENBQUM7WUFFNUIsTUFBTSxTQUFTLEdBQUc7Z0JBQ2hCLEdBQUcsS0FBSztnQkFDUixTQUFTLEVBQUUsS0FBSyxDQUFDLFNBQVMsQ0FBQyxXQUFXLEVBQUUsQ0FBQyxpQkFBaUI7YUFDM0QsQ0FBQztZQUVGLE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsU0FBUyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQztZQUNoRCxNQUFNLEVBQUUsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxJQUFJLEVBQUUsTUFBTSxDQUFDLENBQUM7WUFFakQsTUFBTSxDQUFDLEtBQUssQ0FBQyxzQ0FBc0MsQ0FBQyxDQUFDO1FBQ3ZELENBQUM7UUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1lBQ2YsTUFBTSxDQUFDLEtBQUssQ0FBQyx3Q0FBd0MsRUFBRSxLQUFLLENBQUMsQ0FBQztZQUM5RCx5RUFBeUU7UUFDM0UsQ0FBQztJQUNILENBQUM7SUFFRDs7T0FFRztJQUNLLEtBQUssQ0FBQyxZQUFZO1FBQ3hCLElBQUksQ0FBQztZQUNILDBDQUEwQztZQUMxQyxJQUFJLElBQUksQ0FBQyxTQUFTLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxJQUFJLElBQUksQ0FBQyxTQUFTLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7Z0JBQ25FLGVBQWUsQ0FBQyxnQkFBZ0IsQ0FBQztvQkFDL0IsSUFBSSxFQUFFLHdCQUF3QjtvQkFDOUIsUUFBUSxFQUFFLE1BQU07b0JBQ2hCLE1BQU0sRUFBRSxtQ0FBbUM7b0JBQzNDLE9BQU8sRUFBRSw4Q0FBOEMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxFQUFFO2lCQUMxRixDQUFDLENBQUM7Z0JBQ0gsT0FBTyxJQUFJLENBQUM7WUFDZCxDQUFDO1lBRUQsTUFBTSxJQUFJLEdBQUcsTUFBTSxFQUFFLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsTUFBTSxDQUFDLENBQUM7WUFDdkQsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUVuQyxPQUFPO2dCQUNMLEdBQUcsU0FBUztnQkFDWixTQUFTLEVBQUUsSUFBSSxJQUFJLENBQUMsU0FBUyxDQUFDLFNBQVMsQ0FBQyxDQUFDLG1CQUFtQjthQUM3RCxDQUFDO1FBQ0osQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixJQUFLLEtBQWEsQ0FBQyxJQUFJLEtBQUssUUFBUSxFQUFFLENBQUM7Z0JBQ3JDLE1BQU0sQ0FBQyxLQUFLLENBQUMsa0RBQWtELEVBQUUsS0FBSyxDQUFDLENBQUM7WUFDMUUsQ0FBQztZQUNELE9BQU8sSUFBSSxDQUFDO1FBQ2QsQ0FBQztJQUNILENBQUM7SUFFRDs7T0FFRztJQUNLLEtBQUssQ0FBQyxjQUFjO1FBQzFCLElBQUksQ0FBQztZQUNILE1BQU0sRUFBRSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLEVBQUUsU0FBUyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7UUFDckQsQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixNQUFNLENBQUMsS0FBSyxDQUFDLG1DQUFtQyxFQUFFLEtBQUssQ0FBQyxDQUFDO1lBQ3pELE1BQU0sS0FBSyxDQUFDO1FBQ2QsQ0FBQztJQUNILENBQUM7SUFFRDs7T0FFRztJQUNILEtBQUssQ0FBQyxVQUFVO1FBQ2QsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO1FBRTdCLElBQUksQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFDO1FBQ2xCLElBQUksQ0FBQyxXQUFXLENBQUMsS0FBSyxFQUFFLENBQUM7UUFFekIsMkJBQTJCO1FBQzNCLElBQUksQ0FBQyxZQUFZLEdBQUcsSUFBSSxDQUFDO1FBRXpCLElBQUksQ0FBQztZQUNILE1BQU0sRUFBRSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUM7WUFDaEMsTUFBTSxDQUFDLEtBQUssQ0FBQywwQ0FBMEMsQ0FBQyxDQUFDO1FBQzNELENBQUM7UUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1lBQ2YsSUFBSyxLQUFhLENBQUMsSUFBSSxLQUFLLFFBQVEsRUFBRSxDQUFDO2dCQUNyQyxNQUFNLENBQUMsS0FBSyxDQUFDLHlDQUF5QyxFQUFFLEtBQUssQ0FBQyxDQUFDO1lBQ2pFLENBQUM7UUFDSCxDQUFDO1FBRUQsTUFBTSxDQUFDLEtBQUssQ0FBQywwQkFBMEIsRUFBRTtZQUN2QyxRQUFRLEVBQUUsSUFBSSxDQUFDLEdBQUcsRUFBRSxHQUFHLFNBQVM7WUFDaEMsV0FBVyxFQUFFLElBQUksQ0FBQyxXQUFXLENBQUMsZ0JBQWdCLEVBQUU7U0FDakQsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVEOztPQUVHO0lBQ0gsYUFBYTtRQVFYLElBQUksQ0FBQyxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDaEIsT0FBTztnQkFDTCxPQUFPLEVBQUUsS0FBSztnQkFDZCxHQUFHLEVBQUUsQ0FBQztnQkFDTixRQUFRLEVBQUUsS0FBSztnQkFDZixRQUFRLEVBQUUsQ0FBQztnQkFDWCxXQUFXLEVBQUUsSUFBSSxDQUFDLFdBQVcsQ0FBQyxRQUFRLEVBQUU7Z0JBQ3hDLGtCQUFrQixFQUFFLElBQUk7YUFDekIsQ0FBQztRQUNKLENBQUM7UUFFRCxNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDeEQsT0FBTztZQUNMLE9BQU8sRUFBRSxJQUFJLENBQUMsT0FBTyxFQUFFO1lBQ3ZCLEdBQUc7WUFDSCxRQUFRLEVBQUUsSUFBSTtZQUNkLFFBQVEsRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxjQUFjO1lBQ3hDLFdBQVcsRUFBRSxJQUFJLENBQUMsV0FBVyxDQUFDLFFBQVEsRUFBRTtZQUN4QyxrQkFBa0IsRUFBRTtnQkFDbEIsWUFBWSxFQUFFLElBQUksQ0FBQyxxQkFBcUIsRUFBRTtnQkFDMUMsaUJBQWlCLEVBQUUsSUFBSSxDQUFDLDBCQUEwQixFQUFFO2FBQ3JEO1NBQ0YsQ0FBQztJQUNKLENBQUM7SUFFRCx3REFBd0Q7SUFDeEQseUNBQXlDO0lBQ3pDLHdEQUF3RDtJQUV4RDs7T0FFRztJQUNLLEtBQUssQ0FBQyxzQkFBc0I7UUFDbEMsSUFBSSxDQUFDO1lBQ0gsMkJBQTJCO1lBQzNCLE1BQU0sVUFBVSxHQUFHLE1BQU0sSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO1lBQzNDLElBQUksVUFBVSxFQUFFLENBQUM7Z0JBQ2YsTUFBTSxDQUFDLEtBQUssQ0FBQyx1Q0FBdUMsQ0FBQyxDQUFDO2dCQUN0RCxPQUFPLFVBQVUsQ0FBQztZQUNwQixDQUFDO1FBQ0gsQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixNQUFNLENBQUMsSUFBSSxDQUFDLHFDQUFxQyxFQUFFO2dCQUNqRCxLQUFLLEVBQUUsS0FBSyxZQUFZLEtBQUssQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQzthQUM5RCxDQUFDLENBQUM7UUFDTCxDQUFDO1FBRUQsd0NBQXdDO1FBQ3hDLElBQUksSUFBSSxDQUFDLEtBQUssRUFBRSxJQUFJLEVBQUUsQ0FBQztZQUNyQixNQUFNLENBQUMsS0FBSyxDQUFDLGlEQUFpRCxDQUFDLENBQUM7WUFDaEUsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQztRQUN6QixDQUFDO1FBRUQsTUFBTSxJQUFJLEtBQUssQ0FBQyx3RUFBd0UsQ0FBQyxDQUFDO0lBQzVGLENBQUM7SUFFRDs7T0FFRztJQUNLLHdCQUF3QixDQUFDLFNBQWlCLEVBQUUsWUFBb0IsRUFBRSxTQUFpQjtRQUN6RixNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLEdBQUcsU0FBUyxDQUFDO1FBQ3hDLE1BQU0sV0FBVyxHQUFHLE9BQU8sQ0FBQyxXQUFXLEVBQUUsQ0FBQyxRQUFRLENBQUM7UUFFbkQsTUFBTSxDQUFDLEtBQUssQ0FBQyxzQ0FBc0MsRUFBRTtZQUNuRCxTQUFTO1lBQ1QsUUFBUTtZQUNSLGFBQWEsRUFBRSxDQUFDLFdBQVcsR0FBRyxZQUFZLENBQUMsR0FBRyxDQUFDLElBQUksR0FBRyxJQUFJLENBQUM7U0FDNUQsQ0FBQyxDQUFDO1FBRUgsbUNBQW1DO1FBQ25DLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxzQkFBc0IsQ0FBQyxpQkFBaUIsRUFBRTtZQUNoRSxPQUFPLEVBQUUsU0FBUyxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQzFDLFVBQVUsRUFBRSxTQUFTLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDcEQsV0FBVyxFQUFFLFNBQVMsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsUUFBUTtZQUNyRCxTQUFTLEVBQUUsU0FBUyxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQzVDLFdBQVcsRUFBRSxTQUFTLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDOUMsU0FBUyxFQUFFLENBQUM7U0FDYixDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQ7O09BRUc7SUFDSyxxQkFBcUI7UUFDM0IseURBQXlEO1FBQ3pELE9BQU8sSUFBSSxDQUFDLFdBQVcsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxPQUFPLENBQUM7SUFDN0MsQ0FBQztJQUVEOztPQUVHO0lBQ0ssMEJBQTBCO1FBQ2hDLHVEQUF1RDtRQUN2RCxPQUFPLENBQUMsQ0FBQyxDQUFDLG9CQUFvQjtJQUNoQyxDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFNtYXJ0IGNhY2hlIGZvciBjb2xsZWN0aW9uIGluZGV4IHdpdGggY29uZGl0aW9uYWwgZmV0Y2hpbmcgYW5kIHBlcmZvcm1hbmNlIG9wdGltaXphdGlvblxuICovXG5cbmltcG9ydCAqIGFzIGZzIGZyb20gJ2ZzL3Byb21pc2VzJztcbmltcG9ydCAqIGFzIHBhdGggZnJvbSAncGF0aCc7XG5pbXBvcnQgeyBDb2xsZWN0aW9uSW5kZXgsIENhY2hlZEluZGV4IH0gZnJvbSAnLi4vdHlwZXMvY29sbGVjdGlvbi5qcyc7XG5pbXBvcnQgeyBsb2dnZXIgfSBmcm9tICcuLi91dGlscy9sb2dnZXIuanMnO1xuaW1wb3J0IHsgR2l0SHViQ2xpZW50IH0gZnJvbSAnLi4vY29sbGVjdGlvbi9HaXRIdWJDbGllbnQuanMnO1xuaW1wb3J0IHsgU2VjdXJpdHlNb25pdG9yIH0gZnJvbSAnLi4vc2VjdXJpdHkvc2VjdXJpdHlNb25pdG9yLmpzJztcbmltcG9ydCB7IExSVUNhY2hlLCBDYWNoZUZhY3RvcnkgfSBmcm9tICcuL0xSVUNhY2hlLmpzJztcbmltcG9ydCB7IFBlcmZvcm1hbmNlTW9uaXRvciB9IGZyb20gJy4uL3V0aWxzL1BlcmZvcm1hbmNlTW9uaXRvci5qcyc7XG5cbmV4cG9ydCBjbGFzcyBDb2xsZWN0aW9uSW5kZXhDYWNoZSB7XG4gIHByaXZhdGUgY2FjaGU6IENhY2hlZEluZGV4IHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgcmVhZG9ubHkgVFRMID0gMTUgKiA2MCAqIDEwMDA7IC8vIDE1IG1pbnV0ZXMgaW4gbWlsbGlzZWNvbmRzXG4gIHByaXZhdGUgcmVhZG9ubHkgSU5ERVhfVVJMID0gJ2h0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9Eb2xsaG91c2VNQ1AvY29sbGVjdGlvbi9tYWluL3B1YmxpYy9jb2xsZWN0aW9uLWluZGV4Lmpzb24nO1xuICBwcml2YXRlIGNhY2hlRGlyOiBzdHJpbmc7XG4gIHByaXZhdGUgY2FjaGVGaWxlOiBzdHJpbmc7XG4gIHByaXZhdGUgZ2l0aHViQ2xpZW50OiBHaXRIdWJDbGllbnQ7XG4gIHByaXZhdGUgcGVyZm9ybWFuY2VNb25pdG9yOiBQZXJmb3JtYW5jZU1vbml0b3I7XG4gIHByaXZhdGUgbWVtb3J5Q2FjaGU6IExSVUNhY2hlPGFueT47XG4gIHByaXZhdGUgZmV0Y2hQcm9taXNlOiBQcm9taXNlPENvbGxlY3Rpb25JbmRleD4gfCBudWxsID0gbnVsbDsgLy8gUHJldmVudCBjb25jdXJyZW50IGZldGNoZXNcbiAgXG4gIGNvbnN0cnVjdG9yKGdpdGh1YkNsaWVudDogR2l0SHViQ2xpZW50LCBiYXNlRGlyOiBzdHJpbmcgPSBwcm9jZXNzLmN3ZCgpKSB7XG4gICAgdGhpcy5naXRodWJDbGllbnQgPSBnaXRodWJDbGllbnQ7XG4gICAgdGhpcy5jYWNoZURpciA9IHBhdGguam9pbihiYXNlRGlyLCAnLmRvbGxob3VzZW1jcCcsICdjYWNoZScpO1xuICAgIHRoaXMuY2FjaGVGaWxlID0gcGF0aC5qb2luKHRoaXMuY2FjaGVEaXIsICdjb2xsZWN0aW9uLWluZGV4LWNhY2hlLmpzb24nKTtcbiAgICB0aGlzLnBlcmZvcm1hbmNlTW9uaXRvciA9IFBlcmZvcm1hbmNlTW9uaXRvci5nZXRJbnN0YW5jZSgpO1xuICAgIFxuICAgIC8vIEluaXRpYWxpemUgbWVtb3J5IGNhY2hlIGZvciBmcmVxdWVudGx5IGFjY2Vzc2VkIGRhdGFcbiAgICB0aGlzLm1lbW9yeUNhY2hlID0gQ2FjaGVGYWN0b3J5LmNyZWF0ZUFQSUNhY2hlKHtcbiAgICAgIG1heFNpemU6IDUwLFxuICAgICAgbWF4TWVtb3J5TUI6IDEwLFxuICAgICAgdHRsTXM6IDUgKiA2MCAqIDEwMDAsIC8vIDUgbWludXRlc1xuICAgICAgb25FdmljdGlvbjogKGtleSwgdmFsdWUpID0+IHtcbiAgICAgICAgbG9nZ2VyLmRlYnVnKCdDb2xsZWN0aW9uIG1lbW9yeSBjYWNoZSBldmljdGlvbicsIHsga2V5IH0pO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG4gIFxuICAvKipcbiAgICogR2V0IHRoZSBjb2xsZWN0aW9uIGluZGV4IHdpdGggcGVyZm9ybWFuY2Ugb3B0aW1pemF0aW9uIGFuZCBsYXp5IGxvYWRpbmdcbiAgICovXG4gIGFzeW5jIGdldEluZGV4KGxhenlMb2FkOiBib29sZWFuID0gZmFsc2UpOiBQcm9taXNlPENvbGxlY3Rpb25JbmRleD4ge1xuICAgIGNvbnN0IHN0YXJ0VGltZSA9IERhdGUubm93KCk7XG4gICAgY29uc3QgbWVtb3J5QmVmb3JlID0gcHJvY2Vzcy5tZW1vcnlVc2FnZSgpLmhlYXBVc2VkO1xuICAgIFxuICAgIHRyeSB7XG4gICAgICAvLyBDaGVjayBtZW1vcnkgY2FjaGUgZmlyc3QgZm9yIGZhc3Rlc3QgYWNjZXNzXG4gICAgICBjb25zdCBtZW1vcnlDYWNoZWQgPSB0aGlzLm1lbW9yeUNhY2hlLmdldCgnY29sbGVjdGlvbi1pbmRleCcpO1xuICAgICAgaWYgKG1lbW9yeUNhY2hlZCAmJiB0aGlzLmlzVmFsaWQoKSkge1xuICAgICAgICBsb2dnZXIuZGVidWcoJ1VzaW5nIG1lbW9yeSBjYWNoZWQgY29sbGVjdGlvbiBpbmRleCcpO1xuICAgICAgICB0aGlzLnJlY29yZFBlcmZvcm1hbmNlTWV0cmljcyhzdGFydFRpbWUsIG1lbW9yeUJlZm9yZSwgJ21lbW9yeS1oaXQnKTtcbiAgICAgICAgcmV0dXJuIG1lbW9yeUNhY2hlZDtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgLy8gQ2hlY2sgaWYgd2UgaGF2ZSB2YWxpZCBkaXNrIGNhY2hlZCBkYXRhXG4gICAgICBpZiAodGhpcy5pc1ZhbGlkKCkpIHtcbiAgICAgICAgbG9nZ2VyLmRlYnVnKCdVc2luZyB2YWxpZCBkaXNrIGNhY2hlZCBjb2xsZWN0aW9uIGluZGV4Jyk7XG4gICAgICAgIGNvbnN0IHJlc3VsdCA9IHRoaXMuY2FjaGUhLmRhdGE7XG4gICAgICAgIHRoaXMubWVtb3J5Q2FjaGUuc2V0KCdjb2xsZWN0aW9uLWluZGV4JywgcmVzdWx0KTtcbiAgICAgICAgdGhpcy5yZWNvcmRQZXJmb3JtYW5jZU1ldHJpY3Moc3RhcnRUaW1lLCBtZW1vcnlCZWZvcmUsICdkaXNrLWhpdCcpO1xuICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgfVxuICAgICAgXG4gICAgICAvLyBQcmV2ZW50IGNvbmN1cnJlbnQgZmV0Y2hlc1xuICAgICAgaWYgKHRoaXMuZmV0Y2hQcm9taXNlKSB7XG4gICAgICAgIGxvZ2dlci5kZWJ1ZygnV2FpdGluZyBmb3Igb25nb2luZyBjb2xsZWN0aW9uIGluZGV4IGZldGNoJyk7XG4gICAgICAgIHJldHVybiBhd2FpdCB0aGlzLmZldGNoUHJvbWlzZTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgLy8gTGF6eSBsb2FkaW5nOiBPbmx5IGZldGNoIGlmIG5vdCBpbiBsYXp5IG1vZGUgb3IgYWJzb2x1dGVseSBuZWNlc3NhcnlcbiAgICAgIGlmIChsYXp5TG9hZCAmJiB0aGlzLmNhY2hlPy5kYXRhKSB7XG4gICAgICAgIGxvZ2dlci5kZWJ1ZygnVXNpbmcgc3RhbGUgY2FjaGUgaW4gbGF6eSBsb2FkIG1vZGUnKTtcbiAgICAgICAgdGhpcy5yZWNvcmRQZXJmb3JtYW5jZU1ldHJpY3Moc3RhcnRUaW1lLCBtZW1vcnlCZWZvcmUsICdsYXp5LXN0YWxlJyk7XG4gICAgICAgIHJldHVybiB0aGlzLmNhY2hlLmRhdGE7XG4gICAgICB9XG4gICAgICBcbiAgICAgIC8vIENyZWF0ZSBmZXRjaCBwcm9taXNlIHRvIHByZXZlbnQgY29uY3VycmVudCByZXF1ZXN0c1xuICAgICAgdGhpcy5mZXRjaFByb21pc2UgPSB0aGlzLmZldGNoRnJlc2hXaXRoRmFsbGJhY2soKTtcbiAgICAgIFxuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgdGhpcy5mZXRjaFByb21pc2U7XG4gICAgICAgIHRoaXMubWVtb3J5Q2FjaGUuc2V0KCdjb2xsZWN0aW9uLWluZGV4JywgcmVzdWx0KTtcbiAgICAgICAgdGhpcy5yZWNvcmRQZXJmb3JtYW5jZU1ldHJpY3Moc3RhcnRUaW1lLCBtZW1vcnlCZWZvcmUsICdmcmVzaC1mZXRjaCcpO1xuICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgdGhpcy5mZXRjaFByb21pc2UgPSBudWxsO1xuICAgICAgfVxuICAgICAgXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGxvZ2dlci5lcnJvcignRmFpbGVkIHRvIGdldCBjb2xsZWN0aW9uIGluZGV4OicsIGVycm9yKTtcbiAgICAgIFxuICAgICAgLy8gVHJ5IGxvYWRpbmcgZnJvbSBwZXJzaXN0ZW50IGNhY2hlIGFzIGxhc3QgcmVzb3J0XG4gICAgICBjb25zdCBwZXJzaXN0ZW50Q2FjaGUgPSBhd2FpdCB0aGlzLmxvYWRGcm9tRGlzaygpO1xuICAgICAgaWYgKHBlcnNpc3RlbnRDYWNoZSkge1xuICAgICAgICBsb2dnZXIuZGVidWcoJ1VzaW5nIHBlcnNpc3RlbnQgY2FjaGUgYXMgbGFzdCByZXNvcnQnKTtcbiAgICAgICAgdGhpcy5jYWNoZSA9IHBlcnNpc3RlbnRDYWNoZTtcbiAgICAgICAgY29uc3QgcmVzdWx0ID0gcGVyc2lzdGVudENhY2hlLmRhdGE7XG4gICAgICAgIHRoaXMubWVtb3J5Q2FjaGUuc2V0KCdjb2xsZWN0aW9uLWluZGV4JywgcmVzdWx0KTtcbiAgICAgICAgdGhpcy5yZWNvcmRQZXJmb3JtYW5jZU1ldHJpY3Moc3RhcnRUaW1lLCBtZW1vcnlCZWZvcmUsICdkaXNrLWZhbGxiYWNrJyk7XG4gICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICB9XG4gICAgICBcbiAgICAgIHRocm93IGVycm9yO1xuICAgIH1cbiAgfVxuICBcbiAgLyoqXG4gICAqIENoZWNrIGlmIGN1cnJlbnQgY2FjaGUgaXMgdmFsaWQgKHdpdGhpbiBUVEwpXG4gICAqL1xuICBwcml2YXRlIGlzVmFsaWQoKTogYm9vbGVhbiB7XG4gICAgaWYgKCF0aGlzLmNhY2hlKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIFxuICAgIGNvbnN0IGFnZSA9IERhdGUubm93KCkgLSB0aGlzLmNhY2hlLmZldGNoZWRBdC5nZXRUaW1lKCk7XG4gICAgcmV0dXJuIGFnZSA8IHRoaXMuVFRMO1xuICB9XG4gIFxuICAvKipcbiAgICogRmV0Y2ggZnJlc2ggaW5kZXggZnJvbSBHaXRIdWIgd2l0aCBjb25kaXRpb25hbCByZXF1ZXN0c1xuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBmZXRjaEZyZXNoKCk6IFByb21pc2U8Q29sbGVjdGlvbkluZGV4IHwgbnVsbD4ge1xuICAgIHRyeSB7XG4gICAgICAvLyBCdWlsZCBoZWFkZXJzIGZvciBjb25kaXRpb25hbCByZXF1ZXN0XG4gICAgICBjb25zdCBoZWFkZXJzOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge1xuICAgICAgICAnQWNjZXB0JzogJ2FwcGxpY2F0aW9uL2pzb24nLFxuICAgICAgICAnVXNlci1BZ2VudCc6ICdEb2xsaG91c2VNQ1AvMS4wJ1xuICAgICAgfTtcbiAgICAgIFxuICAgICAgLy8gQWRkIGNvbmRpdGlvbmFsIGhlYWRlcnMgaWYgd2UgaGF2ZSBjYWNoZVxuICAgICAgaWYgKHRoaXMuY2FjaGU/LmV0YWcpIHtcbiAgICAgICAgaGVhZGVyc1snSWYtTm9uZS1NYXRjaCddID0gdGhpcy5jYWNoZS5ldGFnO1xuICAgICAgfVxuICAgICAgaWYgKHRoaXMuY2FjaGU/Lmxhc3RNb2RpZmllZCkge1xuICAgICAgICBoZWFkZXJzWydJZi1Nb2RpZmllZC1TaW5jZSddID0gdGhpcy5jYWNoZS5sYXN0TW9kaWZpZWQ7XG4gICAgICB9XG4gICAgICBcbiAgICAgIC8vIFVzZSBmZXRjaCBkaXJlY3RseSBmb3IgYmV0dGVyIGNvbnRyb2wgb3ZlciBjb25kaXRpb25hbCByZXF1ZXN0c1xuICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaCh0aGlzLklOREVYX1VSTCwgeyBoZWFkZXJzIH0pO1xuICAgICAgXG4gICAgICAvLyAzMDQgTm90IE1vZGlmaWVkIC0gdXNlIGNhY2hlZCBkYXRhXG4gICAgICBpZiAocmVzcG9uc2Uuc3RhdHVzID09PSAzMDQpIHtcbiAgICAgICAgaWYgKHRoaXMuY2FjaGUpIHtcbiAgICAgICAgICAvLyBVcGRhdGUgdGltZXN0YW1wIHRvIGV4dGVuZCBjYWNoZSB2YWxpZGl0eVxuICAgICAgICAgIHRoaXMuY2FjaGUuZmV0Y2hlZEF0ID0gbmV3IERhdGUoKTtcbiAgICAgICAgICBhd2FpdCB0aGlzLnNhdmVUb0Rpc2sodGhpcy5jYWNoZSk7XG4gICAgICAgICAgbG9nZ2VyLmRlYnVnKCdDb2xsZWN0aW9uIGluZGV4IG5vdCBtb2RpZmllZCAtIHJlZnJlc2hlZCBjYWNoZSB0aW1lc3RhbXAnKTtcbiAgICAgICAgICByZXR1cm4gdGhpcy5jYWNoZS5kYXRhO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBcbiAgICAgIGlmICghcmVzcG9uc2Uub2spIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBIVFRQICR7cmVzcG9uc2Uuc3RhdHVzfTogJHtyZXNwb25zZS5zdGF0dXNUZXh0fWApO1xuICAgICAgfVxuICAgICAgXG4gICAgICBjb25zdCBpbmRleERhdGEgPSBhd2FpdCByZXNwb25zZS5qc29uKCkgYXMgQ29sbGVjdGlvbkluZGV4O1xuICAgICAgXG4gICAgICAvLyBWYWxpZGF0ZSB0aGUgaW5kZXggc3RydWN0dXJlXG4gICAgICBpZiAoIXRoaXMudmFsaWRhdGVJbmRleFN0cnVjdHVyZShpbmRleERhdGEpKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBjb2xsZWN0aW9uIGluZGV4IHN0cnVjdHVyZSByZWNlaXZlZCcpO1xuICAgICAgfVxuICAgICAgXG4gICAgICAvLyBDcmVhdGUgbmV3IGNhY2hlIGVudHJ5XG4gICAgICBjb25zdCBuZXdDYWNoZTogQ2FjaGVkSW5kZXggPSB7XG4gICAgICAgIGRhdGE6IGluZGV4RGF0YSxcbiAgICAgICAgZmV0Y2hlZEF0OiBuZXcgRGF0ZSgpLFxuICAgICAgICBldGFnOiByZXNwb25zZS5oZWFkZXJzLmdldCgnZXRhZycpIHx8IHVuZGVmaW5lZCxcbiAgICAgICAgbGFzdE1vZGlmaWVkOiByZXNwb25zZS5oZWFkZXJzLmdldCgnbGFzdC1tb2RpZmllZCcpIHx8IHVuZGVmaW5lZFxuICAgICAgfTtcbiAgICAgIFxuICAgICAgdGhpcy5jYWNoZSA9IG5ld0NhY2hlO1xuICAgICAgXG4gICAgICAvLyBTYXZlIHRvIHBlcnNpc3RlbnQgY2FjaGUgaW4gYmFja2dyb3VuZFxuICAgICAgdGhpcy5zYXZlVG9EaXNrKG5ld0NhY2hlKS5jYXRjaChlcnJvciA9PiB7XG4gICAgICAgIGxvZ2dlci5kZWJ1ZygnRmFpbGVkIHRvIHNhdmUgaW5kZXggY2FjaGUgdG8gZGlzazonLCBlcnJvcik7XG4gICAgICB9KTtcbiAgICAgIFxuICAgICAgbG9nZ2VyLmRlYnVnKGBGcmVzaCBjb2xsZWN0aW9uIGluZGV4IGZldGNoZWQgd2l0aCAke2luZGV4RGF0YS50b3RhbF9lbGVtZW50c30gZWxlbWVudHNgKTtcbiAgICAgIHJldHVybiBpbmRleERhdGE7XG4gICAgICBcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgbG9nZ2VyLmRlYnVnKCdGYWlsZWQgdG8gZmV0Y2ggZnJlc2ggY29sbGVjdGlvbiBpbmRleDonLCBlcnJvcik7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBWYWxpZGF0ZSB0aGUgc3RydWN0dXJlIG9mIGEgY29sbGVjdGlvbiBpbmRleFxuICAgKi9cbiAgcHJpdmF0ZSB2YWxpZGF0ZUluZGV4U3RydWN0dXJlKGluZGV4OiBhbnkpOiBpbmRleCBpcyBDb2xsZWN0aW9uSW5kZXgge1xuICAgIHJldHVybiAoXG4gICAgICBpbmRleCAmJlxuICAgICAgdHlwZW9mIGluZGV4ID09PSAnb2JqZWN0JyAmJlxuICAgICAgdHlwZW9mIGluZGV4LnZlcnNpb24gPT09ICdzdHJpbmcnICYmXG4gICAgICB0eXBlb2YgaW5kZXguZ2VuZXJhdGVkID09PSAnc3RyaW5nJyAmJlxuICAgICAgdHlwZW9mIGluZGV4LnRvdGFsX2VsZW1lbnRzID09PSAnbnVtYmVyJyAmJlxuICAgICAgaW5kZXguaW5kZXggJiZcbiAgICAgIHR5cGVvZiBpbmRleC5pbmRleCA9PT0gJ29iamVjdCcgJiZcbiAgICAgIGluZGV4Lm1ldGFkYXRhICYmXG4gICAgICB0eXBlb2YgaW5kZXgubWV0YWRhdGEgPT09ICdvYmplY3QnXG4gICAgKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIFNhdmUgY2FjaGUgdG8gcGVyc2lzdGVudCBzdG9yYWdlXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHNhdmVUb0Rpc2soY2FjaGU6IENhY2hlZEluZGV4KTogUHJvbWlzZTx2b2lkPiB7XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IHRoaXMuZW5zdXJlQ2FjaGVEaXIoKTtcbiAgICAgIFxuICAgICAgY29uc3QgY2FjaGVEYXRhID0ge1xuICAgICAgICAuLi5jYWNoZSxcbiAgICAgICAgZmV0Y2hlZEF0OiBjYWNoZS5mZXRjaGVkQXQudG9JU09TdHJpbmcoKSAvLyBTZXJpYWxpemUgZGF0ZVxuICAgICAgfTtcbiAgICAgIFxuICAgICAgY29uc3QgZGF0YSA9IEpTT04uc3RyaW5naWZ5KGNhY2hlRGF0YSwgbnVsbCwgMik7XG4gICAgICBhd2FpdCBmcy53cml0ZUZpbGUodGhpcy5jYWNoZUZpbGUsIGRhdGEsICd1dGY4Jyk7XG4gICAgICBcbiAgICAgIGxvZ2dlci5kZWJ1ZygnQ29sbGVjdGlvbiBpbmRleCBjYWNoZSBzYXZlZCB0byBkaXNrJyk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGxvZ2dlci5kZWJ1ZygnRmFpbGVkIHRvIHNhdmUgY29sbGVjdGlvbiBpbmRleCBjYWNoZTonLCBlcnJvcik7XG4gICAgICAvLyBEb24ndCB0aHJvdyAtIGNhY2hlIHBlcnNpc3RlbmNlIGZhaWx1cmVzIHNob3VsZG4ndCBicmVhayBmdW5jdGlvbmFsaXR5XG4gICAgfVxuICB9XG4gIFxuICAvKipcbiAgICogTG9hZCBjYWNoZSBmcm9tIHBlcnNpc3RlbnQgc3RvcmFnZVxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBsb2FkRnJvbURpc2soKTogUHJvbWlzZTxDYWNoZWRJbmRleCB8IG51bGw+IHtcbiAgICB0cnkge1xuICAgICAgLy8gQmFzaWMgc2VjdXJpdHkgY2hlY2sgZm9yIHBhdGggdHJhdmVyc2FsXG4gICAgICBpZiAodGhpcy5jYWNoZUZpbGUuaW5jbHVkZXMoJy4uJykgfHwgdGhpcy5jYWNoZUZpbGUuaW5jbHVkZXMoJ1xcMCcpKSB7XG4gICAgICAgIFNlY3VyaXR5TW9uaXRvci5sb2dTZWN1cml0eUV2ZW50KHtcbiAgICAgICAgICB0eXBlOiAnUEFUSF9UUkFWRVJTQUxfQVRURU1QVCcsXG4gICAgICAgICAgc2V2ZXJpdHk6ICdISUdIJyxcbiAgICAgICAgICBzb3VyY2U6ICdDb2xsZWN0aW9uSW5kZXhDYWNoZS5sb2FkRnJvbURpc2snLFxuICAgICAgICAgIGRldGFpbHM6IGBQb3RlbnRpYWwgcGF0aCB0cmF2ZXJzYWwgYXR0ZW1wdCBkZXRlY3RlZDogJHt0aGlzLmNhY2hlRmlsZS5zdWJzdHJpbmcoMCwgMTAwKX1gXG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgY29uc3QgZGF0YSA9IGF3YWl0IGZzLnJlYWRGaWxlKHRoaXMuY2FjaGVGaWxlLCAndXRmOCcpO1xuICAgICAgY29uc3QgY2FjaGVEYXRhID0gSlNPTi5wYXJzZShkYXRhKTtcbiAgICAgIFxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgLi4uY2FjaGVEYXRhLFxuICAgICAgICBmZXRjaGVkQXQ6IG5ldyBEYXRlKGNhY2hlRGF0YS5mZXRjaGVkQXQpIC8vIERlc2VyaWFsaXplIGRhdGVcbiAgICAgIH07XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGlmICgoZXJyb3IgYXMgYW55KS5jb2RlICE9PSAnRU5PRU5UJykge1xuICAgICAgICBsb2dnZXIuZGVidWcoJ0ZhaWxlZCB0byBsb2FkIGNvbGxlY3Rpb24gaW5kZXggY2FjaGUgZnJvbSBkaXNrOicsIGVycm9yKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgfVxuICBcbiAgLyoqXG4gICAqIEVuc3VyZSBjYWNoZSBkaXJlY3RvcnkgZXhpc3RzXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGVuc3VyZUNhY2hlRGlyKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCBmcy5ta2Rpcih0aGlzLmNhY2hlRGlyLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgbG9nZ2VyLmVycm9yKCdGYWlsZWQgdG8gY3JlYXRlIGNhY2hlIGRpcmVjdG9yeTonLCBlcnJvcik7XG4gICAgICB0aHJvdyBlcnJvcjtcbiAgICB9XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBDbGVhciBhbGwgY2FjaGUgZGF0YSB3aXRoIHBlcmZvcm1hbmNlIG1vbml0b3JpbmdcbiAgICovXG4gIGFzeW5jIGNsZWFyQ2FjaGUoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3Qgc3RhcnRUaW1lID0gRGF0ZS5ub3coKTtcbiAgICBcbiAgICB0aGlzLmNhY2hlID0gbnVsbDtcbiAgICB0aGlzLm1lbW9yeUNhY2hlLmNsZWFyKCk7XG4gICAgXG4gICAgLy8gQ2FuY2VsIGFueSBvbmdvaW5nIGZldGNoXG4gICAgdGhpcy5mZXRjaFByb21pc2UgPSBudWxsO1xuICAgIFxuICAgIHRyeSB7XG4gICAgICBhd2FpdCBmcy51bmxpbmsodGhpcy5jYWNoZUZpbGUpO1xuICAgICAgbG9nZ2VyLmRlYnVnKCdDb2xsZWN0aW9uIGluZGV4IGNhY2hlIGNsZWFyZWQgZnJvbSBkaXNrJyk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGlmICgoZXJyb3IgYXMgYW55KS5jb2RlICE9PSAnRU5PRU5UJykge1xuICAgICAgICBsb2dnZXIuZGVidWcoJ0ZhaWxlZCB0byBjbGVhciBjb2xsZWN0aW9uIGluZGV4IGNhY2hlOicsIGVycm9yKTtcbiAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgbG9nZ2VyLmRlYnVnKCdDb2xsZWN0aW9uIGNhY2hlIGNsZWFyZWQnLCB7XG4gICAgICBkdXJhdGlvbjogRGF0ZS5ub3coKSAtIHN0YXJ0VGltZSxcbiAgICAgIG1lbW9yeUZyZWVkOiB0aGlzLm1lbW9yeUNhY2hlLmdldE1lbW9yeVVzYWdlTUIoKVxuICAgIH0pO1xuICB9XG4gIFxuICAvKipcbiAgICogR2V0IGNvbXByZWhlbnNpdmUgY2FjaGUgc3RhdGlzdGljcyBmb3IgZGVidWdnaW5nIGFuZCBtb25pdG9yaW5nXG4gICAqL1xuICBnZXRDYWNoZVN0YXRzKCk6IHsgXG4gICAgaXNWYWxpZDogYm9vbGVhbjsgXG4gICAgYWdlOiBudW1iZXI7IFxuICAgIGhhc0NhY2hlOiBib29sZWFuOyBcbiAgICBlbGVtZW50czogbnVtYmVyO1xuICAgIG1lbW9yeUNhY2hlOiBhbnk7XG4gICAgcGVyZm9ybWFuY2VNZXRyaWNzOiBhbnk7XG4gIH0ge1xuICAgIGlmICghdGhpcy5jYWNoZSkge1xuICAgICAgcmV0dXJuIHsgXG4gICAgICAgIGlzVmFsaWQ6IGZhbHNlLCBcbiAgICAgICAgYWdlOiAwLCBcbiAgICAgICAgaGFzQ2FjaGU6IGZhbHNlLCBcbiAgICAgICAgZWxlbWVudHM6IDAsXG4gICAgICAgIG1lbW9yeUNhY2hlOiB0aGlzLm1lbW9yeUNhY2hlLmdldFN0YXRzKCksXG4gICAgICAgIHBlcmZvcm1hbmNlTWV0cmljczogbnVsbFxuICAgICAgfTtcbiAgICB9XG4gICAgXG4gICAgY29uc3QgYWdlID0gRGF0ZS5ub3coKSAtIHRoaXMuY2FjaGUuZmV0Y2hlZEF0LmdldFRpbWUoKTtcbiAgICByZXR1cm4ge1xuICAgICAgaXNWYWxpZDogdGhpcy5pc1ZhbGlkKCksXG4gICAgICBhZ2UsXG4gICAgICBoYXNDYWNoZTogdHJ1ZSxcbiAgICAgIGVsZW1lbnRzOiB0aGlzLmNhY2hlLmRhdGEudG90YWxfZWxlbWVudHMsXG4gICAgICBtZW1vcnlDYWNoZTogdGhpcy5tZW1vcnlDYWNoZS5nZXRTdGF0cygpLFxuICAgICAgcGVyZm9ybWFuY2VNZXRyaWNzOiB7XG4gICAgICAgIGNhY2hlSGl0UmF0ZTogdGhpcy5jYWxjdWxhdGVDYWNoZUhpdFJhdGUoKSxcbiAgICAgICAgYXZlcmFnZUFjY2Vzc1RpbWU6IHRoaXMuY2FsY3VsYXRlQXZlcmFnZUFjY2Vzc1RpbWUoKVxuICAgICAgfVxuICAgIH07XG4gIH1cbiAgXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gIC8vIFBSSVZBVEUgSEVMUEVSIE1FVEhPRFMgRk9SIFBFUkZPUk1BTkNFXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gIFxuICAvKipcbiAgICogRmV0Y2ggZnJlc2ggaW5kZXggd2l0aCBjb21wcmVoZW5zaXZlIGZhbGxiYWNrIHN0cmF0ZWd5XG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGZldGNoRnJlc2hXaXRoRmFsbGJhY2soKTogUHJvbWlzZTxDb2xsZWN0aW9uSW5kZXg+IHtcbiAgICB0cnkge1xuICAgICAgLy8gVHJ5IHRvIGZldGNoIGZyZXNoIGluZGV4XG4gICAgICBjb25zdCBmcmVzaEluZGV4ID0gYXdhaXQgdGhpcy5mZXRjaEZyZXNoKCk7XG4gICAgICBpZiAoZnJlc2hJbmRleCkge1xuICAgICAgICBsb2dnZXIuZGVidWcoJ0NvbGxlY3Rpb24gaW5kZXggZmV0Y2hlZCBzdWNjZXNzZnVsbHknKTtcbiAgICAgICAgcmV0dXJuIGZyZXNoSW5kZXg7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGxvZ2dlci53YXJuKCdGcmVzaCBmZXRjaCBmYWlsZWQsIHRyeWluZyBmYWxsYmFjaycsIHtcbiAgICAgICAgZXJyb3I6IGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKVxuICAgICAgfSk7XG4gICAgfVxuICAgIFxuICAgIC8vIEZhbGwgYmFjayB0byBzdGFsZSBjYWNoZSBpZiBhdmFpbGFibGVcbiAgICBpZiAodGhpcy5jYWNoZT8uZGF0YSkge1xuICAgICAgbG9nZ2VyLmRlYnVnKCdVc2luZyBzdGFsZSBjYWNoZWQgY29sbGVjdGlvbiBpbmRleCBhcyBmYWxsYmFjaycpO1xuICAgICAgcmV0dXJuIHRoaXMuY2FjaGUuZGF0YTtcbiAgICB9XG4gICAgXG4gICAgdGhyb3cgbmV3IEVycm9yKCdObyBjb2xsZWN0aW9uIGluZGV4IGF2YWlsYWJsZSAtIGZyZXNoIGZldGNoIGZhaWxlZCBhbmQgbm8gY2FjaGUgZXhpc3RzJyk7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBSZWNvcmQgcGVyZm9ybWFuY2UgbWV0cmljcyBmb3IgY2FjaGUgb3BlcmF0aW9uc1xuICAgKi9cbiAgcHJpdmF0ZSByZWNvcmRQZXJmb3JtYW5jZU1ldHJpY3Moc3RhcnRUaW1lOiBudW1iZXIsIG1lbW9yeUJlZm9yZTogbnVtYmVyLCBvcGVyYXRpb246IHN0cmluZyk6IHZvaWQge1xuICAgIGNvbnN0IGR1cmF0aW9uID0gRGF0ZS5ub3coKSAtIHN0YXJ0VGltZTtcbiAgICBjb25zdCBtZW1vcnlBZnRlciA9IHByb2Nlc3MubWVtb3J5VXNhZ2UoKS5oZWFwVXNlZDtcbiAgICBcbiAgICBsb2dnZXIuZGVidWcoJ0NvbGxlY3Rpb24gY2FjaGUgb3BlcmF0aW9uIGNvbXBsZXRlZCcsIHtcbiAgICAgIG9wZXJhdGlvbixcbiAgICAgIGR1cmF0aW9uLFxuICAgICAgbWVtb3J5VXNhZ2VNQjogKG1lbW9yeUFmdGVyIC0gbWVtb3J5QmVmb3JlKSAvICgxMDI0ICogMTAyNClcbiAgICB9KTtcbiAgICBcbiAgICAvLyBSZWNvcmQgY2FjaGUgcGVyZm9ybWFuY2UgbWV0cmljc1xuICAgIHRoaXMucGVyZm9ybWFuY2VNb25pdG9yLnJlY29yZENhY2hlUGVyZm9ybWFuY2UoJ2NvbGxlY3Rpb25JbmRleCcsIHtcbiAgICAgIGhpdFJhdGU6IG9wZXJhdGlvbi5pbmNsdWRlcygnaGl0JykgPyAxIDogMCxcbiAgICAgIGF2Z0hpdFRpbWU6IG9wZXJhdGlvbi5pbmNsdWRlcygnaGl0JykgPyBkdXJhdGlvbiA6IDAsXG4gICAgICBhdmdNaXNzVGltZTogb3BlcmF0aW9uLmluY2x1ZGVzKCdoaXQnKSA/IDAgOiBkdXJhdGlvbixcbiAgICAgIHRvdGFsSGl0czogb3BlcmF0aW9uLmluY2x1ZGVzKCdoaXQnKSA/IDEgOiAwLFxuICAgICAgdG90YWxNaXNzZXM6IG9wZXJhdGlvbi5pbmNsdWRlcygnaGl0JykgPyAwIDogMSxcbiAgICAgIGV2aWN0aW9uczogMFxuICAgIH0pO1xuICB9XG4gIFxuICAvKipcbiAgICogQ2FsY3VsYXRlIGNhY2hlIGhpdCByYXRlIChwbGFjZWhvbGRlciBmb3IgZnV0dXJlIGltcGxlbWVudGF0aW9uKVxuICAgKi9cbiAgcHJpdmF0ZSBjYWxjdWxhdGVDYWNoZUhpdFJhdGUoKTogbnVtYmVyIHtcbiAgICAvLyBUaGlzIHdvdWxkIGJlIGltcGxlbWVudGVkIHdpdGggYWN0dWFsIG1ldHJpY3MgdHJhY2tpbmdcbiAgICByZXR1cm4gdGhpcy5tZW1vcnlDYWNoZS5nZXRTdGF0cygpLmhpdFJhdGU7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBDYWxjdWxhdGUgYXZlcmFnZSBhY2Nlc3MgdGltZSAocGxhY2Vob2xkZXIgZm9yIGZ1dHVyZSBpbXBsZW1lbnRhdGlvbilcbiAgICovXG4gIHByaXZhdGUgY2FsY3VsYXRlQXZlcmFnZUFjY2Vzc1RpbWUoKTogbnVtYmVyIHtcbiAgICAvLyBUaGlzIHdvdWxkIGJlIGltcGxlbWVudGVkIHdpdGggYWN0dWFsIHRpbWluZyBtZXRyaWNzXG4gICAgcmV0dXJuIDU7IC8vIFBsYWNlaG9sZGVyIHZhbHVlXG4gIH1cbn0iXX0=
@@ -0,0 +1,93 @@
1
+ /**
2
+ * High-performance LRU Cache with memory monitoring and automatic cleanup
3
+ * Optimized for large-scale indexing operations with configurable memory limits
4
+ */
5
+ export interface LRUCacheOptions {
6
+ maxSize: number;
7
+ maxMemoryMB?: number;
8
+ ttlMs?: number;
9
+ onEviction?: (key: string, value: any) => void;
10
+ }
11
+ export interface CacheStats {
12
+ size: number;
13
+ maxSize: number;
14
+ hitCount: number;
15
+ missCount: number;
16
+ evictionCount: number;
17
+ memoryUsageMB: number;
18
+ hitRate: number;
19
+ }
20
+ export declare class LRUCache<T> {
21
+ private readonly maxSize;
22
+ private readonly maxMemoryBytes;
23
+ private readonly ttlMs;
24
+ private readonly onEviction?;
25
+ private cache;
26
+ private head;
27
+ private tail;
28
+ private currentMemoryBytes;
29
+ private hitCount;
30
+ private missCount;
31
+ private evictionCount;
32
+ constructor(options: LRUCacheOptions);
33
+ /**
34
+ * Get value from cache with automatic cleanup
35
+ */
36
+ get(key: string): T | null;
37
+ /**
38
+ * Set value in cache with automatic eviction
39
+ */
40
+ set(key: string, value: T): void;
41
+ /**
42
+ * Delete specific key from cache
43
+ */
44
+ delete(key: string): boolean;
45
+ /**
46
+ * Check if key exists in cache
47
+ */
48
+ has(key: string): boolean;
49
+ /**
50
+ * Clear all entries from cache
51
+ */
52
+ clear(): void;
53
+ /**
54
+ * Get cache statistics
55
+ */
56
+ getStats(): CacheStats;
57
+ /**
58
+ * Get all keys in access order (most recent first)
59
+ */
60
+ keys(): string[];
61
+ /**
62
+ * Get current memory usage in MB
63
+ */
64
+ getMemoryUsageMB(): number;
65
+ /**
66
+ * Manually trigger cleanup of expired entries
67
+ */
68
+ cleanup(): number;
69
+ private moveToFront;
70
+ private addToFront;
71
+ private removeNode;
72
+ private evictIfNecessary;
73
+ private evictLeastRecentlyUsed;
74
+ private estimateSize;
75
+ }
76
+ /**
77
+ * Factory for creating optimized LRU caches for different use cases
78
+ */
79
+ export declare class CacheFactory {
80
+ /**
81
+ * Create cache optimized for search results
82
+ */
83
+ static createSearchResultCache<T>(options?: Partial<LRUCacheOptions>): LRUCache<T>;
84
+ /**
85
+ * Create cache optimized for index data
86
+ */
87
+ static createIndexCache<T>(options?: Partial<LRUCacheOptions>): LRUCache<T>;
88
+ /**
89
+ * Create cache optimized for API responses
90
+ */
91
+ static createAPICache<T>(options?: Partial<LRUCacheOptions>): LRUCache<T>;
92
+ }
93
+ //# sourceMappingURL=LRUCache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LRUCache.d.ts","sourceRoot":"","sources":["../../src/cache/LRUCache.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;CAChD;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;CACjB;AAWD,qBAAa,QAAQ,CAAC,CAAC;IACrB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAkC;IAE9D,OAAO,CAAC,KAAK,CAAmC;IAChD,OAAO,CAAC,IAAI,CAA6B;IACzC,OAAO,CAAC,IAAI,CAA6B;IACzC,OAAO,CAAC,kBAAkB,CAAK;IAG/B,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,aAAa,CAAK;gBAEd,OAAO,EAAE,eAAe;IAOpC;;OAEG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI;IAqB1B;;OAEG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI;IAgChC;;OAEG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAiB5B;;OAEG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAezB;;OAEG;IACH,KAAK,IAAI,IAAI;IAcb;;OAEG;IACH,QAAQ,IAAI,UAAU;IAYtB;;OAEG;IACH,IAAI,IAAI,MAAM,EAAE;IAYhB;;OAEG;IACH,gBAAgB,IAAI,MAAM;IAI1B;;OAEG;IACH,OAAO,IAAI,MAAM;IAuBjB,OAAO,CAAC,WAAW;IAYnB,OAAO,CAAC,UAAU;IAelB,OAAO,CAAC,UAAU;IAclB,OAAO,CAAC,gBAAgB;IAiBxB,OAAO,CAAC,sBAAsB;IAgB9B,OAAO,CAAC,YAAY;CA8BrB;AAED;;GAEG;AACH,qBAAa,YAAY;IACvB;;OAEG;IACH,MAAM,CAAC,uBAAuB,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC;IASlF;;OAEG;IACH,MAAM,CAAC,gBAAgB,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC;IAS3E;;OAEG;IACH,MAAM,CAAC,cAAc,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC;CAQ1E"}