@tellescope/schema 1.253.1 → 1.254.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/lib/cjs/schema.d.ts.map +1 -1
- package/lib/cjs/schema.js +116 -23
- package/lib/cjs/schema.js.map +1 -1
- package/lib/esm/schema.d.ts.map +1 -1
- package/lib/esm/schema.js +117 -24
- package/lib/esm/schema.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/openapi.json +10846 -1364
- package/package.json +9 -9
- package/src/schema.ts +119 -23
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tellescope/schema",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.254.1",
|
|
4
4
|
"description": "Schema definition for Tellescope models",
|
|
5
5
|
"main": "./lib/cjs/schema.js",
|
|
6
6
|
"module": "./lib/esm/schema.js",
|
|
@@ -23,13 +23,13 @@
|
|
|
23
23
|
},
|
|
24
24
|
"homepage": "https://github.com/tellescope-os/tellescope#readme",
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@tellescope/constants": "1.
|
|
27
|
-
"@tellescope/types-client": "1.
|
|
28
|
-
"@tellescope/types-models": "1.
|
|
29
|
-
"@tellescope/types-server": "1.
|
|
30
|
-
"@tellescope/types-utilities": "1.
|
|
31
|
-
"@tellescope/utilities": "1.
|
|
32
|
-
"@tellescope/validation": "1.
|
|
26
|
+
"@tellescope/constants": "1.254.1",
|
|
27
|
+
"@tellescope/types-client": "1.254.1",
|
|
28
|
+
"@tellescope/types-models": "1.254.1",
|
|
29
|
+
"@tellescope/types-server": "1.254.1",
|
|
30
|
+
"@tellescope/types-utilities": "1.254.1",
|
|
31
|
+
"@tellescope/utilities": "1.254.1",
|
|
32
|
+
"@tellescope/validation": "1.254.1",
|
|
33
33
|
"validator": "13.11.0"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
@@ -43,5 +43,5 @@
|
|
|
43
43
|
"publishConfig": {
|
|
44
44
|
"access": "public"
|
|
45
45
|
},
|
|
46
|
-
"gitHead": "
|
|
46
|
+
"gitHead": "28444816447e007bba693810c8ebad150b83a9a5"
|
|
47
47
|
}
|
package/src/schema.ts
CHANGED
|
@@ -90,7 +90,9 @@ import {
|
|
|
90
90
|
AIDecisionAutomationAction,
|
|
91
91
|
AutomationAction,
|
|
92
92
|
TimeTrackTimestamp,
|
|
93
|
+
TimeTrackReviewHistoryItem,
|
|
93
94
|
BelugaPharmacyMapping,
|
|
95
|
+
CompoundFilter,
|
|
94
96
|
BelugaAutomationMappingEntry,
|
|
95
97
|
BelugaUpdateVisitPatientPreferenceItem,
|
|
96
98
|
TimeTrack,
|
|
@@ -172,6 +174,7 @@ import {
|
|
|
172
174
|
fileSizeValidator,
|
|
173
175
|
meetingStatusValidator,
|
|
174
176
|
listOfAttendeesValidator,
|
|
177
|
+
listOfVideoCallParticipantEventsValidator,
|
|
175
178
|
meetingInfoValidator,
|
|
176
179
|
listOfUserIndentitiesValidator,
|
|
177
180
|
meetingsListValidator,
|
|
@@ -287,6 +290,7 @@ import {
|
|
|
287
290
|
userCallRoutingBehaviorValidator,
|
|
288
291
|
userUIRestrictionsValidator,
|
|
289
292
|
userFieldRedactionsValidator,
|
|
293
|
+
portalSchemaRestrictionsValidator,
|
|
290
294
|
externalChatGPTMessagesValidator,
|
|
291
295
|
enduserProfileViewBlocksValidator,
|
|
292
296
|
customDashboardBlocksValidator,
|
|
@@ -2644,6 +2648,7 @@ export const schema: SchemaV1 = build_schema({
|
|
|
2644
2648
|
info: {},
|
|
2645
2649
|
fields: {
|
|
2646
2650
|
...BuiltInFields,
|
|
2651
|
+
accessTags: { redactions: ['enduser'], validator: listOfStringsValidatorEmptyOk },
|
|
2647
2652
|
archivedAt: { validator: dateOptionalOrEmptyStringValidator },
|
|
2648
2653
|
title: {
|
|
2649
2654
|
validator: stringValidator100,
|
|
@@ -3185,9 +3190,21 @@ export const schema: SchemaV1 = build_schema({
|
|
|
3185
3190
|
},
|
|
3186
3191
|
chat_rooms: {
|
|
3187
3192
|
info: {},
|
|
3188
|
-
constraints: {
|
|
3193
|
+
constraints: {
|
|
3189
3194
|
unique: [{ array: 'userIds' }, { array: 'enduserIds' }],
|
|
3190
|
-
relationship: [
|
|
3195
|
+
relationship: [
|
|
3196
|
+
{
|
|
3197
|
+
// Patient-initiated rooms targeting specific care-team staff (userIds) are an intended
|
|
3198
|
+
// portal feature and are left unrestricted. An enduser may only add THEMSELVES to a room
|
|
3199
|
+
// they create — they cannot add other patients (cross-patient PHI broadcast).
|
|
3200
|
+
explanation: 'Endusers can only add their own id to enduserIds on chat rooms they create',
|
|
3201
|
+
evaluate: (doc, _, session) => {
|
|
3202
|
+
if (session.type !== ENDUSER_SESSION_TYPE) return
|
|
3203
|
+
if ((doc.enduserIds ?? []).some(id => id !== session.id))
|
|
3204
|
+
return "enduserIds may only contain your own id for enduser session"
|
|
3205
|
+
}
|
|
3206
|
+
},
|
|
3207
|
+
],
|
|
3191
3208
|
access: [
|
|
3192
3209
|
{ type: 'filter', field: 'userIds' },
|
|
3193
3210
|
{ type: 'filter', field: 'enduserIds' },
|
|
@@ -3486,7 +3503,9 @@ export const schema: SchemaV1 = build_schema({
|
|
|
3486
3503
|
{
|
|
3487
3504
|
explanation: "Only admin users can update tags when accessTags is enabled",
|
|
3488
3505
|
evaluate: ({ _id }, _, session, method, { updates } ) => {
|
|
3489
|
-
|
|
3506
|
+
// editing a user's tags is a privilege-escalation vector whenever tags gate visibility:
|
|
3507
|
+
// enduser access tags (eat) OR resource access tags (erat). Skip only when neither is enabled.
|
|
3508
|
+
if (session.type === 'user' && !session.eat && !(session as UserSession)?.erat) return // neither access-tags feature enabled
|
|
3490
3509
|
if ((session as UserSession)?.roles?.includes('Admin')) return
|
|
3491
3510
|
if (method === 'create') return
|
|
3492
3511
|
if (!updates?.tags) return
|
|
@@ -4182,7 +4201,8 @@ export const schema: SchemaV1 = build_schema({
|
|
|
4182
4201
|
},
|
|
4183
4202
|
},
|
|
4184
4203
|
fields: {
|
|
4185
|
-
...BuiltInFields,
|
|
4204
|
+
...BuiltInFields,
|
|
4205
|
+
accessTags: { redactions: ['enduser'], validator: listOfStringsValidatorEmptyOk },
|
|
4186
4206
|
archivedAt: { validator: dateOptionalOrEmptyStringValidator },
|
|
4187
4207
|
mmsAttachmentURLs: { validator: listOfUniqueStringsValidatorEmptyOk },
|
|
4188
4208
|
title: {
|
|
@@ -4230,7 +4250,8 @@ export const schema: SchemaV1 = build_schema({
|
|
|
4230
4250
|
defaultActions: { read: {}, readMany: {}, update: {}, delete: {} },
|
|
4231
4251
|
enduserActions: { prepare_file_upload: {}, confirm_file_upload: {}, file_download_URL: {}, read: {}, readMany: {}, delete: {}, update: { } /* allow to hide from client side */ },
|
|
4232
4252
|
fields: {
|
|
4233
|
-
...BuiltInFields,
|
|
4253
|
+
...BuiltInFields,
|
|
4254
|
+
accessTags: { redactions: ['enduser'], validator: listOfStringsValidatorEmptyOk },
|
|
4234
4255
|
source: { validator: stringValidator100 },
|
|
4235
4256
|
tags: { validator: listOfStringsValidatorUniqueOptionalOrEmptyOkay },
|
|
4236
4257
|
name: {
|
|
@@ -4499,7 +4520,7 @@ export const schema: SchemaV1 = build_schema({
|
|
|
4499
4520
|
},
|
|
4500
4521
|
enduserActions: { create: {}, read: {}, readMany: {} },
|
|
4501
4522
|
fields: {
|
|
4502
|
-
...BuiltInFields,
|
|
4523
|
+
...BuiltInFields,
|
|
4503
4524
|
title: {
|
|
4504
4525
|
validator: stringValidator1000,
|
|
4505
4526
|
required: true,
|
|
@@ -4824,6 +4845,7 @@ export const schema: SchemaV1 = build_schema({
|
|
|
4824
4845
|
},
|
|
4825
4846
|
fields: {
|
|
4826
4847
|
...BuiltInFields,
|
|
4848
|
+
accessTags: { redactions: ['enduser'], validator: listOfStringsValidatorEmptyOk },
|
|
4827
4849
|
showByUserTags: { validator: listOfStringsValidatorOptionalOrEmptyOk },
|
|
4828
4850
|
belugaVisitType: { validator: stringValidator },
|
|
4829
4851
|
belugaVerificationId: { validator: stringValidator },
|
|
@@ -4837,8 +4859,9 @@ export const schema: SchemaV1 = build_schema({
|
|
|
4837
4859
|
},
|
|
4838
4860
|
belugaCombineMatchingPharmacyMappings: { validator: booleanValidator },
|
|
4839
4861
|
mdiCaseOfferings: {
|
|
4840
|
-
validator: listValidatorOptionalOrEmptyOk(objectValidator<{ offering_id: string }>({
|
|
4862
|
+
validator: listValidatorOptionalOrEmptyOk(objectValidator<{ offering_id: string, conditions?: CompoundFilter<string> }>({
|
|
4841
4863
|
offering_id: stringValidator100,
|
|
4864
|
+
conditions: compoundFilterValidator,
|
|
4842
4865
|
}))
|
|
4843
4866
|
},
|
|
4844
4867
|
autoMergeOnSubmission: { validator: booleanValidator },
|
|
@@ -5945,6 +5968,7 @@ export const schema: SchemaV1 = build_schema({
|
|
|
5945
5968
|
meetingId: { validator: mongoIdStringValidator, readonly: true },
|
|
5946
5969
|
bookingPageId: { validator: mongoIdStringValidator }, // allows rescheduling via booking page
|
|
5947
5970
|
meetingStatus: { validator: meetingStatusValidator },
|
|
5971
|
+
videoCallAttendance: { validator: listOfVideoCallParticipantEventsValidator, readonly: true },
|
|
5948
5972
|
attachments: { validator: listOfGenericAttachmentsValidator },
|
|
5949
5973
|
cancelledAt: { validator: dateOptionalOrEmptyStringValidator },
|
|
5950
5974
|
rescheduledAt: { validator: dateOptionalOrEmptyStringValidator },
|
|
@@ -6079,7 +6103,8 @@ export const schema: SchemaV1 = build_schema({
|
|
|
6079
6103
|
customActions: {},
|
|
6080
6104
|
enduserActions: { read: {}, readMany: {} },
|
|
6081
6105
|
fields: {
|
|
6082
|
-
...BuiltInFields,
|
|
6106
|
+
...BuiltInFields,
|
|
6107
|
+
accessTags: { redactions: ['enduser'], validator: listOfStringsValidatorEmptyOk },
|
|
6083
6108
|
dontSyncToElation: { validator: booleanValidator },
|
|
6084
6109
|
sendIcsEmail: { validator: booleanValidator },
|
|
6085
6110
|
createAndBookAthenaSlot: { validator: booleanValidator },
|
|
@@ -6446,8 +6471,16 @@ export const schema: SchemaV1 = build_schema({
|
|
|
6446
6471
|
enduser_observations: {
|
|
6447
6472
|
info: {},
|
|
6448
6473
|
constraints: {
|
|
6449
|
-
unique: [],
|
|
6450
|
-
relationship: [
|
|
6474
|
+
unique: [],
|
|
6475
|
+
relationship: [
|
|
6476
|
+
{
|
|
6477
|
+
explanation: 'When created by an enduser, enduserId must match their id',
|
|
6478
|
+
evaluate: ({ enduserId },_,session) => {
|
|
6479
|
+
if (session.type === ENDUSER_SESSION_TYPE && session.id !== enduserId)
|
|
6480
|
+
return "enduserId does not match creator id for enduser session"
|
|
6481
|
+
}
|
|
6482
|
+
},
|
|
6483
|
+
],
|
|
6451
6484
|
},
|
|
6452
6485
|
defaultActions: {
|
|
6453
6486
|
...DEFAULT_OPERATIONS,
|
|
@@ -6548,11 +6581,23 @@ export const schema: SchemaV1 = build_schema({
|
|
|
6548
6581
|
managed_content_records: {
|
|
6549
6582
|
info: {},
|
|
6550
6583
|
constraints: {
|
|
6551
|
-
unique: [],
|
|
6552
|
-
relationship: [
|
|
6584
|
+
unique: [],
|
|
6585
|
+
relationship: [
|
|
6586
|
+
{
|
|
6587
|
+
explanation: 'Endusers cannot self-publish managed content or bind it to another enduser',
|
|
6588
|
+
evaluate: (doc, _, session) => {
|
|
6589
|
+
if (session.type !== ENDUSER_SESSION_TYPE) return
|
|
6590
|
+
if (doc.publicRead) return "publicRead cannot be set by endusers"
|
|
6591
|
+
if (doc.allowUnauthenticatedAccess) return "allowUnauthenticatedAccess cannot be set by endusers"
|
|
6592
|
+
if (doc.forInternalUse) return "forInternalUse cannot be set by endusers"
|
|
6593
|
+
if (doc.enduserId !== undefined && doc.enduserId !== session.id)
|
|
6594
|
+
return "enduserId does not match creator id for enduser session"
|
|
6595
|
+
}
|
|
6596
|
+
},
|
|
6597
|
+
],
|
|
6553
6598
|
},
|
|
6554
6599
|
defaultActions: DEFAULT_OPERATIONS,
|
|
6555
|
-
customActions: {
|
|
6600
|
+
customActions: {
|
|
6556
6601
|
update_indexes: {
|
|
6557
6602
|
op: "custom", access: 'update', method: "patch",
|
|
6558
6603
|
name: 'Update Indexes',
|
|
@@ -6607,7 +6652,8 @@ export const schema: SchemaV1 = build_schema({
|
|
|
6607
6652
|
search: {},
|
|
6608
6653
|
},
|
|
6609
6654
|
fields: {
|
|
6610
|
-
...BuiltInFields,
|
|
6655
|
+
...BuiltInFields,
|
|
6656
|
+
accessTags: { redactions: ['enduser'], validator: listOfStringsValidatorEmptyOk },
|
|
6611
6657
|
slug: { validator: stringValidator250 },
|
|
6612
6658
|
title: {
|
|
6613
6659
|
validator: stringValidator1000,
|
|
@@ -7623,6 +7669,12 @@ export const schema: SchemaV1 = build_schema({
|
|
|
7623
7669
|
},
|
|
7624
7670
|
uiRestrictions: { validator: userUIRestrictionsValidator },
|
|
7625
7671
|
fieldRedactions: { validator: userFieldRedactionsValidator },
|
|
7672
|
+
portalSchemaRestrictions: {
|
|
7673
|
+
validator: portalSchemaRestrictionsValidator,
|
|
7674
|
+
initializer: () => ({ disableEditContent: true, disableEditTheming: true, disableEditSnippets: true }),
|
|
7675
|
+
},
|
|
7676
|
+
color: { validator: stringValidator1000 },
|
|
7677
|
+
description: { validator: stringValidator1000Optional },
|
|
7626
7678
|
}
|
|
7627
7679
|
},
|
|
7628
7680
|
appointment_booking_pages: {
|
|
@@ -7666,7 +7718,8 @@ export const schema: SchemaV1 = build_schema({
|
|
|
7666
7718
|
read: {}, readMany: {}, validate_access_token: {},
|
|
7667
7719
|
},
|
|
7668
7720
|
fields: {
|
|
7669
|
-
...BuiltInFields,
|
|
7721
|
+
...BuiltInFields,
|
|
7722
|
+
accessTags: { redactions: ['enduser'], validator: listOfStringsValidatorEmptyOk },
|
|
7670
7723
|
dontRestrictRescheduleToOriginalHost: { validator: booleanValidator },
|
|
7671
7724
|
gtmTag: { validator: stringValidator100EscapeHTML },
|
|
7672
7725
|
archivedAt: { validator: dateOptionalOrEmptyStringValidator },
|
|
@@ -8503,7 +8556,8 @@ If a voicemail is left, it is indicated by recordingURI, transcription, or recor
|
|
|
8503
8556
|
},
|
|
8504
8557
|
enduserActions: {},
|
|
8505
8558
|
fields: {
|
|
8506
|
-
...BuiltInFields,
|
|
8559
|
+
...BuiltInFields,
|
|
8560
|
+
accessTags: { redactions: ['enduser'], validator: listOfStringsValidatorEmptyOk },
|
|
8507
8561
|
title: {
|
|
8508
8562
|
validator: stringValidator100,
|
|
8509
8563
|
required: true,
|
|
@@ -8858,7 +8912,8 @@ If a voicemail is left, it is indicated by recordingURI, transcription, or recor
|
|
|
8858
8912
|
customActions: {},
|
|
8859
8913
|
enduserActions: {},
|
|
8860
8914
|
fields: {
|
|
8861
|
-
...BuiltInFields,
|
|
8915
|
+
...BuiltInFields,
|
|
8916
|
+
accessTags: { redactions: ['enduser'], validator: listOfStringsValidatorEmptyOk },
|
|
8862
8917
|
title: {
|
|
8863
8918
|
validator: stringValidator,
|
|
8864
8919
|
required: true,
|
|
@@ -9040,14 +9095,33 @@ If a voicemail is left, it is indicated by recordingURI, transcription, or recor
|
|
|
9040
9095
|
}
|
|
9041
9096
|
},
|
|
9042
9097
|
{
|
|
9043
|
-
explanation: "Locked time tracks only allow review field updates",
|
|
9044
|
-
evaluate: (_v, _deps,
|
|
9098
|
+
explanation: "Locked time tracks only allow review field updates, or owner resubmission of rejected entries",
|
|
9099
|
+
evaluate: (_v, _deps, session, method, { original, updates }) => {
|
|
9045
9100
|
if (method !== 'update') return
|
|
9046
9101
|
const orig = original as any as TimeTrack | undefined
|
|
9047
9102
|
if (!orig?.lockedAt) return
|
|
9103
|
+
|
|
9104
|
+
const u = updates as any as Partial<TimeTrack> | undefined
|
|
9048
9105
|
const reviewFields = ['reviewedAt', 'reviewedByUserId', 'reviewApproved', 'reviewNote']
|
|
9049
9106
|
const nonReviewFields = Object.keys(updates || {}).filter(k => !reviewFields.includes(k))
|
|
9050
|
-
if (nonReviewFields.length
|
|
9107
|
+
if (nonReviewFields.length === 0) return // pure review update — unchanged behavior
|
|
9108
|
+
|
|
9109
|
+
const isRejected = !!orig.reviewedAt && orig.reviewApproved === false
|
|
9110
|
+
const resubmitFields = [
|
|
9111
|
+
...reviewFields,
|
|
9112
|
+
'correctedAt', 'correctedByUserId', 'correctionNote',
|
|
9113
|
+
'originalTotalDurationInMS', 'totalDurationInMS',
|
|
9114
|
+
'lockedAt', 'lockedByUserId',
|
|
9115
|
+
]
|
|
9116
|
+
const disallowed = Object.keys(updates || {}).filter(k => !resubmitFields.includes(k))
|
|
9117
|
+
|
|
9118
|
+
if (isRejected && session.id === orig.userId && disallowed.length === 0) {
|
|
9119
|
+
if (u?.reviewedAt !== '') return "Resubmitting a rejected time track requires clearing reviewedAt (set to '')"
|
|
9120
|
+
if (u?.reviewApproved === true) return "Cannot approve your own time track during resubmission"
|
|
9121
|
+
return // valid resubmit — entry returns to Pending
|
|
9122
|
+
}
|
|
9123
|
+
|
|
9124
|
+
return `Time track is locked. Only review fields (${reviewFields.join(', ')}) can be updated.`
|
|
9051
9125
|
}
|
|
9052
9126
|
},
|
|
9053
9127
|
{
|
|
@@ -9132,6 +9206,19 @@ If a voicemail is left, it is indicated by recordingURI, transcription, or recor
|
|
|
9132
9206
|
reviewNote: { validator: stringValidator1000Optional },
|
|
9133
9207
|
lockedAt: { validator: dateValidatorOptional },
|
|
9134
9208
|
lockedByUserId: { validator: mongoIdStringOptional },
|
|
9209
|
+
// server-appended on resubmission of a rejected entry (see routing.ts update handler)
|
|
9210
|
+
// note: reviewApproved remains false after resubmit (booleans can't be cleared to '') — status logic must key off reviewedAt
|
|
9211
|
+
reviewHistory: {
|
|
9212
|
+
validator: listValidatorOptionalOrEmptyOk(objectValidator<TimeTrackReviewHistoryItem>({
|
|
9213
|
+
reviewedAt: dateValidator,
|
|
9214
|
+
reviewedByUserId: mongoIdStringOptional,
|
|
9215
|
+
reviewApproved: booleanValidatorOptional,
|
|
9216
|
+
reviewNote: stringValidator1000Optional,
|
|
9217
|
+
resubmittedAt: dateValidatorOptional,
|
|
9218
|
+
resubmittedByUserId: mongoIdStringOptional,
|
|
9219
|
+
})),
|
|
9220
|
+
readonly: true, // server-appended only — clients can read, never write
|
|
9221
|
+
},
|
|
9135
9222
|
},
|
|
9136
9223
|
},
|
|
9137
9224
|
ticket_queues: {
|
|
@@ -9315,8 +9402,17 @@ If a voicemail is left, it is indicated by recordingURI, transcription, or recor
|
|
|
9315
9402
|
info: {
|
|
9316
9403
|
description: 'Lab, medication, and device orders'
|
|
9317
9404
|
},
|
|
9318
|
-
constraints: {
|
|
9319
|
-
unique: [],
|
|
9405
|
+
constraints: {
|
|
9406
|
+
unique: [],
|
|
9407
|
+
relationship: [
|
|
9408
|
+
{
|
|
9409
|
+
explanation: 'When created by an enduser, enduserId must match their id',
|
|
9410
|
+
evaluate: ({ enduserId },_,session) => {
|
|
9411
|
+
if (session.type === ENDUSER_SESSION_TYPE && session.id !== enduserId)
|
|
9412
|
+
return "enduserId does not match creator id for enduser session"
|
|
9413
|
+
}
|
|
9414
|
+
},
|
|
9415
|
+
],
|
|
9320
9416
|
access: [{ type: 'filter', field: 'userId' }]
|
|
9321
9417
|
},
|
|
9322
9418
|
defaultActions: DEFAULT_OPERATIONS,
|
|
@@ -9744,7 +9840,7 @@ If a voicemail is left, it is indicated by recordingURI, transcription, or recor
|
|
|
9744
9840
|
fields: {
|
|
9745
9841
|
...BuiltInFields,
|
|
9746
9842
|
integration: { validator: stringValidator, readonly: true, examples: ['Canvas'] },
|
|
9747
|
-
status: { validator: exactMatchValidator(['Success', 'Error']), readonly: true, examples: ['Error'] },
|
|
9843
|
+
status: { validator: exactMatchValidator(['Success', 'Error', 'Info']), readonly: true, examples: ['Error'] },
|
|
9748
9844
|
type: { validator: stringValidator, readonly: true, examples: ['Patient Create'] },
|
|
9749
9845
|
payload: { validator: stringValidator, readonly: true, examples: ['{}'] },
|
|
9750
9846
|
response: { validator: stringValidator, readonly: true, examples: ['{}'] },
|