@madewithremy/admin 0.1.5 → 0.1.7
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.d.ts +531 -26
- package/dist/index.js +279 -29
- package/dist/index.js.map +1 -1
- package/dist/prod.js +673 -35
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -89,6 +89,16 @@ var AdminTimeoutError = class extends Error {
|
|
|
89
89
|
|
|
90
90
|
// src/http.ts
|
|
91
91
|
var REQUEST_TIMEOUT_MS = 3e4;
|
|
92
|
+
var TRANSIENT_GRACE_MS = 2 * 6e4;
|
|
93
|
+
function isTransientError(err) {
|
|
94
|
+
if (err instanceof AdminApiError) {
|
|
95
|
+
return err.status >= 500;
|
|
96
|
+
}
|
|
97
|
+
if (err instanceof AdminTimeoutError) {
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
return err instanceof TypeError;
|
|
101
|
+
}
|
|
92
102
|
var REPORT_TIMEOUT_MS = 6e4;
|
|
93
103
|
function seg(value) {
|
|
94
104
|
return encodeURIComponent(String(value));
|
|
@@ -350,19 +360,24 @@ function liftFromLive(ctx, params = {}) {
|
|
|
350
360
|
var dataSources_exports = {};
|
|
351
361
|
__export(dataSources_exports, {
|
|
352
362
|
DEFAULT_WAIT_TIMEOUT_MS: () => DEFAULT_WAIT_TIMEOUT_MS,
|
|
363
|
+
DOCUMENTS_IDS_MAX: () => DOCUMENTS_IDS_MAX,
|
|
353
364
|
addDocument: () => addDocument,
|
|
365
|
+
allDocuments: () => allDocuments,
|
|
354
366
|
configGet: () => configGet,
|
|
355
367
|
configSet: () => configSet,
|
|
368
|
+
create: () => create,
|
|
356
369
|
deleteSource: () => deleteSource,
|
|
357
370
|
documents: () => documents,
|
|
358
371
|
drop: () => drop,
|
|
359
372
|
list: () => list3,
|
|
373
|
+
move: () => move,
|
|
360
374
|
promote: () => promote,
|
|
361
375
|
revectorize: () => revectorize,
|
|
362
376
|
rm: () => rm,
|
|
363
377
|
search: () => search,
|
|
364
378
|
summarize: () => summarize,
|
|
365
|
-
waitForIngest: () => waitForIngest
|
|
379
|
+
waitForIngest: () => waitForIngest,
|
|
380
|
+
waitForMove: () => waitForMove
|
|
366
381
|
});
|
|
367
382
|
import { createHash } from "crypto";
|
|
368
383
|
|
|
@@ -456,12 +471,26 @@ async function waitForIngest(ctx, params) {
|
|
|
456
471
|
}
|
|
457
472
|
const wanted = new Set(documentIds);
|
|
458
473
|
const start = Date.now();
|
|
474
|
+
let transientSince = null;
|
|
459
475
|
for (; ; ) {
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
)
|
|
476
|
+
let docs;
|
|
477
|
+
try {
|
|
478
|
+
docs = await allDocuments(ctx, { slug, ids: documentIds });
|
|
479
|
+
transientSince = null;
|
|
480
|
+
} catch (err) {
|
|
481
|
+
if (!isTransientError(err)) {
|
|
482
|
+
throw err;
|
|
483
|
+
}
|
|
484
|
+
transientSince ??= Date.now();
|
|
485
|
+
if (Date.now() - transientSince > TRANSIENT_GRACE_MS) {
|
|
486
|
+
throw err;
|
|
487
|
+
}
|
|
488
|
+
onProgress?.(
|
|
489
|
+
`retrying after a gateway error\u2026 (${Math.round((Date.now() - start) / 1e3)}s)`
|
|
490
|
+
);
|
|
491
|
+
await sleep(POLL_MS);
|
|
492
|
+
continue;
|
|
493
|
+
}
|
|
465
494
|
const tracked = (docs ?? []).filter((d) => wanted.has(d.id));
|
|
466
495
|
const pending = tracked.filter((d) => d.status === "processing");
|
|
467
496
|
const failed = tracked.filter((d) => d.status === "error");
|
|
@@ -486,12 +515,41 @@ async function waitForIngest(ctx, params) {
|
|
|
486
515
|
await sleep(POLL_MS);
|
|
487
516
|
}
|
|
488
517
|
}
|
|
518
|
+
var DOCUMENTS_IDS_MAX = 200;
|
|
489
519
|
function documents(ctx, params) {
|
|
490
520
|
return call(
|
|
491
521
|
ctx,
|
|
492
522
|
"GET",
|
|
493
|
-
`${base(ctx.appId)}/documents${qs({
|
|
494
|
-
|
|
523
|
+
`${base(ctx.appId)}/documents${qs({
|
|
524
|
+
slug: params.slug,
|
|
525
|
+
candidate: params.candidate || void 0,
|
|
526
|
+
ids: params.ids?.length ? params.ids.join(",") : void 0,
|
|
527
|
+
limit: params.limit,
|
|
528
|
+
cursor: params.cursor
|
|
529
|
+
})}`
|
|
530
|
+
);
|
|
531
|
+
}
|
|
532
|
+
async function allDocuments(ctx, params) {
|
|
533
|
+
const groups = params.ids ? Array.from(
|
|
534
|
+
{ length: Math.ceil(params.ids.length / DOCUMENTS_IDS_MAX) },
|
|
535
|
+
(_, i) => params.ids.slice(i * DOCUMENTS_IDS_MAX, (i + 1) * DOCUMENTS_IDS_MAX)
|
|
536
|
+
) : [void 0];
|
|
537
|
+
const out = [];
|
|
538
|
+
for (const ids of groups) {
|
|
539
|
+
let cursor;
|
|
540
|
+
do {
|
|
541
|
+
const page = await documents(ctx, {
|
|
542
|
+
slug: params.slug,
|
|
543
|
+
candidate: params.candidate,
|
|
544
|
+
ids,
|
|
545
|
+
limit: 1e3,
|
|
546
|
+
cursor
|
|
547
|
+
});
|
|
548
|
+
out.push(...page.documents ?? []);
|
|
549
|
+
cursor = page.nextCursor ?? void 0;
|
|
550
|
+
} while (cursor);
|
|
551
|
+
}
|
|
552
|
+
return out;
|
|
495
553
|
}
|
|
496
554
|
function list3(ctx) {
|
|
497
555
|
return call(ctx, "GET", base(ctx.appId));
|
|
@@ -533,7 +591,7 @@ function configGet(ctx, slug) {
|
|
|
533
591
|
);
|
|
534
592
|
}
|
|
535
593
|
function configSet(ctx, params) {
|
|
536
|
-
const { slug, ingest, retrieval } = params;
|
|
594
|
+
const { slug, ingest, retrieval, placement } = params;
|
|
537
595
|
return call(
|
|
538
596
|
ctx,
|
|
539
597
|
"POST",
|
|
@@ -541,10 +599,75 @@ function configSet(ctx, params) {
|
|
|
541
599
|
{
|
|
542
600
|
slug,
|
|
543
601
|
...ingest ? { ingest } : {},
|
|
544
|
-
...retrieval ? { retrieval } : {}
|
|
602
|
+
...retrieval ? { retrieval } : {},
|
|
603
|
+
...placement !== void 0 ? { placement } : {}
|
|
545
604
|
}
|
|
546
605
|
);
|
|
547
606
|
}
|
|
607
|
+
function create(ctx, params) {
|
|
608
|
+
const { slug, name, ingest, placement } = params;
|
|
609
|
+
return call(ctx, "POST", base(ctx.appId), {
|
|
610
|
+
slug,
|
|
611
|
+
...name ? { name } : {},
|
|
612
|
+
...ingest ? { ingest } : {},
|
|
613
|
+
...placement !== void 0 ? { placement } : {}
|
|
614
|
+
});
|
|
615
|
+
}
|
|
616
|
+
function move(ctx, params) {
|
|
617
|
+
return call(ctx, "POST", `${base(ctx.appId)}/move`, {
|
|
618
|
+
slug: params.slug,
|
|
619
|
+
placement: params.placement
|
|
620
|
+
});
|
|
621
|
+
}
|
|
622
|
+
async function waitForMove(ctx, params) {
|
|
623
|
+
const timeoutMs = params.timeoutMs ?? DEFAULT_WAIT_TIMEOUT_MS;
|
|
624
|
+
const start = Date.now();
|
|
625
|
+
let transientSince = null;
|
|
626
|
+
for (; ; ) {
|
|
627
|
+
let source;
|
|
628
|
+
try {
|
|
629
|
+
const { dataSources } = await list3(ctx);
|
|
630
|
+
source = dataSources.find((s) => s.slug === params.slug);
|
|
631
|
+
transientSince = null;
|
|
632
|
+
} catch (err) {
|
|
633
|
+
if (!isTransientError(err)) {
|
|
634
|
+
throw err;
|
|
635
|
+
}
|
|
636
|
+
transientSince ??= Date.now();
|
|
637
|
+
if (Date.now() - transientSince > TRANSIENT_GRACE_MS) {
|
|
638
|
+
throw err;
|
|
639
|
+
}
|
|
640
|
+
params.onProgress?.(
|
|
641
|
+
`retrying after a gateway error\u2026 (${Math.round((Date.now() - start) / 1e3)}s)`
|
|
642
|
+
);
|
|
643
|
+
await sleep(POLL_MS);
|
|
644
|
+
continue;
|
|
645
|
+
}
|
|
646
|
+
if (!source) {
|
|
647
|
+
throw new Error(`Data source "${params.slug}" not found.`);
|
|
648
|
+
}
|
|
649
|
+
const migration = source.migration;
|
|
650
|
+
if (!migration) {
|
|
651
|
+
return { status: "done", source };
|
|
652
|
+
}
|
|
653
|
+
if (migration.error) {
|
|
654
|
+
return { status: "failed", source, error: migration.error };
|
|
655
|
+
}
|
|
656
|
+
if (Date.now() - start > timeoutMs) {
|
|
657
|
+
return {
|
|
658
|
+
status: "timeout",
|
|
659
|
+
source,
|
|
660
|
+
error: `Timed out after ${Math.round(timeoutMs / 1e3)}s with ${migration.copied}/${migration.total} documents copied`
|
|
661
|
+
};
|
|
662
|
+
}
|
|
663
|
+
params.onProgress?.(
|
|
664
|
+
`moving\u2026 ${migration.copied}/${migration.total} documents (${Math.round(
|
|
665
|
+
(Date.now() - start) / 1e3
|
|
666
|
+
)}s)`
|
|
667
|
+
);
|
|
668
|
+
await sleep(POLL_MS);
|
|
669
|
+
}
|
|
670
|
+
}
|
|
548
671
|
function revectorize(ctx, params) {
|
|
549
672
|
const { slug, ingest } = params;
|
|
550
673
|
return call(
|
|
@@ -681,7 +804,9 @@ function summarizeRelease(release) {
|
|
|
681
804
|
}
|
|
682
805
|
return {
|
|
683
806
|
...summary2,
|
|
684
|
-
error: buildFailureReason(release) ?? "Build failed (no error entry in the build log)"
|
|
807
|
+
error: release.failureReason ?? buildFailureReason(release) ?? "Build failed (no error entry in the build log)",
|
|
808
|
+
...release.failureKind ? { failureKind: release.failureKind } : {},
|
|
809
|
+
...release.failurePhase ? { failurePhase: release.failurePhase } : {}
|
|
685
810
|
};
|
|
686
811
|
}
|
|
687
812
|
var POLL_MS2 = 3e3;
|
|
@@ -1101,33 +1226,157 @@ function remove(ctx, ref) {
|
|
|
1101
1226
|
);
|
|
1102
1227
|
}
|
|
1103
1228
|
|
|
1229
|
+
// src/ops/infra.ts
|
|
1230
|
+
var infra_exports = {};
|
|
1231
|
+
__export(infra_exports, {
|
|
1232
|
+
DEFAULT_WAIT_TIMEOUT_MS: () => DEFAULT_WAIT_TIMEOUT_MS2,
|
|
1233
|
+
destroy: () => destroy,
|
|
1234
|
+
get: () => get5,
|
|
1235
|
+
hibernate: () => hibernate,
|
|
1236
|
+
list: () => list6,
|
|
1237
|
+
provision: () => provision,
|
|
1238
|
+
rename: () => rename,
|
|
1239
|
+
resize: () => resize,
|
|
1240
|
+
resume: () => resume,
|
|
1241
|
+
waitForPhase: () => waitForPhase
|
|
1242
|
+
});
|
|
1243
|
+
var DEFAULT_WAIT_TIMEOUT_MS2 = 10 * 60 * 1e3;
|
|
1244
|
+
var POLL_MS3 = 3e3;
|
|
1245
|
+
function base2(appId) {
|
|
1246
|
+
return `/_internal/v2/apps/${appId}/infra`;
|
|
1247
|
+
}
|
|
1248
|
+
function list6(ctx, params) {
|
|
1249
|
+
return call(
|
|
1250
|
+
ctx,
|
|
1251
|
+
"GET",
|
|
1252
|
+
`${base2(ctx.appId)}${params?.includeDestroyed ? "?includeDestroyed=true" : ""}`
|
|
1253
|
+
);
|
|
1254
|
+
}
|
|
1255
|
+
function get5(ctx, params) {
|
|
1256
|
+
return call(
|
|
1257
|
+
ctx,
|
|
1258
|
+
"GET",
|
|
1259
|
+
`${base2(ctx.appId)}/${encodeURIComponent(params.id)}`
|
|
1260
|
+
);
|
|
1261
|
+
}
|
|
1262
|
+
function provision(ctx, params) {
|
|
1263
|
+
return call(ctx, "POST", base2(ctx.appId), {
|
|
1264
|
+
offeringId: params.offeringId,
|
|
1265
|
+
...params.name ? { name: params.name } : {}
|
|
1266
|
+
});
|
|
1267
|
+
}
|
|
1268
|
+
function hibernate(ctx, params) {
|
|
1269
|
+
return call(
|
|
1270
|
+
ctx,
|
|
1271
|
+
"POST",
|
|
1272
|
+
`${base2(ctx.appId)}/${encodeURIComponent(params.id)}/hibernate`
|
|
1273
|
+
);
|
|
1274
|
+
}
|
|
1275
|
+
function resume(ctx, params) {
|
|
1276
|
+
return call(
|
|
1277
|
+
ctx,
|
|
1278
|
+
"POST",
|
|
1279
|
+
`${base2(ctx.appId)}/${encodeURIComponent(params.id)}/resume`
|
|
1280
|
+
);
|
|
1281
|
+
}
|
|
1282
|
+
function destroy(ctx, params) {
|
|
1283
|
+
return call(
|
|
1284
|
+
ctx,
|
|
1285
|
+
"POST",
|
|
1286
|
+
`${base2(ctx.appId)}/${encodeURIComponent(params.id)}/destroy`
|
|
1287
|
+
);
|
|
1288
|
+
}
|
|
1289
|
+
function resize(ctx, params) {
|
|
1290
|
+
return call(
|
|
1291
|
+
ctx,
|
|
1292
|
+
"POST",
|
|
1293
|
+
`${base2(ctx.appId)}/${encodeURIComponent(params.id)}/resize`,
|
|
1294
|
+
{ offeringId: params.offeringId }
|
|
1295
|
+
);
|
|
1296
|
+
}
|
|
1297
|
+
function rename(ctx, params) {
|
|
1298
|
+
return call(
|
|
1299
|
+
ctx,
|
|
1300
|
+
"POST",
|
|
1301
|
+
`${base2(ctx.appId)}/${encodeURIComponent(params.id)}/rename`,
|
|
1302
|
+
{ name: params.name }
|
|
1303
|
+
);
|
|
1304
|
+
}
|
|
1305
|
+
async function waitForPhase(ctx, params) {
|
|
1306
|
+
const timeoutMs = params.timeoutMs ?? DEFAULT_WAIT_TIMEOUT_MS2;
|
|
1307
|
+
const wanted = new Set(params.phases);
|
|
1308
|
+
const start = Date.now();
|
|
1309
|
+
let transientSince = null;
|
|
1310
|
+
for (; ; ) {
|
|
1311
|
+
let resource;
|
|
1312
|
+
try {
|
|
1313
|
+
({ resource } = await get5(ctx, { id: params.id }));
|
|
1314
|
+
transientSince = null;
|
|
1315
|
+
} catch (err) {
|
|
1316
|
+
if (!isTransientError(err)) {
|
|
1317
|
+
throw err;
|
|
1318
|
+
}
|
|
1319
|
+
transientSince ??= Date.now();
|
|
1320
|
+
if (Date.now() - transientSince > TRANSIENT_GRACE_MS) {
|
|
1321
|
+
throw err;
|
|
1322
|
+
}
|
|
1323
|
+
params.onProgress?.(
|
|
1324
|
+
`retrying after a gateway error\u2026 (${Math.round((Date.now() - start) / 1e3)}s)`
|
|
1325
|
+
);
|
|
1326
|
+
await sleep(POLL_MS3);
|
|
1327
|
+
continue;
|
|
1328
|
+
}
|
|
1329
|
+
if (wanted.has(resource.phase) && (params.until?.(resource) ?? true)) {
|
|
1330
|
+
return { status: "done", resource };
|
|
1331
|
+
}
|
|
1332
|
+
if (resource.phase === "failed") {
|
|
1333
|
+
return {
|
|
1334
|
+
status: "failed",
|
|
1335
|
+
resource,
|
|
1336
|
+
error: resource.lastError ?? "The platform could not complete the change."
|
|
1337
|
+
};
|
|
1338
|
+
}
|
|
1339
|
+
if (Date.now() - start > timeoutMs) {
|
|
1340
|
+
return {
|
|
1341
|
+
status: "timeout",
|
|
1342
|
+
resource,
|
|
1343
|
+
error: `Timed out after ${Math.round(timeoutMs / 1e3)}s; resource is still ${resource.phase}`
|
|
1344
|
+
};
|
|
1345
|
+
}
|
|
1346
|
+
params.onProgress?.(
|
|
1347
|
+
`${resource.phase}${resource.detail ? ` \xB7 ${resource.detail}` : ""}${resource.resizingTo ? ` \xB7 resizing to ${resource.resizingTo.label}` : ""}\u2026 (${Math.round((Date.now() - start) / 1e3)}s)`
|
|
1348
|
+
);
|
|
1349
|
+
await sleep(POLL_MS3);
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1104
1353
|
// src/ops/issues.ts
|
|
1105
1354
|
var issues_exports = {};
|
|
1106
1355
|
__export(issues_exports, {
|
|
1107
1356
|
close: () => close,
|
|
1108
1357
|
comment: () => comment,
|
|
1109
|
-
create: () =>
|
|
1358
|
+
create: () => create2,
|
|
1110
1359
|
del: () => del,
|
|
1111
1360
|
edit: () => edit,
|
|
1112
|
-
get: () =>
|
|
1113
|
-
list: () =>
|
|
1361
|
+
get: () => get6,
|
|
1362
|
+
list: () => list7,
|
|
1114
1363
|
reopen: () => reopen
|
|
1115
1364
|
});
|
|
1116
|
-
function
|
|
1365
|
+
function list7(ctx, params = {}) {
|
|
1117
1366
|
return call(
|
|
1118
1367
|
ctx,
|
|
1119
1368
|
"GET",
|
|
1120
1369
|
`/_internal/v2/apps/${ctx.appId}/issues${qs(params)}`
|
|
1121
1370
|
);
|
|
1122
1371
|
}
|
|
1123
|
-
function
|
|
1372
|
+
function get6(ctx, number) {
|
|
1124
1373
|
return call(
|
|
1125
1374
|
ctx,
|
|
1126
1375
|
"GET",
|
|
1127
1376
|
`/_internal/v2/apps/${ctx.appId}/issues/${seg(number)}`
|
|
1128
1377
|
);
|
|
1129
1378
|
}
|
|
1130
|
-
function
|
|
1379
|
+
function create2(ctx, params) {
|
|
1131
1380
|
const requestBody = {
|
|
1132
1381
|
title: params.title,
|
|
1133
1382
|
authorKind: "agent"
|
|
@@ -1322,9 +1571,9 @@ function grade(ctx, runId) {
|
|
|
1322
1571
|
var methods_exports = {};
|
|
1323
1572
|
__export(methods_exports, {
|
|
1324
1573
|
invoke: () => invoke,
|
|
1325
|
-
list: () =>
|
|
1574
|
+
list: () => list8
|
|
1326
1575
|
});
|
|
1327
|
-
async function
|
|
1576
|
+
async function list8(ctx) {
|
|
1328
1577
|
const dashboard = await call(
|
|
1329
1578
|
ctx,
|
|
1330
1579
|
"GET",
|
|
@@ -1381,19 +1630,19 @@ function invalidate(ctx, params = {}) {
|
|
|
1381
1630
|
// src/ops/requests.ts
|
|
1382
1631
|
var requests_exports = {};
|
|
1383
1632
|
__export(requests_exports, {
|
|
1384
|
-
get: () =>
|
|
1385
|
-
list: () =>
|
|
1633
|
+
get: () => get7,
|
|
1634
|
+
list: () => list9,
|
|
1386
1635
|
statsForMethod: () => statsForMethod,
|
|
1387
1636
|
statsSummary: () => statsSummary
|
|
1388
1637
|
});
|
|
1389
|
-
function
|
|
1638
|
+
function list9(ctx, params = {}) {
|
|
1390
1639
|
return call(
|
|
1391
1640
|
ctx,
|
|
1392
1641
|
"GET",
|
|
1393
1642
|
`/_internal/v2/apps/${ctx.appId}/requests${qs(params)}`
|
|
1394
1643
|
);
|
|
1395
1644
|
}
|
|
1396
|
-
function
|
|
1645
|
+
function get7(ctx, requestId) {
|
|
1397
1646
|
return call(
|
|
1398
1647
|
ctx,
|
|
1399
1648
|
"GET",
|
|
@@ -1419,18 +1668,18 @@ function statsForMethod(ctx, methodId, params = {}) {
|
|
|
1419
1668
|
var secrets_exports = {};
|
|
1420
1669
|
__export(secrets_exports, {
|
|
1421
1670
|
del: () => del2,
|
|
1422
|
-
get: () =>
|
|
1423
|
-
list: () =>
|
|
1671
|
+
get: () => get8,
|
|
1672
|
+
list: () => list10,
|
|
1424
1673
|
set: () => set2
|
|
1425
1674
|
});
|
|
1426
|
-
function
|
|
1675
|
+
function list10(ctx) {
|
|
1427
1676
|
return call(
|
|
1428
1677
|
ctx,
|
|
1429
1678
|
"GET",
|
|
1430
1679
|
`/_internal/v2/apps/${ctx.appId}/secrets`
|
|
1431
1680
|
);
|
|
1432
1681
|
}
|
|
1433
|
-
function
|
|
1682
|
+
function get8(ctx, key) {
|
|
1434
1683
|
return call(
|
|
1435
1684
|
ctx,
|
|
1436
1685
|
"GET",
|
|
@@ -1486,11 +1735,11 @@ function updateSettings(ctx, partial) {
|
|
|
1486
1735
|
var users_exports = {};
|
|
1487
1736
|
__export(users_exports, {
|
|
1488
1737
|
createApiKey: () => createApiKey,
|
|
1489
|
-
list: () =>
|
|
1738
|
+
list: () => list11,
|
|
1490
1739
|
revokeApiKey: () => revokeApiKey,
|
|
1491
1740
|
setRole: () => setRole
|
|
1492
1741
|
});
|
|
1493
|
-
function
|
|
1742
|
+
function list11(ctx, params = {}) {
|
|
1494
1743
|
return call(
|
|
1495
1744
|
ctx,
|
|
1496
1745
|
"GET",
|
|
@@ -1691,6 +1940,7 @@ function buildClient(ctx) {
|
|
|
1691
1940
|
removeDomain: (direction, domain) => removeDomain(ctx, direction, domain)
|
|
1692
1941
|
},
|
|
1693
1942
|
files: bindOps(files_exports, ctx),
|
|
1943
|
+
infra: bindOps(infra_exports, ctx),
|
|
1694
1944
|
issues: bindOps(issues_exports, ctx),
|
|
1695
1945
|
jewels: bindOps(jewels_exports, ctx),
|
|
1696
1946
|
methods: bindOps(methods_exports, ctx),
|