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