@graphql-box/cache-manager 2.4.1 → 3.0.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/lib/browser/index.js +1 -1
- package/lib/browser/index.js.map +1 -1
- package/lib/browser/production.analysis.txt +64 -28
- package/lib/main/helpers/isFirstResponseChunk.js +11 -0
- package/lib/main/helpers/isFirstResponseChunk.js.map +1 -0
- package/lib/main/helpers/isLastResponseChunk.js +11 -0
- package/lib/main/helpers/isLastResponseChunk.js.map +1 -0
- package/lib/main/helpers/isNotLastResponseChunk.js +11 -0
- package/lib/main/helpers/isNotLastResponseChunk.js.map +1 -0
- package/lib/main/helpers/isNotResponseChunk.js +11 -0
- package/lib/main/helpers/isNotResponseChunk.js.map +1 -0
- package/lib/main/helpers/mergeResponseDataSets.js +53 -0
- package/lib/main/helpers/mergeResponseDataSets.js.map +1 -0
- package/lib/main/helpers/{normalizeResponseData.js → normalizePatchResponseData.js} +11 -6
- package/lib/main/helpers/normalizePatchResponseData.js.map +1 -0
- package/lib/main/main/index.js +145 -121
- package/lib/main/main/index.js.map +1 -1
- package/lib/module/helpers/isFirstResponseChunk.js +2 -0
- package/lib/module/helpers/isFirstResponseChunk.js.map +1 -0
- package/lib/module/helpers/isLastResponseChunk.js +2 -0
- package/lib/module/helpers/isLastResponseChunk.js.map +1 -0
- package/lib/module/helpers/isNotLastResponseChunk.js +2 -0
- package/lib/module/helpers/isNotLastResponseChunk.js.map +1 -0
- package/lib/module/helpers/isNotResponseChunk.js +2 -0
- package/lib/module/helpers/isNotResponseChunk.js.map +1 -0
- package/lib/module/helpers/mergeResponseDataSets.js +41 -0
- package/lib/module/helpers/mergeResponseDataSets.js.map +1 -0
- package/lib/module/helpers/normalizePatchResponseData.js +17 -0
- package/lib/module/helpers/normalizePatchResponseData.js.map +1 -0
- package/lib/module/main/index.js +143 -122
- package/lib/module/main/index.js.map +1 -1
- package/lib/types/defs/index.d.ts +3 -10
- package/lib/types/defs/index.d.ts.map +1 -1
- package/lib/types/helpers/isFirstResponseChunk.d.ts +5 -0
- package/lib/types/helpers/isFirstResponseChunk.d.ts.map +1 -0
- package/lib/types/helpers/isLastResponseChunk.d.ts +5 -0
- package/lib/types/helpers/isLastResponseChunk.d.ts.map +1 -0
- package/lib/types/helpers/isNotLastResponseChunk.d.ts +5 -0
- package/lib/types/helpers/isNotLastResponseChunk.d.ts.map +1 -0
- package/lib/types/helpers/isNotResponseChunk.d.ts +5 -0
- package/lib/types/helpers/isNotResponseChunk.d.ts.map +1 -0
- package/lib/types/helpers/mergeResponseDataSets.d.ts +4 -0
- package/lib/types/helpers/mergeResponseDataSets.d.ts.map +1 -0
- package/lib/types/helpers/normalizePatchResponseData.d.ts +5 -0
- package/lib/types/helpers/normalizePatchResponseData.d.ts.map +1 -0
- package/lib/types/main/index.d.ts +7 -5
- package/lib/types/main/index.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/__snapshots__/index.test.ts.snap +12481 -11881
- package/src/defs/index.ts +14 -22
- package/src/helpers/isFirstResponseChunk.ts +5 -0
- package/src/helpers/isLastResponseChunk.ts +5 -0
- package/src/helpers/isNotLastResponseChunk.ts +5 -0
- package/src/helpers/isNotResponseChunk.ts +5 -0
- package/src/helpers/mergeResponseDataSets.ts +35 -0
- package/src/helpers/normalizePatchResponseData.ts +17 -0
- package/src/index.test.ts +191 -115
- package/src/main/index.ts +172 -134
- package/lib/main/helpers/normalizeResponseData.js.map +0 -1
- package/lib/module/helpers/normalizeResponseData.js +0 -12
- package/lib/module/helpers/normalizeResponseData.js.map +0 -1
- package/lib/types/helpers/normalizeResponseData.d.ts +0 -11
- package/lib/types/helpers/normalizeResponseData.d.ts.map +0 -1
- package/src/helpers/normalizeResponseData.ts +0 -10
package/lib/module/main/index.js
CHANGED
|
@@ -23,28 +23,13 @@ import { buildFieldKeysAndPaths } from "../helpers/buildKeysAndPaths";
|
|
|
23
23
|
import deriveOpCacheability from "../helpers/deriveOpCacheability";
|
|
24
24
|
import filterOutPropsWithArgsOrDirectives from "../helpers/filterOutPropsWithArgsOrDirectives";
|
|
25
25
|
import filterQuery from "../helpers/filterQuery";
|
|
26
|
-
import
|
|
26
|
+
import isLastResponseChunk from "../helpers/isLastResponseChunk";
|
|
27
|
+
import isNotLastResponseChunk from "../helpers/isNotLastResponseChunk";
|
|
28
|
+
import isNotResponseChunk from "../helpers/isNotResponseChunk";
|
|
29
|
+
import mergeResponseDataSets from "../helpers/mergeResponseDataSets";
|
|
30
|
+
import normalizePatchResponseData from "../helpers/normalizePatchResponseData";
|
|
27
31
|
import { getValidTypeIDValue } from "../helpers/validTypeIDValue";
|
|
28
32
|
export let CacheManager = (_dec = logCacheQuery(), _dec2 = logCacheEntry(), _dec3 = logPartialCompiled(), (_class = class CacheManager {
|
|
29
|
-
static async init(options) {
|
|
30
|
-
const errors = [];
|
|
31
|
-
|
|
32
|
-
if (!options.cache) {
|
|
33
|
-
errors.push(new TypeError("@graphql-box/cache-manager expected options.cache."));
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if (!!options.typeCacheDirectives && !_isPlainObject(options.typeCacheDirectives)) {
|
|
37
|
-
const message = "@graphql-box/cache-manager expected options.typeCacheDirectives to be a plain object.";
|
|
38
|
-
errors.push(new TypeError(message));
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
if (errors.length) {
|
|
42
|
-
return Promise.reject(errors);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return new CacheManager(options);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
33
|
static _countFieldPathChecklist(fieldPathChecklist) {
|
|
49
34
|
const fieldCount = {
|
|
50
35
|
missing: 0,
|
|
@@ -197,22 +182,32 @@ export let CacheManager = (_dec = logCacheQuery(), _dec2 = logCacheEntry(), _dec
|
|
|
197
182
|
|
|
198
183
|
_defineProperty(this, "_partialQueryResponses", new Map());
|
|
199
184
|
|
|
185
|
+
_defineProperty(this, "_responseChunksAwaitingCaching", new Map());
|
|
186
|
+
|
|
200
187
|
_defineProperty(this, "_typeCacheDirectives", void 0);
|
|
201
188
|
|
|
202
189
|
_defineProperty(this, "_typeIDKey", void 0);
|
|
203
190
|
|
|
204
|
-
const
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
191
|
+
const errors = [];
|
|
192
|
+
|
|
193
|
+
if (!options.cache) {
|
|
194
|
+
errors.push(new TypeError("@graphql-box/cache-manager expected options.cache."));
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (!!options.typeCacheDirectives && !_isPlainObject(options.typeCacheDirectives)) {
|
|
198
|
+
const message = "@graphql-box/cache-manager expected options.typeCacheDirectives to be a plain object.";
|
|
199
|
+
errors.push(new TypeError(message));
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (errors.length) {
|
|
203
|
+
throw errors;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
this._cache = options.cache;
|
|
207
|
+
this._cascadeCacheControl = options.cascadeCacheControl || false;
|
|
208
|
+
this._fallbackOperationCacheability = options.fallbackOperationCacheability || NO_CACHE;
|
|
209
|
+
this._typeCacheDirectives = options.typeCacheDirectives || {};
|
|
210
|
+
this._typeIDKey = options.typeIDKey;
|
|
216
211
|
}
|
|
217
212
|
|
|
218
213
|
get cache() {
|
|
@@ -288,6 +283,22 @@ export let CacheManager = (_dec = logCacheQuery(), _dec2 = logCacheEntry(), _dec
|
|
|
288
283
|
};
|
|
289
284
|
}
|
|
290
285
|
|
|
286
|
+
async cacheQuery(requestData, updatedRequestData, rawResponseData, options, context) {
|
|
287
|
+
const cacheManagerContext = { ...context,
|
|
288
|
+
fragmentDefinitions: getFragmentDefinitions(updatedRequestData.ast),
|
|
289
|
+
typeIDKey: this._typeIDKey
|
|
290
|
+
};
|
|
291
|
+
return this._cacheResponse(requestData, updatedRequestData, rawResponseData, options, cacheManagerContext);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
async cacheResponse(requestData, rawResponseData, options, context) {
|
|
295
|
+
const cacheManagerContext = { ...context,
|
|
296
|
+
fragmentDefinitions: getFragmentDefinitions(requestData.ast),
|
|
297
|
+
typeIDKey: this._typeIDKey
|
|
298
|
+
};
|
|
299
|
+
return this._cacheResponse(requestData, undefined, rawResponseData, options, cacheManagerContext);
|
|
300
|
+
}
|
|
301
|
+
|
|
291
302
|
async checkCacheEntry(cacheType, hash, options, context) {
|
|
292
303
|
return this._checkCacheEntry(cacheType, hash, options, context);
|
|
293
304
|
}
|
|
@@ -313,66 +324,10 @@ export let CacheManager = (_dec = logCacheQuery(), _dec2 = logCacheEntry(), _dec
|
|
|
313
324
|
this._partialQueryResponses.delete(hash);
|
|
314
325
|
}
|
|
315
326
|
|
|
316
|
-
async resolveQuery(requestData, updatedRequestData, rawResponseData, options, context) {
|
|
317
|
-
const cacheManagerContext = { ...context,
|
|
318
|
-
fragmentDefinitions: getFragmentDefinitions(updatedRequestData.ast),
|
|
319
|
-
typeIDKey: this._typeIDKey
|
|
320
|
-
};
|
|
321
|
-
const dataCaching = [];
|
|
322
|
-
const {
|
|
323
|
-
cacheMetadata,
|
|
324
|
-
data,
|
|
325
|
-
hasNext,
|
|
326
|
-
paths
|
|
327
|
-
} = await this._resolveRequest(updatedRequestData, rawResponseData, options, cacheManagerContext);
|
|
328
|
-
let partialQueryResponse;
|
|
329
|
-
|
|
330
|
-
if (cacheManagerContext.queryFiltered) {
|
|
331
|
-
if (!(rawResponseData.hasNext || rawResponseData.paths)) {
|
|
332
|
-
dataCaching.push(this._setQueryResponseCacheEntry(updatedRequestData.hash, {
|
|
333
|
-
cacheMetadata,
|
|
334
|
-
data
|
|
335
|
-
}, options, cacheManagerContext));
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
if (!rawResponseData.paths) {
|
|
339
|
-
partialQueryResponse = this._getPartialQueryResponse(requestData.hash);
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
const responseCacheMetadata = CacheManager._mergeResponseCacheMetadata(cacheMetadata, partialQueryResponse);
|
|
344
|
-
|
|
345
|
-
const responseData = this._mergeResponseData(data, partialQueryResponse);
|
|
346
|
-
|
|
347
|
-
if (!(rawResponseData.hasNext || rawResponseData.paths)) {
|
|
348
|
-
dataCaching.push(this._setQueryResponseCacheEntry(requestData.hash, {
|
|
349
|
-
cacheMetadata: responseCacheMetadata,
|
|
350
|
-
data: responseData
|
|
351
|
-
}, options, cacheManagerContext));
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
if (options.awaitDataCaching) {
|
|
355
|
-
await Promise.all(dataCaching);
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
return {
|
|
359
|
-
cacheMetadata: responseCacheMetadata,
|
|
360
|
-
data: responseData,
|
|
361
|
-
hasNext,
|
|
362
|
-
paths
|
|
363
|
-
};
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
async resolveRequest(requestData, rawResponseData, options, context) {
|
|
367
|
-
const cacheManagerContext = { ...context,
|
|
368
|
-
fragmentDefinitions: getFragmentDefinitions(requestData.ast),
|
|
369
|
-
typeIDKey: this._typeIDKey
|
|
370
|
-
};
|
|
371
|
-
return this._resolveRequest(requestData, rawResponseData, options, cacheManagerContext);
|
|
372
|
-
}
|
|
373
|
-
|
|
374
327
|
async _analyzeFieldNode(fieldNode, cachedAncestorFieldData, cachedResponseData, options, context) {
|
|
375
|
-
if (hasChildFields(fieldNode
|
|
328
|
+
if (hasChildFields(fieldNode, {
|
|
329
|
+
fragmentDefinitions: context.fragmentDefinitions
|
|
330
|
+
})) {
|
|
376
331
|
await this._analyzeParentFieldNode(fieldNode, cachedAncestorFieldData, cachedResponseData, options, context);
|
|
377
332
|
} else {
|
|
378
333
|
await this._analyzeLeafFieldNode(fieldNode, cachedAncestorFieldData, cachedResponseData, options, context);
|
|
@@ -507,6 +462,81 @@ export let CacheManager = (_dec = logCacheQuery(), _dec2 = logCacheEntry(), _dec
|
|
|
507
462
|
return cacheMetadata;
|
|
508
463
|
}
|
|
509
464
|
|
|
465
|
+
async _cacheResponse(requestData, updatedRequestData, rawResponseData, options, context) {
|
|
466
|
+
const normalizedResponseData = normalizePatchResponseData(rawResponseData, context);
|
|
467
|
+
let responseDataForCaching = normalizedResponseData;
|
|
468
|
+
|
|
469
|
+
if (isNotLastResponseChunk(rawResponseData, context)) {
|
|
470
|
+
this._setResponseChunksAwaitingCaching(normalizedResponseData, context);
|
|
471
|
+
|
|
472
|
+
responseDataForCaching = undefined;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
if (isLastResponseChunk(rawResponseData, context)) {
|
|
476
|
+
responseDataForCaching = this._retrieveResponseDataForCaching(normalizedResponseData, context);
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
const dataCaching = [];
|
|
480
|
+
|
|
481
|
+
if (responseDataForCaching) {
|
|
482
|
+
const {
|
|
483
|
+
data
|
|
484
|
+
} = responseDataForCaching;
|
|
485
|
+
|
|
486
|
+
const cacheMetadata = this._buildCacheMetadata(requestData, responseDataForCaching, options, context);
|
|
487
|
+
|
|
488
|
+
dataCaching.push(this._setEntityAndRequestFieldPathCacheEntries(requestData, {
|
|
489
|
+
cacheMetadata,
|
|
490
|
+
entityData: _cloneDeep(data),
|
|
491
|
+
requestFieldPathData: _cloneDeep(data)
|
|
492
|
+
}, options, context));
|
|
493
|
+
let queryCacheMetadata;
|
|
494
|
+
let queryData;
|
|
495
|
+
|
|
496
|
+
if (context.operation === QUERY) {
|
|
497
|
+
let partialQueryResponse;
|
|
498
|
+
|
|
499
|
+
if (context.queryFiltered && updatedRequestData) {
|
|
500
|
+
dataCaching.push(this._setQueryResponseCacheEntry(updatedRequestData.hash, {
|
|
501
|
+
cacheMetadata,
|
|
502
|
+
data
|
|
503
|
+
}, options, context));
|
|
504
|
+
partialQueryResponse = this._getPartialQueryResponse(requestData.hash);
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
queryCacheMetadata = CacheManager._mergeResponseCacheMetadata(cacheMetadata, partialQueryResponse);
|
|
508
|
+
queryData = this._mergeResponseData(data, partialQueryResponse);
|
|
509
|
+
dataCaching.push(this._setQueryResponseCacheEntry(requestData.hash, {
|
|
510
|
+
cacheMetadata: queryCacheMetadata,
|
|
511
|
+
data: queryData
|
|
512
|
+
}, options, context));
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
if (options.awaitDataCaching) {
|
|
516
|
+
await Promise.all(dataCaching);
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
if (isNotResponseChunk(normalizedResponseData, context) && queryCacheMetadata && queryData) {
|
|
520
|
+
return {
|
|
521
|
+
cacheMetadata: queryCacheMetadata,
|
|
522
|
+
data: queryData
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
const {
|
|
528
|
+
data,
|
|
529
|
+
hasNext,
|
|
530
|
+
paths
|
|
531
|
+
} = normalizedResponseData;
|
|
532
|
+
return {
|
|
533
|
+
cacheMetadata: this._buildCacheMetadata(requestData, normalizedResponseData, options, context),
|
|
534
|
+
data,
|
|
535
|
+
hasNext,
|
|
536
|
+
paths
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
|
|
510
540
|
async _checkCacheEntry(cacheType, hash, options, context) {
|
|
511
541
|
try {
|
|
512
542
|
const cacheability = await this._hasCacheEntry(cacheType, hash);
|
|
@@ -652,35 +682,6 @@ export let CacheManager = (_dec = logCacheQuery(), _dec2 = logCacheEntry(), _dec
|
|
|
652
682
|
}, options, context);
|
|
653
683
|
}
|
|
654
684
|
|
|
655
|
-
async _resolveRequest(requestData, rawResponseData, options, context) {
|
|
656
|
-
const normalizedResponseData = rawResponseData.paths ? normalizeResponseData(rawResponseData) : rawResponseData;
|
|
657
|
-
const dataCaching = [];
|
|
658
|
-
|
|
659
|
-
const cacheMetadata = this._buildCacheMetadata(requestData, normalizedResponseData, options, context);
|
|
660
|
-
|
|
661
|
-
const {
|
|
662
|
-
data,
|
|
663
|
-
hasNext,
|
|
664
|
-
paths
|
|
665
|
-
} = normalizedResponseData;
|
|
666
|
-
dataCaching.push(this._setEntityAndRequestFieldPathCacheEntries(requestData, {
|
|
667
|
-
cacheMetadata,
|
|
668
|
-
entityData: _cloneDeep(data),
|
|
669
|
-
requestFieldPathData: _cloneDeep(data)
|
|
670
|
-
}, options, context));
|
|
671
|
-
|
|
672
|
-
if (options.awaitDataCaching) {
|
|
673
|
-
await Promise.all(dataCaching);
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
return {
|
|
677
|
-
cacheMetadata,
|
|
678
|
-
data,
|
|
679
|
-
hasNext,
|
|
680
|
-
paths
|
|
681
|
-
};
|
|
682
|
-
}
|
|
683
|
-
|
|
684
685
|
async _retrieveCachedEntityData(validTypeIDValue, {
|
|
685
686
|
possibleTypes,
|
|
686
687
|
typeName
|
|
@@ -799,6 +800,14 @@ export let CacheManager = (_dec = logCacheQuery(), _dec2 = logCacheEntry(), _dec
|
|
|
799
800
|
return cachedResponseData;
|
|
800
801
|
}
|
|
801
802
|
|
|
803
|
+
_retrieveResponseDataForCaching(normalizedResponseData, context) {
|
|
804
|
+
const responseChunks = this._responseChunksAwaitingCaching.get(context.boxID);
|
|
805
|
+
|
|
806
|
+
this._responseChunksAwaitingCaching.delete(context.boxID);
|
|
807
|
+
|
|
808
|
+
return mergeResponseDataSets([...responseChunks, normalizedResponseData]);
|
|
809
|
+
}
|
|
810
|
+
|
|
802
811
|
async _setCacheEntry(cacheType, hash, value, cachemapOptions, _options, _context) {
|
|
803
812
|
try {
|
|
804
813
|
await this._cache.set(`${cacheType}::${hash}`, _cloneDeep(value), cachemapOptions);
|
|
@@ -1017,7 +1026,9 @@ export let CacheManager = (_dec = logCacheQuery(), _dec2 = logCacheEntry(), _dec
|
|
|
1017
1026
|
tag: options.tag
|
|
1018
1027
|
}, options, context);
|
|
1019
1028
|
|
|
1020
|
-
if (hasChildFields(field
|
|
1029
|
+
if (hasChildFields(field, {
|
|
1030
|
+
fragmentDefinitions: context.fragmentDefinitions
|
|
1031
|
+
})) {
|
|
1021
1032
|
if (isEntity) {
|
|
1022
1033
|
_set(data, responseDataPath, {
|
|
1023
1034
|
__cacheKey: `${REQUEST_FIELD_PATHS}::${hashedRequestFieldCacheKey}`
|
|
@@ -1029,13 +1040,23 @@ export let CacheManager = (_dec = logCacheQuery(), _dec2 = logCacheEntry(), _dec
|
|
|
1029
1040
|
}
|
|
1030
1041
|
}
|
|
1031
1042
|
|
|
1043
|
+
_setResponseChunksAwaitingCaching(normalizedResponseData, context) {
|
|
1044
|
+
const responseChunks = this._responseChunksAwaitingCaching.get(context.boxID);
|
|
1045
|
+
|
|
1046
|
+
if (responseChunks) {
|
|
1047
|
+
this._responseChunksAwaitingCaching.set(context.boxID, [...responseChunks, normalizedResponseData]);
|
|
1048
|
+
} else {
|
|
1049
|
+
this._responseChunksAwaitingCaching.set(context.boxID, [normalizedResponseData]);
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1032
1053
|
}, (_applyDecoratedDescriptor(_class.prototype, "_getCacheEntry", [_dec], Object.getOwnPropertyDescriptor(_class.prototype, "_getCacheEntry"), _class.prototype), _applyDecoratedDescriptor(_class.prototype, "_setCacheEntry", [_dec2], Object.getOwnPropertyDescriptor(_class.prototype, "_setCacheEntry"), _class.prototype), _applyDecoratedDescriptor(_class.prototype, "_setPartialQueryResponse", [_dec3], Object.getOwnPropertyDescriptor(_class.prototype, "_setPartialQueryResponse"), _class.prototype)), _class));
|
|
1033
1054
|
export default function init(userOptions) {
|
|
1034
1055
|
if (!_isPlainObject(userOptions)) {
|
|
1035
1056
|
throw new TypeError("@graphql-box/cache-manager expected userOptions to be a plain object.");
|
|
1036
1057
|
}
|
|
1037
1058
|
|
|
1038
|
-
return clientOptions => CacheManager
|
|
1059
|
+
return clientOptions => new CacheManager({ ...clientOptions,
|
|
1039
1060
|
...userOptions
|
|
1040
1061
|
});
|
|
1041
1062
|
}
|