@fjall/components-infrastructure 0.89.5 → 0.94.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/LICENSE +50 -21
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -18
- package/dist/lib/app.d.ts +12 -12
- package/dist/lib/app.js +61 -56
- package/dist/lib/aspects/index.d.ts +1 -1
- package/dist/lib/aspects/index.js +1 -6
- package/dist/lib/aspects/resourceInventory.js +6 -13
- package/dist/lib/config/audit.js +1 -5
- package/dist/lib/config/aws/accessAnalyser.d.ts +11 -0
- package/dist/lib/config/aws/accessAnalyser.js +17 -0
- package/dist/lib/config/aws/accountAuditRole.js +11 -15
- package/dist/lib/config/aws/accountMonitoringRole.js +25 -29
- package/dist/lib/config/aws/alarmTopic.d.ts +8 -0
- package/dist/lib/config/aws/alarmTopic.js +19 -0
- package/dist/lib/config/aws/cloudTrail.js +4 -9
- package/dist/lib/config/aws/configRecorder.d.ts +16 -0
- package/dist/lib/config/aws/configRecorder.js +51 -0
- package/dist/lib/config/aws/configRulePreset.d.ts +13 -0
- package/dist/lib/config/aws/configRulePreset.js +62 -0
- package/dist/lib/config/aws/disasterRecovery.d.ts +1 -1
- package/dist/lib/config/aws/disasterRecovery.js +56 -73
- package/dist/lib/config/aws/ebsDefaultEncryption.d.ts +8 -0
- package/dist/lib/config/aws/ebsDefaultEncryption.js +41 -0
- package/dist/lib/config/aws/ecrDefaultImage.js +25 -30
- package/dist/lib/config/aws/eventBus.js +8 -11
- package/dist/lib/config/aws/guardDutyDetector.d.ts +16 -0
- package/dist/lib/config/aws/guardDutyDetector.js +26 -0
- package/dist/lib/config/aws/identityCenter.d.ts +1 -1
- package/dist/lib/config/aws/identityCenter.js +23 -25
- package/dist/lib/config/aws/identityCenterGroupMembership.js +18 -22
- package/dist/lib/config/aws/index.d.ts +19 -8
- package/dist/lib/config/aws/index.js +19 -25
- package/dist/lib/config/aws/inspectorEnablement.d.ts +9 -0
- package/dist/lib/config/aws/inspectorEnablement.js +51 -0
- package/dist/lib/config/aws/ipam.js +9 -13
- package/dist/lib/config/aws/oidcConnector.js +8 -12
- package/dist/lib/config/aws/platform.js +1 -5
- package/dist/lib/config/aws/s3BlockPublicAccess.d.ts +9 -0
- package/dist/lib/config/aws/s3BlockPublicAccess.js +55 -0
- package/dist/lib/config/aws/scpPreset.d.ts +21 -0
- package/dist/lib/config/aws/scpPreset.js +311 -0
- package/dist/lib/config/aws/securityBaseline.d.ts +15 -0
- package/dist/lib/config/aws/securityBaseline.js +27 -0
- package/dist/lib/config/aws/securityHubHub.d.ts +15 -0
- package/dist/lib/config/aws/securityHubHub.js +28 -0
- package/dist/lib/config/aws/securityServicesAdmin.d.ts +20 -0
- package/dist/lib/config/aws/securityServicesAdmin.js +115 -0
- package/dist/lib/config/index.d.ts +2 -2
- package/dist/lib/config/index.js +2 -21
- package/dist/lib/index.d.ts +4 -4
- package/dist/lib/index.js +5 -26
- package/dist/lib/patterns/aws/account.d.ts +17 -1
- package/dist/lib/patterns/aws/account.js +60 -33
- package/dist/lib/patterns/aws/apexDomainPattern.d.ts +26 -0
- package/dist/lib/patterns/aws/apexDomainPattern.js +91 -0
- package/dist/lib/patterns/aws/auditRole.js +13 -16
- package/dist/lib/patterns/aws/buildkite.d.ts +1 -1
- package/dist/lib/patterns/aws/buildkite.js +70 -75
- package/dist/lib/patterns/aws/cdn.d.ts +5 -5
- package/dist/lib/patterns/aws/cdn.js +22 -28
- package/dist/lib/patterns/aws/compute.d.ts +1 -1
- package/dist/lib/patterns/aws/compute.js +31 -44
- package/dist/lib/patterns/aws/computeEc2.d.ts +1 -1
- package/dist/lib/patterns/aws/computeEc2.js +11 -14
- package/dist/lib/patterns/aws/computeEcs.d.ts +18 -2
- package/dist/lib/patterns/aws/computeEcs.js +41 -31
- package/dist/lib/patterns/aws/computeLambda.d.ts +2 -2
- package/dist/lib/patterns/aws/computeLambda.js +24 -31
- package/dist/lib/patterns/aws/database.d.ts +16 -7
- package/dist/lib/patterns/aws/database.js +81 -73
- package/dist/lib/patterns/aws/delegatedDomainPattern.d.ts +17 -0
- package/dist/lib/patterns/aws/delegatedDomainPattern.js +54 -0
- package/dist/lib/patterns/aws/dnsRecordComposer.d.ts +25 -0
- package/dist/lib/patterns/aws/dnsRecordComposer.js +225 -0
- package/dist/lib/patterns/aws/domain.d.ts +32 -0
- package/dist/lib/patterns/aws/domain.js +115 -0
- package/dist/lib/patterns/aws/domainDelegation.d.ts +3 -3
- package/dist/lib/patterns/aws/domainDelegation.js +28 -37
- package/dist/lib/patterns/aws/domainFactory.d.ts +20 -5
- package/dist/lib/patterns/aws/domainFactory.js +48 -10
- package/dist/lib/patterns/aws/domainValidation.d.ts +11 -0
- package/dist/lib/patterns/aws/domainValidation.js +145 -0
- package/dist/lib/patterns/aws/externalRecordsPattern.d.ts +18 -0
- package/dist/lib/patterns/aws/externalRecordsPattern.js +141 -0
- package/dist/lib/patterns/aws/fivetranProxy.d.ts +1 -1
- package/dist/lib/patterns/aws/fivetranProxy.js +6 -11
- package/dist/lib/patterns/aws/index.d.ts +21 -19
- package/dist/lib/patterns/aws/index.js +25 -36
- package/dist/lib/patterns/aws/interfaces/cdn.js +1 -5
- package/dist/lib/patterns/aws/interfaces/compute.js +4 -11
- package/dist/lib/patterns/aws/interfaces/connector.js +1 -15
- package/dist/lib/patterns/aws/interfaces/database.d.ts +1 -1
- package/dist/lib/patterns/aws/interfaces/database.js +6 -15
- package/dist/lib/patterns/aws/interfaces/domain.d.ts +80 -2
- package/dist/lib/patterns/aws/interfaces/domain.js +1 -6
- package/dist/lib/patterns/aws/interfaces/index.js +8 -41
- package/dist/lib/patterns/aws/interfaces/messaging.js +4 -11
- package/dist/lib/patterns/aws/interfaces/organisation.d.ts +1 -1
- package/dist/lib/patterns/aws/interfaces/organisation.js +4 -11
- package/dist/lib/patterns/aws/interfaces/pattern.js +2 -7
- package/dist/lib/patterns/aws/interfaces/storage.js +1 -5
- package/dist/lib/patterns/aws/managedIdentityCenter.js +7 -12
- package/dist/lib/patterns/aws/messaging.d.ts +7 -7
- package/dist/lib/patterns/aws/messaging.js +22 -33
- package/dist/lib/patterns/aws/network.d.ts +2 -2
- package/dist/lib/patterns/aws/network.js +9 -14
- package/dist/lib/patterns/aws/organisation.d.ts +6 -2
- package/dist/lib/patterns/aws/organisation.js +34 -35
- package/dist/lib/patterns/aws/organisationFactory.d.ts +3 -3
- package/dist/lib/patterns/aws/organisationFactory.js +7 -12
- package/dist/lib/patterns/aws/pattern.js +6 -12
- package/dist/lib/patterns/aws/payload.js +73 -63
- package/dist/lib/patterns/aws/platform.d.ts +6 -3
- package/dist/lib/patterns/aws/platform.js +15 -15
- package/dist/lib/patterns/aws/storage.d.ts +6 -4
- package/dist/lib/patterns/aws/storage.js +35 -40
- package/dist/lib/patterns/aws/subdomainHostedZone.js +11 -16
- package/dist/lib/patterns/aws/targets/fjallTargets.d.ts +37 -0
- package/dist/lib/patterns/aws/targets/fjallTargets.js +66 -0
- package/dist/lib/patterns/aws/targets/index.d.ts +2 -0
- package/dist/lib/patterns/aws/targets/index.js +2 -0
- package/dist/lib/patterns/aws/targets/targetResolution.d.ts +76 -0
- package/dist/lib/patterns/aws/targets/targetResolution.js +119 -0
- package/dist/lib/patterns/index.d.ts +1 -0
- package/dist/lib/patterns/index.js +1 -0
- package/dist/lib/resources/aws/analytics/clickhouse.d.ts +15 -0
- package/dist/lib/resources/aws/analytics/clickhouse.js +292 -0
- package/dist/lib/resources/aws/analytics/clickhouseConstants.d.ts +73 -0
- package/dist/lib/resources/aws/analytics/clickhouseConstants.js +87 -0
- package/dist/lib/resources/aws/analytics/clickhouseSecurityGroup.d.ts +13 -0
- package/dist/lib/resources/aws/analytics/clickhouseSecurityGroup.js +28 -0
- package/dist/lib/resources/aws/analytics/clickhouseTypes.d.ts +47 -0
- package/dist/lib/resources/aws/analytics/clickhouseTypes.js +1 -0
- package/dist/lib/resources/aws/analytics/clickhouseUserData.d.ts +5 -0
- package/dist/lib/resources/aws/analytics/clickhouseUserData.js +248 -0
- package/dist/lib/resources/aws/analytics/index.d.ts +2 -0
- package/dist/lib/resources/aws/analytics/index.js +1 -0
- package/dist/lib/resources/aws/audit/auditRole.js +10 -15
- package/dist/lib/resources/aws/audit/index.d.ts +1 -1
- package/dist/lib/resources/aws/audit/index.js +1 -6
- package/dist/lib/resources/aws/backup/backupPlan.d.ts +1 -1
- package/dist/lib/resources/aws/backup/backupPlan.js +14 -16
- package/dist/lib/resources/aws/backup/backupVault.d.ts +1 -1
- package/dist/lib/resources/aws/backup/backupVault.js +13 -15
- package/dist/lib/resources/aws/backup/index.d.ts +2 -2
- package/dist/lib/resources/aws/backup/index.js +2 -19
- package/dist/lib/resources/aws/base/awsStack.js +17 -19
- package/dist/lib/resources/aws/base/index.d.ts +1 -1
- package/dist/lib/resources/aws/base/index.js +1 -18
- package/dist/lib/resources/aws/cdn/cloudFront.js +40 -42
- package/dist/lib/resources/aws/cdn/index.d.ts +1 -1
- package/dist/lib/resources/aws/cdn/index.js +1 -18
- package/dist/lib/resources/aws/compute/ec2.js +39 -39
- package/dist/lib/resources/aws/compute/ecs.d.ts +18 -396
- package/dist/lib/resources/aws/compute/ecs.js +105 -976
- package/dist/lib/resources/aws/compute/ecsCapacityProviderAspect.d.ts +22 -0
- package/dist/lib/resources/aws/compute/ecsCapacityProviderAspect.js +35 -0
- package/dist/lib/resources/aws/compute/ecsConstants.d.ts +20 -0
- package/dist/lib/resources/aws/compute/ecsConstants.js +49 -0
- package/dist/lib/resources/aws/compute/ecsContext.d.ts +12 -0
- package/dist/lib/resources/aws/compute/ecsContext.js +1 -0
- package/dist/lib/resources/aws/compute/ecsImages.d.ts +4 -0
- package/dist/lib/resources/aws/compute/ecsImages.js +35 -0
- package/dist/lib/resources/aws/compute/ecsNetworking.d.ts +28 -0
- package/dist/lib/resources/aws/compute/ecsNetworking.js +290 -0
- package/dist/lib/resources/aws/compute/ecsRoles.d.ts +15 -0
- package/dist/lib/resources/aws/compute/ecsRoles.js +110 -0
- package/dist/lib/resources/aws/compute/ecsServiceFactory.d.ts +33 -0
- package/dist/lib/resources/aws/compute/ecsServiceFactory.js +183 -0
- package/dist/lib/resources/aws/compute/ecsTaskDefinition.d.ts +30 -0
- package/dist/lib/resources/aws/compute/ecsTaskDefinition.js +168 -0
- package/dist/lib/resources/aws/compute/ecsTypes.d.ts +337 -0
- package/dist/lib/resources/aws/compute/ecsTypes.js +10 -0
- package/dist/lib/resources/aws/compute/ecsValidation.d.ts +18 -0
- package/dist/lib/resources/aws/compute/ecsValidation.js +72 -0
- package/dist/lib/resources/aws/compute/index.d.ts +3 -3
- package/dist/lib/resources/aws/compute/index.js +3 -20
- package/dist/lib/resources/aws/compute/lambda.d.ts +10 -2
- package/dist/lib/resources/aws/compute/lambda.js +81 -71
- package/dist/lib/resources/aws/database/dynamodb.js +24 -27
- package/dist/lib/resources/aws/database/index.d.ts +7 -7
- package/dist/lib/resources/aws/database/index.js +14 -33
- package/dist/lib/resources/aws/database/rdsAurora.d.ts +10 -2
- package/dist/lib/resources/aws/database/rdsAurora.js +76 -61
- package/dist/lib/resources/aws/database/rdsAuroraGlobal.d.ts +2 -2
- package/dist/lib/resources/aws/database/rdsAuroraGlobal.js +24 -21
- package/dist/lib/resources/aws/database/rdsDefaults.js +3 -7
- package/dist/lib/resources/aws/database/rdsHelpers.d.ts +2 -2
- package/dist/lib/resources/aws/database/rdsHelpers.js +21 -29
- package/dist/lib/resources/aws/database/rdsInstance.d.ts +11 -3
- package/dist/lib/resources/aws/database/rdsInstance.js +101 -83
- package/dist/lib/resources/aws/database/rdsProxyOutput.js +5 -9
- package/dist/lib/resources/aws/iam/delegationRole.d.ts +18 -0
- package/dist/lib/resources/aws/iam/delegationRole.js +60 -0
- package/dist/lib/resources/aws/iam/identityCenter/assignment.js +4 -9
- package/dist/lib/resources/aws/iam/identityCenter/group.js +5 -9
- package/dist/lib/resources/aws/iam/identityCenter/index.d.ts +3 -3
- package/dist/lib/resources/aws/iam/identityCenter/index.js +3 -20
- package/dist/lib/resources/aws/iam/identityCenter/permissionSet.d.ts +1 -1
- package/dist/lib/resources/aws/iam/identityCenter/permissionSet.js +5 -9
- package/dist/lib/resources/aws/iam/index.d.ts +5 -4
- package/dist/lib/resources/aws/iam/index.js +5 -21
- package/dist/lib/resources/aws/iam/instanceProfile.js +2 -7
- package/dist/lib/resources/aws/iam/managedPolicy.js +2 -7
- package/dist/lib/resources/aws/iam/policy.js +2 -7
- package/dist/lib/resources/aws/iam/role.js +2 -7
- package/dist/lib/resources/aws/index.d.ts +7 -7
- package/dist/lib/resources/aws/index.js +7 -24
- package/dist/lib/resources/aws/logging/cloudTrail.d.ts +1 -1
- package/dist/lib/resources/aws/logging/cloudTrail.js +18 -22
- package/dist/lib/resources/aws/logging/index.d.ts +2 -2
- package/dist/lib/resources/aws/logging/index.js +2 -19
- package/dist/lib/resources/aws/logging/logGroup.js +4 -10
- package/dist/lib/resources/aws/messaging/eventbridge.js +11 -14
- package/dist/lib/resources/aws/messaging/index.d.ts +4 -4
- package/dist/lib/resources/aws/messaging/index.js +4 -21
- package/dist/lib/resources/aws/messaging/sns.js +11 -14
- package/dist/lib/resources/aws/messaging/sqs.js +32 -34
- package/dist/lib/resources/aws/messaging/utils.d.ts +1 -1
- package/dist/lib/resources/aws/messaging/utils.js +1 -6
- package/dist/lib/resources/aws/monitoring/alarmDefaults.d.ts +36 -0
- package/dist/lib/resources/aws/monitoring/alarmDefaults.js +34 -0
- package/dist/lib/resources/aws/monitoring/ecsAlarms.d.ts +21 -0
- package/dist/lib/resources/aws/monitoring/ecsAlarms.js +88 -0
- package/dist/lib/resources/aws/monitoring/index.d.ts +4 -0
- package/dist/lib/resources/aws/monitoring/index.js +4 -5
- package/dist/lib/resources/aws/monitoring/lambdaAlarms.d.ts +18 -0
- package/dist/lib/resources/aws/monitoring/lambdaAlarms.js +44 -0
- package/dist/lib/resources/aws/monitoring/rdsAlarms.d.ts +20 -0
- package/dist/lib/resources/aws/monitoring/rdsAlarms.js +52 -0
- package/dist/lib/resources/aws/networking/crossAccountDelegationRecord.d.ts +17 -0
- package/dist/lib/resources/aws/networking/crossAccountDelegationRecord.js +26 -0
- package/dist/lib/resources/aws/networking/dnsRecord/aRecord.d.ts +12 -0
- package/dist/lib/resources/aws/networking/dnsRecord/aRecord.js +21 -0
- package/dist/lib/resources/aws/networking/dnsRecord/aaaaRecord.d.ts +12 -0
- package/dist/lib/resources/aws/networking/dnsRecord/aaaaRecord.js +22 -0
- package/dist/lib/resources/aws/networking/dnsRecord/aliasRecord.d.ts +12 -0
- package/dist/lib/resources/aws/networking/dnsRecord/aliasRecord.js +23 -0
- package/dist/lib/resources/aws/networking/dnsRecord/caaRecord.d.ts +17 -0
- package/dist/lib/resources/aws/networking/dnsRecord/caaRecord.js +21 -0
- package/dist/lib/resources/aws/networking/dnsRecord/cnameRecord.d.ts +12 -0
- package/dist/lib/resources/aws/networking/dnsRecord/cnameRecord.js +22 -0
- package/dist/lib/resources/aws/networking/dnsRecord/dnsRecordBase.d.ts +17 -0
- package/dist/lib/resources/aws/networking/dnsRecord/dnsRecordBase.js +17 -0
- package/dist/lib/resources/aws/networking/dnsRecord/index.d.ts +10 -0
- package/dist/lib/resources/aws/networking/dnsRecord/index.js +10 -0
- package/dist/lib/resources/aws/networking/dnsRecord/mxRecord.d.ts +16 -0
- package/dist/lib/resources/aws/networking/dnsRecord/mxRecord.js +21 -0
- package/dist/lib/resources/aws/networking/dnsRecord/nsRecord.d.ts +12 -0
- package/dist/lib/resources/aws/networking/dnsRecord/nsRecord.js +21 -0
- package/dist/lib/resources/aws/networking/dnsRecord/srvRecord.d.ts +18 -0
- package/dist/lib/resources/aws/networking/dnsRecord/srvRecord.js +21 -0
- package/dist/lib/resources/aws/networking/dnsRecord/txtRecord.d.ts +12 -0
- package/dist/lib/resources/aws/networking/dnsRecord/txtRecord.js +21 -0
- package/dist/lib/resources/aws/networking/domain.d.ts +1 -1
- package/dist/lib/resources/aws/networking/domain.js +32 -34
- package/dist/lib/resources/aws/networking/domainCertificate.d.ts +8 -3
- package/dist/lib/resources/aws/networking/domainCertificate.js +22 -16
- package/dist/lib/resources/aws/networking/hostedZone.d.ts +23 -19
- package/dist/lib/resources/aws/networking/hostedZone.js +70 -134
- package/dist/lib/resources/aws/networking/index.d.ts +8 -7
- package/dist/lib/resources/aws/networking/index.js +8 -24
- package/dist/lib/resources/aws/networking/ipam.js +2 -7
- package/dist/lib/resources/aws/networking/ipamPool.d.ts +1 -1
- package/dist/lib/resources/aws/networking/ipamPool.js +45 -55
- package/dist/lib/resources/aws/networking/securityGroup.js +2 -7
- package/dist/lib/resources/aws/networking/vpc.d.ts +1 -1
- package/dist/lib/resources/aws/networking/vpc.js +17 -21
- package/dist/lib/resources/aws/organisation/costAllocationTagActivator.d.ts +1 -1
- package/dist/lib/resources/aws/organisation/costAllocationTagActivator.js +11 -15
- package/dist/lib/resources/aws/organisation/index.d.ts +5 -5
- package/dist/lib/resources/aws/organisation/index.js +4 -12
- package/dist/lib/resources/aws/organisation/organisation.js +5 -7
- package/dist/lib/resources/aws/organisation/organisationAccount.js +7 -10
- package/dist/lib/resources/aws/organisation/organisationPolicy.js +5 -9
- package/dist/lib/resources/aws/organisation/organisationalUnit.js +1 -3
- package/dist/lib/resources/aws/secrets/alias.js +2 -7
- package/dist/lib/resources/aws/secrets/index.d.ts +4 -4
- package/dist/lib/resources/aws/secrets/index.js +4 -21
- package/dist/lib/resources/aws/secrets/kms.js +15 -18
- package/dist/lib/resources/aws/secrets/parameter.d.ts +3 -3
- package/dist/lib/resources/aws/secrets/parameter.js +19 -22
- package/dist/lib/resources/aws/secrets/secret.d.ts +2 -2
- package/dist/lib/resources/aws/secrets/secret.js +12 -14
- package/dist/lib/resources/aws/storage/ecr.d.ts +2 -2
- package/dist/lib/resources/aws/storage/ecr.js +7 -13
- package/dist/lib/resources/aws/storage/index.d.ts +2 -2
- package/dist/lib/resources/aws/storage/index.js +2 -19
- package/dist/lib/resources/aws/storage/s3.d.ts +1 -1
- package/dist/lib/resources/aws/storage/s3.js +24 -12
- package/dist/lib/resources/aws/utilities/awsCustomResource.js +3 -7
- package/dist/lib/resources/aws/utilities/codeBuild.js +7 -12
- package/dist/lib/resources/aws/utilities/customResource.js +14 -17
- package/dist/lib/resources/aws/utilities/customResourceProvider.js +2 -7
- package/dist/lib/resources/aws/utilities/index.d.ts +5 -5
- package/dist/lib/resources/aws/utilities/index.js +5 -22
- package/dist/lib/resources/aws/utilities/resourceShare.js +2 -7
- package/dist/lib/resources/index.d.ts +1 -1
- package/dist/lib/resources/index.js +1 -18
- package/dist/lib/types.js +1 -3
- package/dist/lib/utils/accountsUtils.d.ts +5 -0
- package/dist/lib/utils/accountsUtils.js +18 -0
- package/dist/lib/utils/addSuffixToEmail.js +1 -5
- package/dist/lib/utils/backupTierMapping.js +2 -6
- package/dist/lib/utils/capitaliseString.js +1 -10
- package/dist/lib/utils/connections.js +9 -13
- package/dist/lib/utils/connector.js +10 -23
- package/dist/lib/utils/constructMap.d.ts +33 -0
- package/dist/lib/utils/constructMap.js +154 -0
- package/dist/lib/utils/databaseTypes.js +4 -10
- package/dist/lib/utils/dnsRecords.d.ts +1 -1
- package/dist/lib/utils/dnsRecords.js +23 -27
- package/dist/lib/utils/domainTypes.d.ts +0 -1
- package/dist/lib/utils/domainTypes.js +2 -10
- package/dist/lib/utils/env.js +14 -26
- package/dist/lib/utils/getAccountId.js +3 -7
- package/dist/lib/utils/getAsync.js +7 -10
- package/dist/lib/utils/getConfig.d.ts +0 -2
- package/dist/lib/utils/getConfig.js +29 -47
- package/dist/lib/utils/getStackOutput.js +4 -8
- package/dist/lib/utils/index.d.ts +12 -12
- package/dist/lib/utils/index.js +12 -29
- package/dist/lib/utils/manifestWriter.d.ts +14 -3
- package/dist/lib/utils/manifestWriter.js +60 -43
- package/dist/lib/utils/orgConfigParser.d.ts +14 -0
- package/dist/lib/utils/orgConfigParser.js +49 -0
- package/dist/lib/utils/removalPolicy.js +5 -9
- package/dist/lib/utils/resourceNaming.js +11 -16
- package/dist/lib/utils/standardTagsAspect.js +9 -16
- package/dist/lib/utils/stripAndCamelCase.js +1 -5
- package/dist/lib/utils/validationLogger.js +12 -18
- package/dist/lib/utils/vpcUtils.js +5 -10
- package/package.json +25 -8
- package/dist/lib/config/aws/accountId.d.ts +0 -6
- package/dist/lib/config/aws/accountId.js +0 -32
- package/dist/lib/config/aws/backupGlobalSettings.d.ts +0 -29
- package/dist/lib/config/aws/backupGlobalSettings.js +0 -49
- package/dist/lib/config/aws/costAllocationTags.d.ts +0 -12
- package/dist/lib/config/aws/costAllocationTags.js +0 -47
- package/dist/lib/config/aws/ipamDelegateAdmin.d.ts +0 -8
- package/dist/lib/config/aws/ipamDelegateAdmin.js +0 -57
- package/dist/lib/config/aws/ipamPoolId.d.ts +0 -16
- package/dist/lib/config/aws/ipamPoolId.js +0 -42
- package/dist/lib/config/aws/organisation.d.ts +0 -30
- package/dist/lib/config/aws/organisation.js +0 -92
- package/dist/lib/config/aws/organisationId.d.ts +0 -7
- package/dist/lib/config/aws/organisationId.js +0 -45
- package/dist/lib/config/aws/organisationsAccess.d.ts +0 -10
- package/dist/lib/config/aws/organisationsAccess.js +0 -49
- package/dist/lib/config/aws/ramSharing.d.ts +0 -4
- package/dist/lib/config/aws/ramSharing.js +0 -34
- package/dist/lib/config/monitoring.d.ts +0 -18
- package/dist/lib/config/monitoring.js +0 -22
- package/dist/lib/patterns/aws/connections.d.ts +0 -46
- package/dist/lib/patterns/aws/connections.js +0 -159
- package/dist/lib/patterns/aws/hostedZone.d.ts +0 -28
- package/dist/lib/patterns/aws/hostedZone.js +0 -150
- package/dist/lib/patterns/aws/managedAccount.d.ts +0 -9
- package/dist/lib/patterns/aws/managedAccount.js +0 -55
- package/dist/lib/patterns/aws/managedOrganisation.d.ts +0 -36
- package/dist/lib/patterns/aws/managedOrganisation.js +0 -97
- package/dist/lib/patterns/aws/managedPlatform.d.ts +0 -12
- package/dist/lib/patterns/aws/managedPlatform.js +0 -29
- package/dist/lib/resources/aws/database/database.d.ts +0 -14
- package/dist/lib/resources/aws/database/database.js +0 -28
- package/dist/lib/resources/aws/database/databaseInstance.d.ts +0 -15
- package/dist/lib/resources/aws/database/databaseInstance.js +0 -30
- package/dist/lib/resources/aws/database/migrationLambda.d.ts +0 -80
- package/dist/lib/resources/aws/database/migrationLambda.js +0 -119
- package/dist/lib/resources/aws/iam/identityCenter/attachManagedPolicy.d.ts +0 -13
- package/dist/lib/resources/aws/iam/identityCenter/attachManagedPolicy.js +0 -51
- package/dist/lib/resources/aws/iam/securityGroup.d.ts +0 -5
- package/dist/lib/resources/aws/iam/securityGroup.js +0 -14
- package/dist/lib/resources/aws/monitoring/monitoringRole.d.ts +0 -29
- package/dist/lib/resources/aws/monitoring/monitoringRole.js +0 -120
- package/dist/lib/utils/capitalizeString.d.ts +0 -12
- package/dist/lib/utils/capitalizeString.js +0 -30
|
@@ -1,117 +1,25 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const capitaliseString_1 = require("../../../utils/capitaliseString");
|
|
24
|
-
// Canonical source: @fjall/generator schemas/constants.ts — keep in sync
|
|
25
|
-
const DEFAULT_EC2_INSTANCE_TYPE = "t4g.micro";
|
|
26
|
-
const DEFAULT_WARM_POOL_MIN_SIZE = 1;
|
|
27
|
-
const DEFAULT_WARM_POOL_REUSE_ON_SCALE_IN = true;
|
|
28
|
-
// 14 days balances cost against retaining enough history for post-mortem debugging
|
|
29
|
-
const DEFAULT_LOG_RETENTION_DAYS = 14;
|
|
30
|
-
/**
|
|
31
|
-
* Instance type prefixes that use ARM64 architecture (Graviton processors).
|
|
32
|
-
* All other prefixes are assumed to be x86-64 (STANDARD).
|
|
33
|
-
*
|
|
34
|
-
* Keep in sync with @fjall/generator schemas/instanceTypeArchitecture.ts
|
|
35
|
-
*/
|
|
36
|
-
const ARM_INSTANCE_PREFIXES = [
|
|
37
|
-
"t4g",
|
|
38
|
-
"c6g",
|
|
39
|
-
"c6gd",
|
|
40
|
-
"c6gn",
|
|
41
|
-
"c7g",
|
|
42
|
-
"c7gd",
|
|
43
|
-
"c7gn",
|
|
44
|
-
"r6g",
|
|
45
|
-
"r6gd",
|
|
46
|
-
"r7g",
|
|
47
|
-
"r7gd",
|
|
48
|
-
"m6g",
|
|
49
|
-
"m6gd",
|
|
50
|
-
"m7g",
|
|
51
|
-
"m7gd",
|
|
52
|
-
"a1",
|
|
53
|
-
"x2gd",
|
|
54
|
-
"im4gn",
|
|
55
|
-
"is4gen",
|
|
56
|
-
"i4g",
|
|
57
|
-
"hpc7g"
|
|
58
|
-
];
|
|
59
|
-
/**
|
|
60
|
-
* Infer the AMI hardware type from an EC2 instance type.
|
|
61
|
-
* Uses the instance type prefix to determine if it's ARM (Graviton) or x86-64.
|
|
62
|
-
*
|
|
63
|
-
* @param instanceType - EC2 instance type (e.g., "t4g.micro", "t3.small")
|
|
64
|
-
* @returns AmiHardwareType.ARM for Graviton instances, AmiHardwareType.STANDARD for Intel/AMD
|
|
65
|
-
*/
|
|
66
|
-
function inferAmiHardwareType(instanceType) {
|
|
67
|
-
const prefix = instanceType.split(".")[0] ?? instanceType;
|
|
68
|
-
return ARM_INSTANCE_PREFIXES.includes(prefix)
|
|
69
|
-
? aws_ecs_1.AmiHardwareType.ARM
|
|
70
|
-
: aws_ecs_1.AmiHardwareType.STANDARD;
|
|
71
|
-
}
|
|
72
|
-
/**
|
|
73
|
-
* CDK Aspect that fixes capacity provider deletion dependencies.
|
|
74
|
-
*
|
|
75
|
-
* This is a workaround for CDK bug #15366 where ECS services don't properly
|
|
76
|
-
* depend on CfnClusterCapacityProviderAssociations, causing "capacity provider
|
|
77
|
-
* is in use" errors during stack deletion.
|
|
78
|
-
*
|
|
79
|
-
* The aspect runs at synth time (when associations exist) and adds:
|
|
80
|
-
* - Service depends on CfnClusterCapacityProviderAssociations
|
|
81
|
-
*
|
|
82
|
-
* DELETE order becomes: Services → Associations → Cluster
|
|
83
|
-
*
|
|
84
|
-
* @see https://github.com/aws/aws-cdk/issues/15366
|
|
85
|
-
*/
|
|
86
|
-
class CapacityProviderDependencyAspect {
|
|
87
|
-
constructor(cluster) {
|
|
88
|
-
this.cluster = cluster;
|
|
89
|
-
}
|
|
90
|
-
visit(node) {
|
|
91
|
-
// Find ECS services that belong to this cluster
|
|
92
|
-
if (node instanceof aws_ecs_1.FargateService || node instanceof aws_ecs_1.Ec2Service) {
|
|
93
|
-
// Find CfnClusterCapacityProviderAssociations in the cluster's descendants
|
|
94
|
-
const associations = this.cluster.node
|
|
95
|
-
.findAll()
|
|
96
|
-
.find((child) => child instanceof aws_ecs_1.CfnClusterCapacityProviderAssociations);
|
|
97
|
-
if (associations) {
|
|
98
|
-
// Add dependency: Service → Associations
|
|
99
|
-
// DELETE order: Service deleted first, then Associations
|
|
100
|
-
node.node.addDependency(associations);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
var Protocol;
|
|
106
|
-
(function (Protocol) {
|
|
107
|
-
Protocol[Protocol["HTTP"] = 0] = "HTTP";
|
|
108
|
-
Protocol[Protocol["HTTPS"] = 1] = "HTTPS";
|
|
109
|
-
})(Protocol || (exports.Protocol = Protocol = {}));
|
|
110
|
-
var ScalingType;
|
|
111
|
-
(function (ScalingType) {
|
|
112
|
-
ScalingType["CPU"] = "ECSServiceAverageCPUUtilization";
|
|
113
|
-
ScalingType["MEMORY"] = "ECSServiceAverageMemoryUtilization";
|
|
114
|
-
})(ScalingType || (exports.ScalingType = ScalingType = {}));
|
|
1
|
+
import { Cluster as CdkCluster, ContainerInsights } from "aws-cdk-lib/aws-ecs";
|
|
2
|
+
import { Connections, Port } from "aws-cdk-lib/aws-ec2";
|
|
3
|
+
import { Construct } from "constructs";
|
|
4
|
+
import { CfnOutput, Aspects } from "aws-cdk-lib";
|
|
5
|
+
import { processConnections } from "../../../utils/connections.js";
|
|
6
|
+
import { toPascalCase } from "../../../utils/capitaliseString.js";
|
|
7
|
+
import { createEcsServiceAlarms } from "../monitoring/index.js";
|
|
8
|
+
// Extracted modules
|
|
9
|
+
import { CapacityProviderDependencyAspect } from "./ecsCapacityProviderAspect.js";
|
|
10
|
+
import { validateEcsClusterProps } from "./ecsValidation.js";
|
|
11
|
+
import { createExecutionRole, createTaskRole, createTaskDefinition, addContainersToTask, isServiceFargate, isServiceEc2 } from "./ecsTaskDefinition.js";
|
|
12
|
+
import { addLoadBalancer, addLoadBalancerListener, addHostedZone, addDirectAccessOutputs, registerServiceWithALB } from "./ecsNetworking.js";
|
|
13
|
+
import { createService, addServiceScaling, getOrCreateAsgCapacityProvider } from "./ecsServiceFactory.js";
|
|
14
|
+
// Re-export all types/enums/constants so existing consumers are not broken
|
|
15
|
+
export * from "./ecsTypes.js";
|
|
16
|
+
export * from "./ecsConstants.js";
|
|
17
|
+
export * from "./ecsContext.js";
|
|
18
|
+
export * from "./ecsTaskDefinition.js";
|
|
19
|
+
export * from "./ecsNetworking.js";
|
|
20
|
+
export { CapacityProviderDependencyAspect } from "./ecsCapacityProviderAspect.js";
|
|
21
|
+
export { validateEcsClusterProps, validateSsmPathComponent } from "./ecsValidation.js";
|
|
22
|
+
export * from "./ecsServiceFactory.js";
|
|
115
23
|
/**
|
|
116
24
|
* ECS Cluster supporting multiple services with a shared ALB.
|
|
117
25
|
*
|
|
@@ -148,45 +56,76 @@ var ScalingType;
|
|
|
148
56
|
* ]
|
|
149
57
|
* });
|
|
150
58
|
*/
|
|
151
|
-
class EcsCluster extends
|
|
59
|
+
export default class EcsCluster extends Construct {
|
|
60
|
+
connections;
|
|
61
|
+
// Cluster-level resources
|
|
62
|
+
cluster;
|
|
63
|
+
loadBalancer;
|
|
64
|
+
loadBalancerListener;
|
|
65
|
+
certificate;
|
|
66
|
+
// EC2-specific (mutable state shared with ecsServiceFactory)
|
|
67
|
+
asgState = {
|
|
68
|
+
providers: new Map(),
|
|
69
|
+
autoScalingGroup: undefined,
|
|
70
|
+
asgSecurityGroup: undefined
|
|
71
|
+
};
|
|
72
|
+
// Per-service tracking
|
|
73
|
+
services = new Map();
|
|
74
|
+
// Configuration
|
|
75
|
+
scope;
|
|
76
|
+
props;
|
|
77
|
+
outputName;
|
|
78
|
+
loadBalancerDisabled;
|
|
79
|
+
directAccessEnabled;
|
|
80
|
+
// ALB priority management
|
|
81
|
+
priorityState = {
|
|
82
|
+
nextPriority: 100,
|
|
83
|
+
usedPriorities: new Set()
|
|
84
|
+
};
|
|
152
85
|
constructor(scope, id, props) {
|
|
153
86
|
super(scope, id);
|
|
154
|
-
// Per-service tracking
|
|
155
|
-
this.services = new Map();
|
|
156
|
-
// Per-service ASG capacity providers (keyed by EC2 config signature)
|
|
157
|
-
this.asgCapacityProviders = new Map();
|
|
158
|
-
this.nextPriority = 100;
|
|
159
|
-
this.usedPriorities = new Set();
|
|
160
87
|
this.scope = scope;
|
|
161
88
|
this.props = props;
|
|
162
89
|
// Sanitise cluster name for CloudFormation output keys (must be alphanumeric)
|
|
163
|
-
this.outputName =
|
|
90
|
+
this.outputName = toPascalCase(props.clusterName);
|
|
164
91
|
this.directAccessEnabled = props.cluster?.directAccess === true;
|
|
165
92
|
this.loadBalancerDisabled =
|
|
166
93
|
props.cluster?.loadBalancer === false || this.directAccessEnabled;
|
|
167
|
-
|
|
168
|
-
this.addCluster(props);
|
|
94
|
+
validateEcsClusterProps(props);
|
|
95
|
+
this.cluster = this.addCluster(props);
|
|
169
96
|
for (const serviceProps of props.services) {
|
|
170
97
|
if (serviceProps.capacityProvider === "EC2") {
|
|
171
|
-
this.
|
|
98
|
+
getOrCreateAsgCapacityProvider(this.ctx, serviceProps, this.asgState);
|
|
172
99
|
}
|
|
173
100
|
}
|
|
174
101
|
if (!this.loadBalancerDisabled) {
|
|
175
|
-
this.
|
|
102
|
+
const lbResult = addLoadBalancer(this.ctx, this.anyServiceUsesEc2(), this.asgState.asgSecurityGroup);
|
|
103
|
+
this.loadBalancer = lbResult.loadBalancer;
|
|
176
104
|
if (props.cluster?.domain || props.cluster?.domainConfig) {
|
|
177
|
-
this.
|
|
105
|
+
const hzResult = addHostedZone(this.ctx, this.loadBalancer);
|
|
106
|
+
this.certificate = hzResult.certificate;
|
|
178
107
|
}
|
|
179
|
-
this.addLoadBalancerListener(
|
|
108
|
+
this.loadBalancerListener = addLoadBalancerListener(this.ctx, this.loadBalancer, this.certificate);
|
|
180
109
|
}
|
|
181
110
|
else if (this.directAccessEnabled) {
|
|
182
|
-
this.
|
|
111
|
+
addDirectAccessOutputs(this.ctx, this.asgState.autoScalingGroup);
|
|
183
112
|
}
|
|
184
113
|
for (const serviceProps of props.services) {
|
|
185
114
|
this.addServiceToCluster(serviceProps);
|
|
186
115
|
}
|
|
187
116
|
this.addDeployableServiceOutputs(props);
|
|
188
|
-
this.setupConnections(props);
|
|
189
|
-
|
|
117
|
+
this.connections = this.setupConnections(props);
|
|
118
|
+
Aspects.of(this).add(new CapacityProviderDependencyAspect(this.cluster));
|
|
119
|
+
}
|
|
120
|
+
get ctx() {
|
|
121
|
+
return {
|
|
122
|
+
scope: this,
|
|
123
|
+
props: this.props,
|
|
124
|
+
cluster: this.cluster,
|
|
125
|
+
outputName: this.outputName,
|
|
126
|
+
loadBalancerDisabled: this.loadBalancerDisabled,
|
|
127
|
+
directAccessEnabled: this.directAccessEnabled
|
|
128
|
+
};
|
|
190
129
|
}
|
|
191
130
|
/** Get the cluster's load balancer. Undefined if disabled. */
|
|
192
131
|
getLoadBalancer() {
|
|
@@ -228,20 +167,20 @@ class EcsCluster extends constructs_1.Construct {
|
|
|
228
167
|
*/
|
|
229
168
|
addServiceToCluster(serviceProps) {
|
|
230
169
|
const serviceName = serviceProps.name;
|
|
231
|
-
const executionRole = this.
|
|
232
|
-
const taskRole = this.
|
|
233
|
-
const taskDefinition = this.
|
|
234
|
-
const { containers, primaryContainer } = this.
|
|
235
|
-
const service = this.
|
|
170
|
+
const executionRole = createExecutionRole(this.ctx, serviceName);
|
|
171
|
+
const taskRole = createTaskRole(this.ctx, serviceName, serviceProps);
|
|
172
|
+
const taskDefinition = createTaskDefinition(this.ctx, serviceName, serviceProps, executionRole, taskRole);
|
|
173
|
+
const { containers, primaryContainer } = addContainersToTask(this.ctx, serviceName, serviceProps, taskDefinition);
|
|
174
|
+
const service = createService(this.ctx, serviceName, serviceProps, taskDefinition, this.asgState);
|
|
236
175
|
let targetGroup;
|
|
237
176
|
if (!this.loadBalancerDisabled &&
|
|
238
177
|
primaryContainer &&
|
|
239
178
|
this.loadBalancerListener) {
|
|
240
|
-
targetGroup = this.
|
|
179
|
+
targetGroup = registerServiceWithALB(this.ctx, this.loadBalancerListener, serviceName, serviceProps, service, primaryContainer, this.priorityState);
|
|
241
180
|
}
|
|
242
181
|
let scalingPolicy;
|
|
243
182
|
if (serviceProps.scalingType) {
|
|
244
|
-
scalingPolicy = this.
|
|
183
|
+
scalingPolicy = addServiceScaling(this.ctx, serviceName, serviceProps, service);
|
|
245
184
|
}
|
|
246
185
|
this.services.set(serviceName, {
|
|
247
186
|
service,
|
|
@@ -255,7 +194,7 @@ class EcsCluster extends constructs_1.Construct {
|
|
|
255
194
|
});
|
|
256
195
|
if (serviceProps.connections && serviceProps.connections.length > 0) {
|
|
257
196
|
try {
|
|
258
|
-
|
|
197
|
+
processConnections(serviceProps.connections, taskRole, // IGrantable (task role for IAM grants)
|
|
259
198
|
service // IConnectable (security group for network access)
|
|
260
199
|
);
|
|
261
200
|
}
|
|
@@ -263,47 +202,17 @@ class EcsCluster extends constructs_1.Construct {
|
|
|
263
202
|
throw new Error(`Failed to process connections for ECS service '${serviceName}': ${error instanceof Error ? error.message : String(error)}`);
|
|
264
203
|
}
|
|
265
204
|
}
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
throw new Error(`Duplicate service names: ${[...new Set(duplicateServices)].join(", ")}`);
|
|
277
|
-
}
|
|
278
|
-
// Validate routing when multiple services have ports
|
|
279
|
-
const servicesWithPorts = props.services.filter((s) => s.containers.some((c) => c.port !== undefined));
|
|
280
|
-
if (servicesWithPorts.length > 1 && !this.loadBalancerDisabled) {
|
|
281
|
-
const missingRouting = servicesWithPorts.filter((s) => {
|
|
282
|
-
const rules = Array.isArray(s.routing)
|
|
283
|
-
? s.routing
|
|
284
|
-
: s.routing
|
|
285
|
-
? [s.routing]
|
|
286
|
-
: [];
|
|
287
|
-
return !rules.some((r) => r.path || r.host);
|
|
205
|
+
// Per-service alarm wiring (shared topic on cluster, thresholds per service)
|
|
206
|
+
if (this.props.alertsTopic && serviceProps.alarms !== false) {
|
|
207
|
+
createEcsServiceAlarms({
|
|
208
|
+
scope: this,
|
|
209
|
+
serviceName,
|
|
210
|
+
service,
|
|
211
|
+
targetGroup,
|
|
212
|
+
config: typeof serviceProps.alarms === "object" ? serviceProps.alarms : {},
|
|
213
|
+
alarmTopic: this.props.alertsTopic,
|
|
214
|
+
applicationId: this.props.applicationId
|
|
288
215
|
});
|
|
289
|
-
if (missingRouting.length > 0) {
|
|
290
|
-
throw new Error(`Services with ports require routing config when cluster has multiple services: ` +
|
|
291
|
-
`${missingRouting.map((s) => s.name).join(", ")}. ` +
|
|
292
|
-
"Add routing: { path: '/...' } to each service.");
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
// Validate each service's containers
|
|
296
|
-
for (const service of props.services) {
|
|
297
|
-
if (!service.containers || service.containers.length === 0) {
|
|
298
|
-
throw new Error(`Service '${service.name}': At least one container must be specified.`);
|
|
299
|
-
}
|
|
300
|
-
// Check for duplicate container names within service
|
|
301
|
-
const containerNames = service.containers.map((c) => c.name);
|
|
302
|
-
const duplicateContainers = containerNames.filter((name, index) => containerNames.indexOf(name) !== index);
|
|
303
|
-
if (duplicateContainers.length > 0) {
|
|
304
|
-
throw new Error(`Service '${service.name}': Duplicate container names: ` +
|
|
305
|
-
`${[...new Set(duplicateContainers)].join(", ")}`);
|
|
306
|
-
}
|
|
307
216
|
}
|
|
308
217
|
}
|
|
309
218
|
setupConnections(props) {
|
|
@@ -316,8 +225,8 @@ class EcsCluster extends constructs_1.Construct {
|
|
|
316
225
|
}
|
|
317
226
|
}
|
|
318
227
|
const securityGroups = [];
|
|
319
|
-
if (this.asgSecurityGroup) {
|
|
320
|
-
securityGroups.push(this.asgSecurityGroup);
|
|
228
|
+
if (this.asgState.asgSecurityGroup) {
|
|
229
|
+
securityGroups.push(this.asgState.asgSecurityGroup);
|
|
321
230
|
}
|
|
322
231
|
for (const serviceData of this.services.values()) {
|
|
323
232
|
const serviceSgs = serviceData.service?.connections?.securityGroups || [];
|
|
@@ -327,445 +236,11 @@ class EcsCluster extends constructs_1.Construct {
|
|
|
327
236
|
}
|
|
328
237
|
}
|
|
329
238
|
}
|
|
330
|
-
|
|
239
|
+
return new Connections({
|
|
331
240
|
securityGroups,
|
|
332
|
-
defaultPort:
|
|
241
|
+
defaultPort: Port.tcp(defaultPort)
|
|
333
242
|
});
|
|
334
243
|
}
|
|
335
|
-
/**
|
|
336
|
-
* Creates the execution role for ECS infrastructure operations.
|
|
337
|
-
* Used by the ECS agent to pull images, write logs, and inject secrets.
|
|
338
|
-
* NOT used by application code - that's the task role.
|
|
339
|
-
*/
|
|
340
|
-
createExecutionRole(serviceName) {
|
|
341
|
-
const executionRole = new aws_iam_1.Role(this, `${serviceName}ExecutionRole`, {
|
|
342
|
-
assumedBy: new aws_iam_1.ServicePrincipal("ecs-tasks.amazonaws.com")
|
|
343
|
-
});
|
|
344
|
-
// GetAuthorizationToken is an account-level API that requires resources: ["*"].
|
|
345
|
-
// The image-pull actions also use "*" because ecrRepository can be a string URI
|
|
346
|
-
// (cross-account or public ECR), not always a Repository construct with an ARN.
|
|
347
|
-
executionRole.addToPolicy(new aws_iam_1.PolicyStatement({
|
|
348
|
-
effect: aws_iam_1.Effect.ALLOW,
|
|
349
|
-
actions: [
|
|
350
|
-
"ecr:GetAuthorizationToken",
|
|
351
|
-
"ecr:BatchCheckLayerAvailability",
|
|
352
|
-
"ecr:GetDownloadUrlForLayer",
|
|
353
|
-
"ecr:BatchGetImage"
|
|
354
|
-
],
|
|
355
|
-
resources: ["*"]
|
|
356
|
-
}));
|
|
357
|
-
const logGroupArn = `arn:aws:logs:${aws_cdk_lib_1.Stack.of(this).region}:${aws_cdk_lib_1.Stack.of(this).account}:log-group:/ecs/${this.props.clusterName}*`;
|
|
358
|
-
executionRole.addToPolicy(new aws_iam_1.PolicyStatement({
|
|
359
|
-
effect: aws_iam_1.Effect.ALLOW,
|
|
360
|
-
actions: [
|
|
361
|
-
"logs:CreateLogStream",
|
|
362
|
-
"logs:PutLogEvents",
|
|
363
|
-
"logs:CreateLogGroup"
|
|
364
|
-
],
|
|
365
|
-
resources: [logGroupArn, `${logGroupArn}:*`]
|
|
366
|
-
}));
|
|
367
|
-
const secretNames = this.collectSecretsManagerSecretNames();
|
|
368
|
-
if (secretNames.length > 0) {
|
|
369
|
-
const secretArns = secretNames.map((secretName) => `arn:aws:secretsmanager:${aws_cdk_lib_1.Stack.of(this).region}:${aws_cdk_lib_1.Stack.of(this).account}:secret:${secretName}-*`);
|
|
370
|
-
executionRole.addToPolicy(new aws_iam_1.PolicyStatement({
|
|
371
|
-
effect: aws_iam_1.Effect.ALLOW,
|
|
372
|
-
actions: [
|
|
373
|
-
"secretsmanager:GetSecretValue",
|
|
374
|
-
"secretsmanager:DescribeSecret"
|
|
375
|
-
],
|
|
376
|
-
resources: secretArns
|
|
377
|
-
}));
|
|
378
|
-
}
|
|
379
|
-
const hasSsmSecrets = this.props.services.some((service) => service.containers.some((container) => container.secrets && container.secrets.length > 0));
|
|
380
|
-
if (hasSsmSecrets) {
|
|
381
|
-
if (!this.props.appName) {
|
|
382
|
-
throw new Error(`ECS cluster '${this.props.clusterName}' has services using secrets but appName is not configured. ` +
|
|
383
|
-
`Set appName on cluster props to enable scoped IAM permissions for SSM Parameter Store access.`);
|
|
384
|
-
}
|
|
385
|
-
executionRole.addToPolicy(new aws_iam_1.PolicyStatement({
|
|
386
|
-
effect: aws_iam_1.Effect.ALLOW,
|
|
387
|
-
actions: ["ssm:GetParameters", "ssm:GetParameter"],
|
|
388
|
-
resources: [`arn:aws:ssm:*:*:parameter/${this.props.appName}/*`]
|
|
389
|
-
}));
|
|
390
|
-
}
|
|
391
|
-
// KMS decrypt for SSM SecureString and Secrets Manager with customer-managed keys (CMKs)
|
|
392
|
-
executionRole.addToPolicy(new aws_iam_1.PolicyStatement({
|
|
393
|
-
effect: aws_iam_1.Effect.ALLOW,
|
|
394
|
-
actions: ["kms:Decrypt"],
|
|
395
|
-
resources: ["*"],
|
|
396
|
-
conditions: {
|
|
397
|
-
StringEquals: {
|
|
398
|
-
"kms:ViaService": [
|
|
399
|
-
`ssm.${aws_cdk_lib_1.Stack.of(this).region}.amazonaws.com`,
|
|
400
|
-
`secretsmanager.${aws_cdk_lib_1.Stack.of(this).region}.amazonaws.com`
|
|
401
|
-
]
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
}));
|
|
405
|
-
return executionRole;
|
|
406
|
-
}
|
|
407
|
-
/**
|
|
408
|
-
* Creates the task role for application code running in the container.
|
|
409
|
-
* This role is assumed by the application, not the ECS agent.
|
|
410
|
-
* Includes default ECS Exec permissions plus any service-specific policies.
|
|
411
|
-
*/
|
|
412
|
-
createTaskRole(serviceName, serviceProps) {
|
|
413
|
-
const taskRole = new aws_iam_1.Role(this, `${serviceName}TaskRole`, {
|
|
414
|
-
assumedBy: new aws_iam_1.ServicePrincipal("ecs-tasks.amazonaws.com")
|
|
415
|
-
});
|
|
416
|
-
// SSM permissions for ECS Exec (ecs execute-command)
|
|
417
|
-
taskRole.addToPolicy(new aws_iam_1.PolicyStatement({
|
|
418
|
-
effect: aws_iam_1.Effect.ALLOW,
|
|
419
|
-
actions: [
|
|
420
|
-
"ssmmessages:CreateControlChannel",
|
|
421
|
-
"ssmmessages:CreateDataChannel",
|
|
422
|
-
"ssmmessages:OpenControlChannel",
|
|
423
|
-
"ssmmessages:OpenDataChannel"
|
|
424
|
-
],
|
|
425
|
-
resources: ["*"]
|
|
426
|
-
}));
|
|
427
|
-
if (serviceProps.taskRoleInlinePolicies) {
|
|
428
|
-
for (const [policyName, policyDocument] of Object.entries(serviceProps.taskRoleInlinePolicies)) {
|
|
429
|
-
taskRole.attachInlinePolicy(new aws_iam_1.Policy(this, `${serviceName}${policyName}`, {
|
|
430
|
-
document: policyDocument
|
|
431
|
-
}));
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
if (serviceProps.taskRoleManagedPolicies) {
|
|
435
|
-
for (const policy of serviceProps.taskRoleManagedPolicies) {
|
|
436
|
-
taskRole.addManagedPolicy(policy);
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
return taskRole;
|
|
440
|
-
}
|
|
441
|
-
createTaskDefinition(serviceName, serviceProps, executionRole, taskRole) {
|
|
442
|
-
const cpu = serviceProps.cpu || 256;
|
|
443
|
-
const memoryLimitMiB = serviceProps.memoryLimitMiB || 512;
|
|
444
|
-
if (this.isServiceFargate(serviceProps)) {
|
|
445
|
-
return new aws_ecs_1.FargateTaskDefinition(this, `${serviceName}TaskDefinition`, {
|
|
446
|
-
family: `${this.props.clusterName}-${serviceName}`,
|
|
447
|
-
cpu,
|
|
448
|
-
memoryLimitMiB,
|
|
449
|
-
executionRole,
|
|
450
|
-
taskRole,
|
|
451
|
-
runtimePlatform: {
|
|
452
|
-
cpuArchitecture: aws_ecs_1.CpuArchitecture.ARM64,
|
|
453
|
-
operatingSystemFamily: aws_ecs_1.OperatingSystemFamily.LINUX
|
|
454
|
-
}
|
|
455
|
-
});
|
|
456
|
-
}
|
|
457
|
-
else {
|
|
458
|
-
return new aws_ecs_1.Ec2TaskDefinition(this, `${serviceName}TaskDefinition`, {
|
|
459
|
-
family: `${this.props.clusterName}-${serviceName}`,
|
|
460
|
-
executionRole,
|
|
461
|
-
taskRole,
|
|
462
|
-
...(this.directAccessEnabled && { networkMode: aws_ecs_1.NetworkMode.HOST })
|
|
463
|
-
});
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
addContainersToTask(serviceName, serviceProps, taskDefinition) {
|
|
467
|
-
const containers = [];
|
|
468
|
-
let primaryContainer;
|
|
469
|
-
for (const containerConfig of serviceProps.containers) {
|
|
470
|
-
const image = this.getContainerImage(serviceName, containerConfig, serviceProps);
|
|
471
|
-
const isFirstWithPort = !primaryContainer && containerConfig.port !== undefined;
|
|
472
|
-
const secrets = {};
|
|
473
|
-
if (containerConfig.secretsImport) {
|
|
474
|
-
for (const [key, secretImport] of Object.entries(containerConfig.secretsImport)) {
|
|
475
|
-
const secret = aws_secretsmanager_1.Secret.fromSecretNameV2(this, `${this.props.clusterName}${serviceName}${containerConfig.name}${key}Secret`, secretImport.name);
|
|
476
|
-
secrets[key] = aws_ecs_2.Secret.fromSecretsManager(secret, secretImport.field);
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
if (containerConfig.secrets && containerConfig.secrets.length > 0) {
|
|
480
|
-
if (containerConfig.secretsImport) {
|
|
481
|
-
const secretsImportKeys = Object.keys(containerConfig.secretsImport);
|
|
482
|
-
const duplicateKeys = containerConfig.secrets.filter((key) => secretsImportKeys.includes(key));
|
|
483
|
-
if (duplicateKeys.length > 0) {
|
|
484
|
-
throw new Error(`Container '${containerConfig.name}' in service '${serviceName}' has duplicate secret keys ` +
|
|
485
|
-
`defined in both secrets and secretsImport: ${duplicateKeys.join(", ")}. ` +
|
|
486
|
-
`Each secret key must be unique across both sources.`);
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
const ssmSecretsPath = this.deriveSsmSecretsPath(serviceName, serviceProps.ssmSecretsPath);
|
|
490
|
-
for (const secretName of containerConfig.secrets) {
|
|
491
|
-
const paramPath = `${ssmSecretsPath}/${secretName}`;
|
|
492
|
-
const param = aws_ssm_1.StringParameter.fromSecureStringParameterAttributes(this, `${this.props.clusterName}${serviceName}${containerConfig.name}${secretName}SsmParam`, { parameterName: paramPath });
|
|
493
|
-
secrets[secretName] = aws_ecs_2.Secret.fromSsmParameter(param);
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
const container = taskDefinition.addContainer(`${serviceName}${containerConfig.name}`, {
|
|
497
|
-
image,
|
|
498
|
-
containerName: containerConfig.name,
|
|
499
|
-
logging: new aws_ecs_1.AwsLogDriver({
|
|
500
|
-
streamPrefix: `/ecs/${this.props.clusterName}/${serviceName}`,
|
|
501
|
-
logRetention: DEFAULT_LOG_RETENTION_DAYS
|
|
502
|
-
}),
|
|
503
|
-
environment: {
|
|
504
|
-
...containerConfig.environment,
|
|
505
|
-
...(containerConfig.port
|
|
506
|
-
? { PORT: String(containerConfig.port) }
|
|
507
|
-
: {})
|
|
508
|
-
},
|
|
509
|
-
secrets,
|
|
510
|
-
command: containerConfig.command,
|
|
511
|
-
entryPoint: containerConfig.entryPoint,
|
|
512
|
-
essential: containerConfig.essential ?? true,
|
|
513
|
-
healthCheck: containerConfig.healthCheck
|
|
514
|
-
? {
|
|
515
|
-
command: containerConfig.healthCheck.command,
|
|
516
|
-
interval: containerConfig.healthCheck.interval
|
|
517
|
-
? aws_cdk_lib_1.Duration.seconds(containerConfig.healthCheck.interval)
|
|
518
|
-
: undefined,
|
|
519
|
-
timeout: containerConfig.healthCheck.timeout
|
|
520
|
-
? aws_cdk_lib_1.Duration.seconds(containerConfig.healthCheck.timeout)
|
|
521
|
-
: undefined,
|
|
522
|
-
retries: containerConfig.healthCheck.retries,
|
|
523
|
-
startPeriod: containerConfig.healthCheck.startPeriod
|
|
524
|
-
? aws_cdk_lib_1.Duration.seconds(containerConfig.healthCheck.startPeriod)
|
|
525
|
-
: undefined
|
|
526
|
-
}
|
|
527
|
-
: undefined,
|
|
528
|
-
...(this.isServiceEc2(serviceProps) && {
|
|
529
|
-
memoryLimitMiB: serviceProps.ec2Config?.memoryLimitMiB ?? 1024
|
|
530
|
-
})
|
|
531
|
-
});
|
|
532
|
-
if (containerConfig.port) {
|
|
533
|
-
container.addPortMappings({
|
|
534
|
-
containerPort: containerConfig.port
|
|
535
|
-
});
|
|
536
|
-
}
|
|
537
|
-
if (isFirstWithPort) {
|
|
538
|
-
primaryContainer = container;
|
|
539
|
-
}
|
|
540
|
-
containers.push(container);
|
|
541
|
-
}
|
|
542
|
-
return { containers, primaryContainer };
|
|
543
|
-
}
|
|
544
|
-
getContainerImage(serviceName, containerConfig, serviceProps) {
|
|
545
|
-
const imageSource = containerConfig.image || serviceProps.image || this.props.ecrRepository;
|
|
546
|
-
if (!imageSource) {
|
|
547
|
-
return aws_ecs_1.ContainerImage.fromRegistry("amazon/amazon-ecs-sample");
|
|
548
|
-
}
|
|
549
|
-
// Build image tag with optional dockerTarget suffix
|
|
550
|
-
// Format: <service>-[<target>-]<version>
|
|
551
|
-
// imageVersion comes from CDK context (git SHA) to ensure CloudFormation
|
|
552
|
-
// detects template changes when new code is deployed. Falls back to 'latest'
|
|
553
|
-
// for apps without Dockerfiles (welcome image) or local dev.
|
|
554
|
-
const imageVersion = this.node.tryGetContext("imageVersion") ||
|
|
555
|
-
"latest";
|
|
556
|
-
const targetSuffix = serviceProps.dockerTarget
|
|
557
|
-
? `-${serviceProps.dockerTarget.toLowerCase()}`
|
|
558
|
-
: "";
|
|
559
|
-
const imageTag = `${serviceName.toLowerCase()}${targetSuffix}-${imageVersion}`;
|
|
560
|
-
if (typeof imageSource === "string") {
|
|
561
|
-
const isFullRegistryUrl = (imageSource.includes("/") && !imageSource.includes(".")) || // Docker Hub shorthand: amazon/amazon-ecs-sample
|
|
562
|
-
/^(docker\.io|registry\.hub\.docker\.com|ghcr\.io)\//i.test(imageSource) || // Full Docker Hub / GHCR URLs
|
|
563
|
-
imageSource.startsWith("public.ecr.aws/") || // Public ECR: public.ecr.aws/fjall/welcome
|
|
564
|
-
imageSource.includes(".dkr.ecr."); // Private ECR full URL: 123456789012.dkr.ecr.us-east-2.amazonaws.com/repo:tag
|
|
565
|
-
if (isFullRegistryUrl) {
|
|
566
|
-
return aws_ecs_1.ContainerImage.fromRegistry(imageSource);
|
|
567
|
-
}
|
|
568
|
-
return aws_ecs_1.ContainerImage.fromEcrRepository(aws_ecr_1.Repository.fromRepositoryName(this, `${serviceName}${containerConfig.name}EcrRepo`, imageSource), imageTag);
|
|
569
|
-
}
|
|
570
|
-
if (imageSource instanceof aws_ecr_1.Repository) {
|
|
571
|
-
return aws_ecs_1.ContainerImage.fromEcrRepository(imageSource, imageTag);
|
|
572
|
-
}
|
|
573
|
-
// After string and Repository checks, only ContainerImage remains in the union
|
|
574
|
-
if (!(imageSource instanceof aws_ecs_1.ContainerImage)) {
|
|
575
|
-
throw new Error(`Unsupported image source type: ${typeof imageSource}`);
|
|
576
|
-
}
|
|
577
|
-
return imageSource;
|
|
578
|
-
}
|
|
579
|
-
createService(serviceName, serviceProps, taskDefinition) {
|
|
580
|
-
const desiredCount = serviceProps.desiredCount ?? 2;
|
|
581
|
-
const effectiveProvider = this.getServiceCapacityProvider(serviceProps);
|
|
582
|
-
if (this.isServiceFargate(serviceProps)) {
|
|
583
|
-
const hasNat = this.vpcHasNatGateways();
|
|
584
|
-
const service = new aws_ecs_1.FargateService(this, `${serviceName}Service`, {
|
|
585
|
-
cluster: this.cluster,
|
|
586
|
-
taskDefinition: taskDefinition,
|
|
587
|
-
desiredCount,
|
|
588
|
-
serviceName,
|
|
589
|
-
vpcSubnets: {
|
|
590
|
-
subnetType: hasNat
|
|
591
|
-
? aws_ec2_1.SubnetType.PRIVATE_WITH_EGRESS
|
|
592
|
-
: aws_ec2_1.SubnetType.PUBLIC
|
|
593
|
-
},
|
|
594
|
-
assignPublicIp: !hasNat,
|
|
595
|
-
capacityProviderStrategies: [
|
|
596
|
-
{
|
|
597
|
-
capacityProvider: effectiveProvider,
|
|
598
|
-
weight: 1
|
|
599
|
-
}
|
|
600
|
-
],
|
|
601
|
-
propagateTags: aws_ecs_1.PropagatedTagSource.SERVICE,
|
|
602
|
-
circuitBreaker: { enable: true, rollback: true },
|
|
603
|
-
enableECSManagedTags: true,
|
|
604
|
-
enableExecuteCommand: true,
|
|
605
|
-
healthCheckGracePeriod: aws_cdk_lib_1.Duration.seconds(120),
|
|
606
|
-
minHealthyPercent: 100,
|
|
607
|
-
maxHealthyPercent: 200
|
|
608
|
-
});
|
|
609
|
-
new aws_cdk_lib_1.CfnOutput(this, `${this.outputName}${(0, capitaliseString_1.toPascalCase)(serviceName)}ServiceArn`, {
|
|
610
|
-
key: `${this.outputName}${(0, capitaliseString_1.toPascalCase)(serviceName)}ServiceArn`,
|
|
611
|
-
exportName: `${this.props.clusterName}${serviceName}ServiceArn`,
|
|
612
|
-
value: service.serviceArn,
|
|
613
|
-
description: `ECS Service ARN for ${serviceName}`
|
|
614
|
-
});
|
|
615
|
-
return service;
|
|
616
|
-
}
|
|
617
|
-
else {
|
|
618
|
-
const asgProvider = this.getOrCreateAsgCapacityProvider(serviceProps);
|
|
619
|
-
const service = new aws_ecs_1.Ec2Service(this, `${serviceName}Service`, {
|
|
620
|
-
cluster: this.cluster,
|
|
621
|
-
taskDefinition: taskDefinition,
|
|
622
|
-
desiredCount,
|
|
623
|
-
serviceName,
|
|
624
|
-
capacityProviderStrategies: [
|
|
625
|
-
{
|
|
626
|
-
capacityProvider: asgProvider.capacityProviderName,
|
|
627
|
-
weight: 1
|
|
628
|
-
}
|
|
629
|
-
],
|
|
630
|
-
propagateTags: aws_ecs_1.PropagatedTagSource.SERVICE,
|
|
631
|
-
circuitBreaker: { enable: true, rollback: true },
|
|
632
|
-
placementStrategies: [aws_ecs_1.PlacementStrategy.spreadAcrossInstances()],
|
|
633
|
-
enableECSManagedTags: true,
|
|
634
|
-
enableExecuteCommand: true,
|
|
635
|
-
healthCheckGracePeriod: aws_cdk_lib_1.Duration.seconds(120),
|
|
636
|
-
minHealthyPercent: 100,
|
|
637
|
-
maxHealthyPercent: 200
|
|
638
|
-
});
|
|
639
|
-
new aws_cdk_lib_1.CfnOutput(this, `${this.outputName}${(0, capitaliseString_1.toPascalCase)(serviceName)}ServiceArn`, {
|
|
640
|
-
key: `${this.outputName}${(0, capitaliseString_1.toPascalCase)(serviceName)}ServiceArn`,
|
|
641
|
-
exportName: `${this.props.clusterName}${serviceName}ServiceArn`,
|
|
642
|
-
value: service.serviceArn,
|
|
643
|
-
description: `ECS Service ARN for ${serviceName}`
|
|
644
|
-
});
|
|
645
|
-
return service;
|
|
646
|
-
}
|
|
647
|
-
}
|
|
648
|
-
registerServiceWithALB(serviceName, serviceProps, service, primaryContainer) {
|
|
649
|
-
if (!this.loadBalancerListener) {
|
|
650
|
-
throw new Error("Cannot register service with ALB: loadBalancerListener is not initialised");
|
|
651
|
-
}
|
|
652
|
-
const listener = this.loadBalancerListener;
|
|
653
|
-
const containerPort = primaryContainer.containerPort;
|
|
654
|
-
// Normalise routing to array
|
|
655
|
-
const routingRules = Array.isArray(serviceProps.routing)
|
|
656
|
-
? serviceProps.routing
|
|
657
|
-
: serviceProps.routing
|
|
658
|
-
? [serviceProps.routing]
|
|
659
|
-
: [];
|
|
660
|
-
const healthCheckPath = routingRules.find((r) => r.healthCheckPath)?.healthCheckPath ?? "/";
|
|
661
|
-
const servicesWithPorts = this.props.services.filter((s) => s.containers.some((c) => c.port !== undefined));
|
|
662
|
-
const isSingleService = servicesWithPorts.length === 1;
|
|
663
|
-
const healthCheckConfig = this.isServiceEc2(serviceProps)
|
|
664
|
-
? {
|
|
665
|
-
interval: aws_cdk_lib_1.Duration.seconds(30),
|
|
666
|
-
healthyThresholdCount: 3,
|
|
667
|
-
unhealthyThresholdCount: 3,
|
|
668
|
-
path: healthCheckPath,
|
|
669
|
-
port: "traffic-port",
|
|
670
|
-
timeout: aws_cdk_lib_1.Duration.seconds(15)
|
|
671
|
-
}
|
|
672
|
-
: {
|
|
673
|
-
interval: aws_cdk_lib_1.Duration.seconds(120),
|
|
674
|
-
path: healthCheckPath,
|
|
675
|
-
port: `${containerPort}`,
|
|
676
|
-
timeout: aws_cdk_lib_1.Duration.seconds(10)
|
|
677
|
-
};
|
|
678
|
-
if (isSingleService && routingRules.length <= 1) {
|
|
679
|
-
return listener.addTargets(`${serviceName}TargetGroup`, {
|
|
680
|
-
targets: [
|
|
681
|
-
service.loadBalancerTarget({
|
|
682
|
-
containerName: primaryContainer.containerName,
|
|
683
|
-
containerPort
|
|
684
|
-
})
|
|
685
|
-
],
|
|
686
|
-
port: containerPort,
|
|
687
|
-
protocol: aws_elasticloadbalancingv2_1.ApplicationProtocol.HTTP,
|
|
688
|
-
healthCheck: healthCheckConfig
|
|
689
|
-
});
|
|
690
|
-
}
|
|
691
|
-
else {
|
|
692
|
-
const firstRule = routingRules[0];
|
|
693
|
-
const firstPriority = firstRule?.priority ?? this.getNextPriority();
|
|
694
|
-
if (firstRule?.priority)
|
|
695
|
-
this.usedPriorities.add(firstRule.priority);
|
|
696
|
-
const targetGroup = listener.addTargets(`${serviceName}Targets`, {
|
|
697
|
-
targets: [
|
|
698
|
-
service.loadBalancerTarget({
|
|
699
|
-
containerName: primaryContainer.containerName,
|
|
700
|
-
containerPort
|
|
701
|
-
})
|
|
702
|
-
],
|
|
703
|
-
port: containerPort,
|
|
704
|
-
protocol: aws_elasticloadbalancingv2_1.ApplicationProtocol.HTTP,
|
|
705
|
-
healthCheck: healthCheckConfig,
|
|
706
|
-
conditions: this.buildRoutingConditions(firstRule),
|
|
707
|
-
priority: firstPriority
|
|
708
|
-
});
|
|
709
|
-
// Additional rules reuse the same target group
|
|
710
|
-
for (let i = 1; i < routingRules.length; i++) {
|
|
711
|
-
const rule = routingRules[i];
|
|
712
|
-
const priority = rule.priority ?? this.getNextPriority();
|
|
713
|
-
if (rule.priority)
|
|
714
|
-
this.usedPriorities.add(rule.priority);
|
|
715
|
-
listener.addAction(`${serviceName}Route${i}`, {
|
|
716
|
-
conditions: this.buildRoutingConditions(rule),
|
|
717
|
-
priority,
|
|
718
|
-
action: aws_elasticloadbalancingv2_1.ListenerAction.forward([targetGroup])
|
|
719
|
-
});
|
|
720
|
-
}
|
|
721
|
-
return targetGroup;
|
|
722
|
-
}
|
|
723
|
-
}
|
|
724
|
-
/** Returns the next unused auto-incremented ALB priority, skipping any manually assigned values. */
|
|
725
|
-
getNextPriority() {
|
|
726
|
-
while (this.usedPriorities.has(this.nextPriority)) {
|
|
727
|
-
this.nextPriority++;
|
|
728
|
-
}
|
|
729
|
-
const priority = this.nextPriority++;
|
|
730
|
-
this.usedPriorities.add(priority);
|
|
731
|
-
return priority;
|
|
732
|
-
}
|
|
733
|
-
buildRoutingConditions(rule) {
|
|
734
|
-
const conditions = [];
|
|
735
|
-
if (rule?.path) {
|
|
736
|
-
conditions.push(aws_elasticloadbalancingv2_1.ListenerCondition.pathPatterns([rule.path]));
|
|
737
|
-
}
|
|
738
|
-
if (rule?.host) {
|
|
739
|
-
conditions.push(aws_elasticloadbalancingv2_1.ListenerCondition.hostHeaders([rule.host]));
|
|
740
|
-
}
|
|
741
|
-
return conditions;
|
|
742
|
-
}
|
|
743
|
-
addServiceScaling(serviceName, serviceProps, service) {
|
|
744
|
-
const scalableTarget = new aws_applicationautoscaling_1.ScalableTarget(this, `${serviceName}ScalableTarget`, {
|
|
745
|
-
serviceNamespace: aws_applicationautoscaling_1.ServiceNamespace.ECS,
|
|
746
|
-
resourceId: `service/${this.cluster.clusterName}/${service.serviceName}`,
|
|
747
|
-
scalableDimension: "ecs:service:DesiredCount",
|
|
748
|
-
minCapacity: serviceProps.minCapacity ?? 2,
|
|
749
|
-
maxCapacity: serviceProps.maxCapacity ?? 10
|
|
750
|
-
});
|
|
751
|
-
return new aws_applicationautoscaling_1.TargetTrackingScalingPolicy(this, `${serviceName}ScalingPolicy`, {
|
|
752
|
-
scalingTarget: scalableTarget,
|
|
753
|
-
predefinedMetric: serviceProps.scalingType === ScalingType.MEMORY
|
|
754
|
-
? aws_applicationautoscaling_1.PredefinedMetric.ECS_SERVICE_AVERAGE_MEMORY_UTILIZATION
|
|
755
|
-
: aws_applicationautoscaling_1.PredefinedMetric.ECS_SERVICE_AVERAGE_CPU_UTILIZATION,
|
|
756
|
-
targetValue: 50,
|
|
757
|
-
scaleInCooldown: aws_cdk_lib_1.Duration.seconds(60),
|
|
758
|
-
scaleOutCooldown: aws_cdk_lib_1.Duration.seconds(60)
|
|
759
|
-
});
|
|
760
|
-
}
|
|
761
|
-
/**
|
|
762
|
-
* Check if the VPC has NAT gateways.
|
|
763
|
-
* - For Fjall Vpc: uses hasNatGateways property
|
|
764
|
-
* - For other VPCs: checks if private subnets exist (assumes NAT if present)
|
|
765
|
-
*/
|
|
766
|
-
vpcHasNatGateways() {
|
|
767
|
-
return (0, vpcUtils_1.vpcHasNatGateways)(this.cluster.vpc);
|
|
768
|
-
}
|
|
769
244
|
/**
|
|
770
245
|
* Create DeployableService outputs for deployment automation.
|
|
771
246
|
* Each service gets a DeployableService output so the deployment service
|
|
@@ -773,8 +248,8 @@ class EcsCluster extends constructs_1.Construct {
|
|
|
773
248
|
*/
|
|
774
249
|
addDeployableServiceOutputs(props) {
|
|
775
250
|
for (const [serviceName, serviceData] of this.services) {
|
|
776
|
-
const safeServiceName =
|
|
777
|
-
new
|
|
251
|
+
const safeServiceName = toPascalCase(serviceName);
|
|
252
|
+
new CfnOutput(this, `${this.outputName}${safeServiceName}DeployableService`, {
|
|
778
253
|
key: `${this.outputName}${safeServiceName}DeployableService`,
|
|
779
254
|
exportName: `${props.clusterName}${serviceName}DeployableService`,
|
|
780
255
|
value: serviceData.service.serviceArn,
|
|
@@ -782,378 +257,34 @@ class EcsCluster extends constructs_1.Construct {
|
|
|
782
257
|
});
|
|
783
258
|
}
|
|
784
259
|
}
|
|
785
|
-
/**
|
|
786
|
-
* Gets the capacity provider for a service.
|
|
787
|
-
* Each service MUST specify its own capacityProvider.
|
|
788
|
-
*/
|
|
789
|
-
getServiceCapacityProvider(serviceProps) {
|
|
790
|
-
return serviceProps.capacityProvider;
|
|
791
|
-
}
|
|
792
|
-
/**
|
|
793
|
-
* Checks if a service uses a Fargate capacity provider.
|
|
794
|
-
*/
|
|
795
|
-
isServiceFargate(serviceProps) {
|
|
796
|
-
const provider = this.getServiceCapacityProvider(serviceProps);
|
|
797
|
-
return provider === "FARGATE" || provider === "FARGATE_SPOT";
|
|
798
|
-
}
|
|
799
|
-
/**
|
|
800
|
-
* Checks if a service uses an EC2 capacity provider.
|
|
801
|
-
*/
|
|
802
|
-
isServiceEc2(serviceProps) {
|
|
803
|
-
return this.getServiceCapacityProvider(serviceProps) === "EC2";
|
|
804
|
-
}
|
|
805
|
-
/**
|
|
806
|
-
* Validates an SSM path component for correctness.
|
|
807
|
-
* SSM parameter paths have specific constraints that must be enforced.
|
|
808
|
-
*
|
|
809
|
-
* @param component - The path component to validate
|
|
810
|
-
* @param fieldName - Name of the field for error messages
|
|
811
|
-
* @throws Error if the component is invalid
|
|
812
|
-
*/
|
|
813
|
-
validateSsmPathComponent(component, fieldName) {
|
|
814
|
-
if (!component || component.trim() === "") {
|
|
815
|
-
throw new Error(`${fieldName} cannot be empty for SSM path derivation`);
|
|
816
|
-
}
|
|
817
|
-
if (component.includes("/")) {
|
|
818
|
-
throw new Error(`${fieldName} cannot contain forward slashes (/). Invalid value: "${component}".`);
|
|
819
|
-
}
|
|
820
|
-
// SSM parameter name hierarchy labels have a max length of 2048, but we use a more
|
|
821
|
-
// reasonable limit since each component is just one part of the path
|
|
822
|
-
if (component.length > 128) {
|
|
823
|
-
throw new Error(`${fieldName} exceeds maximum length (128 characters).`);
|
|
824
|
-
}
|
|
825
|
-
}
|
|
826
|
-
/**
|
|
827
|
-
* Collects all Secrets Manager secret names from secretsImport across all services.
|
|
828
|
-
* Used to scope IAM permissions for least-privilege access.
|
|
829
|
-
*/
|
|
830
|
-
collectSecretsManagerSecretNames() {
|
|
831
|
-
const secretNames = new Set();
|
|
832
|
-
for (const service of this.props.services) {
|
|
833
|
-
for (const container of service.containers) {
|
|
834
|
-
if (container.secretsImport) {
|
|
835
|
-
for (const secretImport of Object.values(container.secretsImport)) {
|
|
836
|
-
secretNames.add(secretImport.name);
|
|
837
|
-
}
|
|
838
|
-
}
|
|
839
|
-
}
|
|
840
|
-
}
|
|
841
|
-
return Array.from(secretNames);
|
|
842
|
-
}
|
|
843
|
-
/**
|
|
844
|
-
* Derives the SSM secrets path for a service.
|
|
845
|
-
* Uses explicit path if provided, otherwise derives from app/cluster/service names.
|
|
846
|
-
*/
|
|
847
|
-
deriveSsmSecretsPath(serviceName, explicitPath) {
|
|
848
|
-
if (explicitPath) {
|
|
849
|
-
return explicitPath;
|
|
850
|
-
}
|
|
851
|
-
const appName = this.props.appName;
|
|
852
|
-
if (!appName) {
|
|
853
|
-
throw new Error(`Service '${serviceName}' has secrets defined but no ssmSecretsPath is set ` +
|
|
854
|
-
`and appName is not configured on the cluster. ` +
|
|
855
|
-
`Either set ssmSecretsPath on the service, or set appName on the cluster props ` +
|
|
856
|
-
`to enable automatic path derivation (/<appName>/<clusterName>/<serviceName>).`);
|
|
857
|
-
}
|
|
858
|
-
this.validateSsmPathComponent(appName, "appName");
|
|
859
|
-
this.validateSsmPathComponent(this.props.clusterName, "clusterName");
|
|
860
|
-
this.validateSsmPathComponent(serviceName, "serviceName");
|
|
861
|
-
return `/${appName}/${this.props.clusterName}/${serviceName}`;
|
|
862
|
-
}
|
|
863
|
-
/**
|
|
864
|
-
* Generates a unique key for EC2 config (for ASG deduplication).
|
|
865
|
-
* Services with matching keys share an ASG.
|
|
866
|
-
*/
|
|
867
|
-
getEc2ConfigKey(ec2Config) {
|
|
868
|
-
const instanceType = ec2Config.instanceType ?? DEFAULT_EC2_INSTANCE_TYPE;
|
|
869
|
-
const amiHardwareType = ec2Config.amiHardwareType ??
|
|
870
|
-
(inferAmiHardwareType(instanceType) === aws_ecs_1.AmiHardwareType.ARM
|
|
871
|
-
? "ARM"
|
|
872
|
-
: "STANDARD");
|
|
873
|
-
const warmPoolKey = ec2Config.warmPool
|
|
874
|
-
? `wp${ec2Config.warmPool.minSize ?? DEFAULT_WARM_POOL_MIN_SIZE}-${ec2Config.warmPool.reuseOnScaleIn ?? DEFAULT_WARM_POOL_REUSE_ON_SCALE_IN}`
|
|
875
|
-
: "nowp";
|
|
876
|
-
return `${instanceType}-${amiHardwareType}-${warmPoolKey}`;
|
|
877
|
-
}
|
|
878
|
-
/**
|
|
879
|
-
* Gets or creates an ASG capacity provider for a service.
|
|
880
|
-
* Services with matching EC2 configs share the same ASG.
|
|
881
|
-
*/
|
|
882
|
-
getOrCreateAsgCapacityProvider(serviceProps) {
|
|
883
|
-
const ec2Config = serviceProps.ec2Config ?? {};
|
|
884
|
-
const key = this.getEc2ConfigKey(ec2Config);
|
|
885
|
-
const existing = this.asgCapacityProviders.get(key);
|
|
886
|
-
if (existing) {
|
|
887
|
-
return existing;
|
|
888
|
-
}
|
|
889
|
-
const safeKey = key.replace(/[^a-zA-Z0-9]/g, "");
|
|
890
|
-
const instanceType = ec2Config.instanceType ?? DEFAULT_EC2_INSTANCE_TYPE;
|
|
891
|
-
const amiHardwareType = ec2Config.amiHardwareType
|
|
892
|
-
? ec2Config.amiHardwareType === "STANDARD"
|
|
893
|
-
? aws_ecs_1.AmiHardwareType.STANDARD
|
|
894
|
-
: aws_ecs_1.AmiHardwareType.ARM
|
|
895
|
-
: inferAmiHardwareType(instanceType);
|
|
896
|
-
const minCapacity = ec2Config.minCapacity ?? 2;
|
|
897
|
-
const maxCapacity = ec2Config.maxCapacity ?? 3;
|
|
898
|
-
const asgSecurityGroup = new securityGroup_js_1.SecurityGroup(this, `${safeKey}AsgSecurityGroup`, {
|
|
899
|
-
vpc: this.cluster.vpc,
|
|
900
|
-
description: `Security group for ${key} auto scaling group`
|
|
901
|
-
});
|
|
902
|
-
if (this.directAccessEnabled) {
|
|
903
|
-
for (const service of this.props.services) {
|
|
904
|
-
if (this.isServiceEc2(service)) {
|
|
905
|
-
for (const container of service.containers) {
|
|
906
|
-
if (container.port) {
|
|
907
|
-
asgSecurityGroup.addIngressRule(aws_ec2_1.Peer.anyIpv4(), aws_ec2_1.Port.tcp(container.port), `Direct access to container port ${container.port}`);
|
|
908
|
-
}
|
|
909
|
-
}
|
|
910
|
-
}
|
|
911
|
-
}
|
|
912
|
-
}
|
|
913
|
-
const hasNat = this.vpcHasNatGateways();
|
|
914
|
-
const asg = new aws_autoscaling_1.AutoScalingGroup(this, `${safeKey}AutoScalingGroup`, {
|
|
915
|
-
autoScalingGroupName: `${this.props.clusterName}-${safeKey}-Asg`,
|
|
916
|
-
vpc: this.cluster.vpc,
|
|
917
|
-
vpcSubnets: {
|
|
918
|
-
subnetType: hasNat ? aws_ec2_1.SubnetType.PRIVATE_WITH_EGRESS : aws_ec2_1.SubnetType.PUBLIC
|
|
919
|
-
},
|
|
920
|
-
securityGroup: asgSecurityGroup,
|
|
921
|
-
minCapacity,
|
|
922
|
-
maxCapacity,
|
|
923
|
-
instanceType: new aws_ec2_1.InstanceType(instanceType),
|
|
924
|
-
capacityRebalance: true,
|
|
925
|
-
instanceMonitoring: aws_autoscaling_1.Monitoring.BASIC,
|
|
926
|
-
machineImage: aws_ecs_1.EcsOptimizedImage.amazonLinux2023(amiHardwareType)
|
|
927
|
-
});
|
|
928
|
-
if (ec2Config.warmPool) {
|
|
929
|
-
asg.addWarmPool({
|
|
930
|
-
minSize: ec2Config.warmPool.minSize ?? DEFAULT_WARM_POOL_MIN_SIZE,
|
|
931
|
-
reuseOnScaleIn: ec2Config.warmPool.reuseOnScaleIn ??
|
|
932
|
-
DEFAULT_WARM_POOL_REUSE_ON_SCALE_IN
|
|
933
|
-
});
|
|
934
|
-
}
|
|
935
|
-
const provider = new aws_ecs_1.AsgCapacityProvider(this, `${safeKey}AsgCapacityProvider`, {
|
|
936
|
-
autoScalingGroup: asg,
|
|
937
|
-
enableManagedDraining: true,
|
|
938
|
-
enableManagedTerminationProtection: false
|
|
939
|
-
});
|
|
940
|
-
this.cluster.addAsgCapacityProvider(provider);
|
|
941
|
-
this.asgCapacityProviders.set(key, provider);
|
|
942
|
-
if (!this.autoScalingGroup) {
|
|
943
|
-
this.autoScalingGroup = asg;
|
|
944
|
-
}
|
|
945
|
-
if (!this.asgSecurityGroup) {
|
|
946
|
-
this.asgSecurityGroup = asgSecurityGroup;
|
|
947
|
-
}
|
|
948
|
-
return provider;
|
|
949
|
-
}
|
|
950
|
-
/**
|
|
951
|
-
* Checks if any service in the cluster uses a Fargate capacity provider.
|
|
952
|
-
*/
|
|
260
|
+
/** Checks if any service in the cluster uses a Fargate capacity provider. */
|
|
953
261
|
anyServiceUsesFargate() {
|
|
954
|
-
return this.props.services.some((s) =>
|
|
262
|
+
return this.props.services.some((s) => isServiceFargate(s));
|
|
955
263
|
}
|
|
956
|
-
/**
|
|
957
|
-
* Checks if any service in the cluster uses an EC2 capacity provider.
|
|
958
|
-
*/
|
|
264
|
+
/** Checks if any service in the cluster uses an EC2 capacity provider. */
|
|
959
265
|
anyServiceUsesEc2() {
|
|
960
|
-
return this.props.services.some((s) =>
|
|
266
|
+
return this.props.services.some((s) => isServiceEc2(s));
|
|
961
267
|
}
|
|
962
268
|
addCluster(props) {
|
|
963
269
|
const needsFargate = this.anyServiceUsesFargate();
|
|
964
|
-
|
|
270
|
+
const cluster = new CdkCluster(this, `${props.clusterName}Cluster`, {
|
|
965
271
|
vpc: props.vpc,
|
|
966
272
|
clusterName: props.clusterName,
|
|
967
|
-
containerInsightsV2:
|
|
273
|
+
containerInsightsV2: ContainerInsights.ENABLED,
|
|
968
274
|
enableFargateCapacityProviders: needsFargate
|
|
969
275
|
});
|
|
970
|
-
new
|
|
276
|
+
new CfnOutput(this, `${this.outputName}DeployableCluster`, {
|
|
971
277
|
key: `${this.outputName}DeployableCluster`,
|
|
972
278
|
exportName: `${props.clusterName}DeployableCluster`,
|
|
973
|
-
value:
|
|
279
|
+
value: cluster.clusterArn
|
|
974
280
|
});
|
|
975
|
-
new
|
|
281
|
+
new CfnOutput(this, `${this.outputName}ClusterArn`, {
|
|
976
282
|
key: `${this.outputName}ClusterArn`,
|
|
977
283
|
exportName: `${props.clusterName}ClusterArn`,
|
|
978
|
-
value:
|
|
284
|
+
value: cluster.clusterArn,
|
|
979
285
|
description: `ECS Cluster ARN for ${props.clusterName}`
|
|
980
286
|
});
|
|
981
|
-
|
|
982
|
-
// Note: addAutoScalingGroup removed - ASGs are now created per-service via getOrCreateAsgCapacityProvider
|
|
983
|
-
addLoadBalancer(props) {
|
|
984
|
-
const defaultLoadBalancerName = `${props.clusterName}LoadBalancer`;
|
|
985
|
-
const supportedNameLength = 32;
|
|
986
|
-
let truncatedLoadBalancerName = defaultLoadBalancerName.length > supportedNameLength
|
|
987
|
-
? defaultLoadBalancerName.substring(0, supportedNameLength)
|
|
988
|
-
: defaultLoadBalancerName;
|
|
989
|
-
truncatedLoadBalancerName = truncatedLoadBalancerName.replace(/-+$/, "");
|
|
990
|
-
const isInternal = props.cluster?.loadBalancer === "internal";
|
|
991
|
-
const hasEc2Services = this.anyServiceUsesEc2();
|
|
992
|
-
if (hasEc2Services) {
|
|
993
|
-
this.loadBalancerSecurityGroup = new securityGroup_js_1.SecurityGroup(this, `${props.clusterName}LoadBalancerSecurityGroup`, {
|
|
994
|
-
vpc: this.cluster.vpc,
|
|
995
|
-
description: `Security group for the ${props.clusterName} load balancer`
|
|
996
|
-
});
|
|
997
|
-
if (this.asgSecurityGroup) {
|
|
998
|
-
this.loadBalancerSecurityGroup.connections.allowTo(this.asgSecurityGroup, aws_ec2_1.Port.allTcp());
|
|
999
|
-
// ECS bridge-mode maps container ports to IANA ephemeral range (49152-65535).
|
|
1000
|
-
// The ALB must reach these dynamic ports on the EC2 instances.
|
|
1001
|
-
this.asgSecurityGroup.connections.allowFrom(this.loadBalancerSecurityGroup, aws_ec2_1.Port.tcpRange(49152, 65535));
|
|
1002
|
-
}
|
|
1003
|
-
this.loadBalancer = new aws_elasticloadbalancingv2_1.ApplicationLoadBalancer(this, `${props.clusterName}LoadBalancer`, {
|
|
1004
|
-
vpc: this.cluster.vpc,
|
|
1005
|
-
internetFacing: !isInternal,
|
|
1006
|
-
securityGroup: this.loadBalancerSecurityGroup,
|
|
1007
|
-
loadBalancerName: truncatedLoadBalancerName,
|
|
1008
|
-
vpcSubnets: {
|
|
1009
|
-
subnetType: isInternal
|
|
1010
|
-
? aws_ec2_1.SubnetType.PRIVATE_WITH_EGRESS
|
|
1011
|
-
: aws_ec2_1.SubnetType.PUBLIC
|
|
1012
|
-
}
|
|
1013
|
-
});
|
|
1014
|
-
}
|
|
1015
|
-
else {
|
|
1016
|
-
this.loadBalancer = new aws_elasticloadbalancingv2_1.ApplicationLoadBalancer(this, `${props.clusterName}LoadBalancer`, {
|
|
1017
|
-
vpc: this.cluster.vpc,
|
|
1018
|
-
internetFacing: !isInternal,
|
|
1019
|
-
loadBalancerName: truncatedLoadBalancerName,
|
|
1020
|
-
vpcSubnets: {
|
|
1021
|
-
subnetType: isInternal
|
|
1022
|
-
? aws_ec2_1.SubnetType.PRIVATE_WITH_EGRESS
|
|
1023
|
-
: aws_ec2_1.SubnetType.PUBLIC
|
|
1024
|
-
}
|
|
1025
|
-
});
|
|
1026
|
-
}
|
|
1027
|
-
new aws_cdk_lib_1.CfnOutput(this, `${this.outputName}LoadBalancerDnsName`, {
|
|
1028
|
-
key: `${this.outputName}LoadBalancerDnsName`,
|
|
1029
|
-
exportName: `${props.clusterName}LoadBalancerDnsName`,
|
|
1030
|
-
value: this.loadBalancer.loadBalancerDnsName
|
|
1031
|
-
});
|
|
1032
|
-
const customDomain = props.cluster?.domain || props.cluster?.domainConfig?.domainName;
|
|
1033
|
-
new aws_cdk_lib_1.CfnOutput(this, `${this.outputName}LoadBalancerUrl`, {
|
|
1034
|
-
key: `${this.outputName}LoadBalancerUrl`,
|
|
1035
|
-
exportName: `${props.clusterName}LoadBalancerUrl`,
|
|
1036
|
-
value: customDomain
|
|
1037
|
-
? `https://${customDomain}`
|
|
1038
|
-
: `http://${this.loadBalancer.loadBalancerDnsName}`,
|
|
1039
|
-
description: `Load Balancer URL for ${props.clusterName}`
|
|
1040
|
-
});
|
|
1041
|
-
// Export load balancer ARN for monitoring
|
|
1042
|
-
new aws_cdk_lib_1.CfnOutput(this, `${this.outputName}LoadBalancerArn`, {
|
|
1043
|
-
key: `${this.outputName}LoadBalancerArn`,
|
|
1044
|
-
exportName: `${props.clusterName}LoadBalancerArn`,
|
|
1045
|
-
value: this.loadBalancer.loadBalancerArn,
|
|
1046
|
-
description: `Load Balancer ARN for ${props.clusterName}`
|
|
1047
|
-
});
|
|
1048
|
-
}
|
|
1049
|
-
addDirectAccessOutputs(props) {
|
|
1050
|
-
if (!this.directAccessEnabled || !this.autoScalingGroup)
|
|
1051
|
-
return;
|
|
1052
|
-
const containerPort = props.services.flatMap((s) => s.containers).find((c) => c.port)?.port ||
|
|
1053
|
-
3000;
|
|
1054
|
-
new aws_cdk_lib_1.CfnOutput(this, `${this.outputName}AutoScalingGroupName`, {
|
|
1055
|
-
key: `${this.outputName}AutoScalingGroupName`,
|
|
1056
|
-
exportName: `${props.clusterName}AutoScalingGroupName`,
|
|
1057
|
-
value: this.autoScalingGroup.autoScalingGroupName,
|
|
1058
|
-
description: `Run: aws autoscaling describe-auto-scaling-groups --auto-scaling-group-names <name> to find instance IP`
|
|
1059
|
-
});
|
|
1060
|
-
new aws_cdk_lib_1.CfnOutput(this, `${this.outputName}DirectAccessPort`, {
|
|
1061
|
-
key: `${this.outputName}DirectAccessPort`,
|
|
1062
|
-
exportName: `${props.clusterName}DirectAccessPort`,
|
|
1063
|
-
value: String(containerPort),
|
|
1064
|
-
description: `Access your app at http://<EC2-PUBLIC-IP>:${containerPort}`
|
|
1065
|
-
});
|
|
1066
|
-
}
|
|
1067
|
-
addLoadBalancerListener(props) {
|
|
1068
|
-
if (!this.loadBalancer)
|
|
1069
|
-
return;
|
|
1070
|
-
const port = this.certificate ? 443 : 80;
|
|
1071
|
-
const defaultAction = aws_elasticloadbalancingv2_1.ListenerAction.fixedResponse(404, {
|
|
1072
|
-
contentType: "text/plain",
|
|
1073
|
-
messageBody: "Not Found"
|
|
1074
|
-
});
|
|
1075
|
-
if (this.certificate) {
|
|
1076
|
-
this.loadBalancerListener = this.loadBalancer.addListener(`${props.clusterName}Listener`, {
|
|
1077
|
-
port,
|
|
1078
|
-
certificates: [this.certificate],
|
|
1079
|
-
defaultAction
|
|
1080
|
-
});
|
|
1081
|
-
}
|
|
1082
|
-
else {
|
|
1083
|
-
this.loadBalancerListener = this.loadBalancer.addListener(`${props.clusterName}Listener`, {
|
|
1084
|
-
port,
|
|
1085
|
-
defaultAction
|
|
1086
|
-
});
|
|
1087
|
-
}
|
|
1088
|
-
}
|
|
1089
|
-
addHostedZone(props) {
|
|
1090
|
-
const domainConfig = props.cluster?.domainConfig;
|
|
1091
|
-
const simpleDomain = props.cluster?.domain;
|
|
1092
|
-
const domainName = domainConfig?.domainName ?? simpleDomain;
|
|
1093
|
-
if (!domainName)
|
|
1094
|
-
return;
|
|
1095
|
-
// Managed domain: import zone and cert from domain stack via Fn.importValue
|
|
1096
|
-
if (domainConfig?.managedDomain) {
|
|
1097
|
-
const managed = domainConfig.managedDomain;
|
|
1098
|
-
this.hostedZone = aws_route53_1.HostedZone.fromHostedZoneAttributes(this, `${props.clusterName}ManagedHostedZone`, {
|
|
1099
|
-
hostedZoneId: aws_cdk_lib_1.Fn.importValue(managed.hostedZoneIdExport),
|
|
1100
|
-
zoneName: managed.zoneName
|
|
1101
|
-
});
|
|
1102
|
-
this.certificate = aws_certificatemanager_1.Certificate.fromCertificateArn(this, `${props.clusterName}ManagedCertificate`, aws_cdk_lib_1.Fn.importValue(managed.certificateArnExport));
|
|
1103
|
-
}
|
|
1104
|
-
else if (!domainConfig?.hostedZone) {
|
|
1105
|
-
const hostedZone = new hostedZone_1.HostedZone(this, `${props.clusterName}HostedZone`, {
|
|
1106
|
-
zoneName: domainName
|
|
1107
|
-
});
|
|
1108
|
-
this.hostedZone = hostedZone.getInternalHostedZone();
|
|
1109
|
-
}
|
|
1110
|
-
else {
|
|
1111
|
-
this.hostedZone = domainConfig.hostedZone.getInternalHostedZone();
|
|
1112
|
-
}
|
|
1113
|
-
if (!domainConfig?.certificate && !domainConfig?.managedDomain) {
|
|
1114
|
-
this.certificate = new aws_certificatemanager_1.Certificate(this, `${props.clusterName}Certificate`, {
|
|
1115
|
-
domainName,
|
|
1116
|
-
validation: aws_certificatemanager_1.CertificateValidation.fromDns(this.hostedZone)
|
|
1117
|
-
});
|
|
1118
|
-
}
|
|
1119
|
-
if (domainConfig) {
|
|
1120
|
-
const region = "region" in domainConfig ? domainConfig.region : undefined;
|
|
1121
|
-
const weight = "weight" in domainConfig ? domainConfig.weight : undefined;
|
|
1122
|
-
const geoLocation = "geoLocation" in domainConfig ? domainConfig.geoLocation : undefined;
|
|
1123
|
-
const hasRoutingPolicy = !!region || weight !== undefined || !!geoLocation;
|
|
1124
|
-
let setIdentifier = domainConfig.setIdentifier;
|
|
1125
|
-
if (hasRoutingPolicy && !setIdentifier) {
|
|
1126
|
-
if (region) {
|
|
1127
|
-
setIdentifier = `${props.clusterName}${region}`;
|
|
1128
|
-
}
|
|
1129
|
-
else if (weight !== undefined) {
|
|
1130
|
-
setIdentifier = `${props.clusterName}Weight${weight}`;
|
|
1131
|
-
}
|
|
1132
|
-
else if (geoLocation) {
|
|
1133
|
-
setIdentifier = `${props.clusterName}Geo`;
|
|
1134
|
-
}
|
|
1135
|
-
}
|
|
1136
|
-
if (this.loadBalancer) {
|
|
1137
|
-
this.aRecord = new aws_route53_1.ARecord(this, `${props.clusterName}ARecord`, {
|
|
1138
|
-
recordName: domainName,
|
|
1139
|
-
zone: this.hostedZone,
|
|
1140
|
-
target: aws_route53_1.RecordTarget.fromAlias(new aws_route53_targets_1.LoadBalancerTarget(this.loadBalancer, {
|
|
1141
|
-
evaluateTargetHealth: hasRoutingPolicy
|
|
1142
|
-
})),
|
|
1143
|
-
region,
|
|
1144
|
-
weight,
|
|
1145
|
-
geoLocation,
|
|
1146
|
-
setIdentifier: setIdentifier
|
|
1147
|
-
});
|
|
1148
|
-
}
|
|
1149
|
-
}
|
|
1150
|
-
else if (simpleDomain && this.loadBalancer) {
|
|
1151
|
-
this.aRecord = new aws_route53_1.ARecord(this, `${props.clusterName}ARecord`, {
|
|
1152
|
-
recordName: domainName,
|
|
1153
|
-
zone: this.hostedZone,
|
|
1154
|
-
target: aws_route53_1.RecordTarget.fromAlias(new aws_route53_targets_1.LoadBalancerTarget(this.loadBalancer))
|
|
1155
|
-
});
|
|
1156
|
-
}
|
|
287
|
+
return cluster;
|
|
1157
288
|
}
|
|
1158
289
|
static build(id, props) {
|
|
1159
290
|
return (sb) => {
|
|
@@ -1167,5 +298,3 @@ class EcsCluster extends constructs_1.Construct {
|
|
|
1167
298
|
};
|
|
1168
299
|
}
|
|
1169
300
|
}
|
|
1170
|
-
exports.default = EcsCluster;
|
|
1171
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZWNzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vbGliL3Jlc291cmNlcy9hd3MvY29tcHV0ZS9lY3MudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsaURBb0I2QjtBQUM3QixpREFTNkI7QUFDN0IsMkNBQXVDO0FBR3ZDLDZDQUFzRTtBQUV0RSx1RkFPZ0Q7QUFDaEQsaURBUTZCO0FBQzdCLHVGQUtnRDtBQUNoRCxpREFBMEQ7QUFDMUQsdUVBQXdEO0FBQ3hELGlEQUFzRDtBQUN0RCwrRUFJNEM7QUFDNUMseURBTWlDO0FBQ2pDLHlFQUFxRTtBQUNyRSxpREFBaUQ7QUFDakQsaUVBQTJFO0FBRTNFLHlEQUF5RTtBQUN6RSxxRUFBK0Q7QUFFL0Qsa0VBQW1FO0FBR25FLHNEQUE0RDtBQUM1RCxzRUFBK0Q7QUFHL0QseUVBQXlFO0FBQ3pFLE1BQU0seUJBQXlCLEdBQUcsV0FBVyxDQUFDO0FBQzlDLE1BQU0sMEJBQTBCLEdBQUcsQ0FBQyxDQUFDO0FBQ3JDLE1BQU0sbUNBQW1DLEdBQUcsSUFBSSxDQUFDO0FBQ2pELG1GQUFtRjtBQUNuRixNQUFNLDBCQUEwQixHQUFHLEVBQUUsQ0FBQztBQUV0Qzs7Ozs7R0FLRztBQUNILE1BQU0scUJBQXFCLEdBQUc7SUFDNUIsS0FBSztJQUNMLEtBQUs7SUFDTCxNQUFNO0lBQ04sTUFBTTtJQUNOLEtBQUs7SUFDTCxNQUFNO0lBQ04sTUFBTTtJQUNOLEtBQUs7SUFDTCxNQUFNO0lBQ04sS0FBSztJQUNMLE1BQU07SUFDTixLQUFLO0lBQ0wsTUFBTTtJQUNOLEtBQUs7SUFDTCxNQUFNO0lBQ04sSUFBSTtJQUNKLE1BQU07SUFDTixPQUFPO0lBQ1AsUUFBUTtJQUNSLEtBQUs7SUFDTCxPQUFPO0NBQ1IsQ0FBQztBQUVGOzs7Ozs7R0FNRztBQUNILFNBQVMsb0JBQW9CLENBQUMsWUFBb0I7SUFDaEQsTUFBTSxNQUFNLEdBQUcsWUFBWSxDQUFDLEtBQUssQ0FBQyxHQUFHLENB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QUFPLENBQUMsRUFBZ0IsRUFBRSxFQUFFO1lBQzFCLE1BQU0sUUFBUSxHQUFvQjtnQkFDaEMsR0FBRyxLQUFLO2dCQUNSLEdBQUc7b0JBQ0QsR0FBRyxFQUFFLEVBQUUsQ0FBQyxVQUFVLEVBQUUsSUFBSSxLQUFLLENBQUMsR0FBRztpQkFDbEM7YUFDRixDQUFDO1lBQ0YsT0FBTyxJQUFJLElBQUksQ0FBQyxFQUFFLENBQUMsUUFBUSxFQUFFLEVBQUUsRUFBRSxFQUFFLFFBQVEsQ0FBQyxDQUFDO1FBQy9DLENBQUMsQ0FBQztJQUNKLENBQUM7Q0FDRjtBQS80Q0QsNkJBKzRDQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIEF3c0xvZ0RyaXZlcixcbiAgQ2x1c3RlciBhcyBDZGtDbHVzdGVyLFxuICBDb250YWluZXJJbWFnZSxcbiAgRmFyZ2F0ZVNlcnZpY2UsXG4gIEZhcmdhdGVUYXNrRGVmaW5pdGlvbixcbiAgRWMyU2VydmljZSxcbiAgRWMyVGFza0RlZmluaXRpb24sXG4gIE5ldHdvcmtNb2RlLFxuICBQcm9wYWdhdGVkVGFnU291cmNlLFxuICB0eXBlIFJlcG9zaXRvcnlJbWFnZSxcbiAgdHlwZSBDb250YWluZXJEZWZpbml0aW9uLFxuICBDb250YWluZXJJbnNpZ2h0cyxcbiAgUGxhY2VtZW50U3RyYXRlZ3ksXG4gIEFzZ0NhcGFjaXR5UHJvdmlkZXIsXG4gIEVjc09wdGltaXplZEltYWdlLFxuICBBbWlIYXJkd2FyZVR5cGUsXG4gIENwdUFyY2hpdGVjdHVyZSxcbiAgT3BlcmF0aW5nU3lzdGVtRmFtaWx5LFxuICBDZm5DbHVzdGVyQ2FwYWNpdHlQcm92aWRlckFzc29jaWF0aW9uc1xufSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWVjc1wiO1xuaW1wb3J0IHtcbiAgQ29ubmVjdGlvbnMsXG4gIHR5cGUgSUNvbm5lY3RhYmxlLFxuICB0eXBlIElTZWN1cml0eUdyb3VwLFxuICB0eXBlIElWcGMsXG4gIEluc3RhbmNlVHlwZSxcbiAgUGVlcixcbiAgUG9ydCxcbiAgU3VibmV0VHlwZVxufSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWVjMlwiO1xuaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSBcImNvbnN0cnVjdHNcIjtcbmltcG9ydCB0eXBlIHsgSUNvbnN0cnVjdCB9IGZyb20gXCJjb25zdHJ1Y3RzXCI7XG5pbXBvcnQgeyB0eXBlIFN0YWNrQnVpbGRlciB9IGZyb20gXCIuLi9iYXNlL2F3c1N0YWNrXCI7XG5pbXBvcnQgeyBDZm5PdXRwdXQsIER1cmF0aW9uLCBBc3BlY3RzLCBTdGFjaywgRm4gfSBmcm9tIFwiYXdzLWNkay1saWJcIjtcbmltcG9ydCB0eXBlIHsgSUFzcGVjdCB9IGZyb20gXCJhd3MtY2RrLWxpYlwiO1xuaW1wb3J0IHtcbiAgdHlwZSBBcHBsaWNhdGlvbkxpc3RlbmVyLFxuICBBcHBsaWNhdGlvbkxvYWRCYWxhbmNlcixcbiAgQXBwbGljYXRpb25Qcm90b2NvbCxcbiAgdHlwZSBJQXBwbGljYXRpb25UYXJnZXRHcm91cCxcbiAgTGlzdGVuZXJBY3Rpb24sXG4gIExpc3RlbmVyQ29uZGl0aW9uXG59IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtZWxhc3RpY2xvYWRiYWxhbmNpbmd2MlwiO1xuaW1wb3J0IHtcbiAgRWZmZWN0LFxuICB0eXBlIElNYW5hZ2VkUG9saWN5LFxuICBQb2xpY3ksXG4gIHR5cGUgUG9saWN5RG9jdW1lbnQsXG4gIFBvbGljeVN0YXRlbWVudCxcbiAgUm9sZSxcbiAgU2VydmljZVByaW5jaXBhbFxufSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWlhbVwiO1xuaW1wb3J0IHtcbiAgUHJlZGVmaW5lZE1ldHJpYyxcbiAgU2NhbGFibGVUYXJnZXQsXG4gIFNlcnZpY2VOYW1lc3BhY2UsXG4gIFRhcmdldFRyYWNraW5nU2NhbGluZ1BvbGljeVxufSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWFwcGxpY2F0aW9uYXV0b3NjYWxpbmdcIjtcbmltcG9ydCB7IFNlY3JldCBhcyBFY3NTZWNyZXQgfSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWVjc1wiO1xuaW1wb3J0IHsgU2VjcmV0IH0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1zZWNyZXRzbWFuYWdlclwiO1xuaW1wb3J0IHsgU3RyaW5nUGFyYW1ldGVyIH0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1zc21cIjtcbmltcG9ydCB7XG4gIENlcnRpZmljYXRlLFxuICBDZXJ0aWZpY2F0ZVZhbGlkYXRpb24sXG4gIHR5cGUgSUNlcnRpZmljYXRlXG59IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtY2VydGlmaWNhdGVtYW5hZ2VyXCI7XG5pbXBvcnQge1xuICBBUmVjb3JkLFxuICBIb3N0ZWRab25lIGFzIEFXU0hvc3RlZFpvbmUsXG4gIFJlY29yZFRhcmdldCxcbiAgdHlwZSBJSG9zdGVkWm9uZSxcbiAgdHlwZSBHZW9Mb2NhdGlvblxufSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLXJvdXRlNTNcIjtcbmltcG9ydCB7IExvYWRCYWxhbmNlclRhcmdldCB9IGZyb20gXCJhd3MtY2RrLWxpYi9hd3Mtcm91dGU1My10YXJnZXRzXCI7XG5pbXBvcnQgeyBSZXBvc2l0b3J5IH0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1lY3JcIjtcbmltcG9ydCB7IEF1dG9TY2FsaW5nR3JvdXAsIE1vbml0b3JpbmcgfSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWF1dG9zY2FsaW5nXCI7XG5cbmltcG9ydCB7IEhvc3RlZFpvbmUgYXMgRmphbGxIb3N0ZWRab25lIH0gZnJvbSBcIi4uL25ldHdvcmtpbmcvaG9zdGVkWm9uZVwiO1xuaW1wb3J0IHsgU2VjdXJpdHlHcm91cCB9IGZyb20gXCIuLi9uZXR3b3JraW5nL3NlY3VyaXR5R3JvdXAuanNcIjtcbmltcG9ydCB7IHR5cGUgQ29ubmVjdGlvblNwZWMgfSBmcm9tIFwiLi4vLi4vLi4vdXRpbHMvY29ubmVjdG9yLmpzXCI7XG5pbXBvcnQgeyBwcm9jZXNzQ29ubmVjdGlvbnMgfSBmcm9tIFwiLi4vLi4vLi4vdXRpbHMvY29ubmVjdGlvbnMuanNcIjtcblxuaW1wb3J0IHsgdHlwZSBTZWNyZXRJbXBvcnQgfSBmcm9tIFwiLi4vc2VjcmV0c1wiO1xuaW1wb3J0IHsgdnBjSGFzTmF0R2F0ZXdheXMgfSBmcm9tIFwiLi4vLi4vLi4vdXRpbHMvdnBjVXRpbHNcIjtcbmltcG9ydCB7IHRvUGFzY2FsQ2FzZSB9IGZyb20gXCIuLi8uLi8uLi91dGlscy9jYXBpdGFsaXNlU3RyaW5nXCI7XG5pbXBvcnQgdHlwZSB7IE1hbmFnZWREb21haW5FeHBvcnRzIH0gZnJvbSBcIi4uLy4uLy4uL3V0aWxzL2RvbWFpblR5cGVzXCI7XG5cbi8vIENhbm9uaWNhbCBzb3VyY2U6IEBmamFsbC9nZW5lcmF0b3Igc2NoZW1hcy9jb25zdGFudHMudHMg4oCUIGtlZXAgaW4gc3luY1xuY29uc3QgREVGQVVMVF9FQzJfSU5TVEFOQ0VfVFlQRSA9IFwidDRnLm1pY3JvXCI7XG5jb25zdCBERUZBVUxUX1dBUk1fUE9PTF9NSU5fU0laRSA9IDE7XG5jb25zdCBERUZBVUxUX1dBUk1fUE9PTF9SRVVTRV9PTl9TQ0FMRV9JTiA9IHRydWU7XG4vLyAxNCBkYXlzIGJhbGFuY2VzIGNvc3QgYWdhaW5zdCByZXRhaW5pbmcgZW5vdWdoIGhpc3RvcnkgZm9yIHBvc3QtbW9ydGVtIGRlYnVnZ2luZ1xuY29uc3QgREVGQVVMVF9MT0dfUkVURU5USU9OX0RBWVMgPSAxNDtcblxuLyoqXG4gKiBJbnN0YW5jZSB0eXBlIHByZWZpeGVzIHRoYXQgdXNlIEFSTTY0IGFyY2hpdGVjdHVyZSAoR3Jhdml0b24gcHJvY2Vzc29ycykuXG4gKiBBbGwgb3RoZXIgcHJlZml4ZXMgYXJlIGFzc3VtZWQgdG8gYmUgeDg2LTY0IChTVEFOREFSRCkuXG4gKlxuICogS2VlcCBpbiBzeW5jIHdpdGggQGZqYWxsL2dlbmVyYXRvciBzY2hlbWFzL2luc3RhbmNlVHlwZUFyY2hpdGVjdHVyZS50c1xuICovXG5jb25zdCBBUk1fSU5TVEFOQ0VfUFJFRklYRVMgPSBbXG4gIFwidDRnXCIsXG4gIFwiYzZnXCIsXG4gIFwiYzZnZFwiLFxuICBcImM2Z25cIixcbiAgXCJjN2dcIixcbiAgXCJjN2dkXCIsXG4gIFwiYzdnblwiLFxuICBcInI2Z1wiLFxuICBcInI2Z2RcIixcbiAgXCJyN2dcIixcbiAgXCJyN2dkXCIsXG4gIFwibTZnXCIsXG4gIFwibTZnZFwiLFxuICBcIm03Z1wiLFxuICBcIm03Z2RcIixcbiAgXCJhMVwiLFxuICBcIngyZ2RcIixcbiAgXCJpbTRnblwiLFxuICBcImlzNGdlblwiLFxuICBcImk0Z1wiLFxuICBcImhwYzdnXCJcbl07XG5cbi8qKlxuICogSW5mZXIgdGhlIEFNSSBoYXJkd2FyZSB0eXBlIGZyb20gYW4gRUMyIGluc3RhbmNlIHR5cGUuXG4gKiBVc2VzIHRoZSBpbnN0YW5jZSB0eXBlIHByZWZpeCB0byBkZXRlcm1pbmUgaWYgaXQncyBBUk0gKEdyYXZpdG9uKSBvciB4ODYtNjQuXG4gKlxuICogQHBhcmFtIGluc3RhbmNlVHlwZSAtIEVDMiBpbnN0YW5jZSB0eXBlIChlLmcuLCBcInQ0Zy5taWNyb1wiLCBcInQzLnNtYWxsXCIpXG4gKiBAcmV0dXJucyBBbWlIYXJkd2FyZVR5cGUuQVJNIGZvciBHcmF2aXRvbiBpbnN0YW5jZXMsIEFtaUhhcmR3YXJlVHlwZS5TVEFOREFSRCBmb3IgSW50ZWwvQU1EXG4gKi9cbmZ1bmN0aW9uIGluZmVyQW1pSGFyZHdhcmVUeXBlKGluc3RhbmNlVHlwZTogc3RyaW5nKTogQW1pSGFyZHdhcmVUeXBlIHtcbiAgY29uc3QgcHJlZml4ID0gaW5zdGFuY2VUeXBlLnNwbGl0KFwiLlwiKVswXSA/PyBpbnN0YW5jZVR5cGU7XG4gIHJldHVybiBBUk1fSU5TVEFOQ0VfUFJFRklYRVMuaW5jbHVkZXMocHJlZml4KVxuICAgID8gQW1pSGFyZHdhcmVUeXBlLkFSTVxuICAgIDogQW1pSGFyZHdhcmVUeXBlLlNUQU5EQVJEO1xufVxuXG4vKipcbiAqIENESyBBc3BlY3QgdGhhdCBmaXhlcyBjYXBhY2l0eSBwcm92aWRlciBkZWxldGlvbiBkZXBlbmRlbmNpZXMuXG4gKlxuICogVGhpcyBpcyBhIHdvcmthcm91bmQgZm9yIENESyBidWcgIzE1MzY2IHdoZXJlIEVDUyBzZXJ2aWNlcyBkb24ndCBwcm9wZXJseVxuICogZGVwZW5kIG9uIENmbkNsdXN0ZXJDYXBhY2l0eVByb3ZpZGVyQXNzb2NpYXRpb25zLCBjYXVzaW5nIFwiY2FwYWNpdHkgcHJvdmlkZXJcbiAqIGlzIGluIHVzZVwiIGVycm9ycyBkdXJpbmcgc3RhY2sgZGVsZXRpb24uXG4gKlxuICogVGhlIGFzcGVjdCBydW5zIGF0IHN5bnRoIHRpbWUgKHdoZW4gYXNzb2NpYXRpb25zIGV4aXN0KSBhbmQgYWRkczpcbiAqIC0gU2VydmljZSBkZXBlbmRzIG9uIENmbkNsdXN0ZXJDYXBhY2l0eVByb3ZpZGVyQXNzb2NpYXRpb25zXG4gKlxuICogREVMRVRFIG9yZGVyIGJlY29tZXM6IFNlcnZpY2VzIOKGkiBBc3NvY2lhdGlvbnMg4oaSIENsdXN0ZXJcbiAqXG4gKiBAc2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9hd3MvYXdzLWNkay9pc3N1ZXMvMTUzNjZcbiAqL1xuY2xhc3MgQ2FwYWNpdHlQcm92aWRlckRlcGVuZGVuY3lBc3BlY3QgaW1wbGVtZW50cyBJQXNwZWN0IHtcbiAgcHJpdmF0ZSByZWFkb25seSBjbHVzdGVyOiBDZGtDbHVzdGVyO1xuXG4gIGNvbnN0cnVjdG9yKGNsdXN0ZXI6IENka0NsdXN0ZXIpIHtcbiAgICB0aGlzLmNsdXN0ZXIgPSBjbHVzdGVyO1xuICB9XG5cbiAgdmlzaXQobm9kZTogSUNvbnN0cnVjdCk6IHZvaWQge1xuICAgIC8vIEZpbmQgRUNTIHNlcnZpY2VzIHRoYXQgYmVsb25nIHRvIHRoaXMgY2x1c3RlclxuICAgIGlmIChub2RlIGluc3RhbmNlb2YgRmFyZ2F0ZVNlcnZpY2UgfHwgbm9kZSBpbnN0YW5jZW9mIEVjMlNlcnZpY2UpIHtcbiAgICAgIC8vIEZpbmQgQ2ZuQ2x1c3RlckNhcGFjaXR5UHJvdmlkZXJBc3NvY2lhdGlvbnMgaW4gdGhlIGNsdXN0ZXIncyBkZXNjZW5kYW50c1xuICAgICAgY29uc3QgYXNzb2NpYXRpb25zID0gdGhpcy5jbHVzdGVyLm5vZGVcbiAgICAgICAgLmZpbmRBbGwoKVxuICAgICAgICAuZmluZChcbiAgICAgICAgICAoY2hpbGQpOiBjaGlsZCBpcyBDZm5DbHVzdGVyQ2FwYWNpdHlQcm92aWRlckFzc29jaWF0aW9ucyA9PlxuICAgICAgICAgICAgY2hpbGQgaW5zdGFuY2VvZiBDZm5DbHVzdGVyQ2FwYWNpdHlQcm92aWRlckFzc29jaWF0aW9uc1xuICAgICAgICApO1xuXG4gICAgICBpZiAoYXNzb2NpYXRpb25zKSB7XG4gICAgICAgIC8vIEFkZCBkZXBlbmRlbmN5OiBTZXJ2aWNlIOKGkiBBc3NvY2lhdGlvbnNcbiAgICAgICAgLy8gREVMRVRFIG9yZGVyOiBTZXJ2aWNlIGRlbGV0ZWQgZmlyc3QsIHRoZW4gQXNzb2NpYXRpb25zXG4gICAgICAgIG5vZGUubm9kZS5hZGREZXBlbmRlbmN5KGFzc29jaWF0aW9ucyk7XG4gICAgICB9XG4gICAgfVxuICB9XG59XG5cbmV4cG9ydCBlbnVtIFByb3RvY29sIHtcbiAgSFRUUCxcbiAgSFRUUFNcbn1cblxuZXhwb3J0IGVudW0gU2NhbGluZ1R5cGUge1xuICBDUFUgPSBQcmVkZWZpbmVkTWV0cmljLkVDU19TRVJWSUNFX0FWRVJBR0VfQ1BVX1VUSUxJWkFUSU9OLFxuICBNRU1PUlkgPSBQcmVkZWZpbmVkTWV0cmljLkVDU19TRVJWSUNFX0FWRVJBR0VfTUVNT1JZX1VUSUxJWkFUSU9OXG59XG5cbi8vIENhbm9uaWNhbCBzb3VyY2U6IEBmamFsbC9nZW5lcmF0b3Igc2NoZW1hcy9jb25zdGFudHMudHMg4oCUIGtlZXAgaW4gc3luY1xuZXhwb3J0IHR5cGUgRWNzQ2FwYWNpdHlQcm92aWRlciA9IFwiRkFSR0FURVwiIHwgXCJGQVJHQVRFX1NQT1RcIiB8IFwiRUMyXCI7XG5cbi8qKlxuICogRUMyIGNhcGFjaXR5IGNvbmZpZ3VyYXRpb24gZm9yIEVDUyBFQzItYmFja2VkIGNsdXN0ZXJzLlxuICogT25seSB1c2VkIHdoZW4gY2FwYWNpdHlQcm92aWRlciBpcyBcIkVDMlwiLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEVjMkNhcGFjaXR5Q29uZmlnIHtcbiAgLyoqIEVDMiBpbnN0YW5jZSB0eXBlLiBEZWZhdWx0OiBcInQ0Zy5taWNyb1wiICovXG4gIGluc3RhbmNlVHlwZT86IHN0cmluZztcbiAgLyoqIEFNSSBoYXJkd2FyZSB0eXBlLiBEZWZhdWx0OiBcIkFSTVwiIChHcmF2aXRvbiAtIGJldHRlciBjb3N0L3BlcmZvcm1hbmNlKSAqL1xuICBhbWlIYXJkd2FyZVR5cGU/OiBcIkFSTVwiIHwgXCJTVEFOREFSRFwiO1xuICAvKiogTWluaW11bSBudW1iZXIgb2YgaW5zdGFuY2VzLiBEZWZhdWx0OiAxICovXG4gIG1pbkNhcGFjaXR5PzogbnVtYmVyO1xuICAvKiogTWF4aW11bSBudW1iZXIgb2YgaW5zdGFuY2VzLiBEZWZhdWx0OiAzICovXG4gIG1heENhcGFjaXR5PzogbnVtYmVyO1xuICAvKiogTWVtb3J5IGxpbWl0IGluIE1pQiBmb3IgdGhlIGNvbnRhaW5lci4gRGVmYXVsdDogMTAyNCAqL1xuICBtZW1vcnlMaW1pdE1pQj86IG51bWJlcjtcbiAgLyoqIFdhcm0gcG9vbCBrZWVwcyBzdG9wcGVkIGluc3RhbmNlcyBmb3IgZmFzdGVyIHN0YXJ0ICgxMC0xNXMgdnMgNjAtOTBzKS5cbiAgICogIE1pcnJvcnMgZ2VuZXJhdG9yIFdhcm1Qb29sIHR5cGUgKGdlbmVyYXRvci9zcmMvc2NoZW1hcy9jb21wdXRlU2NoZW1hcy50cykuICovXG4gIHdhcm1Qb29sPzoge1xuICAgIC8qKiBNaW5pbXVtIGluc3RhbmNlcyB0byBrZWVwIGluIHRoZSB3YXJtIHBvb2wuIERlZmF1bHQ6IDEgKi9cbiAgICBtaW5TaXplPzogbnVtYmVyO1xuICAgIC8qKiBSZXR1cm4gaW5zdGFuY2VzIHRvIHRoZSBwb29sIG9uIHNjYWxlLWluIGluc3RlYWQgb2YgdGVybWluYXRpbmcuIERlZmF1bHQ6IHRydWUgKi9cbiAgICByZXVzZU9uU2NhbGVJbj86IGJvb2xlYW47XG4gIH07XG59XG5cbi8qKlxuICogRG9tYWluIGNvbmZpZ3VyYXRpb24gZm9yIEhUVFBTIGFuZCBETlMuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgRG9tYWluQmFzZUNvbmZpZyB7XG4gIGRvbWFpbk5hbWU6IHN0cmluZztcbiAgaG9zdGVkWm9uZT86IEZqYWxsSG9zdGVkWm9uZTtcbiAgY2VydGlmaWNhdGU/OiBDZXJ0aWZpY2F0ZTtcbiAgc2V0SWRlbnRpZmllcj86IHN0cmluZztcbiAgLyoqIEltcG9ydCB6b25lIGFuZCBjZXJ0IGZyb20gYSBtYW5hZ2VkIGRvbWFpbiBzdGFjayB2aWEgRm4uaW1wb3J0VmFsdWUoKSAqL1xuICBtYW5hZ2VkRG9tYWluPzogTWFuYWdlZERvbWFpbkV4cG9ydHM7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgTGF0ZW5jeURvbWFpbkNvbmZpZyBleHRlbmRzIERvbWFpbkJhc2VDb25maWcge1xuICByZWdpb246IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBXZWlnaHRlZERvbWFpbkNvbmZpZyBleHRlbmRzIERvbWFpbkJhc2VDb25maWcge1xuICB3ZWlnaHQ6IG51bWJlcjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBHZW9Mb2NhdGlvbkRvbWFpbkNvbmZpZyBleHRlbmRzIERvbWFpbkJhc2VDb25maWcge1xuICBnZW9Mb2NhdGlvbjogR2VvTG9jYXRpb247XG59XG5cbmV4cG9ydCB0eXBlIERvbWFpbkNvbmZpZyA9XG4gIHwgRG9tYWluQmFzZUNvbmZpZ1xuICB8IExhdGVuY3lEb21haW5Db25maWdcbiAgfCBXZWlnaHRlZERvbWFpbkNvbmZpZ1xuICB8IEdlb0xvY2F0aW9uRG9tYWluQ29uZmlnO1xuXG4vKipcbiAqIEludGVybmFsIGNvbmZpZ3VyYXRpb24gZm9yIGEgY29udGFpbmVyIGluIGEgbXVsdGktY29udGFpbmVyIEVDUyB0YXNrLlxuICpcbiAqIEluIG11bHRpLWNvbnRhaW5lciB0YXNrcywgdGhlIGZpcnN0IGNvbnRhaW5lciB3aXRoIGEgYHBvcnRgIGlzIHRoZSAqKnByaW1hcnkgY29udGFpbmVyKipcbiAqIHRoYXQgcmVjZWl2ZXMgbG9hZCBiYWxhbmNlciB0cmFmZmljLiBBbGwgb3RoZXIgY29udGFpbmVycyBhcmUgKipzaWRlY2FycyoqIHRoYXQgcHJvdmlkZVxuICogc3VwcG9ydGluZyBmdW5jdGlvbmFsaXR5IChsb2dnaW5nLCBtb25pdG9yaW5nLCBwcm94aWVzLCBldGMuKS5cbiAqXG4gKiBAZXhhbXBsZVxuICogLy8gUHJpbWFyeSBjb250YWluZXIgKGhhcyBwb3J0KSArIHNpZGVjYXIgKG5vIHBvcnQpXG4gKiBjb250YWluZXJzOiBbXG4gKiAgIHsgbmFtZTogXCJhcHBcIiwgcG9ydDogMzAwMCB9LCAgICAgICAgICAgLy8gUHJpbWFyeSAtIHJlY2VpdmVzIEFMQiB0cmFmZmljXG4gKiAgIHsgbmFtZTogXCJkYXRhZG9nXCIsIGltYWdlOiBcImRhdGFkb2cvYWdlbnRcIiB9ICAvLyBTaWRlY2FyIC0gbW9uaXRvcmluZ1xuICogXVxuICpcbiAqIEBpbnRlcm5hbFxuICovXG5leHBvcnQgaW50ZXJmYWNlIEVjc0NsdXN0ZXJDb250YWluZXJDb25maWcge1xuICAvKiogVW5pcXVlIGNvbnRhaW5lciBuYW1lICovXG4gIG5hbWU6IHN0cmluZztcbiAgLyoqXG4gICAqIENvbnRhaW5lciBpbWFnZS4gT3B0aW9uczpcbiAgICogLSBPbWl0OiBVc2VzIGRlZmF1bHQgRUNSIHJlcG9zaXRvcnkgKHByaW1hcnkgY29udGFpbmVyIG9ubHkpXG4gICAqIC0gc3RyaW5nOiBFQ1IgcmVwb3NpdG9yeSBuYW1lIG9yIHB1YmxpYyBpbWFnZSBVUkxcbiAgICogLSBSZXBvc2l0b3J5OiBDREsgRUNSIFJlcG9zaXRvcnkgY29uc3RydWN0XG4gICAqL1xuICBpbWFnZT86IHN0cmluZyB8IFJlcG9zaXRvcnk7XG4gIC8qKlxuICAgKiBQb3J0IHRoZSBjb250YWluZXIgbGlzdGVucyBvbi5cbiAgICogVGhlIGZpcnN0IGNvbnRhaW5lciB3aXRoIGEgcG9ydCBiZWNvbWVzIHRoZSAqKnByaW1hcnkgY29udGFpbmVyKipcbiAgICogYW5kIGlzIHJlZ2lzdGVyZWQgd2l0aCB0aGUgbG9hZCBiYWxhbmNlci5cbiAgICovXG4gIHBvcnQ/OiBudW1iZXI7XG4gIC8qKiBFbnZpcm9ubWVudCB2YXJpYWJsZXMgKi9cbiAgZW52aXJvbm1lbnQ/OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+O1xuICAvKipcbiAgICogU2VjcmV0cyBmcm9tIEFXUyBTU00gUGFyYW1ldGVyIFN0b3JlLlxuICAgKiBBcnJheSBvZiBzZWNyZXQgbmFtZXMgdGhhdCB3aWxsIGJlIGZldGNoZWQgZnJvbSB0aGUgc2VydmljZSdzIFNTTSBuYW1lc3BhY2UuXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIHNlY3JldHM6IFtcIkFQSV9LRVlcIiwgXCJEQl9QQVNTV09SRFwiXVxuICAgKi9cbiAgc2VjcmV0cz86IHN0cmluZ1tdO1xuICAvKiogU2VjcmV0cyBpbXBvcnRlZCBmcm9tIG90aGVyIENESyByZXNvdXJjZXMgKEFXUyBTZWNyZXRzIE1hbmFnZXIpICovXG4gIHNlY3JldHNJbXBvcnQ/OiB7IFtrZXk6IHN0cmluZ106IFNlY3JldEltcG9ydCB9O1xuICAvKiogQ29tbWFuZCB0byBydW4gaW4gdGhlIGNvbnRhaW5lciAqL1xuICBjb21tYW5kPzogc3RyaW5nW107XG4gIC8qKiBFbnRyeSBwb2ludCBmb3IgdGhlIGNvbnRhaW5lciAqL1xuICBlbnRyeVBvaW50Pzogc3RyaW5nW107XG4gIC8qKlxuICAgKiBXaGV0aGVyIHRoaXMgY29udGFpbmVyIGlzIGVzc2VudGlhbC5cbiAgICogSWYgYW4gZXNzZW50aWFsIGNvbnRhaW5lciBzdG9wcywgYWxsIGNvbnRhaW5lcnMgaW4gdGhlIHRhc2sgc3RvcC5cbiAgICogRGVmYXVsdDogdHJ1ZSBmb3IgcHJpbWFyeSBjb250YWluZXIsIHRydWUgZm9yIHNpZGVjYXJzXG4gICAqL1xuICBlc3NlbnRpYWw/OiBib29sZWFuO1xuICAvKipcbiAgICogSGVhbHRoIGNoZWNrIGNvbmZpZ3VyYXRpb24uXG4gICAqIERlZmF1bHQ6IEZvciBwcmltYXJ5IGNvbnRhaW5lciB3aXRoIHBvcnQsIHVzZXMgY3VybCBoZWFsdGggY2hlY2suXG4gICAqL1xuICBoZWFsdGhDaGVjaz86IHtcbiAgICBjb21tYW5kOiBzdHJpbmdbXTtcbiAgICBpbnRlcnZhbD86IG51bWJlcjtcbiAgICB0aW1lb3V0PzogbnVtYmVyO1xuICAgIHJldHJpZXM/OiBudW1iZXI7XG4gICAgc3RhcnRQZXJpb2Q/OiBudW1iZXI7XG4gIH07XG59XG5cbi8qKlxuICogQ2x1c3Rlci1sZXZlbCBjb25maWd1cmF0aW9uLlxuICogQ29udHJvbHMgdGhlIHNoYXJlZCBBTEIgZm9yIGFsbCBzZXJ2aWNlcyBpbiB0aGlzIGNsdXN0ZXIuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgRWNzQ2x1c3RlckNsdXN0ZXJDb25maWcge1xuICAvKipcbiAgICogRG9tYWluIGZvciBIVFRQUyBhY2Nlc3MuXG4gICAqIC0gT21pdDogQUxCIGNyZWF0ZWQgd2l0aCBkZWZhdWx0IEROUyAoKi5lbGIuYW1hem9uYXdzLmNvbSlcbiAgICogLSBTcGVjaWZpZWQ6IENyZWF0ZXMgQUNNIGNlcnRpZmljYXRlICsgUm91dGU1MyBETlMgQSByZWNvcmRcbiAgICovXG4gIGRvbWFpbj86IHN0cmluZztcblxuICAvKipcbiAgICogTG9hZCBiYWxhbmNlciBjb25maWd1cmF0aW9uLlxuICAgKiAtIGZhbHNlOiBObyBBTEIgKGZvciB3b3JrZXJzL2ludGVybmFsIHNlcnZpY2VzKVxuICAgKiAtIFwicHVibGljXCI6IEludGVybmV0LWZhY2luZyBBTEIgKGRlZmF1bHQpXG4gICAqIC0gXCJpbnRlcm5hbFwiOiBWUEMtb25seSBBTEJcbiAgICovXG4gIGxvYWRCYWxhbmNlcj86IGZhbHNlIHwgXCJwdWJsaWNcIiB8IFwiaW50ZXJuYWxcIjtcblxuICAvKipcbiAgICogRW5hYmxlIGRpcmVjdCBFQzIgYWNjZXNzIHdpdGhvdXQgQUxCLlxuICAgKiBPcGVucyBjb250YWluZXIgcG9ydHMgb24gc2VjdXJpdHkgZ3JvdXAgZm9yIGRpcmVjdCBhY2Nlc3MgdmlhIEVDMiBwdWJsaWMgSVAuXG4gICAqIFVzZXMgaG9zdCBuZXR3b3JrIG1vZGUgZm9yIHByZWRpY3RhYmxlIHBvcnQgbWFwcGluZyAoY29udGFpbmVyOjMwMDAg4oaSIGhvc3Q6MzAwMCkuXG4gICAqIE9ubHkgdmFsaWQgd2l0aCBFQzIgY2FwYWNpdHkgcHJvdmlkZXIuXG4gICAqL1xuICBkaXJlY3RBY2Nlc3M/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBEb21haW4gY29uZmlndXJhdGlvbiBmb3IgYWR2YW5jZWQgcm91dGluZyBwb2xpY2llcyAobGF0ZW5jeSwgd2VpZ2h0ZWQsIGdlbykuXG4gICAqIE9ubHkgdXNlZCB3aGVuIGRvbWFpbiBpcyBzcGVjaWZpZWQuXG4gICAqL1xuICBkb21haW5Db25maWc/OiBEb21haW5Db25maWc7XG59XG5cbi8qKlxuICogUm91dGluZyBjb25maWd1cmF0aW9uIGZvciBwYXRoL2hvc3QtYmFzZWQgcm91dGluZyBvbiB0aGUgQUxCLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEVjc1JvdXRpbmdDb25maWcge1xuICAvKiogUGF0aCBwYXR0ZXJuIGZvciByb3V0aW5nIChlLmcuLCBcIi9hcGkvKlwiLCBcIi91c2Vycy8qXCIpICovXG4gIHBhdGg/OiBzdHJpbmc7XG4gIC8qKiBIb3N0IGhlYWRlciBmb3Igcm91dGluZyAoZS5nLiwgXCJhcGkuZXhhbXBsZS5jb21cIikgKi9cbiAgaG9zdD86IHN0cmluZztcbiAgLyoqIFByaW9yaXR5IGZvciB0aGlzIHJvdXRpbmcgcnVsZSAoMS01MDAwMCkuIExvd2VyID0gaGlnaGVyIHByaW9yaXR5LiAqL1xuICBwcmlvcml0eT86IG51bWJlcjtcbiAgLyoqIEhlYWx0aCBjaGVjayBwYXRoIGZvciB0aGlzIHNlcnZpY2UncyB0YXJnZXQgZ3JvdXAuIERlZmF1bHQ6IFwiL1wiICovXG4gIGhlYWx0aENoZWNrUGF0aD86IHN0cmluZztcbn1cblxuLyoqXG4gKiBDb25maWd1cmF0aW9uIGZvciBhIHNlcnZpY2UgaW4gYW4gRUNTIGNsdXN0ZXIuXG4gKiBFYWNoIHNlcnZpY2UgZ2V0cyBpdHMgb3duIHRhc2sgZGVmaW5pdGlvbiwgc2NhbGluZywgYW5kIHRhcmdldCBncm91cC5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBFY3NTZXJ2aWNlUHJvcHMge1xuICAvKiogU2VydmljZSBuYW1lICh1bmlxdWUgd2l0aGluIGNsdXN0ZXIpICovXG4gIG5hbWU6IHN0cmluZztcblxuICAvKipcbiAgICogQ29udGFpbmVyIGltYWdlIGZvciB0aGlzIHNlcnZpY2UuXG4gICAqIC0gT21pdDogVXNlcyBjbHVzdGVyJ3MgZGVmYXVsdCBFQ1IgcmVwb3NpdG9yeVxuICAgKiAtIHN0cmluZzogRUNSIHJlcG9zaXRvcnkgbmFtZSBvciBwdWJsaWMgaW1hZ2UgVVJMXG4gICAqIC0gUmVwb3NpdG9yeTogQ0RLIEVDUiBSZXBvc2l0b3J5IGNvbnN0cnVjdFxuICAgKi9cbiAgaW1hZ2U/OiBzdHJpbmcgfCBSZXBvc2l0b3J5O1xuXG4gIC8qKlxuICAgKiBDb250YWluZXIgY29uZmlndXJhdGlvbnMgZm9yIHRoaXMgc2VydmljZS5cbiAgICogVGhlIGZpcnN0IGNvbnRhaW5lciB3aXRoIGEgcG9ydCBpcyB0aGUgKipwcmltYXJ5IGNvbnRhaW5lcioqIChyZWNlaXZlcyBBTEIgdHJhZmZpYykuXG4gICAqL1xuICBjb250YWluZXJzOiBFY3NDbHVzdGVyQ29udGFpbmVyQ29uZmlnW107XG5cbiAgLyoqIENQVSB1bml0cyBmb3IgdGhpcyBzZXJ2aWNlJ3MgdGFza3MgKDI1Ni00MDk2KSAqL1xuICBjcHU/OiBudW1iZXI7XG5cbiAgLyoqIE1lbW9yeSBpbiBNaUIgZm9yIHRoaXMgc2VydmljZSdzIHRhc2tzICg1MTItMzA3MjApICovXG4gIG1lbW9yeUxpbWl0TWlCPzogbnVtYmVyO1xuXG4gIC8qKiBEZXNpcmVkIG51bWJlciBvZiB0YXNrcy4gRGVmYXVsdDogMiAqL1xuICBkZXNpcmVkQ291bnQ/OiBudW1iZXI7XG5cbiAgLyoqIFNjYWxpbmcgdHlwZSAoQ1BVIG9yIE1FTU9SWSkuIE9taXQgdG8gZGlzYWJsZSBhdXRvLXNjYWxpbmcuICovXG4gIHNjYWxpbmdUeXBlPzogU2NhbGluZ1R5cGU7XG5cbiAgLyoqIE1pbmltdW0gbnVtYmVyIG9mIHRhc2tzIGZvciBhdXRvLXNjYWxpbmcuIERlZmF1bHQ6IDIgKi9cbiAgbWluQ2FwYWNpdHk/OiBudW1iZXI7XG5cbiAgLyoqIE1heGltdW0gbnVtYmVyIG9mIHRhc2tzIGZvciBhdXRvLXNjYWxpbmcuIERlZmF1bHQ6IDEwICovXG4gIG1heENhcGFjaXR5PzogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBSb3V0aW5nIHJ1bGVzIGZvciB0aGlzIHNlcnZpY2Ugb24gdGhlIGNsdXN0ZXIncyBBTEIuXG4gICAqIFJlcXVpcmVkIHdoZW4gY2x1c3RlciBoYXMgbXVsdGlwbGUgc2VydmljZXMgd2l0aCBwb3J0cy5cbiAgICogQ2FuIGJlIGEgc2luZ2xlIHJ1bGUgb3IgYW4gYXJyYXkgb2YgcnVsZXMgcG9pbnRpbmcgdG8gdGhlIHNhbWUgdGFyZ2V0IGdyb3VwLlxuICAgKi9cbiAgcm91dGluZz86IEVjc1JvdXRpbmdDb25maWcgfCBFY3NSb3V0aW5nQ29uZmlnW107XG5cbiAgLyoqXG4gICAqIEFkZGl0aW9uYWwgaW5saW5lIHBvbGljaWVzIGZvciB0aGlzIHNlcnZpY2UncyB0YXNrIHJvbGUuXG4gICAqIEFkZGVkIG9uIHRvcCBvZiB0aGUgZGVmYXVsdCBFQ1MgRXhlYyBwZXJtaXNzaW9ucy5cbiAgICovXG4gIHRhc2tSb2xlSW5saW5lUG9saWNpZXM/OiB7XG4gICAgW25hbWU6IHN0cmluZ106IFBvbGljeURvY3VtZW50O1xuICB9O1xuXG4gIC8qKlxuICAgKiBBZGRpdGlvbmFsIG1hbmFnZWQgcG9saWNpZXMgZm9yIHRoaXMgc2VydmljZSdzIHRhc2sgcm9sZS5cbiAgICogQWRkZWQgb24gdG9wIG9mIHRoZSBkZWZhdWx0IEVDUyBFeGVjIHBlcm1pc3Npb25zLlxuICAgKi9cbiAgdGFza1JvbGVNYW5hZ2VkUG9saWNpZXM/OiBJTWFuYWdlZFBvbGljeVtdO1xuXG4gIC8qKlxuICAgKiBSZXNvdXJjZXMgdGhpcyBzZXJ2aWNlIG5lZWRzIHRvIGNvbm5lY3QgdG8gKGUuZy4sIGRhdGFiYXNlcywgUzMgYnVja2V0cywgU1FTIHF1ZXVlcykuXG4gICAqIENyZWF0ZXMgc2VjdXJpdHkgZ3JvdXAgcnVsZXMgZm9yIElDb25uZWN0YWJsZSByZXNvdXJjZXMgYW5kIElBTSBncmFudHMgZm9yIElBTSByZXNvdXJjZXMuXG4gICAqXG4gICAqIFN1cHBvcnRzOlxuICAgKiAtIElDb25uZWN0YWJsZTogU2VjdXJpdHkgZ3JvdXAgcmVzb3VyY2VzIChSRFMsIEVDUywgZXRjLilcbiAgICogLSBJU3RvcmFnZUNvbm5lY3RvcjogUzMgYnVja2V0cyAoSUFNIGdyYW50cylcbiAgICogLSBJRHluYW1vREJDb25uZWN0b3I6IER5bmFtb0RCIHRhYmxlcyAoSUFNIGdyYW50cylcbiAgICogLSBJUXVldWVDb25uZWN0b3I6IFNRUyBxdWV1ZXMgKElBTSBncmFudHMpXG4gICAqIC0gQ29ubmVjdGlvbkNvbmZpZzogRXhwbGljaXQgYWNjZXNzIGxldmVsIGNvbmZpZ3VyYXRpb25cbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogY29ubmVjdGlvbnM6IFtcbiAgICogICBkYXRhYmFzZSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBTZWN1cml0eSBncm91cCAoUkRTKVxuICAgKiAgIHsgcmVzb3VyY2U6IGNhY2hlLCBhY2Nlc3M6IFwicmVhZFwiIH0sICAgLy8gUmVhZC1vbmx5IER5bmFtb0RCXG4gICAqICAgeyByZXNvdXJjZTogYnVja2V0LCBhY2Nlc3M6IFwid3JpdGVcIiB9LCAvLyBXcml0ZS1vbmx5IFMzXG4gICAqICAgeyByZXNvdXJjZTogcXVldWUsIGFjY2VzczogXCJjb25zdW1lXCIgfSAvLyBDb25zdW1lLW9ubHkgU1FTXG4gICAqIF1cbiAgICovXG4gIGNvbm5lY3Rpb25zPzogQ29ubmVjdGlvblNwZWNbXTtcblxuICAvKipcbiAgICogQ2FwYWNpdHkgcHJvdmlkZXIgZm9yIHRoaXMgc2VydmljZS4gUkVRVUlSRUQuXG4gICAqIEVhY2ggc2VydmljZSBzcGVjaWZpZXMgaXRzIG93biBjYXBhY2l0eSBwcm92aWRlci5cbiAgICovXG4gIGNhcGFjaXR5UHJvdmlkZXI6IEVjc0NhcGFjaXR5UHJvdmlkZXI7XG5cbiAgLyoqXG4gICAqIEVDMiBjYXBhY2l0eSBjb25maWd1cmF0aW9uIGZvciB0aGlzIHNlcnZpY2UuXG4gICAqIE9ubHkgdXNlZCB3aGVuIHNlcnZpY2UgY2FwYWNpdHlQcm92aWRlciBpcyBcIkVDMlwiLlxuICAgKiBTZXJ2aWNlcyB3aXRoIG1hdGNoaW5nIGVjMkNvbmZpZyBzaGFyZSBhbiBBU0cgZm9yIGVmZmljaWVuY3kuXG4gICAqL1xuICBlYzJDb25maWc/OiBFYzJDYXBhY2l0eUNvbmZpZztcblxuICAvKipcbiAgICogU1NNIFBhcmFtZXRlciBTdG9yZSBwYXRoIGZvciBzZWNyZXRzLlxuICAgKiBJZiBjb250YWluZXJzIGhhdmUgc2VjcmV0cyBkZWZpbmVkLCB0aGlzIHBhdGggaXMgdXNlZCBhcyB0aGUgYmFzZSBwYXRoLlxuICAgKiBGb3JtYXQ6IC88YXBwPi88Y2x1c3Rlcj4vPHNlcnZpY2U+XG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIHNzbVNlY3JldHNQYXRoOiBcIi9teWFwcC9hcGktY2x1c3Rlci91c2Vyc1wiXG4gICAqL1xuICBzc21TZWNyZXRzUGF0aD86IHN0cmluZztcblxuICAvKipcbiAgICogRG9ja2VyIGJ1aWxkIHRhcmdldCBzdGFnZSBmb3IgbXVsdGktc3RhZ2UgRG9ja2VyZmlsZXMuXG4gICAqIFdoZW4gc3BlY2lmaWVkLCBhcHBlbmRzIGAtPHRhcmdldD5gIHRvIHRoZSBpbWFnZSB0YWcuXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIC8vIFdpdGggZG9ja2VyVGFyZ2V0OiBcImFwaVwiLCBpbWFnZSB0YWcgYmVjb21lczogbXlzZXJ2aWNlLWFwaS1sYXRlc3RcbiAgICogZG9ja2VyVGFyZ2V0OiBcImFwaVwiXG4gICAqL1xuICBkb2NrZXJUYXJnZXQ/OiBzdHJpbmc7XG59XG5cbi8qKlxuICogUHJvcHMgZm9yIGNyZWF0aW5nIGFuIEVDUyBjbHVzdGVyIHdpdGggbXVsdGlwbGUgc2VydmljZXMuXG4gKi9cbmV4cG9ydCB0eXBlIEVjc0NsdXN0ZXJQcm9wcyA9IHtcbiAgLyoqIENsdXN0ZXIgbmFtZSAqL1xuICBjbHVzdGVyTmFtZTogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBBcHBsaWNhdGlvbiBuYW1lIGZvciBTU00gc2VjcmV0cyBuYW1lc3BhY2UuXG4gICAqIFJlcXVpcmVkIHdoZW4gYW55IGNvbnRhaW5lciB1c2VzIHNlY3JldHMgd2l0aG91dCBleHBsaWNpdCBzc21TZWNyZXRzUGF0aC5cbiAgICogVXNlZCB0byBidWlsZCB0aGUgcGF0aDogLzxhcHBOYW1lPi88Y2x1c3Rlck5hbWU+LzxzZXJ2aWNlTmFtZT5cbiAgICovXG4gIGFwcE5hbWU/OiBzdHJpbmc7XG5cbiAgLyoqIFZQQyB0byBkZXBsb3kgaW50byAqL1xuICB2cGM/OiBJVnBjO1xuXG4gIC8qKiBEZWZhdWx0IEVDUiByZXBvc2l0b3J5IG9yIGNvbnRhaW5lciBpbWFnZSAqL1xuICBlY3JSZXBvc2l0b3J5OiBSZXBvc2l0b3J5IHwgUmVwb3NpdG9yeUltYWdlIHwgc3RyaW5nO1xuXG4gIC8vIE5vdGU6IGNhcGFjaXR5UHJvdmlkZXIgYW5kIGVjMkNvbmZpZyBhcmUgcGVyLXNlcnZpY2Ugb25seSAoaW4gRWNzU2VydmljZVByb3BzKVxuXG4gIC8qKlxuICAgKiBDbHVzdGVyIGNvbmZpZ3VyYXRpb24uXG4gICAqIENvbnRyb2xzIHRoZSBzaGFyZWQgQUxCIGZvciBhbGwgc2VydmljZXMuXG4gICAqL1xuICBjbHVzdGVyPzogRWNzQ2x1c3RlckNsdXN0ZXJDb25maWc7XG5cbiAgLyoqXG4gICAqIFNlcnZpY2VzIGluIHRoaXMgY2x1c3Rlci5cbiAgICogRWFjaCBzZXJ2aWNlIGdldHMgaXRzIG93biB0YXNrIGRlZmluaXRpb24sIHNjYWxpbmcsIGFuZCB0YXJnZXQgZ3JvdXAuXG4gICAqIEVhY2ggc2VydmljZSBNVVNUIHNwZWNpZnkgaXRzIG93biBjYXBhY2l0eVByb3ZpZGVyLlxuICAgKiBBbGwgc2VydmljZXMgc2hhcmUgdGhlIGNsdXN0ZXIncyBBTEIgKHVubGVzcyBkaXNhYmxlZCkuXG4gICAqIFRhc2sgcm9sZSBwb2xpY2llcyBhcmUgY29uZmlndXJlZCBwZXItc2VydmljZSBmb3IgbGVhc3QtcHJpdmlsZWdlLlxuICAgKi9cbiAgc2VydmljZXM6IEVjc1NlcnZpY2VQcm9wc1tdO1xufTtcblxuLyoqXG4gKiBEYXRhIHRyYWNrZWQgZm9yIGVhY2ggc2VydmljZSBpbiB0aGUgY2x1c3Rlci5cbiAqL1xuaW50ZXJmYWNlIFNlcnZpY2VEYXRhIHtcbiAgc2VydmljZTogRmFyZ2F0ZVNlcnZpY2UgfCBFYzJTZXJ2aWNlO1xuICB0YXNrRGVmaW5pdGlvbjogRmFyZ2F0ZVRhc2tEZWZpbml0aW9uIHwgRWMyVGFza0RlZmluaXRpb247XG4gIC8qKiBSb2xlIGZvciBFQ1MgYWdlbnQgKHB1bGwgaW1hZ2VzLCB3cml0ZSBsb2dzLCBpbmplY3Qgc2VjcmV0cykgKi9cbiAgZXhlY3V0aW9uUm9sZTogUm9sZTtcbiAgLyoqIFJvbGUgZm9yIGFwcGxpY2F0aW9uIGNvZGUgKHVzZXIgcG9saWNpZXMsIEVDUyBFeGVjKSAqL1xuICB0YXNrUm9sZTogUm9sZTtcbiAgY29udGFpbmVyczogQ29udGFpbmVyRGVmaW5pdGlvbltdO1xuICBwcmltYXJ5Q29udGFpbmVyPzogQ29udGFpbmVyRGVmaW5pdGlvbjtcbiAgdGFyZ2V0R3JvdXA/OiBJQXBwbGljYXRpb25UYXJnZXRHcm91cDtcbiAgc2NhbGluZ1BvbGljeT86IFRhcmdldFRyYWNraW5nU2NhbGluZ1BvbGljeTtcbn1cblxuLyoqXG4gKiBFQ1MgQ2x1c3RlciBzdXBwb3J0aW5nIG11bHRpcGxlIHNlcnZpY2VzIHdpdGggYSBzaGFyZWQgQUxCLlxuICpcbiAqIEBleGFtcGxlXG4gKiAvLyBTaW5nbGUgc2VydmljZSBjbHVzdGVyXG4gKiBuZXcgRWNzQ2x1c3RlcihzY29wZSwgXCJXZWJDbHVzdGVyXCIsIHtcbiAqICAgY2x1c3Rlck5hbWU6IFwiV2ViQ2x1c3RlclwiLFxuICogICBlY3JSZXBvc2l0b3J5OiBlY3IsXG4gKiAgIHNlcnZpY2VzOiBbXG4gKiAgICAgeyBuYW1lOiBcIndlYlwiLCBjb250YWluZXJzOiBbeyBuYW1lOiBcImFwcFwiLCBwb3J0OiAzMDAwIH1dIH1cbiAqICAgXVxuICogfSk7XG4gKlxuICogQGV4YW1wbGVcbiAqIC8vIE11bHRpLXNlcnZpY2UgY2x1c3RlciB3aXRoIHJvdXRpbmdcbiAqIG5ldyBFY3NDbHVzdGVyKHNjb3BlLCBcIkFwaUNsdXN0ZXJcIiwge1xuICogICBjbHVzdGVyTmFtZTogXCJBcGlDbHVzdGVyXCIsXG4gKiAgIGNsdXN0ZXI6IHsgZG9tYWluOiBcImFwaS5leGFtcGxlLmNvbVwiIH0sXG4gKiAgIGVjclJlcG9zaXRvcnk6IGVjcixcbiAqICAgc2VydmljZXM6IFtcbiAqICAgICB7IG5hbWU6IFwidXNlcnNcIiwgY29udGFpbmVyczogW3sgbmFtZTogXCJhcHBcIiwgcG9ydDogMzAwMCB9XSwgcm91dGluZzogeyBwYXRoOiBcIi91c2Vycy8qXCIgfSB9LFxuICogICAgIHsgbmFtZTogXCJvcmRlcnNcIiwgY29udGFpbmVyczogW3sgbmFtZTogXCJhcHBcIiwgcG9ydDogMzAwMSB9XSwgcm91dGluZzogeyBwYXRoOiBcIi9vcmRlcnMvKlwiIH0gfVxuICogICBdXG4gKiB9KTtcbiAqXG4gKiBAZXhhbXBsZVxuICogLy8gV29ya2VyIGNsdXN0ZXIgKG5vIEFMQilcbiAqIG5ldyBFY3NDbHVzdGVyKHNjb3BlLCBcIldvcmtlcnNcIiwge1xuICogICBjbHVzdGVyTmFtZTogXCJXb3JrZXJzXCIsXG4gKiAgIGNsdXN0ZXI6IHsgbG9hZEJhbGFuY2VyOiBmYWxzZSB9LFxuICogICBlY3JSZXBvc2l0b3J5OiBlY3IsXG4gKiAgIHNlcnZpY2VzOiBbXG4gKiAgICAgeyBuYW1lOiBcInByb2Nlc3NvclwiLCBjb250YWluZXJzOiBbeyBuYW1lOiBcIndvcmtlclwiIH1dIH1cbiAqICAgXVxuICogfSk7XG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIEVjc0NsdXN0ZXIgZXh0ZW5kcyBDb25zdHJ1Y3QgaW1wbGVtZW50cyBJQ29ubmVjdGFibGUge1xuICBwdWJsaWMgY29ubmVjdGlvbnMhOiBDb25uZWN0aW9ucztcblxuICAvLyBDbHVzdGVyLWxldmVsIHJlc291cmNlc1xuICBwcml2YXRlIGNsdXN0ZXIhOiBDZGtDbHVzdGVyO1xuICBwcml2YXRlIGxvYWRCYWxhbmNlcj86IEFwcGxpY2F0aW9uTG9hZEJhbGFuY2VyO1xuICBwcml2YXRlIGxvYWRCYWxhbmNlckxpc3RlbmVyPzogQXBwbGljYXRpb25MaXN0ZW5lcjtcbiAgcHJpdmF0ZSBob3N0ZWRab25lPzogSUhvc3RlZFpvbmU7XG4gIHByaXZhdGUgY2VydGlmaWNhdGU/OiBJQ2VydGlmaWNhdGU7XG4gIHByaXZhdGUgYVJlY29yZD86IEFSZWNvcmQ7XG5cbiAgLy8gRUMyLXNwZWNpZmljXG4gIHByaXZhdGUgYXV0b1NjYWxpbmdHcm91cD86IEF1dG9TY2FsaW5nR3JvdXA7XG4gIHByaXZhdGUgYXNnU2VjdXJpdHlHcm91cD86IFNlY3VyaXR5R3JvdXA7XG4gIHByaXZhdGUgYXNnQ2FwYWNpdHlQcm92aWRlcj86IEFzZ0NhcGFjaXR5UHJvdmlkZXI7XG4gIHByaXZhdGUgbG9hZEJhbGFuY2VyU2VjdXJpdHlHcm91cD86IFNlY3VyaXR5R3JvdXA7XG5cbiAgLy8gUGVyLXNlcnZpY2UgdHJhY2tpbmdcbiAgcHJpdmF0ZSBzZXJ2aWNlcyA9IG5ldyBNYXA8c3RyaW5nLCBTZXJ2aWNlRGF0YT4oKTtcblxuICAvLyBQZXItc2VydmljZSBBU0cgY2FwYWNpdHkgcHJvdmlkZXJzIChrZXllZCBieSBFQzIgY29uZmlnIHNpZ25hdHVyZSlcbiAgcHJpdmF0ZSBhc2dDYXBhY2l0eVByb3ZpZGVycyA9IG5ldyBNYXA8c3RyaW5nLCBBc2dDYXBhY2l0eVByb3ZpZGVyPigpO1xuXG4gIC8vIENvbmZpZ3VyYXRpb25cbiAgcHJpdmF0ZSBzY29wZTogQ29uc3RydWN0O1xuICBwcml2YXRlIHByb3BzOiBFY3NDbHVzdGVyUHJvcHM7XG4gIHByaXZhdGUgb3V0cHV0TmFtZTogc3RyaW5nO1xuICBwcml2YXRlIGxvYWRCYWxhbmNlckRpc2FibGVkOiBib29sZWFuO1xuICBwcml2YXRlIGRpcmVjdEFjY2Vzc0VuYWJsZWQ6IGJvb2xlYW47XG4gIHByaXZhdGUgbmV4dFByaW9yaXR5ID0gMTAwO1xuICBwcml2YXRlIHVzZWRQcmlvcml0aWVzID0gbmV3IFNldDxudW1iZXI+KCk7XG5cbiAgY29uc3RydWN0b3Ioc2NvcGU6IENvbnN0cnVjdCwgaWQ6IHN0cmluZywgcHJvcHM6IEVjc0NsdXN0ZXJQcm9wcykge1xuICAgIHN1cGVyKHNjb3BlLCBpZCk7XG5cbiAgICB0aGlzLnNjb3BlID0gc2NvcGU7XG4gICAgdGhpcy5wcm9wcyA9IHByb3BzO1xuICAgIC8vIFNhbml0aXNlIGNsdXN0ZXIgbmFtZSBmb3IgQ2xvdWRGb3JtYXRpb24gb3V0cHV0IGtleXMgKG11c3QgYmUgYWxwaGFudW1lcmljKVxuICAgIHRoaXMub3V0cHV0TmFtZSA9IHRvUGFzY2FsQ2FzZShwcm9wcy5jbHVzdGVyTmFtZSk7XG4gICAgdGhpcy5kaXJlY3RBY2Nlc3NFbmFibGVkID0gcHJvcHMuY2x1c3Rlcj8uZGlyZWN0QWNjZXNzID09PSB0cnVlO1xuICAgIHRoaXMubG9hZEJhbGFuY2VyRGlzYWJsZWQgPVxuICAgICAgcHJvcHMuY2x1c3Rlcj8ubG9hZEJhbGFuY2VyID09PSBmYWxzZSB8fCB0aGlzLmRpcmVjdEFjY2Vzc0VuYWJsZWQ7XG5cbiAgICB0aGlzLnZhbGlkYXRlUHJvcHMocHJvcHMpO1xuXG4gICAgdGhpcy5hZGRDbHVzdGVyKHByb3BzKTtcblxuICAgIGZvciAoY29uc3Qgc2VydmljZVByb3BzIG9mIHByb3BzLnNlcnZpY2VzKSB7XG4gICAgICBpZiAoc2VydmljZVByb3BzLmNhcGFjaXR5UHJvdmlkZXIgPT09IFwiRUMyXCIpIHtcbiAgICAgICAgdGhpcy5nZXRPckNyZWF0ZUFzZ0NhcGFjaXR5UHJvdmlkZXIoc2VydmljZVByb3BzKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoIXRoaXMubG9hZEJhbGFuY2VyRGlzYWJsZWQpIHtcbiAgICAgIHRoaXMuYWRkTG9hZEJhbGFuY2VyKHByb3BzKTtcblxuICAgICAgaWYgKHByb3BzLmNsdXN0ZXI/LmRvbWFpbiB8fCBwcm9wcy5jbHVzdGVyPy5kb21haW5Db25maWcpIHtcbiAgICAgICAgdGhpcy5hZGRIb3N0ZWRab25lKHByb3BzKTtcbiAgICAgIH1cblxuICAgICAgdGhpcy5hZGRMb2FkQmFsYW5jZXJMaXN0ZW5lcihwcm9wcyk7XG4gICAgfSBlbHNlIGlmICh0aGlzLmRpcmVjdEFjY2Vzc0VuYWJsZWQpIHtcbiAgICAgIHRoaXMuYWRkRGlyZWN0QWNjZXNzT3V0cHV0cyhwcm9wcyk7XG4gICAgfVxuXG4gICAgZm9yIChjb25zdCBzZXJ2aWNlUHJvcHMgb2YgcHJvcHMuc2VydmljZXMpIHtcbiAgICAgIHRoaXMuYWRkU2VydmljZVRvQ2x1c3RlcihzZXJ2aWNlUHJvcHMpO1xuICAgIH1cblxuICAgIHRoaXMuYWRkRGVwbG95YWJsZVNlcnZpY2VPdXRwdXRzKHByb3BzKTtcblxuICAgIHRoaXMuc2V0dXBDb25uZWN0aW9ucyhwcm9wcyk7XG5cbiAgICBBc3BlY3RzLm9mKHRoaXMpLmFkZChuZXcgQ2FwYWNpdHlQcm92aWRlckRlcGVuZGVuY3lBc3BlY3QodGhpcy5jbHVzdGVyKSk7XG4gIH1cblxuICAvKiogR2V0IHRoZSBjbHVzdGVyJ3MgbG9hZCBiYWxhbmNlci4gVW5kZWZpbmVkIGlmIGRpc2FibGVkLiAqL1xuICBnZXRMb2FkQmFsYW5jZXIoKTogQXBwbGljYXRpb25Mb2FkQmFsYW5jZXIgfCB1bmRlZmluZWQge1xuICAgIHJldHVybiB0aGlzLmxvYWRCYWxhbmNlcjtcbiAgfVxuXG4gIC8qKiBHZXQgdGhlIGxvYWQgYmFsYW5jZXIncyBsaXN0ZW5lci4gVW5kZWZpbmVkIGlmIGRpc2FibGVkLiAqL1xuICBnZXRMaXN0ZW5lcigpOiBBcHBsaWNhdGlvbkxpc3RlbmVyIHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gdGhpcy5sb2FkQmFsYW5jZXJMaXN0ZW5lcjtcbiAgfVxuXG4gIC8qKiBHZXQgYSBzcGVjaWZpYyBzZXJ2aWNlIGJ5IG5hbWUuICovXG4gIGdldFNlcnZpY2UobmFtZTogc3RyaW5nKTogRmFyZ2F0ZVNlcnZpY2UgfCBFYzJTZXJ2aWNlIHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gdGhpcy5zZXJ2aWNlcy5nZXQobmFtZSk/LnNlcnZpY2U7XG4gIH1cblxuICAvKiogR2V0IGFsbCBzZXJ2aWNlcyBpbiB0aGlzIGNsdXN0ZXIuICovXG4gIGdldFNlcnZpY2VzKCk6IE1hcDxzdHJpbmcsIEZhcmdhdGVTZXJ2aWNlIHwgRWMyU2VydmljZT4ge1xuICAgIGNvbnN0IHJlc3VsdCA9IG5ldyBNYXA8c3RyaW5nLCBGYXJnYXRlU2VydmljZSB8IEVjMlNlcnZpY2U+KCk7XG4gICAgZm9yIChjb25zdCBbbmFtZSwgZGF0YV0gb2YgdGhpcy5zZXJ2aWNlcykge1xuICAgICAgcmVzdWx0LnNldChuYW1lLCBkYXRhLnNlcnZpY2UpO1xuICAgIH1cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG5cbiAgLyoqIEdldCB0aGUgRUNTIGNsdXN0ZXIgY29uc3RydWN0LiAqL1xuICBnZXRDbHVzdGVyKCk6IENka0NsdXN0ZXIge1xuICAgIHJldHVybiB0aGlzLmNsdXN0ZXI7XG4gIH1cblxuICAvKiogR2V0IHRoZSBBTEIgVVJMIChodHRwOi8vIG9yIGh0dHBzOi8vKS4gKi9cbiAgZ2V0VXJsKCk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gICAgaWYgKCF0aGlzLmxvYWRCYWxhbmNlcikgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICBjb25zdCBjdXN0b21Eb21haW4gPVxuICAgICAgdGhpcy5wcm9wcy5jbHVzdGVyPy5kb21haW4gfHxcbiAgICAgIHRoaXMucHJvcHMuY2x1c3Rlcj8uZG9tYWluQ29uZmlnPy5kb21haW5OYW1lO1xuICAgIGlmIChjdXN0b21Eb21haW4pIHJldHVybiBgaHR0cHM6Ly8ke2N1c3RvbURvbWFpbn1gO1xuICAgIHJldHVybiBgaHR0cDovLyR7dGhpcy5sb2FkQmFsYW5jZXIubG9hZEJhbGFuY2VyRG5zTmFtZX1gO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZCBhIHNlcnZpY2UgdG8gdGhlIGNsdXN0ZXIuXG4gICAqIEVhY2ggc2VydmljZSBnZXRzIGl0cyBvd24gdGFzayBkZWZpbml0aW9uLCBjb250YWluZXJzLCBhbmQgdGFyZ2V0IGdyb3VwLlxuICAgKi9cbiAgcHJpdmF0ZSBhZGRTZXJ2aWNlVG9DbHVzdGVyKHNlcnZpY2VQcm9wczogRWNzU2VydmljZVByb3BzKTogdm9pZCB7XG4gICAgY29uc3Qgc2VydmljZU5hbWUgPSBzZXJ2aWNlUHJvcHMubmFtZTtcblxuICAgIGNvbnN0IGV4ZWN1dGlvblJvbGUgPSB0aGlzLmNyZWF0ZUV4ZWN1dGlvblJvbGUoc2VydmljZU5hbWUpO1xuICAgIGNvbnN0IHRhc2tSb2xlID0gdGhpcy5jcmVhdGVUYXNrUm9sZShzZXJ2aWNlTmFtZSwgc2VydmljZVByb3BzKTtcblxuICAgIGNvbnN0IHRhc2tEZWZpbml0aW9uID0gdGhpcy5jcmVhdGVUYXNrRGVmaW5pdGlvbihcbiAgICAgIHNlcnZpY2VOYW1lLFxuICAgICAgc2VydmljZVByb3BzLFxuICAgICAgZXhlY3V0aW9uUm9sZSxcbiAgICAgIHRhc2tSb2xlXG4gICAgKTtcblxuICAgIGNvbnN0IHsgY29udGFpbmVycywgcHJpbWFyeUNvbnRhaW5lciB9ID0gdGhpcy5hZGRDb250YWluZXJzVG9UYXNrKFxuICAgICAgc2VydmljZU5hbWUsXG4gICAgICBzZXJ2aWNlUHJvcHMsXG4gICAgICB0YXNrRGVmaW5pdGlvblxuICAgICk7XG5cbiAgICBjb25zdCBzZXJ2aWNlID0gdGhpcy5jcmVhdGVTZXJ2aWNlKFxuICAgICAgc2VydmljZU5hbWUsXG4gICAgICBzZXJ2aWNlUHJvcHMsXG4gICAgICB0YXNrRGVmaW5pdGlvblxuICAgICk7XG5cbiAgICBsZXQgdGFyZ2V0R3JvdXA6IElBcHBsaWNhdGlvblRhcmdldEdyb3VwIHwgdW5kZWZpbmVkO1xuICAgIGlmIChcbiAgICAgICF0aGlzLmxvYWRCYWxhbmNlckRpc2FibGVkICYmXG4gICAgICBwcmltYXJ5Q29udGFpbmVyICYmXG4gICAgICB0aGlzLmxvYWRCYWxhbmNlckxpc3RlbmVyXG4gICAgKSB7XG4gICAgICB0YXJnZXRHcm91cCA9IHRoaXMucmVnaXN0ZXJTZXJ2aWNlV2l0aEFMQihcbiAgICAgICAgc2VydmljZU5hbWUsXG4gICAgICAgIHNlcnZpY2VQcm9wcyxcbiAgICAgICAgc2VydmljZSxcbiAgICAgICAgcHJpbWFyeUNvbnRhaW5lclxuICAgICAgKTtcbiAgICB9XG5cbiAgICBsZXQgc2NhbGluZ1BvbGljeTogVGFyZ2V0VHJhY2tpbmdTY2FsaW5nUG9saWN5IHwgdW5kZWZpbmVkO1xuICAgIGlmIChzZXJ2aWNlUHJvcHMuc2NhbGluZ1R5cGUpIHtcbiAgICAgIHNjYWxpbmdQb2xpY3kgPSB0aGlzLmFkZFNlcnZpY2VTY2FsaW5nKFxuICAgICAgICBzZXJ2aWNlTmFtZSxcbiAgICAgICAgc2VydmljZVByb3BzLFxuICAgICAgICBzZXJ2aWNlXG4gICAgICApO1xuICAgIH1cblxuICAgIHRoaXMuc2VydmljZXMuc2V0KHNlcnZpY2VOYW1lLCB7XG4gICAgICBzZXJ2aWNlLFxuICAgICAgdGFza0RlZmluaXRpb24sXG4gICAgICBleGVjdXRpb25Sb2xlLFxuICAgICAgdGFza1JvbGUsXG4gICAgICBjb250YWluZXJzLFxuICAgICAgcHJpbWFyeUNvbnRhaW5lcixcbiAgICAgIHRhcmdldEdyb3VwLFxuICAgICAgc2NhbGluZ1BvbGljeVxuICAgIH0pO1xuXG4gICAgaWYgKHNlcnZpY2VQcm9wcy5jb25uZWN0aW9ucyAmJiBzZXJ2aWNlUHJvcHMuY29ubmVjdGlvbnMubGVuZ3RoID4gMCkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgcHJvY2Vzc0Nvbm5lY3Rpb25zKFxuICAgICAgICAgIHNlcnZpY2VQcm9wcy5jb25uZWN0aW9ucyxcbiAgICAgICAgICB0YXNrUm9sZSwgLy8gSUdyYW50YWJsZSAodGFzayByb2xlIGZvciBJQU0gZ3JhbnRzKVxuICAgICAgICAgIHNlcnZpY2UgLy8gSUNvbm5lY3RhYmxlIChzZWN1cml0eSBncm91cCBmb3IgbmV0d29yayBhY2Nlc3MpXG4gICAgICAgICk7XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgYEZhaWxlZCB0byBwcm9jZXNzIGNvbm5lY3Rpb25zIGZvciBFQ1Mgc2VydmljZSAnJHtzZXJ2aWNlTmFtZX0nOiAke1xuICAgICAgICAgICAgZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpXG4gICAgICAgICAgfWBcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHZhbGlkYXRlUHJvcHMocHJvcHM6IEVjc0NsdXN0ZXJQcm9wcyk6IHZvaWQge1xuICAgIC8vIFZhbGlkYXRlIHNlcnZpY2VzIGFycmF5XG4gICAgaWYgKCFwcm9wcy5zZXJ2aWNlcyB8fCBwcm9wcy5zZXJ2aWNlcy5sZW5ndGggPT09IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIkF0IGxlYXN0IG9uZSBzZXJ2aWNlIG11c3QgYmUgc3BlY2lmaWVkLlwiKTtcbiAgICB9XG5cbiAgICAvLyBDaGVjayBmb3IgZHVwbGljYXRlIHNlcnZpY2UgbmFtZXNcbiAgICBjb25zdCBzZXJ2aWNlTmFtZXMgPSBwcm9wcy5zZXJ2aWNlcy5tYXAoKHMpID0+IHMubmFtZSk7XG4gICAgY29uc3QgZHVwbGljYXRlU2VydmljZXMgPSBzZXJ2aWNlTmFtZXMuZmlsdGVyKFxuICAgICAgKG5hbWUsIGluZGV4KSA9PiBzZXJ2aWNlTmFtZXMuaW5kZXhPZihuYW1lKSAhPT0gaW5kZXhcbiAgICApO1xuICAgIGlmIChkdXBsaWNhdGVTZXJ2aWNlcy5sZW5ndGggPiAwKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBEdXBsaWNhdGUgc2VydmljZSBuYW1lczogJHtbLi4ubmV3IFNldChkdXBsaWNhdGVTZXJ2aWNlcyldLmpvaW4oXCIsIFwiKX1gXG4gICAgICApO1xuICAgIH1cblxuICAgIC8vIFZhbGlkYXRlIHJvdXRpbmcgd2hlbiBtdWx0aXBsZSBzZXJ2aWNlcyBoYXZlIHBvcnRzXG4gICAgY29uc3Qgc2VydmljZXNXaXRoUG9ydHMgPSBwcm9wcy5zZXJ2aWNlcy5maWx0ZXIoKHMpID0+XG4gICAgICBzLmNvbnRhaW5lcnMuc29tZSgoYykgPT4gYy5wb3J0ICE9PSB1bmRlZmluZWQpXG4gICAgKTtcblxuICAgIGlmIChzZXJ2aWNlc1dpdGhQb3J0cy5sZW5ndGggPiAxICYmICF0aGlzLmxvYWRCYWxhbmNlckRpc2FibGVkKSB7XG4gICAgICBjb25zdCBtaXNzaW5nUm91dGluZyA9IHNlcnZpY2VzV2l0aFBvcnRzLmZpbHRlcigocykgPT4ge1xuICAgICAgICBjb25zdCBydWxlcyA9IEFycmF5LmlzQXJyYXkocy5yb3V0aW5nKVxuICAgICAgICAgID8gcy5yb3V0aW5nXG4gICAgICAgICAgOiBzLnJvdXRpbmdcbiAgICAgICAgICAgID8gW3Mucm91dGluZ11cbiAgICAgICAgICAgIDogW107XG4gICAgICAgIHJldHVybiAhcnVsZXMuc29tZSgocikgPT4gci5wYXRoIHx8IHIuaG9zdCk7XG4gICAgICB9KTtcbiAgICAgIGlmIChtaXNzaW5nUm91dGluZy5sZW5ndGggPiAwKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICBgU2VydmljZXMgd2l0aCBwb3J0cyByZXF1aXJlIHJvdXRpbmcgY29uZmlnIHdoZW4gY2x1c3RlciBoYXMgbXVsdGlwbGUgc2VydmljZXM6IGAgK1xuICAgICAgICAgICAgYCR7bWlzc2luZ1JvdXRpbmcubWFwKChzKSA9PiBzLm5hbWUpLmpvaW4oXCIsIFwiKX0uIGAgK1xuICAgICAgICAgICAgXCJBZGQgcm91dGluZzogeyBwYXRoOiAnLy4uLicgfSB0byBlYWNoIHNlcnZpY2UuXCJcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBWYWxpZGF0ZSBlYWNoIHNlcnZpY2UncyBjb250YWluZXJzXG4gICAgZm9yIChjb25zdCBzZXJ2aWNlIG9mIHByb3BzLnNlcnZpY2VzKSB7XG4gICAgICBpZiAoIXNlcnZpY2UuY29udGFpbmVycyB8fCBzZXJ2aWNlLmNvbnRhaW5lcnMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICBgU2VydmljZSAnJHtzZXJ2aWNlLm5hbWV9JzogQXQgbGVhc3Qgb25lIGNvbnRhaW5lciBtdXN0IGJlIHNwZWNpZmllZC5gXG4gICAgICAgICk7XG4gICAgICB9XG5cbiAgICAgIC8vIENoZWNrIGZvciBkdXBsaWNhdGUgY29udGFpbmVyIG5hbWVzIHdpdGhpbiBzZXJ2aWNlXG4gICAgICBjb25zdCBjb250YWluZXJOYW1lcyA9IHNlcnZpY2UuY29udGFpbmVycy5tYXAoKGMpID0+IGMubmFtZSk7XG4gICAgICBjb25zdCBkdXBsaWNhdGVDb250YWluZXJzID0gY29udGFpbmVyTmFtZXMuZmlsdGVyKFxuICAgICAgICAobmFtZSwgaW5kZXgpID0+IGNvbnRhaW5lck5hbWVzLmluZGV4T2YobmFtZSkgIT09IGluZGV4XG4gICAgICApO1xuICAgICAgaWYgKGR1cGxpY2F0ZUNvbnRhaW5lcnMubGVuZ3RoID4gMCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgYFNlcnZpY2UgJyR7c2VydmljZS5uYW1lfSc6IER1cGxpY2F0ZSBjb250YWluZXIgbmFtZXM6IGAgK1xuICAgICAgICAgICAgYCR7Wy4uLm5ldyBTZXQoZHVwbGljYXRlQ29udGFpbmVycyldLmpvaW4oXCIsIFwiKX1gXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBzZXR1cENvbm5lY3Rpb25zKHByb3BzOiBFY3NDbHVzdGVyUHJvcHMpOiB2b2lkIHtcbiAgICBsZXQgZGVmYXVsdFBvcnQgPSA4MDtcbiAgICBmb3IgKGNvbnN0IHNlcnZpY2Ugb2YgcHJvcHMuc2VydmljZXMpIHtcbiAgICAgIGNvbnN0IHByaW1hcnlDb250YWluZXIgPSBzZXJ2aWNlLmNvbnRhaW5lcnMuZmluZChcbiAgICAgICAgKGMpID0+IGMucG9ydCAhPT0gdW5kZWZpbmVkXG4gICAgICApO1xuICAgICAgaWYgKHByaW1hcnlDb250YWluZXI/LnBvcnQpIHtcbiAgICAgICAgZGVmYXVsdFBvcnQgPSBwcmltYXJ5Q29udGFpbmVyLnBvcnQ7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH1cblxuICAgIGNvbnN0IHNlY3VyaXR5R3JvdXBzOiBJU2VjdXJpdHlHcm91cFtdID0gW107XG5cbiAgICBpZiAodGhpcy5hc2dTZWN1cml0eUdyb3VwKSB7XG4gICAgICBzZWN1cml0eUdyb3Vwcy5wdXNoKHRoaXMuYXNnU2VjdXJpdHlHcm91cCk7XG4gICAgfVxuXG4gICAgZm9yIChjb25zdCBzZXJ2aWNlRGF0YSBvZiB0aGlzLnNlcnZpY2VzLnZhbHVlcygpKSB7XG4gICAgICBjb25zdCBzZXJ2aWNlU2dzID0gc2VydmljZURhdGEuc2VydmljZT8uY29ubmVjdGlvbnM/LnNlY3VyaXR5R3JvdXBzIHx8IFtdO1xuICAgICAgZm9yIChjb25zdCBzZyBvZiBzZXJ2aWNlU2dzKSB7XG4gICAgICAgIGlmICghc2VjdXJpdHlHcm91cHMuaW5jbHVkZXMoc2cpKSB7XG4gICAgICAgICAgc2VjdXJpdHlHcm91cHMucHVzaChzZyk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICB0aGlzLmNvbm5lY3Rpb25zID0gbmV3IENvbm5lY3Rpb25zKHtcbiAgICAgIHNlY3VyaXR5R3JvdXBzLFxuICAgICAgZGVmYXVsdFBvcnQ6IFBvcnQudGNwKGRlZmF1bHRQb3J0KVxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZXMgdGhlIGV4ZWN1dGlvbiByb2xlIGZvciBFQ1MgaW5mcmFzdHJ1Y3R1cmUgb3BlcmF0aW9ucy5cbiAgICogVXNlZCBieSB0aGUgRUNTIGFnZW50IHRvIHB1bGwgaW1hZ2VzLCB3cml0ZSBsb2dzLCBhbmQgaW5qZWN0IHNlY3JldHMuXG4gICAqIE5PVCB1c2VkIGJ5IGFwcGxpY2F0aW9uIGNvZGUgLSB0aGF0J3MgdGhlIHRhc2sgcm9sZS5cbiAgICovXG4gIHByaXZhdGUgY3JlYXRlRXhlY3V0aW9uUm9sZShzZXJ2aWNlTmFtZTogc3RyaW5nKTogUm9sZSB7XG4gICAgY29uc3QgZXhlY3V0aW9uUm9sZSA9IG5ldyBSb2xlKHRoaXMsIGAke3NlcnZpY2VOYW1lfUV4ZWN1dGlvblJvbGVgLCB7XG4gICAgICBhc3N1bWVkQnk6IG5ldyBTZXJ2aWNlUHJpbmNpcGFsKFwiZWNzLXRhc2tzLmFtYXpvbmF3cy5jb21cIilcbiAgICB9KTtcblxuICAgIC8vIEdldEF1dGhvcml6YXRpb25Ub2tlbiBpcyBhbiBhY2NvdW50LWxldmVsIEFQSSB0aGF0IHJlcXVpcmVzIHJlc291cmNlczogW1wiKlwiXS5cbiAgICAvLyBUaGUgaW1hZ2UtcHVsbCBhY3Rpb25zIGFsc28gdXNlIFwiKlwiIGJlY2F1c2UgZWNyUmVwb3NpdG9yeSBjYW4gYmUgYSBzdHJpbmcgVVJJXG4gICAgLy8gKGNyb3NzLWFjY291bnQgb3IgcHVibGljIEVDUiksIG5vdCBhbHdheXMgYSBSZXBvc2l0b3J5IGNvbnN0cnVjdCB3aXRoIGFuIEFSTi5cbiAgICBleGVjdXRpb25Sb2xlLmFkZFRvUG9saWN5KFxuICAgICAgbmV3IFBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgIGVmZmVjdDogRWZmZWN0LkFMTE9XLFxuICAgICAgICBhY3Rpb25zOiBbXG4gICAgICAgICAgXCJlY3I6R2V0QXV0aG9yaXphdGlvblRva2VuXCIsXG4gICAgICAgICAgXCJlY3I6QmF0Y2hDaGVja0xheWVyQXZhaWxhYmlsaXR5XCIsXG4gICAgICAgICAgXCJlY3I6R2V0RG93bmxvYWRVcmxGb3JMYXllclwiLFxuICAgICAgICAgIFwiZWNyOkJhdGNoR2V0SW1hZ2VcIlxuICAgICAgICBdLFxuICAgICAgICByZXNvdXJjZXM6IFtcIipcIl1cbiAgICAgIH0pXG4gICAgKTtcblxuICAgIGNvbnN0IGxvZ0dyb3VwQXJuID0gYGFybjphd3M6bG9nczoke1N0YWNrLm9mKHRoaXMpLnJlZ2lvbn06JHtTdGFjay5vZih0aGlzKS5hY2NvdW50fTpsb2ctZ3JvdXA6L2Vjcy8ke3RoaXMucHJvcHMuY2x1c3Rlck5hbWV9KmA7XG4gICAgZXhlY3V0aW9uUm9sZS5hZGRUb1BvbGljeShcbiAgICAgIG5ldyBQb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICBlZmZlY3Q6IEVmZmVjdC5BTExPVyxcbiAgICAgICAgYWN0aW9uczogW1xuICAgICAgICAgIFwibG9nczpDcmVhdGVMb2dTdHJlYW1cIixcbiAgICAgICAgICBcImxvZ3M6UHV0TG9nRXZlbnRzXCIsXG4gICAgICAgICAgXCJsb2dzOkNyZWF0ZUxvZ0dyb3VwXCJcbiAgICAgICAgXSxcbiAgICAgICAgcmVzb3VyY2VzOiBbbG9nR3JvdXBBcm4sIGAke2xvZ0dyb3VwQXJufToqYF1cbiAgICAgIH0pXG4gICAgKTtcblxuICAgIGNvbnN0IHNlY3JldE5hbWVzID0gdGhpcy5jb2xsZWN0U2VjcmV0c01hbmFnZXJTZWNyZXROYW1lcygpO1xuICAgIGlmIChzZWNyZXROYW1lcy5sZW5ndGggPiAwKSB7XG4gICAgICBjb25zdCBzZWNyZXRBcm5zID0gc2VjcmV0TmFtZXMubWFwKFxuICAgICAgICAoc2VjcmV0TmFtZSkgPT5cbiAgICAgICAgICBgYXJuOmF3czpzZWNyZXRzbWFuYWdlcjoke1N0YWNrLm9mKHRoaXMpLnJlZ2lvbn06JHtTdGFjay5vZih0aGlzKS5hY2NvdW50fTpzZWNyZXQ6JHtzZWNyZXROYW1lfS0qYFxuICAgICAgKTtcbiAgICAgIGV4ZWN1dGlvblJvbGUuYWRkVG9Qb2xpY3koXG4gICAgICAgIG5ldyBQb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICAgIGVmZmVjdDogRWZmZWN0LkFMTE9XLFxuICAgICAgICAgIGFjdGlvbnM6IFtcbiAgICAgICAgICAgIFwic2VjcmV0c21hbmFnZXI6R2V0U2VjcmV0VmFsdWVcIixcbiAgICAgICAgICAgIFwic2VjcmV0c21hbmFnZXI6RGVzY3JpYmVTZWNyZXRcIlxuICAgICAgICAgIF0sXG4gICAgICAgICAgcmVzb3VyY2VzOiBzZWNyZXRBcm5zXG4gICAgICAgIH0pXG4gICAgICApO1xuICAgIH1cblxuICAgIGNvbnN0IGhhc1NzbVNlY3JldHMgPSB0aGlzLnByb3BzLnNlcnZpY2VzLnNvbWUoKHNlcnZpY2UpID0+XG4gICAgICBzZXJ2aWNlLmNvbnRhaW5lcnMuc29tZShcbiAgICAgICAgKGNvbnRhaW5lcikgPT4gY29udGFpbmVyLnNlY3JldHMgJiYgY29udGFpbmVyLnNlY3JldHMubGVuZ3RoID4gMFxuICAgICAgKVxuICAgICk7XG4gICAgaWYgKGhhc1NzbVNlY3JldHMpIHtcbiAgICAgIGlmICghdGhpcy5wcm9wcy5hcHBOYW1lKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICBgRUNTIGNsdXN0ZXIgJyR7dGhpcy5wcm9wcy5jbHVzdGVyTmFtZX0nIGhhcyBzZXJ2aWNlcyB1c2luZyBzZWNyZXRzIGJ1dCBhcHBOYW1lIGlzIG5vdCBjb25maWd1cmVkLiBgICtcbiAgICAgICAgICAgIGBTZXQgYXBwTmFtZSBvbiBjbHVzdGVyIHByb3BzIHRvIGVuYWJsZSBzY29wZWQgSUFNIHBlcm1pc3Npb25zIGZvciBTU00gUGFyYW1ldGVyIFN0b3JlIGFjY2Vzcy5gXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgICBleGVjdXRpb25Sb2xlLmFkZFRvUG9saWN5KFxuICAgICAgICBuZXcgUG9saWN5U3RhdGVtZW50KHtcbiAgICAgICAgICBlZmZlY3Q6IEVmZmVjdC5BTExPVyxcbiAgICAgICAgICBhY3Rpb25zOiBbXCJzc206R2V0UGFyYW1ldGVyc1wiLCBcInNzbTpHZXRQYXJhbWV0ZXJcIl0sXG4gICAgICAgICAgcmVzb3VyY2VzOiBbYGFybjphd3M6c3NtOio6KjpwYXJhbWV0ZXIvJHt0aGlzLnByb3BzLmFwcE5hbWV9LypgXVxuICAgICAgICB9KVxuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyBLTVMgZGVjcnlwdCBmb3IgU1NNIFNlY3VyZVN0cmluZyBhbmQgU2VjcmV0cyBNYW5hZ2VyIHdpdGggY3VzdG9tZXItbWFuYWdlZCBrZXlzIChDTUtzKVxuICAgIGV4ZWN1dGlvblJvbGUuYWRkVG9Qb2xpY3koXG4gICAgICBuZXcgUG9saWN5U3RhdGVtZW50KHtcbiAgICAgICAgZWZmZWN0OiBFZmZlY3QuQUxMT1csXG4gICAgICAgIGFjdGlvbnM6IFtcImttczpEZWNyeXB0XCJdLFxuICAgICAgICByZXNvdXJjZXM6IFtcIipcIl0sXG4gICAgICAgIGNvbmRpdGlvbnM6IHtcbiAgICAgICAgICBTdHJpbmdFcXVhbHM6IHtcbiAgICAgICAgICAgIFwia21zOlZpYVNlcnZpY2VcIjogW1xuICAgICAgICAgICAgICBgc3NtLiR7U3RhY2sub2YodGhpcykucmVnaW9ufS5hbWF6b25hd3MuY29tYCxcbiAgICAgICAgICAgICAgYHNlY3JldHNtYW5hZ2VyLiR7U3RhY2sub2YodGhpcykucmVnaW9ufS5hbWF6b25hd3MuY29tYFxuICAgICAgICAgICAgXVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSlcbiAgICApO1xuXG4gICAgcmV0dXJuIGV4ZWN1dGlvblJvbGU7XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlcyB0aGUgdGFzayByb2xlIGZvciBhcHBsaWNhdGlvbiBjb2RlIHJ1bm5pbmcgaW4gdGhlIGNvbnRhaW5lci5cbiAgICogVGhpcyByb2xlIGlzIGFzc3VtZWQgYnkgdGhlIGFwcGxpY2F0aW9uLCBub3QgdGhlIEVDUyBhZ2VudC5cbiAgICogSW5jbHVkZXMgZGVmYXVsdCBFQ1MgRXhlYyBwZXJtaXNzaW9ucyBwbHVzIGFueSBzZXJ2aWNlLXNwZWNpZmljIHBvbGljaWVzLlxuICAgKi9cbiAgcHJpdmF0ZSBjcmVhdGVUYXNrUm9sZShcbiAgICBzZXJ2aWNlTmFtZTogc3RyaW5nLFxuICAgIHNlcnZpY2VQcm9wczogRWNzU2VydmljZVByb3BzXG4gICk6IFJvbGUge1xuICAgIGNvbnN0IHRhc2tSb2xlID0gbmV3IFJvbGUodGhpcywgYCR7c2VydmljZU5hbWV9VGFza1JvbGVgLCB7XG4gICAgICBhc3N1bWVkQnk6IG5ldyBTZXJ2aWNlUHJpbmNpcGFsKFwiZWNzLXRhc2tzLmFtYXpvbmF3cy5jb21cIilcbiAgICB9KTtcblxuICAgIC8vIFNTTSBwZXJtaXNzaW9ucyBmb3IgRUNTIEV4ZWMgKGVjcyBleGVjdXRlLWNvbW1hbmQpXG4gICAgdGFza1JvbGUuYWRkVG9Qb2xpY3koXG4gICAgICBuZXcgUG9saWN5U3RhdGVtZW50KHtcbiAgICAgICAgZWZmZWN0OiBFZmZlY3QuQUxMT1csXG4gICAgICAgIGFjdGlvbnM6IFtcbiAgICAgICAgICBcInNzbW1lc3NhZ2VzOkNyZWF0ZUNvbnRyb2xDaGFubmVsXCIsXG4gICAgICAgICAgXCJzc21tZXNzYWdlczpDcmVhdGVEYXRhQ2hhbm5lbFwiLFxuICAgICAgICAgIFwic3NtbWVzc2FnZXM6T3BlbkNvbnRyb2xDaGFubmVsXCIsXG4gICAgICAgICAgXCJzc21tZXNzYWdlczpPcGVuRGF0YUNoYW5uZWxcIlxuICAgICAgICBdLFxuICAgICAgICByZXNvdXJjZXM6IFtcIipcIl1cbiAgICAgIH0pXG4gICAgKTtcblxuICAgIGlmIChzZXJ2aWNlUHJvcHMudGFza1JvbGVJbmxpbmVQb2xpY2llcykge1xuICAgICAgZm9yIChjb25zdCBbcG9saWN5TmFtZSwgcG9saWN5RG9jdW1lbnRdIG9mIE9iamVjdC5lbnRyaWVzKFxuICAgICAgICBzZXJ2aWNlUHJvcHMudGFza1JvbGVJbmxpbmVQb2xpY2llc1xuICAgICAgKSkge1xuICAgICAgICB0YXNrUm9sZS5hdHRhY2hJbmxpbmVQb2xpY3koXG4gICAgICAgICAgbmV3IFBvbGljeSh0aGlzLCBgJHtzZXJ2aWNlTmFtZX0ke3BvbGljeU5hbWV9YCwge1xuICAgICAgICAgICAgZG9jdW1lbnQ6IHBvbGljeURvY3VtZW50XG4gICAgICAgICAgfSlcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoc2VydmljZVByb3BzLnRhc2tSb2xlTWFuYWdlZFBvbGljaWVzKSB7XG4gICAgICBmb3IgKGNvbnN0IHBvbGljeSBvZiBzZXJ2aWNlUHJvcHMudGFza1JvbGVNYW5hZ2VkUG9saWNpZXMpIHtcbiAgICAgICAgdGFza1JvbGUuYWRkTWFuYWdlZFBvbGljeShwb2xpY3kpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB0YXNrUm9sZTtcbiAgfVxuXG4gIHByaXZhdGUgY3JlYXRlVGFza0RlZmluaXRpb24oXG4gICAgc2VydmljZU5hbWU6IHN0cmluZyxcbiAgICBzZXJ2aWNlUHJvcHM6IEVjc1NlcnZpY2VQcm9wcyxcbiAgICBleGVjdXRpb25Sb2xlOiBSb2xlLFxuICAgIHRhc2tSb2xlOiBSb2xlXG4gICk6IEZhcmdhdGVUYXNrRGVmaW5pdGlvbiB8IEVjMlRhc2tEZWZpbml0aW9uIHtcbiAgICBjb25zdCBjcHUgPSBzZXJ2aWNlUHJvcHMuY3B1IHx8IDI1NjtcbiAgICBjb25zdCBtZW1vcnlMaW1pdE1pQiA9IHNlcnZpY2VQcm9wcy5tZW1vcnlMaW1pdE1pQiB8fCA1MTI7XG5cbiAgICBpZiAodGhpcy5pc1NlcnZpY2VGYXJnYXRlKHNlcnZpY2VQcm9wcykpIHtcbiAgICAgIHJldHVybiBuZXcgRmFyZ2F0ZVRhc2tEZWZpbml0aW9uKHRoaXMsIGAke3NlcnZpY2VOYW1lfVRhc2tEZWZpbml0aW9uYCwge1xuICAgICAgICBmYW1pbHk6IGAke3RoaXMucHJvcHMuY2x1c3Rlck5hbWV9LSR7c2VydmljZU5hbWV9YCxcbiAgICAgICAgY3B1LFxuICAgICAgICBtZW1vcnlMaW1pdE1pQixcbiAgICAgICAgZXhlY3V0aW9uUm9sZSxcbiAgICAgICAgdGFza1JvbGUsXG4gICAgICAgIHJ1bnRpbWVQbGF0Zm9ybToge1xuICAgICAgICAgIGNwdUFyY2hpdGVjdHVyZTogQ3B1QXJjaGl0ZWN0dXJlLkFSTTY0LFxuICAgICAgICAgIG9wZXJhdGluZ1N5c3RlbUZhbWlseTogT3BlcmF0aW5nU3lzdGVtRmFtaWx5LkxJTlVYXG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gbmV3IEVjMlRhc2tEZWZpbml0aW9uKHRoaXMsIGAke3NlcnZpY2VOYW1lfVRhc2tEZWZpbml0aW9uYCwge1xuICAgICAgICBmYW1pbHk6IGAke3RoaXMucHJvcHMuY2x1c3Rlck5hbWV9LSR7c2VydmljZU5hbWV9YCxcbiAgICAgICAgZXhlY3V0aW9uUm9sZSxcbiAgICAgICAgdGFza1JvbGUsXG4gICAgICAgIC4uLih0aGlzLmRpcmVjdEFjY2Vzc0VuYWJsZWQgJiYgeyBuZXR3b3JrTW9kZTogTmV0d29ya01vZGUuSE9TVCB9KVxuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBhZGRDb250YWluZXJzVG9UYXNrKFxuICAgIHNlcnZpY2VOYW1lOiBzdHJpbmcsXG4gICAgc2VydmljZVByb3BzOiBFY3NTZXJ2aWNlUHJvcHMsXG4gICAgdGFza0RlZmluaXRpb246IEZhcmdhdGVUYXNrRGVmaW5pdGlvbiB8IEVjMlRhc2tEZWZpbml0aW9uXG4gICk6IHtcbiAgICBjb250YWluZXJzOiBDb250YWluZXJEZWZpbml0aW9uW107XG4gICAgcHJpbWFyeUNvbnRhaW5lcj86IENvbnRhaW5lckRlZmluaXRpb247XG4gIH0ge1xuICAgIGNvbnN0IGNvbnRhaW5lcnM6IENvbnRhaW5lckRlZmluaXRpb25bXSA9IFtdO1xuICAgIGxldCBwcmltYXJ5Q29udGFpbmVyOiBDb250YWluZXJEZWZpbml0aW9uIHwgdW5kZWZpbmVkO1xuXG4gICAgZm9yIChjb25zdCBjb250YWluZXJDb25maWcgb2Ygc2VydmljZVByb3BzLmNvbnRhaW5lcnMpIHtcbiAgICAgIGNvbnN0IGltYWdlID0gdGhpcy5nZXRDb250YWluZXJJbWFnZShcbiAgICAgICAgc2VydmljZU5hbWUsXG4gICAgICAgIGNvbnRhaW5lckNvbmZpZyxcbiAgICAgICAgc2VydmljZVByb3BzXG4gICAgICApO1xuICAgICAgY29uc3QgaXNGaXJzdFdpdGhQb3J0ID1cbiAgICAgICAgIXByaW1hcnlDb250YWluZXIgJiYgY29udGFpbmVyQ29uZmlnLnBvcnQgIT09IHVuZGVmaW5lZDtcblxuICAgICAgY29uc3Qgc2VjcmV0czogUmVjb3JkPHN0cmluZywgRWNzU2VjcmV0PiA9IHt9O1xuICAgICAgaWYgKGNvbnRhaW5lckNvbmZpZy5zZWNyZXRzSW1wb3J0KSB7XG4gICAgICAgIGZvciAoY29uc3QgW2tleSwgc2VjcmV0SW1wb3J0XSBvZiBPYmplY3QuZW50cmllcyhcbiAgICAgICAgICBjb250YWluZXJDb25maWcuc2VjcmV0c0ltcG9ydFxuICAgICAgICApKSB7XG4gICAgICAgICAgY29uc3Qgc2VjcmV0ID0gU2VjcmV0LmZyb21TZWNyZXROYW1lVjIoXG4gICAgICAgICAgICB0aGlzLFxuICAgICAgICAgICAgYCR7dGhpcy5wcm9wcy5jbHVzdGVyTmFtZX0ke3NlcnZpY2VOYW1lfSR7Y29udGFpbmVyQ29uZmlnLm5hbWV9JHtrZXl9U2VjcmV0YCxcbiAgICAgICAgICAgIHNlY3JldEltcG9ydC5uYW1lXG4gICAgICAgICAgKTtcbiAgICAgICAgICBzZWNyZXRzW2tleV0gPSBFY3NTZWNyZXQuZnJvbVNlY3JldHNNYW5hZ2VyKFxuICAgICAgICAgICAgc2VjcmV0LFxuICAgICAgICAgICAgc2VjcmV0SW1wb3J0LmZpZWxkXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAoY29udGFpbmVyQ29uZmlnLnNlY3JldHMgJiYgY29udGFpbmVyQ29uZmlnLnNlY3JldHMubGVuZ3RoID4gMCkge1xuICAgICAgICBpZiAoY29udGFpbmVyQ29uZmlnLnNlY3JldHNJbXBvcnQpIHtcbiAgICAgICAgICBjb25zdCBzZWNyZXRzSW1wb3J0S2V5cyA9IE9iamVjdC5rZXlzKGNvbnRhaW5lckNvbmZpZy5zZWNyZXRzSW1wb3J0KTtcbiAgICAgICAgICBjb25zdCBkdXBsaWNhdGVLZXlzID0gY29udGFpbmVyQ29uZmlnLnNlY3JldHMuZmlsdGVyKChrZXkpID0+XG4gICAgICAgICAgICBzZWNyZXRzSW1wb3J0S2V5cy5pbmNsdWRlcyhrZXkpXG4gICAgICAgICAgKTtcbiAgICAgICAgICBpZiAoZHVwbGljYXRlS2V5cy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgICAgIGBDb250YWluZXIgJyR7Y29udGFpbmVyQ29uZmlnLm5hbWV9JyBpbiBzZXJ2aWNlICcke3NlcnZpY2VOYW1lfScgaGFzIGR1cGxpY2F0ZSBzZWNyZXQga2V5cyBgICtcbiAgICAgICAgICAgICAgICBgZGVmaW5lZCBpbiBib3RoIHNlY3JldHMgYW5kIHNlY3JldHNJbXBvcnQ6ICR7ZHVwbGljYXRlS2V5cy5qb2luKFwiLCBcIil9LiBgICtcbiAgICAgICAgICAgICAgICBgRWFjaCBzZWNyZXQga2V5IG11c3QgYmUgdW5pcXVlIGFjcm9zcyBib3RoIHNvdXJjZXMuYFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBzc21TZWNyZXRzUGF0aCA9IHRoaXMuZGVyaXZlU3NtU2VjcmV0c1BhdGgoXG4gICAgICAgICAgc2VydmljZU5hbWUsXG4gICAgICAgICAgc2VydmljZVByb3BzLnNzbVNlY3JldHNQYXRoXG4gICAgICAgICk7XG5cbiAgICAgICAgZm9yIChjb25zdCBzZWNyZXROYW1lIG9mIGNvbnRhaW5lckNvbmZpZy5zZWNyZXRzKSB7XG4gICAgICAgICAgY29uc3QgcGFyYW1QYXRoID0gYCR7c3NtU2VjcmV0c1BhdGh9LyR7c2VjcmV0TmFtZX1gO1xuICAgICAgICAgIGNvbnN0IHBhcmFtID0gU3RyaW5nUGFyYW1ldGVyLmZyb21TZWN1cmVTdHJpbmdQYXJhbWV0ZXJBdHRyaWJ1dGVzKFxuICAgICAgICAgICAgdGhpcyxcbiAgICAgICAgICAgIGAke3RoaXMucHJvcHMuY2x1c3Rlck5hbWV9JHtzZXJ2aWNlTmFtZX0ke2NvbnRhaW5lckNvbmZpZy5uYW1lfSR7c2VjcmV0TmFtZX1Tc21QYXJhbWAsXG4gICAgICAgICAgICB7IHBhcmFtZXRlck5hbWU6IHBhcmFtUGF0aCB9XG4gICAgICAgICAgKTtcbiAgICAgICAgICBzZWNyZXRzW3NlY3JldE5hbWVdID0gRWNzU2VjcmV0LmZyb21Tc21QYXJhbWV0ZXIocGFyYW0pO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGNvbnRhaW5lciA9IHRhc2tEZWZpbml0aW9uLmFkZENvbnRhaW5lcihcbiAgICAgICAgYCR7c2VydmljZU5hbWV9JHtjb250YWluZXJDb25maWcubmFtZX1gLFxuICAgICAgICB7XG4gICAgICAgICAgaW1hZ2UsXG4gICAgICAgICAgY29udGFpbmVyTmFtZTogY29udGFpbmVyQ29uZmlnLm5hbWUsXG4gICAgICAgICAgbG9nZ2luZzogbmV3IEF3c0xvZ0RyaXZlcih7XG4gICAgICAgICAgICBzdHJlYW1QcmVmaXg6IGAvZWNzLyR7dGhpcy5wcm9wcy5jbHVzdGVyTmFtZX0vJHtzZXJ2aWNlTmFtZX1gLFxuICAgICAgICAgICAgbG9nUmV0ZW50aW9uOiBERUZBVUxUX0xPR19SRVRFTlRJT05fREFZU1xuICAgICAgICAgIH0pLFxuICAgICAgICAgIGVudmlyb25tZW50OiB7XG4gICAgICAgICAgICAuLi5jb250YWluZXJDb25maWcuZW52aXJvbm1lbnQsXG4gICAgICAgICAgICAuLi4oY29udGFpbmVyQ29uZmlnLnBvcnRcbiAgICAgICAgICAgICAgPyB7IFBPUlQ6IFN0cmluZyhjb250YWluZXJDb25maWcucG9ydCkgfVxuICAgICAgICAgICAgICA6IHt9KVxuICAgICAgICAgIH0sXG4gICAgICAgICAgc2VjcmV0cyxcbiAgICAgICAgICBjb21tYW5kOiBjb250YWluZXJDb25maWcuY29tbWFuZCxcbiAgICAgICAgICBlbnRyeVBvaW50OiBjb250YWluZXJDb25maWcuZW50cnlQb2ludCxcbiAgICAgICAgICBlc3NlbnRpYWw6IGNvbnRhaW5lckNvbmZpZy5lc3NlbnRpYWwgPz8gdHJ1ZSxcbiAgICAgICAgICBoZWFsdGhDaGVjazogY29udGFpbmVyQ29uZmlnLmhlYWx0aENoZWNrXG4gICAgICAgICAgICA/IHtcbiAgICAgICAgICAgICAgICBjb21tYW5kOiBjb250YWluZXJDb25maWcuaGVhbHRoQ2hlY2suY29tbWFuZCxcbiAgICAgICAgICAgICAgICBpbnRlcnZhbDogY29udGFpbmVyQ29uZmlnLmhlYWx0aENoZWNrLmludGVydmFsXG4gICAgICAgICAgICAgICAgICA/IER1cmF0aW9uLnNlY29uZHMoY29udGFpbmVyQ29uZmlnLmhlYWx0aENoZWNrLmludGVydmFsKVxuICAgICAgICAgICAgICAgICAgOiB1bmRlZmluZWQsXG4gICAgICAgICAgICAgICAgdGltZW91dDogY29udGFpbmVyQ29uZmlnLmhlYWx0aENoZWNrLnRpbWVvdXRcbiAgICAgICAgICAgICAgICAgID8gRHVyYXRpb24uc2Vjb25kcyhjb250YWluZXJDb25maWcuaGVhbHRoQ2hlY2sudGltZW91dClcbiAgICAgICAgICAgICAgICAgIDogdW5kZWZpbmVkLFxuICAgICAgICAgICAgICAgIHJldHJpZXM6IGNvbnRhaW5lckNvbmZpZy5oZWFsdGhDaGVjay5yZXRyaWVzLFxuICAgICAgICAgICAgICAgIHN0YXJ0UGVyaW9kOiBjb250YWluZXJDb25maWcuaGVhbHRoQ2hlY2suc3RhcnRQZXJpb2RcbiAgICAgICAgICAgICAgICAgID8gRHVyYXRpb24uc2Vjb25kcyhjb250YWluZXJDb25maWcuaGVhbHRoQ2hlY2suc3RhcnRQZXJpb2QpXG4gICAgICAgICAgICAgICAgICA6IHVuZGVmaW5lZFxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICA6IHVuZGVmaW5lZCxcbiAgICAgICAgICAuLi4odGhpcy5pc1NlcnZpY2VFYzIoc2VydmljZVByb3BzKSAmJiB7XG4gICAgICAgICAgICBtZW1vcnlMaW1pdE1pQjogc2VydmljZVByb3BzLmVjMkNvbmZpZz8ubWVtb3J5TGltaXRNaUIgPz8gMTAyNFxuICAgICAgICAgIH0pXG4gICAgICAgIH1cbiAgICAgICk7XG5cbiAgICAgIGlmIChjb250YWluZXJDb25maWcucG9ydCkge1xuICAgICAgICBjb250YWluZXIuYWRkUG9ydE1hcHBpbmdzKHtcbiAgICAgICAgICBjb250YWluZXJQb3J0OiBjb250YWluZXJDb25maWcucG9ydFxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgaWYgKGlzRmlyc3RXaXRoUG9ydCkge1xuICAgICAgICBwcmltYXJ5Q29udGFpbmVyID0gY29udGFpbmVyO1xuICAgICAgfVxuXG4gICAgICBjb250YWluZXJzLnB1c2goY29udGFpbmVyKTtcbiAgICB9XG5cbiAgICByZXR1cm4geyBjb250YWluZXJzLCBwcmltYXJ5Q29udGFpbmVyIH07XG4gIH1cblxuICBwcml2YXRlIGdldENvbnRhaW5lckltYWdlKFxuICAgIHNlcnZpY2VOYW1lOiBzdHJpbmcsXG4gICAgY29udGFpbmVyQ29uZmlnOiBFY3NDbHVzdGVyQ29udGFpbmVyQ29uZmlnLFxuICAgIHNlcnZpY2VQcm9wczogRWNzU2VydmljZVByb3BzXG4gICk6IENvbnRhaW5lckltYWdlIHtcbiAgICBjb25zdCBpbWFnZVNvdXJjZSA9XG4gICAgICBjb250YWluZXJDb25maWcuaW1hZ2UgfHwgc2VydmljZVByb3BzLmltYWdlIHx8IHRoaXMucHJvcHMuZWNyUmVwb3NpdG9yeTtcblxuICAgIGlmICghaW1hZ2VTb3VyY2UpIHtcbiAgICAgIHJldHVybiBDb250YWluZXJJbWFnZS5mcm9tUmVnaXN0cnkoXCJhbWF6b24vYW1hem9uLWVjcy1zYW1wbGVcIik7XG4gICAgfVxuXG4gICAgLy8gQnVpbGQgaW1hZ2UgdGFnIHdpdGggb3B0aW9uYWwgZG9ja2VyVGFyZ2V0IHN1ZmZpeFxuICAgIC8vIEZvcm1hdDogPHNlcnZpY2U+LVs8dGFyZ2V0Pi1dPHZlcnNpb24+XG4gICAgLy8gaW1hZ2VWZXJzaW9uIGNvbWVzIGZyb20gQ0RLIGNvbnRleHQgKGdpdCBTSEEpIHRvIGVuc3VyZSBDbG91ZEZvcm1hdGlvblxuICAgIC8vIGRldGVjdHMgdGVtcGxhdGUgY2hhbmdlcyB3aGVuIG5ldyBjb2RlIGlzIGRlcGxveWVkLiBGYWxscyBiYWNrIHRvICdsYXRlc3QnXG4gICAgLy8gZm9yIGFwcHMgd2l0aG91dCBEb2NrZXJmaWxlcyAod2VsY29tZSBpbWFnZSkgb3IgbG9jYWwgZGV2LlxuICAgIGNvbnN0IGltYWdlVmVyc2lvbiA9XG4gICAgICAodGhpcy5ub2RlLnRyeUdldENvbnRleHQoXCJpbWFnZVZlcnNpb25cIikgYXMgc3RyaW5nIHwgdW5kZWZpbmVkKSB8fFxuICAgICAgXCJsYXRlc3RcIjtcbiAgICBjb25zdCB0YXJnZXRTdWZmaXggPSBzZXJ2aWNlUHJvcHMuZG9ja2VyVGFyZ2V0XG4gICAgICA/IGAtJHtzZXJ2aWNlUHJvcHMuZG9ja2VyVGFyZ2V0LnRvTG93ZXJDYXNlKCl9YFxuICAgICAgOiBcIlwiO1xuICAgIGNvbnN0IGltYWdlVGFnID0gYCR7c2VydmljZU5hbWUudG9Mb3dlckNhc2UoKX0ke3RhcmdldFN1ZmZpeH0tJHtpbWFnZVZlcnNpb259YDtcblxuICAgIGlmICh0eXBlb2YgaW1hZ2VTb3VyY2UgPT09IFwic3RyaW5nXCIpIHtcbiAgICAgIGNvbnN0IGlzRnVsbFJlZ2lzdHJ5VXJsID1cbiAgICAgICAgKGltYWdlU291cmNlLmluY2x1ZGVzKFwiL1wiKSAmJiAhaW1hZ2VTb3VyY2UuaW5jbHVkZXMoXCIuXCIpKSB8fCAvLyBEb2NrZXIgSHViIHNob3J0aGFuZDogYW1hem9uL2FtYXpvbi1lY3Mtc2FtcGxlXG4gICAgICAgIC9eKGRvY2tlclxcLmlvfHJlZ2lzdHJ5XFwuaHViXFwuZG9ja2VyXFwuY29tfGdoY3JcXC5pbylcXC8vaS50ZXN0KFxuICAgICAgICAgIGltYWdlU291cmNlXG4gICAgICAgICkgfHwgLy8gRnVsbCBEb2NrZXIgSHViIC8gR0hDUiBVUkxzXG4gICAgICAgIGltYWdlU291cmNlLnN0YXJ0c1dpdGgoXCJwdWJsaWMuZWNyLmF3cy9cIikgfHwgLy8gUHVibGljIEVDUjogcHVibGljLmVjci5hd3MvZmphbGwvd2VsY29tZVxuICAgICAgICBpbWFnZVNvdXJjZS5pbmNsdWRlcyhcIi5ka3IuZWNyLlwiKTsgLy8gUHJpdmF0ZSBFQ1IgZnVsbCBVUkw6IDEyMzQ1Njc4OTAxMi5ka3IuZWNyLnVzLWVhc3QtMi5hbWF6b25hd3MuY29tL3JlcG86dGFnXG5cbiAgICAgIGlmIChpc0Z1bGxSZWdpc3RyeVVybCkge1xuICAgICAgICByZXR1cm4gQ29udGFpbmVySW1hZ2UuZnJvbVJlZ2lzdHJ5KGltYWdlU291cmNlKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBDb250YWluZXJJbWFnZS5mcm9tRWNyUmVwb3NpdG9yeShcbiAgICAgICAgUmVwb3NpdG9yeS5mcm9tUmVwb3NpdG9yeU5hbWUoXG4gICAgICAgICAgdGhpcyxcbiAgICAgICAgICBgJHtzZXJ2aWNlTmFtZX0ke2NvbnRhaW5lckNvbmZpZy5uYW1lfUVjclJlcG9gLFxuICAgICAgICAgIGltYWdlU291cmNlXG4gICAgICAgICksXG4gICAgICAgIGltYWdlVGFnXG4gICAgICApO1xuICAgIH1cblxuICAgIGlmIChpbWFnZVNvdXJjZSBpbnN0YW5jZW9mIFJlcG9zaXRvcnkpIHtcbiAgICAgIHJldHVybiBDb250YWluZXJJbWFnZS5mcm9tRWNyUmVwb3NpdG9yeShpbWFnZVNvdXJjZSwgaW1hZ2VUYWcpO1xuICAgIH1cblxuICAgIC8vIEFmdGVyIHN0cmluZyBhbmQgUmVwb3NpdG9yeSBjaGVja3MsIG9ubHkgQ29udGFpbmVySW1hZ2UgcmVtYWlucyBpbiB0aGUgdW5pb25cbiAgICBpZiAoIShpbWFnZVNvdXJjZSBpbnN0YW5jZW9mIENvbnRhaW5lckltYWdlKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbnN1cHBvcnRlZCBpbWFnZSBzb3VyY2UgdHlwZTogJHt0eXBlb2YgaW1hZ2VTb3VyY2V9YCk7XG4gICAgfVxuICAgIHJldHVybiBpbWFnZVNvdXJjZTtcbiAgfVxuXG4gIHByaXZhdGUgY3JlYXRlU2VydmljZShcbiAgICBzZXJ2aWNlTmFtZTogc3RyaW5nLFxuICAgIHNlcnZpY2VQcm9wczogRWNzU2VydmljZVByb3BzLFxuICAgIHRhc2tEZWZpbml0aW9uOiBGYXJnYXRlVGFza0RlZmluaXRpb24gfCBFYzJUYXNrRGVmaW5pdGlvblxuICApOiBGYXJnYXRlU2VydmljZSB8IEVjMlNlcnZpY2Uge1xuICAgIGNvbnN0IGRlc2lyZWRDb3VudCA9IHNlcnZpY2VQcm9wcy5kZXNpcmVkQ291bnQgPz8gMjtcbiAgICBjb25zdCBlZmZlY3RpdmVQcm92aWRlciA9IHRoaXMuZ2V0U2VydmljZUNhcGFjaXR5UHJvdmlkZXIoc2VydmljZVByb3BzKTtcblxuICAgIGlmICh0aGlzLmlzU2VydmljZUZhcmdhdGUoc2VydmljZVByb3BzKSkge1xuICAgICAgY29uc3QgaGFzTmF0ID0gdGhpcy52cGNIYXNOYXRHYXRld2F5cygpO1xuICAgICAgY29uc3Qgc2VydmljZSA9IG5ldyBGYXJnYXRlU2VydmljZSh0aGlzLCBgJHtzZXJ2aWNlTmFtZX1TZXJ2aWNlYCwge1xuICAgICAgICBjbHVzdGVyOiB0aGlzLmNsdXN0ZXIsXG4gICAgICAgIHRhc2tEZWZpbml0aW9uOiB0YXNrRGVmaW5pdGlvbiBhcyBGYXJnYXRlVGFza0RlZmluaXRpb24sXG4gICAgICAgIGRlc2lyZWRDb3VudCxcbiAgICAgICAgc2VydmljZU5hbWUsXG4gICAgICAgIHZwY1N1Ym5ldHM6IHtcbiAgICAgICAgICBzdWJuZXRUeXBlOiBoYXNOYXRcbiAgICAgICAgICAgID8gU3VibmV0VHlwZS5QUklWQVRFX1dJVEhfRUdSRVNTXG4gICAgICAgICAgICA6IFN1Ym5ldFR5cGUuUFVCTElDXG4gICAgICAgIH0sXG4gICAgICAgIGFzc2lnblB1YmxpY0lwOiAhaGFzTmF0LFxuICAgICAgICBjYXBhY2l0eVByb3ZpZGVyU3RyYXRlZ2llczogW1xuICAgICAgICAgIHtcbiAgICAgICAgICAgIGNhcGFjaXR5UHJvdmlkZXI6IGVmZmVjdGl2ZVByb3ZpZGVyLFxuICAgICAgICAgICAgd2VpZ2h0OiAxXG4gICAgICAgICAgfVxuICAgICAgICBdLFxuICAgICAgICBwcm9wYWdhdGVUYWdzOiBQcm9wYWdhdGVkVGFnU291cmNlLlNFUlZJQ0UsXG4gICAgICAgIGNpcmN1aXRCcmVha2VyOiB7IGVuYWJsZTogdHJ1ZSwgcm9sbGJhY2s6IHRydWUgfSxcbiAgICAgICAgZW5hYmxlRUNTTWFuYWdlZFRhZ3M6IHRydWUsXG4gICAgICAgIGVuYWJsZUV4ZWN1dGVDb21tYW5kOiB0cnVlLFxuICAgICAgICBoZWFsdGhDaGVja0dyYWNlUGVyaW9kOiBEdXJhdGlvbi5zZWNvbmRzKDEyMCksXG4gICAgICAgIG1pbkhlYWx0aHlQZXJjZW50OiAxMDAsXG4gICAgICAgIG1heEhlYWx0aHlQZXJjZW50OiAyMDBcbiAgICAgIH0pO1xuXG4gICAgICBuZXcgQ2ZuT3V0cHV0KFxuICAgICAgICB0aGlzLFxuICAgICAgICBgJHt0aGlzLm91dHB1dE5hbWV9JHt0b1Bhc2NhbENhc2Uoc2VydmljZU5hbWUpfVNlcnZpY2VBcm5gLFxuICAgICAgICB7XG4gICAgICAgICAga2V5OiBgJHt0aGlzLm91dHB1dE5hbWV9JHt0b1Bhc2NhbENhc2Uoc2VydmljZU5hbWUpfVNlcnZpY2VBcm5gLFxuICAgICAgICAgIGV4cG9ydE5hbWU6IGAke3RoaXMucHJvcHMuY2x1c3Rlck5hbWV9JHtzZXJ2aWNlTmFtZX1TZXJ2aWNlQXJuYCxcbiAgICAgICAgICB2YWx1ZTogc2VydmljZS5zZXJ2aWNlQXJuLFxuICAgICAgICAgIGRlc2NyaXB0aW9uOiBgRUNTIFNlcnZpY2UgQVJOIGZvciAke3NlcnZpY2VOYW1lfWBcbiAgICAgICAgfVxuICAgICAgKTtcbiAgICAgIHJldHVybiBzZXJ2aWNlO1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zdCBhc2dQcm92aWRlciA9IHRoaXMuZ2V0T3JDcmVhdGVBc2dDYXBhY2l0eVByb3ZpZGVyKHNlcnZpY2VQcm9wcyk7XG5cbiAgICAgIGNvbnN0IHNlcnZpY2UgPSBuZXcgRWMyU2VydmljZSh0aGlzLCBgJHtzZXJ2aWNlTmFtZX1TZXJ2aWNlYCwge1xuICAgICAgICBjbHVzdGVyOiB0aGlzLmNsdXN0ZXIsXG4gICAgICAgIHRhc2tEZWZpbml0aW9uOiB0YXNrRGVmaW5pdGlvbiBhcyBFYzJUYXNrRGVmaW5pdGlvbixcbiAgICAgICAgZGVzaXJlZENvdW50LFxuICAgICAgICBzZXJ2aWNlTmFtZSxcbiAgICAgICAgY2FwYWNpdHlQcm92aWRlclN0cmF0ZWdpZXM6IFtcbiAgICAgICAgICB7XG4gICAgICAgICAgICBjYXBhY2l0eVByb3ZpZGVyOiBhc2dQcm92aWRlci5jYXBhY2l0eVByb3ZpZGVyTmFtZSxcbiAgICAgICAgICAgIHdlaWdodDogMVxuICAgICAgICAgIH1cbiAgICAgICAgXSxcbiAgICAgICAgcHJvcGFnYXRlVGFnczogUHJvcGFnYXRlZFRhZ1NvdXJjZS5TRVJWSUNFLFxuICAgICAgICBjaXJjdWl0QnJlYWtlcjogeyBlbmFibGU6IHRydWUsIHJvbGxiYWNrOiB0cnVlIH0sXG4gICAgICAgIHBsYWNlbWVudFN0cmF0ZWdpZXM6IFtQbGFjZW1lbnRTdHJhdGVneS5zcHJlYWRBY3Jvc3NJbnN0YW5jZXMoKV0sXG4gICAgICAgIGVuYWJsZUVDU01hbmFnZWRUYWdzOiB0cnVlLFxuICAgICAgICBlbmFibGVFeGVjdXRlQ29tbWFuZDogdHJ1ZSxcbiAgICAgICAgaGVhbHRoQ2hlY2tHcmFjZVBlcmlvZDogRHVyYXRpb24uc2Vjb25kcygxMjApLFxuICAgICAgICBtaW5IZWFsdGh5UGVyY2VudDogMTAwLFxuICAgICAgICBtYXhIZWFsdGh5UGVyY2VudDogMjAwXG4gICAgICB9KTtcblxuICAgICAgbmV3IENmbk91dHB1dChcbiAgICAgICAgdGhpcyxcbiAgICAgICAgYCR7dGhpcy5vdXRwdXROYW1lfSR7dG9QYXNjYWxDYXNlKHNlcnZpY2VOYW1lKX1TZXJ2aWNlQXJuYCxcbiAgICAgICAge1xuICAgICAgICAgIGtleTogYCR7dGhpcy5vdXRwdXROYW1lfSR7dG9QYXNjYWxDYXNlKHNlcnZpY2VOYW1lKX1TZXJ2aWNlQXJuYCxcbiAgICAgICAgICBleHBvcnROYW1lOiBgJHt0aGlzLnByb3BzLmNsdXN0ZXJOYW1lfSR7c2VydmljZU5hbWV9U2VydmljZUFybmAsXG4gICAgICAgICAgdmFsdWU6IHNlcnZpY2Uuc2VydmljZUFybixcbiAgICAgICAgICBkZXNjcmlwdGlvbjogYEVDUyBTZXJ2aWNlIEFSTiBmb3IgJHtzZXJ2aWNlTmFtZX1gXG4gICAgICAgIH1cbiAgICAgICk7XG4gICAgICByZXR1cm4gc2VydmljZTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHJlZ2lzdGVyU2VydmljZVdpdGhBTEIoXG4gICAgc2VydmljZU5hbWU6IHN0cmluZyxcbiAgICBzZXJ2aWNlUHJvcHM6IEVjc1NlcnZpY2VQcm9wcyxcbiAgICBzZXJ2aWNlOiBGYXJnYXRlU2VydmljZSB8IEVjMlNlcnZpY2UsXG4gICAgcHJpbWFyeUNvbnRhaW5lcjogQ29udGFpbmVyRGVmaW5pdGlvblxuICApOiBJQXBwbGljYXRpb25UYXJnZXRHcm91cCB7XG4gICAgaWYgKCF0aGlzLmxvYWRCYWxhbmNlckxpc3RlbmVyKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIFwiQ2Fubm90IHJlZ2lzdGVyIHNlcnZpY2Ugd2l0aCBBTEI6IGxvYWRCYWxhbmNlckxpc3RlbmVyIGlzIG5vdCBpbml0aWFsaXNlZFwiXG4gICAgICApO1xuICAgIH1cbiAgICBjb25zdCBsaXN0ZW5lciA9IHRoaXMubG9hZEJhbGFuY2VyTGlzdGVuZXI7XG5cbiAgICBjb25zdCBjb250YWluZXJQb3J0ID0gcHJpbWFyeUNvbnRhaW5lci5jb250YWluZXJQb3J0O1xuXG4gICAgLy8gTm9ybWFsaXNlIHJvdXRpbmcgdG8gYXJyYXlcbiAgICBjb25zdCByb3V0aW5nUnVsZXMgPSBBcnJheS5pc0FycmF5KHNlcnZpY2VQcm9wcy5yb3V0aW5nKVxuICAgICAgPyBzZXJ2aWNlUHJvcHMucm91dGluZ1xuICAgICAgOiBzZXJ2aWNlUHJvcHMucm91dGluZ1xuICAgICAgICA/IFtzZXJ2aWNlUHJvcHMucm91dGluZ11cbiAgICAgICAgOiBbXTtcblxuICAgIGNvbnN0IGhlYWx0aENoZWNrUGF0aCA9XG4gICAgICByb3V0aW5nUnVsZXMuZmluZCgocikgPT4gci5oZWFsdGhDaGVja1BhdGgpPy5oZWFsdGhDaGVja1BhdGggPz8gXCIvXCI7XG5cbiAgICBjb25zdCBzZXJ2aWNlc1dpdGhQb3J0cyA9IHRoaXMucHJvcHMuc2VydmljZXMuZmlsdGVyKChzKSA9PlxuICAgICAgcy5jb250YWluZXJzLnNvbWUoKGMpID0+IGMucG9ydCAhPT0gdW5kZWZpbmVkKVxuICAgICk7XG4gICAgY29uc3QgaXNTaW5nbGVTZXJ2aWNlID0gc2VydmljZXNXaXRoUG9ydHMubGVuZ3RoID09PSAxO1xuXG4gICAgY29uc3QgaGVhbHRoQ2hlY2tDb25maWcgPSB0aGlzLmlzU2VydmljZUVjMihzZXJ2aWNlUHJvcHMpXG4gICAgICA/IHtcbiAgICAgICAgICBpbnRlcnZhbDogRHVyYXRpb24uc2Vjb25kcygzMCksXG4gICAgICAgICAgaGVhbHRoeVRocmVzaG9sZENvdW50OiAzLFxuICAgICAgICAgIHVuaGVhbHRoeVRocmVzaG9sZENvdW50OiAzLFxuICAgICAgICAgIHBhdGg6IGhlYWx0aENoZWNrUGF0aCxcbiAgICAgICAgICBwb3J0OiBcInRyYWZmaWMtcG9ydFwiIGFzIGNvbnN0LFxuICAgICAgICAgIHRpbWVvdXQ6IER1cmF0aW9uLnNlY29uZHMoMTUpXG4gICAgICAgIH1cbiAgICAgIDoge1xuICAgICAgICAgIGludGVydmFsOiBEdXJhdGlvbi5zZWNvbmRzKDEyMCksXG4gICAgICAgICAgcGF0aDogaGVhbHRoQ2hlY2tQYXRoLFxuICAgICAgICAgIHBvcnQ6IGAke2NvbnRhaW5lclBvcnR9YCxcbiAgICAgICAgICB0aW1lb3V0OiBEdXJhdGlvbi5zZWNvbmRzKDEwKVxuICAgICAgICB9O1xuXG4gICAgaWYgKGlzU2luZ2xlU2VydmljZSAmJiByb3V0aW5nUnVsZXMubGVuZ3RoIDw9IDEpIHtcbiAgICAgIHJldHVybiBsaXN0ZW5lci5hZGRUYXJnZXRzKGAke3NlcnZpY2VOYW1lfVRhcmdldEdyb3VwYCwge1xuICAgICAgICB0YXJnZXRzOiBbXG4gICAgICAgICAgc2VydmljZS5sb2FkQmFsYW5jZXJUYXJnZXQoe1xuICAgICAgICAgICAgY29udGFpbmVyTmFtZTogcHJpbWFyeUNvbnRhaW5lci5jb250YWluZXJOYW1lLFxuICAgICAgICAgICAgY29udGFpbmVyUG9ydFxuICAgICAgICAgIH0pXG4gICAgICAgIF0sXG4gICAgICAgIHBvcnQ6IGNvbnRhaW5lclBvcnQsXG4gICAgICAgIHByb3RvY29sOiBBcHBsaWNhdGlvblByb3RvY29sLkhUVFAsXG4gICAgICAgIGhlYWx0aENoZWNrOiBoZWFsdGhDaGVja0NvbmZpZ1xuICAgICAgfSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnN0IGZpcnN0UnVsZSA9IHJvdXRpbmdSdWxlc1swXTtcbiAgICAgIGNvbnN0IGZpcnN0UHJpb3JpdHkgPSBmaXJzdFJ1bGU/LnByaW9yaXR5ID8/IHRoaXMuZ2V0TmV4dFByaW9yaXR5KCk7XG4gICAgICBpZiAoZmlyc3RSdWxlPy5wcmlvcml0eSkgdGhpcy51c2VkUHJpb3JpdGllcy5hZGQoZmlyc3RSdWxlLnByaW9yaXR5KTtcblxuICAgICAgY29uc3QgdGFyZ2V0R3JvdXAgPSBsaXN0ZW5lci5hZGRUYXJnZXRzKGAke3NlcnZpY2VOYW1lfVRhcmdldHNgLCB7XG4gICAgICAgIHRhcmdldHM6IFtcbiAgICAgICAgICBzZXJ2aWNlLmxvYWRCYWxhbmNlclRhcmdldCh7XG4gICAgICAgICAgICBjb250YWluZXJOYW1lOiBwcmltYXJ5Q29udGFpbmVyLmNvbnRhaW5lck5hbWUsXG4gICAgICAgICAgICBjb250YWluZXJQb3J0XG4gICAgICAgICAgfSlcbiAgICAgICAgXSxcbiAgICAgICAgcG9ydDogY29udGFpbmVyUG9ydCxcbiAgICAgICAgcHJvdG9jb2w6IEFwcGxpY2F0aW9uUHJvdG9jb2wuSFRUUCxcbiAgICAgICAgaGVhbHRoQ2hlY2s6IGhlYWx0aENoZWNrQ29uZmlnLFxuICAgICAgICBjb25kaXRpb25zOiB0aGlzLmJ1aWxkUm91dGluZ0NvbmRpdGlvbnMoZmlyc3RSdWxlKSxcbiAgICAgICAgcHJpb3JpdHk6IGZpcnN0UHJpb3JpdHlcbiAgICAgIH0pO1xuXG4gICAgICAvLyBBZGRpdGlvbmFsIHJ1bGVzIHJldXNlIHRoZSBzYW1lIHRhcmdldCBncm91cFxuICAgICAgZm9yIChsZXQgaSA9IDE7IGkgPCByb3V0aW5nUnVsZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgY29uc3QgcnVsZSA9IHJvdXRpbmdSdWxlc1tpXTtcbiAgICAgICAgY29uc3QgcHJpb3JpdHkgPSBydWxlLnByaW9yaXR5ID8/IHRoaXMuZ2V0TmV4dFByaW9yaXR5KCk7XG4gICAgICAgIGlmIChydWxlLnByaW9yaXR5KSB0aGlzLnVzZWRQcmlvcml0aWVzLmFkZChydWxlLnByaW9yaXR5KTtcbiAgICAgICAgbGlzdGVuZXIuYWRkQWN0aW9uKGAke3NlcnZpY2VOYW1lfVJvdXRlJHtpfWAsIHtcbiAgICAgICAgICBjb25kaXRpb25zOiB0aGlzLmJ1aWxkUm91dGluZ0NvbmRpdGlvbnMocnVsZSksXG4gICAgICAgICAgcHJpb3JpdHksXG4gICAgICAgICAgYWN0aW9uOiBMaXN0ZW5lckFjdGlvbi5mb3J3YXJkKFt0YXJnZXRHcm91cF0pXG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gdGFyZ2V0R3JvdXA7XG4gICAgfVxuICB9XG5cbiAgLyoqIFJldHVybnMgdGhlIG5leHQgdW51c2VkIGF1dG8taW5jcmVtZW50ZWQgQUxCIHByaW9yaXR5LCBza2lwcGluZyBhbnkgbWFudWFsbHkgYXNzaWduZWQgdmFsdWVzLiAqL1xuICBwcml2YXRlIGdldE5leHRQcmlvcml0eSgpOiBudW1iZXIge1xuICAgIHdoaWxlICh0aGlzLnVzZWRQcmlvcml0aWVzLmhhcyh0aGlzLm5leHRQcmlvcml0eSkpIHtcbiAgICAgIHRoaXMubmV4dFByaW9yaXR5Kys7XG4gICAgfVxuICAgIGNvbnN0IHByaW9yaXR5ID0gdGhpcy5uZXh0UHJpb3JpdHkrKztcbiAgICB0aGlzLnVzZWRQcmlvcml0aWVzLmFkZChwcmlvcml0eSk7XG4gICAgcmV0dXJuIHByaW9yaXR5O1xuICB9XG5cbiAgcHJpdmF0ZSBidWlsZFJvdXRpbmdDb25kaXRpb25zKFxuICAgIHJ1bGU6IEVjc1JvdXRpbmdDb25maWcgfCB1bmRlZmluZWRcbiAgKTogTGlzdGVuZXJDb25kaXRpb25bXSB7XG4gICAgY29uc3QgY29uZGl0aW9uczogTGlzdGVuZXJDb25kaXRpb25bXSA9IFtdO1xuXG4gICAgaWYgKHJ1bGU/LnBhdGgpIHtcbiAgICAgIGNvbmRpdGlvbnMucHVzaChMaXN0ZW5lckNvbmRpdGlvbi5wYXRoUGF0dGVybnMoW3J1bGUucGF0aF0pKTtcbiAgICB9XG4gICAgaWYgKHJ1bGU/Lmhvc3QpIHtcbiAgICAgIGNvbmRpdGlvbnMucHVzaChMaXN0ZW5lckNvbmRpdGlvbi5ob3N0SGVhZGVycyhbcnVsZS5ob3N0XSkpO1xuICAgIH1cblxuICAgIHJldHVybiBjb25kaXRpb25zO1xuICB9XG5cbiAgcHJpdmF0ZSBhZGRTZXJ2aWNlU2NhbGluZyhcbiAgICBzZXJ2aWNlTmFtZTogc3RyaW5nLFxuICAgIHNlcnZpY2VQcm9wczogRWNzU2VydmljZVByb3BzLFxuICAgIHNlcnZpY2U6IEZhcmdhdGVTZXJ2aWNlIHwgRWMyU2VydmljZVxuICApOiBUYXJnZXRUcmFja2luZ1NjYWxpbmdQb2xpY3kge1xuICAgIGNvbnN0IHNjYWxhYmxlVGFyZ2V0ID0gbmV3IFNjYWxhYmxlVGFyZ2V0KFxuICAgICAgdGhpcyxcbiAgICAgIGAke3NlcnZpY2VOYW1lfVNjYWxhYmxlVGFyZ2V0YCxcbiAgICAgIHtcbiAgICAgICAgc2VydmljZU5hbWVzcGFjZTogU2VydmljZU5hbWVzcGFjZS5FQ1MsXG4gICAgICAgIHJlc291cmNlSWQ6IGBzZXJ2aWNlLyR7dGhpcy5jbHVzdGVyLmNsdXN0ZXJOYW1lfS8ke3NlcnZpY2Uuc2VydmljZU5hbWV9YCxcbiAgICAgICAgc2NhbGFibGVEaW1lbnNpb246IFwiZWNzOnNlcnZpY2U6RGVzaXJlZENvdW50XCIsXG4gICAgICAgIG1pbkNhcGFjaXR5OiBzZXJ2aWNlUHJvcHMubWluQ2FwYWNpdHkgPz8gMixcbiAgICAgICAgbWF4Q2FwYWNpdHk6IHNlcnZpY2VQcm9wcy5tYXhDYXBhY2l0eSA/PyAxMFxuICAgICAgfVxuICAgICk7XG5cbiAgICByZXR1cm4gbmV3IFRhcmdldFRyYWNraW5nU2NhbGluZ1BvbGljeShcbiAgICAgIHRoaXMsXG4gICAgICBgJHtzZXJ2aWNlTmFtZX1TY2FsaW5nUG9saWN5YCxcbiAgICAgIHtcbiAgICAgICAgc2NhbGluZ1RhcmdldDogc2NhbGFibGVUYXJnZXQsXG4gICAgICAgIHByZWRlZmluZWRNZXRyaWM6XG4gICAgICAgICAgc2VydmljZVByb3BzLnNjYWxpbmdUeXBlID09PSBTY2FsaW5nVHlwZS5NRU1PUllcbiAgICAgICAgICAgID8gUHJlZGVmaW5lZE1ldHJpYy5FQ1NfU0VSVklDRV9BVkVSQUdFX01FTU9SWV9VVElMSVpBVElPTlxuICAgICAgICAgICAgOiBQcmVkZWZpbmVkTWV0cmljLkVDU19TRVJWSUNFX0FWRVJBR0VfQ1BVX1VUSUxJWkFUSU9OLFxuICAgICAgICB0YXJnZXRWYWx1ZTogNTAsXG4gICAgICAgIHNjYWxlSW5Db29sZG93bjogRHVyYXRpb24uc2Vjb25kcyg2MCksXG4gICAgICAgIHNjYWxlT3V0Q29vbGRvd246IER1cmF0aW9uLnNlY29uZHMoNjApXG4gICAgICB9XG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVjayBpZiB0aGUgVlBDIGhhcyBOQVQgZ2F0ZXdheXMuXG4gICAqIC0gRm9yIEZqYWxsIFZwYzogdXNlcyBoYXNOYXRHYXRld2F5cyBwcm9wZXJ0eVxuICAgKiAtIEZvciBvdGhlciBWUENzOiBjaGVja3MgaWYgcHJpdmF0ZSBzdWJuZXRzIGV4aXN0IChhc3N1bWVzIE5BVCBpZiBwcmVzZW50KVxuICAgKi9cbiAgcHJpdmF0ZSB2cGNIYXNOYXRHYXRld2F5cygpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdnBjSGFzTmF0R2F0ZXdheXModGhpcy5jbHVzdGVyLnZwYyk7XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlIERlcGxveWFibGVTZXJ2aWNlIG91dHB1dHMgZm9yIGRlcGxveW1lbnQgYXV0b21hdGlvbi5cbiAgICogRWFjaCBzZXJ2aWNlIGdldHMgYSBEZXBsb3lhYmxlU2VydmljZSBvdXRwdXQgc28gdGhlIGRlcGxveW1lbnQgc2VydmljZVxuICAgKiBjYW4gZmluZCBhbmQgZGVwbG95IGFsbCBzZXJ2aWNlcyBpbiB0aGUgY2x1c3Rlci5cbiAgICovXG4gIHByaXZhdGUgYWRkRGVwbG95YWJsZVNlcnZpY2VPdXRwdXRzKHByb3BzOiBFY3NDbHVzdGVyUHJvcHMpIHtcbiAgICBmb3IgKGNvbnN0IFtzZXJ2aWNlTmFtZSwgc2VydmljZURhdGFdIG9mIHRoaXMuc2VydmljZXMpIHtcbiAgICAgIGNvbnN0IHNhZmVTZXJ2aWNlTmFtZSA9IHRvUGFzY2FsQ2FzZShzZXJ2aWNlTmFtZSk7XG4gICAgICBuZXcgQ2ZuT3V0cHV0KFxuICAgICAgICB0aGlzLFxuICAgICAgICBgJHt0aGlzLm91dHB1dE5hbWV9JHtzYWZlU2VydmljZU5hbWV9RGVwbG95YWJsZVNlcnZpY2VgLFxuICAgICAgICB7XG4gICAgICAgICAga2V5OiBgJHt0aGlzLm91dHB1dE5hbWV9JHtzYWZlU2VydmljZU5hbWV9RGVwbG95YWJsZVNlcnZpY2VgLFxuICAgICAgICAgIGV4cG9ydE5hbWU6IGAke3Byb3BzLmNsdXN0ZXJOYW1lfSR7c2VydmljZU5hbWV9RGVwbG95YWJsZVNlcnZpY2VgLFxuICAgICAgICAgIHZhbHVlOiBzZXJ2aWNlRGF0YS5zZXJ2aWNlLnNlcnZpY2VBcm4sXG4gICAgICAgICAgZGVzY3JpcHRpb246IGBEZXBsb3lhYmxlIEVDUyBTZXJ2aWNlIEFSTiBmb3IgJHtzZXJ2aWNlTmFtZX0gaW4gJHtwcm9wcy5jbHVzdGVyTmFtZX1gXG4gICAgICAgIH1cbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEdldHMgdGhlIGNhcGFjaXR5IHByb3ZpZGVyIGZvciBhIHNlcnZpY2UuXG4gICAqIEVhY2ggc2VydmljZSBNVVNUIHNwZWNpZnkgaXRzIG93biBjYXBhY2l0eVByb3ZpZGVyLlxuICAgKi9cbiAgcHJpdmF0ZSBnZXRTZXJ2aWNlQ2FwYWNpdHlQcm92aWRlcihcbiAgICBzZXJ2aWNlUHJvcHM6IEVjc1NlcnZpY2VQcm9wc1xuICApOiBFY3NDYXBhY2l0eVByb3ZpZGVyIHtcbiAgICByZXR1cm4gc2VydmljZVByb3BzLmNhcGFjaXR5UHJvdmlkZXI7XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2tzIGlmIGEgc2VydmljZSB1c2VzIGEgRmFyZ2F0ZSBjYXBhY2l0eSBwcm92aWRlci5cbiAgICovXG4gIHByaXZhdGUgaXNTZXJ2aWNlRmFyZ2F0ZShzZXJ2aWNlUHJvcHM6IEVjc1NlcnZpY2VQcm9wcyk6IGJvb2xlYW4ge1xuICAgIGNvbnN0IHByb3ZpZGVyID0gdGhpcy5nZXRTZXJ2aWNlQ2FwYWNpdHlQcm92aWRlcihzZXJ2aWNlUHJvcHMpO1xuICAgIHJldHVybiBwcm92aWRlciA9PT0gXCJGQVJHQVRFXCIgfHwgcHJvdmlkZXIgPT09IFwiRkFSR0FURV9TUE9UXCI7XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2tzIGlmIGEgc2VydmljZSB1c2VzIGFuIEVDMiBjYXBhY2l0eSBwcm92aWRlci5cbiAgICovXG4gIHByaXZhdGUgaXNTZXJ2aWNlRWMyKHNlcnZpY2VQcm9wczogRWNzU2VydmljZVByb3BzKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuZ2V0U2VydmljZUNhcGFjaXR5UHJvdmlkZXIoc2VydmljZVByb3BzKSA9PT0gXCJFQzJcIjtcbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZXMgYW4gU1NNIHBhdGggY29tcG9uZW50IGZvciBjb3JyZWN0bmVzcy5cbiAgICogU1NNIHBhcmFtZXRlciBwYXRocyBoYXZlIHNwZWNpZmljIGNvbnN0cmFpbnRzIHRoYXQgbXVzdCBiZSBlbmZvcmNlZC5cbiAgICpcbiAgICogQHBhcmFtIGNvbXBvbmVudCAtIFRoZSBwYXRoIGNvbXBvbmVudCB0byB2YWxpZGF0ZVxuICAgKiBAcGFyYW0gZmllbGROYW1lIC0gTmFtZSBvZiB0aGUgZmllbGQgZm9yIGVycm9yIG1lc3NhZ2VzXG4gICAqIEB0aHJvd3MgRXJyb3IgaWYgdGhlIGNvbXBvbmVudCBpcyBpbnZhbGlkXG4gICAqL1xuICBwcml2YXRlIHZhbGlkYXRlU3NtUGF0aENvbXBvbmVudChjb21wb25lbnQ6IHN0cmluZywgZmllbGROYW1lOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBpZiAoIWNvbXBvbmVudCB8fCBjb21wb25lbnQudHJpbSgpID09PSBcIlwiKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYCR7ZmllbGROYW1lfSBjYW5ub3QgYmUgZW1wdHkgZm9yIFNTTSBwYXRoIGRlcml2YXRpb25gKTtcbiAgICB9XG4gICAgaWYgKGNvbXBvbmVudC5pbmNsdWRlcyhcIi9cIikpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYCR7ZmllbGROYW1lfSBjYW5ub3QgY29udGFpbiBmb3J3YXJkIHNsYXNoZXMgKC8pLiBJbnZhbGlkIHZhbHVlOiBcIiR7Y29tcG9uZW50fVwiLmBcbiAgICAgICk7XG4gICAgfVxuICAgIC8vIFNTTSBwYXJhbWV0ZXIgbmFtZSBoaWVyYXJjaHkgbGFiZWxzIGhhdmUgYSBtYXggbGVuZ3RoIG9mIDIwNDgsIGJ1dCB3ZSB1c2UgYSBtb3JlXG4gICAgLy8gcmVhc29uYWJsZSBsaW1pdCBzaW5jZSBlYWNoIGNvbXBvbmVudCBpcyBqdXN0IG9uZSBwYXJ0IG9mIHRoZSBwYXRoXG4gICAgaWYgKGNvbXBvbmVudC5sZW5ndGggPiAxMjgpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgJHtmaWVsZE5hbWV9IGV4Y2VlZHMgbWF4aW11bSBsZW5ndGggKDEyOCBjaGFyYWN0ZXJzKS5gKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQ29sbGVjdHMgYWxsIFNlY3JldHMgTWFuYWdlciBzZWNyZXQgbmFtZXMgZnJvbSBzZWNyZXRzSW1wb3J0IGFjcm9zcyBhbGwgc2VydmljZXMuXG4gICAqIFVzZWQgdG8gc2NvcGUgSUFNIHBlcm1pc3Npb25zIGZvciBsZWFzdC1wcml2aWxlZ2UgYWNjZXNzLlxuICAgKi9cbiAgcHJpdmF0ZSBjb2xsZWN0U2VjcmV0c01hbmFnZXJTZWNyZXROYW1lcygpOiBzdHJpbmdbXSB7XG4gICAgY29uc3Qgc2VjcmV0TmFtZXMgPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgICBmb3IgKGNvbnN0IHNlcnZpY2Ugb2YgdGhpcy5wcm9wcy5zZXJ2aWNlcykge1xuICAgICAgZm9yIChjb25zdCBjb250YWluZXIgb2Ygc2VydmljZS5jb250YWluZXJzKSB7XG4gICAgICAgIGlmIChjb250YWluZXIuc2VjcmV0c0ltcG9ydCkge1xuICAgICAgICAgIGZvciAoY29uc3Qgc2VjcmV0SW1wb3J0IG9mIE9iamVjdC52YWx1ZXMoY29udGFpbmVyLnNlY3JldHNJbXBvcnQpKSB7XG4gICAgICAgICAgICBzZWNyZXROYW1lcy5hZGQoc2VjcmV0SW1wb3J0Lm5hbWUpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gQXJyYXkuZnJvbShzZWNyZXROYW1lcyk7XG4gIH1cblxuICAvKipcbiAgICogRGVyaXZlcyB0aGUgU1NNIHNlY3JldHMgcGF0aCBmb3IgYSBzZXJ2aWNlLlxuICAgKiBVc2VzIGV4cGxpY2l0IHBhdGggaWYgcHJvdmlkZWQsIG90aGVyd2lzZSBkZXJpdmVzIGZyb20gYXBwL2NsdXN0ZXIvc2VydmljZSBuYW1lcy5cbiAgICovXG4gIHByaXZhdGUgZGVyaXZlU3NtU2VjcmV0c1BhdGgoXG4gICAgc2VydmljZU5hbWU6IHN0cmluZyxcbiAgICBleHBsaWNpdFBhdGg/OiBzdHJpbmdcbiAgKTogc3RyaW5nIHtcbiAgICBpZiAoZXhwbGljaXRQYXRoKSB7XG4gICAgICByZXR1cm4gZXhwbGljaXRQYXRoO1xuICAgIH1cblxuICAgIGNvbnN0IGFwcE5hbWUgPSB0aGlzLnByb3BzLmFwcE5hbWU7XG4gICAgaWYgKCFhcHBOYW1lKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBTZXJ2aWNlICcke3NlcnZpY2VOYW1lfScgaGFzIHNlY3JldHMgZGVmaW5lZCBidXQgbm8gc3NtU2VjcmV0c1BhdGggaXMgc2V0IGAgK1xuICAgICAgICAgIGBhbmQgYXBwTmFtZSBpcyBub3QgY29uZmlndXJlZCBvbiB0aGUgY2x1c3Rlci4gYCArXG4gICAgICAgICAgYEVpdGhlciBzZXQgc3NtU2VjcmV0c1BhdGggb24gdGhlIHNlcnZpY2UsIG9yIHNldCBhcHBOYW1lIG9uIHRoZSBjbHVzdGVyIHByb3BzIGAgK1xuICAgICAgICAgIGB0byBlbmFibGUgYXV0b21hdGljIHBhdGggZGVyaXZhdGlvbiAoLzxhcHBOYW1lPi88Y2x1c3Rlck5hbWU+LzxzZXJ2aWNlTmFtZT4pLmBcbiAgICAgICk7XG4gICAgfVxuXG4gICAgdGhpcy52YWxpZGF0ZVNzbVBhdGhDb21wb25lbnQoYXBwTmFtZSwgXCJhcHBOYW1lXCIpO1xuICAgIHRoaXMudmFsaWRhdGVTc21QYXRoQ29tcG9uZW50KHRoaXMucHJvcHMuY2x1c3Rlck5hbWUsIFwiY2x1c3Rlck5hbWVcIik7XG4gICAgdGhpcy52YWxpZGF0ZVNzbVBhdGhDb21wb25lbnQoc2VydmljZU5hbWUsIFwic2VydmljZU5hbWVcIik7XG5cbiAgICByZXR1cm4gYC8ke2FwcE5hbWV9LyR7dGhpcy5wcm9wcy5jbHVzdGVyTmFtZX0vJHtzZXJ2aWNlTmFtZX1gO1xuICB9XG5cbiAgLyoqXG4gICAqIEdlbmVyYXRlcyBhIHVuaXF1ZSBrZXkgZm9yIEVDMiBjb25maWcgKGZvciBBU0cgZGVkdXBsaWNhdGlvbikuXG4gICAqIFNlcnZpY2VzIHdpdGggbWF0Y2hpbmcga2V5cyBzaGFyZSBhbiBBU0cuXG4gICAqL1xuICBwcml2YXRlIGdldEVjMkNvbmZpZ0tleShlYzJDb25maWc6IEVjMkNhcGFjaXR5Q29uZmlnKTogc3RyaW5nIHtcbiAgICBjb25zdCBpbnN0YW5jZVR5cGUgPSBlYzJDb25maWcuaW5zdGFuY2VUeXBlID8/IERFRkFVTFRfRUMyX0lOU1RBTkNFX1RZUEU7XG4gICAgY29uc3QgYW1pSGFyZHdhcmVUeXBlID1cbiAgICAgIGVjMkNvbmZpZy5hbWlIYXJkd2FyZVR5cGUgPz9cbiAgICAgIChpbmZlckFtaUhhcmR3YXJlVHlwZShpbnN0YW5jZVR5cGUpID09PSBBbWlIYXJkd2FyZVR5cGUuQVJNXG4gICAgICAgID8gXCJBUk1cIlxuICAgICAgICA6IFwiU1RBTkRBUkRcIik7XG4gICAgY29uc3Qgd2FybVBvb2xLZXkgPSBlYzJDb25maWcud2FybVBvb2xcbiAgICAgID8gYHdwJHtlYzJDb25maWcud2FybVBvb2wubWluU2l6ZSA/PyBERUZBVUxUX1dBUk1fUE9PTF9NSU5fU0laRX0tJHtlYzJDb25maWcud2FybVBvb2wucmV1c2VPblNjYWxlSW4gPz8gREVGQVVMVF9XQVJNX1BPT0xfUkVVU0VfT05fU0NBTEVfSU59YFxuICAgICAgOiBcIm5vd3BcIjtcbiAgICByZXR1cm4gYCR7aW5zdGFuY2VUeXBlfS0ke2FtaUhhcmR3YXJlVHlwZX0tJHt3YXJtUG9vbEtleX1gO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldHMgb3IgY3JlYXRlcyBhbiBBU0cgY2FwYWNpdHkgcHJvdmlkZXIgZm9yIGEgc2VydmljZS5cbiAgICogU2VydmljZXMgd2l0aCBtYXRjaGluZyBFQzIgY29uZmlncyBzaGFyZSB0aGUgc2FtZSBBU0cuXG4gICAqL1xuICBwcml2YXRlIGdldE9yQ3JlYXRlQXNnQ2FwYWNpdHlQcm92aWRlcihcbiAgICBzZXJ2aWNlUHJvcHM6IEVjc1NlcnZpY2VQcm9wc1xuICApOiBBc2dDYXBhY2l0eVByb3ZpZGVyIHtcbiAgICBjb25zdCBlYzJDb25maWcgPSBzZXJ2aWNlUHJvcHMuZWMyQ29uZmlnID8/IHt9O1xuICAgIGNvbnN0IGtleSA9IHRoaXMuZ2V0RWMyQ29uZmlnS2V5KGVjMkNvbmZpZyk7XG5cbiAgICBjb25zdCBleGlzdGluZyA9IHRoaXMuYXNnQ2FwYWNpdHlQcm92aWRlcnMuZ2V0KGtleSk7XG4gICAgaWYgKGV4aXN0aW5nKSB7XG4gICAgICByZXR1cm4gZXhpc3Rpbmc7XG4gICAgfVxuXG4gICAgY29uc3Qgc2FmZUtleSA9IGtleS5yZXBsYWNlKC9bXmEtekEtWjAtOV0vZywgXCJcIik7XG4gICAgY29uc3QgaW5zdGFuY2VUeXBlID0gZWMyQ29uZmlnLmluc3RhbmNlVHlwZSA/PyBERUZBVUxUX0VDMl9JTlNUQU5DRV9UWVBFO1xuICAgIGNvbnN0IGFtaUhhcmR3YXJlVHlwZSA9IGVjMkNvbmZpZy5hbWlIYXJkd2FyZVR5cGVcbiAgICAgID8gZWMyQ29uZmlnLmFtaUhhcmR3YXJlVHlwZSA9PT0gXCJTVEFOREFSRFwiXG4gICAgICAgID8gQW1pSGFyZHdhcmVUeXBlLlNUQU5EQVJEXG4gICAgICAgIDogQW1pSGFyZHdhcmVUeXBlLkFSTVxuICAgICAgOiBpbmZlckFtaUhhcmR3YXJlVHlwZShpbnN0YW5jZVR5cGUpO1xuICAgIGNvbnN0IG1pbkNhcGFjaXR5ID0gZWMyQ29uZmlnLm1pbkNhcGFjaXR5ID8/IDI7XG4gICAgY29uc3QgbWF4Q2FwYWNpdHkgPSBlYzJDb25maWcubWF4Q2FwYWNpdHkgPz8gMztcblxuICAgIGNvbnN0IGFzZ1NlY3VyaXR5R3JvdXAgPSBuZXcgU2VjdXJpdHlHcm91cChcbiAgICAgIHRoaXMsXG4gICAgICBgJHtzYWZlS2V5fUFzZ1NlY3VyaXR5R3JvdXBgLFxuICAgICAge1xuICAgICAgICB2cGM6IHRoaXMuY2x1c3Rlci52cGMsXG4gICAgICAgIGRlc2NyaXB0aW9uOiBgU2VjdXJpdHkgZ3JvdXAgZm9yICR7a2V5fSBhdXRvIHNjYWxpbmcgZ3JvdXBgXG4gICAgICB9XG4gICAgKTtcblxuICAgIGlmICh0aGlzLmRpcmVjdEFjY2Vzc0VuYWJsZWQpIHtcbiAgICAgIGZvciAoY29uc3Qgc2VydmljZSBvZiB0aGlzLnByb3BzLnNlcnZpY2VzKSB7XG4gICAgICAgIGlmICh0aGlzLmlzU2VydmljZUVjMihzZXJ2aWNlKSkge1xuICAgICAgICAgIGZvciAoY29uc3QgY29udGFpbmVyIG9mIHNlcnZpY2UuY29udGFpbmVycykge1xuICAgICAgICAgICAgaWYgKGNvbnRhaW5lci5wb3J0KSB7XG4gICAgICAgICAgICAgIGFzZ1NlY3VyaXR5R3JvdXAuYWRkSW5ncmVzc1J1bGUoXG4gICAgICAgICAgICAgICAgUGVlci5hbnlJcHY0KCksXG4gICAgICAgICAgICAgICAgUG9ydC50Y3AoY29udGFpbmVyLnBvcnQpLFxuICAgICAgICAgICAgICAgIGBEaXJlY3QgYWNjZXNzIHRvIGNvbnRhaW5lciBwb3J0ICR7Y29udGFpbmVyLnBvcnR9YFxuICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIGNvbnN0IGhhc05hdCA9IHRoaXMudnBjSGFzTmF0R2F0ZXdheXMoKTtcbiAgICBjb25zdCBhc2cgPSBuZXcgQXV0b1NjYWxpbmdHcm91cCh0aGlzLCBgJHtzYWZlS2V5fUF1dG9TY2FsaW5nR3JvdXBgLCB7XG4gICAgICBhdXRvU2NhbGluZ0dyb3VwTmFtZTogYCR7dGhpcy5wcm9wcy5jbHVzdGVyTmFtZX0tJHtzYWZlS2V5fS1Bc2dgLFxuICAgICAgdnBjOiB0aGlzLmNsdXN0ZXIudnBjLFxuICAgICAgdnBjU3VibmV0czoge1xuICAgICAgICBzdWJuZXRUeXBlOiBoYXNOYXQgPyBTdWJuZXRUeXBlLlBSSVZBVEVfV0lUSF9FR1JFU1MgOiBTdWJuZXRUeXBlLlBVQkxJQ1xuICAgICAgfSxcbiAgICAgIHNlY3VyaXR5R3JvdXA6IGFzZ1NlY3VyaXR5R3JvdXAsXG4gICAgICBtaW5DYXBhY2l0eSxcbiAgICAgIG1heENhcGFjaXR5LFxuICAgICAgaW5zdGFuY2VUeXBlOiBuZXcgSW5zdGFuY2VUeXBlKGluc3RhbmNlVHlwZSksXG4gICAgICBjYXBhY2l0eVJlYmFsYW5jZTogdHJ1ZSxcbiAgICAgIGluc3RhbmNlTW9uaXRvcmluZzogTW9uaXRvcmluZy5CQVNJQyxcbiAgICAgIG1hY2hpbmVJbWFnZTogRWNzT3B0aW1pemVkSW1hZ2UuYW1hem9uTGludXgyMDIzKGFtaUhhcmR3YXJlVHlwZSlcbiAgICB9KTtcblxuICAgIGlmIChlYzJDb25maWcud2FybVBvb2wpIHtcbiAgICAgIGFzZy5hZGRXYXJtUG9vbCh7XG4gICAgICAgIG1pblNpemU6IGVjMkNvbmZpZy53YXJtUG9vbC5taW5TaXplID8/IERFRkFVTFRfV0FSTV9QT09MX01JTl9TSVpFLFxuICAgICAgICByZXVzZU9uU2NhbGVJbjpcbiAgICAgICAgICBlYzJDb25maWcud2FybVBvb2wucmV1c2VPblNjYWxlSW4gPz9cbiAgICAgICAgICBERUZBVUxUX1dBUk1fUE9PTF9SRVVTRV9PTl9TQ0FMRV9JTlxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgY29uc3QgcHJvdmlkZXIgPSBuZXcgQXNnQ2FwYWNpdHlQcm92aWRlcihcbiAgICAgIHRoaXMsXG4gICAgICBgJHtzYWZlS2V5fUFzZ0NhcGFjaXR5UHJvdmlkZXJgLFxuICAgICAge1xuICAgICAgICBhdXRvU2NhbGluZ0dyb3VwOiBhc2csXG4gICAgICAgIGVuYWJsZU1hbmFnZWREcmFpbmluZzogdHJ1ZSxcbiAgICAgICAgZW5hYmxlTWFuYWdlZFRlcm1pbmF0aW9uUHJvdGVjdGlvbjogZmFsc2VcbiAgICAgIH1cbiAgICApO1xuXG4gICAgdGhpcy5jbHVzdGVyLmFkZEFzZ0NhcGFjaXR5UHJvdmlkZXIocHJvdmlkZXIpO1xuICAgIHRoaXMuYXNnQ2FwYWNpdHlQcm92aWRlcnMuc2V0KGtleSwgcHJvdmlkZXIpO1xuXG4gICAgaWYgKCF0aGlzLmF1dG9TY2FsaW5nR3JvdXApIHtcbiAgICAgIHRoaXMuYXV0b1NjYWxpbmdHcm91cCA9IGFzZztcbiAgICB9XG4gICAgaWYgKCF0aGlzLmFzZ1NlY3VyaXR5R3JvdXApIHtcbiAgICAgIHRoaXMuYXNnU2VjdXJpdHlHcm91cCA9IGFzZ1NlY3VyaXR5R3JvdXA7XG4gICAgfVxuXG4gICAgcmV0dXJuIHByb3ZpZGVyO1xuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrcyBpZiBhbnkgc2VydmljZSBpbiB0aGUgY2x1c3RlciB1c2VzIGEgRmFyZ2F0ZSBjYXBhY2l0eSBwcm92aWRlci5cbiAgICovXG4gIHByaXZhdGUgYW55U2VydmljZVVzZXNGYXJnYXRlKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLnByb3BzLnNlcnZpY2VzLnNvbWUoKHMpID0+IHRoaXMuaXNTZXJ2aWNlRmFyZ2F0ZShzKSk7XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2tzIGlmIGFueSBzZXJ2aWNlIGluIHRoZSBjbHVzdGVyIHVzZXMgYW4gRUMyIGNhcGFjaXR5IHByb3ZpZGVyLlxuICAgKi9cbiAgcHJpdmF0ZSBhbnlTZXJ2aWNlVXNlc0VjMigpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5wcm9wcy5zZXJ2aWNlcy5zb21lKChzKSA9PiB0aGlzLmlzU2VydmljZUVjMihzKSk7XG4gIH1cblxuICBwcml2YXRlIGFkZENsdXN0ZXIocHJvcHM6IEVjc0NsdXN0ZXJQcm9wcykge1xuICAgIGNvbnN0IG5lZWRzRmFyZ2F0ZSA9IHRoaXMuYW55U2VydmljZVVzZXNGYXJnYXRlKCk7XG5cbiAgICB0aGlzLmNsdXN0ZXIgPSBuZXcgQ2RrQ2x1c3Rlcih0aGlzLCBgJHtwcm9wcy5jbHVzdGVyTmFtZX1DbHVzdGVyYCwge1xuICAgICAgdnBjOiBwcm9wcy52cGMsXG4gICAgICBjbHVzdGVyTmFtZTogcHJvcHMuY2x1c3Rlck5hbWUsXG4gICAgICBjb250YWluZXJJbnNpZ2h0c1YyOiBDb250YWluZXJJbnNpZ2h0cy5FTkFCTEVELFxuICAgICAgZW5hYmxlRmFyZ2F0ZUNhcGFjaXR5UHJvdmlkZXJzOiBuZWVkc0ZhcmdhdGVcbiAgICB9KTtcblxuICAgIG5ldyBDZm5PdXRwdXQodGhpcywgYCR7dGhpcy5vdXRwdXROYW1lfURlcGxveWFibGVDbHVzdGVyYCwge1xuICAgICAga2V5OiBgJHt0aGlzLm91dHB1dE5hbWV9RGVwbG95YWJsZUNsdXN0ZXJgLFxuICAgICAgZXhwb3J0TmFtZTogYCR7cHJvcHMuY2x1c3Rlck5hbWV9RGVwbG95YWJsZUNsdXN0ZXJgLFxuICAgICAgdmFsdWU6IHRoaXMuY2x1c3Rlci5jbHVzdGVyQXJuXG4gICAgfSk7XG5cbiAgICBuZXcgQ2ZuT3V0cHV0KHRoaXMsIGAke3RoaXMub3V0cHV0TmFtZX1DbHVzdGVyQXJuYCwge1xuICAgICAga2V5OiBgJHt0aGlzLm91dHB1dE5hbWV9Q2x1c3RlckFybmAsXG4gICAgICBleHBvcnROYW1lOiBgJHtwcm9wcy5jbHVzdGVyTmFtZX1DbHVzdGVyQXJuYCxcbiAgICAgIHZhbHVlOiB0aGlzLmNsdXN0ZXIuY2x1c3RlckFybixcbiAgICAgIGRlc2NyaXB0aW9uOiBgRUNTIENsdXN0ZXIgQVJOIGZvciAke3Byb3BzLmNsdXN0ZXJOYW1lfWBcbiAgICB9KTtcbiAgfVxuXG4gIC8vIE5vdGU6IGFkZEF1dG9TY2FsaW5nR3JvdXAgcmVtb3ZlZCAtIEFTR3MgYXJlIG5vdyBjcmVhdGVkIHBlci1zZXJ2aWNlIHZpYSBnZXRPckNyZWF0ZUFzZ0NhcGFjaXR5UHJvdmlkZXJcblxuICBwcml2YXRlIGFkZExvYWRCYWxhbmNlcihwcm9wczogRWNzQ2x1c3RlclByb3BzKSB7XG4gICAgY29uc3QgZGVmYXVsdExvYWRCYWxhbmNlck5hbWUgPSBgJHtwcm9wcy5jbHVzdGVyTmFtZX1Mb2FkQmFsYW5jZXJgO1xuICAgIGNvbnN0IHN1cHBvcnRlZE5hbWVMZW5ndGggPSAzMjtcblxuICAgIGxldCB0cnVuY2F0ZWRMb2FkQmFsYW5jZXJOYW1lID1cbiAgICAgIGRlZmF1bHRMb2FkQmFsYW5jZXJOYW1lLmxlbmd0aCA+IHN1cHBvcnRlZE5hbWVMZW5ndGhcbiAgICAgICAgPyBkZWZhdWx0TG9hZEJhbGFuY2VyTmFtZS5zdWJzdHJpbmcoMCwgc3VwcG9ydGVkTmFtZUxlbmd0aClcbiAgICAgICAgOiBkZWZhdWx0TG9hZEJhbGFuY2VyTmFtZTtcblxuICAgIHRydW5jYXRlZExvYWRCYWxhbmNlck5hbWUgPSB0cnVuY2F0ZWRMb2FkQmFsYW5jZXJOYW1lLnJlcGxhY2UoLy0rJC8sIFwiXCIpO1xuXG4gICAgY29uc3QgaXNJbnRlcm5hbCA9IHByb3BzLmNsdXN0ZXI/LmxvYWRCYWxhbmNlciA9PT0gXCJpbnRlcm5hbFwiO1xuXG4gICAgY29uc3QgaGFzRWMyU2VydmljZXMgPSB0aGlzLmFueVNlcnZpY2VVc2VzRWMyKCk7XG5cbiAgICBpZiAoaGFzRWMyU2VydmljZXMpIHtcbiAgICAgIHRoaXMubG9hZEJhbGFuY2VyU2VjdXJpdHlHcm91cCA9IG5ldyBTZWN1cml0eUdyb3VwKFxuICAgICAgICB0aGlzLFxuICAgICAgICBgJHtwcm9wcy5jbHVzdGVyTmFtZX1Mb2FkQmFsYW5jZXJTZWN1cml0eUdyb3VwYCxcbiAgICAgICAge1xuICAgICAgICAgIHZwYzogdGhpcy5jbHVzdGVyLnZwYyxcbiAgICAgICAgICBkZXNjcmlwdGlvbjogYFNlY3VyaXR5IGdyb3VwIGZvciB0aGUgJHtwcm9wcy5jbHVzdGVyTmFtZX0gbG9hZCBiYWxhbmNlcmBcbiAgICAgICAgfVxuICAgICAgKTtcblxuICAgICAgaWYgKHRoaXMuYXNnU2VjdXJpdHlHcm91cCkge1xuICAgICAgICB0aGlzLmxvYWRCYWxhbmNlclNlY3VyaXR5R3JvdXAuY29ubmVjdGlvbnMuYWxsb3dUbyhcbiAgICAgICAgICB0aGlzLmFzZ1NlY3VyaXR5R3JvdXAsXG4gICAgICAgICAgUG9ydC5hbGxUY3AoKVxuICAgICAgICApO1xuICAgICAgICAvLyBFQ1MgYnJpZGdlLW1vZGUgbWFwcyBjb250YWluZXIgcG9ydHMgdG8gSUFOQSBlcGhlbWVyYWwgcmFuZ2UgKDQ5MTUyLTY1NTM1KS5cbiAgICAgICAgLy8gVGhlIEFMQiBtdXN0IHJlYWNoIHRoZXNlIGR5bmFtaWMgcG9ydHMgb24gdGhlIEVDMiBpbnN0YW5jZXMuXG4gICAgICAgIHRoaXMuYXNnU2VjdXJpdHlHcm91cC5jb25uZWN0aW9ucy5hbGxvd0Zyb20oXG4gICAgICAgICAgdGhpcy5sb2FkQmFsYW5jZXJTZWN1cml0eUdyb3VwLFxuICAgICAgICAgIFBvcnQudGNwUmFuZ2UoNDkxNTIsIDY1NTM1KVxuICAgICAgICApO1xuICAgICAgfVxuXG4gICAgICB0aGlzLmxvYWRCYWxhbmNlciA9IG5ldyBBcHBsaWNhdGlvbkxvYWRCYWxhbmNlcihcbiAgICAgICAgdGhpcyxcbiAgICAgICAgYCR7cHJvcHMuY2x1c3Rlck5hbWV9TG9hZEJhbGFuY2VyYCxcbiAgICAgICAge1xuICAgICAgICAgIHZwYzogdGhpcy5jbHVzdGVyLnZwYyxcbiAgICAgICAgICBpbnRlcm5ldEZhY2luZzogIWlzSW50ZXJuYWwsXG4gICAgICAgICAgc2VjdXJpdHlHcm91cDogdGhpcy5sb2FkQmFsYW5jZXJTZWN1cml0eUdyb3VwLFxuICAgICAgICAgIGxvYWRCYWxhbmNlck5hbWU6IHRydW5jYXRlZExvYWRCYWxhbmNlck5hbWUsXG4gICAgICAgICAgdnBjU3VibmV0czoge1xuICAgICAgICAgICAgc3VibmV0VHlwZTogaXNJbnRlcm5hbFxuICAgICAgICAgICAgICA/IFN1Ym5ldFR5cGUuUFJJVkFURV9XSVRIX0VHUkVTU1xuICAgICAgICAgICAgICA6IFN1Ym5ldFR5cGUuUFVCTElDXG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICApO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLmxvYWRCYWxhbmNlciA9IG5ldyBBcHBsaWNhdGlvbkxvYWRCYWxhbmNlcihcbiAgICAgICAgdGhpcyxcbiAgICAgICAgYCR7cHJvcHMuY2x1c3Rlck5hbWV9TG9hZEJhbGFuY2VyYCxcbiAgICAgICAge1xuICAgICAgICAgIHZwYzogdGhpcy5jbHVzdGVyLnZwYyxcbiAgICAgICAgICBpbnRlcm5ldEZhY2luZzogIWlzSW50ZXJuYWwsXG4gICAgICAgICAgbG9hZEJhbGFuY2VyTmFtZTogdHJ1bmNhdGVkTG9hZEJhbGFuY2VyTmFtZSxcbiAgICAgICAgICB2cGNTdWJuZXRzOiB7XG4gICAgICAgICAgICBzdWJuZXRUeXBlOiBpc0ludGVybmFsXG4gICAgICAgICAgICAgID8gU3VibmV0VHlwZS5QUklWQVRFX1dJVEhfRUdSRVNTXG4gICAgICAgICAgICAgIDogU3VibmV0VHlwZS5QVUJMSUNcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICk7XG4gICAgfVxuXG4gICAgbmV3IENmbk91dHB1dCh0aGlzLCBgJHt0aGlzLm91dHB1dE5hbWV9TG9hZEJhbGFuY2VyRG5zTmFtZWAsIHtcbiAgICAgIGtleTogYCR7dGhpcy5vdXRwdXROYW1lfUxvYWRCYWxhbmNlckRuc05hbWVgLFxuICAgICAgZXhwb3J0TmFtZTogYCR7cHJvcHMuY2x1c3Rlck5hbWV9TG9hZEJhbGFuY2VyRG5zTmFtZWAsXG4gICAgICB2YWx1ZTogdGhpcy5sb2FkQmFsYW5jZXIubG9hZEJhbGFuY2VyRG5zTmFtZVxuICAgIH0pO1xuXG4gICAgY29uc3QgY3VzdG9tRG9tYWluID1cbiAgICAgIHByb3BzLmNsdXN0ZXI/LmRvbWFpbiB8fCBwcm9wcy5jbHVzdGVyPy5kb21haW5Db25maWc/LmRvbWFpbk5hbWU7XG5cbiAgICBuZXcgQ2ZuT3V0cHV0KHRoaXMsIGAke3RoaXMub3V0cHV0TmFtZX1Mb2FkQmFsYW5jZXJVcmxgLCB7XG4gICAgICBrZXk6IGAke3RoaXMub3V0cHV0TmFtZX1Mb2FkQmFsYW5jZXJVcmxgLFxuICAgICAgZXhwb3J0TmFtZTogYCR7cHJvcHMuY2x1c3Rlck5hbWV9TG9hZEJhbGFuY2VyVXJsYCxcbiAgICAgIHZhbHVlOiBjdXN0b21Eb21haW5cbiAgICAgICAgPyBgaHR0cHM6Ly8ke2N1c3RvbURvbWFpbn1gXG4gICAgICAgIDogYGh0dHA6Ly8ke3RoaXMubG9hZEJhbGFuY2VyLmxvYWRCYWxhbmNlckRuc05hbWV9YCxcbiAgICAgIGRlc2NyaXB0aW9uOiBgTG9hZCBCYWxhbmNlciBVUkwgZm9yICR7cHJvcHMuY2x1c3Rlck5hbWV9YFxuICAgIH0pO1xuXG4gICAgLy8gRXhwb3J0IGxvYWQgYmFsYW5jZXIgQVJOIGZvciBtb25pdG9yaW5nXG4gICAgbmV3IENmbk91dHB1dCh0aGlzLCBgJHt0aGlzLm91dHB1dE5hbWV9TG9hZEJhbGFuY2VyQXJuYCwge1xuICAgICAga2V5OiBgJHt0aGlzLm91dHB1dE5hbWV9TG9hZEJhbGFuY2VyQXJuYCxcbiAgICAgIGV4cG9ydE5hbWU6IGAke3Byb3BzLmNsdXN0ZXJOYW1lfUxvYWRCYWxhbmNlckFybmAsXG4gICAgICB2YWx1ZTogdGhpcy5sb2FkQmFsYW5jZXIubG9hZEJhbGFuY2VyQXJuLFxuICAgICAgZGVzY3JpcHRpb246IGBMb2FkIEJhbGFuY2VyIEFSTiBmb3IgJHtwcm9wcy5jbHVzdGVyTmFtZX1gXG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIGFkZERpcmVjdEFjY2Vzc091dHB1dHMocHJvcHM6IEVjc0NsdXN0ZXJQcm9wcykge1xuICAgIGlmICghdGhpcy5kaXJlY3RBY2Nlc3NFbmFibGVkIHx8ICF0aGlzLmF1dG9TY2FsaW5nR3JvdXApIHJldHVybjtcblxuICAgIGNvbnN0IGNvbnRhaW5lclBvcnQgPVxuICAgICAgcHJvcHMuc2VydmljZXMuZmxhdE1hcCgocykgPT4gcy5jb250YWluZXJzKS5maW5kKChjKSA9PiBjLnBvcnQpPy5wb3J0IHx8XG4gICAgICAzMDAwO1xuXG4gICAgbmV3IENmbk91dHB1dCh0aGlzLCBgJHt0aGlzLm91dHB1dE5hbWV9QXV0b1NjYWxpbmdHcm91cE5hbWVgLCB7XG4gICAgICBrZXk6IGAke3RoaXMub3V0cHV0TmFtZX1BdXRvU2NhbGluZ0dyb3VwTmFtZWAsXG4gICAgICBleHBvcnROYW1lOiBgJHtwcm9wcy5jbHVzdGVyTmFtZX1BdXRvU2NhbGluZ0dyb3VwTmFtZWAsXG4gICAgICB2YWx1ZTogdGhpcy5hdXRvU2NhbGluZ0dyb3VwLmF1dG9TY2FsaW5nR3JvdXBOYW1lLFxuICAgICAgZGVzY3JpcHRpb246IGBSdW46IGF3cyBhdXRvc2NhbGluZyBkZXNjcmliZS1hdXRvLXNjYWxpbmctZ3JvdXBzIC0tYXV0by1zY2FsaW5nLWdyb3VwLW5hbWVzIDxuYW1lPiB0byBmaW5kIGluc3RhbmNlIElQYFxuICAgIH0pO1xuXG4gICAgbmV3IENmbk91dHB1dCh0aGlzLCBgJHt0aGlzLm91dHB1dE5hbWV9RGlyZWN0QWNjZXNzUG9ydGAsIHtcbiAgICAgIGtleTogYCR7dGhpcy5vdXRwdXROYW1lfURpcmVjdEFjY2Vzc1BvcnRgLFxuICAgICAgZXhwb3J0TmFtZTogYCR7cHJvcHMuY2x1c3Rlck5hbWV9RGlyZWN0QWNjZXNzUG9ydGAsXG4gICAgICB2YWx1ZTogU3RyaW5nKGNvbnRhaW5lclBvcnQpLFxuICAgICAgZGVzY3JpcHRpb246IGBBY2Nlc3MgeW91ciBhcHAgYXQgaHR0cDovLzxFQzItUFVCTElDLUlQPjoke2NvbnRhaW5lclBvcnR9YFxuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBhZGRMb2FkQmFsYW5jZXJMaXN0ZW5lcihwcm9wczogRWNzQ2x1c3RlclByb3BzKSB7XG4gICAgaWYgKCF0aGlzLmxvYWRCYWxhbmNlcikgcmV0dXJuO1xuXG4gICAgY29uc3QgcG9ydCA9IHRoaXMuY2VydGlmaWNhdGUgPyA0NDMgOiA4MDtcblxuICAgIGNvbnN0IGRlZmF1bHRBY3Rpb24gPSBMaXN0ZW5lckFjdGlvbi5maXhlZFJlc3BvbnNlKDQwNCwge1xuICAgICAgY29udGVudFR5cGU6IFwidGV4dC9wbGFpblwiLFxuICAgICAgbWVzc2FnZUJvZHk6IFwiTm90IEZvdW5kXCJcbiAgICB9KTtcblxuICAgIGlmICh0aGlzLmNlcnRpZmljYXRlKSB7XG4gICAgICB0aGlzLmxvYWRCYWxhbmNlckxpc3RlbmVyID0gdGhpcy5sb2FkQmFsYW5jZXIuYWRkTGlzdGVuZXIoXG4gICAgICAgIGAke3Byb3BzLmNsdXN0ZXJOYW1lfUxpc3RlbmVyYCxcbiAgICAgICAge1xuICAgICAgICAgIHBvcnQsXG4gICAgICAgICAgY2VydGlmaWNhdGVzOiBbdGhpcy5jZXJ0aWZpY2F0ZV0sXG4gICAgICAgICAgZGVmYXVsdEFjdGlvblxuICAgICAgICB9XG4gICAgICApO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLmxvYWRCYWxhbmNlckxpc3RlbmVyID0gdGhpcy5sb2FkQmFsYW5jZXIuYWRkTGlzdGVuZXIoXG4gICAgICAgIGAke3Byb3BzLmNsdXN0ZXJOYW1lfUxpc3RlbmVyYCxcbiAgICAgICAge1xuICAgICAgICAgIHBvcnQsXG4gICAgICAgICAgZGVmYXVsdEFjdGlvblxuICAgICAgICB9XG4gICAgICApO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgYWRkSG9zdGVkWm9uZShwcm9wczogRWNzQ2x1c3RlclByb3BzKSB7XG4gICAgY29uc3QgZG9tYWluQ29uZmlnID0gcHJvcHMuY2x1c3Rlcj8uZG9tYWluQ29uZmlnO1xuICAgIGNvbnN0IHNpbXBsZURvbWFpbiA9IHByb3BzLmNsdXN0ZXI/LmRvbWFpbjtcblxuICAgIGNvbnN0IGRvbWFpbk5hbWUgPSBkb21haW5Db25maWc/LmRvbWFpbk5hbWUgPz8gc2ltcGxlRG9tYWluO1xuICAgIGlmICghZG9tYWluTmFtZSkgcmV0dXJuO1xuXG4gICAgLy8gTWFuYWdlZCBkb21haW46IGltcG9ydCB6b25lIGFuZCBjZXJ0IGZyb20gZG9tYWluIHN0YWNrIHZpYSBGbi5pbXBvcnRWYWx1ZVxuICAgIGlmIChkb21haW5Db25maWc/Lm1hbmFnZWREb21haW4pIHtcbiAgICAgIGNvbnN0IG1hbmFnZWQgPSBkb21haW5Db25maWcubWFuYWdlZERvbWFpbjtcbiAgICAgIHRoaXMuaG9zdGVkWm9uZSA9IEFXU0hvc3RlZFpvbmUuZnJvbUhvc3RlZFpvbmVBdHRyaWJ1dGVzKFxuICAgICAgICB0aGlzLFxuICAgICAgICBgJHtwcm9wcy5jbHVzdGVyTmFtZX1NYW5hZ2VkSG9zdGVkWm9uZWAsXG4gICAgICAgIHtcbiAgICAgICAgICBob3N0ZWRab25lSWQ6IEZuLmltcG9ydFZhbHVlKG1hbmFnZWQuaG9zdGVkWm9uZUlkRXhwb3J0KSxcbiAgICAgICAgICB6b25lTmFtZTogbWFuYWdlZC56b25lTmFtZVxuICAgICAgICB9XG4gICAgICApO1xuICAgICAgdGhpcy5jZXJ0aWZpY2F0ZSA9IENlcnRpZmljYXRlLmZyb21DZXJ0aWZpY2F0ZUFybihcbiAgICAgICAgdGhpcyxcbiAgICAgICAgYCR7cHJvcHMuY2x1c3Rlck5hbWV9TWFuYWdlZENlcnRpZmljYXRlYCxcbiAgICAgICAgRm4uaW1wb3J0VmFsdWUobWFuYWdlZC5jZXJ0aWZpY2F0ZUFybkV4cG9ydClcbiAgICAgICk7XG4gICAgfSBlbHNlIGlmICghZG9tYWluQ29uZmlnPy5ob3N0ZWRab25lKSB7XG4gICAgICBjb25zdCBob3N0ZWRab25lID0gbmV3IEZqYWxsSG9zdGVkWm9uZShcbiAgICAgICAgdGhpcyxcbiAgICAgICAgYCR7cHJvcHMuY2x1c3Rlck5hbWV9SG9zdGVkWm9uZWAsXG4gICAgICAgIHtcbiAgICAgICAgICB6b25lTmFtZTogZG9tYWluTmFtZVxuICAgICAgICB9XG4gICAgICApO1xuXG4gICAgICB0aGlzLmhvc3RlZFpvbmUgPSBob3N0ZWRab25lLmdldEludGVybmFsSG9zdGVkWm9uZSgpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLmhvc3RlZFpvbmUgPSBkb21haW5Db25maWcuaG9zdGVkWm9uZS5nZXRJbnRlcm5hbEhvc3RlZFpvbmUoKTtcbiAgICB9XG5cbiAgICBpZiAoIWRvbWFpbkNvbmZpZz8uY2VydGlmaWNhdGUgJiYgIWRvbWFpbkNvbmZpZz8ubWFuYWdlZERvbWFpbikge1xuICAgICAgdGhpcy5jZXJ0aWZpY2F0ZSA9IG5ldyBDZXJ0aWZpY2F0ZShcbiAgICAgICAgdGhpcyxcbiAgICAgICAgYCR7cHJvcHMuY2x1c3Rlck5hbWV9Q2VydGlmaWNhdGVgLFxuICAgICAgICB7XG4gICAgICAgICAgZG9tYWluTmFtZSxcbiAgICAgICAgICB2YWxpZGF0aW9uOiBDZXJ0aWZpY2F0ZVZhbGlkYXRpb24uZnJvbURucyh0aGlzLmhvc3RlZFpvbmUpXG4gICAgICAgIH1cbiAgICAgICk7XG4gICAgfVxuXG4gICAgaWYgKGRvbWFpbkNvbmZpZykge1xuICAgICAgY29uc3QgcmVnaW9uID0gXCJyZWdpb25cIiBpbiBkb21haW5Db25maWcgPyBkb21haW5Db25maWcucmVnaW9uIDogdW5kZWZpbmVkO1xuICAgICAgY29uc3Qgd2VpZ2h0ID0gXCJ3ZWlnaHRcIiBpbiBkb21haW5Db25maWcgPyBkb21haW5Db25maWcud2VpZ2h0IDogdW5kZWZpbmVkO1xuICAgICAgY29uc3QgZ2VvTG9jYXRpb24gPVxuICAgICAgICBcImdlb0xvY2F0aW9uXCIgaW4gZG9tYWluQ29uZmlnID8gZG9tYWluQ29uZmlnLmdlb0xvY2F0aW9uIDogdW5kZWZpbmVkO1xuXG4gICAgICBjb25zdCBoYXNSb3V0aW5nUG9saWN5OiBib29sZWFuID1cbiAgICAgICAgISFyZWdpb24gfHwgd2VpZ2h0ICE9PSB1bmRlZmluZWQgfHwgISFnZW9Mb2NhdGlvbjtcblxuICAgICAgbGV0IHNldElkZW50aWZpZXIgPSBkb21haW5Db25maWcuc2V0SWRlbnRpZmllcjtcbiAgICAgIGlmIChoYXNSb3V0aW5nUG9saWN5ICYmICFzZXRJZGVudGlmaWVyKSB7XG4gICAgICAgIGlmIChyZWdpb24pIHtcbiAgICAgICAgICBzZXRJZGVudGlmaWVyID0gYCR7cHJvcHMuY2x1c3Rlck5hbWV9JHtyZWdpb259YDtcbiAgICAgICAgfSBlbHNlIGlmICh3ZWlnaHQgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgIHNldElkZW50aWZpZXIgPSBgJHtwcm9wcy5jbHVzdGVyTmFtZX1XZWlnaHQke3dlaWdodH1gO1xuICAgICAgICB9IGVsc2UgaWYgKGdlb0xvY2F0aW9uKSB7XG4gICAgICAgICAgc2V0SWRlbnRpZmllciA9IGAke3Byb3BzLmNsdXN0ZXJOYW1lfUdlb2A7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMubG9hZEJhbGFuY2VyKSB7XG4gICAgICAgIHRoaXMuYVJlY29yZCA9IG5ldyBBUmVjb3JkKHRoaXMsIGAke3Byb3BzLmNsdXN0ZXJOYW1lfUFSZWNvcmRgLCB7XG4gICAgICAgICAgcmVjb3JkTmFtZTogZG9tYWluTmFtZSxcbiAgICAgICAgICB6b25lOiB0aGlzLmhvc3RlZFpvbmUsXG4gICAgICAgICAgdGFyZ2V0OiBSZWNvcmRUYXJnZXQuZnJvbUFsaWFzKFxuICAgICAgICAgICAgbmV3IExvYWRCYWxhbmNlclRhcmdldCh0aGlzLmxvYWRCYWxhbmNlciwge1xuICAgICAgICAgICAgICBldmFsdWF0ZVRhcmdldEhlYWx0aDogaGFzUm91dGluZ1BvbGljeVxuICAgICAgICAgICAgfSlcbiAgICAgICAgICApLFxuICAgICAgICAgIHJlZ2lvbixcbiAgICAgICAgICB3ZWlnaHQsXG4gICAgICAgICAgZ2VvTG9jYXRpb24sXG4gICAgICAgICAgc2V0SWRlbnRpZmllcjogc2V0SWRlbnRpZmllclxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKHNpbXBsZURvbWFpbiAmJiB0aGlzLmxvYWRCYWxhbmNlcikge1xuICAgICAgdGhpcy5hUmVjb3JkID0gbmV3IEFSZWNvcmQodGhpcywgYCR7cHJvcHMuY2x1c3Rlck5hbWV9QVJlY29yZGAsIHtcbiAgICAgICAgcmVjb3JkTmFtZTogZG9tYWluTmFtZSxcbiAgICAgICAgem9uZTogdGhpcy5ob3N0ZWRab25lLFxuICAgICAgICB0YXJnZXQ6IFJlY29yZFRhcmdldC5mcm9tQWxpYXMoXG4gICAgICAgICAgbmV3IExvYWRCYWxhbmNlclRhcmdldCh0aGlzLmxvYWRCYWxhbmNlcilcbiAgICAgICAgKVxuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgc3RhdGljIGJ1aWxkKFxuICAgIGlkOiBzdHJpbmcsXG4gICAgcHJvcHM6IEVjc0NsdXN0ZXJQcm9wc1xuICApOiAoc2I6IFN0YWNrQnVpbGRlcikgPT4gQ29uc3RydWN0IHtcbiAgICByZXR1cm4gKHNiOiBTdGFja0J1aWxkZXIpID0+IHtcbiAgICAgIGNvbnN0IG5ld1Byb3BzOiBFY3NDbHVzdGVyUHJvcHMgPSB7XG4gICAgICAgIC4uLnByb3BzLFxuICAgICAgICAuLi57XG4gICAgICAgICAgdnBjOiBzYi5nZXROZXR3b3JrKCkgfHwgcHJvcHMudnBjXG4gICAgICAgIH1cbiAgICAgIH07XG4gICAgICByZXR1cm4gbmV3IHRoaXMoc2IuZ2V0U3RhY2soKSwgaWQsIG5ld1Byb3BzKTtcbiAgICB9O1xuICB9XG59XG4iXX0=
|