@decaf-ts/for-nest 0.12.1 → 0.12.2-0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -4
- package/dist/for-nest.cjs +2610 -2
- package/dist/for-nest.js +2723 -2
- package/lib/cjs/auth/AuthInterceptor.cjs +5 -13
- package/lib/cjs/auth/AuthMiddleware.cjs +51 -0
- package/lib/cjs/auth/DecafAuthHandler.cjs +10 -5
- package/lib/cjs/auth/DecafAuthModule.cjs +8 -3
- package/lib/cjs/auth/constants.cjs +5 -3
- package/lib/cjs/auth/decorators.cjs +6 -2
- package/lib/cjs/auth/index.cjs +3 -2
- package/lib/cjs/bin/cli.cjs +2 -2
- package/lib/cjs/cli-module.cjs +2 -2
- package/lib/cjs/constants.cjs +2 -2
- package/lib/cjs/controllers.cjs +2 -2
- package/lib/cjs/core-module.cjs +2 -2
- package/lib/cjs/decaf-model/DecafModelModule.cjs +2 -2
- package/lib/cjs/decaf-model/FromModelController.cjs +8 -2
- package/lib/cjs/decaf-model/decorators/ApiOperationFromModel.cjs +2 -2
- 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 +2 -2
- package/lib/cjs/decaf-model/decorators/decorators.cjs +2 -2
- package/lib/cjs/decaf-model/decorators/expose.cjs +2 -2
- package/lib/cjs/decaf-model/decorators/index.cjs +2 -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 +2 -2
- 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 +2 -2
- package/lib/cjs/events-module/DecafStreamModule.cjs +15 -4
- package/lib/cjs/events-module/EventsController.cjs +30 -7
- package/lib/cjs/events-module/EventsSubscriptionController.cjs +81 -0
- package/lib/cjs/events-module/ObserverSubscriptionRegistry.cjs +51 -0
- package/lib/cjs/events-module/constant.cjs +4 -3
- package/lib/cjs/events-module/index.cjs +5 -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 +2 -2
- 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 +5 -5
- package/lib/cjs/interceptors/DecafRequestHandlerInterceptor.cjs +5 -33
- package/lib/cjs/interceptors/index.cjs +2 -2
- package/lib/cjs/module.cjs +3 -3
- 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 +2 -2
- package/lib/cjs/overrides/logging.cjs +2 -2
- package/lib/cjs/overrides/overrides.cjs +2 -2
- package/lib/cjs/request/DecafAuthHandler.cjs +2 -2
- package/lib/cjs/request/DecafHandlerExecutor.cjs +2 -2
- package/lib/cjs/request/DecafRequestContext.cjs +2 -2
- package/lib/cjs/request/DecafResponseInterceptor.cjs +2 -2
- package/lib/cjs/request/contextualize.cjs +46 -0
- package/lib/cjs/request/index.cjs +3 -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 +2 -2
- package/lib/cjs/webhooks/controllers.cjs +2 -2
- package/lib/cjs/webhooks/index.cjs +2 -2
- package/lib/cjs/webhooks/types.cjs +2 -2
- package/lib/esm/auth/AuthInterceptor.js +5 -13
- package/lib/esm/auth/AuthMiddleware.js +42 -0
- package/lib/esm/auth/DecafAuthHandler.js +9 -4
- package/lib/esm/auth/DecafAuthModule.js +8 -3
- package/lib/esm/auth/constants.js +3 -1
- package/lib/esm/auth/decorators.js +5 -2
- package/lib/esm/auth/index.js +2 -1
- package/lib/esm/bin/cli.js +1 -1
- package/lib/esm/cli-module.js +1 -1
- package/lib/esm/constants.js +1 -1
- package/lib/esm/controllers.js +1 -1
- package/lib/esm/core-module.js +1 -1
- package/lib/esm/decaf-model/DecafModelModule.js +1 -1
- package/lib/esm/decaf-model/FromModelController.js +9 -3
- package/lib/esm/decaf-model/decorators/ApiOperationFromModel.js +1 -1
- 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 +1 -1
- package/lib/esm/decaf-model/decorators/decorators.js +1 -1
- package/lib/esm/decaf-model/decorators/expose.js +1 -1
- package/lib/esm/decaf-model/decorators/index.js +1 -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 +1 -1
- 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 +1 -1
- package/lib/esm/events-module/DecafStreamModule.js +15 -4
- package/lib/esm/events-module/EventsController.js +31 -8
- package/lib/esm/events-module/EventsSubscriptionController.js +72 -0
- package/lib/esm/events-module/ObserverSubscriptionRegistry.js +43 -0
- package/lib/esm/events-module/constant.js +2 -1
- package/lib/esm/events-module/index.js +4 -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 +1 -1
- 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 +4 -4
- package/lib/esm/interceptors/DecafRequestHandlerInterceptor.js +4 -32
- package/lib/esm/interceptors/index.js +1 -1
- package/lib/esm/module.js +2 -2
- 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 +1 -1
- package/lib/esm/overrides/logging.js +1 -1
- package/lib/esm/overrides/overrides.js +1 -1
- package/lib/esm/request/DecafAuthHandler.js +1 -1
- package/lib/esm/request/DecafHandlerExecutor.js +1 -1
- package/lib/esm/request/DecafRequestContext.js +1 -1
- package/lib/esm/request/DecafResponseInterceptor.js +1 -1
- package/lib/esm/request/contextualize.js +42 -0
- package/lib/esm/request/index.js +2 -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 +1 -1
- package/lib/esm/webhooks/controllers.js +1 -1
- package/lib/esm/webhooks/index.js +1 -1
- package/lib/esm/webhooks/types.js +1 -1
- package/lib/types/auth/AuthMiddleware.d.cts +9 -0
- package/lib/types/auth/AuthMiddleware.d.mts +9 -0
- package/lib/types/auth/DecafAuthHandler.d.cts +6 -4
- package/lib/types/auth/DecafAuthHandler.d.mts +6 -4
- package/lib/types/auth/DecafAuthModule.d.cts +3 -2
- package/lib/types/auth/DecafAuthModule.d.mts +3 -2
- package/lib/types/auth/constants.d.cts +2 -0
- package/lib/types/auth/constants.d.mts +2 -0
- package/lib/types/auth/decorators.d.cts +1 -0
- package/lib/types/auth/decorators.d.mts +1 -0
- package/lib/types/auth/index.d.cts +1 -0
- package/lib/types/auth/index.d.mts +1 -0
- package/lib/types/events-module/DecafStreamModule.d.cts +2 -1
- package/lib/types/events-module/DecafStreamModule.d.mts +2 -1
- package/lib/types/events-module/EventsController.d.cts +6 -2
- package/lib/types/events-module/EventsController.d.mts +6 -2
- package/lib/types/events-module/EventsSubscriptionController.d.cts +17 -0
- package/lib/types/events-module/EventsSubscriptionController.d.mts +17 -0
- package/lib/types/events-module/ObserverSubscriptionRegistry.d.cts +13 -0
- package/lib/types/events-module/ObserverSubscriptionRegistry.d.mts +13 -0
- package/lib/types/events-module/constant.d.cts +1 -0
- package/lib/types/events-module/constant.d.mts +1 -0
- package/lib/types/events-module/index.d.cts +3 -0
- package/lib/types/events-module/index.d.mts +3 -0
- package/lib/types/index.d.cts +3 -3
- package/lib/types/index.d.mts +3 -3
- package/lib/types/request/contextualize.d.cts +2 -0
- package/lib/types/request/contextualize.d.mts +2 -0
- package/lib/types/request/index.d.cts +1 -0
- package/lib/types/request/index.d.mts +1 -0
- package/lib/types/types.d.cts +7 -2
- package/lib/types/types.d.mts +7 -2
- package/package.json +1 -1
- package/dist/for-nest.cjs.map +0 -1
- package/dist/for-nest.js.map +0 -1
- package/lib/cjs/auth/AuthInterceptor.cjs.map +0 -1
- package/lib/cjs/auth/DecafAuthHandler.cjs.map +0 -1
- package/lib/cjs/auth/DecafAuthModule.cjs.map +0 -1
- package/lib/cjs/auth/constants.cjs.map +0 -1
- package/lib/cjs/auth/decorators.cjs.map +0 -1
- package/lib/cjs/auth/index.cjs.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/controller-config.cjs.map +0 -1
- package/lib/cjs/decaf-model/decorators/decorators.cjs.map +0 -1
- package/lib/cjs/decaf-model/decorators/expose.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/decorators.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/DecafRequestHandlerInterceptor.cjs.map +0 -1
- package/lib/cjs/interceptors/index.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/logging.cjs.map +0 -1
- package/lib/cjs/overrides/overrides.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/auth/AuthInterceptor.js.map +0 -1
- package/lib/esm/auth/DecafAuthHandler.js.map +0 -1
- package/lib/esm/auth/DecafAuthModule.js.map +0 -1
- package/lib/esm/auth/constants.js.map +0 -1
- package/lib/esm/auth/decorators.js.map +0 -1
- package/lib/esm/auth/index.js.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/controller-config.js.map +0 -1
- package/lib/esm/decaf-model/decorators/decorators.js.map +0 -1
- package/lib/esm/decaf-model/decorators/expose.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/decorators.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/DecafRequestHandlerInterceptor.js.map +0 -1
- package/lib/esm/interceptors/index.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/logging.js.map +0 -1
- package/lib/esm/overrides/overrides.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/dist/for-nest.cjs
CHANGED
|
@@ -1,2 +1,2610 @@
|
|
|
1
|
-
var e,t;e=this,t=function(e,t,r,o,a,s,n,i,c,p,d,l,u,f,h,m,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 E=A(m);const b="swagger",P={API_OPERATION:b+"/apiOperation",API_RESPONSE:b+"/apiResponse",API_PRODUCES:b+"/apiProduces",API_CONSUMES:b+"/apiConsumes",API_TAGS:b+"/apiUseTags",API_CALLBACKS:b+"/apiCallbacks",API_PARAMETERS:b+"/apiParameters",API_HEADERS:b+"/apiHeaders",API_MODEL_PROPERTIES:b+"/apiModelProperties",API_MODEL_PROPERTIES_ARRAY:b+"/apiModelPropertiesArray",API_SECURITY:b+"/apiSecurity",API_EXCLUDE_ENDPOINT:b+"/apiExcludeEndpoint",API_EXCLUDE_CONTROLLER:b+"/apiExcludeController",API_EXTRA_MODELS:b+"/apiExtraModels",API_EXTENSION:b+"/apiExtension",API_SCHEMA:b+"/apiSchema",API_DEFAULT_GETTER:b+"/apiDefaultGetter",API_LINK:b+"/apiLink"},v=e=>void 0===e;function R(e){if("function"==typeof e)return R(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 O(e){return e.filter(n.isString).length>0?"string":"number"}function D(e,t,r=!0){return(o,a)=>{const s=Reflect.getMetadata(P.API_MODEL_PROPERTIES_ARRAY,o)||[],i=":"+a;s.includes(i)||Reflect.defineMetadata(P.API_MODEL_PROPERTIES_ARRAY,[...s,":"+a],o);const c=Reflect.getMetadata(e,o,a);if(c){const s=n.pickBy(t,n.negate(v)),i=r?{...c,...s}:{...s,...c};Reflect.defineMetadata(e,i,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,...n.pickBy(t,n.negate(v))},o,a)}}}function S(e={}){return _(e)}function _(e={},t=!0){const[r,o]=((e,t)=>{if(!e)return[e,t];if(t)return[e,t];const r=n.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=R(e.enum);e.items={type:O(t),enum:t},delete e.enum}else if("enum"in e&&void 0!==e.enum){const t=R(e.enum);e.enum=t,e.type=O(t)}var a;return Array.isArray(e.type)&&(e.type="array",e.items={type:"array",items:{type:e.type[0]}}),D(P.API_MODEL_PROPERTIES,e,t)}function C(e,r,a){const n={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]},[p,d]=n[r],l=T(r,a);return l?s.isOperationBlocked(e,l.kind,l.value)?t.apply(i.ApiExcludeEndpoint()):t.apply(d(a)):s.isOperationBlocked(e,p)?t.apply(i.ApiExcludeEndpoint()):t.apply(d(a))}function T(e,t){if(!t)return;const r=t.replace(/^\/+|\/+$/g,""),o={"listBy/:key":s.PreparedStatementKeys.LIST_BY,"paginateBy/:key/:page":s.PreparedStatementKeys.PAGE_BY,"find/:value":s.PreparedStatementKeys.FIND,"page/:value":s.PreparedStatementKeys.PAGE,"findOneBy/:key/:value":s.PreparedStatementKeys.FIND_ONE_BY,"findBy/:key/:value":s.PreparedStatementKeys.FIND_BY,"statement/:method/*args":"statement","countOf/:field":s.PreparedStatementKeys.COUNT_OF,"maxOf/:field":s.PreparedStatementKeys.MAX_OF,"minOf/:field":s.PreparedStatementKeys.MIN_OF,"avgOf/:field":s.PreparedStatementKeys.AVG_OF,"sumOf/:field":s.PreparedStatementKeys.SUM_OF,"distinctOf/:field":s.PreparedStatementKeys.DISTINCT_OF,"groupOf/:field":s.PreparedStatementKeys.GROUP_OF};if(r.startsWith("query/"))return{kind:"query",value:r.replace(/^query\//,"")};const a=o[r];return a?{kind:"statement",value:a}:"GET"===e&&""===r?{kind:"crud",value:c.OperationKeys.READ}:void 0}function M(e=[]){const t=e.map(e=>i.ApiParam({name:e.name,description:e.description??"Path parameter: "+e.name,required:e.required??!0,type:e.type??String}));return o.applyDecorators(...t)}const x=o.createParamDecorator((e,t)=>{const r=t.switchToHttp().getRequest().body,a=t.getClass(),s=a.class;if(!s)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 s(e)):new s(r):r}),I=o.createParamDecorator((e,t)=>{const r=t.switchToHttp().getRequest(),o=r?.params??{},a=e??Object.keys(o),s=a.map(e=>o[e]);return{raw:o,valuesInOrder:s,keysInOrder:a}});function w(e=[]){const t=e.map(e=>e.name);return I(t)}const q=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}),N="DecafModuleOptions",k="DecafAdapter",F="DecafRoute",$=Symbol("DecafHandlers"),j="DecafExpose",B="DecafControllerConfig",L=Symbol("decaf:context"),U=Symbol("AUTH_HANDLER"),K="auth:meta",H="isPublic",G="requiredRoles",Q="skipModelRoles";function z(t){const r=t?"string"==typeof t?t:t.name:void 0,a=[i.ApiBearerAuth(),o.UseInterceptors(e.AuthInterceptor)];return r&&a.push(o.SetMetadata(K,r)),o.applyDecorators(...a)}function W(){return o.applyDecorators(o.SetMetadata(H,!0))}function Y(...t){return o.applyDecorators(i.ApiSecurity("bearer"),o.SetMetadata(G,t),o.UseInterceptors(e.AuthInterceptor))}function V(e){const t={GET:o.Get,POST:o.Post,PUT:o.Put,PATCH:o.Patch,DELETE:o.Delete}[e];if(!t)throw new s.UnsupportedError(`Unsupported HTTP verb "${e}". No NestJS decorator mapping was found.`);return t}e.DecafRequestContext=class extends u.RequestContext{constructor(e){super({headersOf:e=>e?.headers||void 0},e),this.req=e,this.uuid=s.UUID.instance.generate(),this.request=e}get headers(){return this.getOrUndefined("headers")}put(e){let t;try{t=this.get("overrides")}catch(e){t={}}this.accumulate({overrides:Object.assign(t,e)})}},e.DecafRequestContext=p.__decorate([o.Injectable({scope:o.Scope.REQUEST}),p.__param(0,o.Inject(d.REQUEST)),p.__metadata("design:paramtypes",[Object])],e.DecafRequestContext),e.AuthInterceptor=class{constructor(e,t,r){this.reflector=e,this.requestContext=t,this.authHandler=r}async intercept(e,t){const r=l.Logging.for(this).for(this.intercept),o=this.reflector.getAllAndOverride(H,[e.getHandler(),e.getClass()]),a=this.reflector.get(K,e.getHandler())??this.reflector.get(K,e.getClass()),s=this.reflector.getAllAndOverride(G,[e.getHandler(),e.getClass()]),n=this.reflector.getAllAndOverride(Q,[e.getHandler(),e.getClass()])?void 0:a;r.verbose("Intercepted request"+(a?" for "+a:"")),o?r.debug("Public route \u2014 skipping auth"):this.authHandler?await this.authHandler.authorize(e,n,s,this.requestContext):r.debug("No auth handler registered"),await this.applyTransformers();const i=this.requestContext.getOrUndefined("user"),c=this.requestContext.getOrUndefined("organization");if(i||c){const e=this.requestContext.get("logger").for({user:i,organization:c});this.requestContext.accumulate({logger:e})}return t.handle()}async applyTransformers(){const e=s.Adapter.flavoursToTransform();if(e)for(const t of e){const e=s.Adapter.transformerFor(t);if(!e)continue;const r=e.from?e:new e,o=await r.from(this.requestContext);o&&this.requestContext.accumulate(o)}}},e.AuthInterceptor=p.__decorate([o.Injectable({scope:o.Scope.REQUEST}),p.__param(2,o.Optional()),p.__param(2,o.Inject(U)),p.__metadata("design:paramtypes",[d.Reflector,e.DecafRequestContext,Object])],e.AuthInterceptor);const X=e=>({name:e,description:e+" parameter for the query",required:!0,type:String});function J(e,t,...r){if(e instanceof s.ModelService)return"function"==typeof e[t]?e[t](...r):e.statement(t,...r);if("function"==typeof e[t])return e[t](...r);throw new c.InternalError(`Persistence method "${t}" not found on ${e?.constructor?.name}`)}class Z extends u.AuthHandler{parseRequest(e){const t=e.headers.authorization?.split(" ")[1];return t}extractFromAuth(e){const t=e.switchToHttp().getRequest(),r=this.parseRequest(t);if(!r)throw new s.AuthorizationError("Unauthenticated");return{user:r,roles:[r]}}}var ee,te;e.DecafAuthModule=ee=class{static forRoot(t={}){const r=[e.AuthInterceptor];return t.handler&&(r.push(t.handler),r.push({provide:U,useClass:t.handler})),t.global&&r.push({provide:d.APP_INTERCEPTOR,useExisting:e.AuthInterceptor}),{module:ee,global:t.global??!1,providers:r,exports:[e.AuthInterceptor,U]}}},e.DecafAuthModule=ee=p.__decorate([o.Module({})],e.DecafAuthModule),e.DecafHandlerExecutor=te=class{constructor(e,t){this.handlers=e,this.context=t}async exec(e,t){l.Logging.for(te.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=te=p.__decorate([o.Injectable({scope:o.Scope.REQUEST}),p.__param(0,o.Inject($)),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(f.tap(e=>{r=this.ctx.toResponse(r)}))}},e.DecafResponseInterceptor=p.__decorate([o.Injectable(),p.__metadata("design:paramtypes",[e.DecafRequestContext])],e.DecafResponseInterceptor);class re extends u.DecafController{constructor(e,t){super(e),this.clientContext=e}}class oe extends re{constructor(e,t){super(e,t),this.clientContext=e}persistence(e){if(!this._persistence)try{this._persistence=s.Service.get(this.class)}catch{try{this._persistence=s.ModelService.getService(this.class)}catch{this._persistence=s.Repository.forModel(this.class)}}const t=(e??this.clientContext).toOverrides();return e?this._persistence instanceof s.Repository?this._persistence.override(t):this._persistence.for(t):this._persistence}}const ae=new Map;function se(e,r,o=new Set){if(!s.TransactionOperationKeys.includes(e))return r;const n=(e=>(ae.has(e)||ae.set(e,new WeakMap),ae.get(e)))(e),i=n.get(r);if(i)return i;const p=[c.OperationKeys.UPDATE,c.BulkCrudOperationKeys.UPDATE_ALL].includes(e);class d{}n.set(r,d),Object.defineProperty(d,"name",{value:`${l.toPascalCase(r.name)}${l.toPascalCase(e)}DTO`});const u=(()=>{try{return a.Model.pk(r)}catch{return}})(),f=u?a.Model.pkProps(r):void 0,h=u?Reflect.getMetadata("design:type",r.prototype,u):void 0,m=h===Number||h===BigInt,y=!!f?.generated||!!u&&(a.Model.generatedBySequence(r,u)||de(r,u)||m),g=Array.from(new Set(t.Metadata.properties(r)||[])),A=new Set(a.Model.relations(r)||[]),E=[];for(const e of g)e&&(A.has(e)||e===u&&!p&&y||e!==u&&de(r,e)||E.push(e));for(const e of E){const t=le(r,e),o=!!t?.[a.ValidationKeys.REQUIRED],s=ue(r,e)??Reflect.getMetadata("design:type",r.prototype,e),n={required:o};s&&(n.type=s),S(n)(d.prototype,e);const i=Reflect.getMetadata("design:type",r.prototype,e)??s;void 0!==i&&Reflect.defineMetadata("design:type",i,d.prototype,e),Object.defineProperty(d.prototype,e,{value:void 0,writable:!0,enumerable:!0,configurable:!0})}for(const s of A){const n=t.Metadata.relations(r,s);if(!n)throw new c.InternalError(`Metadata for relation ${s} not found`);let i=n.class;if("function"!=typeof i||i.name||(i=i()),!i||"function"!=typeof i)throw new c.InternalError(`Type for relation ${s} not found`);if(!a.Model.get(i.name))continue;const l=t.Metadata.validationFor(r,s),u=!!l?.[a.ValidationKeys.LIST],f=!!l?.[a.ValidationKeys.REQUIRED];if(o.has(i)){ie(d,s,pe(i),u,f);continue}const h=se(e,i,new Set(o).add(r));p?ce(d,s,i,h,u,f):ne(d,s,h,u,f)}return d}function ne(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 ie(e,t,r,o,a){S(o?{type:"array",items:{type:r},required:a}:{type:"integer"===r?Number:String,required:a})(e.prototype,t),Reflect.defineMetadata("design:type",o?Array:"integer"===r?Number:String,e.prototype,t),Object.defineProperty(e.prototype,t,{value:void 0,writable:!0,enumerable:!0,configurable:!0})}function ce(e,t,r,o,a,s){const n=Reflect.getMetadata(P.API_EXTRA_MODELS,e)||[];n.includes(o)||Reflect.defineMetadata(P.API_EXTRA_MODELS,[...n,o],e);const i=[{$ref:"#/components/schemas/"+o.name},{type:pe(r)}];S(a?{type:"array",required:s,oneOf:i}:{type:Object,required:s,oneOf:i})(e.prototype,t),Reflect.defineMetadata("design:type",a?Array:Object,e.prototype,t),Object.defineProperty(e.prototype,t,{value:void 0,writable:!0,enumerable:!0,configurable:!0})}function pe(e){try{const t=a.Model.pkProps(e),r=t?.type;return r===Number||r===BigInt?"integer":"string"}catch{return"string"}}function de(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 le(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 ue(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)}}s.Adapter.transformerFor=(e=>{const r="string"==typeof e?e:e.alias;return t.Metadata.innerGet(Symbol.for("transformers"),r)}).bind(s.Adapter),s.Adapter.flavoursToTransform=(()=>{const e=t.Metadata.innerGet(Symbol.for("transformers"));if(e)return Object.keys(e)}).bind(s.Adapter),s.Context.prototype.toResponse=function(e){const t=this.pending();return t&&e.header("x-pending-task",JSON.stringify(t)),e};const fe=a.ModelBuilder.prototype;if(fe.decorateClass||(fe.decorateClass=function(e){return this._classDecorators||(this._classDecorators=[]),this._classDecorators.push(e),this}),fe.Auth=function(e){return this.decorateClass(z(e))},!fe.__hasClassDecoratorSupport){const e=fe.build;fe.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},fe.__hasClassDecoratorSupport=!0}var he;class me{static{this.log=l.Logging.for(me.name)}static toDecafError(e,t){return e instanceof c.BaseError?e:new c.InternalError(e instanceof Error?`${t}: ${e.message}`:t)}static getPersistence(e){try{return s.Service.get(e)}catch(t){try{return s.ModelService.getService(e)}catch(t){return s.Repository.forModel(e)}}}static createQueryRoutesFromRepository(e,r=s.PersistenceKeys.QUERY){const o=e instanceof s.ModelService?e.repo:e,a=t.Metadata.get(o.constructor,t.Metadata.key(s.PersistenceKeys.QUERY))??{},n=t.Metadata.get(e.constructor,t.Metadata.key(F))??{};class i extends oe{get class(){throw new c.InternalError("Method not implemented.")}constructor(e,t){super(e,t)}}for(const[e,t]of Object.entries(n)){const r=[t.path.replace(/^\/+|\/+$/g,"")].filter(e=>e&&e.trim()).join("/"),o=me.createComplexQueryHandler(e);me.defineMethod(i,e,o);const a=V(t.httpMethod)(r||void 0),s=me.getQueryDecorators(e,r,t.httpMethod);me.applyDecorators(i,e,[a,...s])}for(const[e,t]of Object.entries(a)){const o=[r,e,...(t.fields??[]).map(e=>":"+e)].filter(e=>e&&e.trim()).join("/"),a=me.createComplexQueryHandler(e);me.defineMethod(i,e,a);const s=V("GET")(o||void 0),n=me.getQueryDecorators(e,o,"GET",!0);me.applyDecorators(i,e,[s,...n])}return i}static create(r,n,c){const d=me.log.for(me.create),f=a.Model.tableName(r),h=l.toKebabCase(f),m=r.name,y=me.getPersistence(r),g=y instanceof s.ModelService?y.repo:y,A=t.Metadata.get(r,t.Metadata.key(B)),E=n?.[r.name],b={...c||{},...A||{},...E||{}},P=u.ModelControllerFactory.create(r,g,b).__routes__,{getPK:v,apiProperties:R,path:O}=me.getRouteParametersFromModel(r);d.debug(`Creating controller for model: ${m} with ${P?.length??0} factory routes`);const D=b.auth;let S=he=class extends oe{static get class(){return r}get class(){return r}constructor(e){super(e,he.name),this.pk=a.Model.pk(r),d.info(`Registering dynamic controller for model: ${this.class.name} route: /${h}`)}};var _;if(S=he=p.__decorate([o.Controller(h),i.ApiTags(m),i.ApiExtraModels(r),p.__metadata("design:paramtypes",[e.DecafRequestContext])],S),_=S,D?.public?W()(_):D?.roles?.length?Y(...D.roles)(_):z(r)(_),D?.skipModelRoles&&o.SetMetadata(Q,!0)(_),P){const e=[...P].sort((e,t)=>{const r=e.path.split("/").filter(Boolean),o=t.path.split("/").filter(Boolean),a=r.filter(e=>e.startsWith(":")).length,s=o.filter(e=>e.startsWith(":")).length,n=r.length-a,i=o.length-s;return n!==i?i-n:a!==s?a-s:0});for(const t of e){const e=t.implementation?.name||t.method.toLowerCase(),o=me.matchRoute(e,t,O,R,v,r,m);if(!o)continue;const{methodName:a,handler:s,decorators:n,paramDecorators:i}=o;if(me.defineMethod(S,a,s)){const e=V(t.method)(t.path.replace(/^\/+|\/+$/g,"")||void 0);me.applyDecorators(S,a,[e,...n],i)}}}return S}static getRouteParametersFromModel(e){const r=a.Model.pk(e),o=t.Metadata.get(e,t.Metadata.key(c.DBKeys.COMPOSED,r)),s=o?.args??[],n=Array.isArray(s)&&s.length>0?Array.from(new Set([...s])):Array.from(new Set([r])),i=t.Metadata.description(e)??"";return{path:":"+n.join("/:"),description:i,apiProperties:n.map(r=>({name:r,description:t.Metadata.description(e,r),required:!0,type:String})),getPK:(...e)=>o?.separator?e.join(o.separator):e.join("")}}static routeParamDecorators(e){let t=0;return e.split("/").filter(Boolean).flatMap(e=>e.startsWith(":")||e.startsWith("*")?[{decorator:o.Param(e.slice(1)),index:t++}]:[])}static defineMethod(e,t,r){return Object.defineProperty(e.prototype||e,t,{value:r,writable:!1,configurable:!0,enumerable:!1}),Object.getOwnPropertyDescriptor(e.prototype||e,t)}static applyDecorators(e,t,r,o=[]){const a=e?.prototype??e,s=Object.getOwnPropertyDescriptor(a,t);r.forEach(e=>e(a,t,s)),o.forEach(({decorator:e,index:r})=>e(a,t,r))}static matchRoute(e,t,r,a,n,c,p){const{method:d,path:l}=t,u=l.replace(/^\/+|\/+$/g,""),f=t.implementation;if("POST"===d&&""===u)return me.createRegistration("create",f,me.createCreateDecorators(c,p),[{decorator:x(),index:0},{decorator:o.Response({passthrough:!0}),index:1}]);if("POST"===d&&"bulk"===u)return me.createRegistration("createAll",f,me.bulkCreateDecorators(c,p),[{decorator:x(),index:0},{decorator:o.Response({passthrough:!0}),index:1}]);if("GET"===d&&"bulk"===u)return me.createRegistration("readAll",f,me.bulkReadDecorators(c,p),[{decorator:o.Query("ids"),index:0}]);if("PUT"===d&&"bulk"===u)return me.createRegistration("updateAll",f,me.bulkUpdateDecorators(c,p,a),[{decorator:x(),index:0},{decorator:o.Response({passthrough:!0}),index:1}]);if("DELETE"===d&&"bulk"===u)return me.createRegistration("deleteAll",f,me.bulkDeleteDecorators(c,p,a),[{decorator:o.Query("ids"),index:0},{decorator:o.Response({passthrough:!0}),index:1}]);if("GET"===d&&u===r)return me.createRegistration("read",f,me.readDecorators(c,p,a,r),me.routeParamDecorators(u));if("PUT"===d&&u===r){const e=me.routeParamDecorators(u);return me.createRegistration("update",f,me.updateDecorators(c,p,a,r),[{decorator:x(),index:0},...e.map(({decorator:e,index:t})=>({decorator:e,index:t+1}))])}if("DELETE"===d&&u===r){const e=me.routeParamDecorators(u);return me.createRegistration("delete",f,me.deleteDecorators(c,p,a,r),e)}const h=u.split("/").filter(Boolean);if(h.length>0&&h.every(e=>e.startsWith(":"))&&u!==r){const e=h.map(e=>e.slice(1)).map(e=>({name:e,description:e+" parameter",required:!0,type:String})),t=h.map(e=>e.slice(1)).join("And"),r=me.routeParamDecorators(u);if("GET"===d)return me.createRegistration("readBy"+t,f,me.readDecorators(c,p,e,u),r);if("PUT"===d)return me.createRegistration("updateBy"+t,f,me.updateDecorators(c,p,e,u),[{decorator:x(),index:0},...r.map(({decorator:e,index:t})=>({decorator:e,index:t+1}))]);if("DELETE"===d)return me.createRegistration("deleteBy"+t,f,me.deleteDecorators(c,p,e,u),r)}if("GET"===d&&"statement/:method/*args"===u)return me.createRegistration("statement",f,me.statementDecorators(c,p),[{decorator:o.Param("method"),index:0},{decorator:o.Param("args"),index:1},{decorator:q(),index:2}]);if("GET"===d&&"findOneBy/:key/:value"===u)return me.createRegistration("findOneBy",f,me.statementShortcutDecorators(c,p,u,s.PreparedStatementKeys.FIND_ONE_BY),me.statementShortcutParams(u));const m={"listBy/:key":s.PreparedStatementKeys.LIST_BY,"paginateBy/:key/:page":s.PreparedStatementKeys.PAGE_BY,"find/:value":s.PreparedStatementKeys.FIND,"page/:value":s.PreparedStatementKeys.PAGE,"findOneBy/:key/:value":s.PreparedStatementKeys.FIND_ONE_BY,"findBy/:key/:value":s.PreparedStatementKeys.FIND_BY,"countOf/:field":s.PreparedStatementKeys.COUNT_OF,"maxOf/:field":s.PreparedStatementKeys.MAX_OF,"minOf/:field":s.PreparedStatementKeys.MIN_OF,"avgOf/:field":s.PreparedStatementKeys.AVG_OF,"sumOf/:field":s.PreparedStatementKeys.SUM_OF,"distinctOf/:field":s.PreparedStatementKeys.DISTINCT_OF,"groupOf/:field":s.PreparedStatementKeys.GROUP_OF}[u];if(m&&"GET"===d)return me.createRegistration(me.statementMethodName(u),f,me.statementShortcutDecorators(c,p,u,m),me.statementShortcutParams(u));if("GET"===d&&u.startsWith("query/")){const e=u.replace(/^query\//,"").split("/")[0];return me.createRegistration(e,f,me.getQueryDecorators(e,u,"GET",!0),me.complexQueryParams(u))}const y=u.split("/").filter(Boolean),g=new Set(["listBy","findBy","findByPaginate","findOneBy","paginateBy","find","page","countOf","maxOf","minOf","avgOf","sumOf","distinctOf","groupOf","statement","bulk","query"]);if(y.length>0&&!u.startsWith("query/")&&!u.startsWith("statement/")&&!g.has(y[0])){const t=y.filter(e=>e.startsWith(":")).map(e=>e.slice(1)).map(e=>({name:e,description:e+" parameter for the query",required:!0,type:String}));return me.createRegistration(e,f,[...t.map(e=>i.ApiParam(e)),i.ApiOperation({summary:`Retrieve records using "${e}".`}),i.ApiOkResponse({description:"Result successfully retrieved."}),i.ApiNoContentResponse({description:"No content returned by the method."})],me.routeParamDecorators(u))}}static createRegistration(e,t,r,o){return{methodName:e,handler:t,decorators:r,paramDecorators:o}}static statementMethodName(e){return e.split("/")[0]}static statementShortcutParams(e){const t=e.split("/").filter(e=>e.startsWith(":")),r=[];return t.forEach((e,t)=>{const a=e.replace(":","");r.push({decorator:o.Param(a),index:t})}),(e.startsWith("listBy/")||e.startsWith("paginateBy/")||e.startsWith("find/")||e.startsWith("page/"))&&r.push({decorator:q(),index:t.length}),r}static complexQueryParams(e){const t=e.split("/").filter(e=>e.startsWith(":")),r=[];return t.forEach((e,t)=>{const a=e.replace(":","");r.push({decorator:o.Param(a),index:t})}),e.startsWith("query/")&&r.push({decorator:q(),index:t.length}),r}static createComplexQueryHandler(e){return async function t(...r){const o=this.log?.for?.(t);try{o&&o.debug(`Invoking custom query "${e}"`);const{ctx:a}=(await this.logCtx([],e,!0)).for(t),s=this.persistence(a),n=me.normalizeQueryArgs(r);if(s?.repo&&"function"==typeof s.repo[e])return s.repo[e](...n);if("function"==typeof s[e])return s[e](...n);if(s?.query&&"function"==typeof s.query)return s.query(e,...n);if("function"==typeof s.statement)return s.statement(e,...n,a);throw new c.InternalError(`Persistence method "${e}" not found on ${s?.constructor?.name}`)}catch(t){throw o&&o.error(`Custom query "${e}" failed`,t),me.toDecafError(t,`Custom query "${e}" failed`)}}}static extractQueryArgs(e){if(0===e.length)return e;const t=e[e.length-1];if(t&&"object"==typeof t&&!Array.isArray(t)){const t=e.pop(),r=void 0!==t.direction,o=void 0!==t.limit,a=void 0!==t.offset;if(!r&&!o&&!a)return e;const s=[];return r?s.push(t.direction):(o||a)&&s.push(void 0),o&&s.push(t.limit),a&&s.push(t.offset),[...e,...s]}return e}static normalizeQueryArgs(e){const t=me.extractQueryArgs(e);if(0===t.length)return t;const r=t[t.length-1];if(!r||"object"!=typeof r||Array.isArray(r))return t;const o=r;return void 0!==o.direction||void 0!==o.limit||void 0!==o.offset||void 0!==o.bookmark?(t.pop(),void 0!==o.direction&&t.push(o.direction),void 0!==o.limit&&t.push(o.limit),void 0!==o.offset&&t.push(o.offset),void 0!==o.bookmark&&t.push(o.bookmark),t):(t.pop(),t)}static createCreateDecorators(e,t){return[C(e,"POST"),i.ApiOperation({summary:`Create a new ${t}.`}),i.ApiBody({description:"Payload for "+t,type:se(c.OperationKeys.CREATE,e)}),i.ApiCreatedResponse({description:t+" created successfully.",schema:{$ref:i.getSchemaPath(e)}}),i.ApiBadRequestResponse({description:"Payload validation failed."}),i.ApiUnprocessableEntityResponse({description:"Repository rejected the provided payload."})]}static bulkCreateDecorators(e,t){return[C(e,"POST","bulk"),i.ApiOperation({summary:`Create a new ${t}.`}),i.ApiBody({description:"Payload for "+t,schema:{type:"array",items:{$ref:i.getSchemaPath(e)}}}),i.ApiCreatedResponse({description:t+" created successfully.",schema:{type:"array",items:{$ref:i.getSchemaPath(e)}}}),i.ApiBadRequestResponse({description:"Payload validation failed."}),i.ApiUnprocessableEntityResponse({description:"Repository rejected the provided payload."})]}static bulkReadDecorators(e,t){return[C(e,"GET","bulk"),i.ApiOperation({summary:`Retrieve ${t} records by ids.`}),i.ApiQuery({name:"ids",required:!0,type:"array"}),i.ApiOkResponse({description:t+" retrieved successfully.",schema:{type:"array",items:{$ref:i.getSchemaPath(e)}}}),i.ApiNotFoundResponse({description:`No ${t} record matches the provided identifier.`})]}static bulkUpdateDecorators(e,t,r){return[C(e,"PUT","bulk"),M(r),i.ApiOperation({summary:`Replace existing ${t} records with new payloads.`}),i.ApiBody({description:"Payload for replacing existing records of "+t,schema:{type:"array",$ref:i.getSchemaPath(se(c.OperationKeys.UPDATE,e))}}),i.ApiOkResponse({description:t+" updated successfully.",schema:{type:"array",items:{$ref:i.getSchemaPath(e)}}}),i.ApiNotFoundResponse({description:`No ${t} record matches the provided identifier.`}),i.ApiBadRequestResponse({description:"Payload validation failed."})]}static bulkDeleteDecorators(e,t,r){return[C(e,"DELETE","bulk"),M(r),i.ApiOperation({summary:`Delete ${t} records by ids.`}),i.ApiQuery({name:"ids",required:!0,type:"array"}),i.ApiOkResponse({description:t+" deleted successfully.",schema:{type:"array",items:{$ref:i.getSchemaPath(e)}}}),i.ApiNotFoundResponse({description:`No ${t} record matches the provided identifier.`})]}static readDecorators(e,t,r,o){return[C(e,"GET",o),M(r),i.ApiOperation({summary:`Retrieve a ${t} record by id.`}),i.ApiOkResponse({description:t+" retrieved successfully.",schema:{$ref:i.getSchemaPath(e)}}),i.ApiNotFoundResponse({description:`No ${t} record matches the provided identifier.`})]}static updateDecorators(e,t,r,o){return[C(e,"PUT",o),M(r),i.ApiOperation({summary:`Replace an existing ${t} record with a new payload.`}),i.ApiBody({description:"Payload for replacing an existing record of "+t,type:se(c.OperationKeys.UPDATE,e)}),i.ApiOkResponse({description:t+" updated successfully.",schema:{$ref:i.getSchemaPath(e)}}),i.ApiNotFoundResponse({description:`No ${t} record matches the provided identifier.`}),i.ApiBadRequestResponse({description:"Payload validation failed."})]}static deleteDecorators(e,t,r,o){return[C(e,"DELETE",o),M(r),i.ApiOperation({summary:`Delete a ${t} record by id.`}),i.ApiOkResponse({description:t+" deleted successfully.",schema:{$ref:i.getSchemaPath(e)}}),i.ApiNotFoundResponse({description:`No ${t} record matches the provided identifier.`})]}static statementDecorators(e,t){return[C(e,"GET","statement/:method/*args"),i.ApiOperation({summary:`Executes a prepared statement on ${t}.`}),i.ApiParam({name:"method",description:"the prepared statement to execute"}),i.ApiParam({name:"args",description:"concatenated list of arguments the prepared statement can accept"}),i.ApiQuery({name:"direction",required:!0,enum:s.OrderDirection,description:"the sort order when applicable"}),i.ApiQuery({name:"limit",required:!0,description:"limit or page size when applicable"}),i.ApiQuery({name:"offset",required:!0,description:"offset or bookmark when applicable"}),i.ApiOkResponse({description:t+" listed found."}),i.ApiNotFoundResponse({description:`No ${t} record matches the provided identifier.`})]}static statementShortcutDecorators(e,t,r,o){const a=[C(e,"GET",r),i.ApiOperation({summary:`Retrieve ${t} records.`}),i.ApiOkResponse({description:t+" retrieved successfully."})];return r.split("/").filter(e=>e.startsWith(":")).forEach(e=>{const t=e.replace(":","");a.push(i.ApiParam({name:t,description:`The ${t} parameter`}))}),(r.startsWith("listBy/")||r.startsWith("paginateBy/")||r.startsWith("find/")||r.startsWith("page/"))&&a.push(i.ApiQuery({name:"direction",required:!0,enum:s.OrderDirection,description:"the sort order"})),(r.startsWith("paginateBy/")||r.startsWith("page/"))&&a.push(i.ApiQuery({name:"limit",required:!1,description:"page size"}),i.ApiQuery({name:"offset",required:!1,description:"page number"}),i.ApiQuery({name:"bookmark",required:!1,description:"bookmark for cursor pagination"})),(r.startsWith("findOneBy/")||r.startsWith("findBy/"))&&a.push(i.ApiNotFoundResponse({description:`No ${t} record matches the provided identifier.`})),o!==s.PreparedStatementKeys.COUNT_OF&&o!==s.PreparedStatementKeys.AVG_OF&&o!==s.PreparedStatementKeys.SUM_OF||a.push(i.ApiOkResponse({description:`Result for ${t}.`,type:Number})),o===s.PreparedStatementKeys.DISTINCT_OF&&a.push(i.ApiOkResponse({description:`Distinct values for ${t}.`,type:[String]})),a}static getQueryDecorators(e,t,r,o=!1){var a;const n=[...(a=t,a.split("/").filter(e=>e.startsWith(":")).map(e=>e.slice(1))).map(e=>({name:e,description:e+" parameter for the query",required:!0,type:String})).map(e=>i.ApiParam(e)),i.ApiOperation({summary:`Retrieve records using "${e}".`}),i.ApiOkResponse({description:"Result successfully retrieved."}),i.ApiNoContentResponse({description:"No content returned by the method."})];return"GET"===r&&o&&n.push(i.ApiQuery({name:"direction",required:!1,enum:s.OrderDirection,description:"the sort order when applicable"}),i.ApiQuery({name:"limit",required:!1,description:"limit or page size"}),i.ApiQuery({name:"offset",required:!1,description:"offset or bookmark"})),n}}function ye(e){var r;let a=class{static{r=this}static{this.log=l.Logging.for(r.name).for(e)}static createModelServices(e){return e.map(e=>({provide:e.name+"Service",useFactory:()=>s.ModelService.forModel(e)}))}static isExposed(r,o){const a=o?.[r.name],s=void 0!==a?a:t.Metadata.get(r,t.Metadata.key(j));return void 0===s||!0===s||!!Array.isArray(s)&&s.includes(e)}static forRoot(e,t={}){const o=this.log.for(this.forRoot);o.info("Generating controllers for flavour...");const a=s.Adapter.models(e).filter(e=>this.isExposed(e,t.controllerExposure));for(const e of a)s.ModelService.forModel(e);let n=[];t.autoServices&&(o.info("Auto-services enabled. Initializing service generation."),n=this.createModelServices(a),o.info(`Auto-services completed. ${n.length} services initialized.`));const i={};!1===t.aggregations&&(i.allowGroupingQueries=!1);const c=a.map(e=>me.create(e,t.controllerConfig,i));return o.info(`Generated ${c.length} controllers`),{module:r,controllers:c,providers:[...n]}}};return a=r=p.__decorate([o.Module({})],a),Object.assign(a,"name",{value:"DecafModule"+e}),a}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(s.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(s.PersistenceKeys.AUTH).extend({decorator:z}).apply();class ge extends s.ForbiddenError{constructor(e){super(e,ge.name)}}class Ae extends c.BaseError{constructor(e){super(Ae.name,e,429)}}const Ee=new Map([[o.UnauthorizedException,e=>new s.AuthorizationError(e)],[o.ForbiddenException,e=>new s.ForbiddenError(e)],[o.BadRequestException,e=>new c.BadRequestError(e)],[o.ConflictException,e=>new c.ConflictError(e)],[o.UnprocessableEntityException,e=>new c.ValidationError(e)]]);e.DecafExceptionFilter=class{constructor(e){this.moduleRef=e}async catch(e,t){const r=t.switchToHttp(),a=r.getResponse(),n=r.getRequest(),i="production"===l.LoggedEnvironment.env;let p;if(e instanceof o.NotFoundException||e instanceof s.UnsupportedError)p=(e=new o.NotAcceptableException(e.message)).getStatus();else if(!(e instanceof c.BaseError)){const t=this.decafErrorFor(e);t?e=t(e.message):429===e.status?e=new Ae(e.message):e instanceof o.HttpException?p=e.getStatus():e=new c.InternalError(e.message)}await this.logError(n,e),a.status(e.code||p).json({status:e.code||p,error:i?e.name:e.message,timestamp:(new Date).toISOString(),path:n.url,method:n.method})}decafErrorFor(e){for(const[t,r]of Ee)if(e instanceof t)return r}async logError(e,t){const r=`Unhandled error on ${e?.method} ${e?.url}`;try{(await this.resolveLogger(e)).error(r,t)}catch{try{l.Logging.get().error(r,t)}catch{}}}async resolveLogger(t){if(this.moduleRef)try{const r=d.ContextIdFactory.getByRequest(t),o=await this.moduleRef.resolve(e.DecafRequestContext,r,{strict:!1});if(o?.logger)return o.logger}catch{}return l.Logging.get()}},e.DecafExceptionFilter=p.__decorate([o.Catch(),o.Injectable(),p.__param(0,o.Optional()),p.__metadata("design:paramtypes",[d.ModuleRef])],e.DecafExceptionFilter);const be={path:"docs",auth:{type:"http",scheme:"bearer",bearerFormat:"JWT",name:"Authorization",description:"Enter JWT token",in:"header"},topbarBgColor:"#000000"};class Pe{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||be.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=E.join(this.options.assetsPath||"",e),o=h.readFileSync(r,{encoding:"base64"});return t?"data:image/png;base64,"+o:o}}class ve{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 i.DocumentBuilder).setTitle(this.options.title).setDescription(e).setVersion(this.options.version||"0.0.1").addBearerAuth(this.options.auth||be.auth).build();return i.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 Pe({title:this.options.title,path:this.options.path||be.path,persistAuthorization:this.options.persistAuthorization??!0,assetsPath:this.options.assetsPath,faviconPath:this.options.faviconFilePath,topbarIconPath:this.options.topbarIconFilePath,topbarBgColor:this.options.topbarBgColor});i.SwaggerModule.setup(this.options.path||be.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",()=>y.stringify(e))}}var Re;e.DecafRequestHandlerInterceptor=Re=class{constructor(e,t){this.requestContext=e,this.executor=t}async contextualize(e){const t={headers:e.headers,overrides:{}},r=(e=>{const t=e.headers;function r(e){if(e)return(Array.isArray(e)?e[0]:e).split(",").map(e=>e.trim()).filter(Boolean)[0]}return r(t?.["x-forwarded-for"])??r(t?.["x-real-ip"])??r(t?.["X-Forwarded-For"])??r(t?.["X-Real-IP"])??e.ip})(e),o=l.Logging.get().for({ip:r});this.requestContext.accumulate(Object.assign({},s.DefaultAdapterFlags,{logger:o,timestamp:new Date,operation:`${e.method} ${e.url}`},t))}async intercept(e,t){const r=e.switchToHttp().getRequest(),o=e.switchToHttp().getResponse(),a=l.Logging.for(Re).for(this.intercept);return a.debug(`CONTEXT ${this.requestContext.uuid} - request: ${r.method} ${r.url}`),await this.contextualize(r),a.debug(`CONTEXT ${this.requestContext.uuid} contextualized - 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=Re=p.__decorate([o.Injectable({scope:o.Scope.REQUEST}),p.__metadata("design:paramtypes",[e.DecafRequestContext,e.DecafHandlerExecutor])],e.DecafRequestHandlerInterceptor);const Oe=new Map;function De(){return Array.from(Oe.values())}function Se(e,t){Oe.has(e)||Oe.set(e,{provide:e,useFactory:t})}var _e;e.DecafCoreModule=class{static{_e=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(_e)),this._logger}constructor(e,t){this.options=e,this.moduleRef=t}static forRoot(t){const r=this.log.for(this.forRoot),o=De();return{module:_e,providers:[{provide:N,useValue:t},{provide:k,useValue:this.persistence?.client},{provide:$,useFactory:()=>t.handlers?.map(e=>(r.info("Registered request handler: "+e.name),new e))??[]},e.DecafRequestContext,e.DecafHandlerExecutor,{provide:d.APP_INTERCEPTOR,useClass:e.DecafRequestHandlerInterceptor},...o],exports:[N,k,$,e.DecafRequestContext,e.DecafHandlerExecutor,...o.map(e=>e.provide)]}}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 s.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=s.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}`)}}u.requestToContextTransformer(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=_e.log.for(this.onApplicationShutdown),t=this.moduleRef.get(k);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 s.Service.shutdown()}catch(t){e.error("Failed to shutdown services",t)}}},e.DecafCoreModule=_e=p.__decorate([o.Global(),o.Module({}),p.__param(0,o.Inject(N)),p.__metadata("design:paramtypes",[Object,d.ModuleRef])],e.DecafCoreModule);const Ce=Symbol("LISTENING_ADAPTERS_FLAVOURS");var Te,Me,xe;e.EventsController=Te=class extends re{constructor(e,t){super(e,Te.name),this.adapters=t.map(e=>s.Adapter.get(e))}listen(){const e=l.Logging.for(Te.name),t=new f.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=f.interval(15e3).pipe(g.tap(()=>{e.debug("Sending heartbeat")}),g.map(()=>({type:"heartbeat",data:{ts:(new Date).toISOString()}})));return f.merge(t,r)}listenForModel(e){const t=l.Logging.for(Te.name);return new f.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",f.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",f.Observable)],e.EventsController.prototype,"listenForModel",null),e.EventsController=Te=p.__decorate([o.Controller(),p.__param(1,o.Inject(Ce)),p.__metadata("design:paramtypes",[e.DecafRequestContext,Array])],e.EventsController),e.DecafStreamModule=Me=class{static forFlavours(t,r="events"){return{module:Me,controllers:[e.EventsController],imports:[d.RouterModule.register([{path:r.replace(/^\//,""),module:Me}])],providers:[e.DecafRequestContext,{provide:Ce,useValue:t??[]}]}}},e.DecafStreamModule=Me=p.__decorate([o.Module({})],e.DecafStreamModule),e.DecafModule=xe=class{static async forRootAsync(t){const{autoControllers:r,autoServices:o}=t,a=(await e.DecafCoreModule.bootPersistence(t)).map(e=>e.flavour),s=[e.DecafCoreModule.forRoot(t)];return r&&a.forEach(e=>{s.push(ye(e).forRoot(e,{autoServices:o,controllerExposure:t.controllerExposure,controllerConfig:t.controllerConfig,aggregations:t.aggregations}))}),t.observerOptions?.enableObserverEvents&&s.push(e.DecafStreamModule.forFlavours(t.observerOptions.observerFlavours||a)),{module:xe,imports:s}}},e.DecafModule=xe=p.__decorate([o.Module({})],e.DecafModule);const Ie="##VERSION##",we="##PACKAGE##";t.Metadata.allowReregistration(!0),t.Metadata.registerLibrary(we,Ie),t.Metadata.allowReregistration(!1),e.AUTH_HANDLER=U,e.AUTH_META_KEY=K,e.ApiOperationFromModel=C,e.ApiParamsFromModel=M,e.ApiProperty=S,e.Auth=z,e.BulkApiOperationFromModel=(e,r,a)=>{const n={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]},[p,d]=n[r],l=a?T(r,a):void 0;return l?s.isOperationBlocked(e,l.kind,l.value)?t.apply(i.ApiExcludeEndpoint()):t.apply(d(a)):s.isOperationBlocked(e,"bulk",p)?t.apply(i.ApiExcludeEndpoint()):t.apply(d(a))},e.COMMIT="3ac17fe",e.CorsError=ge,e.DECAF_ADAPTER_ID=k,e.DECAF_CONTEXT_KEY=L,e.DECAF_CONTROLLER_CONFIG=B,e.DECAF_EXPOSE=j,e.DECAF_HANDLERS=$,e.DECAF_MODULE_OPTIONS=N,e.DECAF_ROUTE=F,e.DECAF_TASK_SERVICE_ID="DecafTaskService",e.DECORATORS=P,e.DECORATORS_PREFIX=b,e.DecafAuthHandler=Z,e.DecafBody=x,e.DecafController=re,e.DecafModelController=oe,e.DecafParams=w,e.DecafRoleAuthHandler=class extends Z{},e.DtoFor=se,e.FULL_VERSION="0.12.0-3ac17fe",e.FromModelController=me,e.IS_PUBLIC_KEY=H,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 ge(`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{this.logger.warn("Helmet not installed. Skipping middleware.")}return this}static setupSwagger(e){return new ve(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.app.get(d.ModuleRef,{strict:!1}))]),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=we,e.Public=W,e.REQUIRED_ROLES_KEY=G,e.Repository=(e,t)=>(r,a,n)=>{const i=((e,t)=>t?`${e.name}Repository@${t}`:e.name+"Repository")(e,t);return Se(i,()=>s.Repository.forModel(e,t)),o.Inject(i)(r,a,n)},e.RequireRoles=Y,e.SKIP_MODEL_ROLES_KEY=Q,e.Service=e=>(t,r,n)=>{let i=e;if(void 0===i){const e=Reflect.getMetadata("design:paramtypes",t)||[];i=e[n]}if(void 0===i)throw new c.InternalError(`@Service() could not determine an injection type for parameter ${n} of ${t.name}. Provide an explicit argument, e.g. @Service(SomeService).`);const p="string"!=typeof i&&"function"==typeof(d=i)&&d.prototype instanceof a.Model;var d;const l=p?i.name+"Service":s.injectableServiceKey(i);return Se(l,()=>{if(p)try{return s.Service.get(i)}catch{return s.ModelService.forModel(i)}return s.Service.get(i)}),o.Inject(l)(t,r,n)},e.SwaggerBuilder=ve,e.UseDecafFilter=()=>o.UseFilters(new e.DecafExceptionFilter),e.UseDecafHeaders=()=>o.UseInterceptors(e.DecafResponseInterceptor),e.VERSION=Ie,e.applyApiDecorators=(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))},e.controllerConfig=e=>r=>(t.Metadata.set(r,B,e),r),e.createApiPropertyDecorator=_,e.createPropertyDecorator=D,e.createRouteHandler=function(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:s,offset:n}=r;return await J(this.persistence(this.ctx),e,...t.valuesInOrder,a,s,n)}catch(t){throw o.error(`Custom query "${e}" failed`,t),s=`Custom query "${e}" failed`,(a=t)instanceof c.BaseError?a:new c.InternalError(a instanceof Error?`${s}: ${a.message}`:s)}var a,s}},e.defineRouteMethod=(e,t,r)=>(Object.defineProperty(e.prototype||e,t,{value:r,writable:!1}),Object.getOwnPropertyDescriptor(e.prototype||e,t)),e.expose=(...e)=>r=>(t.Metadata.set(r,j,!e.length||e),r),e.getApiDecorators=(e,t,r,a=!1)=>{const n=V(r),c=(e=>e.split("/").filter(e=>e.startsWith(":")).map(e=>e.slice(1)))(t).map(X),p=[];return"GET"===r&&a&&p.push(i.ApiQuery({name:"direction",required:!1,enum:s.OrderDirection,description:"the sort order when applicable"}),i.ApiQuery({name:"limit",required:!1,description:"limit or page size when applicable"}),i.ApiQuery({name:"offset",required:!1,description:"offset or bookmark when applicable"})),{method:[n(t),...c.map(i.ApiParam),...p,i.ApiOperation({summary:`Retrieve records using according to "${e}".`}),i.ApiOkResponse({description:"Result successfully retrieved."}),i.ApiNoContentResponse({description:"No content returned by the method."})],params:[w(c),o.Query()]}},e.getEnumType=O,e.getEnumValues=R,e.getModuleFor=ye,e.getRegisteredDecafProviders=De,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 s.Repository.forModel(t)},e.resolvePersistenceMethod=J,e.runMigrations=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("@decaf-ts/for-http/server"),require("rxjs"),require("fs"),require("path"),require("yaml"),require("rxjs/operators")):"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","@decaf-ts/for-http/server","rxjs","fs","path","yaml","rxjs/operators"],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.server,e.rxjs,e.fs,e.path,e.yaml,e.operators);
|
|
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_EXPOSE = "DecafExpose";
|
|
383
|
+
const DECAF_CONTROLLER_CONFIG = "DecafControllerConfig";
|
|
384
|
+
const DECAF_CONTEXT_KEY = Symbol("decaf:context");
|
|
385
|
+
function expose(...flavours) {
|
|
386
|
+
return function expose(target) {
|
|
387
|
+
decoration.Metadata.set(target, DECAF_EXPOSE, flavours.length ? flavours : true);
|
|
388
|
+
return target;
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
function controllerConfig(config) {
|
|
392
|
+
return function controllerConfigDecorator(target) {
|
|
393
|
+
decoration.Metadata.set(target, DECAF_CONTROLLER_CONFIG, config);
|
|
394
|
+
return target;
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
const AUTH_HANDLER = Symbol("AUTH_HANDLER");
|
|
398
|
+
const AUTH_META_KEY = "auth:meta";
|
|
399
|
+
const IS_PUBLIC_KEY = "isPublic";
|
|
400
|
+
const REQUIRED_ROLES_KEY = "requiredRoles";
|
|
401
|
+
const REQUIRED_NAMESPACES_KEY = "requiredNamespaces";
|
|
402
|
+
const SKIP_MODEL_ROLES_KEY = "skipModelRoles";
|
|
403
|
+
const SKIP_MODEL_NAMESPACES_KEY = "skipModelNamespaces";
|
|
404
|
+
exports.DecafRequestContext = class DecafRequestContext extends server.RequestContext {
|
|
405
|
+
constructor(req) {
|
|
406
|
+
super({
|
|
407
|
+
headersOf: request => request?.headers || undefined
|
|
408
|
+
}, req);
|
|
409
|
+
this.req = req;
|
|
410
|
+
this.uuid = core.UUID.instance.generate();
|
|
411
|
+
this.request = req;
|
|
412
|
+
}
|
|
413
|
+
get headers() {
|
|
414
|
+
return this.getOrUndefined("headers");
|
|
415
|
+
}
|
|
416
|
+
put(record) {
|
|
417
|
+
let overrides;
|
|
418
|
+
try {
|
|
419
|
+
overrides = this.get("overrides");
|
|
420
|
+
} catch (e) {
|
|
421
|
+
overrides = {};
|
|
422
|
+
}
|
|
423
|
+
this.accumulate({
|
|
424
|
+
overrides: Object.assign(overrides, record)
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
};
|
|
428
|
+
exports.DecafRequestContext = tslib.__decorate([ common.Injectable({
|
|
429
|
+
scope: common.Scope.REQUEST
|
|
430
|
+
}), tslib.__param(0, common.Inject(core$1.REQUEST)), tslib.__metadata("design:paramtypes", [ Object ]) ], exports.DecafRequestContext);
|
|
431
|
+
exports.AuthInterceptor = class AuthInterceptor {
|
|
432
|
+
constructor(reflector, requestContext, authHandler) {
|
|
433
|
+
this.reflector = reflector;
|
|
434
|
+
this.requestContext = requestContext;
|
|
435
|
+
this.authHandler = authHandler;
|
|
436
|
+
}
|
|
437
|
+
async intercept(ctx, next) {
|
|
438
|
+
const log = logging.Logging.for(this).for(this.intercept);
|
|
439
|
+
const isPublic = this.reflector.getAllAndOverride(IS_PUBLIC_KEY, [ ctx.getHandler(), ctx.getClass() ]);
|
|
440
|
+
const modelName = this.reflector.get(AUTH_META_KEY, ctx.getHandler()) ?? this.reflector.get(AUTH_META_KEY, ctx.getClass());
|
|
441
|
+
const requiredRoles = this.reflector.getAllAndOverride(REQUIRED_ROLES_KEY, [ ctx.getHandler(), ctx.getClass() ]);
|
|
442
|
+
const requiredNamespaces = this.reflector.getAllAndOverride(REQUIRED_NAMESPACES_KEY, [ ctx.getHandler(), ctx.getClass() ]);
|
|
443
|
+
const skipModelRoles = this.reflector.getAllAndOverride(SKIP_MODEL_ROLES_KEY, [ ctx.getHandler(), ctx.getClass() ]);
|
|
444
|
+
const skipModelNamespaces = this.reflector.getAllAndOverride(SKIP_MODEL_NAMESPACES_KEY, [ ctx.getHandler(), ctx.getClass() ]);
|
|
445
|
+
const effectiveModel = skipModelRoles ? undefined : modelName;
|
|
446
|
+
log.verbose(`Intercepted request${modelName ? ` for ${modelName}` : ""}`);
|
|
447
|
+
if (isPublic) {
|
|
448
|
+
log.debug(`Public route — skipping auth`);
|
|
449
|
+
} else if (this.authHandler) {
|
|
450
|
+
await this.authHandler.authorize(ctx, effectiveModel, requiredRoles, requiredNamespaces, skipModelNamespaces, this.requestContext);
|
|
451
|
+
} else {
|
|
452
|
+
log.debug(`No auth handler registered`);
|
|
453
|
+
}
|
|
454
|
+
await this.applyTransformers();
|
|
455
|
+
return next.handle();
|
|
456
|
+
}
|
|
457
|
+
async applyTransformers() {
|
|
458
|
+
const flavours = core.Adapter.flavoursToTransform();
|
|
459
|
+
if (!flavours) return;
|
|
460
|
+
for (const flavour of flavours) {
|
|
461
|
+
const transformer = core.Adapter.transformerFor(flavour);
|
|
462
|
+
if (!transformer) continue;
|
|
463
|
+
const instance = transformer.from ? transformer : new transformer;
|
|
464
|
+
const from = await instance.from(this.requestContext);
|
|
465
|
+
if (from) this.requestContext.accumulate(from);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
};
|
|
469
|
+
exports.AuthInterceptor = tslib.__decorate([ common.Injectable({
|
|
470
|
+
scope: common.Scope.REQUEST
|
|
471
|
+
}), tslib.__param(2, common.Optional()), tslib.__param(2, common.Inject(AUTH_HANDLER)), tslib.__metadata("design:paramtypes", [ core$1.Reflector, exports.DecafRequestContext, Object ]) ], exports.AuthInterceptor);
|
|
472
|
+
function Auth(model) {
|
|
473
|
+
const resource = model ? typeof model === "string" ? model : model.name : undefined;
|
|
474
|
+
const decs = [ swagger.ApiBearerAuth(), common.UseInterceptors(exports.AuthInterceptor) ];
|
|
475
|
+
if (resource) decs.push(common.SetMetadata(AUTH_META_KEY, resource));
|
|
476
|
+
return common.applyDecorators(...decs);
|
|
477
|
+
}
|
|
478
|
+
function Public() {
|
|
479
|
+
return common.applyDecorators(common.SetMetadata(IS_PUBLIC_KEY, true));
|
|
480
|
+
}
|
|
481
|
+
function RequireRoles(...roles) {
|
|
482
|
+
return common.applyDecorators(swagger.ApiSecurity("bearer"), common.SetMetadata(REQUIRED_ROLES_KEY, roles), common.UseInterceptors(exports.AuthInterceptor));
|
|
483
|
+
}
|
|
484
|
+
function RequireNamespaces(...namespaces) {
|
|
485
|
+
return common.applyDecorators(swagger.ApiSecurity("bearer"), common.SetMetadata(REQUIRED_NAMESPACES_KEY, namespaces), common.UseInterceptors(exports.AuthInterceptor));
|
|
486
|
+
}
|
|
487
|
+
function HttpVerbToDecorator(verb) {
|
|
488
|
+
const httpToCrud = {
|
|
489
|
+
GET: common.Get,
|
|
490
|
+
POST: common.Post,
|
|
491
|
+
PUT: common.Put,
|
|
492
|
+
PATCH: common.Patch,
|
|
493
|
+
DELETE: common.Delete
|
|
494
|
+
};
|
|
495
|
+
const decorator = httpToCrud[verb];
|
|
496
|
+
if (!decorator) {
|
|
497
|
+
throw new core.UnsupportedError(`Unsupported HTTP verb "${verb}". No NestJS decorator mapping was found.`);
|
|
498
|
+
}
|
|
499
|
+
return decorator;
|
|
500
|
+
}
|
|
501
|
+
const extractPathParams = routePath => routePath.split("/").filter(p => p.startsWith(":")).map(p => p.slice(1));
|
|
502
|
+
const apiParamSpec = name => ({
|
|
503
|
+
name: name,
|
|
504
|
+
description: `${name} parameter for the query`,
|
|
505
|
+
required: true,
|
|
506
|
+
type: String
|
|
507
|
+
});
|
|
508
|
+
function toDecafError(error, fallbackMessage) {
|
|
509
|
+
if (error instanceof dbDecorators.BaseError) return error;
|
|
510
|
+
return new dbDecorators.InternalError(error instanceof Error ? `${fallbackMessage}: ${error.message}` : fallbackMessage);
|
|
511
|
+
}
|
|
512
|
+
function getApiDecorators(methodName, routePath, httpVerb, includeQueryParams = false) {
|
|
513
|
+
const NestHttpRouteDec = HttpVerbToDecorator(httpVerb);
|
|
514
|
+
const apiPathParams = extractPathParams(routePath).map(apiParamSpec);
|
|
515
|
+
const swaggerQueryParams = [];
|
|
516
|
+
if (httpVerb === "GET" && includeQueryParams) {
|
|
517
|
+
swaggerQueryParams.push(swagger.ApiQuery({
|
|
518
|
+
name: "direction",
|
|
519
|
+
required: false,
|
|
520
|
+
enum: core.OrderDirection,
|
|
521
|
+
description: "the sort order when applicable"
|
|
522
|
+
}), swagger.ApiQuery({
|
|
523
|
+
name: "limit",
|
|
524
|
+
required: false,
|
|
525
|
+
description: "limit or page size when applicable"
|
|
526
|
+
}), swagger.ApiQuery({
|
|
527
|
+
name: "offset",
|
|
528
|
+
required: false,
|
|
529
|
+
description: "offset or bookmark when applicable"
|
|
530
|
+
}));
|
|
531
|
+
}
|
|
532
|
+
return {
|
|
533
|
+
method: [ NestHttpRouteDec(routePath), ...apiPathParams.map(swagger.ApiParam), ...swaggerQueryParams, swagger.ApiOperation({
|
|
534
|
+
summary: `Retrieve records using according to "${methodName}".`
|
|
535
|
+
}), swagger.ApiOkResponse({
|
|
536
|
+
description: `Result successfully retrieved.`
|
|
537
|
+
}), swagger.ApiNoContentResponse({
|
|
538
|
+
description: `No content returned by the method.`
|
|
539
|
+
}) ],
|
|
540
|
+
params: [ DecafParams(apiPathParams), common.Query() ]
|
|
541
|
+
};
|
|
542
|
+
}
|
|
543
|
+
function applyApiDecorators(target, methodName, descriptor, decorators) {
|
|
544
|
+
const proto = target?.prototype ?? target;
|
|
545
|
+
decorators.method.forEach(d => d(proto, methodName, descriptor));
|
|
546
|
+
decorators.params?.forEach((d, index) => d(proto, methodName, index));
|
|
547
|
+
}
|
|
548
|
+
function resolvePersistenceMethod(persistence, methodName, ...args) {
|
|
549
|
+
if (persistence instanceof core.ModelService) {
|
|
550
|
+
return typeof persistence[methodName] === "function" ? persistence[methodName](...args) : persistence.statement(methodName, ...args);
|
|
551
|
+
}
|
|
552
|
+
if (typeof persistence[methodName] === "function") return persistence[methodName](...args);
|
|
553
|
+
throw new dbDecorators.InternalError(`Persistence method "${methodName}" not found on ${persistence?.constructor?.name}`);
|
|
554
|
+
}
|
|
555
|
+
function createRouteHandler(methodName) {
|
|
556
|
+
return async function(pathParams, queryParams) {
|
|
557
|
+
const log = this.log.for(methodName);
|
|
558
|
+
try {
|
|
559
|
+
log.debug(`Invoking persistence method "${methodName}" given parameters: ${JSON.stringify(pathParams.valuesInOrder)}`);
|
|
560
|
+
const {direction: direction, limit: limit, offset: offset} = queryParams;
|
|
561
|
+
return await resolvePersistenceMethod(this.persistence(this.ctx), methodName, ...pathParams.valuesInOrder, direction, limit, offset);
|
|
562
|
+
} catch (e) {
|
|
563
|
+
log.error(`Custom query "${methodName}" failed`, e);
|
|
564
|
+
throw toDecafError(e, `Custom query "${methodName}" failed`);
|
|
565
|
+
}
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
function defineRouteMethod(ControllerClass, methodName, handler) {
|
|
569
|
+
Object.defineProperty(ControllerClass.prototype || ControllerClass, methodName, {
|
|
570
|
+
value: handler,
|
|
571
|
+
writable: false
|
|
572
|
+
});
|
|
573
|
+
return Object.getOwnPropertyDescriptor(ControllerClass.prototype || ControllerClass, methodName);
|
|
574
|
+
}
|
|
575
|
+
const REQUEST_CONTEXTUALIZED_KEY = "__decafRequestContextContextualized";
|
|
576
|
+
function contextualizeRequestContext(requestContext, req) {
|
|
577
|
+
if (requestContext.getOrUndefined(REQUEST_CONTEXTUALIZED_KEY)) {
|
|
578
|
+
return false;
|
|
579
|
+
}
|
|
580
|
+
const headers = req.headers;
|
|
581
|
+
const flags = {
|
|
582
|
+
headers: headers,
|
|
583
|
+
overrides: {}
|
|
584
|
+
};
|
|
585
|
+
const ip = extractIp(req);
|
|
586
|
+
const currentLog = requestContext.getOrUndefined("logger");
|
|
587
|
+
const logger = ip ? (currentLog ?? logging.Logging.get()).for({
|
|
588
|
+
ip: ip
|
|
589
|
+
}) : currentLog ?? logging.Logging.get();
|
|
590
|
+
requestContext.accumulate(Object.assign({}, core.DefaultAdapterFlags, {
|
|
591
|
+
logger: logger,
|
|
592
|
+
timestamp: new Date,
|
|
593
|
+
operation: `${req.method} ${req.url}`
|
|
594
|
+
}, flags, {
|
|
595
|
+
[REQUEST_CONTEXTUALIZED_KEY]: true
|
|
596
|
+
}));
|
|
597
|
+
return true;
|
|
598
|
+
}
|
|
599
|
+
function extractIp(req) {
|
|
600
|
+
const headers = req.headers;
|
|
601
|
+
function parseIpHeader(value) {
|
|
602
|
+
if (!value) return undefined;
|
|
603
|
+
const candidate = Array.isArray(value) ? value[0] : value;
|
|
604
|
+
return candidate.split(",").map(segment => segment.trim()).filter(Boolean)[0];
|
|
605
|
+
}
|
|
606
|
+
return parseIpHeader(headers?.["x-forwarded-for"]) ?? parseIpHeader(headers?.["x-real-ip"]) ?? parseIpHeader(headers?.["X-Forwarded-For"]) ?? parseIpHeader(headers?.["X-Real-IP"]) ?? req.ip;
|
|
607
|
+
}
|
|
608
|
+
exports.AuthMiddleware = class AuthMiddleware {
|
|
609
|
+
constructor(authHandler, requestContext) {
|
|
610
|
+
this.authHandler = authHandler;
|
|
611
|
+
this.requestContext = requestContext;
|
|
612
|
+
}
|
|
613
|
+
async use(req, _res, next) {
|
|
614
|
+
contextualizeRequestContext(this.requestContext, req);
|
|
615
|
+
if (this.authHandler) {
|
|
616
|
+
try {
|
|
617
|
+
await this.authHandler.prime(req, this.requestContext);
|
|
618
|
+
} catch {}
|
|
619
|
+
}
|
|
620
|
+
await next();
|
|
621
|
+
}
|
|
622
|
+
};
|
|
623
|
+
exports.AuthMiddleware = tslib.__decorate([ common.Injectable({
|
|
624
|
+
scope: common.Scope.REQUEST
|
|
625
|
+
}), tslib.__param(0, common.Optional()), tslib.__param(0, common.Inject(AUTH_HANDLER)), tslib.__metadata("design:paramtypes", [ Object, exports.DecafRequestContext ]) ], exports.AuthMiddleware);
|
|
626
|
+
class DecafAuthHandler extends server.AuthHandler {
|
|
627
|
+
isPublicRequest(_request) {
|
|
628
|
+
return false;
|
|
629
|
+
}
|
|
630
|
+
parseRequest(req) {
|
|
631
|
+
const userRole = req.headers.authorization?.split(" ")[1];
|
|
632
|
+
return userRole;
|
|
633
|
+
}
|
|
634
|
+
requestFromContext(ctx) {
|
|
635
|
+
return ctx.switchToHttp().getRequest();
|
|
636
|
+
}
|
|
637
|
+
extractFromRequest(req) {
|
|
638
|
+
const userRole = this.parseRequest(req);
|
|
639
|
+
if (!userRole) throw new core.AuthorizationError("Unauthenticated");
|
|
640
|
+
return {
|
|
641
|
+
user: userRole,
|
|
642
|
+
roles: [ userRole ]
|
|
643
|
+
};
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
class DecafRoleAuthHandler extends DecafAuthHandler {}
|
|
647
|
+
var DecafAuthModule_1;
|
|
648
|
+
exports.DecafAuthModule = DecafAuthModule_1 = class DecafAuthModule {
|
|
649
|
+
static forRoot(options = {}) {
|
|
650
|
+
const providers = [ exports.AuthInterceptor, exports.AuthMiddleware ];
|
|
651
|
+
if (options.handler) {
|
|
652
|
+
providers.push(options.handler);
|
|
653
|
+
providers.push({
|
|
654
|
+
provide: AUTH_HANDLER,
|
|
655
|
+
useClass: options.handler
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
if (options.global) {
|
|
659
|
+
providers.push({
|
|
660
|
+
provide: core$1.APP_INTERCEPTOR,
|
|
661
|
+
useExisting: exports.AuthInterceptor
|
|
662
|
+
});
|
|
663
|
+
}
|
|
664
|
+
return {
|
|
665
|
+
module: DecafAuthModule_1,
|
|
666
|
+
global: options.global ?? false,
|
|
667
|
+
providers: providers,
|
|
668
|
+
exports: [ exports.AuthInterceptor, exports.AuthMiddleware, AUTH_HANDLER ]
|
|
669
|
+
};
|
|
670
|
+
}
|
|
671
|
+
configure(consumer) {
|
|
672
|
+
consumer.apply(exports.AuthMiddleware).forRoutes({
|
|
673
|
+
path: "*",
|
|
674
|
+
method: common.RequestMethod.ALL
|
|
675
|
+
});
|
|
676
|
+
}
|
|
677
|
+
};
|
|
678
|
+
exports.DecafAuthModule = DecafAuthModule_1 = tslib.__decorate([ common.Module({}) ], exports.DecafAuthModule);
|
|
679
|
+
var DecafHandlerExecutor_1;
|
|
680
|
+
exports.DecafHandlerExecutor = DecafHandlerExecutor_1 = class DecafHandlerExecutor {
|
|
681
|
+
constructor(handlers, context) {
|
|
682
|
+
this.handlers = handlers;
|
|
683
|
+
this.context = context;
|
|
684
|
+
}
|
|
685
|
+
async exec(req, res) {
|
|
686
|
+
const log = logging.Logging.for(DecafHandlerExecutor_1.name).for(this.exec);
|
|
687
|
+
log.debug(`CONTEXT ${this.context.uuid} running ${this.handlers.length} handlers for request ${req.method} ${req.url}`);
|
|
688
|
+
for (const handler of this.handlers) {
|
|
689
|
+
await handler.handle(this.context, req, res);
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
};
|
|
693
|
+
exports.DecafHandlerExecutor = DecafHandlerExecutor_1 = tslib.__decorate([ common.Injectable({
|
|
694
|
+
scope: common.Scope.REQUEST
|
|
695
|
+
}), tslib.__param(0, common.Inject(DECAF_HANDLERS)), tslib.__metadata("design:paramtypes", [ Array, exports.DecafRequestContext ]) ], exports.DecafHandlerExecutor);
|
|
696
|
+
exports.DecafResponseInterceptor = class DecafResponseInterceptor {
|
|
697
|
+
constructor(ctx) {
|
|
698
|
+
this.ctx = ctx;
|
|
699
|
+
}
|
|
700
|
+
intercept(context, next) {
|
|
701
|
+
let response = context.switchToHttp().getResponse();
|
|
702
|
+
return next.handle().pipe(rxjs.tap(data => {
|
|
703
|
+
response = this.ctx.toResponse(response);
|
|
704
|
+
}));
|
|
705
|
+
}
|
|
706
|
+
};
|
|
707
|
+
exports.DecafResponseInterceptor = tslib.__decorate([ common.Injectable(), tslib.__metadata("design:paramtypes", [ exports.DecafRequestContext ]) ], exports.DecafResponseInterceptor);
|
|
708
|
+
class DecafController extends server.DecafController {
|
|
709
|
+
constructor(clientContext, _name) {
|
|
710
|
+
super(clientContext);
|
|
711
|
+
this.clientContext = clientContext;
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
class DecafModelController extends DecafController {
|
|
715
|
+
constructor(clientContext, _name) {
|
|
716
|
+
super(clientContext, _name);
|
|
717
|
+
this.clientContext = clientContext;
|
|
718
|
+
}
|
|
719
|
+
persistence(ctx) {
|
|
720
|
+
if (!this._persistence) try {
|
|
721
|
+
this._persistence = core.Service.get(this.class);
|
|
722
|
+
} catch {
|
|
723
|
+
try {
|
|
724
|
+
this._persistence = core.ModelService.getService(this.class);
|
|
725
|
+
} catch {
|
|
726
|
+
this._persistence = core.Repository.forModel(this.class);
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
const activeCtx = ctx ?? this.clientContext;
|
|
730
|
+
const overrides = activeCtx.toOverrides();
|
|
731
|
+
return ctx ? this._persistence instanceof core.Repository ? this._persistence.override(overrides) : this._persistence.for(overrides) : this._persistence;
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
const dtoCache = new Map;
|
|
735
|
+
function DtoFor(op, model, stack = new Set) {
|
|
736
|
+
if (!core.TransactionOperationKeys.includes(op)) {
|
|
737
|
+
return model;
|
|
738
|
+
}
|
|
739
|
+
const cache = getDtoCache(op);
|
|
740
|
+
const cached = cache.get(model);
|
|
741
|
+
if (cached) return cached;
|
|
742
|
+
const isUpdateOp = [ dbDecorators.OperationKeys.UPDATE, dbDecorators.BulkCrudOperationKeys.UPDATE_ALL ].includes(op);
|
|
743
|
+
class DynamicDTO {}
|
|
744
|
+
cache.set(model, DynamicDTO);
|
|
745
|
+
Object.defineProperty(DynamicDTO, "name", {
|
|
746
|
+
value: `${logging.toPascalCase(model.name)}${logging.toPascalCase(op)}DTO`
|
|
747
|
+
});
|
|
748
|
+
const pkProp = (() => {
|
|
749
|
+
try {
|
|
750
|
+
return decoratorValidation.Model.pk(model);
|
|
751
|
+
} catch {
|
|
752
|
+
return undefined;
|
|
753
|
+
}
|
|
754
|
+
})();
|
|
755
|
+
const pkPropsMetadata = pkProp ? decoratorValidation.Model.pkProps(model) : undefined;
|
|
756
|
+
const pkDesignType = pkProp ? Reflect.getMetadata("design:type", model.prototype, pkProp) : undefined;
|
|
757
|
+
const pkTypeIsNumeric = pkDesignType === Number || pkDesignType === BigInt;
|
|
758
|
+
const pkIsGenerated = !!pkPropsMetadata?.generated || (pkProp ? decoratorValidation.Model.generatedBySequence(model, pkProp) || isPropertyGeneratedAcrossInheritance(model, pkProp) || pkTypeIsNumeric : false);
|
|
759
|
+
const allProps = Array.from(new Set(decoration.Metadata.properties(model) || []));
|
|
760
|
+
const relations = new Set(decoratorValidation.Model.relations(model) || []);
|
|
761
|
+
const scalarProps = [];
|
|
762
|
+
for (const prop of allProps) {
|
|
763
|
+
if (!prop) continue;
|
|
764
|
+
if (relations.has(prop)) continue;
|
|
765
|
+
if (prop === pkProp && !isUpdateOp && pkIsGenerated) continue;
|
|
766
|
+
if (prop !== pkProp && isPropertyGeneratedAcrossInheritance(model, prop)) continue;
|
|
767
|
+
scalarProps.push(prop);
|
|
768
|
+
}
|
|
769
|
+
for (const prop of scalarProps) {
|
|
770
|
+
const validation = getValidationAcrossInheritance(model, prop);
|
|
771
|
+
const isRequired = !!validation?.[decoratorValidation.ValidationKeys.REQUIRED];
|
|
772
|
+
const typeHint = getTypeAcrossInheritance(model, prop) ?? Reflect.getMetadata("design:type", model.prototype, prop);
|
|
773
|
+
const apiOptions = {
|
|
774
|
+
required: isRequired
|
|
775
|
+
};
|
|
776
|
+
if (typeHint) apiOptions.type = typeHint;
|
|
777
|
+
ApiProperty(apiOptions)(DynamicDTO.prototype, prop);
|
|
778
|
+
const designType = Reflect.getMetadata("design:type", model.prototype, prop) ?? typeHint;
|
|
779
|
+
if (typeof designType !== "undefined") {
|
|
780
|
+
Reflect.defineMetadata("design:type", designType, DynamicDTO.prototype, prop);
|
|
781
|
+
}
|
|
782
|
+
Object.defineProperty(DynamicDTO.prototype, prop, {
|
|
783
|
+
value: undefined,
|
|
784
|
+
writable: true,
|
|
785
|
+
enumerable: true,
|
|
786
|
+
configurable: true
|
|
787
|
+
});
|
|
788
|
+
}
|
|
789
|
+
for (const relation of relations) {
|
|
790
|
+
const relationMeta = decoration.Metadata.relations(model, relation);
|
|
791
|
+
if (!relationMeta) {
|
|
792
|
+
throw new dbDecorators.InternalError(`Metadata for relation ${relation} not found`);
|
|
793
|
+
}
|
|
794
|
+
let relationType = relationMeta.class;
|
|
795
|
+
if (typeof relationType === "function" && !relationType.name) {
|
|
796
|
+
relationType = relationType();
|
|
797
|
+
}
|
|
798
|
+
if (!relationType || typeof relationType !== "function") {
|
|
799
|
+
throw new dbDecorators.InternalError(`Type for relation ${relation} not found`);
|
|
800
|
+
}
|
|
801
|
+
if (!decoratorValidation.Model.get(relationType.name)) {
|
|
802
|
+
continue;
|
|
803
|
+
}
|
|
804
|
+
const meta = decoration.Metadata.validationFor(model, relation);
|
|
805
|
+
const isArray = !!meta?.[decoratorValidation.ValidationKeys.LIST];
|
|
806
|
+
const isRequired = !!meta?.[decoratorValidation.ValidationKeys.REQUIRED];
|
|
807
|
+
const isCircular = stack.has(relationType);
|
|
808
|
+
if (isCircular) {
|
|
809
|
+
const pkTypeName = getPkOpenApiType(relationType);
|
|
810
|
+
addRelationPkRef(DynamicDTO, relation, pkTypeName, isArray, isRequired);
|
|
811
|
+
continue;
|
|
812
|
+
}
|
|
813
|
+
const relationDto = DtoFor(op, relationType, new Set(stack).add(model));
|
|
814
|
+
if (isUpdateOp) {
|
|
815
|
+
addRelationUpdate(DynamicDTO, relation, relationType, relationDto, isArray, isRequired);
|
|
816
|
+
} else {
|
|
817
|
+
addRelation(DynamicDTO, relation, relationDto, isArray, isRequired);
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
return DynamicDTO;
|
|
821
|
+
}
|
|
822
|
+
function addRelation(DtoClass, relation, relationDto, isArray, isRequired) {
|
|
823
|
+
const apiOptions = {
|
|
824
|
+
type: relationDto,
|
|
825
|
+
required: isRequired,
|
|
826
|
+
isArray: isArray
|
|
827
|
+
};
|
|
828
|
+
ApiProperty(apiOptions)(DtoClass.prototype, relation);
|
|
829
|
+
Reflect.defineMetadata("design:type", isArray ? Array : relationDto, DtoClass.prototype, relation);
|
|
830
|
+
Object.defineProperty(DtoClass.prototype, relation, {
|
|
831
|
+
value: undefined,
|
|
832
|
+
writable: true,
|
|
833
|
+
enumerable: true,
|
|
834
|
+
configurable: true
|
|
835
|
+
});
|
|
836
|
+
}
|
|
837
|
+
function addRelationPkRef(DtoClass, relation, pkTypeName, isArray, isRequired) {
|
|
838
|
+
const apiOptions = isArray ? {
|
|
839
|
+
type: "array",
|
|
840
|
+
items: {
|
|
841
|
+
type: pkTypeName
|
|
842
|
+
},
|
|
843
|
+
required: isRequired
|
|
844
|
+
} : {
|
|
845
|
+
type: pkTypeName === "integer" ? Number : String,
|
|
846
|
+
required: isRequired
|
|
847
|
+
};
|
|
848
|
+
ApiProperty(apiOptions)(DtoClass.prototype, relation);
|
|
849
|
+
Reflect.defineMetadata("design:type", isArray ? Array : pkTypeName === "integer" ? Number : String, DtoClass.prototype, relation);
|
|
850
|
+
Object.defineProperty(DtoClass.prototype, relation, {
|
|
851
|
+
value: undefined,
|
|
852
|
+
writable: true,
|
|
853
|
+
enumerable: true,
|
|
854
|
+
configurable: true
|
|
855
|
+
});
|
|
856
|
+
}
|
|
857
|
+
function addRelationUpdate(DtoClass, relation, relationType, relationDto, isArray, isRequired) {
|
|
858
|
+
const extraModels = Reflect.getMetadata(DECORATORS.API_EXTRA_MODELS, DtoClass) || [];
|
|
859
|
+
if (!extraModels.includes(relationDto)) {
|
|
860
|
+
Reflect.defineMetadata(DECORATORS.API_EXTRA_MODELS, [ ...extraModels, relationDto ], DtoClass);
|
|
861
|
+
}
|
|
862
|
+
const dtoRef = `#/components/schemas/${relationDto.name}`;
|
|
863
|
+
const pkTypeName = getPkOpenApiType(relationType);
|
|
864
|
+
const oneOfItems = [ {
|
|
865
|
+
$ref: dtoRef
|
|
866
|
+
}, {
|
|
867
|
+
type: pkTypeName
|
|
868
|
+
} ];
|
|
869
|
+
const apiOptions = isArray ? {
|
|
870
|
+
type: "array",
|
|
871
|
+
required: isRequired,
|
|
872
|
+
oneOf: oneOfItems
|
|
873
|
+
} : {
|
|
874
|
+
type: Object,
|
|
875
|
+
required: isRequired,
|
|
876
|
+
oneOf: oneOfItems
|
|
877
|
+
};
|
|
878
|
+
ApiProperty(apiOptions)(DtoClass.prototype, relation);
|
|
879
|
+
Reflect.defineMetadata("design:type", isArray ? Array : Object, DtoClass.prototype, relation);
|
|
880
|
+
Object.defineProperty(DtoClass.prototype, relation, {
|
|
881
|
+
value: undefined,
|
|
882
|
+
writable: true,
|
|
883
|
+
enumerable: true,
|
|
884
|
+
configurable: true
|
|
885
|
+
});
|
|
886
|
+
}
|
|
887
|
+
function getPkOpenApiType(relationType) {
|
|
888
|
+
try {
|
|
889
|
+
const pkPropsMetadata = decoratorValidation.Model.pkProps(relationType);
|
|
890
|
+
const pkType = pkPropsMetadata?.type;
|
|
891
|
+
if (pkType === Number || pkType === BigInt) return "integer";
|
|
892
|
+
return "string";
|
|
893
|
+
} catch {
|
|
894
|
+
return "string";
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
function isPropertyGeneratedAcrossInheritance(model, prop) {
|
|
898
|
+
let current = model;
|
|
899
|
+
while (current && current !== Object && current !== Function) {
|
|
900
|
+
if (decoratorValidation.Model.generated(current, prop)) return true;
|
|
901
|
+
current = Object.getPrototypeOf(current);
|
|
902
|
+
}
|
|
903
|
+
return false;
|
|
904
|
+
}
|
|
905
|
+
function getValidationAcrossInheritance(model, prop) {
|
|
906
|
+
let current = model;
|
|
907
|
+
while (current && current !== Object && current !== Function) {
|
|
908
|
+
const validation = decoration.Metadata.validationFor(current, prop);
|
|
909
|
+
if (validation) return validation;
|
|
910
|
+
current = Object.getPrototypeOf(current);
|
|
911
|
+
}
|
|
912
|
+
return undefined;
|
|
913
|
+
}
|
|
914
|
+
function getTypeAcrossInheritance(model, prop) {
|
|
915
|
+
let current = model;
|
|
916
|
+
while (current && current !== Object && current !== Function) {
|
|
917
|
+
const type = decoration.Metadata.type(current, prop);
|
|
918
|
+
if (type) return type;
|
|
919
|
+
current = Object.getPrototypeOf(current);
|
|
920
|
+
}
|
|
921
|
+
return undefined;
|
|
922
|
+
}
|
|
923
|
+
function getDtoCache(op) {
|
|
924
|
+
if (!dtoCache.has(op)) {
|
|
925
|
+
dtoCache.set(op, new WeakMap);
|
|
926
|
+
}
|
|
927
|
+
return dtoCache.get(op);
|
|
928
|
+
}
|
|
929
|
+
core.Adapter.transformerFor = function toContextFlags(adapter) {
|
|
930
|
+
const alias = typeof adapter === "string" ? adapter : adapter.alias;
|
|
931
|
+
return decoration.Metadata["innerGet"](Symbol.for("transformers"), alias);
|
|
932
|
+
}.bind(core.Adapter);
|
|
933
|
+
core.Adapter.flavoursToTransform = function requestTransformers() {
|
|
934
|
+
const meta = decoration.Metadata["innerGet"](Symbol.for("transformers"));
|
|
935
|
+
if (!meta) return undefined;
|
|
936
|
+
return Object.keys(meta);
|
|
937
|
+
}.bind(core.Adapter);
|
|
938
|
+
core.Context.prototype.toResponse = function toResponse(res) {
|
|
939
|
+
const pending = this.pending();
|
|
940
|
+
if (pending) res.header("x-pending-task", JSON.stringify(pending));
|
|
941
|
+
return res;
|
|
942
|
+
};
|
|
943
|
+
const prototype = decoratorValidation.ModelBuilder.prototype;
|
|
944
|
+
if (!prototype.decorateClass) {
|
|
945
|
+
prototype.decorateClass = function(decorator) {
|
|
946
|
+
if (!this._classDecorators) {
|
|
947
|
+
this._classDecorators = [];
|
|
948
|
+
}
|
|
949
|
+
this._classDecorators.push(decorator);
|
|
950
|
+
return this;
|
|
951
|
+
};
|
|
952
|
+
}
|
|
953
|
+
prototype.Auth = function(model) {
|
|
954
|
+
return this.decorateClass(Auth(model));
|
|
955
|
+
};
|
|
956
|
+
if (!prototype.__hasClassDecoratorSupport) {
|
|
957
|
+
const originalBuild = prototype.build;
|
|
958
|
+
prototype.build = function() {
|
|
959
|
+
let result = originalBuild.call(this);
|
|
960
|
+
const decorators = this._classDecorators;
|
|
961
|
+
if (decorators?.length) {
|
|
962
|
+
for (const decorator of decorators) {
|
|
963
|
+
const decorated = decorator(result);
|
|
964
|
+
if (decorated) {
|
|
965
|
+
result = decorated;
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
return result;
|
|
970
|
+
};
|
|
971
|
+
prototype.__hasClassDecoratorSupport = true;
|
|
972
|
+
}
|
|
973
|
+
var DynamicModelController_1;
|
|
974
|
+
class FromModelController {
|
|
975
|
+
static {
|
|
976
|
+
this.log = logging.Logging.for(FromModelController.name);
|
|
977
|
+
}
|
|
978
|
+
static toDecafError(error, fallbackMessage) {
|
|
979
|
+
if (error instanceof dbDecorators.BaseError) return error;
|
|
980
|
+
return new dbDecorators.InternalError(error instanceof Error ? `${fallbackMessage}: ${error.message}` : fallbackMessage);
|
|
981
|
+
}
|
|
982
|
+
static getPersistence(ModelClazz) {
|
|
983
|
+
try {
|
|
984
|
+
return core.Service.get(ModelClazz);
|
|
985
|
+
} catch (e) {
|
|
986
|
+
try {
|
|
987
|
+
return core.ModelService.getService(ModelClazz);
|
|
988
|
+
} catch (e2) {
|
|
989
|
+
return core.Repository.forModel(ModelClazz);
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
static createQueryRoutesFromRepository(persistence, prefix = core.PersistenceKeys.QUERY) {
|
|
994
|
+
const repo = persistence instanceof core.ModelService ? persistence.repo : persistence;
|
|
995
|
+
const queryMethods = decoration.Metadata.get(repo.constructor, decoration.Metadata.key(core.PersistenceKeys.QUERY)) ?? {};
|
|
996
|
+
const routeMethods = decoration.Metadata.get(persistence.constructor, decoration.Metadata.key(DECAF_ROUTE)) ?? {};
|
|
997
|
+
class QueryController extends DecafModelController {
|
|
998
|
+
get class() {
|
|
999
|
+
throw new dbDecorators.InternalError("Method not implemented.");
|
|
1000
|
+
}
|
|
1001
|
+
constructor(clientContext, name) {
|
|
1002
|
+
super(clientContext, name);
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
for (const [methodName, params] of Object.entries(routeMethods)) {
|
|
1006
|
+
const routePath = [ params.path.replace(/^\/+|\/+$/g, "") ].filter(segment => segment && segment.trim()).join("/");
|
|
1007
|
+
const handler = FromModelController.createComplexQueryHandler(methodName);
|
|
1008
|
+
FromModelController.defineMethod(QueryController, methodName, handler);
|
|
1009
|
+
const httpDecorator = HttpVerbToDecorator(params.httpMethod)(routePath || undefined);
|
|
1010
|
+
const decorators = FromModelController.getQueryDecorators(methodName, routePath, params.httpMethod);
|
|
1011
|
+
FromModelController.applyDecorators(QueryController, methodName, [ httpDecorator, ...decorators ]);
|
|
1012
|
+
}
|
|
1013
|
+
for (const [methodName, objValues] of Object.entries(queryMethods)) {
|
|
1014
|
+
const fields = objValues.fields ?? [];
|
|
1015
|
+
const routePath = [ prefix, methodName, ...fields.map(f => `:${f}`) ].filter(segment => segment && segment.trim()).join("/");
|
|
1016
|
+
const handler = FromModelController.createComplexQueryHandler(methodName);
|
|
1017
|
+
FromModelController.defineMethod(QueryController, methodName, handler);
|
|
1018
|
+
const httpDecorator = HttpVerbToDecorator("GET")(routePath || undefined);
|
|
1019
|
+
const decorators = FromModelController.getQueryDecorators(methodName, routePath, "GET", true);
|
|
1020
|
+
FromModelController.applyDecorators(QueryController, methodName, [ httpDecorator, ...decorators ]);
|
|
1021
|
+
}
|
|
1022
|
+
return QueryController;
|
|
1023
|
+
}
|
|
1024
|
+
static create(ModelConstr, moduleConfigOverrides, globalDefaults) {
|
|
1025
|
+
const log = FromModelController.log.for(FromModelController.create);
|
|
1026
|
+
const tableName = decoratorValidation.Model.tableName(ModelConstr);
|
|
1027
|
+
const routePath = logging.toKebabCase(tableName);
|
|
1028
|
+
const modelClazzName = ModelConstr.name;
|
|
1029
|
+
const persistence = FromModelController.getPersistence(ModelConstr);
|
|
1030
|
+
const factoryPersistence = persistence instanceof core.ModelService ? persistence.repo : persistence;
|
|
1031
|
+
const decoratorConfig = decoration.Metadata.get(ModelConstr, decoration.Metadata.key(DECAF_CONTROLLER_CONFIG));
|
|
1032
|
+
const moduleOverride = moduleConfigOverrides?.[ModelConstr.name];
|
|
1033
|
+
const mergedConfig = {
|
|
1034
|
+
...globalDefaults || {},
|
|
1035
|
+
...decoratorConfig || {},
|
|
1036
|
+
...moduleOverride || {}
|
|
1037
|
+
};
|
|
1038
|
+
const FactoryController = server.ModelControllerFactory.create(ModelConstr, factoryPersistence, mergedConfig);
|
|
1039
|
+
const factoryRoutes = FactoryController.__routes__;
|
|
1040
|
+
const {getPK: getPK, apiProperties: apiProperties, path: pkPath} = FromModelController.getRouteParametersFromModel(ModelConstr);
|
|
1041
|
+
log.debug(`Creating controller for model: ${modelClazzName} with ${factoryRoutes?.length ?? 0} factory routes`);
|
|
1042
|
+
const authConfig = mergedConfig.auth;
|
|
1043
|
+
function applyClassAuth(target) {
|
|
1044
|
+
if (authConfig?.public) {
|
|
1045
|
+
Public()(target);
|
|
1046
|
+
} else if (authConfig?.roles?.length) {
|
|
1047
|
+
RequireRoles(...authConfig.roles)(target);
|
|
1048
|
+
} else {
|
|
1049
|
+
Auth(ModelConstr)(target);
|
|
1050
|
+
}
|
|
1051
|
+
if (authConfig?.namespaces?.length) {
|
|
1052
|
+
RequireNamespaces(...authConfig.namespaces)(target);
|
|
1053
|
+
}
|
|
1054
|
+
if (authConfig?.skipModelRoles) {
|
|
1055
|
+
common.SetMetadata(SKIP_MODEL_ROLES_KEY, true)(target);
|
|
1056
|
+
}
|
|
1057
|
+
if (authConfig?.skipModelNamespaces) {
|
|
1058
|
+
common.SetMetadata(SKIP_MODEL_NAMESPACES_KEY, true)(target);
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
let DynamicModelController = DynamicModelController_1 = class DynamicModelController extends DecafModelController {
|
|
1062
|
+
static get class() {
|
|
1063
|
+
return ModelConstr;
|
|
1064
|
+
}
|
|
1065
|
+
get class() {
|
|
1066
|
+
return ModelConstr;
|
|
1067
|
+
}
|
|
1068
|
+
constructor(clientContext) {
|
|
1069
|
+
super(clientContext, DynamicModelController_1.name);
|
|
1070
|
+
this.pk = decoratorValidation.Model.pk(ModelConstr);
|
|
1071
|
+
log.info(`Registering dynamic controller for model: ${this.class.name} route: /${routePath}`);
|
|
1072
|
+
}
|
|
1073
|
+
};
|
|
1074
|
+
DynamicModelController = DynamicModelController_1 = tslib.__decorate([ common.Controller(routePath), swagger.ApiTags(modelClazzName), swagger.ApiExtraModels(ModelConstr), tslib.__metadata("design:paramtypes", [ exports.DecafRequestContext ]) ], DynamicModelController);
|
|
1075
|
+
applyClassAuth(DynamicModelController);
|
|
1076
|
+
if (factoryRoutes) {
|
|
1077
|
+
const sortedRoutes = [ ...factoryRoutes ].sort((a, b) => {
|
|
1078
|
+
const aSegments = a.path.split("/").filter(Boolean);
|
|
1079
|
+
const bSegments = b.path.split("/").filter(Boolean);
|
|
1080
|
+
const aParamCount = aSegments.filter(s => s.startsWith(":")).length;
|
|
1081
|
+
const bParamCount = bSegments.filter(s => s.startsWith(":")).length;
|
|
1082
|
+
const aLiteralCount = aSegments.length - aParamCount;
|
|
1083
|
+
const bLiteralCount = bSegments.length - bParamCount;
|
|
1084
|
+
if (aLiteralCount !== bLiteralCount) return bLiteralCount - aLiteralCount;
|
|
1085
|
+
if (aParamCount !== bParamCount) return aParamCount - bParamCount;
|
|
1086
|
+
return 0;
|
|
1087
|
+
});
|
|
1088
|
+
for (const route of sortedRoutes) {
|
|
1089
|
+
const methodName = route.implementation?.name || route.method.toLowerCase();
|
|
1090
|
+
const registration = FromModelController.matchRoute(methodName, route, pkPath, apiProperties, getPK, ModelConstr, modelClazzName);
|
|
1091
|
+
if (!registration) continue;
|
|
1092
|
+
const {methodName: registeredMethodName, handler: handler, decorators: decorators, paramDecorators: paramDecorators} = registration;
|
|
1093
|
+
const descriptor = FromModelController.defineMethod(DynamicModelController, registeredMethodName, handler);
|
|
1094
|
+
if (descriptor) {
|
|
1095
|
+
const httpDecorator = HttpVerbToDecorator(route.method)(route.path.replace(/^\/+|\/+$/g, "") || undefined);
|
|
1096
|
+
FromModelController.applyDecorators(DynamicModelController, registeredMethodName, [ httpDecorator, ...decorators ], paramDecorators);
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
return DynamicModelController;
|
|
1101
|
+
}
|
|
1102
|
+
static getRouteParametersFromModel(ModelClazz) {
|
|
1103
|
+
const pk = decoratorValidation.Model.pk(ModelClazz);
|
|
1104
|
+
const composed = decoration.Metadata.get(ModelClazz, decoration.Metadata.key(dbDecorators.DBKeys.COMPOSED, pk));
|
|
1105
|
+
const composedKeys = composed?.args ?? [];
|
|
1106
|
+
const uniqueKeys = Array.isArray(composedKeys) && composedKeys.length > 0 ? Array.from(new Set([ ...composedKeys ])) : Array.from(new Set([ pk ]));
|
|
1107
|
+
const description = decoration.Metadata.description(ModelClazz) ?? "";
|
|
1108
|
+
const path = `:${uniqueKeys.join("/:")}`;
|
|
1109
|
+
const apiProperties = uniqueKeys.map(key => ({
|
|
1110
|
+
name: key,
|
|
1111
|
+
description: decoration.Metadata.description(ModelClazz, key),
|
|
1112
|
+
required: true,
|
|
1113
|
+
type: String
|
|
1114
|
+
}));
|
|
1115
|
+
return {
|
|
1116
|
+
path: path,
|
|
1117
|
+
description: description,
|
|
1118
|
+
apiProperties: apiProperties,
|
|
1119
|
+
getPK: (...params) => composed?.separator ? params.join(composed.separator) : params.join("")
|
|
1120
|
+
};
|
|
1121
|
+
}
|
|
1122
|
+
static routeParamDecorators(path) {
|
|
1123
|
+
let paramIndex = 0;
|
|
1124
|
+
return path.split("/").filter(Boolean).flatMap(segment => {
|
|
1125
|
+
if (segment.startsWith(":")) {
|
|
1126
|
+
return [ {
|
|
1127
|
+
decorator: common.Param(segment.slice(1)),
|
|
1128
|
+
index: paramIndex++
|
|
1129
|
+
} ];
|
|
1130
|
+
}
|
|
1131
|
+
if (segment.startsWith("*")) {
|
|
1132
|
+
return [ {
|
|
1133
|
+
decorator: common.Param(segment.slice(1)),
|
|
1134
|
+
index: paramIndex++
|
|
1135
|
+
} ];
|
|
1136
|
+
}
|
|
1137
|
+
return [];
|
|
1138
|
+
});
|
|
1139
|
+
}
|
|
1140
|
+
static defineMethod(target, methodName, handler) {
|
|
1141
|
+
Object.defineProperty(target.prototype || target, methodName, {
|
|
1142
|
+
value: handler,
|
|
1143
|
+
writable: false,
|
|
1144
|
+
configurable: true,
|
|
1145
|
+
enumerable: false
|
|
1146
|
+
});
|
|
1147
|
+
return Object.getOwnPropertyDescriptor(target.prototype || target, methodName);
|
|
1148
|
+
}
|
|
1149
|
+
static applyDecorators(target, methodName, methodDecorators, paramDecorators = []) {
|
|
1150
|
+
const proto = target?.prototype ?? target;
|
|
1151
|
+
const descriptor = Object.getOwnPropertyDescriptor(proto, methodName);
|
|
1152
|
+
methodDecorators.forEach(d => d(proto, methodName, descriptor));
|
|
1153
|
+
paramDecorators.forEach(({decorator: decorator, index: index}) => decorator(proto, methodName, index));
|
|
1154
|
+
}
|
|
1155
|
+
static matchRoute(methodName, route, pkPath, apiProperties, getPK, ModelConstr, modelClazzName) {
|
|
1156
|
+
const {method: method, path: path} = route;
|
|
1157
|
+
const normalizedPath = path.replace(/^\/+|\/+$/g, "");
|
|
1158
|
+
const handler = route.implementation;
|
|
1159
|
+
if (method === "POST" && normalizedPath === "") {
|
|
1160
|
+
return FromModelController.createRegistration("create", handler, FromModelController.createCreateDecorators(ModelConstr, modelClazzName), [ {
|
|
1161
|
+
decorator: DecafBody(),
|
|
1162
|
+
index: 0
|
|
1163
|
+
}, {
|
|
1164
|
+
decorator: common.Response({
|
|
1165
|
+
passthrough: true
|
|
1166
|
+
}),
|
|
1167
|
+
index: 1
|
|
1168
|
+
} ]);
|
|
1169
|
+
}
|
|
1170
|
+
if (method === "POST" && normalizedPath === "bulk") {
|
|
1171
|
+
return FromModelController.createRegistration("createAll", handler, FromModelController.bulkCreateDecorators(ModelConstr, modelClazzName), [ {
|
|
1172
|
+
decorator: DecafBody(),
|
|
1173
|
+
index: 0
|
|
1174
|
+
}, {
|
|
1175
|
+
decorator: common.Response({
|
|
1176
|
+
passthrough: true
|
|
1177
|
+
}),
|
|
1178
|
+
index: 1
|
|
1179
|
+
} ]);
|
|
1180
|
+
}
|
|
1181
|
+
if (method === "GET" && normalizedPath === "bulk") {
|
|
1182
|
+
return FromModelController.createRegistration("readAll", handler, FromModelController.bulkReadDecorators(ModelConstr, modelClazzName), [ {
|
|
1183
|
+
decorator: common.Query("ids"),
|
|
1184
|
+
index: 0
|
|
1185
|
+
} ]);
|
|
1186
|
+
}
|
|
1187
|
+
if (method === "PUT" && normalizedPath === "bulk") {
|
|
1188
|
+
return FromModelController.createRegistration("updateAll", handler, FromModelController.bulkUpdateDecorators(ModelConstr, modelClazzName, apiProperties), [ {
|
|
1189
|
+
decorator: DecafBody(),
|
|
1190
|
+
index: 0
|
|
1191
|
+
}, {
|
|
1192
|
+
decorator: common.Response({
|
|
1193
|
+
passthrough: true
|
|
1194
|
+
}),
|
|
1195
|
+
index: 1
|
|
1196
|
+
} ]);
|
|
1197
|
+
}
|
|
1198
|
+
if (method === "DELETE" && normalizedPath === "bulk") {
|
|
1199
|
+
return FromModelController.createRegistration("deleteAll", handler, FromModelController.bulkDeleteDecorators(ModelConstr, modelClazzName, apiProperties), [ {
|
|
1200
|
+
decorator: common.Query("ids"),
|
|
1201
|
+
index: 0
|
|
1202
|
+
}, {
|
|
1203
|
+
decorator: common.Response({
|
|
1204
|
+
passthrough: true
|
|
1205
|
+
}),
|
|
1206
|
+
index: 1
|
|
1207
|
+
} ]);
|
|
1208
|
+
}
|
|
1209
|
+
if (method === "GET" && normalizedPath === pkPath) {
|
|
1210
|
+
return FromModelController.createRegistration("read", handler, FromModelController.readDecorators(ModelConstr, modelClazzName, apiProperties, pkPath), FromModelController.routeParamDecorators(normalizedPath));
|
|
1211
|
+
}
|
|
1212
|
+
if (method === "PUT" && normalizedPath === pkPath) {
|
|
1213
|
+
const routeParams = FromModelController.routeParamDecorators(normalizedPath);
|
|
1214
|
+
return FromModelController.createRegistration("update", handler, FromModelController.updateDecorators(ModelConstr, modelClazzName, apiProperties, pkPath), [ {
|
|
1215
|
+
decorator: DecafBody(),
|
|
1216
|
+
index: 0
|
|
1217
|
+
}, ...routeParams.map(({decorator: decorator, index: index}) => ({
|
|
1218
|
+
decorator: decorator,
|
|
1219
|
+
index: index + 1
|
|
1220
|
+
})) ]);
|
|
1221
|
+
}
|
|
1222
|
+
if (method === "DELETE" && normalizedPath === pkPath) {
|
|
1223
|
+
const routeParams = FromModelController.routeParamDecorators(normalizedPath);
|
|
1224
|
+
return FromModelController.createRegistration("delete", handler, FromModelController.deleteDecorators(ModelConstr, modelClazzName, apiProperties, pkPath), routeParams);
|
|
1225
|
+
}
|
|
1226
|
+
const fallbackSegments = normalizedPath.split("/").filter(Boolean);
|
|
1227
|
+
const isAllParams = fallbackSegments.length > 0 && fallbackSegments.every(s => s.startsWith(":"));
|
|
1228
|
+
if (isAllParams && normalizedPath !== pkPath) {
|
|
1229
|
+
const fallbackApiProps = fallbackSegments.map(s => s.slice(1)).map(name => ({
|
|
1230
|
+
name: name,
|
|
1231
|
+
description: `${name} parameter`,
|
|
1232
|
+
required: true,
|
|
1233
|
+
type: String
|
|
1234
|
+
}));
|
|
1235
|
+
const suffix = fallbackSegments.map(s => s.slice(1)).join("And");
|
|
1236
|
+
const routeParams = FromModelController.routeParamDecorators(normalizedPath);
|
|
1237
|
+
if (method === "GET") {
|
|
1238
|
+
return FromModelController.createRegistration(`readBy${suffix}`, handler, FromModelController.readDecorators(ModelConstr, modelClazzName, fallbackApiProps, normalizedPath), routeParams);
|
|
1239
|
+
}
|
|
1240
|
+
if (method === "PUT") {
|
|
1241
|
+
return FromModelController.createRegistration(`updateBy${suffix}`, handler, FromModelController.updateDecorators(ModelConstr, modelClazzName, fallbackApiProps, normalizedPath), [ {
|
|
1242
|
+
decorator: DecafBody(),
|
|
1243
|
+
index: 0
|
|
1244
|
+
}, ...routeParams.map(({decorator: decorator, index: index}) => ({
|
|
1245
|
+
decorator: decorator,
|
|
1246
|
+
index: index + 1
|
|
1247
|
+
})) ]);
|
|
1248
|
+
}
|
|
1249
|
+
if (method === "DELETE") {
|
|
1250
|
+
return FromModelController.createRegistration(`deleteBy${suffix}`, handler, FromModelController.deleteDecorators(ModelConstr, modelClazzName, fallbackApiProps, normalizedPath), routeParams);
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1253
|
+
if (method === "GET" && normalizedPath === "statement/:method/*args") {
|
|
1254
|
+
return FromModelController.createRegistration("statement", handler, FromModelController.statementDecorators(ModelConstr, modelClazzName), [ {
|
|
1255
|
+
decorator: common.Param("method"),
|
|
1256
|
+
index: 0
|
|
1257
|
+
}, {
|
|
1258
|
+
decorator: common.Param("args"),
|
|
1259
|
+
index: 1
|
|
1260
|
+
}, {
|
|
1261
|
+
decorator: DecafQuery(),
|
|
1262
|
+
index: 2
|
|
1263
|
+
} ]);
|
|
1264
|
+
}
|
|
1265
|
+
if (method === "GET" && normalizedPath === "findOneBy/:key/:value") {
|
|
1266
|
+
return FromModelController.createRegistration("findOneBy", handler, FromModelController.statementShortcutDecorators(ModelConstr, modelClazzName, normalizedPath, core.PreparedStatementKeys.FIND_ONE_BY), FromModelController.statementShortcutParams(normalizedPath));
|
|
1267
|
+
}
|
|
1268
|
+
const statementRoutes = {
|
|
1269
|
+
"listBy/:key": core.PreparedStatementKeys.LIST_BY,
|
|
1270
|
+
"paginateBy/:key/:page": core.PreparedStatementKeys.PAGE_BY,
|
|
1271
|
+
"find/:value": core.PreparedStatementKeys.FIND,
|
|
1272
|
+
"page/:value": core.PreparedStatementKeys.PAGE,
|
|
1273
|
+
"findOneBy/:key/:value": core.PreparedStatementKeys.FIND_ONE_BY,
|
|
1274
|
+
"findBy/:key/:value": core.PreparedStatementKeys.FIND_BY,
|
|
1275
|
+
"countOf/:field": core.PreparedStatementKeys.COUNT_OF,
|
|
1276
|
+
"maxOf/:field": core.PreparedStatementKeys.MAX_OF,
|
|
1277
|
+
"minOf/:field": core.PreparedStatementKeys.MIN_OF,
|
|
1278
|
+
"avgOf/:field": core.PreparedStatementKeys.AVG_OF,
|
|
1279
|
+
"sumOf/:field": core.PreparedStatementKeys.SUM_OF,
|
|
1280
|
+
"distinctOf/:field": core.PreparedStatementKeys.DISTINCT_OF,
|
|
1281
|
+
"groupOf/:field": core.PreparedStatementKeys.GROUP_OF
|
|
1282
|
+
};
|
|
1283
|
+
const statementKey = statementRoutes[normalizedPath];
|
|
1284
|
+
if (statementKey && method === "GET") {
|
|
1285
|
+
return FromModelController.createRegistration(FromModelController.statementMethodName(normalizedPath), handler, FromModelController.statementShortcutDecorators(ModelConstr, modelClazzName, normalizedPath, statementKey), FromModelController.statementShortcutParams(normalizedPath));
|
|
1286
|
+
}
|
|
1287
|
+
if (method === "GET" && normalizedPath.startsWith("query/")) {
|
|
1288
|
+
const queryMethod = normalizedPath.replace(/^query\//, "").split("/")[0];
|
|
1289
|
+
return FromModelController.createRegistration(queryMethod, handler, FromModelController.getQueryDecorators(queryMethod, normalizedPath, "GET", true), FromModelController.complexQueryParams(normalizedPath));
|
|
1290
|
+
}
|
|
1291
|
+
const pathSegments = normalizedPath.split("/").filter(Boolean);
|
|
1292
|
+
const knownPrefixes = new Set([ "listBy", "findBy", "findByPaginate", "findOneBy", "paginateBy", "find", "page", "countOf", "maxOf", "minOf", "avgOf", "sumOf", "distinctOf", "groupOf", "statement", "bulk", "query" ]);
|
|
1293
|
+
if (pathSegments.length > 0 && !normalizedPath.startsWith("query/") && !normalizedPath.startsWith("statement/") && !knownPrefixes.has(pathSegments[0])) {
|
|
1294
|
+
const apiPathParams = pathSegments.filter(s => s.startsWith(":")).map(s => s.slice(1)).map(name => ({
|
|
1295
|
+
name: name,
|
|
1296
|
+
description: `${name} parameter for the query`,
|
|
1297
|
+
required: true,
|
|
1298
|
+
type: String
|
|
1299
|
+
}));
|
|
1300
|
+
return FromModelController.createRegistration(methodName, handler, [ ...apiPathParams.map(p => swagger.ApiParam(p)), swagger.ApiOperation({
|
|
1301
|
+
summary: `Retrieve records using "${methodName}".`
|
|
1302
|
+
}), swagger.ApiOkResponse({
|
|
1303
|
+
description: "Result successfully retrieved."
|
|
1304
|
+
}), swagger.ApiNoContentResponse({
|
|
1305
|
+
description: "No content returned by the method."
|
|
1306
|
+
}) ], FromModelController.routeParamDecorators(normalizedPath));
|
|
1307
|
+
}
|
|
1308
|
+
return undefined;
|
|
1309
|
+
}
|
|
1310
|
+
static createRegistration(methodName, handler, decorators, paramDecorators) {
|
|
1311
|
+
return {
|
|
1312
|
+
methodName: methodName,
|
|
1313
|
+
handler: handler,
|
|
1314
|
+
decorators: decorators,
|
|
1315
|
+
paramDecorators: paramDecorators
|
|
1316
|
+
};
|
|
1317
|
+
}
|
|
1318
|
+
static statementMethodName(path) {
|
|
1319
|
+
const firstSegment = path.split("/")[0];
|
|
1320
|
+
return firstSegment;
|
|
1321
|
+
}
|
|
1322
|
+
static statementShortcutParams(path) {
|
|
1323
|
+
const segments = path.split("/").filter(s => s.startsWith(":"));
|
|
1324
|
+
const params = [];
|
|
1325
|
+
segments.forEach((seg, i) => {
|
|
1326
|
+
const name = seg.replace(":", "");
|
|
1327
|
+
params.push({
|
|
1328
|
+
decorator: common.Param(name),
|
|
1329
|
+
index: i
|
|
1330
|
+
});
|
|
1331
|
+
});
|
|
1332
|
+
if (path.startsWith("listBy/") || path.startsWith("paginateBy/") || path.startsWith("find/") || path.startsWith("page/")) {
|
|
1333
|
+
params.push({
|
|
1334
|
+
decorator: DecafQuery(),
|
|
1335
|
+
index: segments.length
|
|
1336
|
+
});
|
|
1337
|
+
}
|
|
1338
|
+
return params;
|
|
1339
|
+
}
|
|
1340
|
+
static complexQueryParams(path) {
|
|
1341
|
+
const segments = path.split("/").filter(s => s.startsWith(":"));
|
|
1342
|
+
const params = [];
|
|
1343
|
+
segments.forEach((seg, i) => {
|
|
1344
|
+
const name = seg.replace(":", "");
|
|
1345
|
+
params.push({
|
|
1346
|
+
decorator: common.Param(name),
|
|
1347
|
+
index: i
|
|
1348
|
+
});
|
|
1349
|
+
});
|
|
1350
|
+
if (path.startsWith("query/")) {
|
|
1351
|
+
params.push({
|
|
1352
|
+
decorator: DecafQuery(),
|
|
1353
|
+
index: segments.length
|
|
1354
|
+
});
|
|
1355
|
+
}
|
|
1356
|
+
return params;
|
|
1357
|
+
}
|
|
1358
|
+
static createComplexQueryHandler(methodName) {
|
|
1359
|
+
return async function complexQuery(...args) {
|
|
1360
|
+
const log = this.log?.for?.(complexQuery);
|
|
1361
|
+
try {
|
|
1362
|
+
if (log) log.debug(`Invoking custom query "${methodName}"`);
|
|
1363
|
+
const {ctx: ctx} = (await this.logCtx([], methodName, true)).for(complexQuery);
|
|
1364
|
+
const persistence = this.persistence(ctx);
|
|
1365
|
+
const spreadArgs = FromModelController.normalizeQueryArgs(args);
|
|
1366
|
+
if (persistence?.repo && typeof persistence.repo[methodName] === "function") {
|
|
1367
|
+
return persistence.repo[methodName](...spreadArgs);
|
|
1368
|
+
}
|
|
1369
|
+
if (typeof persistence[methodName] === "function") {
|
|
1370
|
+
return persistence[methodName](...spreadArgs);
|
|
1371
|
+
}
|
|
1372
|
+
if (persistence?.query && typeof persistence.query === "function") {
|
|
1373
|
+
return persistence.query(methodName, ...spreadArgs);
|
|
1374
|
+
}
|
|
1375
|
+
if (typeof persistence.statement === "function") {
|
|
1376
|
+
return persistence.statement(methodName, ...spreadArgs, ctx);
|
|
1377
|
+
}
|
|
1378
|
+
throw new dbDecorators.InternalError(`Persistence method "${methodName}" not found on ${persistence?.constructor?.name}`);
|
|
1379
|
+
} catch (e) {
|
|
1380
|
+
if (log) log.error(`Custom query "${methodName}" failed`, e);
|
|
1381
|
+
throw FromModelController.toDecafError(e, `Custom query "${methodName}" failed`);
|
|
1382
|
+
}
|
|
1383
|
+
};
|
|
1384
|
+
}
|
|
1385
|
+
static extractQueryArgs(args) {
|
|
1386
|
+
if (args.length === 0) return args;
|
|
1387
|
+
const last = args[args.length - 1];
|
|
1388
|
+
if (last && typeof last === "object" && !Array.isArray(last)) {
|
|
1389
|
+
const queryObj = args.pop();
|
|
1390
|
+
const hasDirection = queryObj.direction !== undefined;
|
|
1391
|
+
const hasLimit = queryObj.limit !== undefined;
|
|
1392
|
+
const hasOffset = queryObj.offset !== undefined;
|
|
1393
|
+
if (!hasDirection && !hasLimit && !hasOffset) return args;
|
|
1394
|
+
const extras = [];
|
|
1395
|
+
if (hasDirection) extras.push(queryObj.direction); else if (hasLimit || hasOffset) extras.push(undefined);
|
|
1396
|
+
if (hasLimit) extras.push(queryObj.limit);
|
|
1397
|
+
if (hasOffset) extras.push(queryObj.offset);
|
|
1398
|
+
return [ ...args, ...extras ];
|
|
1399
|
+
}
|
|
1400
|
+
return args;
|
|
1401
|
+
}
|
|
1402
|
+
static normalizeQueryArgs(args) {
|
|
1403
|
+
const normalized = FromModelController.extractQueryArgs(args);
|
|
1404
|
+
if (normalized.length === 0) return normalized;
|
|
1405
|
+
const last = normalized[normalized.length - 1];
|
|
1406
|
+
if (!last || typeof last !== "object" || Array.isArray(last)) {
|
|
1407
|
+
return normalized;
|
|
1408
|
+
}
|
|
1409
|
+
const queryObj = last;
|
|
1410
|
+
const hasQueryFields = queryObj.direction !== undefined || queryObj.limit !== undefined || queryObj.offset !== undefined || queryObj.bookmark !== undefined;
|
|
1411
|
+
if (!hasQueryFields) {
|
|
1412
|
+
normalized.pop();
|
|
1413
|
+
return normalized;
|
|
1414
|
+
}
|
|
1415
|
+
normalized.pop();
|
|
1416
|
+
if (queryObj.direction !== undefined) normalized.push(queryObj.direction);
|
|
1417
|
+
if (queryObj.limit !== undefined) normalized.push(queryObj.limit);
|
|
1418
|
+
if (queryObj.offset !== undefined) normalized.push(queryObj.offset);
|
|
1419
|
+
if (queryObj.bookmark !== undefined) normalized.push(queryObj.bookmark);
|
|
1420
|
+
return normalized;
|
|
1421
|
+
}
|
|
1422
|
+
static createCreateDecorators(ModelConstr, modelClazzName) {
|
|
1423
|
+
return [ ApiOperationFromModel(ModelConstr, "POST"), swagger.ApiOperation({
|
|
1424
|
+
summary: `Create a new ${modelClazzName}.`
|
|
1425
|
+
}), swagger.ApiBody({
|
|
1426
|
+
description: `Payload for ${modelClazzName}`,
|
|
1427
|
+
type: DtoFor(dbDecorators.OperationKeys.CREATE, ModelConstr)
|
|
1428
|
+
}), swagger.ApiCreatedResponse({
|
|
1429
|
+
description: `${modelClazzName} created successfully.`,
|
|
1430
|
+
schema: {
|
|
1431
|
+
$ref: swagger.getSchemaPath(ModelConstr)
|
|
1432
|
+
}
|
|
1433
|
+
}), swagger.ApiBadRequestResponse({
|
|
1434
|
+
description: "Payload validation failed."
|
|
1435
|
+
}), swagger.ApiUnprocessableEntityResponse({
|
|
1436
|
+
description: "Repository rejected the provided payload."
|
|
1437
|
+
}) ];
|
|
1438
|
+
}
|
|
1439
|
+
static bulkCreateDecorators(ModelConstr, modelClazzName) {
|
|
1440
|
+
return [ ApiOperationFromModel(ModelConstr, "POST", "bulk"), swagger.ApiOperation({
|
|
1441
|
+
summary: `Create a new ${modelClazzName}.`
|
|
1442
|
+
}), swagger.ApiBody({
|
|
1443
|
+
description: `Payload for ${modelClazzName}`,
|
|
1444
|
+
schema: {
|
|
1445
|
+
type: "array",
|
|
1446
|
+
items: {
|
|
1447
|
+
$ref: swagger.getSchemaPath(ModelConstr)
|
|
1448
|
+
}
|
|
1449
|
+
}
|
|
1450
|
+
}), swagger.ApiCreatedResponse({
|
|
1451
|
+
description: `${modelClazzName} created successfully.`,
|
|
1452
|
+
schema: {
|
|
1453
|
+
type: "array",
|
|
1454
|
+
items: {
|
|
1455
|
+
$ref: swagger.getSchemaPath(ModelConstr)
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1458
|
+
}), swagger.ApiBadRequestResponse({
|
|
1459
|
+
description: "Payload validation failed."
|
|
1460
|
+
}), swagger.ApiUnprocessableEntityResponse({
|
|
1461
|
+
description: "Repository rejected the provided payload."
|
|
1462
|
+
}) ];
|
|
1463
|
+
}
|
|
1464
|
+
static bulkReadDecorators(ModelConstr, modelClazzName) {
|
|
1465
|
+
return [ ApiOperationFromModel(ModelConstr, "GET", "bulk"), swagger.ApiOperation({
|
|
1466
|
+
summary: `Retrieve ${modelClazzName} records by ids.`
|
|
1467
|
+
}), swagger.ApiQuery({
|
|
1468
|
+
name: "ids",
|
|
1469
|
+
required: true,
|
|
1470
|
+
type: "array"
|
|
1471
|
+
}), swagger.ApiOkResponse({
|
|
1472
|
+
description: `${modelClazzName} retrieved successfully.`,
|
|
1473
|
+
schema: {
|
|
1474
|
+
type: "array",
|
|
1475
|
+
items: {
|
|
1476
|
+
$ref: swagger.getSchemaPath(ModelConstr)
|
|
1477
|
+
}
|
|
1478
|
+
}
|
|
1479
|
+
}), swagger.ApiNotFoundResponse({
|
|
1480
|
+
description: `No ${modelClazzName} record matches the provided identifier.`
|
|
1481
|
+
}) ];
|
|
1482
|
+
}
|
|
1483
|
+
static bulkUpdateDecorators(ModelConstr, modelClazzName, apiProperties) {
|
|
1484
|
+
return [ ApiOperationFromModel(ModelConstr, "PUT", "bulk"), ApiParamsFromModel(apiProperties), swagger.ApiOperation({
|
|
1485
|
+
summary: `Replace existing ${modelClazzName} records with new payloads.`
|
|
1486
|
+
}), swagger.ApiBody({
|
|
1487
|
+
description: `Payload for replacing existing records of ${modelClazzName}`,
|
|
1488
|
+
schema: {
|
|
1489
|
+
type: "array",
|
|
1490
|
+
$ref: swagger.getSchemaPath(DtoFor(dbDecorators.OperationKeys.UPDATE, ModelConstr))
|
|
1491
|
+
}
|
|
1492
|
+
}), swagger.ApiOkResponse({
|
|
1493
|
+
description: `${modelClazzName} updated successfully.`,
|
|
1494
|
+
schema: {
|
|
1495
|
+
type: "array",
|
|
1496
|
+
items: {
|
|
1497
|
+
$ref: swagger.getSchemaPath(ModelConstr)
|
|
1498
|
+
}
|
|
1499
|
+
}
|
|
1500
|
+
}), swagger.ApiNotFoundResponse({
|
|
1501
|
+
description: `No ${modelClazzName} record matches the provided identifier.`
|
|
1502
|
+
}), swagger.ApiBadRequestResponse({
|
|
1503
|
+
description: "Payload validation failed."
|
|
1504
|
+
}) ];
|
|
1505
|
+
}
|
|
1506
|
+
static bulkDeleteDecorators(ModelConstr, modelClazzName, apiProperties) {
|
|
1507
|
+
return [ ApiOperationFromModel(ModelConstr, "DELETE", "bulk"), ApiParamsFromModel(apiProperties), swagger.ApiOperation({
|
|
1508
|
+
summary: `Delete ${modelClazzName} records by ids.`
|
|
1509
|
+
}), swagger.ApiQuery({
|
|
1510
|
+
name: "ids",
|
|
1511
|
+
required: true,
|
|
1512
|
+
type: "array"
|
|
1513
|
+
}), swagger.ApiOkResponse({
|
|
1514
|
+
description: `${modelClazzName} deleted successfully.`,
|
|
1515
|
+
schema: {
|
|
1516
|
+
type: "array",
|
|
1517
|
+
items: {
|
|
1518
|
+
$ref: swagger.getSchemaPath(ModelConstr)
|
|
1519
|
+
}
|
|
1520
|
+
}
|
|
1521
|
+
}), swagger.ApiNotFoundResponse({
|
|
1522
|
+
description: `No ${modelClazzName} record matches the provided identifier.`
|
|
1523
|
+
}) ];
|
|
1524
|
+
}
|
|
1525
|
+
static readDecorators(ModelConstr, modelClazzName, apiProperties, pkPath) {
|
|
1526
|
+
return [ ApiOperationFromModel(ModelConstr, "GET", pkPath), ApiParamsFromModel(apiProperties), swagger.ApiOperation({
|
|
1527
|
+
summary: `Retrieve a ${modelClazzName} record by id.`
|
|
1528
|
+
}), swagger.ApiOkResponse({
|
|
1529
|
+
description: `${modelClazzName} retrieved successfully.`,
|
|
1530
|
+
schema: {
|
|
1531
|
+
$ref: swagger.getSchemaPath(ModelConstr)
|
|
1532
|
+
}
|
|
1533
|
+
}), swagger.ApiNotFoundResponse({
|
|
1534
|
+
description: `No ${modelClazzName} record matches the provided identifier.`
|
|
1535
|
+
}) ];
|
|
1536
|
+
}
|
|
1537
|
+
static updateDecorators(ModelConstr, modelClazzName, apiProperties, pkPath) {
|
|
1538
|
+
return [ ApiOperationFromModel(ModelConstr, "PUT", pkPath), ApiParamsFromModel(apiProperties), swagger.ApiOperation({
|
|
1539
|
+
summary: `Replace an existing ${modelClazzName} record with a new payload.`
|
|
1540
|
+
}), swagger.ApiBody({
|
|
1541
|
+
description: `Payload for replacing an existing record of ${modelClazzName}`,
|
|
1542
|
+
type: DtoFor(dbDecorators.OperationKeys.UPDATE, ModelConstr)
|
|
1543
|
+
}), swagger.ApiOkResponse({
|
|
1544
|
+
description: `${modelClazzName} updated successfully.`,
|
|
1545
|
+
schema: {
|
|
1546
|
+
$ref: swagger.getSchemaPath(ModelConstr)
|
|
1547
|
+
}
|
|
1548
|
+
}), swagger.ApiNotFoundResponse({
|
|
1549
|
+
description: `No ${modelClazzName} record matches the provided identifier.`
|
|
1550
|
+
}), swagger.ApiBadRequestResponse({
|
|
1551
|
+
description: "Payload validation failed."
|
|
1552
|
+
}) ];
|
|
1553
|
+
}
|
|
1554
|
+
static deleteDecorators(ModelConstr, modelClazzName, apiProperties, pkPath) {
|
|
1555
|
+
return [ ApiOperationFromModel(ModelConstr, "DELETE", pkPath), ApiParamsFromModel(apiProperties), swagger.ApiOperation({
|
|
1556
|
+
summary: `Delete a ${modelClazzName} record by id.`
|
|
1557
|
+
}), swagger.ApiOkResponse({
|
|
1558
|
+
description: `${modelClazzName} deleted successfully.`,
|
|
1559
|
+
schema: {
|
|
1560
|
+
$ref: swagger.getSchemaPath(ModelConstr)
|
|
1561
|
+
}
|
|
1562
|
+
}), swagger.ApiNotFoundResponse({
|
|
1563
|
+
description: `No ${modelClazzName} record matches the provided identifier.`
|
|
1564
|
+
}) ];
|
|
1565
|
+
}
|
|
1566
|
+
static statementDecorators(ModelConstr, modelClazzName) {
|
|
1567
|
+
return [ ApiOperationFromModel(ModelConstr, "GET", "statement/:method/*args"), swagger.ApiOperation({
|
|
1568
|
+
summary: `Executes a prepared statement on ${modelClazzName}.`
|
|
1569
|
+
}), swagger.ApiParam({
|
|
1570
|
+
name: "method",
|
|
1571
|
+
description: "the prepared statement to execute"
|
|
1572
|
+
}), swagger.ApiParam({
|
|
1573
|
+
name: "args",
|
|
1574
|
+
description: "concatenated list of arguments the prepared statement can accept"
|
|
1575
|
+
}), swagger.ApiQuery({
|
|
1576
|
+
name: "direction",
|
|
1577
|
+
required: true,
|
|
1578
|
+
enum: core.OrderDirection,
|
|
1579
|
+
description: "the sort order when applicable"
|
|
1580
|
+
}), swagger.ApiQuery({
|
|
1581
|
+
name: "limit",
|
|
1582
|
+
required: true,
|
|
1583
|
+
description: "limit or page size when applicable"
|
|
1584
|
+
}), swagger.ApiQuery({
|
|
1585
|
+
name: "offset",
|
|
1586
|
+
required: true,
|
|
1587
|
+
description: "offset or bookmark when applicable"
|
|
1588
|
+
}), swagger.ApiOkResponse({
|
|
1589
|
+
description: `${modelClazzName} listed found.`
|
|
1590
|
+
}), swagger.ApiNotFoundResponse({
|
|
1591
|
+
description: `No ${modelClazzName} record matches the provided identifier.`
|
|
1592
|
+
}) ];
|
|
1593
|
+
}
|
|
1594
|
+
static statementShortcutDecorators(ModelConstr, modelClazzName, path, statementKey) {
|
|
1595
|
+
const base = [ ApiOperationFromModel(ModelConstr, "GET", path), swagger.ApiOperation({
|
|
1596
|
+
summary: `Retrieve ${modelClazzName} records.`
|
|
1597
|
+
}), swagger.ApiOkResponse({
|
|
1598
|
+
description: `${modelClazzName} retrieved successfully.`
|
|
1599
|
+
}) ];
|
|
1600
|
+
const segments = path.split("/").filter(s => s.startsWith(":"));
|
|
1601
|
+
segments.forEach(seg => {
|
|
1602
|
+
const name = seg.replace(":", "");
|
|
1603
|
+
base.push(swagger.ApiParam({
|
|
1604
|
+
name: name,
|
|
1605
|
+
description: `The ${name} parameter`
|
|
1606
|
+
}));
|
|
1607
|
+
});
|
|
1608
|
+
if (path.startsWith("listBy/") || path.startsWith("paginateBy/") || path.startsWith("find/") || path.startsWith("page/")) {
|
|
1609
|
+
base.push(swagger.ApiQuery({
|
|
1610
|
+
name: "direction",
|
|
1611
|
+
required: true,
|
|
1612
|
+
enum: core.OrderDirection,
|
|
1613
|
+
description: "the sort order"
|
|
1614
|
+
}));
|
|
1615
|
+
}
|
|
1616
|
+
if (path.startsWith("paginateBy/") || path.startsWith("page/")) {
|
|
1617
|
+
base.push(swagger.ApiQuery({
|
|
1618
|
+
name: "limit",
|
|
1619
|
+
required: false,
|
|
1620
|
+
description: "page size"
|
|
1621
|
+
}), swagger.ApiQuery({
|
|
1622
|
+
name: "offset",
|
|
1623
|
+
required: false,
|
|
1624
|
+
description: "page number"
|
|
1625
|
+
}), swagger.ApiQuery({
|
|
1626
|
+
name: "bookmark",
|
|
1627
|
+
required: false,
|
|
1628
|
+
description: "bookmark for cursor pagination"
|
|
1629
|
+
}));
|
|
1630
|
+
}
|
|
1631
|
+
if (path.startsWith("findOneBy/") || path.startsWith("findBy/")) {
|
|
1632
|
+
base.push(swagger.ApiNotFoundResponse({
|
|
1633
|
+
description: `No ${modelClazzName} record matches the provided identifier.`
|
|
1634
|
+
}));
|
|
1635
|
+
}
|
|
1636
|
+
if (statementKey === core.PreparedStatementKeys.COUNT_OF || statementKey === core.PreparedStatementKeys.AVG_OF || statementKey === core.PreparedStatementKeys.SUM_OF) {
|
|
1637
|
+
base.push(swagger.ApiOkResponse({
|
|
1638
|
+
description: `Result for ${modelClazzName}.`,
|
|
1639
|
+
type: Number
|
|
1640
|
+
}));
|
|
1641
|
+
}
|
|
1642
|
+
if (statementKey === core.PreparedStatementKeys.DISTINCT_OF) {
|
|
1643
|
+
base.push(swagger.ApiOkResponse({
|
|
1644
|
+
description: `Distinct values for ${modelClazzName}.`,
|
|
1645
|
+
type: [ String ]
|
|
1646
|
+
}));
|
|
1647
|
+
}
|
|
1648
|
+
return base;
|
|
1649
|
+
}
|
|
1650
|
+
static getQueryDecorators(methodName, routePath, httpVerb, includeQueryParams = false) {
|
|
1651
|
+
const extractPathParams = p => p.split("/").filter(s => s.startsWith(":")).map(s => s.slice(1));
|
|
1652
|
+
const apiPathParams = extractPathParams(routePath).map(name => ({
|
|
1653
|
+
name: name,
|
|
1654
|
+
description: `${name} parameter for the query`,
|
|
1655
|
+
required: true,
|
|
1656
|
+
type: String
|
|
1657
|
+
}));
|
|
1658
|
+
const decorators = [ ...apiPathParams.map(p => swagger.ApiParam(p)), swagger.ApiOperation({
|
|
1659
|
+
summary: `Retrieve records using "${methodName}".`
|
|
1660
|
+
}), swagger.ApiOkResponse({
|
|
1661
|
+
description: "Result successfully retrieved."
|
|
1662
|
+
}), swagger.ApiNoContentResponse({
|
|
1663
|
+
description: "No content returned by the method."
|
|
1664
|
+
}) ];
|
|
1665
|
+
if (httpVerb === "GET" && includeQueryParams) {
|
|
1666
|
+
decorators.push(swagger.ApiQuery({
|
|
1667
|
+
name: "direction",
|
|
1668
|
+
required: false,
|
|
1669
|
+
enum: core.OrderDirection,
|
|
1670
|
+
description: "the sort order when applicable"
|
|
1671
|
+
}), swagger.ApiQuery({
|
|
1672
|
+
name: "limit",
|
|
1673
|
+
required: false,
|
|
1674
|
+
description: "limit or page size"
|
|
1675
|
+
}), swagger.ApiQuery({
|
|
1676
|
+
name: "offset",
|
|
1677
|
+
required: false,
|
|
1678
|
+
description: "offset or bookmark"
|
|
1679
|
+
}));
|
|
1680
|
+
}
|
|
1681
|
+
return decorators;
|
|
1682
|
+
}
|
|
1683
|
+
}
|
|
1684
|
+
function getModuleFor(flavour) {
|
|
1685
|
+
var DecafModelModule_1;
|
|
1686
|
+
let DecafModelModule = class DecafModelModule {
|
|
1687
|
+
static {
|
|
1688
|
+
DecafModelModule_1 = this;
|
|
1689
|
+
}
|
|
1690
|
+
static {
|
|
1691
|
+
this.log = logging.Logging.for(DecafModelModule_1.name).for(flavour);
|
|
1692
|
+
}
|
|
1693
|
+
static createModelServices(models) {
|
|
1694
|
+
return models.map(model => ({
|
|
1695
|
+
provide: `${model.name}Service`,
|
|
1696
|
+
useFactory: () => core.ModelService.forModel(model)
|
|
1697
|
+
}));
|
|
1698
|
+
}
|
|
1699
|
+
static isExposed(model, exposure) {
|
|
1700
|
+
const override = exposure?.[model.name];
|
|
1701
|
+
const value = typeof override !== "undefined" ? override : decoration.Metadata.get(model, decoration.Metadata.key(DECAF_EXPOSE));
|
|
1702
|
+
if (typeof value === "undefined") return true;
|
|
1703
|
+
if (value === true) return true;
|
|
1704
|
+
if (Array.isArray(value)) return value.includes(flavour);
|
|
1705
|
+
return false;
|
|
1706
|
+
}
|
|
1707
|
+
static forRoot(flavour, options = {}) {
|
|
1708
|
+
const log = this.log.for(this.forRoot);
|
|
1709
|
+
log.info(`Generating controllers for flavour...`);
|
|
1710
|
+
const trackedModels = core.Adapter.models(flavour).filter(model => this.isExposed(model, options.controllerExposure));
|
|
1711
|
+
for (const model of trackedModels) core.ModelService.forModel(model);
|
|
1712
|
+
let modelServices = [];
|
|
1713
|
+
if (options.autoServices) {
|
|
1714
|
+
log.info("Auto-services enabled. Initializing service generation.");
|
|
1715
|
+
modelServices = this.createModelServices(trackedModels);
|
|
1716
|
+
log.info(`Auto-services completed. ${modelServices.length} services initialized.`);
|
|
1717
|
+
}
|
|
1718
|
+
const globalDefaults = {};
|
|
1719
|
+
if (options.aggregations === false) {
|
|
1720
|
+
globalDefaults.allowGroupingQueries = false;
|
|
1721
|
+
}
|
|
1722
|
+
const controllers = trackedModels.map(model => FromModelController.create(model, options.controllerConfig, globalDefaults));
|
|
1723
|
+
log.info(`Generated ${controllers.length} controllers`);
|
|
1724
|
+
return {
|
|
1725
|
+
module: DecafModelModule_1,
|
|
1726
|
+
controllers: controllers,
|
|
1727
|
+
providers: [ ...modelServices ]
|
|
1728
|
+
};
|
|
1729
|
+
}
|
|
1730
|
+
};
|
|
1731
|
+
DecafModelModule = DecafModelModule_1 = tslib.__decorate([ common.Module({}) ], DecafModelModule);
|
|
1732
|
+
Object.assign(DecafModelModule, "name", {
|
|
1733
|
+
value: `DecafModule${flavour}`
|
|
1734
|
+
});
|
|
1735
|
+
return DecafModelModule;
|
|
1736
|
+
}
|
|
1737
|
+
decoration.Decoration.for(injectableDecorators.InjectablesKeys.INJECTABLE).extend({
|
|
1738
|
+
decorator: function nestInjectable(category, cfg) {
|
|
1739
|
+
cfg = cfg || (typeof category === "object" ? Object.assign(category, injectableDecorators.DefaultInjectablesConfig) : injectableDecorators.DefaultInjectablesConfig);
|
|
1740
|
+
return common.Injectable({
|
|
1741
|
+
scope: cfg.singleton ? common.Scope.DEFAULT : common.Scope.REQUEST,
|
|
1742
|
+
durable: cfg.singleton ? undefined : true
|
|
1743
|
+
});
|
|
1744
|
+
}
|
|
1745
|
+
}).apply();
|
|
1746
|
+
decoration.Decoration.for(injectableDecorators.InjectablesKeys.INJECT).extend({
|
|
1747
|
+
decorator: function nestInject(category, cfg) {
|
|
1748
|
+
return function innerNestInject(target, propertyKey, descriptor) {
|
|
1749
|
+
return common.Inject(category || target)(target, propertyKey, descriptor);
|
|
1750
|
+
};
|
|
1751
|
+
}
|
|
1752
|
+
}).apply();
|
|
1753
|
+
decoration.Decoration.for(decoratorValidation.ValidationKeys.REQUIRED).extend(ApiProperty({
|
|
1754
|
+
required: true
|
|
1755
|
+
})).apply();
|
|
1756
|
+
decoration.Decoration.for(decoratorValidation.ValidationKeys.MAX).extend({
|
|
1757
|
+
decorator: function maxDec(max) {
|
|
1758
|
+
return ApiProperty({
|
|
1759
|
+
maximum: max,
|
|
1760
|
+
required: false
|
|
1761
|
+
});
|
|
1762
|
+
}
|
|
1763
|
+
}).apply();
|
|
1764
|
+
decoration.Decoration.for(decoratorValidation.ValidationKeys.MIN).extend({
|
|
1765
|
+
decorator: function minDec(min) {
|
|
1766
|
+
return ApiProperty({
|
|
1767
|
+
minimum: min,
|
|
1768
|
+
required: false
|
|
1769
|
+
});
|
|
1770
|
+
}
|
|
1771
|
+
}).apply();
|
|
1772
|
+
decoration.Decoration.for(decoratorValidation.ValidationKeys.MAX_LENGTH).extend({
|
|
1773
|
+
decorator: function maxLengthDec(max) {
|
|
1774
|
+
return ApiProperty({
|
|
1775
|
+
maxLength: max,
|
|
1776
|
+
required: false
|
|
1777
|
+
});
|
|
1778
|
+
}
|
|
1779
|
+
}).apply();
|
|
1780
|
+
decoration.Decoration.for(decoratorValidation.ValidationKeys.MIN_LENGTH).extend({
|
|
1781
|
+
decorator: function minLengthDec(min) {
|
|
1782
|
+
return ApiProperty({
|
|
1783
|
+
minLength: min,
|
|
1784
|
+
required: false
|
|
1785
|
+
});
|
|
1786
|
+
}
|
|
1787
|
+
}).apply();
|
|
1788
|
+
decoration.Decoration.for(decoratorValidation.ValidationKeys.TYPE).extend({
|
|
1789
|
+
decorator: function typeDec(type) {
|
|
1790
|
+
return (target, prop) => {
|
|
1791
|
+
type = Array.isArray(type) ? type[0] : type;
|
|
1792
|
+
if (typeof type === "function" && !type.name) type = type();
|
|
1793
|
+
return ApiProperty({
|
|
1794
|
+
type: type,
|
|
1795
|
+
required: false
|
|
1796
|
+
})(target, prop);
|
|
1797
|
+
};
|
|
1798
|
+
}
|
|
1799
|
+
}).apply();
|
|
1800
|
+
decoration.Decoration.for(decoratorValidation.ValidationKeys.DATE).extend({
|
|
1801
|
+
decorator: function dateDec(format) {
|
|
1802
|
+
return ApiProperty({
|
|
1803
|
+
type: String,
|
|
1804
|
+
format: "date-time",
|
|
1805
|
+
required: false
|
|
1806
|
+
});
|
|
1807
|
+
}
|
|
1808
|
+
}).apply();
|
|
1809
|
+
decoration.Decoration.for(decoratorValidation.ValidationKeys.ENUM).extend({
|
|
1810
|
+
decorator: function optionDec(options) {
|
|
1811
|
+
const opts = Array.isArray(options) ? options : Object.values(options);
|
|
1812
|
+
return ApiProperty({
|
|
1813
|
+
enum: opts,
|
|
1814
|
+
required: false
|
|
1815
|
+
});
|
|
1816
|
+
}
|
|
1817
|
+
}).apply();
|
|
1818
|
+
decoration.Decoration.for(decoratorValidation.ValidationKeys.PATTERN).extend({
|
|
1819
|
+
decorator: function patternDec(pat) {
|
|
1820
|
+
return ApiProperty({
|
|
1821
|
+
pattern: typeof pat === "string" ? pat : pat.source,
|
|
1822
|
+
required: false
|
|
1823
|
+
});
|
|
1824
|
+
}
|
|
1825
|
+
}).apply();
|
|
1826
|
+
decoration.Decoration.for(core.PersistenceKeys.COLUMN).extend({
|
|
1827
|
+
decorator: function columnDec(name) {
|
|
1828
|
+
return ApiProperty({
|
|
1829
|
+
name: name,
|
|
1830
|
+
required: false
|
|
1831
|
+
});
|
|
1832
|
+
}
|
|
1833
|
+
}).apply();
|
|
1834
|
+
decoration.Decoration.for(decoration.DecorationKeys.DESCRIPTION).extend({
|
|
1835
|
+
decorator: function descriptionDec(description) {
|
|
1836
|
+
return ApiProperty({
|
|
1837
|
+
description: description,
|
|
1838
|
+
required: false
|
|
1839
|
+
});
|
|
1840
|
+
}
|
|
1841
|
+
}).apply();
|
|
1842
|
+
decoration.Decoration.for(core.PersistenceKeys.AUTH).extend({
|
|
1843
|
+
decorator: Auth
|
|
1844
|
+
}).apply();
|
|
1845
|
+
class CorsError extends core.ForbiddenError {
|
|
1846
|
+
constructor(msg) {
|
|
1847
|
+
super(msg, CorsError.name);
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1850
|
+
class ToManyRequestsError extends dbDecorators.BaseError {
|
|
1851
|
+
constructor(msg) {
|
|
1852
|
+
super(ToManyRequestsError.name, msg, 429);
|
|
1853
|
+
}
|
|
1854
|
+
}
|
|
1855
|
+
const HTTP_EXCEPTION_TO_DECAF_ERROR = new Map([ [ common.UnauthorizedException, msg => new core.AuthorizationError(msg) ], [ common.ForbiddenException, msg => new core.ForbiddenError(msg) ], [ common.BadRequestException, msg => new dbDecorators.BadRequestError(msg) ], [ common.ConflictException, msg => new dbDecorators.ConflictError(msg) ], [ common.UnprocessableEntityException, msg => new dbDecorators.ValidationError(msg) ] ]);
|
|
1856
|
+
exports.DecafExceptionFilter = class DecafExceptionFilter {
|
|
1857
|
+
constructor(moduleRef) {
|
|
1858
|
+
this.moduleRef = moduleRef;
|
|
1859
|
+
}
|
|
1860
|
+
async catch(exception, host) {
|
|
1861
|
+
const ctx = host.switchToHttp();
|
|
1862
|
+
const response = ctx.getResponse();
|
|
1863
|
+
const request = ctx.getRequest();
|
|
1864
|
+
const isProduction = logging.LoggedEnvironment.env === "production";
|
|
1865
|
+
let statusCode;
|
|
1866
|
+
if (exception instanceof common.NotFoundException || exception instanceof core.UnsupportedError) {
|
|
1867
|
+
exception = new common.NotAcceptableException(exception.message);
|
|
1868
|
+
statusCode = exception.getStatus();
|
|
1869
|
+
} else if (!(exception instanceof dbDecorators.BaseError)) {
|
|
1870
|
+
const toDecafError = this.decafErrorFor(exception);
|
|
1871
|
+
if (toDecafError) {
|
|
1872
|
+
exception = toDecafError(exception.message);
|
|
1873
|
+
} else if (exception.status === 429) {
|
|
1874
|
+
exception = new ToManyRequestsError(exception.message);
|
|
1875
|
+
} else if (exception instanceof common.HttpException) {
|
|
1876
|
+
statusCode = exception.getStatus();
|
|
1877
|
+
} else {
|
|
1878
|
+
exception = new dbDecorators.InternalError(exception.message);
|
|
1879
|
+
}
|
|
1880
|
+
}
|
|
1881
|
+
await this.logError(request, exception);
|
|
1882
|
+
response.status(exception.code || statusCode).json({
|
|
1883
|
+
status: exception.code || statusCode,
|
|
1884
|
+
error: isProduction ? exception.name : exception.message,
|
|
1885
|
+
timestamp: (new Date).toISOString(),
|
|
1886
|
+
path: request.url,
|
|
1887
|
+
method: request.method
|
|
1888
|
+
});
|
|
1889
|
+
}
|
|
1890
|
+
decafErrorFor(exception) {
|
|
1891
|
+
for (const [type, factory] of HTTP_EXCEPTION_TO_DECAF_ERROR) {
|
|
1892
|
+
if (exception instanceof type) return factory;
|
|
1893
|
+
}
|
|
1894
|
+
return undefined;
|
|
1895
|
+
}
|
|
1896
|
+
async logError(request, exception) {
|
|
1897
|
+
const message = `Unhandled error on ${request?.method} ${request?.url}`;
|
|
1898
|
+
try {
|
|
1899
|
+
const log = await this.resolveLogger(request);
|
|
1900
|
+
log.error(message, exception);
|
|
1901
|
+
} catch {
|
|
1902
|
+
try {
|
|
1903
|
+
logging.Logging.get().error(message, exception);
|
|
1904
|
+
} catch {}
|
|
1905
|
+
}
|
|
1906
|
+
}
|
|
1907
|
+
async resolveLogger(request) {
|
|
1908
|
+
if (this.moduleRef) {
|
|
1909
|
+
try {
|
|
1910
|
+
const contextId = core$1.ContextIdFactory.getByRequest(request);
|
|
1911
|
+
const requestContext = await this.moduleRef.resolve(exports.DecafRequestContext, contextId, {
|
|
1912
|
+
strict: false
|
|
1913
|
+
});
|
|
1914
|
+
if (requestContext?.logger) return requestContext.logger;
|
|
1915
|
+
} catch {}
|
|
1916
|
+
}
|
|
1917
|
+
return logging.Logging.get();
|
|
1918
|
+
}
|
|
1919
|
+
};
|
|
1920
|
+
exports.DecafExceptionFilter = tslib.__decorate([ common.Catch(), common.Injectable(), tslib.__param(0, common.Optional()), tslib.__metadata("design:paramtypes", [ core$1.ModuleRef ]) ], exports.DecafExceptionFilter);
|
|
1921
|
+
function UseDecafFilter() {
|
|
1922
|
+
return common.UseFilters(new exports.DecafExceptionFilter);
|
|
1923
|
+
}
|
|
1924
|
+
function UseDecafHeaders() {
|
|
1925
|
+
return common.UseInterceptors(exports.DecafResponseInterceptor);
|
|
1926
|
+
}
|
|
1927
|
+
const SWAGGER_UI_CONSTANTS = {
|
|
1928
|
+
title: "Swagger | OpenAPI Specification (OAS)",
|
|
1929
|
+
description: "Standardized format for describing RESTful APIs",
|
|
1930
|
+
version: "0.0.1",
|
|
1931
|
+
path: "docs",
|
|
1932
|
+
faviconFilePath: "",
|
|
1933
|
+
topbarIconFilePath: "",
|
|
1934
|
+
auth: {
|
|
1935
|
+
type: "http",
|
|
1936
|
+
scheme: "bearer",
|
|
1937
|
+
bearerFormat: "JWT",
|
|
1938
|
+
name: "Authorization",
|
|
1939
|
+
description: "Enter JWT token",
|
|
1940
|
+
in: "header"
|
|
1941
|
+
},
|
|
1942
|
+
persistAuthorization: true,
|
|
1943
|
+
topbarBgColor: "#000000"
|
|
1944
|
+
};
|
|
1945
|
+
class SwaggerCustomUI {
|
|
1946
|
+
constructor(options) {
|
|
1947
|
+
this.options = {
|
|
1948
|
+
...options
|
|
1949
|
+
};
|
|
1950
|
+
}
|
|
1951
|
+
customCSS() {
|
|
1952
|
+
let css = "";
|
|
1953
|
+
if (this.options.topbarIconPath) {
|
|
1954
|
+
const img = this.b64(this.options.topbarIconPath);
|
|
1955
|
+
css += `.topbar-wrapper { content: url('data:image/png;base64,${img}'); width: 200px; height: auto; }\n`;
|
|
1956
|
+
}
|
|
1957
|
+
return css + `\n .topbar-wrapper svg { visibility: hidden; }\n .swagger-ui .topbar { background-color: ${this.options.topbarBgColor || SWAGGER_UI_CONSTANTS.topbarBgColor}; }\n `;
|
|
1958
|
+
}
|
|
1959
|
+
getCustomOptions() {
|
|
1960
|
+
const favicon = {};
|
|
1961
|
+
if (this.options.faviconPath) {
|
|
1962
|
+
favicon["customfavIcon"] = this.b64(this.options.faviconPath, true);
|
|
1963
|
+
}
|
|
1964
|
+
return {
|
|
1965
|
+
customSiteTitle: this.options.title,
|
|
1966
|
+
...favicon,
|
|
1967
|
+
customCss: this.customCSS(),
|
|
1968
|
+
swaggerOptions: {
|
|
1969
|
+
persistAuthorization: this.options.persistAuthorization
|
|
1970
|
+
}
|
|
1971
|
+
};
|
|
1972
|
+
}
|
|
1973
|
+
b64(file, img = false) {
|
|
1974
|
+
const filePath = path__namespace.join(this.options.assetsPath || "", file);
|
|
1975
|
+
const b64 = fs.readFileSync(filePath, {
|
|
1976
|
+
encoding: "base64"
|
|
1977
|
+
});
|
|
1978
|
+
return img ? "data:image/png;base64," + b64 : b64;
|
|
1979
|
+
}
|
|
1980
|
+
}
|
|
1981
|
+
class SwaggerBuilder {
|
|
1982
|
+
constructor(app, options) {
|
|
1983
|
+
this.app = app;
|
|
1984
|
+
this.options = options;
|
|
1985
|
+
}
|
|
1986
|
+
createDocument() {
|
|
1987
|
+
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;
|
|
1988
|
+
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();
|
|
1989
|
+
return swagger.SwaggerModule.createDocument(this.app, config, {
|
|
1990
|
+
extraModels: this.options.extraModels || []
|
|
1991
|
+
});
|
|
1992
|
+
}
|
|
1993
|
+
registerOpenApiRoute(path, contentType, bodyFactory) {
|
|
1994
|
+
if (!path) return;
|
|
1995
|
+
const httpAdapter = this.app.getHttpAdapter();
|
|
1996
|
+
path = path.startsWith("/") ? path : `/${path}`;
|
|
1997
|
+
httpAdapter.get(path, (_req, res) => {
|
|
1998
|
+
httpAdapter.reply(res, bodyFactory(), 200, {
|
|
1999
|
+
"Content-Type": contentType
|
|
2000
|
+
});
|
|
2001
|
+
});
|
|
2002
|
+
}
|
|
2003
|
+
setupSwagger() {
|
|
2004
|
+
const document = this.createDocument();
|
|
2005
|
+
const swaggerUI = new SwaggerCustomUI({
|
|
2006
|
+
title: this.options.title,
|
|
2007
|
+
path: this.options.path || SWAGGER_UI_CONSTANTS.path,
|
|
2008
|
+
persistAuthorization: this.options.persistAuthorization ?? true,
|
|
2009
|
+
assetsPath: this.options.assetsPath,
|
|
2010
|
+
faviconPath: this.options.faviconFilePath,
|
|
2011
|
+
topbarIconPath: this.options.topbarIconFilePath,
|
|
2012
|
+
topbarBgColor: this.options.topbarBgColor
|
|
2013
|
+
});
|
|
2014
|
+
swagger.SwaggerModule.setup(this.options.path || SWAGGER_UI_CONSTANTS.path, this.app, document, {
|
|
2015
|
+
...swaggerUI.getCustomOptions(),
|
|
2016
|
+
jsonDocumentUrl: this.options.openApiJsonPath ? `${this.options.openApiJsonPath}` : undefined,
|
|
2017
|
+
yamlDocumentUrl: this.options.openApiYamlPath ? `${this.options.openApiYamlPath}` : undefined
|
|
2018
|
+
});
|
|
2019
|
+
this.registerOpenApiRoute(this.options.openApiJsonPath, "application/json", () => document);
|
|
2020
|
+
this.registerOpenApiRoute(this.options.openApiYamlPath, "application/x-yaml", () => YAML.stringify(document));
|
|
2021
|
+
}
|
|
2022
|
+
}
|
|
2023
|
+
class NestBootstraper {
|
|
2024
|
+
static get logger() {
|
|
2025
|
+
if (!this._logger) {
|
|
2026
|
+
this._logger = new common.Logger("NestBootstrap");
|
|
2027
|
+
}
|
|
2028
|
+
return this._logger;
|
|
2029
|
+
}
|
|
2030
|
+
static initialize(app) {
|
|
2031
|
+
this.app = app;
|
|
2032
|
+
return this;
|
|
2033
|
+
}
|
|
2034
|
+
static enableLogger(customLogger) {
|
|
2035
|
+
this._logger = customLogger || new common.Logger("NestBootstrap");
|
|
2036
|
+
this.app.useLogger(this._logger);
|
|
2037
|
+
return this;
|
|
2038
|
+
}
|
|
2039
|
+
static enableCors(origins = [], allowMethods = [ "GET", "POST", "PUT", "DELETE" ]) {
|
|
2040
|
+
const allowedOrigins = origins === "*" ? "*" : origins.map(o => o.trim().toLowerCase());
|
|
2041
|
+
const corsOptions = {
|
|
2042
|
+
origin: (origin, callback) => {
|
|
2043
|
+
if (!origin) return callback(null, true);
|
|
2044
|
+
if (allowedOrigins === "*" || Array.isArray(allowedOrigins) && allowedOrigins.includes(origin.toLowerCase())) {
|
|
2045
|
+
return callback(null, true);
|
|
2046
|
+
}
|
|
2047
|
+
callback(new CorsError(`Origin ${origin} not allowed`));
|
|
2048
|
+
},
|
|
2049
|
+
credentials: true,
|
|
2050
|
+
methods: allowMethods.join(",")
|
|
2051
|
+
};
|
|
2052
|
+
this.app.enableCors(corsOptions);
|
|
2053
|
+
return this;
|
|
2054
|
+
}
|
|
2055
|
+
static useHelmet(options) {
|
|
2056
|
+
try {
|
|
2057
|
+
const helmet = require("helmet");
|
|
2058
|
+
this.app.use(helmet(options));
|
|
2059
|
+
this.logger.log("Helmet middleware enabled successfully.");
|
|
2060
|
+
} catch {
|
|
2061
|
+
this.logger.warn("Helmet not installed. Skipping middleware.");
|
|
2062
|
+
}
|
|
2063
|
+
return this;
|
|
2064
|
+
}
|
|
2065
|
+
static setupSwagger(options) {
|
|
2066
|
+
const swagger = new SwaggerBuilder(this.app, {
|
|
2067
|
+
title: options.title,
|
|
2068
|
+
description: options.description,
|
|
2069
|
+
version: options.version,
|
|
2070
|
+
path: options.path || "api",
|
|
2071
|
+
persistAuthorization: options.persistAuthorization ?? true,
|
|
2072
|
+
assetsPath: options.assetsPath,
|
|
2073
|
+
faviconFilePath: options.faviconPath,
|
|
2074
|
+
topbarIconFilePath: options.topbarIconPath,
|
|
2075
|
+
topbarBgColor: options.topbarBgColor,
|
|
2076
|
+
openApiJsonPath: options.openApiJsonPath,
|
|
2077
|
+
openApiYamlPath: options.openApiYamlPath
|
|
2078
|
+
});
|
|
2079
|
+
swagger.setupSwagger();
|
|
2080
|
+
return this;
|
|
2081
|
+
}
|
|
2082
|
+
static useGlobalPipes(...pipes) {
|
|
2083
|
+
if (pipes.length > 0) this.app.useGlobalPipes(...pipes);
|
|
2084
|
+
return this;
|
|
2085
|
+
}
|
|
2086
|
+
static useGlobalFilters(...filters) {
|
|
2087
|
+
this.app.useGlobalFilters(...filters.length > 0 ? filters : [ new exports.DecafExceptionFilter(this.app.get(core$1.ModuleRef, {
|
|
2088
|
+
strict: false
|
|
2089
|
+
})) ]);
|
|
2090
|
+
return this;
|
|
2091
|
+
}
|
|
2092
|
+
static useGlobalInterceptors(...interceptors) {
|
|
2093
|
+
if (interceptors.length > 0) this.app.useGlobalInterceptors(...interceptors);
|
|
2094
|
+
return this;
|
|
2095
|
+
}
|
|
2096
|
+
static async start(port = Number(process.env.PORT) || 3e3, host = undefined, log = true) {
|
|
2097
|
+
this.app.listen(port, host).then(async () => {
|
|
2098
|
+
if (log) {
|
|
2099
|
+
const url = await this.app.getUrl();
|
|
2100
|
+
this.logger.log(`🚀 Application is running at: ${url}`);
|
|
2101
|
+
}
|
|
2102
|
+
});
|
|
2103
|
+
}
|
|
2104
|
+
}
|
|
2105
|
+
var DecafRequestHandlerInterceptor_1;
|
|
2106
|
+
exports.DecafRequestHandlerInterceptor = DecafRequestHandlerInterceptor_1 = class DecafRequestHandlerInterceptor {
|
|
2107
|
+
constructor(requestContext, executor) {
|
|
2108
|
+
this.requestContext = requestContext;
|
|
2109
|
+
this.executor = executor;
|
|
2110
|
+
}
|
|
2111
|
+
async contextualize(req) {
|
|
2112
|
+
contextualizeRequestContext(this.requestContext, req);
|
|
2113
|
+
}
|
|
2114
|
+
async intercept(context, next) {
|
|
2115
|
+
const req = context.switchToHttp().getRequest();
|
|
2116
|
+
const res = context.switchToHttp().getResponse();
|
|
2117
|
+
const log = logging.Logging.for(DecafRequestHandlerInterceptor_1).for(this.intercept);
|
|
2118
|
+
log.debug(`CONTEXT ${this.requestContext.uuid} - request: ${req.method} ${req.url}`);
|
|
2119
|
+
await this.contextualize(req);
|
|
2120
|
+
log.debug(`CONTEXT ${this.requestContext.uuid} contextualized - request: ${req.method} ${req.url}`);
|
|
2121
|
+
await this.executor.exec(req, res);
|
|
2122
|
+
log.debug(`CONTEXT ${this.requestContext.uuid} executors finished - request: ${req.method} ${req.url}`);
|
|
2123
|
+
return next.handle();
|
|
2124
|
+
}
|
|
2125
|
+
};
|
|
2126
|
+
exports.DecafRequestHandlerInterceptor = DecafRequestHandlerInterceptor_1 = tslib.__decorate([ common.Injectable({
|
|
2127
|
+
scope: common.Scope.REQUEST
|
|
2128
|
+
}), tslib.__metadata("design:paramtypes", [ exports.DecafRequestContext, exports.DecafHandlerExecutor ]) ], exports.DecafRequestHandlerInterceptor);
|
|
2129
|
+
const pendingProviders = new Map;
|
|
2130
|
+
function getRegisteredDecafProviders() {
|
|
2131
|
+
return Array.from(pendingProviders.values());
|
|
2132
|
+
}
|
|
2133
|
+
function registerProvider(token, useFactory) {
|
|
2134
|
+
if (pendingProviders.has(token)) return;
|
|
2135
|
+
pendingProviders.set(token, {
|
|
2136
|
+
provide: token,
|
|
2137
|
+
useFactory: useFactory
|
|
2138
|
+
});
|
|
2139
|
+
}
|
|
2140
|
+
function isModelConstructor(value) {
|
|
2141
|
+
return typeof value === "function" && value.prototype instanceof decoratorValidation.Model;
|
|
2142
|
+
}
|
|
2143
|
+
function modelServiceToken(model) {
|
|
2144
|
+
return `${model.name}Service`;
|
|
2145
|
+
}
|
|
2146
|
+
function modelRepositoryToken(model, flavour) {
|
|
2147
|
+
return flavour ? `${model.name}Repository@${flavour}` : `${model.name}Repository`;
|
|
2148
|
+
}
|
|
2149
|
+
function Service(key) {
|
|
2150
|
+
return (target, propertyKey, parameterIndex) => {
|
|
2151
|
+
let resolved = key;
|
|
2152
|
+
if (typeof resolved === "undefined") {
|
|
2153
|
+
const paramTypes = Reflect.getMetadata("design:paramtypes", target) || [];
|
|
2154
|
+
resolved = paramTypes[parameterIndex];
|
|
2155
|
+
}
|
|
2156
|
+
if (typeof resolved === "undefined") {
|
|
2157
|
+
throw new dbDecorators.InternalError(`@Service() could not determine an injection type for parameter ${parameterIndex} of ${target.name}. Provide an explicit argument, e.g. @Service(SomeService).`);
|
|
2158
|
+
}
|
|
2159
|
+
const asModel = typeof resolved !== "string" && isModelConstructor(resolved);
|
|
2160
|
+
const token = asModel ? modelServiceToken(resolved) : core.injectableServiceKey(resolved);
|
|
2161
|
+
registerProvider(token, () => {
|
|
2162
|
+
if (asModel) {
|
|
2163
|
+
try {
|
|
2164
|
+
return core.Service.get(resolved);
|
|
2165
|
+
} catch {
|
|
2166
|
+
return core.ModelService.forModel(resolved);
|
|
2167
|
+
}
|
|
2168
|
+
}
|
|
2169
|
+
return typeof resolved === "string" ? core.Service.get(resolved) : core.Service.get(resolved);
|
|
2170
|
+
});
|
|
2171
|
+
return common.Inject(token)(target, propertyKey, parameterIndex);
|
|
2172
|
+
};
|
|
2173
|
+
}
|
|
2174
|
+
function Repository(model, flavour) {
|
|
2175
|
+
return (target, propertyKey, parameterIndex) => {
|
|
2176
|
+
const token = modelRepositoryToken(model, flavour);
|
|
2177
|
+
registerProvider(token, () => core.Repository.forModel(model, flavour));
|
|
2178
|
+
return common.Inject(token)(target, propertyKey, parameterIndex);
|
|
2179
|
+
};
|
|
2180
|
+
}
|
|
2181
|
+
var DecafCoreModule_1;
|
|
2182
|
+
exports.DecafCoreModule = class DecafCoreModule {
|
|
2183
|
+
static {
|
|
2184
|
+
DecafCoreModule_1 = this;
|
|
2185
|
+
}
|
|
2186
|
+
static get persistence() {
|
|
2187
|
+
if (!this._persistence) throw new dbDecorators.InternalError("Persistence service not initialized");
|
|
2188
|
+
return this._persistence;
|
|
2189
|
+
}
|
|
2190
|
+
static get log() {
|
|
2191
|
+
if (!this._logger) this._logger = logging.Logging.for(DecafCoreModule_1);
|
|
2192
|
+
return this._logger;
|
|
2193
|
+
}
|
|
2194
|
+
constructor(options, moduleRef) {
|
|
2195
|
+
this.options = options;
|
|
2196
|
+
this.moduleRef = moduleRef;
|
|
2197
|
+
}
|
|
2198
|
+
static forRoot(options) {
|
|
2199
|
+
const log = this.log.for(this.forRoot);
|
|
2200
|
+
const decafProviders = getRegisteredDecafProviders();
|
|
2201
|
+
return {
|
|
2202
|
+
module: DecafCoreModule_1,
|
|
2203
|
+
providers: [ {
|
|
2204
|
+
provide: DECAF_MODULE_OPTIONS,
|
|
2205
|
+
useValue: options
|
|
2206
|
+
}, {
|
|
2207
|
+
provide: DECAF_ADAPTER_ID,
|
|
2208
|
+
useValue: this.persistence?.client
|
|
2209
|
+
}, {
|
|
2210
|
+
provide: DECAF_HANDLERS,
|
|
2211
|
+
useFactory: () => options.handlers?.map(H => {
|
|
2212
|
+
log.info(`Registered request handler: ${H.name}`);
|
|
2213
|
+
return new H;
|
|
2214
|
+
}) ?? []
|
|
2215
|
+
}, exports.DecafRequestContext, exports.DecafHandlerExecutor, {
|
|
2216
|
+
provide: core$1.APP_INTERCEPTOR,
|
|
2217
|
+
useClass: exports.DecafRequestHandlerInterceptor
|
|
2218
|
+
}, ...decafProviders ],
|
|
2219
|
+
exports: [ DECAF_MODULE_OPTIONS, DECAF_ADAPTER_ID, DECAF_HANDLERS, exports.DecafRequestContext, exports.DecafHandlerExecutor, ...decafProviders.map(provider => provider.provide) ]
|
|
2220
|
+
};
|
|
2221
|
+
}
|
|
2222
|
+
static async bootPersistence(options) {
|
|
2223
|
+
const log = this.log.for(this.bootPersistence);
|
|
2224
|
+
if (!this._persistence) {
|
|
2225
|
+
const trimmed = options.conf.map(([contr, cfg, ...args]) => {
|
|
2226
|
+
const possible = args.pop();
|
|
2227
|
+
if (!possible) return [ contr, cfg ];
|
|
2228
|
+
return [ contr, cfg, ...args ];
|
|
2229
|
+
});
|
|
2230
|
+
this._persistence = new core.PersistenceService;
|
|
2231
|
+
await this._persistence.boot(trimmed);
|
|
2232
|
+
const clients = this._persistence.client;
|
|
2233
|
+
for (let i = 0; i < clients.length; i++) {
|
|
2234
|
+
const c = options.conf[i];
|
|
2235
|
+
const possibleTransf = c.slice(2, c.length);
|
|
2236
|
+
let transformer = possibleTransf.pop();
|
|
2237
|
+
if (!transformer || !transformer.from) {
|
|
2238
|
+
const contr = core.Adapter.transformerFor(clients[i].flavour);
|
|
2239
|
+
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`);
|
|
2240
|
+
try {
|
|
2241
|
+
transformer = contr.from ? contr : new contr;
|
|
2242
|
+
} catch (e) {
|
|
2243
|
+
throw new dbDecorators.InternalError(`Failed to boot transformer for ${clients[i].flavour}: ${e}`);
|
|
2244
|
+
}
|
|
2245
|
+
}
|
|
2246
|
+
server.requestToContextTransformer(clients[i].flavour)(transformer);
|
|
2247
|
+
}
|
|
2248
|
+
log.info("persistence layer created successfully!");
|
|
2249
|
+
if (options.initialization) {
|
|
2250
|
+
try {
|
|
2251
|
+
await options.initialization();
|
|
2252
|
+
} catch (e) {
|
|
2253
|
+
throw new dbDecorators.InternalError(`Failed to initialize application: ${e}`);
|
|
2254
|
+
}
|
|
2255
|
+
}
|
|
2256
|
+
}
|
|
2257
|
+
return this.persistence.client;
|
|
2258
|
+
}
|
|
2259
|
+
async onApplicationShutdown() {
|
|
2260
|
+
const log = DecafCoreModule_1.log.for(this.onApplicationShutdown);
|
|
2261
|
+
const adapters = this.moduleRef.get(DECAF_ADAPTER_ID);
|
|
2262
|
+
for (const adapter of adapters) try {
|
|
2263
|
+
if (adapter) {
|
|
2264
|
+
log.info(`Shutting down ${adapter.toString()}`);
|
|
2265
|
+
await adapter.shutdown();
|
|
2266
|
+
}
|
|
2267
|
+
} catch (e) {
|
|
2268
|
+
log.error(`Failed to shutdown application`, e);
|
|
2269
|
+
}
|
|
2270
|
+
try {
|
|
2271
|
+
await core.Service.shutdown();
|
|
2272
|
+
} catch (e) {
|
|
2273
|
+
log.error(`Failed to shutdown services`, e);
|
|
2274
|
+
}
|
|
2275
|
+
}
|
|
2276
|
+
};
|
|
2277
|
+
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);
|
|
2278
|
+
const LISTENING_ADAPTERS_FLAVOURS = Symbol("LISTENING_ADAPTERS_FLAVOURS");
|
|
2279
|
+
const OBSERVER_EVENTS_OPTIONS = Symbol("OBSERVER_EVENTS_OPTIONS");
|
|
2280
|
+
function normalizeEventResponse(args) {
|
|
2281
|
+
const [modelConstr, operation, id, payload] = args;
|
|
2282
|
+
const modelName = modelConstr?.name ?? modelConstr;
|
|
2283
|
+
const serializedPayload = Array.isArray(payload) ? payload.map(e => {
|
|
2284
|
+
try {
|
|
2285
|
+
if (typeof e.serialize === "function") return e.serialize();
|
|
2286
|
+
console.warn(`Payload item for ${modelName} does not have serialize method and is an ${typeof e}, attempting to stringify directly. Item: ${e}`);
|
|
2287
|
+
return typeof e === "string" ? e : JSON.stringify(e);
|
|
2288
|
+
} catch (err) {
|
|
2289
|
+
console.warn(`Failed to serialize payload for ${modelName}: ${err}`);
|
|
2290
|
+
return undefined;
|
|
2291
|
+
}
|
|
2292
|
+
}) : payload && typeof payload.serialize === "function" ? payload.serialize() : typeof payload === "string" ? payload : JSON.stringify(payload);
|
|
2293
|
+
console.debug(`Normalized event response for model ${modelName}, operation ${operation}, id ${id}:`, serializedPayload);
|
|
2294
|
+
return [ modelName, operation, id, serializedPayload ];
|
|
2295
|
+
}
|
|
2296
|
+
exports.ObserverSubscriptionRegistry = class ObserverSubscriptionRegistry {
|
|
2297
|
+
constructor() {
|
|
2298
|
+
this.records = new Map;
|
|
2299
|
+
}
|
|
2300
|
+
upsert(subscriberId, topics = []) {
|
|
2301
|
+
const record = {
|
|
2302
|
+
subscriberId: subscriberId,
|
|
2303
|
+
topics: new Set(topics.filter(Boolean)),
|
|
2304
|
+
updatedAt: new Date
|
|
2305
|
+
};
|
|
2306
|
+
this.records.set(subscriberId, record);
|
|
2307
|
+
return record;
|
|
2308
|
+
}
|
|
2309
|
+
remove(subscriberId) {
|
|
2310
|
+
return this.records.delete(subscriberId);
|
|
2311
|
+
}
|
|
2312
|
+
get(subscriberId) {
|
|
2313
|
+
return this.records.get(subscriberId);
|
|
2314
|
+
}
|
|
2315
|
+
topicsFor(subscriberId) {
|
|
2316
|
+
return [ ...this.records.get(subscriberId)?.topics ?? [] ];
|
|
2317
|
+
}
|
|
2318
|
+
matches(subscriberId, topic) {
|
|
2319
|
+
const record = this.records.get(subscriberId);
|
|
2320
|
+
if (!record) return false;
|
|
2321
|
+
if (!record.topics.size) return false;
|
|
2322
|
+
return record.topics.has(topic) || record.topics.has("*");
|
|
2323
|
+
}
|
|
2324
|
+
};
|
|
2325
|
+
exports.ObserverSubscriptionRegistry = tslib.__decorate([ common.Injectable() ], exports.ObserverSubscriptionRegistry);
|
|
2326
|
+
var EventsController_1;
|
|
2327
|
+
exports.EventsController = EventsController_1 = class EventsController extends DecafController {
|
|
2328
|
+
constructor(clientContext, flavours, options, registry) {
|
|
2329
|
+
super(clientContext, EventsController_1.name);
|
|
2330
|
+
this.options = options;
|
|
2331
|
+
this.registry = registry;
|
|
2332
|
+
this.adapters = flavours.map(flavour => core.Adapter.get(flavour));
|
|
2333
|
+
}
|
|
2334
|
+
listen(subscriberId) {
|
|
2335
|
+
const logger = logging.Logging.for(EventsController_1.name);
|
|
2336
|
+
const subscriptionMode = Boolean(this.options.subscriptionMode);
|
|
2337
|
+
if (subscriptionMode && !subscriberId) {
|
|
2338
|
+
throw new common.BadRequestException("subscriberId is required when subscriptionMode is enabled");
|
|
2339
|
+
}
|
|
2340
|
+
const activeSubscriberId = subscriberId ?? "";
|
|
2341
|
+
const events$ = new rxjs.Observable(observer => {
|
|
2342
|
+
const observerId = `B-${Math.random().toString(36).slice(2, 8)}`.toUpperCase();
|
|
2343
|
+
logger.info(`Creating SSE observer: ${observerId} for client ${this.clientContext.uuid}`);
|
|
2344
|
+
const cb = new class {
|
|
2345
|
+
constructor() {
|
|
2346
|
+
this.observerId = observerId;
|
|
2347
|
+
}
|
|
2348
|
+
refresh(...args) {
|
|
2349
|
+
logger.debug(`SSE observer ${this.observerId} received refresh event`);
|
|
2350
|
+
return Promise.resolve().then(() => {
|
|
2351
|
+
const data = normalizeEventResponse(args);
|
|
2352
|
+
observer.next({
|
|
2353
|
+
type: "message",
|
|
2354
|
+
data: data
|
|
2355
|
+
});
|
|
2356
|
+
logger.debug(`SSE observer ${this.observerId} event pushed to client`);
|
|
2357
|
+
});
|
|
2358
|
+
}
|
|
2359
|
+
};
|
|
2360
|
+
const filter = subscriptionMode ? (model, ..._args) => {
|
|
2361
|
+
const topic = typeof model === "string" ? model : model?.name ?? model?.constructor?.name;
|
|
2362
|
+
if (!topic) return false;
|
|
2363
|
+
return this.registry.matches(activeSubscriberId, topic);
|
|
2364
|
+
} : undefined;
|
|
2365
|
+
logger.verbose(`Registering observer ${observerId} across ${this.adapters.length} adapter(s)`);
|
|
2366
|
+
for (const adapter of this.adapters) {
|
|
2367
|
+
const adapterName = adapter?.constructor?.name ?? "UnknownAdapter";
|
|
2368
|
+
try {
|
|
2369
|
+
logger.debug(`Registering observer ${observerId} in adapter ${adapterName}`);
|
|
2370
|
+
adapter.observe(cb, filter);
|
|
2371
|
+
} catch (e) {
|
|
2372
|
+
logger.debug(`Failed to register observer ${observerId} in adapter ${adapterName}: ${e?.message || e}`);
|
|
2373
|
+
logger.error(e);
|
|
2374
|
+
}
|
|
2375
|
+
}
|
|
2376
|
+
return () => {
|
|
2377
|
+
logger.debug(`Cleaning up SSE observer ${observerId}`);
|
|
2378
|
+
for (const adapter of this.adapters) {
|
|
2379
|
+
const adapterName = adapter?.constructor?.name ?? "UnknownAdapter";
|
|
2380
|
+
try {
|
|
2381
|
+
logger.debug(`Unregistering observer ${observerId} from adapter ${adapterName}`);
|
|
2382
|
+
adapter.unObserve(cb);
|
|
2383
|
+
} catch (e) {
|
|
2384
|
+
logger.debug(`Failed during cleanup of observer ${observerId} in adapter ${adapterName}: ${e?.message || e}`);
|
|
2385
|
+
logger.error(e);
|
|
2386
|
+
}
|
|
2387
|
+
}
|
|
2388
|
+
if (subscriptionMode) {
|
|
2389
|
+
this.registry.remove(activeSubscriberId);
|
|
2390
|
+
}
|
|
2391
|
+
};
|
|
2392
|
+
});
|
|
2393
|
+
const HEARTBEAT_INTERVAL_MS = 15e3;
|
|
2394
|
+
const heartbeat$ = rxjs.interval(HEARTBEAT_INTERVAL_MS).pipe(operators.tap(() => {
|
|
2395
|
+
logger.debug("Sending heartbeat");
|
|
2396
|
+
}), operators.map(() => ({
|
|
2397
|
+
type: "heartbeat",
|
|
2398
|
+
data: {
|
|
2399
|
+
ts: (new Date).toISOString()
|
|
2400
|
+
}
|
|
2401
|
+
})));
|
|
2402
|
+
return rxjs.merge(events$, heartbeat$);
|
|
2403
|
+
}
|
|
2404
|
+
listenForModel(model) {
|
|
2405
|
+
const logger = logging.Logging.for(EventsController_1.name);
|
|
2406
|
+
return new rxjs.Observable(observer => {
|
|
2407
|
+
const cb = new class {
|
|
2408
|
+
refresh(...args) {
|
|
2409
|
+
return Promise.resolve().then(() => {
|
|
2410
|
+
observer.next({
|
|
2411
|
+
data: args
|
|
2412
|
+
});
|
|
2413
|
+
});
|
|
2414
|
+
}
|
|
2415
|
+
};
|
|
2416
|
+
try {
|
|
2417
|
+
for (const adapter of this.adapters) {
|
|
2418
|
+
adapter.observe(cb);
|
|
2419
|
+
}
|
|
2420
|
+
} catch (e) {
|
|
2421
|
+
observer.error(`Failed to observe event: ${e.message || e}`);
|
|
2422
|
+
}
|
|
2423
|
+
return () => {
|
|
2424
|
+
try {
|
|
2425
|
+
for (const adapter of this.adapters) {
|
|
2426
|
+
adapter.unObserve(cb);
|
|
2427
|
+
}
|
|
2428
|
+
} catch (e) {
|
|
2429
|
+
logger.error(e);
|
|
2430
|
+
}
|
|
2431
|
+
};
|
|
2432
|
+
});
|
|
2433
|
+
}
|
|
2434
|
+
};
|
|
2435
|
+
tslib.__decorate([ common.Sse(), tslib.__param(0, common.Query("subscriberId")), tslib.__metadata("design:type", Function), tslib.__metadata("design:paramtypes", [ String ]), tslib.__metadata("design:returntype", rxjs.Observable) ], exports.EventsController.prototype, "listen", null);
|
|
2436
|
+
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);
|
|
2437
|
+
exports.EventsController = EventsController_1 = tslib.__decorate([ common.Controller(), tslib.__param(1, common.Inject(LISTENING_ADAPTERS_FLAVOURS)), tslib.__param(2, common.Inject(OBSERVER_EVENTS_OPTIONS)), tslib.__metadata("design:paramtypes", [ exports.DecafRequestContext, Array, Object, exports.ObserverSubscriptionRegistry ]) ], exports.EventsController);
|
|
2438
|
+
var EventsSubscriptionController_1;
|
|
2439
|
+
exports.EventsSubscriptionController = EventsSubscriptionController_1 = class EventsSubscriptionController extends DecafController {
|
|
2440
|
+
constructor(clientContext, options, registry) {
|
|
2441
|
+
super(clientContext, EventsSubscriptionController_1.name);
|
|
2442
|
+
this.options = options;
|
|
2443
|
+
this.registry = registry;
|
|
2444
|
+
}
|
|
2445
|
+
async subscribe(body) {
|
|
2446
|
+
if (!this.options.subscriptionMode) {
|
|
2447
|
+
return {
|
|
2448
|
+
enabled: false
|
|
2449
|
+
};
|
|
2450
|
+
}
|
|
2451
|
+
const subscriberId = body?.subscriberId || await Promise.resolve(core.UUID.instance.generate());
|
|
2452
|
+
const topics = Array.isArray(body?.topics) ? body.topics : [];
|
|
2453
|
+
const record = this.registry.upsert(subscriberId, topics);
|
|
2454
|
+
return {
|
|
2455
|
+
subscriberId: record.subscriberId,
|
|
2456
|
+
topics: this.registry.topicsFor(record.subscriberId)
|
|
2457
|
+
};
|
|
2458
|
+
}
|
|
2459
|
+
unsubscribe(body) {
|
|
2460
|
+
if (!this.options.subscriptionMode) {
|
|
2461
|
+
return {
|
|
2462
|
+
enabled: false
|
|
2463
|
+
};
|
|
2464
|
+
}
|
|
2465
|
+
const subscriberId = body?.subscriberId;
|
|
2466
|
+
if (!subscriberId) {
|
|
2467
|
+
return {
|
|
2468
|
+
unsubscribed: false
|
|
2469
|
+
};
|
|
2470
|
+
}
|
|
2471
|
+
return {
|
|
2472
|
+
unsubscribed: this.registry.remove(subscriberId),
|
|
2473
|
+
subscriberId: subscriberId
|
|
2474
|
+
};
|
|
2475
|
+
}
|
|
2476
|
+
};
|
|
2477
|
+
tslib.__decorate([ common.Post("subscribe"), tslib.__param(0, common.Body()), tslib.__metadata("design:type", Function), tslib.__metadata("design:paramtypes", [ Object ]), tslib.__metadata("design:returntype", Promise) ], exports.EventsSubscriptionController.prototype, "subscribe", null);
|
|
2478
|
+
tslib.__decorate([ common.Post("unsubscribe"), tslib.__param(0, common.Body()), tslib.__metadata("design:type", Function), tslib.__metadata("design:paramtypes", [ Object ]), tslib.__metadata("design:returntype", Object) ], exports.EventsSubscriptionController.prototype, "unsubscribe", null);
|
|
2479
|
+
exports.EventsSubscriptionController = EventsSubscriptionController_1 = tslib.__decorate([ common.Controller(), tslib.__param(1, common.Inject(OBSERVER_EVENTS_OPTIONS)), tslib.__metadata("design:paramtypes", [ exports.DecafRequestContext, Object, exports.ObserverSubscriptionRegistry ]) ], exports.EventsSubscriptionController);
|
|
2480
|
+
var DecafStreamModule_1;
|
|
2481
|
+
exports.DecafStreamModule = DecafStreamModule_1 = class DecafStreamModule {
|
|
2482
|
+
static forFlavours(flavours, path = "events", options = {}) {
|
|
2483
|
+
const controllers = [ exports.EventsController ];
|
|
2484
|
+
if (options.subscriptionMode) {
|
|
2485
|
+
controllers.push(exports.EventsSubscriptionController);
|
|
2486
|
+
}
|
|
2487
|
+
return {
|
|
2488
|
+
module: DecafStreamModule_1,
|
|
2489
|
+
controllers: controllers,
|
|
2490
|
+
imports: [ core$1.RouterModule.register([ {
|
|
2491
|
+
path: path.replace(/^\//, ""),
|
|
2492
|
+
module: DecafStreamModule_1
|
|
2493
|
+
} ]) ],
|
|
2494
|
+
providers: [ exports.DecafRequestContext, exports.ObserverSubscriptionRegistry, {
|
|
2495
|
+
provide: LISTENING_ADAPTERS_FLAVOURS,
|
|
2496
|
+
useValue: flavours ?? []
|
|
2497
|
+
}, {
|
|
2498
|
+
provide: OBSERVER_EVENTS_OPTIONS,
|
|
2499
|
+
useValue: options ?? {}
|
|
2500
|
+
} ]
|
|
2501
|
+
};
|
|
2502
|
+
}
|
|
2503
|
+
};
|
|
2504
|
+
exports.DecafStreamModule = DecafStreamModule_1 = tslib.__decorate([ common.Module({}) ], exports.DecafStreamModule);
|
|
2505
|
+
var DecafModule_1;
|
|
2506
|
+
exports.DecafModule = DecafModule_1 = class DecafModule {
|
|
2507
|
+
static async forRootAsync(options) {
|
|
2508
|
+
const {autoControllers: autoControllers, autoServices: autoServices} = options;
|
|
2509
|
+
const adapters = await exports.DecafCoreModule.bootPersistence(options);
|
|
2510
|
+
const flavours = adapters.map(adapter => adapter.flavour);
|
|
2511
|
+
const imports = [ exports.DecafCoreModule.forRoot(options) ];
|
|
2512
|
+
if (autoControllers) {
|
|
2513
|
+
flavours.forEach(flavour => {
|
|
2514
|
+
imports.push(getModuleFor(flavour).forRoot(flavour, {
|
|
2515
|
+
autoServices: autoServices,
|
|
2516
|
+
controllerExposure: options.controllerExposure,
|
|
2517
|
+
controllerConfig: options.controllerConfig,
|
|
2518
|
+
aggregations: options.aggregations
|
|
2519
|
+
}));
|
|
2520
|
+
});
|
|
2521
|
+
}
|
|
2522
|
+
if (options.observerOptions?.enableObserverEvents) {
|
|
2523
|
+
imports.push(exports.DecafStreamModule.forFlavours(options.observerOptions.observerFlavours || flavours, options.observerOptions.observerApiPath ?? "/events", options.observerOptions));
|
|
2524
|
+
}
|
|
2525
|
+
return {
|
|
2526
|
+
module: DecafModule_1,
|
|
2527
|
+
imports: imports
|
|
2528
|
+
};
|
|
2529
|
+
}
|
|
2530
|
+
};
|
|
2531
|
+
exports.DecafModule = DecafModule_1 = tslib.__decorate([ common.Module({}) ], exports.DecafModule);
|
|
2532
|
+
async function runMigrations() {}
|
|
2533
|
+
function repoForModel(model) {
|
|
2534
|
+
const m = decoratorValidation.Model.get(model);
|
|
2535
|
+
if (!m) throw new dbDecorators.InternalError(`Failed to find repository for ${model}`);
|
|
2536
|
+
const repo = core.Repository.forModel(m);
|
|
2537
|
+
return repo;
|
|
2538
|
+
}
|
|
2539
|
+
const VERSION = "0.12.2-0";
|
|
2540
|
+
const COMMIT = "612701f";
|
|
2541
|
+
const FULL_VERSION = "0.12.2-0-612701f";
|
|
2542
|
+
const PACKAGE_NAME = "@decaf-ts/for-nest";
|
|
2543
|
+
decoration.Metadata.allowReregistration(true);
|
|
2544
|
+
decoration.Metadata.registerLibrary(PACKAGE_NAME, VERSION);
|
|
2545
|
+
decoration.Metadata.allowReregistration(false);
|
|
2546
|
+
exports.AUTH_HANDLER = AUTH_HANDLER;
|
|
2547
|
+
exports.AUTH_META_KEY = AUTH_META_KEY;
|
|
2548
|
+
exports.ApiOperationFromModel = ApiOperationFromModel;
|
|
2549
|
+
exports.ApiParamsFromModel = ApiParamsFromModel;
|
|
2550
|
+
exports.ApiProperty = ApiProperty;
|
|
2551
|
+
exports.Auth = Auth;
|
|
2552
|
+
exports.BulkApiOperationFromModel = BulkApiOperationFromModel;
|
|
2553
|
+
exports.COMMIT = COMMIT;
|
|
2554
|
+
exports.CorsError = CorsError;
|
|
2555
|
+
exports.DECAF_ADAPTER_ID = DECAF_ADAPTER_ID;
|
|
2556
|
+
exports.DECAF_CONTEXT_KEY = DECAF_CONTEXT_KEY;
|
|
2557
|
+
exports.DECAF_CONTROLLER_CONFIG = DECAF_CONTROLLER_CONFIG;
|
|
2558
|
+
exports.DECAF_EXPOSE = DECAF_EXPOSE;
|
|
2559
|
+
exports.DECAF_HANDLERS = DECAF_HANDLERS;
|
|
2560
|
+
exports.DECAF_MODULE_OPTIONS = DECAF_MODULE_OPTIONS;
|
|
2561
|
+
exports.DECAF_ROUTE = DECAF_ROUTE;
|
|
2562
|
+
exports.DECAF_TASK_SERVICE_ID = DECAF_TASK_SERVICE_ID;
|
|
2563
|
+
exports.DECORATORS = DECORATORS;
|
|
2564
|
+
exports.DECORATORS_PREFIX = DECORATORS_PREFIX;
|
|
2565
|
+
exports.DecafAuthHandler = DecafAuthHandler;
|
|
2566
|
+
exports.DecafBody = DecafBody;
|
|
2567
|
+
exports.DecafController = DecafController;
|
|
2568
|
+
exports.DecafModelController = DecafModelController;
|
|
2569
|
+
exports.DecafParams = DecafParams;
|
|
2570
|
+
exports.DecafRoleAuthHandler = DecafRoleAuthHandler;
|
|
2571
|
+
exports.DtoFor = DtoFor;
|
|
2572
|
+
exports.FULL_VERSION = FULL_VERSION;
|
|
2573
|
+
exports.FromModelController = FromModelController;
|
|
2574
|
+
exports.IS_PUBLIC_KEY = IS_PUBLIC_KEY;
|
|
2575
|
+
exports.LISTENING_ADAPTERS_FLAVOURS = LISTENING_ADAPTERS_FLAVOURS;
|
|
2576
|
+
exports.NestBootstraper = NestBootstraper;
|
|
2577
|
+
exports.OBSERVER_EVENTS_OPTIONS = OBSERVER_EVENTS_OPTIONS;
|
|
2578
|
+
exports.PACKAGE_NAME = PACKAGE_NAME;
|
|
2579
|
+
exports.Public = Public;
|
|
2580
|
+
exports.REQUIRED_NAMESPACES_KEY = REQUIRED_NAMESPACES_KEY;
|
|
2581
|
+
exports.REQUIRED_ROLES_KEY = REQUIRED_ROLES_KEY;
|
|
2582
|
+
exports.Repository = Repository;
|
|
2583
|
+
exports.RequireNamespaces = RequireNamespaces;
|
|
2584
|
+
exports.RequireRoles = RequireRoles;
|
|
2585
|
+
exports.SKIP_MODEL_NAMESPACES_KEY = SKIP_MODEL_NAMESPACES_KEY;
|
|
2586
|
+
exports.SKIP_MODEL_ROLES_KEY = SKIP_MODEL_ROLES_KEY;
|
|
2587
|
+
exports.Service = Service;
|
|
2588
|
+
exports.SwaggerBuilder = SwaggerBuilder;
|
|
2589
|
+
exports.UseDecafFilter = UseDecafFilter;
|
|
2590
|
+
exports.UseDecafHeaders = UseDecafHeaders;
|
|
2591
|
+
exports.VERSION = VERSION;
|
|
2592
|
+
exports.applyApiDecorators = applyApiDecorators;
|
|
2593
|
+
exports.contextualizeRequestContext = contextualizeRequestContext;
|
|
2594
|
+
exports.controllerConfig = controllerConfig;
|
|
2595
|
+
exports.createApiPropertyDecorator = createApiPropertyDecorator;
|
|
2596
|
+
exports.createPropertyDecorator = createPropertyDecorator;
|
|
2597
|
+
exports.createRouteHandler = createRouteHandler;
|
|
2598
|
+
exports.defineRouteMethod = defineRouteMethod;
|
|
2599
|
+
exports.expose = expose;
|
|
2600
|
+
exports.getApiDecorators = getApiDecorators;
|
|
2601
|
+
exports.getEnumType = getEnumType;
|
|
2602
|
+
exports.getEnumValues = getEnumValues;
|
|
2603
|
+
exports.getModuleFor = getModuleFor;
|
|
2604
|
+
exports.getRegisteredDecafProviders = getRegisteredDecafProviders;
|
|
2605
|
+
exports.isUndefined = isUndefined;
|
|
2606
|
+
exports.repoForModel = repoForModel;
|
|
2607
|
+
exports.resolvePersistenceMethod = resolvePersistenceMethod;
|
|
2608
|
+
exports.runMigrations = runMigrations;
|
|
2609
|
+
});
|
|
2610
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm9yLW5lc3QuY2pzIiwic291cmNlcyI6WyIuLi9zcmMvb3ZlcnJpZGVzL2NvbnN0YW50cy50cyIsIi4uL3NyYy9vdmVycmlkZXMvaGVscGVycy50cyIsIi4uL3NyYy9vdmVycmlkZXMvZGVjb3JhdGlvbi50cyIsIi4uL3NyYy9kZWNhZi1tb2RlbC9kZWNvcmF0b3JzL0FwaU9wZXJhdGlvbkZyb21Nb2RlbC50cyIsIi4uL3NyYy9kZWNhZi1tb2RlbC9kZWNvcmF0b3JzL0FwaVBhcmFtc0Zyb21Nb2RlbC50cyIsIi4uL3NyYy9kZWNhZi1tb2RlbC9kZWNvcmF0b3JzL0RlY2FmQm9keS50cyIsIi4uL3NyYy9kZWNhZi1tb2RlbC9kZWNvcmF0b3JzL0RlY2FmUGFyYW1zLnRzIiwiLi4vc3JjL2NvbnN0YW50cy50cyIsIi4uL3NyYy9kZWNhZi1tb2RlbC9kZWNvcmF0b3JzL2V4cG9zZS50cyIsIi4uL3NyYy9kZWNhZi1tb2RlbC9kZWNvcmF0b3JzL2NvbnRyb2xsZXItY29uZmlnLnRzIiwiLi4vc3JjL2F1dGgvY29uc3RhbnRzLnRzIiwiLi4vc3JjL3JlcXVlc3QvRGVjYWZSZXF1ZXN0Q29udGV4dC50cyIsIi4uL3NyYy9hdXRoL0F1dGhJbnRlcmNlcHRvci50cyIsIi4uL3NyYy9hdXRoL2RlY29yYXRvcnMudHMiLCIuLi9zcmMvZGVjYWYtbW9kZWwvZGVjb3JhdG9ycy91dGlscy50cyIsIi4uL3NyYy9kZWNhZi1tb2RlbC91dGlscy50cyIsIi4uL3NyYy9yZXF1ZXN0L2NvbnRleHR1YWxpemUudHMiLCIuLi9zcmMvYXV0aC9BdXRoTWlkZGxld2FyZS50cyIsIi4uL3NyYy9hdXRoL0RlY2FmQXV0aEhhbmRsZXIudHMiLCIuLi9zcmMvYXV0aC9EZWNhZkF1dGhNb2R1bGUudHMiLCIuLi9zcmMvcmVxdWVzdC9EZWNhZkhhbmRsZXJFeGVjdXRvci50cyIsIi4uL3NyYy9yZXF1ZXN0L0RlY2FmUmVzcG9uc2VJbnRlcmNlcHRvci50cyIsIi4uL3NyYy9jb250cm9sbGVycy50cyIsIi4uL3NyYy9mYWN0b3J5L29wZW5hcGkvRHRvQnVpbGRlci50cyIsIi4uL3NyYy9vdmVycmlkZXMvb3ZlcnJpZGVzLnRzIiwiLi4vc3JjL292ZXJyaWRlcy9Nb2RlbEJ1aWxkZXJFeHRlbnNpb25zLnRzIiwiLi4vc3JjL2RlY2FmLW1vZGVsL0Zyb21Nb2RlbENvbnRyb2xsZXIudHMiLCIuLi9zcmMvZGVjYWYtbW9kZWwvRGVjYWZNb2RlbE1vZHVsZS50cyIsIi4uL3NyYy9kZWNvcmF0aW9uLnRzIiwiLi4vc3JjL2ZhY3RvcnkvZXJyb3JzL2NvcnMudHMiLCIuLi9zcmMvZmFjdG9yeS9lcnJvcnMvdGhyb3R0bGluZy50cyIsIi4uL3NyYy9mYWN0b3J5L2V4Y2VwdGlvbnMvRGVjYWZFcnJvckZpbHRlci50cyIsIi4uL3NyYy9mYWN0b3J5L2V4Y2VwdGlvbnMvZGVjb3JhdG9ycy50cyIsIi4uL3NyYy9mYWN0b3J5L29wZW5hcGkvY29uc3RhbnRzLnRzIiwiLi4vc3JjL2ZhY3Rvcnkvb3BlbmFwaS9Td2FnZ2VyQ3VzdG9tVUkudHMiLCIuLi9zcmMvZmFjdG9yeS9vcGVuYXBpL1N3YWdnZXJCdWlsZGVyLnRzIiwiLi4vc3JjL2ZhY3RvcnkvTmVzdEJvb3RzdHJhcGVyLnRzIiwiLi4vc3JjL2ludGVyY2VwdG9ycy9EZWNhZlJlcXVlc3RIYW5kbGVySW50ZXJjZXB0b3IudHMiLCIuLi9zcmMvZGVjb3JhdG9ycy50cyIsIi4uL3NyYy9jb3JlLW1vZHVsZS50cyIsIi4uL3NyYy9ldmVudHMtbW9kdWxlL2NvbnN0YW50LnRzIiwiLi4vc3JjL2V2ZW50cy1tb2R1bGUvdXRpbHMudHMiLCIuLi9zcmMvZXZlbnRzLW1vZHVsZS9PYnNlcnZlclN1YnNjcmlwdGlvblJlZ2lzdHJ5LnRzIiwiLi4vc3JjL2V2ZW50cy1tb2R1bGUvRXZlbnRzQ29udHJvbGxlci50cyIsIi4uL3NyYy9ldmVudHMtbW9kdWxlL0V2ZW50c1N1YnNjcmlwdGlvbkNvbnRyb2xsZXIudHMiLCIuLi9zcmMvZXZlbnRzLW1vZHVsZS9EZWNhZlN0cmVhbU1vZHVsZS50cyIsIi4uL3NyYy9tb2R1bGUudHMiLCIuLi9zcmMvdXRpbHMudHMiLCIuLi9zcmMvaW5kZXgudHMiXSwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0IGNvbnN0IERFQ09SQVRPUlNfUFJFRklYID0gXCJzd2FnZ2VyXCI7XG5leHBvcnQgY29uc3QgREVDT1JBVE9SUyA9IHtcbiAgQVBJX09QRVJBVElPTjogYCR7REVDT1JBVE9SU19QUkVGSVh9L2FwaU9wZXJhdGlvbmAsXG4gIEFQSV9SRVNQT05TRTogYCR7REVDT1JBVE9SU19QUkVGSVh9L2FwaVJlc3BvbnNlYCxcbiAgQVBJX1BST0RVQ0VTOiBgJHtERUNPUkFUT1JTX1BSRUZJWH0vYXBpUHJvZHVjZXNgLFxuICBBUElfQ09OU1VNRVM6IGAke0RFQ09SQVRPUlNfUFJFRklYfS9hcGlDb25zdW1lc2AsXG4gIEFQSV9UQUdTOiBgJHtERUNPUkFUT1JTX1BSRUZJWH0vYXBpVXNlVGFnc2AsXG4gIEFQSV9DQUxMQkFDS1M6IGAke0RFQ09SQVRPUlNfUFJFRklYfS9hcGlDYWxsYmFja3NgLFxuICBBUElfUEFSQU1FVEVSUzogYCR7REVDT1JBVE9SU19QUkVGSVh9L2FwaVBhcmFtZXRlcnNgLFxuICBBUElfSEVBREVSUzogYCR7REVDT1JBVE9SU19QUkVGSVh9L2FwaUhlYWRlcnNgLFxuICBBUElfTU9ERUxfUFJPUEVSVElFUzogYCR7REVDT1JBVE9SU19QUkVGSVh9L2FwaU1vZGVsUHJvcGVydGllc2AsXG4gIEFQSV9NT0RFTF9QUk9QRVJUSUVTX0FSUkFZOiBgJHtERUNPUkFUT1JTX1BSRUZJWH0vYXBpTW9kZWxQcm9wZXJ0aWVzQXJyYXlgLFxuICBBUElfU0VDVVJJVFk6IGAke0RFQ09SQVRPUlNfUFJFRklYfS9hcGlTZWN1cml0eWAsXG4gIEFQSV9FWENMVURFX0VORFBPSU5UOiBgJHtERUNPUkFUT1JTX1BSRUZJWH0vYXBpRXhjbHVkZUVuZHBvaW50YCxcbiAgQVBJX0VYQ0xVREVfQ09OVFJPTExFUjogYCR7REVDT1JBVE9SU19QUkVGSVh9L2FwaUV4Y2x1ZGVDb250cm9sbGVyYCxcbiAgQVBJX0VYVFJBX01PREVMUzogYCR7REVDT1JBVE9SU19QUkVGSVh9L2FwaUV4dHJhTW9kZWxzYCxcbiAgQVBJX0VYVEVOU0lPTjogYCR7REVDT1JBVE9SU19QUkVGSVh9L2FwaUV4dGVuc2lvbmAsXG4gIEFQSV9TQ0hFTUE6IGAke0RFQ09SQVRPUlNfUFJFRklYfS9hcGlTY2hlbWFgLFxuICBBUElfREVGQVVMVF9HRVRURVI6IGAke0RFQ09SQVRPUlNfUFJFRklYfS9hcGlEZWZhdWx0R2V0dGVyYCxcbiAgQVBJX0xJTks6IGAke0RFQ09SQVRPUlNfUFJFRklYfS9hcGlMaW5rYCxcbn07XG4iLCJpbXBvcnQgeyBpc0FycmF5LCBpc1VuZGVmaW5lZCwgbmVnYXRlLCBwaWNrQnkgfSBmcm9tIFwibG9kYXNoXCI7XG5pbXBvcnQgeyBERUNPUkFUT1JTIH0gZnJvbSBcIi4vY29uc3RhbnRzXCI7XG5cbmV4cG9ydCBjb25zdCBpc0NvbnN0cnVjdG9yID0gKHZhbDogYW55KTogYm9vbGVhbiA9PiB2YWwgPT09IFwiY29uc3RydWN0b3JcIjtcbmV4cG9ydCBjb25zdCBNRVRBREFUQV9GQUNUT1JZX05BTUUgPSBcIl9PUEVOQVBJX01FVEFEQVRBX0ZBQ1RPUllcIjtcblxuZXhwb3J0IGNvbnN0IE1FVEhPRF9NRVRBREFUQSA9IFwibWV0aG9kXCI7XG5cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVNZXRob2REZWNvcmF0b3I8VCA9IGFueT4oXG4gIG1ldGFrZXk6IHN0cmluZyxcbiAgbWV0YWRhdGE6IFQsXG4gIHsgb3ZlcnJpZGVFeGlzdGluZyB9ID0geyBvdmVycmlkZUV4aXN0aW5nOiB0cnVlIH1cbik6IE1ldGhvZERlY29yYXRvciB7XG4gIHJldHVybiAoXG4gICAgdGFyZ2V0OiBvYmplY3QsXG4gICAga2V5OiBzdHJpbmcgfCBzeW1ib2wsXG4gICAgZGVzY3JpcHRvcjogUHJvcGVydHlEZXNjcmlwdG9yXG4gICkgPT4ge1xuICAgIGlmICh0eXBlb2YgbWV0YWRhdGEgPT09IFwib2JqZWN0XCIpIHtcbiAgICAgIGNvbnN0IHByZXZWYWx1ZSA9IFJlZmxlY3QuZ2V0TWV0YWRhdGEobWV0YWtleSwgZGVzY3JpcHRvci52YWx1ZSk7XG4gICAgICBpZiAocHJldlZhbHVlICYmICFvdmVycmlkZUV4aXN0aW5nKSB7XG4gICAgICAgIHJldHVybiBkZXNjcmlwdG9yO1xuICAgICAgfVxuICAgICAgUmVmbGVjdC5kZWZpbmVNZXRhZGF0YShcbiAgICAgICAgbWV0YWtleSxcbiAgICAgICAgeyAuLi5wcmV2VmFsdWUsIC4uLm1ldGFkYXRhIH0sXG4gICAgICAgIGRlc2NyaXB0b3IudmFsdWVcbiAgICAgICk7XG4gICAgICByZXR1cm4gZGVzY3JpcHRvcjtcbiAgICB9XG4gICAgUmVmbGVjdC5kZWZpbmVNZXRhZGF0YShtZXRha2V5LCBtZXRhZGF0YSwgZGVzY3JpcHRvci52YWx1ZSk7XG4gICAgcmV0dXJuIGRlc2NyaXB0b3I7XG4gIH07XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVDbGFzc0RlY29yYXRvcjxUIGV4dGVuZHMgQXJyYXk8YW55PiA9IGFueT4oXG4gIG1ldGFrZXk6IHN0cmluZyxcbiAgbWV0YWRhdGE6IFQgPSBbXSBhcyBhbnlcbik6IENsYXNzRGVjb3JhdG9yIHtcbiAgcmV0dXJuICh0YXJnZXQpID0+IHtcbiAgICBjb25zdCBwcmV2VmFsdWUgPSBSZWZsZWN0LmdldE1ldGFkYXRhKG1ldGFrZXksIHRhcmdldCkgfHwgW107XG4gICAgUmVmbGVjdC5kZWZpbmVNZXRhZGF0YShtZXRha2V5LCBbLi4ucHJldlZhbHVlLCAuLi5tZXRhZGF0YV0sIHRhcmdldCk7XG4gICAgcmV0dXJuIHRhcmdldDtcbiAgfTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZVByb3BlcnR5RGVjb3JhdG9yPFQgZXh0ZW5kcyBSZWNvcmQ8c3RyaW5nLCBhbnk+ID0gYW55PihcbiAgbWV0YWtleTogc3RyaW5nLFxuICBtZXRhZGF0YTogVCxcbiAgb3ZlcnJpZGVFeGlzdGluZyA9IHRydWVcbik6IFByb3BlcnR5RGVjb3JhdG9yIHtcbiAgcmV0dXJuICgodGFyZ2V0OiBvYmplY3QsIHByb3BlcnR5S2V5OiBzdHJpbmcpID0+IHtcbiAgICBjb25zdCBwcm9wZXJ0aWVzID1cbiAgICAgIFJlZmxlY3QuZ2V0TWV0YWRhdGEoREVDT1JBVE9SUy5BUElfTU9ERUxfUFJPUEVSVElFU19BUlJBWSwgdGFyZ2V0KSB8fCBbXTtcblxuICAgIGNvbnN0IGtleSA9IGA6JHtwcm9wZXJ0eUtleX1gO1xuICAgIGlmICghcHJvcGVydGllcy5pbmNsdWRlcyhrZXkpKSB7XG4gICAgICBSZWZsZWN0LmRlZmluZU1ldGFkYXRhKFxuICAgICAgICBERUNPUkFUT1JTLkFQSV9NT0RFTF9QUk9QRVJUSUVTX0FSUkFZLFxuICAgICAgICBbLi4ucHJvcGVydGllcywgYDoke3Byb3BlcnR5S2V5fWBdLFxuICAgICAgICB0YXJnZXRcbiAgICAgICk7XG4gICAgfVxuICAgIGNvbnN0IGV4aXN0aW5nTWV0YWRhdGEgPSBSZWZsZWN0LmdldE1ldGFkYXRhKG1ldGFrZXksIHRhcmdldCwgcHJvcGVydHlLZXkpO1xuICAgIGlmIChleGlzdGluZ01ldGFkYXRhKSB7XG4gICAgICBjb25zdCBuZXdNZXRhZGF0YSA9IHBpY2tCeShtZXRhZGF0YSwgbmVnYXRlKGlzVW5kZWZpbmVkKSk7XG4gICAgICBjb25zdCBtZXRhZGF0YVRvU2F2ZSA9IG92ZXJyaWRlRXhpc3RpbmdcbiAgICAgICAgPyB7XG4gICAgICAgICAgICAuLi5leGlzdGluZ01ldGFkYXRhLFxuICAgICAgICAgICAgLi4ubmV3TWV0YWRhdGEsXG4gICAgICAgICAgfVxuICAgICAgICA6IHtcbiAgICAgICAgICAgIC4uLm5ld01ldGFkYXRhLFxuICAgICAgICAgICAgLi4uZXhpc3RpbmdNZXRhZGF0YSxcbiAgICAgICAgICB9O1xuXG4gICAgICBSZWZsZWN0LmRlZmluZU1ldGFkYXRhKG1ldGFrZXksIG1ldGFkYXRhVG9TYXZlLCB0YXJnZXQsIHByb3BlcnR5S2V5KTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3QgdHlwZSA9XG4gICAgICAgICh0YXJnZXQ/LmNvbnN0cnVjdG9yIGFzIGFueSk/LltNRVRBREFUQV9GQUNUT1JZX05BTUUgYXMgYW55XT8uKClbXG4gICAgICAgICAgcHJvcGVydHlLZXlcbiAgICAgICAgXT8udHlwZSA/PyBSZWZsZWN0LmdldE1ldGFkYXRhKFwiZGVzaWduOnR5cGVcIiwgdGFyZ2V0LCBwcm9wZXJ0eUtleSk7XG5cbiAgICAgIFJlZmxlY3QuZGVmaW5lTWV0YWRhdGEoXG4gICAgICAgIG1ldGFrZXksXG4gICAgICAgIHtcbiAgICAgICAgICB0eXBlLFxuICAgICAgICAgIC4uLnBpY2tCeShtZXRhZGF0YSwgbmVnYXRlKGlzVW5kZWZpbmVkKSksXG4gICAgICAgIH0sXG4gICAgICAgIHRhcmdldCxcbiAgICAgICAgcHJvcGVydHlLZXlcbiAgICAgICk7XG4gICAgfVxuICB9KSBhcyBQcm9wZXJ0eURlY29yYXRvcjtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZU1peGVkRGVjb3JhdG9yPFQgPSBhbnk+KFxuICBtZXRha2V5OiBzdHJpbmcsXG4gIG1ldGFkYXRhOiBUXG4pOiBNZXRob2REZWNvcmF0b3IgJiBDbGFzc0RlY29yYXRvciB7XG4gIHJldHVybiAoXG4gICAgdGFyZ2V0OiBvYmplY3QsXG4gICAga2V5Pzogc3RyaW5nIHwgc3ltYm9sLFxuICAgIGRlc2NyaXB0b3I/OiBUeXBlZFByb3BlcnR5RGVzY3JpcHRvcjxhbnk+XG4gICk6IGFueSA9PiB7XG4gICAgaWYgKGRlc2NyaXB0b3IpIHtcbiAgICAgIGxldCBtZXRhZGF0YXM6IGFueTtcbiAgICAgIGlmIChBcnJheS5pc0FycmF5KG1ldGFkYXRhKSkge1xuICAgICAgICBjb25zdCBwcmV2aW91c01ldGFkYXRhID1cbiAgICAgICAgICBSZWZsZWN0LmdldE1ldGFkYXRhKG1ldGFrZXksIGRlc2NyaXB0b3IudmFsdWUpIHx8IFtdO1xuICAgICAgICBtZXRhZGF0YXMgPSBbLi4ucHJldmlvdXNNZXRhZGF0YSwgLi4ubWV0YWRhdGFdO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uc3QgcHJldmlvdXNNZXRhZGF0YSA9XG4gICAgICAgICAgUmVmbGVjdC5nZXRNZXRhZGF0YShtZXRha2V5LCBkZXNjcmlwdG9yLnZhbHVlKSB8fCB7fTtcbiAgICAgICAgbWV0YWRhdGFzID0geyAuLi5wcmV2aW91c01ldGFkYXRhLCAuLi5tZXRhZGF0YSB9O1xuICAgICAgfVxuICAgICAgUmVmbGVjdC5kZWZpbmVNZXRhZGF0YShtZXRha2V5LCBtZXRhZGF0YXMsIGRlc2NyaXB0b3IudmFsdWUpO1xuICAgICAgcmV0dXJuIGRlc2NyaXB0b3I7XG4gICAgfVxuXG4gICAgbGV0IG1ldGFkYXRhczogYW55O1xuICAgIGlmIChBcnJheS5pc0FycmF5KG1ldGFkYXRhKSkge1xuICAgICAgY29uc3QgcHJldmlvdXNNZXRhZGF0YSA9IFJlZmxlY3QuZ2V0TWV0YWRhdGEobWV0YWtleSwgdGFyZ2V0KSB8fCBbXTtcbiAgICAgIG1ldGFkYXRhcyA9IFsuLi5wcmV2aW91c01ldGFkYXRhLCAuLi5tZXRhZGF0YV07XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnN0IHByZXZpb3VzTWV0YWRhdGEgPSBSZWZsZWN0LmdldE1ldGFkYXRhKG1ldGFrZXksIHRhcmdldCkgfHwge307XG4gICAgICBtZXRhZGF0YXMgPSBPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sIHByZXZpb3VzTWV0YWRhdGEpLCBtZXRhZGF0YSk7XG4gICAgfVxuICAgIFJlZmxlY3QuZGVmaW5lTWV0YWRhdGEobWV0YWtleSwgbWV0YWRhdGFzLCB0YXJnZXQpO1xuICAgIHJldHVybiB0YXJnZXQ7XG4gIH07XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVQYXJhbURlY29yYXRvcjxUIGV4dGVuZHMgUmVjb3JkPHN0cmluZywgYW55PiA9IGFueT4oXG4gIG1ldGFkYXRhOiBULFxuICBpbml0aWFsOiBQYXJ0aWFsPFQ+XG4pOiBNZXRob2REZWNvcmF0b3IgJiBDbGFzc0RlY29yYXRvciB7XG4gIHJldHVybiAoXG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnNhZmUtZnVuY3Rpb24tdHlwZVxuICAgIHRhcmdldDogb2JqZWN0IHwgRnVuY3Rpb24sXG4gICAga2V5Pzogc3RyaW5nIHwgc3ltYm9sLFxuICAgIGRlc2NyaXB0b3I/OiBUeXBlZFByb3BlcnR5RGVzY3JpcHRvcjxhbnk+XG4gICk6IGFueSA9PiB7XG4gICAgY29uc3QgcGFyYW1PcHRpb25zID0ge1xuICAgICAgLi4uaW5pdGlhbCxcbiAgICAgIC4uLnBpY2tCeShtZXRhZGF0YSwgbmVnYXRlKGlzVW5kZWZpbmVkKSksXG4gICAgfTtcblxuICAgIGlmIChkZXNjcmlwdG9yKSB7XG4gICAgICBjb25zdCBwYXJhbWV0ZXJzID1cbiAgICAgICAgUmVmbGVjdC5nZXRNZXRhZGF0YShERUNPUkFUT1JTLkFQSV9QQVJBTUVURVJTLCBkZXNjcmlwdG9yLnZhbHVlKSB8fCBbXTtcbiAgICAgIFJlZmxlY3QuZGVmaW5lTWV0YWRhdGEoXG4gICAgICAgIERFQ09SQVRPUlMuQVBJX1BBUkFNRVRFUlMsXG4gICAgICAgIFsuLi5wYXJhbWV0ZXJzLCBwYXJhbU9wdGlvbnNdLFxuICAgICAgICBkZXNjcmlwdG9yLnZhbHVlXG4gICAgICApO1xuICAgICAgcmV0dXJuIGRlc2NyaXB0b3I7XG4gICAgfVxuXG4gICAgaWYgKHR5cGVvZiB0YXJnZXQgPT09IFwib2JqZWN0XCIpIHtcbiAgICAgIHJldHVybiB0YXJnZXQ7XG4gICAgfVxuXG4gICAgY29uc3QgcHJvcGVydHlLZXlzID0gT2JqZWN0LmdldE93blByb3BlcnR5TmFtZXModGFyZ2V0LnByb3RvdHlwZSk7XG5cbiAgICBmb3IgKGNvbnN0IHByb3BlcnR5S2V5IG9mIHByb3BlcnR5S2V5cykge1xuICAgICAgaWYgKGlzQ29uc3RydWN0b3IocHJvcGVydHlLZXkpKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBtZXRob2REZXNjcmlwdG9yID0gT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcihcbiAgICAgICAgdGFyZ2V0LnByb3RvdHlwZSxcbiAgICAgICAgcHJvcGVydHlLZXlcbiAgICAgICk7XG5cbiAgICAgIGlmICghbWV0aG9kRGVzY3JpcHRvcikge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgaXNBcGlNZXRob2QgPSBSZWZsZWN0Lmhhc01ldGFkYXRhKFxuICAgICAgICBNRVRIT0RfTUVUQURBVEEsXG4gICAgICAgIG1ldGhvZERlc2NyaXB0b3IudmFsdWVcbiAgICAgICk7XG5cbiAgICAgIGlmICghaXNBcGlNZXRob2QpIHtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHBhcmFtZXRlcnMgPVxuICAgICAgICBSZWZsZWN0LmdldE1ldGFkYXRhKFxuICAgICAgICAgIERFQ09SQVRPUlMuQVBJX1BBUkFNRVRFUlMsXG4gICAgICAgICAgbWV0aG9kRGVzY3JpcHRvci52YWx1ZVxuICAgICAgICApIHx8IFtdO1xuICAgICAgUmVmbGVjdC5kZWZpbmVNZXRhZGF0YShcbiAgICAgICAgREVDT1JBVE9SUy5BUElfUEFSQU1FVEVSUyxcbiAgICAgICAgWy4uLnBhcmFtZXRlcnMsIHBhcmFtT3B0aW9uc10sXG4gICAgICAgIG1ldGhvZERlc2NyaXB0b3IudmFsdWVcbiAgICAgICk7XG4gICAgfVxuICB9O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0VHlwZUlzQXJyYXlUdXBsZShcbiAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnNhZmUtZnVuY3Rpb24tdHlwZVxuICBpbnB1dDogRnVuY3Rpb24gfCBbRnVuY3Rpb25dIHwgdW5kZWZpbmVkIHwgc3RyaW5nIHwgUmVjb3JkPHN0cmluZywgYW55PixcbiAgaXNBcnJheUZsYWc6IGJvb2xlYW5cbiAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnNhZmUtZnVuY3Rpb24tdHlwZVxuKTogW0Z1bmN0aW9uIHwgdW5kZWZpbmVkLCBib29sZWFuXSB7XG4gIGlmICghaW5wdXQpIHtcbiAgICByZXR1cm4gW2lucHV0IGFzIHVuZGVmaW5lZCwgaXNBcnJheUZsYWddO1xuICB9XG4gIGlmIChpc0FycmF5RmxhZykge1xuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW5zYWZlLWZ1bmN0aW9uLXR5cGVcbiAgICByZXR1cm4gW2lucHV0IGFzIEZ1bmN0aW9uLCBpc0FycmF5RmxhZ107XG4gIH1cbiAgY29uc3QgaXNJbnB1dEFycmF5ID0gaXNBcnJheShpbnB1dCk7XG4gIGNvbnN0IHR5cGUgPSBpc0lucHV0QXJyYXkgPyBpbnB1dFswXSA6IGlucHV0O1xuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVuc2FmZS1mdW5jdGlvbi10eXBlXG4gIHJldHVybiBbdHlwZSBhcyBGdW5jdGlvbiwgaXNJbnB1dEFycmF5XTtcbn1cbiIsImltcG9ydCB7IFR5cGUgfSBmcm9tIFwiQG5lc3Rqcy9jb21tb25cIjtcbmltcG9ydCB7IGlzU3RyaW5nLCBuZWdhdGUsIHBpY2tCeSB9IGZyb20gXCJsb2Rhc2hcIjtcbmltcG9ydCB7IERFQ09SQVRPUlMgfSBmcm9tIFwiLi9jb25zdGFudHNcIjtcbmltcG9ydCB7IGdldFR5cGVJc0FycmF5VHVwbGUsIE1FVEFEQVRBX0ZBQ1RPUllfTkFNRSB9IGZyb20gXCIuL2hlbHBlcnNcIjtcbmltcG9ydCB0eXBlIHtcbiAgRW51bUFsbG93ZWRUeXBlcyxcbiAgRW51bVNjaGVtYUF0dHJpYnV0ZXMsXG4gIFNjaGVtYU9iamVjdE1ldGFkYXRhLFxuICBTd2FnZ2VyRW51bVR5cGUsXG59IGZyb20gXCIuLi9zd2FnZ2VyLXR5cGVzXCI7XG5cbmV4cG9ydCBjb25zdCBpc1VuZGVmaW5lZCA9IChvYmo6IGFueSk6IG9iaiBpcyB1bmRlZmluZWQgPT5cbiAgdHlwZW9mIG9iaiA9PT0gXCJ1bmRlZmluZWRcIjtcblxuZXhwb3J0IGZ1bmN0aW9uIGdldEVudW1WYWx1ZXMoXG4gIGVudW1UeXBlOiBTd2FnZ2VyRW51bVR5cGUgfCAoKCkgPT4gU3dhZ2dlckVudW1UeXBlKVxuKTogc3RyaW5nW10gfCBudW1iZXJbXSB7XG4gIGlmICh0eXBlb2YgZW51bVR5cGUgPT09IFwiZnVuY3Rpb25cIikge1xuICAgIHJldHVybiBnZXRFbnVtVmFsdWVzKGVudW1UeXBlKCkpO1xuICB9XG5cbiAgaWYgKEFycmF5LmlzQXJyYXkoZW51bVR5cGUpKSB7XG4gICAgcmV0dXJuIGVudW1UeXBlIGFzIHN0cmluZ1tdO1xuICB9XG4gIGlmICh0eXBlb2YgZW51bVR5cGUgIT09IFwib2JqZWN0XCIpIHtcbiAgICByZXR1cm4gW107XG4gIH1cbiAgLy8gRW51bXMgd2l0aCBudW1lcmljIHZhbHVlc1xuICAvLyAgIGVudW0gU2l6ZSB7XG4gIC8vICAgICBTTUFMTCA9IDEsXG4gIC8vICAgICBCSUcgPSAyXG4gIC8vICAgfVxuICAvLyBhcmUgdHJhbnNwaWxlZCB0byBpbmNsdWRlIGEgcmV2ZXJzZSBtYXBwaW5nXG4gIC8vICAgY29uc3QgU2l6ZSA9IHtcbiAgLy8gICAgIFwiMVwiOiBcIlNNQUxMXCIsXG4gIC8vICAgICBcIjJcIjogXCJCSUdcIixcbiAgLy8gICAgIFwiU01BTExcIjogMSxcbiAgLy8gICAgIFwiQklHXCI6IDIsXG4gIC8vICAgfVxuICBjb25zdCBudW1lcmljVmFsdWVzID0gT2JqZWN0LnZhbHVlcyhlbnVtVHlwZSlcbiAgICAuZmlsdGVyKCh2YWx1ZSkgPT4gdHlwZW9mIHZhbHVlID09PSBcIm51bWJlclwiKVxuICAgIC5tYXAoKHZhbHVlOiBhbnkpID0+IHZhbHVlLnRvU3RyaW5nKCkpO1xuXG4gIHJldHVybiBPYmplY3Qua2V5cyhlbnVtVHlwZSlcbiAgICAuZmlsdGVyKChrZXkpID0+ICFudW1lcmljVmFsdWVzLmluY2x1ZGVzKGtleSkpXG4gICAgLm1hcCgoa2V5KSA9PiBlbnVtVHlwZVtrZXkgYXMgYW55XSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRFbnVtVHlwZSh2YWx1ZXM6IChzdHJpbmcgfCBudW1iZXIpW10pOiBcInN0cmluZ1wiIHwgXCJudW1iZXJcIiB7XG4gIGNvbnN0IGhhc1N0cmluZyA9IHZhbHVlcy5maWx0ZXIoaXNTdHJpbmcpLmxlbmd0aCA+IDA7XG4gIHJldHVybiBoYXNTdHJpbmcgPyBcInN0cmluZ1wiIDogXCJudW1iZXJcIjtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZVByb3BlcnR5RGVjb3JhdG9yPFQgZXh0ZW5kcyBSZWNvcmQ8c3RyaW5nLCBhbnk+ID0gYW55PihcbiAgbWV0YWtleTogc3RyaW5nLFxuICBtZXRhZGF0YTogVCxcbiAgb3ZlcnJpZGVFeGlzdGluZyA9IHRydWVcbik6IFByb3BlcnR5RGVjb3JhdG9yIHtcbiAgcmV0dXJuICgodGFyZ2V0OiBvYmplY3QsIHByb3BlcnR5S2V5OiBzdHJpbmcpID0+IHtcbiAgICBjb25zdCBwcm9wZXJ0aWVzID1cbiAgICAgIFJlZmxlY3QuZ2V0TWV0YWRhdGEoREVDT1JBVE9SUy5BUElfTU9ERUxfUFJPUEVSVElFU19BUlJBWSwgdGFyZ2V0KSB8fCBbXTtcblxuICAgIGNvbnN0IGtleSA9IGA6JHtwcm9wZXJ0eUtleX1gO1xuICAgIGlmICghcHJvcGVydGllcy5pbmNsdWRlcyhrZXkpKSB7XG4gICAgICBSZWZsZWN0LmRlZmluZU1ldGFkYXRhKFxuICAgICAgICBERUNPUkFUT1JTLkFQSV9NT0RFTF9QUk9QRVJUSUVTX0FSUkFZLFxuICAgICAgICBbLi4ucHJvcGVydGllcywgYDoke3Byb3BlcnR5S2V5fWBdLFxuICAgICAgICB0YXJnZXRcbiAgICAgICk7XG4gICAgfVxuICAgIGNvbnN0IGV4aXN0aW5nTWV0YWRhdGEgPSBSZWZsZWN0LmdldE1ldGFkYXRhKG1ldGFrZXksIHRhcmdldCwgcHJvcGVydHlLZXkpO1xuICAgIGlmIChleGlzdGluZ01ldGFkYXRhKSB7XG4gICAgICBjb25zdCBuZXdNZXRhZGF0YSA9IHBpY2tCeShtZXRhZGF0YSwgbmVnYXRlKGlzVW5kZWZpbmVkKSk7XG4gICAgICBjb25zdCBtZXRhZGF0YVRvU2F2ZSA9IG92ZXJyaWRlRXhpc3RpbmdcbiAgICAgICAgPyB7XG4gICAgICAgICAgICAuLi5leGlzdGluZ01ldGFkYXRhLFxuICAgICAgICAgICAgLi4ubmV3TWV0YWRhdGEsXG4gICAgICAgICAgfVxuICAgICAgICA6IHtcbiAgICAgICAgICAgIC4uLm5ld01ldGFkYXRhLFxuICAgICAgICAgICAgLi4uZXhpc3RpbmdNZXRhZGF0YSxcbiAgICAgICAgICB9O1xuXG4gICAgICBSZWZsZWN0LmRlZmluZU1ldGFkYXRhKG1ldGFrZXksIG1ldGFkYXRhVG9TYXZlLCB0YXJnZXQsIHByb3BlcnR5S2V5KTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3QgdHlwZSA9XG4gICAgICAgIC8vIEB0cy1leHBlY3QtZXJyb3IgbmVzdCBqcyBjb2RlXG4gICAgICAgIHRhcmdldD8uY29uc3RydWN0b3I/LltNRVRBREFUQV9GQUNUT1JZX05BTUVdPy4oKVtwcm9wZXJ0eUtleV0/LnR5cGUgPz9cbiAgICAgICAgUmVmbGVjdC5nZXRNZXRhZGF0YShcImRlc2lnbjp0eXBlXCIsIHRhcmdldCwgcHJvcGVydHlLZXkpO1xuXG4gICAgICBSZWZsZWN0LmRlZmluZU1ldGFkYXRhKFxuICAgICAgICBtZXRha2V5LFxuICAgICAgICB7XG4gICAgICAgICAgdHlwZSxcbiAgICAgICAgICByZXF1aXJlZDogZmFsc2UsIC8vIERlZmF1bHQgdG8gb3B0aW9uYWwgdW5sZXNzIEByZXF1aXJlZCgpIGlzIHVzZWRcbiAgICAgICAgICAuLi5waWNrQnkobWV0YWRhdGEsIG5lZ2F0ZShpc1VuZGVmaW5lZCkpLFxuICAgICAgICB9LFxuICAgICAgICB0YXJnZXQsXG4gICAgICAgIHByb3BlcnR5S2V5XG4gICAgICApO1xuICAgIH1cbiAgfSkgYXMgUHJvcGVydHlEZWNvcmF0b3I7XG59XG5cbmV4cG9ydCB0eXBlIEFwaVByb3BlcnR5Q29tbW9uT3B0aW9ucyA9IFNjaGVtYU9iamVjdE1ldGFkYXRhICYge1xuICBcIngtZW51bU5hbWVzXCI/OiBzdHJpbmdbXTtcbiAgLyoqXG4gICAqIExhenkgZnVuY3Rpb24gcmV0dXJuaW5nIHRoZSB0eXBlIGZvciB3aGljaCB0aGUgZGVjb3JhdGVkIHByb3BlcnR5XG4gICAqIGNhbiBiZSB1c2VkIGFzIGFuIGlkXG4gICAqXG4gICAqIFVzZSB0b2dldGhlciB3aXRoIEBBcGlEZWZhdWx0R2V0dGVyIG9uIHRoZSBnZXR0ZXIgcm91dGUgb2YgdGhlIHR5cGVcbiAgICogdG8gZ2VuZXJhdGUgT3BlbkFQSSBsaW5rIG9iamVjdHNcbiAgICpcbiAgICogQHNlZSBbU3dhZ2dlciBsaW5rIG9iamVjdHNdKGh0dHBzOi8vc3dhZ2dlci5pby9kb2NzL3NwZWNpZmljYXRpb24vbGlua3MvKVxuICAgKi9cbiAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnNhZmUtZnVuY3Rpb24tdHlwZVxuICBsaW5rPzogKCkgPT4gVHlwZTx1bmtub3duPiB8IEZ1bmN0aW9uO1xufTtcblxuZXhwb3J0IHR5cGUgQXBpUHJvcGVydHlPcHRpb25zID1cbiAgfCBBcGlQcm9wZXJ0eUNvbW1vbk9wdGlvbnNcbiAgfCAoQXBpUHJvcGVydHlDb21tb25PcHRpb25zICYge1xuICAgICAgZW51bU5hbWU6IHN0cmluZztcbiAgICAgIGVudW1TY2hlbWE/OiBFbnVtU2NoZW1hQXR0cmlidXRlcztcbiAgICB9KTtcblxuY29uc3QgaXNFbnVtQXJyYXkgPSAoXG4gIG9wdHM6IEFwaVByb3BlcnR5T3B0aW9uc1xuKTogb3B0cyBpcyB7XG4gIGlzQXJyYXk6IHRydWU7XG4gIGVudW06IEVudW1BbGxvd2VkVHlwZXM7XG4gIHR5cGU6IGFueTtcbiAgaXRlbXM6IGFueTtcbn0gPT4gKG9wdHMuaXNBcnJheSAmJiBcImVudW1cIiBpbiBvcHRzICYmIG9wdHMuZW51bSAhPT0gdW5kZWZpbmVkKSBhcyBib29sZWFuO1xuXG4vKipcbiAqIEBwdWJsaWNBcGlcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIEFwaVByb3BlcnR5KFxuICBvcHRpb25zOiBBcGlQcm9wZXJ0eU9wdGlvbnMgPSB7fVxuKTogUHJvcGVydHlEZWNvcmF0b3Ige1xuICByZXR1cm4gY3JlYXRlQXBpUHJvcGVydHlEZWNvcmF0b3Iob3B0aW9ucyk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVBcGlQcm9wZXJ0eURlY29yYXRvcihcbiAgb3B0aW9uczogQXBpUHJvcGVydHlPcHRpb25zID0ge30sXG4gIG92ZXJyaWRlRXhpc3RpbmcgPSB0cnVlXG4pOiBQcm9wZXJ0eURlY29yYXRvciB7XG4gIGNvbnN0IFt0eXBlLCBpc0FycmF5XSA9IGdldFR5cGVJc0FycmF5VHVwbGUoXG4gICAgb3B0aW9ucy50eXBlLFxuICAgIG9wdGlvbnMuaXNBcnJheSBhcyBhbnlcbiAgKTtcbiAgb3B0aW9ucyA9IHtcbiAgICAuLi5vcHRpb25zLFxuICAgIHR5cGUsXG4gICAgaXNBcnJheSxcbiAgfSBhcyBBcGlQcm9wZXJ0eU9wdGlvbnM7XG5cbiAgaWYgKGlzRW51bUFycmF5KG9wdGlvbnMpKSB7XG4gICAgb3B0aW9ucy50eXBlID0gXCJhcnJheVwiO1xuXG4gICAgY29uc3QgZW51bVZhbHVlcyA9IGdldEVudW1WYWx1ZXMob3B0aW9ucy5lbnVtKTtcbiAgICBvcHRpb25zLml0ZW1zID0ge1xuICAgICAgdHlwZTogZ2V0RW51bVR5cGUoZW51bVZhbHVlcyksXG4gICAgICBlbnVtOiBlbnVtVmFsdWVzLFxuICAgIH07XG4gICAgLy8gQHRzLWV4cGVjdC1lcnJvciBuZXN0IGpzIGNvZGVcbiAgICBkZWxldGUgb3B0aW9ucy5lbnVtO1xuICB9IGVsc2UgaWYgKFwiZW51bVwiIGluIG9wdGlvbnMgJiYgb3B0aW9ucy5lbnVtICE9PSB1bmRlZmluZWQpIHtcbiAgICBjb25zdCBlbnVtVmFsdWVzID0gZ2V0RW51bVZhbHVlcyhvcHRpb25zLmVudW0pO1xuXG4gICAgb3B0aW9ucy5lbnVtID0gZW51bVZhbHVlcztcbiAgICBvcHRpb25zLnR5cGUgPSBnZXRFbnVtVHlwZShlbnVtVmFsdWVzKTtcbiAgfVxuXG4gIGlmIChBcnJheS5pc0FycmF5KG9wdGlvbnMudHlwZSkpIHtcbiAgICBvcHRpb25zLnR5cGUgPSBcImFycmF5XCI7XG4gICAgb3B0aW9ucy5pdGVtcyA9IHtcbiAgICAgIHR5cGU6IFwiYXJyYXlcIixcbiAgICAgIGl0ZW1zOiB7XG4gICAgICAgIHR5cGU6IG9wdGlvbnMudHlwZVswXSxcbiAgICAgIH0sXG4gICAgfTtcbiAgfVxuXG4gIHJldHVybiBjcmVhdGVQcm9wZXJ0eURlY29yYXRvcihcbiAgICBERUNPUkFUT1JTLkFQSV9NT0RFTF9QUk9QRVJUSUVTLFxuICAgIG9wdGlvbnMsXG4gICAgb3ZlcnJpZGVFeGlzdGluZ1xuICApO1xufVxuIiwiaW1wb3J0IHsgYXBwbHkgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRpb25cIjtcbmltcG9ydCB7IEFwaUV4Y2x1ZGVFbmRwb2ludCB9IGZyb20gXCJAbmVzdGpzL3N3YWdnZXJcIjtcbmltcG9ydCB7XG4gIEJ1bGtDcnVkT3BlcmF0aW9uS2V5cyxcbiAgT3BlcmF0aW9uS2V5cyxcbiAgQ3J1ZE9wZXJhdGlvbnMsXG59IGZyb20gXCJAZGVjYWYtdHMvZGItZGVjb3JhdG9yc1wiO1xuaW1wb3J0IHsgTW9kZWxDb25zdHJ1Y3RvciB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdG9yLXZhbGlkYXRpb25cIjtcbmltcG9ydCB7IERlbGV0ZSwgR2V0LCBQYXRjaCwgUG9zdCwgUHV0IH0gZnJvbSBcIkBuZXN0anMvY29tbW9uXCI7XG5cbmltcG9ydCB7IGlzT3BlcmF0aW9uQmxvY2tlZCBhcyBjb3JlSXNPcGVyYXRpb25CbG9ja2VkIH0gZnJvbSBcIkBkZWNhZi10cy9jb3JlXCI7XG5pbXBvcnQgeyBQcmVwYXJlZFN0YXRlbWVudEtleXMgfSBmcm9tIFwiQGRlY2FmLXRzL2NvcmVcIjtcbmltcG9ydCB7IEh0dHBWZXJicyB9IGZyb20gXCIuL3R5cGVzXCI7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIERldGVybWluZXMgaWYgYSBnaXZlbiBDUlVEIG9wZXJhdGlvbiBpcyBibG9ja2VkIGZvciBhIHNwZWNpZmljIG1vZGVsIGNvbnN0cnVjdG9yLlxuICogQHN1bW1hcnkgUmV0cmlldmVzIHRoZSBvcGVyYXRpb24tYmxvY2tpbmcgaGFuZGxlciBtZXRhZGF0YSBzdG9yZWQgb24gdGhlIHByb3ZpZGVkIG1vZGVsIGNvbnN0cnVjdG9yICh1bmRlciBgT3BlcmF0aW9uS2V5cy5SRUZMRUNUICsgT3BlcmF0aW9uS2V5cy5CTE9DS2ApLCBleGVjdXRlcyBpdCAoaWYgcHJlc2VudCkgd2l0aCBpdHMgcGVyc2lzdGVkIGFyZ3VtZW50cyBwbHVzIHRoZSByZXF1ZXN0ZWQgb3BlcmF0aW9uLCBhbmQgcmV0dXJucyB3aGV0aGVyIHRoZSBvcGVyYXRpb24gaXMgYmxvY2tlZC4gSWYgbm8gaGFuZGxlciBleGlzdHMsIHRoZSBvcGVyYXRpb24gaXMgY29uc2lkZXJlZCBhbGxvd2VkIChyZXR1cm5zIGBmYWxzZWApLlxuICogQHBhcmFtIHtNb2RlbENvbnN0cnVjdG9yPGFueT59IE1vZGVsQ29uc3RydWN0b3IgLSBUaGUgdGFyZ2V0IG1vZGVsIGNvbnN0cnVjdG9yIHdob3NlIG1ldGFkYXRhIG1heSBpbmNsdWRlIGEgYmxvY2tpbmcgaGFuZGxlci5cbiAqIEBwYXJhbSB7Q3J1ZE9wZXJhdGlvbnN9IG9wIC0gVGhlIENSVUQgb3BlcmF0aW9uIHRvIGV2YWx1YXRlIChlLmcuLCBgT3BlcmF0aW9uS2V5cy5DUkVBVEVgLCBgT3BlcmF0aW9uS2V5cy5SRUFEYCwgYE9wZXJhdGlvbktleXMuVVBEQVRFYCwgYE9wZXJhdGlvbktleXMuREVMRVRFYCkuXG4gKiBAcmV0dXJuIHtib29sZWFufSBgdHJ1ZWAgd2hlbiB0aGUgb3BlcmF0aW9uIGlzIGV4cGxpY2l0bHkgYmxvY2tlZCBieSB0aGUgbW9kZWwncyBoYW5kbGVyOyBvdGhlcndpc2UgYGZhbHNlYC5cbiAqIEBmdW5jdGlvbiBpc09wZXJhdGlvbkJsb2NrZWRcbiAqL1xuLyoqXG4gKiBAZGVzY3JpcHRpb24gQ29uZGl0aW9uYWxseSBhcHBsaWVzIGFuIEhUVFAgbWV0aG9kIGRlY29yYXRvciBmb3IgYSBnaXZlbiBtb2RlbCBhbmQgdmVyYiwgaGlkaW5nIHRoZSBlbmRwb2ludCBpbiBTd2FnZ2VyIChhbmQgbm90IHJlZ2lzdGVyaW5nIHRoZSByb3V0ZSkgd2hlbiB0aGUgbW9kZWwgYmxvY2tzIHRoYXQgQ1JVRCBvcGVyYXRpb24uXG4gKiBAc3VtbWFyeSBNYXBzIGFuIEhUVFAgdmVyYiB0byBpdHMgY29ycmVzcG9uZGluZyBgQ3J1ZE9wZXJhdGlvbnNgIGtleSBhbmQgTmVzdCBIVFRQIGRlY29yYXRvciAoYEBHZXRgLCBgQFBvc3RgLCBldGMuKS4gSXQgY2hlY2tzIGBpc09wZXJhdGlvbkJsb2NrZWQoTW9kZWxDb25zdHJ1Y3RvciwgY3J1ZE9wKWAgYW5kLCBpZiBibG9ja2VkLCBhcHBsaWVzIG9ubHkgYEBBcGlFeGNsdWRlRW5kcG9pbnQoKWAgKFN3YWdnZXItaGlkZGVuLCBubyBOZXN0IHJvdXRlKS4gSWYgcGVybWl0dGVkLCBpdCBhcHBsaWVzIHRoZSBhcHByb3ByaWF0ZSBIVFRQIGRlY29yYXRvciB3aXRoIHRoZSBvcHRpb25hbCBgcGF0aGAuXG4gKiBAcGFyYW0ge01vZGVsQ29uc3RydWN0b3I8YW55Pn0gTW9kZWxDb25zdHJ1Y3RvciAtIFRoZSBtb2RlbCBjb25zdHJ1Y3RvciB1c2VkIHRvIHJlc29sdmUgb3BlcmF0aW9uLWJsb2NraW5nIHJ1bGVzLlxuICogQHBhcmFtIHtIdHRwVmVyYnN9IHZlcmIgLSBUaGUgSFRUUCB2ZXJiIHRvIG1hcCAoZS5nLiwgYFwiR0VUXCIgfCBcIlBPU1RcIiB8IFwiUFVUXCIgfCBcIlBBVENIXCIgfCBcIkRFTEVURVwiYCkuXG4gKiBAcGFyYW0ge3N0cmluZ30gW3BhdGhdIC0gT3B0aW9uYWwgcm91dGUgcGF0aCBwYXNzZWQgdGhyb3VnaCB0byB0aGUgY29ycmVzcG9uZGluZyBOZXN0IEhUVFAgbWV0aG9kIGRlY29yYXRvci5cbiAqIEByZXR1cm4ge01ldGhvZERlY29yYXRvcn0gQSBtZXRob2QgZGVjb3JhdG9yIHRoYXQgZWl0aGVyIGV4Y2x1ZGVzIHRoZSBlbmRwb2ludCBmcm9tIFN3YWdnZXIgKGFuZCByb3V0ZSByZWdpc3RyYXRpb24pIG9yIGFwcGxpZXMgdGhlIGNvcnJlY3QgSFRUUCBkZWNvcmF0b3IuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBBcGlPcGVyYXRpb25Gcm9tTW9kZWwoXG4gIE1vZGVsQ29uc3RydWN0b3I6IE1vZGVsQ29uc3RydWN0b3I8YW55PixcbiAgdmVyYjogSHR0cFZlcmJzLFxuICBwYXRoPzogc3RyaW5nXG4pOiBNZXRob2REZWNvcmF0b3Ige1xuICBjb25zdCBodHRwVG9DcnVkOiBSZWNvcmQ8XG4gICAgSHR0cFZlcmJzLFxuICAgIFtDcnVkT3BlcmF0aW9ucywgKHBhdGg/OiBzdHJpbmcpID0+IE1ldGhvZERlY29yYXRvcl1cbiAgPiA9IHtcbiAgICBHRVQ6IFtPcGVyYXRpb25LZXlzLlJFQUQsIEdldF0sXG4gICAgUE9TVDogW09wZXJhdGlvbktleXMuQ1JFQVRFLCBQb3N0XSxcbiAgICBQVVQ6IFtPcGVyYXRpb25LZXlzLlVQREFURSwgUHV0XSxcbiAgICBQQVRDSDogW09wZXJhdGlvbktleXMuVVBEQVRFLCBQYXRjaF0sXG4gICAgREVMRVRFOiBbT3BlcmF0aW9uS2V5cy5ERUxFVEUsIERlbGV0ZV0sXG4gIH07XG5cbiAgY29uc3QgW2NydWRPcCwgSHR0cE1ldGhvZERlY29yYXRvcl0gPSBodHRwVG9DcnVkW3ZlcmJdO1xuICBjb25zdCB0YXJnZXQgPSByZXNvbHZlQmxvY2tUYXJnZXQodmVyYiwgcGF0aCk7XG4gIHJldHVybiB0YXJnZXRcbiAgICA/IGNvcmVJc09wZXJhdGlvbkJsb2NrZWQoTW9kZWxDb25zdHJ1Y3RvciwgdGFyZ2V0LmtpbmQgYXMgYW55LCB0YXJnZXQudmFsdWUpXG4gICAgICA/IGFwcGx5KEFwaUV4Y2x1ZGVFbmRwb2ludCgpKVxuICAgICAgOiBhcHBseShIdHRwTWV0aG9kRGVjb3JhdG9yKHBhdGgpKVxuICAgIDogY29yZUlzT3BlcmF0aW9uQmxvY2tlZChNb2RlbENvbnN0cnVjdG9yLCBjcnVkT3ApXG4gICAgICA/IGFwcGx5KEFwaUV4Y2x1ZGVFbmRwb2ludCgpKVxuICAgICAgOiBhcHBseShIdHRwTWV0aG9kRGVjb3JhdG9yKHBhdGgpKTtcbn1cbi8qKlxuICogQGRlc2NyaXB0aW9uIENvbmRpdGlvbmFsbHkgYXBwbGllcyBhbiBIVFRQIG1ldGhvZCBkZWNvcmF0b3IgZm9yIGEgZ2l2ZW4gbW9kZWwgYW5kIHZlcmIsIGhpZGluZyB0aGUgZW5kcG9pbnQgaW4gU3dhZ2dlciAoYW5kIG5vdCByZWdpc3RlcmluZyB0aGUgcm91dGUpIHdoZW4gdGhlIG1vZGVsIGJsb2NrcyB0aGF0IENSVUQgb3BlcmF0aW9uLlxuICogQHN1bW1hcnkgTWFwcyBhbiBIVFRQIHZlcmIgdG8gaXRzIGNvcnJlc3BvbmRpbmcgYENydWRPcGVyYXRpb25zYCBrZXkgYW5kIE5lc3QgSFRUUCBkZWNvcmF0b3IgKGBAR2V0YCwgYEBQb3N0YCwgZXRjLikuIEl0IGNoZWNrcyBgaXNPcGVyYXRpb25CbG9ja2VkKE1vZGVsQ29uc3RydWN0b3IsIGNydWRPcClgIGFuZCwgaWYgYmxvY2tlZCwgYXBwbGllcyBvbmx5IGBAQXBpRXhjbHVkZUVuZHBvaW50KClgIChTd2FnZ2VyLWhpZGRlbiwgbm8gTmVzdCByb3V0ZSkuIElmIHBlcm1pdHRlZCwgaXQgYXBwbGllcyB0aGUgYXBwcm9wcmlhdGUgSFRUUCBkZWNvcmF0b3Igd2l0aCB0aGUgb3B0aW9uYWwgYHBhdGhgLlxuICogQHBhcmFtIHtNb2RlbENvbnN0cnVjdG9yPGFueT59IE1vZGVsQ29uc3RydWN0b3IgLSBUaGUgbW9kZWwgY29uc3RydWN0b3IgdXNlZCB0byByZXNvbHZlIG9wZXJhdGlvbi1ibG9ja2luZyBydWxlcy5cbiAqIEBwYXJhbSB7SHR0cFZlcmJzfSB2ZXJiIC0gVGhlIEhUVFAgdmVyYiB0byBtYXAgKGUuZy4sIGBcIkdFVFwiIHwgXCJQT1NUXCIgfCBcIlBVVFwiIHwgXCJQQVRDSFwiIHwgXCJERUxFVEVcImApLlxuICogQHBhcmFtIHtzdHJpbmd9IFtwYXRoXSAtIE9wdGlvbmFsIHJvdXRlIHBhdGggcGFzc2VkIHRocm91Z2ggdG8gdGhlIGNvcnJlc3BvbmRpbmcgTmVzdCBIVFRQIG1ldGhvZCBkZWNvcmF0b3IuXG4gKiBAcmV0dXJuIHtNZXRob2REZWNvcmF0b3J9IEEgbWV0aG9kIGRlY29yYXRvciB0aGF0IGVpdGhlciBleGNsdWRlcyB0aGUgZW5kcG9pbnQgZnJvbSBTd2FnZ2VyIChhbmQgcm91dGUgcmVnaXN0cmF0aW9uKSBvciBhcHBsaWVzIHRoZSBjb3JyZWN0IEhUVFAgZGVjb3JhdG9yLlxuICovXG5leHBvcnQgZnVuY3Rpb24gQnVsa0FwaU9wZXJhdGlvbkZyb21Nb2RlbChcbiAgTW9kZWxDb25zdHJ1Y3RvcjogTW9kZWxDb25zdHJ1Y3Rvcjxhbnk+LFxuICB2ZXJiOiBIdHRwVmVyYnMsXG4gIHBhdGg/OiBzdHJpbmdcbik6IE1ldGhvZERlY29yYXRvciB7XG4gIGNvbnN0IGh0dHBUb0NydWQ6IFJlY29yZDxcbiAgICBIdHRwVmVyYnMsXG4gICAgW0J1bGtDcnVkT3BlcmF0aW9uS2V5cywgKHBhdGg/OiBzdHJpbmcpID0+IE1ldGhvZERlY29yYXRvcl1cbiAgPiA9IHtcbiAgICBHRVQ6IFtCdWxrQ3J1ZE9wZXJhdGlvbktleXMuUkVBRF9BTEwsIEdldF0sXG4gICAgUE9TVDogW0J1bGtDcnVkT3BlcmF0aW9uS2V5cy5DUkVBVEVfQUxMLCBQb3N0XSxcbiAgICBQVVQ6IFtCdWxrQ3J1ZE9wZXJhdGlvbktleXMuVVBEQVRFX0FMTCwgUHV0XSxcbiAgICBQQVRDSDogW0J1bGtDcnVkT3BlcmF0aW9uS2V5cy5VUERBVEVfQUxMLCBQYXRjaF0sXG4gICAgREVMRVRFOiBbQnVsa0NydWRPcGVyYXRpb25LZXlzLkRFTEVURV9BTEwsIERlbGV0ZV0sXG4gIH07XG5cbiAgY29uc3QgW2NydWRPcCwgSHR0cE1ldGhvZERlY29yYXRvcl0gPSBodHRwVG9DcnVkW3ZlcmJdO1xuICBjb25zdCB0YXJnZXQgPSBwYXRoID8gcmVzb2x2ZUJsb2NrVGFyZ2V0KHZlcmIsIHBhdGgpIDogdW5kZWZpbmVkO1xuICByZXR1cm4gdGFyZ2V0XG4gICAgPyBjb3JlSXNPcGVyYXRpb25CbG9ja2VkKE1vZGVsQ29uc3RydWN0b3IsIHRhcmdldC5raW5kIGFzIGFueSwgdGFyZ2V0LnZhbHVlKVxuICAgICAgPyBhcHBseShBcGlFeGNsdWRlRW5kcG9pbnQoKSlcbiAgICAgIDogYXBwbHkoSHR0cE1ldGhvZERlY29yYXRvcihwYXRoKSlcbiAgICA6IGNvcmVJc09wZXJhdGlvbkJsb2NrZWQoTW9kZWxDb25zdHJ1Y3RvciwgXCJidWxrXCIgYXMgYW55LCBjcnVkT3AgYXMgYW55KVxuICAgICAgPyBhcHBseShBcGlFeGNsdWRlRW5kcG9pbnQoKSlcbiAgICAgIDogYXBwbHkoSHR0cE1ldGhvZERlY29yYXRvcihwYXRoKSk7XG59XG5mdW5jdGlvbiByZXNvbHZlQmxvY2tUYXJnZXQoXG4gIHZlcmI6IEh0dHBWZXJicyxcbiAgcGF0aD86IHN0cmluZ1xuKTpcbiAgfCB7IGtpbmQ6IFwiY3J1ZFwiIHwgXCJzdGF0ZW1lbnRcIiB8IFwicXVlcnlcIiB8IFwiYnVsa1wiOyB2YWx1ZTogc3RyaW5nIH1cbiAgfCB1bmRlZmluZWQge1xuICBpZiAoIXBhdGgpIHJldHVybiB1bmRlZmluZWQ7XG5cbiAgY29uc3Qgbm9ybWFsaXplZCA9IHBhdGgucmVwbGFjZSgvXlxcLyt8XFwvKyQvZywgXCJcIik7XG4gIGNvbnN0IHN0YXRlbWVudFRhcmdldHM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7XG4gICAgXCJsaXN0QnkvOmtleVwiOiBQcmVwYXJlZFN0YXRlbWVudEtleXMuTElTVF9CWSxcbiAgICBcInBhZ2luYXRlQnkvOmtleS86cGFnZVwiOiBQcmVwYXJlZFN0YXRlbWVudEtleXMuUEFHRV9CWSxcbiAgICBcImZpbmQvOnZhbHVlXCI6IFByZXBhcmVkU3RhdGVtZW50S2V5cy5GSU5ELFxuICAgIFwicGFnZS86dmFsdWVcIjogUHJlcGFyZWRTdGF0ZW1lbnRLZXlzLlBBR0UsXG4gICAgXCJmaW5kT25lQnkvOmtleS86dmFsdWVcIjogUHJlcGFyZWRTdGF0ZW1lbnRLZXlzLkZJTkRfT05FX0JZLFxuICAgIFwiZmluZEJ5LzprZXkvOnZhbHVlXCI6IFByZXBhcmVkU3RhdGVtZW50S2V5cy5GSU5EX0JZLFxuICAgIFwic3RhdGVtZW50LzptZXRob2QvKmFyZ3NcIjogXCJzdGF0ZW1lbnRcIixcbiAgICBcImNvdW50T2YvOmZpZWxkXCI6IFByZXBhcmVkU3RhdGVtZW50S2V5cy5DT1VOVF9PRixcbiAgICBcIm1heE9mLzpmaWVsZFwiOiBQcmVwYXJlZFN0YXRlbWVudEtleXMuTUFYX09GLFxuICAgIFwibWluT2YvOmZpZWxkXCI6IFByZXBhcmVkU3RhdGVtZW50S2V5cy5NSU5fT0YsXG4gICAgXCJhdmdPZi86ZmllbGRcIjogUHJlcGFyZWRTdGF0ZW1lbnRLZXlzLkFWR19PRixcbiAgICBcInN1bU9mLzpmaWVsZFwiOiBQcmVwYXJlZFN0YXRlbWVudEtleXMuU1VNX09GLFxuICAgIFwiZGlzdGluY3RPZi86ZmllbGRcIjogUHJlcGFyZWRTdGF0ZW1lbnRLZXlzLkRJU1RJTkNUX09GLFxuICAgIFwiZ3JvdXBPZi86ZmllbGRcIjogUHJlcGFyZWRTdGF0ZW1lbnRLZXlzLkdST1VQX09GLFxuICB9O1xuXG4gIGlmIChub3JtYWxpemVkLnN0YXJ0c1dpdGgoXCJxdWVyeS9cIikpIHtcbiAgICByZXR1cm4geyBraW5kOiBcInF1ZXJ5XCIsIHZhbHVlOiBub3JtYWxpemVkLnJlcGxhY2UoL15xdWVyeVxcLy8sIFwiXCIpIH07XG4gIH1cblxuICBjb25zdCBzdGF0ZW1lbnRWYWx1ZSA9IHN0YXRlbWVudFRhcmdldHNbbm9ybWFsaXplZF07XG4gIGlmIChzdGF0ZW1lbnRWYWx1ZSkge1xuICAgIHJldHVybiB7IGtpbmQ6IFwic3RhdGVtZW50XCIsIHZhbHVlOiBzdGF0ZW1lbnRWYWx1ZSB9O1xuICB9XG5cbiAgaWYgKHZlcmIgPT09IFwiR0VUXCIgJiYgbm9ybWFsaXplZCA9PT0gXCJcIikge1xuICAgIHJldHVybiB7IGtpbmQ6IFwiY3J1ZFwiLCB2YWx1ZTogT3BlcmF0aW9uS2V5cy5SRUFEIH07XG4gIH1cblxuICByZXR1cm4gdW5kZWZpbmVkO1xufVxuIiwiaW1wb3J0IHsgYXBwbHlEZWNvcmF0b3JzIH0gZnJvbSBcIkBuZXN0anMvY29tbW9uXCI7XG5pbXBvcnQgeyBBcGlQYXJhbSBhcyBBcGlQYXJhbURlYyB9IGZyb20gXCJAbmVzdGpzL3N3YWdnZXJcIjtcbmltcG9ydCB0eXBlIHsgRGVjYWZBcGlQcm9wZXJ0eSB9IGZyb20gXCIuL3R5cGVzXCI7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIEFwcGxpZXMgYSBzZXQgb2YgU3dhZ2dlciBgQEFwaVBhcmFtYCBkZWNvcmF0b3JzIGdlbmVyYXRlZCBmcm9tIGEgdHlwZWQgc3BlY2lmaWNhdGlvbiBhcnJheS5cbiAqIEBzdW1tYXJ5IFRyYW5zZm9ybXMgZWFjaCBlbnRyeSBvZiB0aGUgcHJvdmlkZWQgYEFwaVBhcmFtW11gIGludG8gYSBjb3JyZXNwb25kaW5nIGBAQXBpUGFyYW0oKWAgZGVjb3JhdG9yIChkZWZhdWx0aW5nIGBkZXNjcmlwdGlvbmAsIGByZXF1aXJlZGAsIGFuZCBgdHlwZWAgd2hlbiBvbWl0dGVkKSBhbmQgY29tcG9zZXMgdGhlbSBpbnRvIGEgc2luZ2xlIGRlY29yYXRvciB2aWEgTmVzdCdzIGBhcHBseURlY29yYXRvcnNgLiBVc2VmdWwgZm9yIHN5bmNocm9uaXppbmcgcnVudGltZSByb3V0ZSBwYXJhbXMgd2l0aCBPcGVuQVBJIGRvY3VtZW50YXRpb24gaW4gYSBjb25jaXNlLCBkZWNsYXJhdGl2ZSB3YXkuXG4gKiBAcGFyYW0ge0FwaVBhcmFtW119IFtwcm9wcz1bXV0gQXJyYXkgZGVzY3JpYmluZyBwYXRoIHBhcmFtZXRlcnMgdG8gYmUgZG9jdW1lbnRlZC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBwcm9wc1tdLm5hbWUgVGhlIHBhcmFtZXRlcidzIG5hbWUgYXMgaXQgYXBwZWFycyBpbiB0aGUgcm91dGUgdGVtcGxhdGUgKGUuZy4sIGA6aWRgKS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBbcHJvcHNbXS5kZXNjcmlwdGlvbl0gSHVtYW4tcmVhZGFibGUgZXhwbGFuYXRpb24gb2YgdGhlIHBhcmFtZXRlcjsgZGVmYXVsdHMgdG8gYFwiUGF0aCBwYXJhbWV0ZXI6IDxuYW1lPlwiYC5cbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW3Byb3BzW10ucmVxdWlyZWQ9dHJ1ZV0gV2hldGhlciB0aGUgcGFyYW1ldGVyIGlzIHJlcXVpcmVkOyBkZWZhdWx0cyB0byBgdHJ1ZWAuXG4gKiBAcGFyYW0ge0NvbnN0cnVjdG9yPGFueT59IFtwcm9wc1tdLnR5cGU9U3RyaW5nXSBDb25zdHJ1Y3Rvci90eXBlIHVzZWQgYnkgU3dhZ2dlciB0byBpbmZlciBzY2hlbWEgKGUuZy4sIGBTdHJpbmdgLCBgTnVtYmVyYCwgYFVVSURgLCBjdXN0b20gY2xhc3MpLlxuICogQHJldHVybiB7YW55fSBBIGNvbXBvc2VkIGRlY29yYXRvciBhcHBseWluZyBhbGwgZ2VuZXJhdGVkIGBAQXBpUGFyYW1gIGRlY29yYXRvcnMgdG8gdGhlIHRhcmdldCBtZXRob2Qgb3IgY29udHJvbGxlci5cbiAqIEBmdW5jdGlvbiBBcGlQYXJhbXNGcm9tTW9kZWxcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIEFwaVBhcmFtc0Zyb21Nb2RlbChcbiAgcHJvcHM6IERlY2FmQXBpUHJvcGVydHlbXSA9IFtdXG4pOiBNZXRob2REZWNvcmF0b3IgJiBDbGFzc0RlY29yYXRvciB7XG4gIGNvbnN0IGRlY29yYXRvcnMgPSBwcm9wcy5tYXAoKHApID0+XG4gICAgQXBpUGFyYW1EZWMoe1xuICAgICAgbmFtZTogcC5uYW1lLFxuICAgICAgZGVzY3JpcHRpb246IHAuZGVzY3JpcHRpb24gPz8gYFBhdGggcGFyYW1ldGVyOiAke3AubmFtZX1gLFxuICAgICAgcmVxdWlyZWQ6IHAucmVxdWlyZWQgPz8gdHJ1ZSxcbiAgICAgIC8vIHNjaGVtYTogeyB0eXBlOiAnc3RyaW5nJyB9LFxuICAgICAgdHlwZTogcC50eXBlID8/IFN0cmluZyxcbiAgICB9KVxuICApO1xuICByZXR1cm4gYXBwbHlEZWNvcmF0b3JzKC4uLmRlY29yYXRvcnMpO1xufVxuIiwiaW1wb3J0IHtcbiAgY3JlYXRlUGFyYW1EZWNvcmF0b3IsXG4gIEV4ZWN1dGlvbkNvbnRleHQsXG4gIEludGVybmFsU2VydmVyRXJyb3JFeGNlcHRpb24sXG59IGZyb20gXCJAbmVzdGpzL2NvbW1vblwiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBDdXN0b20gZGVjb3JhdG9yIHRoYXQgZXh0cmFjdHMgdGhlIHJlcXVlc3QgYm9keSBhbmQgaW5zdGFudGlhdGVzIGl0IHVzaW5nIHRoZSBNb2RlbCBjb25zdHJ1Y3RvclxuICogZm91bmQgb24gdGhlIGNvbnRyb2xsZXIuIEhhbmRsZXMgYm90aCBzaW5nbGUgb2JqZWN0cyBhbmQgYXJyYXlzLlxuICovXG5leHBvcnQgY29uc3QgRGVjYWZCb2R5ID0gY3JlYXRlUGFyYW1EZWNvcmF0b3IoXG4gIChkYXRhOiB1bmtub3duLCBjdHg6IEV4ZWN1dGlvbkNvbnRleHQpID0+IHtcbiAgICBjb25zdCByZXF1ZXN0ID0gY3R4LnN3aXRjaFRvSHR0cCgpLmdldFJlcXVlc3QoKTtcbiAgICBjb25zdCBib2R5ID0gcmVxdWVzdC5ib2R5O1xuXG4gICAgLy8gVGhlIER5bmFtaWNNb2RlbENvbnRyb2xsZXIgd2lsbCBoYXZlICdNb2RlbENvbnN0cicgYXZhaWxhYmxlXG4gICAgY29uc3QgY29udHJvbGxlciA9IGN0eC5nZXRDbGFzcygpO1xuICAgIC8vIFdlIGFjY2VzcyB0aGUgc3RhdGljIHByb3BlcnR5IHdlIHdpbGwgYWRkIHRvIHRoZSBEeW5hbWljTW9kZWxDb250cm9sbGVyXG4gICAgY29uc3QgTW9kZWxDb25zdHIgPSAoY29udHJvbGxlciBhcyBhbnkpLmNsYXNzO1xuXG4gICAgaWYgKCFNb2RlbENvbnN0cikge1xuICAgICAgdGhyb3cgbmV3IEludGVybmFsU2VydmVyRXJyb3JFeGNlcHRpb24oXG4gICAgICAgIGBNb2RlbENvbnN0cnVjdG9yIG5vdCBmb3VuZCBvbiBjb250cm9sbGVyICR7Y29udHJvbGxlci5uYW1lfS4gRW5zdXJlIHRoZSBjb250cm9sbGVyIHdhcyBjcmVhdGVkIHZpYSBGcm9tTW9kZWxDb250cm9sbGVyLmBcbiAgICAgICk7XG4gICAgfVxuXG4gICAgaWYgKCFib2R5KSByZXR1cm4gYm9keTtcblxuICAgIGlmIChBcnJheS5pc0FycmF5KGJvZHkpKSB7XG4gICAgICByZXR1cm4gYm9keS5tYXAoKGl0ZW0pID0+IG5ldyBNb2RlbENvbnN0cihpdGVtKSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIG5ldyBNb2RlbENvbnN0cihib2R5KTtcbiAgfVxuKTtcbiIsImltcG9ydCB7IGNyZWF0ZVBhcmFtRGVjb3JhdG9yLCBFeGVjdXRpb25Db250ZXh0IH0gZnJvbSBcIkBuZXN0anMvY29tbW9uXCI7XG5pbXBvcnQgeyBEZWNhZlBhcmFtUHJvcHMsIERlY2FmQXBpUHJvcGVydHkgfSBmcm9tIFwiLi90eXBlc1wiO1xuLyoqXG4gKiBAZGVzY3JpcHRpb24gQ3JlYXRlcyBhIGN1c3RvbSBOZXN0SlMgcGFyYW1ldGVyIGRlY29yYXRvciB0aGF0IGV4dHJhY3RzIGFuZCByZXR1cm5zIHJvdXRlIHBhcmFtZXRlcnMgb3JkZXJlZCBieSBhIHNwZWNpZmljIGtleSBzZXF1ZW5jZS5cbiAqIEBzdW1tYXJ5IFRoZSBgT3JkZXJlZFBhcmFtc2AgZGVjb3JhdG9yIHJlYWRzIHRoZSBpbmNvbWluZyBIVFRQIHJlcXVlc3QncyBgcGFyYW1zYCBvYmplY3QsIG9wdGlvbmFsbHkgb3JkZXJzIGl0IGFjY29yZGluZyB0byBhIHByb3ZpZGVkIGxpc3Qgb2YgcGFyYW1ldGVyIG5hbWVzLCBhbmQgcmV0dXJucyBhbiBvYmplY3QgY29udGFpbmluZyB0aGUgb3JpZ2luYWwgcGFyYW1zLCB0aGUgb3JkZXJlZCB2YWx1ZXMsIGFuZCB0aGUgYXBwbGllZCBvcmRlciBsaXN0LiBUaGlzIGVuc3VyZXMgZGV0ZXJtaW5pc3RpYyBwYXJhbWV0ZXIgYWNjZXNzIGZvciByb3V0ZXMgd2l0aCBtdWx0aXBsZSBwYXRoIHBhcmFtZXRlcnMuXG4gKiBAdGVtcGxhdGUge3N0cmluZ1tdfSBUT3JkZXIgLSBSZXByZXNlbnRzIHRoZSBleHBlY3RlZCBzZXF1ZW5jZSBvZiBwYXJhbWV0ZXIgbmFtZXMuXG4gKiBAcGFyYW0ge1RPcmRlciB8IHVuZGVmaW5lZH0gb3JkZXIgQW4gb3B0aW9uYWwgYXJyYXkgc3BlY2lmeWluZyB0aGUgcGFyYW1ldGVyIG5hbWVzJyBkZXNpcmVkIG9yZGVyLiBJZiBub3QgcHJvdmlkZWQsIHRoZSBkZWNvcmF0b3Igd2lsbCBwcmVzZXJ2ZSB0aGUgb3JkZXIgb2YgdGhlIGtleXMgYXMgdGhleSBhcHBlYXIgaW4gdGhlIG9yaWdpbmFsIGByZXEucGFyYW1zYCBvYmplY3QuXG4gKiBAcGFyYW0ge0V4ZWN1dGlvbkNvbnRleHR9IGN0eCBUaGUgTmVzdEpTIGV4ZWN1dGlvbiBjb250ZXh0LCB1c2VkIHRvIHJldHJpZXZlIHRoZSBjdXJyZW50IEhUVFAgcmVxdWVzdCBvYmplY3QuXG4gKiBAcmV0dXJuIHtEZWNhZlBhcmFtUHJvcHN9IEFuIG9iamVjdCBjb250YWluaW5nOlxuICogLSBgb3JpZ2luYWxgOiB0aGUgcmF3IHBhcmFtZXRlciBtYXAgZnJvbSBgcmVxLnBhcmFtc2A7XG4gKiAtIGBvcmRlcmVkYDogYW4gYXJyYXkgb2YgcGFyYW1ldGVyIHZhbHVlcyBpbiB0aGUgcmVxdWVzdGVkIG9yZGVyO1xuICogLSBgb3JkZXJgOiB0aGUgZWZmZWN0aXZlIG9yZGVyIGxpc3QgdXNlZC5cbiAqIEBmdW5jdGlvbiBPcmRlcmVkUGFyYW1zXG4gKi9cbmNvbnN0IE9yZGVyZWRQYXJhbXMgPSBjcmVhdGVQYXJhbURlY29yYXRvcihcbiAgKG9yZGVyOiBzdHJpbmdbXSB8IHVuZGVmaW5lZCwgY3R4OiBFeGVjdXRpb25Db250ZXh0KTogRGVjYWZQYXJhbVByb3BzID0+IHtcbiAgICBjb25zdCByZXEgPSBjdHguc3dpdGNoVG9IdHRwKCkuZ2V0UmVxdWVzdCgpO1xuICAgIGNvbnN0IG9yaWdpbmFsID0gKHJlcT8ucGFyYW1zID8/IHt9KSBhcyBSZWNvcmQ8c3RyaW5nLCBhbnk+O1xuICAgIGNvbnN0IG9yZGVyTGlzdCA9IG9yZGVyID8/IE9iamVjdC5rZXlzKG9yaWdpbmFsKTtcbiAgICBjb25zdCBvcmRlcmVkID0gb3JkZXJMaXN0Lm1hcCgoaykgPT4gb3JpZ2luYWxba10pO1xuICAgIHJldHVybiB7IHJhdzogb3JpZ2luYWwsIHZhbHVlc0luT3JkZXI6IG9yZGVyZWQsIGtleXNJbk9yZGVyOiBvcmRlckxpc3QgfTtcbiAgfVxuKTtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gQSBoaWdoZXItbGV2ZWwgZGVjb3JhdG9yIGZhY3RvcnkgdGhhdCBsZXZlcmFnZXMgYE9yZGVyZWRQYXJhbXNgIHRvIGV4dHJhY3Qgcm91dGUgcGFyYW1ldGVycyBpbiBhIHNwZWNpZmljIG9yZGVyIGRlcml2ZWQgZnJvbSBhIGxpc3Qgb2YgYEFwaVBhcmFtYCBkZWZpbml0aW9ucy5cbiAqIEBzdW1tYXJ5IGBEZWNhZlBhcmFtc2AgY29tcHV0ZXMgdGhlIG9yZGVyIG9mIHJvdXRlIHBhcmFtZXRlcnMgYmFzZWQgb24gdGhlIHByb3ZpZGVkIGBBcGlQYXJhbVtdYCBzcGVjaWZpY2F0aW9uICh1c2luZyBlYWNoIGVsZW1lbnTigJlzIGBuYW1lYCksIHRoZW4gYXBwbGllcyBgT3JkZXJlZFBhcmFtcyhvcmRlcilgIGFzIGEgcGFyYW1ldGVyIGRlY29yYXRvci4gVGhpcyBlbmFibGVzIHBhcmFtZXRlci1sZXZlbCBiaW5kaW5nIHRoYXQgcmVtYWlucyBjb25zaXN0ZW50IHdpdGggdGhlIGRvY3VtZW50ZWQgQVBJIHBhcmFtZXRlciBtZXRhZGF0YS5cbiAqIEBwYXJhbSB7QXBpUGFyYW1bXX0gW3Byb3BzPVtdXSBBcnJheSBvZiBgQXBpUGFyYW1gIGRlZmluaXRpb25zIHdob3NlIGBuYW1lYCBmaWVsZHMgZGV0ZXJtaW5lIHRoZSBwYXJhbWV0ZXIgZXh0cmFjdGlvbiBvcmRlci5cbiAqIEByZXR1cm4ge1BhcmFtZXRlckRlY29yYXRvcn0gQSBOZXN0SlMgcGFyYW1ldGVyIGRlY29yYXRvciB0aGF0IGluamVjdHMgYW4gb3JkZXJlZCBsaXN0IG9mIHBhcmFtZXRlcnMgYW5kIG1ldGFkYXRhIGludG8gdGhlIGNvbnRyb2xsZXIgbWV0aG9kIGFyZ3VtZW50LlxuICovXG5leHBvcnQgZnVuY3Rpb24gRGVjYWZQYXJhbXMoXG4gIHByb3BzOiBEZWNhZkFwaVByb3BlcnR5W10gPSBbXVxuKTogUGFyYW1ldGVyRGVjb3JhdG9yIHtcbiAgY29uc3Qgb3JkZXIgPSBwcm9wcy5tYXAoKHApID0+IHAubmFtZSk7XG4gIHJldHVybiBPcmRlcmVkUGFyYW1zKG9yZGVyKTtcbn1cblxuZXhwb3J0IGNvbnN0IERlY2FmUXVlcnkgPSBjcmVhdGVQYXJhbURlY29yYXRvcihcbiAgKF86IHVua25vd24sIGN0eDogRXhlY3V0aW9uQ29udGV4dCkgPT4ge1xuICAgIGNvbnN0IHJlcSA9IGN0eC5zd2l0Y2hUb0h0dHAoKS5nZXRSZXF1ZXN0KCk7XG4gICAgY29uc3QgcXVlcnkgPSByZXEucXVlcnkgPz8ge307XG5cbiAgICBjb25zdCBwYXJzZWQ6IGFueSA9IHsgLi4ucXVlcnkgfTtcblxuICAgIC8vIFBhcnNlIGxpbWl0ICYgb2Zmc2V0XG4gICAgaWYgKHBhcnNlZC5saW1pdCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBjb25zdCBuID0gTnVtYmVyKHBhcnNlZC5saW1pdCk7XG4gICAgICBpZiAoIU51bWJlci5pc05hTihuKSkgcGFyc2VkLmxpbWl0ID0gbjtcbiAgICB9XG5cbiAgICBpZiAocGFyc2VkLm9mZnNldCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBjb25zdCBuID0gTnVtYmVyKHBhcnNlZC5vZmZzZXQpO1xuICAgICAgaWYgKCFOdW1iZXIuaXNOYU4obikpIHBhcnNlZC5vZmZzZXQgPSBuO1xuICAgIH1cblxuICAgIC8vIFBhcnNlIGJvb2ttYXJrIG9ubHkgaWYgbnVtZXJpY1xuICAgIGlmIChwYXJzZWQuYm9va21hcmsgIT09IHVuZGVmaW5lZCkge1xuICAgICAgY29uc3QgbiA9IE51bWJlcihwYXJzZWQuYm9va21hcmspO1xuICAgICAgcGFyc2VkLmJvb2ttYXJrID0gTnVtYmVyLmlzTmFOKG4pID8gcGFyc2VkLmJvb2ttYXJrIDogbjtcbiAgICB9XG5cbiAgICByZXR1cm4gcGFyc2VkO1xuICB9XG4pO1xuIiwiaW1wb3J0IHsgQWRhcHRlckZsYWdzLCBDb250ZXh0IH0gZnJvbSBcIkBkZWNhZi10cy9jb3JlXCI7XG5pbXBvcnQgeyBMb2dnZXIgfSBmcm9tIFwiQGRlY2FmLXRzL2xvZ2dpbmdcIjtcblxuZXhwb3J0IGNvbnN0IERFQ0FGX01PRFVMRV9PUFRJT05TID0gXCJEZWNhZk1vZHVsZU9wdGlvbnNcIjtcbmV4cG9ydCBjb25zdCBERUNBRl9BREFQVEVSX0lEID0gXCJEZWNhZkFkYXB0ZXJcIjtcbmV4cG9ydCBjb25zdCBERUNBRl9UQVNLX1NFUlZJQ0VfSUQgPSBcIkRlY2FmVGFza1NlcnZpY2VcIjtcblxuZXhwb3J0IGNvbnN0IERFQ0FGX1JPVVRFID0gXCJEZWNhZlJvdXRlXCI7XG5leHBvcnQgY29uc3QgREVDQUZfSEFORExFUlMgPSBTeW1ib2woXCJEZWNhZkhhbmRsZXJzXCIpO1xuZXhwb3J0IGNvbnN0IERFQ0FGX0VYUE9TRSA9IFwiRGVjYWZFeHBvc2VcIjtcbmV4cG9ydCBjb25zdCBERUNBRl9DT05UUk9MTEVSX0NPTkZJRyA9IFwiRGVjYWZDb250cm9sbGVyQ29uZmlnXCI7XG5cbmV4cG9ydCBjb25zdCBERUNBRl9DT05URVhUX0tFWSA9IFN5bWJvbChcImRlY2FmOmNvbnRleHRcIik7XG5cbmV4cG9ydCB0eXBlIERlY2FmU2VydmVyRmxhZ3M8TE9HIGV4dGVuZHMgTG9nZ2VyID0gTG9nZ2VyPiA9XG4gIEFkYXB0ZXJGbGFnczxMT0c+ICYge1xuICAgIGhlYWRlcnM6IFJlY29yZDxzdHJpbmcsIGFueT47XG4gICAgb3ZlcnJpZGVzOiBSZWNvcmQ8c3RyaW5nLCBhbnk+O1xuICB9O1xuXG5leHBvcnQgdHlwZSBEZWNhZlNlcnZlckN0eCA9IENvbnRleHQ8RGVjYWZTZXJ2ZXJGbGFncz47XG4iLCJpbXBvcnQgeyBNZXRhZGF0YSB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdGlvblwiO1xuXG5pbXBvcnQgeyBERUNBRl9FWFBPU0UgfSBmcm9tIFwiLi4vLi4vY29uc3RhbnRzXCI7XG5cbmV4cG9ydCBmdW5jdGlvbiBleHBvc2UoLi4uZmxhdm91cnM6IHN0cmluZ1tdKSB7XG4gIHJldHVybiBmdW5jdGlvbiBleHBvc2UodGFyZ2V0OiBhbnkpIHtcbiAgICBNZXRhZGF0YS5zZXQoXG4gICAgICB0YXJnZXQsXG4gICAgICBERUNBRl9FWFBPU0UsXG4gICAgICAoZmxhdm91cnMubGVuZ3RoID8gZmxhdm91cnMgOiB0cnVlKSBhcyBhbnlcbiAgICApO1xuICAgIHJldHVybiB0YXJnZXQ7XG4gIH07XG59XG4iLCJpbXBvcnQgeyBNZXRhZGF0YSB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdGlvblwiO1xuaW1wb3J0IHR5cGUgeyBNb2RlbENvbnRyb2xsZXJGYWN0b3J5Q29uZmlnIH0gZnJvbSBcIkBkZWNhZi10cy9mb3ItaHR0cC9zZXJ2ZXJcIjtcblxuaW1wb3J0IHsgREVDQUZfQ09OVFJPTExFUl9DT05GSUcgfSBmcm9tIFwiLi4vLi4vY29uc3RhbnRzXCI7XG5cbi8qKlxuICogQ2xhc3MgZGVjb3JhdG9yIHRoYXQgYXR0YWNoZXMgYSB7QGxpbmsgTW9kZWxDb250cm9sbGVyRmFjdG9yeUNvbmZpZ30gdG8gYSBNb2RlbCxcbiAqIHNvIGBGcm9tTW9kZWxDb250cm9sbGVyLmNyZWF0ZSgpYCBjYW4gcGFzcyBpdCB0byBgTW9kZWxDb250cm9sbGVyRmFjdG9yeS5jcmVhdGUoKWAuXG4gKlxuICogVGhlIHBlci1tb2RlbCBjb25maWcgY2FuIGJlIG92ZXJyaWRkZW4gYnkgdGhlIG1vZHVsZS1sZXZlbCBgY29udHJvbGxlckNvbmZpZ2BcbiAqIG9wdGlvbiBpbiBgRGVjYWZNb2R1bGVPcHRpb25zYC5cbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHNcbiAqIEBjb250cm9sbGVyQ29uZmlnKHsgYWxsb3dHcm91cGluZ1F1ZXJpZXM6IHRydWUsIGFsbG93QnVsa1N0YXRlbWVudDogeyBjcmVhdGU6IHRydWUsIHJlYWQ6IHRydWUsIHVwZGF0ZTogZmFsc2UsIGRlbGV0ZTogdHJ1ZSB9IH0pXG4gKiBAbW9kZWwoKVxuICogY2xhc3MgT3JkZXIgZXh0ZW5kcyBNb2RlbDxPcmRlcj4geyAuLi4gfVxuICogYGBgXG4gKlxuICogQHBhcmFtIGNvbmZpZyAtIEZhY3RvcnkgY29uZmlndXJhdGlvbiBrbm9icyAoYWxsb3dTdGF0ZW1lbnRsZXNzUXVlcnksIGFsbG93R3JvdXBpbmdRdWVyaWVzLCBhbGxvd0J1bGtTdGF0ZW1lbnQpLlxuICovXG5leHBvcnQgZnVuY3Rpb24gY29udHJvbGxlckNvbmZpZyhjb25maWc6IE1vZGVsQ29udHJvbGxlckZhY3RvcnlDb25maWcpIHtcbiAgcmV0dXJuIGZ1bmN0aW9uIGNvbnRyb2xsZXJDb25maWdEZWNvcmF0b3IodGFyZ2V0OiBhbnkpIHtcbiAgICBNZXRhZGF0YS5zZXQodGFyZ2V0LCBERUNBRl9DT05UUk9MTEVSX0NPTkZJRywgY29uZmlnIGFzIGFueSk7XG4gICAgcmV0dXJuIHRhcmdldDtcbiAgfTtcbn1cbiIsImV4cG9ydCBjb25zdCBBVVRIX0hBTkRMRVIgPSBTeW1ib2woXCJBVVRIX0hBTkRMRVJcIik7XG5leHBvcnQgY29uc3QgQVVUSF9NRVRBX0tFWSA9IFwiYXV0aDptZXRhXCI7XG5leHBvcnQgY29uc3QgSVNfUFVCTElDX0tFWSA9IFwiaXNQdWJsaWNcIjtcbmV4cG9ydCBjb25zdCBSRVFVSVJFRF9ST0xFU19LRVkgPSBcInJlcXVpcmVkUm9sZXNcIjtcbmV4cG9ydCBjb25zdCBSRVFVSVJFRF9OQU1FU1BBQ0VTX0tFWSA9IFwicmVxdWlyZWROYW1lc3BhY2VzXCI7XG5leHBvcnQgY29uc3QgU0tJUF9NT0RFTF9ST0xFU19LRVkgPSBcInNraXBNb2RlbFJvbGVzXCI7XG5leHBvcnQgY29uc3QgU0tJUF9NT0RFTF9OQU1FU1BBQ0VTX0tFWSA9IFwic2tpcE1vZGVsTmFtZXNwYWNlc1wiO1xuIiwiaW1wb3J0IHsgSW5qZWN0LCBJbmplY3RhYmxlLCBTY29wZSB9IGZyb20gXCJAbmVzdGpzL2NvbW1vblwiO1xuaW1wb3J0IHsgUkVRVUVTVCB9IGZyb20gXCJAbmVzdGpzL2NvcmVcIjtcbmltcG9ydCB7IFVVSUQgfSBmcm9tIFwiQGRlY2FmLXRzL2NvcmVcIjtcbmltcG9ydCB7IFJlcXVlc3RDb250ZXh0IH0gZnJvbSBcIkBkZWNhZi10cy9mb3ItaHR0cC9zZXJ2ZXJcIjtcbmltcG9ydCB7IHR5cGUgUmVxdWVzdCB9IGZyb20gXCJleHByZXNzXCI7XG5cbmltcG9ydCB7IERlY2FmU2VydmVyQ3R4IH0gZnJvbSBcIi4uL2NvbnN0YW50c1wiO1xuXG5ASW5qZWN0YWJsZSh7IHNjb3BlOiBTY29wZS5SRVFVRVNUIH0pXG5leHBvcnQgY2xhc3MgRGVjYWZSZXF1ZXN0Q29udGV4dDxcbiAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnVzZWQtdmFyc1xuICBDIGV4dGVuZHMgRGVjYWZTZXJ2ZXJDdHggPSBEZWNhZlNlcnZlckN0eCxcbj4gZXh0ZW5kcyBSZXF1ZXN0Q29udGV4dDxSZXF1ZXN0PiB7XG4gIHV1aWQgPSBVVUlELmluc3RhbmNlLmdlbmVyYXRlKCk7XG4gIG92ZXJyaWRlIHJlYWRvbmx5IHJlcXVlc3Q6IFJlcXVlc3Q7XG5cbiAgY29uc3RydWN0b3IoQEluamVjdChSRVFVRVNUKSBwcml2YXRlIHJlYWRvbmx5IHJlcTogUmVxdWVzdCkge1xuICAgIHN1cGVyKFxuICAgICAge1xuICAgICAgICBoZWFkZXJzT2Y6IChyZXF1ZXN0OiBSZXF1ZXN0KSA9PiAocmVxdWVzdCBhcyBhbnkpPy5oZWFkZXJzIHx8IHVuZGVmaW5lZCxcbiAgICAgIH0gYXMgYW55LFxuICAgICAgcmVxXG4gICAgKTtcbiAgICB0aGlzLnJlcXVlc3QgPSByZXE7XG4gIH1cblxuICBnZXQgaGVhZGVycygpOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmcgfCBzdHJpbmdbXSB8IHVuZGVmaW5lZD4gfCB1bmRlZmluZWQge1xuICAgIHJldHVybiB0aGlzLmdldE9yVW5kZWZpbmVkKFwiaGVhZGVyc1wiIGFzIGFueSk7XG4gIH1cblxuICBwdXQocmVjb3JkOiBSZWNvcmQ8YW55LCBhbnk+KSB7XG4gICAgbGV0IG92ZXJyaWRlczogYW55O1xuICAgIHRyeSB7XG4gICAgICBvdmVycmlkZXMgPSB0aGlzLmdldChcIm92ZXJyaWRlc1wiKTtcbiAgICB9IGNhdGNoIChlOiB1bmtub3duKSB7XG4gICAgICBvdmVycmlkZXMgPSB7fTtcbiAgICB9XG5cbiAgICB0aGlzLmFjY3VtdWxhdGUoe1xuICAgICAgb3ZlcnJpZGVzOiBPYmplY3QuYXNzaWduKG92ZXJyaWRlcywgcmVjb3JkKSxcbiAgICB9KTtcbiAgfVxufVxuIiwiaW1wb3J0IHtcbiAgSW5qZWN0YWJsZSxcbiAgTmVzdEludGVyY2VwdG9yLFxuICBFeGVjdXRpb25Db250ZXh0LFxuICBDYWxsSGFuZGxlcixcbiAgSW5qZWN0LFxuICBPcHRpb25hbCxcbiAgU2NvcGUsXG59IGZyb20gXCJAbmVzdGpzL2NvbW1vblwiO1xuaW1wb3J0IHsgUmVmbGVjdG9yIH0gZnJvbSBcIkBuZXN0anMvY29yZVwiO1xuaW1wb3J0IHsgT2JzZXJ2YWJsZSB9IGZyb20gXCJyeGpzXCI7XG5cbmltcG9ydCB7IENvbnN0cnVjdG9yIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0aW9uXCI7XG5pbXBvcnQgeyBMb2dnaW5nIH0gZnJvbSBcIkBkZWNhZi10cy9sb2dnaW5nXCI7XG5pbXBvcnQgeyBBZGFwdGVyIH0gZnJvbSBcIkBkZWNhZi10cy9jb3JlXCI7XG5pbXBvcnQgeyBSZXF1ZXN0VG9Db250ZXh0VHJhbnNmb3JtZXIgfSBmcm9tIFwiQGRlY2FmLXRzL2Zvci1odHRwL3NlcnZlclwiO1xuXG5pbXBvcnQge1xuICBBVVRIX0hBTkRMRVIsXG4gIEFVVEhfTUVUQV9LRVksXG4gIElTX1BVQkxJQ19LRVksXG4gIFJFUVVJUkVEX05BTUVTUEFDRVNfS0VZLFxuICBSRVFVSVJFRF9ST0xFU19LRVksXG4gIFNLSVBfTU9ERUxfUk9MRVNfS0VZLFxuICBTS0lQX01PREVMX05BTUVTUEFDRVNfS0VZLFxufSBmcm9tIFwiLi9jb25zdGFudHNcIjtcbmltcG9ydCB0eXBlIHsgQXV0aEhhbmRsZXIgfSBmcm9tIFwiLi4vdHlwZXNcIjtcbmltcG9ydCB7IERlY2FmUmVxdWVzdENvbnRleHQgfSBmcm9tIFwiLi4vcmVxdWVzdC9EZWNhZlJlcXVlc3RDb250ZXh0XCI7XG5cbkBJbmplY3RhYmxlKHsgc2NvcGU6IFNjb3BlLlJFUVVFU1QgfSlcbmV4cG9ydCBjbGFzcyBBdXRoSW50ZXJjZXB0b3IgaW1wbGVtZW50cyBOZXN0SW50ZXJjZXB0b3Ige1xuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIHJlYWRvbmx5IHJlZmxlY3RvcjogUmVmbGVjdG9yLFxuICAgIHByb3RlY3RlZCByZWFkb25seSByZXF1ZXN0Q29udGV4dDogRGVjYWZSZXF1ZXN0Q29udGV4dCxcbiAgICBAT3B0aW9uYWwoKSBASW5qZWN0KEFVVEhfSEFORExFUikgcHJpdmF0ZSByZWFkb25seSBhdXRoSGFuZGxlcj86IEF1dGhIYW5kbGVyXG4gICkge31cblxuICBhc3luYyBpbnRlcmNlcHQoXG4gICAgY3R4OiBFeGVjdXRpb25Db250ZXh0LFxuICAgIG5leHQ6IENhbGxIYW5kbGVyXG4gICk6IFByb21pc2U8T2JzZXJ2YWJsZTxhbnk+PiB7XG4gICAgY29uc3QgbG9nID0gTG9nZ2luZy5mb3IodGhpcyBhcyBhbnkpLmZvcih0aGlzLmludGVyY2VwdCk7XG5cbiAgICBjb25zdCBpc1B1YmxpYyA9IHRoaXMucmVmbGVjdG9yLmdldEFsbEFuZE92ZXJyaWRlPGJvb2xlYW4+KElTX1BVQkxJQ19LRVksIFtcbiAgICAgIGN0eC5nZXRIYW5kbGVyKCksXG4gICAgICBjdHguZ2V0Q2xhc3MoKSxcbiAgICBdKTtcblxuICAgIGNvbnN0IG1vZGVsTmFtZSA9XG4gICAgICB0aGlzLnJlZmxlY3Rvci5nZXQ8c3RyaW5nIHwgQ29uc3RydWN0b3I+KFxuICAgICAgICBBVVRIX01FVEFfS0VZLFxuICAgICAgICBjdHguZ2V0SGFuZGxlcigpXG4gICAgICApID8/XG4gICAgICB0aGlzLnJlZmxlY3Rvci5nZXQ8c3RyaW5nIHwgQ29uc3RydWN0b3I+KEFVVEhfTUVUQV9LRVksIGN0eC5nZXRDbGFzcygpKTtcblxuICAgIGNvbnN0IHJlcXVpcmVkUm9sZXMgPSB0aGlzLnJlZmxlY3Rvci5nZXRBbGxBbmRPdmVycmlkZTxzdHJpbmdbXT4oXG4gICAgICBSRVFVSVJFRF9ST0xFU19LRVksXG4gICAgICBbY3R4LmdldEhhbmRsZXIoKSwgY3R4LmdldENsYXNzKCldXG4gICAgKTtcblxuICAgIGNvbnN0IHJlcXVpcmVkTmFtZXNwYWNlcyA9IHRoaXMucmVmbGVjdG9yLmdldEFsbEFuZE92ZXJyaWRlPHN0cmluZ1tdPihcbiAgICAgIFJFUVVJUkVEX05BTUVTUEFDRVNfS0VZLFxuICAgICAgW2N0eC5nZXRIYW5kbGVyKCksIGN0eC5nZXRDbGFzcygpXVxuICAgICk7XG5cbiAgICBjb25zdCBza2lwTW9kZWxSb2xlcyA9IHRoaXMucmVmbGVjdG9yLmdldEFsbEFuZE92ZXJyaWRlPGJvb2xlYW4+KFxuICAgICAgU0tJUF9NT0RFTF9ST0xFU19LRVksXG4gICAgICBbY3R4LmdldEhhbmRsZXIoKSwgY3R4LmdldENsYXNzKCldXG4gICAgKTtcblxuICAgIGNvbnN0IHNraXBNb2RlbE5hbWVzcGFjZXMgPSB0aGlzLnJlZmxlY3Rvci5nZXRBbGxBbmRPdmVycmlkZTxib29sZWFuPihcbiAgICAgIFNLSVBfTU9ERUxfTkFNRVNQQUNFU19LRVksXG4gICAgICBbY3R4LmdldEhhbmRsZXIoKSwgY3R4LmdldENsYXNzKCldXG4gICAgKTtcblxuICAgIGNvbnN0IGVmZmVjdGl2ZU1vZGVsID0gc2tpcE1vZGVsUm9sZXMgPyB1bmRlZmluZWQgOiBtb2RlbE5hbWU7XG5cbiAgICBsb2cudmVyYm9zZShgSW50ZXJjZXB0ZWQgcmVxdWVzdCR7bW9kZWxOYW1lID8gYCBmb3IgJHttb2RlbE5hbWV9YCA6IFwiXCJ9YCk7XG5cbiAgICBpZiAoaXNQdWJsaWMpIHtcbiAgICAgIGxvZy5kZWJ1ZyhgUHVibGljIHJvdXRlIOKAlCBza2lwcGluZyBhdXRoYCk7XG4gICAgfSBlbHNlIGlmICh0aGlzLmF1dGhIYW5kbGVyKSB7XG4gICAgICBhd2FpdCB0aGlzLmF1dGhIYW5kbGVyLmF1dGhvcml6ZShcbiAgICAgICAgY3R4LFxuICAgICAgICBlZmZlY3RpdmVNb2RlbCBhcyBzdHJpbmcgfCBDb25zdHJ1Y3RvcixcbiAgICAgICAgcmVxdWlyZWRSb2xlcyxcbiAgICAgICAgcmVxdWlyZWROYW1lc3BhY2VzLFxuICAgICAgICBza2lwTW9kZWxOYW1lc3BhY2VzLFxuICAgICAgICB0aGlzLnJlcXVlc3RDb250ZXh0XG4gICAgICApO1xuICAgIH0gZWxzZSB7XG4gICAgICBsb2cuZGVidWcoYE5vIGF1dGggaGFuZGxlciByZWdpc3RlcmVkYCk7XG4gICAgfVxuXG4gICAgYXdhaXQgdGhpcy5hcHBseVRyYW5zZm9ybWVycygpO1xuXG4gICAgcmV0dXJuIG5leHQuaGFuZGxlKCk7XG4gIH1cblxuICBwcm90ZWN0ZWQgYXN5bmMgYXBwbHlUcmFuc2Zvcm1lcnMoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgZmxhdm91cnMgPSBBZGFwdGVyLmZsYXZvdXJzVG9UcmFuc2Zvcm0oKTtcbiAgICBpZiAoIWZsYXZvdXJzKSByZXR1cm47XG5cbiAgICBmb3IgKGNvbnN0IGZsYXZvdXIgb2YgZmxhdm91cnMpIHtcbiAgICAgIGNvbnN0IHRyYW5zZm9ybWVyID0gQWRhcHRlci50cmFuc2Zvcm1lckZvcihcbiAgICAgICAgZmxhdm91clxuICAgICAgKSBhcyBSZXF1ZXN0VG9Db250ZXh0VHJhbnNmb3JtZXI8YW55PjtcbiAgICAgIGlmICghdHJhbnNmb3JtZXIpIGNvbnRpbnVlO1xuICAgICAgY29uc3QgaW5zdGFuY2UgPSAodHJhbnNmb3JtZXIgYXMgYW55KS5mcm9tXG4gICAgICAgID8gdHJhbnNmb3JtZXJcbiAgICAgICAgOiBuZXcgKHRyYW5zZm9ybWVyIGFzIGFueSkoKTtcbiAgICAgIGNvbnN0IGZyb20gPSBhd2FpdCBpbnN0YW5jZS5mcm9tKHRoaXMucmVxdWVzdENvbnRleHQpO1xuICAgICAgaWYgKGZyb20pIHRoaXMucmVxdWVzdENvbnRleHQuYWNjdW11bGF0ZShmcm9tKTtcbiAgICB9XG4gIH1cbn1cbiIsImltcG9ydCB7IGFwcGx5RGVjb3JhdG9ycywgU2V0TWV0YWRhdGEsIFVzZUludGVyY2VwdG9ycyB9IGZyb20gXCJAbmVzdGpzL2NvbW1vblwiO1xuaW1wb3J0IHsgQXBpQmVhcmVyQXV0aCwgQXBpU2VjdXJpdHkgfSBmcm9tIFwiQG5lc3Rqcy9zd2FnZ2VyXCI7XG5pbXBvcnQgeyBDb25zdHJ1Y3RvciB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdGlvblwiO1xuXG5pbXBvcnQge1xuICBBVVRIX01FVEFfS0VZLFxuICBJU19QVUJMSUNfS0VZLFxuICBSRVFVSVJFRF9OQU1FU1BBQ0VTX0tFWSxcbiAgUkVRVUlSRURfUk9MRVNfS0VZLFxufSBmcm9tIFwiLi9jb25zdGFudHNcIjtcbmltcG9ydCB7IEF1dGhJbnRlcmNlcHRvciB9IGZyb20gXCIuL0F1dGhJbnRlcmNlcHRvclwiO1xuXG5leHBvcnQgZnVuY3Rpb24gQXV0aChtb2RlbD86IHN0cmluZyB8IENvbnN0cnVjdG9yKSB7XG4gIGNvbnN0IHJlc291cmNlID0gbW9kZWxcbiAgICA/IHR5cGVvZiBtb2RlbCA9PT0gXCJzdHJpbmdcIlxuICAgICAgPyBtb2RlbFxuICAgICAgOiBtb2RlbC5uYW1lXG4gICAgOiB1bmRlZmluZWQ7XG4gIGNvbnN0IGRlY3MgPSBbQXBpQmVhcmVyQXV0aCgpLCBVc2VJbnRlcmNlcHRvcnMoQXV0aEludGVyY2VwdG9yKV07XG4gIGlmIChyZXNvdXJjZSkgZGVjcy5wdXNoKFNldE1ldGFkYXRhKEFVVEhfTUVUQV9LRVksIHJlc291cmNlKSk7XG4gIHJldHVybiBhcHBseURlY29yYXRvcnMoLi4uZGVjcyk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBQdWJsaWMoKSB7XG4gIHJldHVybiBhcHBseURlY29yYXRvcnMoU2V0TWV0YWRhdGEoSVNfUFVCTElDX0tFWSwgdHJ1ZSkpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gUmVxdWlyZVJvbGVzKC4uLnJvbGVzOiBzdHJpbmdbXSkge1xuICByZXR1cm4gYXBwbHlEZWNvcmF0b3JzKFxuICAgIEFwaVNlY3VyaXR5KFwiYmVhcmVyXCIpLFxuICAgIFNldE1ldGFkYXRhKFJFUVVJUkVEX1JPTEVTX0tFWSwgcm9sZXMpLFxuICAgIFVzZUludGVyY2VwdG9ycyhBdXRoSW50ZXJjZXB0b3IpXG4gICk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBSZXF1aXJlTmFtZXNwYWNlcyguLi5uYW1lc3BhY2VzOiBzdHJpbmdbXSkge1xuICByZXR1cm4gYXBwbHlEZWNvcmF0b3JzKFxuICAgIEFwaVNlY3VyaXR5KFwiYmVhcmVyXCIpLFxuICAgIFNldE1ldGFkYXRhKFJFUVVJUkVEX05BTUVTUEFDRVNfS0VZLCBuYW1lc3BhY2VzKSxcbiAgICBVc2VJbnRlcmNlcHRvcnMoQXV0aEludGVyY2VwdG9yKVxuICApO1xufVxuIiwiaW1wb3J0IHsgRGVsZXRlLCBHZXQsIFBhdGNoLCBQb3N0LCBQdXQgfSBmcm9tIFwiQG5lc3Rqcy9jb21tb25cIjtcbmltcG9ydCB7IEh0dHBWZXJicyB9IGZyb20gXCIuL3R5cGVzXCI7XG5pbXBvcnQgeyBVbnN1cHBvcnRlZEVycm9yIH0gZnJvbSBcIkBkZWNhZi10cy9jb3JlXCI7XG5cbi8qKlxuICogTWFwcyBhbiBIVFRQIHZlcmIgdG8gaXRzIGNvcnJlc3BvbmRpbmcgTmVzdEpTIG1ldGhvZCBkZWNvcmF0b3IuXG4gKlxuICogQHBhcmFtIHZlcmIgLSBIVFRQIHZlcmIgdG8gYmUgY29udmVydGVkIChlLmcuIEdFVCwgUE9TVCwgUFVULCBQQVRDSCwgREVMRVRFKS5cbiAqIEByZXR1cm5zIEEgTmVzdEpTIG1ldGhvZCBkZWNvcmF0b3IgbWF0Y2hpbmcgdGhlIHByb3ZpZGVkIEhUVFAgdmVyYi5cbiAqXG4gKiBAdGhyb3dzIHtFcnJvcn0gSWYgdGhlIHByb3ZpZGVkIEhUVFAgdmVyYiBpcyBub3Qgc3VwcG9ydGVkIG9yIG5vdCBtYXBwZWRcbiAqIHRvIGEgTmVzdEpTIGRlY29yYXRvci5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIEh0dHBWZXJiVG9EZWNvcmF0b3IoXG4gIHZlcmI6IEh0dHBWZXJic1xuKTogKHBhdGg/OiBzdHJpbmcpID0+IE1ldGhvZERlY29yYXRvciB7XG4gIGNvbnN0IGh0dHBUb0NydWQ6IFJlY29yZDxIdHRwVmVyYnMsIChwYXRoPzogc3RyaW5nKSA9PiBNZXRob2REZWNvcmF0b3I+ID0ge1xuICAgIEdFVDogR2V0LFxuICAgIFBPU1Q6IFBvc3QsXG4gICAgUFVUOiBQdXQsXG4gICAgUEFUQ0g6IFBhdGNoLFxuICAgIERFTEVURTogRGVsZXRlLFxuICB9O1xuXG4gIGNvbnN0IGRlY29yYXRvciA9IGh0dHBUb0NydWRbdmVyYl07XG5cbiAgaWYgKCFkZWNvcmF0b3IpIHtcbiAgICB0aHJvdyBuZXcgVW5zdXBwb3J0ZWRFcnJvcihcbiAgICAgIGBVbnN1cHBvcnRlZCBIVFRQIHZlcmIgXCIke3ZlcmJ9XCIuIE5vIE5lc3RKUyBkZWNvcmF0b3IgbWFwcGluZyB3YXMgZm91bmQuYFxuICAgICk7XG4gIH1cblxuICByZXR1cm4gZGVjb3JhdG9yO1xufVxuIiwiaW1wb3J0IHsgUXVlcnkgfSBmcm9tIFwiQG5lc3Rqcy9jb21tb25cIjtcbmltcG9ydCB7IExvZ2dlciB9IGZyb20gXCJAZGVjYWYtdHMvbG9nZ2luZ1wiO1xuaW1wb3J0IHsgdHlwZSBEZWNvcmF0b3JCdW5kbGUgfSBmcm9tIFwiLi90eXBlc1wiO1xuaW1wb3J0IHtcbiAgQXBpTm9Db250ZW50UmVzcG9uc2UsXG4gIEFwaU9rUmVzcG9uc2UsXG4gIEFwaU9wZXJhdGlvbixcbiAgQXBpUGFyYW0sXG4gIEFwaVF1ZXJ5LFxufSBmcm9tIFwiQG5lc3Rqcy9zd2FnZ2VyXCI7XG5pbXBvcnQge1xuICBEZWNhZkFwaVByb3BlcnR5LFxuICB0eXBlIERlY2FmUGFyYW1Qcm9wcyxcbiAgRGVjYWZQYXJhbXMsXG59IGZyb20gXCIuL2RlY29yYXRvcnNcIjtcbmltcG9ydCB0eXBlIHsgSHR0cFZlcmJzIH0gZnJvbSBcIi4vZGVjb3JhdG9ycy90eXBlc1wiO1xuaW1wb3J0IHtcbiAgRGlyZWN0aW9uTGltaXRPZmZzZXQsXG4gIE1vZGVsU2VydmljZSxcbiAgT3JkZXJEaXJlY3Rpb24sXG4gIFJlcG8sXG59IGZyb20gXCJAZGVjYWYtdHMvY29yZVwiO1xuaW1wb3J0IHsgTW9kZWwgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRvci12YWxpZGF0aW9uXCI7XG5pbXBvcnQgeyBIdHRwVmVyYlRvRGVjb3JhdG9yIH0gZnJvbSBcIi4vZGVjb3JhdG9ycy91dGlsc1wiO1xuaW1wb3J0IHsgRGVjYWZNb2RlbENvbnRyb2xsZXIgfSBmcm9tIFwiLi4vY29udHJvbGxlcnNcIjtcbmltcG9ydCB7IEJhc2VFcnJvciwgSW50ZXJuYWxFcnJvciB9IGZyb20gXCJAZGVjYWYtdHMvZGItZGVjb3JhdG9yc1wiO1xuXG5jb25zdCBleHRyYWN0UGF0aFBhcmFtcyA9IChyb3V0ZVBhdGg6IHN0cmluZyk6IHN0cmluZ1tdID0+IHtcbiAgcmV0dXJuIHJvdXRlUGF0aFxuICAgIC5zcGxpdChcIi9cIilcbiAgICAuZmlsdGVyKChwKSA9PiBwLnN0YXJ0c1dpdGgoXCI6XCIpKVxuICAgIC5tYXAoKHApID0+IHAuc2xpY2UoMSkpO1xufTtcblxuY29uc3QgYXBpUGFyYW1TcGVjID0gKG5hbWU6IHN0cmluZyk6IERlY2FmQXBpUHJvcGVydHkgPT4gKHtcbiAgbmFtZSxcbiAgZGVzY3JpcHRpb246IGAke25hbWV9IHBhcmFtZXRlciBmb3IgdGhlIHF1ZXJ5YCxcbiAgcmVxdWlyZWQ6IHRydWUsXG4gIHR5cGU6IFN0cmluZyxcbn0pO1xuXG5mdW5jdGlvbiB0b0RlY2FmRXJyb3IoZXJyb3I6IHVua25vd24sIGZhbGxiYWNrTWVzc2FnZTogc3RyaW5nKTogQmFzZUVycm9yIHtcbiAgaWYgKGVycm9yIGluc3RhbmNlb2YgQmFzZUVycm9yKSByZXR1cm4gZXJyb3I7XG4gIHJldHVybiBuZXcgSW50ZXJuYWxFcnJvcihcbiAgICBlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gYCR7ZmFsbGJhY2tNZXNzYWdlfTogJHtlcnJvci5tZXNzYWdlfWAgOiBmYWxsYmFja01lc3NhZ2VcbiAgKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldEFwaURlY29yYXRvcnMoXG4gIG1ldGhvZE5hbWU6IHN0cmluZyxcbiAgcm91dGVQYXRoOiBzdHJpbmcsXG4gIGh0dHBWZXJiOiBIdHRwVmVyYnMsXG4gIGluY2x1ZGVRdWVyeVBhcmFtczogYm9vbGVhbiA9IGZhbHNlXG4pOiBEZWNvcmF0b3JCdW5kbGUge1xuICBjb25zdCBOZXN0SHR0cFJvdXRlRGVjID0gSHR0cFZlcmJUb0RlY29yYXRvcihodHRwVmVyYik7XG4gIGNvbnN0IGFwaVBhdGhQYXJhbXMgPSBleHRyYWN0UGF0aFBhcmFtcyhyb3V0ZVBhdGgpLm1hcChhcGlQYXJhbVNwZWMpO1xuXG4gIGNvbnN0IHN3YWdnZXJRdWVyeVBhcmFtcyA9IFtdO1xuICBpZiAoaHR0cFZlcmIgPT09IFwiR0VUXCIgJiYgaW5jbHVkZVF1ZXJ5UGFyYW1zKSB7XG4gICAgc3dhZ2dlclF1ZXJ5UGFyYW1zLnB1c2goXG4gICAgICBBcGlRdWVyeSh7XG4gICAgICAgIG5hbWU6IFwiZGlyZWN0aW9uXCIsXG4gICAgICAgIHJlcXVpcmVkOiBmYWxzZSxcbiAgICAgICAgZW51bTogT3JkZXJEaXJlY3Rpb24sXG4gICAgICAgIGRlc2NyaXB0aW9uOiBcInRoZSBzb3J0IG9yZGVyIHdoZW4gYXBwbGljYWJsZVwiLFxuICAgICAgfSksXG4gICAgICBBcGlRdWVyeSh7XG4gICAgICAgIG5hbWU6IFwibGltaXRcIixcbiAgICAgICAgcmVxdWlyZWQ6IGZhbHNlLFxuICAgICAgICBkZXNjcmlwdGlvbjogXCJsaW1pdCBvciBwYWdlIHNpemUgd2hlbiBhcHBsaWNhYmxlXCIsXG4gICAgICB9KSxcbiAgICAgIEFwaVF1ZXJ5KHtcbiAgICAgICAgbmFtZTogXCJvZmZzZXRcIixcbiAgICAgICAgcmVxdWlyZWQ6IGZhbHNlLFxuICAgICAgICBkZXNjcmlwdGlvbjogXCJvZmZzZXQgb3IgYm9va21hcmsgd2hlbiBhcHBsaWNhYmxlXCIsXG4gICAgICB9KVxuICAgICk7XG4gIH1cblxuICByZXR1cm4ge1xuICAgIG1ldGhvZDogW1xuICAgICAgTmVzdEh0dHBSb3V0ZURlYyhyb3V0ZVBhdGgpLFxuICAgICAgLi4uYXBpUGF0aFBhcmFtcy5tYXAoQXBpUGFyYW0pLFxuICAgICAgLi4uc3dhZ2dlclF1ZXJ5UGFyYW1zLFxuICAgICAgQXBpT3BlcmF0aW9uKHtcbiAgICAgICAgc3VtbWFyeTogYFJldHJpZXZlIHJlY29yZHMgdXNpbmcgYWNjb3JkaW5nIHRvIFwiJHttZXRob2ROYW1lfVwiLmAsXG4gICAgICB9KSxcbiAgICAgIEFwaU9rUmVzcG9uc2Uoe1xuICAgICAgICBkZXNjcmlwdGlvbjogYFJlc3VsdCBzdWNjZXNzZnVsbHkgcmV0cmlldmVkLmAsXG4gICAgICB9KSxcbiAgICAgIEFwaU5vQ29udGVudFJlc3BvbnNlKHtcbiAgICAgICAgZGVzY3JpcHRpb246IGBObyBjb250ZW50IHJldHVybmVkIGJ5IHRoZSBtZXRob2QuYCxcbiAgICAgIH0pLFxuICAgIF0sXG4gICAgcGFyYW1zOiBbRGVjYWZQYXJhbXMoYXBpUGF0aFBhcmFtcyksIFF1ZXJ5KCldLCAvLyAsIERlY2FmQm9keSgpXSxcbiAgfTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGFwcGx5QXBpRGVjb3JhdG9ycyhcbiAgdGFyZ2V0OiBhbnksXG4gIG1ldGhvZE5hbWU6IHN0cmluZyxcbiAgZGVzY3JpcHRvcjogUHJvcGVydHlEZXNjcmlwdG9yLFxuICBkZWNvcmF0b3JzOiBEZWNvcmF0b3JCdW5kbGVcbikge1xuICBjb25zdCBwcm90byA9IHRhcmdldD8ucHJvdG90eXBlID8/IHRhcmdldDtcbiAgZGVjb3JhdG9ycy5tZXRob2QuZm9yRWFjaCgoZCkgPT4gZChwcm90bywgbWV0aG9kTmFtZSwgZGVzY3JpcHRvcikpO1xuICBkZWNvcmF0b3JzLnBhcmFtcz8uZm9yRWFjaCgoZCwgaW5kZXgpID0+IGQocHJvdG8sIG1ldGhvZE5hbWUsIGluZGV4KSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiByZXNvbHZlUGVyc2lzdGVuY2VNZXRob2Q8VCBleHRlbmRzIE1vZGVsPGJvb2xlYW4+PihcbiAgcGVyc2lzdGVuY2U6IFJlcG88VD4gfCBNb2RlbFNlcnZpY2U8VD4sXG4gIG1ldGhvZE5hbWU6IHN0cmluZyxcbiAgLi4uYXJnczogYW55W11cbik6IGFueSB7XG4gIGlmIChwZXJzaXN0ZW5jZSBpbnN0YW5jZW9mIE1vZGVsU2VydmljZSkge1xuICAgIHJldHVybiB0eXBlb2YgKHBlcnNpc3RlbmNlIGFzIGFueSlbbWV0aG9kTmFtZV0gPT09IFwiZnVuY3Rpb25cIlxuICAgICAgPyAocGVyc2lzdGVuY2UgYXMgYW55KVttZXRob2ROYW1lXSguLi5hcmdzKVxuICAgICAgOiBwZXJzaXN0ZW5jZS5zdGF0ZW1lbnQobWV0aG9kTmFtZSwgLi4uYXJncyk7XG4gIH1cblxuICBpZiAodHlwZW9mIChwZXJzaXN0ZW5jZSBhcyBhbnkpW21ldGhvZE5hbWVdID09PSBcImZ1bmN0aW9uXCIpXG4gICAgcmV0dXJuIChwZXJzaXN0ZW5jZSBhcyBhbnkpW21ldGhvZE5hbWVdKC4uLmFyZ3MpO1xuXG4gIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFxuICAgIGBQZXJzaXN0ZW5jZSBtZXRob2QgXCIke21ldGhvZE5hbWV9XCIgbm90IGZvdW5kIG9uICR7cGVyc2lzdGVuY2U/LmNvbnN0cnVjdG9yPy5uYW1lfWBcbiAgKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZVJvdXRlSGFuZGxlcjxUPihtZXRob2ROYW1lOiBzdHJpbmcpIHtcbiAgcmV0dXJuIGFzeW5jIGZ1bmN0aW9uIChcbiAgICB0aGlzOiBEZWNhZk1vZGVsQ29udHJvbGxlcjxhbnk+LFxuICAgIHBhdGhQYXJhbXM6IERlY2FmUGFyYW1Qcm9wcyxcbiAgICBxdWVyeVBhcmFtczogRGlyZWN0aW9uTGltaXRPZmZzZXRcbiAgKTogUHJvbWlzZTxUPiB7XG4gICAgY29uc3QgbG9nOiBMb2dnZXIgPSB0aGlzLmxvZy5mb3IobWV0aG9kTmFtZSk7XG5cbiAgICB0cnkge1xuICAgICAgbG9nLmRlYnVnKFxuICAgICAgICBgSW52b2tpbmcgcGVyc2lzdGVuY2UgbWV0aG9kIFwiJHttZXRob2ROYW1lfVwiIGdpdmVuIHBhcmFtZXRlcnM6ICR7SlNPTi5zdHJpbmdpZnkocGF0aFBhcmFtcy52YWx1ZXNJbk9yZGVyKX1gXG4gICAgICApO1xuICAgICAgY29uc3QgeyBkaXJlY3Rpb24sIGxpbWl0LCBvZmZzZXQgfSA9IHF1ZXJ5UGFyYW1zO1xuICAgICAgcmV0dXJuIGF3YWl0IHJlc29sdmVQZXJzaXN0ZW5jZU1ldGhvZChcbiAgICAgICAgdGhpcy5wZXJzaXN0ZW5jZSh0aGlzLmN0eCksXG4gICAgICAgIG1ldGhvZE5hbWUsXG4gICAgICAgIC4uLnBhdGhQYXJhbXMudmFsdWVzSW5PcmRlcixcbiAgICAgICAgZGlyZWN0aW9uLFxuICAgICAgICBsaW1pdCxcbiAgICAgICAgb2Zmc2V0XG4gICAgICApO1xuICAgIH0gY2F0Y2ggKGU6IGFueSkge1xuICAgICAgbG9nLmVycm9yKGBDdXN0b20gcXVlcnkgXCIke21ldGhvZE5hbWV9XCIgZmFpbGVkYCwgZSk7XG4gICAgICB0aHJvdyB0b0RlY2FmRXJyb3IoZSwgYEN1c3RvbSBxdWVyeSBcIiR7bWV0aG9kTmFtZX1cIiBmYWlsZWRgKTtcbiAgICB9XG4gIH07XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBkZWZpbmVSb3V0ZU1ldGhvZChcbiAgQ29udHJvbGxlckNsYXNzOiBuZXcgKC4uLmFyZ3M6IGFueVtdKSA9PiBhbnksXG4gIG1ldGhvZE5hbWU6IHN0cmluZyxcbiAgaGFuZGxlcjogKC4uLmFyZ3M6IGFueVtdKSA9PiBhbnlcbik6IFByb3BlcnR5RGVzY3JpcHRvciB8IHVuZGVmaW5lZCB7XG4gIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShcbiAgICBDb250cm9sbGVyQ2xhc3MucHJvdG90eXBlIHx8IENvbnRyb2xsZXJDbGFzcyxcbiAgICBtZXRob2ROYW1lLFxuICAgIHtcbiAgICAgIHZhbHVlOiBoYW5kbGVyLFxuICAgICAgd3JpdGFibGU6IGZhbHNlLFxuICAgIH1cbiAgKTtcblxuICByZXR1cm4gT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcihcbiAgICBDb250cm9sbGVyQ2xhc3MucHJvdG90eXBlIHx8IENvbnRyb2xsZXJDbGFzcyxcbiAgICBtZXRob2ROYW1lXG4gICk7XG59XG4iLCJpbXBvcnQgeyBEZWZhdWx0QWRhcHRlckZsYWdzIH0gZnJvbSBcIkBkZWNhZi10cy9jb3JlXCI7XG5pbXBvcnQgeyBMb2dnaW5nLCBMb2dnZXIgfSBmcm9tIFwiQGRlY2FmLXRzL2xvZ2dpbmdcIjtcblxuaW1wb3J0IHsgRGVjYWZSZXF1ZXN0Q29udGV4dCB9IGZyb20gXCIuL0RlY2FmUmVxdWVzdENvbnRleHRcIjtcbmltcG9ydCB7IHR5cGUgRGVjYWZTZXJ2ZXJGbGFncyB9IGZyb20gXCIuLi9jb25zdGFudHNcIjtcblxuY29uc3QgUkVRVUVTVF9DT05URVhUVUFMSVpFRF9LRVkgPSBcIl9fZGVjYWZSZXF1ZXN0Q29udGV4dENvbnRleHR1YWxpemVkXCI7XG5cbmV4cG9ydCBmdW5jdGlvbiBjb250ZXh0dWFsaXplUmVxdWVzdENvbnRleHQoXG4gIHJlcXVlc3RDb250ZXh0OiBEZWNhZlJlcXVlc3RDb250ZXh0LFxuICByZXE6IGFueVxuKTogYm9vbGVhbiB7XG4gIGlmIChyZXF1ZXN0Q29udGV4dC5nZXRPclVuZGVmaW5lZChSRVFVRVNUX0NPTlRFWFRVQUxJWkVEX0tFWSBhcyBhbnkpKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgY29uc3QgaGVhZGVycyA9IHJlcS5oZWFkZXJzO1xuICBjb25zdCBmbGFnczogRGVjYWZTZXJ2ZXJGbGFncyA9IHtcbiAgICBoZWFkZXJzOiBoZWFkZXJzLFxuICAgIG92ZXJyaWRlczoge30sXG4gIH0gYXMgYW55O1xuXG4gIGNvbnN0IGlwID0gZXh0cmFjdElwKHJlcSk7XG4gIGNvbnN0IGN1cnJlbnRMb2cgPSByZXF1ZXN0Q29udGV4dC5nZXRPclVuZGVmaW5lZChcImxvZ2dlclwiIGFzIGFueSkgYXNcbiAgICB8IExvZ2dlclxuICAgIHwgdW5kZWZpbmVkO1xuICBjb25zdCBsb2dnZXIgPSBpcFxuICAgID8gKGN1cnJlbnRMb2cgPz8gTG9nZ2luZy5nZXQoKSkuZm9yKHsgaXAgfSlcbiAgICA6IGN1cnJlbnRMb2cgPz8gTG9nZ2luZy5nZXQoKTtcblxuICByZXF1ZXN0Q29udGV4dC5hY2N1bXVsYXRlKFxuICAgIE9iamVjdC5hc3NpZ24oXG4gICAgICB7fSxcbiAgICAgIERlZmF1bHRBZGFwdGVyRmxhZ3MsXG4gICAgICB7XG4gICAgICAgIGxvZ2dlcixcbiAgICAgICAgdGltZXN0YW1wOiBuZXcgRGF0ZSgpLFxuICAgICAgICBvcGVyYXRpb246IGAke3JlcS5tZXRob2R9ICR7cmVxLnVybH1gLFxuICAgICAgfSxcbiAgICAgIGZsYWdzLFxuICAgICAgeyBbUkVRVUVTVF9DT05URVhUVUFMSVpFRF9LRVldOiB0cnVlIH1cbiAgICApXG4gICk7XG5cbiAgcmV0dXJuIHRydWU7XG59XG5cbmZ1bmN0aW9uIGV4dHJhY3RJcChyZXE6IGFueSk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IGhlYWRlcnMgPSByZXEuaGVhZGVycztcbiAgZnVuY3Rpb24gcGFyc2VJcEhlYWRlcih2YWx1ZT86IHN0cmluZyB8IHN0cmluZ1tdKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgICBpZiAoIXZhbHVlKSByZXR1cm4gdW5kZWZpbmVkO1xuICAgIGNvbnN0IGNhbmRpZGF0ZSA9IEFycmF5LmlzQXJyYXkodmFsdWUpID8gdmFsdWVbMF0gOiB2YWx1ZTtcbiAgICByZXR1cm4gY2FuZGlkYXRlXG4gICAgICAuc3BsaXQoXCIsXCIpXG4gICAgICAubWFwKChzZWdtZW50KSA9PiBzZWdtZW50LnRyaW0oKSlcbiAgICAgIC5maWx0ZXIoQm9vbGVhbilbMF07XG4gIH1cbiAgcmV0dXJuIChcbiAgICBwYXJzZUlwSGVhZGVyKGhlYWRlcnM/LltcIngtZm9yd2FyZGVkLWZvclwiXSkgPz9cbiAgICBwYXJzZUlwSGVhZGVyKGhlYWRlcnM/LltcIngtcmVhbC1pcFwiXSkgPz9cbiAgICBwYXJzZUlwSGVhZGVyKGhlYWRlcnM/LltcIlgtRm9yd2FyZGVkLUZvclwiXSkgPz9cbiAgICBwYXJzZUlwSGVhZGVyKGhlYWRlcnM/LltcIlgtUmVhbC1JUFwiXSkgPz9cbiAgICByZXEuaXBcbiAgKTtcbn1cbiIsImltcG9ydCB7XG4gIEluamVjdCxcbiAgSW5qZWN0YWJsZSxcbiAgTmVzdE1pZGRsZXdhcmUsXG4gIE9wdGlvbmFsLFxuICBTY29wZSxcbn0gZnJvbSBcIkBuZXN0anMvY29tbW9uXCI7XG5pbXBvcnQgeyBBVVRIX0hBTkRMRVIgfSBmcm9tIFwiLi9jb25zdGFudHNcIjtcbmltcG9ydCB0eXBlIHsgQXV0aEhhbmRsZXIgfSBmcm9tIFwiLi4vdHlwZXNcIjtcbmltcG9ydCB7IERlY2FmUmVxdWVzdENvbnRleHQgfSBmcm9tIFwiLi4vcmVxdWVzdC9EZWNhZlJlcXVlc3RDb250ZXh0XCI7XG5pbXBvcnQgeyBjb250ZXh0dWFsaXplUmVxdWVzdENvbnRleHQgfSBmcm9tIFwiLi4vcmVxdWVzdC9jb250ZXh0dWFsaXplXCI7XG5cbkBJbmplY3RhYmxlKHsgc2NvcGU6IFNjb3BlLlJFUVVFU1QgfSlcbmV4cG9ydCBjbGFzcyBBdXRoTWlkZGxld2FyZSBpbXBsZW1lbnRzIE5lc3RNaWRkbGV3YXJlIHtcbiAgY29uc3RydWN0b3IoXG4gICAgQE9wdGlvbmFsKClcbiAgICBASW5qZWN0KEFVVEhfSEFORExFUilcbiAgICBwcml2YXRlIHJlYWRvbmx5IGF1dGhIYW5kbGVyOiBBdXRoSGFuZGxlciB8IHVuZGVmaW5lZCxcbiAgICBwcml2YXRlIHJlYWRvbmx5IHJlcXVlc3RDb250ZXh0OiBEZWNhZlJlcXVlc3RDb250ZXh0XG4gICkge31cblxuICBhc3luYyB1c2UocmVxOiBhbnksIF9yZXM6IGFueSwgbmV4dDogKCkgPT4gdm9pZCB8IFByb21pc2U8dm9pZD4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb250ZXh0dWFsaXplUmVxdWVzdENvbnRleHQodGhpcy5yZXF1ZXN0Q29udGV4dCwgcmVxKTtcbiAgICBpZiAodGhpcy5hdXRoSGFuZGxlcikge1xuICAgICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgdGhpcy5hdXRoSGFuZGxlci5wcmltZShyZXEsIHRoaXMucmVxdWVzdENvbnRleHQgYXMgYW55KTtcbiAgICAgIH0gY2F0Y2gge1xuICAgICAgICAvLyBQcmltaW5nIGlzIGJlc3QtZWZmb3J0LiBUaGUgaW50ZXJjZXB0b3Igd2lsbCBzdGlsbCBwZXJmb3JtIHZhbGlkYXRpb24uXG4gICAgICB9XG4gICAgfVxuICAgIGF3YWl0IG5leHQoKTtcbiAgfVxufVxuIiwiaW1wb3J0IHsgRXhlY3V0aW9uQ29udGV4dCB9IGZyb20gXCJAbmVzdGpzL2NvbW1vblwiO1xuaW1wb3J0IHsgQXV0aG9yaXphdGlvbkVycm9yIH0gZnJvbSBcIkBkZWNhZi10cy9jb3JlXCI7XG5pbXBvcnQgeyBBdXRoSGFuZGxlciwgQXV0aERhdGEsIEF1dGhSZXF1ZXN0TGlrZSB9IGZyb20gXCJAZGVjYWYtdHMvZm9yLWh0dHAvc2VydmVyXCI7XG5pbXBvcnQgeyBEZWNhZlJlcXVlc3RDb250ZXh0IH0gZnJvbSBcIi4uL3JlcXVlc3QvRGVjYWZSZXF1ZXN0Q29udGV4dFwiO1xuXG4vKipcbiAqIFNpbXBsZSBhdXRoIGhhbmRsZXIgdGhhdCByZWFkcyBhIHJvbGUgc3RyaW5nIGZyb20gdGhlIGBBdXRob3JpemF0aW9uOiBCZWFyZXIgPHJvbGU+YCBoZWFkZXIuXG4gKlxuICogT25seSBvdmVycmlkZXMge0BsaW5rIEF1dGhIYW5kbGVyLmV4dHJhY3RGcm9tUmVxdWVzdH0gdG8gcmV0dXJuIHRoZSBiZWFyZXIgdG9rZW4gYXNcbiAqIGJvdGggdGhlIHVzZXIgaWRlbnRpZmllciBhbmQgdGhlIHNpbmdsZSByb2xlLiBUaGUgYmFzZSBjbGFzcyBgYmluZFRvQ29udGV4dGBcbiAqIChgY3R4LmFjY3VtdWxhdGUoZGF0YSlgKSBpcyBzdWZmaWNpZW50IOKAlCB0aGUgdHJhbnNmb3JtZXIvYWRhcHRlciBpcyByZXNwb25zaWJsZVxuICogZm9yIG1hcHBpbmcgY29udGV4dCBmaWVsZHMgdG8gYWRhcHRlci1zcGVjaWZpYyBrZXlzIGxpa2UgYFVVSURgLlxuICovXG5leHBvcnQgY2xhc3MgRGVjYWZBdXRoSGFuZGxlciBleHRlbmRzIEF1dGhIYW5kbGVyPFxuICBFeGVjdXRpb25Db250ZXh0LFxuICBEZWNhZlJlcXVlc3RDb250ZXh0LFxuICBBdXRoRGF0YVxuPiB7XG4gIHByb3RlY3RlZCBvdmVycmlkZSBpc1B1YmxpY1JlcXVlc3QoX3JlcXVlc3Q6IEF1dGhSZXF1ZXN0TGlrZSk6IGJvb2xlYW4ge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIHByb3RlY3RlZCBwYXJzZVJlcXVlc3QocmVxOiBhbnkpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICAgIGNvbnN0IHVzZXJSb2xlID0gcmVxLmhlYWRlcnMuYXV0aG9yaXphdGlvbj8uc3BsaXQoXCIgXCIpWzFdIGFzIHN0cmluZztcbiAgICByZXR1cm4gdXNlclJvbGU7XG4gIH1cblxuICBwcm90ZWN0ZWQgcmVxdWVzdEZyb21Db250ZXh0KGN0eDogRXhlY3V0aW9uQ29udGV4dCkge1xuICAgIHJldHVybiBjdHguc3dpdGNoVG9IdHRwKCkuZ2V0UmVxdWVzdCgpO1xuICB9XG5cbiAgcHJvdGVjdGVkIGV4dHJhY3RGcm9tUmVxdWVzdChyZXE6IGFueSk6IEF1dGhEYXRhIHtcbiAgICBjb25zdCB1c2VyUm9sZSA9IHRoaXMucGFyc2VSZXF1ZXN0KHJlcSk7XG4gICAgaWYgKCF1c2VyUm9sZSkgdGhyb3cgbmV3IEF1dGhvcml6YXRpb25FcnJvcihcIlVuYXV0aGVudGljYXRlZFwiKTtcbiAgICByZXR1cm4geyB1c2VyOiB1c2VyUm9sZSwgcm9sZXM6IFt1c2VyUm9sZV0gfTtcbiAgfVxufVxuXG4vKipcbiAqIEFsaWFzIGZvciB7QGxpbmsgRGVjYWZBdXRoSGFuZGxlcn0ga2VwdCBmb3IgYmFja3dhcmQgY29tcGF0aWJpbGl0eS5cbiAqIFRoZSBcInJvbGVcIiB2YXJpYW50IHByZXZpb3VzbHkgcmV0dXJuZWQgcm9sZXMgZnJvbSBgYXV0aG9yaXplYDsgd2l0aCB0aGUgYmFzZVxuICogY2xhc3Mgbm93IG9yY2hlc3RyYXRpbmcgcm9sZSBjaGVja3MgaW50ZXJuYWxseSwgdGhlIHR3byBjbGFzc2VzIGFyZSBlcXVpdmFsZW50LlxuICovXG5leHBvcnQgY2xhc3MgRGVjYWZSb2xlQXV0aEhhbmRsZXIgZXh0ZW5kcyBEZWNhZkF1dGhIYW5kbGVyIHt9XG4iLCJpbXBvcnQgeyBEeW5hbWljTW9kdWxlLCBNaWRkbGV3YXJlQ29uc3VtZXIsIE1vZHVsZSwgTmVzdE1vZHVsZSwgUmVxdWVzdE1ldGhvZCwgVHlwZSB9IGZyb20gXCJAbmVzdGpzL2NvbW1vblwiO1xuaW1wb3J0IHsgQVBQX0lOVEVSQ0VQVE9SIH0gZnJvbSBcIkBuZXN0anMvY29yZVwiO1xuXG5pbXBvcnQgeyBBdXRoSW50ZXJjZXB0b3IgfSBmcm9tIFwiLi9BdXRoSW50ZXJjZXB0b3JcIjtcbmltcG9ydCB7IEF1dGhNaWRkbGV3YXJlIH0gZnJvbSBcIi4vQXV0aE1pZGRsZXdhcmVcIjtcbmltcG9ydCB7IEFVVEhfSEFORExFUiB9IGZyb20gXCIuL2NvbnN0YW50c1wiO1xuaW1wb3J0IHsgQXV0aEhhbmRsZXIgfSBmcm9tIFwiLi4vdHlwZXNcIjtcblxuZXhwb3J0IHR5cGUgRGVjYWZBdXRoTW9kdWxlT3B0aW9ucyA9IHtcbiAgZ2xvYmFsPzogYm9vbGVhbjtcbiAgaGFuZGxlcj86IFR5cGU8QXV0aEhhbmRsZXI+O1xufTtcblxuQE1vZHVsZSh7fSlcbmV4cG9ydCBjbGFzcyBEZWNhZkF1dGhNb2R1bGUgaW1wbGVtZW50cyBOZXN0TW9kdWxlIHtcbiAgc3RhdGljIGZvclJvb3QoXG4gICAgb3B0aW9uczogRGVjYWZBdXRoTW9kdWxlT3B0aW9ucyA9IHt9XG4gICk6IER5bmFtaWNNb2R1bGUge1xuICAgIGNvbnN0IHByb3ZpZGVyczogRHluYW1pY01vZHVsZVtcInByb3ZpZGVyc1wiXSA9IFtcbiAgICAgIEF1dGhJbnRlcmNlcHRvcixcbiAgICAgIEF1dGhNaWRkbGV3YXJlLFxuICAgIF07XG5cbiAgICBpZiAob3B0aW9ucy5oYW5kbGVyKSB7XG4gICAgICBwcm92aWRlcnMucHVzaChvcHRpb25zLmhhbmRsZXIpO1xuICAgICAgcHJvdmlkZXJzLnB1c2goe1xuICAgICAgICBwcm92aWRlOiBBVVRIX0hBTkRMRVIsXG4gICAgICAgIHVzZUNsYXNzOiBvcHRpb25zLmhhbmRsZXIsXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBpZiAob3B0aW9ucy5nbG9iYWwpIHtcbiAgICAgIChwcm92aWRlcnMgYXMgYW55W10pLnB1c2goe1xuICAgICAgICBwcm92aWRlOiBBUFBfSU5URVJDRVBUT1IsXG4gICAgICAgIHVzZUV4aXN0aW5nOiBBdXRoSW50ZXJjZXB0b3IsXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICByZXR1cm4ge1xuICAgICAgbW9kdWxlOiBEZWNhZkF1dGhNb2R1bGUsXG4gICAgICBnbG9iYWw6IG9wdGlvbnMuZ2xvYmFsID8/IGZhbHNlLFxuICAgICAgcHJvdmlkZXJzLFxuICAgICAgZXhwb3J0czogW0F1dGhJbnRlcmNlcHRvciwgQXV0aE1pZGRsZXdhcmUsIEFVVEhfSEFORExFUl0sXG4gICAgfTtcbiAgfVxuXG4gIGNvbmZpZ3VyZShjb25zdW1lcjogTWlkZGxld2FyZUNvbnN1bWVyKSB7XG4gICAgY29uc3VtZXIuYXBwbHkoQXV0aE1pZGRsZXdhcmUpLmZvclJvdXRlcyh7IHBhdGg6IFwiKlwiLCBtZXRob2Q6IFJlcXVlc3RNZXRob2QuQUxMIH0pO1xuICB9XG59XG4iLCJpbXBvcnQgeyBJbmplY3QsIEluamVjdGFibGUsIFNjb3BlIH0gZnJvbSBcIkBuZXN0anMvY29tbW9uXCI7XG5pbXBvcnQgeyBEZWNhZlJlcXVlc3RDb250ZXh0IH0gZnJvbSBcIi4vRGVjYWZSZXF1ZXN0Q29udGV4dFwiO1xuaW1wb3J0IHsgdHlwZSBEZWNhZlJlcXVlc3RIYW5kbGVyIH0gZnJvbSBcIi4uL3R5cGVzXCI7XG5pbXBvcnQgeyBERUNBRl9IQU5ETEVSUyB9IGZyb20gXCIuLi9jb25zdGFudHNcIjtcbmltcG9ydCB7IExvZ2dpbmcgfSBmcm9tIFwiQGRlY2FmLXRzL2xvZ2dpbmdcIjtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb25cbiAqIEV4ZWN1dGVzIGFsbCByZWdpc3RlcmVkIHtAbGluayBEZWNhZlJlcXVlc3RIYW5kbGVyfSBpbnN0YW5jZXMgZm9yIHRoZSBjdXJyZW50IHJlcXVlc3QsXG4gKiBwcm92aWRpbmcgdGhlbSB3aXRoIGEgc2hhcmVkIHtAbGluayBEZWNhZlJlcXVlc3RDb250ZXh0fS5cbiAqXG4gKiBAc3VtbWFyeVxuICogVGhlIHtAbGluayBEZWNhZkhhbmRsZXJFeGVjdXRvcn0gY2xhc3MgaXMgcmVzcG9uc2libGUgZm9yIG9yY2hlc3RyYXRpbmcgYW5kIGV4ZWN1dGluZ1xuICogYSBzZXF1ZW5jZSBvZiByZXF1ZXN0IGhhbmRsZXJzLiBFYWNoIGhhbmRsZXIgcmVjZWl2ZXMgdGhlIHNhbWUgcmVxdWVzdC1zY29wZWQgY29udGV4dCxcbiAqIGFsbG93aW5nIGNvb3JkaW5hdGVkIHByb2Nlc3Npbmcgc3VjaCBhcyBhdXRoZW50aWNhdGlvbiwgbWV0YWRhdGEgZXh0cmFjdGlvbiwgYXVkaXRpbmcsXG4gKiBhbmQgY3VzdG9tIHBpcGVsaW5lIGJlaGF2aW9yLiBIYW5kbGVycyBhcmUgaW5qZWN0ZWQgdmlhIHRoZSB7QGxpbmsgREVDQUZfSEFORExFUlN9IHRva2VuLFxuICogZW5zdXJpbmcgZXh0ZW5zaWJpbGl0eSBhbmQgbG9vc2UgY291cGxpbmcuXG4gKlxuICogQGNsYXNzIERlY2FmSGFuZGxlckV4ZWN1dG9yXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHRzXG4gKiAvLyBFeGFtcGxlIGhhbmRsZXI6XG4gKiBjbGFzcyBBdXRoSGFuZGxlciBpbXBsZW1lbnRzIERlY2FmUmVxdWVzdEhhbmRsZXIge1xuICogICBhc3luYyBoYW5kbGUoY29udGV4dDogRGVjYWZSZXF1ZXN0Q29udGV4dCwgcmVxOiBSZXF1ZXN0KSB7XG4gKiAgICAgY29uc3QgdG9rZW4gPSByZXEuaGVhZGVyc1tcImF1dGhvcml6YXRpb25cIl07XG4gKiAgICAgY29uc3QgcmVzdWx0ID0gTXlTZXJ2aWNlLmRvU29tZXRoaW5nKHRva2VuKTtcbiAqICAgICBjb250ZXh0LnNldChcIm15LWtleVwiLCByZXN1bHQpO1xuICogICB9XG4gKiB9XG4gKlxuICogLy8gRXhlY3V0b3IgdXNhZ2UgaW4gYSByZXF1ZXN0OlxuICogYXdhaXQgZXhlY3V0b3IuZXhlYyhyZXF1ZXN0KTtcbiAqIC8vIEFsbCBoYW5kbGVycyB3aWxsIHJ1biBpbiBzZXF1ZW5jZVxuICogYGBgXG4gKlxuICogQG1lcm1haWRcbiAqIHNlcXVlbmNlRGlhZ3JhbVxuICogICAgIHBhcnRpY2lwYW50IENsaWVudFxuICogICAgIHBhcnRpY2lwYW50IEV4ZWN1dG9yXG4gKiAgICAgcGFydGljaXBhbnQgSGFuZGxlckFcbiAqICAgICBwYXJ0aWNpcGFudCBIYW5kbGVyQlxuICpcbiAqICAgICBDbGllbnQtPj5FeGVjdXRvcjogZXhlYyhyZXEpXG4gKiAgICAgRXhlY3V0b3ItPj5IYW5kbGVyQTogaGFuZGxlKGNvbnRleHQsIHJlcSlcbiAqICAgICBIYW5kbGVyQS0tPj5FeGVjdXRvcjogY29tcGxldGVkXG4gKiAgICAgRXhlY3V0b3ItPj5IYW5kbGVyQjogaGFuZGxlKGNvbnRleHQsIHJlcSlcbiAqICAgICBIYW5kbGVyQi0tPj5FeGVjdXRvcjogY29tcGxldGVkXG4gKiAgICAgRXhlY3V0b3ItLT4+Q2xpZW50OiBwcm9jZXNzaW5nIGZpbmlzaGVkXG4gKi9cbkBJbmplY3RhYmxlKHsgc2NvcGU6IFNjb3BlLlJFUVVFU1QgfSlcbmV4cG9ydCBjbGFzcyBEZWNhZkhhbmRsZXJFeGVjdXRvciB7XG4gIGNvbnN0cnVjdG9yKFxuICAgIEBJbmplY3QoREVDQUZfSEFORExFUlMpIHByaXZhdGUgcmVhZG9ubHkgaGFuZGxlcnM6IERlY2FmUmVxdWVzdEhhbmRsZXJbXSxcbiAgICBwcml2YXRlIHJlYWRvbmx5IGNvbnRleHQ6IERlY2FmUmVxdWVzdENvbnRleHRcbiAgKSB7fVxuXG4gIGFzeW5jIGV4ZWMocmVxOiBSZXF1ZXN0LCByZXM6IFJlc3BvbnNlKSB7XG4gICAgY29uc3QgbG9nID0gTG9nZ2luZy5mb3IoRGVjYWZIYW5kbGVyRXhlY3V0b3IubmFtZSkuZm9yKHRoaXMuZXhlYyk7XG4gICAgbG9nLmRlYnVnKFxuICAgICAgYENPTlRFWFQgJHt0aGlzLmNvbnRleHQudXVpZH0gcnVubmluZyAke3RoaXMuaGFuZGxlcnMubGVuZ3RofSBoYW5kbGVycyBmb3IgcmVxdWVzdCAke3JlcS5tZXRob2R9ICR7cmVxLnVybH1gXG4gICAgKTtcbiAgICBmb3IgKGNvbnN0IGhhbmRsZXIgb2YgdGhpcy5oYW5kbGVycykge1xuICAgICAgYXdhaXQgaGFuZGxlci5oYW5kbGUodGhpcy5jb250ZXh0LCByZXEsIHJlcyk7XG4gICAgfVxuICB9XG59XG4iLCJpbXBvcnQge1xuICBJbmplY3RhYmxlLFxuICBOZXN0SW50ZXJjZXB0b3IsXG4gIEV4ZWN1dGlvbkNvbnRleHQsXG4gIENhbGxIYW5kbGVyLFxufSBmcm9tIFwiQG5lc3Rqcy9jb21tb25cIjtcbmltcG9ydCB7IE9ic2VydmFibGUsIHRhcCB9IGZyb20gXCJyeGpzXCI7XG5pbXBvcnQgeyBEZWNhZlJlcXVlc3RDb250ZXh0IH0gZnJvbSBcIi4vRGVjYWZSZXF1ZXN0Q29udGV4dFwiO1xuXG5ASW5qZWN0YWJsZSgpXG5leHBvcnQgY2xhc3MgRGVjYWZSZXNwb25zZUludGVyY2VwdG9yIGltcGxlbWVudHMgTmVzdEludGVyY2VwdG9yIHtcbiAgY29uc3RydWN0b3IocHJvdGVjdGVkIGN0eDogRGVjYWZSZXF1ZXN0Q29udGV4dCkge31cblxuICBpbnRlcmNlcHQoY29udGV4dDogRXhlY3V0aW9uQ29udGV4dCwgbmV4dDogQ2FsbEhhbmRsZXIpOiBPYnNlcnZhYmxlPGFueT4ge1xuICAgIGxldCByZXNwb25zZSA9IGNvbnRleHQuc3dpdGNoVG9IdHRwKCkuZ2V0UmVzcG9uc2UoKTtcblxuICAgIHJldHVybiBuZXh0LmhhbmRsZSgpLnBpcGUoXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVudXNlZC12YXJzXG4gICAgICB0YXAoKGRhdGEpID0+IHtcbiAgICAgICAgcmVzcG9uc2UgPSB0aGlzLmN0eC50b1Jlc3BvbnNlKHJlc3BvbnNlKTtcbiAgICAgIH0pXG4gICAgKTtcbiAgfVxufVxuIiwiaW1wb3J0IHsgdHlwZSBSZXF1ZXN0IH0gZnJvbSBcImV4cHJlc3NcIjtcbmltcG9ydCB7IERlY2FmQ29udHJvbGxlciBhcyBIdHRwRGVjYWZDb250cm9sbGVyIH0gZnJvbSBcIkBkZWNhZi10cy9mb3ItaHR0cC9zZXJ2ZXJcIjtcbmltcG9ydCB7XG4gIENvbnRleHQsXG4gIE1vZGVsU2VydmljZSxcbiAgUmVwbyxcbiAgUmVwb3NpdG9yeSxcbiAgU2VydmljZSxcbn0gZnJvbSBcIkBkZWNhZi10cy9jb3JlXCI7XG5pbXBvcnQgeyBNb2RlbCwgdHlwZSBNb2RlbENvbnN0cnVjdG9yIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0b3ItdmFsaWRhdGlvblwiO1xuXG5pbXBvcnQgeyBEZWNhZlNlcnZlckN0eCB9IGZyb20gXCIuL2NvbnN0YW50c1wiO1xuaW1wb3J0IHsgRGVjYWZSZXF1ZXN0Q29udGV4dCB9IGZyb20gXCIuL3JlcXVlc3QvRGVjYWZSZXF1ZXN0Q29udGV4dFwiO1xuXG5leHBvcnQgYWJzdHJhY3QgY2xhc3MgRGVjYWZDb250cm9sbGVyPFxuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVudXNlZC12YXJzXG4gIENPTlRFWFQgZXh0ZW5kcyBEZWNhZlNlcnZlckN0eCA9IERlY2FmU2VydmVyQ3R4LFxuPiBleHRlbmRzIEh0dHBEZWNhZkNvbnRyb2xsZXI8UmVxdWVzdCwgYW55LCBEZWNhZlJlcXVlc3RDb250ZXh0PiB7XG4gIHByb3RlY3RlZCBjb25zdHJ1Y3RvcihcbiAgICBwcm90ZWN0ZWQgcmVhZG9ubHkgY2xpZW50Q29udGV4dDogRGVjYWZSZXF1ZXN0Q29udGV4dCxcbiAgICBfbmFtZTogc3RyaW5nXG4gICkge1xuICAgIHN1cGVyKGNsaWVudENvbnRleHQpO1xuICB9XG59XG5cbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBEZWNhZk1vZGVsQ29udHJvbGxlcjxcbiAgTSBleHRlbmRzIE1vZGVsPGJvb2xlYW4+LFxuICBDIGV4dGVuZHMgRGVjYWZTZXJ2ZXJDdHggPSBEZWNhZlNlcnZlckN0eCxcbj4gZXh0ZW5kcyBEZWNhZkNvbnRyb2xsZXI8Qz4ge1xuICBwcml2YXRlIF9wZXJzaXN0ZW5jZT86IFJlcG88TT4gfCBNb2RlbFNlcnZpY2U8TT47XG5cbiAgcHJvdGVjdGVkIGNvbnN0cnVjdG9yKFxuICAgIHByb3RlY3RlZCBvdmVycmlkZSByZWFkb25seSBjbGllbnRDb250ZXh0OiBEZWNhZlJlcXVlc3RDb250ZXh0LFxuICAgIF9uYW1lOiBzdHJpbmdcbiAgKSB7XG4gICAgc3VwZXIoY2xpZW50Q29udGV4dCwgX25hbWUpO1xuICB9XG5cbiAgYWJzdHJhY3QgZ2V0IGNsYXNzKCk6IE1vZGVsQ29uc3RydWN0b3I8TT47XG5cbiAgcGVyc2lzdGVuY2UoY3R4PzogQ29udGV4dDxhbnk+KTogUmVwbzxNPiB8IE1vZGVsU2VydmljZTxNPiB7XG4gICAgaWYgKCF0aGlzLl9wZXJzaXN0ZW5jZSlcbiAgICAgIHRyeSB7XG4gICAgICAgIHRoaXMuX3BlcnNpc3RlbmNlID0gU2VydmljZS5nZXQ8TW9kZWxTZXJ2aWNlPE0+Pih0aGlzLmNsYXNzKTtcbiAgICAgIH0gY2F0Y2gge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIHRoaXMuX3BlcnNpc3RlbmNlID0gTW9kZWxTZXJ2aWNlLmdldFNlcnZpY2UoXG4gICAgICAgICAgICB0aGlzLmNsYXNzXG4gICAgICAgICAgKSBhcyBNb2RlbFNlcnZpY2U8TT47XG4gICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgIHRoaXMuX3BlcnNpc3RlbmNlID0gUmVwb3NpdG9yeS5mb3JNb2RlbCh0aGlzLmNsYXNzKSBhcyBSZXBvPE0+O1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICBjb25zdCBhY3RpdmVDdHggPSBjdHggPz8gdGhpcy5jbGllbnRDb250ZXh0O1xuICAgIGNvbnN0IG92ZXJyaWRlcyA9IGFjdGl2ZUN0eC50b092ZXJyaWRlcygpO1xuXG4gICAgcmV0dXJuIGN0eFxuICAgICAgPyB0aGlzLl9wZXJzaXN0ZW5jZSBpbnN0YW5jZW9mIFJlcG9zaXRvcnlcbiAgICAgICAgPyB0aGlzLl9wZXJzaXN0ZW5jZS5vdmVycmlkZShvdmVycmlkZXMpXG4gICAgICAgIDogdGhpcy5fcGVyc2lzdGVuY2UuZm9yKG92ZXJyaWRlcylcbiAgICAgIDogdGhpcy5fcGVyc2lzdGVuY2U7XG4gIH1cbn1cbiIsImltcG9ydCB7XG4gIEJ1bGtDcnVkT3BlcmF0aW9uS2V5cyxcbiAgSW50ZXJuYWxFcnJvcixcbiAgT3BlcmF0aW9uS2V5cyxcbn0gZnJvbSBcIkBkZWNhZi10cy9kYi1kZWNvcmF0b3JzXCI7XG5pbXBvcnQgeyBDb25zdHJ1Y3RvciwgTWV0YWRhdGEgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRpb25cIjtcbmltcG9ydCB7IEFwaVByb3BlcnR5IH0gZnJvbSBcIi4uLy4uL292ZXJyaWRlcy9kZWNvcmF0aW9uXCI7XG5pbXBvcnQgeyBNb2RlbCwgVmFsaWRhdGlvbktleXMgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRvci12YWxpZGF0aW9uXCI7XG5pbXBvcnQgeyBUcmFuc2FjdGlvbk9wZXJhdGlvbktleXMgfSBmcm9tIFwiQGRlY2FmLXRzL2NvcmVcIjtcbmltcG9ydCB7IHRvUGFzY2FsQ2FzZSB9IGZyb20gXCJAZGVjYWYtdHMvbG9nZ2luZ1wiO1xuaW1wb3J0IHsgREVDT1JBVE9SUyB9IGZyb20gXCIuLi8uLi9vdmVycmlkZXMvY29uc3RhbnRzXCI7XG5cbmNvbnN0IGR0b0NhY2hlID0gbmV3IE1hcDxcbiAgT3BlcmF0aW9uS2V5cyxcbiAgV2Vha01hcDxDb25zdHJ1Y3Rvcjxhbnk+LCBDb25zdHJ1Y3Rvcjxhbnk+PlxuPigpO1xuXG4vKipcbiAqIEJ1aWxkcyBhIE5lc3QvU3dhZ2dlciBEVE8gY2xhc3MgZm9yIHRoZSBnaXZlbiBtb2RlbCBhbmQgQ1JVRCBvcGVyYXRpb24uXG4gKlxuICogUnVsZXM6XG4gKiAgLSBPbmx5IENSRUFURSBhbmQgVVBEQVRFIChhbmQgdGhlaXIgYnVsayB2YXJpYW50cykgcHJvZHVjZSBhIERUTztcbiAqICAgIGFsbCBvdGhlciBvcGVyYXRpb25zIHJldHVybiB0aGUgb3JpZ2luYWwgbW9kZWwgY2xhc3MgdW5jaGFuZ2VkLlxuICogIC0gQGdlbmVyYXRlZCgpIHByb3BlcnRpZXMgKGNyZWF0ZWRBdCwgdXBkYXRlZEF0LCBjcmVhdGVkQnksIHVwZGF0ZWRCeSxcbiAqICAgIHV1aWQsIHZlcnNpb24sIEBjb21wb3NlZCBwa3MsIOKApikgYXJlICoqbmV2ZXIqKiBleHBvc2VkIGluIGFueSBEVE8uXG4gKiAgLSBUaGUgQHBrKCkgcHJvcGVydHk6XG4gKiAgICAgIOKAoiBVUERBVEUg4oCTIGFsd2F5cyBpbmNsdWRlZC5cbiAqICAgICAg4oCiIENSRUFURSAg4oCTIGluY2x1ZGVkIG9ubHkgd2hlbiB0aGUgcGsgaXMgTk9UIGF1dG8tZ2VuZXJhdGVkXG4gKiAgICAgICAgICAgICAgICAgIChjaGVja2VkIHZpYSBNb2RlbC5wa1Byb3BzKCkuZ2VuZXJhdGVkIEFORCBNb2RlbC5nZW5lcmF0ZWQoKSkuXG4gKiAgLSBSZWxhdGlvbiBwcm9wZXJ0aWVzIChAb25lVG9PbmUsIEBvbmVUb01hbnksIOKApik6XG4gKiAgICAgIOKAoiBDUkVBVEUgIOKAkyBuZXN0ZWQgYXMgRHRvRm9yKENSRUFURSwgUmVsYXRlZE1vZGVsKS4gV2hlbiB0aGUgcmVsYXRpb25cbiAqICAgICAgICAgICAgICAgICAgY3JlYXRlcyBhIGNpcmN1bGFyIHJlZmVyZW5jZSAobW9kZWwgQSDihpIgbW9kZWwgQiDihpIgbW9kZWwgQSksXG4gKiAgICAgICAgICAgICAgICAgIHRoZSBiYWNrLXJlZmVyZW5jZSB1c2VzIHRoZSByZWxhdGVkIG1vZGVsJ3MgUEsgdHlwZVxuICogICAgICAgICAgICAgICAgICAoc3RyaW5nL2ludGVnZXIpIGluc3RlYWQgb2YgdGhlIGZ1bGwgRFRPIHRvIGJyZWFrIHRoZSBjeWNsZS5cbiAqICAgICAg4oCiIFVQREFURSAg4oCTIHVuaW9uIG9mIER0b0ZvcihVUERBVEUsIFJlbGF0ZWRNb2RlbCkgKipvcioqIHRoZVxuICogICAgICAgICAgICAgICAgICByZWxhdGVkIG1vZGVsJ3MgcHJpbWFyeS1rZXkgdHlwZSAoc3RyaW5nIC8gaW50ZWdlciksXG4gKiAgICAgICAgICAgICAgICAgIGV4cHJlc3NlZCBhcyBhIFN3YWdnZXIgb25lT2YuIENpcmN1bGFyIGJhY2stcmVmZXJlbmNlc1xuICogICAgICAgICAgICAgICAgICBvbWl0IHRoZSBEVE8gJHJlZiBhbmQgb25seSBpbmNsdWRlIHRoZSBQSyB0eXBlLlxuICpcbiAqIE1ldGFkYXRhLnByb3BlcnRpZXMoKSBub3cgcmV0dXJucyBBTEwgcHJvcGVydGllcyBhY3Jvc3MgdGhlIHByb3RvdHlwZSBjaGFpbixcbiAqIHNvIERUTyBpbmhlcml0YW5jZSBpcyBubyBsb25nZXIgbmVlZGVkOyBldmVyeSBEVE8gaXMgYSBmbGF0IGNsYXNzLlxuICovXG5leHBvcnQgZnVuY3Rpb24gRHRvRm9yPE0gZXh0ZW5kcyBNb2RlbD4oXG4gIG9wOiBPcGVyYXRpb25LZXlzLFxuICBtb2RlbDogQ29uc3RydWN0b3I8TT4sXG4gIHN0YWNrOiBTZXQ8Q29uc3RydWN0b3I8YW55Pj4gPSBuZXcgU2V0KClcbik6IENvbnN0cnVjdG9yPGFueT4ge1xuICBpZiAoIVRyYW5zYWN0aW9uT3BlcmF0aW9uS2V5cy5pbmNsdWRlcyhvcCkpIHtcbiAgICByZXR1cm4gbW9kZWw7XG4gIH1cblxuICBjb25zdCBjYWNoZSA9IGdldER0b0NhY2hlKG9wKTtcbiAgY29uc3QgY2FjaGVkID0gY2FjaGUuZ2V0KG1vZGVsKTtcbiAgaWYgKGNhY2hlZCkgcmV0dXJuIGNhY2hlZDtcblxuICBjb25zdCBpc1VwZGF0ZU9wID0gW1xuICAgIE9wZXJhdGlvbktleXMuVVBEQVRFLFxuICAgIEJ1bGtDcnVkT3BlcmF0aW9uS2V5cy5VUERBVEVfQUxMLFxuICBdLmluY2x1ZGVzKG9wIGFzIGFueSk7XG5cbiAgY2xhc3MgRHluYW1pY0RUTyB7fVxuICBjYWNoZS5zZXQobW9kZWwsIER5bmFtaWNEVE8pO1xuXG4gIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShEeW5hbWljRFRPLCBcIm5hbWVcIiwge1xuICAgIHZhbHVlOiBgJHt0b1Bhc2NhbENhc2UobW9kZWwubmFtZSl9JHt0b1Bhc2NhbENhc2Uob3ApfURUT2AsXG4gIH0pO1xuXG4gIGNvbnN0IHBrUHJvcCA9ICgoKSA9PiB7XG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiBNb2RlbC5wayhtb2RlbCk7XG4gICAgfSBjYXRjaCB7XG4gICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH1cbiAgfSkoKTtcblxuICBjb25zdCBwa1Byb3BzTWV0YWRhdGEgPSBwa1Byb3AgPyBNb2RlbC5wa1Byb3BzKG1vZGVsIGFzIGFueSkgOiB1bmRlZmluZWQ7XG4gIGNvbnN0IHBrRGVzaWduVHlwZSA9IHBrUHJvcFxuICAgID8gUmVmbGVjdC5nZXRNZXRhZGF0YShcImRlc2lnbjp0eXBlXCIsIG1vZGVsLnByb3RvdHlwZSwgcGtQcm9wIGFzIHN0cmluZylcbiAgICA6IHVuZGVmaW5lZDtcbiAgY29uc3QgcGtUeXBlSXNOdW1lcmljID1cbiAgICBwa0Rlc2lnblR5cGUgPT09IE51bWJlciB8fCBwa0Rlc2lnblR5cGUgPT09IEJpZ0ludDtcbiAgY29uc3QgcGtJc0dlbmVyYXRlZCA9XG4gICAgISFwa1Byb3BzTWV0YWRhdGE/LmdlbmVyYXRlZCB8fFxuICAgIChwa1Byb3BcbiAgICAgID8gTW9kZWwuZ2VuZXJhdGVkQnlTZXF1ZW5jZShtb2RlbCBhcyBhbnksIHBrUHJvcCBhcyBhbnkpIHx8XG4gICAgICAgIGlzUHJvcGVydHlHZW5lcmF0ZWRBY3Jvc3NJbmhlcml0YW5jZShtb2RlbCwgcGtQcm9wIGFzIHN0cmluZykgfHxcbiAgICAgICAgcGtUeXBlSXNOdW1lcmljXG4gICAgICA6IGZhbHNlKTtcblxuICBjb25zdCBhbGxQcm9wcyA9IEFycmF5LmZyb20obmV3IFNldChNZXRhZGF0YS5wcm9wZXJ0aWVzKG1vZGVsKSB8fCBbXSkpO1xuICBjb25zdCByZWxhdGlvbnMgPSBuZXcgU2V0PHN0cmluZz4oKE1vZGVsLnJlbGF0aW9ucyhtb2RlbCkgYXMgc3RyaW5nW10pIHx8IFtdKTtcbiAgY29uc3Qgc2NhbGFyUHJvcHM6IHN0cmluZ1tdID0gW107XG5cbiAgZm9yIChjb25zdCBwcm9wIG9mIGFsbFByb3BzKSB7XG4gICAgaWYgKCFwcm9wKSBjb250aW51ZTtcbiAgICBpZiAocmVsYXRpb25zLmhhcyhwcm9wKSkgY29udGludWU7XG5cbiAgICBpZiAocHJvcCA9PT0gcGtQcm9wICYmICFpc1VwZGF0ZU9wICYmIHBrSXNHZW5lcmF0ZWQpIGNvbnRpbnVlO1xuICAgIGlmIChwcm9wICE9PSBwa1Byb3AgJiYgaXNQcm9wZXJ0eUdlbmVyYXRlZEFjcm9zc0luaGVyaXRhbmNlKG1vZGVsLCBwcm9wKSlcbiAgICAgIGNvbnRpbnVlO1xuXG4gICAgc2NhbGFyUHJvcHMucHVzaChwcm9wKTtcbiAgfVxuXG4gIGZvciAoY29uc3QgcHJvcCBvZiBzY2FsYXJQcm9wcykge1xuICAgIGNvbnN0IHZhbGlkYXRpb24gPSBnZXRWYWxpZGF0aW9uQWNyb3NzSW5oZXJpdGFuY2UobW9kZWwsIHByb3ApO1xuICAgIGNvbnN0IGlzUmVxdWlyZWQgPSAhIXZhbGlkYXRpb24/LltWYWxpZGF0aW9uS2V5cy5SRVFVSVJFRF07XG4gICAgY29uc3QgdHlwZUhpbnQgPVxuICAgICAgZ2V0VHlwZUFjcm9zc0luaGVyaXRhbmNlKG1vZGVsLCBwcm9wKSA/P1xuICAgICAgUmVmbGVjdC5nZXRNZXRhZGF0YShcImRlc2lnbjp0eXBlXCIsIG1vZGVsLnByb3RvdHlwZSwgcHJvcCk7XG5cbiAgICBjb25zdCBhcGlPcHRpb25zOiBQYXJhbWV0ZXJzPHR5cGVvZiBBcGlQcm9wZXJ0eT5bMF0gPSB7XG4gICAgICByZXF1aXJlZDogaXNSZXF1aXJlZCxcbiAgICB9O1xuICAgIGlmICh0eXBlSGludCkgYXBpT3B0aW9ucy50eXBlID0gdHlwZUhpbnQ7XG5cbiAgICBBcGlQcm9wZXJ0eShhcGlPcHRpb25zKShEeW5hbWljRFRPLnByb3RvdHlwZSwgcHJvcCk7XG5cbiAgICBjb25zdCBkZXNpZ25UeXBlID1cbiAgICAgIFJlZmxlY3QuZ2V0TWV0YWRhdGEoXCJkZXNpZ246dHlwZVwiLCBtb2RlbC5wcm90b3R5cGUsIHByb3ApID8/IHR5cGVIaW50O1xuICAgIGlmICh0eXBlb2YgZGVzaWduVHlwZSAhPT0gXCJ1bmRlZmluZWRcIikge1xuICAgICAgUmVmbGVjdC5kZWZpbmVNZXRhZGF0YShcbiAgICAgICAgXCJkZXNpZ246dHlwZVwiLFxuICAgICAgICBkZXNpZ25UeXBlLFxuICAgICAgICBEeW5hbWljRFRPLnByb3RvdHlwZSxcbiAgICAgICAgcHJvcFxuICAgICAgKTtcbiAgICB9XG5cbiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkoRHluYW1pY0RUTy5wcm90b3R5cGUsIHByb3AsIHtcbiAgICAgIHZhbHVlOiB1bmRlZmluZWQsXG4gICAgICB3cml0YWJsZTogdHJ1ZSxcbiAgICAgIGVudW1lcmFibGU6IHRydWUsXG4gICAgICBjb25maWd1cmFibGU6IHRydWUsXG4gICAgfSk7XG4gIH1cblxuICBmb3IgKGNvbnN0IHJlbGF0aW9uIG9mIHJlbGF0aW9ucykge1xuICAgIGNvbnN0IHJlbGF0aW9uTWV0YSA9IE1ldGFkYXRhLnJlbGF0aW9ucyhtb2RlbCwgcmVsYXRpb24gYXMgYW55KTtcbiAgICBpZiAoIXJlbGF0aW9uTWV0YSkge1xuICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoYE1ldGFkYXRhIGZvciByZWxhdGlvbiAke3JlbGF0aW9ufSBub3QgZm91bmRgKTtcbiAgICB9XG5cbiAgICBsZXQgcmVsYXRpb25UeXBlOiBDb25zdHJ1Y3Rvcjxhbnk+IHwgdW5kZWZpbmVkID1cbiAgICAgIHJlbGF0aW9uTWV0YS5jbGFzcyBhcyBDb25zdHJ1Y3Rvcjxhbnk+O1xuICAgIGlmICh0eXBlb2YgcmVsYXRpb25UeXBlID09PSBcImZ1bmN0aW9uXCIgJiYgIXJlbGF0aW9uVHlwZS5uYW1lKSB7XG4gICAgICByZWxhdGlvblR5cGUgPSAocmVsYXRpb25UeXBlIGFzIGFueSkoKTtcbiAgICB9XG4gICAgaWYgKCFyZWxhdGlvblR5cGUgfHwgdHlwZW9mIHJlbGF0aW9uVHlwZSAhPT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihgVHlwZSBmb3IgcmVsYXRpb24gJHtyZWxhdGlvbn0gbm90IGZvdW5kYCk7XG4gICAgfVxuICAgIGlmICghTW9kZWwuZ2V0KHJlbGF0aW9uVHlwZS5uYW1lKSkge1xuICAgICAgY29udGludWU7XG4gICAgfVxuXG4gICAgY29uc3QgbWV0YSA9IE1ldGFkYXRhLnZhbGlkYXRpb25Gb3IobW9kZWwsIHJlbGF0aW9uIGFzIGFueSk7XG4gICAgY29uc3QgaXNBcnJheSA9ICEhKG1ldGEgYXMgYW55KT8uW1ZhbGlkYXRpb25LZXlzLkxJU1RdO1xuICAgIGNvbnN0IGlzUmVxdWlyZWQgPSAhIShtZXRhIGFzIGFueSk/LltWYWxpZGF0aW9uS2V5cy5SRVFVSVJFRF07XG5cbiAgICAvLyBEZXRlY3QgY2lyY3VsYXIgcmVmZXJlbmNlOiBpZiB0aGUgcmVsYXRlZCBtb2RlbCBpcyBhbHJlYWR5IGluIHRoZVxuICAgIC8vIHJlY3Vyc2lvbiBzdGFjaywgdXNlIHRoZSBQSyB0eXBlIGluc3RlYWQgb2YgdGhlIGZ1bGwgRFRPIHRvIGJyZWFrXG4gICAgLy8gdGhlIGN5Y2xlLiBUaGlzIHByZXZlbnRzIEBuZXN0anMvc3dhZ2dlcidzIFNjaGVtYU9iamVjdEZhY3RvcnkgZnJvbVxuICAgIC8vIGluZmluaXRlbHkgcmVjdXJzaW5nIHdoZW4gZXhwbG9yaW5nIHRoZSBzY2hlbWFzLlxuICAgIGNvbnN0IGlzQ2lyY3VsYXIgPSBzdGFjay5oYXMocmVsYXRpb25UeXBlKTtcblxuICAgIGlmIChpc0NpcmN1bGFyKSB7XG4gICAgICBjb25zdCBwa1R5cGVOYW1lID0gZ2V0UGtPcGVuQXBpVHlwZShyZWxhdGlvblR5cGUpO1xuICAgICAgYWRkUmVsYXRpb25Qa1JlZihEeW5hbWljRFRPLCByZWxhdGlvbiwgcGtUeXBlTmFtZSwgaXNBcnJheSwgaXNSZXF1aXJlZCk7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG5cbiAgICBjb25zdCByZWxhdGlvbkR0byA9IER0b0ZvcihvcCwgcmVsYXRpb25UeXBlLCBuZXcgU2V0KHN0YWNrKS5hZGQobW9kZWwpKTtcblxuICAgIGlmIChpc1VwZGF0ZU9wKSB7XG4gICAgICBhZGRSZWxhdGlvblVwZGF0ZShcbiAgICAgICAgRHluYW1pY0RUTyxcbiAgICAgICAgcmVsYXRpb24sXG4gICAgICAgIHJlbGF0aW9uVHlwZSxcbiAgICAgICAgcmVsYXRpb25EdG8sXG4gICAgICAgIGlzQXJyYXksXG4gICAgICAgIGlzUmVxdWlyZWRcbiAgICAgICk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGFkZFJlbGF0aW9uKER5bmFtaWNEVE8sIHJlbGF0aW9uLCByZWxhdGlvbkR0bywgaXNBcnJheSwgaXNSZXF1aXJlZCk7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIER5bmFtaWNEVE87XG59XG5cbmZ1bmN0aW9uIGFkZFJlbGF0aW9uKFxuICBEdG9DbGFzczogYW55LFxuICByZWxhdGlvbjogc3RyaW5nLFxuICByZWxhdGlvbkR0bzogYW55LFxuICBpc0FycmF5OiBib29sZWFuLFxuICBpc1JlcXVpcmVkOiBib29sZWFuXG4pOiB2b2lkIHtcbiAgY29uc3QgYXBpT3B0aW9uczogUGFyYW1ldGVyczx0eXBlb2YgQXBpUHJvcGVydHk+WzBdID0ge1xuICAgIHR5cGU6IHJlbGF0aW9uRHRvLFxuICAgIHJlcXVpcmVkOiBpc1JlcXVpcmVkLFxuICAgIGlzQXJyYXksXG4gIH07XG4gIEFwaVByb3BlcnR5KGFwaU9wdGlvbnMpKER0b0NsYXNzLnByb3RvdHlwZSwgcmVsYXRpb24pO1xuICBSZWZsZWN0LmRlZmluZU1ldGFkYXRhKFxuICAgIFwiZGVzaWduOnR5cGVcIixcbiAgICBpc0FycmF5ID8gQXJyYXkgOiByZWxhdGlvbkR0byxcbiAgICBEdG9DbGFzcy5wcm90b3R5cGUsXG4gICAgcmVsYXRpb25cbiAgKTtcbiAgT2JqZWN0LmRlZmluZVByb3BlcnR5KER0b0NsYXNzLnByb3RvdHlwZSwgcmVsYXRpb24sIHtcbiAgICB2YWx1ZTogdW5kZWZpbmVkLFxuICAgIHdyaXRhYmxlOiB0cnVlLFxuICAgIGVudW1lcmFibGU6IHRydWUsXG4gICAgY29uZmlndXJhYmxlOiB0cnVlLFxuICB9KTtcbn1cblxuLyoqXG4gKiBBZGRzIGEgcmVsYXRpb24gcHJvcGVydHkgdGhhdCB1c2VzIHRoZSBQSyB0eXBlIChzdHJpbmcvaW50ZWdlcikgaW5zdGVhZCBvZlxuICogYSBmdWxsIERUTyBjbGFzcy4gVXNlZCB0byBicmVhayBjaXJjdWxhciByZWZlcmVuY2VzIChlLmcuIEN1c3RvbWVyIOKGkiBPcmRlciDihpIgQ3VzdG9tZXIpLlxuICovXG5mdW5jdGlvbiBhZGRSZWxhdGlvblBrUmVmKFxuICBEdG9DbGFzczogYW55LFxuICByZWxhdGlvbjogc3RyaW5nLFxuICBwa1R5cGVOYW1lOiBzdHJpbmcsXG4gIGlzQXJyYXk6IGJvb2xlYW4sXG4gIGlzUmVxdWlyZWQ6IGJvb2xlYW5cbik6IHZvaWQge1xuICBjb25zdCBhcGlPcHRpb25zOiBQYXJhbWV0ZXJzPHR5cGVvZiBBcGlQcm9wZXJ0eT5bMF0gPSBpc0FycmF5XG4gICAgPyAoeyB0eXBlOiBcImFycmF5XCIsIGl0ZW1zOiB7IHR5cGU6IHBrVHlwZU5hbWUgfSwgcmVxdWlyZWQ6IGlzUmVxdWlyZWQgfSBhcyBhbnkpXG4gICAgOiAoeyB0eXBlOiBwa1R5cGVOYW1lID09PSBcImludGVnZXJcIiA/IE51bWJlciA6IFN0cmluZywgcmVxdWlyZWQ6IGlzUmVxdWlyZWQgfSBhcyBhbnkpO1xuICBBcGlQcm9wZXJ0eShhcGlPcHRpb25zKShEdG9DbGFzcy5wcm90b3R5cGUsIHJlbGF0aW9uKTtcbiAgUmVmbGVjdC5kZWZpbmVNZXRhZGF0YShcbiAgICBcImRlc2lnbjp0eXBlXCIsXG4gICAgaXNBcnJheSA/IEFycmF5IDogKHBrVHlwZU5hbWUgPT09IFwiaW50ZWdlclwiID8gTnVtYmVyIDogU3RyaW5nKSxcbiAgICBEdG9DbGFzcy5wcm90b3R5cGUsXG4gICAgcmVsYXRpb25cbiAgKTtcbiAgT2JqZWN0LmRlZmluZVByb3BlcnR5KER0b0NsYXNzLnByb3RvdHlwZSwgcmVsYXRpb24sIHtcbiAgICB2YWx1ZTogdW5kZWZpbmVkLFxuICAgIHdyaXRhYmxlOiB0cnVlLFxuICAgIGVudW1lcmFibGU6IHRydWUsXG4gICAgY29uZmlndXJhYmxlOiB0cnVlLFxuICB9KTtcbn1cblxuZnVuY3Rpb24gYWRkUmVsYXRpb25VcGRhdGUoXG4gIER0b0NsYXNzOiBhbnksXG4gIHJlbGF0aW9uOiBzdHJpbmcsXG4gIHJlbGF0aW9uVHlwZTogQ29uc3RydWN0b3I8YW55PixcbiAgcmVsYXRpb25EdG86IGFueSxcbiAgaXNBcnJheTogYm9vbGVhbixcbiAgaXNSZXF1aXJlZDogYm9vbGVhblxuKTogdm9pZCB7XG4gIGNvbnN0IGV4dHJhTW9kZWxzID1cbiAgICBSZWZsZWN0LmdldE1ldGFkYXRhKERFQ09SQVRPUlMuQVBJX0VYVFJBX01PREVMUywgRHRvQ2xhc3MpIHx8IFtdO1xuICBpZiAoIWV4dHJhTW9kZWxzLmluY2x1ZGVzKHJlbGF0aW9uRHRvKSkge1xuICAgIFJlZmxlY3QuZGVmaW5lTWV0YWRhdGEoXG4gICAgICBERUNPUkFUT1JTLkFQSV9FWFRSQV9NT0RFTFMsXG4gICAgICBbLi4uZXh0cmFNb2RlbHMsIHJlbGF0aW9uRHRvXSxcbiAgICAgIER0b0NsYXNzXG4gICAgKTtcbiAgfVxuXG4gIGNvbnN0IGR0b1JlZiA9IGAjL2NvbXBvbmVudHMvc2NoZW1hcy8ke3JlbGF0aW9uRHRvLm5hbWV9YDtcbiAgY29uc3QgcGtUeXBlTmFtZSA9IGdldFBrT3BlbkFwaVR5cGUocmVsYXRpb25UeXBlKTtcbiAgY29uc3Qgb25lT2ZJdGVtcyA9IFt7ICRyZWY6IGR0b1JlZiB9LCB7IHR5cGU6IHBrVHlwZU5hbWUgfV07XG5cbiAgY29uc3QgYXBpT3B0aW9uczogUGFyYW1ldGVyczx0eXBlb2YgQXBpUHJvcGVydHk+WzBdID0gaXNBcnJheVxuICAgID8gKHsgdHlwZTogXCJhcnJheVwiLCByZXF1aXJlZDogaXNSZXF1aXJlZCwgb25lT2Y6IG9uZU9mSXRlbXMgfSBhcyBhbnkpXG4gICAgOiAoeyB0eXBlOiBPYmplY3QsIHJlcXVpcmVkOiBpc1JlcXVpcmVkLCBvbmVPZjogb25lT2ZJdGVtcyB9IGFzIGFueSk7XG5cbiAgQXBpUHJvcGVydHkoYXBpT3B0aW9ucykoRHRvQ2xhc3MucHJvdG90eXBlLCByZWxhdGlvbik7XG4gIFJlZmxlY3QuZGVmaW5lTWV0YWRhdGEoXG4gICAgXCJkZXNpZ246dHlwZVwiLFxuICAgIGlzQXJyYXkgPyBBcnJheSA6IE9iamVjdCxcbiAgICBEdG9DbGFzcy5wcm90b3R5cGUsXG4gICAgcmVsYXRpb25cbiAgKTtcbiAgT2JqZWN0LmRlZmluZVByb3BlcnR5KER0b0NsYXNzLnByb3RvdHlwZSwgcmVsYXRpb24sIHtcbiAgICB2YWx1ZTogdW5kZWZpbmVkLFxuICAgIHdyaXRhYmxlOiB0cnVlLFxuICAgIGVudW1lcmFibGU6IHRydWUsXG4gICAgY29uZmlndXJhYmxlOiB0cnVlLFxuICB9KTtcbn1cblxuZnVuY3Rpb24gZ2V0UGtPcGVuQXBpVHlwZShyZWxhdGlvblR5cGU6IENvbnN0cnVjdG9yPGFueT4pOiBzdHJpbmcge1xuICB0cnkge1xuICAgIGNvbnN0IHBrUHJvcHNNZXRhZGF0YSA9IE1vZGVsLnBrUHJvcHMocmVsYXRpb25UeXBlIGFzIGFueSk7XG4gICAgY29uc3QgcGtUeXBlID0gcGtQcm9wc01ldGFkYXRhPy50eXBlO1xuICAgIGlmIChwa1R5cGUgPT09IE51bWJlciB8fCBwa1R5cGUgPT09IEJpZ0ludCkgcmV0dXJuIFwiaW50ZWdlclwiO1xuICAgIHJldHVybiBcInN0cmluZ1wiO1xuICB9IGNhdGNoIHtcbiAgICByZXR1cm4gXCJzdHJpbmdcIjtcbiAgfVxufVxuXG5mdW5jdGlvbiBpc1Byb3BlcnR5R2VuZXJhdGVkQWNyb3NzSW5oZXJpdGFuY2UoXG4gIG1vZGVsOiBDb25zdHJ1Y3Rvcjxhbnk+LFxuICBwcm9wOiBzdHJpbmdcbik6IGJvb2xlYW4ge1xuICBsZXQgY3VycmVudDogYW55ID0gbW9kZWw7XG4gIHdoaWxlIChjdXJyZW50ICYmIGN1cnJlbnQgIT09IE9iamVjdCAmJiBjdXJyZW50ICE9PSBGdW5jdGlvbikge1xuICAgIGlmIChNb2RlbC5nZW5lcmF0ZWQoY3VycmVudCwgcHJvcCBhcyBhbnkpKSByZXR1cm4gdHJ1ZTtcbiAgICBjdXJyZW50ID0gT2JqZWN0LmdldFByb3RvdHlwZU9mKGN1cnJlbnQpO1xuICB9XG4gIHJldHVybiBmYWxzZTtcbn1cblxuZnVuY3Rpb24gZ2V0VmFsaWRhdGlvbkFjcm9zc0luaGVyaXRhbmNlKFxuICBtb2RlbDogQ29uc3RydWN0b3I8YW55PixcbiAgcHJvcDogc3RyaW5nXG4pOiBSZWNvcmQ8c3RyaW5nLCBhbnk+IHwgdW5kZWZpbmVkIHtcbiAgbGV0IGN1cnJlbnQ6IGFueSA9IG1vZGVsO1xuICB3aGlsZSAoY3VycmVudCAmJiBjdXJyZW50ICE9PSBPYmplY3QgJiYgY3VycmVudCAhPT0gRnVuY3Rpb24pIHtcbiAgICBjb25zdCB2YWxpZGF0aW9uID0gTWV0YWRhdGEudmFsaWRhdGlvbkZvcihjdXJyZW50LCBwcm9wIGFzIGFueSk7XG4gICAgaWYgKHZhbGlkYXRpb24pIHJldHVybiB2YWxpZGF0aW9uIGFzIGFueTtcbiAgICBjdXJyZW50ID0gT2JqZWN0LmdldFByb3RvdHlwZU9mKGN1cnJlbnQpO1xuICB9XG4gIHJldHVybiB1bmRlZmluZWQ7XG59XG5cbmZ1bmN0aW9uIGdldFR5cGVBY3Jvc3NJbmhlcml0YW5jZShtb2RlbDogQ29uc3RydWN0b3I8YW55PiwgcHJvcDogc3RyaW5nKTogYW55IHtcbiAgbGV0IGN1cnJlbnQ6IGFueSA9IG1vZGVsO1xuICB3aGlsZSAoY3VycmVudCAmJiBjdXJyZW50ICE9PSBPYmplY3QgJiYgY3VycmVudCAhPT0gRnVuY3Rpb24pIHtcbiAgICBjb25zdCB0eXBlID0gTWV0YWRhdGEudHlwZShjdXJyZW50LCBwcm9wKTtcbiAgICBpZiAodHlwZSkgcmV0dXJuIHR5cGU7XG4gICAgY3VycmVudCA9IE9iamVjdC5nZXRQcm90b3R5cGVPZihjdXJyZW50KTtcbiAgfVxuICByZXR1cm4gdW5kZWZpbmVkO1xufVxuXG5mdW5jdGlvbiBnZXREdG9DYWNoZShcbiAgb3A6IE9wZXJhdGlvbktleXNcbik6IFdlYWtNYXA8Q29uc3RydWN0b3I8YW55PiwgQ29uc3RydWN0b3I8YW55Pj4ge1xuICBpZiAoIWR0b0NhY2hlLmhhcyhvcCkpIHtcbiAgICBkdG9DYWNoZS5zZXQob3AsIG5ldyBXZWFrTWFwKCkpO1xuICB9XG4gIHJldHVybiBkdG9DYWNoZS5nZXQob3ApITtcbn1cbiIsImltcG9ydCB7IENvbnN0cnVjdG9yLCBNZXRhZGF0YSB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdGlvblwiO1xuaW1wb3J0IHsgUmVxdWVzdFRvQ29udGV4dFRyYW5zZm9ybWVyIH0gZnJvbSBcIkBkZWNhZi10cy9mb3ItaHR0cC9zZXJ2ZXJcIjtcbmltcG9ydCB7IEFkYXB0ZXIsIENvbnRleHRPZiwgQ29udGV4dCB9IGZyb20gXCJAZGVjYWYtdHMvY29yZVwiO1xuXG4oQWRhcHRlciBhcyBhbnkpLnRyYW5zZm9ybWVyRm9yID0gZnVuY3Rpb24gdG9Db250ZXh0RmxhZ3M8XG4gIEEgZXh0ZW5kcyBBZGFwdGVyPGFueSwgYW55LCBhbnksIGFueT4sXG4+KGFkYXB0ZXI6IEEgfCBzdHJpbmcpOiBDb25zdHJ1Y3RvcjxSZXF1ZXN0VG9Db250ZXh0VHJhbnNmb3JtZXI8Q29udGV4dE9mPEE+Pj4ge1xuICBjb25zdCBhbGlhcyA9XG4gICAgdHlwZW9mIGFkYXB0ZXIgPT09IFwic3RyaW5nXCIgPyBhZGFwdGVyIDogKGFkYXB0ZXIuYWxpYXMgYXMgc3RyaW5nKTtcbiAgcmV0dXJuIE1ldGFkYXRhW1wiaW5uZXJHZXRcIl0oU3ltYm9sLmZvcihcInRyYW5zZm9ybWVyc1wiKSwgYWxpYXMpO1xufS5iaW5kKEFkYXB0ZXIpO1xuXG4oQWRhcHRlciBhcyBhbnkpLmZsYXZvdXJzVG9UcmFuc2Zvcm0gPSBmdW5jdGlvbiByZXF1ZXN0VHJhbnNmb3JtZXJzKCk6XG4gIHwgc3RyaW5nW11cbiAgfCB1bmRlZmluZWQge1xuICBjb25zdCBtZXRhID0gTWV0YWRhdGFbXCJpbm5lckdldFwiXShTeW1ib2wuZm9yKFwidHJhbnNmb3JtZXJzXCIpKTtcbiAgaWYgKCFtZXRhKSByZXR1cm4gdW5kZWZpbmVkO1xuICByZXR1cm4gT2JqZWN0LmtleXMobWV0YSk7XG59LmJpbmQoQWRhcHRlcik7XG5cbihDb250ZXh0IGFzIGFueSkucHJvdG90eXBlLnRvUmVzcG9uc2UgPSBmdW5jdGlvbiB0b1Jlc3BvbnNlPFxuICBSRVMgZXh0ZW5kcyB7IGhlYWRlcjogYW55IH0sXG4+KHRoaXM6IENvbnRleHQsIHJlczogUkVTKTogUkVTIHtcbiAgY29uc3QgcGVuZGluZyA9IHRoaXMucGVuZGluZygpO1xuICBpZiAocGVuZGluZykgcmVzLmhlYWRlcihcIngtcGVuZGluZy10YXNrXCIsIEpTT04uc3RyaW5naWZ5KHBlbmRpbmcpKTtcbiAgcmV0dXJuIHJlcztcbn07XG4iLCJpbXBvcnQgXCJAZGVjYWYtdHMvZGVjb3JhdG9yLXZhbGlkYXRpb25cIjtcbmltcG9ydCB7IENvbnN0cnVjdG9yIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0aW9uXCI7XG5pbXBvcnQgeyBNb2RlbEJ1aWxkZXIgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRvci12YWxpZGF0aW9uXCI7XG5pbXBvcnQgeyBBdXRoIH0gZnJvbSBcIi4uL2RlY2FmLW1vZGVsL2RlY29yYXRvcnMvZGVjb3JhdG9yc1wiO1xuXG5kZWNsYXJlIG1vZHVsZSBcIkBkZWNhZi10cy9kZWNvcmF0b3ItdmFsaWRhdGlvblwiIHtcbiAgZXhwb3J0IGludGVyZmFjZSBNb2RlbEJ1aWxkZXI8TT4ge1xuICAgIEF1dGgobW9kZWw6IHN0cmluZyB8IENvbnN0cnVjdG9yKTogTW9kZWxCdWlsZGVyPE0+O1xuICAgIGRlY29yYXRlQ2xhc3MoZGVjb3JhdG9yOiBDbGFzc0RlY29yYXRvcik6IE1vZGVsQnVpbGRlcjxNPjtcbiAgfVxufVxuXG5jb25zdCBwcm90b3R5cGUgPSBNb2RlbEJ1aWxkZXIucHJvdG90eXBlIGFzIE1vZGVsQnVpbGRlcjxhbnk+ICYge1xuICBBdXRoOiAobW9kZWw6IHN0cmluZyB8IENvbnN0cnVjdG9yKSA9PiBNb2RlbEJ1aWxkZXI8YW55Pjtcbn07XG5cbmlmICghcHJvdG90eXBlLmRlY29yYXRlQ2xhc3MpIHtcbiAgcHJvdG90eXBlLmRlY29yYXRlQ2xhc3MgPSBmdW5jdGlvbiAoZGVjb3JhdG9yOiBDbGFzc0RlY29yYXRvcikge1xuICAgIGlmICghKHRoaXMgYXMgYW55KS5fY2xhc3NEZWNvcmF0b3JzKSB7XG4gICAgICAodGhpcyBhcyBhbnkpLl9jbGFzc0RlY29yYXRvcnMgPSBbXTtcbiAgICB9XG4gICAgKHRoaXMgYXMgYW55KS5fY2xhc3NEZWNvcmF0b3JzLnB1c2goZGVjb3JhdG9yKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfTtcbn1cblxucHJvdG90eXBlLkF1dGggPSBmdW5jdGlvbiAobW9kZWw6IHN0cmluZyB8IENvbnN0cnVjdG9yKSB7XG4gIHJldHVybiB0aGlzLmRlY29yYXRlQ2xhc3MoQXV0aChtb2RlbCkpO1xufTtcblxuaWYgKCEocHJvdG90eXBlIGFzIGFueSkuX19oYXNDbGFzc0RlY29yYXRvclN1cHBvcnQpIHtcbiAgY29uc3Qgb3JpZ2luYWxCdWlsZCA9IHByb3RvdHlwZS5idWlsZDtcbiAgcHJvdG90eXBlLmJ1aWxkID0gZnVuY3Rpb24gKCkge1xuICAgIGxldCByZXN1bHQgPSBvcmlnaW5hbEJ1aWxkLmNhbGwodGhpcyk7XG4gICAgY29uc3QgZGVjb3JhdG9ycyA9ICh0aGlzIGFzIGFueSkuX2NsYXNzRGVjb3JhdG9ycztcbiAgICBpZiAoZGVjb3JhdG9ycz8ubGVuZ3RoKSB7XG4gICAgICBmb3IgKGNvbnN0IGRlY29yYXRvciBvZiBkZWNvcmF0b3JzKSB7XG4gICAgICAgIGNvbnN0IGRlY29yYXRlZCA9IGRlY29yYXRvcihyZXN1bHQgYXMgYW55KSBhcyB0eXBlb2YgcmVzdWx0IHwgdm9pZDtcbiAgICAgICAgaWYgKGRlY29yYXRlZCkge1xuICAgICAgICAgIHJlc3VsdCA9IGRlY29yYXRlZDtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9O1xuICAocHJvdG90eXBlIGFzIGFueSkuX19oYXNDbGFzc0RlY29yYXRvclN1cHBvcnQgPSB0cnVlO1xufVxuIiwiaW1wb3J0IHtcbiAgQ29udHJvbGxlcixcbiAgUGFyYW0sXG4gIFF1ZXJ5LFxuICBSZXNwb25zZSxcbiAgU2V0TWV0YWRhdGEsXG59IGZyb20gXCJAbmVzdGpzL2NvbW1vblwiO1xuaW1wb3J0IHtcbiAgQXBpQmFkUmVxdWVzdFJlc3BvbnNlLFxuICBBcGlCb2R5LFxuICBBcGlDcmVhdGVkUmVzcG9uc2UsXG4gIEFwaUV4dHJhTW9kZWxzLFxuICBBcGlOb0NvbnRlbnRSZXNwb25zZSxcbiAgQXBpTm90Rm91bmRSZXNwb25zZSxcbiAgQXBpT2tSZXNwb25zZSxcbiAgQXBpT3BlcmF0aW9uLFxuICBBcGlQYXJhbSxcbiAgQXBpUXVlcnksXG4gIEFwaVRhZ3MsXG4gIEFwaVVucHJvY2Vzc2FibGVFbnRpdHlSZXNwb25zZSxcbiAgZ2V0U2NoZW1hUGF0aCxcbn0gZnJvbSBcIkBuZXN0anMvc3dhZ2dlclwiO1xuaW1wb3J0IHtcbiAgTW9kZWxTZXJ2aWNlLFxuICBPcmRlckRpcmVjdGlvbixcbiAgUGVyc2lzdGVuY2VLZXlzLFxuICBQcmVwYXJlZFN0YXRlbWVudEtleXMsXG4gIHR5cGUgUmVwbyxcbiAgUmVwb3NpdG9yeSxcbiAgU2VydmljZSxcbn0gZnJvbSBcIkBkZWNhZi10cy9jb3JlXCI7XG5pbXBvcnQgeyBNb2RlbCwgTW9kZWxDb25zdHJ1Y3RvciB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdG9yLXZhbGlkYXRpb25cIjtcbmltcG9ydCB7IExvZ2dpbmcsIHRvS2ViYWJDYXNlIH0gZnJvbSBcIkBkZWNhZi10cy9sb2dnaW5nXCI7XG5pbXBvcnQge1xuICBEQktleXMsXG4gIEJhc2VFcnJvcixcbiAgSW50ZXJuYWxFcnJvcixcbiAgT3BlcmF0aW9uS2V5cyxcbn0gZnJvbSBcIkBkZWNhZi10cy9kYi1kZWNvcmF0b3JzXCI7XG5pbXBvcnQgeyBDb25zdHJ1Y3RvciwgTWV0YWRhdGEgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRpb25cIjtcbmltcG9ydCB7XG4gIEFwaU9wZXJhdGlvbkZyb21Nb2RlbCxcbiAgQXBpUGFyYW1zRnJvbU1vZGVsLFxuICB0eXBlIERlY2FmQXBpUHJvcGVydHksXG4gIERlY2FmQm9keSxcbiAgRGVjYWZRdWVyeSxcbn0gZnJvbSBcIi4vZGVjb3JhdG9yc1wiO1xuaW1wb3J0IHsgSHR0cFZlcmJUb0RlY29yYXRvciB9IGZyb20gXCIuL2RlY29yYXRvcnMvdXRpbHNcIjtcbmltcG9ydCB0eXBlIHsgSHR0cFZlcmJzIH0gZnJvbSBcIi4vZGVjb3JhdG9ycy90eXBlc1wiO1xuaW1wb3J0IHsgRGVjYWZSZXF1ZXN0Q29udGV4dCB9IGZyb20gXCIuLi9yZXF1ZXN0XCI7XG5pbXBvcnQgeyBERUNBRl9DT05UUk9MTEVSX0NPTkZJRywgREVDQUZfUk9VVEUgfSBmcm9tIFwiLi4vY29uc3RhbnRzXCI7XG5pbXBvcnQge1xuICBTS0lQX01PREVMX05BTUVTUEFDRVNfS0VZLFxuICBTS0lQX01PREVMX1JPTEVTX0tFWSxcbn0gZnJvbSBcIi4uL2F1dGgvY29uc3RhbnRzXCI7XG5pbXBvcnQge1xuICBBdXRoLFxuICBQdWJsaWMsXG4gIFJlcXVpcmVOYW1lc3BhY2VzLFxuICBSZXF1aXJlUm9sZXMsXG59IGZyb20gXCIuLi9hdXRoL2RlY29yYXRvcnNcIjtcbmltcG9ydCB7IENvbnRyb2xsZXJDb25zdHJ1Y3RvciB9IGZyb20gXCIuL3R5cGVzXCI7XG5pbXBvcnQgeyBEZWNhZk1vZGVsQ29udHJvbGxlciB9IGZyb20gXCIuLi9jb250cm9sbGVyc1wiO1xuaW1wb3J0IHsgRHRvRm9yIH0gZnJvbSBcIi4uL2ZhY3Rvcnkvb3BlbmFwaS9EdG9CdWlsZGVyXCI7XG5pbXBvcnQgXCIuLi9vdmVycmlkZXNcIjtcbmltcG9ydCB7XG4gIE1vZGVsQ29udHJvbGxlckZhY3RvcnksXG4gIHR5cGUgTW9kZWxDb250cm9sbGVyRmFjdG9yeUNvbmZpZyxcbiAgdHlwZSBBdXRoQ29uZmlnLFxuICB0eXBlIFNlcnZlclJvdXRlLFxufSBmcm9tIFwiQGRlY2FmLXRzL2Zvci1odHRwL3NlcnZlclwiO1xuXG5leHBvcnQgY2xhc3MgRnJvbU1vZGVsQ29udHJvbGxlciB7XG4gIHByaXZhdGUgc3RhdGljIHJlYWRvbmx5IGxvZyA9IExvZ2dpbmcuZm9yKEZyb21Nb2RlbENvbnRyb2xsZXIubmFtZSk7XG5cbiAgcHJpdmF0ZSBzdGF0aWMgdG9EZWNhZkVycm9yKFxuICAgIGVycm9yOiB1bmtub3duLFxuICAgIGZhbGxiYWNrTWVzc2FnZTogc3RyaW5nXG4gICk6IEJhc2VFcnJvciB7XG4gICAgaWYgKGVycm9yIGluc3RhbmNlb2YgQmFzZUVycm9yKSByZXR1cm4gZXJyb3I7XG4gICAgcmV0dXJuIG5ldyBJbnRlcm5hbEVycm9yKFxuICAgICAgZXJyb3IgaW5zdGFuY2VvZiBFcnJvclxuICAgICAgICA/IGAke2ZhbGxiYWNrTWVzc2FnZX06ICR7ZXJyb3IubWVzc2FnZX1gXG4gICAgICAgIDogZmFsbGJhY2tNZXNzYWdlXG4gICAgKTtcbiAgfVxuXG4gIHN0YXRpYyBnZXRQZXJzaXN0ZW5jZTxUIGV4dGVuZHMgTW9kZWw8Ym9vbGVhbj4+KFxuICAgIE1vZGVsQ2xheno6IE1vZGVsQ29uc3RydWN0b3I8VD5cbiAgKTogUmVwbzxUPiB8IE1vZGVsU2VydmljZTxUPiB7XG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiBTZXJ2aWNlLmdldDxNb2RlbFNlcnZpY2U8VD4+KE1vZGVsQ2xhenopO1xuICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIHJldHVybiBNb2RlbFNlcnZpY2UuZ2V0U2VydmljZShNb2RlbENsYXp6KSBhcyBNb2RlbFNlcnZpY2U8VD47XG4gICAgICB9IGNhdGNoIChlMjogdW5rbm93bikge1xuICAgICAgICByZXR1cm4gUmVwb3NpdG9yeS5mb3JNb2RlbChNb2RlbENsYXp6KSBhcyBSZXBvPFQ+O1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHN0YXRpYyBjcmVhdGVRdWVyeVJvdXRlc0Zyb21SZXBvc2l0b3J5PFQgZXh0ZW5kcyBNb2RlbDxib29sZWFuPj4oXG4gICAgcGVyc2lzdGVuY2U6IFJlcG88VD4gfCBNb2RlbFNlcnZpY2U8VD4sXG4gICAgcHJlZml4OiBzdHJpbmcgPSBQZXJzaXN0ZW5jZUtleXMuUVVFUllcbiAgKTogQ29udHJvbGxlckNvbnN0cnVjdG9yPFQ+IHtcbiAgICBjb25zdCByZXBvOiBSZXBvPFQ+ID1cbiAgICAgIHBlcnNpc3RlbmNlIGluc3RhbmNlb2YgTW9kZWxTZXJ2aWNlID8gcGVyc2lzdGVuY2UucmVwbyA6IHBlcnNpc3RlbmNlO1xuICAgIGNvbnN0IHF1ZXJ5TWV0aG9kczogUmVjb3JkPHN0cmluZywgeyBmaWVsZHM/OiBzdHJpbmdbXSB8IHVuZGVmaW5lZCB9PiA9XG4gICAgICBNZXRhZGF0YS5nZXQoXG4gICAgICAgIHJlcG8uY29uc3RydWN0b3IgYXMgQ29uc3RydWN0b3IsXG4gICAgICAgIE1ldGFkYXRhLmtleShQZXJzaXN0ZW5jZUtleXMuUVVFUlkpXG4gICAgICApID8/IHt9O1xuXG4gICAgY29uc3Qgcm91dGVNZXRob2RzOiBSZWNvcmQ8c3RyaW5nLCBhbnk+ID1cbiAgICAgIE1ldGFkYXRhLmdldChcbiAgICAgICAgcGVyc2lzdGVuY2UuY29uc3RydWN0b3IgYXMgQ29uc3RydWN0b3IsXG4gICAgICAgIE1ldGFkYXRhLmtleShERUNBRl9ST1VURSlcbiAgICAgICkgPz8ge307XG5cbiAgICBjbGFzcyBRdWVyeUNvbnRyb2xsZXIgZXh0ZW5kcyBEZWNhZk1vZGVsQ29udHJvbGxlcjxUPiB7XG4gICAgICBvdmVycmlkZSBnZXQgY2xhc3MoKTogTW9kZWxDb25zdHJ1Y3RvcjxUPiB7XG4gICAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFwiTWV0aG9kIG5vdCBpbXBsZW1lbnRlZC5cIik7XG4gICAgICB9XG4gICAgICBjb25zdHJ1Y3RvcihjbGllbnRDb250ZXh0OiBEZWNhZlJlcXVlc3RDb250ZXh0LCBuYW1lOiBzdHJpbmcpIHtcbiAgICAgICAgc3VwZXIoY2xpZW50Q29udGV4dCwgbmFtZSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgZm9yIChjb25zdCBbbWV0aG9kTmFtZSwgcGFyYW1zXSBvZiBPYmplY3QuZW50cmllcyhyb3V0ZU1ldGhvZHMpKSB7XG4gICAgICBjb25zdCByb3V0ZVBhdGggPSBbcGFyYW1zLnBhdGgucmVwbGFjZSgvXlxcLyt8XFwvKyQvZywgXCJcIildXG4gICAgICAgIC5maWx0ZXIoKHNlZ21lbnQ6IHN0cmluZykgPT4gc2VnbWVudCAmJiBzZWdtZW50LnRyaW0oKSlcbiAgICAgICAgLmpvaW4oXCIvXCIpO1xuXG4gICAgICBjb25zdCBoYW5kbGVyID0gRnJvbU1vZGVsQ29udHJvbGxlci5jcmVhdGVDb21wbGV4UXVlcnlIYW5kbGVyKFxuICAgICAgICBtZXRob2ROYW1lXG4gICAgICApIGFzIGFueTtcbiAgICAgIEZyb21Nb2RlbENvbnRyb2xsZXIuZGVmaW5lTWV0aG9kKFF1ZXJ5Q29udHJvbGxlciwgbWV0aG9kTmFtZSwgaGFuZGxlcik7XG5cbiAgICAgIGNvbnN0IGh0dHBEZWNvcmF0b3IgPSBIdHRwVmVyYlRvRGVjb3JhdG9yKHBhcmFtcy5odHRwTWV0aG9kIGFzIEh0dHBWZXJicykoXG4gICAgICAgIHJvdXRlUGF0aCB8fCB1bmRlZmluZWRcbiAgICAgICk7XG4gICAgICBjb25zdCBkZWNvcmF0b3JzID0gRnJvbU1vZGVsQ29udHJvbGxlci5nZXRRdWVyeURlY29yYXRvcnMoXG4gICAgICAgIG1ldGhvZE5hbWUsXG4gICAgICAgIHJvdXRlUGF0aCxcbiAgICAgICAgcGFyYW1zLmh0dHBNZXRob2RcbiAgICAgICk7XG4gICAgICBGcm9tTW9kZWxDb250cm9sbGVyLmFwcGx5RGVjb3JhdG9ycyhRdWVyeUNvbnRyb2xsZXIsIG1ldGhvZE5hbWUsIFtcbiAgICAgICAgaHR0cERlY29yYXRvcixcbiAgICAgICAgLi4uZGVjb3JhdG9ycyxcbiAgICAgIF0pO1xuICAgIH1cblxuICAgIGZvciAoY29uc3QgW21ldGhvZE5hbWUsIG9ialZhbHVlc10gb2YgT2JqZWN0LmVudHJpZXMocXVlcnlNZXRob2RzKSkge1xuICAgICAgY29uc3QgZmllbGRzID0gb2JqVmFsdWVzLmZpZWxkcyA/PyBbXTtcbiAgICAgIGNvbnN0IHJvdXRlUGF0aCA9IFtwcmVmaXgsIG1ldGhvZE5hbWUsIC4uLmZpZWxkcy5tYXAoKGYpID0+IGA6JHtmfWApXVxuICAgICAgICAuZmlsdGVyKChzZWdtZW50KSA9PiBzZWdtZW50ICYmIHNlZ21lbnQudHJpbSgpKVxuICAgICAgICAuam9pbihcIi9cIik7XG5cbiAgICAgIGNvbnN0IGhhbmRsZXIgPSBGcm9tTW9kZWxDb250cm9sbGVyLmNyZWF0ZUNvbXBsZXhRdWVyeUhhbmRsZXIoXG4gICAgICAgIG1ldGhvZE5hbWVcbiAgICAgICkgYXMgYW55O1xuICAgICAgRnJvbU1vZGVsQ29udHJvbGxlci5kZWZpbmVNZXRob2QoUXVlcnlDb250cm9sbGVyLCBtZXRob2ROYW1lLCBoYW5kbGVyKTtcblxuICAgICAgY29uc3QgaHR0cERlY29yYXRvciA9IEh0dHBWZXJiVG9EZWNvcmF0b3IoXCJHRVRcIiBhcyBIdHRwVmVyYnMpKFxuICAgICAgICByb3V0ZVBhdGggfHwgdW5kZWZpbmVkXG4gICAgICApO1xuICAgICAgY29uc3QgZGVjb3JhdG9ycyA9IEZyb21Nb2RlbENvbnRyb2xsZXIuZ2V0UXVlcnlEZWNvcmF0b3JzKFxuICAgICAgICBtZXRob2ROYW1lLFxuICAgICAgICByb3V0ZVBhdGgsXG4gICAgICAgIFwiR0VUXCIsXG4gICAgICAgIHRydWVcbiAgICAgICk7XG4gICAgICBGcm9tTW9kZWxDb250cm9sbGVyLmFwcGx5RGVjb3JhdG9ycyhRdWVyeUNvbnRyb2xsZXIsIG1ldGhvZE5hbWUsIFtcbiAgICAgICAgaHR0cERlY29yYXRvcixcbiAgICAgICAgLi4uZGVjb3JhdG9ycyxcbiAgICAgIF0pO1xuICAgIH1cblxuICAgIHJldHVybiBRdWVyeUNvbnRyb2xsZXI7XG4gIH1cblxuICBzdGF0aWMgY3JlYXRlPFQgZXh0ZW5kcyBNb2RlbDxhbnk+PihcbiAgICBNb2RlbENvbnN0cjogTW9kZWxDb25zdHJ1Y3RvcjxUPixcbiAgICBtb2R1bGVDb25maWdPdmVycmlkZXM/OiBSZWNvcmQ8c3RyaW5nLCBNb2RlbENvbnRyb2xsZXJGYWN0b3J5Q29uZmlnPixcbiAgICBnbG9iYWxEZWZhdWx0cz86IFBhcnRpYWw8TW9kZWxDb250cm9sbGVyRmFjdG9yeUNvbmZpZz5cbiAgKTogQ29udHJvbGxlckNvbnN0cnVjdG9yPFQ+IHtcbiAgICBjb25zdCBsb2cgPSBGcm9tTW9kZWxDb250cm9sbGVyLmxvZy5mb3IoRnJvbU1vZGVsQ29udHJvbGxlci5jcmVhdGUpO1xuICAgIGNvbnN0IHRhYmxlTmFtZSA9IE1vZGVsLnRhYmxlTmFtZShNb2RlbENvbnN0cik7XG4gICAgY29uc3Qgcm91dGVQYXRoID0gdG9LZWJhYkNhc2UodGFibGVOYW1lKTtcbiAgICBjb25zdCBtb2RlbENsYXp6TmFtZSA9IE1vZGVsQ29uc3RyLm5hbWU7XG4gICAgY29uc3QgcGVyc2lzdGVuY2UgPSBGcm9tTW9kZWxDb250cm9sbGVyLmdldFBlcnNpc3RlbmNlKE1vZGVsQ29uc3RyKTtcblxuICAgIC8vIFdoZW4gcGVyc2lzdGVuY2UgaXMgYSBNb2RlbFNlcnZpY2UsIHRoZSBAcXVlcnkvQHJvdXRlIG1ldGFkYXRhIGxpdmVzIG9uXG4gICAgLy8gdGhlIHVuZGVybHlpbmcgcmVwb3NpdG9yeSBjbGFzcyAoY3VzdG9tIHJlcG8pLCBub3Qgb24gTW9kZWxTZXJ2aWNlIGl0c2VsZi5cbiAgICAvLyBQYXNzIHRoZSByZXBvIHRvIHRoZSBmYWN0b3J5IHNvIGFkZENvbXBsZXhRdWVyaWVzKCkgY2FuIGRpc2NvdmVyIHRoZW0uXG4gICAgY29uc3QgZmFjdG9yeVBlcnNpc3RlbmNlID1cbiAgICAgIHBlcnNpc3RlbmNlIGluc3RhbmNlb2YgTW9kZWxTZXJ2aWNlID8gcGVyc2lzdGVuY2UucmVwbyA6IHBlcnNpc3RlbmNlO1xuXG4gICAgY29uc3QgZGVjb3JhdG9yQ29uZmlnID0gTWV0YWRhdGEuZ2V0KFxuICAgICAgTW9kZWxDb25zdHIsXG4gICAgICBNZXRhZGF0YS5rZXkoREVDQUZfQ09OVFJPTExFUl9DT05GSUcpXG4gICAgKSBhcyBNb2RlbENvbnRyb2xsZXJGYWN0b3J5Q29uZmlnIHwgdW5kZWZpbmVkO1xuICAgIGNvbnN0IG1vZHVsZU92ZXJyaWRlID0gbW9kdWxlQ29uZmlnT3ZlcnJpZGVzPy5bTW9kZWxDb25zdHIubmFtZV07XG4gICAgY29uc3QgbWVyZ2VkQ29uZmlnOiBNb2RlbENvbnRyb2xsZXJGYWN0b3J5Q29uZmlnID0ge1xuICAgICAgLi4uKGdsb2JhbERlZmF1bHRzIHx8IHt9KSxcbiAgICAgIC4uLihkZWNvcmF0b3JDb25maWcgfHwge30pLFxuICAgICAgLi4uKG1vZHVsZU92ZXJyaWRlIHx8IHt9KSxcbiAgICB9O1xuXG4gICAgY29uc3QgRmFjdG9yeUNvbnRyb2xsZXIgPSBNb2RlbENvbnRyb2xsZXJGYWN0b3J5LmNyZWF0ZTxUPihcbiAgICAgIE1vZGVsQ29uc3RyLFxuICAgICAgZmFjdG9yeVBlcnNpc3RlbmNlLFxuICAgICAgbWVyZ2VkQ29uZmlnXG4gICAgKTtcbiAgICBjb25zdCBmYWN0b3J5Um91dGVzID0gKEZhY3RvcnlDb250cm9sbGVyIGFzIGFueSkuX19yb3V0ZXNfXyBhc1xuICAgICAgfCBTZXJ2ZXJSb3V0ZVtdXG4gICAgICB8IHVuZGVmaW5lZDtcblxuICAgIGNvbnN0IHtcbiAgICAgIGdldFBLLFxuICAgICAgYXBpUHJvcGVydGllcyxcbiAgICAgIHBhdGg6IHBrUGF0aCxcbiAgICB9ID0gRnJvbU1vZGVsQ29udHJvbGxlci5nZXRSb3V0ZVBhcmFtZXRlcnNGcm9tTW9kZWwoTW9kZWxDb25zdHIpO1xuXG4gICAgbG9nLmRlYnVnKFxuICAgICAgYENyZWF0aW5nIGNvbnRyb2xsZXIgZm9yIG1vZGVsOiAke21vZGVsQ2xhenpOYW1lfSB3aXRoICR7ZmFjdG9yeVJvdXRlcz8ubGVuZ3RoID8/IDB9IGZhY3Rvcnkgcm91dGVzYFxuICAgICk7XG5cbiAgICBjb25zdCBhdXRoQ29uZmlnOiBBdXRoQ29uZmlnIHwgdW5kZWZpbmVkID0gbWVyZ2VkQ29uZmlnLmF1dGg7XG5cbiAgICBmdW5jdGlvbiBhcHBseUNsYXNzQXV0aCh0YXJnZXQ6IGFueSkge1xuICAgICAgaWYgKGF1dGhDb25maWc/LnB1YmxpYykge1xuICAgICAgICBQdWJsaWMoKSh0YXJnZXQpO1xuICAgICAgfSBlbHNlIGlmIChhdXRoQ29uZmlnPy5yb2xlcz8ubGVuZ3RoKSB7XG4gICAgICAgIFJlcXVpcmVSb2xlcyguLi5hdXRoQ29uZmlnLnJvbGVzKSh0YXJnZXQpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgQXV0aChNb2RlbENvbnN0cikodGFyZ2V0KTtcbiAgICAgIH1cbiAgICAgIGlmIChhdXRoQ29uZmlnPy5uYW1lc3BhY2VzPy5sZW5ndGgpIHtcbiAgICAgICAgUmVxdWlyZU5hbWVzcGFjZXMoLi4uYXV0aENvbmZpZy5uYW1lc3BhY2VzKSh0YXJnZXQpO1xuICAgICAgfVxuICAgICAgaWYgKGF1dGhDb25maWc/LnNraXBNb2RlbFJvbGVzKSB7XG4gICAgICAgIFNldE1ldGFkYXRhKFNLSVBfTU9ERUxfUk9MRVNfS0VZLCB0cnVlKSh0YXJnZXQpO1xuICAgICAgfVxuICAgICAgaWYgKGF1dGhDb25maWc/LnNraXBNb2RlbE5hbWVzcGFjZXMpIHtcbiAgICAgICAgU2V0TWV0YWRhdGEoU0tJUF9NT0RFTF9OQU1FU1BBQ0VTX0tFWSwgdHJ1ZSkodGFyZ2V0KTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBAQ29udHJvbGxlcihyb3V0ZVBhdGgpXG4gICAgQEFwaVRhZ3MobW9kZWxDbGF6ek5hbWUpXG4gICAgQEFwaUV4dHJhTW9kZWxzKE1vZGVsQ29uc3RyKVxuICAgIGNsYXNzIER5bmFtaWNNb2RlbENvbnRyb2xsZXIgZXh0ZW5kcyBEZWNhZk1vZGVsQ29udHJvbGxlcjxUPiB7XG4gICAgICBwcml2YXRlIHJlYWRvbmx5IHBrOiBzdHJpbmcgPSBNb2RlbC5wayhNb2RlbENvbnN0cikgYXMgc3RyaW5nO1xuXG4gICAgICBwcm90ZWN0ZWQgc3RhdGljIGdldCBjbGFzcygpIHtcbiAgICAgICAgcmV0dXJuIE1vZGVsQ29uc3RyO1xuICAgICAgfVxuXG4gICAgICBvdmVycmlkZSBnZXQgY2xhc3MoKTogTW9kZWxDb25zdHJ1Y3RvcjxUPiB7XG4gICAgICAgIHJldHVybiBNb2RlbENvbnN0cjtcbiAgICAgIH1cblxuICAgICAgY29uc3RydWN0b3IoY2xpZW50Q29udGV4dDogRGVjYWZSZXF1ZXN0Q29udGV4dCkge1xuICAgICAgICBzdXBlcihjbGllbnRDb250ZXh0LCBEeW5hbWljTW9kZWxDb250cm9sbGVyLm5hbWUpO1xuICAgICAgICBsb2cuaW5mbyhcbiAgICAgICAgICBgUmVnaXN0ZXJpbmcgZHluYW1pYyBjb250cm9sbGVyIGZvciBtb2RlbDogJHt0aGlzLmNsYXNzLm5hbWV9IHJvdXRlOiAvJHtyb3V0ZVBhdGh9YFxuICAgICAgICApO1xuICAgICAgfVxuICAgIH1cblxuICAgIGFwcGx5Q2xhc3NBdXRoKER5bmFtaWNNb2RlbENvbnRyb2xsZXIpO1xuXG4gICAgaWYgKGZhY3RvcnlSb3V0ZXMpIHtcbiAgICAgIGNvbnN0IHNvcnRlZFJvdXRlcyA9IFsuLi5mYWN0b3J5Um91dGVzXS5zb3J0KChhLCBiKSA9PiB7XG4gICAgICAgIGNvbnN0IGFTZWdtZW50cyA9IGEucGF0aC5zcGxpdChcIi9cIikuZmlsdGVyKEJvb2xlYW4pO1xuICAgICAgICBjb25zdCBiU2VnbWVudHMgPSBiLnBhdGguc3BsaXQoXCIvXCIpLmZpbHRlcihCb29sZWFuKTtcbiAgICAgICAgY29uc3QgYVBhcmFtQ291bnQgPSBhU2VnbWVudHMuZmlsdGVyKChzKSA9PiBzLnN0YXJ0c1dpdGgoXCI6XCIpKS5sZW5ndGg7XG4gICAgICAgIGNvbnN0IGJQYXJhbUNvdW50ID0gYlNlZ21lbnRzLmZpbHRlcigocykgPT4gcy5zdGFydHNXaXRoKFwiOlwiKSkubGVuZ3RoO1xuICAgICAgICBjb25zdCBhTGl0ZXJhbENvdW50ID0gYVNlZ21lbnRzLmxlbmd0aCAtIGFQYXJhbUNvdW50O1xuICAgICAgICBjb25zdCBiTGl0ZXJhbENvdW50ID0gYlNlZ21lbnRzLmxlbmd0aCAtIGJQYXJhbUNvdW50O1xuICAgICAgICBpZiAoYUxpdGVyYWxDb3VudCAhPT0gYkxpdGVyYWxDb3VudClcbiAgICAgICAgICByZXR1cm4gYkxpdGVyYWxDb3VudCAtIGFMaXRlcmFsQ291bnQ7XG4gICAgICAgIGlmIChhUGFyYW1Db3VudCAhPT0gYlBhcmFtQ291bnQpIHJldHVybiBhUGFyYW1Db3VudCAtIGJQYXJhbUNvdW50O1xuICAgICAgICByZXR1cm4gMDtcbiAgICAgIH0pO1xuXG4gICAgICBmb3IgKGNvbnN0IHJvdXRlIG9mIHNvcnRlZFJvdXRlcykge1xuICAgICAgICBjb25zdCBtZXRob2ROYW1lID1cbiAgICAgICAgICByb3V0ZS5pbXBsZW1lbnRhdGlvbj8ubmFtZSB8fCByb3V0ZS5tZXRob2QudG9Mb3dlckNhc2UoKTtcbiAgICAgICAgY29uc3QgcmVnaXN0cmF0aW9uID0gRnJvbU1vZGVsQ29udHJvbGxlci5tYXRjaFJvdXRlKFxuICAgICAgICAgIG1ldGhvZE5hbWUsXG4gICAgICAgICAgcm91dGUsXG4gICAgICAgICAgcGtQYXRoLFxuICAgICAgICAgIGFwaVByb3BlcnRpZXMsXG4gICAgICAgICAgZ2V0UEssXG4gICAgICAgICAgTW9kZWxDb25zdHIsXG4gICAgICAgICAgbW9kZWxDbGF6ek5hbWVcbiAgICAgICAgKTtcbiAgICAgICAgaWYgKCFyZWdpc3RyYXRpb24pIGNvbnRpbnVlO1xuXG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICBtZXRob2ROYW1lOiByZWdpc3RlcmVkTWV0aG9kTmFtZSxcbiAgICAgICAgICBoYW5kbGVyLFxuICAgICAgICAgIGRlY29yYXRvcnMsXG4gICAgICAgICAgcGFyYW1EZWNvcmF0b3JzLFxuICAgICAgICB9ID0gcmVnaXN0cmF0aW9uO1xuXG4gICAgICAgIGNvbnN0IGRlc2NyaXB0b3IgPSBGcm9tTW9kZWxDb250cm9sbGVyLmRlZmluZU1ldGhvZChcbiAgICAgICAgICBEeW5hbWljTW9kZWxDb250cm9sbGVyLFxuICAgICAgICAgIHJlZ2lzdGVyZWRNZXRob2ROYW1lLFxuICAgICAgICAgIGhhbmRsZXJcbiAgICAgICAgKTtcblxuICAgICAgICBpZiAoZGVzY3JpcHRvcikge1xuICAgICAgICAgIGNvbnN0IGh0dHBEZWNvcmF0b3IgPSBIdHRwVmVyYlRvRGVjb3JhdG9yKHJvdXRlLm1ldGhvZCBhcyBIdHRwVmVyYnMpKFxuICAgICAgICAgICAgcm91dGUucGF0aC5yZXBsYWNlKC9eXFwvK3xcXC8rJC9nLCBcIlwiKSB8fCB1bmRlZmluZWRcbiAgICAgICAgICApO1xuICAgICAgICAgIEZyb21Nb2RlbENvbnRyb2xsZXIuYXBwbHlEZWNvcmF0b3JzKFxuICAgICAgICAgICAgRHluYW1pY01vZGVsQ29udHJvbGxlcixcbiAgICAgICAgICAgIHJlZ2lzdGVyZWRNZXRob2ROYW1lLFxuICAgICAgICAgICAgW2h0dHBEZWNvcmF0b3IsIC4uLmRlY29yYXRvcnNdLFxuICAgICAgICAgICAgcGFyYW1EZWNvcmF0b3JzXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBEeW5hbWljTW9kZWxDb250cm9sbGVyIGFzIGFueTtcbiAgfVxuXG4gIHN0YXRpYyBnZXRSb3V0ZVBhcmFtZXRlcnNGcm9tTW9kZWw8VCBleHRlbmRzIE1vZGVsPGFueT4+KFxuICAgIE1vZGVsQ2xheno6IE1vZGVsQ29uc3RydWN0b3I8VD5cbiAgKToge1xuICAgIHBhdGg6IHN0cmluZztcbiAgICBkZXNjcmlwdGlvbjogc3RyaW5nO1xuICAgIGFwaVByb3BlcnRpZXM6IERlY2FmQXBpUHJvcGVydHlbXTtcbiAgICBnZXRQSzogKC4uLnBhcmFtczogQXJyYXk8c3RyaW5nIHwgbnVtYmVyPikgPT4gc3RyaW5nO1xuICB9IHtcbiAgICBjb25zdCBwayA9IE1vZGVsLnBrKE1vZGVsQ2xhenopIGFzIGtleW9mIE1vZGVsPGFueT47XG4gICAgY29uc3QgY29tcG9zZWQgPSBNZXRhZGF0YS5nZXQoXG4gICAgICBNb2RlbENsYXp6LFxuICAgICAgTWV0YWRhdGEua2V5KERCS2V5cy5DT01QT1NFRCwgcGspXG4gICAgKTtcbiAgICBjb25zdCBjb21wb3NlZEtleXMgPSBjb21wb3NlZD8uYXJncyA/PyBbXTtcblxuICAgIGNvbnN0IHVuaXF1ZUtleXMgPVxuICAgICAgQXJyYXkuaXNBcnJheShjb21wb3NlZEtleXMpICYmIGNvbXBvc2VkS2V5cy5sZW5ndGggPiAwXG4gICAgICAgID8gQXJyYXkuZnJvbShuZXcgU2V0KFsuLi5jb21wb3NlZEtleXNdKSlcbiAgICAgICAgOiBBcnJheS5mcm9tKG5ldyBTZXQoW3BrXSkpO1xuXG4gICAgY29uc3QgZGVzY3JpcHRpb24gPSBNZXRhZGF0YS5kZXNjcmlwdGlvbihNb2RlbENsYXp6KSA/PyBcIlwiO1xuICAgIGNvbnN0IHBhdGggPSBgOiR7dW5pcXVlS2V5cy5qb2luKFwiLzpcIil9YDtcbiAgICBjb25zdCBhcGlQcm9wZXJ0aWVzOiBEZWNhZkFwaVByb3BlcnR5W10gPSB1bmlxdWVLZXlzLm1hcCgoa2V5KSA9PiB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBuYW1lOiBrZXksXG4gICAgICAgIGRlc2NyaXB0aW9uOiBNZXRhZGF0YS5kZXNjcmlwdGlvbihNb2RlbENsYXp6LCBrZXkpLFxuICAgICAgICByZXF1aXJlZDogdHJ1ZSxcbiAgICAgICAgdHlwZTogU3RyaW5nLFxuICAgICAgfTtcbiAgICB9KTtcblxuICAgIHJldHVybiB7XG4gICAgICBwYXRoLFxuICAgICAgZGVzY3JpcHRpb24sXG4gICAgICBhcGlQcm9wZXJ0aWVzLFxuICAgICAgZ2V0UEs6ICguLi5wYXJhbXM6IEFycmF5PHN0cmluZyB8IG51bWJlcj4pID0+XG4gICAgICAgIGNvbXBvc2VkPy5zZXBhcmF0b3IgPyBwYXJhbXMuam9pbihjb21wb3NlZC5zZXBhcmF0b3IpIDogcGFyYW1zLmpvaW4oXCJcIiksXG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgc3RhdGljIHJvdXRlUGFyYW1EZWNvcmF0b3JzKFxuICAgIHBhdGg6IHN0cmluZ1xuICApOiBBcnJheTx7IGRlY29yYXRvcjogUGFyYW1ldGVyRGVjb3JhdG9yOyBpbmRleDogbnVtYmVyIH0+IHtcbiAgICBsZXQgcGFyYW1JbmRleCA9IDA7XG4gICAgcmV0dXJuIHBhdGhcbiAgICAgIC5zcGxpdChcIi9cIilcbiAgICAgIC5maWx0ZXIoQm9vbGVhbilcbiAgICAgIC5mbGF0TWFwKChzZWdtZW50KSA9PiB7XG4gICAgICAgIGlmIChzZWdtZW50LnN0YXJ0c1dpdGgoXCI6XCIpKSB7XG4gICAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICAgIHsgZGVjb3JhdG9yOiBQYXJhbShzZWdtZW50LnNsaWNlKDEpKSBhcyBhbnksIGluZGV4OiBwYXJhbUluZGV4KysgfSxcbiAgICAgICAgICBdO1xuICAgICAgICB9XG4gICAgICAgIGlmIChzZWdtZW50LnN0YXJ0c1dpdGgoXCIqXCIpKSB7XG4gICAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICAgIHsgZGVjb3JhdG9yOiBQYXJhbShzZWdtZW50LnNsaWNlKDEpKSBhcyBhbnksIGluZGV4OiBwYXJhbUluZGV4KysgfSxcbiAgICAgICAgICBdO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBbXTtcbiAgICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBzdGF0aWMgZGVmaW5lTWV0aG9kKFxuICAgIHRhcmdldDogYW55LFxuICAgIG1ldGhvZE5hbWU6IHN0cmluZyxcbiAgICBoYW5kbGVyOiAoLi4uYXJnczogYW55W10pID0+IGFueVxuICApOiBQcm9wZXJ0eURlc2NyaXB0b3IgfCB1bmRlZmluZWQge1xuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0YXJnZXQucHJvdG90eXBlIHx8IHRhcmdldCwgbWV0aG9kTmFtZSwge1xuICAgICAgdmFsdWU6IGhhbmRsZXIsXG4gICAgICB3cml0YWJsZTogZmFsc2UsXG4gICAgICBjb25maWd1cmFibGU6IHRydWUsXG4gICAgICBlbnVtZXJhYmxlOiBmYWxzZSxcbiAgICB9KTtcblxuICAgIHJldHVybiBPYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKFxuICAgICAgdGFyZ2V0LnByb3RvdHlwZSB8fCB0YXJnZXQsXG4gICAgICBtZXRob2ROYW1lXG4gICAgKTtcbiAgfVxuXG4gIHByaXZhdGUgc3RhdGljIGFwcGx5RGVjb3JhdG9ycyhcbiAgICB0YXJnZXQ6IGFueSxcbiAgICBtZXRob2ROYW1lOiBzdHJpbmcsXG4gICAgbWV0aG9kRGVjb3JhdG9yczogQXJyYXk8KHRhcmdldDogYW55LCBrZXk6IHN0cmluZywgZGVzYzogYW55KSA9PiB2b2lkPixcbiAgICBwYXJhbURlY29yYXRvcnM6IEFycmF5PHtcbiAgICAgIGRlY29yYXRvcjogUGFyYW1ldGVyRGVjb3JhdG9yO1xuICAgICAgaW5kZXg6IG51bWJlcjtcbiAgICB9PiA9IFtdXG4gICkge1xuICAgIGNvbnN0IHByb3RvID0gdGFyZ2V0Py5wcm90b3R5cGUgPz8gdGFyZ2V0O1xuICAgIGNvbnN0IGRlc2NyaXB0b3IgPSBPYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKHByb3RvLCBtZXRob2ROYW1lKTtcbiAgICBtZXRob2REZWNvcmF0b3JzLmZvckVhY2goKGQpID0+IGQocHJvdG8sIG1ldGhvZE5hbWUsIGRlc2NyaXB0b3IpKTtcbiAgICBwYXJhbURlY29yYXRvcnMuZm9yRWFjaCgoeyBkZWNvcmF0b3IsIGluZGV4IH0pID0+XG4gICAgICBkZWNvcmF0b3IocHJvdG8sIG1ldGhvZE5hbWUsIGluZGV4KVxuICAgICk7XG4gIH1cblxuICBwcml2YXRlIHN0YXRpYyBtYXRjaFJvdXRlKFxuICAgIG1ldGhvZE5hbWU6IHN0cmluZyxcbiAgICByb3V0ZTogU2VydmVyUm91dGUsXG4gICAgcGtQYXRoOiBzdHJpbmcsXG4gICAgYXBpUHJvcGVydGllczogRGVjYWZBcGlQcm9wZXJ0eVtdLFxuICAgIGdldFBLOiAoLi4ucDogQXJyYXk8c3RyaW5nIHwgbnVtYmVyPikgPT4gc3RyaW5nLFxuICAgIE1vZGVsQ29uc3RyOiBNb2RlbENvbnN0cnVjdG9yPGFueT4sXG4gICAgbW9kZWxDbGF6ek5hbWU6IHN0cmluZ1xuICApOlxuICAgIHwge1xuICAgICAgICBtZXRob2ROYW1lOiBzdHJpbmc7XG4gICAgICAgIGhhbmRsZXI6ICguLi5hcmdzOiBhbnlbXSkgPT4gYW55O1xuICAgICAgICBkZWNvcmF0b3JzOiBBcnJheTwodGFyZ2V0OiBhbnksIGtleTogc3RyaW5nLCBkZXNjOiBhbnkpID0+IHZvaWQ+O1xuICAgICAgICBwYXJhbURlY29yYXRvcnM6IEFycmF5PHtcbiAgICAgICAgICBkZWNvcmF0b3I6IFBhcmFtZXRlckRlY29yYXRvcjtcbiAgICAgICAgICBpbmRleDogbnVtYmVyO1xuICAgICAgICB9PjtcbiAgICAgIH1cbiAgICB8IHVuZGVmaW5lZCB7XG4gICAgY29uc3QgeyBtZXRob2QsIHBhdGggfSA9IHJvdXRlO1xuICAgIGNvbnN0IG5vcm1hbGl6ZWRQYXRoID0gcGF0aC5yZXBsYWNlKC9eXFwvK3xcXC8rJC9nLCBcIlwiKTtcbiAgICBjb25zdCBoYW5kbGVyID0gcm91dGUuaW1wbGVtZW50YXRpb24gYXMgKC4uLmFyZ3M6IGFueVtdKSA9PiBhbnk7XG5cbiAgICBpZiAobWV0aG9kID09PSBcIlBPU1RcIiAmJiBub3JtYWxpemVkUGF0aCA9PT0gXCJcIikge1xuICAgICAgcmV0dXJuIEZyb21Nb2RlbENvbnRyb2xsZXIuY3JlYXRlUmVnaXN0cmF0aW9uKFxuICAgICAgICBcImNyZWF0ZVwiLFxuICAgICAgICBoYW5kbGVyLFxuICAgICAgICBGcm9tTW9kZWxDb250cm9sbGVyLmNyZWF0ZUNyZWF0ZURlY29yYXRvcnMoTW9kZWxDb25zdHIsIG1vZGVsQ2xhenpOYW1lKSxcbiAgICAgICAgW1xuICAgICAgICAgIHsgZGVjb3JhdG9yOiBEZWNhZkJvZHkoKSBhcyBhbnksIGluZGV4OiAwIH0sXG4gICAgICAgICAgeyBkZWNvcmF0b3I6IFJlc3BvbnNlKHsgcGFzc3Rocm91Z2g6IHRydWUgfSkgYXMgYW55LCBpbmRleDogMSB9LFxuICAgICAgICBdXG4gICAgICApO1xuICAgIH1cblxuICAgIGlmIChtZXRob2QgPT09IFwiUE9TVFwiICYmIG5vcm1hbGl6ZWRQYXRoID09PSBcImJ1bGtcIikge1xuICAgICAgcmV0dXJuIEZyb21Nb2RlbENvbnRyb2xsZXIuY3JlYXRlUmVnaXN0cmF0aW9uKFxuICAgICAgICBcImNyZWF0ZUFsbFwiLFxuICAgICAgICBoYW5kbGVyLFxuICAgICAgICBGcm9tTW9kZWxDb250cm9sbGVyLmJ1bGtDcmVhdGVEZWNvcmF0b3JzKE1vZGVsQ29uc3RyLCBtb2RlbENsYXp6TmFtZSksXG4gICAgICAgIFtcbiAgICAgICAgICB7IGRlY29yYXRvcjogRGVjYWZCb2R5KCkgYXMgYW55LCBpbmRleDogMCB9LFxuICAgICAgICAgIHsgZGVjb3JhdG9yOiBSZXNwb25zZSh7IHBhc3N0aHJvdWdoOiB0cnVlIH0pIGFzIGFueSwgaW5kZXg6IDEgfSxcbiAgICAgICAgXVxuICAgICAgKTtcbiAgICB9XG5cbiAgICBpZiAobWV0aG9kID09PSBcIkdFVFwiICYmIG5vcm1hbGl6ZWRQYXRoID09PSBcImJ1bGtcIikge1xuICAgICAgcmV0dXJuIEZyb21Nb2RlbENvbnRyb2xsZXIuY3JlYXRlUmVnaXN0cmF0aW9uKFxuICAgICAgICBcInJlYWRBbGxcIixcbiAgICAgICAgaGFuZGxlcixcbiAgICAgICAgRnJvbU1vZGVsQ29udHJvbGxlci5idWxrUmVhZERlY29yYXRvcnMoTW9kZWxDb25zdHIsIG1vZGVsQ2xhenpOYW1lKSxcbiAgICAgICAgW3sgZGVjb3JhdG9yOiBRdWVyeShcImlkc1wiKSBhcyBhbnksIGluZGV4OiAwIH1dXG4gICAgICApO1xuICAgIH1cblxuICAgIGlmIChtZXRob2QgPT09IFwiUFVUXCIgJiYgbm9ybWFsaXplZFBhdGggPT09IFwiYnVsa1wiKSB7XG4gICAgICByZXR1cm4gRnJvbU1vZGVsQ29udHJvbGxlci5jcmVhdGVSZWdpc3RyYXRpb24oXG4gICAgICAgIFwidXBkYXRlQWxsXCIsXG4gICAgICAgIGhhbmRsZXIsXG4gICAgICAgIEZyb21Nb2RlbENvbnRyb2xsZXIuYnVsa1VwZGF0ZURlY29yYXRvcnMoXG4gICAgICAgICAgTW9kZWxDb25zdHIsXG4gICAgICAgICAgbW9kZWxDbGF6ek5hbWUsXG4gICAgICAgICAgYXBpUHJvcGVydGllc1xuICAgICAgICApLFxuICAgICAgICBbXG4gICAgICAgICAgeyBkZWNvcmF0b3I6IERlY2FmQm9keSgpIGFzIGFueSwgaW5kZXg6IDAgfSxcbiAgICAgICAgICB7IGRlY29yYXRvcjogUmVzcG9uc2UoeyBwYXNzdGhyb3VnaDogdHJ1ZSB9KSBhcyBhbnksIGluZGV4OiAxIH0sXG4gICAgICAgIF1cbiAgICAgICk7XG4gICAgfVxuXG4gICAgaWYgKG1ldGhvZCA9PT0gXCJERUxFVEVcIiAmJiBub3JtYWxpemVkUGF0aCA9PT0gXCJidWxrXCIpIHtcbiAgICAgIHJldHVybiBGcm9tTW9kZWxDb250cm9sbGVyLmNyZWF0ZVJlZ2lzdHJhdGlvbihcbiAgICAgICAgXCJkZWxldGVBbGxcIixcbiAgICAgICAgaGFuZGxlcixcbiAgICAgICAgRnJvbU1vZGVsQ29udHJvbGxlci5idWxrRGVsZXRlRGVjb3JhdG9ycyhcbiAgICAgICAgICBNb2RlbENvbnN0cixcbiAgICAgICAgICBtb2RlbENsYXp6TmFtZSxcbiAgICAgICAgICBhcGlQcm9wZXJ0aWVzXG4gICAgICAgICksXG4gICAgICAgIFtcbiAgICAgICAgICB7IGRlY29yYXRvcjogUXVlcnkoXCJpZHNcIikgYXMgYW55LCBpbmRleDogMCB9LFxuICAgICAgICAgIHsgZGVjb3JhdG9yOiBSZXNwb25zZSh7IHBhc3N0aHJvdWdoOiB0cnVlIH0pIGFzIGFueSwgaW5kZXg6IDEgfSxcbiAgICAgICAgXVxuICAgICAgKTtcbiAgICB9XG5cbiAgICBpZiAobWV0aG9kID09PSBcIkdFVFwiICYmIG5vcm1hbGl6ZWRQYXRoID09PSBwa1BhdGgpIHtcbiAgICAgIHJldHVybiBGcm9tTW9kZWxDb250cm9sbGVyLmNyZWF0ZVJlZ2lzdHJhdGlvbihcbiAgICAgICAgXCJyZWFkXCIsXG4gICAgICAgIGhhbmRsZXIsXG4gICAgICAgIEZyb21Nb2RlbENvbnRyb2xsZXIucmVhZERlY29yYXRvcnMoXG4gICAgICAgICAgTW9kZWxDb25zdHIsXG4gICAgICAgICAgbW9kZWxDbGF6ek5hbWUsXG4gICAgICAgICAgYXBpUHJvcGVydGllcyxcbiAgICAgICAgICBwa1BhdGhcbiAgICAgICAgKSxcbiAgICAgICAgRnJvbU1vZGVsQ29udHJvbGxlci5yb3V0ZVBhcmFtRGVjb3JhdG9ycyhub3JtYWxpemVkUGF0aClcbiAgICAgICk7XG4gICAgfVxuXG4gICAgaWYgKG1ldGhvZCA9PT0gXCJQVVRcIiAmJiBub3JtYWxpemVkUGF0aCA9PT0gcGtQYXRoKSB7XG4gICAgICBjb25zdCByb3V0ZVBhcmFtcyA9XG4gICAgICAgIEZyb21Nb2RlbENvbnRyb2xsZXIucm91dGVQYXJhbURlY29yYXRvcnMobm9ybWFsaXplZFBhdGgpO1xuICAgICAgcmV0dXJuIEZyb21Nb2RlbENvbnRyb2xsZXIuY3JlYXRlUmVnaXN0cmF0aW9uKFxuICAgICAgICBcInVwZGF0ZVwiLFxuICAgICAgICBoYW5kbGVyLFxuICAgICAgICBGcm9tTW9kZWxDb250cm9sbGVyLnVwZGF0ZURlY29yYXRvcnMoXG4gICAgICAgICAgTW9kZWxDb25zdHIsXG4gICAgICAgICAgbW9kZWxDbGF6ek5hbWUsXG4gICAgICAgICAgYXBpUHJvcGVydGllcyxcbiAgICAgICAgICBwa1BhdGhcbiAgICAgICAgKSxcbiAgICAgICAgW1xuICAgICAgICAgIHsgZGVjb3JhdG9yOiBEZWNhZkJvZHkoKSBhcyBhbnksIGluZGV4OiAwIH0sXG4gICAgICAgICAgLi4ucm91dGVQYXJhbXMubWFwKCh7IGRlY29yYXRvciwgaW5kZXggfSkgPT4gKHtcbiAgICAgICAgICAgIGRlY29yYXRvcixcbiAgICAgICAgICAgIGluZGV4OiBpbmRleCArIDEsXG4gICAgICAgICAgfSkpLFxuICAgICAgICBdXG4gICAgICApO1xuICAgIH1cblxuICAgIGlmIChtZXRob2QgPT09IFwiREVMRVRFXCIgJiYgbm9ybWFsaXplZFBhdGggPT09IHBrUGF0aCkge1xuICAgICAgY29uc3Qgcm91dGVQYXJhbXMgPVxuICAgICAgICBGcm9tTW9kZWxDb250cm9sbGVyLnJvdXRlUGFyYW1EZWNvcmF0b3JzKG5vcm1hbGl6ZWRQYXRoKTtcbiAgICAgIHJldHVybiBGcm9tTW9kZWxDb250cm9sbGVyLmNyZWF0ZVJlZ2lzdHJhdGlvbihcbiAgICAgICAgXCJkZWxldGVcIixcbiAgICAgICAgaGFuZGxlcixcbiAgICAgICAgRnJvbU1vZGVsQ29udHJvbGxlci5kZWxldGVEZWNvcmF0b3JzKFxuICAgICAgICAgIE1vZGVsQ29uc3RyLFxuICAgICAgICAgIG1vZGVsQ2xhenpOYW1lLFxuICAgICAgICAgIGFwaVByb3BlcnRpZXMsXG4gICAgICAgICAgcGtQYXRoXG4gICAgICAgICksXG4gICAgICAgIHJvdXRlUGFyYW1zXG4gICAgICApO1xuICAgIH1cblxuICAgIC8vIENvbXBvc2VkIFBLIGZhbGxiYWNrIHJvdXRlcyAoZmlsdGVyRW1wdHkpIOKAlCBwYXRoIGRpZmZlcnMgZnJvbSBwa1BhdGhcbiAgICBjb25zdCBmYWxsYmFja1NlZ21lbnRzID0gbm9ybWFsaXplZFBhdGguc3BsaXQoXCIvXCIpLmZpbHRlcihCb29sZWFuKTtcbiAgICBjb25zdCBpc0FsbFBhcmFtcyA9XG4gICAgICBmYWxsYmFja1NlZ21lbnRzLmxlbmd0aCA+IDAgJiZcbiAgICAgIGZhbGxiYWNrU2VnbWVudHMuZXZlcnkoKHMpID0+IHMuc3RhcnRzV2l0aChcIjpcIikpO1xuICAgIGlmIChpc0FsbFBhcmFtcyAmJiBub3JtYWxpemVkUGF0aCAhPT0gcGtQYXRoKSB7XG4gICAgICBjb25zdCBmYWxsYmFja0FwaVByb3BzID0gZmFsbGJhY2tTZWdtZW50c1xuICAgICAgICAubWFwKChzKSA9PiBzLnNsaWNlKDEpKVxuICAgICAgICAubWFwKChuYW1lKSA9PiAoe1xuICAgICAgICAgIG5hbWUsXG4gICAgICAgICAgZGVzY3JpcHRpb246IGAke25hbWV9IHBhcmFtZXRlcmAsXG4gICAgICAgICAgcmVxdWlyZWQ6IHRydWUsXG4gICAgICAgICAgdHlwZTogU3RyaW5nLFxuICAgICAgICB9KSk7XG4gICAgICBjb25zdCBzdWZmaXggPSBmYWxsYmFja1NlZ21lbnRzLm1hcCgocykgPT4gcy5zbGljZSgxKSkuam9pbihcIkFuZFwiKTtcbiAgICAgIGNvbnN0IHJvdXRlUGFyYW1zID1cbiAgICAgICAgRnJvbU1vZGVsQ29udHJvbGxlci5yb3V0ZVBhcmFtRGVjb3JhdG9ycyhub3JtYWxpemVkUGF0aCk7XG4gICAgICBpZiAobWV0aG9kID09PSBcIkdFVFwiKSB7XG4gICAgICAgIHJldHVybiBGcm9tTW9kZWxDb250cm9sbGVyLmNyZWF0ZVJlZ2lzdHJhdGlvbihcbiAgICAgICAgICBgcmVhZEJ5JHtzdWZmaXh9YCxcbiAgICAgICAgICBoYW5kbGVyLFxuICAgICAgICAgIEZyb21Nb2RlbENvbnRyb2xsZXIucmVhZERlY29yYXRvcnMoXG4gICAgICAgICAgICBNb2RlbENvbnN0cixcbiAgICAgICAgICAgIG1vZGVsQ2xhenpOYW1lLFxuICAgICAgICAgICAgZmFsbGJhY2tBcGlQcm9wcyxcbiAgICAgICAgICAgIG5vcm1hbGl6ZWRQYXRoXG4gICAgICAgICAgKSxcbiAgICAgICAgICByb3V0ZVBhcmFtc1xuICAgICAgICApO1xuICAgICAgfVxuICAgICAgaWYgKG1ldGhvZCA9PT0gXCJQVVRcIikge1xuICAgICAgICByZXR1cm4gRnJvbU1vZGVsQ29udHJvbGxlci5jcmVhdGVSZWdpc3RyYXRpb24oXG4gICAgICAgICAgYHVwZGF0ZUJ5JHtzdWZmaXh9YCxcbiAgICAgICAgICBoYW5kbGVyLFxuICAgICAgICAgIEZyb21Nb2RlbENvbnRyb2xsZXIudXBkYXRlRGVjb3JhdG9ycyhcbiAgICAgICAgICAgIE1vZGVsQ29uc3RyLFxuICAgICAgICAgICAgbW9kZWxDbGF6ek5hbWUsXG4gICAgICAgICAgICBmYWxsYmFja0FwaVByb3BzLFxuICAgICAgICAgICAgbm9ybWFsaXplZFBhdGhcbiAgICAgICAgICApLFxuICAgICAgICAgIFtcbiAgICAgICAgICAgIHsgZGVjb3JhdG9yOiBEZWNhZkJvZHkoKSBhcyBhbnksIGluZGV4OiAwIH0sXG4gICAgICAgICAgICAuLi5yb3V0ZVBhcmFtcy5tYXAoKHsgZGVjb3JhdG9yLCBpbmRleCB9KSA9PiAoe1xuICAgICAgICAgICAgICBkZWNvcmF0b3IsXG4gICAgICAgICAgICAgIGluZGV4OiBpbmRleCArIDEsXG4gICAgICAgICAgICB9KSksXG4gICAgICAgICAgXVxuICAgICAgICApO1xuICAgICAgfVxuICAgICAgaWYgKG1ldGhvZCA9PT0gXCJERUxFVEVcIikge1xuICAgICAgICByZXR1cm4gRnJvbU1vZGVsQ29udHJvbGxlci5jcmVhdGVSZWdpc3RyYXRpb24oXG4gICAgICAgICAgYGRlbGV0ZUJ5JHtzdWZmaXh9YCxcbiAgICAgICAgICBoYW5kbGVyLFxuICAgICAgICAgIEZyb21Nb2RlbENvbnRyb2xsZXIuZGVsZXRlRGVjb3JhdG9ycyhcbiAgICAgICAgICAgIE1vZGVsQ29uc3RyLFxuICAgICAgICAgICAgbW9kZWxDbGF6ek5hbWUsXG4gICAgICAgICAgICBmYWxsYmFja0FwaVByb3BzLFxuICAgICAgICAgICAgbm9ybWFsaXplZFBhdGhcbiAgICAgICAgICApLFxuICAgICAgICAgIHJvdXRlUGFyYW1zXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKG1ldGhvZCA9PT0gXCJHRVRcIiAmJiBub3JtYWxpemVkUGF0aCA9PT0gXCJzdGF0ZW1lbnQvOm1ldGhvZC8qYXJnc1wiKSB7XG4gICAgICByZXR1cm4gRnJvbU1vZGVsQ29udHJvbGxlci5jcmVhdGVSZWdpc3RyYXRpb24oXG4gICAgICAgIFwic3RhdGVtZW50XCIsXG4gICAgICAgIGhhbmRsZXIsXG4gICAgICAgIEZyb21Nb2RlbENvbnRyb2xsZXIuc3RhdGVtZW50RGVjb3JhdG9ycyhNb2RlbENvbnN0ciwgbW9kZWxDbGF6ek5hbWUpLFxuICAgICAgICBbXG4gICAgICAgICAgeyBkZWNvcmF0b3I6IFBhcmFtKFwibWV0aG9kXCIpIGFzIGFueSwgaW5kZXg6IDAgfSxcbiAgICAgICAgICB7IGRlY29yYXRvcjogUGFyYW0oXCJhcmdzXCIpIGFzIGFueSwgaW5kZXg6IDEgfSxcbiAgICAgICAgICB7IGRlY29yYXRvcjogRGVjYWZRdWVyeSgpIGFzIGFueSwgaW5kZXg6IDIgfSxcbiAgICAgICAgXVxuICAgICAgKTtcbiAgICB9XG5cbiAgICBpZiAobWV0aG9kID09PSBcIkdFVFwiICYmIG5vcm1hbGl6ZWRQYXRoID09PSBcImZpbmRPbmVCeS86a2V5Lzp2YWx1ZVwiKSB7XG4gICAgICByZXR1cm4gRnJvbU1vZGVsQ29udHJvbGxlci5jcmVhdGVSZWdpc3RyYXRpb24oXG4gICAgICAgIFwiZmluZE9uZUJ5XCIsXG4gICAgICAgIGhhbmRsZXIsXG4gICAgICAgIEZyb21Nb2RlbENvbnRyb2xsZXIuc3RhdGVtZW50U2hvcnRjdXREZWNvcmF0b3JzKFxuICAgICAgICAgIE1vZGVsQ29uc3RyLFxuICAgICAgICAgIG1vZGVsQ2xhenpOYW1lLFxuICAgICAgICAgIG5vcm1hbGl6ZWRQYXRoLFxuICAgICAgICAgIFByZXBhcmVkU3RhdGVtZW50S2V5cy5GSU5EX09ORV9CWVxuICAgICAgICApLFxuICAgICAgICBGcm9tTW9kZWxDb250cm9sbGVyLnN0YXRlbWVudFNob3J0Y3V0UGFyYW1zKG5vcm1hbGl6ZWRQYXRoKVxuICAgICAgKTtcbiAgICB9XG5cbiAgICBjb25zdCBzdGF0ZW1lbnRSb3V0ZXM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPSB7XG4gICAgICBcImxpc3RCeS86a2V5XCI6IFByZXBhcmVkU3RhdGVtZW50S2V5cy5MSVNUX0JZLFxuICAgICAgXCJwYWdpbmF0ZUJ5LzprZXkvOnBhZ2VcIjogUHJlcGFyZWRTdGF0ZW1lbnRLZXlzLlBBR0VfQlksXG4gICAgICBcImZpbmQvOnZhbHVlXCI6IFByZXBhcmVkU3RhdGVtZW50S2V5cy5GSU5ELFxuICAgICAgXCJwYWdlLzp2YWx1ZVwiOiBQcmVwYXJlZFN0YXRlbWVudEtleXMuUEFHRSxcbiAgICAgIFwiZmluZE9uZUJ5LzprZXkvOnZhbHVlXCI6IFByZXBhcmVkU3RhdGVtZW50S2V5cy5GSU5EX09ORV9CWSxcbiAgICAgIFwiZmluZEJ5LzprZXkvOnZhbHVlXCI6IFByZXBhcmVkU3RhdGVtZW50S2V5cy5GSU5EX0JZLFxuICAgICAgXCJjb3VudE9mLzpmaWVsZFwiOiBQcmVwYXJlZFN0YXRlbWVudEtleXMuQ09VTlRfT0YsXG4gICAgICBcIm1heE9mLzpmaWVsZFwiOiBQcmVwYXJlZFN0YXRlbWVudEtleXMuTUFYX09GLFxuICAgICAgXCJtaW5PZi86ZmllbGRcIjogUHJlcGFyZWRTdGF0ZW1lbnRLZXlzLk1JTl9PRixcbiAgICAgIFwiYXZnT2YvOmZpZWxkXCI6IFByZXBhcmVkU3RhdGVtZW50S2V5cy5BVkdfT0YsXG4gICAgICBcInN1bU9mLzpmaWVsZFwiOiBQcmVwYXJlZFN0YXRlbWVudEtleXMuU1VNX09GLFxuICAgICAgXCJkaXN0aW5jdE9mLzpmaWVsZFwiOiBQcmVwYXJlZFN0YXRlbWVudEtleXMuRElTVElOQ1RfT0YsXG4gICAgICBcImdyb3VwT2YvOmZpZWxkXCI6IFByZXBhcmVkU3RhdGVtZW50S2V5cy5HUk9VUF9PRixcbiAgICB9O1xuXG4gICAgY29uc3Qgc3RhdGVtZW50S2V5ID0gc3RhdGVtZW50Um91dGVzW25vcm1hbGl6ZWRQYXRoXTtcbiAgICBpZiAoc3RhdGVtZW50S2V5ICYmIG1ldGhvZCA9PT0gXCJHRVRcIikge1xuICAgICAgcmV0dXJuIEZyb21Nb2RlbENvbnRyb2xsZXIuY3JlYXRlUmVnaXN0cmF0aW9uKFxuICAgICAgICBGcm9tTW9kZWxDb250cm9sbGVyLnN0YXRlbWVudE1ldGhvZE5hbWUobm9ybWFsaXplZFBhdGgpLFxuICAgICAgICBoYW5kbGVyLFxuICAgICAgICBGcm9tTW9kZWxDb250cm9sbGVyLnN0YXRlbWVudFNob3J0Y3V0RGVjb3JhdG9ycyhcbiAgICAgICAgICBNb2RlbENvbnN0cixcbiAgICAgICAgICBtb2RlbENsYXp6TmFtZSxcbiAgICAgICAgICBub3JtYWxpemVkUGF0aCxcbiAgICAgICAgICBzdGF0ZW1lbnRLZXlcbiAgICAgICAgKSxcbiAgICAgICAgRnJvbU1vZGVsQ29udHJvbGxlci5zdGF0ZW1lbnRTaG9ydGN1dFBhcmFtcyhub3JtYWxpemVkUGF0aClcbiAgICAgICk7XG4gICAgfVxuXG4gICAgaWYgKG1ldGhvZCA9PT0gXCJHRVRcIiAmJiBub3JtYWxpemVkUGF0aC5zdGFydHNXaXRoKFwicXVlcnkvXCIpKSB7XG4gICAgICBjb25zdCBxdWVyeU1ldGhvZCA9IG5vcm1hbGl6ZWRQYXRoLnJlcGxhY2UoL15xdWVyeVxcLy8sIFwiXCIpLnNwbGl0KFwiL1wiKVswXTtcbiAgICAgIHJldHVybiBGcm9tTW9kZWxDb250cm9sbGVyLmNyZWF0ZVJlZ2lzdHJhdGlvbihcbiAgICAgICAgcXVlcnlNZXRob2QsXG4gICAgICAgIGhhbmRsZXIsXG4gICAgICAgIEZyb21Nb2RlbENvbnRyb2xsZXIuZ2V0UXVlcnlEZWNvcmF0b3JzKFxuICAgICAgICAgIHF1ZXJ5TWV0aG9kLFxuICAgICAgICAgIG5vcm1hbGl6ZWRQYXRoLFxuICAgICAgICAgIFwiR0VUXCIsXG4gICAgICAgICAgdHJ1ZVxuICAgICAgICApLFxuICAgICAgICBGcm9tTW9kZWxDb250cm9sbGVyLmNvbXBsZXhRdWVyeVBhcmFtcyhub3JtYWxpemVkUGF0aClcbiAgICAgICk7XG4gICAgfVxuXG4gICAgY29uc3QgcGF0aFNlZ21lbnRzID0gbm9ybWFsaXplZFBhdGguc3BsaXQoXCIvXCIpLmZpbHRlcihCb29sZWFuKTtcbiAgICBjb25zdCBrbm93blByZWZpeGVzID0gbmV3IFNldDxzdHJpbmc+KFtcbiAgICAgIFwibGlzdEJ5XCIsXG4gICAgICBcImZpbmRCeVwiLFxuICAgICAgXCJmaW5kQnlQYWdpbmF0ZVwiLFxuICAgICAgXCJmaW5kT25lQnlcIixcbiAgICAgIFwicGFnaW5hdGVCeVwiLFxuICAgICAgXCJmaW5kXCIsXG4gICAgICBcInBhZ2VcIixcbiAgICAgIFwiY291bnRPZlwiLFxuICAgICAgXCJtYXhPZlwiLFxuICAgICAgXCJtaW5PZlwiLFxuICAgICAgXCJhdmdPZlwiLFxuICAgICAgXCJzdW1PZlwiLFxuICAgICAgXCJkaXN0aW5jdE9mXCIsXG4gICAgICBcImdyb3VwT2ZcIixcbiAgICAgIFwic3RhdGVtZW50XCIsXG4gICAgICBcImJ1bGtcIixcbiAgICAgIFwicXVlcnlcIixcbiAgICBdKTtcbiAgICBpZiAoXG4gICAgICBwYXRoU2VnbWVudHMubGVuZ3RoID4gMCAmJlxuICAgICAgIW5vcm1hbGl6ZWRQYXRoLnN0YXJ0c1dpdGgoXCJxdWVyeS9cIikgJiZcbiAgICAgICFub3JtYWxpemVkUGF0aC5zdGFydHNXaXRoKFwic3RhdGVtZW50L1wiKSAmJlxuICAgICAgIWtub3duUHJlZml4ZXMuaGFzKHBhdGhTZWdtZW50c1swXSlcbiAgICApIHtcbiAgICAgIGNvbnN0IGFwaVBhdGhQYXJhbXMgPSBwYXRoU2VnbWVudHNcbiAgICAgICAgLmZpbHRlcigocykgPT4gcy5zdGFydHNXaXRoKFwiOlwiKSlcbiAgICAgICAgLm1hcCgocykgPT4gcy5zbGljZSgxKSlcbiAgICAgICAgLm1hcCgobmFtZSkgPT4gKHtcbiAgICAgICAgICBuYW1lLFxuICAgICAgICAgIGRlc2NyaXB0aW9uOiBgJHtuYW1lfSBwYXJhbWV0ZXIgZm9yIHRoZSBxdWVyeWAsXG4gICAgICAgICAgcmVxdWlyZWQ6IHRydWUsXG4gICAgICAgICAgdHlwZTogU3RyaW5nLFxuICAgICAgICB9KSk7XG5cbiAgICAgIHJldHVybiBGcm9tTW9kZWxDb250cm9sbGVyLmNyZWF0ZVJlZ2lzdHJhdGlvbihcbiAgICAgICAgbWV0aG9kTmFtZSxcbiAgICAgICAgaGFuZGxlcixcbiAgICAgICAgW1xuICAgICAgICAgIC4uLmFwaVBhdGhQYXJhbXMubWFwKChwKSA9PiBBcGlQYXJhbShwKSksXG4gICAgICAgICAgQXBpT3BlcmF0aW9uKHsgc3VtbWFyeTogYFJldHJpZXZlIHJlY29yZHMgdXNpbmcgXCIke21ldGhvZE5hbWV9XCIuYCB9KSxcbiAgICAgICAgICBBcGlPa1Jlc3BvbnNlKHsgZGVzY3JpcHRpb246IFwiUmVzdWx0IHN1Y2Nlc3NmdWxseSByZXRyaWV2ZWQuXCIgfSksXG4gICAgICAgICAgQXBpTm9Db250ZW50UmVzcG9uc2Uoe1xuICAgICAgICAgICAgZGVzY3JpcHRpb246IFwiTm8gY29udGVudCByZXR1cm5lZCBieSB0aGUgbWV0aG9kLlwiLFxuICAgICAgICAgIH0pLFxuICAgICAgICBdLFxuICAgICAgICBGcm9tTW9kZWxDb250cm9sbGVyLnJvdXRlUGFyYW1EZWNvcmF0b3JzKG5vcm1hbGl6ZWRQYXRoKVxuICAgICAgKTtcbiAgICB9XG5cbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG5cbiAgcHJpdmF0ZSBzdGF0aWMgY3JlYXRlUmVnaXN0cmF0aW9uKFxuICAgIG1ldGhvZE5hbWU6IHN0cmluZyxcbiAgICBoYW5kbGVyOiAoLi4uYXJnczogYW55W10pID0+IGFueSxcbiAgICBkZWNvcmF0b3JzOiBBcnJheTwodGFyZ2V0OiBhbnksIGtleTogc3RyaW5nLCBkZXNjOiBhbnkpID0+IHZvaWQ+LFxuICAgIHBhcmFtRGVjb3JhdG9yczogQXJyYXk8eyBkZWNvcmF0b3I6IFBhcmFtZXRlckRlY29yYXRvcjsgaW5kZXg6IG51bWJlciB9PlxuICApIHtcbiAgICByZXR1cm4geyBtZXRob2ROYW1lLCBoYW5kbGVyLCBkZWNvcmF0b3JzLCBwYXJhbURlY29yYXRvcnMgfTtcbiAgfVxuXG4gIHByaXZhdGUgc3RhdGljIHN0YXRlbWVudE1ldGhvZE5hbWUocGF0aDogc3RyaW5nKTogc3RyaW5nIHtcbiAgICBjb25zdCBmaXJzdFNlZ21lbnQgPSBwYXRoLnNwbGl0KFwiL1wiKVswXTtcbiAgICByZXR1cm4gZmlyc3RTZWdtZW50O1xuICB9XG5cbiAgcHJpdmF0ZSBzdGF0aWMgc3RhdGVtZW50U2hvcnRjdXRQYXJhbXMoXG4gICAgcGF0aDogc3RyaW5nXG4gICk6IEFycmF5PHsgZGVjb3JhdG9yOiBQYXJhbWV0ZXJEZWNvcmF0b3I7IGluZGV4OiBudW1iZXIgfT4ge1xuICAgIGNvbnN0IHNlZ21lbnRzID0gcGF0aC5zcGxpdChcIi9cIikuZmlsdGVyKChzKSA9PiBzLnN0YXJ0c1dpdGgoXCI6XCIpKTtcbiAgICBjb25zdCBwYXJhbXM6IEFycmF5PHsgZGVjb3JhdG9yOiBQYXJhbWV0ZXJEZWNvcmF0b3I7IGluZGV4OiBudW1iZXIgfT4gPSBbXTtcbiAgICBzZWdtZW50cy5mb3JFYWNoKChzZWcsIGkpID0+IHtcbiAgICAgIGNvbnN0IG5hbWUgPSBzZWcucmVwbGFjZShcIjpcIiwgXCJcIik7XG4gICAgICBwYXJhbXMucHVzaCh7IGRlY29yYXRvcjogUGFyYW0obmFtZSkgYXMgYW55LCBpbmRleDogaSB9KTtcbiAgICB9KTtcbiAgICBpZiAoXG4gICAgICBwYXRoLnN0YXJ0c1dpdGgoXCJsaXN0QnkvXCIpIHx8XG4gICAgICBwYXRoLnN0YXJ0c1dpdGgoXCJwYWdpbmF0ZUJ5L1wiKSB8fFxuICAgICAgcGF0aC5zdGFydHNXaXRoKFwiZmluZC9cIikgfHxcbiAgICAgIHBhdGguc3RhcnRzV2l0aChcInBhZ2UvXCIpXG4gICAgKSB7XG4gICAgICBwYXJhbXMucHVzaCh7IGRlY29yYXRvcjogRGVjYWZRdWVyeSgpIGFzIGFueSwgaW5kZXg6IHNlZ21lbnRzLmxlbmd0aCB9KTtcbiAgICB9XG4gICAgcmV0dXJuIHBhcmFtcztcbiAgfVxuXG4gIHByaXZhdGUgc3RhdGljIGNvbXBsZXhRdWVyeVBhcmFtcyhcbiAgICBwYXRoOiBzdHJpbmdcbiAgKTogQXJyYXk8eyBkZWNvcmF0b3I6IFBhcmFtZXRlckRlY29yYXRvcjsgaW5kZXg6IG51bWJlciB9PiB7XG4gICAgY29uc3Qgc2VnbWVudHMgPSBwYXRoLnNwbGl0KFwiL1wiKS5maWx0ZXIoKHMpID0+IHMuc3RhcnRzV2l0aChcIjpcIikpO1xuICAgIGNvbnN0IHBhcmFtczogQXJyYXk8eyBkZWNvcmF0b3I6IFBhcmFtZXRlckRlY29yYXRvcjsgaW5kZXg6IG51bWJlciB9PiA9IFtdO1xuICAgIHNlZ21lbnRzLmZvckVhY2goKHNlZywgaSkgPT4ge1xuICAgICAgY29uc3QgbmFtZSA9IHNlZy5yZXBsYWNlKFwiOlwiLCBcIlwiKTtcbiAgICAgIHBhcmFtcy5wdXNoKHsgZGVjb3JhdG9yOiBQYXJhbShuYW1lKSBhcyBhbnksIGluZGV4OiBpIH0pO1xuICAgIH0pO1xuICAgIGlmIChwYXRoLnN0YXJ0c1dpdGgoXCJxdWVyeS9cIikpIHtcbiAgICAgIHBhcmFtcy5wdXNoKHsgZGVjb3JhdG9yOiBEZWNhZlF1ZXJ5KCkgYXMgYW55LCBpbmRleDogc2VnbWVudHMubGVuZ3RoIH0pO1xuICAgIH1cbiAgICByZXR1cm4gcGFyYW1zO1xuICB9XG5cbiAgcHJpdmF0ZSBzdGF0aWMgY3JlYXRlQ29tcGxleFF1ZXJ5SGFuZGxlcihtZXRob2ROYW1lOiBzdHJpbmcpIHtcbiAgICByZXR1cm4gYXN5bmMgZnVuY3Rpb24gY29tcGxleFF1ZXJ5KFxuICAgICAgdGhpczogYW55LFxuICAgICAgLi4uYXJnczogYW55W11cbiAgICApOiBQcm9taXNlPGFueT4ge1xuICAgICAgY29uc3QgbG9nOiBhbnkgPSB0aGlzLmxvZz8uZm9yPy4oY29tcGxleFF1ZXJ5KTtcbiAgICAgIHRyeSB7XG4gICAgICAgIGlmIChsb2cpIGxvZy5kZWJ1ZyhgSW52b2tpbmcgY3VzdG9tIHF1ZXJ5IFwiJHttZXRob2ROYW1lfVwiYCk7XG4gICAgICAgIGNvbnN0IHsgY3R4IH0gPSAoYXdhaXQgdGhpcy5sb2dDdHgoW10sIG1ldGhvZE5hbWUsIHRydWUpKS5mb3IoXG4gICAgICAgICAgY29tcGxleFF1ZXJ5XG4gICAgICAgICk7XG4gICAgICAgIGNvbnN0IHBlcnNpc3RlbmNlID0gdGhpcy5wZXJzaXN0ZW5jZShjdHgpO1xuICAgICAgICBjb25zdCBzcHJlYWRBcmdzID0gRnJvbU1vZGVsQ29udHJvbGxlci5ub3JtYWxpemVRdWVyeUFyZ3MoYXJncyk7XG4gICAgICAgIGlmIChcbiAgICAgICAgICBwZXJzaXN0ZW5jZT8ucmVwbyAmJlxuICAgICAgICAgIHR5cGVvZiBwZXJzaXN0ZW5jZS5yZXBvW21ldGhvZE5hbWVdID09PSBcImZ1bmN0aW9uXCJcbiAgICAgICAgKSB7XG4gICAgICAgICAgcmV0dXJuIHBlcnNpc3RlbmNlLnJlcG9bbWV0aG9kTmFtZV0oLi4uc3ByZWFkQXJncyk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHR5cGVvZiBwZXJzaXN0ZW5jZVttZXRob2ROYW1lXSA9PT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICAgICAgcmV0dXJuIHBlcnNpc3RlbmNlW21ldGhvZE5hbWVdKC4uLnNwcmVhZEFyZ3MpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChwZXJzaXN0ZW5jZT8ucXVlcnkgJiYgdHlwZW9mIHBlcnNpc3RlbmNlLnF1ZXJ5ID09PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgICByZXR1cm4gcGVyc2lzdGVuY2UucXVlcnkobWV0aG9kTmFtZSwgLi4uc3ByZWFkQXJncyk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHR5cGVvZiBwZXJzaXN0ZW5jZS5zdGF0ZW1lbnQgPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICAgIHJldHVybiBwZXJzaXN0ZW5jZS5zdGF0ZW1lbnQobWV0aG9kTmFtZSwgLi4uc3ByZWFkQXJncywgY3R4KTtcbiAgICAgICAgfVxuICAgICAgICB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihcbiAgICAgICAgICBgUGVyc2lzdGVuY2UgbWV0aG9kIFwiJHttZXRob2ROYW1lfVwiIG5vdCBmb3VuZCBvbiAke3BlcnNpc3RlbmNlPy5jb25zdHJ1Y3Rvcj8ubmFtZX1gXG4gICAgICAgICk7XG4gICAgICB9IGNhdGNoIChlOiBhbnkpIHtcbiAgICAgICAgaWYgKGxvZykgbG9nLmVycm9yKGBDdXN0b20gcXVlcnkgXCIke21ldGhvZE5hbWV9XCIgZmFpbGVkYCwgZSk7XG4gICAgICAgIHRocm93IEZyb21Nb2RlbENvbnRyb2xsZXIudG9EZWNhZkVycm9yKFxuICAgICAgICAgIGUsXG4gICAgICAgICAgYEN1c3RvbSBxdWVyeSBcIiR7bWV0aG9kTmFtZX1cIiBmYWlsZWRgXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgc3RhdGljIGV4dHJhY3RRdWVyeUFyZ3MoYXJnczogYW55W10pOiBhbnlbXSB7XG4gICAgaWYgKGFyZ3MubGVuZ3RoID09PSAwKSByZXR1cm4gYXJncztcbiAgICBjb25zdCBsYXN0ID0gYXJnc1thcmdzLmxlbmd0aCAtIDFdO1xuICAgIGlmIChsYXN0ICYmIHR5cGVvZiBsYXN0ID09PSBcIm9iamVjdFwiICYmICFBcnJheS5pc0FycmF5KGxhc3QpKSB7XG4gICAgICBjb25zdCBxdWVyeU9iaiA9IGFyZ3MucG9wKCk7XG4gICAgICBjb25zdCBoYXNEaXJlY3Rpb24gPSBxdWVyeU9iai5kaXJlY3Rpb24gIT09IHVuZGVmaW5lZDtcbiAgICAgIGNvbnN0IGhhc0xpbWl0ID0gcXVlcnlPYmoubGltaXQgIT09IHVuZGVmaW5lZDtcbiAgICAgIGNvbnN0IGhhc09mZnNldCA9IHF1ZXJ5T2JqLm9mZnNldCAhPT0gdW5kZWZpbmVkO1xuICAgICAgaWYgKCFoYXNEaXJlY3Rpb24gJiYgIWhhc0xpbWl0ICYmICFoYXNPZmZzZXQpIHJldHVybiBhcmdzO1xuICAgICAgY29uc3QgZXh0cmFzOiBhbnlbXSA9IFtdO1xuICAgICAgaWYgKGhhc0RpcmVjdGlvbikgZXh0cmFzLnB1c2gocXVlcnlPYmouZGlyZWN0aW9uKTtcbiAgICAgIGVsc2UgaWYgKGhhc0xpbWl0IHx8IGhhc09mZnNldCkgZXh0cmFzLnB1c2godW5kZWZpbmVkKTtcbiAgICAgIGlmIChoYXNMaW1pdCkgZXh0cmFzLnB1c2gocXVlcnlPYmoubGltaXQpO1xuICAgICAgaWYgKGhhc09mZnNldCkgZXh0cmFzLnB1c2gocXVlcnlPYmoub2Zmc2V0KTtcbiAgICAgIHJldHVybiBbLi4uYXJncywgLi4uZXh0cmFzXTtcbiAgICB9XG4gICAgcmV0dXJuIGFyZ3M7XG4gIH1cblxuICBwcml2YXRlIHN0YXRpYyBub3JtYWxpemVRdWVyeUFyZ3MoYXJnczogYW55W10pOiBhbnlbXSB7XG4gICAgY29uc3Qgbm9ybWFsaXplZCA9IEZyb21Nb2RlbENvbnRyb2xsZXIuZXh0cmFjdFF1ZXJ5QXJncyhhcmdzKTtcbiAgICBpZiAobm9ybWFsaXplZC5sZW5ndGggPT09IDApIHJldHVybiBub3JtYWxpemVkO1xuXG4gICAgY29uc3QgbGFzdCA9IG5vcm1hbGl6ZWRbbm9ybWFsaXplZC5sZW5ndGggLSAxXTtcbiAgICBpZiAoIWxhc3QgfHwgdHlwZW9mIGxhc3QgIT09IFwib2JqZWN0XCIgfHwgQXJyYXkuaXNBcnJheShsYXN0KSkge1xuICAgICAgcmV0dXJuIG5vcm1hbGl6ZWQ7XG4gICAgfVxuXG4gICAgY29uc3QgcXVlcnlPYmogPSBsYXN0IGFzIFJlY29yZDxzdHJpbmcsIGFueT47XG4gICAgY29uc3QgaGFzUXVlcnlGaWVsZHMgPVxuICAgICAgcXVlcnlPYmouZGlyZWN0aW9uICE9PSB1bmRlZmluZWQgfHxcbiAgICAgIHF1ZXJ5T2JqLmxpbWl0ICE9PSB1bmRlZmluZWQgfHxcbiAgICAgIHF1ZXJ5T2JqLm9mZnNldCAhPT0gdW5kZWZpbmVkIHx8XG4gICAgICBxdWVyeU9iai5ib29rbWFyayAhPT0gdW5kZWZpbmVkO1xuXG4gICAgaWYgKCFoYXNRdWVyeUZpZWxkcykge1xuICAgICAgbm9ybWFsaXplZC5wb3AoKTtcbiAgICAgIHJldHVybiBub3JtYWxpemVkO1xuICAgIH1cblxuICAgIG5vcm1hbGl6ZWQucG9wKCk7XG4gICAgaWYgKHF1ZXJ5T2JqLmRpcmVjdGlvbiAhPT0gdW5kZWZpbmVkKSBub3JtYWxpemVkLnB1c2gocXVlcnlPYmouZGlyZWN0aW9uKTtcbiAgICBpZiAocXVlcnlPYmoubGltaXQgIT09IHVuZGVmaW5lZCkgbm9ybWFsaXplZC5wdXNoKHF1ZXJ5T2JqLmxpbWl0KTtcbiAgICBpZiAocXVlcnlPYmoub2Zmc2V0ICE9PSB1bmRlZmluZWQpIG5vcm1hbGl6ZWQucHVzaChxdWVyeU9iai5vZmZzZXQpO1xuICAgIGlmIChxdWVyeU9iai5ib29rbWFyayAhPT0gdW5kZWZpbmVkKSBub3JtYWxpemVkLnB1c2gocXVlcnlPYmouYm9va21hcmspO1xuICAgIHJldHVybiBub3JtYWxpemVkO1xuICB9XG5cbiAgcHJpdmF0ZSBzdGF0aWMgY3JlYXRlQ3JlYXRlRGVjb3JhdG9ycyhcbiAgICBNb2RlbENvbnN0cjogTW9kZWxDb25zdHJ1Y3Rvcjxhbnk+LFxuICAgIG1vZGVsQ2xhenpOYW1lOiBzdHJpbmdcbiAgKTogQXJyYXk8KHRhcmdldDogYW55LCBrZXk6IHN0cmluZywgZGVzYzogYW55KSA9PiB2b2lkPiB7XG4gICAgcmV0dXJuIFtcbiAgICAgIEFwaU9wZXJhdGlvbkZyb21Nb2RlbChNb2RlbENvbnN0ciwgXCJQT1NUXCIpLFxuICAgICAgQXBpT3BlcmF0aW9uKHsgc3VtbWFyeTogYENyZWF0ZSBhIG5ldyAke21vZGVsQ2xhenpOYW1lfS5gIH0pLFxuICAgICAgQXBpQm9keSh7XG4gICAgICAgIGRlc2NyaXB0aW9uOiBgUGF5bG9hZCBmb3IgJHttb2RlbENsYXp6TmFtZX1gLFxuICAgICAgICB0eXBlOiBEdG9Gb3IoT3BlcmF0aW9uS2V5cy5DUkVBVEUsIE1vZGVsQ29uc3RyKSxcbiAgICAgIH0pLFxuICAgICAgQXBpQ3JlYXRlZFJlc3BvbnNlKHtcbiAgICAgICAgZGVzY3JpcHRpb246IGAke21vZGVsQ2xhenpOYW1lfSBjcmVhdGVkIHN1Y2Nlc3NmdWxseS5gLFxuICAgICAgICBzY2hlbWE6IHsgJHJlZjogZ2V0U2NoZW1hUGF0aChNb2RlbENvbnN0cikgfSxcbiAgICAgIH0pLFxuICAgICAgQXBpQmFkUmVxdWVzdFJlc3BvbnNlKHsgZGVzY3JpcHRpb246IFwiUGF5bG9hZCB2YWxpZGF0aW9uIGZhaWxlZC5cIiB9KSxcbiAgICAgIEFwaVVucHJvY2Vzc2FibGVFbnRpdHlSZXNwb25zZSh7XG4gICAgICAgIGRlc2NyaXB0aW9uOiBcIlJlcG9zaXRvcnkgcmVqZWN0ZWQgdGhlIHByb3ZpZGVkIHBheWxvYWQuXCIsXG4gICAgICB9KSxcbiAgICBdO1xuICB9XG5cbiAgcHJpdmF0ZSBzdGF0aWMgYnVsa0NyZWF0ZURlY29yYXRvcnMoXG4gICAgTW9kZWxDb25zdHI6IE1vZGVsQ29uc3RydWN0b3I8YW55PixcbiAgICBtb2RlbENsYXp6TmFtZTogc3RyaW5nXG4gICk6IEFycmF5PCh0YXJnZXQ6IGFueSwga2V5OiBzdHJpbmcsIGRlc2M6IGFueSkgPT4gdm9pZD4ge1xuICAgIHJldHVybiBbXG4gICAgICBBcGlPcGVyYXRpb25Gcm9tTW9kZWwoTW9kZWxDb25zdHIsIFwiUE9TVFwiLCBcImJ1bGtcIiksXG4gICAgICBBcGlPcGVyYXRpb24oeyBzdW1tYXJ5OiBgQ3JlYXRlIGEgbmV3ICR7bW9kZWxDbGF6ek5hbWV9LmAgfSksXG4gICAgICBBcGlCb2R5KHtcbiAgICAgICAgZGVzY3JpcHRpb246IGBQYXlsb2FkIGZvciAke21vZGVsQ2xhenpOYW1lfWAsXG4gICAgICAgIHNjaGVtYToge1xuICAgICAgICAgIHR5cGU6IFwiYXJyYXlcIixcbiAgICAgICAgICBpdGVtczogeyAkcmVmOiBnZXRTY2hlbWFQYXRoKE1vZGVsQ29uc3RyKSB9LFxuICAgICAgICB9LFxuICAgICAgfSksXG4gICAgICBBcGlDcmVhdGVkUmVzcG9uc2Uoe1xuICAgICAgICBkZXNjcmlwdGlvbjogYCR7bW9kZWxDbGF6ek5hbWV9IGNyZWF0ZWQgc3VjY2Vzc2Z1bGx5LmAsXG4gICAgICAgIHNjaGVtYToge1xuICAgICAgICAgIHR5cGU6IFwiYXJyYXlcIixcbiAgICAgICAgICBpdGVtczogeyAkcmVmOiBnZXRTY2hlbWFQYXRoKE1vZGVsQ29uc3RyKSB9LFxuICAgICAgICB9LFxuICAgICAgfSksXG4gICAgICBBcGlCYWRSZXF1ZXN0UmVzcG9uc2UoeyBkZXNjcmlwdGlvbjogXCJQYXlsb2FkIHZhbGlkYXRpb24gZmFpbGVkLlwiIH0pLFxuICAgICAgQXBpVW5wcm9jZXNzYWJsZUVudGl0eVJlc3BvbnNlKHtcbiAgICAgICAgZGVzY3JpcHRpb246IFwiUmVwb3NpdG9yeSByZWplY3RlZCB0aGUgcHJvdmlkZWQgcGF5bG9hZC5cIixcbiAgICAgIH0pLFxuICAgIF07XG4gIH1cblxuICBwcml2YXRlIHN0YXRpYyBidWxrUmVhZERlY29yYXRvcnMoXG4gICAgTW9kZWxDb25zdHI6IE1vZGVsQ29uc3RydWN0b3I8YW55PixcbiAgICBtb2RlbENsYXp6TmFtZTogc3RyaW5nXG4gICk6IEFycmF5PCh0YXJnZXQ6IGFueSwga2V5OiBzdHJpbmcsIGRlc2M6IGFueSkgPT4gdm9pZD4ge1xuICAgIHJldHVybiBbXG4gICAgICBBcGlPcGVyYXRpb25Gcm9tTW9kZWwoTW9kZWxDb25zdHIsIFwiR0VUXCIsIFwiYnVsa1wiKSxcbiAgICAgIEFwaU9wZXJhdGlvbih7IHN1bW1hcnk6IGBSZXRyaWV2ZSAke21vZGVsQ2xhenpOYW1lfSByZWNvcmRzIGJ5IGlkcy5gIH0pLFxuICAgICAgQXBpUXVlcnkoeyBuYW1lOiBcImlkc1wiLCByZXF1aXJlZDogdHJ1ZSwgdHlwZTogXCJhcnJheVwiIH0pLFxuICAgICAgQXBpT2tSZXNwb25zZSh7XG4gICAgICAgIGRlc2NyaXB0aW9uOiBgJHttb2RlbENsYXp6TmFtZX0gcmV0cmlldmVkIHN1Y2Nlc3NmdWxseS5gLFxuICAgICAgICBzY2hlbWE6IHtcbiAgICAgICAgICB0eXBlOiBcImFycmF5XCIsXG4gICAgICAgICAgaXRlbXM6IHsgJHJlZjogZ2V0U2NoZW1hUGF0aChNb2RlbENvbnN0cikgfSxcbiAgICAgICAgfSxcbiAgICAgIH0pLFxuICAgICAgQXBpTm90Rm91bmRSZXNwb25zZSh7XG4gICAgICAgIGRlc2NyaXB0aW9uOiBgTm8gJHttb2RlbENsYXp6TmFtZX0gcmVjb3JkIG1hdGNoZXMgdGhlIHByb3ZpZGVkIGlkZW50aWZpZXIuYCxcbiAgICAgIH0pLFxuICAgIF07XG4gIH1cblxuICBwcml2YXRlIHN0YXRpYyBidWxrVXBkYXRlRGVjb3JhdG9ycyhcbiAgICBNb2RlbENvbnN0cjogTW9kZWxDb25zdHJ1Y3Rvcjxhbnk+LFxuICAgIG1vZGVsQ2xhenpOYW1lOiBzdHJpbmcsXG4gICAgYXBpUHJvcGVydGllczogRGVjYWZBcGlQcm9wZXJ0eVtdXG4gICk6IEFycmF5PCh0YXJnZXQ6IGFueSwga2V5OiBzdHJpbmcsIGRlc2M6IGFueSkgPT4gdm9pZD4ge1xuICAgIHJldHVybiBbXG4gICAgICBBcGlPcGVyYXRpb25Gcm9tTW9kZWwoTW9kZWxDb25zdHIsIFwiUFVUXCIsIFwiYnVsa1wiKSxcbiAgICAgIEFwaVBhcmFtc0Zyb21Nb2RlbChhcGlQcm9wZXJ0aWVzKSxcbiAgICAgIEFwaU9wZXJhdGlvbih7XG4gICAgICAgIHN1bW1hcnk6IGBSZXBsYWNlIGV4aXN0aW5nICR7bW9kZWxDbGF6ek5hbWV9IHJlY29yZHMgd2l0aCBuZXcgcGF5bG9hZHMuYCxcbiAgICAgIH0pLFxuICAgICAgQXBpQm9keSh7XG4gICAgICAgIGRlc2NyaXB0aW9uOiBgUGF5bG9hZCBmb3IgcmVwbGFjaW5nIGV4aXN0aW5nIHJlY29yZHMgb2YgJHttb2RlbENsYXp6TmFtZX1gLFxuICAgICAgICBzY2hlbWE6IHtcbiAgICAgICAgICB0eXBlOiBcImFycmF5XCIsXG4gICAgICAgICAgJHJlZjogZ2V0U2NoZW1hUGF0aChEdG9Gb3IoT3BlcmF0aW9uS2V5cy5VUERBVEUsIE1vZGVsQ29uc3RyKSksXG4gICAgICAgIH0sXG4gICAgICB9KSxcbiAgICAgIEFwaU9rUmVzcG9uc2Uoe1xuICAgICAgICBkZXNjcmlwdGlvbjogYCR7bW9kZWxDbGF6ek5hbWV9IHVwZGF0ZWQgc3VjY2Vzc2Z1bGx5LmAsXG4gICAgICAgIHNjaGVtYToge1xuICAgICAgICAgIHR5cGU6IFwiYXJyYXlcIixcbiAgICAgICAgICBpdGVtczogeyAkcmVmOiBnZXRTY2hlbWFQYXRoKE1vZGVsQ29uc3RyKSB9LFxuICAgICAgICB9LFxuICAgICAgfSksXG4gICAgICBBcGlOb3RGb3VuZFJlc3BvbnNlKHtcbiAgICAgICAgZGVzY3JpcHRpb246IGBObyAke21vZGVsQ2xhenpOYW1lfSByZWNvcmQgbWF0Y2hlcyB0aGUgcHJvdmlkZWQgaWRlbnRpZmllci5gLFxuICAgICAgfSksXG4gICAgICBBcGlCYWRSZXF1ZXN0UmVzcG9uc2UoeyBkZXNjcmlwdGlvbjogXCJQYXlsb2FkIHZhbGlkYXRpb24gZmFpbGVkLlwiIH0pLFxuICAgIF07XG4gIH1cblxuICBwcml2YXRlIHN0YXRpYyBidWxrRGVsZXRlRGVjb3JhdG9ycyhcbiAgICBNb2RlbENvbnN0cjogTW9kZWxDb25zdHJ1Y3Rvcjxhbnk+LFxuICAgIG1vZGVsQ2xhenpOYW1lOiBzdHJpbmcsXG4gICAgYXBpUHJvcGVydGllczogRGVjYWZBcGlQcm9wZXJ0eVtdXG4gICk6IEFycmF5PCh0YXJnZXQ6IGFueSwga2V5OiBzdHJpbmcsIGRlc2M6IGFueSkgPT4gdm9pZD4ge1xuICAgIHJldHVybiBbXG4gICAgICBBcGlPcGVyYXRpb25Gcm9tTW9kZWwoTW9kZWxDb25zdHIsIFwiREVMRVRFXCIsIFwiYnVsa1wiKSxcbiAgICAgIEFwaVBhcmFtc0Zyb21Nb2RlbChhcGlQcm9wZXJ0aWVzKSxcbiAgICAgIEFwaU9wZXJhdGlvbih7IHN1bW1hcnk6IGBEZWxldGUgJHttb2RlbENsYXp6TmFtZX0gcmVjb3JkcyBieSBpZHMuYCB9KSxcbiAgICAgIEFwaVF1ZXJ5KHsgbmFtZTogXCJpZHNcIiwgcmVxdWlyZWQ6IHRydWUsIHR5cGU6IFwiYXJyYXlcIiB9KSxcbiAgICAgIEFwaU9rUmVzcG9uc2Uoe1xuICAgICAgICBkZXNjcmlwdGlvbjogYCR7bW9kZWxDbGF6ek5hbWV9IGRlbGV0ZWQgc3VjY2Vzc2Z1bGx5LmAsXG4gICAgICAgIHNjaGVtYToge1xuICAgICAgICAgIHR5cGU6IFwiYXJyYXlcIixcbiAgICAgICAgICBpdGVtczogeyAkcmVmOiBnZXRTY2hlbWFQYXRoKE1vZGVsQ29uc3RyKSB9LFxuICAgICAgICB9LFxuICAgICAgfSksXG4gICAgICBBcGlOb3RGb3VuZFJlc3BvbnNlKHtcbiAgICAgICAgZGVzY3JpcHRpb246IGBObyAke21vZGVsQ2xhenpOYW1lfSByZWNvcmQgbWF0Y2hlcyB0aGUgcHJvdmlkZWQgaWRlbnRpZmllci5gLFxuICAgICAgfSksXG4gICAgXTtcbiAgfVxuXG4gIHByaXZhdGUgc3RhdGljIHJlYWREZWNvcmF0b3JzKFxuICAgIE1vZGVsQ29uc3RyOiBNb2RlbENvbnN0cnVjdG9yPGFueT4sXG4gICAgbW9kZWxDbGF6ek5hbWU6IHN0cmluZyxcbiAgICBhcGlQcm9wZXJ0aWVzOiBEZWNhZkFwaVByb3BlcnR5W10sXG4gICAgcGtQYXRoOiBzdHJpbmdcbiAgKTogQXJyYXk8KHRhcmdldDogYW55LCBrZXk6IHN0cmluZywgZGVzYzogYW55KSA9PiB2b2lkPiB7XG4gICAgcmV0dXJuIFtcbiAgICAgIEFwaU9wZXJhdGlvbkZyb21Nb2RlbChNb2RlbENvbnN0ciwgXCJHRVRcIiwgcGtQYXRoKSxcbiAgICAgIEFwaVBhcmFtc0Zyb21Nb2RlbChhcGlQcm9wZXJ0aWVzKSxcbiAgICAgIEFwaU9wZXJhdGlvbih7IHN1bW1hcnk6IGBSZXRyaWV2ZSBhICR7bW9kZWxDbGF6ek5hbWV9IHJlY29yZCBieSBpZC5gIH0pLFxuICAgICAgQXBpT2tSZXNwb25zZSh7XG4gICAgICAgIGRlc2NyaXB0aW9uOiBgJHttb2RlbENsYXp6TmFtZX0gcmV0cmlldmVkIHN1Y2Nlc3NmdWxseS5gLFxuICAgICAgICBzY2hlbWE6IHsgJHJlZjogZ2V0U2NoZW1hUGF0aChNb2RlbENvbnN0cikgfSxcbiAgICAgIH0pLFxuICAgICAgQXBpTm90Rm91bmRSZXNwb25zZSh7XG4gICAgICAgIGRlc2NyaXB0aW9uOiBgTm8gJHttb2RlbENsYXp6TmFtZX0gcmVjb3JkIG1hdGNoZXMgdGhlIHByb3ZpZGVkIGlkZW50aWZpZXIuYCxcbiAgICAgIH0pLFxuICAgIF07XG4gIH1cblxuICBwcml2YXRlIHN0YXRpYyB1cGRhdGVEZWNvcmF0b3JzKFxuICAgIE1vZGVsQ29uc3RyOiBNb2RlbENvbnN0cnVjdG9yPGFueT4sXG4gICAgbW9kZWxDbGF6ek5hbWU6IHN0cmluZyxcbiAgICBhcGlQcm9wZXJ0aWVzOiBEZWNhZkFwaVByb3BlcnR5W10sXG4gICAgcGtQYXRoOiBzdHJpbmdcbiAgKTogQXJyYXk8KHRhcmdldDogYW55LCBrZXk6IHN0cmluZywgZGVzYzogYW55KSA9PiB2b2lkPiB7XG4gICAgcmV0dXJuIFtcbiAgICAgIEFwaU9wZXJhdGlvbkZyb21Nb2RlbChNb2RlbENvbnN0ciwgXCJQVVRcIiwgcGtQYXRoKSxcbiAgICAgIEFwaVBhcmFtc0Zyb21Nb2RlbChhcGlQcm9wZXJ0aWVzKSxcbiAgICAgIEFwaU9wZXJhdGlvbih7XG4gICAgICAgIHN1bW1hcnk6IGBSZXBsYWNlIGFuIGV4aXN0aW5nICR7bW9kZWxDbGF6ek5hbWV9IHJlY29yZCB3aXRoIGEgbmV3IHBheWxvYWQuYCxcbiAgICAgIH0pLFxuICAgICAgQXBpQm9keSh7XG4gICAgICAgIGRlc2NyaXB0aW9uOiBgUGF5bG9hZCBmb3IgcmVwbGFjaW5nIGFuIGV4aXN0aW5nIHJlY29yZCBvZiAke21vZGVsQ2xhenpOYW1lfWAsXG4gICAgICAgIHR5cGU6IER0b0ZvcihPcGVyYXRpb25LZXlzLlVQREFURSwgTW9kZWxDb25zdHIpLFxuICAgICAgfSksXG4gICAgICBBcGlPa1Jlc3BvbnNlKHtcbiAgICAgICAgZGVzY3JpcHRpb246IGAke21vZGVsQ2xhenpOYW1lfSB1cGRhdGVkIHN1Y2Nlc3NmdWxseS5gLFxuICAgICAgICBzY2hlbWE6IHsgJHJlZjogZ2V0U2NoZW1hUGF0aChNb2RlbENvbnN0cikgfSxcbiAgICAgIH0pLFxuICAgICAgQXBpTm90Rm91bmRSZXNwb25zZSh7XG4gICAgICAgIGRlc2NyaXB0aW9uOiBgTm8gJHttb2RlbENsYXp6TmFtZX0gcmVjb3JkIG1hdGNoZXMgdGhlIHByb3ZpZGVkIGlkZW50aWZpZXIuYCxcbiAgICAgIH0pLFxuICAgICAgQXBpQmFkUmVxdWVzdFJlc3BvbnNlKHsgZGVzY3JpcHRpb246IFwiUGF5bG9hZCB2YWxpZGF0aW9uIGZhaWxlZC5cIiB9KSxcbiAgICBdO1xuICB9XG5cbiAgcHJpdmF0ZSBzdGF0aWMgZGVsZXRlRGVjb3JhdG9ycyhcbiAgICBNb2RlbENvbnN0cjogTW9kZWxDb25zdHJ1Y3Rvcjxhbnk+LFxuICAgIG1vZGVsQ2xhenpOYW1lOiBzdHJpbmcsXG4gICAgYXBpUHJvcGVydGllczogRGVjYWZBcGlQcm9wZXJ0eVtdLFxuICAgIHBrUGF0aDogc3RyaW5nXG4gICk6IEFycmF5PCh0YXJnZXQ6IGFueSwga2V5OiBzdHJpbmcsIGRlc2M6IGFueSkgPT4gdm9pZD4ge1xuICAgIHJldHVybiBbXG4gICAgICBBcGlPcGVyYXRpb25Gcm9tTW9kZWwoTW9kZWxDb25zdHIsIFwiREVMRVRFXCIsIHBrUGF0aCksXG4gICAgICBBcGlQYXJhbXNGcm9tTW9kZWwoYXBpUHJvcGVydGllcyksXG4gICAgICBBcGlPcGVyYXRpb24oeyBzdW1tYXJ5OiBgRGVsZXRlIGEgJHttb2RlbENsYXp6TmFtZX0gcmVjb3JkIGJ5IGlkLmAgfSksXG4gICAgICBBcGlPa1Jlc3BvbnNlKHtcbiAgICAgICAgZGVzY3JpcHRpb246IGAke21vZGVsQ2xhenpOYW1lfSBkZWxldGVkIHN1Y2Nlc3NmdWxseS5gLFxuICAgICAgICBzY2hlbWE6IHsgJHJlZjogZ2V0U2NoZW1hUGF0aChNb2RlbENvbnN0cikgfSxcbiAgICAgIH0pLFxuICAgICAgQXBpTm90Rm91bmRSZXNwb25zZSh7XG4gICAgICAgIGRlc2NyaXB0aW9uOiBgTm8gJHttb2RlbENsYXp6TmFtZX0gcmVjb3JkIG1hdGNoZXMgdGhlIHByb3ZpZGVkIGlkZW50aWZpZXIuYCxcbiAgICAgIH0pLFxuICAgIF07XG4gIH1cblxuICBwcml2YXRlIHN0YXRpYyBzdGF0ZW1lbnREZWNvcmF0b3JzKFxuICAgIE1vZGVsQ29uc3RyOiBNb2RlbENvbnN0cnVjdG9yPGFueT4sXG4gICAgbW9kZWxDbGF6ek5hbWU6IHN0cmluZ1xuICApOiBBcnJheTwodGFyZ2V0OiBhbnksIGtleTogc3RyaW5nLCBkZXNjOiBhbnkpID0+IHZvaWQ+IHtcbiAgICByZXR1cm4gW1xuICAgICAgQXBpT3BlcmF0aW9uRnJvbU1vZGVsKE1vZGVsQ29uc3RyLCBcIkdFVFwiLCBcInN0YXRlbWVudC86bWV0aG9kLyphcmdzXCIpLFxuICAgICAgQXBpT3BlcmF0aW9uKHtcbiAgICAgICAgc3VtbWFyeTogYEV4ZWN1dGVzIGEgcHJlcGFyZWQgc3RhdGVtZW50IG9uICR7bW9kZWxDbGF6ek5hbWV9LmAsXG4gICAgICB9KSxcbiAgICAgIEFwaVBhcmFtKHtcbiAgICAgICAgbmFtZTogXCJtZXRob2RcIixcbiAgICAgICAgZGVzY3JpcHRpb246IFwidGhlIHByZXBhcmVkIHN0YXRlbWVudCB0byBleGVjdXRlXCIsXG4gICAgICB9KSxcbiAgICAgIEFwaVBhcmFtKHtcbiAgICAgICAgbmFtZTogXCJhcmdzXCIsXG4gICAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAgIFwiY29uY2F0ZW5hdGVkIGxpc3Qgb2YgYXJndW1lbnRzIHRoZSBwcmVwYXJlZCBzdGF0ZW1lbnQgY2FuIGFjY2VwdFwiLFxuICAgICAgfSksXG4gICAgICBBcGlRdWVyeSh7XG4gICAgICAgIG5hbWU6IFwiZGlyZWN0aW9uXCIsXG4gICAgICAgIHJlcXVpcmVkOiB0cnVlLFxuICAgICAgICBlbnVtOiBPcmRlckRpcmVjdGlvbixcbiAgICAgICAgZGVzY3JpcHRpb246IFwidGhlIHNvcnQgb3JkZXIgd2hlbiBhcHBsaWNhYmxlXCIsXG4gICAgICB9KSxcbiAgICAgIEFwaVF1ZXJ5KHtcbiAgICAgICAgbmFtZTogXCJsaW1pdFwiLFxuICAgICAgICByZXF1aXJlZDogdHJ1ZSxcbiAgICAgICAgZGVzY3JpcHRpb246IFwibGltaXQgb3IgcGFnZSBzaXplIHdoZW4gYXBwbGljYWJsZVwiLFxuICAgICAgfSksXG4gICAgICBBcGlRdWVyeSh7XG4gICAgICAgIG5hbWU6IFwib2Zmc2V0XCIsXG4gICAgICAgIHJlcXVpcmVkOiB0cnVlLFxuICAgICAgICBkZXNjcmlwdGlvbjogXCJvZmZzZXQgb3IgYm9va21hcmsgd2hlbiBhcHBsaWNhYmxlXCIsXG4gICAgICB9KSxcbiAgICAgIEFwaU9rUmVzcG9uc2UoeyBkZXNjcmlwdGlvbjogYCR7bW9kZWxDbGF6ek5hbWV9IGxpc3RlZCBmb3VuZC5gIH0pLFxuICAgICAgQXBpTm90Rm91bmRSZXNwb25zZSh7XG4gICAgICAgIGRlc2NyaXB0aW9uOiBgTm8gJHttb2RlbENsYXp6TmFtZX0gcmVjb3JkIG1hdGNoZXMgdGhlIHByb3ZpZGVkIGlkZW50aWZpZXIuYCxcbiAgICAgIH0pLFxuICAgIF07XG4gIH1cblxuICBwcml2YXRlIHN0YXRpYyBzdGF0ZW1lbnRTaG9ydGN1dERlY29yYXRvcnMoXG4gICAgTW9kZWxDb25zdHI6IE1vZGVsQ29uc3RydWN0b3I8YW55PixcbiAgICBtb2RlbENsYXp6TmFtZTogc3RyaW5nLFxuICAgIHBhdGg6IHN0cmluZyxcbiAgICBzdGF0ZW1lbnRLZXk6IHN0cmluZ1xuICApOiBBcnJheTwodGFyZ2V0OiBhbnksIGtleTogc3RyaW5nLCBkZXNjOiBhbnkpID0+IHZvaWQ+IHtcbiAgICBjb25zdCBiYXNlOiBBcnJheTwodGFyZ2V0OiBhbnksIGtleTogc3RyaW5nLCBkZXNjOiBhbnkpID0+IHZvaWQ+ID0gW1xuICAgICAgQXBpT3BlcmF0aW9uRnJvbU1vZGVsKE1vZGVsQ29uc3RyLCBcIkdFVFwiLCBwYXRoKSxcbiAgICAgIEFwaU9wZXJhdGlvbih7IHN1bW1hcnk6IGBSZXRyaWV2ZSAke21vZGVsQ2xhenpOYW1lfSByZWNvcmRzLmAgfSksXG4gICAgICBBcGlPa1Jlc3BvbnNlKHtcbiAgICAgICAgZGVzY3JpcHRpb246IGAke21vZGVsQ2xhenpOYW1lfSByZXRyaWV2ZWQgc3VjY2Vzc2Z1bGx5LmAsXG4gICAgICB9KSxcbiAgICBdO1xuXG4gICAgY29uc3Qgc2VnbWVudHMgPSBwYXRoLnNwbGl0KFwiL1wiKS5maWx0ZXIoKHMpID0+IHMuc3RhcnRzV2l0aChcIjpcIikpO1xuICAgIHNlZ21lbnRzLmZvckVhY2goKHNlZykgPT4ge1xuICAgICAgY29uc3QgbmFtZSA9IHNlZy5yZXBsYWNlKFwiOlwiLCBcIlwiKTtcbiAgICAgIGJhc2UucHVzaChBcGlQYXJhbSh7IG5hbWUsIGRlc2NyaXB0aW9uOiBgVGhlICR7bmFtZX0gcGFyYW1ldGVyYCB9KSk7XG4gICAgfSk7XG5cbiAgICBpZiAoXG4gICAgICBwYXRoLnN0YXJ0c1dpdGgoXCJsaXN0QnkvXCIpIHx8XG4gICAgICBwYXRoLnN0YXJ0c1dpdGgoXCJwYWdpbmF0ZUJ5L1wiKSB8fFxuICAgICAgcGF0aC5zdGFydHNXaXRoKFwiZmluZC9cIikgfHxcbiAgICAgIHBhdGguc3RhcnRzV2l0aChcInBhZ2UvXCIpXG4gICAgKSB7XG4gICAgICBiYXNlLnB1c2goXG4gICAgICAgIEFwaVF1ZXJ5KHtcbiAgICAgICAgICBuYW1lOiBcImRpcmVjdGlvblwiLFxuICAgICAgICAgIHJlcXVpcmVkOiB0cnVlLFxuICAgICAgICAgIGVudW06IE9yZGVyRGlyZWN0aW9uLFxuICAgICAgICAgIGRlc2NyaXB0aW9uOiBcInRoZSBzb3J0IG9yZGVyXCIsXG4gICAgICAgIH0pXG4gICAgICApO1xuICAgIH1cbiAgICBpZiAocGF0aC5zdGFydHNXaXRoKFwicGFnaW5hdGVCeS9cIikgfHwgcGF0aC5zdGFydHNXaXRoKFwicGFnZS9cIikpIHtcbiAgICAgIGJhc2UucHVzaChcbiAgICAgICAgQXBpUXVlcnkoeyBuYW1lOiBcImxpbWl0XCIsIHJlcXVpcmVkOiBmYWxzZSwgZGVzY3JpcHRpb246IFwicGFnZSBzaXplXCIgfSksXG4gICAgICAgIEFwaVF1ZXJ5KHtcbiAgICAgICAgICBuYW1lOiBcIm9mZnNldFwiLFxuICAgICAgICAgIHJlcXVpcmVkOiBmYWxzZSxcbiAgICAgICAgICBkZXNjcmlwdGlvbjogXCJwYWdlIG51bWJlclwiLFxuICAgICAgICB9KSxcbiAgICAgICAgQXBpUXVlcnkoe1xuICAgICAgICAgIG5hbWU6IFwiYm9va21hcmtcIixcbiAgICAgICAgICByZXF1aXJlZDogZmFsc2UsXG4gICAgICAgICAgZGVzY3JpcHRpb246IFwiYm9va21hcmsgZm9yIGN1cnNvciBwYWdpbmF0aW9uXCIsXG4gICAgICAgIH0pXG4gICAgICApO1xuICAgIH1cblxuICAgIGlmIChwYXRoLnN0YXJ0c1dpdGgoXCJmaW5kT25lQnkvXCIpIHx8IHBhdGguc3RhcnRzV2l0aChcImZpbmRCeS9cIikpIHtcbiAgICAgIGJhc2UucHVzaChcbiAgICAgICAgQXBpTm90Rm91bmRSZXNwb25zZSh7XG4gICAgICAgICAgZGVzY3JpcHRpb246IGBObyAke21vZGVsQ2xhenpOYW1lfSByZWNvcmQgbWF0Y2hlcyB0aGUgcHJvdmlkZWQgaWRlbnRpZmllci5gLFxuICAgICAgICB9KVxuICAgICAgKTtcbiAgICB9XG5cbiAgICBpZiAoXG4gICAgICBzdGF0ZW1lbnRLZXkgPT09IFByZXBhcmVkU3RhdGVtZW50S2V5cy5DT1VOVF9PRiB8fFxuICAgICAgc3RhdGVtZW50S2V5ID09PSBQcmVwYXJlZFN0YXRlbWVudEtleXMuQVZHX09GIHx8XG4gICAgICBzdGF0ZW1lbnRLZXkgPT09IFByZXBhcmVkU3RhdGVtZW50S2V5cy5TVU1fT0ZcbiAgICApIHtcbiAgICAgIGJhc2UucHVzaChcbiAgICAgICAgQXBpT2tSZXNwb25zZSh7XG4gICAgICAgICAgZGVzY3JpcHRpb246IGBSZXN1bHQgZm9yICR7bW9kZWxDbGF6ek5hbWV9LmAsXG4gICAgICAgICAgdHlwZTogTnVtYmVyLFxuICAgICAgICB9KVxuICAgICAgKTtcbiAgICB9XG4gICAgaWYgKHN0YXRlbWVudEtleSA9PT0gUHJlcGFyZWRTdGF0ZW1lbnRLZXlzLkRJU1RJTkNUX09GKSB7XG4gICAgICBiYXNlLnB1c2goXG4gICAgICAgIEFwaU9rUmVzcG9uc2Uoe1xuICAgICAgICAgIGRlc2NyaXB0aW9uOiBgRGlzdGluY3QgdmFsdWVzIGZvciAke21vZGVsQ2xhenpOYW1lfS5gLFxuICAgICAgICAgIHR5cGU6IFtTdHJpbmddLFxuICAgICAgICB9KVxuICAgICAgKTtcbiAgICB9XG5cbiAgICByZXR1cm4gYmFzZTtcbiAgfVxuXG4gIHByaXZhdGUgc3RhdGljIGdldFF1ZXJ5RGVjb3JhdG9ycyhcbiAgICBtZXRob2ROYW1lOiBzdHJpbmcsXG4gICAgcm91dGVQYXRoOiBzdHJpbmcsXG4gICAgaHR0cFZlcmI6IHN0cmluZyxcbiAgICBpbmNsdWRlUXVlcnlQYXJhbXM6IGJvb2xlYW4gPSBmYWxzZVxuICApOiBBcnJheTwodGFyZ2V0OiBhbnksIGtleTogc3RyaW5nLCBkZXNjOiBhbnkpID0+IHZvaWQ+IHtcbiAgICBjb25zdCBleHRyYWN0UGF0aFBhcmFtcyA9IChwOiBzdHJpbmcpOiBzdHJpbmdbXSA9PlxuICAgICAgcFxuICAgICAgICAuc3BsaXQoXCIvXCIpXG4gICAgICAgIC5maWx0ZXIoKHMpID0+IHMuc3RhcnRzV2l0aChcIjpcIikpXG4gICAgICAgIC5tYXAoKHMpID0+IHMuc2xpY2UoMSkpO1xuXG4gICAgY29uc3QgYXBpUGF0aFBhcmFtcyA9IGV4dHJhY3RQYXRoUGFyYW1zKHJvdXRlUGF0aCkubWFwKChuYW1lKSA9PiAoe1xuICAgICAgbmFtZSxcbiAgICAgIGRlc2NyaXB0aW9uOiBgJHtuYW1lfSBwYXJhbWV0ZXIgZm9yIHRoZSBxdWVyeWAsXG4gICAgICByZXF1aXJlZDogdHJ1ZSxcbiAgICAgIHR5cGU6IFN0cmluZyxcbiAgICB9KSk7XG5cbiAgICBjb25zdCBkZWNvcmF0b3JzOiBBcnJheTwodGFyZ2V0OiBhbnksIGtleTogc3RyaW5nLCBkZXNjOiBhbnkpID0+IHZvaWQ+ID0gW1xuICAgICAgLi4uYXBpUGF0aFBhcmFtcy5tYXAoKHApID0+IEFwaVBhcmFtKHApKSxcbiAgICAgIEFwaU9wZXJhdGlvbih7IHN1bW1hcnk6IGBSZXRyaWV2ZSByZWNvcmRzIHVzaW5nIFwiJHttZXRob2ROYW1lfVwiLmAgfSksXG4gICAgICBBcGlPa1Jlc3BvbnNlKHsgZGVzY3JpcHRpb246IFwiUmVzdWx0IHN1Y2Nlc3NmdWxseSByZXRyaWV2ZWQuXCIgfSksXG4gICAgICBBcGlOb0NvbnRlbnRSZXNwb25zZSh7XG4gICAgICAgIGRlc2NyaXB0aW9uOiBcIk5vIGNvbnRlbnQgcmV0dXJuZWQgYnkgdGhlIG1ldGhvZC5cIixcbiAgICAgIH0pLFxuICAgIF07XG5cbiAgICBpZiAoaHR0cFZlcmIgPT09IFwiR0VUXCIgJiYgaW5jbHVkZVF1ZXJ5UGFyYW1zKSB7XG4gICAgICBkZWNvcmF0b3JzLnB1c2goXG4gICAgICAgIEFwaVF1ZXJ5KHtcbiAgICAgICAgICBuYW1lOiBcImRpcmVjdGlvblwiLFxuICAgICAgICAgIHJlcXVpcmVkOiBmYWxzZSxcbiAgICAgICAgICBlbnVtOiBPcmRlckRpcmVjdGlvbixcbiAgICAgICAgICBkZXNjcmlwdGlvbjogXCJ0aGUgc29ydCBvcmRlciB3aGVuIGFwcGxpY2FibGVcIixcbiAgICAgICAgfSksXG4gICAgICAgIEFwaVF1ZXJ5KHtcbiAgICAgICAgICBuYW1lOiBcImxpbWl0XCIsXG4gICAgICAgICAgcmVxdWlyZWQ6IGZhbHNlLFxuICAgICAgICAgIGRlc2NyaXB0aW9uOiBcImxpbWl0IG9yIHBhZ2Ugc2l6ZVwiLFxuICAgICAgICB9KSxcbiAgICAgICAgQXBpUXVlcnkoe1xuICAgICAgICAgIG5hbWU6IFwib2Zmc2V0XCIsXG4gICAgICAgICAgcmVxdWlyZWQ6IGZhbHNlLFxuICAgICAgICAgIGRlc2NyaXB0aW9uOiBcIm9mZnNldCBvciBib29rbWFya1wiLFxuICAgICAgICB9KVxuICAgICAgKTtcbiAgICB9XG5cbiAgICByZXR1cm4gZGVjb3JhdG9ycztcbiAgfVxufVxuIiwiaW1wb3J0IHsgRHluYW1pY01vZHVsZSwgTW9kdWxlLCBQcm92aWRlciB9IGZyb20gXCJAbmVzdGpzL2NvbW1vblwiO1xuaW1wb3J0IHsgQWRhcHRlciwgTW9kZWxTZXJ2aWNlIH0gZnJvbSBcIkBkZWNhZi10cy9jb3JlXCI7XG5pbXBvcnQgeyBMb2dnaW5nIH0gZnJvbSBcIkBkZWNhZi10cy9sb2dnaW5nXCI7XG5pbXBvcnQgeyBGcm9tTW9kZWxDb250cm9sbGVyIH0gZnJvbSBcIi4vRnJvbU1vZGVsQ29udHJvbGxlclwiO1xuaW1wb3J0IHsgRGVjYWZNb2R1bGVPcHRpb25zIH0gZnJvbSBcIi4uL3R5cGVzXCI7XG5pbXBvcnQgeyBNb2RlbCwgTW9kZWxDb25zdHJ1Y3RvciB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdG9yLXZhbGlkYXRpb25cIjtcbmltcG9ydCB7IE1ldGFkYXRhIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0aW9uXCI7XG5pbXBvcnQgeyBERUNBRl9FWFBPU0UgfSBmcm9tIFwiLi4vY29uc3RhbnRzXCI7XG5pbXBvcnQgdHlwZSB7IE1vZGVsQ29udHJvbGxlckZhY3RvcnlDb25maWcgfSBmcm9tIFwiQGRlY2FmLXRzL2Zvci1odHRwL3NlcnZlclwiO1xuXG5leHBvcnQgZnVuY3Rpb24gZ2V0TW9kdWxlRm9yKGZsYXZvdXI6IHN0cmluZykge1xuICBATW9kdWxlKHt9KVxuICBjbGFzcyBEZWNhZk1vZGVsTW9kdWxlIHtcbiAgICBzdGF0aWMgcmVhZG9ubHkgbG9nID0gTG9nZ2luZy5mb3IoRGVjYWZNb2RlbE1vZHVsZS5uYW1lKS5mb3IoZmxhdm91cik7XG5cbiAgICBzdGF0aWMgY3JlYXRlTW9kZWxTZXJ2aWNlczxUIGV4dGVuZHMgTW9kZWw8Ym9vbGVhbj4+KFxuICAgICAgbW9kZWxzOiBNb2RlbENvbnN0cnVjdG9yPFQ+W11cbiAgICApOiBQcm92aWRlcltdIHtcbiAgICAgIHJldHVybiBtb2RlbHMubWFwKChtb2RlbCkgPT4gKHtcbiAgICAgICAgcHJvdmlkZTogYCR7bW9kZWwubmFtZX1TZXJ2aWNlYCxcbiAgICAgICAgdXNlRmFjdG9yeTogKCkgPT4gTW9kZWxTZXJ2aWNlLmZvck1vZGVsKG1vZGVsIGFzIGFueSksXG4gICAgICB9KSk7XG4gICAgfVxuXG4gICAgc3RhdGljIGlzRXhwb3NlZChcbiAgICAgIG1vZGVsOiBNb2RlbENvbnN0cnVjdG9yPGFueT4sXG4gICAgICBleHBvc3VyZT86IFJlY29yZDxzdHJpbmcsIGJvb2xlYW4gfCBzdHJpbmdbXT5cbiAgICApOiBib29sZWFuIHtcbiAgICAgIGNvbnN0IG92ZXJyaWRlID0gZXhwb3N1cmU/Llttb2RlbC5uYW1lXTtcbiAgICAgIGNvbnN0IHZhbHVlID1cbiAgICAgICAgdHlwZW9mIG92ZXJyaWRlICE9PSBcInVuZGVmaW5lZFwiXG4gICAgICAgICAgPyBvdmVycmlkZVxuICAgICAgICAgIDogTWV0YWRhdGEuZ2V0KG1vZGVsLCBNZXRhZGF0YS5rZXkoREVDQUZfRVhQT1NFKSk7XG5cbiAgICAgIGlmICh0eXBlb2YgdmFsdWUgPT09IFwidW5kZWZpbmVkXCIpIHJldHVybiB0cnVlO1xuICAgICAgaWYgKHZhbHVlID09PSB0cnVlKSByZXR1cm4gdHJ1ZTtcbiAgICAgIGlmIChBcnJheS5pc0FycmF5KHZhbHVlKSkgcmV0dXJuIHZhbHVlLmluY2x1ZGVzKGZsYXZvdXIpO1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIHN0YXRpYyBmb3JSb290KFxuICAgICAgZmxhdm91cjogc3RyaW5nLFxuICAgICAgb3B0aW9uczogUGFydGlhbDxEZWNhZk1vZHVsZU9wdGlvbnM+ID0ge31cbiAgICApOiBEeW5hbWljTW9kdWxlIHtcbiAgICAgIGNvbnN0IGxvZyA9IHRoaXMubG9nLmZvcih0aGlzLmZvclJvb3QpO1xuICAgICAgbG9nLmluZm8oYEdlbmVyYXRpbmcgY29udHJvbGxlcnMgZm9yIGZsYXZvdXIuLi5gKTtcblxuICAgICAgY29uc3QgdHJhY2tlZE1vZGVscyA9IEFkYXB0ZXIubW9kZWxzKGZsYXZvdXIpLmZpbHRlcigobW9kZWwpID0+XG4gICAgICAgIHRoaXMuaXNFeHBvc2VkKG1vZGVsLCBvcHRpb25zLmNvbnRyb2xsZXJFeHBvc3VyZSlcbiAgICAgICk7XG5cbiAgICAgIC8vIENvbnRyb2xsZXJzIGFsd2F5cyByZWx5IG9uIGEgYmFja2luZyBNb2RlbFNlcnZpY2UsIGV2ZW4gd2hlbiBOZXN0IHByb3ZpZGVyc1xuICAgICAgLy8gYXJlIG5vdCBhdXRvLXJlZ2lzdGVyZWQuIFdhcm0gdGhlIHNpbmdsZXRvbiByZWdpc3RyeSBoZXJlIHNvIHNodXRkb3duIGNhblxuICAgICAgLy8gc2VlIHRoZSBsaXZlIHNlcnZpY2VzIGNyZWF0ZWQgZm9yIHRoZSBnZW5lcmF0ZWQgY29udHJvbGxlcnMuXG4gICAgICBmb3IgKGNvbnN0IG1vZGVsIG9mIHRyYWNrZWRNb2RlbHMpIE1vZGVsU2VydmljZS5mb3JNb2RlbChtb2RlbCBhcyBhbnkpO1xuXG4gICAgICBsZXQgbW9kZWxTZXJ2aWNlczogUHJvdmlkZXJbXSA9IFtdO1xuICAgICAgaWYgKG9wdGlvbnMuYXV0b1NlcnZpY2VzKSB7XG4gICAgICAgIGxvZy5pbmZvKFwiQXV0by1zZXJ2aWNlcyBlbmFibGVkLiBJbml0aWFsaXppbmcgc2VydmljZSBnZW5lcmF0aW9uLlwiKTtcbiAgICAgICAgbW9kZWxTZXJ2aWNlcyA9IHRoaXMuY3JlYXRlTW9kZWxTZXJ2aWNlcyh0cmFja2VkTW9kZWxzKTtcbiAgICAgICAgbG9nLmluZm8oXG4gICAgICAgICAgYEF1dG8tc2VydmljZXMgY29tcGxldGVkLiAke21vZGVsU2VydmljZXMubGVuZ3RofSBzZXJ2aWNlcyBpbml0aWFsaXplZC5gXG4gICAgICAgICk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGdsb2JhbERlZmF1bHRzOiBQYXJ0aWFsPE1vZGVsQ29udHJvbGxlckZhY3RvcnlDb25maWc+ID0ge307XG4gICAgICBpZiAob3B0aW9ucy5hZ2dyZWdhdGlvbnMgPT09IGZhbHNlKSB7XG4gICAgICAgIGdsb2JhbERlZmF1bHRzLmFsbG93R3JvdXBpbmdRdWVyaWVzID0gZmFsc2U7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGNvbnRyb2xsZXJzID0gdHJhY2tlZE1vZGVscy5tYXAoKG1vZGVsKSA9PlxuICAgICAgICBGcm9tTW9kZWxDb250cm9sbGVyLmNyZWF0ZShtb2RlbCwgb3B0aW9ucy5jb250cm9sbGVyQ29uZmlnLCBnbG9iYWxEZWZhdWx0cylcbiAgICAgICk7XG4gICAgICBsb2cuaW5mbyhgR2VuZXJhdGVkICR7Y29udHJvbGxlcnMubGVuZ3RofSBjb250cm9sbGVyc2ApO1xuXG4gICAgICByZXR1cm4ge1xuICAgICAgICBtb2R1bGU6IERlY2FmTW9kZWxNb2R1bGUsXG4gICAgICAgIGNvbnRyb2xsZXJzLFxuICAgICAgICBwcm92aWRlcnM6IFtcbiAgICAgICAgICAuLi5tb2RlbFNlcnZpY2VzLFxuICAgICAgICBdLFxuICAgICAgfTtcbiAgICB9XG4gIH1cbiAgT2JqZWN0LmFzc2lnbihEZWNhZk1vZGVsTW9kdWxlLCBcIm5hbWVcIiwge1xuICAgIHZhbHVlOiBgRGVjYWZNb2R1bGUke2ZsYXZvdXJ9YCxcbiAgfSk7XG4gIHJldHVybiBEZWNhZk1vZGVsTW9kdWxlO1xufVxuIiwiaW1wb3J0IHtcbiAgRGVmYXVsdEluamVjdGFibGVzQ29uZmlnLFxuICBJbmplY3RhYmxlQ29uZmlnLFxuICBJbmplY3RhYmxlc0tleXMsXG4gIEluamVjdE9wdGlvbnMsXG59IGZyb20gXCJAZGVjYWYtdHMvaW5qZWN0YWJsZS1kZWNvcmF0b3JzXCI7XG5pbXBvcnQgeyBJbmplY3QsIEluamVjdGFibGUsIFNjb3BlIH0gZnJvbSBcIkBuZXN0anMvY29tbW9uXCI7XG5pbXBvcnQgeyBDb25zdHJ1Y3RvciwgRGVjb3JhdGlvbiwgRGVjb3JhdGlvbktleXMgfSBmcm9tIFwiQGRlY2FmLXRzL2RlY29yYXRpb25cIjtcbmltcG9ydCB7IFZhbGlkYXRpb25LZXlzIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0b3ItdmFsaWRhdGlvblwiO1xuaW1wb3J0IHsgUGVyc2lzdGVuY2VLZXlzIH0gZnJvbSBcIkBkZWNhZi10cy9jb3JlXCI7XG5pbXBvcnQgeyBBcGlQcm9wZXJ0eSB9IGZyb20gXCIuL292ZXJyaWRlcy9kZWNvcmF0aW9uXCI7XG5pbXBvcnQgeyBBdXRoIH0gZnJvbSBcIi4vZGVjYWYtbW9kZWxcIjtcblxuRGVjb3JhdGlvbi5mb3IoSW5qZWN0YWJsZXNLZXlzLklOSkVDVEFCTEUpXG4gIC5leHRlbmQoe1xuICAgIGRlY29yYXRvcjogZnVuY3Rpb24gbmVzdEluamVjdGFibGUoXG4gICAgICBjYXRlZ29yeTogc3RyaW5nIHwgQ29uc3RydWN0b3IsXG4gICAgICBjZmc/OiBJbmplY3RhYmxlQ29uZmlnXG4gICAgKSB7XG4gICAgICBjZmcgPVxuICAgICAgICBjZmcgfHxcbiAgICAgICAgKHR5cGVvZiBjYXRlZ29yeSA9PT0gXCJvYmplY3RcIlxuICAgICAgICAgID8gT2JqZWN0LmFzc2lnbihcbiAgICAgICAgICAgICAgY2F0ZWdvcnkgYXMgUmVjb3JkPGFueSwgYW55PixcbiAgICAgICAgICAgICAgRGVmYXVsdEluamVjdGFibGVzQ29uZmlnXG4gICAgICAgICAgICApXG4gICAgICAgICAgOiBEZWZhdWx0SW5qZWN0YWJsZXNDb25maWcpO1xuICAgICAgcmV0dXJuIEluamVjdGFibGUoe1xuICAgICAgICBzY29wZTogY2ZnLnNpbmdsZXRvbiA/IFNjb3BlLkRFRkFVTFQgOiBTY29wZS5SRVFVRVNULFxuICAgICAgICBkdXJhYmxlOiBjZmcuc2luZ2xldG9uID8gdW5kZWZpbmVkIDogdHJ1ZSxcbiAgICAgIH0pO1xuICAgIH0sXG4gIH0pXG4gIC5hcHBseSgpO1xuXG5EZWNvcmF0aW9uLmZvcihJbmplY3RhYmxlc0tleXMuSU5KRUNUKVxuICAuZXh0ZW5kKHtcbiAgICBkZWNvcmF0b3I6IGZ1bmN0aW9uIG5lc3RJbmplY3QoXG4gICAgICBjYXRlZ29yeTogc3ltYm9sIHwgc3RyaW5nIHwgQ29uc3RydWN0b3IsXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVudXNlZC12YXJzXG4gICAgICBjZmc6IEluamVjdE9wdGlvbnNcbiAgICApIHtcbiAgICAgIHJldHVybiBmdW5jdGlvbiBpbm5lck5lc3RJbmplY3QoXG4gICAgICAgIHRhcmdldDogb2JqZWN0LFxuICAgICAgICBwcm9wZXJ0eUtleT86IGFueSxcbiAgICAgICAgZGVzY3JpcHRvcj86IGFueVxuICAgICAgKSB7XG4gICAgICAgIHJldHVybiBJbmplY3QoY2F0ZWdvcnkgfHwgKHRhcmdldCBhcyBDb25zdHJ1Y3RvcikpKFxuICAgICAgICAgIHRhcmdldCxcbiAgICAgICAgICBwcm9wZXJ0eUtleSxcbiAgICAgICAgICBkZXNjcmlwdG9yXG4gICAgICAgICk7XG4gICAgICB9O1xuICAgIH0sXG4gIH0pXG4gIC5hcHBseSgpO1xuXG5EZWNvcmF0aW9uLmZvcihWYWxpZGF0aW9uS2V5cy5SRVFVSVJFRClcbiAgLmV4dGVuZChcbiAgICBBcGlQcm9wZXJ0eSh7XG4gICAgICByZXF1aXJlZDogdHJ1ZSxcbiAgICB9KVxuICApXG4gIC5hcHBseSgpO1xuXG5EZWNvcmF0aW9uLmZvcihWYWxpZGF0aW9uS2V5cy5NQVgpXG4gIC5leHRlbmQoe1xuICAgIGRlY29yYXRvcjogZnVuY3Rpb24gbWF4RGVjKG1heDogbnVtYmVyKSB7XG4gICAgICByZXR1cm4gQXBpUHJvcGVydHkoeyBtYXhpbXVtOiBtYXgsIHJlcXVpcmVkOiBmYWxzZSB9KTtcbiAgICB9LFxuICB9KVxuICAuYXBwbHkoKTtcblxuRGVjb3JhdGlvbi5mb3IoVmFsaWRhdGlvbktleXMuTUlOKVxuICAuZXh0ZW5kKHtcbiAgICBkZWNvcmF0b3I6IGZ1bmN0aW9uIG1pbkRlYyhtaW46IG51bWJlcikge1xuICAgICAgcmV0dXJuIEFwaVByb3BlcnR5KHsgbWluaW11bTogbWluLCByZXF1aXJlZDogZmFsc2UgfSk7XG4gICAgfSxcbiAgfSlcbiAgLmFwcGx5KCk7XG5cbkRlY29yYXRpb24uZm9yKFZhbGlkYXRpb25LZXlzLk1BWF9MRU5HVEgpXG4gIC5leHRlbmQoe1xuICAgIGRlY29yYXRvcjogZnVuY3Rpb24gbWF4TGVuZ3RoRGVjKG1heDogbnVtYmVyKSB7XG4gICAgICByZXR1cm4gQXBpUHJvcGVydHkoeyBtYXhMZW5ndGg6IG1heCwgcmVxdWlyZWQ6IGZhbHNlIH0pO1xuICAgIH0sXG4gIH0pXG4gIC5hcHBseSgpO1xuXG5EZWNvcmF0aW9uLmZvcihWYWxpZGF0aW9uS2V5cy5NSU5fTEVOR1RIKVxuICAuZXh0ZW5kKHtcbiAgICBkZWNvcmF0b3I6IGZ1bmN0aW9uIG1pbkxlbmd0aERlYyhtaW46IG51bWJlcikge1xuICAgICAgcmV0dXJuIEFwaVByb3BlcnR5KHsgbWluTGVuZ3RoOiBtaW4sIHJlcXVpcmVkOiBmYWxzZSB9KTtcbiAgICB9LFxuICB9KVxuICAuYXBwbHkoKTtcblxuRGVjb3JhdGlvbi5mb3IoVmFsaWRhdGlvbktleXMuVFlQRSlcbiAgLmV4dGVuZCh7XG4gICAgZGVjb3JhdG9yOiBmdW5jdGlvbiB0eXBlRGVjKFxuICAgICAgdHlwZTpcbiAgICAgICAgfCAoQ29uc3RydWN0b3IgfCAoKCkgPT4gQ29uc3RydWN0b3IpKVtdXG4gICAgICAgIHwgQ29uc3RydWN0b3JcbiAgICAgICAgfCAoKCkgPT4gQ29uc3RydWN0b3IpXG4gICAgKSB7XG4gICAgICByZXR1cm4gKHRhcmdldDogb2JqZWN0LCBwcm9wOiBhbnkpID0+IHtcbiAgICAgICAgdHlwZSA9IEFycmF5LmlzQXJyYXkodHlwZSkgPyB0eXBlWzBdIDogdHlwZTtcbiAgICAgICAgaWYgKHR5cGVvZiB0eXBlID09PSBcImZ1bmN0aW9uXCIgJiYgIXR5cGUubmFtZSlcbiAgICAgICAgICB0eXBlID0gKHR5cGUgYXMgKCkgPT4gQ29uc3RydWN0b3IpKCk7XG4gICAgICAgIHJldHVybiBBcGlQcm9wZXJ0eSh7XG4gICAgICAgICAgdHlwZTogdHlwZSBhcyBhbnksXG4gICAgICAgICAgcmVxdWlyZWQ6IGZhbHNlLFxuICAgICAgICB9KSh0YXJnZXQsIHByb3ApO1xuICAgICAgfTtcbiAgICB9LFxuICB9KVxuICAuYXBwbHkoKTtcbi8vXG4vLyBEZWNvcmF0aW9uLmZvcihWYWxpZGF0aW9uS2V5cy5MSVNUKVxuLy8gICAuZXh0ZW5kKHtcbi8vICAgICBkZWNvcmF0b3I6IGZ1bmN0aW9uIGxpc3REZWMoXG4vLyAgICAgICBjbGF6ejpcbi8vICAgICAgICAgfCBDb25zdHJ1Y3RvclxuLy8gICAgICAgICB8ICgoKSA9PiBDb25zdHJ1Y3Rvcilcbi8vICAgICAgICAgfCAoQ29uc3RydWN0b3IgfCAoKCkgPT4gQ29uc3RydWN0b3IpKVtdLFxuLy8gICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnVzZWQtdmFyc1xuLy8gICAgICAgY29sbGVjdGlvbjogXCJBcnJheVwiIHwgXCJTZXRcIiA9IFwiQXJyYXlcIlxuLy8gICAgICkge1xuLy8gICAgICAgcmV0dXJuICh0YXJnZXQ6IG9iamVjdCwgcHJvcDogYW55KSA9PiB7XG4vLyAgICAgICAgIGNsYXp6ID0gQXJyYXkuaXNBcnJheShjbGF6eikgPyBjbGF6elswXSA6IGNsYXp6O1xuLy8gICAgICAgICBpZiAodHlwZW9mIGNsYXp6ID09PSBcImZ1bmN0aW9uXCIgJiYgIWNsYXp6Lm5hbWUpXG4vLyAgICAgICAgICAgY2xhenogPSAoY2xhenogYXMgKCkgPT4gQ29uc3RydWN0b3IpKCk7XG4vLyAgICAgICAgIHJldHVybiBBcGlQcm9wZXJ0eSh7IHR5cGU6IFtjbGF6eiBhcyBhbnldIH0pKHRhcmdldCwgcHJvcCk7XG4vLyAgICAgICB9O1xuLy8gICAgIH0sXG4vLyAgIH0pXG4vLyAgIC5hcHBseSgpO1xuLy8gLy9cbkRlY29yYXRpb24uZm9yKFZhbGlkYXRpb25LZXlzLkRBVEUpXG4gIC5leHRlbmQoe1xuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnNcbiAgICBkZWNvcmF0b3I6IGZ1bmN0aW9uIGRhdGVEZWMoZm9ybWF0OiBzdHJpbmcpIHtcbiAgICAgIHJldHVybiBBcGlQcm9wZXJ0eSh7XG4gICAgICAgIHR5cGU6IFN0cmluZyxcbiAgICAgICAgZm9ybWF0OiBcImRhdGUtdGltZVwiLFxuICAgICAgICByZXF1aXJlZDogZmFsc2UsXG4gICAgICAgIC8vIGV4YW1wbGU6IHBhcnNlRGF0ZShmb3JtYXQsIG5ldyBEYXRlKCkpLFxuICAgICAgfSk7XG4gICAgfSxcbiAgfSlcbiAgLmFwcGx5KCk7XG5cbkRlY29yYXRpb24uZm9yKFZhbGlkYXRpb25LZXlzLkVOVU0pXG4gIC5leHRlbmQoe1xuICAgIGRlY29yYXRvcjogZnVuY3Rpb24gb3B0aW9uRGVjKG9wdGlvbnM6IHN0cmluZ1tdIHwgUmVjb3JkPHN0cmluZywgYW55Pikge1xuICAgICAgY29uc3Qgb3B0cyA9IEFycmF5LmlzQXJyYXkob3B0aW9ucykgPyBvcHRpb25zIDogT2JqZWN0LnZhbHVlcyhvcHRpb25zKTtcbiAgICAgIHJldHVybiBBcGlQcm9wZXJ0eSh7XG4gICAgICAgIGVudW06IG9wdHMsXG4gICAgICAgIHJlcXVpcmVkOiBmYWxzZSxcbiAgICAgIH0pO1xuICAgIH0sXG4gIH0pXG4gIC5hcHBseSgpO1xuXG5EZWNvcmF0aW9uLmZvcihWYWxpZGF0aW9uS2V5cy5QQVRURVJOKVxuICAuZXh0ZW5kKHtcbiAgICBkZWNvcmF0b3I6IGZ1bmN0aW9uIHBhdHRlcm5EZWMocGF0OiBSZWdFeHAgfCBzdHJpbmcpIHtcbiAgICAgIHJldHVybiBBcGlQcm9wZXJ0eSh7XG4gICAgICAgIHBhdHRlcm46IHR5cGVvZiBwYXQgPT09IFwic3RyaW5nXCIgPyBwYXQgOiBwYXQuc291cmNlLFxuICAgICAgICByZXF1aXJlZDogZmFsc2UsXG4gICAgICB9KTtcbiAgICB9LFxuICB9KVxuICAuYXBwbHkoKTtcblxuRGVjb3JhdGlvbi5mb3IoUGVyc2lzdGVuY2VLZXlzLkNPTFVNTilcbiAgLmV4dGVuZCh7XG4gICAgZGVjb3JhdG9yOiBmdW5jdGlvbiBjb2x1bW5EZWMobmFtZTogc3RyaW5nKSB7XG4gICAgICByZXR1cm4gQXBpUHJvcGVydHkoe1xuICAgICAgICBuYW1lOiBuYW1lLFxuICAgICAgICByZXF1aXJlZDogZmFsc2UsXG4gICAgICB9KTtcbiAgICB9LFxuICB9KVxuICAuYXBwbHkoKTtcblxuRGVjb3JhdGlvbi5mb3IoRGVjb3JhdGlvbktleXMuREVTQ1JJUFRJT04pXG4gIC5leHRlbmQoe1xuICAgIGRlY29yYXRvcjogZnVuY3Rpb24gZGVzY3JpcHRpb25EZWMoZGVzY3JpcHRpb246IHN0cmluZykge1xuICAgICAgcmV0dXJuIEFwaVByb3BlcnR5KHtcbiAgICAgICAgZGVzY3JpcHRpb246IGRlc2NyaXB0aW9uLFxuICAgICAgICByZXF1aXJlZDogZmFsc2UsXG4gICAgICB9KTtcbiAgICB9LFxuICB9KVxuICAuYXBwbHkoKTtcblxuRGVjb3JhdGlvbi5mb3IoUGVyc2lzdGVuY2VLZXlzLkFVVEgpLmV4dGVuZCh7IGRlY29yYXRvcjogQXV0aCB9KS5hcHBseSgpO1xuIiwiaW1wb3J0IHsgRm9yYmlkZGVuRXJyb3IgfSBmcm9tIFwiQGRlY2FmLXRzL2NvcmVcIjtcblxuZXhwb3J0IGNsYXNzIENvcnNFcnJvciBleHRlbmRzIEZvcmJpZGRlbkVycm9yIHtcbiAgY29uc3RydWN0b3IobXNnOiBzdHJpbmcgfCBFcnJvcikge1xuICAgIHN1cGVyKG1zZywgQ29yc0Vycm9yLm5hbWUpO1xuICB9XG59XG4iLCJpbXBvcnQgeyBCYXNlRXJyb3IgfSBmcm9tIFwiQGRlY2FmLXRzL2RiLWRlY29yYXRvcnNcIjtcblxuZXhwb3J0IGNsYXNzIFRvTWFueVJlcXVlc3RzRXJyb3IgZXh0ZW5kcyBCYXNlRXJyb3Ige1xuICBjb25zdHJ1Y3Rvcihtc2c6IHN0cmluZyB8IEVycm9yICkge1xuICAgIHN1cGVyKFRvTWFueVJlcXVlc3RzRXJyb3IubmFtZSwgbXNnICwgNDI5KTtcbiAgfVxufSIsImltcG9ydCB7XG4gIEFyZ3VtZW50c0hvc3QsXG4gIEJhZFJlcXVlc3RFeGNlcHRpb24sXG4gIENhdGNoLFxuICBDb25mbGljdEV4Y2VwdGlvbixcbiAgRXhjZXB0aW9uRmlsdGVyLFxuICBGb3JiaWRkZW5FeGNlcHRpb24sXG4gIEh0dHBFeGNlcHRpb24sXG4gIEluamVjdGFibGUsXG4gIE5vdEFjY2VwdGFibGVFeGNlcHRpb24sXG4gIE5vdEZvdW5kRXhjZXB0aW9uLFxuICBPcHRpb25hbCxcbiAgVW5hdXRob3JpemVkRXhjZXB0aW9uLFxuICBVbnByb2Nlc3NhYmxlRW50aXR5RXhjZXB0aW9uLFxufSBmcm9tIFwiQG5lc3Rqcy9jb21tb25cIjtcbmltcG9ydCB7IENvbnRleHRJZEZhY3RvcnksIE1vZHVsZVJlZiB9IGZyb20gXCJAbmVzdGpzL2NvcmVcIjtcbmltcG9ydCB7XG4gIEJhZFJlcXVlc3RFcnJvcixcbiAgQmFzZUVycm9yLFxuICBDb25mbGljdEVycm9yLFxuICBJbnRlcm5hbEVycm9yLFxuICBWYWxpZGF0aW9uRXJyb3IsXG59IGZyb20gXCJAZGVjYWYtdHMvZGItZGVjb3JhdG9yc1wiO1xuaW1wb3J0IHsgTG9nZ2VkRW52aXJvbm1lbnQsIExvZ2dpbmcgfSBmcm9tIFwiQGRlY2FmLXRzL2xvZ2dpbmdcIjtcbmltcG9ydCB7IEF1dGhvcml6YXRpb25FcnJvciwgRm9yYmlkZGVuRXJyb3IsIFVuc3VwcG9ydGVkRXJyb3IgfSBmcm9tIFwiQGRlY2FmLXRzL2NvcmVcIjtcbmltcG9ydCB7IFRvTWFueVJlcXVlc3RzRXJyb3IgfSBmcm9tIFwiLi4vZXJyb3JzL3Rocm90dGxpbmdcIjtcbmltcG9ydCB7IERlY2FmUmVxdWVzdENvbnRleHQgfSBmcm9tIFwiLi4vLi4vcmVxdWVzdC9EZWNhZlJlcXVlc3RDb250ZXh0XCI7XG5pbXBvcnQgdHlwZSB7IFJlcXVlc3RMb2dnZXIgfSBmcm9tIFwiQGRlY2FmLXRzL2Zvci1odHRwL3NlcnZlclwiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBNYXBzIHdlbGwta25vd24gTmVzdEpTIGBIdHRwRXhjZXB0aW9uYCBzdWJjbGFzc2VzIChhcyBndWFyZHMsIHBpcGVzLCBvclxuICogb3RoZXIgZnJhbWV3b3JrLWxldmVsIGNvZGUgd291bGQgdGhyb3cgdGhlbSkgb250byB0aGUgZXF1aXZhbGVudCBkZWNhZi10cyBgQmFzZUVycm9yYC5cbiAqIEBzdW1tYXJ5IE9ubHkgYEJhc2VFcnJvcmAgaW5zdGFuY2VzIGNhcnJ5IHRoZSBgLmNvZGVgIHRoZSByZXNwb25zZSBib2R5IHJlbGllcyBvbiwgc29cbiAqIHdpdGhvdXQgdGhpcyBtYXAgZXZlcnkgbm9uLWRlY2FmIGV4Y2VwdGlvbiDigJQgaW5jbHVkaW5nIHBlcmZlY3RseSBsZWdpdGltYXRlIG9uZXMgbGlrZSBhXG4gKiBndWFyZCdzIGBGb3JiaWRkZW5FeGNlcHRpb25gIOKAlCB3b3VsZCBiZSBmbGF0dGVuZWQgaW50byBhIGdlbmVyaWMgNTAwIGBJbnRlcm5hbEVycm9yYC5cbiAqL1xuY29uc3QgSFRUUF9FWENFUFRJT05fVE9fREVDQUZfRVJST1IgPSBuZXcgTWFwPFxuICBuZXcgKC4uLmFyZ3M6IGFueVtdKSA9PiBIdHRwRXhjZXB0aW9uLFxuICAobXNnOiBzdHJpbmcpID0+IEJhc2VFcnJvclxuPihbXG4gIFtVbmF1dGhvcml6ZWRFeGNlcHRpb24sIChtc2cpID0+IG5ldyBBdXRob3JpemF0aW9uRXJyb3IobXNnKV0sXG4gIFtGb3JiaWRkZW5FeGNlcHRpb24sIChtc2cpID0+IG5ldyBGb3JiaWRkZW5FcnJvcihtc2cpXSxcbiAgW0JhZFJlcXVlc3RFeGNlcHRpb24sIChtc2cpID0+IG5ldyBCYWRSZXF1ZXN0RXJyb3IobXNnKV0sXG4gIFtDb25mbGljdEV4Y2VwdGlvbiwgKG1zZykgPT4gbmV3IENvbmZsaWN0RXJyb3IobXNnKV0sXG4gIFtVbnByb2Nlc3NhYmxlRW50aXR5RXhjZXB0aW9uLCAobXNnKSA9PiBuZXcgVmFsaWRhdGlvbkVycm9yKG1zZyldLFxuXSk7XG5cbkBDYXRjaCgpXG5ASW5qZWN0YWJsZSgpXG5leHBvcnQgY2xhc3MgRGVjYWZFeGNlcHRpb25GaWx0ZXIgaW1wbGVtZW50cyBFeGNlcHRpb25GaWx0ZXIge1xuICBjb25zdHJ1Y3RvcihAT3B0aW9uYWwoKSBwcm90ZWN0ZWQgcmVhZG9ubHkgbW9kdWxlUmVmPzogTW9kdWxlUmVmKSB7fVxuXG4gIGFzeW5jIGNhdGNoKGV4Y2VwdGlvbjogRXJyb3IsIGhvc3Q6IEFyZ3VtZW50c0hvc3QpIHtcbiAgICBjb25zdCBjdHggPSBob3N0LnN3aXRjaFRvSHR0cCgpO1xuICAgIGNvbnN0IHJlc3BvbnNlID0gY3R4LmdldFJlc3BvbnNlKCk7XG4gICAgY29uc3QgcmVxdWVzdCA9IGN0eC5nZXRSZXF1ZXN0KCk7XG5cbiAgICBjb25zdCBpc1Byb2R1Y3Rpb24gPSBMb2dnZWRFbnZpcm9ubWVudC5lbnYgPT09IFwicHJvZHVjdGlvblwiO1xuICAgIGxldCBzdGF0dXNDb2RlO1xuXG4gICAgaWYgKFxuICAgICAgZXhjZXB0aW9uIGluc3RhbmNlb2YgTm90Rm91bmRFeGNlcHRpb24gfHxcbiAgICAgIGV4Y2VwdGlvbiBpbnN0YW5jZW9mIFVuc3VwcG9ydGVkRXJyb3JcbiAgICApIHtcbiAgICAgIGV4Y2VwdGlvbiA9IG5ldyBOb3RBY2NlcHRhYmxlRXhjZXB0aW9uKGV4Y2VwdGlvbi5tZXNzYWdlKTtcbiAgICAgIHN0YXR1c0NvZGUgPSAoZXhjZXB0aW9uIGFzIE5vdEFjY2VwdGFibGVFeGNlcHRpb24pLmdldFN0YXR1cygpO1xuICAgIH0gZWxzZSBpZiAoIShleGNlcHRpb24gaW5zdGFuY2VvZiBCYXNlRXJyb3IpKSB7XG4gICAgICBjb25zdCB0b0RlY2FmRXJyb3IgPSB0aGlzLmRlY2FmRXJyb3JGb3IoZXhjZXB0aW9uKTtcbiAgICAgIGlmICh0b0RlY2FmRXJyb3IpIHtcbiAgICAgICAgZXhjZXB0aW9uID0gdG9EZWNhZkVycm9yKGV4Y2VwdGlvbi5tZXNzYWdlKTtcbiAgICAgIH0gZWxzZSBpZiAoKGV4Y2VwdGlvbiBhcyBhbnkpLnN0YXR1cyA9PT0gNDI5KSB7XG4gICAgICAgIGV4Y2VwdGlvbiA9IG5ldyBUb01hbnlSZXF1ZXN0c0Vycm9yKGV4Y2VwdGlvbi5tZXNzYWdlKTtcbiAgICAgIH0gZWxzZSBpZiAoZXhjZXB0aW9uIGluc3RhbmNlb2YgSHR0cEV4Y2VwdGlvbikge1xuICAgICAgICAvLyBBIHJlY29nbml6ZWQgYnV0IHVubWFwcGVkIEh0dHBFeGNlcHRpb24gKGUuZy4gdGhyb3duIGJ5IGEgZ3VhcmQgb3JcbiAgICAgICAgLy8gcGlwZSkg4oCUIHByZXNlcnZlIGl0cyByZWFsIHN0YXR1cyBpbnN0ZWFkIG9mIGZsYXR0ZW5pbmcgaXQgdG8gNTAwLlxuICAgICAgICBzdGF0dXNDb2RlID0gZXhjZXB0aW9uLmdldFN0YXR1cygpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZXhjZXB0aW9uID0gbmV3IEludGVybmFsRXJyb3IoZXhjZXB0aW9uLm1lc3NhZ2UpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGF3YWl0IHRoaXMubG9nRXJyb3IocmVxdWVzdCwgZXhjZXB0aW9uKTtcblxuICAgIHJlc3BvbnNlLnN0YXR1cygoZXhjZXB0aW9uIGFzIEJhc2VFcnJvcikuY29kZSB8fCBzdGF0dXNDb2RlKS5qc29uKHtcbiAgICAgIHN0YXR1czogKGV4Y2VwdGlvbiBhcyBCYXNlRXJyb3IpLmNvZGUgfHwgc3RhdHVzQ29kZSxcbiAgICAgIGVycm9yOiBpc1Byb2R1Y3Rpb24gPyBleGNlcHRpb24ubmFtZSA6IGV4Y2VwdGlvbi5tZXNzYWdlLFxuICAgICAgdGltZXN0YW1wOiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCksXG4gICAgICBwYXRoOiByZXF1ZXN0LnVybCxcbiAgICAgIG1ldGhvZDogcmVxdWVzdC5tZXRob2QsXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIEZpbmRzIHRoZSBkZWNhZi10cyBgQmFzZUVycm9yYCBjb25zdHJ1Y3RvciBtYXBwZWQgdG8gdGhpcyBleGNlcHRpb24ncyB0eXBlLCBpZiBhbnkuXG4gICAqIEBzdW1tYXJ5IFdhbGtzIGBIVFRQX0VYQ0VQVElPTl9UT19ERUNBRl9FUlJPUmAgd2l0aCBgaW5zdGFuY2VvZmAgKHJhdGhlciB0aGFuIGEgc3RyYWlnaHRcbiAgICogYE1hcC5nZXRgKSBzbyBzdWJjbGFzc2VzIG9mIGEgbWFwcGVkIGV4Y2VwdGlvbiBhcmUgbWF0Y2hlZCB0b28uXG4gICAqL1xuICBwcm90ZWN0ZWQgZGVjYWZFcnJvckZvcihcbiAgICBleGNlcHRpb246IEVycm9yXG4gICk6ICgobXNnOiBzdHJpbmcpID0+IEJhc2VFcnJvcikgfCB1bmRlZmluZWQge1xuICAgIGZvciAoY29uc3QgW3R5cGUsIGZhY3RvcnldIG9mIEhUVFBfRVhDRVBUSU9OX1RPX0RFQ0FGX0VSUk9SKSB7XG4gICAgICBpZiAoZXhjZXB0aW9uIGluc3RhbmNlb2YgdHlwZSkgcmV0dXJuIGZhY3Rvcnk7XG4gICAgfVxuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIExvZ3MgdGhlIGV4Y2VwdGlvbiB3aXRob3V0IGV2ZXIgbGV0dGluZyBsb2dnaW5nIGZhaWx1cmVzIGJsb2NrIHRoZSByZXNwb25zZS5cbiAgICogQHN1bW1hcnkgQSBndWFyZCAob3IgbWlkZGxld2FyZS9DT1JTIGNoZWNrKSBjYW4gdGhyb3cgYmVmb3JlIGFueSBkZWNhZi1hd2FyZSBwcm92aWRlciByYW4sXG4gICAqIHNvIHRoZSByZXF1ZXN0LWJvdW5kIENvbnRleHQgbWF5IG5vdCBleGlzdCB5ZXQg4oCUIG9yIHRoZSByZXNvbHZlZCBsb2dnZXIncyBgLmVycm9yKClgIGl0c2VsZlxuICAgKiBjb3VsZCB0aHJvdyAoYnJva2VuIHRyYW5zcG9ydCwgZm9ybWF0dGVyIGJ1ZywgZXRjLikuIEVpdGhlciB3YXkgdGhlIGNsaWVudC1mYWNpbmcgZXJyb3JcbiAgICogcmVzcG9uc2UgYmVsb3cgbXVzdCBzdGlsbCBnbyBvdXQsIHNvIGV2ZXJ5IGZhaWx1cmUgbW9kZSBoZXJlIGlzIHN3YWxsb3dlZCwgZmFsbGluZyBiYWNrIHRvXG4gICAqIHRoZSBwbGFpbiBgTG9nZ2luZy5nZXQoKWAgbG9nZ2VyIGFuZCwgYXMgYSBsYXN0IHJlc29ydCwgZG9pbmcgbm90aGluZyBhdCBhbGwuXG4gICAqL1xuICBwcm90ZWN0ZWQgYXN5bmMgbG9nRXJyb3IoXG4gICAgcmVxdWVzdDogUmVjb3JkPHN0cmluZywgYW55PixcbiAgICBleGNlcHRpb246IEVycm9yXG4gICk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IG1lc3NhZ2UgPSBgVW5oYW5kbGVkIGVycm9yIG9uICR7cmVxdWVzdD8ubWV0aG9kfSAke3JlcXVlc3Q/LnVybH1gO1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBsb2cgPSBhd2FpdCB0aGlzLnJlc29sdmVMb2dnZXIocmVxdWVzdCk7XG4gICAgICBsb2cuZXJyb3IobWVzc2FnZSwgZXhjZXB0aW9uKTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIExvZ2dpbmcuZ2V0KCkuZXJyb3IobWVzc2FnZSwgZXhjZXB0aW9uKTtcbiAgICAgIH0gY2F0Y2gge1xuICAgICAgICAvLyBsb2dnaW5nIGlzIHVuYXZhaWxhYmxlIOKAlCB0aGUgcmVzcG9uc2UgaXMgc3RpbGwgc2VudCBiZWxvd1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb24gUmVzb2x2ZXMgdGhlIGxvZ2dlciBib3VuZCB0byB0aGUgb3JpZ2luYXRpbmcgcmVxdWVzdCdzIGRlY2FmLXRzIENvbnRleHQuXG4gICAqIEBzdW1tYXJ5IEdsb2JhbCBmaWx0ZXJzIGFyZSBzaW5nbGV0b25zLCBzbyB0aGUgcmVxdWVzdC1zY29wZWQge0BsaW5rIERlY2FmUmVxdWVzdENvbnRleHR9XG4gICAqIChhbmQgdGhlIGNsaWVudC91c2VyLWJvdW5kIGxvZ2dlciBpdCBjYXJyaWVzKSBjYW4ndCBiZSBjb25zdHJ1Y3Rvci1pbmplY3RlZC4gSW5zdGVhZCwgdGhpc1xuICAgKiBsb29rcyB1cCB0aGUgc2FtZSByZXF1ZXN0J3MgY29udGV4dCBpZCBhbmQgcmUtcmVzb2x2ZXMgdGhlIGFscmVhZHktYWNjdW11bGF0ZWQgaW5zdGFuY2VcbiAgICogdGhyb3VnaCBgTW9kdWxlUmVmYC4gRmFsbHMgYmFjayB0byB0aGUgZ2VuZXJpYyBgTG9nZ2luZy5nZXQoKWAgbG9nZ2VyIHdoZW4gdGhlIGZpbHRlciB3YXNuJ3RcbiAgICogY29uc3RydWN0ZWQgd2l0aCBhIGBNb2R1bGVSZWZgIChlLmcuIG1hbnVhbGx5IGBuZXdgJ2QpIG9yIG5vIHJlcXVlc3Qtc2NvcGVkIGNvbnRleHQgZXhpc3RzXG4gICAqIGZvciB0aGlzIHJlcXVlc3QgKGUuZy4gdGhlIGVycm9yIGhhcHBlbmVkIGJlZm9yZSBhbnkgZGVjYWYtYXdhcmUgcHJvdmlkZXIgcmFuLCBhcyBpcyB0aGVcbiAgICogY2FzZSB3aGVuIGEgZ3VhcmQgcmVqZWN0cyB0aGUgcmVxdWVzdCBiZWZvcmUgaW50ZXJjZXB0b3JzIGdldCB0byBiaW5kIHRoZSBjbGllbnQtc2NvcGVkXG4gICAqIGxvZ2dlciBvbnRvIHRoZSBDb250ZXh0KS5cbiAgICovXG4gIHByb3RlY3RlZCBhc3luYyByZXNvbHZlTG9nZ2VyKFxuICAgIHJlcXVlc3Q6IFJlY29yZDxzdHJpbmcsIGFueT5cbiAgKTogUHJvbWlzZTxSZXF1ZXN0TG9nZ2VyPiB7XG4gICAgaWYgKHRoaXMubW9kdWxlUmVmKSB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCBjb250ZXh0SWQgPSBDb250ZXh0SWRGYWN0b3J5LmdldEJ5UmVxdWVzdChyZXF1ZXN0KTtcbiAgICAgICAgY29uc3QgcmVxdWVzdENvbnRleHQgPSBhd2FpdCB0aGlzLm1vZHVsZVJlZi5yZXNvbHZlKFxuICAgICAgICAgIERlY2FmUmVxdWVzdENvbnRleHQsXG4gICAgICAgICAgY29udGV4dElkLFxuICAgICAgICAgIHsgc3RyaWN0OiBmYWxzZSB9XG4gICAgICAgICk7XG4gICAgICAgIGlmIChyZXF1ZXN0Q29udGV4dD8ubG9nZ2VyKSByZXR1cm4gcmVxdWVzdENvbnRleHQubG9nZ2VyO1xuICAgICAgfSBjYXRjaCB7XG4gICAgICAgIC8vIG5vIHJlcXVlc3Qtc2NvcGVkIGNvbnRleHQgYm91bmQgZm9yIHRoaXMgcmVxdWVzdCDigJQgZmFsbCBiYWNrIGJlbG93XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBMb2dnaW5nLmdldCgpIGFzIHVua25vd24gYXMgUmVxdWVzdExvZ2dlcjtcbiAgfVxufVxuIiwiaW1wb3J0IHsgVXNlRmlsdGVycywgVXNlSW50ZXJjZXB0b3JzIH0gZnJvbSBcIkBuZXN0anMvY29tbW9uXCI7XG5pbXBvcnQgeyBEZWNhZkV4Y2VwdGlvbkZpbHRlciB9IGZyb20gXCIuL0RlY2FmRXJyb3JGaWx0ZXJcIjtcbmltcG9ydCB7IERlY2FmUmVzcG9uc2VJbnRlcmNlcHRvciB9IGZyb20gXCIuLi8uLi9yZXF1ZXN0L2luZGV4XCI7XG5cbi8vIE5vIE1vZHVsZVJlZiBhdmFpbGFibGUgYXQgZGVjb3JhdGlvbiB0aW1lLCBzbyB0aGlzIGluc3RhbmNlIGZhbGxzIGJhY2sgdG9cbi8vIExvZ2dpbmcuZ2V0KCkgcmF0aGVyIHRoYW4gdGhlIHJlcXVlc3QtYm91bmQgY29udGV4dCBsb2dnZXI7IHByZWZlclxuLy8gTmVzdEJvb3RzdHJhcGVyLnVzZUdsb2JhbEZpbHRlcnMoKSBmb3IgY29udGV4dC1hd2FyZSBlcnJvciBsb2dnaW5nLlxuZXhwb3J0IGZ1bmN0aW9uIFVzZURlY2FmRmlsdGVyKCkge1xuICByZXR1cm4gVXNlRmlsdGVycyhuZXcgRGVjYWZFeGNlcHRpb25GaWx0ZXIoKSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBVc2VEZWNhZkhlYWRlcnMoKSB7XG4gIHJldHVybiBVc2VJbnRlcmNlcHRvcnMoRGVjYWZSZXNwb25zZUludGVyY2VwdG9yKTtcbn1cbiIsImltcG9ydCB7IENvbnN0cnVjdG9yIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0aW9uXCI7XG5pbXBvcnQgeyBTZWN1cml0eVNjaGVtZU9iamVjdCB9IGZyb20gXCIuLi8uLi9zd2FnZ2VyLXR5cGVzXCI7XG5cbmV4cG9ydCBpbnRlcmZhY2UgU3dhZ2dlck9wdGlvbnMge1xuICB0aXRsZTogc3RyaW5nO1xuICBkZXNjcmlwdGlvbjogc3RyaW5nO1xuICB2ZXJzaW9uPzogc3RyaW5nO1xuICBhc3NldHNQYXRoPzogc3RyaW5nO1xuICBmYXZpY29uRmlsZVBhdGg/OiBzdHJpbmc7XG4gIHRvcGJhckljb25GaWxlUGF0aD86IHN0cmluZztcbiAgcGVyc2lzdEF1dGhvcml6YXRpb24/OiBib29sZWFuO1xuICBwYXRoOiBzdHJpbmc7XG4gIGF1dGg/OiBTZWN1cml0eVNjaGVtZU9iamVjdDtcbiAgdG9wYmFyQmdDb2xvcj86IHN0cmluZztcbiAgZXh0cmFNb2RlbHM/OiBDb25zdHJ1Y3RvcltdO1xuXG4gIC8qKlxuICAgKiBQYXRoIHRvIGV4cG9zZSB0aGUgT3BlbkFQSSBzcGVjaWZpY2F0aW9uIGluIEpTT04gZm9ybWF0LlxuICAgKiBFeGFtcGxlOiAvYXBpL29wZW5hcGkuanNvblxuICAgKi9cbiAgb3BlbkFwaUpzb25QYXRoPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBQYXRoIHRvIGV4cG9zZSB0aGUgT3BlbkFQSSBzcGVjaWZpY2F0aW9uIGluIFlBTUwgZm9ybWF0LlxuICAgKiBSZXF1aXJlcyAneWFtbCcgcGFja2FnZSBhcyBwZWVyIGRlcGVuZGVuY3kuXG4gICAqIEV4YW1wbGU6IC9hcGkvb3BlbmFwaS55YW1sXG4gICAqL1xuICBvcGVuQXBpWWFtbFBhdGg/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCBjb25zdCBTV0FHR0VSX1VJX0NPTlNUQU5UUzogU3dhZ2dlck9wdGlvbnMgPSB7XG4gIHRpdGxlOiBcIlN3YWdnZXIgfCBPcGVuQVBJIFNwZWNpZmljYXRpb24gKE9BUylcIixcbiAgZGVzY3JpcHRpb246IFwiU3RhbmRhcmRpemVkIGZvcm1hdCBmb3IgZGVzY3JpYmluZyBSRVNUZnVsIEFQSXNcIixcbiAgdmVyc2lvbjogXCIwLjAuMVwiLFxuICBwYXRoOiBcImRvY3NcIixcbiAgZmF2aWNvbkZpbGVQYXRoOiBcIlwiLFxuICB0b3BiYXJJY29uRmlsZVBhdGg6IFwiXCIsXG4gIGF1dGg6IHtcbiAgICB0eXBlOiBcImh0dHBcIixcbiAgICBzY2hlbWU6IFwiYmVhcmVyXCIsXG4gICAgYmVhcmVyRm9ybWF0OiBcIkpXVFwiLFxuICAgIG5hbWU6IFwiQXV0aG9yaXphdGlvblwiLFxuICAgIGRlc2NyaXB0aW9uOiBcIkVudGVyIEpXVCB0b2tlblwiLFxuICAgIGluOiBcImhlYWRlclwiLFxuICB9LFxuICBwZXJzaXN0QXV0aG9yaXphdGlvbjogdHJ1ZSxcbiAgdG9wYmFyQmdDb2xvcjogXCIjMDAwMDAwXCIsXG59O1xuIiwiaW1wb3J0IHsgU1dBR0dFUl9VSV9DT05TVEFOVFMgfSBmcm9tIFwiLi9jb25zdGFudHNcIjtcbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gXCJmc1wiO1xuaW1wb3J0ICogYXMgcGF0aCBmcm9tIFwicGF0aFwiO1xuXG5leHBvcnQgaW50ZXJmYWNlIFN3YWdnZXJVSU9wdGlvbnMge1xuICB0aXRsZT86IHN0cmluZztcbiAgcGF0aD86IHN0cmluZztcbiAgcGVyc2lzdEF1dGhvcml6YXRpb246IGJvb2xlYW47XG4gIGFzc2V0c1BhdGg/OiBzdHJpbmc7XG4gIGZhdmljb25QYXRoPzogc3RyaW5nO1xuICB0b3BiYXJJY29uUGF0aD86IHN0cmluZztcbiAgdG9wYmFyQmdDb2xvcj86IHN0cmluZztcbn1cblxuZXhwb3J0IGNsYXNzIFN3YWdnZXJDdXN0b21VSSB7XG4gIHJlYWRvbmx5IG9wdGlvbnM6IFN3YWdnZXJVSU9wdGlvbnM7XG4gIC8vIHByaXZhdGUgcmVhZG9ubHkgYXNzZXRzUGF0aDogc3RyaW5nID0gcGF0aC5qb2luKFxuICAvLyAgIF9fZGlybmFtZSxcbiAgLy8gICBcIi4uXCIsXG4gIC8vICAgXCIuLlwiLFxuICAvLyAgIFwid29ya2RvY3NcIixcbiAgLy8gICBcImFzc2V0c1wiXG4gIC8vICk7XG5cbiAgY29uc3RydWN0b3Iob3B0aW9uczogU3dhZ2dlclVJT3B0aW9ucykge1xuICAgIHRoaXMub3B0aW9ucyA9IHtcbiAgICAgIC4uLm9wdGlvbnMsXG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgY3VzdG9tQ1NTKCkge1xuICAgIGxldCBjc3MgPSBcIlwiO1xuICAgIGlmICh0aGlzLm9wdGlvbnMudG9wYmFySWNvblBhdGgpIHtcbiAgICAgIGNvbnN0IGltZyA9IHRoaXMuYjY0KHRoaXMub3B0aW9ucy50b3BiYXJJY29uUGF0aCk7XG4gICAgICBjc3MgKz0gYC50b3BiYXItd3JhcHBlciB7IGNvbnRlbnQ6IHVybCgnZGF0YTppbWFnZS9wbmc7YmFzZTY0LCR7aW1nfScpOyB3aWR0aDogMjAwcHg7IGhlaWdodDogYXV0bzsgfVxcbmA7XG4gICAgfVxuICAgIHJldHVybiAoXG4gICAgICBjc3MgK1xuICAgICAgYFxuICAgICAgICAudG9wYmFyLXdyYXBwZXIgc3ZnIHsgdmlzaWJpbGl0eTogaGlkZGVuOyB9XG4gICAgICAgIC5zd2FnZ2VyLXVpIC50b3BiYXIgeyBiYWNrZ3JvdW5kLWNvbG9yOiAke3RoaXMub3B0aW9ucy50b3BiYXJCZ0NvbG9yIHx8IFNXQUdHRVJfVUlfQ09OU1RBTlRTLnRvcGJhckJnQ29sb3J9OyB9XG4gICAgICBgXG4gICAgKTtcbiAgfVxuXG4gIGdldEN1c3RvbU9wdGlvbnMoKSB7XG4gICAgY29uc3QgZmF2aWNvbjogUmVjb3JkPHN0cmluZywgYW55PiA9IHt9O1xuICAgIGlmICh0aGlzLm9wdGlvbnMuZmF2aWNvblBhdGgpIHtcbiAgICAgIGZhdmljb25bXCJjdXN0b21mYXZJY29uXCJdID0gdGhpcy5iNjQodGhpcy5vcHRpb25zLmZhdmljb25QYXRoLCB0cnVlKTtcbiAgICB9XG5cbiAgICByZXR1cm4ge1xuICAgICAgY3VzdG9tU2l0ZVRpdGxlOiB0aGlzLm9wdGlvbnMudGl0bGUsXG4gICAgICAuLi5mYXZpY29uLFxuICAgICAgY3VzdG9tQ3NzOiB0aGlzLmN1c3RvbUNTUygpLFxuICAgICAgc3dhZ2dlck9wdGlvbnM6IHtcbiAgICAgICAgcGVyc2lzdEF1dGhvcml6YXRpb246IHRoaXMub3B0aW9ucy5wZXJzaXN0QXV0aG9yaXphdGlvbixcbiAgICAgIH0sXG4gICAgfTtcbiAgfVxuXG4gIGI2NChmaWxlOiBzdHJpbmcsIGltZzogYm9vbGVhbiA9IGZhbHNlKSB7XG4gICAgY29uc3QgZmlsZVBhdGggPSBwYXRoLmpvaW4odGhpcy5vcHRpb25zLmFzc2V0c1BhdGggfHwgXCJcIiwgZmlsZSk7XG4gICAgY29uc3QgYjY0ID0gcmVhZEZpbGVTeW5jKGZpbGVQYXRoLCB7IGVuY29kaW5nOiBcImJhc2U2NFwiIH0pO1xuICAgIHJldHVybiBpbWcgPyBcImRhdGE6aW1hZ2UvcG5nO2Jhc2U2NCxcIiArIGI2NCA6IGI2NDtcbiAgfVxufVxuIiwiaW1wb3J0IHsgSU5lc3RBcHBsaWNhdGlvbiB9IGZyb20gXCJAbmVzdGpzL2NvbW1vblwiO1xuaW1wb3J0IHsgRG9jdW1lbnRCdWlsZGVyLCBTd2FnZ2VyTW9kdWxlIH0gZnJvbSBcIkBuZXN0anMvc3dhZ2dlclwiO1xuaW1wb3J0IHsgU3dhZ2dlckN1c3RvbVVJIH0gZnJvbSBcIi4vU3dhZ2dlckN1c3RvbVVJXCI7XG5pbXBvcnQgeyBTV0FHR0VSX1VJX0NPTlNUQU5UUywgU3dhZ2dlck9wdGlvbnMgfSBmcm9tIFwiLi9jb25zdGFudHNcIjtcbmltcG9ydCBZQU1MIGZyb20gXCJ5YW1sXCI7XG5cbmV4cG9ydCBjbGFzcyBTd2FnZ2VyQnVpbGRlciB7XG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgcmVhZG9ubHkgYXBwOiBJTmVzdEFwcGxpY2F0aW9uLFxuICAgIHByaXZhdGUgcmVhZG9ubHkgb3B0aW9uczogU3dhZ2dlck9wdGlvbnNcbiAgKSB7fVxuXG4gIHByaXZhdGUgY3JlYXRlRG9jdW1lbnQoKSB7XG4gICAgY29uc3QgZGVzY3JpcHRpb24gPSB0aGlzLm9wdGlvbnMucGF0aFxuICAgICAgPyB0aGlzLm9wdGlvbnMuZGVzY3JpcHRpb24gK1xuICAgICAgICBcIlwiICtcbiAgICAgICAgYDxicj48YnI+PGEgaHJlZj1cIiR7dGhpcy5vcHRpb25zLm9wZW5BcGlKc29uUGF0aH1cIj5PcGVuQVBJIEpTT04gU3BlYzwvYT4gfCBgICtcbiAgICAgICAgYDxhIGhyZWY9XCIke3RoaXMub3B0aW9ucy5vcGVuQXBpWWFtbFBhdGh9XCI+T3BlbkFQSSBZQU1MIFNwZWM8L2E+YFxuICAgICAgOiB0aGlzLm9wdGlvbnMuZGVzY3JpcHRpb247XG5cbiAgICBjb25zdCBjb25maWcgPSBuZXcgRG9jdW1lbnRCdWlsZGVyKClcbiAgICAgIC5zZXRUaXRsZSh0aGlzLm9wdGlvbnMudGl0bGUpXG4gICAgICAuc2V0RGVzY3JpcHRpb24oZGVzY3JpcHRpb24pXG4gICAgICAuc2V0VmVyc2lvbih0aGlzLm9wdGlvbnMudmVyc2lvbiB8fCBcIjAuMC4xXCIpXG4gICAgICAuYWRkQmVhcmVyQXV0aCh0aGlzLm9wdGlvbnMuYXV0aCB8fCBTV0FHR0VSX1VJX0NPTlNUQU5UUy5hdXRoKVxuICAgICAgLmJ1aWxkKCk7XG5cbiAgICByZXR1cm4gU3dhZ2dlck1vZHVsZS5jcmVhdGVEb2N1bWVudCh0aGlzLmFwcCwgY29uZmlnLCB7XG4gICAgICBleHRyYU1vZGVsczogdGhpcy5vcHRpb25zLmV4dHJhTW9kZWxzIHx8IFtdLFxuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSByZWdpc3Rlck9wZW5BcGlSb3V0ZShcbiAgICBwYXRoOiBzdHJpbmcgfCB1bmRlZmluZWQsXG4gICAgY29udGVudFR5cGU6IFwiYXBwbGljYXRpb24vanNvblwiIHwgXCJhcHBsaWNhdGlvbi94LXlhbWxcIixcbiAgICBib2R5RmFjdG9yeTogKCkgPT4gdm9pZFxuICApOiB2b2lkIHtcbiAgICBpZiAoIXBhdGgpIHJldHVybjtcblxuICAgIGNvbnN0IGh0dHBBZGFwdGVyID0gdGhpcy5hcHAuZ2V0SHR0cEFkYXB0ZXIoKSBhcyBhbnk7XG4gICAgcGF0aCA9IHBhdGguc3RhcnRzV2l0aChcIi9cIikgPyBwYXRoIDogYC8ke3BhdGh9YDtcbiAgICBodHRwQWRhcHRlci5nZXQocGF0aCwgKF9yZXE6IGFueSwgcmVzOiBhbnkpID0+IHtcbiAgICAgIGh0dHBBZGFwdGVyLnJlcGx5KHJlcywgYm9keUZhY3RvcnkoKSwgMjAwLCB7XG4gICAgICAgIFwiQ29udGVudC1UeXBlXCI6IGNvbnRlbnRUeXBlLFxuICAgICAgfSk7XG4gICAgfSk7XG4gIH1cblxuICBwdWJsaWMgc2V0dXBTd2FnZ2VyKCkge1xuICAgIGNvbnN0IGRvY3VtZW50ID0gdGhpcy5jcmVhdGVEb2N1bWVudCgpO1xuICAgIGNvbnN0IHN3YWdnZXJVSSA9IG5ldyBTd2FnZ2VyQ3VzdG9tVUkoe1xuICAgICAgdGl0bGU6IHRoaXMub3B0aW9ucy50aXRsZSxcbiAgICAgIHBhdGg6IHRoaXMub3B0aW9ucy5wYXRoIHx8IFNXQUdHRVJfVUlfQ09OU1RBTlRTLnBhdGgsXG4gICAgICBwZXJzaXN0QXV0aG9yaXphdGlvbjogdGhpcy5vcHRpb25zLnBlcnNpc3RBdXRob3JpemF0aW9uID8/IHRydWUsXG4gICAgICBhc3NldHNQYXRoOiB0aGlzLm9wdGlvbnMuYXNzZXRzUGF0aCxcbiAgICAgIGZhdmljb25QYXRoOiB0aGlzLm9wdGlvbnMuZmF2aWNvbkZpbGVQYXRoLFxuICAgICAgdG9wYmFySWNvblBhdGg6IHRoaXMub3B0aW9ucy50b3BiYXJJY29uRmlsZVBhdGgsXG4gICAgICB0b3BiYXJCZ0NvbG9yOiB0aGlzLm9wdGlvbnMudG9wYmFyQmdDb2xvcixcbiAgICB9KTtcbiAgICBTd2FnZ2VyTW9kdWxlLnNldHVwKFxuICAgICAgdGhpcy5vcHRpb25zLnBhdGggfHwgU1dBR0dFUl9VSV9DT05TVEFOVFMucGF0aCxcbiAgICAgIHRoaXMuYXBwLFxuICAgICAgZG9jdW1lbnQsXG4gICAgICB7XG4gICAgICAgIC4uLnN3YWdnZXJVSS5nZXRDdXN0b21PcHRpb25zKCksXG4gICAgICAgIGpzb25Eb2N1bWVudFVybDogdGhpcy5vcHRpb25zLm9wZW5BcGlKc29uUGF0aFxuICAgICAgICAgID8gYCR7dGhpcy5vcHRpb25zLm9wZW5BcGlKc29uUGF0aH1gXG4gICAgICAgICAgOiB1bmRlZmluZWQsXG4gICAgICAgIHlhbWxEb2N1bWVudFVybDogdGhpcy5vcHRpb25zLm9wZW5BcGlZYW1sUGF0aFxuICAgICAgICAgID8gYCR7dGhpcy5vcHRpb25zLm9wZW5BcGlZYW1sUGF0aH1gXG4gICAgICAgICAgOiB1bmRlZmluZWQsXG4gICAgICB9XG4gICAgKTtcblxuICAgIHRoaXMucmVnaXN0ZXJPcGVuQXBpUm91dGUoXG4gICAgICB0aGlzLm9wdGlvbnMub3BlbkFwaUpzb25QYXRoLFxuICAgICAgXCJhcHBsaWNhdGlvbi9qc29uXCIsXG4gICAgICAoKSA9PiBkb2N1bWVudFxuICAgICk7XG5cbiAgICB0aGlzLnJlZ2lzdGVyT3BlbkFwaVJvdXRlKFxuICAgICAgdGhpcy5vcHRpb25zLm9wZW5BcGlZYW1sUGF0aCxcbiAgICAgIFwiYXBwbGljYXRpb24veC15YW1sXCIsXG4gICAgICAoKSA9PiBZQU1MLnN0cmluZ2lmeShkb2N1bWVudClcbiAgICApO1xuICB9XG5cbiAgLy8gcHJpdmF0ZSBnZXRWZXJzaW9uKCkge1xuICAvLyAgIC8vIGNvbnN0IHBhY2thZ2VKc29uID0gcGF0aC5qb2luKF9fZGlybmFtZSwgXCIuLlwiLCBcIi4uXCIsIFwicGFja2FnZS5qc29uXCIpO1xuICAvLyAgIC8vIGNvbnN0IHt2ZXJzaW9ufSA9IHJlcXVpcmUocGFja2FnZUpzb24pO1xuICAvLyAgIHJldHVybiBcInZlcnNpb25cIjtcbiAgLy8gfVxufVxuIiwiaW1wb3J0IHtcbiAgSU5lc3RBcHBsaWNhdGlvbixcbiAgTG9nZ2VyLFxuICBOZXN0SW50ZXJjZXB0b3IsXG4gIFBpcGVUcmFuc2Zvcm0sXG59IGZyb20gXCJAbmVzdGpzL2NvbW1vblwiO1xuaW1wb3J0IHsgTW9kdWxlUmVmIH0gZnJvbSBcIkBuZXN0anMvY29yZVwiO1xuaW1wb3J0IHsgRGVjYWZFeGNlcHRpb25GaWx0ZXIgfSBmcm9tIFwiLi9leGNlcHRpb25zXCI7XG5pbXBvcnQgeyBTd2FnZ2VyQnVpbGRlciB9IGZyb20gXCIuL29wZW5hcGlcIjtcbmltcG9ydCB7IENvcnNPcHRpb25zIH0gZnJvbSBcIkBuZXN0anMvY29tbW9uL2ludGVyZmFjZXMvZXh0ZXJuYWwvY29ycy1vcHRpb25zLmludGVyZmFjZVwiO1xuaW1wb3J0IHsgQ29yc0Vycm9yIH0gZnJvbSBcIi4vZXJyb3JzXCI7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uXG4gKiBEZWZpbmVzIGFsbCBjdXN0b21pemFibGUgcGFyYW1ldGVycyBmb3IgU3dhZ2dlciBzZXR1cC5cbiAqXG4gKiBAc3VtbWFyeVxuICogVGhpcyBpbnRlcmZhY2UgYWxsb3dzIGRldmVsb3BlcnMgdG8gY3VzdG9taXplIGhvdyBTd2FnZ2VyIFVJIGlzIGNvbmZpZ3VyZWRcbiAqIHdpdGhpbiB0aGUgTmVzdEpTIGFwcGxpY2F0aW9uLiBJdCBpbmNsdWRlcyBwYXJhbWV0ZXJzIGZvciB0aXRsZXMsIHBhdGhzLFxuICogY29sb3Igc2NoZW1lcywgYW5kIGFzc2V0IHBhdGhzIHRvIHRhaWxvciB0aGUgQVBJIGRvY3VtZW50YXRpb24gZXhwZXJpZW5jZS5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gdGl0bGUgLSBUaXRsZSBkaXNwbGF5ZWQgaW4gU3dhZ2dlciBVSS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBkZXNjcmlwdGlvbiAtIERlc2NyaXB0aW9uIHNob3duIGJlbG93IHRoZSB0aXRsZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSB2ZXJzaW9uIC0gQVBJIHZlcnNpb24gZGlzcGxheWVkIGluIHRoZSBkb2N1bWVudGF0aW9uLlxuICogQHBhcmFtIHtzdHJpbmd9IFtwYXRoXSAtIE9wdGlvbmFsIHBhdGggd2hlcmUgU3dhZ2dlciB3aWxsIGJlIGF2YWlsYWJsZS5cbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW3BlcnNpc3RBdXRob3JpemF0aW9uXSAtIFdoZXRoZXIgYXV0aG9yaXphdGlvbiB0b2tlbnMgcGVyc2lzdCBhY3Jvc3MgcmVsb2Fkcy5cbiAqIEBwYXJhbSB7c3RyaW5nfSBbYXNzZXRzUGF0aF0gLSBQYXRoIHRvIGN1c3RvbSBhc3NldHMgZm9yIFN3YWdnZXIgVUkuXG4gKiBAcGFyYW0ge3N0cmluZ30gW3RvcGJhckJnQ29sb3JdIC0gQ3VzdG9tIGJhY2tncm91bmQgY29sb3IgZm9yIHRoZSBTd2FnZ2VyIHRvcCBiYXIuXG4gKiBAcGFyYW0ge3N0cmluZ30gW3RvcGJhckljb25QYXRoXSAtIFBhdGggdG8gYSBjdXN0b20gaWNvbiBkaXNwbGF5ZWQgaW4gdGhlIHRvcCBiYXIuXG4gKiBAcGFyYW0ge3N0cmluZ30gW2Zhdmljb25QYXRoXSAtIFBhdGggdG8gYSBjdXN0b20gZmF2aWNvbi5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBTd2FnZ2VyU2V0dXBPcHRpb25zIHtcbiAgdGl0bGU6IHN0cmluZztcbiAgZGVzY3JpcHRpb246IHN0cmluZztcbiAgdmVyc2lvbjogc3RyaW5nO1xuICBwYXRoPzogc3RyaW5nO1xuICBwZXJzaXN0QXV0aG9yaXphdGlvbj86IGJvb2xlYW47XG4gIGFzc2V0c1BhdGg/OiBzdHJpbmc7XG4gIHRvcGJhckJnQ29sb3I/OiBzdHJpbmc7XG4gIHRvcGJhckljb25QYXRoPzogc3RyaW5nO1xuICBmYXZpY29uUGF0aD86IHN0cmluZztcbiAgLyoqXG4gICAqIFBhdGggdG8gZXhwb3NlIHRoZSBPcGVuQVBJIHNwZWNpZmljYXRpb24gaW4gSlNPTiBmb3JtYXQuXG4gICAqIEV4YW1wbGU6IC9hcGkvb3BlbmFwaS5qc29uXG4gICAqL1xuICBvcGVuQXBpSnNvblBhdGg/OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBQYXRoIHRvIGV4cG9zZSB0aGUgT3BlbkFQSSBzcGVjaWZpY2F0aW9uIGluIFlBTUwgZm9ybWF0LlxuICAgKiBSZXF1aXJlcyAneWFtbCcgcGFja2FnZSBhcyBwZWVyIGRlcGVuZGVuY3kuXG4gICAqIEV4YW1wbGU6IC9hcGkvb3BlbmFwaS55YW1sXG4gICAqL1xuICBvcGVuQXBpWWFtbFBhdGg/OiBzdHJpbmc7XG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uXG4gKiBBIGZsdWVudCwgc3RhdGljIGJvb3RzdHJhcCBjbGFzcyBmb3IgaW5pdGlhbGl6aW5nIGFuZCBjb25maWd1cmluZyBhIE5lc3RKUyBhcHBsaWNhdGlvbi5cbiAqXG4gKiBAc3VtbWFyeVxuICogVGhlIGBOZXN0Qm9vdHN0cmFwZXJgIGNsYXNzIHByb3ZpZGVzIGEgY2hhaW5hYmxlIEFQSSBmb3IgY29uZmlndXJpbmdcbiAqIGEgTmVzdEpTIGFwcGxpY2F0aW9uIGluc3RhbmNlLiBJdCBpbmNsdWRlcyBidWlsdC1pbiBtZXRob2RzIGZvciBlbmFibGluZ1xuICogQ09SUywgSGVsbWV0IHNlY3VyaXR5LCBTd2FnZ2VyIGRvY3VtZW50YXRpb24sIGdsb2JhbCBwaXBlcywgZmlsdGVycyxcbiAqIGludGVyY2VwdG9ycywgYW5kIHN0YXJ0aW5nIHRoZSBzZXJ2ZXIuXG4gKlxuICogVGhpcyBjbGFzcyBwcm9tb3RlcyBjb25zaXN0ZW5jeSBhbmQgcmVkdWNlcyByZXBldGl0aXZlIHNldHVwIGNvZGVcbiAqIGFjcm9zcyBtdWx0aXBsZSBOZXN0SlMgcHJvamVjdHMuXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHRzXG4gKiBpbXBvcnQgeyBOZXN0RmFjdG9yeSB9IGZyb20gXCJAbmVzdGpzL2NvcmVcIjtcbiAqIGltcG9ydCB7IEFwcE1vZHVsZSB9IGZyb20gXCIuL2FwcC5tb2R1bGVcIjtcbiAqIGltcG9ydCB7IE15TG9nZ2VyIH0gZnJvbSBcIi4vTXlMb2dnZXJcIjtcbiAqIGltcG9ydCB7IE5lc3RCb290c3RyYXBlciB9IGZyb20gXCJAZGVjYWYtdHMvZm9yLW5lc3RcIjtcbiAqXG4gKiBhc3luYyBmdW5jdGlvbiBib290c3RyYXAoKSB7XG4gKiAgIGNvbnN0IGFwcCA9IGF3YWl0IE5lc3RGYWN0b3J5LmNyZWF0ZShBcHBNb2R1bGUpO1xuICpcbiAqICAgYXdhaXQgTmVzdEJvb3RzdHJhcGVyXG4gKiAgICAgLmluaXRpYWxpemUoYXBwKVxuICogICAgIC5lbmFibGVMb2dnZXIobmV3IE15TG9nZ2VyKCkpXG4gKiAgICAgLmVuYWJsZUNvcnMoW1wiaHR0cDovL2xvY2FsaG9zdDo0MjAwXCJdKVxuICogICAgIC51c2VIZWxtZXQoKVxuICogICAgIC5zZXR1cFN3YWdnZXIoe1xuICogICAgICAgdGl0bGU6IFwiT3BlbkFQSSBieSBUcmFkZU1hcmvihKJcIixcbiAqICAgICAgIGRlc2NyaXB0aW9uOiBcIlRyYWRlTWFya+KEoiBBUEkgZG9jdW1lbnRhdGlvblwiLFxuICogICAgICAgdmVyc2lvbjogXCIxLjAuMFwiLFxuICogICAgICAgcGF0aDogXCJhcGlcIixcbiAqICAgICAgIHBlcnNpc3RBdXRob3JpemF0aW9uOiB0cnVlLFxuICogICAgICAgdG9wYmFyQmdDb2xvcjogXCIjMkMzRTUwXCIsXG4gKiAgICAgICB0b3BiYXJJY29uUGF0aDogXCIvYXNzZXRzL2xvZ28uc3ZnXCIsXG4gKiAgICAgICBmYXZpY29uUGF0aDogXCIvYXNzZXRzL2Zhdmljb24uaWNvXCJcbiAqICAgICB9KVxuICogICAgIC51c2VHbG9iYWxGaWx0ZXJzKClcbiAqICAgICAudXNlR2xvYmFsUGlwZXMoLi4uKVxuICogICAgIC51c2VHbG9iYWxJbnRlcmNlcHRvcnMoLi4uKVxuICogICAgIC5zdGFydCgzMDAwKTtcbiAqIH1cbiAqXG4gKiBib290c3RyYXAoKTtcbiAqIGBgYFxuICogQGNsYXNzXG4gKi9cbmV4cG9ydCBjbGFzcyBOZXN0Qm9vdHN0cmFwZXIge1xuICBwcml2YXRlIHN0YXRpYyBhcHA6IElOZXN0QXBwbGljYXRpb247XG4gIHByaXZhdGUgc3RhdGljIF9sb2dnZXI6IExvZ2dlcjtcblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uXG4gICAqIFJldHVybnMgdGhlIGN1cnJlbnQgbG9nZ2VyIGluc3RhbmNlLCBjcmVhdGluZyBhIGRlZmF1bHQgb25lIGlmIG5vdCBzZXQuXG4gICAqXG4gICAqIEBzdW1tYXJ5XG4gICAqIEVuc3VyZXMgdGhhdCBhIHZhbGlkIGBMb2dnZXJgIGluc3RhbmNlIGlzIGFsd2F5cyBhdmFpbGFibGVcbiAgICogZm9yIGxvZ2dpbmcgYm9vdHN0cmFwLXJlbGF0ZWQgbWVzc2FnZXMuXG4gICAqXG4gICAqIEByZXR1cm4ge0xvZ2dlcn0gVGhlIGFjdGl2ZSBsb2dnZXIgaW5zdGFuY2UuXG4gICAqL1xuICBwcml2YXRlIHN0YXRpYyBnZXQgbG9nZ2VyKCk6IExvZ2dlciB7XG4gICAgaWYgKCF0aGlzLl9sb2dnZXIpIHtcbiAgICAgIC8vIGZhbGxiYWNrXG4gICAgICB0aGlzLl9sb2dnZXIgPSBuZXcgTG9nZ2VyKFwiTmVzdEJvb3RzdHJhcFwiKTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuX2xvZ2dlcjtcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb25cbiAgICogSW5pdGlhbGl6ZXMgdGhlIGJvb3RzdHJhcHBlciB3aXRoIGEgZ2l2ZW4gTmVzdEpTIGFwcGxpY2F0aW9uLlxuICAgKlxuICAgKiBAc3VtbWFyeVxuICAgKiBCaW5kcyB0aGUgcHJvdmlkZWQgTmVzdEpTIGFwcCBpbnN0YW5jZSB0byB0aGUgYm9vdHN0cmFwcGVyLCBlbmFibGluZ1xuICAgKiBjaGFpbmVkIGNvbmZpZ3VyYXRpb24gbWV0aG9kcy5cbiAgICpcbiAgICogQHBhcmFtIHtJTmVzdEFwcGxpY2F0aW9ufSBhcHAgLSBUaGUgTmVzdEpTIGFwcGxpY2F0aW9uIGluc3RhbmNlIHRvIGluaXRpYWxpemUuXG4gICAqIEByZXR1cm4ge05lc3RCb290c3RyYXBlcn0gUmV0dXJucyB0aGUgY2xhc3MgZm9yIGNoYWluaW5nIGNvbmZpZ3VyYXRpb24gbWV0aG9kcy5cbiAgICovXG4gIHN0YXRpYyBpbml0aWFsaXplKGFwcDogSU5lc3RBcHBsaWNhdGlvbikge1xuICAgIHRoaXMuYXBwID0gYXBwO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvblxuICAgKiBFbmFibGVzIG9yIHJlcGxhY2VzIHRoZSBnbG9iYWwgbG9nZ2VyIGZvciB0aGUgTmVzdEpTIGFwcGxpY2F0aW9uLlxuICAgKlxuICAgKiBAc3VtbWFyeVxuICAgKiBJZiBhIGN1c3RvbSBsb2dnZXIgaXMgcHJvdmlkZWQsIGl0IHJlcGxhY2VzIHRoZSBkZWZhdWx0IGxvZ2dlci4gT3RoZXJ3aXNlLFxuICAgKiBhIG5ldyBsb2dnZXIgbmFtZWQgYFwiTmVzdEJvb3RzdHJhcFwiYCBpcyB1c2VkLiBUaGlzIGxvZ2dlciBpcyBhbHNvIHJlZ2lzdGVyZWRcbiAgICogd2l0aCB0aGUgTmVzdEpTIGFwcGxpY2F0aW9uLlxuICAgKlxuICAgKiBAcGFyYW0ge0xvZ2dlcn0gW2N1c3RvbUxvZ2dlcl0gLSBPcHRpb25hbCBjdXN0b20gbG9nZ2VyIGluc3RhbmNlLlxuICAgKiBAcmV0dXJuIHtOZXN0Qm9vdHN0cmFwZXJ9IFJldHVybnMgdGhlIGNsYXNzIGZvciBjaGFpbmluZy5cbiAgICovXG4gIHN0YXRpYyBlbmFibGVMb2dnZXIoY3VzdG9tTG9nZ2VyPzogTG9nZ2VyKSB7XG4gICAgdGhpcy5fbG9nZ2VyID0gY3VzdG9tTG9nZ2VyIHx8IG5ldyBMb2dnZXIoXCJOZXN0Qm9vdHN0cmFwXCIpO1xuICAgIHRoaXMuYXBwLnVzZUxvZ2dlcih0aGlzLl9sb2dnZXIpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvblxuICAgKiBFbmFibGVzIENyb3NzLU9yaWdpbiBSZXNvdXJjZSBTaGFyaW5nIChDT1JTKSBmb3IgdGhlIGFwcGxpY2F0aW9uLlxuICAgKlxuICAgKiBAc3VtbWFyeVxuICAgKiBBbGxvd3MgZGVmaW5pbmcgZWl0aGVyIGEgd2lsZGNhcmQgb3JpZ2luIChgXCIqXCJgKSBvciBhIGxpc3Qgb2YgYWxsb3dlZCBvcmlnaW5zLlxuICAgKiBBdXRvbWF0aWNhbGx5IGFjY2VwdHMgbG9jYWwgZGV2ZWxvcG1lbnQgcmVxdWVzdHMgYW5kIHRob3NlIHdpdGhvdXQgb3JpZ2luIGhlYWRlcnMuXG4gICAqIFRocm93cyBhIGBDb3JzRXJyb3JgIGZvciB1bmF1dGhvcml6ZWQgb3JpZ2lucy5cbiAgICpcbiAgICogQHBhcmFtIHsnKicgfCBzdHJpbmdbXX0gW29yaWdpbnM9W11dIC0gTGlzdCBvZiBhbGxvd2VkIG9yaWdpbnMgb3IgYFwiKlwiYCB0byBhbGxvdyBhbGwuXG4gICAqIEBwYXJhbSB7c3RyaW5nW119IFthbGxvd01ldGhvZHM9WydHRVQnLCAnUE9TVCcsICdQVVQnLCAnREVMRVRFJ11dIC0gQWxsb3dlZCBIVFRQIG1ldGhvZHMuXG4gICAqIEByZXR1cm4ge05lc3RCb290c3RyYXBlcn0gUmV0dXJucyB0aGUgY2xhc3MgZm9yIGNoYWluaW5nIGNvbmZpZ3VyYXRpb24uXG4gICAqXG4gICAqL1xuICBzdGF0aWMgZW5hYmxlQ29ycyhcbiAgICBvcmlnaW5zOiBcIipcIiB8IHN0cmluZ1tdID0gW10sXG4gICAgYWxsb3dNZXRob2RzOiBzdHJpbmdbXSA9IFtcIkdFVFwiLCBcIlBPU1RcIiwgXCJQVVRcIiwgXCJERUxFVEVcIl1cbiAgKSB7XG4gICAgY29uc3QgYWxsb3dlZE9yaWdpbnMgPVxuICAgICAgb3JpZ2lucyA9PT0gXCIqXCIgPyBcIipcIiA6IG9yaWdpbnMubWFwKChvKSA9PiBvLnRyaW0oKS50b0xvd2VyQ2FzZSgpKTtcblxuICAgIGNvbnN0IGNvcnNPcHRpb25zOiBDb3JzT3B0aW9ucyA9IHtcbiAgICAgIG9yaWdpbjogKG9yaWdpbiwgY2FsbGJhY2spID0+IHtcbiAgICAgICAgLy8gQWxsb3cgcmVxdWVzdCB3aXRob3V0IG9yaWdpbi4uLlxuICAgICAgICBpZiAoIW9yaWdpbikgcmV0dXJuIGNhbGxiYWNrKG51bGwsIHRydWUpO1xuXG4gICAgICAgIGlmIChcbiAgICAgICAgICBhbGxvd2VkT3JpZ2lucyA9PT0gXCIqXCIgfHxcbiAgICAgICAgICAoQXJyYXkuaXNBcnJheShhbGxvd2VkT3JpZ2lucykgJiZcbiAgICAgICAgICAgIGFsbG93ZWRPcmlnaW5zLmluY2x1ZGVzKG9yaWdpbi50b0xvd2VyQ2FzZSgpKSlcbiAgICAgICAgKSB7XG4gICAgICAgICAgcmV0dXJuIGNhbGxiYWNrKG51bGwsIHRydWUpO1xuICAgICAgICB9XG5cbiAgICAgICAgY2FsbGJhY2sobmV3IENvcnNFcnJvcihgT3JpZ2luICR7b3JpZ2lufSBub3QgYWxsb3dlZGApKTtcbiAgICAgIH0sXG4gICAgICBjcmVkZW50aWFsczogdHJ1ZSxcbiAgICAgIG1ldGhvZHM6IGFsbG93TWV0aG9kcy5qb2luKFwiLFwiKSxcbiAgICB9O1xuXG4gICAgdGhpcy5hcHAuZW5hYmxlQ29ycyhjb3JzT3B0aW9ucyk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uXG4gICAqIEFwcGxpZXMgdGhlIEhlbG1ldCBtaWRkbGV3YXJlIGZvciBlbmhhbmNlZCBzZWN1cml0eS5cbiAgICpcbiAgICogQHN1bW1hcnlcbiAgICogRHluYW1pY2FsbHkgbG9hZHMgdGhlIGBoZWxtZXRgIHBhY2thZ2UgaWYgYXZhaWxhYmxlIGFuZCByZWdpc3RlcnMgaXRcbiAgICogYXMgbWlkZGxld2FyZSB0byBpbXByb3ZlIEhUVFAgaGVhZGVyIHNlY3VyaXR5LiBJZiBub3QgaW5zdGFsbGVkLCBsb2dzIGEgd2FybmluZ1xuICAgKiBhbmQgY29udGludWVzIGV4ZWN1dGlvbiB3aXRob3V0IHRocm93aW5nIGVycm9ycy5cbiAgICpcbiAgICogQHBhcmFtIHtSZWNvcmQ8c3RyaW5nLCBhbnk+fSBbb3B0aW9uc10gLSBPcHRpb25hbCBjb25maWd1cmF0aW9uIHBhc3NlZCB0byBIZWxtZXQuXG4gICAqIEByZXR1cm4ge05lc3RCb290c3RyYXBlcn0gUmV0dXJucyB0aGUgY2xhc3MgZm9yIGNoYWluaW5nIGNvbmZpZ3VyYXRpb24uXG4gICAqL1xuICBzdGF0aWMgdXNlSGVsbWV0KG9wdGlvbnM/OiBSZWNvcmQ8c3RyaW5nLCBhbnk+KSB7XG4gICAgdHJ5IHtcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tcmVxdWlyZS1pbXBvcnRzXG4gICAgICBjb25zdCBoZWxtZXQgPSByZXF1aXJlKFwiaGVsbWV0XCIpOyAvLyBEeW5hbWljIGltcG9ydCB0byBhdm9pZCBoYXJkIGRlcGVuZGVuY3lcbiAgICAgIHRoaXMuYXBwLnVzZShoZWxtZXQob3B0aW9ucykpO1xuICAgICAgdGhpcy5sb2dnZXIubG9nKFwiSGVsbWV0IG1pZGRsZXdhcmUgZW5hYmxlZCBzdWNjZXNzZnVsbHkuXCIpO1xuICAgIH0gY2F0Y2gge1xuICAgICAgdGhpcy5sb2dnZXIud2FybihcIkhlbG1ldCBub3QgaW5zdGFsbGVkLiBTa2lwcGluZyBtaWRkbGV3YXJlLlwiKTtcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8qKlxuICAgKiBAZGVzY3JpcHRpb25cbiAgICogQ29uZmlndXJlcyBhbmQgaW5pdGlhbGl6ZXMgU3dhZ2dlciBVSSBmb3IgQVBJIGRvY3VtZW50YXRpb24uXG4gICAqXG4gICAqIEBzdW1tYXJ5XG4gICAqIFVzZXMgdGhlIGBTd2FnZ2VyQnVpbGRlcmAgdXRpbGl0eSB0byBjb25maWd1cmUgQVBJIGRvY3VtZW50YXRpb25cbiAgICogd2l0aCBkZXRhaWxlZCBjdXN0b21pemF0aW9uIGZvciB0aXRsZSwgdmVyc2lvbiwgcGF0aHMsIGFuZCBjb2xvcnMuXG4gICAqIFN3YWdnZXIgaXMgYXV0b21hdGljYWxseSBleHBvc2VkIGF0IHRoZSBjb25maWd1cmVkIHBhdGguXG4gICAqXG4gICAqIEBwYXJhbSB7U3dhZ2dlclNldHVwT3B0aW9uc30gb3B0aW9ucyAtIFN3YWdnZXIgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICAgKiBAcmV0dXJuIHtOZXN0Qm9vdHN0cmFwZXJ9IFJldHVybnMgdGhlIGNsYXNzIGZvciBjaGFpbmluZyBjb25maWd1cmF0aW9uLlxuICAgKi9cbiAgc3RhdGljIHNldHVwU3dhZ2dlcihvcHRpb25zOiBTd2FnZ2VyU2V0dXBPcHRpb25zKSB7XG4gICAgY29uc3Qgc3dhZ2dlciA9IG5ldyBTd2FnZ2VyQnVpbGRlcih0aGlzLmFwcCwge1xuICAgICAgdGl0bGU6IG9wdGlvbnMudGl0bGUsXG4gICAgICBkZXNjcmlwdGlvbjogb3B0aW9ucy5kZXNjcmlwdGlvbixcbiAgICAgIHZlcnNpb246IG9wdGlvbnMudmVyc2lvbixcbiAgICAgIHBhdGg6IG9wdGlvbnMucGF0aCB8fCBcImFwaVwiLFxuICAgICAgcGVyc2lzdEF1dGhvcml6YXRpb246IG9wdGlvbnMucGVyc2lzdEF1dGhvcml6YXRpb24gPz8gdHJ1ZSxcbiAgICAgIGFzc2V0c1BhdGg6IG9wdGlvbnMuYXNzZXRzUGF0aCxcbiAgICAgIGZhdmljb25GaWxlUGF0aDogb3B0aW9ucy5mYXZpY29uUGF0aCxcbiAgICAgIHRvcGJhckljb25GaWxlUGF0aDogb3B0aW9ucy50b3BiYXJJY29uUGF0aCxcbiAgICAgIHRvcGJhckJnQ29sb3I6IG9wdGlvbnMudG9wYmFyQmdDb2xvcixcbiAgICAgIG9wZW5BcGlKc29uUGF0aDogb3B0aW9ucy5vcGVuQXBpSnNvblBhdGgsXG4gICAgICBvcGVuQXBpWWFtbFBhdGg6IG9wdGlvbnMub3BlbkFwaVlhbWxQYXRoLFxuICAgIH0pO1xuICAgIHN3YWdnZXIuc2V0dXBTd2FnZ2VyKCk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uXG4gICAqIFJlZ2lzdGVycyBvbmUgb3IgbW9yZSBnbG9iYWwgdmFsaWRhdGlvbiBwaXBlcy5cbiAgICpcbiAgICogQHN1bW1hcnlcbiAgICogRW5hYmxlcyByZXF1ZXN0IHBheWxvYWQgdmFsaWRhdGlvbiBhbmQgdHJhbnNmb3JtYXRpb24gZ2xvYmFsbHkgYWNyb3NzXG4gICAqIHRoZSBlbnRpcmUgTmVzdEpTIGFwcGxpY2F0aW9uLiBNdWx0aXBsZSBwaXBlcyBjYW4gYmUgY2hhaW5lZCB0b2dldGhlclxuICAgKiBmb3IgbW9kdWxhciBpbnB1dCB2YWxpZGF0aW9uLlxuICAgKlxuICAgKiBAcGFyYW0gey4uLlBpcGVUcmFuc2Zvcm1bXX0gcGlwZXMgLSBQaXBlIGluc3RhbmNlcyB0byByZWdpc3RlciBnbG9iYWxseS5cbiAgICogQHJldHVybiB7TmVzdEJvb3RzdHJhcGVyfSBSZXR1cm5zIHRoZSBjbGFzcyBmb3IgY2hhaW5pbmcuXG4gICAqL1xuICBzdGF0aWMgdXNlR2xvYmFsUGlwZXMoLi4ucGlwZXM6IFBpcGVUcmFuc2Zvcm1bXSkge1xuICAgIGlmIChwaXBlcy5sZW5ndGggPiAwKSB0aGlzLmFwcC51c2VHbG9iYWxQaXBlcyguLi5waXBlcyk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uXG4gICAqIFJlZ2lzdGVycyBvbmUgb3IgbW9yZSBnbG9iYWwgZXhjZXB0aW9uIGZpbHRlcnMuXG4gICAqXG4gICAqIEBzdW1tYXJ5XG4gICAqIElmIG5vIGZpbHRlcnMgYXJlIHByb3ZpZGVkLCBpdCBhdXRvbWF0aWNhbGx5IHJlZ2lzdGVycyBhIGRlZmF1bHRcbiAgICogc2V0IG9mIHN0YW5kYXJkIGV4Y2VwdGlvbiBmaWx0ZXJzIGZvciBjb21tb24gZXJyb3IgdHlwZXMgbGlrZVxuICAgKiBgSHR0cEV4Y2VwdGlvbmAsIGBWYWxpZGF0aW9uRXhjZXB0aW9uYCwgYENvbmZsaWN0RXhjZXB0aW9uYCwgYW5kIG90aGVycy5cbiAgICpcbiAgICogVGhlIGRlZmF1bHQgYERlY2FmRXhjZXB0aW9uRmlsdGVyYCBpcyBjb25zdHJ1Y3RlZCB3aXRoIHRoZSBhcHBsaWNhdGlvbidzXG4gICAqIGBNb2R1bGVSZWZgIHNvIGl0IGNhbiByZXNvbHZlIHRoZSByZXF1ZXN0LXNjb3BlZCBgRGVjYWZSZXF1ZXN0Q29udGV4dGAgKGFuZFxuICAgKiBpdHMgY2xpZW50LWJvdW5kIGxvZ2dlcikgZm9yIHRoZSByZXF1ZXN0IHRoYXQgdGhyZXcsIGluc3RlYWQgb2YgbG9nZ2luZ1xuICAgKiB0aHJvdWdoIHRoZSBnZW5lcmljIGdsb2JhbCBsb2dnZXIuXG4gICAqXG4gICAqIEBwYXJhbSB7Li4uRXhjZXB0aW9uRmlsdGVyW119IGZpbHRlcnMgLSBPcHRpb25hbCBmaWx0ZXJzIHRvIGFwcGx5IGdsb2JhbGx5LlxuICAgKi9cbiAgc3RhdGljIHVzZUdsb2JhbEZpbHRlcnMoLi4uZmlsdGVyczogYW55W10pIHtcbiAgICB0aGlzLmFwcC51c2VHbG9iYWxGaWx0ZXJzKFxuICAgICAgLi4uKGZpbHRlcnMubGVuZ3RoID4gMFxuICAgICAgICA/IGZpbHRlcnNcbiAgICAgICAgOiBbbmV3IERlY2FmRXhjZXB0aW9uRmlsdGVyKHRoaXMuYXBwLmdldChNb2R1bGVSZWYsIHsgc3RyaWN0OiBmYWxzZSB9KSldKVxuICAgICk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uXG4gICAqIFJlZ2lzdGVycyBnbG9iYWwgaW50ZXJjZXB0b3JzIGZvciByZXF1ZXN0IGFuZCByZXNwb25zZSB0cmFuc2Zvcm1hdGlvbi5cbiAgICpcbiAgICogQHN1bW1hcnlcbiAgICogSW50ZXJjZXB0b3JzIGFsbG93IGFkdmFuY2VkIHJlcXVlc3QvcmVzcG9uc2UgbWFuaXB1bGF0aW9uIHN1Y2ggYXNcbiAgICogc2VyaWFsaXphdGlvbiwgbG9nZ2luZywgb3IgdHJhbnNmb3JtYXRpb24uIE11bHRpcGxlIGludGVyY2VwdG9yc1xuICAgKiBjYW4gYmUgYWRkZWQgZm9yIG1vZHVsYXIgY29uZmlndXJhdGlvbi5cbiAgICpcbiAgICogQHBhcmFtIHsuLi5OZXN0SW50ZXJjZXB0b3JbXX0gaW50ZXJjZXB0b3JzIC0gSW50ZXJjZXB0b3IgaW5zdGFuY2VzIHRvIHJlZ2lzdGVyLlxuICAgKiBAcmV0dXJuIHtOZXN0Qm9vdHN0cmFwZXJ9IFJldHVybnMgdGhlIGNsYXNzIGZvciBjaGFpbmluZyBjb25maWd1cmF0aW9uLlxuICAgKi9cbiAgc3RhdGljIHVzZUdsb2JhbEludGVyY2VwdG9ycyguLi5pbnRlcmNlcHRvcnM6IE5lc3RJbnRlcmNlcHRvcltdKSB7XG4gICAgaWYgKGludGVyY2VwdG9ycy5sZW5ndGggPiAwKVxuICAgICAgdGhpcy5hcHAudXNlR2xvYmFsSW50ZXJjZXB0b3JzKC4uLmludGVyY2VwdG9ycyk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uXG4gICAqIFN0YXJ0cyB0aGUgTmVzdEpTIGFwcGxpY2F0aW9uIGFuZCBiaW5kcyBpdCB0byB0aGUgZ2l2ZW4gcG9ydCBhbmQgaG9zdC5cbiAgICpcbiAgICogQHN1bW1hcnlcbiAgICogTGlzdGVucyBvbiB0aGUgc3BlY2lmaWVkIHBvcnQgYW5kIG9wdGlvbmFsbHkgYSBob3N0LiBPbmNlIHN0YXJ0ZWQsXG4gICAqIGxvZ3MgdGhlIGFwcGxpY2F0aW9uIFVSTCBmb3IgZWFzeSBhY2Nlc3MuIFRoZSBzdGFydHVwIHByb2Nlc3MgcmVzb2x2ZXNcbiAgICogb25jZSB0aGUgYXBwbGljYXRpb24gaXMgc3VjY2Vzc2Z1bGx5IHJ1bm5pbmcuXG4gICAqXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBbcG9ydD0zMDAwXSAtIFBvcnQgbnVtYmVyIHRvIGxpc3RlbiBvbi5cbiAgICogQHBhcmFtIHtzdHJpbmd9IFtob3N0XSAtIE9wdGlvbmFsIGhvc3Qgb3IgSVAgYWRkcmVzcyB0byBiaW5kIHRvLlxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtsb2c9dHJ1ZV0gLSBXaGV0aGVyIHRvIGxvZyB0aGUgYXBwbGljYXRpb24gVVJMIHVwb24gc3RhcnR1cC5cbiAgICogQHJldHVybiB7UHJvbWlzZTx2b2lkPn0gUmVzb2x2ZXMgb25jZSB0aGUgYXBwbGljYXRpb24gc3RhcnRzIHN1Y2Nlc3NmdWxseS5cbiAgICovXG4gIHN0YXRpYyBhc3luYyBzdGFydChcbiAgICBwb3J0OiBudW1iZXIgPSBOdW1iZXIocHJvY2Vzcy5lbnYuUE9SVCkgfHwgMzAwMCxcbiAgICBob3N0OiBzdHJpbmcgfCB1bmRlZmluZWQgPSB1bmRlZmluZWQsXG4gICAgbG9nOiBib29sZWFuID0gdHJ1ZVxuICApIHtcbiAgICB0aGlzLmFwcC5saXN0ZW4ocG9ydCwgaG9zdCBhcyBhbnkpLnRoZW4oYXN5bmMgKCkgPT4ge1xuICAgICAgaWYgKGxvZykge1xuICAgICAgICBjb25zdCB1cmwgPSBhd2FpdCB0aGlzLmFwcC5nZXRVcmwoKTtcbiAgICAgICAgdGhpcy5sb2dnZXIubG9nKGDwn5qAIEFwcGxpY2F0aW9uIGlzIHJ1bm5pbmcgYXQ6ICR7dXJsfWApO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG59XG4iLCJpbXBvcnQge1xuICBDYWxsSGFuZGxlcixcbiAgRXhlY3V0aW9uQ29udGV4dCxcbiAgSW5qZWN0YWJsZSxcbiAgTmVzdEludGVyY2VwdG9yLFxuICBTY29wZSxcbn0gZnJvbSBcIkBuZXN0anMvY29tbW9uXCI7XG5pbXBvcnQgeyBEZWNhZkhhbmRsZXJFeGVjdXRvciwgRGVjYWZSZXF1ZXN0Q29udGV4dCB9IGZyb20gXCIuLi9yZXF1ZXN0XCI7XG5pbXBvcnQgeyBjb250ZXh0dWFsaXplUmVxdWVzdENvbnRleHQgfSBmcm9tIFwiLi4vcmVxdWVzdC9jb250ZXh0dWFsaXplXCI7XG5pbXBvcnQgeyBMb2dnaW5nIH0gZnJvbSBcIkBkZWNhZi10cy9sb2dnaW5nXCI7XG5pbXBvcnQgXCIuLi9vdmVycmlkZXNcIjtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb25cbiAqIEludGVyY2VwdG9yIHJlc3BvbnNpYmxlIGZvciBleGVjdXRpbmcgYWxsIHJlZ2lzdGVyZWQgRGVjYWYgcmVxdWVzdCBoYW5kbGVyc1xuICogYmVmb3JlIHRoZSBjb250cm9sbGVyIG1ldGhvZCBpcyBpbnZva2VkLlxuICpcbiAqIEBzdW1tYXJ5XG4gKiBUaGUge0BsaW5rIERlY2FmUmVxdWVzdEhhbmRsZXJJbnRlcmNlcHRvcn0gaW50ZWdyYXRlcyB0aGUgRGVjYWYgcmVxdWVzdC1oYW5kbGluZyBwaXBlbGluZVxuICogaW50byBOZXN0SlMnIGludGVyY2VwdG9yIG1lY2hhbmlzbS4gQmVmb3JlIHBhc3NpbmcgZXhlY3V0aW9uIHRvIHRoZSBuZXh0IGhhbmRsZXIgaW4gdGhlXG4gKiBOZXN0SlMgY2hhaW4sIGl0IGRlbGVnYXRlcyByZXF1ZXN0IHByb2Nlc3NpbmcgdG8gdGhlIHtAbGluayBEZWNhZkhhbmRsZXJFeGVjdXRvcn0sIHdoaWNoXG4gKiBzZXF1ZW50aWFsbHkgcnVucyBhbGwgcmVnaXN0ZXJlZCB7QGxpbmsgRGVjYWZSZXF1ZXN0SGFuZGxlcn0gaW5zdGFuY2VzLiBUaGlzIGFsbG93c1xuICogYmVoYXZpb3JzIHN1Y2ggYXMgYXV0aGVudGljYXRpb24sIGxvZ2dpbmcsIHRlbmFudCByZXNvbHV0aW9uLCBvciBtZXRhZGF0YSBlbnJpY2htZW50XG4gKiB0byBvY2N1ciBwcmlvciB0byBjb250cm9sbGVyIGV4ZWN1dGlvbi5cbiAqXG4gKiBAY2xhc3MgRGVjYWZSZXF1ZXN0SGFuZGxlckludGVyY2VwdG9yXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHRzXG4gKiAvLyBBcHBseSBnbG9iYWxseTpcbiAqIGFwcC51c2VHbG9iYWxJbnRlcmNlcHRvcnMobmV3IERlY2FmUmVxdWVzdEhhbmRsZXJJbnRlcmNlcHRvcihleGVjdXRvcikpO1xuICpcbiAqIC8vIE9yIGluIGEgbW9kdWxlOlxuICogQE1vZHVsZSh7XG4gKiAgIHByb3ZpZGVyczogW1xuICogICAgIERlY2FmSGFuZGxlckV4ZWN1dG9yLFxuICogICAgIHtcbiAqICAgICAgIHByb3ZpZGU6IEFQUF9JTlRFUkNFUFRPUixcbiAqICAgICAgIHVzZUNsYXNzOiBEZWNhZlJlcXVlc3RIYW5kbGVySW50ZXJjZXB0b3IsXG4gKiAgICAgfSxcbiAqICAgXSxcbiAqIH0pXG4gKiBleHBvcnQgY2xhc3MgQXBwTW9kdWxlIHt9XG4gKiBgYGBcbiAqXG4gKiBAbWVybWFpZFxuICogc2VxdWVuY2VEaWFncmFtXG4gKiAgICAgcGFydGljaXBhbnQgQ2xpZW50XG4gKiAgICAgcGFydGljaXBhbnQgSW50ZXJjZXB0b3JcbiAqICAgICBwYXJ0aWNpcGFudCBFeGVjdXRvclxuICogICAgIHBhcnRpY2lwYW50IENvbnRyb2xsZXJcbiAqXG4gKiAgICAgQ2xpZW50LT4+SW50ZXJjZXB0b3I6IEhUVFAgUmVxdWVzdFxuICogICAgIEludGVyY2VwdG9yLT4+RXhlY3V0b3I6IGV4ZWMocmVxdWVzdClcbiAqICAgICBFeGVjdXRvci0tPj5JbnRlcmNlcHRvcjogaGFuZGxlcnMgY29tcGxldGVkXG4gKiAgICAgSW50ZXJjZXB0b3ItPj5Db250cm9sbGVyOiBuZXh0LmhhbmRsZSgpXG4gKiAgICAgQ29udHJvbGxlci0tPj5DbGllbnQ6IFJlc3BvbnNlXG4gKi9cbkBJbmplY3RhYmxlKHsgc2NvcGU6IFNjb3BlLlJFUVVFU1QgfSlcbmV4cG9ydCBjbGFzcyBEZWNhZlJlcXVlc3RIYW5kbGVySW50ZXJjZXB0b3IgaW1wbGVtZW50cyBOZXN0SW50ZXJjZXB0b3Ige1xuICBjb25zdHJ1Y3RvcihcbiAgICBwcm90ZWN0ZWQgcmVhZG9ubHkgcmVxdWVzdENvbnRleHQ6IERlY2FmUmVxdWVzdENvbnRleHQsXG4gICAgcHJvdGVjdGVkIHJlYWRvbmx5IGV4ZWN1dG9yOiBEZWNhZkhhbmRsZXJFeGVjdXRvclxuICApIHt9XG5cbiAgcHJvdGVjdGVkIGFzeW5jIGNvbnRleHR1YWxpemUocmVxOiBhbnkpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb250ZXh0dWFsaXplUmVxdWVzdENvbnRleHQodGhpcy5yZXF1ZXN0Q29udGV4dCwgcmVxKTtcbiAgfVxuXG4gIGFzeW5jIGludGVyY2VwdChjb250ZXh0OiBFeGVjdXRpb25Db250ZXh0LCBuZXh0OiBDYWxsSGFuZGxlcikge1xuICAgIGNvbnN0IHJlcSA9IGNvbnRleHQuc3dpdGNoVG9IdHRwKCkuZ2V0UmVxdWVzdCgpO1xuICAgIGNvbnN0IHJlcyA9IGNvbnRleHQuc3dpdGNoVG9IdHRwKCkuZ2V0UmVzcG9uc2UoKTtcbiAgICBjb25zdCBsb2cgPSBMb2dnaW5nLmZvcihEZWNhZlJlcXVlc3RIYW5kbGVySW50ZXJjZXB0b3IpLmZvcih0aGlzLmludGVyY2VwdCk7XG4gICAgbG9nLmRlYnVnKFxuICAgICAgYENPTlRFWFQgJHt0aGlzLnJlcXVlc3RDb250ZXh0LnV1aWR9IC0gcmVxdWVzdDogJHtyZXEubWV0aG9kfSAke3JlcS51cmx9YFxuICAgICk7XG4gICAgYXdhaXQgdGhpcy5jb250ZXh0dWFsaXplKHJlcSk7XG4gICAgbG9nLmRlYnVnKFxuICAgICAgYENPTlRFWFQgJHt0aGlzLnJlcXVlc3RDb250ZXh0LnV1aWR9IGNvbnRleHR1YWxpemVkIC0gcmVxdWVzdDogJHtyZXEubWV0aG9kfSAke3JlcS51cmx9YFxuICAgICk7XG5cbiAgICBhd2FpdCB0aGlzLmV4ZWN1dG9yLmV4ZWMocmVxLCByZXMpO1xuICAgIGxvZy5kZWJ1ZyhcbiAgICAgIGBDT05URVhUICR7dGhpcy5yZXF1ZXN0Q29udGV4dC51dWlkfSBleGVjdXRvcnMgZmluaXNoZWQgLSByZXF1ZXN0OiAke3JlcS5tZXRob2R9ICR7cmVxLnVybH1gXG4gICAgKTtcbiAgICByZXR1cm4gbmV4dC5oYW5kbGUoKTtcbiAgfVxufVxuIiwiaW1wb3J0IHsgSW5qZWN0IH0gZnJvbSBcIkBuZXN0anMvY29tbW9uXCI7XG5pbXBvcnQgeyBDb25zdHJ1Y3RvciB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdGlvblwiO1xuaW1wb3J0IHtcbiAgaW5qZWN0YWJsZVNlcnZpY2VLZXksXG4gIE1vZGVsU2VydmljZSxcbiAgUmVwb3NpdG9yeSBhcyBDb3JlUmVwb3NpdG9yeSxcbiAgU2VydmljZSBhcyBDb3JlU2VydmljZSxcbn0gZnJvbSBcIkBkZWNhZi10cy9jb3JlXCI7XG5pbXBvcnQgeyBNb2RlbCB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdG9yLXZhbGlkYXRpb25cIjtcbmltcG9ydCB7IEludGVybmFsRXJyb3IgfSBmcm9tIFwiQGRlY2FmLXRzL2RiLWRlY29yYXRvcnNcIjtcblxuZXhwb3J0IHR5cGUgRGVjYWZGYWN0b3J5UHJvdmlkZXIgPSB7XG4gIHByb3ZpZGU6IHN0cmluZztcbiAgdXNlRmFjdG9yeTogKCkgPT4gdW5rbm93bjtcbn07XG5cbmNvbnN0IHBlbmRpbmdQcm92aWRlcnMgPSBuZXcgTWFwPHN0cmluZywgRGVjYWZGYWN0b3J5UHJvdmlkZXI+KCk7XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIERyYWlucyB0aGUgcHJvdmlkZXJzIHJlZ2lzdGVyZWQgYnkge0BsaW5rIFNlcnZpY2V9L3tAbGluayBSZXBvc2l0b3J5fSB1c2FnZXMuXG4gKiBAc3VtbWFyeSBDb25zdW1lZCBieSB7QGxpbmsgRGVjYWZDb3JlTW9kdWxlLmZvclJvb3R9IHRvIHdpcmUgdGhlIHRva2VucyB0aGF0IHRob3NlIHBhcmFtZXRlclxuICogZGVjb3JhdG9ycyByZWZlcmVuY2UgYmFjayBpbnRvIE5lc3QncyBESSBjb250YWluZXIsIHNpbmNlIGEgcGFyYW1ldGVyIGRlY29yYXRvciBhbG9uZSBjYW5ub3RcbiAqIHN1cHBseSBhIHByb3ZpZGVyLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0UmVnaXN0ZXJlZERlY2FmUHJvdmlkZXJzKCk6IERlY2FmRmFjdG9yeVByb3ZpZGVyW10ge1xuICByZXR1cm4gQXJyYXkuZnJvbShwZW5kaW5nUHJvdmlkZXJzLnZhbHVlcygpKTtcbn1cblxuZnVuY3Rpb24gcmVnaXN0ZXJQcm92aWRlcih0b2tlbjogc3RyaW5nLCB1c2VGYWN0b3J5OiAoKSA9PiB1bmtub3duKTogdm9pZCB7XG4gIGlmIChwZW5kaW5nUHJvdmlkZXJzLmhhcyh0b2tlbikpIHJldHVybjtcbiAgcGVuZGluZ1Byb3ZpZGVycy5zZXQodG9rZW4sIHsgcHJvdmlkZTogdG9rZW4sIHVzZUZhY3RvcnkgfSk7XG59XG5cbmZ1bmN0aW9uIGlzTW9kZWxDb25zdHJ1Y3Rvcih2YWx1ZTogdW5rbm93bik6IHZhbHVlIGlzIENvbnN0cnVjdG9yPGFueT4ge1xuICByZXR1cm4gdHlwZW9mIHZhbHVlID09PSBcImZ1bmN0aW9uXCIgJiYgdmFsdWUucHJvdG90eXBlIGluc3RhbmNlb2YgTW9kZWw7XG59XG5cbmZ1bmN0aW9uIG1vZGVsU2VydmljZVRva2VuKG1vZGVsOiBDb25zdHJ1Y3Rvcjxhbnk+KTogc3RyaW5nIHtcbiAgcmV0dXJuIGAke21vZGVsLm5hbWV9U2VydmljZWA7XG59XG5cbmZ1bmN0aW9uIG1vZGVsUmVwb3NpdG9yeVRva2VuKFxuICBtb2RlbDogQ29uc3RydWN0b3I8YW55PixcbiAgZmxhdm91cj86IHN0cmluZ1xuKTogc3RyaW5nIHtcbiAgcmV0dXJuIGZsYXZvdXIgPyBgJHttb2RlbC5uYW1lfVJlcG9zaXRvcnlAJHtmbGF2b3VyfWAgOiBgJHttb2RlbC5uYW1lfVJlcG9zaXRvcnlgO1xufVxuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBDb25zdHJ1Y3RvciBwYXJhbWV0ZXIgZGVjb3JhdG9yIHRoYXQgaW5qZWN0cyBhIGRlY2FmIHNlcnZpY2UuXG4gKiBAc3VtbWFyeSBUcmFuc2xhdGVzIGRlY2FmJ3Mgc2VydmljZSByZXNvbHV0aW9uIEFQSXMgaW50byBhIE5lc3QgYEBJbmplY3QoKWAgY2FsbDpcbiAqIC0gYEBTZXJ2aWNlKFNvbWVNb2RlbClgIGluamVjdHMgdGhlIG1hdGNoaW5nIGBAc2VydmljZShTb21lTW9kZWwpYCBkZWNhZiBzZXJ2aWNlIHdoZW4gb25lIGlzXG4gKiAgIHJlZ2lzdGVyZWQ7IG90aGVyd2lzZSBpdCBmYWxscyBiYWNrIHRvIHRoZSBgTW9kZWxTZXJ2aWNlPFNvbWVNb2RlbD5gIHNpbmdsZXRvblxuICogICAodmlhIHtAbGluayBNb2RlbFNlcnZpY2UuZm9yTW9kZWx9KS5cbiAqIC0gYEBTZXJ2aWNlKFNvbWVTZXJ2aWNlQ2xhc3MpYCBvciBgQFNlcnZpY2UoXCJhbGlhc1wiKWAgaW5qZWN0cyB0aGUgbWF0Y2hpbmcgYEBzZXJ2aWNlKClgLWRlY29yYXRlZFxuICogICBkZWNhZiB7QGxpbmsgQ29yZVNlcnZpY2V9ICh2aWEge0BsaW5rIENvcmVTZXJ2aWNlLmdldH0pLlxuICogLSBgQFNlcnZpY2UoKWAgaW5mZXJzIHRoZSBwYXJhbWV0ZXIncyB0eXBlIGZyb20gZW1pdHRlZCBjb25zdHJ1Y3RvciBtZXRhZGF0YSBhbmQgcmVzb2x2ZXMgaXQgdGhlXG4gKiAgIHNhbWUgd2F5LCBwcm92aWRlZCB0aGUgcGFyYW1ldGVyIGlzIHR5cGVkIGFzIGEgY29uY3JldGUgY2xhc3MgKGdlbmVyaWNzIGxpa2UgYE1vZGVsU2VydmljZTxYPmBcbiAqICAgYXJlIGVyYXNlZCBhdCBydW50aW1lLCBzbyB0aGUgbW9kZWwtc2VydmljZSBmb3JtIGFsd2F5cyByZXF1aXJlcyBhbiBleHBsaWNpdCBhcmd1bWVudCkuXG4gKiBAcGFyYW0ga2V5IHRoZSBtb2RlbCBjbGFzcywgc2VydmljZSBjbGFzcywgb3IgYWxpYXMgdG8gcmVzb2x2ZS4gT21pdCB0byBpbmZlciBmcm9tIHRoZSBwYXJhbWV0ZXIgdHlwZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIFNlcnZpY2Uoa2V5Pzogc3RyaW5nIHwgQ29uc3RydWN0b3I8YW55Pik6IFBhcmFtZXRlckRlY29yYXRvciB7XG4gIHJldHVybiAoXG4gICAgdGFyZ2V0OiBvYmplY3QsXG4gICAgcHJvcGVydHlLZXk6IHN0cmluZyB8IHN5bWJvbCB8IHVuZGVmaW5lZCxcbiAgICBwYXJhbWV0ZXJJbmRleDogbnVtYmVyXG4gICk6IHZvaWQgPT4ge1xuICAgIGxldCByZXNvbHZlZDogc3RyaW5nIHwgQ29uc3RydWN0b3I8YW55PiB8IHVuZGVmaW5lZCA9IGtleTtcbiAgICBpZiAodHlwZW9mIHJlc29sdmVkID09PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgICBjb25zdCBwYXJhbVR5cGVzOiBhbnlbXSA9XG4gICAgICAgIFJlZmxlY3QuZ2V0TWV0YWRhdGEoXCJkZXNpZ246cGFyYW10eXBlc1wiLCB0YXJnZXQpIHx8IFtdO1xuICAgICAgcmVzb2x2ZWQgPSBwYXJhbVR5cGVzW3BhcmFtZXRlckluZGV4XTtcbiAgICB9XG4gICAgaWYgKHR5cGVvZiByZXNvbHZlZCA9PT0gXCJ1bmRlZmluZWRcIikge1xuICAgICAgdGhyb3cgbmV3IEludGVybmFsRXJyb3IoXG4gICAgICAgIGBAU2VydmljZSgpIGNvdWxkIG5vdCBkZXRlcm1pbmUgYW4gaW5qZWN0aW9uIHR5cGUgZm9yIHBhcmFtZXRlciAke3BhcmFtZXRlckluZGV4fSBvZiAkeyh0YXJnZXQgYXMgQ29uc3RydWN0b3I8YW55PikubmFtZX0uIFByb3ZpZGUgYW4gZXhwbGljaXQgYXJndW1lbnQsIGUuZy4gQFNlcnZpY2UoU29tZVNlcnZpY2UpLmBcbiAgICAgICk7XG4gICAgfVxuXG4gICAgY29uc3QgYXNNb2RlbCA9IHR5cGVvZiByZXNvbHZlZCAhPT0gXCJzdHJpbmdcIiAmJiBpc01vZGVsQ29uc3RydWN0b3IocmVzb2x2ZWQpO1xuICAgIGNvbnN0IHRva2VuID0gYXNNb2RlbFxuICAgICAgPyBtb2RlbFNlcnZpY2VUb2tlbihyZXNvbHZlZCBhcyBDb25zdHJ1Y3Rvcjxhbnk+KVxuICAgICAgOiBpbmplY3RhYmxlU2VydmljZUtleShyZXNvbHZlZCBhcyBzdHJpbmcgfCBDb25zdHJ1Y3Rvcjxhbnk+KTtcblxuICAgIHJlZ2lzdGVyUHJvdmlkZXIodG9rZW4sICgpID0+IHtcbiAgICAgIGlmIChhc01vZGVsKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgcmV0dXJuIENvcmVTZXJ2aWNlLmdldChyZXNvbHZlZCBhcyBDb25zdHJ1Y3Rvcjxhbnk+KTtcbiAgICAgICAgfSBjYXRjaCB7XG4gICAgICAgICAgcmV0dXJuIE1vZGVsU2VydmljZS5mb3JNb2RlbChyZXNvbHZlZCBhcyBDb25zdHJ1Y3Rvcjxhbnk+KTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgcmV0dXJuIHR5cGVvZiByZXNvbHZlZCA9PT0gXCJzdHJpbmdcIlxuICAgICAgICA/IENvcmVTZXJ2aWNlLmdldChyZXNvbHZlZClcbiAgICAgICAgOiBDb3JlU2VydmljZS5nZXQocmVzb2x2ZWQgYXMgQ29uc3RydWN0b3I8YW55Pik7XG4gICAgfSk7XG5cbiAgICByZXR1cm4gSW5qZWN0KHRva2VuKSh0YXJnZXQsIHByb3BlcnR5S2V5LCBwYXJhbWV0ZXJJbmRleCk7XG4gIH07XG59XG5cbi8qKlxuICogQGRlc2NyaXB0aW9uIENvbnN0cnVjdG9yIHBhcmFtZXRlciBkZWNvcmF0b3IgdGhhdCBpbmplY3RzIGEgZGVjYWYge0BsaW5rIENvcmVSZXBvc2l0b3J5fSBmb3IgYG1vZGVsYC5cbiAqIEBzdW1tYXJ5IFVubGlrZSB7QGxpbmsgU2VydmljZX0sIGBtb2RlbGAgaXMgYWx3YXlzIHRyZWF0ZWQgYXMgYSBNb2RlbCBjbGFzczogdGhlIHNhbWUgY2xhc3MgcGFzc2VkXG4gKiB0byBgQFNlcnZpY2UobW9kZWwpYCBhbmQgYEBSZXBvc2l0b3J5KG1vZGVsKWAgcmVzb2x2ZXMgdG8gdHdvIGRpZmZlcmVudCBpbmplY3RlZCBvYmplY3RzIChhXG4gKiBgTW9kZWxTZXJ2aWNlPE0+YCB2cyBhIGBSZXBvc2l0b3J5PE0+YCByZXNwZWN0aXZlbHkpLCB2aWEge0BsaW5rIENvcmVSZXBvc2l0b3J5LmZvck1vZGVsfS5cbiAqIEBwYXJhbSBtb2RlbCB0aGUgbW9kZWwgY2xhc3MgdG8gcmVzb2x2ZSBhIHJlcG9zaXRvcnkgZm9yLlxuICogQHBhcmFtIGZsYXZvdXIgb3B0aW9uYWwgYWRhcHRlciBmbGF2b3VyL2FsaWFzLCBmb3J3YXJkZWQgdG8ge0BsaW5rIENvcmVSZXBvc2l0b3J5LmZvck1vZGVsfS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIFJlcG9zaXRvcnkoXG4gIG1vZGVsOiBDb25zdHJ1Y3Rvcjxhbnk+LFxuICBmbGF2b3VyPzogc3RyaW5nXG4pOiBQYXJhbWV0ZXJEZWNvcmF0b3Ige1xuICByZXR1cm4gKFxuICAgIHRhcmdldDogb2JqZWN0LFxuICAgIHByb3BlcnR5S2V5OiBzdHJpbmcgfCBzeW1ib2wgfCB1bmRlZmluZWQsXG4gICAgcGFyYW1ldGVySW5kZXg6IG51bWJlclxuICApOiB2b2lkID0+IHtcbiAgICBjb25zdCB0b2tlbiA9IG1vZGVsUmVwb3NpdG9yeVRva2VuKG1vZGVsLCBmbGF2b3VyKTtcbiAgICByZWdpc3RlclByb3ZpZGVyKHRva2VuLCAoKSA9PiBDb3JlUmVwb3NpdG9yeS5mb3JNb2RlbChtb2RlbCwgZmxhdm91cikpO1xuICAgIHJldHVybiBJbmplY3QodG9rZW4pKHRhcmdldCwgcHJvcGVydHlLZXksIHBhcmFtZXRlckluZGV4KTtcbiAgfTtcbn1cbiIsImltcG9ydCB7XG4gIER5bmFtaWNNb2R1bGUsXG4gIEdsb2JhbCxcbiAgSW5qZWN0LFxuICBNb2R1bGUsXG4gIE9uQXBwbGljYXRpb25TaHV0ZG93bixcbn0gZnJvbSBcIkBuZXN0anMvY29tbW9uXCI7XG5pbXBvcnQgeyBBUFBfSU5URVJDRVBUT1IsIE1vZHVsZVJlZiB9IGZyb20gXCJAbmVzdGpzL2NvcmVcIjtcbmltcG9ydCB0eXBlIHsgRGVjYWZNb2R1bGVPcHRpb25zIH0gZnJvbSBcIi4vdHlwZXNcIjtcbmltcG9ydCB7XG4gIERFQ0FGX0FEQVBURVJfSUQsXG4gIERFQ0FGX0hBTkRMRVJTLFxuICBERUNBRl9NT0RVTEVfT1BUSU9OUyxcbn0gZnJvbSBcIi4vY29uc3RhbnRzXCI7XG5pbXBvcnQge1xuICBEZWNhZlJlcXVlc3RIYW5kbGVySW50ZXJjZXB0b3IsXG59IGZyb20gXCIuL2ludGVyY2VwdG9yc1wiO1xuaW1wb3J0IHsgRGVjYWZIYW5kbGVyRXhlY3V0b3IsIERlY2FmUmVxdWVzdENvbnRleHQgfSBmcm9tIFwiLi9yZXF1ZXN0XCI7XG5pbXBvcnQgeyBDb25zdHJ1Y3RvciB9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdGlvblwiO1xuaW1wb3J0IHsgQWRhcHRlciwgUGVyc2lzdGVuY2VTZXJ2aWNlLCBTZXJ2aWNlIH0gZnJvbSBcIkBkZWNhZi10cy9jb3JlXCI7XG5pbXBvcnQgeyBnZXRSZWdpc3RlcmVkRGVjYWZQcm92aWRlcnMgfSBmcm9tIFwiLi9kZWNvcmF0b3JzXCI7XG5pbXBvcnQgeyBJbnRlcm5hbEVycm9yIH0gZnJvbSBcIkBkZWNhZi10cy9kYi1kZWNvcmF0b3JzXCI7XG5pbXBvcnQgeyBMb2dnZXIsIExvZ2dpbmcgfSBmcm9tIFwiQGRlY2FmLXRzL2xvZ2dpbmdcIjtcbmltcG9ydCB7XG4gIFJlcXVlc3RUb0NvbnRleHRUcmFuc2Zvcm1lcixcbiAgcmVxdWVzdFRvQ29udGV4dFRyYW5zZm9ybWVyLFxufSBmcm9tIFwiQGRlY2FmLXRzL2Zvci1odHRwL3NlcnZlclwiO1xuXG5AR2xvYmFsKClcbkBNb2R1bGUoe30pXG5leHBvcnQgY2xhc3MgRGVjYWZDb3JlTW9kdWxlPENPTkYsIEFEQVBURVIgZXh0ZW5kcyBBZGFwdGVyPENPTkYsIGFueSwgYW55LCBhbnk+PlxuICBpbXBsZW1lbnRzIE9uQXBwbGljYXRpb25TaHV0ZG93blxue1xuICBwcml2YXRlIHN0YXRpYyBfbG9nZ2VyOiBMb2dnZXI7XG5cbiAgcHJpdmF0ZSBzdGF0aWMgX3BlcnNpc3RlbmNlPzogUGVyc2lzdGVuY2VTZXJ2aWNlPEFkYXB0ZXI8YW55LCBhbnksIGFueSwgYW55Pj47XG5cbiAgcHJvdGVjdGVkIHN0YXRpYyBnZXQgcGVyc2lzdGVuY2UoKTogUGVyc2lzdGVuY2VTZXJ2aWNlPEFkYXB0ZXI8YW55LCBhbnksIGFueSwgYW55Pj4ge1xuICAgIGlmICghdGhpcy5fcGVyc2lzdGVuY2UpXG4gICAgICB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihcIlBlcnNpc3RlbmNlIHNlcnZpY2Ugbm90IGluaXRpYWxpemVkXCIpO1xuICAgIHJldHVybiB0aGlzLl9wZXJzaXN0ZW5jZTtcbiAgfVxuXG4gIHByb3RlY3RlZCBzdGF0aWMgZ2V0IGxvZygpOiBMb2dnZXIge1xuICAgIGlmICghdGhpcy5fbG9nZ2VyKSB0aGlzLl9sb2dnZXIgPSBMb2dnaW5nLmZvcihEZWNhZkNvcmVNb2R1bGUpO1xuICAgIHJldHVybiB0aGlzLl9sb2dnZXI7XG4gIH1cblxuICBjb25zdHJ1Y3RvcihcbiAgICBASW5qZWN0KERFQ0FGX01PRFVMRV9PUFRJT05TKVxuICAgIHByaXZhdGUgcmVhZG9ubHkgb3B0aW9uczogRGVjYWZNb2R1bGVPcHRpb25zPENPTkYsIEFEQVBURVI+LFxuICAgIHByaXZhdGUgcmVhZG9ubHkgbW9kdWxlUmVmOiBNb2R1bGVSZWZcbiAgKSB7fVxuXG4gIHN0YXRpYyBmb3JSb290KG9wdGlvbnM6IERlY2FmTW9kdWxlT3B0aW9ucyk6IER5bmFtaWNNb2R1bGUge1xuICAgIGNvbnN0IGxvZyA9IHRoaXMubG9nLmZvcih0aGlzLmZvclJvb3QpO1xuICAgIGNvbnN0IGRlY2FmUHJvdmlkZXJzID0gZ2V0UmVnaXN0ZXJlZERlY2FmUHJvdmlkZXJzKCk7XG4gICAgcmV0dXJuIHtcbiAgICAgIG1vZHVsZTogRGVjYWZDb3JlTW9kdWxlLFxuICAgICAgcHJvdmlkZXJzOiBbXG4gICAgICAgIHsgcHJvdmlkZTogREVDQUZfTU9EVUxFX09QVElPTlMsIHVzZVZhbHVlOiBvcHRpb25zIH0sXG4gICAgICAgIHsgcHJvdmlkZTogREVDQUZfQURBUFRFUl9JRCwgdXNlVmFsdWU6IHRoaXMucGVyc2lzdGVuY2U/LmNsaWVudCB9LFxuICAgICAgICB7XG4gICAgICAgICAgcHJvdmlkZTogREVDQUZfSEFORExFUlMsXG4gICAgICAgICAgdXNlRmFjdG9yeTogKCkgPT5cbiAgICAgICAgICAgIG9wdGlvbnMuaGFuZGxlcnM/Lm1hcCgoSCkgPT4ge1xuICAgICAgICAgICAgICBsb2cuaW5mbyhgUmVnaXN0ZXJlZCByZXF1ZXN0IGhhbmRsZXI6ICR7SC5uYW1lfWApO1xuICAgICAgICAgICAgICByZXR1cm4gbmV3IEgoKTtcbiAgICAgICAgICAgIH0pID8/IFtdLFxuICAgICAgICB9LFxuICAgICAgICBEZWNhZlJlcXVlc3RDb250ZXh0LFxuICAgICAgICBEZWNhZkhhbmRsZXJFeGVjdXRvcixcbiAgICAgICAge1xuICAgICAgICAgIHByb3ZpZGU6IEFQUF9JTlRFUkNFUFRPUixcbiAgICAgICAgICB1c2VDbGFzczogRGVjYWZSZXF1ZXN0SGFuZGxlckludGVyY2VwdG9yLFxuICAgICAgICB9LFxuICAgICAgICAuLi5kZWNhZlByb3ZpZGVycyxcbiAgICAgIF0sXG4gICAgICBleHBvcnRzOiBbXG4gICAgICAgIERFQ0FGX01PRFVMRV9PUFRJT05TLFxuICAgICAgICBERUNBRl9BREFQVEVSX0lELFxuICAgICAgICBERUNBRl9IQU5ETEVSUyxcbiAgICAgICAgRGVjYWZSZXF1ZXN0Q29udGV4dCxcbiAgICAgICAgRGVjYWZIYW5kbGVyRXhlY3V0b3IsXG4gICAgICAgIC4uLmRlY2FmUHJvdmlkZXJzLm1hcCgocHJvdmlkZXIpID0+IHByb3ZpZGVyLnByb3ZpZGUpLFxuICAgICAgXSxcbiAgICB9O1xuICB9XG5cbiAgc3RhdGljIGFzeW5jIGJvb3RQZXJzaXN0ZW5jZShcbiAgICBvcHRpb25zOiBEZWNhZk1vZHVsZU9wdGlvbnNcbiAgKTogUHJvbWlzZTxBZGFwdGVyPGFueSwgYW55LCBhbnksIGFueT5bXT4ge1xuICAgIGNvbnN0IGxvZyA9IHRoaXMubG9nLmZvcih0aGlzLmJvb3RQZXJzaXN0ZW5jZSk7XG5cbiAgICBpZiAoIXRoaXMuX3BlcnNpc3RlbmNlKSB7XG4gICAgICBjb25zdCB0cmltbWVkID0gb3B0aW9ucy5jb25mLm1hcCgoW2NvbnRyLCBjZmcsIC4uLmFyZ3NdKSA9PiB7XG4gICAgICAgIGNvbnN0IHBvc3NpYmxlID0gYXJncy5wb3AoKTtcbiAgICAgICAgaWYgKCFwb3NzaWJsZSkgcmV0dXJuIFtjb250ciwgY2ZnXTtcbiAgICAgICAgcmV0dXJuIFtjb250ciwgY2ZnLCAuLi5hcmdzXTtcbiAgICAgIH0pO1xuICAgICAgdGhpcy5fcGVyc2lzdGVuY2UgPSBuZXcgUGVyc2lzdGVuY2VTZXJ2aWNlKCk7XG4gICAgICBhd2FpdCB0aGlzLl9wZXJzaXN0ZW5jZS5ib290KHRyaW1tZWQpO1xuICAgICAgY29uc3QgY2xpZW50cyA9IHRoaXMuX3BlcnNpc3RlbmNlLmNsaWVudDtcbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgY2xpZW50cy5sZW5ndGg7IGkrKykge1xuICAgICAgICBjb25zdCBjID0gb3B0aW9ucy5jb25mW2ldO1xuICAgICAgICBjb25zdCBwb3NzaWJsZVRyYW5zZiA9IGMuc2xpY2UoMiwgYy5sZW5ndGgpO1xuICAgICAgICBsZXQgdHJhbnNmb3JtZXIgPSBwb3NzaWJsZVRyYW5zZi5wb3AoKTtcbiAgICAgICAgaWYgKFxuICAgICAgICAgICF0cmFuc2Zvcm1lciB8fFxuICAgICAgICAgICEodHJhbnNmb3JtZXIgYXMgUmVxdWVzdFRvQ29udGV4dFRyYW5zZm9ybWVyPGFueT4pLmZyb21cbiAgICAgICAgKSB7XG4gICAgICAgICAgY29uc3QgY29udHIgPSBBZGFwdGVyLnRyYW5zZm9ybWVyRm9yKGNsaWVudHNbaV0uZmxhdm91cik7XG4gICAgICAgICAgaWYgKCFjb250cilcbiAgICAgICAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFxuICAgICAgICAgICAgICBgTm8gdHJhbnNmb3JtZXIgZm91bmQgZm9yIGZsYXZvdXIgJHtjbGllbnRzW2ldLmZsYXZvdXJ9LiB5b3Ugc2hvdWxkIGVpdGhlciBAcmVxdWVzdFRvQ29udGV4dFRyYW5zZm9ybWVyIG9yIHByb3ZpZGUgYSB0cmFuc2Zvcm1lciBpbiB0aGUgY29uZmlnYFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgdHJhbnNmb3JtZXIgPSAoY29udHIgYXMgUmVxdWVzdFRvQ29udGV4dFRyYW5zZm9ybWVyPGFueT4pLmZyb21cbiAgICAgICAgICAgICAgPyBjb250clxuICAgICAgICAgICAgICA6IG5ldyAoY29udHIgYXMgQ29uc3RydWN0b3I8UmVxdWVzdFRvQ29udGV4dFRyYW5zZm9ybWVyPGFueT4+KSgpO1xuICAgICAgICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKFxuICAgICAgICAgICAgICBgRmFpbGVkIHRvIGJvb3QgdHJhbnNmb3JtZXIgZm9yICR7Y2xpZW50c1tpXS5mbGF2b3VyfTogJHtlfWBcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJlcXVlc3RUb0NvbnRleHRUcmFuc2Zvcm1lcihjbGllbnRzW2ldLmZsYXZvdXIpKHRyYW5zZm9ybWVyKTtcbiAgICAgIH1cbiAgICAgIGxvZy5pbmZvKFwicGVyc2lzdGVuY2UgbGF5ZXIgY3JlYXRlZCBzdWNjZXNzZnVsbHkhXCIpO1xuXG4gICAgICBpZiAob3B0aW9ucy5pbml0aWFsaXphdGlvbikge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGF3YWl0IG9wdGlvbnMuaW5pdGlhbGl6YXRpb24oKTtcbiAgICAgICAgfSBjYXRjaCAoZTogdW5rbm93bikge1xuICAgICAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKGBGYWlsZWQgdG8gaW5pdGlhbGl6ZSBhcHBsaWNhdGlvbjogJHtlfWApO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMucGVyc2lzdGVuY2UuY2xpZW50O1xuICB9XG5cbiAgYXN5bmMgb25BcHBsaWNhdGlvblNodXRkb3duKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IGxvZyA9IERlY2FmQ29yZU1vZHVsZS5sb2cuZm9yKHRoaXMub25BcHBsaWNhdGlvblNodXRkb3duKTtcbiAgICBjb25zdCBhZGFwdGVyczogQWRhcHRlcjxhbnksIGFueSwgYW55LCBhbnk+W10gPVxuICAgICAgdGhpcy5tb2R1bGVSZWYuZ2V0PGFueT4oREVDQUZfQURBUFRFUl9JRCk7XG4gICAgZm9yIChjb25zdCBhZGFwdGVyIG9mIGFkYXB0ZXJzKVxuICAgICAgdHJ5IHtcbiAgICAgICAgaWYgKGFkYXB0ZXIpIHtcbiAgICAgICAgICBsb2cuaW5mbyhgU2h1dHRpbmcgZG93biAke2FkYXB0ZXIudG9TdHJpbmcoKX1gKTtcbiAgICAgICAgICBhd2FpdCBhZGFwdGVyLnNodXRkb3duKCk7XG4gICAgICAgIH1cbiAgICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgICAgbG9nLmVycm9yKGBGYWlsZWQgdG8gc2h1dGRvd24gYXBwbGljYXRpb25gLCBlIGFzIEVycm9yKTtcbiAgICAgIH1cbiAgICB0cnkge1xuICAgICAgYXdhaXQgU2VydmljZS5zaHV0ZG93bigpO1xuICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgIGxvZy5lcnJvcihgRmFpbGVkIHRvIHNodXRkb3duIHNlcnZpY2VzYCwgZSBhcyBFcnJvcik7XG4gICAgfVxuICB9XG59XG4iLCJleHBvcnQgY29uc3QgTElTVEVOSU5HX0FEQVBURVJTX0ZMQVZPVVJTID0gU3ltYm9sKFxuICBcIkxJU1RFTklOR19BREFQVEVSU19GTEFWT1VSU1wiXG4pO1xuXG5leHBvcnQgY29uc3QgT0JTRVJWRVJfRVZFTlRTX09QVElPTlMgPSBTeW1ib2woXCJPQlNFUlZFUl9FVkVOVFNfT1BUSU9OU1wiKTtcbiIsImV4cG9ydCBmdW5jdGlvbiBub3JtYWxpemVFdmVudFJlc3BvbnNlKGFyZ3M6IGFueVtdKTogdW5rbm93bltdIHtcbiAgY29uc3QgW21vZGVsQ29uc3RyLCBvcGVyYXRpb24sIGlkLCBwYXlsb2FkXSA9IGFyZ3M7XG5cbiAgY29uc3QgbW9kZWxOYW1lID0gbW9kZWxDb25zdHI/Lm5hbWUgPz8gbW9kZWxDb25zdHI7XG5cbiAgY29uc3Qgc2VyaWFsaXplZFBheWxvYWQgPSBBcnJheS5pc0FycmF5KHBheWxvYWQpXG4gICAgPyBwYXlsb2FkLm1hcCgoZSkgPT4ge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGlmICh0eXBlb2YgZS5zZXJpYWxpemUgPT09IFwiZnVuY3Rpb25cIikgcmV0dXJuIGUuc2VyaWFsaXplKCk7XG5cbiAgICAgICAgICBjb25zb2xlLndhcm4oXG4gICAgICAgICAgICBgUGF5bG9hZCBpdGVtIGZvciAke21vZGVsTmFtZX0gZG9lcyBub3QgaGF2ZSBzZXJpYWxpemUgbWV0aG9kIGFuZCBpcyBhbiAke3R5cGVvZiBlfSwgYXR0ZW1wdGluZyB0byBzdHJpbmdpZnkgZGlyZWN0bHkuIEl0ZW06ICR7ZX1gXG4gICAgICAgICAgKTtcbiAgICAgICAgICByZXR1cm4gdHlwZW9mIGUgPT09IFwic3RyaW5nXCIgPyBlIDogSlNPTi5zdHJpbmdpZnkoZSk7XG4gICAgICAgIH0gY2F0Y2ggKGVycjogdW5rbm93bikge1xuICAgICAgICAgIGNvbnNvbGUud2FybihgRmFpbGVkIHRvIHNlcmlhbGl6ZSBwYXlsb2FkIGZvciAke21vZGVsTmFtZX06ICR7ZXJyfWApO1xuICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgIH1cbiAgICAgIH0pXG4gICAgOiBwYXlsb2FkICYmIHR5cGVvZiBwYXlsb2FkLnNlcmlhbGl6ZSA9PT0gXCJmdW5jdGlvblwiXG4gICAgICA/IHBheWxvYWQuc2VyaWFsaXplKClcbiAgICAgIDogdHlwZW9mIHBheWxvYWQgPT09IFwic3RyaW5nXCJcbiAgICAgICAgPyBwYXlsb2FkXG4gICAgICAgIDogSlNPTi5zdHJpbmdpZnkocGF5bG9hZCk7XG5cbiAgY29uc29sZS5kZWJ1ZyhcbiAgICBgTm9ybWFsaXplZCBldmVudCByZXNwb25zZSBmb3IgbW9kZWwgJHttb2RlbE5hbWV9LCBvcGVyYXRpb24gJHtvcGVyYXRpb259LCBpZCAke2lkfTpgLFxuICAgIHNlcmlhbGl6ZWRQYXlsb2FkXG4gICk7XG5cbiAgcmV0dXJuIFttb2RlbE5hbWUsIG9wZXJhdGlvbiwgaWQsIHNlcmlhbGl6ZWRQYXlsb2FkXTtcbn1cbiIsImltcG9ydCB7IEluamVjdGFibGUgfSBmcm9tIFwiQG5lc3Rqcy9jb21tb25cIjtcblxuZXhwb3J0IHR5cGUgT2JzZXJ2ZXJTdWJzY3JpcHRpb25SZWNvcmQgPSB7XG4gIHN1YnNjcmliZXJJZDogc3RyaW5nO1xuICB0b3BpY3M6IFNldDxzdHJpbmc+O1xuICB1cGRhdGVkQXQ6IERhdGU7XG59O1xuXG5ASW5qZWN0YWJsZSgpXG5leHBvcnQgY2xhc3MgT2JzZXJ2ZXJTdWJzY3JpcHRpb25SZWdpc3RyeSB7XG4gIHByaXZhdGUgcmVhZG9ubHkgcmVjb3JkcyA9IG5ldyBNYXA8c3RyaW5nLCBPYnNlcnZlclN1YnNjcmlwdGlvblJlY29yZD4oKTtcblxuICB1cHNlcnQoc3Vic2NyaWJlcklkOiBzdHJpbmcsIHRvcGljczogc3RyaW5nW10gPSBbXSk6IE9ic2VydmVyU3Vic2NyaXB0aW9uUmVjb3JkIHtcbiAgICBjb25zdCByZWNvcmQ6IE9ic2VydmVyU3Vic2NyaXB0aW9uUmVjb3JkID0ge1xuICAgICAgc3Vic2NyaWJlcklkLFxuICAgICAgdG9waWNzOiBuZXcgU2V0KHRvcGljcy5maWx0ZXIoQm9vbGVhbikpLFxuICAgICAgdXBkYXRlZEF0OiBuZXcgRGF0ZSgpLFxuICAgIH07XG4gICAgdGhpcy5yZWNvcmRzLnNldChzdWJzY3JpYmVySWQsIHJlY29yZCk7XG4gICAgcmV0dXJuIHJlY29yZDtcbiAgfVxuXG4gIHJlbW92ZShzdWJzY3JpYmVySWQ6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLnJlY29yZHMuZGVsZXRlKHN1YnNjcmliZXJJZCk7XG4gIH1cblxuICBnZXQoc3Vic2NyaWJlcklkOiBzdHJpbmcpOiBPYnNlcnZlclN1YnNjcmlwdGlvblJlY29yZCB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMucmVjb3Jkcy5nZXQoc3Vic2NyaWJlcklkKTtcbiAgfVxuXG4gIHRvcGljc0ZvcihzdWJzY3JpYmVySWQ6IHN0cmluZyk6IHN0cmluZ1tdIHtcbiAgICByZXR1cm4gWy4uLih0aGlzLnJlY29yZHMuZ2V0KHN1YnNjcmliZXJJZCk/LnRvcGljcyA/PyBbXSldO1xuICB9XG5cbiAgbWF0Y2hlcyhzdWJzY3JpYmVySWQ6IHN0cmluZywgdG9waWM6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIGNvbnN0IHJlY29yZCA9IHRoaXMucmVjb3Jkcy5nZXQoc3Vic2NyaWJlcklkKTtcbiAgICBpZiAoIXJlY29yZCkgcmV0dXJuIGZhbHNlO1xuICAgIGlmICghcmVjb3JkLnRvcGljcy5zaXplKSByZXR1cm4gZmFsc2U7XG4gICAgcmV0dXJuIHJlY29yZC50b3BpY3MuaGFzKHRvcGljKSB8fCByZWNvcmQudG9waWNzLmhhcyhcIipcIik7XG4gIH1cbn1cbiIsImltcG9ydCB7IERlY2FmQ29udHJvbGxlciB9IGZyb20gXCIuLi9jb250cm9sbGVyc1wiO1xuaW1wb3J0IHsgRGVjYWZSZXF1ZXN0Q29udGV4dCB9IGZyb20gXCIuLi9yZXF1ZXN0XCI7XG5pbXBvcnQgeyBBZGFwdGVyLCBPYnNlcnZlciwgT2JzZXJ2ZXJGaWx0ZXIgfSBmcm9tIFwiQGRlY2FmLXRzL2NvcmVcIjtcbmltcG9ydCB7XG4gIEJhZFJlcXVlc3RFeGNlcHRpb24sXG4gIENvbnRyb2xsZXIsXG4gIEluamVjdCxcbiAgTWVzc2FnZUV2ZW50LFxuICBRdWVyeSxcbiAgU3NlLFxufSBmcm9tIFwiQG5lc3Rqcy9jb21tb25cIjtcbmltcG9ydCB7IGludGVydmFsLCBtZXJnZSwgT2JzZXJ2YWJsZSB9IGZyb20gXCJyeGpzXCI7XG5pbXBvcnQgeyBMb2dnaW5nIH0gZnJvbSBcIkBkZWNhZi10cy9sb2dnaW5nXCI7XG5pbXBvcnQge1xuICBMSVNURU5JTkdfQURBUFRFUlNfRkxBVk9VUlMsXG4gIE9CU0VSVkVSX0VWRU5UU19PUFRJT05TLFxufSBmcm9tIFwiLi9jb25zdGFudFwiO1xuaW1wb3J0IHsgRGVjYWZTZXJ2ZXJDdHggfSBmcm9tIFwiLi4vY29uc3RhbnRzXCI7XG5pbXBvcnQgeyBub3JtYWxpemVFdmVudFJlc3BvbnNlIH0gZnJvbSBcIi4vdXRpbHNcIjtcbmltcG9ydCB7IG1hcCwgdGFwIH0gZnJvbSBcInJ4anMvb3BlcmF0b3JzXCI7XG5pbXBvcnQgeyBPYnNlcnZlclN1YnNjcmlwdGlvblJlZ2lzdHJ5IH0gZnJvbSBcIi4vT2JzZXJ2ZXJTdWJzY3JpcHRpb25SZWdpc3RyeVwiO1xuaW1wb3J0IHR5cGUgeyBPYnNlcnZlckV2ZW50c09wdGlvbnMgfSBmcm9tIFwiLi4vdHlwZXNcIjtcblxuQENvbnRyb2xsZXIoKVxuZXhwb3J0IGNsYXNzIEV2ZW50c0NvbnRyb2xsZXIgZXh0ZW5kcyBEZWNhZkNvbnRyb2xsZXI8RGVjYWZTZXJ2ZXJDdHg+IHtcbiAgcHJpdmF0ZSByZWFkb25seSBhZGFwdGVyczogQWRhcHRlcjxhbnksIGFueSwgYW55LCBhbnk+W107XG5cbiAgY29uc3RydWN0b3IoXG4gICAgY2xpZW50Q29udGV4dDogRGVjYWZSZXF1ZXN0Q29udGV4dCxcbiAgICBASW5qZWN0KExJU1RFTklOR19BREFQVEVSU19GTEFWT1VSUykgZmxhdm91cnM6IHN0cmluZ1tdLFxuICAgIEBJbmplY3QoT0JTRVJWRVJfRVZFTlRTX09QVElPTlMpIHByaXZhdGUgcmVhZG9ubHkgb3B0aW9uczogT2JzZXJ2ZXJFdmVudHNPcHRpb25zLFxuICAgIHByaXZhdGUgcmVhZG9ubHkgcmVnaXN0cnk6IE9ic2VydmVyU3Vic2NyaXB0aW9uUmVnaXN0cnlcbiAgKSB7XG4gICAgc3VwZXIoY2xpZW50Q29udGV4dCwgRXZlbnRzQ29udHJvbGxlci5uYW1lKTtcbiAgICB0aGlzLmFkYXB0ZXJzID0gZmxhdm91cnMubWFwKChmbGF2b3VyKSA9PiAoQWRhcHRlciBhcyBhbnkpLmdldChmbGF2b3VyKSk7IC8vIGNoYW5nZSB0byBBZGFwdGVyLmNhY2hlKFwiXCIpXG4gIH1cblxuICBAU3NlKClcbiAgbGlzdGVuKEBRdWVyeShcInN1YnNjcmliZXJJZFwiKSBzdWJzY3JpYmVySWQ/OiBzdHJpbmcpOiBPYnNlcnZhYmxlPE1lc3NhZ2VFdmVudD4ge1xuICAgIGNvbnN0IGxvZ2dlciA9IExvZ2dpbmcuZm9yKEV2ZW50c0NvbnRyb2xsZXIubmFtZSk7XG4gICAgY29uc3Qgc3Vic2NyaXB0aW9uTW9kZSA9IEJvb2xlYW4odGhpcy5vcHRpb25zLnN1YnNjcmlwdGlvbk1vZGUpO1xuICAgIGlmIChzdWJzY3JpcHRpb25Nb2RlICYmICFzdWJzY3JpYmVySWQpIHtcbiAgICAgIHRocm93IG5ldyBCYWRSZXF1ZXN0RXhjZXB0aW9uKFxuICAgICAgICBcInN1YnNjcmliZXJJZCBpcyByZXF1aXJlZCB3aGVuIHN1YnNjcmlwdGlvbk1vZGUgaXMgZW5hYmxlZFwiXG4gICAgICApO1xuICAgIH1cbiAgICBjb25zdCBhY3RpdmVTdWJzY3JpYmVySWQgPSBzdWJzY3JpYmVySWQgPz8gXCJcIjtcblxuICAgIGNvbnN0IGV2ZW50cyQgPSBuZXcgT2JzZXJ2YWJsZTxNZXNzYWdlRXZlbnQ+KChvYnNlcnZlcikgPT4ge1xuICAgICAgY29uc3Qgb2JzZXJ2ZXJJZCA9XG4gICAgICAgIGBCLSR7TWF0aC5yYW5kb20oKS50b1N0cmluZygzNikuc2xpY2UoMiwgOCl9YC50b1VwcGVyQ2FzZSgpO1xuXG4gICAgICBsb2dnZXIuaW5mbyhcbiAgICAgICAgYENyZWF0aW5nIFNTRSBvYnNlcnZlcjogJHtvYnNlcnZlcklkfSBmb3IgY2xpZW50ICR7dGhpcy5jbGllbnRDb250ZXh0LnV1aWR9YFxuICAgICAgKTtcbiAgICAgIGNvbnN0IGNiID0gbmV3IChjbGFzcyBpbXBsZW1lbnRzIE9ic2VydmVyIHtcbiAgICAgICAgb2JzZXJ2ZXJJZCA9IG9ic2VydmVySWQ7XG4gICAgICAgIHJlZnJlc2goLi4uYXJnczogYW55W10pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgICBsb2dnZXIuZGVidWcoXG4gICAgICAgICAgICBgU1NFIG9ic2VydmVyICR7dGhpcy5vYnNlcnZlcklkfSByZWNlaXZlZCByZWZyZXNoIGV2ZW50YFxuICAgICAgICAgICk7XG4gICAgICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpLnRoZW4oKCkgPT4ge1xuICAgICAgICAgICAgY29uc3QgZGF0YSA9IG5vcm1hbGl6ZUV2ZW50UmVzcG9uc2UoYXJncyk7XG4gICAgICAgICAgICBvYnNlcnZlci5uZXh0KHsgdHlwZTogXCJtZXNzYWdlXCIsIGRhdGEgfSk7XG4gICAgICAgICAgICBsb2dnZXIuZGVidWcoXG4gICAgICAgICAgICAgIGBTU0Ugb2JzZXJ2ZXIgJHt0aGlzLm9ic2VydmVySWR9IGV2ZW50IHB1c2hlZCB0byBjbGllbnRgXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9KSgpO1xuICAgICAgY29uc3QgZmlsdGVyOiBPYnNlcnZlckZpbHRlciB8IHVuZGVmaW5lZCA9IHN1YnNjcmlwdGlvbk1vZGVcbiAgICAgICAgPyAobW9kZWw6IHN0cmluZyB8IEZ1bmN0aW9uLCAuLi5fYXJnczogYW55W10pID0+IHtcbiAgICAgICAgICAgIGNvbnN0IHRvcGljID1cbiAgICAgICAgICAgICAgdHlwZW9mIG1vZGVsID09PSBcInN0cmluZ1wiXG4gICAgICAgICAgICAgICAgPyBtb2RlbFxuICAgICAgICAgICAgICAgIDogKG1vZGVsIGFzIGFueSk/Lm5hbWUgPz8gKG1vZGVsIGFzIGFueSk/LmNvbnN0cnVjdG9yPy5uYW1lO1xuICAgICAgICAgICAgaWYgKCF0b3BpYykgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMucmVnaXN0cnkubWF0Y2hlcyhhY3RpdmVTdWJzY3JpYmVySWQsIHRvcGljKTtcbiAgICAgICAgICB9XG4gICAgICAgIDogdW5kZWZpbmVkO1xuXG4gICAgICBsb2dnZXIudmVyYm9zZShcbiAgICAgICAgYFJlZ2lzdGVyaW5nIG9ic2VydmVyICR7b2JzZXJ2ZXJJZH0gYWNyb3NzICR7dGhpcy5hZGFwdGVycy5sZW5ndGh9IGFkYXB0ZXIocylgXG4gICAgICApO1xuICAgICAgZm9yIChjb25zdCBhZGFwdGVyIG9mIHRoaXMuYWRhcHRlcnMpIHtcbiAgICAgICAgY29uc3QgYWRhcHRlck5hbWUgPSBhZGFwdGVyPy5jb25zdHJ1Y3Rvcj8ubmFtZSA/PyBcIlVua25vd25BZGFwdGVyXCI7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgbG9nZ2VyLmRlYnVnKFxuICAgICAgICAgICAgYFJlZ2lzdGVyaW5nIG9ic2VydmVyICR7b2JzZXJ2ZXJJZH0gaW4gYWRhcHRlciAke2FkYXB0ZXJOYW1lfWBcbiAgICAgICAgICApO1xuICAgICAgICAgIGFkYXB0ZXIub2JzZXJ2ZShjYiwgZmlsdGVyKTtcbiAgICAgICAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgICAgICAgbG9nZ2VyLmRlYnVnKFxuICAgICAgICAgICAgYEZhaWxlZCB0byByZWdpc3RlciBvYnNlcnZlciAke29ic2VydmVySWR9IGluIGFkYXB0ZXIgJHthZGFwdGVyTmFtZX06ICR7ZT8ubWVzc2FnZSB8fCBlfWBcbiAgICAgICAgICApO1xuICAgICAgICAgIGxvZ2dlci5lcnJvcihlKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICByZXR1cm4gKCkgPT4ge1xuICAgICAgICBsb2dnZXIuZGVidWcoYENsZWFuaW5nIHVwIFNTRSBvYnNlcnZlciAke29ic2VydmVySWR9YCk7XG5cbiAgICAgICAgZm9yIChjb25zdCBhZGFwdGVyIG9mIHRoaXMuYWRhcHRlcnMpIHtcbiAgICAgICAgICBjb25zdCBhZGFwdGVyTmFtZSA9IGFkYXB0ZXI/LmNvbnN0cnVjdG9yPy5uYW1lID8/IFwiVW5rbm93bkFkYXB0ZXJcIjtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgbG9nZ2VyLmRlYnVnKFxuICAgICAgICAgICAgICBgVW5yZWdpc3RlcmluZyBvYnNlcnZlciAke29ic2VydmVySWR9IGZyb20gYWRhcHRlciAke2FkYXB0ZXJOYW1lfWBcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICBhZGFwdGVyLnVuT2JzZXJ2ZShjYik7XG4gICAgICAgICAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgICAgICAgICBsb2dnZXIuZGVidWcoXG4gICAgICAgICAgICAgIGBGYWlsZWQgZHVyaW5nIGNsZWFudXAgb2Ygb2JzZXJ2ZXIgJHtvYnNlcnZlcklkfSBpbiBhZGFwdGVyICR7YWRhcHRlck5hbWV9OiAke2U/Lm1lc3NhZ2UgfHwgZX1gXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgbG9nZ2VyLmVycm9yKGUpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpZiAoc3Vic2NyaXB0aW9uTW9kZSkge1xuICAgICAgICAgIHRoaXMucmVnaXN0cnkucmVtb3ZlKGFjdGl2ZVN1YnNjcmliZXJJZCk7XG4gICAgICAgIH1cbiAgICAgIH07XG4gICAgfSk7XG5cbiAgICBjb25zdCBIRUFSVEJFQVRfSU5URVJWQUxfTVMgPSAxNTAwMDtcbiAgICBjb25zdCBoZWFydGJlYXQkID0gaW50ZXJ2YWwoSEVBUlRCRUFUX0lOVEVSVkFMX01TKS5waXBlKFxuICAgICAgdGFwKCgpID0+IHtcbiAgICAgICAgbG9nZ2VyLmRlYnVnKFwiU2VuZGluZyBoZWFydGJlYXRcIik7XG4gICAgICB9KSxcbiAgICAgIG1hcChcbiAgICAgICAgKCk6IE1lc3NhZ2VFdmVudCA9PiAoe1xuICAgICAgICAgIHR5cGU6IFwiaGVhcnRiZWF0XCIsXG4gICAgICAgICAgZGF0YToge1xuICAgICAgICAgICAgdHM6IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKSxcbiAgICAgICAgICB9LFxuICAgICAgICB9KVxuICAgICAgKVxuICAgICk7XG5cbiAgICByZXR1cm4gbWVyZ2UoZXZlbnRzJCwgaGVhcnRiZWF0JCk7XG4gIH1cblxuICBAU3NlKFwiLzptb2RlbFwiKVxuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVudXNlZC12YXJzXG4gIGxpc3RlbkZvck1vZGVsKEBRdWVyeShcIm1vZGVsXCIpIG1vZGVsOiBzdHJpbmcpOiBPYnNlcnZhYmxlPE1lc3NhZ2VFdmVudD4ge1xuICAgIGNvbnN0IGxvZ2dlciA9IExvZ2dpbmcuZm9yKEV2ZW50c0NvbnRyb2xsZXIubmFtZSk7XG5cbiAgICByZXR1cm4gbmV3IE9ic2VydmFibGU8TWVzc2FnZUV2ZW50Pigob2JzZXJ2ZXIpID0+IHtcbiAgICAgIGNvbnN0IGNiID0gbmV3IChjbGFzcyBpbXBsZW1lbnRzIE9ic2VydmVyIHtcbiAgICAgICAgcmVmcmVzaCguLi5hcmdzOiBhbnlbXSk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoKS50aGVuKCgpID0+IHtcbiAgICAgICAgICAgIG9ic2VydmVyLm5leHQoeyBkYXRhOiBhcmdzIH0gYXMgYW55KTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfSkoKTtcblxuICAgICAgdHJ5IHtcbiAgICAgICAgZm9yIChjb25zdCBhZGFwdGVyIG9mIHRoaXMuYWRhcHRlcnMpIHtcbiAgICAgICAgICBhZGFwdGVyLm9ic2VydmUoY2IpO1xuICAgICAgICB9XG4gICAgICB9IGNhdGNoIChlOiBhbnkpIHtcbiAgICAgICAgb2JzZXJ2ZXIuZXJyb3IoYEZhaWxlZCB0byBvYnNlcnZlIGV2ZW50OiAke2UubWVzc2FnZSB8fCBlfWApO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gKCkgPT4ge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGZvciAoY29uc3QgYWRhcHRlciBvZiB0aGlzLmFkYXB0ZXJzKSB7XG4gICAgICAgICAgICBhZGFwdGVyLnVuT2JzZXJ2ZShjYik7XG4gICAgICAgICAgfVxuICAgICAgICB9IGNhdGNoIChlOiBhbnkpIHtcbiAgICAgICAgICBsb2dnZXIuZXJyb3IoZSk7XG4gICAgICAgIH1cbiAgICAgIH07XG4gICAgfSk7XG4gIH1cbn1cbiIsImltcG9ydCB7IEJvZHksIENvbnRyb2xsZXIsIEluamVjdCwgUG9zdCB9IGZyb20gXCJAbmVzdGpzL2NvbW1vblwiO1xuaW1wb3J0IHsgVVVJRCB9IGZyb20gXCJAZGVjYWYtdHMvY29yZVwiO1xuaW1wb3J0IHsgRGVjYWZSZXF1ZXN0Q29udGV4dCB9IGZyb20gXCIuLi9yZXF1ZXN0XCI7XG5pbXBvcnQgeyBEZWNhZkNvbnRyb2xsZXIgfSBmcm9tIFwiLi4vY29udHJvbGxlcnNcIjtcbmltcG9ydCB7IERlY2FmU2VydmVyQ3R4IH0gZnJvbSBcIi4uL2NvbnN0YW50c1wiO1xuaW1wb3J0IHsgT0JTRVJWRVJfRVZFTlRTX09QVElPTlMgfSBmcm9tIFwiLi9jb25zdGFudFwiO1xuaW1wb3J0IHR5cGUgeyBPYnNlcnZlckV2ZW50c09wdGlvbnMgfSBmcm9tIFwiLi4vdHlwZXNcIjtcbmltcG9ydCB7IE9ic2VydmVyU3Vic2NyaXB0aW9uUmVnaXN0cnkgfSBmcm9tIFwiLi9PYnNlcnZlclN1YnNjcmlwdGlvblJlZ2lzdHJ5XCI7XG5cbnR5cGUgU3Vic2NyaXB0aW9uUGF5bG9hZCA9IHtcbiAgc3Vic2NyaWJlcklkPzogc3RyaW5nO1xuICB0b3BpY3M/OiBzdHJpbmdbXTtcbn07XG5cbkBDb250cm9sbGVyKClcbmV4cG9ydCBjbGFzcyBFdmVudHNTdWJzY3JpcHRpb25Db250cm9sbGVyIGV4dGVuZHMgRGVjYWZDb250cm9sbGVyPERlY2FmU2VydmVyQ3R4PiB7XG4gIGNvbnN0cnVjdG9yKFxuICAgIGNsaWVudENvbnRleHQ6IERlY2FmUmVxdWVzdENvbnRleHQsXG4gICAgQEluamVjdChPQlNFUlZFUl9FVkVOVFNfT1BUSU9OUykgcHJpdmF0ZSByZWFkb25seSBvcHRpb25zOiBPYnNlcnZlckV2ZW50c09wdGlvbnMsXG4gICAgcHJpdmF0ZSByZWFkb25seSByZWdpc3RyeTogT2JzZXJ2ZXJTdWJzY3JpcHRpb25SZWdpc3RyeVxuICApIHtcbiAgICBzdXBlcihjbGllbnRDb250ZXh0LCBFdmVudHNTdWJzY3JpcHRpb25Db250cm9sbGVyLm5hbWUpO1xuICB9XG5cbiAgQFBvc3QoXCJzdWJzY3JpYmVcIilcbiAgYXN5bmMgc3Vic2NyaWJlKFxuICAgIEBCb2R5KCkgYm9keTogU3Vic2NyaXB0aW9uUGF5bG9hZFxuICApOiBQcm9taXNlPFJlY29yZDxzdHJpbmcsIGFueT4+IHtcbiAgICBpZiAoIXRoaXMub3B0aW9ucy5zdWJzY3JpcHRpb25Nb2RlKSB7XG4gICAgICByZXR1cm4geyBlbmFibGVkOiBmYWxzZSB9O1xuICAgIH1cbiAgICBjb25zdCBzdWJzY3JpYmVySWQgPVxuICAgICAgYm9keT8uc3Vic2NyaWJlcklkIHx8IChhd2FpdCBQcm9taXNlLnJlc29sdmUoVVVJRC5pbnN0YW5jZS5nZW5lcmF0ZSgpKSk7XG4gICAgY29uc3QgdG9waWNzID0gQXJyYXkuaXNBcnJheShib2R5Py50b3BpY3MpID8gYm9keS50b3BpY3MgOiBbXTtcbiAgICBjb25zdCByZWNvcmQgPSB0aGlzLnJlZ2lzdHJ5LnVwc2VydChzdWJzY3JpYmVySWQsIHRvcGljcyk7XG4gICAgcmV0dXJuIHtcbiAgICAgIHN1YnNjcmliZXJJZDogcmVjb3JkLnN1YnNjcmliZXJJZCxcbiAgICAgIHRvcGljczogdGhpcy5yZWdpc3RyeS50b3BpY3NGb3IocmVjb3JkLnN1YnNjcmliZXJJZCksXG4gICAgfTtcbiAgfVxuXG4gIEBQb3N0KFwidW5zdWJzY3JpYmVcIilcbiAgdW5zdWJzY3JpYmUoQEJvZHkoKSBib2R5OiBTdWJzY3JpcHRpb25QYXlsb2FkKTogUmVjb3JkPHN0cmluZywgYW55PiB7XG4gICAgaWYgKCF0aGlzLm9wdGlvbnMuc3Vic2NyaXB0aW9uTW9kZSkge1xuICAgICAgcmV0dXJuIHsgZW5hYmxlZDogZmFsc2UgfTtcbiAgICB9XG4gICAgY29uc3Qgc3Vic2NyaWJlcklkID0gYm9keT8uc3Vic2NyaWJlcklkO1xuICAgIGlmICghc3Vic2NyaWJlcklkKSB7XG4gICAgICByZXR1cm4geyB1bnN1YnNjcmliZWQ6IGZhbHNlIH07XG4gICAgfVxuICAgIHJldHVybiB7XG4gICAgICB1bnN1YnNjcmliZWQ6IHRoaXMucmVnaXN0cnkucmVtb3ZlKHN1YnNjcmliZXJJZCksXG4gICAgICBzdWJzY3JpYmVySWQsXG4gICAgfTtcbiAgfVxufVxuIiwiaW1wb3J0IHsgRHluYW1pY01vZHVsZSwgTW9kdWxlIH0gZnJvbSBcIkBuZXN0anMvY29tbW9uXCI7XG5pbXBvcnQgeyBFdmVudHNDb250cm9sbGVyIH0gZnJvbSBcIi4vRXZlbnRzQ29udHJvbGxlclwiO1xuaW1wb3J0IHsgUm91dGVyTW9kdWxlIH0gZnJvbSBcIkBuZXN0anMvY29yZVwiO1xuaW1wb3J0IHtcbiAgTElTVEVOSU5HX0FEQVBURVJTX0ZMQVZPVVJTLFxuICBPQlNFUlZFUl9FVkVOVFNfT1BUSU9OUyxcbn0gZnJvbSBcIi4vY29uc3RhbnRcIjtcbmltcG9ydCB7IERlY2FmUmVxdWVzdENvbnRleHQgfSBmcm9tIFwiLi4vcmVxdWVzdFwiO1xuaW1wb3J0IHsgT2JzZXJ2ZXJTdWJzY3JpcHRpb25SZWdpc3RyeSB9IGZyb20gXCIuL09ic2VydmVyU3Vic2NyaXB0aW9uUmVnaXN0cnlcIjtcbmltcG9ydCB7IE9ic2VydmVyRXZlbnRzT3B0aW9ucyB9IGZyb20gXCIuLi90eXBlc1wiO1xuaW1wb3J0IHsgRXZlbnRzU3Vic2NyaXB0aW9uQ29udHJvbGxlciB9IGZyb20gXCIuL0V2ZW50c1N1YnNjcmlwdGlvbkNvbnRyb2xsZXJcIjtcblxuQE1vZHVsZSh7fSlcbmV4cG9ydCBjbGFzcyBEZWNhZlN0cmVhbU1vZHVsZSB7XG4gIHN0YXRpYyBmb3JGbGF2b3VycyhcbiAgICBmbGF2b3Vyczogc3RyaW5nW10sXG4gICAgcGF0aDogc3RyaW5nID0gXCJldmVudHNcIixcbiAgICBvcHRpb25zOiBPYnNlcnZlckV2ZW50c09wdGlvbnMgPSB7fVxuICApOiBEeW5hbWljTW9kdWxlIHtcbiAgICBjb25zdCBjb250cm9sbGVyczogYW55W10gPSBbRXZlbnRzQ29udHJvbGxlcl07XG4gICAgaWYgKG9wdGlvbnMuc3Vic2NyaXB0aW9uTW9kZSkge1xuICAgICAgY29udHJvbGxlcnMucHVzaChFdmVudHNTdWJzY3JpcHRpb25Db250cm9sbGVyKTtcbiAgICB9XG4gICAgcmV0dXJuIHtcbiAgICAgIG1vZHVsZTogRGVjYWZTdHJlYW1Nb2R1bGUsXG4gICAgICBjb250cm9sbGVycyxcbiAgICAgIGltcG9ydHM6IFtcbiAgICAgICAgUm91dGVyTW9kdWxlLnJlZ2lzdGVyKFtcbiAgICAgICAgICB7XG4gICAgICAgICAgICBwYXRoOiBwYXRoLnJlcGxhY2UoL15cXC8vLCBcIlwiKSxcbiAgICAgICAgICAgIG1vZHVsZTogRGVjYWZTdHJlYW1Nb2R1bGUsXG4gICAgICAgICAgfSxcbiAgICAgICAgXSksXG4gICAgICBdLFxuICAgICAgcHJvdmlkZXJzOiBbXG4gICAgICAgIERlY2FmUmVxdWVzdENvbnRleHQsXG4gICAgICAgIE9ic2VydmVyU3Vic2NyaXB0aW9uUmVnaXN0cnksXG4gICAgICAgIHtcbiAgICAgICAgICBwcm92aWRlOiBMSVNURU5JTkdfQURBUFRFUlNfRkxBVk9VUlMsXG4gICAgICAgICAgdXNlVmFsdWU6IGZsYXZvdXJzID8/IFtdLFxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgcHJvdmlkZTogT0JTRVJWRVJfRVZFTlRTX09QVElPTlMsXG4gICAgICAgICAgdXNlVmFsdWU6IG9wdGlvbnMgPz8ge30sXG4gICAgICAgIH0sXG4gICAgICBdLFxuICAgIH07XG4gIH1cbn1cbiIsImltcG9ydCB7IER5bmFtaWNNb2R1bGUsIEZvcndhcmRSZWZlcmVuY2UsIE1vZHVsZSwgVHlwZSB9IGZyb20gXCJAbmVzdGpzL2NvbW1vblwiO1xuaW1wb3J0IHsgRGVjYWZNb2R1bGVPcHRpb25zIH0gZnJvbSBcIi4vdHlwZXNcIjtcbmltcG9ydCB7IERlY2FmQ29yZU1vZHVsZSB9IGZyb20gXCIuL2NvcmUtbW9kdWxlXCI7XG5pbXBvcnQgeyBBZGFwdGVyIH0gZnJvbSBcIkBkZWNhZi10cy9jb3JlXCI7XG5pbXBvcnQgeyBnZXRNb2R1bGVGb3IgfSBmcm9tIFwiLi9kZWNhZi1tb2RlbC9pbmRleFwiO1xuaW1wb3J0IHsgRGVjYWZTdHJlYW1Nb2R1bGUgfSBmcm9tIFwiLi9ldmVudHMtbW9kdWxlXCI7XG5cbi8qKlxuICogQHB1YmxpY0FwaVxuICovXG5ATW9kdWxlKHt9KVxuZXhwb3J0IGNsYXNzIERlY2FmTW9kdWxlIHtcbiAgc3RhdGljIGFzeW5jIGZvclJvb3RBc3luYyhcbiAgICBvcHRpb25zOiBEZWNhZk1vZHVsZU9wdGlvbnNcbiAgKTogUHJvbWlzZTxEeW5hbWljTW9kdWxlPiB7XG4gICAgY29uc3QgeyBhdXRvQ29udHJvbGxlcnMsIGF1dG9TZXJ2aWNlcyB9ID0gb3B0aW9ucztcblxuICAgIGNvbnN0IGFkYXB0ZXJzOiBBZGFwdGVyPGFueSwgYW55LCBhbnksIGFueT5bXSA9XG4gICAgICBhd2FpdCBEZWNhZkNvcmVNb2R1bGUuYm9vdFBlcnNpc3RlbmNlKG9wdGlvbnMpO1xuICAgIGNvbnN0IGZsYXZvdXJzID0gYWRhcHRlcnMubWFwKChhZGFwdGVyKSA9PiBhZGFwdGVyLmZsYXZvdXIpO1xuXG4gICAgY29uc3QgaW1wb3J0czpcbiAgICAgIHwgKFxuICAgICAgICAgIHwgRHluYW1pY01vZHVsZVxuICAgICAgICAgIHwgVHlwZTxhbnk+XG4gICAgICAgICAgfCBQcm9taXNlPER5bmFtaWNNb2R1bGU+XG4gICAgICAgICAgfCBGb3J3YXJkUmVmZXJlbmNlPGFueT5cbiAgICAgICAgKVtdXG4gICAgICB8IHVuZGVmaW5lZCA9IFtEZWNhZkNvcmVNb2R1bGUuZm9yUm9vdChvcHRpb25zKV07XG5cbiAgICBpZiAoYXV0b0NvbnRyb2xsZXJzKSB7XG4gICAgICBmbGF2b3Vycy5mb3JFYWNoKChmbGF2b3VyKSA9PiB7XG4gICAgICAgIGltcG9ydHMucHVzaChcbiAgICAgICAgICBnZXRNb2R1bGVGb3IoZmxhdm91cikuZm9yUm9vdChmbGF2b3VyLCB7XG4gICAgICAgICAgICBhdXRvU2VydmljZXMsXG4gICAgICAgICAgICBjb250cm9sbGVyRXhwb3N1cmU6IG9wdGlvbnMuY29udHJvbGxlckV4cG9zdXJlLFxuICAgICAgICAgICAgY29udHJvbGxlckNvbmZpZzogb3B0aW9ucy5jb250cm9sbGVyQ29uZmlnLFxuICAgICAgICAgICAgYWdncmVnYXRpb25zOiBvcHRpb25zLmFnZ3JlZ2F0aW9ucyxcbiAgICAgICAgICB9KVxuICAgICAgICApO1xuICAgICAgfSk7XG4gICAgfVxuXG4gICAgaWYgKG9wdGlvbnMub2JzZXJ2ZXJPcHRpb25zPy5lbmFibGVPYnNlcnZlckV2ZW50cykge1xuICAgICAgaW1wb3J0cy5wdXNoKFxuICAgICAgICBEZWNhZlN0cmVhbU1vZHVsZS5mb3JGbGF2b3VycyhcbiAgICAgICAgICBvcHRpb25zLm9ic2VydmVyT3B0aW9ucy5vYnNlcnZlckZsYXZvdXJzIHx8IGZsYXZvdXJzLFxuICAgICAgICAgIG9wdGlvbnMub2JzZXJ2ZXJPcHRpb25zLm9ic2VydmVyQXBpUGF0aCA/PyBcIi9ldmVudHNcIixcbiAgICAgICAgICBvcHRpb25zLm9ic2VydmVyT3B0aW9uc1xuICAgICAgICApXG4gICAgICApO1xuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICBtb2R1bGU6IERlY2FmTW9kdWxlLFxuICAgICAgaW1wb3J0czogaW1wb3J0cyxcbiAgICB9O1xuICB9XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBydW5NaWdyYXRpb25zKCk6IFByb21pc2U8dm9pZD4ge31cbiIsImltcG9ydCB7TW9kZWx9IGZyb20gXCJAZGVjYWYtdHMvZGVjb3JhdG9yLXZhbGlkYXRpb25cIjtcbmltcG9ydCB7SW50ZXJuYWxFcnJvcn0gZnJvbSBcIkBkZWNhZi10cy9kYi1kZWNvcmF0b3JzXCI7XG5pbXBvcnQge1JlcG9zaXRvcnl9IGZyb20gXCJAZGVjYWYtdHMvY29yZVwiO1xuXG5leHBvcnQgZnVuY3Rpb24gcmVwb0Zvck1vZGVsKG1vZGVsOiBzdHJpbmcpIHtcblx0Y29uc3QgbSA9IE1vZGVsLmdldChtb2RlbCk7XG5cdGlmICghbSlcblx0XHR0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihgRmFpbGVkIHRvIGZpbmQgcmVwb3NpdG9yeSBmb3IgJHttb2RlbH1gKVxuXHRjb25zdCByZXBvID0gUmVwb3NpdG9yeS5mb3JNb2RlbChtKTtcblx0cmV0dXJuIHJlcG87XG59IiwiLyoqXG4gKiBAbW9kdWxlIGZvci1uZXN0XG4gKiBAZGVzY3JpcHRpb24gVGhpcyBtb2R1bGUgc2VydmVzIGFzIHRoZSBtYWluIGVudHJ5IHBvaW50IGZvciB0aGUgdHMtd29ya3NwYWNlIGxpYnJhcnkuIEl0IGFnZ3JlZ2F0ZXMgYW5kIGV4cG9ydHNcbiAqIGZ1bmN0aW9uYWxpdHkgZnJvbSB2YXJpb3VzIHN1Ym1vZHVsZXMgYW5kIHV0aWxpdGllcyB3aXRoaW4gdGhlIHByb2plY3QuXG4gKlxuICogVGhlIG1vZHVsZSBpbmNsdWRlczpcbiAqIDEuIFV0aWxpdHkgZnVuY3Rpb25zIGFuZCB0eXBlcyBmcm9tIHRoZSBcIi4vdXRpbHNcIiBkaXJlY3Rvcnk6XG4gKiAgICAtIFRoZXNlIGxpa2VseSBjb250YWluIGhlbHBlciBmdW5jdGlvbnMsIGNvbW1vbiB0eXBlcywgYW5kIHNoYXJlZCBmdW5jdGlvbmFsaXR5IHVzZWQgdGhyb3VnaG91dCB0aGUgcHJvamVjdC5cbiAqICAgIC0gTWF5IGluY2x1ZGUgb3BlcmF0aW9ucyBmb3IgZGF0YSBtYW5pcHVsYXRpb24sIHR5cGUgY2hlY2tpbmcsIG9yIG90aGVyIGdlbmVyYWwtcHVycG9zZSB1dGlsaXRpZXMuXG4gKlxuICogMi4gQSBuYW1lc3BhY2UgYW5kIHJlbGF0ZWQgdHlwZXMgZnJvbSB0aGUgXCIuL25hbWVzcGFjZVwiIGRpcmVjdG9yeTpcbiAqICAgIC0gVGhpcyBjb3VsZCBjb250YWluIGRvbWFpbi1zcGVjaWZpYyBjb2RlIG9yIGEgY29sbGVjdGlvbiBvZiByZWxhdGVkIGZ1bmN0aW9uYWxpdHkuXG4gKiAgICAtIE1pZ2h0IGluY2x1ZGUgaW50ZXJmYWNlcywgdHlwZXMsIG9yIGNsYXNzZXMgdGhhdCByZXByZXNlbnQgY29yZSBjb25jZXB0cyBpbiB0aGUgbGlicmFyeS5cbiAqXG4gKiAzLiBBIFZFUlNJT04gY29uc3RhbnQ6XG4gKiAgICAtIFJlcHJlc2VudHMgdGhlIGN1cnJlbnQgdmVyc2lvbiBvZiB0aGUgbW9kdWxlLlxuICogICAgLSBVc2VmdWwgZm9yIHZlcnNpb24gY2hlY2tpbmcgYW5kIGNvbXBhdGliaWxpdHkgcHVycG9zZXMuXG4gKlxuICogVGhpcyBzdHJ1Y3R1cmUgcHJvdmlkZXMgYSBjbGVhbiBhbmQgb3JnYW5pemVkIGV4cG9ydCBvZiB0aGUgbW9kdWxlJ3MgZnVuY3Rpb25hbGl0eSwgYWxsb3dpbmcgY29uc3VtZXJzXG4gKiB0byBlYXNpbHkgaW1wb3J0IGFuZCB1c2Ugc3BlY2lmaWMgcGFydHMgb2YgdGhlIGxpYnJhcnkgYXMgbmVlZGVkLlxuICovXG5cbmltcG9ydCB7IE1ldGFkYXRhIH0gZnJvbSBcIkBkZWNhZi10cy9kZWNvcmF0aW9uXCI7XG5pbXBvcnQgXCIuL2RlY29yYXRpb25cIjtcblxuZXhwb3J0ICogZnJvbSBcIi4vZGVjb3JhdGlvblwiOyAvLyBvbiB0b3Agb24gcHVycG9zZVxuZXhwb3J0ICogZnJvbSBcIi4vZGVjYWYtbW9kZWxcIjtcbmV4cG9ydCAqIGZyb20gXCIuL2F1dGhcIjtcbmV4cG9ydCAqIGZyb20gXCIuL2ZhY3RvcnlcIjtcbmV4cG9ydCAqIGZyb20gXCIuL2ludGVyY2VwdG9yc1wiO1xuZXhwb3J0ICogZnJvbSBcIi4vb3ZlcnJpZGVzXCI7XG5leHBvcnQgKiBmcm9tIFwiLi9yZXF1ZXN0XCI7XG5leHBvcnQgKiBmcm9tIFwiLi9jb25zdGFudHNcIjtcbmV4cG9ydCAqIGZyb20gXCIuL2NvbnRyb2xsZXJzXCI7XG5leHBvcnQgKiBmcm9tIFwiLi9tb2R1bGVcIjtcbmV4cG9ydCAqIGZyb20gXCIuL2NvcmUtbW9kdWxlXCI7XG5leHBvcnQgKiBmcm9tIFwiLi90eXBlc1wiO1xuZXhwb3J0ICogZnJvbSBcIi4vZGVjb3JhdG9yc1wiO1xuZXhwb3J0ICogZnJvbSBcIi4vdXRpbHNcIjtcbmV4cG9ydCAqIGZyb20gXCIuL2V2ZW50cy1tb2R1bGVcIjtcbi8vIGV4cG9ydCAqIGZyb20gXCIuL3dlYmhvb2tzXCI7XG5cbi8qKlxuICogUmVwcmVzZW50cyB0aGUgY3VycmVudCB2ZXJzaW9uIG9mIHRoZSB0cy13b3Jrc3BhY2UgbW9kdWxlLlxuICogVGhlIGFjdHVhbCB2ZXJzaW9uIG51bWJlciBpcyByZXBsYWNlZCBkdXJpbmcgdGhlIGJ1aWxkIHByb2Nlc3MuXG4gKiBAY29uc3RhbnRcbiAqIEB0eXBlIHtzdHJpbmd9XG4gKi9cbmV4cG9ydCBjb25zdCBWRVJTSU9OID0gXCIjI1ZFUlNJT04jI1wiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBSZXByZXNlbnRzIHRoZSBjdXJyZW50IGNvbW1pdCBoYXNoIG9mIHRoZSBtb2R1bGUgYnVpbGQuXG4gKiBAc3VtbWFyeSBTdG9yZXMgdGhlIGN1cnJlbnQgZ2l0IGNvbW1pdCBoYXNoIGZvciB0aGUgcGFja2FnZS4gVGhlIGJ1aWxkIHJlcGxhY2VzXG4gKiB0aGUgcGxhY2Vob2xkZXIgd2l0aCB0aGUgYWN0dWFsIGNvbW1pdCBoYXNoIGF0IHB1Ymxpc2ggdGltZS5cbiAqIEBjb25zdCBDT01NSVRcbiAqL1xuZXhwb3J0IGNvbnN0IENPTU1JVCA9IFwiIyNDT01NSVQjI1wiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBSZXByZXNlbnRzIHRoZSBmdWxsIHZlcnNpb24gc3RyaW5nIG9mIHRoZSBtb2R1bGUuXG4gKiBAc3VtbWFyeSBTdG9yZXMgdGhlIHNlbXZlciB2ZXJzaW9uIGFuZCBjb21taXQgaGFzaCBmb3IgdGhlIHBhY2thZ2UuXG4gKiBUaGUgYnVpbGQgcmVwbGFjZXMgdGhlIHBsYWNlaG9sZGVyIHdpdGggdGhlIGFjdHVhbCBgPHZlcnNpb24+LTxjb21taXQ+YCB2YWx1ZSBhdCBwdWJsaXNoIHRpbWUuXG4gKiBAY29uc3QgRlVMTF9WRVJTSU9OXG4gKi9cbmV4cG9ydCBjb25zdCBGVUxMX1ZFUlNJT04gPSBcIiMjRlVMTF9WRVJTSU9OIyNcIjtcblxuZXhwb3J0IGNvbnN0IFBBQ0tBR0VfTkFNRSA9IFwiIyNQQUNLQUdFIyNcIjtcblxuTWV0YWRhdGEuYWxsb3dSZXJlZ2lzdHJhdGlvbih0cnVlKTtcbk1ldGFkYXRhLnJlZ2lzdGVyTGlicmFyeShQQUNLQUdFX05BTUUsIFZFUlNJT04pO1xuTWV0YWRhdGEuYWxsb3dSZXJlZ2lzdHJhdGlvbihmYWxzZSk7XG4iXSwibmFtZXMiOlsiREVDT1JBVE9SU19QUkVGSVgiLCJERUNPUkFUT1JTIiwiQVBJX09QRVJBVElPTiIsIkFQSV9SRVNQT05TRSIsIkFQSV9QUk9EVUNFUyIsIkFQSV9DT05TVU1FUyIsIkFQSV9UQUdTIiwiQVBJX0NBTExCQUNLUyIsIkFQSV9QQVJBTUVURVJTIiwiQVBJX0hFQURFUlMiLCJBUElfTU9ERUxfUFJPUEVSVElFUyIsIkFQSV9NT0RFTF9QUk9QRVJUSUVTX0FSUkFZIiwiQVBJX1NFQ1VSSVRZIiwiQVBJX0VYQ0xVREVfRU5EUE9JTlQiLCJBUElfRVhDTFVERV9DT05UUk9MTEVSIiwiQVBJX0VYVFJBX01PREVMUyIsIkFQSV9FWFRFTlNJT04iLCJBUElfU0NIRU1BIiwiQVBJX0RFRkFVTFRfR0VUVEVSIiwiQVBJX0xJTksiLCJpc0NvbnN0cnVjdG9yIiwidmFsIiwiTUVUQURBVEFfRkFDVE9SWV9OQU1FIiwiTUVUSE9EX01FVEFEQVRBIiwiY3JlYXRlTWV0aG9kRGVjb3JhdG9yIiwibWV0YWtleSIsIm1ldGFkYXRhIiwib3ZlcnJpZGVFeGlzdGluZyIsInRhcmdldCIsImtleSIsImRlc2NyaXB0b3IiLCJwcmV2VmFsdWUiLCJSZWZsZWN0IiwiZ2V0TWV0YWRhdGEiLCJ2YWx1ZSIsImRlZmluZU1ldGFkYXRhIiwiY3JlYXRlQ2xhc3NEZWNvcmF0b3IiLCJjcmVhdGVQcm9wZXJ0eURlY29yYXRvciIsInByb3BlcnR5S2V5IiwicHJvcGVydGllcyIsImluY2x1ZGVzIiwiZXhpc3RpbmdNZXRhZGF0YSIsIm5ld01ldGFkYXRhIiwicGlja0J5IiwibmVnYXRlIiwiaXNVbmRlZmluZWQiLCJtZXRhZGF0YVRvU2F2ZSIsInR5cGUiLCJjb25zdHJ1Y3RvciIsImNyZWF0ZU1peGVkRGVjb3JhdG9yIiwibWV0YWRhdGFzIiwiQXJyYXkiLCJpc0FycmF5IiwicHJldmlvdXNNZXRhZGF0YSIsIk9iamVjdCIsImFzc2lnbiIsImNyZWF0ZVBhcmFtRGVjb3JhdG9yIiwiaW5pdGlhbCIsInBhcmFtT3B0aW9ucyIsInBhcmFtZXRlcnMiLCJwcm9wZXJ0eUtleXMiLCJnZXRPd25Qcm9wZXJ0eU5hbWVzIiwicHJvdG90eXBlIiwibWV0aG9kRGVzY3JpcHRvciIsImdldE93blByb3BlcnR5RGVzY3JpcHRvciIsImlzQXBpTWV0aG9kIiwiaGFzTWV0YWRhdGEiLCJnZXRUeXBlSXNBcnJheVR1cGxlIiwiaW5wdXQiLCJpc0FycmF5RmxhZyIsImlzSW5wdXRBcnJheSIsIm9iaiIsImdldEVudW1WYWx1ZXMiLCJlbnVtVHlwZSIsIm51bWVyaWNWYWx1ZXMiLCJ2YWx1ZXMiLCJmaWx0ZXIiLCJtYXAiLCJ0b1N0cmluZyIsImtleXMiLCJnZXRFbnVtVHlwZSIsImhhc1N0cmluZyIsImlzU3RyaW5nIiwibGVuZ3RoIiwicmVxdWlyZWQiLCJpc0VudW1BcnJheSIsIm9wdHMiLCJlbnVtIiwidW5kZWZpbmVkIiwiQXBpUHJvcGVydHkiLCJvcHRpb25zIiwiY3JlYXRlQXBpUHJvcGVydHlEZWNvcmF0b3IiLCJlbnVtVmFsdWVzIiwiaXRlbXMiLCJBcGlPcGVyYXRpb25Gcm9tTW9kZWwiLCJNb2RlbENvbnN0cnVjdG9yIiwidmVyYiIsInBhdGgiLCJodHRwVG9DcnVkIiwiR0VUIiwiT3BlcmF0aW9uS2V5cyIsIlJFQUQiLCJHZXQiLCJQT1NUIiwiQ1JFQVRFIiwiUG9zdCIsIlBVVCIsIlVQREFURSIsIlB1dCIsIlBBVENIIiwiUGF0Y2giLCJERUxFVEUiLCJEZWxldGUiLCJjcnVkT3AiLCJIdHRwTWV0aG9kRGVjb3JhdG9yIiwicmVzb2x2ZUJsb2NrVGFyZ2V0IiwiY29yZUlzT3BlcmF0aW9uQmxvY2tlZCIsImtpbmQiLCJhcHBseSIsIkFwaUV4Y2x1ZGVFbmRwb2ludCIsIkJ1bGtBcGlPcGVyYXRpb25Gcm9tTW9kZWwiLCJCdWxrQ3J1ZE9wZXJhdGlvbktleXMiLCJSRUFEX0FMTCIsIkNSRUFURV9BTEwiLCJVUERBVEVfQUxMIiwiREVMRVRFX0FMTCIsIm5vcm1hbGl6ZWQiLCJyZXBsYWNlIiwic3RhdGVtZW50VGFyZ2V0cyIsIlByZXBhcmVkU3RhdGVtZW50S2V5cyIsIkxJU1RfQlkiLCJQQUdFX0JZIiwiRklORCIsIlBBR0UiLCJGSU5EX09ORV9CWSIsIkZJTkRfQlkiLCJDT1VOVF9PRiIsIk1BWF9PRiIsIk1JTl9PRiIsIkFWR19PRiIsIlNVTV9PRiIsIkRJU1RJTkNUX09GIiwiR1JPVVBfT0YiLCJzdGFydHNXaXRoIiwic3RhdGVtZW50VmFsdWUiLCJBcGlQYXJhbXNGcm9tTW9kZWwiLCJwcm9wcyIsImRlY29yYXRvcnMiLCJwIiwiQXBpUGFyYW1EZWMiLCJuYW1lIiwiZGVzY3JpcHRpb24iLCJTdHJpbmciLCJhcHBseURlY29yYXRvcnMiLCJEZWNhZkJvZHkiLCJkYXRhIiwiY3R4IiwicmVxdWVzdCIsInN3aXRjaFRvSHR0cCIsImdldFJlcXVlc3QiLCJib2R5IiwiY29udHJvbGxlciIsImdldENsYXNzIiwiTW9kZWxDb25zdHIiLCJjbGFzcyIsIkludGVybmFsU2VydmVyRXJyb3JFeGNlcHRpb24iLCJpdGVtIiwiT3JkZXJlZFBhcmFtcyIsIm9yZGVyIiwicmVxIiwib3JpZ2luYWwiLCJwYXJhbXMiLCJvcmRlckxpc3QiLCJvcmRlcmVkIiwiayIsInJhdyIsInZhbHVlc0luT3JkZXIiLCJrZXlzSW5PcmRlciIsIkRlY2FmUGFyYW1zIiwiRGVjYWZRdWVyeSIsIl8iLCJxdWVyeSIsInBhcnNlZCIsImxpbWl0IiwibiIsIk51bWJlciIsImlzTmFOIiwib2Zmc2V0IiwiYm9va21hcmsiLCJERUNBRl9NT0RVTEVfT1BUSU9OUyIsIkRFQ0FGX0FEQVBURVJfSUQiLCJERUNBRl9UQVNLX1NFUlZJQ0VfSUQiLCJERUNBRl9ST1VURSIsIkRFQ0FGX0hBTkRMRVJTIiwiU3ltYm9sIiwiREVDQUZfRVhQT1NFIiwiREVDQUZfQ09OVFJPTExFUl9DT05GSUciLCJERUNBRl9DT05URVhUX0tFWSIsImV4cG9zZSIsImZsYXZvdXJzIiwiTWV0YWRhdGEiLCJzZXQiLCJjb250cm9sbGVyQ29uZmlnIiwiY29uZmlnIiwiY29udHJvbGxlckNvbmZpZ0RlY29yYXRvciIsIkFVVEhfSEFORExFUiIsIkFVVEhfTUVUQV9LRVkiLCJJU19QVUJMSUNfS0VZIiwiUkVRVUlSRURfUk9MRVNfS0VZIiwiUkVRVUlSRURfTkFNRVNQQUNFU19LRVkiLCJTS0lQX01PREVMX1JPTEVTX0tFWSIsIlNLSVBfTU9ERUxfTkFNRVNQQUNFU19LRVkiLCJEZWNhZlJlcXVlc3RDb250ZXh0IiwiUmVxdWVzdENvbnRleHQiLCJzdXBlciIsImhlYWRlcnNPZiIsImhlYWRlcnMiLCJ0aGlzIiwidXVpZCIsIlVVSUQiLCJpbnN0YW5jZSIsImdlbmVyYXRlIiwiZ2V0T3JVbmRlZmluZWQiLCJwdXQiLCJyZWNvcmQiLCJvdmVycmlkZXMiLCJnZXQiLCJlIiwiYWNjdW11bGF0ZSIsIl9fZGVjb3JhdGUiLCJJbmplY3RhYmxlIiwic2NvcGUiLCJTY29wZSIsIlJFUVVFU1QiLCJfX3BhcmFtIiwiSW5qZWN0IiwiQXV0aEludGVyY2VwdG9yIiwicmVmbGVjdG9yIiwicmVxdWVzdENvbnRleHQiLCJhdXRoSGFuZGxlciIsImludGVyY2VwdCIsIm5leHQiLCJsb2ciLCJMb2dnaW5nIiwiZm9yIiwiaXNQdWJsaWMiLCJnZXRBbGxBbmRPdmVycmlkZSIsImdldEhhbmRsZXIiLCJtb2RlbE5hbWUiLCJyZXF1aXJlZFJvbGVzIiwicmVxdWlyZWROYW1lc3BhY2VzIiwic2tpcE1vZGVsUm9sZXMiLCJza2lwTW9kZWxOYW1lc3BhY2VzIiwiZWZmZWN0aXZlTW9kZWwiLCJ2ZXJib3NlIiwiZGVidWciLCJhdXRob3JpemUiLCJhcHBseVRyYW5zZm9ybWVycyIsImhhbmRsZSIsIkFkYXB0ZXIiLCJmbGF2b3Vyc1RvVHJhbnNmb3JtIiwiZmxhdm91ciIsInRyYW5zZm9ybWVyIiwidHJhbnNmb3JtZXJGb3IiLCJmcm9tIiwiT3B0aW9uYWwiLCJSZWZsZWN0b3IiLCJBdXRoIiwibW9kZWwiLCJyZXNvdXJjZSIsImRlY3MiLCJBcGlCZWFyZXJBdXRoIiwiVXNlSW50ZXJjZXB0b3JzIiwicHVzaCIsIlNldE1ldGFkYXRhIiwiUHVibGljIiwiUmVxdWlyZVJvbGVzIiwicm9sZXMiLCJBcGlTZWN1cml0eSIsIlJlcXVpcmVOYW1lc3BhY2VzIiwibmFtZXNwYWNlcyIsIkh0dHBWZXJiVG9EZWNvcmF0b3IiLCJkZWNvcmF0b3IiLCJVbnN1cHBvcnRlZEVycm9yIiwiZXh0cmFjdFBhdGhQYXJhbXMiLCJyb3V0ZVBhdGgiLCJzcGxpdCIsInNsaWNlIiwiYXBpUGFyYW1TcGVjIiwidG9EZWNhZkVycm9yIiwiZXJyb3IiLCJmYWxsYmFja01lc3NhZ2UiLCJCYXNlRXJyb3IiLCJJbnRlcm5hbEVycm9yIiwiRXJyb3IiLCJtZXNzYWdlIiwiZ2V0QXBpRGVjb3JhdG9ycyIsIm1ldGhvZE5hbWUiLCJodHRwVmVyYiIsImluY2x1ZGVRdWVyeVBhcmFtcyIsIk5lc3RIdHRwUm91dGVEZWMiLCJhcGlQYXRoUGFyYW1zIiwic3dhZ2dlclF1ZXJ5UGFyYW1zIiwiQXBpUXVlcnkiLCJPcmRlckRpcmVjdGlvbiIsIm1ldGhvZCIsIkFwaVBhcmFtIiwiQXBpT3BlcmF0aW9uIiwic3VtbWFyeSIsIkFwaU9rUmVzcG9uc2UiLCJBcGlOb0NvbnRlbnRSZXNwb25zZSIsIlF1ZXJ5IiwiYXBwbHlBcGlEZWNvcmF0b3JzIiwicHJvdG8iLCJmb3JFYWNoIiwiZCIsImluZGV4IiwicmVzb2x2ZVBlcnNpc3RlbmNlTWV0aG9kIiwicGVyc2lzdGVuY2UiLCJhcmdzIiwiTW9kZWxTZXJ2aWNlIiwic3RhdGVtZW50IiwiY3JlYXRlUm91dGVIYW5kbGVyIiwiYXN5bmMiLCJwYXRoUGFyYW1zIiwicXVlcnlQYXJhbXMiLCJKU09OIiwic3RyaW5naWZ5IiwiZGlyZWN0aW9uIiwiZGVmaW5lUm91dGVNZXRob2QiLCJDb250cm9sbGVyQ2xhc3MiLCJoYW5kbGVyIiwiZGVmaW5lUHJvcGVydHkiLCJ3cml0YWJsZSIsIlJFUVVFU1RfQ09OVEVYVFVBTElaRURfS0VZIiwiY29udGV4dHVhbGl6ZVJlcXVlc3RDb250ZXh0IiwiZmxhZ3MiLCJpcCIsImV4dHJhY3RJcCIsImN1cnJlbnRMb2ciLCJsb2dnZXIiLCJEZWZhdWx0QWRhcHRlckZsYWdzIiwidGltZXN0YW1wIiwiRGF0ZSIsIm9wZXJhdGlvbiIsInVybCIsInBhcnNlSXBIZWFkZXIiLCJjYW5kaWRhdGUiLCJzZWdtZW50IiwidHJpbSIsIkJvb2xlYW4iLCJBdXRoTWlkZGxld2FyZSIsInVzZSIsIl9yZXMiLCJwcmltZSIsIkRlY2FmQXV0aEhhbmRsZXIiLCJBdXRoSGFuZGxlciIsImlzUHVibGljUmVxdWVzdCIsIl9yZXF1ZXN0IiwicGFyc2VSZXF1ZXN0IiwidXNlclJvbGUiLCJhdXRob3JpemF0aW9uIiwicmVxdWVzdEZyb21Db250ZXh0IiwiZXh0cmFjdEZyb21SZXF1ZXN0IiwiQXV0aG9yaXphdGlvbkVycm9yIiwidXNlciIsIkRlY2FmUm9sZUF1dGhIYW5kbGVyIiwiRGVjYWZBdXRoTW9kdWxlIiwiRGVjYWZBdXRoTW9kdWxlXzEiLCJmb3JSb290IiwicHJvdmlkZXJzIiwicHJvdmlkZSIsInVzZUNsYXNzIiwiZ2xvYmFsIiwiQVBQX0lOVEVSQ0VQVE9SIiwidXNlRXhpc3RpbmciLCJtb2R1bGUiLCJleHBvcnRzIiwiY29uZmlndXJlIiwiY29uc3VtZXIiLCJmb3JSb3V0ZXMiLCJSZXF1ZXN0TWV0aG9kIiwiQUxMIiwiTW9kdWxlIiwiRGVjYWZIYW5kbGVyRXhlY3V0b3IiLCJEZWNhZkhhbmRsZXJFeGVjdXRvcl8xIiwiaGFuZGxlcnMiLCJjb250ZXh0IiwiZXhlYyIsInJlcyIsIkRlY2FmUmVzcG9uc2VJbnRlcmNlcHRvciIsInJlc3BvbnNlIiwiZ2V0UmVzcG9uc2UiLCJwaXBlIiwidGFwIiwidG9SZXNwb25zZSIsIkRlY2FmQ29udHJvbGxlciIsIkh0dHBEZWNhZkNvbnRyb2xsZXIiLCJjbGllbnRDb250ZXh0IiwiX25hbWUiLCJEZWNhZk1vZGVsQ29udHJvbGxlciIsIl9wZXJzaXN0ZW5jZSIsIlNlcnZpY2UiLCJnZXRTZXJ2aWNlIiwiUmVwb3NpdG9yeSIsImZvck1vZGVsIiwiYWN0aXZlQ3R4IiwidG9PdmVycmlkZXMiLCJvdmVycmlkZSIsImR0b0NhY2hlIiwiTWFwIiwiRHRvRm9yIiwib3AiLCJzdGFjayIsIlNldCIsIlRyYW5zYWN0aW9uT3BlcmF0aW9uS2V5cyIsImNhY2hlIiwiZ2V0RHRvQ2FjaGUiLCJjYWNoZWQiLCJpc1VwZGF0ZU9wIiwiRHluYW1pY0RUTyIsInRvUGFzY2FsQ2FzZSIsInBrUHJvcCIsIk1vZGVsIiwicGsiLCJwa1Byb3BzTWV0YWRhdGEiLCJwa1Byb3BzIiwicGtEZXNpZ25UeXBlIiwicGtUeXBlSXNOdW1lcmljIiwiQmlnSW50IiwicGtJc0dlbmVyYXRlZCIsImdlbmVyYXRlZCIsImdlbmVyYXRlZEJ5U2VxdWVuY2UiLCJpc1Byb3BlcnR5R2VuZXJhdGVkQWNyb3NzSW5oZXJpdGFuY2UiLCJhbGxQcm9wcyIsInJlbGF0aW9ucyIsInNjYWxhclByb3BzIiwicHJvcCIsImhhcyIsInZhbGlkYXRpb24iLCJnZXRWYWxpZGF0aW9uQWNyb3NzSW5oZXJpdGFuY2UiLCJpc1JlcXVpcmVkIiwiVmFsaWRhdGlvbktleXMiLCJSRVFVSVJFRCIsInR5cGVIaW50IiwiZ2V0VHlwZUFjcm9zc0luaGVyaXRhbmNlIiwiYXBpT3B0aW9ucyIsImRlc2lnblR5cGUiLCJlbnVtZXJhYmxlIiwiY29uZmlndXJhYmxlIiwicmVsYXRpb24iLCJyZWxhdGlvbk1ldGEiLCJyZWxhdGlvblR5cGUiLCJtZXRhIiwidmFsaWRhdGlvbkZvciIsIkxJU1QiLCJpc0NpcmN1bGFyIiwicGtUeXBlTmFtZSIsImdldFBrT3BlbkFwaVR5cGUiLCJhZGRSZWxhdGlvblBrUmVmIiwicmVsYXRpb25EdG8iLCJhZGQiLCJhZGRSZWxhdGlvblVwZGF0ZSIsImFkZFJlbGF0aW9uIiwiRHRvQ2xhc3MiLCJleHRyYU1vZGVscyIsImR0b1JlZiIsIm9uZU9mSXRlbXMiLCIkcmVmIiwib25lT2YiLCJwa1R5cGUiLCJjdXJyZW50IiwiRnVuY3Rpb24iLCJnZXRQcm90b3R5cGVPZiIsIldlYWtNYXAiLCJ0b0NvbnRleHRGbGFncyIsImFkYXB0ZXIiLCJhbGlhcyIsImJpbmQiLCJyZXF1ZXN0VHJhbnNmb3JtZXJzIiwiQ29udGV4dCIsInBlbmRpbmciLCJoZWFkZXIiLCJNb2RlbEJ1aWxkZXIiLCJkZWNvcmF0ZUNsYXNzIiwiX2NsYXNzRGVjb3JhdG9ycyIsIl9faGFzQ2xhc3NEZWNvcmF0b3JTdXBwb3J0Iiwib3JpZ2luYWxCdWlsZCIsImJ1aWxkIiwicmVzdWx0IiwiY2FsbCIsImRlY29yYXRlZCIsIkZyb21Nb2RlbENvbnRyb2xsZXIiLCJnZXRQZXJzaXN0ZW5jZSIsIk1vZGVsQ2xhenoiLCJlMiIsImNyZWF0ZVF1ZXJ5Um91dGVzRnJvbVJlcG9zaXRvcnkiLCJwcmVmaXgiLCJQZXJzaXN0ZW5jZUtleXMiLCJRVUVSWSIsInJlcG8iLCJxdWVyeU1ldGhvZHMiLCJyb3V0ZU1ldGhvZHMiLCJRdWVyeUNvbnRyb2xsZXIiLCJlbnRyaWVzIiwiam9pbiIsImNyZWF0ZUNvbXBsZXhRdWVyeUhhbmRsZXIiLCJkZWZpbmVNZXRob2QiLCJodHRwRGVjb3JhdG9yIiwiaHR0cE1ldGhvZCIsImdldFF1ZXJ5RGVjb3JhdG9ycyIsIm9ialZhbHVlcyIsImZpZWxkcyIsImYiLCJjcmVhdGUiLCJtb2R1bGVDb25maWdPdmVycmlkZXMiLCJnbG9iYWxEZWZhdWx0cyIsInRhYmxlTmFtZSIsInRvS2ViYWJDYXNlIiwibW9kZWxDbGF6ek5hbWUiLCJmYWN0b3J5UGVyc2lzdGVuY2UiLCJkZWNvcmF0b3JDb25maWciLCJtb2R1bGVPdmVycmlkZSIsIm1lcmdlZENvbmZpZyIsIkZhY3RvcnlDb250cm9sbGVyIiwiTW9kZWxDb250cm9sbGVyRmFjdG9yeSIsImZhY3RvcnlSb3V0ZXMiLCJfX3JvdXRlc19fIiwiZ2V0UEsiLCJhcGlQcm9wZXJ0aWVzIiwicGtQYXRoIiwiZ2V0Um91dGVQYXJhbWV0ZXJzRnJvbU1vZGVsIiwiYXV0aENvbmZpZyIsImF1dGgiLCJhcHBseUNsYXNzQXV0aCIsInB1YmxpYyIsIkR5bmFtaWNNb2RlbENvbnRyb2xsZXIiLCJEeW5hbWljTW9kZWxDb250cm9sbGVyXzEiLCJpbmZvIiwiQ29udHJvbGxlciIsIkFwaVRhZ3MiLCJBcGlFeHRyYU1vZGVscyIsInNvcnRlZFJvdXRlcyIsInNvcnQiLCJhIiwiYiIsImFTZWdtZW50cyIsImJTZWdtZW50cyIsImFQYXJhbUNvdW50IiwicyIsImJQYXJhbUNvdW50IiwiYUxpdGVyYWxDb3VudCIsImJMaXRlcmFsQ291bnQiLCJyb3V0ZSIsImltcGxlbWVudGF0aW9uIiwidG9Mb3dlckNhc2UiLCJyZWdpc3RyYXRpb24iLCJtYXRjaFJvdXRlIiwicmVnaXN0ZXJlZE1ldGhvZE5hbWUiLCJwYXJhbURlY29yYXRvcnMiLCJjb21wb3NlZCIsIkRCS2V5cyIsIkNPTVBPU0VEIiwiY29tcG9zZWRLZXlzIiwidW5pcXVlS2V5cyIsInNlcGFyYXRvciIsInJvdXRlUGFyYW1EZWNvcmF0b3JzIiwicGFyYW1JbmRleCIsImZsYXRNYXAiLCJQYXJhbSIsIm1ldGhvZERlY29yYXRvcnMiLCJub3JtYWxpemVkUGF0aCIsImNyZWF0ZVJlZ2lzdHJhdGlvbiIsImNyZWF0ZUNyZWF0ZURlY29yYXRvcnMiLCJSZXNwb25zZSIsInBhc3N0aHJvdWdoIiwiYnVsa0NyZWF0ZURlY29yYXRvcnMiLCJidWxrUmVhZERlY29yYXRvcnMiLCJidWxrVXBkYXRlRGVjb3JhdG9ycyIsImJ1bGtEZWxldGVEZWNvcmF0b3JzIiwicmVhZERlY29yYXRvcnMiLCJyb3V0ZVBhcmFtcyIsInVwZGF0ZURlY29yYXRvcnMiLCJkZWxldGVEZWNvcmF0b3JzIiwiZmFsbGJhY2tTZWdtZW50cyIsImlzQWxsUGFyYW1zIiwiZXZlcnkiLCJmYWxsYmFja0FwaVByb3BzIiwic3VmZml4Iiwic3RhdGVtZW50RGVjb3JhdG9ycyIsInN0YXRlbWVudFNob3J0Y3V0RGVjb3JhdG9ycyIsInN0YXRlbWVudFNob3J0Y3V0UGFyYW1zIiwic3RhdGVtZW50Um91dGVzIiwic3RhdGVtZW50S2V5Iiwic3RhdGVtZW50TWV0aG9kTmFtZSIsInF1ZXJ5TWV0aG9kIiwiY29tcGxleFF1ZXJ5UGFyYW1zIiwicGF0aFNlZ21lbnRzIiwia25vd25QcmVmaXhlcyIsImZpcnN0U2VnbWVudCIsInNlZ21lbnRzIiwic2VnIiwiaSIsImNvbXBsZXhRdWVyeSIsImxvZ0N0eCIsInNwcmVhZEFyZ3MiLCJub3JtYWxpemVRdWVyeUFyZ3MiLCJleHRyYWN0UXVlcnlBcmdzIiwibGFzdCIsInF1ZXJ5T2JqIiwicG9wIiwiaGFzRGlyZWN0aW9uIiwiaGFzTGltaXQiLCJoYXNPZmZzZXQiLCJleHRyYXMiLCJoYXNRdWVyeUZpZWxkcyIsIkFwaUJvZHkiLCJBcGlDcmVhdGVkUmVzcG9uc2UiLCJzY2hlbWEiLCJnZXRTY2hlbWFQYXRoIiwiQXBpQmFkUmVxdWVzdFJlc3BvbnNlIiwiQXBpVW5wcm9jZXNzYWJsZUVudGl0eVJlc3BvbnNlIiwiQXBpTm90Rm91bmRSZXNwb25zZSIsImJhc2UiLCJnZXRNb2R1bGVGb3IiLCJEZWNhZk1vZGVsTW9kdWxlIiwiRGVjYWZNb2RlbE1vZHVsZV8xIiwiY3JlYXRlTW9kZWxTZXJ2aWNlcyIsIm1vZGVscyIsInVzZUZhY3RvcnkiLCJpc0V4cG9zZWQiLCJleHBvc3VyZSIsInRyYWNrZWRNb2RlbHMiLCJjb250cm9sbGVyRXhwb3N1cmUiLCJtb2RlbFNlcnZpY2VzIiwiYXV0b1NlcnZpY2VzIiwiYWdncmVnYXRpb25zIiwiYWxsb3dHcm91cGluZ1F1ZXJpZXMiLCJjb250cm9sbGVycyIsIkRlY29yYXRpb24iLCJJbmplY3RhYmxlc0tleXMiLCJJTkpFQ1RBQkxFIiwiZXh0ZW5kIiwibmVzdEluamVjdGFibGUiLCJjYXRlZ29yeSIsImNmZyIsIkRlZmF1bHRJbmplY3RhYmxlc0NvbmZpZyIsInNpbmdsZXRvbiIsIkRFRkFVTFQiLCJkdXJhYmxlIiwiSU5KRUNUIiwibmVzdEluamVjdCIsImlubmVyTmVzdEluamVjdCIsIk1BWCIsIm1heERlYyIsIm1heCIsIm1heGltdW0iLCJNSU4iLCJtaW5EZWMiLCJtaW4iLCJtaW5pbXVtIiwiTUFYX0xFTkdUSCIsIm1heExlbmd0aERlYyIsIm1heExlbmd0aCIsIk1JTl9MRU5HVEgiLCJtaW5MZW5ndGhEZWMiLCJtaW5MZW5ndGgiLCJUWVBFIiwidHlwZURlYyIsIkRBVEUiLCJkYXRlRGVjIiwiZm9ybWF0IiwiRU5VTSIsIm9wdGlvbkRlYyIsIlBBVFRFUk4iLCJwYXR0ZXJuRGVjIiwicGF0IiwicGF0dGVybiIsInNvdXJjZSIsIkNPTFVNTiIsImNvbHVtbkRlYyIsIkRlY29yYXRpb25LZXlzIiwiREVTQ1JJUFRJT04iLCJkZXNjcmlwdGlvbkRlYyIsIkFVVEgiLCJDb3JzRXJyb3IiLCJGb3JiaWRkZW5FcnJvciIsIm1zZyIsIlRvTWFueVJlcXVlc3RzRXJyb3IiLCJIVFRQX0VYQ0VQVElPTl9UT19ERUNBRl9FUlJPUiIsIlVuYXV0aG9yaXplZEV4Y2VwdGlvbiIsIkZvcmJpZGRlbkV4Y2VwdGlvbiIsIkJhZFJlcXVlc3RFeGNlcHRpb24iLCJCYWRSZXF1ZXN0RXJyb3IiLCJDb25mbGljdEV4Y2VwdGlvbiIsIkNvbmZsaWN0RXJyb3IiLCJVbnByb2Nlc3NhYmxlRW50aXR5RXhjZXB0aW9uIiwiVmFsaWRhdGlvbkVycm9yIiwiRGVjYWZFeGNlcHRpb25GaWx0ZXIiLCJtb2R1bGVSZWYiLCJleGNlcHRpb24iLCJob3N0IiwiaXNQcm9kdWN0aW9uIiwiTG9nZ2VkRW52aXJvbm1lbnQiLCJlbnYiLCJzdGF0dXNDb2RlIiwiTm90Rm91bmRFeGNlcHRpb24iLCJOb3RBY2NlcHRhYmxlRXhjZXB0aW9uIiwiZ2V0U3RhdHVzIiwiZGVjYWZFcnJvckZvciIsInN0YXR1cyIsIkh0dHBFeGNlcHRpb24iLCJsb2dFcnJvciIsImNvZGUiLCJqc29uIiwidG9JU09TdHJpbmciLCJmYWN0b3J5IiwicmVzb2x2ZUxvZ2dlciIsImNvbnRleHRJZCIsIkNvbnRleHRJZEZhY3RvcnkiLCJnZXRCeVJlcXVlc3QiLCJyZXNvbHZlIiwic3RyaWN0IiwiQ2F0Y2giLCJNb2R1bGVSZWYiLCJVc2VEZWNhZkZpbHRlciIsIlVzZUZpbHRlcnMiLCJVc2VEZWNhZkhlYWRlcnMiLCJTV0FHR0VSX1VJX0NPTlNUQU5UUyIsInRpdGxlIiwidmVyc2lvbiIsImZhdmljb25GaWxlUGF0aCIsInRvcGJhckljb25GaWxlUGF0aCIsInNjaGVtZSIsImJlYXJlckZvcm1hdCIsImluIiwicGVyc2lzdEF1dGhvcml6YXRpb24iLCJ0b3BiYXJCZ0NvbG9yIiwiU3dhZ2dlckN1c3RvbVVJIiwiY3VzdG9tQ1NTIiwiY3NzIiwidG9wYmFySWNvblBhdGgiLCJpbWciLCJiNjQiLCJnZXRDdXN0b21PcHRpb25zIiwiZmF2aWNvbiIsImZhdmljb25QYXRoIiwiY3VzdG9tU2l0ZVRpdGxlIiwiY3VzdG9tQ3NzIiwic3dhZ2dlck9wdGlvbnMiLCJmaWxlIiwiZmlsZVBhdGgiLCJhc3NldHNQYXRoIiwicmVhZEZpbGVTeW5jIiwiZW5jb2RpbmciLCJTd2FnZ2VyQnVpbGRlciIsImFwcCIsImNyZWF0ZURvY3VtZW50Iiwib3BlbkFwaUpzb25QYXRoIiwib3BlbkFwaVlhbWxQYXRoIiwiRG9jdW1lbnRCdWlsZGVyIiwic2V0VGl0bGUiLCJzZXREZXNjcmlwdGlvbiIsInNldFZlcnNpb24iLCJhZGRCZWFyZXJBdXRoIiwiU3dhZ2dlck1vZHVsZSIsInJlZ2lzdGVyT3BlbkFwaVJvdXRlIiwiY29udGVudFR5cGUiLCJib2R5RmFjdG9yeSIsImh0dHBBZGFwdGVyIiwiZ2V0SHR0cEFkYXB0ZXIiLCJfcmVxIiwicmVwbHkiLCJzZXR1cFN3YWdnZXIiLCJkb2N1bWVudCIsInN3YWdnZXJVSSIsInNldHVwIiwianNvbkRvY3VtZW50VXJsIiwieWFtbERvY3VtZW50VXJsIiwiWUFNTCIsIk5lc3RCb290c3RyYXBlciIsIl9sb2dnZXIiLCJMb2dnZXIiLCJpbml0aWFsaXplIiwiZW5hYmxlTG9nZ2VyIiwiY3VzdG9tTG9nZ2VyIiwidXNlTG9nZ2VyIiwiZW5hYmxlQ29ycyIsIm9yaWdpbnMiLCJhbGxvd01ldGhvZHMiLCJhbGxvd2VkT3JpZ2lucyIsIm8iLCJjb3JzT3B0aW9ucyIsIm9yaWdpbiIsImNhbGxiYWNrIiwiY3JlZGVudGlhbHMiLCJtZXRob2RzIiwidXNlSGVsbWV0IiwiaGVsbWV0IiwicmVxdWlyZSIsIndhcm4iLCJzd2FnZ2VyIiwidXNlR2xvYmFsUGlwZXMiLCJwaXBlcyIsInVzZUdsb2JhbEZpbHRlcnMiLCJmaWx0ZXJzIiwidXNlR2xvYmFsSW50ZXJjZXB0b3JzIiwiaW50ZXJjZXB0b3JzIiwic3RhcnQiLCJwb3J0IiwicHJvY2VzcyIsIlBPUlQiLCJsaXN0ZW4iLCJ0aGVuIiwiZ2V0VXJsIiwiRGVjYWZSZXF1ZXN0SGFuZGxlckludGVyY2VwdG9yIiwiRGVjYWZSZXF1ZXN0SGFuZGxlckludGVyY2VwdG9yXzEiLCJleGVjdXRvciIsImNvbnRleHR1YWxpemUiLCJwZW5kaW5nUHJvdmlkZXJzIiwiZ2V0UmVnaXN0ZXJlZERlY2FmUHJvdmlkZXJzIiwicmVnaXN0ZXJQcm92aWRlciIsInRva2VuIiwiaXNNb2RlbENvbnN0cnVjdG9yIiwibW9kZWxTZXJ2aWNlVG9rZW4iLCJtb2RlbFJlcG9zaXRvcnlUb2tlbiIsInBhcmFtZXRlckluZGV4IiwicmVzb2x2ZWQiLCJwYXJhbVR5cGVzIiwiYXNNb2RlbCIsImluamVjdGFibGVTZXJ2aWNlS2V5IiwiQ29yZVNlcnZpY2UiLCJDb3JlUmVwb3NpdG9yeSIsIkRlY2FmQ29yZU1vZHVsZSIsIkRlY2FmQ29yZU1vZHVsZV8xIiwiZGVjYWZQcm92aWRlcnMiLCJ1c2VWYWx1ZSIsImNsaWVudCIsIkgiLCJwcm92aWRlciIsImJvb3RQZXJzaXN0ZW5jZSIsInRyaW1tZWQiLCJjb25mIiwiY29udHIiLCJwb3NzaWJsZSIsIlBlcnNpc3RlbmNlU2VydmljZSIsImJvb3QiLCJjbGllbnRzIiwiYyIsInBvc3NpYmxlVHJhbnNmIiwicmVxdWVzdFRvQ29udGV4dFRyYW5zZm9ybWVyIiwiaW5pdGlhbGl6YXRpb24iLCJvbkFwcGxpY2F0aW9uU2h1dGRvd24iLCJhZGFwdGVycyIsInNodXRkb3duIiwiR2xvYmFsIiwiTElTVEVOSU5HX0FEQVBURVJTX0ZMQVZPVVJTIiwiT0JTRVJWRVJfRVZFTlRTX09QVElPTlMiLCJub3JtYWxpemVFdmVudFJlc3BvbnNlIiwibW9kZWxDb25zdHIiLCJpZCIsInBheWxvYWQiLCJzZXJpYWxpemVkUGF5bG9hZCIsInNlcmlhbGl6ZSIsImNvbnNvbGUiLCJlcnIiLCJPYnNlcnZlclN1YnNjcmlwdGlvblJlZ2lzdHJ5IiwicmVjb3JkcyIsInVwc2VydCIsInN1YnNjcmliZXJJZCIsInRvcGljcyIsInVwZGF0ZWRBdCIsInJlbW92ZSIsImRlbGV0ZSIsInRvcGljc0ZvciIsIm1hdGNoZXMiLCJ0b3BpYyIsInNpemUiLCJFdmVudHNDb250cm9sbGVyIiwiRXZlbnRzQ29udHJvbGxlcl8xIiwicmVnaXN0cnkiLCJzdWJzY3JpcHRpb25Nb2RlIiwiYWN0aXZlU3Vic2NyaWJlcklkIiwiZXZlbnRzJCIsIk9ic2VydmFibGUiLCJvYnNlcnZlciIsIm9ic2VydmVySWQiLCJNYXRoIiwicmFuZG9tIiwidG9VcHBlckNhc2UiLCJjYiIsInJlZnJlc2giLCJQcm9taXNlIiwiX2FyZ3MiLCJhZGFwdGVyTmFtZSIsIm9ic2VydmUiLCJ1bk9ic2VydmUiLCJIRUFSVEJFQVRfSU5URVJWQUxfTVMiLCJoZWFydGJlYXQkIiwiaW50ZXJ2YWwiLCJ0cyIsIm1lcmdlIiwibGlzdGVuRm9yTW9kZWwiLCJTc2UiLCJfX21ldGFkYXRhIiwiRXZlbnRzU3Vic2NyaXB0aW9uQ29udHJvbGxlciIsIkV2ZW50c1N1YnNjcmlwdGlvbkNvbnRyb2xsZXJfMSIsInN1YnNjcmliZSIsImVuYWJsZWQiLCJ1bnN1YnNjcmliZSIsInVuc3Vic2NyaWJlZCIsIkJvZHkiLCJEZWNhZlN0cmVhbU1vZHVsZSIsIkRlY2FmU3RyZWFtTW9kdWxlXzEiLCJmb3JGbGF2b3VycyIsImltcG9ydHMiLCJSb3V0ZXJNb2R1bGUiLCJyZWdpc3RlciIsIkRlY2FmTW9kdWxlIiwiRGVjYWZNb2R1bGVfMSIsImZvclJvb3RBc3luYyIsImF1dG9Db250cm9sbGVycyIsIm9ic2VydmVyT3B0aW9ucyIsImVuYWJsZU9ic2VydmVyRXZlbnRzIiwib2JzZXJ2ZXJGbGF2b3VycyIsIm9ic2VydmVyQXBpUGF0aCIsInJ1bk1pZ3JhdGlvbnMiLCJyZXBvRm9yTW9kZWwiLCJtIiwiVkVSU0lPTiIsIkNPTU1JVCIsIkZVTExfVkVSU0lPTiIsIlBBQ0tB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
|