@adatechnology/meta-whatsapp-module 0.2.0-rc.13 → 0.2.0-rc.14
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.cjs +214 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +333 -1
- package/dist/index.d.ts +333 -1
- package/dist/index.js +211 -4
- package/dist/index.js.map +1 -1
- package/dist/migrations/0007_flow_media.sql +18 -0
- package/dist/migrations/meta/_journal.json +7 -0
- package/package.json +4 -4
package/dist/index.d.cts
CHANGED
|
@@ -1000,6 +1000,257 @@ declare const flowGraphs: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
1000
1000
|
};
|
|
1001
1001
|
dialect: "pg";
|
|
1002
1002
|
}>;
|
|
1003
|
+
/**
|
|
1004
|
+
* Biblioteca de mídia do bot: arquivos que um nó `action` de `send_media` dispara ao chegar nele.
|
|
1005
|
+
*
|
|
1006
|
+
* Tabela separada de `documents` de propósito, e não por simetria: `documents` é o acervo DE UMA
|
|
1007
|
+
* CONVERSA (tem `sessionId` obrigatório) e tem índice único em (companyId, uploadId), porque lá o
|
|
1008
|
+
* mesmo binário chegando duas vezes é reentrega de job. Aqui é o oposto — o mesmo arquivo é
|
|
1009
|
+
* enviado para todo cliente que passar pelo nó, então aquele único bloquearia o segundo envio.
|
|
1010
|
+
*
|
|
1011
|
+
* Sem FK para `flow_graphs.id`: o vínculo natural é (companyId, flowKey), que é justamente o
|
|
1012
|
+
* índice único de lá. `nodeId` não tem como ser FK — nós vivem dentro do jsonb `nodes` — então
|
|
1013
|
+
* apagar um nó no editor deixa a linha órfã; quem lista sempre parte de um nó existente, e a
|
|
1014
|
+
* limpeza é passo de aplicação ao salvar o grafo.
|
|
1015
|
+
*/
|
|
1016
|
+
declare const flowMedia: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
1017
|
+
name: "flow_media";
|
|
1018
|
+
schema: "meta_whatsapp";
|
|
1019
|
+
columns: {
|
|
1020
|
+
id: drizzle_orm_pg_core.PgColumn<{
|
|
1021
|
+
name: "id";
|
|
1022
|
+
tableName: "flow_media";
|
|
1023
|
+
dataType: "string";
|
|
1024
|
+
columnType: "PgUUID";
|
|
1025
|
+
data: string;
|
|
1026
|
+
driverParam: string;
|
|
1027
|
+
notNull: true;
|
|
1028
|
+
hasDefault: true;
|
|
1029
|
+
isPrimaryKey: true;
|
|
1030
|
+
isAutoincrement: false;
|
|
1031
|
+
hasRuntimeDefault: false;
|
|
1032
|
+
enumValues: undefined;
|
|
1033
|
+
baseColumn: never;
|
|
1034
|
+
identity: undefined;
|
|
1035
|
+
generated: undefined;
|
|
1036
|
+
}, {}, {}>;
|
|
1037
|
+
companyId: drizzle_orm_pg_core.PgColumn<{
|
|
1038
|
+
name: "company_id";
|
|
1039
|
+
tableName: "flow_media";
|
|
1040
|
+
dataType: "string";
|
|
1041
|
+
columnType: "PgUUID";
|
|
1042
|
+
data: string;
|
|
1043
|
+
driverParam: string;
|
|
1044
|
+
notNull: true;
|
|
1045
|
+
hasDefault: false;
|
|
1046
|
+
isPrimaryKey: false;
|
|
1047
|
+
isAutoincrement: false;
|
|
1048
|
+
hasRuntimeDefault: false;
|
|
1049
|
+
enumValues: undefined;
|
|
1050
|
+
baseColumn: never;
|
|
1051
|
+
identity: undefined;
|
|
1052
|
+
generated: undefined;
|
|
1053
|
+
}, {}, {}>;
|
|
1054
|
+
flowKey: drizzle_orm_pg_core.PgColumn<{
|
|
1055
|
+
name: "flow_key";
|
|
1056
|
+
tableName: "flow_media";
|
|
1057
|
+
dataType: "string";
|
|
1058
|
+
columnType: "PgVarchar";
|
|
1059
|
+
data: string;
|
|
1060
|
+
driverParam: string;
|
|
1061
|
+
notNull: true;
|
|
1062
|
+
hasDefault: false;
|
|
1063
|
+
isPrimaryKey: false;
|
|
1064
|
+
isAutoincrement: false;
|
|
1065
|
+
hasRuntimeDefault: false;
|
|
1066
|
+
enumValues: [string, ...string[]];
|
|
1067
|
+
baseColumn: never;
|
|
1068
|
+
identity: undefined;
|
|
1069
|
+
generated: undefined;
|
|
1070
|
+
}, {}, {
|
|
1071
|
+
length: 64;
|
|
1072
|
+
}>;
|
|
1073
|
+
nodeId: drizzle_orm_pg_core.PgColumn<{
|
|
1074
|
+
name: "node_id";
|
|
1075
|
+
tableName: "flow_media";
|
|
1076
|
+
dataType: "string";
|
|
1077
|
+
columnType: "PgVarchar";
|
|
1078
|
+
data: string;
|
|
1079
|
+
driverParam: string;
|
|
1080
|
+
notNull: true;
|
|
1081
|
+
hasDefault: false;
|
|
1082
|
+
isPrimaryKey: false;
|
|
1083
|
+
isAutoincrement: false;
|
|
1084
|
+
hasRuntimeDefault: false;
|
|
1085
|
+
enumValues: [string, ...string[]];
|
|
1086
|
+
baseColumn: never;
|
|
1087
|
+
identity: undefined;
|
|
1088
|
+
generated: undefined;
|
|
1089
|
+
}, {}, {
|
|
1090
|
+
length: 64;
|
|
1091
|
+
}>;
|
|
1092
|
+
uploadId: drizzle_orm_pg_core.PgColumn<{
|
|
1093
|
+
name: "upload_id";
|
|
1094
|
+
tableName: "flow_media";
|
|
1095
|
+
dataType: "string";
|
|
1096
|
+
columnType: "PgVarchar";
|
|
1097
|
+
data: string;
|
|
1098
|
+
driverParam: string;
|
|
1099
|
+
notNull: true;
|
|
1100
|
+
hasDefault: false;
|
|
1101
|
+
isPrimaryKey: false;
|
|
1102
|
+
isAutoincrement: false;
|
|
1103
|
+
hasRuntimeDefault: false;
|
|
1104
|
+
enumValues: [string, ...string[]];
|
|
1105
|
+
baseColumn: never;
|
|
1106
|
+
identity: undefined;
|
|
1107
|
+
generated: undefined;
|
|
1108
|
+
}, {}, {
|
|
1109
|
+
length: 256;
|
|
1110
|
+
}>;
|
|
1111
|
+
filename: drizzle_orm_pg_core.PgColumn<{
|
|
1112
|
+
name: "filename";
|
|
1113
|
+
tableName: "flow_media";
|
|
1114
|
+
dataType: "string";
|
|
1115
|
+
columnType: "PgVarchar";
|
|
1116
|
+
data: string;
|
|
1117
|
+
driverParam: string;
|
|
1118
|
+
notNull: true;
|
|
1119
|
+
hasDefault: false;
|
|
1120
|
+
isPrimaryKey: false;
|
|
1121
|
+
isAutoincrement: false;
|
|
1122
|
+
hasRuntimeDefault: false;
|
|
1123
|
+
enumValues: [string, ...string[]];
|
|
1124
|
+
baseColumn: never;
|
|
1125
|
+
identity: undefined;
|
|
1126
|
+
generated: undefined;
|
|
1127
|
+
}, {}, {
|
|
1128
|
+
length: 512;
|
|
1129
|
+
}>;
|
|
1130
|
+
mimeType: drizzle_orm_pg_core.PgColumn<{
|
|
1131
|
+
name: "mime_type";
|
|
1132
|
+
tableName: "flow_media";
|
|
1133
|
+
dataType: "string";
|
|
1134
|
+
columnType: "PgVarchar";
|
|
1135
|
+
data: string;
|
|
1136
|
+
driverParam: string;
|
|
1137
|
+
notNull: true;
|
|
1138
|
+
hasDefault: false;
|
|
1139
|
+
isPrimaryKey: false;
|
|
1140
|
+
isAutoincrement: false;
|
|
1141
|
+
hasRuntimeDefault: false;
|
|
1142
|
+
enumValues: [string, ...string[]];
|
|
1143
|
+
baseColumn: never;
|
|
1144
|
+
identity: undefined;
|
|
1145
|
+
generated: undefined;
|
|
1146
|
+
}, {}, {
|
|
1147
|
+
length: 128;
|
|
1148
|
+
}>;
|
|
1149
|
+
sizeBytes: drizzle_orm_pg_core.PgColumn<{
|
|
1150
|
+
name: "size_bytes";
|
|
1151
|
+
tableName: "flow_media";
|
|
1152
|
+
dataType: "number";
|
|
1153
|
+
columnType: "PgInteger";
|
|
1154
|
+
data: number;
|
|
1155
|
+
driverParam: string | number;
|
|
1156
|
+
notNull: true;
|
|
1157
|
+
hasDefault: false;
|
|
1158
|
+
isPrimaryKey: false;
|
|
1159
|
+
isAutoincrement: false;
|
|
1160
|
+
hasRuntimeDefault: false;
|
|
1161
|
+
enumValues: undefined;
|
|
1162
|
+
baseColumn: never;
|
|
1163
|
+
identity: undefined;
|
|
1164
|
+
generated: undefined;
|
|
1165
|
+
}, {}, {}>;
|
|
1166
|
+
caption: drizzle_orm_pg_core.PgColumn<{
|
|
1167
|
+
name: "caption";
|
|
1168
|
+
tableName: "flow_media";
|
|
1169
|
+
dataType: "string";
|
|
1170
|
+
columnType: "PgText";
|
|
1171
|
+
data: string;
|
|
1172
|
+
driverParam: string;
|
|
1173
|
+
notNull: false;
|
|
1174
|
+
hasDefault: false;
|
|
1175
|
+
isPrimaryKey: false;
|
|
1176
|
+
isAutoincrement: false;
|
|
1177
|
+
hasRuntimeDefault: false;
|
|
1178
|
+
enumValues: [string, ...string[]];
|
|
1179
|
+
baseColumn: never;
|
|
1180
|
+
identity: undefined;
|
|
1181
|
+
generated: undefined;
|
|
1182
|
+
}, {}, {}>;
|
|
1183
|
+
sortOrder: drizzle_orm_pg_core.PgColumn<{
|
|
1184
|
+
name: "sort_order";
|
|
1185
|
+
tableName: "flow_media";
|
|
1186
|
+
dataType: "number";
|
|
1187
|
+
columnType: "PgInteger";
|
|
1188
|
+
data: number;
|
|
1189
|
+
driverParam: string | number;
|
|
1190
|
+
notNull: true;
|
|
1191
|
+
hasDefault: true;
|
|
1192
|
+
isPrimaryKey: false;
|
|
1193
|
+
isAutoincrement: false;
|
|
1194
|
+
hasRuntimeDefault: false;
|
|
1195
|
+
enumValues: undefined;
|
|
1196
|
+
baseColumn: never;
|
|
1197
|
+
identity: undefined;
|
|
1198
|
+
generated: undefined;
|
|
1199
|
+
}, {}, {}>;
|
|
1200
|
+
active: drizzle_orm_pg_core.PgColumn<{
|
|
1201
|
+
name: "active";
|
|
1202
|
+
tableName: "flow_media";
|
|
1203
|
+
dataType: "boolean";
|
|
1204
|
+
columnType: "PgBoolean";
|
|
1205
|
+
data: boolean;
|
|
1206
|
+
driverParam: boolean;
|
|
1207
|
+
notNull: true;
|
|
1208
|
+
hasDefault: true;
|
|
1209
|
+
isPrimaryKey: false;
|
|
1210
|
+
isAutoincrement: false;
|
|
1211
|
+
hasRuntimeDefault: false;
|
|
1212
|
+
enumValues: undefined;
|
|
1213
|
+
baseColumn: never;
|
|
1214
|
+
identity: undefined;
|
|
1215
|
+
generated: undefined;
|
|
1216
|
+
}, {}, {}>;
|
|
1217
|
+
createdAt: drizzle_orm_pg_core.PgColumn<{
|
|
1218
|
+
name: "created_at";
|
|
1219
|
+
tableName: "flow_media";
|
|
1220
|
+
dataType: "date";
|
|
1221
|
+
columnType: "PgTimestamp";
|
|
1222
|
+
data: Date;
|
|
1223
|
+
driverParam: string;
|
|
1224
|
+
notNull: true;
|
|
1225
|
+
hasDefault: true;
|
|
1226
|
+
isPrimaryKey: false;
|
|
1227
|
+
isAutoincrement: false;
|
|
1228
|
+
hasRuntimeDefault: false;
|
|
1229
|
+
enumValues: undefined;
|
|
1230
|
+
baseColumn: never;
|
|
1231
|
+
identity: undefined;
|
|
1232
|
+
generated: undefined;
|
|
1233
|
+
}, {}, {}>;
|
|
1234
|
+
updatedAt: drizzle_orm_pg_core.PgColumn<{
|
|
1235
|
+
name: "updated_at";
|
|
1236
|
+
tableName: "flow_media";
|
|
1237
|
+
dataType: "date";
|
|
1238
|
+
columnType: "PgTimestamp";
|
|
1239
|
+
data: Date;
|
|
1240
|
+
driverParam: string;
|
|
1241
|
+
notNull: true;
|
|
1242
|
+
hasDefault: true;
|
|
1243
|
+
isPrimaryKey: false;
|
|
1244
|
+
isAutoincrement: false;
|
|
1245
|
+
hasRuntimeDefault: false;
|
|
1246
|
+
enumValues: undefined;
|
|
1247
|
+
baseColumn: never;
|
|
1248
|
+
identity: undefined;
|
|
1249
|
+
generated: undefined;
|
|
1250
|
+
}, {}, {}>;
|
|
1251
|
+
};
|
|
1252
|
+
dialect: "pg";
|
|
1253
|
+
}>;
|
|
1003
1254
|
declare const settings: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
1004
1255
|
name: "settings";
|
|
1005
1256
|
schema: "meta_whatsapp";
|
|
@@ -1159,6 +1410,8 @@ type FlowGraphRow = typeof flowGraphs.$inferSelect;
|
|
|
1159
1410
|
type NewFlowGraphRow = typeof flowGraphs.$inferInsert;
|
|
1160
1411
|
type DocumentRow = typeof documents.$inferSelect;
|
|
1161
1412
|
type NewDocumentRow = typeof documents.$inferInsert;
|
|
1413
|
+
type FlowMediaRow = typeof flowMedia.$inferSelect;
|
|
1414
|
+
type NewFlowMediaRow = typeof flowMedia.$inferInsert;
|
|
1162
1415
|
|
|
1163
1416
|
interface ListConversationsFilters {
|
|
1164
1417
|
page?: number;
|
|
@@ -1757,6 +2010,57 @@ declare class FlowInterpreter {
|
|
|
1757
2010
|
}): Promise<FlowRunResult>;
|
|
1758
2011
|
}
|
|
1759
2012
|
|
|
2013
|
+
type FlowMediaLocation = {
|
|
2014
|
+
companyId: string;
|
|
2015
|
+
flowKey: string;
|
|
2016
|
+
nodeId: string;
|
|
2017
|
+
};
|
|
2018
|
+
type AttachFlowMediaParams = FlowMediaLocation & {
|
|
2019
|
+
uploadId: string;
|
|
2020
|
+
filename: string;
|
|
2021
|
+
mimeType: string;
|
|
2022
|
+
sizeBytes: number;
|
|
2023
|
+
caption?: string;
|
|
2024
|
+
sortOrder?: number;
|
|
2025
|
+
};
|
|
2026
|
+
type UpdateFlowMediaParams = {
|
|
2027
|
+
companyId: string;
|
|
2028
|
+
id: string;
|
|
2029
|
+
caption?: string | null;
|
|
2030
|
+
sortOrder?: number;
|
|
2031
|
+
active?: boolean;
|
|
2032
|
+
};
|
|
2033
|
+
declare class FlowMediaRepository {
|
|
2034
|
+
private readonly db;
|
|
2035
|
+
constructor(db: MetaWhatsAppDatabase);
|
|
2036
|
+
private locationFilter;
|
|
2037
|
+
listActive(location: FlowMediaLocation): Promise<FlowMediaRow[]>;
|
|
2038
|
+
listAll(location: FlowMediaLocation): Promise<FlowMediaRow[]>;
|
|
2039
|
+
/**
|
|
2040
|
+
* Anexa um arquivo já existente no storage ao nó.
|
|
2041
|
+
*
|
|
2042
|
+
* `onConflictDoUpdate` em vez de deixar estourar: reanexar o mesmo arquivo é clique repetido no
|
|
2043
|
+
* editor, e o esperado ali é atualizar a legenda/ordem — não um erro de índice único na cara de
|
|
2044
|
+
* quem está montando o fluxo.
|
|
2045
|
+
*/
|
|
2046
|
+
attach(params: AttachFlowMediaParams): Promise<FlowMediaRow>;
|
|
2047
|
+
update(params: UpdateFlowMediaParams): Promise<FlowMediaRow | undefined>;
|
|
2048
|
+
/**
|
|
2049
|
+
* Desanexa do nó. Não toca no storage de propósito: o mesmo `uploadId` pode estar anexado a
|
|
2050
|
+
* outro nó ou a outro fluxo, e apagar o binário aqui quebraria os demais. Quem apaga objeto é o
|
|
2051
|
+
* host, que é dono da biblioteca de arquivos.
|
|
2052
|
+
*/
|
|
2053
|
+
detach(params: {
|
|
2054
|
+
companyId: string;
|
|
2055
|
+
id: string;
|
|
2056
|
+
}): Promise<void>;
|
|
2057
|
+
detachRemovedNodes(params: {
|
|
2058
|
+
companyId: string;
|
|
2059
|
+
flowKey: string;
|
|
2060
|
+
existingNodeIds: string[];
|
|
2061
|
+
}): Promise<void>;
|
|
2062
|
+
}
|
|
2063
|
+
|
|
1760
2064
|
interface NonceStoreInterface {
|
|
1761
2065
|
setIfAbsent(key: string, ttlSeconds: number): Promise<boolean>;
|
|
1762
2066
|
}
|
|
@@ -1895,6 +2199,7 @@ declare function createMetaWhatsAppModule(params: CreateMetaWhatsAppModuleParams
|
|
|
1895
2199
|
delete: DeleteFlowGraphUseCase;
|
|
1896
2200
|
livePositions: GetLiveFlowPositionsUseCase;
|
|
1897
2201
|
repository: FlowGraphRepository;
|
|
2202
|
+
mediaRepository: FlowMediaRepository;
|
|
1898
2203
|
} | undefined;
|
|
1899
2204
|
catalog: CatalogPort | undefined;
|
|
1900
2205
|
};
|
|
@@ -1978,4 +2283,31 @@ declare function redeemSseTicket(store: TicketStoreInterface, ticket: string): P
|
|
|
1978
2283
|
whatsappNumber: string;
|
|
1979
2284
|
} | null>;
|
|
1980
2285
|
|
|
1981
|
-
|
|
2286
|
+
type CreateSendMediaActionParams = {
|
|
2287
|
+
flowMediaRepository: FlowMediaRepository;
|
|
2288
|
+
objectStorage: ObjectStorageInterface & {
|
|
2289
|
+
getObject: NonNullable<ObjectStorageInterface['getObject']>;
|
|
2290
|
+
};
|
|
2291
|
+
logMessage: LogMessageUseCase;
|
|
2292
|
+
startState: SessionState;
|
|
2293
|
+
onError?: (error: unknown, details: {
|
|
2294
|
+
flowKey: string;
|
|
2295
|
+
nodeId: string;
|
|
2296
|
+
uploadId: string;
|
|
2297
|
+
}) => void;
|
|
2298
|
+
};
|
|
2299
|
+
/**
|
|
2300
|
+
* Action `send_media`: ao passar pelo nó, envia os arquivos que a biblioteca tem anexados a ele.
|
|
2301
|
+
*
|
|
2302
|
+
* É a única action built-in que o módulo implementa de ponta a ponta — as outras
|
|
2303
|
+
* (`handoff`, `send_product_list`) dependem de regra de negócio do produto. Esta não: "mandar
|
|
2304
|
+
* estes arquivos ao chegar aqui" é comportamento de canal, e replicá-la em cada host seria
|
|
2305
|
+
* copiar o mesmo código com os mesmos bugs.
|
|
2306
|
+
*
|
|
2307
|
+
* O nó não guarda os arquivos em `actionParams` de propósito. Se guardasse, trocar o material
|
|
2308
|
+
* exigiria editar e republicar o grafo — e o ponto todo é o contrário: quem cuida do conteúdo
|
|
2309
|
+
* troca o arquivo na biblioteca e o fluxo continua igual.
|
|
2310
|
+
*/
|
|
2311
|
+
declare function createSendMediaAction(params: CreateSendMediaActionParams): FlowActionHandler;
|
|
2312
|
+
|
|
2313
|
+
export { type AttachFlowMediaParams, type CompanyDocumentView, type CompanyDocumentsPage, type ConversationDocumentView, type ConversationDocumentsPage, type CreateFlowGraphParams, CreateFlowGraphUseCase, type CreateMetaWhatsAppModuleParams, type CreateSendMediaActionParams, type DeleteConversationParams, type DeleteConversationResult, DeleteConversationUseCase, DeleteFlowGraphUseCase, DocumentRepository, type DocumentRow, type DrizzleMigrateFunction, type ExportConversationParams, type ExportConversationResult, ExportConversationUseCase, FlowGraphRepository, type FlowGraphRow, FlowInterpreter, type FlowMediaLocation, FlowMediaRepository, type FlowMediaRow, type FlowRunResult, type FlowStepInput, type FlowStepResult, GetFlowGraphUseCase, GetLiveFlowPositionsUseCase, type IngestInboundMediaParams, type IngestInboundMediaResult, IngestInboundMediaUseCase, type InsertMessageParams, InvalidFlowGraphError, type LinkDocumentParams, type ListCompanyDocumentsParams, ListCompanyDocumentsUseCase, type ListConversationDocumentsParams, ListConversationDocumentsUseCase, type ListConversationsFilters, type ListConversationsParams, ListConversationsUseCase, type ListDocumentsParams, type ListDocumentsResult, ListFlowGraphsUseCase, type ListMessagesParams, ListMessagesUseCase, type LogMessageParams, LogMessageUseCase, META_WHATSAPP_MIGRATIONS_TABLE, type MessageModerator, MessageRepository, type MessageRow, type MetaWhatsAppDatabase, type MetaWhatsAppModule, type MetaWhatsAppModuleConfig, type MetaWhatsAppModuleFeatures, type MetaWhatsAppModuleProviders, type NewDocumentRow, type NewFlowGraphRow, type NewFlowMediaRow, type NewMessageRow, type NewSessionRow, type NewSettingsRow, type NonceStoreInterface, OptimisticLockError, type PurgeExpiredDocumentsParams, type PurgeExpiredDocumentsResult, PurgeExpiredDocumentsUseCase, type RealtimeRelay, type ReceiveWebhookParams, type ReceiveWebhookResult, ReceiveWebhookUseCase, type ReleaseConversationParams, ReleaseConversationUseCase, type ListMessagesParams$1 as RepositoryListMessagesParams, type RunMetaWhatsAppMigrationsParams, type SaveFlowGraphParams, SaveFlowGraphUseCase, type SendMediaParams, SendMessageUseCase, type SendTemplateParams, type SendTextParams, SessionRepository, type SessionRow, SettingsRepository, type SettingsRow, SseHub, type SseListener, type TakeoverConversationParams, TakeoverConversationUseCase, type TicketStoreInterface, type UpdateFlowMediaParams, WEBHOOK_NONCE_TTL_SECONDS, WhatsAppChannelAdapter, claimWebhookDelivery, createMetaWhatsAppModule, createSendMediaAction, documents, extractMediaDescriptor, flowGraphs, flowMedia, issueSseTicket, messages, metaWhatsAppMigrationsFolder, metaWhatsAppSchema, redeemSseTicket, runMetaWhatsAppMigrations, sessions, settings, verifyWebhookChallenge, verifyWebhookSignature };
|