spectrum-ts 0.9.0 → 1.0.1
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/chunk-2Y5GBI6W.js +129 -0
- package/dist/chunk-7Q7KJKGL.js +117 -0
- package/dist/{chunk-6ZOLTQDN.js → chunk-LAGNM6I7.js} +39 -11
- package/dist/chunk-XMAI2AAN.js +1221 -0
- package/dist/index.d.ts +43 -7
- package/dist/index.js +49 -155
- package/dist/providers/imessage/index.d.ts +16 -7
- package/dist/providers/imessage/index.js +345 -60
- package/dist/providers/terminal/index.d.ts +109 -9
- package/dist/providers/terminal/index.js +813 -32
- package/dist/providers/whatsapp-business/index.d.ts +1 -1
- package/dist/providers/whatsapp-business/index.js +15 -10
- package/dist/{types-B8g0pvfg.d.ts → types-D5KhSXLy.d.ts} +27 -2
- package/package.json +1 -1
- package/dist/chunk-CZIWNTXP.js +0 -710
- package/dist/chunk-PLJI5FTO.js +0 -513
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { C as ContentBuilder, U as User, M as Message, a as ContentInput, b as Content, P as ProviderMessage, c as PlatformDef, d as Platform, e as PlatformProviderConfig, S as SpectrumLike, f as CustomEventStreams, g as Space, I as InboundMessage, O as OutboundMessage } from './types-
|
|
2
|
-
export { A as AnyPlatformDef, E as EventProducer, h as PlatformInstance, i as PlatformMessage, j as PlatformSpace, k as PlatformUser, l as SchemaMessage } from './types-
|
|
1
|
+
import { C as ContentBuilder, U as User, M as Message, a as ContentInput, b as Content, P as ProviderMessage, c as PlatformDef, d as Platform, e as PlatformProviderConfig, S as SpectrumLike, f as CustomEventStreams, g as Space, I as InboundMessage, O as OutboundMessage } from './types-D5KhSXLy.js';
|
|
2
|
+
export { A as AnyPlatformDef, E as EventProducer, h as PlatformInstance, i as PlatformMessage, j as PlatformSpace, k as PlatformUser, l as SchemaMessage } from './types-D5KhSXLy.js';
|
|
3
3
|
import vCard from 'vcf';
|
|
4
4
|
import z__default from 'zod';
|
|
5
5
|
export { M as ManagedStream, m as mergeStreams, s as stream } from './stream-B55k7W8-.js';
|
|
@@ -122,21 +122,39 @@ declare function contact(input: string | ContactInput | vCard): ContentBuilder;
|
|
|
122
122
|
|
|
123
123
|
declare function custom(raw: unknown): ContentBuilder;
|
|
124
124
|
|
|
125
|
+
/**
|
|
126
|
+
* A `group` bundles multiple messages into one logical unit (e.g. an album
|
|
127
|
+
* of images sent together). Each item is a full `Message` — addressable by
|
|
128
|
+
* id, reactable via `.react()`, replyable via `.reply()`.
|
|
129
|
+
*
|
|
130
|
+
* Groups do not nest, and reactions cannot be group members. Enforced by the
|
|
131
|
+
* `group()` builder; platforms may additionally reject unsupported item
|
|
132
|
+
* content types at send time.
|
|
133
|
+
*/
|
|
134
|
+
declare const groupSchema: z__default.ZodObject<{
|
|
135
|
+
type: z__default.ZodLiteral<"group">;
|
|
136
|
+
items: z__default.ZodArray<z__default.ZodCustom<Message, Message>>;
|
|
137
|
+
}, z__default.core.$strip>;
|
|
138
|
+
type Group = z__default.infer<typeof groupSchema>;
|
|
139
|
+
declare function group(...items: [ContentInput, ContentInput, ...ContentInput[]]): ContentBuilder;
|
|
140
|
+
|
|
125
141
|
declare const reactionSchema: z__default.ZodObject<{
|
|
126
142
|
type: z__default.ZodLiteral<"reaction">;
|
|
127
143
|
emoji: z__default.ZodString;
|
|
128
|
-
target: z__default.
|
|
144
|
+
target: z__default.ZodCustom<Message, Message>;
|
|
129
145
|
}, z__default.core.$strip>;
|
|
130
146
|
type Reaction = z__default.infer<typeof reactionSchema>;
|
|
131
147
|
/**
|
|
132
|
-
* Construct a `reaction` content value
|
|
133
|
-
* a string is treated as the target message id directly.
|
|
148
|
+
* Construct a `reaction` content value targeting the given message.
|
|
134
149
|
*
|
|
135
150
|
* `space.send(reaction(emoji, message))` is sugar for `message.react(emoji)`.
|
|
136
151
|
* Reactions are fire-and-forget — the returned `OutboundMessage` will be
|
|
137
152
|
* `undefined` because platforms do not surface a message id for reactions.
|
|
153
|
+
*
|
|
154
|
+
* To react to a message known only by id, resolve it first via
|
|
155
|
+
* `space.getMessage(id)`.
|
|
138
156
|
*/
|
|
139
|
-
declare function reaction(emoji: string, target: Message
|
|
157
|
+
declare function reaction(emoji: string, target: Message): ContentBuilder;
|
|
140
158
|
|
|
141
159
|
declare const resolveContents: (items: readonly ContentInput[]) => Promise<Content[]>;
|
|
142
160
|
|
|
@@ -2122,14 +2140,32 @@ type SpectrumInstance<Providers extends PlatformProviderConfig[] = PlatformProvi
|
|
|
2122
2140
|
edit(message: OutboundMessage, newContent: ContentInput): Promise<void>;
|
|
2123
2141
|
responding<T>(space: Space, fn: () => T | Promise<T>): Promise<T>;
|
|
2124
2142
|
};
|
|
2143
|
+
/**
|
|
2144
|
+
* Runtime behavior tweaks for a Spectrum instance.
|
|
2145
|
+
*/
|
|
2146
|
+
interface SpectrumOptions {
|
|
2147
|
+
/**
|
|
2148
|
+
* When `true`, inbound `group` messages are never delivered whole. Instead,
|
|
2149
|
+
* each group item is yielded from `spectrum.messages` as its own
|
|
2150
|
+
* `[space, message]` tuple, in order. Items retain their individual
|
|
2151
|
+
* `id`, `sender`, `timestamp`, and `.react()` / `.reply()` methods.
|
|
2152
|
+
*
|
|
2153
|
+
* Does not affect outbound `group(...)` sends or `space.getMessage(id)`.
|
|
2154
|
+
*
|
|
2155
|
+
* @default false
|
|
2156
|
+
*/
|
|
2157
|
+
flattenGroups?: boolean;
|
|
2158
|
+
}
|
|
2125
2159
|
declare function Spectrum<const Providers extends PlatformProviderConfig[]>(options: {
|
|
2126
2160
|
projectId: string;
|
|
2127
2161
|
projectSecret: string;
|
|
2128
2162
|
providers: [...Providers];
|
|
2163
|
+
options?: SpectrumOptions;
|
|
2129
2164
|
} | {
|
|
2130
2165
|
projectId?: never;
|
|
2131
2166
|
projectSecret?: never;
|
|
2132
2167
|
providers: [...Providers];
|
|
2168
|
+
options?: SpectrumOptions;
|
|
2133
2169
|
}): Promise<SpectrumInstance<Providers>>;
|
|
2134
2170
|
|
|
2135
2171
|
type SubscriptionStatus = "active" | "canceled" | "past_due";
|
|
@@ -2198,4 +2234,4 @@ declare class UnsupportedError extends Error {
|
|
|
2198
2234
|
declare const fromVCard: (vcf: string) => ContactInput;
|
|
2199
2235
|
declare const toVCard: (contact: Contact) => Promise<string>;
|
|
2200
2236
|
|
|
2201
|
-
export { type CloudPlatform, type Contact, type ContactAddress, type ContactDetails, type ContactEmail, type ContactInput, type ContactName, type ContactOrg, type ContactPhone, Content, ContentBuilder, ContentInput, type DedicatedTokenData, Emoji, type EmojiKey, type ImessageInfoData, Message, Platform, PlatformDef, PlatformProviderConfig, type PlatformStatus, type PlatformsData, type Reaction, type Richlink, type SharedTokenData, Space, Spectrum, SpectrumCloudError, type SpectrumInstance, type SubscriptionData, type SubscriptionStatus, type TokenData, UnsupportedError, type UnsupportedKind, User, type Voice, attachment, cloud, contact, custom, definePlatform, fromVCard, reaction, resolveContents, richlink, text, toVCard, voice };
|
|
2237
|
+
export { type CloudPlatform, type Contact, type ContactAddress, type ContactDetails, type ContactEmail, type ContactInput, type ContactName, type ContactOrg, type ContactPhone, Content, ContentBuilder, ContentInput, type DedicatedTokenData, Emoji, type EmojiKey, type Group, type ImessageInfoData, Message, Platform, PlatformDef, PlatformProviderConfig, type PlatformStatus, type PlatformsData, type Reaction, type Richlink, type SharedTokenData, Space, Spectrum, SpectrumCloudError, type SpectrumInstance, type SubscriptionData, type SubscriptionStatus, type TokenData, UnsupportedError, type UnsupportedKind, User, type Voice, attachment, cloud, contact, custom, definePlatform, fromVCard, group, reaction, resolveContents, richlink, text, toVCard, voice };
|
package/dist/index.js
CHANGED
|
@@ -1,136 +1,30 @@
|
|
|
1
1
|
import {
|
|
2
|
+
group,
|
|
2
3
|
richlink
|
|
3
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-LAGNM6I7.js";
|
|
5
|
+
import {
|
|
6
|
+
voice
|
|
7
|
+
} from "./chunk-7Q7KJKGL.js";
|
|
4
8
|
import {
|
|
5
9
|
SpectrumCloudError,
|
|
6
|
-
attachment,
|
|
7
|
-
bufferToStream,
|
|
8
10
|
cloud,
|
|
9
|
-
contact,
|
|
10
|
-
custom,
|
|
11
|
-
fromVCard,
|
|
12
11
|
mergeStreams,
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
stream,
|
|
16
|
-
streamSchema,
|
|
17
|
-
toVCard
|
|
18
|
-
} from "./chunk-CZIWNTXP.js";
|
|
12
|
+
stream
|
|
13
|
+
} from "./chunk-2Y5GBI6W.js";
|
|
19
14
|
import {
|
|
20
15
|
UnsupportedError,
|
|
21
|
-
|
|
16
|
+
attachment,
|
|
22
17
|
buildSpace,
|
|
18
|
+
contact,
|
|
19
|
+
custom,
|
|
23
20
|
definePlatform,
|
|
21
|
+
fromVCard,
|
|
22
|
+
reaction,
|
|
24
23
|
resolveContents,
|
|
25
|
-
text
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
import { createReadStream } from "fs";
|
|
30
|
-
import { readFile, stat } from "fs/promises";
|
|
31
|
-
import { basename } from "path";
|
|
32
|
-
import { Readable } from "stream";
|
|
33
|
-
import { lookup as lookupMimeType } from "mime-types";
|
|
34
|
-
import z from "zod";
|
|
35
|
-
var AUDIO_MIME_PATTERN = /^audio\//i;
|
|
36
|
-
var audioMimeSchema = z.string().nonempty().regex(AUDIO_MIME_PATTERN, "voice content requires an audio/* MIME type");
|
|
37
|
-
var voiceSchema = z.object({
|
|
38
|
-
type: z.literal("voice"),
|
|
39
|
-
name: z.string().nonempty().optional(),
|
|
40
|
-
mimeType: audioMimeSchema,
|
|
41
|
-
duration: z.number().nonnegative().optional(),
|
|
42
|
-
size: z.number().int().nonnegative().optional(),
|
|
43
|
-
read: readSchema,
|
|
44
|
-
stream: streamSchema
|
|
45
|
-
});
|
|
46
|
-
var resolveVoiceName = (input, name) => {
|
|
47
|
-
if (name) {
|
|
48
|
-
return name;
|
|
49
|
-
}
|
|
50
|
-
if (typeof input === "string") {
|
|
51
|
-
return basename(input);
|
|
52
|
-
}
|
|
53
|
-
return void 0;
|
|
54
|
-
};
|
|
55
|
-
var resolveVoiceMimeType = (name, mimeType) => {
|
|
56
|
-
if (mimeType) {
|
|
57
|
-
if (!AUDIO_MIME_PATTERN.test(mimeType)) {
|
|
58
|
-
throw new Error(
|
|
59
|
-
`voice content requires an audio/* MIME type, got "${mimeType}".`
|
|
60
|
-
);
|
|
61
|
-
}
|
|
62
|
-
return mimeType;
|
|
63
|
-
}
|
|
64
|
-
if (name) {
|
|
65
|
-
const resolved = lookupMimeType(name);
|
|
66
|
-
if (resolved && AUDIO_MIME_PATTERN.test(resolved)) {
|
|
67
|
-
return resolved;
|
|
68
|
-
}
|
|
69
|
-
if (resolved) {
|
|
70
|
-
throw new Error(
|
|
71
|
-
`Resolved non-audio MIME type "${resolved}" from name "${name}". Pass options.mimeType explicitly with an audio/* type.`
|
|
72
|
-
);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
throw new Error(
|
|
76
|
-
"Unable to resolve MIME type for voice content. Pass options.mimeType explicitly."
|
|
77
|
-
);
|
|
78
|
-
};
|
|
79
|
-
var asVoice = (input) => {
|
|
80
|
-
let cached;
|
|
81
|
-
const read = () => {
|
|
82
|
-
cached ??= input.read().catch((err) => {
|
|
83
|
-
cached = void 0;
|
|
84
|
-
throw err;
|
|
85
|
-
});
|
|
86
|
-
return cached;
|
|
87
|
-
};
|
|
88
|
-
const stream2 = input.stream ?? (async () => bufferToStream(await read()));
|
|
89
|
-
return voiceSchema.parse({
|
|
90
|
-
type: "voice",
|
|
91
|
-
name: input.name,
|
|
92
|
-
mimeType: input.mimeType,
|
|
93
|
-
duration: input.duration,
|
|
94
|
-
size: input.size,
|
|
95
|
-
read,
|
|
96
|
-
stream: stream2
|
|
97
|
-
});
|
|
98
|
-
};
|
|
99
|
-
function voice(input, options) {
|
|
100
|
-
return {
|
|
101
|
-
build: async () => {
|
|
102
|
-
const name = resolveVoiceName(input, options?.name);
|
|
103
|
-
const mimeHint = typeof input === "string" ? basename(input) : name;
|
|
104
|
-
const mimeType = resolveVoiceMimeType(mimeHint, options?.mimeType);
|
|
105
|
-
if (typeof input === "string") {
|
|
106
|
-
const stats = await stat(input);
|
|
107
|
-
if (!stats.isFile()) {
|
|
108
|
-
throw new Error(
|
|
109
|
-
`voice content path "${input}" is not a regular file.`
|
|
110
|
-
);
|
|
111
|
-
}
|
|
112
|
-
return asVoice({
|
|
113
|
-
name,
|
|
114
|
-
mimeType,
|
|
115
|
-
duration: options?.duration,
|
|
116
|
-
size: stats.size,
|
|
117
|
-
read: () => readFile(input),
|
|
118
|
-
stream: async () => Readable.toWeb(
|
|
119
|
-
createReadStream(input)
|
|
120
|
-
)
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
return asVoice({
|
|
124
|
-
name,
|
|
125
|
-
mimeType,
|
|
126
|
-
duration: options?.duration,
|
|
127
|
-
size: input.byteLength,
|
|
128
|
-
read: async () => input,
|
|
129
|
-
stream: async () => bufferToStream(input)
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
};
|
|
133
|
-
}
|
|
24
|
+
text,
|
|
25
|
+
toVCard,
|
|
26
|
+
wrapProviderMessage
|
|
27
|
+
} from "./chunk-XMAI2AAN.js";
|
|
134
28
|
|
|
135
29
|
// src/emoji/generated.ts
|
|
136
30
|
var GeneratedEmoji = {
|
|
@@ -2062,29 +1956,33 @@ var aliases = {
|
|
|
2062
1956
|
var Emoji = { ...GeneratedEmoji, ...aliases };
|
|
2063
1957
|
|
|
2064
1958
|
// src/spectrum.ts
|
|
2065
|
-
import
|
|
2066
|
-
var
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
projectId: z2.string().min(1),
|
|
2076
|
-
projectSecret: z2.string().min(1),
|
|
2077
|
-
providers: z2.array(z2.custom())
|
|
1959
|
+
import z from "zod";
|
|
1960
|
+
var spectrumOptionsSchema = z.object({
|
|
1961
|
+
flattenGroups: z.boolean().optional()
|
|
1962
|
+
}).optional();
|
|
1963
|
+
var spectrumConfigSchema = z.union([
|
|
1964
|
+
z.object({
|
|
1965
|
+
projectId: z.string().min(1),
|
|
1966
|
+
projectSecret: z.string().min(1),
|
|
1967
|
+
providers: z.array(z.custom()),
|
|
1968
|
+
options: spectrumOptionsSchema
|
|
2078
1969
|
}),
|
|
2079
|
-
|
|
2080
|
-
projectId:
|
|
2081
|
-
projectSecret:
|
|
2082
|
-
providers:
|
|
1970
|
+
z.object({
|
|
1971
|
+
projectId: z.undefined().optional(),
|
|
1972
|
+
projectSecret: z.undefined().optional(),
|
|
1973
|
+
providers: z.array(z.custom()),
|
|
1974
|
+
options: spectrumOptionsSchema
|
|
2083
1975
|
})
|
|
2084
1976
|
]);
|
|
2085
1977
|
async function Spectrum(options) {
|
|
2086
1978
|
spectrumConfigSchema.parse(options);
|
|
2087
|
-
const {
|
|
1979
|
+
const {
|
|
1980
|
+
projectId,
|
|
1981
|
+
projectSecret,
|
|
1982
|
+
providers,
|
|
1983
|
+
options: runtimeOptions
|
|
1984
|
+
} = options;
|
|
1985
|
+
const flattenGroups = runtimeOptions?.flattenGroups ?? false;
|
|
2088
1986
|
const platformStates = /* @__PURE__ */ new Map();
|
|
2089
1987
|
const customEventStreams = /* @__PURE__ */ new Map();
|
|
2090
1988
|
let stopped = false;
|
|
@@ -2132,11 +2030,6 @@ async function Spectrum(options) {
|
|
|
2132
2030
|
});
|
|
2133
2031
|
const bindSend = async function* () {
|
|
2134
2032
|
for await (const msg of raw) {
|
|
2135
|
-
const extraEntries = Object.entries(msg).filter(
|
|
2136
|
-
([key]) => !providerMessageCoreKeys.has(key)
|
|
2137
|
-
);
|
|
2138
|
-
const extra = Object.fromEntries(extraEntries);
|
|
2139
|
-
const parsedExtra = definition.message?.schema ? definition.message.schema.parse(extra) : {};
|
|
2140
2033
|
const spaceRef = {
|
|
2141
2034
|
...msg.space,
|
|
2142
2035
|
__platform: definition.name
|
|
@@ -2150,19 +2043,19 @@ async function Spectrum(options) {
|
|
|
2150
2043
|
client,
|
|
2151
2044
|
config
|
|
2152
2045
|
});
|
|
2153
|
-
const normalizedMessage =
|
|
2154
|
-
id: msg.id,
|
|
2155
|
-
content: msg.content,
|
|
2156
|
-
sender: msg.sender,
|
|
2157
|
-
timestamp: msg.timestamp ?? /* @__PURE__ */ new Date(),
|
|
2158
|
-
extras: parsedExtra,
|
|
2159
|
-
spaceRef,
|
|
2160
|
-
space,
|
|
2161
|
-
definition,
|
|
2046
|
+
const normalizedMessage = wrapProviderMessage(msg, {
|
|
2162
2047
|
client,
|
|
2163
2048
|
config,
|
|
2164
|
-
|
|
2049
|
+
definition,
|
|
2050
|
+
space,
|
|
2051
|
+
spaceRef
|
|
2165
2052
|
});
|
|
2053
|
+
if (flattenGroups && normalizedMessage.content.type === "group") {
|
|
2054
|
+
for (const item of normalizedMessage.content.items) {
|
|
2055
|
+
yield [space, item];
|
|
2056
|
+
}
|
|
2057
|
+
continue;
|
|
2058
|
+
}
|
|
2166
2059
|
yield [space, normalizedMessage];
|
|
2167
2060
|
}
|
|
2168
2061
|
};
|
|
@@ -2310,6 +2203,7 @@ export {
|
|
|
2310
2203
|
custom,
|
|
2311
2204
|
definePlatform,
|
|
2312
2205
|
fromVCard,
|
|
2206
|
+
group,
|
|
2313
2207
|
mergeStreams,
|
|
2314
2208
|
reaction,
|
|
2315
2209
|
resolveContents,
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { M as ManagedStream } from '../../stream-B55k7W8-.js';
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
2
|
+
import { l as SchemaMessage, d as Platform, c as PlatformDef, P as ProviderMessage } from '../../types-D5KhSXLy.js';
|
|
3
|
+
import * as zod_v4_core from 'zod/v4/core';
|
|
4
4
|
import * as z from 'zod';
|
|
5
5
|
import z__default from 'zod';
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
6
|
+
import { AdvancedIMessage } from '@photon-ai/advanced-imessage';
|
|
7
|
+
import { IMessageSDK } from '@photon-ai/imessage-kit';
|
|
8
8
|
import 'hotscript';
|
|
9
9
|
|
|
10
10
|
type IMessageClient = IMessageSDK | AdvancedIMessage[];
|
|
@@ -16,7 +16,10 @@ declare const spaceSchema: z__default.ZodObject<{
|
|
|
16
16
|
group: "group";
|
|
17
17
|
}>;
|
|
18
18
|
}, z__default.core.$strip>;
|
|
19
|
-
type IMessageMessage = SchemaMessage<typeof userSchema, typeof spaceSchema
|
|
19
|
+
type IMessageMessage = SchemaMessage<typeof userSchema, typeof spaceSchema> & {
|
|
20
|
+
partIndex?: number;
|
|
21
|
+
parentId?: string;
|
|
22
|
+
};
|
|
20
23
|
|
|
21
24
|
declare const imessage: Platform<PlatformDef<"iMessage", z.ZodUnion<readonly [z.ZodObject<{
|
|
22
25
|
local: z.ZodLiteral<true>;
|
|
@@ -43,7 +46,10 @@ declare const imessage: Platform<PlatformDef<"iMessage", z.ZodUnion<readonly [z.
|
|
|
43
46
|
} | {
|
|
44
47
|
id: string;
|
|
45
48
|
type: "group";
|
|
46
|
-
},
|
|
49
|
+
}, z.ZodObject<{
|
|
50
|
+
partIndex: z.ZodOptional<z.ZodNumber>;
|
|
51
|
+
parentId: z.ZodOptional<z.ZodString>;
|
|
52
|
+
}, zod_v4_core.$strip>, ProviderMessage<{
|
|
47
53
|
id: string;
|
|
48
54
|
}, {
|
|
49
55
|
id: string;
|
|
@@ -51,7 +57,10 @@ declare const imessage: Platform<PlatformDef<"iMessage", z.ZodUnion<readonly [z.
|
|
|
51
57
|
} | {
|
|
52
58
|
id: string;
|
|
53
59
|
type: "group";
|
|
54
|
-
},
|
|
60
|
+
}, {
|
|
61
|
+
partIndex?: number | undefined;
|
|
62
|
+
parentId?: string | undefined;
|
|
63
|
+
}>, {
|
|
55
64
|
messages: ({ client }: {
|
|
56
65
|
client: IMessageClient;
|
|
57
66
|
config: {
|