@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.
- package/CHANGELOG.md +56 -0
- package/README.md +494 -111
- package/data/agents/code-reviewer.md +8 -1
- package/data/agents/research-assistant.md +8 -1
- package/data/agents/task-manager.md +8 -1
- package/data/ensembles/business-advisor.md +8 -1
- package/data/ensembles/creative-studio.md +8 -1
- package/data/ensembles/development-team.md +8 -1
- package/data/ensembles/security-analysis-team.md +8 -1
- package/data/memories/conversation-history.md +8 -1
- package/data/memories/learning-progress.md +8 -1
- package/data/memories/project-context.md +8 -1
- package/data/personas/business-consultant.md +8 -1
- package/data/personas/creative-writer.md +8 -1
- package/data/personas/debug-detective.md +8 -1
- package/data/personas/eli5-explainer.md +8 -1
- package/data/personas/security-analyst.md +8 -1
- package/data/personas/technical-analyst.md +8 -1
- package/data/skills/code-review.md +8 -1
- package/data/skills/creative-writing.md +8 -1
- package/data/skills/data-analysis.md +8 -1
- package/data/skills/penetration-testing.md +8 -1
- package/data/skills/research.md +8 -1
- package/data/skills/threat-modeling.md +8 -1
- package/data/skills/translation.md +8 -1
- package/data/templates/code-documentation.md +8 -1
- package/data/templates/email-professional.md +8 -1
- package/data/templates/meeting-notes.md +8 -1
- package/data/templates/penetration-test-report.md +8 -1
- package/data/templates/project-brief.md +8 -1
- package/data/templates/report-executive.md +8 -1
- package/data/templates/security-vulnerability-report.md +8 -1
- package/data/templates/threat-assessment-report.md +8 -1
- package/dist/auth/GitHubAuthManager.d.ts +6 -1
- package/dist/auth/GitHubAuthManager.d.ts.map +1 -1
- package/dist/auth/GitHubAuthManager.js +45 -18
- package/dist/benchmarks/IndexPerformanceBenchmark.d.ts +98 -0
- package/dist/benchmarks/IndexPerformanceBenchmark.d.ts.map +1 -0
- package/dist/benchmarks/IndexPerformanceBenchmark.js +531 -0
- package/dist/cache/CollectionCache.d.ts.map +1 -1
- package/dist/cache/CollectionCache.js +13 -3
- package/dist/cache/CollectionIndexCache.d.ts +77 -0
- package/dist/cache/CollectionIndexCache.d.ts.map +1 -0
- package/dist/cache/CollectionIndexCache.js +349 -0
- package/dist/cache/LRUCache.d.ts +93 -0
- package/dist/cache/LRUCache.d.ts.map +1 -0
- package/dist/cache/LRUCache.js +299 -0
- package/dist/cache/index.d.ts +1 -0
- package/dist/cache/index.d.ts.map +1 -1
- package/dist/cache/index.js +2 -1
- package/dist/collection/CollectionBrowser.d.ts +21 -1
- package/dist/collection/CollectionBrowser.d.ts.map +1 -1
- package/dist/collection/CollectionBrowser.js +130 -10
- package/dist/collection/CollectionIndexManager.d.ts +151 -0
- package/dist/collection/CollectionIndexManager.d.ts.map +1 -0
- package/dist/collection/CollectionIndexManager.js +499 -0
- package/dist/collection/CollectionSearch.d.ts +55 -0
- package/dist/collection/CollectionSearch.d.ts.map +1 -1
- package/dist/collection/CollectionSearch.js +338 -13
- package/dist/collection/CollectionSeeder.d.ts.map +1 -1
- package/dist/collection/CollectionSeeder.js +38 -1
- package/dist/collection/ElementInstaller.d.ts +31 -0
- package/dist/collection/ElementInstaller.d.ts.map +1 -1
- package/dist/collection/ElementInstaller.js +77 -15
- package/dist/collection/PersonaSubmitter.d.ts +1 -1
- package/dist/collection/PersonaSubmitter.d.ts.map +1 -1
- package/dist/collection/PersonaSubmitter.js +2 -2
- package/dist/collection/index.d.ts +1 -0
- package/dist/collection/index.d.ts.map +1 -1
- package/dist/collection/index.js +2 -1
- package/dist/config/ConfigManager.d.ts +78 -0
- package/dist/config/ConfigManager.d.ts.map +1 -0
- package/dist/config/ConfigManager.js +216 -0
- package/dist/config/element-types.d.ts +135 -0
- package/dist/config/element-types.d.ts.map +1 -0
- package/dist/config/element-types.js +108 -0
- package/dist/config/index.d.ts +2 -0
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +3 -1
- package/dist/config/portfolio-constants.d.ts +83 -0
- package/dist/config/portfolio-constants.d.ts.map +1 -0
- package/dist/config/portfolio-constants.js +99 -0
- package/dist/elements/BaseElement.d.ts +14 -2
- package/dist/elements/BaseElement.d.ts.map +1 -1
- package/dist/elements/BaseElement.js +88 -6
- package/dist/elements/agents/Agent.d.ts +10 -1
- package/dist/elements/agents/Agent.d.ts.map +1 -1
- package/dist/elements/agents/Agent.js +66 -19
- package/dist/elements/agents/AgentManager.d.ts +2 -0
- package/dist/elements/agents/AgentManager.d.ts.map +1 -1
- package/dist/elements/agents/AgentManager.js +12 -10
- package/dist/elements/skills/Skill.d.ts +10 -1
- package/dist/elements/skills/Skill.d.ts.map +1 -1
- package/dist/elements/skills/Skill.js +40 -3
- package/dist/elements/skills/SkillManager.d.ts +1 -0
- package/dist/elements/skills/SkillManager.d.ts.map +1 -1
- package/dist/elements/skills/SkillManager.js +10 -4
- package/dist/elements/templates/Template.d.ts +10 -1
- package/dist/elements/templates/Template.d.ts.map +1 -1
- package/dist/elements/templates/Template.js +35 -18
- package/dist/elements/templates/TemplateManager.d.ts +1 -1
- package/dist/elements/templates/TemplateManager.d.ts.map +1 -1
- package/dist/elements/templates/TemplateManager.js +6 -5
- package/dist/generated/version.d.ts +2 -2
- package/dist/generated/version.js +3 -3
- package/dist/index.barrel.d.ts +1 -2
- package/dist/index.barrel.d.ts.map +1 -1
- package/dist/index.barrel.js +2 -4
- package/dist/index.d.ts +143 -25
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1883 -310
- package/dist/persona/PersonaElement.d.ts +10 -0
- package/dist/persona/PersonaElement.d.ts.map +1 -1
- package/dist/persona/PersonaElement.js +55 -32
- package/dist/persona/PersonaElementManager.d.ts.map +1 -1
- package/dist/persona/PersonaElementManager.js +13 -11
- package/dist/persona/PersonaLoader.d.ts.map +1 -1
- package/dist/persona/PersonaLoader.js +8 -2
- package/dist/persona/export-import/PersonaImporter.d.ts.map +1 -1
- package/dist/persona/export-import/PersonaImporter.js +24 -5
- package/dist/persona/export-import/PersonaSharer.d.ts +21 -0
- package/dist/persona/export-import/PersonaSharer.d.ts.map +1 -1
- package/dist/persona/export-import/PersonaSharer.js +198 -22
- package/dist/portfolio/DefaultElementProvider.d.ts +90 -0
- package/dist/portfolio/DefaultElementProvider.d.ts.map +1 -1
- package/dist/portfolio/DefaultElementProvider.js +499 -7
- package/dist/portfolio/GitHubPortfolioIndexer.d.ts +129 -0
- package/dist/portfolio/GitHubPortfolioIndexer.d.ts.map +1 -0
- package/dist/portfolio/GitHubPortfolioIndexer.js +475 -0
- package/dist/portfolio/MigrationManager.d.ts.map +1 -1
- package/dist/portfolio/MigrationManager.js +136 -3
- package/dist/portfolio/PortfolioIndexManager.d.ts +130 -0
- package/dist/portfolio/PortfolioIndexManager.d.ts.map +1 -0
- package/dist/portfolio/PortfolioIndexManager.js +478 -0
- package/dist/portfolio/PortfolioManager.d.ts +5 -0
- package/dist/portfolio/PortfolioManager.d.ts.map +1 -1
- package/dist/portfolio/PortfolioManager.js +61 -20
- package/dist/portfolio/PortfolioRepoManager.d.ts +75 -0
- package/dist/portfolio/PortfolioRepoManager.d.ts.map +1 -0
- package/dist/portfolio/PortfolioRepoManager.js +337 -0
- package/dist/portfolio/UnifiedIndexManager.d.ts +388 -0
- package/dist/portfolio/UnifiedIndexManager.d.ts.map +1 -0
- package/dist/portfolio/UnifiedIndexManager.js +1434 -0
- package/dist/portfolio/index.d.ts +15 -0
- package/dist/portfolio/index.d.ts.map +1 -0
- package/dist/portfolio/index.js +15 -0
- package/dist/portfolio/types.d.ts +7 -0
- package/dist/portfolio/types.d.ts.map +1 -1
- package/dist/portfolio/types.js +6 -1
- package/dist/security/InputValidator.d.ts.map +1 -1
- package/dist/security/InputValidator.js +50 -48
- package/dist/security/audit/SecurityAuditor.d.ts.map +1 -1
- package/dist/security/audit/SecurityAuditor.js +17 -9
- package/dist/security/audit/config/suppressions.d.ts.map +1 -1
- package/dist/security/audit/config/suppressions.js +19 -3
- package/dist/security/contentValidator.d.ts +2 -0
- package/dist/security/contentValidator.d.ts.map +1 -1
- package/dist/security/contentValidator.js +115 -4
- package/dist/security/secureYamlParser.d.ts +1 -0
- package/dist/security/secureYamlParser.d.ts.map +1 -1
- package/dist/security/secureYamlParser.js +29 -7
- package/dist/security/securityMonitor.d.ts +1 -1
- package/dist/security/securityMonitor.d.ts.map +1 -1
- package/dist/security/securityMonitor.js +1 -1
- package/dist/security/tokenManager.d.ts +1 -1
- package/dist/security/tokenManager.d.ts.map +1 -1
- package/dist/security/tokenManager.js +30 -10
- package/dist/server/ServerSetup.d.ts +22 -2
- package/dist/server/ServerSetup.d.ts.map +1 -1
- package/dist/server/ServerSetup.js +77 -12
- package/dist/server/tools/AuthTools.d.ts.map +1 -1
- package/dist/server/tools/AuthTools.js +33 -1
- package/dist/server/tools/BuildInfoTools.d.ts +25 -0
- package/dist/server/tools/BuildInfoTools.d.ts.map +1 -0
- package/dist/server/tools/BuildInfoTools.js +36 -0
- package/dist/server/tools/CollectionTools.d.ts.map +1 -1
- package/dist/server/tools/CollectionTools.js +55 -46
- package/dist/server/tools/ConfigTools.d.ts.map +1 -1
- package/dist/server/tools/ConfigTools.js +29 -1
- package/dist/server/tools/PersonaTools.d.ts +4 -2
- package/dist/server/tools/PersonaTools.d.ts.map +1 -1
- package/dist/server/tools/PersonaTools.js +5 -152
- package/dist/server/tools/PortfolioTools.d.ts +12 -0
- package/dist/server/tools/PortfolioTools.d.ts.map +1 -0
- package/dist/server/tools/PortfolioTools.js +221 -0
- package/dist/server/tools/index.d.ts +3 -1
- package/dist/server/tools/index.d.ts.map +1 -1
- package/dist/server/tools/index.js +4 -2
- package/dist/server/types.d.ts +40 -5
- package/dist/server/types.d.ts.map +1 -1
- package/dist/server/types.js +1 -1
- package/dist/services/BuildInfoService.d.ts +84 -0
- package/dist/services/BuildInfoService.d.ts.map +1 -0
- package/dist/services/BuildInfoService.js +271 -0
- package/dist/tools/portfolio/PortfolioElementAdapter.d.ts +54 -0
- package/dist/tools/portfolio/PortfolioElementAdapter.d.ts.map +1 -0
- package/dist/tools/portfolio/PortfolioElementAdapter.js +229 -0
- package/dist/tools/portfolio/submitToPortfolioTool.d.ts +164 -0
- package/dist/tools/portfolio/submitToPortfolioTool.d.ts.map +1 -0
- package/dist/tools/portfolio/submitToPortfolioTool.js +1523 -0
- package/dist/tools/portfolio/types.d.ts +41 -0
- package/dist/tools/portfolio/types.d.ts.map +1 -0
- package/dist/tools/portfolio/types.js +15 -0
- package/dist/types/collection.d.ts +51 -0
- package/dist/types/collection.d.ts.map +1 -1
- package/dist/types/collection.js +1 -1
- package/dist/utils/EarlyTerminationSearch.d.ts +41 -0
- package/dist/utils/EarlyTerminationSearch.d.ts.map +1 -0
- package/dist/utils/EarlyTerminationSearch.js +164 -0
- package/dist/utils/ErrorHandler.d.ts +86 -0
- package/dist/utils/ErrorHandler.d.ts.map +1 -0
- package/dist/utils/ErrorHandler.js +201 -0
- package/dist/utils/FileDiscoveryUtil.d.ts +53 -0
- package/dist/utils/FileDiscoveryUtil.d.ts.map +1 -0
- package/dist/utils/FileDiscoveryUtil.js +169 -0
- package/dist/utils/GitHubRateLimiter.d.ts +88 -0
- package/dist/utils/GitHubRateLimiter.d.ts.map +1 -0
- package/dist/utils/GitHubRateLimiter.js +315 -0
- package/dist/utils/PerformanceMonitor.d.ts +134 -0
- package/dist/utils/PerformanceMonitor.d.ts.map +1 -0
- package/dist/utils/PerformanceMonitor.js +347 -0
- package/dist/utils/RateLimiter.d.ts.map +1 -0
- package/dist/utils/RateLimiter.js +172 -0
- package/dist/utils/SecureDownloader.d.ts +241 -0
- package/dist/utils/SecureDownloader.d.ts.map +1 -0
- package/dist/utils/SecureDownloader.js +759 -0
- package/dist/utils/ToolCache.d.ts +82 -0
- package/dist/utils/ToolCache.d.ts.map +1 -0
- package/dist/utils/ToolCache.js +196 -0
- package/dist/utils/errorCodes.d.ts +136 -0
- package/dist/utils/errorCodes.d.ts.map +1 -0
- package/dist/utils/errorCodes.js +87 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +4 -1
- package/dist/utils/installation.d.ts +1 -1
- package/dist/utils/installation.d.ts.map +1 -1
- package/dist/utils/installation.js +9 -8
- package/dist/utils/searchUtils.d.ts +31 -0
- package/dist/utils/searchUtils.d.ts.map +1 -1
- package/dist/utils/searchUtils.js +62 -1
- package/package.json +17 -7
- package/dist/config/updateConfig.d.ts +0 -84
- package/dist/config/updateConfig.d.ts.map +0 -1
- package/dist/config/updateConfig.js +0 -148
- package/dist/server/tools/UpdateTools.d.ts +0 -10
- package/dist/server/tools/UpdateTools.d.ts.map +0 -1
- package/dist/server/tools/UpdateTools.js +0 -85
- package/dist/update/BackupManager.d.ts +0 -63
- package/dist/update/BackupManager.d.ts.map +0 -1
- package/dist/update/BackupManager.js +0 -370
- package/dist/update/DependencyChecker.d.ts +0 -41
- package/dist/update/DependencyChecker.d.ts.map +0 -1
- package/dist/update/DependencyChecker.js +0 -132
- package/dist/update/RateLimiter.d.ts.map +0 -1
- package/dist/update/RateLimiter.js +0 -172
- package/dist/update/SignatureVerifier.d.ts +0 -71
- package/dist/update/SignatureVerifier.d.ts.map +0 -1
- package/dist/update/SignatureVerifier.js +0 -214
- package/dist/update/UpdateChecker.d.ts +0 -132
- package/dist/update/UpdateChecker.d.ts.map +0 -1
- package/dist/update/UpdateChecker.js +0 -506
- package/dist/update/UpdateManager.d.ts +0 -60
- package/dist/update/UpdateManager.d.ts.map +0 -1
- package/dist/update/UpdateManager.js +0 -730
- package/dist/update/VersionManager.d.ts +0 -31
- package/dist/update/VersionManager.d.ts.map +0 -1
- package/dist/update/VersionManager.js +0 -181
- package/dist/update/index.d.ts +0 -9
- package/dist/update/index.d.ts.map +0 -1
- package/dist/update/index.js +0 -9
- /package/dist/{update → utils}/RateLimiter.d.ts +0 -0
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Comprehensive Performance Monitoring System
|
|
3
|
+
* Tracks search times, memory usage, cache performance, and system metrics
|
|
4
|
+
*/
|
|
5
|
+
import { logger } from './logger.js';
|
|
6
|
+
import { UnicodeValidator } from '../security/validators/unicodeValidator.js';
|
|
7
|
+
export class PerformanceMonitor {
|
|
8
|
+
static instance = null;
|
|
9
|
+
searchMetrics = [];
|
|
10
|
+
slowQueries = [];
|
|
11
|
+
memorySnapshots = [];
|
|
12
|
+
cacheMetrics = new Map();
|
|
13
|
+
// Configuration
|
|
14
|
+
maxMetricsHistory = 1000;
|
|
15
|
+
slowQueryThreshold = 100; // ms
|
|
16
|
+
memorySnapshotInterval = 30000; // 30 seconds
|
|
17
|
+
maxSlowQueries = 100;
|
|
18
|
+
// Timers and intervals
|
|
19
|
+
memoryMonitorInterval;
|
|
20
|
+
isMonitoring = false;
|
|
21
|
+
constructor() {
|
|
22
|
+
this.startMemoryMonitoring();
|
|
23
|
+
}
|
|
24
|
+
static getInstance() {
|
|
25
|
+
if (!this.instance) {
|
|
26
|
+
this.instance = new PerformanceMonitor();
|
|
27
|
+
}
|
|
28
|
+
return this.instance;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Start performance monitoring
|
|
32
|
+
*/
|
|
33
|
+
startMonitoring() {
|
|
34
|
+
if (this.isMonitoring) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
this.isMonitoring = true;
|
|
38
|
+
this.startMemoryMonitoring();
|
|
39
|
+
logger.info('Performance monitoring started', {
|
|
40
|
+
slowQueryThreshold: this.slowQueryThreshold,
|
|
41
|
+
maxMetricsHistory: this.maxMetricsHistory
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Stop performance monitoring
|
|
46
|
+
*/
|
|
47
|
+
stopMonitoring() {
|
|
48
|
+
this.isMonitoring = false;
|
|
49
|
+
if (this.memoryMonitorInterval) {
|
|
50
|
+
clearInterval(this.memoryMonitorInterval);
|
|
51
|
+
this.memoryMonitorInterval = undefined;
|
|
52
|
+
}
|
|
53
|
+
logger.info('Performance monitoring stopped');
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Record search performance metrics
|
|
57
|
+
*/
|
|
58
|
+
recordSearch(metrics) {
|
|
59
|
+
if (!this.isMonitoring) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
// Normalize query string to prevent Unicode-based attacks
|
|
63
|
+
const validationResult = UnicodeValidator.normalize(metrics.query);
|
|
64
|
+
const normalizedMetrics = {
|
|
65
|
+
...metrics,
|
|
66
|
+
query: validationResult.normalizedContent
|
|
67
|
+
};
|
|
68
|
+
this.searchMetrics.push(normalizedMetrics);
|
|
69
|
+
// Check if it's a slow query (use normalized metrics)
|
|
70
|
+
if (normalizedMetrics.duration > this.slowQueryThreshold) {
|
|
71
|
+
this.recordSlowQuery({
|
|
72
|
+
query: normalizedMetrics.query,
|
|
73
|
+
duration: normalizedMetrics.duration,
|
|
74
|
+
threshold: this.slowQueryThreshold,
|
|
75
|
+
sources: normalizedMetrics.sources,
|
|
76
|
+
resultCount: normalizedMetrics.resultCount,
|
|
77
|
+
memoryUsage: normalizedMetrics.memoryAfter,
|
|
78
|
+
timestamp: normalizedMetrics.timestamp
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
// Trim history if needed
|
|
82
|
+
if (this.searchMetrics.length > this.maxMetricsHistory) {
|
|
83
|
+
this.searchMetrics = this.searchMetrics.slice(-this.maxMetricsHistory);
|
|
84
|
+
}
|
|
85
|
+
// Log significant performance events (use normalized metrics)
|
|
86
|
+
if (normalizedMetrics.duration > this.slowQueryThreshold * 2) {
|
|
87
|
+
logger.warn('Very slow search detected', {
|
|
88
|
+
query: normalizedMetrics.query.substring(0, 50),
|
|
89
|
+
duration: normalizedMetrics.duration,
|
|
90
|
+
resultCount: normalizedMetrics.resultCount,
|
|
91
|
+
sources: normalizedMetrics.sources
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Record cache performance metrics
|
|
97
|
+
*/
|
|
98
|
+
recordCachePerformance(cacheName, stats) {
|
|
99
|
+
if (!this.isMonitoring) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
// Normalize cache name to prevent Unicode-based attacks
|
|
103
|
+
const validationResult = UnicodeValidator.normalize(cacheName);
|
|
104
|
+
const normalizedCacheName = validationResult.normalizedContent;
|
|
105
|
+
this.cacheMetrics.set(normalizedCacheName, stats);
|
|
106
|
+
// Log cache performance warnings (use normalized cache name)
|
|
107
|
+
if (stats.hitRate < 0.5) {
|
|
108
|
+
logger.warn('Low cache hit rate detected', {
|
|
109
|
+
cache: normalizedCacheName,
|
|
110
|
+
hitRate: stats.hitRate,
|
|
111
|
+
totalOperations: stats.totalHits + stats.totalMisses
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Get comprehensive performance metrics
|
|
117
|
+
*/
|
|
118
|
+
getMetrics() {
|
|
119
|
+
return {
|
|
120
|
+
searchTimes: this.searchMetrics.map(m => m.duration),
|
|
121
|
+
memoryUsage: this.memorySnapshots.slice(-100), // Last 100 snapshots
|
|
122
|
+
cacheStats: this.aggregateCacheStats(),
|
|
123
|
+
systemStats: this.getSystemStats(),
|
|
124
|
+
timestamp: new Date()
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Get search performance statistics
|
|
129
|
+
*/
|
|
130
|
+
getSearchStats() {
|
|
131
|
+
if (this.searchMetrics.length === 0) {
|
|
132
|
+
return {
|
|
133
|
+
totalSearches: 0,
|
|
134
|
+
averageTime: 0,
|
|
135
|
+
medianTime: 0,
|
|
136
|
+
p95Time: 0,
|
|
137
|
+
p99Time: 0,
|
|
138
|
+
slowQueries: 0,
|
|
139
|
+
cacheHitRate: 0
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
const times = this.searchMetrics.map(m => m.duration).sort((a, b) => a - b);
|
|
143
|
+
const cacheHits = this.searchMetrics.filter(m => m.cacheHit).length;
|
|
144
|
+
return {
|
|
145
|
+
totalSearches: this.searchMetrics.length,
|
|
146
|
+
averageTime: times.reduce((sum, time) => sum + time, 0) / times.length,
|
|
147
|
+
medianTime: times[Math.floor(times.length / 2)],
|
|
148
|
+
p95Time: times[Math.floor(times.length * 0.95)],
|
|
149
|
+
p99Time: times[Math.floor(times.length * 0.99)],
|
|
150
|
+
slowQueries: this.slowQueries.length,
|
|
151
|
+
cacheHitRate: cacheHits / this.searchMetrics.length
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Get memory usage statistics
|
|
156
|
+
*/
|
|
157
|
+
getMemoryStats() {
|
|
158
|
+
if (this.memorySnapshots.length === 0) {
|
|
159
|
+
const current = this.takeMemorySnapshot();
|
|
160
|
+
return {
|
|
161
|
+
currentUsage: current,
|
|
162
|
+
peakUsage: current,
|
|
163
|
+
averageUsage: current,
|
|
164
|
+
growthRate: 0
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
const current = this.memorySnapshots[this.memorySnapshots.length - 1];
|
|
168
|
+
const peak = this.memorySnapshots.reduce((max, snapshot) => snapshot.heapUsed > max.heapUsed ? snapshot : max);
|
|
169
|
+
const totalHeap = this.memorySnapshots.reduce((sum, snapshot) => sum + snapshot.heapUsed, 0);
|
|
170
|
+
const totalRss = this.memorySnapshots.reduce((sum, snapshot) => sum + snapshot.rss, 0);
|
|
171
|
+
const average = {
|
|
172
|
+
heapUsed: totalHeap / this.memorySnapshots.length,
|
|
173
|
+
heapTotal: this.memorySnapshots.reduce((sum, s) => sum + s.heapTotal, 0) / this.memorySnapshots.length,
|
|
174
|
+
rss: totalRss / this.memorySnapshots.length,
|
|
175
|
+
external: this.memorySnapshots.reduce((sum, s) => sum + s.external, 0) / this.memorySnapshots.length,
|
|
176
|
+
timestamp: new Date()
|
|
177
|
+
};
|
|
178
|
+
// Calculate growth rate (MB per minute)
|
|
179
|
+
let growthRate = 0;
|
|
180
|
+
if (this.memorySnapshots.length > 1) {
|
|
181
|
+
const oldest = this.memorySnapshots[0];
|
|
182
|
+
const timeDiff = (current.timestamp.getTime() - oldest.timestamp.getTime()) / 60000; // minutes
|
|
183
|
+
const memoryDiff = (current.heapUsed - oldest.heapUsed) / (1024 * 1024); // MB
|
|
184
|
+
growthRate = timeDiff > 0 ? memoryDiff / timeDiff : 0;
|
|
185
|
+
}
|
|
186
|
+
return {
|
|
187
|
+
currentUsage: current,
|
|
188
|
+
peakUsage: peak,
|
|
189
|
+
averageUsage: average,
|
|
190
|
+
growthRate
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Get slow queries with analysis
|
|
195
|
+
*/
|
|
196
|
+
getSlowQueries(limit = 10) {
|
|
197
|
+
return this.slowQueries
|
|
198
|
+
.sort((a, b) => b.duration - a.duration)
|
|
199
|
+
.slice(0, limit);
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Analyze performance trends
|
|
203
|
+
*/
|
|
204
|
+
analyzeTrends() {
|
|
205
|
+
const recommendations = [];
|
|
206
|
+
// Analyze search performance trend
|
|
207
|
+
let performanceTrend = 'stable';
|
|
208
|
+
if (this.searchMetrics.length > 10) {
|
|
209
|
+
const recent = this.searchMetrics.slice(-10).map(m => m.duration);
|
|
210
|
+
const older = this.searchMetrics.slice(-20, -10).map(m => m.duration);
|
|
211
|
+
if (recent.length > 0 && older.length > 0) {
|
|
212
|
+
const recentAvg = recent.reduce((sum, t) => sum + t, 0) / recent.length;
|
|
213
|
+
const olderAvg = older.reduce((sum, t) => sum + t, 0) / older.length;
|
|
214
|
+
if (recentAvg > olderAvg * 1.2) {
|
|
215
|
+
performanceTrend = 'degrading';
|
|
216
|
+
recommendations.push('Search performance is degrading. Consider cache optimization or index rebuilding.');
|
|
217
|
+
}
|
|
218
|
+
else if (recentAvg < olderAvg * 0.8) {
|
|
219
|
+
performanceTrend = 'improving';
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
// Analyze memory trend
|
|
224
|
+
const memoryStats = this.getMemoryStats();
|
|
225
|
+
let memoryTrend = 'stable';
|
|
226
|
+
if (memoryStats.growthRate > 1) { // Growing by more than 1MB/minute
|
|
227
|
+
memoryTrend = 'growing';
|
|
228
|
+
recommendations.push('Memory usage is growing rapidly. Consider cache cleanup or memory limits.');
|
|
229
|
+
}
|
|
230
|
+
else if (memoryStats.growthRate < -1) {
|
|
231
|
+
memoryTrend = 'shrinking';
|
|
232
|
+
}
|
|
233
|
+
// Cache performance recommendations
|
|
234
|
+
const cacheStats = this.aggregateCacheStats();
|
|
235
|
+
if (cacheStats.hitRate < 0.6) {
|
|
236
|
+
recommendations.push('Cache hit rate is low. Consider adjusting cache size or TTL settings.');
|
|
237
|
+
}
|
|
238
|
+
// Slow query recommendations
|
|
239
|
+
if (this.slowQueries.length > 10) {
|
|
240
|
+
recommendations.push('Multiple slow queries detected. Consider query optimization or increased caching.');
|
|
241
|
+
}
|
|
242
|
+
return {
|
|
243
|
+
performanceTrend,
|
|
244
|
+
memoryTrend,
|
|
245
|
+
recommendations
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Reset all performance metrics
|
|
250
|
+
*/
|
|
251
|
+
reset() {
|
|
252
|
+
this.searchMetrics = [];
|
|
253
|
+
this.slowQueries = [];
|
|
254
|
+
this.memorySnapshots = [];
|
|
255
|
+
this.cacheMetrics.clear();
|
|
256
|
+
logger.info('Performance metrics reset');
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Export metrics for external analysis
|
|
260
|
+
*/
|
|
261
|
+
exportMetrics() {
|
|
262
|
+
const data = {
|
|
263
|
+
searchMetrics: this.searchMetrics,
|
|
264
|
+
slowQueries: this.slowQueries,
|
|
265
|
+
memorySnapshots: this.memorySnapshots,
|
|
266
|
+
cacheMetrics: Object.fromEntries(this.cacheMetrics),
|
|
267
|
+
exportTimestamp: new Date().toISOString()
|
|
268
|
+
};
|
|
269
|
+
return JSON.stringify(data, null, 2);
|
|
270
|
+
}
|
|
271
|
+
// Private methods
|
|
272
|
+
recordSlowQuery(query) {
|
|
273
|
+
this.slowQueries.push(query);
|
|
274
|
+
// Trim slow queries history
|
|
275
|
+
if (this.slowQueries.length > this.maxSlowQueries) {
|
|
276
|
+
this.slowQueries = this.slowQueries.slice(-this.maxSlowQueries);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
startMemoryMonitoring() {
|
|
280
|
+
if (this.memoryMonitorInterval) {
|
|
281
|
+
clearInterval(this.memoryMonitorInterval);
|
|
282
|
+
}
|
|
283
|
+
this.memoryMonitorInterval = setInterval(() => {
|
|
284
|
+
if (this.isMonitoring) {
|
|
285
|
+
const snapshot = this.takeMemorySnapshot();
|
|
286
|
+
this.memorySnapshots.push(snapshot);
|
|
287
|
+
// Trim memory snapshots (keep last 200)
|
|
288
|
+
if (this.memorySnapshots.length > 200) {
|
|
289
|
+
this.memorySnapshots = this.memorySnapshots.slice(-200);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}, this.memorySnapshotInterval);
|
|
293
|
+
}
|
|
294
|
+
takeMemorySnapshot() {
|
|
295
|
+
const memUsage = process.memoryUsage();
|
|
296
|
+
return {
|
|
297
|
+
heapUsed: memUsage.heapUsed,
|
|
298
|
+
heapTotal: memUsage.heapTotal,
|
|
299
|
+
rss: memUsage.rss,
|
|
300
|
+
external: memUsage.external,
|
|
301
|
+
timestamp: new Date()
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
aggregateCacheStats() {
|
|
305
|
+
if (this.cacheMetrics.size === 0) {
|
|
306
|
+
return {
|
|
307
|
+
hitRate: 0,
|
|
308
|
+
avgHitTime: 0,
|
|
309
|
+
avgMissTime: 0,
|
|
310
|
+
totalHits: 0,
|
|
311
|
+
totalMisses: 0,
|
|
312
|
+
evictions: 0
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
let totalHits = 0;
|
|
316
|
+
let totalMisses = 0;
|
|
317
|
+
let totalEvictions = 0;
|
|
318
|
+
let weightedHitTime = 0;
|
|
319
|
+
let weightedMissTime = 0;
|
|
320
|
+
for (const stats of this.cacheMetrics.values()) {
|
|
321
|
+
totalHits += stats.totalHits;
|
|
322
|
+
totalMisses += stats.totalMisses;
|
|
323
|
+
totalEvictions += stats.evictions;
|
|
324
|
+
weightedHitTime += stats.avgHitTime * stats.totalHits;
|
|
325
|
+
weightedMissTime += stats.avgMissTime * stats.totalMisses;
|
|
326
|
+
}
|
|
327
|
+
return {
|
|
328
|
+
hitRate: totalHits + totalMisses > 0 ? totalHits / (totalHits + totalMisses) : 0,
|
|
329
|
+
avgHitTime: totalHits > 0 ? weightedHitTime / totalHits : 0,
|
|
330
|
+
avgMissTime: totalMisses > 0 ? weightedMissTime / totalMisses : 0,
|
|
331
|
+
totalHits,
|
|
332
|
+
totalMisses,
|
|
333
|
+
evictions: totalEvictions
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
getSystemStats() {
|
|
337
|
+
const os = require('os');
|
|
338
|
+
return {
|
|
339
|
+
cpuUsage: process.cpuUsage().user / 1000000, // Convert to seconds
|
|
340
|
+
loadAverage: os.loadavg(),
|
|
341
|
+
freeMemory: os.freemem(),
|
|
342
|
+
totalMemory: os.totalmem(),
|
|
343
|
+
uptime: process.uptime()
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUGVyZm9ybWFuY2VNb25pdG9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3V0aWxzL1BlcmZvcm1hbmNlTW9uaXRvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7O0dBR0c7QUFFSCxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQ3JDLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLDRDQUE0QyxDQUFDO0FBd0Q5RSxNQUFNLE9BQU8sa0JBQWtCO0lBQ3JCLE1BQU0sQ0FBQyxRQUFRLEdBQThCLElBQUksQ0FBQztJQUVsRCxhQUFhLEdBQW9CLEVBQUUsQ0FBQztJQUNwQyxXQUFXLEdBQWdCLEVBQUUsQ0FBQztJQUM5QixlQUFlLEdBQWtCLEVBQUUsQ0FBQztJQUNwQyxZQUFZLEdBQWtDLElBQUksR0FBRyxFQUFFLENBQUM7SUFFaEUsZ0JBQWdCO0lBQ0MsaUJBQWlCLEdBQUcsSUFBSSxDQUFDO0lBQ3pCLGtCQUFrQixHQUFHLEdBQUcsQ0FBQyxDQUFDLEtBQUs7SUFDL0Isc0JBQXNCLEdBQUcsS0FBSyxDQUFDLENBQUMsYUFBYTtJQUM3QyxjQUFjLEdBQUcsR0FBRyxDQUFDO0lBRXRDLHVCQUF1QjtJQUNmLHFCQUFxQixDQUFrQjtJQUN2QyxZQUFZLEdBQUcsS0FBSyxDQUFDO0lBRTdCO1FBQ0UsSUFBSSxDQUFDLHFCQUFxQixFQUFFLENBQUM7SUFDL0IsQ0FBQztJQUVNLE1BQU0sQ0FBQyxXQUFXO1FBQ3ZCLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7WUFDbkIsSUFBSSxDQUFDLFFBQVEsR0FBRyxJQUFJLGtCQUFrQixFQUFFLENBQUM7UUFDM0MsQ0FBQztRQUNELE9BQU8sSUFBSSxDQUFDLFFBQVEsQ0FBQztJQUN2QixDQUFDO0lBRUQ7O09BRUc7SUFDSCxlQUFlO1FBQ2IsSUFBSSxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUM7WUFDdEIsT0FBTztRQUNULENBQUM7UUFF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QUFDLElBQUksR0FBRyxPQUFPLEVBQUUscUJBQXFCO1lBQ2xFLFdBQVcsRUFBRSxFQUFFLENBQUMsT0FBTyxFQUFFO1lBQ3pCLFVBQVUsRUFBRSxFQUFFLENBQUMsT0FBTyxFQUFFO1lBQ3hCLFdBQVcsRUFBRSxFQUFFLENBQUMsUUFBUSxFQUFFO1lBQzFCLE1BQU0sRUFBRSxPQUFPLENBQUMsTUFBTSxFQUFFO1NBQ3pCLENBQUM7SUFDSixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBDb21wcmVoZW5zaXZlIFBlcmZvcm1hbmNlIE1vbml0b3JpbmcgU3lzdGVtXG4gKiBUcmFja3Mgc2VhcmNoIHRpbWVzLCBtZW1vcnkgdXNhZ2UsIGNhY2hlIHBlcmZvcm1hbmNlLCBhbmQgc3lzdGVtIG1ldHJpY3NcbiAqL1xuXG5pbXBvcnQgeyBsb2dnZXIgfSBmcm9tICcuL2xvZ2dlci5qcyc7XG5pbXBvcnQgeyBVbmljb2RlVmFsaWRhdG9yIH0gZnJvbSAnLi4vc2VjdXJpdHkvdmFsaWRhdG9ycy91bmljb2RlVmFsaWRhdG9yLmpzJztcblxuZXhwb3J0IGludGVyZmFjZSBQZXJmb3JtYW5jZU1ldHJpY3Mge1xuICBzZWFyY2hUaW1lczogbnVtYmVyW107XG4gIG1lbW9yeVVzYWdlOiBNZW1vcnlVc2FnZVtdO1xuICBjYWNoZVN0YXRzOiBDYWNoZVBlcmZvcm1hbmNlO1xuICBzeXN0ZW1TdGF0czogU3lzdGVtU3RhdHM7XG4gIHRpbWVzdGFtcDogRGF0ZTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBNZW1vcnlVc2FnZSB7XG4gIGhlYXBVc2VkOiBudW1iZXI7XG4gIGhlYXBUb3RhbDogbnVtYmVyO1xuICByc3M6IG51bWJlcjtcbiAgZXh0ZXJuYWw6IG51bWJlcjtcbiAgdGltZXN0YW1wOiBEYXRlO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIENhY2hlUGVyZm9ybWFuY2Uge1xuICBoaXRSYXRlOiBudW1iZXI7XG4gIGF2Z0hpdFRpbWU6IG51bWJlcjtcbiAgYXZnTWlzc1RpbWU6IG51bWJlcjtcbiAgdG90YWxIaXRzOiBudW1iZXI7XG4gIHRvdGFsTWlzc2VzOiBudW1iZXI7XG4gIGV2aWN0aW9uczogbnVtYmVyO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFN5c3RlbVN0YXRzIHtcbiAgY3B1VXNhZ2U6IG51bWJlcjtcbiAgbG9hZEF2ZXJhZ2U6IG51bWJlcltdO1xuICBmcmVlTWVtb3J5OiBudW1iZXI7XG4gIHRvdGFsTWVtb3J5OiBudW1iZXI7XG4gIHVwdGltZTogbnVtYmVyO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFNlYXJjaE1ldHJpY3Mge1xuICBxdWVyeTogc3RyaW5nO1xuICBkdXJhdGlvbjogbnVtYmVyO1xuICByZXN1bHRDb3VudDogbnVtYmVyO1xuICBzb3VyY2VzOiBzdHJpbmdbXTtcbiAgY2FjaGVIaXQ6IGJvb2xlYW47XG4gIG1lbW9yeUJlZm9yZTogbnVtYmVyO1xuICBtZW1vcnlBZnRlcjogbnVtYmVyO1xuICB0aW1lc3RhbXA6IERhdGU7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgU2xvd1F1ZXJ5IHtcbiAgcXVlcnk6IHN0cmluZztcbiAgZHVyYXRpb246IG51bWJlcjtcbiAgdGhyZXNob2xkOiBudW1iZXI7XG4gIHNvdXJjZXM6IHN0cmluZ1tdO1xuICByZXN1bHRDb3VudDogbnVtYmVyO1xuICBtZW1vcnlVc2FnZTogbnVtYmVyO1xuICB0aW1lc3RhbXA6IERhdGU7XG59XG5cbmV4cG9ydCBjbGFzcyBQZXJmb3JtYW5jZU1vbml0b3Ige1xuICBwcml2YXRlIHN0YXRpYyBpbnN0YW5jZTogUGVyZm9ybWFuY2VNb25pdG9yIHwgbnVsbCA9IG51bGw7XG5cbiAgcHJpdmF0ZSBzZWFyY2hNZXRyaWNzOiBTZWFyY2hNZXRyaWNzW10gPSBbXTtcbiAgcHJpdmF0ZSBzbG93UXVlcmllczogU2xvd1F1ZXJ5W10gPSBbXTtcbiAgcHJpdmF0ZSBtZW1vcnlTbmFwc2hvdHM6IE1lbW9yeVVzYWdlW10gPSBbXTtcbiAgcHJpdmF0ZSBjYWNoZU1ldHJpY3M6IE1hcDxzdHJpbmcsIENhY2hlUGVyZm9ybWFuY2U+ID0gbmV3IE1hcCgpO1xuXG4gIC8vIENvbmZpZ3VyYXRpb25cbiAgcHJpdmF0ZSByZWFkb25seSBtYXhNZXRyaWNzSGlzdG9yeSA9IDEwMDA7XG4gIHByaXZhdGUgcmVhZG9ubHkgc2xvd1F1ZXJ5VGhyZXNob2xkID0gMTAwOyAvLyBtc1xuICBwcml2YXRlIHJlYWRvbmx5IG1lbW9yeVNuYXBzaG90SW50ZXJ2YWwgPSAzMDAwMDsgLy8gMzAgc2Vjb25kc1xuICBwcml2YXRlIHJlYWRvbmx5IG1heFNsb3dRdWVyaWVzID0gMTAwO1xuXG4gIC8vIFRpbWVycyBhbmQgaW50ZXJ2YWxzXG4gIHByaXZhdGUgbWVtb3J5TW9uaXRvckludGVydmFsPzogTm9kZUpTLlRpbWVvdXQ7XG4gIHByaXZhdGUgaXNNb25pdG9yaW5nID0gZmFsc2U7XG5cbiAgcHJpdmF0ZSBjb25zdHJ1Y3RvcigpIHtcbiAgICB0aGlzLnN0YXJ0TWVtb3J5TW9uaXRvcmluZygpO1xuICB9XG5cbiAgcHVibGljIHN0YXRpYyBnZXRJbnN0YW5jZSgpOiBQZXJmb3JtYW5jZU1vbml0b3Ige1xuICAgIGlmICghdGhpcy5pbnN0YW5jZSkge1xuICAgICAgdGhpcy5pbnN0YW5jZSA9IG5ldyBQZXJmb3JtYW5jZU1vbml0b3IoKTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuaW5zdGFuY2U7XG4gIH1cblxuICAvKipcbiAgICogU3RhcnQgcGVyZm9ybWFuY2UgbW9uaXRvcmluZ1xuICAgKi9cbiAgc3RhcnRNb25pdG9yaW5nKCk6IHZvaWQge1xuICAgIGlmICh0aGlzLmlzTW9uaXRvcmluZykge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRoaXMuaXNNb25pdG9yaW5nID0gdHJ1ZTtcbiAgICB0aGlzLnN0YXJ0TWVtb3J5TW9uaXRvcmluZygpO1xuICAgIFxuICAgIGxvZ2dlci5pbmZvKCdQZXJmb3JtYW5jZSBtb25pdG9yaW5nIHN0YXJ0ZWQnLCB7XG4gICAgICBzbG93UXVlcnlUaHJlc2hvbGQ6IHRoaXMuc2xvd1F1ZXJ5VGhyZXNob2xkLFxuICAgICAgbWF4TWV0cmljc0hpc3Rvcnk6IHRoaXMubWF4TWV0cmljc0hpc3RvcnlcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTdG9wIHBlcmZvcm1hbmNlIG1vbml0b3JpbmdcbiAgICovXG4gIHN0b3BNb25pdG9yaW5nKCk6IHZvaWQge1xuICAgIHRoaXMuaXNNb25pdG9yaW5nID0gZmFsc2U7XG4gICAgXG4gICAgaWYgKHRoaXMubWVtb3J5TW9uaXRvckludGVydmFsKSB7XG4gICAgICBjbGVhckludGVydmFsKHRoaXMubWVtb3J5TW9uaXRvckludGVydmFsKTtcbiAgICAgIHRoaXMubWVtb3J5TW9uaXRvckludGVydmFsID0gdW5kZWZpbmVkO1xuICAgIH1cblxuICAgIGxvZ2dlci5pbmZvKCdQZXJmb3JtYW5jZSBtb25pdG9yaW5nIHN0b3BwZWQnKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZWNvcmQgc2VhcmNoIHBlcmZvcm1hbmNlIG1ldHJpY3NcbiAgICovXG4gIHJlY29yZFNlYXJjaChtZXRyaWNzOiBTZWFyY2hNZXRyaWNzKTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLmlzTW9uaXRvcmluZykge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIE5vcm1hbGl6ZSBxdWVyeSBzdHJpbmcgdG8gcHJldmVudCBVbmljb2RlLWJhc2VkIGF0dGFja3NcbiAgICBjb25zdCB2YWxpZGF0aW9uUmVzdWx0ID0gVW5pY29kZVZhbGlkYXRvci5ub3JtYWxpemUobWV0cmljcy5xdWVyeSk7XG4gICAgY29uc3Qgbm9ybWFsaXplZE1ldHJpY3MgPSB7XG4gICAgICAuLi5tZXRyaWNzLFxuICAgICAgcXVlcnk6IHZhbGlkYXRpb25SZXN1bHQubm9ybWFsaXplZENvbnRlbnRcbiAgICB9O1xuXG4gICAgdGhpcy5zZWFyY2hNZXRyaWNzLnB1c2gobm9ybWFsaXplZE1ldHJpY3MpO1xuXG4gICAgLy8gQ2hlY2sgaWYgaXQncyBhIHNsb3cgcXVlcnkgKHVzZSBub3JtYWxpemVkIG1ldHJpY3MpXG4gICAgaWYgKG5vcm1hbGl6ZWRNZXRyaWNzLmR1cmF0aW9uID4gdGhpcy5zbG93UXVlcnlUaHJlc2hvbGQpIHtcbiAgICAgIHRoaXMucmVjb3JkU2xvd1F1ZXJ5KHtcbiAgICAgICAgcXVlcnk6IG5vcm1hbGl6ZWRNZXRyaWNzLnF1ZXJ5LFxuICAgICAgICBkdXJhdGlvbjogbm9ybWFsaXplZE1ldHJpY3MuZHVyYXRpb24sXG4gICAgICAgIHRocmVzaG9sZDogdGhpcy5zbG93UXVlcnlUaHJlc2hvbGQsXG4gICAgICAgIHNvdXJjZXM6IG5vcm1hbGl6ZWRNZXRyaWNzLnNvdXJjZXMsXG4gICAgICAgIHJlc3VsdENvdW50OiBub3JtYWxpemVkTWV0cmljcy5yZXN1bHRDb3VudCxcbiAgICAgICAgbWVtb3J5VXNhZ2U6IG5vcm1hbGl6ZWRNZXRyaWNzLm1lbW9yeUFmdGVyLFxuICAgICAgICB0aW1lc3RhbXA6IG5vcm1hbGl6ZWRNZXRyaWNzLnRpbWVzdGFtcFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgLy8gVHJpbSBoaXN0b3J5IGlmIG5lZWRlZFxuICAgIGlmICh0aGlzLnNlYXJjaE1ldHJpY3MubGVuZ3RoID4gdGhpcy5tYXhNZXRyaWNzSGlzdG9yeSkge1xuICAgICAgdGhpcy5zZWFyY2hNZXRyaWNzID0gdGhpcy5zZWFyY2hNZXRyaWNzLnNsaWNlKC10aGlzLm1heE1ldHJpY3NIaXN0b3J5KTtcbiAgICB9XG5cbiAgICAvLyBMb2cgc2lnbmlmaWNhbnQgcGVyZm9ybWFuY2UgZXZlbnRzICh1c2Ugbm9ybWFsaXplZCBtZXRyaWNzKVxuICAgIGlmIChub3JtYWxpemVkTWV0cmljcy5kdXJhdGlvbiA+IHRoaXMuc2xvd1F1ZXJ5VGhyZXNob2xkICogMikge1xuICAgICAgbG9nZ2VyLndhcm4oJ1Zlcnkgc2xvdyBzZWFyY2ggZGV0ZWN0ZWQnLCB7XG4gICAgICAgIHF1ZXJ5OiBub3JtYWxpemVkTWV0cmljcy5xdWVyeS5zdWJzdHJpbmcoMCwgNTApLFxuICAgICAgICBkdXJhdGlvbjogbm9ybWFsaXplZE1ldHJpY3MuZHVyYXRpb24sXG4gICAgICAgIHJlc3VsdENvdW50OiBub3JtYWxpemVkTWV0cmljcy5yZXN1bHRDb3VudCxcbiAgICAgICAgc291cmNlczogbm9ybWFsaXplZE1ldHJpY3Muc291cmNlc1xuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFJlY29yZCBjYWNoZSBwZXJmb3JtYW5jZSBtZXRyaWNzXG4gICAqL1xuICByZWNvcmRDYWNoZVBlcmZvcm1hbmNlKGNhY2hlTmFtZTogc3RyaW5nLCBzdGF0czogQ2FjaGVQZXJmb3JtYW5jZSk6IHZvaWQge1xuICAgIGlmICghdGhpcy5pc01vbml0b3JpbmcpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBOb3JtYWxpemUgY2FjaGUgbmFtZSB0byBwcmV2ZW50IFVuaWNvZGUtYmFzZWQgYXR0YWNrc1xuICAgIGNvbnN0IHZhbGlkYXRpb25SZXN1bHQgPSBVbmljb2RlVmFsaWRhdG9yLm5vcm1hbGl6ZShjYWNoZU5hbWUpO1xuICAgIGNvbnN0IG5vcm1hbGl6ZWRDYWNoZU5hbWUgPSB2YWxpZGF0aW9uUmVzdWx0Lm5vcm1hbGl6ZWRDb250ZW50O1xuXG4gICAgdGhpcy5jYWNoZU1ldHJpY3Muc2V0KG5vcm1hbGl6ZWRDYWNoZU5hbWUsIHN0YXRzKTtcblxuICAgIC8vIExvZyBjYWNoZSBwZXJmb3JtYW5jZSB3YXJuaW5ncyAodXNlIG5vcm1hbGl6ZWQgY2FjaGUgbmFtZSlcbiAgICBpZiAoc3RhdHMuaGl0UmF0ZSA8IDAuNSkge1xuICAgICAgbG9nZ2VyLndhcm4oJ0xvdyBjYWNoZSBoaXQgcmF0ZSBkZXRlY3RlZCcsIHtcbiAgICAgICAgY2FjaGU6IG5vcm1hbGl6ZWRDYWNoZU5hbWUsXG4gICAgICAgIGhpdFJhdGU6IHN0YXRzLmhpdFJhdGUsXG4gICAgICAgIHRvdGFsT3BlcmF0aW9uczogc3RhdHMudG90YWxIaXRzICsgc3RhdHMudG90YWxNaXNzZXNcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgY29tcHJlaGVuc2l2ZSBwZXJmb3JtYW5jZSBtZXRyaWNzXG4gICAqL1xuICBnZXRNZXRyaWNzKCk6IFBlcmZvcm1hbmNlTWV0cmljcyB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHNlYXJjaFRpbWVzOiB0aGlzLnNlYXJjaE1ldHJpY3MubWFwKG0gPT4gbS5kdXJhdGlvbiksXG4gICAgICBtZW1vcnlVc2FnZTogdGhpcy5tZW1vcnlTbmFwc2hvdHMuc2xpY2UoLTEwMCksIC8vIExhc3QgMTAwIHNuYXBzaG90c1xuICAgICAgY2FjaGVTdGF0czogdGhpcy5hZ2dyZWdhdGVDYWNoZVN0YXRzKCksXG4gICAgICBzeXN0ZW1TdGF0czogdGhpcy5nZXRTeXN0ZW1TdGF0cygpLFxuICAgICAgdGltZXN0YW1wOiBuZXcgRGF0ZSgpXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgc2VhcmNoIHBlcmZvcm1hbmNlIHN0YXRpc3RpY3NcbiAgICovXG4gIGdldFNlYXJjaFN0YXRzKCk6IHtcbiAgICB0b3RhbFNlYXJjaGVzOiBudW1iZXI7XG4gICAgYXZlcmFnZVRpbWU6IG51bWJlcjtcbiAgICBtZWRpYW5UaW1lOiBudW1iZXI7XG4gICAgcDk1VGltZTogbnVtYmVyO1xuICAgIHA5OVRpbWU6IG51bWJlcjtcbiAgICBzbG93UXVlcmllczogbnVtYmVyO1xuICAgIGNhY2hlSGl0UmF0ZTogbnVtYmVyO1xuICB9IHtcbiAgICBpZiAodGhpcy5zZWFyY2hNZXRyaWNzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgdG90YWxTZWFyY2hlczogMCxcbiAgICAgICAgYXZlcmFnZVRpbWU6IDAsXG4gICAgICAgIG1lZGlhblRpbWU6IDAsXG4gICAgICAgIHA5NVRpbWU6IDAsXG4gICAgICAgIHA5OVRpbWU6IDAsXG4gICAgICAgIHNsb3dRdWVyaWVzOiAwLFxuICAgICAgICBjYWNoZUhpdFJhdGU6IDBcbiAgICAgIH07XG4gICAgfVxuXG4gICAgY29uc3QgdGltZXMgPSB0aGlzLnNlYXJjaE1ldHJpY3MubWFwKG0gPT4gbS5kdXJhdGlvbikuc29ydCgoYSwgYikgPT4gYSAtIGIpO1xuICAgIGNvbnN0IGNhY2hlSGl0cyA9IHRoaXMuc2VhcmNoTWV0cmljcy5maWx0ZXIobSA9PiBtLmNhY2hlSGl0KS5sZW5ndGg7XG5cbiAgICByZXR1cm4ge1xuICAgICAgdG90YWxTZWFyY2hlczogdGhpcy5zZWFyY2hNZXRyaWNzLmxlbmd0aCxcbiAgICAgIGF2ZXJhZ2VUaW1lOiB0aW1lcy5yZWR1Y2UoKHN1bSwgdGltZSkgPT4gc3VtICsgdGltZSwgMCkgLyB0aW1lcy5sZW5ndGgsXG4gICAgICBtZWRpYW5UaW1lOiB0aW1lc1tNYXRoLmZsb29yKHRpbWVzLmxlbmd0aCAvIDIpXSxcbiAgICAgIHA5NVRpbWU6IHRpbWVzW01hdGguZmxvb3IodGltZXMubGVuZ3RoICogMC45NSldLFxuICAgICAgcDk5VGltZTogdGltZXNbTWF0aC5mbG9vcih0aW1lcy5sZW5ndGggKiAwLjk5KV0sXG4gICAgICBzbG93UXVlcmllczogdGhpcy5zbG93UXVlcmllcy5sZW5ndGgsXG4gICAgICBjYWNoZUhpdFJhdGU6IGNhY2hlSGl0cyAvIHRoaXMuc2VhcmNoTWV0cmljcy5sZW5ndGhcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBtZW1vcnkgdXNhZ2Ugc3RhdGlzdGljc1xuICAgKi9cbiAgZ2V0TWVtb3J5U3RhdHMoKToge1xuICAgIGN1cnJlbnRVc2FnZTogTWVtb3J5VXNhZ2U7XG4gICAgcGVha1VzYWdlOiBNZW1vcnlVc2FnZTtcbiAgICBhdmVyYWdlVXNhZ2U6IE1lbW9yeVVzYWdlO1xuICAgIGdyb3d0aFJhdGU6IG51bWJlcjsgLy8gTUIgcGVyIG1pbnV0ZVxuICB9IHtcbiAgICBpZiAodGhpcy5tZW1vcnlTbmFwc2hvdHMubGVuZ3RoID09PSAwKSB7XG4gICAgICBjb25zdCBjdXJyZW50ID0gdGhpcy50YWtlTWVtb3J5U25hcHNob3QoKTtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGN1cnJlbnRVc2FnZTogY3VycmVudCxcbiAgICAgICAgcGVha1VzYWdlOiBjdXJyZW50LFxuICAgICAgICBhdmVyYWdlVXNhZ2U6IGN1cnJlbnQsXG4gICAgICAgIGdyb3d0aFJhdGU6IDBcbiAgICAgIH07XG4gICAgfVxuXG4gICAgY29uc3QgY3VycmVudCA9IHRoaXMubWVtb3J5U25hcHNob3RzW3RoaXMubWVtb3J5U25hcHNob3RzLmxlbmd0aCAtIDFdO1xuICAgIGNvbnN0IHBlYWsgPSB0aGlzLm1lbW9yeVNuYXBzaG90cy5yZWR1Y2UoKG1heCwgc25hcHNob3QpID0+IFxuICAgICAgc25hcHNob3QuaGVhcFVzZWQgPiBtYXguaGVhcFVzZWQgPyBzbmFwc2hvdCA6IG1heFxuICAgICk7XG5cbiAgICBjb25zdCB0b3RhbEhlYXAgPSB0aGlzLm1lbW9yeVNuYXBzaG90cy5yZWR1Y2UoKHN1bSwgc25hcHNob3QpID0+IHN1bSArIHNuYXBzaG90LmhlYXBVc2VkLCAwKTtcbiAgICBjb25zdCB0b3RhbFJzcyA9IHRoaXMubWVtb3J5U25hcHNob3RzLnJlZHVjZSgoc3VtLCBzbmFwc2hvdCkgPT4gc3VtICsgc25hcHNob3QucnNzLCAwKTtcbiAgICBjb25zdCBhdmVyYWdlOiBNZW1vcnlVc2FnZSA9IHtcbiAgICAgIGhlYXBVc2VkOiB0b3RhbEhlYXAgLyB0aGlzLm1lbW9yeVNuYXBzaG90cy5sZW5ndGgsXG4gICAgICBoZWFwVG90YWw6IHRoaXMubWVtb3J5U25hcHNob3RzLnJlZHVjZSgoc3VtLCBzKSA9PiBzdW0gKyBzLmhlYXBUb3RhbCwgMCkgLyB0aGlzLm1lbW9yeVNuYXBzaG90cy5sZW5ndGgsXG4gICAgICByc3M6IHRvdGFsUnNzIC8gdGhpcy5tZW1vcnlTbmFwc2hvdHMubGVuZ3RoLFxuICAgICAgZXh0ZXJuYWw6IHRoaXMubWVtb3J5U25hcHNob3RzLnJlZHVjZSgoc3VtLCBzKSA9PiBzdW0gKyBzLmV4dGVybmFsLCAwKSAvIHRoaXMubWVtb3J5U25hcHNob3RzLmxlbmd0aCxcbiAgICAgIHRpbWVzdGFtcDogbmV3IERhdGUoKVxuICAgIH07XG5cbiAgICAvLyBDYWxjdWxhdGUgZ3Jvd3RoIHJhdGUgKE1CIHBlciBtaW51dGUpXG4gICAgbGV0IGdyb3d0aFJhdGUgPSAwO1xuICAgIGlmICh0aGlzLm1lbW9yeVNuYXBzaG90cy5sZW5ndGggPiAxKSB7XG4gICAgICBjb25zdCBvbGRlc3QgPSB0aGlzLm1lbW9yeVNuYXBzaG90c1swXTtcbiAgICAgIGNvbnN0IHRpbWVEaWZmID0gKGN1cnJlbnQudGltZXN0YW1wLmdldFRpbWUoKSAtIG9sZGVzdC50aW1lc3RhbXAuZ2V0VGltZSgpKSAvIDYwMDAwOyAvLyBtaW51dGVzXG4gICAgICBjb25zdCBtZW1vcnlEaWZmID0gKGN1cnJlbnQuaGVhcFVzZWQgLSBvbGRlc3QuaGVhcFVzZWQpIC8gKDEwMjQgKiAxMDI0KTsgLy8gTUJcbiAgICAgIGdyb3d0aFJhdGUgPSB0aW1lRGlmZiA+IDAgPyBtZW1vcnlEaWZmIC8gdGltZURpZmYgOiAwO1xuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICBjdXJyZW50VXNhZ2U6IGN1cnJlbnQsXG4gICAgICBwZWFrVXNhZ2U6IHBlYWssXG4gICAgICBhdmVyYWdlVXNhZ2U6IGF2ZXJhZ2UsXG4gICAgICBncm93dGhSYXRlXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgc2xvdyBxdWVyaWVzIHdpdGggYW5hbHlzaXNcbiAgICovXG4gIGdldFNsb3dRdWVyaWVzKGxpbWl0OiBudW1iZXIgPSAxMCk6IFNsb3dRdWVyeVtdIHtcbiAgICByZXR1cm4gdGhpcy5zbG93UXVlcmllc1xuICAgICAgLnNvcnQoKGEsIGIpID0+IGIuZHVyYXRpb24gLSBhLmR1cmF0aW9uKVxuICAgICAgLnNsaWNlKDAsIGxpbWl0KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBbmFseXplIHBlcmZvcm1hbmNlIHRyZW5kc1xuICAgKi9cbiAgYW5hbHl6ZVRyZW5kcygpOiB7XG4gICAgcGVyZm9ybWFuY2VUcmVuZDogJ2ltcHJvdmluZycgfCAnZGVncmFkaW5nJyB8ICdzdGFibGUnO1xuICAgIG1lbW9yeVRyZW5kOiAnZ3Jvd2luZycgfCAnc2hyaW5raW5nJyB8ICdzdGFibGUnO1xuICAgIHJlY29tbWVuZGF0aW9uczogc3RyaW5nW107XG4gIH0ge1xuICAgIGNvbnN0IHJlY29tbWVuZGF0aW9uczogc3RyaW5nW10gPSBbXTtcbiAgICBcbiAgICAvLyBBbmFseXplIHNlYXJjaCBwZXJmb3JtYW5jZSB0cmVuZFxuICAgIGxldCBwZXJmb3JtYW5jZVRyZW5kOiAnaW1wcm92aW5nJyB8ICdkZWdyYWRpbmcnIHwgJ3N0YWJsZScgPSAnc3RhYmxlJztcbiAgICBpZiAodGhpcy5zZWFyY2hNZXRyaWNzLmxlbmd0aCA+IDEwKSB7XG4gICAgICBjb25zdCByZWNlbnQgPSB0aGlzLnNlYXJjaE1ldHJpY3Muc2xpY2UoLTEwKS5tYXAobSA9PiBtLmR1cmF0aW9uKTtcbiAgICAgIGNvbnN0IG9sZGVyID0gdGhpcy5zZWFyY2hNZXRyaWNzLnNsaWNlKC0yMCwgLTEwKS5tYXAobSA9PiBtLmR1cmF0aW9uKTtcbiAgICAgIFxuICAgICAgaWYgKHJlY2VudC5sZW5ndGggPiAwICYmIG9sZGVyLmxlbmd0aCA+IDApIHtcbiAgICAgICAgY29uc3QgcmVjZW50QXZnID0gcmVjZW50LnJlZHVjZSgoc3VtLCB0KSA9PiBzdW0gKyB0LCAwKSAvIHJlY2VudC5sZW5ndGg7XG4gICAgICAgIGNvbnN0IG9sZGVyQXZnID0gb2xkZXIucmVkdWNlKChzdW0sIHQpID0+IHN1bSArIHQsIDApIC8gb2xkZXIubGVuZ3RoO1xuICAgICAgICBcbiAgICAgICAgaWYgKHJlY2VudEF2ZyA+IG9sZGVyQXZnICogMS4yKSB7XG4gICAgICAgICAgcGVyZm9ybWFuY2VUcmVuZCA9ICdkZWdyYWRpbmcnO1xuICAgICAgICAgIHJlY29tbWVuZGF0aW9ucy5wdXNoKCdTZWFyY2ggcGVyZm9ybWFuY2UgaXMgZGVncmFkaW5nLiBDb25zaWRlciBjYWNoZSBvcHRpbWl6YXRpb24gb3IgaW5kZXggcmVidWlsZGluZy4nKTtcbiAgICAgICAgfSBlbHNlIGlmIChyZWNlbnRBdmcgPCBvbGRlckF2ZyAqIDAuOCkge1xuICAgICAgICAgIHBlcmZvcm1hbmNlVHJlbmQgPSAnaW1wcm92aW5nJztcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIC8vIEFuYWx5emUgbWVtb3J5IHRyZW5kXG4gICAgY29uc3QgbWVtb3J5U3RhdHMgPSB0aGlzLmdldE1lbW9yeVN0YXRzKCk7XG4gICAgbGV0IG1lbW9yeVRyZW5kOiAnZ3Jvd2luZycgfCAnc2hyaW5raW5nJyB8ICdzdGFibGUnID0gJ3N0YWJsZSc7XG4gICAgXG4gICAgaWYgKG1lbW9yeVN0YXRzLmdyb3d0aFJhdGUgPiAxKSB7IC8vIEdyb3dpbmcgYnkgbW9yZSB0aGFuIDFNQi9taW51dGVcbiAgICAgIG1lbW9yeVRyZW5kID0gJ2dyb3dpbmcnO1xuICAgICAgcmVjb21tZW5kYXRpb25zLnB1c2goJ01lbW9yeSB1c2FnZSBpcyBncm93aW5nIHJhcGlkbHkuIENvbnNpZGVyIGNhY2hlIGNsZWFudXAgb3IgbWVtb3J5IGxpbWl0cy4nKTtcbiAgICB9IGVsc2UgaWYgKG1lbW9yeVN0YXRzLmdyb3d0aFJhdGUgPCAtMSkge1xuICAgICAgbWVtb3J5VHJlbmQgPSAnc2hyaW5raW5nJztcbiAgICB9XG5cbiAgICAvLyBDYWNoZSBwZXJmb3JtYW5jZSByZWNvbW1lbmRhdGlvbnNcbiAgICBjb25zdCBjYWNoZVN0YXRzID0gdGhpcy5hZ2dyZWdhdGVDYWNoZVN0YXRzKCk7XG4gICAgaWYgKGNhY2hlU3RhdHMuaGl0UmF0ZSA8IDAuNikge1xuICAgICAgcmVjb21tZW5kYXRpb25zLnB1c2goJ0NhY2hlIGhpdCByYXRlIGlzIGxvdy4gQ29uc2lkZXIgYWRqdXN0aW5nIGNhY2hlIHNpemUgb3IgVFRMIHNldHRpbmdzLicpO1xuICAgIH1cblxuICAgIC8vIFNsb3cgcXVlcnkgcmVjb21tZW5kYXRpb25zXG4gICAgaWYgKHRoaXMuc2xvd1F1ZXJpZXMubGVuZ3RoID4gMTApIHtcbiAgICAgIHJlY29tbWVuZGF0aW9ucy5wdXNoKCdNdWx0aXBsZSBzbG93IHF1ZXJpZXMgZGV0ZWN0ZWQuIENvbnNpZGVyIHF1ZXJ5IG9wdGltaXphdGlvbiBvciBpbmNyZWFzZWQgY2FjaGluZy4nKTtcbiAgICB9XG5cbiAgICByZXR1cm4ge1xuICAgICAgcGVyZm9ybWFuY2VUcmVuZCxcbiAgICAgIG1lbW9yeVRyZW5kLFxuICAgICAgcmVjb21tZW5kYXRpb25zXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXNldCBhbGwgcGVyZm9ybWFuY2UgbWV0cmljc1xuICAgKi9cbiAgcmVzZXQoKTogdm9pZCB7XG4gICAgdGhpcy5zZWFyY2hNZXRyaWNzID0gW107XG4gICAgdGhpcy5zbG93UXVlcmllcyA9IFtdO1xuICAgIHRoaXMubWVtb3J5U25hcHNob3RzID0gW107XG4gICAgdGhpcy5jYWNoZU1ldHJpY3MuY2xlYXIoKTtcbiAgICBcbiAgICBsb2dnZXIuaW5mbygnUGVyZm9ybWFuY2UgbWV0cmljcyByZXNldCcpO1xuICB9XG5cbiAgLyoqXG4gICAqIEV4cG9ydCBtZXRyaWNzIGZvciBleHRlcm5hbCBhbmFseXNpc1xuICAgKi9cbiAgZXhwb3J0TWV0cmljcygpOiBzdHJpbmcge1xuICAgIGNvbnN0IGRhdGEgPSB7XG4gICAgICBzZWFyY2hNZXRyaWNzOiB0aGlzLnNlYXJjaE1ldHJpY3MsXG4gICAgICBzbG93UXVlcmllczogdGhpcy5zbG93UXVlcmllcyxcbiAgICAgIG1lbW9yeVNuYXBzaG90czogdGhpcy5tZW1vcnlTbmFwc2hvdHMsXG4gICAgICBjYWNoZU1ldHJpY3M6IE9iamVjdC5mcm9tRW50cmllcyh0aGlzLmNhY2hlTWV0cmljcyksXG4gICAgICBleHBvcnRUaW1lc3RhbXA6IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKVxuICAgIH07XG5cbiAgICByZXR1cm4gSlNPTi5zdHJpbmdpZnkoZGF0YSwgbnVsbCwgMik7XG4gIH1cblxuICAvLyBQcml2YXRlIG1ldGhvZHNcblxuICBwcml2YXRlIHJlY29yZFNsb3dRdWVyeShxdWVyeTogU2xvd1F1ZXJ5KTogdm9pZCB7XG4gICAgdGhpcy5zbG93UXVlcmllcy5wdXNoKHF1ZXJ5KTtcblxuICAgIC8vIFRyaW0gc2xvdyBxdWVyaWVzIGhpc3RvcnlcbiAgICBpZiAodGhpcy5zbG93UXVlcmllcy5sZW5ndGggPiB0aGlzLm1heFNsb3dRdWVyaWVzKSB7XG4gICAgICB0aGlzLnNsb3dRdWVyaWVzID0gdGhpcy5zbG93UXVlcmllcy5zbGljZSgtdGhpcy5tYXhTbG93UXVlcmllcyk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBzdGFydE1lbW9yeU1vbml0b3JpbmcoKTogdm9pZCB7XG4gICAgaWYgKHRoaXMubWVtb3J5TW9uaXRvckludGVydmFsKSB7XG4gICAgICBjbGVhckludGVydmFsKHRoaXMubWVtb3J5TW9uaXRvckludGVydmFsKTtcbiAgICB9XG5cbiAgICB0aGlzLm1lbW9yeU1vbml0b3JJbnRlcnZhbCA9IHNldEludGVydmFsKCgpID0+IHtcbiAgICAgIGlmICh0aGlzLmlzTW9uaXRvcmluZykge1xuICAgICAgICBjb25zdCBzbmFwc2hvdCA9IHRoaXMudGFrZU1lbW9yeVNuYXBzaG90KCk7XG4gICAgICAgIHRoaXMubWVtb3J5U25hcHNob3RzLnB1c2goc25hcHNob3QpO1xuXG4gICAgICAgIC8vIFRyaW0gbWVtb3J5IHNuYXBzaG90cyAoa2VlcCBsYXN0IDIwMClcbiAgICAgICAgaWYgKHRoaXMubWVtb3J5U25hcHNob3RzLmxlbmd0aCA+IDIwMCkge1xuICAgICAgICAgIHRoaXMubWVtb3J5U25hcHNob3RzID0gdGhpcy5tZW1vcnlTbmFwc2hvdHMuc2xpY2UoLTIwMCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9LCB0aGlzLm1lbW9yeVNuYXBzaG90SW50ZXJ2YWwpO1xuICB9XG5cbiAgcHJpdmF0ZSB0YWtlTWVtb3J5U25hcHNob3QoKTogTWVtb3J5VXNhZ2Uge1xuICAgIGNvbnN0IG1lbVVzYWdlID0gcHJvY2Vzcy5tZW1vcnlVc2FnZSgpO1xuICAgIHJldHVybiB7XG4gICAgICBoZWFwVXNlZDogbWVtVXNhZ2UuaGVhcFVzZWQsXG4gICAgICBoZWFwVG90YWw6IG1lbVVzYWdlLmhlYXBUb3RhbCxcbiAgICAgIHJzczogbWVtVXNhZ2UucnNzLFxuICAgICAgZXh0ZXJuYWw6IG1lbVVzYWdlLmV4dGVybmFsLFxuICAgICAgdGltZXN0YW1wOiBuZXcgRGF0ZSgpXG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgYWdncmVnYXRlQ2FjaGVTdGF0cygpOiBDYWNoZVBlcmZvcm1hbmNlIHtcbiAgICBpZiAodGhpcy5jYWNoZU1ldHJpY3Muc2l6ZSA9PT0gMCkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgaGl0UmF0ZTogMCxcbiAgICAgICAgYXZnSGl0VGltZTogMCxcbiAgICAgICAgYXZnTWlzc1RpbWU6IDAsXG4gICAgICAgIHRvdGFsSGl0czogMCxcbiAgICAgICAgdG90YWxNaXNzZXM6IDAsXG4gICAgICAgIGV2aWN0aW9uczogMFxuICAgICAgfTtcbiAgICB9XG5cbiAgICBsZXQgdG90YWxIaXRzID0gMDtcbiAgICBsZXQgdG90YWxNaXNzZXMgPSAwO1xuICAgIGxldCB0b3RhbEV2aWN0aW9ucyA9IDA7XG4gICAgbGV0IHdlaWdodGVkSGl0VGltZSA9IDA7XG4gICAgbGV0IHdlaWdodGVkTWlzc1RpbWUgPSAwO1xuXG4gICAgZm9yIChjb25zdCBzdGF0cyBvZiB0aGlzLmNhY2hlTWV0cmljcy52YWx1ZXMoKSkge1xuICAgICAgdG90YWxIaXRzICs9IHN0YXRzLnRvdGFsSGl0cztcbiAgICAgIHRvdGFsTWlzc2VzICs9IHN0YXRzLnRvdGFsTWlzc2VzO1xuICAgICAgdG90YWxFdmljdGlvbnMgKz0gc3RhdHMuZXZpY3Rpb25zO1xuICAgICAgd2VpZ2h0ZWRIaXRUaW1lICs9IHN0YXRzLmF2Z0hpdFRpbWUgKiBzdGF0cy50b3RhbEhpdHM7XG4gICAgICB3ZWlnaHRlZE1pc3NUaW1lICs9IHN0YXRzLmF2Z01pc3NUaW1lICogc3RhdHMudG90YWxNaXNzZXM7XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIGhpdFJhdGU6IHRvdGFsSGl0cyArIHRvdGFsTWlzc2VzID4gMCA/IHRvdGFsSGl0cyAvICh0b3RhbEhpdHMgKyB0b3RhbE1pc3NlcykgOiAwLFxuICAgICAgYXZnSGl0VGltZTogdG90YWxIaXRzID4gMCA/IHdlaWdodGVkSGl0VGltZSAvIHRvdGFsSGl0cyA6IDAsXG4gICAgICBhdmdNaXNzVGltZTogdG90YWxNaXNzZXMgPiAwID8gd2VpZ2h0ZWRNaXNzVGltZSAvIHRvdGFsTWlzc2VzIDogMCxcbiAgICAgIHRvdGFsSGl0cyxcbiAgICAgIHRvdGFsTWlzc2VzLFxuICAgICAgZXZpY3Rpb25zOiB0b3RhbEV2aWN0aW9uc1xuICAgIH07XG4gIH1cblxuICBwcml2YXRlIGdldFN5c3RlbVN0YXRzKCk6IFN5c3RlbVN0YXRzIHtcbiAgICBjb25zdCBvcyA9IHJlcXVpcmUoJ29zJyk7XG4gICAgXG4gICAgcmV0dXJuIHtcbiAgICAgIGNwdVVzYWdlOiBwcm9jZXNzLmNwdVVzYWdlKCkudXNlciAvIDEwMDAwMDAsIC8vIENvbnZlcnQgdG8gc2Vjb25kc1xuICAgICAgbG9hZEF2ZXJhZ2U6IG9zLmxvYWRhdmcoKSxcbiAgICAgIGZyZWVNZW1vcnk6IG9zLmZyZWVtZW0oKSxcbiAgICAgIHRvdGFsTWVtb3J5OiBvcy50b3RhbG1lbSgpLFxuICAgICAgdXB0aW1lOiBwcm9jZXNzLnVwdGltZSgpXG4gICAgfTtcbiAgfVxufSJdfQ==
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RateLimiter.d.ts","sourceRoot":"","sources":["../../src/utils/RateLimiter.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,IAAI,CAAC;CACjB;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;gBAEtB,MAAM,EAAE,iBAAiB;IAsBrC;;;OAGG;IACH,UAAU,IAAI,eAAe;IA0C7B;;;OAGG;IACH,YAAY,IAAI,IAAI;IAUpB;;OAEG;IACH,SAAS,IAAI,eAAe;IAW5B;;;OAGG;IACH,KAAK,IAAI,IAAI;IAMb;;OAEG;IACH,OAAO,CAAC,YAAY;IAQpB;;OAEG;IACH,OAAO,CAAC,YAAY;IAOpB;;OAEG;IACH,QAAQ,IAAI,MAAM;CAKnB;AAED;;GAEG;AACH,qBAAa,kBAAkB;IAC7B;;OAEG;IACH,MAAM,CAAC,mBAAmB,IAAI,WAAW;IAQzC;;;OAGG;IACH,MAAM,CAAC,wBAAwB,IAAI,WAAW;IAQ9C;;;OAGG;IACH,MAAM,CAAC,mBAAmB,IAAI,WAAW;CAO1C"}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RateLimiter - Implements rate limiting for API calls to prevent abuse
|
|
3
|
+
*
|
|
4
|
+
* Features:
|
|
5
|
+
* - Token bucket algorithm for flexible rate limiting
|
|
6
|
+
* - Configurable limits per time window
|
|
7
|
+
* - Memory-efficient implementation
|
|
8
|
+
* - Thread-safe for concurrent requests
|
|
9
|
+
*/
|
|
10
|
+
export class RateLimiter {
|
|
11
|
+
tokens;
|
|
12
|
+
lastRefill;
|
|
13
|
+
lastRequest;
|
|
14
|
+
maxTokens;
|
|
15
|
+
refillRate;
|
|
16
|
+
minDelay;
|
|
17
|
+
constructor(config) {
|
|
18
|
+
if (config.maxRequests <= 0) {
|
|
19
|
+
throw new Error('maxRequests must be positive');
|
|
20
|
+
}
|
|
21
|
+
if (config.windowMs <= 0) {
|
|
22
|
+
throw new Error('windowMs must be positive');
|
|
23
|
+
}
|
|
24
|
+
this.maxTokens = config.maxRequests;
|
|
25
|
+
this.tokens = this.maxTokens;
|
|
26
|
+
this.refillRate = this.maxTokens / config.windowMs;
|
|
27
|
+
// Validate refill rate to prevent division by zero
|
|
28
|
+
if (this.refillRate <= 0 || !isFinite(this.refillRate)) {
|
|
29
|
+
throw new Error('Invalid configuration: refill rate must be positive and finite');
|
|
30
|
+
}
|
|
31
|
+
this.lastRefill = Date.now();
|
|
32
|
+
this.lastRequest = 0;
|
|
33
|
+
this.minDelay = config.minDelayMs || 0;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Check if a request is allowed under the rate limit
|
|
37
|
+
* @returns Status object indicating if request is allowed
|
|
38
|
+
*/
|
|
39
|
+
checkLimit() {
|
|
40
|
+
const now = Date.now();
|
|
41
|
+
// Refill tokens based on time elapsed
|
|
42
|
+
this.refillTokens(now);
|
|
43
|
+
// Check minimum delay between requests
|
|
44
|
+
if (this.minDelay > 0 && this.lastRequest > 0) {
|
|
45
|
+
const timeSinceLastRequest = now - this.lastRequest;
|
|
46
|
+
if (timeSinceLastRequest < this.minDelay) {
|
|
47
|
+
const retryAfterMs = this.minDelay - timeSinceLastRequest;
|
|
48
|
+
return {
|
|
49
|
+
allowed: false,
|
|
50
|
+
retryAfterMs,
|
|
51
|
+
remainingTokens: Math.floor(this.tokens),
|
|
52
|
+
resetTime: new Date(now + retryAfterMs)
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
// Check if we have tokens available
|
|
57
|
+
if (this.tokens < 1) {
|
|
58
|
+
// Calculate when the next token will be available
|
|
59
|
+
const tokensNeeded = 1 - this.tokens;
|
|
60
|
+
const msUntilNextToken = tokensNeeded / this.refillRate;
|
|
61
|
+
return {
|
|
62
|
+
allowed: false,
|
|
63
|
+
retryAfterMs: Math.ceil(msUntilNextToken),
|
|
64
|
+
remainingTokens: 0,
|
|
65
|
+
resetTime: new Date(now + msUntilNextToken)
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
// Request is allowed
|
|
69
|
+
return {
|
|
70
|
+
allowed: true,
|
|
71
|
+
remainingTokens: Math.floor(this.tokens),
|
|
72
|
+
resetTime: this.getResetTime()
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Consume a token for an allowed request
|
|
77
|
+
* Should be called after checkLimit() returns allowed: true
|
|
78
|
+
*/
|
|
79
|
+
consumeToken() {
|
|
80
|
+
const now = Date.now();
|
|
81
|
+
this.refillTokens(now);
|
|
82
|
+
if (this.tokens >= 1) {
|
|
83
|
+
this.tokens -= 1;
|
|
84
|
+
this.lastRequest = now;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Get current rate limit status without consuming a token
|
|
89
|
+
*/
|
|
90
|
+
getStatus() {
|
|
91
|
+
const now = Date.now();
|
|
92
|
+
this.refillTokens(now);
|
|
93
|
+
return {
|
|
94
|
+
allowed: this.tokens >= 1,
|
|
95
|
+
remainingTokens: Math.floor(this.tokens),
|
|
96
|
+
resetTime: this.getResetTime()
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Reset the rate limiter to full capacity
|
|
101
|
+
* Useful for testing or manual intervention
|
|
102
|
+
*/
|
|
103
|
+
reset() {
|
|
104
|
+
this.tokens = this.maxTokens;
|
|
105
|
+
this.lastRefill = Date.now();
|
|
106
|
+
this.lastRequest = 0;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Refill tokens based on time elapsed
|
|
110
|
+
*/
|
|
111
|
+
refillTokens(now) {
|
|
112
|
+
const timeSinceLastRefill = now - this.lastRefill;
|
|
113
|
+
const tokensToAdd = timeSinceLastRefill * this.refillRate;
|
|
114
|
+
this.tokens = Math.min(this.maxTokens, this.tokens + tokensToAdd);
|
|
115
|
+
this.lastRefill = now;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Calculate when the rate limit window will reset
|
|
119
|
+
*/
|
|
120
|
+
getResetTime() {
|
|
121
|
+
const now = Date.now();
|
|
122
|
+
const tokensToFull = this.maxTokens - this.tokens;
|
|
123
|
+
const msUntilFull = tokensToFull / this.refillRate;
|
|
124
|
+
return new Date(now + msUntilFull);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Get human-readable rate limit information
|
|
128
|
+
*/
|
|
129
|
+
toString() {
|
|
130
|
+
const status = this.getStatus();
|
|
131
|
+
return `RateLimit: ${status.remainingTokens}/${this.maxTokens} tokens, ` +
|
|
132
|
+
`resets at ${status.resetTime.toISOString()}`;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Factory function to create common rate limiters
|
|
137
|
+
*/
|
|
138
|
+
export class RateLimiterFactory {
|
|
139
|
+
/**
|
|
140
|
+
* GitHub API rate limiter (60 requests per hour for unauthenticated)
|
|
141
|
+
*/
|
|
142
|
+
static createGitHubLimiter() {
|
|
143
|
+
return new RateLimiter({
|
|
144
|
+
maxRequests: 60,
|
|
145
|
+
windowMs: 60 * 60 * 1000, // 1 hour
|
|
146
|
+
minDelayMs: 1000 // 1 second minimum between requests
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Conservative rate limiter for update checks
|
|
151
|
+
* Allows 10 checks per hour with 30 second minimum delay
|
|
152
|
+
*/
|
|
153
|
+
static createUpdateCheckLimiter() {
|
|
154
|
+
return new RateLimiter({
|
|
155
|
+
maxRequests: 10,
|
|
156
|
+
windowMs: 60 * 60 * 1000, // 1 hour
|
|
157
|
+
minDelayMs: 30 * 1000 // 30 seconds between checks
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Strict rate limiter for sensitive operations
|
|
162
|
+
* Allows 5 requests per hour with 1 minute minimum delay
|
|
163
|
+
*/
|
|
164
|
+
static createStrictLimiter() {
|
|
165
|
+
return new RateLimiter({
|
|
166
|
+
maxRequests: 5,
|
|
167
|
+
windowMs: 60 * 60 * 1000, // 1 hour
|
|
168
|
+
minDelayMs: 60 * 1000 // 1 minute between requests
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUmF0ZUxpbWl0ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdXRpbHMvUmF0ZUxpbWl0ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7O0dBUUc7QUFlSCxNQUFNLE9BQU8sV0FBVztJQUNkLE1BQU0sQ0FBUztJQUNmLFVBQVUsQ0FBUztJQUNuQixXQUFXLENBQVM7SUFDWCxTQUFTLENBQVM7SUFDbEIsVUFBVSxDQUFTO0lBQ25CLFFBQVEsQ0FBUztJQUVsQyxZQUFZLE1BQXlCO1FBQ25DLElBQUksTUFBTSxDQUFDLFdBQVcsSUFBSSxDQUFDLEVBQUUsQ0FBQztZQUM1QixNQUFNLElBQUksS0FBSyxDQUFDLDhCQUE4QixDQUFDLENBQUM7UUFDbEQsQ0FBQztRQUNELElBQUksTUFBTSxDQUFDLFFBQVEsSUFBSSxDQUFDLEVBQUUsQ0FBQztZQUN6QixNQUFNLElBQUksS0FBSyxDQUFDLDJCQUEyQixDQUFDLENBQUM7UUFDL0MsQ0FBQztRQUVELElBQUksQ0FBQyxTQUFTLEdBQUcsTUFBTSxDQUFDLFdBQVcsQ0FBQztRQUNwQyxJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUM7UUFDN0IsSUFBSSxDQUFDLFVBQVUsR0FBRyxJQUFJLENBQUMsU0FBUyxHQUFHLE1BQU0sQ0FBQyxRQUFRLENBQUM7UUFFbkQsbURBQW1EO1FBQ25ELElBQUksSUFBSSxDQUFDLFVBQVUsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUM7WUFDdkQsTUFBTSxJQUFJLEtBQUssQ0FBQyxnRUFBZ0UsQ0FBQyxDQUFDO1FBQ3BGLENBQUM7UUFFRCxJQUFJLENBQUMsVUFBVSxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztRQUM3QixJQUFJLENBQUMsV0FBVyxHQUFHLENBQUMsQ0FBQztRQUNyQixJQUFJLENBQUMsUUFBUSxHQUFHLE1BQU0sQ0FBQyxV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TCxDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsTUFBTSxDQUFDLHdCQUF3QjtRQUM3QixPQUFPLElBQUksV0FBVyxDQUFDO1lBQ3JCLFdBQVcsRUFBRSxFQUFFO1lBQ2YsUUFBUSxFQUFFLEVBQUUsR0FBRyxFQUFFLEdBQUcsSUFBSSxFQUFFLFNBQVM7WUFDbkMsVUFBVSxFQUFFLEVBQUUsR0FBRyxJQUFJLENBQUMsNEJBQTRCO1NBQ25ELENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRDs7O09BR0c7SUFDSCxNQUFNLENBQUMsbUJBQW1CO1FBQ3hCLE9BQU8sSUFBSSxXQUFXLENBQUM7WUFDckIsV0FBVyxFQUFFLENBQUM7WUFDZCxRQUFRLEVBQUUsRUFBRSxHQUFHLEVBQUUsR0FBRyxJQUFJLEVBQUUsU0FBUztZQUNuQyxVQUFVLEVBQUUsRUFBRSxHQUFHLElBQUksQ0FBQyw0QkFBNEI7U0FDbkQsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBSYXRlTGltaXRlciAtIEltcGxlbWVudHMgcmF0ZSBsaW1pdGluZyBmb3IgQVBJIGNhbGxzIHRvIHByZXZlbnQgYWJ1c2VcbiAqIFxuICogRmVhdHVyZXM6XG4gKiAtIFRva2VuIGJ1Y2tldCBhbGdvcml0aG0gZm9yIGZsZXhpYmxlIHJhdGUgbGltaXRpbmdcbiAqIC0gQ29uZmlndXJhYmxlIGxpbWl0cyBwZXIgdGltZSB3aW5kb3dcbiAqIC0gTWVtb3J5LWVmZmljaWVudCBpbXBsZW1lbnRhdGlvblxuICogLSBUaHJlYWQtc2FmZSBmb3IgY29uY3VycmVudCByZXF1ZXN0c1xuICovXG5cbmV4cG9ydCBpbnRlcmZhY2UgUmF0ZUxpbWl0ZXJDb25maWcge1xuICBtYXhSZXF1ZXN0czogbnVtYmVyOyAgICAgIC8vIE1heGltdW0gcmVxdWVzdHMgYWxsb3dlZFxuICB3aW5kb3dNczogbnVtYmVyOyAgICAgICAgIC8vIFRpbWUgd2luZG93IGluIG1pbGxpc2Vjb25kc1xuICBtaW5EZWxheU1zPzogbnVtYmVyOyAgICAgIC8vIE1pbmltdW0gZGVsYXkgYmV0d2VlbiByZXF1ZXN0cyAob3B0aW9uYWwpXG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUmF0ZUxpbWl0U3RhdHVzIHtcbiAgYWxsb3dlZDogYm9vbGVhbjtcbiAgcmV0cnlBZnRlck1zPzogbnVtYmVyO1xuICByZW1haW5pbmdUb2tlbnM6IG51bWJlcjtcbiAgcmVzZXRUaW1lOiBEYXRlO1xufVxuXG5leHBvcnQgY2xhc3MgUmF0ZUxpbWl0ZXIge1xuICBwcml2YXRlIHRva2VuczogbnVtYmVyO1xuICBwcml2YXRlIGxhc3RSZWZpbGw6IG51bWJlcjtcbiAgcHJpdmF0ZSBsYXN0UmVxdWVzdDogbnVtYmVyO1xuICBwcml2YXRlIHJlYWRvbmx5IG1heFRva2VuczogbnVtYmVyO1xuICBwcml2YXRlIHJlYWRvbmx5IHJlZmlsbFJhdGU6IG51bWJlcjtcbiAgcHJpdmF0ZSByZWFkb25seSBtaW5EZWxheTogbnVtYmVyO1xuXG4gIGNvbnN0cnVjdG9yKGNvbmZpZzogUmF0ZUxpbWl0ZXJDb25maWcpIHtcbiAgICBpZiAoY29uZmlnLm1heFJlcXVlc3RzIDw9IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignbWF4UmVxdWVzdHMgbXVzdCBiZSBwb3NpdGl2ZScpO1xuICAgIH1cbiAgICBpZiAoY29uZmlnLndpbmRvd01zIDw9IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignd2luZG93TXMgbXVzdCBiZSBwb3NpdGl2ZScpO1xuICAgIH1cblxuICAgIHRoaXMubWF4VG9rZW5zID0gY29uZmlnLm1heFJlcXVlc3RzO1xuICAgIHRoaXMudG9rZW5zID0gdGhpcy5tYXhUb2tlbnM7XG4gICAgdGhpcy5yZWZpbGxSYXRlID0gdGhpcy5tYXhUb2tlbnMgLyBjb25maWcud2luZG93TXM7XG4gICAgXG4gICAgLy8gVmFsaWRhdGUgcmVmaWxsIHJhdGUgdG8gcHJldmVudCBkaXZpc2lvbiBieSB6ZXJvXG4gICAgaWYgKHRoaXMucmVmaWxsUmF0ZSA8PSAwIHx8ICFpc0Zpbml0ZSh0aGlzLnJlZmlsbFJhdGUpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgY29uZmlndXJhdGlvbjogcmVmaWxsIHJhdGUgbXVzdCBiZSBwb3NpdGl2ZSBhbmQgZmluaXRlJyk7XG4gICAgfVxuICAgIFxuICAgIHRoaXMubGFzdFJlZmlsbCA9IERhdGUubm93KCk7XG4gICAgdGhpcy5sYXN0UmVxdWVzdCA9IDA7XG4gICAgdGhpcy5taW5EZWxheSA9IGNvbmZpZy5taW5EZWxheU1zIHx8IDA7XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2sgaWYgYSByZXF1ZXN0IGlzIGFsbG93ZWQgdW5kZXIgdGhlIHJhdGUgbGltaXRcbiAgICogQHJldHVybnMgU3RhdHVzIG9iamVjdCBpbmRpY2F0aW5nIGlmIHJlcXVlc3QgaXMgYWxsb3dlZFxuICAgKi9cbiAgY2hlY2tMaW1pdCgpOiBSYXRlTGltaXRTdGF0dXMge1xuICAgIGNvbnN0IG5vdyA9IERhdGUubm93KCk7XG4gICAgXG4gICAgLy8gUmVmaWxsIHRva2VucyBiYXNlZCBvbiB0aW1lIGVsYXBzZWRcbiAgICB0aGlzLnJlZmlsbFRva2Vucyhub3cpO1xuXG4gICAgLy8gQ2hlY2sgbWluaW11bSBkZWxheSBiZXR3ZWVuIHJlcXVlc3RzXG4gICAgaWYgKHRoaXMubWluRGVsYXkgPiAwICYmIHRoaXMubGFzdFJlcXVlc3QgPiAwKSB7XG4gICAgICBjb25zdCB0aW1lU2luY2VMYXN0UmVxdWVzdCA9IG5vdyAtIHRoaXMubGFzdFJlcXVlc3Q7XG4gICAgICBpZiAodGltZVNpbmNlTGFzdFJlcXVlc3QgPCB0aGlzLm1pbkRlbGF5KSB7XG4gICAgICAgIGNvbnN0IHJldHJ5QWZ0ZXJNcyA9IHRoaXMubWluRGVsYXkgLSB0aW1lU2luY2VMYXN0UmVxdWVzdDtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBhbGxvd2VkOiBmYWxzZSxcbiAgICAgICAgICByZXRyeUFmdGVyTXMsXG4gICAgICAgICAgcmVtYWluaW5nVG9rZW5zOiBNYXRoLmZsb29yKHRoaXMudG9rZW5zKSxcbiAgICAgICAgICByZXNldFRpbWU6IG5ldyBEYXRlKG5vdyArIHJldHJ5QWZ0ZXJNcylcbiAgICAgICAgfTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBDaGVjayBpZiB3ZSBoYXZlIHRva2VucyBhdmFpbGFibGVcbiAgICBpZiAodGhpcy50b2tlbnMgPCAxKSB7XG4gICAgICAvLyBDYWxjdWxhdGUgd2hlbiB0aGUgbmV4dCB0b2tlbiB3aWxsIGJlIGF2YWlsYWJsZVxuICAgICAgY29uc3QgdG9rZW5zTmVlZGVkID0gMSAtIHRoaXMudG9rZW5zO1xuICAgICAgY29uc3QgbXNVbnRpbE5leHRUb2tlbiA9IHRva2Vuc05lZWRlZCAvIHRoaXMucmVmaWxsUmF0ZTtcbiAgICAgIFxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgYWxsb3dlZDogZmFsc2UsXG4gICAgICAgIHJldHJ5QWZ0ZXJNczogTWF0aC5jZWlsKG1zVW50aWxOZXh0VG9rZW4pLFxuICAgICAgICByZW1haW5pbmdUb2tlbnM6IDAsXG4gICAgICAgIHJlc2V0VGltZTogbmV3IERhdGUobm93ICsgbXNVbnRpbE5leHRUb2tlbilcbiAgICAgIH07XG4gICAgfVxuXG4gICAgLy8gUmVxdWVzdCBpcyBhbGxvd2VkXG4gICAgcmV0dXJuIHtcbiAgICAgIGFsbG93ZWQ6IHRydWUsXG4gICAgICByZW1haW5pbmdUb2tlbnM6IE1hdGguZmxvb3IodGhpcy50b2tlbnMpLFxuICAgICAgcmVzZXRUaW1lOiB0aGlzLmdldFJlc2V0VGltZSgpXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDb25zdW1lIGEgdG9rZW4gZm9yIGFuIGFsbG93ZWQgcmVxdWVzdFxuICAgKiBTaG91bGQgYmUgY2FsbGVkIGFmdGVyIGNoZWNrTGltaXQoKSByZXR1cm5zIGFsbG93ZWQ6IHRydWVcbiAgICovXG4gIGNvbnN1bWVUb2tlbigpOiB2b2lkIHtcbiAgICBjb25zdCBub3cgPSBEYXRlLm5vdygpO1xuICAgIHRoaXMucmVmaWxsVG9rZW5zKG5vdyk7XG4gICAgXG4gICAgaWYgKHRoaXMudG9rZW5zID49IDEpIHtcbiAgICAgIHRoaXMudG9rZW5zIC09IDE7XG4gICAgICB0aGlzLmxhc3RSZXF1ZXN0ID0gbm93O1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgY3VycmVudCByYXRlIGxpbWl0IHN0YXR1cyB3aXRob3V0IGNvbnN1bWluZyBhIHRva2VuXG4gICAqL1xuICBnZXRTdGF0dXMoKTogUmF0ZUxpbWl0U3RhdHVzIHtcbiAgICBjb25zdCBub3cgPSBEYXRlLm5vdygpO1xuICAgIHRoaXMucmVmaWxsVG9rZW5zKG5vdyk7XG5cbiAgICByZXR1cm4ge1xuICAgICAgYWxsb3dlZDogdGhpcy50b2tlbnMgPj0gMSxcbiAgICAgIHJlbWFpbmluZ1Rva2VuczogTWF0aC5mbG9vcih0aGlzLnRva2VucyksXG4gICAgICByZXNldFRpbWU6IHRoaXMuZ2V0UmVzZXRUaW1lKClcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIFJlc2V0IHRoZSByYXRlIGxpbWl0ZXIgdG8gZnVsbCBjYXBhY2l0eVxuICAgKiBVc2VmdWwgZm9yIHRlc3Rpbmcgb3IgbWFudWFsIGludGVydmVudGlvblxuICAgKi9cbiAgcmVzZXQoKTogdm9pZCB7XG4gICAgdGhpcy50b2tlbnMgPSB0aGlzLm1heFRva2VucztcbiAgICB0aGlzLmxhc3RSZWZpbGwgPSBEYXRlLm5vdygpO1xuICAgIHRoaXMubGFzdFJlcXVlc3QgPSAwO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlZmlsbCB0b2tlbnMgYmFzZWQgb24gdGltZSBlbGFwc2VkXG4gICAqL1xuICBwcml2YXRlIHJlZmlsbFRva2Vucyhub3c6IG51bWJlcik6IHZvaWQge1xuICAgIGNvbnN0IHRpbWVTaW5jZUxhc3RSZWZpbGwgPSBub3cgLSB0aGlzLmxhc3RSZWZpbGw7XG4gICAgY29uc3QgdG9rZW5zVG9BZGQgPSB0aW1lU2luY2VMYXN0UmVmaWxsICogdGhpcy5yZWZpbGxSYXRlO1xuICAgIFxuICAgIHRoaXMudG9rZW5zID0gTWF0aC5taW4odGhpcy5tYXhUb2tlbnMsIHRoaXMudG9rZW5zICsgdG9rZW5zVG9BZGQpO1xuICAgIHRoaXMubGFzdFJlZmlsbCA9IG5vdztcbiAgfVxuXG4gIC8qKlxuICAgKiBDYWxjdWxhdGUgd2hlbiB0aGUgcmF0ZSBsaW1pdCB3aW5kb3cgd2lsbCByZXNldFxuICAgKi9cbiAgcHJpdmF0ZSBnZXRSZXNldFRpbWUoKTogRGF0ZSB7XG4gICAgY29uc3Qgbm93ID0gRGF0ZS5ub3coKTtcbiAgICBjb25zdCB0b2tlbnNUb0Z1bGwgPSB0aGlzLm1heFRva2VucyAtIHRoaXMudG9rZW5zO1xuICAgIGNvbnN0IG1zVW50aWxGdWxsID0gdG9rZW5zVG9GdWxsIC8gdGhpcy5yZWZpbGxSYXRlO1xuICAgIHJldHVybiBuZXcgRGF0ZShub3cgKyBtc1VudGlsRnVsbCk7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGh1bWFuLXJlYWRhYmxlIHJhdGUgbGltaXQgaW5mb3JtYXRpb25cbiAgICovXG4gIHRvU3RyaW5nKCk6IHN0cmluZyB7XG4gICAgY29uc3Qgc3RhdHVzID0gdGhpcy5nZXRTdGF0dXMoKTtcbiAgICByZXR1cm4gYFJhdGVMaW1pdDogJHtzdGF0dXMucmVtYWluaW5nVG9rZW5zfS8ke3RoaXMubWF4VG9rZW5zfSB0b2tlbnMsIGAgK1xuICAgICAgICAgICBgcmVzZXRzIGF0ICR7c3RhdHVzLnJlc2V0VGltZS50b0lTT1N0cmluZygpfWA7XG4gIH1cbn1cblxuLyoqXG4gKiBGYWN0b3J5IGZ1bmN0aW9uIHRvIGNyZWF0ZSBjb21tb24gcmF0ZSBsaW1pdGVyc1xuICovXG5leHBvcnQgY2xhc3MgUmF0ZUxpbWl0ZXJGYWN0b3J5IHtcbiAgLyoqXG4gICAqIEdpdEh1YiBBUEkgcmF0ZSBsaW1pdGVyICg2MCByZXF1ZXN0cyBwZXIgaG91ciBmb3IgdW5hdXRoZW50aWNhdGVkKVxuICAgKi9cbiAgc3RhdGljIGNyZWF0ZUdpdEh1YkxpbWl0ZXIoKTogUmF0ZUxpbWl0ZXIge1xuICAgIHJldHVybiBuZXcgUmF0ZUxpbWl0ZXIoe1xuICAgICAgbWF4UmVxdWVzdHM6IDYwLFxuICAgICAgd2luZG93TXM6IDYwICogNjAgKiAxMDAwLCAvLyAxIGhvdXJcbiAgICAgIG1pbkRlbGF5TXM6IDEwMDAgLy8gMSBzZWNvbmQgbWluaW11bSBiZXR3ZWVuIHJlcXVlc3RzXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogQ29uc2VydmF0aXZlIHJhdGUgbGltaXRlciBmb3IgdXBkYXRlIGNoZWNrc1xuICAgKiBBbGxvd3MgMTAgY2hlY2tzIHBlciBob3VyIHdpdGggMzAgc2Vjb25kIG1pbmltdW0gZGVsYXlcbiAgICovXG4gIHN0YXRpYyBjcmVhdGVVcGRhdGVDaGVja0xpbWl0ZXIoKTogUmF0ZUxpbWl0ZXIge1xuICAgIHJldHVybiBuZXcgUmF0ZUxpbWl0ZXIoe1xuICAgICAgbWF4UmVxdWVzdHM6IDEwLFxuICAgICAgd2luZG93TXM6IDYwICogNjAgKiAxMDAwLCAvLyAxIGhvdXJcbiAgICAgIG1pbkRlbGF5TXM6IDMwICogMTAwMCAvLyAzMCBzZWNvbmRzIGJldHdlZW4gY2hlY2tzXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogU3RyaWN0IHJhdGUgbGltaXRlciBmb3Igc2Vuc2l0aXZlIG9wZXJhdGlvbnNcbiAgICogQWxsb3dzIDUgcmVxdWVzdHMgcGVyIGhvdXIgd2l0aCAxIG1pbnV0ZSBtaW5pbXVtIGRlbGF5XG4gICAqL1xuICBzdGF0aWMgY3JlYXRlU3RyaWN0TGltaXRlcigpOiBSYXRlTGltaXRlciB7XG4gICAgcmV0dXJuIG5ldyBSYXRlTGltaXRlcih7XG4gICAgICBtYXhSZXF1ZXN0czogNSxcbiAgICAgIHdpbmRvd01zOiA2MCAqIDYwICogMTAwMCwgLy8gMSBob3VyXG4gICAgICBtaW5EZWxheU1zOiA2MCAqIDEwMDAgLy8gMSBtaW51dGUgYmV0d2VlbiByZXF1ZXN0c1xuICAgIH0pO1xuICB9XG59Il19
|