@ai-ecoverse/slicc-spectrum 2.7.0 → 2.9.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/README.md +7 -7
- package/dist/{chunk-AIE26XNA.js → chunk-OEIRN47D.js} +2 -2
- package/dist/chunk-OEIRN47D.js.map +7 -0
- package/dist/slicc-dummy.js +9 -1
- package/dist/slicc-dummy.js.map +2 -2
- package/dist/slicc-kernel-model.js +1 -1
- package/dist/slicc-ui.js +144 -65
- package/dist/slicc-ui.js.map +4 -4
- package/dist/types/app/composer.d.ts +4 -1
- package/dist/types/app/tool-title.d.ts +3 -0
- package/dist/types/dummy/agent.d.ts +1 -0
- package/dist/types/model/types.d.ts +2 -0
- package/package.json +2 -2
- package/dist/chunk-AIE26XNA.js.map +0 -7
package/dist/slicc-ui.js
CHANGED
|
@@ -14414,48 +14414,6 @@ var o63 = class extends a8 {
|
|
|
14414
14414
|
};
|
|
14415
14415
|
e26("swc-icon-info-circle", o63);
|
|
14416
14416
|
|
|
14417
|
-
// src/app/guard.ts
|
|
14418
|
-
var prefixes = [
|
|
14419
|
-
"sk-",
|
|
14420
|
-
"sk_",
|
|
14421
|
-
"rk_",
|
|
14422
|
-
"pk_live",
|
|
14423
|
-
"ghp_",
|
|
14424
|
-
"gho_",
|
|
14425
|
-
"ghu_",
|
|
14426
|
-
"ghs_",
|
|
14427
|
-
"ghr_",
|
|
14428
|
-
"github_pat_",
|
|
14429
|
-
"glpat-",
|
|
14430
|
-
"xoxa-",
|
|
14431
|
-
"xoxb-",
|
|
14432
|
-
"xoxp-",
|
|
14433
|
-
"xoxs-",
|
|
14434
|
-
"AKIA",
|
|
14435
|
-
"ASIA",
|
|
14436
|
-
"AIza",
|
|
14437
|
-
"npm_",
|
|
14438
|
-
"pypi-",
|
|
14439
|
-
"hf_",
|
|
14440
|
-
"eyJ",
|
|
14441
|
-
"-----BEGIN"
|
|
14442
|
-
];
|
|
14443
|
-
var keyed = /(?:(?:[\w-]*(?:token|secret|passw(?:or)?d|pwd|api[_-]?key|access[_-]?key|private[_-]?key|credential)[\w-]*|\b(?:auth|authorization)\b)["']?\s*[:=]\s*|(?:^|\s)--?[\w-]*(?:token|secret|password|api-key|key)\s+|\bbearer\s+)/gi;
|
|
14444
|
-
var word = /[^\s'"=:,;(){}[\]`]+/g;
|
|
14445
|
-
function guard(text4, growing = false) {
|
|
14446
|
-
let cut = text4.length;
|
|
14447
|
-
for (const match of text4.matchAll(keyed)) cut = Math.min(cut, match.index + match[0].length);
|
|
14448
|
-
for (const match of text4.matchAll(word)) {
|
|
14449
|
-
const token = match[0];
|
|
14450
|
-
const last = growing && match.index + token.length === text4.length;
|
|
14451
|
-
const risky = prefixes.some(
|
|
14452
|
-
(prefix) => token.startsWith(prefix) || last && token.length >= 2 && prefix.startsWith(token)
|
|
14453
|
-
);
|
|
14454
|
-
if (risky) cut = Math.min(cut, match.index);
|
|
14455
|
-
}
|
|
14456
|
-
return cut < text4.length ? `${text4.slice(0, cut).trimEnd()} \u2026` : text4;
|
|
14457
|
-
}
|
|
14458
|
-
|
|
14459
14417
|
// node_modules/mdast-util-to-string/lib/index.js
|
|
14460
14418
|
var emptyOptions = {};
|
|
14461
14419
|
function toString(value, options2) {
|
|
@@ -33316,6 +33274,69 @@ var signInCss = i`
|
|
|
33316
33274
|
}
|
|
33317
33275
|
`;
|
|
33318
33276
|
|
|
33277
|
+
// src/app/guard.ts
|
|
33278
|
+
var prefixes = [
|
|
33279
|
+
"sk-",
|
|
33280
|
+
"sk_",
|
|
33281
|
+
"rk_",
|
|
33282
|
+
"pk_live",
|
|
33283
|
+
"ghp_",
|
|
33284
|
+
"gho_",
|
|
33285
|
+
"ghu_",
|
|
33286
|
+
"ghs_",
|
|
33287
|
+
"ghr_",
|
|
33288
|
+
"github_pat_",
|
|
33289
|
+
"glpat-",
|
|
33290
|
+
"xoxa-",
|
|
33291
|
+
"xoxb-",
|
|
33292
|
+
"xoxp-",
|
|
33293
|
+
"xoxs-",
|
|
33294
|
+
"AKIA",
|
|
33295
|
+
"ASIA",
|
|
33296
|
+
"AIza",
|
|
33297
|
+
"npm_",
|
|
33298
|
+
"pypi-",
|
|
33299
|
+
"hf_",
|
|
33300
|
+
"eyJ",
|
|
33301
|
+
"-----BEGIN"
|
|
33302
|
+
];
|
|
33303
|
+
var keyed = /(?:(?:[\w-]*(?:token|secret|passw(?:or)?d|pwd|api[_-]?key|access[_-]?key|private[_-]?key|credential)[\w-]*|\b(?:auth|authorization)\b)["']?\s*[:=]\s*|(?:^|\s)--?[\w-]*(?:token|secret|password|api-key|key)\s+|\bbearer\s+)/gi;
|
|
33304
|
+
var word = /[^\s'"=:,;(){}[\]`]+/g;
|
|
33305
|
+
function guard(text4, growing = false) {
|
|
33306
|
+
let cut = text4.length;
|
|
33307
|
+
for (const match of text4.matchAll(keyed)) cut = Math.min(cut, match.index + match[0].length);
|
|
33308
|
+
for (const match of text4.matchAll(word)) {
|
|
33309
|
+
const token = match[0];
|
|
33310
|
+
const last = growing && match.index + token.length === text4.length;
|
|
33311
|
+
const risky = prefixes.some(
|
|
33312
|
+
(prefix) => token.startsWith(prefix) || last && token.length >= 2 && prefix.startsWith(token)
|
|
33313
|
+
);
|
|
33314
|
+
if (risky) cut = Math.min(cut, match.index);
|
|
33315
|
+
}
|
|
33316
|
+
return cut < text4.length ? `${text4.slice(0, cut).trimEnd()} \u2026` : text4;
|
|
33317
|
+
}
|
|
33318
|
+
|
|
33319
|
+
// src/app/tool-title.ts
|
|
33320
|
+
var shellLead = /^(?:(?:git|npm|npx|pnpm|yarn|bun|node|deno|python3?|pip3?|curl|wget|ls|cd|cat|rm|mv|cp|chmod|chown|mkdir|touch|tar|zip|unzip|docker|kubectl|gh|wrangler|lsof|find|grep|rg|sed|awk|ssh|scp|rsync|make|cargo|go|ruby|perl|php|java|javac|swift|xcodebuild|brew|apt|yum|sudo|env|export|echo|printf|true|false|test|bash|sh|zsh|fish|source)(?=\s|$)|(?:\.\/))/;
|
|
33321
|
+
function rawTitle(title2) {
|
|
33322
|
+
const text4 = title2.trim();
|
|
33323
|
+
if (!text4) return false;
|
|
33324
|
+
if (text4.length > 80) return true;
|
|
33325
|
+
if (/[|;&><`]|\$\(|&&|\|\|/.test(text4)) return true;
|
|
33326
|
+
if (/^-[A-Za-z0-9]/.test(text4)) return true;
|
|
33327
|
+
if (/^[a-z]/.test(text4) && shellLead.test(text4)) return true;
|
|
33328
|
+
if (!/\s/.test(text4) && (/^[./~]/.test(text4) || /\.[A-Za-z0-9]+$/.test(text4))) return true;
|
|
33329
|
+
return false;
|
|
33330
|
+
}
|
|
33331
|
+
function headline(call) {
|
|
33332
|
+
const title2 = call.title.trim();
|
|
33333
|
+
const name = call.name.trim();
|
|
33334
|
+
const growing = call.status === "running";
|
|
33335
|
+
if (!title2) return guard(name, growing);
|
|
33336
|
+
if (rawTitle(title2)) return guard(`${name} ${title2}`.trim(), growing);
|
|
33337
|
+
return guard(title2, growing);
|
|
33338
|
+
}
|
|
33339
|
+
|
|
33319
33340
|
// src/app/messages.ts
|
|
33320
33341
|
var alone = { calls: [], live: false };
|
|
33321
33342
|
var lickLabels = {
|
|
@@ -33569,9 +33590,6 @@ function step(call, context, id) {
|
|
|
33569
33590
|
</div>`
|
|
33570
33591
|
];
|
|
33571
33592
|
}
|
|
33572
|
-
function headline(call) {
|
|
33573
|
-
return guard(`${call.name} ${call.title}`.trim(), call.status === "running");
|
|
33574
|
-
}
|
|
33575
33593
|
function phase(status2, calls, live, said = false, stopped = false) {
|
|
33576
33594
|
if (status2 === "stopped" || stopped) return "stopped";
|
|
33577
33595
|
if (!calls.length) return status2 === "streaming" && !said ? "active" : null;
|
|
@@ -35288,7 +35306,19 @@ var SliccVaultValue = class extends i2 {
|
|
|
35288
35306
|
};
|
|
35289
35307
|
|
|
35290
35308
|
// src/app/composer.ts
|
|
35291
|
-
var limit =
|
|
35309
|
+
var limit = 100 * 1024 * 1024;
|
|
35310
|
+
function tooLarge(bytes) {
|
|
35311
|
+
return `Too large: attachments are limited to ${size3(bytes)}`;
|
|
35312
|
+
}
|
|
35313
|
+
function smallest(limits = {}) {
|
|
35314
|
+
return Math.min(limit, limits.image ?? limit, limits.text ?? limit, limits.file ?? limit);
|
|
35315
|
+
}
|
|
35316
|
+
function together(bytes) {
|
|
35317
|
+
return `These attachments add up to more than ${size3(bytes)}; send them in separate messages.`;
|
|
35318
|
+
}
|
|
35319
|
+
function carried(attachment2) {
|
|
35320
|
+
return attachment2.url !== void 0 || attachment2.text !== void 0 || attachment2.path === void 0;
|
|
35321
|
+
}
|
|
35292
35322
|
var startingKey = "slicc-spectrum.starting";
|
|
35293
35323
|
var names = (files) => files.map((file) => file.name).join(", ");
|
|
35294
35324
|
function reattach(files) {
|
|
@@ -35512,9 +35542,9 @@ var commands = [
|
|
|
35512
35542
|
name: "thinking",
|
|
35513
35543
|
detail: "Set the thinking level",
|
|
35514
35544
|
args: () => ["off", "low", "medium", "high"].map((value) => ({ value, label: value, detail: "" })),
|
|
35515
|
-
run: (model,
|
|
35545
|
+
run: (model, id, arg) => {
|
|
35516
35546
|
if (["off", "low", "medium", "high"].includes(arg))
|
|
35517
|
-
model.
|
|
35547
|
+
model.agent.setThinking(id, arg);
|
|
35518
35548
|
}
|
|
35519
35549
|
},
|
|
35520
35550
|
{
|
|
@@ -36032,6 +36062,7 @@ var SliccComposer = class extends ThemedElement {
|
|
|
36032
36062
|
}, linger);
|
|
36033
36063
|
}
|
|
36034
36064
|
updated(changed2) {
|
|
36065
|
+
this.#guard();
|
|
36035
36066
|
if (changed2.has("popup"))
|
|
36036
36067
|
this.renderRoot.querySelector('.item[aria-selected="true"]')?.scrollIntoView({ block: "nearest" });
|
|
36037
36068
|
}
|
|
@@ -36143,11 +36174,42 @@ ${row.text}` : row.text;
|
|
|
36143
36174
|
#busy() {
|
|
36144
36175
|
return this.model?.agent.busy(this.#agent) ?? false;
|
|
36145
36176
|
}
|
|
36177
|
+
#limits() {
|
|
36178
|
+
return this.model?.agent.attachmentLimits?.() ?? {};
|
|
36179
|
+
}
|
|
36180
|
+
#cap(attachment2) {
|
|
36181
|
+
return Math.min(limit, this.#limits()[attachment2.kind] ?? limit);
|
|
36182
|
+
}
|
|
36183
|
+
#over(attachment2) {
|
|
36184
|
+
return carried(attachment2) && attachment2.size > (attachment2.error ? limit : this.#cap(attachment2));
|
|
36185
|
+
}
|
|
36186
|
+
#problem(attachment2) {
|
|
36187
|
+
return attachment2.error ?? (this.#over(attachment2) ? tooLarge(this.#cap(attachment2)) : void 0);
|
|
36188
|
+
}
|
|
36189
|
+
#together() {
|
|
36190
|
+
const total = this.#limits().total;
|
|
36191
|
+
if (total === void 0) return null;
|
|
36192
|
+
const sum = this.attachments.filter((attachment2) => !attachment2.error && carried(attachment2)).reduce((bytes, attachment2) => bytes + attachment2.size, 0);
|
|
36193
|
+
return sum > total ? together(total) : null;
|
|
36194
|
+
}
|
|
36195
|
+
#blocked() {
|
|
36196
|
+
return this.attachments.some((attachment2) => this.#over(attachment2)) || !!this.#together();
|
|
36197
|
+
}
|
|
36198
|
+
#guard() {
|
|
36199
|
+
const field3 = this.#field;
|
|
36200
|
+
const blocked2 = this.#blocked();
|
|
36201
|
+
void field3.updateComplete.then(() => {
|
|
36202
|
+
const button = field3.shadowRoot.querySelector(
|
|
36203
|
+
".swc-PromptField-send, .swc-PromptField-stop"
|
|
36204
|
+
);
|
|
36205
|
+
button.disabled = (field3.disabled || blocked2) && !field3.generating;
|
|
36206
|
+
});
|
|
36207
|
+
}
|
|
36146
36208
|
send(mode2 = "send") {
|
|
36147
36209
|
const model = this.model;
|
|
36148
36210
|
const text4 = this.value.trim();
|
|
36149
36211
|
const attachments = this.attachments.filter((attachment2) => !attachment2.error);
|
|
36150
|
-
if (!model || !text4 && attachments.length === 0 || this.#held()) return;
|
|
36212
|
+
if (!model || !text4 && attachments.length === 0 || this.#held() || this.#blocked()) return;
|
|
36151
36213
|
if (model.seat) {
|
|
36152
36214
|
this.#propose(model, text4);
|
|
36153
36215
|
return;
|
|
@@ -36203,7 +36265,7 @@ ${this.value}` : text4;
|
|
|
36203
36265
|
added.push({
|
|
36204
36266
|
...base,
|
|
36205
36267
|
kind: "file",
|
|
36206
|
-
error:
|
|
36268
|
+
error: tooLarge(limit)
|
|
36207
36269
|
});
|
|
36208
36270
|
continue;
|
|
36209
36271
|
}
|
|
@@ -36733,27 +36795,28 @@ ${this.value}` : text4;
|
|
|
36733
36795
|
this.dictating = true;
|
|
36734
36796
|
recognition.start();
|
|
36735
36797
|
}
|
|
36736
|
-
#thumbnail(attachment2) {
|
|
36737
|
-
if (attachment2.kind === "image" && attachment2.url && !
|
|
36798
|
+
#thumbnail(attachment2, problem) {
|
|
36799
|
+
if (attachment2.kind === "image" && attachment2.url && !problem)
|
|
36738
36800
|
return b`<img slot="thumbnail" src=${attachment2.url} alt="" />`;
|
|
36739
|
-
const icon =
|
|
36740
|
-
return b`<span slot="thumbnail" class="thumb" ?data-error=${!!
|
|
36801
|
+
const icon = problem ? b`<swc-icon-alert-triangle></swc-icon-alert-triangle>` : attachment2.kind === "secret" ? b`<swc-icon-lock></swc-icon-lock>` : attachment2.kind === "text" ? b`<swc-icon-file-text></swc-icon-file-text>` : b`<swc-icon-file></swc-icon-file>`;
|
|
36802
|
+
return b`<span slot="thumbnail" class="thumb" ?data-error=${!!problem} aria-hidden="true">${icon}</span>`;
|
|
36741
36803
|
}
|
|
36742
36804
|
#attachment(attachment2) {
|
|
36743
|
-
const
|
|
36805
|
+
const problem = this.#problem(attachment2);
|
|
36806
|
+
const detail = problem ? this.#errorDetail(problem) : attachment2.kind === "secret" ? "Secret" : size3(attachment2.size);
|
|
36744
36807
|
return b`<swc-upload-attachment
|
|
36745
36808
|
slot="attachment"
|
|
36746
36809
|
type="card"
|
|
36747
36810
|
dismissible
|
|
36748
36811
|
data-id=${attachment2.id}
|
|
36749
36812
|
data-kind=${attachment2.kind}
|
|
36750
|
-
?data-error=${!!
|
|
36751
|
-
title=${
|
|
36813
|
+
?data-error=${!!problem}
|
|
36814
|
+
title=${problem ?? attachment2.path ?? attachment2.name}
|
|
36752
36815
|
@swc-upload-attachment-dismiss=${() => this.detach(attachment2.id)}
|
|
36753
36816
|
>
|
|
36754
|
-
${this.#thumbnail(attachment2)}
|
|
36817
|
+
${this.#thumbnail(attachment2, problem)}
|
|
36755
36818
|
<span slot="title">${attachment2.name}</span>
|
|
36756
|
-
<span slot="subtitle" class=${
|
|
36819
|
+
<span slot="subtitle" class=${problem ? "failed" : ""} title=${problem ?? A}>${detail}</span>
|
|
36757
36820
|
</swc-upload-attachment>`;
|
|
36758
36821
|
}
|
|
36759
36822
|
#popup() {
|
|
@@ -36988,12 +37051,14 @@ ${this.value}` : text4;
|
|
|
36988
37051
|
this.attachments.filter((attachment2) => !attachment2.error).map((attachment2) => attachment2.name)
|
|
36989
37052
|
);
|
|
36990
37053
|
const missing = (this.reattach ?? []).filter((file) => !back.has(file.name));
|
|
37054
|
+
const crowded = this.#together();
|
|
36991
37055
|
return b`<div class="column" @drop=${this.#mark}>
|
|
36992
37056
|
<span id="keys" class="sr" aria-hidden="true">${this.#instructions(busy)}</span>
|
|
36993
37057
|
${this.#hold()}
|
|
36994
37058
|
${this.#starters()}
|
|
36995
37059
|
${this.#queue()}
|
|
36996
37060
|
${this.#popup()}
|
|
37061
|
+
${crowded ? b`<p class="send-error" role="alert" data-send-error="together"><swc-icon-alert-triangle size="s" aria-hidden="true"></swc-icon-alert-triangle><span>${crowded}</span></p>` : A}
|
|
36997
37062
|
<swc-prompt-field
|
|
36998
37063
|
accessible-label="Message"
|
|
36999
37064
|
loader=${this.#loader(busy)}
|
|
@@ -38556,7 +38621,7 @@ var SliccChat = class _SliccChat extends ThemedElement {
|
|
|
38556
38621
|
${offered.length ? b`<sp-picker size="s" quiet label="Model" value=${agent.model} @change=${(event2) => model.agent.setModel(agent.id, event2.target.value)} @sp-opened=${this.#modelFilter.opened} @sp-closed=${this.#modelFilter.closed} @keydown=${this.#modelFilter.keys}>
|
|
38557
38622
|
${this.#modelFilter.items(offered)}
|
|
38558
38623
|
</sp-picker>` : b`<swc-action-button size="s" quiet data-action="set-up-model" @click=${() => this.#action("settings")}>Set up a model</swc-action-button>`}
|
|
38559
|
-
<sp-picker size="s" quiet label="Thinking" value=${model.settings.get().thinking} @change=${(event2) => model.
|
|
38624
|
+
<sp-picker size="s" quiet label="Thinking" value=${agent.thinking ?? model.settings.get().thinking} @change=${(event2) => model.agent.setThinking(agent.id, event2.target.value)}>
|
|
38560
38625
|
<sp-menu-item value="off">No thinking</sp-menu-item>
|
|
38561
38626
|
<sp-menu-item value="low">Think a little</sp-menu-item>
|
|
38562
38627
|
<sp-menu-item value="medium">Think</sp-menu-item>
|
|
@@ -38645,7 +38710,7 @@ var SliccChat = class _SliccChat extends ThemedElement {
|
|
|
38645
38710
|
<swc-illustrated-message>
|
|
38646
38711
|
<swc-icon-attach></swc-icon-attach>
|
|
38647
38712
|
<h2 slot="heading">Drop files to attach</h2>
|
|
38648
|
-
<span slot="description">Images, text and other files up to ${
|
|
38713
|
+
<span slot="description">Images, text and other files up to ${Number((smallest(this.model?.agent.attachmentLimits?.()) / 1024 / 1024).toFixed(1))} MB each join your next message. Folders can’t be attached.</span>
|
|
38649
38714
|
</swc-illustrated-message>
|
|
38650
38715
|
</swc-dropzone>` : A}
|
|
38651
38716
|
<p class="sr" role="status" data-announce="drop">${this.dropping ? "Drop to attach files to your message" : ""}</p>
|
|
@@ -39890,7 +39955,10 @@ function watchTitles(model, update) {
|
|
|
39890
39955
|
const seen = /* @__PURE__ */ new Map();
|
|
39891
39956
|
const check3 = (id) => {
|
|
39892
39957
|
const agent = model.agent.list().find((candidate) => candidate.id === id);
|
|
39893
|
-
if (!agent)
|
|
39958
|
+
if (!agent) {
|
|
39959
|
+
if (seen.delete(id)) update();
|
|
39960
|
+
return;
|
|
39961
|
+
}
|
|
39894
39962
|
const title2 = agentTitle(model, agent);
|
|
39895
39963
|
if (seen.get(id) === title2) return;
|
|
39896
39964
|
seen.set(id, title2);
|
|
@@ -39898,7 +39966,12 @@ function watchTitles(model, update) {
|
|
|
39898
39966
|
};
|
|
39899
39967
|
const stops = [
|
|
39900
39968
|
model.agent.on("messages", check3),
|
|
39901
|
-
model.agent.on("message", ({ agentId }) => check3(agentId))
|
|
39969
|
+
model.agent.on("message", ({ agentId }) => check3(agentId)),
|
|
39970
|
+
model.agent.on("agents", (agents) => {
|
|
39971
|
+
const live = new Set(agents.map((agent) => agent.id));
|
|
39972
|
+
for (const id of seen.keys()) if (!live.has(id)) check3(id);
|
|
39973
|
+
for (const agent of agents) check3(agent.id);
|
|
39974
|
+
})
|
|
39902
39975
|
];
|
|
39903
39976
|
return () => {
|
|
39904
39977
|
for (const stop of stops) stop();
|
|
@@ -58060,9 +58133,14 @@ var SliccStatusLabel = class extends i2 {
|
|
|
58060
58133
|
get #anchor() {
|
|
58061
58134
|
return `${this.agent} ${this.calls[0]?.id ?? ""}`;
|
|
58062
58135
|
}
|
|
58136
|
+
#needsLabel() {
|
|
58137
|
+
if (this.calls.length >= 2) return true;
|
|
58138
|
+
const only = this.calls[0];
|
|
58139
|
+
return !!only && rawTitle(only.title);
|
|
58140
|
+
}
|
|
58063
58141
|
#ask() {
|
|
58064
58142
|
const port = this.model?.agent;
|
|
58065
|
-
if (this
|
|
58143
|
+
if (!this.#needsLabel() || !port?.toolLabel) return;
|
|
58066
58144
|
const store2 = cache3(port);
|
|
58067
58145
|
const key = this.#key;
|
|
58068
58146
|
const anchor = this.#anchor;
|
|
@@ -58088,7 +58166,8 @@ var SliccStatusLabel = class extends i2 {
|
|
|
58088
58166
|
return store2?.done.get(this.#key) ?? store2?.latest.get(this.#anchor) ?? "";
|
|
58089
58167
|
}
|
|
58090
58168
|
#wanted() {
|
|
58091
|
-
|
|
58169
|
+
if (this.state === "stopped") return this.text;
|
|
58170
|
+
const base = this.#label() || this.text;
|
|
58092
58171
|
return base && this.note ? `${this.note} \xB7 ${base}` : base;
|
|
58093
58172
|
}
|
|
58094
58173
|
#cancel() {
|