@anvaka/vue-llm 0.4.0 → 0.4.2

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.
@@ -1,5 +1,14 @@
1
- class A {
1
+ var q = (a) => {
2
+ throw TypeError(a);
3
+ };
4
+ var P = (a, e, t) => e.has(a) || q("Cannot " + t);
5
+ var $ = (a, e, t) => e.has(a) ? q("Cannot add the same private member more than once") : e instanceof WeakSet ? e.add(a) : e.set(a, t);
6
+ var y = (a, e, t) => (P(a, e, "access private method"), t);
7
+ import { samplingModeFor as I, SAMPLING_MODE as x, samplingKey as L, classifyTemperatureError as _, recordSamplingConstraint as H } from "./samplingPolicy.js";
8
+ var h, S, v;
9
+ class z {
2
10
  constructor(e) {
11
+ $(this, h);
3
12
  this.config = e, this.capabilities = /* @__PURE__ */ new Set(), this.activeRequests = /* @__PURE__ */ new Map();
4
13
  }
5
14
  async initialize() {
@@ -13,84 +22,114 @@ class A {
13
22
  processResponse(e) {
14
23
  throw new Error("processResponse must be implemented by subclass");
15
24
  }
25
+ // Set (or omit) `request.temperature` per the model's sampling policy. Every
26
+ // provider whose wire format carries a top-level temperature calls this after
27
+ // building the request literal, instead of hand-writing
28
+ // `temperature: options.temperature ?? 0.7`. Centralizes the policy so it
29
+ // travels across transports and stays in one place. Returns `request`.
30
+ applySamplingParams(e, t = {}) {
31
+ var i, c;
32
+ const n = e.model || ((i = this.config) == null ? void 0 : i.model) || "", r = t.temperature ?? ((c = this.config) == null ? void 0 : c.temperature) ?? 0.7, o = I(y(this, h, S).call(this, n), n);
33
+ return o === x.OMIT ? delete e.temperature : e.temperature = o === x.ONE ? 1 : r, e;
34
+ }
35
+ // Send `request` via the given closure; on a temperature-related 400, correct
36
+ // the request in place, retry once, and — only when that corrected retry
37
+ // succeeds — memoize the constraint for this (host, model). Shared by the JSON
38
+ // and streaming paths (and reused by BedrockProvider's URL-in-path override),
39
+ // so the recovery ladder lives in exactly one place. `errorLabel` prefixes the
40
+ // thrown message so each transport keeps its own wording. Returns the ok
41
+ // Response; throws on any unrecoverable error.
42
+ async _sendWithTemperatureRetry(e, t, n = "LLM API Error") {
43
+ var c;
44
+ let r = await e();
45
+ if (r.ok) return r;
46
+ const o = await r.text(), i = r.status === 400 ? y(this, h, v).call(this, t, o) : null;
47
+ if (!i) throw new Error(`${n} (${r.status}): ${o}`);
48
+ if (r = await e(), !r.ok)
49
+ throw new Error(`${n} (${r.status}): ${await r.text()}`);
50
+ return H(y(this, h, S).call(this, t.model || ((c = this.config) == null ? void 0 : c.model) || ""), i), r;
51
+ }
16
52
  async streamRequest(e, t, n) {
17
- const r = this.prepareRequest(e, t), o = new AbortController(), l = t.requestId || this.generateRequestId();
18
- this.activeRequests.set(l, o);
53
+ var T;
54
+ const r = this.prepareRequest(e, t), o = new AbortController(), i = t.requestId || this.generateRequestId();
55
+ this.activeRequests.set(i, o);
56
+ const c = () => o.abort();
57
+ t.signal && (t.signal.aborted ? o.abort() : t.signal.addEventListener("abort", c, { once: !0 }));
19
58
  try {
20
- const k = (await this.makeStreamingRequest(r, o.signal)).body.getReader(), E = new TextDecoder();
21
- let m = "", f = "", g = null, u = "";
22
- const w = /* @__PURE__ */ new Map(), b = () => Array.from(w.values()).sort((a, s) => a.index - s.index).map((a) => {
59
+ const f = (await this.makeStreamingRequest(r, o.signal)).body.getReader(), D = new TextDecoder();
60
+ let b = "", w = "", p = null, d = "";
61
+ const R = /* @__PURE__ */ new Map(), k = () => Array.from(R.values()).sort((l, s) => l.index - s.index).map((l) => {
23
62
  let s = {};
24
- if (a.argsText)
63
+ if (l.argsText)
25
64
  try {
26
- s = JSON.parse(a.argsText);
65
+ s = JSON.parse(l.argsText);
27
66
  } catch {
28
- s = { __parseError: !0, raw: a.argsText };
67
+ s = { __parseError: !0, raw: l.argsText };
29
68
  }
30
- return { id: a.id, name: a.name, args: s };
31
- }), R = (p) => {
32
- if (!p.trim()) return null;
33
- const a = this.parseStreamingLine(p);
34
- if (!a) return null;
35
- const s = this.extractStreamingContent(a);
69
+ return { id: l.id, name: l.name, args: s };
70
+ }), M = (g) => {
71
+ if (!g.trim()) return null;
72
+ const l = this.parseStreamingLine(g);
73
+ if (!l) return null;
74
+ const s = this.extractStreamingContent(l);
36
75
  if (!s) return null;
37
- s.content && (m += s.content), s.thinking && (f += s.thinking), s.usage && (g = q(g, s.usage));
38
- const y = Array.isArray(s.toolCallDeltas) ? s.toolCallDeltas : s.toolCallDelta ? [s.toolCallDelta] : [];
39
- for (const i of y) {
40
- let d = w.get(i.index);
41
- d ? (i.id && (d.id = i.id), i.name && (d.name = i.name)) : (d = { index: i.index, id: i.id || null, name: i.name || "", argsText: "" }, w.set(i.index, d)), i.argsTextDelta && (d.argsText += i.argsTextDelta);
76
+ s.content && (b += s.content), s.thinking && (w += s.thinking), s.usage && (p = N(p, s.usage));
77
+ const C = Array.isArray(s.toolCallDeltas) ? s.toolCallDeltas : s.toolCallDelta ? [s.toolCallDelta] : [];
78
+ for (const u of C) {
79
+ let m = R.get(u.index);
80
+ m ? (u.id && (m.id = u.id), u.name && (m.name = u.name)) : (m = { index: u.index, id: u.id || null, name: u.name || "", argsText: "" }, R.set(u.index, m)), u.argsTextDelta && (m.argsText += u.argsTextDelta);
42
81
  }
43
- const T = s.done || !1, C = T ? b() : null;
82
+ const A = s.done || !1, O = A ? k() : null;
44
83
  return n({
45
84
  content: s.content || "",
46
85
  thinking: s.thinking || "",
47
- fullContent: m,
48
- fullThinking: f,
49
- done: T,
86
+ fullContent: b,
87
+ fullThinking: w,
88
+ done: A,
50
89
  usage: s.usage || null,
51
- fullUsage: g,
90
+ fullUsage: p,
52
91
  finishReason: s.finishReason || null,
53
92
  toolCallDelta: s.toolCallDelta || null,
54
- toolCalls: C
55
- }), T ? "done" : null;
93
+ toolCalls: O
94
+ }), A ? "done" : null;
56
95
  };
57
96
  for (; ; ) {
58
- const { done: p, value: a } = await k.read();
59
- if (p) {
60
- u.length > 0 && R(u);
97
+ const { done: g, value: l } = await f.read();
98
+ if (g) {
99
+ d.length > 0 && M(d);
61
100
  break;
62
101
  }
63
- u += E.decode(a, { stream: !0 });
102
+ d += D.decode(l, { stream: !0 });
64
103
  let s;
65
- for (; (s = u.indexOf(`
104
+ for (; (s = d.indexOf(`
66
105
  `)) !== -1; ) {
67
- const y = u.slice(0, s);
68
- if (u = u.slice(s + 1), R(y) === "done")
69
- return { content: m, thinking: f, toolCalls: b(), usage: g };
106
+ const C = d.slice(0, s);
107
+ if (d = d.slice(s + 1), M(C) === "done")
108
+ return { content: b, thinking: w, toolCalls: k(), usage: p };
70
109
  }
71
110
  }
72
- return { content: m, thinking: f, toolCalls: b(), usage: g };
73
- } catch (h) {
74
- throw h.name === "AbortError" ? new Error("Request cancelled") : h;
111
+ return { content: b, thinking: w, toolCalls: k(), usage: p };
112
+ } catch (E) {
113
+ if (E.name === "AbortError") {
114
+ const f = new Error("Request cancelled");
115
+ throw f.name = "AbortError", f;
116
+ }
117
+ throw E;
75
118
  } finally {
76
- this.activeRequests.delete(l);
119
+ this.activeRequests.delete(i), (T = t.signal) == null || T.removeEventListener("abort", c);
77
120
  }
78
121
  }
79
122
  async makeRequest(e, t, n) {
80
123
  const r = t ? { signal: t } : new AbortController();
81
124
  t || (n = n || this.generateRequestId(), this.activeRequests.set(n, r));
82
125
  try {
83
- const o = this.buildHeaders(), l = await fetch(this.getEndpoint(), {
126
+ const o = this.buildHeaders(), i = r.signal || t, c = () => fetch(this.getEndpoint(), {
84
127
  method: "POST",
85
128
  headers: o,
86
129
  body: JSON.stringify(e),
87
- signal: r.signal || t
130
+ signal: i
88
131
  });
89
- if (!l.ok) {
90
- const h = await l.text();
91
- throw new Error(`LLM API Error (${l.status}): ${h}`);
92
- }
93
- return l.json();
132
+ return (await this._sendWithTemperatureRetry(c, e)).json();
94
133
  } catch (o) {
95
134
  throw o.name === "AbortError" ? new Error("Request cancelled") : o;
96
135
  } finally {
@@ -98,17 +137,13 @@ class A {
98
137
  }
99
138
  }
100
139
  async makeStreamingRequest(e, t) {
101
- const n = this.buildHeaders(), r = await fetch(this.getStreamingEndpoint(), {
140
+ const n = this.buildHeaders(), r = () => fetch(this.getStreamingEndpoint(), {
102
141
  method: "POST",
103
142
  headers: n,
104
143
  body: JSON.stringify(e),
105
144
  signal: t
106
145
  });
107
- if (!r.ok) {
108
- const o = await r.text();
109
- throw new Error(`LLM API Error (${r.status}): ${o}`);
110
- }
111
- return r;
146
+ return this._sendWithTemperatureRetry(r, e);
112
147
  }
113
148
  buildHeaders() {
114
149
  const e = { "Content-Type": "application/json" };
@@ -166,8 +201,8 @@ class A {
166
201
  });
167
202
  if (clearTimeout(r), !o.ok)
168
203
  throw new Error(`Failed to fetch models: ${o.status} ${o.statusText}`);
169
- const l = await o.json();
170
- return this.parseModelsResponse(l);
204
+ const i = await o.json();
205
+ return this.parseModelsResponse(i);
171
206
  } catch (t) {
172
207
  throw t.name === "AbortError" ? new Error("Model discovery timeout - please check your connection") : t;
173
208
  }
@@ -179,14 +214,33 @@ class A {
179
214
  throw new Error("parseModelsResponse must be implemented by subclass");
180
215
  }
181
216
  }
182
- function q(c, e) {
183
- if (!e) return c;
184
- if (!c) return { ...e };
185
- const t = { ...c }, n = ["inputTokens", "outputTokens", "totalTokens", "cachedInputTokens", "cacheCreationInputTokens", "reasoningTokens"];
217
+ h = new WeakSet(), S = function(e) {
218
+ const t = this.getEndpoint();
219
+ let n = t || "";
220
+ try {
221
+ n = new URL(t).host;
222
+ } catch {
223
+ }
224
+ return L(n, e);
225
+ }, // On a 400 whose body complains about `temperature`, correct the request in
226
+ // place (drop it, or pin it to 1). Returns the applied SAMPLING_MODE (a truthy
227
+ // string) if the request was adjusted and is worth retrying once, else null.
228
+ // NOTE: this does NOT record the learned constraint — the caller does that only
229
+ // after the corrected request actually succeeds, so a transient 400 whose retry
230
+ // also fails can't permanently poison the memo for this (host, model).
231
+ v = function(e, t) {
232
+ if (!("temperature" in e)) return null;
233
+ const n = _(t);
234
+ return n ? (n === x.OMIT ? delete e.temperature : e.temperature = 1, n) : null;
235
+ };
236
+ function N(a, e) {
237
+ if (!e) return a;
238
+ if (!a) return { ...e };
239
+ const t = { ...a }, n = ["inputTokens", "outputTokens", "totalTokens", "cachedInputTokens", "cacheCreationInputTokens", "reasoningTokens"];
186
240
  for (const r of n)
187
- e[r] != null && (t[r] = c[r] != null ? Math.max(c[r], e[r]) : e[r]);
241
+ e[r] != null && (t[r] = a[r] != null ? Math.max(a[r], e[r]) : e[r]);
188
242
  return e.raw && (t.raw = e.raw), t.totalTokens == null && t.inputTokens != null && t.outputTokens != null && (t.totalTokens = t.inputTokens + t.outputTokens), t;
189
243
  }
190
244
  export {
191
- A as BaseProvider
245
+ z as BaseProvider
192
246
  };
@@ -1,10 +1,11 @@
1
- import { BaseProvider as d } from "./BaseProvider.js";
2
- import { OpenAIProvider as h } from "./OpenAIProvider.js";
1
+ import { BaseProvider as h } from "./BaseProvider.js";
2
+ import { OpenAIProvider as d } from "./OpenAIProvider.js";
3
3
  import { AnthropicProvider as f } from "./AnthropicProvider.js";
4
- const l = [
4
+ const u = [
5
5
  "anthropic.claude-opus-4-8",
6
6
  "anthropic.claude-opus-4-7",
7
7
  "anthropic.claude-sonnet-5",
8
+ "anthropic.claude-fable-5",
8
9
  "anthropic.claude-haiku-4-5"
9
10
  ];
10
11
  function _(s) {
@@ -33,7 +34,7 @@ class b extends f {
33
34
  return delete e["anthropic-dangerous-direct-browser-access"], e;
34
35
  }
35
36
  }
36
- class R extends h {
37
+ class R extends d {
37
38
  // /v1/chat/completions + Bearer + /v1/models are inherited. Only discovery
38
39
  // differs: list EVERY available model so the single dropdown offers the whole
39
40
  // catalog (the router, not this class, decides each model's transport).
@@ -45,7 +46,7 @@ class R extends h {
45
46
  }
46
47
  }
47
48
  const k = 16;
48
- class p extends d {
49
+ class p extends h {
49
50
  constructor(e, t) {
50
51
  super(e), this._apiPath = t || "/v1/responses";
51
52
  }
@@ -61,31 +62,31 @@ class p extends d {
61
62
  this.capabilities.add("tools"), (e.includes("gpt-5") || e.includes("codex") || /(^|\.)o[13]/.test(e)) && this.capabilities.add("thinking");
62
63
  }
63
64
  prepareRequest(e, t) {
64
- const r = {
65
+ const a = {
65
66
  model: t.model || this.config.model,
66
67
  input: v(e),
67
68
  // The Responses API rejects max_output_tokens < 16 (Chat Completions and
68
69
  // Messages accept less), so clamp — e.g. testConnection sends 10.
69
70
  max_output_tokens: Math.max(k, t.maxTokens || 1e3),
70
71
  stream: t.stream || !1
71
- }, i = x(t.tools);
72
- return i && (r.tools = i), r;
72
+ }, o = x(t.tools);
73
+ return o && (a.tools = o), a;
73
74
  }
74
75
  processResponse(e) {
75
76
  let t = "", n = "";
76
- const r = [];
77
- for (const o of e.output || [])
78
- if (o.type === "message")
79
- for (const a of o.content || []) a.type === "output_text" && (t += a.text || "");
80
- else if (o.type === "reasoning")
81
- for (const a of o.content || []) a.type === "reasoning_text" && (n += a.text || "");
82
- else o.type === "function_call" && r.push({ id: o.call_id || o.id, name: o.name, args: A(o.arguments) });
83
- const i = {
77
+ const a = [];
78
+ for (const i of e.output || [])
79
+ if (i.type === "message")
80
+ for (const r of i.content || []) r.type === "output_text" && (t += r.text || "");
81
+ else if (i.type === "reasoning")
82
+ for (const r of i.content || []) r.type === "reasoning_text" && (n += r.text || "");
83
+ else i.type === "function_call" && a.push({ id: i.call_id || i.id, name: i.name, args: A(i.arguments) });
84
+ const o = {
84
85
  content: t,
85
- usage: u(e.usage),
86
+ usage: l(e.usage),
86
87
  finishReason: c(e.status)
87
88
  };
88
- return n && (i.thinking = n), r.length && (i.toolCalls = r), i;
89
+ return n && (o.thinking = n), a.length && (o.toolCalls = a), o;
89
90
  }
90
91
  // Responses streams plain `data: {json}` SSE (no [DONE]); events carry a
91
92
  // `type`. AnthropicProvider/OpenAIProvider use the same `data: ` line format.
@@ -100,7 +101,7 @@ class p extends d {
100
101
  }
101
102
  }
102
103
  extractStreamingContent(e) {
103
- var t, n, r, i;
104
+ var t, n, a, o;
104
105
  if (e.done) return { done: !0 };
105
106
  switch (e.type) {
106
107
  case "response.output_text.delta":
@@ -112,22 +113,22 @@ class p extends d {
112
113
  // fragments. We seed id/name on `added` and stitch arg text on each delta;
113
114
  // BaseProvider's accumulator keys them by output_index and parses at done.
114
115
  case "response.output_item.added": {
115
- const o = e.item;
116
- return o && o.type === "function_call" ? { content: "", done: !1, toolCallDelta: { index: e.output_index ?? 0, id: o.call_id, name: o.name, argsTextDelta: "" } } : null;
116
+ const i = e.item;
117
+ return i && i.type === "function_call" ? { content: "", done: !1, toolCallDelta: { index: e.output_index ?? 0, id: i.call_id, name: i.name, argsTextDelta: "" } } : null;
117
118
  }
118
119
  case "response.function_call_arguments.delta":
119
120
  return { content: "", done: !1, toolCallDelta: { index: e.output_index ?? 0, argsTextDelta: e.delta || "" } };
120
121
  case "response.completed":
121
- return { done: !0, usage: u((t = e.response) == null ? void 0 : t.usage), finishReason: c((n = e.response) == null ? void 0 : n.status) };
122
+ return { done: !0, usage: l((t = e.response) == null ? void 0 : t.usage), finishReason: c((n = e.response) == null ? void 0 : n.status) };
122
123
  case "response.incomplete":
123
124
  case "response.failed":
124
- return { done: !0, usage: u((r = e.response) == null ? void 0 : r.usage), finishReason: c((i = e.response) == null ? void 0 : i.status) };
125
+ return { done: !0, usage: l((a = e.response) == null ? void 0 : a.usage), finishReason: c((o = e.response) == null ? void 0 : o.status) };
125
126
  default:
126
127
  return null;
127
128
  }
128
129
  }
129
130
  }
130
- class S extends d {
131
+ class S extends h {
131
132
  constructor(e) {
132
133
  super(e), this._claude = new b(e), this._chat = new R(e), this._responses = new p(e, "/v1/responses"), this._openaiResponses = new p(e, "/openai/v1/responses"), this._resolved = /* @__PURE__ */ new Map();
133
134
  }
@@ -145,13 +146,19 @@ class S extends d {
145
146
  _active() {
146
147
  return this._order(this.config.model)[0];
147
148
  }
149
+ // Detect on EVERY sub, not just the active one. _active() is not stable: the
150
+ // first successful request caches its winning transport in _resolved, which
151
+ // re-points _order() — and so _active() — at a sub that initialize() never
152
+ // touched. Its capability set would still be the empty one from the ctor, so
153
+ // hasCapability('tools') would answer false for a model that had just
154
+ // finished calling tools, and the NEXT agent turn would refuse to start.
155
+ // These detectCapabilities are pure id matching with no network, so covering
156
+ // all four transports costs nothing.
148
157
  async initialize() {
149
- const e = this._active();
150
- await e.initialize(), this.capabilities = e.capabilities;
158
+ await Promise.all(this._subs().map((e) => e.initialize())), this.capabilities = this._active().capabilities;
151
159
  }
152
160
  async detectCapabilities() {
153
- const e = this._active();
154
- await e.detectCapabilities(), this.capabilities = e.capabilities;
161
+ await Promise.all(this._subs().map((e) => e.detectCapabilities())), this.capabilities = this._active().capabilities;
155
162
  }
156
163
  hasCapability(e) {
157
164
  return this._active().hasCapability(e);
@@ -163,29 +170,29 @@ class S extends d {
163
170
  }
164
171
  async makeRequest(e, t, n) {
165
172
  if (e && e.__mantle) {
166
- const { messages: r, options: i } = e.__mantle;
167
- return this._runWithFallback((o) => o.makeRequest(o.prepareRequest(r, i), t, n), i == null ? void 0 : i.model);
173
+ const { messages: a, options: o } = e.__mantle;
174
+ return this._runWithFallback((i) => i.makeRequest(i.prepareRequest(a, o), t, n), o == null ? void 0 : o.model);
168
175
  }
169
176
  return this._subForShape(e).makeRequest(e, t, n);
170
177
  }
171
178
  async streamRequest(e, t, n) {
172
- return this._runWithFallback((r) => r.streamRequest(e, t, n), t == null ? void 0 : t.model);
179
+ return this._runWithFallback((a) => a.streamRequest(e, t, n), t == null ? void 0 : t.model);
173
180
  }
174
181
  async _runWithFallback(e, t) {
175
182
  const n = t || this.config.model;
176
- let r;
177
- for (const i of this._order(n))
183
+ let a;
184
+ for (const o of this._order(n))
178
185
  try {
179
- const o = await e(i);
180
- return this._resolved.set(n, i), o;
181
- } catch (o) {
182
- if (g(o)) {
183
- r = o;
186
+ const i = await e(o);
187
+ return this._resolved.set(n, o), this.capabilities = this._active().capabilities, i;
188
+ } catch (i) {
189
+ if (g(i)) {
190
+ a = i;
184
191
  continue;
185
192
  }
186
- throw y(o);
193
+ throw y(i);
187
194
  }
188
- throw r || new Error(`No compatible Mantle API for model '${n}'`);
195
+ throw a || new Error(`No compatible Mantle API for model '${n}'`);
189
196
  }
190
197
  processResponse(e) {
191
198
  return this._subForShape(e).processResponse(e);
@@ -196,9 +203,9 @@ class S extends d {
196
203
  async discoverModels(e = 1e4, t) {
197
204
  try {
198
205
  const n = await this._chat.discoverModels(e, t);
199
- return n.length ? n : l.slice();
206
+ return n.length ? n : u.slice();
200
207
  } catch {
201
- return l.slice();
208
+ return u.slice();
202
209
  }
203
210
  }
204
211
  cancelAllRequests() {
@@ -243,11 +250,11 @@ function x(s) {
243
250
  function c(s) {
244
251
  return s === "completed" ? "stop" : s === "incomplete" ? "length" : s || null;
245
252
  }
246
- function u(s) {
247
- var o, a;
253
+ function l(s) {
254
+ var i, r;
248
255
  if (!s) return null;
249
- const e = s.input_tokens ?? 0, t = s.output_tokens ?? 0, n = { inputTokens: e, outputTokens: t, totalTokens: s.total_tokens ?? e + t, raw: s }, r = (o = s.input_tokens_details) == null ? void 0 : o.cached_tokens, i = (a = s.output_tokens_details) == null ? void 0 : a.reasoning_tokens;
250
- return r != null && (n.cachedInputTokens = r), i != null && (n.reasoningTokens = i), n;
256
+ const e = s.input_tokens ?? 0, t = s.output_tokens ?? 0, n = { inputTokens: e, outputTokens: t, totalTokens: s.total_tokens ?? e + t, raw: s }, a = (i = s.input_tokens_details) == null ? void 0 : i.cached_tokens, o = (r = s.output_tokens_details) == null ? void 0 : r.reasoning_tokens;
257
+ return a != null && (n.cachedInputTokens = a), o != null && (n.reasoningTokens = o), n;
251
258
  }
252
259
  function A(s) {
253
260
  if (!s) return {};
@@ -258,8 +265,8 @@ function A(s) {
258
265
  }
259
266
  }
260
267
  export {
261
- l as BEDROCK_MANTLE_CLAUDE_MODELS,
268
+ u as BEDROCK_MANTLE_CLAUDE_MODELS,
262
269
  S as BedrockMantleProvider,
263
270
  _ as isMantleClaudeModel,
264
- u as normalizeResponsesUsage
271
+ l as normalizeResponsesUsage
265
272
  };