@skill-map/cli 0.24.5 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/tutorial/sm-master.md +457 -0
- package/dist/cli/tutorial/sm-tutorial.md +260 -214
- package/dist/cli.js +97 -60
- package/dist/cli.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/kernel/index.js +1 -1
- package/dist/kernel/index.js.map +1 -1
- package/dist/ui/{chunk-5RHOYCWS.js → chunk-N5FAET6D.js} +3 -3
- package/dist/ui/index.html +1 -1
- package/dist/ui/{main-PNXPQAO6.js → main-QPX4WBVF.js} +1 -1
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -4614,8 +4614,8 @@ async function saveUpdateCheckCache(db, cache) {
|
|
|
4614
4614
|
var SORT_BY_COLUMNS = /* @__PURE__ */ new Set([
|
|
4615
4615
|
"path",
|
|
4616
4616
|
"kind",
|
|
4617
|
-
"
|
|
4618
|
-
"
|
|
4617
|
+
"tokens_total",
|
|
4618
|
+
"tokensTotal",
|
|
4619
4619
|
"links_out_count",
|
|
4620
4620
|
"linksOutCount",
|
|
4621
4621
|
"links_in_count",
|
|
@@ -4626,7 +4626,7 @@ var SORT_BY_COLUMNS = /* @__PURE__ */ new Set([
|
|
|
4626
4626
|
var SORT_BY_DEFAULT_DIRECTION = {
|
|
4627
4627
|
path: "asc",
|
|
4628
4628
|
kind: "asc",
|
|
4629
|
-
|
|
4629
|
+
tokensTotal: "desc",
|
|
4630
4630
|
linksOutCount: "desc",
|
|
4631
4631
|
linksInCount: "desc",
|
|
4632
4632
|
externalRefsCount: "desc"
|
|
@@ -5747,7 +5747,7 @@ var UPDATE_CHECK_TEXTS = {
|
|
|
5747
5747
|
// package.json
|
|
5748
5748
|
var package_default = {
|
|
5749
5749
|
name: "@skill-map/cli",
|
|
5750
|
-
version: "0.
|
|
5750
|
+
version: "0.25.0",
|
|
5751
5751
|
description: "skill-map reference implementation \u2014 kernel + CLI + adapters.",
|
|
5752
5752
|
license: "MIT",
|
|
5753
5753
|
type: "module",
|
|
@@ -15209,7 +15209,7 @@ var LIST_TEXTS = {
|
|
|
15209
15209
|
tableHeaderIn: "IN",
|
|
15210
15210
|
tableHeaderExt: "EXT",
|
|
15211
15211
|
tableHeaderIssues: "ISSUES",
|
|
15212
|
-
|
|
15212
|
+
tableHeaderTokens: "TOKENS",
|
|
15213
15213
|
/** Footer line: count of rendered nodes (`3 nodes` / `1 node`). */
|
|
15214
15214
|
tableFooterCount: "{{count}} {{noun}}\n",
|
|
15215
15215
|
tableFooterNounSingular: "node",
|
|
@@ -15222,7 +15222,7 @@ var LIST_TEXTS = {
|
|
|
15222
15222
|
var SORT_BY = {
|
|
15223
15223
|
path: { column: "path", direction: "asc" },
|
|
15224
15224
|
kind: { column: "kind", direction: "asc" },
|
|
15225
|
-
|
|
15225
|
+
tokens_total: { column: "tokensTotal", direction: "desc" },
|
|
15226
15226
|
links_out_count: { column: "linksOutCount", direction: "desc" },
|
|
15227
15227
|
links_in_count: { column: "linksInCount", direction: "desc" },
|
|
15228
15228
|
external_refs_count: { column: "externalRefsCount", direction: "desc" }
|
|
@@ -15241,7 +15241,7 @@ var ListCommand = class extends SmCommand {
|
|
|
15241
15241
|
and sidecar.annotations.tags by default; --tag-source author|user
|
|
15242
15242
|
narrows to one side).
|
|
15243
15243
|
|
|
15244
|
-
--sort-by accepts: path, kind,
|
|
15244
|
+
--sort-by accepts: path, kind, tokens_total, links_out_count,
|
|
15245
15245
|
links_in_count, external_refs_count. Default: path. --limit N caps
|
|
15246
15246
|
the result; default is no limit.
|
|
15247
15247
|
|
|
@@ -15250,7 +15250,7 @@ var ListCommand = class extends SmCommand {
|
|
|
15250
15250
|
examples: [
|
|
15251
15251
|
["List every node", "$0 list"],
|
|
15252
15252
|
["List only agents", "$0 list --kind agent"],
|
|
15253
|
-
["Top 5 by total
|
|
15253
|
+
["Top 5 by total tokens", "$0 list --sort-by tokens_total --limit 5"],
|
|
15254
15254
|
["Only nodes with issues, machine-readable", "$0 list --issue --json"],
|
|
15255
15255
|
["Filter by tag (author or user surfaces)", "$0 list --tag urgent"],
|
|
15256
15256
|
["Filter by user-only tag", "$0 list --tag wip --tag-source user"]
|
|
@@ -15393,7 +15393,7 @@ function renderTable2(nodes, issuesByNode, ansi) {
|
|
|
15393
15393
|
in: n.linksInCount,
|
|
15394
15394
|
ext: n.externalRefsCount,
|
|
15395
15395
|
issues: issuesByNode.get(n.path) ?? 0,
|
|
15396
|
-
|
|
15396
|
+
tokens: n.tokens?.total ?? null
|
|
15397
15397
|
}));
|
|
15398
15398
|
const widths = computeWidths(rows);
|
|
15399
15399
|
const lines = [];
|
|
@@ -15421,9 +15421,12 @@ function computeWidths(rows) {
|
|
|
15421
15421
|
in: Math.max(headerLen(LIST_TEXTS.tableHeaderIn), ...rows.map((r) => String(r.in).length)),
|
|
15422
15422
|
ext: Math.max(headerLen(LIST_TEXTS.tableHeaderExt), ...rows.map((r) => String(r.ext).length)),
|
|
15423
15423
|
issues: Math.max(headerLen(LIST_TEXTS.tableHeaderIssues), ...rows.map((r) => String(r.issues).length)),
|
|
15424
|
-
|
|
15424
|
+
tokens: Math.max(headerLen(LIST_TEXTS.tableHeaderTokens), ...rows.map((r) => formatTokens(r.tokens).length))
|
|
15425
15425
|
};
|
|
15426
15426
|
}
|
|
15427
|
+
function formatTokens(value) {
|
|
15428
|
+
return value === null ? "-" : String(value);
|
|
15429
|
+
}
|
|
15427
15430
|
function clampMax(value, max) {
|
|
15428
15431
|
return value > max ? max : value;
|
|
15429
15432
|
}
|
|
@@ -15436,7 +15439,7 @@ function formatHeaderRow(w, ansi) {
|
|
|
15436
15439
|
ansi.dim(LIST_TEXTS.tableHeaderIn.padStart(w.in)),
|
|
15437
15440
|
ansi.dim(LIST_TEXTS.tableHeaderExt.padStart(w.ext)),
|
|
15438
15441
|
ansi.dim(LIST_TEXTS.tableHeaderIssues.padStart(w.issues)),
|
|
15439
|
-
ansi.dim(LIST_TEXTS.
|
|
15442
|
+
ansi.dim(LIST_TEXTS.tableHeaderTokens.padStart(w.tokens))
|
|
15440
15443
|
].join(" ");
|
|
15441
15444
|
}
|
|
15442
15445
|
function formatDataRow(r, w, ansi) {
|
|
@@ -15449,7 +15452,7 @@ function formatDataRow(r, w, ansi) {
|
|
|
15449
15452
|
String(r.in).padStart(w.in),
|
|
15450
15453
|
String(r.ext).padStart(w.ext),
|
|
15451
15454
|
issuesCol,
|
|
15452
|
-
|
|
15455
|
+
formatTokens(r.tokens).padStart(w.tokens)
|
|
15453
15456
|
].join(" ");
|
|
15454
15457
|
}
|
|
15455
15458
|
|
|
@@ -22308,7 +22311,7 @@ var SHOW_TEXTS = {
|
|
|
22308
22311
|
/** Tail appended to `nodeHeader` when provider differs from kind. */
|
|
22309
22312
|
providerSuffix: " {{label}}",
|
|
22310
22313
|
providerSuffixLabel: "provider: {{provider}}",
|
|
22311
|
-
// --- field block (Title / Description /
|
|
22314
|
+
// --- field block (Title / Description / Tokens / …) -----------------
|
|
22312
22315
|
/** Field row, label padded by the renderer to align values. */
|
|
22313
22316
|
fieldRow: " {{label}} {{value}}\n",
|
|
22314
22317
|
/** Continuation indent for multi-line values (description, etc.). */
|
|
@@ -22317,7 +22320,6 @@ var SHOW_TEXTS = {
|
|
|
22317
22320
|
fieldLabelDescription: "Description",
|
|
22318
22321
|
fieldLabelStability: "Stability",
|
|
22319
22322
|
fieldLabelVersion: "Version",
|
|
22320
|
-
fieldLabelBytes: "Bytes",
|
|
22321
22323
|
fieldLabelTokens: "Tokens",
|
|
22322
22324
|
fieldLabelExternalRefs: "External refs",
|
|
22323
22325
|
/** `{{total}} total · {{frontmatter}} frontmatter · {{body}} body`. */
|
|
@@ -22431,23 +22433,13 @@ function collectNodeFields(node) {
|
|
|
22431
22433
|
fields.push({ label: SHOW_TEXTS.fieldLabelVersion, value: sanitizeForTerminal(String(projected.version)) });
|
|
22432
22434
|
}
|
|
22433
22435
|
fields.push({
|
|
22434
|
-
label: SHOW_TEXTS.
|
|
22435
|
-
value: tx(SHOW_TEXTS.weightSplit, {
|
|
22436
|
-
total: node.
|
|
22437
|
-
frontmatter: node.
|
|
22438
|
-
body: node.
|
|
22439
|
-
})
|
|
22436
|
+
label: SHOW_TEXTS.fieldLabelTokens,
|
|
22437
|
+
value: node.tokens ? tx(SHOW_TEXTS.weightSplit, {
|
|
22438
|
+
total: node.tokens.total,
|
|
22439
|
+
frontmatter: node.tokens.frontmatter,
|
|
22440
|
+
body: node.tokens.body
|
|
22441
|
+
}) : "-"
|
|
22440
22442
|
});
|
|
22441
|
-
if (node.tokens) {
|
|
22442
|
-
fields.push({
|
|
22443
|
-
label: SHOW_TEXTS.fieldLabelTokens,
|
|
22444
|
-
value: tx(SHOW_TEXTS.weightSplit, {
|
|
22445
|
-
total: node.tokens.total,
|
|
22446
|
-
frontmatter: node.tokens.frontmatter,
|
|
22447
|
-
body: node.tokens.body
|
|
22448
|
-
})
|
|
22449
|
-
});
|
|
22450
|
-
}
|
|
22451
22443
|
fields.push({ label: SHOW_TEXTS.fieldLabelExternalRefs, value: String(node.externalRefsCount) });
|
|
22452
22444
|
return fields;
|
|
22453
22445
|
}
|
|
@@ -23291,7 +23283,7 @@ import { Command as Command37, Option as Option35 } from "clipanion";
|
|
|
23291
23283
|
|
|
23292
23284
|
// cli/i18n/tutorial.texts.ts
|
|
23293
23285
|
var TUTORIAL_TEXTS = {
|
|
23294
|
-
// Success, written to stdout after `<cwd>/
|
|
23286
|
+
// Success, written to stdout after `<cwd>/{{filename}}` is created.
|
|
23295
23287
|
// Multi-line layout: the two trigger phrases (English / Spanish) are
|
|
23296
23288
|
// indented and labelled so they're the most visible part of the
|
|
23297
23289
|
// output. The reminder above them surfaces the SKILL's language
|
|
@@ -23303,55 +23295,91 @@ var TUTORIAL_TEXTS = {
|
|
|
23303
23295
|
* `English` / `Español` labels print dim, the eye lands on the
|
|
23304
23296
|
* trigger phrases the user is going to copy / paste.
|
|
23305
23297
|
*/
|
|
23306
|
-
written: " {{glyph}}
|
|
23298
|
+
written: " {{glyph}} {{filename}} created at {{cwd}}\n\n Open Claude Code in this directory. Your first message sets\n the tutorial language for the rest of the session:\n\n {{enLabel}} run @{{filename}}\n {{esLabel}} ejecut\xE1 @{{filename}}\n",
|
|
23307
23299
|
writtenLabelEn: "English",
|
|
23308
23300
|
writtenLabelEs: "Espa\xF1ol",
|
|
23309
|
-
// Refusal, `
|
|
23301
|
+
// Refusal, `{{filename}}` already exists and `--force` was not set.
|
|
23310
23302
|
// Goes to stderr, exit code 2 (operational error per spec § Exit codes).
|
|
23311
23303
|
// Mirrors the success body shape: glyph + headline, then a dim hint
|
|
23312
23304
|
// line spelling the fix.
|
|
23313
|
-
alreadyExists: "{{glyph}}
|
|
23305
|
+
alreadyExists: "{{glyph}} {{filename}} already exists at {{cwd}}\n {{hint}}\n",
|
|
23314
23306
|
alreadyExistsHint: "Pass `--force` to overwrite.",
|
|
23307
|
+
// Invalid `variant` positional argument. Goes to stderr, exit code 2.
|
|
23308
|
+
// Mirrors `alreadyExists`: glyph + headline + dim hint enumerating the
|
|
23309
|
+
// valid values.
|
|
23310
|
+
invalidVariant: "{{glyph}} sm tutorial: unknown variant '{{variant}}'\n {{hint}}\n",
|
|
23311
|
+
invalidVariantHint: "Valid values: tutorial (default), master.",
|
|
23315
23312
|
// I/O failure on write or on reading the bundled SKILL source.
|
|
23316
|
-
writeFailed: "{{glyph}} sm tutorial: failed to write
|
|
23317
|
-
sourceMissing: "{{glyph}} sm tutorial: could not read the bundled tutorial (
|
|
23313
|
+
writeFailed: "{{glyph}} sm tutorial: failed to write {{filename}}: {{message}}\n",
|
|
23314
|
+
sourceMissing: "{{glyph}} sm tutorial: could not read the bundled tutorial ({{filename}}) from the install.\n {{hint}}\n",
|
|
23318
23315
|
sourceMissingHint: "Reinstall @skill-map/cli or report the bug."
|
|
23319
23316
|
};
|
|
23320
23317
|
|
|
23321
23318
|
// cli/commands/tutorial.ts
|
|
23322
|
-
var
|
|
23319
|
+
var VALID_VARIANTS = ["tutorial", "master"];
|
|
23320
|
+
var DEFAULT_VARIANT = "tutorial";
|
|
23321
|
+
var VARIANT_SPECS = {
|
|
23322
|
+
tutorial: {
|
|
23323
|
+
filename: "sm-tutorial.md",
|
|
23324
|
+
sourcePath: ".claude/skills/sm-tutorial/SKILL.md",
|
|
23325
|
+
bundledName: "sm-tutorial.md"
|
|
23326
|
+
},
|
|
23327
|
+
master: {
|
|
23328
|
+
filename: "sm-master.md",
|
|
23329
|
+
sourcePath: ".claude/skills/sm-master/SKILL.md",
|
|
23330
|
+
bundledName: "sm-master.md"
|
|
23331
|
+
}
|
|
23332
|
+
};
|
|
23323
23333
|
var TutorialCommand = class extends SmCommand {
|
|
23324
23334
|
static paths = [["tutorial"]];
|
|
23325
23335
|
static usage = Command37.Usage({
|
|
23326
23336
|
category: "Setup",
|
|
23327
|
-
description: "Materialize
|
|
23337
|
+
description: "Materialize an interactive tester tutorial (sm-tutorial.md or sm-master.md) in the current directory.",
|
|
23328
23338
|
details: `
|
|
23329
|
-
Drops the canonical SKILL.md content as ./sm-tutorial.md
|
|
23330
|
-
|
|
23331
|
-
|
|
23332
|
-
|
|
23339
|
+
Drops the canonical SKILL.md content as ./sm-tutorial.md (default)
|
|
23340
|
+
or ./sm-master.md (when invoked as \`sm tutorial master\`) so a
|
|
23341
|
+
tester can open Claude Code in the cwd and load the file as a
|
|
23342
|
+
skill by typing "ejecut\xE1 @sm-tutorial.md" (or "@sm-master.md").
|
|
23343
|
+
Top-level only; no subdirectory is created.
|
|
23333
23344
|
|
|
23334
23345
|
Does NOT require an initialized .skill-map/ project. Refuses to
|
|
23335
|
-
overwrite
|
|
23346
|
+
overwrite the target file unless --force is passed. Valid values
|
|
23347
|
+
for the positional argument are: tutorial (default), master.
|
|
23336
23348
|
`,
|
|
23337
23349
|
examples: [
|
|
23338
|
-
["Materialize the tutorial in the cwd", "$0 tutorial"],
|
|
23339
|
-
["
|
|
23350
|
+
["Materialize the basic tutorial in the cwd", "$0 tutorial"],
|
|
23351
|
+
["Materialize the advanced tutorial in the cwd", "$0 tutorial master"],
|
|
23352
|
+
["Overwrite an existing target file", "$0 tutorial --force"]
|
|
23340
23353
|
]
|
|
23341
23354
|
});
|
|
23355
|
+
variant = Option35.String({ required: false });
|
|
23342
23356
|
force = Option35.Boolean("--force", false, {
|
|
23343
|
-
description: "Overwrite an existing
|
|
23357
|
+
description: "Overwrite an existing target file without prompting."
|
|
23344
23358
|
});
|
|
23345
23359
|
async run() {
|
|
23346
23360
|
const ctx = defaultRuntimeContext();
|
|
23347
|
-
const target = join17(ctx.cwd, SM_TUTORIAL_FILENAME);
|
|
23348
23361
|
const stderr = this.context.stderr;
|
|
23349
23362
|
const stderrAnsi = this.ansiFor("stderr");
|
|
23350
23363
|
const errGlyph = stderrAnsi.red("\u2715");
|
|
23364
|
+
const rawVariant = this.variant;
|
|
23365
|
+
if (rawVariant !== void 0 && !isTutorialVariant(rawVariant)) {
|
|
23366
|
+
this.printer.error(
|
|
23367
|
+
tx(TUTORIAL_TEXTS.invalidVariant, {
|
|
23368
|
+
glyph: errGlyph,
|
|
23369
|
+
variant: rawVariant,
|
|
23370
|
+
hint: stderrAnsi.dim(TUTORIAL_TEXTS.invalidVariantHint)
|
|
23371
|
+
})
|
|
23372
|
+
);
|
|
23373
|
+
return ExitCode.Error;
|
|
23374
|
+
}
|
|
23375
|
+
const variant = rawVariant ?? DEFAULT_VARIANT;
|
|
23376
|
+
const spec = VARIANT_SPECS[variant];
|
|
23377
|
+
const target = join17(ctx.cwd, spec.filename);
|
|
23351
23378
|
if (await pathExists(target) && !this.force) {
|
|
23352
23379
|
this.printer.error(
|
|
23353
23380
|
tx(TUTORIAL_TEXTS.alreadyExists, {
|
|
23354
23381
|
glyph: errGlyph,
|
|
23382
|
+
filename: spec.filename,
|
|
23355
23383
|
cwd: stderrAnsi.dim(displayCwd(ctx.cwd)),
|
|
23356
23384
|
hint: stderrAnsi.dim(TUTORIAL_TEXTS.alreadyExistsHint)
|
|
23357
23385
|
})
|
|
@@ -23360,11 +23388,12 @@ var TutorialCommand = class extends SmCommand {
|
|
|
23360
23388
|
}
|
|
23361
23389
|
let body;
|
|
23362
23390
|
try {
|
|
23363
|
-
body = loadBundledTutorialText();
|
|
23391
|
+
body = loadBundledTutorialText(variant);
|
|
23364
23392
|
} catch {
|
|
23365
23393
|
this.printer.error(
|
|
23366
23394
|
tx(TUTORIAL_TEXTS.sourceMissing, {
|
|
23367
23395
|
glyph: errGlyph,
|
|
23396
|
+
filename: spec.filename,
|
|
23368
23397
|
hint: stderrAnsi.dim(TUTORIAL_TEXTS.sourceMissingHint)
|
|
23369
23398
|
})
|
|
23370
23399
|
);
|
|
@@ -23376,6 +23405,7 @@ var TutorialCommand = class extends SmCommand {
|
|
|
23376
23405
|
this.printer.error(
|
|
23377
23406
|
tx(TUTORIAL_TEXTS.writeFailed, {
|
|
23378
23407
|
glyph: errGlyph,
|
|
23408
|
+
filename: spec.filename,
|
|
23379
23409
|
message: formatErrorMessage(err)
|
|
23380
23410
|
})
|
|
23381
23411
|
);
|
|
@@ -23391,6 +23421,7 @@ var TutorialCommand = class extends SmCommand {
|
|
|
23391
23421
|
this.printer.data(
|
|
23392
23422
|
tx(TUTORIAL_TEXTS.written, {
|
|
23393
23423
|
glyph: ansi.green("\u2713"),
|
|
23424
|
+
filename: spec.filename,
|
|
23394
23425
|
cwd: ansi.dim(displayCwd(ctx.cwd)),
|
|
23395
23426
|
enLabel: ansi.dim(TUTORIAL_TEXTS.writtenLabelEn),
|
|
23396
23427
|
esLabel: ansi.dim(TUTORIAL_TEXTS.writtenLabelEs)
|
|
@@ -23399,26 +23430,32 @@ var TutorialCommand = class extends SmCommand {
|
|
|
23399
23430
|
return ExitCode.Ok;
|
|
23400
23431
|
}
|
|
23401
23432
|
};
|
|
23433
|
+
function isTutorialVariant(value) {
|
|
23434
|
+
return VALID_VARIANTS.includes(value);
|
|
23435
|
+
}
|
|
23402
23436
|
function displayCwd(cwd) {
|
|
23403
23437
|
const segments = cwd.split("/").filter((s) => s.length > 0);
|
|
23404
23438
|
if (segments.length === 0) return "./";
|
|
23405
23439
|
return `./${segments[segments.length - 1]}/`;
|
|
23406
23440
|
}
|
|
23407
|
-
var
|
|
23408
|
-
function loadBundledTutorialText() {
|
|
23409
|
-
|
|
23410
|
-
|
|
23411
|
-
|
|
23441
|
+
var cachedTutorials = /* @__PURE__ */ new Map();
|
|
23442
|
+
function loadBundledTutorialText(variant) {
|
|
23443
|
+
const cached = cachedTutorials.get(variant);
|
|
23444
|
+
if (cached !== void 0) return cached;
|
|
23445
|
+
const body = readTutorialFromDisk(variant);
|
|
23446
|
+
cachedTutorials.set(variant, body);
|
|
23447
|
+
return body;
|
|
23412
23448
|
}
|
|
23413
|
-
function readTutorialFromDisk() {
|
|
23449
|
+
function readTutorialFromDisk(variant) {
|
|
23450
|
+
const spec = VARIANT_SPECS[variant];
|
|
23414
23451
|
const here = dirname18(fileURLToPath6(import.meta.url));
|
|
23415
23452
|
const candidates = [
|
|
23416
|
-
// dev: src/cli/commands/ → repo-root .claude/skills
|
|
23417
|
-
resolve36(here, "
|
|
23418
|
-
// bundled: dist/cli.js → dist/cli/tutorial
|
|
23419
|
-
resolve36(here, "cli/tutorial
|
|
23420
|
-
// bundled fallback: any-depth → cli/tutorial
|
|
23421
|
-
resolve36(here, "../cli/tutorial
|
|
23453
|
+
// dev: src/cli/commands/ → repo-root .claude/skills/<slug>/SKILL.md
|
|
23454
|
+
resolve36(here, "../../..", spec.sourcePath),
|
|
23455
|
+
// bundled: dist/cli.js → dist/cli/tutorial/<filename> (sibling)
|
|
23456
|
+
resolve36(here, "cli/tutorial", spec.bundledName),
|
|
23457
|
+
// bundled fallback: any-depth → cli/tutorial/<filename>
|
|
23458
|
+
resolve36(here, "../cli/tutorial", spec.bundledName)
|
|
23422
23459
|
];
|
|
23423
23460
|
for (const candidate of candidates) {
|
|
23424
23461
|
if (existsSync28(candidate)) {
|