@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.
Files changed (378) hide show
  1. package/LICENSE +50 -21
  2. package/dist/index.d.ts +1 -1
  3. package/dist/index.js +1 -18
  4. package/dist/lib/app.d.ts +12 -12
  5. package/dist/lib/app.js +61 -56
  6. package/dist/lib/aspects/index.d.ts +1 -1
  7. package/dist/lib/aspects/index.js +1 -6
  8. package/dist/lib/aspects/resourceInventory.js +6 -13
  9. package/dist/lib/config/audit.js +1 -5
  10. package/dist/lib/config/aws/accessAnalyser.d.ts +11 -0
  11. package/dist/lib/config/aws/accessAnalyser.js +17 -0
  12. package/dist/lib/config/aws/accountAuditRole.js +11 -15
  13. package/dist/lib/config/aws/accountMonitoringRole.js +25 -29
  14. package/dist/lib/config/aws/alarmTopic.d.ts +8 -0
  15. package/dist/lib/config/aws/alarmTopic.js +19 -0
  16. package/dist/lib/config/aws/cloudTrail.js +4 -9
  17. package/dist/lib/config/aws/configRecorder.d.ts +16 -0
  18. package/dist/lib/config/aws/configRecorder.js +51 -0
  19. package/dist/lib/config/aws/configRulePreset.d.ts +13 -0
  20. package/dist/lib/config/aws/configRulePreset.js +62 -0
  21. package/dist/lib/config/aws/disasterRecovery.d.ts +1 -1
  22. package/dist/lib/config/aws/disasterRecovery.js +56 -73
  23. package/dist/lib/config/aws/ebsDefaultEncryption.d.ts +8 -0
  24. package/dist/lib/config/aws/ebsDefaultEncryption.js +41 -0
  25. package/dist/lib/config/aws/ecrDefaultImage.js +25 -30
  26. package/dist/lib/config/aws/eventBus.js +8 -11
  27. package/dist/lib/config/aws/guardDutyDetector.d.ts +16 -0
  28. package/dist/lib/config/aws/guardDutyDetector.js +26 -0
  29. package/dist/lib/config/aws/identityCenter.d.ts +1 -1
  30. package/dist/lib/config/aws/identityCenter.js +23 -25
  31. package/dist/lib/config/aws/identityCenterGroupMembership.js +18 -22
  32. package/dist/lib/config/aws/index.d.ts +19 -8
  33. package/dist/lib/config/aws/index.js +19 -25
  34. package/dist/lib/config/aws/inspectorEnablement.d.ts +9 -0
  35. package/dist/lib/config/aws/inspectorEnablement.js +51 -0
  36. package/dist/lib/config/aws/ipam.js +9 -13
  37. package/dist/lib/config/aws/oidcConnector.js +8 -12
  38. package/dist/lib/config/aws/platform.js +1 -5
  39. package/dist/lib/config/aws/s3BlockPublicAccess.d.ts +9 -0
  40. package/dist/lib/config/aws/s3BlockPublicAccess.js +55 -0
  41. package/dist/lib/config/aws/scpPreset.d.ts +21 -0
  42. package/dist/lib/config/aws/scpPreset.js +311 -0
  43. package/dist/lib/config/aws/securityBaseline.d.ts +15 -0
  44. package/dist/lib/config/aws/securityBaseline.js +27 -0
  45. package/dist/lib/config/aws/securityHubHub.d.ts +15 -0
  46. package/dist/lib/config/aws/securityHubHub.js +28 -0
  47. package/dist/lib/config/aws/securityServicesAdmin.d.ts +20 -0
  48. package/dist/lib/config/aws/securityServicesAdmin.js +115 -0
  49. package/dist/lib/config/index.d.ts +2 -2
  50. package/dist/lib/config/index.js +2 -21
  51. package/dist/lib/index.d.ts +4 -4
  52. package/dist/lib/index.js +5 -26
  53. package/dist/lib/patterns/aws/account.d.ts +17 -1
  54. package/dist/lib/patterns/aws/account.js +60 -33
  55. package/dist/lib/patterns/aws/apexDomainPattern.d.ts +26 -0
  56. package/dist/lib/patterns/aws/apexDomainPattern.js +91 -0
  57. package/dist/lib/patterns/aws/auditRole.js +13 -16
  58. package/dist/lib/patterns/aws/buildkite.d.ts +1 -1
  59. package/dist/lib/patterns/aws/buildkite.js +70 -75
  60. package/dist/lib/patterns/aws/cdn.d.ts +5 -5
  61. package/dist/lib/patterns/aws/cdn.js +22 -28
  62. package/dist/lib/patterns/aws/compute.d.ts +1 -1
  63. package/dist/lib/patterns/aws/compute.js +31 -44
  64. package/dist/lib/patterns/aws/computeEc2.d.ts +1 -1
  65. package/dist/lib/patterns/aws/computeEc2.js +11 -14
  66. package/dist/lib/patterns/aws/computeEcs.d.ts +18 -2
  67. package/dist/lib/patterns/aws/computeEcs.js +41 -31
  68. package/dist/lib/patterns/aws/computeLambda.d.ts +2 -2
  69. package/dist/lib/patterns/aws/computeLambda.js +24 -31
  70. package/dist/lib/patterns/aws/database.d.ts +16 -7
  71. package/dist/lib/patterns/aws/database.js +81 -73
  72. package/dist/lib/patterns/aws/delegatedDomainPattern.d.ts +17 -0
  73. package/dist/lib/patterns/aws/delegatedDomainPattern.js +54 -0
  74. package/dist/lib/patterns/aws/dnsRecordComposer.d.ts +25 -0
  75. package/dist/lib/patterns/aws/dnsRecordComposer.js +225 -0
  76. package/dist/lib/patterns/aws/domain.d.ts +32 -0
  77. package/dist/lib/patterns/aws/domain.js +115 -0
  78. package/dist/lib/patterns/aws/domainDelegation.d.ts +3 -3
  79. package/dist/lib/patterns/aws/domainDelegation.js +28 -37
  80. package/dist/lib/patterns/aws/domainFactory.d.ts +20 -5
  81. package/dist/lib/patterns/aws/domainFactory.js +48 -10
  82. package/dist/lib/patterns/aws/domainValidation.d.ts +11 -0
  83. package/dist/lib/patterns/aws/domainValidation.js +145 -0
  84. package/dist/lib/patterns/aws/externalRecordsPattern.d.ts +18 -0
  85. package/dist/lib/patterns/aws/externalRecordsPattern.js +141 -0
  86. package/dist/lib/patterns/aws/fivetranProxy.d.ts +1 -1
  87. package/dist/lib/patterns/aws/fivetranProxy.js +6 -11
  88. package/dist/lib/patterns/aws/index.d.ts +21 -19
  89. package/dist/lib/patterns/aws/index.js +25 -36
  90. package/dist/lib/patterns/aws/interfaces/cdn.js +1 -5
  91. package/dist/lib/patterns/aws/interfaces/compute.js +4 -11
  92. package/dist/lib/patterns/aws/interfaces/connector.js +1 -15
  93. package/dist/lib/patterns/aws/interfaces/database.d.ts +1 -1
  94. package/dist/lib/patterns/aws/interfaces/database.js +6 -15
  95. package/dist/lib/patterns/aws/interfaces/domain.d.ts +80 -2
  96. package/dist/lib/patterns/aws/interfaces/domain.js +1 -6
  97. package/dist/lib/patterns/aws/interfaces/index.js +8 -41
  98. package/dist/lib/patterns/aws/interfaces/messaging.js +4 -11
  99. package/dist/lib/patterns/aws/interfaces/organisation.d.ts +1 -1
  100. package/dist/lib/patterns/aws/interfaces/organisation.js +4 -11
  101. package/dist/lib/patterns/aws/interfaces/pattern.js +2 -7
  102. package/dist/lib/patterns/aws/interfaces/storage.js +1 -5
  103. package/dist/lib/patterns/aws/managedIdentityCenter.js +7 -12
  104. package/dist/lib/patterns/aws/messaging.d.ts +7 -7
  105. package/dist/lib/patterns/aws/messaging.js +22 -33
  106. package/dist/lib/patterns/aws/network.d.ts +2 -2
  107. package/dist/lib/patterns/aws/network.js +9 -14
  108. package/dist/lib/patterns/aws/organisation.d.ts +6 -2
  109. package/dist/lib/patterns/aws/organisation.js +34 -35
  110. package/dist/lib/patterns/aws/organisationFactory.d.ts +3 -3
  111. package/dist/lib/patterns/aws/organisationFactory.js +7 -12
  112. package/dist/lib/patterns/aws/pattern.js +6 -12
  113. package/dist/lib/patterns/aws/payload.js +73 -63
  114. package/dist/lib/patterns/aws/platform.d.ts +6 -3
  115. package/dist/lib/patterns/aws/platform.js +15 -15
  116. package/dist/lib/patterns/aws/storage.d.ts +6 -4
  117. package/dist/lib/patterns/aws/storage.js +35 -40
  118. package/dist/lib/patterns/aws/subdomainHostedZone.js +11 -16
  119. package/dist/lib/patterns/aws/targets/fjallTargets.d.ts +37 -0
  120. package/dist/lib/patterns/aws/targets/fjallTargets.js +66 -0
  121. package/dist/lib/patterns/aws/targets/index.d.ts +2 -0
  122. package/dist/lib/patterns/aws/targets/index.js +2 -0
  123. package/dist/lib/patterns/aws/targets/targetResolution.d.ts +76 -0
  124. package/dist/lib/patterns/aws/targets/targetResolution.js +119 -0
  125. package/dist/lib/patterns/index.d.ts +1 -0
  126. package/dist/lib/patterns/index.js +1 -0
  127. package/dist/lib/resources/aws/analytics/clickhouse.d.ts +15 -0
  128. package/dist/lib/resources/aws/analytics/clickhouse.js +292 -0
  129. package/dist/lib/resources/aws/analytics/clickhouseConstants.d.ts +73 -0
  130. package/dist/lib/resources/aws/analytics/clickhouseConstants.js +87 -0
  131. package/dist/lib/resources/aws/analytics/clickhouseSecurityGroup.d.ts +13 -0
  132. package/dist/lib/resources/aws/analytics/clickhouseSecurityGroup.js +28 -0
  133. package/dist/lib/resources/aws/analytics/clickhouseTypes.d.ts +47 -0
  134. package/dist/lib/resources/aws/analytics/clickhouseTypes.js +1 -0
  135. package/dist/lib/resources/aws/analytics/clickhouseUserData.d.ts +5 -0
  136. package/dist/lib/resources/aws/analytics/clickhouseUserData.js +248 -0
  137. package/dist/lib/resources/aws/analytics/index.d.ts +2 -0
  138. package/dist/lib/resources/aws/analytics/index.js +1 -0
  139. package/dist/lib/resources/aws/audit/auditRole.js +10 -15
  140. package/dist/lib/resources/aws/audit/index.d.ts +1 -1
  141. package/dist/lib/resources/aws/audit/index.js +1 -6
  142. package/dist/lib/resources/aws/backup/backupPlan.d.ts +1 -1
  143. package/dist/lib/resources/aws/backup/backupPlan.js +14 -16
  144. package/dist/lib/resources/aws/backup/backupVault.d.ts +1 -1
  145. package/dist/lib/resources/aws/backup/backupVault.js +13 -15
  146. package/dist/lib/resources/aws/backup/index.d.ts +2 -2
  147. package/dist/lib/resources/aws/backup/index.js +2 -19
  148. package/dist/lib/resources/aws/base/awsStack.js +17 -19
  149. package/dist/lib/resources/aws/base/index.d.ts +1 -1
  150. package/dist/lib/resources/aws/base/index.js +1 -18
  151. package/dist/lib/resources/aws/cdn/cloudFront.js +40 -42
  152. package/dist/lib/resources/aws/cdn/index.d.ts +1 -1
  153. package/dist/lib/resources/aws/cdn/index.js +1 -18
  154. package/dist/lib/resources/aws/compute/ec2.js +39 -39
  155. package/dist/lib/resources/aws/compute/ecs.d.ts +18 -396
  156. package/dist/lib/resources/aws/compute/ecs.js +105 -976
  157. package/dist/lib/resources/aws/compute/ecsCapacityProviderAspect.d.ts +22 -0
  158. package/dist/lib/resources/aws/compute/ecsCapacityProviderAspect.js +35 -0
  159. package/dist/lib/resources/aws/compute/ecsConstants.d.ts +20 -0
  160. package/dist/lib/resources/aws/compute/ecsConstants.js +49 -0
  161. package/dist/lib/resources/aws/compute/ecsContext.d.ts +12 -0
  162. package/dist/lib/resources/aws/compute/ecsContext.js +1 -0
  163. package/dist/lib/resources/aws/compute/ecsImages.d.ts +4 -0
  164. package/dist/lib/resources/aws/compute/ecsImages.js +35 -0
  165. package/dist/lib/resources/aws/compute/ecsNetworking.d.ts +28 -0
  166. package/dist/lib/resources/aws/compute/ecsNetworking.js +290 -0
  167. package/dist/lib/resources/aws/compute/ecsRoles.d.ts +15 -0
  168. package/dist/lib/resources/aws/compute/ecsRoles.js +110 -0
  169. package/dist/lib/resources/aws/compute/ecsServiceFactory.d.ts +33 -0
  170. package/dist/lib/resources/aws/compute/ecsServiceFactory.js +183 -0
  171. package/dist/lib/resources/aws/compute/ecsTaskDefinition.d.ts +30 -0
  172. package/dist/lib/resources/aws/compute/ecsTaskDefinition.js +168 -0
  173. package/dist/lib/resources/aws/compute/ecsTypes.d.ts +337 -0
  174. package/dist/lib/resources/aws/compute/ecsTypes.js +10 -0
  175. package/dist/lib/resources/aws/compute/ecsValidation.d.ts +18 -0
  176. package/dist/lib/resources/aws/compute/ecsValidation.js +72 -0
  177. package/dist/lib/resources/aws/compute/index.d.ts +3 -3
  178. package/dist/lib/resources/aws/compute/index.js +3 -20
  179. package/dist/lib/resources/aws/compute/lambda.d.ts +10 -2
  180. package/dist/lib/resources/aws/compute/lambda.js +81 -71
  181. package/dist/lib/resources/aws/database/dynamodb.js +24 -27
  182. package/dist/lib/resources/aws/database/index.d.ts +7 -7
  183. package/dist/lib/resources/aws/database/index.js +14 -33
  184. package/dist/lib/resources/aws/database/rdsAurora.d.ts +10 -2
  185. package/dist/lib/resources/aws/database/rdsAurora.js +76 -61
  186. package/dist/lib/resources/aws/database/rdsAuroraGlobal.d.ts +2 -2
  187. package/dist/lib/resources/aws/database/rdsAuroraGlobal.js +24 -21
  188. package/dist/lib/resources/aws/database/rdsDefaults.js +3 -7
  189. package/dist/lib/resources/aws/database/rdsHelpers.d.ts +2 -2
  190. package/dist/lib/resources/aws/database/rdsHelpers.js +21 -29
  191. package/dist/lib/resources/aws/database/rdsInstance.d.ts +11 -3
  192. package/dist/lib/resources/aws/database/rdsInstance.js +101 -83
  193. package/dist/lib/resources/aws/database/rdsProxyOutput.js +5 -9
  194. package/dist/lib/resources/aws/iam/delegationRole.d.ts +18 -0
  195. package/dist/lib/resources/aws/iam/delegationRole.js +60 -0
  196. package/dist/lib/resources/aws/iam/identityCenter/assignment.js +4 -9
  197. package/dist/lib/resources/aws/iam/identityCenter/group.js +5 -9
  198. package/dist/lib/resources/aws/iam/identityCenter/index.d.ts +3 -3
  199. package/dist/lib/resources/aws/iam/identityCenter/index.js +3 -20
  200. package/dist/lib/resources/aws/iam/identityCenter/permissionSet.d.ts +1 -1
  201. package/dist/lib/resources/aws/iam/identityCenter/permissionSet.js +5 -9
  202. package/dist/lib/resources/aws/iam/index.d.ts +5 -4
  203. package/dist/lib/resources/aws/iam/index.js +5 -21
  204. package/dist/lib/resources/aws/iam/instanceProfile.js +2 -7
  205. package/dist/lib/resources/aws/iam/managedPolicy.js +2 -7
  206. package/dist/lib/resources/aws/iam/policy.js +2 -7
  207. package/dist/lib/resources/aws/iam/role.js +2 -7
  208. package/dist/lib/resources/aws/index.d.ts +7 -7
  209. package/dist/lib/resources/aws/index.js +7 -24
  210. package/dist/lib/resources/aws/logging/cloudTrail.d.ts +1 -1
  211. package/dist/lib/resources/aws/logging/cloudTrail.js +18 -22
  212. package/dist/lib/resources/aws/logging/index.d.ts +2 -2
  213. package/dist/lib/resources/aws/logging/index.js +2 -19
  214. package/dist/lib/resources/aws/logging/logGroup.js +4 -10
  215. package/dist/lib/resources/aws/messaging/eventbridge.js +11 -14
  216. package/dist/lib/resources/aws/messaging/index.d.ts +4 -4
  217. package/dist/lib/resources/aws/messaging/index.js +4 -21
  218. package/dist/lib/resources/aws/messaging/sns.js +11 -14
  219. package/dist/lib/resources/aws/messaging/sqs.js +32 -34
  220. package/dist/lib/resources/aws/messaging/utils.d.ts +1 -1
  221. package/dist/lib/resources/aws/messaging/utils.js +1 -6
  222. package/dist/lib/resources/aws/monitoring/alarmDefaults.d.ts +36 -0
  223. package/dist/lib/resources/aws/monitoring/alarmDefaults.js +34 -0
  224. package/dist/lib/resources/aws/monitoring/ecsAlarms.d.ts +21 -0
  225. package/dist/lib/resources/aws/monitoring/ecsAlarms.js +88 -0
  226. package/dist/lib/resources/aws/monitoring/index.d.ts +4 -0
  227. package/dist/lib/resources/aws/monitoring/index.js +4 -5
  228. package/dist/lib/resources/aws/monitoring/lambdaAlarms.d.ts +18 -0
  229. package/dist/lib/resources/aws/monitoring/lambdaAlarms.js +44 -0
  230. package/dist/lib/resources/aws/monitoring/rdsAlarms.d.ts +20 -0
  231. package/dist/lib/resources/aws/monitoring/rdsAlarms.js +52 -0
  232. package/dist/lib/resources/aws/networking/crossAccountDelegationRecord.d.ts +17 -0
  233. package/dist/lib/resources/aws/networking/crossAccountDelegationRecord.js +26 -0
  234. package/dist/lib/resources/aws/networking/dnsRecord/aRecord.d.ts +12 -0
  235. package/dist/lib/resources/aws/networking/dnsRecord/aRecord.js +21 -0
  236. package/dist/lib/resources/aws/networking/dnsRecord/aaaaRecord.d.ts +12 -0
  237. package/dist/lib/resources/aws/networking/dnsRecord/aaaaRecord.js +22 -0
  238. package/dist/lib/resources/aws/networking/dnsRecord/aliasRecord.d.ts +12 -0
  239. package/dist/lib/resources/aws/networking/dnsRecord/aliasRecord.js +23 -0
  240. package/dist/lib/resources/aws/networking/dnsRecord/caaRecord.d.ts +17 -0
  241. package/dist/lib/resources/aws/networking/dnsRecord/caaRecord.js +21 -0
  242. package/dist/lib/resources/aws/networking/dnsRecord/cnameRecord.d.ts +12 -0
  243. package/dist/lib/resources/aws/networking/dnsRecord/cnameRecord.js +22 -0
  244. package/dist/lib/resources/aws/networking/dnsRecord/dnsRecordBase.d.ts +17 -0
  245. package/dist/lib/resources/aws/networking/dnsRecord/dnsRecordBase.js +17 -0
  246. package/dist/lib/resources/aws/networking/dnsRecord/index.d.ts +10 -0
  247. package/dist/lib/resources/aws/networking/dnsRecord/index.js +10 -0
  248. package/dist/lib/resources/aws/networking/dnsRecord/mxRecord.d.ts +16 -0
  249. package/dist/lib/resources/aws/networking/dnsRecord/mxRecord.js +21 -0
  250. package/dist/lib/resources/aws/networking/dnsRecord/nsRecord.d.ts +12 -0
  251. package/dist/lib/resources/aws/networking/dnsRecord/nsRecord.js +21 -0
  252. package/dist/lib/resources/aws/networking/dnsRecord/srvRecord.d.ts +18 -0
  253. package/dist/lib/resources/aws/networking/dnsRecord/srvRecord.js +21 -0
  254. package/dist/lib/resources/aws/networking/dnsRecord/txtRecord.d.ts +12 -0
  255. package/dist/lib/resources/aws/networking/dnsRecord/txtRecord.js +21 -0
  256. package/dist/lib/resources/aws/networking/domain.d.ts +1 -1
  257. package/dist/lib/resources/aws/networking/domain.js +32 -34
  258. package/dist/lib/resources/aws/networking/domainCertificate.d.ts +8 -3
  259. package/dist/lib/resources/aws/networking/domainCertificate.js +22 -16
  260. package/dist/lib/resources/aws/networking/hostedZone.d.ts +23 -19
  261. package/dist/lib/resources/aws/networking/hostedZone.js +70 -134
  262. package/dist/lib/resources/aws/networking/index.d.ts +8 -7
  263. package/dist/lib/resources/aws/networking/index.js +8 -24
  264. package/dist/lib/resources/aws/networking/ipam.js +2 -7
  265. package/dist/lib/resources/aws/networking/ipamPool.d.ts +1 -1
  266. package/dist/lib/resources/aws/networking/ipamPool.js +45 -55
  267. package/dist/lib/resources/aws/networking/securityGroup.js +2 -7
  268. package/dist/lib/resources/aws/networking/vpc.d.ts +1 -1
  269. package/dist/lib/resources/aws/networking/vpc.js +17 -21
  270. package/dist/lib/resources/aws/organisation/costAllocationTagActivator.d.ts +1 -1
  271. package/dist/lib/resources/aws/organisation/costAllocationTagActivator.js +11 -15
  272. package/dist/lib/resources/aws/organisation/index.d.ts +5 -5
  273. package/dist/lib/resources/aws/organisation/index.js +4 -12
  274. package/dist/lib/resources/aws/organisation/organisation.js +5 -7
  275. package/dist/lib/resources/aws/organisation/organisationAccount.js +7 -10
  276. package/dist/lib/resources/aws/organisation/organisationPolicy.js +5 -9
  277. package/dist/lib/resources/aws/organisation/organisationalUnit.js +1 -3
  278. package/dist/lib/resources/aws/secrets/alias.js +2 -7
  279. package/dist/lib/resources/aws/secrets/index.d.ts +4 -4
  280. package/dist/lib/resources/aws/secrets/index.js +4 -21
  281. package/dist/lib/resources/aws/secrets/kms.js +15 -18
  282. package/dist/lib/resources/aws/secrets/parameter.d.ts +3 -3
  283. package/dist/lib/resources/aws/secrets/parameter.js +19 -22
  284. package/dist/lib/resources/aws/secrets/secret.d.ts +2 -2
  285. package/dist/lib/resources/aws/secrets/secret.js +12 -14
  286. package/dist/lib/resources/aws/storage/ecr.d.ts +2 -2
  287. package/dist/lib/resources/aws/storage/ecr.js +7 -13
  288. package/dist/lib/resources/aws/storage/index.d.ts +2 -2
  289. package/dist/lib/resources/aws/storage/index.js +2 -19
  290. package/dist/lib/resources/aws/storage/s3.d.ts +1 -1
  291. package/dist/lib/resources/aws/storage/s3.js +24 -12
  292. package/dist/lib/resources/aws/utilities/awsCustomResource.js +3 -7
  293. package/dist/lib/resources/aws/utilities/codeBuild.js +7 -12
  294. package/dist/lib/resources/aws/utilities/customResource.js +14 -17
  295. package/dist/lib/resources/aws/utilities/customResourceProvider.js +2 -7
  296. package/dist/lib/resources/aws/utilities/index.d.ts +5 -5
  297. package/dist/lib/resources/aws/utilities/index.js +5 -22
  298. package/dist/lib/resources/aws/utilities/resourceShare.js +2 -7
  299. package/dist/lib/resources/index.d.ts +1 -1
  300. package/dist/lib/resources/index.js +1 -18
  301. package/dist/lib/types.js +1 -3
  302. package/dist/lib/utils/accountsUtils.d.ts +5 -0
  303. package/dist/lib/utils/accountsUtils.js +18 -0
  304. package/dist/lib/utils/addSuffixToEmail.js +1 -5
  305. package/dist/lib/utils/backupTierMapping.js +2 -6
  306. package/dist/lib/utils/capitaliseString.js +1 -10
  307. package/dist/lib/utils/connections.js +9 -13
  308. package/dist/lib/utils/connector.js +10 -23
  309. package/dist/lib/utils/constructMap.d.ts +33 -0
  310. package/dist/lib/utils/constructMap.js +154 -0
  311. package/dist/lib/utils/databaseTypes.js +4 -10
  312. package/dist/lib/utils/dnsRecords.d.ts +1 -1
  313. package/dist/lib/utils/dnsRecords.js +23 -27
  314. package/dist/lib/utils/domainTypes.d.ts +0 -1
  315. package/dist/lib/utils/domainTypes.js +2 -10
  316. package/dist/lib/utils/env.js +14 -26
  317. package/dist/lib/utils/getAccountId.js +3 -7
  318. package/dist/lib/utils/getAsync.js +7 -10
  319. package/dist/lib/utils/getConfig.d.ts +0 -2
  320. package/dist/lib/utils/getConfig.js +29 -47
  321. package/dist/lib/utils/getStackOutput.js +4 -8
  322. package/dist/lib/utils/index.d.ts +12 -12
  323. package/dist/lib/utils/index.js +12 -29
  324. package/dist/lib/utils/manifestWriter.d.ts +14 -3
  325. package/dist/lib/utils/manifestWriter.js +60 -43
  326. package/dist/lib/utils/orgConfigParser.d.ts +14 -0
  327. package/dist/lib/utils/orgConfigParser.js +49 -0
  328. package/dist/lib/utils/removalPolicy.js +5 -9
  329. package/dist/lib/utils/resourceNaming.js +11 -16
  330. package/dist/lib/utils/standardTagsAspect.js +9 -16
  331. package/dist/lib/utils/stripAndCamelCase.js +1 -5
  332. package/dist/lib/utils/validationLogger.js +12 -18
  333. package/dist/lib/utils/vpcUtils.js +5 -10
  334. package/package.json +25 -8
  335. package/dist/lib/config/aws/accountId.d.ts +0 -6
  336. package/dist/lib/config/aws/accountId.js +0 -32
  337. package/dist/lib/config/aws/backupGlobalSettings.d.ts +0 -29
  338. package/dist/lib/config/aws/backupGlobalSettings.js +0 -49
  339. package/dist/lib/config/aws/costAllocationTags.d.ts +0 -12
  340. package/dist/lib/config/aws/costAllocationTags.js +0 -47
  341. package/dist/lib/config/aws/ipamDelegateAdmin.d.ts +0 -8
  342. package/dist/lib/config/aws/ipamDelegateAdmin.js +0 -57
  343. package/dist/lib/config/aws/ipamPoolId.d.ts +0 -16
  344. package/dist/lib/config/aws/ipamPoolId.js +0 -42
  345. package/dist/lib/config/aws/organisation.d.ts +0 -30
  346. package/dist/lib/config/aws/organisation.js +0 -92
  347. package/dist/lib/config/aws/organisationId.d.ts +0 -7
  348. package/dist/lib/config/aws/organisationId.js +0 -45
  349. package/dist/lib/config/aws/organisationsAccess.d.ts +0 -10
  350. package/dist/lib/config/aws/organisationsAccess.js +0 -49
  351. package/dist/lib/config/aws/ramSharing.d.ts +0 -4
  352. package/dist/lib/config/aws/ramSharing.js +0 -34
  353. package/dist/lib/config/monitoring.d.ts +0 -18
  354. package/dist/lib/config/monitoring.js +0 -22
  355. package/dist/lib/patterns/aws/connections.d.ts +0 -46
  356. package/dist/lib/patterns/aws/connections.js +0 -159
  357. package/dist/lib/patterns/aws/hostedZone.d.ts +0 -28
  358. package/dist/lib/patterns/aws/hostedZone.js +0 -150
  359. package/dist/lib/patterns/aws/managedAccount.d.ts +0 -9
  360. package/dist/lib/patterns/aws/managedAccount.js +0 -55
  361. package/dist/lib/patterns/aws/managedOrganisation.d.ts +0 -36
  362. package/dist/lib/patterns/aws/managedOrganisation.js +0 -97
  363. package/dist/lib/patterns/aws/managedPlatform.d.ts +0 -12
  364. package/dist/lib/patterns/aws/managedPlatform.js +0 -29
  365. package/dist/lib/resources/aws/database/database.d.ts +0 -14
  366. package/dist/lib/resources/aws/database/database.js +0 -28
  367. package/dist/lib/resources/aws/database/databaseInstance.d.ts +0 -15
  368. package/dist/lib/resources/aws/database/databaseInstance.js +0 -30
  369. package/dist/lib/resources/aws/database/migrationLambda.d.ts +0 -80
  370. package/dist/lib/resources/aws/database/migrationLambda.js +0 -119
  371. package/dist/lib/resources/aws/iam/identityCenter/attachManagedPolicy.d.ts +0 -13
  372. package/dist/lib/resources/aws/iam/identityCenter/attachManagedPolicy.js +0 -51
  373. package/dist/lib/resources/aws/iam/securityGroup.d.ts +0 -5
  374. package/dist/lib/resources/aws/iam/securityGroup.js +0 -14
  375. package/dist/lib/resources/aws/monitoring/monitoringRole.d.ts +0 -29
  376. package/dist/lib/resources/aws/monitoring/monitoringRole.js +0 -120
  377. package/dist/lib/utils/capitalizeString.d.ts +0 -12
  378. package/dist/lib/utils/capitalizeString.js +0 -30
@@ -1,117 +1,25 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ScalingType = exports.Protocol = void 0;
4
- const aws_ecs_1 = require("aws-cdk-lib/aws-ecs");
5
- const aws_ec2_1 = require("aws-cdk-lib/aws-ec2");
6
- const constructs_1 = require("constructs");
7
- const aws_cdk_lib_1 = require("aws-cdk-lib");
8
- const aws_elasticloadbalancingv2_1 = require("aws-cdk-lib/aws-elasticloadbalancingv2");
9
- const aws_iam_1 = require("aws-cdk-lib/aws-iam");
10
- const aws_applicationautoscaling_1 = require("aws-cdk-lib/aws-applicationautoscaling");
11
- const aws_ecs_2 = require("aws-cdk-lib/aws-ecs");
12
- const aws_secretsmanager_1 = require("aws-cdk-lib/aws-secretsmanager");
13
- const aws_ssm_1 = require("aws-cdk-lib/aws-ssm");
14
- const aws_certificatemanager_1 = require("aws-cdk-lib/aws-certificatemanager");
15
- const aws_route53_1 = require("aws-cdk-lib/aws-route53");
16
- const aws_route53_targets_1 = require("aws-cdk-lib/aws-route53-targets");
17
- const aws_ecr_1 = require("aws-cdk-lib/aws-ecr");
18
- const aws_autoscaling_1 = require("aws-cdk-lib/aws-autoscaling");
19
- const hostedZone_1 = require("../networking/hostedZone");
20
- const securityGroup_js_1 = require("../networking/securityGroup.js");
21
- const connections_js_1 = require("../../../utils/connections.js");
22
- const vpcUtils_1 = require("../../../utils/vpcUtils");
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 constructs_1.Construct {
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 = (0, capitaliseString_1.toPascalCase)(props.clusterName);
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
- this.validateProps(props);
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.getOrCreateAsgCapacityProvider(serviceProps);
98
+ getOrCreateAsgCapacityProvider(this.ctx, serviceProps, this.asgState);
172
99
  }
173
100
  }
174
101
  if (!this.loadBalancerDisabled) {
175
- this.addLoadBalancer(props);
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.addHostedZone(props);
105
+ const hzResult = addHostedZone(this.ctx, this.loadBalancer);
106
+ this.certificate = hzResult.certificate;
178
107
  }
179
- this.addLoadBalancerListener(props);
108
+ this.loadBalancerListener = addLoadBalancerListener(this.ctx, this.loadBalancer, this.certificate);
180
109
  }
181
110
  else if (this.directAccessEnabled) {
182
- this.addDirectAccessOutputs(props);
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
- aws_cdk_lib_1.Aspects.of(this).add(new CapacityProviderDependencyAspect(this.cluster));
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.createExecutionRole(serviceName);
232
- const taskRole = this.createTaskRole(serviceName, serviceProps);
233
- const taskDefinition = this.createTaskDefinition(serviceName, serviceProps, executionRole, taskRole);
234
- const { containers, primaryContainer } = this.addContainersToTask(serviceName, serviceProps, taskDefinition);
235
- const service = this.createService(serviceName, serviceProps, taskDefinition);
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.registerServiceWithALB(serviceName, serviceProps, service, primaryContainer);
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.addServiceScaling(serviceName, serviceProps, service);
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
- (0, connections_js_1.processConnections)(serviceProps.connections, taskRole, // IGrantable (task role for IAM grants)
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
- validateProps(props) {
268
- // Validate services array
269
- if (!props.services || props.services.length === 0) {
270
- throw new Error("At least one service must be specified.");
271
- }
272
- // Check for duplicate service names
273
- const serviceNames = props.services.map((s) => s.name);
274
- const duplicateServices = serviceNames.filter((name, index) => serviceNames.indexOf(name) !== index);
275
- if (duplicateServices.length > 0) {
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
- this.connections = new aws_ec2_1.Connections({
239
+ return new Connections({
331
240
  securityGroups,
332
- defaultPort: aws_ec2_1.Port.tcp(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 = (0, capitaliseString_1.toPascalCase)(serviceName);
777
- new aws_cdk_lib_1.CfnOutput(this, `${this.outputName}${safeServiceName}DeployableService`, {
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) => this.isServiceFargate(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) => this.isServiceEc2(s));
266
+ return this.props.services.some((s) => isServiceEc2(s));
961
267
  }
962
268
  addCluster(props) {
963
269
  const needsFargate = this.anyServiceUsesFargate();
964
- this.cluster = new aws_ecs_1.Cluster(this, `${props.clusterName}Cluster`, {
270
+ const cluster = new CdkCluster(this, `${props.clusterName}Cluster`, {
965
271
  vpc: props.vpc,
966
272
  clusterName: props.clusterName,
967
- containerInsightsV2: aws_ecs_1.ContainerInsights.ENABLED,
273
+ containerInsightsV2: ContainerInsights.ENABLED,
968
274
  enableFargateCapacityProviders: needsFargate
969
275
  });
970
- new aws_cdk_lib_1.CfnOutput(this, `${this.outputName}DeployableCluster`, {
276
+ new CfnOutput(this, `${this.outputName}DeployableCluster`, {
971
277
  key: `${this.outputName}DeployableCluster`,
972
278
  exportName: `${props.clusterName}DeployableCluster`,
973
- value: this.cluster.clusterArn
279
+ value: cluster.clusterArn
974
280
  });
975
- new aws_cdk_lib_1.CfnOutput(this, `${this.outputName}ClusterArn`, {
281
+ new CfnOutput(this, `${this.outputName}ClusterArn`, {
976
282
  key: `${this.outputName}ClusterArn`,
977
283
  exportName: `${props.clusterName}ClusterArn`,
978
- value: this.cluster.clusterArn,
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=