aws-cdk 0.0.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 (402) hide show
  1. package/CONTRIBUTING.md +276 -0
  2. package/LICENSE +202 -0
  3. package/NOTICE +16 -0
  4. package/README.md +1274 -0
  5. package/THIRD_PARTY_LICENSES +26821 -0
  6. package/bin/cdk +6 -0
  7. package/build-info.json +4 -0
  8. package/db.json.gz +0 -0
  9. package/generate.sh +25 -0
  10. package/images/garbage-collection.png +0 -0
  11. package/lib/api/aws-auth/account-cache.d.ts +39 -0
  12. package/lib/api/aws-auth/account-cache.js +102 -0
  13. package/lib/api/aws-auth/awscli-compatible.d.ts +42 -0
  14. package/lib/api/aws-auth/awscli-compatible.js +264 -0
  15. package/lib/api/aws-auth/cached.d.ts +11 -0
  16. package/lib/api/aws-auth/cached.js +26 -0
  17. package/lib/api/aws-auth/credential-plugins.d.ts +36 -0
  18. package/lib/api/aws-auth/credential-plugins.js +153 -0
  19. package/lib/api/aws-auth/index.d.ts +3 -0
  20. package/lib/api/aws-auth/index.js +20 -0
  21. package/lib/api/aws-auth/provider-caching.d.ts +13 -0
  22. package/lib/api/aws-auth/provider-caching.js +24 -0
  23. package/lib/api/aws-auth/sdk-logger.d.ts +69 -0
  24. package/lib/api/aws-auth/sdk-logger.js +130 -0
  25. package/lib/api/aws-auth/sdk-provider.d.ts +207 -0
  26. package/lib/api/aws-auth/sdk-provider.js +359 -0
  27. package/lib/api/aws-auth/sdk.d.ts +223 -0
  28. package/lib/api/aws-auth/sdk.js +366 -0
  29. package/lib/api/aws-auth/tracing.d.ts +11 -0
  30. package/lib/api/aws-auth/tracing.js +61 -0
  31. package/lib/api/aws-auth/user-agent.d.ts +7 -0
  32. package/lib/api/aws-auth/user-agent.js +21 -0
  33. package/lib/api/aws-auth/util.d.ts +6 -0
  34. package/lib/api/aws-auth/util.js +23 -0
  35. package/lib/api/bootstrap/bootstrap-environment.d.ts +33 -0
  36. package/lib/api/bootstrap/bootstrap-environment.js +322 -0
  37. package/lib/api/bootstrap/bootstrap-props.d.ts +130 -0
  38. package/lib/api/bootstrap/bootstrap-props.js +14 -0
  39. package/lib/api/bootstrap/bootstrap-template.yaml +692 -0
  40. package/lib/api/bootstrap/deploy-bootstrap.d.ts +37 -0
  41. package/lib/api/bootstrap/deploy-bootstrap.js +143 -0
  42. package/lib/api/bootstrap/index.d.ts +2 -0
  43. package/lib/api/bootstrap/index.js +19 -0
  44. package/lib/api/bootstrap/legacy-template.d.ts +2 -0
  45. package/lib/api/bootstrap/legacy-template.js +82 -0
  46. package/lib/api/context.d.ts +40 -0
  47. package/lib/api/context.js +82 -0
  48. package/lib/api/cxapp/cloud-assembly.d.ts +150 -0
  49. package/lib/api/cxapp/cloud-assembly.js +305 -0
  50. package/lib/api/cxapp/cloud-executable.d.ts +44 -0
  51. package/lib/api/cxapp/cloud-executable.js +90 -0
  52. package/lib/api/cxapp/environments.d.ts +9 -0
  53. package/lib/api/cxapp/environments.js +66 -0
  54. package/lib/api/cxapp/exec.d.ts +56 -0
  55. package/lib/api/cxapp/exec.js +275 -0
  56. package/lib/api/deployments/asset-manifest-builder.d.ts +8 -0
  57. package/lib/api/deployments/asset-manifest-builder.js +35 -0
  58. package/lib/api/deployments/asset-publishing.d.ts +77 -0
  59. package/lib/api/deployments/asset-publishing.js +163 -0
  60. package/lib/api/deployments/assets.d.ts +10 -0
  61. package/lib/api/deployments/assets.js +111 -0
  62. package/lib/api/deployments/checks.d.ts +8 -0
  63. package/lib/api/deployments/checks.js +73 -0
  64. package/lib/api/deployments/cloudformation.d.ts +235 -0
  65. package/lib/api/deployments/cloudformation.js +598 -0
  66. package/lib/api/deployments/deploy-stack.d.ts +177 -0
  67. package/lib/api/deployments/deploy-stack.js +484 -0
  68. package/lib/api/deployments/deployment-method.d.ts +24 -0
  69. package/lib/api/deployments/deployment-method.js +3 -0
  70. package/lib/api/deployments/deployment-result.d.ts +21 -0
  71. package/lib/api/deployments/deployment-result.js +10 -0
  72. package/lib/api/deployments/deployments.d.ts +340 -0
  73. package/lib/api/deployments/deployments.js +369 -0
  74. package/lib/api/deployments/hotswap-deployments.d.ts +14 -0
  75. package/lib/api/deployments/hotswap-deployments.js +357 -0
  76. package/lib/api/deployments/index.d.ts +6 -0
  77. package/lib/api/deployments/index.js +23 -0
  78. package/lib/api/deployments/nested-stack-helpers.d.ts +25 -0
  79. package/lib/api/deployments/nested-stack-helpers.js +88 -0
  80. package/lib/api/environment-access.d.ts +138 -0
  81. package/lib/api/environment-access.js +203 -0
  82. package/lib/api/environment-resources.d.ts +73 -0
  83. package/lib/api/environment-resources.js +208 -0
  84. package/lib/api/evaluate-cloudformation-template.d.ts +84 -0
  85. package/lib/api/evaluate-cloudformation-template.js +443 -0
  86. package/lib/api/garbage-collection/garbage-collector.d.ts +152 -0
  87. package/lib/api/garbage-collection/garbage-collector.js +607 -0
  88. package/lib/api/garbage-collection/progress-printer.d.ts +21 -0
  89. package/lib/api/garbage-collection/progress-printer.js +69 -0
  90. package/lib/api/garbage-collection/stack-refresh.d.ts +44 -0
  91. package/lib/api/garbage-collection/stack-refresh.js +154 -0
  92. package/lib/api/hotswap/appsync-mapping-templates.d.ts +3 -0
  93. package/lib/api/hotswap/appsync-mapping-templates.js +157 -0
  94. package/lib/api/hotswap/code-build-projects.d.ts +3 -0
  95. package/lib/api/hotswap/code-build-projects.js +55 -0
  96. package/lib/api/hotswap/common.d.ts +126 -0
  97. package/lib/api/hotswap/common.js +170 -0
  98. package/lib/api/hotswap/ecs-services.d.ts +3 -0
  99. package/lib/api/hotswap/ecs-services.js +140 -0
  100. package/lib/api/hotswap/lambda-functions.d.ts +3 -0
  101. package/lib/api/hotswap/lambda-functions.js +309 -0
  102. package/lib/api/hotswap/s3-bucket-deployments.d.ts +9 -0
  103. package/lib/api/hotswap/s3-bucket-deployments.js +112 -0
  104. package/lib/api/hotswap/stepfunctions-state-machines.d.ts +3 -0
  105. package/lib/api/hotswap/stepfunctions-state-machines.js +42 -0
  106. package/lib/api/index.d.ts +5 -0
  107. package/lib/api/index.js +22 -0
  108. package/lib/api/logs/find-cloudwatch-logs.d.ts +24 -0
  109. package/lib/api/logs/find-cloudwatch-logs.js +97 -0
  110. package/lib/api/logs/logs-monitor.d.ts +53 -0
  111. package/lib/api/logs/logs-monitor.js +169 -0
  112. package/lib/api/plugin/context-provider-plugin.d.ts +6 -0
  113. package/lib/api/plugin/context-provider-plugin.js +7 -0
  114. package/lib/api/plugin/index.d.ts +3 -0
  115. package/lib/api/plugin/index.js +20 -0
  116. package/lib/api/plugin/mode.d.ts +4 -0
  117. package/lib/api/plugin/mode.js +9 -0
  118. package/lib/api/plugin/plugin.d.ts +63 -0
  119. package/lib/api/plugin/plugin.js +106 -0
  120. package/lib/api/settings.d.ts +29 -0
  121. package/lib/api/settings.js +141 -0
  122. package/lib/api/tags.d.ts +9 -0
  123. package/lib/api/tags.js +10 -0
  124. package/lib/api/toolkit-info.d.ts +51 -0
  125. package/lib/api/toolkit-info.js +156 -0
  126. package/lib/api/util/cloudformation/stack-activity-monitor.d.ts +237 -0
  127. package/lib/api/util/cloudformation/stack-activity-monitor.js +550 -0
  128. package/lib/api/util/cloudformation/stack-event-poller.d.ts +63 -0
  129. package/lib/api/util/cloudformation/stack-event-poller.js +129 -0
  130. package/lib/api/util/cloudformation/stack-status.d.ts +42 -0
  131. package/lib/api/util/cloudformation/stack-status.js +88 -0
  132. package/lib/api/util/display.d.ts +13 -0
  133. package/lib/api/util/display.js +80 -0
  134. package/lib/api/util/placeholders.d.ts +10 -0
  135. package/lib/api/util/placeholders.js +24 -0
  136. package/lib/api/util/rwlock.d.ts +65 -0
  137. package/lib/api/util/rwlock.js +179 -0
  138. package/lib/api/util/string-manipulation.d.ts +10 -0
  139. package/lib/api/util/string-manipulation.js +33 -0
  140. package/lib/api/util/template-body-parameter.d.ts +21 -0
  141. package/lib/api/util/template-body-parameter.js +104 -0
  142. package/lib/cli/cdk-toolkit.d.ts +594 -0
  143. package/lib/cli/cdk-toolkit.js +1019 -0
  144. package/lib/cli/cli-config.d.ts +10 -0
  145. package/lib/cli/cli-config.js +406 -0
  146. package/lib/cli/cli.d.ts +4 -0
  147. package/lib/cli/cli.js +538 -0
  148. package/lib/cli/convert-to-user-input.d.ts +3 -0
  149. package/lib/cli/convert-to-user-input.js +434 -0
  150. package/lib/cli/parse-command-line-arguments.d.ts +1 -0
  151. package/lib/cli/parse-command-line-arguments.js +806 -0
  152. package/lib/cli/platform-warnings.d.ts +2 -0
  153. package/lib/cli/platform-warnings.js +45 -0
  154. package/lib/cli/user-configuration.d.ts +90 -0
  155. package/lib/cli/user-configuration.js +272 -0
  156. package/lib/cli/user-input.d.ts +1163 -0
  157. package/lib/cli/user-input.js +3 -0
  158. package/lib/cli/util/console-formatters.d.ts +18 -0
  159. package/lib/cli/util/console-formatters.js +42 -0
  160. package/lib/cli/util/npm.d.ts +1 -0
  161. package/lib/cli/util/npm.js +22 -0
  162. package/lib/cli/util/yargs-helpers.d.ts +22 -0
  163. package/lib/cli/util/yargs-helpers.js +49 -0
  164. package/lib/cli/version.d.ts +13 -0
  165. package/lib/cli/version.js +120 -0
  166. package/lib/commands/context.d.ts +35 -0
  167. package/lib/commands/context.js +156 -0
  168. package/lib/commands/docs.d.ts +13 -0
  169. package/lib/commands/docs.js +32 -0
  170. package/lib/commands/doctor.d.ts +1 -0
  171. package/lib/commands/doctor.js +69 -0
  172. package/lib/commands/migrate.d.ts +327 -0
  173. package/lib/commands/migrate.js +804 -0
  174. package/lib/context-providers/ami.d.ts +11 -0
  175. package/lib/context-providers/ami.js +50 -0
  176. package/lib/context-providers/availability-zones.d.ts +11 -0
  177. package/lib/context-providers/availability-zones.js +27 -0
  178. package/lib/context-providers/endpoint-service-availability-zones.d.ts +11 -0
  179. package/lib/context-providers/endpoint-service-availability-zones.js +33 -0
  180. package/lib/context-providers/hosted-zones.d.ts +10 -0
  181. package/lib/context-providers/hosted-zones.js +67 -0
  182. package/lib/context-providers/index.d.ts +30 -0
  183. package/lib/context-providers/index.js +109 -0
  184. package/lib/context-providers/keys.d.ts +11 -0
  185. package/lib/context-providers/keys.js +52 -0
  186. package/lib/context-providers/load-balancers.d.ts +20 -0
  187. package/lib/context-providers/load-balancers.js +159 -0
  188. package/lib/context-providers/security-groups.d.ts +9 -0
  189. package/lib/context-providers/security-groups.js +70 -0
  190. package/lib/context-providers/ssm-parameters.d.ts +23 -0
  191. package/lib/context-providers/ssm-parameters.js +59 -0
  192. package/lib/context-providers/vpcs.d.ts +11 -0
  193. package/lib/context-providers/vpcs.js +288 -0
  194. package/lib/diff.d.ts +28 -0
  195. package/lib/diff.js +165 -0
  196. package/lib/import.d.ts +182 -0
  197. package/lib/import.js +335 -0
  198. package/lib/index.d.ts +3 -0
  199. package/lib/index.js +348304 -0
  200. package/lib/index_bg.wasm +0 -0
  201. package/lib/init-hooks.d.ts +40 -0
  202. package/lib/init-hooks.js +64 -0
  203. package/lib/init-templates/.init-version.json +1 -0
  204. package/lib/init-templates/.no-packagejson-validator +0 -0
  205. package/lib/init-templates/.recommended-feature-flags.json +68 -0
  206. package/lib/init-templates/LICENSE +16 -0
  207. package/lib/init-templates/app/csharp/.template.gitignore +342 -0
  208. package/lib/init-templates/app/csharp/README.md +14 -0
  209. package/lib/init-templates/app/csharp/cdk.template.json +15 -0
  210. package/lib/init-templates/app/csharp/src/%name.PascalCased%/%name.PascalCased%.template.csproj +20 -0
  211. package/lib/init-templates/app/csharp/src/%name.PascalCased%/%name.PascalCased%Stack.template.cs +13 -0
  212. package/lib/init-templates/app/csharp/src/%name.PascalCased%/GlobalSuppressions.cs +1 -0
  213. package/lib/init-templates/app/csharp/src/%name.PascalCased%/Program.template.cs +44 -0
  214. package/lib/init-templates/app/csharp/src/%name.PascalCased%.template.sln +18 -0
  215. package/lib/init-templates/app/fsharp/.template.gitignore +342 -0
  216. package/lib/init-templates/app/fsharp/README.md +18 -0
  217. package/lib/init-templates/app/fsharp/cdk.template.json +14 -0
  218. package/lib/init-templates/app/fsharp/src/%name.PascalCased%/%name.PascalCased%.template.fsproj +25 -0
  219. package/lib/init-templates/app/fsharp/src/%name.PascalCased%/%name.PascalCased%Stack.template.fs +8 -0
  220. package/lib/init-templates/app/fsharp/src/%name.PascalCased%/Program.template.fs +11 -0
  221. package/lib/init-templates/app/fsharp/src/%name.PascalCased%.template.sln +18 -0
  222. package/lib/init-templates/app/go/%name%.template.go +70 -0
  223. package/lib/init-templates/app/go/%name%_test.template.go +26 -0
  224. package/lib/init-templates/app/go/.template.gitignore +19 -0
  225. package/lib/init-templates/app/go/README.md +12 -0
  226. package/lib/init-templates/app/go/cdk.template.json +13 -0
  227. package/lib/init-templates/app/go/go.template.mod +9 -0
  228. package/lib/init-templates/app/info.json +4 -0
  229. package/lib/init-templates/app/java/.template.gitignore +13 -0
  230. package/lib/init-templates/app/java/README.md +18 -0
  231. package/lib/init-templates/app/java/cdk.json +13 -0
  232. package/lib/init-templates/app/java/pom.xml +60 -0
  233. package/lib/init-templates/app/java/src/main/java/com/myorg/%name.PascalCased%App.template.java +42 -0
  234. package/lib/init-templates/app/java/src/main/java/com/myorg/%name.PascalCased%Stack.template.java +24 -0
  235. package/lib/init-templates/app/java/src/test/java/com/myorg/%name.PascalCased%Test.template.java +26 -0
  236. package/lib/init-templates/app/javascript/.template.gitignore +5 -0
  237. package/lib/init-templates/app/javascript/.template.npmignore +3 -0
  238. package/lib/init-templates/app/javascript/README.md +12 -0
  239. package/lib/init-templates/app/javascript/bin/%name%.template.js +21 -0
  240. package/lib/init-templates/app/javascript/cdk.template.json +15 -0
  241. package/lib/init-templates/app/javascript/jest.config.js +3 -0
  242. package/lib/init-templates/app/javascript/lib/%name%-stack.template.js +23 -0
  243. package/lib/init-templates/app/javascript/package.json +20 -0
  244. package/lib/init-templates/app/javascript/test/%name%.test.template.js +17 -0
  245. package/lib/init-templates/app/python/%name.PythonModule%/%name.PythonModule%_stack.template.py +19 -0
  246. package/lib/init-templates/app/python/%name.PythonModule%/__init__.py +0 -0
  247. package/lib/init-templates/app/python/.template.gitignore +10 -0
  248. package/lib/init-templates/app/python/README.template.md +58 -0
  249. package/lib/init-templates/app/python/app.template.py +28 -0
  250. package/lib/init-templates/app/python/cdk.template.json +15 -0
  251. package/lib/init-templates/app/python/requirements-dev.txt +1 -0
  252. package/lib/init-templates/app/python/requirements.txt +2 -0
  253. package/lib/init-templates/app/python/source.bat +13 -0
  254. package/lib/init-templates/app/python/tests/__init__.py +0 -0
  255. package/lib/init-templates/app/python/tests/unit/__init__.py +0 -0
  256. package/lib/init-templates/app/python/tests/unit/test_%name.PythonModule%_stack.template.py +15 -0
  257. package/lib/init-templates/app/typescript/.template.gitignore +8 -0
  258. package/lib/init-templates/app/typescript/.template.npmignore +6 -0
  259. package/lib/init-templates/app/typescript/README.md +14 -0
  260. package/lib/init-templates/app/typescript/bin/%name%.template.ts +20 -0
  261. package/lib/init-templates/app/typescript/cdk.template.json +17 -0
  262. package/lib/init-templates/app/typescript/jest.config.js +8 -0
  263. package/lib/init-templates/app/typescript/lib/%name%-stack.template.ts +16 -0
  264. package/lib/init-templates/app/typescript/package.json +26 -0
  265. package/lib/init-templates/app/typescript/test/%name%.test.template.ts +17 -0
  266. package/lib/init-templates/app/typescript/tsconfig.json +31 -0
  267. package/lib/init-templates/lib/info.json +4 -0
  268. package/lib/init-templates/lib/typescript/.template.gitignore +8 -0
  269. package/lib/init-templates/lib/typescript/.template.npmignore +6 -0
  270. package/lib/init-templates/lib/typescript/README.template.md +12 -0
  271. package/lib/init-templates/lib/typescript/jest.config.js +8 -0
  272. package/lib/init-templates/lib/typescript/lib/index.template.ts +21 -0
  273. package/lib/init-templates/lib/typescript/package.json +24 -0
  274. package/lib/init-templates/lib/typescript/test/%name%.test.template.ts +18 -0
  275. package/lib/init-templates/lib/typescript/tsconfig.json +31 -0
  276. package/lib/init-templates/sample-app/csharp/.template.gitignore +342 -0
  277. package/lib/init-templates/sample-app/csharp/README.template.md +19 -0
  278. package/lib/init-templates/sample-app/csharp/cdk.template.json +15 -0
  279. package/lib/init-templates/sample-app/csharp/src/%name.PascalCased%/%name.PascalCased%.template.csproj +20 -0
  280. package/lib/init-templates/sample-app/csharp/src/%name.PascalCased%/%name.PascalCased%Stack.template.cs +24 -0
  281. package/lib/init-templates/sample-app/csharp/src/%name.PascalCased%/GlobalSuppressions.cs +1 -0
  282. package/lib/init-templates/sample-app/csharp/src/%name.PascalCased%/Program.template.cs +15 -0
  283. package/lib/init-templates/sample-app/csharp/src/%name.PascalCased%.template.sln +18 -0
  284. package/lib/init-templates/sample-app/fsharp/.template.gitignore +342 -0
  285. package/lib/init-templates/sample-app/fsharp/README.template.md +20 -0
  286. package/lib/init-templates/sample-app/fsharp/cdk.template.json +14 -0
  287. package/lib/init-templates/sample-app/fsharp/src/%name.PascalCased%/%name.PascalCased%.template.fsproj +25 -0
  288. package/lib/init-templates/sample-app/fsharp/src/%name.PascalCased%/%name.PascalCased%Stack.template.fs +14 -0
  289. package/lib/init-templates/sample-app/fsharp/src/%name.PascalCased%/Program.template.fs +11 -0
  290. package/lib/init-templates/sample-app/fsharp/src/%name.PascalCased%.template.sln +18 -0
  291. package/lib/init-templates/sample-app/go/%name%.template.go +73 -0
  292. package/lib/init-templates/sample-app/go/%name%_test.template.go +25 -0
  293. package/lib/init-templates/sample-app/go/.template.gitignore +19 -0
  294. package/lib/init-templates/sample-app/go/README.md +12 -0
  295. package/lib/init-templates/sample-app/go/cdk.template.json +13 -0
  296. package/lib/init-templates/sample-app/go/go.template.mod +9 -0
  297. package/lib/init-templates/sample-app/info.json +4 -0
  298. package/lib/init-templates/sample-app/java/.template.gitignore +13 -0
  299. package/lib/init-templates/sample-app/java/README.template.md +19 -0
  300. package/lib/init-templates/sample-app/java/cdk.json +13 -0
  301. package/lib/init-templates/sample-app/java/pom.xml +55 -0
  302. package/lib/init-templates/sample-app/java/src/main/java/com/myorg/%name.PascalCased%App.template.java +13 -0
  303. package/lib/init-templates/sample-app/java/src/main/java/com/myorg/%name.PascalCased%Stack.template.java +29 -0
  304. package/lib/init-templates/sample-app/java/src/test/java/com/myorg/%name.PascalCased%StackTest.template.java +27 -0
  305. package/lib/init-templates/sample-app/javascript/.template.gitignore +5 -0
  306. package/lib/init-templates/sample-app/javascript/.template.npmignore +3 -0
  307. package/lib/init-templates/sample-app/javascript/README.template.md +13 -0
  308. package/lib/init-templates/sample-app/javascript/bin/%name%.template.js +6 -0
  309. package/lib/init-templates/sample-app/javascript/cdk.template.json +15 -0
  310. package/lib/init-templates/sample-app/javascript/jest.config.js +3 -0
  311. package/lib/init-templates/sample-app/javascript/lib/%name%-stack.template.js +25 -0
  312. package/lib/init-templates/sample-app/javascript/package.json +20 -0
  313. package/lib/init-templates/sample-app/javascript/test/%name%.test.template.js +16 -0
  314. package/lib/init-templates/sample-app/javascript/tsconfig.json +34 -0
  315. package/lib/init-templates/sample-app/python/%name.PythonModule%/%name.PythonModule%_stack.template.py +26 -0
  316. package/lib/init-templates/sample-app/python/%name.PythonModule%/__init__.py +0 -0
  317. package/lib/init-templates/sample-app/python/.template.gitignore +22 -0
  318. package/lib/init-templates/sample-app/python/README.template.md +65 -0
  319. package/lib/init-templates/sample-app/python/app.template.py +11 -0
  320. package/lib/init-templates/sample-app/python/cdk.template.json +15 -0
  321. package/lib/init-templates/sample-app/python/requirements-dev.txt +1 -0
  322. package/lib/init-templates/sample-app/python/requirements.txt +2 -0
  323. package/lib/init-templates/sample-app/python/source.bat +13 -0
  324. package/lib/init-templates/sample-app/python/tests/__init__.py +0 -0
  325. package/lib/init-templates/sample-app/python/tests/unit/__init__.py +0 -0
  326. package/lib/init-templates/sample-app/python/tests/unit/test_%name.PythonModule%_stack.template.py +21 -0
  327. package/lib/init-templates/sample-app/typescript/.template.gitignore +8 -0
  328. package/lib/init-templates/sample-app/typescript/.template.npmignore +6 -0
  329. package/lib/init-templates/sample-app/typescript/README.template.md +15 -0
  330. package/lib/init-templates/sample-app/typescript/bin/%name%.template.ts +6 -0
  331. package/lib/init-templates/sample-app/typescript/cdk.template.json +17 -0
  332. package/lib/init-templates/sample-app/typescript/jest.config.js +8 -0
  333. package/lib/init-templates/sample-app/typescript/lib/%name%-stack.template.ts +19 -0
  334. package/lib/init-templates/sample-app/typescript/package.json +26 -0
  335. package/lib/init-templates/sample-app/typescript/test/%name%.test.template.ts +17 -0
  336. package/lib/init-templates/sample-app/typescript/tsconfig.json +31 -0
  337. package/lib/init.d.ts +52 -0
  338. package/lib/init.js +430 -0
  339. package/lib/legacy-exports-source.d.ts +27 -0
  340. package/lib/legacy-exports-source.js +88 -0
  341. package/lib/legacy-exports.d.ts +10 -0
  342. package/lib/legacy-exports.js +28 -0
  343. package/lib/legacy-logging-source.d.ts +32 -0
  344. package/lib/legacy-logging-source.js +107 -0
  345. package/lib/list-stacks.d.ts +22 -0
  346. package/lib/list-stacks.js +23 -0
  347. package/lib/logging.d.ts +109 -0
  348. package/lib/logging.js +159 -0
  349. package/lib/migrator.d.ts +25 -0
  350. package/lib/migrator.js +67 -0
  351. package/lib/notices.d.ts +156 -0
  352. package/lib/notices.js +373 -0
  353. package/lib/os.d.ts +7 -0
  354. package/lib/os.js +92 -0
  355. package/lib/serialize.d.ts +27 -0
  356. package/lib/serialize.js +86 -0
  357. package/lib/toolkit/cli-io-host.d.ts +208 -0
  358. package/lib/toolkit/cli-io-host.js +282 -0
  359. package/lib/toolkit/error.d.ts +44 -0
  360. package/lib/toolkit/error.js +78 -0
  361. package/lib/tree.d.ts +31 -0
  362. package/lib/tree.js +40 -0
  363. package/lib/util/archive.d.ts +1 -0
  364. package/lib/util/archive.js +86 -0
  365. package/lib/util/arrays.d.ts +14 -0
  366. package/lib/util/arrays.js +36 -0
  367. package/lib/util/bool.d.ts +7 -0
  368. package/lib/util/bool.js +13 -0
  369. package/lib/util/bytes.d.ts +8 -0
  370. package/lib/util/bytes.js +21 -0
  371. package/lib/util/content-hash.d.ts +5 -0
  372. package/lib/util/content-hash.js +43 -0
  373. package/lib/util/directories.d.ts +23 -0
  374. package/lib/util/directories.js +57 -0
  375. package/lib/util/error.d.ts +9 -0
  376. package/lib/util/error.js +22 -0
  377. package/lib/util/index.d.ts +5 -0
  378. package/lib/util/index.js +22 -0
  379. package/lib/util/objects.d.ts +52 -0
  380. package/lib/util/objects.js +183 -0
  381. package/lib/util/parallel.d.ts +6 -0
  382. package/lib/util/parallel.js +44 -0
  383. package/lib/util/tables.d.ts +1 -0
  384. package/lib/util/tables.js +10 -0
  385. package/lib/util/type-brands.d.ts +39 -0
  386. package/lib/util/type-brands.js +38 -0
  387. package/lib/util/types.d.ts +27 -0
  388. package/lib/util/types.js +25 -0
  389. package/lib/util/validate-notification-arn.d.ts +4 -0
  390. package/lib/util/validate-notification-arn.js +10 -0
  391. package/lib/util/version-range.d.ts +2 -0
  392. package/lib/util/version-range.js +36 -0
  393. package/lib/util/work-graph-builder.d.ts +32 -0
  394. package/lib/util/work-graph-builder.js +167 -0
  395. package/lib/util/work-graph-types.d.ts +50 -0
  396. package/lib/util/work-graph-types.js +14 -0
  397. package/lib/util/work-graph.d.ts +70 -0
  398. package/lib/util/work-graph.js +344 -0
  399. package/lib/util/yaml-cfn.d.ts +15 -0
  400. package/lib/util/yaml-cfn.js +56 -0
  401. package/package.json +197 -0
  402. package/scripts/user-input-gen +2 -0
@@ -0,0 +1,804 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FromScan = exports.CfnTemplateGeneratorProvider = exports.FilterType = exports.ScanStatus = exports.TemplateSourceOptions = void 0;
4
+ exports.generateCdkApp = generateCdkApp;
5
+ exports.generateStack = generateStack;
6
+ exports.readFromPath = readFromPath;
7
+ exports.readFromStack = readFromStack;
8
+ exports.generateTemplate = generateTemplate;
9
+ exports.chunks = chunks;
10
+ exports.setEnvironment = setEnvironment;
11
+ exports.parseSourceOptions = parseSourceOptions;
12
+ exports.scanProgressBar = scanProgressBar;
13
+ exports.printBar = printBar;
14
+ exports.printDots = printDots;
15
+ exports.rewriteLine = rewriteLine;
16
+ exports.displayTimeDiff = displayTimeDiff;
17
+ exports.writeMigrateJsonFile = writeMigrateJsonFile;
18
+ exports.getMigrateScanType = getMigrateScanType;
19
+ exports.isThereAWarning = isThereAWarning;
20
+ exports.buildGenertedTemplateOutput = buildGenertedTemplateOutput;
21
+ exports.buildCfnClient = buildCfnClient;
22
+ exports.appendWarningsToReadme = appendWarningsToReadme;
23
+ /* eslint-disable @typescript-eslint/no-require-imports */
24
+ /* eslint-disable @typescript-eslint/no-var-requires */
25
+ const fs = require("fs");
26
+ const path = require("path");
27
+ const cx_api_1 = require("@aws-cdk/cx-api");
28
+ const cdk_from_cfn = require("cdk-from-cfn");
29
+ const chalk = require("chalk");
30
+ const init_1 = require("../../lib/init");
31
+ const logging_1 = require("../../lib/logging");
32
+ const deployments_1 = require("../api/deployments");
33
+ const error_1 = require("../toolkit/error");
34
+ const archive_1 = require("../util/archive");
35
+ const camelCase = require('camelcase');
36
+ const decamelize = require('decamelize');
37
+ /** The list of languages supported by the built-in noctilucent binary. */
38
+ const MIGRATE_SUPPORTED_LANGUAGES = cdk_from_cfn.supported_languages();
39
+ /**
40
+ * Generates a CDK app from a yaml or json template.
41
+ *
42
+ * @param stackName The name to assign to the stack in the generated app
43
+ * @param stack The yaml or json template for the stack
44
+ * @param language The language to generate the CDK app in
45
+ * @param outputPath The path at which to generate the CDK app
46
+ */
47
+ async function generateCdkApp(stackName, stack, language, outputPath, compress) {
48
+ const resolvedOutputPath = path.join(outputPath !== null && outputPath !== void 0 ? outputPath : process.cwd(), stackName);
49
+ const formattedStackName = decamelize(stackName);
50
+ try {
51
+ fs.rmSync(resolvedOutputPath, { recursive: true, force: true });
52
+ fs.mkdirSync(resolvedOutputPath, { recursive: true });
53
+ const generateOnly = compress;
54
+ await (0, init_1.cliInit)({
55
+ type: 'app',
56
+ language,
57
+ canUseNetwork: true,
58
+ generateOnly,
59
+ workDir: resolvedOutputPath,
60
+ stackName,
61
+ migrate: true,
62
+ });
63
+ let stackFileName;
64
+ switch (language) {
65
+ case 'typescript':
66
+ stackFileName = `${resolvedOutputPath}/lib/${formattedStackName}-stack.ts`;
67
+ break;
68
+ case 'java':
69
+ stackFileName = `${resolvedOutputPath}/src/main/java/com/myorg/${camelCase(formattedStackName, { pascalCase: true })}Stack.java`;
70
+ break;
71
+ case 'python':
72
+ stackFileName = `${resolvedOutputPath}/${formattedStackName.replace(/-/g, '_')}/${formattedStackName.replace(/-/g, '_')}_stack.py`;
73
+ break;
74
+ case 'csharp':
75
+ stackFileName = `${resolvedOutputPath}/src/${camelCase(formattedStackName, { pascalCase: true })}/${camelCase(formattedStackName, { pascalCase: true })}Stack.cs`;
76
+ break;
77
+ case 'go':
78
+ stackFileName = `${resolvedOutputPath}/${formattedStackName}.go`;
79
+ break;
80
+ default:
81
+ throw new error_1.ToolkitError(`${language} is not supported by CDK Migrate. Please choose from: ${MIGRATE_SUPPORTED_LANGUAGES.join(', ')}`);
82
+ }
83
+ fs.writeFileSync(stackFileName, stack);
84
+ if (compress) {
85
+ await (0, archive_1.zipDirectory)(resolvedOutputPath, `${resolvedOutputPath}.zip`);
86
+ fs.rmSync(resolvedOutputPath, { recursive: true, force: true });
87
+ }
88
+ }
89
+ catch (error) {
90
+ fs.rmSync(resolvedOutputPath, { recursive: true, force: true });
91
+ throw error;
92
+ }
93
+ }
94
+ /**
95
+ * Generates a CDK stack file.
96
+ * @param template The template to translate into a CDK stack
97
+ * @param stackName The name to assign to the stack
98
+ * @param language The language to generate the stack in
99
+ * @returns A string representation of a CDK stack file
100
+ */
101
+ function generateStack(template, stackName, language) {
102
+ const formattedStackName = `${camelCase(decamelize(stackName), { pascalCase: true })}Stack`;
103
+ try {
104
+ return cdk_from_cfn.transmute(template, language, formattedStackName);
105
+ }
106
+ catch (e) {
107
+ throw new error_1.ToolkitError(`${formattedStackName} could not be generated because ${e.message}`);
108
+ }
109
+ }
110
+ /**
111
+ * Reads and returns a stack template from a local path.
112
+ *
113
+ * @param inputPath The location of the template
114
+ * @returns A string representation of the template if present, otherwise undefined
115
+ */
116
+ function readFromPath(inputPath) {
117
+ let readFile;
118
+ try {
119
+ readFile = fs.readFileSync(inputPath, 'utf8');
120
+ }
121
+ catch (e) {
122
+ throw new error_1.ToolkitError(`'${inputPath}' is not a valid path.`);
123
+ }
124
+ if (readFile == '') {
125
+ throw new error_1.ToolkitError(`Cloudformation template filepath: '${inputPath}' is an empty file.`);
126
+ }
127
+ return readFile;
128
+ }
129
+ /**
130
+ * Reads and returns a stack template from a deployed CloudFormation stack.
131
+ *
132
+ * @param stackName The name of the stack
133
+ * @param sdkProvider The sdk provider for making CloudFormation calls
134
+ * @param environment The account and region where the stack is deployed
135
+ * @returns A string representation of the template if present, otherwise undefined
136
+ */
137
+ async function readFromStack(stackName, sdkProvider, environment) {
138
+ const cloudFormation = (await sdkProvider.forEnvironment(environment, 0)).sdk.cloudFormation();
139
+ const stack = await deployments_1.CloudFormationStack.lookup(cloudFormation, stackName, true);
140
+ if (stack.stackStatus.isDeploySuccess || stack.stackStatus.isRollbackSuccess) {
141
+ return JSON.stringify(await stack.template());
142
+ }
143
+ else {
144
+ throw new error_1.ToolkitError(`Stack '${stackName}' in account ${environment.account} and region ${environment.region} has a status of '${stack.stackStatus.name}' due to '${stack.stackStatus.reason}'. The stack cannot be migrated until it is in a healthy state.`);
145
+ }
146
+ }
147
+ /**
148
+ * Takes in a stack name and account and region and returns a generated cloudformation template using the cloudformation
149
+ * template generator.
150
+ *
151
+ * @param GenerateTemplateOptions An object containing the stack name, filters, sdkProvider, environment, and newScan flag
152
+ * @returns a generated cloudformation template
153
+ */
154
+ async function generateTemplate(options) {
155
+ const cfn = new CfnTemplateGeneratorProvider(await buildCfnClient(options.sdkProvider, options.environment));
156
+ const scanId = await findLastSuccessfulScan(cfn, options);
157
+ // if a customer accidentally ctrl-c's out of the command and runs it again, this will continue the progress bar where it left off
158
+ const curScan = await cfn.describeResourceScan(scanId);
159
+ if (curScan.Status == ScanStatus.IN_PROGRESS) {
160
+ (0, logging_1.info)('Resource scan in progress. Please wait, this can take 10 minutes or longer.');
161
+ await scanProgressBar(scanId, cfn);
162
+ }
163
+ displayTimeDiff(new Date(), new Date(curScan.StartTime));
164
+ let resources = await cfn.listResourceScanResources(scanId, options.filters);
165
+ (0, logging_1.info)('finding related resources.');
166
+ let relatedResources = await cfn.getResourceScanRelatedResources(scanId, resources);
167
+ (0, logging_1.info)(`Found ${relatedResources.length} resources.`);
168
+ (0, logging_1.info)('Generating CFN template from scanned resources.');
169
+ const templateArn = (await cfn.createGeneratedTemplate(options.stackName, relatedResources)).GeneratedTemplateId;
170
+ let generatedTemplate = await cfn.describeGeneratedTemplate(templateArn);
171
+ (0, logging_1.info)('Please wait, template creation in progress. This may take a couple minutes.');
172
+ while (generatedTemplate.Status !== ScanStatus.COMPLETE && generatedTemplate.Status !== ScanStatus.FAILED) {
173
+ await printDots(`[${generatedTemplate.Status}] Template Creation in Progress`, 400);
174
+ generatedTemplate = await cfn.describeGeneratedTemplate(templateArn);
175
+ }
176
+ (0, logging_1.info)('');
177
+ (0, logging_1.info)('Template successfully generated!');
178
+ return buildGenertedTemplateOutput(generatedTemplate, (await cfn.getGeneratedTemplate(templateArn)).TemplateBody, templateArn);
179
+ }
180
+ async function findLastSuccessfulScan(cfn, options) {
181
+ let resourceScanSummaries = [];
182
+ const clientRequestToken = `cdk-migrate-${options.environment.account}-${options.environment.region}`;
183
+ if (options.fromScan === FromScan.NEW) {
184
+ (0, logging_1.info)(`Starting new scan for account ${options.environment.account} in region ${options.environment.region}`);
185
+ try {
186
+ await cfn.startResourceScan(clientRequestToken);
187
+ resourceScanSummaries = (await cfn.listResourceScans()).ResourceScanSummaries;
188
+ }
189
+ catch (e) {
190
+ // continuing here because if the scan fails on a new-scan it is very likely because there is either already a scan in progress
191
+ // or the customer hit a rate limit. In either case we want to continue with the most recent scan.
192
+ // If this happens to fail for a credential error then that will be caught immediately after anyway.
193
+ (0, logging_1.info)(`Scan failed to start due to error '${e.message}', defaulting to latest scan.`);
194
+ }
195
+ }
196
+ else {
197
+ resourceScanSummaries = (await cfn.listResourceScans()).ResourceScanSummaries;
198
+ await cfn.checkForResourceScan(resourceScanSummaries, options, clientRequestToken);
199
+ }
200
+ // get the latest scan, which we know will exist
201
+ resourceScanSummaries = (await cfn.listResourceScans()).ResourceScanSummaries;
202
+ let scanId = resourceScanSummaries[0].ResourceScanId;
203
+ // find the most recent scan that isn't in a failed state in case we didn't start a new one
204
+ for (const summary of resourceScanSummaries) {
205
+ if (summary.Status !== ScanStatus.FAILED) {
206
+ scanId = summary.ResourceScanId;
207
+ break;
208
+ }
209
+ }
210
+ return scanId;
211
+ }
212
+ /**
213
+ * Takes a string of filters in the format of key1=value1,key2=value2 and returns a map of the filters.
214
+ *
215
+ * @param filters a string of filters in the format of key1=value1,key2=value2
216
+ * @returns a map of the filters
217
+ */
218
+ function parseFilters(filters) {
219
+ if (!filters) {
220
+ return {
221
+ 'resource-identifier': undefined,
222
+ 'resource-type-prefix': undefined,
223
+ 'tag-key': undefined,
224
+ 'tag-value': undefined,
225
+ };
226
+ }
227
+ const filterShorthands = {
228
+ 'identifier': FilterType.RESOURCE_IDENTIFIER,
229
+ 'id': FilterType.RESOURCE_IDENTIFIER,
230
+ 'type': FilterType.RESOURCE_TYPE_PREFIX,
231
+ 'type-prefix': FilterType.RESOURCE_TYPE_PREFIX,
232
+ };
233
+ const filterList = filters.split(',');
234
+ let filterMap = {
235
+ [FilterType.RESOURCE_IDENTIFIER]: undefined,
236
+ [FilterType.RESOURCE_TYPE_PREFIX]: undefined,
237
+ [FilterType.TAG_KEY]: undefined,
238
+ [FilterType.TAG_VALUE]: undefined,
239
+ };
240
+ for (const fil of filterList) {
241
+ const filter = fil.split('=');
242
+ let filterKey = filter[0];
243
+ const filterValue = filter[1];
244
+ // if the key is a shorthand, replace it with the full name
245
+ if (filterKey in filterShorthands) {
246
+ filterKey = filterShorthands[filterKey];
247
+ }
248
+ if (Object.values(FilterType).includes(filterKey)) {
249
+ filterMap[filterKey] = filterValue;
250
+ }
251
+ else {
252
+ throw new error_1.ToolkitError(`Invalid filter: ${filterKey}`);
253
+ }
254
+ }
255
+ return filterMap;
256
+ }
257
+ /**
258
+ * Takes a list of any type and breaks it up into chunks of a specified size.
259
+ *
260
+ * @param list The list to break up
261
+ * @param chunkSize The size of each chunk
262
+ * @returns A list of lists of the specified size
263
+ */
264
+ function chunks(list, chunkSize) {
265
+ const chunkedList = [];
266
+ for (let i = 0; i < list.length; i += chunkSize) {
267
+ chunkedList.push(list.slice(i, i + chunkSize));
268
+ }
269
+ return chunkedList;
270
+ }
271
+ /**
272
+ * Sets the account and region for making CloudFormation calls.
273
+ * @param account The account to use
274
+ * @param region The region to use
275
+ * @returns The environment object
276
+ */
277
+ function setEnvironment(account, region) {
278
+ return {
279
+ account: account !== null && account !== void 0 ? account : cx_api_1.UNKNOWN_ACCOUNT,
280
+ region: region !== null && region !== void 0 ? region : cx_api_1.UNKNOWN_REGION,
281
+ name: 'cdk-migrate-env',
282
+ };
283
+ }
284
+ /**
285
+ * Enum for the source options for the template
286
+ */
287
+ var TemplateSourceOptions;
288
+ (function (TemplateSourceOptions) {
289
+ TemplateSourceOptions["PATH"] = "path";
290
+ TemplateSourceOptions["STACK"] = "stack";
291
+ TemplateSourceOptions["SCAN"] = "scan";
292
+ })(TemplateSourceOptions || (exports.TemplateSourceOptions = TemplateSourceOptions = {}));
293
+ /**
294
+ * Enum for the status of a resource scan
295
+ */
296
+ var ScanStatus;
297
+ (function (ScanStatus) {
298
+ ScanStatus["IN_PROGRESS"] = "IN_PROGRESS";
299
+ ScanStatus["COMPLETE"] = "COMPLETE";
300
+ ScanStatus["FAILED"] = "FAILED";
301
+ })(ScanStatus || (exports.ScanStatus = ScanStatus = {}));
302
+ var FilterType;
303
+ (function (FilterType) {
304
+ FilterType["RESOURCE_IDENTIFIER"] = "resource-identifier";
305
+ FilterType["RESOURCE_TYPE_PREFIX"] = "resource-type-prefix";
306
+ FilterType["TAG_KEY"] = "tag-key";
307
+ FilterType["TAG_VALUE"] = "tag-value";
308
+ })(FilterType || (exports.FilterType = FilterType = {}));
309
+ /**
310
+ * Validates that exactly one source option has been provided.
311
+ * @param fromPath The content of the flag `--from-path`
312
+ * @param fromStack the content of the flag `--from-stack`
313
+ */
314
+ function parseSourceOptions(fromPath, fromStack, stackName) {
315
+ if (fromPath && fromStack) {
316
+ throw new error_1.ToolkitError('Only one of `--from-path` or `--from-stack` may be provided.');
317
+ }
318
+ if (!stackName) {
319
+ throw new error_1.ToolkitError('`--stack-name` is a required field.');
320
+ }
321
+ if (!fromPath && !fromStack) {
322
+ return { source: TemplateSourceOptions.SCAN };
323
+ }
324
+ if (fromPath) {
325
+ return { source: TemplateSourceOptions.PATH, templatePath: fromPath };
326
+ }
327
+ return { source: TemplateSourceOptions.STACK, stackName: stackName };
328
+ }
329
+ /**
330
+ * Takes a set of resources and removes any with the managedbystack flag set to true.
331
+ *
332
+ * @param resourceList the list of resources provided by the list scanned resources calls
333
+ * @returns a list of resources not managed by cfn stacks
334
+ */
335
+ function excludeManaged(resourceList) {
336
+ return resourceList
337
+ .filter((r) => !r.ManagedByStack)
338
+ .map((r) => ({
339
+ ResourceType: r.ResourceType,
340
+ ResourceIdentifier: r.ResourceIdentifier,
341
+ }));
342
+ }
343
+ /**
344
+ * Transforms a list of resources into a list of resource identifiers by removing the ManagedByStack flag.
345
+ * Setting the value of the field to undefined effectively removes it from the object.
346
+ *
347
+ * @param resourceList the list of resources provided by the list scanned resources calls
348
+ * @returns a list of ScannedResourceIdentifier[]
349
+ */
350
+ function resourceIdentifiers(resourceList) {
351
+ const identifiers = [];
352
+ resourceList.forEach((r) => {
353
+ const identifier = {
354
+ ResourceType: r.ResourceType,
355
+ ResourceIdentifier: r.ResourceIdentifier,
356
+ };
357
+ identifiers.push(identifier);
358
+ });
359
+ return identifiers;
360
+ }
361
+ /**
362
+ * Takes a scan id and maintains a progress bar to display the progress of a scan to the user.
363
+ *
364
+ * @param scanId A string representing the scan id
365
+ * @param cloudFormation The CloudFormation sdk client to use
366
+ */
367
+ async function scanProgressBar(scanId, cfn) {
368
+ var _a;
369
+ let curProgress = 0.5;
370
+ // we know it's in progress initially since we wouldn't have gotten here if it wasn't
371
+ let curScan = {
372
+ Status: ScanStatus.IN_PROGRESS,
373
+ $metadata: {},
374
+ };
375
+ while (curScan.Status == ScanStatus.IN_PROGRESS) {
376
+ curScan = await cfn.describeResourceScan(scanId);
377
+ curProgress = (_a = curScan.PercentageCompleted) !== null && _a !== void 0 ? _a : curProgress;
378
+ printBar(30, curProgress);
379
+ await new Promise((resolve) => setTimeout(resolve, 2000));
380
+ }
381
+ (0, logging_1.info)('');
382
+ (0, logging_1.info)('✅ Scan Complete!');
383
+ }
384
+ /**
385
+ * Prints a progress bar to the console. To be used in a while loop to show progress of a long running task.
386
+ * The progress bar deletes the current line on the console and rewrites it with the progress amount.
387
+ *
388
+ * @param width The width of the progress bar
389
+ * @param progress The current progress to display as a percentage of 100
390
+ */
391
+ function printBar(width, progress) {
392
+ if (!process.env.MIGRATE_INTEG_TEST) {
393
+ const FULL_BLOCK = '█';
394
+ const PARTIAL_BLOCK = ['', '▏', '▎', '▍', '▌', '▋', '▊', '▉'];
395
+ const fraction = Math.min(progress / 100, 1);
396
+ const innerWidth = Math.max(1, width - 2);
397
+ const chars = innerWidth * fraction;
398
+ const remainder = chars - Math.floor(chars);
399
+ const fullChars = FULL_BLOCK.repeat(Math.floor(chars));
400
+ const partialChar = PARTIAL_BLOCK[Math.floor(remainder * PARTIAL_BLOCK.length)];
401
+ const filler = '·'.repeat(innerWidth - Math.floor(chars) - (partialChar ? 1 : 0));
402
+ const color = chalk.green;
403
+ rewriteLine('[' + color(fullChars + partialChar) + filler + `] (${progress}%)`);
404
+ }
405
+ }
406
+ /**
407
+ * Prints a message to the console with a series periods appended to it. To be used in a while loop to show progress of a long running task.
408
+ * The message deletes the current line and rewrites it several times to display 1-3 periods to show the user that the task is still running.
409
+ *
410
+ * @param message The message to display
411
+ * @param timeoutx4 The amount of time to wait before printing the next period
412
+ */
413
+ async function printDots(message, timeoutx4) {
414
+ if (!process.env.MIGRATE_INTEG_TEST) {
415
+ rewriteLine(message + ' .');
416
+ await new Promise((resolve) => setTimeout(resolve, timeoutx4));
417
+ rewriteLine(message + ' ..');
418
+ await new Promise((resolve) => setTimeout(resolve, timeoutx4));
419
+ rewriteLine(message + ' ...');
420
+ await new Promise((resolve) => setTimeout(resolve, timeoutx4));
421
+ rewriteLine(message);
422
+ await new Promise((resolve) => setTimeout(resolve, timeoutx4));
423
+ }
424
+ }
425
+ /**
426
+ * Rewrites the current line on the console and writes a new message to it.
427
+ * This is a helper funciton for printDots and printBar.
428
+ *
429
+ * @param message The message to display
430
+ */
431
+ function rewriteLine(message) {
432
+ process.stdout.clearLine(0);
433
+ process.stdout.cursorTo(0);
434
+ process.stdout.write(message);
435
+ }
436
+ /**
437
+ * Prints the time difference between two dates in days, hours, and minutes.
438
+ *
439
+ * @param time1 The first date to compare
440
+ * @param time2 The second date to compare
441
+ */
442
+ function displayTimeDiff(time1, time2) {
443
+ const diff = Math.abs(time1.getTime() - time2.getTime());
444
+ const days = Math.floor(diff / (1000 * 60 * 60 * 24));
445
+ const hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
446
+ const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));
447
+ (0, logging_1.info)(`Using the latest successful scan which is ${days} days, ${hours} hours, and ${minutes} minutes old.`);
448
+ }
449
+ /**
450
+ * Writes a migrate.json file to the output directory.
451
+ *
452
+ * @param outputPath The path to write the migrate.json file to
453
+ * @param stackName The name of the stack
454
+ * @param generatedOutput The output of the template generator
455
+ */
456
+ function writeMigrateJsonFile(outputPath, stackName, migrateJson) {
457
+ const outputToJson = {
458
+ '//': 'This file is generated by cdk migrate. It will be automatically deleted after the first successful deployment of this app to the environment of the original resources.',
459
+ 'Source': migrateJson.source,
460
+ 'Resources': migrateJson.resources,
461
+ };
462
+ fs.writeFileSync(`${path.join(outputPath !== null && outputPath !== void 0 ? outputPath : process.cwd(), stackName)}/migrate.json`, JSON.stringify(outputToJson, null, 2));
463
+ }
464
+ /**
465
+ * Takes a string representing the from-scan flag and returns a FromScan enum value.
466
+ *
467
+ * @param scanType A string representing the from-scan flag
468
+ * @returns A FromScan enum value
469
+ */
470
+ function getMigrateScanType(scanType) {
471
+ switch (scanType) {
472
+ case 'new':
473
+ return FromScan.NEW;
474
+ case 'most-recent':
475
+ return FromScan.MOST_RECENT;
476
+ case '':
477
+ return FromScan.DEFAULT;
478
+ case undefined:
479
+ return FromScan.DEFAULT;
480
+ default:
481
+ throw new error_1.ToolkitError(`Unknown scan type: ${scanType}`);
482
+ }
483
+ }
484
+ /**
485
+ * Takes a generatedTemplateOutput objct and returns a boolean representing whether there are any warnings on any rescources.
486
+ *
487
+ * @param generatedTemplateOutput A GenerateTemplateOutput object
488
+ * @returns A boolean representing whether there are any warnings on any rescources
489
+ */
490
+ function isThereAWarning(generatedTemplateOutput) {
491
+ if (generatedTemplateOutput.resources) {
492
+ for (const resource of generatedTemplateOutput.resources) {
493
+ if (resource.Warnings && resource.Warnings.length > 0) {
494
+ return true;
495
+ }
496
+ }
497
+ }
498
+ return false;
499
+ }
500
+ /**
501
+ * Builds the GenerateTemplateOutput object from the DescribeGeneratedTemplateOutput and the template body.
502
+ *
503
+ * @param generatedTemplateSummary The output of the describe generated template call
504
+ * @param templateBody The body of the generated template
505
+ * @returns A GenerateTemplateOutput object
506
+ */
507
+ function buildGenertedTemplateOutput(generatedTemplateSummary, templateBody, source) {
508
+ const resources = generatedTemplateSummary.Resources;
509
+ const migrateJson = {
510
+ templateBody: templateBody,
511
+ source: source,
512
+ resources: generatedTemplateSummary.Resources.map((r) => ({
513
+ ResourceType: r.ResourceType,
514
+ LogicalResourceId: r.LogicalResourceId,
515
+ ResourceIdentifier: r.ResourceIdentifier,
516
+ })),
517
+ };
518
+ const templateId = generatedTemplateSummary.GeneratedTemplateId;
519
+ return {
520
+ migrateJson: migrateJson,
521
+ resources: resources,
522
+ templateId: templateId,
523
+ };
524
+ }
525
+ /**
526
+ * Builds a CloudFormation sdk client for making requests with the CFN template generator.
527
+ *
528
+ * @param sdkProvider The sdk provider for making CloudFormation calls
529
+ * @param environment The account and region where the stack is deployed
530
+ * @returns A CloudFormation sdk client
531
+ */
532
+ async function buildCfnClient(sdkProvider, environment) {
533
+ const sdk = (await sdkProvider.forEnvironment(environment, 0)).sdk;
534
+ sdk.appendCustomUserAgent('cdk-migrate');
535
+ return sdk.cloudFormation();
536
+ }
537
+ /**
538
+ * Appends a list of warnings to a readme file.
539
+ *
540
+ * @param filepath The path to the readme file
541
+ * @param resources A list of resources to append warnings for
542
+ */
543
+ function appendWarningsToReadme(filepath, resources) {
544
+ const readme = fs.readFileSync(filepath, 'utf8');
545
+ const lines = readme.split('\n');
546
+ const index = lines.findIndex((line) => line.trim() === 'Enjoy!');
547
+ let linesToAdd = ['\n## Warnings'];
548
+ linesToAdd.push('### Write-only properties');
549
+ linesToAdd.push("Write-only properties are resource property values that can be written to but can't be read by AWS CloudFormation or CDK Migrate. For more information, see [IaC generator and write-only properties](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/generate-IaC-write-only-properties.html).");
550
+ linesToAdd.push('\n');
551
+ linesToAdd.push('Write-only properties discovered during migration are organized here by resource ID and categorized by write-only property type. Resolve write-only properties by providing property values in your CDK app. For guidance, see [Resolve write-only properties](https://docs.aws.amazon.com/cdk/v2/guide/migrate.html#migrate-resources-writeonly).');
552
+ for (const resource of resources) {
553
+ if (resource.Warnings && resource.Warnings.length > 0) {
554
+ linesToAdd.push(`### ${resource.LogicalResourceId}`);
555
+ for (const warning of resource.Warnings) {
556
+ linesToAdd.push(`- **${warning.Type}**: `);
557
+ for (const property of warning.Properties) {
558
+ linesToAdd.push(` - ${property.PropertyPath}: ${property.Description}`);
559
+ }
560
+ }
561
+ }
562
+ }
563
+ lines.splice(index, 0, ...linesToAdd);
564
+ fs.writeFileSync(filepath, lines.join('\n'));
565
+ }
566
+ /**
567
+ * takes a list of resources and returns a list of unique resources based on the resource type and logical resource id.
568
+ *
569
+ * @param resources A list of resources to deduplicate
570
+ * @returns A list of unique resources
571
+ */
572
+ function deduplicateResources(resources) {
573
+ let uniqueResources = {};
574
+ for (const resource of resources) {
575
+ const key = Object.keys(resource.ResourceIdentifier)[0];
576
+ // Creating our unique identifier using the resource type, the key, and the value of the resource identifier
577
+ // The resource identifier is a combination of a key value pair defined by a resource's schema, and the resource type of the resource.
578
+ const uniqueIdentifer = `${resource.ResourceType}:${key}:${resource.ResourceIdentifier[key]}`;
579
+ uniqueResources[uniqueIdentifer] = resource;
580
+ }
581
+ return Object.values(uniqueResources);
582
+ }
583
+ /**
584
+ * Class for making CloudFormation template generator calls
585
+ */
586
+ class CfnTemplateGeneratorProvider {
587
+ constructor(cfn) {
588
+ this.cfn = cfn;
589
+ }
590
+ async checkForResourceScan(resourceScanSummaries, options, clientRequestToken) {
591
+ if (!resourceScanSummaries || resourceScanSummaries.length === 0) {
592
+ if (options.fromScan === FromScan.MOST_RECENT) {
593
+ throw new error_1.ToolkitError('No scans found. Please either start a new scan with the `--from-scan` new or do not specify a `--from-scan` option.');
594
+ }
595
+ else {
596
+ (0, logging_1.info)('No scans found. Initiating a new resource scan.');
597
+ await this.startResourceScan(clientRequestToken);
598
+ }
599
+ }
600
+ }
601
+ /**
602
+ * Retrieves a tokenized list of resources and their associated scan. If a token is present the function
603
+ * will loop through all pages and combine them into a single list of ScannedRelatedResources
604
+ *
605
+ * @param scanId scan id for the to list resources for
606
+ * @param resources A list of resources to find related resources for
607
+ */
608
+ async getResourceScanRelatedResources(scanId, resources) {
609
+ var _a, _b;
610
+ let relatedResourceList = resources;
611
+ // break the list of resources into chunks of 100 to avoid hitting the 100 resource limit
612
+ for (const chunk of chunks(resources, 100)) {
613
+ // get the first page of related resources
614
+ const res = await this.cfn.listResourceScanRelatedResources({
615
+ ResourceScanId: scanId,
616
+ Resources: chunk,
617
+ });
618
+ // add the first page to the list
619
+ relatedResourceList.push(...((_a = res.RelatedResources) !== null && _a !== void 0 ? _a : []));
620
+ let nextToken = res.NextToken;
621
+ // if there are more pages, cycle through them and add them to the list before moving on to the next chunk
622
+ while (nextToken) {
623
+ const nextRelatedResources = await this.cfn.listResourceScanRelatedResources({
624
+ ResourceScanId: scanId,
625
+ Resources: resourceIdentifiers(resources),
626
+ NextToken: nextToken,
627
+ });
628
+ nextToken = nextRelatedResources.NextToken;
629
+ relatedResourceList.push(...((_b = nextRelatedResources.RelatedResources) !== null && _b !== void 0 ? _b : []));
630
+ }
631
+ }
632
+ relatedResourceList = deduplicateResources(relatedResourceList);
633
+ // prune the managedbystack flag off of them again.
634
+ return process.env.MIGRATE_INTEG_TEST
635
+ ? resourceIdentifiers(relatedResourceList)
636
+ : resourceIdentifiers(excludeManaged(relatedResourceList));
637
+ }
638
+ /**
639
+ * Kicks off a scan of a customers account, returning the scan id. A scan can take
640
+ * 10 minutes or longer to complete. However this will return a scan id as soon as
641
+ * the scan has begun.
642
+ *
643
+ * @returns A string representing the scan id
644
+ */
645
+ async startResourceScan(requestToken) {
646
+ return (await this.cfn.startResourceScan({
647
+ ClientRequestToken: requestToken,
648
+ })).ResourceScanId;
649
+ }
650
+ /**
651
+ * Gets the most recent scans a customer has completed
652
+ *
653
+ * @returns a list of resource scan summaries
654
+ */
655
+ async listResourceScans() {
656
+ return this.cfn.listResourceScans();
657
+ }
658
+ /**
659
+ * Retrieves a tokenized list of resources from a resource scan. If a token is present, this function
660
+ * will loop through all pages and combine them into a single list of ScannedResource[].
661
+ * Additionally will apply any filters provided by the customer.
662
+ *
663
+ * @param scanId scan id for the to list resources for
664
+ * @param filters a string of filters in the format of key1=value1,key2=value2
665
+ * @returns a combined list of all resources from the scan
666
+ */
667
+ async listResourceScanResources(scanId, filters = []) {
668
+ var _a, _b, _c, _d;
669
+ let resourceList = [];
670
+ let resourceScanInputs;
671
+ if (filters.length > 0) {
672
+ (0, logging_1.info)('Applying filters to resource scan.');
673
+ for (const filter of filters) {
674
+ const filterList = parseFilters(filter);
675
+ resourceScanInputs = {
676
+ ResourceScanId: scanId,
677
+ ResourceIdentifier: filterList[FilterType.RESOURCE_IDENTIFIER],
678
+ ResourceTypePrefix: filterList[FilterType.RESOURCE_TYPE_PREFIX],
679
+ TagKey: filterList[FilterType.TAG_KEY],
680
+ TagValue: filterList[FilterType.TAG_VALUE],
681
+ };
682
+ const resources = await this.cfn.listResourceScanResources(resourceScanInputs);
683
+ resourceList = resourceList.concat((_a = resources.Resources) !== null && _a !== void 0 ? _a : []);
684
+ let nextToken = resources.NextToken;
685
+ // cycle through the pages adding all resources to the list until we run out of pages
686
+ while (nextToken) {
687
+ resourceScanInputs.NextToken = nextToken;
688
+ const nextResources = await this.cfn.listResourceScanResources(resourceScanInputs);
689
+ nextToken = nextResources.NextToken;
690
+ resourceList = resourceList.concat((_b = nextResources.Resources) !== null && _b !== void 0 ? _b : []);
691
+ }
692
+ }
693
+ }
694
+ else {
695
+ (0, logging_1.info)('No filters provided. Retrieving all resources from scan.');
696
+ resourceScanInputs = {
697
+ ResourceScanId: scanId,
698
+ };
699
+ const resources = await this.cfn.listResourceScanResources(resourceScanInputs);
700
+ resourceList = resourceList.concat((_c = resources.Resources) !== null && _c !== void 0 ? _c : []);
701
+ let nextToken = resources.NextToken;
702
+ // cycle through the pages adding all resources to the list until we run out of pages
703
+ while (nextToken) {
704
+ resourceScanInputs.NextToken = nextToken;
705
+ const nextResources = await this.cfn.listResourceScanResources(resourceScanInputs);
706
+ nextToken = nextResources.NextToken;
707
+ resourceList = resourceList.concat((_d = nextResources.Resources) !== null && _d !== void 0 ? _d : []);
708
+ }
709
+ }
710
+ if (resourceList.length === 0) {
711
+ throw new error_1.ToolkitError(`No resources found with filters ${filters.join(' ')}. Please try again with different filters.`);
712
+ }
713
+ resourceList = deduplicateResources(resourceList);
714
+ return process.env.MIGRATE_INTEG_TEST
715
+ ? resourceIdentifiers(resourceList)
716
+ : resourceIdentifiers(excludeManaged(resourceList));
717
+ }
718
+ /**
719
+ * Retrieves information about a resource scan.
720
+ *
721
+ * @param scanId scan id for the to list resources for
722
+ * @returns information about the scan
723
+ */
724
+ async describeResourceScan(scanId) {
725
+ return this.cfn.describeResourceScan({
726
+ ResourceScanId: scanId,
727
+ });
728
+ }
729
+ /**
730
+ * Describes the current status of the template being generated.
731
+ *
732
+ * @param templateId A string representing the template id
733
+ * @returns DescribeGeneratedTemplateOutput an object containing the template status and results
734
+ */
735
+ async describeGeneratedTemplate(templateId) {
736
+ const generatedTemplate = await this.cfn.describeGeneratedTemplate({
737
+ GeneratedTemplateName: templateId,
738
+ });
739
+ if (generatedTemplate.Status == ScanStatus.FAILED) {
740
+ throw new error_1.ToolkitError(generatedTemplate.StatusReason);
741
+ }
742
+ return generatedTemplate;
743
+ }
744
+ /**
745
+ * Retrieves a completed generated cloudformation template from the template generator.
746
+ *
747
+ * @param templateId A string representing the template id
748
+ * @param cloudFormation The CloudFormation sdk client to use
749
+ * @returns DescribeGeneratedTemplateOutput an object containing the template status and body
750
+ */
751
+ async getGeneratedTemplate(templateId) {
752
+ return this.cfn.getGeneratedTemplate({
753
+ GeneratedTemplateName: templateId,
754
+ });
755
+ }
756
+ /**
757
+ * Kicks off a template generation for a set of resources.
758
+ *
759
+ * @param stackName The name of the stack
760
+ * @param resources A list of resources to generate the template from
761
+ * @returns CreateGeneratedTemplateOutput an object containing the template arn to query on later
762
+ */
763
+ async createGeneratedTemplate(stackName, resources) {
764
+ const createTemplateOutput = await this.cfn.createGeneratedTemplate({
765
+ Resources: resources,
766
+ GeneratedTemplateName: stackName,
767
+ });
768
+ if (createTemplateOutput.GeneratedTemplateId === undefined) {
769
+ throw new error_1.ToolkitError('CreateGeneratedTemplate failed to return an Arn.');
770
+ }
771
+ return createTemplateOutput;
772
+ }
773
+ /**
774
+ * Deletes a generated template from the template generator.
775
+ *
776
+ * @param templateArn The arn of the template to delete
777
+ * @returns A promise that resolves when the template has been deleted
778
+ */
779
+ async deleteGeneratedTemplate(templateArn) {
780
+ await this.cfn.deleteGeneratedTemplate({
781
+ GeneratedTemplateName: templateArn,
782
+ });
783
+ }
784
+ }
785
+ exports.CfnTemplateGeneratorProvider = CfnTemplateGeneratorProvider;
786
+ /**
787
+ * The possible ways to choose a scan to generate a CDK application from
788
+ */
789
+ var FromScan;
790
+ (function (FromScan) {
791
+ /**
792
+ * Initiate a new resource scan to build the CDK application from.
793
+ */
794
+ FromScan[FromScan["NEW"] = 0] = "NEW";
795
+ /**
796
+ * Use the last successful scan to build the CDK application from. Will fail if no scan is found.
797
+ */
798
+ FromScan[FromScan["MOST_RECENT"] = 1] = "MOST_RECENT";
799
+ /**
800
+ * Starts a scan if none exists, otherwise uses the most recent successful scan to build the CDK application from.
801
+ */
802
+ FromScan[FromScan["DEFAULT"] = 2] = "DEFAULT";
803
+ })(FromScan || (exports.FromScan = FromScan = {}));
804
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWlncmF0ZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIm1pZ3JhdGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBdUNBLHdDQXVEQztBQVNELHNDQU9DO0FBUUQsb0NBV0M7QUFVRCxzQ0FlQztBQVNELDRDQXNDQztBQWdHRCx3QkFNQztBQVFELHdDQU1DO0FBd0NELGdEQWNDO0FBMENELDBDQWVDO0FBU0QsNEJBaUJDO0FBU0QsOEJBY0M7QUFRRCxrQ0FJQztBQVFELDBDQVFDO0FBU0Qsb0RBY0M7QUFRRCxnREFhQztBQVFELDBDQVNDO0FBU0Qsa0VBcUJDO0FBU0Qsd0NBSUM7QUFRRCx3REEwQkM7QUFub0JELDBEQUEwRDtBQUMxRCx1REFBdUQ7QUFDdkQseUJBQXlCO0FBQ3pCLDZCQUE2QjtBQUU3Qiw0Q0FBK0U7QUFhL0UsNkNBQTZDO0FBQzdDLCtCQUErQjtBQUMvQix5Q0FBeUM7QUFDekMsK0NBQXlDO0FBRXpDLG9EQUF5RDtBQUN6RCw0Q0FBZ0Q7QUFDaEQsNkNBQStDO0FBQy9DLE1BQU0sU0FBUyxHQUFHLE9BQU8sQ0FBQyxXQUFXLENBQUMsQ0FBQztBQUN2QyxNQUFNLFVBQVUsR0FBRyxPQUFPLENBQUMsWUFBWSxDQUFDLENBQUM7QUFDekMsMEVBQTBFO0FBQzFFLE1BQU0sMkJBQTJCLEdBQXNCLFlBQVksQ0FBQyxtQkFBbUIsRUFBRSxDQUFDO0FBRTFGOzs7Ozs7O0dBT0c7QUFDSSxLQUFLLFVBQVUsY0FBYyxDQUNsQyxTQUFpQixFQUNqQixLQUFhLEVBQ2IsUUFBZ0IsRUFDaEIsVUFBbUIsRUFDbkIsUUFBa0I7SUFFbEIsTUFBTSxrQkFBa0IsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLFVBQVUsYUFBVixVQUFVLGNBQVYsVUFBVSxHQUFJLE9BQU8sQ0FBQyxHQUFHLEVBQUUsRUFBRSxTQUFTLENBQUMsQ0FBQztJQUM3RSxNQUFNLGtCQUFrQixHQUFHLFVBQVUsQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUVqRCxJQUFJLENB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QUcsQ0FBQTtJQUVIOztPQUVHO0lBQ0gscURBQVcsQ0FBQTtJQUVYOztPQUVHO0lBQ0gsNkNBQU8sQ0FBQTtBQUNULENBQUMsRUFmVyxRQUFRLHdCQUFSLFFBQVEsUUFlbkIiLCJzb3VyY2VzQ29udGVudCI6WyIvKiBlc2xpbnQtZGlzYWJsZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tcmVxdWlyZS1pbXBvcnRzICovXG4vKiBlc2xpbnQtZGlzYWJsZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdmFyLXJlcXVpcmVzICovXG5pbXBvcnQgKiBhcyBmcyBmcm9tICdmcyc7XG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0IHR5cGUgeyBGb3JSZWFkaW5nIH0gZnJvbSAnQGF3cy1jZGsvY2xpLXBsdWdpbi1jb250cmFjdCc7XG5pbXBvcnQgeyBFbnZpcm9ubWVudCwgVU5LTk9XTl9BQ0NPVU5ULCBVTktOT1dOX1JFR0lPTiB9IGZyb20gJ0Bhd3MtY2RrL2N4LWFwaSc7XG5pbXBvcnQgdHlwZSB7XG4gIERlc2NyaWJlR2VuZXJhdGVkVGVtcGxhdGVDb21tYW5kT3V0cHV0LFxuICBEZXNjcmliZVJlc291cmNlU2NhbkNvbW1hbmRPdXRwdXQsXG4gIEdldEdlbmVyYXRlZFRlbXBsYXRlQ29tbWFuZE91dHB1dCxcbiAgTGlzdFJlc291cmNlU2NhblJlc291cmNlc0NvbW1hbmRJbnB1dCxcbiAgUmVzb3VyY2VEZWZpbml0aW9uLFxuICBSZXNvdXJjZURldGFpbCxcbiAgUmVzb3VyY2VJZGVudGlmaWVyU3VtbWFyeSxcbiAgUmVzb3VyY2VTY2FuU3VtbWFyeSxcbiAgU2Nhbm5lZFJlc291cmNlLFxuICBTY2FubmVkUmVzb3VyY2VJZGVudGlmaWVyLFxufSBmcm9tICdAYXdzLXNkay9jbGllbnQtY2xvdWRmb3JtYXRpb24nO1xuaW1wb3J0ICogYXMgY2RrX2Zyb21fY2ZuIGZyb20gJ2Nkay1mcm9tLWNmbic7XG5pbXBvcnQgKiBhcyBjaGFsayBmcm9tICdjaGFsayc7XG5pbXBvcnQgeyBjbGlJbml0IH0gZnJvbSAnLi4vLi4vbGliL2luaXQnO1xuaW1wb3J0IHsgaW5mbyB9IGZyb20gJy4uLy4uL2xpYi9sb2dnaW5nJztcbmltcG9ydCB0eXBlIHsgSUNsb3VkRm9ybWF0aW9uQ2xpZW50LCBTZGtQcm92aWRlciB9IGZyb20gJy4uL2FwaS9hd3MtYXV0aCc7XG5pbXBvcnQgeyBDbG91ZEZvcm1hdGlvblN0YWNrIH0gZnJvbSAnLi4vYXBpL2RlcGxveW1lbnRzJztcbmltcG9ydCB7IFRvb2xraXRFcnJvciB9IGZyb20gJy4uL3Rvb2xraXQvZXJyb3InO1xuaW1wb3J0IHsgemlwRGlyZWN0b3J5IH0gZnJvbSAnLi4vdXRpbC9hcmNoaXZlJztcbmNvbnN0IGNhbWVsQ2FzZSA9IHJlcXVpcmUoJ2NhbWVsY2FzZScpO1xuY29uc3QgZGVjYW1lbGl6ZSA9IHJlcXVpcmUoJ2RlY2FtZWxpemUnKTtcbi8qKiBUaGUgbGlzdCBvZiBsYW5ndWFnZXMgc3VwcG9ydGVkIGJ5IHRoZSBidWlsdC1pbiBub2N0aWx1Y2VudCBiaW5hcnkuICovXG5jb25zdCBNSUdSQVRFX1NVUFBPUlRFRF9MQU5HVUFHRVM6IHJlYWRvbmx5IHN0cmluZ1tdID0gY2RrX2Zyb21fY2ZuLnN1cHBvcnRlZF9sYW5ndWFnZXMoKTtcblxuLyoqXG4gKiBHZW5lcmF0ZXMgYSBDREsgYXBwIGZyb20gYSB5YW1sIG9yIGpzb24gdGVtcGxhdGUuXG4gKlxuICogQHBhcmFtIHN0YWNrTmFtZSBUaGUgbmFtZSB0byBhc3NpZ24gdG8gdGhlIHN0YWNrIGluIHRoZSBnZW5lcmF0ZWQgYXBwXG4gKiBAcGFyYW0gc3RhY2sgVGhlIHlhbWwgb3IganNvbiB0ZW1wbGF0ZSBmb3IgdGhlIHN0YWNrXG4gKiBAcGFyYW0gbGFuZ3VhZ2UgVGhlIGxhbmd1YWdlIHRvIGdlbmVyYXRlIHRoZSBDREsgYXBwIGluXG4gKiBAcGFyYW0gb3V0cHV0UGF0aCBUaGUgcGF0aCBhdCB3aGljaCB0byBnZW5lcmF0ZSB0aGUgQ0RLIGFwcFxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZ2VuZXJhdGVDZGtBcHAoXG4gIHN0YWNrTmFtZTogc3RyaW5nLFxuICBzdGFjazogc3RyaW5nLFxuICBsYW5ndWFnZTogc3RyaW5nLFxuICBvdXRwdXRQYXRoPzogc3RyaW5nLFxuICBjb21wcmVzcz86IGJvb2xlYW4sXG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3QgcmVzb2x2ZWRPdXRwdXRQYXRoID0gcGF0aC5qb2luKG91dHB1dFBhdGggPz8gcHJvY2Vzcy5jd2QoKSwgc3RhY2tOYW1lKTtcbiAgY29uc3QgZm9ybWF0dGVkU3RhY2tOYW1lID0gZGVjYW1lbGl6ZShzdGFja05hbWUpO1xuXG4gIHRyeSB7XG4gICAgZnMucm1TeW5jKHJlc29sdmVkT3V0cHV0UGF0aCwgeyByZWN1cnNpdmU6IHRydWUsIGZvcmNlOiB0cnVlIH0pO1xuICAgIGZzLm1rZGlyU3luYyhyZXNvbHZlZE91dHB1dFBhdGgsIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xuICAgIGNvbnN0IGdlbmVyYXRlT25seSA9IGNvbXByZXNzO1xuICAgIGF3YWl0IGNsaUluaXQoe1xuICAgICAgdHlwZTogJ2FwcCcsXG4gICAgICBsYW5ndWFnZSxcbiAgICAgIGNhblVzZU5ldHdvcms6IHRydWUsXG4gICAgICBnZW5lcmF0ZU9ubHksXG4gICAgICB3b3JrRGlyOiByZXNvbHZlZE91dHB1dFBhdGgsXG4gICAgICBzdGFja05hbWUsXG4gICAgICBtaWdyYXRlOiB0cnVlLFxuICAgIH0pO1xuXG4gICAgbGV0IHN0YWNrRmlsZU5hbWU6IHN0cmluZztcbiAgICBzd2l0Y2ggKGxhbmd1YWdlKSB7XG4gICAgICBjYXNlICd0eXBlc2NyaXB0JzpcbiAgICAgICAgc3RhY2tGaWxlTmFtZSA9IGAke3Jlc29sdmVkT3V0cHV0UGF0aH0vbGliLyR7Zm9ybWF0dGVkU3RhY2tOYW1lfS1zdGFjay50c2A7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAnamF2YSc6XG4gICAgICAgIHN0YWNrRmlsZU5hbWUgPSBgJHtyZXNvbHZlZE91dHB1dFBhdGh9L3NyYy9tYWluL2phdmEvY29tL215b3JnLyR7Y2FtZWxDYXNlKGZvcm1hdHRlZFN0YWNrTmFtZSwgeyBwYXNjYWxDYXNlOiB0cnVlIH0pfVN0YWNrLmphdmFgO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgJ3B5dGhvbic6XG4gICAgICAgIHN0YWNrRmlsZU5hbWUgPSBgJHtyZXNvbHZlZE91dHB1dFBhdGh9LyR7Zm9ybWF0dGVkU3RhY2tOYW1lLnJlcGxhY2UoLy0vZywgJ18nKX0vJHtmb3JtYXR0ZWRTdGFja05hbWUucmVwbGFjZSgvLS9nLCAnXycpfV9zdGFjay5weWA7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAnY3NoYXJwJzpcbiAgICAgICAgc3RhY2tGaWxlTmFtZSA9IGAke3Jlc29sdmVkT3V0cHV0UGF0aH0vc3JjLyR7Y2FtZWxDYXNlKGZvcm1hdHRlZFN0YWNrTmFtZSwgeyBwYXNjYWxDYXNlOiB0cnVlIH0pfS8ke2NhbWVsQ2FzZShmb3JtYXR0ZWRTdGFja05hbWUsIHsgcGFzY2FsQ2FzZTogdHJ1ZSB9KX1TdGFjay5jc2A7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAnZ28nOlxuICAgICAgICBzdGFja0ZpbGVOYW1lID0gYCR7cmVzb2x2ZWRPdXRwdXRQYXRofS8ke2Zvcm1hdHRlZFN0YWNrTmFtZX0uZ29gO1xuICAgICAgICBicmVhaztcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHRocm93IG5ldyBUb29sa2l0RXJyb3IoXG4gICAgICAgICAgYCR7bGFuZ3VhZ2V9IGlzIG5vdCBzdXBwb3J0ZWQgYnkgQ0RLIE1pZ3JhdGUuIFBsZWFzZSBjaG9vc2UgZnJvbTogJHtNSUdSQVRFX1NVUFBPUlRFRF9MQU5HVUFHRVMuam9pbignLCAnKX1gLFxuICAgICAgICApO1xuICAgIH1cbiAgICBmcy53cml0ZUZpbGVTeW5jKHN0YWNrRmlsZU5hbWUsIHN0YWNrKTtcbiAgICBpZiAoY29tcHJlc3MpIHtcbiAgICAgIGF3YWl0IHppcERpcmVjdG9yeShyZXNvbHZlZE91dHB1dFBhdGgsIGAke3Jlc29sdmVkT3V0cHV0UGF0aH0uemlwYCk7XG4gICAgICBmcy5ybVN5bmMocmVzb2x2ZWRPdXRwdXRQYXRoLCB7IHJlY3Vyc2l2ZTogdHJ1ZSwgZm9yY2U6IHRydWUgfSk7XG4gICAgfVxuICB9IGNhdGNoIChlcnJvcikge1xuICAgIGZzLnJtU3luYyhyZXNvbHZlZE91dHB1dFBhdGgsIHsgcmVjdXJzaXZlOiB0cnVlLCBmb3JjZTogdHJ1ZSB9KTtcbiAgICB0aHJvdyBlcnJvcjtcbiAgfVxufVxuXG4vKipcbiAqIEdlbmVyYXRlcyBhIENESyBzdGFjayBmaWxlLlxuICogQHBhcmFtIHRlbXBsYXRlIFRoZSB0ZW1wbGF0ZSB0byB0cmFuc2xhdGUgaW50byBhIENESyBzdGFja1xuICogQHBhcmFtIHN0YWNrTmFtZSBUaGUgbmFtZSB0byBhc3NpZ24gdG8gdGhlIHN0YWNrXG4gKiBAcGFyYW0gbGFuZ3VhZ2UgVGhlIGxhbmd1YWdlIHRvIGdlbmVyYXRlIHRoZSBzdGFjayBpblxuICogQHJldHVybnMgQSBzdHJpbmcgcmVwcmVzZW50YXRpb24gb2YgYSBDREsgc3RhY2sgZmlsZVxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2VuZXJhdGVTdGFjayh0ZW1wbGF0ZTogc3RyaW5nLCBzdGFja05hbWU6IHN0cmluZywgbGFuZ3VhZ2U6IHN0cmluZykge1xuICBjb25zdCBmb3JtYXR0ZWRTdGFja05hbWUgPSBgJHtjYW1lbENhc2UoZGVjYW1lbGl6ZShzdGFja05hbWUpLCB7IHBhc2NhbENhc2U6IHRydWUgfSl9U3RhY2tgO1xuICB0cnkge1xuICAgIHJldHVybiBjZGtfZnJvbV9jZm4udHJhbnNtdXRlKHRlbXBsYXRlLCBsYW5ndWFnZSwgZm9ybWF0dGVkU3RhY2tOYW1lKTtcbiAgfSBjYXRjaCAoZSkge1xuICAgIHRocm93IG5ldyBUb29sa2l0RXJyb3IoYCR7Zm9ybWF0dGVkU3RhY2tOYW1lfSBjb3VsZCBub3QgYmUgZ2VuZXJhdGVkIGJlY2F1c2UgJHsoZSBhcyBFcnJvcikubWVzc2FnZX1gKTtcbiAgfVxufVxuXG4vKipcbiAqIFJlYWRzIGFuZCByZXR1cm5zIGEgc3RhY2sgdGVtcGxhdGUgZnJvbSBhIGxvY2FsIHBhdGguXG4gKlxuICogQHBhcmFtIGlucHV0UGF0aCBUaGUgbG9jYXRpb24gb2YgdGhlIHRlbXBsYXRlXG4gKiBAcmV0dXJucyBBIHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiB0aGUgdGVtcGxhdGUgaWYgcHJlc2VudCwgb3RoZXJ3aXNlIHVuZGVmaW5lZFxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVhZEZyb21QYXRoKGlucHV0UGF0aDogc3RyaW5nKTogc3RyaW5nIHtcbiAgbGV0IHJlYWRGaWxlOiBzdHJpbmc7XG4gIHRyeSB7XG4gICAgcmVhZEZpbGUgPSBmcy5yZWFkRmlsZVN5bmMoaW5wdXRQYXRoLCAndXRmOCcpO1xuICB9IGNhdGNoIChlKSB7XG4gICAgdGhyb3cgbmV3IFRvb2xraXRFcnJvcihgJyR7aW5wdXRQYXRofScgaXMgbm90IGEgdmFsaWQgcGF0aC5gKTtcbiAgfVxuICBpZiAocmVhZEZpbGUgPT0gJycpIHtcbiAgICB0aHJvdyBuZXcgVG9vbGtpdEVycm9yKGBDbG91ZGZvcm1hdGlvbiB0ZW1wbGF0ZSBmaWxlcGF0aDogJyR7aW5wdXRQYXRofScgaXMgYW4gZW1wdHkgZmlsZS5gKTtcbiAgfVxuICByZXR1cm4gcmVhZEZpbGU7XG59XG5cbi8qKlxuICogUmVhZHMgYW5kIHJldHVybnMgYSBzdGFjayB0ZW1wbGF0ZSBmcm9tIGEgZGVwbG95ZWQgQ2xvdWRGb3JtYXRpb24gc3RhY2suXG4gKlxuICogQHBhcmFtIHN0YWNrTmFtZSBUaGUgbmFtZSBvZiB0aGUgc3RhY2tcbiAqIEBwYXJhbSBzZGtQcm92aWRlciBUaGUgc2RrIHByb3ZpZGVyIGZvciBtYWtpbmcgQ2xvdWRGb3JtYXRpb24gY2FsbHNcbiAqIEBwYXJhbSBlbnZpcm9ubWVudCBUaGUgYWNjb3VudCBhbmQgcmVnaW9uIHdoZXJlIHRoZSBzdGFjayBpcyBkZXBsb3llZFxuICogQHJldHVybnMgQSBzdHJpbmcgcmVwcmVzZW50YXRpb24gb2YgdGhlIHRlbXBsYXRlIGlmIHByZXNlbnQsIG90aGVyd2lzZSB1bmRlZmluZWRcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJlYWRGcm9tU3RhY2soXG4gIHN0YWNrTmFtZTogc3RyaW5nLFxuICBzZGtQcm92aWRlcjogU2RrUHJvdmlkZXIsXG4gIGVudmlyb25tZW50OiBFbnZpcm9ubWVudCxcbik6IFByb21pc2U8c3RyaW5nIHwgdW5kZWZpbmVkPiB7XG4gIGNvbnN0IGNsb3VkRm9ybWF0aW9uID0gKGF3YWl0IHNka1Byb3ZpZGVyLmZvckVudmlyb25tZW50KGVudmlyb25tZW50LCAwIHNhdGlzZmllcyBGb3JSZWFkaW5nKSkuc2RrLmNsb3VkRm9ybWF0aW9uKCk7XG5cbiAgY29uc3Qgc3RhY2sgPSBhd2FpdCBDbG91ZEZvcm1hdGlvblN0YWNrLmxvb2t1cChjbG91ZEZvcm1hdGlvbiwgc3RhY2tOYW1lLCB0cnVlKTtcbiAgaWYgKHN0YWNrLnN0YWNrU3RhdHVzLmlzRGVwbG95U3VjY2VzcyB8fCBzdGFjay5zdGFja1N0YXR1cy5pc1JvbGxiYWNrU3VjY2Vzcykge1xuICAgIHJldHVybiBKU09OLnN0cmluZ2lmeShhd2FpdCBzdGFjay50ZW1wbGF0ZSgpKTtcbiAgfSBlbHNlIHtcbiAgICB0aHJvdyBuZXcgVG9vbGtpdEVycm9yKFxuICAgICAgYFN0YWNrICcke3N0YWNrTmFtZX0nIGluIGFjY291bnQgJHtlbnZpcm9ubWVudC5hY2NvdW50fSBhbmQgcmVnaW9uICR7ZW52aXJvbm1lbnQucmVnaW9ufSBoYXMgYSBzdGF0dXMgb2YgJyR7c3RhY2suc3RhY2tTdGF0dXMubmFtZX0nIGR1ZSB0byAnJHtzdGFjay5zdGFja1N0YXR1cy5yZWFzb259Jy4gVGhlIHN0YWNrIGNhbm5vdCBiZSBtaWdyYXRlZCB1bnRpbCBpdCBpcyBpbiBhIGhlYWx0aHkgc3RhdGUuYCxcbiAgICApO1xuICB9XG59XG5cbi8qKlxuICogVGFrZXMgaW4gYSBzdGFjayBuYW1lIGFuZCBhY2NvdW50IGFuZCByZWdpb24gYW5kIHJldHVybnMgYSBnZW5lcmF0ZWQgY2xvdWRmb3JtYXRpb24gdGVtcGxhdGUgdXNpbmcgdGhlIGNsb3VkZm9ybWF0aW9uXG4gKiB0ZW1wbGF0ZSBnZW5lcmF0b3IuXG4gKlxuICogQHBhcmFtIEdlbmVyYXRlVGVtcGxhdGVPcHRpb25zIEFuIG9iamVjdCBjb250YWluaW5nIHRoZSBzdGFjayBuYW1lLCBmaWx0ZXJzLCBzZGtQcm92aWRlciwgZW52aXJvbm1lbnQsIGFuZCBuZXdTY2FuIGZsYWdcbiAqIEByZXR1cm5zIGEgZ2VuZXJhdGVkIGNsb3VkZm9ybWF0aW9uIHRlbXBsYXRlXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBnZW5lcmF0ZVRlbXBsYXRlKG9wdGlvbnM6IEdlbmVyYXRlVGVtcGxhdGVPcHRpb25zKTogUHJvbWlzZTxHZW5lcmF0ZVRlbXBsYXRlT3V0cHV0PiB7XG4gIGNvbnN0IGNmbiA9IG5ldyBDZm5UZW1wbGF0ZUdlbmVyYXRvclByb3ZpZGVyKGF3YWl0IGJ1aWxkQ2ZuQ2xpZW50KG9wdGlvbnMuc2RrUHJvdmlkZXIsIG9wdGlvbnMuZW52aXJvbm1lbnQpKTtcblxuICBjb25zdCBzY2FuSWQgPSBhd2FpdCBmaW5kTGFzdFN1Y2Nlc3NmdWxTY2FuKGNmbiwgb3B0aW9ucyk7XG5cbiAgLy8gaWYgYSBjdXN0b21lciBhY2NpZGVudGFsbHkgY3RybC1jJ3Mgb3V0IG9mIHRoZSBjb21tYW5kIGFuZCBydW5zIGl0IGFnYWluLCB0aGlzIHdpbGwgY29udGludWUgdGhlIHByb2dyZXNzIGJhciB3aGVyZSBpdCBsZWZ0IG9mZlxuICBjb25zdCBjdXJTY2FuID0gYXdhaXQgY2ZuLmRlc2NyaWJlUmVzb3VyY2VTY2FuKHNjYW5JZCk7XG4gIGlmIChjdXJTY2FuLlN0YXR1cyA9PSBTY2FuU3RhdHVzLklOX1BST0dSRVNTKSB7XG4gICAgaW5mbygnUmVzb3VyY2Ugc2NhbiBpbiBwcm9ncmVzcy4gUGxlYXNlIHdhaXQsIHRoaXMgY2FuIHRha2UgMTAgbWludXRlcyBvciBsb25nZXIuJyk7XG4gICAgYXdhaXQgc2NhblByb2dyZXNzQmFyKHNjYW5JZCwgY2ZuKTtcbiAgfVxuXG4gIGRpc3BsYXlUaW1lRGlmZihuZXcgRGF0ZSgpLCBuZXcgRGF0ZShjdXJTY2FuLlN0YXJ0VGltZSEpKTtcblxuICBsZXQgcmVzb3VyY2VzOiBTY2FubmVkUmVzb3VyY2VbXSA9IGF3YWl0IGNmbi5saXN0UmVzb3VyY2VTY2FuUmVzb3VyY2VzKHNjYW5JZCEsIG9wdGlvbnMuZmlsdGVycyk7XG5cbiAgaW5mbygnZmluZGluZyByZWxhdGVkIHJlc291cmNlcy4nKTtcbiAgbGV0IHJlbGF0ZWRSZXNvdXJjZXMgPSBhd2FpdCBjZm4uZ2V0UmVzb3VyY2VTY2FuUmVsYXRlZFJlc291cmNlcyhzY2FuSWQhLCByZXNvdXJjZXMpO1xuXG4gIGluZm8oYEZvdW5kICR7cmVsYXRlZFJlc291cmNlcy5sZW5ndGh9IHJlc291cmNlcy5gKTtcblxuICBpbmZvKCdHZW5lcmF0aW5nIENGTiB0ZW1wbGF0ZSBmcm9tIHNjYW5uZWQgcmVzb3VyY2VzLicpO1xuICBjb25zdCB0ZW1wbGF0ZUFybiA9IChhd2FpdCBjZm4uY3JlYXRlR2VuZXJhdGVkVGVtcGxhdGUob3B0aW9ucy5zdGFja05hbWUsIHJlbGF0ZWRSZXNvdXJjZXMpKS5HZW5lcmF0ZWRUZW1wbGF0ZUlkITtcblxuICBsZXQgZ2VuZXJhdGVkVGVtcGxhdGUgPSBhd2FpdCBjZm4uZGVzY3JpYmVHZW5lcmF0ZWRUZW1wbGF0ZSh0ZW1wbGF0ZUFybik7XG5cbiAgaW5mbygnUGxlYXNlIHdhaXQsIHRlbXBsYXRlIGNyZWF0aW9uIGluIHByb2dyZXNzLiBUaGlzIG1heSB0YWtlIGEgY291cGxlIG1pbnV0ZXMuJyk7XG4gIHdoaWxlIChnZW5lcmF0ZWRUZW1wbGF0ZS5TdGF0dXMgIT09IFNjYW5TdGF0dXMuQ09NUExFVEUgJiYgZ2VuZXJhdGVkVGVtcGxhdGUuU3RhdHVzICE9PSBTY2FuU3RhdHVzLkZBSUxFRCkge1xuICAgIGF3YWl0IHByaW50RG90cyhgWyR7Z2VuZXJhdGVkVGVtcGxhdGUuU3RhdHVzfV0gVGVtcGxhdGUgQ3JlYXRpb24gaW4gUHJvZ3Jlc3NgLCA0MDApO1xuICAgIGdlbmVyYXRlZFRlbXBsYXRlID0gYXdhaXQgY2ZuLmRlc2NyaWJlR2VuZXJhdGVkVGVtcGxhdGUodGVtcGxhdGVBcm4pO1xuICB9XG4gIGluZm8oJycpO1xuICBpbmZvKCdUZW1wbGF0ZSBzdWNjZXNzZnVsbHkgZ2VuZXJhdGVkIScpO1xuICByZXR1cm4gYnVpbGRHZW5lcnRlZFRlbXBsYXRlT3V0cHV0KFxuICAgIGdlbmVyYXRlZFRlbXBsYXRlLFxuICAgIChhd2FpdCBjZm4uZ2V0R2VuZXJhdGVkVGVtcGxhdGUodGVtcGxhdGVBcm4pKS5UZW1wbGF0ZUJvZHkhLFxuICAgIHRlbXBsYXRlQXJuLFxuICApO1xufVxuXG5hc3luYyBmdW5jdGlvbiBmaW5kTGFzdFN1Y2Nlc3NmdWxTY2FuKFxuICBjZm46IENmblRlbXBsYXRlR2VuZXJhdG9yUHJvdmlkZXIsXG4gIG9wdGlvbnM6IEdlbmVyYXRlVGVtcGxhdGVPcHRpb25zLFxuKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgbGV0IHJlc291cmNlU2NhblN1bW1hcmllczogUmVzb3VyY2VTY2FuU3VtbWFyeVtdIHwgdW5kZWZpbmVkID0gW107XG4gIGNvbnN0IGNsaWVudFJlcXVlc3RUb2tlbiA9IGBjZGstbWlncmF0ZS0ke29wdGlvbnMuZW52aXJvbm1lbnQuYWNjb3VudH0tJHtvcHRpb25zLmVudmlyb25tZW50LnJlZ2lvbn1gO1xuICBpZiAob3B0aW9ucy5mcm9tU2NhbiA9PT0gRnJvbVNjYW4uTkVXKSB7XG4gICAgaW5mbyhgU3RhcnRpbmcgbmV3IHNjYW4gZm9yIGFjY291bnQgJHtvcHRpb25zLmVudmlyb25tZW50LmFjY291bnR9IGluIHJlZ2lvbiAke29wdGlvbnMuZW52aXJvbm1lbnQucmVnaW9ufWApO1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCBjZm4uc3RhcnRSZXNvdXJjZVNjYW4oY2xpZW50UmVxdWVzdFRva2VuKTtcbiAgICAgIHJlc291cmNlU2NhblN1bW1hcmllcyA9IChhd2FpdCBjZm4ubGlzdFJlc291cmNlU2NhbnMoKSkuUmVzb3VyY2VTY2FuU3VtbWFyaWVzO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIC8vIGNvbnRpbnVpbmcgaGVyZSBiZWNhdXNlIGlmIHRoZSBzY2FuIGZhaWxzIG9uIGEgbmV3LXNjYW4gaXQgaXMgdmVyeSBsaWtlbHkgYmVjYXVzZSB0aGVyZSBpcyBlaXRoZXIgYWxyZWFkeSBhIHNjYW4gaW4gcHJvZ3Jlc3NcbiAgICAgIC8vIG9yIHRoZSBjdXN0b21lciBoaXQgYSByYXRlIGxpbWl0LiBJbiBlaXRoZXIgY2FzZSB3ZSB3YW50IHRvIGNvbnRpbnVlIHdpdGggdGhlIG1vc3QgcmVjZW50IHNjYW4uXG4gICAgICAvLyBJZiB0aGlzIGhhcHBlbnMgdG8gZmFpbCBmb3IgYSBjcmVkZW50aWFsIGVycm9yIHRoZW4gdGhhdCB3aWxsIGJlIGNhdWdodCBpbW1lZGlhdGVseSBhZnRlciBhbnl3YXkuXG4gICAgICBpbmZvKGBTY2FuIGZhaWxlZCB0byBzdGFydCBkdWUgdG8gZXJyb3IgJyR7KGUgYXMgRXJyb3IpLm1lc3NhZ2V9JywgZGVmYXVsdGluZyB0byBsYXRlc3Qgc2Nhbi5gKTtcbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgcmVzb3VyY2VTY2FuU3VtbWFyaWVzID0gKGF3YWl0IGNmbi5saXN0UmVzb3VyY2VTY2FucygpKS5SZXNvdXJjZVNjYW5TdW1tYXJpZXM7XG4gICAgYXdhaXQgY2ZuLmNoZWNrRm9yUmVzb3VyY2VTY2FuKHJlc291cmNlU2NhblN1bW1hcmllcywgb3B0aW9ucywgY2xpZW50UmVxdWVzdFRva2VuKTtcbiAgfVxuICAvLyBnZXQgdGhlIGxhdGVzdCBzY2FuLCB3aGljaCB3ZSBrbm93IHdpbGwgZXhpc3RcbiAgcmVzb3VyY2VTY2FuU3VtbWFyaWVzID0gKGF3YWl0IGNmbi5saXN0UmVzb3VyY2VTY2FucygpKS5SZXNvdXJjZVNjYW5TdW1tYXJpZXM7XG4gIGxldCBzY2FuSWQ6IHN0cmluZyB8IHVuZGVmaW5lZCA9IHJlc291cmNlU2NhblN1bW1hcmllcyFbMF0uUmVzb3VyY2VTY2FuSWQ7XG5cbiAgLy8gZmluZCB0aGUgbW9zdCByZWNlbnQgc2NhbiB0aGF0IGlzbid0IGluIGEgZmFpbGVkIHN0YXRlIGluIGNhc2Ugd2UgZGlkbid0IHN0YXJ0IGEgbmV3IG9uZVxuICBmb3IgKGNvbnN0IHN1bW1hcnkgb2YgcmVzb3VyY2VTY2FuU3VtbWFyaWVzISkge1xuICAgIGlmIChzdW1tYXJ5LlN0YXR1cyAhPT0gU2NhblN0YXR1cy5GQUlMRUQpIHtcbiAgICAgIHNjYW5JZCA9IHN1bW1hcnkuUmVzb3VyY2VTY2FuSWQhO1xuICAgICAgYnJlYWs7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHNjYW5JZCE7XG59XG5cbi8qKlxuICogVGFrZXMgYSBzdHJpbmcgb2YgZmlsdGVycyBpbiB0aGUgZm9ybWF0IG9mIGtleTE9dmFsdWUxLGtleTI9dmFsdWUyIGFuZCByZXR1cm5zIGEgbWFwIG9mIHRoZSBmaWx0ZXJzLlxuICpcbiAqIEBwYXJhbSBmaWx0ZXJzIGEgc3RyaW5nIG9mIGZpbHRlcnMgaW4gdGhlIGZvcm1hdCBvZiBrZXkxPXZhbHVlMSxrZXkyPXZhbHVlMlxuICogQHJldHVybnMgYSBtYXAgb2YgdGhlIGZpbHRlcnNcbiAqL1xuZnVuY3Rpb24gcGFyc2VGaWx0ZXJzKGZpbHRlcnM6IHN0cmluZyk6IHtcbiAgW2tleSBpbiBGaWx0ZXJUeXBlXTogc3RyaW5nIHwgdW5kZWZpbmVkO1xufSB7XG4gIGlmICghZmlsdGVycykge1xuICAgIHJldHVybiB7XG4gICAgICAncmVzb3VyY2UtaWRlbnRpZmllcic6IHVuZGVmaW5lZCxcbiAgICAgICdyZXNvdXJjZS10eXBlLXByZWZpeCc6IHVuZGVmaW5lZCxcbiAgICAgICd0YWcta2V5JzogdW5kZWZpbmVkLFxuICAgICAgJ3RhZy12YWx1ZSc6IHVuZGVmaW5lZCxcbiAgICB9O1xuICB9XG5cbiAgY29uc3QgZmlsdGVyU2hvcnRoYW5kczogeyBba2V5OiBzdHJpbmddOiBGaWx0ZXJUeXBlIH0gPSB7XG4gICAgJ2lkZW50aWZpZXInOiBGaWx0ZXJUeXBlLlJFU09VUkNFX0lERU5USUZJRVIsXG4gICAgJ2lkJzogRmlsdGVyVHlwZS5SRVNPVVJDRV9JREVOVElGSUVSLFxuICAgICd0eXBlJzogRmlsdGVyVHlwZS5SRVNPVVJDRV9UWVBFX1BSRUZJWCxcbiAgICAndHlwZS1wcmVmaXgnOiBGaWx0ZXJUeXBlLlJFU09VUkNFX1RZUEVfUFJFRklYLFxuICB9O1xuXG4gIGNvbnN0IGZpbHRlckxpc3QgPSBmaWx0ZXJzLnNwbGl0KCcsJyk7XG5cbiAgbGV0IGZpbHRlck1hcDogeyBba2V5IGluIEZpbHRlclR5cGVdOiBzdHJpbmcgfCB1bmRlZmluZWQgfSA9IHtcbiAgICBbRmlsdGVyVHlwZS5SRVNPVVJDRV9JREVOVElGSUVSXTogdW5kZWZpbmVkLFxuICAgIFtGaWx0ZXJUeXBlLlJFU09VUkNFX1RZUEVfUFJFRklYXTogdW5kZWZpbmVkLFxuICAgIFtGaWx0ZXJUeXBlLlRBR19LRVldOiB1bmRlZmluZWQsXG4gICAgW0ZpbHRlclR5cGUuVEFHX1ZBTFVFXTogdW5kZWZpbmVkLFxuICB9O1xuXG4gIGZvciAoY29uc3QgZmlsIG9mIGZpbHRlckxpc3QpIHtcbiAgICBjb25zdCBmaWx0ZXIgPSBmaWwuc3BsaXQoJz0nKTtcbiAgICBsZXQgZmlsdGVyS2V5ID0gZmlsdGVyWzBdO1xuICAgIGNvbnN0IGZpbHRlclZhbHVlID0gZmlsdGVyWzFdO1xuICAgIC8vIGlmIHRoZSBrZXkgaXMgYSBzaG9ydGhhbmQsIHJlcGxhY2UgaXQgd2l0aCB0aGUgZnVsbCBuYW1lXG4gICAgaWYgKGZpbHRlcktleSBpbiBmaWx0ZXJTaG9ydGhhbmRzKSB7XG4gICAgICBmaWx0ZXJLZXkgPSBmaWx0ZXJTaG9ydGhhbmRzW2ZpbHRlcktleV07XG4gICAgfVxuICAgIGlmIChPYmplY3QudmFsdWVzKEZpbHRlclR5cGUpLmluY2x1ZGVzKGZpbHRlcktleSBhcyBhbnkpKSB7XG4gICAgICBmaWx0ZXJNYXBbZmlsdGVyS2V5IGFzIGtleW9mIHR5cGVvZiBmaWx0ZXJNYXBdID0gZmlsdGVyVmFsdWU7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRocm93IG5ldyBUb29sa2l0RXJyb3IoYEludmFsaWQgZmlsdGVyOiAke2ZpbHRlcktleX1gKTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIGZpbHRlck1hcDtcbn1cblxuLyoqXG4gKiBUYWtlcyBhIGxpc3Qgb2YgYW55IHR5cGUgYW5kIGJyZWFrcyBpdCB1cCBpbnRvIGNodW5rcyBvZiBhIHNwZWNpZmllZCBzaXplLlxuICpcbiAqIEBwYXJhbSBsaXN0IFRoZSBsaXN0IHRvIGJyZWFrIHVwXG4gKiBAcGFyYW0gY2h1bmtTaXplIFRoZSBzaXplIG9mIGVhY2ggY2h1bmtcbiAqIEByZXR1cm5zIEEgbGlzdCBvZiBsaXN0cyBvZiB0aGUgc3BlY2lmaWVkIHNpemVcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNodW5rcyhsaXN0OiBhbnlbXSwgY2h1bmtTaXplOiBudW1iZXIpOiBhbnlbXVtdIHtcbiAgY29uc3QgY2h1bmtlZExpc3Q6IGFueVtdW10gPSBbXTtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBsaXN0Lmxlbmd0aDsgaSArPSBjaHVua1NpemUpIHtcbiAgICBjaHVua2VkTGlzdC5wdXNoKGxpc3Quc2xpY2UoaSwgaSArIGNodW5rU2l6ZSkpO1xuICB9XG4gIHJldHVybiBjaHVua2VkTGlzdDtcbn1cblxuLyoqXG4gKiBTZXRzIHRoZSBhY2NvdW50IGFuZCByZWdpb24gZm9yIG1ha2luZyBDbG91ZEZvcm1hdGlvbiBjYWxscy5cbiAqIEBwYXJhbSBhY2NvdW50IFRoZSBhY2NvdW50IHRvIHVzZVxuICogQHBhcmFtIHJlZ2lvbiBUaGUgcmVnaW9uIHRvIHVzZVxuICogQHJldHVybnMgVGhlIGVudmlyb25tZW50IG9iamVjdFxuICovXG5leHBvcnQgZnVuY3Rpb24gc2V0RW52aXJvbm1lbnQoYWNjb3VudD86IHN0cmluZywgcmVnaW9uPzogc3RyaW5nKTogRW52aXJvbm1lbnQge1xuICByZXR1cm4ge1xuICAgIGFjY291bnQ6IGFjY291bnQgPz8gVU5LTk9XTl9BQ0NPVU5ULFxuICAgIHJlZ2lvbjogcmVnaW9uID8/IFVOS05PV05fUkVHSU9OLFxuICAgIG5hbWU6ICdjZGstbWlncmF0ZS1lbnYnLFxuICB9O1xufVxuXG4vKipcbiAqIEVudW0gZm9yIHRoZSBzb3VyY2Ugb3B0aW9ucyBmb3IgdGhlIHRlbXBsYXRlXG4gKi9cbmV4cG9ydCBlbnVtIFRlbXBsYXRlU291cmNlT3B0aW9ucyB7XG4gIFBBVEggPSAncGF0aCcsXG4gIFNUQUNLID0gJ3N0YWNrJyxcbiAgU0NBTiA9ICdzY2FuJyxcbn1cblxuLyoqXG4gKiBBbiBvYmplY3QgcmVwcmVzZW50aW5nIHRoZSBzb3VyY2Ugb2YgYSB0ZW1wbGF0ZS5cbiAqL1xudHlwZSBUZW1wbGF0ZVNvdXJjZSA9XG4gIHwgeyBzb3VyY2U6IFRlbXBsYXRlU291cmNlT3B0aW9ucy5TQ0FOIH1cbiAgfCB7IHNvdXJjZTogVGVtcGxhdGVTb3VyY2VPcHRpb25zLlBBVEg7IHRlbXBsYXRlUGF0aDogc3RyaW5nIH1cbiAgfCB7IHNvdXJjZTogVGVtcGxhdGVTb3VyY2VPcHRpb25zLlNUQUNLOyBzdGFja05hbWU6IHN0cmluZyB9O1xuXG4vKipcbiAqIEVudW0gZm9yIHRoZSBzdGF0dXMgb2YgYSByZXNvdXJjZSBzY2FuXG4gKi9cbmV4cG9ydCBlbnVtIFNjYW5TdGF0dXMge1xuICBJTl9QUk9HUkVTUyA9ICdJTl9QUk9HUkVTUycsXG4gIENPTVBMRVRFID0gJ0NPTVBMRVRFJyxcbiAgRkFJTEVEID0gJ0ZBSUxFRCcsXG59XG5cbmV4cG9ydCBlbnVtIEZpbHRlclR5cGUge1xuICBSRVNPVVJDRV9JREVOVElGSUVSID0gJ3Jlc291cmNlLWlkZW50aWZpZXInLFxuICBSRVNPVVJDRV9UWVBFX1BSRUZJWCA9ICdyZXNvdXJjZS10eXBlLXByZWZpeCcsXG4gIFRBR19LRVkgPSAndGFnLWtleScsXG4gIFRBR19WQUxVRSA9ICd0YWctdmFsdWUnLFxufVxuXG4vKipcbiAqIFZhbGlkYXRlcyB0aGF0IGV4YWN0bHkgb25lIHNvdXJjZSBvcHRpb24gaGFzIGJlZW4gcHJvdmlkZWQuXG4gKiBAcGFyYW0gZnJvbVBhdGggVGhlIGNvbnRlbnQgb2YgdGhlIGZsYWcgYC0tZnJvbS1wYXRoYFxuICogQHBhcmFtIGZyb21TdGFjayB0aGUgY29udGVudCBvZiB0aGUgZmxhZyBgLS1mcm9tLXN0YWNrYFxuICovXG5leHBvcnQgZnVuY3Rpb24gcGFyc2VTb3VyY2VPcHRpb25zKGZyb21QYXRoPzogc3RyaW5nLCBmcm9tU3RhY2s/OiBib29sZWFuLCBzdGFja05hbWU/OiBzdHJpbmcpOiBUZW1wbGF0ZVNvdXJjZSB7XG4gIGlmIChmcm9tUGF0aCAmJiBmcm9tU3RhY2spIHtcbiAgICB0aHJvdyBuZXcgVG9vbGtpdEVycm9yKCdPbmx5IG9uZSBvZiBgLS1mcm9tLXBhdGhgIG9yIGAtLWZyb20tc3RhY2tgIG1heSBiZSBwcm92aWRlZC4nKTtcbiAgfVxuICBpZiAoIXN0YWNrTmFtZSkge1xuICAgIHRocm93IG5ldyBUb29sa2l0RXJyb3IoJ2AtLXN0YWNrLW5hbWVgIGlzIGEgcmVxdWlyZWQgZmllbGQuJyk7XG4gIH1cbiAgaWYgKCFmcm9tUGF0aCAmJiAhZnJvbVN0YWNrKSB7XG4gICAgcmV0dXJuIHsgc291cmNlOiBUZW1wbGF0ZVNvdXJjZU9wdGlvbnMuU0NBTiB9O1xuICB9XG4gIGlmIChmcm9tUGF0aCkge1xuICAgIHJldHVybiB7IHNvdXJjZTogVGVtcGxhdGVTb3VyY2VPcHRpb25zLlBBVEgsIHRlbXBsYXRlUGF0aDogZnJvbVBhdGggfTtcbiAgfVxuICByZXR1cm4geyBzb3VyY2U6IFRlbXBsYXRlU291cmNlT3B0aW9ucy5TVEFDSywgc3RhY2tOYW1lOiBzdGFja05hbWUhIH07XG59XG5cbi8qKlxuICogVGFrZXMgYSBzZXQgb2YgcmVzb3VyY2VzIGFuZCByZW1vdmVzIGFueSB3aXRoIHRoZSBtYW5hZ2VkYnlzdGFjayBmbGFnIHNldCB0byB0cnVlLlxuICpcbiAqIEBwYXJhbSByZXNvdXJjZUxpc3QgdGhlIGxpc3Qgb2YgcmVzb3VyY2VzIHByb3ZpZGVkIGJ5IHRoZSBsaXN0IHNjYW5uZWQgcmVzb3VyY2VzIGNhbGxzXG4gKiBAcmV0dXJucyBhIGxpc3Qgb2YgcmVzb3VyY2VzIG5vdCBtYW5hZ2VkIGJ5IGNmbiBzdGFja3NcbiAqL1xuZnVuY3Rpb24gZXhjbHVkZU1hbmFnZWQocmVzb3VyY2VMaXN0OiBTY2FubmVkUmVzb3VyY2VbXSk6IFNjYW5uZWRSZXNvdXJjZUlkZW50aWZpZXJbXSB7XG4gIHJldHVybiByZXNvdXJjZUxpc3RcbiAgICAuZmlsdGVyKChyKSA9PiAhci5NYW5hZ2VkQnlTdGFjaylcbiAgICAubWFwKChyKSA9PiAoe1xuICAgICAgUmVzb3VyY2VUeXBlOiByLlJlc291cmNlVHlwZSEsXG4gICAgICBSZXNvdXJjZUlkZW50aWZpZXI6IHIuUmVzb3VyY2VJZGVudGlmaWVyISxcbiAgICB9KSk7XG59XG5cbi8qKlxuICogVHJhbnNmb3JtcyBhIGxpc3Qgb2YgcmVzb3VyY2VzIGludG8gYSBsaXN0IG9mIHJlc291cmNlIGlkZW50aWZpZXJzIGJ5IHJlbW92aW5nIHRoZSBNYW5hZ2VkQnlTdGFjayBmbGFnLlxuICogU2V0dGluZyB0aGUgdmFsdWUgb2YgdGhlIGZpZWxkIHRvIHVuZGVmaW5lZCBlZmZlY3RpdmVseSByZW1vdmVzIGl0IGZyb20gdGhlIG9iamVjdC5cbiAqXG4gKiBAcGFyYW0gcmVzb3VyY2VMaXN0IHRoZSBsaXN0IG9mIHJlc291cmNlcyBwcm92aWRlZCBieSB0aGUgbGlzdCBzY2FubmVkIHJlc291cmNlcyBjYWxsc1xuICogQHJldHVybnMgYSBsaXN0IG9mIFNjYW5uZWRSZXNvdXJjZUlkZW50aWZpZXJbXVxuICovXG5mdW5jdGlvbiByZXNvdXJjZUlkZW50aWZpZXJzKHJlc291cmNlTGlzdDogU2Nhbm5lZFJlc291cmNlW10pOiBTY2FubmVkUmVzb3VyY2VJZGVudGlmaWVyW10ge1xuICBjb25zdCBpZGVudGlmaWVyczogU2Nhbm5lZFJlc291cmNlSWRlbnRpZmllcltdID0gW107XG4gIHJlc291cmNlTGlzdC5mb3JFYWNoKChyKSA9PiB7XG4gICAgY29uc3QgaWRlbnRpZmllcjogU2Nhbm5lZFJlc291cmNlSWRlbnRpZmllciA9IHtcbiAgICAgIFJlc291cmNlVHlwZTogci5SZXNvdXJjZVR5cGUhLFxuICAgICAgUmVzb3VyY2VJZGVudGlmaWVyOiByLlJlc291cmNlSWRlbnRpZmllciEsXG4gICAgfTtcbiAgICBpZGVudGlmaWVycy5wdXNoKGlkZW50aWZpZXIpO1xuICB9KTtcbiAgcmV0dXJuIGlkZW50aWZpZXJzO1xufVxuXG4vKipcbiAqIFRha2VzIGEgc2NhbiBpZCBhbmQgbWFpbnRhaW5zIGEgcHJvZ3Jlc3MgYmFyIHRvIGRpc3BsYXkgdGhlIHByb2dyZXNzIG9mIGEgc2NhbiB0byB0aGUgdXNlci5cbiAqXG4gKiBAcGFyYW0gc2NhbklkIEEgc3RyaW5nIHJlcHJlc2VudGluZyB0aGUgc2NhbiBpZFxuICogQHBhcmFtIGNsb3VkRm9ybWF0aW9uIFRoZSBDbG91ZEZvcm1hdGlvbiBzZGsgY2xpZW50IHRvIHVzZVxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc2NhblByb2dyZXNzQmFyKHNjYW5JZDogc3RyaW5nLCBjZm46IENmblRlbXBsYXRlR2VuZXJhdG9yUHJvdmlkZXIpIHtcbiAgbGV0IGN1clByb2dyZXNzID0gMC41O1xuICAvLyB3ZSBrbm93IGl0J3MgaW4gcHJvZ3Jlc3MgaW5pdGlhbGx5IHNpbmNlIHdlIHdvdWxkbid0IGhhdmUgZ290dGVuIGhlcmUgaWYgaXQgd2Fzbid0XG4gIGxldCBjdXJTY2FuOiBEZXNjcmliZVJlc291cmNlU2NhbkNvbW1hbmRPdXRwdXQgPSB7XG4gICAgU3RhdHVzOiBTY2FuU3RhdHVzLklOX1BST0dSRVNTLFxuICAgICRtZXRhZGF0YToge30sXG4gIH07XG4gIHdoaWxlIChjdXJTY2FuLlN0YXR1cyA9PSBTY2FuU3RhdHVzLklOX1BST0dSRVNTKSB7XG4gICAgY3VyU2NhbiA9IGF3YWl0IGNmbi5kZXNjcmliZVJlc291cmNlU2NhbihzY2FuSWQpO1xuICAgIGN1clByb2dyZXNzID0gY3VyU2Nhbi5QZXJjZW50YWdlQ29tcGxldGVkID8/IGN1clByb2dyZXNzO1xuICAgIHByaW50QmFyKDMwLCBjdXJQcm9ncmVzcyk7XG4gICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHNldFRpbWVvdXQocmVzb2x2ZSwgMjAwMCkpO1xuICB9XG4gIGluZm8oJycpO1xuICBpbmZvKCfinIUgU2NhbiBDb21wbGV0ZSEnKTtcbn1cblxuLyoqXG4gKiBQcmludHMgYSBwcm9ncmVzcyBiYXIgdG8gdGhlIGNvbnNvbGUuIFRvIGJlIHVzZWQgaW4gYSB3aGlsZSBsb29wIHRvIHNob3cgcHJvZ3Jlc3Mgb2YgYSBsb25nIHJ1bm5pbmcgdGFzay5cbiAqIFRoZSBwcm9ncmVzcyBiYXIgZGVsZXRlcyB0aGUgY3VycmVudCBsaW5lIG9uIHRoZSBjb25zb2xlIGFuZCByZXdyaXRlcyBpdCB3aXRoIHRoZSBwcm9ncmVzcyBhbW91bnQuXG4gKlxuICogQHBhcmFtIHdpZHRoIFRoZSB3aWR0aCBvZiB0aGUgcHJvZ3Jlc3MgYmFyXG4gKiBAcGFyYW0gcHJvZ3Jlc3MgVGhlIGN1cnJlbnQgcHJvZ3Jlc3MgdG8gZGlzcGxheSBhcyBhIHBlcmNlbnRhZ2Ugb2YgMTAwXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwcmludEJhcih3aWR0aDogbnVtYmVyLCBwcm9ncmVzczogbnVtYmVyKSB7XG4gIGlmICghcHJvY2Vzcy5lbnYuTUlHUkFURV9JTlRFR19URVNUKSB7XG4gICAgY29uc3QgRlVMTF9CTE9DSyA9ICfilognO1xuICAgIGNvbnN0IFBBUlRJQUxfQkxPQ0sgPSBbJycsICfilo8nLCAn4paOJywgJ+KWjScsICfilownLCAn4paLJywgJ+KWiicsICfiloknXTtcbiAgICBjb25zdCBmcmFjdGlvbiA9IE1hdGgubWluKHByb2dyZXNzIC8gMTAwLCAxKTtcbiAgICBjb25zdCBpbm5lcldpZHRoID0gTWF0aC5tYXgoMSwgd2lkdGggLSAyKTtcbiAgICBjb25zdCBjaGFycyA9IGlubmVyV2lkdGggKiBmcmFjdGlvbjtcbiAgICBjb25zdCByZW1haW5kZXIgPSBjaGFycyAtIE1hdGguZmxvb3IoY2hhcnMpO1xuXG4gICAgY29uc3QgZnVsbENoYXJzID0gRlVMTF9CTE9DSy5yZXBlYXQoTWF0aC5mbG9vcihjaGFycykpO1xuICAgIGNvbnN0IHBhcnRpYWxDaGFyID0gUEFSVElBTF9CTE9DS1tNYXRoLmZsb29yKHJlbWFpbmRlciAqIFBBUlRJQUxfQkxPQ0subGVuZ3RoKV07XG4gICAgY29uc3QgZmlsbGVyID0gJ8K3Jy5yZXBlYXQoaW5uZXJXaWR0aCAtIE1hdGguZmxvb3IoY2hhcnMpIC0gKHBhcnRpYWxDaGFyID8gMSA6IDApKTtcblxuICAgIGNvbnN0IGNvbG9yID0gY2hhbGsuZ3JlZW47XG5cbiAgICByZXdyaXRlTGluZSgnWycgKyBjb2xvcihmdWxsQ2hhcnMgKyBwYXJ0aWFsQ2hhcikgKyBmaWxsZXIgKyBgXSAoJHtwcm9ncmVzc30lKWApO1xuICB9XG59XG5cbi8qKlxuICogUHJpbnRzIGEgbWVzc2FnZSB0byB0aGUgY29uc29sZSB3aXRoIGEgc2VyaWVzIHBlcmlvZHMgYXBwZW5kZWQgdG8gaXQuIFRvIGJlIHVzZWQgaW4gYSB3aGlsZSBsb29wIHRvIHNob3cgcHJvZ3Jlc3Mgb2YgYSBsb25nIHJ1bm5pbmcgdGFzay5cbiAqIFRoZSBtZXNzYWdlIGRlbGV0ZXMgdGhlIGN1cnJlbnQgbGluZSBhbmQgcmV3cml0ZXMgaXQgc2V2ZXJhbCB0aW1lcyB0byBkaXNwbGF5IDEtMyBwZXJpb2RzIHRvIHNob3cgdGhlIHVzZXIgdGhhdCB0aGUgdGFzayBpcyBzdGlsbCBydW5uaW5nLlxuICpcbiAqIEBwYXJhbSBtZXNzYWdlIFRoZSBtZXNzYWdlIHRvIGRpc3BsYXlcbiAqIEBwYXJhbSB0aW1lb3V0eDQgVGhlIGFtb3VudCBvZiB0aW1lIHRvIHdhaXQgYmVmb3JlIHByaW50aW5nIHRoZSBuZXh0IHBlcmlvZFxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcHJpbnREb3RzKG1lc3NhZ2U6IHN0cmluZywgdGltZW91dHg0OiBudW1iZXIpIHtcbiAgaWYgKCFwcm9jZXNzLmVudi5NSUdSQVRFX0lOVEVHX1RFU1QpIHtcbiAgICByZXdyaXRlTGluZShtZXNzYWdlICsgJyAuJyk7XG4gICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHNldFRpbWVvdXQocmVzb2x2ZSwgdGltZW91dHg0KSk7XG5cbiAgICByZXdyaXRlTGluZShtZXNzYWdlICsgJyAuLicpO1xuICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiBzZXRUaW1lb3V0KHJlc29sdmUsIHRpbWVvdXR4NCkpO1xuXG4gICAgcmV3cml0ZUxpbmUobWVzc2FnZSArICcgLi4uJyk7XG4gICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHNldFRpbWVvdXQocmVzb2x2ZSwgdGltZW91dHg0KSk7XG5cbiAgICByZXdyaXRlTGluZShtZXNzYWdlKTtcbiAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4gc2V0VGltZW91dChyZXNvbHZlLCB0aW1lb3V0eDQpKTtcbiAgfVxufVxuXG4vKipcbiAqIFJld3JpdGVzIHRoZSBjdXJyZW50IGxpbmUgb24gdGhlIGNvbnNvbGUgYW5kIHdyaXRlcyBhIG5ldyBtZXNzYWdlIHRvIGl0LlxuICogVGhpcyBpcyBhIGhlbHBlciBmdW5jaXRvbiBmb3IgcHJpbnREb3RzIGFuZCBwcmludEJhci5cbiAqXG4gKiBAcGFyYW0gbWVzc2FnZSBUaGUgbWVzc2FnZSB0byBkaXNwbGF5XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXdyaXRlTGluZShtZXNzYWdlOiBzdHJpbmcpIHtcbiAgcHJvY2Vzcy5zdGRvdXQuY2xlYXJMaW5lKDApO1xuICBwcm9jZXNzLnN0ZG91dC5jdXJzb3JUbygwKTtcbiAgcHJvY2Vzcy5zdGRvdXQud3JpdGUobWVzc2FnZSk7XG59XG5cbi8qKlxuICogUHJpbnRzIHRoZSB0aW1lIGRpZmZlcmVuY2UgYmV0d2VlbiB0d28gZGF0ZXMgaW4gZGF5cywgaG91cnMsIGFuZCBtaW51dGVzLlxuICpcbiAqIEBwYXJhbSB0aW1lMSBUaGUgZmlyc3QgZGF0ZSB0byBjb21wYXJlXG4gKiBAcGFyYW0gdGltZTIgVGhlIHNlY29uZCBkYXRlIHRvIGNvbXBhcmVcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGRpc3BsYXlUaW1lRGlmZih0aW1lMTogRGF0ZSwgdGltZTI6IERhdGUpOiB2b2lkIHtcbiAgY29uc3QgZGlmZiA9IE1hdGguYWJzKHRpbWUxLmdldFRpbWUoKSAtIHRpbWUyLmdldFRpbWUoKSk7XG5cbiAgY29uc3QgZGF5cyA9IE1hdGguZmxvb3IoZGlmZiAvICgxMDAwICogNjAgKiA2MCAqIDI0KSk7XG4gIGNvbnN0IGhvdXJzID0gTWF0aC5mbG9vcigoZGlmZiAlICgxMDAwICogNjAgKiA2MCAqIDI0KSkgLyAoMTAwMCAqIDYwICogNjApKTtcbiAgY29uc3QgbWludXRlcyA9IE1hdGguZmxvb3IoKGRpZmYgJSAoMTAwMCAqIDYwICogNjApKSAvICgxMDAwICogNjApKTtcblxuICBpbmZvKGBVc2luZyB0aGUgbGF0ZXN0IHN1Y2Nlc3NmdWwgc2NhbiB3aGljaCBpcyAke2RheXN9IGRheXMsICR7aG91cnN9IGhvdXJzLCBhbmQgJHttaW51dGVzfSBtaW51dGVzIG9sZC5gKTtcbn1cblxuLyoqXG4gKiBXcml0ZXMgYSBtaWdyYXRlLmpzb24gZmlsZSB0byB0aGUgb3V0cHV0IGRpcmVjdG9yeS5cbiAqXG4gKiBAcGFyYW0gb3V0cHV0UGF0aCBUaGUgcGF0aCB0byB3cml0ZSB0aGUgbWlncmF0ZS5qc29uIGZpbGUgdG9cbiAqIEBwYXJhbSBzdGFja05hbWUgVGhlIG5hbWUgb2YgdGhlIHN0YWNrXG4gKiBAcGFyYW0gZ2VuZXJhdGVkT3V0cHV0IFRoZSBvdXRwdXQgb2YgdGhlIHRlbXBsYXRlIGdlbmVyYXRvclxuICovXG5leHBvcnQgZnVuY3Rpb24gd3JpdGVNaWdyYXRlSnNvbkZpbGUoXG4gIG91dHB1dFBhdGg6IHN0cmluZyB8IHVuZGVmaW5lZCxcbiAgc3RhY2tOYW1lOiBzdHJpbmcsXG4gIG1pZ3JhdGVKc29uOiBNaWdyYXRlSnNvbkZvcm1hdCxcbikge1xuICBjb25zdCBvdXRwdXRUb0pzb24gPSB7XG4gICAgJy8vJzogJ1RoaXMgZmlsZSBpcyBnZW5lcmF0ZWQgYnkgY2RrIG1pZ3JhdGUuIEl0IHdpbGwgYmUgYXV0b21hdGljYWxseSBkZWxldGVkIGFmdGVyIHRoZSBmaXJzdCBzdWNjZXNzZnVsIGRlcGxveW1lbnQgb2YgdGhpcyBhcHAgdG8gdGhlIGVudmlyb25tZW50IG9mIHRoZSBvcmlnaW5hbCByZXNvdXJjZXMuJyxcbiAgICAnU291cmNlJzogbWlncmF0ZUpzb24uc291cmNlLFxuICAgICdSZXNvdXJjZXMnOiBtaWdyYXRlSnNvbi5yZXNvdXJjZXMsXG4gIH07XG4gIGZzLndyaXRlRmlsZVN5bmMoXG4gICAgYCR7cGF0aC5qb2luKG91dHB1dFBhdGggPz8gcHJvY2Vzcy5jd2QoKSwgc3RhY2tOYW1lKX0vbWlncmF0ZS5qc29uYCxcbiAgICBKU09OLnN0cmluZ2lmeShvdXRwdXRUb0pzb24sIG51bGwsIDIpLFxuICApO1xufVxuXG4vKipcbiAqIFRha2VzIGEgc3RyaW5nIHJlcHJlc2VudGluZyB0aGUgZnJvbS1zY2FuIGZsYWcgYW5kIHJldHVybnMgYSBGcm9tU2NhbiBlbnVtIHZhbHVlLlxuICpcbiAqIEBwYXJhbSBzY2FuVHlwZSBBIHN0cmluZyByZXByZXNlbnRpbmcgdGhlIGZyb20tc2NhbiBmbGFnXG4gKiBAcmV0dXJucyBBIEZyb21TY2FuIGVudW0gdmFsdWVcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldE1pZ3JhdGVTY2FuVHlwZShzY2FuVHlwZTogc3RyaW5nKSB7XG4gIHN3aXRjaCAoc2NhblR5cGUpIHtcbiAgICBjYXNlICduZXcnOlxuICAgICAgcmV0dXJuIEZyb21TY2FuLk5FVztcbiAgICBjYXNlICdtb3N0LXJlY2VudCc6XG4gICAgICByZXR1cm4gRnJvbVNjYW4uTU9TVF9SRUNFTlQ7XG4gICAgY2FzZSAnJzpcbiAgICAgIHJldHVybiBGcm9tU2Nhbi5ERUZBVUxUO1xuICAgIGNhc2UgdW5kZWZpbmVkOlxuICAgICAgcmV0dXJuIEZyb21TY2FuLkRFRkFVTFQ7XG4gICAgZGVmYXVsdDpcbiAgICAgIHRocm93IG5ldyBUb29sa2l0RXJyb3IoYFVua25vd24gc2NhbiB0eXBlOiAke3NjYW5UeXBlfWApO1xuICB9XG59XG5cbi8qKlxuICogVGFrZXMgYSBnZW5lcmF0ZWRUZW1wbGF0ZU91dHB1dCBvYmpjdCBhbmQgcmV0dXJucyBhIGJvb2xlYW4gcmVwcmVzZW50aW5nIHdoZXRoZXIgdGhlcmUgYXJlIGFueSB3YXJuaW5ncyBvbiBhbnkgcmVzY291cmNlcy5cbiAqXG4gKiBAcGFyYW0gZ2VuZXJhdGVkVGVtcGxhdGVPdXRwdXQgQSBHZW5lcmF0ZVRlbXBsYXRlT3V0cHV0IG9iamVjdFxuICogQHJldHVybnMgQSBib29sZWFuIHJlcHJlc2VudGluZyB3aGV0aGVyIHRoZXJlIGFyZSBhbnkgd2FybmluZ3Mgb24gYW55IHJlc2NvdXJjZXNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzVGhlcmVBV2FybmluZyhnZW5lcmF0ZWRUZW1wbGF0ZU91dHB1dDogR2VuZXJhdGVUZW1wbGF0ZU91dHB1dCkge1xuICBpZiAoZ2VuZXJhdGVkVGVtcGxhdGVPdXRwdXQucmVzb3VyY2VzKSB7XG4gICAgZm9yIChjb25zdCByZXNvdXJjZSBvZiBnZW5lcmF0ZWRUZW1wbGF0ZU91dHB1dC5yZXNvdXJjZXMpIHtcbiAgICAgIGlmIChyZXNvdXJjZS5XYXJuaW5ncyAmJiByZXNvdXJjZS5XYXJuaW5ncy5sZW5ndGggPiAwKSB7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgfVxuICAgIH1cbiAgfVxuICByZXR1cm4gZmFsc2U7XG59XG5cbi8qKlxuICogQnVpbGRzIHRoZSBHZW5lcmF0ZVRlbXBsYXRlT3V0cHV0IG9iamVjdCBmcm9tIHRoZSBEZXNjcmliZUdlbmVyYXRlZFRlbXBsYXRlT3V0cHV0IGFuZCB0aGUgdGVtcGxhdGUgYm9keS5cbiAqXG4gKiBAcGFyYW0gZ2VuZXJhdGVkVGVtcGxhdGVTdW1tYXJ5IFRoZSBvdXRwdXQgb2YgdGhlIGRlc2NyaWJlIGdlbmVyYXRlZCB0ZW1wbGF0ZSBjYWxsXG4gKiBAcGFyYW0gdGVtcGxhdGVCb2R5IFRoZSBib2R5IG9mIHRoZSBnZW5lcmF0ZWQgdGVtcGxhdGVcbiAqIEByZXR1cm5zIEEgR2VuZXJhdGVUZW1wbGF0ZU91dHB1dCBvYmplY3RcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGJ1aWxkR2VuZXJ0ZWRUZW1wbGF0ZU91dHB1dChcbiAgZ2VuZXJhdGVkVGVtcGxhdGVTdW1tYXJ5OiBEZXNjcmliZUdlbmVyYXRlZFRlbXBsYXRlQ29tbWFuZE91dHB1dCxcbiAgdGVtcGxhdGVCb2R5OiBzdHJpbmcsXG4gIHNvdXJjZTogc3RyaW5nLFxuKTogR2VuZXJhdGVUZW1wbGF0ZU91dHB1dCB7XG4gIGNvbnN0IHJlc291cmNlczogUmVzb3VyY2VEZXRhaWxbXSB8IHVuZGVmaW5lZCA9IGdlbmVyYXRlZFRlbXBsYXRlU3VtbWFyeS5SZXNvdXJjZXM7XG4gIGNvbnN0IG1pZ3JhdGVKc29uOiBNaWdyYXRlSnNvbkZvcm1hdCA9IHtcbiAgICB0ZW1wbGF0ZUJvZHk6IHRlbXBsYXRlQm9keSxcbiAgICBzb3VyY2U6IHNvdXJjZSxcbiAgICByZXNvdXJjZXM6IGdlbmVyYXRlZFRlbXBsYXRlU3VtbWFyeS5SZXNvdXJjZXMhLm1hcCgocikgPT4gKHtcbiAgICAgIFJlc291cmNlVHlwZTogci5SZXNvdXJjZVR5cGUhLFxuICAgICAgTG9naWNhbFJlc291cmNlSWQ6IHIuTG9naWNhbFJlc291cmNlSWQhLFxuICAgICAgUmVzb3VyY2VJZGVudGlmaWVyOiByLlJlc291cmNlSWRlbnRpZmllciEsXG4gICAgfSkpLFxuICB9O1xuICBjb25zdCB0ZW1wbGF0ZUlkID0gZ2VuZXJhdGVkVGVtcGxhdGVTdW1tYXJ5LkdlbmVyYXRlZFRlbXBsYXRlSWQhO1xuICByZXR1cm4ge1xuICAgIG1pZ3JhdGVKc29uOiBtaWdyYXRlSnNvbixcbiAgICByZXNvdXJjZXM6IHJlc291cmNlcyxcbiAgICB0ZW1wbGF0ZUlkOiB0ZW1wbGF0ZUlkLFxuICB9O1xufVxuXG4vKipcbiAqIEJ1aWxkcyBhIENsb3VkRm9ybWF0aW9uIHNkayBjbGllbnQgZm9yIG1ha2luZyByZXF1ZXN0cyB3aXRoIHRoZSBDRk4gdGVtcGxhdGUgZ2VuZXJhdG9yLlxuICpcbiAqIEBwYXJhbSBzZGtQcm92aWRlciBUaGUgc2RrIHByb3ZpZGVyIGZvciBtYWtpbmcgQ2xvdWRGb3JtYXRpb24gY2FsbHNcbiAqIEBwYXJhbSBlbnZpcm9ubWVudCBUaGUgYWNjb3VudCBhbmQgcmVnaW9uIHdoZXJlIHRoZSBzdGFjayBpcyBkZXBsb3llZFxuICogQHJldHVybnMgQSBDbG91ZEZvcm1hdGlvbiBzZGsgY2xpZW50XG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBidWlsZENmbkNsaWVudChzZGtQcm92aWRlcjogU2RrUHJvdmlkZXIsIGVudmlyb25tZW50OiBFbnZpcm9ubWVudCkge1xuICBjb25zdCBzZGsgPSAoYXdhaXQgc2RrUHJvdmlkZXIuZm9yRW52aXJvbm1lbnQoZW52aXJvbm1lbnQsIDAgc2F0aXNmaWVzIEZvclJlYWRpbmcpKS5zZGs7XG4gIHNkay5hcHBlbmRDdXN0b21Vc2VyQWdlbnQoJ2Nkay1taWdyYXRlJyk7XG4gIHJldHVybiBzZGsuY2xvdWRGb3JtYXRpb24oKTtcbn1cblxuLyoqXG4gKiBBcHBlbmRzIGEgbGlzdCBvZiB3YXJuaW5ncyB0byBhIHJlYWRtZSBmaWxlLlxuICpcbiAqIEBwYXJhbSBmaWxlcGF0aCBUaGUgcGF0aCB0byB0aGUgcmVhZG1lIGZpbGVcbiAqIEBwYXJhbSByZXNvdXJjZXMgQSBsaXN0IG9mIHJlc291cmNlcyB0byBhcHBlbmQgd2FybmluZ3MgZm9yXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBhcHBlbmRXYXJuaW5nc1RvUmVhZG1lKGZpbGVwYXRoOiBzdHJpbmcsIHJlc291cmNlczogUmVzb3VyY2VEZXRhaWxbXSkge1xuICBjb25zdCByZWFkbWUgPSBmcy5yZWFkRmlsZVN5bmMoZmlsZXBhdGgsICd1dGY4Jyk7XG4gIGNvbnN0IGxpbmVzID0gcmVhZG1lLnNwbGl0KCdcXG4nKTtcbiAgY29uc3QgaW5kZXggPSBsaW5lcy5maW5kSW5kZXgoKGxpbmUpID0+IGxpbmUudHJpbSgpID09PSAnRW5qb3khJyk7XG4gIGxldCBsaW5lc1RvQWRkID0gWydcXG4jIyBXYXJuaW5ncyddO1xuICBsaW5lc1RvQWRkLnB1c2goJyMjIyBXcml0ZS1vbmx5IHByb3BlcnRpZXMnKTtcbiAgbGluZXNUb0FkZC5wdXNoKFxuICAgIFwiV3JpdGUtb25seSBwcm9wZXJ0aWVzIGFyZSByZXNvdXJjZSBwcm9wZXJ0eSB2YWx1ZXMgdGhhdCBjYW4gYmUgd3JpdHRlbiB0byBidXQgY2FuJ3QgYmUgcmVhZCBieSBBV1MgQ2xvdWRGb3JtYXRpb24gb3IgQ0RLIE1pZ3JhdGUuIEZvciBtb3JlIGluZm9ybWF0aW9uLCBzZWUgW0lhQyBnZW5lcmF0b3IgYW5kIHdyaXRlLW9ubHkgcHJvcGVydGllc10oaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL0FXU0Nsb3VkRm9ybWF0aW9uL2xhdGVzdC9Vc2VyR3VpZGUvZ2VuZXJhdGUtSWFDLXdyaXRlLW9ubHktcHJvcGVydGllcy5odG1sKS5cIixcbiAgKTtcbiAgbGluZXNUb0FkZC5wdXNoKCdcXG4nKTtcbiAgbGluZXNUb0FkZC5wdXNoKFxuICAgICdXcml0ZS1vbmx5IHByb3BlcnRpZXMgZGlzY292ZXJlZCBkdXJpbmcgbWlncmF0aW9uIGFyZSBvcmdhbml6ZWQgaGVyZSBieSByZXNvdXJjZSBJRCBhbmQgY2F0ZWdvcml6ZWQgYnkgd3JpdGUtb25seSBwcm9wZXJ0eSB0eXBlLiBSZXNvbHZlIHdyaXRlLW9ubHkgcHJvcGVydGllcyBieSBwcm92aWRpbmcgcHJvcGVydHkgdmFsdWVzIGluIHlvdXIgQ0RLIGFwcC4gRm9yIGd1aWRhbmNlLCBzZWUgW1Jlc29sdmUgd3JpdGUtb25seSBwcm9wZXJ0aWVzXShodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vY2RrL3YyL2d1aWRlL21pZ3JhdGUuaHRtbCNtaWdyYXRlLXJlc291cmNlcy13cml0ZW9ubHkpLicsXG4gICk7XG4gIGZvciAoY29uc3QgcmVzb3VyY2Ugb2YgcmVzb3VyY2VzKSB7XG4gICAgaWYgKHJlc291cmNlLldhcm5pbmdzICYmIHJlc291cmNlLldhcm5pbmdzLmxlbmd0aCA+IDApIHtcbiAgICAgIGxpbmVzVG9BZGQucHVzaChgIyMjICR7cmVzb3VyY2UuTG9naWNhbFJlc291cmNlSWR9YCk7XG4gICAgICBmb3IgKGNvbnN0IHdhcm5pbmcgb2YgcmVzb3VyY2UuV2FybmluZ3MpIHtcbiAgICAgICAgbGluZXNUb0FkZC5wdXNoKGAtICoqJHt3YXJuaW5nLlR5cGV9Kio6IGApO1xuICAgICAgICBmb3IgKGNvbnN0IHByb3BlcnR5IG9mIHdhcm5pbmcuUHJvcGVydGllcyEpIHtcbiAgICAgICAgICBsaW5lc1RvQWRkLnB1c2goYCAgLSAke3Byb3BlcnR5LlByb3BlcnR5UGF0aH06ICR7cHJvcGVydHkuRGVzY3JpcHRpb259YCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cbiAgbGluZXMuc3BsaWNlKGluZGV4LCAwLCAuLi5saW5lc1RvQWRkKTtcbiAgZnMud3JpdGVGaWxlU3luYyhmaWxlcGF0aCwgbGluZXMuam9pbignXFxuJykpO1xufVxuXG4vKipcbiAqIHRha2VzIGEgbGlzdCBvZiByZXNvdXJjZXMgYW5kIHJldHVybnMgYSBsaXN0IG9mIHVuaXF1ZSByZXNvdXJjZXMgYmFzZWQgb24gdGhlIHJlc291cmNlIHR5cGUgYW5kIGxvZ2ljYWwgcmVzb3VyY2UgaWQuXG4gKlxuICogQHBhcmFtIHJlc291cmNlcyBBIGxpc3Qgb2YgcmVzb3VyY2VzIHRvIGRlZHVwbGljYXRlXG4gKiBAcmV0dXJucyBBIGxpc3Qgb2YgdW5pcXVlIHJlc291cmNlc1xuICovXG5mdW5jdGlvbiBkZWR1cGxpY2F0ZVJlc291cmNlcyhyZXNvdXJjZXM6IFJlc291cmNlRGV0YWlsW10pIHtcbiAgbGV0IHVuaXF1ZVJlc291cmNlczogeyBba2V5OiBzdHJpbmddOiBSZXNvdXJjZURldGFpbCB9ID0ge307XG5cbiAgZm9yIChjb25zdCByZXNvdXJjZSBvZiByZXNvdXJjZXMpIHtcbiAgICBjb25zdCBrZXkgPSBPYmplY3Qua2V5cyhyZXNvdXJjZS5SZXNvdXJjZUlkZW50aWZpZXIhKVswXTtcblxuICAgIC8vIENyZWF0aW5nIG91ciB1bmlxdWUgaWRlbnRpZmllciB1c2luZyB0aGUgcmVzb3VyY2UgdHlwZSwgdGhlIGtleSwgYW5kIHRoZSB2YWx1ZSBvZiB0aGUgcmVzb3VyY2UgaWRlbnRpZmllclxuICAgIC8vIFRoZSByZXNvdXJjZSBpZGVudGlmaWVyIGlzIGEgY29tYmluYXRpb24gb2YgYSBrZXkgdmFsdWUgcGFpciBkZWZpbmVkIGJ5IGEgcmVzb3VyY2UncyBzY2hlbWEsIGFuZCB0aGUgcmVzb3VyY2UgdHlwZSBvZiB0aGUgcmVzb3VyY2UuXG4gICAgY29uc3QgdW5pcXVlSWRlbnRpZmVyID0gYCR7cmVzb3VyY2UuUmVzb3VyY2VUeXBlfToke2tleX06JHtyZXNvdXJjZS5SZXNvdXJjZUlkZW50aWZpZXIhW2tleV19YDtcbiAgICB1bmlxdWVSZXNvdXJjZXNbdW5pcXVlSWRlbnRpZmVyXSA9IHJlc291cmNlO1xuICB9XG5cbiAgcmV0dXJuIE9iamVjdC52YWx1ZXModW5pcXVlUmVzb3VyY2VzKTtcbn1cblxuLyoqXG4gKiBDbGFzcyBmb3IgbWFraW5nIENsb3VkRm9ybWF0aW9uIHRlbXBsYXRlIGdlbmVyYXRvciBjYWxsc1xuICovXG5leHBvcnQgY2xhc3MgQ2ZuVGVtcGxhdGVHZW5lcmF0b3JQcm92aWRlciB7XG4gIHByaXZhdGUgY2ZuOiBJQ2xvdWRGb3JtYXRpb25DbGllbnQ7XG4gIGNvbnN0cnVjdG9yKGNmbjogSUNsb3VkRm9ybWF0aW9uQ2xpZW50KSB7XG4gICAgdGhpcy5jZm4gPSBjZm47XG4gIH1cblxuICBhc3luYyBjaGVja0ZvclJlc291cmNlU2NhbihcbiAgICByZXNvdXJjZVNjYW5TdW1tYXJpZXM6IFJlc291cmNlU2NhblN1bW1hcnlbXSB8IHVuZGVmaW5lZCxcbiAgICBvcHRpb25zOiBHZW5lcmF0ZVRlbXBsYXRlT3B0aW9ucyxcbiAgICBjbGllbnRSZXF1ZXN0VG9rZW46IHN0cmluZyxcbiAgKSB7XG4gICAgaWYgKCFyZXNvdXJjZVNjYW5TdW1tYXJpZXMgfHwgcmVzb3VyY2VTY2FuU3VtbWFyaWVzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgaWYgKG9wdGlvbnMuZnJvbVNjYW4gPT09IEZyb21TY2FuLk1PU1RfUkVDRU5UKSB7XG4gICAgICAgIHRocm93IG5ldyBUb29sa2l0RXJyb3IoXG4gICAgICAgICAgJ05vIHNjYW5zIGZvdW5kLiBQbGVhc2UgZWl0aGVyIHN0YXJ0IGEgbmV3IHNjYW4gd2l0aCB0aGUgYC0tZnJvbS1zY2FuYCBuZXcgb3IgZG8gbm90IHNwZWNpZnkgYSBgLS1mcm9tLXNjYW5gIG9wdGlvbi4nLFxuICAgICAgICApO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgaW5mbygnTm8gc2NhbnMgZm91bmQuIEluaXRpYXRpbmcgYSBuZXcgcmVzb3VyY2Ugc2Nhbi4nKTtcbiAgICAgICAgYXdhaXQgdGhpcy5zdGFydFJlc291cmNlU2NhbihjbGllbnRSZXF1ZXN0VG9rZW4pO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSZXRyaWV2ZXMgYSB0b2tlbml6ZWQgbGlzdCBvZiByZXNvdXJjZXMgYW5kIHRoZWlyIGFzc29jaWF0ZWQgc2Nhbi4gSWYgYSB0b2tlbiBpcyBwcmVzZW50IHRoZSBmdW5jdGlvblxuICAgKiB3aWxsIGxvb3AgdGhyb3VnaCBhbGwgcGFnZXMgYW5kIGNvbWJpbmUgdGhlbSBpbnRvIGEgc2luZ2xlIGxpc3Qgb2YgU2Nhbm5lZFJlbGF0ZWRSZXNvdXJjZXNcbiAgICpcbiAgICogQHBhcmFtIHNjYW5JZCBzY2FuIGlkIGZvciB0aGUgdG8gbGlzdCByZXNvdXJjZXMgZm9yXG4gICAqIEBwYXJhbSByZXNvdXJjZXMgQSBsaXN0IG9mIHJlc291cmNlcyB0byBmaW5kIHJlbGF0ZWQgcmVzb3VyY2VzIGZvclxuICAgKi9cbiAgYXN5bmMgZ2V0UmVzb3VyY2VTY2FuUmVsYXRlZFJlc291cmNlcyhcbiAgICBzY2FuSWQ6IHN0cmluZyxcbiAgICByZXNvdXJjZXM6IFNjYW5uZWRSZXNvdXJjZVtdLFxuICApOiBQcm9taXNlPFNjYW5uZWRSZXNvdXJjZUlkZW50aWZpZXJbXT4ge1xuICAgIGxldCByZWxhdGVkUmVzb3VyY2VMaXN0ID0gcmVzb3VyY2VzO1xuXG4gICAgLy8gYnJlYWsgdGhlIGxpc3Qgb2YgcmVzb3VyY2VzIGludG8gY2h1bmtzIG9mIDEwMCB0byBhdm9pZCBoaXR0aW5nIHRoZSAxMDAgcmVzb3VyY2UgbGltaXRcbiAgICBmb3IgKGNvbnN0IGNodW5rIG9mIGNodW5rcyhyZXNvdXJjZXMsIDEwMCkpIHtcbiAgICAgIC8vIGdldCB0aGUgZmlyc3QgcGFnZSBvZiByZWxhdGVkIHJlc291cmNlc1xuICAgICAgY29uc3QgcmVzID0gYXdhaXQgdGhpcy5jZm4ubGlzdFJlc291cmNlU2NhblJlbGF0ZWRSZXNvdXJjZXMoe1xuICAgICAgICBSZXNvdXJjZVNjYW5JZDogc2NhbklkLFxuICAgICAgICBSZXNvdXJjZXM6IGNodW5rLFxuICAgICAgfSk7XG5cbiAgICAgIC8vIGFkZCB0aGUgZmlyc3QgcGFnZSB0byB0aGUgbGlzdFxuICAgICAgcmVsYXRlZFJlc291cmNlTGlzdC5wdXNoKC4uLihyZXMuUmVsYXRlZFJlc291cmNlcyA/PyBbXSkpO1xuICAgICAgbGV0IG5leHRUb2tlbiA9IHJlcy5OZXh0VG9rZW47XG5cbiAgICAgIC8vIGlmIHRoZXJlIGFyZSBtb3JlIHBhZ2VzLCBjeWNsZSB0aHJvdWdoIHRoZW0gYW5kIGFkZCB0aGVtIHRvIHRoZSBsaXN0IGJlZm9yZSBtb3Zpbmcgb24gdG8gdGhlIG5leHQgY2h1bmtcbiAgICAgIHdoaWxlIChuZXh0VG9rZW4pIHtcbiAgICAgICAgY29uc3QgbmV4dFJlbGF0ZWRSZXNvdXJjZXMgPSBhd2FpdCB0aGlzLmNmbi5saXN0UmVzb3VyY2VTY2FuUmVsYXRlZFJlc291cmNlcyh7XG4gICAgICAgICAgUmVzb3VyY2VTY2FuSWQ6IHNjYW5JZCxcbiAgICAgICAgICBSZXNvdXJjZXM6IHJlc291cmNlSWRlbnRpZmllcnMocmVzb3VyY2VzKSxcbiAgICAgICAgICBOZXh0VG9rZW46IG5leHRUb2tlbixcbiAgICAgICAgfSk7XG4gICAgICAgIG5leHRUb2tlbiA9IG5leHRSZWxhdGVkUmVzb3VyY2VzLk5leHRUb2tlbjtcbiAgICAgICAgcmVsYXRlZFJlc291cmNlTGlzdC5wdXNoKC4uLihuZXh0UmVsYXRlZFJlc291cmNlcy5SZWxhdGVkUmVzb3VyY2VzID8/IFtdKSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmVsYXRlZFJlc291cmNlTGlzdCA9IGRlZHVwbGljYXRlUmVzb3VyY2VzKHJlbGF0ZWRSZXNvdXJjZUxpc3QpO1xuXG4gICAgLy8gcHJ1bmUgdGhlIG1hbmFnZWRieXN0YWNrIGZsYWcgb2ZmIG9mIHRoZW0gYWdhaW4uXG4gICAgcmV0dXJuIHByb2Nlc3MuZW52Lk1JR1JBVEVfSU5URUdfVEVTVFxuICAgICAgPyByZXNvdXJjZUlkZW50aWZpZXJzKHJlbGF0ZWRSZXNvdXJjZUxpc3QpXG4gICAgICA6IHJlc291cmNlSWRlbnRpZmllcnMoZXhjbHVkZU1hbmFnZWQocmVsYXRlZFJlc291cmNlTGlzdCkpO1xuICB9XG5cbiAgLyoqXG4gICAqIEtpY2tzIG9mZiBhIHNjYW4gb2YgYSBjdXN0b21lcnMgYWNjb3VudCwgcmV0dXJuaW5nIHRoZSBzY2FuIGlkLiBBIHNjYW4gY2FuIHRha2VcbiAgICogMTAgbWludXRlcyBvciBsb25nZXIgdG8gY29tcGxldGUuIEhvd2V2ZXIgdGhpcyB3aWxsIHJldHVybiBhIHNjYW4gaWQgYXMgc29vbiBhc1xuICAgKiB0aGUgc2NhbiBoYXMgYmVndW4uXG4gICAqXG4gICAqIEByZXR1cm5zIEEgc3RyaW5nIHJlcHJlc2VudGluZyB0aGUgc2NhbiBpZFxuICAgKi9cbiAgYXN5bmMgc3RhcnRSZXNvdXJjZVNjYW4ocmVxdWVzdFRva2VuOiBzdHJpbmcpIHtcbiAgICByZXR1cm4gKFxuICAgICAgYXdhaXQgdGhpcy5jZm4uc3RhcnRSZXNvdXJjZVNjYW4oe1xuICAgICAgICBDbGllbnRSZXF1ZXN0VG9rZW46IHJlcXVlc3RUb2tlbixcbiAgICAgIH0pXG4gICAgKS5SZXNvdXJjZVNjYW5JZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXRzIHRoZSBtb3N0IHJlY2VudCBzY2FucyBhIGN1c3RvbWVyIGhhcyBjb21wbGV0ZWRcbiAgICpcbiAgICogQHJldHVybnMgYSBsaXN0IG9mIHJlc291cmNlIHNjYW4gc3VtbWFyaWVzXG4gICAqL1xuICBhc3luYyBsaXN0UmVzb3VyY2VTY2FucygpIHtcbiAgICByZXR1cm4gdGhpcy5jZm4ubGlzdFJlc291cmNlU2NhbnMoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXRyaWV2ZXMgYSB0b2tlbml6ZWQgbGlzdCBvZiByZXNvdXJjZXMgZnJvbSBhIHJlc291cmNlIHNjYW4uIElmIGEgdG9rZW4gaXMgcHJlc2VudCwgdGhpcyBmdW5jdGlvblxuICAgKiB3aWxsIGxvb3AgdGhyb3VnaCBhbGwgcGFnZXMgYW5kIGNvbWJpbmUgdGhlbSBpbnRvIGEgc2luZ2xlIGxpc3Qgb2YgU2Nhbm5lZFJlc291cmNlW10uXG4gICAqIEFkZGl0aW9uYWxseSB3aWxsIGFwcGx5IGFueSBmaWx0ZXJzIHByb3ZpZGVkIGJ5IHRoZSBjdXN0b21lci5cbiAgICpcbiAgICogQHBhcmFtIHNjYW5JZCBzY2FuIGlkIGZvciB0aGUgdG8gbGlzdCByZXNvdXJjZXMgZm9yXG4gICAqIEBwYXJhbSBmaWx0ZXJzIGEgc3RyaW5nIG9mIGZpbHRlcnMgaW4gdGhlIGZvcm1hdCBvZiBrZXkxPXZhbHVlMSxrZXkyPXZhbHVlMlxuICAgKiBAcmV0dXJucyBhIGNvbWJpbmVkIGxpc3Qgb2YgYWxsIHJlc291cmNlcyBmcm9tIHRoZSBzY2FuXG4gICAqL1xuICBhc3luYyBsaXN0UmVzb3VyY2VTY2FuUmVzb3VyY2VzKHNjYW5JZDogc3RyaW5nLCBmaWx0ZXJzOiBzdHJpbmdbXSA9IFtdKTogUHJvbWlzZTxTY2FubmVkUmVzb3VyY2VJZGVudGlmaWVyW10+IHtcbiAgICBsZXQgcmVzb3VyY2VMaXN0OiBTY2FubmVkUmVzb3VyY2VbXSA9IFtdO1xuICAgIGxldCByZXNvdXJjZVNjYW5JbnB1dHM6IExpc3RSZXNvdXJjZVNjYW5SZXNvdXJjZXNDb21tYW5kSW5wdXQ7XG5cbiAgICBpZiAoZmlsdGVycy5sZW5ndGggPiAwKSB7XG4gICAgICBpbmZvKCdBcHBseWluZyBmaWx0ZXJzIHRvIHJlc291cmNlIHNjYW4uJyk7XG4gICAgICBmb3IgKGNvbnN0IGZpbHRlciBvZiBmaWx0ZXJzKSB7XG4gICAgICAgIGNvbnN0IGZpbHRlckxpc3QgPSBwYXJzZUZpbHRlcnMoZmlsdGVyKTtcbiAgICAgICAgcmVzb3VyY2VTY2FuSW5wdXRzID0ge1xuICAgICAgICAgIFJlc291cmNlU2NhbklkOiBzY2FuSWQsXG4gICAgICAgICAgUmVzb3VyY2VJZGVudGlmaWVyOiBmaWx0ZXJMaXN0W0ZpbHRlclR5cGUuUkVTT1VSQ0VfSURFTlRJRklFUl0sXG4gICAgICAgICAgUmVzb3VyY2VUeXBlUHJlZml4OiBmaWx0ZXJMaXN0W0ZpbHRlclR5cGUuUkVTT1VSQ0VfVFlQRV9QUkVGSVhdLFxuICAgICAgICAgIFRhZ0tleTogZmlsdGVyTGlzdFtGaWx0ZXJUeXBlLlRBR19LRVldLFxuICAgICAgICAgIFRhZ1ZhbHVlOiBmaWx0ZXJMaXN0W0ZpbHRlclR5cGUuVEFHX1ZBTFVFXSxcbiAgICAgICAgfTtcbiAgICAgICAgY29uc3QgcmVzb3VyY2VzID0gYXdhaXQgdGhpcy5jZm4ubGlzdFJlc291cmNlU2NhblJlc291cmNlcyhyZXNvdXJjZVNjYW5JbnB1dHMpO1xuICAgICAgICByZXNvdXJjZUxpc3QgPSByZXNvdXJjZUxpc3QuY29uY2F0KHJlc291cmNlcy5SZXNvdXJjZXMgPz8gW10pO1xuICAgICAgICBsZXQgbmV4dFRva2VuID0gcmVzb3VyY2VzLk5leHRUb2tlbjtcblxuICAgICAgICAvLyBjeWNsZSB0aHJvdWdoIHRoZSBwYWdlcyBhZGRpbmcgYWxsIHJlc291cmNlcyB0byB0aGUgbGlzdCB1bnRpbCB3ZSBydW4gb3V0IG9mIHBhZ2VzXG4gICAgICAgIHdoaWxlIChuZXh0VG9rZW4pIHtcbiAgICAgICAgICByZXNvdXJjZVNjYW5JbnB1dHMuTmV4dFRva2VuID0gbmV4dFRva2VuO1xuICAgICAgICAgIGNvbnN0IG5leHRSZXNvdXJjZXMgPSBhd2FpdCB0aGlzLmNmbi5saXN0UmVzb3VyY2VTY2FuUmVzb3VyY2VzKHJlc291cmNlU2NhbklucHV0cyk7XG4gICAgICAgICAgbmV4dFRva2VuID0gbmV4dFJlc291cmNlcy5OZXh0VG9rZW47XG4gICAgICAgICAgcmVzb3VyY2VMaXN0ID0gcmVzb3VyY2VMaXN0IS5jb25jYXQobmV4dFJlc291cmNlcy5SZXNvdXJjZXMgPz8gW10pO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIGluZm8oJ05vIGZpbHRlcnMgcHJvdmlkZWQuIFJldHJpZXZpbmcgYWxsIHJlc291cmNlcyBmcm9tIHNjYW4uJyk7XG4gICAgICByZXNvdXJjZVNjYW5JbnB1dHMgPSB7XG4gICAgICAgIFJlc291cmNlU2NhbklkOiBzY2FuSWQsXG4gICAgICB9O1xuICAgICAgY29uc3QgcmVzb3VyY2VzID0gYXdhaXQgdGhpcy5jZm4ubGlzdFJlc291cmNlU2NhblJlc291cmNlcyhyZXNvdXJjZVNjYW5JbnB1dHMpO1xuICAgICAgcmVzb3VyY2VMaXN0ID0gcmVzb3VyY2VMaXN0IS5jb25jYXQocmVzb3VyY2VzLlJlc291cmNlcyA/PyBbXSk7XG4gICAgICBsZXQgbmV4dFRva2VuID0gcmVzb3VyY2VzLk5leHRUb2tlbjtcblxuICAgICAgLy8gY3ljbGUgdGhyb3VnaCB0aGUgcGFnZXMgYWRkaW5nIGFsbCByZXNvdXJjZXMgdG8gdGhlIGxpc3QgdW50aWwgd2UgcnVuIG91dCBvZiBwYWdlc1xuICAgICAgd2hpbGUgKG5leHRUb2tlbikge1xuICAgICAgICByZXNvdXJjZVNjYW5JbnB1dHMuTmV4dFRva2VuID0gbmV4dFRva2VuO1xuICAgICAgICBjb25zdCBuZXh0UmVzb3VyY2VzID0gYXdhaXQgdGhpcy5jZm4ubGlzdFJlc291cmNlU2NhblJlc291cmNlcyhyZXNvdXJjZVNjYW5JbnB1dHMpO1xuICAgICAgICBuZXh0VG9rZW4gPSBuZXh0UmVzb3VyY2VzLk5leHRUb2tlbjtcbiAgICAgICAgcmVzb3VyY2VMaXN0ID0gcmVzb3VyY2VMaXN0IS5jb25jYXQobmV4dFJlc291cmNlcy5SZXNvdXJjZXMgPz8gW10pO1xuICAgICAgfVxuICAgIH1cbiAgICBpZiAocmVzb3VyY2VMaXN0Lmxlbmd0aCA9PT0gMCkge1xuICAgICAgdGhyb3cgbmV3IFRvb2xraXRFcnJvcihgTm8gcmVzb3VyY2VzIGZvdW5kIHdpdGggZmlsdGVycyAke2ZpbHRlcnMuam9pbignICcpfS4gUGxlYXNlIHRyeSBhZ2FpbiB3aXRoIGRpZmZlcmVudCBmaWx0ZXJzLmApO1xuICAgIH1cbiAgICByZXNvdXJjZUxpc3QgPSBkZWR1cGxpY2F0ZVJlc291cmNlcyhyZXNvdXJjZUxpc3QpO1xuXG4gICAgcmV0dXJuIHByb2Nlc3MuZW52Lk1JR1JBVEVfSU5URUdfVEVTVFxuICAgICAgPyByZXNvdXJjZUlkZW50aWZpZXJzKHJlc291cmNlTGlzdClcbiAgICAgIDogcmVzb3VyY2VJZGVudGlmaWVycyhleGNsdWRlTWFuYWdlZChyZXNvdXJjZUxpc3QpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXRyaWV2ZXMgaW5mb3JtYXRpb24gYWJvdXQgYSByZXNvdXJjZSBzY2FuLlxuICAgKlxuICAgKiBAcGFyYW0gc2NhbklkIHNjYW4gaWQgZm9yIHRoZSB0byBsaXN0IHJlc291cmNlcyBmb3JcbiAgICogQHJldHVybnMgaW5mb3JtYXRpb24gYWJvdXQgdGhlIHNjYW5cbiAgICovXG4gIGFzeW5jIGRlc2NyaWJlUmVzb3VyY2VTY2FuKHNjYW5JZDogc3RyaW5nKTogUHJvbWlzZTxEZXNjcmliZVJlc291cmNlU2NhbkNvbW1hbmRPdXRwdXQ+IHtcbiAgICByZXR1cm4gdGhpcy5jZm4uZGVzY3JpYmVSZXNvdXJjZVNjYW4oe1xuICAgICAgUmVzb3VyY2VTY2FuSWQ6IHNjYW5JZCxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZXNjcmliZXMgdGhlIGN1cnJlbnQgc3RhdHVzIG9mIHRoZSB0ZW1wbGF0ZSBiZWluZyBnZW5lcmF0ZWQuXG4gICAqXG4gICAqIEBwYXJhbSB0ZW1wbGF0ZUlkIEEgc3RyaW5nIHJlcHJlc2VudGluZyB0aGUgdGVtcGxhdGUgaWRcbiAgICogQHJldHVybnMgRGVzY3JpYmVHZW5lcmF0ZWRUZW1wbGF0ZU91dHB1dCBhbiBvYmplY3QgY29udGFpbmluZyB0aGUgdGVtcGxhdGUgc3RhdHVzIGFuZCByZXN1bHRzXG4gICAqL1xuICBhc3luYyBkZXNjcmliZUdlbmVyYXRlZFRlbXBsYXRlKHRlbXBsYXRlSWQ6IHN0cmluZyk6IFByb21pc2U8RGVzY3JpYmVHZW5lcmF0ZWRUZW1wbGF0ZUNvbW1hbmRPdXRwdXQ+IHtcbiAgICBjb25zdCBnZW5lcmF0ZWRUZW1wbGF0ZSA9IGF3YWl0IHRoaXMuY2ZuLmRlc2NyaWJlR2VuZXJhdGVkVGVtcGxhdGUoe1xuICAgICAgR2VuZXJhdGVkVGVtcGxhdGVOYW1lOiB0ZW1wbGF0ZUlkLFxuICAgIH0pO1xuXG4gICAgaWYgKGdlbmVyYXRlZFRlbXBsYXRlLlN0YXR1cyA9PSBTY2FuU3RhdHVzLkZBSUxFRCkge1xuICAgICAgdGhyb3cgbmV3IFRvb2xraXRFcnJvcihnZW5lcmF0ZWRUZW1wbGF0ZS5TdGF0dXNSZWFzb24hKTtcbiAgICB9XG5cbiAgICByZXR1cm4gZ2VuZXJhdGVkVGVtcGxhdGU7XG4gIH1cblxuICAvKipcbiAgICogUmV0cmlldmVzIGEgY29tcGxldGVkIGdlbmVyYXRlZCBjbG91ZGZvcm1hdGlvbiB0ZW1wbGF0ZSBmcm9tIHRoZSB0ZW1wbGF0ZSBnZW5lcmF0b3IuXG4gICAqXG4gICAqIEBwYXJhbSB0ZW1wbGF0ZUlkIEEgc3RyaW5nIHJlcHJlc2VudGluZyB0aGUgdGVtcGxhdGUgaWRcbiAgICogQHBhcmFtIGNsb3VkRm9ybWF0aW9uIFRoZSBDbG91ZEZvcm1hdGlvbiBzZGsgY2xpZW50IHRvIHVzZVxuICAgKiBAcmV0dXJucyBEZXNjcmliZUdlbmVyYXRlZFRlbXBsYXRlT3V0cHV0IGFuIG9iamVjdCBjb250YWluaW5nIHRoZSB0ZW1wbGF0ZSBzdGF0dXMgYW5kIGJvZHlcbiAgICovXG4gIGFzeW5jIGdldEdlbmVyYXRlZFRlbXBsYXRlKHRlbXBsYXRlSWQ6IHN0cmluZyk6IFByb21pc2U8R2V0R2VuZXJhdGVkVGVtcGxhdGVDb21tYW5kT3V0cHV0PiB7XG4gICAgcmV0dXJuIHRoaXMuY2ZuLmdldEdlbmVyYXRlZFRlbXBsYXRlKHtcbiAgICAgIEdlbmVyYXRlZFRlbXBsYXRlTmFtZTogdGVtcGxhdGVJZCxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBLaWNrcyBvZmYgYSB0ZW1wbGF0ZSBnZW5lcmF0aW9uIGZvciBhIHNldCBvZiByZXNvdXJjZXMuXG4gICAqXG4gICAqIEBwYXJhbSBzdGFja05hbWUgVGhlIG5hbWUgb2YgdGhlIHN0YWNrXG4gICAqIEBwYXJhbSByZXNvdXJjZXMgQSBsaXN0IG9mIHJlc291cmNlcyB0byBnZW5lcmF0ZSB0aGUgdGVtcGxhdGUgZnJvbVxuICAgKiBAcmV0dXJucyBDcmVhdGVHZW5lcmF0ZWRUZW1wbGF0ZU91dHB1dCBhbiBvYmplY3QgY29udGFpbmluZyB0aGUgdGVtcGxhdGUgYXJuIHRvIHF1ZXJ5IG9uIGxhdGVyXG4gICAqL1xuICBhc3luYyBjcmVhdGVHZW5lcmF0ZWRUZW1wbGF0ZShzdGFja05hbWU6IHN0cmluZywgcmVzb3VyY2VzOiBSZXNvdXJjZURlZmluaXRpb25bXSkge1xuICAgIGNvbnN0IGNyZWF0ZVRlbXBsYXRlT3V0cHV0ID0gYXdhaXQgdGhpcy5jZm4uY3JlYXRlR2VuZXJhdGVkVGVtcGxhdGUoe1xuICAgICAgUmVzb3VyY2VzOiByZXNvdXJjZXMsXG4gICAgICBHZW5lcmF0ZWRUZW1wbGF0ZU5hbWU6IHN0YWNrTmFtZSxcbiAgICB9KTtcblxuICAgIGlmIChjcmVhdGVUZW1wbGF0ZU91dHB1dC5HZW5lcmF0ZWRUZW1wbGF0ZUlkID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHRocm93IG5ldyBUb29sa2l0RXJyb3IoJ0NyZWF0ZUdlbmVyYXRlZFRlbXBsYXRlIGZhaWxlZCB0byByZXR1cm4gYW4gQXJuLicpO1xuICAgIH1cbiAgICByZXR1cm4gY3JlYXRlVGVtcGxhdGVPdXRwdXQ7XG4gIH1cblxuICAvKipcbiAgICogRGVsZXRlcyBhIGdlbmVyYXRlZCB0ZW1wbGF0ZSBmcm9tIHRoZSB0ZW1wbGF0ZSBnZW5lcmF0b3IuXG4gICAqXG4gICAqIEBwYXJhbSB0ZW1wbGF0ZUFybiBUaGUgYXJuIG9mIHRoZSB0ZW1wbGF0ZSB0byBkZWxldGVcbiAgICogQHJldHVybnMgQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2hlbiB0aGUgdGVtcGxhdGUgaGFzIGJlZW4gZGVsZXRlZFxuICAgKi9cbiAgYXN5bmMgZGVsZXRlR2VuZXJhdGVkVGVtcGxhdGUodGVtcGxhdGVBcm46IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgIGF3YWl0IHRoaXMuY2ZuLmRlbGV0ZUdlbmVyYXRlZFRlbXBsYXRlKHtcbiAgICAgIEdlbmVyYXRlZFRlbXBsYXRlTmFtZTogdGVtcGxhdGVBcm4sXG4gICAgfSk7XG4gIH1cbn1cblxuLyoqXG4gKiBUaGUgcG9zc2libGUgd2F5cyB0byBjaG9vc2UgYSBzY2FuIHRvIGdlbmVyYXRlIGEgQ0RLIGFwcGxpY2F0aW9uIGZyb21cbiAqL1xuZXhwb3J0IGVudW0gRnJvbVNjYW4ge1xuICAvKipcbiAgICogSW5pdGlhdGUgYSBuZXcgcmVzb3VyY2Ugc2NhbiB0byBidWlsZCB0aGUgQ0RLIGFwcGxpY2F0aW9uIGZyb20uXG4gICAqL1xuICBORVcsXG5cbiAgLyoqXG4gICAqIFVzZSB0aGUgbGFzdCBzdWNjZXNzZnVsIHNjYW4gdG8gYnVpbGQgdGhlIENESyBhcHBsaWNhdGlvbiBmcm9tLiBXaWxsIGZhaWwgaWYgbm8gc2NhbiBpcyBmb3VuZC5cbiAgICovXG4gIE1PU1RfUkVDRU5ULFxuXG4gIC8qKlxuICAgKiBTdGFydHMgYSBzY2FuIGlmIG5vbmUgZXhpc3RzLCBvdGhlcndpc2UgdXNlcyB0aGUgbW9zdCByZWNlbnQgc3VjY2Vzc2Z1bCBzY2FuIHRvIGJ1aWxkIHRoZSBDREsgYXBwbGljYXRpb24gZnJvbS5cbiAgICovXG4gIERFRkFVTFQsXG59XG5cbi8qKlxuICogSW50ZXJmYWNlIGZvciB0aGUgb3B0aW9ucyBvYmplY3QgcGFzc2VkIHRvIHRoZSBnZW5lcmF0ZVRlbXBsYXRlIGZ1bmN0aW9uXG4gKlxuICogQHBhcmFtIHN0YWNrTmFtZSBUaGUgbmFtZSBvZiB0aGUgc3RhY2tcbiAqIEBwYXJhbSBmaWx0ZXJzIEEgbGlzdCBvZiBmaWx0ZXJzIHRvIGFwcGx5IHRvIHRoZSBzY2FuXG4gKiBAcGFyYW0gZnJvbVNjYW4gQW4gZW51bSB2YWx1ZSBzcGVjaWZ5aW5nIHdoZXRoZXIgYSBuZXcgc2NhbiBzaG91bGQgYmUgc3RhcnRlZCBvciB0aGUgbW9zdCByZWNlbnQgc3VjY2Vzc2Z1bCBzY2FuIHNob3VsZCBiZSB1c2VkXG4gKiBAcGFyYW0gc2RrUHJvdmlkZXIgVGhlIHNkayBwcm92aWRlciBmb3IgbWFraW5nIENsb3VkRm9ybWF0aW9uIGNhbGxzXG4gKiBAcGFyYW0gZW52aXJvbm1lbnQgVGhlIGFjY291bnQgYW5kIHJlZ2lvbiB3aGVyZSB0aGUgc3RhY2sgaXMgZGVwbG95ZWRcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBHZW5lcmF0ZVRlbXBsYXRlT3B0aW9ucyB7XG4gIHN0YWNrTmFtZTogc3RyaW5nO1xuICBmaWx0ZXJzPzogc3RyaW5nW107XG4gIGZyb21TY2FuPzogRnJvbVNjYW47XG4gIHNka1Byb3ZpZGVyOiBTZGtQcm92aWRlcjtcbiAgZW52aXJvbm1lbnQ6IEVudmlyb25tZW50O1xufVxuXG4vKipcbiAqIEludGVyZmFjZSBmb3IgdGhlIG91dHB1dCBvZiB0aGUgZ2VuZXJhdGVUZW1wbGF0ZSBmdW5jdGlvblxuICpcbiAqIEBwYXJhbSBtaWdyYXRlSnNvbiBUaGUgZ2VuZXJhdGVkIE1pZ3JhdGUuanNvbiBmaWxlXG4gKiBAcGFyYW0gcmVzb3VyY2VzIFRoZSBnZW5lcmF0ZWQgdGVtcGxhdGVcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBHZW5lcmF0ZVRlbXBsYXRlT3V0cHV0IHtcbiAgbWlncmF0ZUpzb246IE1pZ3JhdGVKc29uRm9ybWF0O1xuICByZXNvdXJjZXM/OiBSZXNvdXJjZURldGFpbFtdO1xuICB0ZW1wbGF0ZUlkPzogc3RyaW5nO1xufVxuXG4vKipcbiAqIEludGVyZmFjZSBkZWZpbmluZyB0aGUgZm9ybWF0IG9mIHRoZSBnZW5lcmF0ZWQgTWlncmF0ZS5qc29uIGZpbGVcbiAqXG4gKiBAcGFyYW0gVGVtcGxhdGVCb2R5IFRoZSBnZW5lcmF0ZWQgdGVtcGxhdGVcbiAqIEBwYXJhbSBTb3VyY2UgVGhlIHNvdXJjZSBvZiB0aGUgdGVtcGxhdGVcbiAqIEBwYXJhbSBSZXNvdXJjZXMgQSBsaXN0IG9mIHJlc291cmNlcyB0aGF0IHdlcmUgdXNlZCB0byBnZW5lcmF0ZSB0aGUgdGVtcGxhdGVcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBNaWdyYXRlSnNvbkZvcm1hdCB7XG4gIHRlbXBsYXRlQm9keTogc3RyaW5nO1xuICBzb3VyY2U6IHN0cmluZztcbiAgcmVzb3VyY2VzPzogR2VuZXJhdGVkUmVzb3VyY2VJbXBvcnRJZGVudGlmaWVyW107XG59XG5cbi8qKlxuICogSW50ZXJmYWNlIHJlcHJlc2VudGluZyB0aGUgZm9ybWF0IG9mIGEgcmVzb3VyY2UgaWRlbnRpZmllciByZXF1aXJlZCBmb3IgcmVzb3VyY2UgaW1wb3J0XG4gKlxuICogQHBhcmFtIFJlc291cmNlVHlwZSBUaGUgdHlwZSBvZiByZXNvdXJjZVxuICogQHBhcmFtIExvZ2ljYWxSZXNvdXJjZUlkIFRoZSBsb2dpY2FsIGlkIG9mIHRoZSByZXNvdXJjZVxuICogQHBhcmFtIFJlc291cmNlSWRlbnRpZmllciBUaGUgcmVzb3VyY2UgaWRlbnRpZmllciBvZiB0aGUgcmVzb3VyY2VcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBHZW5lcmF0ZWRSZXNvdXJjZUltcG9ydElkZW50aWZpZXIge1xuICAvLyBjZGsgZGVwbG95IGV4cGVjdHMgdGhlIG1pZ3JhdGUuanNvbiByZXNvdXJjZSBpZGVudGlmaWVycyB0byBiZSBQYXNjYWxDYXNlLCBub3QgY2FtZWxDYXNlLlxuICBSZXNvdXJjZVR5cGU6IHN0cmluZztcbiAgTG9naWNhbFJlc291cmNlSWQ6IHN0cmluZztcbiAgUmVzb3VyY2VJZGVudGlmaWVyOiBSZXNvdXJjZUlkZW50aWZpZXJTdW1tYXJ5O1xufVxuIl19