@datacore-one/cli 1.0.2 → 1.0.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/index.js +189 -36
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -8005,7 +8005,7 @@ function checkGitLfs(platform2) {
|
|
|
8005
8005
|
const installed = commandExists("git-lfs");
|
|
8006
8006
|
return {
|
|
8007
8007
|
name: "git-lfs",
|
|
8008
|
-
required:
|
|
8008
|
+
required: false,
|
|
8009
8009
|
installed,
|
|
8010
8010
|
version: installed ? getVersion("git-lfs") : undefined,
|
|
8011
8011
|
installCommand: installed ? undefined : getInstallCommand("git-lfs", platform2) ?? undefined
|
|
@@ -8650,6 +8650,48 @@ function startOperation(operation, params = {}) {
|
|
|
8650
8650
|
return new Operation(operation, params);
|
|
8651
8651
|
}
|
|
8652
8652
|
|
|
8653
|
+
// src/lib/animation.ts
|
|
8654
|
+
var c = {
|
|
8655
|
+
reset: "\x1B[0m",
|
|
8656
|
+
bright: "\x1B[1m",
|
|
8657
|
+
dim: "\x1B[2m",
|
|
8658
|
+
green: "\x1B[32m",
|
|
8659
|
+
cyan: "\x1B[36m",
|
|
8660
|
+
yellow: "\x1B[33m",
|
|
8661
|
+
magenta: "\x1B[35m",
|
|
8662
|
+
blue: "\x1B[34m",
|
|
8663
|
+
gray: "\x1B[90m"
|
|
8664
|
+
};
|
|
8665
|
+
var BANNER = `
|
|
8666
|
+
${c.cyan}${c.bright}
|
|
8667
|
+
██████╗ █████╗ ████████╗ █████╗ ██████╗ ██████╗ ██████╗ ███████╗
|
|
8668
|
+
██╔══██╗██╔══██╗╚══██╔══╝██╔══██╗██╔════╝██╔═══██╗██╔══██╗██╔════╝
|
|
8669
|
+
██║ ██║███████║ ██║ ███████║██║ ██║ ██║██████╔╝█████╗
|
|
8670
|
+
██║ ██║██╔══██║ ██║ ██╔══██║██║ ██║ ██║██╔══██╗██╔══╝
|
|
8671
|
+
██████╔╝██║ ██║ ██║ ██║ ██║╚██████╗╚██████╔╝██║ ██║███████╗
|
|
8672
|
+
╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝
|
|
8673
|
+
${c.reset}${c.dim} AI-Powered Second Brain ${c.reset}
|
|
8674
|
+
`;
|
|
8675
|
+
var INIT_COMPLETE = `
|
|
8676
|
+
${c.green}${c.bright}
|
|
8677
|
+
╔═══════════════════════════════════════════════════════════════╗
|
|
8678
|
+
║ ║
|
|
8679
|
+
║ ${c.reset}${c.green}█████╗ ██████╗████████╗██╗██╗ ██╗███████╗${c.bright} ║
|
|
8680
|
+
║ ${c.reset}${c.green}██╔══██╗██╔════╝╚══██╔══╝██║██║ ██║██╔════╝${c.bright} ║
|
|
8681
|
+
║ ${c.reset}${c.green}███████║██║ ██║ ██║██║ ██║█████╗${c.bright} ║
|
|
8682
|
+
║ ${c.reset}${c.green}██╔══██║██║ ██║ ██║╚██╗ ██╔╝██╔══╝${c.bright} ║
|
|
8683
|
+
║ ${c.reset}${c.green}██║ ██║╚██████╗ ██║ ██║ ╚████╔╝ ███████╗${c.bright} ║
|
|
8684
|
+
║ ${c.reset}${c.green}╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═══╝ ╚══════╝${c.bright} ║
|
|
8685
|
+
║ ║
|
|
8686
|
+
╚═══════════════════════════════════════════════════════════════╝
|
|
8687
|
+
${c.reset}
|
|
8688
|
+
`;
|
|
8689
|
+
function section(title) {
|
|
8690
|
+
console.log();
|
|
8691
|
+
console.log(`${c.cyan}${c.bright}▸ ${title}${c.reset}`);
|
|
8692
|
+
console.log(`${c.dim}${"─".repeat(50)}${c.reset}`);
|
|
8693
|
+
}
|
|
8694
|
+
|
|
8653
8695
|
// src/lib/init.ts
|
|
8654
8696
|
var DATA_DIR4 = join6(process.env.HOME || "~", "Data");
|
|
8655
8697
|
var DATACORE_DIR = join6(DATA_DIR4, ".datacore");
|
|
@@ -8658,6 +8700,7 @@ function isInitialized() {
|
|
|
8658
8700
|
}
|
|
8659
8701
|
async function initDatacore(options = {}) {
|
|
8660
8702
|
const { nonInteractive = false, skipChecks = false, stream = false } = options;
|
|
8703
|
+
const isTTY = stream && process.stdout.isTTY;
|
|
8661
8704
|
const result = {
|
|
8662
8705
|
success: false,
|
|
8663
8706
|
created: [],
|
|
@@ -8665,18 +8708,53 @@ async function initDatacore(options = {}) {
|
|
|
8665
8708
|
errors: [],
|
|
8666
8709
|
nextSteps: []
|
|
8667
8710
|
};
|
|
8668
|
-
const log = (msg) => {
|
|
8669
|
-
if (stream)
|
|
8670
|
-
console.log(msg);
|
|
8671
|
-
};
|
|
8672
8711
|
const op = startOperation("init", { options });
|
|
8673
8712
|
op.start();
|
|
8674
8713
|
try {
|
|
8714
|
+
if (isTTY) {
|
|
8715
|
+
console.clear();
|
|
8716
|
+
console.log(BANNER);
|
|
8717
|
+
console.log();
|
|
8718
|
+
}
|
|
8719
|
+
const TOTAL_STEPS = 6;
|
|
8675
8720
|
op.addStep("check_dependencies");
|
|
8676
8721
|
op.startStep("check_dependencies");
|
|
8677
8722
|
if (!skipChecks) {
|
|
8678
|
-
|
|
8723
|
+
if (isTTY) {
|
|
8724
|
+
section("Checking Dependencies");
|
|
8725
|
+
console.log(" \x1B[90mDatacore requires a few tools to manage your knowledge system.\x1B[0m");
|
|
8726
|
+
console.log();
|
|
8727
|
+
}
|
|
8679
8728
|
const doctor = runDoctor();
|
|
8729
|
+
const depInfo = {
|
|
8730
|
+
git: "Version control for your knowledge repos",
|
|
8731
|
+
"git-lfs": "Large file support (PDFs, images, videos)",
|
|
8732
|
+
node: "Runtime for CLI tools and automation",
|
|
8733
|
+
python: "Powers AI agents and data processing",
|
|
8734
|
+
claude: "Claude Code AI assistant integration"
|
|
8735
|
+
};
|
|
8736
|
+
if (isTTY) {
|
|
8737
|
+
for (const dep of doctor.dependencies) {
|
|
8738
|
+
const info2 = depInfo[dep.name] || "";
|
|
8739
|
+
if (dep.installed) {
|
|
8740
|
+
console.log(` \x1B[32m✓\x1B[0m ${dep.name} ${dep.version ? `\x1B[90m(${dep.version})\x1B[0m` : ""}`);
|
|
8741
|
+
console.log(` \x1B[90m${info2}\x1B[0m`);
|
|
8742
|
+
} else if (dep.required) {
|
|
8743
|
+
console.log(` \x1B[31m✗\x1B[0m ${dep.name} \x1B[31m(required)\x1B[0m`);
|
|
8744
|
+
console.log(` \x1B[90m${info2}\x1B[0m`);
|
|
8745
|
+
if (dep.installCommand) {
|
|
8746
|
+
console.log(` \x1B[33mInstall: ${dep.installCommand}\x1B[0m`);
|
|
8747
|
+
}
|
|
8748
|
+
} else {
|
|
8749
|
+
console.log(` \x1B[33m○\x1B[0m ${dep.name} \x1B[90m(optional)\x1B[0m`);
|
|
8750
|
+
console.log(` \x1B[90m${info2}\x1B[0m`);
|
|
8751
|
+
if (dep.installCommand) {
|
|
8752
|
+
console.log(` \x1B[90mInstall later: ${dep.installCommand}\x1B[0m`);
|
|
8753
|
+
}
|
|
8754
|
+
}
|
|
8755
|
+
}
|
|
8756
|
+
console.log();
|
|
8757
|
+
}
|
|
8680
8758
|
if (doctor.status === "missing_required") {
|
|
8681
8759
|
const missing = doctor.dependencies.filter((d) => d.required && !d.installed);
|
|
8682
8760
|
for (const dep of missing) {
|
|
@@ -8692,39 +8770,55 @@ async function initDatacore(options = {}) {
|
|
|
8692
8770
|
if (doctor.status === "missing_recommended") {
|
|
8693
8771
|
const missing = doctor.dependencies.filter((d) => !d.required && !d.installed);
|
|
8694
8772
|
for (const dep of missing) {
|
|
8695
|
-
result.warnings.push(`
|
|
8773
|
+
result.warnings.push(`Optional: ${dep.name} - install for full functionality`);
|
|
8696
8774
|
}
|
|
8697
8775
|
}
|
|
8698
8776
|
}
|
|
8699
8777
|
op.completeStep("check_dependencies");
|
|
8700
8778
|
op.addStep("create_data_dir");
|
|
8701
8779
|
op.startStep("create_data_dir");
|
|
8780
|
+
if (isTTY) {
|
|
8781
|
+
section("Setting Up ~/Data");
|
|
8782
|
+
console.log(" \x1B[90mThis is your central knowledge directory. Everything lives here.\x1B[0m");
|
|
8783
|
+
console.log();
|
|
8784
|
+
}
|
|
8702
8785
|
if (!existsSync6(DATA_DIR4)) {
|
|
8703
|
-
log(`Creating ${DATA_DIR4}...`);
|
|
8704
8786
|
mkdirSync4(DATA_DIR4, { recursive: true });
|
|
8705
8787
|
result.created.push(DATA_DIR4);
|
|
8788
|
+
if (isTTY)
|
|
8789
|
+
console.log(` \x1B[32m✓\x1B[0m Created ${DATA_DIR4}`);
|
|
8790
|
+
} else if (isTTY) {
|
|
8791
|
+
console.log(` \x1B[32m✓\x1B[0m Found existing ${DATA_DIR4}`);
|
|
8706
8792
|
}
|
|
8707
8793
|
op.completeStep("create_data_dir");
|
|
8708
8794
|
op.addStep("create_datacore_dir");
|
|
8709
8795
|
op.startStep("create_datacore_dir");
|
|
8796
|
+
if (isTTY) {
|
|
8797
|
+
console.log();
|
|
8798
|
+
section("Creating .datacore");
|
|
8799
|
+
console.log(" \x1B[90mSystem configuration, agents, and modules live here.\x1B[0m");
|
|
8800
|
+
console.log();
|
|
8801
|
+
}
|
|
8710
8802
|
if (!existsSync6(DATACORE_DIR)) {
|
|
8711
|
-
log("Creating .datacore configuration...");
|
|
8712
8803
|
const dirs = [
|
|
8713
|
-
"",
|
|
8714
|
-
"commands",
|
|
8715
|
-
"agents",
|
|
8716
|
-
"modules",
|
|
8717
|
-
"specs",
|
|
8718
|
-
"lib",
|
|
8719
|
-
"env",
|
|
8720
|
-
"state",
|
|
8721
|
-
"registry"
|
|
8804
|
+
{ path: "", desc: "Core configuration" },
|
|
8805
|
+
{ path: "commands", desc: "Slash commands (e.g., /today, /sync)" },
|
|
8806
|
+
{ path: "agents", desc: "AI agents for task automation" },
|
|
8807
|
+
{ path: "modules", desc: "Optional extensions (CRM, meetings, etc.)" },
|
|
8808
|
+
{ path: "specs", desc: "System documentation" },
|
|
8809
|
+
{ path: "lib", desc: "Shared utilities" },
|
|
8810
|
+
{ path: "env", desc: "Secrets and API keys (gitignored)" },
|
|
8811
|
+
{ path: "state", desc: "Runtime state (gitignored)" },
|
|
8812
|
+
{ path: "registry", desc: "Agent and command discovery" }
|
|
8722
8813
|
];
|
|
8723
|
-
for (const dir of dirs) {
|
|
8814
|
+
for (const { path: dir, desc } of dirs) {
|
|
8724
8815
|
const path = join6(DATACORE_DIR, dir);
|
|
8725
8816
|
if (!existsSync6(path)) {
|
|
8726
8817
|
mkdirSync4(path, { recursive: true });
|
|
8727
8818
|
result.created.push(path);
|
|
8819
|
+
if (isTTY && dir) {
|
|
8820
|
+
console.log(` \x1B[32m✓\x1B[0m ${dir}/ \x1B[90m- ${desc}\x1B[0m`);
|
|
8821
|
+
}
|
|
8728
8822
|
}
|
|
8729
8823
|
}
|
|
8730
8824
|
writeFileSync4(join6(DATACORE_DIR, "settings.yaml"), `# Datacore Settings
|
|
@@ -8758,77 +8852,136 @@ agents: []
|
|
|
8758
8852
|
commands: []
|
|
8759
8853
|
`);
|
|
8760
8854
|
result.created.push(join6(DATACORE_DIR, "registry", "commands.yaml"));
|
|
8855
|
+
if (isTTY) {
|
|
8856
|
+
console.log();
|
|
8857
|
+
console.log(` \x1B[32m✓\x1B[0m Created settings.yaml`);
|
|
8858
|
+
console.log(" \x1B[90mCustomize in settings.local.yaml (gitignored)\x1B[0m");
|
|
8859
|
+
}
|
|
8860
|
+
} else if (isTTY) {
|
|
8861
|
+
console.log(` \x1B[32m✓\x1B[0m Found existing .datacore/`);
|
|
8761
8862
|
}
|
|
8762
8863
|
op.completeStep("create_datacore_dir");
|
|
8763
8864
|
op.addStep("create_personal_space");
|
|
8764
8865
|
op.startStep("create_personal_space");
|
|
8866
|
+
if (isTTY) {
|
|
8867
|
+
console.log();
|
|
8868
|
+
section("Creating Personal Space");
|
|
8869
|
+
console.log(" \x1B[90mSpaces are separate knowledge areas (personal, work, projects).\x1B[0m");
|
|
8870
|
+
console.log(" \x1B[90mEach space has its own GTD inbox, notes, and journals.\x1B[0m");
|
|
8871
|
+
console.log();
|
|
8872
|
+
}
|
|
8765
8873
|
const spaces = listSpaces();
|
|
8766
8874
|
if (spaces.length === 0) {
|
|
8767
|
-
log("Creating personal space...");
|
|
8768
8875
|
try {
|
|
8769
8876
|
const space = createSpace("personal", "personal");
|
|
8770
8877
|
result.created.push(space.path);
|
|
8878
|
+
if (isTTY) {
|
|
8879
|
+
console.log(` \x1B[32m✓\x1B[0m Created 0-personal/`);
|
|
8880
|
+
console.log(" \x1B[90morg/inbox.org - Capture tasks here\x1B[0m");
|
|
8881
|
+
console.log(" \x1B[90mnotes/ - Your knowledge base\x1B[0m");
|
|
8882
|
+
console.log(" \x1B[90mjournal/ - Daily entries\x1B[0m");
|
|
8883
|
+
}
|
|
8771
8884
|
} catch (err) {
|
|
8772
8885
|
result.warnings.push(`Could not create personal space: ${err.message}`);
|
|
8773
8886
|
}
|
|
8887
|
+
} else if (isTTY) {
|
|
8888
|
+
console.log(` \x1B[32m✓\x1B[0m Found ${spaces.length} existing space(s):`);
|
|
8889
|
+
for (const space of spaces) {
|
|
8890
|
+
console.log(` \x1B[90m${space.name}/\x1B[0m`);
|
|
8891
|
+
}
|
|
8774
8892
|
}
|
|
8775
8893
|
op.completeStep("create_personal_space");
|
|
8776
8894
|
op.addStep("create_claude_symlink");
|
|
8777
8895
|
op.startStep("create_claude_symlink");
|
|
8896
|
+
if (isTTY) {
|
|
8897
|
+
console.log();
|
|
8898
|
+
section("Linking Claude Code");
|
|
8899
|
+
console.log(" \x1B[90mClaude Code looks for .claude/ to find project context.\x1B[0m");
|
|
8900
|
+
console.log(" \x1B[90mThis symlink connects it to your Datacore configuration.\x1B[0m");
|
|
8901
|
+
console.log();
|
|
8902
|
+
}
|
|
8778
8903
|
const claudeDir = join6(DATA_DIR4, ".claude");
|
|
8779
8904
|
if (!existsSync6(claudeDir)) {
|
|
8780
|
-
log("Creating .claude symlink...");
|
|
8781
8905
|
try {
|
|
8782
8906
|
symlinkSync(DATACORE_DIR, claudeDir);
|
|
8783
8907
|
result.created.push(claudeDir);
|
|
8908
|
+
if (isTTY)
|
|
8909
|
+
console.log(` \x1B[32m✓\x1B[0m Created .claude -> .datacore symlink`);
|
|
8784
8910
|
} catch {
|
|
8785
8911
|
result.warnings.push("Could not create .claude symlink");
|
|
8912
|
+
if (isTTY)
|
|
8913
|
+
console.log(` \x1B[33m○\x1B[0m Could not create symlink (run manually if needed)`);
|
|
8786
8914
|
}
|
|
8915
|
+
} else if (isTTY) {
|
|
8916
|
+
console.log(` \x1B[32m✓\x1B[0m Found existing .claude/`);
|
|
8787
8917
|
}
|
|
8788
8918
|
op.completeStep("create_claude_symlink");
|
|
8789
8919
|
op.addStep("create_claude_md");
|
|
8790
8920
|
op.startStep("create_claude_md");
|
|
8921
|
+
if (isTTY) {
|
|
8922
|
+
console.log();
|
|
8923
|
+
section("Creating CLAUDE.md");
|
|
8924
|
+
console.log(" \x1B[90mThis file tells Claude Code about your Datacore system.\x1B[0m");
|
|
8925
|
+
console.log(" \x1B[90mIt auto-loads when you run `claude` in ~/Data.\x1B[0m");
|
|
8926
|
+
console.log();
|
|
8927
|
+
}
|
|
8791
8928
|
const claudeMd = join6(DATA_DIR4, "CLAUDE.md");
|
|
8792
8929
|
const claudeBaseMd = join6(DATA_DIR4, "CLAUDE.base.md");
|
|
8793
8930
|
if (!existsSync6(claudeMd) && !existsSync6(claudeBaseMd)) {
|
|
8794
|
-
log("Creating CLAUDE.md...");
|
|
8795
8931
|
writeFileSync4(claudeBaseMd, `# Datacore
|
|
8796
8932
|
|
|
8797
8933
|
AI-powered second brain built on GTD methodology.
|
|
8798
8934
|
|
|
8799
|
-
##
|
|
8935
|
+
## Quick Start
|
|
8800
8936
|
|
|
8801
|
-
|
|
8937
|
+
\`\`\`bash
|
|
8938
|
+
cd ~/Data && claude
|
|
8939
|
+
\`\`\`
|
|
8802
8940
|
|
|
8803
|
-
##
|
|
8941
|
+
## Commands
|
|
8804
8942
|
|
|
8805
8943
|
- \`datacore today\` - Daily briefing
|
|
8806
8944
|
- \`datacore tomorrow\` - End-of-day wrap-up
|
|
8807
8945
|
- \`datacore sync\` - Sync all repos
|
|
8808
|
-
|
|
8809
|
-
## Documentation
|
|
8810
|
-
|
|
8811
|
-
- \`datacore docs\` - Open documentation
|
|
8812
8946
|
- \`datacore doctor\` - Check system health
|
|
8813
8947
|
|
|
8814
8948
|
## Spaces
|
|
8815
8949
|
|
|
8816
8950
|
${listSpaces().map((s) => `- ${s.name}`).join(`
|
|
8817
|
-
`) || "-
|
|
8951
|
+
`) || "- 0-personal"}
|
|
8818
8952
|
|
|
8819
|
-
##
|
|
8953
|
+
## Documentation
|
|
8820
8954
|
|
|
8821
8955
|
See .datacore/specs/ for detailed documentation.
|
|
8822
8956
|
`);
|
|
8823
8957
|
result.created.push(claudeBaseMd);
|
|
8958
|
+
if (isTTY)
|
|
8959
|
+
console.log(` \x1B[32m✓\x1B[0m Created CLAUDE.base.md`);
|
|
8960
|
+
} else if (isTTY) {
|
|
8961
|
+
console.log(` \x1B[32m✓\x1B[0m Found existing CLAUDE.md`);
|
|
8824
8962
|
}
|
|
8825
8963
|
op.completeStep("create_claude_md");
|
|
8826
8964
|
result.success = true;
|
|
8827
8965
|
result.nextSteps = [
|
|
8828
|
-
"Run `datacore tour` for a guided walkthrough",
|
|
8829
8966
|
"Run `datacore doctor` to verify your setup",
|
|
8830
8967
|
"Start working: `cd ~/Data && claude`"
|
|
8831
8968
|
];
|
|
8969
|
+
if (isTTY) {
|
|
8970
|
+
console.log();
|
|
8971
|
+
console.log(INIT_COMPLETE);
|
|
8972
|
+
console.log();
|
|
8973
|
+
console.log(" \x1B[1mNext steps:\x1B[0m");
|
|
8974
|
+
console.log();
|
|
8975
|
+
console.log(" 1. \x1B[36mcd ~/Data && claude\x1B[0m");
|
|
8976
|
+
console.log(" \x1B[90mStart using your second brain with AI assistance\x1B[0m");
|
|
8977
|
+
console.log();
|
|
8978
|
+
console.log(" 2. \x1B[36mdatacore doctor\x1B[0m");
|
|
8979
|
+
console.log(" \x1B[90mVerify everything is set up correctly\x1B[0m");
|
|
8980
|
+
console.log();
|
|
8981
|
+
console.log(" 3. Add tasks to \x1B[36m0-personal/org/inbox.org\x1B[0m");
|
|
8982
|
+
console.log(" \x1B[90mYour GTD capture inbox - process daily\x1B[0m");
|
|
8983
|
+
console.log();
|
|
8984
|
+
}
|
|
8832
8985
|
op.complete();
|
|
8833
8986
|
} catch (err) {
|
|
8834
8987
|
result.errors.push(err.message);
|
|
@@ -8980,7 +9133,7 @@ import { execSync as execSync5 } from "child_process";
|
|
|
8980
9133
|
import { join as join8 } from "path";
|
|
8981
9134
|
var DATA_DIR6 = join8(process.env.HOME || "~", "Data");
|
|
8982
9135
|
var LOCK_FILE = join8(DATA_DIR6, "datacore.lock.yaml");
|
|
8983
|
-
var CLI_VERSION = "1.0.
|
|
9136
|
+
var CLI_VERSION = "1.0.4";
|
|
8984
9137
|
function getGitInfo(path) {
|
|
8985
9138
|
if (!existsSync8(join8(path, ".git"))) {
|
|
8986
9139
|
return {};
|
|
@@ -9199,7 +9352,7 @@ function restoreFromSnapshot(snapshot, options = {}) {
|
|
|
9199
9352
|
}
|
|
9200
9353
|
|
|
9201
9354
|
// src/index.ts
|
|
9202
|
-
var VERSION = "1.0.
|
|
9355
|
+
var VERSION = "1.0.4";
|
|
9203
9356
|
var args = process.argv.slice(2);
|
|
9204
9357
|
var parsed = parseArgs(args);
|
|
9205
9358
|
async function handleMeta(command, cmdArgs, flags, format) {
|
|
@@ -9247,8 +9400,8 @@ async function handleMeta(command, cmdArgs, flags, format) {
|
|
|
9247
9400
|
}
|
|
9248
9401
|
console.log();
|
|
9249
9402
|
console.log("Next steps:");
|
|
9250
|
-
for (const
|
|
9251
|
-
console.log(` → ${
|
|
9403
|
+
for (const step2 of result.nextSteps) {
|
|
9404
|
+
console.log(` → ${step2}`);
|
|
9252
9405
|
}
|
|
9253
9406
|
} else {
|
|
9254
9407
|
error("Initialization failed");
|