UNPKG

@aws-amplify/graphql-api-construct

Version:

AppSync GraphQL Api Construct using Amplify GraphQL Transformer.

293 lines 50.1 kB
"use strict"; var _a; Object.defineProperty(exports, "__esModule", { value: true }); exports.AmplifyGraphqlApi = void 0; const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti"); const path = require("path"); const constructs_1 = require("constructs"); const graphql_transformer_1 = require("@aws-amplify/graphql-transformer"); const aws_cdk_lib_1 = require("aws-cdk-lib"); const backend_output_storage_1 = require("@aws-amplify/backend-output-storage"); const backend_output_schemas_1 = require("@aws-amplify/backend-output-schemas"); const aws_appsync_1 = require("aws-cdk-lib/aws-appsync"); const user_defined_slots_1 = require("./internal/user-defined-slots"); const internal_1 = require("./internal"); const construct_tree_1 = require("./internal/construct-tree"); const data_source_config_1 = require("./internal/data-source-config"); const metadata_1 = require("./internal/metadata"); /** * L3 Construct which invokes the Amplify Transformer Pattern over an input Graphql Schema. * * This can be used to quickly define appsync apis which support full CRUD+List and Subscriptions, relationships, * auth, search over data, the ability to inject custom business logic and query/mutation operations, and connect to ML services. * * For more information, refer to the docs links below: * Data Modeling - https://docs.amplify.aws/cli/graphql/data-modeling/ * Authorization - https://docs.amplify.aws/cli/graphql/authorization-rules/ * Custom Business Logic - https://docs.amplify.aws/cli/graphql/custom-business-logic/ * Search - https://docs.amplify.aws/cli/graphql/search-and-result-aggregations/ * ML Services - https://docs.amplify.aws/cli/graphql/connect-to-machine-learning-services/ * * For a full reference of the supported custom graphql directives - https://docs.amplify.aws/cli/graphql/directives-reference/ * * The output of this construct is a mapping of L2 or L1 resources generated by the transformer, which generally follow the access pattern * * ```typescript * const api = new AmplifyGraphQlApi(this, 'api', { <params> }); * // Access L2 resources under `.resources` * api.resources.tables["Todo"].tableArn; * * // Access L1 resources under `.resources.cfnResources` * api.resources.cfnResources.cfnGraphqlApi.xrayEnabled = true; * Object.values(api.resources.cfnResources.cfnTables).forEach(table => { * table.pointInTimeRecoverySpecification = { pointInTimeRecoveryEnabled: false }; * }); * ``` * `resources.<ResourceType>.<ResourceName>` - you can then perform any CDK action on these resulting resoureces. */ class AmplifyGraphqlApi extends constructs_1.Construct { /** * New AmplifyGraphqlApi construct, this will create an appsync api with authorization, a schema, and all necessary resolvers, functions, * and datasources. * @param scope the scope to create this construct within. * @param id the id to use for this api. * @param props the properties used to configure the generated api. */ constructor(scope, id, props) { super(scope, id); /** * Be very careful editing this value. This is the string that is used to identify graphql stacks in BI metrics */ this.stackType = 'api-AppSync'; this.stack = aws_cdk_lib_1.Stack.of(scope); // Fall back to default true if no feature flag is provided, otherwise honor the feature flag value provided this.node.setContext('@aws-cdk/aws-iam:oidcRejectUnauthorizedConnections', aws_cdk_lib_1.FeatureFlags.of(this).isEnabled('@aws-cdk/aws-iam:oidcRejectUnauthorizedConnections') ?? true); validateNoOtherAmplifyGraphqlApiInStack(this); const { definition, authorizationModes, conflictResolution, functionSlots, transformerPlugins, predictionsBucket, stackMappings, translationBehavior, functionNameMap, outputStorageStrategy, dataStoreConfiguration, logging, } = props; if (conflictResolution && dataStoreConfiguration) { throw new Error('conflictResolution is deprecated. conflictResolution and dataStoreConfiguration cannot be used together. Please use dataStoreConfiguration.'); } this.dataStoreConfiguration = dataStoreConfiguration || conflictResolution; const attributionMetadata = { dataSources: (0, metadata_1.getMetadataDataSources)(definition), authorizationModes: (0, metadata_1.getMetadataAuthorizationModes)(authorizationModes), customOperations: (0, metadata_1.getMetadataCustomOperations)(definition), }; new backend_output_storage_1.AttributionMetadataStorage().storeAttributionMetadata(aws_cdk_lib_1.Stack.of(scope), this.stackType, path.join(__dirname, '..', 'package.json'), attributionMetadata); (0, internal_1.validateAuthorizationModes)(authorizationModes); const { authConfig, authSynthParameters } = (0, internal_1.convertAuthorizationModesToTransformerAuthConfig)(authorizationModes); (0, user_defined_slots_1.validateFunctionSlots)(functionSlots ?? []); const separatedFunctionSlots = (0, user_defined_slots_1.separateSlots)([...(functionSlots ?? []), ...definition.functionSlots]); // Allow amplifyEnvironmentName to be retrieve from context, and use value 'NONE' if no value can be found. // amplifyEnvironmentName is required for logical id suffixing, as well as Exports from the nested stacks. // Allow export so customers can reuse the env in their own references downstream. const amplifyEnvironmentName = this.node.tryGetContext('amplifyEnvironmentName') ?? 'NONE'; if (amplifyEnvironmentName.length > 8) { throw new Error(`or cdk --context env must have a length <= 8, found ${amplifyEnvironmentName}`); } const assetProvider = new internal_1.AssetProvider(this); const transformParameters = { ...internal_1.defaultTranslationBehavior, ...(translationBehavior ?? {}), allowGen1Patterns: false, }; const executeTransformConfig = { scope: this, nestedStackProvider: { provide: (nestedStackScope, name) => new aws_cdk_lib_1.NestedStack(nestedStackScope, name), }, assetProvider, synthParameters: { amplifyEnvironmentName: amplifyEnvironmentName, apiName: props.apiName ?? id, ...authSynthParameters, provisionHotswapFriendlyResources: translationBehavior?._provisionHotswapFriendlyResources, }, schema: definition.schema, userDefinedSlots: (0, user_defined_slots_1.parseUserDefinedSlots)(separatedFunctionSlots), transformersFactoryArgs: { customTransformers: transformerPlugins ?? [], ...(predictionsBucket ? { storageConfig: { bucketName: predictionsBucket.bucketName } } : {}), functionNameMap: { ...definition.referencedLambdaFunctions, ...functionNameMap, }, outputStorageStrategy: outputStorageStrategy, }, authConfig, stackMapping: stackMappings ?? {}, resolverConfig: this.dataStoreConfiguration ? (0, internal_1.convertToResolverConfig)(this.dataStoreConfiguration) : undefined, transformParameters, // CDK construct uses a custom resource. We'll define this explicitly here to remind ourselves that this value is unused in the CDK // construct flow rdsLayerMapping: undefined, rdsSnsTopicMapping: undefined, ...(0, data_source_config_1.getDataSourceStrategiesProvider)(definition), logging, }; (0, graphql_transformer_1.executeTransform)(executeTransformConfig); this.codegenAssets = new internal_1.CodegenAssets(this, 'AmplifyCodegenAssets', { modelSchema: definition.schema }); this.resources = (0, internal_1.getGeneratedResources)(this); this.generatedFunctionSlots = (0, internal_1.getGeneratedFunctionSlots)(assetProvider.resolverAssets); this.storeOutput(outputStorageStrategy); this.apiId = this.resources.cfnResources.cfnGraphqlApi.attrApiId; this.graphqlUrl = this.resources.cfnResources.cfnGraphqlApi.attrGraphQlUrl; this.realtimeUrl = this.resources.cfnResources.cfnGraphqlApi.attrRealtimeUrl; this.apiKey = this.resources.cfnResources.cfnApiKey?.attrApiKey; } /** * Stores graphql api output to be used for client config generation * @param outputStorageStrategy Strategy to store construct outputs. If no strategy is provided a default strategy will be used. */ storeOutput(outputStorageStrategy = new backend_output_storage_1.StackMetadataBackendOutputStorageStrategy(aws_cdk_lib_1.Stack.of(this))) { const stack = aws_cdk_lib_1.Stack.of(this); const output = { version: '1', payload: { awsAppsyncApiId: this.resources.cfnResources.cfnGraphqlApi.attrApiId, awsAppsyncApiEndpoint: this.resources.cfnResources.cfnGraphqlApi.attrGraphQlUrl, awsAppsyncAuthenticationType: this.resources.cfnResources.cfnGraphqlApi.authenticationType, awsAppsyncRegion: stack.region, amplifyApiModelSchemaS3Uri: this.codegenAssets.modelSchemaS3Uri, }, }; if (this.resources.cfnResources.cfnApiKey) { output.payload.awsAppsyncApiKey = this.resources.cfnResources.cfnApiKey.attrApiKey; } const additionalAuthTypes = (0, internal_1.getAdditionalAuthenticationTypes)(this.resources.cfnResources.cfnGraphqlApi); if (additionalAuthTypes) { output.payload.awsAppsyncAdditionalAuthenticationTypes = additionalAuthTypes; } if (this.dataStoreConfiguration?.project?.handlerType) { output.payload.awsAppsyncConflictResolutionMode = this.dataStoreConfiguration?.project?.handlerType; } outputStorageStrategy.addBackendOutputEntry(backend_output_schemas_1.graphqlOutputKey, output); } /** * The following are proxy methods to the L2 IGraphqlApi interface, to facilitate easier use of the L3 without needing * to access the underlying resources. */ /** * Add a new DynamoDB data source to this API. This is a proxy method to the L2 GraphqlApi Construct. * @param id The data source's id. * @param table The DynamoDB table backing this data source. * @param options The optional configuration for this data source. * @returns the generated data source. */ addDynamoDbDataSource(id, table, options) { return this.resources.graphqlApi.addDynamoDbDataSource(id, table, options); } /** * Add a new elasticsearch data source to this API. This is a proxy method to the L2 GraphqlApi Construct. * @deprecated use `addOpenSearchDataSource` * @param id The data source's id. * @param domain The elasticsearch domain for this data source. * @param options The optional configuration for this data source. * @returns the generated data source. */ addElasticsearchDataSource(id, domain, options) { return this.resources.graphqlApi.addElasticsearchDataSource(id, domain, options); } /** * Add an EventBridge data source to this api. This is a proxy method to the L2 GraphqlApi Construct. * @param id The data source's id. * @param eventBus The EventBridge EventBus on which to put events. * @param options The optional configuration for this data source. */ addEventBridgeDataSource(id, eventBus, options) { return this.resources.graphqlApi.addEventBridgeDataSource(id, eventBus, options); } /** * Add a new http data source to this API. This is a proxy method to the L2 GraphqlApi Construct. * @param id The data source's id. * @param endpoint The http endpoint. * @param options The optional configuration for this data source. * @returns the generated data source. */ addHttpDataSource(id, endpoint, options) { return this.resources.graphqlApi.addHttpDataSource(id, endpoint, options); } /** * Add a new Lambda data source to this API. This is a proxy method to the L2 GraphqlApi Construct. * @param id The data source's id. * @param lambdaFunction The Lambda function to call to interact with this data source. * @param options The optional configuration for this data source. * @returns the generated data source. */ addLambdaDataSource(id, lambdaFunction, options) { return this.resources.graphqlApi.addLambdaDataSource(id, lambdaFunction, options); } /** * Add a new dummy data source to this API. This is a proxy method to the L2 GraphqlApi Construct. * Useful for pipeline resolvers and for backend changes that don't require a data source. * @param id The data source's id. * @param options The optional configuration for this data source. * @returns the generated data source. */ addNoneDataSource(id, options) { return this.resources.graphqlApi.addNoneDataSource(id, options); } /** * dd a new OpenSearch data source to this API. This is a proxy method to the L2 GraphqlApi Construct. * @param id The data source's id. * @param domain The OpenSearch domain for this data source. * @param options The optional configuration for this data source. * @returns the generated data source. */ addOpenSearchDataSource(id, domain, options) { return this.resources.graphqlApi.addOpenSearchDataSource(id, domain, options); } /** * Add a new Rds data source to this API. This is a proxy method to the L2 GraphqlApi Construct. * @param id The data source's id. * @param serverlessCluster The serverless cluster to interact with this data source. * @param secretStore The secret store that contains the username and password for the serverless cluster. * @param databaseName The optional name of the database to use within the cluster. * @param options The optional configuration for this data source. * @returns the generated data source. */ addRdsDataSource(id, serverlessCluster, secretStore, databaseName, options) { return this.resources.graphqlApi.addRdsDataSource(id, serverlessCluster, secretStore, databaseName, options); } /** * Add a resolver to the api. This is a proxy method to the L2 GraphqlApi Construct. * @param id The resolver's id. * @param props the resolver properties. * @returns the generated resolver. */ addResolver(id, props) { return this.resources.graphqlApi.createResolver(id, props); } /** * Add an appsync function to the api. * @param id the function's id. * @returns the generated appsync function. */ addFunction(id, props) { return new aws_appsync_1.AppsyncFunction(this, id, { api: this.resources.graphqlApi, ...props, }); } } exports.AmplifyGraphqlApi = AmplifyGraphqlApi; _a = JSII_RTTI_SYMBOL_1; AmplifyGraphqlApi[_a] = { fqn: "@aws-amplify/graphql-api-construct.AmplifyGraphqlApi", version: "1.20.3" }; /** * Given the provided scope, walk the node tree, and throw an exception if any other AmplifyGraphqlApi constructs * are found in the stack. * @param scope the scope this construct is created in. */ const validateNoOtherAmplifyGraphqlApiInStack = (scope) => { const rootStack = (0, construct_tree_1.getStackForScope)(scope, false); let wasOtherAmplifyGraphlApiFound = false; (0, construct_tree_1.walkAndProcessNodes)(rootStack, (node) => { if (node instanceof AmplifyGraphqlApi && scope !== node) { wasOtherAmplifyGraphlApiFound = true; } }); if (wasOtherAmplifyGraphlApiFound) { throw new Error('Only one AmplifyGraphqlApi is expected in a stack. Place the AmplifyGraphqlApis in separate nested stacks.'); } }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYW1wbGlmeS1ncmFwaHFsLWFwaS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9hbXBsaWZ5LWdyYXBocWwtYXBpLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsNkJBQTZCO0FBQzdCLDJDQUF1QztBQUN2QywwRUFBNEY7QUFDNUYsNkNBQStEO0FBQy9ELGdGQUE0SDtBQUM1SCxnRkFBdUU7QUFFdkUseURBY2lDO0FBUWpDLHNFQUE0RztBQVM1Ryx5Q0FVb0I7QUFDcEIsOERBQWtGO0FBQ2xGLHNFQUFnRjtBQUNoRixrREFBeUg7QUFHekg7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBNkJHO0FBQ0gsTUFBYSxpQkFBa0IsU0FBUSxzQkFBUztJQW9EOUM7Ozs7OztPQU1HO0lBQ0gsWUFBWSxLQUFnQixFQUFFLEVBQVUsRUFBRSxLQUE2QjtRQUNyRSxLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBYm5COztXQUVHO1FBQ2MsY0FBUyxHQUFHLGFBQWEsQ0FBQztRQVd6QyxJQUFJLENBQUMsS0FBSyxHQUFHLG1CQUFLLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBRTdCLDRHQUE0RztRQUM1RyxJQUFJLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FDbEIsb0RBQW9ELEVBQ3BELDBCQUFZLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLFNBQVMsQ0FBQyxvREFBb0QsQ0FBQyxJQUFJLElBQUksQ0FDOUYsQ0FBQztRQUVGLHVDQUF1QyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBRTlDLE1BQU0sRUFDSixVQUFVLEVBQ1Ysa0JBQWtCLEVBQ2xCLGtCQUFrQixFQUNsQixhQUFhLEVBQ2Isa0JBQWtCLEVBQ2xCLGlCQUFpQixFQUNqQixhQUFhLEVBQ2IsbUJBQW1CLEVBQ25CLGVBQWUsRUFDZixxQkFBcUIsRUFDckIsc0JBQXNCLEVBQ3RCLE9BQU8sR0FDUixHQUFHLEtBQUssQ0FBQztRQUVW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QUFFRDs7OztHQUlHO0FBQ0gsTUFBTSx1Q0FBdUMsR0FBRyxDQUFDLEtBQWdCLEVBQVEsRUFBRTtJQUN6RSxNQUFNLFNBQVMsR0FBRyxJQUFBLGlDQUFnQixFQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsQ0FBQztJQUVqRCxJQUFJLDZCQUE2QixHQUFHLEtBQUssQ0FBQztJQUMxQyxJQUFBLG9DQUFtQixFQUFDLFNBQVMsRUFBRSxDQUFDLElBQWUsRUFBRSxFQUFFO1FBQ2pELElBQUksSUFBSSxZQUFZLGlCQUFpQixJQUFJLEtBQUssS0FBSyxJQUFJLEVBQUUsQ0FBQztZQUN4RCw2QkFBNkIsR0FBRyxJQUFJLENBQUM7UUFDdkMsQ0FBQztJQUNILENBQUMsQ0FBQyxDQUFDO0lBRUgsSUFBSSw2QkFBNkIsRUFBRSxDQUFDO1FBQ2xDLE1BQU0sSUFBSSxLQUFLLENBQUMsNEdBQTRHLENBQUMsQ0FBQztJQUNoSSxDQUFDO0FBQ0gsQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgcGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCB7IENvbnN0cnVjdCB9IGZyb20gJ2NvbnN0cnVjdHMnO1xuaW1wb3J0IHsgRXhlY3V0ZVRyYW5zZm9ybUNvbmZpZywgZXhlY3V0ZVRyYW5zZm9ybSB9IGZyb20gJ0Bhd3MtYW1wbGlmeS9ncmFwaHFsLXRyYW5zZm9ybWVyJztcbmltcG9ydCB7IE5lc3RlZFN0YWNrLCBTdGFjaywgRmVhdHVyZUZsYWdzIH0gZnJvbSAnYXdzLWNkay1saWInO1xuaW1wb3J0IHsgQXR0cmlidXRpb25NZXRhZGF0YVN0b3JhZ2UsIFN0YWNrTWV0YWRhdGFCYWNrZW5kT3V0cHV0U3RvcmFnZVN0cmF0ZWd5IH0gZnJvbSAnQGF3cy1hbXBsaWZ5L2JhY2tlbmQtb3V0cHV0LXN0b3JhZ2UnO1xuaW1wb3J0IHsgZ3JhcGhxbE91dHB1dEtleSB9IGZyb20gJ0Bhd3MtYW1wbGlmeS9iYWNrZW5kLW91dHB1dC1zY2hlbWFzJztcbmltcG9ydCB0eXBlIHsgR3JhcGhxbE91dHB1dCwgQXdzQXBwc3luY0F1dGhlbnRpY2F0aW9uVHlwZSB9IGZyb20gJ0Bhd3MtYW1wbGlmeS9iYWNrZW5kLW91dHB1dC1zY2hlbWFzJztcbmltcG9ydCB7XG4gIEFwcHN5bmNGdW5jdGlvbixcbiAgRGF0YVNvdXJjZU9wdGlvbnMsXG4gIER5bmFtb0RiRGF0YVNvdXJjZSxcbiAgRWxhc3RpY3NlYXJjaERhdGFTb3VyY2UsXG4gIEV2ZW50QnJpZGdlRGF0YVNvdXJjZSxcbiAgRXh0ZW5kZWRSZXNvbHZlclByb3BzLFxuICBIdHRwRGF0YVNvdXJjZSxcbiAgSHR0cERhdGFTb3VyY2VPcHRpb25zLFxuICBMYW1iZGFEYXRhU291cmNlLFxuICBOb25lRGF0YVNvdXJjZSxcbiAgT3BlblNlYXJjaERhdGFTb3VyY2UsXG4gIFJkc0RhdGFTb3VyY2UsXG4gIFJlc29sdmVyLFxufSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtYXBwc3luYyc7XG5pbXBvcnQgeyBJVGFibGUgfSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtZHluYW1vZGInO1xuaW1wb3J0IHsgSURvbWFpbiB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1lbGFzdGljc2VhcmNoJztcbmltcG9ydCB7IElEb21haW4gYXMgSU9wZW5TZWFyY2hEb21haW4gfSBmcm9tICdhd3MtY2RrLWxpYi9hd3Mtb3BlbnNlYXJjaHNlcnZpY2UnO1xuaW1wb3J0IHsgSUV2ZW50QnVzIH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLWV2ZW50cyc7XG5pbXBvcnQgeyBJRnVuY3Rpb24gfSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtbGFtYmRhJztcbmltcG9ydCB7IElTZXJ2ZXJsZXNzQ2x1c3RlciB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1yZHMnO1xuaW1wb3J0IHsgSVNlY3JldCB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1zZWNyZXRzbWFuYWdlcic7XG5pbXBvcnQgeyBwYXJzZVVzZXJEZWZpbmVkU2xvdHMsIHZhbGlkYXRlRnVuY3Rpb25TbG90cywgc2VwYXJhdGVTbG90cyB9IGZyb20gJy4vaW50ZXJuYWwvdXNlci1kZWZpbmVkLXNsb3RzJztcbmltcG9ydCB0eXBlIHtcbiAgQW1wbGlmeUdyYXBocWxBcGlSZXNvdXJjZXMsXG4gIEFtcGxpZnlHcmFwaHFsQXBpUHJvcHMsXG4gIEZ1bmN0aW9uU2xvdCxcbiAgSUJhY2tlbmRPdXRwdXRTdG9yYWdlU3RyYXRlZ3ksXG4gIEFkZEZ1bmN0aW9uUHJvcHMsXG4gIERhdGFTdG9yZUNvbmZpZ3VyYXRpb24sXG59IGZyb20gJy4vdHlwZXMnO1xuaW1wb3J0IHtcbiAgY29udmVydEF1dGhvcml6YXRpb25Nb2Rlc1RvVHJhbnNmb3JtZXJBdXRoQ29uZmlnLFxuICBjb252ZXJ0VG9SZXNvbHZlckNvbmZpZyxcbiAgZGVmYXVsdFRyYW5zbGF0aW9uQmVoYXZpb3IsXG4gIEFzc2V0UHJvdmlkZXIsXG4gIGdldEdlbmVyYXRlZFJlc291cmNlcyxcbiAgZ2V0R2VuZXJhdGVkRnVuY3Rpb25TbG90cyxcbiAgQ29kZWdlbkFzc2V0cyxcbiAgZ2V0QWRkaXRpb25hbEF1dGhlbnRpY2F0aW9uVHlwZXMsXG4gIHZhbGlkYXRlQXV0aG9yaXphdGlvbk1vZGVzLFxufSBmcm9tICcuL2ludGVybmFsJztcbmltcG9ydCB7IGdldFN0YWNrRm9yU2NvcGUsIHdhbGtBbmRQcm9jZXNzTm9kZXMgfSBmcm9tICcuL2ludGVybmFsL2NvbnN0cnVjdC10cmVlJztcbmltcG9ydCB7IGdldERhdGFTb3VyY2VTdHJhdGVnaWVzUHJvdmlkZXIgfSBmcm9tICcuL2ludGVybmFsL2RhdGEtc291cmNlLWNvbmZpZyc7XG5pbXBvcnQgeyBnZXRNZXRhZGF0YURhdGFTb3VyY2VzLCBnZXRNZXRhZGF0YUF1dGhvcml6YXRpb25Nb2RlcywgZ2V0TWV0YWRhdGFDdXN0b21PcGVyYXRpb25zIH0gZnJvbSAnLi9pbnRlcm5hbC9tZXRhZGF0YSc7XG5pbXBvcnQgeyBCYWNrZW5kT3V0cHV0U3RvcmFnZVN0cmF0ZWd5LCBCYWNrZW5kT3V0cHV0RW50cnkgfSBmcm9tICdAYXdzLWFtcGxpZnkvcGx1Z2luLXR5cGVzJztcblxuLyoqXG4gKiBMMyBDb25zdHJ1Y3Qgd2hpY2ggaW52b2tlcyB0aGUgQW1wbGlmeSBUcmFuc2Zvcm1lciBQYXR0ZXJuIG92ZXIgYW4gaW5wdXQgR3JhcGhxbCBTY2hlbWEuXG4gKlxuICogVGhpcyBjYW4gYmUgdXNlZCB0byBxdWlja2x5IGRlZmluZSBhcHBzeW5jIGFwaXMgd2hpY2ggc3VwcG9ydCBmdWxsIENSVUQrTGlzdCBhbmQgU3Vic2NyaXB0aW9ucywgcmVsYXRpb25zaGlwcyxcbiAqIGF1dGgsIHNlYXJjaCBvdmVyIGRhdGEsIHRoZSBhYmlsaXR5IHRvIGluamVjdCBjdXN0b20gYnVzaW5lc3MgbG9naWMgYW5kIHF1ZXJ5L211dGF0aW9uIG9wZXJhdGlvbnMsIGFuZCBjb25uZWN0IHRvIE1MIHNlcnZpY2VzLlxuICpcbiAqIEZvciBtb3JlIGluZm9ybWF0aW9uLCByZWZlciB0byB0aGUgZG9jcyBsaW5rcyBiZWxvdzpcbiAqIERhdGEgTW9kZWxpbmcgLSBodHRwczovL2RvY3MuYW1wbGlmeS5hd3MvY2xpL2dyYXBocWwvZGF0YS1tb2RlbGluZy9cbiAqIEF1dGhvcml6YXRpb24gLSBodHRwczovL2RvY3MuYW1wbGlmeS5hd3MvY2xpL2dyYXBocWwvYXV0aG9yaXphdGlvbi1ydWxlcy9cbiAqIEN1c3RvbSBCdXNpbmVzcyBMb2dpYyAtIGh0dHBzOi8vZG9jcy5hbXBsaWZ5LmF3cy9jbGkvZ3JhcGhxbC9jdXN0b20tYnVzaW5lc3MtbG9naWMvXG4gKiBTZWFyY2ggLSBodHRwczovL2RvY3MuYW1wbGlmeS5hd3MvY2xpL2dyYXBocWwvc2VhcmNoLWFuZC1yZXN1bHQtYWdncmVnYXRpb25zL1xuICogTUwgU2VydmljZXMgLSBodHRwczovL2RvY3MuYW1wbGlmeS5hd3MvY2xpL2dyYXBocWwvY29ubmVjdC10by1tYWNoaW5lLWxlYXJuaW5nLXNlcnZpY2VzL1xuICpcbiAqIEZvciBhIGZ1bGwgcmVmZXJlbmNlIG9mIHRoZSBzdXBwb3J0ZWQgY3VzdG9tIGdyYXBocWwgZGlyZWN0aXZlcyAtIGh0dHBzOi8vZG9jcy5hbXBsaWZ5LmF3cy9jbGkvZ3JhcGhxbC9kaXJlY3RpdmVzLXJlZmVyZW5jZS9cbiAqXG4gKiBUaGUgb3V0cHV0IG9mIHRoaXMgY29uc3RydWN0IGlzIGEgbWFwcGluZyBvZiBMMiBvciBMMSByZXNvdXJjZXMgZ2VuZXJhdGVkIGJ5IHRoZSB0cmFuc2Zvcm1lciwgd2hpY2ggZ2VuZXJhbGx5IGZvbGxvdyB0aGUgYWNjZXNzIHBhdHRlcm5cbiAqXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiAgIGNvbnN0IGFwaSA9IG5ldyBBbXBsaWZ5R3JhcGhRbEFwaSh0aGlzLCAnYXBpJywgeyA8cGFyYW1zPiB9KTtcbiAqICAgLy8gQWNjZXNzIEwyIHJlc291cmNlcyB1bmRlciBgLnJlc291cmNlc2BcbiAqICAgYXBpLnJlc291cmNlcy50YWJsZXNbXCJUb2RvXCJdLnRhYmxlQXJuO1xuICpcbiAqICAgLy8gQWNjZXNzIEwxIHJlc291cmNlcyB1bmRlciBgLnJlc291cmNlcy5jZm5SZXNvdXJjZXNgXG4gKiAgIGFwaS5yZXNvdXJjZXMuY2ZuUmVzb3VyY2VzLmNmbkdyYXBocWxBcGkueHJheUVuYWJsZWQgPSB0cnVlO1xuICogICBPYmplY3QudmFsdWVzKGFwaS5yZXNvdXJjZXMuY2ZuUmVzb3VyY2VzLmNmblRhYmxlcykuZm9yRWFjaCh0YWJsZSA9PiB7XG4gKiAgICAgdGFibGUucG9pbnRJblRpbWVSZWNvdmVyeVNwZWNpZmljYXRpb24gPSB7IHBvaW50SW5UaW1lUmVjb3ZlcnlFbmFibGVkOiBmYWxzZSB9O1xuICogICB9KTtcbiAqIGBgYFxuICogYHJlc291cmNlcy48UmVzb3VyY2VUeXBlPi48UmVzb3VyY2VOYW1lPmAgLSB5b3UgY2FuIHRoZW4gcGVyZm9ybSBhbnkgQ0RLIGFjdGlvbiBvbiB0aGVzZSByZXN1bHRpbmcgcmVzb3VyZWNlcy5cbiAqL1xuZXhwb3J0IGNsYXNzIEFtcGxpZnlHcmFwaHFsQXBpIGV4dGVuZHMgQ29uc3RydWN0IHtcbiAgLyoqXG4gICAqIEdlbmVyYXRlZCBMMSBhbmQgTDIgQ0RLIHJlc291cmNlcy5cbiAgICovXG4gIHB1YmxpYyByZWFkb25seSByZXNvdXJjZXM6IEFtcGxpZnlHcmFwaHFsQXBpUmVzb3VyY2VzO1xuXG4gIC8qKlxuICAgKiBSZWZlcmVuY2UgdG8gcGFyZW50IHN0YWNrIG9mIGRhdGEgY29uc3RydWN0XG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgc3RhY2s6IFN0YWNrO1xuXG4gIC8qKlxuICAgKiBHZW5lcmF0ZWQgYXNzZXRzIHJlcXVpcmVkIGZvciBjb2RlZ2VuIHN0ZXBzLiBQZXJzaXN0ZWQgaW4gb3JkZXIgdG8gcmVuZGVyIGFzIHBhcnQgb2YgdGhlIG91dHB1dCBzdHJhdGVneS5cbiAgICovXG4gIHByaXZhdGUgcmVhZG9ubHkgY29kZWdlbkFzc2V0czogQ29kZWdlbkFzc2V0cztcblxuICAvKipcbiAgICogUmVzb2x2ZXJzIGdlbmVyYXRlZCBieSB0aGUgdHJhbnNmb3JtIHByb2Nlc3MsIHBlcnNpc3RlZCBvbiB0aGUgc2lkZSBpbiBvcmRlciB0byBmYWNpbGl0YXRlIHB1bGxpbmcgYSBtYW5pZmVzdFxuICAgKiBmb3IgdGhlIHB1cnBvc2VzIG9mIGluc3BlY3RpbmcgYW5kIHByb2R1Y2luZyBvdmVycmlkZXMuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgZ2VuZXJhdGVkRnVuY3Rpb25TbG90czogRnVuY3Rpb25TbG90W107XG5cbiAgLyoqXG4gICAqIEdyYXBocWwgVVJMIEZvciB0aGUgZ2VuZXJhdGVkIEFQSS4gTWF5IGJlIGEgQ0RLIFRva2VuLlxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IGdyYXBocWxVcmw6IHN0cmluZztcblxuICAvKipcbiAgICogUmVhbHRpbWUgVVJMIEZvciB0aGUgZ2VuZXJhdGVkIEFQSS4gTWF5IGJlIGEgQ0RLIFRva2VuLlxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IHJlYWx0aW1lVXJsOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIEdlbmVyYXRlZCBBcGkgS2V5IGlmIGdlbmVyYXRlZC4gTWF5IGJlIGEgQ0RLIFRva2VuLlxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IGFwaUtleTogc3RyaW5nIHwgdW5kZWZpbmVkO1xuXG4gIC8qKlxuICAgKiBHZW5lcmF0ZWQgQXBpIElkLiBNYXkgYmUgYSBDREsgVG9rZW4uXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgYXBpSWQ6IHN0cmluZztcblxuICAvKipcbiAgICogRGF0YVN0b3JlIGNvbmZsaWN0IHJlc29sdXRpb24gc2V0dGluZ1xuICAgKi9cbiAgcHJpdmF0ZSByZWFkb25seSBkYXRhU3RvcmVDb25maWd1cmF0aW9uOiBEYXRhU3RvcmVDb25maWd1cmF0aW9uIHwgdW5kZWZpbmVkO1xuXG4gIC8qKlxuICAgKiBCZSB2ZXJ5IGNhcmVmdWwgZWRpdGluZyB0aGlzIHZhbHVlLiBUaGlzIGlzIHRoZSBzdHJpbmcgdGhhdCBpcyB1c2VkIHRvIGlkZW50aWZ5IGdyYXBocWwgc3RhY2tzIGluIEJJIG1ldHJpY3NcbiAgICovXG4gIHByaXZhdGUgcmVhZG9ubHkgc3RhY2tUeXBlID0gJ2FwaS1BcHBTeW5jJztcblxuICAvKipcbiAgICogTmV3IEFtcGxpZnlHcmFwaHFsQXBpIGNvbnN0cnVjdCwgdGhpcyB3aWxsIGNyZWF0ZSBhbiBhcHBzeW5jIGFwaSB3aXRoIGF1dGhvcml6YXRpb24sIGEgc2NoZW1hLCBhbmQgYWxsIG5lY2Vzc2FyeSByZXNvbHZlcnMsIGZ1bmN0aW9ucyxcbiAgICogYW5kIGRhdGFzb3VyY2VzLlxuICAgKiBAcGFyYW0gc2NvcGUgdGhlIHNjb3BlIHRvIGNyZWF0ZSB0aGlzIGNvbnN0cnVjdCB3aXRoaW4uXG4gICAqIEBwYXJhbSBpZCB0aGUgaWQgdG8gdXNlIGZvciB0aGlzIGFwaS5cbiAgICogQHBhcmFtIHByb3BzIHRoZSBwcm9wZXJ0aWVzIHVzZWQgdG8gY29uZmlndXJlIHRoZSBnZW5lcmF0ZWQgYXBpLlxuICAgKi9cbiAgY29uc3RydWN0b3Ioc2NvcGU6IENvbnN0cnVjdCwgaWQ6IHN0cmluZywgcHJvcHM6IEFtcGxpZnlHcmFwaHFsQXBpUHJvcHMpIHtcbiAgICBzdXBlcihzY29wZSwgaWQpO1xuICAgIHRoaXMuc3RhY2sgPSBTdGFjay5vZihzY29wZSk7XG5cbiAgICAvLyBGYWxsIGJhY2sgdG8gZGVmYXVsdCB0cnVlIGlmIG5vIGZlYXR1cmUgZmxhZyBpcyBwcm92aWRlZCwgb3RoZXJ3aXNlIGhvbm9yIHRoZSBmZWF0dXJlIGZsYWcgdmFsdWUgcHJvdmlkZWRcbiAgICB0aGlzLm5vZGUuc2V0Q29udGV4dChcbiAgICAgICdAYXdzLWNkay9hd3MtaWFtOm9pZGNSZWplY3RVbmF1dGhvcml6ZWRDb25uZWN0aW9ucycsXG4gICAgICBGZWF0dXJlRmxhZ3Mub2YodGhpcykuaXNFbmFibGVkKCdAYXdzLWNkay9hd3MtaWFtOm9pZGNSZWplY3RVbmF1dGhvcml6ZWRDb25uZWN0aW9ucycpID8/IHRydWUsXG4gICAgKTtcblxuICAgIHZhbGlkYXRlTm9PdGhlckFtcGxpZnlHcmFwaHFsQXBpSW5TdGFjayh0aGlzKTtcblxuICAgIGNvbnN0IHtcbiAgICAgIGRlZmluaXRpb24sXG4gICAgICBhdXRob3JpemF0aW9uTW9kZXMsXG4gICAgICBjb25mbGljdFJlc29sdXRpb24sXG4gICAgICBmdW5jdGlvblNsb3RzLFxuICAgICAgdHJhbnNmb3JtZXJQbHVnaW5zLFxuICAgICAgcHJlZGljdGlvbnNCdWNrZXQsXG4gICAgICBzdGFja01hcHBpbmdzLFxuICAgICAgdHJhbnNsYXRpb25CZWhhdmlvcixcbiAgICAgIGZ1bmN0aW9uTmFtZU1hcCxcbiAgICAgIG91dHB1dFN0b3JhZ2VTdHJhdGVneSxcbiAgICAgIGRhdGFTdG9yZUNvbmZpZ3VyYXRpb24sXG4gICAgICBsb2dnaW5nLFxuICAgIH0gPSBwcm9wcztcblxuICAgIGlmIChjb25mbGljdFJlc29sdXRpb24gJiYgZGF0YVN0b3JlQ29uZmlndXJhdGlvbikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAnY29uZmxpY3RSZXNvbHV0aW9uIGlzIGRlcHJlY2F0ZWQuIGNvbmZsaWN0UmVzb2x1dGlvbiBhbmQgZGF0YVN0b3JlQ29uZmlndXJhdGlvbiBjYW5ub3QgYmUgdXNlZCB0b2dldGhlci4gUGxlYXNlIHVzZSBkYXRhU3RvcmVDb25maWd1cmF0aW9uLicsXG4gICAgICApO1xuICAgIH1cblxuICAgIHRoaXMuZGF0YVN0b3JlQ29uZmlndXJhdGlvbiA9IGRhdGFTdG9yZUNvbmZpZ3VyYXRpb24gfHwgY29uZmxpY3RSZXNvbHV0aW9uO1xuXG4gICAgY29uc3QgYXR0cmlidXRpb25NZXRhZGF0YSA9IHtcbiAgICAgIGRhdGFTb3VyY2VzOiBnZXRNZXRhZGF0YURhdGFTb3VyY2VzKGRlZmluaXRpb24pLFxuICAgICAgYXV0aG9yaXphdGlvbk1vZGVzOiBnZXRNZXRhZGF0YUF1dGhvcml6YXRpb25Nb2RlcyhhdXRob3JpemF0aW9uTW9kZXMpLFxuICAgICAgY3VzdG9tT3BlcmF0aW9uczogZ2V0TWV0YWRhdGFDdXN0b21PcGVyYXRpb25zKGRlZmluaXRpb24pLFxuICAgIH07XG5cbiAgICBuZXcgQXR0cmlidXRpb25NZXRhZGF0YVN0b3JhZ2UoKS5zdG9yZUF0dHJpYnV0aW9uTWV0YWRhdGEoXG4gICAgICBTdGFjay5vZihzY29wZSksXG4gICAgICB0aGlzLnN0YWNrVHlwZSxcbiAgICAgIHBhdGguam9pbihfX2Rpcm5hbWUsICcuLicsICdwYWNrYWdlLmpzb24nKSxcbiAgICAgIGF0dHJpYnV0aW9uTWV0YWRhdGEsXG4gICAgKTtcblxuICAgIHZhbGlkYXRlQXV0aG9yaXphdGlvbk1vZGVzKGF1dGhvcml6YXRpb25Nb2Rlcyk7XG4gICAgY29uc3QgeyBhdXRoQ29uZmlnLCBhdXRoU3ludGhQYXJhbWV0ZXJzIH0gPSBjb252ZXJ0QXV0aG9yaXphdGlvbk1vZGVzVG9UcmFuc2Zvcm1lckF1dGhDb25maWcoYXV0aG9yaXphdGlvbk1vZGVzKTtcblxuICAgIHZhbGlkYXRlRnVuY3Rpb25TbG90cyhmdW5jdGlvblNsb3RzID8/IFtdKTtcbiAgICBjb25zdCBzZXBhcmF0ZWRGdW5jdGlvblNsb3RzID0gc2VwYXJhdGVTbG90cyhbLi4uKGZ1bmN0aW9uU2xvdHMgPz8gW10pLCAuLi5kZWZpbml0aW9uLmZ1bmN0aW9uU2xvdHNdKTtcblxuICAgIC8vIEFsbG93IGFtcGxpZnlFbnZpcm9ubWVudE5hbWUgdG8gYmUgcmV0cmlldmUgZnJvbSBjb250ZXh0LCBhbmQgdXNlIHZhbHVlICdOT05FJyBpZiBubyB2YWx1ZSBjYW4gYmUgZm91bmQuXG4gICAgLy8gYW1wbGlmeUVudmlyb25tZW50TmFtZSBpcyByZXF1aXJlZCBmb3IgbG9naWNhbCBpZCBzdWZmaXhpbmcsIGFzIHdlbGwgYXMgRXhwb3J0cyBmcm9tIHRoZSBuZXN0ZWQgc3RhY2tzLlxuICAgIC8vIEFsbG93IGV4cG9ydCBzbyBjdXN0b21lcnMgY2FuIHJldXNlIHRoZSBlbnYgaW4gdGhlaXIgb3duIHJlZmVyZW5jZXMgZG93bnN0cmVhbS5cbiAgICBjb25zdCBhbXBsaWZ5RW52aXJvbm1lbnROYW1lID0gdGhpcy5ub2RlLnRyeUdldENvbnRleHQoJ2FtcGxpZnlFbnZpcm9ubWVudE5hbWUnKSA/PyAnTk9ORSc7XG4gICAgaWYgKGFtcGxpZnlFbnZpcm9ubWVudE5hbWUubGVuZ3RoID4gOCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBvciBjZGsgLS1jb250ZXh0IGVudiBtdXN0IGhhdmUgYSBsZW5ndGggPD0gOCwgZm91bmQgJHthbXBsaWZ5RW52aXJvbm1lbnROYW1lfWApO1xuICAgIH1cblxuICAgIGNvbnN0IGFzc2V0UHJvdmlkZXIgPSBuZXcgQXNzZXRQcm92aWRlcih0aGlzKTtcblxuICAgIGNvbnN0IHRyYW5zZm9ybVBhcmFtZXRlcnMgPSB7XG4gICAgICAuLi5kZWZhdWx0VHJhbnNsYXRpb25CZWhhdmlvcixcbiAgICAgIC4uLih0cmFuc2xhdGlvbkJlaGF2aW9yID8/IHt9KSxcbiAgICAgIGFsbG93R2VuMVBhdHRlcm5zOiBmYWxzZSxcbiAgICB9O1xuICAgIGNvbnN0IGV4ZWN1dGVUcmFuc2Zvcm1Db25maWc6IEV4ZWN1dGVUcmFuc2Zvcm1Db25maWcgPSB7XG4gICAgICBzY29wZTogdGhpcyxcbiAgICAgIG5lc3RlZFN0YWNrUHJvdmlkZXI6IHtcbiAgICAgICAgcHJvdmlkZTogKG5lc3RlZFN0YWNrU2NvcGU6IENvbnN0cnVjdCwgbmFtZTogc3RyaW5nKSA9PiBuZXcgTmVzdGVkU3RhY2sobmVzdGVkU3RhY2tTY29wZSwgbmFtZSksXG4gICAgICB9LFxuICAgICAgYXNzZXRQcm92aWRlcixcbiAgICAgIHN5bnRoUGFyYW1ldGVyczoge1xuICAgICAgICBhbXBsaWZ5RW52aXJvbm1lbnROYW1lOiBhbXBsaWZ5RW52aXJvbm1lbnROYW1lLFxuICAgICAgICBhcGlOYW1lOiBwcm9wcy5hcGlOYW1lID8/IGlkLFxuICAgICAgICAuLi5hdXRoU3ludGhQYXJhbWV0ZXJzLFxuICAgICAgICBwcm92aXNpb25Ib3Rzd2FwRnJpZW5kbHlSZXNvdXJjZXM6IHRyYW5zbGF0aW9uQmVoYXZpb3I/Ll9wcm92aXNpb25Ib3Rzd2FwRnJpZW5kbHlSZXNvdXJjZXMsXG4gICAgICB9LFxuICAgICAgc2NoZW1hOiBkZWZpbml0aW9uLnNjaGVtYSxcbiAgICAgIHVzZXJEZWZpbmVkU2xvdHM6IHBhcnNlVXNlckRlZmluZWRTbG90cyhzZXBhcmF0ZWRGdW5jdGlvblNsb3RzKSxcbiAgICAgIHRyYW5zZm9ybWVyc0ZhY3RvcnlBcmdzOiB7XG4gICAgICAgIGN1c3RvbVRyYW5zZm9ybWVyczogdHJhbnNmb3JtZXJQbHVnaW5zID8/IFtdLFxuICAgICAgICAuLi4ocHJlZGljdGlvbnNCdWNrZXQgPyB7IHN0b3JhZ2VDb25maWc6IHsgYnVja2V0TmFtZTogcHJlZGljdGlvbnNCdWNrZXQuYnVja2V0TmFtZSB9IH0gOiB7fSksXG4gICAgICAgIGZ1bmN0aW9uTmFtZU1hcDoge1xuICAgICAgICAgIC4uLmRlZmluaXRpb24ucmVmZXJlbmNlZExhbWJkYUZ1bmN0aW9ucyxcbiAgICAgICAgICAuLi5mdW5jdGlvbk5hbWVNYXAsXG4gICAgICAgIH0sXG4gICAgICAgIG91dHB1dFN0b3JhZ2VTdHJhdGVneTogb3V0cHV0U3RvcmFnZVN0cmF0ZWd5IGFzIEJhY2tlbmRPdXRwdXRTdG9yYWdlU3RyYXRlZ3k8QmFja2VuZE91dHB1dEVudHJ5PixcbiAgICAgIH0sXG4gICAgICBhdXRoQ29uZmlnLFxuICAgICAgc3RhY2tNYXBwaW5nOiBzdGFja01hcHBpbmdzID8/IHt9LFxuICAgICAgcmVzb2x2ZXJDb25maWc6IHRoaXMuZGF0YVN0b3JlQ29uZmlndXJhdGlvbiA/IGNvbnZlcnRUb1Jlc29sdmVyQ29uZmlnKHRoaXMuZGF0YVN0b3JlQ29uZmlndXJhdGlvbikgOiB1bmRlZmluZWQsXG4gICAgICB0cmFuc2Zvcm1QYXJhbWV0ZXJzLFxuICAgICAgLy8gQ0RLIGNvbnN0cnVjdCB1c2VzIGEgY3VzdG9tIHJlc291cmNlLiBXZSdsbCBkZWZpbmUgdGhpcyBleHBsaWNpdGx5IGhlcmUgdG8gcmVtaW5kIG91cnNlbHZlcyB0aGF0IHRoaXMgdmFsdWUgaXMgdW51c2VkIGluIHRoZSBDREtcbiAgICAgIC8vIGNvbnN0cnVjdCBmbG93XG4gICAgICByZHNMYXllck1hcHBpbmc6IHVuZGVmaW5lZCxcbiAgICAgIHJkc1Nuc1RvcGljTWFwcGluZzogdW5kZWZpbmVkLFxuICAgICAgLi4uZ2V0RGF0YVNvdXJjZVN0cmF0ZWdpZXNQcm92aWRlcihkZWZpbml0aW9uKSxcbiAgICAgIGxvZ2dpbmcsXG4gICAgfTtcblxuICAgIGV4ZWN1dGVUcmFuc2Zvcm0oZXhlY3V0ZVRyYW5zZm9ybUNvbmZpZyk7XG5cbiAgICB0aGlzLmNvZGVnZW5Bc3NldHMgPSBuZXcgQ29kZWdlbkFzc2V0cyh0aGlzLCAnQW1wbGlmeUNvZGVnZW5Bc3NldHMnLCB7IG1vZGVsU2NoZW1hOiBkZWZpbml0aW9uLnNjaGVtYSB9KTtcblxuICAgIHRoaXMucmVzb3VyY2VzID0gZ2V0R2VuZXJhdGVkUmVzb3VyY2VzKHRoaXMpO1xuICAgIHRoaXMuZ2VuZXJhdGVkRnVuY3Rpb25TbG90cyA9IGdldEdlbmVyYXRlZEZ1bmN0aW9uU2xvdHMoYXNzZXRQcm92aWRlci5yZXNvbHZlckFzc2V0cyk7XG4gICAgdGhpcy5zdG9yZU91dHB1dChvdXRwdXRTdG9yYWdlU3RyYXRlZ3kpO1xuXG4gICAgdGhpcy5hcGlJZCA9IHRoaXMucmVzb3VyY2VzLmNmblJlc291cmNlcy5jZm5HcmFwaHFsQXBpLmF0dHJBcGlJZDtcbiAgICB0aGlzLmdyYXBocWxVcmwgPSB0aGlzLnJlc291cmNlcy5jZm5SZXNvdXJjZXMuY2ZuR3JhcGhxbEFwaS5hdHRyR3JhcGhRbFVybDtcbiAgICB0aGlzLnJlYWx0aW1lVXJsID0gdGhpcy5yZXNvdXJjZXMuY2ZuUmVzb3VyY2VzLmNmbkdyYXBocWxBcGkuYXR0clJlYWx0aW1lVXJsO1xuICAgIHRoaXMuYXBpS2V5ID0gdGhpcy5yZXNvdXJjZXMuY2ZuUmVzb3VyY2VzLmNmbkFwaUtleT8uYXR0ckFwaUtleTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTdG9yZXMgZ3JhcGhxbCBhcGkgb3V0cHV0IHRvIGJlIHVzZWQgZm9yIGNsaWVudCBjb25maWcgZ2VuZXJhdGlvblxuICAgKiBAcGFyYW0gb3V0cHV0U3RvcmFnZVN0cmF0ZWd5IFN0cmF0ZWd5IHRvIHN0b3JlIGNvbnN0cnVjdCBvdXRwdXRzLiBJZiBubyBzdHJhdGVneSBpcyBwcm92aWRlZCBhIGRlZmF1bHQgc3RyYXRlZ3kgd2lsbCBiZSB1c2VkLlxuICAgKi9cbiAgcHJpdmF0ZSBzdG9yZU91dHB1dChcbiAgICBvdXRwdXRTdG9yYWdlU3RyYXRlZ3k6IElCYWNrZW5kT3V0cHV0U3RvcmFnZVN0cmF0ZWd5ID0gbmV3IFN0YWNrTWV0YWRhdGFCYWNrZW5kT3V0cHV0U3RvcmFnZVN0cmF0ZWd5KFN0YWNrLm9mKHRoaXMpKSxcbiAgKTogdm9pZCB7XG4gICAgY29uc3Qgc3RhY2sgPSBTdGFjay5vZih0aGlzKTtcbiAgICBjb25zdCBvdXRwdXQ6IEdyYXBocWxPdXRwdXQgPSB7XG4gICAgICB2ZXJzaW9uOiAnMScsXG4gICAgICBwYXlsb2FkOiB7XG4gICAgICAgIGF3c0FwcHN5bmNBcGlJZDogdGhpcy5yZXNvdXJjZXMuY2ZuUmVzb3VyY2VzLmNmbkdyYXBocWxBcGkuYXR0ckFwaUlkLFxuICAgICAgICBhd3NBcHBzeW5jQXBpRW5kcG9pbnQ6IHRoaXMucmVzb3VyY2VzLmNmblJlc291cmNlcy5jZm5HcmFwaHFsQXBpLmF0dHJHcmFwaFFsVXJsLFxuICAgICAgICBhd3NBcHBzeW5jQXV0aGVudGljYXRpb25UeXBlOiB0aGlzLnJlc291cmNlcy5jZm5SZXNvdXJjZXMuY2ZuR3JhcGhxbEFwaS5hdXRoZW50aWNhdGlvblR5cGUgYXMgQXdzQXBwc3luY0F1dGhlbnRpY2F0aW9uVHlwZSxcbiAgICAgICAgYXdzQXBwc3luY1JlZ2lvbjogc3RhY2sucmVnaW9uLFxuICAgICAgICBhbXBsaWZ5QXBpTW9kZWxTY2hlbWFTM1VyaTogdGhpcy5jb2RlZ2VuQXNzZXRzLm1vZGVsU2NoZW1hUzNVcmksXG4gICAgICB9LFxuICAgIH07XG5cbiAgICBpZiAodGhpcy5yZXNvdXJjZXMuY2ZuUmVzb3VyY2VzLmNmbkFwaUtleSkge1xuICAgICAgb3V0cHV0LnBheWxvYWQuYXdzQXBwc3luY0FwaUtleSA9IHRoaXMucmVzb3VyY2VzLmNmblJlc291cmNlcy5jZm5BcGlLZXkuYXR0ckFwaUtleTtcbiAgICB9XG5cbiAgICBjb25zdCBhZGRpdGlvbmFsQXV0aFR5cGVzID0gZ2V0QWRkaXRpb25hbEF1dGhlbnRpY2F0aW9uVHlwZXModGhpcy5yZXNvdXJjZXMuY2ZuUmVzb3VyY2VzLmNmbkdyYXBocWxBcGkpO1xuICAgIGlmIChhZGRpdGlvbmFsQXV0aFR5cGVzKSB7XG4gICAgICBvdXRwdXQucGF5bG9hZC5hd3NBcHBzeW5jQWRkaXRpb25hbEF1dGhlbnRpY2F0aW9uVHlwZXMgPSBhZGRpdGlvbmFsQXV0aFR5cGVzO1xuICAgIH1cblxuICAgIGlmICh0aGlzLmRhdGFTdG9yZUNvbmZpZ3VyYXRpb24/LnByb2plY3Q/LmhhbmRsZXJUeXBlKSB7XG4gICAgICBvdXRwdXQucGF5bG9hZC5hd3NBcHBzeW5jQ29uZmxpY3RSZXNvbHV0aW9uTW9kZSA9IHRoaXMuZGF0YVN0b3JlQ29uZmlndXJhdGlvbj8ucHJvamVjdD8uaGFuZGxlclR5cGU7XG4gICAgfVxuXG4gICAgb3V0cHV0U3RvcmFnZVN0cmF0ZWd5LmFkZEJhY2tlbmRPdXRwdXRFbnRyeShncmFwaHFsT3V0cHV0S2V5LCBvdXRwdXQpO1xuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBmb2xsb3dpbmcgYXJlIHByb3h5IG1ldGhvZHMgdG8gdGhlIEwyIElHcmFwaHFsQXBpIGludGVyZmFjZSwgdG8gZmFjaWxpdGF0ZSBlYXNpZXIgdXNlIG9mIHRoZSBMMyB3aXRob3V0IG5lZWRpbmdcbiAgICogdG8gYWNjZXNzIHRoZSB1bmRlcmx5aW5nIHJlc291cmNlcy5cbiAgICovXG5cbiAgLyoqXG4gICAqIEFkZCBhIG5ldyBEeW5hbW9EQiBkYXRhIHNvdXJjZSB0byB0aGlzIEFQSS4gVGhpcyBpcyBhIHByb3h5IG1ldGhvZCB0byB0aGUgTDIgR3JhcGhxbEFwaSBDb25zdHJ1Y3QuXG4gICAqIEBwYXJhbSBpZCBUaGUgZGF0YSBzb3VyY2UncyBpZC5cbiAgICogQHBhcmFtIHRhYmxlIFRoZSBEeW5hbW9EQiB0YWJsZSBiYWNraW5nIHRoaXMgZGF0YSBzb3VyY2UuXG4gICAqIEBwYXJhbSBvcHRpb25zIFRoZSBvcHRpb25hbCBjb25maWd1cmF0aW9uIGZvciB0aGlzIGRhdGEgc291cmNlLlxuICAgKiBAcmV0dXJucyB0aGUgZ2VuZXJhdGVkIGRhdGEgc291cmNlLlxuICAgKi9cbiAgcHVibGljIGFkZER5bmFtb0RiRGF0YVNvdXJjZShpZDogc3RyaW5nLCB0YWJsZTogSVRhYmxlLCBvcHRpb25zPzogRGF0YVNvdXJjZU9wdGlvbnMpOiBEeW5hbW9EYkRhdGFTb3VyY2Uge1xuICAgIHJldHVybiB0aGlzLnJlc291cmNlcy5ncmFwaHFsQXBpLmFkZER5bmFtb0RiRGF0YVNvdXJjZShpZCwgdGFibGUsIG9wdGlvbnMpO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZCBhIG5ldyBlbGFzdGljc2VhcmNoIGRhdGEgc291cmNlIHRvIHRoaXMgQVBJLiBUaGlzIGlzIGEgcHJveHkgbWV0aG9kIHRvIHRoZSBMMiBHcmFwaHFsQXBpIENvbnN0cnVjdC5cbiAgICogQGRlcHJlY2F0ZWQgdXNlIGBhZGRPcGVuU2VhcmNoRGF0YVNvdXJjZWBcbiAgICogQHBhcmFtIGlkIFRoZSBkYXRhIHNvdXJjZSdzIGlkLlxuICAgKiBAcGFyYW0gZG9tYWluIFRoZSBlbGFzdGljc2VhcmNoIGRvbWFpbiBmb3IgdGhpcyBkYXRhIHNvdXJjZS5cbiAgICogQHBhcmFtIG9wdGlvbnMgVGhlIG9wdGlvbmFsIGNvbmZpZ3VyYXRpb24gZm9yIHRoaXMgZGF0YSBzb3VyY2UuXG4gICAqIEByZXR1cm5zIHRoZSBnZW5lcmF0ZWQgZGF0YSBzb3VyY2UuXG4gICAqL1xuICBwdWJsaWMgYWRkRWxhc3RpY3NlYXJjaERhdGFTb3VyY2UoaWQ6IHN0cmluZywgZG9tYWluOiBJRG9tYWluLCBvcHRpb25zPzogRGF0YVNvdXJjZU9wdGlvbnMpOiBFbGFzdGljc2VhcmNoRGF0YVNvdXJjZSB7XG4gICAgcmV0dXJuIHRoaXMucmVzb3VyY2VzLmdyYXBocWxBcGkuYWRkRWxhc3RpY3NlYXJjaERhdGFTb3VyY2UoaWQsIGRvbWFpbiwgb3B0aW9ucyk7XG4gIH1cblxuICAvKipcbiAgICogQWRkIGFuIEV2ZW50QnJpZGdlIGRhdGEgc291cmNlIHRvIHRoaXMgYXBpLiBUaGlzIGlzIGEgcHJveHkgbWV0aG9kIHRvIHRoZSBMMiBHcmFwaHFsQXBpIENvbnN0cnVjdC5cbiAgICogQHBhcmFtIGlkIFRoZSBkYXRhIHNvdXJjZSdzIGlkLlxuICAgKiBAcGFyYW0gZXZlbnRCdXMgVGhlIEV2ZW50QnJpZGdlIEV2ZW50QnVzIG9uIHdoaWNoIHRvIHB1dCBldmVudHMuXG4gICAqIEBwYXJhbSBvcHRpb25zIFRoZSBvcHRpb25hbCBjb25maWd1cmF0aW9uIGZvciB0aGlzIGRhdGEgc291cmNlLlxuICAgKi9cbiAgcHVibGljIGFkZEV2ZW50QnJpZGdlRGF0YVNvdXJjZShpZDogc3RyaW5nLCBldmVudEJ1czogSUV2ZW50QnVzLCBvcHRpb25zPzogRGF0YVNvdXJjZU9wdGlvbnMpOiBFdmVudEJyaWRnZURhdGFTb3VyY2Uge1xuICAgIHJldHVybiB0aGlzLnJlc291cmNlcy5ncmFwaHFsQXBpLmFkZEV2ZW50QnJpZGdlRGF0YVNvdXJjZShpZCwgZXZlbnRCdXMsIG9wdGlvbnMpO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZCBhIG5ldyBodHRwIGRhdGEgc291cmNlIHRvIHRoaXMgQVBJLiBUaGlzIGlzIGEgcHJveHkgbWV0aG9kIHRvIHRoZSBMMiBHcmFwaHFsQXBpIENvbnN0cnVjdC5cbiAgICogQHBhcmFtIGlkIFRoZSBkYXRhIHNvdXJjZSdzIGlkLlxuICAgKiBAcGFyYW0gZW5kcG9pbnQgVGhlIGh0dHAgZW5kcG9pbnQuXG4gICAqIEBwYXJhbSBvcHRpb25zIFRoZSBvcHRpb25hbCBjb25maWd1cmF0aW9uIGZvciB0aGlzIGRhdGEgc291cmNlLlxuICAgKiBAcmV0dXJucyB0aGUgZ2VuZXJhdGVkIGRhdGEgc291cmNlLlxuICAgKi9cbiAgcHVibGljIGFkZEh0dHBEYXRhU291cmNlKGlkOiBzdHJpbmcsIGVuZHBvaW50OiBzdHJpbmcsIG9wdGlvbnM/OiBIdHRwRGF0YVNvdXJjZU9wdGlvbnMpOiBIdHRwRGF0YVNvdXJjZSB7XG4gICAgcmV0dXJuIHRoaXMucmVzb3VyY2VzLmdyYXBocWxBcGkuYWRkSHR0cERhdGFTb3VyY2UoaWQsIGVuZHBvaW50LCBvcHRpb25zKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGQgYSBuZXcgTGFtYmRhIGRhdGEgc291cmNlIHRvIHRoaXMgQVBJLiBUaGlzIGlzIGEgcHJveHkgbWV0aG9kIHRvIHRoZSBMMiBHcmFwaHFsQXBpIENvbnN0cnVjdC5cbiAgICogQHBhcmFtIGlkIFRoZSBkYXRhIHNvdXJjZSdzIGlkLlxuICAgKiBAcGFyYW0gbGFtYmRhRnVuY3Rpb24gVGhlIExhbWJkYSBmdW5jdGlvbiB0byBjYWxsIHRvIGludGVyYWN0IHdpdGggdGhpcyBkYXRhIHNvdXJjZS5cbiAgICogQHBhcmFtIG9wdGlvbnMgVGhlIG9wdGlvbmFsIGNvbmZpZ3VyYXRpb24gZm9yIHRoaXMgZGF0YSBzb3VyY2UuXG4gICAqIEByZXR1cm5zIHRoZSBnZW5lcmF0ZWQgZGF0YSBzb3VyY2UuXG4gICAqL1xuICBwdWJsaWMgYWRkTGFtYmRhRGF0YVNvdXJjZShpZDogc3RyaW5nLCBsYW1iZGFGdW5jdGlvbjogSUZ1bmN0aW9uLCBvcHRpb25zPzogRGF0YVNvdXJjZU9wdGlvbnMpOiBMYW1iZGFEYXRhU291cmNlIHtcbiAgICByZXR1cm4gdGhpcy5yZXNvdXJjZXMuZ3JhcGhxbEFwaS5hZGRMYW1iZGFEYXRhU291cmNlKGlkLCBsYW1iZGFGdW5jdGlvbiwgb3B0aW9ucyk7XG4gIH1cblxuICAvKipcbiAgICogQWRkIGEgbmV3IGR1bW15IGRhdGEgc291cmNlIHRvIHRoaXMgQVBJLiBUaGlzIGlzIGEgcHJveHkgbWV0aG9kIHRvIHRoZSBMMiBHcmFwaHFsQXBpIENvbnN0cnVjdC5cbiAgICogVXNlZnVsIGZvciBwaXBlbGluZSByZXNvbHZlcnMgYW5kIGZvciBiYWNrZW5kIGNoYW5nZXMgdGhhdCBkb24ndCByZXF1aXJlIGEgZGF0YSBzb3VyY2UuXG4gICAqIEBwYXJhbSBpZCBUaGUgZGF0YSBzb3VyY2UncyBpZC5cbiAgICogQHBhcmFtIG9wdGlvbnMgVGhlIG9wdGlvbmFsIGNvbmZpZ3VyYXRpb24gZm9yIHRoaXMgZGF0YSBzb3VyY2UuXG4gICAqIEByZXR1cm5zIHRoZSBnZW5lcmF0ZWQgZGF0YSBzb3VyY2UuXG4gICAqL1xuICBwdWJsaWMgYWRkTm9uZURhdGFTb3VyY2UoaWQ6IHN0cmluZywgb3B0aW9ucz86IERhdGFTb3VyY2VPcHRpb25zKTogTm9uZURhdGFTb3VyY2Uge1xuICAgIHJldHVybiB0aGlzLnJlc291cmNlcy5ncmFwaHFsQXBpLmFkZE5vbmVEYXRhU291cmNlKGlkLCBvcHRpb25zKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBkZCBhIG5ldyBPcGVuU2VhcmNoIGRhdGEgc291cmNlIHRvIHRoaXMgQVBJLiBUaGlzIGlzIGEgcHJveHkgbWV0aG9kIHRvIHRoZSBMMiBHcmFwaHFsQXBpIENvbnN0cnVjdC5cbiAgICogQHBhcmFtIGlkIFRoZSBkYXRhIHNvdXJjZSdzIGlkLlxuICAgKiBAcGFyYW0gZG9tYWluIFRoZSBPcGVuU2VhcmNoIGRvbWFpbiBmb3IgdGhpcyBkYXRhIHNvdXJjZS5cbiAgICogQHBhcmFtIG9wdGlvbnMgVGhlIG9wdGlvbmFsIGNvbmZpZ3VyYXRpb24gZm9yIHRoaXMgZGF0YSBzb3VyY2UuXG4gICAqIEByZXR1cm5zIHRoZSBnZW5lcmF0ZWQgZGF0YSBzb3VyY2UuXG4gICAqL1xuICBwdWJsaWMgYWRkT3BlblNlYXJjaERhdGFTb3VyY2UoaWQ6IHN0cmluZywgZG9tYWluOiBJT3BlblNlYXJjaERvbWFpbiwgb3B0aW9ucz86IERhdGFTb3VyY2VPcHRpb25zKTogT3BlblNlYXJjaERhdGFTb3VyY2Uge1xuICAgIHJldHVybiB0aGlzLnJlc291cmNlcy5ncmFwaHFsQXBpLmFkZE9wZW5TZWFyY2hEYXRhU291cmNlKGlkLCBkb21haW4sIG9wdGlvbnMpO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZCBhIG5ldyBSZHMgZGF0YSBzb3VyY2UgdG8gdGhpcyBBUEkuIFRoaXMgaXMgYSBwcm94eSBtZXRob2QgdG8gdGhlIEwyIEdyYXBocWxBcGkgQ29uc3RydWN0LlxuICAgKiBAcGFyYW0gaWQgVGhlIGRhdGEgc291cmNlJ3MgaWQuXG4gICAqIEBwYXJhbSBzZXJ2ZXJsZXNzQ2x1c3RlciBUaGUgc2VydmVybGVzcyBjbHVzdGVyIHRvIGludGVyYWN0IHdpdGggdGhpcyBkYXRhIHNvdXJjZS5cbiAgICogQHBhcmFtIHNlY3JldFN0b3JlIFRoZSBzZWNyZXQgc3RvcmUgdGhhdCBjb250YWlucyB0aGUgdXNlcm5hbWUgYW5kIHBhc3N3b3JkIGZvciB0aGUgc2VydmVybGVzcyBjbHVzdGVyLlxuICAgKiBAcGFyYW0gZGF0YWJhc2VOYW1lIFRoZSBvcHRpb25hbCBuYW1lIG9mIHRoZSBkYXRhYmFzZSB0byB1c2Ugd2l0aGluIHRoZSBjbHVzdGVyLlxuICAgKiBAcGFyYW0gb3B0aW9ucyBUaGUgb3B0aW9uYWwgY29uZmlndXJhdGlvbiBmb3IgdGhpcyBkYXRhIHNvdXJjZS5cbiAgICogQHJldHVybnMgdGhlIGdlbmVyYXRlZCBkYXRhIHNvdXJjZS5cbiAgICovXG4gIHB1YmxpYyBhZGRSZHNEYXRhU291cmNlKFxuICAgIGlkOiBzdHJpbmcsXG4gICAgc2VydmVybGVzc0NsdXN0ZXI6IElTZXJ2ZXJsZXNzQ2x1c3RlcixcbiAgICBzZWNyZXRTdG9yZTogSVNlY3JldCxcbiAgICBkYXRhYmFzZU5hbWU/OiBzdHJpbmcsXG4gICAgb3B0aW9ucz86IERhdGFTb3VyY2VPcHRpb25zLFxuICApOiBSZHNEYXRhU291cmNlIHtcbiAgICByZXR1cm4gdGhpcy5yZXNvdXJjZXMuZ3JhcGhxbEFwaS5hZGRSZHNEYXRhU291cmNlKGlkLCBzZXJ2ZXJsZXNzQ2x1c3Rlciwgc2VjcmV0U3RvcmUsIGRhdGFiYXNlTmFtZSwgb3B0aW9ucyk7XG4gIH1cblxuICAvKipcbiAgICogQWRkIGEgcmVzb2x2ZXIgdG8gdGhlIGFwaS4gVGhpcyBpcyBhIHByb3h5IG1ldGhvZCB0byB0aGUgTDIgR3JhcGhxbEFwaSBDb25zdHJ1Y3QuXG4gICAqIEBwYXJhbSBpZCBUaGUgcmVzb2x2ZXIncyBpZC5cbiAgICogQHBhcmFtIHByb3BzIHRoZSByZXNvbHZlciBwcm9wZXJ0aWVzLlxuICAgKiBAcmV0dXJucyB0aGUgZ2VuZXJhdGVkIHJlc29sdmVyLlxuICAgKi9cbiAgcHVibGljIGFkZFJlc29sdmVyKGlkOiBzdHJpbmcsIHByb3BzOiBFeHRlbmRlZFJlc29sdmVyUHJvcHMpOiBSZXNvbHZlciB7XG4gICAgcmV0dXJuIHRoaXMucmVzb3VyY2VzLmdyYXBocWxBcGkuY3JlYXRlUmVzb2x2ZXIoaWQsIHByb3BzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGQgYW4gYXBwc3luYyBmdW5jdGlvbiB0byB0aGUgYXBpLlxuICAgKiBAcGFyYW0gaWQgdGhlIGZ1bmN0aW9uJ3MgaWQuXG4gICAqIEByZXR1cm5zIHRoZSBnZW5lcmF0ZWQgYXBwc3luYyBmdW5jdGlvbi5cbiAgICovXG4gIHB1YmxpYyBhZGRGdW5jdGlvbihpZDogc3RyaW5nLCBwcm9wczogQWRkRnVuY3Rpb25Qcm9wcyk6IEFwcHN5bmNGdW5jdGlvbiB7XG4gICAgcmV0dXJuIG5ldyBBcHBzeW5jRnVuY3Rpb24odGhpcywgaWQsIHtcbiAgICAgIGFwaTogdGhpcy5yZXNvdXJjZXMuZ3JhcGhxbEFwaSxcbiAgICAgIC4uLnByb3BzLFxuICAgIH0pO1xuICB9XG59XG5cbi8qKlxuICogR2l2ZW4gdGhlIHByb3ZpZGVkIHNjb3BlLCB3YWxrIHRoZSBub2RlIHRyZWUsIGFuZCB0aHJvdyBhbiBleGNlcHRpb24gaWYgYW55IG90aGVyIEFtcGxpZnlHcmFwaHFsQXBpIGNvbnN0cnVjdHNcbiAqIGFyZSBmb3VuZCBpbiB0aGUgc3RhY2suXG4gKiBAcGFyYW0gc2NvcGUgdGhlIHNjb3BlIHRoaXMgY29uc3RydWN0IGlzIGNyZWF0ZWQgaW4uXG4gKi9cbmNvbnN0IHZhbGlkYXRlTm9PdGhlckFtcGxpZnlHcmFwaHFsQXBpSW5TdGFjayA9IChzY29wZTogQ29uc3RydWN0KTogdm9pZCA9PiB7XG4gIGNvbnN0IHJvb3RTdGFjayA9IGdldFN0YWNrRm9yU2NvcGUoc2NvcGUsIGZhbHNlKTtcblxuICBsZXQgd2FzT3RoZXJBbXBsaWZ5R3JhcGhsQXBpRm91bmQgPSBmYWxzZTtcbiAgd2Fsa0FuZFByb2Nlc3NOb2Rlcyhyb290U3RhY2ssIChub2RlOiBDb25zdHJ1Y3QpID0+IHtcbiAgICBpZiAobm9kZSBpbnN0YW5jZW9mIEFtcGxpZnlHcmFwaHFsQXBpICYmIHNjb3BlICE9PSBub2RlKSB7XG4gICAgICB3YXNPdGhlckFtcGxpZnlHcmFwaGxBcGlGb3VuZCA9IHRydWU7XG4gICAgfVxuICB9KTtcblxuICBpZiAod2FzT3RoZXJBbXBsaWZ5R3JhcGhsQXBpRm91bmQpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ09ubHkgb25lIEFtcGxpZnlHcmFwaHFsQXBpIGlzIGV4cGVjdGVkIGluIGEgc3RhY2suIFBsYWNlIHRoZSBBbXBsaWZ5R3Jh