@cloudsnorkel/cdk-github-runners 0.9.4 → 0.9.6

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 (99) hide show
  1. package/.gitattributes +5 -3
  2. package/.jsii +332 -284
  3. package/API.md +55 -19
  4. package/README.md +135 -65
  5. package/assets/{providers/image-builders → image-builders}/aws-image-builder/delete-ami.lambda/index.js +2 -2
  6. package/assets/{providers/image-builders → image-builders}/aws-image-builder/filter-failed-builds.lambda/index.js +1 -1
  7. package/assets/image-builders/aws-image-builder/reaper.lambda/index.js +163 -0
  8. package/assets/{providers/image-builders → image-builders}/aws-image-builder/versioner.lambda/index.js +2 -2
  9. package/cdk.json +10 -0
  10. package/lib/access.js +1 -1
  11. package/lib/image-builders/api.js +47 -0
  12. package/lib/{providers/image-builders → image-builders}/aws-image-builder/ami.d.ts +2 -3
  13. package/lib/image-builders/aws-image-builder/ami.js +93 -0
  14. package/lib/{providers/image-builders → image-builders}/aws-image-builder/builder.d.ts +10 -3
  15. package/lib/image-builders/aws-image-builder/builder.js +568 -0
  16. package/lib/image-builders/aws-image-builder/common.js +46 -0
  17. package/lib/{providers/image-builders → image-builders}/aws-image-builder/container.d.ts +1 -1
  18. package/lib/image-builders/aws-image-builder/container.js +63 -0
  19. package/lib/{providers/image-builders → image-builders}/aws-image-builder/delete-ami-function.d.ts +1 -1
  20. package/lib/image-builders/aws-image-builder/delete-ami-function.js +23 -0
  21. package/lib/image-builders/aws-image-builder/delete-ami.lambda.js +87 -0
  22. package/lib/{providers/image-builders → image-builders}/aws-image-builder/deprecated/ami.d.ts +4 -4
  23. package/lib/image-builders/aws-image-builder/deprecated/ami.js +240 -0
  24. package/lib/{providers/image-builders → image-builders}/aws-image-builder/deprecated/common.d.ts +1 -1
  25. package/lib/image-builders/aws-image-builder/deprecated/common.js +144 -0
  26. package/lib/{providers/image-builders → image-builders}/aws-image-builder/deprecated/container.d.ts +3 -3
  27. package/lib/image-builders/aws-image-builder/deprecated/container.js +222 -0
  28. package/lib/{providers/image-builders → image-builders}/aws-image-builder/deprecated/index.js +1 -1
  29. package/lib/{providers/image-builders → image-builders}/aws-image-builder/deprecated/linux-components.d.ts +1 -1
  30. package/lib/image-builders/aws-image-builder/deprecated/linux-components.js +172 -0
  31. package/lib/{providers/image-builders → image-builders}/aws-image-builder/deprecated/windows-components.d.ts +1 -1
  32. package/lib/image-builders/aws-image-builder/deprecated/windows-components.js +126 -0
  33. package/lib/{providers/image-builders → image-builders}/aws-image-builder/filter-failed-builds-function.d.ts +1 -1
  34. package/lib/image-builders/aws-image-builder/filter-failed-builds-function.js +23 -0
  35. package/lib/image-builders/aws-image-builder/filter-failed-builds.lambda.js +18 -0
  36. package/lib/{providers/image-builders → image-builders}/aws-image-builder/index.js +1 -1
  37. package/lib/image-builders/aws-image-builder/reaper-function.d.ts +13 -0
  38. package/lib/image-builders/aws-image-builder/reaper-function.js +23 -0
  39. package/lib/image-builders/aws-image-builder/reaper.lambda.d.ts +1 -0
  40. package/lib/image-builders/aws-image-builder/reaper.lambda.js +149 -0
  41. package/lib/{providers/image-builders → image-builders}/aws-image-builder/versioner-function.d.ts +1 -1
  42. package/lib/image-builders/aws-image-builder/versioner-function.js +23 -0
  43. package/lib/image-builders/aws-image-builder/versioner.lambda.js +96 -0
  44. package/lib/{providers/image-builders → image-builders}/codebuild-deprecated.d.ts +5 -5
  45. package/lib/image-builders/codebuild-deprecated.js +373 -0
  46. package/lib/{providers/image-builders → image-builders}/codebuild.d.ts +2 -2
  47. package/lib/image-builders/codebuild.js +289 -0
  48. package/lib/{providers/image-builders → image-builders}/common.d.ts +6 -4
  49. package/lib/{providers/image-builders → image-builders}/common.js +1 -1
  50. package/lib/{providers/image-builders → image-builders}/components.d.ts +8 -2
  51. package/lib/image-builders/components.js +568 -0
  52. package/lib/{providers/image-builders → image-builders}/index.js +1 -1
  53. package/lib/{providers/image-builders → image-builders}/static.d.ts +1 -1
  54. package/lib/image-builders/static.js +58 -0
  55. package/lib/providers/codebuild.d.ts +1 -1
  56. package/lib/providers/codebuild.js +4 -4
  57. package/lib/providers/common.js +3 -3
  58. package/lib/providers/ec2.d.ts +2 -2
  59. package/lib/providers/ec2.js +4 -4
  60. package/lib/providers/ecs.d.ts +1 -1
  61. package/lib/providers/ecs.js +3 -3
  62. package/lib/providers/fargate.d.ts +1 -1
  63. package/lib/providers/fargate.js +4 -4
  64. package/lib/providers/index.d.ts +1 -1
  65. package/lib/providers/index.js +2 -2
  66. package/lib/providers/lambda.d.ts +1 -1
  67. package/lib/providers/lambda.js +4 -4
  68. package/lib/runner.d.ts +3 -3
  69. package/lib/runner.js +5 -5
  70. package/lib/secrets.js +1 -1
  71. package/package.json +12 -10
  72. package/lib/providers/image-builders/api.js +0 -47
  73. package/lib/providers/image-builders/aws-image-builder/ami.js +0 -81
  74. package/lib/providers/image-builders/aws-image-builder/builder.js +0 -520
  75. package/lib/providers/image-builders/aws-image-builder/common.js +0 -46
  76. package/lib/providers/image-builders/aws-image-builder/container.js +0 -63
  77. package/lib/providers/image-builders/aws-image-builder/delete-ami-function.js +0 -23
  78. package/lib/providers/image-builders/aws-image-builder/delete-ami.lambda.js +0 -87
  79. package/lib/providers/image-builders/aws-image-builder/deprecated/ami.js +0 -240
  80. package/lib/providers/image-builders/aws-image-builder/deprecated/common.js +0 -144
  81. package/lib/providers/image-builders/aws-image-builder/deprecated/container.js +0 -222
  82. package/lib/providers/image-builders/aws-image-builder/deprecated/linux-components.js +0 -172
  83. package/lib/providers/image-builders/aws-image-builder/deprecated/windows-components.js +0 -129
  84. package/lib/providers/image-builders/aws-image-builder/filter-failed-builds-function.js +0 -23
  85. package/lib/providers/image-builders/aws-image-builder/filter-failed-builds.lambda.js +0 -18
  86. package/lib/providers/image-builders/aws-image-builder/versioner-function.js +0 -23
  87. package/lib/providers/image-builders/aws-image-builder/versioner.lambda.js +0 -96
  88. package/lib/providers/image-builders/codebuild-deprecated.js +0 -373
  89. package/lib/providers/image-builders/codebuild.js +0 -287
  90. package/lib/providers/image-builders/components.js +0 -535
  91. package/lib/providers/image-builders/static.js +0 -58
  92. /package/lib/{providers/image-builders → image-builders}/api.d.ts +0 -0
  93. /package/lib/{providers/image-builders → image-builders}/aws-image-builder/common.d.ts +0 -0
  94. /package/lib/{providers/image-builders → image-builders}/aws-image-builder/delete-ami.lambda.d.ts +0 -0
  95. /package/lib/{providers/image-builders → image-builders}/aws-image-builder/deprecated/index.d.ts +0 -0
  96. /package/lib/{providers/image-builders → image-builders}/aws-image-builder/filter-failed-builds.lambda.d.ts +0 -0
  97. /package/lib/{providers/image-builders → image-builders}/aws-image-builder/index.d.ts +0 -0
  98. /package/lib/{providers/image-builders → image-builders}/aws-image-builder/versioner.lambda.d.ts +0 -0
  99. /package/lib/{providers/image-builders → image-builders}/index.d.ts +0 -0
@@ -0,0 +1,568 @@
1
+ "use strict";
2
+ var _a;
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.RunnerImageComponent = void 0;
5
+ const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
6
+ const path = require("path");
7
+ const aws_cdk_lib_1 = require("aws-cdk-lib");
8
+ const aws_image_builder_1 = require("./aws-image-builder");
9
+ const providers_1 = require("../providers");
10
+ /**
11
+ * Components are used to build runner images. They can run commands in the image, copy files into the image, and run some Docker commands.
12
+ */
13
+ class RunnerImageComponent {
14
+ /**
15
+ * Define a custom component that can run commands in the image, copy files into the image, and run some Docker commands.
16
+ *
17
+ * The order of operations is (1) assets (2) commands (3) docker commands.
18
+ *
19
+ * Use this to customize the image for the runner.
20
+ *
21
+ * **WARNING:** Docker commands are not guaranteed to be included before the next component
22
+ */
23
+ static custom(props) {
24
+ return new class extends RunnerImageComponent {
25
+ get name() {
26
+ if (props.name && !props.name.match(/[a-zA-Z0-9\-]/)) {
27
+ throw new Error(`Invalid component name: ${props.name}. Name must only contain alphanumeric characters and dashes.`);
28
+ }
29
+ return `Custom-${props.name ?? 'Undefined'}`;
30
+ }
31
+ getCommands(_os, _architecture) {
32
+ return props.commands ?? [];
33
+ }
34
+ getAssets(_os, _architecture) {
35
+ return props.assets ?? [];
36
+ }
37
+ getDockerCommands(_os, _architecture) {
38
+ return props.dockerCommands ?? [];
39
+ }
40
+ }();
41
+ }
42
+ /**
43
+ * A component to install the required packages for the runner.
44
+ */
45
+ static requiredPackages() {
46
+ return new class extends RunnerImageComponent {
47
+ constructor() {
48
+ super(...arguments);
49
+ this.name = 'RequiredPackages';
50
+ }
51
+ getCommands(os, architecture) {
52
+ if (os.is(providers_1.Os.LINUX_UBUNTU)) {
53
+ let archUrl;
54
+ if (architecture.is(providers_1.Architecture.X86_64)) {
55
+ archUrl = 'amd64';
56
+ }
57
+ else if (architecture.is(providers_1.Architecture.ARM64)) {
58
+ archUrl = 'arm64';
59
+ }
60
+ else {
61
+ throw new Error(`Unsupported architecture for required packages: ${architecture.name}`);
62
+ }
63
+ return [
64
+ 'apt-get update',
65
+ 'DEBIAN_FRONTEND=noninteractive apt-get upgrade -y',
66
+ 'DEBIAN_FRONTEND=noninteractive apt-get install -y curl sudo jq bash zip unzip iptables software-properties-common ca-certificates',
67
+ `curl -sfLo /tmp/amazon-cloudwatch-agent.deb https://s3.amazonaws.com/amazoncloudwatch-agent/ubuntu/${archUrl}/latest/amazon-cloudwatch-agent.deb`,
68
+ 'dpkg -i -E /tmp/amazon-cloudwatch-agent.deb',
69
+ 'rm /tmp/amazon-cloudwatch-agent.deb',
70
+ ];
71
+ }
72
+ else if (os.is(providers_1.Os.LINUX_AMAZON_2)) {
73
+ return [
74
+ 'yum update -y',
75
+ 'yum install -y jq tar gzip bzip2 which binutils zip unzip sudo shadow-utils',
76
+ ];
77
+ }
78
+ else if (os.is(providers_1.Os.WINDOWS)) {
79
+ return [
80
+ '$p = Start-Process msiexec.exe -PassThru -Wait -ArgumentList \'/i https://s3.amazonaws.com/amazoncloudwatch-agent/windows/amd64/latest/amazon-cloudwatch-agent.msi /qn\'',
81
+ 'if ($p.ExitCode -ne 0) { throw "Exit code is $p.ExitCode" }',
82
+ ];
83
+ }
84
+ throw new Error(`Unsupported OS for required packages: ${os.name}`);
85
+ }
86
+ };
87
+ }
88
+ /**
89
+ * A component to prepare the required runner user.
90
+ */
91
+ static runnerUser() {
92
+ return new class extends RunnerImageComponent {
93
+ constructor() {
94
+ super(...arguments);
95
+ this.name = 'RunnerUser';
96
+ }
97
+ getCommands(os, _architecture) {
98
+ if (os.is(providers_1.Os.LINUX_UBUNTU)) {
99
+ return [
100
+ 'addgroup runner',
101
+ 'adduser --system --disabled-password --home /home/runner --ingroup runner runner',
102
+ 'usermod -aG sudo runner',
103
+ 'echo "%sudo ALL=(ALL:ALL) NOPASSWD: ALL" > /etc/sudoers.d/runner',
104
+ ];
105
+ }
106
+ else if (os.is(providers_1.Os.LINUX_AMAZON_2)) {
107
+ return [
108
+ '/usr/sbin/groupadd runner',
109
+ '/usr/sbin/useradd --system --shell /usr/sbin/nologin --home-dir /home/runner --gid runner runner',
110
+ 'mkdir -p /home/runner',
111
+ 'chown runner /home/runner',
112
+ 'echo "%runner ALL=(ALL:ALL) NOPASSWD: ALL" > /etc/sudoers.d/runner',
113
+ ];
114
+ }
115
+ else if (os.is(providers_1.Os.WINDOWS)) {
116
+ return [];
117
+ }
118
+ throw new Error(`Unsupported OS for runner user: ${os.name}`);
119
+ }
120
+ };
121
+ }
122
+ /**
123
+ * A component to install the AWS CLI.
124
+ */
125
+ static awsCli() {
126
+ return new class extends RunnerImageComponent {
127
+ constructor() {
128
+ super(...arguments);
129
+ this.name = 'AwsCli';
130
+ }
131
+ getCommands(os, architecture) {
132
+ if (os.is(providers_1.Os.LINUX_UBUNTU) || os.is(providers_1.Os.LINUX_AMAZON_2)) {
133
+ let archUrl;
134
+ if (architecture.is(providers_1.Architecture.X86_64)) {
135
+ archUrl = 'x86_64';
136
+ }
137
+ else if (architecture.is(providers_1.Architecture.ARM64)) {
138
+ archUrl = 'aarch64';
139
+ }
140
+ else {
141
+ throw new Error(`Unsupported architecture for awscli: ${architecture.name}`);
142
+ }
143
+ return [
144
+ `curl -fsSL "https://awscli.amazonaws.com/awscli-exe-linux-${archUrl}.zip" -o awscliv2.zip`,
145
+ 'unzip -q awscliv2.zip',
146
+ './aws/install',
147
+ 'rm -rf awscliv2.zip aws',
148
+ ];
149
+ }
150
+ else if (os.is(providers_1.Os.WINDOWS)) {
151
+ return [
152
+ '$p = Start-Process msiexec.exe -PassThru -Wait -ArgumentList \'/i https://awscli.amazonaws.com/AWSCLIV2.msi /qn\'',
153
+ 'if ($p.ExitCode -ne 0) { throw "Exit code is $p.ExitCode" }',
154
+ ];
155
+ }
156
+ throw new Error(`Unknown os/architecture combo for awscli: ${os.name}/${architecture.name}`);
157
+ }
158
+ }();
159
+ }
160
+ /**
161
+ * A component to install the GitHub CLI.
162
+ */
163
+ static githubCli() {
164
+ return new class extends RunnerImageComponent {
165
+ constructor() {
166
+ super(...arguments);
167
+ this.name = 'GithubCli';
168
+ }
169
+ getCommands(os, architecture) {
170
+ if (os.is(providers_1.Os.LINUX_UBUNTU)) {
171
+ return [
172
+ 'curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg',
173
+ 'echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] ' +
174
+ ' https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null',
175
+ 'apt-get update',
176
+ 'DEBIAN_FRONTEND=noninteractive apt-get install -y gh',
177
+ ];
178
+ }
179
+ else if (os.is(providers_1.Os.LINUX_AMAZON_2)) {
180
+ return [
181
+ 'curl -fsSSL https://cli.github.com/packages/rpm/gh-cli.repo -o /etc/yum.repos.d/gh-cli.repo',
182
+ 'yum install -y gh',
183
+ ];
184
+ }
185
+ else if (os.is(providers_1.Os.WINDOWS)) {
186
+ return [
187
+ 'cmd /c curl -w "%{redirect_url}" -fsS https://github.com/cli/cli/releases/latest > $Env:TEMP\\latest-gh',
188
+ '$LatestUrl = Get-Content $Env:TEMP\\latest-gh',
189
+ '$GH_VERSION = ($LatestUrl -Split \'/\')[-1].substring(1)',
190
+ 'Invoke-WebRequest -UseBasicParsing -Uri "https://github.com/cli/cli/releases/download/v${GH_VERSION}/gh_${GH_VERSION}_windows_amd64.msi" -OutFile gh.msi',
191
+ '$p = Start-Process msiexec.exe -PassThru -Wait -ArgumentList \'/i gh.msi /qn\'',
192
+ 'if ($p.ExitCode -ne 0) { throw "Exit code is $p.ExitCode" }',
193
+ 'del gh.msi',
194
+ ];
195
+ }
196
+ throw new Error(`Unknown os/architecture combo for github cli: ${os.name}/${architecture.name}`);
197
+ }
198
+ }();
199
+ }
200
+ /**
201
+ * A component to install the GitHub CLI.
202
+ */
203
+ static git() {
204
+ return new class extends RunnerImageComponent {
205
+ constructor() {
206
+ super(...arguments);
207
+ this.name = 'Git';
208
+ }
209
+ getCommands(os, architecture) {
210
+ if (os.is(providers_1.Os.LINUX_UBUNTU)) {
211
+ return [
212
+ 'add-apt-repository ppa:git-core/ppa',
213
+ 'apt-get update',
214
+ 'DEBIAN_FRONTEND=noninteractive apt-get install -y git',
215
+ ];
216
+ }
217
+ else if (os.is(providers_1.Os.LINUX_AMAZON_2)) {
218
+ return [
219
+ 'yum install -y git',
220
+ ];
221
+ }
222
+ else if (os.is(providers_1.Os.WINDOWS)) {
223
+ return [
224
+ 'cmd /c curl -w "%{redirect_url}" -fsS https://github.com/git-for-windows/git/releases/latest > $Env:TEMP\\latest-git',
225
+ '$LatestUrl = Get-Content $Env:TEMP\\latest-git',
226
+ '$GIT_VERSION = ($LatestUrl -Split \'/\')[-1].substring(1)',
227
+ '$GIT_VERSION_SHORT = ($GIT_VERSION -Split \'.windows.\')[0]',
228
+ '$GIT_REVISION = ($GIT_VERSION -Split \'.windows.\')[1]',
229
+ 'If ($GIT_REVISION -gt 1) {$GIT_VERSION_SHORT = "$GIT_VERSION_SHORT.$GIT_REVISION"}',
230
+ 'Invoke-WebRequest -UseBasicParsing -Uri https://github.com/git-for-windows/git/releases/download/v${GIT_VERSION}/Git-${GIT_VERSION_SHORT}-64-bit.exe -OutFile git-setup.exe',
231
+ '$p = Start-Process git-setup.exe -PassThru -Wait -ArgumentList \'/VERYSILENT\'',
232
+ 'if ($p.ExitCode -ne 0) { throw "Exit code is $p.ExitCode" }',
233
+ 'del git-setup.exe',
234
+ ];
235
+ }
236
+ throw new Error(`Unknown os/architecture combo for git: ${os.name}/${architecture.name}`);
237
+ }
238
+ }();
239
+ }
240
+ /**
241
+ * A component to install the GitHub Actions Runner. This is the actual executable that connects to GitHub to ask for jobs and then execute them.
242
+ *
243
+ * @param runnerVersion The version of the runner to install. Usually you would set this to latest.
244
+ */
245
+ static githubRunner(runnerVersion) {
246
+ return new class extends RunnerImageComponent {
247
+ constructor() {
248
+ super(...arguments);
249
+ this.name = 'GithubRunner';
250
+ }
251
+ getCommands(os, architecture) {
252
+ if (os.is(providers_1.Os.LINUX_UBUNTU) || os.is(providers_1.Os.LINUX_AMAZON_2)) {
253
+ let versionCommand;
254
+ if (runnerVersion.is(providers_1.RunnerVersion.latest())) {
255
+ versionCommand = 'RUNNER_VERSION=`curl -w "%{redirect_url}" -fsS https://github.com/actions/runner/releases/latest | grep -oE "[^/v]+$"`';
256
+ }
257
+ else {
258
+ versionCommand = `RUNNER_VERSION='${runnerVersion.version}'`;
259
+ }
260
+ let archUrl;
261
+ if (architecture.is(providers_1.Architecture.X86_64)) {
262
+ archUrl = 'x64';
263
+ }
264
+ else if (architecture.is(providers_1.Architecture.ARM64)) {
265
+ archUrl = 'arm64';
266
+ }
267
+ else {
268
+ throw new Error(`Unsupported architecture for GitHub Runner: ${architecture.name}`);
269
+ }
270
+ let commands = [
271
+ versionCommand,
272
+ `curl -fsSLO "https://github.com/actions/runner/releases/download/v\${RUNNER_VERSION}/actions-runner-linux-${archUrl}-\${RUNNER_VERSION}.tar.gz"`,
273
+ `tar -C /home/runner -xzf "actions-runner-linux-${archUrl}-\${RUNNER_VERSION}.tar.gz"`,
274
+ `rm actions-runner-linux-${archUrl}-\${RUNNER_VERSION}.tar.gz`,
275
+ `echo -n ${runnerVersion.version} > /home/runner/RUNNER_VERSION`,
276
+ ];
277
+ if (os.is(providers_1.Os.LINUX_UBUNTU)) {
278
+ commands.push('/home/runner/bin/installdependencies.sh');
279
+ }
280
+ else if (os.is(providers_1.Os.LINUX_AMAZON_2)) {
281
+ commands.push('yum install -y openssl-libs krb5-libs zlib libicu60');
282
+ }
283
+ return commands;
284
+ }
285
+ else if (os.is(providers_1.Os.WINDOWS)) {
286
+ let runnerCommands;
287
+ if (runnerVersion.is(providers_1.RunnerVersion.latest())) {
288
+ runnerCommands = [
289
+ 'cmd /c curl -w "%{redirect_url}" -fsS https://github.com/actions/runner/releases/latest > $Env:TEMP\\latest-gha',
290
+ '$LatestUrl = Get-Content $Env:TEMP\\latest-gha',
291
+ '$RUNNER_VERSION = ($LatestUrl -Split \'/\')[-1].substring(1)',
292
+ ];
293
+ }
294
+ else {
295
+ runnerCommands = [`$RUNNER_VERSION = '${runnerVersion.version}'`];
296
+ }
297
+ return runnerCommands.concat([
298
+ 'Invoke-WebRequest -UseBasicParsing -Uri "https://github.com/actions/runner/releases/download/v${RUNNER_VERSION}/actions-runner-win-x64-${RUNNER_VERSION}.zip" -OutFile actions.zip',
299
+ 'Expand-Archive actions.zip -DestinationPath C:\\actions',
300
+ 'del actions.zip',
301
+ `echo ${runnerVersion.version} | Out-File -Encoding ASCII -NoNewline C:\\actions\\RUNNER_VERSION`,
302
+ ]);
303
+ }
304
+ throw new Error(`Unknown os/architecture combo for github runner: ${os.name}/${architecture.name}`);
305
+ }
306
+ getDockerCommands(_os, _architecture) {
307
+ return [
308
+ `ENV RUNNER_VERSION=${runnerVersion.version}`,
309
+ ];
310
+ }
311
+ }();
312
+ }
313
+ /**
314
+ * A component to install Docker.
315
+ *
316
+ * On Windows this sets up dockerd for Windows containers without Docker Desktop. If you need Linux containers on Windows, you'll need to install Docker Desktop which doesn't seem to play well with servers (PRs welcome).
317
+ */
318
+ static docker() {
319
+ return new class extends RunnerImageComponent {
320
+ constructor() {
321
+ super(...arguments);
322
+ this.name = 'Docker';
323
+ }
324
+ getCommands(os, architecture) {
325
+ if (os.is(providers_1.Os.LINUX_UBUNTU)) {
326
+ return [
327
+ 'curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker.gpg',
328
+ 'echo ' +
329
+ ' "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu ' +
330
+ ' $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null',
331
+ 'apt-get update',
332
+ 'DEBIAN_FRONTEND=noninteractive apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin',
333
+ 'usermod -aG docker runner',
334
+ 'ln -s /usr/libexec/docker/cli-plugins/docker-compose /usr/bin/docker-compose',
335
+ ];
336
+ }
337
+ else if (os.is(providers_1.Os.LINUX_AMAZON_2)) {
338
+ return [
339
+ 'yum install -y docker',
340
+ ];
341
+ }
342
+ else if (os.is(providers_1.Os.WINDOWS)) {
343
+ return [
344
+ // figure out latest docker version
345
+ 'cmd /c curl -w "%{redirect_url}" -fsS https://github.com/moby/moby/releases/latest > $Env:TEMP\\latest-docker',
346
+ '$LatestUrl = Get-Content $Env:TEMP\\latest-docker',
347
+ '$DOCKER_VERSION = ($LatestUrl -Split \'/\')[-1].substring(1)',
348
+ // download static binaries
349
+ 'Invoke-WebRequest -UseBasicParsing -Uri "https://download.docker.com/win/static/stable/x86_64/docker-${DOCKER_VERSION}.zip" -OutFile docker.zip',
350
+ // extract to C:\Program Files\Docker
351
+ 'Expand-Archive docker.zip -DestinationPath "$Env:ProgramFiles"',
352
+ 'del docker.zip',
353
+ // add to path
354
+ '$persistedPaths = [Environment]::GetEnvironmentVariable(\'Path\', [EnvironmentVariableTarget]::Machine)',
355
+ '[Environment]::SetEnvironmentVariable("PATH", $persistedPaths + ";$Env:ProgramFiles\\Docker", [EnvironmentVariableTarget]::Machine)',
356
+ '$env:PATH = $env:PATH + ";$Env:ProgramFiles\\Docker"',
357
+ // register docker service
358
+ 'dockerd --register-service',
359
+ 'if ($LASTEXITCODE -ne 0) { throw "Exit code is $LASTEXITCODE" }',
360
+ // enable containers feature
361
+ 'Enable-WindowsOptionalFeature -Online -FeatureName containers -All -NoRestart',
362
+ // install docker-compose
363
+ 'cmd /c curl -w "%{redirect_url}" -fsS https://github.com/docker/compose/releases/latest > $Env:TEMP\\latest-docker-compose',
364
+ '$LatestUrl = Get-Content $Env:TEMP\\latest-docker-compose',
365
+ '$LatestDockerCompose = ($LatestUrl -Split \'/\')[-1]',
366
+ 'Invoke-WebRequest -UseBasicParsing -Uri "https://github.com/docker/compose/releases/download/${LatestDockerCompose}/docker-compose-Windows-x86_64.exe" -OutFile $Env:ProgramFiles\\Docker\\docker-compose.exe',
367
+ 'New-Item -ItemType directory -Path "$Env:ProgramFiles\\Docker\\cli-plugins"',
368
+ 'Copy-Item -Path "$Env:ProgramFiles\\Docker\\docker-compose.exe" -Destination "$Env:ProgramFiles\\Docker\\cli-plugins\\docker-compose.exe"',
369
+ ];
370
+ }
371
+ throw new Error(`Unknown os/architecture combo for docker: ${os.name}/${architecture.name}`);
372
+ }
373
+ shouldReboot(os, _architecture) {
374
+ return os.is(providers_1.Os.WINDOWS);
375
+ }
376
+ }();
377
+ }
378
+ /**
379
+ * A component to install Docker-in-Docker.
380
+ */
381
+ static dockerInDocker() {
382
+ return new class extends RunnerImageComponent {
383
+ constructor() {
384
+ super(...arguments);
385
+ this.name = 'Docker-in-Docker';
386
+ }
387
+ getCommands(os, architecture) {
388
+ if (os.is(providers_1.Os.LINUX_UBUNTU) || os.is(providers_1.Os.LINUX_AMAZON_2)) {
389
+ let archUrl;
390
+ if (architecture.is(providers_1.Architecture.X86_64)) {
391
+ archUrl = 'x86_64';
392
+ }
393
+ else if (architecture.is(providers_1.Architecture.ARM64)) {
394
+ archUrl = 'aarch64';
395
+ }
396
+ else {
397
+ throw new Error(`Unsupported architecture for Docker-in-Docker: ${architecture.name}`);
398
+ }
399
+ return [
400
+ os.is(providers_1.Os.LINUX_UBUNTU) ? 'DEBIAN_FRONTEND=noninteractive apt-get install -y socat' : 'yum install -y socat',
401
+ 'DOCKER_CHANNEL="stable"',
402
+ 'DIND_COMMIT="42b1175eda071c0e9121e1d64345928384a93df1"',
403
+ 'DOCKER_VERSION="20.10.18"',
404
+ 'DOCKER_COMPOSE_VERSION="2.11.0"',
405
+ `curl -fsSL "https://download.docker.com/linux/static/\${DOCKER_CHANNEL}/${archUrl}/docker-\${DOCKER_VERSION}.tgz" -o docker.tgz`,
406
+ 'tar --strip-components 1 -C /usr/local/bin/ -xzf docker.tgz',
407
+ 'rm docker.tgz',
408
+ '# set up subuid/subgid so that "--userns-remap=default" works out-of-the box',
409
+ 'addgroup dockremap',
410
+ 'useradd -g dockremap dockremap',
411
+ 'echo \'dockremap:165536:65536\' >> /etc/subuid',
412
+ 'echo \'dockremap:165536:65536\' >> /etc/subgid',
413
+ 'curl -fsSL "https://raw.githubusercontent.com/docker/docker/${DIND_COMMIT}/hack/dind" -o /usr/local/bin/dind',
414
+ `curl -fsSL https://github.com/docker/compose/releases/download/v\${DOCKER_COMPOSE_VERSION}/docker-compose-linux-${archUrl} -o /usr/local/bin/docker-compose`,
415
+ 'mkdir -p /home/runner/.docker/cli-plugins && ln -s /usr/local/bin/docker-compose /home/runner/.docker/cli-plugins/docker-compose',
416
+ 'chown -R runner /home/runner/.docker',
417
+ 'chmod +x /usr/local/bin/dind /usr/local/bin/docker-compose',
418
+ 'addgroup docker && usermod -aG docker runner',
419
+ ];
420
+ }
421
+ throw new Error(`Unknown os/architecture combo for Docker-in-Docker: ${os.name}/${architecture.name}`);
422
+ }
423
+ }();
424
+ }
425
+ /**
426
+ * A component to add a trusted certificate authority. This can be used to support GitHub Enterprise Server with self-signed certificate.
427
+ *
428
+ * @param source path to certificate file in PEM format
429
+ * @param name unique certificate name to be used on runner file system
430
+ */
431
+ static extraCertificates(source, name) {
432
+ return new class extends RunnerImageComponent {
433
+ constructor() {
434
+ super(...arguments);
435
+ this.name = `Extra-Certificates-${name}`;
436
+ }
437
+ getCommands(os, architecture) {
438
+ if (!name.match(/^[a-zA-Z0-9_-]+$/)) {
439
+ throw new Error(`Invalid certificate name: ${name}. Name must only contain alphanumeric characters, dashes and underscores.`);
440
+ }
441
+ if (os.is(providers_1.Os.LINUX_UBUNTU)) {
442
+ return [
443
+ 'update-ca-certificates',
444
+ ];
445
+ }
446
+ else if (os.is(providers_1.Os.LINUX_AMAZON_2)) {
447
+ return [
448
+ 'update-ca-trust',
449
+ ];
450
+ }
451
+ else if (os.is(providers_1.Os.WINDOWS)) {
452
+ return [
453
+ `Import-Certificate -FilePath C:\\${name}.crt -CertStoreLocation Cert:\\LocalMachine\\Root`,
454
+ `Remove-Item C:\\${name}.crt`,
455
+ ];
456
+ }
457
+ throw new Error(`Unknown os/architecture combo for extra certificates: ${os.name}/${architecture.name}`);
458
+ }
459
+ getAssets(os, _architecture) {
460
+ if (os.is(providers_1.Os.LINUX_UBUNTU)) {
461
+ return [
462
+ { source, target: `/usr/local/share/ca-certificates/${name}.crt` },
463
+ ];
464
+ }
465
+ else if (os.is(providers_1.Os.LINUX_AMAZON_2)) {
466
+ return [
467
+ { source, target: `/etc/pki/ca-trust/source/anchors/${name}.crt` },
468
+ ];
469
+ }
470
+ else if (os.is(providers_1.Os.WINDOWS)) {
471
+ return [
472
+ { source, target: `C:\\${name}.crt` },
473
+ ];
474
+ }
475
+ throw new Error(`Unsupported OS for extra certificates: ${os.name}`);
476
+ }
477
+ }();
478
+ }
479
+ /**
480
+ * A component to set up the required Lambda entrypoint for Lambda runners.
481
+ */
482
+ static lambdaEntrypoint() {
483
+ return new class extends RunnerImageComponent {
484
+ constructor() {
485
+ super(...arguments);
486
+ this.name = 'Lambda-Entrypoint';
487
+ }
488
+ getCommands(os, _architecture) {
489
+ if (!os.is(providers_1.Os.LINUX_AMAZON_2) && !os.is(providers_1.Os.LINUX_UBUNTU)) {
490
+ throw new Error(`Unsupported OS for Lambda entrypoint: ${os.name}`);
491
+ }
492
+ return [];
493
+ }
494
+ getAssets(_os, _architecture) {
495
+ return [
496
+ {
497
+ source: path.join(__dirname, '..', '..', 'assets', 'docker-images', 'lambda', 'linux-x64', 'runner.js'),
498
+ target: '${LAMBDA_TASK_ROOT}/runner.js',
499
+ },
500
+ {
501
+ source: path.join(__dirname, '..', '..', 'assets', 'docker-images', 'lambda', 'linux-x64', 'runner.sh'),
502
+ target: '${LAMBDA_TASK_ROOT}/runner.sh',
503
+ },
504
+ ];
505
+ }
506
+ getDockerCommands(_os, _architecture) {
507
+ return [
508
+ 'WORKDIR ${LAMBDA_TASK_ROOT}',
509
+ 'CMD ["runner.handler"]',
510
+ ];
511
+ }
512
+ };
513
+ }
514
+ /**
515
+ * Returns assets to copy into the built image. Can be used to copy files into the image.
516
+ */
517
+ getAssets(_os, _architecture) {
518
+ return [];
519
+ }
520
+ /**
521
+ * Returns Docker commands to run to in built image. Can be used to add commands like `VOLUME`, `ENTRYPOINT`, `CMD`, etc.
522
+ *
523
+ * Docker commands are added after assets and normal commands.
524
+ */
525
+ getDockerCommands(_os, _architecture) {
526
+ return [];
527
+ }
528
+ /**
529
+ * Returns true if the image builder should be rebooted after this component is installed.
530
+ */
531
+ shouldReboot(_os, _architecture) {
532
+ return false;
533
+ }
534
+ /**
535
+ * Convert component to an AWS Image Builder component.
536
+ *
537
+ * @internal
538
+ */
539
+ _asAwsImageBuilderComponent(scope, id, os, architecture) {
540
+ let platform;
541
+ if (os.is(providers_1.Os.LINUX_UBUNTU) || os.is(providers_1.Os.LINUX_AMAZON_2)) {
542
+ platform = 'Linux';
543
+ }
544
+ else if (os.is(providers_1.Os.WINDOWS)) {
545
+ platform = 'Windows';
546
+ }
547
+ else {
548
+ throw new Error(`Unknown os/architecture combo for image builder component: ${os.name}/${architecture.name}`);
549
+ }
550
+ return new aws_image_builder_1.ImageBuilderComponent(scope, id, {
551
+ platform: platform,
552
+ commands: this.getCommands(os, architecture),
553
+ assets: this.getAssets(os, architecture).map((asset, index) => {
554
+ return {
555
+ asset: new aws_cdk_lib_1.aws_s3_assets.Asset(scope, `${id} asset ${index}`, { path: asset.source }),
556
+ path: asset.target,
557
+ };
558
+ }),
559
+ displayName: id,
560
+ description: id,
561
+ reboot: this.shouldReboot(os, architecture),
562
+ });
563
+ }
564
+ }
565
+ _a = JSII_RTTI_SYMBOL_1;
566
+ RunnerImageComponent[_a] = { fqn: "@cloudsnorkel/cdk-github-runners.RunnerImageComponent", version: "0.9.6" };
567
+ exports.RunnerImageComponent = RunnerImageComponent;
568
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tcG9uZW50cy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9pbWFnZS1idWlsZGVycy9jb21wb25lbnRzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsNkJBQTZCO0FBQzdCLDZDQUF5RDtBQUV6RCwyREFBNEQ7QUFFNUQsNENBQStEO0FBOEIvRDs7R0FFRztBQUNILE1BQXNCLG9CQUFvQjtJQUN4Qzs7Ozs7Ozs7T0FRRztJQUNILE1BQU0sQ0FBQyxNQUFNLENBQUMsS0FBc0M7UUFDbEQsT0FBTyxJQUFJLEtBQU0sU0FBUSxvQkFBb0I7WUFDM0MsSUFBSSxJQUFJO2dCQUNOLElBQUksS0FBSyxDQUFDLElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLGVBQWUsQ0FBQyxFQUFFO29CQUNwRCxNQUFNLElBQUksS0FBSyxDQUFDLDJCQUEyQixLQUFLLENBQUMsSUFBSSw4REFBOEQsQ0FBQyxDQUFDO2lCQUN0SDtnQkFDRCxPQUFPLFVBQVUsS0FBSyxDQUFDLElBQUksSUFBSSxXQUFXLEVBQUUsQ0FBQztZQUMvQyxDQUFDO1lBRUQsV0FBVyxDQUFDLEdBQU8sRUFBRSxhQUEyQjtnQkFDOUMsT0FBTyxLQUFLLENBQUMsUUFBUSxJQUFJLEVBQUUsQ0FBQztZQUM5QixDQUFDO1lBQ0QsU0FBUyxDQUFDLEdBQU8sRUFBRSxhQUEyQjtnQkFDNUMsT0FBTyxLQUFLLENBQUMsTUFBTSxJQUFJLEVBQUUsQ0FBQztZQUM1QixDQUFDO1lBRUQsaUJBQWlCLENBQUMsR0FBTyxFQUFFLGFBQTJCO2dCQUNwRCxPQUFPLEtBQUssQ0FBQyxjQUFjLElBQUksRUFBRSxDQUFDO1lBQ3BDLENBQUM7U0FDRixFQUFFLENBQUM7SUFDTixDQUFDO0lBRUQ7O09BRUc7SUFDSCxNQUFNLENBQUMsZ0JBQWdCO1FBQ3JCLE9BQU8sSUFBSSxLQUFNLFNBQVEsb0JBQW9CO1lBQWxDOztnQkFDVCxTQUFJLEdBQUcsa0JB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SSxDQUFDLFlBQVksQ0FBQyxFQUFFLEVBQUUsWUFBWSxDQUFDO1NBQzVDLENBQUMsQ0FBQztJQUNMLENBQUM7Ozs7QUEzaUJtQixvREFBb0IiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0IHsgYXdzX3MzX2Fzc2V0cyBhcyBzM19hc3NldHMgfSBmcm9tICdhd3MtY2RrLWxpYic7XG5pbXBvcnQgeyBDb25zdHJ1Y3QgfSBmcm9tICdjb25zdHJ1Y3RzJztcbmltcG9ydCB7IEltYWdlQnVpbGRlckNvbXBvbmVudCB9IGZyb20gJy4vYXdzLWltYWdlLWJ1aWxkZXInO1xuaW1wb3J0IHsgUnVubmVySW1hZ2VBc3NldCB9IGZyb20gJy4vY29tbW9uJztcbmltcG9ydCB7IEFyY2hpdGVjdHVyZSwgT3MsIFJ1bm5lclZlcnNpb24gfSBmcm9tICcuLi9wcm92aWRlcnMnO1xuXG5leHBvcnQgaW50ZXJmYWNlIFJ1bm5lckltYWdlQ29tcG9uZW50Q3VzdG9tUHJvcHMge1xuICAvKipcbiAgICogQ29tcG9uZW50IG5hbWUgdXNlZCBmb3IgKDEpIGltYWdlIGJ1aWxkIGxvZ2dpbmcgYW5kICgyKSBpZGVudGlmaWVyIGZvciB7QGxpbmsgSW1hZ2VSdW5uZXJCdWlsZGVyLnJlbW92ZUNvbXBvbmVudH0uXG4gICAqXG4gICAqIE5hbWUgbXVzdCBvbmx5IGNvbnRhaW4gYWxwaGFudW1lcmljIGNoYXJhY3RlcnMgYW5kIGRhc2hlcy5cbiAgICovXG4gIHJlYWRvbmx5IG5hbWU/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIENvbW1hbmRzIHRvIHJ1biBpbiB0aGUgYnVpbHQgaW1hZ2UuXG4gICAqL1xuICByZWFkb25seSBjb21tYW5kcz86IHN0cmluZ1tdO1xuXG4gIC8qKlxuICAgKiBBc3NldHMgdG8gY29weSBpbnRvIHRoZSBidWlsdCBpbWFnZS5cbiAgICovXG4gIHJlYWRvbmx5IGFzc2V0cz86IFJ1bm5lckltYWdlQXNzZXRbXTtcblxuICAvKipcbiAgICogRG9ja2VyIGNvbW1hbmRzIHRvIHJ1biBpbiB0aGUgYnVpbHQgaW1hZ2UuXG4gICAqXG4gICAqIEZvciBleGFtcGxlOiBgWydFTlYgZm9vPWJhcicsICdSVU4gZWNobyAkZm9vJ11gXG4gICAqXG4gICAqIFRoZXNlIGNvbW1hbmRzIGFyZSBpZ25vcmVkIHdoZW4gYnVpbGRpbmcgQU1Jcy5cbiAgICovXG4gIHJlYWRvbmx5IGRvY2tlckNvbW1hbmRzPzogc3RyaW5nW107XG59XG5cbi8qKlxuICogQ29tcG9uZW50cyBhcmUgdXNlZCB0byBidWlsZCBydW5uZXIgaW1hZ2VzLiBUaGV5IGNhbiBydW4gY29tbWFuZHMgaW4gdGhlIGltYWdlLCBjb3B5IGZpbGVzIGludG8gdGhlIGltYWdlLCBhbmQgcnVuIHNvbWUgRG9ja2VyIGNvbW1hbmRzLlxuICovXG5leHBvcnQgYWJzdHJhY3QgY2xhc3MgUnVubmVySW1hZ2VDb21wb25lbnQge1xuICAvKipcbiAgICogRGVmaW5lIGEgY3VzdG9tIGNvbXBvbmVudCB0aGF0IGNhbiBydW4gY29tbWFuZHMgaW4gdGhlIGltYWdlLCBjb3B5IGZpbGVzIGludG8gdGhlIGltYWdlLCBhbmQgcnVuIHNvbWUgRG9ja2VyIGNvbW1hbmRzLlxuICAgKlxuICAgKiBUaGUgb3JkZXIgb2Ygb3BlcmF0aW9ucyBpcyAoMSkgYXNzZXRzICgyKSBjb21tYW5kcyAoMykgZG9ja2VyIGNvbW1hbmRzLlxuICAgKlxuICAgKiBVc2UgdGhpcyB0byBjdXN0b21pemUgdGhlIGltYWdlIGZvciB0aGUgcnVubmVyLlxuICAgKlxuICAgKiAqKldBUk5JTkc6KiogRG9ja2VyIGNvbW1hbmRzIGFyZSBub3QgZ3VhcmFudGVlZCB0byBiZSBpbmNsdWRlZCBiZWZvcmUgdGhlIG5leHQgY29tcG9uZW50XG4gICAqL1xuICBzdGF0aWMgY3VzdG9tKHByb3BzOiBSdW5uZXJJbWFnZUNvbXBvbmVudEN1c3RvbVByb3BzKTogUnVubmVySW1hZ2VDb21wb25lbnQge1xuICAgIHJldHVybiBuZXcgY2xhc3MgZXh0ZW5kcyBSdW5uZXJJbWFnZUNvbXBvbmVudCB7XG4gICAgICBnZXQgbmFtZSgpIHtcbiAgICAgICAgaWYgKHByb3BzLm5hbWUgJiYgIXByb3BzLm5hbWUubWF0Y2goL1thLXpBLVowLTlcXC1dLykpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgY29tcG9uZW50IG5hbWU6ICR7cHJvcHMubmFtZX0uIE5hbWUgbXVzdCBvbmx5IGNvbnRhaW4gYWxwaGFudW1lcmljIGNoYXJhY3RlcnMgYW5kIGRhc2hlcy5gKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gYEN1c3RvbS0ke3Byb3BzLm5hbWUgPz8gJ1VuZGVmaW5lZCd9YDtcbiAgICAgIH1cblxuICAgICAgZ2V0Q29tbWFuZHMoX29zOiBPcywgX2FyY2hpdGVjdHVyZTogQXJjaGl0ZWN0dXJlKSB7XG4gICAgICAgIHJldHVybiBwcm9wcy5jb21tYW5kcyA/PyBbXTtcbiAgICAgIH1cbiAgICAgIGdldEFzc2V0cyhfb3M6IE9zLCBfYXJjaGl0ZWN0dXJlOiBBcmNoaXRlY3R1cmUpIHtcbiAgICAgICAgcmV0dXJuIHByb3BzLmFzc2V0cyA/PyBbXTtcbiAgICAgIH1cblxuICAgICAgZ2V0RG9ja2VyQ29tbWFuZHMoX29zOiBPcywgX2FyY2hpdGVjdHVyZTogQXJjaGl0ZWN0dXJlKSB7XG4gICAgICAgIHJldHVybiBwcm9wcy5kb2NrZXJDb21tYW5kcyA/PyBbXTtcbiAgICAgIH1cbiAgICB9KCk7XG4gIH1cblxuICAvKipcbiAgICogQSBjb21wb25lbnQgdG8gaW5zdGFsbCB0aGUgcmVxdWlyZWQgcGFja2FnZXMgZm9yIHRoZSBydW5uZXIuXG4gICAqL1xuICBzdGF0aWMgcmVxdWlyZWRQYWNrYWdlcygpOiBSdW5uZXJJbWFnZUNvbXBvbmVudCB7XG4gICAgcmV0dXJuIG5ldyBjbGFzcyBleHRlbmRzIFJ1bm5lckltYWdlQ29tcG9uZW50IHtcbiAgICAgIG5hbWUgPSAnUmVxdWlyZWRQYWNrYWdlcyc7XG5cbiAgICAgIGdldENvbW1hbmRzKG9zOiBPcywgYXJjaGl0ZWN0dXJlOiBBcmNoaXRlY3R1cmUpOiBzdHJpbmdbXSB7XG4gICAgICAgIGlmIChvcy5pcyhPcy5MSU5VWF9VQlVOVFUpKSB7XG4gICAgICAgICAgbGV0IGFyY2hVcmw7XG4gICAgICAgICAgaWYgKGFyY2hpdGVjdHVyZS5pcyhBcmNoaXRlY3R1cmUuWDg2XzY0KSkge1xuICAgICAgICAgICAgYXJjaFVybCA9ICdhbWQ2NCc7XG4gICAgICAgICAgfSBlbHNlIGlmIChhcmNoaXRlY3R1cmUuaXMoQXJjaGl0ZWN0dXJlLkFSTTY0KSkge1xuICAgICAgICAgICAgYXJjaFVybCA9ICdhcm02NCc7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgVW5zdXBwb3J0ZWQgYXJjaGl0ZWN0dXJlIGZvciByZXF1aXJlZCBwYWNrYWdlczogJHthcmNoaXRlY3R1cmUubmFtZX1gKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICByZXR1cm4gW1xuICAgICAgICAgICAgJ2FwdC1nZXQgdXBkYXRlJyxcbiAgICAgICAgICAgICdERUJJQU5fRlJPTlRFTkQ9bm9uaW50ZXJhY3RpdmUgYXB0LWdldCB1cGdyYWRlIC15JyxcbiAgICAgICAgICAgICdERUJJQU5fRlJPTlRFTkQ9bm9uaW50ZXJhY3RpdmUgYXB0LWdldCBpbnN0YWxsIC15IGN1cmwgc3VkbyBqcSBiYXNoIHppcCB1bnppcCBpcHRhYmxlcyBzb2Z0d2FyZS1wcm9wZXJ0aWVzLWNvbW1vbiBjYS1jZXJ0aWZpY2F0ZXMnLFxuICAgICAgICAgICAgYGN1cmwgLXNmTG8gL3RtcC9hbWF6b24tY2xvdWR3YXRjaC1hZ2VudC5kZWIgaHR0cHM6Ly9zMy5hbWF6b25hd3MuY29tL2FtYXpvbmNsb3Vkd2F0Y2gtYWdlbnQvdWJ1bnR1LyR7YXJjaFVybH0vbGF0ZXN0L2FtYXpvbi1jbG91ZHdhdGNoLWFnZW50LmRlYmAsXG4gICAgICAgICAgICAnZHBrZyAtaSAtRSAvdG1wL2FtYXpvbi1jbG91ZHdhdGNoLWFnZW50LmRlYicsXG4gICAgICAgICAgICAncm0gL3RtcC9hbWF6b24tY2xvdWR3YXRjaC1hZ2VudC5kZWInLFxuICAgICAgICAgIF07XG4gICAgICAgIH0gZWxzZSBpZiAob3MuaXMoT3MuTElOVVhfQU1BWk9OXzIpKSB7XG4gICAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICAgICd5dW0gdXBkYXRlIC15JyxcbiAgICAgICAgICAgICd5dW0gaW5zdGFsbCAteSBqcSB0YXIgZ3ppcCBiemlwMiB3aGljaCBiaW51dGlscyB6aXAgdW56aXAgc3VkbyBzaGFkb3ctdXRpbHMnLFxuICAgICAgICAgIF07XG4gICAgICAgIH0gZWxzZSBpZiAob3MuaXMoT3MuV0lORE9XUykpIHtcbiAgICAgICAgICByZXR1cm4gW1xuICAgICAgICAgICAgJyRwID0gU3RhcnQtUHJvY2VzcyBtc2lleGVjLmV4ZSAtUGFzc1RocnUgLVdhaXQgLUFyZ3VtZW50TGlzdCBcXCcvaSBodHRwczovL3MzLmFtYXpvbmF3cy5jb20vYW1hem9uY2xvdWR3YXRjaC1hZ2VudC93aW5kb3dzL2FtZDY0L2xhdGVzdC9hbWF6b24tY2xvdWR3YXRjaC1hZ2VudC5tc2kgL3FuXFwnJyxcbiAgICAgICAgICAgICdpZiAoJHAuRXhpdENvZGUgLW5lIDApIHsgdGhyb3cgXCJFeGl0IGNvZGUgaXMgJHAuRXhpdENvZGVcIiB9JyxcbiAgICAgICAgICBdO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbnN1cHBvcnRlZCBPUyBmb3IgcmVxdWlyZWQgcGFja2FnZXM6ICR7b3MubmFtZX1gKTtcbiAgICAgIH1cbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIEEgY29tcG9uZW50IHRvIHByZXBhcmUgdGhlIHJlcXVpcmVkIHJ1bm5lciB1c2VyLlxuICAgKi9cbiAgc3RhdGljIHJ1bm5lclVzZXIoKTogUnVubmVySW1hZ2VDb21wb25lbnQge1xuICAgIHJldHVybiBuZXcgY2xhc3MgZXh0ZW5kcyBSdW5uZXJJbWFnZUNvbXBvbmVudCB7XG4gICAgICBuYW1lID0gJ1J1bm5lclVzZXInO1xuXG4gICAgICBnZXRDb21tYW5kcyhvczogT3MsIF9hcmNoaXRlY3R1cmU6IEFyY2hpdGVjdHVyZSk6IHN0cmluZ1tdIHtcbiAgICAgICAgaWYgKG9zLmlzKE9zLkxJTlVYX1VCVU5UVSkpIHtcbiAgICAgICAgICByZXR1cm4gW1xuICAgICAgICAgICAgJ2FkZGdyb3VwIHJ1bm5lcicsXG4gICAgICAgICAgICAnYWRkdXNlciAtLXN5c3RlbSAtLWRpc2FibGVkLXBhc3N3b3JkIC0taG9tZSAvaG9tZS9ydW5uZXIgLS1pbmdyb3VwIHJ1bm5lciBydW5uZXInLFxuICAgICAgICAgICAgJ3VzZXJtb2QgLWFHIHN1ZG8gcnVubmVyJyxcbiAgICAgICAgICAgICdlY2hvIFwiJXN1ZG8gICBBTEw9KEFMTDpBTEwpIE5PUEFTU1dEOiBBTExcIiA+IC9ldGMvc3Vkb2Vycy5kL3J1bm5lcicsXG4gICAgICAgICAgXTtcbiAgICAgICAgfSBlbHNlIGlmIChvcy5pcyhPcy5MSU5VWF9BTUFaT05fMikpIHtcbiAgICAgICAgICByZXR1cm4gW1xuICAgICAgICAgICAgJy91c3Ivc2Jpbi9ncm91cGFkZCBydW5uZXInLFxuICAgICAgICAgICAgJy91c3Ivc2Jpbi91c2VyYWRkIC0tc3lzdGVtIC0tc2hlbGwgL3Vzci9zYmluL25vbG9naW4gLS1ob21lLWRpciAvaG9tZS9ydW5uZXIgLS1naWQgcnVubmVyIHJ1bm5lcicsXG4gICAgICAgICAgICAnbWtkaXIgLXAgL2hvbWUvcnVubmVyJyxcbiAgICAgICAgICAgICdjaG93biBydW5uZXIgL2hvbWUvcnVubmVyJyxcbiAgICAgICAgICAgICdlY2hvIFwiJXJ1bm5lciAgIEFMTD0oQUxMOkFMTCkgTk9QQVNTV0Q6IEFMTFwiID4gL2V0Yy9zdWRvZXJzLmQvcnVubmVyJyxcbiAgICAgICAgICBdO1xuICAgICAgICB9IGVsc2UgaWYgKG9zLmlzKE9zLldJTkRPV1MpKSB7XG4gICAgICAgICAgcmV0dXJuIFtdO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbnN1cHBvcnRlZCBPUyBmb3IgcnVubmVyIHVzZXI6ICR7b3MubmFtZX1gKTtcbiAgICAgIH1cbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIEEgY29tcG9uZW50IHRvIGluc3RhbGwgdGhlIEFXUyBDTEkuXG4gICAqL1xuICBzdGF0aWMgYXdzQ2xpKCk6IFJ1bm5lckltYWdlQ29tcG9uZW50IHtcbiAgICByZXR1cm4gbmV3IGNsYXNzIGV4dGVuZHMgUnVubmVySW1hZ2VDb21wb25lbnQge1xuICAgICAgbmFtZSA9ICdBd3NDbGknO1xuXG4gICAgICBnZXRDb21tYW5kcyhvczogT3MsIGFyY2hpdGVjdHVyZTogQXJjaGl0ZWN0dXJlKSB7XG4gICAgICAgIGlmIChvcy5pcyhPcy5MSU5VWF9VQlVOVFUpIHx8IG9zLmlzKE9zLkxJTlVYX0FNQVpPTl8yKSkge1xuICAgICAgICAgIGxldCBhcmNoVXJsOiBzdHJpbmc7XG4gICAgICAgICAgaWYgKGFyY2hpdGVjdHVyZS5pcyhBcmNoaXRlY3R1cmUuWDg2XzY0KSkge1xuICAgICAgICAgICAgYXJjaFVybCA9ICd4ODZfNjQnO1xuICAgICAgICAgIH0gZWxzZSBpZiAoYXJjaGl0ZWN0dXJlLmlzKEFyY2hpdGVjdHVyZS5BUk02NCkpIHtcbiAgICAgICAgICAgIGFyY2hVcmwgPSAnYWFyY2g2NCc7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgVW5zdXBwb3J0ZWQgYXJjaGl0ZWN0dXJlIGZvciBhd3NjbGk6ICR7YXJjaGl0ZWN0dXJlLm5hbWV9YCk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICAgIGBjdXJsIC1mc1NMIFwiaHR0cHM6Ly9hd3NjbGkuYW1hem9uYXdzLmNvbS9hd3NjbGktZXhlLWxpbnV4LSR7YXJjaFVybH0uemlwXCIgLW8gYXdzY2xpdjIuemlwYCxcbiAgICAgICAgICAgICd1bnppcCAtcSBhd3NjbGl2Mi56aXAnLFxuICAgICAgICAgICAgJy4vYXdzL2luc3RhbGwnLFxuICAgICAgICAgICAgJ3JtIC1yZiBhd3NjbGl2Mi56aXAgYXdzJyxcbiAgICAgICAgICBdO1xuICAgICAgICB9IGVsc2UgaWYgKG9zLmlzKE9zLldJTkRPV1MpKSB7XG4gICAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICAgICckcCA9IFN0YXJ0LVByb2Nlc3MgbXNpZXhlYy5leGUgLVBhc3NUaHJ1IC1XYWl0IC1Bcmd1bWVudExpc3QgXFwnL2kgaHR0cHM6Ly9hd3NjbGkuYW1hem9uYXdzLmNvbS9BV1NDTElWMi5tc2kgL3FuXFwnJyxcbiAgICAgICAgICAgICdpZiAoJHAuRXhpdENvZGUgLW5lIDApIHsgdGhyb3cgXCJFeGl0IGNvZGUgaXMgJHAuRXhpdENvZGVcIiB9JyxcbiAgICAgICAgICBdO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbmtub3duIG9zL2FyY2hpdGVjdHVyZSBjb21ibyBmb3IgYXdzY2xpOiAke29zLm5hbWV9LyR7YXJjaGl0ZWN0dXJlLm5hbWV9YCk7XG4gICAgICB9XG4gICAgfSgpO1xuICB9XG5cbiAgLyoqXG4gICAqIEEgY29tcG9uZW50IHRvIGluc3RhbGwgdGhlIEdpdEh1YiBDTEkuXG4gICAqL1xuICBzdGF0aWMgZ2l0aHViQ2xpKCk6IFJ1bm5lckltYWdlQ29tcG9uZW50IHtcbiAgICByZXR1cm4gbmV3IGNsYXNzIGV4dGVuZHMgUnVubmVySW1hZ2VDb21wb25lbnQge1xuICAgICAgbmFtZSA9ICdHaXRodWJDbGknO1xuXG4gICAgICBnZXRDb21tYW5kcyhvczogT3MsIGFyY2hpdGVjdHVyZTogQXJjaGl0ZWN0dXJlKSB7XG4gICAgICAgIGlmIChvcy5pcyhPcy5MSU5VWF9VQlVOVFUpKSB7XG4gICAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICAgICdjdXJsIC1mc1NMIGh0dHBzOi8vY2xpLmdpdGh1Yi5jb20vcGFja2FnZXMvZ2l0aHViY2xpLWFyY2hpdmUta2V5cmluZy5ncGcgfCBzdWRvIGRkIG9mPS91c3Ivc2hhcmUva2V5cmluZ3MvZ2l0aHViY2xpLWFyY2hpdmUta2V5cmluZy5ncGcnLFxuICAgICAgICAgICAgJ2VjaG8gXCJkZWIgW2FyY2g9JChkcGtnIC0tcHJpbnQtYXJjaGl0ZWN0dXJlKSBzaWduZWQtYnk9L3Vzci9zaGFyZS9rZXlyaW5ncy9naXRodWJjbGktYXJjaGl2ZS1rZXlyaW5nLmdwZ10gJyArXG4gICAgICAgICAgICAnICBodHRwczovL2NsaS5naXRodWIuY29tL3BhY2thZ2VzIHN0YWJsZSBtYWluXCIgfCBzdWRvIHRlZSAvZXRjL2FwdC9zb3VyY2VzLmxpc3QuZC9naXRodWItY2xpLmxpc3QgPiAvZGV2L251bGwnLFxuICAgICAgICAgICAgJ2FwdC1nZXQgdXBkYXRlJyxcbiAgICAgICAgICAgICdERUJJQU5fRlJPTlRFTkQ9bm9uaW50ZXJhY3RpdmUgYXB0LWdldCBpbnN0YWxsIC15IGdoJyxcbiAgICAgICAgICBdO1xuICAgICAgICB9IGVsc2UgaWYgKG9zLmlzKE9zLkxJTlVYX0FNQVpPTl8yKSkge1xuICAgICAgICAgIHJldHVybiBbXG4gICAgICAgICAgICAnY3VybCAtZnNTU0wgaHR0cHM6Ly9jbGkuZ2l0aHViLmNvbS9wYWNrYWdlcy9ycG0vZ2gtY2xpLnJlcG8gLW8gL2V0Yy95dW0ucmVwb3MuZC9naC1jbGkucmVwbycsXG4gICAgICAgICAgICAneXVtIGluc3RhbGwgLXkgZ2gnLFxuICAgICAgICAgIF07XG4gICAgICAgIH0gZWxzZSBpZiAob3MuaXMoT3MuV0lORE9XUykpIHtcbiAgICAgICAgICByZXR1cm4gW1xuICAgICAgICAgICAgJ2NtZCAvYyBjdXJsIC13IFwiJXtyZWRpcmVjdF91cmx9XCIgLWZzUyBodHRwczovL2dpdGh1Yi5jb20vY2xpL2NsaS9yZWxlYXNlcy9sYXRlc3QgPiAkRW52OlRFTVBcXFxcbGF0ZXN0LWdoJyxcbiAgICAgICAgICAgICckTGF0ZXN0VXJsID0gR2V0LUNvbnRlbnQgJEVudjpURU1QXFxcXGxhdGVzdC1naCcsXG4gICAgICAgICAgICAnJEdIX1ZFUlNJT04gPSAoJExhdGVzdFVybCAtU3BsaXQgXFwnL1xcJylbLTFdLnN1YnN0cmluZygxKScsXG4gICAgICAgICAgICAnSW52b2tlLVdlYlJlcXVlc3QgLVVzZUJhc2ljUGFyc2luZyAtVXJpIFwiaHR0cHM6Ly9naXRodWIuY29tL2NsaS9jbGkvcmVsZWFzZXMvZG93bmxvYWQvdiR7R0hfVkVSU0lPTn0vZ2hfJHtHSF9WRVJTSU9OfV93aW5kb3dzX2FtZDY0Lm1zaVwiIC1PdXRGaWxlIGdoLm1zaScsXG4gICAgICAgICAgICAnJHAgPSBTdGFydC1Qcm9jZXNzIG1zaWV4ZWMuZXhlIC1QYXNzVGhydSAtV2FpdCAtQXJndW1lbnRMaXN0IFxcJy9pIGdoLm1zaSAvcW5cXCcnLFxuICAgICAgICAgICAgJ2lmICgkcC5FeGl0Q29kZSAtbmUgMCkgeyB0aHJvdyBcIkV4aXQgY29kZSBpcyAkcC5FeGl0Q29kZVwiIH0nLFxuICAgICAgICAgICAgJ2RlbCBnaC5tc2knLFxuICAgICAgICAgIF07XG4gICAgICAgIH1cblxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFVua25vd24gb3MvYXJjaGl0ZWN0dXJlIGNvbWJvIGZvciBnaXRodWIgY2xpOiAke29zLm5hbWV9LyR7YXJjaGl0ZWN0dXJlLm5hbWV9YCk7XG4gICAgICB9XG4gICAgfSgpO1xuICB9XG5cbiAgLyoqXG4gICAqIEEgY29tcG9uZW50IHRvIGluc3RhbGwgdGhlIEdpdEh1YiBDTEkuXG4gICAqL1xuICBzdGF0aWMgZ2l0KCk6IFJ1bm5lckltYWdlQ29tcG9uZW50IHtcbiAgICByZXR1cm4gbmV3IGNsYXNzIGV4dGVuZHMgUnVubmVySW1hZ2VDb21wb25lbnQge1xuICAgICAgbmFtZSA9ICdHaXQnO1xuXG4gICAgICBnZXRDb21tYW5kcyhvczogT3MsIGFyY2hpdGVjdHVyZTogQXJjaGl0ZWN0dXJlKSB7XG4gICAgICAgIGlmIChvcy5pcyhPcy5MSU5VWF9VQlVOVFUpKSB7XG4gICAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICAgICdhZGQtYXB0LXJlcG9zaXRvcnkgcHBhOmdpdC1jb3JlL3BwYScsXG4gICAgICAgICAgICAnYXB0LWdldCB1cGRhdGUnLFxuICAgICAgICAgICAgJ0RFQklBTl9GUk9OVEVORD1ub25pbnRlcmFjdGl2ZSBhcHQtZ2V0IGluc3RhbGwgLXkgZ2l0JyxcbiAgICAgICAgICBdO1xuICAgICAgICB9IGVsc2UgaWYgKG9zLmlzKE9zLkxJTlVYX0FNQVpPTl8yKSkge1xuICAgICAgICAgIHJldHVybiBbXG4gICAgICAgICAgICAneXVtIGluc3RhbGwgLXkgZ2l0JyxcbiAgICAgICAgICBdO1xuICAgICAgICB9IGVsc2UgaWYgKG9zLmlzKE9zLldJTkRPV1MpKSB7XG4gICAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICAgICdjbWQgL2MgY3VybCAtdyBcIiV7cmVkaXJlY3RfdXJsfVwiIC1mc1MgaHR0cHM6Ly9naXRodWIuY29tL2dpdC1mb3Itd2luZG93cy9naXQvcmVsZWFzZXMvbGF0ZXN0ID4gJEVudjpURU1QXFxcXGxhdGVzdC1naXQnLFxuICAgICAgICAgICAgJyRMYXRlc3RVcmwgPSBHZXQtQ29udGVudCAkRW52OlRFTVBcXFxcbGF0ZXN0LWdpdCcsXG4gICAgICAgICAgICAnJEdJVF9WRVJTSU9OID0gKCRMYXRlc3RVcmwgLVNwbGl0IFxcJy9cXCcpWy0xXS5zdWJzdHJpbmcoMSknLFxuICAgICAgICAgICAgJyRHSVRfVkVSU0lPTl9TSE9SVCA9ICgkR0lUX1ZFUlNJT04gLVNwbGl0IFxcJy53aW5kb3dzLlxcJylbMF0nLFxuICAgICAgICAgICAgJyRHSVRfUkVWSVNJT04gPSAoJEdJVF9WRVJTSU9OIC1TcGxpdCBcXCcud2luZG93cy5cXCcpWzFdJyxcbiAgICAgICAgICAgICdJZiAoJEdJVF9SRVZJU0lPTiAtZ3QgMSkgeyRHSVRfVkVSU0lPTl9TSE9SVCA9IFwiJEdJVF9WRVJTSU9OX1NIT1JULiRHSVRfUkVWSVNJT05cIn0nLFxuICAgICAgICAgICAgJ0ludm9rZS1XZWJSZXF1ZXN0IC1Vc2VCYXNpY1BhcnNpbmcgLVVyaSBodHRwczovL2dpdGh1Yi5jb20vZ2l0LWZvci13aW5kb3dzL2dpdC9yZWxlYXNlcy9kb3dubG9hZC92JHtHSVRfVkVSU0lPTn0vR2l0LSR7R0lUX1ZFUlNJT05fU0hPUlR9LTY0LWJpdC5leGUgLU91dEZpbGUgZ2l0LXNldHVwLmV4ZScsXG4gICAgICAgICAgICAnJHAgPSBTdGFydC1Qcm9jZXNzIGdpdC1zZXR1cC5leGUgLVBhc3NUaHJ1IC1XYWl0IC1Bcmd1bWVudExpc3QgXFwnL1ZFUllTSUxFTlRcXCcnLFxuICAgICAgICAgICAgJ2lmICgkcC5FeGl0Q29kZSAtbmUgMCkgeyB0aHJvdyBcIkV4aXQgY29kZSBpcyAkcC5FeGl0Q29kZVwiIH0nLFxuICAgICAgICAgICAgJ2RlbCBnaXQtc2V0dXAuZXhlJyxcbiAgICAgICAgICBdO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbmtub3duIG9zL2FyY2hpdGVjdHVyZSBjb21ibyBmb3IgZ2l0OiAke29zLm5hbWV9LyR7YXJjaGl0ZWN0dXJlLm5hbWV9YCk7XG4gICAgICB9XG4gICAgfSgpO1xuICB9XG5cbiAgLyoqXG4gICAqIEEgY29tcG9uZW50IHRvIGluc3RhbGwgdGhlIEdpdEh1YiBBY3Rpb25zIFJ1bm5lci4gVGhpcyBpcyB0aGUgYWN0dWFsIGV4ZWN1dGFibGUgdGhhdCBjb25uZWN0cyB0byBHaXRIdWIgdG8gYXNrIGZvciBqb2JzIGFuZCB0aGVuIGV4ZWN1dGUgdGhlbS5cbiAgICpcbiAgICogQHBhcmFtIHJ1bm5lclZlcnNpb24gVGhlIHZlcnNpb24gb2YgdGhlIHJ1bm5lciB0byBpbnN0YWxsLiBVc3VhbGx5IHlvdSB3b3VsZCBzZXQgdGhpcyB0byBsYXRlc3QuXG4gICAqL1xuICBzdGF0aWMgZ2l0aHViUnVubmVyKHJ1bm5lclZlcnNpb246IFJ1bm5lclZlcnNpb24pOiBSdW5uZXJJbWFnZUNvbXBvbmVudCB7XG4gICAgcmV0dXJuIG5ldyBjbGFzcyBleHRlbmRzIFJ1bm5lckltYWdlQ29tcG9uZW50IHtcbiAgICAgIG5hbWUgPSAnR2l0aHViUnVubmVyJztcblxuICAgICAgZ2V0Q29tbWFuZHMob3M6IE9zLCBhcmNoaXRlY3R1cmU6IEFyY2hpdGVjdHVyZSkge1xuICAgICAgICBpZiAob3MuaXMoT3MuTElOVVhfVUJVTlRVKSB8fCBvcy5pcyhPcy5MSU5VWF9BTUFaT05fMikpIHtcbiAgICAgICAgICBsZXQgdmVyc2lvbkNvbW1hbmQ6IHN0cmluZztcbiAgICAgICAgICBpZiAocnVubmVyVmVyc2lvbi5pcyhSdW5uZXJWZXJzaW9uLmxhdGVzdCgpKSkge1xuICAgICAgICAgICAgdmVyc2lvbkNvbW1hbmQgPSAnUlVOTkVSX1ZFUlNJT049YGN1cmwgLXcgXCIle3JlZGlyZWN0X3VybH1cIiAtZnNTIGh0dHBzOi8vZ2l0aHViLmNvbS9hY3Rpb25zL3J1bm5lci9yZWxlYXNlcy9sYXRlc3QgfCBncmVwIC1vRSBcIlteL3ZdKyRcImAnO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB2ZXJzaW9uQ29tbWFuZCA9IGBSVU5ORVJfVkVSU0lPTj0nJHtydW5uZXJWZXJzaW9uLnZlcnNpb259J2A7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgbGV0IGFyY2hVcmw7XG4gICAgICAgICAgaWYgKGFyY2hpdGVjdHVyZS5pcyhBcmNoaXRlY3R1cmUuWDg2XzY0KSkge1xuICAgICAgICAgICAgYXJjaFVybCA9ICd4NjQnO1xuICAgICAgICAgIH0gZWxzZSBpZiAoYXJjaGl0ZWN0dXJlLmlzKEFyY2hpdGVjdHVyZS5BUk02NCkpIHtcbiAgICAgICAgICAgIGFyY2hVcmwgPSAnYXJtNjQnO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFVuc3VwcG9ydGVkIGFyY2hpdGVjdHVyZSBmb3IgR2l0SHViIFJ1bm5lcjogJHthcmNoaXRlY3R1cmUubmFtZX1gKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBsZXQgY29tbWFuZHMgPSBbXG4gICAgICAgICAgICB2ZXJzaW9uQ29tbWFuZCxcbiAgICAgICAgICAgIGBjdXJsIC1mc1NMTyBcImh0dHBzOi8vZ2l0aHViLmNvbS9hY3Rpb25zL3J1bm5lci9yZWxlYXNlcy9kb3dubG9hZC92XFwke1JVTk5FUl9WRVJTSU9OfS9hY3Rpb25zLXJ1bm5lci1saW51eC0ke2FyY2hVcmx9LVxcJHtSVU5ORVJfVkVSU0lPTn0udGFyLmd6XCJgLFxuICAgICAgICAgICAgYHRhciAtQyAvaG9tZS9ydW5uZXIgLXh6ZiBcImFjdGlvbnMtcnVubmVyLWxpbnV4LSR7YXJjaFVybH0tXFwke1JVTk5FUl9WRVJTSU9OfS50YXIuZ3pcImAsXG4gICAgICAgICAgICBgcm0gYWN0aW9ucy1ydW5uZXItbGludXgtJHthcmNoVXJsfS1cXCR7UlVOTkVSX1ZFUlNJT059LnRhci5nemAsXG4gICAgICAgICAgICBgZWNobyAtbiAke3J1bm5lclZlcnNpb24udmVyc2lvbn0gPiAvaG9tZS9ydW5uZXIvUlVOTkVSX1ZFUlNJT05gLFxuICAgICAgICAgIF07XG5cbiAgICAgICAgICBpZiAob3MuaXMoT3MuTElOVVhfVUJVTlRVKSkge1xuICAgICAgICAgICAgY29tbWFuZHMucHVzaCgnL2hvbWUvcnVubmVyL2Jpbi9pbnN0YWxsZGVwZW5kZW5jaWVzLnNoJyk7XG4gICAgICAgICAgfSBlbHNlIGlmIChvcy5pcyhPcy5MSU5VWF9BTUFaT05fMikpIHtcbiAgICAgICAgICAgIGNvbW1hbmRzLnB1c2goJ3l1bSBpbnN0YWxsIC15IG9wZW5zc2wtbGlicyBrcmI1LWxpYnMgemxpYiBsaWJpY3U2MCcpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHJldHVybiBjb21tYW5kcztcbiAgICAgICAgfSBlbHNlIGlmIChvcy5pcyhPcy5XSU5ET1dTKSkge1xuICAgICAgICAgIGxldCBydW5uZXJDb21tYW5kczogc3RyaW5nW107XG4gICAgICAgICAgaWYgKHJ1bm5lclZlcnNpb24uaXMoUnVubmVyVmVyc2lvbi5sYXRlc3QoKSkpIHtcbiAgICAgICAgICAgIHJ1bm5lckNvbW1hbmRzID0gW1xuICAgICAgICAgICAgICAnY21kIC9jIGN1cmwgLXcgXCIle3JlZGlyZWN0X3VybH1cIiAtZnNTIGh0dHBzOi8vZ2l0aHViLmNvbS9hY3Rpb25zL3J1bm5lci9yZWxlYXNlcy9sYXRlc3QgPiAkRW52OlRFTVBcXFxcbGF0ZXN0LWdoYScsXG4gICAgICAgICAgICAgICckTGF0ZXN0VXJsID0gR2V0LUNvbnRlbnQgJEVudjpURU1QXFxcXGxhdGVzdC1naGEnLFxuICAgICAgICAgICAgICAnJFJVTk5FUl9WRVJTSU9OID0gKCRMYXRlc3RVcmwgLVNwbGl0IFxcJy9cXCcpWy0xXS5zdWJzdHJpbmcoMSknLFxuICAgICAgICAgICAgXTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcnVubmVyQ29tbWFuZHMgPSBbYCRSVU5ORVJfVkVSU0lPTiA9ICcke3J1bm5lclZlcnNpb24udmVyc2lvbn0nYF07XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmV0dXJuIHJ1bm5lckNvbW1hbmRzLmNvbmNhdChbXG4gICAgICAgICAgICAnSW52b2tlLVdlYlJlcXVlc3QgLVVzZUJhc2ljUGFyc2luZyAtVXJpIFwiaHR0cHM6Ly9naXRodWIuY29tL2FjdGlvbnMvcnVubmVyL3JlbGVhc2VzL2Rvd25sb2FkL3Yke1JVTk5FUl9WRVJTSU9OfS9hY3Rpb25zLXJ1bm5lci13aW4teDY0LSR7UlVOTkVSX1ZFUlNJT059LnppcFwiIC1PdXRGaWxlIGFjdGlvbnMuemlwJyxcbiAgICAgICAgICAgICdFeHBhbmQtQXJjaGl2ZSBhY3Rpb25zLnppcCAtRGVzdGluYXRpb25QYXRoIEM6XFxcXGFjdGlvbnMnLFxuICAgICAgICAgICAgJ2RlbCBhY3Rpb25zLnppcCcsXG4gICAgICAgICAgICBgZWNobyAke3J1bm5lclZlcnNpb24udmVyc2lvbn0gfCBPdXQtRmlsZSAtRW5jb2RpbmcgQVNDSUkgLU5vTmV3bGluZSBDOlxcXFxhY3Rpb25zXFxcXFJVTk5FUl9WRVJTSU9OYCxcbiAgICAgICAgICBdKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgVW5rbm93biBvcy9hcmNoaXRlY3R1cmUgY29tYm8gZm9yIGdpdGh1YiBydW5uZXI6ICR7b3MubmFtZX0vJHthcmNoaXRlY3R1cmUubmFtZX1gKTtcbiAgICAgIH1cblxuICAgICAgZ2V0RG9ja2VyQ29tbWFuZHMoX29zOiBPcywgX2FyY2hpdGVjdHVyZTogQXJjaGl0ZWN0dXJlKTogc3RyaW5nW10ge1xuICAgICAgICByZXR1cm4gW1xuICAgICAgICAgIGBFTlYgUlVOTkVSX1ZFUlNJT049JHtydW5uZXJWZXJzaW9uLnZlcnNpb259YCxcbiAgICAgICAgXTtcbiAgICAgIH1cbiAgICB9KCk7XG4gIH1cblxuICAvKipcbiAgICogQSBjb21wb25lbnQgdG8gaW5zdGFsbCBEb2NrZXIuXG4gICAqXG4gICAqIE9uIFdpbmRvd3MgdGhpcyBzZXRzIHVwIGRvY2tlcmQgZm9yIFdpbmRvd3MgY29udGFpbmVycyB3aXRob3V0IERvY2tlciBEZXNrdG9wLiBJZiB5b3UgbmVlZCBMaW51eCBjb250YWluZXJzIG9uIFdpbmRvd3MsIHlvdSdsbCBuZWVkIHRvIGluc3RhbGwgRG9ja2VyIERlc2t0b3Agd2hpY2ggZG9lc24ndCBzZWVtIHRvIHBsYXkgd2VsbCB3aXRoIHNlcnZlcnMgKFBScyB3ZWxjb21lKS5cbiAgICovXG4gIHN0YXRpYyBkb2NrZXIoKTogUnVubmVySW1hZ2VDb21wb25lbnQge1xuICAgIHJldHVybiBuZXcgY2xhc3MgZXh0ZW5kcyBSdW5uZXJJbWFnZUNvbXBvbmVudCB7XG4gICAgICBuYW1lID0gJ0RvY2tlcic7XG5cbiAgICAgIGdldENvbW1hbmRzKG9zOiBPcywgYXJjaGl0ZWN0dXJlOiBBcmNoaXRlY3R1cmUpIHtcbiAgICAgICAgaWYgKG9zLmlzKE9zLkxJTlVYX1VCVU5UVSkpIHtcbiAgICAgICAgICByZXR1cm4gW1xuICAgICAgICAgICAgJ2N1cmwgLWZzU0wgaHR0cHM6Ly9kb3dubG9hZC5kb2NrZXIuY29tL2xpbnV4L3VidW50dS9ncGcgfCBzdWRvIGdwZyAtLWRlYXJtb3IgLW8gL3Vzci9zaGFyZS9rZXlyaW5ncy9kb2NrZXIuZ3BnJyxcbiAgICAgICAgICAgICdlY2hvICcgK1xuICAgICAgICAgICAgICAgICcgIFwiZGViIFthcmNoPSQoZHBrZyAtLXByaW50LWFyY2hpdGVjdHVyZSkgc2lnbmVkLWJ5PS91c3Ivc2hhcmUva2V5cmluZ3MvZG9ja2VyLmdwZ10gaHR0cHM6Ly9kb3dubG9hZC5kb2NrZXIuY29tL2xpbnV4L3VidW50dSAnICtcbiAgICAgICAgICAgICAgICAnICAkKGxzYl9yZWxlYXNlIC1jcykgc3RhYmxlXCIgfCBzdWRvIHRlZSAvZXRjL2FwdC9zb3VyY2VzLmxpc3QuZC9kb2NrZXIubGlzdCA+IC9kZXYvbnVsbCcsXG4gICAgICAgICAgICAnYXB0LWdldCB1cGRhdGUnLFxuICAgICAgICAgICAgJ0RFQklBTl9GUk9OVEVORD1ub25pbnRlcmFjdGl2ZSBhcHQtZ2V0IGluc3RhbGwgLXkgZG9ja2VyLWNlIGRvY2tlci1jZS1jbGkgY29udGFpbmVyZC5pbyBkb2NrZXItY29tcG9zZS1wbHVnaW4nLFxuICAgICAgICAgICAgJ3VzZXJtb2QgLWFHIGRvY2tlciBydW5uZXInLFxuICAgICAgICAgICAgJ2xuIC1zIC91c3IvbGliZXhlYy9kb2NrZXIvY2xpLXBsdWdpbnMvZG9ja2VyLWNvbXBvc2UgL3Vzci9iaW4vZG9ja2VyLWNvbXBvc2UnLFxuICAgICAgICAgIF07XG4gICAgICAgIH0gZWxzZSBpZiAob3MuaXMoT3MuTElOVVhfQU1BWk9OXzIpKSB7XG4gICAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICAgICd5dW0gaW5zdGFsbCAteSBkb2NrZXInLFxuICAgICAgICAgIF07XG4gICAgICAgIH0gZWxzZSBpZiAob3MuaXMoT3MuV0lORE9XUykpIHtcbiAgICAgICAgICByZXR1cm4gW1xuICAgICAgICAgICAgLy8gZmlndXJlIG91dCBsYXRlc3QgZG9ja2VyIHZlcnNpb25cbiAgICAgICAgICAgICdjbWQgL2MgY3VybCAtdyBcIiV7cmVkaXJlY3RfdXJsfVwiIC1mc1MgaHR0cHM6Ly9naXRodWIuY29tL21vYnkvbW9ieS9yZWxlYXNlcy9sYXRlc3QgPiAkRW52OlRFTVBcXFxcbGF0ZXN0LWRvY2tlcicsXG4gICAgICAgICAgICAnJExhdGVzdFVybCA9IEdldC1Db250ZW50ICRFbnY6VEVNUFxcXFxsYXRlc3QtZG9ja2VyJyxcbiAgICAgICAgICAgICckRE9DS0VSX1ZFUlNJT04gPSAoJExhdGVzdFVybCAtU3BsaXQgXFwnL1xcJylbLTFdLnN1YnN0cmluZygxKScsXG4gICAgICAgICAgICAvLyBkb3dubG9hZCBzdGF0aWMgYmluYXJpZXNcbiAgICAgICAgICAgICdJbnZva2UtV2ViUmVxdWVzdCAtVXNlQmFzaWNQYXJzaW5nIC1VcmkgXCJodHRwczovL2Rvd25sb2FkLmRvY2tlci5jb20vd2luL3N0YXRpYy9zdGFibGUveDg2XzY0L2RvY2tlci0ke0RPQ0tFUl9WRVJTSU9OfS56aXBcIiAtT3V0RmlsZSBkb2NrZXIuemlwJyxcbiAgICAgICAgICAgIC8vIGV4dHJhY3QgdG8gQzpcXFByb2dyYW0gRmlsZXNcXERvY2tlclxuICAgICAgICAgICAgJ0V4cGFuZC1BcmNoaXZlIGRvY2tlci56aXAgLURlc3RpbmF0aW9uUGF0aCBcIiRFbnY6UHJvZ3JhbUZpbGVzXCInLFxuICAgICAgICAgICAgJ2RlbCBkb2NrZXIuemlwJyxcbiAgICAgICAgICAgIC8vIGFkZCB0byBwYXRoXG4gICAgICAgICAgICAnJHBlcnNpc3RlZFBhdGhzID0gW0Vudmlyb25tZW50XTo6R2V0RW52aXJvbm1lbnRWYXJpYWJsZShcXCdQYXRoXFwnLCBbRW52aXJvbm1lbnRWYXJpYWJsZVRhcmdldF06Ok1hY2hpbmUpJyxcbiAgICAgICAgICAgICdbRW52aXJvbm1lbnRdOjpTZXRFbnZpcm9ubWVudFZhcmlhYmxlKFwiUEFUSFwiLCAkcGVyc2lzdGVkUGF0aHMgKyBcIjskRW52OlByb2dyYW1GaWxlc1xcXFxEb2NrZXJcIiwgW0Vudmlyb25tZW50VmFyaWFibGVUYXJnZXRdOjpNYWNoaW5lKScsXG4gICAgICAgICAgICAnJGVudjpQQVRIID0gJGVudjpQQVRIICsgXCI7JEVudjpQcm9ncmFtRmlsZXNcXFxcRG9ja2VyXCInLFxuICAgICAgICAgICAgLy8gcmVnaXN0ZXIgZG9ja2VyIHNlcnZpY2VcbiAgICAgICAgICAgICdkb2NrZXJkIC0tcmVnaXN0ZXItc2VydmljZScsXG4gICAgICAgICAgICAnaWYgKCRMQVNURVhJVENPREUgLW5lIDApIHsgdGhyb3cgXCJFeGl0IGNvZGUgaXMgJExBU1RFWElUQ09ERVwiIH0nLFxuICAgICAgICAgICAgLy8gZW5hYmxlIGNvbnRhaW5lcnMgZmVhdHVyZVxuICAgICAgICAgICAgJ0VuYWJsZS1XaW5kb3dzT3B0aW9uYWxGZWF0dXJlIC1PbmxpbmUgLUZlYXR1cmVOYW1lIGNvbnRhaW5lcnMgLUFsbCAtTm9SZXN0YXJ0JyxcbiAgICAgICAgICAgIC8vIGluc3RhbGwgZG9ja2VyLWNvbXBvc2VcbiAgICAgICAgICAgICdjbWQgL2MgY3VybCAtdyBcIiV7cmVkaXJlY3RfdXJsfVwiIC1mc1MgaHR0cHM6Ly9naXRodWIuY29tL2RvY2tlci9jb21wb3NlL3JlbGVhc2VzL2xhdGVzdCA+ICRFbnY6VEVNUFxcXFxsYXRlc3QtZG9ja2VyLWNvbXBvc2UnLFxuICAgICAgICAgICAgJyRMYXRlc3RVcmwgPSBHZXQtQ29udGVudCAkRW52OlRFTVBcXFxcbGF0ZXN0LWRvY2tlci1jb21wb3NlJyxcbiAgICAgICAgICAgICckTGF0ZXN0RG9ja2VyQ29tcG9zZSA9ICgkTGF0ZXN0VXJsIC1TcGxpdCBcXCcvXFwnKVstMV0nLFxuICAgICAgICAgICAgJ0ludm9rZS1XZWJSZXF1ZXN0IC1Vc2VCYXNpY1BhcnNpbmcgLVVyaSAgXCJodHRwczovL2dpdGh1Yi5jb20vZG9ja2VyL2NvbXBvc2UvcmVsZWFzZXMvZG93bmxvYWQvJHtMYXRlc3REb2NrZXJDb21wb3NlfS9kb2NrZXItY29tcG9zZS1XaW5kb3dzLXg4Nl82NC5leGVcIiAtT3V0RmlsZSAkRW52OlByb2dyYW1GaWxlc1xcXFxEb2NrZXJcXFxcZG9ja2VyLWNvbXBvc2UuZXhlJyxcbiAgICAgICAgICAgICdOZXctSXRlbSAtSXRlbVR5cGUgZGlyZWN0b3J5IC1QYXRoIFwiJEVudjpQcm9ncmFtRmlsZXNcXFxcRG9ja2VyXFxcXGNsaS1wbHVnaW5zXCInLFxuICAgICAgICAgICAgJ0NvcHktSXRlbSAtUGF0aCBcIiRFbnY6UHJvZ3JhbUZpbGVzXFxcXERvY2tlclxcXFxkb2NrZXItY29tcG9zZS5leGVcIiAtRGVzdGluYXRpb24gXCIkRW52OlByb2dyYW1GaWxlc1xcXFxEb2NrZXJcXFxcY2xpLXBsdWdpbnNcXFxcZG9ja2VyLWNvbXBvc2UuZXhlXCInLFxuICAgICAgICAgIF07XG4gICAgICAgIH1cblxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFVua25vd24gb3MvYXJjaGl0ZWN0dXJlIGNvbWJvIGZvciBkb2NrZXI6ICR7b3MubmFtZX0vJHthcmNoaXRlY3R1cmUubmFtZX1gKTtcbiAgICAgIH1cblxuICAgICAgc2hvdWxkUmVib290KG9zOiBPcywgX2FyY2hpdGVjdHVyZTogQXJjaGl0ZWN0dXJlKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiBvcy5pcyhPcy5XSU5ET1dTKTtcbiAgICAgIH1cbiAgICB9KCk7XG4gIH1cblxuICAvKipcbiAgICogQSBjb21wb25lbnQgdG8gaW5zdGFsbCBEb2NrZXItaW4tRG9ja2VyLlxuICAgKi9cbiAgc3RhdGljIGRvY2tlckluRG9ja2VyKCk6IFJ1bm5lckltYWdlQ29tcG9uZW50IHtcbiAgICByZXR1cm4gbmV3IGNsYXNzIGV4dGVuZHMgUnVubmVySW1hZ2VDb21wb25lbnQge1xuICAgICAgbmFtZSA9ICdEb2NrZXItaW4tRG9ja2VyJztcblxuICAgICAgZ2V0Q29tbWFuZHMob3M6IE9zLCBhcmNoaXRlY3R1cmU6IEFyY2hpdGVjdHVyZSkge1xuICAgICAgICBpZiAob3MuaXMoT3MuTElOVVhfVUJVTlRVKSB8fCBvcy5pcyhPcy5MSU5VWF9BTUFaT05fMikpIHtcbiAgICAgICAgICBsZXQgYXJjaFVybDogc3RyaW5nO1xuICAgICAgICAgIGlmIChhcmNoaXRlY3R1cmUuaXMoQXJjaGl0ZWN0dXJlLlg4Nl82NCkpIHtcbiAgICAgICAgICAgIGFyY2hVcmwgPSAneDg2XzY0JztcbiAgICAgICAgICB9IGVsc2UgaWYgKGFyY2hpdGVjdHVyZS5pcyhBcmNoaXRlY3R1cmUuQVJNNjQpKSB7XG4gICAgICAgICAgICBhcmNoVXJsID0gJ2FhcmNoNjQnO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFVuc3VwcG9ydGVkIGFyY2hpdGVjdHVyZSBmb3IgRG9ja2VyLWluLURvY2tlcjogJHthcmNoaXRlY3R1cmUubmFtZX1gKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICByZXR1cm4gW1xuICAgICAgICAgICAgb3MuaXMoT3MuTElOVVhfVUJVTlRVKSA/ICdERUJJQU5fRlJPTlRFTkQ9bm9uaW50ZXJhY3RpdmUgYXB0LWdldCBpbnN0YWxsIC15IHNvY2F0JyA6ICd5dW0gaW5zdGFsbCAteSBzb2NhdCcsIC8vIGZvciBFQ1NcbiAgICAgICAgICAgICdET0NLRVJfQ0hBTk5FTD1cInN0YWJsZVwiJyxcbiAgICAgICAgICAgICdESU5EX0NPTU1JVD1cIjQyYjExNzVlZGEwNzFjMGU5MTIxZTFkNjQzNDU5MjgzODRhOTNkZjFcIicsXG4gICAgICAgICAgICAnRE9DS0VSX1ZFUlNJT049XCIyMC4xMC4xOFwiJyxcbiAgICAgICAgICAgICdET0NLRVJfQ09NUE9TRV9WRVJTSU9OPVwiMi4xMS4wXCInLFxuICAgICAgICAgICAgYGN1cmwgLWZzU0wgXCJodHRwczovL2Rvd25sb2FkLmRvY2tlci5jb20vbGludXgvc3RhdGljL1xcJHtET0NLRVJfQ0hBTk5FTH0vJHthcmNoVXJsfS9kb2NrZXItXFwke0RPQ0tFUl9WRVJTSU9OfS50Z3pcIiAtbyBkb2NrZXIudGd6YCxcbiAgICAgICAgICAgICd0YXIgLS1zdHJpcC1jb21wb25lbnRzIDEgLUMgL3Vzci9sb2NhbC9iaW4vIC14emYgZG9ja2VyLnRneicsXG4gICAgICAgICAgICAncm0gZG9ja2VyLnRneicsXG4gICAgICAgICAgICAnIyBzZXQgdXAgc3VidWlkL3N1YmdpZCBzbyB0aGF0IFwiLS11c2VybnMtcmVtYXA9ZGVmYXVsdFwiIHdvcmtzIG91dC1vZi10aGUgYm94JyxcbiAgICAgICAgICAgICdhZGRncm91cCBkb2NrcmVtYXAnLFxuICAgICAgICAgICAgJ3VzZXJhZGQgLWcgZG9ja3JlbWFwIGRvY2tyZW1hcCcsXG4gICAgICAgICAgICAnZWNobyBcXCdkb2NrcmVtYXA6MTY1NTM2OjY1NTM2XFwnID4+IC9ldGMvc3VidWlkJyxcbiAgICAgICAgICAgICdlY2hvIFxcJ2RvY2tyZW1hcDoxNjU1MzY6NjU1MzZcXCcgPj4gL2V0Yy9zdWJnaWQnLFxuICAgICAgICAgICAgJ2N1cmwgLWZzU0wgXCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vZG9ja2VyL2RvY2tlci8ke0RJTkRfQ09NTUlUfS9oYWNrL2RpbmRcIiAtbyAvdXNyL2xvY2FsL2Jpbi9kaW5kJyxcbiAgICAgICAgICAgIGBjdXJsIC1mc1NMIGh0dHBzOi8vZ2l0aHViLmNvbS9kb2NrZXIvY29tcG9zZS9yZWxlYXNlcy9kb3dubG9hZC92XFwke0RPQ0tFUl9DT01QT1NFX1ZFUlNJT059L2RvY2tlci1jb21wb3NlLWxpbnV4LSR7YXJjaFVybH0gLW8gL3Vzci9sb2NhbC9iaW4vZG9ja2VyLWNvbXBvc2VgLFxuICAgICAgICAgICAgJ21rZGlyIC1wIC9ob21lL3J1bm5lci8uZG9ja2VyL2NsaS1wbHVnaW5zICYmIGxuIC1zIC91c3IvbG9jYWwvYmluL2RvY2tlci1jb21wb3NlIC9ob21lL3J1bm5lci8uZG9ja2VyL2NsaS1wbHVnaW5zL2RvY2tlci1jb21wb3NlJyxcbiAgICAgICAgICAgICdjaG93biAtUiBydW5uZXIgL2hvbWUvcnVubmVyLy5kb2NrZXInLFxuICAgICAgICAgICAgJ2NobW9kICt4IC91c3IvbG9jYWwvYmluL2RpbmQgL3Vzci9sb2NhbC9iaW4vZG9ja2VyLWNvbXBvc2UnLFxuICAgICAgICAgICAgJ2FkZGdyb3VwIGRvY2tlciAmJiB1c2VybW9kIC1hRyBkb2NrZXIgcnVubmVyJyxcbiAgICAgICAgICBdO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbmtub3duIG9zL2FyY2hpdGVjdHVyZSBjb21ibyBmb3IgRG9ja2VyLWluLURvY2tlcjogJHtvcy5uYW1lfS8ke2FyY2hpdGVjdHVyZS5uYW1lfWApO1xuICAgICAgfVxuICAgIH0oKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBIGNvbXBvbmVudCB0byBhZGQgYSB0cnVzdGVkIGNlcnRpZmljYXRlIGF1dGhvcml0eS4gVGhpcyBjYW4gYmUgdXNlZCB0byBzdXBwb3J0IEdpdEh1YiBFbnRlcnByaXNlIFNlcnZlciB3aXRoIHNlbGYtc2lnbmVkIGNlcnRpZmljYXRlLlxuICAgKlxuICAgKiBAcGFyYW0gc291cmNlIHBhdGggdG8gY2VydGlmaWNhdGUgZmlsZSBpbiBQRU0gZm9ybWF0XG4gICAqIEBwYXJhbSBuYW1lIHVuaXF1ZSBjZXJ0aWZpY2F0ZSBuYW1lIHRvIGJlIHVzZWQgb24gcnVubmVyIGZpbGUgc3lzdGVtXG4gICAqL1xuICBzdGF0aWMgZXh0cmFDZXJ0aWZpY2F0ZXMoc291cmNlOiBzdHJpbmcsIG5hbWU6IHN0cmluZyk6IFJ1bm5lckltYWdlQ29tcG9uZW50IHtcbiAgICByZXR1cm4gbmV3IGNsYXNzIGV4dGVuZHMgUnVubmVySW1hZ2VDb21wb25lbnQge1xuICAgICAgbmFtZSA9IGBFeHRyYS1DZXJ0aWZpY2F0ZXMtJHtuYW1lfWA7XG5cbiAgICAgIGdldENvbW1hbmRzKG9zOiBPcywgYXJjaGl0ZWN0dXJlOiBBcmNoaXRlY3R1cmUpIHtcbiAgICAgICAgaWYgKCFuYW1lLm1hdGNoKC9eW2EtekEtWjAtOV8tXSskLykpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgY2VydGlmaWNhdGUgbmFtZTogJHtuYW1lfS4gTmFtZSBtdXN0IG9ubHkgY29udGFpbiBhbHBoYW51bWVyaWMgY2hhcmFjdGVycywgZGFzaGVzIGFuZCB1bmRlcnNjb3Jlcy5gKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChvcy5pcyhPcy5MSU5VWF9VQlVOVFUpKSB7XG4gICAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICAgICd1cGRhdGUtY2EtY2VydGlmaWNhdGVzJyxcbiAgICAgICAgICBdO1xuICAgICAgICB9IGVsc2UgaWYgKG9zLmlzKE9zLkxJTlVYX0FNQVpPTl8yKSkge1xuICAgICAgICAgIHJldHVybiBbXG4gICAgICAgICAgICAndXBkYXRlLWNhLXRydXN0JyxcbiAgICAgICAgICBdO1xuICAgICAgICB9IGVsc2UgaWYgKG9zLmlzKE9zLldJTkRPV1MpKSB7XG4gICAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICAgIGBJbXBvcnQtQ2VydGlmaWNhdGUgLUZpbGVQYXRoIEM6XFxcXCR7bmFtZX0uY3J0IC1DZXJ0U3RvcmVMb2NhdGlvbiBDZXJ0OlxcXFxMb2NhbE1hY2hpbmVcXFxcUm9vdGAsXG4gICAgICAgICAgICBgUmVtb3ZlLUl0ZW0gQzpcXFxcJHtuYW1lfS5jcnRgLFxuICAgICAgICAgIF07XG4gICAgICAgIH1cblxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFVua25vd24gb3MvYXJjaGl0ZWN0dXJlIGNvbWJvIGZvciBleHRyYSBjZXJ0aWZpY2F0ZXM6ICR7b3MubmFtZX0vJHthcmNoaXRlY3R1cmUubmFtZX1gKTtcbiAgICAgIH1cblxuICAgICAgZ2V0QXNzZXRzKG9zOiBPcywgX2FyY2hpdGVjdHVyZTogQXJjaGl0ZWN0dXJlKTogUnVubmVySW1hZ2VBc3NldFtdIHtcbiAgICAgICAgaWYgKG9zLmlzKE9zLkxJTlVYX1VCVU5UVSkpIHtcbiAgICAgICAgICByZXR1cm4gW1xuICAgICAgICAgICAgeyBzb3VyY2UsIHRhcmdldDogYC91c3IvbG9jYWwvc2hhcmUvY2EtY2VydGlmaWNhdGVzLyR7bmFtZX0uY3J0YCB9LFxuICAgICAgICAgIF07XG4gICAgICAgIH0gZWxzZSBpZiAob3MuaXMoT3MuTElOVVhfQU1BWk9OXzIpKSB7XG4gICAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICAgIHsgc291cmNlLCB0YXJnZXQ6IGAvZXRjL3BraS9jYS10cnVzdC9zb3VyY2UvYW5jaG9ycy8ke25hbWV9LmNydGAgfSxcbiAgICAgICAgICBdO1xuICAgICAgICB9IGVsc2UgaWYgKG9zLmlzKE9zLldJTkRPV1MpKSB7XG4gICAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICAgIHsgc291cmNlLCB0YXJnZXQ6IGBDOlxcXFwke25hbWV9LmNydGAgfSxcbiAgICAgICAgICBdO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbnN1cHBvcnRlZCBPUyBmb3IgZXh0cmEgY2VydGlmaWNhdGVzOiAke29zLm5hbWV9YCk7XG4gICAgICB9XG4gICAgfSgpO1xuICB9XG5cbiAgLyoqXG4gICAqIEEgY29tcG9uZW50IHRvIHNldCB1cCB0aGUgcmVxdWlyZWQgTGFtYmRhIGVudHJ5cG9pbnQgZm9yIExhbWJkYSBydW5uZXJzLlxuICAgKi9cbiAgc3RhdGljIGxhbWJkYUVudHJ5cG9pbnQoKTogUnVubmVySW1hZ2VDb21wb25lbnQge1xuICAgIHJldHVybiBuZXcgY2xhc3MgZXh0ZW5kcyBSdW5uZXJJbWFnZUNvbXBvbmVudCB7XG4gICAgICBuYW1lID0gJ0xhbWJkYS1FbnRyeXBvaW50JztcblxuICAgICAgZ2V0Q29tbWFuZHMob3M6IE9zLCBfYXJjaGl0ZWN0dXJlOiBBcmNoaXRlY3R1cmUpIHtcbiAgICAgICAgaWYgKCFvcy5pcyhPcy5MSU5VWF9BTUFaT05fMikgJiYgIW9zLmlzKE9zLkxJTlVYX1VCVU5UVSkpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFVuc3VwcG9ydGVkIE9TIGZvciBMYW1iZGEgZW50cnlwb2ludDogJHtvcy5uYW1lfWApO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIFtdO1xuICAgICAgfVxuXG4gICAgICBnZXRBc3NldHMoX29zOiBPcywgX2FyY2hpdGVjdHVyZTogQXJjaGl0ZWN0dXJlKTogUnVubmVySW1hZ2VBc3NldFtdIHtcbiAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICB7XG4gICAgICAgICAgICBzb3VyY2U6IHBhdGguam9pbihfX2Rpcm5hbWUsICcuLicsICcuLicsICdhc3NldHMnLCAnZG9ja2VyLWltYWdlcycsICdsYW1iZGEnLCAnbGludXgteDY0JywgJ3J1bm5lci5qcycpLFxuICAgICAgICAgICAgdGFyZ2V0OiAnJHtMQU1CREFfVEFTS19ST09UfS9ydW5uZXIuanMnLFxuICAgICAgICAgIH0sXG4gICAgICAgICAge1xuICAgICAgICAgICAgc291cmNlOiBwYXRoLmpvaW4oX19kaXJuYW1lLCAnLi4nLCAnLi4nLCAnYXNzZXRzJywgJ2RvY2tlci1pbWFnZXMnLCAnbGFtYmRhJywgJ2xpbnV4LXg2NCcsICdydW5uZXIuc2gnKSxcbiAgICAgICAgICAgIHRhcmdldDogJyR7TEFNQkRBX1RBU0tfUk9PVH0vcnVubmVyLnNoJyxcbiAgICAgICAgICB9LFxuICAgICAgICBdO1xuICAgICAgfVxuXG4gICAgICBnZXREb2NrZXJDb21tYW5kcyhfb3M6IE9zLCBfYXJjaGl0ZWN0dXJlOiBBcmNoaXRlY3R1cmUpOiBzdHJpbmdbXSB7XG4gICAgICAgIHJldHVybiBbXG4gICAgICAgICAgJ1dPUktESVIgJHtMQU1CREFfVEFTS19ST09UfScsXG4gICAgICAgICAgJ0NNRCBbXCJydW5uZXIuaGFuZGxlclwiXScsXG4gICAgICAgIF07XG4gICAgICB9XG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDb21wb25lbnQgbmFtZS5cbiAgICpcbiAgICogVXNlZCB0byBpZGVudGlmeSBjb21wb25lbnQgaW4gaW1hZ2UgYnVpbGQgbG9ncywgYW5kIGZvciB7QGxpbmsgUnVubmVySW1hZ2VCdWlsZGVyLnJlbW92ZUNvbXBvbmVudH1cbiAgICovXG4gIGFic3RyYWN0IHJlYWRvbmx5IG5hbWU6IHN0cmluZztcblxuICAvKipcbiAgICogUmV0dXJucyBjb21tYW5kcyB0byBydW4gdG8gaW4gYnVpbHQgaW1hZ2UuIENhbiBiZSB1c2VkIHRvIGluc3RhbGwgcGFja2FnZXMsIHNldHVwIGJ1aWxkIHByZXJlcXVpc2l0ZXMsIGV0Yy5cbiAgICovXG4gIGFic3RyYWN0IGdldENvbW1hbmRzKF9vczogT3MsIF9hcmNoaXRlY3R1cmU6IEFyY2hpdGVjdHVyZSk6IHN0cmluZ1tdO1xuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGFzc2V0cyB0byBjb3B5IGludG8gdGhlIGJ1aWx0IGltYWdlLiBDYW4gYmUgdXNlZCB0byBjb3B5IGZpbGVzIGludG8gdGhlIGltYWdlLlxuICAgKi9cbiAgZ2V0QXNzZXRzKF9vczogT3MsIF9hcmNoaXRlY3R1cmU6IEFyY2hpdGVjdHVyZSk6IFJ1bm5lckltYWdlQXNzZXRbXSB7XG4gICAgcmV0dXJuIFtdO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgRG9ja2VyIGNvbW1hbmRzIHRvIHJ1biB0byBpbiBidWlsdCBpbWFnZS4gQ2FuIGJlIHVzZWQgdG8gYWRkIGNvbW1hbmRzIGxpa2UgYFZPTFVNRWAsIGBFTlRSWVBPSU5UYCwgYENNRGAsIGV0Yy5cbiAgICpcbiAgICogRG9ja2VyIGNvbW1hbmRzIGFyZSBhZGRlZCBhZnRlciBhc3NldHMgYW5kIG5vcm1hbCBjb21tYW5kcy5cbiAgICovXG4gIGdldERvY2tlckNvbW1hbmRzKF9vczogT3MsIF9hcmNoaXRlY3R1cmU6IEFyY2hpdGVjdHVyZSk6IHN0cmluZ1tdIHtcbiAgICByZXR1cm4gW107XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyB0cnVlIGlmIHRoZSBpbWFnZSBidWlsZGVyIHNob3VsZCBiZSByZWJvb3RlZCBhZnRlciB0aGlzIGNvbXBvbmVudCBpcyBpbnN0YWxsZWQuXG4gICAqL1xuICBzaG91bGRSZWJvb3QoX29zOiBPcywgX2FyY2hpdGVjdHVyZTogQXJjaGl0ZWN0dXJlKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgLyoqXG4gICAqIENvbnZlcnQgY29tcG9uZW50IHRvIGFuIEFXUyBJbWFnZSBCdWlsZGVyIGNvbXBvbmVudC5cbiAgICpcbiAgICogQGludGVybmFsXG4gICAqL1xuICBfYXNBd3NJbWFnZUJ1aWxkZXJDb21wb25lbnQoc2NvcGU6IENvbnN0cnVjdCwgaWQ6IHN0cmluZywgb3M6IE9zLCBhcmNoaXRlY3R1cmU6IEFyY2hpdGVjdHVyZSkge1xuICAgIGxldCBwbGF0Zm9ybTogJ0xpbnV4JyB8ICdXaW5kb3dzJztcbiAgICBpZiAob3MuaXMoT3MuTElOVVhfVUJVTlRVKSB8fCBvcy5pcyhPcy5MSU5VWF9BTUFaT05fMikpIHtcbiAgICAgIHBsYXRmb3JtID0gJ0xpbnV4JztcbiAgICB9IGVsc2UgaWYgKG9zLmlzKE9zLldJTkRPV1MpKSB7XG4gICAgICBwbGF0Zm9ybSA9ICdXaW5kb3dzJztcbiAgICB9IGVsc2Uge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbmtub3duIG9zL2FyY2hpdGVjdHVyZSBjb21ibyBmb3IgaW1hZ2UgYnVpbGRlciBjb21wb25lbnQ6ICR7b3MubmFtZX0vJHthcmNoaXRlY3R1cmUubmFtZX1gKTtcbiAgICB9XG5cbiAgICByZXR1cm4gbmV3IEltYWdlQnVpbGRlckNvbXBvbmVudChzY29wZSwgaWQsIHtcbiAgICAgIHBsYXRmb3JtOiBwbGF0Zm9ybSxcbiAgICAgIGNvbW1hbmRzOiB0aGlzLmdldENvbW1hbmRzKG9zLCBhcmNoaXRlY3R1cmUpLFxuICAgICAgYXNzZXRzOiB0aGlzLmdldEFzc2V0cyhvcywgYXJjaGl0ZWN0dXJlKS5tYXAoKGFzc2V0LCBpbmRleCkgPT4ge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIGFzc2V0OiBuZXcgczNfYXNzZXRzLkFzc2V0KHNjb3BlLCBgJHtpZH0gYXNzZXQgJHtpbmRleH1gLCB7IHBhdGg6IGFzc2V0LnNvdXJjZSB9KSxcbiAgICAgICAgICBwYXRoOiBhc3NldC50YXJnZXQsXG4gICAgICAgIH07XG4gICAgICB9KSxcbiAgICAgIGRpc3BsYXlOYW1lOiBpZCxcbiAgICAgIGRlc2NyaXB0aW9uOiBpZCxcbiAgICAgIHJlYm9vdDogdGhpcy5zaG91bGRSZWJvb3Qob3MsIGFyY2hpdGVjdHVyZSksXG4gICAgfSk7XG4gIH1cbn1cblxuIl19