kimiflare 0.87.0 → 0.88.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.
- package/README.md +6 -6
- package/dist/index.js +61 -21
- package/dist/index.js.map +1 -1
- package/dist/sdk/index.d.ts +1 -1
- package/dist/sdk/index.js +15 -6
- package/dist/sdk/index.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -8,11 +8,11 @@
|
|
|
8
8
|
<a href="https://github.com/sinameraji/kimiflare/blob/main/LICENSE"><img src="https://img.shields.io/github/license/sinameraji/kimiflare?style=flat-square&color=2ea44f" alt="license"></a>
|
|
9
9
|
<img src="https://img.shields.io/badge/node-%3E%3D20-339933?style=flat-square&logo=nodedotjs&logoColor=white" alt="Node.js >= 20">
|
|
10
10
|
<img src="https://img.shields.io/badge/typescript-5.7-3178c6?style=flat-square&logo=typescript&logoColor=white" alt="TypeScript">
|
|
11
|
-
<a href="https://developers.cloudflare.com/workers-ai/models/kimi-k2"><img src="https://img.shields.io/badge/powered%20by-Kimi%20K2.
|
|
11
|
+
<a href="https://developers.cloudflare.com/workers-ai/models/kimi-k2"><img src="https://img.shields.io/badge/powered%20by-Kimi%20K2.7-f59e0b?style=flat-square" alt="Powered by Kimi K2.7"></a>
|
|
12
12
|
</p>
|
|
13
13
|
|
|
14
14
|
<p align="center">
|
|
15
|
-
<strong>A terminal coding agent powered by <a href="https://developers.cloudflare.com/workers-ai/models/kimi-k2">Kimi K2.
|
|
15
|
+
<strong>A terminal coding agent powered by <a href="https://developers.cloudflare.com/workers-ai/models/kimi-k2">Kimi K2.7</a> on <a href="https://developers.cloudflare.com/workers-ai/">Cloudflare Workers AI</a> — with optional routing through your own <a href="https://developers.cloudflare.com/ai-gateway/">AI Gateway</a> for first-class observability, caching, and authoritative cost.</strong><br>
|
|
16
16
|
All on your Cloudflare account.
|
|
17
17
|
</p>
|
|
18
18
|
|
|
@@ -93,11 +93,11 @@ Once configured, `/cost` shows the Gateway-confirmed totals, cache hit ratio, pe
|
|
|
93
93
|
|
|
94
94
|
### Model
|
|
95
95
|
|
|
96
|
-
KimiFlare runs on **Kimi K2.
|
|
96
|
+
KimiFlare runs on **Kimi K2.7** via Cloudflare Workers AI — no API key needed beyond your Cloudflare token:
|
|
97
97
|
|
|
98
|
-
- `@cf/moonshotai/kimi-k2.
|
|
98
|
+
- `@cf/moonshotai/kimi-k2.7-code` — 262k context, reasoning, tools, vision
|
|
99
99
|
|
|
100
|
-
`@cf/moonshotai/kimi-k2.5`
|
|
100
|
+
`@cf/moonshotai/kimi-k2.6` and `@cf/moonshotai/kimi-k2.5` are also available.
|
|
101
101
|
|
|
102
102
|
### One-shot mode
|
|
103
103
|
|
|
@@ -120,7 +120,7 @@ const { session } = await createAgentSession({
|
|
|
120
120
|
accountId: process.env.CLOUDFLARE_ACCOUNT_ID,
|
|
121
121
|
apiToken: process.env.CLOUDFLARE_API_TOKEN,
|
|
122
122
|
aiGatewayId: process.env.CLOUDFLARE_AI_GATEWAY_ID,
|
|
123
|
-
model: "@cf/moonshotai/kimi-k2.
|
|
123
|
+
model: "@cf/moonshotai/kimi-k2.7-code",
|
|
124
124
|
},
|
|
125
125
|
});
|
|
126
126
|
|
package/dist/index.js
CHANGED
|
@@ -295,7 +295,7 @@ var init_config = __esm({
|
|
|
295
295
|
"src/config.ts"() {
|
|
296
296
|
"use strict";
|
|
297
297
|
EFFORTS = ["low", "medium", "high"];
|
|
298
|
-
DEFAULT_MODEL = "@cf/moonshotai/kimi-k2.
|
|
298
|
+
DEFAULT_MODEL = "@cf/moonshotai/kimi-k2.7-code";
|
|
299
299
|
DEFAULT_REASONING_EFFORT = "medium";
|
|
300
300
|
}
|
|
301
301
|
});
|
|
@@ -709,7 +709,7 @@ async function* deployForTui() {
|
|
|
709
709
|
throw err;
|
|
710
710
|
}
|
|
711
711
|
const nextCfg = {
|
|
712
|
-
...cfg ?? { accountId: "", apiToken: "", model: "@cf/moonshotai/kimi-k2.
|
|
712
|
+
...cfg ?? { accountId: "", apiToken: "", model: "@cf/moonshotai/kimi-k2.7-code" },
|
|
713
713
|
remoteWorkerUrl: workerUrl,
|
|
714
714
|
remoteAuthSecret: authSecret
|
|
715
715
|
};
|
|
@@ -1413,6 +1413,15 @@ var init_registry = __esm({
|
|
|
1413
1413
|
]);
|
|
1414
1414
|
SEED = [
|
|
1415
1415
|
// ── Kimi models (Cloudflare Workers AI, native to kimiflare) ──────────────
|
|
1416
|
+
{
|
|
1417
|
+
id: "@cf/moonshotai/kimi-k2.7-code",
|
|
1418
|
+
provider: "workers-ai",
|
|
1419
|
+
contextWindow: 262144,
|
|
1420
|
+
maxOutputTokens: 16384,
|
|
1421
|
+
pricing: { inputPerMtok: 0.95, cachedInputPerMtok: 0.19, outputPerMtok: 4 },
|
|
1422
|
+
supports: { tools: true, reasoning: true, streaming: true, vision: true },
|
|
1423
|
+
billingMode: "unified"
|
|
1424
|
+
},
|
|
1416
1425
|
{
|
|
1417
1426
|
id: "@cf/moonshotai/kimi-k2.6",
|
|
1418
1427
|
provider: "workers-ai",
|
|
@@ -1539,7 +1548,7 @@ async function* runKimi(opts2) {
|
|
|
1539
1548
|
`Your stored ${modelProvider} key is likely invalid or expired. Fix:`,
|
|
1540
1549
|
` /keys set ${modelProvider} <new-key> replace the stored key`,
|
|
1541
1550
|
` /keys clear ${modelProvider} remove it and reopen the picker to paste fresh`,
|
|
1542
|
-
` /model @cf/moonshotai/kimi-k2.
|
|
1551
|
+
` /model @cf/moonshotai/kimi-k2.7-code switch back to Workers AI (no key needed)`
|
|
1543
1552
|
].join("\n") : msg;
|
|
1544
1553
|
const apiErr = new KimiApiError(`kimiflare: ${wrappedMsg}`, err?.code, res.status);
|
|
1545
1554
|
if (isRetryable(apiErr, attempt)) {
|
|
@@ -1580,7 +1589,7 @@ function missingKeyMessage(model, provider, unifiedAvailable) {
|
|
|
1580
1589
|
if (unifiedAvailable) {
|
|
1581
1590
|
lines.push(` 2. Enable Cloudflare Unified Billing for this gateway in the CF dashboard, then run: /keys unified on`);
|
|
1582
1591
|
}
|
|
1583
|
-
lines.push(` ${unifiedAvailable ? "3" : "2"}. Switch back to a Workers AI model: /model @cf/moonshotai/kimi-k2.
|
|
1592
|
+
lines.push(` ${unifiedAvailable ? "3" : "2"}. Switch back to a Workers AI model: /model @cf/moonshotai/kimi-k2.7-code`);
|
|
1584
1593
|
return lines.join("\n");
|
|
1585
1594
|
}
|
|
1586
1595
|
function gatewayHeadersFor(opts2) {
|
|
@@ -7198,7 +7207,7 @@ var init_spawn_worker = __esm({
|
|
|
7198
7207
|
},
|
|
7199
7208
|
model: {
|
|
7200
7209
|
type: "string",
|
|
7201
|
-
description: "Model to use for the worker. Defaults to @cf/moonshotai/kimi-k2.
|
|
7210
|
+
description: "Model to use for the worker. Defaults to @cf/moonshotai/kimi-k2.7-code."
|
|
7202
7211
|
},
|
|
7203
7212
|
branchName: {
|
|
7204
7213
|
type: "string",
|
|
@@ -7243,7 +7252,7 @@ var init_spawn_worker = __esm({
|
|
|
7243
7252
|
budget: { maxCostUsd: budgetUsd },
|
|
7244
7253
|
outputFormat: args.outputFormat ?? "structured",
|
|
7245
7254
|
tools: args.tools ?? (args.mode === "plan" ? "read-only" : "all"),
|
|
7246
|
-
model: args.model ?? "@cf/moonshotai/kimi-k2.
|
|
7255
|
+
model: args.model ?? "@cf/moonshotai/kimi-k2.7-code",
|
|
7247
7256
|
...args.mode === "execute" ? {
|
|
7248
7257
|
branchName: args.branchName,
|
|
7249
7258
|
baseBranch: args.baseBranch ?? "main",
|
|
@@ -9628,7 +9637,7 @@ async function* authGitHubForTui() {
|
|
|
9628
9637
|
const cfg = await loadConfig() ?? {
|
|
9629
9638
|
accountId: "",
|
|
9630
9639
|
apiToken: "",
|
|
9631
|
-
model: "@cf/moonshotai/kimi-k2.
|
|
9640
|
+
model: "@cf/moonshotai/kimi-k2.7-code"
|
|
9632
9641
|
};
|
|
9633
9642
|
await saveConfig({
|
|
9634
9643
|
...cfg,
|
|
@@ -10101,7 +10110,7 @@ function setupRoutes(config2) {
|
|
|
10101
10110
|
if (pathname === "/prompt" && method === "POST") {
|
|
10102
10111
|
const body = await readBody(req);
|
|
10103
10112
|
const prompt = typeof body.prompt === "string" ? body.prompt : "";
|
|
10104
|
-
const model = typeof body.model === "string" ? body.model : config2.model ?? "@cf/moonshotai/kimi-k2.
|
|
10113
|
+
const model = typeof body.model === "string" ? body.model : config2.model ?? "@cf/moonshotai/kimi-k2.7-code";
|
|
10105
10114
|
const cwd = typeof body.cwd === "string" ? body.cwd : process.cwd();
|
|
10106
10115
|
const title = typeof body.title === "string" ? body.title : void 0;
|
|
10107
10116
|
const files = Array.isArray(body.files) ? body.files.filter((f) => typeof f === "string") : [];
|
|
@@ -11105,7 +11114,7 @@ Return a JSON array of strings. Example:
|
|
|
11105
11114
|
return {
|
|
11106
11115
|
accountId: this.opts.accountId,
|
|
11107
11116
|
apiToken: this.opts.apiToken,
|
|
11108
|
-
model: this.opts.model ?? "@cf/moonshotai/kimi-k2.
|
|
11117
|
+
model: this.opts.model ?? "@cf/moonshotai/kimi-k2.7-code",
|
|
11109
11118
|
gateway: this.opts.gateway
|
|
11110
11119
|
};
|
|
11111
11120
|
}
|
|
@@ -14034,7 +14043,7 @@ ${w.context ?? ""}` : w.context ?? "",
|
|
|
14034
14043
|
budget: { maxCostUsd },
|
|
14035
14044
|
outputFormat: "structured",
|
|
14036
14045
|
tools: w.mode === "plan" ? "read-only" : "all",
|
|
14037
|
-
model: w.model ?? "@cf/moonshotai/kimi-k2.
|
|
14046
|
+
model: w.model ?? "@cf/moonshotai/kimi-k2.7-code",
|
|
14038
14047
|
// Sandbox-driven worker needs the repo to clone:
|
|
14039
14048
|
githubToken: repo.token,
|
|
14040
14049
|
owner: repo.owner,
|
|
@@ -15997,7 +16006,7 @@ var init_builtins = __esm({
|
|
|
15997
16006
|
{ name: "mode", argHint: "edit|plan|auto|multi-agent-experimental", description: "Switch agent mode", source: "builtin" },
|
|
15998
16007
|
{ name: "multi-agent", argHint: "[enable|disable|status|setup]", description: "Configure multi-agent (endpoint, auto-implement, set up)", source: "builtin" },
|
|
15999
16008
|
{ name: "theme", argHint: "[<name>]", description: "Switch color theme", source: "builtin" },
|
|
16000
|
-
{ name: "ui", argHint: "ink
|
|
16009
|
+
{ name: "ui", argHint: "ink", description: "Switch UI engine to React Ink (takes effect on next launch). Camouflage is opt-in via --ui camouflage.", source: "builtin" },
|
|
16001
16010
|
{ name: "plan", description: "Switch to plan mode", source: "builtin" },
|
|
16002
16011
|
{ name: "auto", description: "Switch to auto mode", source: "builtin" },
|
|
16003
16012
|
{ name: "edit", description: "Switch to edit mode", source: "builtin" },
|
|
@@ -20647,7 +20656,7 @@ Executor opened PR: ${prUrl}` : plan });
|
|
|
20647
20656
|
{
|
|
20648
20657
|
value: "camouflage",
|
|
20649
20658
|
label: "Camouflage",
|
|
20650
|
-
description: "experimental
|
|
20659
|
+
description: "experimental \u2014 opt in with `kimiflare --ui camouflage`"
|
|
20651
20660
|
}
|
|
20652
20661
|
],
|
|
20653
20662
|
default: current,
|
|
@@ -20667,6 +20676,14 @@ Executor opened PR: ${prUrl}` : plan });
|
|
|
20667
20676
|
});
|
|
20668
20677
|
return true;
|
|
20669
20678
|
}
|
|
20679
|
+
if (nextUi === "camouflage") {
|
|
20680
|
+
cam.send("ShowToast", {
|
|
20681
|
+
text: "Camouflage is experimental and must be opted into explicitly. Launch with `kimiflare --ui camouflage` or set `KIMIFLARE_UI=camouflage`.",
|
|
20682
|
+
kind: "error",
|
|
20683
|
+
ttl_ms: 12e3
|
|
20684
|
+
});
|
|
20685
|
+
return true;
|
|
20686
|
+
}
|
|
20670
20687
|
try {
|
|
20671
20688
|
const existing = await loadConfig() ?? null;
|
|
20672
20689
|
if (existing) {
|
|
@@ -20681,7 +20698,7 @@ Executor opened PR: ${prUrl}` : plan });
|
|
|
20681
20698
|
return true;
|
|
20682
20699
|
}
|
|
20683
20700
|
cam.send("ShowToast", {
|
|
20684
|
-
text: `UI engine set to "${nextUi}". RESTART kimiflare for it to take effect
|
|
20701
|
+
text: `UI engine set to "${nextUi}". RESTART kimiflare for it to take effect. (or \`unset KIMIFLARE_UI\` if you previously exported it)`,
|
|
20685
20702
|
kind: "error",
|
|
20686
20703
|
ttl_ms: 12e3
|
|
20687
20704
|
});
|
|
@@ -28589,7 +28606,7 @@ function UiPicker({ current, onPick }) {
|
|
|
28589
28606
|
{
|
|
28590
28607
|
label: "Camouflage",
|
|
28591
28608
|
value: "camouflage",
|
|
28592
|
-
description: "experimental
|
|
28609
|
+
description: "experimental \u2014 opt in with `kimiflare --ui camouflage`"
|
|
28593
28610
|
},
|
|
28594
28611
|
{ label: "< Back", value: "__back__", description: "" }
|
|
28595
28612
|
];
|
|
@@ -31397,7 +31414,7 @@ function executeFreshStart(ctx, planText, overrideMode) {
|
|
|
31397
31414
|
rebuildSystemPromptForMode(
|
|
31398
31415
|
ctx.messagesRef.current,
|
|
31399
31416
|
ctx.cacheStableRef.current,
|
|
31400
|
-
ctx.cfg?.model ?? "@cf/moonshotai/kimi-k2.
|
|
31417
|
+
ctx.cfg?.model ?? "@cf/moonshotai/kimi-k2.7-code",
|
|
31401
31418
|
overrideMode ?? ctx.mode,
|
|
31402
31419
|
[...ALL_TOOLS, ...ctx.mcpToolsRef.current, ...ctx.lspToolsRef.current]
|
|
31403
31420
|
);
|
|
@@ -31967,6 +31984,17 @@ var init_slash_commands = __esm({
|
|
|
31967
31984
|
return true;
|
|
31968
31985
|
}
|
|
31969
31986
|
const next = arg;
|
|
31987
|
+
if (next === "camouflage") {
|
|
31988
|
+
setEvents((e) => [
|
|
31989
|
+
...e,
|
|
31990
|
+
{
|
|
31991
|
+
kind: "error",
|
|
31992
|
+
key: mkKey2(),
|
|
31993
|
+
text: "Camouflage is experimental and must be opted into explicitly. Launch with `kimiflare --ui camouflage` or set `KIMIFLARE_UI=camouflage`."
|
|
31994
|
+
}
|
|
31995
|
+
]);
|
|
31996
|
+
return true;
|
|
31997
|
+
}
|
|
31970
31998
|
ctx.setCfg((prev) => {
|
|
31971
31999
|
if (!prev) return prev;
|
|
31972
32000
|
const updated = { ...prev, uiEngine: next };
|
|
@@ -31979,7 +32007,7 @@ var init_slash_commands = __esm({
|
|
|
31979
32007
|
{
|
|
31980
32008
|
kind: "error",
|
|
31981
32009
|
key: mkKey2(),
|
|
31982
|
-
text: `UI engine set to "${next}". RESTART kimiflare for it to take effect.`
|
|
32010
|
+
text: `UI engine set to "${next}". RESTART kimiflare for it to take effect.`
|
|
31983
32011
|
}
|
|
31984
32012
|
]);
|
|
31985
32013
|
return true;
|
|
@@ -34630,6 +34658,17 @@ ${wcagWarnings.join("\n")}` }
|
|
|
34630
34658
|
(picked) => {
|
|
34631
34659
|
setShowUiPicker(false);
|
|
34632
34660
|
if (!picked) return;
|
|
34661
|
+
if (picked === "camouflage") {
|
|
34662
|
+
setEvents((e) => [
|
|
34663
|
+
...e,
|
|
34664
|
+
{
|
|
34665
|
+
kind: "error",
|
|
34666
|
+
key: mkKey(),
|
|
34667
|
+
text: "Camouflage is experimental and must be opted into explicitly. Launch with `kimiflare --ui camouflage` or set `KIMIFLARE_UI=camouflage`."
|
|
34668
|
+
}
|
|
34669
|
+
]);
|
|
34670
|
+
return;
|
|
34671
|
+
}
|
|
34633
34672
|
setCfg((c) => {
|
|
34634
34673
|
if (!c) return c;
|
|
34635
34674
|
const updated = { ...c, uiEngine: picked };
|
|
@@ -34642,7 +34681,7 @@ ${wcagWarnings.join("\n")}` }
|
|
|
34642
34681
|
{
|
|
34643
34682
|
kind: "error",
|
|
34644
34683
|
key: mkKey(),
|
|
34645
|
-
text: `UI engine set to "${picked}". RESTART kimiflare for it to take effect.`
|
|
34684
|
+
text: `UI engine set to "${picked}". RESTART kimiflare for it to take effect.`
|
|
34646
34685
|
}
|
|
34647
34686
|
]);
|
|
34648
34687
|
},
|
|
@@ -36357,7 +36396,7 @@ function buildTextLines(version) {
|
|
|
36357
36396
|
` ${bold}${accent}Kimiflare${reset}`,
|
|
36358
36397
|
"",
|
|
36359
36398
|
` ${dim}Terminal coding agent${reset}`,
|
|
36360
|
-
` ${dim}powered by Kimi-K2.
|
|
36399
|
+
` ${dim}powered by Kimi-K2.7${reset}`,
|
|
36361
36400
|
"",
|
|
36362
36401
|
` ${dim}v${version}${reset}`,
|
|
36363
36402
|
"",
|
|
@@ -36720,7 +36759,7 @@ async function runPrintMode(opts2) {
|
|
|
36720
36759
|
|
|
36721
36760
|
// src/index.tsx
|
|
36722
36761
|
var program = new Command2();
|
|
36723
|
-
program.name("kimiflare").description("Terminal coding agent powered by Kimi-K2.
|
|
36762
|
+
program.name("kimiflare").description("Terminal coding agent powered by Kimi-K2.7 on Cloudflare Workers AI.").version(getAppVersion()).option("-p, --print <prompt>", "one-shot mode: send prompt, stream reply to stdout, exit").option("-m, --model <id>", "model id (defaults to @cf/moonshotai/kimi-k2.7-code)").option("--dangerously-allow-all", "auto-approve every permission prompt (print mode only)").option("--reasoning", "include reasoning in stdout (print mode only)").option("--thinking", "alias for --reasoning").option("--continue-on-limit", "reset tool-call counter and continue when the 200-call limit is hit (print mode only)").option("--max-input-tokens <n>", "cumulative prompt token budget; exits 42 when exhausted (print mode only)", (v) => parseInt(v, 10)).option("--emit-events", "emit Camouflage NDJSON events to stdout; requires -p (for initial prompt)").option("--multi-turn", "with --emit-events: keep reading stdin for UserInputSubmitted follow-ups after the initial turn").option("--ui <name>", "render UI with the given engine: `ink` (default, stable) or `camouflage` (experimental Rust TUI). Can also be set via the KIMIFLARE_UI environment variable.").option("--camouflage-bin <path>", "with --ui camouflage: path to the camouflage-tui binary (defaults to PATH lookup)").option("--mode <mode>", "run mode: interactive (default), print, rpc").option("-c, --continue", "continue the most recent session in the current working directory (print mode only)").option("-S, --session <id>", "resume a specific session by id (print mode only)").option("-f, --file <path>", "attach file(s) to the prompt; repeatable, supports globs (print mode only)", (v, prev) => (prev ?? []).concat(v)).option("--format <mode>", "output format for print mode: text (default), json, stream-json").option("--dir <path>", "run in the specified directory instead of the current one (print mode only)").option("--title <title>", "override the auto-generated session title (print mode only)").option("--attach <url>", "attach to a running kimiflare serve instance (print mode only)");
|
|
36724
36763
|
program.command("cost").description("Show cost attribution by task type (requires costAttribution enabled)").option("-w, --week", "last 7 days (default)").option("-m, --month", "last 30 days").option("-d, --day", "today only").option("-s, --session <id>", "single session detail").option("-c, --category <name>", "filter by category").option("--json", "machine-readable output").option("--reclassify", "re-run classification on all sessions").option("--local-only", "skip Cloudflare reconciliation").action(async (cmdOpts) => {
|
|
36725
36764
|
const cfg = await loadConfig();
|
|
36726
36765
|
const enabled = cfg?.costAttribution ?? false;
|
|
@@ -36845,7 +36884,7 @@ async function main() {
|
|
|
36845
36884
|
if (opts.print !== void 0) {
|
|
36846
36885
|
if (!cfg) {
|
|
36847
36886
|
console.error(
|
|
36848
|
-
'kimiflare: missing credentials.\nSet CLOUDFLARE_ACCOUNT_ID and CLOUDFLARE_API_TOKEN, or write them to\n ~/.config/kimiflare/config.json (chmod 600)\n { "accountId": "...", "apiToken": "...", "model": "@cf/moonshotai/kimi-k2.
|
|
36887
|
+
'kimiflare: missing credentials.\nSet CLOUDFLARE_ACCOUNT_ID and CLOUDFLARE_API_TOKEN, or write them to\n ~/.config/kimiflare/config.json (chmod 600)\n { "accountId": "...", "apiToken": "...", "model": "@cf/moonshotai/kimi-k2.7-code" }'
|
|
36849
36888
|
);
|
|
36850
36889
|
process.exit(2);
|
|
36851
36890
|
}
|
|
@@ -36895,7 +36934,8 @@ async function main() {
|
|
|
36895
36934
|
process.exit(2);
|
|
36896
36935
|
}
|
|
36897
36936
|
const logoText = renderLogo(getAppVersion());
|
|
36898
|
-
const
|
|
36937
|
+
const explicitUi = opts.ui ?? process.env.KIMIFLARE_UI;
|
|
36938
|
+
const uiEngine = (explicitUi ?? (cfg?.uiEngine === "ink" ? "ink" : void 0) ?? "ink").toLowerCase();
|
|
36899
36939
|
if (uiEngine !== "camouflage") {
|
|
36900
36940
|
console.log(logoText);
|
|
36901
36941
|
}
|