@researchdatabox/redbox-core 5.1.0-beta.12568 → 5.1.0-beta.13939
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/browser/redoc-library-loader.cjs +20 -0
- package/browser/redoc-standalone.js +143 -0
- package/dist/CoreBase.d.ts +43 -0
- package/dist/CoreBase.d.ts.map +1 -0
- package/dist/CoreBase.js +101 -0
- package/dist/CoreController.d.ts +23 -31
- package/dist/CoreController.d.ts.map +1 -1
- package/dist/CoreController.js +142 -131
- package/dist/CoreService.d.ts +13 -33
- package/dist/CoreService.d.ts.map +1 -1
- package/dist/CoreService.js +69 -95
- package/dist/HarvestRunService.d.ts +9 -1
- package/dist/HarvestRunService.d.ts.map +1 -1
- package/dist/HarvestRunService.js +1 -1
- package/dist/RecordRouteForm.d.ts +49 -0
- package/dist/RecordRouteForm.d.ts.map +1 -0
- package/dist/RecordRouteForm.js +188 -0
- package/dist/RecordSaveResponse.d.ts +4 -0
- package/dist/RecordSaveResponse.d.ts.map +1 -1
- package/dist/RecordSaveResponse.js +3 -2
- package/dist/action-execution/executor.d.ts +1 -1
- package/dist/action-execution/executor.d.ts.map +1 -1
- package/dist/action-execution/executor.js +19 -20
- package/dist/action-execution/legacy-result.d.ts +1 -1
- package/dist/action-execution/legacy-result.d.ts.map +1 -1
- package/dist/action-execution/legacy-result.js +43 -10
- package/dist/action-execution/types.d.ts +3 -3
- package/dist/action-execution/types.d.ts.map +1 -1
- package/dist/api-routes/groups/harvest-runs.d.ts +1 -0
- package/dist/api-routes/groups/harvest-runs.d.ts.map +1 -1
- package/dist/api-routes/groups/harvest-runs.js +24 -3
- package/dist/api-routes/groups/records.d.ts.map +1 -1
- package/dist/api-routes/groups/records.js +30 -21
- package/dist/api-routes/groups/reports.d.ts.map +1 -1
- package/dist/api-routes/groups/reports.js +3 -2
- package/dist/api-routes/helpers.d.ts +1 -1
- package/dist/api-routes/helpers.d.ts.map +1 -1
- package/dist/api-routes/helpers.js +10 -6
- package/dist/api-routes/openapi.d.ts.map +1 -1
- package/dist/api-routes/openapi.js +15 -1
- package/dist/api-routes/request-extraction.js +2 -2
- package/dist/api-routes/schemas/common.d.ts.map +1 -1
- package/dist/api-routes/schemas/common.js +7 -2
- package/dist/api-routes/schemas/responses.d.ts +38 -12
- package/dist/api-routes/schemas/responses.d.ts.map +1 -1
- package/dist/api-routes/schemas/responses.js +11 -1
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +13 -3
- package/dist/config/agendaQueue.config.d.ts +5 -0
- package/dist/config/agendaQueue.config.d.ts.map +1 -1
- package/dist/config/agendaQueue.config.js +29 -2
- package/dist/config/appConfigSecrets.config.d.ts +14 -0
- package/dist/config/appConfigSecrets.config.d.ts.map +1 -0
- package/dist/config/appConfigSecrets.config.js +8 -0
- package/dist/config/brandingConfigurationDefaults.config.d.ts +16 -3
- package/dist/config/brandingConfigurationDefaults.config.d.ts.map +1 -1
- package/dist/config/brandingConfigurationDefaults.config.js +1 -1
- package/dist/config/dompurify.config.d.ts.map +1 -1
- package/dist/config/dompurify.config.js +3 -2
- package/dist/config/harvestRuns.config.d.ts +7 -0
- package/dist/config/harvestRuns.config.d.ts.map +1 -1
- package/dist/config/harvestRuns.config.js +2 -1
- package/dist/config/http.config.d.ts +3 -2
- package/dist/config/http.config.d.ts.map +1 -1
- package/dist/config/http.config.js +108 -12
- package/dist/config/i18n.config.d.ts +3 -0
- package/dist/config/i18n.config.d.ts.map +1 -1
- package/dist/config/i18n.config.js +1 -1
- package/dist/config/index.d.ts +4 -0
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +4 -1
- package/dist/config/log.config.d.ts +33 -5
- package/dist/config/log.config.d.ts.map +1 -1
- package/dist/config/log.config.js +58 -54
- package/dist/config/record.config.d.ts +17 -0
- package/dist/config/record.config.d.ts.map +1 -1
- package/dist/config/record.config.js +7 -1
- package/dist/config/routes.config.d.ts.map +1 -1
- package/dist/config/routes.config.js +11 -2
- package/dist/config/session.config.d.ts +2 -2
- package/dist/config/session.config.d.ts.map +1 -1
- package/dist/config/solr.config.d.ts +8 -0
- package/dist/config/solr.config.d.ts.map +1 -1
- package/dist/config/solr.config.js +15 -2
- package/dist/config/storage.config.d.ts.map +1 -1
- package/dist/config/storage.config.js +9 -1
- package/dist/config/vocab.config.d.ts +1 -0
- package/dist/config/vocab.config.d.ts.map +1 -1
- package/dist/config/vocab.config.js +3 -3
- package/dist/config/webpack.config.d.ts.map +1 -1
- package/dist/config/webpack.config.js +23 -5
- package/dist/configmodels/ConfigModels.d.ts.map +1 -1
- package/dist/configmodels/ConfigModels.js +3 -2
- package/dist/configmodels/FigsharePublishing.d.ts +1 -1
- package/dist/controllers/ActionController.d.ts.map +1 -1
- package/dist/controllers/ActionController.js +8 -2
- package/dist/controllers/BrandingAppController.d.ts.map +1 -1
- package/dist/controllers/BrandingAppController.js +21 -2
- package/dist/controllers/DynamicAssetController.d.ts +9 -10
- package/dist/controllers/DynamicAssetController.d.ts.map +1 -1
- package/dist/controllers/DynamicAssetController.js +67 -53
- package/dist/controllers/EmailController.d.ts.map +1 -1
- package/dist/controllers/EmailController.js +32 -14
- package/dist/controllers/ExportController.d.ts +9 -0
- package/dist/controllers/ExportController.d.ts.map +1 -1
- package/dist/controllers/ExportController.js +154 -3
- package/dist/controllers/FormVocabularyController.d.ts.map +1 -1
- package/dist/controllers/FormVocabularyController.js +62 -33
- package/dist/controllers/RecordAuditController.d.ts.map +1 -1
- package/dist/controllers/RecordAuditController.js +4 -2
- package/dist/controllers/RecordController.d.ts +4 -1
- package/dist/controllers/RecordController.d.ts.map +1 -1
- package/dist/controllers/RecordController.js +248 -114
- package/dist/controllers/ReportController.d.ts +1 -0
- package/dist/controllers/ReportController.d.ts.map +1 -1
- package/dist/controllers/ReportController.js +40 -12
- package/dist/controllers/TranslationController.d.ts.map +1 -1
- package/dist/controllers/TranslationController.js +56 -16
- package/dist/controllers/UserController.d.ts +3 -1
- package/dist/controllers/UserController.d.ts.map +1 -1
- package/dist/controllers/UserController.js +178 -76
- package/dist/controllers/VocabularyController.d.ts +0 -1
- package/dist/controllers/VocabularyController.d.ts.map +1 -1
- package/dist/controllers/VocabularyController.js +18 -16
- package/dist/controllers/webservice/AdminController.d.ts.map +1 -1
- package/dist/controllers/webservice/AdminController.js +2 -5
- package/dist/controllers/webservice/HarvestRunController.d.ts +1 -0
- package/dist/controllers/webservice/HarvestRunController.d.ts.map +1 -1
- package/dist/controllers/webservice/HarvestRunController.js +46 -2
- package/dist/controllers/webservice/IntegrationAuditController.d.ts +0 -1
- package/dist/controllers/webservice/IntegrationAuditController.d.ts.map +1 -1
- package/dist/controllers/webservice/IntegrationAuditController.js +13 -6
- package/dist/controllers/webservice/RecordController.d.ts +1 -1
- package/dist/controllers/webservice/RecordController.d.ts.map +1 -1
- package/dist/controllers/webservice/RecordController.js +13 -4
- package/dist/controllers/webservice/ReportController.d.ts.map +1 -1
- package/dist/controllers/webservice/ReportController.js +15 -10
- package/dist/controllers/webservice/UserManagementController.d.ts.map +1 -1
- package/dist/controllers/webservice/UserManagementController.js +17 -8
- package/dist/controllers/webservice/VocabularyController.d.ts.map +1 -1
- package/dist/controllers/webservice/VocabularyController.js +19 -13
- package/dist/form-config/generated-view-only.d.ts.map +1 -1
- package/dist/form-config/generated-view-only.js +12 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/loader/index.d.ts +1 -0
- package/dist/loader/index.d.ts.map +1 -1
- package/dist/loader/index.js +56 -11
- package/dist/middleware/redboxSession.d.ts.map +1 -1
- package/dist/middleware/redboxSession.js +15 -3
- package/dist/middleware/requestChronicle.d.ts +14 -0
- package/dist/middleware/requestChronicle.d.ts.map +1 -0
- package/dist/middleware/requestChronicle.js +73 -0
- package/dist/model/BuildResponse.d.ts +7 -5
- package/dist/model/BuildResponse.d.ts.map +1 -1
- package/dist/model/RBValidationError.d.ts +18 -5
- package/dist/model/RBValidationError.d.ts.map +1 -1
- package/dist/model/RBValidationError.js +56 -17
- package/dist/model/storage/ExportJobModel.d.ts +33 -0
- package/dist/model/storage/ExportJobModel.d.ts.map +1 -0
- package/dist/model/storage/ExportJobModel.js +3 -0
- package/dist/model/storage/HarvestRunModel.d.ts +20 -0
- package/dist/model/storage/HarvestRunModel.d.ts.map +1 -1
- package/dist/model/storage/HarvestRunModel.js +2 -1
- package/dist/model/storage/index.d.ts +2 -1
- package/dist/model/storage/index.d.ts.map +1 -1
- package/dist/model/storage/index.js +1 -1
- package/dist/policies/checkAuth.d.ts.map +1 -1
- package/dist/policies/checkAuth.js +3 -2
- package/dist/policies/contentSecurityPolicy.d.ts.map +1 -1
- package/dist/policies/contentSecurityPolicy.js +7 -2
- package/dist/policies/noCache.d.ts.map +1 -1
- package/dist/policies/noCache.js +4 -3
- package/dist/record-contract/record-contract-compiler.d.ts.map +1 -1
- package/dist/record-contract/record-contract-compiler.js +3 -19
- package/dist/record-contract/record-contract-context.d.ts +2 -0
- package/dist/record-contract/record-contract-context.d.ts.map +1 -1
- package/dist/record-contract/record-contract-context.js +1 -1
- package/dist/responses/notFound.d.ts.map +1 -1
- package/dist/responses/notFound.js +6 -1
- package/dist/responses/serverError.d.ts.map +1 -1
- package/dist/responses/serverError.js +13 -3
- package/dist/sails.d.ts +27 -17
- package/dist/sails.d.ts.map +1 -1
- package/dist/services/AgendaQueueService.d.ts +11 -2
- package/dist/services/AgendaQueueService.d.ts.map +1 -1
- package/dist/services/AgendaQueueService.js +163 -51
- package/dist/services/AppConfigSecrets.d.ts +66 -0
- package/dist/services/AppConfigSecrets.d.ts.map +1 -0
- package/dist/services/AppConfigSecrets.js +396 -0
- package/dist/services/AppConfigService.d.ts +16 -1
- package/dist/services/AppConfigService.d.ts.map +1 -1
- package/dist/services/AppConfigService.js +283 -33
- package/dist/services/BrandingThemeCssService.d.ts.map +1 -1
- package/dist/services/BrandingThemeCssService.js +32 -3
- package/dist/services/BrandingThemeTokens.d.ts.map +1 -1
- package/dist/services/BrandingThemeTokens.js +10 -1
- package/dist/services/ConfigService.d.ts +1 -0
- package/dist/services/ConfigService.d.ts.map +1 -1
- package/dist/services/ConfigService.js +24 -9
- package/dist/services/DomSanitizerService.d.ts.map +1 -1
- package/dist/services/DomSanitizerService.js +19 -6
- package/dist/services/EmailService.d.ts +10 -2
- package/dist/services/EmailService.d.ts.map +1 -1
- package/dist/services/EmailService.js +53 -53
- package/dist/services/ExportService.d.ts +62 -0
- package/dist/services/ExportService.d.ts.map +1 -0
- package/dist/services/ExportService.js +609 -0
- package/dist/services/FormVocabularyService.d.ts.map +1 -1
- package/dist/services/FormVocabularyService.js +14 -4
- package/dist/services/FormsService.d.ts +3 -0
- package/dist/services/FormsService.d.ts.map +1 -1
- package/dist/services/FormsService.js +10 -3
- package/dist/services/HarvestRunService.d.ts +23 -1
- package/dist/services/HarvestRunService.d.ts.map +1 -1
- package/dist/services/HarvestRunService.js +155 -22
- package/dist/services/I18nEntriesService.d.ts +5 -0
- package/dist/services/I18nEntriesService.d.ts.map +1 -1
- package/dist/services/I18nEntriesService.js +55 -3
- package/dist/services/NamedQueryService.d.ts +1 -0
- package/dist/services/NamedQueryService.d.ts.map +1 -1
- package/dist/services/NamedQueryService.js +67 -31
- package/dist/services/RDMPService.d.ts.map +1 -1
- package/dist/services/RDMPService.js +69 -83
- package/dist/services/RaidService.d.ts.map +1 -1
- package/dist/services/RaidService.js +45 -11
- package/dist/services/RecordSchemaService.d.ts +3 -1
- package/dist/services/RecordSchemaService.d.ts.map +1 -1
- package/dist/services/RecordSchemaService.js +2 -1
- package/dist/services/RecordValidationService.d.ts +3 -0
- package/dist/services/RecordValidationService.d.ts.map +1 -1
- package/dist/services/RecordValidationService.js +25 -5
- package/dist/services/RecordsService.d.ts +10 -1
- package/dist/services/RecordsService.d.ts.map +1 -1
- package/dist/services/RecordsService.js +194 -93
- package/dist/services/ReportsService.d.ts +1 -0
- package/dist/services/ReportsService.d.ts.map +1 -1
- package/dist/services/ReportsService.js +10 -9
- package/dist/services/RvaImportService.d.ts.map +1 -1
- package/dist/services/RvaImportService.js +6 -5
- package/dist/services/SolrSearchService.d.ts +7 -2
- package/dist/services/SolrSearchService.d.ts.map +1 -1
- package/dist/services/SolrSearchService.js +205 -81
- package/dist/services/StorageManagerService.d.ts +5 -0
- package/dist/services/StorageManagerService.d.ts.map +1 -1
- package/dist/services/StorageManagerService.js +4 -1
- package/dist/services/TriggerService.d.ts.map +1 -1
- package/dist/services/TriggerService.js +64 -56
- package/dist/services/UsersService.d.ts +13 -1
- package/dist/services/UsersService.d.ts.map +1 -1
- package/dist/services/UsersService.js +191 -257
- package/dist/services/VocabularyService.d.ts +11 -1
- package/dist/services/VocabularyService.d.ts.map +1 -1
- package/dist/services/VocabularyService.js +120 -24
- package/dist/services/doi-v2/http.d.ts +3 -2
- package/dist/services/doi-v2/http.d.ts.map +1 -1
- package/dist/services/doi-v2/http.js +38 -4
- package/dist/services/doi-v2/runtime.d.ts +4 -3
- package/dist/services/doi-v2/runtime.d.ts.map +1 -1
- package/dist/services/doi-v2/runtime.js +52 -17
- package/dist/services/figshare-v2/assets.d.ts +1 -1
- package/dist/services/figshare-v2/assets.d.ts.map +1 -1
- package/dist/services/figshare-v2/assets.js +1 -1
- package/dist/services/figshare-v2/http.d.ts +3 -2
- package/dist/services/figshare-v2/http.d.ts.map +1 -1
- package/dist/services/figshare-v2/http.js +38 -4
- package/dist/services/figshare-v2/observability.d.ts.map +1 -1
- package/dist/services/figshare-v2/observability.js +3 -3
- package/dist/services/figshare-v2/runtime.d.ts +4 -3
- package/dist/services/figshare-v2/runtime.d.ts.map +1 -1
- package/dist/services/figshare-v2/runtime.js +48 -13
- package/dist/services/index.d.ts +3 -0
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/index.js +8 -3
- package/dist/services/integration-v2/runtime.d.ts +1 -1
- package/dist/services/integration-v2/runtime.d.ts.map +1 -1
- package/dist/services/integration-v2/runtime.js +7 -7
- package/dist/services/oni-v2/audit.d.ts +3 -2
- package/dist/services/oni-v2/audit.d.ts.map +1 -1
- package/dist/services/oni-v2/audit.js +38 -4
- package/dist/services/oni-v2/bindings.d.ts +1 -1
- package/dist/services/oni-v2/bindings.d.ts.map +1 -1
- package/dist/services/oni-v2/bindings.js +37 -4
- package/dist/services/oni-v2/repository.d.ts +3 -2
- package/dist/services/oni-v2/repository.d.ts.map +1 -1
- package/dist/services/oni-v2/repository.js +42 -7
- package/dist/services/oni-v2/runtime.d.ts +5 -4
- package/dist/services/oni-v2/runtime.d.ts.map +1 -1
- package/dist/services/oni-v2/runtime.js +57 -19
- package/dist/services/oni-v2/templating.d.ts +4 -2
- package/dist/services/oni-v2/templating.d.ts.map +1 -1
- package/dist/services/oni-v2/templating.js +42 -7
- package/dist/services/raid-v2/audit.d.ts +1 -1
- package/dist/services/raid-v2/audit.d.ts.map +1 -1
- package/dist/services/raid-v2/audit.js +39 -5
- package/dist/services/raid-v2/errors.d.ts +9 -9
- package/dist/services/raid-v2/errors.js +44 -11
- package/dist/services/raid-v2/http.d.ts +1 -1
- package/dist/services/raid-v2/http.d.ts.map +1 -1
- package/dist/services/raid-v2/http.js +42 -8
- package/dist/services/raid-v2/logger.d.ts +1 -1
- package/dist/services/raid-v2/logger.d.ts.map +1 -1
- package/dist/services/raid-v2/logger.js +42 -8
- package/dist/services/raid-v2/mapping.d.ts +1 -1
- package/dist/services/raid-v2/mapping.d.ts.map +1 -1
- package/dist/services/raid-v2/mapping.js +41 -7
- package/dist/services/raid-v2/runtime.d.ts +1 -1
- package/dist/services/raid-v2/runtime.d.ts.map +1 -1
- package/dist/services/raid-v2/runtime.js +76 -34
- package/dist/services/raid-v2/tags.d.ts +8 -8
- package/dist/services/raid-v2/tags.d.ts.map +1 -1
- package/dist/services/raid-v2/tags.js +42 -9
- package/dist/services/record-hooks/coordinator.d.ts +11 -0
- package/dist/services/record-hooks/coordinator.d.ts.map +1 -1
- package/dist/services/record-hooks/coordinator.js +70 -6
- package/dist/storage/GridFSDriver.d.ts +16 -9
- package/dist/storage/GridFSDriver.d.ts.map +1 -1
- package/dist/storage/GridFSDriver.js +87 -33
- package/dist/storage/TusStorageManagerDataStore.d.ts +11 -1
- package/dist/storage/TusStorageManagerDataStore.d.ts.map +1 -1
- package/dist/storage/TusStorageManagerDataStore.js +190 -56
- package/dist/utilities/HarvestHistoryRetention.d.ts +17 -0
- package/dist/utilities/HarvestHistoryRetention.d.ts.map +1 -0
- package/dist/utilities/HarvestHistoryRetention.js +141 -0
- package/dist/utilities/HarvestRunIndexes.d.ts +12 -0
- package/dist/utilities/HarvestRunIndexes.d.ts.map +1 -0
- package/dist/utilities/HarvestRunIndexes.js +84 -0
- package/dist/utilities/PinoLoggerUtils.d.ts +9 -0
- package/dist/utilities/PinoLoggerUtils.d.ts.map +1 -0
- package/dist/utilities/PinoLoggerUtils.js +17 -0
- package/dist/utilities/RequestChronicle.d.ts +221 -0
- package/dist/utilities/RequestChronicle.d.ts.map +1 -0
- package/dist/utilities/RequestChronicle.js +770 -0
- package/dist/utilities/RequestChronicleContext.d.ts +6 -0
- package/dist/utilities/RequestChronicleContext.d.ts.map +1 -0
- package/dist/utilities/RequestChronicleContext.js +19 -0
- package/dist/utilities/RequestChronicleSettings.d.ts +29 -0
- package/dist/utilities/RequestChronicleSettings.d.ts.map +1 -0
- package/dist/utilities/RequestChronicleSettings.js +31 -0
- package/dist/utilities/TransactionUtils.d.ts +2 -1
- package/dist/utilities/TransactionUtils.d.ts.map +1 -1
- package/dist/utilities/TransactionUtils.js +1 -1
- package/dist/utilities/TranslationHtml.d.ts.map +1 -1
- package/dist/utilities/TranslationHtml.js +13 -5
- package/dist/utilities/VocabularyAdminAccess.d.ts +10 -0
- package/dist/utilities/VocabularyAdminAccess.d.ts.map +1 -0
- package/dist/utilities/VocabularyAdminAccess.js +42 -0
- package/dist/visitor/construct.visitor.d.ts.map +1 -1
- package/dist/visitor/construct.visitor.js +7 -2
- package/dist/visitor/context-variables.visitor.d.ts +1 -2
- package/dist/visitor/context-variables.visitor.d.ts.map +1 -1
- package/dist/visitor/context-variables.visitor.js +1 -1
- package/dist/visitor/migrate-config-v4-v5.visitor.d.ts.map +1 -1
- package/dist/visitor/migrate-config-v4-v5.visitor.js +5 -1
- package/dist/visitor/related-object-data-inline.visitor.d.ts +1 -1
- package/dist/visitor/related-object-data-inline.visitor.d.ts.map +1 -1
- package/dist/visitor/related-object-data-inline.visitor.js +57 -23
- package/dist/visitor/validator.visitor.d.ts.map +1 -1
- package/dist/visitor/validator.visitor.js +4 -2
- package/dist/visitor/visitor-helpers.js +3 -3
- package/dist/visitor/vocab-inline.visitor.d.ts +1 -2
- package/dist/visitor/vocab-inline.visitor.d.ts.map +1 -1
- package/dist/visitor/vocab-inline.visitor.js +1 -1
- package/dist/waterline-models/ExportJob.d.ts +38 -0
- package/dist/waterline-models/ExportJob.d.ts.map +1 -0
- package/dist/waterline-models/ExportJob.js +148 -0
- package/dist/waterline-models/HarvestRecordEvent.d.ts.map +1 -1
- package/dist/waterline-models/HarvestRecordEvent.js +3 -9
- package/dist/waterline-models/HarvestRun.d.ts +5 -1
- package/dist/waterline-models/HarvestRun.d.ts.map +1 -1
- package/dist/waterline-models/HarvestRun.js +13 -7
- package/dist/waterline-models/HarvestRunChunk.d.ts.map +1 -1
- package/dist/waterline-models/HarvestRunChunk.js +3 -7
- package/dist/waterline-models/User.d.ts +2 -2
- package/dist/waterline-models/User.d.ts.map +1 -1
- package/dist/waterline-models/User.js +3 -3
- package/dist/waterline-models/index.d.ts +2 -0
- package/dist/waterline-models/index.d.ts.map +1 -1
- package/dist/waterline-models/index.js +4 -1
- package/logfmt-transport.cjs +59 -0
- package/package.json +76 -45
- package/dist/Logger.d.ts +0 -16
- package/dist/Logger.d.ts.map +0 -1
- package/dist/Logger.js +0 -3
|
@@ -0,0 +1,770 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RequestChronicleHelper = exports.RequestChronicleLimits = exports.RequestChronicleClassifications = exports.RequestChronicleOutcomes = exports.defaultRequestChronicleSettings = void 0;
|
|
4
|
+
exports.sanitizeChroniclePath = sanitizeChroniclePath;
|
|
5
|
+
exports.safeChronicleText = safeChronicleText;
|
|
6
|
+
exports.sanitizeChronicleValue = sanitizeChronicleValue;
|
|
7
|
+
exports.summarizeChronicleValue = summarizeChronicleValue;
|
|
8
|
+
exports.toChronicleError = toChronicleError;
|
|
9
|
+
exports.toChronicleLogRecord = toChronicleLogRecord;
|
|
10
|
+
const node_crypto_1 = require("node:crypto");
|
|
11
|
+
const node_perf_hooks_1 = require("node:perf_hooks");
|
|
12
|
+
const api_1 = require("@opentelemetry/api");
|
|
13
|
+
const RedactionUtils_1 = require("./RedactionUtils");
|
|
14
|
+
const RequestChronicleSettings_1 = require("./RequestChronicleSettings");
|
|
15
|
+
var RequestChronicleSettings_2 = require("./RequestChronicleSettings");
|
|
16
|
+
Object.defineProperty(exports, "defaultRequestChronicleSettings", { enumerable: true, get: function () { return RequestChronicleSettings_2.defaultRequestChronicleSettings; } });
|
|
17
|
+
/**
|
|
18
|
+
* What happened to the request.
|
|
19
|
+
* - success: the response was sent with a status below 400, and no errors were recorded.
|
|
20
|
+
* - failure: the response was sent with a 4xx or 5xx status, or errors were recorded.
|
|
21
|
+
* - aborted: the connection closed before the response was completely sent.
|
|
22
|
+
*/
|
|
23
|
+
exports.RequestChronicleOutcomes = ['success', 'failure', 'aborted'];
|
|
24
|
+
/**
|
|
25
|
+
* Why the request chronicle was retained (or discarded), which also determines the log level.
|
|
26
|
+
*/
|
|
27
|
+
exports.RequestChronicleClassifications = [
|
|
28
|
+
'error',
|
|
29
|
+
'client-error',
|
|
30
|
+
'aborted',
|
|
31
|
+
'slow',
|
|
32
|
+
'warning',
|
|
33
|
+
'sample',
|
|
34
|
+
'discard',
|
|
35
|
+
];
|
|
36
|
+
/**
|
|
37
|
+
* The log level used for each classification.
|
|
38
|
+
* Client errors are logged at 'warn' instead of 'info' when errors were recorded.
|
|
39
|
+
*/
|
|
40
|
+
const classificationLevels = {
|
|
41
|
+
error: 'error',
|
|
42
|
+
'client-error': 'info',
|
|
43
|
+
aborted: 'info',
|
|
44
|
+
slow: 'warn',
|
|
45
|
+
warning: 'warn',
|
|
46
|
+
sample: 'info',
|
|
47
|
+
discard: null,
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Limits on the size of the captured data.
|
|
51
|
+
*/
|
|
52
|
+
exports.RequestChronicleLimits = Object.freeze({
|
|
53
|
+
maxDepth: 4,
|
|
54
|
+
maxStringLength: 500,
|
|
55
|
+
maxArrayItems: 20,
|
|
56
|
+
maxObjectKeys: 30,
|
|
57
|
+
maxValueJsonLength: 4096,
|
|
58
|
+
maxInfoKeys: 100,
|
|
59
|
+
maxErrors: 20,
|
|
60
|
+
maxErrorDepth: 3,
|
|
61
|
+
maxErrorDetails: 10,
|
|
62
|
+
maxErrorMessageLength: 1000,
|
|
63
|
+
maxErrorJsonLength: 8192,
|
|
64
|
+
maxStackLength: 4000,
|
|
65
|
+
maxStackLines: 12,
|
|
66
|
+
maxKeyLength: 100,
|
|
67
|
+
});
|
|
68
|
+
const reservedKeys = [
|
|
69
|
+
// Request chronicle fields.
|
|
70
|
+
'requestId',
|
|
71
|
+
'traceId',
|
|
72
|
+
'result',
|
|
73
|
+
'req',
|
|
74
|
+
'res',
|
|
75
|
+
'errors',
|
|
76
|
+
'errorsOmitted',
|
|
77
|
+
// Fields set by pino, which must not be overwritten by request details.
|
|
78
|
+
'level',
|
|
79
|
+
'time',
|
|
80
|
+
'pid',
|
|
81
|
+
'hostname',
|
|
82
|
+
'name',
|
|
83
|
+
'msg',
|
|
84
|
+
'err',
|
|
85
|
+
'v',
|
|
86
|
+
];
|
|
87
|
+
const sensitiveKeyPattern = /token|authorization|secret|apikey|api_key|password|credential|cookie/i;
|
|
88
|
+
const upstreamRequestIdPattern = /^[A-Za-z0-9._:-]{1,128}$/;
|
|
89
|
+
const tokenPathPatterns = [
|
|
90
|
+
// Branding preview stylesheets: /:branding/:portal/preview/:token.css
|
|
91
|
+
[/(\/preview\/)[^/?#\s]+(\.css)/gi, '$1REDACTED$2'],
|
|
92
|
+
// Token-like query parameters.
|
|
93
|
+
[/([?&](?:token|access_token|id_token|code|key|apiKey|api_key)=)[^&#\s]*/gi, '$1REDACTED'],
|
|
94
|
+
];
|
|
95
|
+
/**
|
|
96
|
+
* Remove tokens from request paths and URLs.
|
|
97
|
+
* @param value The path or URL.
|
|
98
|
+
*/
|
|
99
|
+
function sanitizeChroniclePath(value) {
|
|
100
|
+
let result = value;
|
|
101
|
+
for (const [pattern, replacement] of tokenPathPatterns) {
|
|
102
|
+
result = result.replace(pattern, replacement);
|
|
103
|
+
}
|
|
104
|
+
return result;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Convert a value to a string that is safe to log: secrets and token-bearing paths are redacted,
|
|
108
|
+
* and the length is bounded. Only the start of a very long string is processed.
|
|
109
|
+
* @param value The value.
|
|
110
|
+
* @param maxLength The maximum length, excluding the truncation marker.
|
|
111
|
+
*/
|
|
112
|
+
function safeChronicleText(value, maxLength) {
|
|
113
|
+
let text;
|
|
114
|
+
try {
|
|
115
|
+
text = typeof value === 'string' ? value : String(value);
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
return '[Unprintable]';
|
|
119
|
+
}
|
|
120
|
+
// Process a little more than the limit, so tokens near the limit can still be recognised.
|
|
121
|
+
const head = text.length > maxLength + 200 ? text.substring(0, maxLength + 200) : text;
|
|
122
|
+
const redacted = sanitizeChroniclePath(String((0, RedactionUtils_1.redactSecret)(head)))
|
|
123
|
+
// Credentials can be embedded in diagnostic text, including an Error's stack.
|
|
124
|
+
.replace(/(\bBearer\s+)[A-Za-z0-9._~+/-]+=*/gi, '$1REDACTED')
|
|
125
|
+
.replace(/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+(?:\.[A-Za-z0-9_-]*)?/g, 'REDACTED')
|
|
126
|
+
.replace(/\bsk_(?:live|test)_[A-Za-z0-9]+\b/g, 'REDACTED');
|
|
127
|
+
if (redacted.length <= maxLength && head.length === text.length) {
|
|
128
|
+
return redacted;
|
|
129
|
+
}
|
|
130
|
+
// Redact a token path that is cut off by the truncation.
|
|
131
|
+
const truncated = redacted.substring(0, maxLength).replace(/(\/preview\/)[^/?#\s]*$/i, '$1REDACTED');
|
|
132
|
+
return `${truncated}…[truncated ${Math.max(text.length - maxLength, 0)} chars]`;
|
|
133
|
+
}
|
|
134
|
+
function isSensitiveKey(key) {
|
|
135
|
+
return sensitiveKeyPattern.test(key);
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Sanitise the top-level entries of a details object: bound the number and length of keys,
|
|
139
|
+
* redact sensitive keys, and sanitise the values.
|
|
140
|
+
*/
|
|
141
|
+
function sanitizeChronicleEntries(info) {
|
|
142
|
+
const entries = [];
|
|
143
|
+
let omitted = 0;
|
|
144
|
+
for (const rawKey in info) {
|
|
145
|
+
if (!Object.prototype.hasOwnProperty.call(info, rawKey)) {
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
if (entries.length >= exports.RequestChronicleLimits.maxInfoKeys) {
|
|
149
|
+
omitted += 1;
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
const key = safeChronicleText(rawKey, exports.RequestChronicleLimits.maxKeyLength);
|
|
153
|
+
entries.push([key, isSensitiveKey(rawKey) ? 'REDACTED' : sanitizeChronicleValue(info[rawKey])]);
|
|
154
|
+
}
|
|
155
|
+
return { entries, omitted };
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Make an operation name safe to use as a key and in log messages.
|
|
159
|
+
*/
|
|
160
|
+
function safeOperationName(operation) {
|
|
161
|
+
return (safeChronicleText(operation, exports.RequestChronicleLimits.maxKeyLength).replace(/[^A-Za-z0-9._:-]/g, '_') || 'operation');
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Convert a value to a plain, size-bounded representation that is safe to log.
|
|
165
|
+
* Redacts sensitive keys and token-bearing paths, and limits depth, items, keys, and string length.
|
|
166
|
+
* @param value The value to sanitise.
|
|
167
|
+
*/
|
|
168
|
+
function sanitizeChronicleValue(value) {
|
|
169
|
+
const sanitized = sanitizeInner(value, 0, new WeakSet());
|
|
170
|
+
try {
|
|
171
|
+
const json = JSON.stringify(sanitized);
|
|
172
|
+
if (json !== undefined && json.length > exports.RequestChronicleLimits.maxValueJsonLength) {
|
|
173
|
+
return { truncated: true, jsonLength: json.length };
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
catch {
|
|
177
|
+
return '[Unserialisable]';
|
|
178
|
+
}
|
|
179
|
+
return sanitized;
|
|
180
|
+
}
|
|
181
|
+
function sanitizeInner(value, depth, seen) {
|
|
182
|
+
if (value === null || value === undefined || typeof value === 'boolean' || typeof value === 'number') {
|
|
183
|
+
return value;
|
|
184
|
+
}
|
|
185
|
+
if (typeof value === 'string') {
|
|
186
|
+
return safeChronicleText(value, exports.RequestChronicleLimits.maxStringLength);
|
|
187
|
+
}
|
|
188
|
+
if (typeof value === 'bigint') {
|
|
189
|
+
return value.toString();
|
|
190
|
+
}
|
|
191
|
+
if (typeof value === 'function') {
|
|
192
|
+
return '[Function]';
|
|
193
|
+
}
|
|
194
|
+
if (typeof value !== 'object') {
|
|
195
|
+
return String(value);
|
|
196
|
+
}
|
|
197
|
+
if (value instanceof Date) {
|
|
198
|
+
return Number.isNaN(value.getTime()) ? 'Invalid Date' : value.toISOString();
|
|
199
|
+
}
|
|
200
|
+
if (value instanceof Error) {
|
|
201
|
+
return toChronicleErrorInner(value, depth, seen);
|
|
202
|
+
}
|
|
203
|
+
if (Buffer.isBuffer(value)) {
|
|
204
|
+
return `[Buffer ${value.length} bytes]`;
|
|
205
|
+
}
|
|
206
|
+
if (seen.has(value)) {
|
|
207
|
+
return '[Circular]';
|
|
208
|
+
}
|
|
209
|
+
if (Array.isArray(value)) {
|
|
210
|
+
if (depth >= exports.RequestChronicleLimits.maxDepth) {
|
|
211
|
+
return `[Array(${value.length})]`;
|
|
212
|
+
}
|
|
213
|
+
seen.add(value);
|
|
214
|
+
const items = value
|
|
215
|
+
.slice(0, exports.RequestChronicleLimits.maxArrayItems)
|
|
216
|
+
.map(item => sanitizeInner(item, depth + 1, seen));
|
|
217
|
+
if (value.length > exports.RequestChronicleLimits.maxArrayItems) {
|
|
218
|
+
items.push(`…${value.length - exports.RequestChronicleLimits.maxArrayItems} more items`);
|
|
219
|
+
}
|
|
220
|
+
seen.delete(value);
|
|
221
|
+
return items;
|
|
222
|
+
}
|
|
223
|
+
if (depth >= exports.RequestChronicleLimits.maxDepth) {
|
|
224
|
+
return '[Object]';
|
|
225
|
+
}
|
|
226
|
+
seen.add(value);
|
|
227
|
+
const result = {};
|
|
228
|
+
let count = 0;
|
|
229
|
+
for (const key in value) {
|
|
230
|
+
if (!Object.prototype.hasOwnProperty.call(value, key)) {
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
if (count >= exports.RequestChronicleLimits.maxObjectKeys) {
|
|
234
|
+
result['…'] = 'more keys omitted';
|
|
235
|
+
break;
|
|
236
|
+
}
|
|
237
|
+
count += 1;
|
|
238
|
+
result[safeChronicleText(key, exports.RequestChronicleLimits.maxKeyLength)] = isSensitiveKey(key)
|
|
239
|
+
? 'REDACTED'
|
|
240
|
+
: sanitizeInner(value[key], depth + 1, seen);
|
|
241
|
+
}
|
|
242
|
+
seen.delete(value);
|
|
243
|
+
return result;
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Describe the shape of a value without including its content.
|
|
247
|
+
* Use this for results that may be large or contain personal or sensitive data.
|
|
248
|
+
* @param value The value to describe.
|
|
249
|
+
*/
|
|
250
|
+
function summarizeChronicleValue(value) {
|
|
251
|
+
if (value === null) {
|
|
252
|
+
return { type: 'null' };
|
|
253
|
+
}
|
|
254
|
+
if (Array.isArray(value)) {
|
|
255
|
+
return { type: 'array', length: value.length };
|
|
256
|
+
}
|
|
257
|
+
if (typeof value === 'string') {
|
|
258
|
+
return { type: 'string', length: value.length };
|
|
259
|
+
}
|
|
260
|
+
if (typeof value === 'object') {
|
|
261
|
+
return { type: 'object', keyCount: Object.keys(value).length };
|
|
262
|
+
}
|
|
263
|
+
return { type: typeof value };
|
|
264
|
+
}
|
|
265
|
+
function isRBValidationErrorLike(item) {
|
|
266
|
+
return item.name === 'RBValidationError' && Array.isArray(item.displayErrors);
|
|
267
|
+
}
|
|
268
|
+
/** A summary of a display error, which is already a plain, safe object. */
|
|
269
|
+
class DisplayErrorSummary {
|
|
270
|
+
name;
|
|
271
|
+
message;
|
|
272
|
+
constructor(name, message) {
|
|
273
|
+
this.name = name;
|
|
274
|
+
this.message = message;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Convert a possible error to a consistent, size-bounded plain object representation.
|
|
279
|
+
* Handles causes, aggregate and suppressed errors, and cycles, without throwing.
|
|
280
|
+
* Names, messages, codes, and stacks are redacted and bounded, as is the whole result.
|
|
281
|
+
* @param item This might be an error, or a string, or something else.
|
|
282
|
+
*/
|
|
283
|
+
function toChronicleError(item) {
|
|
284
|
+
try {
|
|
285
|
+
const result = toChronicleErrorInner(item, 0, new WeakSet());
|
|
286
|
+
// Check each complete candidate, including omission markers and JSON escaping.
|
|
287
|
+
const { details: _details, ...withoutDetails } = result;
|
|
288
|
+
const { stack: _stack, ...summary } = withoutDetails;
|
|
289
|
+
const candidates = [
|
|
290
|
+
result,
|
|
291
|
+
{ ...withoutDetails, details: [{ message: 'Nested errors omitted due to size.' }] },
|
|
292
|
+
{ ...summary, details: [{ message: 'Stack and nested errors omitted due to size.' }] },
|
|
293
|
+
];
|
|
294
|
+
return (candidates.find(candidate => JSON.stringify(candidate).length <= exports.RequestChronicleLimits.maxErrorJsonLength) ?? {
|
|
295
|
+
message: 'Error details omitted due to size.',
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
catch {
|
|
299
|
+
return { message: 'Unable to record the error.' };
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
function toChronicleErrorInner(item, depth, seen) {
|
|
303
|
+
const limits = exports.RequestChronicleLimits;
|
|
304
|
+
if (item instanceof Error || Array.isArray(item)) {
|
|
305
|
+
if (seen.has(item)) {
|
|
306
|
+
return { message: '[Circular]' };
|
|
307
|
+
}
|
|
308
|
+
seen.add(item);
|
|
309
|
+
}
|
|
310
|
+
const result = {};
|
|
311
|
+
// Only the first few nested errors are processed; the total is counted.
|
|
312
|
+
const maxDetails = limits.maxErrorDetails;
|
|
313
|
+
const details = [];
|
|
314
|
+
let detailsTotal = 0;
|
|
315
|
+
const addDetails = (items) => {
|
|
316
|
+
detailsTotal += items.length;
|
|
317
|
+
const remaining = maxDetails - details.length;
|
|
318
|
+
if (remaining > 0) {
|
|
319
|
+
details.push(...items.slice(0, remaining));
|
|
320
|
+
}
|
|
321
|
+
};
|
|
322
|
+
if (item instanceof Error) {
|
|
323
|
+
if (item.name) {
|
|
324
|
+
result.name = safeChronicleText(item.name, limits.maxStringLength);
|
|
325
|
+
}
|
|
326
|
+
if (item.message) {
|
|
327
|
+
result.message = safeChronicleText(item.message, limits.maxErrorMessageLength);
|
|
328
|
+
}
|
|
329
|
+
const code = item.code;
|
|
330
|
+
if (typeof code === 'string' || typeof code === 'number') {
|
|
331
|
+
result.code = safeChronicleText(code, limits.maxStringLength);
|
|
332
|
+
}
|
|
333
|
+
if (isRBValidationErrorLike(item)) {
|
|
334
|
+
const displayErrors = item.displayErrors;
|
|
335
|
+
detailsTotal += displayErrors.length;
|
|
336
|
+
details.push(...displayErrors.slice(0, maxDetails).map(displayError => new DisplayErrorSummary(displayError?.title !== undefined && displayError?.title !== null
|
|
337
|
+
? safeChronicleText(displayError.title, limits.maxStringLength)
|
|
338
|
+
: undefined, safeChronicleText(Object.entries({
|
|
339
|
+
id: displayError?.id,
|
|
340
|
+
status: displayError?.status,
|
|
341
|
+
code: displayError?.code,
|
|
342
|
+
detail: displayError?.detail,
|
|
343
|
+
})
|
|
344
|
+
.filter(([_key, value]) => value !== undefined && value !== null)
|
|
345
|
+
.map(([key, value]) => `${key}: ${safeChronicleText(value, limits.maxStringLength)}`)
|
|
346
|
+
.join(', '), limits.maxErrorMessageLength))));
|
|
347
|
+
}
|
|
348
|
+
else if (depth === 0 && typeof item.stack === 'string') {
|
|
349
|
+
// Keep the location of unexpected errors.
|
|
350
|
+
result.stack = safeChronicleText(item.stack, limits.maxStackLength)
|
|
351
|
+
.split('\n')
|
|
352
|
+
.slice(0, limits.maxStackLines)
|
|
353
|
+
.join('\n');
|
|
354
|
+
}
|
|
355
|
+
if (item.cause !== undefined && item.cause !== null) {
|
|
356
|
+
addDetails([item.cause]);
|
|
357
|
+
}
|
|
358
|
+
if (typeof SuppressedError !== 'undefined' && item instanceof SuppressedError) {
|
|
359
|
+
addDetails([item.error, item.suppressed]);
|
|
360
|
+
}
|
|
361
|
+
if (item instanceof AggregateError && Array.isArray(item.errors)) {
|
|
362
|
+
addDetails(item.errors);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
else if (Array.isArray(item)) {
|
|
366
|
+
addDetails(item);
|
|
367
|
+
}
|
|
368
|
+
else if (typeof item === 'string') {
|
|
369
|
+
result.message = safeChronicleText(item, limits.maxErrorMessageLength);
|
|
370
|
+
}
|
|
371
|
+
else if (item !== null && typeof item === 'object' && typeof item.message === 'string') {
|
|
372
|
+
result.message = safeChronicleText(item.message, limits.maxErrorMessageLength);
|
|
373
|
+
}
|
|
374
|
+
else {
|
|
375
|
+
const sanitized = sanitizeInner(item, depth, seen);
|
|
376
|
+
result.message = safeChronicleText(typeof sanitized === 'string' ? sanitized : (JSON.stringify(sanitized) ?? String(item)), limits.maxErrorMessageLength);
|
|
377
|
+
}
|
|
378
|
+
if (detailsTotal > 0) {
|
|
379
|
+
if (depth >= limits.maxErrorDepth) {
|
|
380
|
+
result.details = [{ message: `${detailsTotal} nested errors omitted` }];
|
|
381
|
+
}
|
|
382
|
+
else {
|
|
383
|
+
result.details = details.map(detail => {
|
|
384
|
+
if (detail instanceof DisplayErrorSummary) {
|
|
385
|
+
return { ...(detail.name !== undefined ? { name: detail.name } : {}), message: detail.message };
|
|
386
|
+
}
|
|
387
|
+
return toChronicleErrorInner(detail, depth + 1, seen);
|
|
388
|
+
});
|
|
389
|
+
if (detailsTotal > details.length) {
|
|
390
|
+
result.details.push({ message: `${detailsTotal - details.length} more errors omitted` });
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
return result;
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* Convert arrays to objects keyed by index, so that the structure survives
|
|
398
|
+
* log formats that flatten nested objects but not arrays (e.g. pino-logfmt: `errors_0_message`).
|
|
399
|
+
* @param value The value to convert.
|
|
400
|
+
*/
|
|
401
|
+
function toChronicleLogRecord(value) {
|
|
402
|
+
if (Array.isArray(value)) {
|
|
403
|
+
return Object.fromEntries(value.map((item, index) => [String(index), toChronicleLogRecord(item)]));
|
|
404
|
+
}
|
|
405
|
+
if (value !== null && typeof value === 'object') {
|
|
406
|
+
return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, toChronicleLogRecord(item)]));
|
|
407
|
+
}
|
|
408
|
+
return value;
|
|
409
|
+
}
|
|
410
|
+
// Source and compiled modules can coexist in the development loader.
|
|
411
|
+
const helperBrand = Symbol.for('@researchdatabox/redbox-core/RequestChronicleHelper');
|
|
412
|
+
class RequestChronicleHelper {
|
|
413
|
+
logger;
|
|
414
|
+
[helperBrand] = true;
|
|
415
|
+
#data = {};
|
|
416
|
+
#recordedErrors = new WeakSet();
|
|
417
|
+
#state = 'pending';
|
|
418
|
+
#startedAt = 0;
|
|
419
|
+
#logged = false;
|
|
420
|
+
#hasWarnings = false;
|
|
421
|
+
#requestId;
|
|
422
|
+
#settings;
|
|
423
|
+
#random;
|
|
424
|
+
#now;
|
|
425
|
+
#generateRequestId;
|
|
426
|
+
#successSampleExclude = null;
|
|
427
|
+
constructor(logger, options = {}) {
|
|
428
|
+
this.logger = logger;
|
|
429
|
+
const configured = typeof sails !== 'undefined' ? sails?.config?.log?.requestChronicle : undefined;
|
|
430
|
+
this.#settings = (0, RequestChronicleSettings_1.resolveRequestChronicleSettings)(options.settings ?? configured);
|
|
431
|
+
this.#random = options.random ?? Math.random;
|
|
432
|
+
this.#now = options.now ?? (() => node_perf_hooks_1.performance.now());
|
|
433
|
+
this.#generateRequestId = options.generateRequestId ?? node_crypto_1.randomUUID;
|
|
434
|
+
if (this.#settings.successSampleExcludePattern) {
|
|
435
|
+
try {
|
|
436
|
+
this.#successSampleExclude = new RegExp(this.#settings.successSampleExcludePattern, 'i');
|
|
437
|
+
}
|
|
438
|
+
catch {
|
|
439
|
+
// An invalid pattern excludes nothing.
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* Get the request chronicle helper for a request, creating it if needed.
|
|
445
|
+
* The logger and options are only used when the helper is created.
|
|
446
|
+
*/
|
|
447
|
+
static fromReq(logger, req, options) {
|
|
448
|
+
const request = req;
|
|
449
|
+
if (request.options === undefined || request.options === null) {
|
|
450
|
+
request.options = {};
|
|
451
|
+
}
|
|
452
|
+
if (request.options.requestChronicleHelper === undefined || request.options.requestChronicleHelper === null) {
|
|
453
|
+
// Make the event accessible to other middleware, plus anywhere that can access the req.
|
|
454
|
+
request.options.requestChronicleHelper = new RequestChronicleHelper(logger, options);
|
|
455
|
+
}
|
|
456
|
+
return request.options.requestChronicleHelper;
|
|
457
|
+
}
|
|
458
|
+
/**
|
|
459
|
+
* Get the request chronicle helper for a request, without creating it.
|
|
460
|
+
* Requests that did not pass through the HTTP middleware (e.g. socket and virtual requests) have no helper.
|
|
461
|
+
*/
|
|
462
|
+
static existing(req) {
|
|
463
|
+
try {
|
|
464
|
+
const helper = req?.options?.requestChronicleHelper;
|
|
465
|
+
return helper?.[helperBrand] === true ? helper : undefined;
|
|
466
|
+
}
|
|
467
|
+
catch {
|
|
468
|
+
return undefined;
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
/**
|
|
472
|
+
* Get the current request chronicle data.
|
|
473
|
+
* Do not use this for logging - use the `log` method.
|
|
474
|
+
*/
|
|
475
|
+
get data() {
|
|
476
|
+
return structuredClone(this.#data);
|
|
477
|
+
}
|
|
478
|
+
/** The request id, generated when the chronicle starts. */
|
|
479
|
+
get requestId() {
|
|
480
|
+
return this.#requestId;
|
|
481
|
+
}
|
|
482
|
+
get settings() {
|
|
483
|
+
return { ...this.#settings };
|
|
484
|
+
}
|
|
485
|
+
get isRunning() {
|
|
486
|
+
return this.#state === 'running';
|
|
487
|
+
}
|
|
488
|
+
get isFinished() {
|
|
489
|
+
return this.#state === 'finished';
|
|
490
|
+
}
|
|
491
|
+
start() {
|
|
492
|
+
this.#safely('start', () => {
|
|
493
|
+
if (this.#state !== 'pending') {
|
|
494
|
+
this.logger.warn('Request Chronicle Helper: Cannot start request chronicle that is running or finished.');
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
this.#state = 'running';
|
|
498
|
+
this.#startedAt = this.#now();
|
|
499
|
+
this.#requestId = this.#generateRequestId();
|
|
500
|
+
this.#data.requestId = this.#requestId;
|
|
501
|
+
const spanContext = api_1.trace.getActiveSpan()?.spanContext();
|
|
502
|
+
if (spanContext && (0, api_1.isSpanContextValid)(spanContext)) {
|
|
503
|
+
this.#data.traceId = spanContext.traceId;
|
|
504
|
+
}
|
|
505
|
+
this.#data.result = { timestamp: new Date().toISOString() };
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
updateReq(req) {
|
|
509
|
+
this.#safely('updateReq', () => {
|
|
510
|
+
if (!this.isRunning || this.#data.req !== undefined) {
|
|
511
|
+
this.logger.warn('Request Chronicle Helper: Cannot update request chronicle that is not running or has existing req.');
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
514
|
+
const path = req.path ?? req.url?.split('?')[0];
|
|
515
|
+
const upstreamRequestId = req.headers?.['x-request-id'];
|
|
516
|
+
this.#data.req = {
|
|
517
|
+
method: typeof req.method === 'string'
|
|
518
|
+
? safeChronicleText(req.method, exports.RequestChronicleLimits.maxKeyLength)
|
|
519
|
+
: undefined,
|
|
520
|
+
path: typeof path === 'string' ? safeChronicleText(path, exports.RequestChronicleLimits.maxStringLength) : undefined,
|
|
521
|
+
hostname: typeof req.hostname === 'string'
|
|
522
|
+
? safeChronicleText(req.hostname, exports.RequestChronicleLimits.maxStringLength)
|
|
523
|
+
: undefined,
|
|
524
|
+
...(typeof upstreamRequestId === 'string' && upstreamRequestIdPattern.test(upstreamRequestId)
|
|
525
|
+
? { upstreamRequestId }
|
|
526
|
+
: {}),
|
|
527
|
+
};
|
|
528
|
+
});
|
|
529
|
+
}
|
|
530
|
+
/**
|
|
531
|
+
* Conclude the request chronicle.
|
|
532
|
+
* Only the first call has an effect.
|
|
533
|
+
* @param res The response. A response that has not finished writing is recorded as aborted.
|
|
534
|
+
* @return True if this call concluded the chronicle, otherwise false.
|
|
535
|
+
*/
|
|
536
|
+
finish(res) {
|
|
537
|
+
let concluded = false;
|
|
538
|
+
this.#safely('finish', () => {
|
|
539
|
+
if (!this.isRunning) {
|
|
540
|
+
return;
|
|
541
|
+
}
|
|
542
|
+
const durationMs = Math.max(0, Math.round(this.#now() - this.#startedAt));
|
|
543
|
+
const completed = res === undefined ? true : res.writableFinished === true;
|
|
544
|
+
const statusCode = res !== undefined && (res.headersSent || res.writableFinished) && Number.isFinite(res.statusCode)
|
|
545
|
+
? res.statusCode
|
|
546
|
+
: undefined;
|
|
547
|
+
this.#state = 'finished';
|
|
548
|
+
this.#data.res = { ...(statusCode !== undefined ? { statusCode } : {}), completed };
|
|
549
|
+
const outcome = this.#outcome(completed, statusCode);
|
|
550
|
+
const classification = this.#classify(completed, statusCode, durationMs);
|
|
551
|
+
this.#data.result = {
|
|
552
|
+
...this.#data.result,
|
|
553
|
+
durationMs,
|
|
554
|
+
outcome,
|
|
555
|
+
classification,
|
|
556
|
+
severity: this.#level(classification) ?? 'none',
|
|
557
|
+
};
|
|
558
|
+
concluded = true;
|
|
559
|
+
});
|
|
560
|
+
return concluded;
|
|
561
|
+
}
|
|
562
|
+
/**
|
|
563
|
+
* Log the finished request chronicle once, at the level for its classification.
|
|
564
|
+
* @param logger The logger to use.
|
|
565
|
+
*/
|
|
566
|
+
log(logger = this.logger) {
|
|
567
|
+
this.#safely('log', () => {
|
|
568
|
+
if (!this.isFinished || this.#logged) {
|
|
569
|
+
return;
|
|
570
|
+
}
|
|
571
|
+
this.#logged = true;
|
|
572
|
+
const classification = this.#data.result?.classification;
|
|
573
|
+
const level = classification ? this.#level(classification) : null;
|
|
574
|
+
if (level !== null) {
|
|
575
|
+
logger[level](toChronicleLogRecord(this.#data), 'Request chronicle');
|
|
576
|
+
}
|
|
577
|
+
});
|
|
578
|
+
}
|
|
579
|
+
get hasErrors() {
|
|
580
|
+
return (this.#data.errors?.length ?? 0) > 0 || (this.#data.errorsOmitted ?? 0) > 0;
|
|
581
|
+
}
|
|
582
|
+
/**
|
|
583
|
+
* Record an error.
|
|
584
|
+
* Errors recorded when the chronicle is not running are logged immediately, with the request id.
|
|
585
|
+
* @param error The error.
|
|
586
|
+
* @param info Safe operation details to include when the error is logged outside a running chronicle.
|
|
587
|
+
*/
|
|
588
|
+
addError(error, info) {
|
|
589
|
+
this.#safely('addError', () => {
|
|
590
|
+
// Services may record a failure before rethrowing it to a controller.
|
|
591
|
+
// Retain that error once while the request runs, without hiding late failures.
|
|
592
|
+
if (this.isRunning && error !== null && typeof error === 'object') {
|
|
593
|
+
if (this.#recordedErrors.has(error)) {
|
|
594
|
+
return;
|
|
595
|
+
}
|
|
596
|
+
this.#recordedErrors.add(error);
|
|
597
|
+
}
|
|
598
|
+
const chronicleError = toChronicleError(error);
|
|
599
|
+
if (!this.isRunning) {
|
|
600
|
+
let safeInfo;
|
|
601
|
+
try {
|
|
602
|
+
if (info !== undefined) {
|
|
603
|
+
safeInfo = sanitizeChronicleValue(info);
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
catch {
|
|
607
|
+
// Hostile details must not suppress the error itself.
|
|
608
|
+
}
|
|
609
|
+
this.logger.error(toChronicleLogRecord({
|
|
610
|
+
requestId: this.#requestId,
|
|
611
|
+
...(safeInfo !== undefined ? { info: safeInfo } : {}),
|
|
612
|
+
error: chronicleError,
|
|
613
|
+
}), this.isFinished
|
|
614
|
+
? 'Request chronicle: error recorded after the request finished.'
|
|
615
|
+
: 'Request chronicle: error recorded without an active request chronicle.');
|
|
616
|
+
return;
|
|
617
|
+
}
|
|
618
|
+
if (!Array.isArray(this.#data.errors)) {
|
|
619
|
+
this.#data.errors = [];
|
|
620
|
+
}
|
|
621
|
+
if (this.#data.errors.length >= exports.RequestChronicleLimits.maxErrors) {
|
|
622
|
+
this.#data.errorsOmitted = (this.#data.errorsOmitted ?? 0) + 1;
|
|
623
|
+
return;
|
|
624
|
+
}
|
|
625
|
+
this.#data.errors.push(chronicleError);
|
|
626
|
+
});
|
|
627
|
+
}
|
|
628
|
+
/**
|
|
629
|
+
* Add arbitrary details to the request chronicle.
|
|
630
|
+
* Values are sanitised and size-bounded.
|
|
631
|
+
* Warnings retain the request and raise its severity to at least warn.
|
|
632
|
+
* Details added after the chronicle finished are logged at the supplied level, with the request id.
|
|
633
|
+
* Details added when there is no running chronicle (e.g. socket requests) are ignored.
|
|
634
|
+
* @param info The details to add.
|
|
635
|
+
* @param level The severity of these details; defaults to debug for late details.
|
|
636
|
+
*/
|
|
637
|
+
addInfo(info, level = 'debug') {
|
|
638
|
+
this.#safely('addInfo', () => {
|
|
639
|
+
if (info === null || info === undefined || typeof info !== 'object') {
|
|
640
|
+
return;
|
|
641
|
+
}
|
|
642
|
+
if (!this.isRunning && !this.isFinished) {
|
|
643
|
+
// There is no request chronicle (e.g. socket requests), so there is nothing to relate the details to.
|
|
644
|
+
return;
|
|
645
|
+
}
|
|
646
|
+
if (this.isRunning && level === 'warn') {
|
|
647
|
+
this.#hasWarnings = true;
|
|
648
|
+
}
|
|
649
|
+
const { entries, omitted } = sanitizeChronicleEntries(info);
|
|
650
|
+
if (entries.length === 0) {
|
|
651
|
+
return;
|
|
652
|
+
}
|
|
653
|
+
if (this.isFinished) {
|
|
654
|
+
this.logger[level](toChronicleLogRecord({
|
|
655
|
+
requestId: this.#requestId,
|
|
656
|
+
info: Object.fromEntries(entries),
|
|
657
|
+
...(omitted > 0 ? { infoOmitted: true } : {}),
|
|
658
|
+
}), 'Request chronicle: details recorded after the request finished.');
|
|
659
|
+
return;
|
|
660
|
+
}
|
|
661
|
+
if (omitted > 0) {
|
|
662
|
+
this.logger.warn('Request Chronicle Helper: Too many request chronicle details, some were ignored.');
|
|
663
|
+
}
|
|
664
|
+
for (const [key, value] of entries) {
|
|
665
|
+
if (reservedKeys.includes(key)) {
|
|
666
|
+
this.logger.warn(`Request Chronicle Helper: Cannot overwrite reserved request chronicle key '${key}'.`);
|
|
667
|
+
continue;
|
|
668
|
+
}
|
|
669
|
+
if (!(key in this.#data) && Object.keys(this.#data).length >= exports.RequestChronicleLimits.maxInfoKeys) {
|
|
670
|
+
this.logger.warn(`Request Chronicle Helper: Too many request chronicle keys, ignoring key '${key}'.`);
|
|
671
|
+
continue;
|
|
672
|
+
}
|
|
673
|
+
// Later values replace earlier values for the same key.
|
|
674
|
+
this.#data[key] = value;
|
|
675
|
+
}
|
|
676
|
+
});
|
|
677
|
+
}
|
|
678
|
+
/**
|
|
679
|
+
* Record the result of work that may continue after the response is sent, such as an audit event.
|
|
680
|
+
* While the request is running, the result is added to the request chronicle.
|
|
681
|
+
* After the request finishes, the result is logged separately, with the request id.
|
|
682
|
+
* @param operation A short name for the operation.
|
|
683
|
+
* @param error The error if the operation failed, otherwise undefined.
|
|
684
|
+
*/
|
|
685
|
+
addOperationResult(operation, error) {
|
|
686
|
+
this.#safely('addOperationResult', () => {
|
|
687
|
+
const name = safeOperationName(operation);
|
|
688
|
+
const failed = error !== undefined;
|
|
689
|
+
if (this.isRunning) {
|
|
690
|
+
this.addInfo({ [name]: failed ? 'failure' : 'success' });
|
|
691
|
+
if (failed) {
|
|
692
|
+
this.addError(error);
|
|
693
|
+
}
|
|
694
|
+
return;
|
|
695
|
+
}
|
|
696
|
+
const details = { requestId: this.#requestId, operation: name, outcome: failed ? 'failure' : 'success' };
|
|
697
|
+
if (failed) {
|
|
698
|
+
this.logger.error(toChronicleLogRecord({ ...details, error: toChronicleError(error) }), `Request chronicle: operation '${name}' failed after the request finished.`);
|
|
699
|
+
}
|
|
700
|
+
else {
|
|
701
|
+
this.logger.debug(details, `Request chronicle: operation '${name}' succeeded after the request finished.`);
|
|
702
|
+
}
|
|
703
|
+
});
|
|
704
|
+
}
|
|
705
|
+
#outcome(completed, statusCode) {
|
|
706
|
+
if (!completed) {
|
|
707
|
+
return 'aborted';
|
|
708
|
+
}
|
|
709
|
+
if ((statusCode ?? 0) >= 400 || this.hasErrors) {
|
|
710
|
+
return 'failure';
|
|
711
|
+
}
|
|
712
|
+
return 'success';
|
|
713
|
+
}
|
|
714
|
+
/**
|
|
715
|
+
* Classify this request chronicle.
|
|
716
|
+
* Keep all failed, aborted, slow, and warning requests, and a sample of the successful requests.
|
|
717
|
+
*/
|
|
718
|
+
#classify(completed, statusCode, durationMs) {
|
|
719
|
+
const status = statusCode ?? 0;
|
|
720
|
+
if (status >= 500) {
|
|
721
|
+
return 'error';
|
|
722
|
+
}
|
|
723
|
+
if (status >= 400) {
|
|
724
|
+
return 'client-error';
|
|
725
|
+
}
|
|
726
|
+
if (this.hasErrors) {
|
|
727
|
+
return 'error';
|
|
728
|
+
}
|
|
729
|
+
if (!completed) {
|
|
730
|
+
return 'aborted';
|
|
731
|
+
}
|
|
732
|
+
if (durationMs > this.#settings.slowThresholdMs) {
|
|
733
|
+
return 'slow';
|
|
734
|
+
}
|
|
735
|
+
if (this.#hasWarnings) {
|
|
736
|
+
return 'warning';
|
|
737
|
+
}
|
|
738
|
+
const path = this.#data.req?.path;
|
|
739
|
+
if (this.#successSampleExclude !== null && typeof path === 'string' && this.#successSampleExclude.test(path)) {
|
|
740
|
+
return 'discard';
|
|
741
|
+
}
|
|
742
|
+
return this.#random() < this.#settings.successSampleRate ? 'sample' : 'discard';
|
|
743
|
+
}
|
|
744
|
+
#level(classification) {
|
|
745
|
+
if ((classification === 'client-error' && this.hasErrors) ||
|
|
746
|
+
(this.#hasWarnings && classificationLevels[classification] === 'info')) {
|
|
747
|
+
return 'warn';
|
|
748
|
+
}
|
|
749
|
+
return classificationLevels[classification];
|
|
750
|
+
}
|
|
751
|
+
/**
|
|
752
|
+
* Run a function, logging instead of throwing any error, so that recording never breaks the request.
|
|
753
|
+
*/
|
|
754
|
+
#safely(name, func) {
|
|
755
|
+
try {
|
|
756
|
+
func();
|
|
757
|
+
}
|
|
758
|
+
catch {
|
|
759
|
+
try {
|
|
760
|
+
// Don't include the error: it may come from hostile or unprintable input.
|
|
761
|
+
this.logger.warn(`Request Chronicle Helper: '${name}' failed.`);
|
|
762
|
+
}
|
|
763
|
+
catch {
|
|
764
|
+
// Ignore logging failures.
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
exports.RequestChronicleHelper = RequestChronicleHelper;
|
|
770
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUmVxdWVzdENocm9uaWNsZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy91dGlsaXRpZXMvUmVxdWVzdENocm9uaWNsZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFvTEEsc0RBTUM7QUFRRCw4Q0FvQkM7QUF5Q0Qsd0RBV0M7QUF3RUQsMERBY0M7QUFvQkQsNENBbUJDO0FBaUhELG9EQVFDO0FBaGdCRCw2Q0FBeUM7QUFDekMscURBQThDO0FBQzlDLDRDQUErRDtBQUcvRCxxREFBZ0Q7QUFDaEQseUVBQXVHO0FBRXZHLHVFQUE0RztBQUFuRywySUFBQSwrQkFBK0IsT0FBQTtBQUV4Qzs7Ozs7R0FLRztBQUNVLFFBQUEsd0JBQXdCLEdBQUcsQ0FBQyxTQUFTLEVBQUUsU0FBUyxFQUFFLFNBQVMsQ0FBVSxDQUFDO0FBR25GOztHQUVHO0FBQ1UsUUFBQSwrQkFBK0IsR0FBRztJQUM3QyxPQUFPO0lBQ1AsY0FBYztJQUNkLFNBQVM7SUFDVCxNQUFNO0lBQ04sU0FBUztJQUNULFFBQVE7SUFDUixTQUFTO0NBQ0QsQ0FBQztBQUdYOzs7R0FHRztBQUNILE1BQU0sb0JBQW9CLEdBQWtGO0lBQzFHLEtBQUssRUFBRSxPQUFPO0lBQ2QsY0FBYyxFQUFFLE1BQU07SUFDdEIsT0FBTyxFQUFFLE1BQU07SUFDZixJQUFJLEVBQUUsTUFBTTtJQUNaLE9BQU8sRUFBRSxNQUFNO0lBQ2YsTUFBTSxFQUFFLE1BQU07SUFDZCxPQUFPLEVBQUUsSUFBSTtDQUNkLENBQUM7QUFtRkY7O0dBRUc7QUFDVSxRQUFBLHNCQUFzQixHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUM7SUFDbEQsUUFBUSxFQUFFLENBQUM7SUFDWCxlQUFlLEVBQUUsR0FBRztJQUNwQixhQUFhLEVBQUUsRUFBRTtJQUNqQixhQUFhLEVBQUUsRUFBRTtJQUNqQixrQkFBa0IsRUFBRSxJQUFJO0lBQ3hCLFdBQVcsRUFBRSxHQUFHO0lBQ2hCLFNBQVMsRUFBRSxFQUFFO0lBQ2IsYUFBYSxFQUFFLENBQUM7SUFDaEIsZUFBZSxFQUFFLEVBQUU7SUFDbkIscUJBQXFCLEVBQUUsSUFBSTtJQUMzQixrQkFBa0IsRUFBRSxJQUFJO0lBQ3hCLGNBQWMsRUFBRSxJQUFJO0lBQ3BCLGFBQWEsRUFBRSxFQUFFO0lBQ2pCLFlBQVksRUFBRSxHQUFHO0NBQ2xCLENBQUMsQ0FBQztBQUVILE1BQU0sWUFBWSxHQUFHO0lBQ25CLDRCQUE0QjtJQUM1QixXQUFXO0lBQ1gsU0FBUztJQUNULFFBQVE7SUFDUixLQUFLO0lBQ0wsS0FBSztJQUNMLFFBQVE7SUFDUixlQUFlO0lBQ2Ysd0VBQXdFO0lBQ3hFLE9BQU87SUFDUCxNQUFNO0lBQ04sS0FBSztJQUNMLFVBQVU7SUFDVixNQUFNO0lBQ04sS0FBSztJQUNMLEtBQUs7SUFDTCxHQUFHO0NBQ0osQ0FBQztBQUNGLE1BQU0sbUJBQW1CLEdBQUcsdUVBQXVFLENBQUM7QUFDcEcsTUFBTSx3QkFBd0IsR0FBRywwQkFBMEIsQ0FBQztBQUM1RCxNQUFNLGlCQUFpQixHQUF1QjtJQUM1QyxzRUFBc0U7SUFDdEUsQ0FBQyxpQ0FBaUMsRUFBRSxjQUFjLENBQUM7SUFDbkQsK0JBQStCO0lBQy9CLENBQUMsMEVBQTBFLEVBQUUsWUFBWSxDQUFDO0NBQzNGLENBQUM7QUFFRjs7O0dBR0c7QUFDSCxTQUFnQixxQkFBcUIsQ0FBQyxLQUFhO0lBQ2pELElBQUksTUFBTSxHQUFHLEtBQUssQ0FBQztJQUNuQixLQUFLLE1BQU0sQ0FBQyxPQUFPLEVBQUUsV0FBVyxDQUFDLElBQUksaUJBQWlCLEVBQUUsQ0FBQztRQUN2RCxNQUFNLEdBQUcsTUFBTSxDQUFDLE9BQU8sQ0FBQyxPQUFPLEVBQUUsV0FBVyxDQUFDLENBQUM7SUFDaEQsQ0FBQztJQUNELE9BQU8sTUFBTSxDQUFDO0FBQ2hCLENBQUM7QUFFRDs7Ozs7R0FLRztBQUNILFNBQWdCLGlCQUFpQixDQUFDLEtBQWMsRUFBRSxTQUFpQjtJQUNqRSxJQUFJLElBQVksQ0FBQztJQUNqQixJQUFJLENBQUM7UUFDSCxJQUFJLEdBQUcsT0FBTyxLQUFLLEtBQUssUUFBUSxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUMzRCxDQUFDO0lBQUMsTUFBTSxDQUFDO1FBQ1AsT0FBTyxlQUFlLENBQUM7SUFDekIsQ0FBQztJQUNELDBGQUEwRjtJQUMxRixNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsTUFBTSxHQUFHLFNBQVMsR0FBRyxHQUFHLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxFQUFFLFNBQVMsR0FBRyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDO0lBQ3ZGLE1BQU0sUUFBUSxHQUFHLHFCQUFxQixDQUFDLE1BQU0sQ0FBQyxJQUFBLDZCQUFZLEVBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztRQUNoRSw4RUFBOEU7U0FDN0UsT0FBTyxDQUFDLHFDQUFxQyxFQUFFLFlBQVksQ0FBQztTQUM1RCxPQUFPLENBQUMsMkRBQTJELEVBQUUsVUFBVSxDQUFDO1NBQ2hGLE9BQU8sQ0FBQyxvQ0FBb0MsRUFBRSxVQUFVLENBQUMsQ0FBQztJQUM3RCxJQUFJLFFBQVEsQ0FBQyxNQUFNLElBQUksU0FBUyxJQUFJLElBQUksQ0FBQyxNQUFNLEtBQUssSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO1FBQ2hFLE9BQU8sUUFBUSxDQUFDO0lBQ2xCLENBQUM7SUFDRCx5REFBeUQ7SUFDekQsTUFBTSxTQUFTLEdBQUcsUUFBUSxDQUFDLFNBQVMsQ0FBQyxDQUFDLEVBQUUsU0FBUyxDQUFDLENBQUMsT0FBTyxDQUFDLDBCQUEwQixFQUFFLFlBQVksQ0FBQyxDQUFDO0lBQ3JHLE9BQU8sR0FBRyxTQUFTLGVBQWUsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsTUFBTSxHQUFHLFNBQVMsRUFBRSxDQUFDLENBQUMsU0FBUyxDQUFDO0FBQ2xGLENBQUM7QUFFRCxTQUFTLGNBQWMsQ0FBQyxHQUFXO0lBQ2pDLE9BQU8sbUJBQW1CLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0FBQ3ZDLENBQUM7QUFFRDs7O0dBR0c7QUFDSCxTQUFTLHdCQUF3QixDQUFDLElBQTZCO0lBQzdELE1BQU0sT0FBTyxHQUF3QixFQUFFLENBQUM7SUFDeEMsSUFBSSxPQUFPLEdBQUcsQ0FBQyxDQUFDO0lBQ2hCLEtBQUssTUFBTSxNQUFNLElBQUksSUFBSSxFQUFFLENBQUM7UUFDMUIsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsTUFBTSxDQUFDLEVBQUUsQ0FBQztZQUN4RCxTQUFTO1FBQ1gsQ0FBQztRQUNELElBQUksT0FBTyxDQUFDLE1BQU0sSUFBSSw4QkFBc0IsQ0FBQyxXQUFXLEVBQUUsQ0FBQztZQUN6RCxPQUFPLElBQUksQ0FBQyxDQUFDO1lBQ2IsTUFBTTtRQUNSLENBQUM7UUFDRCxNQUFNLEdBQUcsR0FBRyxpQkFBaUIsQ0FBQyxNQUFNLEVBQUUsOEJBQXNCLENBQUMsWUFBWSxDQUFDLENBQUM7UUFDM0UsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLEdBQUcsRUFBRSxjQUFjLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsc0JBQXNCLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ2xHLENBQUM7SUFDRCxPQUFPLEVBQUUsT0FBTyxFQUFFLE9BQU8sRUFBRSxDQUFDO0FBQzlCLENBQUM7QUFFRDs7R0FFRztBQUNILFNBQVMsaUJBQWlCLENBQUMsU0FBa0I7SUFDM0MsT0FBTyxDQUNMLGlCQUFpQixDQUFDLFNBQVMsRUFBRSw4QkFBc0IsQ0FBQyxZQUFZLENBQUMsQ0FBQyxPQUFPLENBQUMsbUJBQW1CLEVBQUUsR0FBRyxDQUFDLElBQUksV0FBVyxDQUNuSCxDQUFDO0FBQ0osQ0FBQztBQUVEOzs7O0dBSUc7QUFDSCxTQUFnQixzQkFBc0IsQ0FBQyxLQUFjO0lBQ25ELE1BQU0sU0FBUyxHQUFHLGFBQWEsQ0FBQyxLQUFLLEVBQUUsQ0FBQyxFQUFFLElBQUksT0FBTyxFQUFVLENBQUMsQ0FBQztJQUNqRSxJQUFJLENBQUM7UUFDSCxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBQ3ZDLElBQUksSUFBSSxLQUFLLFNBQVMsSUFBSSxJQUFJLENBQUMsTUFBTSxHQUFHLDhCQUFzQixDQUFDLGtCQUFrQixFQUFFLENBQUM7WUFDbEYsT0FBTyxFQUFFLFNBQVMsRUFBRSxJQUFJLEVBQUUsVUFBVSxFQUFFLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQztRQUN0RCxDQUFDO0lBQ0gsQ0FBQztJQUFDLE1BQU0sQ0FBQztRQUNQLE9BQU8sa0JBQWtCLENBQUM7SUFDNUIsQ0FBQztJQUNELE9BQU8sU0FBUyxDQUFDO0FBQ25CLENBQUM7QUFFRCxTQUFTLGFBQWEsQ0FBQyxLQUFjLEVBQUUsS0FBYSxFQUFFLElBQXFCO0lBQ3pFLElBQUksS0FBSyxLQUFLLElBQUksSUFBSSxLQUFLLEtBQUssU0FBUyxJQUFJLE9BQU8sS0FBSyxLQUFLLFNBQVMsSUFBSSxPQUFPLEtBQUssS0FBSyxRQUFRLEVBQUUsQ0FBQztRQUNyRyxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFDRCxJQUFJLE9BQU8sS0FBSyxLQUFLLFFBQVEsRUFBRSxDQUFDO1FBQzlCLE9BQU8saUJBQWlCLENBQUMsS0FBSyxFQUFFLDhCQUFzQixDQUFDLGVBQWUsQ0FBQyxDQUFDO0lBQzFFLENBQUM7SUFDRCxJQUFJLE9BQU8sS0FBSyxLQUFLLFFBQVEsRUFBRSxDQUFDO1FBQzlCLE9BQU8sS0FBSyxDQUFDLFFBQVEsRUFBRSxDQUFDO0lBQzFCLENBQUM7SUFDRCxJQUFJLE9BQU8sS0FBSyxLQUFLLFVBQVUsRUFBRSxDQUFDO1FBQ2hDLE9BQU8sWUFBWSxDQUFDO0lBQ3RCLENBQUM7SUFDRCxJQUFJLE9BQU8sS0FBSyxLQUFLLFFBQVEsRUFBRSxDQUFDO1FBQzlCLE9BQU8sTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ3ZCLENBQUM7SUFDRCxJQUFJLEtBQUssWUFBWSxJQUFJLEVBQUUsQ0FBQztRQUMxQixPQUFPLE1BQU0sQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLGNBQWMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLFdBQVcsRUFBRSxDQUFDO0lBQzlFLENBQUM7SUFDRCxJQUFJLEtBQUssWUFBWSxLQUFLLEVBQUUsQ0FBQztRQUMzQixPQUFPLHFCQUFxQixDQUFDLEtBQUssRUFBRSxLQUFLLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFDbkQsQ0FBQztJQUNELElBQUksTUFBTSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO1FBQzNCLE9BQU8sV0FBVyxLQUFLLENBQUMsTUFBTSxTQUFTLENBQUM7SUFDMUMsQ0FBQztJQUNELElBQUksSUFBSSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO1FBQ3BCLE9BQU8sWUFBWSxDQUFDO0lBQ3RCLENBQUM7SUFDRCxJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztRQUN6QixJQUFJLEtBQUssSUFBSSw4QkFBc0IsQ0FBQyxRQUFRLEVBQUUsQ0FBQztZQUM3QyxPQUFPLFVBQVUsS0FBSyxDQUFDLE1BQU0sSUFBSSxDQUFDO1FBQ3BDLENBQUM7UUFDRCxJQUFJLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ2hCLE1BQU0sS0FBSyxHQUFHLEtBQUs7YUFDaEIsS0FBSyxDQUFDLENBQUMsRUFBRSw4QkFBc0IsQ0FBQyxhQUFhLENBQUM7YUFDOUMsR0FBRyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsYUFBYSxDQUFDLElBQUksRUFBRSxLQUFLLEdBQUcsQ0FBQyxFQUFFLElBQUksQ0FBQyxDQUFDLENBQUM7UUFDckQsSUFBSSxLQUFLLENBQUMsTUFBTSxHQUFHLDhCQUFzQixDQUFDLGFBQWEsRUFBRSxDQUFDO1lBQ3hELEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxLQUFLLENBQUMsTUFBTSxHQUFHLDhCQUFzQixDQUFDLGFBQWEsYUFBYSxDQUFDLENBQUM7UUFDbkYsQ0FBQztRQUNELElBQUksQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDbkIsT0FBTyxLQUFLLENBQUM7SUFDZixDQUFDO0lBQ0QsSUFBSSxLQUFLLElBQUksOEJBQXNCLENBQUMsUUFBUSxFQUFFLENBQUM7UUFDN0MsT0FBTyxVQUFVLENBQUM7SUFDcEIsQ0FBQztJQUNELElBQUksQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDaEIsTUFBTSxNQUFNLEdBQTRCLEVBQUUsQ0FBQztJQUMzQyxJQUFJLEtBQUssR0FBRyxDQUFDLENBQUM7SUFDZCxLQUFLLE1BQU0sR0FBRyxJQUFJLEtBQUssRUFBRSxDQUFDO1FBQ3hCLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsS0FBSyxFQUFFLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDdEQsU0FBUztRQUNYLENBQUM7UUFDRCxJQUFJLEtBQUssSUFBSSw4QkFBc0IsQ0FBQyxhQUFhLEVBQUUsQ0FBQztZQUNsRCxNQUFNLENBQUMsR0FBRyxDQUFDLEdBQUcsbUJBQW1CLENBQUM7WUFDbEMsTUFBTTtRQUNSLENBQUM7UUFDRCxLQUFLLElBQUksQ0FBQyxDQUFDO1FBQ1gsTUFBTSxDQUFDLGlCQUFpQixDQUFDLEdBQUcsRUFBRSw4QkFBc0IsQ0FBQyxZQUFZLENBQUMsQ0FBQyxHQUFHLGNBQWMsQ0FBQyxHQUFHLENBQUM7WUFDdkYsQ0FBQyxDQUFDLFVBQVU7WUFDWixDQUFDLENBQUMsYUFBYSxDQUFFLEtBQWlDLENBQUMsR0FBRyxDQUFDLEVBQUUsS0FBSyxHQUFHLENBQUMsRUFBRSxJQUFJLENBQUMsQ0FBQztJQUM5RSxDQUFDO0lBQ0QsSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUNuQixPQUFPLE1BQU0sQ0FBQztBQUNoQixDQUFDO0FBRUQ7Ozs7R0FJRztBQUNILFNBQWdCLHVCQUF1QixDQUFDLEtBQWM7SUFDcEQsSUFBSSxLQUFLLEtBQUssSUFBSSxFQUFFLENBQUM7UUFDbkIsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsQ0FBQztJQUMxQixDQUFDO0lBQ0QsSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7UUFDekIsT0FBTyxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsTUFBTSxFQUFFLEtBQUssQ0FBQyxNQUFNLEVBQUUsQ0FBQztJQUNqRCxDQUFDO0lBQ0QsSUFBSSxPQUFPLEtBQUssS0FBSyxRQUFRLEVBQUUsQ0FBQztRQUM5QixPQUFPLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxNQUFNLEVBQUUsS0FBSyxDQUFDLE1BQU0sRUFBRSxDQUFDO0lBQ2xELENBQUM7SUFDRCxJQUFJLE9BQU8sS0FBSyxLQUFLLFFBQVEsRUFBRSxDQUFDO1FBQzlCLE9BQU8sRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLFFBQVEsRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDO0lBQ2pFLENBQUM7SUFDRCxPQUFPLEVBQUUsSUFBSSxFQUFFLE9BQU8sS0FBSyxFQUFFLENBQUM7QUFDaEMsQ0FBQztBQUVELFNBQVMsdUJBQXVCLENBQUMsSUFBVztJQUMxQyxPQUFPLElBQUksQ0FBQyxJQUFJLEtBQUssbUJBQW1CLElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBRSxJQUFvQyxDQUFDLGFBQWEsQ0FBQyxDQUFDO0FBQ2pILENBQUM7QUFFRCwyRUFBMkU7QUFDM0UsTUFBTSxtQkFBbUI7SUFFWjtJQUNBO0lBRlgsWUFDVyxJQUF3QixFQUN4QixPQUFlO1FBRGYsU0FBSSxHQUFKLElBQUksQ0FBb0I7UUFDeEIsWUFBTyxHQUFQLE9BQU8sQ0FBUTtJQUN2QixDQUFDO0NBQ0w7QUFFRDs7Ozs7R0FLRztBQUNILFNBQWdCLGdCQUFnQixDQUFDLElBQWE7SUFDNUMsSUFBSSxDQUFDO1FBQ0gsTUFBTSxNQUFNLEdBQUcscUJBQXFCLENBQUMsSUFBSSxFQUFFLENBQUMsRUFBRSxJQUFJLE9BQU8sRUFBVSxDQUFDLENBQUM7UUFDckUsK0VBQStFO1FBQy9FLE1BQU0sRUFBRSxPQUFPLEVBQUUsUUFBUSxFQUFFLEdBQUcsY0FBYyxFQUFFLEdBQUcsTUFBTSxDQUFDO1FBQ3hELE1BQU0sRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLEdBQUcsT0FBTyxFQUFFLEdBQUcsY0FBYyxDQUFDO1FBQ3JELE1BQU0sVUFBVSxHQUFHO1lBQ2pCLE1BQU07WUFDTixFQUFFLEdBQUcsY0FBYyxFQUFFLE9BQU8sRUFBRSxDQUFDLEVBQUUsT0FBTyxFQUFFLG9DQUFvQyxFQUFFLENBQUMsRUFBRTtZQUNuRixFQUFFLEdBQUcsT0FBTyxFQUFFLE9BQU8sRUFBRSxDQUFDLEVBQUUsT0FBTyxFQUFFLDhDQUE4QyxFQUFFLENBQUMsRUFBRTtTQUN2RixDQUFDO1FBQ0YsT0FBTyxDQUNMLFVBQVUsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLFNBQVMsQ0FBQyxDQUFDLE1BQU0sSUFBSSw4QkFBc0IsQ0FBQyxrQkFBa0IsQ0FBQyxJQUFJO1lBQzdHLE9BQU8sRUFBRSxvQ0FBb0M7U0FDOUMsQ0FDRixDQUFDO0lBQ0osQ0FBQztJQUFDLE1BQU0sQ0FBQztRQUNQLE9BQU8sRUFBRSxPQUFPLEVBQUUsNkJBQTZCLEVBQUUsQ0FBQztJQUNwRCxDQUFDO0FBQ0gsQ0FBQztBQUVELFNBQVMscUJBQXFCLENBQUMsSUFBYSxFQUFFLEtBQWEsRUFBRSxJQUFxQjtJQUNoRixNQUFNLE1BQU0sR0FBRyw4QkFBc0IsQ0FBQztJQUN0QyxJQUFJLElBQUksWUFBWSxLQUFLLElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO1FBQ2pELElBQUksSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO1lBQ25CLE9BQU8sRUFBRSxPQUFPLEVBQUUsWUFBWSxFQUFFLENBQUM7UUFDbkMsQ0FBQztRQUNELElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDakIsQ0FBQztJQUVELE1BQU0sTUFBTSxHQUEwQixFQUFFLENBQUM7SUFDekMsd0VBQXdFO0lBQ3hFLE1BQU0sVUFBVSxHQUFHLE1BQU0sQ0FBQyxlQUFlLENBQUM7SUFDMUMsTUFBTSxPQUFPLEdBQWMsRUFBRSxDQUFDO0lBQzlCLElBQUksWUFBWSxHQUFHLENBQUMsQ0FBQztJQUNyQixNQUFNLFVBQVUsR0FBRyxDQUFDLEtBQXlCLEVBQUUsRUFBRTtRQUMvQyxZQUFZLElBQUksS0FBSyxDQUFDLE1BQU0sQ0FBQztRQUM3QixNQUFNLFNBQVMsR0FBRyxVQUFVLEdBQUcsT0FBTyxDQUFDLE1BQU0sQ0FBQztRQUM5QyxJQUFJLFNBQVMsR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUNsQixPQUFPLENBQUMsSUFBSSxDQUFDLEdBQUcsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsU0FBUyxDQUFDLENBQUMsQ0FBQztRQUM3QyxDQUFDO0lBQ0gsQ0FBQyxDQUFDO0lBRUYsSUFBSSxJQUFJLFlBQVksS0FBSyxFQUFFLENBQUM7UUFDMUIsSUFBSSxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDZCxNQUFNLENBQUMsSUFBSSxHQUFHLGlCQUFpQixDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsTUFBTSxDQUFDLGVBQWUsQ0FBQyxDQUFDO1FBQ3JFLENBQUM7UUFDRCxJQUFJLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUNqQixNQUFNLENBQUMsT0FBTyxHQUFHLGlCQUFpQixDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsTUFBTSxDQUFDLHFCQUFxQixDQUFDLENBQUM7UUFDakYsQ0FBQztRQUNELE1BQU0sSUFBSSxHQUFJLElBQTJCLENBQUMsSUFBSSxDQUFDO1FBQy9DLElBQUksT0FBTyxJQUFJLEtBQUssUUFBUSxJQUFJLE9BQU8sSUFBSSxLQUFLLFFBQVEsRUFBRSxDQUFDO1lBQ3pELE1BQU0sQ0FBQyxJQUFJLEdBQUcsaUJBQWlCLENBQUMsSUFBSSxFQUFFLE1BQU0sQ0FBQyxlQUFlLENBQUMsQ0FBQztRQUNoRSxDQUFDO1FBQ0QsSUFBSSx1QkFBdUIsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO1lBQ2xDLE1BQU0sYUFBYSxHQUFHLElBQUksQ0FBQyxhQUFhLENBQUM7WUFDekMsWUFBWSxJQUFJLGFBQWEsQ0FBQyxNQUFNLENBQUM7WUFDckMsT0FBTyxDQUFDLElBQUksQ0FDVixHQUFHLGFBQWEsQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLFVBQVUsQ0FBQyxDQUFDLEdBQUcsQ0FDdkMsWUFBWSxDQUFDLEVBQUUsQ0FDYixJQUFJLG1CQUFtQixDQUNyQixZQUFZLEVBQUUsS0FBSyxLQUFLLFNBQVMsSUFBSSxZQUFZLEVBQUUsS0FBSyxLQUFLLElBQUk7Z0JBQy9ELENBQUMsQ0FBQyxpQkFBaUIsQ0FBQyxZQUFZLENBQUMsS0FBSyxFQUFFLE1BQU0sQ0FBQyxlQUFlLENBQUM7Z0JBQy9ELENBQUMsQ0FBQyxTQUFTLEVBQ2IsaUJBQWlCLENBQ2YsTUFBTSxDQUFDLE9BQU8sQ0FBQztnQkFDYixFQUFFLEVBQUUsWUFBWSxFQUFFLEVBQUU7Z0JBQ3BCLE1BQU0sRUFBRSxZQUFZLEVBQUUsTUFBTTtnQkFDNUIsSUFBSSxFQUFFLFlBQVksRUFBRSxJQUFJO2dCQUN4QixNQUFNLEVBQUUsWUFBWSxFQUFFLE1BQU07YUFDN0IsQ0FBQztpQkFDQyxNQUFNLENBQUMsQ0FBQyxDQUFDLElBQUksRUFBRSxLQUFLLENBQUMsRUFBRSxFQUFFLENBQUMsS0FBSyxLQUFLLFNBQVMsSUFBSSxLQUFLLEtBQUssSUFBSSxDQUFDO2lCQUNoRSxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBRSxLQUFLLENBQUMsRUFBRSxFQUFFLENBQUMsR0FBRyxHQUFHLEtBQUssaUJBQWlCLENBQUMsS0FBSyxFQUFFLE1BQU0sQ0FBQyxlQUFlLENBQUMsRUFBRSxDQUFDO2lCQUNwRixJQUFJLENBQUMsSUFBSSxDQUFDLEVBQ2IsTUFBTSxDQUFDLHFCQUFxQixDQUM3QixDQUNGLENBQ0osQ0FDRixDQUFDO1FBQ0osQ0FBQzthQUFNLElBQUksS0FBSyxLQUFLLENBQUMsSUFBSSxPQUFPLElBQUksQ0FBQyxLQUFLLEtBQUssUUFBUSxFQUFFLENBQUM7WUFDekQsMENBQTBDO1lBQzFDLE1BQU0sQ0FBQyxLQUFLLEdBQUcsaUJBQWlCLENBQUMsSUFBSSxDQUFDLEtBQUssRUFBRSxNQUFNLENBQUMsY0FBYyxDQUFDO2lCQUNoRSxLQUFLLENBQUMsSUFBSSxDQUFDO2lCQUNYLEtBQUssQ0FBQyxDQUFDLEVBQUUsTUFBTSxDQUFDLGFBQWEsQ0FBQztpQkFDOUIsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ2hCLENBQUM7UUFDRCxJQUFJLElBQUksQ0FBQyxLQUFLLEtBQUssU0FBUyxJQUFJLElBQUksQ0FBQyxLQUFLLEtBQUssSUFBSSxFQUFFLENBQUM7WUFDcEQsVUFBVSxDQUFDLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7UUFDM0IsQ0FBQztRQUNELElBQUksT0FBTyxlQUFlLEtBQUssV0FBVyxJQUFJLElBQUksWUFBWSxlQUFlLEVBQUUsQ0FBQztZQUM5RSxVQUFVLENBQUMsQ0FBQyxJQUFJLENBQUMsS0FBSyxFQUFFLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDO1FBQzVDLENBQUM7UUFDRCxJQUFJLElBQUksWUFBWSxjQUFjLElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQztZQUNqRSxVQUFVLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQzFCLENBQUM7SUFDSCxDQUFDO1NBQU0sSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7UUFDL0IsVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ25CLENBQUM7U0FBTSxJQUFJLE9BQU8sSUFBSSxLQUFLLFFBQVEsRUFBRSxDQUFDO1FBQ3BDLE1BQU0sQ0FBQyxPQUFPLEdBQUcsaUJBQWlCLENBQUMsSUFBSSxFQUFFLE1BQU0sQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDO0lBQ3pFLENBQUM7U0FBTSxJQUFJLElBQUksS0FBSyxJQUFJLElBQUksT0FBTyxJQUFJLEtBQUssUUFBUSxJQUFJLE9BQVEsSUFBOEIsQ0FBQyxPQUFPLEtBQUssUUFBUSxFQUFFLENBQUM7UUFDcEgsTUFBTSxDQUFDLE9BQU8sR0FBRyxpQkFBaUIsQ0FBRSxJQUE0QixDQUFDLE9BQU8sRUFBRSxNQUFNLENBQUMscUJBQXFCLENBQUMsQ0FBQztJQUMxRyxDQUFDO1NBQU0sQ0FBQztRQUNOLE1BQU0sU0FBUyxHQUFHLGFBQWEsQ0FBQyxJQUFJLEVBQUUsS0FBSyxFQUFFLElBQUksQ0FBQyxDQUFDO1FBQ25ELE1BQU0sQ0FBQyxPQUFPLEdBQUcsaUJBQWlCLENBQ2hDLE9BQU8sU0FBUyxLQUFLLFFBQVEsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsU0FBUyxDQUFDLElBQUksTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLEVBQ3ZGLE1BQU0sQ0FBQyxxQkFBcUIsQ0FDN0IsQ0FBQztJQUNKLENBQUM7SUFFRCxJQUFJLFlBQVksR0FBRyxDQUFDLEVBQUUsQ0FBQztRQUNyQixJQUFJLEtBQUssSUFBSSxNQUFNLENBQUMsYUFBYSxFQUFFLENBQUM7WUFDbEMsTUFBTSxDQUFDLE9BQU8sR0FBRyxDQUFDLEVBQUUsT0FBTyxFQUFFLEdBQUcsWUFBWSx3QkFBd0IsRUFBRSxDQUFDLENBQUM7UUFDMUUsQ0FBQzthQUFNLENBQUM7WUFDTixNQUFNLENBQUMsT0FBTyxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLEVBQUU7Z0JBQ3BDLElBQUksTUFBTSxZQUFZLG1CQUFtQixFQUFFLENBQUM7b0JBQzFDLE9BQU8sRUFBRSxHQUFHLENBQUMsTUFBTSxDQUFDLElBQUksS0FBSyxTQUFTLENBQUMsQ0FBQyxDQUFDLEVBQUUsSUFBSSxFQUFFLE1BQU0sQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsT0FBTyxFQUFFLE1BQU0sQ0FBQyxPQUFPLEVBQUUsQ0FBQztnQkFDbEcsQ0FBQztnQkFDRCxPQUFPLHFCQUFxQixDQUFDLE1BQU0sRUFBRSxLQUFLLEdBQUcsQ0FBQyxFQUFFLElBQUksQ0FBQyxDQUFDO1lBQ3hELENBQUMsQ0FBQyxDQUFDO1lBQ0gsSUFBSSxZQUFZLEdBQUcsT0FBTyxDQUFDLE1BQU0sRUFBRSxDQUFDO2dCQUNsQyxNQUFNLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxFQUFFLE9BQU8sRUFBRSxHQUFHLFlBQVksR0FBRyxPQUFPLENBQUMsTUFBTSxzQkFBc0IsRUFBRSxDQUFDLENBQUM7WUFDM0YsQ0FBQztRQUNILENBQUM7SUFDSCxDQUFDO0lBQ0QsT0FBTyxNQUFNLENBQUM7QUFDaEIsQ0FBQztBQUVEOzs7O0dBSUc7QUFDSCxTQUFnQixvQkFBb0IsQ0FBQyxLQUFjO0lBQ2pELElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO1FBQ3pCLE9BQU8sTUFBTSxDQUFDLFdBQVcsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxFQUFFLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLEVBQUUsb0JBQW9CLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDckcsQ0FBQztJQUNELElBQUksS0FBSyxLQUFLLElBQUksSUFBSSxPQUFPLEtBQUssS0FBSyxRQUFRLEVBQUUsQ0FBQztRQUNoRCxPQUFPLE1BQU0sQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBRSxJQUFJLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxHQUFHLEVBQUUsb0JBQW9CLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDM0csQ0FBQztJQUNELE9BQU8sS0FBSyxDQUFDO0FBQ2YsQ0FBQztBQUlELHFFQUFxRTtBQUNyRSxNQUFNLFdBQVcsR0FBRyxNQUFNLENBQUMsR0FBRyxDQUFDLHFEQUFxRCxDQUFDLENBQUM7QUFFdEYsTUFBYSxzQkFBc0I7SUFnQnZCO0lBZk8sQ0FBQyxXQUFXLENBQUMsR0FBRyxJQUFJLENBQUM7SUFDdEMsS0FBSyxHQUFxQixFQUFFLENBQUM7SUFDcEIsZUFBZSxHQUFHLElBQUksT0FBTyxFQUFVLENBQUM7SUFDakQsTUFBTSxHQUFtQixTQUFTLENBQUM7SUFDbkMsVUFBVSxHQUFHLENBQUMsQ0FBQztJQUNmLE9BQU8sR0FBRyxLQUFLLENBQUM7SUFDaEIsWUFBWSxHQUFHLEtBQUssQ0FBQztJQUNyQixVQUFVLENBQVU7SUFDWCxTQUFTLENBQTJCO0lBQ3BDLE9BQU8sQ0FBZTtJQUN0QixJQUFJLENBQWU7SUFDbkIsa0JBQWtCLENBQWU7SUFDakMscUJBQXFCLEdBQWtCLElBQUksQ0FBQztJQUVyRCxZQUNVLE1BQWUsRUFDdkIsVUFBbUMsRUFBRTtRQUQ3QixXQUFNLEdBQU4sTUFBTSxDQUFTO1FBR3ZCLE1BQU0sVUFBVSxHQUFHLE9BQU8sS0FBSyxLQUFLLFdBQVcsQ0FBQyxDQUFDLENBQUMsS0FBSyxFQUFFLE1BQU0sRUFBRSxHQUFHLEVBQUUsZ0JBQWdCLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQztRQUNuRyxJQUFJLENBQUMsU0FBUyxHQUFHLElBQUEsMERBQStCLEVBQUMsT0FBTyxDQUFDLFFBQVEsSUFBSSxVQUFVLENBQUMsQ0FBQztRQUNqRixJQUFJLENBQUMsT0FBTyxHQUFHLE9BQU8sQ0FBQyxNQUFNLElBQUksSUFBSSxDQUFDLE1BQU0sQ0FBQztRQUM3QyxJQUFJLENBQUMsSUFBSSxHQUFHLE9BQU8sQ0FBQyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQyw2QkFBVyxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUM7UUFDckQsSUFBSSxDQUFDLGtCQUFrQixHQUFHLE9BQU8sQ0FBQyxpQkFBaUIsSUFBSSx3QkFBVSxDQUFDO1FBQ2xFLElBQUksSUFBSSxDQUFDLFNBQVMsQ0FBQywyQkFBMkIsRUFBRSxDQUFDO1lBQy9DLElBQUksQ0FBQztnQkFDSCxJQUFJLENBQUMscUJBQXFCLEdBQUcsSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQywyQkFBMkIsRUFBRSxHQUFHLENBQUMsQ0FBQztZQUMzRixDQUFDO1lBQUMsTUFBTSxDQUFDO2dCQUNQLHVDQUF1QztZQUN6QyxDQUFDO1FBQ0gsQ0FBQztJQUNILENBQUM7SUFFRDs7O09BR0c7SUFDSSxNQUFNLENBQUMsT0FBTyxDQUNuQixNQUFlLEVBQ2YsR0FBd0IsRUFDeEIsT0FBaUM7UUFFakMsTUFBTSxPQUFPLEdBQUcsR0FBcUMsQ0FBQztRQUN0RCxJQUFJLE9BQU8sQ0FBQyxPQUFPLEtBQUssU0FBUyxJQUFJLE9BQU8sQ0FBQyxPQUFPLEtBQUssSUFBSSxFQUFFLENBQUM7WUFDOUQsT0FBTyxDQUFDLE9BQU8sR0FBRyxFQUFFLENBQUM7UUFDdkIsQ0FBQztRQUVELElBQUksT0FBTyxDQUFDLE9BQU8sQ0FBQyxzQkFBc0IsS0FBSyxTQUFTLElBQUksT0FBTyxDQUFDLE9BQU8sQ0FBQyxzQkFBc0IsS0FBSyxJQUFJLEVBQUUsQ0FBQztZQUM1Ryx3RkFBd0Y7WUFDeEYsT0FBTyxDQUFDLE9BQU8sQ0FBQyxzQkFBc0IsR0FBRyxJQUFJLHNCQUFzQixDQUFDLE1BQU0sRUFBRSxPQUFPLENBQUMsQ0FBQztRQUN2RixDQUFDO1FBRUQsT0FBTyxPQUFPLENBQUMsT0FBTyxDQUFDLHNCQUFzQixDQUFDO0lBQ2hELENBQUM7SUFFRDs7O09BR0c7SUFDSSxNQUFNLENBQUMsUUFBUSxDQUFDLEdBQTJDO1FBQ2hFLElBQUksQ0FBQztZQUNILE1BQU0sTUFBTSxHQUFJLEdBQXlELEVBQUUsT0FBTyxFQUFFLHNCQUFzQixDQUFDO1lBQzNHLE9BQU8sTUFBTSxFQUFFLENBQUMsV0FBVyxDQUFDLEtBQUssSUFBSSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQztRQUM3RCxDQUFDO1FBQUMsTUFBTSxDQUFDO1lBQ1AsT0FBTyxTQUFTLENBQUM7UUFDbkIsQ0FBQztJQUNILENBQUM7SUFFRDs7O09BR0c7SUFDSCxJQUFJLElBQUk7UUFDTixPQUFPLGVBQWUsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDckMsQ0FBQztJQUVELDJEQUEyRDtJQUMzRCxJQUFJLFNBQVM7UUFDWCxPQUFPLElBQUksQ0FBQyxVQUFVLENBQUM7SUFDekIsQ0FBQztJQUVELElBQUksUUFBUTtRQUNWLE9BQU8sRUFBRSxHQUFHLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztJQUMvQixDQUFDO0lBRUQsSUFBSSxTQUFTO1FBQ1gsT0FBTyxJQUFJLENBQUMsTUFBTSxLQUFLLFNBQVMsQ0FBQztJQUNuQyxDQUFDO0lBRUQsSUFBSSxVQUFVO1FBQ1osT0FBTyxJQUFJLENBQUMsTUFBTSxLQUFLLFVBQVUsQ0FBQztJQUNwQyxDQUFDO0lBRUQsS0FBSztRQUNILElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxFQUFFLEdBQUcsRUFBRTtZQUN6QixJQUFJLElBQUksQ0FBQyxNQUFNLEtBQUssU0FBUyxFQUFFLENBQUM7Z0JBQzlCLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLHVGQUF1RixDQUFDLENBQUM7Z0JBQzFHLE9BQU87WUFDVCxDQUFDO1lBQ0QsSUFBSSxDQUFDLE1BQU0sR0FBRyxTQUFTLENBQUM7WUFDeEIsSUFBSSxDQUFDLFVBQVUsR0FBRyxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDOUIsSUFBSSxDQUFDLFVBQVUsR0FBRyxJQUFJLENBQUMsa0JBQWtCLEVBQUUsQ0FBQztZQUM1QyxJQUFJLENBQUMsS0FBSyxDQUFDLFNBQVMsR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDO1lBQ3ZDLE1BQU0sV0FBVyxHQUFHLFdBQUssQ0FBQyxhQUFhLEVBQUUsRUFBRSxXQUFXLEVBQUUsQ0FBQztZQUN6RCxJQUFJLFdBQVcsSUFBSSxJQUFBLHdCQUFrQixFQUFDLFdBQVcsQ0FBQyxFQUFFLENBQUM7Z0JBQ25ELElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxHQUFHLFdBQVcsQ0FBQyxPQUFPLENBQUM7WUFDM0MsQ0FBQztZQUNELElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxHQUFHLEVBQUUsU0FBUyxFQUFFLElBQUksSUFBSSxFQUFFLENBQUMsV0FBVyxFQUFFLEVBQUUsQ0FBQztRQUM5RCxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRCxTQUFTLENBQUMsR0FBd0I7UUFDaEMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxXQUFXLEVBQUUsR0FBRyxFQUFFO1lBQzdCLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxLQUFLLFNBQVMsRUFBRSxDQUFDO2dCQUNwRCxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FDZCxvR0FBb0csQ0FDckcsQ0FBQztnQkFDRixPQUFPO1lBQ1QsQ0FBQztZQUNELE1BQU0sSUFBSSxHQUFHLEdBQUcsQ0FBQyxJQUFJLElBQUksR0FBRyxDQUFDLEdBQUcsRUFBRSxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDaEQsTUFBTSxpQkFBaUIsR0FBRyxHQUFHLENBQUMsT0FBTyxFQUFFLENBQUMsY0FBYyxDQUFDLENBQUM7WUFDeEQsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLEdBQUc7Z0JBQ2YsTUFBTSxFQUNKLE9BQU8sR0FBRyxDQUFDLE1BQU0sS0FBSyxRQUFRO29CQUM1QixDQUFDLENBQUMsaUJBQWlCLENBQUMsR0FBRyxDQUFDLE1BQU0sRUFBRSw4QkFBc0IsQ0FBQyxZQUFZLENBQUM7b0JBQ3BFLENBQUMsQ0FBQyxTQUFTO2dCQUNmLElBQUksRUFBRSxPQUFPLElBQUksS0FBSyxRQUFRLENBQUMsQ0FBQyxDQUFDLGlCQUFpQixDQUFDLElBQUksRUFBRSw4QkFBc0IsQ0FBQyxlQUFlLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUztnQkFDNUcsUUFBUSxFQUNOLE9BQU8sR0FBRyxDQUFDLFFBQVEsS0FBSyxRQUFRO29CQUM5QixDQUFDLENBQUMsaUJBQWlCLENBQUMsR0FBRyxDQUFDLFFBQVEsRUFBRSw4QkFBc0IsQ0FBQyxlQUFlLENBQUM7b0JBQ3pFLENBQUMsQ0FBQyxTQUFTO2dCQUNmLEdBQUcsQ0FBQyxPQUFPLGlCQUFpQixLQUFLLFFBQVEsSUFBSSx3QkFBd0IsQ0FBQyxJQUFJLENBQUMsaUJBQWlCLENBQUM7b0JBQzNGLENBQUMsQ0FBQyxFQUFFLGlCQUFpQixFQUFFO29CQUN2QixDQUFDLENBQUMsRUFBRSxDQUFDO2FBQ1IsQ0FBQztRQUNKLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVEOzs7OztPQUtHO0lBQ0gsTUFBTSxDQUFDLEdBQThCO1FBQ25DLElBQUksU0FBUyxHQUFHLEtBQUssQ0FBQztRQUN0QixJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsRUFBRSxHQUFHLEVBQUU7WUFDMUIsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztnQkFDcEIsT0FBTztZQUNULENBQUM7WUFDRCxNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQztZQUMxRSxNQUFNLFNBQVMsR0FBRyxHQUFHLEtBQUssU0FBUyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxnQkFBZ0IsS0FBSyxJQUFJLENBQUM7WUFDM0UsTUFBTSxVQUFVLEdBQ2QsR0FBRyxLQUFLLFNBQVMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxXQUFXLElBQUksR0FBRyxDQUFDLGdCQUFnQixDQUFDLElBQUksTUFBTSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDO2dCQUMvRixDQUFDLENBQUMsR0FBRyxDQUFDLFVBQVU7Z0JBQ2hCLENBQUMsQ0FBQyxTQUFTLENBQUM7WUFDaEIsSUFBSSxDQUFDLE1BQU0sR0FBRyxVQUFVLENBQUM7WUFDekIsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLEdBQUcsRUFBRSxHQUFHLENBQUMsVUFBVSxLQUFLLFNBQVMsQ0FBQyxDQUFDLENBQUMsRUFBRSxVQUFVLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsU0FBUyxFQUFFLENBQUM7WUFFcEYsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxTQUFTLEVBQUUsVUFBVSxDQUFDLENBQUM7WUFDckQsTUFBTSxjQUFjLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxTQUFTLEVBQUUsVUFBVSxFQUFFLFVBQVUsQ0FBQyxDQUFDO1lBQ3pFLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxHQUFHO2dCQUNsQixHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTTtnQkFDcEIsVUFBVTtnQkFDVixPQUFPO2dCQUNQLGNBQWM7Z0JBQ2QsUUFBUSxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsY0FBYyxDQUFDLElBQUksTUFBTTthQUNoRCxDQUFDO1lBQ0YsU0FBUyxHQUFHLElBQUksQ0FBQztRQUNuQixDQUFDLENBQUMsQ0FBQztRQUNILE9BQU8sU0FBUyxDQUFDO0lBQ25CLENBQUM7SUFFRDs7O09BR0c7SUFDSSxHQUFHLENBQUMsU0FBa0IsSUFBSSxDQUFDLE1BQU07UUFDdEMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsR0FBRyxFQUFFO1lBQ3ZCLElBQUksQ0FBQyxJQUFJLENBQUMsVUFBVSxJQUFJLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztnQkFDckMsT0FBTztZQUNULENBQUM7WUFDRCxJQUFJLENBQUMsT0FBTyxHQUFHLElBQUksQ0FBQztZQUNwQixNQUFNLGNBQWMsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sRUFBRSxjQUFjLENBQUM7WUFDekQsTUFBTSxLQUFLLEdBQUcsY0FBYyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLGNBQWMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUM7WUFDbEUsSUFBSSxLQUFLLEtBQUssSUFBSSxFQUFFLENBQUM7Z0JBQ25CLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxvQkFBb0IsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUUsbUJBQW1CLENBQUMsQ0FBQztZQUN2RSxDQUFDO1FBQ0gsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQsSUFBSSxTQUFTO1FBQ1gsT0FBTyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxFQUFFLE1BQU0sSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLGFBQWEsSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDckYsQ0FBQztJQUVEOzs7OztPQUtHO0lBQ0ksUUFBUSxDQUFDLEtBQWUsRUFBRSxJQUE4QjtRQUM3RCxJQUFJLENBQUMsT0FBTyxDQUFDLFVBQVUsRUFBRSxHQUFHLEVBQUU7WUFDNUIsc0VBQXNFO1lBQ3RFLCtFQUErRTtZQUMvRSxJQUFJLElBQUksQ0FBQyxTQUFTLElBQUksS0FBSyxLQUFLLElBQUksSUFBSSxPQUFPLEtBQUssS0FBSyxRQUFRLEVBQUUsQ0FBQztnQkFDbEUsSUFBSSxJQUFJLENBQUMsZUFBZSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO29CQUNwQyxPQUFPO2dCQUNULENBQUM7Z0JBQ0QsSUFBSSxDQUFDLGVBQWUsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUM7WUFDbEMsQ0FBQztZQUNELE1BQU0sY0FBYyxHQUFHLGdCQUFnQixDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQy9DLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7Z0JBQ3BCLElBQUksUUFBaUIsQ0FBQztnQkFDdEIsSUFBSSxDQUFDO29CQUNILElBQUksSUFBSSxLQUFLLFNBQVMsRUFBRSxDQUFDO3dCQUN2QixRQUFRLEdBQUcsc0JBQXNCLENBQUMsSUFBSSxDQUFDLENBQUM7b0JBQzFDLENBQUM7Z0JBQ0gsQ0FBQztnQkFBQyxNQUFNLENBQUM7b0JBQ1Asc0RBQXNEO2dCQUN4RCxDQUFDO2dCQUNELElBQUksQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUNmLG9CQUFvQixDQUFDO29CQUNuQixTQUFTLEVBQUUsSUFBSSxDQUFDLFVBQVU7b0JBQzFCLEdBQUcsQ0FBQyxRQUFRLEtBQUssU0FBUyxDQUFDLENBQUMsQ0FBQyxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO29CQUNyRCxLQUFLLEVBQUUsY0FBYztpQkFDdEIsQ0FBQyxFQUNGLElBQUksQ0FBQyxVQUFVO29CQUNiLENBQUMsQ0FBQywrREFBK0Q7b0JBQ2pFLENBQUMsQ0FBQyx3RUFBd0UsQ0FDN0UsQ0FBQztnQkFDRixPQUFPO1lBQ1QsQ0FBQztZQUNELElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQztnQkFDdEMsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLEdBQUcsRUFBRSxDQUFDO1lBQ3pCLENBQUM7WUFDRCxJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLE1BQU0sSUFBSSw4QkFBc0IsQ0FBQyxTQUFTLEVBQUUsQ0FBQztnQkFDakUsSUFBSSxDQUFDLEtBQUssQ0FBQyxhQUFhLEdBQUcsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLGFBQWEsSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUM7Z0JBQy9ELE9BQU87WUFDVCxDQUFDO1lBQ0QsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxDQUFDO1FBQ3pDLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVEOzs7Ozs7OztPQVFHO0lBQ0ksT0FBTyxDQUFDLElBQTZCLEVBQUUsUUFBbUMsT0FBTztRQUN0RixJQUFJLENBQUMsT0FBTyxDQUFDLFNBQVMsRUFBRSxHQUFHLEVBQUU7WUFDM0IsSUFBSSxJQUFJLEtBQUssSUFBSSxJQUFJLElBQUksS0FBSyxTQUFTLElBQUksT0FBTyxJQUFJLEtBQUssUUFBUSxFQUFFLENBQUM7Z0JBQ3BFLE9BQU87WUFDVCxDQUFDO1lBQ0QsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLElBQUksQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7Z0JBQ3hDLHNHQUFzRztnQkFDdEcsT0FBTztZQUNULENBQUM7WUFDRCxJQUFJLElBQUksQ0FBQyxTQUFTLElBQUksS0FBSyxLQUFLLE1BQU0sRUFBRSxDQUFDO2dCQUN2QyxJQUFJLENBQUMsWUFBWSxHQUFHLElBQUksQ0FBQztZQUMzQixDQUFDO1lBQ0QsTUFBTSxFQUFFLE9BQU8sRUFBRSxPQUFPLEVBQUUsR0FBRyx3QkFBd0IsQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUM1RCxJQUFJLE9BQU8sQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7Z0JBQ3pCLE9BQU87WUFDVCxDQUFDO1lBQ0QsSUFBSSxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7Z0JBQ3BCLElBQUksQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQ2hCLG9CQUFvQixDQUFDO29CQUNuQixTQUFTLEVBQUUsSUFBSSxDQUFDLFVBQVU7b0JBQzFCLElBQUksRUFBRSxNQUFNLENBQUMsV0FBVyxDQUFDLE9BQU8sQ0FBQztvQkFDakMsR0FBRyxDQUFDLE9BQU8sR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsV0FBVyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7aUJBQzlDLENBQUMsRUFDRixpRUFBaUUsQ0FDbEUsQ0FBQztnQkFDRixPQUFPO1lBQ1QsQ0FBQztZQUNELElBQUksT0FBTyxHQUFHLENBQUMsRUFBRSxDQUFDO2dCQUNoQixJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxrRkFBa0YsQ0FBQyxDQUFDO1lBQ3ZHLENBQUM7WUFDRCxLQUFLLE1BQU0sQ0FBQyxHQUFHLEVBQUUsS0FBSyxDQUFDLElBQUksT0FBTyxFQUFFLENBQUM7Z0JBQ25DLElBQUksWUFBWSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO29CQUMvQixJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyw4RUFBOEUsR0FBRyxJQUFJLENBQUMsQ0FBQztvQkFDeEcsU0FBUztnQkFDWCxDQUFDO2dCQUNELElBQUksQ0FBQyxDQUFDLEdBQUcsSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsTUFBTSxJQUFJLDhCQUFzQixDQUFDLFdBQVcsRUFBRSxDQUFDO29CQUNqRyxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyw0RUFBNEUsR0FBRyxJQUFJLENBQUMsQ0FBQztvQkFDdEcsU0FBUztnQkFDWCxDQUFDO2dCQUNELHdEQUF3RDtnQkFDeEQsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsR0FBRyxLQUFLLENBQUM7WUFDMUIsQ0FBQztRQUNILENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVEOzs7Ozs7T0FNRztJQUNJLGtCQUFrQixDQUFDLFNBQWlCLEVBQUUsS0FBZTtRQUMxRCxJQUFJLENBQUMsT0FBTyxDQUFDLG9CQUFvQixFQUFFLEdBQUcsRUFBRTtZQUN0QyxNQUFNLElBQUksR0FBRyxpQkFBaUIsQ0FBQyxTQUFTLENBQUMsQ0FBQztZQUMxQyxNQUFNLE1BQU0sR0FBRyxLQUFLLEtBQUssU0FBUyxDQUFDO1lBQ25DLElBQUksSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDO2dCQUNuQixJQUFJLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsU0FBUyxFQUFFLENBQUMsQ0FBQztnQkFDekQsSUFBSSxNQUFNLEVBQUUsQ0FBQztvQkFDWCxJQUFJLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDO2dCQUN2QixDQUFDO2dCQUNELE9BQU87WUFDVCxDQUFDO1lBQ0QsTUFBTSxPQUFPLEdBQUcsRUFBRSxTQUFTLEVBQUUsSUFBSSxDQUFDLFVBQVUsRUFBRSxTQUFTLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsU0FBUyxFQUFFLENBQUM7WUFDekcsSUFBSSxNQUFNLEVBQUUsQ0FBQztnQkFDWCxJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FDZixvQkFBb0IsQ0FBQyxFQUFFLEdBQUcsT0FBTyxFQUFFLEtBQUssRUFBRSxnQkFBZ0IsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLEVBQ3BFLGlDQUFpQyxJQUFJLHNDQUFzQyxDQUM1RSxDQUFDO1lBQ0osQ0FBQztpQkFBTSxDQUFDO2dCQUNOLElBQUksQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLE9BQU8sRUFBRSxpQ0FBaUMsSUFBSSx5Q0FBeUMsQ0FBQyxDQUFDO1lBQzdHLENBQUM7UUFDSCxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRCxRQUFRLENBQUMsU0FBa0IsRUFBRSxVQUE4QjtRQUN6RCxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7WUFDZixPQUFPLFNBQVMsQ0FBQztRQUNuQixDQUFDO1FBQ0QsSUFBSSxDQUFDLFVBQVUsSUFBSSxDQUFDLENBQUMsSUFBSSxHQUFHLElBQUksSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDO1lBQy9DLE9BQU8sU0FBUyxDQUFDO1FBQ25CLENBQUM7UUFDRCxPQUFPLFNBQVMsQ0FBQztJQUNuQixDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsU0FBUyxDQUNQLFNBQWtCLEVBQ2xCLFVBQThCLEVBQzlCLFVBQWtCO1FBRWxCLE1BQU0sTUFBTSxHQUFHLFVBQVUsSUFBSSxDQUFDLENBQUM7UUFDL0IsSUFBSSxNQUFNLElBQUksR0FBRyxFQUFFLENBQUM7WUFDbEIsT0FBTyxPQUFPLENBQUM7UUFDakIsQ0FBQztRQUNELElBQUksTUFBTSxJQUFJLEdBQUcsRUFBRSxDQUFDO1lBQ2xCLE9BQU8sY0FBYyxDQUFDO1FBQ3hCLENBQUM7UUFDRCxJQUFJLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztZQUNuQixPQUFPLE9BQU8sQ0FBQztRQUNqQixDQUFDO1FBQ0QsSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDO1lBQ2YsT0FBTyxTQUFTLENBQUM7UUFDbkIsQ0FBQztRQUNELElBQUksVUFBVSxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsZUFBZSxFQUFFLENBQUM7WUFDaEQsT0FBTyxNQUFNLENBQUM7UUFDaEIsQ0FBQztRQUNELElBQUksSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDO1lBQ3RCLE9BQU8sU0FBUyxDQUFDO1FBQ25CLENBQUM7UUFDRCxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsRUFBRSxJQUFJLENBQUM7UUFDbEMsSUFBSSxJQUFJLENBQUMscUJBQXFCLEtBQUssSUFBSSxJQUFJLE9BQU8sSUFBSSxLQUFLLFFBQVEsSUFBSSxJQUFJLENBQUMscUJBQXFCLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7WUFDN0csT0FBTyxTQUFTLENBQUM7UUFDbkIsQ0FBQztRQUNELE9BQU8sSUFBSSxDQUFDLE9BQU8sRUFBRSxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsaUJBQWlCLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDO0lBQ2xGLENBQUM7SUFFRCxNQUFNLENBQUMsY0FBbUQ7UUFDeEQsSUFDRSxDQUFDLGNBQWMsS0FBSyxjQUFjLElBQUksSUFBSSxDQUFDLFNBQVMsQ0FBQztZQUNyRCxDQUFDLElBQUksQ0FBQyxZQUFZLElBQUksb0JBQW9CLENBQUMsY0FBYyxDQUFDLEtBQUssTUFBTSxDQUFDLEVBQ3RFLENBQUM7WUFDRCxPQUFPLE1BQU0sQ0FBQztRQUNoQixDQUFDO1FBQ0QsT0FBTyxvQkFBb0IsQ0FBQyxjQUFjLENBQUMsQ0FBQztJQUM5QyxDQUFDO0lBRUQ7O09BRUc7SUFDSCxPQUFPLENBQUMsSUFBWSxFQUFFLElBQWdCO1FBQ3BDLElBQUksQ0FBQztZQUNILElBQUksRUFBRSxDQUFDO1FBQ1QsQ0FBQztRQUFDLE1BQU0sQ0FBQztZQUNQLElBQUksQ0FBQztnQkFDSCwwRUFBMEU7Z0JBQzFFLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLDhCQUE4QixJQUFJLFdBQVcsQ0FBQyxDQUFDO1lBQ2xFLENBQUM7WUFBQyxNQUFNLENBQUM7Z0JBQ1AsMkJBQTJCO1lBQzdCLENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQztDQUNGO0FBOVlELHdEQThZQyJ9
|