stim 1.9.0 → 1.10.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/dist/{android-_y4Ohi5z.mjs → android-787HhP5w.mjs} +119 -29
- package/dist/{android-BPGizezh.mjs → android-DBkeHwpm.mjs} +168 -95
- package/dist/{android-DEgo4oCo.mjs → android-DPov-fv2.mjs} +2 -2
- package/dist/{android-cas-eiExNLf7.mjs → android-cas-CITmIeWY.mjs} +9 -8
- package/dist/android-cas-compiler.mjs +1 -1
- package/dist/{app-install-Uf3a83Tv.mjs → app-install-CrJ6t_bv.mjs} +2 -2
- package/dist/budget-BP4jZZL4.mjs +620 -0
- package/dist/build-progress-BXx-ZBe4.mjs +512 -0
- package/dist/{cache-manifest-Dg7OnMrp.mjs → cache-manifest-Pubfp8wV.mjs} +1 -1
- package/dist/cache-manifest.mjs +1 -1
- package/dist/cli.mjs +16 -16
- package/dist/collector-run.d.mts +5 -1
- package/dist/collector-run.mjs +7 -7
- package/dist/{command-output-gByVmIjy.mjs → command-output-D5z2_bcF.mjs} +1 -1
- package/dist/{config-Cp9lM3wX.mjs → config-BEq0Qw_a.mjs} +14 -131
- package/dist/{dependency-state-Bq5DcLGn.mjs → dependency-state-r9UesA9a.mjs} +2 -2
- package/dist/{deps-Cip5vUm1.mjs → deps-DP4eWqea.mjs} +3 -3
- package/dist/{detached-entry-KEu0_AXL.mjs → detached-entry-DJHoca49.mjs} +1 -1
- package/dist/{dev-client-HyqISM0h.mjs → dev-client-92U593KT.mjs} +137 -250
- package/dist/{device-D4U-xLty.mjs → device-DhTZe7L4.mjs} +7 -7
- package/dist/{build-lock-DPXPLgTc.mjs → device-lease-CbEaIk7b.mjs} +370 -12
- package/dist/{device-pool-CnTAz8X1.mjs → device-pool-Di8Q-9Ro.mjs} +4 -4
- package/dist/{device-remote-AQ5rQPqr.mjs → device-remote-Dy1jGj3U.mjs} +547 -468
- package/dist/{doctor-B_Ei3bZu.mjs → doctor-B-inAJmt.mjs} +58 -22
- package/dist/{error-diagnostics-Vfz83GCF.mjs → error-diagnostics-xxWKNO3-.mjs} +11 -12
- package/dist/{exec-jIAlgilk.mjs → exec-DK8KaVHK.mjs} +3 -2
- package/dist/{gc-Ckw8RQHi.mjs → gc-ChPFZMRC.mjs} +500 -1114
- package/dist/{guide-BiAbhs1J.mjs → guide-DwmaD_Wa.mjs} +882 -528
- package/dist/guide-status-CWvti2Lg.mjs +125 -0
- package/dist/idle-DpRLp5lj.mjs +157 -0
- package/dist/in-use-CjUluqIX.mjs +245 -0
- package/dist/{ios-BL2NFckr.mjs → ios-B2Fpqvlb.mjs} +25 -59
- package/dist/{ios-BzUJWk1K.mjs → ios-Dd-hYJBh.mjs} +130 -89
- package/dist/{ios-device-DPsSm0v_.mjs → ios-device-BiOsSVzd.mjs} +1 -1
- package/dist/{ios-device-D972i9wf.mjs → ios-device-CtRdEVjx.mjs} +3 -3
- package/dist/{launch-verify-Q_OtW1Rf.mjs → launch-verify-CQS_Kg-C.mjs} +5 -5
- package/dist/{logs-CI9NQSK7.mjs → logs-MARIy6m9.mjs} +9 -9
- package/dist/{metro-DrLHaMn2.mjs → metro-BWLOJ_Wr.mjs} +116 -10
- package/dist/{named-ports-CmLQSIRj.mjs → named-ports-DiTfSz6p.mjs} +4 -4
- package/dist/{ndjson-9uFNRwfe.mjs → ndjson-CDY9IkVC.mjs} +3 -56
- package/dist/{ndjson-DvHSsNU9.d.mts → ndjson-Du3j0AQ9.d.mts} +1 -0
- package/dist/{ownership-D15Op8vN.mjs → ownership-D2xbLVoz.mjs} +2 -3
- package/dist/ownership-DZjdx8Gq.mjs +1180 -0
- package/dist/{ports-BNKoWVWZ.mjs → ports-CLSSFOuz.mjs} +3 -3
- package/dist/{project-DS112DYB.mjs → project-BXZzOABt.mjs} +2 -2
- package/dist/{reload-ZNJUo1pl.mjs → reload-DoETJ3rl.mjs} +9 -10
- package/dist/{server-bare-DWkkcIxV.mjs → server-bare-DVbb7kXH.mjs} +1 -1
- package/dist/{server-expo-B_lctBR3.mjs → server-expo-BvOCeakp.mjs} +4 -4
- package/dist/server-expo-DBVTdult.mjs +2 -0
- package/dist/{settings-D030k0t4.mjs → settings-DOugPlPz.mjs} +16 -428
- package/dist/{settings-BKNh5rl4.mjs → settings-EWYNwe72.mjs} +16 -14
- package/dist/settings.schema.json +75 -0
- package/dist/{simslim-B_LsGLuJ.mjs → simslim-Ca3487H6.mjs} +182 -5
- package/dist/{slot-launch-DU9A-gYw.mjs → slot-launch-C5cg0fmk.mjs} +4 -4
- package/dist/{spawn-claims-Dn3C_N6w.mjs → spawn-claims-CUleC2cM.mjs} +1 -1
- package/dist/{start-DYkkKF0s.mjs → start-F9gv5dcC.mjs} +147 -98
- package/dist/start-VoFsPSes.mjs +2 -0
- package/dist/{state-NcJzMEBF.mjs → state-WGdIbi_d.mjs} +2 -2
- package/dist/{stats-DG9e66Rz.mjs → stats-BAgJaLA4.mjs} +1 -1
- package/dist/{stats-B63-JVAY.mjs → stats-DBYJ5bxL.mjs} +4 -4
- package/dist/{status-S6ehL4Ui.mjs → status-DLCD-o3s.mjs} +63 -231
- package/dist/status-Dr4fRkym.mjs +216 -0
- package/dist/{guide-status-BAMVU0ZA.mjs → stim-installations-CINXy_su.mjs} +3 -124
- package/dist/{stop-BO28HGqF.mjs → stop-Dj4pfmyv.mjs} +22 -18
- package/dist/{stop-T1R-cZRz.mjs → stop-ZvOeTmKb.mjs} +2 -2
- package/dist/supervisor-run.d.mts +11 -2
- package/dist/supervisor-run.mjs +185 -17
- package/dist/{workspace-process-lock-DWaiRD0e.mjs → workspace-process-lock-BXA96myD.mjs} +2 -2
- package/dist/workspaces-BTUyFfkv.mjs +1003 -0
- package/dist/{worktree-DKhSF0UX.mjs → worktree-4aZg2NnI.mjs} +1 -1
- package/dist/{worktree-LGB-UwgG.mjs → worktree-BMS7GeqB.mjs} +40 -122
- package/dist/{worktree-R_cUlE7s.mjs → worktree-BlizKDpZ.mjs} +143 -18
- package/dist/{xcode-BZqyxh3e.mjs → xcode-B2tBkf0m.mjs} +9 -158
- package/package.json +6 -5
- package/dist/build-progress-CVqkfPC6.mjs +0 -188
- package/dist/device-lease-Crs-HkJY.mjs +0 -366
- package/dist/logs-query-Cqma3WIu.mjs +0 -298
- package/dist/ownership-DCQPuWEc.mjs +0 -489
- package/dist/public-http-probe-CyMDrQ3c.mjs +0 -61
- package/dist/server-expo-CeILEu86.mjs +0 -2
- package/dist/sim-pool-KaIsp2Ft.mjs +0 -723
- package/dist/spawn-entry-nCE6m770.mjs +0 -14
- package/dist/workspace-state-DF2gCFhx.mjs +0 -169
|
@@ -1,10 +1,116 @@
|
|
|
1
|
-
import { D as process_identity_exports,
|
|
2
|
-
import { t as getExecutor } from "./exec-
|
|
3
|
-
import {
|
|
4
|
-
import { existsSync, readlinkSync, realpathSync } from "fs";
|
|
5
|
-
import { sep } from "path";
|
|
1
|
+
import { D as process_identity_exports, M as isOnMountedVolume, N as listMountedVolumes, g as loadConfig$1, n as allMetroPorts, r as claimMetroPort, y as releaseMetroPort } from "./config-BEq0Qw_a.mjs";
|
|
2
|
+
import { t as getExecutor } from "./exec-DK8KaVHK.mjs";
|
|
3
|
+
import { existsSync, mkdirSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { existsSync as existsSync$1, readlinkSync, realpathSync as realpathSync$1 } from "fs";
|
|
5
|
+
import { join, resolve, sep } from "path";
|
|
6
|
+
import { buildCacheRoot as sharedBuildCache, withDirLock, workspaceId, workspaceName as workspaceName$1, workspaceStateDir as workspaceDir } from "@stim-cli/core";
|
|
7
|
+
import { emulatorLogFile, readJsonObject, readWorkspaceState, readWorkspaceState as readWorkspaceState$1, sharedCcache, sharedCompilationCache, supervisorLogFile, supervisorPidFile, workspaceDerivedData, workspaceLastUsed, workspaceLogErrorIndex, workspaceLogsDir, workspaceMetadataFile, workspaceStateFile, workspaceStateLock } from "@stim-cli/core/state";
|
|
8
|
+
import { dirname as dirname$1 } from "node:path";
|
|
6
9
|
import { request } from "http";
|
|
7
10
|
import { connect } from "net";
|
|
11
|
+
//#region src/workspace/paths.ts
|
|
12
|
+
function ensureWorkspaceStorage(projectRoot) {
|
|
13
|
+
const canonicalRoot = resolve(projectRoot);
|
|
14
|
+
const dir = workspaceDir(canonicalRoot);
|
|
15
|
+
const file = workspaceMetadataFile(canonicalRoot);
|
|
16
|
+
mkdirSync(dir, { recursive: true });
|
|
17
|
+
return withDirLock(join(dir, "metadata.lock"), () => {
|
|
18
|
+
if (!existsSync(file)) {
|
|
19
|
+
const metadata = {
|
|
20
|
+
projectRoot: canonicalRoot,
|
|
21
|
+
workspace: workspaceName$1(canonicalRoot),
|
|
22
|
+
version: 1
|
|
23
|
+
};
|
|
24
|
+
const tmp = `${file}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
25
|
+
writeFileSync(tmp, `${JSON.stringify(metadata, null, 2)}\n`);
|
|
26
|
+
try {
|
|
27
|
+
renameSync(tmp, file);
|
|
28
|
+
} catch (error) {
|
|
29
|
+
rmSync(tmp, { force: true });
|
|
30
|
+
throw error;
|
|
31
|
+
}
|
|
32
|
+
return dir;
|
|
33
|
+
}
|
|
34
|
+
if (readJsonObject(file)?.projectRoot === canonicalRoot) return dir;
|
|
35
|
+
const error = /* @__PURE__ */ new Error(`Stim workspace collision at ${dir}: its workspace.json does not belong to ${canonicalRoot}.`);
|
|
36
|
+
error.code = "STIM_WORKSPACE_COLLISION";
|
|
37
|
+
throw error;
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
//#endregion
|
|
41
|
+
//#region src/workspace/workspace-state.ts
|
|
42
|
+
function withWorkspaceStateLock(root, fn) {
|
|
43
|
+
const file = workspaceStateFile(root);
|
|
44
|
+
return withDirLock(workspaceStateLock(root), fn, { ensureParent: () => {
|
|
45
|
+
ensureWorkspaceStorage(root);
|
|
46
|
+
mkdirSync(dirname$1(file), { recursive: true });
|
|
47
|
+
} });
|
|
48
|
+
}
|
|
49
|
+
function writeWorkspaceState(root, patch) {
|
|
50
|
+
return updateWorkspaceState(root, (state) => ({
|
|
51
|
+
...state,
|
|
52
|
+
...patch
|
|
53
|
+
}));
|
|
54
|
+
}
|
|
55
|
+
function updateWorkspaceState(root, update) {
|
|
56
|
+
return withWorkspaceStateLock(root, () => replaceWorkspaceState(root, update(readWorkspaceState(root) ?? {})));
|
|
57
|
+
}
|
|
58
|
+
function replaceWorkspaceState(root, state) {
|
|
59
|
+
const file = workspaceStateFile(root);
|
|
60
|
+
mkdirSync(dirname$1(file), { recursive: true });
|
|
61
|
+
const tmp = `${file}.tmp-${process.pid}`;
|
|
62
|
+
writeFileSync(tmp, `${JSON.stringify(state, null, 2)}\n`);
|
|
63
|
+
renameSync(tmp, file);
|
|
64
|
+
return state;
|
|
65
|
+
}
|
|
66
|
+
function clearWorkspaceStateKeys(root, keys) {
|
|
67
|
+
if (!existsSync(workspaceStateFile(root))) return;
|
|
68
|
+
withWorkspaceStateLock(root, () => {
|
|
69
|
+
const state = readWorkspaceState(root);
|
|
70
|
+
const file = workspaceStateFile(root);
|
|
71
|
+
if (!state) {
|
|
72
|
+
try {
|
|
73
|
+
rmSync(file, { force: true });
|
|
74
|
+
} catch {}
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
let changed = false;
|
|
78
|
+
for (const key of keys) {
|
|
79
|
+
if (!(key in state)) continue;
|
|
80
|
+
delete state[key];
|
|
81
|
+
changed = true;
|
|
82
|
+
}
|
|
83
|
+
if (!changed) return;
|
|
84
|
+
if (Object.keys(state).length === 0) {
|
|
85
|
+
rmSync(file, { force: true });
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
replaceWorkspaceState(root, state);
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
function clearWorkspaceStateKey(root, key, shouldClear) {
|
|
92
|
+
return withWorkspaceStateLock(root, () => {
|
|
93
|
+
const state = readWorkspaceState(root);
|
|
94
|
+
if (!state || !(key in state)) return true;
|
|
95
|
+
if (!shouldClear(state[key])) return false;
|
|
96
|
+
delete state[key];
|
|
97
|
+
const file = workspaceStateFile(root);
|
|
98
|
+
if (Object.keys(state).length === 0) {
|
|
99
|
+
try {
|
|
100
|
+
rmSync(file, { force: true });
|
|
101
|
+
} catch {}
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
replaceWorkspaceState(root, state);
|
|
105
|
+
return true;
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
function recordWorkspaceUse(root, now = /* @__PURE__ */ new Date()) {
|
|
109
|
+
try {
|
|
110
|
+
writeWorkspaceState(root, { lastUsedAt: now.toISOString() });
|
|
111
|
+
} catch {}
|
|
112
|
+
}
|
|
113
|
+
//#endregion
|
|
8
114
|
//#region src/ports.ts
|
|
9
115
|
function isMetroRunning(port) {
|
|
10
116
|
return new Promise((resolve) => {
|
|
@@ -55,14 +161,14 @@ async function computeNextPort(isFree = isPortFree) {
|
|
|
55
161
|
throw new Error(`Found no free Metro port between ${FIRST_PORT} and 8281. Free one up, or stop a stale bundler (\`stim status\`, \`stim stop <port>\`).`);
|
|
56
162
|
}
|
|
57
163
|
async function findReclaimablePort(excludeProjectPath, probe = isMetroRunning, { isMounted = isOnMountedVolume, mountedVolumes } = {}) {
|
|
58
|
-
const cfg = loadConfig();
|
|
164
|
+
const cfg = loadConfig$1();
|
|
59
165
|
if (!cfg?.projects) return null;
|
|
60
166
|
const mounted = mountedVolumes || listMountedVolumes();
|
|
61
167
|
const candidates = [];
|
|
62
168
|
for (const [path, proj] of Object.entries(cfg.projects)) {
|
|
63
169
|
if (path === excludeProjectPath) continue;
|
|
64
170
|
if (Object.keys(proj.ports ?? {}).length) continue;
|
|
65
|
-
if (existsSync(path)) continue;
|
|
171
|
+
if (existsSync$1(path)) continue;
|
|
66
172
|
if (!isMounted(path, mounted)) continue;
|
|
67
173
|
if (typeof proj.metroPort === "number") candidates.push({
|
|
68
174
|
port: proj.metroPort,
|
|
@@ -217,7 +323,7 @@ function processCwd(pid) {
|
|
|
217
323
|
}
|
|
218
324
|
function canonicalPath(path) {
|
|
219
325
|
try {
|
|
220
|
-
return realpathSync(path);
|
|
326
|
+
return realpathSync$1(path);
|
|
221
327
|
} catch {
|
|
222
328
|
return path;
|
|
223
329
|
}
|
|
@@ -232,7 +338,7 @@ const NOT_OURS_UNRESPONSIVE = "unresponsive";
|
|
|
232
338
|
const NOT_OURS_UNREADABLE_CWD = "unreadable-cwd";
|
|
233
339
|
const NOT_OURS_FOREIGN_CWD = "foreign-cwd";
|
|
234
340
|
function ownedSupervisor(projectPath, port) {
|
|
235
|
-
const supervisor = readWorkspaceState(canonicalPath(projectPath))?.supervisor;
|
|
341
|
+
const supervisor = readWorkspaceState$1(canonicalPath(projectPath))?.supervisor;
|
|
236
342
|
if (supervisor?.port !== port || (0, process_identity_exports.inspectProcessIdentity)(supervisor) !== "same") return null;
|
|
237
343
|
return supervisor;
|
|
238
344
|
}
|
|
@@ -300,4 +406,4 @@ function killMetroTree(leader, processToken) {
|
|
|
300
406
|
}
|
|
301
407
|
}
|
|
302
408
|
//#endregion
|
|
303
|
-
export {
|
|
409
|
+
export { workspaceLogErrorIndex as A, sharedCcache as C, workspaceDerivedData as D, supervisorPidFile as E, workspaceName$1 as M, workspaceStateFile as N, workspaceDir as O, withDirLock as P, sharedBuildCache as S, supervisorLogFile as T, withWorkspaceStateLock as _, processCwd as a, emulatorLogFile as b, signalProcessTree as c, reserveMetroPort as d, clearWorkspaceStateKey as f, updateWorkspaceState as g, recordWorkspaceUse as h, pidExists as i, workspaceLogsDir as j, workspaceId as k, isMetroRunning as l, readWorkspaceState$1 as m, listeningPids as n, processCwds as o, clearWorkspaceStateKeys as p, listeningPidsByPort as r, resolveProjectMetro as s, killMetroTree as t, isPortFree as u, workspaceLastUsed as v, sharedCompilationCache as w, ensureWorkspaceStorage as x, writeWorkspaceState as y };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { D as process_identity_exports, T as withConfigLock, f as getProject, g as loadConfig, s as ensureConfig, u as getConfigDir, x as saveConfig } from "./config-
|
|
2
|
-
import { t as getExecutor } from "./exec-
|
|
3
|
-
import {
|
|
4
|
-
import { t as withWorkspaceProcessLock } from "./workspace-process-lock-
|
|
1
|
+
import { D as process_identity_exports, T as withConfigLock, f as getProject, g as loadConfig, s as ensureConfig, u as getConfigDir, x as saveConfig } from "./config-BEq0Qw_a.mjs";
|
|
2
|
+
import { t as getExecutor } from "./exec-DK8KaVHK.mjs";
|
|
3
|
+
import { c as signalProcessTree, n as listeningPids, u as isPortFree } from "./metro-BWLOJ_Wr.mjs";
|
|
4
|
+
import { t as withWorkspaceProcessLock } from "./workspace-process-lock-BXA96myD.mjs";
|
|
5
5
|
import { realpathSync } from "node:fs";
|
|
6
6
|
//#region src/named-ports.ts
|
|
7
7
|
const FIRST_PORT = 8900;
|
|
@@ -1,62 +1,9 @@
|
|
|
1
|
-
import { closeSync, mkdirSync, openSync,
|
|
1
|
+
import { closeSync, mkdirSync, openSync, writeSync } from "fs";
|
|
2
2
|
import { dirname } from "path";
|
|
3
|
-
import { rotateLog
|
|
3
|
+
import { rotateLog } from "@stim-cli/core";
|
|
4
|
+
import { LEVELS, SOURCES, levelRank, parseNdjsonLine, readNdjsonGenerations } from "@stim-cli/core/state";
|
|
4
5
|
//#region src/ndjson.ts
|
|
5
6
|
const ROTATE_CHECK_MS = 1e3;
|
|
6
|
-
const LEVELS = [
|
|
7
|
-
"debug",
|
|
8
|
-
"info",
|
|
9
|
-
"warn",
|
|
10
|
-
"error",
|
|
11
|
-
"fatal"
|
|
12
|
-
];
|
|
13
|
-
const SOURCES = [
|
|
14
|
-
"metro",
|
|
15
|
-
"client",
|
|
16
|
-
"device",
|
|
17
|
-
"build"
|
|
18
|
-
];
|
|
19
|
-
function levelRank(level) {
|
|
20
|
-
const i = LEVELS.indexOf(level);
|
|
21
|
-
return i < 0 ? 0 : i;
|
|
22
|
-
}
|
|
23
|
-
function parseNdjsonLine(line) {
|
|
24
|
-
if (typeof line !== "string") return null;
|
|
25
|
-
const trimmed = line.trim();
|
|
26
|
-
if (!trimmed) return null;
|
|
27
|
-
let value;
|
|
28
|
-
try {
|
|
29
|
-
value = JSON.parse(trimmed);
|
|
30
|
-
} catch {
|
|
31
|
-
return null;
|
|
32
|
-
}
|
|
33
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
34
|
-
return value;
|
|
35
|
-
}
|
|
36
|
-
function parseNdjsonText(text) {
|
|
37
|
-
if (typeof text !== "string" || text === "") return [];
|
|
38
|
-
const out = [];
|
|
39
|
-
const lines = text.split("\n");
|
|
40
|
-
lines.pop();
|
|
41
|
-
for (const line of lines) {
|
|
42
|
-
const record = parseNdjsonLine(line);
|
|
43
|
-
if (record) out.push(record);
|
|
44
|
-
}
|
|
45
|
-
return out;
|
|
46
|
-
}
|
|
47
|
-
function readNdjsonGenerations(file) {
|
|
48
|
-
const out = [];
|
|
49
|
-
for (const path of [rotatedLogPath(file), file]) {
|
|
50
|
-
let text;
|
|
51
|
-
try {
|
|
52
|
-
text = readFileSync(path, "utf-8");
|
|
53
|
-
} catch {
|
|
54
|
-
continue;
|
|
55
|
-
}
|
|
56
|
-
for (const record of parseNdjsonText(text)) out.push(record);
|
|
57
|
-
}
|
|
58
|
-
return out;
|
|
59
|
-
}
|
|
60
7
|
function formatNdjsonLine(record) {
|
|
61
8
|
try {
|
|
62
9
|
return `${JSON.stringify(record)}\n`;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { D as process_identity_exports } from "./config-
|
|
2
|
-
import {
|
|
3
|
-
import { a as pidExists } from "./metro-DrLHaMn2.mjs";
|
|
1
|
+
import { D as process_identity_exports } from "./config-BEq0Qw_a.mjs";
|
|
2
|
+
import { _ as withWorkspaceStateLock, i as pidExists, m as readWorkspaceState, y as writeWorkspaceState } from "./metro-BWLOJ_Wr.mjs";
|
|
4
3
|
import { realpathSync } from "node:fs";
|
|
5
4
|
//#region src/collector/state.ts
|
|
6
5
|
function collectorRoot(root) {
|