@lossless.org/client 0.1.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/.smartconfig.json +37 -0
- package/dist_ts/00_commitinfo_data.d.ts +8 -0
- package/dist_ts/00_commitinfo_data.js +9 -0
- package/dist_ts/classes.losslessorgclient.d.ts +32 -0
- package/dist_ts/classes.losslessorgclient.js +103 -0
- package/dist_ts/core/classes.error.d.ts +16 -0
- package/dist_ts/core/classes.error.js +29 -0
- package/dist_ts/core/classes.operation.d.ts +17 -0
- package/dist_ts/core/classes.operation.js +70 -0
- package/dist_ts/core/interfaces.d.ts +18 -0
- package/dist_ts/core/interfaces.js +2 -0
- package/dist_ts/index.d.ts +4 -0
- package/dist_ts/index.js +3 -0
- package/dist_ts/nosqldb/classes.atomicdelete.d.ts +26 -0
- package/dist_ts/nosqldb/classes.atomicdelete.js +44 -0
- package/dist_ts/nosqldb/classes.atomicfindoneandupdate.d.ts +27 -0
- package/dist_ts/nosqldb/classes.atomicfindoneandupdate.js +86 -0
- package/dist_ts/nosqldb/classes.atomicupdate.d.ts +26 -0
- package/dist_ts/nosqldb/classes.atomicupdate.js +55 -0
- package/dist_ts/nosqldb/classes.bootstraprecord.d.ts +14 -0
- package/dist_ts/nosqldb/classes.bootstraprecord.js +80 -0
- package/dist_ts/nosqldb/classes.bsonassertion.d.ts +2 -0
- package/dist_ts/nosqldb/classes.bsonassertion.js +29 -0
- package/dist_ts/nosqldb/classes.bsonobjectid.d.ts +2 -0
- package/dist_ts/nosqldb/classes.bsonobjectid.js +50 -0
- package/dist_ts/nosqldb/classes.bsonsnapshot.d.ts +3 -0
- package/dist_ts/nosqldb/classes.bsonsnapshot.js +126 -0
- package/dist_ts/nosqldb/classes.cached-document.d.ts +27 -0
- package/dist_ts/nosqldb/classes.cached-document.js +112 -0
- package/dist_ts/nosqldb/classes.collection.d.ts +302 -0
- package/dist_ts/nosqldb/classes.collection.js +1568 -0
- package/dist_ts/nosqldb/classes.collectionfactory.d.ts +30 -0
- package/dist_ts/nosqldb/classes.collectionfactory.js +65 -0
- package/dist_ts/nosqldb/classes.collectionlifecycle.d.ts +4 -0
- package/dist_ts/nosqldb/classes.collectionlifecycle.js +15 -0
- package/dist_ts/nosqldb/classes.collectionpreparation.d.ts +34 -0
- package/dist_ts/nosqldb/classes.collectionpreparation.js +134 -0
- package/dist_ts/nosqldb/classes.collectiontopology.d.ts +47 -0
- package/dist_ts/nosqldb/classes.collectiontopology.js +388 -0
- package/dist_ts/nosqldb/classes.connection.d.ts +18 -0
- package/dist_ts/nosqldb/classes.connection.js +23 -0
- package/dist_ts/nosqldb/classes.convenience.d.ts +1 -0
- package/dist_ts/nosqldb/classes.convenience.js +5 -0
- package/dist_ts/nosqldb/classes.cursor.d.ts +15 -0
- package/dist_ts/nosqldb/classes.cursor.js +82 -0
- package/dist_ts/nosqldb/classes.cursoroperation.d.ts +7 -0
- package/dist_ts/nosqldb/classes.cursoroperation.js +36 -0
- package/dist_ts/nosqldb/classes.db.d.ts +98 -0
- package/dist_ts/nosqldb/classes.db.js +434 -0
- package/dist_ts/nosqldb/classes.distributedcoordinator.d.ts +52 -0
- package/dist_ts/nosqldb/classes.distributedcoordinator.js +314 -0
- package/dist_ts/nosqldb/classes.doc.d.ts +722 -0
- package/dist_ts/nosqldb/classes.doc.js +2976 -0
- package/dist_ts/nosqldb/classes.easystore.d.ts +42 -0
- package/dist_ts/nosqldb/classes.easystore.js +199 -0
- package/dist_ts/nosqldb/classes.exactpersistence.d.ts +141 -0
- package/dist_ts/nosqldb/classes.exactpersistence.js +1110 -0
- package/dist_ts/nosqldb/classes.lucene.adapter.d.ts +173 -0
- package/dist_ts/nosqldb/classes.lucene.adapter.js +623 -0
- package/dist_ts/nosqldb/classes.mongoadministration.d.ts +73 -0
- package/dist_ts/nosqldb/classes.mongoadministration.js +497 -0
- package/dist_ts/nosqldb/classes.namespaceinspection.d.ts +42 -0
- package/dist_ts/nosqldb/classes.namespaceinspection.js +138 -0
- package/dist_ts/nosqldb/classes.operationbudget.d.ts +22 -0
- package/dist_ts/nosqldb/classes.operationbudget.js +65 -0
- package/dist_ts/nosqldb/classes.ordinarypersistence.d.ts +18 -0
- package/dist_ts/nosqldb/classes.ordinarypersistence.js +71 -0
- package/dist_ts/nosqldb/classes.persistence.d.ts +14 -0
- package/dist_ts/nosqldb/classes.persistence.js +34 -0
- package/dist_ts/nosqldb/classes.session.d.ts +28 -0
- package/dist_ts/nosqldb/classes.session.js +246 -0
- package/dist_ts/nosqldb/classes.storedinspection.d.ts +44 -0
- package/dist_ts/nosqldb/classes.storedinspection.js +100 -0
- package/dist_ts/nosqldb/classes.testdatabase.d.ts +56 -0
- package/dist_ts/nosqldb/classes.testdatabase.js +250 -0
- package/dist_ts/nosqldb/classes.watcher.d.ts +37 -0
- package/dist_ts/nosqldb/classes.watcher.js +98 -0
- package/dist_ts/nosqldb/index.d.ts +27 -0
- package/dist_ts/nosqldb/index.js +18 -0
- package/dist_ts/nosqldb/logging.d.ts +2 -0
- package/dist_ts/nosqldb/logging.js +3 -0
- package/dist_ts/nosqldb/plugins.d.ts +17 -0
- package/dist_ts/nosqldb/plugins.js +20 -0
- package/dist_ts/nosqldb/shim.d.ts +1 -0
- package/dist_ts/nosqldb/shim.js +8 -0
- package/dist_ts/nosqldb/testsupport.d.ts +3 -0
- package/dist_ts/nosqldb/testsupport.js +3 -0
- package/dist_ts/objectstorage/classes.bucket.d.ts +227 -0
- package/dist_ts/objectstorage/classes.bucket.js +939 -0
- package/dist_ts/objectstorage/classes.connection.d.ts +21 -0
- package/dist_ts/objectstorage/classes.connection.js +27 -0
- package/dist_ts/objectstorage/classes.directory.d.ts +124 -0
- package/dist_ts/objectstorage/classes.directory.js +335 -0
- package/dist_ts/objectstorage/classes.exactpathpurgeerror.d.ts +5 -0
- package/dist_ts/objectstorage/classes.exactpathpurgeerror.js +18 -0
- package/dist_ts/objectstorage/classes.exactuploaderror.d.ts +5 -0
- package/dist_ts/objectstorage/classes.exactuploaderror.js +19 -0
- package/dist_ts/objectstorage/classes.file.d.ts +91 -0
- package/dist_ts/objectstorage/classes.file.js +255 -0
- package/dist_ts/objectstorage/classes.listcursor.d.ts +41 -0
- package/dist_ts/objectstorage/classes.listcursor.js +67 -0
- package/dist_ts/objectstorage/classes.metadata.d.ts +57 -0
- package/dist_ts/objectstorage/classes.metadata.js +113 -0
- package/dist_ts/objectstorage/classes.smartbucket.d.ts +57 -0
- package/dist_ts/objectstorage/classes.smartbucket.js +357 -0
- package/dist_ts/objectstorage/classes.trash.d.ts +11 -0
- package/dist_ts/objectstorage/classes.trash.js +22 -0
- package/dist_ts/objectstorage/classes.watcher.d.ts +79 -0
- package/dist_ts/objectstorage/classes.watcher.js +249 -0
- package/dist_ts/objectstorage/helpers.d.ts +25 -0
- package/dist_ts/objectstorage/helpers.js +215 -0
- package/dist_ts/objectstorage/index.d.ts +13 -0
- package/dist_ts/objectstorage/index.js +13 -0
- package/dist_ts/objectstorage/interfaces.d.ts +276 -0
- package/dist_ts/objectstorage/interfaces.js +2 -0
- package/dist_ts/objectstorage/internal.exactpathpurge.operations.d.ts +11 -0
- package/dist_ts/objectstorage/internal.exactpathpurge.operations.js +1069 -0
- package/dist_ts/objectstorage/internal.exactupload.capability.d.ts +40 -0
- package/dist_ts/objectstorage/internal.exactupload.capability.js +382 -0
- package/dist_ts/objectstorage/internal.exactupload.operations.d.ts +11 -0
- package/dist_ts/objectstorage/internal.exactupload.operations.js +1104 -0
- package/dist_ts/objectstorage/internal.multipart.planner.d.ts +8 -0
- package/dist_ts/objectstorage/internal.multipart.planner.js +63 -0
- package/dist_ts/objectstorage/internal.multipart.stream.d.ts +17 -0
- package/dist_ts/objectstorage/internal.multipart.stream.js +440 -0
- package/dist_ts/objectstorage/internal.multipart.types.d.ts +82 -0
- package/dist_ts/objectstorage/internal.multipart.types.js +2 -0
- package/dist_ts/objectstorage/plugins.d.ts +17 -0
- package/dist_ts/objectstorage/plugins.js +23 -0
- package/dist_ts/plugins.d.ts +4 -0
- package/dist_ts/plugins.js +5 -0
- package/dist_ts/sqldb/classes.clickhouseconnection.d.ts +39 -0
- package/dist_ts/sqldb/classes.clickhouseconnection.js +225 -0
- package/dist_ts/sqldb/classes.sqlconnection.d.ts +50 -0
- package/dist_ts/sqldb/classes.sqlconnection.js +376 -0
- package/dist_ts/sqldb/classes.sqltable.d.ts +29 -0
- package/dist_ts/sqldb/classes.sqltable.js +70 -0
- package/dist_ts/sqldb/clickhouse/classes.metricwriter.d.ts +27 -0
- package/dist_ts/sqldb/clickhouse/classes.metricwriter.js +89 -0
- package/dist_ts/sqldb/clickhouse/index.d.ts +9 -0
- package/dist_ts/sqldb/clickhouse/index.js +13 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.clickhousetable.d.ts +88 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.clickhousetable.js +304 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.httpclient.d.ts +28 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.httpclient.js +46 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.querybuilder.d.ts +43 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.querybuilder.js +155 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.resultset.d.ts +13 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.resultset.js +36 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.smartclickhouse.d.ts +49 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.smartclickhouse.js +106 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.timedatatable.d.ts +51 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.timedatatable.js +96 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.plugins.d.ts +5 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.plugins.js +6 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.types.d.ts +53 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.types.js +41 -0
- package/dist_ts/sqldb/index.d.ts +6 -0
- package/dist_ts/sqldb/index.js +6 -0
- package/dist_ts/sqldb/interfaces.d.ts +53 -0
- package/dist_ts/sqldb/interfaces.js +19 -0
- package/dist_ts/sqldb/internal.sqlpool.d.ts +51 -0
- package/dist_ts/sqldb/internal.sqlpool.js +214 -0
- package/dist_ts/sqldb/plugins.clickhouse.d.ts +4 -0
- package/dist_ts/sqldb/plugins.clickhouse.js +5 -0
- package/dist_ts/sqldb/plugins.mariadb.d.ts +4 -0
- package/dist_ts/sqldb/plugins.mariadb.js +5 -0
- package/docs/source/smartbucket/license.md +19 -0
- package/docs/source/smartclickhouse/license.md +19 -0
- package/license.md +21 -0
- package/package.json +101 -0
- package/readme.md +157 -0
- package/ts/00_commitinfo_data.ts +8 -0
- package/ts/classes.losslessorgclient.ts +104 -0
- package/ts/core/classes.error.ts +31 -0
- package/ts/core/classes.operation.ts +60 -0
- package/ts/core/interfaces.ts +24 -0
- package/ts/index.ts +4 -0
- package/ts/nosqldb/classes.atomicdelete.ts +81 -0
- package/ts/nosqldb/classes.atomicfindoneandupdate.ts +152 -0
- package/ts/nosqldb/classes.atomicupdate.ts +99 -0
- package/ts/nosqldb/classes.bootstraprecord.ts +107 -0
- package/ts/nosqldb/classes.bsonassertion.ts +25 -0
- package/ts/nosqldb/classes.bsonobjectid.ts +45 -0
- package/ts/nosqldb/classes.bsonsnapshot.ts +105 -0
- package/ts/nosqldb/classes.cached-document.ts +67 -0
- package/ts/nosqldb/classes.collection.ts +2399 -0
- package/ts/nosqldb/classes.collectionfactory.ts +87 -0
- package/ts/nosqldb/classes.collectionlifecycle.ts +24 -0
- package/ts/nosqldb/classes.collectionpreparation.ts +164 -0
- package/ts/nosqldb/classes.collectiontopology.ts +645 -0
- package/ts/nosqldb/classes.connection.ts +31 -0
- package/ts/nosqldb/classes.convenience.ts +5 -0
- package/ts/nosqldb/classes.cursor.ts +88 -0
- package/ts/nosqldb/classes.cursoroperation.ts +38 -0
- package/ts/nosqldb/classes.db.ts +637 -0
- package/ts/nosqldb/classes.distributedcoordinator.ts +305 -0
- package/ts/nosqldb/classes.doc.ts +4928 -0
- package/ts/nosqldb/classes.easystore.ts +154 -0
- package/ts/nosqldb/classes.exactpersistence.ts +1974 -0
- package/ts/nosqldb/classes.lucene.adapter.ts +780 -0
- package/ts/nosqldb/classes.mongoadministration.ts +867 -0
- package/ts/nosqldb/classes.namespaceinspection.ts +199 -0
- package/ts/nosqldb/classes.operationbudget.ts +75 -0
- package/ts/nosqldb/classes.ordinarypersistence.ts +84 -0
- package/ts/nosqldb/classes.persistence.ts +62 -0
- package/ts/nosqldb/classes.session.ts +389 -0
- package/ts/nosqldb/classes.storedinspection.ts +151 -0
- package/ts/nosqldb/classes.testdatabase.ts +272 -0
- package/ts/nosqldb/classes.watcher.ts +96 -0
- package/ts/nosqldb/index.ts +51 -0
- package/ts/nosqldb/logging.ts +3 -0
- package/ts/nosqldb/plugins.ts +37 -0
- package/ts/nosqldb/shim.ts +6 -0
- package/ts/nosqldb/testsupport.ts +13 -0
- package/ts/objectstorage/classes.bucket.ts +1114 -0
- package/ts/objectstorage/classes.connection.ts +36 -0
- package/ts/objectstorage/classes.directory.ts +425 -0
- package/ts/objectstorage/classes.exactpathpurgeerror.ts +24 -0
- package/ts/objectstorage/classes.exactuploaderror.ts +25 -0
- package/ts/objectstorage/classes.file.ts +303 -0
- package/ts/objectstorage/classes.listcursor.ts +89 -0
- package/ts/objectstorage/classes.metadata.ts +134 -0
- package/ts/objectstorage/classes.smartbucket.ts +445 -0
- package/ts/objectstorage/classes.trash.ts +30 -0
- package/ts/objectstorage/classes.watcher.ts +289 -0
- package/ts/objectstorage/helpers.ts +254 -0
- package/ts/objectstorage/index.ts +13 -0
- package/ts/objectstorage/interfaces.ts +389 -0
- package/ts/objectstorage/internal.exactpathpurge.operations.ts +1936 -0
- package/ts/objectstorage/internal.exactupload.capability.ts +580 -0
- package/ts/objectstorage/internal.exactupload.operations.ts +1715 -0
- package/ts/objectstorage/internal.multipart.planner.ts +90 -0
- package/ts/objectstorage/internal.multipart.stream.ts +606 -0
- package/ts/objectstorage/internal.multipart.types.ts +106 -0
- package/ts/objectstorage/plugins.ts +35 -0
- package/ts/plugins.ts +4 -0
- package/ts/sqldb/classes.clickhouseconnection.ts +189 -0
- package/ts/sqldb/classes.sqlconnection.ts +350 -0
- package/ts/sqldb/classes.sqltable.ts +70 -0
- package/ts/sqldb/clickhouse/classes.metricwriter.ts +72 -0
- package/ts/sqldb/clickhouse/index.ts +16 -0
- package/ts/sqldb/clickhouse/smartclickhouse.classes.clickhousetable.ts +372 -0
- package/ts/sqldb/clickhouse/smartclickhouse.classes.httpclient.ts +52 -0
- package/ts/sqldb/clickhouse/smartclickhouse.classes.querybuilder.ts +120 -0
- package/ts/sqldb/clickhouse/smartclickhouse.classes.resultset.ts +44 -0
- package/ts/sqldb/clickhouse/smartclickhouse.classes.smartclickhouse.ts +123 -0
- package/ts/sqldb/clickhouse/smartclickhouse.classes.timedatatable.ts +114 -0
- package/ts/sqldb/clickhouse/smartclickhouse.plugins.ts +5 -0
- package/ts/sqldb/clickhouse/smartclickhouse.types.ts +134 -0
- package/ts/sqldb/index.ts +6 -0
- package/ts/sqldb/interfaces.ts +61 -0
- package/ts/sqldb/internal.sqlpool.ts +179 -0
- package/ts/sqldb/plugins.clickhouse.ts +4 -0
- package/ts/sqldb/plugins.mariadb.ts +4 -0
|
@@ -0,0 +1,1568 @@
|
|
|
1
|
+
import * as plugins from './plugins.js';
|
|
2
|
+
import { LosslessClientError } from '../core/classes.error.js';
|
|
3
|
+
import { runCursorOperation } from './classes.cursoroperation.js';
|
|
4
|
+
import { CollectionPreparationBudget, prepareBoundCollection, } from './classes.collectionpreparation.js';
|
|
5
|
+
import { getOrdinaryPersistencePolicy, validateOrdinaryStoredDocument, } from './classes.ordinarypersistence.js';
|
|
6
|
+
import { SmartdataDb } from './classes.db.js';
|
|
7
|
+
import { SmartdataDbCursor } from './classes.cursor.js';
|
|
8
|
+
import { SmartDataDbDoc, } from './classes.doc.js';
|
|
9
|
+
import { SmartdataDbWatcher } from './classes.watcher.js';
|
|
10
|
+
import { CollectionFactory } from './classes.collectionfactory.js';
|
|
11
|
+
import { logger } from './logging.js';
|
|
12
|
+
import { SmartdataPersistenceError, normalizeOrdinaryPersistenceError, } from './classes.persistence.js';
|
|
13
|
+
import { notifyCollectionReconnect } from './classes.collectionlifecycle.js';
|
|
14
|
+
import { runWithOrdinarySmartdataSession, } from './classes.session.js';
|
|
15
|
+
import { collectionModelSchemaResolverSymbol, collectionTopologyDbInspectionSymbol, getExpectedCollectionTopologyForSchema, compareSmartdataTopologyStrings, } from './classes.collectiontopology.js';
|
|
16
|
+
const collectionFactory = new CollectionFactory();
|
|
17
|
+
const unsafeFieldNames = new Set(['__proto__', 'prototype', 'constructor']);
|
|
18
|
+
const automaticTextIndexName = 'smartdata_text_index';
|
|
19
|
+
const requireSafeFieldName = (fieldArg, labelArg, allowPathArg = false) => {
|
|
20
|
+
if (typeof fieldArg !== 'string' ||
|
|
21
|
+
fieldArg.length === 0 ||
|
|
22
|
+
fieldArg.includes('\0') ||
|
|
23
|
+
fieldArg.startsWith('$')) {
|
|
24
|
+
throw new SmartdataPersistenceError('invalid_configuration', `${labelArg} must be a non-empty safe field name.`);
|
|
25
|
+
}
|
|
26
|
+
const segments = fieldArg.split('.');
|
|
27
|
+
if ((!allowPathArg && segments.length !== 1) ||
|
|
28
|
+
segments.some((segmentArg) => segmentArg.length === 0 ||
|
|
29
|
+
segmentArg.startsWith('$') ||
|
|
30
|
+
unsafeFieldNames.has(segmentArg))) {
|
|
31
|
+
throw new SmartdataPersistenceError('invalid_configuration', `${labelArg} contains an unsafe field name.`);
|
|
32
|
+
}
|
|
33
|
+
return fieldArg;
|
|
34
|
+
};
|
|
35
|
+
const normalizeCollectionName = (collectionNameArg, labelArg = 'SmartData collectionName') => {
|
|
36
|
+
if (typeof collectionNameArg !== 'string' ||
|
|
37
|
+
collectionNameArg.trim().length === 0 ||
|
|
38
|
+
collectionNameArg.includes('\0') ||
|
|
39
|
+
collectionNameArg.startsWith('system.')) {
|
|
40
|
+
throw new SmartdataPersistenceError('invalid_configuration', `${labelArg} must be a non-empty non-system name without null bytes.`);
|
|
41
|
+
}
|
|
42
|
+
return collectionNameArg;
|
|
43
|
+
};
|
|
44
|
+
const normalizeIndexOptions = (optionsArg, indexNameArg, allowExtendedOptionsArg = false) => {
|
|
45
|
+
const options = optionsArg || {};
|
|
46
|
+
const allowedKeys = new Set([
|
|
47
|
+
'background',
|
|
48
|
+
'unique',
|
|
49
|
+
'sparse',
|
|
50
|
+
'expireAfterSeconds',
|
|
51
|
+
]);
|
|
52
|
+
if (!allowExtendedOptionsArg) {
|
|
53
|
+
for (const optionName of Object.keys(options)) {
|
|
54
|
+
if (allowedKeys.has(optionName)) {
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
throw new SmartdataPersistenceError('invalid_configuration', `Index "${indexNameArg}" defines unsupported option "${optionName}".`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
for (const booleanOption of ['background', 'unique', 'sparse']) {
|
|
61
|
+
if (options[booleanOption] !== undefined &&
|
|
62
|
+
typeof options[booleanOption] !== 'boolean') {
|
|
63
|
+
throw new SmartdataPersistenceError('invalid_configuration', `Index "${indexNameArg}" option "${booleanOption}" must be boolean.`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (options.expireAfterSeconds !== undefined &&
|
|
67
|
+
(!Number.isFinite(options.expireAfterSeconds) ||
|
|
68
|
+
options.expireAfterSeconds < 0)) {
|
|
69
|
+
throw new SmartdataPersistenceError('invalid_configuration', `Index "${indexNameArg}" expireAfterSeconds must be a finite non-negative number.`);
|
|
70
|
+
}
|
|
71
|
+
return Object.freeze(allowExtendedOptionsArg
|
|
72
|
+
? { ...options }
|
|
73
|
+
: {
|
|
74
|
+
...(options.background === true ? { background: true } : {}),
|
|
75
|
+
...(options.unique === true ? { unique: true } : {}),
|
|
76
|
+
...(options.sparse === true ? { sparse: true } : {}),
|
|
77
|
+
...(options.expireAfterSeconds !== undefined
|
|
78
|
+
? { expireAfterSeconds: options.expireAfterSeconds }
|
|
79
|
+
: {}),
|
|
80
|
+
});
|
|
81
|
+
};
|
|
82
|
+
const stableValue = (valueArg) => {
|
|
83
|
+
if (Array.isArray(valueArg)) {
|
|
84
|
+
return `[${valueArg.map((entryArg) => stableValue(entryArg)).join(',')}]`;
|
|
85
|
+
}
|
|
86
|
+
if (typeof valueArg === 'object' && valueArg !== null) {
|
|
87
|
+
return `{${Object.keys(valueArg)
|
|
88
|
+
.sort(compareSmartdataTopologyStrings)
|
|
89
|
+
.map((keyArg) => `${JSON.stringify(keyArg)}:${stableValue(valueArg[keyArg])}`)
|
|
90
|
+
.join(',')}}`;
|
|
91
|
+
}
|
|
92
|
+
return JSON.stringify(valueArg);
|
|
93
|
+
};
|
|
94
|
+
const normalizeCollectionModelSchema = (configArg, allowExtendedIndexOptionsArg = false, identityValueTypesArg, ordinaryPolicyArg) => {
|
|
95
|
+
if (typeof configArg !== 'object' ||
|
|
96
|
+
configArg === null ||
|
|
97
|
+
Array.isArray(configArg)) {
|
|
98
|
+
throw new SmartdataPersistenceError('invalid_configuration', 'Collection model config must be an object.');
|
|
99
|
+
}
|
|
100
|
+
const allowedConfigKeys = new Set([
|
|
101
|
+
'collectionName',
|
|
102
|
+
'persistedFields',
|
|
103
|
+
'numericFields',
|
|
104
|
+
'identityFields',
|
|
105
|
+
'searchableFields',
|
|
106
|
+
'indexes',
|
|
107
|
+
]);
|
|
108
|
+
for (const key of Object.keys(configArg)) {
|
|
109
|
+
if (!allowedConfigKeys.has(key)) {
|
|
110
|
+
throw new SmartdataPersistenceError('invalid_configuration', `Collection model config defines unsupported key "${key}".`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
const collectionName = normalizeCollectionName(configArg.collectionName);
|
|
114
|
+
if (!Array.isArray(configArg.persistedFields)) {
|
|
115
|
+
throw new SmartdataPersistenceError('invalid_configuration', 'Collection model persistedFields must be an array.');
|
|
116
|
+
}
|
|
117
|
+
const persistedFields = [];
|
|
118
|
+
for (const field of configArg.persistedFields) {
|
|
119
|
+
requireSafeFieldName(field, 'A persisted field');
|
|
120
|
+
if (!persistedFields.includes(field)) {
|
|
121
|
+
persistedFields.push(field);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (ordinaryPolicyArg?.idType === 'string' && !persistedFields.includes('_id')) {
|
|
125
|
+
persistedFields.push('_id');
|
|
126
|
+
}
|
|
127
|
+
if (configArg.numericFields !== undefined &&
|
|
128
|
+
!Array.isArray(configArg.numericFields)) {
|
|
129
|
+
throw new SmartdataPersistenceError('invalid_configuration', 'Collection model numericFields must be an array.');
|
|
130
|
+
}
|
|
131
|
+
const numericFields = [];
|
|
132
|
+
for (const field of configArg.numericFields || []) {
|
|
133
|
+
requireSafeFieldName(field, 'A numeric field');
|
|
134
|
+
if (!persistedFields.includes(field)) {
|
|
135
|
+
throw new SmartdataPersistenceError('invalid_configuration', `Numeric field "${field}" is not a declared persisted field.`);
|
|
136
|
+
}
|
|
137
|
+
if (!numericFields.includes(field)) {
|
|
138
|
+
numericFields.push(field);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
if (configArg.identityFields !== undefined &&
|
|
142
|
+
!Array.isArray(configArg.identityFields)) {
|
|
143
|
+
throw new SmartdataPersistenceError('invalid_configuration', 'Collection model identityFields must be an array.');
|
|
144
|
+
}
|
|
145
|
+
const identityFields = [];
|
|
146
|
+
for (const field of configArg.identityFields || []) {
|
|
147
|
+
requireSafeFieldName(field, 'An identity field');
|
|
148
|
+
if (!persistedFields.includes(field)) {
|
|
149
|
+
throw new SmartdataPersistenceError('invalid_configuration', `Identity field "${field}" is not a declared persisted field.`);
|
|
150
|
+
}
|
|
151
|
+
if (!identityFields.includes(field)) {
|
|
152
|
+
identityFields.push(field);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
const identityValueTypes = {};
|
|
156
|
+
for (const field of Object.keys(identityValueTypesArg || {})) {
|
|
157
|
+
if (!identityFields.includes(field)) {
|
|
158
|
+
throw new SmartdataPersistenceError('invalid_configuration', `Identity valueType field "${field}" is not a declared identity field.`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
for (const field of identityFields) {
|
|
162
|
+
const valueType = identityValueTypesArg?.[field] ?? 'string';
|
|
163
|
+
if (valueType !== 'string' && valueType !== 'positiveSafeInteger') {
|
|
164
|
+
throw new SmartdataPersistenceError('invalid_configuration', `Identity field "${field}" has an unsupported valueType.`);
|
|
165
|
+
}
|
|
166
|
+
identityValueTypes[field] = valueType;
|
|
167
|
+
if (valueType === 'positiveSafeInteger' && !numericFields.includes(field)) {
|
|
168
|
+
numericFields.push(field);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
const searchableFields = [];
|
|
172
|
+
if (configArg.searchableFields !== undefined &&
|
|
173
|
+
!Array.isArray(configArg.searchableFields)) {
|
|
174
|
+
throw new SmartdataPersistenceError('invalid_configuration', 'Collection model searchableFields must be an array.');
|
|
175
|
+
}
|
|
176
|
+
for (const field of configArg.searchableFields || []) {
|
|
177
|
+
requireSafeFieldName(field, 'A searchable field');
|
|
178
|
+
if (!persistedFields.includes(field)) {
|
|
179
|
+
throw new SmartdataPersistenceError('invalid_configuration', `Searchable field "${field}" is not a declared persisted field.`);
|
|
180
|
+
}
|
|
181
|
+
if (!searchableFields.includes(field)) {
|
|
182
|
+
searchableFields.push(field);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
if (configArg.indexes !== undefined && !Array.isArray(configArg.indexes)) {
|
|
186
|
+
throw new SmartdataPersistenceError('invalid_configuration', 'Collection model indexes must be an array.');
|
|
187
|
+
}
|
|
188
|
+
const indexesByName = new Map();
|
|
189
|
+
for (const index of configArg.indexes || []) {
|
|
190
|
+
if (typeof index !== 'object' ||
|
|
191
|
+
index === null ||
|
|
192
|
+
Array.isArray(index) ||
|
|
193
|
+
typeof index.name !== 'string' ||
|
|
194
|
+
index.name.trim().length === 0 ||
|
|
195
|
+
index.name.includes('\0')) {
|
|
196
|
+
throw new SmartdataPersistenceError('invalid_configuration', 'Every collection model index requires a non-empty safe name.');
|
|
197
|
+
}
|
|
198
|
+
if (index.name === automaticTextIndexName) {
|
|
199
|
+
throw new SmartdataPersistenceError('invalid_configuration', `Index name "${automaticTextIndexName}" is reserved for SmartData's automatic text index.`);
|
|
200
|
+
}
|
|
201
|
+
const indexKeys = Object.entries(index.key || {});
|
|
202
|
+
if (indexKeys.length === 0) {
|
|
203
|
+
throw new SmartdataPersistenceError('invalid_configuration', `Index "${index.name}" requires at least one key.`);
|
|
204
|
+
}
|
|
205
|
+
const normalizedKeys = indexKeys.map(([field, direction]) => {
|
|
206
|
+
requireSafeFieldName(field, `Index "${index.name}" field`, true);
|
|
207
|
+
const root = field.split('.')[0];
|
|
208
|
+
if (!persistedFields.includes(root) &&
|
|
209
|
+
root !== '_createdAt' &&
|
|
210
|
+
root !== '_updatedAt') {
|
|
211
|
+
throw new SmartdataPersistenceError('invalid_configuration', `Index "${index.name}" references undeclared field "${field}".`);
|
|
212
|
+
}
|
|
213
|
+
if (direction !== 1 && direction !== -1 && direction !== 'text') {
|
|
214
|
+
throw new SmartdataPersistenceError('invalid_configuration', `Index "${index.name}" has an invalid direction for "${field}".`);
|
|
215
|
+
}
|
|
216
|
+
return Object.freeze([field, direction]);
|
|
217
|
+
});
|
|
218
|
+
const normalizedIndex = Object.freeze({
|
|
219
|
+
name: index.name,
|
|
220
|
+
key: Object.freeze(normalizedKeys),
|
|
221
|
+
options: normalizeIndexOptions(index.options, index.name, allowExtendedIndexOptionsArg),
|
|
222
|
+
});
|
|
223
|
+
const existing = indexesByName.get(index.name);
|
|
224
|
+
if (existing && stableValue(existing) !== stableValue(normalizedIndex)) {
|
|
225
|
+
throw new SmartdataPersistenceError('invalid_configuration', `Index "${index.name}" has divergent declarations.`);
|
|
226
|
+
}
|
|
227
|
+
indexesByName.set(index.name, existing || normalizedIndex);
|
|
228
|
+
}
|
|
229
|
+
const textIndexes = [...indexesByName.values()].filter((indexArg) => indexArg.key.some(([, directionArg]) => directionArg === 'text'));
|
|
230
|
+
if (textIndexes.length > 1) {
|
|
231
|
+
throw new SmartdataPersistenceError('invalid_configuration', 'A collection model may declare at most one text index.');
|
|
232
|
+
}
|
|
233
|
+
if (textIndexes.length === 1) {
|
|
234
|
+
const indexedTextFields = textIndexes[0].key
|
|
235
|
+
.filter(([, directionArg]) => directionArg === 'text')
|
|
236
|
+
.map(([fieldArg]) => fieldArg)
|
|
237
|
+
.sort(compareSmartdataTopologyStrings);
|
|
238
|
+
const normalizedSearchableFields = [...searchableFields].sort(compareSmartdataTopologyStrings);
|
|
239
|
+
if (stableValue(indexedTextFields) !==
|
|
240
|
+
stableValue(normalizedSearchableFields)) {
|
|
241
|
+
throw new SmartdataPersistenceError('invalid_configuration', `Text index "${textIndexes[0].name}" must cover exactly the declared searchable fields.`);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
if (searchableFields.length > 0 && textIndexes.length === 0) {
|
|
245
|
+
indexesByName.set(automaticTextIndexName, Object.freeze({
|
|
246
|
+
name: automaticTextIndexName,
|
|
247
|
+
key: Object.freeze(searchableFields.map((fieldArg) => Object.freeze([fieldArg, 'text']))),
|
|
248
|
+
options: Object.freeze({}),
|
|
249
|
+
}));
|
|
250
|
+
}
|
|
251
|
+
for (const identityField of identityFields) {
|
|
252
|
+
const hasIdentityIndex = [...indexesByName.values()].some((indexArg) => indexArg.options.unique === true &&
|
|
253
|
+
indexArg.key.length === 1 &&
|
|
254
|
+
indexArg.key[0][0] === identityField &&
|
|
255
|
+
indexArg.key[0][1] === 1);
|
|
256
|
+
if (!hasIdentityIndex) {
|
|
257
|
+
throw new SmartdataPersistenceError('invalid_configuration', `Identity field "${identityField}" requires an explicit single-field ascending unique index.`);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
const normalizedCore = {
|
|
261
|
+
ordinaryPersistence: ordinaryPolicyArg,
|
|
262
|
+
collectionName,
|
|
263
|
+
persistedFields: Object.freeze([...persistedFields]),
|
|
264
|
+
numericFields: Object.freeze([...numericFields]),
|
|
265
|
+
identityFields: Object.freeze([...identityFields]),
|
|
266
|
+
identityValueTypes: Object.freeze({ ...identityValueTypes }),
|
|
267
|
+
searchableFields: Object.freeze([...searchableFields]),
|
|
268
|
+
indexes: Object.freeze([...indexesByName.values()]),
|
|
269
|
+
};
|
|
270
|
+
return Object.freeze({
|
|
271
|
+
...normalizedCore,
|
|
272
|
+
fingerprint: stableValue({
|
|
273
|
+
ordinaryPersistence: ordinaryPolicyArg ? {
|
|
274
|
+
idType: ordinaryPolicyArg.idType, timestamps: ordinaryPolicyArg.timestamps,
|
|
275
|
+
} : undefined,
|
|
276
|
+
collectionName,
|
|
277
|
+
persistedFields: [...persistedFields].sort(compareSmartdataTopologyStrings),
|
|
278
|
+
numericFields: [...numericFields].sort(compareSmartdataTopologyStrings),
|
|
279
|
+
identityFields: [...identityFields].sort(compareSmartdataTopologyStrings),
|
|
280
|
+
identityValueTypes,
|
|
281
|
+
searchableFields: [...searchableFields].sort(compareSmartdataTopologyStrings),
|
|
282
|
+
indexes: [...indexesByName.values()].sort((leftArg, rightArg) => compareSmartdataTopologyStrings(leftArg.name, rightArg.name)),
|
|
283
|
+
}),
|
|
284
|
+
});
|
|
285
|
+
};
|
|
286
|
+
const getOwnMetadataValue = (metadata, key) => {
|
|
287
|
+
if (!metadata || !Object.prototype.hasOwnProperty.call(metadata, key)) {
|
|
288
|
+
return undefined;
|
|
289
|
+
}
|
|
290
|
+
return metadata[key];
|
|
291
|
+
};
|
|
292
|
+
const mergeStringArrays = (...arrays) => {
|
|
293
|
+
const merged = [];
|
|
294
|
+
for (const array of arrays) {
|
|
295
|
+
if (!array) {
|
|
296
|
+
continue;
|
|
297
|
+
}
|
|
298
|
+
for (const item of array) {
|
|
299
|
+
if (!merged.includes(item)) {
|
|
300
|
+
merged.push(item);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
return merged;
|
|
305
|
+
};
|
|
306
|
+
const mergeIdentityValueTypes = (...typeMapsArg) => {
|
|
307
|
+
const merged = {};
|
|
308
|
+
for (const typeMap of typeMapsArg) {
|
|
309
|
+
for (const [field, valueType] of Object.entries(typeMap || {})) {
|
|
310
|
+
const existing = merged[field];
|
|
311
|
+
if (existing && existing !== valueType) {
|
|
312
|
+
throw new SmartdataPersistenceError('invalid_configuration', `Identity field "${field}" has divergent inherited valueType declarations.`);
|
|
313
|
+
}
|
|
314
|
+
merged[field] = valueType;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
return merged;
|
|
318
|
+
};
|
|
319
|
+
const mergeRegularIndexes = (...indexArrays) => {
|
|
320
|
+
const mergedMap = new Map();
|
|
321
|
+
for (const indexArray of indexArrays) {
|
|
322
|
+
if (!indexArray) {
|
|
323
|
+
continue;
|
|
324
|
+
}
|
|
325
|
+
for (const indexDef of indexArray) {
|
|
326
|
+
mergedMap.set(indexDef.field, {
|
|
327
|
+
field: indexDef.field,
|
|
328
|
+
options: { ...indexDef.options },
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
return [...mergedMap.values()];
|
|
333
|
+
};
|
|
334
|
+
const stableIndexValue = (valueArg) => {
|
|
335
|
+
if (Array.isArray(valueArg)) {
|
|
336
|
+
return `[${valueArg.map((entryArg) => stableIndexValue(entryArg)).join(',')}]`;
|
|
337
|
+
}
|
|
338
|
+
if (typeof valueArg === 'object' && valueArg !== null) {
|
|
339
|
+
return `{${Object.keys(valueArg)
|
|
340
|
+
.sort(compareSmartdataTopologyStrings)
|
|
341
|
+
.map((keyArg) => `${JSON.stringify(keyArg)}:${stableIndexValue(valueArg[keyArg])}`)
|
|
342
|
+
.join(',')}}`;
|
|
343
|
+
}
|
|
344
|
+
return JSON.stringify(valueArg);
|
|
345
|
+
};
|
|
346
|
+
const compoundIndexesEqual = (leftArg, rightArg) => {
|
|
347
|
+
const leftKeyEntries = Object.entries(leftArg.key);
|
|
348
|
+
const rightKeyEntries = Object.entries(rightArg.key);
|
|
349
|
+
return (stableIndexValue(leftKeyEntries) === stableIndexValue(rightKeyEntries) &&
|
|
350
|
+
stableIndexValue(leftArg.options || {}) ===
|
|
351
|
+
stableIndexValue(rightArg.options || {}));
|
|
352
|
+
};
|
|
353
|
+
const mergeCompoundIndexes = (...indexArrays) => {
|
|
354
|
+
const mergedMap = new Map();
|
|
355
|
+
for (const indexArray of indexArrays) {
|
|
356
|
+
if (!indexArray) {
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
359
|
+
for (const indexDefinition of indexArray) {
|
|
360
|
+
const existing = mergedMap.get(indexDefinition.name);
|
|
361
|
+
if (existing && !compoundIndexesEqual(existing, indexDefinition)) {
|
|
362
|
+
throw new SmartdataPersistenceError('invalid_configuration', `Compound index "${indexDefinition.name}" has divergent inherited declarations.`);
|
|
363
|
+
}
|
|
364
|
+
if (!existing) {
|
|
365
|
+
mergedMap.set(indexDefinition.name, {
|
|
366
|
+
...indexDefinition,
|
|
367
|
+
name: indexDefinition.name,
|
|
368
|
+
key: { ...indexDefinition.key },
|
|
369
|
+
options: { ...(indexDefinition.options || {}) },
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
return [...mergedMap.values()];
|
|
375
|
+
};
|
|
376
|
+
const mergeDecoratorMetadata = (...metadataArgs) => {
|
|
377
|
+
const merged = {};
|
|
378
|
+
merged.globalSaveableProperties = mergeStringArrays(...metadataArgs.map((metadataArg) => getOwnMetadataValue(metadataArg, 'globalSaveableProperties')));
|
|
379
|
+
merged.saveableProperties = mergeStringArrays(...metadataArgs.map((metadataArg) => getOwnMetadataValue(metadataArg, 'saveableProperties')));
|
|
380
|
+
merged.uniqueIndexes = mergeStringArrays(...metadataArgs.map((metadataArg) => getOwnMetadataValue(metadataArg, 'uniqueIndexes')));
|
|
381
|
+
merged.identityValueTypes = mergeIdentityValueTypes(...metadataArgs.map((metadataArg) => getOwnMetadataValue(metadataArg, 'identityValueTypes')));
|
|
382
|
+
merged.searchableFields = mergeStringArrays(...metadataArgs.map((metadataArg) => getOwnMetadataValue(metadataArg, 'searchableFields')));
|
|
383
|
+
merged.regularIndexes = mergeRegularIndexes(...metadataArgs.map((metadataArg) => getOwnMetadataValue(metadataArg, 'regularIndexes')));
|
|
384
|
+
merged.compoundIndexes = mergeCompoundIndexes(...metadataArgs.map((metadataArg) => getOwnMetadataValue(metadataArg, 'compoundIndexes')));
|
|
385
|
+
merged.namedIndexes = mergeCompoundIndexes(...metadataArgs.map((metadataArg) => getOwnMetadataValue(metadataArg, 'namedIndexes')));
|
|
386
|
+
const svDbOptions = {};
|
|
387
|
+
for (const metadataArg of metadataArgs) {
|
|
388
|
+
const options = getOwnMetadataValue(metadataArg, '_svDbOptions');
|
|
389
|
+
if (options) {
|
|
390
|
+
Object.assign(svDbOptions, options);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
if (Object.keys(svDbOptions).length > 0) {
|
|
394
|
+
merged._svDbOptions = svDbOptions;
|
|
395
|
+
}
|
|
396
|
+
return merged;
|
|
397
|
+
};
|
|
398
|
+
const collectInheritedDecoratorMetadata = (constructor) => {
|
|
399
|
+
const metadataChain = [];
|
|
400
|
+
let proto = Object.getPrototypeOf(constructor.prototype);
|
|
401
|
+
while (proto && proto !== Object.prototype) {
|
|
402
|
+
const metadata = proto.constructor?.[Symbol.metadata];
|
|
403
|
+
if (metadata) {
|
|
404
|
+
metadataChain.unshift(metadata);
|
|
405
|
+
}
|
|
406
|
+
proto = Object.getPrototypeOf(proto);
|
|
407
|
+
}
|
|
408
|
+
return mergeDecoratorMetadata(...metadataChain);
|
|
409
|
+
};
|
|
410
|
+
/**
|
|
411
|
+
* Initialize prototype and constructor properties from TC39 decorator metadata.
|
|
412
|
+
* Shared by both Collection and managed decorators.
|
|
413
|
+
*/
|
|
414
|
+
function initializeDecoratorMetadata(constructor, metadata) {
|
|
415
|
+
const mergedMetadata = mergeDecoratorMetadata(collectInheritedDecoratorMetadata(constructor), metadata);
|
|
416
|
+
const proto = constructor.prototype;
|
|
417
|
+
const ctor = constructor;
|
|
418
|
+
// Prototype properties (instance-level)
|
|
419
|
+
if (mergedMetadata.globalSaveableProperties?.length) {
|
|
420
|
+
proto.globalSaveableProperties = [...mergedMetadata.globalSaveableProperties];
|
|
421
|
+
}
|
|
422
|
+
if (mergedMetadata.saveableProperties?.length) {
|
|
423
|
+
proto.saveableProperties = [...mergedMetadata.saveableProperties];
|
|
424
|
+
}
|
|
425
|
+
if (mergedMetadata.uniqueIndexes?.length) {
|
|
426
|
+
proto.uniqueIndexes = [...mergedMetadata.uniqueIndexes];
|
|
427
|
+
}
|
|
428
|
+
if (mergedMetadata.identityValueTypes) {
|
|
429
|
+
proto.identityValueTypes = { ...mergedMetadata.identityValueTypes };
|
|
430
|
+
}
|
|
431
|
+
if (mergedMetadata.regularIndexes?.length) {
|
|
432
|
+
proto.regularIndexes = [...mergedMetadata.regularIndexes];
|
|
433
|
+
}
|
|
434
|
+
if (mergedMetadata.compoundIndexes?.length) {
|
|
435
|
+
proto.compoundIndexes = [...mergedMetadata.compoundIndexes];
|
|
436
|
+
ctor.compoundIndexes = [...mergedMetadata.compoundIndexes];
|
|
437
|
+
}
|
|
438
|
+
// Constructor properties (static-level)
|
|
439
|
+
if (mergedMetadata.searchableFields?.length) {
|
|
440
|
+
ctor.searchableFields = [...mergedMetadata.searchableFields];
|
|
441
|
+
}
|
|
442
|
+
if (mergedMetadata._svDbOptions) {
|
|
443
|
+
ctor._svDbOptions = { ...mergedMetadata._svDbOptions };
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
const definedModelSchemaSymbol = Symbol.for('@push.rocks/smartdata.definedCollectionModelSchema');
|
|
447
|
+
const schemaFromDecoratorMetadata = (constructorArg, collectionNameArg) => {
|
|
448
|
+
const ownMetadata = Object.prototype.hasOwnProperty.call(constructorArg, Symbol.metadata)
|
|
449
|
+
? constructorArg[Symbol.metadata]
|
|
450
|
+
: undefined;
|
|
451
|
+
const metadata = mergeDecoratorMetadata(collectInheritedDecoratorMetadata(constructorArg), ownMetadata);
|
|
452
|
+
const persistedFields = [
|
|
453
|
+
...new Set([
|
|
454
|
+
...(metadata.saveableProperties || []),
|
|
455
|
+
...(metadata.uniqueIndexes || []),
|
|
456
|
+
...(metadata.regularIndexes || []).map((indexArg) => indexArg.field.split('.')[0]),
|
|
457
|
+
...(metadata.compoundIndexes || []).flatMap((indexArg) => Object.keys(indexArg.key).map((fieldArg) => fieldArg.split('.')[0])),
|
|
458
|
+
]),
|
|
459
|
+
];
|
|
460
|
+
const numericFields = Object.entries(metadata._svDbOptions || {})
|
|
461
|
+
.filter(([, optionsArg]) => optionsArg?.numeric === true)
|
|
462
|
+
.map(([fieldArg]) => fieldArg);
|
|
463
|
+
const indexes = [];
|
|
464
|
+
for (const uniqueField of metadata.uniqueIndexes || []) {
|
|
465
|
+
indexes.push({
|
|
466
|
+
name: `${uniqueField}_1`,
|
|
467
|
+
key: { [uniqueField]: 1 },
|
|
468
|
+
options: { unique: true },
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
for (const regularIndex of metadata.regularIndexes || []) {
|
|
472
|
+
const rawOptions = { ...(regularIndex.options || {}) };
|
|
473
|
+
const explicitName = typeof rawOptions.name === 'string'
|
|
474
|
+
? rawOptions.name
|
|
475
|
+
: `${regularIndex.field}_1`;
|
|
476
|
+
delete rawOptions.name;
|
|
477
|
+
indexes.push({
|
|
478
|
+
name: explicitName,
|
|
479
|
+
key: { [regularIndex.field]: 1 },
|
|
480
|
+
options: rawOptions,
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
for (const compoundIndexDefinition of metadata.compoundIndexes || []) {
|
|
484
|
+
const validatedDefinition = validateCompoundIndexDefinition(compoundIndexDefinition);
|
|
485
|
+
indexes.push({
|
|
486
|
+
name: validatedDefinition.name,
|
|
487
|
+
key: { ...validatedDefinition.key },
|
|
488
|
+
options: { ...(validatedDefinition.options || {}) },
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
indexes.push(...(metadata.namedIndexes || []));
|
|
492
|
+
return normalizeCollectionModelSchema({
|
|
493
|
+
collectionName: collectionNameArg,
|
|
494
|
+
persistedFields,
|
|
495
|
+
numericFields,
|
|
496
|
+
identityFields: metadata.uniqueIndexes || [],
|
|
497
|
+
searchableFields: metadata.searchableFields || [],
|
|
498
|
+
indexes,
|
|
499
|
+
}, true, metadata.identityValueTypes, getOrdinaryPersistencePolicy(constructorArg));
|
|
500
|
+
};
|
|
501
|
+
const installCollectionBinding = (constructorArg, dbResolverArg, schemaResolverArg) => {
|
|
502
|
+
const getCollection = (receiverArg) => {
|
|
503
|
+
const db = dbResolverArg(receiverArg);
|
|
504
|
+
if (!(db instanceof SmartdataDb)) {
|
|
505
|
+
throw new SmartdataPersistenceError('invalid_configuration', `Model "${constructorArg.name}" did not resolve a SmartdataDb.`);
|
|
506
|
+
}
|
|
507
|
+
const schema = schemaResolverArg();
|
|
508
|
+
if (schema.ordinaryPersistence !== getOrdinaryPersistencePolicy(constructorArg)) {
|
|
509
|
+
throw new SmartdataPersistenceError('invalid_configuration', 'Persistence policy must be installed before binding a programmatic model.');
|
|
510
|
+
}
|
|
511
|
+
return collectionFactory.getCollection(schema.collectionName, db, schema);
|
|
512
|
+
};
|
|
513
|
+
Object.defineProperty(constructorArg, collectionModelSchemaResolverSymbol, {
|
|
514
|
+
value: schemaResolverArg,
|
|
515
|
+
enumerable: false,
|
|
516
|
+
configurable: true,
|
|
517
|
+
writable: false,
|
|
518
|
+
});
|
|
519
|
+
constructorArg.className = constructorArg.name;
|
|
520
|
+
Object.defineProperty(constructorArg, 'collection', {
|
|
521
|
+
get() {
|
|
522
|
+
return getCollection(this);
|
|
523
|
+
},
|
|
524
|
+
enumerable: false,
|
|
525
|
+
configurable: true,
|
|
526
|
+
});
|
|
527
|
+
Object.defineProperty(constructorArg.prototype, 'collection', {
|
|
528
|
+
get() {
|
|
529
|
+
return getCollection(this);
|
|
530
|
+
},
|
|
531
|
+
enumerable: false,
|
|
532
|
+
configurable: true,
|
|
533
|
+
});
|
|
534
|
+
return constructorArg;
|
|
535
|
+
};
|
|
536
|
+
/**
|
|
537
|
+
* Programmatically declares and binds an ordinary SmartData model.
|
|
538
|
+
*
|
|
539
|
+
* Repeating an equivalent declaration is safe. Divergent declarations for
|
|
540
|
+
* the same constructor, database and collection fail before database work.
|
|
541
|
+
*/
|
|
542
|
+
export function defineCollectionModel(modelArg, dbArg, configArg) {
|
|
543
|
+
if (typeof modelArg !== 'function' ||
|
|
544
|
+
!(modelArg.prototype instanceof SmartDataDbDoc)) {
|
|
545
|
+
throw new SmartdataPersistenceError('invalid_configuration', 'defineCollectionModel requires a SmartDataDbDoc constructor.');
|
|
546
|
+
}
|
|
547
|
+
const inheritedPrototype = Object.getPrototypeOf(modelArg.prototype);
|
|
548
|
+
const inheritedConstructor = Object.getPrototypeOf(modelArg);
|
|
549
|
+
const inheritedSchema = inheritedConstructor?.[definedModelSchemaSymbol];
|
|
550
|
+
const normalizedSchema = normalizeCollectionModelSchema({
|
|
551
|
+
...configArg,
|
|
552
|
+
persistedFields: [
|
|
553
|
+
...(inheritedPrototype?.saveableProperties || []),
|
|
554
|
+
...(configArg.persistedFields || []),
|
|
555
|
+
],
|
|
556
|
+
numericFields: [
|
|
557
|
+
...(inheritedSchema?.numericFields || []),
|
|
558
|
+
...(configArg.numericFields || []),
|
|
559
|
+
],
|
|
560
|
+
identityFields: [
|
|
561
|
+
...(inheritedSchema?.identityFields || []),
|
|
562
|
+
...(configArg.identityFields || []),
|
|
563
|
+
],
|
|
564
|
+
searchableFields: [
|
|
565
|
+
...(inheritedSchema?.searchableFields || []),
|
|
566
|
+
...(configArg.searchableFields || []),
|
|
567
|
+
],
|
|
568
|
+
indexes: [
|
|
569
|
+
...(inheritedSchema?.indexes || [])
|
|
570
|
+
.filter((indexArg) => indexArg.name !== automaticTextIndexName)
|
|
571
|
+
.map((indexArg) => ({
|
|
572
|
+
name: indexArg.name,
|
|
573
|
+
key: Object.fromEntries(indexArg.key),
|
|
574
|
+
options: { ...indexArg.options },
|
|
575
|
+
})),
|
|
576
|
+
...(configArg.indexes || []),
|
|
577
|
+
],
|
|
578
|
+
}, false, undefined, getOrdinaryPersistencePolicy(modelArg));
|
|
579
|
+
const existingOwnSchema = Object.prototype.hasOwnProperty.call(modelArg, definedModelSchemaSymbol)
|
|
580
|
+
? modelArg[definedModelSchemaSymbol]
|
|
581
|
+
: undefined;
|
|
582
|
+
if (existingOwnSchema &&
|
|
583
|
+
(existingOwnSchema.fingerprint !== normalizedSchema.fingerprint ||
|
|
584
|
+
existingOwnSchema.ordinaryPersistence?.assertStoredDocument !==
|
|
585
|
+
normalizedSchema.ordinaryPersistence?.assertStoredDocument)) {
|
|
586
|
+
throw new SmartdataPersistenceError('invalid_configuration', `Model "${modelArg.name}" already has a divergent collection schema.`);
|
|
587
|
+
}
|
|
588
|
+
const effectiveSchema = existingOwnSchema || normalizedSchema;
|
|
589
|
+
if (!existingOwnSchema) {
|
|
590
|
+
Object.defineProperty(modelArg, definedModelSchemaSymbol, {
|
|
591
|
+
value: effectiveSchema,
|
|
592
|
+
enumerable: false,
|
|
593
|
+
configurable: false,
|
|
594
|
+
writable: false,
|
|
595
|
+
});
|
|
596
|
+
}
|
|
597
|
+
modelArg.prototype.saveableProperties = [
|
|
598
|
+
...effectiveSchema.persistedFields,
|
|
599
|
+
];
|
|
600
|
+
modelArg.prototype.uniqueIndexes = [...effectiveSchema.identityFields];
|
|
601
|
+
modelArg.prototype.identityValueTypes = {
|
|
602
|
+
...effectiveSchema.identityValueTypes,
|
|
603
|
+
};
|
|
604
|
+
modelArg.searchableFields = [
|
|
605
|
+
...effectiveSchema.searchableFields,
|
|
606
|
+
];
|
|
607
|
+
return installCollectionBinding(modelArg, () => (dbArg instanceof SmartdataDb ? dbArg : dbArg()), () => effectiveSchema);
|
|
608
|
+
}
|
|
609
|
+
const validateCompoundIndexDefinition = (definitionArg) => {
|
|
610
|
+
if (typeof definitionArg?.name !== 'string' ||
|
|
611
|
+
definitionArg.name.trim().length === 0) {
|
|
612
|
+
throw new SmartdataPersistenceError('invalid_configuration', 'A compound index requires a non-empty name.');
|
|
613
|
+
}
|
|
614
|
+
if (typeof definitionArg.key !== 'object' ||
|
|
615
|
+
definitionArg.key === null ||
|
|
616
|
+
Array.isArray(definitionArg.key) ||
|
|
617
|
+
Object.keys(definitionArg.key).length < 2) {
|
|
618
|
+
throw new SmartdataPersistenceError('invalid_configuration', `Compound index "${definitionArg.name}" requires at least two ordered fields.`);
|
|
619
|
+
}
|
|
620
|
+
for (const [field, direction] of Object.entries(definitionArg.key)) {
|
|
621
|
+
if (field.trim().length === 0 ||
|
|
622
|
+
field.startsWith('$') ||
|
|
623
|
+
field.includes('\0') ||
|
|
624
|
+
(direction !== 1 && direction !== -1)) {
|
|
625
|
+
throw new SmartdataPersistenceError('invalid_configuration', `Compound index "${definitionArg.name}" has an invalid field or direction.`);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
const options = { ...(definitionArg.options || {}) };
|
|
629
|
+
if ('name' in options) {
|
|
630
|
+
throw new SmartdataPersistenceError('invalid_configuration', `Compound index "${definitionArg.name}" must define its name outside options.`);
|
|
631
|
+
}
|
|
632
|
+
if ('unique' in options && typeof options.unique !== 'boolean') {
|
|
633
|
+
throw new SmartdataPersistenceError('invalid_configuration', `Compound index "${definitionArg.name}" has a non-boolean unique option.`);
|
|
634
|
+
}
|
|
635
|
+
if ('sparse' in options && typeof options.sparse !== 'boolean') {
|
|
636
|
+
throw new SmartdataPersistenceError('invalid_configuration', `Compound index "${definitionArg.name}" has a non-boolean sparse option.`);
|
|
637
|
+
}
|
|
638
|
+
if ('expireAfterSeconds' in options &&
|
|
639
|
+
(!Number.isFinite(options.expireAfterSeconds) ||
|
|
640
|
+
options.expireAfterSeconds < 0)) {
|
|
641
|
+
throw new SmartdataPersistenceError('invalid_configuration', `Compound index "${definitionArg.name}" has an invalid expireAfterSeconds option.`);
|
|
642
|
+
}
|
|
643
|
+
return {
|
|
644
|
+
name: definitionArg.name,
|
|
645
|
+
key: { ...definitionArg.key },
|
|
646
|
+
options: { ...(definitionArg.options || {}) },
|
|
647
|
+
};
|
|
648
|
+
};
|
|
649
|
+
/**
|
|
650
|
+
* Declares a stable named compound index owned by a SmartData model.
|
|
651
|
+
*/
|
|
652
|
+
export function compoundIndex(definitionArg) {
|
|
653
|
+
const definition = validateCompoundIndexDefinition(definitionArg);
|
|
654
|
+
return function classDecorator(value, context) {
|
|
655
|
+
if (context.kind !== 'class') {
|
|
656
|
+
throw new Error('compoundIndex can only decorate classes');
|
|
657
|
+
}
|
|
658
|
+
const metadata = context.metadata;
|
|
659
|
+
if (!Object.prototype.hasOwnProperty.call(metadata, 'compoundIndexes')) {
|
|
660
|
+
metadata.compoundIndexes = [...(metadata.compoundIndexes || [])];
|
|
661
|
+
}
|
|
662
|
+
const ownCompoundIndexes = metadata.compoundIndexes;
|
|
663
|
+
const existing = ownCompoundIndexes.find((indexDefinition) => indexDefinition.name === definition.name);
|
|
664
|
+
if (existing && !compoundIndexesEqual(existing, definition)) {
|
|
665
|
+
throw new SmartdataPersistenceError('invalid_configuration', `Compound index "${definition.name}" has divergent declarations.`);
|
|
666
|
+
}
|
|
667
|
+
if (!existing) {
|
|
668
|
+
ownCompoundIndexes.push(definition);
|
|
669
|
+
}
|
|
670
|
+
initializeDecoratorMetadata(value, context.metadata);
|
|
671
|
+
return value;
|
|
672
|
+
};
|
|
673
|
+
}
|
|
674
|
+
/** Declares an inherited named index without implicitly declaring persisted fields. */
|
|
675
|
+
export function namedIndex(definitionArg) {
|
|
676
|
+
const requirePlainDataObject = (valueArg, keysArg) => {
|
|
677
|
+
if (!valueArg || Object.getPrototypeOf(valueArg) !== Object.prototype ||
|
|
678
|
+
Reflect.ownKeys(valueArg).some((keyArg) => typeof keyArg !== 'string' ||
|
|
679
|
+
(keysArg && !keysArg.includes(keyArg)) ||
|
|
680
|
+
!('value' in Object.getOwnPropertyDescriptor(valueArg, keyArg)))) {
|
|
681
|
+
throw new SmartdataPersistenceError('invalid_configuration', 'Invalid named index declaration.');
|
|
682
|
+
}
|
|
683
|
+
};
|
|
684
|
+
requirePlainDataObject(definitionArg, ['name', 'key', 'options']);
|
|
685
|
+
requirePlainDataObject(definitionArg.key);
|
|
686
|
+
if (definitionArg.options !== undefined)
|
|
687
|
+
requirePlainDataObject(definitionArg.options);
|
|
688
|
+
const schema = normalizeCollectionModelSchema({
|
|
689
|
+
collectionName: 'named_index_declaration',
|
|
690
|
+
persistedFields: [...new Set(Object.keys(definitionArg.key).map((pathArg) => pathArg.split('.')[0]))],
|
|
691
|
+
searchableFields: Object.entries(definitionArg.key)
|
|
692
|
+
.filter(([, directionArg]) => directionArg === 'text').map(([pathArg]) => pathArg),
|
|
693
|
+
indexes: [definitionArg],
|
|
694
|
+
});
|
|
695
|
+
// Share topology constraints too (reserved names, index widths, supported options).
|
|
696
|
+
getExpectedCollectionTopologyForSchema(schema);
|
|
697
|
+
const normalized = schema.indexes[0];
|
|
698
|
+
const definition = Object.freeze({
|
|
699
|
+
name: normalized.name,
|
|
700
|
+
key: Object.freeze(Object.fromEntries(normalized.key)),
|
|
701
|
+
options: normalized.options,
|
|
702
|
+
});
|
|
703
|
+
return function classDecorator(value, context) {
|
|
704
|
+
if (context.kind !== 'class') {
|
|
705
|
+
throw new SmartdataPersistenceError('invalid_configuration', 'namedIndex can only decorate classes.');
|
|
706
|
+
}
|
|
707
|
+
const metadata = context.metadata;
|
|
708
|
+
metadata.namedIndexes = mergeCompoundIndexes(metadata.namedIndexes, [definition]);
|
|
709
|
+
return value;
|
|
710
|
+
};
|
|
711
|
+
}
|
|
712
|
+
/**
|
|
713
|
+
* This is a decorator that will tell the decorated class what dbTable to use
|
|
714
|
+
* @param dbArg
|
|
715
|
+
*/
|
|
716
|
+
export function Collection(dbArg, optionsArg) {
|
|
717
|
+
return function classDecorator(value, context) {
|
|
718
|
+
if (context.kind !== 'class') {
|
|
719
|
+
throw new Error('Collection can only decorate classes');
|
|
720
|
+
}
|
|
721
|
+
const constructor = value;
|
|
722
|
+
initializeDecoratorMetadata(constructor, context.metadata);
|
|
723
|
+
const collectionName = normalizeCollectionName(optionsArg?.collectionName ?? constructor.name);
|
|
724
|
+
return installCollectionBinding(constructor, () => (dbArg instanceof SmartdataDb ? dbArg : dbArg()), () => {
|
|
725
|
+
return schemaFromDecoratorMetadata(constructor, collectionName);
|
|
726
|
+
});
|
|
727
|
+
};
|
|
728
|
+
}
|
|
729
|
+
export const setDefaultManagerForDoc = (managerArg, dbDocArg) => {
|
|
730
|
+
dbDocArg.prototype.defaultManager = managerArg;
|
|
731
|
+
return dbDocArg;
|
|
732
|
+
};
|
|
733
|
+
/**
|
|
734
|
+
* This is a decorator that will tell the decorated class what dbTable to use
|
|
735
|
+
* @param dbArg
|
|
736
|
+
*/
|
|
737
|
+
export function managed(managerOrOptionsArg, optionsArg) {
|
|
738
|
+
const firstArgumentIsOptions = typeof managerOrOptionsArg === 'object' &&
|
|
739
|
+
managerOrOptionsArg !== null &&
|
|
740
|
+
!('db' in managerOrOptionsArg) &&
|
|
741
|
+
'collectionName' in managerOrOptionsArg &&
|
|
742
|
+
optionsArg === undefined;
|
|
743
|
+
const managerArg = firstArgumentIsOptions
|
|
744
|
+
? undefined
|
|
745
|
+
: managerOrOptionsArg;
|
|
746
|
+
const bindingOptions = firstArgumentIsOptions
|
|
747
|
+
? managerOrOptionsArg
|
|
748
|
+
: optionsArg;
|
|
749
|
+
return function classDecorator(value, context) {
|
|
750
|
+
if (context.kind !== 'class') {
|
|
751
|
+
throw new Error('managed can only decorate classes');
|
|
752
|
+
}
|
|
753
|
+
const constructor = value;
|
|
754
|
+
initializeDecoratorMetadata(constructor, context.metadata);
|
|
755
|
+
// Resolution helpers (capture managerArg via closure)
|
|
756
|
+
const getManager = (receiverArg) => {
|
|
757
|
+
if (!managerArg) {
|
|
758
|
+
if (typeof receiverArg === 'function') {
|
|
759
|
+
return receiverArg.prototype.defaultManager;
|
|
760
|
+
}
|
|
761
|
+
return (receiverArg
|
|
762
|
+
?.defaultManager ?? constructor.prototype.defaultManager);
|
|
763
|
+
}
|
|
764
|
+
if (typeof managerArg !== 'function' && managerArg.db) {
|
|
765
|
+
return managerArg;
|
|
766
|
+
}
|
|
767
|
+
return managerArg();
|
|
768
|
+
};
|
|
769
|
+
const collectionName = normalizeCollectionName(bindingOptions?.collectionName ?? constructor.name);
|
|
770
|
+
installCollectionBinding(constructor, (receiverArg) => getManager(receiverArg).db, () => {
|
|
771
|
+
return schemaFromDecoratorMetadata(constructor, collectionName);
|
|
772
|
+
});
|
|
773
|
+
Object.defineProperty(constructor, 'manager', {
|
|
774
|
+
get() { return getManager(this); },
|
|
775
|
+
enumerable: false,
|
|
776
|
+
configurable: true
|
|
777
|
+
});
|
|
778
|
+
Object.defineProperty(constructor.prototype, 'manager', {
|
|
779
|
+
get() { return getManager(this); },
|
|
780
|
+
enumerable: false,
|
|
781
|
+
configurable: true
|
|
782
|
+
});
|
|
783
|
+
return constructor;
|
|
784
|
+
};
|
|
785
|
+
}
|
|
786
|
+
/**
|
|
787
|
+
* @dpecrecated use @managed instead
|
|
788
|
+
*/
|
|
789
|
+
export const Manager = managed;
|
|
790
|
+
export class SmartdataCollection {
|
|
791
|
+
/**
|
|
792
|
+
* the collection that is used
|
|
793
|
+
*/
|
|
794
|
+
mongoDbCollection;
|
|
795
|
+
objectValidation = null;
|
|
796
|
+
collectionName;
|
|
797
|
+
smartdataDb;
|
|
798
|
+
uniqueIndexes = [];
|
|
799
|
+
regularIndexes = [];
|
|
800
|
+
compoundIndexes = [];
|
|
801
|
+
modelSchema;
|
|
802
|
+
initializationPromise;
|
|
803
|
+
initializationGeneration = 0;
|
|
804
|
+
initialized = false;
|
|
805
|
+
constructor(classNameArg, smartDataDbArg) {
|
|
806
|
+
// tell the collection where it belongs
|
|
807
|
+
this.collectionName = classNameArg;
|
|
808
|
+
this.smartdataDb = smartDataDbArg;
|
|
809
|
+
// tell the db class about it (important since Db uses different systems under the hood)
|
|
810
|
+
this.smartdataDb.addCollection(this);
|
|
811
|
+
}
|
|
812
|
+
runWithOrdinarySession(sessionArg, ordinaryWriteArg, operationArg) {
|
|
813
|
+
return runWithOrdinarySmartdataSession(sessionArg, this.smartdataDb, {
|
|
814
|
+
ordinaryWrite: ordinaryWriteArg,
|
|
815
|
+
prepared: this.isInitializedForCurrentDatabase(),
|
|
816
|
+
preparationMessage: `Initialize collection "${this.collectionName}" before using an owned SmartData session.`,
|
|
817
|
+
}, operationArg);
|
|
818
|
+
}
|
|
819
|
+
/**
|
|
820
|
+
* Returns the deep-frozen normalized model schema bound to this collection,
|
|
821
|
+
* or undefined when no model schema has been bound yet. The schema exposes
|
|
822
|
+
* declared fields and named index definitions only, never raw driver access.
|
|
823
|
+
*/
|
|
824
|
+
getBoundModelSchema() {
|
|
825
|
+
return this.modelSchema;
|
|
826
|
+
}
|
|
827
|
+
bindModelSchema(schemaArg) {
|
|
828
|
+
if (schemaArg.collectionName !== this.collectionName ||
|
|
829
|
+
(this.modelSchema &&
|
|
830
|
+
(this.modelSchema.fingerprint !== schemaArg.fingerprint ||
|
|
831
|
+
this.modelSchema.ordinaryPersistence?.assertStoredDocument !==
|
|
832
|
+
schemaArg.ordinaryPersistence?.assertStoredDocument))) {
|
|
833
|
+
throw new SmartdataPersistenceError('invalid_configuration', `Collection "${this.collectionName}" cannot bind a divergent model schema.`);
|
|
834
|
+
}
|
|
835
|
+
if (!this.modelSchema) {
|
|
836
|
+
this.modelSchema = schemaArg;
|
|
837
|
+
this.initializationGeneration++;
|
|
838
|
+
this.initialized = false;
|
|
839
|
+
this.initializationPromise = undefined;
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
resetForDatabaseReconnect() {
|
|
843
|
+
this.initializationGeneration++;
|
|
844
|
+
delete this
|
|
845
|
+
.mongoDbCollection;
|
|
846
|
+
this.initialized = false;
|
|
847
|
+
this.initializationPromise = undefined;
|
|
848
|
+
this.uniqueIndexes = [];
|
|
849
|
+
this.regularIndexes = [];
|
|
850
|
+
this.compoundIndexes = [];
|
|
851
|
+
notifyCollectionReconnect(this);
|
|
852
|
+
}
|
|
853
|
+
/**
|
|
854
|
+
* makes sure a collection exists within MongoDb that maps to the SmartdataCollection
|
|
855
|
+
*/
|
|
856
|
+
async init() {
|
|
857
|
+
if (this.initialized) {
|
|
858
|
+
return;
|
|
859
|
+
}
|
|
860
|
+
if (!this.initializationPromise) {
|
|
861
|
+
const generation = this.initializationGeneration;
|
|
862
|
+
const targetDb = this.smartdataDb.mongoDb;
|
|
863
|
+
let initializationPromise;
|
|
864
|
+
initializationPromise = this.initializeOnce(targetDb, generation)
|
|
865
|
+
.then(() => {
|
|
866
|
+
if (this.initializationGeneration === generation
|
|
867
|
+
&& this.smartdataDb.mongoDb === targetDb) {
|
|
868
|
+
this.initialized = true;
|
|
869
|
+
}
|
|
870
|
+
})
|
|
871
|
+
.catch((errorArg) => {
|
|
872
|
+
const isCurrentGeneration = this.initializationGeneration === generation
|
|
873
|
+
&& this.smartdataDb.mongoDb === targetDb;
|
|
874
|
+
if (this.initializationPromise === initializationPromise) {
|
|
875
|
+
this.initializationPromise = undefined;
|
|
876
|
+
if (isCurrentGeneration) {
|
|
877
|
+
this.initialized = false;
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
if (isCurrentGeneration) {
|
|
881
|
+
throw errorArg;
|
|
882
|
+
}
|
|
883
|
+
})
|
|
884
|
+
.finally(() => {
|
|
885
|
+
if (this.initializationPromise === initializationPromise) {
|
|
886
|
+
this.initializationPromise = undefined;
|
|
887
|
+
}
|
|
888
|
+
});
|
|
889
|
+
this.initializationPromise = initializationPromise;
|
|
890
|
+
}
|
|
891
|
+
const initializationPromise = this.initializationPromise;
|
|
892
|
+
await initializationPromise;
|
|
893
|
+
if (!this.initialized) {
|
|
894
|
+
await this.init();
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
async ensureInitialized() {
|
|
898
|
+
await this.init();
|
|
899
|
+
}
|
|
900
|
+
/** Explicit bounded preparation of the bound model's exact declared topology. */
|
|
901
|
+
async prepareCollection(opts) {
|
|
902
|
+
const budget = new CollectionPreparationBudget(opts);
|
|
903
|
+
const generation = this.initializationGeneration;
|
|
904
|
+
const targetDb = this.smartdataDb.mongoDb;
|
|
905
|
+
const assertCurrent = () => {
|
|
906
|
+
budget.check();
|
|
907
|
+
if (this.initializationGeneration !== generation || this.smartdataDb.mongoDb !== targetDb ||
|
|
908
|
+
this.smartdataDb.status !== 'connected') {
|
|
909
|
+
throw new SmartdataPersistenceError('unsupported_operation', 'SmartData connection changed during collection preparation.');
|
|
910
|
+
}
|
|
911
|
+
};
|
|
912
|
+
try {
|
|
913
|
+
if (!this.modelSchema) {
|
|
914
|
+
throw new SmartdataPersistenceError('invalid_configuration', 'Collection preparation requires a bound model schema.');
|
|
915
|
+
}
|
|
916
|
+
// The caller owns its waiting deadline, not the preceding operation.
|
|
917
|
+
while (this.initializationPromise) {
|
|
918
|
+
await budget.waitFor(this.initializationPromise);
|
|
919
|
+
assertCurrent();
|
|
920
|
+
}
|
|
921
|
+
assertCurrent();
|
|
922
|
+
this.initialized = false;
|
|
923
|
+
const schema = this.modelSchema;
|
|
924
|
+
const preparation = (async () => {
|
|
925
|
+
const outcome = await this.smartdataDb[collectionTopologyDbInspectionSymbol](async (dbArg) => {
|
|
926
|
+
try {
|
|
927
|
+
return { collection: await prepareBoundCollection(dbArg, schema, budget, assertCurrent) };
|
|
928
|
+
}
|
|
929
|
+
catch (errorArg) {
|
|
930
|
+
// Let the connection owner check its epoch before publishing either outcome.
|
|
931
|
+
return { error: errorArg };
|
|
932
|
+
}
|
|
933
|
+
});
|
|
934
|
+
assertCurrent();
|
|
935
|
+
if ('error' in outcome)
|
|
936
|
+
throw outcome.error;
|
|
937
|
+
this.mongoDbCollection = outcome.collection;
|
|
938
|
+
this.publishModelIndexes(schema);
|
|
939
|
+
this.initialized = true;
|
|
940
|
+
})();
|
|
941
|
+
this.initializationPromise = preparation;
|
|
942
|
+
try {
|
|
943
|
+
await preparation;
|
|
944
|
+
}
|
|
945
|
+
finally {
|
|
946
|
+
if (this.initializationPromise === preparation)
|
|
947
|
+
this.initializationPromise = undefined;
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
catch (errorArg) {
|
|
951
|
+
budget.check();
|
|
952
|
+
throw errorArg;
|
|
953
|
+
}
|
|
954
|
+
finally {
|
|
955
|
+
budget.close();
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
isInitializedForCurrentDatabase() {
|
|
959
|
+
return this.initialized && Boolean(this.mongoDbCollection);
|
|
960
|
+
}
|
|
961
|
+
async initializeOnce(targetDbArg, generationArg) {
|
|
962
|
+
let targetCollection = this.mongoDbCollection;
|
|
963
|
+
if (!targetCollection) {
|
|
964
|
+
const wantedCollection = await targetDbArg
|
|
965
|
+
.listCollections({ name: this.collectionName }, { nameOnly: true })
|
|
966
|
+
.hasNext();
|
|
967
|
+
if (!wantedCollection) {
|
|
968
|
+
try {
|
|
969
|
+
await targetDbArg.createCollection(this.collectionName);
|
|
970
|
+
}
|
|
971
|
+
catch (errorArg) {
|
|
972
|
+
const mongoError = errorArg;
|
|
973
|
+
if (mongoError.code !== 48) {
|
|
974
|
+
throw errorArg;
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
logger.log('info', `Successfully initiated Collection ${this.collectionName}`);
|
|
978
|
+
}
|
|
979
|
+
targetCollection = targetDbArg.collection(this.collectionName);
|
|
980
|
+
}
|
|
981
|
+
if (this.initializationGeneration !== generationArg
|
|
982
|
+
|| this.smartdataDb.mongoDb !== targetDbArg) {
|
|
983
|
+
return;
|
|
984
|
+
}
|
|
985
|
+
this.mongoDbCollection = targetCollection;
|
|
986
|
+
const modelSchema = this.modelSchema;
|
|
987
|
+
if (!modelSchema) {
|
|
988
|
+
return;
|
|
989
|
+
}
|
|
990
|
+
for (const index of modelSchema.indexes) {
|
|
991
|
+
await targetCollection.createIndex(Object.fromEntries(index.key), {
|
|
992
|
+
...index.options,
|
|
993
|
+
name: index.name,
|
|
994
|
+
});
|
|
995
|
+
}
|
|
996
|
+
const actualIndexes = await targetCollection.listIndexes().toArray();
|
|
997
|
+
for (const expected of modelSchema.indexes) {
|
|
998
|
+
const actual = actualIndexes.find((indexArg) => indexArg.name === expected.name);
|
|
999
|
+
if (!actual) {
|
|
1000
|
+
throw new SmartdataPersistenceError('invalid_configuration', `Index "${expected.name}" was not created on "${this.collectionName}".`);
|
|
1001
|
+
}
|
|
1002
|
+
const actualKeyEntries = Object.entries(actual.key || {});
|
|
1003
|
+
const expectedTextFields = expected.key
|
|
1004
|
+
.filter(([, directionArg]) => directionArg === 'text')
|
|
1005
|
+
.map(([fieldArg]) => fieldArg);
|
|
1006
|
+
const canonicalExpectedKey = [];
|
|
1007
|
+
let textMarkerAdded = false;
|
|
1008
|
+
for (const [field, direction] of expected.key) {
|
|
1009
|
+
if (direction === 'text') {
|
|
1010
|
+
if (!textMarkerAdded) {
|
|
1011
|
+
canonicalExpectedKey.push(['_fts', 'text'], ['_ftsx', 1]);
|
|
1012
|
+
textMarkerAdded = true;
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
else {
|
|
1016
|
+
canonicalExpectedKey.push([field, direction]);
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
const actualTextFields = Object.keys(actual.weights || {}).sort(compareSmartdataTopologyStrings);
|
|
1020
|
+
if (stableValue(actualKeyEntries) !==
|
|
1021
|
+
stableValue(canonicalExpectedKey) ||
|
|
1022
|
+
stableValue(actualTextFields) !==
|
|
1023
|
+
stableValue([...expectedTextFields].sort(compareSmartdataTopologyStrings))) {
|
|
1024
|
+
throw new SmartdataPersistenceError('invalid_configuration', `Index "${expected.name}" has an unexpected key specification.`);
|
|
1025
|
+
}
|
|
1026
|
+
for (const booleanOption of ['unique', 'sparse']) {
|
|
1027
|
+
if (Boolean(actual[booleanOption]) !==
|
|
1028
|
+
Boolean(expected.options[booleanOption])) {
|
|
1029
|
+
throw new SmartdataPersistenceError('invalid_configuration', `Index "${expected.name}" has an unexpected "${booleanOption}" option.`);
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
if (expected.options.expireAfterSeconds !== undefined &&
|
|
1033
|
+
actual.expireAfterSeconds !==
|
|
1034
|
+
expected.options.expireAfterSeconds) {
|
|
1035
|
+
throw new SmartdataPersistenceError('invalid_configuration', `Index "${expected.name}" has an unexpected expireAfterSeconds option.`);
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
if (this.initializationGeneration !== generationArg
|
|
1039
|
+
|| this.smartdataDb.mongoDb !== targetDbArg
|
|
1040
|
+
|| this.mongoDbCollection !== targetCollection) {
|
|
1041
|
+
return;
|
|
1042
|
+
}
|
|
1043
|
+
this.publishModelIndexes(modelSchema);
|
|
1044
|
+
}
|
|
1045
|
+
publishModelIndexes(modelSchema) {
|
|
1046
|
+
this.uniqueIndexes = modelSchema.indexes
|
|
1047
|
+
.filter((indexArg) => indexArg.options.unique)
|
|
1048
|
+
.filter((indexArg) => indexArg.key.length === 1 && indexArg.key[0][1] === 1)
|
|
1049
|
+
.map((indexArg) => indexArg.key[0][0]);
|
|
1050
|
+
this.regularIndexes = modelSchema.indexes
|
|
1051
|
+
.filter((indexArg) => indexArg.key.length === 1 &&
|
|
1052
|
+
indexArg.key[0][1] === 1)
|
|
1053
|
+
.map((indexArg) => ({
|
|
1054
|
+
field: indexArg.key[0][0],
|
|
1055
|
+
options: { ...indexArg.options },
|
|
1056
|
+
}));
|
|
1057
|
+
this.compoundIndexes = modelSchema.indexes
|
|
1058
|
+
.filter((indexArg) => indexArg.key.length >= 2 &&
|
|
1059
|
+
indexArg.key.every(([, directionArg]) => directionArg !== 'text'))
|
|
1060
|
+
.map((indexArg) => ({
|
|
1061
|
+
name: indexArg.name,
|
|
1062
|
+
key: Object.fromEntries(indexArg.key),
|
|
1063
|
+
options: { ...indexArg.options },
|
|
1064
|
+
}));
|
|
1065
|
+
}
|
|
1066
|
+
/**
|
|
1067
|
+
* mark unique index
|
|
1068
|
+
*/
|
|
1069
|
+
async markUniqueIndexes(keyArrayArg = []) {
|
|
1070
|
+
for (const key of keyArrayArg) {
|
|
1071
|
+
if (!this.uniqueIndexes.includes(key)) {
|
|
1072
|
+
try {
|
|
1073
|
+
await this.mongoDbCollection.createIndex({ [key]: 1 }, {
|
|
1074
|
+
unique: true,
|
|
1075
|
+
name: `${key}_1`,
|
|
1076
|
+
});
|
|
1077
|
+
this.uniqueIndexes.push(key);
|
|
1078
|
+
}
|
|
1079
|
+
catch (err) {
|
|
1080
|
+
const errorCode = err?.code || err?.codeName || 'unknown';
|
|
1081
|
+
const errorMessage = err?.message || String(err);
|
|
1082
|
+
logger.log('error', `Failed to create unique index on field "${key}" in collection "${this.collectionName}". ` +
|
|
1083
|
+
`MongoDB error [${errorCode}]: ${errorMessage}. ` +
|
|
1084
|
+
`Uniqueness constraint on "${key}" is NOT enforced.`);
|
|
1085
|
+
if (errorCode === 11000 || errorCode === 'DuplicateKey' || String(errorMessage).includes('E11000')) {
|
|
1086
|
+
await this.logDuplicatesForField(key);
|
|
1087
|
+
}
|
|
1088
|
+
throw err;
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
/**
|
|
1094
|
+
* creates regular indexes for the collection
|
|
1095
|
+
*/
|
|
1096
|
+
async createRegularIndexes(indexesArg = []) {
|
|
1097
|
+
for (const indexDef of indexesArg) {
|
|
1098
|
+
// Check if we've already created this index
|
|
1099
|
+
const indexKey = indexDef.field;
|
|
1100
|
+
if (!this.regularIndexes.some(i => i.field === indexKey)) {
|
|
1101
|
+
try {
|
|
1102
|
+
await this.mongoDbCollection.createIndex({ [indexDef.field]: 1 }, // Simple single-field index
|
|
1103
|
+
indexDef.options);
|
|
1104
|
+
this.regularIndexes.push(indexDef);
|
|
1105
|
+
}
|
|
1106
|
+
catch (err) {
|
|
1107
|
+
const errorCode = err?.code || err?.codeName || 'unknown';
|
|
1108
|
+
const errorMessage = err?.message || String(err);
|
|
1109
|
+
logger.log('warn', `Failed to create index on field "${indexKey}" in collection "${this.collectionName}". ` +
|
|
1110
|
+
`MongoDB error [${errorCode}]: ${errorMessage}.`);
|
|
1111
|
+
if (indexDef.options?.unique &&
|
|
1112
|
+
(errorCode === 11000 || errorCode === 'DuplicateKey' || String(errorMessage).includes('E11000'))) {
|
|
1113
|
+
await this.logDuplicatesForField(indexKey);
|
|
1114
|
+
}
|
|
1115
|
+
throw err;
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
/**
|
|
1121
|
+
* Logs duplicate values for a field to help diagnose unique index creation failures.
|
|
1122
|
+
*/
|
|
1123
|
+
async logDuplicatesForField(field) {
|
|
1124
|
+
try {
|
|
1125
|
+
const pipeline = [
|
|
1126
|
+
{ $group: { _id: `$${field}`, count: { $sum: 1 }, ids: { $push: '$_id' } } },
|
|
1127
|
+
{ $match: { count: { $gt: 1 } } },
|
|
1128
|
+
{ $limit: 5 },
|
|
1129
|
+
];
|
|
1130
|
+
const duplicates = await this.mongoDbCollection.aggregate(pipeline).toArray();
|
|
1131
|
+
if (duplicates.length > 0) {
|
|
1132
|
+
for (const dup of duplicates) {
|
|
1133
|
+
logger.log('warn', `Duplicate values for "${field}" in "${this.collectionName}": ` +
|
|
1134
|
+
`value=${JSON.stringify(dup._id)} appears ${dup.count} times ` +
|
|
1135
|
+
`(document _ids: ${JSON.stringify(dup.ids.slice(0, 5))})`);
|
|
1136
|
+
}
|
|
1137
|
+
logger.log('warn', `Unique index on "${field}" in "${this.collectionName}" was NOT created. ` +
|
|
1138
|
+
`Resolve duplicates and restart to enforce uniqueness.`);
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
catch (aggErr) {
|
|
1142
|
+
logger.log('warn', `Could not identify duplicate documents for field "${field}" in "${this.collectionName}": ${aggErr?.message || String(aggErr)}`);
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
/**
|
|
1146
|
+
* adds a validation function that all newly inserted and updated objects have to pass
|
|
1147
|
+
*/
|
|
1148
|
+
addDocValidation(funcArg) {
|
|
1149
|
+
this.objectValidation = funcArg;
|
|
1150
|
+
}
|
|
1151
|
+
/**
|
|
1152
|
+
* finds an object in the DbCollection
|
|
1153
|
+
*/
|
|
1154
|
+
async findOne(filterObject, opts) {
|
|
1155
|
+
return this.runWithOrdinarySession(opts?.session, false, async (rawSessionArg) => {
|
|
1156
|
+
await this.init();
|
|
1157
|
+
return this.mongoDbCollection.findOne(filterObject, {
|
|
1158
|
+
projection: opts?.projection,
|
|
1159
|
+
maxTimeMS: opts?.maxTimeMS,
|
|
1160
|
+
session: rawSessionArg,
|
|
1161
|
+
});
|
|
1162
|
+
});
|
|
1163
|
+
}
|
|
1164
|
+
async getCursor(filterObjectArg, dbDocArg, opts) {
|
|
1165
|
+
await this.init();
|
|
1166
|
+
const cursor = this.mongoDbCollection.find(filterObjectArg, { session: opts?.session });
|
|
1167
|
+
return new SmartdataDbCursor(cursor, dbDocArg);
|
|
1168
|
+
}
|
|
1169
|
+
/**
|
|
1170
|
+
* finds an object in the DbCollection
|
|
1171
|
+
*/
|
|
1172
|
+
async findAll(filterObject, opts) {
|
|
1173
|
+
return this.runWithOrdinarySession(opts?.session, false, async (rawSessionArg) => {
|
|
1174
|
+
await this.init();
|
|
1175
|
+
const cursor = this.mongoDbCollection.find(filterObject, {
|
|
1176
|
+
session: rawSessionArg,
|
|
1177
|
+
});
|
|
1178
|
+
let result;
|
|
1179
|
+
let operationFailed = false;
|
|
1180
|
+
try {
|
|
1181
|
+
result = await cursor.toArray();
|
|
1182
|
+
}
|
|
1183
|
+
catch (errorArg) {
|
|
1184
|
+
operationFailed = true;
|
|
1185
|
+
throw errorArg;
|
|
1186
|
+
}
|
|
1187
|
+
finally {
|
|
1188
|
+
try {
|
|
1189
|
+
await cursor.close();
|
|
1190
|
+
}
|
|
1191
|
+
catch (closeError) {
|
|
1192
|
+
if (!operationFailed) {
|
|
1193
|
+
throw closeError;
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
// In-memory check for duplicate _id values (should never happen)
|
|
1198
|
+
if (result.length > 0) {
|
|
1199
|
+
const idSet = new Set();
|
|
1200
|
+
const duplicateIds = [];
|
|
1201
|
+
for (const doc of result) {
|
|
1202
|
+
const idStr = String(doc._id);
|
|
1203
|
+
if (idSet.has(idStr)) {
|
|
1204
|
+
duplicateIds.push(idStr);
|
|
1205
|
+
}
|
|
1206
|
+
else {
|
|
1207
|
+
idSet.add(idStr);
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
if (duplicateIds.length > 0) {
|
|
1211
|
+
logger.log('error', `Integrity issue in "${this.collectionName}": found ${duplicateIds.length} duplicate _id values ` +
|
|
1212
|
+
`in findAll results: [${duplicateIds.slice(0, 5).join(', ')}]. This should never happen.`);
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
return result;
|
|
1216
|
+
});
|
|
1217
|
+
}
|
|
1218
|
+
/**
|
|
1219
|
+
* Watches the collection, returning a SmartdataDbWatcher with RxJS and EventEmitter support.
|
|
1220
|
+
* @param filterObject match filter for change stream
|
|
1221
|
+
* @param opts optional MongoDB ChangeStreamOptions & { bufferTimeMs } to buffer events
|
|
1222
|
+
* @param smartdataDbDocArg document class for instance creation
|
|
1223
|
+
*/
|
|
1224
|
+
async watch(filterObject, opts = {}, smartdataDbDocArg) {
|
|
1225
|
+
if ('capabilities' in this.smartdataDb &&
|
|
1226
|
+
this.smartdataDb.capabilities.changeStreams === 'unsupported') {
|
|
1227
|
+
throw new LosslessClientError('unsupported_capability', 'Change streams are unsupported by this backend.');
|
|
1228
|
+
}
|
|
1229
|
+
await this.init();
|
|
1230
|
+
// Extract bufferTimeMs from options
|
|
1231
|
+
const { bufferTimeMs, fullDocument, ...otherOptions } = opts || {};
|
|
1232
|
+
// Determine fullDocument behavior: default to 'updateLookup'
|
|
1233
|
+
const changeStreamOptions = {
|
|
1234
|
+
...otherOptions,
|
|
1235
|
+
fullDocument: fullDocument === undefined
|
|
1236
|
+
? 'updateLookup'
|
|
1237
|
+
: fullDocument === true
|
|
1238
|
+
? 'updateLookup'
|
|
1239
|
+
: fullDocument,
|
|
1240
|
+
};
|
|
1241
|
+
// Build pipeline with match if provided
|
|
1242
|
+
const pipeline = filterObject ? [{ $match: filterObject }] : [];
|
|
1243
|
+
const changeStream = this.mongoDbCollection.watch(pipeline, changeStreamOptions);
|
|
1244
|
+
const smartdataWatcher = new SmartdataDbWatcher(changeStream, smartdataDbDocArg, { bufferTimeMs });
|
|
1245
|
+
await smartdataWatcher.readyDeferred.promise;
|
|
1246
|
+
return smartdataWatcher;
|
|
1247
|
+
}
|
|
1248
|
+
/**
|
|
1249
|
+
* create an object in the database
|
|
1250
|
+
*/
|
|
1251
|
+
prepareOrdinaryInsert(documentArg) {
|
|
1252
|
+
const policy = this.modelSchema?.ordinaryPersistence;
|
|
1253
|
+
if (!policy)
|
|
1254
|
+
return documentArg;
|
|
1255
|
+
if (policy.idType === 'objectId' && !Object.prototype.hasOwnProperty.call(documentArg, '_id')) {
|
|
1256
|
+
documentArg = { ...documentArg, _id: new plugins.mongodb.ObjectId() };
|
|
1257
|
+
}
|
|
1258
|
+
return validateOrdinaryStoredDocument(documentArg, policy, this.modelSchema.persistedFields);
|
|
1259
|
+
}
|
|
1260
|
+
async insert(dbDocArg, opts) {
|
|
1261
|
+
const preparedObject = this.modelSchema?.ordinaryPersistence
|
|
1262
|
+
? this.prepareOrdinaryInsert(await dbDocArg.createSavableObject()) : undefined;
|
|
1263
|
+
return this.runWithOrdinarySession(opts?.session, true, async (rawSessionArg) => {
|
|
1264
|
+
await this.init();
|
|
1265
|
+
await this.checkDoc(dbDocArg);
|
|
1266
|
+
await this.markUniqueIndexes(dbDocArg.uniqueIndexes);
|
|
1267
|
+
// Create regular indexes if available
|
|
1268
|
+
if (dbDocArg.regularIndexes && dbDocArg.regularIndexes.length > 0) {
|
|
1269
|
+
await this.createRegularIndexes(dbDocArg.regularIndexes);
|
|
1270
|
+
}
|
|
1271
|
+
const saveableObject = preparedObject ?? await dbDocArg.createSavableObject();
|
|
1272
|
+
try {
|
|
1273
|
+
return await this.mongoDbCollection.insertOne(saveableObject, {
|
|
1274
|
+
session: rawSessionArg,
|
|
1275
|
+
});
|
|
1276
|
+
}
|
|
1277
|
+
catch (err) {
|
|
1278
|
+
return normalizeOrdinaryPersistenceError(err, `Insert conflicts with a unique index in collection "${this.collectionName}".`);
|
|
1279
|
+
}
|
|
1280
|
+
});
|
|
1281
|
+
}
|
|
1282
|
+
/**
|
|
1283
|
+
* Executes a bounded grouped-totals aggregation over already-validated
|
|
1284
|
+
* stages and never exposes the aggregation cursor. Prefer the validated
|
|
1285
|
+
* static `SmartDataDbDoc.getGroupedTotals()`, which owns input validation
|
|
1286
|
+
* before this raw persistence boundary.
|
|
1287
|
+
*/
|
|
1288
|
+
async aggregateGroupedTotals(matchArg, groupArg, limitArg, opts) {
|
|
1289
|
+
opts?.signal?.throwIfAborted();
|
|
1290
|
+
return this.runWithOrdinarySession(opts?.session, false, async (rawSessionArg) => {
|
|
1291
|
+
await this.init();
|
|
1292
|
+
const pipeline = [];
|
|
1293
|
+
if (matchArg && Object.keys(matchArg).length > 0) {
|
|
1294
|
+
pipeline.push({ $match: matchArg });
|
|
1295
|
+
}
|
|
1296
|
+
pipeline.push({ $group: groupArg });
|
|
1297
|
+
pipeline.push({ $limit: limitArg });
|
|
1298
|
+
opts?.signal?.throwIfAborted();
|
|
1299
|
+
const cursor = this.mongoDbCollection.aggregate(pipeline, {
|
|
1300
|
+
session: rawSessionArg,
|
|
1301
|
+
...(opts?.timeoutMS !== undefined ? { timeoutMS: opts.timeoutMS, timeoutMode: 'cursorLifetime' } : {}),
|
|
1302
|
+
signal: opts?.signal,
|
|
1303
|
+
...(opts?.maxTimeMS !== undefined
|
|
1304
|
+
? { maxTimeMS: opts.maxTimeMS }
|
|
1305
|
+
: {}),
|
|
1306
|
+
});
|
|
1307
|
+
return runCursorOperation(cursor, (cursorArg) => cursorArg.toArray(), opts?.signal);
|
|
1308
|
+
});
|
|
1309
|
+
}
|
|
1310
|
+
async insertMany(dbDocsArg, opts) {
|
|
1311
|
+
if (!Array.isArray(dbDocsArg) || dbDocsArg.length === 0) {
|
|
1312
|
+
throw new SmartdataPersistenceError('invalid_argument', `insertMany requires a non-empty document batch for collection "${this.collectionName}".`);
|
|
1313
|
+
}
|
|
1314
|
+
const preparedObjects = this.modelSchema?.ordinaryPersistence ? [] : undefined;
|
|
1315
|
+
if (preparedObjects) {
|
|
1316
|
+
for (const dbDocArg of dbDocsArg) {
|
|
1317
|
+
preparedObjects.push(this.prepareOrdinaryInsert(await dbDocArg.createSavableObject()));
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
return this.runWithOrdinarySession(opts?.session, true, async (rawSessionArg) => {
|
|
1321
|
+
await this.init();
|
|
1322
|
+
for (const dbDocArg of dbDocsArg) {
|
|
1323
|
+
await this.checkDoc(dbDocArg);
|
|
1324
|
+
}
|
|
1325
|
+
const firstDocument = dbDocsArg[0];
|
|
1326
|
+
await this.markUniqueIndexes(firstDocument.uniqueIndexes);
|
|
1327
|
+
if (firstDocument.regularIndexes
|
|
1328
|
+
&& firstDocument.regularIndexes.length > 0) {
|
|
1329
|
+
await this.createRegularIndexes(firstDocument.regularIndexes);
|
|
1330
|
+
}
|
|
1331
|
+
const saveableObjects = preparedObjects ?? [];
|
|
1332
|
+
if (!preparedObjects) {
|
|
1333
|
+
for (const dbDocArg of dbDocsArg) {
|
|
1334
|
+
saveableObjects.push(await dbDocArg.createSavableObject());
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
try {
|
|
1338
|
+
return await this.mongoDbCollection.insertMany(saveableObjects, {
|
|
1339
|
+
session: rawSessionArg,
|
|
1340
|
+
ordered: opts?.ordered !== false,
|
|
1341
|
+
});
|
|
1342
|
+
}
|
|
1343
|
+
catch (err) {
|
|
1344
|
+
return normalizeOrdinaryPersistenceError(err, `Insert conflicts with a unique index in collection "${this.collectionName}".`);
|
|
1345
|
+
}
|
|
1346
|
+
});
|
|
1347
|
+
}
|
|
1348
|
+
/** Model.insertManyIfAbsent owns identity and new-instance validation. */
|
|
1349
|
+
async insertManyIfAbsent(documentsArg, identityFieldArg, optsArg) {
|
|
1350
|
+
const prepared = [];
|
|
1351
|
+
let bytes = 0;
|
|
1352
|
+
// Validate the entire batch before any write, including opted-in whole
|
|
1353
|
+
// stored-document policies and collection-level object validation.
|
|
1354
|
+
for (const document of documentsArg) {
|
|
1355
|
+
await this.checkDoc(document);
|
|
1356
|
+
const stored = this.prepareOrdinaryInsert(await document.createSavableObject());
|
|
1357
|
+
const bson = plugins.mongodb.BSON.serialize(stored);
|
|
1358
|
+
bytes += bson.byteLength;
|
|
1359
|
+
if (bytes > 16 * 1024 * 1024) {
|
|
1360
|
+
throw new SmartdataPersistenceError('invalid_argument', 'insertManyIfAbsent accepts at most 16 MiB of serialized documents.');
|
|
1361
|
+
}
|
|
1362
|
+
prepared.push(plugins.mongodb.BSON.deserialize(bson));
|
|
1363
|
+
}
|
|
1364
|
+
return this.runWithOrdinarySession(optsArg.session, true, async (rawSessionArg) => {
|
|
1365
|
+
await this.init();
|
|
1366
|
+
const first = documentsArg[0];
|
|
1367
|
+
await this.markUniqueIndexes(first.uniqueIndexes);
|
|
1368
|
+
await this.createRegularIndexes(first.regularIndexes || []);
|
|
1369
|
+
try {
|
|
1370
|
+
const result = await this.mongoDbCollection.bulkWrite(prepared.map((document) => ({
|
|
1371
|
+
updateOne: {
|
|
1372
|
+
filter: { [identityFieldArg]: document[identityFieldArg] },
|
|
1373
|
+
update: { $setOnInsert: document },
|
|
1374
|
+
upsert: true,
|
|
1375
|
+
},
|
|
1376
|
+
})), { ordered: false, session: rawSessionArg, timeoutMS: optsArg.timeoutMS });
|
|
1377
|
+
if (result.upsertedCount + result.matchedCount !== prepared.length) {
|
|
1378
|
+
throw new SmartdataPersistenceError('unsupported_operation', 'insertManyIfAbsent requires an acknowledged result for every identity.');
|
|
1379
|
+
}
|
|
1380
|
+
return { insertedCount: result.upsertedCount, matchedCount: result.matchedCount };
|
|
1381
|
+
}
|
|
1382
|
+
catch (errorArg) {
|
|
1383
|
+
return normalizeOrdinaryPersistenceError(errorArg, `Insert conflicts with a unique index in collection "${this.collectionName}".`);
|
|
1384
|
+
}
|
|
1385
|
+
});
|
|
1386
|
+
}
|
|
1387
|
+
/**
|
|
1388
|
+
* inserts object into the DbCollection
|
|
1389
|
+
*/
|
|
1390
|
+
async update(dbDocArg, opts) {
|
|
1391
|
+
if (this.modelSchema?.ordinaryPersistence) {
|
|
1392
|
+
throw new SmartdataPersistenceError('unsupported_operation', 'Validated ordinary models require a transactional postimage update.');
|
|
1393
|
+
}
|
|
1394
|
+
return this.runWithOrdinarySession(opts?.session, true, async (rawSessionArg) => {
|
|
1395
|
+
await this.init();
|
|
1396
|
+
await this.checkDoc(dbDocArg);
|
|
1397
|
+
await this.markUniqueIndexes(dbDocArg.uniqueIndexes);
|
|
1398
|
+
if (dbDocArg.regularIndexes && dbDocArg.regularIndexes.length > 0) {
|
|
1399
|
+
await this.createRegularIndexes(dbDocArg.regularIndexes);
|
|
1400
|
+
}
|
|
1401
|
+
const identifiableObject = await dbDocArg.createIdentifiableObject();
|
|
1402
|
+
this.assertConstrainingIdentifiableObject(identifiableObject, 'update');
|
|
1403
|
+
const saveableObject = await dbDocArg.createSavableObject();
|
|
1404
|
+
const updateableObject = {};
|
|
1405
|
+
for (const key of Object.keys(saveableObject)) {
|
|
1406
|
+
if (identifiableObject[key]) {
|
|
1407
|
+
continue;
|
|
1408
|
+
}
|
|
1409
|
+
updateableObject[key] = saveableObject[key];
|
|
1410
|
+
}
|
|
1411
|
+
try {
|
|
1412
|
+
return await this.mongoDbCollection.updateOne(identifiableObject, { $set: updateableObject }, { upsert: true, session: rawSessionArg });
|
|
1413
|
+
}
|
|
1414
|
+
catch (errorArg) {
|
|
1415
|
+
return normalizeOrdinaryPersistenceError(errorArg, `Update conflicts with a unique index in collection "${this.collectionName}".`);
|
|
1416
|
+
}
|
|
1417
|
+
});
|
|
1418
|
+
}
|
|
1419
|
+
async delete(dbDocArg, opts) {
|
|
1420
|
+
return this.runWithOrdinarySession(opts?.session, true, async (rawSessionArg) => {
|
|
1421
|
+
await this.init();
|
|
1422
|
+
await this.checkDoc(dbDocArg);
|
|
1423
|
+
const identifiableObject = await dbDocArg.createIdentifiableObject();
|
|
1424
|
+
this.assertConstrainingIdentifiableObject(identifiableObject, 'delete');
|
|
1425
|
+
return this.mongoDbCollection.deleteOne(identifiableObject, {
|
|
1426
|
+
session: rawSessionArg,
|
|
1427
|
+
});
|
|
1428
|
+
});
|
|
1429
|
+
}
|
|
1430
|
+
/**
|
|
1431
|
+
* Rejects instance-level document targeting when the model declares no
|
|
1432
|
+
* identity fields. An empty identity filter would otherwise address an
|
|
1433
|
+
* arbitrary document in the collection.
|
|
1434
|
+
*/
|
|
1435
|
+
assertConstrainingIdentifiableObject(identifiableObjectArg, operationLabelArg) {
|
|
1436
|
+
if (Object.keys(identifiableObjectArg).length === 0) {
|
|
1437
|
+
throw new SmartdataPersistenceError('invalid_configuration', `Instance ${operationLabelArg} on collection "${this.collectionName}" requires declared identity fields; without them the operation would target an arbitrary document.`);
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1440
|
+
async getCount(filterObject, opts) {
|
|
1441
|
+
if (opts?.hint !== undefined && (typeof opts.hint !== 'string' ||
|
|
1442
|
+
(opts.hint !== '_id_' && !this.modelSchema?.indexes.some((indexArg) => indexArg.name === opts.hint)))) {
|
|
1443
|
+
throw new SmartdataPersistenceError('invalid_argument', 'Query hint must name an index declared by this model or the built-in _id_ index.');
|
|
1444
|
+
}
|
|
1445
|
+
return this.runWithOrdinarySession(opts?.session, false, async (rawSessionArg) => {
|
|
1446
|
+
await this.init();
|
|
1447
|
+
opts?.signal?.throwIfAborted();
|
|
1448
|
+
const pipeline = [{ $match: filterObject }];
|
|
1449
|
+
if (opts?.limit !== undefined) {
|
|
1450
|
+
pipeline.push({ $limit: opts.limit });
|
|
1451
|
+
}
|
|
1452
|
+
pipeline.push({ $count: 'count' });
|
|
1453
|
+
const cursor = this.mongoDbCollection.aggregate(pipeline, {
|
|
1454
|
+
hint: opts?.hint,
|
|
1455
|
+
maxTimeMS: opts?.maxTimeMS,
|
|
1456
|
+
timeoutMS: opts?.timeoutMS,
|
|
1457
|
+
signal: opts?.signal,
|
|
1458
|
+
session: rawSessionArg,
|
|
1459
|
+
});
|
|
1460
|
+
return runCursorOperation(cursor, async (cursorArg) => (await cursorArg.next())?.count ?? 0, opts?.signal);
|
|
1461
|
+
});
|
|
1462
|
+
}
|
|
1463
|
+
async getIndexInfo() {
|
|
1464
|
+
await this.init();
|
|
1465
|
+
const indexes = await this.mongoDbCollection.listIndexes().toArray();
|
|
1466
|
+
return indexes.map((indexArg) => {
|
|
1467
|
+
let fields;
|
|
1468
|
+
if (indexArg.key._fts === 'text') {
|
|
1469
|
+
const weights = typeof indexArg.weights === 'object' &&
|
|
1470
|
+
indexArg.weights !== null &&
|
|
1471
|
+
!Array.isArray(indexArg.weights)
|
|
1472
|
+
? indexArg.weights
|
|
1473
|
+
: {};
|
|
1474
|
+
fields = Object.keys(weights).map((path) => ({
|
|
1475
|
+
path,
|
|
1476
|
+
direction: 'text',
|
|
1477
|
+
}));
|
|
1478
|
+
}
|
|
1479
|
+
else {
|
|
1480
|
+
fields = Object.entries(indexArg.key).map(([path, direction]) => {
|
|
1481
|
+
if (direction !== 1 && direction !== -1) {
|
|
1482
|
+
throw new SmartdataPersistenceError('unsupported_operation', `Index "${indexArg.name}" uses an unsupported direction.`);
|
|
1483
|
+
}
|
|
1484
|
+
return {
|
|
1485
|
+
path,
|
|
1486
|
+
direction,
|
|
1487
|
+
};
|
|
1488
|
+
});
|
|
1489
|
+
}
|
|
1490
|
+
return {
|
|
1491
|
+
name: indexArg.name,
|
|
1492
|
+
fields,
|
|
1493
|
+
unique: indexArg.unique === true,
|
|
1494
|
+
sparse: indexArg.sparse === true,
|
|
1495
|
+
expireAfterSeconds: typeof indexArg.expireAfterSeconds === 'number'
|
|
1496
|
+
? indexArg.expireAfterSeconds
|
|
1497
|
+
: undefined,
|
|
1498
|
+
};
|
|
1499
|
+
});
|
|
1500
|
+
}
|
|
1501
|
+
/**
|
|
1502
|
+
* Runs an integrity check on the collection.
|
|
1503
|
+
* Compares estimated vs actual document count and checks for duplicates on unique index fields.
|
|
1504
|
+
*/
|
|
1505
|
+
async checkCollectionIntegrity() {
|
|
1506
|
+
await this.init();
|
|
1507
|
+
const result = {
|
|
1508
|
+
ok: true,
|
|
1509
|
+
estimatedCount: 0,
|
|
1510
|
+
actualCount: 0,
|
|
1511
|
+
duplicateFields: [],
|
|
1512
|
+
};
|
|
1513
|
+
try {
|
|
1514
|
+
result.estimatedCount = await this.mongoDbCollection.estimatedDocumentCount();
|
|
1515
|
+
result.actualCount = await this.mongoDbCollection.countDocuments({});
|
|
1516
|
+
if (result.estimatedCount !== result.actualCount) {
|
|
1517
|
+
result.ok = false;
|
|
1518
|
+
logger.log('warn', `Integrity check on "${this.collectionName}": estimatedDocumentCount=${result.estimatedCount} ` +
|
|
1519
|
+
`but countDocuments=${result.actualCount}. Possible data inconsistency.`);
|
|
1520
|
+
}
|
|
1521
|
+
// Check for duplicates on each tracked unique index field
|
|
1522
|
+
for (const field of this.uniqueIndexes) {
|
|
1523
|
+
try {
|
|
1524
|
+
const pipeline = [
|
|
1525
|
+
{ $group: { _id: `$${field}`, count: { $sum: 1 } } },
|
|
1526
|
+
{ $match: { count: { $gt: 1 } } },
|
|
1527
|
+
{ $count: 'total' },
|
|
1528
|
+
];
|
|
1529
|
+
const countResult = await this.mongoDbCollection.aggregate(pipeline).toArray();
|
|
1530
|
+
const dupCount = countResult[0]?.total || 0;
|
|
1531
|
+
if (dupCount > 0) {
|
|
1532
|
+
result.ok = false;
|
|
1533
|
+
result.duplicateFields.push({ field, duplicateValues: dupCount });
|
|
1534
|
+
logger.log('warn', `Integrity check on "${this.collectionName}": field "${field}" has ${dupCount} values with duplicates ` +
|
|
1535
|
+
`despite being marked as unique.`);
|
|
1536
|
+
}
|
|
1537
|
+
}
|
|
1538
|
+
catch (fieldErr) {
|
|
1539
|
+
logger.log('warn', `Integrity check: could not verify uniqueness of "${field}" in "${this.collectionName}": ${fieldErr?.message || String(fieldErr)}`);
|
|
1540
|
+
}
|
|
1541
|
+
}
|
|
1542
|
+
}
|
|
1543
|
+
catch (err) {
|
|
1544
|
+
result.ok = false;
|
|
1545
|
+
logger.log('error', `Integrity check failed for "${this.collectionName}": ${err?.message || String(err)}`);
|
|
1546
|
+
}
|
|
1547
|
+
return result;
|
|
1548
|
+
}
|
|
1549
|
+
/**
|
|
1550
|
+
* checks a Doc for constraints
|
|
1551
|
+
* if this.objectValidation is not set it passes.
|
|
1552
|
+
*/
|
|
1553
|
+
checkDoc(docArg) {
|
|
1554
|
+
const done = plugins.smartpromise.defer();
|
|
1555
|
+
let validationResult = true;
|
|
1556
|
+
if (this.objectValidation) {
|
|
1557
|
+
validationResult = this.objectValidation(docArg);
|
|
1558
|
+
}
|
|
1559
|
+
if (validationResult) {
|
|
1560
|
+
done.resolve();
|
|
1561
|
+
}
|
|
1562
|
+
else {
|
|
1563
|
+
done.reject('validation of object did not pass');
|
|
1564
|
+
}
|
|
1565
|
+
return done.promise;
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5jb2xsZWN0aW9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdHMvbm9zcWxkYi9jbGFzc2VzLmNvbGxlY3Rpb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxjQUFjLENBQUM7QUFDeEMsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDL0QsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFDbEUsT0FBTyxFQUNMLDJCQUEyQixFQUFFLHNCQUFzQixHQUVwRCxNQUFNLG9DQUFvQyxDQUFDO0FBQzVDLE9BQU8sRUFDTCw0QkFBNEIsRUFBRSw4QkFBOEIsR0FFN0QsTUFBTSxrQ0FBa0MsQ0FBQztBQUMxQyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDOUMsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDeEQsT0FBTyxFQUNMLGNBQWMsR0FJZixNQUFNLGtCQUFrQixDQUFDO0FBQzFCLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQzFELE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBQ25FLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFDdEMsT0FBTyxFQUNMLHlCQUF5QixFQUN6QixpQ0FBaUMsR0FDbEMsTUFBTSwwQkFBMEIsQ0FBQztBQUNsQyxPQUFPLEVBQUUseUJBQXlCLEVBQUUsTUFBTSxrQ0FBa0MsQ0FBQztBQUM3RSxPQUFPLEVBQ0wsK0JBQStCLEdBRWhDLE1BQU0sc0JBQXNCLENBQUM7QUFDOUIsT0FBTyxFQUNMLG1DQUFtQyxFQUNuQyxvQ0FBb0MsRUFDcEMsc0NBQXNDLEVBQ3RDLCtCQUErQixHQUNoQyxNQUFNLGlDQUFpQyxDQUFDO0FBZXpDLE1BQU0saUJBQWlCLEdBQUcsSUFBSSxpQkFBaUIsRUFBRSxDQUFDO0FBd0hsRCxNQUFNLGdCQUFnQixHQUFHLElBQUksR0FBRyxDQUFDLENBQUMsV0FBVyxFQUFFLFdBQVcsRUFBRSxhQUFhLENBQUMsQ0FBQyxDQUFDO0FBQzVFLE1BQU0sc0JBQXNCLEdBQUcsc0JBQXNCLENBQUM7QUFFdEQsTUFBTSxvQkFBb0IsR0FBRyxDQUMzQixRQUFnQixFQUNoQixRQUFnQixFQUNoQixZQUFZLEdBQUcsS0FBSyxFQUNaLEVBQUU7SUFDVixJQUNFLE9BQU8sUUFBUSxLQUFLLFFBQVE7UUFDNUIsUUFBUSxDQUFDLE1BQU0sS0FBSyxDQUFDO1FBQ3JCLFFBQVEsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDO1FBQ3ZCLFFBQVEsQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLEVBQ3hCLENBQUM7UUFDRCxNQUFNLElBQUkseUJBQXlCLENBQ2pDLHVCQUF1QixFQUN2QixHQUFHLFFBQVEsdUNBQXVDLENBQ25ELENBQUM7SUFDSixDQUFDO0lBQ0QsTUFBTSxRQUFRLEdBQUcsUUFBUSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUNyQyxJQUNFLENBQUMsQ0FBQyxZQUFZLElBQUksUUFBUSxDQUFDLE1BQU0sS0FBSyxDQUFDLENBQUM7UUFDeEMsUUFBUSxDQUFDLElBQUksQ0FDWCxDQUFDLFVBQVUsRUFBRSxFQUFFLENBQ2IsVUFBVSxDQUFDLE1BQU0sS0FBSyxDQUFDO1lBQ3ZCLFVBQVUsQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDO1lBQzFCLGdCQUFnQixDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsQ0FDbkMsRUFDRCxDQUFDO1FBQ0QsTUFBTSxJQUFJLHlCQUF5QixDQUNqQyx1QkFBdUIsRUFDdkIsR0FBRyxRQUFRLGlDQUFpQyxDQUM3QyxDQUFDO0lBQ0osQ0FBQztJQUNELE9BQU8sUUFBUSxDQUFDO0FBQ2xCLENBQUMsQ0FBQztBQUVGLE1BQU0sdUJBQXVCLEdBQUcsQ0FDOUIsaUJBQXlCLEVBQ3pCLFFBQVEsR0FBRywwQkFBMEIsRUFDN0IsRUFBRTtJQUNWLElBQ0UsT0FBTyxpQkFBaUIsS0FBSyxRQUFRO1FBQ3JDLGlCQUFpQixDQUFDLElBQUksRUFBRSxDQUFDLE1BQU0sS0FBSyxDQUFDO1FBQ3JDLGlCQUFpQixDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUM7UUFDaEMsaUJBQWlCLENBQUMsVUFBVSxDQUFDLFNBQVMsQ0FBQyxFQUN2QyxDQUFDO1FBQ0QsTUFBTSxJQUFJLHlCQUF5QixDQUNqQyx1QkFBdUIsRUFDdkIsR0FBRyxRQUFRLDBEQUEwRCxDQUN0RSxDQUFDO0lBQ0osQ0FBQztJQUNELE9BQU8saUJBQWlCLENBQUM7QUFDM0IsQ0FBQyxDQUFDO0FBRUYsTUFBTSxxQkFBcUIsR0FBRyxDQUM1QixVQUFxQyxFQUNyQyxZQUFvQixFQUNwQix1QkFBdUIsR0FBRyxLQUFLLEVBQ04sRUFBRTtJQUMzQixNQUFNLE9BQU8sR0FBRyxVQUFVLElBQUksRUFBRSxDQUFDO0lBQ2pDLE1BQU0sV0FBVyxHQUFHLElBQUksR0FBRyxDQUFDO1FBQzFCLFlBQVk7UUFDWixRQUFRO1FBQ1IsUUFBUTtRQUNSLG9CQUFvQjtLQUNyQixDQUFDLENBQUM7SUFDSCxJQUFJLENBQUMsdUJBQXVCLEVBQUUsQ0FBQztRQUM3QixLQUFLLE1BQU0sVUFBVSxJQUFJLE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztZQUM5QyxJQUFJLFdBQVcsQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQztnQkFDaEMsU0FBUztZQUNYLENBQUM7WUFDRCxNQUFNLElBQUkseUJBQXlCLENBQ2pDLHVCQUF1QixFQUN2QixVQUFVLFlBQVksaUNBQWlDLFVBQVUsSUFBSSxDQUN0RSxDQUFDO1FBQ0osQ0FBQztJQUNILENBQUM7SUFDRCxLQUFLLE1BQU0sYUFBYSxJQUFJLENBQUMsWUFBWSxFQUFFLFFBQVEsRUFBRSxRQUFRLENBQVUsRUFBRSxDQUFDO1FBQ3hFLElBQ0UsT0FBTyxDQUFDLGFBQWEsQ0FBQyxLQUFLLFNBQVM7WUFDcEMsT0FBTyxPQUFPLENBQUMsYUFBYSxDQUFDLEtBQUssU0FBUyxFQUMzQyxDQUFDO1lBQ0QsTUFBTSxJQUFJLHlCQUF5QixDQUNqQyx1QkFBdUIsRUFDdkIsVUFBVSxZQUFZLGFBQWEsYUFBYSxvQkFBb0IsQ0FDckUsQ0FBQztRQUNKLENBQUM7SUFDSCxDQUFDO0lBQ0QsSUFDRSxPQUFPLENBQUMsa0JBQWtCLEtBQUssU0FBUztRQUN4QyxDQUFDLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsa0JBQWtCLENBQUM7WUFDM0MsT0FBTyxDQUFDLGtCQUFrQixHQUFHLENBQUMsQ0FBQyxFQUNqQyxDQUFDO1FBQ0QsTUFBTSxJQUFJLHlCQUF5QixDQUNqQyx1QkFBdUIsRUFDdkIsVUFBVSxZQUFZLDREQUE0RCxDQUNuRixDQUFDO0lBQ0osQ0FBQztJQUNELE9BQU8sTUFBTSxDQUFDLE1BQU0sQ0FDbEIsdUJBQXVCO1FBQ3JCLENBQUMsQ0FBQyxFQUFFLEdBQUcsT0FBTyxFQUFFO1FBQ2hCLENBQUMsQ0FBQztZQUNFLEdBQUcsQ0FBQyxPQUFPLENBQUMsVUFBVSxLQUFLLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxVQUFVLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztZQUM1RCxHQUFHLENBQUMsT0FBTyxDQUFDLE1BQU0sS0FBSyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7WUFDcEQsR0FBRyxDQUFDLE9BQU8sQ0FBQyxNQUFNLEtBQUssSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO1lBQ3BELEdBQUcsQ0FBQyxPQUFPLENBQUMsa0JBQWtCLEtBQUssU0FBUztnQkFDMUMsQ0FBQyxDQUFDLEVBQUUsa0JBQWtCLEVBQUUsT0FBTyxDQUFDLGtCQUFrQixFQUFFO2dCQUNwRCxDQUFDLENBQUMsRUFBRSxDQUFDO1NBQ1IsQ0FDTixDQUFDO0FBQ0osQ0FBQyxDQUFDO0FBRUYsTUFBTSxXQUFXLEdBQUcsQ0FBQyxRQUFpQixFQUFVLEVBQUU7SUFDaEQsSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUM7UUFDNUIsT0FBTyxJQUFJLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxRQUFRLEVBQUUsRUFBRSxDQUFDLFdBQVcsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDO0lBQzVFLENBQUM7SUFDRCxJQUFJLE9BQU8sUUFBUSxLQUFLLFFBQVEsSUFBSSxRQUFRLEtBQUssSUFBSSxFQUFFLENBQUM7UUFDdEQsT0FBTyxJQUFJLE1BQU0sQ0FBQyxJQUFJLENBQUMsUUFBbUMsQ0FBQzthQUN4RCxJQUFJLENBQUMsK0JBQStCLENBQUM7YUFDckMsR0FBRyxDQUNGLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FDVCxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLElBQUksV0FBVyxDQUNyQyxRQUFvQyxDQUFDLE1BQU0sQ0FBQyxDQUM5QyxFQUFFLENBQ047YUFDQSxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQztJQUNsQixDQUFDO0lBQ0QsT0FBTyxJQUFJLENBQUMsU0FBUyxDQUFDLFFBQVEsQ0FBQyxDQUFDO0FBQ2xDLENBQUMsQ0FBQztBQUVGLE1BQU0sOEJBQThCLEdBQUcsQ0FDckMsU0FBc0MsRUFDdEMsNEJBQTRCLEdBQUcsS0FBSyxFQUNwQyxxQkFFQyxFQUNELGlCQUE4QyxFQUNaLEVBQUU7SUFDcEMsSUFDRSxPQUFPLFNBQVMsS0FBSyxRQUFRO1FBQzdCLFNBQVMsS0FBSyxJQUFJO1FBQ2xCLEtBQUssQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLEVBQ3hCLENBQUM7UUFDRCxNQUFNLElBQUkseUJBQXlCLENBQ2pDLHVCQUF1QixFQUN2Qiw0Q0FBNEMsQ0FDN0MsQ0FBQztJQUNKLENBQUM7SUFDRCxNQUFNLGlCQUFpQixHQUFHLElBQUksR0FBRyxDQUFDO1FBQ2hDLGdCQUFnQjtRQUNoQixpQkFBaUI7UUFDakIsZUFBZTtRQUNmLGdCQUFnQjtRQUNoQixrQkFBa0I7UUFDbEIsU0FBUztLQUNWLENBQUMsQ0FBQztJQUNILEtBQUssTUFBTSxHQUFHLElBQUksTUFBTSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDO1FBQ3pDLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUNoQyxNQUFNLElBQUkseUJBQXlCLENBQ2pDLHVCQUF1QixFQUN2QixvREFBb0QsR0FBRyxJQUFJLENBQzVELENBQUM7UUFDSixDQUFDO0lBQ0gsQ0FBQztJQUNELE1BQU0sY0FBYyxHQUFHLHVCQUF1QixDQUFDLFNBQVMsQ0FBQyxjQUFjLENBQUMsQ0FBQztJQUN6RSxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsZUFBZSxDQUFDLEVBQUUsQ0FBQztRQUM5QyxNQUFNLElBQUkseUJBQXlCLENBQ2pDLHVCQUF1QixFQUN2QixvREFBb0QsQ0FDckQsQ0FBQztJQUNKLENBQUM7SUFDRCxNQUFNLGVBQWUsR0FBYSxFQUFFLENBQUM7SUFDckMsS0FBSyxNQUFNLEtBQUssSUFBSSxTQUFTLENBQUMsZUFBZSxFQUFFLENBQUM7UUFDOUMsb0JBQW9CLENBQUMsS0FBSyxFQUFFLG1CQUFtQixDQUFDLENBQUM7UUFDakQsSUFBSSxDQUFDLGVBQWUsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUNyQyxlQUFlLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQzlCLENBQUM7SUFDSCxDQUFDO0lBQ0QsSUFBSSxpQkFBaUIsRUFBRSxNQUFNLEtBQUssUUFBUSxJQUFJLENBQUMsZUFBZSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO1FBQy9FLGVBQWUsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDOUIsQ0FBQztJQUNELElBQ0UsU0FBUyxDQUFDLGFBQWEsS0FBSyxTQUFTO1FBQ3JDLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsYUFBYSxDQUFDLEVBQ3ZDLENBQUM7UUFDRCxNQUFNLElBQUkseUJBQXlCLENBQ2pDLHVCQUF1QixFQUN2QixrREFBa0QsQ0FDbkQsQ0FBQztJQUNKLENBQUM7SUFDRCxNQUFNLGFBQWEsR0FBYSxFQUFFLENBQUM7SUFDbkMsS0FBSyxNQUFNLEtBQUssSUFBSSxTQUFTLENBQUMsYUFBYSxJQUFJLEVBQUUsRUFBRSxDQUFDO1FBQ2xELG9CQUFvQixDQUFDLEtBQUssRUFBRSxpQkFBaUIsQ0FBQyxDQUFDO1FBQy9DLElBQUksQ0FBQyxlQUFlLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDckMsTUFBTSxJQUFJLHlCQUF5QixDQUNqQyx1QkFBdUIsRUFDdkIsa0JBQWtCLEtBQUssc0NBQXNDLENBQzlELENBQUM7UUFDSixDQUFDO1FBQ0QsSUFBSSxDQUFDLGFBQWEsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUNuQyxhQUFhLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQzVCLENBQUM7SUFDSCxDQUFDO0lBQ0QsSUFDRSxTQUFTLENBQUMsY0FBYyxLQUFLLFNBQVM7UUFDdEMsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxjQUFjLENBQUMsRUFDeEMsQ0FBQztRQUNELE1BQU0sSUFBSSx5QkFBeUIsQ0FDakMsdUJBQXVCLEVBQ3ZCLG1EQUFtRCxDQUNwRCxDQUFDO0lBQ0osQ0FBQztJQUNELE1BQU0sY0FBYyxHQUFhLEVBQUUsQ0FBQztJQUNwQyxLQUFLLE1BQU0sS0FBSyxJQUFJLFNBQVMsQ0FBQyxjQUFjLElBQUksRUFBRSxFQUFFLENBQUM7UUFDbkQsb0JBQW9CLENBQUMsS0FBSyxFQUFFLG1CQUFtQixDQUFDLENBQUM7UUFDakQsSUFBSSxDQUFDLGVBQWUsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUNyQyxNQUFNLElBQUkseUJBQXlCLENBQ2pDLHVCQUF1QixFQUN2QixtQkFBbUIsS0FBSyxzQ0FBc0MsQ0FDL0QsQ0FBQztRQUNKLENBQUM7UUFDRCxJQUFJLENBQUMsY0FBYyxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQ3BDLGNBQWMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDN0IsQ0FBQztJQUNILENBQUM7SUFDRCxNQUFNLGtCQUFrQixHQUFnRCxFQUFFLENBQUM7SUFDM0UsS0FBSyxNQUFNLEtBQUssSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLHFCQUFxQixJQUFJLEVBQUUsQ0FBQyxFQUFFLENBQUM7UUFDN0QsSUFBSSxDQUFDLGNBQWMsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUNwQyxNQUFNLElBQUkseUJBQXlCLENBQ2pDLHVCQUF1QixFQUN2Qiw2QkFBNkIsS0FBSyxxQ0FBcUMsQ0FDeEUsQ0FBQztRQUNKLENBQUM7SUFDSCxDQUFDO0lBQ0QsS0FBSyxNQUFNLEtBQUssSUFBSSxjQUFjLEVBQUUsQ0FBQztRQUNuQyxNQUFNLFNBQVMsR0FBRyxxQkFBcUIsRUFBRSxDQUFDLEtBQUssQ0FBQyxJQUFJLFFBQVEsQ0FBQztRQUM3RCxJQUFJLFNBQVMsS0FBSyxRQUFRLElBQUksU0FBUyxLQUFLLHFCQUFxQixFQUFFLENBQUM7WUFDbEUsTUFBTSxJQUFJLHlCQUF5QixDQUNqQyx1QkFBdUIsRUFDdkIsbUJBQW1CLEtBQUssaUNBQWlDLENBQzFELENBQUM7UUFDSixDQUFDO1FBQ0Qsa0JBQWtCLENBQUMsS0FBSyxDQUFDLEdBQUcsU0FBUyxDQUFDO1FBQ3RDLElBQUksU0FBUyxLQUFLLHFCQUFxQixJQUFJLENBQUMsYUFBYSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQzFFLGFBQWEsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDNUIsQ0FBQztJQUNILENBQUM7SUFDRCxNQUFNLGdCQUFnQixHQUFhLEVBQUUsQ0FBQztJQUN0QyxJQUNFLFNBQVMsQ0FBQyxnQkFBZ0IsS0FBSyxTQUFTO1FBQ3hDLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsZ0JBQWdCLENBQUMsRUFDMUMsQ0FBQztRQUNELE1BQU0sSUFBSSx5QkFBeUIsQ0FDakMsdUJBQXVCLEVBQ3ZCLHFEQUFxRCxDQUN0RCxDQUFDO0lBQ0osQ0FBQztJQUNELEtBQUssTUFBTSxLQUFLLElBQUksU0FBUyxDQUFDLGdCQUFnQixJQUFJLEVBQUUsRUFBRSxDQUFDO1FBQ3JELG9CQUFvQixDQUFDLEtBQUssRUFBRSxvQkFBb0IsQ0FBQyxDQUFDO1FBQ2xELElBQUksQ0FBQyxlQUFlLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDckMsTUFBTSxJQUFJLHlCQUF5QixDQUNqQyx1QkFBdUIsRUFDdkIscUJBQXFCLEtBQUssc0NBQXNDLENBQ2pFLENBQUM7UUFDSixDQUFDO1FBQ0QsSUFBSSxDQUFDLGdCQUFnQixDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQ3RDLGdCQUFnQixDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUMvQixDQUFDO0lBQ0gsQ0FBQztJQUNELElBQUksU0FBUyxDQUFDLE9BQU8sS0FBSyxTQUFTLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDO1FBQ3pFLE1BQU0sSUFBSSx5QkFBeUIsQ0FDakMsdUJBQXVCLEVBQ3ZCLDRDQUE0QyxDQUM3QyxDQUFDO0lBQ0osQ0FBQztJQUNELE1BQU0sYUFBYSxHQUFHLElBQUksR0FBRyxFQUcxQixDQUFDO0lBQ0osS0FBSyxNQUFNLEtBQUssSUFBSSxTQUFTLENBQUMsT0FBTyxJQUFJLEVBQUUsRUFBRSxDQUFDO1FBQzVDLElBQ0UsT0FBTyxLQUFLLEtBQUssUUFBUTtZQUN6QixLQUFLLEtBQUssSUFBSTtZQUNkLEtBQUssQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDO1lBQ3BCLE9BQU8sS0FBSyxDQUFDLElBQUksS0FBSyxRQUFRO1lBQzlCLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUMsTUFBTSxLQUFLLENBQUM7WUFDOUIsS0FBSyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLEVBQ3pCLENBQUM7WUFDRCxNQUFNLElBQUkseUJBQXlCLENBQ2pDLHVCQUF1QixFQUN2Qiw4REFBOEQsQ0FDL0QsQ0FBQztRQUNKLENBQUM7UUFDRCxJQUFJLEtBQUssQ0FBQyxJQUFJLEtBQUssc0JBQXNCLEVBQUUsQ0FBQztZQUMxQyxNQUFNLElBQUkseUJBQXlCLENBQ2pDLHVCQUF1QixFQUN2QixlQUFlLHNCQUFzQixxREFBcUQsQ0FDM0YsQ0FBQztRQUNKLENBQUM7UUFDRCxNQUFNLFNBQVMsR0FBRyxNQUFNLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxHQUFHLElBQUksRUFBRSxDQUFDLENBQUM7UUFDbEQsSUFBSSxTQUFTLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQzNCLE1BQU0sSUFBSSx5QkFBeUIsQ0FDakMsdUJBQXVCLEVBQ3ZCLFVBQVUsS0FBSyxDQUFDLElBQUksOEJBQThCLENBQ25ELENBQUM7UUFDSixDQUFDO1FBQ0QsTUFBTSxjQUFjLEdBQUcsU0FBUyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsS0FBSyxFQUFFLFNBQVMsQ0FBQyxFQUFFLEVBQUU7WUFDMUQsb0JBQW9CLENBQUMsS0FBSyxFQUFFLFVBQVUsS0FBSyxDQUFDLElBQUksU0FBUyxFQUFFLElBQUksQ0FBQyxDQUFDO1lBQ2pFLE1BQU0sSUFBSSxHQUFHLEtBQUssQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDakMsSUFDRSxDQUFDLGVBQWUsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDO2dCQUMvQixJQUFJLEtBQUssWUFBWTtnQkFDckIsSUFBSSxLQUFLLFlBQVksRUFDckIsQ0FBQztnQkFDRCxNQUFNLElBQUkseUJBQXlCLENBQ2pDLHVCQUF1QixFQUN2QixVQUFVLEtBQUssQ0FBQyxJQUFJLGtDQUFrQyxLQUFLLElBQUksQ0FDaEUsQ0FBQztZQUNKLENBQUM7WUFDRCxJQUFJLFNBQVMsS0FBSyxDQUFDLElBQUksU0FBUyxLQUFLLENBQUMsQ0FBQyxJQUFJLFNBQVMsS0FBSyxNQUFNLEVBQUUsQ0FBQztnQkFDaEUsTUFBTSxJQUFJLHlCQUF5QixDQUNqQyx1QkFBdUIsRUFDdkIsVUFBVSxLQUFLLENBQUMsSUFBSSxtQ0FBbUMsS0FBSyxJQUFJLENBQ2pFLENBQUM7WUFDSixDQUFDO1lBQ0QsT0FBTyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUMsS0FBSyxFQUFFLFNBQVMsQ0FBVSxDQUFDLENBQUM7UUFDcEQsQ0FBQyxDQUFDLENBQUM7UUFDSCxNQUFNLGVBQWUsR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDO1lBQ3BDLElBQUksRUFBRSxLQUFLLENBQUMsSUFBSTtZQUNoQixHQUFHLEVBQUUsTUFBTSxDQUFDLE1BQU0sQ0FBQyxjQUFjLENBQUM7WUFDbEMsT0FBTyxFQUFFLHFCQUFxQixDQUM1QixLQUFLLENBQUMsT0FBTyxFQUNiLEtBQUssQ0FBQyxJQUFJLEVBQ1YsNEJBQTRCLENBQzdCO1NBQ0YsQ0FBQyxDQUFDO1FBQ0gsTUFBTSxRQUFRLEdBQUcsYUFBYSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDL0MsSUFBSSxRQUFRLElBQUksV0FBVyxDQUFDLFFBQVEsQ0FBQyxLQUFLLFdBQVcsQ0FBQyxlQUFlLENBQUMsRUFBRSxDQUFDO1lBQ3ZFLE1BQU0sSUFBSSx5QkFBeUIsQ0FDakMsdUJBQXVCLEVBQ3ZCLFVBQVUsS0FBSyxDQUFDLElBQUksK0JBQStCLENBQ3BELENBQUM7UUFDSixDQUFDO1FBQ0QsYUFBYSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFLFFBQVEsSUFBSSxlQUFlLENBQUMsQ0FBQztJQUM3RCxDQUFDO0lBQ0QsTUFBTSxXQUFXLEdBQUcsQ0FBQyxHQUFHLGFBQWEsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLFFBQVEsRUFBRSxFQUFFLENBQ2xFLFFBQVEsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLFlBQVksQ0FBQyxFQUFFLEVBQUUsQ0FBQyxZQUFZLEtBQUssTUFBTSxDQUFDLENBQ2pFLENBQUM7SUFDRixJQUFJLFdBQVcsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7UUFDM0IsTUFBTSxJQUFJLHlCQUF5QixDQUNqQyx1QkFBdUIsRUFDdkIsd0RBQXdELENBQ3pELENBQUM7SUFDSixDQUFDO0lBQ0QsSUFBSSxXQUFXLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO1FBQzdCLE1BQU0saUJBQWlCLEdBQUcsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUc7YUFDekMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLFlBQVksQ0FBQyxFQUFFLEVBQUUsQ0FBQyxZQUFZLEtBQUssTUFBTSxDQUFDO2FBQ3JELEdBQUcsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLEVBQUUsRUFBRSxDQUFDLFFBQVEsQ0FBQzthQUM3QixJQUFJLENBQUMsK0JBQStCLENBQUMsQ0FBQztRQUN6QyxNQUFNLDBCQUEwQixHQUFHLENBQUMsR0FBRyxnQkFBZ0IsQ0FBQyxDQUFDLElBQUksQ0FDM0QsK0JBQStCLENBQ2hDLENBQUM7UUFDRixJQUNFLFdBQVcsQ0FBQyxpQkFBaUIsQ0FBQztZQUM5QixXQUFXLENBQUMsMEJBQTBCLENBQUMsRUFDdkMsQ0FBQztZQUNELE1BQU0sSUFBSSx5QkFBeUIsQ0FDakMsdUJBQXVCLEVBQ3ZCLGVBQWUsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksc0RBQXNELENBQ3pGLENBQUM7UUFDSixDQUFDO0lBQ0gsQ0FBQztJQUNELElBQUksZ0JBQWdCLENBQUMsTUFBTSxHQUFHLENBQUMsSUFBSSxXQUFXLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO1FBQzVELGFBQWEsQ0FBQyxHQUFHLENBQ2Ysc0JBQXNCLEVBQ3RCLE1BQU0sQ0FBQyxNQUFNLENBQUM7WUFDWixJQUFJLEVBQUUsc0JBQXNCO1lBQzVCLEdBQUcsRUFBRSxNQUFNLENBQUMsTUFBTSxDQUNoQixnQkFBZ0IsQ0FBQyxHQUFHLENBQUMsQ0FBQyxRQUFRLEVBQUUsRUFBRSxDQUNoQyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUMsUUFBUSxFQUFFLE1BQU0sQ0FBVSxDQUFDLENBQzNDLENBQ0Y7WUFDRCxPQUFPLEVBQUUsTUFBTSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUM7U0FDM0IsQ0FBQyxDQUNILENBQUM7SUFDSixDQUFDO0lBQ0QsS0FBSyxNQUFNLGFBQWEsSUFBSSxjQUFjLEVBQUUsQ0FBQztRQUMzQyxNQUFNLGdCQUFnQixHQUFHLENBQUMsR0FBRyxhQUFhLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQ3ZELENBQUMsUUFBUSxFQUFFLEVBQUUsQ0FDWCxRQUFRLENBQUMsT0FBTyxDQUFDLE1BQU0sS0FBSyxJQUFJO1lBQ2hDLFFBQVEsQ0FBQyxHQUFHLENBQUMsTUFBTSxLQUFLLENBQUM7WUFDekIsUUFBUSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxhQUFhO1lBQ3BDLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUMzQixDQUFDO1FBQ0YsSUFBSSxDQUFDLGdCQUFnQixFQUFFLENBQUM7WUFDdEIsTUFBTSxJQUFJLHlCQUF5QixDQUNqQyx1QkFBdUIsRUFDdkIsbUJBQW1CLGFBQWEsNkRBQTZELENBQzlGLENBQUM7UUFDSixDQUFDO0lBQ0gsQ0FBQztJQUNELE1BQU0sY0FBYyxHQUFHO1FBQ3JCLG1CQUFtQixFQUFFLGlCQUFpQjtRQUN0QyxjQUFjO1FBQ2QsZUFBZSxFQUFFLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxHQUFHLGVBQWUsQ0FBQyxDQUFDO1FBQ3BELGFBQWEsRUFBRSxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUMsR0FBRyxhQUFhLENBQUMsQ0FBQztRQUNoRCxjQUFjLEVBQUUsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLEdBQUcsY0FBYyxDQUFDLENBQUM7UUFDbEQsa0JBQWtCLEVBQUUsTUFBTSxDQUFDLE1BQU0sQ0FBQyxFQUFFLEdBQUcsa0JBQWtCLEVBQUUsQ0FBQztRQUM1RCxnQkFBZ0IsRUFBRSxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUMsR0FBRyxnQkFBZ0IsQ0FBQyxDQUFDO1FBQ3RELE9BQU8sRUFBRSxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUMsR0FBRyxhQUFhLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQztLQUNwRCxDQUFDO0lBQ0YsT0FBTyxNQUFNLENBQUMsTUFBTSxDQUFDO1FBQ25CLEdBQUcsY0FBYztRQUNqQixXQUFXLEVBQUUsV0FBVyxDQUFDO1lBQ3ZCLG1CQUFtQixFQUFFLGlCQUFpQixDQUFDLENBQUMsQ0FBQztnQkFDdkMsTUFBTSxFQUFFLGlCQUFpQixDQUFDLE1BQU0sRUFBRSxVQUFVLEVBQUUsaUJBQWlCLENBQUMsVUFBVTthQUMzRSxDQUFDLENBQUMsQ0FBQyxTQUFTO1lBQ2IsY0FBYztZQUNkLGVBQWUsRUFBRSxDQUFDLEdBQUcsZUFBZSxDQUFDLENBQUMsSUFBSSxDQUFDLCtCQUErQixDQUFDO1lBQzNFLGFBQWEsRUFBRSxDQUFDLEdBQUcsYUFBYSxDQUFDLENBQUMsSUFBSSxDQUFDLCtCQUErQixDQUFDO1lBQ3ZFLGNBQWMsRUFBRSxDQUFDLEdBQUcsY0FBYyxDQUFDLENBQUMsSUFBSSxDQUFDLCtCQUErQixDQUFDO1lBQ3pFLGtCQUFrQjtZQUNsQixnQkFBZ0IsRUFBRSxDQUFDLEdBQUcsZ0JBQWdCLENBQUMsQ0FBQyxJQUFJLENBQzFDLCtCQUErQixDQUNoQztZQUNELE9BQU8sRUFBRSxDQUFDLEdBQUcsYUFBYSxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsT0FBTyxFQUFFLFFBQVEsRUFBRSxFQUFFLENBQzlELCtCQUErQixDQUFDLE9BQU8sQ0FBQyxJQUFJLEVBQUUsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUM3RDtTQUNGLENBQUM7S0FDSCxDQUFDLENBQUM7QUFDTCxDQUFDLENBQUM7QUFFRixNQUFNLG1CQUFtQixHQUFHLENBQUksUUFBYSxFQUFFLEdBQXNDLEVBQWlCLEVBQUU7SUFDdEcsSUFBSSxDQUFDLFFBQVEsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsR0FBRyxDQUFDLEVBQUUsQ0FBQztRQUN0RSxPQUFPLFNBQVMsQ0FBQztJQUNuQixDQUFDO0lBQ0QsT0FBTyxRQUFRLENBQUMsR0FBRyxDQUFNLENBQUM7QUFDNUIsQ0FBQyxDQUFDO0FBRUYsTUFBTSxpQkFBaUIsR0FBRyxDQUFDLEdBQUcsTUFBbUMsRUFBWSxFQUFFO0lBQzdFLE1BQU0sTUFBTSxHQUFhLEVBQUUsQ0FBQztJQUM1QixLQUFLLE1BQU0sS0FBSyxJQUFJLE1BQU0sRUFBRSxDQUFDO1FBQzNCLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztZQUNYLFNBQVM7UUFDWCxDQUFDO1FBQ0QsS0FBSyxNQUFNLElBQUksSUFBSSxLQUFLLEVBQUUsQ0FBQztZQUN6QixJQUFJLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO2dCQUMzQixNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQ3BCLENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQztJQUNELE9BQU8sTUFBTSxDQUFDO0FBQ2hCLENBQUMsQ0FBQztBQUVGLE1BQU0sdUJBQXVCLEdBQUcsQ0FDOUIsR0FBRyxXQUVGLEVBQzRDLEVBQUU7SUFDL0MsTUFBTSxNQUFNLEdBQWdELEVBQUUsQ0FBQztJQUMvRCxLQUFLLE1BQU0sT0FBTyxJQUFJLFdBQVcsRUFBRSxDQUFDO1FBQ2xDLEtBQUssTUFBTSxDQUFDLEtBQUssRUFBRSxTQUFTLENBQUMsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFDLE9BQU8sSUFBSSxFQUFFLENBQUMsRUFBRSxDQUFDO1lBQy9ELE1BQU0sUUFBUSxHQUFHLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUMvQixJQUFJLFFBQVEsSUFBSSxRQUFRLEtBQUssU0FBUyxFQUFFLENBQUM7Z0JBQ3ZDLE1BQU0sSUFBSSx5QkFBeUIsQ0FDakMsdUJBQXVCLEVBQ3ZCLG1CQUFtQixLQUFLLG1EQUFtRCxDQUM1RSxDQUFDO1lBQ0osQ0FBQztZQUNELE1BQU0sQ0FBQyxLQUFLLENBQUMsR0FBRyxTQUFTLENBQUM7UUFDNUIsQ0FBQztJQUNILENBQUM7SUFDRCxPQUFPLE1BQU0sQ0FBQztBQUNoQixDQUFDLENBQUM7QUFFRixNQUFNLG1CQUFtQixHQUFHLENBQzFCLEdBQUcsV0FBOEUsRUFDakMsRUFBRTtJQUNsRCxNQUFNLFNBQVMsR0FBRyxJQUFJLEdBQUcsRUFBbUQsQ0FBQztJQUM3RSxLQUFLLE1BQU0sVUFBVSxJQUFJLFdBQVcsRUFBRSxDQUFDO1FBQ3JDLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQztZQUNoQixTQUFTO1FBQ1gsQ0FBQztRQUNELEtBQUssTUFBTSxRQUFRLElBQUksVUFBVSxFQUFFLENBQUM7WUFDbEMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUMsS0FBSyxFQUFFO2dCQUM1QixLQUFLLEVBQUUsUUFBUSxDQUFDLEtBQUs7Z0JBQ3JCLE9BQU8sRUFBRSxFQUFFLEdBQUcsUUFBUSxDQUFDLE9BQU8sRUFBRTthQUNqQyxDQUFDLENBQUM7UUFDTCxDQUFDO0lBQ0gsQ0FBQztJQUNELE9BQU8sQ0FBQyxHQUFHLFNBQVMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDO0FBQ2pDLENBQUMsQ0FBQztBQUVGLE1BQU0sZ0JBQWdCLEdBQUcsQ0FBQyxRQUFpQixFQUFVLEVBQUU7SUFDckQsSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUM7UUFDNUIsT0FBTyxJQUFJLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxRQUFRLEVBQUUsRUFBRSxDQUFDLGdCQUFnQixDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUM7SUFDakYsQ0FBQztJQUNELElBQUksT0FBTyxRQUFRLEtBQUssUUFBUSxJQUFJLFFBQVEsS0FBSyxJQUFJLEVBQUUsQ0FBQztRQUN0RCxPQUFPLElBQUksTUFBTSxDQUFDLElBQUksQ0FBQyxRQUFtQyxDQUFDO2FBQ3hELElBQUksQ0FBQywrQkFBK0IsQ0FBQzthQUNyQyxHQUFHLENBQ0YsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUNULEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsSUFBSSxnQkFBZ0IsQ0FDMUMsUUFBb0MsQ0FBQyxNQUFNLENBQUMsQ0FDOUMsRUFBRSxDQUNOO2FBQ0EsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUM7SUFDbEIsQ0FBQztJQUNELE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQyxRQUFRLENBQUMsQ0FBQztBQUNsQyxDQUFDLENBQUM7QUFFRixNQUFNLG9CQUFvQixHQUFHLENBQzNCLE9BQThCLEVBQzlCLFFBQStCLEVBQ3RCLEVBQUU7SUFDWCxNQUFNLGNBQWMsR0FBRyxNQUFNLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUNuRCxNQUFNLGVBQWUsR0FBRyxNQUFNLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUNyRCxPQUFPLENBQ0wsZ0JBQWdCLENBQUMsY0FBYyxDQUFDLEtBQUssZ0JBQWdCLENBQUMsZUFBZSxDQUFDO1FBQ3RFLGdCQUFnQixDQUFDLE9BQU8sQ0FBQyxPQUFPLElBQUksRUFBRSxDQUFDO1lBQ3JDLGdCQUFnQixDQUFDLFFBQVEsQ0FBQyxPQUFPLElBQUksRUFBRSxDQUFDLENBQzNDLENBQUM7QUFDSixDQUFDLENBQUM7QUFFRixNQUFNLG9CQUFvQixHQUFHLENBQzNCLEdBQUcsV0FBNkMsRUFDakMsRUFBRTtJQUNqQixNQUFNLFNBQVMsR0FBRyxJQUFJLEdBQUcsRUFBdUIsQ0FBQztJQUNqRCxLQUFLLE1BQU0sVUFBVSxJQUFJLFdBQVcsRUFBRSxDQUFDO1FBQ3JDLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQztZQUNoQixTQUFTO1FBQ1gsQ0FBQztRQUNELEtBQUssTUFBTSxlQUFlLElBQUksVUFBVSxFQUFFLENBQUM7WUFDekMsTUFBTSxRQUFRLEdBQUcsU0FBUyxDQUFDLEdBQUcsQ0FBQyxlQUFlLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDckQsSUFBSSxRQUFRLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxRQUFRLEVBQUUsZUFBZSxDQUFDLEVBQUUsQ0FBQztnQkFDakUsTUFBTSxJQUFJLHlCQUF5QixDQUNqQyx1QkFBdUIsRUFDdkIsbUJBQW1CLGVBQWUsQ0FBQyxJQUFJLHlDQUF5QyxDQUNqRixDQUFDO1lBQ0osQ0FBQztZQUNELElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztnQkFDZCxTQUFTLENBQUMsR0FBRyxDQUFDLGVBQWUsQ0FBQyxJQUFJLEVBQUU7b0JBQ2xDLEdBQUcsZUFBZTtvQkFDbEIsSUFBSSxFQUFFLGVBQWUsQ0FBQyxJQUFJO29CQUMxQixHQUFHLEVBQUUsRUFBRSxHQUFHLGVBQWUsQ0FBQyxHQUFHLEVBQUU7b0JBQy9CLE9BQU8sRUFBRSxFQUFFLEdBQUcsQ0FBQyxlQUFlLENBQUMsT0FBTyxJQUFJLEVBQUUsQ0FBQyxFQUFFO2lCQUNoRCxDQUFDLENBQUM7WUFDTCxDQUFDO1FBQ0gsQ0FBQztJQUNILENBQUM7SUFDRCxPQUFPLENBQUMsR0FBRyxTQUFTLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQztBQUNqQyxDQUFDLENBQUM7QUFFRixNQUFNLHNCQUFzQixHQUFHLENBQzdCLEdBQUcsWUFBNEQsRUFDbEMsRUFBRTtJQUMvQixNQUFNLE1BQU0sR0FBZ0MsRUFBRSxDQUFDO0lBRS9DLE1BQU0sQ0FBQyx3QkFBd0IsR0FBRyxpQkFBaUIsQ0FDakQsR0FBRyxZQUFZLENBQUMsR0FBRyxDQUFDLENBQUMsV0FBVyxFQUFFLEVBQUUsQ0FBQyxtQkFBbUIsQ0FBVyxXQUFXLEVBQUUsMEJBQTBCLENBQUMsQ0FBQyxDQUM3RyxDQUFDO0lBQ0YsTUFBTSxDQUFDLGtCQUFrQixHQUFHLGlCQUFpQixDQUMzQyxHQUFHLFlBQVksQ0FBQyxHQUFHLENBQUMsQ0FBQyxXQUFXLEVBQUUsRUFBRSxDQUFDLG1CQUFtQixDQUFXLFdBQVcsRUFBRSxvQkFBb0IsQ0FBQyxDQUFDLENBQ3ZHLENBQUM7SUFDRixNQUFNLENBQUMsYUFBYSxHQUFHLGlCQUFpQixDQUN0QyxHQUFHLFlBQVksQ0FBQyxHQUFHLENBQUMsQ0FBQyxXQUFXLEVBQUUsRUFBRSxDQUFDLG1CQUFtQixDQUFXLFdBQVcsRUFBRSxlQUFlLENBQUMsQ0FBQyxDQUNsRyxDQUFDO0lBQ0YsTUFBTSxDQUFDLGtCQUFrQixHQUFHLHVCQUF1QixDQUNqRCxHQUFHLFlBQVksQ0FBQyxHQUFHLENBQUMsQ0FBQyxXQUFXLEVBQUUsRUFBRSxDQUNsQyxtQkFBbUIsQ0FDakIsV0FBVyxFQUNYLG9CQUFvQixDQUNyQixDQUNGLENBQ0YsQ0FBQztJQUNGLE1BQU0sQ0FBQyxnQkFBZ0IsR0FBRyxpQkFBaUIsQ0FDekMsR0FBRyxZQUFZLENBQUMsR0FBRyxDQUFDLENBQUMsV0FBVyxFQUFFLEVBQUUsQ0FBQyxtQkFBbUIsQ0FBVyxXQUFXLEVBQUUsa0JBQWtCLENBQUMsQ0FBQyxDQUNyRyxDQUFDO0lBQ0YsTUFBTSxDQUFDLGNBQWMsR0FBRyxtQkFBbUIsQ0FDekMsR0FBRyxZQUFZLENBQUMsR0FBRyxDQUFDLENBQUMsV0FBVyxFQUFFLEVBQUUsQ0FBQyxtQkFBbUIsQ0FBaUQsV0FBVyxFQUFFLGdCQUFnQixDQUFDLENBQUMsQ0FDekksQ0FBQztJQUNGLE1BQU0sQ0FBQyxlQUFlLEdBQUcsb0JBQW9CLENBQzNDLEdBQUcsWUFBWSxDQUFDLEdBQUcsQ0FBQyxDQUFDLFdBQVcsRUFBRSxFQUFFLENBQ2xDLG1CQUFtQixDQUNqQixXQUFXLEVBQ1gsaUJBQWlCLENBQ2xCLENBQ0YsQ0FDRixDQUFDO0lBQ0YsTUFBTSxDQUFDLFlBQVksR0FBRyxvQkFBb0IsQ0FDeEMsR0FBRyxZQUFZLENBQUMsR0FBRyxDQUFDLENBQUMsV0FBVyxFQUFFLEVBQUUsQ0FDbEMsbUJBQW1CLENBQTBCLFdBQVcsRUFBRSxjQUFjLENBQUMsQ0FBQyxDQUM3RSxDQUFDO0lBRUYsTUFBTSxXQUFXLEdBQXdCLEVBQUUsQ0FBQztJQUM1QyxLQUFLLE1BQU0sV0FBVyxJQUFJLFlBQVksRUFBRSxDQUFDO1FBQ3ZDLE1BQU0sT0FBTyxHQUFHLG1CQUFtQixDQUFzQixXQUFXLEVBQUUsY0FBYyxDQUFDLENBQUM7UUFDdEYsSUFBSSxPQUFPLEVBQUUsQ0FBQztZQUNaLE1BQU0sQ0FBQyxNQUFNLENBQUMsV0FBVyxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQ3RDLENBQUM7SUFDSCxDQUFDO0lBQ0QsSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztRQUN4QyxNQUFNLENBQUMsWUFBWSxHQUFHLFdBQVcsQ0FBQztJQUNwQyxDQUFDO0lBRUQsT0FBTyxNQUFNLENBQUM7QUFDaEIsQ0FBQyxDQUFDO0FBRUYsTUFBTSxpQ0FBaUMsR0FBRyxDQUN4QyxXQUEwRCxFQUM3QixFQUFFO0lBQy9CLE1BQU0sYUFBYSxHQUFrQyxFQUFFLENBQUM7SUFDeEQsSUFBSSxLQUFLLEdBQUcsTUFBTSxDQUFDLGNBQWMsQ0FBQyxXQUFXLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDekQsT0FBTyxLQUFLLElBQUksS0FBSyxLQUFLLE1BQU0sQ0FBQyxTQUFTLEVBQUUsQ0FBQztRQUMzQyxNQUFNLFFBQVEsR0FBRyxLQUFLLENBQUMsV0FBVyxFQUFFLENBQUUsTUFBYyxDQUFDLFFBQVEsQ0FFaEQsQ0FBQztRQUNkLElBQUksUUFBUSxFQUFFLENBQUM7WUFDYixhQUFhLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQ2xDLENBQUM7UUFDRCxLQUFLLEdBQUcsTUFBTSxDQUFDLGNBQWMsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUN2QyxDQUFDO0lBQ0QsT0FBTyxzQkFBc0IsQ0FBQyxHQUFHLGFBQWEsQ0FBQyxDQUFDO0FBQ2xELENBQUMsQ0FBQztBQUVGOzs7R0FHRztBQUNILFNBQVMsMkJBQTJCLENBQ2xDLFdBQTBELEVBQzFELFFBQWE7SUFFYixNQUFNLGNBQWMsR0FBRyxzQkFBc0IsQ0FDM0MsaUNBQWlDLENBQUMsV0FBVyxDQUFDLEVBQzlDLFFBQW1ELENBQ3BELENBQUM7SUFFRixNQUFNLEtBQUssR0FBRyxXQUFXLENBQUMsU0FBUyxDQUFDO0lBQ3BDLE1BQU0sSUFBSSxHQUFHLFdBQWtCLENBQUM7SUFFaEMsd0NBQXdDO0lBQ3hDLElBQUksY0FBYyxDQUFDLHdCQUF3QixFQUFFLE1BQU0sRUFBRSxDQUFDO1FBQ3BELEtBQUssQ0FBQyx3QkFBd0IsR0FBRyxDQUFDLEdBQUcsY0FBYyxDQUFDLHdCQUF3QixDQUFDLENBQUM7SUFDaEYsQ0FBQztJQUNELElBQUksY0FBYyxDQUFDLGtCQUFrQixFQUFFLE1BQU0sRUFBRSxDQUFDO1FBQzlDLEtBQUssQ0FBQyxrQkFBa0IsR0FBRyxDQUFDLEdBQUcsY0FBYyxDQUFDLGtCQUFrQixDQUFDLENBQUM7SUFDcEUsQ0FBQztJQUNELElBQUksY0FBYyxDQUFDLGFBQWEsRUFBRSxNQUFNLEVBQUUsQ0FBQztRQUN6QyxLQUFLLENBQUMsYUFBYSxHQUFHLENBQUMsR0FBRyxjQUFjLENBQUMsYUFBYSxDQUFDLENBQUM7SUFDMUQsQ0FBQztJQUNELElBQUksY0FBYyxDQUFDLGtCQUFrQixFQUFFLENBQUM7UUFDdEMsS0FBSyxDQUFDLGtCQUFrQixHQUFHLEVBQUUsR0FBRyxjQUFjLENBQUMsa0JBQWtCLEVBQUUsQ0FBQztJQUN0RSxDQUFDO0lBQ0QsSUFBSSxjQUFjLENBQUMsY0FBYyxFQUFFLE1BQU0sRUFBRSxDQUFDO1FBQzFDLEtBQUssQ0FBQyxjQUFjLEdBQUcsQ0FBQyxHQUFHLGNBQWMsQ0FBQyxjQUFjLENBQUMsQ0FBQztJQUM1RCxDQUFDO0lBQ0QsSUFBSSxjQUFjLENBQUMsZUFBZSxFQUFFLE1BQU0sRUFBRSxDQUFDO1FBQzNDLEtBQUssQ0FBQyxlQUFlLEdBQUcsQ0FBQyxHQUFHLGNBQWMsQ0FBQyxlQUFlLENBQUMsQ0FBQztRQUM1RCxJQUFJLENBQUMsZUFBZSxHQUFHLENBQUMsR0FBRyxjQUFjLENBQUMsZUFBZSxDQUFDLENBQUM7SUFDN0QsQ0FBQztJQUVELHdDQUF3QztJQUN4QyxJQUFJLGNBQWMsQ0FBQyxnQkFBZ0IsRUFBRSxNQUFNLEVBQUUsQ0FBQztRQUM1QyxJQUFJLENBQUMsZ0JBQWdCLEdBQUcsQ0FBQyxHQUFHLGNBQWMsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO0lBQy9ELENBQUM7SUFDRCxJQUFJLGNBQWMsQ0FBQyxZQUFZLEVBQUUsQ0FBQztRQUNoQyxJQUFJLENBQUMsWUFBWSxHQUFHLEVBQUUsR0FBRyxjQUFjLENBQUMsWUFBWSxFQUFFLENBQUM7SUFDekQsQ0FBQztBQUNILENBQUM7QUFRRCxNQUFNLHdCQUF3QixHQUFHLE1BQU0sQ0FBQyxHQUFHLENBQ3pDLG9EQUFvRCxDQUNyRCxDQUFDO0FBRUYsTUFBTSwyQkFBMkIsR0FBRyxDQUNsQyxjQUFnRCxFQUNoRCxpQkFBeUIsRUFDUyxFQUFFO0lBQ3BDLE1BQU0sV0FBVyxHQUFHLE1BQU0sQ0FBQyxTQUFTLENBQUMsY0FBYyxDQUFDLElBQUksQ0FDdEQsY0FBYyxFQUNiLE1BQWMsQ0FBQyxRQUFRLENBQ3pCO1FBQ0MsQ0FBQyxDQUFHLGNBQXNCLENBQUUsTUFBYyxDQUFDLFFBQVEsQ0FFbkM7UUFDaEIsQ0FBQyxDQUFDLFNBQVMsQ0FBQztJQUNkLE1BQU0sUUFBUSxHQUFHLHNCQUFzQixDQUNyQyxpQ0FBaUMsQ0FBQyxjQUFjLENBQUMsRUFDakQsV0FBVyxDQUNaLENBQUM7SUFDRixNQUFNLGVBQWUsR0FBRztRQUN0QixHQUFHLElBQUksR0FBRyxDQUFTO1lBQ2pCLEdBQUcsQ0FBQyxRQUFRLENBQUMsa0JBQWtCLElBQUksRUFBRSxDQUFDO1lBQ3RDLEdBQUcsQ0FBQyxRQUFRLENBQUMsYUFBYSxJQUFJLEVBQUUsQ0FBQztZQUNqQyxHQUFHLENBQUMsUUFBUSxDQUFDLGNBQWMsSUFBSSxFQUFFLENBQUMsQ0FBQyxHQUFHLENBQ3BDLENBQUMsUUFBMkIsRUFBRSxFQUFFLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQzlEO1lBQ0QsR0FBRyxDQUFDLFFBQVEsQ0FBQyxlQUFlLElBQUksRUFBRSxDQUFDLENBQUMsT0FBTyxDQUN6QyxDQUFDLFFBQWtDLEVBQUUsRUFBRSxDQUNyQyxNQUFNLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxRQUFRLEVBQUUsRUFBRSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FDdEU7U0FDRixDQUFDO0tBQ0gsQ0FBQztJQUNGLE1BQU0sYUFBYSxHQUFHLE1BQU0sQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLFlBQVksSUFBSSxFQUFFLENBQUM7U0FDOUQsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLFVBQVUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxVQUFVLEVBQUUsT0FBTyxLQUFLLElBQUksQ0FBQztTQUN4RCxHQUFHLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUNqQyxNQUFNLE9BQU8sR0FBNEIsRUFBRSxDQUFDO0lBQzVDLEtBQUssTUFBTSxXQUFXLElBQUksUUFBUSxDQUFDLGFBQWEsSUFBSSxFQUFFLEVBQUUsQ0FBQztRQUN2RCxPQUFPLENBQUMsSUFBSSxDQUFDO1lBQ1gsSUFBSSxFQUFFLEdBQUcsV0FBVyxJQUFJO1lBQ3hCLEdBQUcsRUFBRSxFQUFFLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQyxFQUFFO1lBQ3pCLE9BQU8sRUFBRSxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUU7U0FDMUIsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUNELEtBQUssTUFBTSxZQUFZLElBQUksUUFBUSxDQUFDLGNBQWMsSUFBSSxFQUFFLEVBQUUsQ0FBQztRQUN6RCxNQUFNLFVBQVUsR0FBRyxFQUFFLEdBQUcsQ0FBQyxZQUFZLENBQUMsT0FBTyxJQUFJLEVBQUUsQ0FBQyxFQUduRCxDQUFDO1FBQ0YsTUFBTSxZQUFZLEdBQ2hCLE9BQU8sVUFBVSxDQUFDLElBQUksS0FBSyxRQUFRO1lBQ2pDLENBQUMsQ0FBQyxVQUFVLENBQUMsSUFBSTtZQUNqQixDQUFDLENBQUMsR0FBRyxZQUFZLENBQUMsS0FBSyxJQUFJLENBQUM7UUFDaEMsT0FBTyxVQUFVLENBQUMsSUFBSSxDQUFDO1FBQ3ZCLE9BQU8sQ0FBQyxJQUFJLENBQUM7WUFDWCxJQUFJLEVBQUUsWUFBWTtZQUNsQixHQUFHLEVBQUUsRUFBRSxDQUFDLFlBQVksQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLEVBQUU7WUFDaEMsT0FBTyxFQUFFLFVBQTBDO1NBQ3BELENBQUMsQ0FBQztJQUNMLENBQUM7SUFDRCxLQUFLLE1BQU0sdUJBQXVCLElBQUksUUFBUSxDQUFDLGVBQWUsSUFBSSxFQUFFLEVBQUUsQ0FBQztRQUNyRSxNQUFNLG1CQUFtQixHQUFHLCtCQUErQixDQUN6RCx1QkFBdUIsQ0FDeEIsQ0FBQztRQUNGLE9BQU8sQ0FBQyxJQUFJLENBQUM7WUFDWCxJQUFJLEVBQUUsbUJBQW1CLENBQUMsSUFBSTtZQUM5QixHQUFHLEVBQUUsRUFBRSxHQUFHLG1CQUFtQixDQUFDLEdBQUcsRUFBRTtZQUNuQyxPQUFPLEVBQUUsRUFBRSxHQUFHLENBQUMsbUJBQW1CLENBQUMsT0FBTyxJQUFJLEVBQUUsQ0FBQyxFQUFFO1NBQ3BELENBQUMsQ0FBQztJQUNMLENBQUM7SUFDRCxPQUFPLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUMsWUFBWSxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFDL0MsT0FBTyw4QkFBOEIsQ0FDbkM7UUFDRSxjQUFjLEVBQUUsaUJBQWlCO1FBQ2pDLGVBQWU7UUFDZixhQUFhO1FBQ2IsY0FBYyxFQUFFLFFBQVEsQ0FBQyxhQUFhLElBQUksRUFBRTtRQUM1QyxnQkFBZ0IsRUFBRSxRQUFRLENBQUMsZ0JBQWdCLElBQUksRUFBRTtRQUNqRCxPQUFPO0tBQ1IsRUFDRCxJQUFJLEVBQ0osUUFBUSxDQUFDLGtCQUFrQixFQUMzQiw0QkFBNEIsQ0FBQyxjQUFjLENBQUMsQ0FDN0MsQ0FBQztBQUNKLENBQUMsQ0FBQztBQUVGLE1BQU0sd0JBQXdCLEdBQUcsQ0FHL0IsY0FBbUQsRUFDbkQsYUFBcUQsRUFDckQsaUJBQXlELEVBQ3BCLEVBQUU7SUFDdkMsTUFBTSxhQUFhLEdBQUcsQ0FBQyxXQUFxQixFQUFFLEVBQUU7UUFDOUMsTUFBTSxFQUFFLEdBQUcsYUFBYSxDQUFDLFdBQVcsQ0FBQyxDQUFDO1FBQ3RDLElBQUksQ0FBQyxDQUFDLEVBQUUsWUFBWSxXQUFXLENBQUMsRUFBRSxDQUFDO1lBQ2pDLE1BQU0sSUFBSSx5QkFBeUIsQ0FDakMsdUJBQXVCLEVBQ3ZCLFVBQVUsY0FBYyxDQUFDLElBQUksa0NBQWtDLENBQ2hFLENBQUM7UUFDSixDQUFDO1FBQ0QsTUFBTSxNQUFNLEdBQUcsaUJBQWlCLEVBQUUsQ0FBQztRQUNuQyxJQUFJLE1BQU0sQ0FBQyxtQkFBbUIsS0FBSyw0QkFBNEIsQ0FBQyxjQUFjLENBQUMsRUFBRSxDQUFDO1lBQ2hGLE1BQU0sSUFBSSx5QkFBeUIsQ0FBQyx1QkFBdUIsRUFDekQsMkVBQTJFLENBQUMsQ0FBQztRQUNqRixDQUFDO1FBQ0QsT0FBTyxpQkFBaUIsQ0FBQyxhQUFhLENBQ3BDLE1BQU0sQ0FBQyxjQUFjLEVBQ3JCLEVBQUUsRUFDRixNQUFNLENBQ1AsQ0FBQztJQUNKLENBQUMsQ0FBQztJQUNGLE1BQU0sQ0FBQyxjQUFjLENBQUMsY0FBYyxFQUFFLG1DQUFtQyxFQUFFO1FBQ3pFLEtBQUssRUFBRSxpQkFBaUI7UUFDeEIsVUFBVSxFQUFFLEtBQUs7UUFDakIsWUFBWSxFQUFFLElBQUk7UUFDbEIsUUFBUSxFQUFFLEtBQUs7S0FDaEIsQ0FBQyxDQUFDO0lBQ0YsY0FBc0IsQ0FBQyxTQUFTLEdBQUcsY0FBYyxDQUFDLElBQUksQ0FBQztJQUN4RCxNQUFNLENBQUMsY0FBYyxDQUFDLGNBQWMsRUFBRSxZQUFZLEVBQUU7UUFDbEQsR0FBRztZQUNELE9BQU8sYUFBYSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQzdCLENBQUM7UUFDRCxVQUFVLEVBQUUsS0FBSztRQUNqQixZQUFZLEVBQUUsSUFBSTtLQUNuQixDQUFDLENBQUM7SUFDSCxNQUFNLENBQUMsY0FBYyxDQUFDLGNBQWMsQ0FBQyxTQUFTLEVBQUUsWUFBWSxFQUFFO1FBQzVELEdBQUc7WUFDRCxPQUFPLGFBQWEsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUM3QixDQUFDO1FBQ0QsVUFBVSxFQUFFLEtBQUs7UUFDakIsWUFBWSxFQUFFLElBQUk7S0FDbkIsQ0FBQyxDQUFDO0lBQ0gsT0FBTyxjQUFjLENBQUM7QUFDeEIsQ0FBQyxDQUFDO0FBRUY7Ozs7O0dBS0c7QUFDSCxNQUFNLFVBQVUscUJBQXFCLENBR25DLFFBQTZDLEVBQzdDLEtBQTBDLEVBQzFDLFNBQXlDO0lBRXpDLElBQ0UsT0FBTyxRQUFRLEtBQUssVUFBVTtRQUM5QixDQUFDLENBQUMsUUFBUSxDQUFDLFNBQVMsWUFBWSxjQUFjLENBQUMsRUFDL0MsQ0FBQztRQUNELE1BQU0sSUFBSSx5QkFBeUIsQ0FDakMsdUJBQXVCLEVBQ3ZCLDhEQUE4RCxDQUMvRCxDQUFDO0lBQ0osQ0FBQztJQUNELE1BQU0sa0JBQWtCLEdBQUcsTUFBTSxDQUFDLGNBQWMsQ0FBQyxRQUFRLENBQUMsU0FBUyxDQUl0RCxDQUFDO0lBQ2QsTUFBTSxvQkFBb0IsR0FBRyxNQUFNLENBQUMsY0FBYyxDQUFDLFFBQVEsQ0FJOUMsQ0FBQztJQUNkLE1BQU0sZUFBZSxHQUFHLG9CQUFvQixFQUFFLENBQUMsd0JBQXdCLENBQUMsQ0FBQztJQUN6RSxNQUFNLGdCQUFnQixHQUFHLDhCQUE4QixDQUFDO1FBQ3RELEdBQUcsU0FBUztRQUNaLGVBQWUsRUFBRTtZQUNmLEdBQUcsQ0FBQyxrQkFBa0IsRUFBRSxrQkFBa0IsSUFBSSxFQUFFLENBQUM7WUFDakQsR0FBRyxDQUFDLFNBQVMsQ0FBQyxlQUFlLElBQUksRUFBRSxDQUFDO1NBQ0w7UUFDakMsYUFBYSxFQUFFO1lBQ2IsR0FBRyxDQUFDLGVBQWUsRUFBRSxhQUFhLElBQUksRUFBRSxDQUFDO1lBQ3pDLEdBQUcsQ0FBQyxTQUFTLENBQUMsYUFBYSxJQUFJLEVBQUUsQ0FBQztTQUNhO1FBQ2pELGNBQWMsRUFBRTtZQUNkLEdBQUcsQ0FBQyxlQUFlLEVBQUUsY0FBYyxJQUFJLEVBQUUsQ0FBQztZQUMxQyxHQUFHLENBQUMsU0FBUyxDQUFDLGNBQWMsSUFBSSxFQUFFLENBQUM7U0FDSjtRQUNqQyxnQkFBZ0IsRUFBRTtZQUNoQixHQUFHLENBQUMsZUFBZSxFQUFFLGdCQUFnQixJQUFJLEVBQUUsQ0FBQztZQUM1QyxHQUFHLENBQUMsU0FBUyxDQUFDLGdCQUFnQixJQUFJLEVBQUUsQ0FBQztTQUNOO1FBQ2pDLE9BQU8sRUFBRTtZQUNQLEdBQUcsQ0FBQyxlQUFlLEVBQUUsT0FBTyxJQUFJLEVBQUUsQ0FBQztpQkFDaEMsTUFBTSxDQUFDLENBQUMsUUFBUSxFQUFFLEVBQUUsQ0FBQyxRQUFRLENBQUMsSUFBSSxLQUFLLHNCQUFzQixDQUFDO2lCQUM5RCxHQUFHLENBQUMsQ0FBQyxRQUFRLEVBQUUsRUFBRSxDQUFDLENBQUM7Z0JBQ2xCLElBQUksRUFBRSxRQUFRLENBQUMsSUFBSTtnQkFDbkIsR0FBRyxFQUFFLE1BQU0sQ0FBQyxXQUFXLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQztnQkFDckMsT0FBTyxFQUFFLEVBQUUsR0FBRyxRQUFRLENBQUMsT0FBTyxFQUFFO2FBQ2pDLENBQUMsQ0FBQztZQUNMLEdBQUcsQ0FBQyxTQUFTLENBQUMsT0FBTyxJQUFJLEVBQUUsQ0FBQztTQUM3QjtLQUNGLEVBQUUsS0FBSyxFQUFFLFNBQVMsRUFBRSw0QkFBNEIsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDO0lBQzdELE1BQU0saUJBQWlCLEdBQUcsTUFBTSxDQUFDLFNBQVMsQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUM1RCxRQUFRLEVBQ1Isd0JBQXdCLENBQ3pCO1FBQ0MsQ0FBQyxDQUFHLFFBQWdCLENBQ2hCLHdCQUF3QixDQUNZO1FBQ3hDLENBQUMsQ0FBQyxTQUFTLENBQUM7SUFDZCxJQUNFLGlCQUFpQjtRQUNqQixDQUFDLGlCQUFpQixDQUFDLFdBQVcsS0FBSyxnQkFBZ0IsQ0FBQyxXQUFXO1lBQzdELGlCQUFpQixDQUFDLG1CQUFtQixFQUFFLG9CQUFvQjtnQkFDekQsZ0JBQWdCLENBQUMsbUJBQW1CLEVBQUUsb0JBQW9CLENBQUMsRUFDL0QsQ0FBQztRQUNELE1BQU0sSUFBSSx5QkFBeUIsQ0FDakMsdUJBQXVCLEVBQ3ZCLFVBQVUsUUFBUSxDQUFDLElBQUksOENBQThDLENBQ3RFLENBQUM7SUFDSixDQUFDO0lBQ0QsTUFBTSxlQUFlLEdBQUcsaUJBQWlCLElBQUksZ0JBQWdCLENBQUM7SUFDOUQsSUFBSSxDQUFDLGlCQUFpQixFQUFFLENBQUM7UUFDdkIsTUFBTSxDQUFDLGNBQWMsQ0FBQyxRQUFRLEVBQUUsd0JBQXdCLEVBQUU7WUFDeEQsS0FBSyxFQUFFLGVBQWU7WUFDdEIsVUFBVSxFQUFFLEtBQUs7WUFDakIsWUFBWSxFQUFFLEtBQUs7WUFDbkIsUUFBUSxFQUFFLEtBQUs7U0FDaEIsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUNELFFBQVEsQ0FBQyxTQUFTLENBQUMsa0JBQWtCLEdBQUc7UUFDdEMsR0FBRyxlQUFlLENBQUMsZUFBZTtLQUNuQyxDQUFDO0lBQ0YsUUFBUSxDQUFDLFNBQVMsQ0FBQyxhQUFhLEdBQUcsQ0FBQyxHQUFHLGVBQWUsQ0FBQyxjQUFjLENBQUMsQ0FBQztJQUN2RSxRQUFRLENBQUMsU0FBUyxDQUFDLGtCQUFrQixHQUFHO1FBQ3RDLEdBQUcsZUFBZSxDQUFDLGtCQUFrQjtLQUN0QyxDQUFDO0lBQ0QsUUFBZ0IsQ0FBQyxnQkFBZ0IsR0FBRztRQUNuQyxHQUFHLGVBQWUsQ0FBQyxnQkFBZ0I7S0FDcEMsQ0FBQztJQUNGLE9BQU8sd0JBQXdCLENBQzdCLFFBQVEsRUFDUixHQUFHLEVBQUUsQ0FBQyxDQUFDLEtBQUssWUFBWSxXQUFXLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsS0FBSyxFQUFFLENBQUMsRUFDdEQsR0FBRyxFQUFFLENBQUMsZUFBZSxDQUN0QixDQUFDO0FBQ0osQ0FBQztBQUVELE1BQU0sK0JBQStCLEdBQUcsQ0FDdEMsYUFBdUMsRUFDYixFQUFFO0lBQzVCLElBQ0UsT0FBTyxhQUFhLEVBQUUsSUFBSSxLQUFLLFFBQVE7UUFDdkMsYUFBYSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUN0QyxDQUFDO1FBQ0QsTUFBTSxJQUFJLHlCQUF5QixDQUNqQyx1QkFBdUIsRUFDdkIsNkNBQTZDLENBQzlDLENBQUM7SUFDSixDQUFDO0lBQ0QsSUFDRSxPQUFPLGFBQWEsQ0FBQyxHQUFHLEtBQUssUUFBUTtRQUNyQyxhQUFhLENBQUMsR0FBRyxLQUFLLElBQUk7UUFDMUIsS0FBSyxDQUFDLE9BQU8sQ0FBQyxhQUFhLENBQUMsR0FBRyxDQUFDO1FBQ2hDLE1BQU0sQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLEdBQUcsQ0FBQyxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQ3pDLENBQUM7UUFDRCxNQUFNLElBQUkseUJBQXlCLENBQ2pDLHVCQUF1QixFQUN2QixtQkFBbUIsYUFBYSxDQUFDLElBQUkseUNBQXlDLENBQy9FLENBQUM7SUFDSixDQUFDO0lBQ0QsS0FBSyxNQUFNLENBQUMsS0FBSyxFQUFFLFNBQVMsQ0FBQyxJQUFJLE1BQU0sQ0FBQyxPQUFPLENBQUMsYUFBYSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7UUFDbkUsSUFDRSxLQUFLLENBQUMsSUFBSSxFQUFFLENBQUMsTUFBTSxLQUFLLENBQUM7WUFDekIsS0FBSyxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUM7WUFDckIsS0FBSyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUM7WUFDcEIsQ0FBQyxTQUFTLEtBQUssQ0FBQyxJQUFJLFNBQVMsS0FBSyxDQUFDLENBQUMsQ0FBQyxFQUNyQyxDQUFDO1lBQ0QsTUFBTSxJQUFJLHlCQUF5QixDQUNqQyx1QkFBdUIsRUFDdkIsbUJBQW1CLGFBQWEsQ0FBQyxJQUFJLHNDQUFzQyxDQUM1RSxDQUFDO1FBQ0osQ0FBQztJQUNILENBQUM7SUFDRCxNQUFNLE9BQU8sR0FBRyxFQUFFLEdBQUcsQ0FBQyxhQUFhLENBQUMsT0FBTyxJQUFJLEVBQUUsQ0FBQyxFQUE2QixDQUFDO0lBQ2hGLElBQUksTUFBTSxJQUFJLE9BQU8sRUFBRSxDQUFDO1FBQ3RCLE1BQU0sSUFBSSx5QkFBeUIsQ0FDakMsdUJBQXVCLEVBQ3ZCLG1CQUFtQixhQUFhLENBQUMsSUFBSSx5Q0FBeUMsQ0FDL0UsQ0FBQztJQUNKLENBQUM7SUFDRCxJQUFJLFFBQVEsSUFBSSxPQUFPLElBQUksT0FBTyxPQUFPLENBQUMsTUFBTSxLQUFLLFNBQVMsRUFBRSxDQUFDO1FBQy9ELE1BQU0sSUFBSSx5QkFBeUIsQ0FDakMsdUJBQXVCLEVBQ3ZCLG1CQUFtQixhQUFhLENBQUMsSUFBSSxvQ0FBb0MsQ0FDMUUsQ0FBQztJQUNKLENBQUM7SUFDRCxJQUFJLFFBQVEsSUFBSSxPQUFPLElBQUksT0FBTyxPQUFPLENBQUMsTUFBTSxLQUFLLFNBQVMsRUFBRSxDQUFDO1FBQy9ELE1BQU0sSUFBSSx5QkFBeUIsQ0FDakMsdUJBQXVCLEVBQ3ZCLG1CQUFtQixhQUFhLENBQUMsSUFBSSxvQ0FBb0MsQ0FDMUUsQ0FBQztJQUNKLENBQUM7SUFDRCxJQUNFLG9CQUFvQixJQUFJLE9BQU87UUFDL0IsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLGtCQUFrQixDQUFDO1lBQzFDLE9BQU8sQ0FBQyxrQkFBNkIsR0FBRyxDQUFDLENBQUMsRUFDN0MsQ0FBQztRQUNELE1BQU0sSUFBSSx5QkFBeUIsQ0FDakMsdUJBQXVCLEVBQ3ZCLG1CQUFtQixhQUFhLENBQUMsSUFBSSw2Q0FBNkMsQ0FDbkYsQ0FBQztJQUNKLENBQUM7SUFDRCxPQUFPO1FBQ0wsSUFBSSxFQUFFLGFBQWEsQ0FBQyxJQUFJO1FBQ3hCLEdBQUcsRUFBRSxFQUFFLEdBQUcsYUFBYSxDQUFDLEdBQUcsRUFBRTtRQUM3QixPQUFPLEVBQUUsRUFBRSxHQUFHLENBQUMsYUFBYSxDQUFDLE9BQU8sSUFBSSxFQUFFLENBQUMsRUFBRTtLQUM5QyxDQUFDO0FBQ0osQ0FBQyxDQUFDO0FBRUY7O0dBRUc7QUFDSCxNQUFNLFVBQVUsYUFBYSxDQUFDLGFBQXVDO0lBQ25FLE1BQU0sVUFBVSxHQUFHLCtCQUErQixDQUFDLGFBQWEsQ0FBQyxDQUFDO0lBQ2xFLE9BQU8sU0FBUyxjQUFjLENBQUMsS0FBZSxFQUFFLE9BQThCO1FBQzVFLElBQUksT0FBTyxDQUFDLElBQUksS0FBSyxPQUFPLEVBQUUsQ0FBQztZQUM3QixNQUFNLElBQUksS0FBSyxDQUFDLHlDQUF5QyxDQUFDLENBQUM7UUFDN0QsQ0FBQztRQUNELE1BQU0sUUFBUSxHQUFHLE9BQU8sQ0FBQyxRQUF1QyxDQUFDO1FBQ2pFLElBQ0UsQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLGlCQUFpQixDQUFDLEVBQ2xFLENBQUM7WUFDRCxRQUFRLENBQUMsZUFBZSxHQUFHLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxlQUFlLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQztRQUNuRSxDQUFDO1FBQ0QsTUFBTSxrQkFBa0IsR0FBRyxRQUFRLENBQUMsZUFBZ0IsQ0FBQztRQUNyRCxNQUFNLFFBQVEsR0FBRyxrQkFBa0IsQ0FBQyxJQUFJLENBQ3RDLENBQUMsZUFBZSxFQUFFLEVBQUUsQ0FBQyxlQUFlLENBQUMsSUFBSSxLQUFLLFVBQVUsQ0FBQyxJQUFJLENBQzlELENBQUM7UUFDRixJQUFJLFFBQVEsSUFBSSxDQUFDLG9CQUFvQixDQUFDLFFBQVEsRUFBRSxVQUFVLENBQUMsRUFBRSxDQUFDO1lBQzVELE1BQU0sSUFBSSx5QkFBeUIsQ0FDakMsdUJBQXVCLEVBQ3ZCLG1CQUFtQixVQUFVLENBQUMsSUFBSSwrQkFBK0IsQ0FDbEUsQ0FBQztRQUNKLENBQUM7UUFDRCxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7WUFDZCxrQkFBa0IsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDdEMsQ0FBQztRQUNELDJCQUEyQixDQUN6QixLQUFzRCxFQUN0RCxPQUFPLENBQUMsUUFBUSxDQUNqQixDQUFDO1FBQ0YsT0FBTyxLQUFZLENBQUM7SUFDdEIsQ0FBQyxDQUFDO0FBQ0osQ0FBQztBQUVELHVGQUF1RjtBQUN2RixNQUFNLFVBQVUsVUFBVSxDQUFDLGFBQW9DO0lBQzdELE1BQU0sc0JBQXNCLEdBQUcsQ0FBQyxRQUFpQixFQUFFLE9BQWtCLEVBQUUsRUFBRTtRQUN2RSxJQUFJLENBQUMsUUFBUSxJQUFJLE1BQU0sQ0FBQyxjQUFjLENBQUMsUUFBUSxDQUFDLEtBQUssTUFBTSxDQUFDLFNBQVM7WUFDbkUsT0FBTyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLE9BQU8sTUFBTSxLQUFLLFFBQVE7Z0JBQ25FLENBQUMsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsQ0FBQztnQkFDdEMsQ0FBQyxDQUFDLE9BQU8sSUFBSSxNQUFNLENBQUMsd0JBQXdCLENBQUMsUUFBUSxFQUFFLE1BQU0sQ0FBRSxDQUFDLENBQUMsRUFBRSxDQUFDO1lBQ3RFLE1BQU0sSUFBSSx5QkFBeUIsQ0FBQyx1QkFBdUIsRUFBRSxrQ0FBa0MsQ0FBQyxDQUFDO1FBQ25HLENBQUM7SUFDSCxDQUFDLENBQUM7SUFDRixzQkFBc0IsQ0FBQyxhQUFhLEVBQUUsQ0FBQyxNQUFNLEVBQUUsS0FBSyxFQUFFLFNBQVMsQ0FBQyxDQUFDLENBQUM7SUFDbEUsc0JBQXNCLENBQUMsYUFBYSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQzFDLElBQUksYUFBYSxDQUFDLE9BQU8sS0FBSyxTQUFTO1FBQUUsc0JBQXNCLENBQUMsYUFBYSxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQ3ZGLE1BQU0sTUFBTSxHQUFHLDhCQUE4QixDQUFDO1FBQzVDLGNBQWMsRUFBRSx5QkFBeUI7UUFDekMsZUFBZSxFQUFFLENBQUMsR0FBRyxJQUFJLEdBQUcsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ3JHLGdCQUFnQixFQUFFLE1BQU0sQ0FBQyxPQUFPLENBQUMsYUFBYSxDQUFDLEdBQUcsQ0FBQzthQUNoRCxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsWUFBWSxDQUFDLEVBQUUsRUFBRSxDQUFDLFlBQVksS0FBSyxNQUFNLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxFQUFFLEVBQUUsQ0FBQyxPQUFPLENBQUM7UUFDcEYsT0FBTyxFQUFFLENBQUMsYUFBYSxDQUFDO0tBQ3pCLENBQUMsQ0FBQztJQUNILG9GQUFvRjtJQUNwRixzQ0FBc0MsQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUMvQyxNQUFNLFVBQVUsR0FBRyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3JDLE1BQU0sVUFBVSxHQUEwQixNQUFNLENBQUMsTUFBTSxDQUFDO1FBQ3RELElBQUksRUFBRSxVQUFVLENBQUMsSUFBSTtRQUNyQixHQUFHLEVBQUUsTUFBTSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUN0RCxPQUFPLEVBQUUsVUFBVSxDQUFDLE9BQU87S0FDNUIsQ0FBQyxDQUFDO0lBQ0gsT0FBTyxTQUFTLGNBQWMsQ0FBQyxLQUFlLEVBQUUsT0FBOEI7UUFDNUUsSUFBSSxPQUFPLENBQUMsSUFBSSxLQUFLLE9BQU8sRUFBRSxDQUFDO1lBQzdCLE1BQU0sSUFBSSx5QkFBeUIsQ0FBQyx1QkFBdUIsRUFBRSx1Q0FBdUMsQ0FBQyxDQUFDO1FBQ3hHLENBQUM7UUFDRCxNQUFNLFFBQVEsR0FBRyxPQUFPLENBQUMsUUFBdUMsQ0FBQztRQUNqRSxRQUFRLENBQUMsWUFBWSxHQUFHLG9CQUFvQixDQUFDLFFBQVEsQ0FBQyxZQUFZLEVBQUUsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDO1FBQ2xGLE9BQU8sS0FBWSxDQUFDO0lBQ3RCLENBQUMsQ0FBQztBQUNKLENBQUM7QUFFRDs7O0dBR0c7QUFDSCxNQUFNLFVBQVUsVUFBVSxDQUN4QixLQUEwQyxFQUMxQyxVQUFzQztJQUV0QyxPQUFPLFNBQVMsY0FBYyxDQUFDLEtBQWUsRUFBRSxPQUE4QjtRQUM1RSxJQUFJLE9BQU8sQ0FBQyxJQUFJLEtBQUssT0FBTyxFQUFFLENBQUM7WUFDN0IsTUFBTSxJQUFJLEtBQUssQ0FBQyxzQ0FBc0MsQ0FBQyxDQUFDO1FBQzFELENBQUM7UUFFRCxNQUFNLFdBQVcsR0FBRyxLQUErRCxDQUFDO1FBQ3BGLDJCQUEyQixDQUFDLFdBQVcsRUFBRSxPQUFPLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDM0QsTUFBTSxjQUFjLEdBQUcsdUJBQXVCLENBQzVDLFVBQVUsRUFBRSxjQUFjLElBQUksV0FBVyxDQUFDLElBQUksQ0FDL0MsQ0FBQztRQUNGLE9BQU8sd0JBQXdCLENBQzdCLFdBQStDLEVBQy9DLEdBQUcsRUFBRSxDQUFDLENBQUMsS0FBSyxZQUFZLFdBQVcsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLEVBQUUsQ0FBQyxFQUN0RCxHQUFHLEVBQUU7WUFDSCxPQUFPLDJCQUEyQixDQUNoQyxXQUErQyxFQUMvQyxjQUFjLENBQ2YsQ0FBQztRQUNKLENBQUMsQ0FDSyxDQUFDO0lBQ1gsQ0FBQyxDQUFDO0FBQ0osQ0FBQztBQU1ELE1BQU0sQ0FBQyxNQUFNLHVCQUF1QixHQUFHLENBQUssVUFBb0IsRUFBRSxRQUFXLEVBQUssRUFBRTtJQUNqRixRQUFnQixDQUFDLFNBQVMsQ0FBQyxjQUFjLEdBQUcsVUFBVSxDQUFDO0lBQ3hELE9BQU8sUUFBUSxDQUFDO0FBQ2xCLENBQUMsQ0FBQztBQUVGOzs7R0FHRztBQUNILE1BQU0sVUFBVSxPQUFPLENBQ3JCLG1CQUc2QixFQUM3QixVQUFzQztJQUV0QyxNQUFNLHNCQUFzQixHQUMxQixPQUFPLG1CQUFtQixLQUFLLFFBQVE7UUFDdkMsbUJBQW1CLEtBQUssSUFBSTtRQUM1QixDQUFDLENBQUMsSUFBSSxJQUFJLG1CQUFtQixDQUFDO1FBQzlCLGdCQUFnQixJQUFJLG1CQUFtQjtRQUN2QyxVQUFVLEtBQUssU0FBUyxDQUFDO0lBQzNCLE1BQU0sVUFBVSxHQUFHLHNCQUFzQjtRQUN2QyxDQUFDLENBQUMsU0FBUztRQUNYLENBQUMsQ0FBRSxtQkFBaUUsQ0FBQztJQUN2RSxNQUFNLGNBQWMsR0FBRyxzQkFBc0I7UUFDM0MsQ0FBQyxDQUFFLG1CQUFpRDtRQUNwRCxDQUFDLENBQUMsVUFBVSxDQUFDO0lBQ2YsT0FBTyxTQUFTLGNBQWMsQ0FBQyxLQUFlLEVBQUUsT0FBOEI7UUFDNUUsSUFBSSxPQUFPLENBQUMsSUFBSSxLQUFLLE9BQU8sRUFBRSxDQUFDO1lBQzdCLE1BQU0sSUFBSSxLQUFLLENBQUMsbUNBQW1DLENBQUMsQ0FBQztRQUN2RCxDQUFDO1FBRUQsTUFBTSxXQUFXLEdBQUcsS0FBK0QsQ0FBQztRQUNwRiwyQkFBMkIsQ0FBQyxXQUFXLEVBQUUsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBRTNELHNEQUFzRDtRQUN0RCxNQUFNLFVBQVUsR0FBRyxDQUFDLFdBQXFCLEVBQVksRUFBRTtZQUNyRCxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7Z0JBQ2hCLElBQUksT0FBTyxXQUFXLEtBQUssVUFBVSxFQUFFLENBQUM7b0JBQ3RDLE9BQVEsV0FBa0MsQ0FBQyxTQUFTLENBQUMsY0FBYyxDQUFDO2dCQUN0RSxDQUFDO2dCQUNELE9BQU8sQ0FDSixXQUF5RDtvQkFDeEQsRUFBRSxjQUFjLElBQUksV0FBVyxDQUFDLFNBQVMsQ0FBQyxjQUFjLENBQzNELENBQUM7WUFDSixDQUFDO1lBQ0QsSUFBSSxPQUFPLFVBQVUsS0FBSyxVQUFVLElBQUksVUFBVSxDQUFDLEVBQUUsRUFBRSxDQUFDO2dCQUN0RCxPQUFPLFVBQXNCLENBQUM7WUFDaEMsQ0FBQztZQUNELE9BQVEsVUFBaUMsRUFBRSxDQUFDO1FBQzlDLENBQUMsQ0FBQztRQUVGLE1BQU0sY0FBYyxHQUFHLHVCQUF1QixDQUM1QyxjQUFjLEVBQUUsY0FBYyxJQUFJLFdBQVcsQ0FBQyxJQUFJLENBQ25ELENBQUM7UUFDRix3QkFBd0IsQ0FDdEIsV0FBK0MsRUFDL0MsQ0FBQyxXQUFXLEVBQUUsRUFBRSxDQUFDLFVBQVUsQ0FBQyxXQUFXLENBQUMsQ0FBQyxFQUFFLEVBQzNDLEdBQUcsRUFBRTtZQUNILE9BQU8sMkJBQTJCLENBQ2hDLFdBQStDLEVBQy9DLGNBQWMsQ0FDZixDQUFDO1FBQ0osQ0FBQyxDQUNGLENBQUM7UUFDRixNQUFNLENBQUMsY0FBYyxDQUFDLFdBQVcsRUFBRSxTQUFTLEVBQUU7WUFDNUMsR0FBRyxLQUFrQixPQUFPLFVBQVUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDL0MsVUFBVSxFQUFFLEtBQUs7WUFDakIsWUFBWSxFQUFFLElBQUk7U0FDbkIsQ0FBQyxDQUFDO1FBRUgsTUFBTSxDQUFDLGNBQWMsQ0FBQyxXQUFXLENBQUMsU0FBUyxFQUFFLFNBQVMsRUFBRTtZQUN0RCxHQUFHLEtBQWtCLE9BQU8sVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUMvQyxVQUFVLEVBQUUsS0FBSztZQUNqQixZQUFZLEVBQUUsSUFBSTtTQUNuQixDQUFDLENBQUM7UUFFSCxPQUFPLFdBQWtCLENBQUM7SUFDNUIsQ0FBQyxDQUFDO0FBQ0osQ0FBQztBQUVEOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sT0FBTyxHQUFHLE9BQU8sQ0FBQztBQUUvQixNQUFNLE9BQU8sbUJBQW1CO0lBQzlCOztPQUVHO0lBQ0ksaUJBQWlCLENBQThCO0lBQy9DLGdCQUFnQixHQUFpQyxJQUFJLENBQUM7SUFDdEQsY0FBYyxDQUFTO0lBQ3ZCLFdBQVcsQ0FBYztJQUN6QixhQUFhLEdBQWEsRUFBRSxDQUFDO0lBQzdCLGNBQWMsR0FBbUQsRUFBRSxDQUFDO0lBQ3BFLGVBQWUsR0FBK0IsRUFBRSxDQUFDO0lBQ2hELFdBQVcsQ0FBb0M7SUFDL0MscUJBQXFCLENBQWlCO0lBQ3RDLHdCQUF3QixHQUFHLENBQUMsQ0FBQztJQUM3QixXQUFXLEdBQUcsS0FBSyxDQUFDO0lBRTVCLFlBQVksWUFBb0IsRUFBRSxjQUEyQjtRQUMzRCx1Q0FBdUM7UUFDdkMsSUFBSSxDQUFDLGNBQWMsR0FBRyxZQUFZLENBQUM7UUFDbkMsSUFBSSxDQUFDLFdBQVcsR0FBRyxjQUFjLENBQUM7UUFFbEMsd0ZBQXdGO1FBQ3hGLElBQUksQ0FBQyxXQUFXLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ3ZDLENBQUM7SUFFTyxzQkFBc0IsQ0FDNUIsVUFBaUQsRUFDakQsZ0JBQXlCLEVBQ3pCLFlBRXFCO1FBRXJCLE9BQU8sK0JBQStCLENBQ3BDLFVBQVUsRUFDVixJQUFJLENBQUMsV0FBVyxFQUNoQjtZQUNFLGFBQWEsRUFBRSxnQkFBZ0I7WUFDL0IsUUFBUSxFQUFFLElBQUksQ0FBQywrQkFBK0IsRUFBRTtZQUNoRCxrQkFBa0IsRUFDaEIsMEJBQTBCLElBQUksQ0FBQyxjQUFjLDRDQUE0QztTQUM1RixFQUNELFlBQVksQ0FDYixDQUFDO0lBQ0osQ0FBQztJQUVEOzs7O09BSUc7SUFDSSxtQkFBbUI7UUFDeEIsT0FBTyxJQUFJLENBQUMsV0FBVyxDQUFDO0lBQzFCLENBQUM7SUFFTSxlQUFlLENBQUMsU0FBMkM7UUFDaEUsSUFDRSxTQUFTLENBQUMsY0FBYyxLQUFLLElBQUksQ0FBQyxjQUFjO1lBQ2hELENBQUMsSUFBSSxDQUFDLFdBQVc7Z0JBQ2YsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLFdBQVcsS0FBSyxTQUFTLENBQUMsV0FBVztvQkFDckQsSUFBSSxDQUFDLFdBQVcsQ0FBQyxtQkFBbUIsRUFBRSxvQkFBb0I7d0JBQ3hELFNBQVMsQ0FBQyxtQkFBbUIsRUFBRSxvQkFBb0IsQ0FBQyxDQUFDLEVBQzNELENBQUM7WUFDRCxNQUFNLElBQUkseUJBQXlCLENBQ2pDLHVCQUF1QixFQUN2QixlQUFlLElBQUksQ0FBQyxjQUFjLHlDQUF5QyxDQUM1RSxDQUFDO1FBQ0osQ0FBQztRQUNELElBQUksQ0FBQyxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7WUFDdEIsSUFBSSxDQUFDLFdBQVcsR0FBRyxTQUFTLENBQUM7WUFDN0IsSUFBSSxDQUFDLHdCQUF3QixFQUFFLENBQUM7WUFDaEMsSUFBSSxDQUFDLFdBQVcsR0FBRyxLQUFLLENBQUM7WUFDekIsSUFBSSxDQUFDLHFCQUFxQixHQUFHLFNBQVMsQ0FBQztRQUN6QyxDQUFDO0lBQ0gsQ0FBQztJQUVNLHlCQUF5QjtRQUM5QixJQUFJLENBQUMsd0JBQXdCLEVBQUUsQ0FBQztRQUNoQyxPQUFRLElBQTJEO2FBQ2hFLGlCQUFpQixDQUFDO1FBQ3JCLElBQUksQ0FBQyxXQUFXLEdBQUcsS0FBSyxDQUFDO1FBQ3pCLElBQUksQ0FBQyxxQkFBcUIsR0FBRyxTQUFTLENBQUM7UUFDdkMsSUFBSSxDQUFDLGFBQWEsR0FBRyxFQUFFLENBQUM7UUFDeEIsSUFBSSxDQUFDLGNBQWMsR0FBRyxFQUFFLENBQUM7UUFDekIsSUFBSSxDQUFDLGVBQWUsR0FBRyxFQUFFLENBQUM7UUFDMUIseUJBQXlCLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDbEMsQ0FBQztJQUVEOztPQUVHO0lBQ0ksS0FBSyxDQUFDLElBQUk7UUFDZixJQUFJLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztZQUNyQixPQUFPO1FBQ1QsQ0FBQztRQUNELElBQUksQ0FBQyxJQUFJLENBQUMscUJBQXFCLEVBQUUsQ0FBQztZQUNoQyxNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsd0JBQXdCLENBQUM7WUFDakQsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQyxPQUFPLENBQUM7WUFDMUMsSUFBSSxxQkFBcUMsQ0FBQztZQUMxQyxxQkFBcUIsR0FBRyxJQUFJLENBQUMsY0FBYyxDQUFDLFFBQVEsRUFBRSxVQUFVLENBQUM7aUJBQzlELElBQUksQ0FBQyxHQUFHLEVBQUU7Z0JBQ1QsSUFDRSxJQUFJLENBQUMsd0JBQXdCLEtBQUssVUFBVTt1QkFDekMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxPQUFPLEtBQUssUUFBUSxFQUN4QyxDQUFDO29CQUNELElBQUksQ0FBQyxXQUFXLEdBQUcsSUFBSSxDQUFDO2dCQUMxQixDQUFDO1lBQ0gsQ0FBQyxDQUFDO2lCQUNELEtBQUssQ0FBQyxDQUFDLFFBQVEsRUFBRSxFQUFFO2dCQUNsQixNQUFNLG1CQUFtQixHQUN2QixJQUFJLENBQUMsd0JBQXdCLEtBQUssVUFBVTt1QkFDekMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxPQUFPLEtBQUssUUFBUSxDQUFDO2dCQUMzQyxJQUFJLElBQUksQ0FBQyxxQkFBcUIsS0FBSyxxQkFBcUIsRUFBRSxDQUFDO29CQUN6RCxJQUFJLENBQUMscUJBQXFCLEdBQUcsU0FBUyxDQUFDO29CQUN2QyxJQUFJLG1CQUFtQixFQUFFLENBQUM7d0JBQ3hCLElBQUksQ0FBQyxXQUFXLEdBQUcsS0FBSyxDQUFDO29CQUMzQixDQUFDO2dCQUNILENBQUM7Z0JBQ0QsSUFBSSxtQkFBbUIsRUFBRSxDQUFDO29CQUN4QixNQUFNLFFBQVEsQ0FBQztnQkFDakIsQ0FBQztZQUNILENBQUMsQ0FBQztpQkFDRCxPQUFPLENBQUMsR0FBRyxFQUFFO2dCQUNaLElBQUksSUFBSSxDQUFDLHFCQUFxQixLQUFLLHFCQUFxQixFQUFFLENBQUM7b0JBQ3pELElBQUksQ0FBQyxxQkFBcUIsR0FBRyxTQUFTLENBQUM7Z0JBQ3pDLENBQUM7WUFDSCxDQUFDLENBQUMsQ0FBQztZQUNMLElBQUksQ0FBQyxxQkFBcUIsR0FBRyxxQkFBcUIsQ0FBQztRQUNyRCxDQUFDO1FBQ0QsTUFBTSxxQkFBcUIsR0FBRyxJQUFJLENBQUMscUJBQXFCLENBQUM7UUFDekQsTUFBTSxxQkFBcUIsQ0FBQztRQUM1QixJQUFJLENBQUMsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDO1lBQ3RCLE1BQU0sSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQ3BCLENBQUM7SUFDSCxDQUFDO0lBRU0sS0FBSyxDQUFDLGlCQUFpQjtRQUM1QixNQUFNLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUNwQixDQUFDO0lBRUQsaUZBQWlGO0lBQzFFLEtBQUssQ0FBQyxpQkFBaUIsQ0FBQyxJQUE0QztRQUN6RSxNQUFNLE1BQU0sR0FBRyxJQUFJLDJCQUEyQixDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ3JELE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQyx3QkFBd0IsQ0FBQztRQUNqRCxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsV0FBVyxDQUFDLE9BQU8sQ0FBQztRQUMxQyxNQUFNLGFBQWEsR0FBRyxHQUFHLEVBQUU7WUFDekIsTUFBTSxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQ2YsSUFBSSxJQUFJLENBQUMsd0JBQXdCLEtBQUssVUFBVSxJQUFJLElBQUksQ0FBQyxXQUFXLENBQUMsT0FBTyxLQUFLLFFBQVE7Z0JBQ3ZGLElBQUksQ0FBQyxXQUFXLENBQUMsTUFBTSxLQUFLLFdBQVcsRUFBRSxDQUFDO2dCQUMxQyxNQUFNLElBQUkseUJBQXlCLENBQUMsdUJBQXVCLEVBQ3pELDZEQUE2RCxDQUFDLENBQUM7WUFDbkUsQ0FBQztRQUNILENBQUMsQ0FBQztRQUNGLElBQUksQ0FBQztZQUNILElBQUksQ0FBQyxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7Z0JBQ3RCLE1BQU0sSUFBSSx5QkFBeUIsQ0FBQyx1QkFBdUIsRUFDekQsdURBQXVELENBQUMsQ0FBQztZQUM3RCxDQUFDO1lBQ0QscUVBQXFFO1lBQ3JFLE9BQU8sSUFBSSxDQUFDLHFCQUFxQixFQUFFLENBQUM7Z0JBQ2xDLE1BQU0sTUFBTSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMscUJBQXFCLENBQUMsQ0FBQztnQkFDakQsYUFBYSxFQUFFLENBQUM7WUFDbEIsQ0FBQztZQUNELGFBQWEsRUFBRSxDQUFDO1lBQ2hCLElBQUksQ0FBQyxXQUFXLEdBQUcsS0FBSyxDQUFDO1lBQ3pCLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxXQUFXLENBQUM7WUFDaEMsTUFBTSxXQUFXLEdBQUcsQ0FBQyxLQUFLLElBQUksRUFBRTtnQkFDOUIsTUFBTSxPQUFPLEdBQUcsTUFBTSxJQUFJLENBQUMsV0FBVyxDQUFDLG9DQUFvQyxDQUFDLENBQUMsS0FBSyxFQUFFLEtBQUssRUFBRSxFQUFFO29CQUMzRixJQUFJLENBQUM7d0JBQ0gsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLHNCQUFzQixDQUFDLEtBQUssRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFLGFBQWEsQ0FBQyxFQUFFLENBQUM7b0JBQzVGLENBQUM7b0JBQUMsT0FBTyxRQUFRLEVBQUUsQ0FBQzt3QkFDbEIsNkVBQTZFO3dCQUM3RSxPQUFPLEVBQUUsS0FBSyxFQUFFLFFBQVEsRUFBRSxDQUFDO29CQUM3QixDQUFDO2dCQUNILENBQUMsQ0FBQyxDQUFDO2dCQUNILGFBQWEsRUFBRSxDQUFDO2dCQUNoQixJQUFJLE9BQU8sSUFBSSxPQUFPO29CQUFFLE1BQU0sT0FBTyxDQUFDLEtBQUssQ0FBQztnQkFDNUMsSUFBSSxDQUFDLGlCQUFpQixHQUFHLE9BQU8sQ0FBQyxVQUFVLENBQUM7Z0JBQzVDLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxNQUFNLENBQUMsQ0FBQztnQkFDakMsSUFBSSxDQUFDLFdBQVcsR0FBRyxJQUFJLENBQUM7WUFDMUIsQ0FBQyxDQUFDLEVBQUUsQ0FBQztZQUNMLElBQUksQ0FBQyxxQkFBcUIsR0FBRyxXQUFXLENBQUM7WUFDekMsSUFBSSxDQUFDO2dCQUNILE1BQU0sV0FBVyxDQUFDO1lBQ3BCLENBQUM7b0JBQVMsQ0FBQztnQkFDVCxJQUFJLElBQUksQ0FBQyxxQkFBcUIsS0FBSyxXQUFXO29CQUFFLElBQUksQ0FBQyxxQkFBcUIsR0FBRyxTQUFTLENBQUM7WUFDekYsQ0FBQztRQUNILENBQUM7UUFBQyxPQUFPLFFBQVEsRUFBRSxDQUFDO1lBQ2xCLE1BQU0sQ0FBQyxLQUFLLEVBQUUsQ0FBQztZQUNmLE1BQU0sUUFBUSxDQUFDO1FBQ2pCLENBQUM7Z0JBQVMsQ0FBQztZQUNULE1BQU0sQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUNqQixDQUFDO0lBQ0gsQ0FBQztJQUVNLCtCQUErQjtRQUNwQyxPQUFPLElBQUksQ0FBQyxXQUFXLElBQUksT0FBTyxDQUFDLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO0lBQzdELENBQUM7SUFFTyxLQUFLLENBQUMsY0FBYyxDQUMxQixXQUErQixFQUMvQixhQUFxQjtRQUVyQixJQUFJLGdCQUFnQixHQUFHLElBQUksQ0FBQyxpQkFBaUIsQ0FBQztRQUM5QyxJQUFJLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztZQUN0QixNQUFNLGdCQUFnQixHQUFHLE1BQU0sV0FBVztpQkFDdkMsZUFBZSxDQUNkLEVBQUUsSUFBSSxFQUFFLElBQUksQ0FBQyxjQUFjLEVBQUUsRUFDN0IsRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFLENBQ25CO2lCQUNBLE9BQU8sRUFBRSxDQUFDO1lBQ2IsSUFBSSxDQUFDLGdCQUFnQixFQUFFLENBQUM7Z0JBQ3RCLElBQUksQ0FBQztvQkFDSCxNQUFNLFdBQVcsQ0FBQyxnQkFBZ0IsQ0FDaEMsSUFBSSxDQUFDLGNBQWMsQ0FDcEIsQ0FBQztnQkFDSixDQUFDO2dCQUFDLE9BQU8sUUFBUSxFQUFFLENBQUM7b0JBQ2xCLE1BQU0sVUFBVSxHQUFHLFFBQThCLENBQUM7b0JBQ2xELElBQUksVUFBVSxDQUFDLElBQUksS0FBSyxFQUFFLEVBQUUsQ0FBQzt3QkFDM0IsTUFBTSxRQUFRLENBQUM7b0JBQ2pCLENBQUM7Z0JBQ0gsQ0FBQztnQkFDRCxNQUFNLENBQUMsR0FBRyxDQUFDLE1BQU0sRUFBRSxxQ0FBcUMsSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDLENBQUM7WUFDakYsQ0FBQztZQUNELGdCQUFnQixHQUFHLFdBQVcsQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxDQUFDO1FBQ2pFLENBQUM7UUFDRCxJQUNFLElBQUksQ0FBQyx3QkFBd0IsS0FBSyxhQUFhO2VBQzVDLElBQUksQ0FBQyxXQUFXLENBQUMsT0FBTyxLQUFLLFdBQVcsRUFDM0MsQ0FBQztZQUNELE9BQU87UUFDVCxDQUFDO1FBQ0QsSUFBSSxDQUFDLGlCQUFpQixHQUFHLGdCQUFnQixDQUFDO1FBQzFDLE1BQU0sV0FBVyxHQUFHLElBQUksQ0FBQyxXQUFXLENBQUM7UUFDckMsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDO1lBQ2pCLE9BQU87UUFDVCxDQUFDO1FBQ0QsS0FBSyxNQUFNLEtBQUssSUFBSSxXQUFXLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDeEMsTUFBTSxnQkFBZ0IsQ0FBQyxXQUFXLENBQ2hDLE1BQU0sQ0FBQyxXQUFXLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBdUMsRUFDbkU7Z0JBQ0UsR0FBRyxLQUFLLENBQUMsT0FBTztnQkFDaEIsSUFBSSxFQUFFLEtBQUssQ0FBQyxJQUFJO2FBQ2pCLENBQ0YsQ0FBQztRQUNKLENBQUM7UUFDRCxNQUFNLGFBQWEsR0FBRyxNQUFNLGdCQUFnQixDQUFDLFdBQVcsRUFBRSxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ3JFLEtBQUssTUFBTSxRQUFRLElBQUksV0FBVyxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQzNDLE1BQU0sTUFBTSxHQUFHLGFBQWEsQ0FBQyxJQUFJLENBQy9CLENBQUMsUUFBUSxFQUFFLEVBQUUsQ0FBQyxRQUFRLENBQUMsSUFBSSxLQUFLLFFBQVEsQ0FBQyxJQUFJLENBQzlDLENBQUM7WUFDRixJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7Z0JBQ1osTUFBTSxJQUFJLHlCQUF5QixDQUNqQyx1QkFBdUIsRUFDdkIsVUFBVSxRQUFRLENBQUMsSUFBSSx5QkFBeUIsSUFBSSxDQUFDLGNBQWMsSUFBSSxDQUN4RSxDQUFDO1lBQ0osQ0FBQztZQUNELE1BQU0sZ0JBQWdCLEdBQUcsTUFBTSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsR0FBRyxJQUFJLEVBQUUsQ0FBQyxDQUFDO1lBQzFELE1BQU0sa0JBQWtCLEdBQUcsUUFBUSxDQUFDLEdBQUc7aUJBQ3BDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxZQUFZLENBQUMsRUFBRSxFQUFFLENBQUMsWUFBWSxLQUFLLE1BQU0sQ0FBQztpQkFDckQsR0FBRyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsRUFBRSxFQUFFLENBQUMsUUFBUSxDQUFDLENBQUM7WUFDakMsTUFBTSxvQkFBb0IsR0FFdEIsRUFBRSxDQUFDO1lBQ1AsSUFBSSxlQUFlLEdBQUcsS0FBSyxDQUFDO1lBQzVCLEtBQUssTUFBTSxDQUFDLEtBQUssRUFBRSxTQUFTLENBQUMsSUFBSSxRQUFRLENBQUMsR0FBRyxFQUFFLENBQUM7Z0JBQzlDLElBQUksU0FBUyxLQUFLLE1BQU0sRUFBRSxDQUFDO29CQUN6QixJQUFJLENBQUMsZUFBZSxFQUFFLENBQUM7d0JBQ3JCLG9CQUFvQixDQUFDLElBQUksQ0FBQyxDQUFDLE1BQU0sRUFBRSxNQUFNLENBQUMsRUFBRSxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO3dCQUMxRCxlQUFlLEdBQUcsSUFBSSxDQUFDO29CQUN6QixDQUFDO2dCQUNILENBQUM7cUJBQU0sQ0FBQztvQkFDTixvQkFBb0IsQ0FBQyxJQUFJLENBQUMsQ0FBQyxLQUFLLEVBQUUsU0FBUyxDQUFDLENBQUMsQ0FBQztnQkFDaEQsQ0FBQztZQUNILENBQUM7WUFDRCxNQUFNLGdCQUFnQixHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLE9BQU8sSUFBSSxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQzdELCtCQUErQixDQUNoQyxDQUFDO1lBQ0YsSUFDRSxXQUFXLENBQUMsZ0JBQWdCLENBQUM7Z0JBQzNCLFdBQVcsQ0FBQyxvQkFBb0IsQ0FBQztnQkFDbkMsV0FBVyxDQUFDLGdCQUFnQixDQUFDO29CQUMzQixXQUFXLENBQ1QsQ0FBQyxHQUFHLGtCQUFrQixDQUFDLENBQUMsSUFBSSxDQUFDLCtCQUErQixDQUFDLENBQzlELEVBQ0gsQ0FBQztnQkFDRCxNQUFNLElBQUkseUJBQXlCLENBQ2pDLHVCQUF1QixFQUN2QixVQUFVLFFBQVEsQ0FBQyxJQUFJLHdDQUF3QyxDQUNoRSxDQUFDO1lBQ0osQ0FBQztZQUNELEtBQUssTUFBTSxhQUFhLElBQUksQ0FBQyxRQUFRLEVBQUUsUUFBUSxDQUFVLEVBQUUsQ0FBQztnQkFDMUQsSUFDRSxPQUFPLENBQUMsTUFBTSxDQUFDLGFBQWEsQ0FBQyxDQUFDO29CQUM5QixPQUFPLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxhQUFhLENBQUMsQ0FBQyxFQUN4QyxDQUFDO29CQUNELE1BQU0sSUFBSSx5QkFBeUIsQ0FDakMsdUJBQXVCLEVBQ3ZCLFVBQVUsUUFBUSxDQUFDLElBQUksd0JBQXdCLGFBQWEsV0FBVyxDQUN4RSxDQUFDO2dCQUNKLENBQUM7WUFDSCxDQUFDO1lBQ0QsSUFDRSxRQUFRLENBQUMsT0FBTyxDQUFDLGtCQUFrQixLQUFLLFNBQVM7Z0JBQ2pELE1BQU0sQ0FBQyxrQkFBa0I7b0JBQ3ZCLFFBQVEsQ0FBQyxPQUFPLENBQUMsa0JBQWtCLEVBQ3JDLENBQUM7Z0JBQ0QsTUFBTSxJQUFJLHlCQUF5QixDQUNqQyx1QkFBdUIsRUFDdkIsVUFBVSxRQUFRLENBQUMsSUFBSSxnREFBZ0QsQ0FDeEUsQ0FBQztZQUNKLENBQUM7UUFDSCxDQUFDO1FBQ0QsSUFDRSxJQUFJLENBQUMsd0JBQXdCLEtBQUssYUFBYTtlQUM1QyxJQUFJLENBQUMsV0FBVyxDQUFDLE9BQU8sS0FBSyxXQUFXO2VBQ3hDLElBQUksQ0FBQyxpQkFBaUIsS0FBSyxnQkFBZ0IsRUFDOUMsQ0FBQztZQUNELE9BQU87UUFDVCxDQUFDO1FBQ0QsSUFBSSxDQUFDLG1CQUFtQixDQUFDLFdBQVcsQ0FBQyxDQUFDO0lBQ3hDLENBQUM7SUFFTyxtQkFBbUIsQ0FBQyxXQUE2QztRQUN2RSxJQUFJLENBQUMsYUFBYSxHQUFHLFdBQVcsQ0FBQyxPQUFPO2FBQ3JDLE1BQU0sQ0FBQyxDQUFDLFFBQVEsRUFBRSxFQUFFLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUM7YUFDN0MsTUFBTSxDQUNMLENBQUMsUUFBUSxFQUFFLEVBQUUsQ0FDWCxRQUFRLENBQUMsR0FBRyxDQUFDLE1BQU0sS0FBSyxDQUFDLElBQUksUUFBUSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQ3hEO2FBQ0EsR0FBRyxDQUFDLENBQUMsUUFBUSxFQUFFLEVBQUUsQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDekMsSUFBSSxDQUFDLGNBQWMsR0FBRyxXQUFXLENBQUMsT0FBTzthQUN0QyxNQUFNLENBQ0wsQ0FBQyxRQUFRLEVBQUUsRUFBRSxDQUNYLFFBQVEsQ0FBQyxHQUFHLENBQUMsTUFBTSxLQUFLLENBQUM7WUFDekIsUUFBUSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQzNCO2FBQ0EsR0FBRyxDQUFDLENBQUMsUUFBUSxFQUFFLEVBQUUsQ0FBQyxDQUFDO1lBQ2xCLEtBQUssRUFBRSxRQUFRLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUN6QixPQUFPLEVBQUUsRUFBRSxHQUFHLFFBQVEsQ0FBQyxPQUFPLEVBQUU7U0FDakMsQ0FBQyxDQUFDLENBQUM7UUFDTixJQUFJLENBQUMsZUFBZSxHQUFHLFdBQVcsQ0FBQyxPQUFPO2FBQ3ZDLE1BQU0sQ0FDTCxDQUFDLFFBQVEsRUFBRSxFQUFFLENBQ1gsUUFBUSxDQUFDLEdBQUcsQ0FBQyxNQUFNLElBQUksQ0FBQztZQUN4QixRQUFRLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsRUFBRSxZQUFZLENBQUMsRUFBRSxFQUFFLENBQUMsWUFBWSxLQUFLLE1BQU0sQ0FBQyxDQUNwRTthQUNBLEdBQUcsQ0FBQyxDQUFDLFFBQVEsRUFBRSxFQUFFLENBQUMsQ0FBQztZQUNsQixJQUFJLEVBQUUsUUFBUSxDQUFDLElBQUk7WUFDbkIsR0FBRyxFQUFFLE1BQU0sQ0FBQyxXQUFXLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FHbkM7WUFDRCxPQUFPLEVBQUUsRUFBRSxHQUFHLFFBQVEsQ0FBQyxPQUFPLEVBQUU7U0FDakMsQ0FBQyxDQUFDLENBQUM7SUFDUixDQUFDO0lBRUQ7O09BRUc7SUFDSSxLQUFLLENBQUMsaUJBQWlCLENBQUMsY0FBd0IsRUFBRTtRQUN2RCxLQUFLLE1BQU0sR0FBRyxJQUFJLFdBQVcsRUFBRSxDQUFDO1lBQzlCLElBQUksQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO2dCQUN0QyxJQUFJLENBQUM7b0JBQ0gsTUFBTSxJQUFJLENBQUMsaUJBQWlCLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRTt3QkFDckQsTUFBTSxFQUFFLElBQUk7d0JBQ1osSUFBSSxFQUFFLEdBQUcsR0FBRyxJQUFJO3FCQUNqQixDQUFDLENBQUM7b0JBQ0gsSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7Z0JBQy9CLENBQUM7Z0JBQUMsT0FBTyxHQUFRLEVBQUUsQ0FBQztvQkFDbEIsTUFBTSxTQUFTLEdBQUcsR0FBRyxFQUFFLElBQUksSUFBSSxHQUFHLEVBQUUsUUFBUSxJQUFJLFNBQVMsQ0FBQztvQkFDMUQsTUFBTSxZQUFZLEdBQUcsR0FBRyxFQUFFLE9BQU8sSUFBSSxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUM7b0JBQ2pELE1BQU0sQ0FBQyxHQUFHLENBQ1IsT0FBTyxFQUNQLDJDQUEyQyxHQUFHLG9CQUFvQixJQUFJLENBQUMsY0FBYyxLQUFLO3dCQUMxRixrQkFBa0IsU0FBUyxNQUFNLFlBQVksSUFBSTt3QkFDakQsNkJBQTZCLEdBQUcsb0JBQW9CLENBQ3JELENBQUM7b0JBQ0YsSUFBSSxTQUFTLEtBQUssS0FBSyxJQUFJLFNBQVMsS0FBSyxjQUFjLElBQUksTUFBTSxDQUFDLFlBQVksQ0FBQyxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDO3dCQUNuRyxNQUFNLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxHQUFHLENBQUMsQ0FBQztvQkFDeEMsQ0FBQztvQkFDRCxNQUFNLEdBQUcsQ0FBQztnQkFDWixDQUFDO1lBQ0gsQ0FBQztRQUNILENBQUM7SUFDSCxDQUFDO0lBRUQ7O09BRUc7SUFDSSxLQUFLLENBQUMsb0JBQW9CLENBQUMsYUFBNkQsRUFBRTtRQUMvRixLQUFLLE1BQU0sUUFBUSxJQUFJLFVBQVUsRUFBRSxDQUFDO1lBQ2xDLDRDQUE0QztZQUM1QyxNQUFNLFFBQVEsR0FBRyxRQUFRLENBQUMsS0FBSyxDQUFDO1lBQ2hDLElBQUksQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxLQUFLLEtBQUssUUFBUSxDQUFDLEVBQUUsQ0FBQztnQkFDekQsSUFBSSxDQUFDO29CQUNILE1BQU0sSUFBSSxDQUFDLGlCQUFpQixDQUFDLFdBQVcsQ0FDdEMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSw0QkFBNEI7b0JBQ3JELFFBQVEsQ0FBQyxPQUFPLENBQ2pCLENBQUM7b0JBQ0YsSUFBSSxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7Z0JBQ3JDLENBQUM7Z0JBQUMsT0FBTyxHQUFRLEVBQUUsQ0FBQztvQkFDbEIsTUFBTSxTQUFTLEdBQUcsR0FBRyxFQUFFLElBQUksSUFBSSxHQUFHLEVBQUUsUUFBUSxJQUFJLFNBQVMsQ0FBQztvQkFDMUQsTUFBTSxZQUFZLEdBQUcsR0FBRyxFQUFFLE9BQU8sSUFBSSxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUM7b0JBQ2pELE1BQU0sQ0FBQyxHQUFHLENBQ1IsTUFBTSxFQUNOLG9DQUFvQyxRQUFRLG9CQUFvQixJQUFJLENBQUMsY0FBYyxLQUFLO3dCQUN4RixrQkFBa0IsU0FBUyxNQUFNLFlBQVksR0FBRyxDQUNqRCxDQUFDO29CQUNGLElBQ0UsUUFBUSxDQUFDLE9BQU8sRUFBRSxNQUFNO3dCQUN4QixDQUFDLFNBQVMsS0FBSyxLQUFLLElBQUksU0FBUyxLQUFLLGNBQWMsSUFBSSxNQUFNLENBQUMsWUFBWSxDQUFDLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxDQUFDLEVBQ2hHLENBQUM7d0JBQ0QsTUFBTSxJQUFJLENBQUMscUJBQXFCLENBQUMsUUFBUSxDQUFDLENBQUM7b0JBQzdDLENBQUM7b0JBQ0QsTUFBTSxHQUFHLENBQUM7Z0JBQ1osQ0FBQztZQUNILENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQztJQUVEOztPQUVHO0lBQ0ssS0FBSyxDQUFDLHFCQUFxQixDQUFDLEtBQWE7UUFDL0MsSUFBSSxDQUFDO1lBQ0gsTUFBTSxRQUFRLEdBQUc7Z0JBQ2YsRUFBRSxNQUFNLEVBQUUsRUFBRSxHQUFHLEVBQUUsSUFBSSxLQUFLLEVBQUUsRUFBRSxLQUFLLEVBQUUsRUFBRSxJQUFJLEVBQUUsQ0FBQyxFQUFFLEVBQUUsR0FBRyxFQUFFLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxFQUFFLEVBQUU7Z0JBQzVFLEVBQUUsTUFBTSxFQUFFLEVBQUUsS0FBSyxFQUFFLEVBQUUsR0FBRyxFQUFFLENBQUMsRUFBRSxFQUFFLEVBQUU7Z0JBQ2pDLEVBQUUsTUFBTSxFQUFFLENBQUMsRUFBRTthQUNkLENBQUM7WUFDRixNQUFNLFVBQVUsR0FBRyxNQUFNLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxTQUFTLENBQUMsUUFBUSxDQUFDLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDOUUsSUFBSSxVQUFVLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO2dCQUMxQixLQUFLLE1BQU0sR0FBRyxJQUFJLFVBQVUsRUFBRSxDQUFDO29CQUM3QixNQUFNLENBQUMsR0FBRyxDQUNSLE1BQU0sRUFDTix5QkFBeUIsS0FBSyxTQUFTLElBQUksQ0FBQyxjQUFjLEtBQUs7d0JBQy9ELFNBQVMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLFlBQVksR0FBRyxDQUFDLEtBQUssU0FBUzt3QkFDOUQsbUJBQW1CLElBQUksQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FDMUQsQ0FBQztnQkFDSixDQUFDO2dCQUNELE1BQU0sQ0FBQyxHQUFHLENBQ1IsTUFBTSxFQUNOLG9CQUFvQixLQUFLLFNBQVMsSUFBSSxDQUFDLGNBQWMscUJBQXFCO29CQUMxRSx1REFBdUQsQ0FDeEQsQ0FBQztZQUNKLENBQUM7UUFDSCxDQUFDO1FBQUMsT0FBTyxNQUFXLEVBQUUsQ0FBQztZQUNyQixNQUFNLENBQUMsR0FBRyxDQUNSLE1BQU0sRUFDTixxREFBcUQsS0FBSyxTQUFTLElBQUksQ0FBQyxjQUFjLE1BQU0sTUFBTSxFQUFFLE9BQU8sSUFBSSxNQUFNLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FDaEksQ0FBQztRQUNKLENBQUM7SUFDSCxDQUFDO0lBRUQ7O09BRUc7SUFDSSxnQkFBZ0IsQ0FBQyxPQUE4QjtRQUNwRCxJQUFJLENBQUMsZ0JBQWdCLEdBQUcsT0FBTyxDQUFDO0lBQ2xDLENBQUM7SUFFRDs7T0FFRztJQUNJLEtBQUssQ0FBQyxPQUFPLENBQ2xCLFlBQWlCLEVBQ2pCLElBSUM7UUFFRCxPQUFPLElBQUksQ0FBQyxzQkFBc0IsQ0FDaEMsSUFBSSxFQUFFLE9BQU8sRUFDYixLQUFLLEVBQ0wsS0FBSyxFQUFFLGFBQWEsRUFBRSxFQUFFO1lBQ3RCLE1BQU0sSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1lBQ2xCLE9BQU8sSUFBSSxDQUFDLGlCQUFpQixDQUFDLE9BQU8sQ0FBQyxZQUFZLEVBQUU7Z0JBQ2xELFVBQVUsRUFBRSxJQUFJLEVBQUUsVUFBVTtnQkFDNUIsU0FBUyxFQUFFLElBQUksRUFBRSxTQUFTO2dCQUMxQixPQUFPLEVBQUUsYUFBYTthQUN2QixDQUFDLENBQUM7UUFDTCxDQUFDLENBQ0YsQ0FBQztJQUNKLENBQUM7SUFFTSxLQUFLLENBQUMsU0FBUyxDQUNwQixlQUFvQixFQUNwQixRQUErQixFQUMvQixJQUFrRDtRQUVsRCxNQUFNLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUNsQixNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsaUJBQWlCLENBQUMsSUFBSSxDQUFDLGVBQWUsRUFBRSxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQztRQUN4RixPQUFPLElBQUksaUJBQWlCLENBQUMsTUFBTSxFQUFFLFFBQVEsQ0FBQyxDQUFDO0lBQ2pELENBQUM7SUFFRDs7T0FFRztJQUNJLEtBQUssQ0FBQyxPQUFPLENBQ2xCLFlBQWlCLEVBQ2pCLElBQThDO1FBRTlDLE9BQU8sSUFBSSxDQUFDLHNCQUFzQixDQUNoQyxJQUFJLEVBQUUsT0FBTyxFQUNiLEtBQUssRUFDTCxLQUFLLEVBQUUsYUFBYSxFQUFFLEVBQUU7WUFDdEIsTUFBTSxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDbEIsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLGlCQUFpQixDQUFDLElBQUksQ0FBQyxZQUFZLEVBQUU7Z0JBQ3ZELE9BQU8sRUFBRSxhQUFhO2FBQ3ZCLENBQUMsQ0FBQztZQUNILElBQUksTUFBYyxDQUFDO1lBQ25CLElBQUksZUFBZSxHQUFHLEtBQUssQ0FBQztZQUM1QixJQUFJLENBQUM7Z0JBQ0gsTUFBTSxHQUFHLE1BQU0sTUFBTSxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQ2xDLENBQUM7WUFBQyxPQUFPLFFBQVEsRUFBRSxDQUFDO2dCQUNsQixlQUFlLEdBQUcsSUFBSSxDQUFDO2dCQUN2QixNQUFNLFFBQVEsQ0FBQztZQUNqQixDQUFDO29CQUFTLENBQUM7Z0JBQ1QsSUFBSSxDQUFDO29CQUNILE1BQU0sTUFBTSxDQUFDLEtBQUssRUFBRSxDQUFDO2dCQUN2QixDQUFDO2dCQUFDLE9BQU8sVUFBVSxFQUFFLENBQUM7b0JBQ3BCLElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQzt3QkFDckIsTUFBTSxVQUFVLENBQUM7b0JBQ25CLENBQUM7Z0JBQ0gsQ0FBQztZQUNILENBQUM7WUFFRCxpRUFBaUU7WUFDakUsSUFBSSxNQUFNLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO2dCQUN0QixNQUFNLEtBQUssR0FBRyxJQUFJLEdBQUcsRUFBVSxDQUFDO2dCQUNoQyxNQUFNLFlBQVksR0FBYSxFQUFFLENBQUM7Z0JBQ2xDLEtBQUssTUFBTSxHQUFHLElBQUksTUFBTSxFQUFFLENBQUM7b0JBQ3pCLE1BQU0sS0FBSyxHQUFHLE1BQU0sQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUM7b0JBQzlCLElBQUksS0FBSyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO3dCQUNyQixZQUFZLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO29CQUMzQixDQUFDO3lCQUFNLENBQUM7d0JBQ04sS0FBSyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQztvQkFDbkIsQ0FBQztnQkFDSCxDQUFDO2dCQUNELElBQUksWUFBWSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztvQkFDNUIsTUFBTSxDQUFDLEdBQUcsQ0FDUixPQUFPLEVBQ1AsdUJBQXVCLElBQUksQ0FBQyxjQUFjLFlBQVksWUFBWSxDQUFDLE1BQU0sd0JBQXdCO3dCQUNqRyx3QkFBd0IsWUFBWSxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyw4QkFBOEIsQ0FDMUYsQ0FBQztnQkFDSixDQUFDO1lBQ0gsQ0FBQztZQUVELE9BQU8sTUFBTSxDQUFDO1FBQ2hCLENBQUMsQ0FDRixDQUFDO0lBQ0osQ0FBQztJQUVEOzs7OztPQUtHO0lBQ0ksS0FBSyxDQUFDLEtBQUssQ0FDaEIsWUFBaUIsRUFDakIsT0FBMEUsRUFBRSxFQUM1RSxpQkFBeUM7UUFFekMsSUFBSSxjQUFjLElBQUksSUFBSSxDQUFDLFdBQVc7WUFDbkMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxZQUEyQyxDQUFDLGFBQWEsS0FBSyxhQUFhLEVBQUUsQ0FBQztZQUNoRyxNQUFNLElBQUksbUJBQW1CLENBQUMsd0JBQXdCLEVBQUUsaURBQWlELENBQUMsQ0FBQztRQUM3RyxDQUFDO1FBQ0QsTUFBTSxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDbEIsb0NBQW9DO1FBQ3BDLE1BQU0sRUFBRSxZQUFZLEVBQUUsWUFBWSxFQUFFLEdBQUcsWUFBWSxFQUFFLEdBQUcsSUFBSSxJQUFJLEVBQUUsQ0FBQztRQUNuRSw2REFBNkQ7UUFDN0QsTUFBTSxtQkFBbUIsR0FBd0M7WUFDL0QsR0FBRyxZQUFZO1lBQ2YsWUFBWSxFQUNWLFlBQVksS0FBSyxTQUFTO2dCQUN4QixDQUFDLENBQUMsY0FBYztnQkFDaEIsQ0FBQyxDQUFFLFlBQW9CLEtBQUssSUFBSTtvQkFDaEMsQ0FBQyxDQUFDLGNBQWM7b0JBQ2hCLENBQUMsQ0FBQyxZQUFZO1NBQ1osQ0FBQztRQUNULHdDQUF3QztRQUN4QyxNQUFNLFFBQVEsR0FBRyxZQUFZLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxNQUFNLEVBQUUsWUFBWSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO1FBQ2hFLE1BQU0sWUFBWSxHQUFHLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxLQUFLLENBQy9DLFFBQVEsRUFDUixtQkFBbUIsQ0FDcEIsQ0FBQztRQUNGLE1BQU0sZ0JBQWdCLEdBQUcsSUFBSSxrQkFBa0IsQ0FDN0MsWUFBWSxFQUNaLGlCQUFrQixFQUNsQixFQUFFLFlBQVksRUFBRSxDQUNqQixDQUFDO1FBQ0YsTUFBTSxnQkFBZ0IsQ0FBQyxhQUFhLENBQUMsT0FBTyxDQUFDO1FBQzdDLE9BQU8sZ0JBQWdCLENBQUM7SUFDMUIsQ0FBQztJQUVEOztPQUVHO0lBQ0sscUJBQXFCLENBQUMsV0FBZ0I7UUFDNUMsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLFdBQVcsRUFBRSxtQkFBbUIsQ0FBQztRQUNyRCxJQUFJLENBQUMsTUFBTTtZQUFFLE9BQU8sV0FBVyxDQUFDO1FBQ2hDLElBQUksTUFBTSxDQUFDLE1BQU0sS0FBSyxVQUFVLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsV0FBVyxFQUFFLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDOUYsV0FBVyxHQUFHLEVBQUUsR0FBRyxXQUFXLEVBQUUsR0FBRyxFQUFFLElBQUksT0FBTyxDQUFDLE9BQU8sQ0FBQyxRQUFRLEVBQUUsRUFBRSxDQUFDO1FBQ3hFLENBQUM7UUFDRCxPQUFPLDhCQUE4QixDQUFDLFdBQVcsRUFBRSxNQUFNLEVBQUUsSUFBSSxDQUFDLFdBQVksQ0FBQyxlQUFlLENBQUMsQ0FBQztJQUNoRyxDQUFDO0lBRU0sS0FBSyxDQUFDLE1BQU0sQ0FDakIsUUFBd0MsRUFDeEMsSUFBOEM7UUFFOUMsTUFBTSxjQUFjLEdBQUcsSUFBSSxDQUFDLFdBQVcsRUFBRSxtQkFBbUI7WUFDMUQsQ0FBQyxDQUFDLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxNQUFNLFFBQVEsQ0FBQyxtQkFBbUIsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQztRQUNqRixPQUFPLElBQUksQ0FBQyxzQkFBc0IsQ0FDaEMsSUFBSSxFQUFFLE9BQU8sRUFDYixJQUFJLEVBQ0osS0FBSyxFQUFFLGFBQWEsRUFBRSxFQUFFO1lBQ3RCLE1BQU0sSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1lBQ2xCLE1BQU0sSUFBSSxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsQ0FBQztZQUM5QixNQUFNLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxRQUFRLENBQUMsYUFBYSxDQUFDLENBQUM7WUFFckQsc0NBQXNDO1lBQ3RDLElBQUksUUFBUSxDQUFDLGNBQWMsSUFBSSxRQUFRLENBQUMsY0FBYyxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztnQkFDbEUsTUFBTSxJQUFJLENBQUMsb0JBQW9CLENBQUMsUUFBUSxDQUFDLGNBQWMsQ0FBQyxDQUFDO1lBQzNELENBQUM7WUFFRCxNQUFNLGNBQWMsR0FBRyxjQUFjLElBQUksTUFBTSxRQUFRLENBQUMsbUJBQW1CLEVBQUUsQ0FBQztZQUM5RSxJQUFJLENBQUM7Z0JBQ0gsT0FBTyxNQUFNLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxTQUFTLENBQUMsY0FBYyxFQUFFO29CQUM1RCxPQUFPLEVBQUUsYUFBYTtpQkFDdkIsQ0FBQyxDQUFDO1lBQ0wsQ0FBQztZQUFDLE9BQU8sR0FBUSxFQUFFLENBQUM7Z0JBQ2xCLE9BQU8saUNBQWlDLENBQ3RDLEdBQUcsRUFDSCx1REFBdUQsSUFBSSxDQUFDLGNBQWMsSUFBSSxDQUMvRSxDQUFDO1lBQ0osQ0FBQztRQUNILENBQUMsQ0FDRixDQUFDO0lBQ0osQ0FBQztJQUVEOzs7OztPQUtHO0lBQ0ksS0FBSyxDQUFDLHNCQUFzQixDQUNqQyxRQUFzRSxFQUN0RSxRQUFrQyxFQUNsQyxRQUFnQixFQUNoQixJQUE0RztRQUU1RyxJQUFJLEVBQUUsTUFBTSxFQUFFLGNBQWMsRUFBRSxDQUFDO1FBQy9CLE9BQU8sSUFBSSxDQUFDLHNCQUFzQixDQUNoQyxJQUFJLEVBQUUsT0FBTyxFQUNiLEtBQUssRUFDTCxLQUFLLEVBQUUsYUFBYSxFQUFFLEVBQUU7WUFDdEIsTUFBTSxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDbEIsTUFBTSxRQUFRLEdBQStCLEVBQUUsQ0FBQztZQUNoRCxJQUFJLFFBQVEsSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztnQkFDakQsUUFBUSxDQUFDLElBQUksQ0FBQyxFQUFFLE1BQU0sRUFBRSxRQUFRLEVBQUUsQ0FBQyxDQUFDO1lBQ3RDLENBQUM7WUFDRCxRQUFRLENBQUMsSUFBSSxDQUFDLEVBQUUsTUFBTSxFQUFFLFFBQVEsRUFBRSxDQUFDLENBQUM7WUFDcEMsUUFBUSxDQUFDLElBQUksQ0FBQyxFQUFFLE1BQU0sRUFBRSxRQUFRLEVBQUUsQ0FBQyxDQUFDO1lBQ3BDLElBQUksRUFBRSxNQUFNLEVBQUUsY0FBYyxFQUFFLENBQUM7WUFDL0IsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLGlCQUFpQixDQUFDLFNBQVMsQ0FBQyxRQUFRLEVBQUU7Z0JBQ3hELE9BQU8sRUFBRSxhQUFhO2dCQUN0QixHQUFHLENBQUMsSUFBSSxFQUFFLFNBQVMsS0FBSyxTQUFTLENBQUMsQ0FBQyxDQUFDLEVBQUUsU0FBUyxFQUFFLElBQUksQ0FBQyxTQUFTLEVBQUUsV0FBVyxFQUFFLGdCQUFnQixFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztnQkFDdEcsTUFBTSxFQUFFLElBQUksRUFBRSxNQUFNO2dCQUNwQixHQUFHLENBQUMsSUFBSSxFQUFFLFNBQVMsS0FBSyxTQUFTO29CQUMvQixDQUFDLENBQUMsRUFBRSxTQUFTLEVBQUUsSUFBSSxDQUFDLFNBQVMsRUFBRTtvQkFDL0IsQ0FBQyxDQUFDLEVBQUUsQ0FBQzthQUNSLENBQUMsQ0FBQztZQUNILE9BQU8sa0JBQWtCLENBQUMsTUFBTSxFQUFFLENBQUMsU0FBUyxFQUFFLEVBQUUsQ0FBQyxTQUFTLENBQUMsT0FBTyxFQUFFLEVBQUUsSUFBSSxFQUFFLE1BQU0sQ0FBQyxDQUFDO1FBQ3RGLENBQUMsQ0FDRixDQUFDO0lBQ0osQ0FBQztJQUVNLEtBQUssQ0FBQyxVQUFVLENBQ3JCLFNBQWdELEVBQ2hELElBQWlFO1FBRWpFLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxJQUFJLFNBQVMsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDeEQsTUFBTSxJQUFJLHlCQUF5QixDQUNqQyxrQkFBa0IsRUFDbEIsa0VBQWtFLElBQUksQ0FBQyxjQUFjLElBQUksQ0FDMUYsQ0FBQztRQUNKLENBQUM7UUFDRCxNQUFNLGVBQWUsR0FBc0IsSUFBSSxDQUFDLFdBQVcsRUFBRSxtQkFBbUIsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7UUFDbEcsSUFBSSxlQUFlLEVBQUUsQ0FBQztZQUNwQixLQUFLLE1BQU0sUUFBUSxJQUFJLFNBQVMsRUFBRSxDQUFDO2dCQUNqQyxlQUFlLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxNQUFNLFFBQVEsQ0FBQyxtQkFBbUIsRUFBRSxDQUFDLENBQUMsQ0FBQztZQUN6RixDQUFDO1FBQ0gsQ0FBQztRQUNELE9BQU8sSUFBSSxDQUFDLHNCQUFzQixDQUNoQyxJQUFJLEVBQUUsT0FBTyxFQUNiLElBQUksRUFDSixLQUFLLEVBQUUsYUFBYSxFQUFFLEVBQUU7WUFDdEIsTUFBTSxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDbEIsS0FBSyxNQUFNLFFBQVEsSUFBSSxTQUFTLEVBQUUsQ0FBQztnQkFDakMsTUFBTSxJQUFJLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1lBQ2hDLENBQUM7WUFDRCxNQUFNLGFBQWEsR0FBRyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDbkMsTUFBTSxJQUFJLENBQUMsaUJBQWlCLENBQUMsYUFBYSxDQUFDLGFBQWEsQ0FBQyxDQUFDO1lBQzFELElBQ0UsYUFBYSxDQUFDLGNBQWM7bUJBQ3pCLGFBQWEsQ0FBQyxjQUFjLENBQUMsTUFBTSxHQUFHLENBQUMsRUFDMUMsQ0FBQztnQkFDRCxNQUFNLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxhQUFhLENBQUMsY0FBYyxDQUFDLENBQUM7WUFDaEUsQ0FBQztZQUNELE1BQU0sZUFBZSxHQUFVLGVBQWUsSUFBSSxFQUFFLENBQUM7WUFDckQsSUFBSSxDQUFDLGVBQWUsRUFBRSxDQUFDO2dCQUNyQixLQUFLLE1BQU0sUUFBUSxJQUFJLFNBQVMsRUFBRSxDQUFDO29CQUNqQyxlQUFlLENBQUMsSUFBSSxDQUFDLE1BQU0sUUFBUSxDQUFDLG1CQUFtQixFQUFFLENBQUMsQ0FBQztnQkFDN0QsQ0FBQztZQUNILENBQUM7WUFDRCxJQUFJLENBQUM7Z0JBQ0gsT0FBTyxNQUFNLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxVQUFVLENBQUMsZUFBZSxFQUFFO29CQUM5RCxPQUFPLEVBQUUsYUFBYTtvQkFDdEIsT0FBTyxFQUFFLElBQUksRUFBRSxPQUFPLEtBQUssS0FBSztpQkFDakMsQ0FBQyxDQUFDO1lBQ0wsQ0FBQztZQUFDLE9BQU8sR0FBUSxFQUFFLENBQUM7Z0JBQ2xCLE9BQU8saUNBQWlDLENBQ3RDLEdBQUcsRUFDSCx1REFBdUQsSUFBSSxDQUFDLGNBQWMsSUFBSSxDQUMvRSxDQUFDO1lBQ0osQ0FBQztRQUNILENBQUMsQ0FDRixDQUFDO0lBQ0osQ0FBQztJQUVELDBFQUEwRTtJQUNuRSxLQUFLLENBQUMsa0JBQWtCLENBQzdCLFlBQW1ELEVBQ25ELGdCQUF3QixFQUN4QixPQUFvRTtRQUVwRSxNQUFNLFFBQVEsR0FBK0IsRUFBRSxDQUFDO1FBQ2hELElBQUksS0FBSyxHQUFHLENBQUMsQ0FBQztRQUNkLHVFQUF1RTtRQUN2RSxtRUFBbUU7UUFDbkUsS0FBSyxNQUFNLFFBQVEsSUFBSSxZQUFZLEVBQUUsQ0FBQztZQUNwQyxNQUFNLElBQUksQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLENBQUM7WUFDOUIsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLHFCQUFxQixDQUFDLE1BQU0sUUFBUSxDQUFDLG1CQUFtQixFQUFFLENBQUMsQ0FBQztZQUNoRixNQUFNLElBQUksR0FBRyxPQUFPLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLENBQUM7WUFDcEQsS0FBSyxJQUFJLElBQUksQ0FBQyxVQUFVLENBQUM7WUFDekIsSUFBSSxLQUFLLEdBQUcsRUFBRSxHQUFHLElBQUksR0FBRyxJQUFJLEVBQUUsQ0FBQztnQkFDN0IsTUFBTSxJQUFJLHlCQUF5QixDQUFDLGtCQUFrQixFQUNwRCxvRUFBb0UsQ0FBQyxDQUFDO1lBQzFFLENBQUM7WUFDRCxRQUFRLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO1FBQ3hELENBQUM7UUFDRCxPQUFPLElBQUksQ0FBQyxzQkFBc0IsQ0FBQyxPQUFPLENBQUMsT0FBTyxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsYUFBYSxFQUFFLEVBQUU7WUFDaEYsTUFBTSxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDbEIsTUFBTSxLQUFLLEdBQUcsWUFBWSxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQzlCLE1BQU0sSUFBSSxDQUFDLGlCQUFpQixDQUFDLEtBQUssQ0FBQyxhQUFhLENBQUMsQ0FBQztZQUNsRCxNQUFNLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxLQUFLLENBQUMsY0FBYyxJQUFJLEVBQUUsQ0FBQyxDQUFDO1lBQzVELElBQUksQ0FBQztnQkFDSCxNQUFNLE1BQU0sR0FBRyxNQUFNLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxTQUFTLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxDQUFDLFFBQVEsRUFBRSxFQUFFLENBQUMsQ0FBQztvQkFDaEYsU0FBUyxFQUFFO3dCQUNULE1BQU0sRUFBRSxFQUFFLENBQUMsZ0JBQWdCLENBQUMsRUFBRSxRQUFRLENBQUMsZ0JBQWdCLENBQUMsRUFBRTt3QkFDMUQsTUFBTSxFQUFFLEVBQUUsWUFBWSxFQUFFLFFBQVEsRUFBRTt3QkFDbEMsTUFBTSxFQUFFLElBQUk7cUJBQ2I7aUJBQ0YsQ0FBQyxDQUFDLEVBQUUsRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRSxhQUFhLEVBQUUsU0FBUyxFQUFFLE9BQU8sQ0FBQyxTQUFTLEVBQUUsQ0FBQyxDQUFDO2dCQUMvRSxJQUFJLE1BQU0sQ0FBQyxhQUFhLEdBQUcsTUFBTSxDQUFDLFlBQVksS0FBSyxRQUFRLENBQUMsTUFBTSxFQUFFLENBQUM7b0JBQ25FLE1BQU0sSUFBSSx5QkFBeUIsQ0FBQyx1QkFBdUIsRUFDekQsd0VBQXdFLENBQUMsQ0FBQztnQkFDOUUsQ0FBQztnQkFDRCxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sQ0FBQyxhQUFhLEVBQUUsWUFBWSxFQUFFLE1BQU0sQ0FBQyxZQUFZLEVBQUUsQ0FBQztZQUNwRixDQUFDO1lBQUMsT0FBTyxRQUFRLEVBQUUsQ0FBQztnQkFDbEIsT0FBTyxpQ0FBaUMsQ0FBQyxRQUFRLEVBQy9DLHVEQUF1RCxJQUFJLENBQUMsY0FBYyxJQUFJLENBQUMsQ0FBQztZQUNwRixDQUFDO1FBQ0gsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQ7O09BRUc7SUFDSSxLQUFLLENBQUMsTUFBTSxDQUNqQixRQUF3QyxFQUN4QyxJQUE4QztRQUU5QyxJQUFJLElBQUksQ0FBQyxXQUFXLEVBQUUsbUJBQW1CLEVBQUUsQ0FBQztZQUMxQyxNQUFNLElBQUkseUJBQXlCLENBQUMsdUJBQXVCLEVBQ3pELHFFQUFxRSxDQUFDLENBQUM7UUFDM0UsQ0FBQztRQUNELE9BQU8sSUFBSSxDQUFDLHNCQUFzQixDQUNoQyxJQUFJLEVBQUUsT0FBTyxFQUNiLElBQUksRUFDSixLQUFLLEVBQUUsYUFBYSxFQUFFLEVBQUU7WUFDdEIsTUFBTSxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDbEIsTUFBTSxJQUFJLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1lBQzlCLE1BQU0sSUFBSSxDQUFDLGlCQUFpQixDQUFDLFFBQVEsQ0FBQyxhQUFhLENBQUMsQ0FBQztZQUNyRCxJQUFJLFFBQVEsQ0FBQyxjQUFjLElBQUksUUFBUSxDQUFDLGNBQWMsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7Z0JBQ2xFLE1BQU0sSUFBSSxDQUFDLG9CQUFvQixDQUFDLFFBQVEsQ0FBQyxjQUFjLENBQUMsQ0FBQztZQUMzRCxDQUFDO1lBQ0QsTUFBTSxrQkFBa0IsR0FBRyxNQUFNLFFBQVEsQ0FBQyx3QkFBd0IsRUFBRSxDQUFDO1lBQ3JFLElBQUksQ0FBQyxvQ0FBb0MsQ0FBQyxrQkFBa0IsRUFBRSxRQUFRLENBQUMsQ0FBQztZQUN4RSxNQUFNLGNBQWMsR0FBRyxNQUFNLFFBQVEsQ0FBQyxtQkFBbUIsRUFBUyxDQUFDO1lBQ25FLE1BQU0sZ0JBQWdCLEdBQVEsRUFBRSxDQUFDO1lBQ2pDLEtBQUssTUFBTSxHQUFHLElBQUksTUFBTSxDQUFDLElBQUksQ0FBQyxjQUFjLENBQUMsRUFBRSxDQUFDO2dCQUM5QyxJQUFJLGtCQUFrQixDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7b0JBQzVCLFNBQVM7Z0JBQ1gsQ0FBQztnQkFDRCxnQkFBZ0IsQ0FBQyxHQUFHLENBQUMsR0FBRyxjQUFjLENBQUMsR0FBRyxDQUFDLENBQUM7WUFDOUMsQ0FBQztZQUNELElBQUksQ0FBQztnQkFDSCxPQUFPLE1BQU0sSUFBSSxDQUFDLGlCQUFpQixDQUFDLFNBQVMsQ0FDM0Msa0JBQWtCLEVBQ2xCLEVBQUUsSUFBSSxFQUFFLGdCQUFnQixFQUFFLEVBQzFCLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsYUFBYSxFQUFFLENBQ3pDLENBQUM7WUFDSixDQUFDO1lBQUMsT0FBTyxRQUFRLEVBQUUsQ0FBQztnQkFDbEIsT0FBTyxpQ0FBaUMsQ0FDdEMsUUFBUSxFQUNSLHVEQUF1RCxJQUFJLENBQUMsY0FBYyxJQUFJLENBQy9FLENBQUM7WUFDSixDQUFDO1FBQ0gsQ0FBQyxDQUNGLENBQUM7SUFDSixDQUFDO0lBRU0sS0FBSyxDQUFDLE1BQU0sQ0FDakIsUUFBd0MsRUFDeEMsSUFBOEM7UUFFOUMsT0FBTyxJQUFJLENBQUMsc0JBQXNCLENBQ2hDLElBQUksRUFBRSxPQUFPLEVBQ2IsSUFBSSxFQUNKLEtBQUssRUFBRSxhQUFhLEVBQUUsRUFBRTtZQUN0QixNQUFNLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUNsQixNQUFNLElBQUksQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLENBQUM7WUFDOUIsTUFBTSxrQkFBa0IsR0FBRyxNQUFNLFFBQVEsQ0FBQyx3QkFBd0IsRUFBRSxDQUFDO1lBQ3JFLElBQUksQ0FBQyxvQ0FBb0MsQ0FBQyxrQkFBa0IsRUFBRSxRQUFRLENBQUMsQ0FBQztZQUN4RSxPQUFPLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxTQUFTLENBQUMsa0JBQWtCLEVBQUU7Z0JBQzFELE9BQU8sRUFBRSxhQUFhO2FBQ3ZCLENBQUMsQ0FBQztRQUNMLENBQUMsQ0FDRixDQUFDO0lBQ0osQ0FBQztJQUVEOzs7O09BSUc7SUFDSyxvQ0FBb0MsQ0FDMUMscUJBQThDLEVBQzlDLGlCQUF5QjtRQUV6QixJQUFJLE1BQU0sQ0FBQyxJQUFJLENBQUMscUJBQXFCLENBQUMsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDcEQsTUFBTSxJQUFJLHlCQUF5QixDQUNqQyx1QkFBdUIsRUFDdkIsWUFBWSxpQkFBaUIsbUJBQW1CLElBQUksQ0FBQyxjQUFjLHFHQUFxRyxDQUN6SyxDQUFDO1FBQ0osQ0FBQztJQUNILENBQUM7SUFFTSxLQUFLLENBQUMsUUFBUSxDQUNuQixZQUFpQixFQUNqQixJQU9DO1FBRUQsSUFBSSxJQUFJLEVBQUUsSUFBSSxLQUFLLFNBQVMsSUFBSSxDQUM5QixPQUFPLElBQUksQ0FBQyxJQUFJLEtBQUssUUFBUTtZQUM3QixDQUFDLElBQUksQ0FBQyxJQUFJLEtBQUssTUFBTSxJQUFJLENBQUMsSUFBSSxDQUFDLFdBQVcsRUFBRSxPQUFPLENBQUMsSUFBSSxDQUN0RCxDQUFDLFFBQVEsRUFBRSxFQUFFLENBQUMsUUFBUSxDQUFDLElBQUksS0FBSyxJQUFJLENBQUMsSUFBSSxDQUMxQyxDQUFDLENBQ0gsRUFBRSxDQUFDO1lBQ0YsTUFBTSxJQUFJLHlCQUF5QixDQUNqQyxrQkFBa0IsRUFDbEIsa0ZBQWtGLENBQ25GLENBQUM7UUFDSixDQUFDO1FBQ0QsT0FBTyxJQUFJLENBQUMsc0JBQXNCLENBQ2hDLElBQUksRUFBRSxPQUFPLEVBQ2IsS0FBSyxFQUNMLEtBQUssRUFBRSxhQUFhLEVBQUUsRUFBRTtZQUN0QixNQUFNLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUNsQixJQUFJLEVBQUUsTUFBTSxFQUFFLGNBQWMsRUFBRSxDQUFDO1lBQy9CLE1BQU0sUUFBUSxHQUErQixDQUFDLEVBQUUsTUFBTSxFQUFFLFlBQVksRUFBRSxDQUFDLENBQUM7WUFDeEUsSUFBSSxJQUFJLEVBQUUsS0FBSyxLQUFLLFNBQVMsRUFBRSxDQUFDO2dCQUM5QixRQUFRLENBQUMsSUFBSSxDQUFDLEVBQUUsTUFBTSxFQUFFLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFDO1lBQ3hDLENBQUM7WUFDRCxRQUFRLENBQUMsSUFBSSxDQUFDLEVBQUUsTUFBTSxFQUFFLE9BQU8sRUFBRSxDQUFDLENBQUM7WUFDbkMsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLGlCQUFpQixDQUFDLFNBQVMsQ0FBb0IsUUFBUSxFQUFFO2dCQUMzRSxJQUFJLEVBQUUsSUFBSSxFQUFFLElBQUk7Z0JBQ2hCLFNBQVMsRUFBRSxJQUFJLEVBQUUsU0FBUztnQkFDMUIsU0FBUyxFQUFFLElBQUksRUFBRSxTQUFTO2dCQUMxQixNQUFNLEVBQUUsSUFBSSxFQUFFLE1BQU07Z0JBQ3BCLE9BQU8sRUFBRSxhQUFhO2FBQ3ZCLENBQUMsQ0FBQztZQUNILE9BQU8sa0JBQWtCLENBQUMsTUFBTSxFQUFFLEtBQUssRUFBRSxTQUFTLEVBQUUsRUFBRSxDQUNwRCxDQUFDLE1BQU0sU0FBUyxDQUFDLElBQUksRUFBRSxDQUFDLEVBQUUsS0FBSyxJQUFJLENBQUMsRUFDdEMsSUFBSSxFQUFFLE1BQU0sQ0FBQyxDQUFDO1FBQ2hCLENBQUMsQ0FDRixDQUFDO0lBQ0osQ0FBQztJQUVNLEtBQUssQ0FBQyxZQUFZO1FBQ3ZCLE1BQU0sSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQ2xCLE1BQU0sT0FBTyxHQUFHLE1BQU0sSUFBSSxDQUFDLGlCQUFpQixDQUFDLFdBQVcsRUFBRSxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ3JFLE9BQU8sT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLFFBQVEsRUFBRSxFQUFFO1lBQzlCLElBQUksTUFBcUMsQ0FBQztZQUMxQyxJQUFJLFFBQVEsQ0FBQyxHQUFHLENBQUMsSUFBSSxLQUFLLE1BQU0sRUFBRSxDQUFDO2dCQUNqQyxNQUFNLE9BQU8sR0FDWCxPQUFPLFFBQVEsQ0FBQyxPQUFPLEtBQUssUUFBUTtvQkFDcEMsUUFBUSxDQUFDLE9BQU8sS0FBSyxJQUFJO29CQUN6QixDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQztvQkFDOUIsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxPQUFPO29CQUNsQixDQUFDLENBQUMsRUFBRSxDQUFDO2dCQUNULE1BQU0sR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsQ0FBQztvQkFDM0MsSUFBSTtvQkFDSixTQUFTLEVBQUUsTUFBZTtpQkFDM0IsQ0FBQyxDQUFDLENBQUM7WUFDTixDQUFDO2lCQUFNLENBQUM7Z0JBQ04sTUFBTSxHQUFHLE1BQU0sQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsSUFBSSxFQUFFLFNBQVMsQ0FBQyxFQUFFLEVBQUU7b0JBQzlELElBQUksU0FBUyxLQUFLLENBQUMsSUFBSSxTQUFTLEtBQUssQ0FBQyxDQUFDLEVBQUUsQ0FBQzt3QkFDeEMsTUFBTSxJQUFJLHlCQUF5QixDQUNqQyx1QkFBdUIsRUFDdkIsVUFBVSxRQUFRLENBQUMsSUFBSSxrQ0FBa0MsQ0FDMUQsQ0FBQztvQkFDSixDQUFDO29CQUNELE9BQU87d0JBQ0wsSUFBSTt3QkFDSixTQUFTO3FCQUNWLENBQUM7Z0JBQ0osQ0FBQyxDQUFDLENBQUM7WUFDTCxDQUFDO1lBQ0QsT0FBTztnQkFDTCxJQUFJLEVBQUUsUUFBUSxDQUFDLElBQUk7Z0JBQ25CLE1BQU07Z0JBQ04sTUFBTSxFQUFFLFFBQVEsQ0FBQyxNQUFNLEtBQUssSUFBSTtnQkFDaEMsTUFBTSxFQUFFLFFBQVEsQ0FBQyxNQUFNLEtBQUssSUFBSTtnQkFDaEMsa0JBQWtCLEVBQ2hCLE9BQU8sUUFBUSxDQUFDLGtCQUFrQixLQUFLLFFBQVE7b0JBQzdDLENBQUMsQ0FBQyxRQUFRLENBQUMsa0JBQWtCO29CQUM3QixDQUFDLENBQUMsU0FBUzthQUNoQixDQUFDO1FBQ0osQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQ7OztPQUdHO0lBQ0ksS0FBSyxDQUFDLHdCQUF3QjtRQU1uQyxNQUFNLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUNsQixNQUFNLE1BQU0sR0FBRztZQUNiLEVBQUUsRUFBRSxJQUFJO1lBQ1IsY0FBYyxFQUFFLENBQUM7WUFDakIsV0FBVyxFQUFFLENBQUM7WUFDZCxlQUFlLEVBQUUsRUFBdUQ7U0FDekUsQ0FBQztRQUVGLElBQUksQ0FBQztZQUNILE1BQU0sQ0FBQyxjQUFjLEdBQUcsTUFBTSxJQUFJLENBQUMsaUJBQWlCLENBQUMsc0JBQXNCLEVBQUUsQ0FBQztZQUM5RSxNQUFNLENBQUMsV0FBVyxHQUFHLE1BQU0sSUFBSSxDQUFDLGlCQUFpQixDQUFDLGNBQWMsQ0FBQyxFQUFFLENBQUMsQ0FBQztZQUVyRSxJQUFJLE1BQU0sQ0FBQyxjQUFjLEtBQUssTUFBTSxDQUFDLFdBQVcsRUFBRSxDQUFDO2dCQUNqRCxNQUFNLENBQUMsRUFBRSxHQUFHLEtBQUssQ0FBQztnQkFDbEIsTUFBTSxDQUFDLEdBQUcsQ0FDUixNQUFNLEVBQ04sdUJBQXVCLElBQUksQ0FBQyxjQUFjLDZCQUE2QixNQUFNLENBQUMsY0FBYyxHQUFHO29CQUMvRixzQkFBc0IsTUFBTSxDQUFDLFdBQVcsZ0NBQWdDLENBQ3pFLENBQUM7WUFDSixDQUFDO1lBRUQsMERBQTBEO1lBQzFELEtBQUssTUFBTSxLQUFLLElBQUksSUFBSSxDQUFDLGFBQWEsRUFBRSxDQUFDO2dCQUN2QyxJQUFJLENBQUM7b0JBQ0gsTUFBTSxRQUFRLEdBQUc7d0JBQ2YsRUFBRSxNQUFNLEVBQUUsRUFBRSxHQUFHLEVBQUUsSUFBSSxLQUFLLEVBQUUsRUFBRSxLQUFLLEVBQUUsRUFBRSxJQUFJLEVBQUUsQ0FBQyxFQUFFLEVBQUUsRUFBRTt3QkFDcEQsRUFBRSxNQUFNLEVBQUUsRUFBRSxLQUFLLEVBQUUsRUFBRSxHQUFHLEVBQUUsQ0FBQyxFQUFFLEVBQUUsRUFBRTt3QkFDakMsRUFBRSxNQUFNLEVBQUUsT0FBTyxFQUFFO3FCQUNwQixDQUFDO29CQUNGLE1BQU0sV0FBVyxHQUFHLE1BQU0sSUFBSSxDQUFDLGlCQUFpQixDQUFDLFNBQVMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxPQUFPLEVBQUUsQ0FBQztvQkFDL0UsTUFBTSxRQUFRLEdBQUcsV0FBVyxDQUFDLENBQUMsQ0FBQyxFQUFFLEtBQUssSUFBSSxDQUFDLENBQUM7b0JBQzVDLElBQUksUUFBUSxHQUFHLENBQUMsRUFBRSxDQUFDO3dCQUNqQixNQUFNLENBQUMsRUFBRSxHQUFHLEtBQUssQ0FBQzt3QkFDbEIsTUFBTSxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsRUFBRSxLQUFLLEVBQUUsZUFBZSxFQUFFLFFBQVEsRUFBRSxDQUFDLENBQUM7d0JBQ2xFLE1BQU0sQ0FBQyxHQUFHLENBQ1IsTUFBTSxFQUNOLHVCQUF1QixJQUFJLENBQUMsY0FBYyxhQUFhLEtBQUssU0FBUyxRQUFRLDBCQUEwQjs0QkFDdkcsaUNBQWlDLENBQ2xDLENBQUM7b0JBQ0osQ0FBQztnQkFDSCxDQUFDO2dCQUFDLE9BQU8sUUFBYSxFQUFFLENBQUM7b0JBQ3ZCLE1BQU0sQ0FBQyxHQUFHLENBQ1IsTUFBTSxFQUNOLG9EQUFvRCxLQUFLLFNBQVMsSUFBSSxDQUFDLGNBQWMsTUFBTSxRQUFRLEVBQUUsT0FBTyxJQUFJLE1BQU0sQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUNuSSxDQUFDO2dCQUNKLENBQUM7WUFDSCxDQUFDO1FBQ0gsQ0FBQztRQUFDLE9BQU8sR0FBUSxFQUFFLENBQUM7WUFDbEIsTUFBTSxDQUFDLEVBQUUsR0FBRyxLQUFLLENBQUM7WUFDbEIsTUFBTSxDQUFDLEdBQUcsQ0FDUixPQUFPLEVBQ1AsK0JBQStCLElBQUksQ0FBQyxjQUFjLE1BQU0sR0FBRyxFQUFFLE9BQU8sSUFBSSxNQUFNLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FDdEYsQ0FBQztRQUNKLENBQUM7UUFFRCxPQUFPLE1BQU0sQ0FBQztJQUNoQixDQUFDO0lBRUQ7OztPQUdHO0lBQ0ssUUFBUSxDQUFDLE1BQVM7UUFDeEIsTUFBTSxJQUFJLEdBQUcsT0FBTyxDQUFDLFlBQVksQ0FBQyxLQUFLLEVBQVEsQ0FBQztRQUNoRCxJQUFJLGdCQUFnQixHQUFHLElBQUksQ0FBQztRQUM1QixJQUFJLElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO1lBQzFCLGdCQUFnQixHQUFHLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUNuRCxDQUFDO1FBQ0QsSUFBSSxnQkFBZ0IsRUFBRSxDQUFDO1lBQ3JCLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUNqQixDQUFDO2FBQU0sQ0FBQztZQUNOLElBQUksQ0FBQyxNQUFNLENBQUMsbUNBQW1DLENBQUMsQ0FBQztRQUNuRCxDQUFDO1FBQ0QsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFDO0lBQ3RCLENBQUM7Q0FDRiJ9
|