import { AmplifyData, AmplifyDynamoDbTableWrapper, } from '@aws-amplify/data-construct'; import { generateModelsSync } from '@aws-amplify/graphql-generator'; import * as path from 'path'; import { combineCDKSchemas, convertSchemaToCDK, isCombinedSchema, isDataSchema, splitSchemasByTableMap, } from './convert_schema.js'; import { convertFunctionNameMapToCDK } from './convert_functions.js'; import { buildConstructFactoryProvidedAuthConfig, convertAuthorizationModesToCDK, isUsingDefaultApiKeyAuth, } from './convert_authorization_modes.js'; import { validateAuthorizationModes } from './validate_authorization_modes.js'; import { AmplifyError, AmplifyUserError, CDKContextKey, TagName, } from '@aws-amplify/platform-core'; import { Aspects, RemovalPolicy, Tags } from 'aws-cdk-lib'; import { convertJsResolverDefinition } from './convert_js_resolvers.js'; import { AppSyncPolicyGenerator } from './app_sync_policy_generator.js'; import { Bucket } from 'aws-cdk-lib/aws-s3'; import { BucketDeployment, Source } from 'aws-cdk-lib/aws-s3-deployment'; import { convertLoggingOptionsToCDK } from './logging_options_parser.js'; const modelIntrospectionSchemaKey = 'modelIntrospectionSchema.json'; const defaultName = 'amplifyData'; /** * Singleton factory for AmplifyGraphqlApi constructs that can be used in Amplify project files. * * Exported for testing purpose only & should NOT be exported out of the package. */ export class DataFactory { props; importStack; // publicly accessible for testing purpose only. static factoryCount = 0; generator; /** * Create a new AmplifyConstruct */ constructor(props, importStack = new Error().stack) { this.props = props; this.importStack = importStack; if (DataFactory.factoryCount > 0) { throw new AmplifyUserError('MultipleSingletonResourcesError', { message: 'Multiple `defineData` calls are not allowed within an Amplify backend', resolution: 'Remove all but one `defineData` call', }); } DataFactory.factoryCount++; } /** * Gets an instance of the Data construct */ getInstance = (props) => { const { constructContainer, outputStorageStrategy, importPathVerifier, resourceNameValidator, } = props; importPathVerifier?.verify(this.importStack, path.join('amplify', 'data', 'resource'), 'Amplify Data must be defined in amplify/data/resource.ts'); if (this.props.name) { resourceNameValidator?.validate(this.props.name); } if (!this.generator) { this.generator = new DataGenerator(this.props, buildConstructFactoryProvidedAuthConfig(props.constructContainer .getConstructFactory('AuthResources') ?.getInstance(props)), props, outputStorageStrategy); } return constructContainer.getOrCompute(this.generator); }; } class DataGenerator { props; providedAuthConfig; getInstanceProps; outputStorageStrategy; resourceGroupName = 'data'; name; constructor(props, providedAuthConfig, getInstanceProps, outputStorageStrategy) { this.props = props; this.providedAuthConfig = providedAuthConfig; this.getInstanceProps = getInstanceProps; this.outputStorageStrategy = outputStorageStrategy; this.name = props.name ?? defaultName; } generateContainerEntry = ({ scope, ssmEnvironmentEntriesGenerator, backendSecretResolver, stableBackendIdentifiers, }) => { const amplifyGraphqlDefinitions = []; const schemasJsFunctions = []; const schemasFunctionSchemaAccess = []; let schemasLambdaFunctions = {}; try { const schemas = isCombinedSchema(this.props.schema) ? this.props.schema.schemas : [this.props.schema]; const isSandboxDeployment = scope.node.tryGetContext(CDKContextKey.DEPLOYMENT_TYPE) === 'sandbox'; // get the branch name and use the imported table map for that key // use the sandbox key when in sandbox deployment const amplifyBranchName = isSandboxDeployment ? 'sandbox' : scope.node.tryGetContext(CDKContextKey.BACKEND_NAME); // ensure all branch names are unique if (this.props.migratedAmplifyGen1DynamoDbTableMappings) { const branchNames = new Set(); for (const tableMap of this.props .migratedAmplifyGen1DynamoDbTableMappings) { if (branchNames.has(tableMap.branchName)) { throw new AmplifyUserError('DefineDataConfigurationError', { message: 'Branch names must be unique in the migratedAmplifyGen1DynamoDbTableMappings', resolution: 'Ensure all branch names are unique', }); } branchNames.add(tableMap.branchName); } } const tableMapForCurrentBranch = (this.props.migratedAmplifyGen1DynamoDbTableMappings ?? []).find((tableMap) => tableMap.branchName === amplifyBranchName); const splitSchemas = splitSchemasByTableMap(schemas, tableMapForCurrentBranch); splitSchemas.forEach(({ schema, importedTableName }) => { if (isDataSchema(schema)) { const { jsFunctions, functionSchemaAccess, lambdaFunctions } = schema.transform(); schemasJsFunctions.push(...jsFunctions); schemasFunctionSchemaAccess.push(...functionSchemaAccess); schemasLambdaFunctions = { ...schemasLambdaFunctions, ...lambdaFunctions, }; } amplifyGraphqlDefinitions.push(convertSchemaToCDK(schema, backendSecretResolver, stableBackendIdentifiers, importedTableName)); }); } catch (error) { throw new AmplifyUserError('InvalidSchemaError', { message: error instanceof Error ? error.message : 'Failed to parse schema definition.', resolution: 'Check your data schema definition for syntax and type errors.', }, error instanceof Error ? error : undefined); } let authorizationModes; try { authorizationModes = convertAuthorizationModesToCDK(this.getInstanceProps, this.providedAuthConfig, this.props.authorizationModes); } catch (error) { if (AmplifyError.isAmplifyError(error)) { throw error; } throw new AmplifyUserError('InvalidSchemaAuthError', { message: error instanceof Error ? error.message : 'Failed to parse authorization modes.', resolution: 'Ensure the auth rules on your schema are valid.', }, error instanceof Error ? error : undefined); } try { validateAuthorizationModes(this.props.authorizationModes, authorizationModes); } catch (error) { throw new AmplifyUserError('InvalidSchemaAuthError', { message: error instanceof Error ? error.message : 'Failed to validate authorization modes', resolution: 'Ensure the auth rules on your schema are valid.', }, error instanceof Error ? error : undefined); } const sandboxModeEnabled = isUsingDefaultApiKeyAuth(this.providedAuthConfig, this.props.authorizationModes); const propsFunctions = this.props.functions ?? {}; const functionNameMap = convertFunctionNameMapToCDK(this.getInstanceProps, { ...propsFunctions, ...schemasLambdaFunctions, }); let amplifyApi = undefined; let modelIntrospectionSchema = undefined; const isSandboxDeployment = scope.node.tryGetContext(CDKContextKey.DEPLOYMENT_TYPE) === 'sandbox'; const cdkLoggingOptions = convertLoggingOptionsToCDK(this.props.logging ?? undefined); try { const combinedSchema = combineCDKSchemas(amplifyGraphqlDefinitions); modelIntrospectionSchema = generateModelsSync({ schema: combinedSchema.schema, target: 'introspection', })['model-introspection.json']; amplifyApi = new AmplifyData(scope, this.name, { apiName: this.name, definition: combinedSchema, authorizationModes, outputStorageStrategy: this.outputStorageStrategy, functionNameMap, translationBehavior: { sandboxModeEnabled, /** * The destructive updates should be always allowed in backend definition and not to be controlled on the IaC * The CI/CD check should take the responsibility to validate if any tables are being replaced and determine whether to execute the changeset */ allowDestructiveGraphqlSchemaUpdates: true, _provisionHotswapFriendlyResources: isSandboxDeployment, }, logging: cdkLoggingOptions, stackMappings: this.props.stackMappings, }); } catch (error) { throw new AmplifyUserError('AmplifyDataConstructInitializationError', { message: 'Failed to instantiate data construct', resolution: 'See the underlying error message for more details.', }, error); } const modelIntrospectionSchemaBucket = new Bucket(scope, 'modelIntrospectionSchemaBucket', { enforceSSL: true, autoDeleteObjects: true, removalPolicy: RemovalPolicy.DESTROY, }); new BucketDeployment(scope, 'modelIntrospectionSchemaBucketDeployment', { // See https://github.com/aws-amplify/amplify-category-api/pull/1939 memoryLimit: 1536, destinationBucket: modelIntrospectionSchemaBucket, sources: [ Source.data(modelIntrospectionSchemaKey, modelIntrospectionSchema), ], }); Tags.of(amplifyApi).add(TagName.FRIENDLY_NAME, this.name); /**; * Enable the table replacement upon GSI update * This is allowed in sandbox mode ONLY */ if (isSandboxDeployment) { Aspects.of(amplifyApi).add(new ReplaceTableUponGsiUpdateOverrideAspect()); } convertJsResolverDefinition(scope, amplifyApi, schemasJsFunctions); const namePrefix = this.name === defaultName ? '' : defaultName; const ssmEnvironmentScopeContext = { [`${namePrefix}${this.name}_GRAPHQL_ENDPOINT`]: amplifyApi.resources.cfnResources.cfnGraphqlApi.attrGraphQlUrl, [`${namePrefix}${this.name}_MODEL_INTROSPECTION_SCHEMA_BUCKET_NAME`]: modelIntrospectionSchemaBucket.bucketName, [`${namePrefix}${this.name}_MODEL_INTROSPECTION_SCHEMA_KEY`]: modelIntrospectionSchemaKey, ['AMPLIFY_DATA_DEFAULT_NAME']: `${namePrefix}${this.name}`, }; const backwardsCompatibleScopeContext = `${this.name}_GRAPHQL_ENDPOINT` !== `${namePrefix}${this.name}_GRAPHQL_ENDPOINT` ? { // @deprecated [`${this.name}_GRAPHQL_ENDPOINT`]: amplifyApi.resources.cfnResources.cfnGraphqlApi.attrGraphQlUrl, } : {}; const ssmEnvironmentEntries = ssmEnvironmentEntriesGenerator.generateSsmEnvironmentEntries({ ...ssmEnvironmentScopeContext, ...backwardsCompatibleScopeContext, }); const policyGenerator = new AppSyncPolicyGenerator(amplifyApi.resources.graphqlApi, `${modelIntrospectionSchemaBucket.bucketArn}/${modelIntrospectionSchemaKey}`); schemasFunctionSchemaAccess.forEach((accessDefinition) => { const policy = policyGenerator.generateGraphqlAccessPolicy(accessDefinition.actions); accessDefinition.resourceProvider .getInstance(this.getInstanceProps) .getResourceAccessAcceptor() .acceptResourceAccess(policy, ssmEnvironmentEntries); }); return amplifyApi; }; } const REPLACE_TABLE_UPON_GSI_UPDATE_ATTRIBUTE_NAME = 'replaceTableUponGsiUpdate'; /** * Aspect class to modify the amplify managed DynamoDB table * to allow table replacement upon GSI update */ class ReplaceTableUponGsiUpdateOverrideAspect { visit(scope) { if (AmplifyDynamoDbTableWrapper.isAmplifyDynamoDbTableResource(scope)) { // These value setters are not exposed in the wrapper // Need to use the property override to escape the hatch scope.addPropertyOverride(REPLACE_TABLE_UPON_GSI_UPDATE_ATTRIBUTE_NAME, true); } } } /** * Creates a factory that implements ConstructFactory */ export const defineData = (props) => new DataFactory(props, new Error().stack); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmFjdG9yeS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9mYWN0b3J5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQWFBLE9BQU8sRUFDTCxXQUFXLEVBQ1gsMkJBQTJCLEdBRzVCLE1BQU0sNkJBQTZCLENBQUM7QUFFckMsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFDcEUsT0FBTyxLQUFLLElBQUksTUFBTSxNQUFNLENBQUM7QUFFN0IsT0FBTyxFQUNMLGlCQUFpQixFQUNqQixrQkFBa0IsRUFDbEIsZ0JBQWdCLEVBQ2hCLFlBQVksRUFDWixzQkFBc0IsR0FDdkIsTUFBTSxxQkFBcUIsQ0FBQztBQUM3QixPQUFPLEVBQUUsMkJBQTJCLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUNyRSxPQUFPLEVBRUwsdUNBQXVDLEVBQ3ZDLDhCQUE4QixFQUM5Qix3QkFBd0IsR0FDekIsTUFBTSxrQ0FBa0MsQ0FBQztBQUMxQyxPQUFPLEVBQUUsMEJBQTBCLEVBQUUsTUFBTSxtQ0FBbUMsQ0FBQztBQUMvRSxPQUFPLEVBQ0wsWUFBWSxFQUNaLGdCQUFnQixFQUNoQixhQUFhLEVBQ2IsT0FBTyxHQUNSLE1BQU0sNEJBQTRCLENBQUM7QUFDcEMsT0FBTyxFQUFFLE9BQU8sRUFBVyxhQUFhLEVBQUUsSUFBSSxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQ3BFLE9BQU8sRUFBRSwyQkFBMkIsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQ3hFLE9BQU8sRUFBRSxzQkFBc0IsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBS3hFLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUM1QyxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFDekUsT0FBTyxFQUFFLDBCQUEwQixFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFDekUsTUFBTSwyQkFBMkIsR0FBRywrQkFBK0IsQ0FB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QU8sQ0FDekIsQ0FBQztZQUNGLGdCQUFnQixDQUFDLGdCQUFnQjtpQkFDOUIsV0FBVyxDQUFDLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQztpQkFDbEMseUJBQXlCLEVBQUU7aUJBQzNCLG9CQUFvQixDQUFDLE1BQU0sRUFBRSxxQkFBcUIsQ0FBQyxDQUFDO1FBQ3pELENBQUMsQ0FBQyxDQUFDO1FBRUgsT0FBTyxVQUFVLENBQUM7SUFDcEIsQ0FBQyxDQUFDO0NBQ0g7QUFFRCxNQUFNLDRDQUE0QyxHQUNoRCwyQkFBMkIsQ0FBQztBQUU5Qjs7O0dBR0c7QUFDSCxNQUFNLHVDQUF1QztJQUNwQyxLQUFLLENBQUMsS0FBaUI7UUFDNUIsSUFBSSwyQkFBMkIsQ0FBQyw4QkFBOEIsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQ3RFLHFEQUFxRDtZQUNyRCx3REFBd0Q7WUFDeEQsS0FBSyxDQUFDLG1CQUFtQixDQUN2Qiw0Q0FBNEMsRUFDNUMsSUFBSSxDQUNMLENBQUM7UUFDSixDQUFDO0lBQ0gsQ0FBQztDQUNGO0FBRUQ7O0dBRUc7QUFDSCxNQUFNLENBQUMsTUFBTSxVQUFVLEdBQUcsQ0FBQyxLQUFnQixFQUFpQyxFQUFFLENBQzVFLElBQUksV0FBVyxDQUFDLEtBQUssRUFBRSxJQUFJLEtBQUssRUFBRSxDQUFDLEtBQUssQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSUNvbnN0cnVjdCB9IGZyb20gJ2NvbnN0cnVjdHMnO1xuaW1wb3J0IHtcbiAgQW1wbGlmeUZ1bmN0aW9uLFxuICBBbXBsaWZ5UmVzb3VyY2VHcm91cE5hbWUsXG4gIEF1dGhSZXNvdXJjZXMsXG4gIEJhY2tlbmRPdXRwdXRTdG9yYWdlU3RyYXRlZ3ksXG4gIENvbnN0cnVjdENvbnRhaW5lckVudHJ5R2VuZXJhdG9yLFxuICBDb25zdHJ1Y3RGYWN0b3J5LFxuICBDb25zdHJ1Y3RGYWN0b3J5R2V0SW5zdGFuY2VQcm9wcyxcbiAgR2VuZXJhdGVDb250YWluZXJFbnRyeVByb3BzLFxuICBSZWZlcmVuY2VBdXRoUmVzb3VyY2VzLFxuICBSZXNvdXJjZVByb3ZpZGVyLFxufSBmcm9tICdAYXdzLWFtcGxpZnkvcGx1Z2luLXR5cGVzJztcbmltcG9ydCB7XG4gIEFtcGxpZnlEYXRhLFxuICBBbXBsaWZ5RHluYW1vRGJUYWJsZVdyYXBwZXIsXG4gIElBbXBsaWZ5RGF0YURlZmluaXRpb24sXG4gIFRyYW5zbGF0aW9uQmVoYXZpb3IsXG59IGZyb20gJ0Bhd3MtYW1wbGlmeS9kYXRhLWNvbnN0cnVjdCc7XG5pbXBvcnQgeyBHcmFwaHFsT3V0cHV0IH0gZnJvbSAnQGF3cy1hbXBsaWZ5L2JhY2tlbmQtb3V0cHV0LXNjaGVtYXMnO1xuaW1wb3J0IHsgZ2VuZXJhdGVNb2RlbHNTeW5jIH0gZnJvbSAnQGF3cy1hbXBsaWZ5L2dyYXBocWwtZ2VuZXJhdG9yJztcbmltcG9ydCAqIGFzIHBhdGggZnJvbSAncGF0aCc7XG5pbXBvcnQgeyBBbXBsaWZ5RGF0YUVycm9yLCBEYXRhUHJvcHMgfSBmcm9tICcuL3R5cGVzLmpzJztcbmltcG9ydCB7XG4gIGNvbWJpbmVDREtTY2hlbWFzLFxuICBjb252ZXJ0U2NoZW1hVG9DREssXG4gIGlzQ29tYmluZWRTY2hlbWEsXG4gIGlzRGF0YVNjaGVtYSxcbiAgc3BsaXRTY2hlbWFzQnlUYWJsZU1hcCxcbn0gZnJvbSAnLi9jb252ZXJ0X3NjaGVtYS5qcyc7XG5pbXBvcnQgeyBjb252ZXJ0RnVuY3Rpb25OYW1lTWFwVG9DREsgfSBmcm9tICcuL2NvbnZlcnRfZnVuY3Rpb25zLmpzJztcbmltcG9ydCB7XG4gIFByb3ZpZGVkQXV0aENvbmZpZyxcbiAgYnVpbGRDb25zdHJ1Y3RGYWN0b3J5UHJvdmlkZWRBdXRoQ29uZmlnLFxuICBjb252ZXJ0QXV0aG9yaXphdGlvbk1vZGVzVG9DREssXG4gIGlzVXNpbmdEZWZhdWx0QXBpS2V5QXV0aCxcbn0gZnJvbSAnLi9jb252ZXJ0X2F1dGhvcml6YXRpb25fbW9kZXMuanMnO1xuaW1wb3J0IHsgdmFsaWRhdGVBdXRob3JpemF0aW9uTW9kZXMgfSBmcm9tICcuL3ZhbGlkYXRlX2F1dGhvcml6YXRpb25fbW9kZXMuanMnO1xuaW1wb3J0IHtcbiAgQW1wbGlmeUVycm9yLFxuICBBbXBsaWZ5VXNlckVycm9yLFxuICBDREtDb250ZXh0S2V5LFxuICBUYWdOYW1lLFxufSBmcm9tICdAYXdzLWFtcGxpZnkvcGxhdGZvcm0tY29yZSc7XG5pbXBvcnQgeyBBc3BlY3RzLCBJQXNwZWN0LCBSZW1vdmFsUG9saWN5LCBUYWdzIH0gZnJvbSAnYXdzLWNkay1saWInO1xuaW1wb3J0IHsgY29udmVydEpzUmVzb2x2ZXJEZWZpbml0aW9uIH0gZnJvbSAnLi9jb252ZXJ0X2pzX3Jlc29sdmVycy5qcyc7XG5pbXBvcnQgeyBBcHBTeW5jUG9saWN5R2VuZXJhdG9yIH0gZnJvbSAnLi9hcHBfc3luY19wb2xpY3lfZ2VuZXJhdG9yLmpzJztcbmltcG9ydCB7XG4gIEZ1bmN0aW9uU2NoZW1hQWNjZXNzLFxuICBKc1Jlc29sdmVyLFxufSBmcm9tICdAYXdzLWFtcGxpZnkvZGF0YS1zY2hlbWEtdHlwZXMnO1xuaW1wb3J0IHsgQnVja2V0IH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLXMzJztcbmltcG9ydCB7IEJ1Y2tldERlcGxveW1lbnQsIFNvdXJjZSB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1zMy1kZXBsb3ltZW50JztcbmltcG9ydCB7IGNvbnZlcnRMb2dnaW5nT3B0aW9uc1RvQ0RLIH0gZnJvbSAnLi9sb2dnaW5nX29wdGlvbnNfcGFyc2VyLmpzJztcbmNvbnN0IG1vZGVsSW50cm9zcGVjdGlvblNjaGVtYUtleSA9ICdtb2RlbEludHJvc3BlY3Rpb25TY2hlbWEuanNvbic7XG5jb25zdCBkZWZhdWx0TmFtZSA9ICdhbXBsaWZ5RGF0YSc7XG5cbi8qKlxuICogU2luZ2xldG9uIGZhY3RvcnkgZm9yIEFtcGxpZnlHcmFwaHFsQXBpIGNvbnN0cnVjdHMgdGhhdCBjYW4gYmUgdXNlZCBpbiBBbXBsaWZ5IHByb2plY3QgZmlsZXMuXG4gKlxuICogRXhwb3J0ZWQgZm9yIHRlc3RpbmcgcHVycG9zZSBvbmx5ICYgc2hvdWxkIE5PVCBiZSBleHBvcnRlZCBvdXQgb2YgdGhlIHBhY2thZ2UuXG4gKi9cbmV4cG9ydCBjbGFzcyBEYXRhRmFjdG9yeSBpbXBsZW1lbnRzIENvbnN0cnVjdEZhY3Rvcnk8QW1wbGlmeURhdGE+IHtcbiAgLy8gcHVibGljbHkgYWNjZXNzaWJsZSBmb3IgdGVzdGluZyBwdXJwb3NlIG9ubHkuXG4gIHN0YXRpYyBmYWN0b3J5Q291bnQgPSAwO1xuXG4gIHByaXZhdGUgZ2VuZXJhdG9yOiBDb25zdHJ1Y3RDb250YWluZXJFbnRyeUdlbmVyYXRvcjtcblxuICAvKipcbiAgICogQ3JlYXRlIGEgbmV3IEFtcGxpZnlDb25zdHJ1Y3RcbiAgICovXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgcmVhZG9ubHkgcHJvcHM6IERhdGFQcm9wcyxcbiAgICBwcml2YXRlIHJlYWRvbmx5IGltcG9ydFN0YWNrID0gbmV3IEVycm9yKCkuc3RhY2ssXG4gICkge1xuICAgIGlmIChEYXRhRmFjdG9yeS5mYWN0b3J5Q291bnQgPiAwKSB7XG4gICAgICB0aHJvdyBuZXcgQW1wbGlmeVVzZXJFcnJvcignTXVsdGlwbGVTaW5nbGV0b25SZXNvdXJjZXNFcnJvcicsIHtcbiAgICAgICAgbWVzc2FnZTpcbiAgICAgICAgICAnTXVsdGlwbGUgYGRlZmluZURhdGFgIGNhbGxzIGFyZSBub3QgYWxsb3dlZCB3aXRoaW4gYW4gQW1wbGlmeSBiYWNrZW5kJyxcbiAgICAgICAgcmVzb2x1dGlvbjogJ1JlbW92ZSBhbGwgYnV0IG9uZSBgZGVmaW5lRGF0YWAgY2FsbCcsXG4gICAgICB9KTtcbiAgICB9XG4gICAgRGF0YUZhY3RvcnkuZmFjdG9yeUNvdW50Kys7XG4gIH1cblxuICAvKipcbiAgICogR2V0cyBhbiBpbnN0YW5jZSBvZiB0aGUgRGF0YSBjb25zdHJ1Y3RcbiAgICovXG4gIGdldEluc3RhbmNlID0gKHByb3BzOiBDb25zdHJ1Y3RGYWN0b3J5R2V0SW5zdGFuY2VQcm9wcyk6IEFtcGxpZnlEYXRhID0+IHtcbiAgICBjb25zdCB7XG4gICAgICBjb25zdHJ1Y3RDb250YWluZXIsXG4gICAgICBvdXRwdXRTdG9yYWdlU3RyYXRlZ3ksXG4gICAgICBpbXBvcnRQYXRoVmVyaWZpZXIsXG4gICAgICByZXNvdXJjZU5hbWVWYWxpZGF0b3IsXG4gICAgfSA9IHByb3BzO1xuICAgIGltcG9ydFBhdGhWZXJpZmllcj8udmVyaWZ5KFxuICAgICAgdGhpcy5pbXBvcnRTdGFjayxcbiAgICAgIHBhdGguam9pbignYW1wbGlmeScsICdkYXRhJywgJ3Jlc291cmNlJyksXG4gICAgICAnQW1wbGlmeSBEYXRhIG11c3QgYmUgZGVmaW5lZCBpbiBhbXBsaWZ5L2RhdGEvcmVzb3VyY2UudHMnLFxuICAgICk7XG4gICAgaWYgKHRoaXMucHJvcHMubmFtZSkge1xuICAgICAgcmVzb3VyY2VOYW1lVmFsaWRhdG9yPy52YWxpZGF0ZSh0aGlzLnByb3BzLm5hbWUpO1xuICAgIH1cbiAgICBpZiAoIXRoaXMuZ2VuZXJhdG9yKSB7XG4gICAgICB0aGlzLmdlbmVyYXRvciA9IG5ldyBEYXRhR2VuZXJhdG9yKFxuICAgICAgICB0aGlzLnByb3BzLFxuICAgICAgICBidWlsZENvbnN0cnVjdEZhY3RvcnlQcm92aWRlZEF1dGhDb25maWcoXG4gICAgICAgICAgcHJvcHMuY29uc3RydWN0Q29udGFpbmVyXG4gICAgICAgICAgICAuZ2V0Q29uc3RydWN0RmFjdG9yeTxcbiAgICAgICAgICAgICAgUmVzb3VyY2VQcm92aWRlcjxBdXRoUmVzb3VyY2VzIHwgUmVmZXJlbmNlQXV0aFJlc291cmNlcz5cbiAgICAgICAgICAgID4oJ0F1dGhSZXNvdXJjZXMnKVxuICAgICAgICAgICAgPy5nZXRJbnN0YW5jZShwcm9wcyksXG4gICAgICAgICksXG4gICAgICAgIHByb3BzLFxuICAgICAgICBvdXRwdXRTdG9yYWdlU3RyYXRlZ3ksXG4gICAgICApO1xuICAgIH1cbiAgICByZXR1cm4gY29uc3RydWN0Q29udGFpbmVyLmdldE9yQ29tcHV0ZSh0aGlzLmdlbmVyYXRvcikgYXMgQW1wbGlmeURhdGE7XG4gIH07XG59XG5cbmNsYXNzIERhdGFHZW5lcmF0b3IgaW1wbGVtZW50cyBDb25zdHJ1Y3RDb250YWluZXJFbnRyeUdlbmVyYXRvciB7XG4gIHJlYWRvbmx5IHJlc291cmNlR3JvdXBOYW1lOiBBbXBsaWZ5UmVzb3VyY2VHcm91cE5hbWUgPSAnZGF0YSc7XG4gIHByaXZhdGUgcmVhZG9ubHkgbmFtZTogc3RyaW5nO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgcmVhZG9ubHkgcHJvcHM6IERhdGFQcm9wcyxcbiAgICBwcml2YXRlIHJlYWRvbmx5IHByb3ZpZGVkQXV0aENvbmZpZzogUHJvdmlkZWRBdXRoQ29uZmlnIHwgdW5kZWZpbmVkLFxuICAgIHByaXZhdGUgcmVhZG9ubHkgZ2V0SW5zdGFuY2VQcm9wczogQ29uc3RydWN0RmFjdG9yeUdldEluc3RhbmNlUHJvcHMsXG4gICAgcHJpdmF0ZSByZWFkb25seSBvdXRwdXRTdG9yYWdlU3RyYXRlZ3k6IEJhY2tlbmRPdXRwdXRTdG9yYWdlU3RyYXRlZ3k8R3JhcGhxbE91dHB1dD4sXG4gICkge1xuICAgIHRoaXMubmFtZSA9IHByb3BzLm5hbWUgPz8gZGVmYXVsdE5hbWU7XG4gIH1cblxuICBnZW5lcmF0ZUNvbnRhaW5lckVudHJ5ID0gKHtcbiAgICBzY29wZSxcbiAgICBzc21FbnZpcm9ubWVudEVudHJpZXNHZW5lcmF0b3IsXG4gICAgYmFja2VuZFNlY3JldFJlc29sdmVyLFxuICAgIHN0YWJsZUJhY2tlbmRJZGVudGlmaWVycyxcbiAgfTogR2VuZXJhdGVDb250YWluZXJFbnRyeVByb3BzKSA9PiB7XG4gICAgY29uc3QgYW1wbGlmeUdyYXBocWxEZWZpbml0aW9uczogSUFtcGxpZnlEYXRhRGVmaW5pdGlvbltdID0gW107XG4gICAgY29uc3Qgc2NoZW1hc0pzRnVuY3Rpb25zOiBKc1Jlc29sdmVyW10gPSBbXTtcbiAgICBjb25zdCBzY2hlbWFzRnVuY3Rpb25TY2hlbWFBY2Nlc3M6IEZ1bmN0aW9uU2NoZW1hQWNjZXNzW10gPSBbXTtcbiAgICBsZXQgc2NoZW1hc0xhbWJkYUZ1bmN0aW9uczogUmVjb3JkPFxuICAgICAgc3RyaW5nLFxuICAgICAgQ29uc3RydWN0RmFjdG9yeTxBbXBsaWZ5RnVuY3Rpb24+XG4gICAgPiA9IHt9O1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBzY2hlbWFzID0gaXNDb21iaW5lZFNjaGVtYSh0aGlzLnByb3BzLnNjaGVtYSlcbiAgICAgICAgPyB0aGlzLnByb3BzLnNjaGVtYS5zY2hlbWFzXG4gICAgICAgIDogW3RoaXMucHJvcHMuc2NoZW1hXTtcblxuICAgICAgY29uc3QgaXNTYW5kYm94RGVwbG95bWVudCA9XG4gICAgICAgIHNjb3BlLm5vZGUudHJ5R2V0Q29udGV4dChDREtDb250ZXh0S2V5LkRFUExPWU1FTlRfVFlQRSkgPT09ICdzYW5kYm94JztcblxuICAgICAgLy8gZ2V0IHRoZSBicmFuY2ggbmFtZSBhbmQgdXNlIHRoZSBpbXBvcnRlZCB0YWJsZSBtYXAgZm9yIHRoYXQga2V5XG4gICAgICAvLyB1c2UgdGhlIHNhbmRib3gga2V5IHdoZW4gaW4gc2FuZGJveCBkZXBsb3ltZW50XG4gICAgICBjb25zdCBhbXBsaWZ5QnJhbmNoTmFtZSA9IGlzU2FuZGJveERlcGxveW1lbnRcbiAgICAgICAgPyAnc2FuZGJveCdcbiAgICAgICAgOiBzY29wZS5ub2RlLnRyeUdldENvbnRleHQoQ0RLQ29udGV4dEtleS5CQUNLRU5EX05BTUUpO1xuICAgICAgLy8gZW5zdXJlIGFsbCBicmFuY2ggbmFtZXMgYXJlIHVuaXF1ZVxuICAgICAgaWYgKHRoaXMucHJvcHMubWlncmF0ZWRBbXBsaWZ5R2VuMUR5bmFtb0RiVGFibGVNYXBwaW5ncykge1xuICAgICAgICBjb25zdCBicmFuY2hOYW1lcyA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICAgICAgICBmb3IgKGNvbnN0IHRhYmxlTWFwIG9mIHRoaXMucHJvcHNcbiAgICAgICAgICAubWlncmF0ZWRBbXBsaWZ5R2VuMUR5bmFtb0RiVGFibGVNYXBwaW5ncykge1xuICAgICAgICAgIGlmIChicmFuY2hOYW1lcy5oYXModGFibGVNYXAuYnJhbmNoTmFtZSkpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBBbXBsaWZ5VXNlckVycm9yKCdEZWZpbmVEYXRhQ29uZmlndXJhdGlvbkVycm9yJywge1xuICAgICAgICAgICAgICBtZXNzYWdlOlxuICAgICAgICAgICAgICAgICdCcmFuY2ggbmFtZXMgbXVzdCBiZSB1bmlxdWUgaW4gdGhlIG1pZ3JhdGVkQW1wbGlmeUdlbjFEeW5hbW9EYlRhYmxlTWFwcGluZ3MnLFxuICAgICAgICAgICAgICByZXNvbHV0aW9uOiAnRW5zdXJlIGFsbCBicmFuY2ggbmFtZXMgYXJlIHVuaXF1ZScsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG4gICAgICAgICAgYnJhbmNoTmFtZXMuYWRkKHRhYmxlTWFwLmJyYW5jaE5hbWUpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHRhYmxlTWFwRm9yQ3VycmVudEJyYW5jaCA9IChcbiAgICAgICAgdGhpcy5wcm9wcy5taWdyYXRlZEFtcGxpZnlHZW4xRHluYW1vRGJUYWJsZU1hcHBpbmdzID8/IFtdXG4gICAgICApLmZpbmQoKHRhYmxlTWFwKSA9PiB0YWJsZU1hcC5icmFuY2hOYW1lID09PSBhbXBsaWZ5QnJhbmNoTmFtZSk7XG4gICAgICBjb25zdCBzcGxpdFNjaGVtYXMgPSBzcGxpdFNjaGVtYXNCeVRhYmxlTWFwKFxuICAgICAgICBzY2hlbWFzLFxuICAgICAgICB0YWJsZU1hcEZvckN1cnJlbnRCcmFuY2gsXG4gICAgICApO1xuXG4gICAgICBzcGxpdFNjaGVtYXMuZm9yRWFjaCgoeyBzY2hlbWEsIGltcG9ydGVkVGFibGVOYW1lIH0pID0+IHtcbiAgICAgICAgaWYgKGlzRGF0YVNjaGVtYShzY2hlbWEpKSB7XG4gICAgICAgICAgY29uc3QgeyBqc0Z1bmN0aW9ucywgZnVuY3Rpb25TY2hlbWFBY2Nlc3MsIGxhbWJkYUZ1bmN0aW9ucyB9ID1cbiAgICAgICAgICAgIHNjaGVtYS50cmFuc2Zvcm0oKTtcbiAgICAgICAgICBzY2hlbWFzSnNGdW5jdGlvbnMucHVzaCguLi5qc0Z1bmN0aW9ucyk7XG4gICAgICAgICAgc2NoZW1hc0Z1bmN0aW9uU2NoZW1hQWNjZXNzLnB1c2goLi4uZnVuY3Rpb25TY2hlbWFBY2Nlc3MpO1xuICAgICAgICAgIHNjaGVtYXNMYW1iZGFGdW5jdGlvbnMgPSB7XG4gICAgICAgICAgICAuLi5zY2hlbWFzTGFtYmRhRnVuY3Rpb25zLFxuICAgICAgICAgICAgLi4ubGFtYmRhRnVuY3Rpb25zLFxuICAgICAgICAgIH07XG4gICAgICAgIH1cblxuICAgICAgICBhbXBsaWZ5R3JhcGhxbERlZmluaXRpb25zLnB1c2goXG4gICAgICAgICAgY29udmVydFNjaGVtYVRvQ0RLKFxuICAgICAgICAgICAgc2NoZW1hLFxuICAgICAgICAgICAgYmFja2VuZFNlY3JldFJlc29sdmVyLFxuICAgICAgICAgICAgc3RhYmxlQmFja2VuZElkZW50aWZpZXJzLFxuICAgICAgICAgICAgaW1wb3J0ZWRUYWJsZU5hbWUsXG4gICAgICAgICAgKSxcbiAgICAgICAgKTtcbiAgICAgIH0pO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICB0aHJvdyBuZXcgQW1wbGlmeVVzZXJFcnJvcjxBbXBsaWZ5RGF0YUVycm9yPihcbiAgICAgICAgJ0ludmFsaWRTY2hlbWFFcnJvcicsXG4gICAgICAgIHtcbiAgICAgICAgICBtZXNzYWdlOlxuICAgICAgICAgICAgZXJyb3IgaW5zdGFuY2VvZiBFcnJvclxuICAgICAgICAgICAgICA/IGVycm9yLm1lc3NhZ2VcbiAgICAgICAgICAgICAgOiAnRmFpbGVkIHRvIHBhcnNlIHNjaGVtYSBkZWZpbml0aW9uLicsXG4gICAgICAgICAgcmVzb2x1dGlvbjpcbiAgICAgICAgICAgICdDaGVjayB5b3VyIGRhdGEgc2NoZW1hIGRlZmluaXRpb24gZm9yIHN5bnRheCBhbmQgdHlwZSBlcnJvcnMuJyxcbiAgICAgICAgfSxcbiAgICAgICAgZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yIDogdW5kZWZpbmVkLFxuICAgICAgKTtcbiAgICB9XG5cbiAgICBsZXQgYXV0aG9yaXphdGlvbk1vZGVzO1xuICAgIHRyeSB7XG4gICAgICBhdXRob3JpemF0aW9uTW9kZXMgPSBjb252ZXJ0QXV0aG9yaXphdGlvbk1vZGVzVG9DREsoXG4gICAgICAgIHRoaXMuZ2V0SW5zdGFuY2VQcm9wcyxcbiAgICAgICAgdGhpcy5wcm92aWRlZEF1dGhDb25maWcsXG4gICAgICAgIHRoaXMucHJvcHMuYXV0aG9yaXphdGlvbk1vZGVzLFxuICAgICAgKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgaWYgKEFtcGxpZnlFcnJvci5pc0FtcGxpZnlFcnJvcihlcnJvcikpIHtcbiAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICB9XG4gICAgICB0aHJvdyBuZXcgQW1wbGlmeVVzZXJFcnJvcjxBbXBsaWZ5RGF0YUVycm9yPihcbiAgICAgICAgJ0ludmFsaWRTY2hlbWFBdXRoRXJyb3InLFxuICAgICAgICB7XG4gICAgICAgICAgbWVzc2FnZTpcbiAgICAgICAgICAgIGVycm9yIGluc3RhbmNlb2YgRXJyb3JcbiAgICAgICAgICAgICAgPyBlcnJvci5tZXNzYWdlXG4gICAgICAgICAgICAgIDogJ0ZhaWxlZCB0byBwYXJzZSBhdXRob3JpemF0aW9uIG1vZGVzLicsXG4gICAgICAgICAgcmVzb2x1dGlvbjogJ0Vuc3VyZSB0aGUgYXV0aCBydWxlcyBvbiB5b3VyIHNjaGVtYSBhcmUgdmFsaWQuJyxcbiAgICAgICAgfSxcbiAgICAgICAgZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yIDogdW5kZWZpbmVkLFxuICAgICAgKTtcbiAgICB9XG5cbiAgICB0cnkge1xuICAgICAgdmFsaWRhdGVBdXRob3JpemF0aW9uTW9kZXMoXG4gICAgICAgIHRoaXMucHJvcHMuYXV0aG9yaXphdGlvbk1vZGVzLFxuICAgICAgICBhdXRob3JpemF0aW9uTW9kZXMsXG4gICAgICApO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICB0aHJvdyBuZXcgQW1wbGlmeVVzZXJFcnJvcjxBbXBsaWZ5RGF0YUVycm9yPihcbiAgICAgICAgJ0ludmFsaWRTY2hlbWFBdXRoRXJyb3InLFxuICAgICAgICB7XG4gICAgICAgICAgbWVzc2FnZTpcbiAgICAgICAgICAgIGVycm9yIGluc3RhbmNlb2YgRXJyb3JcbiAgICAgICAgICAgICAgPyBlcnJvci5tZXNzYWdlXG4gICAgICAgICAgICAgIDogJ0ZhaWxlZCB0byB2YWxpZGF0ZSBhdXRob3JpemF0aW9uIG1vZGVzJyxcbiAgICAgICAgICByZXNvbHV0aW9uOiAnRW5zdXJlIHRoZSBhdXRoIHJ1bGVzIG9uIHlvdXIgc2NoZW1hIGFyZSB2YWxpZC4nLFxuICAgICAgICB9LFxuICAgICAgICBlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IgOiB1bmRlZmluZWQsXG4gICAgICApO1xuICAgIH1cblxuICAgIGNvbnN0IHNhbmRib3hNb2RlRW5hYmxlZCA9IGlzVXNpbmdEZWZhdWx0QXBpS2V5QXV0aChcbiAgICAgIHRoaXMucHJvdmlkZWRBdXRoQ29uZmlnLFxuICAgICAgdGhpcy5wcm9wcy5hdXRob3JpemF0aW9uTW9kZXMsXG4gICAgKTtcblxuICAgIGNvbnN0IHByb3BzRnVuY3Rpb25zID0gdGhpcy5wcm9wcy5mdW5jdGlvbnMgPz8ge307XG5cbiAgICBjb25zdCBmdW5jdGlvbk5hbWVNYXAgPSBjb252ZXJ0RnVuY3Rpb25OYW1lTWFwVG9DREsodGhpcy5nZXRJbnN0YW5jZVByb3BzLCB7XG4gICAgICAuLi5wcm9wc0Z1bmN0aW9ucyxcbiAgICAgIC4uLnNjaGVtYXNMYW1iZGFGdW5jdGlvbnMsXG4gICAgfSk7XG4gICAgbGV0IGFtcGxpZnlBcGkgPSB1bmRlZmluZWQ7XG4gICAgbGV0IG1vZGVsSW50cm9zcGVjdGlvblNjaGVtYTogc3RyaW5nIHwgdW5kZWZpbmVkID0gdW5kZWZpbmVkO1xuXG4gICAgY29uc3QgaXNTYW5kYm94RGVwbG95bWVudCA9XG4gICAgICBzY29wZS5ub2RlLnRyeUdldENvbnRleHQoQ0RLQ29udGV4dEtleS5ERVBMT1lNRU5UX1RZUEUpID09PSAnc2FuZGJveCc7XG5cbiAgICBjb25zdCBjZGtMb2dnaW5nT3B0aW9ucyA9IGNvbnZlcnRMb2dnaW5nT3B0aW9uc1RvQ0RLKFxuICAgICAgdGhpcy5wcm9wcy5sb2dnaW5nID8/IHVuZGVmaW5lZCxcbiAgICApO1xuXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGNvbWJpbmVkU2NoZW1hID0gY29tYmluZUNES1NjaGVtYXMoYW1wbGlmeUdyYXBocWxEZWZpbml0aW9ucyk7XG4gICAgICBtb2RlbEludHJvc3BlY3Rpb25TY2hlbWEgPSBnZW5lcmF0ZU1vZGVsc1N5bmMoe1xuICAgICAgICBzY2hlbWE6IGNvbWJpbmVkU2NoZW1hLnNjaGVtYSxcbiAgICAgICAgdGFyZ2V0OiAnaW50cm9zcGVjdGlvbicsXG4gICAgICB9KVsnbW9kZWwtaW50cm9zcGVjdGlvbi5qc29uJ107XG5cbiAgICAgIGFtcGxpZnlBcGkgPSBuZXcgQW1wbGlmeURhdGEoc2NvcGUsIHRoaXMubmFtZSwge1xuICAgICAgICBhcGlOYW1lOiB0aGlzLm5hbWUsXG4gICAgICAgIGRlZmluaXRpb246IGNvbWJpbmVkU2NoZW1hLFxuICAgICAgICBhdXRob3JpemF0aW9uTW9kZXMsXG4gICAgICAgIG91dHB1dFN0b3JhZ2VTdHJhdGVneTogdGhpcy5vdXRwdXRTdG9yYWdlU3RyYXRlZ3ksXG4gICAgICAgIGZ1bmN0aW9uTmFtZU1hcCxcbiAgICAgICAgdHJhbnNsYXRpb25CZWhhdmlvcjoge1xuICAgICAgICAgIHNhbmRib3hNb2RlRW5hYmxlZCxcbiAgICAgICAgICAvKipcbiAgICAgICAgICAgKiBUaGUgZGVzdHJ1Y3RpdmUgdXBkYXRlcyBzaG91bGQgYmUgYWx3YXlzIGFsbG93ZWQgaW4gYmFja2VuZCBkZWZpbml0aW9uIGFuZCBub3QgdG8gYmUgY29udHJvbGxlZCBvbiB0aGUgSWFDXG4gICAgICAgICAgICogVGhlIENJL0NEIGNoZWNrIHNob3VsZCB0YWtlIHRoZSByZXNwb25zaWJpbGl0eSB0byB2YWxpZGF0ZSBpZiBhbnkgdGFibGVzIGFyZSBiZWluZyByZXBsYWNlZCBhbmQgZGV0ZXJtaW5lIHdoZXRoZXIgdG8gZXhlY3V0ZSB0aGUgY2hhbmdlc2V0XG4gICAgICAgICAgICovXG4gICAgICAgICAgYWxsb3dEZXN0cnVjdGl2ZUdyYXBocWxTY2hlbWFVcGRhdGVzOiB0cnVlLFxuICAgICAgICAgIF9wcm92aXNpb25Ib3Rzd2FwRnJpZW5kbHlSZXNvdXJjZXM6IGlzU2FuZGJveERlcGxveW1lbnQsXG4gICAgICAgIH0sXG4gICAgICAgIGxvZ2dpbmc6IGNka0xvZ2dpbmdPcHRpb25zLFxuICAgICAgICBzdGFja01hcHBpbmdzOiB0aGlzLnByb3BzLnN0YWNrTWFwcGluZ3MsXG4gICAgICB9KTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgdGhyb3cgbmV3IEFtcGxpZnlVc2VyRXJyb3IoXG4gICAgICAgICdBbXBsaWZ5RGF0YUNvbnN0cnVjdEluaXRpYWxpemF0aW9uRXJyb3InLFxuICAgICAgICB7XG4gICAgICAgICAgbWVzc2FnZTogJ0ZhaWxlZCB0byBpbnN0YW50aWF0ZSBkYXRhIGNvbnN0cnVjdCcsXG4gICAgICAgICAgcmVzb2x1dGlvbjogJ1NlZSB0aGUgdW5kZXJseWluZyBlcnJvciBtZXNzYWdlIGZvciBtb3JlIGRldGFpbHMuJyxcbiAgICAgICAgfSxcbiAgICAgICAgZXJyb3IgYXMgRXJyb3IsXG4gICAgICApO1xuICAgIH1cblxuICAgIGNvbnN0IG1vZGVsSW50cm9zcGVjdGlvblNjaGVtYUJ1Y2tldCA9IG5ldyBCdWNrZXQoXG4gICAgICBzY29wZSxcbiAgICAgICdtb2RlbEludHJvc3BlY3Rpb25TY2hlbWFCdWNrZXQnLFxuICAgICAge1xuICAgICAgICBlbmZvcmNlU1NMOiB0cnVlLFxuICAgICAgICBhdXRvRGVsZXRlT2JqZWN0czogdHJ1ZSxcbiAgICAgICAgcmVtb3ZhbFBvbGljeTogUmVtb3ZhbFBvbGljeS5ERVNUUk9ZLFxuICAgICAgfSxcbiAgICApO1xuICAgIG5ldyBCdWNrZXREZXBsb3ltZW50KHNjb3BlLCAnbW9kZWxJbnRyb3NwZWN0aW9uU2NoZW1hQnVja2V0RGVwbG95bWVudCcsIHtcbiAgICAgIC8vIFNlZSBodHRwczovL2dpdGh1Yi5jb20vYXdzLWFtcGxpZnkvYW1wbGlmeS1jYXRlZ29yeS1hcGkvcHVsbC8xOTM5XG4gICAgICBtZW1vcnlMaW1pdDogMTUzNixcbiAgICAgIGRlc3RpbmF0aW9uQnVja2V0OiBtb2RlbEludHJvc3BlY3Rpb25TY2hlbWFCdWNrZXQsXG4gICAgICBzb3VyY2VzOiBbXG4gICAgICAgIFNvdXJjZS5kYXRhKG1vZGVsSW50cm9zcGVjdGlvblNjaGVtYUtleSwgbW9kZWxJbnRyb3NwZWN0aW9uU2NoZW1hKSxcbiAgICAgIF0sXG4gICAgfSk7XG5cbiAgICBUYWdzLm9mKGFtcGxpZnlBcGkpLmFkZChUYWdOYW1lLkZSSUVORExZX05BTUUsIHRoaXMubmFtZSk7XG5cbiAgICAvKio7XG4gICAgICogRW5hYmxlIHRoZSB0YWJsZSByZXBsYWNlbWVudCB1cG9uIEdTSSB1cGRhdGVcbiAgICAgKiBUaGlzIGlzIGFsbG93ZWQgaW4gc2FuZGJveCBtb2RlIE9OTFlcbiAgICAgKi9cbiAgICBpZiAoaXNTYW5kYm94RGVwbG95bWVudCkge1xuICAgICAgQXNwZWN0cy5vZihhbXBsaWZ5QXBpKS5hZGQobmV3IFJlcGxhY2VUYWJsZVVwb25Hc2lVcGRhdGVPdmVycmlkZUFzcGVjdCgpKTtcbiAgICB9XG5cbiAgICBjb252ZXJ0SnNSZXNvbHZlckRlZmluaXRpb24oc2NvcGUsIGFtcGxpZnlBcGksIHNjaGVtYXNKc0Z1bmN0aW9ucyk7XG5cbiAgICBjb25zdCBuYW1lUHJlZml4ID0gdGhpcy5uYW1lID09PSBkZWZhdWx0TmFtZSA/ICcnIDogZGVmYXVsdE5hbWU7XG5cbiAgICBjb25zdCBzc21FbnZpcm9ubWVudFNjb3BlQ29udGV4dCA9IHtcbiAgICAgIFtgJHtuYW1lUHJlZml4fSR7dGhpcy5uYW1lfV9HUkFQSFFMX0VORFBPSU5UYF06XG4gICAgICAgIGFtcGxpZnlBcGkucmVzb3VyY2VzLmNmblJlc291cmNlcy5jZm5HcmFwaHFsQXBpLmF0dHJHcmFwaFFsVXJsLFxuICAgICAgW2Ake25hbWVQcmVmaXh9JHt0aGlzLm5hbWV9X01PREVMX0lOVFJPU1BFQ1RJT05fU0NIRU1BX0JVQ0tFVF9OQU1FYF06XG4gICAgICAgIG1vZGVsSW50cm9zcGVjdGlvblNjaGVtYUJ1Y2tldC5idWNrZXROYW1lLFxuICAgICAgW2Ake25hbWVQcmVmaXh9JHt0aGlzLm5hbWV9X01PREVMX0lOVFJPU1BFQ1RJT05fU0NIRU1BX0tFWWBdOlxuICAgICAgICBtb2RlbEludHJvc3BlY3Rpb25TY2hlbWFLZXksXG4gICAgICBbJ0FNUExJRllfREFUQV9ERUZBVUxUX05BTUUnXTogYCR7bmFtZVByZWZpeH0ke3RoaXMubmFtZX1gLFxuICAgIH07XG5cbiAgICBjb25zdCBiYWNrd2FyZHNDb21wYXRpYmxlU2NvcGVDb250ZXh0ID1cbiAgICAgIGAke3RoaXMubmFtZX1fR1JBUEhRTF9FTkRQT0lOVGAgIT09XG4gICAgICBgJHtuYW1lUHJlZml4fSR7dGhpcy5uYW1lfV9HUkFQSFFMX0VORFBPSU5UYFxuICAgICAgICA/IHtcbiAgICAgICAgICAgIC8vIEBkZXByZWNhdGVkXG4gICAgICAgICAgICBbYCR7dGhpcy5uYW1lfV9HUkFQSFFMX0VORFBPSU5UYF06XG4gICAgICAgICAgICAgIGFtcGxpZnlBcGkucmVzb3VyY2VzLmNmblJlc291cmNlcy5jZm5HcmFwaHFsQXBpLmF0dHJHcmFwaFFsVXJsLFxuICAgICAgICAgIH1cbiAgICAgICAgOiB7fTtcblxuICAgIGNvbnN0IHNzbUVudmlyb25tZW50RW50cmllcyA9XG4gICAgICBzc21FbnZpcm9ubWVudEVudHJpZXNHZW5lcmF0b3IuZ2VuZXJhdGVTc21FbnZpcm9ubWVudEVudHJpZXMoe1xuICAgICAgICAuLi5zc21FbnZpcm9ubWVudFNjb3BlQ29udGV4dCxcbiAgICAgICAgLi4uYmFja3dhcmRzQ29tcGF0aWJsZVNjb3BlQ29udGV4dCxcbiAgICAgIH0pO1xuXG4gICAgY29uc3QgcG9saWN5R2VuZXJhdG9yID0gbmV3IEFwcFN5bmNQb2xpY3lHZW5lcmF0b3IoXG4gICAgICBhbXBsaWZ5QXBpLnJlc291cmNlcy5ncmFwaHFsQXBpLFxuICAgICAgYCR7bW9kZWxJbnRyb3NwZWN0aW9uU2NoZW1hQnVja2V0LmJ1Y2tldEFybn0vJHttb2RlbEludHJvc3BlY3Rpb25TY2hlbWFLZXl9YCxcbiAgICApO1xuXG4gICAgc2NoZW1hc0Z1bmN0aW9uU2NoZW1hQWNjZXNzLmZvckVhY2goKGFjY2Vzc0RlZmluaXRpb24pID0+IHtcbiAgICAgIGNvbnN0IHBvbGljeSA9IHBvbGljeUdlbmVyYXRvci5nZW5lcmF0ZUdyYXBocWxBY2Nlc3NQb2xpY3koXG4gICAgICAgIGFjY2Vzc0RlZmluaXRpb24uYWN0aW9ucyxcbiAgICAgICk7XG4gICAgICBhY2Nlc3NEZWZpbml0aW9uLnJlc291cmNlUHJvdmlkZXJcbiAgICAgICAgLmdldEluc3RhbmNlKHRoaXMuZ2V0SW5zdGFuY2VQcm9wcylcbiAgICAgICAgLmdldFJlc291cmNlQWNjZXNzQWNjZXB0b3IoKVxuICAgICAgICAuYWNjZXB0UmVzb3VyY2VBY2Nlc3MocG9saWN5LCBzc21FbnZpcm9ubWVudEVudHJpZXMpO1xuICAgIH0pO1xuXG4gICAgcmV0dXJuIGFtcGxpZnlBcGk7XG4gIH07XG59XG5cbmNvbnN0IFJFUExBQ0VfVEFCTEVfVVBPTl9HU0lfVVBEQVRFX0FUVFJJQlVURV9OQU1FOiBrZXlvZiBUcmFuc2xhdGlvbkJlaGF2aW9yID1cbiAgJ3JlcGxhY2VUYWJsZVVwb25Hc2lVcGRhdGUnO1xuXG4vKipcbiAqIEFzcGVjdCBjbGFzcyB0byBtb2RpZnkgdGhlIGFtcGxpZnkgbWFuYWdlZCBEeW5hbW9EQiB0YWJsZVxuICogdG8gYWxsb3cgdGFibGUgcmVwbGFjZW1lbnQgdXBvbiBHU0kgdXBkYXRlXG4gKi9cbmNsYXNzIFJlcGxhY2VUYWJsZVVwb25Hc2lVcGRhdGVPdmVycmlkZUFzcGVjdCBpbXBsZW1lbnRzIElBc3BlY3Qge1xuICBwdWJsaWMgdmlzaXQoc2NvcGU6IElDb25zdHJ1Y3QpOiB2b2lkIHtcbiAgICBpZiAoQW1wbGlmeUR5bmFtb0RiVGFibGVXcmFwcGVyLmlzQW1wbGlmeUR5bmFtb0RiVGFibGVSZXNvdXJjZShzY29wZSkpIHtcbiAgICAgIC8vIFRoZXNlIHZhbHVlIHNldHRlcnMgYXJlIG5vdCBleHBvc2VkIGluIHRoZSB3cmFwcGVyXG4gICAgICAvLyBOZWVkIHRvIHVzZSB0aGUgcHJvcGVydHkgb3ZlcnJpZGUgdG8gZXNjYXBlIHRoZSBoYXRjaFxuICAgICAgc2NvcGUuYWRkUHJvcGVydHlPdmVycmlkZShcbiAgICAgICAgUkVQTEFDRV9UQUJMRV9VUE9OX0dTSV9VUERBVEVfQVRUUklCVVRFX05BTUUsXG4gICAgICAgIHRydWUsXG4gICAgICApO1xuICAgIH1cbiAgfVxufVxuXG4vKipcbiAqIENyZWF0ZXMgYSBmYWN0b3J5IHRoYXQgaW1wbGVtZW50cyBDb25zdHJ1Y3RGYWN0b3J5PEFtcGxpZnlHcmFwaHFsQXBpPlxuICovXG5leHBvcnQgY29uc3QgZGVmaW5lRGF0YSA9IChwcm9wczogRGF0YVByb3BzKTogQ29uc3RydWN0RmFjdG9yeTxBbXBsaWZ5RGF0YT4gPT5cbiAgbmV3IERhdGFGYWN0b3J5KHByb3BzLCBuZXcgRXJyb3IoKS5zdGFjayk7XG4iXX0=