@aiready/cli 0.10.3 โ 0.10.6
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/.turbo/turbo-build.log +8 -8
- package/.turbo/turbo-test.log +3 -3
- package/dist/chunk-R3O7QPKD.mjs +419 -0
- package/dist/chunk-VQCWYJYJ.mjs +438 -0
- package/dist/cli.js +188 -98
- package/dist/cli.mjs +106 -33
- package/dist/index.js +105 -85
- package/dist/index.mjs +1 -1
- package/package.json +12 -12
- package/src/.aiready/aiready-report-20260306-191804.json +8281 -0
- package/src/.aiready/aiready-report-20260306-191824.json +8281 -0
- package/src/.aiready/aiready-report-20260306-191838.json +8281 -0
- package/src/.aiready/aiready-report-20260306-192002.json +15942 -0
- package/src/.aiready/aiready-report-20260306-192102.json +15048 -0
- package/src/.aiready/aiready-report-20260306-202328.json +19961 -0
- package/src/.aiready/aiready-report-20260306-213155.json +24657 -0
- package/src/.aiready/aiready-report-20260306-213925.json +24657 -0
- package/src/commands/scan.ts +144 -32
- package/src/index.ts +139 -106
package/src/index.ts
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
type ToolScoringOutput,
|
|
8
8
|
type ScoringResult,
|
|
9
9
|
calculateTokenBudget,
|
|
10
|
+
ToolName,
|
|
10
11
|
} from '@aiready/core';
|
|
11
12
|
export type { ToolScoringOutput, ScoringResult };
|
|
12
13
|
|
|
@@ -32,23 +33,29 @@ export interface UnifiedAnalysisOptions extends ScanOptions {
|
|
|
32
33
|
}
|
|
33
34
|
|
|
34
35
|
export interface UnifiedAnalysisResult {
|
|
35
|
-
//
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
36
|
+
// Canonical keys matching ToolName enum members
|
|
37
|
+
[ToolName.PatternDetect]?: SpokeOutput & { duplicates: any[] };
|
|
38
|
+
[ToolName.ContextAnalyzer]?: SpokeOutput;
|
|
39
|
+
[ToolName.NamingConsistency]?: SpokeOutput;
|
|
40
|
+
[ToolName.DocDrift]?: SpokeOutput;
|
|
41
|
+
[ToolName.DependencyHealth]?: SpokeOutput;
|
|
42
|
+
[ToolName.AiSignalClarity]?: any;
|
|
43
|
+
[ToolName.AgentGrounding]?: any;
|
|
44
|
+
[ToolName.TestabilityIndex]?: any;
|
|
45
|
+
[ToolName.ChangeAmplification]?: SpokeOutput;
|
|
46
|
+
|
|
47
|
+
// Legacy/Internal metadata
|
|
46
48
|
summary: {
|
|
47
49
|
totalIssues: number;
|
|
48
50
|
toolsRun: string[];
|
|
49
51
|
executionTime: number;
|
|
50
52
|
};
|
|
51
53
|
scoring?: ScoringResult;
|
|
54
|
+
// Compatibility fallbacks (deprecated)
|
|
55
|
+
/** @deprecated use [ToolName.PatternDetect] */
|
|
56
|
+
patternDetect?: any;
|
|
57
|
+
/** @deprecated use [ToolName.ContextAnalyzer] */
|
|
58
|
+
contextAnalyzer?: any;
|
|
52
59
|
}
|
|
53
60
|
|
|
54
61
|
// Severity ordering (higher number = more severe)
|
|
@@ -114,11 +121,14 @@ export async function analyzeUnified(
|
|
|
114
121
|
if (options.progressCallback) {
|
|
115
122
|
options.progressCallback({ tool: 'patterns', data: patternResult });
|
|
116
123
|
}
|
|
117
|
-
|
|
124
|
+
const output = {
|
|
118
125
|
results: sortBySeverity(patternResult.results),
|
|
119
126
|
summary: patternResult.summary || {},
|
|
120
127
|
duplicates: patternResult.duplicates || [],
|
|
121
128
|
};
|
|
129
|
+
result[ToolName.PatternDetect] = output;
|
|
130
|
+
result.patternDetect = output; // Compatibility fallback
|
|
131
|
+
|
|
122
132
|
result.summary.totalIssues += patternResult.results.reduce(
|
|
123
133
|
(sum, file) => sum + file.issues.length,
|
|
124
134
|
0
|
|
@@ -141,10 +151,13 @@ export async function analyzeUnified(
|
|
|
141
151
|
|
|
142
152
|
const { generateSummary: genContextSummary } =
|
|
143
153
|
await import('@aiready/context-analyzer');
|
|
144
|
-
|
|
154
|
+
const output = {
|
|
145
155
|
results: sorted,
|
|
146
156
|
summary: genContextSummary(sorted),
|
|
147
157
|
};
|
|
158
|
+
result[ToolName.ContextAnalyzer] = output;
|
|
159
|
+
result.contextAnalyzer = output; // Compatibility fallback
|
|
160
|
+
|
|
148
161
|
result.summary.totalIssues += sorted.length;
|
|
149
162
|
}
|
|
150
163
|
|
|
@@ -160,7 +173,7 @@ export async function analyzeUnified(
|
|
|
160
173
|
if (options.progressCallback) {
|
|
161
174
|
options.progressCallback({ tool: 'consistency', data: report });
|
|
162
175
|
}
|
|
163
|
-
result.
|
|
176
|
+
result[ToolName.NamingConsistency] = {
|
|
164
177
|
results: report.results ? sortBySeverity(report.results) : [],
|
|
165
178
|
summary: report.summary,
|
|
166
179
|
};
|
|
@@ -179,11 +192,14 @@ export async function analyzeUnified(
|
|
|
179
192
|
if (options.progressCallback) {
|
|
180
193
|
options.progressCallback({ tool: 'doc-drift', data: report });
|
|
181
194
|
}
|
|
182
|
-
result.
|
|
183
|
-
results: report.results || [],
|
|
195
|
+
result[ToolName.DocDrift] = {
|
|
196
|
+
results: (report as any).results || (report as any).issues || [],
|
|
184
197
|
summary: report.summary || {},
|
|
185
198
|
};
|
|
186
|
-
|
|
199
|
+
const issueCount =
|
|
200
|
+
(report as any).issues?.length ||
|
|
201
|
+
((report as any).results ? (report as any).results.length : 0);
|
|
202
|
+
result.summary.totalIssues += issueCount;
|
|
187
203
|
}
|
|
188
204
|
|
|
189
205
|
// Run Dependency Health analysis
|
|
@@ -198,11 +214,14 @@ export async function analyzeUnified(
|
|
|
198
214
|
if (options.progressCallback) {
|
|
199
215
|
options.progressCallback({ tool: 'deps-health', data: report });
|
|
200
216
|
}
|
|
201
|
-
result.
|
|
202
|
-
results: report.results || [],
|
|
217
|
+
result[ToolName.DependencyHealth] = {
|
|
218
|
+
results: (report as any).results || (report as any).issues || [],
|
|
203
219
|
summary: report.summary || {},
|
|
204
220
|
};
|
|
205
|
-
|
|
221
|
+
const issueCount =
|
|
222
|
+
(report as any).issues?.length ||
|
|
223
|
+
((report as any).results ? (report as any).results.length : 0);
|
|
224
|
+
result.summary.totalIssues += issueCount;
|
|
206
225
|
}
|
|
207
226
|
|
|
208
227
|
// Run AI Signal Clarity analysis
|
|
@@ -218,14 +237,14 @@ export async function analyzeUnified(
|
|
|
218
237
|
if (options.progressCallback) {
|
|
219
238
|
options.progressCallback({ tool: 'ai-signal-clarity', data: report });
|
|
220
239
|
}
|
|
221
|
-
result.
|
|
240
|
+
result[ToolName.AiSignalClarity] = {
|
|
222
241
|
...report,
|
|
223
|
-
results: report.results || [],
|
|
242
|
+
results: report.results || report.issues || [],
|
|
224
243
|
summary: report.summary || {},
|
|
225
244
|
};
|
|
226
245
|
result.summary.totalIssues +=
|
|
227
|
-
report.results?.reduce(
|
|
228
|
-
(sum: number, r: any) => sum + (r.issues?.length ||
|
|
246
|
+
(report.results || report.issues)?.reduce(
|
|
247
|
+
(sum: number, r: any) => sum + (r.issues?.length || 1),
|
|
229
248
|
0
|
|
230
249
|
) || 0;
|
|
231
250
|
}
|
|
@@ -242,12 +261,16 @@ export async function analyzeUnified(
|
|
|
242
261
|
if (options.progressCallback) {
|
|
243
262
|
options.progressCallback({ tool: 'agent-grounding', data: report });
|
|
244
263
|
}
|
|
245
|
-
result.
|
|
246
|
-
...report,
|
|
247
|
-
results: report.results || [],
|
|
264
|
+
result[ToolName.AgentGrounding] = {
|
|
265
|
+
...(report as any),
|
|
266
|
+
results: (report as any).results || (report as any).issues || [],
|
|
248
267
|
summary: report.summary || {},
|
|
249
268
|
};
|
|
250
|
-
result.summary.totalIssues +=
|
|
269
|
+
result.summary.totalIssues += (
|
|
270
|
+
(report as any).issues ||
|
|
271
|
+
(report as any).results ||
|
|
272
|
+
[]
|
|
273
|
+
).length;
|
|
251
274
|
}
|
|
252
275
|
|
|
253
276
|
// Run Testability analysis
|
|
@@ -262,12 +285,16 @@ export async function analyzeUnified(
|
|
|
262
285
|
if (options.progressCallback) {
|
|
263
286
|
options.progressCallback({ tool: 'testability', data: report });
|
|
264
287
|
}
|
|
265
|
-
result.
|
|
266
|
-
...report,
|
|
267
|
-
results: report.results || [],
|
|
288
|
+
result[ToolName.TestabilityIndex] = {
|
|
289
|
+
...(report as any),
|
|
290
|
+
results: (report as any).results || (report as any).issues || [],
|
|
268
291
|
summary: report.summary || {},
|
|
269
292
|
};
|
|
270
|
-
result.summary.totalIssues +=
|
|
293
|
+
result.summary.totalIssues += (
|
|
294
|
+
(report as any).issues ||
|
|
295
|
+
(report as any).results ||
|
|
296
|
+
[]
|
|
297
|
+
).length;
|
|
271
298
|
}
|
|
272
299
|
|
|
273
300
|
// Run Change Amplification analysis
|
|
@@ -283,7 +310,7 @@ export async function analyzeUnified(
|
|
|
283
310
|
if (options.progressCallback) {
|
|
284
311
|
options.progressCallback({ tool: 'change-amplification', data: report });
|
|
285
312
|
}
|
|
286
|
-
result.
|
|
313
|
+
result[ToolName.ChangeAmplification] = {
|
|
287
314
|
results: report.results || [],
|
|
288
315
|
summary: report.summary || {},
|
|
289
316
|
};
|
|
@@ -301,16 +328,17 @@ export async function scoreUnified(
|
|
|
301
328
|
const toolScores: Map<string, ToolScoringOutput> = new Map();
|
|
302
329
|
|
|
303
330
|
// Patterns score
|
|
304
|
-
if (results.
|
|
331
|
+
if (results[ToolName.PatternDetect]) {
|
|
332
|
+
const data = results[ToolName.PatternDetect];
|
|
305
333
|
const { calculatePatternScore } = await import('@aiready/pattern-detect');
|
|
306
334
|
try {
|
|
307
335
|
const patternScore = calculatePatternScore(
|
|
308
|
-
|
|
309
|
-
|
|
336
|
+
data.duplicates,
|
|
337
|
+
data.results?.length || 0
|
|
310
338
|
);
|
|
311
339
|
|
|
312
340
|
// Calculate token budget for patterns (waste = duplication)
|
|
313
|
-
const wastedTokens =
|
|
341
|
+
const wastedTokens = data.duplicates.reduce(
|
|
314
342
|
(sum: number, d: any) => sum + (d.tokenCost || 0),
|
|
315
343
|
0
|
|
316
344
|
);
|
|
@@ -323,17 +351,18 @@ export async function scoreUnified(
|
|
|
323
351
|
},
|
|
324
352
|
});
|
|
325
353
|
|
|
326
|
-
toolScores.set(
|
|
354
|
+
toolScores.set(ToolName.PatternDetect, patternScore);
|
|
327
355
|
} catch (err) {
|
|
328
356
|
void err;
|
|
329
357
|
}
|
|
330
358
|
}
|
|
331
359
|
|
|
332
360
|
// Context score
|
|
333
|
-
if (results.
|
|
361
|
+
if (results[ToolName.ContextAnalyzer]) {
|
|
362
|
+
const data = results[ToolName.ContextAnalyzer];
|
|
334
363
|
const { calculateContextScore } = await import('@aiready/context-analyzer');
|
|
335
364
|
try {
|
|
336
|
-
const ctxSummary =
|
|
365
|
+
const ctxSummary = data.summary;
|
|
337
366
|
const contextScore = calculateContextScore(ctxSummary);
|
|
338
367
|
|
|
339
368
|
// Calculate token budget for context (waste = fragmentation + depth overhead)
|
|
@@ -346,72 +375,74 @@ export async function scoreUnified(
|
|
|
346
375
|
},
|
|
347
376
|
});
|
|
348
377
|
|
|
349
|
-
toolScores.set(
|
|
378
|
+
toolScores.set(ToolName.ContextAnalyzer, contextScore);
|
|
350
379
|
} catch (err) {
|
|
351
380
|
void err;
|
|
352
381
|
}
|
|
353
382
|
}
|
|
354
383
|
|
|
355
384
|
// Consistency score
|
|
356
|
-
if (results.
|
|
385
|
+
if (results[ToolName.NamingConsistency]) {
|
|
386
|
+
const data = results[ToolName.NamingConsistency];
|
|
357
387
|
const { calculateConsistencyScore } = await import('@aiready/consistency');
|
|
358
388
|
try {
|
|
359
|
-
const issues =
|
|
360
|
-
|
|
361
|
-
const totalFiles = results.consistency.summary?.filesAnalyzed || 0;
|
|
389
|
+
const issues = data.results?.flatMap((r: any) => r.issues) || [];
|
|
390
|
+
const totalFiles = data.summary?.filesAnalyzed || 0;
|
|
362
391
|
const consistencyScore = calculateConsistencyScore(issues, totalFiles);
|
|
363
|
-
toolScores.set(
|
|
392
|
+
toolScores.set(ToolName.NamingConsistency, consistencyScore);
|
|
364
393
|
} catch (err) {
|
|
365
394
|
void err;
|
|
366
395
|
}
|
|
367
396
|
}
|
|
368
397
|
|
|
369
398
|
// AI signal clarity score
|
|
370
|
-
if (results.
|
|
399
|
+
if (results[ToolName.AiSignalClarity]) {
|
|
371
400
|
const { calculateAiSignalClarityScore } =
|
|
372
401
|
await import('@aiready/ai-signal-clarity');
|
|
373
402
|
try {
|
|
374
|
-
const hrScore = calculateAiSignalClarityScore(
|
|
375
|
-
|
|
403
|
+
const hrScore = calculateAiSignalClarityScore(
|
|
404
|
+
results[ToolName.AiSignalClarity]
|
|
405
|
+
);
|
|
406
|
+
toolScores.set(ToolName.AiSignalClarity, hrScore);
|
|
376
407
|
} catch (err) {
|
|
377
408
|
void err;
|
|
378
409
|
}
|
|
379
410
|
}
|
|
380
411
|
|
|
381
412
|
// Agent grounding score
|
|
382
|
-
if (results.
|
|
413
|
+
if (results[ToolName.AgentGrounding]) {
|
|
383
414
|
const { calculateGroundingScore } =
|
|
384
415
|
await import('@aiready/agent-grounding');
|
|
385
416
|
try {
|
|
386
|
-
const agScore = calculateGroundingScore(results.
|
|
387
|
-
toolScores.set(
|
|
417
|
+
const agScore = calculateGroundingScore(results[ToolName.AgentGrounding]);
|
|
418
|
+
toolScores.set(ToolName.AgentGrounding, agScore);
|
|
388
419
|
} catch (err) {
|
|
389
420
|
void err;
|
|
390
421
|
}
|
|
391
422
|
}
|
|
392
423
|
|
|
393
424
|
// Testability score
|
|
394
|
-
if (results.
|
|
425
|
+
if (results[ToolName.TestabilityIndex]) {
|
|
395
426
|
const { calculateTestabilityScore } = await import('@aiready/testability');
|
|
396
427
|
try {
|
|
397
|
-
const tbScore = calculateTestabilityScore(
|
|
398
|
-
|
|
428
|
+
const tbScore = calculateTestabilityScore(
|
|
429
|
+
results[ToolName.TestabilityIndex]
|
|
430
|
+
);
|
|
431
|
+
toolScores.set(ToolName.TestabilityIndex, tbScore);
|
|
399
432
|
} catch (err) {
|
|
400
433
|
void err;
|
|
401
434
|
}
|
|
402
435
|
}
|
|
403
436
|
|
|
404
437
|
// Documentation Drift score
|
|
405
|
-
if (results.
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
0,
|
|
412
|
-
rawMetrics: results.docDrift.summary,
|
|
438
|
+
if (results[ToolName.DocDrift]) {
|
|
439
|
+
const data = results[ToolName.DocDrift];
|
|
440
|
+
toolScores.set(ToolName.DocDrift, {
|
|
441
|
+
toolName: ToolName.DocDrift,
|
|
442
|
+
score: data.summary.score || data.summary.totalScore || 0,
|
|
443
|
+
rawMetrics: data.summary,
|
|
413
444
|
factors: [],
|
|
414
|
-
recommendations: (
|
|
445
|
+
recommendations: (data.summary.recommendations || []).map(
|
|
415
446
|
(action: string) => ({
|
|
416
447
|
action,
|
|
417
448
|
estimatedImpact: 5,
|
|
@@ -422,36 +453,38 @@ export async function scoreUnified(
|
|
|
422
453
|
}
|
|
423
454
|
|
|
424
455
|
// Dependency Health score
|
|
425
|
-
if (results.
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
456
|
+
if (results[ToolName.DependencyHealth]) {
|
|
457
|
+
const data = results[ToolName.DependencyHealth];
|
|
458
|
+
toolScores.set(ToolName.DependencyHealth, {
|
|
459
|
+
toolName: ToolName.DependencyHealth,
|
|
460
|
+
score: data.summary.score || 0,
|
|
461
|
+
rawMetrics: data.summary,
|
|
430
462
|
factors: [],
|
|
431
|
-
recommendations: (
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
463
|
+
recommendations: (data.summary.recommendations || []).map(
|
|
464
|
+
(action: string) => ({
|
|
465
|
+
action,
|
|
466
|
+
estimatedImpact: 5,
|
|
467
|
+
priority: 'medium',
|
|
468
|
+
})
|
|
469
|
+
),
|
|
438
470
|
});
|
|
439
471
|
}
|
|
440
472
|
|
|
441
473
|
// Change Amplification score
|
|
442
|
-
if (results.
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
474
|
+
if (results[ToolName.ChangeAmplification]) {
|
|
475
|
+
const data = results[ToolName.ChangeAmplification];
|
|
476
|
+
toolScores.set(ToolName.ChangeAmplification, {
|
|
477
|
+
toolName: ToolName.ChangeAmplification,
|
|
478
|
+
score: data.summary.score || 0,
|
|
479
|
+
rawMetrics: data.summary,
|
|
447
480
|
factors: [],
|
|
448
|
-
recommendations: (
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
481
|
+
recommendations: (data.summary.recommendations || []).map(
|
|
482
|
+
(action: string) => ({
|
|
483
|
+
action,
|
|
484
|
+
estimatedImpact: 5,
|
|
485
|
+
priority: 'medium',
|
|
486
|
+
})
|
|
487
|
+
),
|
|
455
488
|
});
|
|
456
489
|
}
|
|
457
490
|
|
|
@@ -482,40 +515,40 @@ export function generateUnifiedSummary(result: UnifiedAnalysisResult): string {
|
|
|
482
515
|
output += ` Total issues found: ${summary.totalIssues}\n`;
|
|
483
516
|
output += ` Execution time: ${(summary.executionTime / 1000).toFixed(2)}s\n\n`;
|
|
484
517
|
|
|
485
|
-
if (result.
|
|
486
|
-
output += `๐ Pattern Analysis: ${result.
|
|
518
|
+
if (result[ToolName.PatternDetect]) {
|
|
519
|
+
output += `๐ Pattern Analysis: ${result[ToolName.PatternDetect].results.length} issues\n`;
|
|
487
520
|
}
|
|
488
521
|
|
|
489
|
-
if (result.
|
|
490
|
-
output += `๐ง Context Analysis: ${result.
|
|
522
|
+
if (result[ToolName.ContextAnalyzer]) {
|
|
523
|
+
output += `๐ง Context Analysis: ${result[ToolName.ContextAnalyzer].results.length} issues\n`;
|
|
491
524
|
}
|
|
492
525
|
|
|
493
|
-
if (result.
|
|
494
|
-
output += `๐ท๏ธ Consistency Analysis: ${result.
|
|
526
|
+
if (result[ToolName.NamingConsistency]) {
|
|
527
|
+
output += `๐ท๏ธ Consistency Analysis: ${result[ToolName.NamingConsistency].summary.totalIssues} issues\n`;
|
|
495
528
|
}
|
|
496
529
|
|
|
497
|
-
if (result.
|
|
498
|
-
output += `๐ Doc Drift Analysis: ${result.
|
|
530
|
+
if (result[ToolName.DocDrift]) {
|
|
531
|
+
output += `๐ Doc Drift Analysis: ${result[ToolName.DocDrift].results?.length || 0} issues\n`;
|
|
499
532
|
}
|
|
500
533
|
|
|
501
|
-
if (result.
|
|
502
|
-
output += `๐ฆ Dependency Health: ${result.
|
|
534
|
+
if (result[ToolName.DependencyHealth]) {
|
|
535
|
+
output += `๐ฆ Dependency Health: ${result[ToolName.DependencyHealth].results?.length || 0} issues\n`;
|
|
503
536
|
}
|
|
504
537
|
|
|
505
|
-
if (result.
|
|
506
|
-
output += `๐ง AI Signal Clarity: ${result.
|
|
538
|
+
if (result[ToolName.AiSignalClarity]) {
|
|
539
|
+
output += `๐ง AI Signal Clarity: ${result[ToolName.AiSignalClarity].summary?.totalSignals || 0} signals\n`;
|
|
507
540
|
}
|
|
508
541
|
|
|
509
|
-
if (result.
|
|
510
|
-
output += `๐งญ Agent Grounding: ${result.
|
|
542
|
+
if (result[ToolName.AgentGrounding]) {
|
|
543
|
+
output += `๐งญ Agent Grounding: ${result[ToolName.AgentGrounding].results?.length || 0} issues\n`;
|
|
511
544
|
}
|
|
512
545
|
|
|
513
|
-
if (result.
|
|
514
|
-
output += `๐งช Testability Index: ${result.
|
|
546
|
+
if (result[ToolName.TestabilityIndex]) {
|
|
547
|
+
output += `๐งช Testability Index: ${result[ToolName.TestabilityIndex].results?.length || 0} issues\n`;
|
|
515
548
|
}
|
|
516
549
|
|
|
517
|
-
if (result.
|
|
518
|
-
output += `๐ฅ Change Amplification: ${result.
|
|
550
|
+
if (result[ToolName.ChangeAmplification]) {
|
|
551
|
+
output += `๐ฅ Change Amplification: ${result[ToolName.ChangeAmplification].summary?.totalIssues || 0} cascading risks\n`;
|
|
519
552
|
}
|
|
520
553
|
|
|
521
554
|
return output;
|