@decaf-ts/for-nest 0.11.1 → 0.11.2-refactor.2
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/README.md +1 -1
- package/dist/for-nest.cjs +2654 -2
- package/dist/for-nest.js +2756 -2
- package/lib/cjs/auth/AuthInterceptor.cjs +90 -0
- package/lib/cjs/auth/DecafAuthHandler.cjs +37 -0
- package/lib/cjs/auth/DecafAuthModule.cjs +56 -0
- package/lib/cjs/auth/constants.cjs +10 -0
- package/lib/cjs/auth/decorators.cjs +28 -0
- package/lib/cjs/auth/index.cjs +23 -0
- package/lib/cjs/bin/cli.cjs +2 -2
- package/lib/cjs/cli-module.cjs +64 -7
- package/lib/cjs/constants.cjs +5 -6
- package/lib/cjs/controllers.cjs +13 -109
- package/lib/cjs/core-module.cjs +8 -8
- package/lib/cjs/decaf-model/DecafModelModule.cjs +23 -4
- package/lib/cjs/decaf-model/FromModelController.cjs +751 -789
- package/lib/cjs/decaf-model/decorators/ApiOperationFromModel.cjs +53 -16
- package/lib/cjs/decaf-model/decorators/ApiParamsFromModel.cjs +2 -2
- package/lib/cjs/decaf-model/decorators/DecafBody.cjs +2 -2
- package/lib/cjs/decaf-model/decorators/DecafParams.cjs +2 -2
- package/lib/cjs/decaf-model/decorators/controller-config.cjs +29 -0
- package/lib/cjs/decaf-model/decorators/decorators.cjs +5 -45
- package/lib/cjs/decaf-model/decorators/expose.cjs +13 -0
- package/lib/cjs/decaf-model/decorators/index.cjs +3 -2
- package/lib/cjs/decaf-model/decorators/types.cjs +2 -2
- package/lib/cjs/decaf-model/decorators/utils.cjs +2 -2
- package/lib/cjs/decaf-model/index.cjs +28 -19
- package/lib/cjs/decaf-model/types.cjs +2 -2
- package/lib/cjs/decaf-model/utils.cjs +2 -2
- package/lib/cjs/decoration.cjs +2 -2
- package/lib/cjs/decorators.cjs +85 -0
- package/lib/cjs/events-module/DecafStreamModule.cjs +2 -2
- package/lib/cjs/events-module/EventsController.cjs +2 -2
- package/lib/cjs/events-module/constant.cjs +2 -2
- package/lib/cjs/events-module/index.cjs +2 -2
- package/lib/cjs/events-module/utils.cjs +2 -2
- package/lib/cjs/factory/NestBootstraper.cjs +2 -2
- package/lib/cjs/factory/errors/cors.cjs +2 -2
- package/lib/cjs/factory/errors/index.cjs +2 -2
- package/lib/cjs/factory/errors/throttling.cjs +2 -2
- package/lib/cjs/factory/exceptions/DecafErrorFilter.cjs +2 -2
- package/lib/cjs/factory/exceptions/decorators.cjs +2 -2
- package/lib/cjs/factory/exceptions/index.cjs +2 -2
- package/lib/cjs/factory/index.cjs +2 -2
- package/lib/cjs/factory/openapi/DtoBuilder.cjs +37 -6
- package/lib/cjs/factory/openapi/SwaggerBuilder.cjs +2 -2
- package/lib/cjs/factory/openapi/SwaggerCustomUI.cjs +2 -2
- package/lib/cjs/factory/openapi/constants.cjs +2 -2
- package/lib/cjs/factory/openapi/index.cjs +2 -2
- package/lib/cjs/index.cjs +8 -7
- package/lib/cjs/interceptors/DecafRequestHandlerInterceptor.cjs +25 -21
- package/lib/cjs/interceptors/index.cjs +3 -4
- package/lib/cjs/module.cjs +5 -2
- package/lib/cjs/overrides/Adapter.cjs +2 -2
- package/lib/cjs/overrides/ModelBuilderExtensions.cjs +2 -2
- package/lib/cjs/overrides/constants.cjs +2 -2
- package/lib/cjs/overrides/decoration.cjs +2 -2
- package/lib/cjs/overrides/helpers.cjs +2 -2
- package/lib/cjs/overrides/index.cjs +3 -2
- package/lib/cjs/overrides/logging.cjs +5 -0
- package/lib/cjs/overrides/overrides.cjs +2 -2
- package/lib/cjs/request/DecafAuthHandler.cjs +5 -39
- package/lib/cjs/request/DecafHandlerExecutor.cjs +2 -2
- package/lib/cjs/request/DecafRequestContext.cjs +11 -20
- package/lib/cjs/request/DecafResponseInterceptor.cjs +3 -3
- package/lib/cjs/request/index.cjs +2 -2
- package/lib/cjs/swagger-types.cjs +2 -2
- package/lib/cjs/types.cjs +2 -2
- package/lib/cjs/utils.cjs +2 -2
- package/lib/cjs/webhooks/DecafWebhookModule.cjs +11 -12
- package/lib/cjs/webhooks/controllers.cjs +10 -10
- package/lib/cjs/webhooks/index.cjs +2 -15
- package/lib/cjs/webhooks/types.cjs +2 -2
- package/lib/esm/auth/AuthInterceptor.js +81 -0
- package/lib/esm/auth/DecafAuthHandler.js +31 -0
- package/lib/esm/auth/DecafAuthModule.js +48 -0
- package/lib/esm/auth/constants.js +6 -0
- package/lib/esm/auth/decorators.js +22 -0
- package/lib/esm/auth/index.js +6 -0
- package/lib/esm/bin/cli.js +1 -1
- package/lib/esm/cli-module.js +63 -6
- package/lib/esm/constants.js +3 -4
- package/lib/esm/controllers.js +13 -109
- package/lib/esm/core-module.js +7 -7
- package/lib/esm/decaf-model/DecafModelModule.js +22 -3
- package/lib/esm/decaf-model/FromModelController.js +753 -791
- package/lib/esm/decaf-model/decorators/ApiOperationFromModel.js +53 -15
- package/lib/esm/decaf-model/decorators/ApiParamsFromModel.js +1 -1
- package/lib/esm/decaf-model/decorators/DecafBody.js +1 -1
- package/lib/esm/decaf-model/decorators/DecafParams.js +1 -1
- package/lib/esm/decaf-model/decorators/controller-config.js +25 -0
- package/lib/esm/decaf-model/decorators/decorators.js +2 -43
- package/lib/esm/decaf-model/decorators/expose.js +9 -0
- package/lib/esm/decaf-model/decorators/index.js +2 -1
- package/lib/esm/decaf-model/decorators/types.js +1 -1
- package/lib/esm/decaf-model/decorators/utils.js +1 -1
- package/lib/esm/decaf-model/index.js +11 -4
- package/lib/esm/decaf-model/types.js +1 -1
- package/lib/esm/decaf-model/utils.js +1 -1
- package/lib/esm/decoration.js +1 -1
- package/lib/esm/decorators.js +79 -0
- package/lib/esm/events-module/DecafStreamModule.js +1 -1
- package/lib/esm/events-module/EventsController.js +1 -1
- package/lib/esm/events-module/constant.js +1 -1
- package/lib/esm/events-module/index.js +1 -1
- package/lib/esm/events-module/utils.js +1 -1
- package/lib/esm/factory/NestBootstraper.js +1 -1
- package/lib/esm/factory/errors/cors.js +1 -1
- package/lib/esm/factory/errors/index.js +1 -1
- package/lib/esm/factory/errors/throttling.js +1 -1
- package/lib/esm/factory/exceptions/DecafErrorFilter.js +1 -1
- package/lib/esm/factory/exceptions/decorators.js +1 -1
- package/lib/esm/factory/exceptions/index.js +1 -1
- package/lib/esm/factory/index.js +1 -1
- package/lib/esm/factory/openapi/DtoBuilder.js +36 -5
- package/lib/esm/factory/openapi/SwaggerBuilder.js +1 -1
- package/lib/esm/factory/openapi/SwaggerCustomUI.js +1 -1
- package/lib/esm/factory/openapi/constants.js +1 -1
- package/lib/esm/factory/openapi/index.js +1 -1
- package/lib/esm/index.js +7 -6
- package/lib/esm/interceptors/DecafRequestHandlerInterceptor.js +25 -21
- package/lib/esm/interceptors/index.js +2 -3
- package/lib/esm/module.js +4 -1
- package/lib/esm/overrides/Adapter.js +1 -1
- package/lib/esm/overrides/ModelBuilderExtensions.js +1 -1
- package/lib/esm/overrides/constants.js +1 -1
- package/lib/esm/overrides/decoration.js +1 -1
- package/lib/esm/overrides/helpers.js +1 -1
- package/lib/esm/overrides/index.js +2 -1
- package/lib/esm/overrides/logging.js +2 -0
- package/lib/esm/overrides/overrides.js +1 -1
- package/lib/esm/request/DecafAuthHandler.js +2 -36
- package/lib/esm/request/DecafHandlerExecutor.js +1 -1
- package/lib/esm/request/DecafRequestContext.js +10 -19
- package/lib/esm/request/DecafResponseInterceptor.js +2 -2
- package/lib/esm/request/index.js +1 -1
- package/lib/esm/swagger-types.js +1 -1
- package/lib/esm/types.js +1 -1
- package/lib/esm/utils.js +1 -1
- package/lib/esm/webhooks/DecafWebhookModule.js +5 -6
- package/lib/esm/webhooks/controllers.js +2 -2
- package/lib/esm/webhooks/index.js +1 -2
- package/lib/esm/webhooks/types.js +1 -1
- package/lib/types/{interceptors → auth}/AuthInterceptor.d.cts +4 -1
- package/lib/types/{interceptors → auth}/AuthInterceptor.d.mts +4 -1
- package/lib/types/auth/DecafAuthHandler.d.cts +22 -0
- package/lib/types/auth/DecafAuthHandler.d.mts +22 -0
- package/lib/types/auth/DecafAuthModule.d.cts +9 -0
- package/lib/types/auth/DecafAuthModule.d.mts +9 -0
- package/lib/types/auth/constants.d.cts +5 -0
- package/lib/types/auth/constants.d.mts +5 -0
- package/lib/types/auth/decorators.d.cts +4 -0
- package/lib/types/auth/decorators.d.mts +4 -0
- package/lib/types/auth/index.d.cts +6 -0
- package/lib/types/auth/index.d.mts +6 -0
- package/lib/types/cli-module.d.cts +1 -4
- package/lib/types/cli-module.d.mts +1 -4
- package/lib/types/constants.d.cts +2 -3
- package/lib/types/constants.d.mts +2 -3
- package/lib/types/controllers.d.cts +7 -12
- package/lib/types/controllers.d.mts +7 -12
- package/lib/types/decaf-model/DecafModelModule.d.cts +1 -0
- package/lib/types/decaf-model/DecafModelModule.d.mts +1 -0
- package/lib/types/decaf-model/FromModelController.d.cts +40 -52
- package/lib/types/decaf-model/FromModelController.d.mts +40 -52
- package/lib/types/decaf-model/decorators/ApiOperationFromModel.d.cts +0 -2
- package/lib/types/decaf-model/decorators/ApiOperationFromModel.d.mts +0 -2
- package/lib/types/decaf-model/decorators/controller-config.d.cts +18 -0
- package/lib/types/decaf-model/decorators/controller-config.d.mts +18 -0
- package/lib/types/decaf-model/decorators/decorators.d.cts +1 -29
- package/lib/types/decaf-model/decorators/decorators.d.mts +1 -29
- package/lib/types/decaf-model/decorators/expose.d.cts +1 -0
- package/lib/types/decaf-model/decorators/expose.d.mts +1 -0
- package/lib/types/decaf-model/decorators/index.d.cts +1 -0
- package/lib/types/decaf-model/decorators/index.d.mts +1 -0
- package/lib/types/decaf-model/decorators/types.d.cts +8 -21
- package/lib/types/decaf-model/decorators/types.d.mts +8 -21
- package/lib/types/decaf-model/index.d.cts +11 -3
- package/lib/types/decaf-model/index.d.mts +11 -3
- package/lib/types/decaf-model/utils.d.cts +2 -1
- package/lib/types/decaf-model/utils.d.mts +2 -1
- package/lib/types/decorators.d.cts +34 -0
- package/lib/types/decorators.d.mts +34 -0
- package/lib/types/factory/openapi/DtoBuilder.d.cts +7 -3
- package/lib/types/factory/openapi/DtoBuilder.d.mts +7 -3
- package/lib/types/index.d.cts +5 -5
- package/lib/types/index.d.mts +5 -5
- package/lib/types/interceptors/DecafRequestHandlerInterceptor.d.cts +1 -2
- package/lib/types/interceptors/DecafRequestHandlerInterceptor.d.mts +1 -2
- package/lib/types/interceptors/index.d.cts +1 -2
- package/lib/types/interceptors/index.d.mts +1 -2
- package/lib/types/overrides/Adapter.d.cts +1 -1
- package/lib/types/overrides/Adapter.d.mts +1 -1
- package/lib/types/overrides/index.d.cts +1 -0
- package/lib/types/overrides/index.d.mts +1 -0
- package/lib/types/overrides/logging.d.cts +1 -0
- package/lib/types/overrides/logging.d.mts +1 -0
- package/lib/types/request/DecafAuthHandler.d.cts +1 -10
- package/lib/types/request/DecafAuthHandler.d.mts +1 -10
- package/lib/types/request/DecafRequestContext.d.cts +4 -5
- package/lib/types/request/DecafRequestContext.d.mts +4 -5
- package/lib/types/types.d.cts +12 -24
- package/lib/types/types.d.mts +12 -24
- package/lib/types/webhooks/controllers.d.cts +1 -1
- package/lib/types/webhooks/controllers.d.mts +1 -1
- package/lib/types/webhooks/index.d.cts +0 -1
- package/lib/types/webhooks/index.d.mts +0 -1
- package/package.json +5 -13
- package/dist/for-nest.cjs.map +0 -1
- package/dist/for-nest.js.map +0 -1
- package/lib/cjs/bin/cli.cjs.map +0 -1
- package/lib/cjs/cli-module.cjs.map +0 -1
- package/lib/cjs/constants.cjs.map +0 -1
- package/lib/cjs/controllers.cjs.map +0 -1
- package/lib/cjs/core-module.cjs.map +0 -1
- package/lib/cjs/decaf-model/DecafModelModule.cjs.map +0 -1
- package/lib/cjs/decaf-model/FromModelController.cjs.map +0 -1
- package/lib/cjs/decaf-model/decorators/ApiOperationFromModel.cjs.map +0 -1
- package/lib/cjs/decaf-model/decorators/ApiParamsFromModel.cjs.map +0 -1
- package/lib/cjs/decaf-model/decorators/DecafBody.cjs.map +0 -1
- package/lib/cjs/decaf-model/decorators/DecafParams.cjs.map +0 -1
- package/lib/cjs/decaf-model/decorators/decorators.cjs.map +0 -1
- package/lib/cjs/decaf-model/decorators/index.cjs.map +0 -1
- package/lib/cjs/decaf-model/decorators/types.cjs.map +0 -1
- package/lib/cjs/decaf-model/decorators/utils.cjs.map +0 -1
- package/lib/cjs/decaf-model/index.cjs.map +0 -1
- package/lib/cjs/decaf-model/types.cjs.map +0 -1
- package/lib/cjs/decaf-model/utils.cjs.map +0 -1
- package/lib/cjs/decoration.cjs.map +0 -1
- package/lib/cjs/events-module/DecafStreamModule.cjs.map +0 -1
- package/lib/cjs/events-module/EventsController.cjs.map +0 -1
- package/lib/cjs/events-module/constant.cjs.map +0 -1
- package/lib/cjs/events-module/index.cjs.map +0 -1
- package/lib/cjs/events-module/utils.cjs.map +0 -1
- package/lib/cjs/factory/NestBootstraper.cjs.map +0 -1
- package/lib/cjs/factory/errors/cors.cjs.map +0 -1
- package/lib/cjs/factory/errors/index.cjs.map +0 -1
- package/lib/cjs/factory/errors/throttling.cjs.map +0 -1
- package/lib/cjs/factory/exceptions/DecafErrorFilter.cjs.map +0 -1
- package/lib/cjs/factory/exceptions/decorators.cjs.map +0 -1
- package/lib/cjs/factory/exceptions/index.cjs.map +0 -1
- package/lib/cjs/factory/index.cjs.map +0 -1
- package/lib/cjs/factory/openapi/DtoBuilder.cjs.map +0 -1
- package/lib/cjs/factory/openapi/SwaggerBuilder.cjs.map +0 -1
- package/lib/cjs/factory/openapi/SwaggerCustomUI.cjs.map +0 -1
- package/lib/cjs/factory/openapi/constants.cjs.map +0 -1
- package/lib/cjs/factory/openapi/index.cjs.map +0 -1
- package/lib/cjs/index.cjs.map +0 -1
- package/lib/cjs/interceptors/AuthInterceptor.cjs +0 -52
- package/lib/cjs/interceptors/AuthInterceptor.cjs.map +0 -1
- package/lib/cjs/interceptors/DecafRequestHandlerInterceptor.cjs.map +0 -1
- package/lib/cjs/interceptors/context.cjs +0 -18
- package/lib/cjs/interceptors/context.cjs.map +0 -1
- package/lib/cjs/interceptors/index.cjs.map +0 -1
- package/lib/cjs/migrations/index.cjs +0 -35
- package/lib/cjs/migrations/index.cjs.map +0 -1
- package/lib/cjs/migrations/migration-module.cjs +0 -60
- package/lib/cjs/migrations/migration-module.cjs.map +0 -1
- package/lib/cjs/migrations/migration-options.cjs +0 -4
- package/lib/cjs/migrations/migration-options.cjs.map +0 -1
- package/lib/cjs/module.cjs.map +0 -1
- package/lib/cjs/overrides/Adapter.cjs.map +0 -1
- package/lib/cjs/overrides/ModelBuilderExtensions.cjs.map +0 -1
- package/lib/cjs/overrides/constants.cjs.map +0 -1
- package/lib/cjs/overrides/decoration.cjs.map +0 -1
- package/lib/cjs/overrides/helpers.cjs.map +0 -1
- package/lib/cjs/overrides/index.cjs.map +0 -1
- package/lib/cjs/overrides/overrides.cjs.map +0 -1
- package/lib/cjs/ram/RamRequestTransformer.cjs +0 -26
- package/lib/cjs/ram/RamRequestTransformer.cjs.map +0 -1
- package/lib/cjs/ram/index.cjs +0 -19
- package/lib/cjs/ram/index.cjs.map +0 -1
- package/lib/cjs/request/DecafAuthHandler.cjs.map +0 -1
- package/lib/cjs/request/DecafHandlerExecutor.cjs.map +0 -1
- package/lib/cjs/request/DecafRequestContext.cjs.map +0 -1
- package/lib/cjs/request/DecafResponseInterceptor.cjs.map +0 -1
- package/lib/cjs/request/index.cjs.map +0 -1
- package/lib/cjs/swagger-types.cjs.map +0 -1
- package/lib/cjs/types.cjs.map +0 -1
- package/lib/cjs/utils.cjs.map +0 -1
- package/lib/cjs/webhooks/DecafWebhookModule.cjs.map +0 -1
- package/lib/cjs/webhooks/controllers.cjs.map +0 -1
- package/lib/cjs/webhooks/index.cjs.map +0 -1
- package/lib/cjs/webhooks/types.cjs.map +0 -1
- package/lib/esm/bin/cli.js.map +0 -1
- package/lib/esm/cli-module.js.map +0 -1
- package/lib/esm/constants.js.map +0 -1
- package/lib/esm/controllers.js.map +0 -1
- package/lib/esm/core-module.js.map +0 -1
- package/lib/esm/decaf-model/DecafModelModule.js.map +0 -1
- package/lib/esm/decaf-model/FromModelController.js.map +0 -1
- package/lib/esm/decaf-model/decorators/ApiOperationFromModel.js.map +0 -1
- package/lib/esm/decaf-model/decorators/ApiParamsFromModel.js.map +0 -1
- package/lib/esm/decaf-model/decorators/DecafBody.js.map +0 -1
- package/lib/esm/decaf-model/decorators/DecafParams.js.map +0 -1
- package/lib/esm/decaf-model/decorators/decorators.js.map +0 -1
- package/lib/esm/decaf-model/decorators/index.js.map +0 -1
- package/lib/esm/decaf-model/decorators/types.js.map +0 -1
- package/lib/esm/decaf-model/decorators/utils.js.map +0 -1
- package/lib/esm/decaf-model/index.js.map +0 -1
- package/lib/esm/decaf-model/types.js.map +0 -1
- package/lib/esm/decaf-model/utils.js.map +0 -1
- package/lib/esm/decoration.js.map +0 -1
- package/lib/esm/events-module/DecafStreamModule.js.map +0 -1
- package/lib/esm/events-module/EventsController.js.map +0 -1
- package/lib/esm/events-module/constant.js.map +0 -1
- package/lib/esm/events-module/index.js.map +0 -1
- package/lib/esm/events-module/utils.js.map +0 -1
- package/lib/esm/factory/NestBootstraper.js.map +0 -1
- package/lib/esm/factory/errors/cors.js.map +0 -1
- package/lib/esm/factory/errors/index.js.map +0 -1
- package/lib/esm/factory/errors/throttling.js.map +0 -1
- package/lib/esm/factory/exceptions/DecafErrorFilter.js.map +0 -1
- package/lib/esm/factory/exceptions/decorators.js.map +0 -1
- package/lib/esm/factory/exceptions/index.js.map +0 -1
- package/lib/esm/factory/index.js.map +0 -1
- package/lib/esm/factory/openapi/DtoBuilder.js.map +0 -1
- package/lib/esm/factory/openapi/SwaggerBuilder.js.map +0 -1
- package/lib/esm/factory/openapi/SwaggerCustomUI.js.map +0 -1
- package/lib/esm/factory/openapi/constants.js.map +0 -1
- package/lib/esm/factory/openapi/index.js.map +0 -1
- package/lib/esm/index.js.map +0 -1
- package/lib/esm/interceptors/AuthInterceptor.js +0 -43
- package/lib/esm/interceptors/AuthInterceptor.js.map +0 -1
- package/lib/esm/interceptors/DecafRequestHandlerInterceptor.js.map +0 -1
- package/lib/esm/interceptors/context.js +0 -12
- package/lib/esm/interceptors/context.js.map +0 -1
- package/lib/esm/interceptors/index.js.map +0 -1
- package/lib/esm/migrations/index.js +0 -18
- package/lib/esm/migrations/index.js.map +0 -1
- package/lib/esm/migrations/migration-module.js +0 -52
- package/lib/esm/migrations/migration-module.js.map +0 -1
- package/lib/esm/migrations/migration-options.js +0 -7
- package/lib/esm/migrations/migration-options.js.map +0 -1
- package/lib/esm/module.js.map +0 -1
- package/lib/esm/overrides/Adapter.js.map +0 -1
- package/lib/esm/overrides/ModelBuilderExtensions.js.map +0 -1
- package/lib/esm/overrides/constants.js.map +0 -1
- package/lib/esm/overrides/decoration.js.map +0 -1
- package/lib/esm/overrides/helpers.js.map +0 -1
- package/lib/esm/overrides/index.js.map +0 -1
- package/lib/esm/overrides/overrides.js.map +0 -1
- package/lib/esm/ram/RamRequestTransformer.js +0 -21
- package/lib/esm/ram/RamRequestTransformer.js.map +0 -1
- package/lib/esm/ram/index.js +0 -2
- package/lib/esm/ram/index.js.map +0 -1
- package/lib/esm/request/DecafAuthHandler.js.map +0 -1
- package/lib/esm/request/DecafHandlerExecutor.js.map +0 -1
- package/lib/esm/request/DecafRequestContext.js.map +0 -1
- package/lib/esm/request/DecafResponseInterceptor.js.map +0 -1
- package/lib/esm/request/index.js.map +0 -1
- package/lib/esm/swagger-types.js.map +0 -1
- package/lib/esm/types.js.map +0 -1
- package/lib/esm/utils.js.map +0 -1
- package/lib/esm/webhooks/DecafWebhookModule.js.map +0 -1
- package/lib/esm/webhooks/controllers.js.map +0 -1
- package/lib/esm/webhooks/index.js.map +0 -1
- package/lib/esm/webhooks/types.js.map +0 -1
- package/lib/types/interceptors/context.d.cts +0 -6
- package/lib/types/interceptors/context.d.mts +0 -6
- package/lib/types/migrations/index.d.cts +0 -17
- package/lib/types/migrations/index.d.mts +0 -17
- package/lib/types/migrations/migration-module.d.cts +0 -15
- package/lib/types/migrations/migration-module.d.mts +0 -15
- package/lib/types/migrations/migration-options.d.cts +0 -11
- package/lib/types/migrations/migration-options.d.mts +0 -11
- package/lib/types/ram/RamRequestTransformer.d.cts +0 -5
- package/lib/types/ram/RamRequestTransformer.d.mts +0 -5
- package/lib/types/ram/index.d.cts +0 -1
- package/lib/types/ram/index.d.mts +0 -1
package/dist/for-nest.js
CHANGED
|
@@ -1,2 +1,2756 @@
|
|
|
1
|
-
import{apply as e,Metadata as t,Decoration as r,DecorationKeys as o,metadata as s,uses as i}from"@decaf-ts/decoration";import{InjectablesKeys as n,DefaultInjectablesConfig as a}from"@decaf-ts/injectable-decorators";import{Delete as c,Patch as p,Put as d,Post as l,Get as u,applyDecorators as h,createParamDecorator as f,InternalServerErrorException as g,Injectable as m,Optional as y,Inject as b,UseInterceptors as v,SetMetadata as w,Scope as A,Query as E,Param as P,Response as R,Controller as T,Module as O,Catch as x,NotFoundException as S,NotAcceptableException as $,UseFilters as _,Logger as C,Global as k,Sse as I}from"@nestjs/common";import{Model as N,ValidationKeys as F,ModelBuilder as D}from"@decaf-ts/decorator-validation";import{AuthorizationError as q,PersistenceKeys as M,UUID as L,OrderDirection as j,ModelService as U,Service as B,Repository as G,ContextualLoggedClass as z,TransactionOperationKeys as H,Adapter as Y,Context as J,PreparedStatementKeys as X,ForbiddenError as W,UnsupportedError as Q,DefaultAdapterFlags as V,PersistenceService as K}from"@decaf-ts/core";import{isArray as Z,isString as ee,pickBy as te,negate as re}from"lodash";import{ApiExcludeEndpoint as oe,ApiParam as se,ApiBearerAuth as ie,ApiQuery as ne,ApiOperation as ae,ApiOkResponse as ce,ApiNoContentResponse as pe,ApiNotFoundResponse as de,ApiBody as le,getSchemaPath as ue,ApiCreatedResponse as he,ApiBadRequestResponse as fe,ApiUnprocessableEntityResponse as ge,ApiTags as me,ApiExtraModels as ye,DocumentBuilder as be,SwaggerModule as ve}from"@nestjs/swagger";import{OperationKeys as we,BulkCrudOperationKeys as Ae,InternalError as Ee,DBKeys as Pe,ValidationError as Re,BaseError as Te}from"@decaf-ts/db-decorators";import{__decorate as Oe,__param as xe,__metadata as Se}from"tslib";import{Reflector as $e,REQUEST as _e,ModuleRef as Ce,APP_INTERCEPTOR as ke,RouterModule as Ie}from"@nestjs/core";import{Logging as Ne,toPascalCase as Fe,toKebabCase as De,LoggedEnvironment as qe}from"@decaf-ts/logging";import{tap as Me,Observable as Le,interval as je,merge as Ue}from"rxjs";import{readFileSync as Be}from"fs";import*as Ge from"path";import ze from"yaml";import{tap as He,map as Ye}from"rxjs/operators";import{MigrationService as Je}from"@decaf-ts/core/migrations";import{WebhookSubscription as Xe,WebhookEventRecord as We,WebhookDelivery as Qe,collectPagedResults as Ve,WebhookStatus as Ke}from"@decaf-ts/for-http/server";export{WebhookDelivery,WebhookDeliveryService,WebhookEventRecord,WebhookPublisherService,WebhookSignatureMiddleware,WebhookStatus,WebhookSubscription,WebhookSubscriptionService,computeNextAttempt,signWebhookPayload,verifyWebhookSignature}from"@decaf-ts/for-http/server";const Ze="swagger",et={API_OPERATION:Ze+"/apiOperation",API_RESPONSE:Ze+"/apiResponse",API_PRODUCES:Ze+"/apiProduces",API_CONSUMES:Ze+"/apiConsumes",API_TAGS:Ze+"/apiUseTags",API_CALLBACKS:Ze+"/apiCallbacks",API_PARAMETERS:Ze+"/apiParameters",API_HEADERS:Ze+"/apiHeaders",API_MODEL_PROPERTIES:Ze+"/apiModelProperties",API_MODEL_PROPERTIES_ARRAY:Ze+"/apiModelPropertiesArray",API_SECURITY:Ze+"/apiSecurity",API_EXCLUDE_ENDPOINT:Ze+"/apiExcludeEndpoint",API_EXCLUDE_CONTROLLER:Ze+"/apiExcludeController",API_EXTRA_MODELS:Ze+"/apiExtraModels",API_EXTENSION:Ze+"/apiExtension",API_SCHEMA:Ze+"/apiSchema",API_DEFAULT_GETTER:Ze+"/apiDefaultGetter",API_LINK:Ze+"/apiLink"};function tt(e,t){if(!e)return[e,t];if(t)return[e,t];const r=Z(e);return[r?e[0]:e,r]}const rt=e=>void 0===e;function ot(e){if("function"==typeof e)return ot(e());if(Array.isArray(e))return e;if("object"!=typeof e)return[];const t=Object.values(e).filter(e=>"number"==typeof e).map(e=>e.toString());return Object.keys(e).filter(e=>!t.includes(e)).map(t=>e[t])}function st(e){return e.filter(ee).length>0?"string":"number"}function it(e,t,r=!0){return(o,s)=>{const i=Reflect.getMetadata(et.API_MODEL_PROPERTIES_ARRAY,o)||[],n=":"+s;i.includes(n)||Reflect.defineMetadata(et.API_MODEL_PROPERTIES_ARRAY,[...i,":"+s],o);const a=Reflect.getMetadata(e,o,s);if(a){const i=te(t,re(rt)),n=r?{...a,...i}:{...i,...a};Reflect.defineMetadata(e,n,o,s)}else{const r=o?.constructor?._OPENAPI_METADATA_FACTORY?.()[s]?.type??Reflect.getMetadata("design:type",o,s);Reflect.defineMetadata(e,{type:r,required:!1,...te(t,re(rt))},o,s)}}}function nt(e={}){return at(e)}function at(e={},t=!0){const[r,o]=tt(e.type,e.isArray);if((s=e={...e,type:r,isArray:o}).isArray&&"enum"in s&&void 0!==s.enum){e.type="array";const t=ot(e.enum);e.items={type:st(t),enum:t},delete e.enum}else if("enum"in e&&void 0!==e.enum){const t=ot(e.enum);e.enum=t,e.type=st(t)}var s;return Array.isArray(e.type)&&(e.type="array",e.items={type:"array",items:{type:e.type[0]}}),it(et.API_MODEL_PROPERTIES,e,t)}function ct(e,r){const{handler:o,args:s}=t.get(e,we.REFLECT+we.BLOCK)||{};return!!o&&(o(...s,r)??!1)}function pt(t,r,o){const s={GET:[we.READ,u],POST:[we.CREATE,l],PUT:[we.UPDATE,d],PATCH:[we.UPDATE,p],DELETE:[we.DELETE,c]},[i,n]=s[r];return ct(t,i)?e(oe()):e(n(o))}function dt(t,r,o){const s={GET:[Ae.READ_ALL,u],POST:[Ae.CREATE_ALL,l],PUT:[Ae.UPDATE_ALL,d],PATCH:[Ae.UPDATE_ALL,p],DELETE:[Ae.DELETE_ALL,c]},[i,n]=s[r];return ct(t,i)?e(oe()):e(n(o))}function lt(e=[]){const t=e.map(e=>se({name:e.name,description:e.description??"Path parameter: "+e.name,required:e.required??!0,type:e.type??String}));return h(...t)}const ut=f((e,t)=>{const r=t.switchToHttp().getRequest().body,o=t.getClass(),s=o.class;if(!s)throw new g(`ModelConstructor not found on controller ${o.name}. Ensure the controller was created via FromModelController.`);return r?Array.isArray(r)?r.map(e=>new s(e)):new s(r):r}),ht=f((e,t)=>{const r=t.switchToHttp().getRequest(),o=r?.params??{},s=e??Object.keys(o),i=s.map(e=>o[e]);return{raw:o,valuesInOrder:i,keysInOrder:s}});function ft(e=[]){const t=e.map(e=>e.name);return ht(t)}const gt=f((e,t)=>{const r={...t.switchToHttp().getRequest().query??{}};if(void 0!==r.limit){const e=Number(r.limit);Number.isNaN(e)||(r.limit=e)}if(void 0!==r.offset){const e=Number(r.offset);Number.isNaN(e)||(r.offset=e)}if(void 0!==r.bookmark){const e=Number(r.bookmark);r.bookmark=Number.isNaN(e)?r.bookmark:e}return r});function mt(e){const t={GET:u,POST:l,PUT:d,PATCH:p,DELETE:c}[e];if(!t)throw Error(`Unsupported HTTP verb "${e}". No NestJS decorator mapping was found.`);return t}const yt="DecafModuleOptions",bt="DecafAdapter",vt="DecafTaskService",wt="DecafRoute",At=Symbol("DecafHandlers"),Et=Symbol("DecafAdapterForOptions"),Pt=Symbol("AUTH_HANDLER"),Rt="auth:meta",Tt=Symbol("decaf:context");let Ot=class{constructor(e,t){this.reflector=e,this.authHandler=t}async intercept(e,t){const r=Ne.for(this).for(this.intercept),o=this.reflector.get(Rt,e.getHandler())??this.reflector.get(Rt,e.getClass());return r.verbose("Intercepted request"+(o?" for "+o:"")),this.authHandler?await this.authHandler.authorize(e,o):r.debug("No auth handler/model"),t.handle()}};function xt(e){const t=e?"string"==typeof e?e:e.name:void 0,r=[ie(),v(Ot)];return t&&r.push(w(Rt,t)),h(...r)}Ot=Oe([m(),xe(1,y()),xe(1,b(Pt)),Se("design:paramtypes",[$e,Object])],Ot);class St{parseRequest(e){const t=e.headers.authorization?.split(" ")[1];return t}async authorize(e,r){const o=e.switchToHttp().getRequest(),s=this.parseRequest(o);if(!s)throw new q("Unauthenticated");if(!t.get(N.get(r),M.AUTH_ROLE).includes(s))throw new q("Missing role: "+s)}}class $t extends St{constructor(){super()}async authorize(e,r){const o=e.switchToHttp().getRequest(),s=this.parseRequest(o);if(!s)throw new q("Unauthenticated");const i=t.get(N.get(r),M.AUTH_ROLE);if(!i.includes(s))throw new q("Missing role: "+s);return i}}let _t=class{constructor(e){this.req=e,this.uuid=L.instance.generate()}get request(){return this.req}put(e){let t;try{t=this.ctx.get("overrides")}catch(e){t={}}this._ctx=this.ctx.accumulate({overrides:Object.assign(t,e)})}applyCtx(e){if(this._ctx)throw new Ee("Trying to overwrite context");this._ctx=e}get ctx(){if(!this._ctx)throw new Ee("Context not initialized for request");return this._ctx}};var Ct;_t=Oe([m({scope:A.REQUEST}),xe(0,b(_e)),Se("design:paramtypes",[Request])],_t);let kt=Ct=class{constructor(e,t){this.handlers=e,this.context=t}async exec(e,t){Ne.for(Ct.name).for(this.exec).debug(`CONTEXT ${this.context.uuid} running ${this.handlers.length} handlers for request ${e.method} ${e.url}`);for(const r of this.handlers)await r.handle(this.context,e,t)}};kt=Ct=Oe([m({scope:A.REQUEST}),xe(0,b(At)),Se("design:paramtypes",[Array,_t])],kt);let It=class{constructor(e){this.ctx=e}intercept(e,t){let r=e.switchToHttp().getResponse();return t.handle().pipe(Me(e=>{r=this.ctx.ctx.toResponse(r)}))}};It=Oe([m(),Se("design:paramtypes",[_t])],It);const Nt=e=>({name:e,description:e+" parameter for the query",required:!0,type:String});function Ft(e,t,r,o=!1){const s=mt(r),i=(e=>e.split("/").filter(e=>e.startsWith(":")).map(e=>e.slice(1)))(t).map(Nt),n=[];return"GET"===r&&o&&n.push(ne({name:"direction",required:!1,enum:j,description:"the sort order when applicable"}),ne({name:"limit",required:!1,description:"limit or page size when applicable"}),ne({name:"offset",required:!1,description:"offset or bookmark when applicable"})),{method:[s(t),...i.map(se),...n,ae({summary:`Retrieve records using according to "${e}".`}),ce({description:"Result successfully retrieved."}),pe({description:"No content returned by the method."})],params:[ft(i),E()]}}function Dt(e,t,r,o){const s=e?.prototype??e;o.method.forEach(e=>e(s,t,r)),o.params?.forEach((e,r)=>e(s,t,r))}function qt(e,t,...r){if(e instanceof U)return"function"==typeof e[t]?e[t](...r):e.statement(t,...r);if("function"==typeof e[t])return e[t](...r);throw Error(`Persistence method "${t}" not found on ${e?.constructor?.name}`)}function Mt(e){return async function(t,r){const o=this.log.for(e);try{o.debug(`Invoking persistence method "${e}" given parameters: ${JSON.stringify(t.valuesInOrder)}`);const{direction:s,limit:i,offset:n}=r;return await qt(this.persistence(),e,...t.valuesInOrder,s,i,n)}catch(t){throw o.error(`Custom query "${e}" failed`,t),t}}}function Lt(e,t,r){return Object.defineProperty(e.prototype||e,t,{value:r,writable:!1}),Object.getOwnPropertyDescriptor(e.prototype||e,t)}class jt extends B{constructor(e,t){super(),this.clientContext=e}logCtx(e,t,r=!1,o){const s=this.clientContext.ctx;let i;e=e.filter(e=>void 0!==e),o&&(o.headers||o.ip)&&(i=o,o={});const n=z.logCtx.call(this,t,o||{},r,...e,s);return this.bindLoggerToRequest(n,i)}bindLoggerToRequest(e,t){const r=this;function o(e,t){return e.log=((e,t)=>{const o=(e=>{if(!e)return;const t=e.headers,r=Bt(t?.["x-forwarded-for"])??Bt(t?.["x-real-ip"])??Bt(t?.["X-Forwarded-For"])??Bt(t?.["X-Real-IP"]);if(r)return r;if("string"==typeof e.ip&&e.ip.length)return e.ip;const o=e.socket||e.connection;return o&&"string"==typeof o.remoteAddress&&o.remoteAddress.length?o.remoteAddress:void 0})(t??r.clientContext.request);if(!o)return e;const s={ip:o};return e.for(s)})(e.log,t),e}return(e=>"object"==typeof e&&null!==e&&"function"==typeof e.then)(e)?e.then(e=>o(e,t)):o(e,t)}}class Ut extends jt{persistence(e){if(!this._persistence)try{this._persistence=B.get(this.class)}catch(e){try{this._persistence=U.getService(this.class)}catch(e){this._persistence=G.forModel(this.class)}}const t=this.clientContext.request[Et]||{};return e&&this.clientContext.put(t),e?this._persistence instanceof G?this._persistence.override(t):this._persistence.for(t):this._persistence}constructor(e,t){super(e,t)}logCtx(e,t,r=!1,o){const s=this.clientContext.ctx;let i;o&&(o.headers||o.ip)&&(i=o,o={});try{o=s.get("overrides")}catch(e){}const n=this.persistence(s);let a,c;return n instanceof U?a=n.repo._adapter:n instanceof G?a=n._adapter:n.context&&(a=n),r?a.logCtx(e,t,!0,o).then(e=>this.bindLoggerToRequest(e,i)):(c=a.logCtx(e,t,!1,o),this.bindLoggerToRequest(c,i))}}function Bt(e){if(e)return(Array.isArray(e)?e[0]:e).split(",").map(e=>e.trim()).filter(Boolean)[0]}const Gt=new Map;function zt(e,r){if(!H.includes(e))return r;const o=(e=>(Gt.has(e)||Gt.set(e,new WeakMap),Gt.get(e)))(e),s=o.get(r);if(s)return s;const i=[we.UPDATE,Ae.UPDATE_ALL].includes(e);class n{}o.set(r,n),Object.defineProperty(n,"name",{value:`${Fe(r.name)}${Fe(e)}DTO`});const a=(()=>{try{return N.pk(r)}catch{return}})(),c=a?N.pkProps(r):void 0,p=a?Reflect.getMetadata("design:type",r.prototype,a):void 0,d=p===Number||p===BigInt,l=!!c?.generated||!!a&&(N.generatedBySequence(r,a)||Jt(r,a)||d),u=Array.from(new Set(t.properties(r)||[])),h=new Set(N.relations(r)||[]),f=[];for(const e of u)e&&(h.has(e)||e===a&&!i&&l||e!==a&&Jt(r,e)||f.push(e));for(const e of f){const t=Xt(r,e),o=!!t?.[F.REQUIRED],s=Wt(r,e)??Reflect.getMetadata("design:type",r.prototype,e),i={required:o};s&&(i.type=s),nt(i)(n.prototype,e);const a=Reflect.getMetadata("design:type",r.prototype,e)??s;void 0!==a&&Reflect.defineMetadata("design:type",a,n.prototype,e),Object.defineProperty(n.prototype,e,{value:void 0,writable:!0,enumerable:!0,configurable:!0})}for(const o of h){const s=t.relations(r,o);if(!s)throw new Ee(`Metadata for relation ${o} not found`);let a=s.class;if("function"!=typeof a||a.name||(a=a()),!a||"function"!=typeof a)throw new Ee(`Type for relation ${o} not found`);if(!N.get(a.name))continue;const c=t.validationFor(r,o),p=!!c?.[F.LIST],d=!!c?.[F.REQUIRED],l=zt(e,a);i?Yt(n,o,a,l,p,d):Ht(n,o,l,p,d)}return n}function Ht(e,t,r,o,s){nt({type:r,required:s,isArray:o})(e.prototype,t),Reflect.defineMetadata("design:type",o?Array:r,e.prototype,t),Object.defineProperty(e.prototype,t,{value:void 0,writable:!0,enumerable:!0,configurable:!0})}function Yt(e,t,r,o,s,i){const n=Reflect.getMetadata(et.API_EXTRA_MODELS,e)||[];n.includes(o)||Reflect.defineMetadata(et.API_EXTRA_MODELS,[...n,o],e);const a="#/components/schemas/"+o.name,c=(e=>{try{const t=N.pkProps(e),r=t?.type;return r===Number||r===BigInt?"integer":"string"}catch{return"string"}})(r),p=[{$ref:a},{type:c}];nt(s?{type:"array",required:i,oneOf:p}:{type:Object,required:i,oneOf:p})(e.prototype,t),Reflect.defineMetadata("design:type",s?Array:Object,e.prototype,t),Object.defineProperty(e.prototype,t,{value:void 0,writable:!0,enumerable:!0,configurable:!0})}function Jt(e,t){let r=e;for(;r&&r!==Object&&r!==Function;){if(N.generated(r,t))return!0;r=Object.getPrototypeOf(r)}return!1}function Xt(e,r){let o=e;for(;o&&o!==Object&&o!==Function;){const e=t.validationFor(o,r);if(e)return e;o=Object.getPrototypeOf(o)}}function Wt(e,r){let o=e;for(;o&&o!==Object&&o!==Function;){const e=t.type(o,r);if(e)return e;o=Object.getPrototypeOf(o)}}Y.transformerFor=(e=>{const r="string"==typeof e?e:e.alias;return t.innerGet(Symbol.for("transformers"),r)}).bind(Y),Y.flavoursToTransform=(()=>{const e=t.innerGet(Symbol.for("transformers"));if(e)return Object.keys(e)}).bind(Y),J.prototype.toResponse=function(e){const t=this.pending();return t&&e.header("x-pending-task",JSON.stringify(t)),e};const Qt=D.prototype;if(Qt.decorateClass||(Qt.decorateClass=function(e){return this._classDecorators||(this._classDecorators=[]),this._classDecorators.push(e),this}),Qt.Auth=function(e){return this.decorateClass(xt(e))},!Qt.__hasClassDecoratorSupport){const e=Qt.build;Qt.build=function(){let t=e.call(this);const r=this._classDecorators;if(r?.length)for(const e of r){const r=e(t);r&&(t=r)}return t},Qt.__hasClassDecoratorSupport=!0}class Vt{static{this.log=Ne.for(Vt.name)}static getPersistence(e){try{return B.get(e)}catch(t){try{return U.getService(e)}catch(t){return G.forModel(e)}}}static createQueryRoutesFromRepository(e,r=M.QUERY){const o=Vt.log.for(Vt.createQueryRoutesFromRepository),s=e instanceof U?e.repo:e,i=s.class,n=t.get(s.constructor,t.key(M.QUERY))??{},a=t.get(e.constructor,t.key(wt))??{};class c extends Ut{get class(){throw Error("Method not implemented.")}constructor(e,t){super(e,t)}}for(const[e,t]of Object.entries(a)){const r=[t.path.replace(/^\/+|\/+$/g,"")].filter(e=>e&&e.trim()).join("/"),s=Mt(e);if(!s){const t=`Invalid or missing handler for model ${i.name} on decorated method ${e}`;throw o.error(t),Error(t)}const n=Lt(c,e,s);n&&Dt(c,e,n,Ft(e,r,t.httpMethod))}for(const[e,t]of Object.entries(n)){const o=[r,e,...(t.fields??[]).map(e=>":"+e)].filter(e=>e&&e.trim()).join("/"),s=Lt(c,e,Mt(e));s&&Dt(c,e,s,Ft(e,o,"GET",!0))}return c}static create(e){const t=Vt.log.for(Vt.create),r=N.tableName(e),o=De(r),s=e.name,i=Vt.getPersistence(e),{description:n,getPK:a,apiProperties:c,path:p}=Vt.getRouteParametersFromModel(e);t.debug("Creating controller for model: "+s);const d=Vt.createQueryRoutesFromRepository(i);let l=class extends d{static get class(){return e}get class(){return e}constructor(r){super(r),this.pk=N.pk(e),t.info(`Registering dynamic controller for model: ${this.class.name} route: /${o}`)}async listBy(e,t){const{ctx:r}=(await this.logCtx([],X.LIST_BY,!0)).for(this.listBy);return this.persistence(r).listBy(e,t.direction,r)}async paginateBy(e,t){const{ctx:r}=(await this.logCtx([],X.PAGE_BY,!0)).for(this.paginateBy);return this.persistence(r).paginateBy(e,t.direction,t,r)}async find(e,t){const{ctx:r}=(await this.logCtx([],X.FIND,!0)).for(this.find),o=t.direction??j.ASC;return qt(this.persistence(r),this.find.name,e,o,r)}async page(e,t){const{ctx:r}=(await this.logCtx([],X.PAGE,!0)).for(this.page),{direction:o=j.ASC,limit:s,offset:i,bookmark:n}=t,a={offset:i??1,limit:s??10,bookmark:n};return qt(this.persistence(r),this.page.name,e,o,a,r)}async findOneBy(e,t){const{ctx:r}=(await this.logCtx([],X.FIND_ONE_BY,!0)).for(this.findOneBy);return this.persistence(r).findOneBy(e,t,r)}async findBy(e,t,r){const{ctx:o}=(await this.logCtx([],X.FIND_BY,!0)).for(this.findBy);return this.persistence(o).for(o.toOverrides()).findBy(e,t,o)}async statement(e,t,r){const{ctx:o}=(await this.logCtx([],M.STATEMENT,!0)).for(this.statement),{direction:s,offset:i,limit:n,bookmark:a}=r,c=(t=t.map(e=>("string"==typeof e?parseInt(e):e)||e)).length>1?t[1]:void 0,p=s??c;switch(p&&t.length>1&&(t[1]=p),e){case X.FIND:case X.FIND_BY:break;case X.LIST_BY:t.push(s);break;case X.PAGE:case X.PAGE_BY:t=[t[0],p,{limit:n,offset:i,bookmark:a}];case X.FIND_ONE_BY:case X.COUNT_OF:case X.MAX_OF:case X.MIN_OF:case X.AVG_OF:case X.SUM_OF:case X.DISTINCT_OF:case X.GROUP_OF:}return this.persistence(o).statement(e,...t,o)}async createAll(t,r){const{ctx:o,log:i}=(await this.logCtx([],Ae.CREATE_ALL,!0)).for(this.createAll);let n;i.verbose("creating new "+s);try{n=await this.persistence(o).createAll(t.map(t=>new e(t)),o)}catch(e){throw i.error("Failed to create new "+s,e),e}return i.info(`created new ${s} with id ${n[this.pk]}`),o.toResponse(r),n}async create(e,t){const{ctx:r,log:o}=(await this.logCtx([],we.CREATE,!0)).for(this.create);let i;o.verbose("creating new "+s);try{const t=this.persistence(r);i=await t.create(e,r)}catch(e){throw o.error("Failed to create new "+s,e),e}return o.info(`created new ${s} with id ${i[this.pk]}`),r.toResponse(t),i}async readAll(e){const{ctx:t,log:r}=(await this.logCtx([],Ae.READ_ALL,!0)).for(this.readAll),o=Array.isArray(e)?e:[e];let i;try{r.debug(`reading ${o} ${s}: ${o}`);const e=this.persistence(t);i=await e.readAll(o,t)}catch(e){throw r.error(`Failed to ${s} with id ${o}`,e),e}return r.info(`read ${i.length} ${s}`),i}async read(e){const{ctx:t,log:r}=(await this.logCtx([],we.READ,!0)).for(this.read),o=a(...e.valuesInOrder);if(void 0===o)throw new Re(`No ${this.pk} provided`);let i;try{r.debug(`reading ${s} with ${this.pk} ${o}`);const e=this.persistence(t);i=await e.read(o,t)}catch(e){throw r.error(`Failed to read ${s} with id ${o}`,e),e}return r.info(`read ${s} with id ${i[this.pk]}`),i}async updateAll(e,t){const{ctx:r,log:o}=(await this.logCtx([],Ae.UPDATE_ALL,!0)).for(this.updateAll);let i;try{o.info(`updating ${e.length} ${s}`),i=await this.persistence(r).updateAll(e,r)}catch(e){throw o.error(e),e}return r.toResponse(t),i}async update(t,r,o){const{ctx:i,log:n}=(await this.logCtx([],we.UPDATE,!0)).for(this.update),c=a(...t.valuesInOrder);if(void 0===c)throw new Re(`No ${this.pk} provided`);let p;try{n.info(`updating ${s} with ${this.pk} ${c}`);const t=JSON.parse(JSON.stringify(r)),o=this.persistence(i);p=await o.update(new e({...t,[this.pk]:c}),i)}catch(e){throw n.error(e),e}return i.toResponse(o),p}async deleteAll(e,t){const{ctx:r,log:o}=(await this.logCtx([],Ae.DELETE_ALL,!0)).for(this.deleteAll),i=Array.isArray(e)?e:[e];let n;try{o.debug(`deleting ${i.length} ${s}: ${i}`),n=await this.persistence(r).deleteAll(i,r)}catch(e){throw o.error(`Failed to delete ${s} with id ${i}`,e),e}return o.info(`deleted ${n.length} ${s}`),r.toResponse(t),n}async delete(e,t){const{ctx:r,log:o}=(await this.logCtx([],we.DELETE,!0)).for(this.delete),i=a(...e.valuesInOrder);if(void 0===i)throw new Re(`No ${this.pk} provided`);let n;try{o.debug(`deleting ${s} with ${this.pk} ${i}`),n=await this.persistence(r).delete(i,r)}catch(e){throw o.error(`Failed to delete ${s} with id ${i}`,e),e}return o.info(`deleted ${s} with id ${i}`),r.toResponse(t),n}};return Oe([pt(e,"GET","listBy/:key"),ae({summary:`Retrieve ${s} records by query.`}),se({name:"key",description:"the model key to sort by"}),ne({name:"direction",required:!0,enum:j}),ce({description:s+" listed successfully."}),xe(0,P("key")),xe(1,gt()),Se("design:type",Function),Se("design:paramtypes",[String,Object]),Se("design:returntype",Promise)],l.prototype,"listBy",null),Oe([pt(e,"GET","paginateBy/:key/:page"),ae({summary:`Retrieve ${s} records by query.`}),se({name:"key",description:"the model key to sort by"}),se({name:"page",description:"the page to retrieve or the bookmark"}),ne({name:"direction",required:!0,enum:j,description:"the sort order"}),ne({name:"limit",required:!0,description:"the page size"}),ne({name:"offset",description:"the bookmark when necessary"}),ce({description:s+" listed paginated."}),xe(0,P("key")),xe(1,gt()),Se("design:type",Function),Se("design:paramtypes",[String,Object]),Se("design:returntype",Promise)],l.prototype,"paginateBy",null),Oe([pt(e,"GET","find/:value"),ae({summary:`Find ${s} records using the default query attributes.`}),se({name:"value",description:"The string to match against the default query attributes"}),ne({name:"direction",required:!1,enum:j,description:"the sort order for the matching results"}),ce({description:s+" records matching the provided prefix."}),xe(0,P("value")),xe(1,gt()),Se("design:type",Function),Se("design:paramtypes",[String,Object]),Se("design:returntype",Promise)],l.prototype,"find",null),Oe([pt(e,"GET","page/:value"),ae({summary:`Page ${s} records using the default query attributes.`}),se({name:"value",description:"The string to match against the default query attributes"}),ne({name:"direction",required:!1,enum:j,description:"the sort order for the paged results"}),ne({name:"limit",required:!1,description:"page size"}),ne({name:"offset",required:!1,description:"page number"}),ne({name:"bookmark",required:!1,description:"bookmark for cursor pagination"}),ce({description:s+" records paged by the provided prefix."}),xe(0,P("value")),xe(1,gt()),Se("design:type",Function),Se("design:paramtypes",[String,Object]),Se("design:returntype",Promise)],l.prototype,"page",null),Oe([pt(e,"GET","findOneBy/:key"),ae({summary:`Retrieve ${s} records by query.`}),se({name:"key",description:"the model key to sort by"}),ce({description:s+" listed found."}),de({description:`No ${s} record matches the provided identifier.`}),xe(0,P("key")),xe(1,P("value")),Se("design:type",Function),Se("design:paramtypes",[String,Object]),Se("design:returntype",Promise)],l.prototype,"findOneBy",null),Oe([pt(e,"GET","findBy/:key/:value"),ae({summary:`Retrieve ${s} records by query.`}),se({name:"key",description:"the model key to compare"}),se({name:"value",description:"the value to match"}),ne({name:"direction",required:!0,enum:j,description:"the sort order when applicable"}),ce({description:s+" listed found."}),de({description:`No ${s} record matches the provided identifier.`}),xe(0,P("key")),xe(1,P("value")),xe(2,gt()),Se("design:type",Function),Se("design:paramtypes",[String,Object,Object]),Se("design:returntype",Promise)],l.prototype,"findBy",null),Oe([pt(e,"GET","statement/:method/*args"),ae({summary:`Executes a prepared statement on ${s}.`}),se({name:"method",description:"the prepared statement to execute"}),se({name:"args",description:"concatenated list of arguments the prepared statement can accept"}),ne({name:"direction",required:!0,enum:j,description:"the sort order when applicable"}),ne({name:"limit",required:!0,description:"limit or page size when applicable"}),ne({name:"offset",required:!0,description:"offset or bookmark when applicable"}),ce({description:s+" listed found."}),de({description:`No ${s} record matches the provided identifier.`}),xe(0,P("method")),xe(1,P("args")),xe(2,gt()),Se("design:type",Function),Se("design:paramtypes",[String,Array,Object]),Se("design:returntype",Promise)],l.prototype,"statement",null),Oe([pt(e,"POST","bulk"),ae({summary:`Create a new ${s}.`}),le({description:"Payload for "+s,schema:{type:"array",items:{$ref:ue(e)}}}),he({description:s+" created successfully.",schema:{type:"array",items:{$ref:ue(e)}}}),fe({description:"Payload validation failed."}),ge({description:"Repository rejected the provided payload."}),xe(0,ut()),xe(1,R({passthrough:!0})),Se("design:type",Function),Se("design:paramtypes",[Array,Object]),Se("design:returntype",Promise)],l.prototype,"createAll",null),Oe([pt(e,"POST"),ae({summary:`Create a new ${s}.`}),le({description:"Payload for "+s,type:zt(we.CREATE,e)}),he({description:s+" created successfully.",schema:{$ref:ue(e)}}),fe({description:"Payload validation failed."}),ge({description:"Repository rejected the provided payload."}),xe(0,ut()),xe(1,R({passthrough:!0})),Se("design:type",Function),Se("design:paramtypes",[Object,Object]),Se("design:returntype",Promise)],l.prototype,"create",null),Oe([pt(e,"GET","bulk"),ae({summary:`Retrieve a ${s} record by id.`}),ne({name:"ids",required:!0,type:"array"}),ce({description:s+" retrieved successfully.",schema:{type:"array",items:{$ref:ue(e)}}}),de({description:`No ${s} record matches the provided identifier.`}),xe(0,E("ids")),Se("design:type",Function),Se("design:paramtypes",[Array]),Se("design:returntype",Promise)],l.prototype,"readAll",null),Oe([pt(e,"GET",p),lt(c),ae({summary:`Retrieve a ${s} record by id.`}),ce({description:s+" retrieved successfully.",schema:{$ref:ue(e)}}),de({description:`No ${s} record matches the provided identifier.`}),xe(0,ft(c)),Se("design:type",Function),Se("design:paramtypes",[Object]),Se("design:returntype",Promise)],l.prototype,"read",null),Oe([pt(e,"PUT","bulk"),lt(c),ae({summary:`Replace an existing ${s} record with a new payload.`}),le({description:"Payload for replace a existing record of "+s,schema:{type:"array",$ref:ue(zt(we.UPDATE,e))}}),ce({description:s+" updated successfully.",schema:{type:"array",items:{$ref:ue(e)}}}),de({description:`No ${s} record matches the provided identifier.`}),fe({description:"Payload validation failed."}),xe(0,ut()),xe(1,R({passthrough:!0})),Se("design:type",Function),Se("design:paramtypes",[Array,Object]),Se("design:returntype",Promise)],l.prototype,"updateAll",null),Oe([pt(e,"PUT",p),lt(c),ae({summary:`Replace an existing ${s} record with a new payload.`}),le({description:"Payload for replace a existing record of "+s,type:zt(we.UPDATE,e)}),ce({description:s+" updated successfully.",schema:{$ref:ue(e)}}),de({description:`No ${s} record matches the provided identifier.`}),fe({description:"Payload validation failed."}),xe(0,ft(c)),xe(1,ut()),xe(2,R({passthrough:!0})),Se("design:type",Function),Se("design:paramtypes",[Object,Object,Object]),Se("design:returntype",Promise)],l.prototype,"update",null),Oe([pt(e,"DELETE","bulk"),lt(c),ae({summary:`Retrieve a ${s} record by id.`}),ne({name:"ids",required:!0,type:"array"}),ce({description:s+" deleted successfully.",schema:{type:"array",items:{$ref:ue(e)}}}),de({description:`No ${s} record matches the provided identifier.`}),xe(0,E("ids")),xe(1,R({passthrough:!0})),Se("design:type",Function),Se("design:paramtypes",[Array,Object]),Se("design:returntype",Promise)],l.prototype,"deleteAll",null),Oe([pt(e,"DELETE",p),lt(c),ae({summary:`Delete a ${s} record by id.`}),ce({description:s+" deleted successfully.",schema:{$ref:ue(e)}}),de({description:`No ${s} record matches the provided identifier.`}),xe(0,ft(c)),xe(1,R({passthrough:!0})),Se("design:type",Function),Se("design:paramtypes",[Object,Object]),Se("design:returntype",Promise)],l.prototype,"delete",null),l=Oe([T(o),me(s),ye(e),xt(e),Se("design:paramtypes",[_t])],l),l}static getRouteParametersFromModel(e){const r=N.pk(e),o=t.get(e,t.key(Pe.COMPOSED,r)),s=o?.args??[],i=Array.isArray(s)&&s.length>0?Array.from(new Set([...s])):Array.from(new Set([r])),n=t.description(e);return{path:":"+i.join("/:"),description:n,apiProperties:i.map(r=>({name:r,description:t.description(e,r),required:!0,type:String})),getPK:(...e)=>o?.separator?e.join(o.separator):e.join("")}}}function Kt(e){var t;let r=class{static{t=this}static{this.log=Ne.for(t.name).for(e)}static createModelServices(e){return e.map(e=>({provide:e.name+"Service",useFactory:()=>U.forModel(e)}))}static forRoot(e,r={}){const o=this.log.for(this.forRoot);o.info("Generating controllers for flavour...");const s=Y.models(e);let i=[];r.autoServices&&(o.info("Auto-services enabled. Initializing service generation."),i=this.createModelServices(s),o.info(`Auto-services completed. ${i.length} services initialized.`));const n=s.map(Vt.create);return o.info(`Generated ${n.length} controllers`),{module:t,controllers:n,providers:[...i]}}};return r=t=Oe([O({})],r),Object.assign(r,"name",{value:"DecafModule"+e}),r}r.for(n.INJECTABLE).extend({decorator:(e,t)=>(t=t||("object"==typeof e?Object.assign(e,a):a),m({scope:t.singleton?A.DEFAULT:A.REQUEST,durable:!t.singleton||void 0}))}).apply(),r.for(n.INJECT).extend({decorator:(e,t)=>(t,r,o)=>b(e||t)(t,r,o)}).apply(),r.for(F.REQUIRED).extend(nt({required:!0})).apply(),r.for(F.MAX).extend({decorator:e=>nt({maximum:e,required:!1})}).apply(),r.for(F.MIN).extend({decorator:e=>nt({minimum:e,required:!1})}).apply(),r.for(F.MAX_LENGTH).extend({decorator:e=>nt({maxLength:e,required:!1})}).apply(),r.for(F.MIN_LENGTH).extend({decorator:e=>nt({minLength:e,required:!1})}).apply(),r.for(F.TYPE).extend({decorator:e=>(t,r)=>("function"!=typeof(e=Array.isArray(e)?e[0]:e)||e.name||(e=e()),nt({type:e,required:!1})(t,r))}).apply(),r.for(F.DATE).extend({decorator:e=>nt({type:String,format:"date-time",required:!1})}).apply(),r.for(F.ENUM).extend({decorator:e=>nt({enum:Array.isArray(e)?e:Object.values(e),required:!1})}).apply(),r.for(F.PATTERN).extend({decorator:e=>nt({pattern:"string"==typeof e?e:e.source,required:!1})}).apply(),r.for(M.COLUMN).extend({decorator:e=>nt({name:e,required:!1})}).apply(),r.for(o.DESCRIPTION).extend({decorator:e=>nt({description:e,required:!1})}).apply(),r.for(M.AUTH).extend({decorator:xt}).apply();class Zt extends W{constructor(e){super(e,Zt.name)}}class er extends Te{constructor(e){super(er.name,e,429)}}let tr=class{catch(e,t){const r=t.switchToHttp(),o=r.getResponse(),s=r.getRequest(),i="production"===qe.env;let n;e instanceof S||e instanceof Q?n=(e=new $(e.message)).getStatus():e instanceof Te||(e=429===e.status?new er(e.message):new Ee(e.message)),o.status(e.code||n).json({status:e.code||n,error:i?e.name:e.message,timestamp:(new Date).toISOString(),path:s.url,method:s.method})}};function rr(){return _(new tr)}function or(){return v(It)}tr=Oe([x()],tr);const sr={path:"docs",auth:{type:"http",scheme:"bearer",bearerFormat:"JWT",name:"Authorization",description:"Enter JWT token",in:"header"},topbarBgColor:"#000000"};class ir{constructor(e){this.options={...e}}customCSS(){let e="";return this.options.topbarIconPath&&(e+=`.topbar-wrapper { content: url('data:image/png;base64,${this.b64(this.options.topbarIconPath)}'); width: 200px; height: auto; }\n`),e+`\n .topbar-wrapper svg { visibility: hidden; }\n .swagger-ui .topbar { background-color: ${this.options.topbarBgColor||sr.topbarBgColor}; }\n `}getCustomOptions(){const e={};return this.options.faviconPath&&(e.customfavIcon=this.b64(this.options.faviconPath,!0)),{customSiteTitle:this.options.title,...e,customCss:this.customCSS(),swaggerOptions:{persistAuthorization:this.options.persistAuthorization}}}b64(e,t=!1){const r=Ge.join(this.options.assetsPath||"",e),o=Be(r,{encoding:"base64"});return t?"data:image/png;base64,"+o:o}}class nr{constructor(e,t){this.app=e,this.options=t}createDocument(){const e=this.options.path?this.options.description+""+`<br><br><a href="${this.options.openApiJsonPath}">OpenAPI JSON Spec</a> | `+`<a href="${this.options.openApiYamlPath}">OpenAPI YAML Spec</a>`:this.options.description,t=(new be).setTitle(this.options.title).setDescription(e).setVersion(this.options.version||"0.0.1").addBearerAuth(this.options.auth||sr.auth).build();return ve.createDocument(this.app,t,{extraModels:this.options.extraModels||[]})}registerOpenApiRoute(e,t,r){if(!e)return;const o=this.app.getHttpAdapter();e=e.startsWith("/")?e:"/"+e,o.get(e,(e,s)=>{o.reply(s,r(),200,{"Content-Type":t})})}setupSwagger(){const e=this.createDocument(),t=new ir({title:this.options.title,path:this.options.path||sr.path,persistAuthorization:this.options.persistAuthorization??!0,assetsPath:this.options.assetsPath,faviconPath:this.options.faviconFilePath,topbarIconPath:this.options.topbarIconFilePath,topbarBgColor:this.options.topbarBgColor});ve.setup(this.options.path||sr.path,this.app,e,{...t.getCustomOptions(),jsonDocumentUrl:this.options.openApiJsonPath?""+this.options.openApiJsonPath:void 0,yamlDocumentUrl:this.options.openApiYamlPath?""+this.options.openApiYamlPath:void 0}),this.registerOpenApiRoute(this.options.openApiJsonPath,"application/json",()=>e),this.registerOpenApiRoute(this.options.openApiYamlPath,"application/x-yaml",()=>ze.stringify(e))}}class ar{static get logger(){return this._logger||(this._logger=new C("NestBootstrap")),this._logger}static initialize(e){return this.app=e,this}static enableLogger(e){return this._logger=e||new C("NestBootstrap"),this.app.useLogger(this._logger),this}static enableCors(e=[],t=["GET","POST","PUT","DELETE"]){const r="*"===e?"*":e.map(e=>e.trim().toLowerCase()),o={origin:(e,t)=>e?"*"===r||Array.isArray(r)&&r.includes(e.toLowerCase())?t(null,!0):void t(new Zt(`Origin ${e} not allowed`)):t(null,!0),credentials:!0,methods:t.join(",")};return this.app.enableCors(o),this}static useHelmet(e){try{const t=require("helmet");this.app.use(t(e)),this.logger.log("Helmet middleware enabled successfully.")}catch(e){this.logger.warn("Helmet not installed. Skipping middleware.")}return this}static setupSwagger(e){return new nr(this.app,{title:e.title,description:e.description,version:e.version,path:e.path||"api",persistAuthorization:e.persistAuthorization??!0,assetsPath:e.assetsPath,faviconFilePath:e.faviconPath,topbarIconFilePath:e.topbarIconPath,topbarBgColor:e.topbarBgColor,openApiJsonPath:e.openApiJsonPath,openApiYamlPath:e.openApiYamlPath}).setupSwagger(),this}static useGlobalPipes(...e){return e.length>0&&this.app.useGlobalPipes(...e),this}static useGlobalFilters(...e){return this.app.useGlobalFilters(...e.length>0?e:[new tr]),this}static useGlobalInterceptors(...e){return e.length>0&&this.app.useGlobalInterceptors(...e),this}static async start(e=Number(process.env.PORT)||3e3,t=void 0,r=!0){this.app.listen(e,t).then(async()=>{if(r){const e=await this.app.getUrl();this.logger.log("\ud83d\ude80 Application is running at: "+e)}})}}var cr;let pr=cr=class{constructor(e,t){this.requestContext=e,this.executor=t}async contextualize(e){const t={headers:e.headers,overrides:{}},r=Y.flavoursToTransform();if(r)for(const o of r)try{const r=Y.transformerFor(o),s=await r.from(e);Object.assign(t.overrides,s)}catch(e){throw new Ee("Failed to contextualize request: "+e)}return(new J).accumulate(Object.assign({},V,{logger:Ne.get(),timestamp:new Date},t))}async intercept(e,t){const r=e.switchToHttp().getRequest(),o=e.switchToHttp().getResponse(),s=Ne.for(cr).for(this.intercept);s.debug(`CONTEXT ${this.requestContext.uuid} - request: ${r.method} ${r.url}`);const i=await this.contextualize(r);return s.debug(`CONTEXT ${this.requestContext.uuid} contextualized - request: ${r.method} ${r.url}`),this.requestContext.applyCtx(i),s.debug(`CONTEXT ${this.requestContext.uuid} applied - request: ${r.method} ${r.url}`),await this.executor.exec(r,o),s.debug(`CONTEXT ${this.requestContext.uuid} executors finished - request: ${r.method} ${r.url}`),t.handle()}};pr=cr=Oe([m({scope:A.REQUEST}),Se("design:paramtypes",[_t,kt])],pr);class dr{}function lr(e){return r=>(t.set("transformers",e,r),"function"==typeof r?s("transformers",e)(r):r)}var ur;let hr=class{static{ur=this}static get persistence(){if(!this._persistence)throw new Ee("Persistence service not initialized");return this._persistence}static get log(){return this._logger||(this._logger=Ne.for(ur)),this._logger}constructor(e,t){this.options=e,this.moduleRef=t}static forRoot(e){const t=this.log.for(this.forRoot);return{module:ur,providers:[{provide:yt,useValue:e},{provide:bt,useValue:this.persistence?.client},{provide:At,useFactory:()=>e.handlers?.map(e=>(t.info("Registered request handler: "+e.name),new e))??[]},Ot,{provide:ke,useExisting:Ot},_t,kt,{provide:ke,useClass:pr}],exports:[yt,bt,At,_t,kt]}}static async bootPersistence(e){const t=this.log.for(this.bootPersistence);if(!this._persistence){const r=e.conf.map(([e,t,...r])=>r.pop()?[e,t,...r]:[e,t]);this._persistence=new K,await this._persistence.boot(r);const o=this._persistence.client;for(let t=0;t<o.length;t++){const r=e.conf[t];let s=r.slice(2,r.length).pop();if(!s||!s.from){const e=Y.transformerFor(o[t].flavour);if(!e)throw new Ee(`No transformer found for flavour ${o[t].flavour}. you should either @requestToContextTransformer or provide a transformer in the config`);try{s=e.from?e:new e}catch(e){throw new Ee(`Failed to boot transformer for ${o[t].flavour}: ${e}`)}}lr(o[t].flavour)(s)}if(t.info("persistence layer created successfully!"),e.initialization)try{await e.initialization()}catch(e){throw new Ee("Failed to initialize application: "+e)}}return this.persistence.client}async onApplicationShutdown(){const e=ur.log.for(this.onApplicationShutdown),t=this.moduleRef.get(bt);for(const r of t)try{r&&(e.info("Shutting down "+r.toString()),await r.shutdown())}catch(t){e.error("Failed to shutdown application",t)}try{await B.shutdown()}catch(t){e.error("Failed to shutdown services",t)}}};hr=ur=Oe([k(),O({}),xe(0,b(yt)),Se("design:paramtypes",[Object,Ce])],hr);const fr=Symbol("LISTENING_ADAPTERS_FLAVOURS");var gr;let mr=gr=class extends jt{constructor(e,t){super(e,gr.name),this.adapters=t.map(e=>Y.get(e))}listen(){const e=Ne.for(gr.name),t=new Le(t=>{const r=("B-"+Math.random().toString(36).slice(2,8)).toUpperCase();e.info(`Creating SSE observer: ${r} for client ${this.clientContext.uuid}`);const o=new class{constructor(){this.observerId=r}refresh(...r){return e.debug(`SSE observer ${this.observerId} received refresh event`),Promise.resolve().then(()=>{const o=(e=>{const[t,r,o,s]=e;return[t?.name??t,r,o,Array.isArray(s)?s.map(e=>{try{return"function"==typeof e.serialize?e.serialize():"string"==typeof e?e:JSON.stringify(e)}catch(e){return}}):s&&"function"==typeof s.serialize?s.serialize():"string"==typeof s?s:JSON.stringify(s)]})(r);t.next({type:"message",data:o}),e.debug(`SSE observer ${this.observerId} event pushed to client`)})}};e.verbose(`Registering observer ${r} across ${this.adapters.length} adapter(s)`);for(const t of this.adapters){const s=t?.constructor?.name??"UnknownAdapter";try{e.debug(`Registering observer ${r} in adapter ${s}`),t.observe(o)}catch(t){e.debug(`Failed to register observer ${r} in adapter ${s}: ${t?.message||t}`),e.error(t)}}return()=>{e.debug("Cleaning up SSE observer "+r);for(const t of this.adapters){const s=t?.constructor?.name??"UnknownAdapter";try{e.debug(`Unregistering observer ${r} from adapter ${s}`),t.unObserve(o)}catch(t){e.debug(`Failed during cleanup of observer ${r} in adapter ${s}: ${t?.message||t}`),e.error(t)}}}}),r=je(15e3).pipe(He(()=>{e.debug("Sending heartbeat")}),Ye(()=>({type:"heartbeat",data:{ts:(new Date).toISOString()}})));return Ue(t,r)}listenForModel(e){const t=Ne.for(gr.name);return new Le(e=>{const r=new class{refresh(...t){return Promise.resolve().then(()=>{e.next({data:t})})}};try{for(const e of this.adapters)e.observe(r)}catch(t){e.error("Failed to observe event: "+(t.message||t))}return()=>{try{for(const e of this.adapters)e.unObserve(r)}catch(e){t.error(e)}}})}};var yr;Oe([I(),Se("design:type",Function),Se("design:paramtypes",[]),Se("design:returntype",Le)],mr.prototype,"listen",null),Oe([I("/:model"),xe(0,E("model")),Se("design:type",Function),Se("design:paramtypes",[String]),Se("design:returntype",Le)],mr.prototype,"listenForModel",null),mr=gr=Oe([T(),xe(1,b(fr)),Se("design:paramtypes",[_t,Array])],mr);let br=yr=class{static forFlavours(e,t="events"){return{module:yr,controllers:[mr],imports:[Ie.register([{path:t.replace(/^\//,""),module:yr}])],providers:[_t,{provide:fr,useValue:e??[]}]}}};var vr;br=yr=Oe([O({})],br);let wr=vr=class{static async forRootAsync(e){const{autoControllers:t,autoServices:r}=e,o=(await hr.bootPersistence(e)).map(e=>e.flavour),s=[hr.forRoot(e)];return t&&o.forEach(e=>{s.push(Kt(e).forRoot(e,{autoServices:r}))}),e.observerOptions?.enableObserverEvents&&s.push(br.forFlavours(e.observerOptions.observerFlavours||o)),{module:vr,imports:s}}};async function Ar(){}var Er;wr=vr=Oe([O({})],wr);const Pr=Ne.for("DecafMigrationModule");let Rr=Er=class{static forRoot(){return{module:Er}}static async migrate(e,t){const r=Pr.for(this.migrate);if(!t||0===t.length)throw new Ee("No adapters provided. Make sure DecafCoreModule is configured and adapters are available.");return r.info("Running migrations with config: "+JSON.stringify(e)),Je.migrateAdapters(t,e||{})}};function Tr(e){const t=N.get(e);if(!t)throw new Ee("Failed to find repository for "+e);return G.forModel(t)}var Or,xr;Rr=Er=Oe([k(),O({providers:[{provide:"MIGRATION_ADAPTERS",useFactory:e=>e,inject:[bt]}],exports:["MIGRATION_ADAPTERS"]})],Rr);let Sr=Or=class extends jt{constructor(e){super(e,Or.name)}async deactivate(e){const{ctx:t}=(await this.logCtx([],"deactivate",!0)).for(this.deactivate),r=G.forModel(Xe),o=await r.read(e,t);return o.active=!1,r.update(o,t)}async reactivate(e){const{ctx:t}=(await this.logCtx([],"reactivate",!0)).for(this.reactivate),r=G.forModel(Xe),o=await r.read(e,t);return o.active=!0,r.update(o,t)}};Oe([l(":id/deactivate"),xe(0,P("id")),Se("design:type",Function),Se("design:paramtypes",[String]),Se("design:returntype",Promise)],Sr.prototype,"deactivate",null),Oe([l(":id/reactivate"),xe(0,P("id")),Se("design:type",Function),Se("design:paramtypes",[String]),Se("design:returntype",Promise)],Sr.prototype,"reactivate",null),Sr=Or=Oe([T("webhook-subscriptions"),Se("design:paramtypes",[_t])],Sr);let $r=xr=class extends jt{constructor(e){super(e,xr.name)}async replay(e){const{ctx:t}=(await this.logCtx([],"replay",!0)).for(this.replay),r=G.forModel(We),o=G.forModel(Qe);try{let s;try{s=await r.read(e,t)}catch(o){const i=await r.select().where(r.attr("id").eq(e)).limit(1).execute(t);if(!i.length)throw o;s=i[0]}let i=[];try{i=await Ve(()=>o.select().where(o.attr("eventId").eq(s.id)).orderBy("createdAt",j.ASC).thenBy("id",j.ASC).paginate(250,t),250,t)}catch{try{i=await o.select().where(o.attr("eventId").eq(s.id)).execute(t)}catch{i=[]}}const n=new Date;for(const e of i)e.status=Ke.PENDING,e.attempts=0,e.nextAttemptAt=n,e.lastAttemptAt=null,e.errorMessage=void 0,e.responseStatus=void 0,e.responseBody=void 0;if(s.status=Ke.PENDING,s.deliveriesSucceeded=0,s.deliveriesFailed=0,s.nextAttemptAt=n,s.updatedAt=n,i.length)try{await o.updateAll(i,t.override({applyUpdateValidation:!1}))}catch{}return r.update(s,t)}catch(e){throw e}}};var _r;Oe([l(":id/replay"),xe(0,P("id")),Se("design:type",Function),Se("design:paramtypes",[String]),Se("design:returntype",Promise)],$r.prototype,"replay",null),$r=xr=Oe([T("webhook-events"),Se("design:paramtypes",[_t])],$r);let Cr=class{static{_r=this}static{this._logger=Ne.for(_r)}static get log(){return this._logger}static async bootPersistence(e){const t=this.log.for(this.bootPersistence);if(!this._persistence){const r=e.conf.map(([e,t,...r])=>r.pop()?[e,t,...r]:[e,t]);this._persistence=new K,await this._persistence.boot(r);const o=this._persistence.client;for(let t=0;t<o.length;t++){const r=Y._cache||(Y._cache={}),s=[o[t].flavour,o[t].alias,"webhook_deliveries","webhook_events","webhook_subscriptions"].filter(e=>!!e);for(const e of s)r[e]=o[t];const n=e.conf[t];let a=n.slice(2,n.length).pop();if(!a||!a.from){const e=Y.transformerFor(o[t].flavour);if(!e)throw new Ee(`No transformer found for flavour ${o[t].flavour}.`);try{a=e.from?e:new e}catch(e){throw new Ee(`Failed to boot transformer for ${o[t].flavour}: ${e}`)}}lr(o[t].flavour)(a),i(o[t].flavour)(Xe),i(o[t].flavour)(We),i(o[t].flavour)(Qe)}if(t.info("persistence layer created successfully!"),e.initialization)try{await e.initialization()}catch(e){throw new Ee("Failed to initialize webhook module: "+e)}}return this._persistence.client}static async forRoot(e){return this.forRootAsync(e)}static async forRootAsync(e){await this.bootPersistence(e);const t=[Vt.create(Xe),Vt.create(We),Vt.create(Qe),Sr,$r];return{module:_r,controllers:t,imports:[Ie.register([{path:(e.webhookApiPath||"webhooks").replace(/^\//,""),module:_r}])],providers:[_t,kt,{provide:At,useFactory:()=>e.handlers?.map(e=>new e)??[]},{provide:ke,useClass:pr}],exports:[_t,kt]}}};Cr=_r=Oe([O({})],Cr);const kr=Cr;async function Ir(){}const Nr="##VERSION##",Fr="##COMMIT##",Dr="##FULL_VERSION##",qr="##PACKAGE##";t.allowReregistration(!0),t.registerLibrary(qr,Nr),t.allowReregistration(!1);export{Pt as AUTH_HANDLER,Rt as AUTH_META_KEY,pt as ApiOperationFromModel,lt as ApiParamsFromModel,nt as ApiProperty,xt as Auth,Ot as AuthInterceptor,dt as BulkApiOperationFromModel,Fr as COMMIT,Zt as CorsError,bt as DECAF_ADAPTER_ID,Et as DECAF_ADAPTER_OPTIONS,Tt as DECAF_CONTEXT_KEY,At as DECAF_HANDLERS,yt as DECAF_MODULE_OPTIONS,wt as DECAF_ROUTE,vt as DECAF_TASK_SERVICE_ID,et as DECORATORS,Ze as DECORATORS_PREFIX,St as DecafAuthHandler,ut as DecafBody,jt as DecafController,hr as DecafCoreModule,tr as DecafExceptionFilter,kt as DecafHandlerExecutor,Rr as DecafMigrationModule,Ut as DecafModelController,wr as DecafModule,ft as DecafParams,gt as DecafQuery,_t as DecafRequestContext,pr as DecafRequestHandlerInterceptor,It as DecafResponseInterceptor,$t as DecafRoleAuthHandler,br as DecafStreamModule,Cr as DecafWebhookModule,kr as DecafWebhooksModule,zt as DtoFor,mr as EventsController,Dr as FULL_VERSION,Vt as FromModelController,mt as HttpVerbToDecorator,ar as NestBootstraper,qr as PACKAGE_NAME,dr as RequestToContextTransformer,nr as SwaggerBuilder,rr as UseDecafFilter,or as UseDecafHeaders,Nr as VERSION,$r as WebhookEventActionsController,Sr as WebhookSubscriptionActionsController,at as createApiPropertyDecorator,it as createPropertyDecorator,st as getEnumType,ot as getEnumValues,Kt as getModuleFor,ct as isOperationBlocked,rt as isUndefined,Tr as repoForModel,lr as requestToContextTransformer,Ar as runMigrations,Ir as runWebhooksMigrations};
|
|
2
|
-
|
|
1
|
+
import { apply, Metadata, Decoration, DecorationKeys } from "@decaf-ts/decoration";
|
|
2
|
+
|
|
3
|
+
import { InjectablesKeys, DefaultInjectablesConfig } from "@decaf-ts/injectable-decorators";
|
|
4
|
+
|
|
5
|
+
import { Delete, Patch, Put, Post, Get, applyDecorators, createParamDecorator as createParamDecorator$1, InternalServerErrorException, Injectable, Scope, Inject, Optional, UseInterceptors, SetMetadata, Query, Module, Controller, Response, Param, NotFoundException, NotAcceptableException, Catch, UseFilters, Logger, Global, Sse } from "@nestjs/common";
|
|
6
|
+
|
|
7
|
+
import { ModelBuilder, Model, ValidationKeys } from "@decaf-ts/decorator-validation";
|
|
8
|
+
|
|
9
|
+
import { isOperationBlocked, PreparedStatementKeys, UUID, Adapter, OrderDirection, ModelService, AuthorizationError, Context, DefaultAdapterFlags, Service as Service$1, Repository as Repository$1, TransactionOperationKeys, PersistenceKeys, ForbiddenError, UnsupportedError, injectableServiceKey, PersistenceService } from "@decaf-ts/core";
|
|
10
|
+
|
|
11
|
+
import { pickBy, negate, isUndefined as isUndefined$1, isArray, isString } from "lodash";
|
|
12
|
+
|
|
13
|
+
import { ApiExcludeEndpoint, ApiParam, ApiBearerAuth, ApiSecurity, ApiQuery, ApiOperation, ApiOkResponse, ApiNoContentResponse, ApiTags, ApiExtraModels, ApiBody, ApiCreatedResponse, getSchemaPath, ApiBadRequestResponse, ApiUnprocessableEntityResponse, ApiNotFoundResponse, DocumentBuilder, SwaggerModule } from "@nestjs/swagger";
|
|
14
|
+
|
|
15
|
+
import { OperationKeys, BulkCrudOperationKeys, InternalError, DBKeys, ValidationError, BaseError } from "@decaf-ts/db-decorators";
|
|
16
|
+
|
|
17
|
+
import { __decorate, __param, __metadata } from "tslib";
|
|
18
|
+
|
|
19
|
+
import { REQUEST, Reflector, APP_INTERCEPTOR, ModuleRef, RouterModule } from "@nestjs/core";
|
|
20
|
+
|
|
21
|
+
import { Logging, toPascalCase, toKebabCase, LoggedEnvironment } from "@decaf-ts/logging";
|
|
22
|
+
|
|
23
|
+
import { RequestContext, AuthHandler, DecafController as DecafController$1, ModelControllerFactory, requestToContextTransformer } from "@decaf-ts/for-http/server";
|
|
24
|
+
|
|
25
|
+
import { tap, Observable, interval, merge } from "rxjs";
|
|
26
|
+
|
|
27
|
+
import { readFileSync } from "fs";
|
|
28
|
+
|
|
29
|
+
import * as path from "path";
|
|
30
|
+
|
|
31
|
+
import YAML from "yaml";
|
|
32
|
+
|
|
33
|
+
import { tap as tap$1, map } from "rxjs/operators";
|
|
34
|
+
|
|
35
|
+
const DECORATORS_PREFIX = "swagger";
|
|
36
|
+
|
|
37
|
+
const DECORATORS = {
|
|
38
|
+
API_OPERATION: `${DECORATORS_PREFIX}/apiOperation`,
|
|
39
|
+
API_RESPONSE: `${DECORATORS_PREFIX}/apiResponse`,
|
|
40
|
+
API_PRODUCES: `${DECORATORS_PREFIX}/apiProduces`,
|
|
41
|
+
API_CONSUMES: `${DECORATORS_PREFIX}/apiConsumes`,
|
|
42
|
+
API_TAGS: `${DECORATORS_PREFIX}/apiUseTags`,
|
|
43
|
+
API_CALLBACKS: `${DECORATORS_PREFIX}/apiCallbacks`,
|
|
44
|
+
API_PARAMETERS: `${DECORATORS_PREFIX}/apiParameters`,
|
|
45
|
+
API_HEADERS: `${DECORATORS_PREFIX}/apiHeaders`,
|
|
46
|
+
API_MODEL_PROPERTIES: `${DECORATORS_PREFIX}/apiModelProperties`,
|
|
47
|
+
API_MODEL_PROPERTIES_ARRAY: `${DECORATORS_PREFIX}/apiModelPropertiesArray`,
|
|
48
|
+
API_SECURITY: `${DECORATORS_PREFIX}/apiSecurity`,
|
|
49
|
+
API_EXCLUDE_ENDPOINT: `${DECORATORS_PREFIX}/apiExcludeEndpoint`,
|
|
50
|
+
API_EXCLUDE_CONTROLLER: `${DECORATORS_PREFIX}/apiExcludeController`,
|
|
51
|
+
API_EXTRA_MODELS: `${DECORATORS_PREFIX}/apiExtraModels`,
|
|
52
|
+
API_EXTENSION: `${DECORATORS_PREFIX}/apiExtension`,
|
|
53
|
+
API_SCHEMA: `${DECORATORS_PREFIX}/apiSchema`,
|
|
54
|
+
API_DEFAULT_GETTER: `${DECORATORS_PREFIX}/apiDefaultGetter`,
|
|
55
|
+
API_LINK: `${DECORATORS_PREFIX}/apiLink`
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const isConstructor = val => val === "constructor";
|
|
59
|
+
|
|
60
|
+
const METADATA_FACTORY_NAME = "_OPENAPI_METADATA_FACTORY";
|
|
61
|
+
|
|
62
|
+
const METHOD_METADATA = "method";
|
|
63
|
+
|
|
64
|
+
function createMethodDecorator(metakey, metadata, {overrideExisting: overrideExisting} = {
|
|
65
|
+
overrideExisting: true
|
|
66
|
+
}) {
|
|
67
|
+
return (target, key, descriptor) => {
|
|
68
|
+
if (typeof metadata === "object") {
|
|
69
|
+
const prevValue = Reflect.getMetadata(metakey, descriptor.value);
|
|
70
|
+
if (prevValue && !overrideExisting) {
|
|
71
|
+
return descriptor;
|
|
72
|
+
}
|
|
73
|
+
Reflect.defineMetadata(metakey, {
|
|
74
|
+
...prevValue,
|
|
75
|
+
...metadata
|
|
76
|
+
}, descriptor.value);
|
|
77
|
+
return descriptor;
|
|
78
|
+
}
|
|
79
|
+
Reflect.defineMetadata(metakey, metadata, descriptor.value);
|
|
80
|
+
return descriptor;
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function createClassDecorator(metakey, metadata = []) {
|
|
85
|
+
return target => {
|
|
86
|
+
const prevValue = Reflect.getMetadata(metakey, target) || [];
|
|
87
|
+
Reflect.defineMetadata(metakey, [ ...prevValue, ...metadata ], target);
|
|
88
|
+
return target;
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function createPropertyDecorator$1(metakey, metadata, overrideExisting = true) {
|
|
93
|
+
return (target, propertyKey) => {
|
|
94
|
+
const properties = Reflect.getMetadata(DECORATORS.API_MODEL_PROPERTIES_ARRAY, target) || [];
|
|
95
|
+
const key = `:${propertyKey}`;
|
|
96
|
+
if (!properties.includes(key)) {
|
|
97
|
+
Reflect.defineMetadata(DECORATORS.API_MODEL_PROPERTIES_ARRAY, [ ...properties, `:${propertyKey}` ], target);
|
|
98
|
+
}
|
|
99
|
+
const existingMetadata = Reflect.getMetadata(metakey, target, propertyKey);
|
|
100
|
+
if (existingMetadata) {
|
|
101
|
+
const newMetadata = pickBy(metadata, negate(isUndefined$1));
|
|
102
|
+
const metadataToSave = overrideExisting ? {
|
|
103
|
+
...existingMetadata,
|
|
104
|
+
...newMetadata
|
|
105
|
+
} : {
|
|
106
|
+
...newMetadata,
|
|
107
|
+
...existingMetadata
|
|
108
|
+
};
|
|
109
|
+
Reflect.defineMetadata(metakey, metadataToSave, target, propertyKey);
|
|
110
|
+
} else {
|
|
111
|
+
const type = target?.constructor?.[METADATA_FACTORY_NAME]?.()[propertyKey]?.type ?? Reflect.getMetadata("design:type", target, propertyKey);
|
|
112
|
+
Reflect.defineMetadata(metakey, {
|
|
113
|
+
type: type,
|
|
114
|
+
...pickBy(metadata, negate(isUndefined$1))
|
|
115
|
+
}, target, propertyKey);
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function createMixedDecorator(metakey, metadata) {
|
|
121
|
+
return (target, key, descriptor) => {
|
|
122
|
+
if (descriptor) {
|
|
123
|
+
let metadatas;
|
|
124
|
+
if (Array.isArray(metadata)) {
|
|
125
|
+
const previousMetadata = Reflect.getMetadata(metakey, descriptor.value) || [];
|
|
126
|
+
metadatas = [ ...previousMetadata, ...metadata ];
|
|
127
|
+
} else {
|
|
128
|
+
const previousMetadata = Reflect.getMetadata(metakey, descriptor.value) || {};
|
|
129
|
+
metadatas = {
|
|
130
|
+
...previousMetadata,
|
|
131
|
+
...metadata
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
Reflect.defineMetadata(metakey, metadatas, descriptor.value);
|
|
135
|
+
return descriptor;
|
|
136
|
+
}
|
|
137
|
+
let metadatas;
|
|
138
|
+
if (Array.isArray(metadata)) {
|
|
139
|
+
const previousMetadata = Reflect.getMetadata(metakey, target) || [];
|
|
140
|
+
metadatas = [ ...previousMetadata, ...metadata ];
|
|
141
|
+
} else {
|
|
142
|
+
const previousMetadata = Reflect.getMetadata(metakey, target) || {};
|
|
143
|
+
metadatas = Object.assign(Object.assign({}, previousMetadata), metadata);
|
|
144
|
+
}
|
|
145
|
+
Reflect.defineMetadata(metakey, metadatas, target);
|
|
146
|
+
return target;
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function createParamDecorator(metadata, initial) {
|
|
151
|
+
return (target, key, descriptor) => {
|
|
152
|
+
const paramOptions = {
|
|
153
|
+
...initial,
|
|
154
|
+
...pickBy(metadata, negate(isUndefined$1))
|
|
155
|
+
};
|
|
156
|
+
if (descriptor) {
|
|
157
|
+
const parameters = Reflect.getMetadata(DECORATORS.API_PARAMETERS, descriptor.value) || [];
|
|
158
|
+
Reflect.defineMetadata(DECORATORS.API_PARAMETERS, [ ...parameters, paramOptions ], descriptor.value);
|
|
159
|
+
return descriptor;
|
|
160
|
+
}
|
|
161
|
+
if (typeof target === "object") {
|
|
162
|
+
return target;
|
|
163
|
+
}
|
|
164
|
+
const propertyKeys = Object.getOwnPropertyNames(target.prototype);
|
|
165
|
+
for (const propertyKey of propertyKeys) {
|
|
166
|
+
if (isConstructor(propertyKey)) {
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
const methodDescriptor = Object.getOwnPropertyDescriptor(target.prototype, propertyKey);
|
|
170
|
+
if (!methodDescriptor) {
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
const isApiMethod = Reflect.hasMetadata(METHOD_METADATA, methodDescriptor.value);
|
|
174
|
+
if (!isApiMethod) {
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
const parameters = Reflect.getMetadata(DECORATORS.API_PARAMETERS, methodDescriptor.value) || [];
|
|
178
|
+
Reflect.defineMetadata(DECORATORS.API_PARAMETERS, [ ...parameters, paramOptions ], methodDescriptor.value);
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function getTypeIsArrayTuple(input, isArrayFlag) {
|
|
184
|
+
if (!input) {
|
|
185
|
+
return [ input, isArrayFlag ];
|
|
186
|
+
}
|
|
187
|
+
if (isArrayFlag) {
|
|
188
|
+
return [ input, isArrayFlag ];
|
|
189
|
+
}
|
|
190
|
+
const isInputArray = isArray(input);
|
|
191
|
+
const type = isInputArray ? input[0] : input;
|
|
192
|
+
return [ type, isInputArray ];
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const isUndefined = obj => typeof obj === "undefined";
|
|
196
|
+
|
|
197
|
+
function getEnumValues(enumType) {
|
|
198
|
+
if (typeof enumType === "function") {
|
|
199
|
+
return getEnumValues(enumType());
|
|
200
|
+
}
|
|
201
|
+
if (Array.isArray(enumType)) {
|
|
202
|
+
return enumType;
|
|
203
|
+
}
|
|
204
|
+
if (typeof enumType !== "object") {
|
|
205
|
+
return [];
|
|
206
|
+
}
|
|
207
|
+
const numericValues = Object.values(enumType).filter(value => typeof value === "number").map(value => value.toString());
|
|
208
|
+
return Object.keys(enumType).filter(key => !numericValues.includes(key)).map(key => enumType[key]);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function getEnumType(values) {
|
|
212
|
+
const hasString = values.filter(isString).length > 0;
|
|
213
|
+
return hasString ? "string" : "number";
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function createPropertyDecorator(metakey, metadata, overrideExisting = true) {
|
|
217
|
+
return (target, propertyKey) => {
|
|
218
|
+
const properties = Reflect.getMetadata(DECORATORS.API_MODEL_PROPERTIES_ARRAY, target) || [];
|
|
219
|
+
const key = `:${propertyKey}`;
|
|
220
|
+
if (!properties.includes(key)) {
|
|
221
|
+
Reflect.defineMetadata(DECORATORS.API_MODEL_PROPERTIES_ARRAY, [ ...properties, `:${propertyKey}` ], target);
|
|
222
|
+
}
|
|
223
|
+
const existingMetadata = Reflect.getMetadata(metakey, target, propertyKey);
|
|
224
|
+
if (existingMetadata) {
|
|
225
|
+
const newMetadata = pickBy(metadata, negate(isUndefined));
|
|
226
|
+
const metadataToSave = overrideExisting ? {
|
|
227
|
+
...existingMetadata,
|
|
228
|
+
...newMetadata
|
|
229
|
+
} : {
|
|
230
|
+
...newMetadata,
|
|
231
|
+
...existingMetadata
|
|
232
|
+
};
|
|
233
|
+
Reflect.defineMetadata(metakey, metadataToSave, target, propertyKey);
|
|
234
|
+
} else {
|
|
235
|
+
const type = target?.constructor?.[METADATA_FACTORY_NAME]?.()[propertyKey]?.type ?? Reflect.getMetadata("design:type", target, propertyKey);
|
|
236
|
+
Reflect.defineMetadata(metakey, {
|
|
237
|
+
type: type,
|
|
238
|
+
required: false,
|
|
239
|
+
...pickBy(metadata, negate(isUndefined))
|
|
240
|
+
}, target, propertyKey);
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const isEnumArray = opts => opts.isArray && "enum" in opts && opts.enum !== undefined;
|
|
246
|
+
|
|
247
|
+
function ApiProperty(options = {}) {
|
|
248
|
+
return createApiPropertyDecorator(options);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function createApiPropertyDecorator(options = {}, overrideExisting = true) {
|
|
252
|
+
const [type, isArray] = getTypeIsArrayTuple(options.type, options.isArray);
|
|
253
|
+
options = {
|
|
254
|
+
...options,
|
|
255
|
+
type: type,
|
|
256
|
+
isArray: isArray
|
|
257
|
+
};
|
|
258
|
+
if (isEnumArray(options)) {
|
|
259
|
+
options.type = "array";
|
|
260
|
+
const enumValues = getEnumValues(options.enum);
|
|
261
|
+
options.items = {
|
|
262
|
+
type: getEnumType(enumValues),
|
|
263
|
+
enum: enumValues
|
|
264
|
+
};
|
|
265
|
+
delete options.enum;
|
|
266
|
+
} else if ("enum" in options && options.enum !== undefined) {
|
|
267
|
+
const enumValues = getEnumValues(options.enum);
|
|
268
|
+
options.enum = enumValues;
|
|
269
|
+
options.type = getEnumType(enumValues);
|
|
270
|
+
}
|
|
271
|
+
if (Array.isArray(options.type)) {
|
|
272
|
+
options.type = "array";
|
|
273
|
+
options.items = {
|
|
274
|
+
type: "array",
|
|
275
|
+
items: {
|
|
276
|
+
type: options.type[0]
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
return createPropertyDecorator(DECORATORS.API_MODEL_PROPERTIES, options, overrideExisting);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function ApiOperationFromModel(ModelConstructor, verb, path) {
|
|
284
|
+
const httpToCrud = {
|
|
285
|
+
GET: [ OperationKeys.READ, Get ],
|
|
286
|
+
POST: [ OperationKeys.CREATE, Post ],
|
|
287
|
+
PUT: [ OperationKeys.UPDATE, Put ],
|
|
288
|
+
PATCH: [ OperationKeys.UPDATE, Patch ],
|
|
289
|
+
DELETE: [ OperationKeys.DELETE, Delete ]
|
|
290
|
+
};
|
|
291
|
+
const [crudOp, HttpMethodDecorator] = httpToCrud[verb];
|
|
292
|
+
const target = resolveBlockTarget(verb, path);
|
|
293
|
+
return target ? isOperationBlocked(ModelConstructor, target.kind, target.value) ? apply(ApiExcludeEndpoint()) : apply(HttpMethodDecorator(path)) : isOperationBlocked(ModelConstructor, crudOp) ? apply(ApiExcludeEndpoint()) : apply(HttpMethodDecorator(path));
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
function BulkApiOperationFromModel(ModelConstructor, verb, path) {
|
|
297
|
+
const httpToCrud = {
|
|
298
|
+
GET: [ BulkCrudOperationKeys.READ_ALL, Get ],
|
|
299
|
+
POST: [ BulkCrudOperationKeys.CREATE_ALL, Post ],
|
|
300
|
+
PUT: [ BulkCrudOperationKeys.UPDATE_ALL, Put ],
|
|
301
|
+
PATCH: [ BulkCrudOperationKeys.UPDATE_ALL, Patch ],
|
|
302
|
+
DELETE: [ BulkCrudOperationKeys.DELETE_ALL, Delete ]
|
|
303
|
+
};
|
|
304
|
+
const [crudOp, HttpMethodDecorator] = httpToCrud[verb];
|
|
305
|
+
const target = path ? resolveBlockTarget(verb, path) : undefined;
|
|
306
|
+
return target ? isOperationBlocked(ModelConstructor, target.kind, target.value) ? apply(ApiExcludeEndpoint()) : apply(HttpMethodDecorator(path)) : isOperationBlocked(ModelConstructor, "bulk", crudOp) ? apply(ApiExcludeEndpoint()) : apply(HttpMethodDecorator(path));
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
function resolveBlockTarget(verb, path) {
|
|
310
|
+
if (!path) return undefined;
|
|
311
|
+
const normalized = path.replace(/^\/+|\/+$/g, "");
|
|
312
|
+
const statementTargets = {
|
|
313
|
+
"listBy/:key": PreparedStatementKeys.LIST_BY,
|
|
314
|
+
"paginateBy/:key/:page": PreparedStatementKeys.PAGE_BY,
|
|
315
|
+
"find/:value": PreparedStatementKeys.FIND,
|
|
316
|
+
"page/:value": PreparedStatementKeys.PAGE,
|
|
317
|
+
"findOneBy/:key/:value": PreparedStatementKeys.FIND_ONE_BY,
|
|
318
|
+
"findBy/:key/:value": PreparedStatementKeys.FIND_BY,
|
|
319
|
+
"statement/:method/*args": "statement",
|
|
320
|
+
"countOf/:field": PreparedStatementKeys.COUNT_OF,
|
|
321
|
+
"maxOf/:field": PreparedStatementKeys.MAX_OF,
|
|
322
|
+
"minOf/:field": PreparedStatementKeys.MIN_OF,
|
|
323
|
+
"avgOf/:field": PreparedStatementKeys.AVG_OF,
|
|
324
|
+
"sumOf/:field": PreparedStatementKeys.SUM_OF,
|
|
325
|
+
"distinctOf/:field": PreparedStatementKeys.DISTINCT_OF,
|
|
326
|
+
"groupOf/:field": PreparedStatementKeys.GROUP_OF
|
|
327
|
+
};
|
|
328
|
+
if (normalized.startsWith("query/")) {
|
|
329
|
+
return {
|
|
330
|
+
kind: "query",
|
|
331
|
+
value: normalized.replace(/^query\//, "")
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
const statementValue = statementTargets[normalized];
|
|
335
|
+
if (statementValue) {
|
|
336
|
+
return {
|
|
337
|
+
kind: "statement",
|
|
338
|
+
value: statementValue
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
if (verb === "GET" && normalized === "") {
|
|
342
|
+
return {
|
|
343
|
+
kind: "crud",
|
|
344
|
+
value: OperationKeys.READ
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
return undefined;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
function ApiParamsFromModel(props = []) {
|
|
351
|
+
const decorators = props.map(p => ApiParam({
|
|
352
|
+
name: p.name,
|
|
353
|
+
description: p.description ?? `Path parameter: ${p.name}`,
|
|
354
|
+
required: p.required ?? true,
|
|
355
|
+
type: p.type ?? String
|
|
356
|
+
}));
|
|
357
|
+
return applyDecorators(...decorators);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
const DecafBody = createParamDecorator$1((data, ctx) => {
|
|
361
|
+
const request = ctx.switchToHttp().getRequest();
|
|
362
|
+
const body = request.body;
|
|
363
|
+
const controller = ctx.getClass();
|
|
364
|
+
const ModelConstr = controller.class;
|
|
365
|
+
if (!ModelConstr) {
|
|
366
|
+
throw new InternalServerErrorException(`ModelConstructor not found on controller ${controller.name}. Ensure the controller was created via FromModelController.`);
|
|
367
|
+
}
|
|
368
|
+
if (!body) return body;
|
|
369
|
+
if (Array.isArray(body)) {
|
|
370
|
+
return body.map(item => new ModelConstr(item));
|
|
371
|
+
}
|
|
372
|
+
return new ModelConstr(body);
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
const OrderedParams = createParamDecorator$1((order, ctx) => {
|
|
376
|
+
const req = ctx.switchToHttp().getRequest();
|
|
377
|
+
const original = req?.params ?? {};
|
|
378
|
+
const orderList = order ?? Object.keys(original);
|
|
379
|
+
const ordered = orderList.map(k => original[k]);
|
|
380
|
+
return {
|
|
381
|
+
raw: original,
|
|
382
|
+
valuesInOrder: ordered,
|
|
383
|
+
keysInOrder: orderList
|
|
384
|
+
};
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
function DecafParams(props = []) {
|
|
388
|
+
const order = props.map(p => p.name);
|
|
389
|
+
return OrderedParams(order);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
const DecafQuery = createParamDecorator$1((_, ctx) => {
|
|
393
|
+
const req = ctx.switchToHttp().getRequest();
|
|
394
|
+
const query = req.query ?? {};
|
|
395
|
+
const parsed = {
|
|
396
|
+
...query
|
|
397
|
+
};
|
|
398
|
+
if (parsed.limit !== undefined) {
|
|
399
|
+
const n = Number(parsed.limit);
|
|
400
|
+
if (!Number.isNaN(n)) parsed.limit = n;
|
|
401
|
+
}
|
|
402
|
+
if (parsed.offset !== undefined) {
|
|
403
|
+
const n = Number(parsed.offset);
|
|
404
|
+
if (!Number.isNaN(n)) parsed.offset = n;
|
|
405
|
+
}
|
|
406
|
+
if (parsed.bookmark !== undefined) {
|
|
407
|
+
const n = Number(parsed.bookmark);
|
|
408
|
+
parsed.bookmark = Number.isNaN(n) ? parsed.bookmark : n;
|
|
409
|
+
}
|
|
410
|
+
return parsed;
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
const DECAF_MODULE_OPTIONS = "DecafModuleOptions";
|
|
414
|
+
|
|
415
|
+
const DECAF_ADAPTER_ID = "DecafAdapter";
|
|
416
|
+
|
|
417
|
+
const DECAF_TASK_SERVICE_ID = "DecafTaskService";
|
|
418
|
+
|
|
419
|
+
const DECAF_ROUTE = "DecafRoute";
|
|
420
|
+
|
|
421
|
+
const DECAF_HANDLERS = Symbol("DecafHandlers");
|
|
422
|
+
|
|
423
|
+
const DECAF_EXPOSE = "DecafExpose";
|
|
424
|
+
|
|
425
|
+
const DECAF_CONTROLLER_CONFIG = "DecafControllerConfig";
|
|
426
|
+
|
|
427
|
+
const DECAF_CONTEXT_KEY = Symbol("decaf:context");
|
|
428
|
+
|
|
429
|
+
function expose(...flavours) {
|
|
430
|
+
return function expose(target) {
|
|
431
|
+
Metadata.set(target, DECAF_EXPOSE, flavours.length ? flavours : true);
|
|
432
|
+
return target;
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
function controllerConfig(config) {
|
|
437
|
+
return function controllerConfigDecorator(target) {
|
|
438
|
+
Metadata.set(target, DECAF_CONTROLLER_CONFIG, config);
|
|
439
|
+
return target;
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
const AUTH_HANDLER = Symbol("AUTH_HANDLER");
|
|
444
|
+
|
|
445
|
+
const AUTH_META_KEY = "auth:meta";
|
|
446
|
+
|
|
447
|
+
const IS_PUBLIC_KEY = "isPublic";
|
|
448
|
+
|
|
449
|
+
const REQUIRED_ROLES_KEY = "requiredRoles";
|
|
450
|
+
|
|
451
|
+
const SKIP_MODEL_ROLES_KEY = "skipModelRoles";
|
|
452
|
+
|
|
453
|
+
let DecafRequestContext = class DecafRequestContext extends RequestContext {
|
|
454
|
+
constructor(req) {
|
|
455
|
+
super({
|
|
456
|
+
headersOf: request => request?.headers || undefined
|
|
457
|
+
}, req);
|
|
458
|
+
this.req = req;
|
|
459
|
+
this.uuid = UUID.instance.generate();
|
|
460
|
+
this.request = req;
|
|
461
|
+
}
|
|
462
|
+
put(record) {
|
|
463
|
+
let overrides;
|
|
464
|
+
try {
|
|
465
|
+
overrides = this.get("overrides");
|
|
466
|
+
} catch (e) {
|
|
467
|
+
overrides = {};
|
|
468
|
+
}
|
|
469
|
+
this.accumulate({
|
|
470
|
+
overrides: Object.assign(overrides, record)
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
};
|
|
474
|
+
|
|
475
|
+
DecafRequestContext = __decorate([ Injectable({
|
|
476
|
+
scope: Scope.REQUEST
|
|
477
|
+
}), __param(0, Inject(REQUEST)), __metadata("design:paramtypes", [ Object ]) ], DecafRequestContext);
|
|
478
|
+
|
|
479
|
+
let AuthInterceptor = class AuthInterceptor {
|
|
480
|
+
constructor(reflector, requestContext, authHandler) {
|
|
481
|
+
this.reflector = reflector;
|
|
482
|
+
this.requestContext = requestContext;
|
|
483
|
+
this.authHandler = authHandler;
|
|
484
|
+
}
|
|
485
|
+
async intercept(ctx, next) {
|
|
486
|
+
const log = Logging.for(this).for(this.intercept);
|
|
487
|
+
const isPublic = this.reflector.getAllAndOverride(IS_PUBLIC_KEY, [ ctx.getHandler(), ctx.getClass() ]);
|
|
488
|
+
const modelName = this.reflector.get(AUTH_META_KEY, ctx.getHandler()) ?? this.reflector.get(AUTH_META_KEY, ctx.getClass());
|
|
489
|
+
const requiredRoles = this.reflector.getAllAndOverride(REQUIRED_ROLES_KEY, [ ctx.getHandler(), ctx.getClass() ]);
|
|
490
|
+
const skipModelRoles = this.reflector.getAllAndOverride(SKIP_MODEL_ROLES_KEY, [ ctx.getHandler(), ctx.getClass() ]);
|
|
491
|
+
const effectiveModel = skipModelRoles ? undefined : modelName;
|
|
492
|
+
log.verbose(`Intercepted request${modelName ? ` for ${modelName}` : ""}`);
|
|
493
|
+
if (isPublic) {
|
|
494
|
+
log.debug(`Public route — skipping auth`);
|
|
495
|
+
} else if (this.authHandler) {
|
|
496
|
+
await this.authHandler.authorize(ctx, effectiveModel, requiredRoles, this.requestContext);
|
|
497
|
+
} else {
|
|
498
|
+
log.debug(`No auth handler registered`);
|
|
499
|
+
}
|
|
500
|
+
await this.applyTransformers();
|
|
501
|
+
const user = this.requestContext.getOrUndefined("user");
|
|
502
|
+
const organization = this.requestContext.getOrUndefined("organization");
|
|
503
|
+
if (user || organization) {
|
|
504
|
+
const currentLog = this.requestContext.get("logger");
|
|
505
|
+
const childLog = currentLog.for({
|
|
506
|
+
user: user,
|
|
507
|
+
organization: organization
|
|
508
|
+
});
|
|
509
|
+
this.requestContext.accumulate({
|
|
510
|
+
logger: childLog
|
|
511
|
+
});
|
|
512
|
+
}
|
|
513
|
+
return next.handle();
|
|
514
|
+
}
|
|
515
|
+
async applyTransformers() {
|
|
516
|
+
const flavours = Adapter.flavoursToTransform();
|
|
517
|
+
if (!flavours) return;
|
|
518
|
+
for (const flavour of flavours) {
|
|
519
|
+
const transformer = Adapter.transformerFor(flavour);
|
|
520
|
+
if (!transformer) continue;
|
|
521
|
+
const from = await transformer.from(this.requestContext);
|
|
522
|
+
if (from) this.requestContext.accumulate(from);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
};
|
|
526
|
+
|
|
527
|
+
AuthInterceptor = __decorate([ Injectable({
|
|
528
|
+
scope: Scope.REQUEST
|
|
529
|
+
}), __param(2, Optional()), __param(2, Inject(AUTH_HANDLER)), __metadata("design:paramtypes", [ Reflector, DecafRequestContext, Object ]) ], AuthInterceptor);
|
|
530
|
+
|
|
531
|
+
function Auth(model) {
|
|
532
|
+
const resource = model ? typeof model === "string" ? model : model.name : undefined;
|
|
533
|
+
const decs = [ ApiBearerAuth(), UseInterceptors(AuthInterceptor) ];
|
|
534
|
+
if (resource) decs.push(SetMetadata(AUTH_META_KEY, resource));
|
|
535
|
+
return applyDecorators(...decs);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
function Public() {
|
|
539
|
+
return applyDecorators(SetMetadata(IS_PUBLIC_KEY, true));
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
function RequireRoles(...roles) {
|
|
543
|
+
return applyDecorators(ApiSecurity("bearer"), SetMetadata(REQUIRED_ROLES_KEY, roles), UseInterceptors(AuthInterceptor));
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
function HttpVerbToDecorator(verb) {
|
|
547
|
+
const httpToCrud = {
|
|
548
|
+
GET: Get,
|
|
549
|
+
POST: Post,
|
|
550
|
+
PUT: Put,
|
|
551
|
+
PATCH: Patch,
|
|
552
|
+
DELETE: Delete
|
|
553
|
+
};
|
|
554
|
+
const decorator = httpToCrud[verb];
|
|
555
|
+
if (!decorator) {
|
|
556
|
+
throw new Error(`Unsupported HTTP verb "${verb}". No NestJS decorator mapping was found.`);
|
|
557
|
+
}
|
|
558
|
+
return decorator;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
const extractPathParams = routePath => routePath.split("/").filter(p => p.startsWith(":")).map(p => p.slice(1));
|
|
562
|
+
|
|
563
|
+
const apiParamSpec = name => ({
|
|
564
|
+
name: name,
|
|
565
|
+
description: `${name} parameter for the query`,
|
|
566
|
+
required: true,
|
|
567
|
+
type: String
|
|
568
|
+
});
|
|
569
|
+
|
|
570
|
+
function getApiDecorators(methodName, routePath, httpVerb, includeQueryParams = false) {
|
|
571
|
+
const NestHttpRouteDec = HttpVerbToDecorator(httpVerb);
|
|
572
|
+
const apiPathParams = extractPathParams(routePath).map(apiParamSpec);
|
|
573
|
+
const swaggerQueryParams = [];
|
|
574
|
+
if (httpVerb === "GET" && includeQueryParams) {
|
|
575
|
+
swaggerQueryParams.push(ApiQuery({
|
|
576
|
+
name: "direction",
|
|
577
|
+
required: false,
|
|
578
|
+
enum: OrderDirection,
|
|
579
|
+
description: "the sort order when applicable"
|
|
580
|
+
}), ApiQuery({
|
|
581
|
+
name: "limit",
|
|
582
|
+
required: false,
|
|
583
|
+
description: "limit or page size when applicable"
|
|
584
|
+
}), ApiQuery({
|
|
585
|
+
name: "offset",
|
|
586
|
+
required: false,
|
|
587
|
+
description: "offset or bookmark when applicable"
|
|
588
|
+
}));
|
|
589
|
+
}
|
|
590
|
+
return {
|
|
591
|
+
method: [ NestHttpRouteDec(routePath), ...apiPathParams.map(ApiParam), ...swaggerQueryParams, ApiOperation({
|
|
592
|
+
summary: `Retrieve records using according to "${methodName}".`
|
|
593
|
+
}), ApiOkResponse({
|
|
594
|
+
description: `Result successfully retrieved.`
|
|
595
|
+
}), ApiNoContentResponse({
|
|
596
|
+
description: `No content returned by the method.`
|
|
597
|
+
}) ],
|
|
598
|
+
params: [ DecafParams(apiPathParams), Query() ]
|
|
599
|
+
};
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
function applyApiDecorators(target, methodName, descriptor, decorators) {
|
|
603
|
+
const proto = target?.prototype ?? target;
|
|
604
|
+
decorators.method.forEach(d => d(proto, methodName, descriptor));
|
|
605
|
+
decorators.params?.forEach((d, index) => d(proto, methodName, index));
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
function resolvePersistenceMethod(persistence, methodName, ...args) {
|
|
609
|
+
if (persistence instanceof ModelService) {
|
|
610
|
+
return typeof persistence[methodName] === "function" ? persistence[methodName](...args) : persistence.statement(methodName, ...args);
|
|
611
|
+
}
|
|
612
|
+
if (typeof persistence[methodName] === "function") return persistence[methodName](...args);
|
|
613
|
+
throw new Error(`Persistence method "${methodName}" not found on ${persistence?.constructor?.name}`);
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
function createRouteHandler(methodName) {
|
|
617
|
+
return async function(pathParams, queryParams) {
|
|
618
|
+
const log = this.log.for(methodName);
|
|
619
|
+
try {
|
|
620
|
+
log.debug(`Invoking persistence method "${methodName}" given parameters: ${JSON.stringify(pathParams.valuesInOrder)}`);
|
|
621
|
+
const {direction: direction, limit: limit, offset: offset} = queryParams;
|
|
622
|
+
return await resolvePersistenceMethod(this.persistence(), methodName, ...pathParams.valuesInOrder, direction, limit, offset);
|
|
623
|
+
} catch (e) {
|
|
624
|
+
log.error(`Custom query "${methodName}" failed`, e);
|
|
625
|
+
throw e;
|
|
626
|
+
}
|
|
627
|
+
};
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
function defineRouteMethod(ControllerClass, methodName, handler) {
|
|
631
|
+
Object.defineProperty(ControllerClass.prototype || ControllerClass, methodName, {
|
|
632
|
+
value: handler,
|
|
633
|
+
writable: false
|
|
634
|
+
});
|
|
635
|
+
return Object.getOwnPropertyDescriptor(ControllerClass.prototype || ControllerClass, methodName);
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
class DecafAuthHandler extends AuthHandler {
|
|
639
|
+
parseRequest(req) {
|
|
640
|
+
const userRole = req.headers.authorization?.split(" ")[1];
|
|
641
|
+
return userRole;
|
|
642
|
+
}
|
|
643
|
+
extractFromAuth(ctx) {
|
|
644
|
+
const req = ctx.switchToHttp().getRequest();
|
|
645
|
+
const userRole = this.parseRequest(req);
|
|
646
|
+
if (!userRole) throw new AuthorizationError("Unauthenticated");
|
|
647
|
+
return {
|
|
648
|
+
user: userRole,
|
|
649
|
+
roles: [ userRole ]
|
|
650
|
+
};
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
class DecafRoleAuthHandler extends DecafAuthHandler {}
|
|
655
|
+
|
|
656
|
+
Adapter.transformerFor = function toContextFlags(adapter) {
|
|
657
|
+
const alias = typeof adapter === "string" ? adapter : adapter.alias;
|
|
658
|
+
return Metadata["innerGet"](Symbol.for("transformers"), alias);
|
|
659
|
+
}.bind(Adapter);
|
|
660
|
+
|
|
661
|
+
Adapter.flavoursToTransform = function requestTransformers() {
|
|
662
|
+
const meta = Metadata["innerGet"](Symbol.for("transformers"));
|
|
663
|
+
if (!meta) return undefined;
|
|
664
|
+
return Object.keys(meta);
|
|
665
|
+
}.bind(Adapter);
|
|
666
|
+
|
|
667
|
+
Context.prototype.toResponse = function toResponse(res) {
|
|
668
|
+
const pending = this.pending();
|
|
669
|
+
if (pending) res.header("x-pending-task", JSON.stringify(pending));
|
|
670
|
+
return res;
|
|
671
|
+
};
|
|
672
|
+
|
|
673
|
+
const prototype = ModelBuilder.prototype;
|
|
674
|
+
|
|
675
|
+
if (!prototype.decorateClass) {
|
|
676
|
+
prototype.decorateClass = function(decorator) {
|
|
677
|
+
if (!this._classDecorators) {
|
|
678
|
+
this._classDecorators = [];
|
|
679
|
+
}
|
|
680
|
+
this._classDecorators.push(decorator);
|
|
681
|
+
return this;
|
|
682
|
+
};
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
prototype.Auth = function(model) {
|
|
686
|
+
return this.decorateClass(Auth(model));
|
|
687
|
+
};
|
|
688
|
+
|
|
689
|
+
if (!prototype.__hasClassDecoratorSupport) {
|
|
690
|
+
const originalBuild = prototype.build;
|
|
691
|
+
prototype.build = function() {
|
|
692
|
+
let result = originalBuild.call(this);
|
|
693
|
+
const decorators = this._classDecorators;
|
|
694
|
+
if (decorators?.length) {
|
|
695
|
+
for (const decorator of decorators) {
|
|
696
|
+
const decorated = decorator(result);
|
|
697
|
+
if (decorated) {
|
|
698
|
+
result = decorated;
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
return result;
|
|
703
|
+
};
|
|
704
|
+
prototype.__hasClassDecoratorSupport = true;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
var DecafRequestHandlerInterceptor_1;
|
|
708
|
+
|
|
709
|
+
let DecafRequestHandlerInterceptor = DecafRequestHandlerInterceptor_1 = class DecafRequestHandlerInterceptor {
|
|
710
|
+
constructor(requestContext, executor) {
|
|
711
|
+
this.requestContext = requestContext;
|
|
712
|
+
this.executor = executor;
|
|
713
|
+
}
|
|
714
|
+
async contextualize(req) {
|
|
715
|
+
const headers = req.headers;
|
|
716
|
+
const flags = {
|
|
717
|
+
headers: headers,
|
|
718
|
+
overrides: {}
|
|
719
|
+
};
|
|
720
|
+
const ip = extractIp(req);
|
|
721
|
+
const logger = Logging.get().for({
|
|
722
|
+
ip: ip
|
|
723
|
+
});
|
|
724
|
+
this.requestContext.accumulate(Object.assign({}, DefaultAdapterFlags, {
|
|
725
|
+
logger: logger,
|
|
726
|
+
timestamp: new Date,
|
|
727
|
+
operation: `${req.method} ${req.url}`
|
|
728
|
+
}, flags));
|
|
729
|
+
}
|
|
730
|
+
async intercept(context, next) {
|
|
731
|
+
const req = context.switchToHttp().getRequest();
|
|
732
|
+
const res = context.switchToHttp().getResponse();
|
|
733
|
+
const log = Logging.for(DecafRequestHandlerInterceptor_1).for(this.intercept);
|
|
734
|
+
log.debug(`CONTEXT ${this.requestContext.uuid} - request: ${req.method} ${req.url}`);
|
|
735
|
+
await this.contextualize(req);
|
|
736
|
+
log.debug(`CONTEXT ${this.requestContext.uuid} contextualized - request: ${req.method} ${req.url}`);
|
|
737
|
+
await this.executor.exec(req, res);
|
|
738
|
+
log.debug(`CONTEXT ${this.requestContext.uuid} executors finished - request: ${req.method} ${req.url}`);
|
|
739
|
+
return next.handle();
|
|
740
|
+
}
|
|
741
|
+
};
|
|
742
|
+
|
|
743
|
+
DecafRequestHandlerInterceptor = DecafRequestHandlerInterceptor_1 = __decorate([ Injectable({
|
|
744
|
+
scope: Scope.REQUEST
|
|
745
|
+
}), __metadata("design:paramtypes", [ DecafRequestContext, DecafHandlerExecutor ]) ], DecafRequestHandlerInterceptor);
|
|
746
|
+
|
|
747
|
+
function extractIp(req) {
|
|
748
|
+
const headers = req.headers;
|
|
749
|
+
function parseIpHeader(value) {
|
|
750
|
+
if (!value) return undefined;
|
|
751
|
+
const candidate = Array.isArray(value) ? value[0] : value;
|
|
752
|
+
return candidate.split(",").map(segment => segment.trim()).filter(Boolean)[0];
|
|
753
|
+
}
|
|
754
|
+
return parseIpHeader(headers?.["x-forwarded-for"]) ?? parseIpHeader(headers?.["x-real-ip"]) ?? parseIpHeader(headers?.["X-Forwarded-For"]) ?? parseIpHeader(headers?.["X-Real-IP"]) ?? req.ip;
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
var DecafAuthModule_1;
|
|
758
|
+
|
|
759
|
+
let DecafAuthModule = DecafAuthModule_1 = class DecafAuthModule {
|
|
760
|
+
static forRoot(options = {}) {
|
|
761
|
+
const providers = [ AuthInterceptor, DecafRequestHandlerInterceptor, {
|
|
762
|
+
provide: APP_INTERCEPTOR,
|
|
763
|
+
useClass: DecafRequestHandlerInterceptor
|
|
764
|
+
} ];
|
|
765
|
+
if (options.handler) {
|
|
766
|
+
providers.push(options.handler);
|
|
767
|
+
providers.push({
|
|
768
|
+
provide: AUTH_HANDLER,
|
|
769
|
+
useClass: options.handler
|
|
770
|
+
});
|
|
771
|
+
}
|
|
772
|
+
if (options.global) {
|
|
773
|
+
providers.push({
|
|
774
|
+
provide: APP_INTERCEPTOR,
|
|
775
|
+
useExisting: AuthInterceptor
|
|
776
|
+
});
|
|
777
|
+
}
|
|
778
|
+
return {
|
|
779
|
+
module: DecafAuthModule_1,
|
|
780
|
+
global: options.global ?? false,
|
|
781
|
+
providers: providers,
|
|
782
|
+
exports: [ AuthInterceptor, AUTH_HANDLER ]
|
|
783
|
+
};
|
|
784
|
+
}
|
|
785
|
+
};
|
|
786
|
+
|
|
787
|
+
DecafAuthModule = DecafAuthModule_1 = __decorate([ Module({}) ], DecafAuthModule);
|
|
788
|
+
|
|
789
|
+
var DecafHandlerExecutor_1;
|
|
790
|
+
|
|
791
|
+
let DecafHandlerExecutor = DecafHandlerExecutor_1 = class DecafHandlerExecutor {
|
|
792
|
+
constructor(handlers, context) {
|
|
793
|
+
this.handlers = handlers;
|
|
794
|
+
this.context = context;
|
|
795
|
+
}
|
|
796
|
+
async exec(req, res) {
|
|
797
|
+
const log = Logging.for(DecafHandlerExecutor_1.name).for(this.exec);
|
|
798
|
+
log.debug(`CONTEXT ${this.context.uuid} running ${this.handlers.length} handlers for request ${req.method} ${req.url}`);
|
|
799
|
+
for (const handler of this.handlers) {
|
|
800
|
+
await handler.handle(this.context, req, res);
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
};
|
|
804
|
+
|
|
805
|
+
DecafHandlerExecutor = DecafHandlerExecutor_1 = __decorate([ Injectable({
|
|
806
|
+
scope: Scope.REQUEST
|
|
807
|
+
}), __param(0, Inject(DECAF_HANDLERS)), __metadata("design:paramtypes", [ Array, DecafRequestContext ]) ], DecafHandlerExecutor);
|
|
808
|
+
|
|
809
|
+
let DecafResponseInterceptor = class DecafResponseInterceptor {
|
|
810
|
+
constructor(ctx) {
|
|
811
|
+
this.ctx = ctx;
|
|
812
|
+
}
|
|
813
|
+
intercept(context, next) {
|
|
814
|
+
let response = context.switchToHttp().getResponse();
|
|
815
|
+
return next.handle().pipe(tap(data => {
|
|
816
|
+
response = this.ctx.toResponse(response);
|
|
817
|
+
}));
|
|
818
|
+
}
|
|
819
|
+
};
|
|
820
|
+
|
|
821
|
+
DecafResponseInterceptor = __decorate([ Injectable(), __metadata("design:paramtypes", [ DecafRequestContext ]) ], DecafResponseInterceptor);
|
|
822
|
+
|
|
823
|
+
class DecafController extends DecafController$1 {
|
|
824
|
+
constructor(clientContext, _name) {
|
|
825
|
+
super(clientContext);
|
|
826
|
+
this.clientContext = clientContext;
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
class DecafModelController extends DecafController {
|
|
831
|
+
constructor(clientContext, _name) {
|
|
832
|
+
super(clientContext, _name);
|
|
833
|
+
this.clientContext = clientContext;
|
|
834
|
+
}
|
|
835
|
+
persistence(ctx) {
|
|
836
|
+
if (!this._persistence) try {
|
|
837
|
+
this._persistence = Service$1.get(this.class);
|
|
838
|
+
} catch (e) {
|
|
839
|
+
try {
|
|
840
|
+
this._persistence = ModelService.getService(this.class);
|
|
841
|
+
} catch (e) {
|
|
842
|
+
this._persistence = Repository$1.forModel(this.class);
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
const overrides = this.clientContext.toOverrides();
|
|
846
|
+
return ctx ? this._persistence instanceof Repository$1 ? this._persistence.override(overrides) : this._persistence.for(overrides) : this._persistence;
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
const dtoCache = new Map;
|
|
851
|
+
|
|
852
|
+
function DtoFor(op, model, stack = new Set) {
|
|
853
|
+
if (!TransactionOperationKeys.includes(op)) {
|
|
854
|
+
return model;
|
|
855
|
+
}
|
|
856
|
+
const cache = getDtoCache(op);
|
|
857
|
+
const cached = cache.get(model);
|
|
858
|
+
if (cached) return cached;
|
|
859
|
+
const isUpdateOp = [ OperationKeys.UPDATE, BulkCrudOperationKeys.UPDATE_ALL ].includes(op);
|
|
860
|
+
class DynamicDTO {}
|
|
861
|
+
cache.set(model, DynamicDTO);
|
|
862
|
+
Object.defineProperty(DynamicDTO, "name", {
|
|
863
|
+
value: `${toPascalCase(model.name)}${toPascalCase(op)}DTO`
|
|
864
|
+
});
|
|
865
|
+
const pkProp = (() => {
|
|
866
|
+
try {
|
|
867
|
+
return Model.pk(model);
|
|
868
|
+
} catch {
|
|
869
|
+
return undefined;
|
|
870
|
+
}
|
|
871
|
+
})();
|
|
872
|
+
const pkPropsMetadata = pkProp ? Model.pkProps(model) : undefined;
|
|
873
|
+
const pkDesignType = pkProp ? Reflect.getMetadata("design:type", model.prototype, pkProp) : undefined;
|
|
874
|
+
const pkTypeIsNumeric = pkDesignType === Number || pkDesignType === BigInt;
|
|
875
|
+
const pkIsGenerated = !!pkPropsMetadata?.generated || (pkProp ? Model.generatedBySequence(model, pkProp) || isPropertyGeneratedAcrossInheritance(model, pkProp) || pkTypeIsNumeric : false);
|
|
876
|
+
const allProps = Array.from(new Set(Metadata.properties(model) || []));
|
|
877
|
+
const relations = new Set(Model.relations(model) || []);
|
|
878
|
+
const scalarProps = [];
|
|
879
|
+
for (const prop of allProps) {
|
|
880
|
+
if (!prop) continue;
|
|
881
|
+
if (relations.has(prop)) continue;
|
|
882
|
+
if (prop === pkProp && !isUpdateOp && pkIsGenerated) continue;
|
|
883
|
+
if (prop !== pkProp && isPropertyGeneratedAcrossInheritance(model, prop)) continue;
|
|
884
|
+
scalarProps.push(prop);
|
|
885
|
+
}
|
|
886
|
+
for (const prop of scalarProps) {
|
|
887
|
+
const validation = getValidationAcrossInheritance(model, prop);
|
|
888
|
+
const isRequired = !!validation?.[ValidationKeys.REQUIRED];
|
|
889
|
+
const typeHint = getTypeAcrossInheritance(model, prop) ?? Reflect.getMetadata("design:type", model.prototype, prop);
|
|
890
|
+
const apiOptions = {
|
|
891
|
+
required: isRequired
|
|
892
|
+
};
|
|
893
|
+
if (typeHint) apiOptions.type = typeHint;
|
|
894
|
+
ApiProperty(apiOptions)(DynamicDTO.prototype, prop);
|
|
895
|
+
const designType = Reflect.getMetadata("design:type", model.prototype, prop) ?? typeHint;
|
|
896
|
+
if (typeof designType !== "undefined") {
|
|
897
|
+
Reflect.defineMetadata("design:type", designType, DynamicDTO.prototype, prop);
|
|
898
|
+
}
|
|
899
|
+
Object.defineProperty(DynamicDTO.prototype, prop, {
|
|
900
|
+
value: undefined,
|
|
901
|
+
writable: true,
|
|
902
|
+
enumerable: true,
|
|
903
|
+
configurable: true
|
|
904
|
+
});
|
|
905
|
+
}
|
|
906
|
+
for (const relation of relations) {
|
|
907
|
+
const relationMeta = Metadata.relations(model, relation);
|
|
908
|
+
if (!relationMeta) {
|
|
909
|
+
throw new InternalError(`Metadata for relation ${relation} not found`);
|
|
910
|
+
}
|
|
911
|
+
let relationType = relationMeta.class;
|
|
912
|
+
if (typeof relationType === "function" && !relationType.name) {
|
|
913
|
+
relationType = relationType();
|
|
914
|
+
}
|
|
915
|
+
if (!relationType || typeof relationType !== "function") {
|
|
916
|
+
throw new InternalError(`Type for relation ${relation} not found`);
|
|
917
|
+
}
|
|
918
|
+
if (!Model.get(relationType.name)) {
|
|
919
|
+
continue;
|
|
920
|
+
}
|
|
921
|
+
const meta = Metadata.validationFor(model, relation);
|
|
922
|
+
const isArray = !!meta?.[ValidationKeys.LIST];
|
|
923
|
+
const isRequired = !!meta?.[ValidationKeys.REQUIRED];
|
|
924
|
+
const isCircular = stack.has(relationType);
|
|
925
|
+
if (isCircular) {
|
|
926
|
+
const pkTypeName = getPkOpenApiType(relationType);
|
|
927
|
+
addRelationPkRef(DynamicDTO, relation, pkTypeName, isArray, isRequired);
|
|
928
|
+
continue;
|
|
929
|
+
}
|
|
930
|
+
const relationDto = DtoFor(op, relationType, new Set(stack).add(model));
|
|
931
|
+
if (isUpdateOp) {
|
|
932
|
+
addRelationUpdate(DynamicDTO, relation, relationType, relationDto, isArray, isRequired);
|
|
933
|
+
} else {
|
|
934
|
+
addRelation(DynamicDTO, relation, relationDto, isArray, isRequired);
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
return DynamicDTO;
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
function addRelation(DtoClass, relation, relationDto, isArray, isRequired) {
|
|
941
|
+
const apiOptions = {
|
|
942
|
+
type: relationDto,
|
|
943
|
+
required: isRequired,
|
|
944
|
+
isArray: isArray
|
|
945
|
+
};
|
|
946
|
+
ApiProperty(apiOptions)(DtoClass.prototype, relation);
|
|
947
|
+
Reflect.defineMetadata("design:type", isArray ? Array : relationDto, DtoClass.prototype, relation);
|
|
948
|
+
Object.defineProperty(DtoClass.prototype, relation, {
|
|
949
|
+
value: undefined,
|
|
950
|
+
writable: true,
|
|
951
|
+
enumerable: true,
|
|
952
|
+
configurable: true
|
|
953
|
+
});
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
function addRelationPkRef(DtoClass, relation, pkTypeName, isArray, isRequired) {
|
|
957
|
+
const apiOptions = isArray ? {
|
|
958
|
+
type: "array",
|
|
959
|
+
items: {
|
|
960
|
+
type: pkTypeName
|
|
961
|
+
},
|
|
962
|
+
required: isRequired
|
|
963
|
+
} : {
|
|
964
|
+
type: pkTypeName === "integer" ? Number : String,
|
|
965
|
+
required: isRequired
|
|
966
|
+
};
|
|
967
|
+
ApiProperty(apiOptions)(DtoClass.prototype, relation);
|
|
968
|
+
Reflect.defineMetadata("design:type", isArray ? Array : pkTypeName === "integer" ? Number : String, DtoClass.prototype, relation);
|
|
969
|
+
Object.defineProperty(DtoClass.prototype, relation, {
|
|
970
|
+
value: undefined,
|
|
971
|
+
writable: true,
|
|
972
|
+
enumerable: true,
|
|
973
|
+
configurable: true
|
|
974
|
+
});
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
function addRelationUpdate(DtoClass, relation, relationType, relationDto, isArray, isRequired) {
|
|
978
|
+
const extraModels = Reflect.getMetadata(DECORATORS.API_EXTRA_MODELS, DtoClass) || [];
|
|
979
|
+
if (!extraModels.includes(relationDto)) {
|
|
980
|
+
Reflect.defineMetadata(DECORATORS.API_EXTRA_MODELS, [ ...extraModels, relationDto ], DtoClass);
|
|
981
|
+
}
|
|
982
|
+
const dtoRef = `#/components/schemas/${relationDto.name}`;
|
|
983
|
+
const pkTypeName = getPkOpenApiType(relationType);
|
|
984
|
+
const oneOfItems = [ {
|
|
985
|
+
$ref: dtoRef
|
|
986
|
+
}, {
|
|
987
|
+
type: pkTypeName
|
|
988
|
+
} ];
|
|
989
|
+
const apiOptions = isArray ? {
|
|
990
|
+
type: "array",
|
|
991
|
+
required: isRequired,
|
|
992
|
+
oneOf: oneOfItems
|
|
993
|
+
} : {
|
|
994
|
+
type: Object,
|
|
995
|
+
required: isRequired,
|
|
996
|
+
oneOf: oneOfItems
|
|
997
|
+
};
|
|
998
|
+
ApiProperty(apiOptions)(DtoClass.prototype, relation);
|
|
999
|
+
Reflect.defineMetadata("design:type", isArray ? Array : Object, DtoClass.prototype, relation);
|
|
1000
|
+
Object.defineProperty(DtoClass.prototype, relation, {
|
|
1001
|
+
value: undefined,
|
|
1002
|
+
writable: true,
|
|
1003
|
+
enumerable: true,
|
|
1004
|
+
configurable: true
|
|
1005
|
+
});
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
function getPkOpenApiType(relationType) {
|
|
1009
|
+
try {
|
|
1010
|
+
const pkPropsMetadata = Model.pkProps(relationType);
|
|
1011
|
+
const pkType = pkPropsMetadata?.type;
|
|
1012
|
+
if (pkType === Number || pkType === BigInt) return "integer";
|
|
1013
|
+
return "string";
|
|
1014
|
+
} catch {
|
|
1015
|
+
return "string";
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
function isPropertyGeneratedAcrossInheritance(model, prop) {
|
|
1020
|
+
let current = model;
|
|
1021
|
+
while (current && current !== Object && current !== Function) {
|
|
1022
|
+
if (Model.generated(current, prop)) return true;
|
|
1023
|
+
current = Object.getPrototypeOf(current);
|
|
1024
|
+
}
|
|
1025
|
+
return false;
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
function getValidationAcrossInheritance(model, prop) {
|
|
1029
|
+
let current = model;
|
|
1030
|
+
while (current && current !== Object && current !== Function) {
|
|
1031
|
+
const validation = Metadata.validationFor(current, prop);
|
|
1032
|
+
if (validation) return validation;
|
|
1033
|
+
current = Object.getPrototypeOf(current);
|
|
1034
|
+
}
|
|
1035
|
+
return undefined;
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
function getTypeAcrossInheritance(model, prop) {
|
|
1039
|
+
let current = model;
|
|
1040
|
+
while (current && current !== Object && current !== Function) {
|
|
1041
|
+
const type = Metadata.type(current, prop);
|
|
1042
|
+
if (type) return type;
|
|
1043
|
+
current = Object.getPrototypeOf(current);
|
|
1044
|
+
}
|
|
1045
|
+
return undefined;
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
function getDtoCache(op) {
|
|
1049
|
+
if (!dtoCache.has(op)) {
|
|
1050
|
+
dtoCache.set(op, new WeakMap);
|
|
1051
|
+
}
|
|
1052
|
+
return dtoCache.get(op);
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
var DynamicModelController_1;
|
|
1056
|
+
|
|
1057
|
+
class FromModelController {
|
|
1058
|
+
static {
|
|
1059
|
+
this.log = Logging.for(FromModelController.name);
|
|
1060
|
+
}
|
|
1061
|
+
static getPersistence(ModelClazz) {
|
|
1062
|
+
try {
|
|
1063
|
+
return Service$1.get(ModelClazz);
|
|
1064
|
+
} catch (e) {
|
|
1065
|
+
try {
|
|
1066
|
+
return ModelService.getService(ModelClazz);
|
|
1067
|
+
} catch (e2) {
|
|
1068
|
+
return Repository$1.forModel(ModelClazz);
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
static createQueryRoutesFromRepository(persistence, prefix = PersistenceKeys.QUERY) {
|
|
1073
|
+
const repo = persistence instanceof ModelService ? persistence.repo : persistence;
|
|
1074
|
+
const ModelConstr = repo.class;
|
|
1075
|
+
const queryMethods = Metadata.get(repo.constructor, Metadata.key(PersistenceKeys.QUERY)) ?? {};
|
|
1076
|
+
const routeMethods = Metadata.get(persistence.constructor, Metadata.key(DECAF_ROUTE)) ?? {};
|
|
1077
|
+
class QueryController extends DecafModelController {
|
|
1078
|
+
get class() {
|
|
1079
|
+
throw new Error("Method not implemented.");
|
|
1080
|
+
}
|
|
1081
|
+
constructor(clientContext, name) {
|
|
1082
|
+
super(clientContext, name);
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
for (const [methodName, params] of Object.entries(routeMethods)) {
|
|
1086
|
+
const routePath = [ params.path.replace(/^\/+|\/+$/g, "") ].filter(segment => segment && segment.trim()).join("/");
|
|
1087
|
+
const handler = FromModelController.createComplexQueryHandler(methodName);
|
|
1088
|
+
FromModelController.defineMethod(QueryController, methodName, handler);
|
|
1089
|
+
const httpDecorator = HttpVerbToDecorator(params.httpMethod)(routePath || undefined);
|
|
1090
|
+
const decorators = FromModelController.getQueryDecorators(methodName, routePath, params.httpMethod);
|
|
1091
|
+
FromModelController.applyDecorators(QueryController, methodName, [ httpDecorator, ...decorators ]);
|
|
1092
|
+
}
|
|
1093
|
+
for (const [methodName, objValues] of Object.entries(queryMethods)) {
|
|
1094
|
+
const fields = objValues.fields ?? [];
|
|
1095
|
+
const routePath = [ prefix, methodName, ...fields.map(f => `:${f}`) ].filter(segment => segment && segment.trim()).join("/");
|
|
1096
|
+
const handler = FromModelController.createComplexQueryHandler(methodName);
|
|
1097
|
+
FromModelController.defineMethod(QueryController, methodName, handler);
|
|
1098
|
+
const httpDecorator = HttpVerbToDecorator("GET")(routePath || undefined);
|
|
1099
|
+
const decorators = FromModelController.getQueryDecorators(methodName, routePath, "GET", true);
|
|
1100
|
+
FromModelController.applyDecorators(QueryController, methodName, [ httpDecorator, ...decorators ]);
|
|
1101
|
+
}
|
|
1102
|
+
return QueryController;
|
|
1103
|
+
}
|
|
1104
|
+
static create(ModelConstr, moduleConfigOverrides, globalDefaults) {
|
|
1105
|
+
const log = FromModelController.log.for(FromModelController.create);
|
|
1106
|
+
const tableName = Model.tableName(ModelConstr);
|
|
1107
|
+
const routePath = toKebabCase(tableName);
|
|
1108
|
+
const modelClazzName = ModelConstr.name;
|
|
1109
|
+
const persistence = FromModelController.getPersistence(ModelConstr);
|
|
1110
|
+
const factoryPersistence = persistence instanceof ModelService ? persistence.repo : persistence;
|
|
1111
|
+
const decoratorConfig = Metadata.get(ModelConstr, Metadata.key(DECAF_CONTROLLER_CONFIG));
|
|
1112
|
+
const moduleOverride = moduleConfigOverrides?.[ModelConstr.name];
|
|
1113
|
+
const mergedConfig = {
|
|
1114
|
+
...globalDefaults || {},
|
|
1115
|
+
...decoratorConfig || {},
|
|
1116
|
+
...moduleOverride || {}
|
|
1117
|
+
};
|
|
1118
|
+
const FactoryController = ModelControllerFactory.create(ModelConstr, factoryPersistence, mergedConfig);
|
|
1119
|
+
const factoryRoutes = FactoryController.__routes__;
|
|
1120
|
+
const {getPK: getPK, apiProperties: apiProperties, path: pkPath} = FromModelController.getRouteParametersFromModel(ModelConstr);
|
|
1121
|
+
log.debug(`Creating controller for model: ${modelClazzName} with ${factoryRoutes?.length ?? 0} factory routes`);
|
|
1122
|
+
const authConfig = mergedConfig.auth;
|
|
1123
|
+
function applyClassAuth(target) {
|
|
1124
|
+
if (authConfig?.public) {
|
|
1125
|
+
Public()(target);
|
|
1126
|
+
} else if (authConfig?.roles?.length) {
|
|
1127
|
+
RequireRoles(...authConfig.roles)(target);
|
|
1128
|
+
} else {
|
|
1129
|
+
Auth(ModelConstr)(target);
|
|
1130
|
+
}
|
|
1131
|
+
if (authConfig?.skipModelRoles) {
|
|
1132
|
+
SetMetadata(SKIP_MODEL_ROLES_KEY, true)(target);
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
let DynamicModelController = DynamicModelController_1 = class DynamicModelController extends DecafModelController {
|
|
1136
|
+
static get class() {
|
|
1137
|
+
return ModelConstr;
|
|
1138
|
+
}
|
|
1139
|
+
get class() {
|
|
1140
|
+
return ModelConstr;
|
|
1141
|
+
}
|
|
1142
|
+
constructor(clientContext) {
|
|
1143
|
+
super(clientContext, DynamicModelController_1.name);
|
|
1144
|
+
this.pk = Model.pk(ModelConstr);
|
|
1145
|
+
log.info(`Registering dynamic controller for model: ${this.class.name} route: /${routePath}`);
|
|
1146
|
+
}
|
|
1147
|
+
};
|
|
1148
|
+
DynamicModelController = DynamicModelController_1 = __decorate([ Controller(routePath), ApiTags(modelClazzName), ApiExtraModels(ModelConstr), __metadata("design:paramtypes", [ DecafRequestContext ]) ], DynamicModelController);
|
|
1149
|
+
applyClassAuth(DynamicModelController);
|
|
1150
|
+
if (factoryRoutes) {
|
|
1151
|
+
const sortedRoutes = [ ...factoryRoutes ].sort((a, b) => {
|
|
1152
|
+
const aSegments = a.path.split("/").filter(Boolean);
|
|
1153
|
+
const bSegments = b.path.split("/").filter(Boolean);
|
|
1154
|
+
const aParamCount = aSegments.filter(s => s.startsWith(":")).length;
|
|
1155
|
+
const bParamCount = bSegments.filter(s => s.startsWith(":")).length;
|
|
1156
|
+
const aLiteralCount = aSegments.length - aParamCount;
|
|
1157
|
+
const bLiteralCount = bSegments.length - bParamCount;
|
|
1158
|
+
if (aLiteralCount !== bLiteralCount) return bLiteralCount - aLiteralCount;
|
|
1159
|
+
if (aParamCount !== bParamCount) return aParamCount - bParamCount;
|
|
1160
|
+
return 0;
|
|
1161
|
+
});
|
|
1162
|
+
for (const route of sortedRoutes) {
|
|
1163
|
+
const registration = FromModelController.matchRoute(route, pkPath, apiProperties, getPK, ModelConstr, modelClazzName, factoryPersistence);
|
|
1164
|
+
if (!registration) continue;
|
|
1165
|
+
const {methodName: methodName, handler: handler, decorators: decorators, paramDecorators: paramDecorators} = registration;
|
|
1166
|
+
const descriptor = FromModelController.defineMethod(DynamicModelController, methodName, handler);
|
|
1167
|
+
if (descriptor) {
|
|
1168
|
+
const httpDecorator = HttpVerbToDecorator(route.method)(route.path.replace(/^\/+|\/+$/g, "") || undefined);
|
|
1169
|
+
FromModelController.applyDecorators(DynamicModelController, methodName, [ httpDecorator, ...decorators ], paramDecorators);
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
return DynamicModelController;
|
|
1174
|
+
}
|
|
1175
|
+
static getRouteParametersFromModel(ModelClazz) {
|
|
1176
|
+
const pk = Model.pk(ModelClazz);
|
|
1177
|
+
const composed = Metadata.get(ModelClazz, Metadata.key(DBKeys.COMPOSED, pk));
|
|
1178
|
+
const composedKeys = composed?.args ?? [];
|
|
1179
|
+
const uniqueKeys = Array.isArray(composedKeys) && composedKeys.length > 0 ? Array.from(new Set([ ...composedKeys ])) : Array.from(new Set([ pk ]));
|
|
1180
|
+
const description = Metadata.description(ModelClazz) ?? "";
|
|
1181
|
+
const path = `:${uniqueKeys.join("/:")}`;
|
|
1182
|
+
const apiProperties = uniqueKeys.map(key => ({
|
|
1183
|
+
name: key,
|
|
1184
|
+
description: Metadata.description(ModelClazz, key),
|
|
1185
|
+
required: true,
|
|
1186
|
+
type: String
|
|
1187
|
+
}));
|
|
1188
|
+
return {
|
|
1189
|
+
path: path,
|
|
1190
|
+
description: description,
|
|
1191
|
+
apiProperties: apiProperties,
|
|
1192
|
+
getPK: (...params) => composed?.separator ? params.join(composed.separator) : params.join("")
|
|
1193
|
+
};
|
|
1194
|
+
}
|
|
1195
|
+
static defineMethod(target, methodName, handler) {
|
|
1196
|
+
Object.defineProperty(target.prototype || target, methodName, {
|
|
1197
|
+
value: handler,
|
|
1198
|
+
writable: false,
|
|
1199
|
+
configurable: true,
|
|
1200
|
+
enumerable: false
|
|
1201
|
+
});
|
|
1202
|
+
return Object.getOwnPropertyDescriptor(target.prototype || target, methodName);
|
|
1203
|
+
}
|
|
1204
|
+
static applyDecorators(target, methodName, methodDecorators, paramDecorators = []) {
|
|
1205
|
+
const proto = target?.prototype ?? target;
|
|
1206
|
+
const descriptor = Object.getOwnPropertyDescriptor(proto, methodName);
|
|
1207
|
+
methodDecorators.forEach(d => d(proto, methodName, descriptor));
|
|
1208
|
+
paramDecorators.forEach(({decorator: decorator, index: index}) => decorator(proto, methodName, index));
|
|
1209
|
+
}
|
|
1210
|
+
static matchRoute(route, pkPath, apiProperties, getPK, ModelConstr, modelClazzName, persistence) {
|
|
1211
|
+
const {method: method, path: path} = route;
|
|
1212
|
+
const normalizedPath = path.replace(/^\/+|\/+$/g, "");
|
|
1213
|
+
if (method === "POST" && normalizedPath === "") {
|
|
1214
|
+
return FromModelController.createRegistration("create", FromModelController.createCreateHandler(ModelConstr, modelClazzName), FromModelController.createCreateDecorators(ModelConstr, modelClazzName), [ {
|
|
1215
|
+
decorator: DecafBody(),
|
|
1216
|
+
index: 0
|
|
1217
|
+
}, {
|
|
1218
|
+
decorator: Response({
|
|
1219
|
+
passthrough: true
|
|
1220
|
+
}),
|
|
1221
|
+
index: 1
|
|
1222
|
+
} ]);
|
|
1223
|
+
}
|
|
1224
|
+
if (method === "POST" && normalizedPath === "bulk") {
|
|
1225
|
+
return FromModelController.createRegistration("createAll", FromModelController.createBulkCreateHandler(ModelConstr, modelClazzName), FromModelController.bulkCreateDecorators(ModelConstr, modelClazzName), [ {
|
|
1226
|
+
decorator: DecafBody(),
|
|
1227
|
+
index: 0
|
|
1228
|
+
}, {
|
|
1229
|
+
decorator: Response({
|
|
1230
|
+
passthrough: true
|
|
1231
|
+
}),
|
|
1232
|
+
index: 1
|
|
1233
|
+
} ]);
|
|
1234
|
+
}
|
|
1235
|
+
if (method === "GET" && normalizedPath === "bulk") {
|
|
1236
|
+
return FromModelController.createRegistration("readAll", FromModelController.createBulkReadHandler(modelClazzName), FromModelController.bulkReadDecorators(ModelConstr, modelClazzName), [ {
|
|
1237
|
+
decorator: Query("ids"),
|
|
1238
|
+
index: 0
|
|
1239
|
+
} ]);
|
|
1240
|
+
}
|
|
1241
|
+
if (method === "PUT" && normalizedPath === "bulk") {
|
|
1242
|
+
return FromModelController.createRegistration("updateAll", FromModelController.createBulkUpdateHandler(modelClazzName), FromModelController.bulkUpdateDecorators(ModelConstr, modelClazzName, apiProperties), [ {
|
|
1243
|
+
decorator: DecafBody(),
|
|
1244
|
+
index: 0
|
|
1245
|
+
}, {
|
|
1246
|
+
decorator: Response({
|
|
1247
|
+
passthrough: true
|
|
1248
|
+
}),
|
|
1249
|
+
index: 1
|
|
1250
|
+
} ]);
|
|
1251
|
+
}
|
|
1252
|
+
if (method === "DELETE" && normalizedPath === "bulk") {
|
|
1253
|
+
return FromModelController.createRegistration("deleteAll", FromModelController.createBulkDeleteHandler(modelClazzName), FromModelController.bulkDeleteDecorators(ModelConstr, modelClazzName, apiProperties), [ {
|
|
1254
|
+
decorator: Query("ids"),
|
|
1255
|
+
index: 0
|
|
1256
|
+
}, {
|
|
1257
|
+
decorator: Response({
|
|
1258
|
+
passthrough: true
|
|
1259
|
+
}),
|
|
1260
|
+
index: 1
|
|
1261
|
+
} ]);
|
|
1262
|
+
}
|
|
1263
|
+
if (method === "GET" && normalizedPath === pkPath) {
|
|
1264
|
+
return FromModelController.createRegistration("read", FromModelController.createReadHandler(getPK, modelClazzName), FromModelController.readDecorators(ModelConstr, modelClazzName, apiProperties, pkPath), [ {
|
|
1265
|
+
decorator: DecafParams(apiProperties),
|
|
1266
|
+
index: 0
|
|
1267
|
+
} ]);
|
|
1268
|
+
}
|
|
1269
|
+
if (method === "PUT" && normalizedPath === pkPath) {
|
|
1270
|
+
return FromModelController.createRegistration("update", FromModelController.createUpdateHandler(getPK, ModelConstr, modelClazzName), FromModelController.updateDecorators(ModelConstr, modelClazzName, apiProperties, pkPath), [ {
|
|
1271
|
+
decorator: DecafParams(apiProperties),
|
|
1272
|
+
index: 0
|
|
1273
|
+
}, {
|
|
1274
|
+
decorator: DecafBody(),
|
|
1275
|
+
index: 1
|
|
1276
|
+
}, {
|
|
1277
|
+
decorator: Response({
|
|
1278
|
+
passthrough: true
|
|
1279
|
+
}),
|
|
1280
|
+
index: 2
|
|
1281
|
+
} ]);
|
|
1282
|
+
}
|
|
1283
|
+
if (method === "DELETE" && normalizedPath === pkPath) {
|
|
1284
|
+
return FromModelController.createRegistration("delete", FromModelController.createDeleteHandler(getPK, modelClazzName), FromModelController.deleteDecorators(ModelConstr, modelClazzName, apiProperties, pkPath), [ {
|
|
1285
|
+
decorator: DecafParams(apiProperties),
|
|
1286
|
+
index: 0
|
|
1287
|
+
}, {
|
|
1288
|
+
decorator: Response({
|
|
1289
|
+
passthrough: true
|
|
1290
|
+
}),
|
|
1291
|
+
index: 1
|
|
1292
|
+
} ]);
|
|
1293
|
+
}
|
|
1294
|
+
const fallbackSegments = normalizedPath.split("/").filter(Boolean);
|
|
1295
|
+
const isAllParams = fallbackSegments.length > 0 && fallbackSegments.every(s => s.startsWith(":"));
|
|
1296
|
+
if (isAllParams && normalizedPath !== pkPath) {
|
|
1297
|
+
const fallbackApiProps = fallbackSegments.map(s => s.slice(1)).map(name => ({
|
|
1298
|
+
name: name,
|
|
1299
|
+
description: `${name} parameter`,
|
|
1300
|
+
required: true,
|
|
1301
|
+
type: String
|
|
1302
|
+
}));
|
|
1303
|
+
const suffix = fallbackSegments.map(s => s.slice(1)).join("And");
|
|
1304
|
+
if (method === "GET") {
|
|
1305
|
+
return FromModelController.createRegistration(`readBy${suffix}`, FromModelController.createReadHandler(getPK, modelClazzName), FromModelController.readDecorators(ModelConstr, modelClazzName, fallbackApiProps, normalizedPath), [ {
|
|
1306
|
+
decorator: DecafParams(fallbackApiProps),
|
|
1307
|
+
index: 0
|
|
1308
|
+
} ]);
|
|
1309
|
+
}
|
|
1310
|
+
if (method === "PUT") {
|
|
1311
|
+
return FromModelController.createRegistration(`updateBy${suffix}`, FromModelController.createUpdateHandler(getPK, ModelConstr, modelClazzName), FromModelController.updateDecorators(ModelConstr, modelClazzName, fallbackApiProps, normalizedPath), [ {
|
|
1312
|
+
decorator: DecafParams(fallbackApiProps),
|
|
1313
|
+
index: 0
|
|
1314
|
+
}, {
|
|
1315
|
+
decorator: DecafBody(),
|
|
1316
|
+
index: 1
|
|
1317
|
+
}, {
|
|
1318
|
+
decorator: Response({
|
|
1319
|
+
passthrough: true
|
|
1320
|
+
}),
|
|
1321
|
+
index: 2
|
|
1322
|
+
} ]);
|
|
1323
|
+
}
|
|
1324
|
+
if (method === "DELETE") {
|
|
1325
|
+
return FromModelController.createRegistration(`deleteBy${suffix}`, FromModelController.createDeleteHandler(getPK, modelClazzName), FromModelController.deleteDecorators(ModelConstr, modelClazzName, fallbackApiProps, normalizedPath), [ {
|
|
1326
|
+
decorator: DecafParams(fallbackApiProps),
|
|
1327
|
+
index: 0
|
|
1328
|
+
}, {
|
|
1329
|
+
decorator: Response({
|
|
1330
|
+
passthrough: true
|
|
1331
|
+
}),
|
|
1332
|
+
index: 1
|
|
1333
|
+
} ]);
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
if (method === "GET" && normalizedPath === "statement/:method/*args") {
|
|
1337
|
+
return FromModelController.createRegistration("statement", FromModelController.createStatementHandler(modelClazzName), FromModelController.statementDecorators(ModelConstr, modelClazzName), [ {
|
|
1338
|
+
decorator: Param("method"),
|
|
1339
|
+
index: 0
|
|
1340
|
+
}, {
|
|
1341
|
+
decorator: Param("args"),
|
|
1342
|
+
index: 1
|
|
1343
|
+
}, {
|
|
1344
|
+
decorator: DecafQuery(),
|
|
1345
|
+
index: 2
|
|
1346
|
+
} ]);
|
|
1347
|
+
}
|
|
1348
|
+
const statementRoutes = {
|
|
1349
|
+
"listBy/:key": PreparedStatementKeys.LIST_BY,
|
|
1350
|
+
"paginateBy/:key/:page": PreparedStatementKeys.PAGE_BY,
|
|
1351
|
+
"find/:value": PreparedStatementKeys.FIND,
|
|
1352
|
+
"page/:value": PreparedStatementKeys.PAGE,
|
|
1353
|
+
"findOneBy/:key/:value": PreparedStatementKeys.FIND_ONE_BY,
|
|
1354
|
+
"findBy/:key/:value": PreparedStatementKeys.FIND_BY,
|
|
1355
|
+
"countOf/:field": PreparedStatementKeys.COUNT_OF,
|
|
1356
|
+
"maxOf/:field": PreparedStatementKeys.MAX_OF,
|
|
1357
|
+
"minOf/:field": PreparedStatementKeys.MIN_OF,
|
|
1358
|
+
"avgOf/:field": PreparedStatementKeys.AVG_OF,
|
|
1359
|
+
"sumOf/:field": PreparedStatementKeys.SUM_OF,
|
|
1360
|
+
"distinctOf/:field": PreparedStatementKeys.DISTINCT_OF,
|
|
1361
|
+
"groupOf/:field": PreparedStatementKeys.GROUP_OF
|
|
1362
|
+
};
|
|
1363
|
+
const statementKey = statementRoutes[normalizedPath];
|
|
1364
|
+
if (statementKey && method === "GET") {
|
|
1365
|
+
return FromModelController.createRegistration(FromModelController.statementMethodName(normalizedPath), FromModelController.createStatementShortcutHandler(statementKey, modelClazzName), FromModelController.statementShortcutDecorators(ModelConstr, modelClazzName, normalizedPath, statementKey), FromModelController.statementShortcutParams(normalizedPath));
|
|
1366
|
+
}
|
|
1367
|
+
if (method === "GET" && normalizedPath.startsWith("query/")) {
|
|
1368
|
+
const queryMethod = normalizedPath.replace(/^query\//, "").split("/")[0];
|
|
1369
|
+
return FromModelController.createRegistration(queryMethod, FromModelController.createComplexQueryHandler(queryMethod), FromModelController.getQueryDecorators(queryMethod, normalizedPath, "GET", true), FromModelController.complexQueryParams(normalizedPath));
|
|
1370
|
+
}
|
|
1371
|
+
const pathSegments = normalizedPath.split("/").filter(Boolean);
|
|
1372
|
+
const knownPrefixes = new Set([ "listBy", "findBy", "findByPaginate", "findOneBy", "paginateBy", "find", "page", "countOf", "maxOf", "minOf", "avgOf", "sumOf", "distinctOf", "groupOf", "statement", "bulk", "query" ]);
|
|
1373
|
+
if (pathSegments.length > 0 && !normalizedPath.startsWith("query/") && !knownPrefixes.has(pathSegments[0])) {
|
|
1374
|
+
const routeMetadata = Metadata.get(persistence?.constructor, Metadata.key(DECAF_ROUTE)) ?? {};
|
|
1375
|
+
const matchedEntry = Object.entries(routeMetadata).find(([, info]) => info && typeof info === "object" && info.path?.replace(/^\/+|\/+$/g, "") === normalizedPath);
|
|
1376
|
+
const actualMethodName = matchedEntry?.[0] || pathSegments[0];
|
|
1377
|
+
const paramSegments = pathSegments.filter(s => s.startsWith(":"));
|
|
1378
|
+
const apiPathParams = paramSegments.map(s => s.slice(1)).map(name => ({
|
|
1379
|
+
name: name,
|
|
1380
|
+
description: `${name} parameter for the query`,
|
|
1381
|
+
required: true,
|
|
1382
|
+
type: String
|
|
1383
|
+
}));
|
|
1384
|
+
return FromModelController.createRegistration(actualMethodName, FromModelController.createCustomRouteHandler(actualMethodName), [ ...apiPathParams.map(p => ApiParam(p)), ApiOperation({
|
|
1385
|
+
summary: `Retrieve records using "${actualMethodName}".`
|
|
1386
|
+
}), ApiOkResponse({
|
|
1387
|
+
description: "Result successfully retrieved."
|
|
1388
|
+
}), ApiNoContentResponse({
|
|
1389
|
+
description: "No content returned by the method."
|
|
1390
|
+
}) ], FromModelController.complexQueryParams(normalizedPath));
|
|
1391
|
+
}
|
|
1392
|
+
return undefined;
|
|
1393
|
+
}
|
|
1394
|
+
static createRegistration(methodName, handler, decorators, paramDecorators) {
|
|
1395
|
+
return {
|
|
1396
|
+
methodName: methodName,
|
|
1397
|
+
handler: handler,
|
|
1398
|
+
decorators: decorators,
|
|
1399
|
+
paramDecorators: paramDecorators
|
|
1400
|
+
};
|
|
1401
|
+
}
|
|
1402
|
+
static statementMethodName(path) {
|
|
1403
|
+
const firstSegment = path.split("/")[0];
|
|
1404
|
+
return firstSegment;
|
|
1405
|
+
}
|
|
1406
|
+
static statementShortcutParams(path) {
|
|
1407
|
+
const segments = path.split("/").filter(s => s.startsWith(":"));
|
|
1408
|
+
const params = [];
|
|
1409
|
+
segments.forEach((seg, i) => {
|
|
1410
|
+
const name = seg.replace(":", "");
|
|
1411
|
+
params.push({
|
|
1412
|
+
decorator: Param(name),
|
|
1413
|
+
index: i
|
|
1414
|
+
});
|
|
1415
|
+
});
|
|
1416
|
+
if (path.startsWith("listBy/") || path.startsWith("paginateBy/") || path.startsWith("find/") || path.startsWith("page/")) {
|
|
1417
|
+
params.push({
|
|
1418
|
+
decorator: DecafQuery(),
|
|
1419
|
+
index: segments.length
|
|
1420
|
+
});
|
|
1421
|
+
}
|
|
1422
|
+
return params;
|
|
1423
|
+
}
|
|
1424
|
+
static complexQueryParams(path) {
|
|
1425
|
+
const segments = path.split("/").filter(s => s.startsWith(":"));
|
|
1426
|
+
const params = [];
|
|
1427
|
+
segments.forEach((seg, i) => {
|
|
1428
|
+
const name = seg.replace(":", "");
|
|
1429
|
+
params.push({
|
|
1430
|
+
decorator: Param(name),
|
|
1431
|
+
index: i
|
|
1432
|
+
});
|
|
1433
|
+
});
|
|
1434
|
+
if (path.startsWith("query/")) {
|
|
1435
|
+
params.push({
|
|
1436
|
+
decorator: DecafQuery(),
|
|
1437
|
+
index: segments.length
|
|
1438
|
+
});
|
|
1439
|
+
}
|
|
1440
|
+
return params;
|
|
1441
|
+
}
|
|
1442
|
+
static createCreateHandler(ModelConstr, modelClazzName) {
|
|
1443
|
+
return async function create(data, resp) {
|
|
1444
|
+
const {ctx: ctx, log: log} = (await this.logCtx([], OperationKeys.CREATE, true)).for(create);
|
|
1445
|
+
log.verbose(`creating new ${modelClazzName}`);
|
|
1446
|
+
let created;
|
|
1447
|
+
try {
|
|
1448
|
+
created = await this.persistence(ctx).create(data, ctx);
|
|
1449
|
+
} catch (e) {
|
|
1450
|
+
log.error(`Failed to create new ${modelClazzName}`, e);
|
|
1451
|
+
throw e;
|
|
1452
|
+
}
|
|
1453
|
+
log.info(`created new ${modelClazzName} with id ${created[this.pk]}`);
|
|
1454
|
+
if (resp) ctx.toResponse(resp);
|
|
1455
|
+
return created;
|
|
1456
|
+
};
|
|
1457
|
+
}
|
|
1458
|
+
static createBulkCreateHandler(ModelConstr, modelClazzName) {
|
|
1459
|
+
return async function createAll(data, resp) {
|
|
1460
|
+
const {ctx: ctx, log: log} = (await this.logCtx([], BulkCrudOperationKeys.CREATE_ALL, true)).for(createAll);
|
|
1461
|
+
log.verbose(`creating new ${modelClazzName}`);
|
|
1462
|
+
let created;
|
|
1463
|
+
try {
|
|
1464
|
+
created = await this.persistence(ctx).createAll(data.map(d => new ModelConstr(d)), ctx);
|
|
1465
|
+
} catch (e) {
|
|
1466
|
+
log.error(`Failed to create new ${modelClazzName}`, e);
|
|
1467
|
+
throw e;
|
|
1468
|
+
}
|
|
1469
|
+
log.info(`created new ${modelClazzName} with id ${created[this.pk]}`);
|
|
1470
|
+
if (resp) ctx.toResponse(resp);
|
|
1471
|
+
return created;
|
|
1472
|
+
};
|
|
1473
|
+
}
|
|
1474
|
+
static createBulkReadHandler(modelClazzName) {
|
|
1475
|
+
return async function readAll(ids) {
|
|
1476
|
+
const {ctx: ctx, log: log} = (await this.logCtx([], BulkCrudOperationKeys.READ_ALL, true)).for(readAll);
|
|
1477
|
+
const normalizedIds = Array.isArray(ids) ? ids : [ ids ];
|
|
1478
|
+
let read;
|
|
1479
|
+
try {
|
|
1480
|
+
log.debug(`reading ${normalizedIds} ${modelClazzName}`);
|
|
1481
|
+
read = await this.persistence(ctx).readAll(normalizedIds, ctx);
|
|
1482
|
+
} catch (e) {
|
|
1483
|
+
log.error(`Failed to read ${modelClazzName}`, e);
|
|
1484
|
+
throw e;
|
|
1485
|
+
}
|
|
1486
|
+
log.info(`read ${read.length} ${modelClazzName}`);
|
|
1487
|
+
return read;
|
|
1488
|
+
};
|
|
1489
|
+
}
|
|
1490
|
+
static createBulkUpdateHandler(modelClazzName) {
|
|
1491
|
+
return async function updateAll(body, resp) {
|
|
1492
|
+
const {ctx: ctx, log: log} = (await this.logCtx([], BulkCrudOperationKeys.UPDATE_ALL, true)).for(updateAll);
|
|
1493
|
+
let updated;
|
|
1494
|
+
try {
|
|
1495
|
+
log.info(`updating ${body.length} ${modelClazzName}`);
|
|
1496
|
+
updated = await this.persistence(ctx).updateAll(body, ctx);
|
|
1497
|
+
} catch (e) {
|
|
1498
|
+
log.error(e);
|
|
1499
|
+
throw e;
|
|
1500
|
+
}
|
|
1501
|
+
if (resp) ctx.toResponse(resp);
|
|
1502
|
+
return updated;
|
|
1503
|
+
};
|
|
1504
|
+
}
|
|
1505
|
+
static createBulkDeleteHandler(modelClazzName) {
|
|
1506
|
+
return async function deleteAll(ids, resp) {
|
|
1507
|
+
const {ctx: ctx, log: log} = (await this.logCtx([], BulkCrudOperationKeys.DELETE_ALL, true)).for(deleteAll);
|
|
1508
|
+
const normalizedIds = Array.isArray(ids) ? ids : [ ids ];
|
|
1509
|
+
let read;
|
|
1510
|
+
try {
|
|
1511
|
+
log.debug(`deleting ${normalizedIds.length} ${modelClazzName}`);
|
|
1512
|
+
read = await this.persistence(ctx).deleteAll(normalizedIds, ctx);
|
|
1513
|
+
} catch (e) {
|
|
1514
|
+
log.error(`Failed to delete ${modelClazzName}`, e);
|
|
1515
|
+
throw e;
|
|
1516
|
+
}
|
|
1517
|
+
log.info(`deleted ${read.length} ${modelClazzName}`);
|
|
1518
|
+
if (resp) ctx.toResponse(resp);
|
|
1519
|
+
return read;
|
|
1520
|
+
};
|
|
1521
|
+
}
|
|
1522
|
+
static createReadHandler(getPK, modelClazzName) {
|
|
1523
|
+
return async function read(routeParams) {
|
|
1524
|
+
const {ctx: ctx, log: log} = (await this.logCtx([], OperationKeys.READ, true)).for(read);
|
|
1525
|
+
const id = getPK(...routeParams.valuesInOrder);
|
|
1526
|
+
if (typeof id === "undefined") throw new ValidationError(`No ${this.pk} provided`);
|
|
1527
|
+
let readResult;
|
|
1528
|
+
try {
|
|
1529
|
+
log.debug(`reading ${modelClazzName} with ${this.pk} ${id}`);
|
|
1530
|
+
readResult = await this.persistence(ctx).read(id, ctx);
|
|
1531
|
+
} catch (e) {
|
|
1532
|
+
log.error(`Failed to read ${modelClazzName} with id ${id}`, e);
|
|
1533
|
+
throw e;
|
|
1534
|
+
}
|
|
1535
|
+
log.info(`read ${modelClazzName} with id ${readResult[this.pk]}`);
|
|
1536
|
+
return readResult;
|
|
1537
|
+
};
|
|
1538
|
+
}
|
|
1539
|
+
static createUpdateHandler(getPK, ModelConstr, modelClazzName) {
|
|
1540
|
+
return async function update(routeParams, body, resp) {
|
|
1541
|
+
const {ctx: ctx, log: log} = (await this.logCtx([], OperationKeys.UPDATE, true)).for(update);
|
|
1542
|
+
const id = getPK(...routeParams.valuesInOrder);
|
|
1543
|
+
if (typeof id === "undefined") throw new ValidationError(`No ${this.pk} provided`);
|
|
1544
|
+
let updated;
|
|
1545
|
+
try {
|
|
1546
|
+
log.info(`updating ${modelClazzName} with ${this.pk} ${id}`);
|
|
1547
|
+
const payload = JSON.parse(JSON.stringify(body));
|
|
1548
|
+
updated = await this.persistence(ctx).update(new ModelConstr({
|
|
1549
|
+
...payload,
|
|
1550
|
+
[this.pk]: id
|
|
1551
|
+
}), ctx);
|
|
1552
|
+
} catch (e) {
|
|
1553
|
+
log.error(e);
|
|
1554
|
+
throw e;
|
|
1555
|
+
}
|
|
1556
|
+
if (resp) ctx.toResponse(resp);
|
|
1557
|
+
return updated;
|
|
1558
|
+
};
|
|
1559
|
+
}
|
|
1560
|
+
static createDeleteHandler(getPK, modelClazzName) {
|
|
1561
|
+
return async function remove(routeParams, resp) {
|
|
1562
|
+
const {ctx: ctx, log: log} = (await this.logCtx([], OperationKeys.DELETE, true)).for(remove);
|
|
1563
|
+
const id = getPK(...routeParams.valuesInOrder);
|
|
1564
|
+
if (typeof id === "undefined") throw new ValidationError(`No ${this.pk} provided`);
|
|
1565
|
+
let del;
|
|
1566
|
+
try {
|
|
1567
|
+
log.debug(`deleting ${modelClazzName} with ${this.pk} ${id}`);
|
|
1568
|
+
del = await this.persistence(ctx).delete(id, ctx);
|
|
1569
|
+
} catch (e) {
|
|
1570
|
+
log.error(`Failed to delete ${modelClazzName} with id ${id}`, e);
|
|
1571
|
+
throw e;
|
|
1572
|
+
}
|
|
1573
|
+
log.info(`deleted ${modelClazzName} with id ${id}`);
|
|
1574
|
+
if (resp) ctx.toResponse(resp);
|
|
1575
|
+
return del;
|
|
1576
|
+
};
|
|
1577
|
+
}
|
|
1578
|
+
static createStatementHandler(modelClazzName) {
|
|
1579
|
+
return async function statement(name, args, details) {
|
|
1580
|
+
const {ctx: ctx} = (await this.logCtx([], PersistenceKeys.STATEMENT, true)).for(statement);
|
|
1581
|
+
const {direction: direction, offset: offset, limit: limit, bookmark: bookmark} = details;
|
|
1582
|
+
args = args.map(a => (typeof a === "string" ? parseInt(a) : a) || a);
|
|
1583
|
+
const pathDirection = args.length > 1 ? args[1] : undefined;
|
|
1584
|
+
const resolvedDirection = direction ?? pathDirection;
|
|
1585
|
+
if (resolvedDirection && args.length > 1) args[1] = resolvedDirection;
|
|
1586
|
+
switch (name) {
|
|
1587
|
+
case PreparedStatementKeys.FIND:
|
|
1588
|
+
case PreparedStatementKeys.FIND_BY:
|
|
1589
|
+
break;
|
|
1590
|
+
|
|
1591
|
+
case PreparedStatementKeys.LIST_BY:
|
|
1592
|
+
args.push(direction);
|
|
1593
|
+
break;
|
|
1594
|
+
|
|
1595
|
+
case PreparedStatementKeys.PAGE:
|
|
1596
|
+
case PreparedStatementKeys.PAGE_BY:
|
|
1597
|
+
args = [ args[0], resolvedDirection, {
|
|
1598
|
+
limit: limit,
|
|
1599
|
+
offset: offset,
|
|
1600
|
+
bookmark: bookmark
|
|
1601
|
+
} ];
|
|
1602
|
+
break;
|
|
1603
|
+
|
|
1604
|
+
case PreparedStatementKeys.FIND_ONE_BY:
|
|
1605
|
+
break;
|
|
1606
|
+
|
|
1607
|
+
case PreparedStatementKeys.COUNT_OF:
|
|
1608
|
+
case PreparedStatementKeys.MAX_OF:
|
|
1609
|
+
case PreparedStatementKeys.MIN_OF:
|
|
1610
|
+
case PreparedStatementKeys.AVG_OF:
|
|
1611
|
+
case PreparedStatementKeys.SUM_OF:
|
|
1612
|
+
case PreparedStatementKeys.DISTINCT_OF:
|
|
1613
|
+
case PreparedStatementKeys.GROUP_OF:
|
|
1614
|
+
break;
|
|
1615
|
+
}
|
|
1616
|
+
return this.persistence(ctx).statement(name, ...args, ctx);
|
|
1617
|
+
};
|
|
1618
|
+
}
|
|
1619
|
+
static createStatementShortcutHandler(statementKey, modelClazzName) {
|
|
1620
|
+
return async function statementShortcut(...args) {
|
|
1621
|
+
const {ctx: ctx} = (await this.logCtx([], statementKey, true)).for(statementShortcut);
|
|
1622
|
+
switch (statementKey) {
|
|
1623
|
+
case PreparedStatementKeys.LIST_BY:
|
|
1624
|
+
{
|
|
1625
|
+
const [key, details] = args;
|
|
1626
|
+
return this.persistence(ctx).listBy(key, details?.direction, ctx);
|
|
1627
|
+
}
|
|
1628
|
+
|
|
1629
|
+
case PreparedStatementKeys.PAGE_BY:
|
|
1630
|
+
{
|
|
1631
|
+
const [key, page, details] = args;
|
|
1632
|
+
return this.persistence(ctx).paginateBy(key, details?.direction, {
|
|
1633
|
+
limit: details?.limit,
|
|
1634
|
+
offset: details?.offset,
|
|
1635
|
+
page: page
|
|
1636
|
+
}, ctx);
|
|
1637
|
+
}
|
|
1638
|
+
|
|
1639
|
+
case PreparedStatementKeys.FIND:
|
|
1640
|
+
{
|
|
1641
|
+
const [value, details] = args;
|
|
1642
|
+
const direction = details?.direction ?? OrderDirection.ASC;
|
|
1643
|
+
const persistence = this.persistence(ctx);
|
|
1644
|
+
if (typeof persistence.find === "function") return persistence.find(value, direction, ctx);
|
|
1645
|
+
return persistence.statement(PreparedStatementKeys.FIND, value, direction, ctx);
|
|
1646
|
+
}
|
|
1647
|
+
|
|
1648
|
+
case PreparedStatementKeys.PAGE:
|
|
1649
|
+
{
|
|
1650
|
+
const [value, details] = args;
|
|
1651
|
+
const ref = {
|
|
1652
|
+
offset: details?.offset ?? 1,
|
|
1653
|
+
limit: details?.limit ?? 10,
|
|
1654
|
+
bookmark: details?.bookmark
|
|
1655
|
+
};
|
|
1656
|
+
const persistence = this.persistence(ctx);
|
|
1657
|
+
const direction = details?.direction ?? OrderDirection.ASC;
|
|
1658
|
+
if (typeof persistence.page === "function") return persistence.page(value, direction, ref, ctx);
|
|
1659
|
+
return persistence.statement(PreparedStatementKeys.PAGE, value, direction, ref, ctx);
|
|
1660
|
+
}
|
|
1661
|
+
|
|
1662
|
+
case PreparedStatementKeys.FIND_ONE_BY:
|
|
1663
|
+
{
|
|
1664
|
+
const [key, value] = args;
|
|
1665
|
+
return this.persistence(ctx).findOneBy(key, value, ctx);
|
|
1666
|
+
}
|
|
1667
|
+
|
|
1668
|
+
case PreparedStatementKeys.FIND_BY:
|
|
1669
|
+
{
|
|
1670
|
+
const [key, value] = args;
|
|
1671
|
+
return this.persistence(ctx).for(ctx.toOverrides()).findBy(key, value, ctx);
|
|
1672
|
+
}
|
|
1673
|
+
|
|
1674
|
+
default:
|
|
1675
|
+
if (statementKey === PreparedStatementKeys.COUNT_OF || statementKey === PreparedStatementKeys.MAX_OF || statementKey === PreparedStatementKeys.MIN_OF || statementKey === PreparedStatementKeys.AVG_OF || statementKey === PreparedStatementKeys.SUM_OF || statementKey === PreparedStatementKeys.DISTINCT_OF || statementKey === PreparedStatementKeys.GROUP_OF) {
|
|
1676
|
+
const [field] = args;
|
|
1677
|
+
return this.persistence(ctx).statement(statementKey, field, ctx);
|
|
1678
|
+
}
|
|
1679
|
+
throw new Error(`Unknown statement: ${statementKey}`);
|
|
1680
|
+
}
|
|
1681
|
+
};
|
|
1682
|
+
}
|
|
1683
|
+
static createComplexQueryHandler(methodName) {
|
|
1684
|
+
return async function complexQuery(...args) {
|
|
1685
|
+
const log = this.log?.for?.(complexQuery);
|
|
1686
|
+
try {
|
|
1687
|
+
if (log) log.debug(`Invoking custom query "${methodName}"`);
|
|
1688
|
+
const {ctx: ctx} = (await this.logCtx([], methodName, true)).for(complexQuery);
|
|
1689
|
+
const persistence = this.persistence(ctx);
|
|
1690
|
+
const spreadArgs = FromModelController.extractQueryArgs(args);
|
|
1691
|
+
if (typeof persistence[methodName] === "function") {
|
|
1692
|
+
return persistence[methodName](...spreadArgs, ctx);
|
|
1693
|
+
}
|
|
1694
|
+
if (typeof persistence.statement === "function") {
|
|
1695
|
+
return persistence.statement(methodName, ...spreadArgs, ctx);
|
|
1696
|
+
}
|
|
1697
|
+
throw new Error(`Persistence method "${methodName}" not found on ${persistence?.constructor?.name}`);
|
|
1698
|
+
} catch (e) {
|
|
1699
|
+
if (log) log.error(`Custom query "${methodName}" failed`, e);
|
|
1700
|
+
throw e;
|
|
1701
|
+
}
|
|
1702
|
+
};
|
|
1703
|
+
}
|
|
1704
|
+
static createCustomRouteHandler(methodName) {
|
|
1705
|
+
return async function customRoute(...args) {
|
|
1706
|
+
const log = this.log?.for?.(customRoute);
|
|
1707
|
+
const {ctx: ctx} = (await this.logCtx([], methodName, true)).for(customRoute);
|
|
1708
|
+
const persistence = this.persistence(ctx);
|
|
1709
|
+
const spreadArgs = FromModelController.extractQueryArgs(args);
|
|
1710
|
+
if (typeof persistence[methodName] === "function") {
|
|
1711
|
+
return persistence[methodName](...spreadArgs, ctx);
|
|
1712
|
+
}
|
|
1713
|
+
if (persistence?.repo && typeof persistence.repo[methodName] === "function") {
|
|
1714
|
+
return persistence.repo[methodName](...spreadArgs, ctx);
|
|
1715
|
+
}
|
|
1716
|
+
if (typeof persistence.statement === "function") {
|
|
1717
|
+
return persistence.statement(methodName, ...spreadArgs, ctx);
|
|
1718
|
+
}
|
|
1719
|
+
throw new Error(`Method "${methodName}" not found on ${persistence?.constructor?.name} or its repo`);
|
|
1720
|
+
};
|
|
1721
|
+
}
|
|
1722
|
+
static extractQueryArgs(args) {
|
|
1723
|
+
if (args.length === 0) return args;
|
|
1724
|
+
const last = args[args.length - 1];
|
|
1725
|
+
if (last && typeof last === "object" && !Array.isArray(last)) {
|
|
1726
|
+
const queryObj = args.pop();
|
|
1727
|
+
const hasDirection = queryObj.direction !== undefined;
|
|
1728
|
+
const hasLimit = queryObj.limit !== undefined;
|
|
1729
|
+
const hasOffset = queryObj.offset !== undefined;
|
|
1730
|
+
if (!hasDirection && !hasLimit && !hasOffset) return args;
|
|
1731
|
+
const extras = [];
|
|
1732
|
+
if (hasDirection) extras.push(queryObj.direction); else if (hasLimit || hasOffset) extras.push(undefined);
|
|
1733
|
+
if (hasLimit) extras.push(queryObj.limit);
|
|
1734
|
+
if (hasOffset) extras.push(queryObj.offset);
|
|
1735
|
+
return [ ...args, ...extras ];
|
|
1736
|
+
}
|
|
1737
|
+
return args;
|
|
1738
|
+
}
|
|
1739
|
+
static createCreateDecorators(ModelConstr, modelClazzName) {
|
|
1740
|
+
return [ ApiOperationFromModel(ModelConstr, "POST"), ApiOperation({
|
|
1741
|
+
summary: `Create a new ${modelClazzName}.`
|
|
1742
|
+
}), ApiBody({
|
|
1743
|
+
description: `Payload for ${modelClazzName}`,
|
|
1744
|
+
type: DtoFor(OperationKeys.CREATE, ModelConstr)
|
|
1745
|
+
}), ApiCreatedResponse({
|
|
1746
|
+
description: `${modelClazzName} created successfully.`,
|
|
1747
|
+
schema: {
|
|
1748
|
+
$ref: getSchemaPath(ModelConstr)
|
|
1749
|
+
}
|
|
1750
|
+
}), ApiBadRequestResponse({
|
|
1751
|
+
description: "Payload validation failed."
|
|
1752
|
+
}), ApiUnprocessableEntityResponse({
|
|
1753
|
+
description: "Repository rejected the provided payload."
|
|
1754
|
+
}) ];
|
|
1755
|
+
}
|
|
1756
|
+
static bulkCreateDecorators(ModelConstr, modelClazzName) {
|
|
1757
|
+
return [ ApiOperationFromModel(ModelConstr, "POST", "bulk"), ApiOperation({
|
|
1758
|
+
summary: `Create a new ${modelClazzName}.`
|
|
1759
|
+
}), ApiBody({
|
|
1760
|
+
description: `Payload for ${modelClazzName}`,
|
|
1761
|
+
schema: {
|
|
1762
|
+
type: "array",
|
|
1763
|
+
items: {
|
|
1764
|
+
$ref: getSchemaPath(ModelConstr)
|
|
1765
|
+
}
|
|
1766
|
+
}
|
|
1767
|
+
}), ApiCreatedResponse({
|
|
1768
|
+
description: `${modelClazzName} created successfully.`,
|
|
1769
|
+
schema: {
|
|
1770
|
+
type: "array",
|
|
1771
|
+
items: {
|
|
1772
|
+
$ref: getSchemaPath(ModelConstr)
|
|
1773
|
+
}
|
|
1774
|
+
}
|
|
1775
|
+
}), ApiBadRequestResponse({
|
|
1776
|
+
description: "Payload validation failed."
|
|
1777
|
+
}), ApiUnprocessableEntityResponse({
|
|
1778
|
+
description: "Repository rejected the provided payload."
|
|
1779
|
+
}) ];
|
|
1780
|
+
}
|
|
1781
|
+
static bulkReadDecorators(ModelConstr, modelClazzName) {
|
|
1782
|
+
return [ ApiOperationFromModel(ModelConstr, "GET", "bulk"), ApiOperation({
|
|
1783
|
+
summary: `Retrieve ${modelClazzName} records by ids.`
|
|
1784
|
+
}), ApiQuery({
|
|
1785
|
+
name: "ids",
|
|
1786
|
+
required: true,
|
|
1787
|
+
type: "array"
|
|
1788
|
+
}), ApiOkResponse({
|
|
1789
|
+
description: `${modelClazzName} retrieved successfully.`,
|
|
1790
|
+
schema: {
|
|
1791
|
+
type: "array",
|
|
1792
|
+
items: {
|
|
1793
|
+
$ref: getSchemaPath(ModelConstr)
|
|
1794
|
+
}
|
|
1795
|
+
}
|
|
1796
|
+
}), ApiNotFoundResponse({
|
|
1797
|
+
description: `No ${modelClazzName} record matches the provided identifier.`
|
|
1798
|
+
}) ];
|
|
1799
|
+
}
|
|
1800
|
+
static bulkUpdateDecorators(ModelConstr, modelClazzName, apiProperties) {
|
|
1801
|
+
return [ ApiOperationFromModel(ModelConstr, "PUT", "bulk"), ApiParamsFromModel(apiProperties), ApiOperation({
|
|
1802
|
+
summary: `Replace existing ${modelClazzName} records with new payloads.`
|
|
1803
|
+
}), ApiBody({
|
|
1804
|
+
description: `Payload for replacing existing records of ${modelClazzName}`,
|
|
1805
|
+
schema: {
|
|
1806
|
+
type: "array",
|
|
1807
|
+
$ref: getSchemaPath(DtoFor(OperationKeys.UPDATE, ModelConstr))
|
|
1808
|
+
}
|
|
1809
|
+
}), ApiOkResponse({
|
|
1810
|
+
description: `${modelClazzName} updated successfully.`,
|
|
1811
|
+
schema: {
|
|
1812
|
+
type: "array",
|
|
1813
|
+
items: {
|
|
1814
|
+
$ref: getSchemaPath(ModelConstr)
|
|
1815
|
+
}
|
|
1816
|
+
}
|
|
1817
|
+
}), ApiNotFoundResponse({
|
|
1818
|
+
description: `No ${modelClazzName} record matches the provided identifier.`
|
|
1819
|
+
}), ApiBadRequestResponse({
|
|
1820
|
+
description: "Payload validation failed."
|
|
1821
|
+
}) ];
|
|
1822
|
+
}
|
|
1823
|
+
static bulkDeleteDecorators(ModelConstr, modelClazzName, apiProperties) {
|
|
1824
|
+
return [ ApiOperationFromModel(ModelConstr, "DELETE", "bulk"), ApiParamsFromModel(apiProperties), ApiOperation({
|
|
1825
|
+
summary: `Delete ${modelClazzName} records by ids.`
|
|
1826
|
+
}), ApiQuery({
|
|
1827
|
+
name: "ids",
|
|
1828
|
+
required: true,
|
|
1829
|
+
type: "array"
|
|
1830
|
+
}), ApiOkResponse({
|
|
1831
|
+
description: `${modelClazzName} deleted successfully.`,
|
|
1832
|
+
schema: {
|
|
1833
|
+
type: "array",
|
|
1834
|
+
items: {
|
|
1835
|
+
$ref: getSchemaPath(ModelConstr)
|
|
1836
|
+
}
|
|
1837
|
+
}
|
|
1838
|
+
}), ApiNotFoundResponse({
|
|
1839
|
+
description: `No ${modelClazzName} record matches the provided identifier.`
|
|
1840
|
+
}) ];
|
|
1841
|
+
}
|
|
1842
|
+
static readDecorators(ModelConstr, modelClazzName, apiProperties, pkPath) {
|
|
1843
|
+
return [ ApiOperationFromModel(ModelConstr, "GET", pkPath), ApiParamsFromModel(apiProperties), ApiOperation({
|
|
1844
|
+
summary: `Retrieve a ${modelClazzName} record by id.`
|
|
1845
|
+
}), ApiOkResponse({
|
|
1846
|
+
description: `${modelClazzName} retrieved successfully.`,
|
|
1847
|
+
schema: {
|
|
1848
|
+
$ref: getSchemaPath(ModelConstr)
|
|
1849
|
+
}
|
|
1850
|
+
}), ApiNotFoundResponse({
|
|
1851
|
+
description: `No ${modelClazzName} record matches the provided identifier.`
|
|
1852
|
+
}) ];
|
|
1853
|
+
}
|
|
1854
|
+
static updateDecorators(ModelConstr, modelClazzName, apiProperties, pkPath) {
|
|
1855
|
+
return [ ApiOperationFromModel(ModelConstr, "PUT", pkPath), ApiParamsFromModel(apiProperties), ApiOperation({
|
|
1856
|
+
summary: `Replace an existing ${modelClazzName} record with a new payload.`
|
|
1857
|
+
}), ApiBody({
|
|
1858
|
+
description: `Payload for replacing an existing record of ${modelClazzName}`,
|
|
1859
|
+
type: DtoFor(OperationKeys.UPDATE, ModelConstr)
|
|
1860
|
+
}), ApiOkResponse({
|
|
1861
|
+
description: `${modelClazzName} updated successfully.`,
|
|
1862
|
+
schema: {
|
|
1863
|
+
$ref: getSchemaPath(ModelConstr)
|
|
1864
|
+
}
|
|
1865
|
+
}), ApiNotFoundResponse({
|
|
1866
|
+
description: `No ${modelClazzName} record matches the provided identifier.`
|
|
1867
|
+
}), ApiBadRequestResponse({
|
|
1868
|
+
description: "Payload validation failed."
|
|
1869
|
+
}) ];
|
|
1870
|
+
}
|
|
1871
|
+
static deleteDecorators(ModelConstr, modelClazzName, apiProperties, pkPath) {
|
|
1872
|
+
return [ ApiOperationFromModel(ModelConstr, "DELETE", pkPath), ApiParamsFromModel(apiProperties), ApiOperation({
|
|
1873
|
+
summary: `Delete a ${modelClazzName} record by id.`
|
|
1874
|
+
}), ApiOkResponse({
|
|
1875
|
+
description: `${modelClazzName} deleted successfully.`,
|
|
1876
|
+
schema: {
|
|
1877
|
+
$ref: getSchemaPath(ModelConstr)
|
|
1878
|
+
}
|
|
1879
|
+
}), ApiNotFoundResponse({
|
|
1880
|
+
description: `No ${modelClazzName} record matches the provided identifier.`
|
|
1881
|
+
}) ];
|
|
1882
|
+
}
|
|
1883
|
+
static statementDecorators(ModelConstr, modelClazzName) {
|
|
1884
|
+
return [ ApiOperationFromModel(ModelConstr, "GET", "statement/:method/*args"), ApiOperation({
|
|
1885
|
+
summary: `Executes a prepared statement on ${modelClazzName}.`
|
|
1886
|
+
}), ApiParam({
|
|
1887
|
+
name: "method",
|
|
1888
|
+
description: "the prepared statement to execute"
|
|
1889
|
+
}), ApiParam({
|
|
1890
|
+
name: "args",
|
|
1891
|
+
description: "concatenated list of arguments the prepared statement can accept"
|
|
1892
|
+
}), ApiQuery({
|
|
1893
|
+
name: "direction",
|
|
1894
|
+
required: true,
|
|
1895
|
+
enum: OrderDirection,
|
|
1896
|
+
description: "the sort order when applicable"
|
|
1897
|
+
}), ApiQuery({
|
|
1898
|
+
name: "limit",
|
|
1899
|
+
required: true,
|
|
1900
|
+
description: "limit or page size when applicable"
|
|
1901
|
+
}), ApiQuery({
|
|
1902
|
+
name: "offset",
|
|
1903
|
+
required: true,
|
|
1904
|
+
description: "offset or bookmark when applicable"
|
|
1905
|
+
}), ApiOkResponse({
|
|
1906
|
+
description: `${modelClazzName} listed found.`
|
|
1907
|
+
}), ApiNotFoundResponse({
|
|
1908
|
+
description: `No ${modelClazzName} record matches the provided identifier.`
|
|
1909
|
+
}) ];
|
|
1910
|
+
}
|
|
1911
|
+
static statementShortcutDecorators(ModelConstr, modelClazzName, path, statementKey) {
|
|
1912
|
+
const base = [ ApiOperationFromModel(ModelConstr, "GET", path), ApiOperation({
|
|
1913
|
+
summary: `Retrieve ${modelClazzName} records.`
|
|
1914
|
+
}), ApiOkResponse({
|
|
1915
|
+
description: `${modelClazzName} retrieved successfully.`
|
|
1916
|
+
}) ];
|
|
1917
|
+
const segments = path.split("/").filter(s => s.startsWith(":"));
|
|
1918
|
+
segments.forEach(seg => {
|
|
1919
|
+
const name = seg.replace(":", "");
|
|
1920
|
+
base.push(ApiParam({
|
|
1921
|
+
name: name,
|
|
1922
|
+
description: `The ${name} parameter`
|
|
1923
|
+
}));
|
|
1924
|
+
});
|
|
1925
|
+
if (path.startsWith("listBy/") || path.startsWith("paginateBy/") || path.startsWith("find/") || path.startsWith("page/")) {
|
|
1926
|
+
base.push(ApiQuery({
|
|
1927
|
+
name: "direction",
|
|
1928
|
+
required: true,
|
|
1929
|
+
enum: OrderDirection,
|
|
1930
|
+
description: "the sort order"
|
|
1931
|
+
}));
|
|
1932
|
+
}
|
|
1933
|
+
if (path.startsWith("paginateBy/") || path.startsWith("page/")) {
|
|
1934
|
+
base.push(ApiQuery({
|
|
1935
|
+
name: "limit",
|
|
1936
|
+
required: false,
|
|
1937
|
+
description: "page size"
|
|
1938
|
+
}), ApiQuery({
|
|
1939
|
+
name: "offset",
|
|
1940
|
+
required: false,
|
|
1941
|
+
description: "page number"
|
|
1942
|
+
}), ApiQuery({
|
|
1943
|
+
name: "bookmark",
|
|
1944
|
+
required: false,
|
|
1945
|
+
description: "bookmark for cursor pagination"
|
|
1946
|
+
}));
|
|
1947
|
+
}
|
|
1948
|
+
if (path.startsWith("findOneBy/") || path.startsWith("findBy/")) {
|
|
1949
|
+
base.push(ApiNotFoundResponse({
|
|
1950
|
+
description: `No ${modelClazzName} record matches the provided identifier.`
|
|
1951
|
+
}));
|
|
1952
|
+
}
|
|
1953
|
+
if (statementKey === PreparedStatementKeys.COUNT_OF || statementKey === PreparedStatementKeys.AVG_OF || statementKey === PreparedStatementKeys.SUM_OF) {
|
|
1954
|
+
base.push(ApiOkResponse({
|
|
1955
|
+
description: `Result for ${modelClazzName}.`,
|
|
1956
|
+
type: Number
|
|
1957
|
+
}));
|
|
1958
|
+
}
|
|
1959
|
+
if (statementKey === PreparedStatementKeys.DISTINCT_OF) {
|
|
1960
|
+
base.push(ApiOkResponse({
|
|
1961
|
+
description: `Distinct values for ${modelClazzName}.`,
|
|
1962
|
+
type: [ String ]
|
|
1963
|
+
}));
|
|
1964
|
+
}
|
|
1965
|
+
return base;
|
|
1966
|
+
}
|
|
1967
|
+
static getQueryDecorators(methodName, routePath, httpVerb, includeQueryParams = false) {
|
|
1968
|
+
const extractPathParams = p => p.split("/").filter(s => s.startsWith(":")).map(s => s.slice(1));
|
|
1969
|
+
const apiPathParams = extractPathParams(routePath).map(name => ({
|
|
1970
|
+
name: name,
|
|
1971
|
+
description: `${name} parameter for the query`,
|
|
1972
|
+
required: true,
|
|
1973
|
+
type: String
|
|
1974
|
+
}));
|
|
1975
|
+
const decorators = [ ...apiPathParams.map(p => ApiParam(p)), ApiOperation({
|
|
1976
|
+
summary: `Retrieve records using "${methodName}".`
|
|
1977
|
+
}), ApiOkResponse({
|
|
1978
|
+
description: "Result successfully retrieved."
|
|
1979
|
+
}), ApiNoContentResponse({
|
|
1980
|
+
description: "No content returned by the method."
|
|
1981
|
+
}) ];
|
|
1982
|
+
if (httpVerb === "GET" && includeQueryParams) {
|
|
1983
|
+
decorators.push(ApiQuery({
|
|
1984
|
+
name: "direction",
|
|
1985
|
+
required: false,
|
|
1986
|
+
enum: OrderDirection,
|
|
1987
|
+
description: "the sort order when applicable"
|
|
1988
|
+
}), ApiQuery({
|
|
1989
|
+
name: "limit",
|
|
1990
|
+
required: false,
|
|
1991
|
+
description: "limit or page size"
|
|
1992
|
+
}), ApiQuery({
|
|
1993
|
+
name: "offset",
|
|
1994
|
+
required: false,
|
|
1995
|
+
description: "offset or bookmark"
|
|
1996
|
+
}));
|
|
1997
|
+
}
|
|
1998
|
+
return decorators;
|
|
1999
|
+
}
|
|
2000
|
+
}
|
|
2001
|
+
|
|
2002
|
+
function getModuleFor(flavour) {
|
|
2003
|
+
var DecafModelModule_1;
|
|
2004
|
+
let DecafModelModule = class DecafModelModule {
|
|
2005
|
+
static {
|
|
2006
|
+
DecafModelModule_1 = this;
|
|
2007
|
+
}
|
|
2008
|
+
static {
|
|
2009
|
+
this.log = Logging.for(DecafModelModule_1.name).for(flavour);
|
|
2010
|
+
}
|
|
2011
|
+
static createModelServices(models) {
|
|
2012
|
+
return models.map(model => ({
|
|
2013
|
+
provide: `${model.name}Service`,
|
|
2014
|
+
useFactory: () => ModelService.forModel(model)
|
|
2015
|
+
}));
|
|
2016
|
+
}
|
|
2017
|
+
static isExposed(model, exposure) {
|
|
2018
|
+
const override = exposure?.[model.name];
|
|
2019
|
+
const value = typeof override !== "undefined" ? override : Metadata.get(model, Metadata.key(DECAF_EXPOSE));
|
|
2020
|
+
if (typeof value === "undefined") return true;
|
|
2021
|
+
if (value === true) return true;
|
|
2022
|
+
if (Array.isArray(value)) return value.includes(flavour);
|
|
2023
|
+
return false;
|
|
2024
|
+
}
|
|
2025
|
+
static forRoot(flavour, options = {}) {
|
|
2026
|
+
const log = this.log.for(this.forRoot);
|
|
2027
|
+
log.info(`Generating controllers for flavour...`);
|
|
2028
|
+
const trackedModels = Adapter.models(flavour).filter(model => this.isExposed(model, options.controllerExposure));
|
|
2029
|
+
let modelServices = [];
|
|
2030
|
+
if (options.autoServices) {
|
|
2031
|
+
log.info("Auto-services enabled. Initializing service generation.");
|
|
2032
|
+
modelServices = this.createModelServices(trackedModels);
|
|
2033
|
+
log.info(`Auto-services completed. ${modelServices.length} services initialized.`);
|
|
2034
|
+
}
|
|
2035
|
+
const globalDefaults = {};
|
|
2036
|
+
if (options.aggregations === false) {
|
|
2037
|
+
globalDefaults.allowGroupingQueries = false;
|
|
2038
|
+
}
|
|
2039
|
+
const controllers = trackedModels.map(model => FromModelController.create(model, options.controllerConfig, globalDefaults));
|
|
2040
|
+
log.info(`Generated ${controllers.length} controllers`);
|
|
2041
|
+
return {
|
|
2042
|
+
module: DecafModelModule_1,
|
|
2043
|
+
controllers: controllers,
|
|
2044
|
+
providers: [ ...modelServices ]
|
|
2045
|
+
};
|
|
2046
|
+
}
|
|
2047
|
+
};
|
|
2048
|
+
DecafModelModule = DecafModelModule_1 = __decorate([ Module({}) ], DecafModelModule);
|
|
2049
|
+
Object.assign(DecafModelModule, "name", {
|
|
2050
|
+
value: `DecafModule${flavour}`
|
|
2051
|
+
});
|
|
2052
|
+
return DecafModelModule;
|
|
2053
|
+
}
|
|
2054
|
+
|
|
2055
|
+
Decoration.for(InjectablesKeys.INJECTABLE).extend({
|
|
2056
|
+
decorator: function nestInjectable(category, cfg) {
|
|
2057
|
+
cfg = cfg || (typeof category === "object" ? Object.assign(category, DefaultInjectablesConfig) : DefaultInjectablesConfig);
|
|
2058
|
+
return Injectable({
|
|
2059
|
+
scope: cfg.singleton ? Scope.DEFAULT : Scope.REQUEST,
|
|
2060
|
+
durable: cfg.singleton ? undefined : true
|
|
2061
|
+
});
|
|
2062
|
+
}
|
|
2063
|
+
}).apply();
|
|
2064
|
+
|
|
2065
|
+
Decoration.for(InjectablesKeys.INJECT).extend({
|
|
2066
|
+
decorator: function nestInject(category, cfg) {
|
|
2067
|
+
return function innerNestInject(target, propertyKey, descriptor) {
|
|
2068
|
+
return Inject(category || target)(target, propertyKey, descriptor);
|
|
2069
|
+
};
|
|
2070
|
+
}
|
|
2071
|
+
}).apply();
|
|
2072
|
+
|
|
2073
|
+
Decoration.for(ValidationKeys.REQUIRED).extend(ApiProperty({
|
|
2074
|
+
required: true
|
|
2075
|
+
})).apply();
|
|
2076
|
+
|
|
2077
|
+
Decoration.for(ValidationKeys.MAX).extend({
|
|
2078
|
+
decorator: function maxDec(max) {
|
|
2079
|
+
return ApiProperty({
|
|
2080
|
+
maximum: max,
|
|
2081
|
+
required: false
|
|
2082
|
+
});
|
|
2083
|
+
}
|
|
2084
|
+
}).apply();
|
|
2085
|
+
|
|
2086
|
+
Decoration.for(ValidationKeys.MIN).extend({
|
|
2087
|
+
decorator: function minDec(min) {
|
|
2088
|
+
return ApiProperty({
|
|
2089
|
+
minimum: min,
|
|
2090
|
+
required: false
|
|
2091
|
+
});
|
|
2092
|
+
}
|
|
2093
|
+
}).apply();
|
|
2094
|
+
|
|
2095
|
+
Decoration.for(ValidationKeys.MAX_LENGTH).extend({
|
|
2096
|
+
decorator: function maxLengthDec(max) {
|
|
2097
|
+
return ApiProperty({
|
|
2098
|
+
maxLength: max,
|
|
2099
|
+
required: false
|
|
2100
|
+
});
|
|
2101
|
+
}
|
|
2102
|
+
}).apply();
|
|
2103
|
+
|
|
2104
|
+
Decoration.for(ValidationKeys.MIN_LENGTH).extend({
|
|
2105
|
+
decorator: function minLengthDec(min) {
|
|
2106
|
+
return ApiProperty({
|
|
2107
|
+
minLength: min,
|
|
2108
|
+
required: false
|
|
2109
|
+
});
|
|
2110
|
+
}
|
|
2111
|
+
}).apply();
|
|
2112
|
+
|
|
2113
|
+
Decoration.for(ValidationKeys.TYPE).extend({
|
|
2114
|
+
decorator: function typeDec(type) {
|
|
2115
|
+
return (target, prop) => {
|
|
2116
|
+
type = Array.isArray(type) ? type[0] : type;
|
|
2117
|
+
if (typeof type === "function" && !type.name) type = type();
|
|
2118
|
+
return ApiProperty({
|
|
2119
|
+
type: type,
|
|
2120
|
+
required: false
|
|
2121
|
+
})(target, prop);
|
|
2122
|
+
};
|
|
2123
|
+
}
|
|
2124
|
+
}).apply();
|
|
2125
|
+
|
|
2126
|
+
Decoration.for(ValidationKeys.DATE).extend({
|
|
2127
|
+
decorator: function dateDec(format) {
|
|
2128
|
+
return ApiProperty({
|
|
2129
|
+
type: String,
|
|
2130
|
+
format: "date-time",
|
|
2131
|
+
required: false
|
|
2132
|
+
});
|
|
2133
|
+
}
|
|
2134
|
+
}).apply();
|
|
2135
|
+
|
|
2136
|
+
Decoration.for(ValidationKeys.ENUM).extend({
|
|
2137
|
+
decorator: function optionDec(options) {
|
|
2138
|
+
const opts = Array.isArray(options) ? options : Object.values(options);
|
|
2139
|
+
return ApiProperty({
|
|
2140
|
+
enum: opts,
|
|
2141
|
+
required: false
|
|
2142
|
+
});
|
|
2143
|
+
}
|
|
2144
|
+
}).apply();
|
|
2145
|
+
|
|
2146
|
+
Decoration.for(ValidationKeys.PATTERN).extend({
|
|
2147
|
+
decorator: function patternDec(pat) {
|
|
2148
|
+
return ApiProperty({
|
|
2149
|
+
pattern: typeof pat === "string" ? pat : pat.source,
|
|
2150
|
+
required: false
|
|
2151
|
+
});
|
|
2152
|
+
}
|
|
2153
|
+
}).apply();
|
|
2154
|
+
|
|
2155
|
+
Decoration.for(PersistenceKeys.COLUMN).extend({
|
|
2156
|
+
decorator: function columnDec(name) {
|
|
2157
|
+
return ApiProperty({
|
|
2158
|
+
name: name,
|
|
2159
|
+
required: false
|
|
2160
|
+
});
|
|
2161
|
+
}
|
|
2162
|
+
}).apply();
|
|
2163
|
+
|
|
2164
|
+
Decoration.for(DecorationKeys.DESCRIPTION).extend({
|
|
2165
|
+
decorator: function descriptionDec(description) {
|
|
2166
|
+
return ApiProperty({
|
|
2167
|
+
description: description,
|
|
2168
|
+
required: false
|
|
2169
|
+
});
|
|
2170
|
+
}
|
|
2171
|
+
}).apply();
|
|
2172
|
+
|
|
2173
|
+
Decoration.for(PersistenceKeys.AUTH).extend({
|
|
2174
|
+
decorator: Auth
|
|
2175
|
+
}).apply();
|
|
2176
|
+
|
|
2177
|
+
class CorsError extends ForbiddenError {
|
|
2178
|
+
constructor(msg) {
|
|
2179
|
+
super(msg, CorsError.name);
|
|
2180
|
+
}
|
|
2181
|
+
}
|
|
2182
|
+
|
|
2183
|
+
class ToManyRequestsError extends BaseError {
|
|
2184
|
+
constructor(msg) {
|
|
2185
|
+
super(ToManyRequestsError.name, msg, 429);
|
|
2186
|
+
}
|
|
2187
|
+
}
|
|
2188
|
+
|
|
2189
|
+
let DecafExceptionFilter = class DecafExceptionFilter {
|
|
2190
|
+
catch(exception, host) {
|
|
2191
|
+
const ctx = host.switchToHttp();
|
|
2192
|
+
const response = ctx.getResponse();
|
|
2193
|
+
const request = ctx.getRequest();
|
|
2194
|
+
const isProduction = LoggedEnvironment.env === "production";
|
|
2195
|
+
let statusCode;
|
|
2196
|
+
if (exception instanceof NotFoundException || exception instanceof UnsupportedError) {
|
|
2197
|
+
exception = new NotAcceptableException(exception.message);
|
|
2198
|
+
statusCode = exception.getStatus();
|
|
2199
|
+
} else if (!(exception instanceof BaseError)) {
|
|
2200
|
+
if (exception.status === 429) {
|
|
2201
|
+
exception = new ToManyRequestsError(exception.message);
|
|
2202
|
+
} else {
|
|
2203
|
+
exception = new InternalError(exception.message);
|
|
2204
|
+
}
|
|
2205
|
+
}
|
|
2206
|
+
response.status(exception.code || statusCode).json({
|
|
2207
|
+
status: exception.code || statusCode,
|
|
2208
|
+
error: isProduction ? exception.name : exception.message,
|
|
2209
|
+
timestamp: (new Date).toISOString(),
|
|
2210
|
+
path: request.url,
|
|
2211
|
+
method: request.method
|
|
2212
|
+
});
|
|
2213
|
+
}
|
|
2214
|
+
};
|
|
2215
|
+
|
|
2216
|
+
DecafExceptionFilter = __decorate([ Catch() ], DecafExceptionFilter);
|
|
2217
|
+
|
|
2218
|
+
function UseDecafFilter() {
|
|
2219
|
+
return UseFilters(new DecafExceptionFilter);
|
|
2220
|
+
}
|
|
2221
|
+
|
|
2222
|
+
function UseDecafHeaders() {
|
|
2223
|
+
return UseInterceptors(DecafResponseInterceptor);
|
|
2224
|
+
}
|
|
2225
|
+
|
|
2226
|
+
const SWAGGER_UI_CONSTANTS = {
|
|
2227
|
+
title: "Swagger | OpenAPI Specification (OAS)",
|
|
2228
|
+
description: "Standardized format for describing RESTful APIs",
|
|
2229
|
+
version: "0.0.1",
|
|
2230
|
+
path: "docs",
|
|
2231
|
+
faviconFilePath: "",
|
|
2232
|
+
topbarIconFilePath: "",
|
|
2233
|
+
auth: {
|
|
2234
|
+
type: "http",
|
|
2235
|
+
scheme: "bearer",
|
|
2236
|
+
bearerFormat: "JWT",
|
|
2237
|
+
name: "Authorization",
|
|
2238
|
+
description: "Enter JWT token",
|
|
2239
|
+
in: "header"
|
|
2240
|
+
},
|
|
2241
|
+
persistAuthorization: true,
|
|
2242
|
+
topbarBgColor: "#000000"
|
|
2243
|
+
};
|
|
2244
|
+
|
|
2245
|
+
class SwaggerCustomUI {
|
|
2246
|
+
constructor(options) {
|
|
2247
|
+
this.options = {
|
|
2248
|
+
...options
|
|
2249
|
+
};
|
|
2250
|
+
}
|
|
2251
|
+
customCSS() {
|
|
2252
|
+
let css = "";
|
|
2253
|
+
if (this.options.topbarIconPath) {
|
|
2254
|
+
const img = this.b64(this.options.topbarIconPath);
|
|
2255
|
+
css += `.topbar-wrapper { content: url('data:image/png;base64,${img}'); width: 200px; height: auto; }\n`;
|
|
2256
|
+
}
|
|
2257
|
+
return css + `\n .topbar-wrapper svg { visibility: hidden; }\n .swagger-ui .topbar { background-color: ${this.options.topbarBgColor || SWAGGER_UI_CONSTANTS.topbarBgColor}; }\n `;
|
|
2258
|
+
}
|
|
2259
|
+
getCustomOptions() {
|
|
2260
|
+
const favicon = {};
|
|
2261
|
+
if (this.options.faviconPath) {
|
|
2262
|
+
favicon["customfavIcon"] = this.b64(this.options.faviconPath, true);
|
|
2263
|
+
}
|
|
2264
|
+
return {
|
|
2265
|
+
customSiteTitle: this.options.title,
|
|
2266
|
+
...favicon,
|
|
2267
|
+
customCss: this.customCSS(),
|
|
2268
|
+
swaggerOptions: {
|
|
2269
|
+
persistAuthorization: this.options.persistAuthorization
|
|
2270
|
+
}
|
|
2271
|
+
};
|
|
2272
|
+
}
|
|
2273
|
+
b64(file, img = false) {
|
|
2274
|
+
const filePath = path.join(this.options.assetsPath || "", file);
|
|
2275
|
+
const b64 = readFileSync(filePath, {
|
|
2276
|
+
encoding: "base64"
|
|
2277
|
+
});
|
|
2278
|
+
return img ? "data:image/png;base64," + b64 : b64;
|
|
2279
|
+
}
|
|
2280
|
+
}
|
|
2281
|
+
|
|
2282
|
+
class SwaggerBuilder {
|
|
2283
|
+
constructor(app, options) {
|
|
2284
|
+
this.app = app;
|
|
2285
|
+
this.options = options;
|
|
2286
|
+
}
|
|
2287
|
+
createDocument() {
|
|
2288
|
+
const description = this.options.path ? this.options.description + "" + `<br><br><a href="${this.options.openApiJsonPath}">OpenAPI JSON Spec</a> | ` + `<a href="${this.options.openApiYamlPath}">OpenAPI YAML Spec</a>` : this.options.description;
|
|
2289
|
+
const config = (new DocumentBuilder).setTitle(this.options.title).setDescription(description).setVersion(this.options.version || "0.0.1").addBearerAuth(this.options.auth || SWAGGER_UI_CONSTANTS.auth).build();
|
|
2290
|
+
return SwaggerModule.createDocument(this.app, config, {
|
|
2291
|
+
extraModels: this.options.extraModels || []
|
|
2292
|
+
});
|
|
2293
|
+
}
|
|
2294
|
+
registerOpenApiRoute(path, contentType, bodyFactory) {
|
|
2295
|
+
if (!path) return;
|
|
2296
|
+
const httpAdapter = this.app.getHttpAdapter();
|
|
2297
|
+
path = path.startsWith("/") ? path : `/${path}`;
|
|
2298
|
+
httpAdapter.get(path, (_req, res) => {
|
|
2299
|
+
httpAdapter.reply(res, bodyFactory(), 200, {
|
|
2300
|
+
"Content-Type": contentType
|
|
2301
|
+
});
|
|
2302
|
+
});
|
|
2303
|
+
}
|
|
2304
|
+
setupSwagger() {
|
|
2305
|
+
const document = this.createDocument();
|
|
2306
|
+
const swaggerUI = new SwaggerCustomUI({
|
|
2307
|
+
title: this.options.title,
|
|
2308
|
+
path: this.options.path || SWAGGER_UI_CONSTANTS.path,
|
|
2309
|
+
persistAuthorization: this.options.persistAuthorization ?? true,
|
|
2310
|
+
assetsPath: this.options.assetsPath,
|
|
2311
|
+
faviconPath: this.options.faviconFilePath,
|
|
2312
|
+
topbarIconPath: this.options.topbarIconFilePath,
|
|
2313
|
+
topbarBgColor: this.options.topbarBgColor
|
|
2314
|
+
});
|
|
2315
|
+
SwaggerModule.setup(this.options.path || SWAGGER_UI_CONSTANTS.path, this.app, document, {
|
|
2316
|
+
...swaggerUI.getCustomOptions(),
|
|
2317
|
+
jsonDocumentUrl: this.options.openApiJsonPath ? `${this.options.openApiJsonPath}` : undefined,
|
|
2318
|
+
yamlDocumentUrl: this.options.openApiYamlPath ? `${this.options.openApiYamlPath}` : undefined
|
|
2319
|
+
});
|
|
2320
|
+
this.registerOpenApiRoute(this.options.openApiJsonPath, "application/json", () => document);
|
|
2321
|
+
this.registerOpenApiRoute(this.options.openApiYamlPath, "application/x-yaml", () => YAML.stringify(document));
|
|
2322
|
+
}
|
|
2323
|
+
}
|
|
2324
|
+
|
|
2325
|
+
class NestBootstraper {
|
|
2326
|
+
static get logger() {
|
|
2327
|
+
if (!this._logger) {
|
|
2328
|
+
this._logger = new Logger("NestBootstrap");
|
|
2329
|
+
}
|
|
2330
|
+
return this._logger;
|
|
2331
|
+
}
|
|
2332
|
+
static initialize(app) {
|
|
2333
|
+
this.app = app;
|
|
2334
|
+
return this;
|
|
2335
|
+
}
|
|
2336
|
+
static enableLogger(customLogger) {
|
|
2337
|
+
this._logger = customLogger || new Logger("NestBootstrap");
|
|
2338
|
+
this.app.useLogger(this._logger);
|
|
2339
|
+
return this;
|
|
2340
|
+
}
|
|
2341
|
+
static enableCors(origins = [], allowMethods = [ "GET", "POST", "PUT", "DELETE" ]) {
|
|
2342
|
+
const allowedOrigins = origins === "*" ? "*" : origins.map(o => o.trim().toLowerCase());
|
|
2343
|
+
const corsOptions = {
|
|
2344
|
+
origin: (origin, callback) => {
|
|
2345
|
+
if (!origin) return callback(null, true);
|
|
2346
|
+
if (allowedOrigins === "*" || Array.isArray(allowedOrigins) && allowedOrigins.includes(origin.toLowerCase())) {
|
|
2347
|
+
return callback(null, true);
|
|
2348
|
+
}
|
|
2349
|
+
callback(new CorsError(`Origin ${origin} not allowed`));
|
|
2350
|
+
},
|
|
2351
|
+
credentials: true,
|
|
2352
|
+
methods: allowMethods.join(",")
|
|
2353
|
+
};
|
|
2354
|
+
this.app.enableCors(corsOptions);
|
|
2355
|
+
return this;
|
|
2356
|
+
}
|
|
2357
|
+
static useHelmet(options) {
|
|
2358
|
+
try {
|
|
2359
|
+
const helmet = require("helmet");
|
|
2360
|
+
this.app.use(helmet(options));
|
|
2361
|
+
this.logger.log("Helmet middleware enabled successfully.");
|
|
2362
|
+
} catch (e) {
|
|
2363
|
+
this.logger.warn("Helmet not installed. Skipping middleware.");
|
|
2364
|
+
}
|
|
2365
|
+
return this;
|
|
2366
|
+
}
|
|
2367
|
+
static setupSwagger(options) {
|
|
2368
|
+
const swagger = new SwaggerBuilder(this.app, {
|
|
2369
|
+
title: options.title,
|
|
2370
|
+
description: options.description,
|
|
2371
|
+
version: options.version,
|
|
2372
|
+
path: options.path || "api",
|
|
2373
|
+
persistAuthorization: options.persistAuthorization ?? true,
|
|
2374
|
+
assetsPath: options.assetsPath,
|
|
2375
|
+
faviconFilePath: options.faviconPath,
|
|
2376
|
+
topbarIconFilePath: options.topbarIconPath,
|
|
2377
|
+
topbarBgColor: options.topbarBgColor,
|
|
2378
|
+
openApiJsonPath: options.openApiJsonPath,
|
|
2379
|
+
openApiYamlPath: options.openApiYamlPath
|
|
2380
|
+
});
|
|
2381
|
+
swagger.setupSwagger();
|
|
2382
|
+
return this;
|
|
2383
|
+
}
|
|
2384
|
+
static useGlobalPipes(...pipes) {
|
|
2385
|
+
if (pipes.length > 0) this.app.useGlobalPipes(...pipes);
|
|
2386
|
+
return this;
|
|
2387
|
+
}
|
|
2388
|
+
static useGlobalFilters(...filters) {
|
|
2389
|
+
this.app.useGlobalFilters(...filters.length > 0 ? filters : [ new DecafExceptionFilter ]);
|
|
2390
|
+
return this;
|
|
2391
|
+
}
|
|
2392
|
+
static useGlobalInterceptors(...interceptors) {
|
|
2393
|
+
if (interceptors.length > 0) this.app.useGlobalInterceptors(...interceptors);
|
|
2394
|
+
return this;
|
|
2395
|
+
}
|
|
2396
|
+
static async start(port = Number(process.env.PORT) || 3e3, host = undefined, log = true) {
|
|
2397
|
+
this.app.listen(port, host).then(async () => {
|
|
2398
|
+
if (log) {
|
|
2399
|
+
const url = await this.app.getUrl();
|
|
2400
|
+
this.logger.log(`🚀 Application is running at: ${url}`);
|
|
2401
|
+
}
|
|
2402
|
+
});
|
|
2403
|
+
}
|
|
2404
|
+
}
|
|
2405
|
+
|
|
2406
|
+
const pendingProviders = new Map;
|
|
2407
|
+
|
|
2408
|
+
function getRegisteredDecafProviders() {
|
|
2409
|
+
return Array.from(pendingProviders.values());
|
|
2410
|
+
}
|
|
2411
|
+
|
|
2412
|
+
function registerProvider(token, useFactory) {
|
|
2413
|
+
if (pendingProviders.has(token)) return;
|
|
2414
|
+
pendingProviders.set(token, {
|
|
2415
|
+
provide: token,
|
|
2416
|
+
useFactory: useFactory
|
|
2417
|
+
});
|
|
2418
|
+
}
|
|
2419
|
+
|
|
2420
|
+
function isModelConstructor(value) {
|
|
2421
|
+
return typeof value === "function" && value.prototype instanceof Model;
|
|
2422
|
+
}
|
|
2423
|
+
|
|
2424
|
+
function modelServiceToken(model) {
|
|
2425
|
+
return `${model.name}Service`;
|
|
2426
|
+
}
|
|
2427
|
+
|
|
2428
|
+
function modelRepositoryToken(model, flavour) {
|
|
2429
|
+
return flavour ? `${model.name}Repository@${flavour}` : `${model.name}Repository`;
|
|
2430
|
+
}
|
|
2431
|
+
|
|
2432
|
+
function Service(key) {
|
|
2433
|
+
return (target, propertyKey, parameterIndex) => {
|
|
2434
|
+
let resolved = key;
|
|
2435
|
+
if (typeof resolved === "undefined") {
|
|
2436
|
+
const paramTypes = Reflect.getMetadata("design:paramtypes", target) || [];
|
|
2437
|
+
resolved = paramTypes[parameterIndex];
|
|
2438
|
+
}
|
|
2439
|
+
if (typeof resolved === "undefined") {
|
|
2440
|
+
throw new Error(`@Service() could not determine an injection type for parameter ${parameterIndex} of ${target.name}. Provide an explicit argument, e.g. @Service(SomeService).`);
|
|
2441
|
+
}
|
|
2442
|
+
const asModel = typeof resolved !== "string" && isModelConstructor(resolved);
|
|
2443
|
+
const token = asModel ? modelServiceToken(resolved) : injectableServiceKey(resolved);
|
|
2444
|
+
registerProvider(token, () => {
|
|
2445
|
+
if (asModel) return ModelService.forModel(resolved);
|
|
2446
|
+
return typeof resolved === "string" ? Service$1.get(resolved) : Service$1.get(resolved);
|
|
2447
|
+
});
|
|
2448
|
+
return Inject(token)(target, propertyKey, parameterIndex);
|
|
2449
|
+
};
|
|
2450
|
+
}
|
|
2451
|
+
|
|
2452
|
+
function Repository(model, flavour) {
|
|
2453
|
+
return (target, propertyKey, parameterIndex) => {
|
|
2454
|
+
const token = modelRepositoryToken(model, flavour);
|
|
2455
|
+
registerProvider(token, () => Repository$1.forModel(model, flavour));
|
|
2456
|
+
return Inject(token)(target, propertyKey, parameterIndex);
|
|
2457
|
+
};
|
|
2458
|
+
}
|
|
2459
|
+
|
|
2460
|
+
var DecafCoreModule_1;
|
|
2461
|
+
|
|
2462
|
+
let DecafCoreModule = class DecafCoreModule {
|
|
2463
|
+
static {
|
|
2464
|
+
DecafCoreModule_1 = this;
|
|
2465
|
+
}
|
|
2466
|
+
static get persistence() {
|
|
2467
|
+
if (!this._persistence) throw new InternalError("Persistence service not initialized");
|
|
2468
|
+
return this._persistence;
|
|
2469
|
+
}
|
|
2470
|
+
static get log() {
|
|
2471
|
+
if (!this._logger) this._logger = Logging.for(DecafCoreModule_1);
|
|
2472
|
+
return this._logger;
|
|
2473
|
+
}
|
|
2474
|
+
constructor(options, moduleRef) {
|
|
2475
|
+
this.options = options;
|
|
2476
|
+
this.moduleRef = moduleRef;
|
|
2477
|
+
}
|
|
2478
|
+
static forRoot(options) {
|
|
2479
|
+
const log = this.log.for(this.forRoot);
|
|
2480
|
+
const decafProviders = getRegisteredDecafProviders();
|
|
2481
|
+
return {
|
|
2482
|
+
module: DecafCoreModule_1,
|
|
2483
|
+
providers: [ {
|
|
2484
|
+
provide: DECAF_MODULE_OPTIONS,
|
|
2485
|
+
useValue: options
|
|
2486
|
+
}, {
|
|
2487
|
+
provide: DECAF_ADAPTER_ID,
|
|
2488
|
+
useValue: this.persistence?.client
|
|
2489
|
+
}, {
|
|
2490
|
+
provide: DECAF_HANDLERS,
|
|
2491
|
+
useFactory: () => options.handlers?.map(H => {
|
|
2492
|
+
log.info(`Registered request handler: ${H.name}`);
|
|
2493
|
+
return new H;
|
|
2494
|
+
}) ?? []
|
|
2495
|
+
}, DecafRequestContext, DecafHandlerExecutor, {
|
|
2496
|
+
provide: APP_INTERCEPTOR,
|
|
2497
|
+
useClass: DecafRequestHandlerInterceptor
|
|
2498
|
+
}, ...decafProviders ],
|
|
2499
|
+
exports: [ DECAF_MODULE_OPTIONS, DECAF_ADAPTER_ID, DECAF_HANDLERS, DecafRequestContext, DecafHandlerExecutor, ...decafProviders.map(provider => provider.provide) ]
|
|
2500
|
+
};
|
|
2501
|
+
}
|
|
2502
|
+
static async bootPersistence(options) {
|
|
2503
|
+
const log = this.log.for(this.bootPersistence);
|
|
2504
|
+
if (!this._persistence) {
|
|
2505
|
+
const trimmed = options.conf.map(([contr, cfg, ...args]) => {
|
|
2506
|
+
const possible = args.pop();
|
|
2507
|
+
if (!possible) return [ contr, cfg ];
|
|
2508
|
+
return [ contr, cfg, ...args ];
|
|
2509
|
+
});
|
|
2510
|
+
this._persistence = new PersistenceService;
|
|
2511
|
+
await this._persistence.boot(trimmed);
|
|
2512
|
+
const clients = this._persistence.client;
|
|
2513
|
+
for (let i = 0; i < clients.length; i++) {
|
|
2514
|
+
const c = options.conf[i];
|
|
2515
|
+
const possibleTransf = c.slice(2, c.length);
|
|
2516
|
+
let transformer = possibleTransf.pop();
|
|
2517
|
+
if (!transformer || !transformer.from) {
|
|
2518
|
+
const contr = Adapter.transformerFor(clients[i].flavour);
|
|
2519
|
+
if (!contr) throw new InternalError(`No transformer found for flavour ${clients[i].flavour}. you should either @requestToContextTransformer or provide a transformer in the config`);
|
|
2520
|
+
try {
|
|
2521
|
+
transformer = contr.from ? contr : new contr;
|
|
2522
|
+
} catch (e) {
|
|
2523
|
+
throw new InternalError(`Failed to boot transformer for ${clients[i].flavour}: ${e}`);
|
|
2524
|
+
}
|
|
2525
|
+
}
|
|
2526
|
+
requestToContextTransformer(clients[i].flavour)(transformer);
|
|
2527
|
+
}
|
|
2528
|
+
log.info("persistence layer created successfully!");
|
|
2529
|
+
if (options.initialization) {
|
|
2530
|
+
try {
|
|
2531
|
+
await options.initialization();
|
|
2532
|
+
} catch (e) {
|
|
2533
|
+
throw new InternalError(`Failed to initialize application: ${e}`);
|
|
2534
|
+
}
|
|
2535
|
+
}
|
|
2536
|
+
}
|
|
2537
|
+
return this.persistence.client;
|
|
2538
|
+
}
|
|
2539
|
+
async onApplicationShutdown() {
|
|
2540
|
+
const log = DecafCoreModule_1.log.for(this.onApplicationShutdown);
|
|
2541
|
+
const adapters = this.moduleRef.get(DECAF_ADAPTER_ID);
|
|
2542
|
+
for (const adapter of adapters) try {
|
|
2543
|
+
if (adapter) {
|
|
2544
|
+
log.info(`Shutting down ${adapter.toString()}`);
|
|
2545
|
+
await adapter.shutdown();
|
|
2546
|
+
}
|
|
2547
|
+
} catch (e) {
|
|
2548
|
+
log.error(`Failed to shutdown application`, e);
|
|
2549
|
+
}
|
|
2550
|
+
try {
|
|
2551
|
+
await Service$1.shutdown();
|
|
2552
|
+
} catch (e) {
|
|
2553
|
+
log.error(`Failed to shutdown services`, e);
|
|
2554
|
+
}
|
|
2555
|
+
}
|
|
2556
|
+
};
|
|
2557
|
+
|
|
2558
|
+
DecafCoreModule = DecafCoreModule_1 = __decorate([ Global(), Module({}), __param(0, Inject(DECAF_MODULE_OPTIONS)), __metadata("design:paramtypes", [ Object, ModuleRef ]) ], DecafCoreModule);
|
|
2559
|
+
|
|
2560
|
+
const LISTENING_ADAPTERS_FLAVOURS = Symbol("LISTENING_ADAPTERS_FLAVOURS");
|
|
2561
|
+
|
|
2562
|
+
function normalizeEventResponse(args) {
|
|
2563
|
+
const [modelConstr, operation, id, payload] = args;
|
|
2564
|
+
const modelName = modelConstr?.name ?? modelConstr;
|
|
2565
|
+
const serializedPayload = Array.isArray(payload) ? payload.map(e => {
|
|
2566
|
+
try {
|
|
2567
|
+
if (typeof e.serialize === "function") return e.serialize();
|
|
2568
|
+
console.warn(`Payload item for ${modelName} does not have serialize method and is an ${typeof e}, attempting to stringify directly. Item: ${e}`);
|
|
2569
|
+
return typeof e === "string" ? e : JSON.stringify(e);
|
|
2570
|
+
} catch (err) {
|
|
2571
|
+
console.warn(`Failed to serialize payload for ${modelName}: ${err}`);
|
|
2572
|
+
return undefined;
|
|
2573
|
+
}
|
|
2574
|
+
}) : payload && typeof payload.serialize === "function" ? payload.serialize() : typeof payload === "string" ? payload : JSON.stringify(payload);
|
|
2575
|
+
console.debug(`Normalized event response for model ${modelName}, operation ${operation}, id ${id}:`, serializedPayload);
|
|
2576
|
+
return [ modelName, operation, id, serializedPayload ];
|
|
2577
|
+
}
|
|
2578
|
+
|
|
2579
|
+
var EventsController_1;
|
|
2580
|
+
|
|
2581
|
+
let EventsController = EventsController_1 = class EventsController extends DecafController {
|
|
2582
|
+
constructor(clientContext, flavours) {
|
|
2583
|
+
super(clientContext, EventsController_1.name);
|
|
2584
|
+
this.adapters = flavours.map(flavour => Adapter.get(flavour));
|
|
2585
|
+
}
|
|
2586
|
+
listen() {
|
|
2587
|
+
const logger = Logging.for(EventsController_1.name);
|
|
2588
|
+
const events$ = new Observable(observer => {
|
|
2589
|
+
const observerId = `B-${Math.random().toString(36).slice(2, 8)}`.toUpperCase();
|
|
2590
|
+
logger.info(`Creating SSE observer: ${observerId} for client ${this.clientContext.uuid}`);
|
|
2591
|
+
const cb = new class {
|
|
2592
|
+
constructor() {
|
|
2593
|
+
this.observerId = observerId;
|
|
2594
|
+
}
|
|
2595
|
+
refresh(...args) {
|
|
2596
|
+
logger.debug(`SSE observer ${this.observerId} received refresh event`);
|
|
2597
|
+
return Promise.resolve().then(() => {
|
|
2598
|
+
const data = normalizeEventResponse(args);
|
|
2599
|
+
observer.next({
|
|
2600
|
+
type: "message",
|
|
2601
|
+
data: data
|
|
2602
|
+
});
|
|
2603
|
+
logger.debug(`SSE observer ${this.observerId} event pushed to client`);
|
|
2604
|
+
});
|
|
2605
|
+
}
|
|
2606
|
+
};
|
|
2607
|
+
logger.verbose(`Registering observer ${observerId} across ${this.adapters.length} adapter(s)`);
|
|
2608
|
+
for (const adapter of this.adapters) {
|
|
2609
|
+
const adapterName = adapter?.constructor?.name ?? "UnknownAdapter";
|
|
2610
|
+
try {
|
|
2611
|
+
logger.debug(`Registering observer ${observerId} in adapter ${adapterName}`);
|
|
2612
|
+
adapter.observe(cb);
|
|
2613
|
+
} catch (e) {
|
|
2614
|
+
logger.debug(`Failed to register observer ${observerId} in adapter ${adapterName}: ${e?.message || e}`);
|
|
2615
|
+
logger.error(e);
|
|
2616
|
+
}
|
|
2617
|
+
}
|
|
2618
|
+
return () => {
|
|
2619
|
+
logger.debug(`Cleaning up SSE observer ${observerId}`);
|
|
2620
|
+
for (const adapter of this.adapters) {
|
|
2621
|
+
const adapterName = adapter?.constructor?.name ?? "UnknownAdapter";
|
|
2622
|
+
try {
|
|
2623
|
+
logger.debug(`Unregistering observer ${observerId} from adapter ${adapterName}`);
|
|
2624
|
+
adapter.unObserve(cb);
|
|
2625
|
+
} catch (e) {
|
|
2626
|
+
logger.debug(`Failed during cleanup of observer ${observerId} in adapter ${adapterName}: ${e?.message || e}`);
|
|
2627
|
+
logger.error(e);
|
|
2628
|
+
}
|
|
2629
|
+
}
|
|
2630
|
+
};
|
|
2631
|
+
});
|
|
2632
|
+
const HEARTBEAT_INTERVAL_MS = 15e3;
|
|
2633
|
+
const heartbeat$ = interval(HEARTBEAT_INTERVAL_MS).pipe(tap$1(() => {
|
|
2634
|
+
logger.debug("Sending heartbeat");
|
|
2635
|
+
}), map(() => ({
|
|
2636
|
+
type: "heartbeat",
|
|
2637
|
+
data: {
|
|
2638
|
+
ts: (new Date).toISOString()
|
|
2639
|
+
}
|
|
2640
|
+
})));
|
|
2641
|
+
return merge(events$, heartbeat$);
|
|
2642
|
+
}
|
|
2643
|
+
listenForModel(model) {
|
|
2644
|
+
const logger = Logging.for(EventsController_1.name);
|
|
2645
|
+
return new Observable(observer => {
|
|
2646
|
+
const cb = new class {
|
|
2647
|
+
refresh(...args) {
|
|
2648
|
+
return Promise.resolve().then(() => {
|
|
2649
|
+
observer.next({
|
|
2650
|
+
data: args
|
|
2651
|
+
});
|
|
2652
|
+
});
|
|
2653
|
+
}
|
|
2654
|
+
};
|
|
2655
|
+
try {
|
|
2656
|
+
for (const adapter of this.adapters) {
|
|
2657
|
+
adapter.observe(cb);
|
|
2658
|
+
}
|
|
2659
|
+
} catch (e) {
|
|
2660
|
+
observer.error(`Failed to observe event: ${e.message || e}`);
|
|
2661
|
+
}
|
|
2662
|
+
return () => {
|
|
2663
|
+
try {
|
|
2664
|
+
for (const adapter of this.adapters) {
|
|
2665
|
+
adapter.unObserve(cb);
|
|
2666
|
+
}
|
|
2667
|
+
} catch (e) {
|
|
2668
|
+
logger.error(e);
|
|
2669
|
+
}
|
|
2670
|
+
};
|
|
2671
|
+
});
|
|
2672
|
+
}
|
|
2673
|
+
};
|
|
2674
|
+
|
|
2675
|
+
__decorate([ Sse(), __metadata("design:type", Function), __metadata("design:paramtypes", []), __metadata("design:returntype", Observable) ], EventsController.prototype, "listen", null);
|
|
2676
|
+
|
|
2677
|
+
__decorate([ Sse("/:model"), __param(0, Query("model")), __metadata("design:type", Function), __metadata("design:paramtypes", [ String ]), __metadata("design:returntype", Observable) ], EventsController.prototype, "listenForModel", null);
|
|
2678
|
+
|
|
2679
|
+
EventsController = EventsController_1 = __decorate([ Controller(), __param(1, Inject(LISTENING_ADAPTERS_FLAVOURS)), __metadata("design:paramtypes", [ DecafRequestContext, Array ]) ], EventsController);
|
|
2680
|
+
|
|
2681
|
+
var DecafStreamModule_1;
|
|
2682
|
+
|
|
2683
|
+
let DecafStreamModule = DecafStreamModule_1 = class DecafStreamModule {
|
|
2684
|
+
static forFlavours(flavours, path = "events") {
|
|
2685
|
+
return {
|
|
2686
|
+
module: DecafStreamModule_1,
|
|
2687
|
+
controllers: [ EventsController ],
|
|
2688
|
+
imports: [ RouterModule.register([ {
|
|
2689
|
+
path: path.replace(/^\//, ""),
|
|
2690
|
+
module: DecafStreamModule_1
|
|
2691
|
+
} ]) ],
|
|
2692
|
+
providers: [ DecafRequestContext, {
|
|
2693
|
+
provide: LISTENING_ADAPTERS_FLAVOURS,
|
|
2694
|
+
useValue: flavours ?? []
|
|
2695
|
+
} ]
|
|
2696
|
+
};
|
|
2697
|
+
}
|
|
2698
|
+
};
|
|
2699
|
+
|
|
2700
|
+
DecafStreamModule = DecafStreamModule_1 = __decorate([ Module({}) ], DecafStreamModule);
|
|
2701
|
+
|
|
2702
|
+
var DecafModule_1;
|
|
2703
|
+
|
|
2704
|
+
let DecafModule = DecafModule_1 = class DecafModule {
|
|
2705
|
+
static async forRootAsync(options) {
|
|
2706
|
+
const {autoControllers: autoControllers, autoServices: autoServices} = options;
|
|
2707
|
+
const adapters = await DecafCoreModule.bootPersistence(options);
|
|
2708
|
+
const flavours = adapters.map(adapter => adapter.flavour);
|
|
2709
|
+
const imports = [ DecafCoreModule.forRoot(options) ];
|
|
2710
|
+
if (autoControllers) {
|
|
2711
|
+
flavours.forEach(flavour => {
|
|
2712
|
+
imports.push(getModuleFor(flavour).forRoot(flavour, {
|
|
2713
|
+
autoServices: autoServices,
|
|
2714
|
+
controllerExposure: options.controllerExposure,
|
|
2715
|
+
controllerConfig: options.controllerConfig,
|
|
2716
|
+
aggregations: options.aggregations
|
|
2717
|
+
}));
|
|
2718
|
+
});
|
|
2719
|
+
}
|
|
2720
|
+
if (options.observerOptions?.enableObserverEvents) {
|
|
2721
|
+
imports.push(DecafStreamModule.forFlavours(options.observerOptions.observerFlavours || flavours));
|
|
2722
|
+
}
|
|
2723
|
+
return {
|
|
2724
|
+
module: DecafModule_1,
|
|
2725
|
+
imports: imports
|
|
2726
|
+
};
|
|
2727
|
+
}
|
|
2728
|
+
};
|
|
2729
|
+
|
|
2730
|
+
DecafModule = DecafModule_1 = __decorate([ Module({}) ], DecafModule);
|
|
2731
|
+
|
|
2732
|
+
async function runMigrations() {}
|
|
2733
|
+
|
|
2734
|
+
function repoForModel(model) {
|
|
2735
|
+
const m = Model.get(model);
|
|
2736
|
+
if (!m) throw new InternalError(`Failed to find repository for ${model}`);
|
|
2737
|
+
const repo = Repository$1.forModel(m);
|
|
2738
|
+
return repo;
|
|
2739
|
+
}
|
|
2740
|
+
|
|
2741
|
+
const VERSION = "0.11.2-refactor.2";
|
|
2742
|
+
|
|
2743
|
+
const COMMIT = "85f1cec";
|
|
2744
|
+
|
|
2745
|
+
const FULL_VERSION = "0.11.2-refactor.2-85f1cec";
|
|
2746
|
+
|
|
2747
|
+
const PACKAGE_NAME = "@decaf-ts/for-nest";
|
|
2748
|
+
|
|
2749
|
+
Metadata.allowReregistration(true);
|
|
2750
|
+
|
|
2751
|
+
Metadata.registerLibrary(PACKAGE_NAME, VERSION);
|
|
2752
|
+
|
|
2753
|
+
Metadata.allowReregistration(false);
|
|
2754
|
+
|
|
2755
|
+
export { AUTH_HANDLER, AUTH_META_KEY, ApiOperationFromModel, ApiParamsFromModel, ApiProperty, Auth, AuthInterceptor, BulkApiOperationFromModel, COMMIT, CorsError, DECAF_ADAPTER_ID, DECAF_CONTEXT_KEY, DECAF_CONTROLLER_CONFIG, DECAF_EXPOSE, DECAF_HANDLERS, DECAF_MODULE_OPTIONS, DECAF_ROUTE, DECAF_TASK_SERVICE_ID, DECORATORS, DECORATORS_PREFIX, DecafAuthHandler, DecafAuthModule, DecafBody, DecafController, DecafCoreModule, DecafExceptionFilter, DecafHandlerExecutor, DecafModelController, DecafModule, DecafParams, DecafRequestContext, DecafRequestHandlerInterceptor, DecafResponseInterceptor, DecafRoleAuthHandler, DecafStreamModule, DtoFor, EventsController, FULL_VERSION, FromModelController, IS_PUBLIC_KEY, NestBootstraper, PACKAGE_NAME, Public, REQUIRED_ROLES_KEY, Repository, RequireRoles, SKIP_MODEL_ROLES_KEY, Service, SwaggerBuilder, UseDecafFilter, UseDecafHeaders, VERSION, applyApiDecorators, controllerConfig, createApiPropertyDecorator, createPropertyDecorator, createRouteHandler, defineRouteMethod, expose, getApiDecorators, getEnumType, getEnumValues, getModuleFor, getRegisteredDecafProviders, isUndefined, repoForModel, resolvePersistenceMethod, runMigrations };
|
|
2756
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm9yLW5lc3QuanMiLCJzb3VyY2VzIjpbIi4uL3NyYy9vdmVycmlkZXMvY29uc3RhbnRzLnRzIiwiLi4vc3JjL292ZXJyaWRlcy9oZWxwZXJzLnRzIiwiLi4vc3JjL292ZXJyaWRlcy9kZWNvcmF0aW9uLnRzIiwiLi4vc3JjL2RlY2FmLW1vZGVsL2RlY29yYXRvcnMvQXBpT3BlcmF0aW9uRnJvbU1vZGVsLnRzIiwiLi4vc3JjL2RlY2FmLW1vZGVsL2RlY29yYXRvcnMvQXBpUGFyYW1zRnJvbU1vZGVsLnRzIiwiLi4vc3JjL2RlY2FmLW1vZGVsL2RlY29yYXRvcnMvRGVjYWZCb2R5LnRzIiwiLi4vc3JjL2RlY2FmLW1vZGVsL2RlY29yYXRvcnMvRGVjYWZQYXJhbXMudHMiLCIuLi9zcmMvY29uc3RhbnRzLnRzIiwiLi4vc3JjL2RlY2FmLW1vZGVsL2RlY29yYXRvcnMvZXhwb3NlLnRzIiwiLi4vc3JjL2RlY2FmLW1vZGVsL2RlY29yYXRvcnMvY29udHJvbGxlci1jb25maWcudHMiLCIuLi9zcmMvYXV0aC9jb25zdGFudHMudHMiLCIuLi9zcmMvcmVxdWVzdC9EZWNhZlJlcXVlc3RDb250ZXh0LnRzIiwiLi4vc3JjL2F1dGgvQXV0aEludGVyY2VwdG9yLnRzIiwiLi4vc3JjL2F1dGgvZGVjb3JhdG9ycy50cyIsIi4uL3NyYy9kZWNhZi1tb2RlbC9kZWNvcmF0b3JzL3V0aWxzLnRzIiwiLi4vc3JjL2RlY2FmLW1vZGVsL3V0aWxzLnRzIiwiLi4vc3JjL2F1dGgvRGVjYWZBdXRoSGFuZGxlci50cyIsIi4uL3NyYy9vdmVycmlkZXMvb3ZlcnJpZGVzLnRzIiwiLi4vc3JjL292ZXJyaWRlcy9Nb2RlbEJ1aWxkZXJFeHRlbnNpb25zLnRzIiwiLi4vc3JjL2ludGVyY2VwdG9ycy9EZWNhZlJlcXVlc3RIYW5kbGVySW50ZXJjZXB0b3IudHMiLCIuLi9zcmMvYXV0aC9EZWNhZkF1dGhNb2R1bGUudHMiLCIuLi9zcmMvcmVxdWVzdC9EZWNhZkhhbmRsZXJFeGVjdXRvci50cyIsIi4uL3NyYy9yZXF1ZXN0L0RlY2FmUmVzcG9uc2VJbnRlcmNlcHRvci50cyIsIi4uL3NyYy9jb250cm9sbGVycy50cyIsIi4uL3NyYy9mYWN0b3J5L29wZW5hcGkvRHRvQnVpbGRlci50cyIsIi4uL3NyYy9kZWNhZi1tb2RlbC9Gcm9tTW9kZWxDb250cm9sbGVyLnRzIiwiLi4vc3JjL2RlY2FmLW1vZGVsL0RlY2FmTW9kZWxNb2R1bGUudHMiLCIuLi9zcmMvZGVjb3JhdGlvbi50cyIsIi4uL3NyYy9mYWN0b3J5L2Vycm9ycy9jb3JzLnRzIiwiLi4vc3JjL2ZhY3RvcnkvZXJyb3JzL3Rocm90dGxpbmcudHMiLCIuLi9zcmMvZmFjdG9yeS9leGNlcHRpb25zL0RlY2FmRXJyb3JGaWx0ZXIudHMiLCIuLi9zcmMvZmFjdG9yeS9leGNlcHRpb25zL2RlY29yYXRvcnMudHMiLCIuLi9zcmMvZmFjdG9yeS9vcGVuYXBpL2NvbnN0YW50cy50cyIsIi4uL3NyYy9mYWN0b3J5L29wZW5hcGkvU3dhZ2dlckN1c3RvbVVJLnRzIiwiLi4vc3JjL2ZhY3Rvcnkvb3BlbmFwaS9Td2FnZ2VyQnVpbGRlci50cyIsIi4uL3NyYy9mYWN0b3J5L05lc3RCb290c3RyYXBlci50cyIsIi4uL3NyYy9kZWNvcmF0b3JzLnRzIiwiLi4vc3JjL2NvcmUtbW9kdWxlLnRzIiwiLi4vc3JjL2V2ZW50cy1tb2R1bGUvY29uc3RhbnQudHMiLCIuLi9zcmMvZXZlbnRzLW1vZHVsZS91dGlscy50cyIsIi4uL3NyYy9ldmVudHMtbW9kdWxlL0V2ZW50c0NvbnRyb2xsZXIudHMiLCIuLi9zcmMvZXZlbnRzLW1vZHVsZS9EZWNhZlN0cmVhbU1vZHVsZS50cyIsIi4uL3NyYy9tb2R1bGUudHMiLCIuLi9zcmMvdXRpbHMudHMiLCIuLi9zcmMvaW5kZXgudHMiXSwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0IGNvbnN0IERFQ09SQVRPUlNfUFJFRklYID0gXCJzd2FnZ2VyXCI7XG5leHBvcnQgY29uc3QgREVDT1JBVE9SUyA9IHtcbiAgQVBJX09QRVJBVElPTjogYCR7REVDT1JBVE9SU19QUkVGSVh9L2FwaU9wZXJhdGlvbmAsXG4gIEFQSV9SRVNQT05TRTogYCR7REVDT1JBVE9SU19QUkVGSVh9L2FwaVJlc3BvbnNlYCxcbiAgQVBJX1BST0RVQ0VTOiBgJHtERUNPUkFUT1JTX1BSRUZJWH0vYXBpUHJvZHVjZXNgLFxuICBBUElfQ09OU1VNRVM6IGAke0RFQ09SQVRPUlNfUFJFRklYfS9hcGlDb25zdW1lc2AsXG4gIEFQSV9UQUdTOiBgJHtERUNPUkFUT1JTX1BSRUZJWH0vYXBpVXNlVGFnc2AsXG4gIEFQSV9DQUxMQkFDS1M6IGAke0RFQ09SQVRPUlNfUFJFRklYfS9hcGlDYWxsYmFja3NgLFxuICBBUElfUEFSQU1FVEVSUzogYCR7REVDT1JBVE9SU19QUkVGSVh9L2FwaVBhcmFtZXRlcnNgLFxuICBBUElfSEVBREVSUzogYCR7REVDT1JBVE9SU19QUkVGSVh9L2FwaUhlYWRlcnNgLFxuICBBUElfTU9ERUxfUFJPUEVSVElFUzogYCR7REVDT1JBVE9SU19QUkVGSVh9L2FwaU1vZGVsUHJvcGVydGllc2AsXG4gIEFQSV9NT0RFTF9QUk9QRVJUSUVTX0FSUkFZOiBgJHtERUNPUkFUT1JTX1BSRUZJWH0vYXBpTW9kZWxQcm9wZXJ0aWVzQXJyYXlgLFxuICBBUElfU0VDVVJJVFk6IGAke0RFQ09SQVRPUlNfUFJFRklYfS9hcGlTZWN1cml0eWAsXG4gIEFQSV9FWENMVURFX0VORFBPSU5UOiBgJHtERUNPUkFUT1JTX1BSRUZJWH0vYXBpRXhjbHVkZUVuZHBvaW50YCxcbiAgQVBJX0VYQ0xVREVfQ09OVFJPTExFUjogYCR7REVDT1JBVE9SU19QUkVGSVh9L2FwaUV4Y2x1ZGVDb250cm9sbGVyYCxcbiAgQVBJX0VYVFJBX01PREVMUzogYCR7REVDT1JBVE9SU19QUkVGSVh9L2FwaUV4dHJhTW9kZWxzYCxcbiAgQVBJX0VYVEVOU0lPTjogYCR7REVDT1JBVE9SU19QUkVGSVh9L2FwaUV4dGVuc2lvbmAsXG4gIEFQSV9TQ0hFTUE6IGAke0RFQ09SQVRPUlNfUFJFRklYfS9hcGlTY2hlbWFgLFxuICBBUElfREVGQVVMVF9HRVRURVI6IGAke0RFQ09SQVRPUlNfUFJFRklYfS9hcGlEZWZhdWx0R2V0dGVyYCxcbiAgQVBJX0xJTks6IGAke0RFQ09SQVRPUlNfUFJFRklYfS9hcGlMaW5rYCxcbn07XG4iLCJpbXBvcnQgeyBpc0FycmF5LCBpc1VuZGVmaW5lZCwgbmVnYXRlLCBwaWNrQnkgfSBmcm9tIFwibG9kYXNoXCI7XG5pbXBvcnQgeyBERUNPUkFUT1JTIH0gZnJvbSBcIi4vY29uc3RhbnRzXCI7XG5cbmV4cG9ydCBjb25zdCBpc0NvbnN0cnVjdG9yID0gKHZhbDogYW55KTogYm9vbGVhbiA9PiB2YWwgPT09IFwiY29uc3RydWN0b3JcIjtcbmV4cG9ydCBjb25zdCBNRVRBREFUQV9GQUNUT1JZX05BTUUgPSBcIl9PUEVOQVBJX01FVEFEQVRBX0ZBQ1RPUllcIjtcblxuZXhwb3J0IGNvbnN0IE1FVEhPRF9NRVRBREFUQSA9IFwibWV0aG9kXCI7XG5cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVNZXRob2REZWNvcmF0b3I8VCA9IGFueT4oXG4gIG1ldGFrZXk6IHN0cmluZyxcbiAgbWV0YWRhdGE6IFQsXG4gIHsgb3ZlcnJpZGVFeGlzdGluZyB9ID0geyBvdmVycmlkZUV4aXN0aW5nOiB0cnVlIH1cbik6IE1ldGhvZERlY29yYXRvciB7XG4gIHJldHVybiAoXG4gICAgdGFyZ2V0OiBvYmplY3QsXG4gICAga2V5OiBzdHJpbmcgfCBzeW1ib2wsXG4gICAgZGVzY3JpcHRvcjogUHJvcGVydHlEZXNjcmlwdG9yXG4gICkgPT4ge1xuICAgIGlmICh0eXBlb2YgbWV0YWRhdGEgPT09IFwib2JqZWN0XCIpIHtcbiAgICAgIGNvbnN0IHByZXZWYWx1ZSA9IFJlZmxlY3QuZ2V0TWV0YWRhdGEobWV0YWtleSwgZGVzY3JpcHRvci52YWx1ZSk7XG4gICAgICBpZiAocHJldlZhbHVlICYmICFvdmVycmlkZUV4aXN0aW5nKSB7XG4gICAgICAgIHJldHVybiBkZXNjcmlwdG9yO1xuICAgICAgfVxuICAgICAgUmVmbGVjdC5kZWZpbmVNZXRhZGF0YShcbiAgICAgICAgbWV0YWtleSxcbiAgICAgICAgeyAuLi5wcmV2VmFsdWUsIC4uLm1ldGFkYXRhIH0sXG4gICAgICAgIGRlc2NyaXB0b3IudmFsdWVcbiAgICAgICk7XG4gICAgICByZXR1cm4gZGVzY3JpcHRvcjtcbiAgICB9XG4gICAgUmVmbGVjdC5kZWZpbmVNZXRhZGF0YShtZXRha2V5LCBtZXRhZGF0YSwgZGVzY3JpcHRvci52YWx1ZSk7XG4gICAgcmV0dXJuIGRlc2NyaXB0b3I7XG4gIH07XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVDbGFzc0RlY29yYXRvcjxUIGV4dGVuZHMgQXJyYXk8YW55PiA9IGFueT4oXG4gIG1ldGFrZXk6IHN0cmluZyxcbiAgbWV0YWRhdGE6IFQgPSBbXSBhcyBhbnlcbik6IENsYXNzRGVjb3JhdG9yIHtcbiAgcmV0dXJuICh0YXJnZXQpID0+IHtcbiAgICBjb25zdCBwcmV2VmFsdWUgPSBSZWZsZWN0LmdldE1ldGFkYXRhKG1ldGFrZXksIHRhcmdldCkgfHwgW107XG4gICAgUmVmbGVjdC5kZWZpbmVNZXRhZGF0YShtZXRha2V5LCBbLi4ucHJldlZhbHVlLCAuLi5tZXRhZGF0YV0sIHRhcmdldCk7XG4gICAgcmV0dXJuIHRhcmdldDtcbiAgfTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZVByb3BlcnR5RGVjb3JhdG9yPFQgZXh0ZW5kcyBSZWNvcmQ8c3RyaW5nLCBhbnk+ID0gYW55PihcbiAgbWV0YWtleTogc3RyaW5nLFxuICBtZXRhZGF0YTogVCxcbiAgb3ZlcnJpZGVFeGlzdGluZyA9IHRydWVcbik6IFByb3BlcnR5RGVjb3JhdG9yIHtcbiAgcmV0dXJuICgodGFyZ2V0OiBvYmplY3QsIHByb3BlcnR5S2V5OiBzdHJpbmcpID0+IHtcbiAgICBjb25zdCBwcm9wZXJ0aWVzID1cbiAgICAgIFJlZmxlY3QuZ2V0TWV0YWRhdGEoREVDT1JBVE9SUy5BUElfTU9ERUxfUFJPUEVSVElFU19BUlJBWSwgdGFyZ2V0KSB8fCBbXTtcblxuICAgIGNvbnN0IGtleSA9IGA6JHtwcm9wZXJ0eUtleX1gO1xuICAgIGlmICghcHJvcGVydGllcy5pbmNsdWRlcyhrZXkpKSB7XG4gICAgICBSZWZsZWN0LmRlZmluZU1ldGFkYXRhKFxuICAgICAgICBERUNPUkFUT1JTLkFQSV9NT0RFTF9QUk9QRVJUSUVTX0FSUkFZLFxuICAgICAgICBbLi4ucHJvcGVydGllcywgYDoke3Byb3BlcnR5S2V5fWBdLFxuICAgICAgICB0YXJnZXRcbiAgICAgICk7XG4gICAgfVxuICAgIGNvbnN0IGV4aXN0aW5nTWV0YWRhdGEgPSBSZWZsZWN0LmdldE1ldGFkYXRhKG1ldGFrZXksIHRhcmdldCwgcHJvcGVydHlLZXkpO1xuICAgIGlmIChleGlzdGluZ01ldGFkYXRhKSB7XG4gICAgICBjb25zdCBuZXdNZXRhZGF0YSA9IHBpY2tCeShtZXRhZGF0YSwgbmVnYXRlKGlzVW5kZWZpbmVkKSk7XG4gICAgICBjb25zdCBtZXRhZGF0YVRvU2F2ZSA9IG92ZXJyaWRlRXhpc3RpbmdcbiAgICAgICAgPyB7XG4gICAgICAgICAgICAuLi5leGlzdGluZ01ldGFkYXRhLFxuICAgICAgICAgICAgLi4ubmV3TWV0YWRhdGEsXG4gICAgICAgICAgfVxuICAgICAgICA6IHtcbiAgICAgICAgICAgIC4uLm5ld01ldGFkYXRhLFxuICAgICAgICAgICAgLi4uZXhpc3RpbmdNZXRhZGF0YSxcbiAgICAgICAgICB9O1xuXG4gICAgICBSZWZsZWN0LmRlZmluZU1ldGFkYXRhKG1ldGFrZXksIG1ldGFkYXRhVG9TYXZlLCB0YXJnZXQsIHByb3BlcnR5S2V5KTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3QgdHlwZSA9XG4gICAgICAgICh0YXJnZXQ/LmNvbnN0cnVjdG9yIGFzIGFueSk/LltNRVRBREFUQV9GQUNUT1JZX05BTUUgYXMgYW55XT8uKClbXG4gICAgICAgICAgcHJvcGVydHlLZXlcbiAgICAgICAgXT8udHlwZSA/PyBSZWZsZWN0LmdldE1ldGFkYXRhKFwiZGVzaWduOnR5cGVcIiwgdGFyZ2V0LCBwcm9wZXJ0eUtleSk7XG5cbiAgICAgIFJlZmxlY3QuZGVmaW5lTWV0YWRhdGEoXG4gICAgICAgIG1ldGFrZXksXG4gICAgICAgIHtcbiAgICAgICAgICB0eXBlLFxuICAgICAgICAgIC4uLnBpY2tCeShtZXRhZGF0YSwgbmVnYXRlKGlzVW5kZWZpbmVkKSksXG4gICAgICAgIH0sXG4gICAgICAgIHRhcmdldCxcbiAgICAgICAgcHJvcGVydHlLZXlcbiAgICAgICk7XG4gICAgfVxuICB9KSBhcyBQcm9wZXJ0eURlY29yYXRvcjtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZU1peGVkRGVjb3JhdG9yPFQgPSBhbnk+KFxuICBtZXRha2V5OiBzdHJpbmcsXG4gIG1ldGFkYXRhOiBUXG4pOiBNZXRob2REZWNvcmF0b3IgJiBDbGFzc0RlY29yYXRvciB7XG4gIHJldHVybiAoXG4gICAgdGFyZ2V0OiBvYmplY3QsXG4gICAga2V5Pzogc3RyaW5nIHwgc3ltYm9sLFxuICAgIGRlc2NyaXB0b3I/OiBUeXBlZFByb3BlcnR5RGVzY3JpcHRvcjxhbnk+XG4gICk6IGFueSA9PiB7XG4gICAgaWYgKGRlc2NyaXB0b3IpIHtcbiAgICAgIGxldCBtZXRhZGF0YXM6IGFueTtcbiAgICAgIGlmIChBcnJheS5pc0FycmF5KG1ldGFkYXRhKSkge1xuICAgICAgICBjb25zdCBwcmV2aW91c01ldGFkYXRhID1cbiAgICAgICAgICBSZWZsZWN0LmdldE1ldGFkYXRhKG1ldGFrZXksIGRlc2NyaXB0b3IudmFsdWUpIHx8IFtdO1xuICAgICAgICBtZXRhZGF0YXMgPSBbLi4ucHJldmlvdXNNZXRhZGF0YSwgLi4ubWV0YWRhdGFdO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uc3QgcHJldmlvdXNNZXRhZGF0YSA9XG4gICAgICAgICAgUmVmbGVjdC5nZXRNZXRhZGF0YShtZXRha2V5LCBkZXNjcmlwdG9yLnZhbHVlKSB8fCB7fTtcbiAgICAgICAgbWV0YWRhdGFzID0geyAuLi5wcmV2aW91c01ldGFkYXRhLCAuLi5tZXRhZGF0YSB9O1xuICAgICAgfVxuICAgICAgUmVmbGVjdC5kZWZpbmVNZXRhZGF0YShtZXRha2V5LCBtZXRhZGF0YXMsIGRlc2NyaXB0b3IudmFsdWUpO1xuICAgICAgcmV0dXJuIGRlc2NyaXB0b3I7XG4gICAgfVxuXG4gICAgbGV0IG1ldGFkYXRhczogYW55O1xuICAgIGlmIChBcnJheS5pc0FycmF5KG1ldGFkYXRhKSkge1xuICAgICAgY29uc3QgcHJldmlvdXNNZXRhZGF0YSA9IFJlZmxlY3QuZ2V0TWV0YWRhdGEobWV0YWtleSwgdGFyZ2V0KSB8fCBbXTtcbiAgICAgIG1ldGFkYXRhcyA9IFsuLi5wcmV2aW91c01ldGFkYXRhLCAuLi5tZXRhZGF0YV07XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnN0IHByZXZpb3VzTWV0YWRhdGEgPSBSZWZsZWN0LmdldE1ldGFkYXRhKG1ldGFrZXksIHRhcmdldCkgfHwge307XG4gICAgICBtZXRhZGF0YXMgPSBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHByZXZpb3VzTWV0YWRhdGEpLCBtZXRhZGF0YSk7XG4gICAgfVxuICAgIFJlZmxlY3QuZGVmaW5lTWV0YWRhdGEobWV0YWtleSwgbWV0YWRhdGFzLCB0YXJnZXQpO1xuICAgIHJldHVybiB0YXJnZXQ7XG4gIH07XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVQYXJhbURlY29yYXRvcjxUIGV4dGVuZHMgUmVjb3JkPHN0cmluZywgYW55PiA9IGFueT4oXG4gIG1ldGFkYXRhOiBULFxuICBpbml0aWFsOiBQYXJ0aWFsPFQ+XG4pOiBNZXRob2REZWNvcmF0b3IgJiBDbGFzc0RlY29yYXRvciB7XG4gIHJldHVybiAoXG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnNhZmUtZnVuY3Rpb24tdHlwZVxuICAgIHRhcmdldDogb2JqZWN0IHwgRnVuY3Rpb24sXG4gICAga2V5Pzogc3RyaW5nIHwgc3ltYm9sLFxuICAgIGRlc2NyaXB0b3I/OiBUeXBlZFByb3BlcnR5RGVzY3JpcHRvcjxhbnk+XG4gICk6IGFueSA9PiB7XG4gICAgY29uc3QgcGFyYW1PcHRpb25zID0ge1xuICAgICAgLi4uaW5pdGlhbCxcbiAgICAgIC4uLnBpY2tCeShtZXRhZGF0YSwgbmVnYXRlKGlzVW5kZWZpbmVkKSksXG4gICAgfTtcblxuICAgIGlmIChkZXNjcmlwdG9yKSB7XG4gICAgICBjb25zdCBwYXJhbWV0ZXJzID1cbiAgICAgICAgUmVmbGVjdC5nZXRNZXRhZGF0YShERUNPUkFUT1JTLkFQSV9QQVJBTUVURVJTLCBkZXNjcmlwdG9yLnZhbHVlKSB8fCBbXTtcbiAgICAgIFJlZmxlY3QuZGVmaW5lTWV0YWRhdGEoXG4gICAgICAgIERFQ09SQVRPUlMuQVBJX1BBUkFNRVRFUlMsXG4gICAgICAgIFsuLi5wYXJhbWV0ZXJzLCBwYXJhbU9wdGlvbnNdLFxuICAgICAgICBkZXNjcmlwdG9yLnZhbHVlXG4gICAgICApO1xuICAgICAgcmV0dXJuIGRlc2NyaXB0b3I7XG4gICAgfVxuXG4gICAgaWYgKHR5cGVvZiB0YXJnZXQgPT09IFwib2JqZWN0XCIpIHtcbiAgICAgIHJldHVybiB0YXJnZXQ7XG4gICAgfVxuXG4gICAgY29uc3QgcHJvcGVydHlLZXlzID0gT2JqZWN0LmdldE93blByb3BlcnR5TmFtZXModGFyZ2V0LnByb3RvdHlwZSk7XG5cbiAgICBmb3IgKGNvbnN0IHByb3BlcnR5S2V5IG9mIHByb3BlcnR5S2V5cykge1xuICAgICAgaWYgKGlzQ29uc3RydWN0b3IocHJvcGVydHlLZXkpKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBtZXRob2REZXNjcmlwdG9yID0gT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcihcbiAgICAgICAgdGFyZ2V0LnByb3RvdHlwZSxcbiAgICAgICAgcHJvcGVydHlLZXlcbiAgICAgICk7XG5cbiAgICAgIGlmICghbWV0aG9kRGVzY3JpcHRvcikge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgaXNBcGlNZXRob2QgPSBSZWZsZWN0Lmhhc01ldGFkYXRhKFxuICAgICAgICBNRVRIT0RfTUVUQURBVEEsXG4gICAgICAgIG1ldGhvZERlc2NyaXB0b3IudmFsdWVcbiAgICAgICk7XG5cbiAgICAgIGlmICghaXNBcGlNZXRob2QpIHtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHBhcmFtZXRlcnMgPVxuICAgICAgICBSZWZsZWN0LmdldE1ldGFkYXRhKFxuICAgICAgICAgIERFQ09SQVRPUlMuQVBJX1BBUkFNRVRFUlMsXG4gICAgICAgICAgbWV0aG9kRGVzY3JpcHRvci52YWx1ZVxuICAgICAgICApIHx8IFtdO1xuICAgICAgUmVmbGVjdC5kZWZpbmVNZXRhZGF0YShcbiAgICAgICAgREVDT1JBVE9SUy5BUElfUEFSQU1FVEVSUyxcbiAgICAgICAgWy4uLnBhcmFtZXRlcnMsIHBhcmFtT3B0aW9uc10sXG4gICAgICAgIG1ldGhvZERlc2NyaXB0b3IudmFsdWVcbiAgICAgICk7XG4gICAgfVxuICB9O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0VHlwZUlzQXJyYXlUdXBsZShcbiAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnNhZmUtZnVuY3Rpb24tdHlwZVxuICBpbnB1dDogRnVuY3Rpb24gfCBbRnVuY3Rpb25dIHwgdW5kZWZpbmVkIHwgc3RyaW5nIHwgUmVjb3JkPHN0cmluZywgYW55PixcbiAgaXNBcnJheUZsYWc6IGJvb2xlYW5cbiAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnNhZmUtZnVuY3Rpb24tdHlwZVxuKTogW0Z1bmN0aW9uIHwgdW5kZWZpbmVkLCBib29sZWFuXSB7XG4gIGlmICghaW5wdXQpIHtcbiAgICByZXR1cm4gW2lucHV0IGFzIHVuZGVmaW5lZCwgaXNBcnJheUZsYWddO1xuICB9XG4gIGlmIChpc0FycmF5RmxhZykge1xuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW5zYWZlLWZ1bmN0aW9uLXR5cGVcbiAgICByZXR1cm4gW2lucHV0IGFzIEZ1bmN0aW9uLCBpc0FycmF5RmxhZ107XG4gIH1cbiAgY29uc3QgaXNJbnB1dEFycmF5ID0gaXNBcnJheShpbnB1dCk7XG4gIGNvbnN0IHR5cGUgPSBpc0lucHV0QXJyYXkgPyBpbnB1dFswXSA6IGlucHV0O1xuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVuc2FmZS1mdW5jdGlvbi10eXBlXG4gIHJldHVybiBbdHlwZSBhcyBGdW5jdGlvbiwgaXNJbnB1dEFycmF5XTtcbn1cbiIsImltcG9ydCB7IFR5cGUgfSBmcm9tIFwiQG5lc3Rqcy9jb21tb25cIjtcbmltcG9ydCB7IGlzU3RyaW5nLCBuZWdhdGUsIHBpY2tCeSB9IGZyb20gXCJsb2Rhc2hcIjtcbmltcG9ydCB7IERFQ09SQVRPUlMgfSBmcm9tIFwiLi9jb25zdGFudHNcIjtcbmltcG9ydCB7IGdldFR5cGVJc0FycmF5VHVwbGUsIE1FVEFEQVRBX0ZBQ1RPUllfTkFNRSB9IGZyb20gXCIuL2hlbHBlcnNcIjtcbmltcG9ydCB0eXBlIHtcbiAgRW51bUFsbG93ZWRUeXBlcyxcbiAgRW51bVNjaGVtYUF0dHJpYnV0ZXMsXG4gIFNjaGVtYU9iamVjdE1ldGFkYXRhLFxuICBTd2FnZ2VyRW51bVR5cGUsXG59IGZyb20gXCIuLi9zd2FnZ2VyLXR5cGVzXCI7XG5cbmV4cG9ydCBjb25zdCBpc1VuZGVmaW5lZCA9IChvYmo6IGFueSk6IG9iaiBpcyB1bmRlZmluZWQgPT5cbiAgdHlwZW9mIG9iaiA9PT0gXCJ1bmRlZmluZWRcIjtcblxuZXhwb3J0IGZ1bmN0aW9uIGdldEVudW1WYWx1ZXMoXG4gIGVudW1UeXBlOiBTd2FnZ2VyRW51bVR5cGUgfCAoKCkgPT4gU3dhZ2dlckVudW1UeXBlKVxuKTogc3RyaW5nW10gfCBudW1iZXJbXSB7XG4gIGlmICh0eXBlb2YgZW51bVR5cGUgPT09IFwiZnVuY3Rpb25cIikge1xuICAgIHJldHVybiBnZXRFbnVtVmFsdWVzKGVudW1UeXBlKCkpO1xuICB9XG5cbiAgaWYgKEFycmF5LmlzQXJyYXkoZW51bVR5cGUpKSB7XG4gICAgcmV0dXJuIGVudW1UeXBlIGFzIHN0cmluZ1tdO1xuICB9XG4gIGlmICh0eXBlb2YgZW51bVR5cGUgIT09IFwib2JqZWN0XCIpIHtcbiAgICByZXR1cm4gW107XG4gIH1cbiAgLy8gRW51bXMgd2l0aCBudW1lcmljIHZhbHVlc1xuICAvLyAgIGVudW0gU2l6ZSB7XG4gIC8vICAgICBTTUFMTCA9IDEsXG4gIC8vICAgICBCSUcgPSAyXG4gIC8vICAgfVxuICAvLyBhcmUgdHJhbnNwaWxlZCB0byBpbmNsdWRlIGEgcmV2ZXJzZSBtYXBwaW5nXG4gIC8vICAgY29uc3QgU2l6ZSA9IHtcbiAgLy8gICAgIFwiMVwiOiBcIlNNQUxMXCIsXG4gIC8vICAgICBcIjJcIjogXCJCSUdcIixcbiAgLy8gICAgIFwiU01BTExcIjogMSxcbiAgLy8gICAgIFwiQklHXCI6IDIsXG4gIC8vICAgfVxuICBjb25zdCBudW1lcmljVmFsdWVzID0gT2JqZWN0LnZhbHVlcyhlbnVtVHlwZSlcbiAgICAuZmlsdGVyKCh2YWx1ZSkgPT4gdHlwZW9mIHZhbHVlID09PSBcIm51bWJlclwiKVxuICAgIC5tYXAoKHZhbHVlOiBhbnkpID0+IHZhbHVlLnRvU3RyaW5nKCkpO1xuXG4gIHJldHVybiBPYmplY3Qua2V5cyhlbnVtVHlwZSlcbiAgICAuZmlsdGVyKChrZXkpID0+ICFudW1lcmljVmFsdWVzLmluY2x1ZGVzKGtleSkpXG4gICAgLm1hcCgoa2V5KSA9PiBlbnVtVHlwZVtrZXkgYXMgYW55XSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRFbnVtVHlwZSh2YWx1ZXM6IChzdHJpbmcgfCBudW1iZXIpW10pOiBcInN0cmluZ1wiIHwgXCJudW1iZXJcIiB7XG4gIGNvbnN0IGhhc1N0cmluZyA9IHZhbHVlcy5maWx0ZXIoaXNTdHJpbmcpLmxlbmd0aCA+IDA7XG4gIHJldHVybiBoYXNTdHJpbmcgPyBcInN0cmluZ1wiIDogXCJudW1iZXJcIjtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZVByb3BlcnR5RGVjb3JhdG9yPFQgZXh0ZW5kcyBSZWNvcmQ8c3RyaW5nLCBhbnk+ID0gYW55PihcbiAgbWV0YWtleTogc3RyaW5nLFxuICBtZXRhZGF0YTogVCxcbiAgb3ZlcnJpZGVFeGlzdGluZyA9IHRydWVcbik6IFByb3BlcnR5RGVjb3JhdG9yIHtcbiAgcmV0dXJuICgodGFyZ2V0OiBvYmplY3QsIHByb3BlcnR5S2V5OiBzdHJpbmcpID0+IHtcbiAgICBjb25zdCBwcm9wZXJ0aWVzID1cbiAgICAgIFJlZmxlY3QuZ2V0TWV0YWRhdGEoREVDT1JBVE9SUy5BUElfTU9ERUxfUFJPUEVSVElFU19BUlJBWSwgdGFyZ2V0KSB8fCBbXTtcblxuICAgIGNvbnN0IGtleSA9IGA6JHtwcm9wZXJ0eUtleX1gO1xuICAgIGlmICghcHJvcGVydGllcy5pbmNsdWRlcyhrZXkpKSB7XG4gICAgICBSZWZsZWN0LmRlZmluZU1ldGFkYXRhKFxuICAgICAgICBERUNPUkFUT1JTLkFQSV9NT0RFTF9QUk9QRVJUSUVTX0FSUkFZLFxuICAgICAgICBbLi4ucHJvcGVydGllcywgYDoke3Byb3BlcnR5S2V5fWBdLFxuICAgICAgICB0YXJnZXRcbiAgICAgICk7XG4gICAgfVxuICAgIGNvbnN0IGV4aXN0aW5nTWV0YWRhdGEgPSBSZWZsZWN0LmdldE1ldGFkYXRhKG1ldGFrZXksIHRhcmdldCwgcHJvcGVydHlLZXkpO1xuICAgIGlmIChleGlzdGluZ01ldGFkYXRhKSB7XG4gICAgICBjb25zdCBuZXdNZXRhZGF0YSA9IHBpY2tCeShtZXRhZGF0YSwgbmVnYXRlKGlzVW5kZWZpbmVkKSk7XG4gICAgICBjb25zdCBtZXRhZGF0YVRvU2F2ZSA9IG92ZXJyaWRlRXhpc3RpbmdcbiAgICAgICAgPyB7XG4gICAgICAgICAgICAuLi5leGlzdGluZ01ldGFkYXRhLFxuICAgICAgICAgICAgLi4ubmV3TWV0YWRhdGEsXG4gICAgICAgICAgfVxuICAgICAgICA6IHtcbiAgICAgICAgICAgIC4uLm5ld01ldGFkYXRhLFxuICAgICAgICAgICAgLi4uZXhpc3RpbmdNZXRhZGF0YSxcbiAgICAgICAgICB9O1xuXG4gICAgICBSZWZsZWN0LmRlZmluZU1ldGFkYXRhKG1ldGFrZXksIG1ldGFkYXRhVG9TYXZlLCB0YXJnZXQsIHByb3BlcnR5S2V5KTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3QgdHlwZSA9XG4gICAgICAgIC8vIEB0cy1leHBlY3QtZXJyb3IgbmVzdCBqcyBjb2RlXG4gICAgICAgIHRhcmdldD8uY29uc3RydWN0b3I/LltNRVRBREFUQV9GQUNUT1JZX05BTUVdPy4oKVtwcm9wZXJ0eUtleV0/LnR5cGUgPz9cbiAgICAgICAgUmVmbGVjdC5nZXRNZXRhZGF0YShcImRlc2lnbjp0eXBlXCIsIHRhcmdldCwgcHJvcGVydHlLZXkpO1xuXG4gICAgICBSZWZsZWN0LmRlZmluZU1ldGFkYXRhKFxuICAgICAgICBtZXRha2V5LFxuICAgICAgICB7XG4gICAgICAgICAgdHlwZSxcbiAgICAgICAgICByZXF1aXJlZDogZmFsc2UsIC8vIERlZmF1bHQgdG8gb3B0aW9uYWwgdW5sZXNzIEByZXF1aXJlZCgpIGlzIHVzZWRcbiAgICAgICAgICAuLi5waWNrQnkobWV0YWRhdGEsIG5lZ2F0ZShpc1VuZGVmaW5lZCkpLFxuICAgICAgICB9LFxuICAgICAgICB0YXJnZXQsXG4gICAgICAgIHByb3BlcnR5S2V5XG4gICAgICApO1xuICAgIH1cbiAgfSkgYXMgUHJvcGVydHlEZWNvcmF0b3I7XG59XG5cbmV4cG9ydCB0eXBlIEFwaVByb3BlcnR5Q29tbW9uT3B0aW9ucyA9IFNjaGVtYU9iamVjdE1ldGFkYXRhICYge1xuICBcIngtZW51bU5hbWVzXCI/OiBzdHJpbmdbXTtcbiAgLyoqXG4gICAqIExhenkgZnVuY3Rpb24gcmV0dXJuaW5nIHRoZSB0eXBlIGZvciB3aGljaCB0aGUgZGVjb3JhdGVkIHByb3BlcnR5XG4gICAqIGNhbiBiZSB1c2VkIGFzIGFuIGlkXG4gICAqXG4gICAqIFVzZSB0b2dldGhlciB3aXRoIEBBcGlEZWZhdWx0R2V0dGVyIG9uIHRoZSBnZXR0ZXIgcm91dGUgb2YgdGhlIHR5cGVcbiAgICogdG8gZ2VuZXJhdGUgT3BlbkFQSSBsaW5rIG9iamVjdHNcbiAgICpcbiAgICogQHNlZSBbU3dhZ2dlciBsaW5rIG9iamVjdHNdKGh0dHBzOi8vc3dhZ2dlci5pby9kb2NzL3NwZWNpZmljYXRpb24vbGlua3MvKVxuICAgKi9cbiAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnNhZmUtZnVuY3Rpb24tdHlwZVxuICBsaW5rPzogKCkgPT4gVHlwZTx1bmtub3duPiB8IEZ1bmN0aW9uO1xufTtcblxuZXhwb3J0IHR5cGUgQXBpUHJvcGVydHlPcHRpb25zID1cbiAgfCBBcGlQcm9wZXJ0eUNvbW1vbk9wdGlvbnNcbiAgfCAoQXBpUHJvcGVydHlDb21tb25PcHRpb25zICYge1xuICAgICAgZW51bU5hbWU6IHN0cmluZztcbiAgICAgIGVudW1TY2hlbWE/OiBFbnVtU2NoZW1hQXR0cmlidXRlcztcbiAgICB9KTtcblxuY29uc3QgaXNFbnVtQXJyYXkgPSAoXG4gIG9wdHM6IEFwaVByb3BlcnR5T3B0aW9uc1xuKTogb3B0cyBpcyB7XG4gIGlzQXJyYXk6IHRydWU7XG4gIGVudW06IEVudW1BbGxvd2VkVHlwZXM7XG4gIHR5cGU6IGFueTtcbiAgaXRlbXM6IGFueTtcbn0gPT4gKG9wdHMuaXNBcnJheSAmJiBcImVudW1cIiBpbiBvcHRzICYmIG9wdHMuZW51bSAhPT0gdW5kZWZpbmVkKSBhcyBib29sZWFuO1xuXG4vKipcbiAqIEBwdWJsaWNBcGlcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIEFwaVByb3BlcnR5KFxuICBvcHRpb25zOiBBcGlQcm9wZXJ0eU9wdGlvbnMgPSB7fVxuKTogUHJvcGVydHlEZWNvcmF0b3Ige1xuICByZXR1cm4gY3JlYXRlQXBpUHJvcGVydHlEZWNvcmF0b3Iob3B0aW9ucyk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVBcGlQcm9wZXJ0eURlY29yYXRvcihcbiAgb3B0aW9uczogQXBpUHJvcGVydHlPcHRpb25zID0ge30sXG4gIG92ZXJyaWRlRXhpc3RpbmcgPSB0cnVlXG4pOiBQcm9wZXJ0eURlY29yYXRvciB7XG4gIGNvbnN0IFt0eXBlLCBpc0FycmF5XSA9IGdldFR5cGVJc0FycmF5VHVwbGUoXG4gICAgb3B0aW9ucy50eXBlLFxuICAgIG9wdGlvbnMuaXNBcnJheSBhcyBhbnlcbiAgKTtcbiAgb3B0aW9ucyA9IHtcbiAgICAuLi5vcHRpb25zLFxuICAgIHR5cGUsXG4gICAgaXNBcnJheSxcbiAgfSBhcyBBcGlQcm9wZXJ0eU9wdGlvbnM7XG5cbiAgaWYgKGlzRW51bUFycmF5KG9wdGlvbnMpKSB7XG4gICAgb3B0aW9ucy50eXBlID0gXCJhcnJheVwiO1xuXG4gICAgY29uc3QgZW51bVZhbHVlcyA9IGdldEVudW1WYWx1ZXMob3B0aW9ucy5lbnVtKTtcbiAgICBvcHRpb25zLml0ZW1zID0ge1xuICAgICAgdHlwZTogZ2V0RW51bVR5cGUoZW51bVZhbHVlcyksXG4gICAgICBlbnVtOiBlbnVtVmFsdWVzLFxuICAgIH07XG4gICAgLy8gQHRzLWV4cGVjdC1lcnJvciBuZXN0IGpzIGNvZGVcbiAgICBkZWxldGUgb3B0aW9ucy5lbnVtO1xuICB9IGVsc2UgaWYgKFwiZW51bVwiIGluIG9wdGlvbnMgJiYgb3B0aW9ucy5lbnVtICE9PSB1bmRlZmluZWQpIHtcbiAgICBjb25zdCBlbnVtVmFsdWVzID0gZ2V0RW51bVZhbHVlcyhvcHRpb25zLmVudW0pO1xuXG4gICAgb3B0aW9ucy5lbnVtID0gZW51bVZhbHVlcztcbiAgICBvcHRpb25zLnR5cGUgPSBnZXRFbnVtVHlwZShlbnVtVmFsdWVzKTtcbiAgfVxuXG4gIGlmIChBcnJheS5pc0FycmF5KG9wdGlvbnMudHlwZSkpIHtcbiAgICBvcHRpb25zLnR5cGUgPSBcImFycmF5XCI7XG4gICAgb3B0aW9ucy5pdGVtcyA9IHtcbiAgICAgIHR5cGU6IFwiYXJyYXlcIixcbiAgICAgIGl0ZW1zOiB7XG4gICAgICAgIHR5cGU6IG9wdGlvbnMudHlwZVswXSxcbiAgICAgIH0sXG4gICAgfTtcbiAgfVxuXG4gIHJldHVybiBjcmVhdGVQcm9wZXJ0eURlY29yYXRvcihcbiAgICBERUNPUkFUT1JTLkFQSV9NT0RFTF9QUk9QRVJUSUVTLFxuICAgIG9wdGlvbnMsXG4gICAgb3ZlcnJpZGVFeGlzdGluZ1xuICApO1xufVxuIiwiaW1wb3J0IHsgYXBwbHksIE1ldGFkYXRhIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0aW9uXCI7XG5pbXBvcnQgeyBBcGlFeGNsdWRlRW5kcG9pbnQgfSBmcm9tIFwiQG5lc3Rqcy9zd2FnZ2VyXCI7XG5pbXBvcnQge1xuICBCdWxrQ3J1ZE9wZXJhdGlvbktleXMsXG4gIE9wZXJhdGlvbktleXMsXG4gIENydWRPcGVyYXRpb25zLFxufSBmcm9tIFwiQGRlY2FmLXRzL2RiLWRlY29yYXRvcnNcIjtcbmltcG9ydCB7IE1vZGVsQ29uc3RydWN0b3IgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRvci12YWxpZGF0aW9uXCI7XG5pbXBvcnQgeyBEZWxldGUsIEdldCwgUGF0Y2gsIFBvc3QsIFB1dCB9IGZyb20gXCJAbmVzdGpzL2NvbW1vblwiO1xuXG5pbXBvcnQgeyBpc09wZXJhdGlvbkJsb2NrZWQgYXMgY29yZUlzT3BlcmF0aW9uQmxvY2tlZCB9IGZyb20gXCJAZGVjYWYtdHMvY29yZVwiO1xuaW1wb3J0IHsgUHJlcGFyZWRTdGF0ZW1lbnRLZXlzIH0gZnJvbSBcIkBkZWNhZi10cy9jb3JlXCI7XG5pbXBvcnQgeyBIdHRwVmVyYnMgfSBmcm9tIFwiLi90eXBlc1wiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBEZXRlcm1pbmVzIGlmIGEgZ2l2ZW4gQ1JVRCBvcGVyYXRpb24gaXMgYmxvY2tlZCBmb3IgYSBzcGVjaWZpYyBtb2RlbCBjb25zdHJ1Y3Rvci5cbiAqIEBzdW1tYXJ5IFJldHJpZXZlcyB0aGUgb3BlcmF0aW9uLWJsb2NraW5nIGhhbmRsZXIgbWV0YWRhdGEgc3RvcmVkIG9uIHRoZSBwcm92aWRlZCBtb2RlbCBjb25zdHJ1Y3RvciAodW5kZXIgYE9wZXJhdGlvbktleXMuUkVGTEVDVCArIE9wZXJhdGlvbktleXMuQkxPQ0tgKSwgZXhlY3V0ZXMgaXQgKGlmIHByZXNlbnQpIHdpdGggaXRzIHBlcnNpc3RlZCBhcmd1bWVudHMgcGx1cyB0aGUgcmVxdWVzdGVkIG9wZXJhdGlvbiwgYW5kIHJldHVybnMgd2hldGhlciB0aGUgb3BlcmF0aW9uIGlzIGJsb2NrZWQuIElmIG5vIGhhbmRsZXIgZXhpc3RzLCB0aGUgb3BlcmF0aW9uIGlzIGNvbnNpZGVyZWQgYWxsb3dlZCAocmV0dXJucyBgZmFsc2VgKS5cbiAqIEBwYXJhbSB7TW9kZWxDb25zdHJ1Y3Rvcjxhbnk+fSBNb2RlbENvbnN0cnVjdG9yIC0gVGhlIHRhcmdldCBtb2RlbCBjb25zdHJ1Y3RvciB3aG9zZSBtZXRhZGF0YSBtYXkgaW5jbHVkZSBhIGJsb2NraW5nIGhhbmRsZXIuXG4gKiBAcGFyYW0ge0NydWRPcGVyYXRpb25zfSBvcCAtIFRoZSBDUlVEIG9wZXJhdGlvbiB0byBldmFsdWF0ZSAoZS5nLiwgYE9wZXJhdGlvbktleXMuQ1JFQVRFYCwgYE9wZXJhdGlvbktleXMuUkVBRGAsIGBPcGVyYXRpb25LZXlzLlVQREFURWAsIGBPcGVyYXRpb25LZXlzLkRFTEVURWApLlxuICogQHJldHVybiB7Ym9vbGVhbn0gYHRydWVgIHdoZW4gdGhlIG9wZXJhdGlvbiBpcyBleHBsaWNpdGx5IGJsb2NrZWQgYnkgdGhlIG1vZGVsJ3MgaGFuZGxlcjsgb3RoZXJ3aXNlIGBmYWxzZWAuXG4gKiBAZnVuY3Rpb24gaXNPcGVyYXRpb25CbG9ja2VkXG4gKi9cbi8qKlxuICogQGRlc2NyaXB0aW9uIENvbmRpdGlvbmFsbHkgYXBwbGllcyBhbiBIVFRQIG1ldGhvZCBkZWNvcmF0b3IgZm9yIGEgZ2l2ZW4gbW9kZWwgYW5kIHZlcmIsIGhpZGluZyB0aGUgZW5kcG9pbnQgaW4gU3dhZ2dlciAoYW5kIG5vdCByZWdpc3RlcmluZyB0aGUgcm91dGUpIHdoZW4gdGhlIG1vZGVsIGJsb2NrcyB0aGF0IENSVUQgb3BlcmF0aW9uLlxuICogQHN1bW1hcnkgTWFwcyBhbiBIVFRQIHZlcmIgdG8gaXRzIGNvcnJlc3BvbmRpbmcgYENydWRPcGVyYXRpb25zYCBrZXkgYW5kIE5lc3QgSFRUUCBkZWNvcmF0b3IgKGBAR2V0YCwgYEBQb3N0YCwgZXRjLikuIEl0IGNoZWNrcyBgaXNPcGVyYXRpb25CbG9ja2VkKE1vZGVsQ29uc3RydWN0b3IsIGNydWRPcClgIGFuZCwgaWYgYmxvY2tlZCwgYXBwbGllcyBvbmx5IGBAQXBpRXhjbHVkZUVuZHBvaW50KClgIChTd2FnZ2VyLWhpZGRlbiwgbm8gTmVzdCByb3V0ZSkuIElmIHBlcm1pdHRlZCwgaXQgYXBwbGllcyB0aGUgYXBwcm9wcmlhdGUgSFRUUCBkZWNvcmF0b3Igd2l0aCB0aGUgb3B0aW9uYWwgYHBhdGhgLlxuICogQHBhcmFtIHtNb2RlbENvbnN0cnVjdG9yPGFueT59IE1vZGVsQ29uc3RydWN0b3IgLSBUaGUgbW9kZWwgY29uc3RydWN0b3IgdXNlZCB0byByZXNvbHZlIG9wZXJhdGlvbi1ibG9ja2luZyBydWxlcy5cbiAqIEBwYXJhbSB7SHR0cFZlcmJzfSB2ZXJiIC0gVGhlIEhUVFAgdmVyYiB0byBtYXAgKGUuZy4sIGBcIkdFVFwiIHwgXCJQT1NUXCIgfCBcIlBVVFwiIHwgXCJQQVRDSFwiIHwgXCJERUxFVEVcImApLlxuICogQHBhcmFtIHtzdHJpbmd9IFtwYXRoXSAtIE9wdGlvbmFsIHJvdXRlIHBhdGggcGFzc2VkIHRocm91Z2ggdG8gdGhlIGNvcnJlc3BvbmRpbmcgTmVzdCBIVFRQIG1ldGhvZCBkZWNvcmF0b3IuXG4gKiBAcmV0dXJuIHtNZXRob2REZWNvcmF0b3J9IEEgbWV0aG9kIGRlY29yYXRvciB0aGF0IGVpdGhlciBleGNsdWRlcyB0aGUgZW5kcG9pbnQgZnJvbSBTd2FnZ2VyIChhbmQgcm91dGUgcmVnaXN0cmF0aW9uKSBvciBhcHBsaWVzIHRoZSBjb3JyZWN0IEhUVFAgZGVjb3JhdG9yLlxuICovXG5leHBvcnQgZnVuY3Rpb24gQXBpT3BlcmF0aW9uRnJvbU1vZGVsKFxuICBNb2RlbENvbnN0cnVjdG9yOiBNb2RlbENvbnN0cnVjdG9yPGFueT4sXG4gIHZlcmI6IEh0dHBWZXJicyxcbiAgcGF0aD86IHN0cmluZ1xuKTogTWV0aG9kRGVjb3JhdG9yIHtcbiAgY29uc3QgaHR0cFRvQ3J1ZDogUmVjb3JkPFxuICAgIEh0dHBWZXJicyxcbiAgICBbQ3J1ZE9wZXJhdGlvbnMsIChwYXRoPzogc3RyaW5nKSA9PiBNZXRob2REZWNvcmF0b3JdXG4gID4gPSB7XG4gICAgR0VUOiBbT3BlcmF0aW9uS2V5cy5SRUFELCBHZXRdLFxuICAgIFBPU1Q6IFtPcGVyYXRpb25LZXlzLkNSRUFURSwgUG9zdF0sXG4gICAgUFVUOiBbT3BlcmF0aW9uS2V5cy5VUERBVEUsIFB1dF0sXG4gICAgUEFUQ0g6IFtPcGVyYXRpb25LZXlzLlVQREFURSwgUGF0Y2hdLFxuICAgIERFTEVURTogW09wZXJhdGlvbktleXMuREVMRVRFLCBEZWxldGVdLFxuICB9O1xuXG4gIGNvbnN0IFtjcnVkT3AsIEh0dHBNZXRob2REZWNvcmF0b3JdID0gaHR0cFRvQ3J1ZFt2ZXJiXTtcbiAgY29uc3QgdGFyZ2V0ID0gcmVzb2x2ZUJsb2NrVGFyZ2V0KHZlcmIsIHBhdGgpO1xuICByZXR1cm4gdGFyZ2V0XG4gICAgPyBjb3JlSXNPcGVyYXRpb25CbG9ja2VkKE1vZGVsQ29uc3RydWN0b3IsIHRhcmdldC5raW5kIGFzIGFueSwgdGFyZ2V0LnZhbHVlKVxuICAgICAgPyBhcHBseShBcGlFeGNsdWRlRW5kcG9pbnQoKSlcbiAgICAgIDogYXBwbHkoSHR0cE1ldGhvZERlY29yYXRvcihwYXRoKSlcbiAgICA6IGNvcmVJc09wZXJhdGlvbkJsb2NrZWQoTW9kZWxDb25zdHJ1Y3RvciwgY3J1ZE9wKVxuICAgID8gYXBwbHkoQXBpRXhjbHVkZUVuZHBvaW50KCkpXG4gICAgOiBhcHBseShIdHRwTWV0aG9kRGVjb3JhdG9yKHBhdGgpKTtcbn1cbi8qKlxuICogQGRlc2NyaXB0aW9uIENvbmRpdGlvbmFsbHkgYXBwbGllcyBhbiBIVFRQIG1ldGhvZCBkZWNvcmF0b3IgZm9yIGEgZ2l2ZW4gbW9kZWwgYW5kIHZlcmIsIGhpZGluZyB0aGUgZW5kcG9pbnQgaW4gU3dhZ2dlciAoYW5kIG5vdCByZWdpc3RlcmluZyB0aGUgcm91dGUpIHdoZW4gdGhlIG1vZGVsIGJsb2NrcyB0aGF0IENSVUQgb3BlcmF0aW9uLlxuICogQHN1bW1hcnkgTWFwcyBhbiBIVFRQIHZlcmIgdG8gaXRzIGNvcnJlc3BvbmRpbmcgYENydWRPcGVyYXRpb25zYCBrZXkgYW5kIE5lc3QgSFRUUCBkZWNvcmF0b3IgKGBAR2V0YCwgYEBQb3N0YCwgZXRjLikuIEl0IGNoZWNrcyBgaXNPcGVyYXRpb25CbG9ja2VkKE1vZGVsQ29uc3RydWN0b3IsIGNydWRPcClgIGFuZCwgaWYgYmxvY2tlZCwgYXBwbGllcyBvbmx5IGBAQXBpRXhjbHVkZUVuZHBvaW50KClgIChTd2FnZ2VyLWhpZGRlbiwgbm8gTmVzdCByb3V0ZSkuIElmIHBlcm1pdHRlZCwgaXQgYXBwbGllcyB0aGUgYXBwcm9wcmlhdGUgSFRUUCBkZWNvcmF0b3Igd2l0aCB0aGUgb3B0aW9uYWwgYHBhdGhgLlxuICogQHBhcmFtIHtNb2RlbENvbnN0cnVjdG9yPGFueT59IE1vZGVsQ29uc3RydWN0b3IgLSBUaGUgbW9kZWwgY29uc3RydWN0b3IgdXNlZCB0byByZXNvbHZlIG9wZXJhdGlvbi1ibG9ja2luZyBydWxlcy5cbiAqIEBwYXJhbSB7SHR0cFZlcmJzfSB2ZXJiIC0gVGhlIEhUVFAgdmVyYiB0byBtYXAgKGUuZy4sIGBcIkdFVFwiIHwgXCJQT1NUXCIgfCBcIlBVVFwiIHwgXCJQQVRDSFwiIHwgXCJERUxFVEVcImApLlxuICogQHBhcmFtIHtzdHJpbmd9IFtwYXRoXSAtIE9wdGlvbmFsIHJvdXRlIHBhdGggcGFzc2VkIHRocm91Z2ggdG8gdGhlIGNvcnJlc3BvbmRpbmcgTmVzdCBIVFRQIG1ldGhvZCBkZWNvcmF0b3IuXG4gKiBAcmV0dXJuIHtNZXRob2REZWNvcmF0b3J9IEEgbWV0aG9kIGRlY29yYXRvciB0aGF0IGVpdGhlciBleGNsdWRlcyB0aGUgZW5kcG9pbnQgZnJvbSBTd2FnZ2VyIChhbmQgcm91dGUgcmVnaXN0cmF0aW9uKSBvciBhcHBsaWVzIHRoZSBjb3JyZWN0IEhUVFAgZGVjb3JhdG9yLlxuICovXG5leHBvcnQgZnVuY3Rpb24gQnVsa0FwaU9wZXJhdGlvbkZyb21Nb2RlbChcbiAgTW9kZWxDb25zdHJ1Y3RvcjogTW9kZWxDb25zdHJ1Y3Rvcjxhbnk+LFxuICB2ZXJiOiBIdHRwVmVyYnMsXG4gIHBhdGg/OiBzdHJpbmdcbik6IE1ldGhvZERlY29yYXRvciB7XG4gIGNvbnN0IGh0dHBUb0NydWQ6IFJlY29yZDxcbiAgICBIdHRwVmVyYnMsXG4gICAgW0J1bGtDcnVkT3BlcmF0aW9uS2V5cywgKHBhdGg/OiBzdHJpbmcpID0+IE1ldGhvZERlY29yYXRvcl1cbiAgPiA9IHtcbiAgICBHRVQ6IFtCdWxrQ3J1ZE9wZXJhdGlvbktleXMuUkVBRF9BTEwsIEdldF0sXG4gICAgUE9TVDogW0J1bGtDcnVkT3BlcmF0aW9uS2V5cy5DUkVBVEVfQUxMLCBQb3N0XSxcbiAgICBQVVQ6IFtCdWxrQ3J1ZE9wZXJhdGlvbktleXMuVVBEQVRFX0FMTCwgUHV0XSxcbiAgICBQQVRDSDogW0J1bGtDcnVkT3BlcmF0aW9uS2V5cy5VUERBVEVfQUxMLCBQYXRjaF0sXG4gICAgREVMRVRFOiBbQnVsa0NydWRPcGVyYXRpb25LZXlzLkRFTEVURV9BTEwsIERlbGV0ZV0sXG4gIH07XG5cbiAgY29uc3QgW2NydWRPcCwgSHR0cE1ldGhvZERlY29yYXRvcl0gPSBodHRwVG9DcnVkW3ZlcmJdO1xuICBjb25zdCB0YXJnZXQgPSBwYXRoID8gcmVzb2x2ZUJsb2NrVGFyZ2V0KHZlcmIsIHBhdGgpIDogdW5kZWZpbmVkO1xuICByZXR1cm4gdGFyZ2V0XG4gICAgPyBjb3JlSXNPcGVyYXRpb25CbG9ja2VkKE1vZGVsQ29uc3RydWN0b3IsIHRhcmdldC5raW5kIGFzIGFueSwgdGFyZ2V0LnZhbHVlKVxuICAgICAgPyBhcHBseShBcGlFeGNsdWRlRW5kcG9pbnQoKSlcbiAgICAgIDogYXBwbHkoSHR0cE1ldGhvZERlY29yYXRvcihwYXRoKSlcbiAgICA6IGNvcmVJc09wZXJhdGlvbkJsb2NrZWQoTW9kZWxDb25zdHJ1Y3RvciwgXCJidWxrXCIgYXMgYW55LCBjcnVkT3AgYXMgYW55KVxuICAgID8gYXBwbHkoQXBpRXhjbHVkZUVuZHBvaW50KCkpXG4gICAgOiBhcHBseShIdHRwTWV0aG9kRGVjb3JhdG9yKHBhdGgpKTtcbn1cbmZ1bmN0aW9uIHJlc29sdmVCbG9ja1RhcmdldChcbiAgdmVyYjogSHR0cFZlcmJzLFxuICBwYXRoPzogc3RyaW5nXG4pOiB7IGtpbmQ6IFwiY3J1ZFwiIHwgXCJzdGF0ZW1lbnRcIiB8IFwicXVlcnlcIiB8IFwiYnVsa1wiOyB2YWx1ZTogc3RyaW5nIH0gfCB1bmRlZmluZWQge1xuICBpZiAoIXBhdGgpIHJldHVybiB1bmRlZmluZWQ7XG5cbiAgY29uc3Qgbm9ybWFsaXplZCA9IHBhdGgucmVwbGFjZSgvXlxcLyt8XFwvKyQvZywgXCJcIik7XG4gIGNvbnN0IHN0YXRlbWVudFRhcmdldHM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7XG4gICAgXCJsaXN0QnkvOmtleVwiOiBQcmVwYXJlZFN0YXRlbWVudEtleXMuTElTVF9CWSxcbiAgICBcInBhZ2luYXRlQnkvOmtleS86cGFnZVwiOiBQcmVwYXJlZFN0YXRlbWVudEtleXMuUEFHRV9CWSxcbiAgICBcImZpbmQvOnZhbHVlXCI6IFByZXBhcmVkU3RhdGVtZW50S2V5cy5GSU5ELFxuICAgIFwicGFnZS86dmFsdWVcIjogUHJlcGFyZWRTdGF0ZW1lbnRLZXlzLlBBR0UsXG4gICAgXCJmaW5kT25lQnkvOmtleS86dmFsdWVcIjogUHJlcGFyZWRTdGF0ZW1lbnRLZXlzLkZJTkRfT05FX0JZLFxuICAgIFwiZmluZEJ5LzprZXkvOnZhbHVlXCI6IFByZXBhcmVkU3RhdGVtZW50S2V5cy5GSU5EX0JZLFxuICAgIFwic3RhdGVtZW50LzptZXRob2QvKmFyZ3NcIjogXCJzdGF0ZW1lbnRcIixcbiAgICBcImNvdW50T2YvOmZpZWxkXCI6IFByZXBhcmVkU3RhdGVtZW50S2V5cy5DT1VOVF9PRixcbiAgICBcIm1heE9mLzpmaWVsZFwiOiBQcmVwYXJlZFN0YXRlbWVudEtleXMuTUFYX09GLFxuICAgIFwibWluT2YvOmZpZWxkXCI6IFByZXBhcmVkU3RhdGVtZW50S2V5cy5NSU5fT0YsXG4gICAgXCJhdmdPZi86ZmllbGRcIjogUHJlcGFyZWRTdGF0ZW1lbnRLZXlzLkFWR19PRixcbiAgICBcInN1bU9mLzpmaWVsZFwiOiBQcmVwYXJlZFN0YXRlbWVudEtleXMuU1VNX09GLFxuICAgIFwiZGlzdGluY3RPZi86ZmllbGRcIjogUHJlcGFyZWRTdGF0ZW1lbnRLZXlzLkRJU1RJTkNUX09GLFxuICAgIFwiZ3JvdXBPZi86ZmllbGRcIjogUHJlcGFyZWRTdGF0ZW1lbnRLZXlzLkdST1VQX09GLFxuICB9O1xuXG4gIGlmIChub3JtYWxpemVkLnN0YXJ0c1dpdGgoXCJxdWVyeS9cIikpIHtcbiAgICByZXR1cm4geyBraW5kOiBcInF1ZXJ5XCIsIHZhbHVlOiBub3JtYWxpemVkLnJlcGxhY2UoL15xdWVyeVxcLy8sIFwiXCIpIH07XG4gIH1cblxuICBjb25zdCBzdGF0ZW1lbnRWYWx1ZSA9IHN0YXRlbWVudFRhcmdldHNbbm9ybWFsaXplZF07XG4gIGlmIChzdGF0ZW1lbnRWYWx1ZSkge1xuICAgIHJldHVybiB7IGtpbmQ6IFwic3RhdGVtZW50XCIsIHZhbHVlOiBzdGF0ZW1lbnRWYWx1ZSB9O1xuICB9XG5cbiAgaWYgKHZlcmIgPT09IFwiR0VUXCIgJiYgbm9ybWFsaXplZCA9PT0gXCJcIikge1xuICAgIHJldHVybiB7IGtpbmQ6IFwiY3J1ZFwiLCB2YWx1ZTogT3BlcmF0aW9uS2V5cy5SRUFEIH07XG4gIH1cblxuICByZXR1cm4gdW5kZWZpbmVkO1xufVxuIiwiaW1wb3J0IHsgYXBwbHlEZWNvcmF0b3JzIH0gZnJvbSBcIkBuZXN0anMvY29tbW9uXCI7XG5pbXBvcnQgeyBBcGlQYXJhbSBhcyBBcGlQYXJhbURlYyB9IGZyb20gXCJAbmVzdGpzL3N3YWdnZXJcIjtcbmltcG9ydCB0eXBlIHsgRGVjYWZBcGlQcm9wZXJ0eSB9IGZyb20gXCIuL3R5cGVzXCI7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIEFwcGxpZXMgYSBzZXQgb2YgU3dhZ2dlciBgQEFwaVBhcmFtYCBkZWNvcmF0b3JzIGdlbmVyYXRlZCBmcm9tIGEgdHlwZWQgc3BlY2lmaWNhdGlvbiBhcnJheS5cbiAqIEBzdW1tYXJ5IFRyYW5zZm9ybXMgZWFjaCBlbnRyeSBvZiB0aGUgcHJvdmlkZWQgYEFwaVBhcmFtW11gIGludG8gYSBjb3JyZXNwb25kaW5nIGBAQXBpUGFyYW0oKWAgZGVjb3JhdG9yIChkZWZhdWx0aW5nIGBkZXNjcmlwdGlvbmAsIGByZXF1aXJlZGAsIGFuZCBgdHlwZWAgd2hlbiBvbWl0dGVkKSBhbmQgY29tcG9zZXMgdGhlbSBpbnRvIGEgc2luZ2xlIGRlY29yYXRvciB2aWEgTmVzdCdzIGBhcHBseURlY29yYXRvcnNgLiBVc2VmdWwgZm9yIHN5bmNocm9uaXppbmcgcnVudGltZSByb3V0ZSBwYXJhbXMgd2l0aCBPcGVuQVBJIGRvY3VtZW50YXRpb24gaW4gYSBjb25jaXNlLCBkZWNsYXJhdGl2ZSB3YXkuXG4gKiBAcGFyYW0ge0FwaVBhcmFtW119IFtwcm9wcz1bXV0gQXJyYXkgZGVzY3JpYmluZyBwYXRoIHBhcmFtZXRlcnMgdG8gYmUgZG9jdW1lbnRlZC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBwcm9wc1tdLm5hbWUgVGhlIHBhcmFtZXRlcidzIG5hbWUgYXMgaXQgYXBwZWFycyBpbiB0aGUgcm91dGUgdGVtcGxhdGUgKGUuZy4sIGA6aWRgKS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBbcHJvcHNbXS5kZXNjcmlwdGlvbl0gSHVtYW4tcmVhZGFibGUgZXhwbGFuYXRpb24gb2YgdGhlIHBhcmFtZXRlcjsgZGVmYXVsdHMgdG8gYFwiUGF0aCBwYXJhbWV0ZXI6IDxuYW1lPlwiYC5cbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW3Byb3BzW10ucmVxdWlyZWQ9dHJ1ZV0gV2hldGhlciB0aGUgcGFyYW1ldGVyIGlzIHJlcXVpcmVkOyBkZWZhdWx0cyB0byBgdHJ1ZWAuXG4gKiBAcGFyYW0ge0NvbnN0cnVjdG9yPGFueT59IFtwcm9wc1tdLnR5cGU9U3RyaW5nXSBDb25zdHJ1Y3Rvci90eXBlIHVzZWQgYnkgU3dhZ2dlciB0byBpbmZlciBzY2hlbWEgKGUuZy4sIGBTdHJpbmdgLCBgTnVtYmVyYCwgYFVVSURgLCBjdXN0b20gY2xhc3MpLlxuICogQHJldHVybiB7YW55fSBBIGNvbXBvc2VkIGRlY29yYXRvciBhcHBseWluZyBhbGwgZ2VuZXJhdGVkIGBAQXBpUGFyYW1gIGRlY29yYXRvcnMgdG8gdGhlIHRhcmdldCBtZXRob2Qgb3IgY29udHJvbGxlci5cbiAqIEBmdW5jdGlvbiBBcGlQYXJhbXNGcm9tTW9kZWxcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIEFwaVBhcmFtc0Zyb21Nb2RlbChcbiAgcHJvcHM6IERlY2FmQXBpUHJvcGVydHlbXSA9IFtdXG4pOiBNZXRob2REZWNvcmF0b3IgJiBDbGFzc0RlY29yYXRvciB7XG4gIGNvbnN0IGRlY29yYXRvcnMgPSBwcm9wcy5tYXAoKHApID0+XG4gICAgQXBpUGFyYW1EZWMoe1xuICAgICAgbmFtZTogcC5uYW1lLFxuICAgICAgZGVzY3JpcHRpb246IHAuZGVzY3JpcHRpb24gPz8gYFBhdGggcGFyYW1ldGVyOiAke3AubmFtZX1gLFxuICAgICAgcmVxdWlyZWQ6IHAucmVxdWlyZWQgPz8gdHJ1ZSxcbiAgICAgIC8vIHNjaGVtYTogeyB0eXBlOiAnc3RyaW5nJyB9LFxuICAgICAgdHlwZTogcC50eXBlID8/IFN0cmluZyxcbiAgICB9KVxuICApO1xuICByZXR1cm4gYXBwbHlEZWNvcmF0b3JzKC4uLmRlY29yYXRvcnMpO1xufVxuIiwiaW1wb3J0IHtcbiAgY3JlYXRlUGFyYW1EZWNvcmF0b3IsXG4gIEV4ZWN1dGlvbkNvbnRleHQsXG4gIEludGVybmFsU2VydmVyRXJyb3JFeGNlcHRpb24sXG59IGZyb20gXCJAbmVzdGpzL2NvbW1vblwiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBDdXN0b20gZGVjb3JhdG9yIHRoYXQgZXh0cmFjdHMgdGhlIHJlcXVlc3QgYm9keSBhbmQgaW5zdGFudGlhdGVzIGl0IHVzaW5nIHRoZSBNb2RlbCBjb25zdHJ1Y3RvclxuICogZm91bmQgb24gdGhlIGNvbnRyb2xsZXIuIEhhbmRsZXMgYm90aCBzaW5nbGUgb2JqZWN0cyBhbmQgYXJyYXlzLlxuICovXG5leHBvcnQgY29uc3QgRGVjYWZCb2R5ID0gY3JlYXRlUGFyYW1EZWNvcmF0b3IoXG4gIChkYXRhOiB1bmtub3duLCBjdHg6IEV4ZWN1dGlvbkNvbnRleHQpID0+IHtcbiAgICBjb25zdCByZXF1ZXN0ID0gY3R4LnN3aXRjaFRvSHR0cCgpLmdldFJlcXVlc3QoKTtcbiAgICBjb25zdCBib2R5ID0gcmVxdWVzdC5ib2R5O1xuXG4gICAgLy8gVGhlIER5bmFtaWNNb2RlbENvbnRyb2xsZXIgd2lsbCBoYXZlICdNb2RlbENvbnN0cicgYXZhaWxhYmxlXG4gICAgY29uc3QgY29udHJvbGxlciA9IGN0eC5nZXRDbGFzcygpO1xuICAgIC8vIFdlIGFjY2VzcyB0aGUgc3RhdGljIHByb3BlcnR5IHdlIHdpbGwgYWRkIHRvIHRoZSBEeW5hbWljTW9kZWxDb250cm9sbGVyXG4gICAgY29uc3QgTW9kZWxDb25zdHIgPSAoY29udHJvbGxlciBhcyBhbnkpLmNsYXNzO1xuXG4gICAgaWYgKCFNb2RlbENvbnN0cikge1xuICAgICAgdGhyb3cgbmV3IEludGVybmFsU2VydmVyRXJyb3JFeGNlcHRpb24oXG4gICAgICAgIGBNb2RlbENvbnN0cnVjdG9yIG5vdCBmb3VuZCBvbiBjb250cm9sbGVyICR7Y29udHJvbGxlci5uYW1lfS4gRW5zdXJlIHRoZSBjb250cm9sbGVyIHdhcyBjcmVhdGVkIHZpYSBGcm9tTW9kZWxDb250cm9sbGVyLmBcbiAgICAgICk7XG4gICAgfVxuXG4gICAgaWYgKCFib2R5KSByZXR1cm4gYm9keTtcblxuICAgIGlmIChBcnJheS5pc0FycmF5KGJvZHkpKSB7XG4gICAgICByZXR1cm4gYm9keS5tYXAoKGl0ZW0pID0+IG5ldyBNb2RlbENvbnN0cihpdGVtKSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIG5ldyBNb2RlbENvbnN0cihib2R5KTtcbiAgfVxuKTtcbiIsImltcG9ydCB7IGNyZWF0ZVBhcmFtRGVjb3JhdG9yLCBFeGVjdXRpb25Db250ZXh0IH0gZnJvbSBcIkBuZXN0anMvY29tbW9uXCI7XG5pbXBvcnQgeyBEZWNhZlBhcmFtUHJvcHMsIERlY2FmQXBpUHJvcGVydHkgfSBmcm9tIFwiLi90eXBlc1wiO1xuLyoqXG4gKiBAZGVzY3JpcHRpb24gQ3JlYXRlcyBhIGN1c3RvbSBOZXN0SlMgcGFyYW1ldGVyIGRlY29yYXRvciB0aGF0IGV4dHJhY3RzIGFuZCByZXR1cm5zIHJvdXRlIHBhcmFtZXRlcnMgb3JkZXJlZCBieSBhIHNwZWNpZmljIGtleSBzZXF1ZW5jZS5cbiAqIEBzdW1tYXJ5IFRoZSBgT3JkZXJlZFBhcmFtc2AgZGVjb3JhdG9yIHJlYWRzIHRoZSBpbmNvbWluZyBIVFRQIHJlcXVlc3QncyBgcGFyYW1zYCBvYmplY3QsIG9wdGlvbmFsbHkgb3JkZXJzIGl0IGFjY29yZGluZyB0byBhIHByb3ZpZGVkIGxpc3Qgb2YgcGFyYW1ldGVyIG5hbWVzLCBhbmQgcmV0dXJucyBhbiBvYmplY3QgY29udGFpbmluZyB0aGUgb3JpZ2luYWwgcGFyYW1zLCB0aGUgb3JkZXJlZCB2YWx1ZXMsIGFuZCB0aGUgYXBwbGllZCBvcmRlciBsaXN0LiBUaGlzIGVuc3VyZXMgZGV0ZXJtaW5pc3RpYyBwYXJhbWV0ZXIgYWNjZXNzIGZvciByb3V0ZXMgd2l0aCBtdWx0aXBsZSBwYXRoIHBhcmFtZXRlcnMuXG4gKiBAdGVtcGxhdGUge3N0cmluZ1tdfSBUT3JkZXIgLSBSZXByZXNlbnRzIHRoZSBleHBlY3RlZCBzZXF1ZW5jZSBvZiBwYXJhbWV0ZXIgbmFtZXMuXG4gKiBAcGFyYW0ge1RPcmRlciB8IHVuZGVmaW5lZH0gb3JkZXIgQW4gb3B0aW9uYWwgYXJyYXkgc3BlY2lmeWluZyB0aGUgcGFyYW1ldGVyIG5hbWVzJyBkZXNpcmVkIG9yZGVyLiBJZiBub3QgcHJvdmlkZWQsIHRoZSBkZWNvcmF0b3Igd2lsbCBwcmVzZXJ2ZSB0aGUgb3JkZXIgb2YgdGhlIGtleXMgYXMgdGhleSBhcHBlYXIgaW4gdGhlIG9yaWdpbmFsIGByZXEucGFyYW1zYCBvYmplY3QuXG4gKiBAcGFyYW0ge0V4ZWN1dGlvbkNvbnRleHR9IGN0eCBUaGUgTmVzdEpTIGV4ZWN1dGlvbiBjb250ZXh0LCB1c2VkIHRvIHJldHJpZXZlIHRoZSBjdXJyZW50IEhUVFAgcmVxdWVzdCBvYmplY3QuXG4gKiBAcmV0dXJuIHtEZWNhZlBhcmFtUHJvcHN9IEFuIG9iamVjdCBjb250YWluaW5nOlxuICogLSBgb3JpZ2luYWxgOiB0aGUgcmF3IHBhcmFtZXRlciBtYXAgZnJvbSBgcmVxLnBhcmFtc2A7XG4gKiAtIGBvcmRlcmVkYDogYW4gYXJyYXkgb2YgcGFyYW1ldGVyIHZhbHVlcyBpbiB0aGUgcmVxdWVzdGVkIG9yZGVyO1xuICogLSBgb3JkZXJgOiB0aGUgZWZmZWN0aXZlIG9yZGVyIGxpc3QgdXNlZC5cbiAqIEBmdW5jdGlvbiBPcmRlcmVkUGFyYW1zXG4gKi9cbmNvbnN0IE9yZGVyZWRQYXJhbXMgPSBjcmVhdGVQYXJhbURlY29yYXRvcihcbiAgKG9yZGVyOiBzdHJpbmdbXSB8IHVuZGVmaW5lZCwgY3R4OiBFeGVjdXRpb25Db250ZXh0KTogRGVjYWZQYXJhbVByb3BzID0+IHtcbiAgICBjb25zdCByZXEgPSBjdHguc3dpdGNoVG9IdHRwKCkuZ2V0UmVxdWVzdCgpO1xuICAgIGNvbnN0IG9yaWdpbmFsID0gKHJlcT8ucGFyYW1zID8/IHt9KSBhcyBSZWNvcmQ8c3RyaW5nLCBhbnk+O1xuICAgIGNvbnN0IG9yZGVyTGlzdCA9IG9yZGVyID8/IE9iamVjdC5rZXlzKG9yaWdpbmFsKTtcbiAgICBjb25zdCBvcmRlcmVkID0gb3JkZXJMaXN0Lm1hcCgoaykgPT4gb3JpZ2luYWxba10pO1xuICAgIHJldHVybiB7IHJhdzogb3JpZ2luYWwsIHZhbHVlc0luT3JkZXI6IG9yZGVyZWQsIGtleXNJbk9yZGVyOiBvcmRlckxpc3QgfTtcbiAgfVxuKTtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gQSBoaWdoZXItbGV2ZWwgZGVjb3JhdG9yIGZhY3RvcnkgdGhhdCBsZXZlcmFnZXMgYE9yZGVyZWRQYXJhbXNgIHRvIGV4dHJhY3Qgcm91dGUgcGFyYW1ldGVycyBpbiBhIHNwZWNpZmljIG9yZGVyIGRlcml2ZWQgZnJvbSBhIGxpc3Qgb2YgYEFwaVBhcmFtYCBkZWZpbml0aW9ucy5cbiAqIEBzdW1tYXJ5IGBEZWNhZlBhcmFtc2AgY29tcHV0ZXMgdGhlIG9yZGVyIG9mIHJvdXRlIHBhcmFtZXRlcnMgYmFzZWQgb24gdGhlIHByb3ZpZGVkIGBBcGlQYXJhbVtdYCBzcGVjaWZpY2F0aW9uICh1c2luZyBlYWNoIGVsZW1lbnTigJlzIGBuYW1lYCksIHRoZW4gYXBwbGllcyBgT3JkZXJlZFBhcmFtcyhvcmRlcilgIGFzIGEgcGFyYW1ldGVyIGRlY29yYXRvci4gVGhpcyBlbmFibGVzIHBhcmFtZXRlci1sZXZlbCBiaW5kaW5nIHRoYXQgcmVtYWlucyBjb25zaXN0ZW50IHdpdGggdGhlIGRvY3VtZW50ZWQgQVBJIHBhcmFtZXRlciBtZXRhZGF0YS5cbiAqIEBwYXJhbSB7QXBpUGFyYW1bXX0gW3Byb3BzPVtdXSBBcnJheSBvZiBgQXBpUGFyYW1gIGRlZmluaXRpb25zIHdob3NlIGBuYW1lYCBmaWVsZHMgZGV0ZXJtaW5lIHRoZSBwYXJhbWV0ZXIgZXh0cmFjdGlvbiBvcmRlci5cbiAqIEByZXR1cm4ge1BhcmFtZXRlckRlY29yYXRvcn0gQSBOZXN0SlMgcGFyYW1ldGVyIGRlY29yYXRvciB0aGF0IGluamVjdHMgYW4gb3JkZXJlZCBsaXN0IG9mIHBhcmFtZXRlcnMgYW5kIG1ldGFkYXRhIGludG8gdGhlIGNvbnRyb2xsZXIgbWV0aG9kIGFyZ3VtZW50LlxuICovXG5leHBvcnQgZnVuY3Rpb24gRGVjYWZQYXJhbXMoXG4gIHByb3BzOiBEZWNhZkFwaVByb3BlcnR5W10gPSBbXVxuKTogUGFyYW1ldGVyRGVjb3JhdG9yIHtcbiAgY29uc3Qgb3JkZXIgPSBwcm9wcy5tYXAoKHApID0+IHAubmFtZSk7XG4gIHJldHVybiBPcmRlcmVkUGFyYW1zKG9yZGVyKTtcbn1cblxuZXhwb3J0IGNvbnN0IERlY2FmUXVlcnkgPSBjcmVhdGVQYXJhbURlY29yYXRvcihcbiAgKF86IHVua25vd24sIGN0eDogRXhlY3V0aW9uQ29udGV4dCkgPT4ge1xuICAgIGNvbnN0IHJlcSA9IGN0eC5zd2l0Y2hUb0h0dHAoKS5nZXRSZXF1ZXN0KCk7XG4gICAgY29uc3QgcXVlcnkgPSByZXEucXVlcnkgPz8ge307XG5cbiAgICBjb25zdCBwYXJzZWQ6IGFueSA9IHsgLi4ucXVlcnkgfTtcblxuICAgIC8vIFBhcnNlIGxpbWl0ICYgb2Zmc2V0XG4gICAgaWYgKHBhcnNlZC5saW1pdCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBjb25zdCBuID0gTnVtYmVyKHBhcnNlZC5saW1pdCk7XG4gICAgICBpZiAoIU51bWJlci5pc05hTihuKSkgcGFyc2VkLmxpbWl0ID0gbjtcbiAgICB9XG5cbiAgICBpZiAocGFyc2VkLm9mZnNldCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBjb25zdCBuID0gTnVtYmVyKHBhcnNlZC5vZmZzZXQpO1xuICAgICAgaWYgKCFOdW1iZXIuaXNOYU4obikpIHBhcnNlZC5vZmZzZXQgPSBuO1xuICAgIH1cblxuICAgIC8vIFBhcnNlIGJvb2ttYXJrIG9ubHkgaWYgbnVtZXJpY1xuICAgIGlmIChwYXJzZWQuYm9va21hcmsgIT09IHVuZGVmaW5lZCkge1xuICAgICAgY29uc3QgbiA9IE51bWJlcihwYXJzZWQuYm9va21hcmspO1xuICAgICAgcGFyc2VkLmJvb2ttYXJrID0gTnVtYmVyLmlzTmFOKG4pID8gcGFyc2VkLmJvb2ttYXJrIDogbjtcbiAgICB9XG5cbiAgICByZXR1cm4gcGFyc2VkO1xuICB9XG4pO1xuIiwiaW1wb3J0IHsgQWRhcHRlckZsYWdzLCBDb250ZXh0IH0gZnJvbSBcIkBkZWNhZi10cy9jb3JlXCI7XG5pbXBvcnQgeyBMb2dnZXIgfSBmcm9tIFwiQGRlY2FmLXRzL2xvZ2dpbmdcIjtcblxuZXhwb3J0IGNvbnN0IERFQ0FGX01PRFVMRV9PUFRJT05TID0gXCJEZWNhZk1vZHVsZU9wdGlvbnNcIjtcbmV4cG9ydCBjb25zdCBERUNBRl9BREFQVEVSX0lEID0gXCJEZWNhZkFkYXB0ZXJcIjtcbmV4cG9ydCBjb25zdCBERUNBRl9UQVNLX1NFUlZJQ0VfSUQgPSBcIkRlY2FmVGFza1NlcnZpY2VcIjtcblxuZXhwb3J0IGNvbnN0IERFQ0FGX1JPVVRFID0gXCJEZWNhZlJvdXRlXCI7XG5leHBvcnQgY29uc3QgREVDQUZfSEFORExFUlMgPSBTeW1ib2woXCJEZWNhZkhhbmRsZXJzXCIpO1xuZXhwb3J0IGNvbnN0IERFQ0FGX0VYUE9TRSA9IFwiRGVjYWZFeHBvc2VcIjtcbmV4cG9ydCBjb25zdCBERUNBRl9DT05UUk9MTEVSX0NPTkZJRyA9IFwiRGVjYWZDb250cm9sbGVyQ29uZmlnXCI7XG5cbmV4cG9ydCBjb25zdCBERUNBRl9DT05URVhUX0tFWSA9IFN5bWJvbChcImRlY2FmOmNvbnRleHRcIik7XG5cbmV4cG9ydCB0eXBlIERlY2FmU2VydmVyRmxhZ3M8TE9HIGV4dGVuZHMgTG9nZ2VyID0gTG9nZ2VyPiA9XG4gIEFkYXB0ZXJGbGFnczxMT0c+ICYge1xuICAgIGhlYWRlcnM6IFJlY29yZDxzdHJpbmcsIGFueT47XG4gICAgb3ZlcnJpZGVzOiBSZWNvcmQ8c3RyaW5nLCBhbnk+O1xuICB9O1xuXG5leHBvcnQgdHlwZSBEZWNhZlNlcnZlckN0eCA9IENvbnRleHQ8RGVjYWZTZXJ2ZXJGbGFncz47XG4iLCJpbXBvcnQgeyBNZXRhZGF0YSB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdGlvblwiO1xuXG5pbXBvcnQgeyBERUNBRl9FWFBPU0UgfSBmcm9tIFwiLi4vLi4vY29uc3RhbnRzXCI7XG5cbmV4cG9ydCBmdW5jdGlvbiBleHBvc2UoLi4uZmxhdm91cnM6IHN0cmluZ1tdKSB7XG4gIHJldHVybiBmdW5jdGlvbiBleHBvc2UodGFyZ2V0OiBhbnkpIHtcbiAgICBNZXRhZGF0YS5zZXQoXG4gICAgICB0YXJnZXQsXG4gICAgICBERUNBRl9FWFBPU0UsXG4gICAgICAoZmxhdm91cnMubGVuZ3RoID8gZmxhdm91cnMgOiB0cnVlKSBhcyBhbnlcbiAgICApO1xuICAgIHJldHVybiB0YXJnZXQ7XG4gIH07XG59XG4iLCJpbXBvcnQgeyBNZXRhZGF0YSB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdGlvblwiO1xuaW1wb3J0IHR5cGUgeyBNb2RlbENvbnRyb2xsZXJGYWN0b3J5Q29uZmlnIH0gZnJvbSBcIkBkZWNhZi10cy9mb3ItaHR0cC9zZXJ2ZXJcIjtcblxuaW1wb3J0IHsgREVDQUZfQ09OVFJPTExFUl9DT05GSUcgfSBmcm9tIFwiLi4vLi4vY29uc3RhbnRzXCI7XG5cbi8qKlxuICogQ2xhc3MgZGVjb3JhdG9yIHRoYXQgYXR0YWNoZXMgYSB7QGxpbmsgTW9kZWxDb250cm9sbGVyRmFjdG9yeUNvbmZpZ30gdG8gYSBNb2RlbCxcbiAqIHNvIGBGcm9tTW9kZWxDb250cm9sbGVyLmNyZWF0ZSgpYCBjYW4gcGFzcyBpdCB0byBgTW9kZWxDb250cm9sbGVyRmFjdG9yeS5jcmVhdGUoKWAuXG4gKlxuICogVGhlIHBlci1tb2RlbCBjb25maWcgY2FuIGJlIG92ZXJyaWRkZW4gYnkgdGhlIG1vZHVsZS1sZXZlbCBgY29udHJvbGxlckNvbmZpZ2BcbiAqIG9wdGlvbiBpbiBgRGVjYWZNb2R1bGVPcHRpb25zYC5cbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHNcbiAqIEBjb250cm9sbGVyQ29uZmlnKHsgYWxsb3dHcm91cGluZ1F1ZXJpZXM6IHRydWUsIGFsbG93QnVsa1N0YXRlbWVudDogeyBjcmVhdGU6IHRydWUsIHJlYWQ6IHRydWUsIHVwZGF0ZTogZmFsc2UsIGRlbGV0ZTogdHJ1ZSB9IH0pXG4gKiBAbW9kZWwoKVxuICogY2xhc3MgT3JkZXIgZXh0ZW5kcyBNb2RlbDxPcmRlcj4geyAuLi4gfVxuICogYGBgXG4gKlxuICogQHBhcmFtIGNvbmZpZyAtIEZhY3RvcnkgY29uZmlndXJhdGlvbiBrbm9icyAoYWxsb3dTdGF0ZW1lbnRsZXNzUXVlcnksIGFsbG93R3JvdXBpbmdRdWVyaWVzLCBhbGxvd0J1bGtTdGF0ZW1lbnQpLlxuICovXG5leHBvcnQgZnVuY3Rpb24gY29udHJvbGxlckNvbmZpZyhjb25maWc6IE1vZGVsQ29udHJvbGxlckZhY3RvcnlDb25maWcpIHtcbiAgcmV0dXJuIGZ1bmN0aW9uIGNvbnRyb2xsZXJDb25maWdEZWNvcmF0b3IodGFyZ2V0OiBhbnkpIHtcbiAgICBNZXRhZGF0YS5zZXQodGFyZ2V0LCBERUNBRl9DT05UUk9MTEVSX0NPTkZJRywgY29uZmlnIGFzIGFueSk7XG4gICAgcmV0dXJuIHRhcmdldDtcbiAgfTtcbn1cbiIsImV4cG9ydCBjb25zdCBBVVRIX0hBTkRMRVIgPSBTeW1ib2woXCJBVVRIX0hBTkRMRVJcIik7XG5leHBvcnQgY29uc3QgQVVUSF9NRVRBX0tFWSA9IFwiYXV0aDptZXRhXCI7XG5leHBvcnQgY29uc3QgSVNfUFVCTElDX0tFWSA9IFwiaXNQdWJsaWNcIjtcbmV4cG9ydCBjb25zdCBSRVFVSVJFRF9ST0xFU19LRVkgPSBcInJlcXVpcmVkUm9sZXNcIjtcbmV4cG9ydCBjb25zdCBTS0lQX01PREVMX1JPTEVTX0tFWSA9IFwic2tpcE1vZGVsUm9sZXNcIjtcbiIsImltcG9ydCB7IEluamVjdCwgSW5qZWN0YWJsZSwgU2NvcGUgfSBmcm9tIFwiQG5lc3Rqcy9jb21tb25cIjtcbmltcG9ydCB7IFJFUVVFU1QgfSBmcm9tIFwiQG5lc3Rqcy9jb3JlXCI7XG5pbXBvcnQgeyBVVUlEIH0gZnJvbSBcIkBkZWNhZi10cy9jb3JlXCI7XG5pbXBvcnQgeyBSZXF1ZXN0Q29udGV4dCB9IGZyb20gXCJAZGVjYWYtdHMvZm9yLWh0dHAvc2VydmVyXCI7XG5pbXBvcnQgeyB0eXBlIFJlcXVlc3QgfSBmcm9tIFwiZXhwcmVzc1wiO1xuXG5pbXBvcnQgeyBEZWNhZlNlcnZlckN0eCB9IGZyb20gXCIuLi9jb25zdGFudHNcIjtcblxuQEluamVjdGFibGUoeyBzY29wZTogU2NvcGUuUkVRVUVTVCB9KVxuZXhwb3J0IGNsYXNzIERlY2FmUmVxdWVzdENvbnRleHQ8QyBleHRlbmRzIERlY2FmU2VydmVyQ3R4ID0gRGVjYWZTZXJ2ZXJDdHg+IGV4dGVuZHMgUmVxdWVzdENvbnRleHQ8UmVxdWVzdD4ge1xuICB1dWlkID0gVVVJRC5pbnN0YW5jZS5nZW5lcmF0ZSgpO1xuICBvdmVycmlkZSByZWFkb25seSByZXF1ZXN0OiBSZXF1ZXN0O1xuXG4gIGNvbnN0cnVjdG9yKEBJbmplY3QoUkVRVUVTVCkgcHJpdmF0ZSByZWFkb25seSByZXE6IFJlcXVlc3QpIHtcbiAgICBzdXBlcihcbiAgICAgIHtcbiAgICAgICAgaGVhZGVyc09mOiAocmVxdWVzdDogUmVxdWVzdCkgPT4gKHJlcXVlc3QgYXMgYW55KT8uaGVhZGVycyB8fCB1bmRlZmluZWQsXG4gICAgICB9IGFzIGFueSxcbiAgICAgIHJlcVxuICAgICk7XG4gICAgdGhpcy5yZXF1ZXN0ID0gcmVxO1xuICB9XG5cbiAgcHV0KHJlY29yZDogUmVjb3JkPGFueSwgYW55Pikge1xuICAgIGxldCBvdmVycmlkZXM6IGFueTtcbiAgICB0cnkge1xuICAgICAgb3ZlcnJpZGVzID0gdGhpcy5nZXQoXCJvdmVycmlkZXNcIik7XG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVudXNlZC12YXJzXG4gICAgfSBjYXRjaCAoZTogdW5rbm93bikge1xuICAgICAgb3ZlcnJpZGVzID0ge307XG4gICAgfVxuXG4gICAgdGhpcy5hY2N1bXVsYXRlKHtcbiAgICAgIG92ZXJyaWRlczogT2JqZWN0LmFzc2lnbihvdmVycmlkZXMsIHJlY29yZCksXG4gICAgfSk7XG4gIH1cbn1cbiIsImltcG9ydCB7XG4gIEluamVjdGFibGUsXG4gIE5lc3RJbnRlcmNlcHRvcixcbiAgRXhlY3V0aW9uQ29udGV4dCxcbiAgQ2FsbEhhbmRsZXIsXG4gIEluamVjdCxcbiAgT3B0aW9uYWwsXG4gIFNjb3BlLFxufSBmcm9tIFwiQG5lc3Rqcy9jb21tb25cIjtcbmltcG9ydCB7IFJlZmxlY3RvciB9IGZyb20gXCJAbmVzdGpzL2NvcmVcIjtcbmltcG9ydCB7IE9ic2VydmFibGUgfSBmcm9tIFwicnhqc1wiO1xuXG5pbXBvcnQgeyBDb25zdHJ1Y3RvciB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdGlvblwiO1xuaW1wb3J0IHsgTG9nZ2luZyB9IGZyb20gXCJAZGVjYWYtdHMvbG9nZ2luZ1wiO1xuaW1wb3J0IHsgQWRhcHRlciB9IGZyb20gXCJAZGVjYWYtdHMvY29yZVwiO1xuaW1wb3J0IHsgUmVxdWVzdFRvQ29udGV4dFRyYW5zZm9ybWVyIH0gZnJvbSBcIkBkZWNhZi10cy9mb3ItaHR0cC9zZXJ2ZXJcIjtcblxuaW1wb3J0IHsgQVVUSF9IQU5ETEVSLCBBVVRIX01FVEFfS0VZLCBJU19QVUJMSUNfS0VZLCBSRVFVSVJFRF9ST0xFU19LRVksIFNLSVBfTU9ERUxfUk9MRVNfS0VZIH0gZnJvbSBcIi4vY29uc3RhbnRzXCI7XG5pbXBvcnQgdHlwZSB7IEF1dGhIYW5kbGVyIH0gZnJvbSBcIi4uL3R5cGVzXCI7XG5pbXBvcnQgeyBEZWNhZlJlcXVlc3RDb250ZXh0IH0gZnJvbSBcIi4uL3JlcXVlc3QvRGVjYWZSZXF1ZXN0Q29udGV4dFwiO1xuXG5ASW5qZWN0YWJsZSh7IHNjb3BlOiBTY29wZS5SRVFVRVNUIH0pXG5leHBvcnQgY2xhc3MgQXV0aEludGVyY2VwdG9yIGltcGxlbWVudHMgTmVzdEludGVyY2VwdG9yIHtcbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSByZWFkb25seSByZWZsZWN0b3I6IFJlZmxlY3RvcixcbiAgICBwcm90ZWN0ZWQgcmVhZG9ubHkgcmVxdWVzdENvbnRleHQ6IERlY2FmUmVxdWVzdENvbnRleHQsXG4gICAgQE9wdGlvbmFsKCkgQEluamVjdChBVVRIX0hBTkRMRVIpIHByaXZhdGUgcmVhZG9ubHkgYXV0aEhhbmRsZXI/OiBBdXRoSGFuZGxlclxuICApIHt9XG5cbiAgYXN5bmMgaW50ZXJjZXB0KFxuICAgIGN0eDogRXhlY3V0aW9uQ29udGV4dCxcbiAgICBuZXh0OiBDYWxsSGFuZGxlclxuICApOiBQcm9taXNlPE9ic2VydmFibGU8YW55Pj4ge1xuICAgIGNvbnN0IGxvZyA9IExvZ2dpbmcuZm9yKHRoaXMgYXMgYW55KS5mb3IodGhpcy5pbnRlcmNlcHQpO1xuXG4gICAgY29uc3QgaXNQdWJsaWMgPSB0aGlzLnJlZmxlY3Rvci5nZXRBbGxBbmRPdmVycmlkZTxib29sZWFuPihJU19QVUJMSUNfS0VZLCBbXG4gICAgICBjdHguZ2V0SGFuZGxlcigpLFxuICAgICAgY3R4LmdldENsYXNzKCksXG4gICAgXSk7XG5cbiAgICBjb25zdCBtb2RlbE5hbWUgPVxuICAgICAgdGhpcy5yZWZsZWN0b3IuZ2V0PHN0cmluZyB8IENvbnN0cnVjdG9yPihcbiAgICAgICAgQVVUSF9NRVRBX0tFWSxcbiAgICAgICAgY3R4LmdldEhhbmRsZXIoKVxuICAgICAgKSA/P1xuICAgICAgdGhpcy5yZWZsZWN0b3IuZ2V0PHN0cmluZyB8IENvbnN0cnVjdG9yPihBVVRIX01FVEFfS0VZLCBjdHguZ2V0Q2xhc3MoKSk7XG5cbiAgICBjb25zdCByZXF1aXJlZFJvbGVzID0gdGhpcy5yZWZsZWN0b3IuZ2V0QWxsQW5kT3ZlcnJpZGU8c3RyaW5nW10+KFxuICAgICAgUkVRVUlSRURfUk9MRVNfS0VZLFxuICAgICAgW2N0eC5nZXRIYW5kbGVyKCksIGN0eC5nZXRDbGFzcygpXVxuICAgICk7XG5cbiAgICBjb25zdCBza2lwTW9kZWxSb2xlcyA9IHRoaXMucmVmbGVjdG9yLmdldEFsbEFuZE92ZXJyaWRlPGJvb2xlYW4+KFxuICAgICAgU0tJUF9NT0RFTF9ST0xFU19LRVksXG4gICAgICBbY3R4LmdldEhhbmRsZXIoKSwgY3R4LmdldENsYXNzKCldXG4gICAgKTtcblxuICAgIGNvbnN0IGVmZmVjdGl2ZU1vZGVsID0gc2tpcE1vZGVsUm9sZXMgPyB1bmRlZmluZWQgOiBtb2RlbE5hbWU7XG5cbiAgICBsb2cudmVyYm9zZShgSW50ZXJjZXB0ZWQgcmVxdWVzdCR7bW9kZWxOYW1lID8gYCBmb3IgJHttb2RlbE5hbWV9YCA6IFwiXCJ9YCk7XG5cbiAgICBpZiAoaXNQdWJsaWMpIHtcbiAgICAgIGxvZy5kZWJ1ZyhgUHVibGljIHJvdXRlIOKAlCBza2lwcGluZyBhdXRoYCk7XG4gICAgfSBlbHNlIGlmICh0aGlzLmF1dGhIYW5kbGVyKSB7XG4gICAgICBhd2FpdCB0aGlzLmF1dGhIYW5kbGVyLmF1dGhvcml6ZShcbiAgICAgICAgY3R4LFxuICAgICAgICBlZmZlY3RpdmVNb2RlbCBhcyBzdHJpbmcgfCBDb25zdHJ1Y3RvcixcbiAgICAgICAgcmVxdWlyZWRSb2xlcyxcbiAgICAgICAgdGhpcy5yZXF1ZXN0Q29udGV4dFxuICAgICAgKTtcbiAgICB9IGVsc2Uge1xuICAgICAgbG9nLmRlYnVnKGBObyBhdXRoIGhhbmRsZXIgcmVnaXN0ZXJlZGApO1xuICAgIH1cblxuICAgIC8vIFRyYW5zZm9ybWVycyBydW4gQUZURVIgYXV0aCBzbyB0aGV5IGNhbiByZWFkIGF1dGgtcG9wdWxhdGVkIGZpZWxkc1xuICAgIC8vIChlLmcuIGB1c2VyYCkgZnJvbSB0aGUgY29udGV4dCBhbmQgbWFwIHRoZW0gdG8gYWRhcHRlci1zcGVjaWZpYyBrZXlzXG4gICAgLy8gKGUuZy4gYFVVSURgIGZvciBSYW1BZGFwdGVyJ3MgQGNyZWF0ZWRCeS9AdXBkYXRlZEJ5IGhhbmRsZXJzKS5cbiAgICBhd2FpdCB0aGlzLmFwcGx5VHJhbnNmb3JtZXJzKCk7XG5cbiAgICBjb25zdCB1c2VyID0gdGhpcy5yZXF1ZXN0Q29udGV4dC5nZXRPclVuZGVmaW5lZChcInVzZXJcIiBhcyBhbnkpO1xuICAgIGNvbnN0IG9yZ2FuaXphdGlvbiA9IHRoaXMucmVxdWVzdENvbnRleHQuZ2V0T3JVbmRlZmluZWQoXCJvcmdhbml6YXRpb25cIiBhcyBhbnkpO1xuICAgIGlmICh1c2VyIHx8IG9yZ2FuaXphdGlvbikge1xuICAgICAgY29uc3QgY3VycmVudExvZyA9IHRoaXMucmVxdWVzdENvbnRleHQuZ2V0KFwibG9nZ2VyXCIgYXMgYW55KTtcbiAgICAgIGNvbnN0IGNoaWxkTG9nID0gY3VycmVudExvZy5mb3IoeyB1c2VyLCBvcmdhbml6YXRpb24gfSk7XG4gICAgICB0aGlzLnJlcXVlc3RDb250ZXh0LmFjY3VtdWxhdGUoeyBsb2dnZXI6IGNoaWxkTG9nIH0gYXMgYW55KTtcbiAgICB9XG5cbiAgICByZXR1cm4gbmV4dC5oYW5kbGUoKTtcbiAgfVxuXG4gIHByb3RlY3RlZCBhc3luYyBhcHBseVRyYW5zZm9ybWVycygpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCBmbGF2b3VycyA9IEFkYXB0ZXIuZmxhdm91cnNUb1RyYW5zZm9ybSgpO1xuICAgIGlmICghZmxhdm91cnMpIHJldHVybjtcblxuICAgIGZvciAoY29uc3QgZmxhdm91ciBvZiBmbGF2b3Vycykge1xuICAgICAgY29uc3QgdHJhbnNmb3JtZXIgPSBBZGFwdGVyLnRyYW5zZm9ybWVyRm9yKFxuICAgICAgICBmbGF2b3VyXG4gICAgICApIGFzIFJlcXVlc3RUb0NvbnRleHRUcmFuc2Zvcm1lcjxhbnk+O1xuICAgICAgaWYgKCF0cmFuc2Zvcm1lcikgY29udGludWU7XG4gICAgICBjb25zdCBmcm9tID0gYXdhaXQgdHJhbnNmb3JtZXIuZnJvbSh0aGlzLnJlcXVlc3RDb250ZXh0KTtcbiAgICAgIGlmIChmcm9tKSB0aGlzLnJlcXVlc3RDb250ZXh0LmFjY3VtdWxhdGUoZnJvbSk7XG4gICAgfVxuICB9XG59XG4iLCJpbXBvcnQgeyBhcHBseURlY29yYXRvcnMsIFNldE1ldGFkYXRhLCBVc2VJbnRlcmNlcHRvcnMgfSBmcm9tIFwiQG5lc3Rqcy9jb21tb25cIjtcbmltcG9ydCB7IEFwaUJlYXJlckF1dGgsIEFwaVNlY3VyaXR5IH0gZnJvbSBcIkBuZXN0anMvc3dhZ2dlclwiO1xuaW1wb3J0IHsgQ29uc3RydWN0b3IgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRpb25cIjtcblxuaW1wb3J0IHsgQVVUSF9NRVRBX0tFWSwgSVNfUFVCTElDX0tFWSwgUkVRVUlSRURfUk9MRVNfS0VZIH0gZnJvbSBcIi4vY29uc3RhbnRzXCI7XG5pbXBvcnQgeyBBdXRoSW50ZXJjZXB0b3IgfSBmcm9tIFwiLi9BdXRoSW50ZXJjZXB0b3JcIjtcblxuZXhwb3J0IGZ1bmN0aW9uIEF1dGgobW9kZWw/OiBzdHJpbmcgfCBDb25zdHJ1Y3Rvcikge1xuICBjb25zdCByZXNvdXJjZSA9IG1vZGVsXG4gICAgPyB0eXBlb2YgbW9kZWwgPT09IFwic3RyaW5nXCJcbiAgICAgID8gbW9kZWxcbiAgICAgIDogbW9kZWwubmFtZVxuICAgIDogdW5kZWZpbmVkO1xuICBjb25zdCBkZWNzID0gW0FwaUJlYXJlckF1dGgoKSwgVXNlSW50ZXJjZXB0b3JzKEF1dGhJbnRlcmNlcHRvcildO1xuICBpZiAocmVzb3VyY2UpIGRlY3MucHVzaChTZXRNZXRhZGF0YShBVVRIX01FVEFfS0VZLCByZXNvdXJjZSkpO1xuICByZXR1cm4gYXBwbHlEZWNvcmF0b3JzKC4uLmRlY3MpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gUHVibGljKCkge1xuICByZXR1cm4gYXBwbHlEZWNvcmF0b3JzKFNldE1ldGFkYXRhKElTX1BVQkxJQ19LRVksIHRydWUpKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIFJlcXVpcmVSb2xlcyguLi5yb2xlczogc3RyaW5nW10pIHtcbiAgcmV0dXJuIGFwcGx5RGVjb3JhdG9ycyhcbiAgICBBcGlTZWN1cml0eShcImJlYXJlclwiKSxcbiAgICBTZXRNZXRhZGF0YShSRVFVSVJFRF9ST0xFU19LRVksIHJvbGVzKSxcbiAgICBVc2VJbnRlcmNlcHRvcnMoQXV0aEludGVyY2VwdG9yKVxuICApO1xufVxuIiwiaW1wb3J0IHsgRGVsZXRlLCBHZXQsIFBhdGNoLCBQb3N0LCBQdXQgfSBmcm9tIFwiQG5lc3Rqcy9jb21tb25cIjtcbmltcG9ydCB7IEh0dHBWZXJicyB9IGZyb20gXCIuL3R5cGVzXCI7XG5cbi8qKlxuICogTWFwcyBhbiBIVFRQIHZlcmIgdG8gaXRzIGNvcnJlc3BvbmRpbmcgTmVzdEpTIG1ldGhvZCBkZWNvcmF0b3IuXG4gKlxuICogQHBhcmFtIHZlcmIgLSBIVFRQIHZlcmIgdG8gYmUgY29udmVydGVkIChlLmcuIEdFVCwgUE9TVCwgUFVULCBQQVRDSCwgREVMRVRFKS5cbiAqIEByZXR1cm5zIEEgTmVzdEpTIG1ldGhvZCBkZWNvcmF0b3IgbWF0Y2hpbmcgdGhlIHByb3ZpZGVkIEhUVFAgdmVyYi5cbiAqXG4gKiBAdGhyb3dzIHtFcnJvcn0gSWYgdGhlIHByb3ZpZGVkIEhUVFAgdmVyYiBpcyBub3Qgc3VwcG9ydGVkIG9yIG5vdCBtYXBwZWRcbiAqIHRvIGEgTmVzdEpTIGRlY29yYXRvci5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIEh0dHBWZXJiVG9EZWNvcmF0b3IoXG4gIHZlcmI6IEh0dHBWZXJic1xuKTogKHBhdGg/OiBzdHJpbmcpID0+IE1ldGhvZERlY29yYXRvciB7XG4gIGNvbnN0IGh0dHBUb0NydWQ6IFJlY29yZDxIdHRwVmVyYnMsIChwYXRoPzogc3RyaW5nKSA9PiBNZXRob2REZWNvcmF0b3I+ID0ge1xuICAgIEdFVDogR2V0LFxuICAgIFBPU1Q6IFBvc3QsXG4gICAgUFVUOiBQdXQsXG4gICAgUEFUQ0g6IFBhdGNoLFxuICAgIERFTEVURTogRGVsZXRlLFxuICB9O1xuXG4gIGNvbnN0IGRlY29yYXRvciA9IGh0dHBUb0NydWRbdmVyYl07XG5cbiAgaWYgKCFkZWNvcmF0b3IpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICBgVW5zdXBwb3J0ZWQgSFRUUCB2ZXJiIFwiJHt2ZXJifVwiLiBObyBOZXN0SlMgZGVjb3JhdG9yIG1hcHBpbmcgd2FzIGZvdW5kLmBcbiAgICApO1xuICB9XG5cbiAgcmV0dXJuIGRlY29yYXRvcjtcbn1cbiIsImltcG9ydCB7IFF1ZXJ5IH0gZnJvbSBcIkBuZXN0anMvY29tbW9uXCI7XG5pbXBvcnQgeyBMb2dnZXIgfSBmcm9tIFwiQGRlY2FmLXRzL2xvZ2dpbmdcIjtcbmltcG9ydCB7IHR5cGUgRGVjb3JhdG9yQnVuZGxlIH0gZnJvbSBcIi4vdHlwZXNcIjtcbmltcG9ydCB7XG4gIEFwaU5vQ29udGVudFJlc3BvbnNlLFxuICBBcGlPa1Jlc3BvbnNlLFxuICBBcGlPcGVyYXRpb24sXG4gIEFwaVBhcmFtLFxuICBBcGlRdWVyeSxcbn0gZnJvbSBcIkBuZXN0anMvc3dhZ2dlclwiO1xuaW1wb3J0IHtcbiAgRGVjYWZBcGlQcm9wZXJ0eSxcbiAgdHlwZSBEZWNhZlBhcmFtUHJvcHMsXG4gIERlY2FmUGFyYW1zLFxufSBmcm9tIFwiLi9kZWNvcmF0b3JzXCI7XG5pbXBvcnQgdHlwZSB7IEh0dHBWZXJicyB9IGZyb20gXCIuL2RlY29yYXRvcnMvdHlwZXNcIjtcbmltcG9ydCB7XG4gIERpcmVjdGlvbkxpbWl0T2Zmc2V0LFxuICBNb2RlbFNlcnZpY2UsXG4gIE9yZGVyRGlyZWN0aW9uLFxuICBSZXBvLFxufSBmcm9tIFwiQGRlY2FmLXRzL2NvcmVcIjtcbmltcG9ydCB7IE1vZGVsIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0b3ItdmFsaWRhdGlvblwiO1xuaW1wb3J0IHsgSHR0cFZlcmJUb0RlY29yYXRvciB9IGZyb20gXCIuL2RlY29yYXRvcnMvdXRpbHNcIjtcbmltcG9ydCB7IERlY2FmTW9kZWxDb250cm9sbGVyIH0gZnJvbSBcIi4uL2NvbnRyb2xsZXJzXCI7XG5cbmNvbnN0IGV4dHJhY3RQYXRoUGFyYW1zID0gKHJvdXRlUGF0aDogc3RyaW5nKTogc3RyaW5nW10gPT4ge1xuICByZXR1cm4gcm91dGVQYXRoXG4gICAgLnNwbGl0KFwiL1wiKVxuICAgIC5maWx0ZXIoKHApID0+IHAuc3RhcnRzV2l0aChcIjpcIikpXG4gICAgLm1hcCgocCkgPT4gcC5zbGljZSgxKSk7XG59O1xuXG5jb25zdCBhcGlQYXJhbVNwZWMgPSAobmFtZTogc3RyaW5nKTogRGVjYWZBcGlQcm9wZXJ0eSA9PiAoe1xuICBuYW1lLFxuICBkZXNjcmlwdGlvbjogYCR7bmFtZX0gcGFyYW1ldGVyIGZvciB0aGUgcXVlcnlgLFxuICByZXF1aXJlZDogdHJ1ZSxcbiAgdHlwZTogU3RyaW5nLFxufSk7XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRBcGlEZWNvcmF0b3JzKFxuICBtZXRob2ROYW1lOiBzdHJpbmcsXG4gIHJvdXRlUGF0aDogc3RyaW5nLFxuICBodHRwVmVyYjogSHR0cFZlcmJzLFxuICBpbmNsdWRlUXVlcnlQYXJhbXM6IGJvb2xlYW4gPSBmYWxzZVxuKTogRGVjb3JhdG9yQnVuZGxlIHtcbiAgY29uc3QgTmVzdEh0dHBSb3V0ZURlYyA9IEh0dHBWZXJiVG9EZWNvcmF0b3IoaHR0cFZlcmIpO1xuICBjb25zdCBhcGlQYXRoUGFyYW1zID0gZXh0cmFjdFBhdGhQYXJhbXMocm91dGVQYXRoKS5tYXAoYXBpUGFyYW1TcGVjKTtcblxuICBjb25zdCBzd2FnZ2VyUXVlcnlQYXJhbXMgPSBbXTtcbiAgaWYgKGh0dHBWZXJiID09PSBcIkdFVFwiICYmIGluY2x1ZGVRdWVyeVBhcmFtcykge1xuICAgIHN3YWdnZXJRdWVyeVBhcmFtcy5wdXNoKFxuICAgICAgQXBpUXVlcnkoe1xuICAgICAgICBuYW1lOiBcImRpcmVjdGlvblwiLFxuICAgICAgICByZXF1aXJlZDogZmFsc2UsXG4gICAgICAgIGVudW06IE9yZGVyRGlyZWN0aW9uLFxuICAgICAgICBkZXNjcmlwdGlvbjogXCJ0aGUgc29ydCBvcmRlciB3aGVuIGFwcGxpY2FibGVcIixcbiAgICAgIH0pLFxuICAgICAgQXBpUXVlcnkoe1xuICAgICAgICBuYW1lOiBcImxpbWl0XCIsXG4gICAgICAgIHJlcXVpcmVkOiBmYWxzZSxcbiAgICAgICAgZGVzY3JpcHRpb246IFwibGltaXQgb3IgcGFnZSBzaXplIHdoZW4gYXBwbGljYWJsZVwiLFxuICAgICAgfSksXG4gICAgICBBcGlRdWVyeSh7XG4gICAgICAgIG5hbWU6IFwib2Zmc2V0XCIsXG4gICAgICAgIHJlcXVpcmVkOiBmYWxzZSxcbiAgICAgICAgZGVzY3JpcHRpb246IFwib2Zmc2V0IG9yIGJvb2ttYXJrIHdoZW4gYXBwbGljYWJsZVwiLFxuICAgICAgfSlcbiAgICApO1xuICB9XG5cbiAgcmV0dXJuIHtcbiAgICBtZXRob2Q6IFtcbiAgICAgIE5lc3RIdHRwUm91dGVEZWMocm91dGVQYXRoKSxcbiAgICAgIC4uLmFwaVBhdGhQYXJhbXMubWFwKEFwaVBhcmFtKSxcbiAgICAgIC4uLnN3YWdnZXJRdWVyeVBhcmFtcyxcbiAgICAgIEFwaU9wZXJhdGlvbih7XG4gICAgICAgIHN1bW1hcnk6IGBSZXRyaWV2ZSByZWNvcmRzIHVzaW5nIGFjY29yZGluZyB0byBcIiR7bWV0aG9kTmFtZX1cIi5gLFxuICAgICAgfSksXG4gICAgICBBcGlPa1Jlc3BvbnNlKHtcbiAgICAgICAgZGVzY3JpcHRpb246IGBSZXN1bHQgc3VjY2Vzc2Z1bGx5IHJldHJpZXZlZC5gLFxuICAgICAgfSksXG4gICAgICBBcGlOb0NvbnRlbnRSZXNwb25zZSh7XG4gICAgICAgIGRlc2NyaXB0aW9uOiBgTm8gY29udGVudCByZXR1cm5lZCBieSB0aGUgbWV0aG9kLmAsXG4gICAgICB9KSxcbiAgICBdLFxuICAgIHBhcmFtczogW0RlY2FmUGFyYW1zKGFwaVBhdGhQYXJhbXMpLCBRdWVyeSgpXSwgLy8gLCBEZWNhZkJvZHkoKV0sXG4gIH07XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBhcHBseUFwaURlY29yYXRvcnMoXG4gIHRhcmdldDogYW55LFxuICBtZXRob2ROYW1lOiBzdHJpbmcsXG4gIGRlc2NyaXB0b3I6IFByb3BlcnR5RGVzY3JpcHRvcixcbiAgZGVjb3JhdG9yczogRGVjb3JhdG9yQnVuZGxlXG4pIHtcbiAgY29uc3QgcHJvdG8gPSB0YXJnZXQ/LnByb3RvdHlwZSA/PyB0YXJnZXQ7XG4gIGRlY29yYXRvcnMubWV0aG9kLmZvckVhY2goKGQpID0+IGQocHJvdG8sIG1ldGhvZE5hbWUsIGRlc2NyaXB0b3IpKTtcbiAgZGVjb3JhdG9ycy5wYXJhbXM/LmZvckVhY2goKGQsIGluZGV4KSA9PiBkKHByb3RvLCBtZXRob2ROYW1lLCBpbmRleCkpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcmVzb2x2ZVBlcnNpc3RlbmNlTWV0aG9kPFQgZXh0ZW5kcyBNb2RlbDxib29sZWFuPj4oXG4gIHBlcnNpc3RlbmNlOiBSZXBvPFQ+IHwgTW9kZWxTZXJ2aWNlPFQ+LFxuICBtZXRob2ROYW1lOiBzdHJpbmcsXG4gIC4uLmFyZ3M6IGFueVtdXG4pOiBhbnkge1xuICBpZiAocGVyc2lzdGVuY2UgaW5zdGFuY2VvZiBNb2RlbFNlcnZpY2UpIHtcbiAgICByZXR1cm4gdHlwZW9mIChwZXJzaXN0ZW5jZSBhcyBhbnkpW21ldGhvZE5hbWVdID09PSBcImZ1bmN0aW9uXCJcbiAgICAgID8gKHBlcnNpc3RlbmNlIGFzIGFueSlbbWV0aG9kTmFtZV0oLi4uYXJncylcbiAgICAgIDogcGVyc2lzdGVuY2Uuc3RhdGVtZW50KG1ldGhvZE5hbWUsIC4uLmFyZ3MpO1xuICB9XG5cbiAgaWYgKHR5cGVvZiAocGVyc2lzdGVuY2UgYXMgYW55KVttZXRob2ROYW1lXSA9PT0gXCJmdW5jdGlvblwiKVxuICAgIHJldHVybiAocGVyc2lzdGVuY2UgYXMgYW55KVttZXRob2ROYW1lXSguLi5hcmdzKTtcblxuICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgYFBlcnNpc3RlbmNlIG1ldGhvZCBcIiR7bWV0aG9kTmFtZX1cIiBub3QgZm91bmQgb24gJHtwZXJzaXN0ZW5jZT8uY29uc3RydWN0b3I/Lm5hbWV9YFxuICApO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlUm91dGVIYW5kbGVyPFQ+KG1ldGhvZE5hbWU6IHN0cmluZykge1xuICByZXR1cm4gYXN5bmMgZnVuY3Rpb24gKFxuICAgIHRoaXM6IERlY2FmTW9kZWxDb250cm9sbGVyPGFueT4sXG4gICAgcGF0aFBhcmFtczogRGVjYWZQYXJhbVByb3BzLFxuICAgIHF1ZXJ5UGFyYW1zOiBEaXJlY3Rpb25MaW1pdE9mZnNldFxuICApOiBQcm9taXNlPFQ+IHtcbiAgICBjb25zdCBsb2c6IExvZ2dlciA9IHRoaXMubG9nLmZvcihtZXRob2ROYW1lKTtcblxuICAgIHRyeSB7XG4gICAgICBsb2cuZGVidWcoXG4gICAgICAgIGBJbnZva2luZyBwZXJzaXN0ZW5jZSBtZXRob2QgXCIke21ldGhvZE5hbWV9XCIgZ2l2ZW4gcGFyYW1ldGVyczogJHtKU09OLnN0cmluZ2lmeShwYXRoUGFyYW1zLnZhbHVlc0luT3JkZXIpfWBcbiAgICAgICk7XG4gICAgICBjb25zdCB7IGRpcmVjdGlvbiwgbGltaXQsIG9mZnNldCB9ID0gcXVlcnlQYXJhbXM7XG4gICAgICByZXR1cm4gYXdhaXQgcmVzb2x2ZVBlcnNpc3RlbmNlTWV0aG9kKFxuICAgICAgICB0aGlzLnBlcnNpc3RlbmNlKCksXG4gICAgICAgIG1ldGhvZE5hbWUsXG4gICAgICAgIC4uLnBhdGhQYXJhbXMudmFsdWVzSW5PcmRlcixcbiAgICAgICAgZGlyZWN0aW9uLFxuICAgICAgICBsaW1pdCxcbiAgICAgICAgb2Zmc2V0XG4gICAgICApO1xuICAgIH0gY2F0Y2ggKGU6IGFueSkge1xuICAgICAgbG9nLmVycm9yKGBDdXN0b20gcXVlcnkgXCIke21ldGhvZE5hbWV9XCIgZmFpbGVkYCwgZSk7XG4gICAgICB0aHJvdyBlO1xuICAgIH1cbiAgfTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGRlZmluZVJvdXRlTWV0aG9kKFxuICBDb250cm9sbGVyQ2xhc3M6IG5ldyAoLi4uYXJnczogYW55W10pID0+IGFueSxcbiAgbWV0aG9kTmFtZTogc3RyaW5nLFxuICBoYW5kbGVyOiAoLi4uYXJnczogYW55W10pID0+IGFueVxuKTogUHJvcGVydHlEZXNjcmlwdG9yIHwgdW5kZWZpbmVkIHtcbiAgT2JqZWN0LmRlZmluZVByb3BlcnR5KFxuICAgIENvbnRyb2xsZXJDbGFzcy5wcm90b3R5cGUgfHwgQ29udHJvbGxlckNsYXNzLFxuICAgIG1ldGhvZE5hbWUsXG4gICAge1xuICAgICAgdmFsdWU6IGhhbmRsZXIsXG4gICAgICB3cml0YWJsZTogZmFsc2UsXG4gICAgfVxuICApO1xuXG4gIHJldHVybiBPYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKFxuICAgIENvbnRyb2xsZXJDbGFzcy5wcm90b3R5cGUgfHwgQ29udHJvbGxlckNsYXNzLFxuICAgIG1ldGhvZE5hbWVcbiAgKTtcbn1cbiIsImltcG9ydCB7IEV4ZWN1dGlvbkNvbnRleHQgfSBmcm9tIFwiQG5lc3Rqcy9jb21tb25cIjtcbmltcG9ydCB7IEF1dGhvcml6YXRpb25FcnJvciB9IGZyb20gXCJAZGVjYWYtdHMvY29yZVwiO1xuaW1wb3J0IHsgQXV0aEhhbmRsZXIsIEF1dGhEYXRhIH0gZnJvbSBcIkBkZWNhZi10cy9mb3ItaHR0cC9zZXJ2ZXJcIjtcbmltcG9ydCB7IERlY2FmUmVxdWVzdENvbnRleHQgfSBmcm9tIFwiLi4vcmVxdWVzdC9EZWNhZlJlcXVlc3RDb250ZXh0XCI7XG5cbi8qKlxuICogU2ltcGxlIGF1dGggaGFuZGxlciB0aGF0IHJlYWRzIGEgcm9sZSBzdHJpbmcgZnJvbSB0aGUgYEF1dGhvcml6YXRpb246IEJlYXJlciA8cm9sZT5gIGhlYWRlci5cbiAqXG4gKiBPbmx5IG92ZXJyaWRlcyB7QGxpbmsgQXV0aEhhbmRsZXIuZXh0cmFjdEZyb21BdXRofSB0byByZXR1cm4gdGhlIGJlYXJlciB0b2tlbiBhc1xuICogYm90aCB0aGUgdXNlciBpZGVudGlmaWVyIGFuZCB0aGUgc2luZ2xlIHJvbGUuIFRoZSBiYXNlIGNsYXNzIGBiaW5kVG9Db250ZXh0YFxuICogKGBjdHguYWNjdW11bGF0ZShkYXRhKWApIGlzIHN1ZmZpY2llbnQg4oCUIHRoZSB0cmFuc2Zvcm1lci9hZGFwdGVyIGlzIHJlc3BvbnNpYmxlXG4gKiBmb3IgbWFwcGluZyBjb250ZXh0IGZpZWxkcyB0byBhZGFwdGVyLXNwZWNpZmljIGtleXMgbGlrZSBgVVVJRGAuXG4gKi9cbmV4cG9ydCBjbGFzcyBEZWNhZkF1dGhIYW5kbGVyIGV4dGVuZHMgQXV0aEhhbmRsZXI8XG4gIEV4ZWN1dGlvbkNvbnRleHQsXG4gIERlY2FmUmVxdWVzdENvbnRleHQsXG4gIEF1dGhEYXRhXG4+IHtcbiAgcHJvdGVjdGVkIHBhcnNlUmVxdWVzdChyZXE6IGFueSk6IHN0cmluZyB7XG4gICAgY29uc3QgdXNlclJvbGUgPSByZXEuaGVhZGVycy5hdXRob3JpemF0aW9uPy5zcGxpdChcIiBcIilbMV0gYXMgc3RyaW5nO1xuICAgIHJldHVybiB1c2VyUm9sZTtcbiAgfVxuXG4gIHByb3RlY3RlZCBleHRyYWN0RnJvbUF1dGgoY3R4OiBFeGVjdXRpb25Db250ZXh0KTogQXV0aERhdGEge1xuICAgIGNvbnN0IHJlcSA9IGN0eC5zd2l0Y2hUb0h0dHAoKS5nZXRSZXF1ZXN0KCk7XG4gICAgY29uc3QgdXNlclJvbGUgPSB0aGlzLnBhcnNlUmVxdWVzdChyZXEpO1xuICAgIGlmICghdXNlclJvbGUpIHRocm93IG5ldyBBdXRob3JpemF0aW9uRXJyb3IoXCJVbmF1dGhlbnRpY2F0ZWRcIik7XG4gICAgcmV0dXJuIHsgdXNlcjogdXNlclJvbGUsIHJvbGVzOiBbdXNlclJvbGVdIH07XG4gIH1cbn1cblxuLyoqXG4gKiBBbGlhcyBmb3Ige0BsaW5rIERlY2FmQXV0aEhhbmRsZXJ9IGtlcHQgZm9yIGJhY2t3YXJkIGNvbXBhdGliaWxpdHkuXG4gKiBUaGUgXCJyb2xlXCIgdmFyaWFudCBwcmV2aW91c2x5IHJldHVybmVkIHJvbGVzIGZyb20gYGF1dGhvcml6ZWA7IHdpdGggdGhlIGJhc2VcbiAqIGNsYXNzIG5vdyBvcmNoZXN0cmF0aW5nIHJvbGUgY2hlY2tzIGludGVybmFsbHksIHRoZSB0d28gY2xhc3NlcyBhcmUgZXF1aXZhbGVudC5cbiAqL1xuZXhwb3J0IGNsYXNzIERlY2FmUm9sZUF1dGhIYW5kbGVyIGV4dGVuZHMgRGVjYWZBdXRoSGFuZGxlciB7fVxuIiwiaW1wb3J0IHsgQ29uc3RydWN0b3IsIE1ldGFkYXRhIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0aW9uXCI7XG5pbXBvcnQgeyBSZXF1ZXN0VG9Db250ZXh0VHJhbnNmb3JtZXIgfSBmcm9tIFwiQGRlY2FmLXRzL2Zvci1odHRwL3NlcnZlclwiO1xuaW1wb3J0IHsgQWRhcHRlciwgQ29udGV4dE9mLCBDb250ZXh0IH0gZnJvbSBcIkBkZWNhZi10cy9jb3JlXCI7XG5cbihBZGFwdGVyIGFzIGFueSkudHJhbnNmb3JtZXJGb3IgPSBmdW5jdGlvbiB0b0NvbnRleHRGbGFnczxcbiAgQSBleHRlbmRzIEFkYXB0ZXI8YW55LCBhbnksIGFueSwgYW55Pixcbj4oYWRhcHRlcjogQSB8IHN0cmluZyk6IENvbnN0cnVjdG9yPFJlcXVlc3RUb0NvbnRleHRUcmFuc2Zvcm1lcjxDb250ZXh0T2Y8QT4+PiB7XG4gIGNvbnN0IGFsaWFzID1cbiAgICB0eXBlb2YgYWRhcHRlciA9PT0gXCJzdHJpbmdcIiA/IGFkYXB0ZXIgOiAoYWRhcHRlci5hbGlhcyBhcyBzdHJpbmcpO1xuICByZXR1cm4gTWV0YWRhdGFbXCJpbm5lckdldFwiXShTeW1ib2wuZm9yKFwidHJhbnNmb3JtZXJzXCIpLCBhbGlhcyk7XG59LmJpbmQoQWRhcHRlcik7XG5cbihBZGFwdGVyIGFzIGFueSkuZmxhdm91cnNUb1RyYW5zZm9ybSA9IGZ1bmN0aW9uIHJlcXVlc3RUcmFuc2Zvcm1lcnMoKTpcbiAgfCBzdHJpbmdbXVxuICB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IG1ldGEgPSBNZXRhZGF0YVtcImlubmVyR2V0XCJdKFN5bWJvbC5mb3IoXCJ0cmFuc2Zvcm1lcnNcIikpO1xuICBpZiAoIW1ldGEpIHJldHVybiB1bmRlZmluZWQ7XG4gIHJldHVybiBPYmplY3Qua2V5cyhtZXRhKTtcbn0uYmluZChBZGFwdGVyKTtcblxuKENvbnRleHQgYXMgYW55KS5wcm90b3R5cGUudG9SZXNwb25zZSA9IGZ1bmN0aW9uIHRvUmVzcG9uc2U8XG4gIFJFUyBleHRlbmRzIHsgaGVhZGVyOiBhbnkgfSxcbj4odGhpczogQ29udGV4dCwgcmVzOiBSRVMpOiBSRVMge1xuICBjb25zdCBwZW5kaW5nID0gdGhpcy5wZW5kaW5nKCk7XG4gIGlmIChwZW5kaW5nKSByZXMuaGVhZGVyKFwieC1wZW5kaW5nLXRhc2tcIiwgSlNPTi5zdHJpbmdpZnkocGVuZGluZykpO1xuICByZXR1cm4gcmVzO1xufTtcbiIsImltcG9ydCBcIkBkZWNhZi10cy9kZWNvcmF0b3ItdmFsaWRhdGlvblwiO1xuaW1wb3J0IHsgQ29uc3RydWN0b3IgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRpb25cIjtcbmltcG9ydCB7IE1vZGVsQnVpbGRlciB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdG9yLXZhbGlkYXRpb25cIjtcbmltcG9ydCB7IEF1dGggfSBmcm9tIFwiLi4vZGVjYWYtbW9kZWwvZGVjb3JhdG9ycy9kZWNvcmF0b3JzXCI7XG5cbmRlY2xhcmUgbW9kdWxlIFwiQGRlY2FmLXRzL2RlY29yYXRvci12YWxpZGF0aW9uXCIge1xuICBleHBvcnQgaW50ZXJmYWNlIE1vZGVsQnVpbGRlcjxNPiB7XG4gICAgQXV0aChtb2RlbDogc3RyaW5nIHwgQ29uc3RydWN0b3IpOiBNb2RlbEJ1aWxkZXI8TT47XG4gICAgZGVjb3JhdGVDbGFzcyhkZWNvcmF0b3I6IENsYXNzRGVjb3JhdG9yKTogTW9kZWxCdWlsZGVyPE0+O1xuICB9XG59XG5cbmNvbnN0IHByb3RvdHlwZSA9IE1vZGVsQnVpbGRlci5wcm90b3R5cGUgYXMgTW9kZWxCdWlsZGVyPGFueT4gJiB7XG4gIEF1dGg6IChtb2RlbDogc3RyaW5nIHwgQ29uc3RydWN0b3IpID0+IE1vZGVsQnVpbGRlcjxhbnk+O1xufTtcblxuaWYgKCFwcm90b3R5cGUuZGVjb3JhdGVDbGFzcykge1xuICBwcm90b3R5cGUuZGVjb3JhdGVDbGFzcyA9IGZ1bmN0aW9uIChkZWNvcmF0b3I6IENsYXNzRGVjb3JhdG9yKSB7XG4gICAgaWYgKCEodGhpcyBhcyBhbnkpLl9jbGFzc0RlY29yYXRvcnMpIHtcbiAgICAgICh0aGlzIGFzIGFueSkuX2NsYXNzRGVjb3JhdG9ycyA9IFtdO1xuICAgIH1cbiAgICAodGhpcyBhcyBhbnkpLl9jbGFzc0RlY29yYXRvcnMucHVzaChkZWNvcmF0b3IpO1xuICAgIHJldHVybiB0aGlzO1xuICB9O1xufVxuXG5wcm90b3R5cGUuQXV0aCA9IGZ1bmN0aW9uIChtb2RlbDogc3RyaW5nIHwgQ29uc3RydWN0b3IpIHtcbiAgcmV0dXJuIHRoaXMuZGVjb3JhdGVDbGFzcyhBdXRoKG1vZGVsKSk7XG59O1xuXG5pZiAoIShwcm90b3R5cGUgYXMgYW55KS5fX2hhc0NsYXNzRGVjb3JhdG9yU3VwcG9ydCkge1xuICBjb25zdCBvcmlnaW5hbEJ1aWxkID0gcHJvdG90eXBlLmJ1aWxkO1xuICBwcm90b3R5cGUuYnVpbGQgPSBmdW5jdGlvbiAoKSB7XG4gICAgbGV0IHJlc3VsdCA9IG9yaWdpbmFsQnVpbGQuY2FsbCh0aGlzKTtcbiAgICBjb25zdCBkZWNvcmF0b3JzID0gKHRoaXMgYXMgYW55KS5fY2xhc3NEZWNvcmF0b3JzO1xuICAgIGlmIChkZWNvcmF0b3JzPy5sZW5ndGgpIHtcbiAgICAgIGZvciAoY29uc3QgZGVjb3JhdG9yIG9mIGRlY29yYXRvcnMpIHtcbiAgICAgICAgY29uc3QgZGVjb3JhdGVkID0gZGVjb3JhdG9yKHJlc3VsdCBhcyBhbnkpIGFzIHR5cGVvZiByZXN1bHQgfCB2b2lkO1xuICAgICAgICBpZiAoZGVjb3JhdGVkKSB7XG4gICAgICAgICAgcmVzdWx0ID0gZGVjb3JhdGVkO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiByZXN1bHQ7XG4gIH07XG4gIChwcm90b3R5cGUgYXMgYW55KS5fX2hhc0NsYXNzRGVjb3JhdG9yU3VwcG9ydCA9IHRydWU7XG59XG4iLCJpbXBvcnQge1xuICBDYWxsSGFuZGxlcixcbiAgRXhlY3V0aW9uQ29udGV4dCxcbiAgSW5qZWN0YWJsZSxcbiAgTmVzdEludGVyY2VwdG9yLFxuICBTY29wZSxcbn0gZnJvbSBcIkBuZXN0anMvY29tbW9uXCI7XG5pbXBvcnQgeyBEZWNhZkhhbmRsZXJFeGVjdXRvciwgRGVjYWZSZXF1ZXN0Q29udGV4dCB9IGZyb20gXCIuLi9yZXF1ZXN0XCI7XG5pbXBvcnQgeyBEZWZhdWx0QWRhcHRlckZsYWdzIH0gZnJvbSBcIkBkZWNhZi10cy9jb3JlXCI7XG5pbXBvcnQgeyBEZWNhZlNlcnZlckZsYWdzIH0gZnJvbSBcIi4uL2NvbnN0YW50c1wiO1xuaW1wb3J0IFwiLi4vb3ZlcnJpZGVzXCI7XG5pbXBvcnQgeyBMb2dnaW5nIH0gZnJvbSBcIkBkZWNhZi10cy9sb2dnaW5nXCI7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uXG4gKiBJbnRlcmNlcHRvciByZXNwb25zaWJsZSBmb3IgZXhlY3V0aW5nIGFsbCByZWdpc3RlcmVkIERlY2FmIHJlcXVlc3QgaGFuZGxlcnNcbiAqIGJlZm9yZSB0aGUgY29udHJvbGxlciBtZXRob2QgaXMgaW52b2tlZC5cbiAqXG4gKiBAc3VtbWFyeVxuICogVGhlIHtAbGluayBEZWNhZlJlcXVlc3RIYW5kbGVySW50ZXJjZXB0b3J9IGludGVncmF0ZXMgdGhlIERlY2FmIHJlcXVlc3QtaGFuZGxpbmcgcGlwZWxpbmVcbiAqIGludG8gTmVzdEpTJyBpbnRlcmNlcHRvciBtZWNoYW5pc20uIEJlZm9yZSBwYXNzaW5nIGV4ZWN1dGlvbiB0byB0aGUgbmV4dCBoYW5kbGVyIGluIHRoZVxuICogTmVzdEpTIGNoYWluLCBpdCBkZWxlZ2F0ZXMgcmVxdWVzdCBwcm9jZXNzaW5nIHRvIHRoZSB7QGxpbmsgRGVjYWZIYW5kbGVyRXhlY3V0b3J9LCB3aGljaFxuICogc2VxdWVudGlhbGx5IHJ1bnMgYWxsIHJlZ2lzdGVyZWQge0BsaW5rIERlY2FmUmVxdWVzdEhhbmRsZXJ9IGluc3RhbmNlcy4gVGhpcyBhbGxvd3NcbiAqIGJlaGF2aW9ycyBzdWNoIGFzIGF1dGhlbnRpY2F0aW9uLCBsb2dnaW5nLCB0ZW5hbnQgcmVzb2x1dGlvbiwgb3IgbWV0YWRhdGEgZW5yaWNobWVudFxuICogdG8gb2NjdXIgcHJpb3IgdG8gY29udHJvbGxlciBleGVjdXRpb24uXG4gKlxuICogQGNsYXNzIERlY2FmUmVxdWVzdEhhbmRsZXJJbnRlcmNlcHRvclxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0c1xuICogLy8gQXBwbHkgZ2xvYmFsbHk6XG4gKiBhcHAudXNlR2xvYmFsSW50ZXJjZXB0b3JzKG5ldyBEZWNhZlJlcXVlc3RIYW5kbGVySW50ZXJjZXB0b3IoZXhlY3V0b3IpKTtcbiAqXG4gKiAvLyBPciBpbiBhIG1vZHVsZTpcbiAqIEBNb2R1bGUoe1xuICogICBwcm92aWRlcnM6IFtcbiAqICAgICBEZWNhZkhhbmRsZXJFeGVjdXRvcixcbiAqICAgICB7XG4gKiAgICAgICBwcm92aWRlOiBBUFBfSU5URVJDRVBUT1IsXG4gKiAgICAgICB1c2VDbGFzczogRGVjYWZSZXF1ZXN0SGFuZGxlckludGVyY2VwdG9yLFxuICogICAgIH0sXG4gKiAgIF0sXG4gKiB9KVxuICogZXhwb3J0IGNsYXNzIEFwcE1vZHVsZSB7fVxuICogYGBgXG4gKlxuICogQG1lcm1haWRcbiAqIHNlcXVlbmNlRGlhZ3JhbVxuICogICAgIHBhcnRpY2lwYW50IENsaWVudFxuICogICAgIHBhcnRpY2lwYW50IEludGVyY2VwdG9yXG4gKiAgICAgcGFydGljaXBhbnQgRXhlY3V0b3JcbiAqICAgICBwYXJ0aWNpcGFudCBDb250cm9sbGVyXG4gKlxuICogICAgIENsaWVudC0+PkludGVyY2VwdG9yOiBIVFRQIFJlcXVlc3RcbiAqICAgICBJbnRlcmNlcHRvci0+PkV4ZWN1dG9yOiBleGVjKHJlcXVlc3QpXG4gKiAgICAgRXhlY3V0b3ItLT4+SW50ZXJjZXB0b3I6IGhhbmRsZXJzIGNvbXBsZXRlZFxuICogICAgIEludGVyY2VwdG9yLT4+Q29udHJvbGxlcjogbmV4dC5oYW5kbGUoKVxuICogICAgIENvbnRyb2xsZXItLT4+Q2xpZW50OiBSZXNwb25zZVxuICovXG5ASW5qZWN0YWJsZSh7IHNjb3BlOiBTY29wZS5SRVFVRVNUIH0pXG5leHBvcnQgY2xhc3MgRGVjYWZSZXF1ZXN0SGFuZGxlckludGVyY2VwdG9yIGltcGxlbWVudHMgTmVzdEludGVyY2VwdG9yIHtcbiAgY29uc3RydWN0b3IoXG4gICAgcHJvdGVjdGVkIHJlYWRvbmx5IHJlcXVlc3RDb250ZXh0OiBEZWNhZlJlcXVlc3RDb250ZXh0LFxuICAgIHByb3RlY3RlZCByZWFkb25seSBleGVjdXRvcjogRGVjYWZIYW5kbGVyRXhlY3V0b3JcbiAgKSB7fVxuXG4gIHByb3RlY3RlZCBhc3luYyBjb250ZXh0dWFsaXplKHJlcTogYW55KTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgaGVhZGVycyA9IHJlcS5oZWFkZXJzO1xuICAgIGNvbnN0IGZsYWdzOiBEZWNhZlNlcnZlckZsYWdzID0ge1xuICAgICAgaGVhZGVyczogaGVhZGVycyxcbiAgICAgIG92ZXJyaWRlczoge30sXG4gICAgfSBhcyBhbnk7XG5cbiAgICBjb25zdCBpcCA9IGV4dHJhY3RJcChyZXEpO1xuICAgIGNvbnN0IGxvZ2dlciA9IExvZ2dpbmcuZ2V0KCkuZm9yKHsgaXAgfSk7XG5cbiAgICB0aGlzLnJlcXVlc3RDb250ZXh0LmFjY3VtdWxhdGUoXG4gICAgICBPYmplY3QuYXNzaWduKFxuICAgICAgICB7fSxcbiAgICAgICAgRGVmYXVsdEFkYXB0ZXJGbGFncyxcbiAgICAgICAge1xuICAgICAgICAgIGxvZ2dlcixcbiAgICAgICAgICB0aW1lc3RhbXA6IG5ldyBEYXRlKCksXG4gICAgICAgICAgb3BlcmF0aW9uOiBgJHtyZXEubWV0aG9kfSAke3JlcS51cmx9YCxcbiAgICAgICAgfSxcbiAgICAgICAgZmxhZ3NcbiAgICAgIClcbiAgICApO1xuICB9XG5cbiAgYXN5bmMgaW50ZXJjZXB0KGNvbnRleHQ6IEV4ZWN1dGlvbkNvbnRleHQsIG5leHQ6IENhbGxIYW5kbGVyKSB7XG4gICAgY29uc3QgcmVxID0gY29udGV4dC5zd2l0Y2hUb0h0dHAoKS5nZXRSZXF1ZXN0KCk7XG4gICAgY29uc3QgcmVzID0gY29udGV4dC5zd2l0Y2hUb0h0dHAoKS5nZXRSZXNwb25zZSgpO1xuICAgIGNvbnN0IGxvZyA9IExvZ2dpbmcuZm9yKERlY2FmUmVxdWVzdEhhbmRsZXJJbnRlcmNlcHRvcikuZm9yKHRoaXMuaW50ZXJjZXB0KTtcbiAgICBsb2cuZGVidWcoXG4gICAgICBgQ09OVEVYVCAke3RoaXMucmVxdWVzdENvbnRleHQudXVpZH0gLSByZXF1ZXN0OiAke3JlcS5tZXRob2R9ICR7cmVxLnVybH1gXG4gICAgKTtcbiAgICBhd2FpdCB0aGlzLmNvbnRleHR1YWxpemUocmVxKTtcbiAgICBsb2cuZGVidWcoXG4gICAgICBgQ09OVEVYVCAke3RoaXMucmVxdWVzdENvbnRleHQudXVpZH0gY29udGV4dHVhbGl6ZWQgLSByZXF1ZXN0OiAke3JlcS5tZXRob2R9ICR7cmVxLnVybH1gXG4gICAgKTtcblxuICAgIGF3YWl0IHRoaXMuZXhlY3V0b3IuZXhlYyhyZXEsIHJlcyk7XG4gICAgbG9nLmRlYnVnKFxuICAgICAgYENPTlRFWFQgJHt0aGlzLnJlcXVlc3RDb250ZXh0LnV1aWR9IGV4ZWN1dG9ycyBmaW5pc2hlZCAtIHJlcXVlc3Q6ICR7cmVxLm1ldGhvZH0gJHtyZXEudXJsfWBcbiAgICApO1xuICAgIHJldHVybiBuZXh0LmhhbmRsZSgpO1xuICB9XG59XG5cbmZ1bmN0aW9uIGV4dHJhY3RJcChyZXE6IGFueSk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IGhlYWRlcnMgPSByZXEuaGVhZGVycztcbiAgZnVuY3Rpb24gcGFyc2VJcEhlYWRlcih2YWx1ZT86IHN0cmluZyB8IHN0cmluZ1tdKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgICBpZiAoIXZhbHVlKSByZXR1cm4gdW5kZWZpbmVkO1xuICAgIGNvbnN0IGNhbmRpZGF0ZSA9IEFycmF5LmlzQXJyYXkodmFsdWUpID8gdmFsdWVbMF0gOiB2YWx1ZTtcbiAgICByZXR1cm4gY2FuZGlkYXRlXG4gICAgICAuc3BsaXQoXCIsXCIpXG4gICAgICAubWFwKChzZWdtZW50KSA9PiBzZWdtZW50LnRyaW0oKSlcbiAgICAgIC5maWx0ZXIoQm9vbGVhbilbMF07XG4gIH1cbiAgcmV0dXJuIChcbiAgICBwYXJzZUlwSGVhZGVyKGhlYWRlcnM/LltcIngtZm9yd2FyZGVkLWZvclwiXSkgPz9cbiAgICBwYXJzZUlwSGVhZGVyKGhlYWRlcnM/LltcIngtcmVhbC1pcFwiXSkgPz9cbiAgICBwYXJzZUlwSGVhZGVyKGhlYWRlcnM/LltcIlgtRm9yd2FyZGVkLUZvclwiXSkgPz9cbiAgICBwYXJzZUlwSGVhZGVyKGhlYWRlcnM/LltcIlgtUmVhbC1JUFwiXSkgPz9cbiAgICByZXEuaXBcbiAgKTtcbn1cbiIsImltcG9ydCB7IER5bmFtaWNNb2R1bGUsIE1vZHVsZSwgVHlwZSB9IGZyb20gXCJAbmVzdGpzL2NvbW1vblwiO1xuaW1wb3J0IHsgQVBQX0lOVEVSQ0VQVE9SIH0gZnJvbSBcIkBuZXN0anMvY29yZVwiO1xuXG5pbXBvcnQgeyBBdXRoSW50ZXJjZXB0b3IgfSBmcm9tIFwiLi9BdXRoSW50ZXJjZXB0b3JcIjtcbmltcG9ydCB7IEFVVEhfSEFORExFUiB9IGZyb20gXCIuL2NvbnN0YW50c1wiO1xuaW1wb3J0IHsgRGVjYWZSZXF1ZXN0SGFuZGxlckludGVyY2VwdG9yIH0gZnJvbSBcIi4uL2ludGVyY2VwdG9ycy9EZWNhZlJlcXVlc3RIYW5kbGVySW50ZXJjZXB0b3JcIjtcbmltcG9ydCB7IEF1dGhIYW5kbGVyIH0gZnJvbSBcIi4uL3R5cGVzXCI7XG5cbmV4cG9ydCB0eXBlIERlY2FmQXV0aE1vZHVsZU9wdGlvbnMgPSB7XG4gIGdsb2JhbD86IGJvb2xlYW47XG4gIGhhbmRsZXI/OiBUeXBlPEF1dGhIYW5kbGVyPjtcbn07XG5cbkBNb2R1bGUoe30pXG5leHBvcnQgY2xhc3MgRGVjYWZBdXRoTW9kdWxlIHtcbiAgc3RhdGljIGZvclJvb3QoXG4gICAgb3B0aW9uczogRGVjYWZBdXRoTW9kdWxlT3B0aW9ucyA9IHt9XG4gICk6IER5bmFtaWNNb2R1bGUge1xuICAgIGNvbnN0IHByb3ZpZGVyczogRHluYW1pY01vZHVsZVtcInByb3ZpZGVyc1wiXSA9IFtcbiAgICAgIEF1dGhJbnRlcmNlcHRvcixcbiAgICAgIERlY2FmUmVxdWVzdEhhbmRsZXJJbnRlcmNlcHRvcixcbiAgICAgIHtcbiAgICAgICAgcHJvdmlkZTogQVBQX0lOVEVSQ0VQVE9SLFxuICAgICAgICB1c2VDbGFzczogRGVjYWZSZXF1ZXN0SGFuZGxlckludGVyY2VwdG9yLFxuICAgICAgfSxcbiAgICBdO1xuXG4gICAgaWYgKG9wdGlvbnMuaGFuZGxlcikge1xuICAgICAgcHJvdmlkZXJzLnB1c2gob3B0aW9ucy5oYW5kbGVyKTtcbiAgICAgIHByb3ZpZGVycy5wdXNoKHtcbiAgICAgICAgcHJvdmlkZTogQVVUSF9IQU5ETEVSLFxuICAgICAgICB1c2VDbGFzczogb3B0aW9ucy5oYW5kbGVyLFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgaWYgKG9wdGlvbnMuZ2xvYmFsKSB7XG4gICAgICAocHJvdmlkZXJzIGFzIGFueVtdKS5wdXNoKHtcbiAgICAgICAgcHJvdmlkZTogQVBQX0lOVEVSQ0VQVE9SLFxuICAgICAgICB1c2VFeGlzdGluZzogQXV0aEludGVyY2VwdG9yLFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIG1vZHVsZTogRGVjYWZBdXRoTW9kdWxlLFxuICAgICAgZ2xvYmFsOiBvcHRpb25zLmdsb2JhbCA/PyBmYWxzZSxcbiAgICAgIHByb3ZpZGVycyxcbiAgICAgIGV4cG9ydHM6IFtBdXRoSW50ZXJjZXB0b3IsIEFVVEhfSEFORExFUl0sXG4gICAgfTtcbiAgfVxufVxuIiwiaW1wb3J0IHsgSW5qZWN0LCBJbmplY3RhYmxlLCBTY29wZSB9IGZyb20gXCJAbmVzdGpzL2NvbW1vblwiO1xuaW1wb3J0IHsgRGVjYWZSZXF1ZXN0Q29udGV4dCB9IGZyb20gXCIuL0RlY2FmUmVxdWVzdENvbnRleHRcIjtcbmltcG9ydCB7IHR5cGUgRGVjYWZSZXF1ZXN0SGFuZGxlciB9IGZyb20gXCIuLi90eXBlc1wiO1xuaW1wb3J0IHsgREVDQUZfSEFORExFUlMgfSBmcm9tIFwiLi4vY29uc3RhbnRzXCI7XG5pbXBvcnQgeyBMb2dnaW5nIH0gZnJvbSBcIkBkZWNhZi10cy9sb2dnaW5nXCI7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uXG4gKiBFeGVjdXRlcyBhbGwgcmVnaXN0ZXJlZCB7QGxpbmsgRGVjYWZSZXF1ZXN0SGFuZGxlcn0gaW5zdGFuY2VzIGZvciB0aGUgY3VycmVudCByZXF1ZXN0LFxuICogcHJvdmlkaW5nIHRoZW0gd2l0aCBhIHNoYXJlZCB7QGxpbmsgRGVjYWZSZXF1ZXN0Q29udGV4dH0uXG4gKlxuICogQHN1bW1hcnlcbiAqIFRoZSB7QGxpbmsgRGVjYWZIYW5kbGVyRXhlY3V0b3J9IGNsYXNzIGlzIHJlc3BvbnNpYmxlIGZvciBvcmNoZXN0cmF0aW5nIGFuZCBleGVjdXRpbmdcbiAqIGEgc2VxdWVuY2Ugb2YgcmVxdWVzdCBoYW5kbGVycy4gRWFjaCBoYW5kbGVyIHJlY2VpdmVzIHRoZSBzYW1lIHJlcXVlc3Qtc2NvcGVkIGNvbnRleHQsXG4gKiBhbGxvd2luZyBjb29yZGluYXRlZCBwcm9jZXNzaW5nIHN1Y2ggYXMgYXV0aGVudGljYXRpb24sIG1ldGFkYXRhIGV4dHJhY3Rpb24sIGF1ZGl0aW5nLFxuICogYW5kIGN1c3RvbSBwaXBlbGluZSBiZWhhdmlvci4gSGFuZGxlcnMgYXJlIGluamVjdGVkIHZpYSB0aGUge0BsaW5rIERFQ0FGX0hBTkRMRVJTfSB0b2tlbixcbiAqIGVuc3VyaW5nIGV4dGVuc2liaWxpdHkgYW5kIGxvb3NlIGNvdXBsaW5nLlxuICpcbiAqIEBjbGFzcyBEZWNhZkhhbmRsZXJFeGVjdXRvclxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0c1xuICogLy8gRXhhbXBsZSBoYW5kbGVyOlxuICogY2xhc3MgQXV0aEhhbmRsZXIgaW1wbGVtZW50cyBEZWNhZlJlcXVlc3RIYW5kbGVyIHtcbiAqICAgYXN5bmMgaGFuZGxlKGNvbnRleHQ6IERlY2FmUmVxdWVzdENvbnRleHQsIHJlcTogUmVxdWVzdCkge1xuICogICAgIGNvbnN0IHRva2VuID0gcmVxLmhlYWRlcnNbXCJhdXRob3JpemF0aW9uXCJdO1xuICogICAgIGNvbnN0IHJlc3VsdCA9IE15U2VydmljZS5kb1NvbWV0aGluZyh0b2tlbik7XG4gKiAgICAgY29udGV4dC5zZXQoXCJteS1rZXlcIiwgcmVzdWx0KTtcbiAqICAgfVxuICogfVxuICpcbiAqIC8vIEV4ZWN1dG9yIHVzYWdlIGluIGEgcmVxdWVzdDpcbiAqIGF3YWl0IGV4ZWN1dG9yLmV4ZWMocmVxdWVzdCk7XG4gKiAvLyBBbGwgaGFuZGxlcnMgd2lsbCBydW4gaW4gc2VxdWVuY2VcbiAqIGBgYFxuICpcbiAqIEBtZXJtYWlkXG4gKiBzZXF1ZW5jZURpYWdyYW1cbiAqICAgICBwYXJ0aWNpcGFudCBDbGllbnRcbiAqICAgICBwYXJ0aWNpcGFudCBFeGVjdXRvclxuICogICAgIHBhcnRpY2lwYW50IEhhbmRsZXJBXG4gKiAgICAgcGFydGljaXBhbnQgSGFuZGxlckJcbiAqXG4gKiAgICAgQ2xpZW50LT4+RXhlY3V0b3I6IGV4ZWMocmVxKVxuICogICAgIEV4ZWN1dG9yLT4+SGFuZGxlckE6IGhhbmRsZShjb250ZXh0LCByZXEpXG4gKiAgICAgSGFuZGxlckEtLT4+RXhlY3V0b3I6IGNvbXBsZXRlZFxuICogICAgIEV4ZWN1dG9yLT4+SGFuZGxlckI6IGhhbmRsZShjb250ZXh0LCByZXEpXG4gKiAgICAgSGFuZGxlckItLT4+RXhlY3V0b3I6IGNvbXBsZXRlZFxuICogICAgIEV4ZWN1dG9yLS0+PkNsaWVudDogcHJvY2Vzc2luZyBmaW5pc2hlZFxuICovXG5ASW5qZWN0YWJsZSh7IHNjb3BlOiBTY29wZS5SRVFVRVNUIH0pXG5leHBvcnQgY2xhc3MgRGVjYWZIYW5kbGVyRXhlY3V0b3Ige1xuICBjb25zdHJ1Y3RvcihcbiAgICBASW5qZWN0KERFQ0FGX0hBTkRMRVJTKSBwcml2YXRlIHJlYWRvbmx5IGhhbmRsZXJzOiBEZWNhZlJlcXVlc3RIYW5kbGVyW10sXG4gICAgcHJpdmF0ZSByZWFkb25seSBjb250ZXh0OiBEZWNhZlJlcXVlc3RDb250ZXh0XG4gICkge31cblxuICBhc3luYyBleGVjKHJlcTogUmVxdWVzdCwgcmVzOiBSZXNwb25zZSkge1xuICAgIGNvbnN0IGxvZyA9IExvZ2dpbmcuZm9yKERlY2FmSGFuZGxlckV4ZWN1dG9yLm5hbWUpLmZvcih0aGlzLmV4ZWMpO1xuICAgIGxvZy5kZWJ1ZyhcbiAgICAgIGBDT05URVhUICR7dGhpcy5jb250ZXh0LnV1aWR9IHJ1bm5pbmcgJHt0aGlzLmhhbmRsZXJzLmxlbmd0aH0gaGFuZGxlcnMgZm9yIHJlcXVlc3QgJHtyZXEubWV0aG9kfSAke3JlcS51cmx9YFxuICAgICk7XG4gICAgZm9yIChjb25zdCBoYW5kbGVyIG9mIHRoaXMuaGFuZGxlcnMpIHtcbiAgICAgIGF3YWl0IGhhbmRsZXIuaGFuZGxlKHRoaXMuY29udGV4dCwgcmVxLCByZXMpO1xuICAgIH1cbiAgfVxufVxuIiwiaW1wb3J0IHtcbiAgSW5qZWN0YWJsZSxcbiAgTmVzdEludGVyY2VwdG9yLFxuICBFeGVjdXRpb25Db250ZXh0LFxuICBDYWxsSGFuZGxlcixcbn0gZnJvbSBcIkBuZXN0anMvY29tbW9uXCI7XG5pbXBvcnQgeyBPYnNlcnZhYmxlLCB0YXAgfSBmcm9tIFwicnhqc1wiO1xuaW1wb3J0IHsgRGVjYWZSZXF1ZXN0Q29udGV4dCB9IGZyb20gXCIuL0RlY2FmUmVxdWVzdENvbnRleHRcIjtcblxuQEluamVjdGFibGUoKVxuZXhwb3J0IGNsYXNzIERlY2FmUmVzcG9uc2VJbnRlcmNlcHRvciBpbXBsZW1lbnRzIE5lc3RJbnRlcmNlcHRvciB7XG4gIGNvbnN0cnVjdG9yKHByb3RlY3RlZCBjdHg6IERlY2FmUmVxdWVzdENvbnRleHQpIHt9XG5cbiAgaW50ZXJjZXB0KGNvbnRleHQ6IEV4ZWN1dGlvbkNvbnRleHQsIG5leHQ6IENhbGxIYW5kbGVyKTogT2JzZXJ2YWJsZTxhbnk+IHtcbiAgICBsZXQgcmVzcG9uc2UgPSBjb250ZXh0LnN3aXRjaFRvSHR0cCgpLmdldFJlc3BvbnNlKCk7XG5cbiAgICByZXR1cm4gbmV4dC5oYW5kbGUoKS5waXBlKFxuICAgICAgdGFwKChkYXRhKSA9PiB7XG4gICAgICAgIHJlc3BvbnNlID0gdGhpcy5jdHgudG9SZXNwb25zZShyZXNwb25zZSk7XG4gICAgICB9KVxuICAgICk7XG4gIH1cbn1cbiIsImltcG9ydCB7IHR5cGUgUmVxdWVzdCB9IGZyb20gXCJleHByZXNzXCI7XG5pbXBvcnQgeyBEZWNhZkNvbnRyb2xsZXIgYXMgSHR0cERlY2FmQ29udHJvbGxlciB9IGZyb20gXCJAZGVjYWYtdHMvZm9yLWh0dHAvc2VydmVyXCI7XG5pbXBvcnQge1xuICBDb250ZXh0LFxuICBNb2RlbFNlcnZpY2UsXG4gIFJlcG8sXG4gIFJlcG9zaXRvcnksXG4gIFNlcnZpY2UsXG59IGZyb20gXCJAZGVjYWYtdHMvY29yZVwiO1xuaW1wb3J0IHsgTW9kZWwsIHR5cGUgTW9kZWxDb25zdHJ1Y3RvciB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdG9yLXZhbGlkYXRpb25cIjtcblxuaW1wb3J0IHsgRGVjYWZTZXJ2ZXJDdHggfSBmcm9tIFwiLi9jb25zdGFudHNcIjtcbmltcG9ydCB7IERlY2FmUmVxdWVzdENvbnRleHQgfSBmcm9tIFwiLi9yZXF1ZXN0L0RlY2FmUmVxdWVzdENvbnRleHRcIjtcblxuZXhwb3J0IGFic3RyYWN0IGNsYXNzIERlY2FmQ29udHJvbGxlcjxcbiAgQ09OVEVYVCBleHRlbmRzIERlY2FmU2VydmVyQ3R4ID0gRGVjYWZTZXJ2ZXJDdHgsXG4+IGV4dGVuZHMgSHR0cERlY2FmQ29udHJvbGxlcjxSZXF1ZXN0LCBhbnksIERlY2FmUmVxdWVzdENvbnRleHQ+IHtcbiAgcHJvdGVjdGVkIGNvbnN0cnVjdG9yKFxuICAgIHByb3RlY3RlZCByZWFkb25seSBjbGllbnRDb250ZXh0OiBEZWNhZlJlcXVlc3RDb250ZXh0LFxuICAgIF9uYW1lOiBzdHJpbmdcbiAgKSB7XG4gICAgc3VwZXIoY2xpZW50Q29udGV4dCk7XG4gIH1cbn1cblxuZXhwb3J0IGFic3RyYWN0IGNsYXNzIERlY2FmTW9kZWxDb250cm9sbGVyPFxuICBNIGV4dGVuZHMgTW9kZWw8Ym9vbGVhbj4sXG4gIEMgZXh0ZW5kcyBEZWNhZlNlcnZlckN0eCA9IERlY2FmU2VydmVyQ3R4LFxuPiBleHRlbmRzIERlY2FmQ29udHJvbGxlcjxDPiB7XG4gIHByaXZhdGUgX3BlcnNpc3RlbmNlPzogUmVwbzxNPiB8IE1vZGVsU2VydmljZTxNPjtcblxuICBwcm90ZWN0ZWQgY29uc3RydWN0b3IoXG4gICAgcHJvdGVjdGVkIG92ZXJyaWRlIHJlYWRvbmx5IGNsaWVudENvbnRleHQ6IERlY2FmUmVxdWVzdENvbnRleHQsXG4gICAgX25hbWU6IHN0cmluZ1xuICApIHtcbiAgICBzdXBlcihjbGllbnRDb250ZXh0LCBfbmFtZSk7XG4gIH1cblxuICBhYnN0cmFjdCBnZXQgY2xhc3MoKTogTW9kZWxDb25zdHJ1Y3RvcjxNPjtcblxuICBwZXJzaXN0ZW5jZShjdHg/OiBDb250ZXh0PGFueT4pOiBSZXBvPE0+IHwgTW9kZWxTZXJ2aWNlPE0+IHtcbiAgICBpZiAoIXRoaXMuX3BlcnNpc3RlbmNlKVxuICAgICAgdHJ5IHtcbiAgICAgICAgdGhpcy5fcGVyc2lzdGVuY2UgPSBTZXJ2aWNlLmdldDxNb2RlbFNlcnZpY2U8TT4+KHRoaXMuY2xhc3MpO1xuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVudXNlZC12YXJzXG4gICAgICB9IGNhdGNoIChlOiB1bmtub3duKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgdGhpcy5fcGVyc2lzdGVuY2UgPSBNb2RlbFNlcnZpY2UuZ2V0U2VydmljZShcbiAgICAgICAgICAgIHRoaXMuY2xhc3NcbiAgICAgICAgICApIGFzIE1vZGVsU2VydmljZTxNPjtcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVudXNlZC12YXJzXG4gICAgICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgICAgICB0aGlzLl9wZXJzaXN0ZW5jZSA9IFJlcG9zaXRvcnkuZm9yTW9kZWwodGhpcy5jbGFzcykgYXMgUmVwbzxNPjtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgY29uc3Qgb3ZlcnJpZGVzID0gdGhpcy5jbGllbnRDb250ZXh0LnRvT3ZlcnJpZGVzKCk7XG5cbiAgICByZXR1cm4gY3R4XG4gICAgICA/IHRoaXMuX3BlcnNpc3RlbmNlIGluc3RhbmNlb2YgUmVwb3NpdG9yeVxuICAgICAgICA/IHRoaXMuX3BlcnNpc3RlbmNlLm92ZXJyaWRlKG92ZXJyaWRlcylcbiAgICAgICAgOiB0aGlzLl9wZXJzaXN0ZW5jZS5mb3Iob3ZlcnJpZGVzKVxuICAgICAgOiB0aGlzLl9wZXJzaXN0ZW5jZTtcbiAgfVxufVxuIiwiaW1wb3J0IHtcbiAgQnVsa0NydWRPcGVyYXRpb25LZXlzLFxuICBJbnRlcm5hbEVycm9yLFxuICBPcGVyYXRpb25LZXlzLFxufSBmcm9tIFwiQGRlY2FmLXRzL2RiLWRlY29yYXRvcnNcIjtcbmltcG9ydCB7IENvbnN0cnVjdG9yLCBNZXRhZGF0YSB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdGlvblwiO1xuaW1wb3J0IHsgQXBpUHJvcGVydHkgfSBmcm9tIFwiLi4vLi4vb3ZlcnJpZGVzL2RlY29yYXRpb25cIjtcbmltcG9ydCB7IE1vZGVsLCBWYWxpZGF0aW9uS2V5cyB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdG9yLXZhbGlkYXRpb25cIjtcbmltcG9ydCB7IFRyYW5zYWN0aW9uT3BlcmF0aW9uS2V5cyB9IGZyb20gXCJAZGVjYWYtdHMvY29yZVwiO1xuaW1wb3J0IHsgdG9QYXNjYWxDYXNlIH0gZnJvbSBcIkBkZWNhZi10cy9sb2dnaW5nXCI7XG5pbXBvcnQgeyBERUNPUkFUT1JTIH0gZnJvbSBcIi4uLy4uL292ZXJyaWRlcy9jb25zdGFudHNcIjtcblxuY29uc3QgZHRvQ2FjaGUgPSBuZXcgTWFwPFxuICBPcGVyYXRpb25LZXlzLFxuICBXZWFrTWFwPENvbnN0cnVjdG9yPGFueT4sIENvbnN0cnVjdG9yPGFueT4+XG4+KCk7XG5cbi8qKlxuICogQnVpbGRzIGEgTmVzdC9Td2FnZ2VyIERUTyBjbGFzcyBmb3IgdGhlIGdpdmVuIG1vZGVsIGFuZCBDUlVEIG9wZXJhdGlvbi5cbiAqXG4gKiBSdWxlczpcbiAqICAtIE9ubHkgQ1JFQVRFIGFuZCBVUERBVEUgKGFuZCB0aGVpciBidWxrIHZhcmlhbnRzKSBwcm9kdWNlIGEgRFRPO1xuICogICAgYWxsIG90aGVyIG9wZXJhdGlvbnMgcmV0dXJuIHRoZSBvcmlnaW5hbCBtb2RlbCBjbGFzcyB1bmNoYW5nZWQuXG4gKiAgLSBAZ2VuZXJhdGVkKCkgcHJvcGVydGllcyAoY3JlYXRlZEF0LCB1cGRhdGVkQXQsIGNyZWF0ZWRCeSwgdXBkYXRlZEJ5LFxuICogICAgdXVpZCwgdmVyc2lvbiwgQGNvbXBvc2VkIHBrcywg4oCmKSBhcmUgKipuZXZlcioqIGV4cG9zZWQgaW4gYW55IERUTy5cbiAqICAtIFRoZSBAcGsoKSBwcm9wZXJ0eTpcbiAqICAgICAg4oCiIFVQREFURSDigJMgYWx3YXlzIGluY2x1ZGVkLlxuICogICAgICDigKIgQ1JFQVRFICDigJMgaW5jbHVkZWQgb25seSB3aGVuIHRoZSBwayBpcyBOT1QgYXV0by1nZW5lcmF0ZWRcbiAqICAgICAgICAgICAgICAgICAgKGNoZWNrZWQgdmlhIE1vZGVsLnBrUHJvcHMoKS5nZW5lcmF0ZWQgQU5EIE1vZGVsLmdlbmVyYXRlZCgpKS5cbiAqICAtIFJlbGF0aW9uIHByb3BlcnRpZXMgKEBvbmVUb09uZSwgQG9uZVRvTWFueSwg4oCmKTpcbiAqICAgICAg4oCiIENSRUFURSAg4oCTIG5lc3RlZCBhcyBEdG9Gb3IoQ1JFQVRFLCBSZWxhdGVkTW9kZWwpLiBXaGVuIHRoZSByZWxhdGlvblxuICogICAgICAgICAgICAgICAgICBjcmVhdGVzIGEgY2lyY3VsYXIgcmVmZXJlbmNlIChtb2RlbCBBIOKGkiBtb2RlbCBCIOKGkiBtb2RlbCBBKSxcbiAqICAgICAgICAgICAgICAgICAgdGhlIGJhY2stcmVmZXJlbmNlIHVzZXMgdGhlIHJlbGF0ZWQgbW9kZWwncyBQSyB0eXBlXG4gKiAgICAgICAgICAgICAgICAgIChzdHJpbmcvaW50ZWdlcikgaW5zdGVhZCBvZiB0aGUgZnVsbCBEVE8gdG8gYnJlYWsgdGhlIGN5Y2xlLlxuICogICAgICDigKIgVVBEQVRFICDigJMgdW5pb24gb2YgRHRvRm9yKFVQREFURSwgUmVsYXRlZE1vZGVsKSAqKm9yKiogdGhlXG4gKiAgICAgICAgICAgICAgICAgIHJlbGF0ZWQgbW9kZWwncyBwcmltYXJ5LWtleSB0eXBlIChzdHJpbmcgLyBpbnRlZ2VyKSxcbiAqICAgICAgICAgICAgICAgICAgZXhwcmVzc2VkIGFzIGEgU3dhZ2dlciBvbmVPZi4gQ2lyY3VsYXIgYmFjay1yZWZlcmVuY2VzXG4gKiAgICAgICAgICAgICAgICAgIG9taXQgdGhlIERUTyAkcmVmIGFuZCBvbmx5IGluY2x1ZGUgdGhlIFBLIHR5cGUuXG4gKlxuICogTWV0YWRhdGEucHJvcGVydGllcygpIG5vdyByZXR1cm5zIEFMTCBwcm9wZXJ0aWVzIGFjcm9zcyB0aGUgcHJvdG90eXBlIGNoYWluLFxuICogc28gRFRPIGluaGVyaXRhbmNlIGlzIG5vIGxvbmdlciBuZWVkZWQ7IGV2ZXJ5IERUTyBpcyBhIGZsYXQgY2xhc3MuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBEdG9Gb3I8TSBleHRlbmRzIE1vZGVsPihcbiAgb3A6IE9wZXJhdGlvbktleXMsXG4gIG1vZGVsOiBDb25zdHJ1Y3RvcjxNPixcbiAgc3RhY2s6IFNldDxDb25zdHJ1Y3Rvcjxhbnk+PiA9IG5ldyBTZXQoKVxuKTogQ29uc3RydWN0b3I8YW55PiB7XG4gIGlmICghVHJhbnNhY3Rpb25PcGVyYXRpb25LZXlzLmluY2x1ZGVzKG9wKSkge1xuICAgIHJldHVybiBtb2RlbDtcbiAgfVxuXG4gIGNvbnN0IGNhY2hlID0gZ2V0RHRvQ2FjaGUob3ApO1xuICBjb25zdCBjYWNoZWQgPSBjYWNoZS5nZXQobW9kZWwpO1xuICBpZiAoY2FjaGVkKSByZXR1cm4gY2FjaGVkO1xuXG4gIGNvbnN0IGlzVXBkYXRlT3AgPSBbXG4gICAgT3BlcmF0aW9uS2V5cy5VUERBVEUsXG4gICAgQnVsa0NydWRPcGVyYXRpb25LZXlzLlVQREFURV9BTEwsXG4gIF0uaW5jbHVkZXMob3AgYXMgYW55KTtcblxuICBjbGFzcyBEeW5hbWljRFRPIHt9XG4gIGNhY2hlLnNldChtb2RlbCwgRHluYW1pY0RUTyk7XG5cbiAgT2JqZWN0LmRlZmluZVByb3BlcnR5KER5bmFtaWNEVE8sIFwibmFtZVwiLCB7XG4gICAgdmFsdWU6IGAke3RvUGFzY2FsQ2FzZShtb2RlbC5uYW1lKX0ke3RvUGFzY2FsQ2FzZShvcCl9RFRPYCxcbiAgfSk7XG5cbiAgY29uc3QgcGtQcm9wID0gKCgpID0+IHtcbiAgICB0cnkge1xuICAgICAgcmV0dXJuIE1vZGVsLnBrKG1vZGVsKTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuICB9KSgpO1xuXG4gIGNvbnN0IHBrUHJvcHNNZXRhZGF0YSA9IHBrUHJvcCA/IE1vZGVsLnBrUHJvcHMobW9kZWwgYXMgYW55KSA6IHVuZGVmaW5lZDtcbiAgY29uc3QgcGtEZXNpZ25UeXBlID0gcGtQcm9wXG4gICAgPyBSZWZsZWN0LmdldE1ldGFkYXRhKFwiZGVzaWduOnR5cGVcIiwgbW9kZWwucHJvdG90eXBlLCBwa1Byb3AgYXMgc3RyaW5nKVxuICAgIDogdW5kZWZpbmVkO1xuICBjb25zdCBwa1R5cGVJc051bWVyaWMgPVxuICAgIHBrRGVzaWduVHlwZSA9PT0gTnVtYmVyIHx8IHBrRGVzaWduVHlwZSA9PT0gQmlnSW50O1xuICBjb25zdCBwa0lzR2VuZXJhdGVkID1cbiAgICAhIXBrUHJvcHNNZXRhZGF0YT8uZ2VuZXJhdGVkIHx8XG4gICAgKHBrUHJvcFxuICAgICAgPyBNb2RlbC5nZW5lcmF0ZWRCeVNlcXVlbmNlKG1vZGVsIGFzIGFueSwgcGtQcm9wIGFzIGFueSkgfHxcbiAgICAgICAgaXNQcm9wZXJ0eUdlbmVyYXRlZEFjcm9zc0luaGVyaXRhbmNlKG1vZGVsLCBwa1Byb3AgYXMgc3RyaW5nKSB8fFxuICAgICAgICBwa1R5cGVJc051bWVyaWNcbiAgICAgIDogZmFsc2UpO1xuXG4gIGNvbnN0IGFsbFByb3BzID0gQXJyYXkuZnJvbShuZXcgU2V0KE1ldGFkYXRhLnByb3BlcnRpZXMobW9kZWwpIHx8IFtdKSk7XG4gIGNvbnN0IHJlbGF0aW9ucyA9IG5ldyBTZXQ8c3RyaW5nPigoTW9kZWwucmVsYXRpb25zKG1vZGVsKSBhcyBzdHJpbmdbXSkgfHwgW10pO1xuICBjb25zdCBzY2FsYXJQcm9wczogc3RyaW5nW10gPSBbXTtcblxuICBmb3IgKGNvbnN0IHByb3Agb2YgYWxsUHJvcHMpIHtcbiAgICBpZiAoIXByb3ApIGNvbnRpbnVlO1xuICAgIGlmIChyZWxhdGlvbnMuaGFzKHByb3ApKSBjb250aW51ZTtcblxuICAgIGlmIChwcm9wID09PSBwa1Byb3AgJiYgIWlzVXBkYXRlT3AgJiYgcGtJc0dlbmVyYXRlZCkgY29udGludWU7XG4gICAgaWYgKHByb3AgIT09IHBrUHJvcCAmJiBpc1Byb3BlcnR5R2VuZXJhdGVkQWNyb3NzSW5oZXJpdGFuY2UobW9kZWwsIHByb3ApKVxuICAgICAgY29udGludWU7XG5cbiAgICBzY2FsYXJQcm9wcy5wdXNoKHByb3ApO1xuICB9XG5cbiAgZm9yIChjb25zdCBwcm9wIG9mIHNjYWxhclByb3BzKSB7XG4gICAgY29uc3QgdmFsaWRhdGlvbiA9IGdldFZhbGlkYXRpb25BY3Jvc3NJbmhlcml0YW5jZShtb2RlbCwgcHJvcCk7XG4gICAgY29uc3QgaXNSZXF1aXJlZCA9ICEhdmFsaWRhdGlvbj8uW1ZhbGlkYXRpb25LZXlzLlJFUVVJUkVEXTtcbiAgICBjb25zdCB0eXBlSGludCA9XG4gICAgICBnZXRUeXBlQWNyb3NzSW5oZXJpdGFuY2UobW9kZWwsIHByb3ApID8/XG4gICAgICBSZWZsZWN0LmdldE1ldGFkYXRhKFwiZGVzaWduOnR5cGVcIiwgbW9kZWwucHJvdG90eXBlLCBwcm9wKTtcblxuICAgIGNvbnN0IGFwaU9wdGlvbnM6IFBhcmFtZXRlcnM8dHlwZW9mIEFwaVByb3BlcnR5PlswXSA9IHtcbiAgICAgIHJlcXVpcmVkOiBpc1JlcXVpcmVkLFxuICAgIH07XG4gICAgaWYgKHR5cGVIaW50KSBhcGlPcHRpb25zLnR5cGUgPSB0eXBlSGludDtcblxuICAgIEFwaVByb3BlcnR5KGFwaU9wdGlvbnMpKER5bmFtaWNEVE8ucHJvdG90eXBlLCBwcm9wKTtcblxuICAgIGNvbnN0IGRlc2lnblR5cGUgPVxuICAgICAgUmVmbGVjdC5nZXRNZXRhZGF0YShcImRlc2lnbjp0eXBlXCIsIG1vZGVsLnByb3RvdHlwZSwgcHJvcCkgPz8gdHlwZUhpbnQ7XG4gICAgaWYgKHR5cGVvZiBkZXNpZ25UeXBlICE9PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgICBSZWZsZWN0LmRlZmluZU1ldGFkYXRhKFxuICAgICAgICBcImRlc2lnbjp0eXBlXCIsXG4gICAgICAgIGRlc2lnblR5cGUsXG4gICAgICAgIER5bmFtaWNEVE8ucHJvdG90eXBlLFxuICAgICAgICBwcm9wXG4gICAgICApO1xuICAgIH1cblxuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShEeW5hbWljRFRPLnByb3RvdHlwZSwgcHJvcCwge1xuICAgICAgdmFsdWU6IHVuZGVmaW5lZCxcbiAgICAgIHdyaXRhYmxlOiB0cnVlLFxuICAgICAgZW51bWVyYWJsZTogdHJ1ZSxcbiAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZSxcbiAgICB9KTtcbiAgfVxuXG4gIGZvciAoY29uc3QgcmVsYXRpb24gb2YgcmVsYXRpb25zKSB7XG4gICAgY29uc3QgcmVsYXRpb25NZXRhID0gTWV0YWRhdGEucmVsYXRpb25zKG1vZGVsLCByZWxhdGlvbiBhcyBhbnkpO1xuICAgIGlmICghcmVsYXRpb25NZXRhKSB7XG4gICAgICB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihgTWV0YWRhdGEgZm9yIHJlbGF0aW9uICR7cmVsYXRpb259IG5vdCBmb3VuZGApO1xuICAgIH1cblxuICAgIGxldCByZWxhdGlvblR5cGU6IENvbnN0cnVjdG9yPGFueT4gfCB1bmRlZmluZWQgPVxuICAgICAgcmVsYXRpb25NZXRhLmNsYXNzIGFzIENvbnN0cnVjdG9yPGFueT47XG4gICAgaWYgKHR5cGVvZiByZWxhdGlvblR5cGUgPT09IFwiZnVuY3Rpb25cIiAmJiAhcmVsYXRpb25UeXBlLm5hbWUpIHtcbiAgICAgIHJlbGF0aW9uVHlwZSA9IChyZWxhdGlvblR5cGUgYXMgYW55KSgpO1xuICAgIH1cbiAgICBpZiAoIXJlbGF0aW9uVHlwZSB8fCB0eXBlb2YgcmVsYXRpb25UeXBlICE9PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKGBUeXBlIGZvciByZWxhdGlvbiAke3JlbGF0aW9ufSBub3QgZm91bmRgKTtcbiAgICB9XG4gICAgaWYgKCFNb2RlbC5nZXQocmVsYXRpb25UeXBlLm5hbWUpKSB7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG5cbiAgICBjb25zdCBtZXRhID0gTWV0YWRhdGEudmFsaWRhdGlvbkZvcihtb2RlbCwgcmVsYXRpb24gYXMgYW55KTtcbiAgICBjb25zdCBpc0FycmF5ID0gISEobWV0YSBhcyBhbnkpPy5bVmFsaWRhdGlvbktleXMuTElTVF07XG4gICAgY29uc3QgaXNSZXF1aXJlZCA9ICEhKG1ldGEgYXMgYW55KT8uW1ZhbGlkYXRpb25LZXlzLlJFUVVJUkVEXTtcblxuICAgIC8vIERldGVjdCBjaXJjdWxhciByZWZlcmVuY2U6IGlmIHRoZSByZWxhdGVkIG1vZGVsIGlzIGFscmVhZHkgaW4gdGhlXG4gICAgLy8gcmVjdXJzaW9uIHN0YWNrLCB1c2UgdGhlIFBLIHR5cGUgaW5zdGVhZCBvZiB0aGUgZnVsbCBEVE8gdG8gYnJlYWtcbiAgICAvLyB0aGUgY3ljbGUuIFRoaXMgcHJldmVudHMgQG5lc3Rqcy9zd2FnZ2VyJ3MgU2NoZW1hT2JqZWN0RmFjdG9yeSBmcm9tXG4gICAgLy8gaW5maW5pdGVseSByZWN1cnNpbmcgd2hlbiBleHBsb3JpbmcgdGhlIHNjaGVtYXMuXG4gICAgY29uc3QgaXNDaXJjdWxhciA9IHN0YWNrLmhhcyhyZWxhdGlvblR5cGUpO1xuXG4gICAgaWYgKGlzQ2lyY3VsYXIpIHtcbiAgICAgIGNvbnN0IHBrVHlwZU5hbWUgPSBnZXRQa09wZW5BcGlUeXBlKHJlbGF0aW9uVHlwZSk7XG4gICAgICBhZGRSZWxhdGlvblBrUmVmKER5bmFtaWNEVE8sIHJlbGF0aW9uLCBwa1R5cGVOYW1lLCBpc0FycmF5LCBpc1JlcXVpcmVkKTtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cblxuICAgIGNvbnN0IHJlbGF0aW9uRHRvID0gRHRvRm9yKG9wLCByZWxhdGlvblR5cGUsIG5ldyBTZXQoc3RhY2spLmFkZChtb2RlbCkpO1xuXG4gICAgaWYgKGlzVXBkYXRlT3ApIHtcbiAgICAgIGFkZFJlbGF0aW9uVXBkYXRlKFxuICAgICAgICBEeW5hbWljRFRPLFxuICAgICAgICByZWxhdGlvbixcbiAgICAgICAgcmVsYXRpb25UeXBlLFxuICAgICAgICByZWxhdGlvbkR0byxcbiAgICAgICAgaXNBcnJheSxcbiAgICAgICAgaXNSZXF1aXJlZFxuICAgICAgKTtcbiAgICB9IGVsc2Uge1xuICAgICAgYWRkUmVsYXRpb24oRHluYW1pY0RUTywgcmVsYXRpb24sIHJlbGF0aW9uRHRvLCBpc0FycmF5LCBpc1JlcXVpcmVkKTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gRHluYW1pY0RUTztcbn1cblxuZnVuY3Rpb24gYWRkUmVsYXRpb24oXG4gIER0b0NsYXNzOiBhbnksXG4gIHJlbGF0aW9uOiBzdHJpbmcsXG4gIHJlbGF0aW9uRHRvOiBhbnksXG4gIGlzQXJyYXk6IGJvb2xlYW4sXG4gIGlzUmVxdWlyZWQ6IGJvb2xlYW5cbik6IHZvaWQge1xuICBjb25zdCBhcGlPcHRpb25zOiBQYXJhbWV0ZXJzPHR5cGVvZiBBcGlQcm9wZXJ0eT5bMF0gPSB7XG4gICAgdHlwZTogcmVsYXRpb25EdG8sXG4gICAgcmVxdWlyZWQ6IGlzUmVxdWlyZWQsXG4gICAgaXNBcnJheSxcbiAgfTtcbiAgQXBpUHJvcGVydHkoYXBpT3B0aW9ucykoRHRvQ2xhc3MucHJvdG90eXBlLCByZWxhdGlvbik7XG4gIFJlZmxlY3QuZGVmaW5lTWV0YWRhdGEoXG4gICAgXCJkZXNpZ246dHlwZVwiLFxuICAgIGlzQXJyYXkgPyBBcnJheSA6IHJlbGF0aW9uRHRvLFxuICAgIER0b0NsYXNzLnByb3RvdHlwZSxcbiAgICByZWxhdGlvblxuICApO1xuICBPYmplY3QuZGVmaW5lUHJvcGVydHkoRHRvQ2xhc3MucHJvdG90eXBlLCByZWxhdGlvbiwge1xuICAgIHZhbHVlOiB1bmRlZmluZWQsXG4gICAgd3JpdGFibGU6IHRydWUsXG4gICAgZW51bWVyYWJsZTogdHJ1ZSxcbiAgICBjb25maWd1cmFibGU6IHRydWUsXG4gIH0pO1xufVxuXG4vKipcbiAqIEFkZHMgYSByZWxhdGlvbiBwcm9wZXJ0eSB0aGF0IHVzZXMgdGhlIFBLIHR5cGUgKHN0cmluZy9pbnRlZ2VyKSBpbnN0ZWFkIG9mXG4gKiBhIGZ1bGwgRFRPIGNsYXNzLiBVc2VkIHRvIGJyZWFrIGNpcmN1bGFyIHJlZmVyZW5jZXMgKGUuZy4gQ3VzdG9tZXIg4oaSIE9yZGVyIOKGkiBDdXN0b21lcikuXG4gKi9cbmZ1bmN0aW9uIGFkZFJlbGF0aW9uUGtSZWYoXG4gIER0b0NsYXNzOiBhbnksXG4gIHJlbGF0aW9uOiBzdHJpbmcsXG4gIHBrVHlwZU5hbWU6IHN0cmluZyxcbiAgaXNBcnJheTogYm9vbGVhbixcbiAgaXNSZXF1aXJlZDogYm9vbGVhblxuKTogdm9pZCB7XG4gIGNvbnN0IGFwaU9wdGlvbnM6IFBhcmFtZXRlcnM8dHlwZW9mIEFwaVByb3BlcnR5PlswXSA9IGlzQXJyYXlcbiAgICA/ICh7IHR5cGU6IFwiYXJyYXlcIiwgaXRlbXM6IHsgdHlwZTogcGtUeXBlTmFtZSB9LCByZXF1aXJlZDogaXNSZXF1aXJlZCB9IGFzIGFueSlcbiAgICA6ICh7IHR5cGU6IHBrVHlwZU5hbWUgPT09IFwiaW50ZWdlclwiID8gTnVtYmVyIDogU3RyaW5nLCByZXF1aXJlZDogaXNSZXF1aXJlZCB9IGFzIGFueSk7XG4gIEFwaVByb3BlcnR5KGFwaU9wdGlvbnMpKER0b0NsYXNzLnByb3RvdHlwZSwgcmVsYXRpb24pO1xuICBSZWZsZWN0LmRlZmluZU1ldGFkYXRhKFxuICAgIFwiZGVzaWduOnR5cGVcIixcbiAgICBpc0FycmF5ID8gQXJyYXkgOiAocGtUeXBlTmFtZSA9PT0gXCJpbnRlZ2VyXCIgPyBOdW1iZXIgOiBTdHJpbmcpLFxuICAgIER0b0NsYXNzLnByb3RvdHlwZSxcbiAgICByZWxhdGlvblxuICApO1xuICBPYmplY3QuZGVmaW5lUHJvcGVydHkoRHRvQ2xhc3MucHJvdG90eXBlLCByZWxhdGlvbiwge1xuICAgIHZhbHVlOiB1bmRlZmluZWQsXG4gICAgd3JpdGFibGU6IHRydWUsXG4gICAgZW51bWVyYWJsZTogdHJ1ZSxcbiAgICBjb25maWd1cmFibGU6IHRydWUsXG4gIH0pO1xufVxuXG5mdW5jdGlvbiBhZGRSZWxhdGlvblVwZGF0ZShcbiAgRHRvQ2xhc3M6IGFueSxcbiAgcmVsYXRpb246IHN0cmluZyxcbiAgcmVsYXRpb25UeXBlOiBDb25zdHJ1Y3Rvcjxhbnk+LFxuICByZWxhdGlvbkR0bzogYW55LFxuICBpc0FycmF5OiBib29sZWFuLFxuICBpc1JlcXVpcmVkOiBib29sZWFuXG4pOiB2b2lkIHtcbiAgY29uc3QgZXh0cmFNb2RlbHMgPVxuICAgIFJlZmxlY3QuZ2V0TWV0YWRhdGEoREVDT1JBVE9SUy5BUElfRVhUUkFfTU9ERUxTLCBEdG9DbGFzcykgfHwgW107XG4gIGlmICghZXh0cmFNb2RlbHMuaW5jbHVkZXMocmVsYXRpb25EdG8pKSB7XG4gICAgUmVmbGVjdC5kZWZpbmVNZXRhZGF0YShcbiAgICAgIERFQ09SQVRPUlMuQVBJX0VYVFJBX01PREVMUyxcbiAgICAgIFsuLi5leHRyYU1vZGVscywgcmVsYXRpb25EdG9dLFxuICAgICAgRHRvQ2xhc3NcbiAgICApO1xuICB9XG5cbiAgY29uc3QgZHRvUmVmID0gYCMvY29tcG9uZW50cy9zY2hlbWFzLyR7cmVsYXRpb25EdG8ubmFtZX1gO1xuICBjb25zdCBwa1R5cGVOYW1lID0gZ2V0UGtPcGVuQXBpVHlwZShyZWxhdGlvblR5cGUpO1xuICBjb25zdCBvbmVPZkl0ZW1zID0gW3sgJHJlZjogZHRvUmVmIH0sIHsgdHlwZTogcGtUeXBlTmFtZSB9XTtcblxuICBjb25zdCBhcGlPcHRpb25zOiBQYXJhbWV0ZXJzPHR5cGVvZiBBcGlQcm9wZXJ0eT5bMF0gPSBpc0FycmF5XG4gICAgPyAoeyB0eXBlOiBcImFycmF5XCIsIHJlcXVpcmVkOiBpc1JlcXVpcmVkLCBvbmVPZjogb25lT2ZJdGVtcyB9IGFzIGFueSlcbiAgICA6ICh7IHR5cGU6IE9iamVjdCwgcmVxdWlyZWQ6IGlzUmVxdWlyZWQsIG9uZU9mOiBvbmVPZkl0ZW1zIH0gYXMgYW55KTtcblxuICBBcGlQcm9wZXJ0eShhcGlPcHRpb25zKShEdG9DbGFzcy5wcm90b3R5cGUsIHJlbGF0aW9uKTtcbiAgUmVmbGVjdC5kZWZpbmVNZXRhZGF0YShcbiAgICBcImRlc2lnbjp0eXBlXCIsXG4gICAgaXNBcnJheSA/IEFycmF5IDogT2JqZWN0LFxuICAgIER0b0NsYXNzLnByb3RvdHlwZSxcbiAgICByZWxhdGlvblxuICApO1xuICBPYmplY3QuZGVmaW5lUHJvcGVydHkoRHRvQ2xhc3MucHJvdG90eXBlLCByZWxhdGlvbiwge1xuICAgIHZhbHVlOiB1bmRlZmluZWQsXG4gICAgd3JpdGFibGU6IHRydWUsXG4gICAgZW51bWVyYWJsZTogdHJ1ZSxcbiAgICBjb25maWd1cmFibGU6IHRydWUsXG4gIH0pO1xufVxuXG5mdW5jdGlvbiBnZXRQa09wZW5BcGlUeXBlKHJlbGF0aW9uVHlwZTogQ29uc3RydWN0b3I8YW55Pik6IHN0cmluZyB7XG4gIHRyeSB7XG4gICAgY29uc3QgcGtQcm9wc01ldGFkYXRhID0gTW9kZWwucGtQcm9wcyhyZWxhdGlvblR5cGUgYXMgYW55KTtcbiAgICBjb25zdCBwa1R5cGUgPSBwa1Byb3BzTWV0YWRhdGE/LnR5cGU7XG4gICAgaWYgKHBrVHlwZSA9PT0gTnVtYmVyIHx8IHBrVHlwZSA9PT0gQmlnSW50KSByZXR1cm4gXCJpbnRlZ2VyXCI7XG4gICAgcmV0dXJuIFwic3RyaW5nXCI7XG4gIH0gY2F0Y2gge1xuICAgIHJldHVybiBcInN0cmluZ1wiO1xuICB9XG59XG5cbmZ1bmN0aW9uIGlzUHJvcGVydHlHZW5lcmF0ZWRBY3Jvc3NJbmhlcml0YW5jZShcbiAgbW9kZWw6IENvbnN0cnVjdG9yPGFueT4sXG4gIHByb3A6IHN0cmluZ1xuKTogYm9vbGVhbiB7XG4gIGxldCBjdXJyZW50OiBhbnkgPSBtb2RlbDtcbiAgd2hpbGUgKGN1cnJlbnQgJiYgY3VycmVudCAhPT0gT2JqZWN0ICYmIGN1cnJlbnQgIT09IEZ1bmN0aW9uKSB7XG4gICAgaWYgKE1vZGVsLmdlbmVyYXRlZChjdXJyZW50LCBwcm9wIGFzIGFueSkpIHJldHVybiB0cnVlO1xuICAgIGN1cnJlbnQgPSBPYmplY3QuZ2V0UHJvdG90eXBlT2YoY3VycmVudCk7XG4gIH1cbiAgcmV0dXJuIGZhbHNlO1xufVxuXG5mdW5jdGlvbiBnZXRWYWxpZGF0aW9uQWNyb3NzSW5oZXJpdGFuY2UoXG4gIG1vZGVsOiBDb25zdHJ1Y3Rvcjxhbnk+LFxuICBwcm9wOiBzdHJpbmdcbik6IFJlY29yZDxzdHJpbmcsIGFueT4gfCB1bmRlZmluZWQge1xuICBsZXQgY3VycmVudDogYW55ID0gbW9kZWw7XG4gIHdoaWxlIChjdXJyZW50ICYmIGN1cnJlbnQgIT09IE9iamVjdCAmJiBjdXJyZW50ICE9PSBGdW5jdGlvbikge1xuICAgIGNvbnN0IHZhbGlkYXRpb24gPSBNZXRhZGF0YS52YWxpZGF0aW9uRm9yKGN1cnJlbnQsIHByb3AgYXMgYW55KTtcbiAgICBpZiAodmFsaWRhdGlvbikgcmV0dXJuIHZhbGlkYXRpb24gYXMgYW55O1xuICAgIGN1cnJlbnQgPSBPYmplY3QuZ2V0UHJvdG90eXBlT2YoY3VycmVudCk7XG4gIH1cbiAgcmV0dXJuIHVuZGVmaW5lZDtcbn1cblxuZnVuY3Rpb24gZ2V0VHlwZUFjcm9zc0luaGVyaXRhbmNlKG1vZGVsOiBDb25zdHJ1Y3Rvcjxhbnk+LCBwcm9wOiBzdHJpbmcpOiBhbnkge1xuICBsZXQgY3VycmVudDogYW55ID0gbW9kZWw7XG4gIHdoaWxlIChjdXJyZW50ICYmIGN1cnJlbnQgIT09IE9iamVjdCAmJiBjdXJyZW50ICE9PSBGdW5jdGlvbikge1xuICAgIGNvbnN0IHR5cGUgPSBNZXRhZGF0YS50eXBlKGN1cnJlbnQsIHByb3ApO1xuICAgIGlmICh0eXBlKSByZXR1cm4gdHlwZTtcbiAgICBjdXJyZW50ID0gT2JqZWN0LmdldFByb3RvdHlwZU9mKGN1cnJlbnQpO1xuICB9XG4gIHJldHVybiB1bmRlZmluZWQ7XG59XG5cbmZ1bmN0aW9uIGdldER0b0NhY2hlKFxuICBvcDogT3BlcmF0aW9uS2V5c1xuKTogV2Vha01hcDxDb25zdHJ1Y3Rvcjxhbnk+LCBDb25zdHJ1Y3Rvcjxhbnk+PiB7XG4gIGlmICghZHRvQ2FjaGUuaGFzKG9wKSkge1xuICAgIGR0b0NhY2hlLnNldChvcCwgbmV3IFdlYWtNYXAoKSk7XG4gIH1cbiAgcmV0dXJuIGR0b0NhY2hlLmdldChvcCkhO1xufVxuIiwiaW1wb3J0IHsgQ29udHJvbGxlciwgUGFyYW0sIFF1ZXJ5LCBSZXNwb25zZSwgU2V0TWV0YWRhdGEgfSBmcm9tIFwiQG5lc3Rqcy9jb21tb25cIjtcbmltcG9ydCB7XG4gIEFwaUJhZFJlcXVlc3RSZXNwb25zZSxcbiAgQXBpQm9keSxcbiAgQXBpQ3JlYXRlZFJlc3BvbnNlLFxuICBBcGlFeHRyYU1vZGVscyxcbiAgQXBpTm9Db250ZW50UmVzcG9uc2UsXG4gIEFwaU5vdEZvdW5kUmVzcG9uc2UsXG4gIEFwaU9rUmVzcG9uc2UsXG4gIEFwaU9wZXJhdGlvbixcbiAgQXBpUGFyYW0sXG4gIEFwaVF1ZXJ5LFxuICBBcGlUYWdzLFxuICBBcGlVbnByb2Nlc3NhYmxlRW50aXR5UmVzcG9uc2UsXG4gIGdldFNjaGVtYVBhdGgsXG59IGZyb20gXCJAbmVzdGpzL3N3YWdnZXJcIjtcbmltcG9ydCB7XG4gIHR5cGUgRGlyZWN0aW9uTGltaXRPZmZzZXQsXG4gIE1vZGVsU2VydmljZSxcbiAgT3JkZXJEaXJlY3Rpb24sXG4gIFBlcnNpc3RlbmNlS2V5cyxcbiAgUHJlcGFyZWRTdGF0ZW1lbnRLZXlzLFxuICB0eXBlIFJlcG8sXG4gIFJlcG9zaXRvcnksXG4gIFNlcnZpY2UsXG59IGZyb20gXCJAZGVjYWYtdHMvY29yZVwiO1xuaW1wb3J0IHsgTW9kZWwsIE1vZGVsQ29uc3RydWN0b3IgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRvci12YWxpZGF0aW9uXCI7XG5pbXBvcnQgeyBMb2dnaW5nLCB0b0tlYmFiQ2FzZSB9IGZyb20gXCJAZGVjYWYtdHMvbG9nZ2luZ1wiO1xuaW1wb3J0IHtcbiAgQnVsa0NydWRPcGVyYXRpb25LZXlzLFxuICBEQktleXMsXG4gIE9wZXJhdGlvbktleXMsXG4gIFZhbGlkYXRpb25FcnJvcixcbn0gZnJvbSBcIkBkZWNhZi10cy9kYi1kZWNvcmF0b3JzXCI7XG5pbXBvcnQgeyBDb25zdHJ1Y3RvciwgTWV0YWRhdGEgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRpb25cIjtcbmltcG9ydCB7XG4gIEFwaU9wZXJhdGlvbkZyb21Nb2RlbCxcbiAgQXBpUGFyYW1zRnJvbU1vZGVsLFxuICB0eXBlIERlY2FmQXBpUHJvcGVydHksXG4gIERlY2FmQm9keSxcbiAgRGVjYWZQYXJhbXMsXG4gIERlY2FmUXVlcnksXG59IGZyb20gXCIuL2RlY29yYXRvcnNcIjtcbmltcG9ydCB7IEh0dHBWZXJiVG9EZWNvcmF0b3IgfSBmcm9tIFwiLi9kZWNvcmF0b3JzL3V0aWxzXCI7XG5pbXBvcnQgdHlwZSB7IEh0dHBWZXJicyB9IGZyb20gXCIuL2RlY29yYXRvcnMvdHlwZXNcIjtcbmltcG9ydCB7IERlY2FmUmVxdWVzdENvbnRleHQgfSBmcm9tIFwiLi4vcmVxdWVzdFwiO1xuaW1wb3J0IHsgREVDQUZfQ09OVFJPTExFUl9DT05GSUcsIERFQ0FGX1JPVVRFIH0gZnJvbSBcIi4uL2NvbnN0YW50c1wiO1xuaW1wb3J0IHsgU0tJUF9NT0RFTF9ST0xFU19LRVkgfSBmcm9tIFwiLi4vYXV0aC9jb25zdGFudHNcIjtcbmltcG9ydCB7IEF1dGgsIFB1YmxpYywgUmVxdWlyZVJvbGVzIH0gZnJvbSBcIi4uL2F1dGgvZGVjb3JhdG9yc1wiO1xuaW1wb3J0IHsgQ29udHJvbGxlckNvbnN0cnVjdG9yIH0gZnJvbSBcIi4vdHlwZXNcIjtcbmltcG9ydCB7IERlY2FmTW9kZWxDb250cm9sbGVyIH0gZnJvbSBcIi4uL2NvbnRyb2xsZXJzXCI7XG5pbXBvcnQgeyBEdG9Gb3IgfSBmcm9tIFwiLi4vZmFjdG9yeS9vcGVuYXBpL0R0b0J1aWxkZXJcIjtcbmltcG9ydCBcIi4uL292ZXJyaWRlc1wiO1xuaW1wb3J0IHtcbiAgTW9kZWxDb250cm9sbGVyRmFjdG9yeSxcbiAgdHlwZSBNb2RlbENvbnRyb2xsZXJGYWN0b3J5Q29uZmlnLFxuICB0eXBlIEF1dGhDb25maWcsXG4gIHR5cGUgU2VydmVyUm91dGUsXG59IGZyb20gXCJAZGVjYWYtdHMvZm9yLWh0dHAvc2VydmVyXCI7XG5cbmV4cG9ydCBjbGFzcyBGcm9tTW9kZWxDb250cm9sbGVyIHtcbiAgcHJpdmF0ZSBzdGF0aWMgcmVhZG9ubHkgbG9nID0gTG9nZ2luZy5mb3IoRnJvbU1vZGVsQ29udHJvbGxlci5uYW1lKTtcblxuICBzdGF0aWMgZ2V0UGVyc2lzdGVuY2U8VCBleHRlbmRzIE1vZGVsPGJvb2xlYW4+PihcbiAgICBNb2RlbENsYXp6OiBNb2RlbENvbnN0cnVjdG9yPFQ+XG4gICk6IFJlcG88VD4gfCBNb2RlbFNlcnZpY2U8VD4ge1xuICAgIHRyeSB7XG4gICAgICByZXR1cm4gU2VydmljZS5nZXQ8TW9kZWxTZXJ2aWNlPFQ+PihNb2RlbENsYXp6KTtcbiAgICB9IGNhdGNoIChlOiB1bmtub3duKSB7XG4gICAgICB0cnkge1xuICAgICAgICByZXR1cm4gTW9kZWxTZXJ2aWNlLmdldFNlcnZpY2UoTW9kZWxDbGF6eikgYXMgTW9kZWxTZXJ2aWNlPFQ+O1xuICAgICAgfSBjYXRjaCAoZTI6IHVua25vd24pIHtcbiAgICAgICAgcmV0dXJuIFJlcG9zaXRvcnkuZm9yTW9kZWwoTW9kZWxDbGF6eikgYXMgUmVwbzxUPjtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBzdGF0aWMgY3JlYXRlUXVlcnlSb3V0ZXNGcm9tUmVwb3NpdG9yeTxUIGV4dGVuZHMgTW9kZWw8Ym9vbGVhbj4+KFxuICAgIHBlcnNpc3RlbmNlOiBSZXBvPFQ+IHwgTW9kZWxTZXJ2aWNlPFQ+LFxuICAgIHByZWZpeDogc3RyaW5nID0gUGVyc2lzdGVuY2VLZXlzLlFVRVJZXG4gICk6IENvbnRyb2xsZXJDb25zdHJ1Y3RvcjxUPiB7XG4gICAgY29uc3QgcmVwbzogUmVwbzxUPiA9XG4gICAgICBwZXJzaXN0ZW5jZSBpbnN0YW5jZW9mIE1vZGVsU2VydmljZSA/IHBlcnNpc3RlbmNlLnJlcG8gOiBwZXJzaXN0ZW5jZTtcbiAgICBjb25zdCBNb2RlbENvbnN0cjogQ29uc3RydWN0b3IgPSByZXBvLmNsYXNzO1xuICAgIGNvbnN0IHF1ZXJ5TWV0aG9kczogUmVjb3JkPHN0cmluZywgeyBmaWVsZHM/OiBzdHJpbmdbXSB8IHVuZGVmaW5lZCB9PiA9XG4gICAgICBNZXRhZGF0YS5nZXQoXG4gICAgICAgIHJlcG8uY29uc3RydWN0b3IgYXMgQ29uc3RydWN0b3IsXG4gICAgICAgIE1ldGFkYXRhLmtleShQZXJzaXN0ZW5jZUtleXMuUVVFUlkpXG4gICAgICApID8/IHt9O1xuXG4gICAgY29uc3Qgcm91dGVNZXRob2RzOiBSZWNvcmQ8c3RyaW5nLCBhbnk+ID1cbiAgICAgIE1ldGFkYXRhLmdldChcbiAgICAgICAgcGVyc2lzdGVuY2UuY29uc3RydWN0b3IgYXMgQ29uc3RydWN0b3IsXG4gICAgICAgIE1ldGFkYXRhLmtleShERUNBRl9ST1VURSlcbiAgICAgICkgPz8ge307XG5cbiAgICBjbGFzcyBRdWVyeUNvbnRyb2xsZXIgZXh0ZW5kcyBEZWNhZk1vZGVsQ29udHJvbGxlcjxUPiB7XG4gICAgICBvdmVycmlkZSBnZXQgY2xhc3MoKTogTW9kZWxDb25zdHJ1Y3RvcjxUPiB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIk1ldGhvZCBub3QgaW1wbGVtZW50ZWQuXCIpO1xuICAgICAgfVxuICAgICAgY29uc3RydWN0b3IoY2xpZW50Q29udGV4dDogRGVjYWZSZXF1ZXN0Q29udGV4dCwgbmFtZTogc3RyaW5nKSB7XG4gICAgICAgIHN1cGVyKGNsaWVudENvbnRleHQsIG5hbWUpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGZvciAoY29uc3QgW21ldGhvZE5hbWUsIHBhcmFtc10gb2YgT2JqZWN0LmVudHJpZXMocm91dGVNZXRob2RzKSkge1xuICAgICAgY29uc3Qgcm91dGVQYXRoID0gW3BhcmFtcy5wYXRoLnJlcGxhY2UoL15cXC8rfFxcLyskL2csIFwiXCIpXVxuICAgICAgICAuZmlsdGVyKChzZWdtZW50OiBzdHJpbmcpID0+IHNlZ21lbnQgJiYgc2VnbWVudC50cmltKCkpXG4gICAgICAgIC5qb2luKFwiL1wiKTtcblxuICAgICAgY29uc3QgaGFuZGxlciA9IEZyb21Nb2RlbENvbnRyb2xsZXIuY3JlYXRlQ29tcGxleFF1ZXJ5SGFuZGxlcihcbiAgICAgICAgbWV0aG9kTmFtZVxuICAgICAgKSBhcyBhbnk7XG4gICAgICBGcm9tTW9kZWxDb250cm9sbGVyLmRlZmluZU1ldGhvZChcbiAgICAgICAgUXVlcnlDb250cm9sbGVyLFxuICAgICAgICBtZXRob2ROYW1lLFxuICAgICAgICBoYW5kbGVyXG4gICAgICApO1xuXG4gICAgICBjb25zdCBodHRwRGVjb3JhdG9yID0gSHR0cFZlcmJUb0RlY29yYXRvcihwYXJhbXMuaHR0cE1ldGhvZCBhcyBIdHRwVmVyYnMpKHJvdXRlUGF0aCB8fCB1bmRlZmluZWQpO1xuICAgICAgY29uc3QgZGVjb3JhdG9ycyA9IEZyb21Nb2RlbENvbnRyb2xsZXIuZ2V0UXVlcnlEZWNvcmF0b3JzKFxuICAgICAgICBtZXRob2ROYW1lLFxuICAgICAgICByb3V0ZVBhdGgsXG4gICAgICAgIHBhcmFtcy5odHRwTWV0aG9kXG4gICAgICApO1xuICAgICAgRnJvbU1vZGVsQ29udHJvbGxlci5hcHBseURlY29yYXRvcnMoXG4gICAgICAgIFF1ZXJ5Q29udHJvbGxlcixcbiAgICAgICAgbWV0aG9kTmFtZSxcbiAgICAgICAgW2h0dHBEZWNvcmF0b3IsIC4uLmRlY29yYXRvcnNdXG4gICAgICApO1xuICAgIH1cblxuICAgIGZvciAoY29uc3QgW21ldGhvZE5hbWUsIG9ialZhbHVlc10gb2YgT2JqZWN0LmVudHJpZXMocXVlcnlNZXRob2RzKSkge1xuICAgICAgY29uc3QgZmllbGRzID0gb2JqVmFsdWVzLmZpZWxkcyA/PyBbXTtcbiAgICAgIGNvbnN0IHJvdXRlUGF0aCA9IFtwcmVmaXgsIG1ldGhvZE5hbWUsIC4uLmZpZWxkcy5tYXAoKGYpID0+IGA6JHtmfWApXVxuICAgICAgICAuZmlsdGVyKChzZWdtZW50KSA9PiBzZWdtZW50ICYmIHNlZ21lbnQudHJpbSgpKVxuICAgICAgICAuam9pbihcIi9cIik7XG5cbiAgICAgIGNvbnN0IGhhbmRsZXIgPSBGcm9tTW9kZWxDb250cm9sbGVyLmNyZWF0ZUNvbXBsZXhRdWVyeUhhbmRsZXIoXG4gICAgICAgIG1ldGhvZE5hbWVcbiAgICAgICkgYXMgYW55O1xuICAgICAgRnJvbU1vZGVsQ29udHJvbGxlci5kZWZpbmVNZXRob2QoXG4gICAgICAgIFF1ZXJ5Q29udHJvbGxlcixcbiAgICAgICAgbWV0aG9kTmFtZSxcbiAgICAgICAgaGFuZGxlclxuICAgICAgKTtcblxuICAgICAgY29uc3QgaHR0cERlY29yYXRvciA9IEh0dHBWZXJiVG9EZWNvcmF0b3IoXCJHRVRcIiBhcyBIdHRwVmVyYnMpKHJvdXRlUGF0aCB8fCB1bmRlZmluZWQpO1xuICAgICAgY29uc3QgZGVjb3JhdG9ycyA9IEZyb21Nb2RlbENvbnRyb2xsZXIuZ2V0UXVlcnlEZWNvcmF0b3JzKFxuICAgICAgICBtZXRob2ROYW1lLFxuICAgICAgICByb3V0ZVBhdGgsXG4gICAgICAgIFwiR0VUXCIsXG4gICAgICAgIHRydWVcbiAgICAgICk7XG4gICAgICBGcm9tTW9kZWxDb250cm9sbGVyLmFwcGx5RGVjb3JhdG9ycyhcbiAgICAgICAgUXVlcnlDb250cm9sbGVyLFxuICAgICAgICBtZXRob2ROYW1lLFxuICAgICAgICBbaHR0cERlY29yYXRvciwgLi4uZGVjb3JhdG9yc11cbiAgICAgICk7XG4gICAgfVxuXG4gICAgcmV0dXJuIFF1ZXJ5Q29udHJvbGxlcjtcbiAgfVxuXG4gIHN0YXRpYyBjcmVhdGU8VCBleHRlbmRzIE1vZGVsPGFueT4+KFxuICAgIE1vZGVsQ29uc3RyOiBNb2RlbENvbnN0cnVjdG9yPFQ+LFxuICAgIG1vZHVsZUNvbmZpZ092ZXJyaWRlcz86IFJlY29yZDxzdHJpbmcsIE1vZGVsQ29udHJvbGxlckZhY3RvcnlDb25maWc+LFxuICAgIGdsb2JhbERlZmF1bHRzPzogUGFydGlhbDxNb2RlbENvbnRyb2xsZXJGYWN0b3J5Q29uZmlnPlxuICApOiBDb250cm9sbGVyQ29uc3RydWN0b3I8VD4ge1xuICAgIGNvbnN0IGxvZyA9IEZyb21Nb2RlbENvbnRyb2xsZXIubG9nLmZvcihGcm9tTW9kZWxDb250cm9sbGVyLmNyZWF0ZSk7XG4gICAgY29uc3QgdGFibGVOYW1lID0gTW9kZWwudGFibGVOYW1lKE1vZGVsQ29uc3RyKTtcbiAgICBjb25zdCByb3V0ZVBhdGggPSB0b0tlYmFiQ2FzZSh0YWJsZU5hbWUpO1xuICAgIGNvbnN0IG1vZGVsQ2xhenpOYW1lID0gTW9kZWxDb25zdHIubmFtZTtcbiAgICBjb25zdCBwZXJzaXN0ZW5jZSA9IEZyb21Nb2RlbENvbnRyb2xsZXIuZ2V0UGVyc2lzdGVuY2UoTW9kZWxDb25zdHIpO1xuXG4gICAgLy8gV2hlbiBwZXJzaXN0ZW5jZSBpcyBhIE1vZGVsU2VydmljZSwgdGhlIEBxdWVyeS9Acm91dGUgbWV0YWRhdGEgbGl2ZXMgb25cbiAgICAvLyB0aGUgdW5kZXJseWluZyByZXBvc2l0b3J5IGNsYXNzIChjdXN0b20gcmVwbyksIG5vdCBvbiBNb2RlbFNlcnZpY2UgaXRzZWxmLlxuICAgIC8vIFBhc3MgdGhlIHJlcG8gdG8gdGhlIGZhY3Rvcnkgc28gYWRkQ29tcGxleFF1ZXJpZXMoKSBjYW4gZGlzY292ZXIgdGhlbS5cbiAgICBjb25zdCBmYWN0b3J5UGVyc2lzdGVuY2UgPVxuICAgICAgcGVyc2lzdGVuY2UgaW5zdGFuY2VvZiBNb2RlbFNlcnZpY2UgPyBwZXJzaXN0ZW5jZS5yZXBvIDogcGVyc2lzdGVuY2U7XG5cbiAgICBjb25zdCBkZWNvcmF0b3JDb25maWcgPSBNZXRhZGF0YS5nZXQoXG4gICAgICBNb2RlbENvbnN0cixcbiAgICAgIE1ldGFkYXRhLmtleShERUNBRl9DT05UUk9MTEVSX0NPTkZJRylcbiAgICApIGFzIE1vZGVsQ29udHJvbGxlckZhY3RvcnlDb25maWcgfCB1bmRlZmluZWQ7XG4gICAgY29uc3QgbW9kdWxlT3ZlcnJpZGUgPSBtb2R1bGVDb25maWdPdmVycmlkZXM/LltNb2RlbENvbnN0ci5uYW1lXTtcbiAgICBjb25zdCBtZXJnZWRDb25maWc6IE1vZGVsQ29udHJvbGxlckZhY3RvcnlDb25maWcgPSB7XG4gICAgICAuLi4oZ2xvYmFsRGVmYXVsdHMgfHwge30pLFxuICAgICAgLi4uKGRlY29yYXRvckNvbmZpZyB8fCB7fSksXG4gICAgICAuLi4obW9kdWxlT3ZlcnJpZGUgfHwge30pLFxuICAgIH07XG5cbiAgICBjb25zdCBGYWN0b3J5Q29udHJvbGxlciA9IE1vZGVsQ29udHJvbGxlckZhY3RvcnkuY3JlYXRlPFQ+KFxuICAgICAgTW9kZWxDb25zdHIsXG4gICAgICBmYWN0b3J5UGVyc2lzdGVuY2UsXG4gICAgICBtZXJnZWRDb25maWdcbiAgICApO1xuICAgIGNvbnN0IGZhY3RvcnlSb3V0ZXMgPSAoRmFjdG9yeUNvbnRyb2xsZXIgYXMgYW55KS5fX3JvdXRlc19fIGFzXG4gICAgICB8IFNlcnZlclJvdXRlW11cbiAgICAgIHwgdW5kZWZpbmVkO1xuXG4gICAgY29uc3QgeyBnZXRQSywgYXBpUHJvcGVydGllcywgcGF0aDogcGtQYXRoIH0gPVxuICAgICAgRnJvbU1vZGVsQ29udHJvbGxlci5nZXRSb3V0ZVBhcmFtZXRlcnNGcm9tTW9kZWwoTW9kZWxDb25zdHIpO1xuXG4gICAgbG9nLmRlYnVnKFxuICAgICAgYENyZWF0aW5nIGNvbnRyb2xsZXIgZm9yIG1vZGVsOiAke21vZGVsQ2xhenpOYW1lfSB3aXRoICR7ZmFjdG9yeVJvdXRlcz8ubGVuZ3RoID8/IDB9IGZhY3Rvcnkgcm91dGVzYFxuICAgICk7XG5cbiAgICBjb25zdCBhdXRoQ29uZmlnOiBBdXRoQ29uZmlnIHwgdW5kZWZpbmVkID0gbWVyZ2VkQ29uZmlnLmF1dGg7XG5cbiAgICBmdW5jdGlvbiBhcHBseUNsYXNzQXV0aCh0YXJnZXQ6IGFueSkge1xuICAgICAgaWYgKGF1dGhDb25maWc/LnB1YmxpYykge1xuICAgICAgICBQdWJsaWMoKSh0YXJnZXQpO1xuICAgICAgfSBlbHNlIGlmIChhdXRoQ29uZmlnPy5yb2xlcz8ubGVuZ3RoKSB7XG4gICAgICAgIFJlcXVpcmVSb2xlcyguLi5hdXRoQ29uZmlnLnJvbGVzKSh0YXJnZXQpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgQXV0aChNb2RlbENvbnN0cikodGFyZ2V0KTtcbiAgICAgIH1cbiAgICAgIGlmIChhdXRoQ29uZmlnPy5za2lwTW9kZWxSb2xlcykge1xuICAgICAgICBTZXRNZXRhZGF0YShTS0lQX01PREVMX1JPTEVTX0tFWSwgdHJ1ZSkodGFyZ2V0KTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBAQ29udHJvbGxlcihyb3V0ZVBhdGgpXG4gICAgQEFwaVRhZ3MobW9kZWxDbGF6ek5hbWUpXG4gICAgQEFwaUV4dHJhTW9kZWxzKE1vZGVsQ29uc3RyKVxuICAgIGNsYXNzIER5bmFtaWNNb2RlbENvbnRyb2xsZXIgZXh0ZW5kcyBEZWNhZk1vZGVsQ29udHJvbGxlcjxUPiB7XG4gICAgICBwcml2YXRlIHJlYWRvbmx5IHBrOiBzdHJpbmcgPSBNb2RlbC5wayhNb2RlbENvbnN0cikgYXMgc3RyaW5nO1xuXG4gICAgICBwcm90ZWN0ZWQgc3RhdGljIGdldCBjbGFzcygpIHtcbiAgICAgICAgcmV0dXJuIE1vZGVsQ29uc3RyO1xuICAgICAgfVxuXG4gICAgICBvdmVycmlkZSBnZXQgY2xhc3MoKTogTW9kZWxDb25zdHJ1Y3RvcjxUPiB7XG4gICAgICAgIHJldHVybiBNb2RlbENvbnN0cjtcbiAgICAgIH1cblxuICAgICAgY29uc3RydWN0b3IoY2xpZW50Q29udGV4dDogRGVjYWZSZXF1ZXN0Q29udGV4dCkge1xuICAgICAgICBzdXBlcihjbGllbnRDb250ZXh0LCBEeW5hbWljTW9kZWxDb250cm9sbGVyLm5hbWUpO1xuICAgICAgICBsb2cuaW5mbyhcbiAgICAgICAgICBgUmVnaXN0ZXJpbmcgZHluYW1pYyBjb250cm9sbGVyIGZvciBtb2RlbDogJHt0aGlzLmNsYXNzLm5hbWV9IHJvdXRlOiAvJHtyb3V0ZVBhdGh9YFxuICAgICAgICApO1xuICAgICAgfVxuICAgIH1cblxuICAgIGFwcGx5Q2xhc3NBdXRoKER5bmFtaWNNb2RlbENvbnRyb2xsZXIpO1xuXG4gICAgaWYgKGZhY3RvcnlSb3V0ZXMpIHtcbiAgICAgIGNvbnN0IHNvcnRlZFJvdXRlcyA9IFsuLi5mYWN0b3J5Um91dGVzXS5zb3J0KChhLCBiKSA9PiB7XG4gICAgICAgIGNvbnN0IGFTZWdtZW50cyA9IGEucGF0aC5zcGxpdChcIi9cIikuZmlsdGVyKEJvb2xlYW4pO1xuICAgICAgICBjb25zdCBiU2VnbWVudHMgPSBiLnBhdGguc3BsaXQoXCIvXCIpLmZpbHRlcihCb29sZWFuKTtcbiAgICAgICAgY29uc3QgYVBhcmFtQ291bnQgPSBhU2VnbWVudHMuZmlsdGVyKChzKSA9PiBzLnN0YXJ0c1dpdGgoXCI6XCIpKS5sZW5ndGg7XG4gICAgICAgIGNvbnN0IGJQYXJhbUNvdW50ID0gYlNlZ21lbnRzLmZpbHRlcigocykgPT4gcy5zdGFydHNXaXRoKFwiOlwiKSkubGVuZ3RoO1xuICAgICAgICBjb25zdCBhTGl0ZXJhbENvdW50ID0gYVNlZ21lbnRzLmxlbmd0aCAtIGFQYXJhbUNvdW50O1xuICAgICAgICBjb25zdCBiTGl0ZXJhbENvdW50ID0gYlNlZ21lbnRzLmxlbmd0aCAtIGJQYXJhbUNvdW50O1xuICAgICAgICBpZiAoYUxpdGVyYWxDb3VudCAhPT0gYkxpdGVyYWxDb3VudClcbiAgICAgICAgICByZXR1cm4gYkxpdGVyYWxDb3VudCAtIGFMaXRlcmFsQ291bnQ7XG4gICAgICAgIGlmIChhUGFyYW1Db3VudCAhPT0gYlBhcmFtQ291bnQpXG4gICAgICAgICAgcmV0dXJuIGFQYXJhbUNvdW50IC0gYlBhcmFtQ291bnQ7XG4gICAgICAgIHJldHVybiAwO1xuICAgICAgfSk7XG4gICAgICBmb3IgKGNvbnN0IHJvdXRlIG9mIHNvcnRlZFJvdXRlcykge1xuICAgICAgICBjb25zdCByZWdpc3RyYXRpb24gPSBGcm9tTW9kZWxDb250cm9sbGVyLm1hdGNoUm91dGUoXG4gICAgICAgICAgcm91dGUsXG4gICAgICAgICAgcGtQYXRoLFxuICAgICAgICAgIGFwaVByb3BlcnRpZXMsXG4gICAgICAgICAgZ2V0UEssXG4gICAgICAgICAgTW9kZWxDb25zdHIsXG4gICAgICAgICAgbW9kZWxDbGF6ek5hbWUsXG4gICAgICAgICAgZmFjdG9yeVBlcnNpc3RlbmNlXG4gICAgICAgICk7XG4gICAgICAgIGlmICghcmVnaXN0cmF0aW9uKSBjb250aW51ZTtcblxuICAgICAgICBjb25zdCB7IG1ldGhvZE5hbWUsIGhhbmRsZXIsIGRlY29yYXRvcnMsIHBhcmFtRGVjb3JhdG9ycyB9ID1cbiAgICAgICAgICByZWdpc3RyYXRpb247XG5cbiAgICAgICAgY29uc3QgZGVzY3JpcHRvciA9IEZyb21Nb2RlbENvbnRyb2xsZXIuZGVmaW5lTWV0aG9kKFxuICAgICAgICAgIER5bmFtaWNNb2RlbENvbnRyb2xsZXIsXG4gICAgICAgICAgbWV0aG9kTmFtZSxcbiAgICAgICAgICBoYW5kbGVyXG4gICAgICAgICk7XG5cbiAgICAgICAgaWYgKGRlc2NyaXB0b3IpIHtcbiAgICAgICAgICBjb25zdCBodHRwRGVjb3JhdG9yID0gSHR0cFZlcmJUb0RlY29yYXRvcihyb3V0ZS5tZXRob2QgYXMgSHR0cFZlcmJzKShcbiAgICAgICAgICAgIHJvdXRlLnBhdGgucmVwbGFjZSgvXlxcLyt8XFwvKyQvZywgXCJcIikgfHwgdW5kZWZpbmVkXG4gICAgICAgICAgKTtcbiAgICAgICAgICBGcm9tTW9kZWxDb250cm9sbGVyLmFwcGx5RGVjb3JhdG9ycyhcbiAgICAgICAgICAgIER5bmFtaWNNb2RlbENvbnRyb2xsZXIsXG4gICAgICAgICAgICBtZXRob2ROYW1lLFxuICAgICAgICAgICAgW2h0dHBEZWNvcmF0b3IsIC4uLmRlY29yYXRvcnNdLFxuICAgICAgICAgICAgcGFyYW1EZWNvcmF0b3JzXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBEeW5hbWljTW9kZWxDb250cm9sbGVyIGFzIGFueTtcbiAgfVxuXG4gIHN0YXRpYyBnZXRSb3V0ZVBhcmFtZXRlcnNGcm9tTW9kZWw8VCBleHRlbmRzIE1vZGVsPGFueT4+KFxuICAgIE1vZGVsQ2xheno6IE1vZGVsQ29uc3RydWN0b3I8VD5cbiAgKToge1xuICAgIHBhdGg6IHN0cmluZztcbiAgICBkZXNjcmlwdGlvbjogc3RyaW5nO1xuICAgIGFwaVByb3BlcnRpZXM6IERlY2FmQXBpUHJvcGVydHlbXTtcbiAgICBnZXRQSzogKC4uLnBhcmFtczogQXJyYXk8c3RyaW5nIHwgbnVtYmVyPikgPT4gc3RyaW5nO1xuICB9IHtcbiAgICBjb25zdCBwayA9IE1vZGVsLnBrKE1vZGVsQ2xhenopIGFzIGtleW9mIE1vZGVsPGFueT47XG4gICAgY29uc3QgY29tcG9zZWQgPSBNZXRhZGF0YS5nZXQoXG4gICAgICBNb2RlbENsYXp6LFxuICAgICAgTWV0YWRhdGEua2V5KERCS2V5cy5DT01QT1NFRCwgcGspXG4gICAgKTtcbiAgICBjb25zdCBjb21wb3NlZEtleXMgPSBjb21wb3NlZD8uYXJncyA/PyBbXTtcblxuICAgIGNvbnN0IHVuaXF1ZUtleXMgPVxuICAgICAgQXJyYXkuaXNBcnJheShjb21wb3NlZEtleXMpICYmIGNvbXBvc2VkS2V5cy5sZW5ndGggPiAwXG4gICAgICAgID8gQXJyYXkuZnJvbShuZXcgU2V0KFsuLi5jb21wb3NlZEtleXNdKSlcbiAgICAgICAgOiBBcnJheS5mcm9tKG5ldyBTZXQoW3BrXSkpO1xuXG4gICAgY29uc3QgZGVzY3JpcHRpb24gPSBNZXRhZGF0YS5kZXNjcmlwdGlvbihNb2RlbENsYXp6KSA/PyBcIlwiO1xuICAgIGNvbnN0IHBhdGggPSBgOiR7dW5pcXVlS2V5cy5qb2luKFwiLzpcIil9YDtcbiAgICBjb25zdCBhcGlQcm9wZXJ0aWVzOiBEZWNhZkFwaVByb3BlcnR5W10gPSB1bmlxdWVLZXlzLm1hcCgoa2V5KSA9PiB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBuYW1lOiBrZXksXG4gICAgICAgIGRlc2NyaXB0aW9uOiBNZXRhZGF0YS5kZXNjcmlwdGlvbihNb2RlbENsYXp6LCBrZXkpLFxuICAgICAgICByZXF1aXJlZDogdHJ1ZSxcbiAgICAgICAgdHlwZTogU3RyaW5nLFxuICAgICAgfTtcbiAgICB9KTtcblxuICAgIHJldHVybiB7XG4gICAgICBwYXRoLFxuICAgICAgZGVzY3JpcHRpb24sXG4gICAgICBhcGlQcm9wZXJ0aWVzLFxuICAgICAgZ2V0UEs6ICguLi5wYXJhbXM6IEFycmF5PHN0cmluZyB8IG51bWJlcj4pID0+XG4gICAgICAgIGNvbXBvc2VkPy5zZXBhcmF0b3IgPyBwYXJhbXMuam9pbihjb21wb3NlZC5zZXBhcmF0b3IpIDogcGFyYW1zLmpvaW4oXCJcIiksXG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgc3RhdGljIGRlZmluZU1ldGhvZChcbiAgICB0YXJnZXQ6IGFueSxcbiAgICBtZXRob2ROYW1lOiBzdHJpbmcsXG4gICAgaGFuZGxlcjogKC4uLmFyZ3M6IGFueVtdKSA9PiBhbnlcbiAgKTogUHJvcGVydHlEZXNjcmlwdG9yIHwgdW5kZWZpbmVkIHtcbiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkoXG4gICAgICB0YXJnZXQucHJvdG90eXBlIHx8IHRhcmdldCxcbiAgICAgIG1ldGhvZE5hbWUsXG4gICAgICB7XG4gICAgICAgIHZhbHVlOiBoYW5kbGVyLFxuICAgICAgICB3cml0YWJsZTogZmFsc2UsXG4gICAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZSxcbiAgICAgICAgZW51bWVyYWJsZTogZmFsc2UsXG4gICAgICB9XG4gICAgKTtcblxuICAgIHJldHVybiBPYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKFxuICAgICAgdGFyZ2V0LnByb3RvdHlwZSB8fCB0YXJnZXQsXG4gICAgICBtZXRob2ROYW1lXG4gICAgKTtcbiAgfVxuXG4gIHByaXZhdGUgc3RhdGljIGFwcGx5RGVjb3JhdG9ycyhcbiAgICB0YXJnZXQ6IGFueSxcbiAgICBtZXRob2ROYW1lOiBzdHJpbmcsXG4gICAgbWV0aG9kRGVjb3JhdG9yczogQXJyYXk8KHRhcmdldDogYW55LCBrZXk6IHN0cmluZywgZGVzYzogYW55KSA9PiB2b2lkPixcbiAgICBwYXJhbURlY29yYXRvcnM6IEFycmF5PHsgZGVjb3JhdG9yOiBQYXJhbWV0ZXJEZWNvcmF0b3I7IGluZGV4OiBudW1iZXIgfT4gPSBbXVxuICApIHtcbiAgICBjb25zdCBwcm90byA9IHRhcmdldD8ucHJvdG90eXBlID8/IHRhcmdldDtcbiAgICBjb25zdCBkZXNjcmlwdG9yID0gT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcihwcm90bywgbWV0aG9kTmFtZSk7XG4gICAgbWV0aG9kRGVjb3JhdG9ycy5mb3JFYWNoKChkKSA9PiBkKHByb3RvLCBtZXRob2ROYW1lLCBkZXNjcmlwdG9yKSk7XG4gICAgcGFyYW1EZWNvcmF0b3JzLmZvckVhY2goKHsgZGVjb3JhdG9yLCBpbmRleCB9KSA9PlxuICAgICAgZGVjb3JhdG9yKHByb3RvLCBtZXRob2ROYW1lLCBpbmRleClcbiAgICApO1xuICB9XG5cbiAgcHJpdmF0ZSBzdGF0aWMgbWF0Y2hSb3V0ZShcbiAgICByb3V0ZTogU2VydmVyUm91dGUsXG4gICAgcGtQYXRoOiBzdHJpbmcsXG4gICAgYXBpUHJvcGVydGllczogRGVjYWZBcGlQcm9wZXJ0eVtdLFxuICAgIGdldFBLOiAoLi4ucDogQXJyYXk8c3RyaW5nIHwgbnVtYmVyPikgPT4gc3RyaW5nLFxuICAgIE1vZGVsQ29uc3RyOiBNb2RlbENvbnN0cnVjdG9yPGFueT4sXG4gICAgbW9kZWxDbGF6ek5hbWU6IHN0cmluZyxcbiAgICBwZXJzaXN0ZW5jZT86IGFueVxuICApOiB7XG4gICAgbWV0aG9kTmFtZTogc3RyaW5nO1xuICAgIGhhbmRsZXI6ICguLi5hcmdzOiBhbnlbXSkgPT4gYW55O1xuICAgIGRlY29yYXRvcnM6IEFycmF5PCh0YXJnZXQ6IGFueSwga2V5OiBzdHJpbmcsIGRlc2M6IGFueSkgPT4gdm9pZD47XG4gICAgcGFyYW1EZWNvcmF0b3JzOiBBcnJheTx7IGRlY29yYXRvcjogUGFyYW1ldGVyRGVjb3JhdG9yOyBpbmRleDogbnVtYmVyIH0+O1xuICB9IHwgdW5kZWZpbmVkIHtcbiAgICBjb25zdCB7IG1ldGhvZCwgcGF0aCB9ID0gcm91dGU7XG4gICAgY29uc3Qgbm9ybWFsaXplZFBhdGggPSBwYXRoLnJlcGxhY2UoL15cXC8rfFxcLyskL2csIFwiXCIpO1xuXG4gICAgaWYgKG1ldGhvZCA9PT0gXCJQT1NUXCIgJiYgbm9ybWFsaXplZFBhdGggPT09IFwiXCIpIHtcbiAgICAgIHJldHVybiBGcm9tTW9kZWxDb250cm9sbGVyLmNyZWF0ZVJlZ2lzdHJhdGlvbihcbiAgICAgICAgXCJjcmVhdGVcIixcbiAgICAgICAgRnJvbU1vZGVsQ29udHJvbGxlci5jcmVhdGVDcmVhdGVIYW5kbGVyKE1vZGVsQ29uc3RyLCBtb2RlbENsYXp6TmFtZSksXG4gICAgICAgIEZyb21Nb2RlbENvbnRyb2xsZXIuY3JlYXRlQ3JlYXRlRGVjb3JhdG9ycyhNb2RlbENvbnN0ciwgbW9kZWxDbGF6ek5hbWUpLFxuICAgICAgICBbeyBkZWNvcmF0b3I6IERlY2FmQm9keSgpIGFzIGFueSwgaW5kZXg6IDAgfSwgeyBkZWNvcmF0b3I6IFJlc3BvbnNlKHsgcGFzc3Rocm91Z2g6IHRydWUgfSkgYXMgYW55LCBpbmRleDogMSB9XVxuICAgICAgKTtcbiAgICB9XG5cbiAgICBpZiAobWV0aG9kID09PSBcIlBPU1RcIiAmJiBub3JtYWxpemVkUGF0aCA9PT0gXCJidWxrXCIpIHtcbiAgICAgIHJldHVybiBGcm9tTW9kZWxDb250cm9sbGVyLmNyZWF0ZVJlZ2lzdHJhdGlvbihcbiAgICAgICAgXCJjcmVhdGVBbGxcIixcbiAgICAgICAgRnJvbU1vZGVsQ29udHJvbGxlci5jcmVhdGVCdWxrQ3JlYXRlSGFuZGxlcihNb2RlbENvbnN0ciwgbW9kZWxDbGF6ek5hbWUpLFxuICAgICAgICBGcm9tTW9kZWxDb250cm9sbGVyLmJ1bGtDcmVhdGVEZWNvcmF0b3JzKE1vZGVsQ29uc3RyLCBtb2RlbENsYXp6TmFtZSksXG4gICAgICAgIFt7IGRlY29yYXRvcjogRGVjYWZCb2R5KCkgYXMgYW55LCBpbmRleDogMCB9LCB7IGRlY29yYXRvcjogUmVzcG9uc2UoeyBwYXNzdGhyb3VnaDogdHJ1ZSB9KSBhcyBhbnksIGluZGV4OiAxIH1dXG4gICAgICApO1xuICAgIH1cblxuICAgIGlmIChtZXRob2QgPT09IFwiR0VUXCIgJiYgbm9ybWFsaXplZFBhdGggPT09IFwiYnVsa1wiKSB7XG4gICAgICByZXR1cm4gRnJvbU1vZGVsQ29udHJvbGxlci5jcmVhdGVSZWdpc3RyYXRpb24oXG4gICAgICAgIFwicmVhZEFsbFwiLFxuICAgICAgICBGcm9tTW9kZWxDb250cm9sbGVyLmNyZWF0ZUJ1bGtSZWFkSGFuZGxlcihtb2RlbENsYXp6TmFtZSksXG4gICAgICAgIEZyb21Nb2RlbENvbnRyb2xsZXIuYnVsa1JlYWREZWNvcmF0b3JzKE1vZGVsQ29uc3RyLCBtb2RlbENsYXp6TmFtZSksXG4gICAgICAgIFt7IGRlY29yYXRvcjogUXVlcnkoXCJpZHNcIikgYXMgYW55LCBpbmRleDogMCB9XVxuICAgICAgKTtcbiAgICB9XG5cbiAgICBpZiAobWV0aG9kID09PSBcIlBVVFwiICYmIG5vcm1hbGl6ZWRQYXRoID09PSBcImJ1bGtcIikge1xuICAgICAgcmV0dXJuIEZyb21Nb2RlbENvbnRyb2xsZXIuY3JlYXRlUmVnaXN0cmF0aW9uKFxuICAgICAgICBcInVwZGF0ZUFsbFwiLFxuICAgICAgICBGcm9tTW9kZWxDb250cm9sbGVyLmNyZWF0ZUJ1bGtVcGRhdGVIYW5kbGVyKG1vZGVsQ2xhenpOYW1lKSxcbiAgICAgICAgRnJvbU1vZGVsQ29udHJvbGxlci5idWxrVXBkYXRlRGVjb3JhdG9ycyhNb2RlbENvbnN0ciwgbW9kZWxDbGF6ek5hbWUsIGFwaVByb3BlcnRpZXMpLFxuICAgICAgICBbeyBkZWNvcmF0b3I6IERlY2FmQm9keSgpIGFzIGFueSwgaW5kZXg6IDAgfSwgeyBkZWNvcmF0b3I6IFJlc3BvbnNlKHsgcGFzc3Rocm91Z2g6IHRydWUgfSkgYXMgYW55LCBpbmRleDogMSB9XVxuICAgICAgKTtcbiAgICB9XG5cbiAgICBpZiAobWV0aG9kID09PSBcIkRFTEVURVwiICYmIG5vcm1hbGl6ZWRQYXRoID09PSBcImJ1bGtcIikge1xuICAgICAgcmV0dXJuIEZyb21Nb2RlbENvbnRyb2xsZXIuY3JlYXRlUmVnaXN0cmF0aW9uKFxuICAgICAgICBcImRlbGV0ZUFsbFwiLFxuICAgICAgICBGcm9tTW9kZWxDb250cm9sbGVyLmNyZWF0ZUJ1bGtEZWxldGVIYW5kbGVyKG1vZGVsQ2xhenpOYW1lKSxcbiAgICAgICAgRnJvbU1vZGVsQ29udHJvbGxlci5idWxrRGVsZXRlRGVjb3JhdG9ycyhNb2RlbENvbnN0ciwgbW9kZWxDbGF6ek5hbWUsIGFwaVByb3BlcnRpZXMpLFxuICAgICAgICBbeyBkZWNvcmF0b3I6IFF1ZXJ5KFwiaWRzXCIpIGFzIGFueSwgaW5kZXg6IDAgfSwgeyBkZWNvcmF0b3I6IFJlc3BvbnNlKHsgcGFzc3Rocm91Z2g6IHRydWUgfSkgYXMgYW55LCBpbmRleDogMSB9XVxuICAgICAgKTtcbiAgICB9XG5cbiAgICBpZiAobWV0aG9kID09PSBcIkdFVFwiICYmIG5vcm1hbGl6ZWRQYXRoID09PSBwa1BhdGgpIHtcbiAgICAgIHJldHVybiBGcm9tTW9kZWxDb250cm9sbGVyLmNyZWF0ZVJlZ2lzdHJhdGlvbihcbiAgICAgICAgXCJyZWFkXCIsXG4gICAgICAgIEZyb21Nb2RlbENvbnRyb2xsZXIuY3JlYXRlUmVhZEhhbmRsZXIoZ2V0UEssIG1vZGVsQ2xhenpOYW1lKSxcbiAgICAgICAgRnJvbU1vZGVsQ29udHJvbGxlci5yZWFkRGVjb3JhdG9ycyhNb2RlbENvbnN0ciwgbW9kZWxDbGF6ek5hbWUsIGFwaVByb3BlcnRpZXMsIHBrUGF0aCksXG4gICAgICAgIFt7IGRlY29yYXRvcjogRGVjYWZQYXJhbXMoYXBpUHJvcGVydGllcykgYXMgYW55LCBpbmRleDogMCB9XVxuICAgICAgKTtcbiAgICB9XG5cbiAgICBpZiAobWV0aG9kID09PSBcIlBVVFwiICYmIG5vcm1hbGl6ZWRQYXRoID09PSBwa1BhdGgpIHtcbiAgICAgIHJldHVybiBGcm9tTW9kZWxDb250cm9sbGVyLmNyZWF0ZVJlZ2lzdHJhdGlvbihcbiAgICAgICAgXCJ1cGRhdGVcIixcbiAgICAgICAgRnJvbU1vZGVsQ29udHJvbGxlci5jcmVhdGVVcGRhdGVIYW5kbGVyKGdldFBLLCBNb2RlbENvbnN0ciwgbW9kZWxDbGF6ek5hbWUpLFxuICAgICAgICBGcm9tTW9kZWxDb250cm9sbGVyLnVwZGF0ZURlY29yYXRvcnMoTW9kZWxDb25zdHIsIG1vZGVsQ2xhenpOYW1lLCBhcGlQcm9wZXJ0aWVzLCBwa1BhdGgpLFxuICAgICAgICBbXG4gICAgICAgICAgeyBkZWNvcmF0b3I6IERlY2FmUGFyYW1zKGFwaVByb3BlcnRpZXMpIGFzIGFueSwgaW5kZXg6IDAgfSxcbiAgICAgICAgICB7IGRlY29yYXRvcjogRGVjYWZCb2R5KCkgYXMgYW55LCBpbmRleDogMSB9LFxuICAgICAgICAgIHsgZGVjb3JhdG9yOiBSZXNwb25zZSh7IHBhc3N0aHJvdWdoOiB0cnVlIH0pIGFzIGFueSwgaW5kZXg6IDIgfSxcbiAgICAgICAgXVxuICAgICAgKTtcbiAgICB9XG5cbiAgICBpZiAobWV0aG9kID09PSBcIkRFTEVURVwiICYmIG5vcm1hbGl6ZWRQYXRoID09PSBwa1BhdGgpIHtcbiAgICAgIHJldHVybiBGcm9tTW9kZWxDb250cm9sbGVyLmNyZWF0ZVJlZ2lzdHJhdGlvbihcbiAgICAgICAgXCJkZWxldGVcIixcbiAgICAgICAgRnJvbU1vZGVsQ29udHJvbGxlci5jcmVhdGVEZWxldGVIYW5kbGVyKGdldFBLLCBtb2RlbENsYXp6TmFtZSksXG4gICAgICAgIEZyb21Nb2RlbENvbnRyb2xsZXIuZGVsZXRlRGVjb3JhdG9ycyhNb2RlbENvbnN0ciwgbW9kZWxDbGF6ek5hbWUsIGFwaVByb3BlcnRpZXMsIHBrUGF0aCksXG4gICAgICAgIFtcbiAgICAgICAgICB7IGRlY29yYXRvcjogRGVjYWZQYXJhbXMoYXBpUHJvcGVydGllcykgYXMgYW55LCBpbmRleDogMCB9LFxuICAgICAgICAgIHsgZGVjb3JhdG9yOiBSZXNwb25zZSh7IHBhc3N0aHJvdWdoOiB0cnVlIH0pIGFzIGFueSwgaW5kZXg6IDEgfSxcbiAgICAgICAgXVxuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyBDb21wb3NlZCBQSyBmYWxsYmFjayByb3V0ZXMgKGZpbHRlckVtcHR5KSDigJQgcGF0aCBkaWZmZXJzIGZyb20gcGtQYXRoXG4gICAgY29uc3QgZmFsbGJhY2tTZWdtZW50cyA9IG5vcm1hbGl6ZWRQYXRoLnNwbGl0KFwiL1wiKS5maWx0ZXIoQm9vbGVhbik7XG4gICAgY29uc3QgaXNBbGxQYXJhbXMgPSBmYWxsYmFja1NlZ21lbnRzLmxlbmd0aCA+IDAgJiYgZmFsbGJhY2tTZWdtZW50cy5ldmVyeSgocykgPT4gcy5zdGFydHNXaXRoKFwiOlwiKSk7XG4gICAgaWYgKGlzQWxsUGFyYW1zICYmIG5vcm1hbGl6ZWRQYXRoICE9PSBwa1BhdGgpIHtcbiAgICAgIGNvbnN0IGZhbGxiYWNrQXBpUHJvcHMgPSBmYWxsYmFja1NlZ21lbnRzLm1hcCgocykgPT4gcy5zbGljZSgxKSkubWFwKChuYW1lKSA9PiAoe1xuICAgICAgICBuYW1lLFxuICAgICAgICBkZXNjcmlwdGlvbjogYCR7bmFtZX0gcGFyYW1ldGVyYCxcbiAgICAgICAgcmVxdWlyZWQ6IHRydWUsXG4gICAgICAgIHR5cGU6IFN0cmluZyxcbiAgICAgIH0pKTtcbiAgICAgIGNvbnN0IHN1ZmZpeCA9IGZhbGxiYWNrU2VnbWVudHMubWFwKChzKSA9PiBzLnNsaWNlKDEpKS5qb2luKFwiQW5kXCIpO1xuICAgICAgaWYgKG1ldGhvZCA9PT0gXCJHRVRcIikge1xuICAgICAgICByZXR1cm4gRnJvbU1vZGVsQ29udHJvbGxlci5jcmVhdGVSZWdpc3RyYXRpb24oXG4gICAgICAgICAgYHJlYWRCeSR7c3VmZml4fWAsXG4gICAgICAgICAgRnJvbU1vZGVsQ29udHJvbGxlci5jcmVhdGVSZWFkSGFuZGxlcihnZXRQSywgbW9kZWxDbGF6ek5hbWUpLFxuICAgICAgICAgIEZyb21Nb2RlbENvbnRyb2xsZXIucmVhZERlY29yYXRvcnMoTW9kZWxDb25zdHIsIG1vZGVsQ2xhenpOYW1lLCBmYWxsYmFja0FwaVByb3BzLCBub3JtYWxpemVkUGF0aCksXG4gICAgICAgICAgW3sgZGVjb3JhdG9yOiBEZWNhZlBhcmFtcyhmYWxsYmFja0FwaVByb3BzKSBhcyBhbnksIGluZGV4OiAwIH1dXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgICBpZiAobWV0aG9kID09PSBcIlBVVFwiKSB7XG4gICAgICAgIHJldHVybiBGcm9tTW9kZWxDb250cm9sbGVyLmNyZWF0ZVJlZ2lzdHJhdGlvbihcbiAgICAgICAgICBgdXBkYXRlQnkke3N1ZmZpeH1gLFxuICAgICAgICAgIEZyb21Nb2RlbENvbnRyb2xsZXIuY3JlYXRlVXBkYXRlSGFuZGxlcihnZXRQSywgTW9kZWxDb25zdHIsIG1vZGVsQ2xhenpOYW1lKSxcbiAgICAgICAgICBGcm9tTW9kZWxDb250cm9sbGVyLnVwZGF0ZURlY29yYXRvcnMoTW9kZWxDb25zdHIsIG1vZGVsQ2xhenpOYW1lLCBmYWxsYmFja0FwaVByb3BzLCBub3JtYWxpemVkUGF0aCksXG4gICAgICAgICAgW1xuICAgICAgICAgICAgeyBkZWNvcmF0b3I6IERlY2FmUGFyYW1zKGZhbGxiYWNrQXBpUHJvcHMpIGFzIGFueSwgaW5kZXg6IDAgfSxcbiAgICAgICAgICAgIHsgZGVjb3JhdG9yOiBEZWNhZkJvZHkoKSBhcyBhbnksIGluZGV4OiAxIH0sXG4gICAgICAgICAgICB7IGRlY29yYXRvcjogUmVzcG9uc2UoeyBwYXNzdGhyb3VnaDogdHJ1ZSB9KSBhcyBhbnksIGluZGV4OiAyIH0sXG4gICAgICAgICAgXVxuICAgICAgICApO1xuICAgICAgfVxuICAgICAgaWYgKG1ldGhvZCA9PT0gXCJERUxFVEVcIikge1xuICAgICAgICByZXR1cm4gRnJvbU1vZGVsQ29udHJvbGxlci5jcmVhdGVSZWdpc3RyYXRpb24oXG4gICAgICAgICAgYGRlbGV0ZUJ5JHtzdWZmaXh9YCxcbiAgICAgICAgICBGcm9tTW9kZWxDb250cm9sbGVyLmNyZWF0ZURlbGV0ZUhhbmRsZXIoZ2V0UEssIG1vZGVsQ2xhenpOYW1lKSxcbiAgICAgICAgICBGcm9tTW9kZWxDb250cm9sbGVyLmRlbGV0ZURlY29yYXRvcnMoTW9kZWxDb25zdHIsIG1vZGVsQ2xhenpOYW1lLCBmYWxsYmFja0FwaVByb3BzLCBub3JtYWxpemVkUGF0aCksXG4gICAgICAgICAgW1xuICAgICAgICAgICAgeyBkZWNvcmF0b3I6IERlY2FmUGFyYW1zKGZhbGxiYWNrQXBpUHJvcHMpIGFzIGFueSwgaW5kZXg6IDAgfSxcbiAgICAgICAgICAgIHsgZGVjb3JhdG9yOiBSZXNwb25zZSh7IHBhc3N0aHJvdWdoOiB0cnVlIH0pIGFzIGFueSwgaW5kZXg6IDEgfSxcbiAgICAgICAgICBdXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKG1ldGhvZCA9PT0gXCJHRVRcIiAmJiBub3JtYWxpemVkUGF0aCA9PT0gXCJzdGF0ZW1lbnQvOm1ldGhvZC8qYXJnc1wiKSB7XG4gICAgICByZXR1cm4gRnJvbU1vZGVsQ29udHJvbGxlci5jcmVhdGVSZWdpc3RyYXRpb24oXG4gICAgICAgIFwic3RhdGVtZW50XCIsXG4gICAgICAgIEZyb21Nb2RlbENvbnRyb2xsZXIuY3JlYXRlU3RhdGVtZW50SGFuZGxlcihtb2RlbENsYXp6TmFtZSksXG4gICAgICAgIEZyb21Nb2RlbENvbnRyb2xsZXIuc3RhdGVtZW50RGVjb3JhdG9ycyhNb2RlbENvbnN0ciwgbW9kZWxDbGF6ek5hbWUpLFxuICAgICAgICBbXG4gICAgICAgICAgeyBkZWNvcmF0b3I6IFBhcmFtKFwibWV0aG9kXCIpIGFzIGFueSwgaW5kZXg6IDAgfSxcbiAgICAgICAgICB7IGRlY29yYXRvcjogUGFyYW0oXCJhcmdzXCIpIGFzIGFueSwgaW5kZXg6IDEgfSxcbiAgICAgICAgICB7IGRlY29yYXRvcjogRGVjYWZRdWVyeSgpIGFzIGFueSwgaW5kZXg6IDIgfSxcbiAgICAgICAgXVxuICAgICAgKTtcbiAgICB9XG5cbiAgICBjb25zdCBzdGF0ZW1lbnRSb3V0ZXM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7XG4gICAgICBcImxpc3RCeS86a2V5XCI6IFByZXBhcmVkU3RhdGVtZW50S2V5cy5MSVNUX0JZLFxuICAgICAgXCJwYWdpbmF0ZUJ5LzprZXkvOnBhZ2VcIjogUHJlcGFyZWRTdGF0ZW1lbnRLZXlzLlBBR0VfQlksXG4gICAgICBcImZpbmQvOnZhbHVlXCI6IFByZXBhcmVkU3RhdGVtZW50S2V5cy5GSU5ELFxuICAgICAgXCJwYWdlLzp2YWx1ZVwiOiBQcmVwYXJlZFN0YXRlbWVudEtleXMuUEFHRSxcbiAgICAgIFwiZmluZE9uZUJ5LzprZXkvOnZhbHVlXCI6IFByZXBhcmVkU3RhdGVtZW50S2V5cy5GSU5EX09ORV9CWSxcbiAgICAgIFwiZmluZEJ5LzprZXkvOnZhbHVlXCI6IFByZXBhcmVkU3RhdGVtZW50S2V5cy5GSU5EX0JZLFxuICAgICAgXCJjb3VudE9mLzpmaWVsZFwiOiBQcmVwYXJlZFN0YXRlbWVudEtleXMuQ09VTlRfT0YsXG4gICAgICBcIm1heE9mLzpmaWVsZFwiOiBQcmVwYXJlZFN0YXRlbWVudEtleXMuTUFYX09GLFxuICAgICAgXCJtaW5PZi86ZmllbGRcIjogUHJlcGFyZWRTdGF0ZW1lbnRLZXlzLk1JTl9PRixcbiAgICAgIFwiYXZnT2YvOmZpZWxkXCI6IFByZXBhcmVkU3RhdGVtZW50S2V5cy5BVkdfT0YsXG4gICAgICBcInN1bU9mLzpmaWVsZFwiOiBQcmVwYXJlZFN0YXRlbWVudEtleXMuU1VNX09GLFxuICAgICAgXCJkaXN0aW5jdE9mLzpmaWVsZFwiOiBQcmVwYXJlZFN0YXRlbWVudEtleXMuRElTVElOQ1RfT0YsXG4gICAgICBcImdyb3VwT2YvOmZpZWxkXCI6IFByZXBhcmVkU3RhdGVtZW50S2V5cy5HUk9VUF9PRixcbiAgICB9O1xuXG4gICAgY29uc3Qgc3RhdGVtZW50S2V5ID0gc3RhdGVtZW50Um91dGVzW25vcm1hbGl6ZWRQYXRoXTtcbiAgICBpZiAoc3RhdGVtZW50S2V5ICYmIG1ldGhvZCA9PT0gXCJHRVRcIikge1xuICAgICAgcmV0dXJuIEZyb21Nb2RlbENvbnRyb2xsZXIuY3JlYXRlUmVnaXN0cmF0aW9uKFxuICAgICAgICBGcm9tTW9kZWxDb250cm9sbGVyLnN0YXRlbWVudE1ldGhvZE5hbWUobm9ybWFsaXplZFBhdGgpLFxuICAgICAgICBGcm9tTW9kZWxDb250cm9sbGVyLmNyZWF0ZVN0YXRlbWVudFNob3J0Y3V0SGFuZGxlcihzdGF0ZW1lbnRLZXksIG1vZGVsQ2xhenpOYW1lKSxcbiAgICAgICAgRnJvbU1vZGVsQ29udHJvbGxlci5zdGF0ZW1lbnRTaG9ydGN1dERlY29yYXRvcnMoTW9kZWxDb25zdHIsIG1vZGVsQ2xhenpOYW1lLCBub3JtYWxpemVkUGF0aCwgc3RhdGVtZW50S2V5KSxcbiAgICAgICAgRnJvbU1vZGVsQ29udHJvbGxlci5zdGF0ZW1lbnRTaG9ydGN1dFBhcmFtcyhub3JtYWxpemVkUGF0aClcbiAgICAgICk7XG4gICAgfVxuXG4gICAgaWYgKG1ldGhvZCA9PT0gXCJHRVRcIiAmJiBub3JtYWxpemVkUGF0aC5zdGFydHNXaXRoKFwicXVlcnkvXCIpKSB7XG4gICAgICBjb25zdCBxdWVyeU1ldGhvZCA9IG5vcm1hbGl6ZWRQYXRoLnJlcGxhY2UoL15xdWVyeVxcLy8sIFwiXCIpLnNwbGl0KFwiL1wiKVswXTtcbiAgICAgIHJldHVybiBGcm9tTW9kZWxDb250cm9sbGVyLmNyZWF0ZVJlZ2lzdHJhdGlvbihcbiAgICAgICAgcXVlcnlNZXRob2QsXG4gICAgICAgIEZyb21Nb2RlbENvbnRyb2xsZXIuY3JlYXRlQ29tcGxleFF1ZXJ5SGFuZGxlcihxdWVyeU1ldGhvZCksXG4gICAgICAgIEZyb21Nb2RlbENvbnRyb2xsZXIuZ2V0UXVlcnlEZWNvcmF0b3JzKHF1ZXJ5TWV0aG9kLCBub3JtYWxpemVkUGF0aCwgXCJHRVRcIiwgdHJ1ZSksXG4gICAgICAgIEZyb21Nb2RlbENvbnRyb2xsZXIuY29tcGxleFF1ZXJ5UGFyYW1zKG5vcm1hbGl6ZWRQYXRoKVxuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyBGYWxsYmFjayBmb3IgY3VzdG9tIEByb3V0ZSgpIHBhdGhzIChlLmcuIFwibWV0YWRhdGEvZm9yLXByb2R1Y3QvOnByb2R1Y3RDb2RlXCIpXG4gICAgY29uc3QgcGF0aFNlZ21lbnRzID0gbm9ybWFsaXplZFBhdGguc3BsaXQoXCIvXCIpLmZpbHRlcihCb29sZWFuKTtcbiAgICBjb25zdCBrbm93blByZWZpeGVzID0gbmV3IFNldDxzdHJpbmc+KFtcbiAgICAgIFwibGlzdEJ5XCIsIFwiZmluZEJ5XCIsIFwiZmluZEJ5UGFnaW5hdGVcIiwgXCJmaW5kT25lQnlcIiwgXCJwYWdpbmF0ZUJ5XCIsXG4gICAgICBcImZpbmRcIiwgXCJwYWdlXCIsIFwiY291bnRPZlwiLCBcIm1heE9mXCIsIFwibWluT2ZcIiwgXCJhdmdPZlwiLCBcInN1bU9mXCIsXG4gICAgICBcImRpc3RpbmN0T2ZcIiwgXCJncm91cE9mXCIsIFwic3RhdGVtZW50XCIsIFwiYnVsa1wiLCBcInF1ZXJ5XCIsXG4gICAgXSk7XG4gICAgaWYgKFxuICAgICAgcGF0aFNlZ21lbnRzLmxlbmd0aCA+IDAgJiZcbiAgICAgICFub3JtYWxpemVkUGF0aC5zdGFydHNXaXRoKFwicXVlcnkvXCIpICYmXG4gICAgICAha25vd25QcmVmaXhlcy5oYXMocGF0aFNlZ21lbnRzWzBdKVxuICAgICkge1xuICAgICAgLy8gTG9vayB1cCB0aGUgYWN0dWFsIG1ldGhvZCBuYW1lIGZyb20gQHJvdXRlIG1ldGFkYXRhIGJ5IG1hdGNoaW5nIHRoZSBwYXRoLlxuICAgICAgLy8gVGhlIEByb3V0ZSBkZWNvcmF0b3Igc3RvcmVzIHsgcGF0aCwgaHR0cE1ldGhvZCwgaGFuZGxlciB9IGtleWVkIGJ5IG1ldGhvZCBuYW1lXG4gICAgICAvLyBvbiB0aGUgcmVwb3NpdG9yeSBjb25zdHJ1Y3Rvci5cbiAgICAgIGNvbnN0IHJvdXRlTWV0YWRhdGE6IFJlY29yZDxzdHJpbmcsIGFueT4gPVxuICAgICAgICBNZXRhZGF0YS5nZXQoXG4gICAgICAgICAgKHBlcnNpc3RlbmNlIGFzIGFueSk/LmNvbnN0cnVjdG9yLFxuICAgICAgICAgIE1ldGFkYXRhLmtleShERUNBRl9ST1VURSlcbiAgICAgICAgKSA/PyB7fTtcbiAgICAgIGNvbnN0IG1hdGNoZWRFbnRyeSA9IE9iamVjdC5lbnRyaWVzKHJvdXRlTWV0YWRhdGEpLmZpbmQoXG4gICAgICAgIChbLCBpbmZvXSkgPT5cbiAgICAgICAgICBpbmZvICYmXG4gICAgICAgICAgdHlwZW9mIGluZm8gPT09IFwib2JqZWN0XCIgJiZcbiAgICAgICAgICBpbmZvLnBhdGg/LnJlcGxhY2UoL15cXC8rfFxcLyskL2csIFwiXCIpID09PSBub3JtYWxpemVkUGF0aFxuICAgICAgKTtcbiAgICAgIGNvbnN0IGFjdHVhbE1ldGhvZE5hbWUgPSBtYXRjaGVkRW50cnk/LlswXSB8fCBwYXRoU2VnbWVudHNbMF07XG5cbiAgICAgIGNvbnN0IHBhcmFtU2VnbWVudHMgPSBwYXRoU2VnbWVudHMuZmlsdGVyKChzKSA9PiBzLnN0YXJ0c1dpdGgoXCI6XCIpKTtcbiAgICAgIGNvbnN0IGFwaVBhdGhQYXJhbXMgPSBwYXJhbVNlZ21lbnRzLm1hcCgocykgPT4gcy5zbGljZSgxKSkubWFwKChuYW1lKSA9PiAoe1xuICAgICAgICBuYW1lLFxuICAgICAgICBkZXNjcmlwdGlvbjogYCR7bmFtZX0gcGFyYW1ldGVyIGZvciB0aGUgcXVlcnlgLFxuICAgICAgICByZXF1aXJlZDogdHJ1ZSxcbiAgICAgICAgdHlwZTogU3RyaW5nLFxuICAgICAgfSkpO1xuXG4gICAgICByZXR1cm4gRnJvbU1vZGVsQ29udHJvbGxlci5jcmVhdGVSZWdpc3RyYXRpb24oXG4gICAgICAgIGFjdHVhbE1ldGhvZE5hbWUsXG4gICAgICAgIEZyb21Nb2RlbENvbnRyb2xsZXIuY3JlYXRlQ3VzdG9tUm91dGVIYW5kbGVyKGFjdHVhbE1ldGhvZE5hbWUpLFxuICAgICAgICBbXG4gICAgICAgICAgLi4uYXBpUGF0aFBhcmFtcy5tYXAoKHApID0+IEFwaVBhcmFtKHApKSxcbiAgICAgICAgICBBcGlPcGVyYXRpb24oeyBzdW1tYXJ5OiBgUmV0cmlldmUgcmVjb3JkcyB1c2luZyBcIiR7YWN0dWFsTWV0aG9kTmFtZX1cIi5gIH0pLFxuICAgICAgICAgIEFwaU9rUmVzcG9uc2UoeyBkZXNjcmlwdGlvbjogXCJSZXN1bHQgc3VjY2Vzc2Z1bGx5IHJldHJpZXZlZC5cIiB9KSxcbiAgICAgICAgICBBcGlOb0NvbnRlbnRSZXNwb25zZSh7IGRlc2NyaXB0aW9uOiBcIk5vIGNvbnRlbnQgcmV0dXJuZWQgYnkgdGhlIG1ldGhvZC5cIiB9KSxcbiAgICAgICAgXSxcbiAgICAgICAgRnJvbU1vZGVsQ29udHJvbGxlci5jb21wbGV4UXVlcnlQYXJhbXMobm9ybWFsaXplZFBhdGgpXG4gICAgICApO1xuICAgIH1cblxuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cblxuICBwcml2YXRlIHN0YXRpYyBjcmVhdGVSZWdpc3RyYXRpb24oXG4gICAgbWV0aG9kTmFtZTogc3RyaW5nLFxuICAgIGhhbmRsZXI6ICguLi5hcmdzOiBhbnlbXSkgPT4gYW55LFxuICAgIGRlY29yYXRvcnM6IEFycmF5PCh0YXJnZXQ6IGFueSwga2V5OiBzdHJpbmcsIGRlc2M6IGFueSkgPT4gdm9pZD4sXG4gICAgcGFyYW1EZWNvcmF0b3JzOiBBcnJheTx7IGRlY29yYXRvcjogUGFyYW1ldGVyRGVjb3JhdG9yOyBpbmRleDogbnVtYmVyIH0+XG4gICkge1xuICAgIHJldHVybiB7IG1ldGhvZE5hbWUsIGhhbmRsZXIsIGRlY29yYXRvcnMsIHBhcmFtRGVjb3JhdG9ycyB9O1xuICB9XG5cbiAgcHJpdmF0ZSBzdGF0aWMgc3RhdGVtZW50TWV0aG9kTmFtZShwYXRoOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIGNvbnN0IGZpcnN0U2VnbWVudCA9IHBhdGguc3BsaXQoXCIvXCIpWzBdO1xuICAgIHJldHVybiBmaXJzdFNlZ21lbnQ7XG4gIH1cblxuICBwcml2YXRlIHN0YXRpYyBzdGF0ZW1lbnRTaG9ydGN1dFBhcmFtcyhcbiAgICBwYXRoOiBzdHJpbmdcbiAgKTogQXJyYXk8eyBkZWNvcmF0b3I6IFBhcmFtZXRlckRlY29yYXRvcjsgaW5kZXg6IG51bWJlciB9PiB7XG4gICAgY29uc3Qgc2VnbWVudHMgPSBwYXRoLnNwbGl0KFwiL1wiKS5maWx0ZXIoKHMpID0+IHMuc3RhcnRzV2l0aChcIjpcIikpO1xuICAgIGNvbnN0IHBhcmFtczogQXJyYXk8eyBkZWNvcmF0b3I6IFBhcmFtZXRlckRlY29yYXRvcjsgaW5kZXg6IG51bWJlciB9PiA9IFtdO1xuICAgIHNlZ21lbnRzLmZvckVhY2goKHNlZywgaSkgPT4ge1xuICAgICAgY29uc3QgbmFtZSA9IHNlZy5yZXBsYWNlKFwiOlwiLCBcIlwiKTtcbiAgICAgIHBhcmFtcy5wdXNoKHsgZGVjb3JhdG9yOiBQYXJhbShuYW1lKSBhcyBhbnksIGluZGV4OiBpIH0pO1xuICAgIH0pO1xuICAgIGlmIChcbiAgICAgIHBhdGguc3RhcnRzV2l0aChcImxpc3RCeS9cIikgfHxcbiAgICAgIHBhdGguc3RhcnRzV2l0aChcInBhZ2luYXRlQnkvXCIpIHx8XG4gICAgICBwYXRoLnN0YXJ0c1dpdGgoXCJmaW5kL1wiKSB8fFxuICAgICAgcGF0aC5zdGFydHNXaXRoKFwicGFnZS9cIilcbiAgICApIHtcbiAgICAgIHBhcmFtcy5wdXNoKHsgZGVjb3JhdG9yOiBEZWNhZlF1ZXJ5KCkgYXMgYW55LCBpbmRleDogc2VnbWVudHMubGVuZ3RoIH0pO1xuICAgIH1cbiAgICByZXR1cm4gcGFyYW1zO1xuICB9XG5cbiAgcHJpdmF0ZSBzdGF0aWMgY29tcGxleFF1ZXJ5UGFyYW1zKFxuICAgIHBhdGg6IHN0cmluZ1xuICApOiBBcnJheTx7IGRlY29yYXRvcjogUGFyYW1ldGVyRGVjb3JhdG9yOyBpbmRleDogbnVtYmVyIH0+IHtcbiAgICBjb25zdCBzZWdtZW50cyA9IHBhdGguc3BsaXQoXCIvXCIpLmZpbHRlcigocykgPT4gcy5zdGFydHNXaXRoKFwiOlwiKSk7XG4gICAgY29uc3QgcGFyYW1zOiBBcnJheTx7IGRlY29yYXRvcjogUGFyYW1ldGVyRGVjb3JhdG9yOyBpbmRleDogbnVtYmVyIH0+ID0gW107XG4gICAgc2VnbWVudHMuZm9yRWFjaCgoc2VnLCBpKSA9PiB7XG4gICAgICBjb25zdCBuYW1lID0gc2VnLnJlcGxhY2UoXCI6XCIsIFwiXCIpO1xuICAgICAgcGFyYW1zLnB1c2goeyBkZWNvcmF0b3I6IFBhcmFtKG5hbWUpIGFzIGFueSwgaW5kZXg6IGkgfSk7XG4gICAgfSk7XG4gICAgaWYgKHBhdGguc3RhcnRzV2l0aChcInF1ZXJ5L1wiKSkge1xuICAgICAgcGFyYW1zLnB1c2goeyBkZWNvcmF0b3I6IERlY2FmUXVlcnkoKSBhcyBhbnksIGluZGV4OiBzZWdtZW50cy5sZW5ndGggfSk7XG4gICAgfVxuICAgIHJldHVybiBwYXJhbXM7XG4gIH1cblxuICBwcml2YXRlIHN0YXRpYyBjcmVhdGVDcmVhdGVIYW5kbGVyKFxuICAgIE1vZGVsQ29uc3RyOiBNb2RlbENvbnN0cnVjdG9yPGFueT4sXG4gICAgbW9kZWxDbGF6ek5hbWU6IHN0cmluZ1xuICApIHtcbiAgICByZXR1cm4gYXN5bmMgZnVuY3Rpb24gY3JlYXRlKFxuICAgICAgdGhpczogYW55LFxuICAgICAgZGF0YTogYW55LFxuICAgICAgcmVzcD86IGFueVxuICAgICk6IFByb21pc2U8TW9kZWw8YW55Pj4ge1xuICAgICAgY29uc3QgeyBjdHgsIGxvZyB9ID0gKFxuICAgICAgICBhd2FpdCB0aGlzLmxvZ0N0eChbXSwgT3BlcmF0aW9uS2V5cy5DUkVBVEUsIHRydWUpXG4gICAgICApLmZvcihjcmVhdGUpO1xuICAgICAgbG9nLnZlcmJvc2UoYGNyZWF0aW5nIG5ldyAke21vZGVsQ2xhenpOYW1lfWApO1xuICAgICAgbGV0IGNyZWF0ZWQ6IE1vZGVsO1xuICAgICAgdHJ5IHtcbiAgICAgICAgY3JlYXRlZCA9IGF3YWl0IHRoaXMucGVyc2lzdGVuY2UoY3R4KS5jcmVhdGUoZGF0YSwgY3R4KTtcbiAgICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgICAgbG9nLmVycm9yKGBGYWlsZWQgdG8gY3JlYXRlIG5ldyAke21vZGVsQ2xhenpOYW1lfWAsIGUgYXMgRXJyb3IpO1xuICAgICAgICB0aHJvdyBlO1xuICAgICAgfVxuICAgICAgbG9nLmluZm8oYGNyZWF0ZWQgbmV3ICR7bW9kZWxDbGF6ek5hbWV9IHdpdGggaWQgJHsoY3JlYXRlZCBhcyBhbnkpW3RoaXMucGtdfWApO1xuICAgICAgaWYgKHJlc3ApIGN0eC50b1Jlc3BvbnNlKHJlc3ApO1xuICAgICAgcmV0dXJuIGNyZWF0ZWQ7XG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgc3RhdGljIGNyZWF0ZUJ1bGtDcmVhdGVIYW5kbGVyKFxuICAgIE1vZGVsQ29uc3RyOiBNb2RlbENvbnN0cnVjdG9yPGFueT4sXG4gICAgbW9kZWxDbGF6ek5hbWU6IHN0cmluZ1xuICApIHtcbiAgICByZXR1cm4gYXN5bmMgZnVuY3Rpb24gY3JlYXRlQWxsKFxuICAgICAgdGhpczogYW55LFxuICAgICAgZGF0YTogYW55W10sXG4gICAgICByZXNwPzogYW55XG4gICAgKTogUHJvbWlzZTxNb2RlbFtdPiB7XG4gICAgICBjb25zdCB7IGN0eCwgbG9nIH0gPSAoXG4gICAgICAgIGF3YWl0IHRoaXMubG9nQ3R4KFtdLCBCdWxrQ3J1ZE9wZXJhdGlvbktleXMuQ1JFQVRFX0FMTCwgdHJ1ZSlcbiAgICAgICkuZm9yKGNyZWF0ZUFsbCk7XG4gICAgICBsb2cudmVyYm9zZShgY3JlYXRpbmcgbmV3ICR7bW9kZWxDbGF6ek5hbWV9YCk7XG4gICAgICBsZXQgY3JlYXRlZDogYW55W107XG4gICAgICB0cnkge1xuICAgICAgICBjcmVhdGVkID0gYXdhaXQgdGhpcy5wZXJzaXN0ZW5jZShjdHgpLmNyZWF0ZUFsbChcbiAgICAgICAgICBkYXRhLm1hcCgoZCkgPT4gbmV3IE1vZGVsQ29uc3RyKGQpKSxcbiAgICAgICAgICBjdHhcbiAgICAgICAgKTtcbiAgICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgICAgbG9nLmVycm9yKGBGYWlsZWQgdG8gY3JlYXRlIG5ldyAke21vZGVsQ2xhenpOYW1lfWAsIGUgYXMgRXJyb3IpO1xuICAgICAgICB0aHJvdyBlO1xuICAgICAgfVxuICAgICAgbG9nLmluZm8oYGNyZWF0ZWQgbmV3ICR7bW9kZWxDbGF6ek5hbWV9IHdpdGggaWQgJHsoY3JlYXRlZCBhcyBhbnkpW3RoaXMucGtdfWApO1xuICAgICAgaWYgKHJlc3ApIGN0eC50b1Jlc3BvbnNlKHJlc3ApO1xuICAgICAgcmV0dXJuIGNyZWF0ZWQ7XG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgc3RhdGljIGNyZWF0ZUJ1bGtSZWFkSGFuZGxlcihtb2RlbENsYXp6TmFtZTogc3RyaW5nKSB7XG4gICAgcmV0dXJuIGFzeW5jIGZ1bmN0aW9uIHJlYWRBbGwoXG4gICAgICB0aGlzOiBhbnksXG4gICAgICBpZHM6IHN0cmluZ1tdXG4gICAgKTogUHJvbWlzZTxNb2RlbFtdPiB7XG4gICAgICBjb25zdCB7IGN0eCwgbG9nIH0gPSAoXG4gICAgICAgIGF3YWl0IHRoaXMubG9nQ3R4KFtdLCBCdWxrQ3J1ZE9wZXJhdGlvbktleXMuUkVBRF9BTEwsIHRydWUpXG4gICAgICApLmZvcihyZWFkQWxsKTtcbiAgICAgIGNvbnN0IG5vcm1hbGl6ZWRJZHMgPSBBcnJheS5pc0FycmF5KGlkcykgPyBpZHMgOiBbaWRzXTtcbiAgICAgIGxldCByZWFkOiBNb2RlbFtdO1xuICAgICAgdHJ5IHtcbiAgICAgICAgbG9nLmRlYnVnKGByZWFkaW5nICR7bm9ybWFsaXplZElkc30gJHttb2RlbENsYXp6TmFtZX1gKTtcbiAgICAgICAgcmVhZCA9IGF3YWl0IHRoaXMucGVyc2lzdGVuY2UoY3R4KS5yZWFkQWxsKG5vcm1hbGl6ZWRJZHMgYXMgYW55LCBjdHgpO1xuICAgICAgfSBjYXRjaCAoZTogdW5rbm93bikge1xuICAgICAgICBsb2cuZXJyb3IoYEZhaWxlZCB0byByZWFkICR7bW9kZWxDbGF6ek5hbWV9YCwgZSBhcyBFcnJvcik7XG4gICAgICAgIHRocm93IGU7XG4gICAgICB9XG4gICAgICBsb2cuaW5mbyhgcmVhZCAke3JlYWQubGVuZ3RofSAke21vZGVsQ2xhenpOYW1lfWApO1xuICAgICAgcmV0dXJuIHJlYWQ7XG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgc3RhdGljIGNyZWF0ZUJ1bGtVcGRhdGVIYW5kbGVyKG1vZGVsQ2xhenpOYW1lOiBzdHJpbmcpIHtcbiAgICByZXR1cm4gYXN5bmMgZnVuY3Rpb24gdXBkYXRlQWxsKFxuICAgICAgdGhpczogYW55LFxuICAgICAgYm9keTogYW55W10sXG4gICAgICByZXNwPzogYW55XG4gICAgKTogUHJvbWlzZTxhbnlbXT4ge1xuICAgICAgY29uc3QgeyBjdHgsIGxvZyB9ID0gKFxuICAgICAgICBhd2FpdCB0aGlzLmxvZ0N0eChbXSwgQnVsa0NydWRPcGVyYXRpb25LZXlzLlVQREFURV9BTEwsIHRydWUpXG4gICAgICApLmZvcih1cGRhdGVBbGwpO1xuICAgICAgbGV0IHVwZGF0ZWQ6IGFueVtdO1xuICAgICAgdHJ5IHtcbiAgICAgICAgbG9nLmluZm8oYHVwZGF0aW5nICR7Ym9keS5sZW5ndGh9ICR7bW9kZWxDbGF6ek5hbWV9YCk7XG4gICAgICAgIHVwZGF0ZWQgPSBhd2FpdCB0aGlzLnBlcnNpc3RlbmNlKGN0eCkudXBkYXRlQWxsKGJvZHksIGN0eCk7XG4gICAgICB9IGNhdGNoIChlOiB1bmtub3duKSB7XG4gICAgICAgIGxvZy5lcnJvcihlIGFzIEVycm9yKTtcbiAgICAgICAgdGhyb3cgZTtcbiAgICAgIH1cbiAgICAgIGlmIChyZXNwKSBjdHgudG9SZXNwb25zZShyZXNwKTtcbiAgICAgIHJldHVybiB1cGRhdGVkO1xuICAgIH07XG4gIH1cblxuICBwcml2YXRlIHN0YXRpYyBjcmVhdGVCdWxrRGVsZXRlSGFuZGxlcihtb2RlbENsYXp6TmFtZTogc3RyaW5nKSB7XG4gICAgcmV0dXJuIGFzeW5jIGZ1bmN0aW9uIGRlbGV0ZUFsbChcbiAgICAgIHRoaXM6IGFueSxcbiAgICAgIGlkczogc3RyaW5nW10sXG4gICAgICByZXNwPzogYW55XG4gICAgKTogUHJvbWlzZTxNb2RlbFtdPiB7XG4gICAgICBjb25zdCB7IGN0eCwgbG9nIH0gPSAoXG4gICAgICAgIGF3YWl0IHRoaXMubG9nQ3R4KFtdLCBCdWxrQ3J1ZE9wZXJhdGlvbktleXMuREVMRVRFX0FMTCwgdHJ1ZSlcbiAgICAgICkuZm9yKGRlbGV0ZUFsbCk7XG4gICAgICBjb25zdCBub3JtYWxpemVkSWRzID0gQXJyYXkuaXNBcnJheShpZHMpID8gaWRzIDogW2lkc107XG4gICAgICBsZXQgcmVhZDogTW9kZWxbXTtcbiAgICAgIHRyeSB7XG4gICAgICAgIGxvZy5kZWJ1ZyhgZGVsZXRpbmcgJHtub3JtYWxpemVkSWRzLmxlbmd0aH0gJHttb2RlbENsYXp6TmFtZX1gKTtcbiAgICAgICAgcmVhZCA9IGF3YWl0IHRoaXMucGVyc2lzdGVuY2UoY3R4KS5kZWxldGVBbGwobm9ybWFsaXplZElkcywgY3R4KTtcbiAgICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgICAgbG9nLmVycm9yKGBGYWlsZWQgdG8gZGVsZXRlICR7bW9kZWxDbGF6ek5hbWV9YCwgZSBhcyBFcnJvcik7XG4gICAgICAgIHRocm93IGU7XG4gICAgICB9XG4gICAgICBsb2cuaW5mbyhgZGVsZXRlZCAke3JlYWQubGVuZ3RofSAke21vZGVsQ2xhenpOYW1lfWApO1xuICAgICAgaWYgKHJlc3ApIGN0eC50b1Jlc3BvbnNlKHJlc3ApO1xuICAgICAgcmV0dXJuIHJlYWQ7XG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgc3RhdGljIGNyZWF0ZVJlYWRIYW5kbGVyKFxuICAgIGdldFBLOiAoLi4ucDogQXJyYXk8c3RyaW5nIHwgbnVtYmVyPikgPT4gc3RyaW5nLFxuICAgIG1vZGVsQ2xhenpOYW1lOiBzdHJpbmdcbiAgKSB7XG4gICAgcmV0dXJuIGFzeW5jIGZ1bmN0aW9uIHJlYWQoXG4gICAgICB0aGlzOiBhbnksXG4gICAgICByb3V0ZVBhcmFtczogYW55XG4gICAgKTogUHJvbWlzZTxNb2RlbD4ge1xuICAgICAgY29uc3QgeyBjdHgsIGxvZyB9ID0gKFxuICAgICAgICBhd2FpdCB0aGlzLmxvZ0N0eChbXSwgT3BlcmF0aW9uS2V5cy5SRUFELCB0cnVlKVxuICAgICAgKS5mb3IocmVhZCk7XG4gICAgICBjb25zdCBpZCA9IGdldFBLKC4uLnJvdXRlUGFyYW1zLnZhbHVlc0luT3JkZXIpO1xuICAgICAgaWYgKHR5cGVvZiBpZCA9PT0gXCJ1bmRlZmluZWRcIilcbiAgICAgICAgdGhyb3cgbmV3IFZhbGlkYXRpb25FcnJvcihgTm8gJHt0aGlzLnBrfSBwcm92aWRlZGApO1xuICAgICAgbGV0IHJlYWRSZXN1bHQ6IE1vZGVsO1xuICAgICAgdHJ5IHtcbiAgICAgICAgbG9nLmRlYnVnKGByZWFkaW5nICR7bW9kZWxDbGF6ek5hbWV9IHdpdGggJHt0aGlzLnBrfSAke2lkfWApO1xuICAgICAgICByZWFkUmVzdWx0ID0gYXdhaXQgdGhpcy5wZXJzaXN0ZW5jZShjdHgpLnJlYWQoaWQsIGN0eCk7XG4gICAgICB9IGNhdGNoIChlOiB1bmtub3duKSB7XG4gICAgICAgIGxvZy5lcnJvcihgRmFpbGVkIHRvIHJlYWQgJHttb2RlbENsYXp6TmFtZX0gd2l0aCBpZCAke2lkfWAsIGUgYXMgRXJyb3IpO1xuICAgICAgICB0aHJvdyBlO1xuICAgICAgfVxuICAgICAgbG9nLmluZm8oYHJlYWQgJHttb2RlbENsYXp6TmFtZX0gd2l0aCBpZCAkeyhyZWFkUmVzdWx0IGFzIGFueSlbdGhpcy5wa119YCk7XG4gICAgICByZXR1cm4gcmVhZFJlc3VsdDtcbiAgICB9O1xuICB9XG5cbiAgcHJpdmF0ZSBzdGF0aWMgY3JlYXRlVXBkYXRlSGFuZGxlcihcbiAgICBnZXRQSzogKC4uLnA6IEFycmF5PHN0cmluZyB8IG51bWJlcj4pID0+IHN0cmluZyxcbiAgICBNb2RlbENvbnN0cjogTW9kZWxDb25zdHJ1Y3Rvcjxhbnk+LFxuICAgIG1vZGVsQ2xhenpOYW1lOiBzdHJpbmdcbiAgKSB7XG4gICAgcmV0dXJuIGFzeW5jIGZ1bmN0aW9uIHVwZGF0ZShcbiAgICAgIHRoaXM6IGFueSxcbiAgICAgIHJvdXRlUGFyYW1zOiBhbnksXG4gICAgICBib2R5OiBhbnksXG4gICAgICByZXNwPzogYW55XG4gICAgKTogUHJvbWlzZTxhbnk+IHtcbiAgICAgIGNvbnN0IHsgY3R4LCBsb2cgfSA9IChcbiAgICAgICAgYXdhaXQgdGhpcy5sb2dDdHgoW10sIE9wZXJhdGlvbktleXMuVVBEQVRFLCB0cnVlKVxuICAgICAgKS5mb3IodXBkYXRlKTtcbiAgICAgIGNvbnN0IGlkID0gZ2V0UEsoLi4ucm91dGVQYXJhbXMudmFsdWVzSW5PcmRlcik7XG4gICAgICBpZiAodHlwZW9mIGlkID09PSBcInVuZGVmaW5lZFwiKVxuICAgICAgICB0aHJvdyBuZXcgVmFsaWRhdGlvbkVycm9yKGBObyAke3RoaXMucGt9IHByb3ZpZGVkYCk7XG4gICAgICBsZXQgdXBkYXRlZDogYW55O1xuICAgICAgdHJ5IHtcbiAgICAgICAgbG9nLmluZm8oYHVwZGF0aW5nICR7bW9kZWxDbGF6ek5hbWV9IHdpdGggJHt0aGlzLnBrfSAke2lkfWApO1xuICAgICAgICBjb25zdCBwYXlsb2FkID0gSlNPTi5wYXJzZShKU09OLnN0cmluZ2lmeShib2R5KSk7XG4gICAgICAgIHVwZGF0ZWQgPSBhd2FpdCB0aGlzLnBlcnNpc3RlbmNlKGN0eCkudXBkYXRlKFxuICAgICAgICAgIG5ldyBNb2RlbENvbnN0cih7IC4uLnBheWxvYWQsIFt0aGlzLnBrXTogaWQgfSksXG4gICAgICAgICAgY3R4XG4gICAgICAgICk7XG4gICAgICB9IGNhdGNoIChlOiB1bmtub3duKSB7XG4gICAgICAgIGxvZy5lcnJvcihlIGFzIEVycm9yKTtcbiAgICAgICAgdGhyb3cgZTtcbiAgICAgIH1cbiAgICAgIGlmIChyZXNwKSBjdHgudG9SZXNwb25zZShyZXNwKTtcbiAgICAgIHJldHVybiB1cGRhdGVkO1xuICAgIH07XG4gIH1cblxuICBwcml2YXRlIHN0YXRpYyBjcmVhdGVEZWxldGVIYW5kbGVyKFxuICAgIGdldFBLOiAoLi4ucDogQXJyYXk8c3RyaW5nIHwgbnVtYmVyPikgPT4gc3RyaW5nLFxuICAgIG1vZGVsQ2xhenpOYW1lOiBzdHJpbmdcbiAgKSB7XG4gICAgcmV0dXJuIGFzeW5jIGZ1bmN0aW9uIHJlbW92ZShcbiAgICAgIHRoaXM6IGFueSxcbiAgICAgIHJvdXRlUGFyYW1zOiBhbnksXG4gICAgICByZXNwPzogYW55XG4gICAgKTogUHJvbWlzZTxNb2RlbD4ge1xuICAgICAgY29uc3QgeyBjdHgsIGxvZyB9ID0gKFxuICAgICAgICBhd2FpdCB0aGlzLmxvZ0N0eChbXSwgT3BlcmF0aW9uS2V5cy5ERUxFVEUsIHRydWUpXG4gICAgICApLmZvcihyZW1vdmUpO1xuICAgICAgY29uc3QgaWQgPSBnZXRQSyguLi5yb3V0ZVBhcmFtcy52YWx1ZXNJbk9yZGVyKTtcbiAgICAgIGlmICh0eXBlb2YgaWQgPT09IFwidW5kZWZpbmVkXCIpXG4gICAgICAgIHRocm93IG5ldyBWYWxpZGF0aW9uRXJyb3IoYE5vICR7dGhpcy5wa30gcHJvdmlkZWRgKTtcbiAgICAgIGxldCBkZWw6IE1vZGVsO1xuICAgICAgdHJ5IHtcbiAgICAgICAgbG9nLmRlYnVnKGBkZWxldGluZyAke21vZGVsQ2xhenpOYW1lfSB3aXRoICR7dGhpcy5wa30gJHtpZH1gKTtcbiAgICAgICAgZGVsID0gYXdhaXQgdGhpcy5wZXJzaXN0ZW5jZShjdHgpLmRlbGV0ZShpZCwgY3R4KTtcbiAgICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgICAgbG9nLmVycm9yKGBGYWlsZWQgdG8gZGVsZXRlICR7bW9kZWxDbGF6ek5hbWV9IHdpdGggaWQgJHtpZH1gLCBlIGFzIEVycm9yKTtcbiAgICAgICAgdGhyb3cgZTtcbiAgICAgIH1cbiAgICAgIGxvZy5pbmZvKGBkZWxldGVkICR7bW9kZWxDbGF6ek5hbWV9IHdpdGggaWQgJHtpZH1gKTtcbiAgICAgIGlmIChyZXNwKSBjdHgudG9SZXNwb25zZShyZXNwKTtcbiAgICAgIHJldHVybiBkZWw7XG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgc3RhdGljIGNyZWF0ZVN0YXRlbWVudEhhbmRsZXIobW9kZWxDbGF6ek5hbWU6IHN0cmluZykge1xuICAgIHJldHVybiBhc3luYyBmdW5jdGlvbiBzdGF0ZW1lbnQoXG4gICAgICB0aGlzOiBhbnksXG4gICAgICBuYW1lOiBzdHJpbmcsXG4gICAgICBhcmdzOiAoc3RyaW5nIHwgbnVtYmVyKVtdLFxuICAgICAgZGV0YWlsczogRGlyZWN0aW9uTGltaXRPZmZzZXRcbiAgICApOiBQcm9taXNlPGFueT4ge1xuICAgICAgY29uc3QgeyBjdHggfSA9IChcbiAgICAgICAgYXdhaXQgdGhpcy5sb2dDdHgoW10sIFBlcnNpc3RlbmNlS2V5cy5TVEFURU1FTlQsIHRydWUpXG4gICAgICApLmZvcihzdGF0ZW1lbnQpO1xuICAgICAgY29uc3QgeyBkaXJlY3Rpb24sIG9mZnNldCwgbGltaXQsIGJvb2ttYXJrIH0gPSBkZXRhaWxzO1xuICAgICAgYXJncyA9IGFyZ3MubWFwKFxuICAgICAgICAoYSkgPT4gKHR5cGVvZiBhID09PSBcInN0cmluZ1wiID8gcGFyc2VJbnQoYSBhcyBzdHJpbmcpIDogYSkgfHwgYVxuICAgICAgKSBhcyBhbnlbXTtcbiAgICAgIGNvbnN0IHBhdGhEaXJlY3Rpb24gPSBhcmdzLmxlbmd0aCA+IDEgPyBhcmdzWzFdIDogdW5kZWZpbmVkO1xuICAgICAgY29uc3QgcmVzb2x2ZWREaXJlY3Rpb24gPSAoZGlyZWN0aW9uID8/IHBhdGhEaXJlY3Rpb24pIGFzXG4gICAgICAgIHwgc3RyaW5nXG4gICAgICAgIHwgdW5kZWZpbmVkO1xuICAgICAgaWYgKHJlc29sdmVkRGlyZWN0aW9uICYmIGFyZ3MubGVuZ3RoID4gMSkgYXJnc1sxXSA9IHJlc29sdmVkRGlyZWN0aW9uO1xuICAgICAgc3dpdGNoIChuYW1lKSB7XG4gICAgICAgIGNhc2UgUHJlcGFyZWRTdGF0ZW1lbnRLZXlzLkZJTkQ6XG4gICAgICAgIGNhc2UgUHJlcGFyZWRTdGF0ZW1lbnRLZXlzLkZJTkRfQlk6XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgUHJlcGFyZWRTdGF0ZW1lbnRLZXlzLkxJU1RfQlk6XG4gICAgICAgICAgYXJncy5wdXNoKGRpcmVjdGlvbiBhcyBzdHJpbmcpO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlIFByZXBhcmVkU3RhdGVtZW50S2V5cy5QQUdFOlxuICAgICAgICBjYXNlIFByZXBhcmVkU3RhdGVtZW50S2V5cy5QQUdFX0JZOlxuICAgICAgICAgIGFyZ3MgPSBbXG4gICAgICAgICAgICBhcmdzWzBdLFxuICAgICAgICAgICAgcmVzb2x2ZWREaXJlY3Rpb24gYXMgYW55LFxuICAgICAgICAgICAgeyBsaW1pdCwgb2Zmc2V0LCBib29rbWFyayB9LFxuICAgICAgICAgIF07XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgUHJlcGFyZWRTdGF0ZW1lbnRLZXlzLkZJTkRfT05FX0JZOlxuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlIFByZXBhcmVkU3RhdGVtZW50S2V5cy5DT1VOVF9PRjpcbiAgICAgICAgY2FzZSBQcmVwYXJlZFN0YXRlbWVudEtleXMuTUFYX09GOlxuICAgICAgICBjYXNlIFByZXBhcmVkU3RhdGVtZW50S2V5cy5NSU5fT0Y6XG4gICAgICAgIGNhc2UgUHJlcGFyZWRTdGF0ZW1lbnRLZXlzLkFWR19PRjpcbiAgICAgICAgY2FzZSBQcmVwYXJlZFN0YXRlbWVudEtleXMuU1VNX09GOlxuICAgICAgICBjYXNlIFByZXBhcmVkU3RhdGVtZW50S2V5cy5ESVNUSU5DVF9PRjpcbiAgICAgICAgY2FzZSBQcmVwYXJlZFN0YXRlbWVudEtleXMuR1JPVVBfT0Y6XG4gICAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICByZXR1cm4gdGhpcy5wZXJzaXN0ZW5jZShjdHgpLnN0YXRlbWVudChuYW1lLCAuLi5hcmdzLCBjdHgpO1xuICAgIH07XG4gIH1cblxuICBwcml2YXRlIHN0YXRpYyBjcmVhdGVTdGF0ZW1lbnRTaG9ydGN1dEhhbmRsZXIoXG4gICAgc3RhdGVtZW50S2V5OiBzdHJpbmcsXG4gICAgbW9kZWxDbGF6ek5hbWU6IHN0cmluZ1xuICApIHtcbiAgICByZXR1cm4gYXN5bmMgZnVuY3Rpb24gc3RhdGVtZW50U2hvcnRjdXQoXG4gICAgICB0aGlzOiBhbnksXG4gICAgICAuLi5hcmdzOiBhbnlbXVxuICAgICk6IFByb21pc2U8YW55PiB7XG4gICAgICBjb25zdCB7IGN0eCB9ID0gKFxuICAgICAgICBhd2FpdCB0aGlzLmxvZ0N0eChbXSwgc3RhdGVtZW50S2V5LCB0cnVlKVxuICAgICAgKS5mb3Ioc3RhdGVtZW50U2hvcnRjdXQpO1xuXG4gICAgICBzd2l0Y2ggKHN0YXRlbWVudEtleSkge1xuICAgICAgICBjYXNlIFByZXBhcmVkU3RhdGVtZW50S2V5cy5MSVNUX0JZOiB7XG4gICAgICAgICAgY29uc3QgW2tleSwgZGV0YWlsc10gPSBhcmdzO1xuICAgICAgICAgIHJldHVybiB0aGlzLnBlcnNpc3RlbmNlKGN0eCkubGlzdEJ5KFxuICAgICAgICAgICAga2V5LFxuICAgICAgICAgICAgKGRldGFpbHMgYXMgYW55KT8uZGlyZWN0aW9uIGFzIE9yZGVyRGlyZWN0aW9uLFxuICAgICAgICAgICAgY3R4XG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgICBjYXNlIFByZXBhcmVkU3RhdGVtZW50S2V5cy5QQUdFX0JZOiB7XG4gICAgICAgICAgY29uc3QgW2tleSwgcGFnZSwgZGV0YWlsc10gPSBhcmdzO1xuICAgICAgICAgIHJldHVybiB0aGlzLnBlcnNpc3RlbmNlKGN0eCkucGFnaW5hdGVCeShcbiAgICAgICAgICAgIGtleSxcbiAgICAgICAgICAgIChkZXRhaWxzIGFzIGFueSk/LmRpcmVjdGlvbiBhcyBPcmRlckRpcmVjdGlvbixcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgbGltaXQ6IChkZXRhaWxzIGFzIGFueSk/LmxpbWl0LFxuICAgICAgICAgICAgICBvZmZzZXQ6IChkZXRhaWxzIGFzIGFueSk/Lm9mZnNldCxcbiAgICAgICAgICAgICAgcGFnZSxcbiAgICAgICAgICAgIH0gYXMgYW55LFxuICAgICAgICAgICAgY3R4XG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgICBjYXNlIFByZXBhcmVkU3RhdGVtZW50S2V5cy5GSU5EOiB7XG4gICAgICAgICAgY29uc3QgW3ZhbHVlLCBkZXRhaWxzXSA9IGFyZ3M7XG4gICAgICAgICAgY29uc3QgZGlyZWN0aW9uID1cbiAgICAgICAgICAgIChkZXRhaWxzIGFzIGFueSk/LmRpcmVjdGlvbiA/PyBPcmRlckRpcmVjdGlvbi5BU0M7XG4gICAgICAgICAgY29uc3QgcGVyc2lzdGVuY2UgPSB0aGlzLnBlcnNpc3RlbmNlKGN0eCk7XG4gICAgICAgICAgaWYgKHR5cGVvZiBwZXJzaXN0ZW5jZS5maW5kID09PSBcImZ1bmN0aW9uXCIpXG4gICAgICAgICAgICByZXR1cm4gcGVyc2lzdGVuY2UuZmluZCh2YWx1ZSwgZGlyZWN0aW9uLCBjdHgpO1xuICAgICAgICAgIHJldHVybiBwZXJzaXN0ZW5jZS5zdGF0ZW1lbnQoUHJlcGFyZWRTdGF0ZW1lbnRLZXlzLkZJTkQsIHZhbHVlLCBkaXJlY3Rpb24sIGN0eCk7XG4gICAgICAgIH1cbiAgICAgICAgY2FzZSBQcmVwYXJlZFN0YXRlbWVudEtleXMuUEFHRToge1xuICAgICAgICAgIGNvbnN0IFt2YWx1ZSwgZGV0YWlsc10gPSBhcmdzO1xuICAgICAgICAgIGNvbnN0IHJlZiA9IHtcbiAgICAgICAgICAgIG9mZnNldDogKGRldGFpbHMgYXMgYW55KT8ub2Zmc2V0ID8/IDEsXG4gICAgICAgICAgICBsaW1pdDogKGRldGFpbHMgYXMgYW55KT8ubGltaXQgPz8gMTAsXG4gICAgICAgICAgICBib29rbWFyazogKGRldGFpbHMgYXMgYW55KT8uYm9va21hcmssXG4gICAgICAgICAgfTtcbiAgICAgICAgICBjb25zdCBwZXJzaXN0ZW5jZSA9IHRoaXMucGVyc2lzdGVuY2UoY3R4KTtcbiAgICAgICAgICBjb25zdCBkaXJlY3Rpb24gPSAoZGV0YWlscyBhcyBhbnkpPy5kaXJlY3Rpb24gPz8gT3JkZXJEaXJlY3Rpb24uQVNDO1xuICAgICAgICAgIGlmICh0eXBlb2YgcGVyc2lzdGVuY2UucGFnZSA9PT0gXCJmdW5jdGlvblwiKVxuICAgICAgICAgICAgcmV0dXJuIHBlcnNpc3RlbmNlLnBhZ2UodmFsdWUsIGRpcmVjdGlvbiwgcmVmLCBjdHgpO1xuICAgICAgICAgIHJldHVybiBwZXJzaXN0ZW5jZS5zdGF0ZW1lbnQoUHJlcGFyZWRTdGF0ZW1lbnRLZXlzLlBBR0UsIHZhbHVlLCBkaXJlY3Rpb24sIHJlZiwgY3R4KTtcbiAgICAgICAgfVxuICAgICAgICBjYXNlIFByZXBhcmVkU3RhdGVtZW50S2V5cy5GSU5EX09ORV9CWToge1xuICAgICAgICAgIGNvbnN0IFtrZXksIHZhbHVlXSA9IGFyZ3M7XG4gICAgICAgICAgcmV0dXJuIHRoaXMucGVyc2lzdGVuY2UoY3R4KS5maW5kT25lQnkoa2V5LCB2YWx1ZSwgY3R4KTtcbiAgICAgICAgfVxuICAgICAgICBjYXNlIFByZXBhcmVkU3RhdGVtZW50S2V5cy5GSU5EX0JZOiB7XG4gICAgICAgICAgY29uc3QgW2tleSwgdmFsdWVdID0gYXJncztcbiAgICAgICAgICByZXR1cm4gdGhpcy5wZXJzaXN0ZW5jZShjdHgpXG4gICAgICAgICAgICAuZm9yKGN0eC50b092ZXJyaWRlcygpKVxuICAgICAgICAgICAgLmZpbmRCeShrZXksIHZhbHVlLCBjdHgpO1xuICAgICAgICB9XG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgaWYgKFxuICAgICAgICAgICAgc3RhdGVtZW50S2V5ID09PSBQcmVwYXJlZFN0YXRlbWVudEtleXMuQ09VTlRfT0YgfHxcbiAgICAgICAgICAgIHN0YXRlbWVudEtleSA9PT0gUHJlcGFyZWRTdGF0ZW1lbnRLZXlzLk1BWF9PRiB8fFxuICAgICAgICAgICAgc3RhdGVtZW50S2V5ID09PSBQcmVwYXJlZFN0YXRlbWVudEtleXMuTUlOX09GIHx8XG4gICAgICAgICAgICBzdGF0ZW1lbnRLZXkgPT09IFByZXBhcmVkU3RhdGVtZW50S2V5cy5BVkdfT0YgfHxcbiAgICAgICAgICAgIHN0YXRlbWVudEtleSA9PT0gUHJlcGFyZWRTdGF0ZW1lbnRLZXlzLlNVTV9PRiB8fFxuICAgICAgICAgICAgc3RhdGVtZW50S2V5ID09PSBQcmVwYXJlZFN0YXRlbWVudEtleXMuRElTVElOQ1RfT0YgfHxcbiAgICAgICAgICAgIHN0YXRlbWVudEtleSA9PT0gUHJlcGFyZWRTdGF0ZW1lbnRLZXlzLkdST1VQX09GXG4gICAgICAgICAgKSB7XG4gICAgICAgICAgICBjb25zdCBbZmllbGRdID0gYXJncztcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnBlcnNpc3RlbmNlKGN0eCkuc3RhdGVtZW50KHN0YXRlbWVudEtleSwgZmllbGQsIGN0eCk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgVW5rbm93biBzdGF0ZW1lbnQ6ICR7c3RhdGVtZW50S2V5fWApO1xuICAgICAgfVxuICAgIH07XG4gIH1cblxuICBwcml2YXRlIHN0YXRpYyBjcmVhdGVDb21wbGV4UXVlcnlIYW5kbGVyKG1ldGhvZE5hbWU6IHN0cmluZykge1xuICAgIHJldHVybiBhc3luYyBmdW5jdGlvbiBjb21wbGV4UXVlcnkoXG4gICAgICB0aGlzOiBhbnksXG4gICAgICAuLi5hcmdzOiBhbnlbXVxuICAgICk6IFByb21pc2U8YW55PiB7XG4gICAgICBjb25zdCBsb2c6IGFueSA9IHRoaXMubG9nPy5mb3I/Lihjb21wbGV4UXVlcnkpO1xuICAgICAgdHJ5IHtcbiAgICAgICAgaWYgKGxvZykgbG9nLmRlYnVnKGBJbnZva2luZyBjdXN0b20gcXVlcnkgXCIke21ldGhvZE5hbWV9XCJgKTtcbiAgICAgICAgY29uc3QgeyBjdHggfSA9IChcbiAgICAgICAgICBhd2FpdCB0aGlzLmxvZ0N0eChbXSwgbWV0aG9kTmFtZSwgdHJ1ZSlcbiAgICAgICAgKS5mb3IoY29tcGxleFF1ZXJ5KTtcbiAgICAgICAgY29uc3QgcGVyc2lzdGVuY2UgPSB0aGlzLnBlcnNpc3RlbmNlKGN0eCk7XG4gICAgICAgIGNvbnN0IHNwcmVhZEFyZ3MgPSBGcm9tTW9kZWxDb250cm9sbGVyLmV4dHJhY3RRdWVyeUFyZ3MoYXJncyk7XG4gICAgICAgIGlmICh0eXBlb2YgcGVyc2lzdGVuY2VbbWV0aG9kTmFtZV0gPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICAgIHJldHVybiBwZXJzaXN0ZW5jZVttZXRob2ROYW1lXSguLi5zcHJlYWRBcmdzLCBjdHgpO1xuICAgICAgICB9XG4gICAgICAgIGlmICh0eXBlb2YgcGVyc2lzdGVuY2Uuc3RhdGVtZW50ID09PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgICByZXR1cm4gcGVyc2lzdGVuY2Uuc3RhdGVtZW50KG1ldGhvZE5hbWUsIC4uLnNwcmVhZEFyZ3MsIGN0eCk7XG4gICAgICAgIH1cbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgIGBQZXJzaXN0ZW5jZSBtZXRob2QgXCIke21ldGhvZE5hbWV9XCIgbm90IGZvdW5kIG9uICR7cGVyc2lzdGVuY2U/LmNvbnN0cnVjdG9yPy5uYW1lfWBcbiAgICAgICAgKTtcbiAgICAgIH0gY2F0Y2ggKGU6IGFueSkge1xuICAgICAgICBpZiAobG9nKSBsb2cuZXJyb3IoYEN1c3RvbSBxdWVyeSBcIiR7bWV0aG9kTmFtZX1cIiBmYWlsZWRgLCBlKTtcbiAgICAgICAgdGhyb3cgZTtcbiAgICAgIH1cbiAgICB9O1xuICB9XG5cbiAgcHJpdmF0ZSBzdGF0aWMgY3JlYXRlQ3VzdG9tUm91dGVIYW5kbGVyKG1ldGhvZE5hbWU6IHN0cmluZykge1xuICAgIHJldHVybiBhc3luYyBmdW5jdGlvbiBjdXN0b21Sb3V0ZShcbiAgICAgIHRoaXM6IGFueSxcbiAgICAgIC4uLmFyZ3M6IGFueVtdXG4gICAgKTogUHJvbWlzZTxhbnk+IHtcbiAgICAgIGNvbnN0IGxvZzogYW55ID0gdGhpcy5sb2c/LmZvcj8uKGN1c3RvbVJvdXRlKTtcbiAgICAgIGNvbnN0IHsgY3R4IH0gPSAoXG4gICAgICAgIGF3YWl0IHRoaXMubG9nQ3R4KFtdLCBtZXRob2ROYW1lLCB0cnVlKVxuICAgICAgKS5mb3IoY3VzdG9tUm91dGUpO1xuICAgICAgY29uc3QgcGVyc2lzdGVuY2UgPSB0aGlzLnBlcnNpc3RlbmNlKGN0eCk7XG4gICAgICBjb25zdCBzcHJlYWRBcmdzID0gRnJvbU1vZGVsQ29udHJvbGxlci5leHRyYWN0UXVlcnlBcmdzKGFyZ3MpO1xuXG4gICAgICAvLyBUcnkgdGhlIHBlcnNpc3RlbmNlIGRpcmVjdGx5ICh3b3JrcyB3aGVuIGl0J3MgYSBjdXN0b20gUmVwb3NpdG9yeSlcbiAgICAgIGlmICh0eXBlb2YgcGVyc2lzdGVuY2VbbWV0aG9kTmFtZV0gPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICByZXR1cm4gcGVyc2lzdGVuY2VbbWV0aG9kTmFtZV0oLi4uc3ByZWFkQXJncywgY3R4KTtcbiAgICAgIH1cbiAgICAgIC8vIFdoZW4gcGVyc2lzdGVuY2UgaXMgYSBNb2RlbFNlcnZpY2UsIHRoZSBtZXRob2QgbGl2ZXMgb24gdGhlIHVuZGVybHlpbmcgcmVwb1xuICAgICAgaWYgKHBlcnNpc3RlbmNlPy5yZXBvICYmIHR5cGVvZiBwZXJzaXN0ZW5jZS5yZXBvW21ldGhvZE5hbWVdID09PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgcmV0dXJuIHBlcnNpc3RlbmNlLnJlcG9bbWV0aG9kTmFtZV0oLi4uc3ByZWFkQXJncywgY3R4KTtcbiAgICAgIH1cbiAgICAgIC8vIEZhbGwgYmFjayB0byBzdGF0ZW1lbnQgZ2F0ZXdheVxuICAgICAgaWYgKHR5cGVvZiBwZXJzaXN0ZW5jZS5zdGF0ZW1lbnQgPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICByZXR1cm4gcGVyc2lzdGVuY2Uuc3RhdGVtZW50KG1ldGhvZE5hbWUsIC4uLnNwcmVhZEFyZ3MsIGN0eCk7XG4gICAgICB9XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBNZXRob2QgXCIke21ldGhvZE5hbWV9XCIgbm90IGZvdW5kIG9uICR7cGVyc2lzdGVuY2U/LmNvbnN0cnVjdG9yPy5uYW1lfSBvciBpdHMgcmVwb2BcbiAgICAgICk7XG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgc3RhdGljIGV4dHJhY3RRdWVyeUFyZ3MoYXJnczogYW55W10pOiBhbnlbXSB7XG4gICAgaWYgKGFyZ3MubGVuZ3RoID09PSAwKSByZXR1cm4gYXJncztcbiAgICBjb25zdCBsYXN0ID0gYXJnc1thcmdzLmxlbmd0aCAtIDFdO1xuICAgIGlmIChcbiAgICAgIGxhc3QgJiZcbiAgICAgIHR5cGVvZiBsYXN0ID09PSBcIm9iamVjdFwiICYmXG4gICAgICAhQXJyYXkuaXNBcnJheShsYXN0KVxuICAgICkge1xuICAgICAgY29uc3QgcXVlcnlPYmogPSBhcmdzLnBvcCgpO1xuICAgICAgY29uc3QgaGFzRGlyZWN0aW9uID0gcXVlcnlPYmouZGlyZWN0aW9uICE9PSB1bmRlZmluZWQ7XG4gICAgICBjb25zdCBoYXNMaW1pdCA9IHF1ZXJ5T2JqLmxpbWl0ICE9PSB1bmRlZmluZWQ7XG4gICAgICBjb25zdCBoYXNPZmZzZXQgPSBxdWVyeU9iai5vZmZzZXQgIT09IHVuZGVmaW5lZDtcbiAgICAgIGlmICghaGFzRGlyZWN0aW9uICYmICFoYXNMaW1pdCAmJiAhaGFzT2Zmc2V0KSByZXR1cm4gYXJncztcbiAgICAgIGNvbnN0IGV4dHJhczogYW55W10gPSBbXTtcbiAgICAgIGlmIChoYXNEaXJlY3Rpb24pIGV4dHJhcy5wdXNoKHF1ZXJ5T2JqLmRpcmVjdGlvbik7XG4gICAgICBlbHNlIGlmIChoYXNMaW1pdCB8fCBoYXNPZmZzZXQpIGV4dHJhcy5wdXNoKHVuZGVmaW5lZCk7XG4gICAgICBpZiAoaGFzTGltaXQpIGV4dHJhcy5wdXNoKHF1ZXJ5T2JqLmxpbWl0KTtcbiAgICAgIGlmIChoYXNPZmZzZXQpIGV4dHJhcy5wdXNoKHF1ZXJ5T2JqLm9mZnNldCk7XG4gICAgICByZXR1cm4gWy4uLmFyZ3MsIC4uLmV4dHJhc107XG4gICAgfVxuICAgIHJldHVybiBhcmdzO1xuICB9XG5cbiAgcHJpdmF0ZSBzdGF0aWMgY3JlYXRlQ3JlYXRlRGVjb3JhdG9ycyhcbiAgICBNb2RlbENvbnN0cjogTW9kZWxDb25zdHJ1Y3Rvcjxhbnk+LFxuICAgIG1vZGVsQ2xhenpOYW1lOiBzdHJpbmdcbiAgKTogQXJyYXk8KHRhcmdldDogYW55LCBrZXk6IHN0cmluZywgZGVzYzogYW55KSA9PiB2b2lkPiB7XG4gICAgcmV0dXJuIFtcbiAgICAgIEFwaU9wZXJhdGlvbkZyb21Nb2RlbChNb2RlbENvbnN0ciwgXCJQT1NUXCIpLFxuICAgICAgQXBpT3BlcmF0aW9uKHsgc3VtbWFyeTogYENyZWF0ZSBhIG5ldyAke21vZGVsQ2xhenpOYW1lfS5gIH0pLFxuICAgICAgQXBpQm9keSh7XG4gICAgICAgIGRlc2NyaXB0aW9uOiBgUGF5bG9hZCBmb3IgJHttb2RlbENsYXp6TmFtZX1gLFxuICAgICAgICB0eXBlOiBEdG9Gb3IoT3BlcmF0aW9uS2V5cy5DUkVBVEUsIE1vZGVsQ29uc3RyKSxcbiAgICAgIH0pLFxuICAgICAgQXBpQ3JlYXRlZFJlc3BvbnNlKHtcbiAgICAgICAgZGVzY3JpcHRpb246IGAke21vZGVsQ2xhenpOYW1lfSBjcmVhdGVkIHN1Y2Nlc3NmdWxseS5gLFxuICAgICAgICBzY2hlbWE6IHsgJHJlZjogZ2V0U2NoZW1hUGF0aChNb2RlbENvbnN0cikgfSxcbiAgICAgIH0pLFxuICAgICAgQXBpQmFkUmVxdWVzdFJlc3BvbnNlKHsgZGVzY3JpcHRpb246IFwiUGF5bG9hZCB2YWxpZGF0aW9uIGZhaWxlZC5cIiB9KSxcbiAgICAgIEFwaVVucHJvY2Vzc2FibGVFbnRpdHlSZXNwb25zZSh7XG4gICAgICAgIGRlc2NyaXB0aW9uOiBcIlJlcG9zaXRvcnkgcmVqZWN0ZWQgdGhlIHByb3ZpZGVkIHBheWxvYWQuXCIsXG4gICAgICB9KSxcbiAgICBdO1xuICB9XG5cbiAgcHJpdmF0ZSBzdGF0aWMgYnVsa0NyZWF0ZURlY29yYXRvcnMoXG4gICAgTW9kZWxDb25zdHI6IE1vZGVsQ29uc3RydWN0b3I8YW55PixcbiAgICBtb2RlbENsYXp6TmFtZTogc3RyaW5nXG4gICk6IEFycmF5PCh0YXJnZXQ6IGFueSwga2V5OiBzdHJpbmcsIGRlc2M6IGFueSkgPT4gdm9pZD4ge1xuICAgIHJldHVybiBbXG4gICAgICBBcGlPcGVyYXRpb25Gcm9tTW9kZWwoTW9kZWxDb25zdHIsIFwiUE9TVFwiLCBcImJ1bGtcIiksXG4gICAgICBBcGlPcGVyYXRpb24oeyBzdW1tYXJ5OiBgQ3JlYXRlIGEgbmV3ICR7bW9kZWxDbGF6ek5hbWV9LmAgfSksXG4gICAgICBBcGlCb2R5KHtcbiAgICAgICAgZGVzY3JpcHRpb246IGBQYXlsb2FkIGZvciAke21vZGVsQ2xhenpOYW1lfWAsXG4gICAgICAgIHNjaGVtYToge1xuICAgICAgICAgIHR5cGU6IFwiYXJyYXlcIixcbiAgICAgICAgICBpdGVtczogeyAkcmVmOiBnZXRTY2hlbWFQYXRoKE1vZGVsQ29uc3RyKSB9LFxuICAgICAgICB9LFxuICAgICAgfSksXG4gICAgICBBcGlDcmVhdGVkUmVzcG9uc2Uoe1xuICAgICAgICBkZXNjcmlwdGlvbjogYCR7bW9kZWxDbGF6ek5hbWV9IGNyZWF0ZWQgc3VjY2Vzc2Z1bGx5LmAsXG4gICAgICAgIHNjaGVtYToge1xuICAgICAgICAgIHR5cGU6IFwiYXJyYXlcIixcbiAgICAgICAgICBpdGVtczogeyAkcmVmOiBnZXRTY2hlbWFQYXRoKE1vZGVsQ29uc3RyKSB9LFxuICAgICAgICB9LFxuICAgICAgfSksXG4gICAgICBBcGlCYWRSZXF1ZXN0UmVzcG9uc2UoeyBkZXNjcmlwdGlvbjogXCJQYXlsb2FkIHZhbGlkYXRpb24gZmFpbGVkLlwiIH0pLFxuICAgICAgQXBpVW5wcm9jZXNzYWJsZUVudGl0eVJlc3BvbnNlKHtcbiAgICAgICAgZGVzY3JpcHRpb246IFwiUmVwb3NpdG9yeSByZWplY3RlZCB0aGUgcHJvdmlkZWQgcGF5bG9hZC5cIixcbiAgICAgIH0pLFxuICAgIF07XG4gIH1cblxuICBwcml2YXRlIHN0YXRpYyBidWxrUmVhZERlY29yYXRvcnMoXG4gICAgTW9kZWxDb25zdHI6IE1vZGVsQ29uc3RydWN0b3I8YW55PixcbiAgICBtb2RlbENsYXp6TmFtZTogc3RyaW5nXG4gICk6IEFycmF5PCh0YXJnZXQ6IGFueSwga2V5OiBzdHJpbmcsIGRlc2M6IGFueSkgPT4gdm9pZD4ge1xuICAgIHJldHVybiBbXG4gICAgICBBcGlPcGVyYXRpb25Gcm9tTW9kZWwoTW9kZWxDb25zdHIsIFwiR0VUXCIsIFwiYnVsa1wiKSxcbiAgICAgIEFwaU9wZXJhdGlvbih7IHN1bW1hcnk6IGBSZXRyaWV2ZSAke21vZGVsQ2xhenpOYW1lfSByZWNvcmRzIGJ5IGlkcy5gIH0pLFxuICAgICAgQXBpUXVlcnkoeyBuYW1lOiBcImlkc1wiLCByZXF1aXJlZDogdHJ1ZSwgdHlwZTogXCJhcnJheVwiIH0pLFxuICAgICAgQXBpT2tSZXNwb25zZSh7XG4gICAgICAgIGRlc2NyaXB0aW9uOiBgJHttb2RlbENsYXp6TmFtZX0gcmV0cmlldmVkIHN1Y2Nlc3NmdWxseS5gLFxuICAgICAgICBzY2hlbWE6IHtcbiAgICAgICAgICB0eXBlOiBcImFycmF5XCIsXG4gICAgICAgICAgaXRlbXM6IHsgJHJlZjogZ2V0U2NoZW1hUGF0aChNb2RlbENvbnN0cikgfSxcbiAgICAgICAgfSxcbiAgICAgIH0pLFxuICAgICAgQXBpTm90Rm91bmRSZXNwb25zZSh7XG4gICAgICAgIGRlc2NyaXB0aW9uOiBgTm8gJHttb2RlbENsYXp6TmFtZX0gcmVjb3JkIG1hdGNoZXMgdGhlIHByb3ZpZGVkIGlkZW50aWZpZXIuYCxcbiAgICAgIH0pLFxuICAgIF07XG4gIH1cblxuICBwcml2YXRlIHN0YXRpYyBidWxrVXBkYXRlRGVjb3JhdG9ycyhcbiAgICBNb2RlbENvbnN0cjogTW9kZWxDb25zdHJ1Y3Rvcjxhbnk+LFxuICAgIG1vZGVsQ2xhenpOYW1lOiBzdHJpbmcsXG4gICAgYXBpUHJvcGVydGllczogRGVjYWZBcGlQcm9wZXJ0eVtdXG4gICk6IEFycmF5PCh0YXJnZXQ6IGFueSwga2V5OiBzdHJpbmcsIGRlc2M6IGFueSkgPT4gdm9pZD4ge1xuICAgIHJldHVybiBbXG4gICAgICBBcGlPcGVyYXRpb25Gcm9tTW9kZWwoTW9kZWxDb25zdHIsIFwiUFVUXCIsIFwiYnVsa1wiKSxcbiAgICAgIEFwaVBhcmFtc0Zyb21Nb2RlbChhcGlQcm9wZXJ0aWVzKSxcbiAgICAgIEFwaU9wZXJhdGlvbih7XG4gICAgICAgIHN1bW1hcnk6IGBSZXBsYWNlIGV4aXN0aW5nICR7bW9kZWxDbGF6ek5hbWV9IHJlY29yZHMgd2l0aCBuZXcgcGF5bG9hZHMuYCxcbiAgICAgIH0pLFxuICAgICAgQXBpQm9keSh7XG4gICAgICAgIGRlc2NyaXB0aW9uOiBgUGF5bG9hZCBmb3IgcmVwbGFjaW5nIGV4aXN0aW5nIHJlY29yZHMgb2YgJHttb2RlbENsYXp6TmFtZX1gLFxuICAgICAgICBzY2hlbWE6IHtcbiAgICAgICAgICB0eXBlOiBcImFycmF5XCIsXG4gICAgICAgICAgJHJlZjogZ2V0U2NoZW1hUGF0aChEdG9Gb3IoT3BlcmF0aW9uS2V5cy5VUERBVEUsIE1vZGVsQ29uc3RyKSksXG4gICAgICAgIH0sXG4gICAgICB9KSxcbiAgICAgIEFwaU9rUmVzcG9uc2Uoe1xuICAgICAgICBkZXNjcmlwdGlvbjogYCR7bW9kZWxDbGF6ek5hbWV9IHVwZGF0ZWQgc3VjY2Vzc2Z1bGx5LmAsXG4gICAgICAgIHNjaGVtYToge1xuICAgICAgICAgIHR5cGU6IFwiYXJyYXlcIixcbiAgICAgICAgICBpdGVtczogeyAkcmVmOiBnZXRTY2hlbWFQYXRoKE1vZGVsQ29uc3RyKSB9LFxuICAgICAgICB9LFxuICAgICAgfSksXG4gICAgICBBcGlOb3RGb3VuZFJlc3BvbnNlKHtcbiAgICAgICAgZGVzY3JpcHRpb246IGBObyAke21vZGVsQ2xhenpOYW1lfSByZWNvcmQgbWF0Y2hlcyB0aGUgcHJvdmlkZWQgaWRlbnRpZmllci5gLFxuICAgICAgfSksXG4gICAgICBBcGlCYWRSZXF1ZXN0UmVzcG9uc2UoeyBkZXNjcmlwdGlvbjogXCJQYXlsb2FkIHZhbGlkYXRpb24gZmFpbGVkLlwiIH0pLFxuICAgIF07XG4gIH1cblxuICBwcml2YXRlIHN0YXRpYyBidWxrRGVsZXRlRGVjb3JhdG9ycyhcbiAgICBNb2RlbENvbnN0cjogTW9kZWxDb25zdHJ1Y3Rvcjxhbnk+LFxuICAgIG1vZGVsQ2xhenpOYW1lOiBzdHJpbmcsXG4gICAgYXBpUHJvcGVydGllczogRGVjYWZBcGlQcm9wZXJ0eVtdXG4gICk6IEFycmF5PCh0YXJnZXQ6IGFueSwga2V5OiBzdHJpbmcsIGRlc2M6IGFueSkgPT4gdm9pZD4ge1xuICAgIHJldHVybiBbXG4gICAgICBBcGlPcGVyYXRpb25Gcm9tTW9kZWwoTW9kZWxDb25zdHIsIFwiREVMRVRFXCIsIFwiYnVsa1wiKSxcbiAgICAgIEFwaVBhcmFtc0Zyb21Nb2RlbChhcGlQcm9wZXJ0aWVzKSxcbiAgICAgIEFwaU9wZXJhdGlvbih7IHN1bW1hcnk6IGBEZWxldGUgJHttb2RlbENsYXp6TmFtZX0gcmVjb3JkcyBieSBpZHMuYCB9KSxcbiAgICAgIEFwaVF1ZXJ5KHsgbmFtZTogXCJpZHNcIiwgcmVxdWlyZWQ6IHRydWUsIHR5cGU6IFwiYXJyYXlcIiB9KSxcbiAgICAgIEFwaU9rUmVzcG9uc2Uoe1xuICAgICAgICBkZXNjcmlwdGlvbjogYCR7bW9kZWxDbGF6ek5hbWV9IGRlbGV0ZWQgc3VjY2Vzc2Z1bGx5LmAsXG4gICAgICAgIHNjaGVtYToge1xuICAgICAgICAgIHR5cGU6IFwiYXJyYXlcIixcbiAgICAgICAgICBpdGVtczogeyAkcmVmOiBnZXRTY2hlbWFQYXRoKE1vZGVsQ29uc3RyKSB9LFxuICAgICAgICB9LFxuICAgICAgfSksXG4gICAgICBBcGlOb3RGb3VuZFJlc3BvbnNlKHtcbiAgICAgICAgZGVzY3JpcHRpb246IGBObyAke21vZGVsQ2xhenpOYW1lfSByZWNvcmQgbWF0Y2hlcyB0aGUgcHJvdmlkZWQgaWRlbnRpZmllci5gLFxuICAgICAgfSksXG4gICAgXTtcbiAgfVxuXG4gIHByaXZhdGUgc3RhdGljIHJlYWREZWNvcmF0b3JzKFxuICAgIE1vZGVsQ29uc3RyOiBNb2RlbENvbnN0cnVjdG9yPGFueT4sXG4gICAgbW9kZWxDbGF6ek5hbWU6IHN0cmluZyxcbiAgICBhcGlQcm9wZXJ0aWVzOiBEZWNhZkFwaVByb3BlcnR5W10sXG4gICAgcGtQYXRoOiBzdHJpbmdcbiAgKTogQXJyYXk8KHRhcmdldDogYW55LCBrZXk6IHN0cmluZywgZGVzYzogYW55KSA9PiB2b2lkPiB7XG4gICAgcmV0dXJuIFtcbiAgICAgIEFwaU9wZXJhdGlvbkZyb21Nb2RlbChNb2RlbENvbnN0ciwgXCJHRVRcIiwgcGtQYXRoKSxcbiAgICAgIEFwaVBhcmFtc0Zyb21Nb2RlbChhcGlQcm9wZXJ0aWVzKSxcbiAgICAgIEFwaU9wZXJhdGlvbih7IHN1bW1hcnk6IGBSZXRyaWV2ZSBhICR7bW9kZWxDbGF6ek5hbWV9IHJlY29yZCBieSBpZC5gIH0pLFxuICAgICAgQXBpT2tSZXNwb25zZSh7XG4gICAgICAgIGRlc2NyaXB0aW9uOiBgJHttb2RlbENsYXp6TmFtZX0gcmV0cmlldmVkIHN1Y2Nlc3NmdWxseS5gLFxuICAgICAgICBzY2hlbWE6IHsgJHJlZjogZ2V0U2NoZW1hUGF0aChNb2RlbENvbnN0cikgfSxcbiAgICAgIH0pLFxuICAgICAgQXBpTm90Rm91bmRSZXNwb25zZSh7XG4gICAgICAgIGRlc2NyaXB0aW9uOiBgTm8gJHttb2RlbENsYXp6TmFtZX0gcmVjb3JkIG1hdGNoZXMgdGhlIHByb3ZpZGVkIGlkZW50aWZpZXIuYCxcbiAgICAgIH0pLFxuICAgIF07XG4gIH1cblxuICBwcml2YXRlIHN0YXRpYyB1cGRhdGVEZWNvcmF0b3JzKFxuICAgIE1vZGVsQ29uc3RyOiBNb2RlbENvbnN0cnVjdG9yPGFueT4sXG4gICAgbW9kZWxDbGF6ek5hbWU6IHN0cmluZyxcbiAgICBhcGlQcm9wZXJ0aWVzOiBEZWNhZkFwaVByb3BlcnR5W10sXG4gICAgcGtQYXRoOiBzdHJpbmdcbiAgKTogQXJyYXk8KHRhcmdldDogYW55LCBrZXk6IHN0cmluZywgZGVzYzogYW55KSA9PiB2b2lkPiB7XG4gICAgcmV0dXJuIFtcbiAgICAgIEFwaU9wZXJhdGlvbkZyb21Nb2RlbChNb2RlbENvbnN0ciwgXCJQVVRcIiwgcGtQYXRoKSxcbiAgICAgIEFwaVBhcmFtc0Zyb21Nb2RlbChhcGlQcm9wZXJ0aWVzKSxcbiAgICAgIEFwaU9wZXJhdGlvbih7XG4gICAgICAgIHN1bW1hcnk6IGBSZXBsYWNlIGFuIGV4aXN0aW5nICR7bW9kZWxDbGF6ek5hbWV9IHJlY29yZCB3aXRoIGEgbmV3IHBheWxvYWQuYCxcbiAgICAgIH0pLFxuICAgICAgQXBpQm9keSh7XG4gICAgICAgIGRlc2NyaXB0aW9uOiBgUGF5bG9hZCBmb3IgcmVwbGFjaW5nIGFuIGV4aXN0aW5nIHJlY29yZCBvZiAke21vZGVsQ2xhenpOYW1lfWAsXG4gICAgICAgIHR5cGU6IER0b0ZvcihPcGVyYXRpb25LZXlzLlVQREFURSwgTW9kZWxDb25zdHIpLFxuICAgICAgfSksXG4gICAgICBBcGlPa1Jlc3BvbnNlKHtcbiAgICAgICAgZGVzY3JpcHRpb246IGAke21vZGVsQ2xhenpOYW1lfSB1cGRhdGVkIHN1Y2Nlc3NmdWxseS5gLFxuICAgICAgICBzY2hlbWE6IHsgJHJlZjogZ2V0U2NoZW1hUGF0aChNb2RlbENvbnN0cikgfSxcbiAgICAgIH0pLFxuICAgICAgQXBpTm90Rm91bmRSZXNwb25zZSh7XG4gICAgICAgIGRlc2NyaXB0aW9uOiBgTm8gJHttb2RlbENsYXp6TmFtZX0gcmVjb3JkIG1hdGNoZXMgdGhlIHByb3ZpZGVkIGlkZW50aWZpZXIuYCxcbiAgICAgIH0pLFxuICAgICAgQXBpQmFkUmVxdWVzdFJlc3BvbnNlKHsgZGVzY3JpcHRpb246IFwiUGF5bG9hZCB2YWxpZGF0aW9uIGZhaWxlZC5cIiB9KSxcbiAgICBdO1xuICB9XG5cbiAgcHJpdmF0ZSBzdGF0aWMgZGVsZXRlRGVjb3JhdG9ycyhcbiAgICBNb2RlbENvbnN0cjogTW9kZWxDb25zdHJ1Y3Rvcjxhbnk+LFxuICAgIG1vZGVsQ2xhenpOYW1lOiBzdHJpbmcsXG4gICAgYXBpUHJvcGVydGllczogRGVjYWZBcGlQcm9wZXJ0eVtdLFxuICAgIHBrUGF0aDogc3RyaW5nXG4gICk6IEFycmF5PCh0YXJnZXQ6IGFueSwga2V5OiBzdHJpbmcsIGRlc2M6IGFueSkgPT4gdm9pZD4ge1xuICAgIHJldHVybiBbXG4gICAgICBBcGlPcGVyYXRpb25Gcm9tTW9kZWwoTW9kZWxDb25zdHIsIFwiREVMRVRFXCIsIHBrUGF0aCksXG4gICAgICBBcGlQYXJhbXNGcm9tTW9kZWwoYXBpUHJvcGVydGllcyksXG4gICAgICBBcGlPcGVyYXRpb24oeyBzdW1tYXJ5OiBgRGVsZXRlIGEgJHttb2RlbENsYXp6TmFtZX0gcmVjb3JkIGJ5IGlkLmAgfSksXG4gICAgICBBcGlPa1Jlc3BvbnNlKHtcbiAgICAgICAgZGVzY3JpcHRpb246IGAke21vZGVsQ2xhenpOYW1lfSBkZWxldGVkIHN1Y2Nlc3NmdWxseS5gLFxuICAgICAgICBzY2hlbWE6IHsgJHJlZjogZ2V0U2NoZW1hUGF0aChNb2RlbENvbnN0cikgfSxcbiAgICAgIH0pLFxuICAgICAgQXBpTm90Rm91bmRSZXNwb25zZSh7XG4gICAgICAgIGRlc2NyaXB0aW9uOiBgTm8gJHttb2RlbENsYXp6TmFtZX0gcmVjb3JkIG1hdGNoZXMgdGhlIHByb3ZpZGVkIGlkZW50aWZpZXIuYCxcbiAgICAgIH0pLFxuICAgIF07XG4gIH1cblxuICBwcml2YXRlIHN0YXRpYyBzdGF0ZW1lbnREZWNvcmF0b3JzKFxuICAgIE1vZGVsQ29uc3RyOiBNb2RlbENvbnN0cnVjdG9yPGFueT4sXG4gICAgbW9kZWxDbGF6ek5hbWU6IHN0cmluZ1xuICApOiBBcnJheTwodGFyZ2V0OiBhbnksIGtleTogc3RyaW5nLCBkZXNjOiBhbnkpID0+IHZvaWQ+IHtcbiAgICByZXR1cm4gW1xuICAgICAgQXBpT3BlcmF0aW9uRnJvbU1vZGVsKE1vZGVsQ29uc3RyLCBcIkdFVFwiLCBcInN0YXRlbWVudC86bWV0aG9kLyphcmdzXCIpLFxuICAgICAgQXBpT3BlcmF0aW9uKHtcbiAgICAgICAgc3VtbWFyeTogYEV4ZWN1dGVzIGEgcHJlcGFyZWQgc3RhdGVtZW50IG9uICR7bW9kZWxDbGF6ek5hbWV9LmAsXG4gICAgICB9KSxcbiAgICAgIEFwaVBhcmFtKHsgbmFtZTogXCJtZXRob2RcIiwgZGVzY3JpcHRpb246IFwidGhlIHByZXBhcmVkIHN0YXRlbWVudCB0byBleGVjdXRlXCIgfSksXG4gICAgICBBcGlQYXJhbSh7XG4gICAgICAgIG5hbWU6IFwiYXJnc1wiLFxuICAgICAgICBkZXNjcmlwdGlvbjogXCJjb25jYXRlbmF0ZWQgbGlzdCBvZiBhcmd1bWVudHMgdGhlIHByZXBhcmVkIHN0YXRlbWVudCBjYW4gYWNjZXB0XCIsXG4gICAgICB9KSxcbiAgICAgIEFwaVF1ZXJ5KHtcbiAgICAgICAgbmFtZTogXCJkaXJlY3Rpb25cIixcbiAgICAgICAgcmVxdWlyZWQ6IHRydWUsXG4gICAgICAgIGVudW06IE9yZGVyRGlyZWN0aW9uLFxuICAgICAgICBkZXNjcmlwdGlvbjogXCJ0aGUgc29ydCBvcmRlciB3aGVuIGFwcGxpY2FibGVcIixcbiAgICAgIH0pLFxuICAgICAgQXBpUXVlcnkoeyBuYW1lOiBcImxpbWl0XCIsIHJlcXVpcmVkOiB0cnVlLCBkZXNjcmlwdGlvbjogXCJsaW1pdCBvciBwYWdlIHNpemUgd2hlbiBhcHBsaWNhYmxlXCIgfSksXG4gICAgICBBcGlRdWVyeSh7IG5hbWU6IFwib2Zmc2V0XCIsIHJlcXVpcmVkOiB0cnVlLCBkZXNjcmlwdGlvbjogXCJvZmZzZXQgb3IgYm9va21hcmsgd2hlbiBhcHBsaWNhYmxlXCIgfSksXG4gICAgICBBcGlPa1Jlc3BvbnNlKHsgZGVzY3JpcHRpb246IGAke21vZGVsQ2xhenpOYW1lfSBsaXN0ZWQgZm91bmQuYCB9KSxcbiAgICAgIEFwaU5vdEZvdW5kUmVzcG9uc2Uoe1xuICAgICAgICBkZXNjcmlwdGlvbjogYE5vICR7bW9kZWxDbGF6ek5hbWV9IHJlY29yZCBtYXRjaGVzIHRoZSBwcm92aWRlZCBpZGVudGlmaWVyLmAsXG4gICAgICB9KSxcbiAgICBdO1xuICB9XG5cbiAgcHJpdmF0ZSBzdGF0aWMgc3RhdGVtZW50U2hvcnRjdXREZWNvcmF0b3JzKFxuICAgIE1vZGVsQ29uc3RyOiBNb2RlbENvbnN0cnVjdG9yPGFueT4sXG4gICAgbW9kZWxDbGF6ek5hbWU6IHN0cmluZyxcbiAgICBwYXRoOiBzdHJpbmcsXG4gICAgc3RhdGVtZW50S2V5OiBzdHJpbmdcbiAgKTogQXJyYXk8KHRhcmdldDogYW55LCBrZXk6IHN0cmluZywgZGVzYzogYW55KSA9PiB2b2lkPiB7XG4gICAgY29uc3QgYmFzZTogQXJyYXk8KHRhcmdldDogYW55LCBrZXk6IHN0cmluZywgZGVzYzogYW55KSA9PiB2b2lkPiA9IFtcbiAgICAgIEFwaU9wZXJhdGlvbkZyb21Nb2RlbChNb2RlbENvbnN0ciwgXCJHRVRcIiwgcGF0aCksXG4gICAgICBBcGlPcGVyYXRpb24oeyBzdW1tYXJ5OiBgUmV0cmlldmUgJHttb2RlbENsYXp6TmFtZX0gcmVjb3Jkcy5gIH0pLFxuICAgICAgQXBpT2tSZXNwb25zZSh7IGRlc2NyaXB0aW9uOiBgJHttb2RlbENsYXp6TmFtZX0gcmV0cmlldmVkIHN1Y2Nlc3NmdWxseS5gIH0pLFxuICAgIF07XG5cbiAgICBjb25zdCBzZWdtZW50cyA9IHBhdGguc3BsaXQoXCIvXCIpLmZpbHRlcigocykgPT4gcy5zdGFydHNXaXRoKFwiOlwiKSk7XG4gICAgc2VnbWVudHMuZm9yRWFjaCgoc2VnKSA9PiB7XG4gICAgICBjb25zdCBuYW1lID0gc2VnLnJlcGxhY2UoXCI6XCIsIFwiXCIpO1xuICAgICAgYmFzZS5wdXNoKEFwaVBhcmFtKHsgbmFtZSwgZGVzY3JpcHRpb246IGBUaGUgJHtuYW1lfSBwYXJhbWV0ZXJgIH0pKTtcbiAgICB9KTtcblxuICAgIGlmIChcbiAgICAgIHBhdGguc3RhcnRzV2l0aChcImxpc3RCeS9cIikgfHxcbiAgICAgIHBhdGguc3RhcnRzV2l0aChcInBhZ2luYXRlQnkvXCIpIHx8XG4gICAgICBwYXRoLnN0YXJ0c1dpdGgoXCJmaW5kL1wiKSB8fFxuICAgICAgcGF0aC5zdGFydHNXaXRoKFwicGFnZS9cIilcbiAgICApIHtcbiAgICAgIGJhc2UucHVzaChcbiAgICAgICAgQXBpUXVlcnkoe1xuICAgICAgICAgIG5hbWU6IFwiZGlyZWN0aW9uXCIsXG4gICAgICAgICAgcmVxdWlyZWQ6IHRydWUsXG4gICAgICAgICAgZW51bTogT3JkZXJEaXJlY3Rpb24sXG4gICAgICAgICAgZGVzY3JpcHRpb246IFwidGhlIHNvcnQgb3JkZXJcIixcbiAgICAgICAgfSlcbiAgICAgICk7XG4gICAgfVxuICAgIGlmIChwYXRoLnN0YXJ0c1dpdGgoXCJwYWdpbmF0ZUJ5L1wiKSB8fCBwYXRoLnN0YXJ0c1dpdGgoXCJwYWdlL1wiKSkge1xuICAgICAgYmFzZS5wdXNoKFxuICAgICAgICBBcGlRdWVyeSh7IG5hbWU6IFwibGltaXRcIiwgcmVxdWlyZWQ6IGZhbHNlLCBkZXNjcmlwdGlvbjogXCJwYWdlIHNpemVcIiB9KSxcbiAgICAgICAgQXBpUXVlcnkoeyBuYW1lOiBcIm9mZnNldFwiLCByZXF1aXJlZDogZmFsc2UsIGRlc2NyaXB0aW9uOiBcInBhZ2UgbnVtYmVyXCIgfSksXG4gICAgICAgIEFwaVF1ZXJ5KHsgbmFtZTogXCJib29rbWFya1wiLCByZXF1aXJlZDogZmFsc2UsIGRlc2NyaXB0aW9uOiBcImJvb2ttYXJrIGZvciBjdXJzb3IgcGFnaW5hdGlvblwiIH0pXG4gICAgICApO1xuICAgIH1cblxuICAgIGlmIChwYXRoLnN0YXJ0c1dpdGgoXCJmaW5kT25lQnkvXCIpIHx8IHBhdGguc3RhcnRzV2l0aChcImZpbmRCeS9cIikpIHtcbiAgICAgIGJhc2UucHVzaChcbiAgICAgICAgQXBpTm90Rm91bmRSZXNwb25zZSh7XG4gICAgICAgICAgZGVzY3JpcHRpb246IGBObyAke21vZGVsQ2xhenpOYW1lfSByZWNvcmQgbWF0Y2hlcyB0aGUgcHJvdmlkZWQgaWRlbnRpZmllci5gLFxuICAgICAgICB9KVxuICAgICAgKTtcbiAgICB9XG5cbiAgICBpZiAoXG4gICAgICBzdGF0ZW1lbnRLZXkgPT09IFByZXBhcmVkU3RhdGVtZW50S2V5cy5DT1VOVF9PRiB8fFxuICAgICAgc3RhdGVtZW50S2V5ID09PSBQcmVwYXJlZFN0YXRlbWVudEtleXMuQVZHX09GIHx8XG4gICAgICBzdGF0ZW1lbnRLZXkgPT09IFByZXBhcmVkU3RhdGVtZW50S2V5cy5TVU1fT0ZcbiAgICApIHtcbiAgICAgIGJhc2UucHVzaChBcGlPa1Jlc3BvbnNlKHsgZGVzY3JpcHRpb246IGBSZXN1bHQgZm9yICR7bW9kZWxDbGF6ek5hbWV9LmAsIHR5cGU6IE51bWJlciB9KSk7XG4gICAgfVxuICAgIGlmIChzdGF0ZW1lbnRLZXkgPT09IFByZXBhcmVkU3RhdGVtZW50S2V5cy5ESVNUSU5DVF9PRikge1xuICAgICAgYmFzZS5wdXNoKEFwaU9rUmVzcG9uc2UoeyBkZXNjcmlwdGlvbjogYERpc3RpbmN0IHZhbHVlcyBmb3IgJHttb2RlbENsYXp6TmFtZX0uYCwgdHlwZTogW1N0cmluZ10gfSkpO1xuICAgIH1cblxuICAgIHJldHVybiBiYXNlO1xuICB9XG5cbiAgcHJpdmF0ZSBzdGF0aWMgZ2V0UXVlcnlEZWNvcmF0b3JzKFxuICAgIG1ldGhvZE5hbWU6IHN0cmluZyxcbiAgICByb3V0ZVBhdGg6IHN0cmluZyxcbiAgICBodHRwVmVyYjogc3RyaW5nLFxuICAgIGluY2x1ZGVRdWVyeVBhcmFtczogYm9vbGVhbiA9IGZhbHNlXG4gICk6IEFycmF5PCh0YXJnZXQ6IGFueSwga2V5OiBzdHJpbmcsIGRlc2M6IGFueSkgPT4gdm9pZD4ge1xuICAgIGNvbnN0IGV4dHJhY3RQYXRoUGFyYW1zID0gKHA6IHN0cmluZyk6IHN0cmluZ1tdID0+XG4gICAgICBwLnNwbGl0KFwiL1wiKS5maWx0ZXIoKHMpID0+IHMuc3RhcnRzV2l0aChcIjpcIikpLm1hcCgocykgPT4gcy5zbGljZSgxKSk7XG5cbiAgICBjb25zdCBhcGlQYXRoUGFyYW1zID0gZXh0cmFjdFBhdGhQYXJhbXMocm91dGVQYXRoKS5tYXAoKG5hbWUpID0+ICh7XG4gICAgICBuYW1lLFxuICAgICAgZGVzY3JpcHRpb246IGAke25hbWV9IHBhcmFtZXRlciBmb3IgdGhlIHF1ZXJ5YCxcbiAgICAgIHJlcXVpcmVkOiB0cnVlLFxuICAgICAgdHlwZTogU3RyaW5nLFxuICAgIH0pKTtcblxuICAgIGNvbnN0IGRlY29yYXRvcnM6IEFycmF5PCh0YXJnZXQ6IGFueSwga2V5OiBzdHJpbmcsIGRlc2M6IGFueSkgPT4gdm9pZD4gPSBbXG4gICAgICAuLi5hcGlQYXRoUGFyYW1zLm1hcCgocCkgPT4gQXBpUGFyYW0ocCkpLFxuICAgICAgQXBpT3BlcmF0aW9uKHsgc3VtbWFyeTogYFJldHJpZXZlIHJlY29yZHMgdXNpbmcgXCIke21ldGhvZE5hbWV9XCIuYCB9KSxcbiAgICAgIEFwaU9rUmVzcG9uc2UoeyBkZXNjcmlwdGlvbjogXCJSZXN1bHQgc3VjY2Vzc2Z1bGx5IHJldHJpZXZlZC5cIiB9KSxcbiAgICAgIEFwaU5vQ29udGVudFJlc3BvbnNlKHsgZGVzY3JpcHRpb246IFwiTm8gY29udGVudCByZXR1cm5lZCBieSB0aGUgbWV0aG9kLlwiIH0pLFxuICAgIF07XG5cbiAgICBpZiAoaHR0cFZlcmIgPT09IFwiR0VUXCIgJiYgaW5jbHVkZVF1ZXJ5UGFyYW1zKSB7XG4gICAgICBkZWNvcmF0b3JzLnB1c2goXG4gICAgICAgIEFwaVF1ZXJ5KHtcbiAgICAgICAgICBuYW1lOiBcImRpcmVjdGlvblwiLFxuICAgICAgICAgIHJlcXVpcmVkOiBmYWxzZSxcbiAgICAgICAgICBlbnVtOiBPcmRlckRpcmVjdGlvbixcbiAgICAgICAgICBkZXNjcmlwdGlvbjogXCJ0aGUgc29ydCBvcmRlciB3aGVuIGFwcGxpY2FibGVcIixcbiAgICAgICAgfSksXG4gICAgICAgIEFwaVF1ZXJ5KHsgbmFtZTogXCJsaW1pdFwiLCByZXF1aXJlZDogZmFsc2UsIGRlc2NyaXB0aW9uOiBcImxpbWl0IG9yIHBhZ2Ugc2l6ZVwiIH0pLFxuICAgICAgICBBcGlRdWVyeSh7IG5hbWU6IFwib2Zmc2V0XCIsIHJlcXVpcmVkOiBmYWxzZSwgZGVzY3JpcHRpb246IFwib2Zmc2V0IG9yIGJvb2ttYXJrXCIgfSlcbiAgICAgICk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGRlY29yYXRvcnM7XG4gIH1cbn1cbiIsImltcG9ydCB7IER5bmFtaWNNb2R1bGUsIE1vZHVsZSwgUHJvdmlkZXIgfSBmcm9tIFwiQG5lc3Rqcy9jb21tb25cIjtcbmltcG9ydCB7IEFkYXB0ZXIsIE1vZGVsU2VydmljZSB9IGZyb20gXCJAZGVjYWYtdHMvY29yZVwiO1xuaW1wb3J0IHsgTG9nZ2luZyB9IGZyb20gXCJAZGVjYWYtdHMvbG9nZ2luZ1wiO1xuaW1wb3J0IHsgRnJvbU1vZGVsQ29udHJvbGxlciB9IGZyb20gXCIuL0Zyb21Nb2RlbENvbnRyb2xsZXJcIjtcbmltcG9ydCB7IERlY2FmTW9kdWxlT3B0aW9ucyB9IGZyb20gXCIuLi90eXBlc1wiO1xuaW1wb3J0IHsgTW9kZWwsIE1vZGVsQ29uc3RydWN0b3IgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRvci12YWxpZGF0aW9uXCI7XG5pbXBvcnQgeyBNZXRhZGF0YSB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdGlvblwiO1xuaW1wb3J0IHsgREVDQUZfRVhQT1NFIH0gZnJvbSBcIi4uL2NvbnN0YW50c1wiO1xuaW1wb3J0IHR5cGUgeyBNb2RlbENvbnRyb2xsZXJGYWN0b3J5Q29uZmlnIH0gZnJvbSBcIkBkZWNhZi10cy9mb3ItaHR0cC9zZXJ2ZXJcIjtcblxuZXhwb3J0IGZ1bmN0aW9uIGdldE1vZHVsZUZvcihmbGF2b3VyOiBzdHJpbmcpIHtcbiAgQE1vZHVsZSh7fSlcbiAgY2xhc3MgRGVjYWZNb2RlbE1vZHVsZSB7XG4gICAgc3RhdGljIHJlYWRvbmx5IGxvZyA9IExvZ2dpbmcuZm9yKERlY2FmTW9kZWxNb2R1bGUubmFtZSkuZm9yKGZsYXZvdXIpO1xuXG4gICAgc3RhdGljIGNyZWF0ZU1vZGVsU2VydmljZXM8VCBleHRlbmRzIE1vZGVsPGJvb2xlYW4+PihcbiAgICAgIG1vZGVsczogTW9kZWxDb25zdHJ1Y3RvcjxUPltdXG4gICAgKTogUHJvdmlkZXJbXSB7XG4gICAgICByZXR1cm4gbW9kZWxzLm1hcCgobW9kZWwpID0+ICh7XG4gICAgICAgIHByb3ZpZGU6IGAke21vZGVsLm5hbWV9U2VydmljZWAsXG4gICAgICAgIHVzZUZhY3Rvcnk6ICgpID0+IE1vZGVsU2VydmljZS5mb3JNb2RlbChtb2RlbCBhcyBhbnkpLFxuICAgICAgfSkpO1xuICAgIH1cblxuICAgIHN0YXRpYyBpc0V4cG9zZWQoXG4gICAgICBtb2RlbDogTW9kZWxDb25zdHJ1Y3Rvcjxhbnk+LFxuICAgICAgZXhwb3N1cmU/OiBSZWNvcmQ8c3RyaW5nLCBib29sZWFuIHwgc3RyaW5nW10+XG4gICAgKTogYm9vbGVhbiB7XG4gICAgICBjb25zdCBvdmVycmlkZSA9IGV4cG9zdXJlPy5bbW9kZWwubmFtZV07XG4gICAgICBjb25zdCB2YWx1ZSA9XG4gICAgICAgIHR5cGVvZiBvdmVycmlkZSAhPT0gXCJ1bmRlZmluZWRcIlxuICAgICAgICAgID8gb3ZlcnJpZGVcbiAgICAgICAgICA6IE1ldGFkYXRhLmdldChtb2RlbCwgTWV0YWRhdGEua2V5KERFQ0FGX0VYUE9TRSkpO1xuXG4gICAgICBpZiAodHlwZW9mIHZhbHVlID09PSBcInVuZGVmaW5lZFwiKSByZXR1cm4gdHJ1ZTtcbiAgICAgIGlmICh2YWx1ZSA9PT0gdHJ1ZSkgcmV0dXJuIHRydWU7XG4gICAgICBpZiAoQXJyYXkuaXNBcnJheSh2YWx1ZSkpIHJldHVybiB2YWx1ZS5pbmNsdWRlcyhmbGF2b3VyKTtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBzdGF0aWMgZm9yUm9vdChcbiAgICAgIGZsYXZvdXI6IHN0cmluZyxcbiAgICAgIG9wdGlvbnM6IFBhcnRpYWw8RGVjYWZNb2R1bGVPcHRpb25zPiA9IHt9XG4gICAgKTogRHluYW1pY01vZHVsZSB7XG4gICAgICBjb25zdCBsb2cgPSB0aGlzLmxvZy5mb3IodGhpcy5mb3JSb290KTtcbiAgICAgIGxvZy5pbmZvKGBHZW5lcmF0aW5nIGNvbnRyb2xsZXJzIGZvciBmbGF2b3VyLi4uYCk7XG5cbiAgICAgIGNvbnN0IHRyYWNrZWRNb2RlbHMgPSBBZGFwdGVyLm1vZGVscyhmbGF2b3VyKS5maWx0ZXIoKG1vZGVsKSA9PlxuICAgICAgICB0aGlzLmlzRXhwb3NlZChtb2RlbCwgb3B0aW9ucy5jb250cm9sbGVyRXhwb3N1cmUpXG4gICAgICApO1xuXG4gICAgICBsZXQgbW9kZWxTZXJ2aWNlczogUHJvdmlkZXJbXSA9IFtdO1xuICAgICAgaWYgKG9wdGlvbnMuYXV0b1NlcnZpY2VzKSB7XG4gICAgICAgIGxvZy5pbmZvKFwiQXV0by1zZXJ2aWNlcyBlbmFibGVkLiBJbml0aWFsaXppbmcgc2VydmljZSBnZW5lcmF0aW9uLlwiKTtcbiAgICAgICAgbW9kZWxTZXJ2aWNlcyA9IHRoaXMuY3JlYXRlTW9kZWxTZXJ2aWNlcyh0cmFja2VkTW9kZWxzKTtcbiAgICAgICAgbG9nLmluZm8oXG4gICAgICAgICAgYEF1dG8tc2VydmljZXMgY29tcGxldGVkLiAke21vZGVsU2VydmljZXMubGVuZ3RofSBzZXJ2aWNlcyBpbml0aWFsaXplZC5gXG4gICAgICAgICk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGdsb2JhbERlZmF1bHRzOiBQYXJ0aWFsPE1vZGVsQ29udHJvbGxlckZhY3RvcnlDb25maWc+ID0ge307XG4gICAgICBpZiAob3B0aW9ucy5hZ2dyZWdhdGlvbnMgPT09IGZhbHNlKSB7XG4gICAgICAgIGdsb2JhbERlZmF1bHRzLmFsbG93R3JvdXBpbmdRdWVyaWVzID0gZmFsc2U7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGNvbnRyb2xsZXJzID0gdHJhY2tlZE1vZGVscy5tYXAoKG1vZGVsKSA9PlxuICAgICAgICBGcm9tTW9kZWxDb250cm9sbGVyLmNyZWF0ZShtb2RlbCwgb3B0aW9ucy5jb250cm9sbGVyQ29uZmlnLCBnbG9iYWxEZWZhdWx0cylcbiAgICAgICk7XG4gICAgICBsb2cuaW5mbyhgR2VuZXJhdGVkICR7Y29udHJvbGxlcnMubGVuZ3RofSBjb250cm9sbGVyc2ApO1xuXG4gICAgICByZXR1cm4ge1xuICAgICAgICBtb2R1bGU6IERlY2FmTW9kZWxNb2R1bGUsXG4gICAgICAgIGNvbnRyb2xsZXJzLFxuICAgICAgICBwcm92aWRlcnM6IFtcbiAgICAgICAgICAuLi5tb2RlbFNlcnZpY2VzLFxuICAgICAgICBdLFxuICAgICAgfTtcbiAgICB9XG4gIH1cbiAgT2JqZWN0LmFzc2lnbihEZWNhZk1vZGVsTW9kdWxlLCBcIm5hbWVcIiwge1xuICAgIHZhbHVlOiBgRGVjYWZNb2R1bGUke2ZsYXZvdXJ9YCxcbiAgfSk7XG4gIHJldHVybiBEZWNhZk1vZGVsTW9kdWxlO1xufVxuIiwiaW1wb3J0IHtcbiAgRGVmYXVsdEluamVjdGFibGVzQ29uZmlnLFxuICBJbmplY3RhYmxlQ29uZmlnLFxuICBJbmplY3RhYmxlc0tleXMsXG4gIEluamVjdE9wdGlvbnMsXG59IGZyb20gXCJAZGVjYWYtdHMvaW5qZWN0YWJsZS1kZWNvcmF0b3JzXCI7XG5pbXBvcnQgeyBJbmplY3QsIEluamVjdGFibGUsIFNjb3BlIH0gZnJvbSBcIkBuZXN0anMvY29tbW9uXCI7XG5pbXBvcnQgeyBDb25zdHJ1Y3RvciwgRGVjb3JhdGlvbiwgRGVjb3JhdGlvbktleXMgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRpb25cIjtcbmltcG9ydCB7IFZhbGlkYXRpb25LZXlzIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0b3ItdmFsaWRhdGlvblwiO1xuaW1wb3J0IHsgUGVyc2lzdGVuY2VLZXlzIH0gZnJvbSBcIkBkZWNhZi10cy9jb3JlXCI7XG5pbXBvcnQgeyBBcGlQcm9wZXJ0eSB9IGZyb20gXCIuL292ZXJyaWRlcy9kZWNvcmF0aW9uXCI7XG5pbXBvcnQgeyBBdXRoIH0gZnJvbSBcIi4vZGVjYWYtbW9kZWxcIjtcblxuRGVjb3JhdGlvbi5mb3IoSW5qZWN0YWJsZXNLZXlzLklOSkVDVEFCTEUpXG4gIC5leHRlbmQoe1xuICAgIGRlY29yYXRvcjogZnVuY3Rpb24gbmVzdEluamVjdGFibGUoXG4gICAgICBjYXRlZ29yeTogc3RyaW5nIHwgQ29uc3RydWN0b3IsXG4gICAgICBjZmc/OiBJbmplY3RhYmxlQ29uZmlnXG4gICAgKSB7XG4gICAgICBjZmcgPVxuICAgICAgICBjZmcgfHxcbiAgICAgICAgKHR5cGVvZiBjYXRlZ29yeSA9PT0gXCJvYmplY3RcIlxuICAgICAgICAgID8gT2JqZWN0LmFzc2lnbihcbiAgICAgICAgICAgICAgY2F0ZWdvcnkgYXMgUmVjb3JkPGFueSwgYW55PixcbiAgICAgICAgICAgICAgRGVmYXVsdEluamVjdGFibGVzQ29uZmlnXG4gICAgICAgICAgICApXG4gICAgICAgICAgOiBEZWZhdWx0SW5qZWN0YWJsZXNDb25maWcpO1xuICAgICAgcmV0dXJuIEluamVjdGFibGUoe1xuICAgICAgICBzY29wZTogY2ZnLnNpbmdsZXRvbiA/IFNjb3BlLkRFRkFVTFQgOiBTY29wZS5SRVFVRVNULFxuICAgICAgICBkdXJhYmxlOiBjZmcuc2luZ2xldG9uID8gdW5kZWZpbmVkIDogdHJ1ZSxcbiAgICAgIH0pO1xuICAgIH0sXG4gIH0pXG4gIC5hcHBseSgpO1xuXG5EZWNvcmF0aW9uLmZvcihJbmplY3RhYmxlc0tleXMuSU5KRUNUKVxuICAuZXh0ZW5kKHtcbiAgICBkZWNvcmF0b3I6IGZ1bmN0aW9uIG5lc3RJbmplY3QoXG4gICAgICBjYXRlZ29yeTogc3ltYm9sIHwgc3RyaW5nIHwgQ29uc3RydWN0b3IsXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVudXNlZC12YXJzXG4gICAgICBjZmc6IEluamVjdE9wdGlvbnNcbiAgICApIHtcbiAgICAgIHJldHVybiBmdW5jdGlvbiBpbm5lck5lc3RJbmplY3QoXG4gICAgICAgIHRhcmdldDogb2JqZWN0LFxuICAgICAgICBwcm9wZXJ0eUtleT86IGFueSxcbiAgICAgICAgZGVzY3JpcHRvcj86IGFueVxuICAgICAgKSB7XG4gICAgICAgIHJldHVybiBJbmplY3QoY2F0ZWdvcnkgfHwgKHRhcmdldCBhcyBDb25zdHJ1Y3RvcikpKFxuICAgICAgICAgIHRhcmdldCxcbiAgICAgICAgICBwcm9wZXJ0eUtleSxcbiAgICAgICAgICBkZXNjcmlwdG9yXG4gICAgICAgICk7XG4gICAgICB9O1xuICAgIH0sXG4gIH0pXG4gIC5hcHBseSgpO1xuXG5EZWNvcmF0aW9uLmZvcihWYWxpZGF0aW9uS2V5cy5SRVFVSVJFRClcbiAgLmV4dGVuZChcbiAgICBBcGlQcm9wZXJ0eSh7XG4gICAgICByZXF1aXJlZDogdHJ1ZSxcbiAgICB9KVxuICApXG4gIC5hcHBseSgpO1xuXG5EZWNvcmF0aW9uLmZvcihWYWxpZGF0aW9uS2V5cy5NQVgpXG4gIC5leHRlbmQoe1xuICAgIGRlY29yYXRvcjogZnVuY3Rpb24gbWF4RGVjKG1heDogbnVtYmVyKSB7XG4gICAgICByZXR1cm4gQXBpUHJvcGVydHkoeyBtYXhpbXVtOiBtYXgsIHJlcXVpcmVkOiBmYWxzZSB9KTtcbiAgICB9LFxuICB9KVxuICAuYXBwbHkoKTtcblxuRGVjb3JhdGlvbi5mb3IoVmFsaWRhdGlvbktleXMuTUlOKVxuICAuZXh0ZW5kKHtcbiAgICBkZWNvcmF0b3I6IGZ1bmN0aW9uIG1pbkRlYyhtaW46IG51bWJlcikge1xuICAgICAgcmV0dXJuIEFwaVByb3BlcnR5KHsgbWluaW11bTogbWluLCByZXF1aXJlZDogZmFsc2UgfSk7XG4gICAgfSxcbiAgfSlcbiAgLmFwcGx5KCk7XG5cbkRlY29yYXRpb24uZm9yKFZhbGlkYXRpb25LZXlzLk1BWF9MRU5HVEgpXG4gIC5leHRlbmQoe1xuICAgIGRlY29yYXRvcjogZnVuY3Rpb24gbWF4TGVuZ3RoRGVjKG1heDogbnVtYmVyKSB7XG4gICAgICByZXR1cm4gQXBpUHJvcGVydHkoeyBtYXhMZW5ndGg6IG1heCwgcmVxdWlyZWQ6IGZhbHNlIH0pO1xuICAgIH0sXG4gIH0pXG4gIC5hcHBseSgpO1xuXG5EZWNvcmF0aW9uLmZvcihWYWxpZGF0aW9uS2V5cy5NSU5fTEVOR1RIKVxuICAuZXh0ZW5kKHtcbiAgICBkZWNvcmF0b3I6IGZ1bmN0aW9uIG1pbkxlbmd0aERlYyhtaW46IG51bWJlcikge1xuICAgICAgcmV0dXJuIEFwaVByb3BlcnR5KHsgbWluTGVuZ3RoOiBtaW4sIHJlcXVpcmVkOiBmYWxzZSB9KTtcbiAgICB9LFxuICB9KVxuICAuYXBwbHkoKTtcblxuRGVjb3JhdGlvbi5mb3IoVmFsaWRhdGlvbktleXMuVFlQRSlcbiAgLmV4dGVuZCh7XG4gICAgZGVjb3JhdG9yOiBmdW5jdGlvbiB0eXBlRGVjKFxuICAgICAgdHlwZTpcbiAgICAgICAgfCAoQ29uc3RydWN0b3IgfCAoKCkgPT4gQ29uc3RydWN0b3IpKVtdXG4gICAgICAgIHwgQ29uc3RydWN0b3JcbiAgICAgICAgfCAoKCkgPT4gQ29uc3RydWN0b3IpXG4gICAgKSB7XG4gICAgICByZXR1cm4gKHRhcmdldDogb2JqZWN0LCBwcm9wOiBhbnkpID0+IHtcbiAgICAgICAgdHlwZSA9IEFycmF5LmlzQXJyYXkodHlwZSkgPyB0eXBlWzBdIDogdHlwZTtcbiAgICAgICAgaWYgKHR5cGVvZiB0eXBlID09PSBcImZ1bmN0aW9uXCIgJiYgIXR5cGUubmFtZSlcbiAgICAgICAgICB0eXBlID0gKHR5cGUgYXMgKCkgPT4gQ29uc3RydWN0b3IpKCk7XG4gICAgICAgIHJldHVybiBBcGlQcm9wZXJ0eSh7XG4gICAgICAgICAgdHlwZTogdHlwZSBhcyBhbnksXG4gICAgICAgICAgcmVxdWlyZWQ6IGZhbHNlLFxuICAgICAgICB9KSh0YXJnZXQsIHByb3ApO1xuICAgICAgfTtcbiAgICB9LFxuICB9KVxuICAuYXBwbHkoKTtcbi8vXG4vLyBEZWNvcmF0aW9uLmZvcihWYWxpZGF0aW9uS2V5cy5MSVNUKVxuLy8gICAuZXh0ZW5kKHtcbi8vICAgICBkZWNvcmF0b3I6IGZ1bmN0aW9uIGxpc3REZWMoXG4vLyAgICAgICBjbGF6ejpcbi8vICAgICAgICAgfCBDb25zdHJ1Y3RvclxuLy8gICAgICAgICB8ICgoKSA9PiBDb25zdHJ1Y3Rvcilcbi8vICAgICAgICAgfCAoQ29uc3RydWN0b3IgfCAoKCkgPT4gQ29uc3RydWN0b3IpKVtdLFxuLy8gICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnVzZWQtdmFyc1xuLy8gICAgICAgY29sbGVjdGlvbjogXCJBcnJheVwiIHwgXCJTZXRcIiA9IFwiQXJyYXlcIlxuLy8gICAgICkge1xuLy8gICAgICAgcmV0dXJuICh0YXJnZXQ6IG9iamVjdCwgcHJvcDogYW55KSA9PiB7XG4vLyAgICAgICAgIGNsYXp6ID0gQXJyYXkuaXNBcnJheShjbGF6eikgPyBjbGF6elswXSA6IGNsYXp6O1xuLy8gICAgICAgICBpZiAodHlwZW9mIGNsYXp6ID09PSBcImZ1bmN0aW9uXCIgJiYgIWNsYXp6Lm5hbWUpXG4vLyAgICAgICAgICAgY2xhenogPSAoY2xhenogYXMgKCkgPT4gQ29uc3RydWN0b3IpKCk7XG4vLyAgICAgICAgIHJldHVybiBBcGlQcm9wZXJ0eSh7IHR5cGU6IFtjbGF6eiBhcyBhbnldIH0pKHRhcmdldCwgcHJvcCk7XG4vLyAgICAgICB9O1xuLy8gICAgIH0sXG4vLyAgIH0pXG4vLyAgIC5hcHBseSgpO1xuLy8gLy9cbkRlY29yYXRpb24uZm9yKFZhbGlkYXRpb25LZXlzLkRBVEUpXG4gIC5leHRlbmQoe1xuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnNcbiAgICBkZWNvcmF0b3I6IGZ1bmN0aW9uIGRhdGVEZWMoZm9ybWF0OiBzdHJpbmcpIHtcbiAgICAgIHJldHVybiBBcGlQcm9wZXJ0eSh7XG4gICAgICAgIHR5cGU6IFN0cmluZyxcbiAgICAgICAgZm9ybWF0OiBcImRhdGUtdGltZVwiLFxuICAgICAgICByZXF1aXJlZDogZmFsc2UsXG4gICAgICAgIC8vIGV4YW1wbGU6IHBhcnNlRGF0ZShmb3JtYXQsIG5ldyBEYXRlKCkpLFxuICAgICAgfSk7XG4gICAgfSxcbiAgfSlcbiAgLmFwcGx5KCk7XG5cbkRlY29yYXRpb24uZm9yKFZhbGlkYXRpb25LZXlzLkVOVU0pXG4gIC5leHRlbmQoe1xuICAgIGRlY29yYXRvcjogZnVuY3Rpb24gb3B0aW9uRGVjKG9wdGlvbnM6IHN0cmluZ1tdIHwgUmVjb3JkPHN0cmluZywgYW55Pikge1xuICAgICAgY29uc3Qgb3B0cyA9IEFycmF5LmlzQXJyYXkob3B0aW9ucykgPyBvcHRpb25zIDogT2JqZWN0LnZhbHVlcyhvcHRpb25zKTtcbiAgICAgIHJldHVybiBBcGlQcm9wZXJ0eSh7XG4gICAgICAgIGVudW06IG9wdHMsXG4gICAgICAgIHJlcXVpcmVkOiBmYWxzZSxcbiAgICAgIH0pO1xuICAgIH0sXG4gIH0pXG4gIC5hcHBseSgpO1xuXG5EZWNvcmF0aW9uLmZvcihWYWxpZGF0aW9uS2V5cy5QQVRURVJOKVxuICAuZXh0ZW5kKHtcbiAgICBkZWNvcmF0b3I6IGZ1bmN0aW9uIHBhdHRlcm5EZWMocGF0OiBSZWdFeHAgfCBzdHJpbmcpIHtcbiAgICAgIHJldHVybiBBcGlQcm9wZXJ0eSh7XG4gICAgICAgIHBhdHRlcm46IHR5cGVvZiBwYXQgPT09IFwic3RyaW5nXCIgPyBwYXQgOiBwYXQuc291cmNlLFxuICAgICAgICByZXF1aXJlZDogZmFsc2UsXG4gICAgICB9KTtcbiAgICB9LFxuICB9KVxuICAuYXBwbHkoKTtcblxuRGVjb3JhdGlvbi5mb3IoUGVyc2lzdGVuY2VLZXlzLkNPTFVNTilcbiAgLmV4dGVuZCh7XG4gICAgZGVjb3JhdG9yOiBmdW5jdGlvbiBjb2x1bW5EZWMobmFtZTogc3RyaW5nKSB7XG4gICAgICByZXR1cm4gQXBpUHJvcGVydHkoe1xuICAgICAgICBuYW1lOiBuYW1lLFxuICAgICAgICByZXF1aXJlZDogZmFsc2UsXG4gICAgICB9KTtcbiAgICB9LFxuICB9KVxuICAuYXBwbHkoKTtcblxuRGVjb3JhdGlvbi5mb3IoRGVjb3JhdGlvbktleXMuREVTQ1JJUFRJT04pXG4gIC5leHRlbmQoe1xuICAgIGRlY29yYXRvcjogZnVuY3Rpb24gZGVzY3JpcHRpb25EZWMoZGVzY3JpcHRpb246IHN0cmluZykge1xuICAgICAgcmV0dXJuIEFwaVByb3BlcnR5KHtcbiAgICAgICAgZGVzY3JpcHRpb246IGRlc2NyaXB0aW9uLFxuICAgICAgICByZXF1aXJlZDogZmFsc2UsXG4gICAgICB9KTtcbiAgICB9LFxuICB9KVxuICAuYXBwbHkoKTtcblxuRGVjb3JhdGlvbi5mb3IoUGVyc2lzdGVuY2VLZXlzLkFVVEgpLmV4dGVuZCh7IGRlY29yYXRvcjogQXV0aCB9KS5hcHBseSgpO1xuIiwiaW1wb3J0IHsgRm9yYmlkZGVuRXJyb3IgfSBmcm9tIFwiQGRlY2FmLXRzL2NvcmVcIjtcblxuZXhwb3J0IGNsYXNzIENvcnNFcnJvciBleHRlbmRzIEZvcmJpZGRlbkVycm9yIHtcbiAgY29uc3RydWN0b3IobXNnOiBzdHJpbmcgfCBFcnJvcikge1xuICAgIHN1cGVyKG1zZywgQ29yc0Vycm9yLm5hbWUpO1xuICB9XG59XG4iLCJpbXBvcnQgeyBCYXNlRXJyb3IgfSBmcm9tIFwiQGRlY2FmLXRzL2RiLWRlY29yYXRvcnNcIjtcblxuZXhwb3J0IGNsYXNzIFRvTWFueVJlcXVlc3RzRXJyb3IgZXh0ZW5kcyBCYXNlRXJyb3Ige1xuICBjb25zdHJ1Y3Rvcihtc2c6IHN0cmluZyB8IEVycm9yICkge1xuICAgIHN1cGVyKFRvTWFueVJlcXVlc3RzRXJyb3IubmFtZSwgbXNnICwgNDI5KTtcbiAgfVxufSIsImltcG9ydCB7XG4gIEFyZ3VtZW50c0hvc3QsXG4gIENhdGNoLFxuICBFeGNlcHRpb25GaWx0ZXIsXG4gIE5vdEFjY2VwdGFibGVFeGNlcHRpb24sXG4gIE5vdEZvdW5kRXhjZXB0aW9uLFxufSBmcm9tIFwiQG5lc3Rqcy9jb21tb25cIjtcbmltcG9ydCB7IEJhc2VFcnJvciwgSW50ZXJuYWxFcnJvciB9IGZyb20gXCJAZGVjYWYtdHMvZGItZGVjb3JhdG9yc1wiO1xuaW1wb3J0IHsgTG9nZ2VkRW52aXJvbm1lbnQgfSBmcm9tIFwiQGRlY2FmLXRzL2xvZ2dpbmdcIjtcbmltcG9ydCB7IFVuc3VwcG9ydGVkRXJyb3IgfSBmcm9tIFwiQGRlY2FmLXRzL2NvcmVcIjtcbmltcG9ydCB7IFRvTWFueVJlcXVlc3RzRXJyb3IgfSBmcm9tIFwiLi4vZXJyb3JzL3Rocm90dGxpbmdcIjtcblxuQENhdGNoKClcbmV4cG9ydCBjbGFzcyBEZWNhZkV4Y2VwdGlvbkZpbHRlciBpbXBsZW1lbnRzIEV4Y2VwdGlvbkZpbHRlciB7XG4gIGNhdGNoKGV4Y2VwdGlvbjogRXJyb3IsIGhvc3Q6IEFyZ3VtZW50c0hvc3QpIHtcbiAgICBjb25zdCBjdHggPSBob3N0LnN3aXRjaFRvSHR0cCgpO1xuICAgIGNvbnN0IHJlc3BvbnNlID0gY3R4LmdldFJlc3BvbnNlKCk7XG4gICAgY29uc3QgcmVxdWVzdCA9IGN0eC5nZXRSZXF1ZXN0KCk7XG5cbiAgICBjb25zdCBpc1Byb2R1Y3Rpb24gPSBMb2dnZWRFbnZpcm9ubWVudC5lbnYgPT09IFwicHJvZHVjdGlvblwiO1xuICAgIGxldCBzdGF0dXNDb2RlO1xuXG4gICAgaWYgKFxuICAgICAgZXhjZXB0aW9uIGluc3RhbmNlb2YgTm90Rm91bmRFeGNlcHRpb24gfHxcbiAgICAgIGV4Y2VwdGlvbiBpbnN0YW5jZW9mIFVuc3VwcG9ydGVkRXJyb3JcbiAgICApIHtcbiAgICAgIGV4Y2VwdGlvbiA9IG5ldyBOb3RBY2NlcHRhYmxlRXhjZXB0aW9uKGV4Y2VwdGlvbi5tZXNzYWdlKTtcbiAgICAgIHN0YXR1c0NvZGUgPSAoZXhjZXB0aW9uIGFzIE5vdEFjY2VwdGFibGVFeGNlcHRpb24pLmdldFN0YXR1cygpO1xuICAgIH0gZWxzZSBpZiAoIShleGNlcHRpb24gaW5zdGFuY2VvZiBCYXNlRXJyb3IpKSB7XG4gICAgICBpZigoZXhjZXB0aW9uIGFzIGFueSkuc3RhdHVzID09PSA0Mjkpe1xuICAgICAgICBleGNlcHRpb24gPSBuZXcgVG9NYW55UmVxdWVzdHNFcnJvcihleGNlcHRpb24ubWVzc2FnZSk7XG4gICAgICB9ZWxzZXtcbiAgICAgICAgZXhjZXB0aW9uID0gbmV3IEludGVybmFsRXJyb3IoZXhjZXB0aW9uLm1lc3NhZ2UpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJlc3BvbnNlLnN0YXR1cygoZXhjZXB0aW9uIGFzIEJhc2VFcnJvcikuY29kZSB8fCBzdGF0dXNDb2RlKS5qc29uKHtcbiAgICAgIHN0YXR1czogKGV4Y2VwdGlvbiBhcyBCYXNlRXJyb3IpLmNvZGUgfHwgc3RhdHVzQ29kZSxcbiAgICAgIGVycm9yOiBpc1Byb2R1Y3Rpb24gPyBleGNlcHRpb24ubmFtZSA6IGV4Y2VwdGlvbi5tZXNzYWdlLFxuICAgICAgdGltZXN0YW1wOiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCksXG4gICAgICBwYXRoOiByZXF1ZXN0LnVybCxcbiAgICAgIG1ldGhvZDogcmVxdWVzdC5tZXRob2QsXG4gICAgfSk7XG4gIH1cbn1cbiIsImltcG9ydCB7IFVzZUZpbHRlcnMsIFVzZUludGVyY2VwdG9ycyB9IGZyb20gXCJAbmVzdGpzL2NvbW1vblwiO1xuaW1wb3J0IHsgRGVjYWZFeGNlcHRpb25GaWx0ZXIgfSBmcm9tIFwiLi9EZWNhZkVycm9yRmlsdGVyXCI7XG5pbXBvcnQgeyBEZWNhZlJlc3BvbnNlSW50ZXJjZXB0b3IgfSBmcm9tIFwiLi4vLi4vcmVxdWVzdC9pbmRleFwiO1xuXG5leHBvcnQgZnVuY3Rpb24gVXNlRGVjYWZGaWx0ZXIoKSB7XG4gIHJldHVybiBVc2VGaWx0ZXJzKG5ldyBEZWNhZkV4Y2VwdGlvbkZpbHRlcigpKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIFVzZURlY2FmSGVhZGVycygpIHtcbiAgcmV0dXJuIFVzZUludGVyY2VwdG9ycyhEZWNhZlJlc3BvbnNlSW50ZXJjZXB0b3IpO1xufVxuIiwiaW1wb3J0IHsgQ29uc3RydWN0b3IgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRpb25cIjtcbmltcG9ydCB7IFNlY3VyaXR5U2NoZW1lT2JqZWN0IH0gZnJvbSBcIi4uLy4uL3N3YWdnZXItdHlwZXNcIjtcblxuZXhwb3J0IGludGVyZmFjZSBTd2FnZ2VyT3B0aW9ucyB7XG4gIHRpdGxlOiBzdHJpbmc7XG4gIGRlc2NyaXB0aW9uOiBzdHJpbmc7XG4gIHZlcnNpb24/OiBzdHJpbmc7XG4gIGFzc2V0c1BhdGg/OiBzdHJpbmc7XG4gIGZhdmljb25GaWxlUGF0aD86IHN0cmluZztcbiAgdG9wYmFySWNvbkZpbGVQYXRoPzogc3RyaW5nO1xuICBwZXJzaXN0QXV0aG9yaXphdGlvbj86IGJvb2xlYW47XG4gIHBhdGg6IHN0cmluZztcbiAgYXV0aD86IFNlY3VyaXR5U2NoZW1lT2JqZWN0O1xuICB0b3BiYXJCZ0NvbG9yPzogc3RyaW5nO1xuICBleHRyYU1vZGVscz86IENvbnN0cnVjdG9yW107XG5cbiAgLyoqXG4gICAqIFBhdGggdG8gZXhwb3NlIHRoZSBPcGVuQVBJIHNwZWNpZmljYXRpb24gaW4gSlNPTiBmb3JtYXQuXG4gICAqIEV4YW1wbGU6IC9hcGkvb3BlbmFwaS5qc29uXG4gICAqL1xuICBvcGVuQXBpSnNvblBhdGg/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFBhdGggdG8gZXhwb3NlIHRoZSBPcGVuQVBJIHNwZWNpZmljYXRpb24gaW4gWUFNTCBmb3JtYXQuXG4gICAqIFJlcXVpcmVzICd5YW1sJyBwYWNrYWdlIGFzIHBlZXIgZGVwZW5kZW5jeS5cbiAgICogRXhhbXBsZTogL2FwaS9vcGVuYXBpLnlhbWxcbiAgICovXG4gIG9wZW5BcGlZYW1sUGF0aD86IHN0cmluZztcbn1cblxuZXhwb3J0IGNvbnN0IFNXQUdHRVJfVUlfQ09OU1RBTlRTOiBTd2FnZ2VyT3B0aW9ucyA9IHtcbiAgdGl0bGU6IFwiU3dhZ2dlciB8IE9wZW5BUEkgU3BlY2lmaWNhdGlvbiAoT0FTKVwiLFxuICBkZXNjcmlwdGlvbjogXCJTdGFuZGFyZGl6ZWQgZm9ybWF0IGZvciBkZXNjcmliaW5nIFJFU1RmdWwgQVBJc1wiLFxuICB2ZXJzaW9uOiBcIjAuMC4xXCIsXG4gIHBhdGg6IFwiZG9jc1wiLFxuICBmYXZpY29uRmlsZVBhdGg6IFwiXCIsXG4gIHRvcGJhckljb25GaWxlUGF0aDogXCJcIixcbiAgYXV0aDoge1xuICAgIHR5cGU6IFwiaHR0cFwiLFxuICAgIHNjaGVtZTogXCJiZWFyZXJcIixcbiAgICBiZWFyZXJGb3JtYXQ6IFwiSldUXCIsXG4gICAgbmFtZTogXCJBdXRob3JpemF0aW9uXCIsXG4gICAgZGVzY3JpcHRpb246IFwiRW50ZXIgSldUIHRva2VuXCIsXG4gICAgaW46IFwiaGVhZGVyXCIsXG4gIH0sXG4gIHBlcnNpc3RBdXRob3JpemF0aW9uOiB0cnVlLFxuICB0b3BiYXJCZ0NvbG9yOiBcIiMwMDAwMDBcIixcbn07XG4iLCJpbXBvcnQgeyBTV0FHR0VSX1VJX0NPTlNUQU5UUyB9IGZyb20gXCIuL2NvbnN0YW50c1wiO1xuaW1wb3J0IHsgcmVhZEZpbGVTeW5jIH0gZnJvbSBcImZzXCI7XG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gXCJwYXRoXCI7XG5cbmV4cG9ydCBpbnRlcmZhY2UgU3dhZ2dlclVJT3B0aW9ucyB7XG4gIHRpdGxlPzogc3RyaW5nO1xuICBwYXRoPzogc3RyaW5nO1xuICBwZXJzaXN0QXV0aG9yaXphdGlvbjogYm9vbGVhbjtcbiAgYXNzZXRzUGF0aD86IHN0cmluZztcbiAgZmF2aWNvblBhdGg/OiBzdHJpbmc7XG4gIHRvcGJhckljb25QYXRoPzogc3RyaW5nO1xuICB0b3BiYXJCZ0NvbG9yPzogc3RyaW5nO1xufVxuXG5leHBvcnQgY2xhc3MgU3dhZ2dlckN1c3RvbVVJIHtcbiAgcmVhZG9ubHkgb3B0aW9uczogU3dhZ2dlclVJT3B0aW9ucztcbiAgLy8gcHJpdmF0ZSByZWFkb25seSBhc3NldHNQYXRoOiBzdHJpbmcgPSBwYXRoLmpvaW4oXG4gIC8vICAgX19kaXJuYW1lLFxuICAvLyAgIFwiLi5cIixcbiAgLy8gICBcIi4uXCIsXG4gIC8vICAgXCJ3b3JrZG9jc1wiLFxuICAvLyAgIFwiYXNzZXRzXCJcbiAgLy8gKTtcblxuICBjb25zdHJ1Y3RvcihvcHRpb25zOiBTd2FnZ2VyVUlPcHRpb25zKSB7XG4gICAgdGhpcy5vcHRpb25zID0ge1xuICAgICAgLi4ub3B0aW9ucyxcbiAgICB9O1xuICB9XG5cbiAgcHJpdmF0ZSBjdXN0b21DU1MoKSB7XG4gICAgbGV0IGNzcyA9IFwiXCI7XG4gICAgaWYgKHRoaXMub3B0aW9ucy50b3BiYXJJY29uUGF0aCkge1xuICAgICAgY29uc3QgaW1nID0gdGhpcy5iNjQodGhpcy5vcHRpb25zLnRvcGJhckljb25QYXRoKTtcbiAgICAgIGNzcyArPSBgLnRvcGJhci13cmFwcGVyIHsgY29udGVudDogdXJsKCdkYXRhOmltYWdlL3BuZztiYXNlNjQsJHtpbWd9Jyk7IHdpZHRoOiAyMDBweDsgaGVpZ2h0OiBhdXRvOyB9XFxuYDtcbiAgICB9XG4gICAgcmV0dXJuIChcbiAgICAgIGNzcyArXG4gICAgICBgXG4gICAgICAgIC50b3BiYXItd3JhcHBlciBzdmcgeyB2aXNpYmlsaXR5OiBoaWRkZW47IH1cbiAgICAgICAgLnN3YWdnZXItdWkgLnRvcGJhciB7IGJhY2tncm91bmQtY29sb3I6ICR7dGhpcy5vcHRpb25zLnRvcGJhckJnQ29sb3IgfHwgU1dBR0dFUl9VSV9DT05TVEFOVFMudG9wYmFyQmdDb2xvcn07IH1cbiAgICAgIGBcbiAgICApO1xuICB9XG5cbiAgZ2V0Q3VzdG9tT3B0aW9ucygpIHtcbiAgICBjb25zdCBmYXZpY29uOiBSZWNvcmQ8c3RyaW5nLCBhbnk+ID0ge307XG4gICAgaWYgKHRoaXMub3B0aW9ucy5mYXZpY29uUGF0aCkge1xuICAgICAgZmF2aWNvbltcImN1c3RvbWZhdkljb25cIl0gPSB0aGlzLmI2NCh0aGlzLm9wdGlvbnMuZmF2aWNvblBhdGgsIHRydWUpO1xuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICBjdXN0b21TaXRlVGl0bGU6IHRoaXMub3B0aW9ucy50aXRsZSxcbiAgICAgIC4uLmZhdmljb24sXG4gICAgICBjdXN0b21Dc3M6IHRoaXMuY3VzdG9tQ1NTKCksXG4gICAgICBzd2FnZ2VyT3B0aW9uczoge1xuICAgICAgICBwZXJzaXN0QXV0aG9yaXphdGlvbjogdGhpcy5vcHRpb25zLnBlcnNpc3RBdXRob3JpemF0aW9uLFxuICAgICAgfSxcbiAgICB9O1xuICB9XG5cbiAgYjY0KGZpbGU6IHN0cmluZywgaW1nOiBib29sZWFuID0gZmFsc2UpIHtcbiAgICBjb25zdCBmaWxlUGF0aCA9IHBhdGguam9pbih0aGlzLm9wdGlvbnMuYXNzZXRzUGF0aCB8fCBcIlwiLCBmaWxlKTtcbiAgICBjb25zdCBiNjQgPSByZWFkRmlsZVN5bmMoZmlsZVBhdGgsIHsgZW5jb2Rpbmc6IFwiYmFzZTY0XCIgfSk7XG4gICAgcmV0dXJuIGltZyA/IFwiZGF0YTppbWFnZS9wbmc7YmFzZTY0LFwiICsgYjY0IDogYjY0O1xuICB9XG59XG4iLCJpbXBvcnQgeyBJTmVzdEFwcGxpY2F0aW9uIH0gZnJvbSBcIkBuZXN0anMvY29tbW9uXCI7XG5pbXBvcnQgeyBEb2N1bWVudEJ1aWxkZXIsIFN3YWdnZXJNb2R1bGUgfSBmcm9tIFwiQG5lc3Rqcy9zd2FnZ2VyXCI7XG5pbXBvcnQgeyBTd2FnZ2VyQ3VzdG9tVUkgfSBmcm9tIFwiLi9Td2FnZ2VyQ3VzdG9tVUlcIjtcbmltcG9ydCB7IFNXQUdHRVJfVUlfQ09OU1RBTlRTLCBTd2FnZ2VyT3B0aW9ucyB9IGZyb20gXCIuL2NvbnN0YW50c1wiO1xuaW1wb3J0IFlBTUwgZnJvbSBcInlhbWxcIjtcblxuZXhwb3J0IGNsYXNzIFN3YWdnZXJCdWlsZGVyIHtcbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSByZWFkb25seSBhcHA6IElOZXN0QXBwbGljYXRpb24sXG4gICAgcHJpdmF0ZSByZWFkb25seSBvcHRpb25zOiBTd2FnZ2VyT3B0aW9uc1xuICApIHt9XG5cbiAgcHJpdmF0ZSBjcmVhdGVEb2N1bWVudCgpIHtcbiAgICBjb25zdCBkZXNjcmlwdGlvbiA9IHRoaXMub3B0aW9ucy5wYXRoXG4gICAgICA/IHRoaXMub3B0aW9ucy5kZXNjcmlwdGlvbiArXG4gICAgICAgIFwiXCIgK1xuICAgICAgICBgPGJyPjxicj48YSBocmVmPVwiJHt0aGlzLm9wdGlvbnMub3BlbkFwaUpzb25QYXRofVwiPk9wZW5BUEkgSlNPTiBTcGVjPC9hPiB8IGAgK1xuICAgICAgICBgPGEgaHJlZj1cIiR7dGhpcy5vcHRpb25zLm9wZW5BcGlZYW1sUGF0aH1cIj5PcGVuQVBJIFlBTUwgU3BlYzwvYT5gXG4gICAgICA6IHRoaXMub3B0aW9ucy5kZXNjcmlwdGlvbjtcblxuICAgIGNvbnN0IGNvbmZpZyA9IG5ldyBEb2N1bWVudEJ1aWxkZXIoKVxuICAgICAgLnNldFRpdGxlKHRoaXMub3B0aW9ucy50aXRsZSlcbiAgICAgIC5zZXREZXNjcmlwdGlvbihkZXNjcmlwdGlvbilcbiAgICAgIC5zZXRWZXJzaW9uKHRoaXMub3B0aW9ucy52ZXJzaW9uIHx8IFwiMC4wLjFcIilcbiAgICAgIC5hZGRCZWFyZXJBdXRoKHRoaXMub3B0aW9ucy5hdXRoIHx8IFNXQUdHRVJfVUlfQ09OU1RBTlRTLmF1dGgpXG4gICAgICAuYnVpbGQoKTtcblxuICAgIHJldHVybiBTd2FnZ2VyTW9kdWxlLmNyZWF0ZURvY3VtZW50KHRoaXMuYXBwLCBjb25maWcsIHtcbiAgICAgIGV4dHJhTW9kZWxzOiB0aGlzLm9wdGlvbnMuZXh0cmFNb2RlbHMgfHwgW10sXG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIHJlZ2lzdGVyT3BlbkFwaVJvdXRlKFxuICAgIHBhdGg6IHN0cmluZyB8IHVuZGVmaW5lZCxcbiAgICBjb250ZW50VHlwZTogXCJhcHBsaWNhdGlvbi9qc29uXCIgfCBcImFwcGxpY2F0aW9uL3gteWFtbFwiLFxuICAgIGJvZHlGYWN0b3J5OiAoKSA9PiB2b2lkXG4gICk6IHZvaWQge1xuICAgIGlmICghcGF0aCkgcmV0dXJuO1xuXG4gICAgY29uc3QgaHR0cEFkYXB0ZXIgPSB0aGlzLmFwcC5nZXRIdHRwQWRhcHRlcigpIGFzIGFueTtcbiAgICBwYXRoID0gcGF0aC5zdGFydHNXaXRoKFwiL1wiKSA/IHBhdGggOiBgLyR7cGF0aH1gO1xuICAgIGh0dHBBZGFwdGVyLmdldChwYXRoLCAoX3JlcTogYW55LCByZXM6IGFueSkgPT4ge1xuICAgICAgaHR0cEFkYXB0ZXIucmVwbHkocmVzLCBib2R5RmFjdG9yeSgpLCAyMDAsIHtcbiAgICAgICAgXCJDb250ZW50LVR5cGVcIjogY29udGVudFR5cGUsXG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuXG4gIHB1YmxpYyBzZXR1cFN3YWdnZXIoKSB7XG4gICAgY29uc3QgZG9jdW1lbnQgPSB0aGlzLmNyZWF0ZURvY3VtZW50KCk7XG4gICAgY29uc3Qgc3dhZ2dlclVJID0gbmV3IFN3YWdnZXJDdXN0b21VSSh7XG4gICAgICB0aXRsZTogdGhpcy5vcHRpb25zLnRpdGxlLFxuICAgICAgcGF0aDogdGhpcy5vcHRpb25zLnBhdGggfHwgU1dBR0dFUl9VSV9DT05TVEFOVFMucGF0aCxcbiAgICAgIHBlcnNpc3RBdXRob3JpemF0aW9uOiB0aGlzLm9wdGlvbnMucGVyc2lzdEF1dGhvcml6YXRpb24gPz8gdHJ1ZSxcbiAgICAgIGFzc2V0c1BhdGg6IHRoaXMub3B0aW9ucy5hc3NldHNQYXRoLFxuICAgICAgZmF2aWNvblBhdGg6IHRoaXMub3B0aW9ucy5mYXZpY29uRmlsZVBhdGgsXG4gICAgICB0b3BiYXJJY29uUGF0aDogdGhpcy5vcHRpb25zLnRvcGJhckljb25GaWxlUGF0aCxcbiAgICAgIHRvcGJhckJnQ29sb3I6IHRoaXMub3B0aW9ucy50b3BiYXJCZ0NvbG9yLFxuICAgIH0pO1xuICAgIFN3YWdnZXJNb2R1bGUuc2V0dXAoXG4gICAgICB0aGlzLm9wdGlvbnMucGF0aCB8fCBTV0FHR0VSX1VJX0NPTlNUQU5UUy5wYXRoLFxuICAgICAgdGhpcy5hcHAsXG4gICAgICBkb2N1bWVudCxcbiAgICAgIHtcbiAgICAgICAgLi4uc3dhZ2dlclVJLmdldEN1c3RvbU9wdGlvbnMoKSxcbiAgICAgICAganNvbkRvY3VtZW50VXJsOiB0aGlzLm9wdGlvbnMub3BlbkFwaUpzb25QYXRoXG4gICAgICAgICAgPyBgJHt0aGlzLm9wdGlvbnMub3BlbkFwaUpzb25QYXRofWBcbiAgICAgICAgICA6IHVuZGVmaW5lZCxcbiAgICAgICAgeWFtbERvY3VtZW50VXJsOiB0aGlzLm9wdGlvbnMub3BlbkFwaVlhbWxQYXRoXG4gICAgICAgICAgPyBgJHt0aGlzLm9wdGlvbnMub3BlbkFwaVlhbWxQYXRofWBcbiAgICAgICAgICA6IHVuZGVmaW5lZCxcbiAgICAgIH1cbiAgICApO1xuXG4gICAgdGhpcy5yZWdpc3Rlck9wZW5BcGlSb3V0ZShcbiAgICAgIHRoaXMub3B0aW9ucy5vcGVuQXBpSnNvblBhdGgsXG4gICAgICBcImFwcGxpY2F0aW9uL2pzb25cIixcbiAgICAgICgpID0+IGRvY3VtZW50XG4gICAgKTtcblxuICAgIHRoaXMucmVnaXN0ZXJPcGVuQXBpUm91dGUoXG4gICAgICB0aGlzLm9wdGlvbnMub3BlbkFwaVlhbWxQYXRoLFxuICAgICAgXCJhcHBsaWNhdGlvbi94LXlhbWxcIixcbiAgICAgICgpID0+IFlBTUwuc3RyaW5naWZ5KGRvY3VtZW50KVxuICAgICk7XG4gIH1cblxuICAvLyBwcml2YXRlIGdldFZlcnNpb24oKSB7XG4gIC8vICAgLy8gY29uc3QgcGFja2FnZUpzb24gPSBwYXRoLmpvaW4oX19kaXJuYW1lLCBcIi4uXCIsIFwiLi5cIiwgXCJwYWNrYWdlLmpzb25cIik7XG4gIC8vICAgLy8gY29uc3Qge3ZlcnNpb259ID0gcmVxdWlyZShwYWNrYWdlSnNvbik7XG4gIC8vICAgcmV0dXJuIFwidmVyc2lvblwiO1xuICAvLyB9XG59XG4iLCJpbXBvcnQge1xuICBJTmVzdEFwcGxpY2F0aW9uLFxuICBMb2dnZXIsXG4gIE5lc3RJbnRlcmNlcHRvcixcbiAgUGlwZVRyYW5zZm9ybSxcbn0gZnJvbSBcIkBuZXN0anMvY29tbW9uXCI7XG5pbXBvcnQgeyBEZWNhZkV4Y2VwdGlvbkZpbHRlciB9IGZyb20gXCIuL2V4Y2VwdGlvbnNcIjtcbmltcG9ydCB7IFN3YWdnZXJCdWlsZGVyIH0gZnJvbSBcIi4vb3BlbmFwaVwiO1xuaW1wb3J0IHsgQ29yc09wdGlvbnMgfSBmcm9tIFwiQG5lc3Rqcy9jb21tb24vaW50ZXJmYWNlcy9leHRlcm5hbC9jb3JzLW9wdGlvbnMuaW50ZXJmYWNlXCI7XG5pbXBvcnQgeyBDb3JzRXJyb3IgfSBmcm9tIFwiLi9lcnJvcnNcIjtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb25cbiAqIERlZmluZXMgYWxsIGN1c3RvbWl6YWJsZSBwYXJhbWV0ZXJzIGZvciBTd2FnZ2VyIHNldHVwLlxuICpcbiAqIEBzdW1tYXJ5XG4gKiBUaGlzIGludGVyZmFjZSBhbGxvd3MgZGV2ZWxvcGVycyB0byBjdXN0b21pemUgaG93IFN3YWdnZXIgVUkgaXMgY29uZmlndXJlZFxuICogd2l0aGluIHRoZSBOZXN0SlMgYXBwbGljYXRpb24uIEl0IGluY2x1ZGVzIHBhcmFtZXRlcnMgZm9yIHRpdGxlcywgcGF0aHMsXG4gKiBjb2xvciBzY2hlbWVzLCBhbmQgYXNzZXQgcGF0aHMgdG8gdGFpbG9yIHRoZSBBUEkgZG9jdW1lbnRhdGlvbiBleHBlcmllbmNlLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSB0aXRsZSAtIFRpdGxlIGRpc3BsYXllZCBpbiBTd2FnZ2VyIFVJLlxuICogQHBhcmFtIHtzdHJpbmd9IGRlc2NyaXB0aW9uIC0gRGVzY3JpcHRpb24gc2hvd24gYmVsb3cgdGhlIHRpdGxlLlxuICogQHBhcmFtIHtzdHJpbmd9IHZlcnNpb24gLSBBUEkgdmVyc2lvbiBkaXNwbGF5ZWQgaW4gdGhlIGRvY3VtZW50YXRpb24uXG4gKiBAcGFyYW0ge3N0cmluZ30gW3BhdGhdIC0gT3B0aW9uYWwgcGF0aCB3aGVyZSBTd2FnZ2VyIHdpbGwgYmUgYXZhaWxhYmxlLlxuICogQHBhcmFtIHtib29sZWFufSBbcGVyc2lzdEF1dGhvcml6YXRpb25dIC0gV2hldGhlciBhdXRob3JpemF0aW9uIHRva2VucyBwZXJzaXN0IGFjcm9zcyByZWxvYWRzLlxuICogQHBhcmFtIHtzdHJpbmd9IFthc3NldHNQYXRoXSAtIFBhdGggdG8gY3VzdG9tIGFzc2V0cyBmb3IgU3dhZ2dlciBVSS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBbdG9wYmFyQmdDb2xvcl0gLSBDdXN0b20gYmFja2dyb3VuZCBjb2xvciBmb3IgdGhlIFN3YWdnZXIgdG9wIGJhci5cbiAqIEBwYXJhbSB7c3RyaW5nfSBbdG9wYmFySWNvblBhdGhdIC0gUGF0aCB0byBhIGN1c3RvbSBpY29uIGRpc3BsYXllZCBpbiB0aGUgdG9wIGJhci5cbiAqIEBwYXJhbSB7c3RyaW5nfSBbZmF2aWNvblBhdGhdIC0gUGF0aCB0byBhIGN1c3RvbSBmYXZpY29uLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFN3YWdnZXJTZXR1cE9wdGlvbnMge1xuICB0aXRsZTogc3RyaW5nO1xuICBkZXNjcmlwdGlvbjogc3RyaW5nO1xuICB2ZXJzaW9uOiBzdHJpbmc7XG4gIHBhdGg/OiBzdHJpbmc7XG4gIHBlcnNpc3RBdXRob3JpemF0aW9uPzogYm9vbGVhbjtcbiAgYXNzZXRzUGF0aD86IHN0cmluZztcbiAgdG9wYmFyQmdDb2xvcj86IHN0cmluZztcbiAgdG9wYmFySWNvblBhdGg/OiBzdHJpbmc7XG4gIGZhdmljb25QYXRoPzogc3RyaW5nO1xuICAvKipcbiAgICogUGF0aCB0byBleHBvc2UgdGhlIE9wZW5BUEkgc3BlY2lmaWNhdGlvbiBpbiBKU09OIGZvcm1hdC5cbiAgICogRXhhbXBsZTogL2FwaS9vcGVuYXBpLmpzb25cbiAgICovXG4gIG9wZW5BcGlKc29uUGF0aD86IHN0cmluZztcbiAgLyoqXG4gICAqIFBhdGggdG8gZXhwb3NlIHRoZSBPcGVuQVBJIHNwZWNpZmljYXRpb24gaW4gWUFNTCBmb3JtYXQuXG4gICAqIFJlcXVpcmVzICd5YW1sJyBwYWNrYWdlIGFzIHBlZXIgZGVwZW5kZW5jeS5cbiAgICogRXhhbXBsZTogL2FwaS9vcGVuYXBpLnlhbWxcbiAgICovXG4gIG9wZW5BcGlZYW1sUGF0aD86IHN0cmluZztcbn1cblxuLyoqXG4gKiBAZGVzY3JpcHRpb25cbiAqIEEgZmx1ZW50LCBzdGF0aWMgYm9vdHN0cmFwIGNsYXNzIGZvciBpbml0aWFsaXppbmcgYW5kIGNvbmZpZ3VyaW5nIGEgTmVzdEpTIGFwcGxpY2F0aW9uLlxuICpcbiAqIEBzdW1tYXJ5XG4gKiBUaGUgYE5lc3RCb290c3RyYXBlcmAgY2xhc3MgcHJvdmlkZXMgYSBjaGFpbmFibGUgQVBJIGZvciBjb25maWd1cmluZ1xuICogYSBOZXN0SlMgYXBwbGljYXRpb24gaW5zdGFuY2UuIEl0IGluY2x1ZGVzIGJ1aWx0LWluIG1ldGhvZHMgZm9yIGVuYWJsaW5nXG4gKiBDT1JTLCBIZWxtZXQgc2VjdXJpdHksIFN3YWdnZXIgZG9jdW1lbnRhdGlvbiwgZ2xvYmFsIHBpcGVzLCBmaWx0ZXJzLFxuICogaW50ZXJjZXB0b3JzLCBhbmQgc3RhcnRpbmcgdGhlIHNlcnZlci5cbiAqXG4gKiBUaGlzIGNsYXNzIHByb21vdGVzIGNvbnNpc3RlbmN5IGFuZCByZWR1Y2VzIHJlcGV0aXRpdmUgc2V0dXAgY29kZVxuICogYWNyb3NzIG11bHRpcGxlIE5lc3RKUyBwcm9qZWN0cy5cbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHNcbiAqIGltcG9ydCB7IE5lc3RGYWN0b3J5IH0gZnJvbSBcIkBuZXN0anMvY29yZVwiO1xuICogaW1wb3J0IHsgQXBwTW9kdWxlIH0gZnJvbSBcIi4vYXBwLm1vZHVsZVwiO1xuICogaW1wb3J0IHsgTXlMb2dnZXIgfSBmcm9tIFwiLi9NeUxvZ2dlclwiO1xuICogaW1wb3J0IHsgTmVzdEJvb3RzdHJhcGVyIH0gZnJvbSBcIkBkZWNhZi10cy9mb3ItbmVzdFwiO1xuICpcbiAqIGFzeW5jIGZ1bmN0aW9uIGJvb3RzdHJhcCgpIHtcbiAqICAgY29uc3QgYXBwID0gYXdhaXQgTmVzdEZhY3RvcnkuY3JlYXRlKEFwcE1vZHVsZSk7XG4gKlxuICogICBhd2FpdCBOZXN0Qm9vdHN0cmFwZXJcbiAqICAgICAuaW5pdGlhbGl6ZShhcHApXG4gKiAgICAgLmVuYWJsZUxvZ2dlcihuZXcgTXlMb2dnZXIoKSlcbiAqICAgICAuZW5hYmxlQ29ycyhbXCJodHRwOi8vbG9jYWxob3N0OjQyMDBcIl0pXG4gKiAgICAgLnVzZUhlbG1ldCgpXG4gKiAgICAgLnNldHVwU3dhZ2dlcih7XG4gKiAgICAgICB0aXRsZTogXCJPcGVuQVBJIGJ5IFRyYWRlTWFya+KEolwiLFxuICogICAgICAgZGVzY3JpcHRpb246IFwiVHJhZGVNYXJr4oSiIEFQSSBkb2N1bWVudGF0aW9uXCIsXG4gKiAgICAgICB2ZXJzaW9uOiBcIjEuMC4wXCIsXG4gKiAgICAgICBwYXRoOiBcImFwaVwiLFxuICogICAgICAgcGVyc2lzdEF1dGhvcml6YXRpb246IHRydWUsXG4gKiAgICAgICB0b3BiYXJCZ0NvbG9yOiBcIiMyQzNFNTBcIixcbiAqICAgICAgIHRvcGJhckljb25QYXRoOiBcIi9hc3NldHMvbG9nby5zdmdcIixcbiAqICAgICAgIGZhdmljb25QYXRoOiBcIi9hc3NldHMvZmF2aWNvbi5pY29cIlxuICogICAgIH0pXG4gKiAgICAgLnVzZUdsb2JhbEZpbHRlcnMoKVxuICogICAgIC51c2VHbG9iYWxQaXBlcyguLi4pXG4gKiAgICAgLnVzZUdsb2JhbEludGVyY2VwdG9ycyguLi4pXG4gKiAgICAgLnN0YXJ0KDMwMDApO1xuICogfVxuICpcbiAqIGJvb3RzdHJhcCgpO1xuICogYGBgXG4gKiBAY2xhc3NcbiAqL1xuZXhwb3J0IGNsYXNzIE5lc3RCb290c3RyYXBlciB7XG4gIHByaXZhdGUgc3RhdGljIGFwcDogSU5lc3RBcHBsaWNhdGlvbjtcbiAgcHJpdmF0ZSBzdGF0aWMgX2xvZ2dlcjogTG9nZ2VyO1xuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb25cbiAgICogUmV0dXJucyB0aGUgY3VycmVudCBsb2dnZXIgaW5zdGFuY2UsIGNyZWF0aW5nIGEgZGVmYXVsdCBvbmUgaWYgbm90IHNldC5cbiAgICpcbiAgICogQHN1bW1hcnlcbiAgICogRW5zdXJlcyB0aGF0IGEgdmFsaWQgYExvZ2dlcmAgaW5zdGFuY2UgaXMgYWx3YXlzIGF2YWlsYWJsZVxuICAgKiBmb3IgbG9nZ2luZyBib290c3RyYXAtcmVsYXRlZCBtZXNzYWdlcy5cbiAgICpcbiAgICogQHJldHVybiB7TG9nZ2VyfSBUaGUgYWN0aXZlIGxvZ2dlciBpbnN0YW5jZS5cbiAgICovXG4gIHByaXZhdGUgc3RhdGljIGdldCBsb2dnZXIoKTogTG9nZ2VyIHtcbiAgICBpZiAoIXRoaXMuX2xvZ2dlcikge1xuICAgICAgLy8gZmFsbGJhY2tcbiAgICAgIHRoaXMuX2xvZ2dlciA9IG5ldyBMb2dnZXIoXCJOZXN0Qm9vdHN0cmFwXCIpO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5fbG9nZ2VyO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvblxuICAgKiBJbml0aWFsaXplcyB0aGUgYm9vdHN0cmFwcGVyIHdpdGggYSBnaXZlbiBOZXN0SlMgYXBwbGljYXRpb24uXG4gICAqXG4gICAqIEBzdW1tYXJ5XG4gICAqIEJpbmRzIHRoZSBwcm92aWRlZCBOZXN0SlMgYXBwIGluc3RhbmNlIHRvIHRoZSBib290c3RyYXBwZXIsIGVuYWJsaW5nXG4gICAqIGNoYWluZWQgY29uZmlndXJhdGlvbiBtZXRob2RzLlxuICAgKlxuICAgKiBAcGFyYW0ge0lOZXN0QXBwbGljYXRpb259IGFwcCAtIFRoZSBOZXN0SlMgYXBwbGljYXRpb24gaW5zdGFuY2UgdG8gaW5pdGlhbGl6ZS5cbiAgICogQHJldHVybiB7TmVzdEJvb3RzdHJhcGVyfSBSZXR1cm5zIHRoZSBjbGFzcyBmb3IgY2hhaW5pbmcgY29uZmlndXJhdGlvbiBtZXRob2RzLlxuICAgKi9cbiAgc3RhdGljIGluaXRpYWxpemUoYXBwOiBJTmVzdEFwcGxpY2F0aW9uKSB7XG4gICAgdGhpcy5hcHAgPSBhcHA7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uXG4gICAqIEVuYWJsZXMgb3IgcmVwbGFjZXMgdGhlIGdsb2JhbCBsb2dnZXIgZm9yIHRoZSBOZXN0SlMgYXBwbGljYXRpb24uXG4gICAqXG4gICAqIEBzdW1tYXJ5XG4gICAqIElmIGEgY3VzdG9tIGxvZ2dlciBpcyBwcm92aWRlZCwgaXQgcmVwbGFjZXMgdGhlIGRlZmF1bHQgbG9nZ2VyLiBPdGhlcndpc2UsXG4gICAqIGEgbmV3IGxvZ2dlciBuYW1lZCBgXCJOZXN0Qm9vdHN0cmFwXCJgIGlzIHVzZWQuIFRoaXMgbG9nZ2VyIGlzIGFsc28gcmVnaXN0ZXJlZFxuICAgKiB3aXRoIHRoZSBOZXN0SlMgYXBwbGljYXRpb24uXG4gICAqXG4gICAqIEBwYXJhbSB7TG9nZ2VyfSBbY3VzdG9tTG9nZ2VyXSAtIE9wdGlvbmFsIGN1c3RvbSBsb2dnZXIgaW5zdGFuY2UuXG4gICAqIEByZXR1cm4ge05lc3RCb290c3RyYXBlcn0gUmV0dXJucyB0aGUgY2xhc3MgZm9yIGNoYWluaW5nLlxuICAgKi9cbiAgc3RhdGljIGVuYWJsZUxvZ2dlcihjdXN0b21Mb2dnZXI/OiBMb2dnZXIpIHtcbiAgICB0aGlzLl9sb2dnZXIgPSBjdXN0b21Mb2dnZXIgfHwgbmV3IExvZ2dlcihcIk5lc3RCb290c3RyYXBcIik7XG4gICAgdGhpcy5hcHAudXNlTG9nZ2VyKHRoaXMuX2xvZ2dlcik7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uXG4gICAqIEVuYWJsZXMgQ3Jvc3MtT3JpZ2luIFJlc291cmNlIFNoYXJpbmcgKENPUlMpIGZvciB0aGUgYXBwbGljYXRpb24uXG4gICAqXG4gICAqIEBzdW1tYXJ5XG4gICAqIEFsbG93cyBkZWZpbmluZyBlaXRoZXIgYSB3aWxkY2FyZCBvcmlnaW4gKGBcIipcImApIG9yIGEgbGlzdCBvZiBhbGxvd2VkIG9yaWdpbnMuXG4gICAqIEF1dG9tYXRpY2FsbHkgYWNjZXB0cyBsb2NhbCBkZXZlbG9wbWVudCByZXF1ZXN0cyBhbmQgdGhvc2Ugd2l0aG91dCBvcmlnaW4gaGVhZGVycy5cbiAgICogVGhyb3dzIGEgYENvcnNFcnJvcmAgZm9yIHVuYXV0aG9yaXplZCBvcmlnaW5zLlxuICAgKlxuICAgKiBAcGFyYW0geycqJyB8IHN0cmluZ1tdfSBbb3JpZ2lucz1bXV0gLSBMaXN0IG9mIGFsbG93ZWQgb3JpZ2lucyBvciBgXCIqXCJgIHRvIGFsbG93IGFsbC5cbiAgICogQHBhcmFtIHtzdHJpbmdbXX0gW2FsbG93TWV0aG9kcz1bJ0dFVCcsICdQT1NUJywgJ1BVVCcsICdERUxFVEUnXV0gLSBBbGxvd2VkIEhUVFAgbWV0aG9kcy5cbiAgICogQHJldHVybiB7TmVzdEJvb3RzdHJhcGVyfSBSZXR1cm5zIHRoZSBjbGFzcyBmb3IgY2hhaW5pbmcgY29uZmlndXJhdGlvbi5cbiAgICpcbiAgICovXG4gIHN0YXRpYyBlbmFibGVDb3JzKFxuICAgIG9yaWdpbnM6IFwiKlwiIHwgc3RyaW5nW10gPSBbXSxcbiAgICBhbGxvd01ldGhvZHM6IHN0cmluZ1tdID0gW1wiR0VUXCIsIFwiUE9TVFwiLCBcIlBVVFwiLCBcIkRFTEVURVwiXVxuICApIHtcbiAgICBjb25zdCBhbGxvd2VkT3JpZ2lucyA9XG4gICAgICBvcmlnaW5zID09PSBcIipcIiA/IFwiKlwiIDogb3JpZ2lucy5tYXAoKG8pID0+IG8udHJpbSgpLnRvTG93ZXJDYXNlKCkpO1xuXG4gICAgY29uc3QgY29yc09wdGlvbnM6IENvcnNPcHRpb25zID0ge1xuICAgICAgb3JpZ2luOiAob3JpZ2luLCBjYWxsYmFjaykgPT4ge1xuICAgICAgICAvLyBBbGxvdyByZXF1ZXN0IHdpdGhvdXQgb3JpZ2luLi4uXG4gICAgICAgIGlmICghb3JpZ2luKSByZXR1cm4gY2FsbGJhY2sobnVsbCwgdHJ1ZSk7XG5cbiAgICAgICAgaWYgKFxuICAgICAgICAgIGFsbG93ZWRPcmlnaW5zID09PSBcIipcIiB8fFxuICAgICAgICAgIChBcnJheS5pc0FycmF5KGFsbG93ZWRPcmlnaW5zKSAmJlxuICAgICAgICAgICAgYWxsb3dlZE9yaWdpbnMuaW5jbHVkZXMob3JpZ2luLnRvTG93ZXJDYXNlKCkpKVxuICAgICAgICApIHtcbiAgICAgICAgICByZXR1cm4gY2FsbGJhY2sobnVsbCwgdHJ1ZSk7XG4gICAgICAgIH1cblxuICAgICAgICBjYWxsYmFjayhuZXcgQ29yc0Vycm9yKGBPcmlnaW4gJHtvcmlnaW59IG5vdCBhbGxvd2VkYCkpO1xuICAgICAgfSxcbiAgICAgIGNyZWRlbnRpYWxzOiB0cnVlLFxuICAgICAgbWV0aG9kczogYWxsb3dNZXRob2RzLmpvaW4oXCIsXCIpLFxuICAgIH07XG5cbiAgICB0aGlzLmFwcC5lbmFibGVDb3JzKGNvcnNPcHRpb25zKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb25cbiAgICogQXBwbGllcyB0aGUgSGVsbWV0IG1pZGRsZXdhcmUgZm9yIGVuaGFuY2VkIHNlY3VyaXR5LlxuICAgKlxuICAgKiBAc3VtbWFyeVxuICAgKiBEeW5hbWljYWxseSBsb2FkcyB0aGUgYGhlbG1ldGAgcGFja2FnZSBpZiBhdmFpbGFibGUgYW5kIHJlZ2lzdGVycyBpdFxuICAgKiBhcyBtaWRkbGV3YXJlIHRvIGltcHJvdmUgSFRUUCBoZWFkZXIgc2VjdXJpdHkuIElmIG5vdCBpbnN0YWxsZWQsIGxvZ3MgYSB3YXJuaW5nXG4gICAqIGFuZCBjb250aW51ZXMgZXhlY3V0aW9uIHdpdGhvdXQgdGhyb3dpbmcgZXJyb3JzLlxuICAgKlxuICAgKiBAcGFyYW0ge1JlY29yZDxzdHJpbmcsIGFueT59IFtvcHRpb25zXSAtIE9wdGlvbmFsIGNvbmZpZ3VyYXRpb24gcGFzc2VkIHRvIEhlbG1ldC5cbiAgICogQHJldHVybiB7TmVzdEJvb3RzdHJhcGVyfSBSZXR1cm5zIHRoZSBjbGFzcyBmb3IgY2hhaW5pbmcgY29uZmlndXJhdGlvbi5cbiAgICovXG4gIHN0YXRpYyB1c2VIZWxtZXQob3B0aW9ucz86IFJlY29yZDxzdHJpbmcsIGFueT4pIHtcbiAgICB0cnkge1xuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1yZXF1aXJlLWltcG9ydHNcbiAgICAgIGNvbnN0IGhlbG1ldCA9IHJlcXVpcmUoXCJoZWxtZXRcIik7IC8vIER5bmFtaWMgaW1wb3J0IHRvIGF2b2lkIGhhcmQgZGVwZW5kZW5jeVxuICAgICAgdGhpcy5hcHAudXNlKGhlbG1ldChvcHRpb25zKSk7XG4gICAgICB0aGlzLmxvZ2dlci5sb2coXCJIZWxtZXQgbWlkZGxld2FyZSBlbmFibGVkIHN1Y2Nlc3NmdWxseS5cIik7XG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVudXNlZC12YXJzXG4gICAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgICB0aGlzLmxvZ2dlci53YXJuKFwiSGVsbWV0IG5vdCBpbnN0YWxsZWQuIFNraXBwaW5nIG1pZGRsZXdhcmUuXCIpO1xuICAgIH1cblxuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvblxuICAgKiBDb25maWd1cmVzIGFuZCBpbml0aWFsaXplcyBTd2FnZ2VyIFVJIGZvciBBUEkgZG9jdW1lbnRhdGlvbi5cbiAgICpcbiAgICogQHN1bW1hcnlcbiAgICogVXNlcyB0aGUgYFN3YWdnZXJCdWlsZGVyYCB1dGlsaXR5IHRvIGNvbmZpZ3VyZSBBUEkgZG9jdW1lbnRhdGlvblxuICAgKiB3aXRoIGRldGFpbGVkIGN1c3RvbWl6YXRpb24gZm9yIHRpdGxlLCB2ZXJzaW9uLCBwYXRocywgYW5kIGNvbG9ycy5cbiAgICogU3dhZ2dlciBpcyBhdXRvbWF0aWNhbGx5IGV4cG9zZWQgYXQgdGhlIGNvbmZpZ3VyZWQgcGF0aC5cbiAgICpcbiAgICogQHBhcmFtIHtTd2FnZ2VyU2V0dXBPcHRpb25zfSBvcHRpb25zIC0gU3dhZ2dlciBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gICAqIEByZXR1cm4ge05lc3RCb290c3RyYXBlcn0gUmV0dXJucyB0aGUgY2xhc3MgZm9yIGNoYWluaW5nIGNvbmZpZ3VyYXRpb24uXG4gICAqL1xuICBzdGF0aWMgc2V0dXBTd2FnZ2VyKG9wdGlvbnM6IFN3YWdnZXJTZXR1cE9wdGlvbnMpIHtcbiAgICBjb25zdCBzd2FnZ2VyID0gbmV3IFN3YWdnZXJCdWlsZGVyKHRoaXMuYXBwLCB7XG4gICAgICB0aXRsZTogb3B0aW9ucy50aXRsZSxcbiAgICAgIGRlc2NyaXB0aW9uOiBvcHRpb25zLmRlc2NyaXB0aW9uLFxuICAgICAgdmVyc2lvbjogb3B0aW9ucy52ZXJzaW9uLFxuICAgICAgcGF0aDogb3B0aW9ucy5wYXRoIHx8IFwiYXBpXCIsXG4gICAgICBwZXJzaXN0QXV0aG9yaXphdGlvbjogb3B0aW9ucy5wZXJzaXN0QXV0aG9yaXphdGlvbiA/PyB0cnVlLFxuICAgICAgYXNzZXRzUGF0aDogb3B0aW9ucy5hc3NldHNQYXRoLFxuICAgICAgZmF2aWNvbkZpbGVQYXRoOiBvcHRpb25zLmZhdmljb25QYXRoLFxuICAgICAgdG9wYmFySWNvbkZpbGVQYXRoOiBvcHRpb25zLnRvcGJhckljb25QYXRoLFxuICAgICAgdG9wYmFyQmdDb2xvcjogb3B0aW9ucy50b3BiYXJCZ0NvbG9yLFxuICAgICAgb3BlbkFwaUpzb25QYXRoOiBvcHRpb25zLm9wZW5BcGlKc29uUGF0aCxcbiAgICAgIG9wZW5BcGlZYW1sUGF0aDogb3B0aW9ucy5vcGVuQXBpWWFtbFBhdGgsXG4gICAgfSk7XG4gICAgc3dhZ2dlci5zZXR1cFN3YWdnZXIoKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb25cbiAgICogUmVnaXN0ZXJzIG9uZSBvciBtb3JlIGdsb2JhbCB2YWxpZGF0aW9uIHBpcGVzLlxuICAgKlxuICAgKiBAc3VtbWFyeVxuICAgKiBFbmFibGVzIHJlcXVlc3QgcGF5bG9hZCB2YWxpZGF0aW9uIGFuZCB0cmFuc2Zvcm1hdGlvbiBnbG9iYWxseSBhY3Jvc3NcbiAgICogdGhlIGVudGlyZSBOZXN0SlMgYXBwbGljYXRpb24uIE11bHRpcGxlIHBpcGVzIGNhbiBiZSBjaGFpbmVkIHRvZ2V0aGVyXG4gICAqIGZvciBtb2R1bGFyIGlucHV0IHZhbGlkYXRpb24uXG4gICAqXG4gICAqIEBwYXJhbSB7Li4uUGlwZVRyYW5zZm9ybVtdfSBwaXBlcyAtIFBpcGUgaW5zdGFuY2VzIHRvIHJlZ2lzdGVyIGdsb2JhbGx5LlxuICAgKiBAcmV0dXJuIHtOZXN0Qm9vdHN0cmFwZXJ9IFJldHVybnMgdGhlIGNsYXNzIGZvciBjaGFpbmluZy5cbiAgICovXG4gIHN0YXRpYyB1c2VHbG9iYWxQaXBlcyguLi5waXBlczogUGlwZVRyYW5zZm9ybVtdKSB7XG4gICAgaWYgKHBpcGVzLmxlbmd0aCA+IDApIHRoaXMuYXBwLnVzZUdsb2JhbFBpcGVzKC4uLnBpcGVzKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb25cbiAgICogUmVnaXN0ZXJzIG9uZSBvciBtb3JlIGdsb2JhbCBleGNlcHRpb24gZmlsdGVycy5cbiAgICpcbiAgICogQHN1bW1hcnlcbiAgICogSWYgbm8gZmlsdGVycyBhcmUgcHJvdmlkZWQsIGl0IGF1dG9tYXRpY2FsbHkgcmVnaXN0ZXJzIGEgZGVmYXVsdFxuICAgKiBzZXQgb2Ygc3RhbmRhcmQgZXhjZXB0aW9uIGZpbHRlcnMgZm9yIGNvbW1vbiBlcnJvciB0eXBlcyBsaWtlXG4gICAqIGBIdHRwRXhjZXB0aW9uYCwgYFZhbGlkYXRpb25FeGNlcHRpb25gLCBgQ29uZmxpY3RFeGNlcHRpb25gLCBhbmQgb3RoZXJzLlxuICAgKlxuICAgKiBAcGFyYW0gey4uLkV4Y2VwdGlvbkZpbHRlcltdfSBmaWx0ZXJzIC0gT3B0aW9uYWwgZmlsdGVycyB0byBhcHBseSBnbG9iYWxseS5cbiAgICovXG4gIHN0YXRpYyB1c2VHbG9iYWxGaWx0ZXJzKC4uLmZpbHRlcnM6IGFueVtdKSB7XG4gICAgdGhpcy5hcHAudXNlR2xvYmFsRmlsdGVycyhcbiAgICAgIC4uLihmaWx0ZXJzLmxlbmd0aCA+IDAgPyBmaWx0ZXJzIDogW25ldyBEZWNhZkV4Y2VwdGlvbkZpbHRlcigpXSlcbiAgICApO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvblxuICAgKiBSZWdpc3RlcnMgZ2xvYmFsIGludGVyY2VwdG9ycyBmb3IgcmVxdWVzdCBhbmQgcmVzcG9uc2UgdHJhbnNmb3JtYXRpb24uXG4gICAqXG4gICAqIEBzdW1tYXJ5XG4gICAqIEludGVyY2VwdG9ycyBhbGxvdyBhZHZhbmNlZCByZXF1ZXN0L3Jlc3BvbnNlIG1hbmlwdWxhdGlvbiBzdWNoIGFzXG4gICAqIHNlcmlhbGl6YXRpb24sIGxvZ2dpbmcsIG9yIHRyYW5zZm9ybWF0aW9uLiBNdWx0aXBsZSBpbnRlcmNlcHRvcnNcbiAgICogY2FuIGJlIGFkZGVkIGZvciBtb2R1bGFyIGNvbmZpZ3VyYXRpb24uXG4gICAqXG4gICAqIEBwYXJhbSB7Li4uTmVzdEludGVyY2VwdG9yW119IGludGVyY2VwdG9ycyAtIEludGVyY2VwdG9yIGluc3RhbmNlcyB0byByZWdpc3Rlci5cbiAgICogQHJldHVybiB7TmVzdEJvb3RzdHJhcGVyfSBSZXR1cm5zIHRoZSBjbGFzcyBmb3IgY2hhaW5pbmcgY29uZmlndXJhdGlvbi5cbiAgICovXG4gIHN0YXRpYyB1c2VHbG9iYWxJbnRlcmNlcHRvcnMoLi4uaW50ZXJjZXB0b3JzOiBOZXN0SW50ZXJjZXB0b3JbXSkge1xuICAgIGlmIChpbnRlcmNlcHRvcnMubGVuZ3RoID4gMClcbiAgICAgIHRoaXMuYXBwLnVzZUdsb2JhbEludGVyY2VwdG9ycyguLi5pbnRlcmNlcHRvcnMpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvblxuICAgKiBTdGFydHMgdGhlIE5lc3RKUyBhcHBsaWNhdGlvbiBhbmQgYmluZHMgaXQgdG8gdGhlIGdpdmVuIHBvcnQgYW5kIGhvc3QuXG4gICAqXG4gICAqIEBzdW1tYXJ5XG4gICAqIExpc3RlbnMgb24gdGhlIHNwZWNpZmllZCBwb3J0IGFuZCBvcHRpb25hbGx5IGEgaG9zdC4gT25jZSBzdGFydGVkLFxuICAgKiBsb2dzIHRoZSBhcHBsaWNhdGlvbiBVUkwgZm9yIGVhc3kgYWNjZXNzLiBUaGUgc3RhcnR1cCBwcm9jZXNzIHJlc29sdmVzXG4gICAqIG9uY2UgdGhlIGFwcGxpY2F0aW9uIGlzIHN1Y2Nlc3NmdWxseSBydW5uaW5nLlxuICAgKlxuICAgKiBAcGFyYW0ge251bWJlcn0gW3BvcnQ9MzAwMF0gLSBQb3J0IG51bWJlciB0byBsaXN0ZW4gb24uXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbaG9zdF0gLSBPcHRpb25hbCBob3N0IG9yIElQIGFkZHJlc3MgdG8gYmluZCB0by5cbiAgICogQHBhcmFtIHtib29sZWFufSBbbG9nPXRydWVdIC0gV2hldGhlciB0byBsb2cgdGhlIGFwcGxpY2F0aW9uIFVSTCB1cG9uIHN0YXJ0dXAuXG4gICAqIEByZXR1cm4ge1Byb21pc2U8dm9pZD59IFJlc29sdmVzIG9uY2UgdGhlIGFwcGxpY2F0aW9uIHN0YXJ0cyBzdWNjZXNzZnVsbHkuXG4gICAqL1xuICBzdGF0aWMgYXN5bmMgc3RhcnQoXG4gICAgcG9ydDogbnVtYmVyID0gTnVtYmVyKHByb2Nlc3MuZW52LlBPUlQpIHx8IDMwMDAsXG4gICAgaG9zdDogc3RyaW5nIHwgdW5kZWZpbmVkID0gdW5kZWZpbmVkLFxuICAgIGxvZzogYm9vbGVhbiA9IHRydWVcbiAgKSB7XG4gICAgdGhpcy5hcHAubGlzdGVuKHBvcnQsIGhvc3QgYXMgYW55KS50aGVuKGFzeW5jICgpID0+IHtcbiAgICAgIGlmIChsb2cpIHtcbiAgICAgICAgY29uc3QgdXJsID0gYXdhaXQgdGhpcy5hcHAuZ2V0VXJsKCk7XG4gICAgICAgIHRoaXMubG9nZ2VyLmxvZyhg8J+agCBBcHBsaWNhdGlvbiBpcyBydW5uaW5nIGF0OiAke3VybH1gKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxufVxuIiwiaW1wb3J0IHsgSW5qZWN0IH0gZnJvbSBcIkBuZXN0anMvY29tbW9uXCI7XG5pbXBvcnQgeyBDb25zdHJ1Y3RvciB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdGlvblwiO1xuaW1wb3J0IHtcbiAgaW5qZWN0YWJsZVNlcnZpY2VLZXksXG4gIE1vZGVsU2VydmljZSxcbiAgUmVwb3NpdG9yeSBhcyBDb3JlUmVwb3NpdG9yeSxcbiAgU2VydmljZSBhcyBDb3JlU2VydmljZSxcbn0gZnJvbSBcIkBkZWNhZi10cy9jb3JlXCI7XG5pbXBvcnQgeyBNb2RlbCB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdG9yLXZhbGlkYXRpb25cIjtcblxuZXhwb3J0IHR5cGUgRGVjYWZGYWN0b3J5UHJvdmlkZXIgPSB7XG4gIHByb3ZpZGU6IHN0cmluZztcbiAgdXNlRmFjdG9yeTogKCkgPT4gdW5rbm93bjtcbn07XG5cbmNvbnN0IHBlbmRpbmdQcm92aWRlcnMgPSBuZXcgTWFwPHN0cmluZywgRGVjYWZGYWN0b3J5UHJvdmlkZXI+KCk7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIERyYWlucyB0aGUgcHJvdmlkZXJzIHJlZ2lzdGVyZWQgYnkge0BsaW5rIFNlcnZpY2V9L3tAbGluayBSZXBvc2l0b3J5fSB1c2FnZXMuXG4gKiBAc3VtbWFyeSBDb25zdW1lZCBieSB7QGxpbmsgRGVjYWZDb3JlTW9kdWxlLmZvclJvb3R9IHRvIHdpcmUgdGhlIHRva2VucyB0aGF0IHRob3NlIHBhcmFtZXRlclxuICogZGVjb3JhdG9ycyByZWZlcmVuY2UgYmFjayBpbnRvIE5lc3QncyBESSBjb250YWluZXIsIHNpbmNlIGEgcGFyYW1ldGVyIGRlY29yYXRvciBhbG9uZSBjYW5ub3RcbiAqIHN1cHBseSBhIHByb3ZpZGVyLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0UmVnaXN0ZXJlZERlY2FmUHJvdmlkZXJzKCk6IERlY2FmRmFjdG9yeVByb3ZpZGVyW10ge1xuICByZXR1cm4gQXJyYXkuZnJvbShwZW5kaW5nUHJvdmlkZXJzLnZhbHVlcygpKTtcbn1cblxuZnVuY3Rpb24gcmVnaXN0ZXJQcm92aWRlcih0b2tlbjogc3RyaW5nLCB1c2VGYWN0b3J5OiAoKSA9PiB1bmtub3duKTogdm9pZCB7XG4gIGlmIChwZW5kaW5nUHJvdmlkZXJzLmhhcyh0b2tlbikpIHJldHVybjtcbiAgcGVuZGluZ1Byb3ZpZGVycy5zZXQodG9rZW4sIHsgcHJvdmlkZTogdG9rZW4sIHVzZUZhY3RvcnkgfSk7XG59XG5cbmZ1bmN0aW9uIGlzTW9kZWxDb25zdHJ1Y3Rvcih2YWx1ZTogdW5rbm93bik6IHZhbHVlIGlzIENvbnN0cnVjdG9yPGFueT4ge1xuICByZXR1cm4gdHlwZW9mIHZhbHVlID09PSBcImZ1bmN0aW9uXCIgJiYgdmFsdWUucHJvdG90eXBlIGluc3RhbmNlb2YgTW9kZWw7XG59XG5cbmZ1bmN0aW9uIG1vZGVsU2VydmljZVRva2VuKG1vZGVsOiBDb25zdHJ1Y3Rvcjxhbnk+KTogc3RyaW5nIHtcbiAgcmV0dXJuIGAke21vZGVsLm5hbWV9U2VydmljZWA7XG59XG5cbmZ1bmN0aW9uIG1vZGVsUmVwb3NpdG9yeVRva2VuKFxuICBtb2RlbDogQ29uc3RydWN0b3I8YW55PixcbiAgZmxhdm91cj86IHN0cmluZ1xuKTogc3RyaW5nIHtcbiAgcmV0dXJuIGZsYXZvdXIgPyBgJHttb2RlbC5uYW1lfVJlcG9zaXRvcnlAJHtmbGF2b3VyfWAgOiBgJHttb2RlbC5uYW1lfVJlcG9zaXRvcnlgO1xufVxuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBDb25zdHJ1Y3RvciBwYXJhbWV0ZXIgZGVjb3JhdG9yIHRoYXQgaW5qZWN0cyBhIGRlY2FmIHNlcnZpY2UuXG4gKiBAc3VtbWFyeSBUcmFuc2xhdGVzIGRlY2FmJ3Mgc2VydmljZSByZXNvbHV0aW9uIEFQSXMgaW50byBhIE5lc3QgYEBJbmplY3QoKWAgY2FsbDpcbiAqIC0gYEBTZXJ2aWNlKFNvbWVNb2RlbClgIGluamVjdHMgdGhlIGBNb2RlbFNlcnZpY2U8U29tZU1vZGVsPmAgc2luZ2xldG9uIGZvciB0aGF0IG1vZGVsXG4gKiAgICh2aWEge0BsaW5rIE1vZGVsU2VydmljZS5mb3JNb2RlbH0pLlxuICogLSBgQFNlcnZpY2UoU29tZVNlcnZpY2VDbGFzcylgIG9yIGBAU2VydmljZShcImFsaWFzXCIpYCBpbmplY3RzIHRoZSBtYXRjaGluZyBgQHNlcnZpY2UoKWAtZGVjb3JhdGVkXG4gKiAgIGRlY2FmIHtAbGluayBDb3JlU2VydmljZX0gKHZpYSB7QGxpbmsgQ29yZVNlcnZpY2UuZ2V0fSkuXG4gKiAtIGBAU2VydmljZSgpYCBpbmZlcnMgdGhlIHBhcmFtZXRlcidzIHR5cGUgZnJvbSBlbWl0dGVkIGNvbnN0cnVjdG9yIG1ldGFkYXRhIGFuZCByZXNvbHZlcyBpdCB0aGVcbiAqICAgc2FtZSB3YXksIHByb3ZpZGVkIHRoZSBwYXJhbWV0ZXIgaXMgdHlwZWQgYXMgYSBjb25jcmV0ZSBjbGFzcyAoZ2VuZXJpY3MgbGlrZSBgTW9kZWxTZXJ2aWNlPFg+YFxuICogICBhcmUgZXJhc2VkIGF0IHJ1bnRpbWUsIHNvIHRoZSBtb2RlbC1zZXJ2aWNlIGZvcm0gYWx3YXlzIHJlcXVpcmVzIGFuIGV4cGxpY2l0IGFyZ3VtZW50KS5cbiAqIEBwYXJhbSBrZXkgdGhlIG1vZGVsIGNsYXNzLCBzZXJ2aWNlIGNsYXNzLCBvciBhbGlhcyB0byByZXNvbHZlLiBPbWl0IHRvIGluZmVyIGZyb20gdGhlIHBhcmFtZXRlciB0eXBlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gU2VydmljZShrZXk/OiBzdHJpbmcgfCBDb25zdHJ1Y3Rvcjxhbnk+KTogUGFyYW1ldGVyRGVjb3JhdG9yIHtcbiAgcmV0dXJuIChcbiAgICB0YXJnZXQ6IG9iamVjdCxcbiAgICBwcm9wZXJ0eUtleTogc3RyaW5nIHwgc3ltYm9sIHwgdW5kZWZpbmVkLFxuICAgIHBhcmFtZXRlckluZGV4OiBudW1iZXJcbiAgKTogdm9pZCA9PiB7XG4gICAgbGV0IHJlc29sdmVkOiBzdHJpbmcgfCBDb25zdHJ1Y3Rvcjxhbnk+IHwgdW5kZWZpbmVkID0ga2V5O1xuICAgIGlmICh0eXBlb2YgcmVzb2x2ZWQgPT09IFwidW5kZWZpbmVkXCIpIHtcbiAgICAgIGNvbnN0IHBhcmFtVHlwZXM6IGFueVtdID1cbiAgICAgICAgUmVmbGVjdC5nZXRNZXRhZGF0YShcImRlc2lnbjpwYXJhbXR5cGVzXCIsIHRhcmdldCkgfHwgW107XG4gICAgICByZXNvbHZlZCA9IHBhcmFtVHlwZXNbcGFyYW1ldGVySW5kZXhdO1xuICAgIH1cbiAgICBpZiAodHlwZW9mIHJlc29sdmVkID09PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBAU2VydmljZSgpIGNvdWxkIG5vdCBkZXRlcm1pbmUgYW4gaW5qZWN0aW9uIHR5cGUgZm9yIHBhcmFtZXRlciAke3BhcmFtZXRlckluZGV4fSBvZiAkeyh0YXJnZXQgYXMgQ29uc3RydWN0b3I8YW55PikubmFtZX0uIFByb3ZpZGUgYW4gZXhwbGljaXQgYXJndW1lbnQsIGUuZy4gQFNlcnZpY2UoU29tZVNlcnZpY2UpLmBcbiAgICAgICk7XG4gICAgfVxuXG4gICAgY29uc3QgYXNNb2RlbCA9IHR5cGVvZiByZXNvbHZlZCAhPT0gXCJzdHJpbmdcIiAmJiBpc01vZGVsQ29uc3RydWN0b3IocmVzb2x2ZWQpO1xuICAgIGNvbnN0IHRva2VuID0gYXNNb2RlbFxuICAgICAgPyBtb2RlbFNlcnZpY2VUb2tlbihyZXNvbHZlZCBhcyBDb25zdHJ1Y3Rvcjxhbnk+KVxuICAgICAgOiBpbmplY3RhYmxlU2VydmljZUtleShyZXNvbHZlZCBhcyBzdHJpbmcgfCBDb25zdHJ1Y3Rvcjxhbnk+KTtcblxuICAgIHJlZ2lzdGVyUHJvdmlkZXIodG9rZW4sICgpID0+IHtcbiAgICAgIGlmIChhc01vZGVsKSByZXR1cm4gTW9kZWxTZXJ2aWNlLmZvck1vZGVsKHJlc29sdmVkIGFzIENvbnN0cnVjdG9yPGFueT4pO1xuICAgICAgcmV0dXJuIHR5cGVvZiByZXNvbHZlZCA9PT0gXCJzdHJpbmdcIlxuICAgICAgICA/IENvcmVTZXJ2aWNlLmdldChyZXNvbHZlZClcbiAgICAgICAgOiBDb3JlU2VydmljZS5nZXQocmVzb2x2ZWQgYXMgQ29uc3RydWN0b3I8YW55Pik7XG4gICAgfSk7XG5cbiAgICByZXR1cm4gSW5qZWN0KHRva2VuKSh0YXJnZXQsIHByb3BlcnR5S2V5LCBwYXJhbWV0ZXJJbmRleCk7XG4gIH07XG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIENvbnN0cnVjdG9yIHBhcmFtZXRlciBkZWNvcmF0b3IgdGhhdCBpbmplY3RzIGEgZGVjYWYge0BsaW5rIENvcmVSZXBvc2l0b3J5fSBmb3IgYG1vZGVsYC5cbiAqIEBzdW1tYXJ5IFVubGlrZSB7QGxpbmsgU2VydmljZX0sIGBtb2RlbGAgaXMgYWx3YXlzIHRyZWF0ZWQgYXMgYSBNb2RlbCBjbGFzczogdGhlIHNhbWUgY2xhc3MgcGFzc2VkXG4gKiB0byBgQFNlcnZpY2UobW9kZWwpYCBhbmQgYEBSZXBvc2l0b3J5KG1vZGVsKWAgcmVzb2x2ZXMgdG8gdHdvIGRpZmZlcmVudCBpbmplY3RlZCBvYmplY3RzIChhXG4gKiBgTW9kZWxTZXJ2aWNlPE0+YCB2cyBhIGBSZXBvc2l0b3J5PE0+YCByZXNwZWN0aXZlbHkpLCB2aWEge0BsaW5rIENvcmVSZXBvc2l0b3J5LmZvck1vZGVsfS5cbiAqIEBwYXJhbSBtb2RlbCB0aGUgbW9kZWwgY2xhc3MgdG8gcmVzb2x2ZSBhIHJlcG9zaXRvcnkgZm9yLlxuICogQHBhcmFtIGZsYXZvdXIgb3B0aW9uYWwgYWRhcHRlciBmbGF2b3VyL2FsaWFzLCBmb3J3YXJkZWQgdG8ge0BsaW5rIENvcmVSZXBvc2l0b3J5LmZvck1vZGVsfS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIFJlcG9zaXRvcnkoXG4gIG1vZGVsOiBDb25zdHJ1Y3Rvcjxhbnk+LFxuICBmbGF2b3VyPzogc3RyaW5nXG4pOiBQYXJhbWV0ZXJEZWNvcmF0b3Ige1xuICByZXR1cm4gKFxuICAgIHRhcmdldDogb2JqZWN0LFxuICAgIHByb3BlcnR5S2V5OiBzdHJpbmcgfCBzeW1ib2wgfCB1bmRlZmluZWQsXG4gICAgcGFyYW1ldGVySW5kZXg6IG51bWJlclxuICApOiB2b2lkID0+IHtcbiAgICBjb25zdCB0b2tlbiA9IG1vZGVsUmVwb3NpdG9yeVRva2VuKG1vZGVsLCBmbGF2b3VyKTtcbiAgICByZWdpc3RlclByb3ZpZGVyKHRva2VuLCAoKSA9PiBDb3JlUmVwb3NpdG9yeS5mb3JNb2RlbChtb2RlbCwgZmxhdm91cikpO1xuICAgIHJldHVybiBJbmplY3QodG9rZW4pKHRhcmdldCwgcHJvcGVydHlLZXksIHBhcmFtZXRlckluZGV4KTtcbiAgfTtcbn1cbiIsImltcG9ydCB7XG4gIER5bmFtaWNNb2R1bGUsXG4gIEdsb2JhbCxcbiAgSW5qZWN0LFxuICBNb2R1bGUsXG4gIE9uQXBwbGljYXRpb25TaHV0ZG93bixcbn0gZnJvbSBcIkBuZXN0anMvY29tbW9uXCI7XG5pbXBvcnQgeyBBUFBfSU5URVJDRVBUT1IsIE1vZHVsZVJlZiB9IGZyb20gXCJAbmVzdGpzL2NvcmVcIjtcbmltcG9ydCB0eXBlIHsgRGVjYWZNb2R1bGVPcHRpb25zIH0gZnJvbSBcIi4vdHlwZXNcIjtcbmltcG9ydCB7XG4gIERFQ0FGX0FEQVBURVJfSUQsXG4gIERFQ0FGX0hBTkRMRVJTLFxuICBERUNBRl9NT0RVTEVfT1BUSU9OUyxcbn0gZnJvbSBcIi4vY29uc3RhbnRzXCI7XG5pbXBvcnQge1xuICBEZWNhZlJlcXVlc3RIYW5kbGVySW50ZXJjZXB0b3IsXG59IGZyb20gXCIuL2ludGVyY2VwdG9yc1wiO1xuaW1wb3J0IHsgRGVjYWZIYW5kbGVyRXhlY3V0b3IsIERlY2FmUmVxdWVzdENvbnRleHQgfSBmcm9tIFwiLi9yZXF1ZXN0XCI7XG5pbXBvcnQgeyBDb25zdHJ1Y3RvciB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdGlvblwiO1xuaW1wb3J0IHsgQWRhcHRlciwgUGVyc2lzdGVuY2VTZXJ2aWNlLCBTZXJ2aWNlIH0gZnJvbSBcIkBkZWNhZi10cy9jb3JlXCI7XG5pbXBvcnQgeyBnZXRSZWdpc3RlcmVkRGVjYWZQcm92aWRlcnMgfSBmcm9tIFwiLi9kZWNvcmF0b3JzXCI7XG5pbXBvcnQgeyBJbnRlcm5hbEVycm9yIH0gZnJvbSBcIkBkZWNhZi10cy9kYi1kZWNvcmF0b3JzXCI7XG5pbXBvcnQgeyBMb2dnZXIsIExvZ2dpbmcgfSBmcm9tIFwiQGRlY2FmLXRzL2xvZ2dpbmdcIjtcbmltcG9ydCB7XG4gIFJlcXVlc3RUb0NvbnRleHRUcmFuc2Zvcm1lcixcbiAgcmVxdWVzdFRvQ29udGV4dFRyYW5zZm9ybWVyLFxufSBmcm9tIFwiQGRlY2FmLXRzL2Zvci1odHRwL3NlcnZlclwiO1xuXG5AR2xvYmFsKClcbkBNb2R1bGUoe30pXG5leHBvcnQgY2xhc3MgRGVjYWZDb3JlTW9kdWxlPENPTkYsIEFEQVBURVIgZXh0ZW5kcyBBZGFwdGVyPENPTkYsIGFueSwgYW55LCBhbnk+PlxuICBpbXBsZW1lbnRzIE9uQXBwbGljYXRpb25TaHV0ZG93blxue1xuICBwcml2YXRlIHN0YXRpYyBfbG9nZ2VyOiBMb2dnZXI7XG5cbiAgcHJpdmF0ZSBzdGF0aWMgX3BlcnNpc3RlbmNlPzogUGVyc2lzdGVuY2VTZXJ2aWNlPEFkYXB0ZXI8YW55LCBhbnksIGFueSwgYW55Pj47XG5cbiAgcHJvdGVjdGVkIHN0YXRpYyBnZXQgcGVyc2lzdGVuY2UoKTogUGVyc2lzdGVuY2VTZXJ2aWNlPEFkYXB0ZXI8YW55LCBhbnksIGFueSwgYW55Pj4ge1xuICAgIGlmICghdGhpcy5fcGVyc2lzdGVuY2UpXG4gICAgICB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihcIlBlcnNpc3RlbmNlIHNlcnZpY2Ugbm90IGluaXRpYWxpemVkXCIpO1xuICAgIHJldHVybiB0aGlzLl9wZXJzaXN0ZW5jZTtcbiAgfVxuXG4gIHByb3RlY3RlZCBzdGF0aWMgZ2V0IGxvZygpOiBMb2dnZXIge1xuICAgIGlmICghdGhpcy5fbG9nZ2VyKSB0aGlzLl9sb2dnZXIgPSBMb2dnaW5nLmZvcihEZWNhZkNvcmVNb2R1bGUpO1xuICAgIHJldHVybiB0aGlzLl9sb2dnZXI7XG4gIH1cblxuICBjb25zdHJ1Y3RvcihcbiAgICBASW5qZWN0KERFQ0FGX01PRFVMRV9PUFRJT05TKVxuICAgIHByaXZhdGUgcmVhZG9ubHkgb3B0aW9uczogRGVjYWZNb2R1bGVPcHRpb25zPENPTkYsIEFEQVBURVI+LFxuICAgIHByaXZhdGUgcmVhZG9ubHkgbW9kdWxlUmVmOiBNb2R1bGVSZWZcbiAgKSB7fVxuXG4gIHN0YXRpYyBmb3JSb290KG9wdGlvbnM6IERlY2FmTW9kdWxlT3B0aW9ucyk6IER5bmFtaWNNb2R1bGUge1xuICAgIGNvbnN0IGxvZyA9IHRoaXMubG9nLmZvcih0aGlzLmZvclJvb3QpO1xuICAgIGNvbnN0IGRlY2FmUHJvdmlkZXJzID0gZ2V0UmVnaXN0ZXJlZERlY2FmUHJvdmlkZXJzKCk7XG4gICAgcmV0dXJuIHtcbiAgICAgIG1vZHVsZTogRGVjYWZDb3JlTW9kdWxlLFxuICAgICAgcHJvdmlkZXJzOiBbXG4gICAgICAgIHsgcHJvdmlkZTogREVDQUZfTU9EVUxFX09QVElPTlMsIHVzZVZhbHVlOiBvcHRpb25zIH0sXG4gICAgICAgIHsgcHJvdmlkZTogREVDQUZfQURBUFRFUl9JRCwgdXNlVmFsdWU6IHRoaXMucGVyc2lzdGVuY2U/LmNsaWVudCB9LFxuICAgICAgICB7XG4gICAgICAgICAgcHJvdmlkZTogREVDQUZfSEFORExFUlMsXG4gICAgICAgICAgdXNlRmFjdG9yeTogKCkgPT5cbiAgICAgICAgICAgIG9wdGlvbnMuaGFuZGxlcnM/Lm1hcCgoSCkgPT4ge1xuICAgICAgICAgICAgICBsb2cuaW5mbyhgUmVnaXN0ZXJlZCByZXF1ZXN0IGhhbmRsZXI6ICR7SC5uYW1lfWApO1xuICAgICAgICAgICAgICByZXR1cm4gbmV3IEgoKTtcbiAgICAgICAgICAgIH0pID8/IFtdLFxuICAgICAgICB9LFxuICAgICAgICBEZWNhZlJlcXVlc3RDb250ZXh0LFxuICAgICAgICBEZWNhZkhhbmRsZXJFeGVjdXRvcixcbiAgICAgICAge1xuICAgICAgICAgIHByb3ZpZGU6IEFQUF9JTlRFUkNFUFRPUixcbiAgICAgICAgICB1c2VDbGFzczogRGVjYWZSZXF1ZXN0SGFuZGxlckludGVyY2VwdG9yLFxuICAgICAgICB9LFxuICAgICAgICAuLi5kZWNhZlByb3ZpZGVycyxcbiAgICAgIF0sXG4gICAgICBleHBvcnRzOiBbXG4gICAgICAgIERFQ0FGX01PRFVMRV9PUFRJT05TLFxuICAgICAgICBERUNBRl9BREFQVEVSX0lELFxuICAgICAgICBERUNBRl9IQU5ETEVSUyxcbiAgICAgICAgRGVjYWZSZXF1ZXN0Q29udGV4dCxcbiAgICAgICAgRGVjYWZIYW5kbGVyRXhlY3V0b3IsXG4gICAgICAgIC4uLmRlY2FmUHJvdmlkZXJzLm1hcCgocHJvdmlkZXIpID0+IHByb3ZpZGVyLnByb3ZpZGUpLFxuICAgICAgXSxcbiAgICB9O1xuICB9XG5cbiAgc3RhdGljIGFzeW5jIGJvb3RQZXJzaXN0ZW5jZShcbiAgICBvcHRpb25zOiBEZWNhZk1vZHVsZU9wdGlvbnNcbiAgKTogUHJvbWlzZTxBZGFwdGVyPGFueSwgYW55LCBhbnksIGFueT5bXT4ge1xuICAgIGNvbnN0IGxvZyA9IHRoaXMubG9nLmZvcih0aGlzLmJvb3RQZXJzaXN0ZW5jZSk7XG5cbiAgICBpZiAoIXRoaXMuX3BlcnNpc3RlbmNlKSB7XG4gICAgICBjb25zdCB0cmltbWVkID0gb3B0aW9ucy5jb25mLm1hcCgoW2NvbnRyLCBjZmcsIC4uLmFyZ3NdKSA9PiB7XG4gICAgICAgIGNvbnN0IHBvc3NpYmxlID0gYXJncy5wb3AoKTtcbiAgICAgICAgaWYgKCFwb3NzaWJsZSkgcmV0dXJuIFtjb250ciwgY2ZnXTtcbiAgICAgICAgcmV0dXJuIFtjb250ciwgY2ZnLCAuLi5hcmdzXTtcbiAgICAgIH0pO1xuICAgICAgdGhpcy5fcGVyc2lzdGVuY2UgPSBuZXcgUGVyc2lzdGVuY2VTZXJ2aWNlKCk7XG4gICAgICBhd2FpdCB0aGlzLl9wZXJzaXN0ZW5jZS5ib290KHRyaW1tZWQpO1xuICAgICAgY29uc3QgY2xpZW50cyA9IHRoaXMuX3BlcnNpc3RlbmNlLmNsaWVudDtcbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgY2xpZW50cy5sZW5ndGg7IGkrKykge1xuICAgICAgICBjb25zdCBjID0gb3B0aW9ucy5jb25mW2ldO1xuICAgICAgICBjb25zdCBwb3NzaWJsZVRyYW5zZiA9IGMuc2xpY2UoMiwgYy5sZW5ndGgpO1xuICAgICAgICBsZXQgdHJhbnNmb3JtZXIgPSBwb3NzaWJsZVRyYW5zZi5wb3AoKTtcbiAgICAgICAgaWYgKFxuICAgICAgICAgICF0cmFuc2Zvcm1lciB8fFxuICAgICAgICAgICEodHJhbnNmb3JtZXIgYXMgUmVxdWVzdFRvQ29udGV4dFRyYW5zZm9ybWVyPGFueT4pLmZyb21cbiAgICAgICAgKSB7XG4gICAgICAgICAgY29uc3QgY29udHIgPSBBZGFwdGVyLnRyYW5zZm9ybWVyRm9yKGNsaWVudHNbaV0uZmxhdm91cik7XG4gICAgICAgICAgaWYgKCFjb250cilcbiAgICAgICAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFxuICAgICAgICAgICAgICBgTm8gdHJhbnNmb3JtZXIgZm91bmQgZm9yIGZsYXZvdXIgJHtjbGllbnRzW2ldLmZsYXZvdXJ9LiB5b3Ugc2hvdWxkIGVpdGhlciBAcmVxdWVzdFRvQ29udGV4dFRyYW5zZm9ybWVyIG9yIHByb3ZpZGUgYSB0cmFuc2Zvcm1lciBpbiB0aGUgY29uZmlnYFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgdHJhbnNmb3JtZXIgPSAoY29udHIgYXMgUmVxdWVzdFRvQ29udGV4dFRyYW5zZm9ybWVyPGFueT4pLmZyb21cbiAgICAgICAgICAgICAgPyBjb250clxuICAgICAgICAgICAgICA6IG5ldyAoY29udHIgYXMgQ29uc3RydWN0b3I8UmVxdWVzdFRvQ29udGV4dFRyYW5zZm9ybWVyPGFueT4+KSgpO1xuICAgICAgICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFxuICAgICAgICAgICAgICBgRmFpbGVkIHRvIGJvb3QgdHJhbnNmb3JtZXIgZm9yICR7Y2xpZW50c1tpXS5mbGF2b3VyfTogJHtlfWBcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJlcXVlc3RUb0NvbnRleHRUcmFuc2Zvcm1lcihjbGllbnRzW2ldLmZsYXZvdXIpKHRyYW5zZm9ybWVyKTtcbiAgICAgIH1cbiAgICAgIGxvZy5pbmZvKFwicGVyc2lzdGVuY2UgbGF5ZXIgY3JlYXRlZCBzdWNjZXNzZnVsbHkhXCIpO1xuXG4gICAgICBpZiAob3B0aW9ucy5pbml0aWFsaXphdGlvbikge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGF3YWl0IG9wdGlvbnMuaW5pdGlhbGl6YXRpb24oKTtcbiAgICAgICAgfSBjYXRjaCAoZTogdW5rbm93bikge1xuICAgICAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKGBGYWlsZWQgdG8gaW5pdGlhbGl6ZSBhcHBsaWNhdGlvbjogJHtlfWApO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMucGVyc2lzdGVuY2UuY2xpZW50O1xuICB9XG5cbiAgYXN5bmMgb25BcHBsaWNhdGlvblNodXRkb3duKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IGxvZyA9IERlY2FmQ29yZU1vZHVsZS5sb2cuZm9yKHRoaXMub25BcHBsaWNhdGlvblNodXRkb3duKTtcbiAgICBjb25zdCBhZGFwdGVyczogQWRhcHRlcjxhbnksIGFueSwgYW55LCBhbnk+W10gPVxuICAgICAgdGhpcy5tb2R1bGVSZWYuZ2V0PGFueT4oREVDQUZfQURBUFRFUl9JRCk7XG4gICAgZm9yIChjb25zdCBhZGFwdGVyIG9mIGFkYXB0ZXJzKVxuICAgICAgdHJ5IHtcbiAgICAgICAgaWYgKGFkYXB0ZXIpIHtcbiAgICAgICAgICBsb2cuaW5mbyhgU2h1dHRpbmcgZG93biAke2FkYXB0ZXIudG9TdHJpbmcoKX1gKTtcbiAgICAgICAgICBhd2FpdCBhZGFwdGVyLnNodXRkb3duKCk7XG4gICAgICAgIH1cbiAgICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgICAgbG9nLmVycm9yKGBGYWlsZWQgdG8gc2h1dGRvd24gYXBwbGljYXRpb25gLCBlIGFzIEVycm9yKTtcbiAgICAgIH1cbiAgICB0cnkge1xuICAgICAgYXdhaXQgU2VydmljZS5zaHV0ZG93bigpO1xuICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgIGxvZy5lcnJvcihgRmFpbGVkIHRvIHNodXRkb3duIHNlcnZpY2VzYCwgZSBhcyBFcnJvcik7XG4gICAgfVxuICB9XG59XG4iLCJleHBvcnQgY29uc3QgTElTVEVOSU5HX0FEQVBURVJTX0ZMQVZPVVJTID0gU3ltYm9sKFxuICBcIkxJU1RFTklOR19BREFQVEVSU19GTEFWT1VSU1wiXG4pO1xuIiwiaW1wb3J0IHsgTW9kZWwgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRvci12YWxpZGF0aW9uXCI7XG5cbmV4cG9ydCBmdW5jdGlvbiBub3JtYWxpemVFdmVudFJlc3BvbnNlKGFyZ3M6IGFueVtdKTogdW5rbm93bltdIHtcbiAgY29uc3QgW21vZGVsQ29uc3RyLCBvcGVyYXRpb24sIGlkLCBwYXlsb2FkXSA9IGFyZ3M7XG5cbiAgY29uc3QgbW9kZWxOYW1lID0gbW9kZWxDb25zdHI/Lm5hbWUgPz8gbW9kZWxDb25zdHI7XG5cbiAgY29uc3Qgc2VyaWFsaXplZFBheWxvYWQgPSBBcnJheS5pc0FycmF5KHBheWxvYWQpXG4gICAgPyBwYXlsb2FkLm1hcCgoZSkgPT4ge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGlmICh0eXBlb2YgZS5zZXJpYWxpemUgPT09IFwiZnVuY3Rpb25cIikgcmV0dXJuIGUuc2VyaWFsaXplKCk7XG5cbiAgICAgICAgICBjb25zb2xlLndhcm4oXG4gICAgICAgICAgICBgUGF5bG9hZCBpdGVtIGZvciAke21vZGVsTmFtZX0gZG9lcyBub3QgaGF2ZSBzZXJpYWxpemUgbWV0aG9kIGFuZCBpcyBhbiAke3R5cGVvZiBlfSwgYXR0ZW1wdGluZyB0byBzdHJpbmdpZnkgZGlyZWN0bHkuIEl0ZW06ICR7ZX1gXG4gICAgICAgICAgKTtcbiAgICAgICAgICByZXR1cm4gdHlwZW9mIGUgPT09IFwic3RyaW5nXCIgPyBlIDogSlNPTi5zdHJpbmdpZnkoZSk7XG4gICAgICAgIH0gY2F0Y2ggKGVycjogdW5rbm93bikge1xuICAgICAgICAgIGNvbnNvbGUud2FybihgRmFpbGVkIHRvIHNlcmlhbGl6ZSBwYXlsb2FkIGZvciAke21vZGVsTmFtZX06ICR7ZXJyfWApO1xuICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgIH1cbiAgICAgIH0pXG4gICAgOiBwYXlsb2FkICYmIHR5cGVvZiBwYXlsb2FkLnNlcmlhbGl6ZSA9PT0gXCJmdW5jdGlvblwiXG4gICAgICA/IHBheWxvYWQuc2VyaWFsaXplKClcbiAgICAgIDogdHlwZW9mIHBheWxvYWQgPT09IFwic3RyaW5nXCJcbiAgICAgICAgPyBwYXlsb2FkXG4gICAgICAgIDogSlNPTi5zdHJpbmdpZnkocGF5bG9hZCk7XG5cbiAgY29uc29sZS5kZWJ1ZyhcbiAgICBgTm9ybWFsaXplZCBldmVudCByZXNwb25zZSBmb3IgbW9kZWwgJHttb2RlbE5hbWV9LCBvcGVyYXRpb24gJHtvcGVyYXRpb259LCBpZCAke2lkfTpgLFxuICAgIHNlcmlhbGl6ZWRQYXlsb2FkXG4gICk7XG5cbiAgcmV0dXJuIFttb2RlbE5hbWUsIG9wZXJhdGlvbiwgaWQsIHNlcmlhbGl6ZWRQYXlsb2FkXTtcbn1cbiIsImltcG9ydCB7IERlY2FmQ29udHJvbGxlciB9IGZyb20gXCIuLi9jb250cm9sbGVyc1wiO1xuaW1wb3J0IHsgRGVjYWZSZXF1ZXN0Q29udGV4dCB9IGZyb20gXCIuLi9yZXF1ZXN0XCI7XG5pbXBvcnQgeyBBZGFwdGVyLCBPYnNlcnZlciB9IGZyb20gXCJAZGVjYWYtdHMvY29yZVwiO1xuaW1wb3J0IHsgQ29udHJvbGxlciwgSW5qZWN0LCBNZXNzYWdlRXZlbnQsIFF1ZXJ5LCBTc2UgfSBmcm9tIFwiQG5lc3Rqcy9jb21tb25cIjtcbmltcG9ydCB7IGludGVydmFsLCBtZXJnZSwgT2JzZXJ2YWJsZSB9IGZyb20gXCJyeGpzXCI7XG5pbXBvcnQgeyBMb2dnaW5nIH0gZnJvbSBcIkBkZWNhZi10cy9sb2dnaW5nXCI7XG5pbXBvcnQgeyBMSVNURU5JTkdfQURBUFRFUlNfRkxBVk9VUlMgfSBmcm9tIFwiLi9jb25zdGFudFwiO1xuaW1wb3J0IHsgRGVjYWZTZXJ2ZXJDdHggfSBmcm9tIFwiLi4vY29uc3RhbnRzXCI7XG5pbXBvcnQgeyBub3JtYWxpemVFdmVudFJlc3BvbnNlIH0gZnJvbSBcIi4vdXRpbHNcIjtcbmltcG9ydCB7IG1hcCwgdGFwIH0gZnJvbSBcInJ4anMvb3BlcmF0b3JzXCI7XG5cbkBDb250cm9sbGVyKClcbmV4cG9ydCBjbGFzcyBFdmVudHNDb250cm9sbGVyIGV4dGVuZHMgRGVjYWZDb250cm9sbGVyPERlY2FmU2VydmVyQ3R4PiB7XG4gIHByaXZhdGUgcmVhZG9ubHkgYWRhcHRlcnM6IEFkYXB0ZXI8YW55LCBhbnksIGFueSwgYW55PltdO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIGNsaWVudENvbnRleHQ6IERlY2FmUmVxdWVzdENvbnRleHQsXG4gICAgQEluamVjdChMSVNURU5JTkdfQURBUFRFUlNfRkxBVk9VUlMpIGZsYXZvdXJzOiBzdHJpbmdbXVxuICApIHtcbiAgICBzdXBlcihjbGllbnRDb250ZXh0LCBFdmVudHNDb250cm9sbGVyLm5hbWUpO1xuICAgIHRoaXMuYWRhcHRlcnMgPSBmbGF2b3Vycy5tYXAoKGZsYXZvdXIpID0+IChBZGFwdGVyIGFzIGFueSkuZ2V0KGZsYXZvdXIpKTsgLy8gY2hhbmdlIHRvIEFkYXB0ZXIuY2FjaGUoXCJcIilcbiAgfVxuXG4gIEBTc2UoKVxuICBsaXN0ZW4oKTogT2JzZXJ2YWJsZTxNZXNzYWdlRXZlbnQ+IHtcbiAgICBjb25zdCBsb2dnZXIgPSBMb2dnaW5nLmZvcihFdmVudHNDb250cm9sbGVyLm5hbWUpO1xuXG4gICAgY29uc3QgZXZlbnRzJCA9IG5ldyBPYnNlcnZhYmxlPE1lc3NhZ2VFdmVudD4oKG9ic2VydmVyKSA9PiB7XG4gICAgICBjb25zdCBvYnNlcnZlcklkID1cbiAgICAgICAgYEItJHtNYXRoLnJhbmRvbSgpLnRvU3RyaW5nKDM2KS5zbGljZSgyLCA4KX1gLnRvVXBwZXJDYXNlKCk7XG5cbiAgICAgIGxvZ2dlci5pbmZvKFxuICAgICAgICBgQ3JlYXRpbmcgU1NFIG9ic2VydmVyOiAke29ic2VydmVySWR9IGZvciBjbGllbnQgJHt0aGlzLmNsaWVudENvbnRleHQudXVpZH1gXG4gICAgICApO1xuICAgICAgY29uc3QgY2IgPSBuZXcgKGNsYXNzIGltcGxlbWVudHMgT2JzZXJ2ZXIge1xuICAgICAgICBvYnNlcnZlcklkID0gb2JzZXJ2ZXJJZDtcbiAgICAgICAgcmVmcmVzaCguLi5hcmdzOiBhbnlbXSk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICAgIGxvZ2dlci5kZWJ1ZyhcbiAgICAgICAgICAgIGBTU0Ugb2JzZXJ2ZXIgJHt0aGlzLm9ic2VydmVySWR9IHJlY2VpdmVkIHJlZnJlc2ggZXZlbnRgXG4gICAgICAgICAgKTtcbiAgICAgICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKCkudGhlbigoKSA9PiB7XG4gICAgICAgICAgICBjb25zdCBkYXRhID0gbm9ybWFsaXplRXZlbnRSZXNwb25zZShhcmdzKTtcbiAgICAgICAgICAgIG9ic2VydmVyLm5leHQoeyB0eXBlOiBcIm1lc3NhZ2VcIiwgZGF0YSB9KTtcbiAgICAgICAgICAgIGxvZ2dlci5kZWJ1ZyhcbiAgICAgICAgICAgICAgYFNTRSBvYnNlcnZlciAke3RoaXMub2JzZXJ2ZXJJZH0gZXZlbnQgcHVzaGVkIHRvIGNsaWVudGBcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIH0pKCk7XG5cbiAgICAgIGxvZ2dlci52ZXJib3NlKFxuICAgICAgICBgUmVnaXN0ZXJpbmcgb2JzZXJ2ZXIgJHtvYnNlcnZlcklkfSBhY3Jvc3MgJHt0aGlzLmFkYXB0ZXJzLmxlbmd0aH0gYWRhcHRlcihzKWBcbiAgICAgICk7XG4gICAgICBmb3IgKGNvbnN0IGFkYXB0ZXIgb2YgdGhpcy5hZGFwdGVycykge1xuICAgICAgICBjb25zdCBhZGFwdGVyTmFtZSA9IGFkYXB0ZXI/LmNvbnN0cnVjdG9yPy5uYW1lID8/IFwiVW5rbm93bkFkYXB0ZXJcIjtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBsb2dnZXIuZGVidWcoXG4gICAgICAgICAgICBgUmVnaXN0ZXJpbmcgb2JzZXJ2ZXIgJHtvYnNlcnZlcklkfSBpbiBhZGFwdGVyICR7YWRhcHRlck5hbWV9YFxuICAgICAgICAgICk7XG4gICAgICAgICAgYWRhcHRlci5vYnNlcnZlKGNiKTtcbiAgICAgICAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgICAgICAgbG9nZ2VyLmRlYnVnKFxuICAgICAgICAgICAgYEZhaWxlZCB0byByZWdpc3RlciBvYnNlcnZlciAke29ic2VydmVySWR9IGluIGFkYXB0ZXIgJHthZGFwdGVyTmFtZX06ICR7ZT8ubWVzc2FnZSB8fCBlfWBcbiAgICAgICAgICApO1xuICAgICAgICAgIGxvZ2dlci5lcnJvcihlKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICByZXR1cm4gKCkgPT4ge1xuICAgICAgICBsb2dnZXIuZGVidWcoYENsZWFuaW5nIHVwIFNTRSBvYnNlcnZlciAke29ic2VydmVySWR9YCk7XG5cbiAgICAgICAgZm9yIChjb25zdCBhZGFwdGVyIG9mIHRoaXMuYWRhcHRlcnMpIHtcbiAgICAgICAgICBjb25zdCBhZGFwdGVyTmFtZSA9IGFkYXB0ZXI/LmNvbnN0cnVjdG9yPy5uYW1lID8/IFwiVW5rbm93bkFkYXB0ZXJcIjtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgbG9nZ2VyLmRlYnVnKFxuICAgICAgICAgICAgICBgVW5yZWdpc3RlcmluZyBvYnNlcnZlciAke29ic2VydmVySWR9IGZyb20gYWRhcHRlciAke2FkYXB0ZXJOYW1lfWBcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICBhZGFwdGVyLnVuT2JzZXJ2ZShjYik7XG4gICAgICAgICAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgICAgICAgICBsb2dnZXIuZGVidWcoXG4gICAgICAgICAgICAgIGBGYWlsZWQgZHVyaW5nIGNsZWFudXAgb2Ygb2JzZXJ2ZXIgJHtvYnNlcnZlcklkfSBpbiBhZGFwdGVyICR7YWRhcHRlck5hbWV9OiAke2U/Lm1lc3NhZ2UgfHwgZX1gXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgbG9nZ2VyLmVycm9yKGUpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfTtcbiAgICB9KTtcblxuICAgIGNvbnN0IEhFQVJUQkVBVF9JTlRFUlZBTF9NUyA9IDE1MDAwO1xuICAgIGNvbnN0IGhlYXJ0YmVhdCQgPSBpbnRlcnZhbChIRUFSVEJFQVRfSU5URVJWQUxfTVMpLnBpcGUoXG4gICAgICB0YXAoKCkgPT4ge1xuICAgICAgICBsb2dnZXIuZGVidWcoXCJTZW5kaW5nIGhlYXJ0YmVhdFwiKTtcbiAgICAgIH0pLFxuICAgICAgbWFwKFxuICAgICAgICAoKTogTWVzc2FnZUV2ZW50ID0+ICh7XG4gICAgICAgICAgdHlwZTogXCJoZWFydGJlYXRcIixcbiAgICAgICAgICBkYXRhOiB7XG4gICAgICAgICAgICB0czogbmV3IERhdGUoKS50b0lTT1N0cmluZygpLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0pXG4gICAgICApXG4gICAgKTtcblxuICAgIHJldHVybiBtZXJnZShldmVudHMkLCBoZWFydGJlYXQkKTtcbiAgfVxuXG4gIEBTc2UoXCIvOm1vZGVsXCIpXG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnNcbiAgbGlzdGVuRm9yTW9kZWwoQFF1ZXJ5KFwibW9kZWxcIikgbW9kZWw6IHN0cmluZyk6IE9ic2VydmFibGU8TWVzc2FnZUV2ZW50PiB7XG4gICAgY29uc3QgbG9nZ2VyID0gTG9nZ2luZy5mb3IoRXZlbnRzQ29udHJvbGxlci5uYW1lKTtcblxuICAgIHJldHVybiBuZXcgT2JzZXJ2YWJsZTxNZXNzYWdlRXZlbnQ+KChvYnNlcnZlcikgPT4ge1xuICAgICAgY29uc3QgY2IgPSBuZXcgKGNsYXNzIGltcGxlbWVudHMgT2JzZXJ2ZXIge1xuICAgICAgICByZWZyZXNoKC4uLmFyZ3M6IGFueVtdKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpLnRoZW4oKCkgPT4ge1xuICAgICAgICAgICAgb2JzZXJ2ZXIubmV4dCh7IGRhdGE6IGFyZ3MgfSBhcyBhbnkpO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9KSgpO1xuXG4gICAgICB0cnkge1xuICAgICAgICBmb3IgKGNvbnN0IGFkYXB0ZXIgb2YgdGhpcy5hZGFwdGVycykge1xuICAgICAgICAgIGFkYXB0ZXIub2JzZXJ2ZShjYik7XG4gICAgICAgIH1cbiAgICAgIH0gY2F0Y2ggKGU6IGFueSkge1xuICAgICAgICBvYnNlcnZlci5lcnJvcihgRmFpbGVkIHRvIG9ic2VydmUgZXZlbnQ6ICR7ZS5tZXNzYWdlIHx8IGV9YCk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiAoKSA9PiB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgZm9yIChjb25zdCBhZGFwdGVyIG9mIHRoaXMuYWRhcHRlcnMpIHtcbiAgICAgICAgICAgIGFkYXB0ZXIudW5PYnNlcnZlKGNiKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gY2F0Y2ggKGU6IGFueSkge1xuICAgICAgICAgIGxvZ2dlci5lcnJvcihlKTtcbiAgICAgICAgfVxuICAgICAgfTtcbiAgICB9KTtcbiAgfVxufVxuIiwiaW1wb3J0IHsgRHluYW1pY01vZHVsZSwgTW9kdWxlIH0gZnJvbSBcIkBuZXN0anMvY29tbW9uXCI7XG5pbXBvcnQgeyBFdmVudHNDb250cm9sbGVyIH0gZnJvbSBcIi4vRXZlbnRzQ29udHJvbGxlclwiO1xuaW1wb3J0IHsgUm91dGVyTW9kdWxlIH0gZnJvbSBcIkBuZXN0anMvY29yZVwiO1xuaW1wb3J0IHsgTElTVEVOSU5HX0FEQVBURVJTX0ZMQVZPVVJTIH0gZnJvbSBcIi4vY29uc3RhbnRcIjtcbmltcG9ydCB7IERlY2FmUmVxdWVzdENvbnRleHQgfSBmcm9tIFwiLi4vcmVxdWVzdFwiO1xuXG5ATW9kdWxlKHt9KVxuZXhwb3J0IGNsYXNzIERlY2FmU3RyZWFtTW9kdWxlIHtcbiAgc3RhdGljIGZvckZsYXZvdXJzKFxuICAgIGZsYXZvdXJzOiBzdHJpbmdbXSxcbiAgICBwYXRoOiBzdHJpbmcgPSBcImV2ZW50c1wiXG4gICk6IER5bmFtaWNNb2R1bGUge1xuICAgIHJldHVybiB7XG4gICAgICBtb2R1bGU6IERlY2FmU3RyZWFtTW9kdWxlLFxuICAgICAgY29udHJvbGxlcnM6IFtFdmVudHNDb250cm9sbGVyXSxcbiAgICAgIGltcG9ydHM6IFtcbiAgICAgICAgUm91dGVyTW9kdWxlLnJlZ2lzdGVyKFtcbiAgICAgICAgICB7XG4gICAgICAgICAgICBwYXRoOiBwYXRoLnJlcGxhY2UoL15cXC8vLCBcIlwiKSxcbiAgICAgICAgICAgIG1vZHVsZTogRGVjYWZTdHJlYW1Nb2R1bGUsXG4gICAgICAgICAgfSxcbiAgICAgICAgXSksXG4gICAgICBdLFxuICAgICAgcHJvdmlkZXJzOiBbXG4gICAgICAgIERlY2FmUmVxdWVzdENvbnRleHQsXG4gICAgICAgIHtcbiAgICAgICAgICBwcm92aWRlOiBMSVNURU5JTkdfQURBUFRFUlNfRkxBVk9VUlMsXG4gICAgICAgICAgdXNlVmFsdWU6IGZsYXZvdXJzID8/IFtdLFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICB9O1xuICB9XG59XG4iLCJpbXBvcnQgeyBEeW5hbWljTW9kdWxlLCBGb3J3YXJkUmVmZXJlbmNlLCBNb2R1bGUsIFR5cGUgfSBmcm9tIFwiQG5lc3Rqcy9jb21tb25cIjtcbmltcG9ydCB7IERlY2FmTW9kdWxlT3B0aW9ucyB9IGZyb20gXCIuL3R5cGVzXCI7XG5pbXBvcnQgeyBEZWNhZkNvcmVNb2R1bGUgfSBmcm9tIFwiLi9jb3JlLW1vZHVsZVwiO1xuaW1wb3J0IHsgQWRhcHRlciB9IGZyb20gXCJAZGVjYWYtdHMvY29yZVwiO1xuaW1wb3J0IHsgZ2V0TW9kdWxlRm9yIH0gZnJvbSBcIi4vZGVjYWYtbW9kZWwvaW5kZXhcIjtcbmltcG9ydCB7IERlY2FmU3RyZWFtTW9kdWxlIH0gZnJvbSBcIi4vZXZlbnRzLW1vZHVsZVwiO1xuXG4vKipcbiAqIEBwdWJsaWNBcGlcbiAqL1xuQE1vZHVsZSh7fSlcbmV4cG9ydCBjbGFzcyBEZWNhZk1vZHVsZSB7XG4gIHN0YXRpYyBhc3luYyBmb3JSb290QXN5bmMoXG4gICAgb3B0aW9uczogRGVjYWZNb2R1bGVPcHRpb25zXG4gICk6IFByb21pc2U8RHluYW1pY01vZHVsZT4ge1xuICAgIGNvbnN0IHsgYXV0b0NvbnRyb2xsZXJzLCBhdXRvU2VydmljZXMgfSA9IG9wdGlvbnM7XG5cbiAgICBjb25zdCBhZGFwdGVyczogQWRhcHRlcjxhbnksIGFueSwgYW55LCBhbnk+W10gPVxuICAgICAgYXdhaXQgRGVjYWZDb3JlTW9kdWxlLmJvb3RQZXJzaXN0ZW5jZShvcHRpb25zKTtcbiAgICBjb25zdCBmbGF2b3VycyA9IGFkYXB0ZXJzLm1hcCgoYWRhcHRlcikgPT4gYWRhcHRlci5mbGF2b3VyKTtcblxuICAgIGNvbnN0IGltcG9ydHM6XG4gICAgICB8IChcbiAgICAgICAgICB8IER5bmFtaWNNb2R1bGVcbiAgICAgICAgICB8IFR5cGU8YW55PlxuICAgICAgICAgIHwgUHJvbWlzZTxEeW5hbWljTW9kdWxlPlxuICAgICAgICAgIHwgRm9yd2FyZFJlZmVyZW5jZTxhbnk+XG4gICAgICAgIClbXVxuICAgICAgfCB1bmRlZmluZWQgPSBbRGVjYWZDb3JlTW9kdWxlLmZvclJvb3Qob3B0aW9ucyldO1xuXG4gICAgaWYgKGF1dG9Db250cm9sbGVycykge1xuICAgICAgICBmbGF2b3Vycy5mb3JFYWNoKChmbGF2b3VyKSA9PiB7XG4gICAgICAgICAgaW1wb3J0cy5wdXNoKFxuICAgICAgICAgICAgZ2V0TW9kdWxlRm9yKGZsYXZvdXIpLmZvclJvb3QoZmxhdm91ciwge1xuICAgICAgICAgICAgICBhdXRvU2VydmljZXMsXG4gICAgICAgICAgICAgIGNvbnRyb2xsZXJFeHBvc3VyZTogb3B0aW9ucy5jb250cm9sbGVyRXhwb3N1cmUsXG4gICAgICAgICAgICAgIGNvbnRyb2xsZXJDb25maWc6IG9wdGlvbnMuY29udHJvbGxlckNvbmZpZyxcbiAgICAgICAgICAgICAgYWdncmVnYXRpb25zOiBvcHRpb25zLmFnZ3JlZ2F0aW9ucyxcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgKTtcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICBpZiAob3B0aW9ucy5vYnNlcnZlck9wdGlvbnM/LmVuYWJsZU9ic2VydmVyRXZlbnRzKSB7XG4gICAgICBpbXBvcnRzLnB1c2goXG4gICAgICAgIERlY2FmU3RyZWFtTW9kdWxlLmZvckZsYXZvdXJzKFxuICAgICAgICAgIG9wdGlvbnMub2JzZXJ2ZXJPcHRpb25zLm9ic2VydmVyRmxhdm91cnMgfHwgZmxhdm91cnNcbiAgICAgICAgKVxuICAgICAgKTtcbiAgICB9XG5cbiAgICByZXR1cm4ge1xuICAgICAgbW9kdWxlOiBEZWNhZk1vZHVsZSxcbiAgICAgIGltcG9ydHM6IGltcG9ydHMsXG4gICAgfTtcbiAgfVxufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcnVuTWlncmF0aW9ucygpOiBQcm9taXNlPHZvaWQ+IHt9XG4iLCJpbXBvcnQge01vZGVsfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRvci12YWxpZGF0aW9uXCI7XG5pbXBvcnQge0ludGVybmFsRXJyb3J9IGZyb20gXCJAZGVjYWYtdHMvZGItZGVjb3JhdG9yc1wiO1xuaW1wb3J0IHtSZXBvc2l0b3J5fSBmcm9tIFwiQGRlY2FmLXRzL2NvcmVcIjtcblxuZXhwb3J0IGZ1bmN0aW9uIHJlcG9Gb3JNb2RlbChtb2RlbDogc3RyaW5nKSB7XG5cdGNvbnN0IG0gPSBNb2RlbC5nZXQobW9kZWwpO1xuXHRpZiAoIW0pXG5cdFx0dGhyb3cgbmV3IEludGVybmFsRXJyb3IoYEZhaWxlZCB0byBmaW5kIHJlcG9zaXRvcnkgZm9yICR7bW9kZWx9YClcblx0Y29uc3QgcmVwbyA9IFJlcG9zaXRvcnkuZm9yTW9kZWwobSk7XG5cdHJldHVybiByZXBvO1xufSIsIi8qKlxuICogQG1vZHVsZSBmb3ItbmVzdFxuICogQGRlc2NyaXB0aW9uIFRoaXMgbW9kdWxlIHNlcnZlcyBhcyB0aGUgbWFpbiBlbnRyeSBwb2ludCBmb3IgdGhlIHRzLXdvcmtzcGFjZSBsaWJyYXJ5LiBJdCBhZ2dyZWdhdGVzIGFuZCBleHBvcnRzXG4gKiBmdW5jdGlvbmFsaXR5IGZyb20gdmFyaW91cyBzdWJtb2R1bGVzIGFuZCB1dGlsaXRpZXMgd2l0aGluIHRoZSBwcm9qZWN0LlxuICpcbiAqIFRoZSBtb2R1bGUgaW5jbHVkZXM6XG4gKiAxLiBVdGlsaXR5IGZ1bmN0aW9ucyBhbmQgdHlwZXMgZnJvbSB0aGUgXCIuL3V0aWxzXCIgZGlyZWN0b3J5OlxuICogICAgLSBUaGVzZSBsaWtlbHkgY29udGFpbiBoZWxwZXIgZnVuY3Rpb25zLCBjb21tb24gdHlwZXMsIGFuZCBzaGFyZWQgZnVuY3Rpb25hbGl0eSB1c2VkIHRocm91Z2hvdXQgdGhlIHByb2plY3QuXG4gKiAgICAtIE1heSBpbmNsdWRlIG9wZXJhdGlvbnMgZm9yIGRhdGEgbWFuaXB1bGF0aW9uLCB0eXBlIGNoZWNraW5nLCBvciBvdGhlciBnZW5lcmFsLXB1cnBvc2UgdXRpbGl0aWVzLlxuICpcbiAqIDIuIEEgbmFtZXNwYWNlIGFuZCByZWxhdGVkIHR5cGVzIGZyb20gdGhlIFwiLi9uYW1lc3BhY2VcIiBkaXJlY3Rvcnk6XG4gKiAgICAtIFRoaXMgY291bGQgY29udGFpbiBkb21haW4tc3BlY2lmaWMgY29kZSBvciBhIGNvbGxlY3Rpb24gb2YgcmVsYXRlZCBmdW5jdGlvbmFsaXR5LlxuICogICAgLSBNaWdodCBpbmNsdWRlIGludGVyZmFjZXMsIHR5cGVzLCBvciBjbGFzc2VzIHRoYXQgcmVwcmVzZW50IGNvcmUgY29uY2VwdHMgaW4gdGhlIGxpYnJhcnkuXG4gKlxuICogMy4gQSBWRVJTSU9OIGNvbnN0YW50OlxuICogICAgLSBSZXByZXNlbnRzIHRoZSBjdXJyZW50IHZlcnNpb24gb2YgdGhlIG1vZHVsZS5cbiAqICAgIC0gVXNlZnVsIGZvciB2ZXJzaW9uIGNoZWNraW5nIGFuZCBjb21wYXRpYmlsaXR5IHB1cnBvc2VzLlxuICpcbiAqIFRoaXMgc3RydWN0dXJlIHByb3ZpZGVzIGEgY2xlYW4gYW5kIG9yZ2FuaXplZCBleHBvcnQgb2YgdGhlIG1vZHVsZSdzIGZ1bmN0aW9uYWxpdHksIGFsbG93aW5nIGNvbnN1bWVyc1xuICogdG8gZWFzaWx5IGltcG9ydCBhbmQgdXNlIHNwZWNpZmljIHBhcnRzIG9mIHRoZSBsaWJyYXJ5IGFzIG5lZWRlZC5cbiAqL1xuXG5pbXBvcnQgeyBNZXRhZGF0YSB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdGlvblwiO1xuaW1wb3J0IFwiLi9kZWNvcmF0aW9uXCI7XG5cbmV4cG9ydCAqIGZyb20gXCIuL2RlY29yYXRpb25cIjsgLy8gb24gdG9wIG9uIHB1cnBvc2VcbmV4cG9ydCAqIGZyb20gXCIuL2RlY2FmLW1vZGVsXCI7XG5leHBvcnQgKiBmcm9tIFwiLi9hdXRoXCI7XG5leHBvcnQgKiBmcm9tIFwiLi9mYWN0b3J5XCI7XG5leHBvcnQgKiBmcm9tIFwiLi9pbnRlcmNlcHRvcnNcIjtcbmV4cG9ydCAqIGZyb20gXCIuL292ZXJyaWRlc1wiO1xuZXhwb3J0ICogZnJvbSBcIi4vcmVxdWVzdFwiO1xuZXhwb3J0ICogZnJvbSBcIi4vY29uc3RhbnRzXCI7XG5leHBvcnQgKiBmcm9tIFwiLi9jb250cm9sbGVyc1wiO1xuZXhwb3J0ICogZnJvbSBcIi4vbW9kdWxlXCI7XG5leHBvcnQgKiBmcm9tIFwiLi9jb3JlLW1vZHVsZVwiO1xuZXhwb3J0ICogZnJvbSBcIi4vdHlwZXNcIjtcbmV4cG9ydCAqIGZyb20gXCIuL2RlY29yYXRvcnNcIjtcbmV4cG9ydCAqIGZyb20gXCIuL3V0aWxzXCI7XG5leHBvcnQgKiBmcm9tIFwiLi9ldmVudHMtbW9kdWxlXCI7XG4vLyBleHBvcnQgKiBmcm9tIFwiLi93ZWJob29rc1wiO1xuXG4vKipcbiAqIFJlcHJlc2VudHMgdGhlIGN1cnJlbnQgdmVyc2lvbiBvZiB0aGUgdHMtd29ya3NwYWNlIG1vZHVsZS5cbiAqIFRoZSBhY3R1YWwgdmVyc2lvbiBudW1iZXIgaXMgcmVwbGFjZWQgZHVyaW5nIHRoZSBidWlsZCBwcm9jZXNzLlxuICogQGNvbnN0YW50XG4gKiBAdHlwZSB7c3RyaW5nfVxuICovXG5leHBvcnQgY29uc3QgVkVSU0lPTiA9IFwiIyNWRVJTSU9OIyNcIjtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gUmVwcmVzZW50cyB0aGUgY3VycmVudCBjb21taXQgaGFzaCBvZiB0aGUgbW9kdWxlIGJ1aWxkLlxuICogQHN1bW1hcnkgU3RvcmVzIHRoZSBjdXJyZW50IGdpdCBjb21taXQgaGFzaCBmb3IgdGhlIHBhY2thZ2UuIFRoZSBidWlsZCByZXBsYWNlc1xuICogdGhlIHBsYWNlaG9sZGVyIHdpdGggdGhlIGFjdHVhbCBjb21taXQgaGFzaCBhdCBwdWJsaXNoIHRpbWUuXG4gKiBAY29uc3QgQ09NTUlUXG4gKi9cbmV4cG9ydCBjb25zdCBDT01NSVQgPSBcIiMjQ09NTUlUIyNcIjtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gUmVwcmVzZW50cyB0aGUgZnVsbCB2ZXJzaW9uIHN0cmluZyBvZiB0aGUgbW9kdWxlLlxuICogQHN1bW1hcnkgU3RvcmVzIHRoZSBzZW12ZXIgdmVyc2lvbiBhbmQgY29tbWl0IGhhc2ggZm9yIHRoZSBwYWNrYWdlLlxuICogVGhlIGJ1aWxkIHJlcGxhY2VzIHRoZSBwbGFjZWhvbGRlciB3aXRoIHRoZSBhY3R1YWwgYDx2ZXJzaW9uPi08Y29tbWl0PmAgdmFsdWUgYXQgcHVibGlzaCB0aW1lLlxuICogQGNvbnN0IEZVTExfVkVSU0lPTlxuICovXG5leHBvcnQgY29uc3QgRlVMTF9WRVJTSU9OID0gXCIjI0ZVTExfVkVSU0lPTiMjXCI7XG5cbmV4cG9ydCBjb25zdCBQQUNLQUdFX05BTUUgPSBcIiMjUEFDS0FHRSMjXCI7XG5cbk1ldGFkYXRhLmFsbG93UmVyZWdpc3RyYXRpb24odHJ1ZSk7XG5NZXRhZGF0YS5yZWdpc3RlckxpYnJhcnkoUEFDS0FHRV9OQU1FLCBWRVJTSU9OKTtcbk1ldGFkYXRhLmFsbG93UmVyZWdpc3RyYXRpb24oZmFsc2UpO1xuIl0sIm5hbWVzIjpbIkRFQ09SQVRPUlNfUFJFRklYIiwiREVDT1JBVE9SUyIsIkFQSV9PUEVSQVRJT04iLCJBUElfUkVTUE9OU0UiLCJBUElfUFJPRFVDRVMiLCJBUElfQ09OU1VNRVMiLCJBUElfVEFHUyIsIkFQSV9DQUxMQkFDS1MiLCJBUElfUEFSQU1FVEVSUyIsIkFQSV9IRUFERVJTIiwiQVBJX01PREVMX1BST1BFUlRJRVMiLCJBUElfTU9ERUxfUFJPUEVSVElFU19BUlJBWSIsIkFQSV9TRUNVUklUWSIsIkFQSV9FWENMVURFX0VORFBPSU5UIiwiQVBJX0VYQ0xVREVfQ09OVFJPTExFUiIsIkFQSV9FWFRSQV9NT0RFTFMiLCJBUElfRVhURU5TSU9OIiwiQVBJX1NDSEVNQSIsIkFQSV9ERUZBVUxUX0dFVFRFUiIsIkFQSV9MSU5LIiwiaXNDb25zdHJ1Y3RvciIsInZhbCIsIk1FVEFEQVRBX0ZBQ1RPUllfTkFNRSIsIk1FVEhPRF9NRVRBREFUQSIsImNyZWF0ZU1ldGhvZERlY29yYXRvciIsIm1ldGFrZXkiLCJtZXRhZGF0YSIsIm92ZXJyaWRlRXhpc3RpbmciLCJ0YXJnZXQiLCJrZXkiLCJkZXNjcmlwdG9yIiwicHJldlZhbHVlIiwiUmVmbGVjdCIsImdldE1ldGFkYXRhIiwidmFsdWUiLCJkZWZpbmVNZXRhZGF0YSIsImNyZWF0ZUNsYXNzRGVjb3JhdG9yIiwiY3JlYXRlUHJvcGVydHlEZWNvcmF0b3IiLCJwcm9wZXJ0eUtleSIsInByb3BlcnRpZXMiLCJpbmNsdWRlcyIsImV4aXN0aW5nTWV0YWRhdGEiLCJuZXdNZXRhZGF0YSIsInBpY2tCeSIsIm5lZ2F0ZSIsImlzVW5kZWZpbmVkIiwibWV0YWRhdGFUb1NhdmUiLCJ0eXBlIiwiY29uc3RydWN0b3IiLCJjcmVhdGVNaXhlZERlY29yYXRvciIsIm1ldGFkYXRhcyIsIkFycmF5IiwiaXNBcnJheSIsInByZXZpb3VzTWV0YWRhdGEiLCJPYmplY3QiLCJhc3NpZ24iLCJjcmVhdGVQYXJhbURlY29yYXRvciIsImluaXRpYWwiLCJwYXJhbU9wdGlvbnMiLCJwYXJhbWV0ZXJzIiwicHJvcGVydHlLZXlzIiwiZ2V0T3duUHJvcGVydHlOYW1lcyIsInByb3RvdHlwZSIsIm1ldGhvZERlc2NyaXB0b3IiLCJnZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IiLCJpc0FwaU1ldGhvZCIsImhhc01ldGFkYXRhIiwiZ2V0VHlwZUlzQXJyYXlUdXBsZSIsImlucHV0IiwiaXNBcnJheUZsYWciLCJpc0lucHV0QXJyYXkiLCJvYmoiLCJnZXRFbnVtVmFsdWVzIiwiZW51bVR5cGUiLCJudW1lcmljVmFsdWVzIiwidmFsdWVzIiwiZmlsdGVyIiwibWFwIiwidG9TdHJpbmciLCJrZXlzIiwiZ2V0RW51bVR5cGUiLCJoYXNTdHJpbmciLCJpc1N0cmluZyIsImxlbmd0aCIsInJlcXVpcmVkIiwiaXNFbnVtQXJyYXkiLCJvcHRzIiwiZW51bSIsInVuZGVmaW5lZCIsIkFwaVByb3BlcnR5Iiwib3B0aW9ucyIsImNyZWF0ZUFwaVByb3BlcnR5RGVjb3JhdG9yIiwiZW51bVZhbHVlcyIsIml0ZW1zIiwiQXBpT3BlcmF0aW9uRnJvbU1vZGVsIiwiTW9kZWxDb25zdHJ1Y3RvciIsInZlcmIiLCJwYXRoIiwiaHR0cFRvQ3J1ZCIsIkdFVCIsIk9wZXJhdGlvbktleXMiLCJSRUFEIiwiR2V0IiwiUE9TVCIsIkNSRUFURSIsIlBvc3QiLCJQVVQiLCJVUERBVEUiLCJQdXQiLCJQQVRDSCIsIlBhdGNoIiwiREVMRVRFIiwiRGVsZXRlIiwiY3J1ZE9wIiwiSHR0cE1ldGhvZERlY29yYXRvciIsInJlc29sdmVCbG9ja1RhcmdldCIsImNvcmVJc09wZXJhdGlvbkJsb2NrZWQiLCJraW5kIiwiYXBwbHkiLCJBcGlFeGNsdWRlRW5kcG9pbnQiLCJCdWxrQXBpT3BlcmF0aW9uRnJvbU1vZGVsIiwiQnVsa0NydWRPcGVyYXRpb25LZXlzIiwiUkVBRF9BTEwiLCJDUkVBVEVfQUxMIiwiVVBEQVRFX0FMTCIsIkRFTEVURV9BTEwiLCJub3JtYWxpemVkIiwicmVwbGFjZSIsInN0YXRlbWVudFRhcmdldHMiLCJQcmVwYXJlZFN0YXRlbWVudEtleXMiLCJMSVNUX0JZIiwiUEFHRV9CWSIsIkZJTkQiLCJQQUdFIiwiRklORF9PTkVfQlkiLCJGSU5EX0JZIiwiQ09VTlRfT0YiLCJNQVhfT0YiLCJNSU5fT0YiLCJBVkdfT0YiLCJTVU1fT0YiLCJESVNUSU5DVF9PRiIsIkdST1VQX09GIiwic3RhcnRzV2l0aCIsInN0YXRlbWVudFZhbHVlIiwiQXBpUGFyYW1zRnJvbU1vZGVsIiwicHJvcHMiLCJkZWNvcmF0b3JzIiwicCIsIkFwaVBhcmFtRGVjIiwibmFtZSIsImRlc2NyaXB0aW9uIiwiU3RyaW5nIiwiYXBwbHlEZWNvcmF0b3JzIiwiRGVjYWZCb2R5IiwiZGF0YSIsImN0eCIsInJlcXVlc3QiLCJzd2l0Y2hUb0h0dHAiLCJnZXRSZXF1ZXN0IiwiYm9keSIsImNvbnRyb2xsZXIiLCJnZXRDbGFzcyIsIk1vZGVsQ29uc3RyIiwiY2xhc3MiLCJJbnRlcm5hbFNlcnZlckVycm9yRXhjZXB0aW9uIiwiaXRlbSIsIk9yZGVyZWRQYXJhbXMiLCJvcmRlciIsInJlcSIsIm9yaWdpbmFsIiwicGFyYW1zIiwib3JkZXJMaXN0Iiwib3JkZXJlZCIsImsiLCJyYXciLCJ2YWx1ZXNJbk9yZGVyIiwia2V5c0luT3JkZXIiLCJEZWNhZlBhcmFtcyIsIkRlY2FmUXVlcnkiLCJfIiwicXVlcnkiLCJwYXJzZWQiLCJsaW1pdCIsIm4iLCJOdW1iZXIiLCJpc05hTiIsIm9mZnNldCIsImJvb2ttYXJrIiwiREVDQUZfTU9EVUxFX09QVElPTlMiLCJERUNBRl9BREFQVEVSX0lEIiwiREVDQUZfVEFTS19TRVJWSUNFX0lEIiwiREVDQUZfUk9VVEUiLCJERUNBRl9IQU5ETEVSUyIsIlN5bWJvbCIsIkRFQ0FGX0VYUE9TRSIsIkRFQ0FGX0NPTlRST0xMRVJfQ09ORklHIiwiREVDQUZfQ09OVEVYVF9LRVkiLCJleHBvc2UiLCJmbGF2b3VycyIsIk1ldGFkYXRhIiwic2V0IiwiY29udHJvbGxlckNvbmZpZyIsImNvbmZpZyIsImNvbnRyb2xsZXJDb25maWdEZWNvcmF0b3IiLCJBVVRIX0hBTkRMRVIiLCJBVVRIX01FVEFfS0VZIiwiSVNfUFVCTElDX0tFWSIsIlJFUVVJUkVEX1JPTEVTX0tFWSIsIlNLSVBfTU9ERUxfUk9MRVNfS0VZIiwiRGVjYWZSZXF1ZXN0Q29udGV4dCIsIlJlcXVlc3RDb250ZXh0Iiwic3VwZXIiLCJoZWFkZXJzT2YiLCJoZWFkZXJzIiwidGhpcyIsInV1aWQiLCJVVUlEIiwiaW5zdGFuY2UiLCJnZW5lcmF0ZSIsInB1dCIsInJlY29yZCIsIm92ZXJyaWRlcyIsImdldCIsImUiLCJhY2N1bXVsYXRlIiwiX19kZWNvcmF0ZSIsIkluamVjdGFibGUiLCJzY29wZSIsIlNjb3BlIiwiUkVRVUVTVCIsIl9fcGFyYW0iLCJJbmplY3QiLCJBdXRoSW50ZXJjZXB0b3IiLCJyZWZsZWN0b3IiLCJyZXF1ZXN0Q29udGV4dCIsImF1dGhIYW5kbGVyIiwiaW50ZXJjZXB0IiwibmV4dCIsImxvZyIsIkxvZ2dpbmciLCJmb3IiLCJpc1B1YmxpYyIsImdldEFsbEFuZE92ZXJyaWRlIiwiZ2V0SGFuZGxlciIsIm1vZGVsTmFtZSIsInJlcXVpcmVkUm9sZXMiLCJza2lwTW9kZWxSb2xlcyIsImVmZmVjdGl2ZU1vZGVsIiwidmVyYm9zZSIsImRlYnVnIiwiYXV0aG9yaXplIiwiYXBwbHlUcmFuc2Zvcm1lcnMiLCJ1c2VyIiwiZ2V0T3JVbmRlZmluZWQiLCJvcmdhbml6YXRpb24iLCJjdXJyZW50TG9nIiwiY2hpbGRMb2ciLCJsb2dnZXIiLCJoYW5kbGUiLCJBZGFwdGVyIiwiZmxhdm91cnNUb1RyYW5zZm9ybSIsImZsYXZvdXIiLCJ0cmFuc2Zvcm1lciIsInRyYW5zZm9ybWVyRm9yIiwiZnJvbSIsIk9wdGlvbmFsIiwiUmVmbGVjdG9yIiwiQXV0aCIsIm1vZGVsIiwicmVzb3VyY2UiLCJkZWNzIiwiQXBpQmVhcmVyQXV0aCIsIlVzZUludGVyY2VwdG9ycyIsInB1c2giLCJTZXRNZXRhZGF0YSIsIlB1YmxpYyIsIlJlcXVpcmVSb2xlcyIsInJvbGVzIiwiQXBpU2VjdXJpdHkiLCJIdHRwVmVyYlRvRGVjb3JhdG9yIiwiZGVjb3JhdG9yIiwiRXJyb3IiLCJleHRyYWN0UGF0aFBhcmFtcyIsInJvdXRlUGF0aCIsInNwbGl0Iiwic2xpY2UiLCJhcGlQYXJhbVNwZWMiLCJnZXRBcGlEZWNvcmF0b3JzIiwibWV0aG9kTmFtZSIsImh0dHBWZXJiIiwiaW5jbHVkZVF1ZXJ5UGFyYW1zIiwiTmVzdEh0dHBSb3V0ZURlYyIsImFwaVBhdGhQYXJhbXMiLCJzd2FnZ2VyUXVlcnlQYXJhbXMiLCJBcGlRdWVyeSIsIk9yZGVyRGlyZWN0aW9uIiwibWV0aG9kIiwiQXBpUGFyYW0iLCJBcGlPcGVyYXRpb24iLCJzdW1tYXJ5IiwiQXBpT2tSZXNwb25zZSIsIkFwaU5vQ29udGVudFJlc3BvbnNlIiwiUXVlcnkiLCJhcHBseUFwaURlY29yYXRvcnMiLCJwcm90byIsImZvckVhY2giLCJkIiwiaW5kZXgiLCJyZXNvbHZlUGVyc2lzdGVuY2VNZXRob2QiLCJwZXJzaXN0ZW5jZSIsImFyZ3MiLCJNb2RlbFNlcnZpY2UiLCJzdGF0ZW1lbnQiLCJjcmVhdGVSb3V0ZUhhbmRsZXIiLCJhc3luYyIsInBhdGhQYXJhbXMiLCJxdWVyeVBhcmFtcyIsIkpTT04iLCJzdHJpbmdpZnkiLCJkaXJlY3Rpb24iLCJlcnJvciIsImRlZmluZVJvdXRlTWV0aG9kIiwiQ29udHJvbGxlckNsYXNzIiwiaGFuZGxlciIsImRlZmluZVByb3BlcnR5Iiwid3JpdGFibGUiLCJEZWNhZkF1dGhIYW5kbGVyIiwiQXV0aEhhbmRsZXIiLCJwYXJzZVJlcXVlc3QiLCJ1c2VyUm9sZSIsImF1dGhvcml6YXRpb24iLCJleHRyYWN0RnJvbUF1dGgiLCJBdXRob3JpemF0aW9uRXJyb3IiLCJEZWNhZlJvbGVBdXRoSGFuZGxlciIsInRvQ29udGV4dEZsYWdzIiwiYWRhcHRlciIsImFsaWFzIiwiYmluZCIsInJlcXVlc3RUcmFuc2Zvcm1lcnMiLCJtZXRhIiwiQ29udGV4dCIsInRvUmVzcG9uc2UiLCJyZXMiLCJwZW5kaW5nIiwiaGVhZGVyIiwiTW9kZWxCdWlsZGVyIiwiZGVjb3JhdGVDbGFzcyIsIl9jbGFzc0RlY29yYXRvcnMiLCJfX2hhc0NsYXNzRGVjb3JhdG9yU3VwcG9ydCIsIm9yaWdpbmFsQnVpbGQiLCJidWlsZCIsInJlc3VsdCIsImNhbGwiLCJkZWNvcmF0ZWQiLCJEZWNhZlJlcXVlc3RIYW5kbGVySW50ZXJjZXB0b3IiLCJEZWNhZlJlcXVlc3RIYW5kbGVySW50ZXJjZXB0b3JfMSIsImV4ZWN1dG9yIiwiY29udGV4dHVhbGl6ZSIsImZsYWdzIiwiaXAiLCJleHRyYWN0SXAiLCJEZWZhdWx0QWRhcHRlckZsYWdzIiwidGltZXN0YW1wIiwiRGF0ZSIsIm9wZXJhdGlvbiIsInVybCIsImNvbnRleHQiLCJnZXRSZXNwb25zZSIsImV4ZWMiLCJEZWNhZkhhbmRsZXJFeGVjdXRvciIsInBhcnNlSXBIZWFkZXIiLCJjYW5kaWRhdGUiLCJzZWdtZW50IiwidHJpbSIsIkJvb2xlYW4iLCJEZWNhZkF1dGhNb2R1bGUiLCJEZWNhZkF1dGhNb2R1bGVfMSIsImZvclJvb3QiLCJwcm92aWRlcnMiLCJwcm92aWRlIiwiQVBQX0lOVEVSQ0VQVE9SIiwidXNlQ2xhc3MiLCJnbG9iYWwiLCJ1c2VFeGlzdGluZyIsIm1vZHVsZSIsImV4cG9ydHMiLCJNb2R1bGUiLCJEZWNhZkhhbmRsZXJFeGVjdXRvcl8xIiwiaGFuZGxlcnMiLCJEZWNhZlJlc3BvbnNlSW50ZXJjZXB0b3IiLCJyZXNwb25zZSIsInBpcGUiLCJ0YXAiLCJEZWNhZkNvbnRyb2xsZXIiLCJIdHRwRGVjYWZDb250cm9sbGVyIiwiY2xpZW50Q29udGV4dCIsIl9uYW1lIiwiRGVjYWZNb2RlbENvbnRyb2xsZXIiLCJfcGVyc2lzdGVuY2UiLCJTZXJ2aWNlIiwiZ2V0U2VydmljZSIsIlJlcG9zaXRvcnkiLCJmb3JNb2RlbCIsInRvT3ZlcnJpZGVzIiwib3ZlcnJpZGUiLCJkdG9DYWNoZSIsIk1hcCIsIkR0b0ZvciIsIm9wIiwic3RhY2siLCJTZXQiLCJUcmFuc2FjdGlvbk9wZXJhdGlvbktleXMiLCJjYWNoZSIsImdldER0b0NhY2hlIiwiY2FjaGVkIiwiaXNVcGRhdGVPcCIsIkR5bmFtaWNEVE8iLCJ0b1Bhc2NhbENhc2UiLCJwa1Byb3AiLCJNb2RlbCIsInBrIiwicGtQcm9wc01ldGFkYXRhIiwicGtQcm9wcyIsInBrRGVzaWduVHlwZSIsInBrVHlwZUlzTnVtZXJpYyIsIkJpZ0ludCIsInBrSXNHZW5lcmF0ZWQiLCJnZW5lcmF0ZWQiLCJnZW5lcmF0ZWRCeVNlcXVlbmNlIiwiaXNQcm9wZXJ0eUdlbmVyYXRlZEFjcm9zc0luaGVyaXRhbmNlIiwiYWxsUHJvcHMiLCJyZWxhdGlvbnMiLCJzY2FsYXJQcm9wcyIsInByb3AiLCJoYXMiLCJ2YWxpZGF0aW9uIiwiZ2V0VmFsaWRhdGlvbkFjcm9zc0luaGVyaXRhbmNlIiwiaXNSZXF1aXJlZCIsIlZhbGlkYXRpb25LZXlzIiwiUkVRVUlSRUQiLCJ0eXBlSGludCIsImdldFR5cGVBY3Jvc3NJbmhlcml0YW5jZSIsImFwaU9wdGlvbnMiLCJkZXNpZ25UeXBlIiwiZW51bWVyYWJsZSIsImNvbmZpZ3VyYWJsZSIsInJlbGF0aW9uIiwicmVsYXRpb25NZXRhIiwiSW50ZXJuYWxFcnJvciIsInJlbGF0aW9uVHlwZSIsInZhbGlkYXRpb25Gb3IiLCJMSVNUIiwiaXNDaXJjdWxhciIsInBrVHlwZU5hbWUiLCJnZXRQa09wZW5BcGlUeXBlIiwiYWRkUmVsYXRpb25Qa1JlZiIsInJlbGF0aW9uRHRvIiwiYWRkIiwiYWRkUmVsYXRpb25VcGRhdGUiLCJhZGRSZWxhdGlvbiIsIkR0b0NsYXNzIiwiZXh0cmFNb2RlbHMiLCJkdG9SZWYiLCJvbmVPZkl0ZW1zIiwiJHJlZiIsIm9uZU9mIiwicGtUeXBlIiwiY3VycmVudCIsIkZ1bmN0aW9uIiwiZ2V0UHJvdG90eXBlT2YiLCJXZWFrTWFwIiwiRnJvbU1vZGVsQ29udHJvbGxlciIsImdldFBlcnNpc3RlbmNlIiwiTW9kZWxDbGF6eiIsImUyIiwiY3JlYXRlUXVlcnlSb3V0ZXNGcm9tUmVwb3NpdG9yeSIsInByZWZpeCIsIlBlcnNpc3RlbmNlS2V5cyIsIlFVRVJZIiwicmVwbyIsInF1ZXJ5TWV0aG9kcyIsInJvdXRlTWV0aG9kcyIsIlF1ZXJ5Q29udHJvbGxlciIsImVudHJpZXMiLCJqb2luIiwiY3JlYXRlQ29tcGxleFF1ZXJ5SGFuZGxlciIsImRlZmluZU1ldGhvZCIsImh0dHBEZWNvcmF0b3IiLCJodHRwTWV0aG9kIiwiZ2V0UXVlcnlEZWNvcmF0b3JzIiwib2JqVmFsdWVzIiwiZmllbGRzIiwiZiIsImNyZWF0ZSIsIm1vZHVsZUNvbmZpZ092ZXJyaWRlcyIsImdsb2JhbERlZmF1bHRzIiwidGFibGVOYW1lIiwidG9LZWJhYkNhc2UiLCJtb2RlbENsYXp6TmFtZSIsImZhY3RvcnlQZXJzaXN0ZW5jZSIsImRlY29yYXRvckNvbmZpZyIsIm1vZHVsZU92ZXJyaWRlIiwibWVyZ2VkQ29uZmlnIiwiRmFjdG9yeUNvbnRyb2xsZXIiLCJNb2RlbENvbnRyb2xsZXJGYWN0b3J5IiwiZmFjdG9yeVJvdXRlcyIsIl9fcm91dGVzX18iLCJnZXRQSyIsImFwaVByb3BlcnRpZXMiLCJwa1BhdGgiLCJnZXRSb3V0ZVBhcmFtZXRlcnNGcm9tTW9kZWwiLCJhdXRoQ29uZmlnIiwiYXV0aCIsImFwcGx5Q2xhc3NBdXRoIiwicHVibGljIiwiRHluYW1pY01vZGVsQ29udHJvbGxlciIsIkR5bmFtaWNNb2RlbENvbnRyb2xsZXJfMSIsImluZm8iLCJDb250cm9sbGVyIiwiQXBpVGFncyIsIkFwaUV4dHJhTW9kZWxzIiwic29ydGVkUm91dGVzIiwic29ydCIsImEiLCJiIiwiYVNlZ21lbnRzIiwiYlNlZ21lbnRzIiwiYVBhcmFtQ291bnQiLCJzIiwiYlBhcmFtQ291bnQiLCJhTGl0ZXJhbENvdW50IiwiYkxpdGVyYWxDb3VudCIsInJvdXRlIiwicmVnaXN0cmF0aW9uIiwibWF0Y2hSb3V0ZSIsInBhcmFtRGVjb3JhdG9ycyIsImNvbXBvc2VkIiwiREJLZXlzIiwiQ09NUE9TRUQiLCJjb21wb3NlZEtleXMiLCJ1bmlxdWVLZXlzIiwic2VwYXJhdG9yIiwibWV0aG9kRGVjb3JhdG9ycyIsIm5vcm1hbGl6ZWRQYXRoIiwiY3JlYXRlUmVnaXN0cmF0aW9uIiwiY3JlYXRlQ3JlYXRlSGFuZGxlciIsImNyZWF0ZUNyZWF0ZURlY29yYXRvcnMiLCJSZXNwb25zZSIsInBhc3N0aHJvdWdoIiwiY3JlYXRlQnVsa0NyZWF0ZUhhbmRsZXIiLCJidWxrQ3JlYXRlRGVjb3JhdG9ycyIsImNyZWF0ZUJ1bGtSZWFkSGFuZGxlciIsImJ1bGtSZWFkRGVjb3JhdG9ycyIsImNyZWF0ZUJ1bGtVcGRhdGVIYW5kbGVyIiwiYnVsa1VwZGF0ZURlY29yYXRvcnMiLCJjcmVhdGVCdWxrRGVsZXRlSGFuZGxlciIsImJ1bGtEZWxldGVEZWNvcmF0b3JzIiwiY3JlYXRlUmVhZEhhbmRsZXIiLCJyZWFkRGVjb3JhdG9ycyIsImNyZWF0ZVVwZGF0ZUhhbmRsZXIiLCJ1cGRhdGVEZWNvcmF0b3JzIiwiY3JlYXRlRGVsZXRlSGFuZGxlciIsImRlbGV0ZURlY29yYXRvcnMiLCJmYWxsYmFja1NlZ21lbnRzIiwiaXNBbGxQYXJhbXMiLCJldmVyeSIsImZhbGxiYWNrQXBpUHJvcHMiLCJzdWZmaXgiLCJjcmVhdGVTdGF0ZW1lbnRIYW5kbGVyIiwic3RhdGVtZW50RGVjb3JhdG9ycyIsIlBhcmFtIiwic3RhdGVtZW50Um91dGVzIiwic3RhdGVtZW50S2V5Iiwic3RhdGVtZW50TWV0aG9kTmFtZSIsImNyZWF0ZVN0YXRlbWVudFNob3J0Y3V0SGFuZGxlciIsInN0YXRlbWVudFNob3J0Y3V0RGVjb3JhdG9ycyIsInN0YXRlbWVudFNob3J0Y3V0UGFyYW1zIiwicXVlcnlNZXRob2QiLCJjb21wbGV4UXVlcnlQYXJhbXMiLCJwYXRoU2VnbWVudHMiLCJrbm93blByZWZpeGVzIiwicm91dGVNZXRhZGF0YSIsIm1hdGNoZWRFbnRyeSIsImZpbmQiLCJhY3R1YWxNZXRob2ROYW1lIiwicGFyYW1TZWdtZW50cyIsImNyZWF0ZUN1c3RvbVJvdXRlSGFuZGxlciIsImZpcnN0U2VnbWVudCIsInNlZ21lbnRzIiwic2VnIiwiaSIsInJlc3AiLCJsb2dDdHgiLCJjcmVhdGVkIiwiY3JlYXRlQWxsIiwicmVhZEFsbCIsImlkcyIsIm5vcm1hbGl6ZWRJZHMiLCJyZWFkIiwidXBkYXRlQWxsIiwidXBkYXRlZCIsImRlbGV0ZUFsbCIsInJvdXRlUGFyYW1zIiwiaWQiLCJWYWxpZGF0aW9uRXJyb3IiLCJyZWFkUmVzdWx0IiwidXBkYXRlIiwicGF5bG9hZCIsInBhcnNlIiwicmVtb3ZlIiwiZGVsIiwiZGVsZXRlIiwiZGV0YWlscyIsIlNUQVRFTUVOVCIsInBhcnNlSW50IiwicGF0aERpcmVjdGlvbiIsInJlc29sdmVkRGlyZWN0aW9uIiwic3RhdGVtZW50U2hvcnRjdXQiLCJsaXN0QnkiLCJwYWdlIiwicGFnaW5hdGVCeSIsIkFTQyIsInJlZiIsImZpbmRPbmVCeSIsImZpbmRCeSIsImZpZWxkIiwiY29tcGxleFF1ZXJ5Iiwic3ByZWFkQXJncyIsImV4dHJhY3RRdWVyeUFyZ3MiLCJjdXN0b21Sb3V0ZSIsImxhc3QiLCJxdWVyeU9iaiIsInBvcCIsImhhc0RpcmVjdGlvbiIsImhhc0xpbWl0IiwiaGFzT2Zmc2V0IiwiZXh0cmFzIiwiQXBpQm9keSIsIkFwaUNyZWF0ZWRSZXNwb25zZSIsInNjaGVtYSIsImdldFNjaGVtYVBhdGgiLCJBcGlCYWRSZXF1ZXN0UmVzcG9uc2UiLCJBcGlVbnByb2Nlc3NhYmxlRW50aXR5UmVzcG9uc2UiLCJBcGlOb3RGb3VuZFJlc3BvbnNlIiwiYmFzZSIsImdldE1vZHVsZUZvciIsIkRlY2FmTW9kZWxNb2R1bGUiLCJEZWNhZk1vZGVsTW9kdWxlXzEiLCJjcmVhdGVNb2RlbFNlcnZpY2VzIiwibW9kZWxzIiwidXNlRmFjdG9yeSIsImlzRXhwb3NlZCIsImV4cG9zdXJlIiwidHJhY2tlZE1vZGVscyIsImNvbnRyb2xsZXJFeHBvc3VyZSIsIm1vZGVsU2VydmljZXMiLCJhdXRvU2VydmljZXMiLCJhZ2dyZWdhdGlvbnMiLCJhbGxvd0dyb3VwaW5nUXVlcmllcyIsImNvbnRyb2xsZXJzIiwiRGVjb3JhdGlvbiIsIkluamVjdGFibGVzS2V5cyIsIklOSkVDVEFCTEUiLCJleHRlbmQiLCJuZXN0SW5qZWN0YWJsZSIsImNhdGVnb3J5IiwiY2ZnIiwiRGVmYXVsdEluamVjdGFibGVzQ29uZmlnIiwic2luZ2xldG9uIiwiREVGQVVMVCIsImR1cmFibGUiLCJJTkpFQ1QiLCJuZXN0SW5qZWN0IiwiaW5uZXJOZXN0SW5qZWN0IiwiTUFYIiwibWF4RGVjIiwibWF4IiwibWF4aW11bSIsIk1JTiIsIm1pbkRlYyIsIm1pbiIsIm1pbmltdW0iLCJNQVhfTEVOR1RIIiwibWF4TGVuZ3RoRGVjIiwibWF4TGVuZ3RoIiwiTUlOX0xFTkdUSCIsIm1pbkxlbmd0aERlYyIsIm1pbkxlbmd0aCIsIlRZUEUiLCJ0eXBlRGVjIiwiREFURSIsImRhdGVEZWMiLCJmb3JtYXQiLCJFTlVNIiwib3B0aW9uRGVjIiwiUEFUVEVSTiIsInBhdHRlcm5EZWMiLCJwYXQiLCJwYXR0ZXJuIiwic291cmNlIiwiQ09MVU1OIiwiY29sdW1uRGVjIiwiRGVjb3JhdGlvbktleXMiLCJERVNDUklQVElPTiIsImRlc2NyaXB0aW9uRGVjIiwiQVVUSCIsIkNvcnNFcnJvciIsIkZvcmJpZGRlbkVycm9yIiwibXNnIiwiVG9NYW55UmVxdWVzdHNFcnJvciIsIkJhc2VFcnJvciIsIkRlY2FmRXhjZXB0aW9uRmlsdGVyIiwiZXhjZXB0aW9uIiwiaG9zdCIsImlzUHJvZHVjdGlvbiIsIkxvZ2dlZEVudmlyb25tZW50IiwiZW52Iiwic3RhdHVzQ29kZSIsIk5vdEZvdW5kRXhjZXB0aW9uIiwiVW5zdXBwb3J0ZWRFcnJvciIsIk5vdEFjY2VwdGFibGVFeGNlcHRpb24iLCJtZXNzYWdlIiwiZ2V0U3RhdHVzIiwic3RhdHVzIiwiY29kZSIsImpzb24iLCJ0b0lTT1N0cmluZyIsIkNhdGNoIiwiVXNlRGVjYWZGaWx0ZXIiLCJVc2VGaWx0ZXJzIiwiVXNlRGVjYWZIZWFkZXJzIiwiU1dBR0dFUl9VSV9DT05TVEFOVFMiLCJ0aXRsZSIsInZlcnNpb24iLCJmYXZpY29uRmlsZVBhdGgiLCJ0b3BiYXJJY29uRmlsZVBhdGgiLCJzY2hlbWUiLCJiZWFyZXJGb3JtYXQiLCJpbiIsInBlcnNpc3RBdXRob3JpemF0aW9uIiwidG9wYmFyQmdDb2xvciIsIlN3YWdnZXJDdXN0b21VSSIsImN1c3RvbUNTUyIsImNzcyIsInRvcGJhckljb25QYXRoIiwiaW1nIiwiYjY0IiwiZ2V0Q3VzdG9tT3B0aW9ucyIsImZhdmljb24iLCJmYXZpY29uUGF0aCIsImN1c3RvbVNpdGVUaXRsZSIsImN1c3RvbUNzcyIsInN3YWdnZXJPcHRpb25zIiwiZmlsZSIsImZpbGVQYXRoIiwiYXNzZXRzUGF0aCIsInJlYWRGaWxlU3luYyIsImVuY29kaW5nIiwiU3dhZ2dlckJ1aWxkZXIiLCJhcHAiLCJjcmVhdGVEb2N1bWVudCIsIm9wZW5BcGlKc29uUGF0aCIsIm9wZW5BcGlZYW1sUGF0aCIsIkRvY3VtZW50QnVpbGRlciIsInNldFRpdGxlIiwic2V0RGVzY3JpcHRpb24iLCJzZXRWZXJzaW9uIiwiYWRkQmVhcmVyQXV0aCIsIlN3YWdnZXJNb2R1bGUiLCJyZWdpc3Rlck9wZW5BcGlSb3V0ZSIsImNvbnRlbnRUeXBlIiwiYm9keUZhY3RvcnkiLCJodHRwQWRhcHRlciIsImdldEh0dHBBZGFwdGVyIiwiX3JlcSIsInJlcGx5Iiwic2V0dXBTd2FnZ2VyIiwiZG9jdW1lbnQiLCJzd2FnZ2VyVUkiLCJzZXR1cCIsImpzb25Eb2N1bWVudFVybCIsInlhbWxEb2N1bWVudFVybCIsIllBTUwiLCJOZXN0Qm9vdHN0cmFwZXIiLCJfbG9nZ2VyIiwiTG9nZ2VyIiwiaW5pdGlhbGl6ZSIsImVuYWJsZUxvZ2dlciIsImN1c3RvbUxvZ2dlciIsInVzZUxvZ2dlciIsImVuYWJsZUNvcnMiLCJvcmlnaW5zIiwiYWxsb3dNZXRob2RzIiwiYWxsb3dlZE9yaWdpbnMiLCJvIiwidG9Mb3dlckNhc2UiLCJjb3JzT3B0aW9ucyIsIm9yaWdpbiIsImNhbGxiYWNrIiwiY3JlZGVudGlhbHMiLCJtZXRob2RzIiwidXNlSGVsbWV0IiwiaGVsbWV0IiwicmVxdWlyZSIsInVzZSIsIndhcm4iLCJzd2FnZ2VyIiwidXNlR2xvYmFsUGlwZXMiLCJwaXBlcyIsInVzZUdsb2JhbEZpbHRlcnMiLCJmaWx0ZXJzIiwidXNlR2xvYmFsSW50ZXJjZXB0b3JzIiwiaW50ZXJjZXB0b3JzIiwic3RhcnQiLCJwb3J0IiwicHJvY2VzcyIsIlBPUlQiLCJsaXN0ZW4iLCJ0aGVuIiwiZ2V0VXJsIiwicGVuZGluZ1Byb3ZpZGVycyIsImdldFJlZ2lzdGVyZWREZWNhZlByb3ZpZGVycyIsInJlZ2lzdGVyUHJvdmlkZXIiLCJ0b2tlbiIsImlzTW9kZWxDb25zdHJ1Y3RvciIsIm1vZGVsU2VydmljZVRva2VuIiwibW9kZWxSZXBvc2l0b3J5VG9rZW4iLCJwYXJhbWV0ZXJJbmRleCIsInJlc29sdmVkIiwicGFyYW1UeXBlcyIsImFzTW9kZWwiLCJpbmplY3RhYmxlU2VydmljZUtleSIsIkNvcmVTZXJ2aWNlIiwiQ29yZVJlcG9zaXRvcnkiLCJEZWNhZkNvcmVNb2R1bGUiLCJEZWNhZkNvcmVNb2R1bGVfMSIsIm1vZHVsZVJlZiIsImRlY2FmUHJvdmlkZXJzIiwidXNlVmFsdWUiLCJjbGllbnQiLCJIIiwicHJvdmlkZXIiLCJib290UGVyc2lzdGVuY2UiLCJ0cmltbWVkIiwiY29uZiIsImNvbnRyIiwicG9zc2libGUiLCJQZXJzaXN0ZW5jZVNlcnZpY2UiLCJib290IiwiY2xpZW50cyIsImMiLCJwb3NzaWJsZVRyYW5zZiIsInJlcXVlc3RUb0NvbnRleHRUcmFuc2Zvcm1lciIsImluaXRpYWxpemF0aW9uIiwib25BcHBsaWNhdGlvblNodXRkb3duIiwiYWRhcHRlcnMiLCJzaHV0ZG93biIsIkdsb2JhbCIsIk1vZHVsZVJlZiIsIkxJU1RFTklOR19BREFQVEVSU19GTEFWT1VSUyIsIm5vcm1hbGl6ZUV2ZW50UmVzcG9uc2UiLCJtb2RlbENvbnN0ciIsInNlcmlhbGl6ZWRQYXlsb2FkIiwic2VyaWFsaXplIiwiY29uc29sZSIsImVyciIsIkV2ZW50c0NvbnRyb2xsZXIiLCJFdmVudHNDb250cm9sbGVyXzEiLCJldmVudHMkIiwiT2JzZXJ2YWJsZSIsIm9ic2VydmVyIiwib2JzZXJ2ZXJJZCIsIk1hdGgiLCJyYW5kb20iLCJ0b1VwcGVyQ2FzZSIsImNiIiwicmVmcmVzaCIsIlByb21pc2UiLCJyZXNvbHZlIiwiYWRhcHRlck5hbWUiLCJvYnNlcnZlIiwidW5PYnNlcnZlIiwiSEVBUlRCRUFUX0lOVEVSVkFMX01TIiwiaGVhcnRiZWF0JCIsImludGVydmFsIiwidHMiLCJtZXJnZSIsImxpc3RlbkZvck1vZGVsIiwiU3NlIiwiRGVjYWZTdHJlYW1Nb2R1bGUiLCJEZWNhZlN0cmVhbU1vZHVsZV8xIiwiZm9yRmxhdm91cnMiLCJpbXBvcnRzIiwiUm91dGVyTW9kdWxlIiwicmVnaXN0ZXIiLCJEZWNhZk1vZHVsZSIsIkRlY2FmTW9kdWxlXzEiLCJmb3JSb290QXN5bmMiLCJhdXRvQ29udHJvbGxlcnMiLCJvYnNlcnZlck9wdGlvbnMiLCJlbmFibGVPYnNlcnZlckV2ZW50cyIsIm9ic2VydmVyRmxhdm91cnMiLCJydW5NaWdyYXRpb25zIiwicmVwb0Zvck1vZGVsIiwibSIsIlZFUlNJT04iLCJDT01NSVQiLCJGVUxMX1ZFUlNJT04iLCJQQUNLQUdFX05BTUUiLCJhbGxvd1JlcmVnaXN0cmF0aW9uIiwicmVnaXN0ZXJMaWJyYXJ5Il0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQU8sTUFBTUEsb0JBQW9COztBQUMxQixNQUFNQyxhQUFhO0lBQ3hCQyxlQUFlLEdBQUdGO0lBQ2xCRyxjQUFjLEdBQUdIO0lBQ2pCSSxjQUFjLEdBQUdKO0lBQ2pCSyxjQUFjLEdBQUdMO0lBQ2pCTSxVQUFVLEdBQUdOO0lBQ2JPLGVBQWUsR0FBR1A7SUFDbEJRLGdCQUFnQixHQUFHUjtJQUNuQlMsYUFBYSxHQUFHVDtJQUNoQlUsc0JBQXNCLEdBQUdWO0lBQ3pCVyw0QkFBNEIsR0FBR1g7SUFDL0JZLGNBQWMsR0FBR1o7SUFDakJhLHNCQUFzQixHQUFHYjtJQUN6QmMsd0JBQXdCLEdBQUdkO0lBQzNCZSxrQkFBa0IsR0FBR2Y7SUFDckJnQixlQUFlLEdBQUdoQjtJQUNsQmlCLFlBQVksR0FBR2pCO0lBQ2ZrQixvQkFBb0IsR0FBR2xCO0lBQ3ZCbUIsVUFBVSxHQUFHbkI7OztBQ2hCUixNQUFNb0IsZ0JBQWlCQyxPQUFzQkEsUUFBUTs7QUFDckQsTUFBTUMsd0JBQXdCOztBQUU5QixNQUFNQyxrQkFBa0I7O0FBRXpCLFNBQVVDLHNCQUNkQyxTQUNBQyxXQUNBQyxrQkFBRUEsb0JBQXFCO0lBQUVBLGtCQUFrQjs7SUFFM0MsT0FBTyxDQUNMQyxRQUNBQyxLQUNBQztRQUVBLFdBQVdKLGFBQWEsVUFBVTtZQUNoQyxNQUFNSyxZQUFZQyxRQUFRQyxZQUFZUixTQUFTSyxXQUFXSTtZQUMxRCxJQUFJSCxjQUFjSixrQkFBa0I7Z0JBQ2xDLE9BQU9HO0FBQ1Q7WUFDQUUsUUFBUUcsZUFDTlYsU0FDQTttQkFBS007bUJBQWNMO2VBQ25CSSxXQUFXSTtZQUViLE9BQU9KO0FBQ1Q7UUFDQUUsUUFBUUcsZUFBZVYsU0FBU0MsVUFBVUksV0FBV0k7UUFDckQsT0FBT0o7O0FBRVg7O1NBRWdCTSxxQkFDZFgsU0FDQUMsV0FBYztJQUVkLE9BQVFFO1FBQ04sTUFBTUcsWUFBWUMsUUFBUUMsWUFBWVIsU0FBU0csV0FBVztRQUMxREksUUFBUUcsZUFBZVYsU0FBUyxLQUFJTSxjQUFjTCxZQUFXRTtRQUM3RCxPQUFPQTs7QUFFWDs7QUFFTSxTQUFVUywwQkFDZFosU0FDQUMsVUFDQUMsbUJBQW1CO0lBRW5CLE9BQUEsQ0FBU0MsUUFBZ0JVO1FBQ3ZCLE1BQU1DLGFBQ0pQLFFBQVFDLFlBQVloQyxXQUFXVSw0QkFBNEJpQixXQUFXO1FBRXhFLE1BQU1DLE1BQU0sSUFBSVM7UUFDaEIsS0FBS0MsV0FBV0MsU0FBU1gsTUFBTTtZQUM3QkcsUUFBUUcsZUFDTmxDLFdBQVdVLDRCQUNYLEtBQUk0QixZQUFZLElBQUlELGlCQUNwQlY7QUFFSjtRQUNBLE1BQU1hLG1CQUFtQlQsUUFBUUMsWUFBWVIsU0FBU0csUUFBUVU7UUFDOUQsSUFBSUcsa0JBQWtCO1lBQ3BCLE1BQU1DLGNBQWNDLE9BQU9qQixVQUFVa0IsT0FBT0M7WUFDNUMsTUFBTUMsaUJBQWlCbkIsbUJBQ25CO21CQUNLYzttQkFDQUM7Z0JBRUw7bUJBQ0tBO21CQUNBRDs7WUFHVFQsUUFBUUcsZUFBZVYsU0FBU3FCLGdCQUFnQmxCLFFBQVFVO0FBQzFELGVBQU87WUFDTCxNQUFNUyxPQUNIbkIsUUFBUW9CLGNBQXNCMUIsMkJBQzdCZ0IsY0FDQ1MsUUFBUWYsUUFBUUMsWUFBWSxlQUFlTCxRQUFRVTtZQUV4RE4sUUFBUUcsZUFDTlYsU0FDQTtnQkFDRXNCO21CQUNHSixPQUFPakIsVUFBVWtCLE9BQU9DO2VBRTdCakIsUUFDQVU7QUFFSjtBQUNEO0FBQ0g7O0FBRU0sU0FBVVcscUJBQ2R4QixTQUNBQztJQUVBLE9BQU8sQ0FDTEUsUUFDQUMsS0FDQUM7UUFFQSxJQUFJQSxZQUFZO1lBQ2QsSUFBSW9CO1lBQ0osSUFBSUMsTUFBTUMsUUFBUTFCLFdBQVc7Z0JBQzNCLE1BQU0yQixtQkFDSnJCLFFBQVFDLFlBQVlSLFNBQVNLLFdBQVdJLFVBQVU7Z0JBQ3BEZ0IsWUFBWSxLQUFJRyxxQkFBcUIzQjtBQUN2QyxtQkFBTztnQkFDTCxNQUFNMkIsbUJBQ0pyQixRQUFRQyxZQUFZUixTQUFTSyxXQUFXSSxVQUFVLENBQUE7Z0JBQ3BEZ0IsWUFBWTt1QkFBS0c7dUJBQXFCM0I7O0FBQ3hDO1lBQ0FNLFFBQVFHLGVBQWVWLFNBQVN5QixXQUFXcEIsV0FBV0k7WUFDdEQsT0FBT0o7QUFDVDtRQUVBLElBQUlvQjtRQUNKLElBQUlDLE1BQU1DLFFBQVExQixXQUFXO1lBQzNCLE1BQU0yQixtQkFBbUJyQixRQUFRQyxZQUFZUixTQUFTRyxXQUFXO1lBQ2pFc0IsWUFBWSxLQUFJRyxxQkFBcUIzQjtBQUN2QyxlQUFPO1lBQ0wsTUFBTTJCLG1CQUFtQnJCLFFBQVFDLFlBQVlSLFNBQVNHLFdBQVcsQ0FBQTtZQUNqRXNCLFlBQVlJLE9BQU9DLE9BQU9ELE9BQU9DLE9BQU8sSUFBSUYsbUJBQW1CM0I7QUFDakU7UUFDQU0sUUFBUUcsZUFBZVYsU0FBU3lCLFdBQVd0QjtRQUMzQyxPQUFPQTs7QUFFWDs7QUFFTSxTQUFVNEIscUJBQ2Q5QixVQUNBK0I7SUFFQSxPQUFPLENBRUw3QixRQUNBQyxLQUNBQztRQUVBLE1BQU00QixlQUFlO2VBQ2hCRDtlQUNBZCxPQUFPakIsVUFBVWtCLE9BQU9DOztRQUc3QixJQUFJZixZQUFZO1lBQ2QsTUFBTTZCLGFBQ0ozQixRQUFRQyxZQUFZaEMsV0FBV08sZ0JBQWdCc0IsV0FBV0ksVUFBVTtZQUN0RUYsUUFBUUcsZUFDTmxDLFdBQVdPLGdCQUNYLEtBQUltRCxZQUFZRCxnQkFDaEI1QixXQUFXSTtZQUViLE9BQU9KO0FBQ1Q7UUFFQSxXQUFXRixXQUFXLFVBQVU7WUFDOUIsT0FBT0E7QUFDVDtRQUVBLE1BQU1nQyxlQUFlTixPQUFPTyxvQkFBb0JqQyxPQUFPa0M7UUFFdkQsS0FBSyxNQUFNeEIsZUFBZXNCLGNBQWM7WUFDdEMsSUFBSXhDLGNBQWNrQixjQUFjO2dCQUM5QjtBQUNGO1lBRUEsTUFBTXlCLG1CQUFtQlQsT0FBT1UseUJBQzlCcEMsT0FBT2tDLFdBQ1B4QjtZQUdGLEtBQUt5QixrQkFBa0I7Z0JBQ3JCO0FBQ0Y7WUFFQSxNQUFNRSxjQUFjakMsUUFBUWtDLFlBQzFCM0MsaUJBQ0F3QyxpQkFBaUI3QjtZQUduQixLQUFLK0IsYUFBYTtnQkFDaEI7QUFDRjtZQUVBLE1BQU1OLGFBQ0ozQixRQUFRQyxZQUNOaEMsV0FBV08sZ0JBQ1h1RCxpQkFBaUI3QixVQUNkO1lBQ1BGLFFBQVFHLGVBQ05sQyxXQUFXTyxnQkFDWCxLQUFJbUQsWUFBWUQsZ0JBQ2hCSyxpQkFBaUI3QjtBQUVyQjs7QUFFSjs7U0FFZ0JpQyxvQkFFZEMsT0FDQUM7SUFHQSxLQUFLRCxPQUFPO1FBQ1YsT0FBTyxFQUFDQSxPQUFvQkM7QUFDOUI7SUFDQSxJQUFJQSxhQUFhO1FBRWYsT0FBTyxFQUFDRCxPQUFtQkM7QUFDN0I7SUFDQSxNQUFNQyxlQUFlbEIsUUFBUWdCO0lBQzdCLE1BQU1yQixPQUFPdUIsZUFBZUYsTUFBTSxLQUFLQTtJQUV2QyxPQUFPLEVBQUNyQixNQUFrQnVCO0FBQzVCOztBQ2hOTyxNQUFNekIsY0FBZTBCLGNBQ25CQSxRQUFROztBQUVYLFNBQVVDLGNBQ2RDO0lBRUEsV0FBV0EsYUFBYSxZQUFZO1FBQ2xDLE9BQU9ELGNBQWNDO0FBQ3ZCO0lBRUEsSUFBSXRCLE1BQU1DLFFBQVFxQixXQUFXO1FBQzNCLE9BQU9BO0FBQ1Q7SUFDQSxXQUFXQSxhQUFhLFVBQVU7UUFDaEMsT0FBTztBQUNUO0lBYUEsTUFBTUMsZ0JBQWdCcEIsT0FBT3FCLE9BQU9GLFVBQ2pDRyxPQUFRMUMsZ0JBQWlCQSxVQUFVLFVBQ25DMkMsSUFBSzNDLFNBQWVBLE1BQU00QztJQUU3QixPQUFPeEIsT0FBT3lCLEtBQUtOLFVBQ2hCRyxPQUFRL0MsUUFBUzZDLGNBQWNsQyxTQUFTWCxNQUN4Q2dELElBQUtoRCxPQUFRNEMsU0FBUzVDO0FBQzNCOztBQUVNLFNBQVVtRCxZQUFZTDtJQUMxQixNQUFNTSxZQUFZTixPQUFPQyxPQUFPTSxVQUFVQyxTQUFTO0lBQ25ELE9BQU9GLFlBQVksV0FBVztBQUNoQzs7QUFFTSxTQUFVNUMsd0JBQ2RaLFNBQ0FDLFVBQ0FDLG1CQUFtQjtJQUVuQixPQUFBLENBQVNDLFFBQWdCVTtRQUN2QixNQUFNQyxhQUNKUCxRQUFRQyxZQUFZaEMsV0FBV1UsNEJBQTRCaUIsV0FBVztRQUV4RSxNQUFNQyxNQUFNLElBQUlTO1FBQ2hCLEtBQUtDLFdBQVdDLFNBQVNYLE1BQU07WUFDN0JHLFFBQVFHLGVBQ05sQyxXQUFXVSw0QkFDWCxLQUFJNEIsWUFBWSxJQUFJRCxpQkFDcEJWO0FBRUo7UUFDQSxNQUFNYSxtQkFBbUJULFFBQVFDLFlBQVlSLFNBQVNHLFFBQVFVO1FBQzlELElBQUlHLGtCQUFrQjtZQUNwQixNQUFNQyxjQUFjQyxPQUFPakIsVUFBVWtCLE9BQU9DO1lBQzVDLE1BQU1DLGlCQUFpQm5CLG1CQUNuQjttQkFDS2M7bUJBQ0FDO2dCQUVMO21CQUNLQTttQkFDQUQ7O1lBR1RULFFBQVFHLGVBQWVWLFNBQVNxQixnQkFBZ0JsQixRQUFRVTtBQUMxRCxlQUFPO1lBQ0wsTUFBTVMsT0FFSm5CLFFBQVFvQixjQUFjMUIsMkJBQTJCZ0IsY0FBY1MsUUFDL0RmLFFBQVFDLFlBQVksZUFBZUwsUUFBUVU7WUFFN0NOLFFBQVFHLGVBQ05WLFNBQ0E7Z0JBQ0VzQjtnQkFDQXFDLFVBQVU7bUJBQ1B6QyxPQUFPakIsVUFBVWtCLE9BQU9DO2VBRTdCakIsUUFDQVU7QUFFSjtBQUNEO0FBQ0g7O0FBd0JBLE1BQU0rQyxjQUNKQyxRQU1JQSxLQUFLbEMsV0FBVyxVQUFVa0MsUUFBUUEsS0FBS0MsU0FBU0M7O0FBS2hELFNBQVVDLFlBQ2RDLFVBQThCO0lBRTlCLE9BQU9DLDJCQUEyQkQ7QUFDcEM7O0FBRU0sU0FBVUMsMkJBQ2RELFVBQThCLElBQzlCL0QsbUJBQW1CO0lBRW5CLE9BQU9vQixNQUFNSyxXQUFXZSxvQkFDdEJ1QixRQUFRM0MsTUFDUjJDLFFBQVF0QztJQUVWc0MsVUFBVTtXQUNMQTtRQUNIM0M7UUFDQUs7O0lBR0YsSUFBSWlDLFlBQVlLLFVBQVU7UUFDeEJBLFFBQVEzQyxPQUFPO1FBRWYsTUFBTTZDLGFBQWFwQixjQUFja0IsUUFBUUg7UUFDekNHLFFBQVFHLFFBQVE7WUFDZDlDLE1BQU1pQyxZQUFZWTtZQUNsQkwsTUFBTUs7O2VBR0RGLFFBQVFIO0FBQ2pCLFdBQU8sSUFBSSxVQUFVRyxXQUFXQSxRQUFRSCxTQUFTQyxXQUFXO1FBQzFELE1BQU1JLGFBQWFwQixjQUFja0IsUUFBUUg7UUFFekNHLFFBQVFILE9BQU9LO1FBQ2ZGLFFBQVEzQyxPQUFPaUMsWUFBWVk7QUFDN0I7SUFFQSxJQUFJekMsTUFBTUMsUUFBUXNDLFFBQVEzQyxPQUFPO1FBQy9CMkMsUUFBUTNDLE9BQU87UUFDZjJDLFFBQVFHLFFBQVE7WUFDZDlDLE1BQU07WUFDTjhDLE9BQU87Z0JBQ0w5QyxNQUFNMkMsUUFBUTNDLEtBQUs7OztBQUd6QjtJQUVBLE9BQU9WLHdCQUNMcEMsV0FBV1Msc0JBQ1hnRixTQUNBL0Q7QUFFSjs7U0NoS2dCbUUsc0JBQ2RDLGtCQUNBQyxNQUNBQztJQUVBLE1BQU1DLGFBR0Y7UUFDRkMsS0FBSyxFQUFDQyxjQUFjQyxNQUFNQztRQUMxQkMsTUFBTSxFQUFDSCxjQUFjSSxRQUFRQztRQUM3QkMsS0FBSyxFQUFDTixjQUFjTyxRQUFRQztRQUM1QkMsT0FBTyxFQUFDVCxjQUFjTyxRQUFRRztRQUM5QkMsUUFBUSxFQUFDWCxjQUFjVyxRQUFRQzs7SUFHakMsT0FBT0MsUUFBUUMsdUJBQXVCaEIsV0FBV0Y7SUFDakQsTUFBTXBFLFNBQVN1RixtQkFBbUJuQixNQUFNQztJQUN4QyxPQUFPckUsU0FDSHdGLG1CQUF1QnJCLGtCQUFrQm5FLE9BQU95RixNQUFhekYsT0FBT00sU0FDbEVvRixNQUFNQyx3QkFDTkQsTUFBTUosb0JBQW9CakIsU0FDNUJtQixtQkFBdUJyQixrQkFBa0JrQixVQUN6Q0ssTUFBTUMsd0JBQ05ELE1BQU1KLG9CQUFvQmpCO0FBQ2hDOztTQVNnQnVCLDBCQUNkekIsa0JBQ0FDLE1BQ0FDO0lBRUEsTUFBTUMsYUFHRjtRQUNGQyxLQUFLLEVBQUNzQixzQkFBc0JDLFVBQVVwQjtRQUN0Q0MsTUFBTSxFQUFDa0Isc0JBQXNCRSxZQUFZbEI7UUFDekNDLEtBQUssRUFBQ2Usc0JBQXNCRyxZQUFZaEI7UUFDeENDLE9BQU8sRUFBQ1ksc0JBQXNCRyxZQUFZZDtRQUMxQ0MsUUFBUSxFQUFDVSxzQkFBc0JJLFlBQVliOztJQUc3QyxPQUFPQyxRQUFRQyx1QkFBdUJoQixXQUFXRjtJQUNqRCxNQUFNcEUsU0FBU3FFLE9BQU9rQixtQkFBbUJuQixNQUFNQyxRQUFRVDtJQUN2RCxPQUFPNUQsU0FDSHdGLG1CQUF1QnJCLGtCQUFrQm5FLE9BQU95RixNQUFhekYsT0FBT00sU0FDbEVvRixNQUFNQyx3QkFDTkQsTUFBTUosb0JBQW9CakIsU0FDNUJtQixtQkFBdUJyQixrQkFBa0IsUUFBZWtCLFVBQ3hESyxNQUFNQyx3QkFDTkQsTUFBTUosb0JBQW9CakI7QUFDaEM7O0FBQ0EsU0FBU2tCLG1CQUNQbkIsTUFDQUM7SUFFQSxLQUFLQSxNQUFNLE9BQU9UO0lBRWxCLE1BQU1zQyxhQUFhN0IsS0FBSzhCLFFBQVEsY0FBYztJQUM5QyxNQUFNQyxtQkFBMkM7UUFDL0MsZUFBZUMsc0JBQXNCQztRQUNyQyx5QkFBeUJELHNCQUFzQkU7UUFDL0MsZUFBZUYsc0JBQXNCRztRQUNyQyxlQUFlSCxzQkFBc0JJO1FBQ3JDLHlCQUF5Qkosc0JBQXNCSztRQUMvQyxzQkFBc0JMLHNCQUFzQk07UUFDNUMsMkJBQTJCO1FBQzNCLGtCQUFrQk4sc0JBQXNCTztRQUN4QyxnQkFBZ0JQLHNCQUFzQlE7UUFDdEMsZ0JBQWdCUixzQkFBc0JTO1FBQ3RDLGdCQUFnQlQsc0JBQXNCVTtRQUN0QyxnQkFBZ0JWLHNCQUFzQlc7UUFDdEMscUJBQXFCWCxzQkFBc0JZO1FBQzNDLGtCQUFrQlosc0JBQXNCYTs7SUFHMUMsSUFBSWhCLFdBQVdpQixXQUFXLFdBQVc7UUFDbkMsT0FBTztZQUFFMUIsTUFBTTtZQUFTbkYsT0FBTzRGLFdBQVdDLFFBQVEsWUFBWTs7QUFDaEU7SUFFQSxNQUFNaUIsaUJBQWlCaEIsaUJBQWlCRjtJQUN4QyxJQUFJa0IsZ0JBQWdCO1FBQ2xCLE9BQU87WUFBRTNCLE1BQU07WUFBYW5GLE9BQU84Rzs7QUFDckM7SUFFQSxJQUFJaEQsU0FBUyxTQUFTOEIsZUFBZSxJQUFJO1FBQ3ZDLE9BQU87WUFBRVQsTUFBTTtZQUFRbkYsT0FBT2tFLGNBQWNDOztBQUM5QztJQUVBLE9BQU9iO0FBQ1Q7O0FDakhNLFNBQVV5RCxtQkFDZEMsUUFBNEI7SUFFNUIsTUFBTUMsYUFBYUQsTUFBTXJFLElBQUt1RSxLQUM1QkMsU0FBWTtRQUNWQyxNQUFNRixFQUFFRTtRQUNSQyxhQUFhSCxFQUFFRyxlQUFlLG1CQUFtQkgsRUFBRUU7UUFDbkRsRSxVQUFVZ0UsRUFBRWhFLFlBQVk7UUFFeEJyQyxNQUFNcUcsRUFBRXJHLFFBQVF5Rzs7SUFHcEIsT0FBT0MsbUJBQW1CTjtBQUM1Qjs7QUNsQk8sTUFBTU8sWUFBWWxHLHVCQUN2QixDQUFDbUcsTUFBZUM7SUFDZCxNQUFNQyxVQUFVRCxJQUFJRSxlQUFlQztJQUNuQyxNQUFNQyxPQUFPSCxRQUFRRztJQUdyQixNQUFNQyxhQUFhTCxJQUFJTTtJQUV2QixNQUFNQyxjQUFlRixXQUFtQkc7SUFFeEMsS0FBS0QsYUFBYTtRQUNoQixNQUFNLElBQUlFLDZCQUNSLDRDQUE0Q0osV0FBV1g7QUFFM0Q7SUFFQSxLQUFLVSxNQUFNLE9BQU9BO0lBRWxCLElBQUk3RyxNQUFNQyxRQUFRNEcsT0FBTztRQUN2QixPQUFPQSxLQUFLbkYsSUFBS3lGLFFBQVMsSUFBSUgsWUFBWUc7QUFDNUM7SUFFQSxPQUFPLElBQUlILFlBQVlIOzs7QUNsQjNCLE1BQU1PLGdCQUFnQi9HLHVCQUNwQixDQUFDZ0gsT0FBNkJaO0lBQzVCLE1BQU1hLE1BQU1iLElBQUlFLGVBQWVDO0lBQy9CLE1BQU1XLFdBQVlELEtBQUtFLFVBQVU7SUFDakMsTUFBTUMsWUFBWUosU0FBU2xILE9BQU95QixLQUFLMkY7SUFDdkMsTUFBTUcsVUFBVUQsVUFBVS9GLElBQUtpRyxLQUFNSixTQUFTSTtJQUM5QyxPQUFPO1FBQUVDLEtBQUtMO1FBQVVNLGVBQWVIO1FBQVNJLGFBQWFMOzs7O0FBVTNELFNBQVVNLFlBQ2RoQyxRQUE0QjtJQUU1QixNQUFNc0IsUUFBUXRCLE1BQU1yRSxJQUFLdUUsS0FBTUEsRUFBRUU7SUFDakMsT0FBT2lCLGNBQWNDO0FBQ3ZCOztBQUVPLE1BQU1XLGFBQWEzSCx1QkFDeEIsQ0FBQzRILEdBQVl4QjtJQUNYLE1BQU1hLE1BQU1iLElBQUlFLGVBQWVDO0lBQy9CLE1BQU1zQixRQUFRWixJQUFJWSxTQUFTLENBQUE7SUFFM0IsTUFBTUMsU0FBYztXQUFLRDs7SUFHekIsSUFBSUMsT0FBT0MsVUFBVS9GLFdBQVc7UUFDOUIsTUFBTWdHLElBQUlDLE9BQU9ILE9BQU9DO1FBQ3hCLEtBQUtFLE9BQU9DLE1BQU1GLElBQUlGLE9BQU9DLFFBQVFDO0FBQ3ZDO0lBRUEsSUFBSUYsT0FBT0ssV0FBV25HLFdBQVc7UUFDL0IsTUFBTWdHLElBQUlDLE9BQU9ILE9BQU9LO1FBQ3hCLEtBQUtGLE9BQU9DLE1BQU1GLElBQUlGLE9BQU9LLFNBQVNIO0FBQ3hDO0lBR0EsSUFBSUYsT0FBT00sYUFBYXBHLFdBQVc7UUFDakMsTUFBTWdHLElBQUlDLE9BQU9ILE9BQU9NO1FBQ3hCTixPQUFPTSxXQUFXSCxPQUFPQyxNQUFNRixLQUFLRixPQUFPTSxXQUFXSjtBQUN4RDtJQUVBLE9BQU9GOzs7QUMxREosTUFBTU8sdUJBQXVCOztBQUM3QixNQUFNQyxtQkFBbUI7O0FBQ3pCLE1BQU1DLHdCQUF3Qjs7QUFFOUIsTUFBTUMsY0FBYzs7TUFDZEMsaUJBQWlCQyxPQUFPOztBQUM5QixNQUFNQyxlQUFlOztBQUNyQixNQUFNQywwQkFBMEI7O01BRTFCQyxvQkFBb0JILE9BQU87O0FDUmxDLFNBQVVJLFVBQVVDO0lBQ3hCLE9BQU8sU0FBU0QsT0FBTzFLO1FBQ3JCNEssU0FBU0MsSUFDUDdLLFFBQ0F1SyxjQUNDSSxTQUFTcEgsU0FBU29ILFdBQVc7UUFFaEMsT0FBTzNLO0FBQ1Q7QUFDRjs7QUNRTSxTQUFVOEssaUJBQWlCQztJQUMvQixPQUFPLFNBQVNDLDBCQUEwQmhMO1FBQ3hDNEssU0FBU0MsSUFBSTdLLFFBQVF3Syx5QkFBeUJPO1FBQzlDLE9BQU8vSztBQUNUO0FBQ0Y7O01DMUJhaUwsZUFBZVgsT0FBTzs7QUFDNUIsTUFBTVksZ0JBQWdCOztBQUN0QixNQUFNQyxnQkFBZ0I7O0FBQ3RCLE1BQU1DLHFCQUFxQjs7QUFDM0IsTUFBTUMsdUJBQXVCOztBQ0s3QixJQUFNQyxzQkFBTixNQUFNQSw0QkFBdUVDO0lBSWxGLFdBQUFuSyxDQUE2QnlIO1FBQzNCMkMsTUFDRTtZQUNFQyxXQUFZeEQsV0FBc0JBLFNBQWlCeUQsV0FBVzlIO1dBRWhFaUY7UUFMMEM4QyxLQUFBOUMsTUFBQUE7UUFIOUM4QyxLQUFBQyxPQUFPQyxLQUFLQyxTQUFTQztRQVVuQkosS0FBSzFELFVBQVVZO0FBQ2pCO0lBRUEsR0FBQW1ELENBQUlDO1FBQ0YsSUFBSUM7UUFDSjtZQUNFQSxZQUFZUCxLQUFLUSxJQUFJO0FBRXZCLFVBQUUsT0FBT0M7WUFDUEYsWUFBWSxDQUFBO0FBQ2Q7UUFFQVAsS0FBS1UsV0FBVztZQUNkSCxXQUFXeEssT0FBT0MsT0FBT3VLLFdBQVdEOztBQUV4Qzs7O0FBMUJXWCxzQkFBbUJnQixXQUFBLEVBRC9CQyxXQUFXO0lBQUVDLE9BQU9DLE1BQU1DO0lBS1pDLFFBQUEsR0FBQUMsT0FBT0YsMERBSlRwQjs7QUNhTixJQUFNdUIsa0JBQU4sTUFBTUE7SUFDWCxXQUFBekwsQ0FDbUIwTCxXQUNFQyxnQkFDZ0NDO1FBRmxDckIsS0FBQW1CLFlBQUFBO1FBQ0VuQixLQUFBb0IsaUJBQUFBO1FBQ2dDcEIsS0FBQXFCLGNBQUFBO0FBQ2xEO0lBRUgsZUFBTUMsQ0FDSmpGLEtBQ0FrRjtRQUVBLE1BQU1DLE1BQU1DLFFBQVFDLElBQUkxQixNQUFhMEIsSUFBSTFCLEtBQUtzQjtRQUU5QyxNQUFNSyxXQUFXM0IsS0FBS21CLFVBQVVTLGtCQUEyQnBDLGVBQWUsRUFDeEVuRCxJQUFJd0YsY0FDSnhGLElBQUlNO1FBR04sTUFBTW1GLFlBQ0o5QixLQUFLbUIsVUFBVVgsSUFDYmpCLGVBQ0FsRCxJQUFJd0YsaUJBRU43QixLQUFLbUIsVUFBVVgsSUFBMEJqQixlQUFlbEQsSUFBSU07UUFFOUQsTUFBTW9GLGdCQUFnQi9CLEtBQUttQixVQUFVUyxrQkFDbkNuQyxvQkFDQSxFQUFDcEQsSUFBSXdGLGNBQWN4RixJQUFJTTtRQUd6QixNQUFNcUYsaUJBQWlCaEMsS0FBS21CLFVBQVVTLGtCQUNwQ2xDLHNCQUNBLEVBQUNyRCxJQUFJd0YsY0FBY3hGLElBQUlNO1FBR3pCLE1BQU1zRixpQkFBaUJELGlCQUFpQi9KLFlBQVk2SjtRQUVwRE4sSUFBSVUsUUFBUSxzQkFBc0JKLFlBQVksUUFBUUEsY0FBYztRQUVwRSxJQUFJSCxVQUFVO1lBQ1pILElBQUlXLE1BQU07QUFDWixlQUFPLElBQUluQyxLQUFLcUIsYUFBYTtrQkFDckJyQixLQUFLcUIsWUFBWWUsVUFDckIvRixLQUNBNEYsZ0JBQ0FGLGVBQ0EvQixLQUFLb0I7QUFFVCxlQUFPO1lBQ0xJLElBQUlXLE1BQU07QUFDWjtjQUtNbkMsS0FBS3FDO1FBRVgsTUFBTUMsT0FBT3RDLEtBQUtvQixlQUFlbUIsZUFBZTtRQUNoRCxNQUFNQyxlQUFleEMsS0FBS29CLGVBQWVtQixlQUFlO1FBQ3hELElBQUlELFFBQVFFLGNBQWM7WUFDeEIsTUFBTUMsYUFBYXpDLEtBQUtvQixlQUFlWixJQUFJO1lBQzNDLE1BQU1rQyxXQUFXRCxXQUFXZixJQUFJO2dCQUFFWTtnQkFBTUU7O1lBQ3hDeEMsS0FBS29CLGVBQWVWLFdBQVc7Z0JBQUVpQyxRQUFRRDs7QUFDM0M7UUFFQSxPQUFPbkIsS0FBS3FCO0FBQ2Q7SUFFVSx1QkFBTVA7UUFDZCxNQUFNckQsV0FBVzZELFFBQVFDO1FBQ3pCLEtBQUs5RCxVQUFVO1FBRWYsS0FBSyxNQUFNK0QsV0FBVy9ELFVBQVU7WUFDOUIsTUFBTWdFLGNBQWNILFFBQVFJLGVBQzFCRjtZQUVGLEtBQUtDLGFBQWE7WUFDbEIsTUFBTUUsYUFBYUYsWUFBWUUsS0FBS2xELEtBQUtvQjtZQUN6QyxJQUFJOEIsTUFBTWxELEtBQUtvQixlQUFlVixXQUFXd0M7QUFDM0M7QUFDRjs7O0FBaEZXaEMsa0JBQWVQLFdBQUEsRUFEM0JDLFdBQVc7SUFBRUMsT0FBT0MsTUFBTUM7SUFLdEJDLFFBQUEsR0FBQW1DLGFBQVluQyxRQUFBLEdBQUFDLE9BQU8zQixrREFGUThELFdBQ096RCxxQkFBbUI1SixhQUg3Q21MOztBQ2ZQLFNBQVVtQyxLQUFLQztJQUNuQixNQUFNQyxXQUFXRCxlQUNOQSxVQUFVLFdBQ2ZBLFFBQ0FBLE1BQU12SCxPQUNSOUQ7SUFDSixNQUFNdUwsT0FBTyxFQUFDQyxpQkFBaUJDLGdCQUFnQnhDO0lBQy9DLElBQUlxQyxVQUFVQyxLQUFLRyxLQUFLQyxZQUFZckUsZUFBZWdFO0lBQ25ELE9BQU9ySCxtQkFBbUJzSDtBQUM1Qjs7U0FFZ0JLO0lBQ2QsT0FBTzNILGdCQUFnQjBILFlBQVlwRSxlQUFlO0FBQ3BEOztBQUVNLFNBQVVzRSxnQkFBZ0JDO0lBQzlCLE9BQU83SCxnQkFDTDhILFlBQVksV0FDWkosWUFBWW5FLG9CQUFvQnNFLFFBQ2hDTCxnQkFBZ0J4QztBQUVwQjs7QUNoQk0sU0FBVStDLG9CQUNkeEw7SUFFQSxNQUFNRSxhQUFvRTtRQUN4RUMsS0FBS0c7UUFDTEMsTUFBTUU7UUFDTkMsS0FBS0U7UUFDTEMsT0FBT0M7UUFDUEMsUUFBUUM7O0lBR1YsTUFBTXlLLFlBQVl2TCxXQUFXRjtJQUU3QixLQUFLeUwsV0FBVztRQUNkLE1BQU0sSUFBSUMsTUFDUiwwQkFBMEIxTDtBQUU5QjtJQUVBLE9BQU95TDtBQUNUOztBQ05BLE1BQU1FLG9CQUFxQkMsYUFDbEJBLFVBQ0pDLE1BQU0sS0FDTmpOLE9BQVF3RSxLQUFNQSxFQUFFTCxXQUFXLE1BQzNCbEUsSUFBS3VFLEtBQU1BLEVBQUUwSSxNQUFNOztBQUd4QixNQUFNQyxlQUFnQnpJLFNBQVk7SUFDaENBO0lBQ0FDLGFBQWEsR0FBR0Q7SUFDaEJsRSxVQUFVO0lBQ1ZyQyxNQUFNeUc7OztBQUdGLFNBQVV3SSxpQkFDZEMsWUFDQUwsV0FDQU0sVUFDQUMscUJBQThCO0lBRTlCLE1BQU1DLG1CQUFtQlosb0JBQW9CVTtJQUM3QyxNQUFNRyxnQkFBZ0JWLGtCQUFrQkMsV0FBVy9NLElBQUlrTjtJQUV2RCxNQUFNTyxxQkFBcUI7SUFDM0IsSUFBSUosYUFBYSxTQUFTQyxvQkFBb0I7UUFDNUNHLG1CQUFtQnBCLEtBQ2pCcUIsU0FBUztZQUNQakosTUFBTTtZQUNObEUsVUFBVTtZQUNWRyxNQUFNaU47WUFDTmpKLGFBQWE7WUFFZmdKLFNBQVM7WUFDUGpKLE1BQU07WUFDTmxFLFVBQVU7WUFDVm1FLGFBQWE7WUFFZmdKLFNBQVM7WUFDUGpKLE1BQU07WUFDTmxFLFVBQVU7WUFDVm1FLGFBQWE7O0FBR25CO0lBRUEsT0FBTztRQUNMa0osUUFBUSxFQUNOTCxpQkFBaUJSLGVBQ2RTLGNBQWN4TixJQUFJNk4sY0FDbEJKLG9CQUNISyxhQUFhO1lBQ1hDLFNBQVMsd0NBQXdDWDtZQUVuRFksY0FBYztZQUNadEosYUFBYTtZQUVmdUoscUJBQXFCO1lBQ25CdkosYUFBYTs7UUFHakJvQixRQUFRLEVBQUNPLFlBQVltSCxnQkFBZ0JVOztBQUV6Qzs7QUFFTSxTQUFVQyxtQkFDZHBSLFFBQ0FxUSxZQUNBblEsWUFDQXFIO0lBRUEsTUFBTThKLFFBQVFyUixRQUFRa0MsYUFBYWxDO0lBQ25DdUgsV0FBV3NKLE9BQU9TLFFBQVNDLEtBQU1BLEVBQUVGLE9BQU9oQixZQUFZblE7SUFDdERxSCxXQUFXd0IsUUFBUXVJLFFBQVEsQ0FBQ0MsR0FBR0MsVUFBVUQsRUFBRUYsT0FBT2hCLFlBQVltQjtBQUNoRTs7QUFFTSxTQUFVQyx5QkFDZEMsYUFDQXJCLGVBQ0dzQjtJQUVILElBQUlELHVCQUF1QkUsY0FBYztRQUN2QyxjQUFlRixZQUFvQnJCLGdCQUFnQixhQUM5Q3FCLFlBQW9CckIsZUFBZXNCLFFBQ3BDRCxZQUFZRyxVQUFVeEIsZUFBZXNCO0FBQzNDO0lBRUEsV0FBWUQsWUFBb0JyQixnQkFBZ0IsWUFDOUMsT0FBUXFCLFlBQW9CckIsZUFBZXNCO0lBRTdDLE1BQU0sSUFBSTdCLE1BQ1IsdUJBQXVCTyw0QkFBNEJxQixhQUFhdFEsYUFBYXNHO0FBRWpGOztBQUVNLFNBQVVvSyxtQkFBc0J6QjtJQUNwQyxPQUFPMEIsZUFFTEMsWUFDQUM7UUFFQSxNQUFNOUUsTUFBY3hCLEtBQUt3QixJQUFJRSxJQUFJZ0Q7UUFFakM7WUFDRWxELElBQUlXLE1BQ0YsZ0NBQWdDdUMsaUNBQWlDNkIsS0FBS0MsVUFBVUgsV0FBVzVJO1lBRTdGLE9BQU1nSixXQUFFQSxXQUFTekksT0FBRUEsT0FBS0ksUUFBRUEsVUFBV2tJO1lBQ3JDLGFBQWFSLHlCQUNYOUYsS0FBSytGLGVBQ0xyQixlQUNHMkIsV0FBVzVJLGVBQ2RnSixXQUNBekksT0FDQUk7QUFFSixVQUFFLE9BQU9xQztZQUNQZSxJQUFJa0YsTUFBTSxpQkFBaUJoQyxzQkFBc0JqRTtZQUNqRCxNQUFNQTtBQUNSO0FBQ0Y7QUFDRjs7U0FFZ0JrRyxrQkFDZEMsaUJBQ0FsQyxZQUNBbUM7SUFFQTlRLE9BQU8rUSxlQUNMRixnQkFBZ0JyUSxhQUFhcVEsaUJBQzdCbEMsWUFDQTtRQUNFL1AsT0FBT2tTO1FBQ1BFLFVBQVU7O0lBSWQsT0FBT2hSLE9BQU9VLHlCQUNabVEsZ0JBQWdCclEsYUFBYXFRLGlCQUM3QmxDO0FBRUo7O0FDekpNLE1BQU9zQyx5QkFBeUJDO0lBSzFCLFlBQUFDLENBQWFoSztRQUNyQixNQUFNaUssV0FBV2pLLElBQUk2QyxRQUFRcUgsZUFBZTlDLE1BQU0sS0FBSztRQUN2RCxPQUFPNkM7QUFDVDtJQUVVLGVBQUFFLENBQWdCaEw7UUFDeEIsTUFBTWEsTUFBTWIsSUFBSUUsZUFBZUM7UUFDL0IsTUFBTTJLLFdBQVduSCxLQUFLa0gsYUFBYWhLO1FBQ25DLEtBQUtpSyxVQUFVLE1BQU0sSUFBSUcsbUJBQW1CO1FBQzVDLE9BQU87WUFBRWhGLE1BQU02RTtZQUFVcEQsT0FBTyxFQUFDb0Q7O0FBQ25DOzs7QUFRSSxNQUFPSSw2QkFBNkJQOztBQ2hDekNuRSxRQUFnQkksaUJBQWlCLFNBQVN1RSxlQUV6Q0M7SUFDQSxNQUFNQyxlQUNHRCxZQUFZLFdBQVdBLFVBQVdBLFFBQVFDO0lBQ25ELE9BQU96SSxTQUFTLFlBQVlOLE9BQU8rQyxJQUFJLGlCQUFpQmdHO0FBQzFELEVBQUVDLEtBQUs5RTs7QUFFTkEsUUFBZ0JDLHNCQUFzQixTQUFTOEU7SUFHOUMsTUFBTUMsT0FBTzVJLFNBQVMsWUFBWU4sT0FBTytDLElBQUk7SUFDN0MsS0FBS21HLE1BQU0sT0FBTzVQO0lBQ2xCLE9BQU9sQyxPQUFPeUIsS0FBS3FRO0FBQ3JCLEVBQUVGLEtBQUs5RTs7QUFFTmlGLFFBQWdCdlIsVUFBVXdSLGFBQWEsU0FBU0EsV0FFaENDO0lBQ2YsTUFBTUMsVUFBVWpJLEtBQUtpSTtJQUNyQixJQUFJQSxTQUFTRCxJQUFJRSxPQUFPLGtCQUFrQjNCLEtBQUtDLFVBQVV5QjtJQUN6RCxPQUFPRDtBQUNUOztBQ2RBLE1BQU16UixZQUFZNFIsYUFBYTVSOztBQUkvQixLQUFLQSxVQUFVNlIsZUFBZTtJQUM1QjdSLFVBQVU2UixnQkFBZ0IsU0FBVWxFO1FBQ2xDLEtBQU1sRSxLQUFhcUksa0JBQWtCO1lBQ2xDckksS0FBYXFJLG1CQUFtQjtBQUNuQztRQUNDckksS0FBYXFJLGlCQUFpQjFFLEtBQUtPO1FBQ3BDLE9BQU9sRTtBQUNUO0FBQ0Y7O0FBRUF6SixVQUFVOE0sT0FBTyxTQUFVQztJQUN6QixPQUFPdEQsS0FBS29JLGNBQWMvRSxLQUFLQztBQUNqQzs7QUFFQSxLQUFNL00sVUFBa0IrUiw0QkFBNEI7SUFDbEQsTUFBTUMsZ0JBQWdCaFMsVUFBVWlTO0lBQ2hDalMsVUFBVWlTLFFBQVE7UUFDaEIsSUFBSUMsU0FBU0YsY0FBY0csS0FBSzFJO1FBQ2hDLE1BQU1wRSxhQUFjb0UsS0FBYXFJO1FBQ2pDLElBQUl6TSxZQUFZaEUsUUFBUTtZQUN0QixLQUFLLE1BQU1zTSxhQUFhdEksWUFBWTtnQkFDbEMsTUFBTStNLFlBQVl6RSxVQUFVdUU7Z0JBQzVCLElBQUlFLFdBQVc7b0JBQ2JGLFNBQVNFO0FBQ1g7QUFDRjtBQUNGO1FBQ0EsT0FBT0Y7QUFDVDtJQUNDbFMsVUFBa0IrUiw2QkFBNkI7QUFDbEQ7Ozs7QUNjTyxJQUFNTSxpQ0FBOEJDLG1DQUFwQyxNQUFNRDtJQUNYLFdBQUFuVCxDQUNxQjJMLGdCQUNBMEg7UUFEQTlJLEtBQUFvQixpQkFBQUE7UUFDQXBCLEtBQUE4SSxXQUFBQTtBQUNsQjtJQUVPLG1CQUFNQyxDQUFjN0w7UUFDNUIsTUFBTTZDLFVBQVU3QyxJQUFJNkM7UUFDcEIsTUFBTWlKLFFBQTBCO1lBQzlCakosU0FBU0E7WUFDVFEsV0FBVyxDQUFBOztRQUdiLE1BQU0wSSxLQUFLQyxVQUFVaE07UUFDckIsTUFBTXlGLFNBQVNsQixRQUFRakIsTUFBTWtCLElBQUk7WUFBRXVIOztRQUVuQ2pKLEtBQUtvQixlQUFlVixXQUNsQjNLLE9BQU9DLE9BQ0wsQ0FBQSxHQUNBbVQscUJBQ0E7WUFDRXhHO1lBQ0F5RyxXQUFXLElBQUlDO1lBQ2ZDLFdBQVcsR0FBR3BNLElBQUlnSSxVQUFVaEksSUFBSXFNO1dBRWxDUDtBQUdOO0lBRUEsZUFBTTFILENBQVVrSSxTQUEyQmpJO1FBQ3pDLE1BQU1yRSxNQUFNc00sUUFBUWpOLGVBQWVDO1FBQ25DLE1BQU13TCxNQUFNd0IsUUFBUWpOLGVBQWVrTjtRQUNuQyxNQUFNakksTUFBTUMsUUFBUUMsSUFBSW1ILGtDQUFnQ25ILElBQUkxQixLQUFLc0I7UUFDakVFLElBQUlXLE1BQ0YsV0FBV25DLEtBQUtvQixlQUFlbkIsbUJBQW1CL0MsSUFBSWdJLFVBQVVoSSxJQUFJcU07Y0FFaEV2SixLQUFLK0ksY0FBYzdMO1FBQ3pCc0UsSUFBSVcsTUFDRixXQUFXbkMsS0FBS29CLGVBQWVuQixrQ0FBa0MvQyxJQUFJZ0ksVUFBVWhJLElBQUlxTTtjQUcvRXZKLEtBQUs4SSxTQUFTWSxLQUFLeE0sS0FBSzhLO1FBQzlCeEcsSUFBSVcsTUFDRixXQUFXbkMsS0FBS29CLGVBQWVuQixzQ0FBc0MvQyxJQUFJZ0ksVUFBVWhJLElBQUlxTTtRQUV6RixPQUFPaEksS0FBS3FCO0FBQ2Q7OztBQS9DV2dHLGlDQUE4QkMsbUNBQUFsSSxXQUFBLEVBRDFDQyxXQUFXO0lBQUVDLE9BQU9DLE1BQU1DO3NDQUdZcEIscUJBQ05nSywyQkFIcEJmOztBQWtEYixTQUFTTSxVQUFVaE07SUFDakIsTUFBTTZDLFVBQVU3QyxJQUFJNkM7SUFDcEIsU0FBUzZKLGNBQWNqVjtRQUNyQixLQUFLQSxPQUFPLE9BQU9zRDtRQUNuQixNQUFNNFIsWUFBWWpVLE1BQU1DLFFBQVFsQixTQUFTQSxNQUFNLEtBQUtBO1FBQ3BELE9BQU9rVixVQUNKdkYsTUFBTSxLQUNOaE4sSUFBS3dTLFdBQVlBLFFBQVFDLFFBQ3pCMVMsT0FBTzJTLFNBQVM7QUFDckI7SUFDQSxPQUNFSixjQUFjN0osVUFBVSx1QkFDeEI2SixjQUFjN0osVUFBVSxpQkFDeEI2SixjQUFjN0osVUFBVSx1QkFDeEI2SixjQUFjN0osVUFBVSxpQkFDeEI3QyxJQUFJK0w7QUFFUjs7OztBQ2pITyxJQUFNZ0Isa0JBQWVDLG9CQUFyQixNQUFNRDtJQUNYLGNBQU9FLENBQ0xoUyxVQUFrQztRQUVsQyxNQUFNaVMsWUFBd0MsRUFDNUNsSixpQkFDQTBILGdDQUNBO1lBQ0V5QixTQUFTQztZQUNUQyxVQUFVM0I7O1FBSWQsSUFBSXpRLFFBQVEwTyxTQUFTO1lBQ25CdUQsVUFBVXpHLEtBQUt4TCxRQUFRME87WUFDdkJ1RCxVQUFVekcsS0FBSztnQkFDYjBHLFNBQVMvSztnQkFDVGlMLFVBQVVwUyxRQUFRME87O0FBRXRCO1FBRUEsSUFBSTFPLFFBQVFxUyxRQUFRO1lBQ2pCSixVQUFvQnpHLEtBQUs7Z0JBQ3hCMEcsU0FBU0M7Z0JBQ1RHLGFBQWF2Sjs7QUFFakI7UUFFQSxPQUFPO1lBQ0x3SixRQUFRUjtZQUNSTSxRQUFRclMsUUFBUXFTLFVBQVU7WUFDMUJKO1lBQ0FPLFNBQVMsRUFBQ3pKLGlCQUFpQjVCOztBQUUvQjs7O0FBbENXMkssa0JBQWVDLG9CQUFBdkosV0FBQSxFQUQzQmlLLE9BQU8sQ0FBQSxNQUNLWDs7OztBQ3FDTixJQUFNTix1QkFBb0JrQix5QkFBMUIsTUFBTWxCO0lBQ1gsV0FBQWxVLENBQzJDcVYsVUFDeEJ0QjtRQUR3QnhKLEtBQUE4SyxXQUFBQTtRQUN4QjlLLEtBQUF3SixVQUFBQTtBQUNoQjtJQUVILFVBQU1FLENBQUt4TSxLQUFjOEs7UUFDdkIsTUFBTXhHLE1BQU1DLFFBQVFDLElBQUltSix1QkFBcUI5TyxNQUFNMkYsSUFBSTFCLEtBQUswSjtRQUM1RGxJLElBQUlXLE1BQ0YsV0FBV25DLEtBQUt3SixRQUFRdkosZ0JBQWdCRCxLQUFLOEssU0FBU2xULCtCQUErQnNGLElBQUlnSSxVQUFVaEksSUFBSXFNO1FBRXpHLEtBQUssTUFBTTFDLFdBQVc3RyxLQUFLOEssVUFBVTtrQkFDN0JqRSxRQUFRakUsT0FBTzVDLEtBQUt3SixTQUFTdE0sS0FBSzhLO0FBQzFDO0FBQ0Y7OztBQWRXMkIsdUJBQW9Ca0IseUJBQUFsSyxXQUFBLEVBRGhDQyxXQUFXO0lBQUVDLE9BQU9DLE1BQU1DO0lBR3RCQyxRQUFBLEdBQUFDLE9BQU92QywyREFDa0JpQiwwQkFIakJnSzs7QUN6Q04sSUFBTW9CLDJCQUFOLE1BQU1BO0lBQ1gsV0FBQXRWLENBQXNCNEc7UUFBQTJELEtBQUEzRCxNQUFBQTtBQUEyQjtJQUVqRCxTQUFBaUYsQ0FBVWtJLFNBQTJCakk7UUFDbkMsSUFBSXlKLFdBQVd4QixRQUFRak4sZUFBZWtOO1FBRXRDLE9BQU9sSSxLQUFLcUIsU0FBU3FJLEtBQ25CQyxJQUFLOU87WUFDSDRPLFdBQVdoTCxLQUFLM0QsSUFBSTBMLFdBQVdpRDs7QUFHckM7OztBQVhXRCwyQkFBd0JwSyxXQUFBLEVBRHBDQyxnREFFNEJqQiwwQkFEaEJvTDs7QUNJUCxNQUFnQkksd0JBRVpDO0lBQ1IsV0FBQTNWLENBQ3FCNFYsZUFDbkJDO1FBRUF6TCxNQUFNd0w7UUFIYXJMLEtBQUFxTCxnQkFBQUE7QUFJckI7OztBQUdJLE1BQWdCRSw2QkFHWko7SUFHUixXQUFBMVYsQ0FDOEI0VixlQUM1QkM7UUFFQXpMLE1BQU13TCxlQUFlQztRQUhPdEwsS0FBQXFMLGdCQUFBQTtBQUk5QjtJQUlBLFdBQUF0RixDQUFZMUo7UUFDVixLQUFLMkQsS0FBS3dMLGNBQ1I7WUFDRXhMLEtBQUt3TCxlQUFlQyxVQUFRakwsSUFBcUJSLEtBQUtuRDtBQUV4RCxVQUFFLE9BQU80RDtZQUNQO2dCQUNFVCxLQUFLd0wsZUFBZXZGLGFBQWF5RixXQUMvQjFMLEtBQUtuRDtBQUdULGNBQUUsT0FBTzREO2dCQUNQVCxLQUFLd0wsZUFBZUcsYUFBV0MsU0FBUzVMLEtBQUtuRDtBQUMvQztBQUNGO1FBRUYsTUFBTTBELFlBQVlQLEtBQUtxTCxjQUFjUTtRQUVyQyxPQUFPeFAsTUFDSDJELEtBQUt3TCx3QkFBd0JHLGVBQzNCM0wsS0FBS3dMLGFBQWFNLFNBQVN2TCxhQUMzQlAsS0FBS3dMLGFBQWE5SixJQUFJbkIsYUFDeEJQLEtBQUt3TDtBQUNYOzs7QUNuREYsTUFBTU8sV0FBVyxJQUFJQzs7QUE4QmYsU0FBVUMsT0FDZEMsSUFDQTVJLE9BQ0E2SSxRQUErQixJQUFJQztJQUVuQyxLQUFLQyx5QkFBeUJwWCxTQUFTaVgsS0FBSztRQUMxQyxPQUFPNUk7QUFDVDtJQUVBLE1BQU1nSixRQUFRQyxZQUFZTDtJQUMxQixNQUFNTSxTQUFTRixNQUFNOUwsSUFBSThDO0lBQ3pCLElBQUlrSixRQUFRLE9BQU9BO0lBRW5CLE1BQU1DLGFBQWEsRUFDakI1VCxjQUFjTyxRQUNkYyxzQkFBc0JHLGFBQ3RCcEYsU0FBU2lYO0lBRVgsTUFBTVE7SUFDTkosTUFBTXBOLElBQUlvRSxPQUFPb0o7SUFFakIzVyxPQUFPK1EsZUFBZTRGLFlBQVksUUFBUTtRQUN4Qy9YLE9BQU8sR0FBR2dZLGFBQWFySixNQUFNdkgsUUFBUTRRLGFBQWFUOztJQUdwRCxNQUFNVSxTQUFTO1FBQ2I7WUFDRSxPQUFPQyxNQUFNQyxHQUFHeEo7QUFDbEIsVUFBRTtZQUNBLE9BQU9yTDtBQUNUO0FBQ0QsTUFOYztJQVFmLE1BQU04VSxrQkFBa0JILFNBQVNDLE1BQU1HLFFBQVExSixTQUFnQnJMO0lBQy9ELE1BQU1nVixlQUFlTCxTQUNqQm5ZLFFBQVFDLFlBQVksZUFBZTRPLE1BQU0vTSxXQUFXcVcsVUFDcEQzVTtJQUNKLE1BQU1pVixrQkFDSkQsaUJBQWlCL08sVUFBVStPLGlCQUFpQkU7SUFDOUMsTUFBTUMsa0JBQ0ZMLGlCQUFpQk0sY0FDbEJULFNBQ0dDLE1BQU1TLG9CQUFvQmhLLE9BQWNzSixXQUN4Q1cscUNBQXFDakssT0FBT3NKLFdBQzVDTSxrQkFDQTtJQUVOLE1BQU1NLFdBQVc1WCxNQUFNc04sS0FBSyxJQUFJa0osSUFBSW5OLFNBQVNqSyxXQUFXc08sVUFBVTtJQUNsRSxNQUFNbUssWUFBWSxJQUFJckIsSUFBYVMsTUFBTVksVUFBVW5LLFVBQXVCO0lBQzFFLE1BQU1vSyxjQUF3QjtJQUU5QixLQUFLLE1BQU1DLFFBQVFILFVBQVU7UUFDM0IsS0FBS0csTUFBTTtRQUNYLElBQUlGLFVBQVVHLElBQUlELE9BQU87UUFFekIsSUFBSUEsU0FBU2YsV0FBV0gsY0FBY1csZUFBZTtRQUNyRCxJQUFJTyxTQUFTZixVQUFVVyxxQ0FBcUNqSyxPQUFPcUssT0FDakU7UUFFRkQsWUFBWS9KLEtBQUtnSztBQUNuQjtJQUVBLEtBQUssTUFBTUEsUUFBUUQsYUFBYTtRQUM5QixNQUFNRyxhQUFhQywrQkFBK0J4SyxPQUFPcUs7UUFDekQsTUFBTUksZUFBZUYsYUFBYUcsZUFBZUM7UUFDakQsTUFBTUMsV0FDSkMseUJBQXlCN0ssT0FBT3FLLFNBQ2hDbFosUUFBUUMsWUFBWSxlQUFlNE8sTUFBTS9NLFdBQVdvWDtRQUV0RCxNQUFNUyxhQUFnRDtZQUNwRHZXLFVBQVVrVzs7UUFFWixJQUFJRyxVQUFVRSxXQUFXNVksT0FBTzBZO1FBRWhDaFcsWUFBWWtXLFdBQVpsVyxDQUF3QndVLFdBQVduVyxXQUFXb1g7UUFFOUMsTUFBTVUsYUFDSjVaLFFBQVFDLFlBQVksZUFBZTRPLE1BQU0vTSxXQUFXb1gsU0FBU087UUFDL0QsV0FBV0csZUFBZSxhQUFhO1lBQ3JDNVosUUFBUUcsZUFDTixlQUNBeVosWUFDQTNCLFdBQVduVyxXQUNYb1g7QUFFSjtRQUVBNVgsT0FBTytRLGVBQWU0RixXQUFXblcsV0FBV29YLE1BQU07WUFDaERoWixPQUFPc0Q7WUFDUDhPLFVBQVU7WUFDVnVILFlBQVk7WUFDWkMsY0FBYzs7QUFFbEI7SUFFQSxLQUFLLE1BQU1DLFlBQVlmLFdBQVc7UUFDaEMsTUFBTWdCLGVBQWV4UCxTQUFTd08sVUFBVW5LLE9BQU9rTDtRQUMvQyxLQUFLQyxjQUFjO1lBQ2pCLE1BQU0sSUFBSUMsY0FBYyx5QkFBeUJGO0FBQ25EO1FBRUEsSUFBSUcsZUFDRkYsYUFBYTVSO1FBQ2YsV0FBVzhSLGlCQUFpQixlQUFlQSxhQUFhNVMsTUFBTTtZQUM1RDRTLGVBQWdCQTtBQUNsQjtRQUNBLEtBQUtBLHVCQUF1QkEsaUJBQWlCLFlBQVk7WUFDdkQsTUFBTSxJQUFJRCxjQUFjLHFCQUFxQkY7QUFDL0M7UUFDQSxLQUFLM0IsTUFBTXJNLElBQUltTyxhQUFhNVMsT0FBTztZQUNqQztBQUNGO1FBRUEsTUFBTThMLE9BQU81SSxTQUFTMlAsY0FBY3RMLE9BQU9rTDtRQUMzQyxNQUFNM1ksWUFBYWdTLE9BQWVtRyxlQUFlYTtRQUNqRCxNQUFNZCxlQUFnQmxHLE9BQWVtRyxlQUFlQztRQU1wRCxNQUFNYSxhQUFhM0MsTUFBTXlCLElBQUllO1FBRTdCLElBQUlHLFlBQVk7WUFDZCxNQUFNQyxhQUFhQyxpQkFBaUJMO1lBQ3BDTSxpQkFBaUJ2QyxZQUFZOEIsVUFBVU8sWUFBWWxaLFNBQVNrWTtZQUM1RDtBQUNGO1FBRUEsTUFBTW1CLGNBQWNqRCxPQUFPQyxJQUFJeUMsY0FBYyxJQUFJdkMsSUFBSUQsT0FBT2dELElBQUk3TDtRQUVoRSxJQUFJbUosWUFBWTtZQUNkMkMsa0JBQ0UxQyxZQUNBOEIsVUFDQUcsY0FDQU8sYUFDQXJaLFNBQ0FrWTtBQUVKLGVBQU87WUFDTHNCLFlBQVkzQyxZQUFZOEIsVUFBVVUsYUFBYXJaLFNBQVNrWTtBQUMxRDtBQUNGO0lBRUEsT0FBT3JCO0FBQ1Q7O0FBRUEsU0FBUzJDLFlBQ1BDLFVBQ0FkLFVBQ0FVLGFBQ0FyWixTQUNBa1k7SUFFQSxNQUFNSyxhQUFnRDtRQUNwRDVZLE1BQU0wWjtRQUNOclgsVUFBVWtXO1FBQ1ZsWTs7SUFFRnFDLFlBQVlrVyxXQUFabFcsQ0FBd0JvWCxTQUFTL1ksV0FBV2lZO0lBQzVDL1osUUFBUUcsZUFDTixlQUNBaUIsVUFBVUQsUUFBUXNaLGFBQ2xCSSxTQUFTL1ksV0FDVGlZO0lBRUZ6WSxPQUFPK1EsZUFBZXdJLFNBQVMvWSxXQUFXaVksVUFBVTtRQUNsRDdaLE9BQU9zRDtRQUNQOE8sVUFBVTtRQUNWdUgsWUFBWTtRQUNaQyxjQUFjOztBQUVsQjs7QUFNQSxTQUFTVSxpQkFDUEssVUFDQWQsVUFDQU8sWUFDQWxaLFNBQ0FrWTtJQUVBLE1BQU1LLGFBQWdEdlksVUFDakQ7UUFBRUwsTUFBTTtRQUFTOEMsT0FBTztZQUFFOUMsTUFBTXVaOztRQUFjbFgsVUFBVWtXO1FBQ3hEO1FBQUV2WSxNQUFNdVosZUFBZSxZQUFZN1EsU0FBU2pDO1FBQVFwRSxVQUFVa1c7O0lBQ25FN1YsWUFBWWtXLFdBQVpsVyxDQUF3Qm9YLFNBQVMvWSxXQUFXaVk7SUFDNUMvWixRQUFRRyxlQUNOLGVBQ0FpQixVQUFVRCxRQUFTbVosZUFBZSxZQUFZN1EsU0FBU2pDLFFBQ3ZEcVQsU0FBUy9ZLFdBQ1RpWTtJQUVGelksT0FBTytRLGVBQWV3SSxTQUFTL1ksV0FBV2lZLFVBQVU7UUFDbEQ3WixPQUFPc0Q7UUFDUDhPLFVBQVU7UUFDVnVILFlBQVk7UUFDWkMsY0FBYzs7QUFFbEI7O0FBRUEsU0FBU2Esa0JBQ1BFLFVBQ0FkLFVBQ0FHLGNBQ0FPLGFBQ0FyWixTQUNBa1k7SUFFQSxNQUFNd0IsY0FDSjlhLFFBQVFDLFlBQVloQyxXQUFXYyxrQkFBa0I4YixhQUFhO0lBQ2hFLEtBQUtDLFlBQVl0YSxTQUFTaWEsY0FBYztRQUN0Q3phLFFBQVFHLGVBQ05sQyxXQUFXYyxrQkFDWCxLQUFJK2IsYUFBYUwsZUFDakJJO0FBRUo7SUFFQSxNQUFNRSxTQUFTLHdCQUF3Qk4sWUFBWW5UO0lBQ25ELE1BQU1nVCxhQUFhQyxpQkFBaUJMO0lBQ3BDLE1BQU1jLGFBQWEsRUFBQztRQUFFQyxNQUFNRjtPQUFVO1FBQUVoYSxNQUFNdVo7O0lBRTlDLE1BQU1YLGFBQWdEdlksVUFDakQ7UUFBRUwsTUFBTTtRQUFTcUMsVUFBVWtXO1FBQVk0QixPQUFPRjtRQUM5QztRQUFFamEsTUFBTU87UUFBUThCLFVBQVVrVztRQUFZNEIsT0FBT0Y7O0lBRWxEdlgsWUFBWWtXLFdBQVpsVyxDQUF3Qm9YLFNBQVMvWSxXQUFXaVk7SUFDNUMvWixRQUFRRyxlQUNOLGVBQ0FpQixVQUFVRCxRQUFRRyxRQUNsQnVaLFNBQVMvWSxXQUNUaVk7SUFFRnpZLE9BQU8rUSxlQUFld0ksU0FBUy9ZLFdBQVdpWSxVQUFVO1FBQ2xEN1osT0FBT3NEO1FBQ1A4TyxVQUFVO1FBQ1Z1SCxZQUFZO1FBQ1pDLGNBQWM7O0FBRWxCOztBQUVBLFNBQVNTLGlCQUFpQkw7SUFDeEI7UUFDRSxNQUFNNUIsa0JBQWtCRixNQUFNRyxRQUFRMkI7UUFDdEMsTUFBTWlCLFNBQVM3QyxpQkFBaUJ2WDtRQUNoQyxJQUFJb2EsV0FBVzFSLFVBQVUwUixXQUFXekMsUUFBUSxPQUFPO1FBQ25ELE9BQU87QUFDVCxNQUFFO1FBQ0EsT0FBTztBQUNUO0FBQ0Y7O0FBRUEsU0FBU0kscUNBQ1BqSyxPQUNBcUs7SUFFQSxJQUFJa0MsVUFBZXZNO0lBQ25CLE9BQU91TSxXQUFXQSxZQUFZOVosVUFBVThaLFlBQVlDLFVBQVU7UUFDNUQsSUFBSWpELE1BQU1RLFVBQVV3QyxTQUFTbEMsT0FBYyxPQUFPO1FBQ2xEa0MsVUFBVTlaLE9BQU9nYSxlQUFlRjtBQUNsQztJQUNBLE9BQU87QUFDVDs7QUFFQSxTQUFTL0IsK0JBQ1B4SyxPQUNBcUs7SUFFQSxJQUFJa0MsVUFBZXZNO0lBQ25CLE9BQU91TSxXQUFXQSxZQUFZOVosVUFBVThaLFlBQVlDLFVBQVU7UUFDNUQsTUFBTWpDLGFBQWE1TyxTQUFTMlAsY0FBY2lCLFNBQVNsQztRQUNuRCxJQUFJRSxZQUFZLE9BQU9BO1FBQ3ZCZ0MsVUFBVTlaLE9BQU9nYSxlQUFlRjtBQUNsQztJQUNBLE9BQU81WDtBQUNUOztBQUVBLFNBQVNrVyx5QkFBeUI3SyxPQUF5QnFLO0lBQ3pELElBQUlrQyxVQUFldk07SUFDbkIsT0FBT3VNLFdBQVdBLFlBQVk5WixVQUFVOFosWUFBWUMsVUFBVTtRQUM1RCxNQUFNdGEsT0FBT3lKLFNBQVN6SixLQUFLcWEsU0FBU2xDO1FBQ3BDLElBQUluWSxNQUFNLE9BQU9BO1FBQ2pCcWEsVUFBVTlaLE9BQU9nYSxlQUFlRjtBQUNsQztJQUNBLE9BQU81WDtBQUNUOztBQUVBLFNBQVNzVSxZQUNQTDtJQUVBLEtBQUtILFNBQVM2QixJQUFJMUIsS0FBSztRQUNyQkgsU0FBUzdNLElBQUlnTixJQUFJLElBQUk4RDtBQUN2QjtJQUNBLE9BQU9qRSxTQUFTdkwsSUFBSTBMO0FBQ3RCOzs7O01DeFJhK0Q7O1FBQ2FqUSxLQUFBd0IsTUFBTUMsUUFBUUMsSUFBSXVPLG9CQUFvQmxVO0FBQU07SUFFcEUscUJBQU9tVSxDQUNMQztRQUVBO1lBQ0UsT0FBTzFFLFVBQVFqTCxJQUFxQjJQO0FBQ3RDLFVBQUUsT0FBTzFQO1lBQ1A7Z0JBQ0UsT0FBT3dGLGFBQWF5RixXQUFXeUU7QUFDakMsY0FBRSxPQUFPQztnQkFDUCxPQUFPekUsYUFBV0MsU0FBU3VFO0FBQzdCO0FBQ0Y7QUFDRjtJQUVBLHNDQUFPRSxDQUNMdEssYUFDQXVLLFNBQWlCQyxnQkFBZ0JDO1FBRWpDLE1BQU1DLE9BQ0oxSyx1QkFBdUJFLGVBQWVGLFlBQVkwSyxPQUFPMUs7UUFDM0QsTUFBTW5KLGNBQTJCNlQsS0FBSzVUO1FBQ3RDLE1BQU02VCxlQUNKelIsU0FBU3VCLElBQ1BpUSxLQUFLaGIsYUFDTHdKLFNBQVMzSyxJQUFJaWMsZ0JBQWdCQyxXQUMxQixDQUFBO1FBRVAsTUFBTUcsZUFDSjFSLFNBQVN1QixJQUNQdUYsWUFBWXRRLGFBQ1p3SixTQUFTM0ssSUFBSW1LLGlCQUNWLENBQUE7UUFFUCxNQUFNbVMsd0JBQXdCckY7WUFDNUIsU0FBYTtnQkFDWCxNQUFNLElBQUlwSCxNQUFNO0FBQ2xCO1lBQ0EsV0FBQTFPLENBQVk0VixlQUFvQ3RQO2dCQUM5QzhELE1BQU13TCxlQUFldFA7QUFDdkI7O1FBR0YsS0FBSyxPQUFPMkksWUFBWXRILFdBQVdySCxPQUFPOGEsUUFBUUYsZUFBZTtZQUMvRCxNQUFNdE0sWUFBWSxFQUFDakgsT0FBTzFFLEtBQUs4QixRQUFRLGNBQWMsTUFDbERuRCxPQUFReVMsV0FBb0JBLFdBQVdBLFFBQVFDLFFBQy9DK0csS0FBSztZQUVSLE1BQU1qSyxVQUFVb0osb0JBQW9CYywwQkFDbENyTTtZQUVGdUwsb0JBQW9CZSxhQUNsQkosaUJBQ0FsTSxZQUNBbUM7WUFHRixNQUFNb0ssZ0JBQWdCaE4sb0JBQW9CN0csT0FBTzhULFdBQTNCak4sQ0FBb0RJLGFBQWFwTTtZQUN2RixNQUFNMkQsYUFBYXFVLG9CQUFvQmtCLG1CQUNyQ3pNLFlBQ0FMLFdBQ0FqSCxPQUFPOFQ7WUFFVGpCLG9CQUFvQi9ULGdCQUNsQjBVLGlCQUNBbE0sWUFDQSxFQUFDdU0sa0JBQWtCclY7QUFFdkI7UUFFQSxLQUFLLE9BQU84SSxZQUFZME0sY0FBY3JiLE9BQU84YSxRQUFRSCxlQUFlO1lBQ2xFLE1BQU1XLFNBQVNELFVBQVVDLFVBQVU7WUFDbkMsTUFBTWhOLFlBQVksRUFBQ2lNLFFBQVE1TCxlQUFlMk0sT0FBTy9aLElBQUtnYSxLQUFNLElBQUlBLE9BQzdEamEsT0FBUXlTLFdBQVlBLFdBQVdBLFFBQVFDLFFBQ3ZDK0csS0FBSztZQUVSLE1BQU1qSyxVQUFVb0osb0JBQW9CYywwQkFDbENyTTtZQUVGdUwsb0JBQW9CZSxhQUNsQkosaUJBQ0FsTSxZQUNBbUM7WUFHRixNQUFNb0ssZ0JBQWdCaE4sb0JBQW9CLE1BQXBCQSxDQUF3Q0ksYUFBYXBNO1lBQzNFLE1BQU0yRCxhQUFhcVUsb0JBQW9Ca0IsbUJBQ3JDek0sWUFDQUwsV0FDQSxPQUNBO1lBRUY0TCxvQkFBb0IvVCxnQkFDbEIwVSxpQkFDQWxNLFlBQ0EsRUFBQ3VNLGtCQUFrQnJWO0FBRXZCO1FBRUEsT0FBT2dWO0FBQ1Q7SUFFTyxhQUFBVyxDQUNMM1UsYUFDQTRVLHVCQUNBQztRQUVBLE1BQU1qUSxNQUFNeU8sb0JBQW9Cek8sSUFBSUUsSUFBSXVPLG9CQUFvQnNCO1FBQzVELE1BQU1HLFlBQVk3RSxNQUFNNkUsVUFBVTlVO1FBQ2xDLE1BQU15SCxZQUFZc04sWUFBWUQ7UUFDOUIsTUFBTUUsaUJBQWlCaFYsWUFBWWI7UUFDbkMsTUFBTWdLLGNBQWNrSyxvQkFBb0JDLGVBQWV0VDtRQUt2RCxNQUFNaVYscUJBQ0o5TCx1QkFBdUJFLGVBQWVGLFlBQVkwSyxPQUFPMUs7UUFFM0QsTUFBTStMLGtCQUFrQjdTLFNBQVN1QixJQUMvQjVELGFBQ0FxQyxTQUFTM0ssSUFBSXVLO1FBRWYsTUFBTWtULGlCQUFpQlAsd0JBQXdCNVUsWUFBWWI7UUFDM0QsTUFBTWlXLGVBQTZDO2VBQzdDUCxrQkFBa0IsQ0FBQTtlQUNsQkssbUJBQW1CLENBQUE7ZUFDbkJDLGtCQUFrQixDQUFBOztRQUd4QixNQUFNRSxvQkFBb0JDLHVCQUF1QlgsT0FDL0MzVSxhQUNBaVYsb0JBQ0FHO1FBRUYsTUFBTUcsZ0JBQWlCRixrQkFBMEJHO1FBSWpELE9BQU1DLE9BQUVBLE9BQUtDLGVBQUVBLGVBQWU1WixNQUFNNlosVUFDbEN0QyxvQkFBb0J1Qyw0QkFBNEI1VjtRQUVsRDRFLElBQUlXLE1BQ0Ysa0NBQWtDeVAsdUJBQXVCTyxlQUFldmEsVUFBVTtRQUdwRixNQUFNNmEsYUFBcUNULGFBQWFVO1FBRXhELFNBQVNDLGVBQWV0ZTtZQUN0QixJQUFJb2UsWUFBWUcsUUFBUTtnQkFDdEIvTyxTQUFTeFA7QUFDWCxtQkFBTyxJQUFJb2UsWUFBWTFPLE9BQU9uTSxRQUFRO2dCQUNwQ2tNLGdCQUFnQjJPLFdBQVcxTyxNQUEzQkQsQ0FBa0N6UDtBQUNwQyxtQkFBTztnQkFDTGdQLEtBQUt6RyxZQUFMeUcsQ0FBa0JoUDtBQUNwQjtZQUNBLElBQUlvZSxZQUFZelEsZ0JBQWdCO2dCQUM5QjRCLFlBQVlsRSxzQkFBc0IsS0FBbENrRSxDQUF3Q3ZQO0FBQzFDO0FBQ0Y7UUFFQSxJQUdNd2UseUJBQXNCQywyQkFINUIsTUFHTUQsK0JBQStCdEg7WUFHekIsZ0JBQVc7Z0JBQ25CLE9BQU8zTztBQUNUO1lBRUEsU0FBYTtnQkFDWCxPQUFPQTtBQUNUO1lBRUEsV0FBQW5ILENBQVk0VjtnQkFDVnhMLE1BQU13TCxlQUFleUgseUJBQXVCL1c7Z0JBWDdCaUUsS0FBQThNLEtBQWFELE1BQU1DLEdBQUdsUTtnQkFZckM0RSxJQUFJdVIsS0FDRiw2Q0FBNkMvUyxLQUFLbkQsTUFBTWQsZ0JBQWdCc0k7QUFFNUU7O1FBaEJJd08seUJBQXNCQywyQkFBQW5TLFdBQUEsRUFIM0JxUyxXQUFXM08sWUFDWDRPLFFBQVFyQixpQkFDUnNCLGVBQWV0VyxnREFZYStDLDBCQVh2QmtUO1FBbUJORixlQUFlRTtRQUVmLElBQUlWLGVBQWU7WUFDakIsTUFBTWdCLGVBQWUsS0FBSWhCLGdCQUFlaUIsS0FBSyxDQUFDQyxHQUFHQztnQkFDL0MsTUFBTUMsWUFBWUYsRUFBRTNhLEtBQUs0TCxNQUFNLEtBQUtqTixPQUFPMlM7Z0JBQzNDLE1BQU13SixZQUFZRixFQUFFNWEsS0FBSzRMLE1BQU0sS0FBS2pOLE9BQU8yUztnQkFDM0MsTUFBTXlKLGNBQWNGLFVBQVVsYyxPQUFRcWMsS0FBTUEsRUFBRWxZLFdBQVcsTUFBTTVEO2dCQUMvRCxNQUFNK2IsY0FBY0gsVUFBVW5jLE9BQVFxYyxLQUFNQSxFQUFFbFksV0FBVyxNQUFNNUQ7Z0JBQy9ELE1BQU1nYyxnQkFBZ0JMLFVBQVUzYixTQUFTNmI7Z0JBQ3pDLE1BQU1JLGdCQUFnQkwsVUFBVTViLFNBQVMrYjtnQkFDekMsSUFBSUMsa0JBQWtCQyxlQUNwQixPQUFPQSxnQkFBZ0JEO2dCQUN6QixJQUFJSCxnQkFBZ0JFLGFBQ2xCLE9BQU9GLGNBQWNFO2dCQUN2QixPQUFPOztZQUVULEtBQUssTUFBTUcsU0FBU1gsY0FBYztnQkFDaEMsTUFBTVksZUFBZTlELG9CQUFvQitELFdBQ3ZDRixPQUNBdkIsUUFDQUQsZUFDQUQsT0FDQXpWLGFBQ0FnVixnQkFDQUM7Z0JBRUYsS0FBS2tDLGNBQWM7Z0JBRW5CLE9BQU1yUCxZQUFFQSxZQUFVbUMsU0FBRUEsU0FBT2pMLFlBQUVBLFlBQVVxWSxpQkFBRUEsbUJBQ3ZDRjtnQkFFRixNQUFNeGYsYUFBYTBiLG9CQUFvQmUsYUFDckM2Qix3QkFDQW5PLFlBQ0FtQztnQkFHRixJQUFJdFMsWUFBWTtvQkFDZCxNQUFNMGMsZ0JBQWdCaE4sb0JBQW9CNlAsTUFBTTVPLE9BQTFCakIsQ0FDcEI2UCxNQUFNcGIsS0FBSzhCLFFBQVEsY0FBYyxPQUFPdkM7b0JBRTFDZ1ksb0JBQW9CL1QsZ0JBQ2xCMlcsd0JBQ0FuTyxZQUNBLEVBQUN1TSxrQkFBa0JyVixjQUNuQnFZO0FBRUo7QUFDRjtBQUNGO1FBRUEsT0FBT3BCO0FBQ1Q7SUFFQSxrQ0FBT0wsQ0FDTHJDO1FBT0EsTUFBTXJELEtBQUtELE1BQU1DLEdBQUdxRDtRQUNwQixNQUFNK0QsV0FBV2pWLFNBQVN1QixJQUN4QjJQLFlBQ0FsUixTQUFTM0ssSUFBSTZmLE9BQU9DLFVBQVV0SDtRQUVoQyxNQUFNdUgsZUFBZUgsVUFBVWxPLFFBQVE7UUFFdkMsTUFBTXNPLGFBQ0oxZSxNQUFNQyxRQUFRd2UsaUJBQWlCQSxhQUFhemMsU0FBUyxJQUNqRGhDLE1BQU1zTixLQUFLLElBQUlrSixJQUFJLEtBQUlpSSxtQkFDdkJ6ZSxNQUFNc04sS0FBSyxJQUFJa0osSUFBSSxFQUFDVTtRQUUxQixNQUFNOVEsY0FBY2lELFNBQVNqRCxZQUFZbVUsZUFBZTtRQUN4RCxNQUFNelgsT0FBTyxJQUFJNGIsV0FBV3hELEtBQUs7UUFDakMsTUFBTXdCLGdCQUFvQ2dDLFdBQVdoZCxJQUFLaEQsUUFDakQ7WUFDTHlILE1BQU16SDtZQUNOMEgsYUFBYWlELFNBQVNqRCxZQUFZbVUsWUFBWTdiO1lBQzlDdUQsVUFBVTtZQUNWckMsTUFBTXlHOztRQUlWLE9BQU87WUFDTHZEO1lBQ0FzRDtZQUNBc1c7WUFDQUQsT0FBTyxJQUFJalYsV0FDVDhXLFVBQVVLLFlBQVluWCxPQUFPMFQsS0FBS29ELFNBQVNLLGFBQWFuWCxPQUFPMFQsS0FBSzs7QUFFMUU7SUFFUSxtQkFBT0UsQ0FDYjNjLFFBQ0FxUSxZQUNBbUM7UUFFQTlRLE9BQU8rUSxlQUNMelMsT0FBT2tDLGFBQWFsQyxRQUNwQnFRLFlBQ0E7WUFDRS9QLE9BQU9rUztZQUNQRSxVQUFVO1lBQ1Z3SCxjQUFjO1lBQ2RELFlBQVk7O1FBSWhCLE9BQU92WSxPQUFPVSx5QkFDWnBDLE9BQU9rQyxhQUFhbEMsUUFDcEJxUTtBQUVKO0lBRVEsc0JBQU94SSxDQUNiN0gsUUFDQXFRLFlBQ0E4UCxrQkFDQVAsa0JBQTJFO1FBRTNFLE1BQU12TyxRQUFRclIsUUFBUWtDLGFBQWFsQztRQUNuQyxNQUFNRSxhQUFhd0IsT0FBT1UseUJBQXlCaVAsT0FBT2hCO1FBQzFEOFAsaUJBQWlCN08sUUFBU0MsS0FBTUEsRUFBRUYsT0FBT2hCLFlBQVluUTtRQUNyRDBmLGdCQUFnQnRPLFFBQVEsRUFBR3pCLHNCQUFXMkIsa0JBQ3BDM0IsVUFBVXdCLE9BQU9oQixZQUFZbUI7QUFFakM7SUFFUSxpQkFBT21PLENBQ2JGLE9BQ0F2QixRQUNBRCxlQUNBRCxPQUNBelYsYUFDQWdWLGdCQUNBN0w7UUFPQSxPQUFNYixRQUFFQSxRQUFNeE0sTUFBRUEsUUFBU29iO1FBQ3pCLE1BQU1XLGlCQUFpQi9iLEtBQUs4QixRQUFRLGNBQWM7UUFFbEQsSUFBSTBLLFdBQVcsVUFBVXVQLG1CQUFtQixJQUFJO1lBQzlDLE9BQU94RSxvQkFBb0J5RSxtQkFDekIsVUFDQXpFLG9CQUFvQjBFLG9CQUFvQi9YLGFBQWFnVixpQkFDckQzQixvQkFBb0IyRSx1QkFBdUJoWSxhQUFhZ1YsaUJBQ3hELEVBQUM7Z0JBQUUxTixXQUFXL0g7Z0JBQW9CMEosT0FBTztlQUFLO2dCQUFFM0IsV0FBVzJRLFNBQVM7b0JBQUVDLGFBQWE7O2dCQUFnQmpQLE9BQU87O0FBRTlHO1FBRUEsSUFBSVgsV0FBVyxVQUFVdVAsbUJBQW1CLFFBQVE7WUFDbEQsT0FBT3hFLG9CQUFvQnlFLG1CQUN6QixhQUNBekUsb0JBQW9COEUsd0JBQXdCblksYUFBYWdWLGlCQUN6RDNCLG9CQUFvQitFLHFCQUFxQnBZLGFBQWFnVixpQkFDdEQsRUFBQztnQkFBRTFOLFdBQVcvSDtnQkFBb0IwSixPQUFPO2VBQUs7Z0JBQUUzQixXQUFXMlEsU0FBUztvQkFBRUMsYUFBYTs7Z0JBQWdCalAsT0FBTzs7QUFFOUc7UUFFQSxJQUFJWCxXQUFXLFNBQVN1UCxtQkFBbUIsUUFBUTtZQUNqRCxPQUFPeEUsb0JBQW9CeUUsbUJBQ3pCLFdBQ0F6RSxvQkFBb0JnRixzQkFBc0JyRCxpQkFDMUMzQixvQkFBb0JpRixtQkFBbUJ0WSxhQUFhZ1YsaUJBQ3BELEVBQUM7Z0JBQUUxTixXQUFXc0IsTUFBTTtnQkFBZUssT0FBTzs7QUFFOUM7UUFFQSxJQUFJWCxXQUFXLFNBQVN1UCxtQkFBbUIsUUFBUTtZQUNqRCxPQUFPeEUsb0JBQW9CeUUsbUJBQ3pCLGFBQ0F6RSxvQkFBb0JrRix3QkFBd0J2RCxpQkFDNUMzQixvQkFBb0JtRixxQkFBcUJ4WSxhQUFhZ1YsZ0JBQWdCVSxnQkFDdEUsRUFBQztnQkFBRXBPLFdBQVcvSDtnQkFBb0IwSixPQUFPO2VBQUs7Z0JBQUUzQixXQUFXMlEsU0FBUztvQkFBRUMsYUFBYTs7Z0JBQWdCalAsT0FBTzs7QUFFOUc7UUFFQSxJQUFJWCxXQUFXLFlBQVl1UCxtQkFBbUIsUUFBUTtZQUNwRCxPQUFPeEUsb0JBQW9CeUUsbUJBQ3pCLGFBQ0F6RSxvQkFBb0JvRix3QkFBd0J6RCxpQkFDNUMzQixvQkFBb0JxRixxQkFBcUIxWSxhQUFhZ1YsZ0JBQWdCVSxnQkFDdEUsRUFBQztnQkFBRXBPLFdBQVdzQixNQUFNO2dCQUFlSyxPQUFPO2VBQUs7Z0JBQUUzQixXQUFXMlEsU0FBUztvQkFBRUMsYUFBYTs7Z0JBQWdCalAsT0FBTzs7QUFFL0c7UUFFQSxJQUFJWCxXQUFXLFNBQVN1UCxtQkFBbUJsQyxRQUFRO1lBQ2pELE9BQU90QyxvQkFBb0J5RSxtQkFDekIsUUFDQXpFLG9CQUFvQnNGLGtCQUFrQmxELE9BQU9ULGlCQUM3QzNCLG9CQUFvQnVGLGVBQWU1WSxhQUFhZ1YsZ0JBQWdCVSxlQUFlQyxTQUMvRSxFQUFDO2dCQUFFck8sV0FBV3ZHLFlBQVkyVTtnQkFBdUJ6TSxPQUFPOztBQUU1RDtRQUVBLElBQUlYLFdBQVcsU0FBU3VQLG1CQUFtQmxDLFFBQVE7WUFDakQsT0FBT3RDLG9CQUFvQnlFLG1CQUN6QixVQUNBekUsb0JBQW9Cd0Ysb0JBQW9CcEQsT0FBT3pWLGFBQWFnVixpQkFDNUQzQixvQkFBb0J5RixpQkFBaUI5WSxhQUFhZ1YsZ0JBQWdCVSxlQUFlQyxTQUNqRixFQUNFO2dCQUFFck8sV0FBV3ZHLFlBQVkyVTtnQkFBdUJ6TSxPQUFPO2VBQ3ZEO2dCQUFFM0IsV0FBVy9IO2dCQUFvQjBKLE9BQU87ZUFDeEM7Z0JBQUUzQixXQUFXMlEsU0FBUztvQkFBRUMsYUFBYTs7Z0JBQWdCalAsT0FBTzs7QUFHbEU7UUFFQSxJQUFJWCxXQUFXLFlBQVl1UCxtQkFBbUJsQyxRQUFRO1lBQ3BELE9BQU90QyxvQkFBb0J5RSxtQkFDekIsVUFDQXpFLG9CQUFvQjBGLG9CQUFvQnRELE9BQU9ULGlCQUMvQzNCLG9CQUFvQjJGLGlCQUFpQmhaLGFBQWFnVixnQkFBZ0JVLGVBQWVDLFNBQ2pGLEVBQ0U7Z0JBQUVyTyxXQUFXdkcsWUFBWTJVO2dCQUF1QnpNLE9BQU87ZUFDdkQ7Z0JBQUUzQixXQUFXMlEsU0FBUztvQkFBRUMsYUFBYTs7Z0JBQWdCalAsT0FBTzs7QUFHbEU7UUFHQSxNQUFNZ1EsbUJBQW1CcEIsZUFBZW5RLE1BQU0sS0FBS2pOLE9BQU8yUztRQUMxRCxNQUFNOEwsY0FBY0QsaUJBQWlCamUsU0FBUyxLQUFLaWUsaUJBQWlCRSxNQUFPckMsS0FBTUEsRUFBRWxZLFdBQVc7UUFDOUYsSUFBSXNhLGVBQWVyQixtQkFBbUJsQyxRQUFRO1lBQzVDLE1BQU15RCxtQkFBbUJILGlCQUFpQnZlLElBQUtvYyxLQUFNQSxFQUFFblAsTUFBTSxJQUFJak4sSUFBS3lFLFNBQUk7Z0JBQ3hFQTtnQkFDQUMsYUFBYSxHQUFHRDtnQkFDaEJsRSxVQUFVO2dCQUNWckMsTUFBTXlHOztZQUVSLE1BQU1nYSxTQUFTSixpQkFBaUJ2ZSxJQUFLb2MsS0FBTUEsRUFBRW5QLE1BQU0sSUFBSXVNLEtBQUs7WUFDNUQsSUFBSTVMLFdBQVcsT0FBTztnQkFDcEIsT0FBTytLLG9CQUFvQnlFLG1CQUN6QixTQUFTdUIsVUFDVGhHLG9CQUFvQnNGLGtCQUFrQmxELE9BQU9ULGlCQUM3QzNCLG9CQUFvQnVGLGVBQWU1WSxhQUFhZ1YsZ0JBQWdCb0Usa0JBQWtCdkIsaUJBQ2xGLEVBQUM7b0JBQUV2USxXQUFXdkcsWUFBWXFZO29CQUEwQm5RLE9BQU87O0FBRS9EO1lBQ0EsSUFBSVgsV0FBVyxPQUFPO2dCQUNwQixPQUFPK0ssb0JBQW9CeUUsbUJBQ3pCLFdBQVd1QixVQUNYaEcsb0JBQW9Cd0Ysb0JBQW9CcEQsT0FBT3pWLGFBQWFnVixpQkFDNUQzQixvQkFBb0J5RixpQkFBaUI5WSxhQUFhZ1YsZ0JBQWdCb0Usa0JBQWtCdkIsaUJBQ3BGLEVBQ0U7b0JBQUV2USxXQUFXdkcsWUFBWXFZO29CQUEwQm5RLE9BQU87bUJBQzFEO29CQUFFM0IsV0FBVy9IO29CQUFvQjBKLE9BQU87bUJBQ3hDO29CQUFFM0IsV0FBVzJRLFNBQVM7d0JBQUVDLGFBQWE7O29CQUFnQmpQLE9BQU87O0FBR2xFO1lBQ0EsSUFBSVgsV0FBVyxVQUFVO2dCQUN2QixPQUFPK0ssb0JBQW9CeUUsbUJBQ3pCLFdBQVd1QixVQUNYaEcsb0JBQW9CMEYsb0JBQW9CdEQsT0FBT1QsaUJBQy9DM0Isb0JBQW9CMkYsaUJBQWlCaFosYUFBYWdWLGdCQUFnQm9FLGtCQUFrQnZCLGlCQUNwRixFQUNFO29CQUFFdlEsV0FBV3ZHLFlBQVlxWTtvQkFBMEJuUSxPQUFPO21CQUMxRDtvQkFBRTNCLFdBQVcyUSxTQUFTO3dCQUFFQyxhQUFhOztvQkFBZ0JqUCxPQUFPOztBQUdsRTtBQUNGO1FBRUEsSUFBSVgsV0FBVyxTQUFTdVAsbUJBQW1CLDJCQUEyQjtZQUNwRSxPQUFPeEUsb0JBQW9CeUUsbUJBQ3pCLGFBQ0F6RSxvQkFBb0JpRyx1QkFBdUJ0RSxpQkFDM0MzQixvQkFBb0JrRyxvQkFBb0J2WixhQUFhZ1YsaUJBQ3JELEVBQ0U7Z0JBQUUxTixXQUFXa1MsTUFBTTtnQkFBa0J2USxPQUFPO2VBQzVDO2dCQUFFM0IsV0FBV2tTLE1BQU07Z0JBQWdCdlEsT0FBTztlQUMxQztnQkFBRTNCLFdBQVd0RztnQkFBcUJpSSxPQUFPOztBQUcvQztRQUVBLE1BQU13USxrQkFBMEM7WUFDOUMsZUFBZTNiLHNCQUFzQkM7WUFDckMseUJBQXlCRCxzQkFBc0JFO1lBQy9DLGVBQWVGLHNCQUFzQkc7WUFDckMsZUFBZUgsc0JBQXNCSTtZQUNyQyx5QkFBeUJKLHNCQUFzQks7WUFDL0Msc0JBQXNCTCxzQkFBc0JNO1lBQzVDLGtCQUFrQk4sc0JBQXNCTztZQUN4QyxnQkFBZ0JQLHNCQUFzQlE7WUFDdEMsZ0JBQWdCUixzQkFBc0JTO1lBQ3RDLGdCQUFnQlQsc0JBQXNCVTtZQUN0QyxnQkFBZ0JWLHNCQUFzQlc7WUFDdEMscUJBQXFCWCxzQkFBc0JZO1lBQzNDLGtCQUFrQlosc0JBQXNCYTs7UUFHMUMsTUFBTSthLGVBQWVELGdCQUFnQjVCO1FBQ3JDLElBQUk2QixnQkFBZ0JwUixXQUFXLE9BQU87WUFDcEMsT0FBTytLLG9CQUFvQnlFLG1CQUN6QnpFLG9CQUFvQnNHLG9CQUFvQjlCLGlCQUN4Q3hFLG9CQUFvQnVHLCtCQUErQkYsY0FBYzFFLGlCQUNqRTNCLG9CQUFvQndHLDRCQUE0QjdaLGFBQWFnVixnQkFBZ0I2QyxnQkFBZ0I2QixlQUM3RnJHLG9CQUFvQnlHLHdCQUF3QmpDO0FBRWhEO1FBRUEsSUFBSXZQLFdBQVcsU0FBU3VQLGVBQWVqWixXQUFXLFdBQVc7WUFDM0QsTUFBTW1iLGNBQWNsQyxlQUFlamEsUUFBUSxZQUFZLElBQUk4SixNQUFNLEtBQUs7WUFDdEUsT0FBTzJMLG9CQUFvQnlFLG1CQUN6QmlDLGFBQ0ExRyxvQkFBb0JjLDBCQUEwQjRGLGNBQzlDMUcsb0JBQW9Ca0IsbUJBQW1Cd0YsYUFBYWxDLGdCQUFnQixPQUFPLE9BQzNFeEUsb0JBQW9CMkcsbUJBQW1CbkM7QUFFM0M7UUFHQSxNQUFNb0MsZUFBZXBDLGVBQWVuUSxNQUFNLEtBQUtqTixPQUFPMlM7UUFDdEQsTUFBTThNLGdCQUFnQixJQUFJMUssSUFBWSxFQUNwQyxVQUFVLFVBQVUsa0JBQWtCLGFBQWEsY0FDbkQsUUFBUSxRQUFRLFdBQVcsU0FBUyxTQUFTLFNBQVMsU0FDdEQsY0FBYyxXQUFXLGFBQWEsUUFBUTtRQUVoRCxJQUNFeUssYUFBYWpmLFNBQVMsTUFDckI2YyxlQUFlalosV0FBVyxjQUMxQnNiLGNBQWNsSixJQUFJaUosYUFBYSxLQUNoQztZQUlBLE1BQU1FLGdCQUNKOVgsU0FBU3VCLElBQ051RixhQUFxQnRRLGFBQ3RCd0osU0FBUzNLLElBQUltSyxpQkFDVixDQUFBO1lBQ1AsTUFBTXVZLGVBQWVqaEIsT0FBTzhhLFFBQVFrRyxlQUFlRSxLQUNqRCxJQUFJbEUsVUFDRkEsZUFDT0EsU0FBUyxZQUNoQkEsS0FBS3JhLE1BQU04QixRQUFRLGNBQWMsUUFBUWlhO1lBRTdDLE1BQU15QyxtQkFBbUJGLGVBQWUsTUFBTUgsYUFBYTtZQUUzRCxNQUFNTSxnQkFBZ0JOLGFBQWF4ZixPQUFRcWMsS0FBTUEsRUFBRWxZLFdBQVc7WUFDOUQsTUFBTXNKLGdCQUFnQnFTLGNBQWM3ZixJQUFLb2MsS0FBTUEsRUFBRW5QLE1BQU0sSUFBSWpOLElBQUt5RSxTQUFJO2dCQUNsRUE7Z0JBQ0FDLGFBQWEsR0FBR0Q7Z0JBQ2hCbEUsVUFBVTtnQkFDVnJDLE1BQU15Rzs7WUFHUixPQUFPZ1Usb0JBQW9CeUUsbUJBQ3pCd0Msa0JBQ0FqSCxvQkFBb0JtSCx5QkFBeUJGLG1CQUM3QyxLQUNLcFMsY0FBY3hOLElBQUt1RSxLQUFNc0osU0FBU3RKLEtBQ3JDdUosYUFBYTtnQkFBRUMsU0FBUywyQkFBMkI2UjtnQkFDbkQ1UixjQUFjO2dCQUFFdEosYUFBYTtnQkFDN0J1SixxQkFBcUI7Z0JBQUV2SixhQUFhO2tCQUV0Q2lVLG9CQUFvQjJHLG1CQUFtQm5DO0FBRTNDO1FBRUEsT0FBT3hjO0FBQ1Q7SUFFUSx5QkFBT3ljLENBQ2JoUSxZQUNBbUMsU0FDQWpMLFlBQ0FxWTtRQUVBLE9BQU87WUFBRXZQO1lBQVltQztZQUFTakw7WUFBWXFZOztBQUM1QztJQUVRLDBCQUFPc0MsQ0FBb0I3ZDtRQUNqQyxNQUFNMmUsZUFBZTNlLEtBQUs0TCxNQUFNLEtBQUs7UUFDckMsT0FBTytTO0FBQ1Q7SUFFUSw4QkFBT1gsQ0FDYmhlO1FBRUEsTUFBTTRlLFdBQVc1ZSxLQUFLNEwsTUFBTSxLQUFLak4sT0FBUXFjLEtBQU1BLEVBQUVsWSxXQUFXO1FBQzVELE1BQU00QixTQUFrRTtRQUN4RWthLFNBQVMzUixRQUFRLENBQUM0UixLQUFLQztZQUNyQixNQUFNemIsT0FBT3diLElBQUkvYyxRQUFRLEtBQUs7WUFDOUI0QyxPQUFPdUcsS0FBSztnQkFBRU8sV0FBV2tTLE1BQU1yYTtnQkFBYzhKLE9BQU8yUjs7O1FBRXRELElBQ0U5ZSxLQUFLOEMsV0FBVyxjQUNoQjlDLEtBQUs4QyxXQUFXLGtCQUNoQjlDLEtBQUs4QyxXQUFXLFlBQ2hCOUMsS0FBSzhDLFdBQVcsVUFDaEI7WUFDQTRCLE9BQU91RyxLQUFLO2dCQUFFTyxXQUFXdEc7Z0JBQXFCaUksT0FBT3lSLFNBQVMxZjs7QUFDaEU7UUFDQSxPQUFPd0Y7QUFDVDtJQUVRLHlCQUFPd1osQ0FDYmxlO1FBRUEsTUFBTTRlLFdBQVc1ZSxLQUFLNEwsTUFBTSxLQUFLak4sT0FBUXFjLEtBQU1BLEVBQUVsWSxXQUFXO1FBQzVELE1BQU00QixTQUFrRTtRQUN4RWthLFNBQVMzUixRQUFRLENBQUM0UixLQUFLQztZQUNyQixNQUFNemIsT0FBT3diLElBQUkvYyxRQUFRLEtBQUs7WUFDOUI0QyxPQUFPdUcsS0FBSztnQkFBRU8sV0FBV2tTLE1BQU1yYTtnQkFBYzhKLE9BQU8yUjs7O1FBRXRELElBQUk5ZSxLQUFLOEMsV0FBVyxXQUFXO1lBQzdCNEIsT0FBT3VHLEtBQUs7Z0JBQUVPLFdBQVd0RztnQkFBcUJpSSxPQUFPeVIsU0FBUzFmOztBQUNoRTtRQUNBLE9BQU93RjtBQUNUO0lBRVEsMEJBQU91WCxDQUNiL1gsYUFDQWdWO1FBRUEsT0FBT3hMLGVBQWVtTCxPQUVwQm5WLE1BQ0FxYjtZQUVBLE9BQU1wYixLQUFFQSxLQUFHbUYsS0FBRUEsY0FDTHhCLEtBQUswWCxPQUFPLElBQUk3ZSxjQUFjSSxRQUFRLE9BQzVDeUksSUFBSTZQO1lBQ04vUCxJQUFJVSxRQUFRLGdCQUFnQjBQO1lBQzVCLElBQUkrRjtZQUNKO2dCQUNFQSxnQkFBZ0IzWCxLQUFLK0YsWUFBWTFKLEtBQUtrVixPQUFPblYsTUFBTUM7QUFDckQsY0FBRSxPQUFPb0U7Z0JBQ1BlLElBQUlrRixNQUFNLHdCQUF3QmtMLGtCQUFrQm5SO2dCQUNwRCxNQUFNQTtBQUNSO1lBQ0FlLElBQUl1UixLQUFLLGVBQWVuQiwwQkFBMkIrRixRQUFnQjNYLEtBQUs4TTtZQUN4RSxJQUFJMkssTUFBTXBiLElBQUkwTCxXQUFXMFA7WUFDekIsT0FBT0U7QUFDVDtBQUNGO0lBRVEsOEJBQU81QyxDQUNiblksYUFDQWdWO1FBRUEsT0FBT3hMLGVBQWV3UixVQUVwQnhiLE1BQ0FxYjtZQUVBLE9BQU1wYixLQUFFQSxLQUFHbUYsS0FBRUEsY0FDTHhCLEtBQUswWCxPQUFPLElBQUl4ZCxzQkFBc0JFLFlBQVksT0FDeERzSCxJQUFJa1c7WUFDTnBXLElBQUlVLFFBQVEsZ0JBQWdCMFA7WUFDNUIsSUFBSStGO1lBQ0o7Z0JBQ0VBLGdCQUFnQjNYLEtBQUsrRixZQUFZMUosS0FBS3ViLFVBQ3BDeGIsS0FBSzlFLElBQUtzTyxLQUFNLElBQUloSixZQUFZZ0osS0FDaEN2SjtBQUVKLGNBQUUsT0FBT29FO2dCQUNQZSxJQUFJa0YsTUFBTSx3QkFBd0JrTCxrQkFBa0JuUjtnQkFDcEQsTUFBTUE7QUFDUjtZQUNBZSxJQUFJdVIsS0FBSyxlQUFlbkIsMEJBQTJCK0YsUUFBZ0IzWCxLQUFLOE07WUFDeEUsSUFBSTJLLE1BQU1wYixJQUFJMEwsV0FBVzBQO1lBQ3pCLE9BQU9FO0FBQ1Q7QUFDRjtJQUVRLDRCQUFPMUMsQ0FBc0JyRDtRQUNuQyxPQUFPeEwsZUFBZXlSLFFBRXBCQztZQUVBLE9BQU16YixLQUFFQSxLQUFHbUYsS0FBRUEsY0FDTHhCLEtBQUswWCxPQUFPLElBQUl4ZCxzQkFBc0JDLFVBQVUsT0FDdER1SCxJQUFJbVc7WUFDTixNQUFNRSxnQkFBZ0JuaUIsTUFBTUMsUUFBUWlpQixPQUFPQSxNQUFNLEVBQUNBO1lBQ2xELElBQUlFO1lBQ0o7Z0JBQ0V4VyxJQUFJVyxNQUFNLFdBQVc0VixpQkFBaUJuRztnQkFDdENvRyxhQUFhaFksS0FBSytGLFlBQVkxSixLQUFLd2IsUUFBUUUsZUFBc0IxYjtBQUNuRSxjQUFFLE9BQU9vRTtnQkFDUGUsSUFBSWtGLE1BQU0sa0JBQWtCa0wsa0JBQWtCblI7Z0JBQzlDLE1BQU1BO0FBQ1I7WUFDQWUsSUFBSXVSLEtBQUssUUFBUWlGLEtBQUtwZ0IsVUFBVWdhO1lBQ2hDLE9BQU9vRztBQUNUO0FBQ0Y7SUFFUSw4QkFBTzdDLENBQXdCdkQ7UUFDckMsT0FBT3hMLGVBQWU2UixVQUVwQnhiLE1BQ0FnYjtZQUVBLE9BQU1wYixLQUFFQSxLQUFHbUYsS0FBRUEsY0FDTHhCLEtBQUswWCxPQUFPLElBQUl4ZCxzQkFBc0JHLFlBQVksT0FDeERxSCxJQUFJdVc7WUFDTixJQUFJQztZQUNKO2dCQUNFMVcsSUFBSXVSLEtBQUssWUFBWXRXLEtBQUs3RSxVQUFVZ2E7Z0JBQ3BDc0csZ0JBQWdCbFksS0FBSytGLFlBQVkxSixLQUFLNGIsVUFBVXhiLE1BQU1KO0FBQ3hELGNBQUUsT0FBT29FO2dCQUNQZSxJQUFJa0YsTUFBTWpHO2dCQUNWLE1BQU1BO0FBQ1I7WUFDQSxJQUFJZ1gsTUFBTXBiLElBQUkwTCxXQUFXMFA7WUFDekIsT0FBT1M7QUFDVDtBQUNGO0lBRVEsOEJBQU83QyxDQUF3QnpEO1FBQ3JDLE9BQU94TCxlQUFlK1IsVUFFcEJMLEtBQ0FMO1lBRUEsT0FBTXBiLEtBQUVBLEtBQUdtRixLQUFFQSxjQUNMeEIsS0FBSzBYLE9BQU8sSUFBSXhkLHNCQUFzQkksWUFBWSxPQUN4RG9ILElBQUl5VztZQUNOLE1BQU1KLGdCQUFnQm5pQixNQUFNQyxRQUFRaWlCLE9BQU9BLE1BQU0sRUFBQ0E7WUFDbEQsSUFBSUU7WUFDSjtnQkFDRXhXLElBQUlXLE1BQU0sWUFBWTRWLGNBQWNuZ0IsVUFBVWdhO2dCQUM5Q29HLGFBQWFoWSxLQUFLK0YsWUFBWTFKLEtBQUs4YixVQUFVSixlQUFlMWI7QUFDOUQsY0FBRSxPQUFPb0U7Z0JBQ1BlLElBQUlrRixNQUFNLG9CQUFvQmtMLGtCQUFrQm5SO2dCQUNoRCxNQUFNQTtBQUNSO1lBQ0FlLElBQUl1UixLQUFLLFdBQVdpRixLQUFLcGdCLFVBQVVnYTtZQUNuQyxJQUFJNkYsTUFBTXBiLElBQUkwTCxXQUFXMFA7WUFDekIsT0FBT087QUFDVDtBQUNGO0lBRVEsd0JBQU96QyxDQUNibEQsT0FDQVQ7UUFFQSxPQUFPeEwsZUFBZTRSLEtBRXBCSTtZQUVBLE9BQU0vYixLQUFFQSxLQUFHbUYsS0FBRUEsY0FDTHhCLEtBQUswWCxPQUFPLElBQUk3ZSxjQUFjQyxNQUFNLE9BQzFDNEksSUFBSXNXO1lBQ04sTUFBTUssS0FBS2hHLFNBQVMrRixZQUFZM2E7WUFDaEMsV0FBVzRhLE9BQU8sYUFDaEIsTUFBTSxJQUFJQyxnQkFBZ0IsTUFBTXRZLEtBQUs4TTtZQUN2QyxJQUFJeUw7WUFDSjtnQkFDRS9XLElBQUlXLE1BQU0sV0FBV3lQLHVCQUF1QjVSLEtBQUs4TSxNQUFNdUw7Z0JBQ3ZERSxtQkFBbUJ2WSxLQUFLK0YsWUFBWTFKLEtBQUsyYixLQUFLSyxJQUFJaGM7QUFDcEQsY0FBRSxPQUFPb0U7Z0JBQ1BlLElBQUlrRixNQUFNLGtCQUFrQmtMLDBCQUEwQnlHLE1BQU01WDtnQkFDNUQsTUFBTUE7QUFDUjtZQUNBZSxJQUFJdVIsS0FBSyxRQUFRbkIsMEJBQTJCMkcsV0FBbUJ2WSxLQUFLOE07WUFDcEUsT0FBT3lMO0FBQ1Q7QUFDRjtJQUVRLDBCQUFPOUMsQ0FDYnBELE9BQ0F6VixhQUNBZ1Y7UUFFQSxPQUFPeEwsZUFBZW9TLE9BRXBCSixhQUNBM2IsTUFDQWdiO1lBRUEsT0FBTXBiLEtBQUVBLEtBQUdtRixLQUFFQSxjQUNMeEIsS0FBSzBYLE9BQU8sSUFBSTdlLGNBQWNPLFFBQVEsT0FDNUNzSSxJQUFJOFc7WUFDTixNQUFNSCxLQUFLaEcsU0FBUytGLFlBQVkzYTtZQUNoQyxXQUFXNGEsT0FBTyxhQUNoQixNQUFNLElBQUlDLGdCQUFnQixNQUFNdFksS0FBSzhNO1lBQ3ZDLElBQUlvTDtZQUNKO2dCQUNFMVcsSUFBSXVSLEtBQUssWUFBWW5CLHVCQUF1QjVSLEtBQUs4TSxNQUFNdUw7Z0JBQ3ZELE1BQU1JLFVBQVVsUyxLQUFLbVMsTUFBTW5TLEtBQUtDLFVBQVUvSjtnQkFDMUN5YixnQkFBZ0JsWSxLQUFLK0YsWUFBWTFKLEtBQUttYyxPQUNwQyxJQUFJNWIsWUFBWTt1QkFBSzZiO29CQUFTLENBQUN6WSxLQUFLOE0sS0FBS3VMO29CQUN6Q2hjO0FBRUosY0FBRSxPQUFPb0U7Z0JBQ1BlLElBQUlrRixNQUFNakc7Z0JBQ1YsTUFBTUE7QUFDUjtZQUNBLElBQUlnWCxNQUFNcGIsSUFBSTBMLFdBQVcwUDtZQUN6QixPQUFPUztBQUNUO0FBQ0Y7SUFFUSwwQkFBT3ZDLENBQ2J0RCxPQUNBVDtRQUVBLE9BQU94TCxlQUFldVMsT0FFcEJQLGFBQ0FYO1lBRUEsT0FBTXBiLEtBQUVBLEtBQUdtRixLQUFFQSxjQUNMeEIsS0FBSzBYLE9BQU8sSUFBSTdlLGNBQWNXLFFBQVEsT0FDNUNrSSxJQUFJaVg7WUFDTixNQUFNTixLQUFLaEcsU0FBUytGLFlBQVkzYTtZQUNoQyxXQUFXNGEsT0FBTyxhQUNoQixNQUFNLElBQUlDLGdCQUFnQixNQUFNdFksS0FBSzhNO1lBQ3ZDLElBQUk4TDtZQUNKO2dCQUNFcFgsSUFBSVcsTUFBTSxZQUFZeVAsdUJBQXVCNVIsS0FBSzhNLE1BQU11TDtnQkFDeERPLFlBQVk1WSxLQUFLK0YsWUFBWTFKLEtBQUt3YyxPQUFPUixJQUFJaGM7QUFDL0MsY0FBRSxPQUFPb0U7Z0JBQ1BlLElBQUlrRixNQUFNLG9CQUFvQmtMLDBCQUEwQnlHLE1BQU01WDtnQkFDOUQsTUFBTUE7QUFDUjtZQUNBZSxJQUFJdVIsS0FBSyxXQUFXbkIsMEJBQTBCeUc7WUFDOUMsSUFBSVosTUFBTXBiLElBQUkwTCxXQUFXMFA7WUFDekIsT0FBT21CO0FBQ1Q7QUFDRjtJQUVRLDZCQUFPMUMsQ0FBdUJ0RTtRQUNwQyxPQUFPeEwsZUFBZUYsVUFFcEJuSyxNQUNBaUssTUFDQThTO1lBRUEsT0FBTXpjLEtBQUVBLGNBQ0EyRCxLQUFLMFgsT0FBTyxJQUFJbkgsZ0JBQWdCd0ksV0FBVyxPQUNqRHJYLElBQUl3RTtZQUNOLE9BQU1PLFdBQUVBLFdBQVNySSxRQUFFQSxRQUFNSixPQUFFQSxPQUFLSyxVQUFFQSxZQUFheWE7WUFDL0M5UyxPQUFPQSxLQUFLMU8sSUFDVCtiLGFBQWNBLE1BQU0sV0FBVzJGLFNBQVMzRixLQUFlQSxNQUFNQTtZQUVoRSxNQUFNNEYsZ0JBQWdCalQsS0FBS3BPLFNBQVMsSUFBSW9PLEtBQUssS0FBSy9OO1lBQ2xELE1BQU1paEIsb0JBQXFCelMsYUFBYXdTO1lBR3hDLElBQUlDLHFCQUFxQmxULEtBQUtwTyxTQUFTLEdBQUdvTyxLQUFLLEtBQUtrVDtZQUNwRCxRQUFRbmQ7Y0FDTixLQUFLckIsc0JBQXNCRztjQUMzQixLQUFLSCxzQkFBc0JNO2dCQUN6Qjs7Y0FDRixLQUFLTixzQkFBc0JDO2dCQUN6QnFMLEtBQUtyQyxLQUFLOEM7Z0JBQ1Y7O2NBQ0YsS0FBSy9MLHNCQUFzQkk7Y0FDM0IsS0FBS0osc0JBQXNCRTtnQkFDekJvTCxPQUFPLEVBQ0xBLEtBQUssSUFDTGtULG1CQUNBO29CQUFFbGI7b0JBQU9JO29CQUFRQzs7Z0JBRW5COztjQUNGLEtBQUszRCxzQkFBc0JLO2dCQUN6Qjs7Y0FDRixLQUFLTCxzQkFBc0JPO2NBQzNCLEtBQUtQLHNCQUFzQlE7Y0FDM0IsS0FBS1Isc0JBQXNCUztjQUMzQixLQUFLVCxzQkFBc0JVO2NBQzNCLEtBQUtWLHNCQUFzQlc7Y0FDM0IsS0FBS1gsc0JBQXNCWTtjQUMzQixLQUFLWixzQkFBc0JhO2dCQUN6Qjs7WUFFSixPQUFPeUUsS0FBSytGLFlBQVkxSixLQUFLNkosVUFBVW5LLFNBQVNpSyxNQUFNM0o7QUFDeEQ7QUFDRjtJQUVRLHFDQUFPbWEsQ0FDYkYsY0FDQTFFO1FBRUEsT0FBT3hMLGVBQWUrUyxxQkFFakJuVDtZQUVILE9BQU0zSixLQUFFQSxjQUNBMkQsS0FBSzBYLE9BQU8sSUFBSXBCLGNBQWMsT0FDcEM1VSxJQUFJeVg7WUFFTixRQUFRN0M7Y0FDTixLQUFLNWIsc0JBQXNCQztnQkFBUztvQkFDbEMsT0FBT3JHLEtBQUt3a0IsV0FBVzlTO29CQUN2QixPQUFPaEcsS0FBSytGLFlBQVkxSixLQUFLK2MsT0FDM0I5a0IsS0FDQ3drQixTQUFpQnJTLFdBQ2xCcEs7QUFFSjs7Y0FDQSxLQUFLM0Isc0JBQXNCRTtnQkFBUztvQkFDbEMsT0FBT3RHLEtBQUsra0IsTUFBTVAsV0FBVzlTO29CQUM3QixPQUFPaEcsS0FBSytGLFlBQVkxSixLQUFLaWQsV0FDM0JobEIsS0FDQ3drQixTQUFpQnJTLFdBQ2xCO3dCQUNFekksT0FBUThhLFNBQWlCOWE7d0JBQ3pCSSxRQUFTMGEsU0FBaUIxYTt3QkFDMUJpYjt1QkFFRmhkO0FBRUo7O2NBQ0EsS0FBSzNCLHNCQUFzQkc7Z0JBQU07b0JBQy9CLE9BQU9sRyxPQUFPbWtCLFdBQVc5UztvQkFDekIsTUFBTVMsWUFDSHFTLFNBQWlCclMsYUFBYXhCLGVBQWVzVTtvQkFDaEQsTUFBTXhULGNBQWMvRixLQUFLK0YsWUFBWTFKO29CQUNyQyxXQUFXMEosWUFBWWtSLFNBQVMsWUFDOUIsT0FBT2xSLFlBQVlrUixLQUFLdGlCLE9BQU84UixXQUFXcEs7b0JBQzVDLE9BQU8wSixZQUFZRyxVQUFVeEwsc0JBQXNCRyxNQUFNbEcsT0FBTzhSLFdBQVdwSztBQUM3RTs7Y0FDQSxLQUFLM0Isc0JBQXNCSTtnQkFBTTtvQkFDL0IsT0FBT25HLE9BQU9ta0IsV0FBVzlTO29CQUN6QixNQUFNd1QsTUFBTTt3QkFDVnBiLFFBQVMwYSxTQUFpQjFhLFVBQVU7d0JBQ3BDSixPQUFROGEsU0FBaUI5YSxTQUFTO3dCQUNsQ0ssVUFBV3lhLFNBQWlCemE7O29CQUU5QixNQUFNMEgsY0FBYy9GLEtBQUsrRixZQUFZMUo7b0JBQ3JDLE1BQU1vSyxZQUFhcVMsU0FBaUJyUyxhQUFheEIsZUFBZXNVO29CQUNoRSxXQUFXeFQsWUFBWXNULFNBQVMsWUFDOUIsT0FBT3RULFlBQVlzVCxLQUFLMWtCLE9BQU84UixXQUFXK1MsS0FBS25kO29CQUNqRCxPQUFPMEosWUFBWUcsVUFBVXhMLHNCQUFzQkksTUFBTW5HLE9BQU84UixXQUFXK1MsS0FBS25kO0FBQ2xGOztjQUNBLEtBQUszQixzQkFBc0JLO2dCQUFhO29CQUN0QyxPQUFPekcsS0FBS0ssU0FBU3FSO29CQUNyQixPQUFPaEcsS0FBSytGLFlBQVkxSixLQUFLb2QsVUFBVW5sQixLQUFLSyxPQUFPMEg7QUFDckQ7O2NBQ0EsS0FBSzNCLHNCQUFzQk07Z0JBQVM7b0JBQ2xDLE9BQU8xRyxLQUFLSyxTQUFTcVI7b0JBQ3JCLE9BQU9oRyxLQUFLK0YsWUFBWTFKLEtBQ3JCcUYsSUFBSXJGLElBQUl3UCxlQUNSNk4sT0FBT3BsQixLQUFLSyxPQUFPMEg7QUFDeEI7O2NBQ0E7Z0JBQ0UsSUFDRWlhLGlCQUFpQjViLHNCQUFzQk8sWUFDdkNxYixpQkFBaUI1YixzQkFBc0JRLFVBQ3ZDb2IsaUJBQWlCNWIsc0JBQXNCUyxVQUN2Q21iLGlCQUFpQjViLHNCQUFzQlUsVUFDdkNrYixpQkFBaUI1YixzQkFBc0JXLFVBQ3ZDaWIsaUJBQWlCNWIsc0JBQXNCWSxlQUN2Q2diLGlCQUFpQjViLHNCQUFzQmEsVUFDdkM7b0JBQ0EsT0FBT29lLFNBQVMzVDtvQkFDaEIsT0FBT2hHLEtBQUsrRixZQUFZMUosS0FBSzZKLFVBQVVvUSxjQUFjcUQsT0FBT3RkO0FBQzlEO2dCQUNBLE1BQU0sSUFBSThILE1BQU0sc0JBQXNCbVM7O0FBRTVDO0FBQ0Y7SUFFUSxnQ0FBT3ZGLENBQTBCck07UUFDdkMsT0FBTzBCLGVBQWV3VCxnQkFFakI1VDtZQUVILE1BQU14RSxNQUFXeEIsS0FBS3dCLEtBQUtFLE1BQU1rWTtZQUNqQztnQkFDRSxJQUFJcFksS0FBS0EsSUFBSVcsTUFBTSwwQkFBMEJ1QztnQkFDN0MsT0FBTXJJLEtBQUVBLGNBQ0EyRCxLQUFLMFgsT0FBTyxJQUFJaFQsWUFBWSxPQUNsQ2hELElBQUlrWTtnQkFDTixNQUFNN1QsY0FBYy9GLEtBQUsrRixZQUFZMUo7Z0JBQ3JDLE1BQU13ZCxhQUFhNUosb0JBQW9CNkosaUJBQWlCOVQ7Z0JBQ3hELFdBQVdELFlBQVlyQixnQkFBZ0IsWUFBWTtvQkFDakQsT0FBT3FCLFlBQVlyQixlQUFlbVYsWUFBWXhkO0FBQ2hEO2dCQUNBLFdBQVcwSixZQUFZRyxjQUFjLFlBQVk7b0JBQy9DLE9BQU9ILFlBQVlHLFVBQVV4QixlQUFlbVYsWUFBWXhkO0FBQzFEO2dCQUNBLE1BQU0sSUFBSThILE1BQ1IsdUJBQXVCTyw0QkFBNEJxQixhQUFhdFEsYUFBYXNHO0FBRWpGLGNBQUUsT0FBTzBFO2dCQUNQLElBQUllLEtBQUtBLElBQUlrRixNQUFNLGlCQUFpQmhDLHNCQUFzQmpFO2dCQUMxRCxNQUFNQTtBQUNSO0FBQ0Y7QUFDRjtJQUVRLCtCQUFPMlcsQ0FBeUIxUztRQUN0QyxPQUFPMEIsZUFBZTJULGVBRWpCL1Q7WUFFSCxNQUFNeEUsTUFBV3hCLEtBQUt3QixLQUFLRSxNQUFNcVk7WUFDakMsT0FBTTFkLEtBQUVBLGNBQ0EyRCxLQUFLMFgsT0FBTyxJQUFJaFQsWUFBWSxPQUNsQ2hELElBQUlxWTtZQUNOLE1BQU1oVSxjQUFjL0YsS0FBSytGLFlBQVkxSjtZQUNyQyxNQUFNd2QsYUFBYTVKLG9CQUFvQjZKLGlCQUFpQjlUO1lBR3hELFdBQVdELFlBQVlyQixnQkFBZ0IsWUFBWTtnQkFDakQsT0FBT3FCLFlBQVlyQixlQUFlbVYsWUFBWXhkO0FBQ2hEO1lBRUEsSUFBSTBKLGFBQWEwSyxlQUFlMUssWUFBWTBLLEtBQUsvTCxnQkFBZ0IsWUFBWTtnQkFDM0UsT0FBT3FCLFlBQVkwSyxLQUFLL0wsZUFBZW1WLFlBQVl4ZDtBQUNyRDtZQUVBLFdBQVcwSixZQUFZRyxjQUFjLFlBQVk7Z0JBQy9DLE9BQU9ILFlBQVlHLFVBQVV4QixlQUFlbVYsWUFBWXhkO0FBQzFEO1lBQ0EsTUFBTSxJQUFJOEgsTUFDUixXQUFXTyw0QkFBNEJxQixhQUFhdFEsYUFBYXNHO0FBRXJFO0FBQ0Y7SUFFUSx1QkFBTytkLENBQWlCOVQ7UUFDOUIsSUFBSUEsS0FBS3BPLFdBQVcsR0FBRyxPQUFPb087UUFDOUIsTUFBTWdVLE9BQU9oVSxLQUFLQSxLQUFLcE8sU0FBUztRQUNoQyxJQUNFb2lCLGVBQ09BLFNBQVMsYUFDZnBrQixNQUFNQyxRQUFRbWtCLE9BQ2Y7WUFDQSxNQUFNQyxXQUFXalUsS0FBS2tVO1lBQ3RCLE1BQU1DLGVBQWVGLFNBQVN4VCxjQUFjeE87WUFDNUMsTUFBTW1pQixXQUFXSCxTQUFTamMsVUFBVS9GO1lBQ3BDLE1BQU1vaUIsWUFBWUosU0FBUzdiLFdBQVduRztZQUN0QyxLQUFLa2lCLGlCQUFpQkMsYUFBYUMsV0FBVyxPQUFPclU7WUFDckQsTUFBTXNVLFNBQWdCO1lBQ3RCLElBQUlILGNBQWNHLE9BQU8zVyxLQUFLc1csU0FBU3hULGlCQUNsQyxJQUFJMlQsWUFBWUMsV0FBV0MsT0FBTzNXLEtBQUsxTDtZQUM1QyxJQUFJbWlCLFVBQVVFLE9BQU8zVyxLQUFLc1csU0FBU2pjO1lBQ25DLElBQUlxYyxXQUFXQyxPQUFPM1csS0FBS3NXLFNBQVM3YjtZQUNwQyxPQUFPLEtBQUk0SCxTQUFTc1U7QUFDdEI7UUFDQSxPQUFPdFU7QUFDVDtJQUVRLDZCQUFPNE8sQ0FDYmhZLGFBQ0FnVjtRQUVBLE9BQU8sRUFDTHJaLHNCQUFzQnFFLGFBQWEsU0FDbkN3SSxhQUFhO1lBQUVDLFNBQVMsZ0JBQWdCdU07WUFDeEMySSxRQUFRO1lBQ052ZSxhQUFhLGVBQWU0VjtZQUM1QnBjLE1BQU15VyxPQUFPcFQsY0FBY0ksUUFBUTJEO1lBRXJDNGQsbUJBQW1CO1lBQ2pCeGUsYUFBYSxHQUFHNFY7WUFDaEI2SSxRQUFRO2dCQUFFL0ssTUFBTWdMLGNBQWM5ZDs7WUFFaEMrZCxzQkFBc0I7WUFBRTNlLGFBQWE7WUFDckM0ZSwrQkFBK0I7WUFDN0I1ZSxhQUFhOztBQUduQjtJQUVRLDJCQUFPZ1osQ0FDYnBZLGFBQ0FnVjtRQUVBLE9BQU8sRUFDTHJaLHNCQUFzQnFFLGFBQWEsUUFBUSxTQUMzQ3dJLGFBQWE7WUFBRUMsU0FBUyxnQkFBZ0J1TTtZQUN4QzJJLFFBQVE7WUFDTnZlLGFBQWEsZUFBZTRWO1lBQzVCNkksUUFBUTtnQkFDTmpsQixNQUFNO2dCQUNOOEMsT0FBTztvQkFBRW9YLE1BQU1nTCxjQUFjOWQ7OztZQUdqQzRkLG1CQUFtQjtZQUNqQnhlLGFBQWEsR0FBRzRWO1lBQ2hCNkksUUFBUTtnQkFDTmpsQixNQUFNO2dCQUNOOEMsT0FBTztvQkFBRW9YLE1BQU1nTCxjQUFjOWQ7OztZQUdqQytkLHNCQUFzQjtZQUFFM2UsYUFBYTtZQUNyQzRlLCtCQUErQjtZQUM3QjVlLGFBQWE7O0FBR25CO0lBRVEseUJBQU9rWixDQUNidFksYUFDQWdWO1FBRUEsT0FBTyxFQUNMclosc0JBQXNCcUUsYUFBYSxPQUFPLFNBQzFDd0ksYUFBYTtZQUFFQyxTQUFTLFlBQVl1TTtZQUNwQzVNLFNBQVM7WUFBRWpKLE1BQU07WUFBT2xFLFVBQVU7WUFBTXJDLE1BQU07WUFDOUM4UCxjQUFjO1lBQ1p0SixhQUFhLEdBQUc0VjtZQUNoQjZJLFFBQVE7Z0JBQ05qbEIsTUFBTTtnQkFDTjhDLE9BQU87b0JBQUVvWCxNQUFNZ0wsY0FBYzlkOzs7WUFHakNpZSxvQkFBb0I7WUFDbEI3ZSxhQUFhLE1BQU00Vjs7QUFHekI7SUFFUSwyQkFBT3dELENBQ2J4WSxhQUNBZ1YsZ0JBQ0FVO1FBRUEsT0FBTyxFQUNML1osc0JBQXNCcUUsYUFBYSxPQUFPLFNBQzFDbEIsbUJBQW1CNFcsZ0JBQ25CbE4sYUFBYTtZQUNYQyxTQUFTLG9CQUFvQnVNO1lBRS9CMkksUUFBUTtZQUNOdmUsYUFBYSw2Q0FBNkM0VjtZQUMxRDZJLFFBQVE7Z0JBQ05qbEIsTUFBTTtnQkFDTmthLE1BQU1nTCxjQUFjek8sT0FBT3BULGNBQWNPLFFBQVF3RDs7WUFHckQwSSxjQUFjO1lBQ1p0SixhQUFhLEdBQUc0VjtZQUNoQjZJLFFBQVE7Z0JBQ05qbEIsTUFBTTtnQkFDTjhDLE9BQU87b0JBQUVvWCxNQUFNZ0wsY0FBYzlkOzs7WUFHakNpZSxvQkFBb0I7WUFDbEI3ZSxhQUFhLE1BQU00VjtZQUVyQitJLHNCQUFzQjtZQUFFM2UsYUFBYTs7QUFFekM7SUFFUSwyQkFBT3NaLENBQ2IxWSxhQUNBZ1YsZ0JBQ0FVO1FBRUEsT0FBTyxFQUNML1osc0JBQXNCcUUsYUFBYSxVQUFVLFNBQzdDbEIsbUJBQW1CNFcsZ0JBQ25CbE4sYUFBYTtZQUFFQyxTQUFTLFVBQVV1TTtZQUNsQzVNLFNBQVM7WUFBRWpKLE1BQU07WUFBT2xFLFVBQVU7WUFBTXJDLE1BQU07WUFDOUM4UCxjQUFjO1lBQ1p0SixhQUFhLEdBQUc0VjtZQUNoQjZJLFFBQVE7Z0JBQ05qbEIsTUFBTTtnQkFDTjhDLE9BQU87b0JBQUVvWCxNQUFNZ0wsY0FBYzlkOzs7WUFHakNpZSxvQkFBb0I7WUFDbEI3ZSxhQUFhLE1BQU00Vjs7QUFHekI7SUFFUSxxQkFBTzRELENBQ2I1WSxhQUNBZ1YsZ0JBQ0FVLGVBQ0FDO1FBRUEsT0FBTyxFQUNMaGEsc0JBQXNCcUUsYUFBYSxPQUFPMlYsU0FDMUM3VyxtQkFBbUI0VyxnQkFDbkJsTixhQUFhO1lBQUVDLFNBQVMsY0FBY3VNO1lBQ3RDdE0sY0FBYztZQUNadEosYUFBYSxHQUFHNFY7WUFDaEI2SSxRQUFRO2dCQUFFL0ssTUFBTWdMLGNBQWM5ZDs7WUFFaENpZSxvQkFBb0I7WUFDbEI3ZSxhQUFhLE1BQU00Vjs7QUFHekI7SUFFUSx1QkFBTzhELENBQ2I5WSxhQUNBZ1YsZ0JBQ0FVLGVBQ0FDO1FBRUEsT0FBTyxFQUNMaGEsc0JBQXNCcUUsYUFBYSxPQUFPMlYsU0FDMUM3VyxtQkFBbUI0VyxnQkFDbkJsTixhQUFhO1lBQ1hDLFNBQVMsdUJBQXVCdU07WUFFbEMySSxRQUFRO1lBQ052ZSxhQUFhLCtDQUErQzRWO1lBQzVEcGMsTUFBTXlXLE9BQU9wVCxjQUFjTyxRQUFRd0Q7WUFFckMwSSxjQUFjO1lBQ1p0SixhQUFhLEdBQUc0VjtZQUNoQjZJLFFBQVE7Z0JBQUUvSyxNQUFNZ0wsY0FBYzlkOztZQUVoQ2llLG9CQUFvQjtZQUNsQjdlLGFBQWEsTUFBTTRWO1lBRXJCK0ksc0JBQXNCO1lBQUUzZSxhQUFhOztBQUV6QztJQUVRLHVCQUFPNFosQ0FDYmhaLGFBQ0FnVixnQkFDQVUsZUFDQUM7UUFFQSxPQUFPLEVBQ0xoYSxzQkFBc0JxRSxhQUFhLFVBQVUyVixTQUM3QzdXLG1CQUFtQjRXLGdCQUNuQmxOLGFBQWE7WUFBRUMsU0FBUyxZQUFZdU07WUFDcEN0TSxjQUFjO1lBQ1p0SixhQUFhLEdBQUc0VjtZQUNoQjZJLFFBQVE7Z0JBQUUvSyxNQUFNZ0wsY0FBYzlkOztZQUVoQ2llLG9CQUFvQjtZQUNsQjdlLGFBQWEsTUFBTTRWOztBQUd6QjtJQUVRLDBCQUFPdUUsQ0FDYnZaLGFBQ0FnVjtRQUVBLE9BQU8sRUFDTHJaLHNCQUFzQnFFLGFBQWEsT0FBTyw0QkFDMUN3SSxhQUFhO1lBQ1hDLFNBQVMsb0NBQW9DdU07WUFFL0N6TSxTQUFTO1lBQUVwSixNQUFNO1lBQVVDLGFBQWE7WUFDeENtSixTQUFTO1lBQ1BwSixNQUFNO1lBQ05DLGFBQWE7WUFFZmdKLFNBQVM7WUFDUGpKLE1BQU07WUFDTmxFLFVBQVU7WUFDVkcsTUFBTWlOO1lBQ05qSixhQUFhO1lBRWZnSixTQUFTO1lBQUVqSixNQUFNO1lBQVNsRSxVQUFVO1lBQU1tRSxhQUFhO1lBQ3ZEZ0osU0FBUztZQUFFakosTUFBTTtZQUFVbEUsVUFBVTtZQUFNbUUsYUFBYTtZQUN4RHNKLGNBQWM7WUFBRXRKLGFBQWEsR0FBRzRWO1lBQ2hDaUosb0JBQW9CO1lBQ2xCN2UsYUFBYSxNQUFNNFY7O0FBR3pCO0lBRVEsa0NBQU82RSxDQUNiN1osYUFDQWdWLGdCQUNBbFosTUFDQTRkO1FBRUEsTUFBTXdFLE9BQTZELEVBQ2pFdmlCLHNCQUFzQnFFLGFBQWEsT0FBT2xFLE9BQzFDME0sYUFBYTtZQUFFQyxTQUFTLFlBQVl1TTtZQUNwQ3RNLGNBQWM7WUFBRXRKLGFBQWEsR0FBRzRWOztRQUdsQyxNQUFNMEYsV0FBVzVlLEtBQUs0TCxNQUFNLEtBQUtqTixPQUFRcWMsS0FBTUEsRUFBRWxZLFdBQVc7UUFDNUQ4YixTQUFTM1IsUUFBUzRSO1lBQ2hCLE1BQU14YixPQUFPd2IsSUFBSS9jLFFBQVEsS0FBSztZQUM5QnNnQixLQUFLblgsS0FBS3dCLFNBQVM7Z0JBQUVwSjtnQkFBTUMsYUFBYSxPQUFPRDs7O1FBR2pELElBQ0VyRCxLQUFLOEMsV0FBVyxjQUNoQjlDLEtBQUs4QyxXQUFXLGtCQUNoQjlDLEtBQUs4QyxXQUFXLFlBQ2hCOUMsS0FBSzhDLFdBQVcsVUFDaEI7WUFDQXNmLEtBQUtuWCxLQUNIcUIsU0FBUztnQkFDUGpKLE1BQU07Z0JBQ05sRSxVQUFVO2dCQUNWRyxNQUFNaU47Z0JBQ05qSixhQUFhOztBQUduQjtRQUNBLElBQUl0RCxLQUFLOEMsV0FBVyxrQkFBa0I5QyxLQUFLOEMsV0FBVyxVQUFVO1lBQzlEc2YsS0FBS25YLEtBQ0hxQixTQUFTO2dCQUFFakosTUFBTTtnQkFBU2xFLFVBQVU7Z0JBQU9tRSxhQUFhO2dCQUN4RGdKLFNBQVM7Z0JBQUVqSixNQUFNO2dCQUFVbEUsVUFBVTtnQkFBT21FLGFBQWE7Z0JBQ3pEZ0osU0FBUztnQkFBRWpKLE1BQU07Z0JBQVlsRSxVQUFVO2dCQUFPbUUsYUFBYTs7QUFFL0Q7UUFFQSxJQUFJdEQsS0FBSzhDLFdBQVcsaUJBQWlCOUMsS0FBSzhDLFdBQVcsWUFBWTtZQUMvRHNmLEtBQUtuWCxLQUNIa1gsb0JBQW9CO2dCQUNsQjdlLGFBQWEsTUFBTTRWOztBQUd6QjtRQUVBLElBQ0UwRSxpQkFBaUI1YixzQkFBc0JPLFlBQ3ZDcWIsaUJBQWlCNWIsc0JBQXNCVSxVQUN2Q2tiLGlCQUFpQjViLHNCQUFzQlcsUUFDdkM7WUFDQXlmLEtBQUtuWCxLQUFLMkIsY0FBYztnQkFBRXRKLGFBQWEsY0FBYzRWO2dCQUFtQnBjLE1BQU0wSTs7QUFDaEY7UUFDQSxJQUFJb1ksaUJBQWlCNWIsc0JBQXNCWSxhQUFhO1lBQ3REd2YsS0FBS25YLEtBQUsyQixjQUFjO2dCQUFFdEosYUFBYSx1QkFBdUI0VjtnQkFBbUJwYyxNQUFNLEVBQUN5Rzs7QUFDMUY7UUFFQSxPQUFPNmU7QUFDVDtJQUVRLHlCQUFPM0osQ0FDYnpNLFlBQ0FMLFdBQ0FNLFVBQ0FDLHFCQUE4QjtRQUU5QixNQUFNUixvQkFBcUJ2SSxLQUN6QkEsRUFBRXlJLE1BQU0sS0FBS2pOLE9BQVFxYyxLQUFNQSxFQUFFbFksV0FBVyxNQUFNbEUsSUFBS29jLEtBQU1BLEVBQUVuUCxNQUFNO1FBRW5FLE1BQU1PLGdCQUFnQlYsa0JBQWtCQyxXQUFXL00sSUFBS3lFLFNBQUk7WUFDMURBO1lBQ0FDLGFBQWEsR0FBR0Q7WUFDaEJsRSxVQUFVO1lBQ1ZyQyxNQUFNeUc7O1FBR1IsTUFBTUwsYUFBbUUsS0FDcEVrSixjQUFjeE4sSUFBS3VFLEtBQU1zSixTQUFTdEosS0FDckN1SixhQUFhO1lBQUVDLFNBQVMsMkJBQTJCWDtZQUNuRFksY0FBYztZQUFFdEosYUFBYTtZQUM3QnVKLHFCQUFxQjtZQUFFdkosYUFBYTs7UUFHdEMsSUFBSTJJLGFBQWEsU0FBU0Msb0JBQW9CO1lBQzVDaEosV0FBVytILEtBQ1RxQixTQUFTO2dCQUNQakosTUFBTTtnQkFDTmxFLFVBQVU7Z0JBQ1ZHLE1BQU1pTjtnQkFDTmpKLGFBQWE7Z0JBRWZnSixTQUFTO2dCQUFFakosTUFBTTtnQkFBU2xFLFVBQVU7Z0JBQU9tRSxhQUFhO2dCQUN4RGdKLFNBQVM7Z0JBQUVqSixNQUFNO2dCQUFVbEUsVUFBVTtnQkFBT21FLGFBQWE7O0FBRTdEO1FBRUEsT0FBT0o7QUFDVDs7O0FDNzNDSSxTQUFVbWYsYUFBYWhZOztJQUUzQixJQUFNaVksbUJBQU4sTUFBTUE7Ozs7O1lBQ1loYixLQUFBd0IsTUFBTUMsUUFBUUMsSUFBSXVaLG1CQUFpQmxmLE1BQU0yRixJQUFJcUI7QUFBUztRQUV0RSwwQkFBT21ZLENBQ0xDO1lBRUEsT0FBT0EsT0FBTzdqQixJQUFLZ00sVUFBSztnQkFDdEIrRyxTQUFTLEdBQUcvRyxNQUFNdkg7Z0JBQ2xCcWYsWUFBWSxNQUFNblYsYUFBYTJGLFNBQVN0STs7QUFFNUM7UUFFQSxnQkFBTytYLENBQ0wvWCxPQUNBZ1k7WUFFQSxNQUFNeFAsV0FBV3dQLFdBQVdoWSxNQUFNdkg7WUFDbEMsTUFBTXBILGVBQ0dtWCxhQUFhLGNBQ2hCQSxXQUNBN00sU0FBU3VCLElBQUk4QyxPQUFPckUsU0FBUzNLLElBQUlzSztZQUV2QyxXQUFXakssVUFBVSxhQUFhLE9BQU87WUFDekMsSUFBSUEsVUFBVSxNQUFNLE9BQU87WUFDM0IsSUFBSWlCLE1BQU1DLFFBQVFsQixRQUFRLE9BQU9BLE1BQU1NLFNBQVM4TjtZQUNoRCxPQUFPO0FBQ1Q7UUFFQSxjQUFPb0gsQ0FDTHBILFNBQ0E1SyxVQUF1QztZQUV2QyxNQUFNcUosTUFBTXhCLEtBQUt3QixJQUFJRSxJQUFJMUIsS0FBS21LO1lBQzlCM0ksSUFBSXVSLEtBQUs7WUFFVCxNQUFNd0ksZ0JBQWdCMVksUUFBUXNZLE9BQU9wWSxTQUFTMUwsT0FBUWlNLFNBQ3BEdEQsS0FBS3FiLFVBQVUvWCxPQUFPbkwsUUFBUXFqQjtZQUdoQyxJQUFJQyxnQkFBNEI7WUFDaEMsSUFBSXRqQixRQUFRdWpCLGNBQWM7Z0JBQ3hCbGEsSUFBSXVSLEtBQUs7Z0JBQ1QwSSxnQkFBZ0J6YixLQUFLa2Isb0JBQW9CSztnQkFDekMvWixJQUFJdVIsS0FDRiw0QkFBNEIwSSxjQUFjN2pCO0FBRTlDO1lBRUEsTUFBTTZaLGlCQUF3RCxDQUFBO1lBQzlELElBQUl0WixRQUFRd2pCLGlCQUFpQixPQUFPO2dCQUNsQ2xLLGVBQWVtSyx1QkFBdUI7QUFDeEM7WUFFQSxNQUFNQyxjQUFjTixjQUFjamtCLElBQUtnTSxTQUNyQzJNLG9CQUFvQnNCLE9BQU9qTyxPQUFPbkwsUUFBUWdILGtCQUFrQnNTO1lBRTlEalEsSUFBSXVSLEtBQUssYUFBYThJLFlBQVlqa0I7WUFFbEMsT0FBTztnQkFDTDhTLFFBQVF1UTtnQkFDUlk7Z0JBQ0F6UixXQUFXLEtBQ05xUjs7QUFHVDs7SUFqRUlULG1CQUFnQkMscUJBQUF0YSxXQUFBLEVBRHJCaUssT0FBTyxDQUFBLE1BQ0ZvUTtJQW1FTmpsQixPQUFPQyxPQUFPZ2xCLGtCQUFrQixRQUFRO1FBQ3RDcm1CLE9BQU8sY0FBY29POztJQUV2QixPQUFPaVk7QUFDVDs7QUN0RUFjLFdBQVdwYSxJQUFJcWEsZ0JBQWdCQyxZQUM1QkMsT0FBTztJQUNOL1gsV0FBVyxTQUFTZ1ksZUFDbEJDLFVBQ0FDO1FBRUFBLE1BQ0VBLGVBQ1FELGFBQWEsV0FDakJwbUIsT0FBT0MsT0FDTG1tQixVQUNBRSw0QkFFRkE7UUFDTixPQUFPemIsV0FBVztZQUNoQkMsT0FBT3ViLElBQUlFLFlBQVl4YixNQUFNeWIsVUFBVXpiLE1BQU1DO1lBQzdDeWIsU0FBU0osSUFBSUUsWUFBWXJrQixZQUFZOztBQUV6QztHQUVEOEI7O0FBRUgraEIsV0FBV3BhLElBQUlxYSxnQkFBZ0JVLFFBQzVCUixPQUFPO0lBQ04vWCxXQUFXLFNBQVN3WSxXQUNsQlAsVUFFQUM7UUFFQSxPQUFPLFNBQVNPLGdCQUNkdG9CLFFBQ0FVLGFBQ0FSO1lBRUEsT0FBTzBNLE9BQU9rYixZQUFhOW5CLE9BQXBCNE0sQ0FDTDVNLFFBQ0FVLGFBQ0FSO0FBRUo7QUFDRjtHQUVEd0Y7O0FBRUgraEIsV0FBV3BhLElBQUlzTSxlQUFlQyxVQUMzQmdPLE9BQ0MvakIsWUFBWTtJQUNWTCxVQUFVO0lBR2JrQzs7QUFFSCtoQixXQUFXcGEsSUFBSXNNLGVBQWU0TyxLQUMzQlgsT0FBTztJQUNOL1gsV0FBVyxTQUFTMlksT0FBT0M7UUFDekIsT0FBTzVrQixZQUFZO1lBQUU2a0IsU0FBU0Q7WUFBS2psQixVQUFVOztBQUMvQztHQUVEa0M7O0FBRUgraEIsV0FBV3BhLElBQUlzTSxlQUFlZ1AsS0FDM0JmLE9BQU87SUFDTi9YLFdBQVcsU0FBUytZLE9BQU9DO1FBQ3pCLE9BQU9obEIsWUFBWTtZQUFFaWxCLFNBQVNEO1lBQUtybEIsVUFBVTs7QUFDL0M7R0FFRGtDOztBQUVIK2hCLFdBQVdwYSxJQUFJc00sZUFBZW9QLFlBQzNCbkIsT0FBTztJQUNOL1gsV0FBVyxTQUFTbVosYUFBYVA7UUFDL0IsT0FBTzVrQixZQUFZO1lBQUVvbEIsV0FBV1I7WUFBS2psQixVQUFVOztBQUNqRDtHQUVEa0M7O0FBRUgraEIsV0FBV3BhLElBQUlzTSxlQUFldVAsWUFDM0J0QixPQUFPO0lBQ04vWCxXQUFXLFNBQVNzWixhQUFhTjtRQUMvQixPQUFPaGxCLFlBQVk7WUFBRXVsQixXQUFXUDtZQUFLcmxCLFVBQVU7O0FBQ2pEO0dBRURrQzs7QUFFSCtoQixXQUFXcGEsSUFBSXNNLGVBQWUwUCxNQUMzQnpCLE9BQU87SUFDTi9YLFdBQVcsU0FBU3laLFFBQ2xCbm9CO1FBS0EsT0FBTyxDQUFDbkIsUUFBZ0JzWjtZQUN0Qm5ZLE9BQU9JLE1BQU1DLFFBQVFMLFFBQVFBLEtBQUssS0FBS0E7WUFDdkMsV0FBV0EsU0FBUyxlQUFlQSxLQUFLdUcsTUFDdEN2RyxPQUFRQTtZQUNWLE9BQU8wQyxZQUFZO2dCQUNqQjFDLE1BQU1BO2dCQUNOcUMsVUFBVTtjQUZMSyxDQUdKN0QsUUFBUXNaOztBQUVmO0dBRUQ1VDs7QUFzQkgraEIsV0FBV3BhLElBQUlzTSxlQUFlNFAsTUFDM0IzQixPQUFPO0lBRU4vWCxXQUFXLFNBQVMyWixRQUFRQztRQUMxQixPQUFPNWxCLFlBQVk7WUFDakIxQyxNQUFNeUc7WUFDTjZoQixRQUFRO1lBQ1JqbUIsVUFBVTs7QUFHZDtHQUVEa0M7O0FBRUgraEIsV0FBV3BhLElBQUlzTSxlQUFlK1AsTUFDM0I5QixPQUFPO0lBQ04vWCxXQUFXLFNBQVM4WixVQUFVN2xCO1FBQzVCLE1BQU1KLE9BQU9uQyxNQUFNQyxRQUFRc0MsV0FBV0EsVUFBVXBDLE9BQU9xQixPQUFPZTtRQUM5RCxPQUFPRCxZQUFZO1lBQ2pCRixNQUFNRDtZQUNORixVQUFVOztBQUVkO0dBRURrQzs7QUFFSCtoQixXQUFXcGEsSUFBSXNNLGVBQWVpUSxTQUMzQmhDLE9BQU87SUFDTi9YLFdBQVcsU0FBU2dhLFdBQVdDO1FBQzdCLE9BQU9qbUIsWUFBWTtZQUNqQmttQixnQkFBZ0JELFFBQVEsV0FBV0EsTUFBTUEsSUFBSUU7WUFDN0N4bUIsVUFBVTs7QUFFZDtHQUVEa0M7O0FBRUgraEIsV0FBV3BhLElBQUk2TyxnQkFBZ0IrTixRQUM1QnJDLE9BQU87SUFDTi9YLFdBQVcsU0FBU3FhLFVBQVV4aUI7UUFDNUIsT0FBTzdELFlBQVk7WUFDakI2RCxNQUFNQTtZQUNObEUsVUFBVTs7QUFFZDtHQUVEa0M7O0FBRUgraEIsV0FBV3BhLElBQUk4YyxlQUFlQyxhQUMzQnhDLE9BQU87SUFDTi9YLFdBQVcsU0FBU3dhLGVBQWUxaUI7UUFDakMsT0FBTzlELFlBQVk7WUFDakI4RCxhQUFhQTtZQUNibkUsVUFBVTs7QUFFZDtHQUVEa0M7O0FBRUgraEIsV0FBV3BhLElBQUk2TyxnQkFBZ0JvTyxNQUFNMUMsT0FBTztJQUFFL1gsV0FBV2I7R0FBUXRKOztBQ25NM0QsTUFBTzZrQixrQkFBa0JDO0lBQzdCLFdBQUFwcEIsQ0FBWXFwQjtRQUNWamYsTUFBTWlmLEtBQUtGLFVBQVU3aUI7QUFDdkI7OztBQ0hJLE1BQU9nakIsNEJBQTRCQztJQUN2QyxXQUFBdnBCLENBQVlxcEI7UUFDVmpmLE1BQU1rZixvQkFBb0JoakIsTUFBTStpQixLQUFNO0FBQ3hDOzs7QUNRSyxJQUFNRyx1QkFBTixNQUFNQTtJQUNYLE1BQU1DLFdBQWtCQztRQUN0QixNQUFNOWlCLE1BQU04aUIsS0FBSzVpQjtRQUNqQixNQUFNeU8sV0FBVzNPLElBQUlvTjtRQUNyQixNQUFNbk4sVUFBVUQsSUFBSUc7UUFFcEIsTUFBTTRpQixlQUFlQyxrQkFBa0JDLFFBQVE7UUFDL0MsSUFBSUM7UUFFSixJQUNFTCxxQkFBcUJNLHFCQUNyQk4scUJBQXFCTyxrQkFDckI7WUFDQVAsWUFBWSxJQUFJUSx1QkFBdUJSLFVBQVVTO1lBQ2pESixhQUFjTCxVQUFxQ1U7QUFDckQsZUFBTyxNQUFNVixxQkFBcUJGLFlBQVk7WUFDNUMsSUFBSUUsVUFBa0JXLFdBQVcsS0FBSTtnQkFDbkNYLFlBQVksSUFBSUgsb0JBQW9CRyxVQUFVUztBQUNoRCxtQkFBSztnQkFDSFQsWUFBWSxJQUFJeFEsY0FBY3dRLFVBQVVTO0FBQzFDO0FBQ0Y7UUFFQTNVLFNBQVM2VSxPQUFRWCxVQUF3QlksUUFBUVAsWUFBWVEsS0FBSztZQUNoRUYsUUFBU1gsVUFBd0JZLFFBQVFQO1lBQ3pDN1ksT0FBTzBZLGVBQWVGLFVBQVVuakIsT0FBT21qQixVQUFVUztZQUNqRHZXLFlBQVcsSUFBSUMsTUFBTzJXO1lBQ3RCdG5CLE1BQU00RCxRQUFRaU47WUFDZHJFLFFBQVE1SSxRQUFRNEk7O0FBRXBCOzs7QUE5QlcrWix1QkFBb0J0ZSxXQUFBLEVBRGhDc2YsV0FDWWhCOztTQ1RHaUI7SUFDZCxPQUFPQyxXQUFXLElBQUlsQjtBQUN4Qjs7U0FFZ0JtQjtJQUNkLE9BQU8xYyxnQkFBZ0JxSDtBQUN6Qjs7QUNvQk8sTUFBTXNWLHVCQUF1QztJQUNsREMsT0FBTztJQUNQdGtCLGFBQWE7SUFDYnVrQixTQUFTO0lBQ1Q3bkIsTUFBTTtJQUNOOG5CLGlCQUFpQjtJQUNqQkMsb0JBQW9CO0lBQ3BCL04sTUFBTTtRQUNKbGQsTUFBTTtRQUNOa3JCLFFBQVE7UUFDUkMsY0FBYztRQUNkNWtCLE1BQU07UUFDTkMsYUFBYTtRQUNiNGtCLElBQUk7O0lBRU5DLHNCQUFzQjtJQUN0QkMsZUFBZTs7O01DaENKQztJQVVYLFdBQUF0ckIsQ0FBWTBDO1FBQ1Y2SCxLQUFLN0gsVUFBVTtlQUNWQTs7QUFFUDtJQUVRLFNBQUE2b0I7UUFDTixJQUFJQyxNQUFNO1FBQ1YsSUFBSWpoQixLQUFLN0gsUUFBUStvQixnQkFBZ0I7WUFDL0IsTUFBTUMsTUFBTW5oQixLQUFLb2hCLElBQUlwaEIsS0FBSzdILFFBQVErb0I7WUFDbENELE9BQU8seURBQXlERTtBQUNsRTtRQUNBLE9BQ0VGLE1BQ0EsMEdBRTRDamhCLEtBQUs3SCxRQUFRMm9CLGlCQUFpQlQscUJBQXFCUztBQUduRztJQUVBLGdCQUFBTztRQUNFLE1BQU1DLFVBQStCLENBQUE7UUFDckMsSUFBSXRoQixLQUFLN0gsUUFBUW9wQixhQUFhO1lBQzVCRCxRQUFRLG1CQUFtQnRoQixLQUFLb2hCLElBQUlwaEIsS0FBSzdILFFBQVFvcEIsYUFBYTtBQUNoRTtRQUVBLE9BQU87WUFDTEMsaUJBQWlCeGhCLEtBQUs3SCxRQUFRbW9CO2VBQzNCZ0I7WUFDSEcsV0FBV3poQixLQUFLZ2hCO1lBQ2hCVSxnQkFBZ0I7Z0JBQ2RiLHNCQUFzQjdnQixLQUFLN0gsUUFBUTBvQjs7O0FBR3pDO0lBRUEsR0FBQU8sQ0FBSU8sTUFBY1IsTUFBZTtRQUMvQixNQUFNUyxXQUFXbHBCLEtBQUtvWSxLQUFLOVEsS0FBSzdILFFBQVEwcEIsY0FBYyxJQUFJRjtRQUMxRCxNQUFNUCxNQUFNVSxhQUFhRixVQUFVO1lBQUVHLFVBQVU7O1FBQy9DLE9BQU9aLE1BQU0sMkJBQTJCQyxNQUFNQTtBQUNoRDs7O01DM0RXWTtJQUNYLFdBQUF2c0IsQ0FDbUJ3c0IsS0FDQTlwQjtRQURBNkgsS0FBQWlpQixNQUFBQTtRQUNBamlCLEtBQUE3SCxVQUFBQTtBQUNoQjtJQUVLLGNBQUErcEI7UUFDTixNQUFNbG1CLGNBQWNnRSxLQUFLN0gsUUFBUU8sT0FDN0JzSCxLQUFLN0gsUUFBUTZELGNBQ2IsS0FDQSxvQkFBb0JnRSxLQUFLN0gsUUFBUWdxQiw4Q0FDakMsWUFBWW5pQixLQUFLN0gsUUFBUWlxQiwyQ0FDekJwaUIsS0FBSzdILFFBQVE2RDtRQUVqQixNQUFNb0QsVUFBUyxJQUFJaWpCLGlCQUNoQkMsU0FBU3RpQixLQUFLN0gsUUFBUW1vQixPQUN0QmlDLGVBQWV2bUIsYUFDZndtQixXQUFXeGlCLEtBQUs3SCxRQUFRb29CLFdBQVcsU0FDbkNrQyxjQUFjemlCLEtBQUs3SCxRQUFRdWEsUUFBUTJOLHFCQUFxQjNOLE1BQ3hEbEs7UUFFSCxPQUFPa2EsY0FBY1IsZUFBZWxpQixLQUFLaWlCLEtBQUs3aUIsUUFBUTtZQUNwRG1RLGFBQWF2UCxLQUFLN0gsUUFBUW9YLGVBQWU7O0FBRTdDO0lBRVEsb0JBQUFvVCxDQUNOanFCLE1BQ0FrcUIsYUFDQUM7UUFFQSxLQUFLbnFCLE1BQU07UUFFWCxNQUFNb3FCLGNBQWM5aUIsS0FBS2lpQixJQUFJYztRQUM3QnJxQixPQUFPQSxLQUFLOEMsV0FBVyxPQUFPOUMsT0FBTyxJQUFJQTtRQUN6Q29xQixZQUFZdGlCLElBQUk5SCxNQUFNLENBQUNzcUIsTUFBV2hiO1lBQ2hDOGEsWUFBWUcsTUFBTWpiLEtBQUs2YSxlQUFlLEtBQUs7Z0JBQ3pDLGdCQUFnQkQ7OztBQUd0QjtJQUVPLFlBQUFNO1FBQ0wsTUFBTUMsV0FBV25qQixLQUFLa2lCO1FBQ3RCLE1BQU1rQixZQUFZLElBQUlyQyxnQkFBZ0I7WUFDcENULE9BQU90Z0IsS0FBSzdILFFBQVFtb0I7WUFDcEI1bkIsTUFBTXNILEtBQUs3SCxRQUFRTyxRQUFRMm5CLHFCQUFxQjNuQjtZQUNoRG1vQixzQkFBc0I3Z0IsS0FBSzdILFFBQVEwb0Isd0JBQXdCO1lBQzNEZ0IsWUFBWTdoQixLQUFLN0gsUUFBUTBwQjtZQUN6Qk4sYUFBYXZoQixLQUFLN0gsUUFBUXFvQjtZQUMxQlUsZ0JBQWdCbGhCLEtBQUs3SCxRQUFRc29CO1lBQzdCSyxlQUFlOWdCLEtBQUs3SCxRQUFRMm9COztRQUU5QjRCLGNBQWNXLE1BQ1pyakIsS0FBSzdILFFBQVFPLFFBQVEybkIscUJBQXFCM25CLE1BQzFDc0gsS0FBS2lpQixLQUNMa0IsVUFDQTtlQUNLQyxVQUFVL0I7WUFDYmlDLGlCQUFpQnRqQixLQUFLN0gsUUFBUWdxQixrQkFDMUIsR0FBR25pQixLQUFLN0gsUUFBUWdxQixvQkFDaEJscUI7WUFDSnNyQixpQkFBaUJ2akIsS0FBSzdILFFBQVFpcUIsa0JBQzFCLEdBQUdwaUIsS0FBSzdILFFBQVFpcUIsb0JBQ2hCbnFCOztRQUlSK0gsS0FBSzJpQixxQkFDSDNpQixLQUFLN0gsUUFBUWdxQixpQkFDYixvQkFDQSxNQUFNZ0I7UUFHUm5qQixLQUFLMmlCLHFCQUNIM2lCLEtBQUs3SCxRQUFRaXFCLGlCQUNiLHNCQUNBLE1BQU1vQixLQUFLaGQsVUFBVTJjO0FBRXpCOzs7TUNnQldNO0lBY0gsaUJBQVc5Z0I7UUFDakIsS0FBSzNDLEtBQUswakIsU0FBUztZQUVqQjFqQixLQUFLMGpCLFVBQVUsSUFBSUMsT0FBTztBQUM1QjtRQUNBLE9BQU8zakIsS0FBSzBqQjtBQUNkO0lBYUEsaUJBQU9FLENBQVczQjtRQUNoQmppQixLQUFLaWlCLE1BQU1BO1FBQ1gsT0FBT2ppQjtBQUNUO0lBY0EsbUJBQU82akIsQ0FBYUM7UUFDbEI5akIsS0FBSzBqQixVQUFVSSxnQkFBZ0IsSUFBSUgsT0FBTztRQUMxQzNqQixLQUFLaWlCLElBQUk4QixVQUFVL2pCLEtBQUswakI7UUFDeEIsT0FBTzFqQjtBQUNUO0lBZ0JBLGlCQUFPZ2tCLENBQ0xDLFVBQTBCLElBQzFCQyxlQUF5QixFQUFDLE9BQU8sUUFBUSxPQUFPO1FBRWhELE1BQU1DLGlCQUNKRixZQUFZLE1BQU0sTUFBTUEsUUFBUTNzQixJQUFLOHNCLEtBQU1BLEVBQUVyYSxPQUFPc2E7UUFFdEQsTUFBTUMsY0FBMkI7WUFDL0JDLFFBQVEsQ0FBQ0EsUUFBUUM7Z0JBRWYsS0FBS0QsUUFBUSxPQUFPQyxTQUFTLE1BQU07Z0JBRW5DLElBQ0VMLG1CQUFtQixPQUNsQnZ1QixNQUFNQyxRQUFRc3VCLG1CQUNiQSxlQUFlbHZCLFNBQVNzdkIsT0FBT0YsZ0JBQ2pDO29CQUNBLE9BQU9HLFNBQVMsTUFBTTtBQUN4QjtnQkFFQUEsU0FBUyxJQUFJNUYsVUFBVSxVQUFVMkY7O1lBRW5DRSxhQUFhO1lBQ2JDLFNBQVNSLGFBQWFwVCxLQUFLOztRQUc3QjlRLEtBQUtpaUIsSUFBSStCLFdBQVdNO1FBQ3BCLE9BQU90a0I7QUFDVDtJQWNBLGdCQUFPMmtCLENBQVV4c0I7UUFDZjtZQUVFLE1BQU15c0IsU0FBU0MsUUFBUTtZQUN2QjdrQixLQUFLaWlCLElBQUk2QyxJQUFJRixPQUFPenNCO1lBQ3BCNkgsS0FBSzJDLE9BQU9uQixJQUFJO0FBRWxCLFVBQUUsT0FBT2Y7WUFDUFQsS0FBSzJDLE9BQU9vaUIsS0FBSztBQUNuQjtRQUVBLE9BQU8va0I7QUFDVDtJQWNBLG1CQUFPa2pCLENBQWEvcUI7UUFDbEIsTUFBTTZzQixVQUFVLElBQUloRCxlQUFlaGlCLEtBQUtpaUIsS0FBSztZQUMzQzNCLE9BQU9ub0IsUUFBUW1vQjtZQUNmdGtCLGFBQWE3RCxRQUFRNkQ7WUFDckJ1a0IsU0FBU3BvQixRQUFRb29CO1lBQ2pCN25CLE1BQU1QLFFBQVFPLFFBQVE7WUFDdEJtb0Isc0JBQXNCMW9CLFFBQVEwb0Isd0JBQXdCO1lBQ3REZ0IsWUFBWTFwQixRQUFRMHBCO1lBQ3BCckIsaUJBQWlCcm9CLFFBQVFvcEI7WUFDekJkLG9CQUFvQnRvQixRQUFRK29CO1lBQzVCSixlQUFlM29CLFFBQVEyb0I7WUFDdkJxQixpQkFBaUJocUIsUUFBUWdxQjtZQUN6QkMsaUJBQWlCanFCLFFBQVFpcUI7O1FBRTNCNEMsUUFBUTlCO1FBQ1IsT0FBT2xqQjtBQUNUO0lBY0EscUJBQU9pbEIsSUFBa0JDO1FBQ3ZCLElBQUlBLE1BQU10dEIsU0FBUyxHQUFHb0ksS0FBS2lpQixJQUFJZ0Qsa0JBQWtCQztRQUNqRCxPQUFPbGxCO0FBQ1Q7SUFhQSx1QkFBT21sQixJQUFvQkM7UUFDekJwbEIsS0FBS2lpQixJQUFJa0Qsb0JBQ0hDLFFBQVF4dEIsU0FBUyxJQUFJd3RCLFVBQVUsRUFBQyxJQUFJbkc7UUFFMUMsT0FBT2pmO0FBQ1Q7SUFjQSw0QkFBT3FsQixJQUF5QkM7UUFDOUIsSUFBSUEsYUFBYTF0QixTQUFTLEdBQ3hCb0ksS0FBS2lpQixJQUFJb0QseUJBQXlCQztRQUNwQyxPQUFPdGxCO0FBQ1Q7SUFnQkEsa0JBQWF1bEIsQ0FDWEMsT0FBZXRuQixPQUFPdW5CLFFBQVFuRyxJQUFJb0csU0FBUyxLQUMzQ3ZHLE9BQTJCbG5CLFdBQzNCdUosTUFBZTtRQUVmeEIsS0FBS2lpQixJQUFJMEQsT0FBT0gsTUFBTXJHLE1BQWF5RyxLQUFLeGY7WUFDdEMsSUFBSTVFLEtBQUs7Z0JBQ1AsTUFBTStILFlBQVl2SixLQUFLaWlCLElBQUk0RDtnQkFDM0I3bEIsS0FBSzJDLE9BQU9uQixJQUFJLGlDQUFpQytIO0FBQ25EOztBQUVKOzs7QUNoVUYsTUFBTXVjLG1CQUFtQixJQUFJOVo7O1NBUWIrWjtJQUNkLE9BQU9ud0IsTUFBTXNOLEtBQUs0aUIsaUJBQWlCMXVCO0FBQ3JDOztBQUVBLFNBQVM0dUIsaUJBQWlCQyxPQUFlN0s7SUFDdkMsSUFBSTBLLGlCQUFpQmxZLElBQUlxWSxRQUFRO0lBQ2pDSCxpQkFBaUI1bUIsSUFBSSttQixPQUFPO1FBQUU1YixTQUFTNGI7UUFBTzdLOztBQUNoRDs7QUFFQSxTQUFTOEssbUJBQW1CdnhCO0lBQzFCLGNBQWNBLFVBQVUsY0FBY0EsTUFBTTRCLHFCQUFxQnNXO0FBQ25FOztBQUVBLFNBQVNzWixrQkFBa0I3aUI7SUFDekIsT0FBTyxHQUFHQSxNQUFNdkg7QUFDbEI7O0FBRUEsU0FBU3FxQixxQkFDUDlpQixPQUNBUDtJQUVBLE9BQU9BLFVBQVUsR0FBR08sTUFBTXZILGtCQUFrQmdILFlBQVksR0FBR08sTUFBTXZIO0FBQ25FOztBQWNNLFNBQVUwUCxRQUFRblg7SUFDdEIsT0FBTyxDQUNMRCxRQUNBVSxhQUNBc3hCO1FBRUEsSUFBSUMsV0FBa0RoeUI7UUFDdEQsV0FBV2d5QixhQUFhLGFBQWE7WUFDbkMsTUFBTUMsYUFDSjl4QixRQUFRQyxZQUFZLHFCQUFxQkwsV0FBVztZQUN0RGl5QixXQUFXQyxXQUFXRjtBQUN4QjtRQUNBLFdBQVdDLGFBQWEsYUFBYTtZQUNuQyxNQUFNLElBQUluaUIsTUFDUixrRUFBa0VraUIscUJBQXNCaHlCLE9BQTRCMEg7QUFFeEg7UUFFQSxNQUFNeXFCLGlCQUFpQkYsYUFBYSxZQUFZSixtQkFBbUJJO1FBQ25FLE1BQU1MLFFBQVFPLFVBQ1ZMLGtCQUFrQkcsWUFDbEJHLHFCQUFxQkg7UUFFekJOLGlCQUFpQkMsT0FBTztZQUN0QixJQUFJTyxTQUFTLE9BQU92Z0IsYUFBYTJGLFNBQVMwYTtZQUMxQyxjQUFjQSxhQUFhLFdBQ3ZCSSxVQUFZbG1CLElBQUk4bEIsWUFDaEJJLFVBQVlsbUIsSUFBSThsQjs7UUFHdEIsT0FBT3JsQixPQUFPZ2xCLE1BQVBobEIsQ0FBYzVNLFFBQVFVLGFBQWFzeEI7O0FBRTlDOztBQVVNLFNBQVUxYSxXQUNkckksT0FDQVA7SUFFQSxPQUFPLENBQ0wxTyxRQUNBVSxhQUNBc3hCO1FBRUEsTUFBTUosUUFBUUcscUJBQXFCOWlCLE9BQU9QO1FBQzFDaWpCLGlCQUFpQkMsT0FBTyxNQUFNVSxhQUFlL2EsU0FBU3RJLE9BQU9QO1FBQzdELE9BQU85QixPQUFPZ2xCLE1BQVBobEIsQ0FBYzVNLFFBQVFVLGFBQWFzeEI7O0FBRTlDOzs7O0FDcEZPLElBQU1PLGtCQUFOLE1BQU1BOzs7O0lBT0Qsc0JBQVc3Z0I7UUFDbkIsS0FBSy9GLEtBQUt3TCxjQUNSLE1BQU0sSUFBSWtELGNBQWM7UUFDMUIsT0FBTzFPLEtBQUt3TDtBQUNkO0lBRVUsY0FBV2hLO1FBQ25CLEtBQUt4QixLQUFLMGpCLFNBQVMxakIsS0FBSzBqQixVQUFVamlCLFFBQVFDLElBQUltbEI7UUFDOUMsT0FBTzdtQixLQUFLMGpCO0FBQ2Q7SUFFQSxXQUFBanVCLENBRW1CMEMsU0FDQTJ1QjtRQURBOW1CLEtBQUE3SCxVQUFBQTtRQUNBNkgsS0FBQThtQixZQUFBQTtBQUNoQjtJQUVILGNBQU8zYyxDQUFRaFM7UUFDYixNQUFNcUosTUFBTXhCLEtBQUt3QixJQUFJRSxJQUFJMUIsS0FBS21LO1FBQzlCLE1BQU00YyxpQkFBaUJoQjtRQUN2QixPQUFPO1lBQ0xyYixRQUFRbWM7WUFDUnpjLFdBQVcsRUFDVDtnQkFBRUMsU0FBUy9MO2dCQUFzQjBvQixVQUFVN3VCO2VBQzNDO2dCQUFFa1MsU0FBUzlMO2dCQUFrQnlvQixVQUFVaG5CLEtBQUsrRixhQUFha2hCO2VBQ3pEO2dCQUNFNWMsU0FBUzNMO2dCQUNUMGMsWUFBWSxNQUNWampCLFFBQVEyUyxVQUFVeFQsSUFBSzR2QjtvQkFDckIxbEIsSUFBSXVSLEtBQUssK0JBQStCbVUsRUFBRW5yQjtvQkFDMUMsT0FBTyxJQUFJbXJCO3NCQUNQO2VBRVZ2bkIscUJBQ0FnSyxzQkFDQTtnQkFDRVUsU0FBU0M7Z0JBQ1RDLFVBQVUzQjtrQkFFVG1lO1lBRUxwYyxTQUFTLEVBQ1ByTSxzQkFDQUMsa0JBQ0FHLGdCQUNBaUIscUJBQ0FnSyx5QkFDR29kLGVBQWV6dkIsSUFBSzZ2QixZQUFhQSxTQUFTOWM7O0FBR25EO0lBRUEsNEJBQWErYyxDQUNYanZCO1FBRUEsTUFBTXFKLE1BQU14QixLQUFLd0IsSUFBSUUsSUFBSTFCLEtBQUtvbkI7UUFFOUIsS0FBS3BuQixLQUFLd0wsY0FBYztZQUN0QixNQUFNNmIsVUFBVWx2QixRQUFRbXZCLEtBQUtod0IsSUFBSSxFQUFFaXdCLE9BQU9uTCxRQUFRcFc7Z0JBQ2hELE1BQU13aEIsV0FBV3hoQixLQUFLa1U7Z0JBQ3RCLEtBQUtzTixVQUFVLE9BQU8sRUFBQ0QsT0FBT25MO2dCQUM5QixPQUFPLEVBQUNtTCxPQUFPbkwsUUFBUXBXOztZQUV6QmhHLEtBQUt3TCxlQUFlLElBQUlpYztrQkFDbEJ6bkIsS0FBS3dMLGFBQWFrYyxLQUFLTDtZQUM3QixNQUFNTSxVQUFVM25CLEtBQUt3TCxhQUFheWI7WUFDbEMsS0FBSyxJQUFJelAsSUFBSSxHQUFHQSxJQUFJbVEsUUFBUS92QixRQUFRNGYsS0FBSztnQkFDdkMsTUFBTW9RLElBQUl6dkIsUUFBUW12QixLQUFLOVA7Z0JBQ3ZCLE1BQU1xUSxpQkFBaUJELEVBQUVyakIsTUFBTSxHQUFHcWpCLEVBQUVod0I7Z0JBQ3BDLElBQUlvTCxjQUFjNmtCLGVBQWUzTjtnQkFDakMsS0FDR2xYLGdCQUNDQSxZQUFpREUsTUFDbkQ7b0JBQ0EsTUFBTXFrQixRQUFRMWtCLFFBQVFJLGVBQWUwa0IsUUFBUW5RLEdBQUd6VTtvQkFDaEQsS0FBS3drQixPQUNILE1BQU0sSUFBSTdZLGNBQ1Isb0NBQW9DaVosUUFBUW5RLEdBQUd6VTtvQkFFbkQ7d0JBQ0VDLGNBQWV1a0IsTUFBMkNya0IsT0FDdERxa0IsUUFDQSxJQUFLQTtBQUNYLHNCQUFFLE9BQU85bUI7d0JBQ1AsTUFBTSxJQUFJaU8sY0FDUixrQ0FBa0NpWixRQUFRblEsR0FBR3pVLFlBQVl0QztBQUU3RDtBQUNGO2dCQUNBcW5CLDRCQUE0QkgsUUFBUW5RLEdBQUd6VSxRQUF2QytrQixDQUFnRDlrQjtBQUNsRDtZQUNBeEIsSUFBSXVSLEtBQUs7WUFFVCxJQUFJNWEsUUFBUTR2QixnQkFBZ0I7Z0JBQzFCOzBCQUNRNXZCLFFBQVE0dkI7QUFDaEIsa0JBQUUsT0FBT3RuQjtvQkFDUCxNQUFNLElBQUlpTyxjQUFjLHFDQUFxQ2pPO0FBQy9EO0FBQ0Y7QUFDRjtRQUVBLE9BQU9ULEtBQUsrRixZQUFZa2hCO0FBQzFCO0lBRUEsMkJBQU1lO1FBQ0osTUFBTXhtQixNQUFNcWxCLGtCQUFnQnJsQixJQUFJRSxJQUFJMUIsS0FBS2dvQjtRQUN6QyxNQUFNQyxXQUNKam9CLEtBQUs4bUIsVUFBVXRtQixJQUFTakM7UUFDMUIsS0FBSyxNQUFNa0osV0FBV3dnQixVQUNwQjtZQUNFLElBQUl4Z0IsU0FBUztnQkFDWGpHLElBQUl1UixLQUFLLGlCQUFpQnRMLFFBQVFsUTtzQkFDNUJrUSxRQUFReWdCO0FBQ2hCO0FBQ0YsVUFBRSxPQUFPem5CO1lBQ1BlLElBQUlrRixNQUFNLGtDQUFrQ2pHO0FBQzlDO1FBQ0Y7a0JBQ1FnTCxVQUFReWM7QUFDaEIsVUFBRSxPQUFPem5CO1lBQ1BlLElBQUlrRixNQUFNLCtCQUErQmpHO0FBQzNDO0FBQ0Y7OztBQWxJV21tQixrQkFBZUMsb0JBQUFsbUIsV0FBQSxFQUYzQnduQixVQUNBdmQsT0FBTyxDQUFBLElBb0JINUosUUFBQSxHQUFBQyxPQUFPM0Msa0VBRW9COHBCLGdCQXJCbkJ4Qjs7QUM5Qk4sTUFBTXlCLDhCQUE4QjFwQixPQUN6Qzs7QUNDSSxTQUFVMnBCLHVCQUF1QnRpQjtJQUNyQyxPQUFPdWlCLGFBQWFqZixXQUFXK08sSUFBSUksV0FBV3pTO0lBRTlDLE1BQU1sRSxZQUFZeW1CLGFBQWF4c0IsUUFBUXdzQjtJQUV2QyxNQUFNQyxvQkFBb0I1eUIsTUFBTUMsUUFBUTRpQixXQUNwQ0EsUUFBUW5oQixJQUFLbUo7UUFDWDtZQUNFLFdBQVdBLEVBQUVnb0IsY0FBYyxZQUFZLE9BQU9ob0IsRUFBRWdvQjtZQUVoREMsUUFBUTNELEtBQ04sb0JBQW9CampCLDZEQUE2RHJCLDhDQUE4Q0E7WUFFakksY0FBY0EsTUFBTSxXQUFXQSxJQUFJOEYsS0FBS0MsVUFBVS9GO0FBQ3BELFVBQUUsT0FBT2tvQjtZQUNQRCxRQUFRM0QsS0FBSyxtQ0FBbUNqakIsY0FBYzZtQjtZQUM5RCxPQUFPMXdCO0FBQ1Q7U0FFRndnQixrQkFBa0JBLFFBQVFnUSxjQUFjLGFBQ3RDaFEsUUFBUWdRLHFCQUNEaFEsWUFBWSxXQUNqQkEsVUFDQWxTLEtBQUtDLFVBQVVpUztJQUV2QmlRLFFBQVF2bUIsTUFDTix1Q0FBdUNMLHdCQUF3QndILGlCQUFpQitPLE9BQ2hGbVE7SUFHRixPQUFPLEVBQUMxbUIsV0FBV3dILFdBQVcrTyxJQUFJbVE7QUFDcEM7Ozs7QUNyQk8sSUFBTUksbUJBQWdCQyxxQkFBdEIsTUFBTUQseUJBQXlCemQ7SUFHcEMsV0FBQTFWLENBQ0U0VixlQUNxQ3JNO1FBRXJDYSxNQUFNd0wsZUFBZXdkLG1CQUFpQjlzQjtRQUN0Q2lFLEtBQUtpb0IsV0FBV2pwQixTQUFTMUgsSUFBS3lMLFdBQWFGLFFBQWdCckMsSUFBSXVDO0FBQ2pFO0lBR0EsTUFBQTRpQjtRQUNFLE1BQU1oakIsU0FBU2xCLFFBQVFDLElBQUltbkIsbUJBQWlCOXNCO1FBRTVDLE1BQU0rc0IsVUFBVSxJQUFJQyxXQUEwQkM7WUFDNUMsTUFBTUMsYUFDSixLQUFLQyxLQUFLQyxTQUFTNXhCLFNBQVMsSUFBSWdOLE1BQU0sR0FBRyxLQUFLNmtCO1lBRWhEem1CLE9BQU9vUSxLQUNMLDBCQUEwQmtXLHlCQUF5QmpwQixLQUFLcUwsY0FBY3BMO1lBRXhFLE1BQU1vcEIsS0FBSyxJQUFBO2dCQUFLLFdBQUE1ekI7b0JBQ2R1SyxLQUFBaXBCLGFBQWFBO0FBYWY7Z0JBWkUsT0FBQUssSUFBV3RqQjtvQkFDVHJELE9BQU9SLE1BQ0wsZ0JBQWdCbkMsS0FBS2lwQjtvQkFFdkIsT0FBT00sUUFBUUMsVUFBVTVELEtBQUs7d0JBQzVCLE1BQU14cEIsT0FBT2tzQix1QkFBdUJ0aUI7d0JBQ3BDZ2pCLFNBQVN6bkIsS0FBSzs0QkFBRS9MLE1BQU07NEJBQVc0Rzs7d0JBQ2pDdUcsT0FBT1IsTUFDTCxnQkFBZ0JuQyxLQUFLaXBCOztBQUczQjs7WUFHRnRtQixPQUFPVCxRQUNMLHdCQUF3QittQixxQkFBcUJqcEIsS0FBS2lvQixTQUFTcndCO1lBRTdELEtBQUssTUFBTTZQLFdBQVd6SCxLQUFLaW9CLFVBQVU7Z0JBQ25DLE1BQU13QixjQUFjaGlCLFNBQVNoUyxhQUFhc0csUUFBUTtnQkFDbEQ7b0JBQ0U0RyxPQUFPUixNQUNMLHdCQUF3QjhtQix5QkFBeUJRO29CQUVuRGhpQixRQUFRaWlCLFFBQVFMO0FBQ2xCLGtCQUFFLE9BQU81b0I7b0JBQ1BrQyxPQUFPUixNQUNMLCtCQUErQjhtQix5QkFBeUJRLGdCQUFnQmhwQixHQUFHa2YsV0FBV2xmO29CQUV4RmtDLE9BQU8rRCxNQUFNakc7QUFDZjtBQUNGO1lBRUEsT0FBTztnQkFDTGtDLE9BQU9SLE1BQU0sNEJBQTRCOG1CO2dCQUV6QyxLQUFLLE1BQU14aEIsV0FBV3pILEtBQUtpb0IsVUFBVTtvQkFDbkMsTUFBTXdCLGNBQWNoaUIsU0FBU2hTLGFBQWFzRyxRQUFRO29CQUNsRDt3QkFDRTRHLE9BQU9SLE1BQ0wsMEJBQTBCOG1CLDJCQUEyQlE7d0JBRXZEaGlCLFFBQVFraUIsVUFBVU47QUFDcEIsc0JBQUUsT0FBTzVvQjt3QkFDUGtDLE9BQU9SLE1BQ0wscUNBQXFDOG1CLHlCQUF5QlEsZ0JBQWdCaHBCLEdBQUdrZixXQUFXbGY7d0JBRTlGa0MsT0FBTytELE1BQU1qRztBQUNmO0FBQ0Y7OztRQUlKLE1BQU1tcEIsd0JBQXdCO1FBQzlCLE1BQU1DLGFBQWFDLFNBQVNGLHVCQUF1QjNlLEtBQ2pEQyxNQUFJO1lBQ0Z2SSxPQUFPUixNQUFNO1lBRWY3SyxJQUNFLE9BQUE7WUFDRTlCLE1BQU07WUFDTjRHLE1BQU07Z0JBQ0oydEIsS0FBSSxJQUFJMWdCLE1BQU8yVzs7O1FBTXZCLE9BQU9nSyxNQUFNbEIsU0FBU2U7QUFDeEI7SUFJQSxjQUFBSSxDQUErQjNtQjtRQUM3QixNQUFNWCxTQUFTbEIsUUFBUUMsSUFBSW1uQixtQkFBaUI5c0I7UUFFNUMsT0FBTyxJQUFJZ3RCLFdBQTBCQztZQUNuQyxNQUFNSyxLQUFLLElBQUE7Z0JBQ1QsT0FBQUMsSUFBV3RqQjtvQkFDVCxPQUFPdWpCLFFBQVFDLFVBQVU1RCxLQUFLO3dCQUM1Qm9ELFNBQVN6bkIsS0FBSzs0QkFBRW5GLE1BQU00Sjs7O0FBRTFCOztZQUdGO2dCQUNFLEtBQUssTUFBTXlCLFdBQVd6SCxLQUFLaW9CLFVBQVU7b0JBQ25DeGdCLFFBQVFpaUIsUUFBUUw7QUFDbEI7QUFDRixjQUFFLE9BQU81b0I7Z0JBQ1B1b0IsU0FBU3RpQixNQUFNLDRCQUE0QmpHLEVBQUVrZixXQUFXbGY7QUFDMUQ7WUFFQSxPQUFPO2dCQUNMO29CQUNFLEtBQUssTUFBTWdILFdBQVd6SCxLQUFLaW9CLFVBQVU7d0JBQ25DeGdCLFFBQVFraUIsVUFBVU47QUFDcEI7QUFDRixrQkFBRSxPQUFPNW9CO29CQUNQa0MsT0FBTytELE1BQU1qRztBQUNmOzs7QUFHTjs7O0FBbEhBRSxXQUFBLEVBREN1cEIsaUhBQ1NuQixlQWdGVEgsaUJBQUFyeUIsV0FBQSxVQUFBOztBQUlEb0ssV0FBQSxFQUZDdXBCLElBQUksWUFFV2xwQixRQUFBLEdBQUF3RSxNQUFNLDZIQUF5QnVqQixlQThCOUNILGlCQUFBcnlCLFdBQUEsa0JBQUE7O0FBOUhVcXlCLG1CQUFnQkMscUJBQUFsb0IsV0FBQSxFQUQ1QnFTLGNBTUloUyxRQUFBLEdBQUFDLE9BQU9vbkIsaUVBRE8xb0IscUJBQW1CL0osWUFKekJnekI7Ozs7QUNMTixJQUFNdUIsb0JBQWlCQyxzQkFBdkIsTUFBTUQ7SUFDWCxrQkFBT0UsQ0FDTHJyQixVQUNBdEcsT0FBZTtRQUVmLE9BQU87WUFDTGdTLFFBQVEwZjtZQUNSdk8sYUFBYSxFQUFDK007WUFDZDBCLFNBQVMsRUFDUEMsYUFBYUMsU0FBUyxFQUNwQjtnQkFDRTl4QixNQUFNQSxLQUFLOEIsUUFBUSxPQUFPO2dCQUMxQmtRLFFBQVEwZjs7WUFJZGhnQixXQUFXLEVBQ1R6SyxxQkFDQTtnQkFDRTBLLFNBQVNnZTtnQkFDVHJCLFVBQVVob0IsWUFBWTs7O0FBSTlCOzs7QUF4QldtckIsb0JBQWlCQyxzQkFBQXpwQixXQUFBLEVBRDdCaUssT0FBTyxDQUFBLE1BQ0t1Zjs7OztBQ0lOLElBQU1NLGNBQVdDLGdCQUFqQixNQUFNRDtJQUNYLHlCQUFhRSxDQUNYeHlCO1FBRUEsT0FBTXl5QixpQkFBRUEsaUJBQWVsUCxjQUFFQSxnQkFBaUJ2akI7UUFFMUMsTUFBTTh2QixpQkFDRXJCLGdCQUFnQlEsZ0JBQWdCanZCO1FBQ3hDLE1BQU02RyxXQUFXaXBCLFNBQVMzd0IsSUFBS21RLFdBQVlBLFFBQVExRTtRQUVuRCxNQUFNdW5CLFVBT1UsRUFBQzFELGdCQUFnQnpjLFFBQVFoUztRQUV6QyxJQUFJeXlCLGlCQUFpQjtZQUNqQjVyQixTQUFTMkcsUUFBUzVDO2dCQUNoQnVuQixRQUFRM21CLEtBQ05vWCxhQUFhaFksU0FBU29ILFFBQVFwSCxTQUFTO29CQUNyQzJZO29CQUNBRixvQkFBb0JyakIsUUFBUXFqQjtvQkFDNUJyYyxrQkFBa0JoSCxRQUFRZ0g7b0JBQzFCd2MsY0FBY3hqQixRQUFRd2pCOzs7QUFJOUI7UUFFRixJQUFJeGpCLFFBQVEweUIsaUJBQWlCQyxzQkFBc0I7WUFDakRSLFFBQVEzbUIsS0FDTndtQixrQkFBa0JFLFlBQ2hCbHlCLFFBQVEweUIsZ0JBQWdCRSxvQkFBb0IvckI7QUFHbEQ7UUFFQSxPQUFPO1lBQ0wwTCxRQUFRZ2dCO1lBQ1JKLFNBQVNBOztBQUViOzs7QUE1Q1dHLGNBQVdDLGdCQUFBL3BCLFdBQUEsRUFEdkJpSyxPQUFPLENBQUEsTUFDSzZmOztBQStDTnJrQixlQUFlNGtCLGlCQUFnQzs7QUN0RGhELFNBQVVDLGFBQWEzbkI7SUFDNUIsTUFBTTRuQixJQUFJcmUsTUFBTXJNLElBQUk4QztJQUNwQixLQUFLNG5CLEdBQ0osTUFBTSxJQUFJeGMsY0FBYyxpQ0FBaUNwTDtJQUMxRCxNQUFNbU4sT0FBTzlFLGFBQVdDLFNBQVNzZjtJQUNqQyxPQUFPemE7QUFDUjs7QUNzQ08sTUFBTTBhLFVBQVU7O0FBUWhCLE1BQU1DLFNBQVM7O0FBUWYsTUFBTUMsZUFBZTs7QUFFckIsTUFBTUMsZUFBZTs7QUFFNUJyc0IsU0FBU3NzQixvQkFBb0I7O0FBQzdCdHNCLFNBQVN1c0IsZ0JBQWdCRixjQUFjSDs7QUFDdkNsc0IsU0FBU3NzQixvQkFBb0I7OyJ9
|