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