aws-cdk 2.1006.0 → 3.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 (256) hide show
  1. package/README.md +1 -1
  2. package/THIRD_PARTY_LICENSES +104 -86
  3. package/build-info.json +2 -2
  4. package/db.json.gz +0 -0
  5. package/lib/api/aws-auth.d.ts +1 -0
  6. package/lib/api/{logs/index.js → aws-auth.js} +2 -3
  7. package/lib/api/bootstrap.d.ts +1 -0
  8. package/lib/api/bootstrap.js +18 -0
  9. package/lib/api/cloud-assembly.d.ts +1 -0
  10. package/lib/api/cloud-assembly.js +18 -0
  11. package/lib/api/cloudformation.d.ts +1 -0
  12. package/lib/api/cloudformation.js +18 -0
  13. package/lib/api/context.d.ts +1 -40
  14. package/lib/api/context.js +16 -80
  15. package/lib/api/deployments.d.ts +1 -0
  16. package/lib/api/deployments.js +18 -0
  17. package/lib/api/environment.d.ts +1 -0
  18. package/lib/api/environment.js +18 -0
  19. package/lib/api/garbage-collection.d.ts +1 -0
  20. package/lib/api/garbage-collection.js +18 -0
  21. package/lib/api/hotswap.d.ts +1 -0
  22. package/lib/api/hotswap.js +18 -0
  23. package/lib/api/index.d.ts +5 -1
  24. package/lib/api/index.js +6 -2
  25. package/lib/api/logs-monitor.d.ts +1 -0
  26. package/lib/api/logs-monitor.js +18 -0
  27. package/lib/api/notices.d.ts +1 -0
  28. package/lib/api/notices.js +18 -0
  29. package/lib/api/plugin.d.ts +1 -0
  30. package/lib/api/{resource-import/index.js → plugin.js} +2 -3
  31. package/lib/api/resource-import.d.ts +1 -0
  32. package/lib/api/resource-import.js +18 -0
  33. package/lib/api/rwlock.d.ts +1 -0
  34. package/lib/api/{garbage-collection/index.js → rwlock.js} +2 -2
  35. package/lib/api/settings.d.ts +1 -26
  36. package/lib/api/settings.js +16 -103
  37. package/lib/api/stack-events.d.ts +1 -0
  38. package/lib/api/stack-events.js +18 -0
  39. package/lib/api/tags.d.ts +1 -9
  40. package/lib/api/tags.js +16 -8
  41. package/lib/api/toolkit-info.d.ts +1 -52
  42. package/lib/api/toolkit-info.js +16 -152
  43. package/lib/api/tree.d.ts +1 -31
  44. package/lib/api/tree.js +16 -35
  45. package/lib/api/work-graph.d.ts +1 -0
  46. package/lib/api/work-graph.js +18 -0
  47. package/lib/api-private.d.ts +3 -0
  48. package/lib/api-private.js +22 -0
  49. package/lib/cli/cdk-toolkit.d.ts +20 -16
  50. package/lib/cli/cdk-toolkit.js +102 -37
  51. package/lib/cli/cli-config.js +2 -2
  52. package/lib/cli/cli.d.ts +1 -1
  53. package/lib/cli/cli.js +22 -19
  54. package/lib/cli/io-host/cli-io-host.js +2 -2
  55. package/lib/cli/pretty-print-error.js +3 -1
  56. package/lib/cli/util/npm.d.ts +4 -1
  57. package/lib/cli/util/npm.js +25 -13
  58. package/lib/cli/version.d.ts +1 -1
  59. package/lib/cli/version.js +21 -25
  60. package/lib/commands/context.js +3 -2
  61. package/lib/commands/diff.d.ts +1 -50
  62. package/lib/commands/diff.js +5 -213
  63. package/lib/commands/init/init.js +3 -2
  64. package/lib/commands/list-stacks.js +4 -4
  65. package/lib/context-providers/ami.d.ts +1 -13
  66. package/lib/context-providers/ami.js +16 -48
  67. package/lib/context-providers/availability-zones.d.ts +1 -13
  68. package/lib/context-providers/availability-zones.js +16 -25
  69. package/lib/context-providers/cc-api-provider.d.ts +1 -30
  70. package/lib/context-providers/cc-api-provider.js +16 -136
  71. package/lib/context-providers/endpoint-service-availability-zones.d.ts +1 -13
  72. package/lib/context-providers/endpoint-service-availability-zones.js +16 -31
  73. package/lib/context-providers/hosted-zones.d.ts +1 -12
  74. package/lib/context-providers/hosted-zones.js +16 -65
  75. package/lib/context-providers/index.d.ts +1 -44
  76. package/lib/context-providers/index.js +15 -126
  77. package/lib/context-providers/keys.d.ts +1 -13
  78. package/lib/context-providers/keys.js +16 -50
  79. package/lib/context-providers/load-balancers.d.ts +1 -20
  80. package/lib/context-providers/load-balancers.js +16 -154
  81. package/lib/context-providers/security-groups.d.ts +1 -9
  82. package/lib/context-providers/security-groups.js +16 -66
  83. package/lib/context-providers/ssm-parameters.d.ts +1 -25
  84. package/lib/context-providers/ssm-parameters.js +16 -57
  85. package/lib/context-providers/vpcs.d.ts +1 -13
  86. package/lib/context-providers/vpcs.js +16 -285
  87. package/lib/{api/cxapp → cxapp}/cloud-assembly.d.ts +3 -59
  88. package/lib/cxapp/cloud-assembly.js +108 -0
  89. package/lib/{api/cxapp → cxapp}/cloud-executable.d.ts +10 -3
  90. package/lib/cxapp/cloud-executable.js +92 -0
  91. package/lib/{api/cxapp → cxapp}/environments.d.ts +1 -2
  92. package/lib/{api/cxapp → cxapp}/environments.js +2 -2
  93. package/lib/cxapp/exec.d.ts +14 -0
  94. package/lib/cxapp/exec.js +157 -0
  95. package/lib/cxapp/index.d.ts +4 -0
  96. package/lib/{api/bootstrap → cxapp}/index.js +5 -3
  97. package/lib/index.js +134493 -125222
  98. package/lib/init-templates/.init-version.json +1 -1
  99. package/lib/init-templates/.recommended-feature-flags.json +3 -1
  100. package/lib/legacy-aws-auth.d.ts +74 -0
  101. package/lib/legacy-aws-auth.js +40 -0
  102. package/lib/legacy-exports-source.d.ts +13 -18
  103. package/lib/legacy-exports-source.js +42 -49
  104. package/lib/legacy-exports.d.ts +3 -6
  105. package/lib/legacy-exports.js +5 -5
  106. package/lib/legacy-types.d.ts +31 -0
  107. package/lib/legacy-types.js +3 -0
  108. package/package.json +19 -18
  109. package/lib/api/aws-auth/account-cache.d.ts +0 -36
  110. package/lib/api/aws-auth/account-cache.js +0 -99
  111. package/lib/api/aws-auth/awscli-compatible.d.ts +0 -42
  112. package/lib/api/aws-auth/awscli-compatible.js +0 -263
  113. package/lib/api/aws-auth/cached.d.ts +0 -11
  114. package/lib/api/aws-auth/cached.js +0 -26
  115. package/lib/api/aws-auth/credential-plugins.d.ts +0 -36
  116. package/lib/api/aws-auth/credential-plugins.js +0 -152
  117. package/lib/api/aws-auth/index.d.ts +0 -3
  118. package/lib/api/aws-auth/index.js +0 -20
  119. package/lib/api/aws-auth/provider-caching.d.ts +0 -13
  120. package/lib/api/aws-auth/provider-caching.js +0 -24
  121. package/lib/api/aws-auth/sdk-logger.d.ts +0 -69
  122. package/lib/api/aws-auth/sdk-logger.js +0 -124
  123. package/lib/api/aws-auth/sdk-provider.d.ts +0 -207
  124. package/lib/api/aws-auth/sdk-provider.js +0 -357
  125. package/lib/api/aws-auth/sdk.d.ts +0 -229
  126. package/lib/api/aws-auth/sdk.js +0 -373
  127. package/lib/api/aws-auth/tracing.d.ts +0 -11
  128. package/lib/api/aws-auth/tracing.js +0 -60
  129. package/lib/api/aws-auth/user-agent.d.ts +0 -7
  130. package/lib/api/aws-auth/user-agent.js +0 -20
  131. package/lib/api/aws-auth/util.d.ts +0 -6
  132. package/lib/api/aws-auth/util.js +0 -23
  133. package/lib/api/bootstrap/bootstrap-environment.d.ts +0 -35
  134. package/lib/api/bootstrap/bootstrap-environment.js +0 -321
  135. package/lib/api/bootstrap/bootstrap-props.d.ts +0 -130
  136. package/lib/api/bootstrap/bootstrap-props.js +0 -14
  137. package/lib/api/bootstrap/deploy-bootstrap.d.ts +0 -39
  138. package/lib/api/bootstrap/deploy-bootstrap.js +0 -141
  139. package/lib/api/bootstrap/index.d.ts +0 -2
  140. package/lib/api/bootstrap/legacy-template.d.ts +0 -2
  141. package/lib/api/bootstrap/legacy-template.js +0 -82
  142. package/lib/api/cloudformation/evaluate-cloudformation-template.d.ts +0 -85
  143. package/lib/api/cloudformation/evaluate-cloudformation-template.js +0 -440
  144. package/lib/api/cloudformation/index.d.ts +0 -4
  145. package/lib/api/cloudformation/index.js +0 -21
  146. package/lib/api/cloudformation/nested-stack-helpers.d.ts +0 -25
  147. package/lib/api/cloudformation/nested-stack-helpers.js +0 -86
  148. package/lib/api/cloudformation/stack-helpers.d.ts +0 -96
  149. package/lib/api/cloudformation/stack-helpers.js +0 -158
  150. package/lib/api/cloudformation/template-body-parameter.d.ts +0 -22
  151. package/lib/api/cloudformation/template-body-parameter.js +0 -104
  152. package/lib/api/cxapp/cloud-assembly.js +0 -304
  153. package/lib/api/cxapp/cloud-executable.js +0 -89
  154. package/lib/api/cxapp/exec.d.ts +0 -56
  155. package/lib/api/cxapp/exec.js +0 -272
  156. package/lib/api/deployments/asset-manifest-builder.d.ts +0 -8
  157. package/lib/api/deployments/asset-manifest-builder.js +0 -35
  158. package/lib/api/deployments/asset-publishing.d.ts +0 -60
  159. package/lib/api/deployments/asset-publishing.js +0 -141
  160. package/lib/api/deployments/assets.d.ts +0 -11
  161. package/lib/api/deployments/assets.js +0 -109
  162. package/lib/api/deployments/cfn-api.d.ts +0 -138
  163. package/lib/api/deployments/cfn-api.js +0 -438
  164. package/lib/api/deployments/checks.d.ts +0 -9
  165. package/lib/api/deployments/checks.js +0 -72
  166. package/lib/api/deployments/deploy-stack.d.ts +0 -155
  167. package/lib/api/deployments/deploy-stack.js +0 -478
  168. package/lib/api/deployments/deployment-method.d.ts +0 -24
  169. package/lib/api/deployments/deployment-method.js +0 -3
  170. package/lib/api/deployments/deployment-result.d.ts +0 -21
  171. package/lib/api/deployments/deployment-result.js +0 -10
  172. package/lib/api/deployments/deployments.d.ts +0 -296
  173. package/lib/api/deployments/deployments.js +0 -331
  174. package/lib/api/deployments/hotswap-deployments.d.ts +0 -17
  175. package/lib/api/deployments/hotswap-deployments.js +0 -441
  176. package/lib/api/deployments/index.d.ts +0 -4
  177. package/lib/api/deployments/index.js +0 -21
  178. package/lib/api/environment/environment-access.d.ts +0 -140
  179. package/lib/api/environment/environment-access.js +0 -202
  180. package/lib/api/environment/environment-resources.d.ts +0 -75
  181. package/lib/api/environment/environment-resources.js +0 -207
  182. package/lib/api/environment/index.d.ts +0 -3
  183. package/lib/api/environment/index.js +0 -20
  184. package/lib/api/environment/placeholders.d.ts +0 -10
  185. package/lib/api/environment/placeholders.js +0 -23
  186. package/lib/api/garbage-collection/garbage-collector.d.ts +0 -158
  187. package/lib/api/garbage-collection/garbage-collector.js +0 -599
  188. package/lib/api/garbage-collection/index.d.ts +0 -1
  189. package/lib/api/garbage-collection/progress-printer.d.ts +0 -23
  190. package/lib/api/garbage-collection/progress-printer.js +0 -70
  191. package/lib/api/garbage-collection/stack-refresh.d.ts +0 -49
  192. package/lib/api/garbage-collection/stack-refresh.js +0 -151
  193. package/lib/api/hotswap/appsync-mapping-templates.d.ts +0 -4
  194. package/lib/api/hotswap/appsync-mapping-templates.js +0 -162
  195. package/lib/api/hotswap/code-build-projects.d.ts +0 -4
  196. package/lib/api/hotswap/code-build-projects.js +0 -62
  197. package/lib/api/hotswap/common.d.ts +0 -89
  198. package/lib/api/hotswap/common.js +0 -128
  199. package/lib/api/hotswap/ecs-services.d.ts +0 -4
  200. package/lib/api/hotswap/ecs-services.js +0 -159
  201. package/lib/api/hotswap/lambda-functions.d.ts +0 -4
  202. package/lib/api/hotswap/lambda-functions.js +0 -297
  203. package/lib/api/hotswap/s3-bucket-deployments.d.ts +0 -5
  204. package/lib/api/hotswap/s3-bucket-deployments.js +0 -117
  205. package/lib/api/hotswap/stepfunctions-state-machines.d.ts +0 -4
  206. package/lib/api/hotswap/stepfunctions-state-machines.js +0 -48
  207. package/lib/api/logs/find-cloudwatch-logs.d.ts +0 -25
  208. package/lib/api/logs/find-cloudwatch-logs.js +0 -95
  209. package/lib/api/logs/index.d.ts +0 -2
  210. package/lib/api/logs/logs-monitor.d.ts +0 -76
  211. package/lib/api/logs/logs-monitor.js +0 -187
  212. package/lib/api/plugin/context-provider-plugin.d.ts +0 -6
  213. package/lib/api/plugin/context-provider-plugin.js +0 -7
  214. package/lib/api/plugin/index.d.ts +0 -3
  215. package/lib/api/plugin/index.js +0 -20
  216. package/lib/api/plugin/mode.d.ts +0 -4
  217. package/lib/api/plugin/mode.js +0 -9
  218. package/lib/api/plugin/plugin.d.ts +0 -63
  219. package/lib/api/plugin/plugin.js +0 -102
  220. package/lib/api/resource-import/importer.d.ts +0 -220
  221. package/lib/api/resource-import/importer.js +0 -331
  222. package/lib/api/resource-import/index.d.ts +0 -2
  223. package/lib/api/resource-import/migrator.d.ts +0 -26
  224. package/lib/api/resource-import/migrator.js +0 -71
  225. package/lib/api/stack-events/index.d.ts +0 -3
  226. package/lib/api/stack-events/index.js +0 -20
  227. package/lib/api/stack-events/stack-activity-monitor.d.ts +0 -100
  228. package/lib/api/stack-events/stack-activity-monitor.js +0 -142
  229. package/lib/api/stack-events/stack-event-poller.d.ts +0 -69
  230. package/lib/api/stack-events/stack-event-poller.js +0 -128
  231. package/lib/api/stack-events/stack-progress-monitor.d.ts +0 -48
  232. package/lib/api/stack-events/stack-progress-monitor.js +0 -94
  233. package/lib/api/stack-events/stack-status.d.ts +0 -42
  234. package/lib/api/stack-events/stack-status.js +0 -88
  235. package/lib/api/util/rwlock.d.ts +0 -65
  236. package/lib/api/util/rwlock.js +0 -179
  237. package/lib/api/work-graph/index.d.ts +0 -3
  238. package/lib/api/work-graph/index.js +0 -20
  239. package/lib/api/work-graph/work-graph-builder.d.ts +0 -34
  240. package/lib/api/work-graph/work-graph-builder.js +0 -168
  241. package/lib/api/work-graph/work-graph-types.d.ts +0 -50
  242. package/lib/api/work-graph/work-graph-types.js +0 -13
  243. package/lib/api/work-graph/work-graph.d.ts +0 -72
  244. package/lib/api/work-graph/work-graph.js +0 -346
  245. package/lib/cli/activity-printer/base.d.ts +0 -50
  246. package/lib/cli/activity-printer/base.js +0 -114
  247. package/lib/cli/activity-printer/current.d.ts +0 -26
  248. package/lib/cli/activity-printer/current.js +0 -118
  249. package/lib/cli/activity-printer/display.d.ts +0 -13
  250. package/lib/cli/activity-printer/display.js +0 -80
  251. package/lib/cli/activity-printer/history.d.ts +0 -32
  252. package/lib/cli/activity-printer/history.js +0 -108
  253. package/lib/cli/activity-printer/index.d.ts +0 -3
  254. package/lib/cli/activity-printer/index.js +0 -20
  255. package/lib/notices.d.ts +0 -203
  256. package/lib/notices.js +0 -411
@@ -1,599 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.GarbageCollector = exports.ObjectAsset = exports.ImageAsset = exports.ECR_ISOLATED_TAG = exports.S3_ISOLATED_TAG = void 0;
4
- const chalk = require("chalk");
5
- const promptly = require("promptly");
6
- const toolkit_info_1 = require("../toolkit-info");
7
- const progress_printer_1 = require("./progress-printer");
8
- const stack_refresh_1 = require("./stack-refresh");
9
- const api_1 = require("../../../../@aws-cdk/tmp-toolkit-helpers/src/api");
10
- const private_1 = require("../../../../@aws-cdk/tmp-toolkit-helpers/src/api/io/private");
11
- const mode_1 = require("../plugin/mode");
12
- // Must use a require() otherwise esbuild complains
13
- // eslint-disable-next-line @typescript-eslint/no-require-imports,@typescript-eslint/consistent-type-imports
14
- const pLimit = require('p-limit');
15
- exports.S3_ISOLATED_TAG = 'aws-cdk:isolated';
16
- exports.ECR_ISOLATED_TAG = 'aws-cdk.isolated'; // ':' is not valid in ECR tags
17
- const P_LIMIT = 50;
18
- const DAY = 24 * 60 * 60 * 1000; // Number of milliseconds in a day
19
- /**
20
- * An image asset that lives in the bootstrapped ECR Repository
21
- */
22
- class ImageAsset {
23
- constructor(digest, size, tags, manifest) {
24
- this.digest = digest;
25
- this.size = size;
26
- this.tags = tags;
27
- this.manifest = manifest;
28
- }
29
- getTag(tag) {
30
- return this.tags.find(t => t.includes(tag));
31
- }
32
- hasTag(tag) {
33
- return this.tags.some(t => t.includes(tag));
34
- }
35
- hasIsolatedTag() {
36
- return this.hasTag(exports.ECR_ISOLATED_TAG);
37
- }
38
- getIsolatedTag() {
39
- return this.getTag(exports.ECR_ISOLATED_TAG);
40
- }
41
- isolatedTagBefore(date) {
42
- const dateIsolated = this.dateIsolated();
43
- if (!dateIsolated || dateIsolated == '') {
44
- return false;
45
- }
46
- return new Date(dateIsolated) < date;
47
- }
48
- buildImageTag(inc) {
49
- // isolatedTag will look like "X-aws-cdk.isolated-YYYYY"
50
- return `${inc}-${exports.ECR_ISOLATED_TAG}-${String(Date.now())}`;
51
- }
52
- dateIsolated() {
53
- // isolatedTag will look like "X-aws-cdk.isolated-YYYYY"
54
- return this.getIsolatedTag()?.split('-')[3];
55
- }
56
- }
57
- exports.ImageAsset = ImageAsset;
58
- /**
59
- * An object asset that lives in the bootstrapped S3 Bucket
60
- */
61
- class ObjectAsset {
62
- constructor(bucket, key, size) {
63
- this.bucket = bucket;
64
- this.key = key;
65
- this.size = size;
66
- this.cached_tags = undefined;
67
- }
68
- fileName() {
69
- return this.key.split('.')[0];
70
- }
71
- async allTags(s3) {
72
- if (this.cached_tags) {
73
- return this.cached_tags;
74
- }
75
- const response = await s3.getObjectTagging({ Bucket: this.bucket, Key: this.key });
76
- this.cached_tags = response.TagSet;
77
- return this.cached_tags;
78
- }
79
- getTag(tag) {
80
- if (!this.cached_tags) {
81
- throw new api_1.ToolkitError('Cannot call getTag before allTags');
82
- }
83
- return this.cached_tags.find((t) => t.Key === tag)?.Value;
84
- }
85
- hasTag(tag) {
86
- if (!this.cached_tags) {
87
- throw new api_1.ToolkitError('Cannot call hasTag before allTags');
88
- }
89
- return this.cached_tags.some((t) => t.Key === tag);
90
- }
91
- hasIsolatedTag() {
92
- return this.hasTag(exports.S3_ISOLATED_TAG);
93
- }
94
- isolatedTagBefore(date) {
95
- const tagValue = this.getTag(exports.S3_ISOLATED_TAG);
96
- if (!tagValue || tagValue == '') {
97
- return false;
98
- }
99
- return new Date(tagValue) < date;
100
- }
101
- }
102
- exports.ObjectAsset = ObjectAsset;
103
- /**
104
- * A class to facilitate Garbage Collection of S3 and ECR assets
105
- */
106
- class GarbageCollector {
107
- constructor(props) {
108
- this.props = props;
109
- this.ioHelper = props.ioHelper;
110
- this.garbageCollectS3Assets = ['s3', 'all'].includes(props.type);
111
- this.garbageCollectEcrAssets = ['ecr', 'all'].includes(props.type);
112
- this.permissionToDelete = ['delete-tagged', 'full'].includes(props.action);
113
- this.permissionToTag = ['tag', 'full'].includes(props.action);
114
- this.confirm = props.confirm ?? true;
115
- this.bootstrapStackName = props.bootstrapStackName ?? toolkit_info_1.DEFAULT_TOOLKIT_STACK_NAME;
116
- }
117
- /**
118
- * Perform garbage collection on the resolved environment.
119
- */
120
- async garbageCollect() {
121
- await this.ioHelper.notify(private_1.IO.DEFAULT_TOOLKIT_DEBUG.msg(`${this.garbageCollectS3Assets} ${this.garbageCollectEcrAssets}`));
122
- // SDKs
123
- const sdk = (await this.props.sdkProvider.forEnvironment(this.props.resolvedEnvironment, mode_1.Mode.ForWriting)).sdk;
124
- const cfn = sdk.cloudFormation();
125
- const qualifier = await this.bootstrapQualifier(sdk, this.bootstrapStackName);
126
- const activeAssets = new stack_refresh_1.ActiveAssetCache();
127
- // Grab stack templates first
128
- await (0, stack_refresh_1.refreshStacks)(cfn, this.ioHelper, activeAssets, qualifier);
129
- // Start the background refresh
130
- const backgroundStackRefresh = new stack_refresh_1.BackgroundStackRefresh({
131
- cfn,
132
- ioHelper: this.ioHelper,
133
- activeAssets,
134
- qualifier,
135
- });
136
- backgroundStackRefresh.start();
137
- try {
138
- if (this.garbageCollectS3Assets) {
139
- await this.garbageCollectS3(sdk, activeAssets, backgroundStackRefresh);
140
- }
141
- if (this.garbageCollectEcrAssets) {
142
- await this.garbageCollectEcr(sdk, activeAssets, backgroundStackRefresh);
143
- }
144
- }
145
- catch (err) {
146
- throw new api_1.ToolkitError(err);
147
- }
148
- finally {
149
- backgroundStackRefresh.stop();
150
- }
151
- }
152
- /**
153
- * Perform garbage collection on ECR assets
154
- */
155
- async garbageCollectEcr(sdk, activeAssets, backgroundStackRefresh) {
156
- const ecr = sdk.ecr();
157
- const repo = await this.bootstrapRepositoryName(sdk, this.bootstrapStackName);
158
- const numImages = await this.numImagesInRepo(ecr, repo);
159
- const printer = new progress_printer_1.ProgressPrinter(this.ioHelper, numImages, 1000);
160
- await this.ioHelper.notify(private_1.IO.DEFAULT_TOOLKIT_DEBUG.msg(`Found bootstrap repo ${repo} with ${numImages} images`));
161
- try {
162
- // const batches = 1;
163
- const batchSize = 1000;
164
- const currentTime = Date.now();
165
- const graceDays = this.props.rollbackBufferDays;
166
- await this.ioHelper.notify(private_1.IO.DEFAULT_TOOLKIT_DEBUG.msg(`Parsing through ${numImages} images in batches`));
167
- printer.start();
168
- for await (const batch of this.readRepoInBatches(ecr, repo, batchSize, currentTime)) {
169
- await backgroundStackRefresh.noOlderThan(600000); // 10 mins
170
- const { included: isolated, excluded: notIsolated } = partition(batch, asset => !asset.tags.some(t => activeAssets.contains(t)));
171
- await this.ioHelper.notify(private_1.IO.DEFAULT_TOOLKIT_DEBUG.msg(`${isolated.length} isolated images`));
172
- await this.ioHelper.notify(private_1.IO.DEFAULT_TOOLKIT_DEBUG.msg(`${notIsolated.length} not isolated images`));
173
- await this.ioHelper.notify(private_1.IO.DEFAULT_TOOLKIT_DEBUG.msg(`${batch.length} images total`));
174
- let deletables = isolated;
175
- let taggables = [];
176
- let untaggables = [];
177
- if (graceDays > 0) {
178
- await this.ioHelper.notify(private_1.IO.DEFAULT_TOOLKIT_DEBUG.msg('Filtering out images that are not old enough to delete'));
179
- // We delete images that are not referenced in ActiveAssets and have the Isolated Tag with a date
180
- // earlier than the current time - grace period.
181
- deletables = isolated.filter(img => img.isolatedTagBefore(new Date(currentTime - (graceDays * DAY))));
182
- // We tag images that are not referenced in ActiveAssets and do not have the Isolated Tag.
183
- taggables = isolated.filter(img => !img.hasIsolatedTag());
184
- // We untag images that are referenced in ActiveAssets and currently have the Isolated Tag.
185
- untaggables = notIsolated.filter(img => img.hasIsolatedTag());
186
- }
187
- await this.ioHelper.notify(private_1.IO.DEFAULT_TOOLKIT_DEBUG.msg(`${deletables.length} deletable assets`));
188
- await this.ioHelper.notify(private_1.IO.DEFAULT_TOOLKIT_DEBUG.msg(`${taggables.length} taggable assets`));
189
- await this.ioHelper.notify(private_1.IO.DEFAULT_TOOLKIT_DEBUG.msg(`${untaggables.length} assets to untag`));
190
- if (this.permissionToDelete && deletables.length > 0) {
191
- await this.confirmationPrompt(printer, deletables, 'image');
192
- await this.parallelDeleteEcr(ecr, repo, deletables, printer);
193
- }
194
- if (this.permissionToTag && taggables.length > 0) {
195
- await this.parallelTagEcr(ecr, repo, taggables, printer);
196
- }
197
- if (this.permissionToTag && untaggables.length > 0) {
198
- await this.parallelUntagEcr(ecr, repo, untaggables);
199
- }
200
- printer.reportScannedAsset(batch.length);
201
- }
202
- }
203
- catch (err) {
204
- throw new api_1.ToolkitError(err);
205
- }
206
- finally {
207
- printer.stop();
208
- }
209
- }
210
- /**
211
- * Perform garbage collection on S3 assets
212
- */
213
- async garbageCollectS3(sdk, activeAssets, backgroundStackRefresh) {
214
- const s3 = sdk.s3();
215
- const bucket = await this.bootstrapBucketName(sdk, this.bootstrapStackName);
216
- const numObjects = await this.numObjectsInBucket(s3, bucket);
217
- const printer = new progress_printer_1.ProgressPrinter(this.ioHelper, numObjects, 1000);
218
- await this.ioHelper.notify(private_1.IO.DEFAULT_TOOLKIT_DEBUG.msg(`Found bootstrap bucket ${bucket} with ${numObjects} objects`));
219
- try {
220
- const batchSize = 1000;
221
- const currentTime = Date.now();
222
- const graceDays = this.props.rollbackBufferDays;
223
- await this.ioHelper.notify(private_1.IO.DEFAULT_TOOLKIT_DEBUG.msg(`Parsing through ${numObjects} objects in batches`));
224
- printer.start();
225
- // Process objects in batches of 1000
226
- // This is the batch limit of s3.DeleteObject and we intend to optimize for the "worst case" scenario
227
- // where gc is run for the first time on a long-standing bucket where ~100% of objects are isolated.
228
- for await (const batch of this.readBucketInBatches(s3, bucket, batchSize, currentTime)) {
229
- await backgroundStackRefresh.noOlderThan(600000); // 10 mins
230
- const { included: isolated, excluded: notIsolated } = partition(batch, asset => !activeAssets.contains(asset.fileName()));
231
- await this.ioHelper.notify(private_1.IO.DEFAULT_TOOLKIT_DEBUG.msg(`${isolated.length} isolated assets`));
232
- await this.ioHelper.notify(private_1.IO.DEFAULT_TOOLKIT_DEBUG.msg(`${notIsolated.length} not isolated assets`));
233
- await this.ioHelper.notify(private_1.IO.DEFAULT_TOOLKIT_DEBUG.msg(`${batch.length} objects total`));
234
- let deletables = isolated;
235
- let taggables = [];
236
- let untaggables = [];
237
- if (graceDays > 0) {
238
- await this.ioHelper.notify(private_1.IO.DEFAULT_TOOLKIT_DEBUG.msg('Filtering out assets that are not old enough to delete'));
239
- await this.parallelReadAllTags(s3, batch);
240
- // We delete objects that are not referenced in ActiveAssets and have the Isolated Tag with a date
241
- // earlier than the current time - grace period.
242
- deletables = isolated.filter(obj => obj.isolatedTagBefore(new Date(currentTime - (graceDays * DAY))));
243
- // We tag objects that are not referenced in ActiveAssets and do not have the Isolated Tag.
244
- taggables = isolated.filter(obj => !obj.hasIsolatedTag());
245
- // We untag objects that are referenced in ActiveAssets and currently have the Isolated Tag.
246
- untaggables = notIsolated.filter(obj => obj.hasIsolatedTag());
247
- }
248
- await this.ioHelper.notify(private_1.IO.DEFAULT_TOOLKIT_DEBUG.msg(`${deletables.length} deletable assets`));
249
- await this.ioHelper.notify(private_1.IO.DEFAULT_TOOLKIT_DEBUG.msg(`${taggables.length} taggable assets`));
250
- await this.ioHelper.notify(private_1.IO.DEFAULT_TOOLKIT_DEBUG.msg(`${untaggables.length} assets to untag`));
251
- if (this.permissionToDelete && deletables.length > 0) {
252
- await this.confirmationPrompt(printer, deletables, 'object');
253
- await this.parallelDeleteS3(s3, bucket, deletables, printer);
254
- }
255
- if (this.permissionToTag && taggables.length > 0) {
256
- await this.parallelTagS3(s3, bucket, taggables, currentTime, printer);
257
- }
258
- if (this.permissionToTag && untaggables.length > 0) {
259
- await this.parallelUntagS3(s3, bucket, untaggables);
260
- }
261
- printer.reportScannedAsset(batch.length);
262
- }
263
- }
264
- catch (err) {
265
- throw new api_1.ToolkitError(err);
266
- }
267
- finally {
268
- printer.stop();
269
- }
270
- }
271
- async parallelReadAllTags(s3, objects) {
272
- const limit = pLimit(P_LIMIT);
273
- for (const obj of objects) {
274
- await limit(() => obj.allTags(s3));
275
- }
276
- }
277
- /**
278
- * Untag assets that were previously tagged, but now currently referenced.
279
- * Since this is treated as an implementation detail, we do not print the results in the printer.
280
- */
281
- async parallelUntagEcr(ecr, repo, untaggables) {
282
- const limit = pLimit(P_LIMIT);
283
- for (const img of untaggables) {
284
- const tag = img.getIsolatedTag();
285
- await limit(() => ecr.batchDeleteImage({
286
- repositoryName: repo,
287
- imageIds: [{
288
- imageTag: tag,
289
- }],
290
- }));
291
- }
292
- await this.ioHelper.notify(private_1.IO.DEFAULT_TOOLKIT_DEBUG.msg(`Untagged ${untaggables.length} assets`));
293
- }
294
- /**
295
- * Untag assets that were previously tagged, but now currently referenced.
296
- * Since this is treated as an implementation detail, we do not print the results in the printer.
297
- */
298
- async parallelUntagS3(s3, bucket, untaggables) {
299
- const limit = pLimit(P_LIMIT);
300
- for (const obj of untaggables) {
301
- const tags = await obj.allTags(s3) ?? [];
302
- const updatedTags = tags.filter((tag) => tag.Key !== exports.S3_ISOLATED_TAG);
303
- await limit(() => s3.deleteObjectTagging({
304
- Bucket: bucket,
305
- Key: obj.key,
306
- }));
307
- await limit(() => s3.putObjectTagging({
308
- Bucket: bucket,
309
- Key: obj.key,
310
- Tagging: {
311
- TagSet: updatedTags,
312
- },
313
- }));
314
- }
315
- await this.ioHelper.notify(private_1.IO.DEFAULT_TOOLKIT_DEBUG.msg(`Untagged ${untaggables.length} assets`));
316
- }
317
- /**
318
- * Tag images in parallel using p-limit
319
- */
320
- async parallelTagEcr(ecr, repo, taggables, printer) {
321
- const limit = pLimit(P_LIMIT);
322
- for (let i = 0; i < taggables.length; i++) {
323
- const img = taggables[i];
324
- const tagEcr = async () => {
325
- try {
326
- await ecr.putImage({
327
- repositoryName: repo,
328
- imageDigest: img.digest,
329
- imageManifest: img.manifest,
330
- imageTag: img.buildImageTag(i),
331
- });
332
- }
333
- catch (error) {
334
- // This is a false negative -- an isolated asset is untagged
335
- // likely due to an imageTag collision. We can safely ignore,
336
- // and the isolated asset will be tagged next time.
337
- await this.ioHelper.notify(private_1.IO.DEFAULT_TOOLKIT_DEBUG.msg(`Warning: unable to tag image ${JSON.stringify(img.tags)} with ${img.buildImageTag(i)} due to the following error: ${error}`));
338
- }
339
- };
340
- await limit(() => tagEcr());
341
- }
342
- printer.reportTaggedAsset(taggables);
343
- await this.ioHelper.notify(private_1.IO.DEFAULT_TOOLKIT_DEBUG.msg(`Tagged ${taggables.length} assets`));
344
- }
345
- /**
346
- * Tag objects in parallel using p-limit. The putObjectTagging API does not
347
- * support batch tagging so we must handle the parallelism client-side.
348
- */
349
- async parallelTagS3(s3, bucket, taggables, date, printer) {
350
- const limit = pLimit(P_LIMIT);
351
- for (const obj of taggables) {
352
- await limit(() => s3.putObjectTagging({
353
- Bucket: bucket,
354
- Key: obj.key,
355
- Tagging: {
356
- TagSet: [
357
- {
358
- Key: exports.S3_ISOLATED_TAG,
359
- Value: String(date),
360
- },
361
- ],
362
- },
363
- }));
364
- }
365
- printer.reportTaggedAsset(taggables);
366
- await this.ioHelper.notify(private_1.IO.DEFAULT_TOOLKIT_DEBUG.msg(`Tagged ${taggables.length} assets`));
367
- }
368
- /**
369
- * Delete images in parallel. The deleteImage API supports batches of 100.
370
- */
371
- async parallelDeleteEcr(ecr, repo, deletables, printer) {
372
- const batchSize = 100;
373
- const imagesToDelete = deletables.map(img => ({
374
- imageDigest: img.digest,
375
- }));
376
- try {
377
- const batches = [];
378
- for (let i = 0; i < imagesToDelete.length; i += batchSize) {
379
- batches.push(imagesToDelete.slice(i, i + batchSize));
380
- }
381
- // Delete images in batches
382
- for (const batch of batches) {
383
- await ecr.batchDeleteImage({
384
- imageIds: batch,
385
- repositoryName: repo,
386
- });
387
- const deletedCount = batch.length;
388
- await this.ioHelper.notify(private_1.IO.DEFAULT_TOOLKIT_DEBUG.msg(`Deleted ${deletedCount} assets`));
389
- printer.reportDeletedAsset(deletables.slice(0, deletedCount));
390
- }
391
- }
392
- catch (err) {
393
- await this.ioHelper.notify(private_1.IO.DEFAULT_TOOLKIT_ERROR.msg(`Error deleting images: ${err}`));
394
- }
395
- }
396
- /**
397
- * Delete objects in parallel. The deleteObjects API supports batches of 1000.
398
- */
399
- async parallelDeleteS3(s3, bucket, deletables, printer) {
400
- const batchSize = 1000;
401
- const objectsToDelete = deletables.map(asset => ({
402
- Key: asset.key,
403
- }));
404
- try {
405
- const batches = [];
406
- for (let i = 0; i < objectsToDelete.length; i += batchSize) {
407
- batches.push(objectsToDelete.slice(i, i + batchSize));
408
- }
409
- // Delete objects in batches
410
- for (const batch of batches) {
411
- await s3.deleteObjects({
412
- Bucket: bucket,
413
- Delete: {
414
- Objects: batch,
415
- Quiet: true,
416
- },
417
- });
418
- const deletedCount = batch.length;
419
- await this.ioHelper.notify(private_1.IO.DEFAULT_TOOLKIT_DEBUG.msg(`Deleted ${deletedCount} assets`));
420
- printer.reportDeletedAsset(deletables.slice(0, deletedCount));
421
- }
422
- }
423
- catch (err) {
424
- await this.ioHelper.notify(private_1.IO.DEFAULT_TOOLKIT_DEBUG.msg(chalk.red(`Error deleting objects: ${err}`)));
425
- }
426
- }
427
- async bootstrapBucketName(sdk, bootstrapStackName) {
428
- const toolkitInfo = await toolkit_info_1.ToolkitInfo.lookup(this.props.resolvedEnvironment, sdk, this.ioHelper, bootstrapStackName);
429
- return toolkitInfo.bucketName;
430
- }
431
- async bootstrapRepositoryName(sdk, bootstrapStackName) {
432
- const toolkitInfo = await toolkit_info_1.ToolkitInfo.lookup(this.props.resolvedEnvironment, sdk, this.ioHelper, bootstrapStackName);
433
- return toolkitInfo.repositoryName;
434
- }
435
- async bootstrapQualifier(sdk, bootstrapStackName) {
436
- const toolkitInfo = await toolkit_info_1.ToolkitInfo.lookup(this.props.resolvedEnvironment, sdk, this.ioHelper, bootstrapStackName);
437
- return toolkitInfo.bootstrapStack.parameters.Qualifier;
438
- }
439
- async numObjectsInBucket(s3, bucket) {
440
- let totalCount = 0;
441
- let continuationToken;
442
- do {
443
- const response = await s3.listObjectsV2({
444
- Bucket: bucket,
445
- ContinuationToken: continuationToken,
446
- });
447
- totalCount += response.KeyCount ?? 0;
448
- continuationToken = response.NextContinuationToken;
449
- } while (continuationToken);
450
- return totalCount;
451
- }
452
- async numImagesInRepo(ecr, repo) {
453
- let totalCount = 0;
454
- let nextToken;
455
- do {
456
- const response = await ecr.listImages({
457
- repositoryName: repo,
458
- nextToken: nextToken,
459
- });
460
- totalCount += response.imageIds?.length ?? 0;
461
- nextToken = response.nextToken;
462
- } while (nextToken);
463
- return totalCount;
464
- }
465
- async *readRepoInBatches(ecr, repo, batchSize = 1000, currentTime) {
466
- let continuationToken;
467
- do {
468
- const batch = [];
469
- while (batch.length < batchSize) {
470
- const response = await ecr.listImages({
471
- repositoryName: repo,
472
- nextToken: continuationToken,
473
- });
474
- // No images in the repository
475
- if (!response.imageIds || response.imageIds.length === 0) {
476
- break;
477
- }
478
- // map unique image digest to (possibly multiple) tags
479
- const images = imageMap(response.imageIds ?? []);
480
- const imageIds = Object.keys(images).map(key => ({
481
- imageDigest: key,
482
- }));
483
- const describeImageInfo = await ecr.describeImages({
484
- repositoryName: repo,
485
- imageIds: imageIds,
486
- });
487
- const getImageInfo = await ecr.batchGetImage({
488
- repositoryName: repo,
489
- imageIds: imageIds,
490
- });
491
- const combinedImageInfo = describeImageInfo.imageDetails?.map(imageDetail => {
492
- const matchingImage = getImageInfo.images?.find(img => img.imageId?.imageDigest === imageDetail.imageDigest);
493
- return {
494
- ...imageDetail,
495
- manifest: matchingImage?.imageManifest,
496
- };
497
- });
498
- for (const image of combinedImageInfo ?? []) {
499
- const lastModified = image.imagePushedAt ?? new Date(currentTime);
500
- // Store the image if it was pushed earlier than today - createdBufferDays
501
- if (image.imageDigest && lastModified < new Date(currentTime - (this.props.createdBufferDays * DAY))) {
502
- batch.push(new ImageAsset(image.imageDigest, image.imageSizeInBytes ?? 0, image.imageTags ?? [], image.manifest ?? ''));
503
- }
504
- }
505
- continuationToken = response.nextToken;
506
- if (!continuationToken)
507
- break; // No more images to fetch
508
- }
509
- if (batch.length > 0) {
510
- yield batch;
511
- }
512
- } while (continuationToken);
513
- }
514
- /**
515
- * Generator function that reads objects from the S3 Bucket in batches.
516
- */
517
- async *readBucketInBatches(s3, bucket, batchSize = 1000, currentTime) {
518
- let continuationToken;
519
- do {
520
- const batch = [];
521
- while (batch.length < batchSize) {
522
- const response = await s3.listObjectsV2({
523
- Bucket: bucket,
524
- ContinuationToken: continuationToken,
525
- });
526
- response.Contents?.forEach((obj) => {
527
- const key = obj.Key ?? '';
528
- const size = obj.Size ?? 0;
529
- const lastModified = obj.LastModified ?? new Date(currentTime);
530
- // Store the object if it has a Key and
531
- // if it has not been modified since today - createdBufferDays
532
- if (key && lastModified < new Date(currentTime - (this.props.createdBufferDays * DAY))) {
533
- batch.push(new ObjectAsset(bucket, key, size));
534
- }
535
- });
536
- continuationToken = response.NextContinuationToken;
537
- if (!continuationToken)
538
- break; // No more objects to fetch
539
- }
540
- if (batch.length > 0) {
541
- yield batch;
542
- }
543
- } while (continuationToken);
544
- }
545
- async confirmationPrompt(printer, deletables, type) {
546
- const pluralize = (name, count) => {
547
- return count === 1 ? name : `${name}s`;
548
- };
549
- if (this.confirm) {
550
- const message = [
551
- `Found ${deletables.length} ${pluralize(type, deletables.length)} to delete based off of the following criteria:`,
552
- `- ${type}s have been isolated for > ${this.props.rollbackBufferDays} days`,
553
- `- ${type}s were created > ${this.props.createdBufferDays} days ago`,
554
- '',
555
- 'Delete this batch (yes/no/delete-all)?',
556
- ].join('\n');
557
- printer.pause();
558
- const response = await promptly.prompt(message, { trim: true });
559
- // Anything other than yes/y/delete-all is treated as no
560
- if (!response || !['yes', 'y', 'delete-all'].includes(response.toLowerCase())) {
561
- throw new api_1.ToolkitError('Deletion aborted by user');
562
- }
563
- else if (response.toLowerCase() == 'delete-all') {
564
- this.confirm = false;
565
- }
566
- }
567
- printer.resume();
568
- }
569
- }
570
- exports.GarbageCollector = GarbageCollector;
571
- function partition(xs, pred) {
572
- const result = {
573
- included: [],
574
- excluded: [],
575
- };
576
- for (const x of xs) {
577
- if (pred(x)) {
578
- result.included.push(x);
579
- }
580
- else {
581
- result.excluded.push(x);
582
- }
583
- }
584
- return result;
585
- }
586
- function imageMap(imageIds) {
587
- const images = {};
588
- for (const image of imageIds ?? []) {
589
- if (!image.imageDigest || !image.imageTag) {
590
- continue;
591
- }
592
- if (!images[image.imageDigest]) {
593
- images[image.imageDigest] = [];
594
- }
595
- images[image.imageDigest].push(image.imageTag);
596
- }
597
- return images;
598
- }
599
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2FyYmFnZS1jb2xsZWN0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJnYXJiYWdlLWNvbGxlY3Rvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFHQSwrQkFBK0I7QUFDL0IscUNBQXFDO0FBRXJDLGtEQUEwRTtBQUMxRSx5REFBcUQ7QUFDckQsbURBQTBGO0FBQzFGLDBFQUFnRjtBQUNoRix5RkFBZ0c7QUFDaEcseUNBQXNDO0FBRXRDLG1EQUFtRDtBQUNuRCw0R0FBNEc7QUFDNUcsTUFBTSxNQUFNLEdBQTZCLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQztBQUUvQyxRQUFBLGVBQWUsR0FBRyxrQkFBa0IsQ0FBQztBQUNyQyxRQUFBLGdCQUFnQixHQUFHLGtCQUFrQixDQUFDLENBQUMsK0JBQStCO0FBQ25GLE1BQU0sT0FBTyxHQUFHLEVBQUUsQ0FBQztBQUNuQixNQUFNLEdBQUcsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUMsQ0FBQyxrQ0FBa0M7QUFJbkU7O0dBRUc7QUFDSCxNQUFhLFVBQVU7SUFDckIsWUFDa0IsTUFBYyxFQUNkLElBQVksRUFDWixJQUFjLEVBQ2QsUUFBZ0I7UUFIaEIsV0FBTSxHQUFOLE1BQU0sQ0FBUTtRQUNkLFNBQUksR0FBSixJQUFJLENBQVE7UUFDWixTQUFJLEdBQUosSUFBSSxDQUFVO1FBQ2QsYUFBUSxHQUFSLFFBQVEsQ0FBUTtJQUVsQyxDQUFDO0lBRU8sTUFBTSxDQUFDLEdBQVc7UUFDeEIsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztJQUM5QyxDQUFDO0lBRU8sTUFBTSxDQUFDLEdBQVc7UUFDeEIsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMs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QUUsQ0FBQztRQUNuQixJQUFJLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO1lBQ1osTUFBTSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDMUIsQ0FBQzthQUFNLENBQUM7WUFDTixNQUFNLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUMxQixDQUFDO0lBQ0gsQ0FBQztJQUVELE9BQU8sTUFBTSxDQUFDO0FBQ2hCLENBQUM7QUFFRCxTQUFTLFFBQVEsQ0FBQyxRQUEyQjtJQUMzQyxNQUFNLE1BQU0sR0FBNkIsRUFBRSxDQUFDO0lBQzVDLEtBQUssTUFBTSxLQUFLLElBQUksUUFBUSxJQUFJLEVBQUUsRUFBRSxDQUFDO1FBQ25DLElBQUksQ0FBQyxLQUFLLENBQUMsV0FBVyxJQUFJLENBQUMsS0FBSyxDQUFDLFFBQVEsRUFBRSxDQUFDO1lBQzFDLFNBQVM7UUFDWCxDQUFDO1FBQ0QsSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQztZQUMvQixNQUFNLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxHQUFHLEVBQUUsQ0FBQztRQUNqQyxDQUFDO1FBQ0QsTUFBTSxDQUFDLEtBQUssQ0FBQyxXQUFXLENBQUMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQ2pELENBQUM7SUFDRCxPQUFPLE1BQU0sQ0FBQztBQUNoQixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHR5cGUgKiBhcyBjeGFwaSBmcm9tICdAYXdzLWNkay9jeC1hcGknO1xuaW1wb3J0IHR5cGUgeyBJbWFnZUlkZW50aWZpZXIgfSBmcm9tICdAYXdzLXNkay9jbGllbnQtZWNyJztcbmltcG9ydCB0eXBlIHsgVGFnIH0gZnJvbSAnQGF3cy1zZGsvY2xpZW50LXMzJztcbmltcG9ydCAqIGFzIGNoYWxrIGZyb20gJ2NoYWxrJztcbmltcG9ydCAqIGFzIHByb21wdGx5IGZyb20gJ3Byb21wdGx5JztcbmltcG9ydCB0eXBlIHsgSUVDUkNsaWVudCwgSVMzQ2xpZW50LCBTREssIFNka1Byb3ZpZGVyIH0gZnJvbSAnLi4vYXdzLWF1dGgnO1xuaW1wb3J0IHsgREVGQVVMVF9UT09MS0lUX1NUQUNLX05BTUUsIFRvb2xraXRJbmZvIH0gZnJvbSAnLi4vdG9vbGtpdC1pbmZvJztcbmltcG9ydCB7IFByb2dyZXNzUHJpbnRlciB9IGZyb20gJy4vcHJvZ3Jlc3MtcHJpbnRlcic7XG5pbXBvcnQgeyBBY3RpdmVBc3NldENhY2hlLCBCYWNrZ3JvdW5kU3RhY2tSZWZyZXNoLCByZWZyZXNoU3RhY2tzIH0gZnJvbSAnLi9zdGFjay1yZWZyZXNoJztcbmltcG9ydCB7IFRvb2xraXRFcnJvciB9IGZyb20gJy4uLy4uLy4uLy4uL0Bhd3MtY2RrL3RtcC10b29sa2l0LWhlbHBlcnMvc3JjL2FwaSc7XG5pbXBvcnQgeyBJTywgdHlwZSBJb0hlbHBlciB9IGZyb20gJy4uLy4uLy4uLy4uL0Bhd3MtY2RrL3RtcC10b29sa2l0LWhlbHBlcnMvc3JjL2FwaS9pby9wcml2YXRlJztcbmltcG9ydCB7IE1vZGUgfSBmcm9tICcuLi9wbHVnaW4vbW9kZSc7XG5cbi8vIE11c3QgdXNlIGEgcmVxdWlyZSgpIG90aGVyd2lzZSBlc2J1aWxkIGNvbXBsYWluc1xuLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1yZXF1aXJlLWltcG9ydHMsQHR5cGVzY3JpcHQtZXNsaW50L2NvbnNpc3RlbnQtdHlwZS1pbXBvcnRzXG5jb25zdCBwTGltaXQ6IHR5cGVvZiBpbXBvcnQoJ3AtbGltaXQnKSA9IHJlcXVpcmUoJ3AtbGltaXQnKTtcblxuZXhwb3J0IGNvbnN0IFMzX0lTT0xBVEVEX1RBRyA9ICdhd3MtY2RrOmlzb2xhdGVkJztcbmV4cG9ydCBjb25zdCBFQ1JfSVNPTEFURURfVEFHID0gJ2F3cy1jZGsuaXNvbGF0ZWQnOyAvLyAnOicgaXMgbm90IHZhbGlkIGluIEVDUiB0YWdzXG5jb25zdCBQX0xJTUlUID0gNTA7XG5jb25zdCBEQVkgPSAyNCAqIDYwICogNjAgKiAxMDAwOyAvLyBOdW1iZXIgb2YgbWlsbGlzZWNvbmRzIGluIGEgZGF5XG5cbmV4cG9ydCB0eXBlIEdjQXNzZXQgPSBJbWFnZUFzc2V0IHwgT2JqZWN0QXNzZXQ7XG5cbi8qKlxuICogQW4gaW1hZ2UgYXNzZXQgdGhhdCBsaXZlcyBpbiB0aGUgYm9vdHN0cmFwcGVkIEVDUiBSZXBvc2l0b3J5XG4gKi9cbmV4cG9ydCBjbGFzcyBJbWFnZUFzc2V0IHtcbiAgcHVibGljIGNvbnN0cnVjdG9yKFxuICAgIHB1YmxpYyByZWFkb25seSBkaWdlc3Q6IHN0cmluZyxcbiAgICBwdWJsaWMgcmVhZG9ubHkgc2l6ZTogbnVtYmVyLFxuICAgIHB1YmxpYyByZWFkb25seSB0YWdzOiBzdHJpbmdbXSxcbiAgICBwdWJsaWMgcmVhZG9ubHkgbWFuaWZlc3Q6IHN0cmluZyxcbiAgKSB7XG4gIH1cblxuICBwcml2YXRlIGdldFRhZyh0YWc6IHN0cmluZykge1xuICAgIHJldHVybiB0aGlzLnRhZ3MuZmluZCh0ID0+IHQuaW5jbHVkZXModGFnKSk7XG4gIH1cblxuICBwcml2YXRlIGhhc1RhZyh0YWc6IHN0cmluZykge1xuICAgIHJldHVybiB0aGlzLnRhZ3Muc29tZSh0ID0+IHQuaW5jbHVkZXModGFnKSk7XG4gIH1cblxuICBwdWJsaWMgaGFzSXNvbGF0ZWRUYWcoKSB7XG4gICAgcmV0dXJuIHRoaXMuaGFzVGFnKEVDUl9JU09MQVRFRF9UQUcpO1xuICB9XG5cbiAgcHVibGljIGdldElzb2xhdGVkVGFnKCkge1xuICAgIHJldHVybiB0aGlzLmdldFRhZyhFQ1JfSVNPTEFURURfVEFHKTtcbiAgfVxuXG4gIHB1YmxpYyBpc29sYXRlZFRhZ0JlZm9yZShkYXRlOiBEYXRlKSB7XG4gICAgY29uc3QgZGF0ZUlzb2xhdGVkID0gdGhpcy5kYXRlSXNvbGF0ZWQoKTtcbiAgICBpZiAoIWRhdGVJc29sYXRlZCB8fCBkYXRlSXNvbGF0ZWQgPT0gJycpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgcmV0dXJuIG5ldyBEYXRlKGRhdGVJc29sYXRlZCkgPCBkYXRlO1xuICB9XG5cbiAgcHVibGljIGJ1aWxkSW1hZ2VUYWcoaW5jOiBudW1iZXIpIHtcbiAgICAvLyBpc29sYXRlZFRhZyB3aWxsIGxvb2sgbGlrZSBcIlgtYXdzLWNkay5pc29sYXRlZC1ZWVlZWVwiXG4gICAgcmV0dXJuIGAke2luY30tJHtFQ1JfSVNPTEFURURfVEFHfS0ke1N0cmluZyhEYXRlLm5vdygpKX1gO1xuICB9XG5cbiAgcHVibGljIGRhdGVJc29sYXRlZCgpIHtcbiAgICAvLyBpc29sYXRlZFRhZyB3aWxsIGxvb2sgbGlrZSBcIlgtYXdzLWNkay5pc29sYXRlZC1ZWVlZWVwiXG4gICAgcmV0dXJuIHRoaXMuZ2V0SXNvbGF0ZWRUYWcoKT8uc3BsaXQoJy0nKVszXTtcbiAgfVxufVxuXG4vKipcbiAqIEFuIG9iamVjdCBhc3NldCB0aGF0IGxpdmVzIGluIHRoZSBib290c3RyYXBwZWQgUzMgQnVja2V0XG4gKi9cbmV4cG9ydCBjbGFzcyBPYmplY3RBc3NldCB7XG4gIHByaXZhdGUgY2FjaGVkX3RhZ3M6IFRhZ1tdIHwgdW5kZWZpbmVkID0gdW5kZWZpbmVkO1xuXG4gIHB1YmxpYyBjb25zdHJ1Y3Rvcihwcml2YXRlIHJlYWRvbmx5IGJ1Y2tldDogc3RyaW5nLCBwdWJsaWMgcmVhZG9ubHkga2V5OiBzdHJpbmcsIHB1YmxpYyByZWFkb25seSBzaXplOiBudW1iZXIpIHtcbiAgfVxuXG4gIHB1YmxpYyBmaWxlTmFtZSgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLmtleS5zcGxpdCgnLicpWzBdO1xuICB9XG5cbiAgcHVibGljIGFzeW5jIGFsbFRhZ3MoczM6IElTM0NsaWVudCkge1xuICAgIGlmICh0aGlzLmNhY2hlZF90YWdzKSB7XG4gICAgICByZXR1cm4gdGhpcy5jYWNoZWRfdGFncztcbiAgICB9XG5cbiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHMzLmdldE9iamVjdFRhZ2dpbmcoeyBCdWNrZXQ6IHRoaXMuYnVja2V0LCBLZXk6IHRoaXMua2V5IH0pO1xuICAgIHRoaXMuY2FjaGVkX3RhZ3MgPSByZXNwb25zZS5UYWdTZXQ7XG4gICAgcmV0dXJuIHRoaXMuY2FjaGVkX3RhZ3M7XG4gIH1cblxuICBwcml2YXRlIGdldFRhZyh0YWc6IHN0cmluZykge1xuICAgIGlmICghdGhpcy5jYWNoZWRfdGFncykge1xuICAgICAgdGhyb3cgbmV3IFRvb2xraXRFcnJvcignQ2Fubm90IGNhbGwgZ2V0VGFnIGJlZm9yZSBhbGxUYWdzJyk7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLmNhY2hlZF90YWdzLmZpbmQoKHQ6IGFueSkgPT4gdC5LZXkgPT09IHRhZyk/LlZhbHVlO1xuICB9XG5cbiAgcHJpdmF0ZSBoYXNUYWcodGFnOiBzdHJpbmcpIHtcbiAgICBpZiAoIXRoaXMuY2FjaGVkX3RhZ3MpIHtcbiAgICAgIHRocm93IG5ldyBUb29sa2l0RXJyb3IoJ0Nhbm5vdCBjYWxsIGhhc1RhZyBiZWZvcmUgYWxsVGFncycpO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5jYWNoZWRfdGFncy5zb21lKCh0OiBhbnkpID0+IHQuS2V5ID09PSB0YWcpO1xuICB9XG5cbiAgcHVibGljIGhhc0lzb2xhdGVkVGFnKCkge1xuICAgIHJldHVybiB0aGlzLmhhc1RhZyhTM19JU09MQVRFRF9UQUcpO1xuICB9XG5cbiAgcHVibGljIGlzb2xhdGVkVGFnQmVmb3JlKGRhdGU6IERhdGUpIHtcbiAgICBjb25zdCB0YWdWYWx1ZSA9IHRoaXMuZ2V0VGFnKFMzX0lTT0xBVEVEX1RBRyk7XG4gICAgaWYgKCF0YWdWYWx1ZSB8fCB0YWdWYWx1ZSA9PSAnJykge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICByZXR1cm4gbmV3IERhdGUodGFnVmFsdWUpIDwgZGF0ZTtcbiAgfVxufVxuXG4vKipcbiAqIFByb3BzIGZvciB0aGUgR2FyYmFnZSBDb2xsZWN0b3JcbiAqL1xuaW50ZXJmYWNlIEdhcmJhZ2VDb2xsZWN0b3JQcm9wcyB7XG4gIC8qKlxuICAgKiBUaGUgYWN0aW9uIHRvIHBlcmZvcm0uIFNwZWNpZnkgdGhpcyBpZiB5b3Ugd2FudCB0byBwZXJmb3JtIGEgdHJ1bmNhdGVkIHNldFxuICAgKiBvZiBhY3Rpb25zIGF2YWlsYWJsZS5cbiAgICovXG4gIHJlYWRvbmx5IGFjdGlvbjogJ3ByaW50JyB8ICd0YWcnIHwgJ2RlbGV0ZS10YWdnZWQnIHwgJ2Z1bGwnO1xuXG4gIC8qKlxuICAgKiBUaGUgdHlwZSBvZiBhc3NldCB0byBnYXJiYWdlIGNvbGxlY3QuXG4gICAqL1xuICByZWFkb25seSB0eXBlOiAnczMnIHwgJ2VjcicgfCAnYWxsJztcblxuICAvKipcbiAgICogVGhlIGRheXMgYW4gYXNzZXQgbXVzdCBiZSBpbiBpc29sYXRpb24gYmVmb3JlIGJlaW5nIGFjdHVhbGx5IGRlbGV0ZWQuXG4gICAqL1xuICByZWFkb25seSByb2xsYmFja0J1ZmZlckRheXM6IG51bWJlcjtcblxuICAvKipcbiAgICogUmVmdXNlIGRlbGV0aW9uIG9mIGFueSBhc3NldHMgeW91bmdlciB0aGFuIHRoaXMgbnVtYmVyIG9mIGRheXMuXG4gICAqL1xuICByZWFkb25seSBjcmVhdGVkQnVmZmVyRGF5czogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBUaGUgZW52aXJvbm1lbnQgdG8gZGVwbG95IHRoaXMgc3RhY2sgaW5cbiAgICpcbiAgICogVGhlIGVudmlyb25tZW50IG9uIHRoZSBzdGFjayBhcnRpZmFjdCBtYXkgYmUgdW5yZXNvbHZlZCwgdGhpcyBvbmVcbiAgICogbXVzdCBiZSByZXNvbHZlZC5cbiAgICovXG4gIHJlYWRvbmx5IHJlc29sdmVkRW52aXJvbm1lbnQ6IGN4YXBpLkVudmlyb25tZW50O1xuXG4gIC8qKlxuICAgKiBTREsgcHJvdmlkZXIgKHNlZWRlZCB3aXRoIGRlZmF1bHQgY3JlZGVudGlhbHMpXG4gICAqXG4gICAqIFdpbGwgYmUgdXNlZCB0byBtYWtlIFNESyBjYWxscyB0byBDbG91ZEZvcm1hdGlvbiwgUzMsIGFuZCBFQ1IuXG4gICAqL1xuICByZWFkb25seSBzZGtQcm92aWRlcjogU2RrUHJvdmlkZXI7XG5cbiAgLyoqXG4gICAqIFVzZWQgdG8gc2VuZCBtZXNzYWdlcy5cbiAgICovXG4gIHJlYWRvbmx5IGlvSGVscGVyOiBJb0hlbHBlcjtcblxuICAvKipcbiAgICogVGhlIG5hbWUgb2YgdGhlIGJvb3RzdHJhcCBzdGFjayB0byBsb29rIGZvci5cbiAgICpcbiAgICogQGRlZmF1bHQgREVGQVVMVF9UT09MS0lUX1NUQUNLX05BTUVcbiAgICovXG4gIHJlYWRvbmx5IGJvb3RzdHJhcFN0YWNrTmFtZT86IHN0cmluZztcblxuICAvKipcbiAgICogQ29uZmlybSB3aXRoIHRoZSB1c2VyIGJlZm9yZSBhY3R1YWwgZGVsZXRpb24gaGFwcGVuc1xuICAgKlxuICAgKiBAZGVmYXVsdCB0cnVlXG4gICAqL1xuICByZWFkb25seSBjb25maXJtPzogYm9vbGVhbjtcbn1cblxuLyoqXG4gKiBBIGNsYXNzIHRvIGZhY2lsaXRhdGUgR2FyYmFnZSBDb2xsZWN0aW9uIG9mIFMzIGFuZCBFQ1IgYXNzZXRzXG4gKi9cbmV4cG9ydCBjbGFzcyBHYXJiYWdlQ29sbGVjdG9yIHtcbiAgcHJpdmF0ZSBnYXJiYWdlQ29sbGVjdFMzQXNzZXRzOiBib29sZWFuO1xuICBwcml2YXRlIGdhcmJhZ2VDb2xsZWN0RWNyQXNzZXRzOiBib29sZWFuO1xuICBwcml2YXRlIHBlcm1pc3Npb25Ub0RlbGV0ZTogYm9vbGVhbjtcbiAgcHJpdmF0ZSBwZXJtaXNzaW9uVG9UYWc6IGJvb2xlYW47XG4gIHByaXZhdGUgYm9vdHN0cmFwU3RhY2tOYW1lOiBzdHJpbmc7XG4gIHByaXZhdGUgY29uZmlybTogYm9vbGVhbjtcbiAgcHJpdmF0ZSBpb0hlbHBlcjogSW9IZWxwZXI7XG5cbiAgcHVibGljIGNvbnN0cnVjdG9yKHJlYWRvbmx5IHByb3BzOiBHYXJiYWdlQ29sbGVjdG9yUHJvcHMpIHtcbiAgICB0aGlzLmlvSGVscGVyID0gcHJvcHMuaW9IZWxwZXI7XG5cbiAgICB0aGlzLmdhcmJhZ2VDb2xsZWN0UzNBc3NldHMgPSBbJ3MzJywgJ2FsbCddLmluY2x1ZGVzKHByb3BzLnR5cGUpO1xuICAgIHRoaXMuZ2FyYmFnZUNvbGxlY3RFY3JBc3NldHMgPSBbJ2VjcicsICdhbGwnXS5pbmNsdWRlcyhwcm9wcy50eXBlKTtcblxuICAgIHRoaXMucGVybWlzc2lvblRvRGVsZXRlID0gWydkZWxldGUtdGFnZ2VkJywgJ2Z1bGwnXS5pbmNsdWRlcyhwcm9wcy5hY3Rpb24pO1xuICAgIHRoaXMucGVybWlzc2lvblRvVGFnID0gWyd0YWcnLCAnZnVsbCddLmluY2x1ZGVzKHByb3BzLmFjdGlvbik7XG4gICAgdGhpcy5jb25maXJtID0gcHJvcHMuY29uZmlybSA/PyB0cnVlO1xuXG4gICAgdGhpcy5ib290c3RyYXBTdGFja05hbWUgPSBwcm9wcy5ib290c3RyYXBTdGFja05hbWUgPz8gREVGQVVMVF9UT09MS0lUX1NUQUNLX05BTUU7XG4gIH1cblxuICAvKipcbiAgICogUGVyZm9ybSBnYXJiYWdlIGNvbGxlY3Rpb24gb24gdGhlIHJlc29sdmVkIGVudmlyb25tZW50LlxuICAgKi9cbiAgcHVibGljIGFzeW5jIGdhcmJhZ2VDb2xsZWN0KCkge1xuICAgIGF3YWl0IHRoaXMuaW9IZWxwZXIubm90aWZ5KElPLkRFRkFVTFRfVE9PTEtJVF9ERUJVRy5tc2coYCR7dGhpcy5nYXJiYWdlQ29sbGVjdFMzQXNzZXRzfSAke3RoaXMuZ2FyYmFnZUNvbGxlY3RFY3JBc3NldHN9YCkpO1xuXG4gICAgLy8gU0RLc1xuICAgIGNvbnN0IHNkayA9IChhd2FpdCB0aGlzLnByb3BzLnNka1Byb3ZpZGVyLmZvckVudmlyb25tZW50KHRoaXMucHJvcHMucmVzb2x2ZWRFbnZpcm9ubWVudCwgTW9kZS5Gb3JXcml0aW5nKSkuc2RrO1xuICAgIGNvbnN0IGNmbiA9IHNkay5jbG91ZEZvcm1hdGlvbigpO1xuXG4gICAgY29uc3QgcXVhbGlmaWVyID0gYXdhaXQgdGhpcy5ib290c3RyYXBRdWFsaWZpZXIoc2RrLCB0aGlzLmJvb3RzdHJhcFN0YWNrTmFtZSk7XG4gICAgY29uc3QgYWN0aXZlQXNzZXRzID0gbmV3IEFjdGl2ZUFzc2V0Q2FjaGUoKTtcblxuICAgIC8vIEdyYWIgc3RhY2sgdGVtcGxhdGVzIGZpcnN0XG4gICAgYXdhaXQgcmVmcmVzaFN0YWNrcyhjZm4sIHRoaXMuaW9IZWxwZXIsIGFjdGl2ZUFzc2V0cywgcXVhbGlmaWVyKTtcbiAgICAvLyBTdGFydCB0aGUgYmFja2dyb3VuZCByZWZyZXNoXG4gICAgY29uc3QgYmFja2dyb3VuZFN0YWNrUmVmcmVzaCA9IG5ldyBCYWNrZ3JvdW5kU3RhY2tSZWZyZXNoKHtcbiAgICAgIGNmbixcbiAgICAgIGlvSGVscGVyOiB0aGlzLmlvSGVscGVyLFxuICAgICAgYWN0aXZlQXNzZXRzLFxuICAgICAgcXVhbGlmaWVyLFxuICAgIH0pO1xuICAgIGJhY2tncm91bmRTdGFja1JlZnJlc2guc3RhcnQoKTtcblxuICAgIHRyeSB7XG4gICAgICBpZiAodGhpcy5nYXJiYWdlQ29sbGVjdFMzQXNzZXRzKSB7XG4gICAgICAgIGF3YWl0IHRoaXMuZ2FyYmFnZUNvbGxlY3RTMyhzZGssIGFjdGl2ZUFzc2V0cywgYmFja2dyb3VuZFN0YWNrUmVmcmVzaCk7XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLmdhcmJhZ2VDb2xsZWN0RWNyQXNzZXRzKSB7XG4gICAgICAgIGF3YWl0IHRoaXMuZ2FyYmFnZUNvbGxlY3RFY3Ioc2RrLCBhY3RpdmVBc3NldHMsIGJhY2tncm91bmRTdGFja1JlZnJlc2gpO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycjogYW55KSB7XG4gICAgICB0aHJvdyBuZXcgVG9vbGtpdEVycm9yKGVycik7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIGJhY2tncm91bmRTdGFja1JlZnJlc2guc3RvcCgpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBQZXJmb3JtIGdhcmJhZ2UgY29sbGVjdGlvbiBvbiBFQ1IgYXNzZXRzXG4gICAqL1xuICBwdWJsaWMgYXN5bmMgZ2FyYmFnZUNvbGxlY3RFY3Ioc2RrOiBTREssIGFjdGl2ZUFzc2V0czogQWN0aXZlQXNzZXRDYWNoZSwgYmFja2dyb3VuZFN0YWNrUmVmcmVzaDogQmFja2dyb3VuZFN0YWNrUmVmcmVzaCkge1xuICAgIGNvbnN0IGVjciA9IHNkay5lY3IoKTtcbiAgICBjb25zdCByZXBvID0gYXdhaXQgdGhpcy5ib290c3RyYXBSZXBvc2l0b3J5TmFtZShzZGssIHRoaXMuYm9vdHN0cmFwU3RhY2tOYW1lKTtcbiAgICBjb25zdCBudW1JbWFnZXMgPSBhd2FpdCB0aGlzLm51bUltYWdlc0luUmVwbyhlY3IsIHJlcG8pO1xuICAgIGNvbnN0IHByaW50ZXIgPSBuZXcgUHJvZ3Jlc3NQcmludGVyKHRoaXMuaW9IZWxwZXIsIG51bUltYWdlcywgMTAwMCk7XG5cbiAgICBhd2FpdCB0aGlzLmlvSGVscGVyLm5vdGlmeShJTy5ERUZBVUxUX1RPT0xLSVRfREVCVUcubXNnKGBGb3VuZCBib290c3RyYXAgcmVwbyAke3JlcG99IHdpdGggJHtudW1JbWFnZXN9IGltYWdlc2ApKTtcblxuICAgIHRyeSB7XG4gICAgICAvLyBjb25zdCBiYXRjaGVzID0gMTtcbiAgICAgIGNvbnN0IGJhdGNoU2l6ZSA9IDEwMDA7XG4gICAgICBjb25zdCBjdXJyZW50VGltZSA9IERhdGUubm93KCk7XG4gICAgICBjb25zdCBncmFjZURheXMgPSB0aGlzLnByb3BzLnJvbGxiYWNrQnVmZmVyRGF5cztcblxuICAgICAgYXdhaXQgdGhpcy5pb0hlbHBlci5ub3RpZnkoSU8uREVGQVVMVF9UT09MS0lUX0RFQlVHLm1zZyhgUGFyc2luZyB0aHJvdWdoICR7bnVtSW1hZ2VzfSBpbWFnZXMgaW4gYmF0Y2hlc2ApKTtcblxuICAgICAgcHJpbnRlci5zdGFydCgpO1xuXG4gICAgICBmb3IgYXdhaXQgKGNvbnN0IGJhdGNoIG9mIHRoaXMucmVhZFJlcG9JbkJhdGNoZXMoZWNyLCByZXBvLCBiYXRjaFNpemUsIGN1cnJlbnRUaW1lKSkge1xuICAgICAgICBhd2FpdCBiYWNrZ3JvdW5kU3RhY2tSZWZyZXNoLm5vT2xkZXJUaGFuKDYwMF8wMDApOyAvLyAxMCBtaW5zXG5cbiAgICAgICAgY29uc3QgeyBpbmNsdWRlZDogaXNvbGF0ZWQsIGV4Y2x1ZGVkOiBub3RJc29sYXRlZCB9ID0gcGFydGl0aW9uKGJhdGNoLCBhc3NldCA9PiAhYXNzZXQudGFncy5zb21lKHQgPT4gYWN0aXZlQXNzZXRzLmNvbnRhaW5zKHQpKSk7XG5cbiAgICAgICAgYXdhaXQgdGhpcy5pb0hlbHBlci5ub3RpZnkoSU8uREVGQVVMVF9UT09MS0lUX0RFQlVHLm1zZyhgJHtpc29sYXRlZC5sZW5ndGh9IGlzb2xhdGVkIGltYWdlc2ApKTtcbiAgICAgICAgYXdhaXQgdGhpcy5pb0hlbHBlci5ub3RpZnkoSU8uREVGQVVMVF9UT09MS0lUX0RFQlVHLm1zZyhgJHtub3RJc29sYXRlZC5sZW5ndGh9IG5vdCBpc29sYXRlZCBpbWFnZXNgKSk7XG4gICAgICAgIGF3YWl0IHRoaXMuaW9IZWxwZXIubm90aWZ5KElPLkRFRkFVTFRfVE9PTEtJVF9ERUJVRy5tc2coYCR7YmF0Y2gubGVuZ3RofSBpbWFnZXMgdG90YWxgKSk7XG5cbiAgICAgICAgbGV0IGRlbGV0YWJsZXM6IEltYWdlQXNzZXRbXSA9IGlzb2xhdGVkO1xuICAgICAgICBsZXQgdGFnZ2FibGVzOiBJbWFnZUFzc2V0W10gPSBbXTtcbiAgICAgICAgbGV0IHVudGFnZ2FibGVzOiBJbWFnZUFzc2V0W10gPSBbXTtcblxuICAgICAgICBpZiAoZ3JhY2VEYXlzID4gMCkge1xuICAgICAgICAgIGF3YWl0IHRoaXMuaW9IZWxwZXIubm90aWZ5KElPLkRFRkFVTFRfVE9PTEtJVF9ERUJVRy5tc2coJ0ZpbHRlcmluZyBvdXQgaW1hZ2VzIHRoYXQgYXJlIG5vdCBvbGQgZW5vdWdoIHRvIGRlbGV0ZScpKTtcblxuICAgICAgICAgIC8vIFdlIGRlbGV0ZSBpbWFnZXMgdGhhdCBhcmUgbm90IHJlZmVyZW5jZWQgaW4gQWN0aXZlQXNzZXRzIGFuZCBoYXZlIHRoZSBJc29sYXRlZCBUYWcgd2l0aCBhIGRhdGVcbiAgICAgICAgICAvLyBlYXJsaWVyIHRoYW4gdGhlIGN1cnJlbnQgdGltZSAtIGdyYWNlIHBlcmlvZC5cbiAgICAgICAgICBkZWxldGFibGVzID0gaXNvbGF0ZWQuZmlsdGVyKGltZyA9PiBpbWcuaXNvbGF0ZWRUYWdCZWZvcmUobmV3IERhdGUoY3VycmVudFRpbWUgLSAoZ3JhY2VEYXlzICogREFZKSkpKTtcblxuICAgICAgICAgIC8vIFdlIHRhZyBpbWFnZXMgdGhhdCBhcmUgbm90IHJlZmVyZW5jZWQgaW4gQWN0aXZlQXNzZXRzIGFuZCBkbyBub3QgaGF2ZSB0aGUgSXNvbGF0ZWQgVGFnLlxuICAgICAgICAgIHRhZ2dhYmxlcyA9IGlzb2xhdGVkLmZpbHRlcihpbWcgPT4gIWltZy5oYXNJc29sYXRlZFRhZygpKTtcblxuICAgICAgICAgIC8vIFdlIHVudGFnIGltYWdlcyB0aGF0IGFyZSByZWZlcmVuY2VkIGluIEFjdGl2ZUFzc2V0cyBhbmQgY3VycmVudGx5IGhhdmUgdGhlIElzb2xhdGVkIFRhZy5cbiAgICAgICAgICB1bnRhZ2dhYmxlcyA9IG5vdElzb2xhdGVkLmZpbHRlcihpbWcgPT4gaW1nLmhhc0lzb2xhdGVkVGFnKCkpO1xuICAgICAgICB9XG5cbiAgICAgICAgYXdhaXQgdGhpcy5pb0hlbHBlci5ub3RpZnkoSU8uREVGQVVMVF9UT09MS0lUX0RFQlVHLm1zZyhgJHtkZWxldGFibGVzLmxlbmd0aH0gZGVsZXRhYmxlIGFzc2V0c2ApKTtcbiAgICAgICAgYXdhaXQgdGhpcy5pb0hlbHBlci5ub3RpZnkoSU8uREVGQVVMVF9UT09MS0lUX0RFQlVHLm1zZyhgJHt0YWdnYWJsZXMubGVuZ3RofSB0YWdnYWJsZSBhc3NldHNgKSk7XG4gICAgICAgIGF3YWl0IHRoaXMuaW9IZWxwZXIubm90aWZ5KElPLkRFRkFVTFRfVE9PTEtJVF9ERUJVRy5tc2coYCR7dW50YWdnYWJsZXMubGVuZ3RofSBhc3NldHMgdG8gdW50YWdgKSk7XG5cbiAgICAgICAgaWYgKHRoaXMucGVybWlzc2lvblRvRGVsZXRlICYmIGRlbGV0YWJsZXMubGVuZ3RoID4gMCkge1xuICAgICAgICAgIGF3YWl0IHRoaXMuY29uZmlybWF0aW9uUHJvbXB0KHByaW50ZXIsIGRlbGV0YWJsZXMsICdpbWFnZScpO1xuICAgICAgICAgIGF3YWl0IHRoaXMucGFyYWxsZWxEZWxldGVFY3IoZWNyLCByZXBvLCBkZWxldGFibGVzLCBwcmludGVyKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0aGlzLnBlcm1pc3Npb25Ub1RhZyAmJiB0YWdnYWJsZXMubGVuZ3RoID4gMCkge1xuICAgICAgICAgIGF3YWl0IHRoaXMucGFyYWxsZWxUYWdFY3IoZWNyLCByZXBvLCB0YWdnYWJsZXMsIHByaW50ZXIpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRoaXMucGVybWlzc2lvblRvVGFnICYmIHVudGFnZ2FibGVzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICBhd2FpdCB0aGlzLnBhcmFsbGVsVW50YWdFY3IoZWNyLCByZXBvLCB1bnRhZ2dhYmxlcyk7XG4gICAgICAgIH1cblxuICAgICAgICBwcmludGVyLnJlcG9ydFNjYW5uZWRBc3NldChiYXRjaC5sZW5ndGgpO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycjogYW55KSB7XG4gICAgICB0aHJvdyBuZXcgVG9vbGtpdEVycm9yKGVycik7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIHByaW50ZXIuc3RvcCgpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBQZXJmb3JtIGdhcmJhZ2UgY29sbGVjdGlvbiBvbiBTMyBhc3NldHNcbiAgICovXG4gIHB1YmxpYyBhc3luYyBnYXJiYWdlQ29sbGVjdFMzKHNkazogU0RLLCBhY3RpdmVBc3NldHM6IEFjdGl2ZUFzc2V0Q2FjaGUsIGJhY2tncm91bmRTdGFja1JlZnJlc2g6IEJhY2tncm91bmRTdGFja1JlZnJlc2gpIHtcbiAgICBjb25zdCBzMyA9IHNkay5zMygpO1xuICAgIGNvbnN0IGJ1Y2tldCA9IGF3YWl0IHRoaXMuYm9vdHN0cmFwQnVja2V0TmFtZShzZGssIHRoaXMuYm9vdHN0cmFwU3RhY2tOYW1lKTtcbiAgICBjb25zdCBudW1PYmplY3RzID0gYXdhaXQgdGhpcy5udW1PYmplY3RzSW5CdWNrZXQoczMsIGJ1Y2tldCk7XG4gICAgY29uc3QgcHJpbnRlciA9IG5ldyBQcm9ncmVzc1ByaW50ZXIodGhpcy5pb0hlbHBlciwgbnVtT2JqZWN0cywgMTAwMCk7XG5cbiAgICBhd2FpdCB0aGlzLmlvSGVscGVyLm5vdGlmeShJTy5ERUZBVUxUX1RPT0xLSVRfREVCVUcubXNnKGBGb3VuZCBib290c3RyYXAgYnVja2V0ICR7YnVja2V0fSB3aXRoICR7bnVtT2JqZWN0c30gb2JqZWN0c2ApKTtcblxuICAgIHRyeSB7XG4gICAgICBjb25zdCBiYXRjaFNpemUgPSAxMDAwO1xuICAgICAgY29uc3QgY3VycmVudFRpbWUgPSBEYXRlLm5vdygpO1xuICAgICAgY29uc3QgZ3JhY2VEYXlzID0gdGhpcy5wcm9wcy5yb2xsYmFja0J1ZmZlckRheXM7XG5cbiAgICAgIGF3YWl0IHRoaXMuaW9IZWxwZXIubm90aWZ5KElPLkRFRkFVTFRfVE9PTEtJVF9ERUJVRy5tc2coYFBhcnNpbmcgdGhyb3VnaCAke251bU9iamVjdHN9IG9iamVjdHMgaW4gYmF0Y2hlc2ApKTtcblxuICAgICAgcHJpbnRlci5zdGFydCgpO1xuXG4gICAgICAvLyBQcm9jZXNzIG9iamVjdHMgaW4gYmF0Y2hlcyBvZiAxMDAwXG4gICAgICAvLyBUaGlzIGlzIHRoZSBiYXRjaCBsaW1pdCBvZiBzMy5EZWxldGVPYmplY3QgYW5kIHdlIGludGVuZCB0byBvcHRpbWl6ZSBmb3IgdGhlIFwid29yc3QgY2FzZVwiIHNjZW5hcmlvXG4gICAgICAvLyB3aGVyZSBnYyBpcyBydW4gZm9yIHRoZSBmaXJzdCB0aW1lIG9uIGEgbG9uZy1zdGFuZGluZyBidWNrZXQgd2hlcmUgfjEwMCUgb2Ygb2JqZWN0cyBhcmUgaXNvbGF0ZWQuXG4gICAgICBmb3IgYXdhaXQgKGNvbnN0IGJhdGNoIG9mIHRoaXMucmVhZEJ1Y2tldEluQmF0Y2hlcyhzMywgYnVja2V0LCBiYXRjaFNpemUsIGN1cnJlbnRUaW1lKSkge1xuICAgICAgICBhd2FpdCBiYWNrZ3JvdW5kU3RhY2tSZWZyZXNoLm5vT2xkZXJUaGFuKDYwMF8wMDApOyAvLyAxMCBtaW5zXG5cbiAgICAgICAgY29uc3QgeyBpbmNsdWRlZDogaXNvbGF0ZWQsIGV4Y2x1ZGVkOiBub3RJc29sYXRlZCB9ID0gcGFydGl0aW9uKGJhdGNoLCBhc3NldCA9PiAhYWN0aXZlQXNzZXRzLmNvbnRhaW5zKGFzc2V0LmZpbGVOYW1lKCkpKTtcblxuICAgICAgICBhd2FpdCB0aGlzLmlvSGVscGVyLm5vdGlmeShJTy5ERUZBVUxUX1RPT0xLSVRfREVCVUcubXNnKGAke2lzb2xhdGVkLmxlbmd0aH0gaXNvbGF0ZWQgYXNzZXRzYCkpO1xuICAgICAgICBhd2FpdCB0aGlzLmlvSGVscGVyLm5vdGlmeShJTy5ERUZBVUxUX1RPT0xLSVRfREVCVUcubXNnKGAke25vdElzb2xhdGVkLmxlbmd0aH0gbm90IGlzb2xhdGVkIGFzc2V0c2ApKTtcbiAgICAgICAgYXdhaXQgdGhpcy5pb0hlbHBlci5ub3RpZnkoSU8uREVGQVVMVF9UT09MS0lUX0RFQlVHLm1zZyhgJHtiYXRjaC5sZW5ndGh9IG9iamVjdHMgdG90YWxgKSk7XG5cbiAgICAgICAgbGV0IGRlbGV0YWJsZXM6IE9iamVjdEFzc2V0W10gPSBpc29sYXRlZDtcbiAgICAgICAgbGV0IHRhZ2dhYmxlczogT2JqZWN0QXNzZXRbXSA9IFtdO1xuICAgICAgICBsZXQgdW50YWdnYWJsZXM6IE9iamVjdEFzc2V0W10gPSBbXTtcblxuICAgICAgICBpZiAoZ3JhY2VEYXlzID4gMCkge1xuICAgICAgICAgIGF3YWl0IHRoaXMuaW9IZWxwZXIubm90aWZ5KElPLkRFRkFVTFRfVE9PTEtJVF9ERUJVRy5tc2coJ0ZpbHRlcmluZyBvdXQgYXNzZXRzIHRoYXQgYXJlIG5vdCBvbGQgZW5vdWdoIHRvIGRlbGV0ZScpKTtcbiAgICAgICAgICBhd2FpdCB0aGlzLnBhcmFsbGVsUmVhZEFsbFRhZ3MoczMsIGJhdGNoKTtcblxuICAgICAgICAgIC8vIFdlIGRlbGV0ZSBvYmplY3RzIHRoYXQgYXJlIG5vdCByZWZlcmVuY2VkIGluIEFjdGl2ZUFzc2V0cyBhbmQgaGF2ZSB0aGUgSXNvbGF0ZWQgVGFnIHdpdGggYSBkYXRlXG4gICAgICAgICAgLy8gZWFybGllciB0aGFuIHRoZSBjdXJyZW50IHRpbWUgLSBncmFjZSBwZXJpb2QuXG4gICAgICAgICAgZGVsZXRhYmxlcyA9IGlzb2xhdGVkLmZpbHRlcihvYmogPT4gb2JqLmlzb2xhdGVkVGFnQmVmb3JlKG5ldyBEYXRlKGN1cnJlbnRUaW1lIC0gKGdyYWNlRGF5cyAqIERBWSkpKSk7XG5cbiAgICAgICAgICAvLyBXZSB0YWcgb2JqZWN0cyB0aGF0IGFyZSBub3QgcmVmZXJlbmNlZCBpbiBBY3RpdmVBc3NldHMgYW5kIGRvIG5vdCBoYXZlIHRoZSBJc29sYXRlZCBUYWcuXG4gICAgICAgICAgdGFnZ2FibGVzID0gaXNvbGF0ZWQuZmlsdGVyKG9iaiA9PiAhb2JqLmhhc0lzb2xhdGVkVGFnKCkpO1xuXG4gICAgICAgICAgLy8gV2UgdW50YWcgb2JqZWN0cyB0aGF0IGFyZSByZWZlcmVuY2VkIGluIEFjdGl2ZUFzc2V0cyBhbmQgY3VycmVudGx5IGhhdmUgdGhlIElzb2xhdGVkIFRhZy5cbiAgICAgICAgICB1bnRhZ2dhYmxlcyA9IG5vdElzb2xhdGVkLmZpbHRlcihvYmogPT4gb2JqLmhhc0lzb2xhdGVkVGFnKCkpO1xuICAgICAgICB9XG5cbiAgICAgICAgYXdhaXQgdGhpcy5pb0hlbHBlci5ub3RpZnkoSU8uREVGQVVMVF9UT09MS0lUX0RFQlVHLm1zZyhgJHtkZWxldGFibGVzLmxlbmd0aH0gZGVsZXRhYmxlIGFzc2V0c2ApKTtcbiAgICAgICAgYXdhaXQgdGhpcy5pb0hlbHBlci5ub3RpZnkoSU8uREVGQVVMVF9UT09MS0lUX0RFQlVHLm1zZyhgJHt0YWdnYWJsZXMubGVuZ3RofSB0YWdnYWJsZSBhc3NldHNgKSk7XG4gICAgICAgIGF3YWl0IHRoaXMuaW9IZWxwZXIubm90aWZ5KElPLkRFRkFVTFRfVE9PTEtJVF9ERUJVRy5tc2coYCR7dW50YWdnYWJsZXMubGVuZ3RofSBhc3NldHMgdG8gdW50YWdgKSk7XG5cbiAgICAgICAgaWYgKHRoaXMucGVybWlzc2lvblRvRGVsZXRlICYmIGRlbGV0YWJsZXMubGVuZ3RoID4gMCkge1xuICAgICAgICAgIGF3YWl0IHRoaXMuY29uZmlybWF0aW9uUHJvbXB0KHByaW50ZXIsIGRlbGV0YWJsZXMsICdvYmplY3QnKTtcbiAgICAgICAgICBhd2FpdCB0aGlzLnBhcmFsbGVsRGVsZXRlUzMoczMsIGJ1Y2tldCwgZGVsZXRhYmxlcywgcHJpbnRlcik7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodGhpcy5wZXJtaXNzaW9uVG9UYWcgJiYgdGFnZ2FibGVzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICBhd2FpdCB0aGlzLnBhcmFsbGVsVGFnUzMoczMsIGJ1Y2tldCwgdGFnZ2FibGVzLCBjdXJyZW50VGltZSwgcHJpbnRlcik7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodGhpcy5wZXJtaXNzaW9uVG9UYWcgJiYgdW50YWdnYWJsZXMubGVuZ3RoID4gMCkge1xuICAgICAgICAgIGF3YWl0IHRoaXMucGFyYWxsZWxVbnRhZ1MzKHMzLCBidWNrZXQsIHVudGFnZ2FibGVzKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHByaW50ZXIucmVwb3J0U2Nhbm5lZEFzc2V0KGJhdGNoLmxlbmd0aCk7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXJyOiBhbnkpIHtcbiAgICAgIHRocm93IG5ldyBUb29sa2l0RXJyb3IoZXJyKTtcbiAgICB9IGZpbmFsbHkge1xuICAgICAgcHJpbnRlci5zdG9wKCk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBwYXJhbGxlbFJlYWRBbGxUYWdzKHMzOiBJUzNDbGllbnQsIG9iamVjdHM6IE9iamVjdEFzc2V0W10pIHtcbiAgICBjb25zdCBsaW1pdCA9IHBMaW1pdChQX0xJTUlUKTtcblxuICAgIGZvciAoY29uc3Qgb2JqIG9mIG9iamVjdHMpIHtcbiAgICAgIGF3YWl0IGxpbWl0KCgpID0+IG9iai5hbGxUYWdzKHMzKSk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFVudGFnIGFzc2V0cyB0aGF0IHdlcmUgcHJldmlvdXNseSB0YWdnZWQsIGJ1dCBub3cgY3VycmVudGx5IHJlZmVyZW5jZWQuXG4gICAqIFNpbmNlIHRoaXMgaXMgdHJlYXRlZCBhcyBhbiBpbXBsZW1lbnRhdGlvbiBkZXRhaWwsIHdlIGRvIG5vdCBwcmludCB0aGUgcmVzdWx0cyBpbiB0aGUgcHJpbnRlci5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgcGFyYWxsZWxVbnRhZ0VjcihlY3I6IElFQ1JDbGllbnQsIHJlcG86IHN0cmluZywgdW50YWdnYWJsZXM6IEltYWdlQXNzZXRbXSkge1xuICAgIGNvbnN0IGxpbWl0ID0gcExpbWl0KFBfTElNSVQpO1xuXG4gICAgZm9yIChjb25zdCBpbWcgb2YgdW50YWdnYWJsZXMpIHtcbiAgICAgIGNvbnN0IHRhZyA9IGltZy5nZXRJc29sYXRlZFRhZygpO1xuICAgICAgYXdhaXQgbGltaXQoKCkgPT5cbiAgICAgICAgZWNyLmJhdGNoRGVsZXRlSW1hZ2Uoe1xuICAgICAgICAgIHJlcG9zaXRvcnlOYW1lOiByZXBvLFxuICAgICAgICAgIGltYWdlSWRzOiBbe1xuICAgICAgICAgICAgaW1hZ2VUYWc6IHRhZyxcbiAgICAgICAgICB9XSxcbiAgICAgICAgfSksXG4gICAgICApO1xuICAgIH1cblxuICAgIGF3YWl0IHRoaXMuaW9IZWxwZXIubm90aWZ5KElPLkRFRkFVTFRfVE9PTEtJVF9ERUJVRy5tc2coYFVudGFnZ2VkICR7dW50YWdnYWJsZXMubGVuZ3RofSBhc3NldHNgKSk7XG4gIH1cblxuICAvKipcbiAgICogVW50YWcgYXNzZXRzIHRoYXQgd2VyZSBwcmV2aW91c2x5IHRhZ2dlZCwgYnV0IG5vdyBjdXJyZW50bHkgcmVmZXJlbmNlZC5cbiAgICogU2luY2UgdGhpcyBpcyB0cmVhdGVkIGFzIGFuIGltcGxlbWVudGF0aW9uIGRldGFpbCwgd2UgZG8gbm90IHByaW50IHRoZSByZXN1bHRzIGluIHRoZSBwcmludGVyLlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBwYXJhbGxlbFVudGFnUzMoczM6IElTM0NsaWVudCwgYnVja2V0OiBzdHJpbmcsIHVudGFnZ2FibGVzOiBPYmplY3RBc3NldFtdKSB7XG4gICAgY29uc3QgbGltaXQgPSBwTGltaXQoUF9MSU1JVCk7XG5cbiAgICBmb3IgKGNvbnN0IG9iaiBvZiB1bnRhZ2dhYmxlcykge1xuICAgICAgY29uc3QgdGFncyA9IGF3YWl0IG9iai5hbGxUYWdzKHMzKSA/PyBbXTtcbiAgICAgIGNvbnN0IHVwZGF0ZWRUYWdzID0gdGFncy5maWx0ZXIoKHRhZzogVGFnKSA9PiB0YWcuS2V5ICE9PSBTM19JU09MQVRFRF9UQUcpO1xuICAgICAgYXdhaXQgbGltaXQoKCkgPT5cbiAgICAgICAgczMuZGVsZXRlT2JqZWN0VGFnZ2luZyh7XG4gICAgICAgICAgQnVja2V0OiBidWNrZXQsXG4gICAgICAgICAgS2V5OiBvYmoua2V5LFxuXG4gICAgICAgIH0pLFxuICAgICAgKTtcbiAgICAgIGF3YWl0IGxpbWl0KCgpID0+XG4gICAgICAgIHMzLnB1dE9iamVjdFRhZ2dpbmcoe1xuICAgICAgICAgIEJ1Y2tldDogYnVja2V0LFxuICAgICAgICAgIEtleTogb2JqLmtleSxcbiAgICAgICAgICBUYWdnaW5nOiB7XG4gICAgICAgICAgICBUYWdTZXQ6IHVwZGF0ZWRUYWdzLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0pLFxuICAgICAgKTtcbiAgICB9XG5cbiAgICBhd2FpdCB0aGlzLmlvSGVscGVyLm5vdGlmeShJTy5ERUZBVUxUX1RPT0xLSVRfREVCVUcubXNnKGBVbnRhZ2dlZCAke3VudGFnZ2FibGVzLmxlbmd0aH0gYXNzZXRzYCkpO1xuICB9XG5cbiAgLyoqXG4gICAqIFRhZyBpbWFnZXMgaW4gcGFyYWxsZWwgdXNpbmcgcC1saW1pdFxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBwYXJhbGxlbFRhZ0VjcihlY3I6IElFQ1JDbGllbnQsIHJlcG86IHN0cmluZywgdGFnZ2FibGVzOiBJbWFnZUFzc2V0W10sIHByaW50ZXI6IFByb2dyZXNzUHJpbnRlcikge1xuICAgIGNvbnN0IGxpbWl0ID0gcExpbWl0KFBfTElNSVQpO1xuXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0YWdnYWJsZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGNvbnN0IGltZyA9IHRhZ2dhYmxlc1tpXTtcbiAgICAgIGNvbnN0IHRhZ0VjciA9IGFzeW5jICgpID0+IHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBhd2FpdCBlY3IucHV0SW1hZ2Uoe1xuICAgICAgICAgICAgcmVwb3NpdG9yeU5hbWU6IHJlcG8sXG4gICAgICAgICAgICBpbWFnZURpZ2VzdDogaW1nLmRpZ2VzdCxcbiAgICAgICAgICAgIGltYWdlTWFuaWZlc3Q6IGltZy5tYW5pZmVzdCxcbiAgICAgICAgICAgIGltYWdlVGFnOiBpbWcuYnVpbGRJbWFnZVRhZyhpKSxcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICAvLyBUaGlzIGlzIGEgZmFsc2UgbmVnYXRpdmUgLS0gYW4gaXNvbGF0ZWQgYXNzZXQgaXMgdW50YWdnZWRcbiAgICAgICAgICAvLyBsaWtlbHkgZHVlIHRvIGFuIGltYWdlVGFnIGNvbGxpc2lvbi4gV2UgY2FuIHNhZmVseSBpZ25vcmUsXG4gICAgICAgICAgLy8gYW5kIHRoZSBpc29sYXRlZCBhc3NldCB3aWxsIGJlIHRhZ2dlZCBuZXh0IHRpbWUuXG4gICAgICAgICAgYXdhaXQgdGhpcy5pb0hlbHBlci5ub3RpZnkoSU8uREVGQVVMVF9UT09MS0lUX0RFQlVHLm1zZyhgV2FybmluZzogdW5hYmxlIHRvIHRhZyBpbWFnZSAke0pTT04uc3RyaW5naWZ5KGltZy50YWdzKX0gd2l0aCAke2ltZy5idWlsZEltYWdlVGFnKGkpfSBkdWUgdG8gdGhlIGZvbGxvd2luZyBlcnJvcjogJHtlcnJvcn1gKSk7XG4gICAgICAgIH1cbiAgICAgIH07XG4gICAgICBhd2FpdCBsaW1pdCgoKSA9PiB0YWdFY3IoKSk7XG4gICAgfVxuXG4gICAgcHJpbnRlci5yZXBvcnRUYWdnZWRBc3NldCh0YWdnYWJsZXMpO1xuICAgIGF3YWl0IHRoaXMuaW9IZWxwZXIubm90aWZ5KElPLkRFRkFVTFRfVE9PTEtJVF9ERUJVRy5tc2coYFRhZ2dlZCAke3RhZ2dhYmxlcy5sZW5ndGh9IGFzc2V0c2ApKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUYWcgb2JqZWN0cyBpbiBwYXJhbGxlbCB1c2luZyBwLWxpbWl0LiBUaGUgcHV0T2JqZWN0VGFnZ2luZyBBUEkgZG9lcyBub3RcbiAgICogc3VwcG9ydCBiYXRjaCB0YWdnaW5nIHNvIHdlIG11c3QgaGFuZGxlIHRoZSBwYXJhbGxlbGlzbSBjbGllbnQtc2lkZS5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgcGFyYWxsZWxUYWdTMyhzMzogSVMzQ2xpZW50LCBidWNrZXQ6IHN0cmluZywgdGFnZ2FibGVzOiBPYmplY3RBc3NldFtdLCBkYXRlOiBudW1iZXIsIHByaW50ZXI6IFByb2dyZXNzUHJpbnRlcikge1xuICAgIGNvbnN0IGxpbWl0ID0gcExpbWl0KFBfTElNSVQpO1xuXG4gICAgZm9yIChjb25zdCBvYmogb2YgdGFnZ2FibGVzKSB7XG4gICAgICBhd2FpdCBsaW1pdCgoKSA9PlxuICAgICAgICBzMy5wdXRPYmplY3RUYWdnaW5nKHtcbiAgICAgICAgICBCdWNrZXQ6IGJ1Y2tldCxcbiAgICAgICAgICBLZXk6IG9iai5rZXksXG4gICAgICAgICAgVGFnZ2luZzoge1xuICAgICAgICAgICAgVGFnU2V0OiBbXG4gICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBLZXk6IFMzX0lTT0xBVEVEX1RBRyxcbiAgICAgICAgICAgICAgICBWYWx1ZTogU3RyaW5nKGRhdGUpLFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgXSxcbiAgICAgICAgICB9LFxuICAgICAgICB9KSxcbiAgICAgICk7XG4gICAgfVxuXG4gICAgcHJpbnRlci5yZXBvcnRUYWdnZWRBc3NldCh0YWdnYWJsZXMpO1xuICAgIGF3YWl0IHRoaXMuaW9IZWxwZXIubm90aWZ5KElPLkRFRkFVTFRfVE9PTEtJVF9ERUJVRy5tc2coYFRhZ2dlZCAke3RhZ2dhYmxlcy5sZW5ndGh9IGFzc2V0c2ApKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZWxldGUgaW1hZ2VzIGluIHBhcmFsbGVsLiBUaGUgZGVsZXRlSW1hZ2UgQVBJIHN1cHBvcnRzIGJhdGNoZXMgb2YgMTAwLlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBwYXJhbGxlbERlbGV0ZUVjcihlY3I6IElFQ1JDbGllbnQsIHJlcG86IHN0cmluZywgZGVsZXRhYmxlczogSW1hZ2VBc3NldFtdLCBwcmludGVyOiBQcm9ncmVzc1ByaW50ZXIpIHtcbiAgICBjb25zdCBiYXRjaFNpemUgPSAxMDA7XG4gICAgY29uc3QgaW1hZ2VzVG9EZWxldGUgPSBkZWxldGFibGVzLm1hcChpbWcgPT4gKHtcbiAgICAgIGltYWdlRGlnZXN0OiBpbWcuZGlnZXN0LFxuICAgIH0pKTtcblxuICAgIHRyeSB7XG4gICAgICBjb25zdCBiYXRjaGVzID0gW107XG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGltYWdlc1RvRGVsZXRlLmxlbmd0aDsgaSArPSBiYXRjaFNpemUpIHtcbiAgICAgICAgYmF0Y2hlcy5wdXNoKGltYWdlc1RvRGVsZXRlLnNsaWNlKGksIGkgKyBiYXRjaFNpemUpKTtcbiAgICAgIH1cbiAgICAgIC8vIERlbGV0ZSBpbWFnZXMgaW4gYmF0Y2hlc1xuICAgICAgZm9yIChjb25zdCBiYXRjaCBvZiBiYXRjaGVzKSB7XG4gICAgICAgIGF3YWl0IGVjci5iYXRjaERlbGV0ZUltYWdlKHtcbiAgICAgICAgICBpbWFnZUlkczogYmF0Y2gsXG4gICAgICAgICAgcmVwb3NpdG9yeU5hbWU6IHJlcG8sXG4gICAgICAgIH0pO1xuXG4gICAgICAgIGNvbnN0IGRlbGV0ZWRDb3VudCA9IGJhdGNoLmxlbmd0aDtcbiAgICAgICAgYXdhaXQgdGhpcy5pb0hlbHBlci5ub3RpZnkoSU8uREVGQVVMVF9UT09MS0lUX0RFQlVHLm1zZyhgRGVsZXRlZCAke2RlbGV0ZWRDb3VudH0gYXNzZXRzYCkpO1xuICAgICAgICBwcmludGVyLnJlcG9ydERlbGV0ZWRBc3NldChkZWxldGFibGVzLnNsaWNlKDAsIGRlbGV0ZWRDb3VudCkpO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgYXdhaXQgdGhpcy5pb0hlbHBlci5ub3RpZnkoSU8uREVGQVVMVF9UT09MS0lUX0VSUk9SLm1zZyhgRXJyb3IgZGVsZXRpbmcgaW1hZ2VzOiAke2Vycn1gKSk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIERlbGV0ZSBvYmplY3RzIGluIHBhcmFsbGVsLiBUaGUgZGVsZXRlT2JqZWN0cyBBUEkgc3VwcG9ydHMgYmF0Y2hlcyBvZiAxMDAwLlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBwYXJhbGxlbERlbGV0ZVMzKHMzOiBJUzNDbGllbnQsIGJ1Y2tldDogc3RyaW5nLCBkZWxldGFibGVzOiBPYmplY3RBc3NldFtdLCBwcmludGVyOiBQcm9ncmVzc1ByaW50ZXIpIHtcbiAgICBjb25zdCBiYXRjaFNpemUgPSAxMDAwO1xuICAgIGNvbnN0IG9iamVjdHNUb0RlbGV0ZSA9IGRlbGV0YWJsZXMubWFwKGFzc2V0ID0+ICh7XG4gICAgICBLZXk6IGFzc2V0LmtleSxcbiAgICB9KSk7XG5cbiAgICB0cnkge1xuICAgICAgY29uc3QgYmF0Y2hlcyA9IFtdO1xuICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBvYmplY3RzVG9EZWxldGUubGVuZ3RoOyBpICs9IGJhdGNoU2l6ZSkge1xuICAgICAgICBiYXRjaGVzLnB1c2gob2JqZWN0c1RvRGVsZXRlLnNsaWNlKGksIGkgKyBiYXRjaFNpemUpKTtcbiAgICAgIH1cbiAgICAgIC8vIERlbGV0ZSBvYmplY3RzIGluIGJhdGNoZXNcbiAgICAgIGZvciAoY29uc3QgYmF0Y2ggb2YgYmF0Y2hlcykge1xuICAgICAgICBhd2FpdCBzMy5kZWxldGVPYmplY3RzKHtcbiAgICAgICAgICBCdWNrZXQ6IGJ1Y2tldCxcbiAgICAgICAgICBEZWxldGU6IHtcbiAgICAgICAgICAgIE9iamVjdHM6IGJhdGNoLFxuICAgICAgICAgICAgUXVpZXQ6IHRydWUsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgY29uc3QgZGVsZXRlZENvdW50ID0gYmF0Y2gubGVuZ3RoO1xuICAgICAgICBhd2FpdCB0aGlzLmlvSGVscGVyLm5vdGlmeShJTy5ERUZBVUxUX1RPT0xLSVRfREVCVUcubXNnKGBEZWxldGVkICR7ZGVsZXRlZENvdW50fSBhc3NldHNgKSk7XG4gICAgICAgIHByaW50ZXIucmVwb3J0RGVsZXRlZEFzc2V0KGRlbGV0YWJsZXMuc2xpY2UoMCwgZGVsZXRlZENvdW50KSk7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICBhd2FpdCB0aGlzLmlvSGVscGVyLm5vdGlmeShJTy5ERUZBVUxUX1RPT0xLSVRfREVCVUcubXNnKGNoYWxrLnJlZChgRXJyb3IgZGVsZXRpbmcgb2JqZWN0czogJHtlcnJ9YCkpKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGJvb3RzdHJhcEJ1Y2tldE5hbWUoc2RrOiBTREssIGJvb3RzdHJhcFN0YWNrTmFtZTogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBjb25zdCB0b29sa2l0SW5mbyA9IGF3YWl0IFRvb2xraXRJbmZvLmxvb2t1cCh0aGlzLnByb3BzLnJlc29sdmVkRW52aXJvbm1lbnQsIHNkaywgdGhpcy5pb0hlbHBlciwgYm9vdHN0cmFwU3RhY2tOYW1lKTtcbiAgICByZXR1cm4gdG9vbGtpdEluZm8uYnVja2V0TmFtZTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgYm9vdHN0cmFwUmVwb3NpdG9yeU5hbWUoc2RrOiBTREssIGJvb3RzdHJhcFN0YWNrTmFtZTogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBjb25zdCB0b29sa2l0SW5mbyA9IGF3YWl0IFRvb2xraXRJbmZvLmxvb2t1cCh0aGlzLnByb3BzLnJlc29sdmVkRW52aXJvbm1lbnQsIHNkaywgdGhpcy5pb0hlbHBlciwgYm9vdHN0cmFwU3RhY2tOYW1lKTtcbiAgICByZXR1cm4gdG9vbGtpdEluZm8ucmVwb3NpdG9yeU5hbWU7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGJvb3RzdHJhcFF1YWxpZmllcihzZGs6IFNESywgYm9vdHN0cmFwU3RhY2tOYW1lOiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZyB8IHVuZGVmaW5lZD4ge1xuICAgIGNvbnN0IHRvb2xraXRJbmZvID0gYXdhaXQgVG9vbGtpdEluZm8ubG9va3VwKHRoaXMucHJvcHMucmVzb2x2ZWRFbnZpcm9ubWVudCwgc2RrLCB0aGlzLmlvSGVscGVyLCBib290c3RyYXBTdGFja05hbWUpO1xuICAgIHJldHVybiB0b29sa2l0SW5mby5ib290c3RyYXBTdGFjay5wYXJhbWV0ZXJzLlF1YWxpZmllcjtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgbnVtT2JqZWN0c0luQnVja2V0KHMzOiBJUzNDbGllbnQsIGJ1Y2tldDogc3RyaW5nKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICBsZXQgdG90YWxDb3VudCA9IDA7XG4gICAgbGV0IGNvbnRpbnVhdGlvblRva2VuOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG5cbiAgICBkbyB7XG4gICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHMzLmxpc3RPYmplY3RzVjIoe1xuICAgICAgICBCdWNrZXQ6IGJ1Y2tldCxcbiAgICAgICAgQ29udGludWF0aW9uVG9rZW46IGNvbnRpbnVhdGlvblRva2VuLFxuICAgICAgfSk7XG5cbiAgICAgIHRvdGFsQ291bnQgKz0gcmVzcG9uc2UuS2V5Q291bnQgPz8gMDtcbiAgICAgIGNvbnRpbnVhdGlvblRva2VuID0gcmVzcG9uc2UuTmV4dENvbnRpbnVhdGlvblRva2VuO1xuICAgIH0gd2hpbGUgKGNvbnRpbnVhdGlvblRva2VuKTtcblxuICAgIHJldHVybiB0b3RhbENvdW50O1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBudW1JbWFnZXNJblJlcG8oZWNyOiBJRUNSQ2xpZW50LCByZXBvOiBzdHJpbmcpOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIGxldCB0b3RhbENvdW50ID0gMDtcbiAgICBsZXQgbmV4dFRva2VuOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG5cbiAgICBkbyB7XG4gICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGVjci5saXN0SW1hZ2VzKHtcbiAgICAgICAgcmVwb3NpdG9yeU5hbWU6IHJlcG8sXG4gICAgICAgIG5leHRUb2tlbjogbmV4dFRva2VuLFxuICAgICAgfSk7XG5cbiAgICAgIHRvdGFsQ291bnQgKz0gcmVzcG9uc2UuaW1hZ2VJZHM/Lmxlbmd0aCA/PyAwO1xuICAgICAgbmV4dFRva2VuID0gcmVzcG9uc2UubmV4dFRva2VuO1xuICAgIH0gd2hpbGUgKG5leHRUb2tlbik7XG5cbiAgICByZXR1cm4gdG90YWxDb3VudDtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgKnJlYWRSZXBvSW5CYXRjaGVzKGVjcjogSUVDUkNsaWVudCwgcmVwbzogc3RyaW5nLCBiYXRjaFNpemU6IG51bWJlciA9IDEwMDAsIGN1cnJlbnRUaW1lOiBudW1iZXIpOiBBc3luY0dlbmVyYXRvcjxJbWFnZUFzc2V0W10+IHtcbiAgICBsZXQgY29udGludWF0aW9uVG9rZW46IHN0cmluZyB8IHVuZGVmaW5lZDtcblxuICAgIGRvIHtcbiAgICAgIGNvbnN0IGJhdGNoOiBJbWFnZUFzc2V0W10gPSBbXTtcblxuICAgICAgd2hpbGUgKGJhdGNoLmxlbmd0aCA8IGJhdGNoU2l6ZSkge1xuICAgICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGVjci5saXN0SW1hZ2VzKHtcbiAgICAgICAgICByZXBvc2l0b3J5TmFtZTogcmVwbyxcbiAgICAgICAgICBuZXh0VG9rZW46IGNvbnRpbnVhdGlvblRva2VuLFxuICAgICAgICB9KTtcblxuICAgICAgICAvLyBObyBpbWFnZXMgaW4gdGhlIHJlcG9zaXRvcnlcbiAgICAgICAgaWYgKCFyZXNwb25zZS5pbWFnZUlkcyB8fCByZXNwb25zZS5pbWFnZUlkcy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIG1hcCB1bmlxdWUgaW1hZ2UgZGlnZXN0IHRvIChwb3NzaWJseSBtdWx0aXBsZSkgdGFnc1xuICAgICAgICBjb25zdCBpbWFnZXMgPSBpbWFnZU1hcChyZXNwb25zZS5pbWFnZUlkcyA/PyBbXSk7XG5cbiAgICAgICAgY29uc3QgaW1hZ2VJZHMgPSBPYmplY3Qua2V5cyhpbWFnZXMpLm1hcChrZXkgPT4gKHtcbiAgICAgICAgICBpbWFnZURpZ2VzdDoga2V5LFxuICAgICAgICB9KSk7XG5cbiAgICAgICAgY29uc3QgZGVzY3JpYmVJbWFnZUluZm8gPSBhd2FpdCBlY3IuZGVzY3JpYmVJbWFnZXMoe1xuICAgICAgICAgIHJlcG9zaXRvcnlOYW1lOiByZXBvLFxuICAgICAgICAgIGltYWdlSWRzOiBpbWFnZUlkcyxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgY29uc3QgZ2V0SW1hZ2VJbmZvID0gYXdhaXQgZWNyLmJhdGNoR2V0SW1hZ2Uoe1xuICAgICAgICAgIHJlcG9zaXRvcnlOYW1lOiByZXBvLFxuICAgICAgICAgIGltYWdlSWRzOiBpbWFnZUlkcyxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgY29uc3QgY29tYmluZWRJbWFnZUluZm8gPSBkZXNjcmliZUltYWdlSW5mby5pbWFnZURldGFpbHM/Lm1hcChpbWFnZURldGFpbCA9PiB7XG4gICAgICAgICAgY29uc3QgbWF0Y2hpbmdJbWFnZSA9IGdldEltYWdlSW5mby5pbWFnZXM/LmZpbmQoXG4gICAgICAgICAgICBpbWcgPT4gaW1nLmltYWdlSWQ/LmltYWdlRGlnZXN0ID09PSBpbWFnZURldGFpbC5pbWFnZURpZ2VzdCxcbiAgICAgICAgICApO1xuXG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIC4uLmltYWdlRGV0YWlsLFxuICAgICAgICAgICAgbWFuaWZlc3Q6IG1hdGNoaW5nSW1hZ2U/LmltYWdlTWFuaWZlc3QsXG4gICAgICAgICAgfTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgZm9yIChjb25zdCBpbWFnZSBvZiBjb21iaW5lZEltYWdlSW5mbyA/PyBbXSkge1xuICAgICAgICAgIGNvbnN0IGxhc3RNb2RpZmllZCA9IGltYWdlLmltYWdlUHVzaGVkQXQgPz8gbmV3IERhdGUoY3VycmVudFRpbWUpO1xuICAgICAgICAgIC8vIFN0b3JlIHRoZSBpbWFnZSBpZiBpdCB3YXMgcHVzaGVkIGVhcmxpZXIgdGhhbiB0b2RheSAtIGNyZWF0ZWRCdWZmZXJEYXlzXG4gICAgICAgICAgaWYgKGltYWdlLmltYWdlRGlnZXN0ICYmIGxhc3RNb2RpZmllZCA8IG5ldyBEYXRlKGN1cnJlbnRUaW1lIC0gKHRoaXMucHJvcHMuY3JlYXRlZEJ1ZmZlckRheXMgKiBEQVkpKSkge1xuICAgICAgICAgICAgYmF0Y2gucHVzaChuZXcgSW1hZ2VBc3NldChpbWFnZS5pbWFnZURpZ2VzdCwgaW1hZ2UuaW1hZ2VTaXplSW5CeXRlcyA/PyAwLCBpbWFnZS5pbWFnZVRhZ3MgPz8gW10sIGltYWdlLm1hbmlmZXN0ID8/ICcnKSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgY29udGludWF0aW9uVG9rZW4gPSByZXNwb25zZS5uZXh0VG9rZW47XG5cbiAgICAgICAgaWYgKCFjb250aW51YXRpb25Ub2tlbikgYnJlYWs7IC8vIE5vIG1vcmUgaW1hZ2VzIHRvIGZldGNoXG4gICAgICB9XG5cbiAgICAgIGlmIChiYXRjaC5sZW5ndGggPiAwKSB7XG4gICAgICAgIHlpZWxkIGJhdGNoO1xuICAgICAgfVxuICAgIH0gd2hpbGUgKGNvbnRpbnVhdGlvblRva2VuKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZW5lcmF0b3IgZnVuY3Rpb24gdGhhdCByZWFkcyBvYmplY3RzIGZyb20gdGhlIFMzIEJ1Y2tldCBpbiBiYXRjaGVzLlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyAqcmVhZEJ1Y2tldEluQmF0Y2hlcyhzMzogSVMzQ2xpZW50LCBidWNrZXQ6IHN0cmluZywgYmF0Y2hTaXplOiBudW1iZXIgPSAxMDAwLCBjdXJyZW50VGltZTogbnVtYmVyKTogQXN5bmNHZW5lcmF0b3I8T2JqZWN0QXNzZXRbXT4ge1xuICAgIGxldCBjb250aW51YXRpb25Ub2tlbjogc3RyaW5nIHwgdW5kZWZpbmVkO1xuXG4gICAgZG8ge1xuICAgICAgY29uc3QgYmF0Y2g6IE9iamVjdEFzc2V0W10gPSBbXTtcblxuICAgICAgd2hpbGUgKGJhdGNoLmxlbmd0aCA8IGJhdGNoU2l6ZSkge1xuICAgICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHMzLmxpc3RPYmplY3RzVjIoe1xuICAgICAgICAgIEJ1Y2tldDogYnVja2V0LFxuICAgICAgICAgIENvbnRpbnVhdGlvblRva2VuOiBjb250aW51YXRpb25Ub2tlbixcbiAgICAgICAgfSk7XG5cbiAgICAgICAgcmVzcG9uc2UuQ29udGVudHM/LmZvckVhY2goKG9iajogYW55KSA9PiB7XG4gICAgICAgICAgY29uc3Qga2V5ID0gb2JqLktleSA/PyAnJztcbiAgICAgICAgICBjb25zdCBzaXplID0gb2JqLlNpemUgPz8gMDtcbiAgICAgICAgICBjb25zdCBsYXN0TW9kaWZpZWQgPSBvYmouTGFzdE1vZGlmaWVkID8/IG5ldyBEYXRlKGN1cnJlbnRUaW1lKTtcbiAgICAgICAgICAvLyBTdG9yZSB0aGUgb2JqZWN0IGlmIGl0IGhhcyBhIEtleSBhbmRcbiAgICAgICAgICAvLyBpZiBpdCBoYXMgbm90IGJlZW4gbW9kaWZpZWQgc2luY2UgdG9kYXkgLSBjcmVhdGVkQnVmZmVyRGF5c1xuICAgICAgICAgIGlmIChrZXkgJiYgbGFzdE1vZGlmaWVkIDwgbmV3IERhdGUoY3VycmVudFRpbWUgLSAodGhpcy5wcm9wcy5jcmVhdGVkQnVmZmVyRGF5cyAqIERBWSkpKSB7XG4gICAgICAgICAgICBiYXRjaC5wdXNoKG5ldyBPYmplY3RBc3NldChidWNrZXQsIGtleSwgc2l6ZSkpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG5cbiAgICAgICAgY29udGludWF0aW9uVG9rZW4gPSByZXNwb25zZS5OZXh0Q29udGludWF0aW9uVG9rZW47XG5cbiAgICAgICAgaWYgKCFjb250aW51YXRpb25Ub2tlbikgYnJlYWs7IC8vIE5vIG1vcmUgb2JqZWN0cyB0byBmZXRjaFxuICAgICAgfVxuXG4gICAgICBpZiAoYmF0Y2gubGVuZ3RoID4gMCkge1xuICAgICAgICB5aWVsZCBiYXRjaDtcbiAgICAgIH1cbiAgICB9IHdoaWxlIChjb250aW51YXRpb25Ub2tlbik7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGNvbmZpcm1hdGlvblByb21wdChwcmludGVyOiBQcm9ncmVzc1ByaW50ZXIsIGRlbGV0YWJsZXM6IEdjQXNzZXRbXSwgdHlwZTogc3RyaW5nKSB7XG4gICAgY29uc3QgcGx1cmFsaXplID0gKG5hbWU6IHN0cmluZywgY291bnQ6IG51bWJlcik6IHN0cmluZyA9PiB7XG4gICAgICByZXR1cm4gY291bnQgPT09IDEgPyBuYW1lIDogYCR7bmFtZX1zYDtcbiAgICB9O1xuXG4gICAgaWYgKHRoaXMuY29uZmlybSkge1xuICAgICAgY29uc3QgbWVzc2FnZSA9IFtcbiAgICAgICAgYEZvdW5kICR7ZGVsZXRhYmxlcy5sZW5ndGh9ICR7cGx1cmFsaXplKHR5cGUsIGRlbGV0YWJsZXMubGVuZ3RoKX0gdG8gZGVsZXRlIGJhc2VkIG9mZiBvZiB0aGUgZm9sbG93aW5nIGNyaXRlcmlhOmAsXG4gICAgICAgIGAtICR7dHlwZX1zIGhhdmUgYmVlbiBpc29sYXRlZCBmb3IgPiAke3RoaXMucHJvcHMucm9sbGJhY2tCdWZmZXJEYXlzfSBkYXlzYCxcbiAgICAgICAgYC0gJHt0eXBlfXMgd2VyZSBjcmVhdGVkID4gJHt0aGlzLnByb3BzLmNyZWF0ZWRCdWZmZXJEYXlzfSBkYXlzIGFnb2AsXG4gICAgICAgICcnLFxuICAgICAgICAnRGVsZXRlIHRoaXMgYmF0Y2ggKHllcy9uby9kZWxldGUtYWxsKT8nLFxuICAgICAgXS5qb2luKCdcXG4nKTtcbiAgICAgIHByaW50ZXIucGF1c2UoKTtcbiAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgcHJvbXB0bHkucHJvbXB0KG1lc3NhZ2UsXG4gICAgICAgIHsgdHJpbTogdHJ1ZSB9LFxuICAgICAgKTtcblxuICAgICAgLy8gQW55dGhpbmcgb3RoZXIgdGhhbiB5ZXMveS9kZWxldGUtYWxsIGlzIHRyZWF0ZWQgYXMgbm9cbiAgICAgIGlmICghcmVzcG9uc2UgfHwgIVsneWVzJywgJ3knLCAnZGVsZXRlLWFsbCddLmluY2x1ZGVzKHJlc3BvbnNlLnRvTG93ZXJDYXNlKCkpKSB7XG4gICAgICAgIHRocm93IG5ldyBUb29sa2l0RXJyb3IoJ0RlbGV0aW9uIGFib3J0ZWQgYnkgdXNlcicpO1xuICAgICAgfSBlbHNlIGlmIChyZXNwb25zZS50b0xvd2VyQ2FzZSgpID09ICdkZWxldGUtYWxsJykge1xuICAgICAgICB0aGlzLmNvbmZpcm0gPSBmYWxzZTtcbiAgICAgIH1cbiAgICB9XG4gICAgcHJpbnRlci5yZXN1bWUoKTtcbiAgfVxufVxuXG5mdW5jdGlvbiBwYXJ0aXRpb248QT4oeHM6IEl0ZXJhYmxlPEE+LCBwcmVkOiAoeDogQSkgPT4gYm9vbGVhbik6IHsgaW5jbHVkZWQ6IEFbXTsgZXhjbHVkZWQ6IEFbXSB9IHtcbiAgY29uc3QgcmVzdWx0ID0ge1xuICAgIGluY2x1ZGVkOiBbXSBhcyBBW10sXG4gICAgZXhjbHVkZWQ6IFtdIGFzIEFbXSxcbiAgfTtcblxuICBmb3IgKGNvbnN0IHggb2YgeHMpIHtcbiAgICBpZiAocHJlZCh4KSkge1xuICAgICAgcmVzdWx0LmluY2x1ZGVkLnB1c2goeCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJlc3VsdC5leGNsdWRlZC5wdXNoKHgpO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiByZXN1bHQ7XG59XG5cbmZ1bmN0aW9uIGltYWdlTWFwKGltYWdlSWRzOiBJbWFnZUlkZW50aWZpZXJbXSkge1xuICBjb25zdCBpbWFnZXM6IFJlY29yZDxzdHJpbmcsIHN0cmluZ1tdPiA9IHt9O1xuICBmb3IgKGNvbnN0IGltYWdlIG9mIGltYWdlSWRzID8/IFtdKSB7XG4gICAgaWYgKCFpbWFnZS5pbWFnZURpZ2VzdCB8fCAhaW1hZ2UuaW1hZ2VUYWcpIHtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cbiAgICBpZiAoIWltYWdlc1tpbWFnZS5pbWFnZURpZ2VzdF0pIHtcbiAgICAgIGltYWdlc1tpbWFnZS5pbWFnZURpZ2VzdF0gPSBbXTtcbiAgICB9XG4gICAgaW1hZ2VzW2ltYWdlLmltYWdlRGlnZXN0XS5wdXNoKGltYWdlLmltYWdlVGFnKTtcbiAgfVxuICByZXR1cm4gaW1hZ2VzO1xufVxuIl19