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