@andreprado/agentkit 0.1.0 → 0.2.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 +8 -77
- package/docs/guides/add-channel.md +14 -92
- package/docs/guides/add-knowledge.md +0 -21
- package/docs/guides/add-tool.md +5 -11
- package/docs/guides/channel-security.md +3 -207
- package/docs/guides/connect-discord.md +7 -172
- package/docs/guides/connect-slack.md +6 -121
- package/docs/guides/connect-telegram.md +6 -165
- package/docs/guides/connect-whatsapp-evolution.md +6 -116
- package/docs/guides/connect-whatsapp-uazapi.md +6 -134
- package/docs/guides/connect-whatsapp-zapster.md +6 -202
- package/docs/guides/create-agent.md +5 -14
- package/docs/guides/debug-channel.md +4 -156
- package/docs/guides/improve-local.md +13 -0
- package/docs/guides/local-only-migration.md +35 -0
- package/docs/guides/replay-local-traces.md +11 -0
- package/docs/guides/run-evals.md +2 -4
- package/docs/guides/security-rules.md +5 -154
- package/docs/guides/use-jev.md +3 -6
- package/docs/guides/use-provider.md +0 -3
- package/docs/guides/write-feedback.md +10 -0
- package/docs/llms-full.txt +27 -448
- package/docs/llms.txt +8 -44
- package/package.json +2 -4
- package/src/cli/commands/channels.ts +8 -1613
- package/src/cli/commands/feedback.ts +8 -86
- package/src/cli/constants.ts +0 -3
- package/src/cli/flags.ts +0 -28
- package/src/cli/help.ts +16 -92
- package/src/cli/index.ts +15 -1091
- package/src/index.ts +6 -158
- package/src/providers/pi.ts +2 -0
- package/src/runtime/channels/discord.ts +16 -8
- package/src/runtime/channels/generic-webhook.ts +21 -313
- package/src/runtime/channels/net-guard.ts +480 -0
- package/src/runtime/channels/provider-fetch.ts +54 -0
- package/src/runtime/channels/slack.ts +9 -3
- package/src/runtime/channels/telegram.ts +43 -10
- package/src/runtime/channels/whatsapp-evolution.ts +33 -60
- package/src/runtime/channels/whatsapp-uazapi.ts +33 -164
- package/src/runtime/channels/whatsapp-zapster.ts +35 -7
- package/src/runtime/chat.ts +5 -3
- package/src/runtime/config.ts +36 -147
- package/src/runtime/database.ts +2 -2
- package/src/runtime/dev-server.ts +8 -8
- package/src/runtime/env.ts +11 -0
- package/src/runtime/improve.ts +2 -262
- package/src/runtime/inspect.ts +13 -73
- package/src/runtime/knowledge/embeddings.ts +45 -7
- package/src/runtime/knowledge/ingest.ts +70 -7
- package/src/runtime/knowledge/tool.ts +16 -2
- package/src/runtime/knowledge/vector.ts +31 -31
- package/src/runtime/tool-runner.ts +5 -3
- package/src/runtime/tools.ts +10 -14
- package/src/storage/sqlite.ts +11 -32
- package/src/templates/blank.ts +15 -102
- package/src/templates/common.ts +60 -0
- package/src/templates/dentista.ts +7 -74
- package/src/templates/skills/agentkit-capsule/SKILL.md +5 -7
- package/src/templates/skills/agentkit-capsule/references/docs-router.md +2 -3
- package/src/templates/skills/agentkit-channels/SKILL.md +6 -119
- package/src/templates/skills/agentkit-channels/references/channel-buffering.md +0 -9
- package/src/templates/skills/agentkit-channels/references/channel-debugging.md +1 -64
- package/src/templates/skills/agentkit-channels/references/discord.md +2 -92
- package/src/templates/skills/agentkit-channels/references/slack.md +2 -55
- package/src/templates/skills/agentkit-channels/references/telegram.md +2 -71
- package/src/templates/skills/agentkit-channels/references/whatsapp-evolution.md +2 -56
- package/src/templates/skills/agentkit-channels/references/whatsapp-uazapi.md +2 -53
- package/src/templates/skills/agentkit-channels/references/whatsapp-zapster.md +2 -70
- package/src/templates/skills/agentkit-database/SKILL.md +2 -4
- package/src/templates/skills/agentkit-evals/SKILL.md +1 -1
- package/src/templates/skills/agentkit-improve/SKILL.md +6 -85
- package/src/templates/skills/agentkit-improve/references/trace-packets.md +1 -1
- package/src/templates/skills/agentkit-provider/SKILL.md +0 -1
- package/src/templates/skills/agentkit-security/SKILL.md +1 -3
- package/src/templates/skills/agentkit-tools/SKILL.md +1 -1
- package/src/templates/skills/agentkit-tools/examples/database-write.tool.md +1 -2
- package/src/templates/skills/agentkit-troubleshooting/SKILL.md +5 -11
- package/src/templates/support.ts +8 -92
- package/docs/guides/add-managed-composio.md +0 -165
- package/docs/guides/improve-from-production.md +0 -151
- package/docs/guides/prepare-deploy.md +0 -227
- package/docs/guides/replay-production-traces.md +0 -72
- package/docs/guides/send-feedback.md +0 -135
- package/src/cli/cloud-client.ts +0 -377
- package/src/cli/deploy-chat-ui.ts +0 -606
- package/src/cli/deploy-readiness.ts +0 -561
- package/src/cloud/artifact.ts +0 -139
- package/src/cloud/client.ts +0 -80
- package/src/cloud/contracts.ts +0 -63
- package/src/cloud/index.ts +0 -3
- package/src/runtime/build.ts +0 -43
- package/src/runtime/core/deploy-state.ts +0 -54
- package/src/runtime/core/manifest.ts +0 -283
- package/src/runtime/core/targets.ts +0 -133
- package/src/runtime/deploy-readiness.ts +0 -135
- package/src/runtime/deploy.ts +0 -1
- package/src/runtime/integrations/composio.ts +0 -425
- package/src/runtime/targets/cloudflare/build.ts +0 -3319
- package/src/runtime/targets/container/build.ts +0 -146
- package/src/runtime/targets/container/server.ts +0 -33
- package/src/runtime/targets/vps/deploy.ts +0 -223
- package/src/templates/skills/agentkit-deploy/SKILL.md +0 -52
- package/src/templates/skills/agentkit-integrations/SKILL.md +0 -98
package/src/cli/cloud-client.ts
DELETED
|
@@ -1,377 +0,0 @@
|
|
|
1
|
-
import { chmod, mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
2
|
-
import { homedir } from "node:os";
|
|
3
|
-
import { join } from "node:path";
|
|
4
|
-
|
|
5
|
-
import { AgentKitError } from "../runtime/errors";
|
|
6
|
-
import { defaultAgentKitCloudApiUrl } from "./constants";
|
|
7
|
-
import { parseCloudApiUrl } from "./flags";
|
|
8
|
-
|
|
9
|
-
export type CloudAuthConfig = {
|
|
10
|
-
apiUrl: string;
|
|
11
|
-
token: string;
|
|
12
|
-
source?: "environment" | "file";
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
export type CloudMeResponse = {
|
|
16
|
-
account?: {
|
|
17
|
-
email?: string;
|
|
18
|
-
status?: string;
|
|
19
|
-
};
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
export type CloudCapabilitiesResponse = {
|
|
23
|
-
capabilities?: Array<{
|
|
24
|
-
name?: string;
|
|
25
|
-
status?: string;
|
|
26
|
-
}>;
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
export type CloudLimitsResponse = {
|
|
30
|
-
online_agents?: {
|
|
31
|
-
account?: {
|
|
32
|
-
used?: number | null;
|
|
33
|
-
limit?: number | null;
|
|
34
|
-
};
|
|
35
|
-
global?: {
|
|
36
|
-
used?: number | null;
|
|
37
|
-
limit?: number | null;
|
|
38
|
-
};
|
|
39
|
-
};
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
export type CloudManagedComposioResponse = {
|
|
43
|
-
managed_composio?: {
|
|
44
|
-
entitlement?: "active" | "missing" | string;
|
|
45
|
-
api_key?: "set" | "missing" | string;
|
|
46
|
-
toolkits?: Array<{
|
|
47
|
-
toolkit?: string;
|
|
48
|
-
auth_config_env?: string;
|
|
49
|
-
auth_config?: "set" | "missing" | string;
|
|
50
|
-
auth_config_source?: "project" | "account" | "global" | "env" | string;
|
|
51
|
-
}>;
|
|
52
|
-
};
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
export type CloudProjectResolveResponse = {
|
|
56
|
-
project?: {
|
|
57
|
-
id?: string;
|
|
58
|
-
name?: string;
|
|
59
|
-
owner_state?: "anonymous" | "claimed";
|
|
60
|
-
};
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
export type DeployAccessTokenCreateResponse = {
|
|
64
|
-
access_token?: {
|
|
65
|
-
id?: string;
|
|
66
|
-
deploy_id?: string;
|
|
67
|
-
account_id?: string;
|
|
68
|
-
name?: string;
|
|
69
|
-
token?: string;
|
|
70
|
-
created_at?: string;
|
|
71
|
-
expires_at?: string;
|
|
72
|
-
last_used_at?: string;
|
|
73
|
-
};
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
export type DeployAccessTokenListResponse = {
|
|
77
|
-
access_tokens?: Array<{
|
|
78
|
-
id?: string;
|
|
79
|
-
deploy_id?: string;
|
|
80
|
-
account_id?: string;
|
|
81
|
-
name?: string;
|
|
82
|
-
created_at?: string;
|
|
83
|
-
expires_at?: string;
|
|
84
|
-
last_used_at?: string;
|
|
85
|
-
}>;
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
export type AccountApiTokenCreateResponse = {
|
|
89
|
-
token?: {
|
|
90
|
-
id?: string;
|
|
91
|
-
account_id?: string;
|
|
92
|
-
name?: string;
|
|
93
|
-
token?: string;
|
|
94
|
-
created_at?: string;
|
|
95
|
-
expires_at?: string;
|
|
96
|
-
last_used_at?: string;
|
|
97
|
-
};
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
export type AccountApiTokenListResponse = {
|
|
101
|
-
tokens?: Array<{
|
|
102
|
-
id?: string;
|
|
103
|
-
account_id?: string;
|
|
104
|
-
name?: string;
|
|
105
|
-
created_at?: string;
|
|
106
|
-
expires_at?: string;
|
|
107
|
-
last_used_at?: string;
|
|
108
|
-
revoked_at?: string;
|
|
109
|
-
}>;
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
export type BillingCheckoutResponse = {
|
|
113
|
-
checkout?: {
|
|
114
|
-
id?: string;
|
|
115
|
-
url?: string;
|
|
116
|
-
};
|
|
117
|
-
billing_intent?: {
|
|
118
|
-
id?: string;
|
|
119
|
-
account_id?: string;
|
|
120
|
-
email?: string;
|
|
121
|
-
requested_slots?: number;
|
|
122
|
-
status?: string;
|
|
123
|
-
secret?: string;
|
|
124
|
-
};
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
export type BillingCheckoutIntentResponse = {
|
|
128
|
-
billing_intent?: {
|
|
129
|
-
id?: string;
|
|
130
|
-
account_id?: string;
|
|
131
|
-
email?: string;
|
|
132
|
-
requested_slots?: number;
|
|
133
|
-
status?: string;
|
|
134
|
-
checkout_session_id?: string;
|
|
135
|
-
stripe_customer_id?: string;
|
|
136
|
-
stripe_subscription_id?: string;
|
|
137
|
-
completed_at?: string;
|
|
138
|
-
token_claimed_at?: string;
|
|
139
|
-
};
|
|
140
|
-
};
|
|
141
|
-
|
|
142
|
-
export type BillingClaimResponse = BillingCheckoutIntentResponse & AccountApiTokenCreateResponse;
|
|
143
|
-
|
|
144
|
-
export type BillingPortalResponse = {
|
|
145
|
-
portal?: {
|
|
146
|
-
url?: string;
|
|
147
|
-
};
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
export type CloudSecretsResponse = {
|
|
151
|
-
secrets?: Array<{
|
|
152
|
-
name?: string;
|
|
153
|
-
status?: string;
|
|
154
|
-
updated_at?: string;
|
|
155
|
-
}>;
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
export type FeedbackSendResponse = {
|
|
159
|
-
feedback?: {
|
|
160
|
-
id?: string;
|
|
161
|
-
account_id?: string;
|
|
162
|
-
kind?: string;
|
|
163
|
-
summary?: string;
|
|
164
|
-
status?: string;
|
|
165
|
-
client_report_id?: string;
|
|
166
|
-
created_at?: string;
|
|
167
|
-
};
|
|
168
|
-
};
|
|
169
|
-
|
|
170
|
-
export function cloudAuthPath(): string {
|
|
171
|
-
return join(homedir(), ".agentkit", "cloud.json");
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
export async function readCloudAuth(): Promise<CloudAuthConfig | null> {
|
|
175
|
-
if (process.env.AGENTKIT_CLOUD_API_TOKEN) {
|
|
176
|
-
return {
|
|
177
|
-
apiUrl: process.env.AGENTKIT_CLOUD_API_URL ?? defaultAgentKitCloudApiUrl,
|
|
178
|
-
token: process.env.AGENTKIT_CLOUD_API_TOKEN,
|
|
179
|
-
source: "environment",
|
|
180
|
-
};
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
try {
|
|
184
|
-
const parsed = JSON.parse(await readFile(cloudAuthPath(), "utf8"));
|
|
185
|
-
|
|
186
|
-
if (parsed && typeof parsed === "object" && typeof parsed.token === "string") {
|
|
187
|
-
return {
|
|
188
|
-
apiUrl: typeof parsed.apiUrl === "string" ? parsed.apiUrl : defaultAgentKitCloudApiUrl,
|
|
189
|
-
token: parsed.token,
|
|
190
|
-
source: "file",
|
|
191
|
-
};
|
|
192
|
-
}
|
|
193
|
-
} catch {
|
|
194
|
-
return null;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
return null;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
export async function readCloudAuthForApiUrl(apiUrl: string): Promise<CloudAuthConfig | null> {
|
|
201
|
-
const auth = await readCloudAuth();
|
|
202
|
-
|
|
203
|
-
if (auth?.source === "file" && !cloudAuthMatchesApiUrl(auth, apiUrl)) {
|
|
204
|
-
return null;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
return auth;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
export async function writeCloudAuth(config: CloudAuthConfig): Promise<void> {
|
|
211
|
-
await mkdir(join(homedir(), ".agentkit"), { recursive: true });
|
|
212
|
-
await writeFile(cloudAuthPath(), `${JSON.stringify(config, null, 2)}\n`, { mode: 0o600 });
|
|
213
|
-
await chmod(cloudAuthPath(), 0o600);
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
export async function clearCloudAuth(): Promise<void> {
|
|
217
|
-
await rm(cloudAuthPath(), { force: true });
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
export async function resolveCloudApiUrl(flag: string | boolean | undefined): Promise<string> {
|
|
221
|
-
if (flag !== undefined) {
|
|
222
|
-
return parseCloudApiUrl(flag);
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
const auth = await readCloudAuth();
|
|
226
|
-
return auth?.apiUrl ?? parseCloudApiUrl(undefined);
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
export async function verifyCloudLogin(
|
|
230
|
-
apiUrl: string,
|
|
231
|
-
token: string,
|
|
232
|
-
): Promise<{ me: CloudMeResponse; capabilities: CloudCapabilitiesResponse }> {
|
|
233
|
-
const me = await cloudApiRequestWithToken<CloudMeResponse>(apiUrl, "/v1/me", token, { method: "GET" });
|
|
234
|
-
const capabilities = await cloudApiRequestWithToken<CloudCapabilitiesResponse>(
|
|
235
|
-
apiUrl,
|
|
236
|
-
"/v1/me/capabilities",
|
|
237
|
-
token,
|
|
238
|
-
{ method: "GET" },
|
|
239
|
-
);
|
|
240
|
-
|
|
241
|
-
return { me, capabilities };
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
export async function cloudGet<T>(apiUrl: string, path: string): Promise<T> {
|
|
245
|
-
const response = await cloudFetch(apiUrl, path);
|
|
246
|
-
const payload = await response.json();
|
|
247
|
-
|
|
248
|
-
if (!response.ok) {
|
|
249
|
-
throw new Error(readCloudError(payload, response.status));
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
return payload as T;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
export async function cloudPost<T>(apiUrl: string, path: string, body: unknown): Promise<T> {
|
|
256
|
-
const response = await cloudFetch(apiUrl, path, {
|
|
257
|
-
method: "POST",
|
|
258
|
-
headers: { "Content-Type": "application/json" },
|
|
259
|
-
body: JSON.stringify(body),
|
|
260
|
-
});
|
|
261
|
-
const payload = await response.json();
|
|
262
|
-
|
|
263
|
-
if (!response.ok) {
|
|
264
|
-
throw new Error(readCloudError(payload, response.status));
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
return payload as T;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
export async function cloudFetch(apiUrl: string, path: string, init: RequestInit = {}): Promise<Response> {
|
|
271
|
-
const headers = new Headers(init.headers);
|
|
272
|
-
const auth = await readCloudAuthForApiUrl(apiUrl);
|
|
273
|
-
const apiToken = auth?.token;
|
|
274
|
-
|
|
275
|
-
if (apiToken && !headers.has("Authorization")) {
|
|
276
|
-
headers.set("Authorization", `Bearer ${apiToken}`);
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
return fetch(new URL(path, parseCloudApiUrl(apiUrl)).href, {
|
|
280
|
-
...init,
|
|
281
|
-
headers,
|
|
282
|
-
});
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
function cloudAuthMatchesApiUrl(auth: CloudAuthConfig, apiUrl: string): boolean {
|
|
286
|
-
return parseCloudApiUrl(auth.apiUrl) === parseCloudApiUrl(apiUrl);
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
export async function cloudApiRequest(apiUrl: string, path: string, init: RequestInit): Promise<unknown> {
|
|
290
|
-
const auth = await readCloudAuthForApiUrl(apiUrl);
|
|
291
|
-
const headers = new Headers(init.headers);
|
|
292
|
-
const apiToken = auth?.token;
|
|
293
|
-
|
|
294
|
-
if (!headers.has("Content-Type") && init.body !== undefined) {
|
|
295
|
-
headers.set("Content-Type", "application/json");
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
if (apiToken && !headers.has("Authorization")) {
|
|
299
|
-
headers.set("Authorization", `Bearer ${apiToken}`);
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
const response = await fetch(new URL(path, parseCloudApiUrl(apiUrl)).href, {
|
|
303
|
-
...init,
|
|
304
|
-
headers,
|
|
305
|
-
});
|
|
306
|
-
const payload = await response.json().catch(() => null);
|
|
307
|
-
|
|
308
|
-
if (!response.ok) {
|
|
309
|
-
const code =
|
|
310
|
-
payload && typeof payload === "object" && "error" in payload
|
|
311
|
-
? String((payload as { error?: { code?: unknown } }).error?.code ?? "cloud_request_failed")
|
|
312
|
-
: "cloud_request_failed";
|
|
313
|
-
let message = readCloudError(payload, response.status);
|
|
314
|
-
|
|
315
|
-
if (code === "auth_token_invalid") {
|
|
316
|
-
message = `${message} Token source: ${auth ? formatCloudAuthSource(auth) : "none"}. Run: agentkit login --token <token>`;
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
throw new AgentKitError(code, message);
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
return payload;
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
export async function cloudApiRequestWithToken<T>(
|
|
326
|
-
apiUrl: string,
|
|
327
|
-
path: string,
|
|
328
|
-
token: string,
|
|
329
|
-
init: RequestInit,
|
|
330
|
-
): Promise<T> {
|
|
331
|
-
const headers = new Headers(init.headers);
|
|
332
|
-
|
|
333
|
-
if (!headers.has("Content-Type") && init.body !== undefined) {
|
|
334
|
-
headers.set("Content-Type", "application/json");
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
headers.set("Authorization", `Bearer ${token}`);
|
|
338
|
-
|
|
339
|
-
const response = await fetch(new URL(path, parseCloudApiUrl(apiUrl)).href, {
|
|
340
|
-
...init,
|
|
341
|
-
headers,
|
|
342
|
-
});
|
|
343
|
-
const payload = await response.json().catch(() => null);
|
|
344
|
-
|
|
345
|
-
if (!response.ok) {
|
|
346
|
-
const code =
|
|
347
|
-
payload && typeof payload === "object" && "error" in payload
|
|
348
|
-
? String((payload as { error?: { code?: unknown } }).error?.code ?? "cloud_request_failed")
|
|
349
|
-
: "cloud_request_failed";
|
|
350
|
-
throw new AgentKitError(code, readCloudError(payload, response.status));
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
return payload as T;
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
export function readCloudError(payload: unknown, status: number): string {
|
|
357
|
-
if (payload && typeof payload === "object" && "error" in payload) {
|
|
358
|
-
const error = (payload as { error?: { message?: unknown } }).error;
|
|
359
|
-
if (typeof error?.message === "string") {
|
|
360
|
-
return error.message;
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
return `AgentKit Cloud request failed with HTTP ${status}.`;
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
export function formatCloudAuthSource(auth: CloudAuthConfig): string {
|
|
368
|
-
if (auth.source === "environment") {
|
|
369
|
-
return "AGENTKIT_CLOUD_API_TOKEN";
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
if (auth.source === "file") {
|
|
373
|
-
return cloudAuthPath();
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
return "AgentKit Cloud auth";
|
|
377
|
-
}
|