@hddz/plugin-harness 0.1.19 → 0.2.1

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.

Potentially problematic release.


This version of @hddz/plugin-harness might be problematic. Click here for more details.

Files changed (41) hide show
  1. package/README.md +97 -114
  2. package/dist/core/auditors/index.d.ts +2 -0
  3. package/dist/core/auditors/index.js +7 -0
  4. package/dist/core/auditors/skill-auditor.d.ts +72 -0
  5. package/dist/core/auditors/skill-auditor.js +488 -0
  6. package/dist/core/index.d.ts +22 -0
  7. package/dist/core/index.js +47 -0
  8. package/dist/core/loggers/config-logger.d.ts +25 -0
  9. package/dist/core/loggers/config-logger.js +139 -0
  10. package/dist/core/loggers/index.d.ts +4 -0
  11. package/dist/core/loggers/index.js +9 -0
  12. package/dist/core/loggers/operation-logger.d.ts +23 -0
  13. package/dist/core/loggers/operation-logger.js +125 -0
  14. package/dist/core/middleware/context-injector.d.ts +25 -0
  15. package/dist/core/middleware/context-injector.js +174 -0
  16. package/dist/core/middleware/index.d.ts +5 -0
  17. package/dist/core/middleware/index.js +11 -0
  18. package/dist/core/middleware/loop-detector.d.ts +18 -0
  19. package/dist/core/middleware/loop-detector.js +125 -0
  20. package/dist/core/middleware/trace-logger.d.ts +34 -0
  21. package/dist/core/middleware/trace-logger.js +141 -0
  22. package/dist/core/utils/file.d.ts +28 -0
  23. package/dist/core/utils/file.js +104 -0
  24. package/dist/core/utils/format.d.ts +16 -0
  25. package/dist/core/utils/format.js +60 -0
  26. package/dist/core/utils/index.d.ts +2 -0
  27. package/dist/core/utils/index.js +14 -0
  28. package/dist/core/validators/config-validator.d.ts +25 -0
  29. package/dist/core/validators/config-validator.js +235 -0
  30. package/dist/core/validators/index.d.ts +2 -0
  31. package/dist/core/validators/index.js +7 -0
  32. package/dist/file-watcher.d.ts +37 -0
  33. package/dist/file-watcher.js +151 -0
  34. package/dist/index.d.ts +63 -0
  35. package/dist/index.js +166 -106
  36. package/dist/src/file-watcher.d.ts +37 -0
  37. package/dist/src/file-watcher.js +151 -0
  38. package/dist/src/index.d.ts +70 -0
  39. package/dist/src/index.js +192 -0
  40. package/package.json +4 -12
  41. package/openclaw.plugin.json +0 -39
@@ -0,0 +1,488 @@
1
+ "use strict";
2
+ // src/auditors/skill-auditor.ts
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ Object.defineProperty(exports, "__esModule", { value: true });
37
+ exports.SkillAuditor = void 0;
38
+ const fs = __importStar(require("fs-extra"));
39
+ const path = __importStar(require("path"));
40
+ const child_process_1 = require("child_process");
41
+ class SkillAuditor {
42
+ workspacePath;
43
+ constructor(workspacePath) {
44
+ this.workspacePath = workspacePath;
45
+ }
46
+ /**
47
+ * 审核 Skill
48
+ */
49
+ async audit(skillPath, source = 'unknown') {
50
+ const warnings = [];
51
+ const recommendations = [];
52
+ // 获取元数据
53
+ const metadata = await this.getSkillMetadata(skillPath);
54
+ // 1. 检查来源
55
+ const sourceWarning = this.checkSource(source);
56
+ if (sourceWarning)
57
+ warnings.push(sourceWarning);
58
+ // 2. 检查 SKILL.md
59
+ if (!metadata.hasSkillMd) {
60
+ warnings.push({
61
+ type: 'permission',
62
+ severity: 'high',
63
+ message: '缺少 SKILL.md 文件,无法确认权限声明',
64
+ });
65
+ }
66
+ else {
67
+ // 检查权限声明
68
+ const permissionWarning = this.checkPermissions(metadata.declaredPermissions);
69
+ if (permissionWarning)
70
+ warnings.push(permissionWarning);
71
+ }
72
+ // 3. 扫描危险代码
73
+ const codeWarnings = await this.scanDangerousCode(skillPath);
74
+ warnings.push(...codeWarnings);
75
+ // 4. 检查依赖
76
+ if (metadata.hasPackageJson) {
77
+ const depWarnings = await this.checkDependencies(skillPath, metadata.dependencies);
78
+ warnings.push(...depWarnings);
79
+ }
80
+ // 5. 检查脚本目录
81
+ if (metadata.hasScripts) {
82
+ const scriptWarnings = await this.scanScripts(skillPath);
83
+ warnings.push(...scriptWarnings);
84
+ }
85
+ // 计算风险等级
86
+ const riskLevel = this.calculateRiskLevel(warnings);
87
+ const passed = riskLevel !== 'CRITICAL' && riskLevel !== 'HIGH';
88
+ // 生成建议
89
+ if (!passed) {
90
+ recommendations.push('⚠️ 建议人工审核后再决定是否安装');
91
+ }
92
+ if (metadata.dependencies.length > 10) {
93
+ recommendations.push(`📦 依赖较多(${metadata.dependencies.length} 个),建议检查是否有不必要的依赖`);
94
+ }
95
+ if (!metadata.hasSkillMd) {
96
+ recommendations.push('📝 要求作者添加 SKILL.md 权限声明');
97
+ }
98
+ return {
99
+ skillName: path.basename(skillPath),
100
+ skillPath,
101
+ source,
102
+ riskLevel,
103
+ passed,
104
+ warnings,
105
+ recommendations,
106
+ metadata,
107
+ };
108
+ }
109
+ /**
110
+ * 检查来源
111
+ */
112
+ checkSource(source) {
113
+ const trustedSources = [
114
+ 'clawhub',
115
+ 'official',
116
+ 'github.com/openclaw',
117
+ 'github.com/clawd',
118
+ ];
119
+ const unknownSources = ['unknown', '', undefined];
120
+ if (unknownSources.includes(source)) {
121
+ return {
122
+ type: 'other',
123
+ severity: 'medium',
124
+ message: `来源未知:${source}`,
125
+ };
126
+ }
127
+ if (trustedSources.some(s => source.toLowerCase().includes(s))) {
128
+ return null; // 可信来源,无警告
129
+ }
130
+ return {
131
+ type: 'other',
132
+ severity: 'low',
133
+ message: `来源:${source}(非官方来源)`,
134
+ };
135
+ }
136
+ /**
137
+ * 检查权限声明
138
+ */
139
+ checkPermissions(permissions) {
140
+ const dangerousPermissions = [
141
+ 'exec',
142
+ 'system',
143
+ 'fullFileSystem',
144
+ 'network',
145
+ 'externalApi',
146
+ ];
147
+ const hasDangerous = permissions.some(p => dangerousPermissions.some(dp => p.toLowerCase().includes(dp)));
148
+ if (hasDangerous) {
149
+ return {
150
+ type: 'permission',
151
+ severity: 'medium',
152
+ message: `声明了危险权限:${permissions.filter(p => dangerousPermissions.some(dp => p.toLowerCase().includes(dp))).join(', ')}`,
153
+ };
154
+ }
155
+ if (permissions.length === 0) {
156
+ return {
157
+ type: 'permission',
158
+ severity: 'low',
159
+ message: '未声明任何权限(可能不需要权限,也可能未声明)',
160
+ };
161
+ }
162
+ return null;
163
+ }
164
+ /**
165
+ * 扫描危险代码
166
+ */
167
+ async scanDangerousCode(skillPath) {
168
+ const warnings = [];
169
+ const dangerousPatterns = [
170
+ {
171
+ pattern: /exec\s*\(/g,
172
+ name: 'exec()',
173
+ severity: 'high',
174
+ message: '发现系统命令执行',
175
+ },
176
+ {
177
+ pattern: /eval\s*\(/g,
178
+ name: 'eval()',
179
+ severity: 'critical',
180
+ message: '发现代码执行(eval)',
181
+ },
182
+ {
183
+ pattern: /child_process/g,
184
+ name: 'child_process',
185
+ severity: 'high',
186
+ message: '使用 Node.js 子进程模块',
187
+ },
188
+ {
189
+ pattern: /spawn\s*\(/g,
190
+ name: 'spawn()',
191
+ severity: 'high',
192
+ message: '发现进程生成',
193
+ },
194
+ {
195
+ pattern: /fs\.writeFile/g,
196
+ name: 'fs.writeFile',
197
+ severity: 'medium',
198
+ message: '发现文件写入操作',
199
+ },
200
+ {
201
+ pattern: /fs\.unlink/g,
202
+ name: 'fs.unlink',
203
+ severity: 'medium',
204
+ message: '发现文件删除操作',
205
+ },
206
+ {
207
+ pattern: /fetch\s*\(/g,
208
+ name: 'fetch()',
209
+ severity: 'medium',
210
+ message: '发现网络请求',
211
+ },
212
+ {
213
+ pattern: /axios\./g,
214
+ name: 'axios',
215
+ severity: 'medium',
216
+ message: '使用 axios 进行网络请求',
217
+ },
218
+ {
219
+ pattern: /https?:\/\/[^\s'"]+/g,
220
+ name: 'hardcoded_url',
221
+ severity: 'low',
222
+ message: '发现硬编码 URL',
223
+ },
224
+ {
225
+ pattern: /process\.env/g,
226
+ name: 'process.env',
227
+ severity: 'low',
228
+ message: '访问环境变量',
229
+ },
230
+ ];
231
+ const filesToScan = await this.getJsFiles(skillPath);
232
+ for (const file of filesToScan) {
233
+ try {
234
+ const content = await fs.readFile(file, 'utf8');
235
+ const lines = content.split('\n');
236
+ for (const { pattern, name, severity, message } of dangerousPatterns) {
237
+ pattern.lastIndex = 0; // 重置正则状态
238
+ let match;
239
+ while ((match = pattern.exec(content)) !== null) {
240
+ // 计算行号
241
+ const beforeMatch = content.substring(0, match.index);
242
+ const lineNumber = beforeMatch.split('\n').length;
243
+ // 跳过注释中的匹配
244
+ const line = lines[lineNumber - 1];
245
+ if (line.trim().startsWith('//') || line.trim().startsWith('*')) {
246
+ continue;
247
+ }
248
+ warnings.push({
249
+ type: 'dangerous_code',
250
+ severity,
251
+ message: `${message}: ${name}`,
252
+ file: path.relative(skillPath, file),
253
+ line: lineNumber,
254
+ });
255
+ }
256
+ }
257
+ }
258
+ catch (error) {
259
+ // 忽略读取错误
260
+ }
261
+ }
262
+ return warnings;
263
+ }
264
+ /**
265
+ * 扫描脚本文件
266
+ */
267
+ async scanScripts(skillPath) {
268
+ const warnings = [];
269
+ const scriptsDir = path.join(skillPath, 'scripts');
270
+ if (!await fs.pathExists(scriptsDir)) {
271
+ return warnings;
272
+ }
273
+ const scriptFiles = await fs.readdir(scriptsDir);
274
+ for (const script of scriptFiles) {
275
+ const scriptPath = path.join(scriptsDir, script);
276
+ // 检查 shell 脚本
277
+ if (script.endsWith('.sh')) {
278
+ const content = await fs.readFile(scriptPath, 'utf8');
279
+ const dangerousCommands = [
280
+ { pattern: /rm\s+-rf/g, message: '发现危险命令:rm -rf' },
281
+ { pattern: /curl.*\|\s*bash/g, message: '发现管道执行:curl | bash' },
282
+ { pattern: /wget.*\|\s*bash/g, message: '发现管道执行:wget | bash' },
283
+ { pattern: /sudo/g, message: '使用 sudo 提权' },
284
+ { pattern: /chmod\s+777/g, message: '设置文件权限为 777' },
285
+ ];
286
+ for (const { pattern, message } of dangerousCommands) {
287
+ if (pattern.test(content)) {
288
+ warnings.push({
289
+ type: 'dangerous_code',
290
+ severity: 'high',
291
+ message,
292
+ file: `scripts/${script}`,
293
+ });
294
+ }
295
+ }
296
+ }
297
+ }
298
+ return warnings;
299
+ }
300
+ /**
301
+ * 检查依赖
302
+ */
303
+ async checkDependencies(skillPath, dependencies) {
304
+ const warnings = [];
305
+ // 检查依赖数量
306
+ if (dependencies.length > 20) {
307
+ warnings.push({
308
+ type: 'dependency',
309
+ severity: 'low',
310
+ message: `依赖过多(${dependencies.length} 个),可能增加攻击面`,
311
+ });
312
+ }
313
+ // 尝试运行 npm audit
314
+ try {
315
+ const auditOutput = (0, child_process_1.execSync)('npm audit --json', {
316
+ cwd: skillPath,
317
+ stdio: ['pipe', 'pipe', 'pipe'],
318
+ encoding: 'utf8',
319
+ });
320
+ const audit = JSON.parse(auditOutput);
321
+ const vulnerabilities = audit.metadata?.vulnerabilities;
322
+ if (vulnerabilities && vulnerabilities.total > 0) {
323
+ warnings.push({
324
+ type: 'dependency',
325
+ severity: vulnerabilities.critical > 0 || vulnerabilities.high > 0 ? 'high' : 'medium',
326
+ message: `发现 ${vulnerabilities.total} 个依赖漏洞(${vulnerabilities.critical} 严重,${vulnerabilities.high} 高)`,
327
+ });
328
+ }
329
+ }
330
+ catch (error) {
331
+ // npm audit 可能失败,忽略
332
+ }
333
+ return warnings;
334
+ }
335
+ /**
336
+ * 获取 Skill 元数据
337
+ */
338
+ async getSkillMetadata(skillPath) {
339
+ const metadata = {
340
+ hasSkillMd: false,
341
+ hasScripts: false,
342
+ hasPackageJson: false,
343
+ declaredPermissions: [],
344
+ dependencies: [],
345
+ devDependencies: [],
346
+ };
347
+ // 检查 SKILL.md
348
+ const skillMdPath = path.join(skillPath, 'SKILL.md');
349
+ if (await fs.pathExists(skillMdPath)) {
350
+ metadata.hasSkillMd = true;
351
+ const content = await fs.readFile(skillMdPath, 'utf8');
352
+ // 提取权限声明(假设格式为 "Permissions: exec, network")
353
+ const permissionMatch = content.match(/Permissions?:\s*([^\n]+)/i);
354
+ if (permissionMatch) {
355
+ metadata.declaredPermissions = permissionMatch[1]
356
+ .split(',')
357
+ .map(p => p.trim())
358
+ .filter(p => p);
359
+ }
360
+ }
361
+ // 检查 scripts 目录
362
+ const scriptsDir = path.join(skillPath, 'scripts');
363
+ metadata.hasScripts = await fs.pathExists(scriptsDir);
364
+ // 检查 package.json
365
+ const packageJsonPath = path.join(skillPath, 'package.json');
366
+ if (await fs.pathExists(packageJsonPath)) {
367
+ metadata.hasPackageJson = true;
368
+ try {
369
+ const pkg = JSON.parse(await fs.readFile(packageJsonPath, 'utf8'));
370
+ metadata.dependencies = Object.keys(pkg.dependencies || {});
371
+ metadata.devDependencies = Object.keys(pkg.devDependencies || {});
372
+ }
373
+ catch (error) {
374
+ // 忽略解析错误
375
+ }
376
+ }
377
+ // 获取最后修改时间
378
+ try {
379
+ const stats = await fs.stat(skillPath);
380
+ metadata.lastModified = stats.mtime;
381
+ }
382
+ catch (error) {
383
+ // 忽略
384
+ }
385
+ return metadata;
386
+ }
387
+ /**
388
+ * 获取所有 JS 文件
389
+ */
390
+ async getJsFiles(dir) {
391
+ const files = [];
392
+ async function scan(currentDir) {
393
+ const entries = await fs.readdir(currentDir, { withFileTypes: true });
394
+ for (const entry of entries) {
395
+ const fullPath = path.join(currentDir, entry.name);
396
+ if (entry.isDirectory()) {
397
+ // 跳过 node_modules
398
+ if (entry.name === 'node_modules' || entry.name === 'dist') {
399
+ continue;
400
+ }
401
+ await scan(fullPath);
402
+ }
403
+ else if (entry.isFile() && (entry.name.endsWith('.js') || entry.name.endsWith('.ts'))) {
404
+ files.push(fullPath);
405
+ }
406
+ }
407
+ }
408
+ await scan(dir);
409
+ return files;
410
+ }
411
+ /**
412
+ * 计算风险等级
413
+ */
414
+ calculateRiskLevel(warnings) {
415
+ const criticalCount = warnings.filter(w => w.severity === 'critical').length;
416
+ const highCount = warnings.filter(w => w.severity === 'high').length;
417
+ const mediumCount = warnings.filter(w => w.severity === 'medium').length;
418
+ if (criticalCount > 0)
419
+ return 'CRITICAL';
420
+ if (highCount > 2)
421
+ return 'HIGH';
422
+ if (highCount > 0 || mediumCount > 3)
423
+ return 'MEDIUM';
424
+ return 'LOW';
425
+ }
426
+ /**
427
+ * 生成审计报告
428
+ */
429
+ generateReport(result) {
430
+ const lines = [];
431
+ lines.push(`# Skill 安全审计报告`);
432
+ lines.push('');
433
+ lines.push(`## 基本信息`);
434
+ lines.push(`- **Skill 名称**: ${result.skillName}`);
435
+ lines.push(`- **路径**: ${result.skillPath}`);
436
+ lines.push(`- **来源**: ${result.source}`);
437
+ lines.push(`- **风险等级**: ${this.getRiskEmoji(result.riskLevel)} ${result.riskLevel}`);
438
+ lines.push(`- **审核结果**: ${result.passed ? '✅ 通过' : '❌ 未通过'}`);
439
+ lines.push('');
440
+ if (result.warnings.length > 0) {
441
+ lines.push(`## 警告(${result.warnings.length} 个)`);
442
+ lines.push('');
443
+ for (const warning of result.warnings) {
444
+ lines.push(`- ${this.getSeverityEmoji(warning.severity)} **[${warning.type}]** ${warning.message}`);
445
+ if (warning.file) {
446
+ lines.push(` - 文件:\`${warning.file}\`${warning.line ? ` 第 ${warning.line} 行` : ''}`);
447
+ }
448
+ }
449
+ lines.push('');
450
+ }
451
+ if (result.recommendations.length > 0) {
452
+ lines.push(`## 建议`);
453
+ lines.push('');
454
+ for (const rec of result.recommendations) {
455
+ lines.push(`- ${rec}`);
456
+ }
457
+ lines.push('');
458
+ }
459
+ lines.push(`## 元数据`);
460
+ lines.push(`- 有 SKILL.md: ${result.metadata.hasSkillMd ? '✅' : '❌'}`);
461
+ lines.push(`- 有 scripts 目录:${result.metadata.hasScripts ? '✅' : '❌'}`);
462
+ lines.push(`- 有 package.json: ${result.metadata.hasPackageJson ? '✅' : '❌'}`);
463
+ lines.push(`- 声明权限:${result.metadata.declaredPermissions.join(', ') || '无'}`);
464
+ lines.push(`- 依赖数量:${result.metadata.dependencies.length}`);
465
+ lines.push('');
466
+ return lines.join('\n');
467
+ }
468
+ getRiskEmoji(level) {
469
+ const emojis = {
470
+ LOW: '🟢',
471
+ MEDIUM: '🟡',
472
+ HIGH: '🟠',
473
+ CRITICAL: '🔴',
474
+ };
475
+ return emojis[level] || '⚪';
476
+ }
477
+ getSeverityEmoji(severity) {
478
+ const emojis = {
479
+ low: 'ℹ️',
480
+ medium: '⚠️',
481
+ high: '🚨',
482
+ critical: '💀',
483
+ };
484
+ return emojis[severity] || '⚪';
485
+ }
486
+ }
487
+ exports.SkillAuditor = SkillAuditor;
488
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2tpbGwtYXVkaXRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9jb3JlL2F1ZGl0b3JzL3NraWxsLWF1ZGl0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLGdDQUFnQzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBRWhDLDZDQUErQjtBQUMvQiwyQ0FBNkI7QUFDN0IsaURBQXlDO0FBK0J6QyxNQUFhLFlBQVk7SUFDZixhQUFhLENBQVM7SUFFOUIsWUFBWSxhQUFxQjtRQUMvQixJQUFJLENBQUMsYUFBYSxHQUFHLGFBQWEsQ0FBQztJQUNyQyxDQUFDO0lBRUQ7O09BRUc7SUFDSCxLQUFLLENBQUMsS0FBSyxDQUFDLFNBQWlCLEVBQUUsU0FBaUIsU0FBUztRQUN2RCxNQUFNLFFBQVEsR0FBYyxFQUFFLENBQUM7UUFDL0IsTUFBTSxlQUFlLEdBQWEsRUFBRSxDQUFDO1FBRXJDLFFBQVE7UUFDUixNQUFNLFFBQVEsR0FBRyxNQUFNLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUV4RCxVQUFVO1FBQ1YsTUFBTSxhQUFhLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUMvQyxJQUFJLGFBQWE7WUFBRSxRQUFRLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDO1FBRWhELGlCQUFpQjtRQUNqQixJQUFJLENBQUMsUUFBUSxDQUFDLFVBQVUsRUFBRSxDQUFDO1lBQ3pCLFFBQVEsQ0FBQyxJQUFJLENBQUM7Z0JBQ1osSUFBSSxFQUFFLFlBQVk7Z0JBQ2xCLFFBQVEsRUFBRSxNQUFNO2dCQUNoQixPQUFPLEVBQUUseUJBQXlCO2FBQ25DLENBQUMsQ0FBQztRQUNMLENBQUM7YUFBTSxDQUFDO1lBQ04sU0FBUztZQUNULE1BQU0saUJBQWlCLEdBQUcsSUFBSSxDQUFDLGdCQUFnQixDQUFDLFFBQVEsQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO1lB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LENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQztRQUM5RSxLQUFLLENBQUMsSUFBSSxDQUFDLFVBQVUsTUFBTSxDQUFDLFFBQVEsQ0FBQyxtQkFBbUIsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksR0FBRyxFQUFFLENBQUMsQ0FBQztRQUM5RSxLQUFLLENBQUMsSUFBSSxDQUFDLFVBQVUsTUFBTSxDQUFDLFFBQVEsQ0FBQyxZQUFZLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQztRQUM1RCxLQUFLLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBRWYsT0FBTyxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQzFCLENBQUM7SUFFTyxZQUFZLENBQUMsS0FBYTtRQUNoQyxNQUFNLE1BQU0sR0FBMkI7WUFDckMsR0FBRyxFQUFFLElBQUk7WUFDVCxNQUFNLEVBQUUsSUFBSTtZQUNaLElBQUksRUFBRSxJQUFJO1lBQ1YsUUFBUSxFQUFFLElBQUk7U0FDZixDQUFDO1FBQ0YsT0FBTyxNQUFNLENBQUMsS0FBSyxDQUFDLElBQUksR0FBRyxDQUFDO0lBQzlCLENBQUM7SUFFTyxnQkFBZ0IsQ0FBQyxRQUFnQjtRQUN2QyxNQUFNLE1BQU0sR0FBMkI7WUFDckMsR0FBRyxFQUFFLElBQUk7WUFDVCxNQUFNLEVBQUUsSUFBSTtZQUNaLElBQUksRUFBRSxJQUFJO1lBQ1YsUUFBUSxFQUFFLElBQUk7U0FDZixDQUFDO1FBQ0YsT0FBTyxNQUFNLENBQUMsUUFBUSxDQUFDLElBQUksR0FBRyxDQUFDO0lBQ2pDLENBQUM7Q0FDRjtBQXJmRCxvQ0FxZkMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBzcmMvYXVkaXRvcnMvc2tpbGwtYXVkaXRvci50c1xuXG5pbXBvcnQgKiBhcyBmcyBmcm9tICdmcy1leHRyYSc7XG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0IHsgZXhlY1N5bmMgfSBmcm9tICdjaGlsZF9wcm9jZXNzJztcblxuZXhwb3J0IGludGVyZmFjZSBTa2lsbEF1ZGl0UmVzdWx0IHtcbiAgc2tpbGxOYW1lOiBzdHJpbmc7XG4gIHNraWxsUGF0aDogc3RyaW5nO1xuICBzb3VyY2U6IHN0cmluZztcbiAgcmlza0xldmVsOiAnTE9XJyB8ICdNRURJVU0nIHwgJ0hJR0gnIHwgJ0NSSVRJQ0FMJztcbiAgcGFzc2VkOiBib29sZWFuO1xuICB3YXJuaW5nczogV2FybmluZ1tdO1xuICByZWNvbW1lbmRhdGlvbnM6IHN0cmluZ1tdO1xuICBtZXRhZGF0YTogU2tpbGxNZXRhZGF0YTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBXYXJuaW5nIHtcbiAgdHlwZTogJ2Rhbmdlcm91c19jb2RlJyB8ICdwZXJtaXNzaW9uJyB8ICdkZXBlbmRlbmN5JyB8ICduZXR3b3JrJyB8ICdvdGhlcic7XG4gIHNldmVyaXR5OiAnbG93JyB8ICdtZWRpdW0nIHwgJ2hpZ2gnIHwgJ2NyaXRpY2FsJztcbiAgbWVzc2FnZTogc3RyaW5nO1xuICBmaWxlPzogc3RyaW5nO1xuICBsaW5lPzogbnVtYmVyO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFNraWxsTWV0YWRhdGEge1xuICBoYXNTa2lsbE1kOiBib29sZWFuO1xuICBoYXNTY3JpcHRzOiBib29sZWFuO1xuICBoYXNQYWNrYWdlSnNvbjogYm9vbGVhbjtcbiAgZGVjbGFyZWRQZXJtaXNzaW9uczogc3RyaW5nW107XG4gIGRlcGVuZGVuY2llczogc3RyaW5nW107XG4gIGRldkRlcGVuZGVuY2llczogc3RyaW5nW107XG4gIGxhc3RNb2RpZmllZD86IERhdGU7XG59XG5cbmV4cG9ydCBjbGFzcyBTa2lsbEF1ZGl0b3Ige1xuICBwcml2YXRlIHdvcmtzcGFjZVBhdGg6IHN0cmluZztcblxuICBjb25zdHJ1Y3Rvcih3b3Jrc3BhY2VQYXRoOiBzdHJpbmcpIHtcbiAgICB0aGlzLndvcmtzcGFjZVBhdGggPSB3b3Jrc3BhY2VQYXRoO1xuICB9XG5cbiAgLyoqXG4gICAqIOWuoeaguCBTa2lsbFxuICAgKi9cbiAgYXN5bmMgYXVkaXQoc2tpbGxQYXRoOiBzdHJpbmcsIHNvdXJjZTogc3RyaW5nID0gJ3Vua25vd24nKTogUHJvbWlzZTxTa2lsbEF1ZGl0UmVzdWx0PiB7XG4gICAgY29uc3Qgd2FybmluZ3M6IFdhcm5pbmdbXSA9IFtdO1xuICAgIGNvbnN0IHJlY29tbWVuZGF0aW9uczogc3RyaW5nW10gPSBbXTtcblxuICAgIC8vIOiOt+WPluWFg+aVsOaNrlxuICAgIGNvbnN0IG1ldGFkYXRhID0gYXdhaXQgdGhpcy5nZXRTa2lsbE1ldGFkYXRhKHNraWxsUGF0aCk7XG5cbiAgICAvLyAxLiDmo4Dmn6XmnaXmupBcbiAgICBjb25zdCBzb3VyY2VXYXJuaW5nID0gdGhpcy5jaGVja1NvdXJjZShzb3VyY2UpO1xuICAgIGlmIChzb3VyY2VXYXJuaW5nKSB3YXJuaW5ncy5wdXNoKHNvdXJjZVdhcm5pbmcpO1xuXG4gICAgLy8gMi4g5qOA5p+lIFNLSUxMLm1kXG4gICAgaWYgKCFtZXRhZGF0YS5oYXNTa2lsbE1kKSB7XG4gICAgICB3YXJuaW5ncy5wdXNoKHtcbiAgICAgICAgdHlwZTogJ3Blcm1pc3Npb24nLFxuICAgICAgICBzZXZlcml0eTogJ2hpZ2gnLFxuICAgICAgICBtZXNzYWdlOiAn57y65bCRIFNLSUxMLm1kIOaWh+S7tu+8jOaXoOazleehruiupOadg+mZkOWjsOaYjicsXG4gICAgICB9KTtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8g5qOA5p+l5p2D6ZmQ5aOw5piOXG4gICAgICBjb25zdCBwZXJtaXNzaW9uV2FybmluZyA9IHRoaXMuY2hlY2tQZXJtaXNzaW9ucyhtZXRhZGF0YS5kZWNsYXJlZFBlcm1pc3Npb25zKTtcbiAgICAgIGlmIChwZXJtaXNzaW9uV2FybmluZykgd2FybmluZ3MucHVzaChwZXJtaXNzaW9uV2FybmluZyk7XG4gICAgfVxuXG4gICAgLy8gMy4g5omr5o+P5Y2x6Zmp5Luj56CBXG4gICAgY29uc3QgY29kZVdhcm5pbmdzID0gYXdhaXQgdGhpcy5zY2FuRGFuZ2Vyb3VzQ29kZShza2lsbFBhdGgpO1xuICAgIHdhcm5pbmdzLnB1c2goLi4uY29kZVdhcm5pbmdzKTtcblxuICAgIC8vIDQuIOajgOafpeS+nei1llxuICAgIGlmIChtZXRhZGF0YS5oYXNQYWNrYWdlSnNvbikge1xuICAgICAgY29uc3QgZGVwV2FybmluZ3MgPSBhd2FpdCB0aGlzLmNoZWNrRGVwZW5kZW5jaWVzKHNraWxsUGF0aCwgbWV0YWRhdGEuZGVwZW5kZW5jaWVzKTtcbiAgICAgIHdhcm5pbmdzLnB1c2goLi4uZGVwV2FybmluZ3MpO1xuICAgIH1cblxuICAgIC8vIDUuIOajgOafpeiEmuacrOebruW9lVxuICAgIGlmIChtZXRhZGF0YS5oYXNTY3JpcHRzKSB7XG4gICAgICBjb25zdCBzY3JpcHRXYXJuaW5ncyA9IGF3YWl0IHRoaXMuc2NhblNjcmlwdHMoc2tpbGxQYXRoKTtcbiAgICAgIHdhcm5pbmdzLnB1c2goLi4uc2NyaXB0V2FybmluZ3MpO1xuICAgIH1cblxuICAgIC8vIOiuoeeul+mjjumZqeetiee6p1xuICAgIGNvbnN0IHJpc2tMZXZlbCA9IHRoaXMuY2FsY3VsYXRlUmlza0xldmVsKHdhcm5pbmdzKTtcbiAgICBjb25zdCBwYXNzZWQgPSByaXNrTGV2ZWwgIT09ICdDUklUSUNBTCcgJiYgcmlza0xldmVsICE9PSAnSElHSCc7XG5cbiAgICAvLyDnlJ/miJDlu7rorq5cbiAgICBpZiAoIXBhc3NlZCkge1xuICAgICAgcmVjb21tZW5kYXRpb25zLnB1c2goJ+KaoO+4jyDlu7rorq7kurrlt6XlrqHmoLjlkI7lho3lhrPlrprmmK/lkKblronoo4UnKTtcbiAgICB9XG4gICAgaWYgKG1ldGFkYXRhLmRlcGVuZGVuY2llcy5sZW5ndGggPiAxMCkge1xuICAgICAgcmVjb21tZW5kYXRpb25zLnB1c2goYPCfk6Yg5L6d6LWW6L6D5aSa77yIJHttZXRhZGF0YS5kZXBlbmRlbmNpZXMubGVuZ3RofSDkuKrvvInvvIzlu7rorq7mo4Dmn6XmmK/lkKbmnInkuI3lv4XopoHnmoTkvp3otZZgKTtcbiAgICB9XG4gICAgaWYgKCFtZXRhZGF0YS5oYXNTa2lsbE1kKSB7XG4gICAgICByZWNvbW1lbmRhdGlvbnMucHVzaCgn8J+TnSDopoHmsYLkvZzogIXmt7vliqAgU0tJTEwubWQg5p2D6ZmQ5aOw5piOJyk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIHNraWxsTmFtZTogcGF0aC5iYXNlbmFtZShza2lsbFBhdGgpLFxuICAgICAgc2tpbGxQYXRoLFxuICAgICAgc291cmNlLFxuICAgICAgcmlza0xldmVsLFxuICAgICAgcGFzc2VkLFxuICAgICAgd2FybmluZ3MsXG4gICAgICByZWNvbW1lbmRhdGlvbnMsXG4gICAgICBtZXRhZGF0YSxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIOajgOafpeadpea6kFxuICAgKi9cbiAgcHJpdmF0ZSBjaGVja1NvdXJjZShzb3VyY2U6IHN0cmluZyk6IFdhcm5pbmcgfCBudWxsIHtcbiAgICBjb25zdCB0cnVzdGVkU291cmNlcyA9IFtcbiAgICAgICdjbGF3aHViJyxcbiAgICAgICdvZmZpY2lhbCcsXG4gICAgICAnZ2l0aHViLmNvbS9vcGVuY2xhdycsXG4gICAgICAnZ2l0aHViLmNvbS9jbGF3ZCcsXG4gICAgXTtcblxuICAgIGNvbnN0IHVua25vd25Tb3VyY2VzID0gWyd1bmtub3duJywgJycsIHVuZGVmaW5lZF07XG5cbiAgICBpZiAodW5rbm93blNvdXJjZXMuaW5jbHVkZXMoc291cmNlKSkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgdHlwZTogJ290aGVyJyxcbiAgICAgICAgc2V2ZXJpdHk6ICdtZWRpdW0nLFxuICAgICAgICBtZXNzYWdlOiBg5p2l5rqQ5pyq55+l77yaJHtzb3VyY2V9YCxcbiAgICAgIH07XG4gICAgfVxuXG4gICAgaWYgKHRydXN0ZWRTb3VyY2VzLnNvbWUocyA9PiBzb3VyY2UudG9Mb3dlckNhc2UoKS5pbmNsdWRlcyhzKSkpIHtcbiAgICAgIHJldHVybiBudWxsOyAvLyDlj6/kv6HmnaXmupDvvIzml6DorablkYpcbiAgICB9XG5cbiAgICByZXR1cm4ge1xuICAgICAgdHlwZTogJ290aGVyJyxcbiAgICAgIHNldmVyaXR5OiAnbG93JyxcbiAgICAgIG1lc3NhZ2U6IGDmnaXmupDvvJoke3NvdXJjZX3vvIjpnZ7lrpjmlrnmnaXmupDvvIlgLFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICog5qOA5p+l5p2D6ZmQ5aOw5piOXG4gICAqL1xuICBwcml2YXRlIGNoZWNrUGVybWlzc2lvbnMocGVybWlzc2lvbnM6IHN0cmluZ1tdKTogV2FybmluZyB8IG51bGwge1xuICAgIGNvbnN0IGRhbmdlcm91c1Blcm1pc3Npb25zID0gW1xuICAgICAgJ2V4ZWMnLFxuICAgICAgJ3N5c3RlbScsXG4gICAgICAnZnVsbEZpbGVTeXN0ZW0nLFxuICAgICAgJ25ldHdvcmsnLFxuICAgICAgJ2V4dGVybmFsQXBpJyxcbiAgICBdO1xuXG4gICAgY29uc3QgaGFzRGFuZ2Vyb3VzID0gcGVybWlzc2lvbnMuc29tZShwID0+XG4gICAgICBkYW5nZXJvdXNQZXJtaXNzaW9ucy5zb21lKGRwID0+IHAudG9Mb3dlckNhc2UoKS5pbmNsdWRlcyhkcCkpXG4gICAgKTtcblxuICAgIGlmIChoYXNEYW5nZXJvdXMpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHR5cGU6ICdwZXJtaXNzaW9uJyxcbiAgICAgICAgc2V2ZXJpdHk6ICdtZWRpdW0nLFxuICAgICAgICBtZXNzYWdlOiBg5aOw5piO5LqG5Y2x6Zmp5p2D6ZmQ77yaJHtwZXJtaXNzaW9ucy5maWx0ZXIocCA9PiBkYW5nZXJvdXNQZXJtaXNzaW9ucy5zb21lKGRwID0+IHAudG9Mb3dlckNhc2UoKS5pbmNsdWRlcyhkcCkpKS5qb2luKCcsICcpfWAsXG4gICAgICB9O1xuICAgIH1cblxuICAgIGlmIChwZXJtaXNzaW9ucy5sZW5ndGggPT09IDApIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHR5cGU6ICdwZXJtaXNzaW9uJyxcbiAgICAgICAgc2V2ZXJpdHk6ICdsb3cnLFxuICAgICAgICBtZXNzYWdlOiAn5pyq5aOw5piO5Lu75L2V5p2D6ZmQ77yI5Y+v6IO95LiN6ZyA6KaB5p2D6ZmQ77yM5Lmf5Y+v6IO95pyq5aOw5piO77yJJyxcbiAgICAgIH07XG4gICAgfVxuXG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICAvKipcbiAgICog5omr5o+P5Y2x6Zmp5Luj56CBXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHNjYW5EYW5nZXJvdXNDb2RlKHNraWxsUGF0aDogc3RyaW5nKTogUHJvbWlzZTxXYXJuaW5nW10+IHtcbiAgICBjb25zdCB3YXJuaW5nczogV2FybmluZ1tdID0gW107XG5cbiAgICBjb25zdCBkYW5nZXJvdXNQYXR0ZXJucyA9IFtcbiAgICAgIHtcbiAgICAgICAgcGF0dGVybjogL2V4ZWNcXHMqXFwoL2csXG4gICAgICAgIG5hbWU6ICdleGVjKCknLFxuICAgICAgICBzZXZlcml0eTogJ2hpZ2gnIGFzIGNvbnN0LFxuICAgICAgICBtZXNzYWdlOiAn5Y+R546w57O757uf5ZG95Luk5omn6KGMJyxcbiAgICAgIH0sXG4gICAgICB7XG4gICAgICAgIHBhdHRlcm46IC9ldmFsXFxzKlxcKC9nLFxuICAgICAgICBuYW1lOiAnZXZhbCgpJyxcbiAgICAgICAgc2V2ZXJpdHk6ICdjcml0aWNhbCcgYXMgY29uc3QsXG4gICAgICAgIG1lc3NhZ2U6ICflj5HnjrDku6PnoIHmiafooYzvvIhldmFs77yJJyxcbiAgICAgIH0sXG4gICAgICB7XG4gICAgICAgIHBhdHRlcm46IC9jaGlsZF9wcm9jZXNzL2csXG4gICAgICAgIG5hbWU6ICdjaGlsZF9wcm9jZXNzJyxcbiAgICAgICAgc2V2ZXJpdHk6ICdoaWdoJyBhcyBjb25zdCxcbiAgICAgICAgbWVzc2FnZTogJ+S9v+eUqCBOb2RlLmpzIOWtkOi/m+eoi+aooeWdlycsXG4gICAgICB9LFxuICAgICAge1xuICAgICAgICBwYXR0ZXJuOiAvc3Bhd25cXHMqXFwoL2csXG4gICAgICAgIG5hbWU6ICdzcGF3bigpJyxcbiAgICAgICAgc2V2ZXJpdHk6ICdoaWdoJyBhcyBjb25zdCxcbiAgICAgICAgbWVzc2FnZTogJ+WPkeeOsOi/m+eoi+eUn+aIkCcsXG4gICAgICB9LFxuICAgICAge1xuICAgICAgICBwYXR0ZXJuOiAvZnNcXC53cml0ZUZpbGUvZyxcbiAgICAgICAgbmFtZTogJ2ZzLndyaXRlRmlsZScsXG4gICAgICAgIHNldmVyaXR5OiAnbWVkaXVtJyBhcyBjb25zdCxcbiAgICAgICAgbWVzc2FnZTogJ+WPkeeOsOaWh+S7tuWGmeWFpeaTjeS9nCcsXG4gICAgICB9LFxuICAgICAge1xuICAgICAgICBwYXR0ZXJuOiAvZnNcXC51bmxpbmsvZyxcbiAgICAgICAgbmFtZTogJ2ZzLnVubGluaycsXG4gICAgICAgIHNldmVyaXR5OiAnbWVkaXVtJyBhcyBjb25zdCxcbiAgICAgICAgbWVzc2FnZTogJ+WPkeeOsOaWh+S7tuWIoOmZpOaTjeS9nCcsXG4gICAgICB9LFxuICAgICAge1xuICAgICAgICBwYXR0ZXJuOiAvZmV0Y2hcXHMqXFwoL2csXG4gICAgICAgIG5hbWU6ICdmZXRjaCgpJyxcbiAgICAgICAgc2V2ZXJpdHk6ICdtZWRpdW0nIGFzIGNvbnN0LFxuICAgICAgICBtZXNzYWdlOiAn5Y+R546w572R57uc6K+35rGCJyxcbiAgICAgIH0sXG4gICAgICB7XG4gICAgICAgIHBhdHRlcm46IC9heGlvc1xcLi9nLFxuICAgICAgICBuYW1lOiAnYXhpb3MnLFxuICAgICAgICBzZXZlcml0eTogJ21lZGl1bScgYXMgY29uc3QsXG4gICAgICAgIG1lc3NhZ2U6ICfkvb/nlKggYXhpb3Mg6L+b6KGM572R57uc6K+35rGCJyxcbiAgICAgIH0sXG4gICAgICB7XG4gICAgICAgIHBhdHRlcm46IC9odHRwcz86XFwvXFwvW15cXHMnXCJdKy9nLFxuICAgICAgICBuYW1lOiAnaGFyZGNvZGVkX3VybCcsXG4gICAgICAgIHNldmVyaXR5OiAnbG93JyBhcyBjb25zdCxcbiAgICAgICAgbWVzc2FnZTogJ+WPkeeOsOehrOe8lueggSBVUkwnLFxuICAgICAgfSxcbiAgICAgIHtcbiAgICAgICAgcGF0dGVybjogL3Byb2Nlc3NcXC5lbnYvZyxcbiAgICAgICAgbmFtZTogJ3Byb2Nlc3MuZW52JyxcbiAgICAgICAgc2V2ZXJpdHk6ICdsb3cnIGFzIGNvbnN0LFxuICAgICAgICBtZXNzYWdlOiAn6K6/6Zeu546v5aKD5Y+Y6YePJyxcbiAgICAgIH0sXG4gICAgXTtcblxuICAgIGNvbnN0IGZpbGVzVG9TY2FuID0gYXdhaXQgdGhpcy5nZXRKc0ZpbGVzKHNraWxsUGF0aCk7XG5cbiAgICBmb3IgKGNvbnN0IGZpbGUgb2YgZmlsZXNUb1NjYW4pIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IGNvbnRlbnQgPSBhd2FpdCBmcy5yZWFkRmlsZShmaWxlLCAndXRmOCcpO1xuICAgICAgICBjb25zdCBsaW5lcyA9IGNvbnRlbnQuc3BsaXQoJ1xcbicpO1xuXG4gICAgICAgIGZvciAoY29uc3QgeyBwYXR0ZXJuLCBuYW1lLCBzZXZlcml0eSwgbWVzc2FnZSB9IG9mIGRhbmdlcm91c1BhdHRlcm5zKSB7XG4gICAgICAgICAgcGF0dGVybi5sYXN0SW5kZXggPSAwOyAvLyDph43nva7mraPliJnnirbmgIFcbiAgICAgICAgICBsZXQgbWF0Y2g7XG4gICAgICAgICAgd2hpbGUgKChtYXRjaCA9IHBhdHRlcm4uZXhlYyhjb250ZW50KSkgIT09IG51bGwpIHtcbiAgICAgICAgICAgIC8vIOiuoeeul+ihjOWPt1xuICAgICAgICAgICAgY29uc3QgYmVmb3JlTWF0Y2ggPSBjb250ZW50LnN1YnN0cmluZygwLCBtYXRjaC5pbmRleCk7XG4gICAgICAgICAgICBjb25zdCBsaW5lTnVtYmVyID0gYmVmb3JlTWF0Y2guc3BsaXQoJ1xcbicpLmxlbmd0aDtcblxuICAgICAgICAgICAgLy8g6Lez6L+H5rOo6YeK5Lit55qE5Yy56YWNXG4gICAgICAgICAgICBjb25zdCBsaW5lID0gbGluZXNbbGluZU51bWJlciAtIDFdO1xuICAgICAgICAgICAgaWYgKGxpbmUudHJpbSgpLnN0YXJ0c1dpdGgoJy8vJykgfHwgbGluZS50cmltKCkuc3RhcnRzV2l0aCgnKicpKSB7XG4gICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB3YXJuaW5ncy5wdXNoKHtcbiAgICAgICAgICAgICAgdHlwZTogJ2Rhbmdlcm91c19jb2RlJyxcbiAgICAgICAgICAgICAgc2V2ZXJpdHksXG4gICAgICAgICAgICAgIG1lc3NhZ2U6IGAke21lc3NhZ2V9OiAke25hbWV9YCxcbiAgICAgICAgICAgICAgZmlsZTogcGF0aC5yZWxhdGl2ZShza2lsbFBhdGgsIGZpbGUpLFxuICAgICAgICAgICAgICBsaW5lOiBsaW5lTnVtYmVyLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAvLyDlv73nlaXor7vlj5bplJnor69cbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gd2FybmluZ3M7XG4gIH1cblxuICAvKipcbiAgICog5omr5o+P6ISa5pys5paH5Lu2XG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHNjYW5TY3JpcHRzKHNraWxsUGF0aDogc3RyaW5nKTogUHJvbWlzZTxXYXJuaW5nW10+IHtcbiAgICBjb25zdCB3YXJuaW5nczogV2FybmluZ1tdID0gW107XG4gICAgY29uc3Qgc2NyaXB0c0RpciA9IHBhdGguam9pbihza2lsbFBhdGgsICdzY3JpcHRzJyk7XG5cbiAgICBpZiAoIWF3YWl0IGZzLnBhdGhFeGlzdHMoc2NyaXB0c0RpcikpIHtcbiAgICAgIHJldHVybiB3YXJuaW5ncztcbiAgICB9XG5cbiAgICBjb25zdCBzY3JpcHRGaWxlcyA9IGF3YWl0IGZzLnJlYWRkaXIoc2NyaXB0c0Rpcik7XG5cbiAgICBmb3IgKGNvbnN0IHNjcmlwdCBvZiBzY3JpcHRGaWxlcykge1xuICAgICAgY29uc3Qgc2NyaXB0UGF0aCA9IHBhdGguam9pbihzY3JpcHRzRGlyLCBzY3JpcHQpO1xuXG4gICAgICAvLyDmo4Dmn6Ugc2hlbGwg6ISa5pysXG4gICAgICBpZiAoc2NyaXB0LmVuZHNXaXRoKCcuc2gnKSkge1xuICAgICAgICBjb25zdCBjb250ZW50ID0gYXdhaXQgZnMucmVhZEZpbGUoc2NyaXB0UGF0aCwgJ3V0ZjgnKTtcblxuICAgICAgICBjb25zdCBkYW5nZXJvdXNDb21tYW5kcyA9IFtcbiAgICAgICAgICB7IHBhdHRlcm46IC9ybVxccystcmYvZywgbWVzc2FnZTogJ+WPkeeOsOWNsemZqeWRveS7pO+8mnJtIC1yZicgfSxcbiAgICAgICAgICB7IHBhdHRlcm46IC9jdXJsLipcXHxcXHMqYmFzaC9nLCBtZXNzYWdlOiAn5Y+R546w566h6YGT5omn6KGM77yaY3VybCB8IGJhc2gnIH0sXG4gICAgICAgICAgeyBwYXR0ZXJuOiAvd2dldC4qXFx8XFxzKmJhc2gvZywgbWVzc2FnZTogJ+WPkeeOsOeuoemBk+aJp+ihjO+8mndnZXQgfCBiYXNoJyB9LFxuICAgICAgICAgIHsgcGF0dGVybjogL3N1ZG8vZywgbWVzc2FnZTogJ+S9v+eUqCBzdWRvIOaPkOadgycgfSxcbiAgICAgICAgICB7IHBhdHRlcm46IC9jaG1vZFxccys3NzcvZywgbWVzc2FnZTogJ+iuvue9ruaWh+S7tuadg+mZkOS4uiA3NzcnIH0sXG4gICAgICAgIF07XG5cbiAgICAgICAgZm9yIChjb25zdCB7IHBhdHRlcm4sIG1lc3NhZ2UgfSBvZiBkYW5nZXJvdXNDb21tYW5kcykge1xuICAgICAgICAgIGlmIChwYXR0ZXJuLnRlc3QoY29udGVudCkpIHtcbiAgICAgICAgICAgIHdhcm5pbmdzLnB1c2goe1xuICAgICAgICAgICAgICB0eXBlOiAnZGFuZ2Vyb3VzX2NvZGUnLFxuICAgICAgICAgICAgICBzZXZlcml0eTogJ2hpZ2gnLFxuICAgICAgICAgICAgICBtZXNzYWdlLFxuICAgICAgICAgICAgICBmaWxlOiBgc2NyaXB0cy8ke3NjcmlwdH1gLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHdhcm5pbmdzO1xuICB9XG5cbiAgLyoqXG4gICAqIOajgOafpeS+nei1llxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBjaGVja0RlcGVuZGVuY2llcyhza2lsbFBhdGg6IHN0cmluZywgZGVwZW5kZW5jaWVzOiBzdHJpbmdbXSk6IFByb21pc2U8V2FybmluZ1tdPiB7XG4gICAgY29uc3Qgd2FybmluZ3M6IFdhcm5pbmdbXSA9IFtdO1xuXG4gICAgLy8g5qOA5p+l5L6d6LWW5pWw6YePXG4gICAgaWYgKGRlcGVuZGVuY2llcy5sZW5ndGggPiAyMCkge1xuICAgICAgd2FybmluZ3MucHVzaCh7XG4gICAgICAgIHR5cGU6ICdkZXBlbmRlbmN5JyxcbiAgICAgICAgc2V2ZXJpdHk6ICdsb3cnLFxuICAgICAgICBtZXNzYWdlOiBg5L6d6LWW6L+H5aSa77yIJHtkZXBlbmRlbmNpZXMubGVuZ3RofSDkuKrvvInvvIzlj6/og73lop7liqDmlLvlh7vpnaJgLFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgLy8g5bCd6K+V6L+Q6KGMIG5wbSBhdWRpdFxuICAgIHRyeSB7XG4gICAgICBjb25zdCBhdWRpdE91dHB1dCA9IGV4ZWNTeW5jKCducG0gYXVkaXQgLS1qc29uJywge1xuICAgICAgICBjd2Q6IHNraWxsUGF0aCxcbiAgICAgICAgc3RkaW86IFsncGlwZScsICdwaXBlJywgJ3BpcGUnXSxcbiAgICAgICAgZW5jb2Rpbmc6ICd1dGY4JyxcbiAgICAgIH0pO1xuXG4gICAgICBjb25zdCBhdWRpdCA9IEpTT04ucGFyc2UoYXVkaXRPdXRwdXQpO1xuICAgICAgY29uc3QgdnVsbmVyYWJpbGl0aWVzID0gYXVkaXQubWV0YWRhdGE/LnZ1bG5lcmFiaWxpdGllcztcblxuICAgICAgaWYgKHZ1bG5lcmFiaWxpdGllcyAmJiB2dWxuZXJhYmlsaXRpZXMudG90YWwgPiAwKSB7XG4gICAgICAgIHdhcm5pbmdzLnB1c2goe1xuICAgICAgICAgIHR5cGU6ICdkZXBlbmRlbmN5JyxcbiAgICAgICAgICBzZXZlcml0eTogdnVsbmVyYWJpbGl0aWVzLmNyaXRpY2FsID4gMCB8fCB2dWxuZXJhYmlsaXRpZXMuaGlnaCA+IDAgPyAnaGlnaCcgOiAnbWVkaXVtJyxcbiAgICAgICAgICBtZXNzYWdlOiBg5Y+R546wICR7dnVsbmVyYWJpbGl0aWVzLnRvdGFsfSDkuKrkvp3otZbmvI/mtJ7vvIgke3Z1bG5lcmFiaWxpdGllcy5jcml0aWNhbH0g5Lil6YeN77yMJHt2dWxuZXJhYmlsaXRpZXMuaGlnaH0g6auY77yJYCxcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIC8vIG5wbSBhdWRpdCDlj6/og73lpLHotKXvvIzlv73nlaVcbiAgICB9XG5cbiAgICByZXR1cm4gd2FybmluZ3M7XG4gIH1cblxuICAvKipcbiAgICog6I635Y+WIFNraWxsIOWFg+aVsOaNrlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBnZXRTa2lsbE1ldGFkYXRhKHNraWxsUGF0aDogc3RyaW5nKTogUHJvbWlzZTxTa2lsbE1ldGFkYXRhPiB7XG4gICAgY29uc3QgbWV0YWRhdGE6IFNraWxsTWV0YWRhdGEgPSB7XG4gICAgICBoYXNTa2lsbE1kOiBmYWxzZSxcbiAgICAgIGhhc1NjcmlwdHM6IGZhbHNlLFxuICAgICAgaGFzUGFja2FnZUpzb246IGZhbHNlLFxuICAgICAgZGVjbGFyZWRQZXJtaXNzaW9uczogW10sXG4gICAgICBkZXBlbmRlbmNpZXM6IFtdLFxuICAgICAgZGV2RGVwZW5kZW5jaWVzOiBbXSxcbiAgICB9O1xuXG4gICAgLy8g5qOA5p+lIFNLSUxMLm1kXG4gICAgY29uc3Qgc2tpbGxNZFBhdGggPSBwYXRoLmpvaW4oc2tpbGxQYXRoLCAnU0tJTEwubWQnKTtcbiAgICBpZiAoYXdhaXQgZnMucGF0aEV4aXN0cyhza2lsbE1kUGF0aCkpIHtcbiAgICAgIG1ldGFkYXRhLmhhc1NraWxsTWQgPSB0cnVlO1xuICAgICAgY29uc3QgY29udGVudCA9IGF3YWl0IGZzLnJlYWRGaWxlKHNraWxsTWRQYXRoLCAndXRmOCcpO1xuXG4gICAgICAvLyDmj5Dlj5bmnYPpmZDlo7DmmI7vvIjlgYforr7moLzlvI/kuLogXCJQZXJtaXNzaW9uczogZXhlYywgbmV0d29ya1wi77yJXG4gICAgICBjb25zdCBwZXJtaXNzaW9uTWF0Y2ggPSBjb250ZW50Lm1hdGNoKC9QZXJtaXNzaW9ucz86XFxzKihbXlxcbl0rKS9pKTtcbiAgICAgIGlmIChwZXJtaXNzaW9uTWF0Y2gpIHtcbiAgICAgICAgbWV0YWRhdGEuZGVjbGFyZWRQZXJtaXNzaW9ucyA9IHBlcm1pc3Npb25NYXRjaFsxXVxuICAgICAgICAgIC5zcGxpdCgnLCcpXG4gICAgICAgICAgLm1hcChwID0+IHAudHJpbSgpKVxuICAgICAgICAgIC5maWx0ZXIocCA9PiBwKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyDmo4Dmn6Ugc2NyaXB0cyDnm67lvZVcbiAgICBjb25zdCBzY3JpcHRzRGlyID0gcGF0aC5qb2luKHNraWxsUGF0aCwgJ3NjcmlwdHMnKTtcbiAgICBtZXRhZGF0YS5oYXNTY3JpcHRzID0gYXdhaXQgZnMucGF0aEV4aXN0cyhzY3JpcHRzRGlyKTtcblxuICAgIC8vIOajgOafpSBwYWNrYWdlLmpzb25cbiAgICBjb25zdCBwYWNrYWdlSnNvblBhdGggPSBwYXRoLmpvaW4oc2tpbGxQYXRoLCAncGFja2FnZS5qc29uJyk7XG4gICAgaWYgKGF3YWl0IGZzLnBhdGhFeGlzdHMocGFja2FnZUpzb25QYXRoKSkge1xuICAgICAgbWV0YWRhdGEuaGFzUGFja2FnZUpzb24gPSB0cnVlO1xuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgcGtnID0gSlNPTi5wYXJzZShhd2FpdCBmcy5yZWFkRmlsZShwYWNrYWdlSnNvblBhdGgsICd1dGY4JykpO1xuICAgICAgICBtZXRhZGF0YS5kZXBlbmRlbmNpZXMgPSBPYmplY3Qua2V5cyhwa2cuZGVwZW5kZW5jaWVzIHx8IHt9KTtcbiAgICAgICAgbWV0YWRhdGEuZGV2RGVwZW5kZW5jaWVzID0gT2JqZWN0LmtleXMocGtnLmRldkRlcGVuZGVuY2llcyB8fCB7fSk7XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAvLyDlv73nlaXop6PmnpDplJnor69cbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyDojrflj5bmnIDlkI7kv67mlLnml7bpl7RcbiAgICB0cnkge1xuICAgICAgY29uc3Qgc3RhdHMgPSBhd2FpdCBmcy5zdGF0KHNraWxsUGF0aCk7XG4gICAgICBtZXRhZGF0YS5sYXN0TW9kaWZpZWQgPSBzdGF0cy5tdGltZTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgLy8g5b+955WlXG4gICAgfVxuXG4gICAgcmV0dXJuIG1ldGFkYXRhO1xuICB9XG5cbiAgLyoqXG4gICAqIOiOt+WPluaJgOaciSBKUyDmlofku7ZcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgZ2V0SnNGaWxlcyhkaXI6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nW10+IHtcbiAgICBjb25zdCBmaWxlczogc3RyaW5nW10gPSBbXTtcblxuICAgIGFzeW5jIGZ1bmN0aW9uIHNjYW4oY3VycmVudERpcjogc3RyaW5nKSB7XG4gICAgICBjb25zdCBlbnRyaWVzID0gYXdhaXQgZnMucmVhZGRpcihjdXJyZW50RGlyLCB7IHdpdGhGaWxlVHlwZXM6IHRydWUgfSk7XG5cbiAgICAgIGZvciAoY29uc3QgZW50cnkgb2YgZW50cmllcykge1xuICAgICAgICBjb25zdCBmdWxsUGF0aCA9IHBhdGguam9pbihjdXJyZW50RGlyLCBlbnRyeS5uYW1lKTtcblxuICAgICAgICBpZiAoZW50cnkuaXNEaXJlY3RvcnkoKSkge1xuICAgICAgICAgIC8vIOi3s+i/hyBub2RlX21vZHVsZXNcbiAgICAgICAgICBpZiAoZW50cnkubmFtZSA9PT0gJ25vZGVfbW9kdWxlcycgfHwgZW50cnkubmFtZSA9PT0gJ2Rpc3QnKSB7XG4gICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICB9XG4gICAgICAgICAgYXdhaXQgc2NhbihmdWxsUGF0aCk7XG4gICAgICAgIH0gZWxzZSBpZiAoZW50cnkuaXNGaWxlKCkgJiYgKGVudHJ5Lm5hbWUuZW5kc1dpdGgoJy5qcycpIHx8IGVudHJ5Lm5hbWUuZW5kc1dpdGgoJy50cycpKSkge1xuICAgICAgICAgIGZpbGVzLnB1c2goZnVsbFBhdGgpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgYXdhaXQgc2NhbihkaXIpO1xuICAgIHJldHVybiBmaWxlcztcbiAgfVxuXG4gIC8qKlxuICAgKiDorqHnrpfpo47pmannrYnnuqdcbiAgICovXG4gIHByaXZhdGUgY2FsY3VsYXRlUmlza0xldmVsKHdhcm5pbmdzOiBXYXJuaW5nW10pOiAnTE9XJyB8ICdNRURJVU0nIHwgJ0hJR0gnIHwgJ0NSSVRJQ0FMJyB7XG4gICAgY29uc3QgY3JpdGljYWxDb3VudCA9IHdhcm5pbmdzLmZpbHRlcih3ID0+IHcuc2V2ZXJpdHkgPT09ICdjcml0aWNhbCcpLmxlbmd0aDtcbiAgICBjb25zdCBoaWdoQ291bnQgPSB3YXJuaW5ncy5maWx0ZXIodyA9PiB3LnNldmVyaXR5ID09PSAnaGlnaCcpLmxlbmd0aDtcbiAgICBjb25zdCBtZWRpdW1Db3VudCA9IHdhcm5pbmdzLmZpbHRlcih3ID0+IHcuc2V2ZXJpdHkgPT09ICdtZWRpdW0nKS5sZW5ndGg7XG5cbiAgICBpZiAoY3JpdGljYWxDb3VudCA+IDApIHJldHVybiAnQ1JJVElDQUwnO1xuICAgIGlmIChoaWdoQ291bnQgPiAyKSByZXR1cm4gJ0hJR0gnO1xuICAgIGlmIChoaWdoQ291bnQgPiAwIHx8IG1lZGl1bUNvdW50ID4gMykgcmV0dXJuICdNRURJVU0nO1xuICAgIHJldHVybiAnTE9XJztcbiAgfVxuXG4gIC8qKlxuICAgKiDnlJ/miJDlrqHorqHmiqXlkYpcbiAgICovXG4gIGdlbmVyYXRlUmVwb3J0KHJlc3VsdDogU2tpbGxBdWRpdFJlc3VsdCk6IHN0cmluZyB7XG4gICAgY29uc3QgbGluZXM6IHN0cmluZ1tdID0gW107XG5cbiAgICBsaW5lcy5wdXNoKGAjIFNraWxsIOWuieWFqOWuoeiuoeaKpeWRimApO1xuICAgIGxpbmVzLnB1c2goJycpO1xuICAgIGxpbmVzLnB1c2goYCMjIOWfuuacrOS/oeaBr2ApO1xuICAgIGxpbmVzLnB1c2goYC0gKipTa2lsbCDlkI3np7AqKjogJHtyZXN1bHQuc2tpbGxOYW1lfWApO1xuICAgIGxpbmVzLnB1c2goYC0gKirot6/lvoQqKjogJHtyZXN1bHQuc2tpbGxQYXRofWApO1xuICAgIGxpbmVzLnB1c2goYC0gKirmnaXmupAqKjogJHtyZXN1bHQuc291cmNlfWApO1xuICAgIGxpbmVzLnB1c2goYC0gKirpo47pmannrYnnuqcqKjogJHt0aGlzLmdldFJpc2tFbW9qaShyZXN1bHQucmlza0xldmVsKX0gJHtyZXN1bHQucmlza0xldmVsfWApO1xuICAgIGxpbmVzLnB1c2goYC0gKirlrqHmoLjnu5PmnpwqKjogJHtyZXN1bHQucGFzc2VkID8gJ+KchSDpgJrov4cnIDogJ+KdjCDmnKrpgJrov4cnfWApO1xuICAgIGxpbmVzLnB1c2goJycpO1xuXG4gICAgaWYgKHJlc3VsdC53YXJuaW5ncy5sZW5ndGggPiAwKSB7XG4gICAgICBsaW5lcy5wdXNoKGAjIyDorablkYrvvIgke3Jlc3VsdC53YXJuaW5ncy5sZW5ndGh9IOS4qu+8iWApO1xuICAgICAgbGluZXMucHVzaCgnJyk7XG4gICAgICBmb3IgKGNvbnN0IHdhcm5pbmcgb2YgcmVzdWx0Lndhcm5pbmdzKSB7XG4gICAgICAgIGxpbmVzLnB1c2goYC0gJHt0aGlzLmdldFNldmVyaXR5RW1vamkod2FybmluZy5zZXZlcml0eSl9ICoqWyR7d2FybmluZy50eXBlfV0qKiAke3dhcm5pbmcubWVzc2FnZX1gKTtcbiAgICAgICAgaWYgKHdhcm5pbmcuZmlsZSkge1xuICAgICAgICAgIGxpbmVzLnB1c2goYCAgLSDmlofku7bvvJpcXGAke3dhcm5pbmcuZmlsZX1cXGAke3dhcm5pbmcubGluZSA/IGAg56ysICR7d2FybmluZy5saW5lfSDooYxgIDogJyd9YCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIGxpbmVzLnB1c2goJycpO1xuICAgIH1cblxuICAgIGlmIChyZXN1bHQucmVjb21tZW5kYXRpb25zLmxlbmd0aCA+IDApIHtcbiAgICAgIGxpbmVzLnB1c2goYCMjIOW7uuiurmApO1xuICAgICAgbGluZXMucHVzaCgnJyk7XG4gICAgICBmb3IgKGNvbnN0IHJlYyBvZiByZXN1bHQucmVjb21tZW5kYXRpb25zKSB7XG4gICAgICAgIGxpbmVzLnB1c2goYC0gJHtyZWN9YCk7XG4gICAgICB9XG4gICAgICBsaW5lcy5wdXNoKCcnKTtcbiAgICB9XG5cbiAgICBsaW5lcy5wdXNoKGAjIyDlhYPmlbDmja5gKTtcbiAgICBsaW5lcy5wdXNoKGAtIOaciSBTS0lMTC5tZDogJHtyZXN1bHQubWV0YWRhdGEuaGFzU2tpbGxNZCA/ICfinIUnIDogJ+KdjCd9YCk7XG4gICAgbGluZXMucHVzaChgLSDmnIkgc2NyaXB0cyDnm67lvZXvvJoke3Jlc3VsdC5tZXRhZGF0YS5oYXNTY3JpcHRzID8gJ+KchScgOiAn4p2MJ31gKTtcbiAgICBsaW5lcy5wdXNoKGAtIOaciSBwYWNrYWdlLmpzb246ICR7cmVzdWx0Lm1ldGFkYXRhLmhhc1BhY2thZ2VKc29uID8gJ+KchScgOiAn4p2MJ31gKTtcbiAgICBsaW5lcy5wdXNoKGAtIOWjsOaYjuadg+mZkO+8miR7cmVzdWx0Lm1ldGFkYXRhLmRlY2xhcmVkUGVybWlzc2lvbnMuam9pbignLCAnKSB8fCAn5pegJ31gKTtcbiAgICBsaW5lcy5wdXNoKGAtIOS+nei1luaVsOmHj++8miR7cmVzdWx0Lm1ldGFkYXRhLmRlcGVuZGVuY2llcy5sZW5ndGh9YCk7XG4gICAgbGluZXMucHVzaCgnJyk7XG5cbiAgICByZXR1cm4gbGluZXMuam9pbignXFxuJyk7XG4gIH1cblxuICBwcml2YXRlIGdldFJpc2tFbW9qaShsZXZlbDogc3RyaW5nKTogc3RyaW5nIHtcbiAgICBjb25zdCBlbW9qaXM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7XG4gICAgICBMT1c6ICfwn5+iJyxcbiAgICAgIE1FRElVTTogJ/Cfn6EnLFxuICAgICAgSElHSDogJ/Cfn6AnLFxuICAgICAgQ1JJVElDQUw6ICfwn5S0JyxcbiAgICB9O1xuICAgIHJldHVybiBlbW9qaXNbbGV2ZWxdIHx8ICfimqonO1xuICB9XG5cbiAgcHJpdmF0ZSBnZXRTZXZlcml0eUVtb2ppKHNldmVyaXR5OiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIGNvbnN0IGVtb2ppczogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHtcbiAgICAgIGxvdzogJ+KEue+4jycsXG4gICAgICBtZWRpdW06ICfimqDvuI8nLFxuICAgICAgaGlnaDogJ/CfmqgnLFxuICAgICAgY3JpdGljYWw6ICfwn5KAJyxcbiAgICB9O1xuICAgIHJldHVybiBlbW9qaXNbc2V2ZXJpdHldIHx8ICfimqonO1xuICB9XG59XG4iXX0=
@@ -0,0 +1,22 @@
1
+ export * from './middleware';
2
+ export * from './validators';
3
+ export * from './loggers';
4
+ export * from './utils';
5
+ export * from './auditors';
6
+ import { LoopDetector } from './middleware/loop-detector';
7
+ import { TraceLogger } from './middleware/trace-logger';
8
+ import { ContextInjector } from './middleware/context-injector';
9
+ import { ConfigValidator } from './validators/config-validator';
10
+ import { ConfigLogger } from './loggers/config-logger';
11
+ import { OperationLogger } from './loggers/operation-logger';
12
+ export interface Harness {
13
+ loopDetector: LoopDetector;
14
+ traceLogger: TraceLogger;
15
+ contextInjector: ContextInjector;
16
+ configValidator: ConfigValidator;
17
+ configLogger: ConfigLogger;
18
+ operationLogger: OperationLogger;
19
+ }
20
+ export declare function createHarness(workspacePath: string): Harness;
21
+ export declare function createConfigValidator(): ConfigValidator;
22
+ export default createHarness;
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ // src/index.ts - 主入口
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
16
+ };
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.createHarness = createHarness;
19
+ exports.createConfigValidator = createConfigValidator;
20
+ __exportStar(require("./middleware"), exports);
21
+ __exportStar(require("./validators"), exports);
22
+ __exportStar(require("./loggers"), exports);
23
+ __exportStar(require("./utils"), exports);
24
+ __exportStar(require("./auditors"), exports);
25
+ // 便捷工厂函数
26
+ const loop_detector_1 = require("./middleware/loop-detector");
27
+ const trace_logger_1 = require("./middleware/trace-logger");
28
+ const context_injector_1 = require("./middleware/context-injector");
29
+ const config_validator_1 = require("./validators/config-validator");
30
+ const config_logger_1 = require("./loggers/config-logger");
31
+ const operation_logger_1 = require("./loggers/operation-logger");
32
+ function createHarness(workspacePath) {
33
+ return {
34
+ loopDetector: new loop_detector_1.LoopDetector(workspacePath),
35
+ traceLogger: new trace_logger_1.TraceLogger(workspacePath),
36
+ contextInjector: new context_injector_1.ContextInjector(workspacePath),
37
+ configValidator: new config_validator_1.ConfigValidator(workspacePath),
38
+ configLogger: new config_logger_1.ConfigLogger(workspacePath),
39
+ operationLogger: new operation_logger_1.OperationLogger(workspacePath),
40
+ };
41
+ }
42
+ // 便捷导出(用于包装层)
43
+ function createConfigValidator() {
44
+ return new config_validator_1.ConfigValidator(process.cwd());
45
+ }
46
+ exports.default = createHarness;
47
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY29yZS9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEscUJBQXFCOzs7Ozs7Ozs7Ozs7Ozs7O0FBeUJyQixzQ0FTQztBQUdELHNEQUVDO0FBckNELCtDQUE2QjtBQUM3QiwrQ0FBNkI7QUFDN0IsNENBQTBCO0FBQzFCLDBDQUF3QjtBQUN4Qiw2Q0FBMkI7QUFFM0IsU0FBUztBQUNULDhEQUEwRDtBQUMxRCw0REFBd0Q7QUFDeEQsb0VBQWdFO0FBQ2hFLG9FQUFnRTtBQUNoRSwyREFBdUQ7QUFDdkQsaUVBQTZEO0FBVzdELFNBQWdCLGFBQWEsQ0FBQyxhQUFxQjtJQUNqRCxPQUFPO1FBQ0wsWUFBWSxFQUFFLElBQUksNEJBQVksQ0FBQyxhQUFhLENBQUM7UUFDN0MsV0FBVyxFQUFFLElBQUksMEJBQVcsQ0FBQyxhQUFhLENBQUM7UUFDM0MsZUFBZSxFQUFFLElBQUksa0NBQWUsQ0FBQyxhQUFhLENBQUM7UUFDbkQsZUFBZSxFQUFFLElBQUksa0NBQWUsQ0FBQyxhQUFhLENBQUM7UUFDbkQsWUFBWSxFQUFFLElBQUksNEJBQVksQ0FBQyxhQUFhLENBQUM7UUFDN0MsZUFBZSxFQUFFLElBQUksa0NBQWUsQ0FBQyxhQUFhLENBQUM7S0FDcEQsQ0FBQztBQUNKLENBQUM7QUFFRCxjQUFjO0FBQ2QsU0FBZ0IscUJBQXFCO0lBQ25DLE9BQU8sSUFBSSxrQ0FBZSxDQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDO0FBQzVDLENBQUM7QUFFRCxrQkFBZSxhQUFhLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBzcmMvaW5kZXgudHMgLSDkuLvlhaXlj6NcblxuZXhwb3J0ICogZnJvbSAnLi9taWRkbGV3YXJlJztcbmV4cG9ydCAqIGZyb20gJy4vdmFsaWRhdG9ycyc7XG5leHBvcnQgKiBmcm9tICcuL2xvZ2dlcnMnO1xuZXhwb3J0ICogZnJvbSAnLi91dGlscyc7XG5leHBvcnQgKiBmcm9tICcuL2F1ZGl0b3JzJztcblxuLy8g5L6/5o235bel5Y6C5Ye95pWwXG5pbXBvcnQgeyBMb29wRGV0ZWN0b3IgfSBmcm9tICcuL21pZGRsZXdhcmUvbG9vcC1kZXRlY3Rvcic7XG5pbXBvcnQgeyBUcmFjZUxvZ2dlciB9IGZyb20gJy4vbWlkZGxld2FyZS90cmFjZS1sb2dnZXInO1xuaW1wb3J0IHsgQ29udGV4dEluamVjdG9yIH0gZnJvbSAnLi9taWRkbGV3YXJlL2NvbnRleHQtaW5qZWN0b3InO1xuaW1wb3J0IHsgQ29uZmlnVmFsaWRhdG9yIH0gZnJvbSAnLi92YWxpZGF0b3JzL2NvbmZpZy12YWxpZGF0b3InO1xuaW1wb3J0IHsgQ29uZmlnTG9nZ2VyIH0gZnJvbSAnLi9sb2dnZXJzL2NvbmZpZy1sb2dnZXInO1xuaW1wb3J0IHsgT3BlcmF0aW9uTG9nZ2VyIH0gZnJvbSAnLi9sb2dnZXJzL29wZXJhdGlvbi1sb2dnZXInO1xuXG5leHBvcnQgaW50ZXJmYWNlIEhhcm5lc3Mge1xuICBsb29wRGV0ZWN0b3I6IExvb3BEZXRlY3RvcjtcbiAgdHJhY2VMb2dnZXI6IFRyYWNlTG9nZ2VyO1xuICBjb250ZXh0SW5qZWN0b3I6IENvbnRleHRJbmplY3RvcjtcbiAgY29uZmlnVmFsaWRhdG9yOiBDb25maWdWYWxpZGF0b3I7XG4gIGNvbmZpZ0xvZ2dlcjogQ29uZmlnTG9nZ2VyO1xuICBvcGVyYXRpb25Mb2dnZXI6IE9wZXJhdGlvbkxvZ2dlcjtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZUhhcm5lc3Mod29ya3NwYWNlUGF0aDogc3RyaW5nKTogSGFybmVzcyB7XG4gIHJldHVybiB7XG4gICAgbG9vcERldGVjdG9yOiBuZXcgTG9vcERldGVjdG9yKHdvcmtzcGFjZVBhdGgpLFxuICAgIHRyYWNlTG9nZ2VyOiBuZXcgVHJhY2VMb2dnZXIod29ya3NwYWNlUGF0aCksXG4gICAgY29udGV4dEluamVjdG9yOiBuZXcgQ29udGV4dEluamVjdG9yKHdvcmtzcGFjZVBhdGgpLFxuICAgIGNvbmZpZ1ZhbGlkYXRvcjogbmV3IENvbmZpZ1ZhbGlkYXRvcih3b3Jrc3BhY2VQYXRoKSxcbiAgICBjb25maWdMb2dnZXI6IG5ldyBDb25maWdMb2dnZXIod29ya3NwYWNlUGF0aCksXG4gICAgb3BlcmF0aW9uTG9nZ2VyOiBuZXcgT3BlcmF0aW9uTG9nZ2VyKHdvcmtzcGFjZVBhdGgpLFxuICB9O1xufVxuXG4vLyDkvr/mjbflr7zlh7rvvIjnlKjkuo7ljIXoo4XlsYLvvIlcbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVDb25maWdWYWxpZGF0b3IoKTogQ29uZmlnVmFsaWRhdG9yIHtcbiAgcmV0dXJuIG5ldyBDb25maWdWYWxpZGF0b3IocHJvY2Vzcy5jd2QoKSk7XG59XG5cbmV4cG9ydCBkZWZhdWx0IGNyZWF0ZUhhcm5lc3M7XG4iXX0=
@@ -0,0 +1,25 @@
1
+ export interface ConfigChange {
2
+ timestamp: string;
3
+ modifier: string;
4
+ file: string;
5
+ changes: Array<{
6
+ field: string;
7
+ oldValue: any;
8
+ newValue: any;
9
+ }>;
10
+ reason: string;
11
+ verified: boolean;
12
+ gatewayRestarted: boolean;
13
+ sessionId?: string;
14
+ }
15
+ export declare class ConfigLogger {
16
+ private workspacePath;
17
+ private logFilePath;
18
+ constructor(workspacePath: string);
19
+ log(change: Omit<ConfigChange, 'timestamp'>): void;
20
+ private formatEntry;
21
+ private truncateValue;
22
+ getRecentChanges(limit?: number): ConfigChange[];
23
+ private parseEntry;
24
+ exportToJson(outputPath: string): void;
25
+ }