@dollhousemcp/mcp-server 1.7.3 ā 1.7.4
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/dist/config/ConfigWizard.d.ts +78 -0
- package/dist/config/ConfigWizard.d.ts.map +1 -0
- package/dist/config/ConfigWizard.js +370 -0
- package/dist/config/ConfigWizardCheck.d.ts +47 -0
- package/dist/config/ConfigWizardCheck.d.ts.map +1 -0
- package/dist/config/ConfigWizardCheck.js +208 -0
- package/dist/config/ConfigWizardDisplay.d.ts +64 -0
- package/dist/config/ConfigWizardDisplay.d.ts.map +1 -0
- package/dist/config/ConfigWizardDisplay.js +150 -0
- package/dist/config/WizardFirstResponse.d.ts +25 -0
- package/dist/config/WizardFirstResponse.d.ts.map +1 -0
- package/dist/config/WizardFirstResponse.js +118 -0
- package/dist/config/portfolioConfig.d.ts +40 -0
- package/dist/config/portfolioConfig.d.ts.map +1 -0
- package/dist/config/portfolioConfig.js +58 -0
- package/dist/config/wizardTemplates.d.ts +84 -0
- package/dist/config/wizardTemplates.d.ts.map +1 -0
- package/dist/config/wizardTemplates.js +195 -0
- package/dist/elements/BaseElement.d.ts +15 -0
- package/dist/elements/BaseElement.d.ts.map +1 -1
- package/dist/elements/BaseElement.js +38 -5
- package/dist/generated/version.d.ts +2 -2
- package/dist/generated/version.js +3 -3
- package/dist/handlers/PortfolioPullHandler.d.ts +69 -0
- package/dist/handlers/PortfolioPullHandler.d.ts.map +1 -0
- package/dist/handlers/PortfolioPullHandler.js +340 -0
- package/dist/scripts/scripts/run-config-wizard.js +57 -0
- package/dist/scripts/src/config/ConfigManager.js +799 -0
- package/dist/scripts/src/config/ConfigWizard.js +368 -0
- package/dist/scripts/src/errors/SecurityError.js +47 -0
- package/dist/scripts/src/security/constants.js +28 -0
- package/dist/scripts/src/security/contentValidator.js +415 -0
- package/dist/scripts/src/security/errors.js +32 -0
- package/dist/scripts/src/security/regexValidator.js +217 -0
- package/dist/scripts/src/security/secureYamlParser.js +272 -0
- package/dist/scripts/src/security/securityMonitor.js +111 -0
- package/dist/scripts/src/security/validators/unicodeValidator.js +315 -0
- package/dist/scripts/src/utils/logger.js +288 -0
- package/dist/sync/PortfolioDownloader.d.ts +27 -0
- package/dist/sync/PortfolioDownloader.d.ts.map +1 -0
- package/dist/sync/PortfolioDownloader.js +120 -0
- package/dist/sync/PortfolioSyncComparer.d.ts +50 -0
- package/dist/sync/PortfolioSyncComparer.d.ts.map +1 -0
- package/dist/sync/PortfolioSyncComparer.js +158 -0
- package/dist/tools/getWelcomeMessage.d.ts +41 -0
- package/dist/tools/getWelcomeMessage.d.ts.map +1 -0
- package/dist/tools/getWelcomeMessage.js +109 -0
- package/dist/utils/TemplateRenderer.d.ts +63 -0
- package/dist/utils/TemplateRenderer.d.ts.map +1 -0
- package/dist/utils/TemplateRenderer.js +154 -0
- package/package.json +1 -1
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PortfolioPullHandler - Handles pulling portfolio elements from GitHub
|
|
3
|
+
*
|
|
4
|
+
* This handler implements the pull functionality for sync_portfolio,
|
|
5
|
+
* enabling users to download their portfolio from GitHub to local storage.
|
|
6
|
+
* Supports multiple sync modes (additive, mirror, backup) and dry-run.
|
|
7
|
+
*/
|
|
8
|
+
import { PortfolioRepoManager } from '../portfolio/PortfolioRepoManager.js';
|
|
9
|
+
import { GitHubPortfolioIndexer } from '../portfolio/GitHubPortfolioIndexer.js';
|
|
10
|
+
import { PortfolioManager } from '../portfolio/PortfolioManager.js';
|
|
11
|
+
import { PortfolioIndexManager } from '../portfolio/PortfolioIndexManager.js';
|
|
12
|
+
import { ElementType } from '../portfolio/types.js';
|
|
13
|
+
import { logger } from '../utils/logger.js';
|
|
14
|
+
import { PortfolioSyncComparer } from '../sync/PortfolioSyncComparer.js';
|
|
15
|
+
import { PortfolioDownloader } from '../sync/PortfolioDownloader.js';
|
|
16
|
+
import { UnicodeValidator } from '../security/validators/unicodeValidator.js';
|
|
17
|
+
import { SecurityMonitor } from '../security/securityMonitor.js';
|
|
18
|
+
import { getPortfolioRepositoryName } from '../config/portfolioConfig.js';
|
|
19
|
+
import * as fs from 'fs/promises';
|
|
20
|
+
import * as path from 'path';
|
|
21
|
+
export class PortfolioPullHandler {
|
|
22
|
+
portfolioRepoManager;
|
|
23
|
+
githubIndexer;
|
|
24
|
+
portfolioManager;
|
|
25
|
+
indexManager;
|
|
26
|
+
syncComparer;
|
|
27
|
+
downloader;
|
|
28
|
+
constructor() {
|
|
29
|
+
this.portfolioRepoManager = new PortfolioRepoManager(getPortfolioRepositoryName());
|
|
30
|
+
this.githubIndexer = GitHubPortfolioIndexer.getInstance();
|
|
31
|
+
this.portfolioManager = PortfolioManager.getInstance();
|
|
32
|
+
this.indexManager = PortfolioIndexManager.getInstance();
|
|
33
|
+
this.syncComparer = new PortfolioSyncComparer();
|
|
34
|
+
this.downloader = new PortfolioDownloader();
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Execute the pull operation from GitHub to local portfolio
|
|
38
|
+
*/
|
|
39
|
+
async executePull(options, personaIndicator) {
|
|
40
|
+
try {
|
|
41
|
+
logger.info('Starting portfolio pull operation', { options });
|
|
42
|
+
// Step 1: Validate sync mode
|
|
43
|
+
const syncMode = this.validateSyncMode(options.mode);
|
|
44
|
+
// Step 2: Fetch GitHub portfolio index
|
|
45
|
+
const progressMessages = [];
|
|
46
|
+
progressMessages.push('š Fetching portfolio from GitHub...');
|
|
47
|
+
const githubIndex = await this.githubIndexer.getIndex(true);
|
|
48
|
+
if (!githubIndex || githubIndex.totalElements === 0) {
|
|
49
|
+
return {
|
|
50
|
+
content: [{
|
|
51
|
+
type: "text",
|
|
52
|
+
text: `${personaIndicator}ā ļø No elements found in GitHub portfolio. Nothing to pull.`
|
|
53
|
+
}]
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
progressMessages.push(`š Found ${githubIndex.totalElements} elements on GitHub`);
|
|
57
|
+
// Step 3: Get local portfolio state
|
|
58
|
+
await this.indexManager.rebuildIndex();
|
|
59
|
+
const localElements = await this.getAllLocalElements();
|
|
60
|
+
progressMessages.push(`š Found ${this.countElements(localElements)} local elements`);
|
|
61
|
+
// Step 4: Compare and determine sync actions
|
|
62
|
+
const syncActions = this.syncComparer.compareElements(githubIndex.elements, localElements, syncMode);
|
|
63
|
+
// Step 5: Handle dry-run mode
|
|
64
|
+
if (options.dryRun) {
|
|
65
|
+
return this.formatDryRunResults(syncActions, progressMessages, personaIndicator);
|
|
66
|
+
}
|
|
67
|
+
// Step 6: Check for deletions requiring confirmation
|
|
68
|
+
if (syncActions.toDelete.length > 0 &&
|
|
69
|
+
syncMode === 'mirror' &&
|
|
70
|
+
!options.force &&
|
|
71
|
+
options.confirmDeletions !== false) {
|
|
72
|
+
return {
|
|
73
|
+
content: [{
|
|
74
|
+
type: "text",
|
|
75
|
+
text: `${personaIndicator}ā ļø Pull operation would delete ${syncActions.toDelete.length} local elements.\n\n` +
|
|
76
|
+
`Elements to delete:\n${syncActions.toDelete.map(a => ` - ${a.name}`).join('\n')}\n\n` +
|
|
77
|
+
`To proceed, run with \`force: true\` or \`confirmDeletions: false\``
|
|
78
|
+
}]
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
// Step 7: Execute sync actions
|
|
82
|
+
const results = await this.executeSyncActions(syncActions, githubIndex.username, githubIndex.repository, progressMessages);
|
|
83
|
+
// Step 8: Return success summary
|
|
84
|
+
return {
|
|
85
|
+
content: [{
|
|
86
|
+
type: "text",
|
|
87
|
+
text: `${personaIndicator}ā
**Portfolio Pull Complete**\n\n` +
|
|
88
|
+
progressMessages.join('\n') + '\n\n' +
|
|
89
|
+
`**Summary:**\n` +
|
|
90
|
+
` š„ Added: ${results.added}\n` +
|
|
91
|
+
` š Updated: ${results.updated}\n` +
|
|
92
|
+
` š Skipped: ${results.skipped}\n` +
|
|
93
|
+
(results.deleted > 0 ? ` šļø Deleted: ${results.deleted}\n` : '') +
|
|
94
|
+
`\nYour local portfolio is now synchronized with GitHub!`
|
|
95
|
+
}]
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
logger.error('Portfolio pull failed', { error });
|
|
100
|
+
return {
|
|
101
|
+
content: [{
|
|
102
|
+
type: "text",
|
|
103
|
+
text: `${personaIndicator}ā Failed to pull portfolio: ${error instanceof Error ? error.message : String(error)}`
|
|
104
|
+
}]
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Validate and normalize sync mode
|
|
110
|
+
* SECURITY FIX: Added Unicode normalization to prevent homograph attacks
|
|
111
|
+
*/
|
|
112
|
+
validateSyncMode(mode) {
|
|
113
|
+
const validModes = ['additive', 'mirror', 'backup'];
|
|
114
|
+
// SECURITY FIX: Normalize Unicode to prevent homograph attacks
|
|
115
|
+
const normalizedMode = mode ?
|
|
116
|
+
UnicodeValidator.normalize(mode).normalizedContent :
|
|
117
|
+
'additive';
|
|
118
|
+
const syncMode = normalizedMode.toLowerCase();
|
|
119
|
+
if (!validModes.includes(syncMode)) {
|
|
120
|
+
throw new Error(`Invalid sync mode: ${mode}. Valid modes are: ${validModes.join(', ')}`);
|
|
121
|
+
}
|
|
122
|
+
return syncMode;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Get all local elements organized by type
|
|
126
|
+
*/
|
|
127
|
+
async getAllLocalElements() {
|
|
128
|
+
const elements = new Map();
|
|
129
|
+
const elementTypes = Object.values(ElementType);
|
|
130
|
+
for (const type of elementTypes) {
|
|
131
|
+
const typeElements = await this.indexManager.getElementsByType(type);
|
|
132
|
+
if (typeElements.length > 0) {
|
|
133
|
+
elements.set(type, typeElements);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return elements;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Count total elements in a map
|
|
140
|
+
*/
|
|
141
|
+
countElements(elements) {
|
|
142
|
+
let count = 0;
|
|
143
|
+
for (const typeElements of elements.values()) {
|
|
144
|
+
count += typeElements.length;
|
|
145
|
+
}
|
|
146
|
+
return count;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Format dry-run results for display
|
|
150
|
+
*/
|
|
151
|
+
formatDryRunResults(syncActions, progressMessages, personaIndicator) {
|
|
152
|
+
const lines = [
|
|
153
|
+
`${personaIndicator}š **Dry Run Results**`,
|
|
154
|
+
'',
|
|
155
|
+
...progressMessages,
|
|
156
|
+
'',
|
|
157
|
+
'**Planned Actions:**'
|
|
158
|
+
];
|
|
159
|
+
if (syncActions.toAdd.length > 0) {
|
|
160
|
+
lines.push(`\nš„ **To Add (${syncActions.toAdd.length}):**`);
|
|
161
|
+
syncActions.toAdd.forEach(action => {
|
|
162
|
+
lines.push(` - ${action.type}/${action.name}`);
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
if (syncActions.toUpdate.length > 0) {
|
|
166
|
+
lines.push(`\nš **To Update (${syncActions.toUpdate.length}):**`);
|
|
167
|
+
syncActions.toUpdate.forEach(action => {
|
|
168
|
+
lines.push(` - ${action.type}/${action.name}`);
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
if (syncActions.toDelete.length > 0) {
|
|
172
|
+
lines.push(`\nšļø **To Delete (${syncActions.toDelete.length}):**`);
|
|
173
|
+
syncActions.toDelete.forEach(action => {
|
|
174
|
+
lines.push(` - ${action.type}/${action.name}`);
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
if (syncActions.toSkip.length > 0) {
|
|
178
|
+
lines.push(`\nš **To Skip (${syncActions.toSkip.length}):**`);
|
|
179
|
+
syncActions.toSkip.forEach(action => {
|
|
180
|
+
lines.push(` - ${action.type}/${action.name} (${action.reason})`);
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
lines.push('', 'Run without `dryRun: true` to execute these changes.');
|
|
184
|
+
return {
|
|
185
|
+
content: [{
|
|
186
|
+
type: "text",
|
|
187
|
+
text: lines.join('\n')
|
|
188
|
+
}]
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Execute the sync actions
|
|
193
|
+
*/
|
|
194
|
+
async executeSyncActions(syncActions, username, repository, progressMessages) {
|
|
195
|
+
const results = {
|
|
196
|
+
added: 0,
|
|
197
|
+
updated: 0,
|
|
198
|
+
deleted: 0,
|
|
199
|
+
skipped: syncActions.toSkip.length
|
|
200
|
+
};
|
|
201
|
+
// PERFORMANCE: Process downloads in parallel batches for improved speed
|
|
202
|
+
const BATCH_SIZE = 5; // Process 5 downloads at a time to avoid rate limiting
|
|
203
|
+
// Helper function to process a batch of actions
|
|
204
|
+
const processBatch = async (actions, operation) => {
|
|
205
|
+
const results = await Promise.allSettled(actions.map(async (action) => {
|
|
206
|
+
progressMessages.push(`${operation}: ${action.type}/${action.name}`);
|
|
207
|
+
await this.downloadAndSaveElement(action, username, repository);
|
|
208
|
+
return action;
|
|
209
|
+
}));
|
|
210
|
+
return results.map((result, index) => ({
|
|
211
|
+
action: actions[index],
|
|
212
|
+
success: result.status === 'fulfilled',
|
|
213
|
+
error: result.status === 'rejected' ? result.reason : null
|
|
214
|
+
}));
|
|
215
|
+
};
|
|
216
|
+
// Process additions in batches
|
|
217
|
+
for (let i = 0; i < syncActions.toAdd.length; i += BATCH_SIZE) {
|
|
218
|
+
const batch = syncActions.toAdd.slice(i, i + BATCH_SIZE);
|
|
219
|
+
const batchResults = await processBatch(batch, 'š„ Downloading');
|
|
220
|
+
for (const result of batchResults) {
|
|
221
|
+
if (result.success) {
|
|
222
|
+
results.added++;
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
logger.error(`Failed to add ${result.action.type}/${result.action.name}`, { error: result.error });
|
|
226
|
+
progressMessages.push(`ā Failed to add: ${result.action.type}/${result.action.name}`);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
// Process updates in batches
|
|
231
|
+
for (let i = 0; i < syncActions.toUpdate.length; i += BATCH_SIZE) {
|
|
232
|
+
const batch = syncActions.toUpdate.slice(i, i + BATCH_SIZE);
|
|
233
|
+
const batchResults = await processBatch(batch, 'š Updating');
|
|
234
|
+
for (const result of batchResults) {
|
|
235
|
+
if (result.success) {
|
|
236
|
+
results.updated++;
|
|
237
|
+
}
|
|
238
|
+
else {
|
|
239
|
+
logger.error(`Failed to update ${result.action.type}/${result.action.name}`, { error: result.error });
|
|
240
|
+
progressMessages.push(`ā Failed to update: ${result.action.type}/${result.action.name}`);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
// Process deletions
|
|
245
|
+
for (const action of syncActions.toDelete) {
|
|
246
|
+
try {
|
|
247
|
+
progressMessages.push(`šļø Deleting: ${action.type}/${action.name}`);
|
|
248
|
+
await this.deleteLocalElement(action);
|
|
249
|
+
results.deleted++;
|
|
250
|
+
}
|
|
251
|
+
catch (error) {
|
|
252
|
+
logger.error(`Failed to delete ${action.type}/${action.name}`, { error });
|
|
253
|
+
progressMessages.push(`ā Failed to delete: ${action.type}/${action.name}`);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
// PERFORMANCE: Batch rebuild index after all operations complete
|
|
257
|
+
if (results.added > 0 || results.updated > 0 || results.deleted > 0) {
|
|
258
|
+
progressMessages.push('š Rebuilding index...');
|
|
259
|
+
await this.indexManager.rebuildIndex();
|
|
260
|
+
}
|
|
261
|
+
return results;
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Download element from GitHub and save locally
|
|
265
|
+
* SECURITY: Added audit logging for GitHub operations
|
|
266
|
+
*/
|
|
267
|
+
async downloadAndSaveElement(action, username, repository) {
|
|
268
|
+
// Set up the repo manager with the correct context
|
|
269
|
+
this.portfolioRepoManager.setToken(await this.getGitHubToken());
|
|
270
|
+
// SECURITY: Log the download operation for audit trail
|
|
271
|
+
SecurityMonitor.logSecurityEvent({
|
|
272
|
+
type: 'PORTFOLIO_FETCH_SUCCESS',
|
|
273
|
+
severity: 'LOW',
|
|
274
|
+
source: 'PortfolioPullHandler.downloadAndSaveElement',
|
|
275
|
+
details: `Downloading element: ${action.type}/${action.name} from ${username}/${repository}`
|
|
276
|
+
});
|
|
277
|
+
// Download the element content
|
|
278
|
+
const elementData = await this.downloader.downloadFromGitHub(this.portfolioRepoManager, action.path, username, repository);
|
|
279
|
+
// Save to local portfolio
|
|
280
|
+
const elementDir = this.portfolioManager.getElementDir(action.type);
|
|
281
|
+
const fileName = path.basename(action.path);
|
|
282
|
+
const filePath = path.join(elementDir, fileName);
|
|
283
|
+
await fs.writeFile(filePath, elementData.content, 'utf-8');
|
|
284
|
+
// SECURITY: Log successful save for audit trail
|
|
285
|
+
SecurityMonitor.logSecurityEvent({
|
|
286
|
+
type: 'ELEMENT_CREATED',
|
|
287
|
+
severity: 'LOW',
|
|
288
|
+
source: 'PortfolioPullHandler.downloadAndSaveElement',
|
|
289
|
+
details: `Saved element to: ${action.type}/${fileName}`
|
|
290
|
+
});
|
|
291
|
+
// PERFORMANCE: Skip individual index rebuild - will batch rebuild after all operations
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Delete local element
|
|
295
|
+
* SECURITY: Added audit logging for deletion operations
|
|
296
|
+
*/
|
|
297
|
+
async deleteLocalElement(action) {
|
|
298
|
+
const elementDir = this.portfolioManager.getElementDir(action.type);
|
|
299
|
+
// Use the original filename from the path to preserve extension
|
|
300
|
+
const fileName = path.basename(action.path) || `${action.name}.md`;
|
|
301
|
+
const filePath = path.join(elementDir, fileName);
|
|
302
|
+
// SECURITY: Log deletion attempt for audit trail
|
|
303
|
+
SecurityMonitor.logSecurityEvent({
|
|
304
|
+
type: 'ELEMENT_DELETED',
|
|
305
|
+
severity: 'MEDIUM',
|
|
306
|
+
source: 'PortfolioPullHandler.deleteLocalElement',
|
|
307
|
+
details: `Attempting to delete: ${action.type}/${fileName}`
|
|
308
|
+
});
|
|
309
|
+
try {
|
|
310
|
+
await fs.unlink(filePath);
|
|
311
|
+
// PERFORMANCE: Skip individual index rebuild - will batch rebuild after all operations
|
|
312
|
+
// SECURITY: Log successful deletion
|
|
313
|
+
SecurityMonitor.logSecurityEvent({
|
|
314
|
+
type: 'ELEMENT_DELETED',
|
|
315
|
+
severity: 'MEDIUM',
|
|
316
|
+
source: 'PortfolioPullHandler.deleteLocalElement',
|
|
317
|
+
details: `Successfully deleted: ${action.type}/${fileName}`
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
catch (error) {
|
|
321
|
+
if (error.code !== 'ENOENT') {
|
|
322
|
+
throw error;
|
|
323
|
+
}
|
|
324
|
+
// File already doesn't exist, that's fine
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Get GitHub token from auth manager
|
|
329
|
+
*/
|
|
330
|
+
async getGitHubToken() {
|
|
331
|
+
// This should use the same token management as the rest of the system
|
|
332
|
+
const { TokenManager } = await import('../security/tokenManager.js');
|
|
333
|
+
const token = await TokenManager.getGitHubTokenAsync();
|
|
334
|
+
if (!token) {
|
|
335
|
+
throw new Error('GitHub authentication required. Please run setup_github_auth first.');
|
|
336
|
+
}
|
|
337
|
+
return token;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUG9ydGZvbGlvUHVsbEhhbmRsZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaGFuZGxlcnMvUG9ydGZvbGlvUHVsbEhhbmRsZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7OztHQU1HO0FBRUgsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sc0NBQXNDLENBQUM7QUFDNUUsT0FBTyxFQUFFLHNCQUFzQixFQUFFLE1BQU0sd0NBQXdDLENBQUM7QUFDaEYsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sa0NBQWtDLENBQUM7QUFDcEUsT0FBTyxFQUFFLHFCQUFxQixFQUFFLE1BQU0sdUNBQXVDLENBQUM7QUFDOUUsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQ3BELE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUM1QyxPQUFPLEVBQUUscUJBQXFCLEVBQXdCLE1BQU0sa0NBQWtDLENBQUM7QUFDL0YsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFDckUsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sNENBQTRDLENBQUM7QUFDOUUsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBQ2pFLE9BQU8sRUFBRSwwQkFBMEIsRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBQzFFLE9BQU8sS0FBSyxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQ2xDLE9BQU8sS0FBSyxJQUFJLE1BQU0sTUFBTSxDQUFDO0FBaUI3QixNQUFNLE9BQU8sb0JBQW9CO0lBQ3ZCLG9CQUFvQixDQUF1QjtJQUMzQyxhQUFhLENBQXlCO0lBQ3RDLGdCQUFnQixDQUFtQjtJQUNuQyxZQUFZLENBQXdCO0lBQ3BDLFlBQVksQ0FBd0I7SUFDcEMsVUFBVSxDQUFzQjtJQUV4QztRQUNFLElBQUksQ0FBQyxvQkFBb0IsR0FBRyxJQUFJLG9CQUFvQixDQUFDLDBC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eUJBQXlCLE1BQU0sQ0FBQyxJQUFJLElBQUksUUFBUSxFQUFFO2FBQzVELENBQUMsQ0FBQztRQUNMLENBQUM7UUFBQyxPQUFPLEtBQVUsRUFBRSxDQUFDO1lBQ3BCLElBQUksS0FBSyxDQUFDLElBQUksS0FBSyxRQUFRLEVBQUUsQ0FBQztnQkFDNUIsTUFBTSxLQUFLLENBQUM7WUFDZCxDQUFDO1lBQ0QsMENBQTBDO1FBQzVDLENBQUM7SUFDSCxDQUFDO0lBRUQ7O09BRUc7SUFDSyxLQUFLLENBQUMsY0FBYztRQUMxQixzRUFBc0U7UUFDdEUsTUFBTSxFQUFFLFlBQVksRUFBRSxHQUFHLE1BQU0sTUFBTSxDQUFDLDZCQUE2QixDQUFDLENBQUM7UUFDckUsTUFBTSxLQUFLLEdBQUcsTUFBTSxZQUFZLENBQUMsbUJBQW1CLEVBQUUsQ0FBQztRQUN2RCxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDWCxNQUFNLElBQUksS0FBSyxDQUFDLHFFQUFxRSxDQUFDLENBQUM7UUFDekYsQ0FBQztRQUNELE9BQU8sS0FBSyxDQUFDO0lBQ2YsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBQb3J0Zm9saW9QdWxsSGFuZGxlciAtIEhhbmRsZXMgcHVsbGluZyBwb3J0Zm9saW8gZWxlbWVudHMgZnJvbSBHaXRIdWJcbiAqIFxuICogVGhpcyBoYW5kbGVyIGltcGxlbWVudHMgdGhlIHB1bGwgZnVuY3Rpb25hbGl0eSBmb3Igc3luY19wb3J0Zm9saW8sXG4gKiBlbmFibGluZyB1c2VycyB0byBkb3dubG9hZCB0aGVpciBwb3J0Zm9saW8gZnJvbSBHaXRIdWIgdG8gbG9jYWwgc3RvcmFnZS5cbiAqIFN1cHBvcnRzIG11bHRpcGxlIHN5bmMgbW9kZXMgKGFkZGl0aXZlLCBtaXJyb3IsIGJhY2t1cCkgYW5kIGRyeS1ydW4uXG4gKi9cblxuaW1wb3J0IHsgUG9ydGZvbGlvUmVwb01hbmFnZXIgfSBmcm9tICcuLi9wb3J0Zm9saW8vUG9ydGZvbGlvUmVwb01hbmFnZXIuanMnO1xuaW1wb3J0IHsgR2l0SHViUG9ydGZvbGlvSW5kZXhlciB9IGZyb20gJy4uL3BvcnRmb2xpby9HaXRIdWJQb3J0Zm9saW9JbmRleGVyLmpzJztcbmltcG9ydCB7IFBvcnRmb2xpb01hbmFnZXIgfSBmcm9tICcuLi9wb3J0Zm9saW8vUG9ydGZvbGlvTWFuYWdlci5qcyc7XG5pbXBvcnQgeyBQb3J0Zm9saW9JbmRleE1hbmFnZXIgfSBmcm9tICcuLi9wb3J0Zm9saW8vUG9ydGZvbGlvSW5kZXhNYW5hZ2VyLmpzJztcbmltcG9ydCB7IEVsZW1lbnRUeXBlIH0gZnJvbSAnLi4vcG9ydGZvbGlvL3R5cGVzLmpzJztcbmltcG9ydCB7IGxvZ2dlciB9IGZyb20gJy4uL3V0aWxzL2xvZ2dlci5qcyc7XG5pbXBvcnQgeyBQb3J0Zm9saW9TeW5jQ29tcGFyZXIsIFN5bmNNb2RlLCBTeW5jQWN0aW9uIH0gZnJvbSAnLi4vc3luYy9Qb3J0Zm9saW9TeW5jQ29tcGFyZXIuanMnO1xuaW1wb3J0IHsgUG9ydGZvbGlvRG93bmxvYWRlciB9IGZyb20gJy4uL3N5bmMvUG9ydGZvbGlvRG93bmxvYWRlci5qcyc7XG5pbXBvcnQgeyBVbmljb2RlVmFsaWRhdG9yIH0gZnJvbSAnLi4vc2VjdXJpdHkvdmFsaWRhdG9ycy91bmljb2RlVmFsaWRhdG9yLmpzJztcbmltcG9ydCB7IFNlY3VyaXR5TW9uaXRvciB9IGZyb20gJy4uL3NlY3VyaXR5L3NlY3VyaXR5TW9uaXRvci5qcyc7XG5pbXBvcnQgeyBnZXRQb3J0Zm9saW9SZXBvc2l0b3J5TmFtZSB9IGZyb20gJy4uL2NvbmZpZy9wb3J0Zm9saW9Db25maWcuanMnO1xuaW1wb3J0ICogYXMgZnMgZnJvbSAnZnMvcHJvbWlzZXMnO1xuaW1wb3J0ICogYXMgcGF0aCBmcm9tICdwYXRoJztcblxuZXhwb3J0IGludGVyZmFjZSBQdWxsT3B0aW9ucyB7XG4gIGRpcmVjdGlvbjogc3RyaW5nO1xuICBtb2RlPzogc3RyaW5nO1xuICBmb3JjZT86IGJvb2xlYW47XG4gIGRyeVJ1bj86IGJvb2xlYW47XG4gIGNvbmZpcm1EZWxldGlvbnM/OiBib29sZWFuO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFB1bGxSZXN1bHQge1xuICBjb250ZW50OiBBcnJheTx7XG4gICAgdHlwZTogc3RyaW5nO1xuICAgIHRleHQ6IHN0cmluZztcbiAgfT47XG59XG5cbmV4cG9ydCBjbGFzcyBQb3J0Zm9saW9QdWxsSGFuZGxlciB7XG4gIHByaXZhdGUgcG9ydGZvbGlvUmVwb01hbmFnZXI6IFBvcnRmb2xpb1JlcG9NYW5hZ2VyO1xuICBwcml2YXRlIGdpdGh1YkluZGV4ZXI6IEdpdEh1YlBvcnRmb2xpb0luZGV4ZXI7XG4gIHByaXZhdGUgcG9ydGZvbGlvTWFuYWdlcjogUG9ydGZvbGlvTWFuYWdlcjtcbiAgcHJpdmF0ZSBpbmRleE1hbmFnZXI6IFBvcnRmb2xpb0luZGV4TWFuYWdlcjtcbiAgcHJpdmF0ZSBzeW5jQ29tcGFyZXI6IFBvcnRmb2xpb1N5bmNDb21wYXJlcjtcbiAgcHJpdmF0ZSBkb3dubG9hZGVyOiBQb3J0Zm9saW9Eb3dubG9hZGVyO1xuXG4gIGNvbnN0cnVjdG9yKCkge1xuICAgIHRoaXMucG9ydGZvbGlvUmVwb01hbmFnZXIgPSBuZXcgUG9ydGZvbGlvUmVwb01hbmFnZXIoZ2V0UG9ydGZvbGlvUmVwb3NpdG9yeU5hbWUoKSk7XG4gICAgdGhpcy5naXRodWJJbmRleGVyID0gR2l0SHViUG9ydGZvbGlvSW5kZXhlci5nZXRJbnN0YW5jZSgpO1xuICAgIHRoaXMucG9ydGZvbGlvTWFuYWdlciA9IFBvcnRmb2xpb01hbmFnZXIuZ2V0SW5zdGFuY2UoKTtcbiAgICB0aGlzLmluZGV4TWFuYWdlciA9IFBvcnRmb2xpb0luZGV4TWFuYWdlci5nZXRJbnN0YW5jZSgpO1xuICAgIHRoaXMuc3luY0NvbXBhcmVyID0gbmV3IFBvcnRmb2xpb1N5bmNDb21wYXJlcigpO1xuICAgIHRoaXMuZG93bmxvYWRlciA9IG5ldyBQb3J0Zm9saW9Eb3dubG9hZGVyKCk7XG4gIH1cblxuICAvKipcbiAgICogRXhlY3V0ZSB0aGUgcHVsbCBvcGVyYXRpb24gZnJvbSBHaXRIdWIgdG8gbG9jYWwgcG9ydGZvbGlvXG4gICAqL1xuICBhc3luYyBleGVjdXRlUHVsbChvcHRpb25zOiBQdWxsT3B0aW9ucywgcGVyc29uYUluZGljYXRvcjogc3RyaW5nKTogUHJvbWlzZTxQdWxsUmVzdWx0PiB7XG4gICAgdHJ5IHtcbiAgICAgIGxvZ2dlci5pbmZvKCdTdGFydGluZyBwb3J0Zm9saW8gcHVsbCBvcGVyYXRpb24nLCB7IG9wdGlvbnMgfSk7XG4gICAgICBcbiAgICAgIC8vIFN0ZXAgMTogVmFsaWRhdGUgc3luYyBtb2RlXG4gICAgICBjb25zdCBzeW5jTW9kZSA9IHRoaXMudmFsaWRhdGVTeW5jTW9kZShvcHRpb25zLm1vZGUpO1xuICAgICAgXG4gICAgICAvLyBTdGVwIDI6IEZldGNoIEdpdEh1YiBwb3J0Zm9saW8gaW5kZXhcbiAgICAgIGNvbnN0IHByb2dyZXNzTWVzc2FnZXM6IHN0cmluZ1tdID0gW107XG4gICAgICBwcm9ncmVzc01lc3NhZ2VzLnB1c2goJ/CflI0gRmV0Y2hpbmcgcG9ydGZvbGlvIGZyb20gR2l0SHViLi4uJyk7XG4gICAgICBcbiAgICAgIGNvbnN0IGdpdGh1YkluZGV4ID0gYXdhaXQgdGhpcy5naXRodWJJbmRleGVyLmdldEluZGV4KHRydWUpO1xuICAgICAgXG4gICAgICBpZiAoIWdpdGh1YkluZGV4IHx8IGdpdGh1YkluZGV4LnRvdGFsRWxlbWVudHMgPT09IDApIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBjb250ZW50OiBbe1xuICAgICAgICAgICAgdHlwZTogXCJ0ZXh0XCIsXG4gICAgICAgICAgICB0ZXh0OiBgJHtwZXJzb25hSW5kaWNhdG9yfeKaoO+4jyBObyBlbGVtZW50cyBmb3VuZCBpbiBHaXRIdWIgcG9ydGZvbGlvLiBOb3RoaW5nIHRvIHB1bGwuYFxuICAgICAgICAgIH1dXG4gICAgICAgIH07XG4gICAgICB9XG4gICAgICBcbiAgICAgIHByb2dyZXNzTWVzc2FnZXMucHVzaChg8J+TiiBGb3VuZCAke2dpdGh1YkluZGV4LnRvdGFsRWxlbWVudHN9IGVsZW1lbnRzIG9uIEdpdEh1YmApO1xuICAgICAgXG4gICAgICAvLyBTdGVwIDM6IEdldCBsb2NhbCBwb3J0Zm9saW8gc3RhdGVcbiAgICAgIGF3YWl0IHRoaXMuaW5kZXhNYW5hZ2VyLnJlYnVpbGRJbmRleCgpO1xuICAgICAgY29uc3QgbG9jYWxFbGVtZW50cyA9IGF3YWl0IHRoaXMuZ2V0QWxsTG9jYWxFbGVtZW50cygpO1xuICAgICAgcHJvZ3Jlc3NNZXNzYWdlcy5wdXNoKGDwn5OBIEZvdW5kICR7dGhpcy5jb3VudEVsZW1lbnRzKGxvY2FsRWxlbWVudHMpfSBsb2NhbCBlbGVtZW50c2ApO1xuICAgICAgXG4gICAgICAvLyBTdGVwIDQ6IENvbXBhcmUgYW5kIGRldGVybWluZSBzeW5jIGFjdGlvbnNcbiAgICAgIGNvbnN0IHN5bmNBY3Rpb25zID0gdGhpcy5zeW5jQ29tcGFyZXIuY29tcGFyZUVsZW1lbnRzKFxuICAgICAgICBnaXRodWJJbmRleC5lbGVtZW50cyxcbiAgICAgICAgbG9jYWxFbGVtZW50cyxcbiAgICAgICAgc3luY01vZGVcbiAgICAgICk7XG4gICAgICBcbiAgICAgIC8vIFN0ZXAgNTogSGFuZGxlIGRyeS1ydW4gbW9kZVxuICAgICAgaWYgKG9wdGlvbnMuZHJ5UnVuKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmZvcm1hdERyeVJ1blJlc3VsdHMoc3luY0FjdGlvbnMsIHByb2dyZXNzTWVzc2FnZXMsIHBlcnNvbmFJbmRpY2F0b3IpO1xuICAgICAgfVxuICAgICAgXG4gICAgICAvLyBTdGVwIDY6IENoZWNrIGZvciBkZWxldGlvbnMgcmVxdWlyaW5nIGNvbmZpcm1hdGlvblxuICAgICAgaWYgKHN5bmNBY3Rpb25zLnRvRGVsZXRlLmxlbmd0aCA+IDAgJiYgXG4gICAgICAgICAgc3luY01vZGUgPT09ICdtaXJyb3InICYmIFxuICAgICAgICAgICFvcHRpb25zLmZvcmNlICYmIFxuICAgICAgICAgIG9wdGlvbnMuY29uZmlybURlbGV0aW9ucyAhPT0gZmFsc2UpIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBjb250ZW50OiBbe1xuICAgICAgICAgICAgdHlwZTogXCJ0ZXh0XCIsXG4gICAgICAgICAgICB0ZXh0OiBgJHtwZXJzb25hSW5kaWNhdG9yfeKaoO+4jyBQdWxsIG9wZXJhdGlvbiB3b3VsZCBkZWxldGUgJHtzeW5jQWN0aW9ucy50b0RlbGV0ZS5sZW5ndGh9IGxvY2FsIGVsZW1lbnRzLlxcblxcbmAgK1xuICAgICAgICAgICAgICAgICAgYEVsZW1lbnRzIHRvIGRlbGV0ZTpcXG4ke3N5bmNBY3Rpb25zLnRvRGVsZXRlLm1hcChhID0+IGAgIC0gJHthLm5hbWV9YCkuam9pbignXFxuJyl9XFxuXFxuYCArXG4gICAgICAgICAgICAgICAgICBgVG8gcHJvY2VlZCwgcnVuIHdpdGggXFxgZm9yY2U6IHRydWVcXGAgb3IgXFxgY29uZmlybURlbGV0aW9uczogZmFsc2VcXGBgXG4gICAgICAgICAgfV1cbiAgICAgICAgfTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgLy8gU3RlcCA3OiBFeGVjdXRlIHN5bmMgYWN0aW9uc1xuICAgICAgY29uc3QgcmVzdWx0cyA9IGF3YWl0IHRoaXMuZXhlY3V0ZVN5bmNBY3Rpb25zKFxuICAgICAgICBzeW5jQWN0aW9ucywgXG4gICAgICAgIGdpdGh1YkluZGV4LnVzZXJuYW1lLCBcbiAgICAgICAgZ2l0aHViSW5kZXgucmVwb3NpdG9yeSxcbiAgICAgICAgcHJvZ3Jlc3NNZXNzYWdlc1xuICAgICAgKTtcbiAgICAgIFxuICAgICAgLy8gU3RlcCA4OiBSZXR1cm4gc3VjY2VzcyBzdW1tYXJ5XG4gICAgICByZXR1cm4ge1xuICAgICAgICBjb250ZW50OiBbe1xuICAgICAgICAgIHR5cGU6IFwidGV4dFwiLFxuICAgICAgICAgIHRleHQ6IGAke3BlcnNvbmFJbmRpY2F0b3J94pyFICoqUG9ydGZvbGlvIFB1bGwgQ29tcGxldGUqKlxcblxcbmAgK1xuICAgICAgICAgICAgICAgIHByb2dyZXNzTWVzc2FnZXMuam9pbignXFxuJykgKyAnXFxuXFxuJyArXG4gICAgICAgICAgICAgICAgYCoqU3VtbWFyeToqKlxcbmAgK1xuICAgICAgICAgICAgICAgIGAgIPCfk6UgQWRkZWQ6ICR7cmVzdWx0cy5hZGRlZH1cXG5gICtcbiAgICAgICAgICAgICAgICBgICDwn5SEIFVwZGF0ZWQ6ICR7cmVzdWx0cy51cGRhdGVkfVxcbmAgK1xuICAgICAgICAgICAgICAgIGAgIPCflJcgU2tpcHBlZDogJHtyZXN1bHRzLnNraXBwZWR9XFxuYCArXG4gICAgICAgICAgICAgICAgKHJlc3VsdHMuZGVsZXRlZCA+IDAgPyBgICDwn5eR77iPIERlbGV0ZWQ6ICR7cmVzdWx0cy5kZWxldGVkfVxcbmAgOiAnJykgK1xuICAgICAgICAgICAgICAgIGBcXG5Zb3VyIGxvY2FsIHBvcnRmb2xpbyBpcyBub3cgc3luY2hyb25pemVkIHdpdGggR2l0SHViIWBcbiAgICAgICAgfV1cbiAgICAgIH07XG4gICAgICBcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgbG9nZ2VyLmVycm9yKCdQb3J0Zm9saW8gcHVsbCBmYWlsZWQnLCB7IGVycm9yIH0pO1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgY29udGVudDogW3tcbiAgICAgICAgICB0eXBlOiBcInRleHRcIixcbiAgICAgICAgICB0ZXh0OiBgJHtwZXJzb25hSW5kaWNhdG9yfeKdjCBGYWlsZWQgdG8gcHVsbCBwb3J0Zm9saW86ICR7ZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpfWBcbiAgICAgICAgfV1cbiAgICAgIH07XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFZhbGlkYXRlIGFuZCBub3JtYWxpemUgc3luYyBtb2RlXG4gICAqIFNFQ1VSSVRZIEZJWDogQWRkZWQgVW5pY29kZSBub3JtYWxpemF0aW9uIHRvIHByZXZlbnQgaG9tb2dyYXBoIGF0dGFja3NcbiAgICovXG4gIHByaXZhdGUgdmFsaWRhdGVTeW5jTW9kZShtb2RlPzogc3RyaW5nKTogU3luY01vZGUge1xuICAgIGNvbnN0IHZhbGlkTW9kZXM6IFN5bmNNb2RlW10gPSBbJ2FkZGl0aXZlJywgJ21pcnJvcicsICdiYWNrdXAnXTtcbiAgICBcbiAgICAvLyBTRUNVUklUWSBGSVg6IE5vcm1hbGl6ZSBVbmljb2RlIHRvIHByZXZlbnQgaG9tb2dyYXBoIGF0dGFja3NcbiAgICBjb25zdCBub3JtYWxpemVkTW9kZSA9IG1vZGUgPyBcbiAgICAgIFVuaWNvZGVWYWxpZGF0b3Iubm9ybWFsaXplKG1vZGUpLm5vcm1hbGl6ZWRDb250ZW50IDogXG4gICAgICAnYWRkaXRpdmUnO1xuICAgIFxuICAgIGNvbnN0IHN5bmNNb2RlID0gbm9ybWFsaXplZE1vZGUudG9Mb3dlckNhc2UoKSBhcyBTeW5jTW9kZTtcbiAgICBcbiAgICBpZiAoIXZhbGlkTW9kZXMuaW5jbHVkZXMoc3luY01vZGUpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgc3luYyBtb2RlOiAke21vZGV9LiBWYWxpZCBtb2RlcyBhcmU6ICR7dmFsaWRNb2Rlcy5qb2luKCcsICcpfWApO1xuICAgIH1cbiAgICBcbiAgICByZXR1cm4gc3luY01vZGU7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGFsbCBsb2NhbCBlbGVtZW50cyBvcmdhbml6ZWQgYnkgdHlwZVxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBnZXRBbGxMb2NhbEVsZW1lbnRzKCk6IFByb21pc2U8TWFwPEVsZW1lbnRUeXBlLCBhbnlbXT4+IHtcbiAgICBjb25zdCBlbGVtZW50cyA9IG5ldyBNYXA8RWxlbWVudFR5cGUsIGFueVtdPigpO1xuICAgIGNvbnN0IGVsZW1lbnRUeXBlcyA9IE9iamVjdC52YWx1ZXMoRWxlbWVudFR5cGUpO1xuICAgIFxuICAgIGZvciAoY29uc3QgdHlwZSBvZiBlbGVtZW50VHlwZXMpIHtcbiAgICAgIGNvbnN0IHR5cGVFbGVtZW50cyA9IGF3YWl0IHRoaXMuaW5kZXhNYW5hZ2VyLmdldEVsZW1lbnRzQnlUeXBlKHR5cGUpO1xuICAgICAgaWYgKHR5cGVFbGVtZW50cy5sZW5ndGggPiAwKSB7XG4gICAgICAgIGVsZW1lbnRzLnNldCh0eXBlLCB0eXBlRWxlbWVudHMpO1xuICAgICAgfVxuICAgIH1cbiAgICBcbiAgICByZXR1cm4gZWxlbWVudHM7XG4gIH1cblxuICAvKipcbiAgICogQ291bnQgdG90YWwgZWxlbWVudHMgaW4gYSBtYXBcbiAgICovXG4gIHByaXZhdGUgY291bnRFbGVtZW50cyhlbGVtZW50czogTWFwPEVsZW1lbnRUeXBlLCBhbnlbXT4pOiBudW1iZXIge1xuICAgIGxldCBjb3VudCA9IDA7XG4gICAgZm9yIChjb25zdCB0eXBlRWxlbWVudHMgb2YgZWxlbWVudHMudmFsdWVzKCkpIHtcbiAgICAgIGNvdW50ICs9IHR5cGVFbGVtZW50cy5sZW5ndGg7XG4gICAgfVxuICAgIHJldHVybiBjb3VudDtcbiAgfVxuXG4gIC8qKlxuICAgKiBGb3JtYXQgZHJ5LXJ1biByZXN1bHRzIGZvciBkaXNwbGF5XG4gICAqL1xuICBwcml2YXRlIGZvcm1hdERyeVJ1blJlc3VsdHMoXG4gICAgc3luY0FjdGlvbnM6IHsgdG9BZGQ6IFN5bmNBY3Rpb25bXSwgdG9VcGRhdGU6IFN5bmNBY3Rpb25bXSwgdG9EZWxldGU6IFN5bmNBY3Rpb25bXSwgdG9Ta2lwOiBTeW5jQWN0aW9uW10gfSxcbiAgICBwcm9ncmVzc01lc3NhZ2VzOiBzdHJpbmdbXSxcbiAgICBwZXJzb25hSW5kaWNhdG9yOiBzdHJpbmdcbiAgKTogUHVsbFJlc3VsdCB7XG4gICAgY29uc3QgbGluZXMgPSBbXG4gICAgICBgJHtwZXJzb25hSW5kaWNhdG9yffCflI0gKipEcnkgUnVuIFJlc3VsdHMqKmAsXG4gICAgICAnJyxcbiAgICAgIC4uLnByb2dyZXNzTWVzc2FnZXMsXG4gICAgICAnJyxcbiAgICAgICcqKlBsYW5uZWQgQWN0aW9uczoqKidcbiAgICBdO1xuICAgIFxuICAgIGlmIChzeW5jQWN0aW9ucy50b0FkZC5sZW5ndGggPiAwKSB7XG4gICAgICBsaW5lcy5wdXNoKGBcXG7wn5OlICoqVG8gQWRkICgke3N5bmNBY3Rpb25zLnRvQWRkLmxlbmd0aH0pOioqYCk7XG4gICAgICBzeW5jQWN0aW9ucy50b0FkZC5mb3JFYWNoKGFjdGlvbiA9PiB7XG4gICAgICAgIGxpbmVzLnB1c2goYCAgLSAke2FjdGlvbi50eXBlfS8ke2FjdGlvbi5uYW1lfWApO1xuICAgICAgfSk7XG4gICAgfVxuICAgIFxuICAgIGlmIChzeW5jQWN0aW9ucy50b1VwZGF0ZS5sZW5ndGggPiAwKSB7XG4gICAgICBsaW5lcy5wdXNoKGBcXG7wn5SEICoqVG8gVXBkYXRlICgke3N5bmNBY3Rpb25zLnRvVXBkYXRlLmxlbmd0aH0pOioqYCk7XG4gICAgICBzeW5jQWN0aW9ucy50b1VwZGF0ZS5mb3JFYWNoKGFjdGlvbiA9PiB7XG4gICAgICAgIGxpbmVzLnB1c2goYCAgLSAke2FjdGlvbi50eXBlfS8ke2FjdGlvbi5uYW1lfWApO1xuICAgICAgfSk7XG4gICAgfVxuICAgIFxuICAgIGlmIChzeW5jQWN0aW9ucy50b0RlbGV0ZS5sZW5ndGggPiAwKSB7XG4gICAgICBsaW5lcy5wdXNoKGBcXG7wn5eR77iPICoqVG8gRGVsZXRlICgke3N5bmNBY3Rpb25zLnRvRGVsZXRlLmxlbmd0aH0pOioqYCk7XG4gICAgICBzeW5jQWN0aW9ucy50b0RlbGV0ZS5mb3JFYWNoKGFjdGlvbiA9PiB7XG4gICAgICAgIGxpbmVzLnB1c2goYCAgLSAke2FjdGlvbi50eXBlfS8ke2FjdGlvbi5uYW1lfWApO1xuICAgICAgfSk7XG4gICAgfVxuICAgIFxuICAgIGlmIChzeW5jQWN0aW9ucy50b1NraXAubGVuZ3RoID4gMCkge1xuICAgICAgbGluZXMucHVzaChgXFxu8J+UlyAqKlRvIFNraXAgKCR7c3luY0FjdGlvbnMudG9Ta2lwLmxlbmd0aH0pOioqYCk7XG4gICAgICBzeW5jQWN0aW9ucy50b1NraXAuZm9yRWFjaChhY3Rpb24gPT4ge1xuICAgICAgICBsaW5lcy5wdXNoKGAgIC0gJHthY3Rpb24udHlwZX0vJHthY3Rpb24ubmFtZX0gKCR7YWN0aW9uLnJlYXNvbn0pYCk7XG4gICAgICB9KTtcbiAgICB9XG4gICAgXG4gICAgbGluZXMucHVzaCgnJywgJ1J1biB3aXRob3V0IGBkcnlSdW46IHRydWVgIHRvIGV4ZWN1dGUgdGhlc2UgY2hhbmdlcy4nKTtcbiAgICBcbiAgICByZXR1cm4ge1xuICAgICAgY29udGVudDogW3tcbiAgICAgICAgdHlwZTogXCJ0ZXh0XCIsXG4gICAgICAgIHRleHQ6IGxpbmVzLmpvaW4oJ1xcbicpXG4gICAgICB9XVxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogRXhlY3V0ZSB0aGUgc3luYyBhY3Rpb25zXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGV4ZWN1dGVTeW5jQWN0aW9ucyhcbiAgICBzeW5jQWN0aW9uczogeyB0b0FkZDogU3luY0FjdGlvbltdLCB0b1VwZGF0ZTogU3luY0FjdGlvbltdLCB0b0RlbGV0ZTogU3luY0FjdGlvbltdLCB0b1NraXA6IFN5bmNBY3Rpb25bXSB9LFxuICAgIHVzZXJuYW1lOiBzdHJpbmcsXG4gICAgcmVwb3NpdG9yeTogc3RyaW5nLFxuICAgIHByb2dyZXNzTWVzc2FnZXM6IHN0cmluZ1tdXG4gICk6IFByb21pc2U8eyBhZGRlZDogbnVtYmVyLCB1cGRhdGVkOiBudW1iZXIsIGRlbGV0ZWQ6IG51bWJlciwgc2tpcHBlZDogbnVtYmVyIH0+IHtcbiAgICBjb25zdCByZXN1bHRzID0ge1xuICAgICAgYWRkZWQ6IDAsXG4gICAgICB1cGRhdGVkOiAwLFxuICAgICAgZGVsZXRlZDogMCxcbiAgICAgIHNraXBwZWQ6IHN5bmNBY3Rpb25zLnRvU2tpcC5sZW5ndGhcbiAgICB9O1xuICAgIFxuICAgIC8vIFBFUkZPUk1BTkNFOiBQcm9jZXNzIGRvd25sb2FkcyBpbiBwYXJhbGxlbCBiYXRjaGVzIGZvciBpbXByb3ZlZCBzcGVlZFxuICAgIGNvbnN0IEJBVENIX1NJWkUgPSA1OyAvLyBQcm9jZXNzIDUgZG93bmxvYWRzIGF0IGEgdGltZSB0byBhdm9pZCByYXRlIGxpbWl0aW5nXG4gICAgXG4gICAgLy8gSGVscGVyIGZ1bmN0aW9uIHRvIHByb2Nlc3MgYSBiYXRjaCBvZiBhY3Rpb25zXG4gICAgY29uc3QgcHJvY2Vzc0JhdGNoID0gYXN5bmMgKGFjdGlvbnM6IFN5bmNBY3Rpb25bXSwgb3BlcmF0aW9uOiBzdHJpbmcpID0+IHtcbiAgICAgIGNvbnN0IHJlc3VsdHMgPSBhd2FpdCBQcm9taXNlLmFsbFNldHRsZWQoXG4gICAgICAgIGFjdGlvbnMubWFwKGFzeW5jIChhY3Rpb24pID0+IHtcbiAgICAgICAgICBwcm9ncmVzc01lc3NhZ2VzLnB1c2goYCR7b3BlcmF0aW9ufTogJHthY3Rpb24udHlwZX0vJHthY3Rpb24ubmFtZX1gKTtcbiAgICAgICAgICBhd2FpdCB0aGlzLmRvd25sb2FkQW5kU2F2ZUVsZW1lbnQoYWN0aW9uLCB1c2VybmFtZSwgcmVwb3NpdG9yeSk7XG4gICAgICAgICAgcmV0dXJuIGFjdGlvbjtcbiAgICAgICAgfSlcbiAgICAgICk7XG4gICAgICBcbiAgICAgIHJldHVybiByZXN1bHRzLm1hcCgocmVzdWx0LCBpbmRleCkgPT4gKHtcbiAgICAgICAgYWN0aW9uOiBhY3Rpb25zW2luZGV4XSxcbiAgICAgICAgc3VjY2VzczogcmVzdWx0LnN0YXR1cyA9PT0gJ2Z1bGZpbGxlZCcsXG4gICAgICAgIGVycm9yOiByZXN1bHQuc3RhdHVzID09PSAncmVqZWN0ZWQnID8gcmVzdWx0LnJlYXNvbiA6IG51bGxcbiAgICAgIH0pKTtcbiAgICB9O1xuICAgIFxuICAgIC8vIFByb2Nlc3MgYWRkaXRpb25zIGluIGJhdGNoZXNcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHN5bmNBY3Rpb25zLnRvQWRkLmxlbmd0aDsgaSArPSBCQVRDSF9TSVpFKSB7XG4gICAgICBjb25zdCBiYXRjaCA9IHN5bmNBY3Rpb25zLnRvQWRkLnNsaWNlKGksIGkgKyBCQVRDSF9TSVpFKTtcbiAgICAgIGNvbnN0IGJhdGNoUmVzdWx0cyA9IGF3YWl0IHByb2Nlc3NCYXRjaChiYXRjaCwgJ/Cfk6UgRG93bmxvYWRpbmcnKTtcbiAgICAgIFxuICAgICAgZm9yIChjb25zdCByZXN1bHQgb2YgYmF0Y2hSZXN1bHRzKSB7XG4gICAgICAgIGlmIChyZXN1bHQuc3VjY2Vzcykge1xuICAgICAgICAgIHJlc3VsdHMuYWRkZWQrKztcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBsb2dnZXIuZXJyb3IoYEZhaWxlZCB0byBhZGQgJHtyZXN1bHQuYWN0aW9uLnR5cGV9LyR7cmVzdWx0LmFjdGlvbi5uYW1lfWAsIHsgZXJyb3I6IHJlc3VsdC5lcnJvciB9KTtcbiAgICAgICAgICBwcm9ncmVzc01lc3NhZ2VzLnB1c2goYOKdjCBGYWlsZWQgdG8gYWRkOiAke3Jlc3VsdC5hY3Rpb24udHlwZX0vJHtyZXN1bHQuYWN0aW9uLm5hbWV9YCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgLy8gUHJvY2VzcyB1cGRhdGVzIGluIGJhdGNoZXNcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHN5bmNBY3Rpb25zLnRvVXBkYXRlLmxlbmd0aDsgaSArPSBCQVRDSF9TSVpFKSB7XG4gICAgICBjb25zdCBiYXRjaCA9IHN5bmNBY3Rpb25zLnRvVXBkYXRlLnNsaWNlKGksIGkgKyBCQVRDSF9TSVpFKTtcbiAgICAgIGNvbnN0IGJhdGNoUmVzdWx0cyA9IGF3YWl0IHByb2Nlc3NCYXRjaChiYXRjaCwgJ/CflIQgVXBkYXRpbmcnKTtcbiAgICAgIFxuICAgICAgZm9yIChjb25zdCByZXN1bHQgb2YgYmF0Y2hSZXN1bHRzKSB7XG4gICAgICAgIGlmIChyZXN1bHQuc3VjY2Vzcykge1xuICAgICAgICAgIHJlc3VsdHMudXBkYXRlZCsrO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGxvZ2dlci5lcnJvcihgRmFpbGVkIHRvIHVwZGF0ZSAke3Jlc3VsdC5hY3Rpb24udHlwZX0vJHtyZXN1bHQuYWN0aW9uLm5hbWV9YCwgeyBlcnJvcjogcmVzdWx0LmVycm9yIH0pO1xuICAgICAgICAgIHByb2dyZXNzTWVzc2FnZXMucHVzaChg4p2MIEZhaWxlZCB0byB1cGRhdGU6ICR7cmVzdWx0LmFjdGlvbi50eXBlfS8ke3Jlc3VsdC5hY3Rpb24ubmFtZX1gKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgICBcbiAgICAvLyBQcm9jZXNzIGRlbGV0aW9uc1xuICAgIGZvciAoY29uc3QgYWN0aW9uIG9mIHN5bmNBY3Rpb25zLnRvRGVsZXRlKSB7XG4gICAgICB0cnkge1xuICAgICAgICBwcm9ncmVzc01lc3NhZ2VzLnB1c2goYPCfl5HvuI8gRGVsZXRpbmc6ICR7YWN0aW9uLnR5cGV9LyR7YWN0aW9uLm5hbWV9YCk7XG4gICAgICAgIGF3YWl0IHRoaXMuZGVsZXRlTG9jYWxFbGVtZW50KGFjdGlvbik7XG4gICAgICAgIHJlc3VsdHMuZGVsZXRlZCsrO1xuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgbG9nZ2VyLmVycm9yKGBGYWlsZWQgdG8gZGVsZXRlICR7YWN0aW9uLnR5cGV9LyR7YWN0aW9uLm5hbWV9YCwgeyBlcnJvciB9KTtcbiAgICAgICAgcHJvZ3Jlc3NNZXNzYWdlcy5wdXNoKGDinYwgRmFpbGVkIHRvIGRlbGV0ZTogJHthY3Rpb24udHlwZX0vJHthY3Rpb24ubmFtZX1gKTtcbiAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgLy8gUEVSRk9STUFOQ0U6IEJhdGNoIHJlYnVpbGQgaW5kZXggYWZ0ZXIgYWxsIG9wZXJhdGlvbnMgY29tcGxldGVcbiAgICBpZiAocmVzdWx0cy5hZGRlZCA+IDAgfHwgcmVzdWx0cy51cGRhdGVkID4gMCB8fCByZXN1bHRzLmRlbGV0ZWQgPiAwKSB7XG4gICAgICBwcm9ncmVzc01lc3NhZ2VzLnB1c2goJ/CflIQgUmVidWlsZGluZyBpbmRleC4uLicpO1xuICAgICAgYXdhaXQgdGhpcy5pbmRleE1hbmFnZXIucmVidWlsZEluZGV4KCk7XG4gICAgfVxuICAgIFxuICAgIHJldHVybiByZXN1bHRzO1xuICB9XG5cbiAgLyoqXG4gICAqIERvd25sb2FkIGVsZW1lbnQgZnJvbSBHaXRIdWIgYW5kIHNhdmUgbG9jYWxseVxuICAgKiBTRUNVUklUWTogQWRkZWQgYXVkaXQgbG9nZ2luZyBmb3IgR2l0SHViIG9wZXJhdGlvbnNcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgZG93bmxvYWRBbmRTYXZlRWxlbWVudChcbiAgICBhY3Rpb246IFN5bmNBY3Rpb24sXG4gICAgdXNlcm5hbWU6IHN0cmluZyxcbiAgICByZXBvc2l0b3J5OiBzdHJpbmdcbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgLy8gU2V0IHVwIHRoZSByZXBvIG1hbmFnZXIgd2l0aCB0aGUgY29ycmVjdCBjb250ZXh0XG4gICAgdGhpcy5wb3J0Zm9saW9SZXBvTWFuYWdlci5zZXRUb2tlbihhd2FpdCB0aGlzLmdldEdpdEh1YlRva2VuKCkpO1xuICAgIFxuICAgIC8vIFNFQ1VSSVRZOiBMb2cgdGhlIGRvd25sb2FkIG9wZXJhdGlvbiBmb3IgYXVkaXQgdHJhaWxcbiAgICBTZWN1cml0eU1vbml0b3IubG9nU2VjdXJpdHlFdmVudCh7XG4gICAgICB0eXBlOiAnUE9SVEZPTElPX0ZFVENIX1NVQ0NFU1MnLFxuICAgICAgc2V2ZXJpdHk6ICdMT1cnLFxuICAgICAgc291cmNlOiAnUG9ydGZvbGlvUHVsbEhhbmRsZXIuZG93bmxvYWRBbmRTYXZlRWxlbWVudCcsXG4gICAgICBkZXRhaWxzOiBgRG93bmxvYWRpbmcgZWxlbWVudDogJHthY3Rpb24udHlwZX0vJHthY3Rpb24ubmFtZX0gZnJvbSAke3VzZXJuYW1lfS8ke3JlcG9zaXRvcnl9YFxuICAgIH0pO1xuICAgIFxuICAgIC8vIERvd25sb2FkIHRoZSBlbGVtZW50IGNvbnRlbnRcbiAgICBjb25zdCBlbGVtZW50RGF0YSA9IGF3YWl0IHRoaXMuZG93bmxvYWRlci5kb3dubG9hZEZyb21HaXRIdWIoXG4gICAgICB0aGlzLnBvcnRmb2xpb1JlcG9NYW5hZ2VyLFxuICAgICAgYWN0aW9uLnBhdGgsXG4gICAgICB1c2VybmFtZSxcbiAgICAgIHJlcG9zaXRvcnlcbiAgICApO1xuICAgIFxuICAgIC8vIFNhdmUgdG8gbG9jYWwgcG9ydGZvbGlvXG4gICAgY29uc3QgZWxlbWVudERpciA9IHRoaXMucG9ydGZvbGlvTWFuYWdlci5nZXRFbGVtZW50RGlyKGFjdGlvbi50eXBlKTtcbiAgICBjb25zdCBmaWxlTmFtZSA9IHBhdGguYmFzZW5hbWUoYWN0aW9uLnBhdGgpO1xuICAgIGNvbnN0IGZpbGVQYXRoID0gcGF0aC5qb2luKGVsZW1lbnREaXIsIGZpbGVOYW1lKTtcbiAgICBcbiAgICBhd2FpdCBmcy53cml0ZUZpbGUoZmlsZVBhdGgsIGVsZW1lbnREYXRhLmNvbnRlbnQsICd1dGYtOCcpO1xuICAgIFxuICAgIC8vIFNFQ1VSSVRZOiBMb2cgc3VjY2Vzc2Z1bCBzYXZlIGZvciBhdWRpdCB0cmFpbFxuICAgIFNlY3VyaXR5TW9uaXRvci5sb2dTZWN1cml0eUV2ZW50KHtcbiAgICAgIHR5cGU6ICdFTEVNRU5UX0NSRUFURUQnLFxuICAgICAgc2V2ZXJpdHk6ICdMT1cnLFxuICAgICAgc291cmNlOiAnUG9ydGZvbGlvUHVsbEhhbmRsZXIuZG93bmxvYWRBbmRTYXZlRWxlbWVudCcsXG4gICAgICBkZXRhaWxzOiBgU2F2ZWQgZWxlbWVudCB0bzogJHthY3Rpb24udHlwZX0vJHtmaWxlTmFtZX1gXG4gICAgfSk7XG4gICAgXG4gICAgLy8gUEVSRk9STUFOQ0U6IFNraXAgaW5kaXZpZHVhbCBpbmRleCByZWJ1aWxkIC0gd2lsbCBiYXRjaCByZWJ1aWxkIGFmdGVyIGFsbCBvcGVyYXRpb25zXG4gIH1cblxuICAvKipcbiAgICogRGVsZXRlIGxvY2FsIGVsZW1lbnRcbiAgICogU0VDVVJJVFk6IEFkZGVkIGF1ZGl0IGxvZ2dpbmcgZm9yIGRlbGV0aW9uIG9wZXJhdGlvbnNcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgZGVsZXRlTG9jYWxFbGVtZW50KGFjdGlvbjogU3luY0FjdGlvbik6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IGVsZW1lbnREaXIgPSB0aGlzLnBvcnRmb2xpb01hbmFnZXIuZ2V0RWxlbWVudERpcihhY3Rpb24udHlwZSk7XG4gICAgLy8gVXNlIHRoZSBvcmlnaW5hbCBmaWxlbmFtZSBmcm9tIHRoZSBwYXRoIHRvIHByZXNlcnZlIGV4dGVuc2lvblxuICAgIGNvbnN0IGZpbGVOYW1lID0gcGF0aC5iYXNlbmFtZShhY3Rpb24ucGF0aCkgfHwgYCR7YWN0aW9uLm5hbWV9Lm1kYDtcbiAgICBjb25zdCBmaWxlUGF0aCA9IHBhdGguam9pbihlbGVtZW50RGlyLCBmaWxlTmFtZSk7XG4gICAgXG4gICAgLy8gU0VDVVJJVFk6IExvZyBkZWxldGlvbiBhdHRlbXB0IGZvciBhdWRpdCB0cmFpbFxuICAgIFNlY3VyaXR5TW9uaXRvci5sb2dTZWN1cml0eUV2ZW50KHtcbiAgICAgIHR5cGU6ICdFTEVNRU5UX0RFTEVURUQnLFxuICAgICAgc2V2ZXJpdHk6ICdNRURJVU0nLFxuICAgICAgc291cmNlOiAnUG9ydGZvbGlvUHVsbEhhbmRsZXIuZGVsZXRlTG9jYWxFbGVtZW50JyxcbiAgICAgIGRldGFpbHM6IGBBdHRlbXB0aW5nIHRvIGRlbGV0ZTogJHthY3Rpb24udHlwZX0vJHtmaWxlTmFtZX1gXG4gICAgfSk7XG4gICAgXG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IGZzLnVubGluayhmaWxlUGF0aCk7XG4gICAgICAvLyBQRVJGT1JNQU5DRTogU2tpcCBpbmRpdmlkdWFsIGluZGV4IHJlYnVpbGQgLSB3aWxsIGJhdGNoIHJlYnVpbGQgYWZ0ZXIgYWxsIG9wZXJhdGlvbnNcbiAgICAgIFxuICAgICAgLy8gU0VDVVJJVFk6IExvZyBzdWNjZXNzZnVsIGRlbGV0aW9uXG4gICAgICBTZWN1cml0eU1vbml0b3IubG9nU2VjdXJpdHlFdmVudCh7XG4gICAgICAgIHR5cGU6ICdFTEVNRU5UX0RFTEVURUQnLFxuICAgICAgICBzZXZlcml0eTogJ01FRElVTScsXG4gICAgICAgIHNvdXJjZTogJ1BvcnRmb2xpb1B1bGxIYW5kbGVyLmRlbGV0ZUxvY2FsRWxlbWVudCcsXG4gICAgICAgIGRldGFpbHM6IGBTdWNjZXNzZnVsbHkgZGVsZXRlZDogJHthY3Rpb24udHlwZX0vJHtmaWxlTmFtZX1gXG4gICAgICB9KTtcbiAgICB9IGNhdGNoIChlcnJvcjogYW55KSB7XG4gICAgICBpZiAoZXJyb3IuY29kZSAhPT0gJ0VOT0VOVCcpIHtcbiAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICB9XG4gICAgICAvLyBGaWxlIGFscmVhZHkgZG9lc24ndCBleGlzdCwgdGhhdCdzIGZpbmVcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogR2V0IEdpdEh1YiB0b2tlbiBmcm9tIGF1dGggbWFuYWdlclxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBnZXRHaXRIdWJUb2tlbigpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIC8vIFRoaXMgc2hvdWxkIHVzZSB0aGUgc2FtZSB0b2tlbiBtYW5hZ2VtZW50IGFzIHRoZSByZXN0IG9mIHRoZSBzeXN0ZW1cbiAgICBjb25zdCB7IFRva2VuTWFuYWdlciB9ID0gYXdhaXQgaW1wb3J0KCcuLi9zZWN1cml0eS90b2tlbk1hbmFnZXIuanMnKTtcbiAgICBjb25zdCB0b2tlbiA9IGF3YWl0IFRva2VuTWFuYWdlci5nZXRHaXRIdWJUb2tlbkFzeW5jKCk7XG4gICAgaWYgKCF0b2tlbikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdHaXRIdWIgYXV0aGVudGljYXRpb24gcmVxdWlyZWQuIFBsZWFzZSBydW4gc2V0dXBfZ2l0aHViX2F1dGggZmlyc3QuJyk7XG4gICAgfVxuICAgIHJldHVybiB0b2tlbjtcbiAgfVxufSJdfQ==
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
/**
|
|
4
|
+
* Standalone script to run the configuration wizard
|
|
5
|
+
* Can be used for testing or manual configuration
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.runConfigWizard = main;
|
|
9
|
+
const ConfigManager_js_1 = require("../src/config/ConfigManager.js");
|
|
10
|
+
const ConfigWizard_js_1 = require("../src/config/ConfigWizard.js");
|
|
11
|
+
const chalk_1 = require("chalk");
|
|
12
|
+
async function main() {
|
|
13
|
+
try {
|
|
14
|
+
// Initialize config manager
|
|
15
|
+
const configManager = ConfigManager_js_1.ConfigManager.getInstance();
|
|
16
|
+
await configManager.initialize();
|
|
17
|
+
// Create and run wizard
|
|
18
|
+
const wizard = new ConfigWizard_js_1.ConfigWizard(configManager);
|
|
19
|
+
// Check if we should force run (for testing)
|
|
20
|
+
const forceRun = process.argv.includes('--force');
|
|
21
|
+
if (forceRun || await wizard.shouldRunWizard()) {
|
|
22
|
+
const choice = await wizard.promptInitial();
|
|
23
|
+
if (choice === 'yes') {
|
|
24
|
+
await wizard.runWizard();
|
|
25
|
+
}
|
|
26
|
+
else if (choice === 'never') {
|
|
27
|
+
await wizard.markDismissed();
|
|
28
|
+
console.log(chalk_1.default.gray('\nWizard dismissed. You can run it manually anytime.\n'));
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
console.log(chalk_1.default.gray('\nSkipped for now. The wizard will ask again next time.\n'));
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
const config = configManager.getConfig();
|
|
36
|
+
if (config.wizard?.completed) {
|
|
37
|
+
console.log(chalk_1.default.green('\nā
Configuration wizard already completed.'));
|
|
38
|
+
console.log(chalk_1.default.gray('Use --force to run it again.\n'));
|
|
39
|
+
}
|
|
40
|
+
else if (config.wizard?.dismissed) {
|
|
41
|
+
console.log(chalk_1.default.yellow('\nā ļø Configuration wizard was previously dismissed.'));
|
|
42
|
+
console.log(chalk_1.default.gray('Use --force to run it anyway.\n'));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// Clean up
|
|
46
|
+
wizard.close();
|
|
47
|
+
process.exit(0);
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
console.error(chalk_1.default.red('\nā Error running configuration wizard:'), error);
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// Run if called directly
|
|
55
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
56
|
+
main();
|
|
57
|
+
}
|