@cloudsnorkel/cdk-github-runners 0.9.4 → 0.9.5
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/.gitattributes +3 -3
- package/.jsii +315 -267
- package/API.md +43 -7
- package/README.md +15 -2
- package/assets/{providers/image-builders → image-builders}/aws-image-builder/delete-ami.lambda/index.js +2 -2
- package/assets/{providers/image-builders → image-builders}/aws-image-builder/filter-failed-builds.lambda/index.js +1 -1
- package/assets/{providers/image-builders → image-builders}/aws-image-builder/versioner.lambda/index.js +2 -2
- package/lib/access.js +1 -1
- package/lib/image-builders/api.js +47 -0
- package/lib/{providers/image-builders → image-builders}/aws-image-builder/ami.d.ts +2 -3
- package/lib/image-builders/aws-image-builder/ami.js +93 -0
- package/lib/{providers/image-builders → image-builders}/aws-image-builder/builder.d.ts +9 -2
- package/lib/image-builders/aws-image-builder/builder.js +529 -0
- package/lib/image-builders/aws-image-builder/common.js +46 -0
- package/lib/{providers/image-builders → image-builders}/aws-image-builder/container.d.ts +1 -1
- package/lib/image-builders/aws-image-builder/container.js +63 -0
- package/lib/{providers/image-builders → image-builders}/aws-image-builder/delete-ami-function.d.ts +1 -1
- package/lib/image-builders/aws-image-builder/delete-ami-function.js +23 -0
- package/lib/image-builders/aws-image-builder/delete-ami.lambda.js +87 -0
- package/lib/{providers/image-builders → image-builders}/aws-image-builder/deprecated/ami.d.ts +2 -2
- package/lib/image-builders/aws-image-builder/deprecated/ami.js +240 -0
- package/lib/{providers/image-builders → image-builders}/aws-image-builder/deprecated/common.d.ts +1 -1
- package/lib/image-builders/aws-image-builder/deprecated/common.js +144 -0
- package/lib/{providers/image-builders → image-builders}/aws-image-builder/deprecated/container.d.ts +1 -1
- package/lib/image-builders/aws-image-builder/deprecated/container.js +222 -0
- package/lib/{providers/image-builders → image-builders}/aws-image-builder/deprecated/index.js +1 -1
- package/lib/{providers/image-builders → image-builders}/aws-image-builder/deprecated/linux-components.d.ts +1 -1
- package/lib/image-builders/aws-image-builder/deprecated/linux-components.js +172 -0
- package/lib/{providers/image-builders → image-builders}/aws-image-builder/deprecated/windows-components.d.ts +1 -1
- package/lib/image-builders/aws-image-builder/deprecated/windows-components.js +126 -0
- package/lib/{providers/image-builders → image-builders}/aws-image-builder/filter-failed-builds-function.d.ts +1 -1
- package/lib/image-builders/aws-image-builder/filter-failed-builds-function.js +23 -0
- package/lib/image-builders/aws-image-builder/filter-failed-builds.lambda.js +18 -0
- package/lib/{providers/image-builders → image-builders}/aws-image-builder/index.js +1 -1
- package/lib/{providers/image-builders → image-builders}/aws-image-builder/versioner-function.d.ts +1 -1
- package/lib/image-builders/aws-image-builder/versioner-function.js +23 -0
- package/lib/image-builders/aws-image-builder/versioner.lambda.js +96 -0
- package/lib/{providers/image-builders → image-builders}/codebuild-deprecated.d.ts +2 -2
- package/lib/image-builders/codebuild-deprecated.js +373 -0
- package/lib/{providers/image-builders → image-builders}/codebuild.d.ts +2 -2
- package/lib/image-builders/codebuild.js +287 -0
- package/lib/{providers/image-builders → image-builders}/common.d.ts +4 -2
- package/lib/image-builders/common.js +61 -0
- package/lib/{providers/image-builders → image-builders}/components.d.ts +8 -2
- package/lib/image-builders/components.js +568 -0
- package/lib/{providers/image-builders → image-builders}/index.js +1 -1
- package/lib/{providers/image-builders → image-builders}/static.d.ts +1 -1
- package/lib/image-builders/static.js +58 -0
- package/lib/providers/codebuild.d.ts +1 -1
- package/lib/providers/codebuild.js +4 -4
- package/lib/providers/common.js +3 -3
- package/lib/providers/ec2.d.ts +1 -1
- package/lib/providers/ec2.js +4 -4
- package/lib/providers/ecs.d.ts +1 -1
- package/lib/providers/ecs.js +3 -3
- package/lib/providers/fargate.d.ts +1 -1
- package/lib/providers/fargate.js +4 -4
- package/lib/providers/index.d.ts +1 -1
- package/lib/providers/index.js +2 -2
- package/lib/providers/lambda.d.ts +1 -1
- package/lib/providers/lambda.js +4 -4
- package/lib/runner.js +1 -1
- package/lib/secrets.js +1 -1
- package/package.json +10 -10
- package/lib/providers/image-builders/api.js +0 -47
- package/lib/providers/image-builders/aws-image-builder/ami.js +0 -81
- package/lib/providers/image-builders/aws-image-builder/builder.js +0 -520
- package/lib/providers/image-builders/aws-image-builder/common.js +0 -46
- package/lib/providers/image-builders/aws-image-builder/container.js +0 -63
- package/lib/providers/image-builders/aws-image-builder/delete-ami-function.js +0 -23
- package/lib/providers/image-builders/aws-image-builder/delete-ami.lambda.js +0 -87
- package/lib/providers/image-builders/aws-image-builder/deprecated/ami.js +0 -240
- package/lib/providers/image-builders/aws-image-builder/deprecated/common.js +0 -144
- package/lib/providers/image-builders/aws-image-builder/deprecated/container.js +0 -222
- package/lib/providers/image-builders/aws-image-builder/deprecated/linux-components.js +0 -172
- package/lib/providers/image-builders/aws-image-builder/deprecated/windows-components.js +0 -129
- package/lib/providers/image-builders/aws-image-builder/filter-failed-builds-function.js +0 -23
- package/lib/providers/image-builders/aws-image-builder/filter-failed-builds.lambda.js +0 -18
- package/lib/providers/image-builders/aws-image-builder/versioner-function.js +0 -23
- package/lib/providers/image-builders/aws-image-builder/versioner.lambda.js +0 -96
- package/lib/providers/image-builders/codebuild-deprecated.js +0 -373
- package/lib/providers/image-builders/codebuild.js +0 -287
- package/lib/providers/image-builders/common.js +0 -61
- package/lib/providers/image-builders/components.js +0 -535
- package/lib/providers/image-builders/static.js +0 -58
- /package/lib/{providers/image-builders → image-builders}/api.d.ts +0 -0
- /package/lib/{providers/image-builders → image-builders}/aws-image-builder/common.d.ts +0 -0
- /package/lib/{providers/image-builders → image-builders}/aws-image-builder/delete-ami.lambda.d.ts +0 -0
- /package/lib/{providers/image-builders → image-builders}/aws-image-builder/deprecated/index.d.ts +0 -0
- /package/lib/{providers/image-builders → image-builders}/aws-image-builder/filter-failed-builds.lambda.d.ts +0 -0
- /package/lib/{providers/image-builders → image-builders}/aws-image-builder/index.d.ts +0 -0
- /package/lib/{providers/image-builders → image-builders}/aws-image-builder/versioner.lambda.d.ts +0 -0
- /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, '..', 'providers', 'docker-images', 'lambda', 'linux-x64', 'runner.js'),
|
|
498
|
+
target: '${LAMBDA_TASK_ROOT}/runner.js',
|
|
499
|
+
},
|
|
500
|
+
{
|
|
501
|
+
source: path.join(__dirname, '..', 'providers', '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.5" };
|
|
567
|
+
exports.RunnerImageComponent = RunnerImageComponent;
|
|
568
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tcG9uZW50cy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9pbWFnZS1idWlsZGVycy9jb21wb25lbnRzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsNkJBQTZCO0FBQzdCLDZDQUF5RDtBQUV6RCwyREFBNEQ7QUFFNUQsNENBQStEO0FBOEIvRDs7R0FFRztBQUNILE1BQXNCLG9CQUFvQjtJQUN4Qzs7Ozs7Ozs7T0FRRztJQUNILE1BQU0sQ0FBQyxNQUFNLENBQUMsS0FBc0M7UUFDbEQsT0FBTyxJQUFJLEtBQU0sU0FBUSxvQkFBb0I7WUFDM0MsSUFBSSxJQUFJO2dCQUNOLElBQUksS0FBSyxDQUFDLElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLGVBQWUsQ0FBQyxFQUFFO29CQUNwRCxNQUFNLElBQUksS0FBSyxDQUFDLDJCQUEyQixLQUFLLENBQUMsSUFBSSw4REFBOEQsQ0FBQyxDQUFDO2lCQUN0SDtnQkFDRCxPQUFPLFVBQVUsS0FBSyxDQUFDLElBQUksSUFBSSxXQUFXLEVBQUUsQ0FBQztZQUMvQyxDQUFDO1lBRUQsV0FBVyxDQUFDLEdBQU8sRUFBRSxhQUEyQjtnQkFDOUMsT0FBTyxLQUFLLENBQUMsUUFBUSxJQUFJLEVBQUUsQ0FBQztZQUM5QixDQUFDO1lBQ0QsU0FBUyxDQUFDLEdBQU8sRUFBRSxhQUEyQjtnQkFDNUMsT0FBTyxLQUFLLENBQUMsTUFBTSxJQUFJLEVBQUUsQ0FBQztZQUM1QixDQUFDO1lBRUQsaUJBQWlCLENBQUMsR0FBTyxFQUFFLGFBQTJCO2dCQUNwRCxPQUFPLEtBQUssQ0FBQyxjQUFjLElBQUksRUFBRSxDQUFDO1lBQ3BDLENBQUM7U0FDRixFQUFFLENBQUM7SUFDTixDQUFDO0lBRUQ7O09BRUc7SUFDSCxNQUFNLENBQUMsZ0JBQWdCO1FBQ3JCLE9BQU8sSUFBSSxLQUFNLFNBQVEsb0JBQW9CO1lBQWxDOztnQkFDVCxTQUFJLEdBQUcsa0JB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RSxFQUFFLFlBQVksQ0FBQztTQUM1QyxDQUFDLENBQUM7SUFDTCxDQUFDOzs7O0FBM2lCbUIsb0RBQW9CIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgcGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCB7IGF3c19zM19hc3NldHMgYXMgczNfYXNzZXRzIH0gZnJvbSAnYXdzLWNkay1saWInO1xuaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSAnY29uc3RydWN0cyc7XG5pbXBvcnQgeyBJbWFnZUJ1aWxkZXJDb21wb25lbnQgfSBmcm9tICcuL2F3cy1pbWFnZS1idWlsZGVyJztcbmltcG9ydCB7IFJ1bm5lckltYWdlQXNzZXQgfSBmcm9tICcuL2NvbW1vbic7XG5pbXBvcnQgeyBBcmNoaXRlY3R1cmUsIE9zLCBSdW5uZXJWZXJzaW9uIH0gZnJvbSAnLi4vcHJvdmlkZXJzJztcblxuZXhwb3J0IGludGVyZmFjZSBSdW5uZXJJbWFnZUNvbXBvbmVudEN1c3RvbVByb3BzIHtcbiAgLyoqXG4gICAqIENvbXBvbmVudCBuYW1lIHVzZWQgZm9yICgxKSBpbWFnZSBidWlsZCBsb2dnaW5nIGFuZCAoMikgaWRlbnRpZmllciBmb3Ige0BsaW5rIEltYWdlUnVubmVyQnVpbGRlci5yZW1vdmVDb21wb25lbnR9LlxuICAgKlxuICAgKiBOYW1lIG11c3Qgb25seSBjb250YWluIGFscGhhbnVtZXJpYyBjaGFyYWN0ZXJzIGFuZCBkYXNoZXMuXG4gICAqL1xuICByZWFkb25seSBuYW1lPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBDb21tYW5kcyB0byBydW4gaW4gdGhlIGJ1aWx0IGltYWdlLlxuICAgKi9cbiAgcmVhZG9ubHkgY29tbWFuZHM/OiBzdHJpbmdbXTtcblxuICAvKipcbiAgICogQXNzZXRzIHRvIGNvcHkgaW50byB0aGUgYnVpbHQgaW1hZ2UuXG4gICAqL1xuICByZWFkb25seSBhc3NldHM/OiBSdW5uZXJJbWFnZUFzc2V0W107XG5cbiAgLyoqXG4gICAqIERvY2tlciBjb21tYW5kcyB0byBydW4gaW4gdGhlIGJ1aWx0IGltYWdlLlxuICAgKlxuICAgKiBGb3IgZXhhbXBsZTogYFsnRU5WIGZvbz1iYXInLCAnUlVOIGVjaG8gJGZvbyddYFxuICAgKlxuICAgKiBUaGVzZSBjb21tYW5kcyBhcmUgaWdub3JlZCB3aGVuIGJ1aWxkaW5nIEFNSXMuXG4gICAqL1xuICByZWFkb25seSBkb2NrZXJDb21tYW5kcz86IHN0cmluZ1tdO1xufVxuXG4vKipcbiAqIENvbXBvbmVudHMgYXJlIHVzZWQgdG8gYnVpbGQgcnVubmVyIGltYWdlcy4gVGhleSBjYW4gcnVuIGNvbW1hbmRzIGluIHRoZSBpbWFnZSwgY29weSBmaWxlcyBpbnRvIHRoZSBpbWFnZSwgYW5kIHJ1biBzb21lIERvY2tlciBjb21tYW5kcy5cbiAqL1xuZXhwb3J0IGFic3RyYWN0IGNsYXNzIFJ1bm5lckltYWdlQ29tcG9uZW50IHtcbiAgLyoqXG4gICAqIERlZmluZSBhIGN1c3RvbSBjb21wb25lbnQgdGhhdCBjYW4gcnVuIGNvbW1hbmRzIGluIHRoZSBpbWFnZSwgY29weSBmaWxlcyBpbnRvIHRoZSBpbWFnZSwgYW5kIHJ1biBzb21lIERvY2tlciBjb21tYW5kcy5cbiAgICpcbiAgICogVGhlIG9yZGVyIG9mIG9wZXJhdGlvbnMgaXMgKDEpIGFzc2V0cyAoMikgY29tbWFuZHMgKDMpIGRvY2tlciBjb21tYW5kcy5cbiAgICpcbiAgICogVXNlIHRoaXMgdG8gY3VzdG9taXplIHRoZSBpbWFnZSBmb3IgdGhlIHJ1bm5lci5cbiAgICpcbiAgICogKipXQVJOSU5HOioqIERvY2tlciBjb21tYW5kcyBhcmUgbm90IGd1YXJhbnRlZWQgdG8gYmUgaW5jbHVkZWQgYmVmb3JlIHRoZSBuZXh0IGNvbXBvbmVudFxuICAgKi9cbiAgc3RhdGljIGN1c3RvbShwcm9wczogUnVubmVySW1hZ2VDb21wb25lbnRDdXN0b21Qcm9wcyk6IFJ1bm5lckltYWdlQ29tcG9uZW50IHtcbiAgICByZXR1cm4gbmV3IGNsYXNzIGV4dGVuZHMgUnVubmVySW1hZ2VDb21wb25lbnQge1xuICAgICAgZ2V0IG5hbWUoKSB7XG4gICAgICAgIGlmIChwcm9wcy5uYW1lICYmICFwcm9wcy5uYW1lLm1hdGNoKC9bYS16QS1aMC05XFwtXS8pKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIGNvbXBvbmVudCBuYW1lOiAke3Byb3BzLm5hbWV9LiBOYW1lIG11c3Qgb25seSBjb250YWluIGFscGhhbnVtZXJpYyBjaGFyYWN0ZXJzIGFuZCBkYXNoZXMuYCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGBDdXN0b20tJHtwcm9wcy5uYW1lID8/ICdVbmRlZmluZWQnfWA7XG4gICAgICB9XG5cbiAgICAgIGdldENvbW1hbmRzKF9vczogT3MsIF9hcmNoaXRlY3R1cmU6IEFyY2hpdGVjdHVyZSkge1xuICAgICAgICByZXR1cm4gcHJvcHMuY29tbWFuZHMgPz8gW107XG4gICAgICB9XG4gICAgICBnZXRBc3NldHMoX29zOiBPcywgX2FyY2hpdGVjdHVyZTogQXJjaGl0ZWN0dXJlKSB7XG4gICAgICAgIHJldHVybiBwcm9wcy5hc3NldHMgPz8gW107XG4gICAgICB9XG5cbiAgICAgIGdldERvY2tlckNvbW1hbmRzKF9vczogT3MsIF9hcmNoaXRlY3R1cmU6IEFyY2hpdGVjdHVyZSkge1xuICAgICAgICByZXR1cm4gcHJvcHMuZG9ja2VyQ29tbWFuZHMgPz8gW107XG4gICAgICB9XG4gICAgfSgpO1xuICB9XG5cbiAgLyoqXG4gICAqIEEgY29tcG9uZW50IHRvIGluc3RhbGwgdGhlIHJlcXVpcmVkIHBhY2thZ2VzIGZvciB0aGUgcnVubmVyLlxuICAgKi9cbiAgc3RhdGljIHJlcXVpcmVkUGFja2FnZXMoKTogUnVubmVySW1hZ2VDb21wb25lbnQge1xuICAgIHJldHVybiBuZXcgY2xhc3MgZXh0ZW5kcyBSdW5uZXJJbWFnZUNvbXBvbmVudCB7XG4gICAgICBuYW1lID0gJ1JlcXVpcmVkUGFja2FnZXMnO1xuXG4gICAgICBnZXRDb21tYW5kcyhvczogT3MsIGFyY2hpdGVjdHVyZTogQXJjaGl0ZWN0dXJlKTogc3RyaW5nW10ge1xuICAgICAgICBpZiAob3MuaXMoT3MuTElOVVhfVUJVTlRVKSkge1xuICAgICAgICAgIGxldCBhcmNoVXJsO1xuICAgICAgICAgIGlmIChhcmNoaXRlY3R1cmUuaXMoQXJjaGl0ZWN0dXJlLlg4Nl82NCkpIHtcbiAgICAgICAgICAgIGFyY2hVcmwgPSAnYW1kNjQnO1xuICAgICAgICAgIH0gZWxzZSBpZiAoYXJjaGl0ZWN0dXJlLmlzKEFyY2hpdGVjdHVyZS5BUk02NCkpIHtcbiAgICAgICAgICAgIGFyY2hVcmwgPSAnYXJtNjQnO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFVuc3VwcG9ydGVkIGFyY2hpdGVjdHVyZSBmb3IgcmVxdWlyZWQgcGFja2FnZXM6ICR7YXJjaGl0ZWN0dXJlLm5hbWV9YCk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICAgICdhcHQtZ2V0IHVwZGF0ZScsXG4gICAgICAgICAgICAnREVCSUFOX0ZST05URU5EPW5vbmludGVyYWN0aXZlIGFwdC1nZXQgdXBncmFkZSAteScsXG4gICAgICAgICAgICAnREVCSUFOX0ZST05URU5EPW5vbmludGVyYWN0aXZlIGFwdC1nZXQgaW5zdGFsbCAteSBjdXJsIHN1ZG8ganEgYmFzaCB6aXAgdW56aXAgaXB0YWJsZXMgc29mdHdhcmUtcHJvcGVydGllcy1jb21tb24gY2EtY2VydGlmaWNhdGVzJyxcbiAgICAgICAgICAgIGBjdXJsIC1zZkxvIC90bXAvYW1hem9uLWNsb3Vkd2F0Y2gtYWdlbnQuZGViIGh0dHBzOi8vczMuYW1hem9uYXdzLmNvbS9hbWF6b25jbG91ZHdhdGNoLWFnZW50L3VidW50dS8ke2FyY2hVcmx9L2xhdGVzdC9hbWF6b24tY2xvdWR3YXRjaC1hZ2VudC5kZWJgLFxuICAgICAgICAgICAgJ2Rwa2cgLWkgLUUgL3RtcC9hbWF6b24tY2xvdWR3YXRjaC1hZ2VudC5kZWInLFxuICAgICAgICAgICAgJ3JtIC90bXAvYW1hem9uLWNsb3Vkd2F0Y2gtYWdlbnQuZGViJyxcbiAgICAgICAgICBdO1xuICAgICAgICB9IGVsc2UgaWYgKG9zLmlzKE9zLkxJTlVYX0FNQVpPTl8yKSkge1xuICAgICAgICAgIHJldHVybiBbXG4gICAgICAgICAgICAneXVtIHVwZGF0ZSAteScsXG4gICAgICAgICAgICAneXVtIGluc3RhbGwgLXkganEgdGFyIGd6aXAgYnppcDIgd2hpY2ggYmludXRpbHMgemlwIHVuemlwIHN1ZG8gc2hhZG93LXV0aWxzJyxcbiAgICAgICAgICBdO1xuICAgICAgICB9IGVsc2UgaWYgKG9zLmlzKE9zLldJTkRPV1MpKSB7XG4gICAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICAgICckcCA9IFN0YXJ0LVByb2Nlc3MgbXNpZXhlYy5leGUgLVBhc3NUaHJ1IC1XYWl0IC1Bcmd1bWVudExpc3QgXFwnL2kgaHR0cHM6Ly9zMy5hbWF6b25hd3MuY29tL2FtYXpvbmNsb3Vkd2F0Y2gtYWdlbnQvd2luZG93cy9hbWQ2NC9sYXRlc3QvYW1hem9uLWNsb3Vkd2F0Y2gtYWdlbnQubXNpIC9xblxcJycsXG4gICAgICAgICAgICAnaWYgKCRwLkV4aXRDb2RlIC1uZSAwKSB7IHRocm93IFwiRXhpdCBjb2RlIGlzICRwLkV4aXRDb2RlXCIgfScsXG4gICAgICAgICAgXTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgVW5zdXBwb3J0ZWQgT1MgZm9yIHJlcXVpcmVkIHBhY2thZ2VzOiAke29zLm5hbWV9YCk7XG4gICAgICB9XG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBIGNvbXBvbmVudCB0byBwcmVwYXJlIHRoZSByZXF1aXJlZCBydW5uZXIgdXNlci5cbiAgICovXG4gIHN0YXRpYyBydW5uZXJVc2VyKCk6IFJ1bm5lckltYWdlQ29tcG9uZW50IHtcbiAgICByZXR1cm4gbmV3IGNsYXNzIGV4dGVuZHMgUnVubmVySW1hZ2VDb21wb25lbnQge1xuICAgICAgbmFtZSA9ICdSdW5uZXJVc2VyJztcblxuICAgICAgZ2V0Q29tbWFuZHMob3M6IE9zLCBfYXJjaGl0ZWN0dXJlOiBBcmNoaXRlY3R1cmUpOiBzdHJpbmdbXSB7XG4gICAgICAgIGlmIChvcy5pcyhPcy5MSU5VWF9VQlVOVFUpKSB7XG4gICAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICAgICdhZGRncm91cCBydW5uZXInLFxuICAgICAgICAgICAgJ2FkZHVzZXIgLS1zeXN0ZW0gLS1kaXNhYmxlZC1wYXNzd29yZCAtLWhvbWUgL2hvbWUvcnVubmVyIC0taW5ncm91cCBydW5uZXIgcnVubmVyJyxcbiAgICAgICAgICAgICd1c2VybW9kIC1hRyBzdWRvIHJ1bm5lcicsXG4gICAgICAgICAgICAnZWNobyBcIiVzdWRvICAgQUxMPShBTEw6QUxMKSBOT1BBU1NXRDogQUxMXCIgPiAvZXRjL3N1ZG9lcnMuZC9ydW5uZXInLFxuICAgICAgICAgIF07XG4gICAgICAgIH0gZWxzZSBpZiAob3MuaXMoT3MuTElOVVhfQU1BWk9OXzIpKSB7XG4gICAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICAgICcvdXNyL3NiaW4vZ3JvdXBhZGQgcnVubmVyJyxcbiAgICAgICAgICAgICcvdXNyL3NiaW4vdXNlcmFkZCAtLXN5c3RlbSAtLXNoZWxsIC91c3Ivc2Jpbi9ub2xvZ2luIC0taG9tZS1kaXIgL2hvbWUvcnVubmVyIC0tZ2lkIHJ1bm5lciBydW5uZXInLFxuICAgICAgICAgICAgJ21rZGlyIC1wIC9ob21lL3J1bm5lcicsXG4gICAgICAgICAgICAnY2hvd24gcnVubmVyIC9ob21lL3J1bm5lcicsXG4gICAgICAgICAgICAnZWNobyBcIiVydW5uZXIgICBBTEw9KEFMTDpBTEwpIE5PUEFTU1dEOiBBTExcIiA+IC9ldGMvc3Vkb2Vycy5kL3J1bm5lcicsXG4gICAgICAgICAgXTtcbiAgICAgICAgfSBlbHNlIGlmIChvcy5pcyhPcy5XSU5ET1dTKSkge1xuICAgICAgICAgIHJldHVybiBbXTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgVW5zdXBwb3J0ZWQgT1MgZm9yIHJ1bm5lciB1c2VyOiAke29zLm5hbWV9YCk7XG4gICAgICB9XG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBIGNvbXBvbmVudCB0byBpbnN0YWxsIHRoZSBBV1MgQ0xJLlxuICAgKi9cbiAgc3RhdGljIGF3c0NsaSgpOiBSdW5uZXJJbWFnZUNvbXBvbmVudCB7XG4gICAgcmV0dXJuIG5ldyBjbGFzcyBleHRlbmRzIFJ1bm5lckltYWdlQ29tcG9uZW50IHtcbiAgICAgIG5hbWUgPSAnQXdzQ2xpJztcblxuICAgICAgZ2V0Q29tbWFuZHMob3M6IE9zLCBhcmNoaXRlY3R1cmU6IEFyY2hpdGVjdHVyZSkge1xuICAgICAgICBpZiAob3MuaXMoT3MuTElOVVhfVUJVTlRVKSB8fCBvcy5pcyhPcy5MSU5VWF9BTUFaT05fMikpIHtcbiAgICAgICAgICBsZXQgYXJjaFVybDogc3RyaW5nO1xuICAgICAgICAgIGlmIChhcmNoaXRlY3R1cmUuaXMoQXJjaGl0ZWN0dXJlLlg4Nl82NCkpIHtcbiAgICAgICAgICAgIGFyY2hVcmwgPSAneDg2XzY0JztcbiAgICAgICAgICB9IGVsc2UgaWYgKGFyY2hpdGVjdHVyZS5pcyhBcmNoaXRlY3R1cmUuQVJNNjQpKSB7XG4gICAgICAgICAgICBhcmNoVXJsID0gJ2FhcmNoNjQnO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFVuc3VwcG9ydGVkIGFyY2hpdGVjdHVyZSBmb3IgYXdzY2xpOiAke2FyY2hpdGVjdHVyZS5uYW1lfWApO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHJldHVybiBbXG4gICAgICAgICAgICBgY3VybCAtZnNTTCBcImh0dHBzOi8vYXdzY2xpLmFtYXpvbmF3cy5jb20vYXdzY2xpLWV4ZS1saW51eC0ke2FyY2hVcmx9LnppcFwiIC1vIGF3c2NsaXYyLnppcGAsXG4gICAgICAgICAgICAndW56aXAgLXEgYXdzY2xpdjIuemlwJyxcbiAgICAgICAgICAgICcuL2F3cy9pbnN0YWxsJyxcbiAgICAgICAgICAgICdybSAtcmYgYXdzY2xpdjIuemlwIGF3cycsXG4gICAgICAgICAgXTtcbiAgICAgICAgfSBlbHNlIGlmIChvcy5pcyhPcy5XSU5ET1dTKSkge1xuICAgICAgICAgIHJldHVybiBbXG4gICAgICAgICAgICAnJHAgPSBTdGFydC1Qcm9jZXNzIG1zaWV4ZWMuZXhlIC1QYXNzVGhydSAtV2FpdCAtQXJndW1lbnRMaXN0IFxcJy9pIGh0dHBzOi8vYXdzY2xpLmFtYXpvbmF3cy5jb20vQVdTQ0xJVjIubXNpIC9xblxcJycsXG4gICAgICAgICAgICAnaWYgKCRwLkV4aXRDb2RlIC1uZSAwKSB7IHRocm93IFwiRXhpdCBjb2RlIGlzICRwLkV4aXRDb2RlXCIgfScsXG4gICAgICAgICAgXTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgVW5rbm93biBvcy9hcmNoaXRlY3R1cmUgY29tYm8gZm9yIGF3c2NsaTogJHtvcy5uYW1lfS8ke2FyY2hpdGVjdHVyZS5uYW1lfWApO1xuICAgICAgfVxuICAgIH0oKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBIGNvbXBvbmVudCB0byBpbnN0YWxsIHRoZSBHaXRIdWIgQ0xJLlxuICAgKi9cbiAgc3RhdGljIGdpdGh1YkNsaSgpOiBSdW5uZXJJbWFnZUNvbXBvbmVudCB7XG4gICAgcmV0dXJuIG5ldyBjbGFzcyBleHRlbmRzIFJ1bm5lckltYWdlQ29tcG9uZW50IHtcbiAgICAgIG5hbWUgPSAnR2l0aHViQ2xpJztcblxuICAgICAgZ2V0Q29tbWFuZHMob3M6IE9zLCBhcmNoaXRlY3R1cmU6IEFyY2hpdGVjdHVyZSkge1xuICAgICAgICBpZiAob3MuaXMoT3MuTElOVVhfVUJVTlRVKSkge1xuICAgICAgICAgIHJldHVybiBbXG4gICAgICAgICAgICAnY3VybCAtZnNTTCBodHRwczovL2NsaS5naXRodWIuY29tL3BhY2thZ2VzL2dpdGh1YmNsaS1hcmNoaXZlLWtleXJpbmcuZ3BnIHwgc3VkbyBkZCBvZj0vdXNyL3NoYXJlL2tleXJpbmdzL2dpdGh1YmNsaS1hcmNoaXZlLWtleXJpbmcuZ3BnJyxcbiAgICAgICAgICAgICdlY2hvIFwiZGViIFthcmNoPSQoZHBrZyAtLXByaW50LWFyY2hpdGVjdHVyZSkgc2lnbmVkLWJ5PS91c3Ivc2hhcmUva2V5cmluZ3MvZ2l0aHViY2xpLWFyY2hpdmUta2V5cmluZy5ncGddICcgK1xuICAgICAgICAgICAgJyAgaHR0cHM6Ly9jbGkuZ2l0aHViLmNvbS9wYWNrYWdlcyBzdGFibGUgbWFpblwiIHwgc3VkbyB0ZWUgL2V0Yy9hcHQvc291cmNlcy5saXN0LmQvZ2l0aHViLWNsaS5saXN0ID4gL2Rldi9udWxsJyxcbiAgICAgICAgICAgICdhcHQtZ2V0IHVwZGF0ZScsXG4gICAgICAgICAgICAnREVCSUFOX0ZST05URU5EPW5vbmludGVyYWN0aXZlIGFwdC1nZXQgaW5zdGFsbCAteSBnaCcsXG4gICAgICAgICAgXTtcbiAgICAgICAgfSBlbHNlIGlmIChvcy5pcyhPcy5MSU5VWF9BTUFaT05fMikpIHtcbiAgICAgICAgICByZXR1cm4gW1xuICAgICAgICAgICAgJ2N1cmwgLWZzU1NMIGh0dHBzOi8vY2xpLmdpdGh1Yi5jb20vcGFja2FnZXMvcnBtL2doLWNsaS5yZXBvIC1vIC9ldGMveXVtLnJlcG9zLmQvZ2gtY2xpLnJlcG8nLFxuICAgICAgICAgICAgJ3l1bSBpbnN0YWxsIC15IGdoJyxcbiAgICAgICAgICBdO1xuICAgICAgICB9IGVsc2UgaWYgKG9zLmlzKE9zLldJTkRPV1MpKSB7XG4gICAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICAgICdjbWQgL2MgY3VybCAtdyBcIiV7cmVkaXJlY3RfdXJsfVwiIC1mc1MgaHR0cHM6Ly9naXRodWIuY29tL2NsaS9jbGkvcmVsZWFzZXMvbGF0ZXN0ID4gJEVudjpURU1QXFxcXGxhdGVzdC1naCcsXG4gICAgICAgICAgICAnJExhdGVzdFVybCA9IEdldC1Db250ZW50ICRFbnY6VEVNUFxcXFxsYXRlc3QtZ2gnLFxuICAgICAgICAgICAgJyRHSF9WRVJTSU9OID0gKCRMYXRlc3RVcmwgLVNwbGl0IFxcJy9cXCcpWy0xXS5zdWJzdHJpbmcoMSknLFxuICAgICAgICAgICAgJ0ludm9rZS1XZWJSZXF1ZXN0IC1Vc2VCYXNpY1BhcnNpbmcgLVVyaSBcImh0dHBzOi8vZ2l0aHViLmNvbS9jbGkvY2xpL3JlbGVhc2VzL2Rvd25sb2FkL3Yke0dIX1ZFUlNJT059L2doXyR7R0hfVkVSU0lPTn1fd2luZG93c19hbWQ2NC5tc2lcIiAtT3V0RmlsZSBnaC5tc2knLFxuICAgICAgICAgICAgJyRwID0gU3RhcnQtUHJvY2VzcyBtc2lleGVjLmV4ZSAtUGFzc1RocnUgLVdhaXQgLUFyZ3VtZW50TGlzdCBcXCcvaSBnaC5tc2kgL3FuXFwnJyxcbiAgICAgICAgICAgICdpZiAoJHAuRXhpdENvZGUgLW5lIDApIHsgdGhyb3cgXCJFeGl0IGNvZGUgaXMgJHAuRXhpdENvZGVcIiB9JyxcbiAgICAgICAgICAgICdkZWwgZ2gubXNpJyxcbiAgICAgICAgICBdO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbmtub3duIG9zL2FyY2hpdGVjdHVyZSBjb21ibyBmb3IgZ2l0aHViIGNsaTogJHtvcy5uYW1lfS8ke2FyY2hpdGVjdHVyZS5uYW1lfWApO1xuICAgICAgfVxuICAgIH0oKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBIGNvbXBvbmVudCB0byBpbnN0YWxsIHRoZSBHaXRIdWIgQ0xJLlxuICAgKi9cbiAgc3RhdGljIGdpdCgpOiBSdW5uZXJJbWFnZUNvbXBvbmVudCB7XG4gICAgcmV0dXJuIG5ldyBjbGFzcyBleHRlbmRzIFJ1bm5lckltYWdlQ29tcG9uZW50IHtcbiAgICAgIG5hbWUgPSAnR2l0JztcblxuICAgICAgZ2V0Q29tbWFuZHMob3M6IE9zLCBhcmNoaXRlY3R1cmU6IEFyY2hpdGVjdHVyZSkge1xuICAgICAgICBpZiAob3MuaXMoT3MuTElOVVhfVUJVTlRVKSkge1xuICAgICAgICAgIHJldHVybiBbXG4gICAgICAgICAgICAnYWRkLWFwdC1yZXBvc2l0b3J5IHBwYTpnaXQtY29yZS9wcGEnLFxuICAgICAgICAgICAgJ2FwdC1nZXQgdXBkYXRlJyxcbiAgICAgICAgICAgICdERUJJQU5fRlJPTlRFTkQ9bm9uaW50ZXJhY3RpdmUgYXB0LWdldCBpbnN0YWxsIC15IGdpdCcsXG4gICAgICAgICAgXTtcbiAgICAgICAgfSBlbHNlIGlmIChvcy5pcyhPcy5MSU5VWF9BTUFaT05fMikpIHtcbiAgICAgICAgICByZXR1cm4gW1xuICAgICAgICAgICAgJ3l1bSBpbnN0YWxsIC15IGdpdCcsXG4gICAgICAgICAgXTtcbiAgICAgICAgfSBlbHNlIGlmIChvcy5pcyhPcy5XSU5ET1dTKSkge1xuICAgICAgICAgIHJldHVybiBbXG4gICAgICAgICAgICAnY21kIC9jIGN1cmwgLXcgXCIle3JlZGlyZWN0X3VybH1cIiAtZnNTIGh0dHBzOi8vZ2l0aHViLmNvbS9naXQtZm9yLXdpbmRvd3MvZ2l0L3JlbGVhc2VzL2xhdGVzdCA+ICRFbnY6VEVNUFxcXFxsYXRlc3QtZ2l0JyxcbiAgICAgICAgICAgICckTGF0ZXN0VXJsID0gR2V0LUNvbnRlbnQgJEVudjpURU1QXFxcXGxhdGVzdC1naXQnLFxuICAgICAgICAgICAgJyRHSVRfVkVSU0lPTiA9ICgkTGF0ZXN0VXJsIC1TcGxpdCBcXCcvXFwnKVstMV0uc3Vic3RyaW5nKDEpJyxcbiAgICAgICAgICAgICckR0lUX1ZFUlNJT05fU0hPUlQgPSAoJEdJVF9WRVJTSU9OIC1TcGxpdCBcXCcud2luZG93cy5cXCcpWzBdJyxcbiAgICAgICAgICAgICckR0lUX1JFVklTSU9OID0gKCRHSVRfVkVSU0lPTiAtU3BsaXQgXFwnLndpbmRvd3MuXFwnKVsxXScsXG4gICAgICAgICAgICAnSWYgKCRHSVRfUkVWSVNJT04gLWd0IDEpIHskR0lUX1ZFUlNJT05fU0hPUlQgPSBcIiRHSVRfVkVSU0lPTl9TSE9SVC4kR0lUX1JFVklTSU9OXCJ9JyxcbiAgICAgICAgICAgICdJbnZva2UtV2ViUmVxdWVzdCAtVXNlQmFzaWNQYXJzaW5nIC1VcmkgaHR0cHM6Ly9naXRodWIuY29tL2dpdC1mb3Itd2luZG93cy9naXQvcmVsZWFzZXMvZG93bmxvYWQvdiR7R0lUX1ZFUlNJT059L0dpdC0ke0dJVF9WRVJTSU9OX1NIT1JUfS02NC1iaXQuZXhlIC1PdXRGaWxlIGdpdC1zZXR1cC5leGUnLFxuICAgICAgICAgICAgJyRwID0gU3RhcnQtUHJvY2VzcyBnaXQtc2V0dXAuZXhlIC1QYXNzVGhydSAtV2FpdCAtQXJndW1lbnRMaXN0IFxcJy9WRVJZU0lMRU5UXFwnJyxcbiAgICAgICAgICAgICdpZiAoJHAuRXhpdENvZGUgLW5lIDApIHsgdGhyb3cgXCJFeGl0IGNvZGUgaXMgJHAuRXhpdENvZGVcIiB9JyxcbiAgICAgICAgICAgICdkZWwgZ2l0LXNldHVwLmV4ZScsXG4gICAgICAgICAgXTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgVW5rbm93biBvcy9hcmNoaXRlY3R1cmUgY29tYm8gZm9yIGdpdDogJHtvcy5uYW1lfS8ke2FyY2hpdGVjdHVyZS5uYW1lfWApO1xuICAgICAgfVxuICAgIH0oKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBIGNvbXBvbmVudCB0byBpbnN0YWxsIHRoZSBHaXRIdWIgQWN0aW9ucyBSdW5uZXIuIFRoaXMgaXMgdGhlIGFjdHVhbCBleGVjdXRhYmxlIHRoYXQgY29ubmVjdHMgdG8gR2l0SHViIHRvIGFzayBmb3Igam9icyBhbmQgdGhlbiBleGVjdXRlIHRoZW0uXG4gICAqXG4gICAqIEBwYXJhbSBydW5uZXJWZXJzaW9uIFRoZSB2ZXJzaW9uIG9mIHRoZSBydW5uZXIgdG8gaW5zdGFsbC4gVXN1YWxseSB5b3Ugd291bGQgc2V0IHRoaXMgdG8gbGF0ZXN0LlxuICAgKi9cbiAgc3RhdGljIGdpdGh1YlJ1bm5lcihydW5uZXJWZXJzaW9uOiBSdW5uZXJWZXJzaW9uKTogUnVubmVySW1hZ2VDb21wb25lbnQge1xuICAgIHJldHVybiBuZXcgY2xhc3MgZXh0ZW5kcyBSdW5uZXJJbWFnZUNvbXBvbmVudCB7XG4gICAgICBuYW1lID0gJ0dpdGh1YlJ1bm5lcic7XG5cbiAgICAgIGdldENvbW1hbmRzKG9zOiBPcywgYXJjaGl0ZWN0dXJlOiBBcmNoaXRlY3R1cmUpIHtcbiAgICAgICAgaWYgKG9zLmlzKE9zLkxJTlVYX1VCVU5UVSkgfHwgb3MuaXMoT3MuTElOVVhfQU1BWk9OXzIpKSB7XG4gICAgICAgICAgbGV0IHZlcnNpb25Db21tYW5kOiBzdHJpbmc7XG4gICAgICAgICAgaWYgKHJ1bm5lclZlcnNpb24uaXMoUnVubmVyVmVyc2lvbi5sYXRlc3QoKSkpIHtcbiAgICAgICAgICAgIHZlcnNpb25Db21tYW5kID0gJ1JVTk5FUl9WRVJTSU9OPWBjdXJsIC13IFwiJXtyZWRpcmVjdF91cmx9XCIgLWZzUyBodHRwczovL2dpdGh1Yi5jb20vYWN0aW9ucy9ydW5uZXIvcmVsZWFzZXMvbGF0ZXN0IHwgZ3JlcCAtb0UgXCJbXi92XSskXCJgJztcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdmVyc2lvbkNvbW1hbmQgPSBgUlVOTkVSX1ZFUlNJT049JyR7cnVubmVyVmVyc2lvbi52ZXJzaW9ufSdgO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGxldCBhcmNoVXJsO1xuICAgICAgICAgIGlmIChhcmNoaXRlY3R1cmUuaXMoQXJjaGl0ZWN0dXJlLlg4Nl82NCkpIHtcbiAgICAgICAgICAgIGFyY2hVcmwgPSAneDY0JztcbiAgICAgICAgICB9IGVsc2UgaWYgKGFyY2hpdGVjdHVyZS5pcyhBcmNoaXRlY3R1cmUuQVJNNjQpKSB7XG4gICAgICAgICAgICBhcmNoVXJsID0gJ2FybTY0JztcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbnN1cHBvcnRlZCBhcmNoaXRlY3R1cmUgZm9yIEdpdEh1YiBSdW5uZXI6ICR7YXJjaGl0ZWN0dXJlLm5hbWV9YCk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgbGV0IGNvbW1hbmRzID0gW1xuICAgICAgICAgICAgdmVyc2lvbkNvbW1hbmQsXG4gICAgICAgICAgICBgY3VybCAtZnNTTE8gXCJodHRwczovL2dpdGh1Yi5jb20vYWN0aW9ucy9ydW5uZXIvcmVsZWFzZXMvZG93bmxvYWQvdlxcJHtSVU5ORVJfVkVSU0lPTn0vYWN0aW9ucy1ydW5uZXItbGludXgtJHthcmNoVXJsfS1cXCR7UlVOTkVSX1ZFUlNJT059LnRhci5nelwiYCxcbiAgICAgICAgICAgIGB0YXIgLUMgL2hvbWUvcnVubmVyIC14emYgXCJhY3Rpb25zLXJ1bm5lci1saW51eC0ke2FyY2hVcmx9LVxcJHtSVU5ORVJfVkVSU0lPTn0udGFyLmd6XCJgLFxuICAgICAgICAgICAgYHJtIGFjdGlvbnMtcnVubmVyLWxpbnV4LSR7YXJjaFVybH0tXFwke1JVTk5FUl9WRVJTSU9OfS50YXIuZ3pgLFxuICAgICAgICAgICAgYGVjaG8gLW4gJHtydW5uZXJWZXJzaW9uLnZlcnNpb259ID4gL2hvbWUvcnVubmVyL1JVTk5FUl9WRVJTSU9OYCxcbiAgICAgICAgICBdO1xuXG4gICAgICAgICAgaWYgKG9zLmlzKE9zLkxJTlVYX1VCVU5UVSkpIHtcbiAgICAgICAgICAgIGNvbW1hbmRzLnB1c2goJy9ob21lL3J1bm5lci9iaW4vaW5zdGFsbGRlcGVuZGVuY2llcy5zaCcpO1xuICAgICAgICAgIH0gZWxzZSBpZiAob3MuaXMoT3MuTElOVVhfQU1BWk9OXzIpKSB7XG4gICAgICAgICAgICBjb21tYW5kcy5wdXNoKCd5dW0gaW5zdGFsbCAteSBvcGVuc3NsLWxpYnMga3JiNS1saWJzIHpsaWIgbGliaWN1NjAnKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICByZXR1cm4gY29tbWFuZHM7XG4gICAgICAgIH0gZWxzZSBpZiAob3MuaXMoT3MuV0lORE9XUykpIHtcbiAgICAgICAgICBsZXQgcnVubmVyQ29tbWFuZHM6IHN0cmluZ1tdO1xuICAgICAgICAgIGlmIChydW5uZXJWZXJzaW9uLmlzKFJ1bm5lclZlcnNpb24ubGF0ZXN0KCkpKSB7XG4gICAgICAgICAgICBydW5uZXJDb21tYW5kcyA9IFtcbiAgICAgICAgICAgICAgJ2NtZCAvYyBjdXJsIC13IFwiJXtyZWRpcmVjdF91cmx9XCIgLWZzUyBodHRwczovL2dpdGh1Yi5jb20vYWN0aW9ucy9ydW5uZXIvcmVsZWFzZXMvbGF0ZXN0ID4gJEVudjpURU1QXFxcXGxhdGVzdC1naGEnLFxuICAgICAgICAgICAgICAnJExhdGVzdFVybCA9IEdldC1Db250ZW50ICRFbnY6VEVNUFxcXFxsYXRlc3QtZ2hhJyxcbiAgICAgICAgICAgICAgJyRSVU5ORVJfVkVSU0lPTiA9ICgkTGF0ZXN0VXJsIC1TcGxpdCBcXCcvXFwnKVstMV0uc3Vic3RyaW5nKDEpJyxcbiAgICAgICAgICAgIF07XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJ1bm5lckNvbW1hbmRzID0gW2AkUlVOTkVSX1ZFUlNJT04gPSAnJHtydW5uZXJWZXJzaW9uLnZlcnNpb259J2BdO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHJldHVybiBydW5uZXJDb21tYW5kcy5jb25jYXQoW1xuICAgICAgICAgICAgJ0ludm9rZS1XZWJSZXF1ZXN0IC1Vc2VCYXNpY1BhcnNpbmcgLVVyaSBcImh0dHBzOi8vZ2l0aHViLmNvbS9hY3Rpb25zL3J1bm5lci9yZWxlYXNlcy9kb3dubG9hZC92JHtSVU5ORVJfVkVSU0lPTn0vYWN0aW9ucy1ydW5uZXItd2luLXg2NC0ke1JVTk5FUl9WRVJTSU9OfS56aXBcIiAtT3V0RmlsZSBhY3Rpb25zLnppcCcsXG4gICAgICAgICAgICAnRXhwYW5kLUFyY2hpdmUgYWN0aW9ucy56aXAgLURlc3RpbmF0aW9uUGF0aCBDOlxcXFxhY3Rpb25zJyxcbiAgICAgICAgICAgICdkZWwgYWN0aW9ucy56aXAnLFxuICAgICAgICAgICAgYGVjaG8gJHtydW5uZXJWZXJzaW9uLnZlcnNpb259IHwgT3V0LUZpbGUgLUVuY29kaW5nIEFTQ0lJIC1Ob05ld2xpbmUgQzpcXFxcYWN0aW9uc1xcXFxSVU5ORVJfVkVSU0lPTmAsXG4gICAgICAgICAgXSk7XG4gICAgICAgIH1cblxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFVua25vd24gb3MvYXJjaGl0ZWN0dXJlIGNvbWJvIGZvciBnaXRodWIgcnVubmVyOiAke29zLm5hbWV9LyR7YXJjaGl0ZWN0dXJlLm5hbWV9YCk7XG4gICAgICB9XG5cbiAgICAgIGdldERvY2tlckNvbW1hbmRzKF9vczogT3MsIF9hcmNoaXRlY3R1cmU6IEFyY2hpdGVjdHVyZSk6IHN0cmluZ1tdIHtcbiAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICBgRU5WIFJVTk5FUl9WRVJTSU9OPSR7cnVubmVyVmVyc2lvbi52ZXJzaW9ufWAsXG4gICAgICAgIF07XG4gICAgICB9XG4gICAgfSgpO1xuICB9XG5cbiAgLyoqXG4gICAqIEEgY29tcG9uZW50IHRvIGluc3RhbGwgRG9ja2VyLlxuICAgKlxuICAgKiBPbiBXaW5kb3dzIHRoaXMgc2V0cyB1cCBkb2NrZXJkIGZvciBXaW5kb3dzIGNvbnRhaW5lcnMgd2l0aG91dCBEb2NrZXIgRGVza3RvcC4gSWYgeW91IG5lZWQgTGludXggY29udGFpbmVycyBvbiBXaW5kb3dzLCB5b3UnbGwgbmVlZCB0byBpbnN0YWxsIERvY2tlciBEZXNrdG9wIHdoaWNoIGRvZXNuJ3Qgc2VlbSB0byBwbGF5IHdlbGwgd2l0aCBzZXJ2ZXJzIChQUnMgd2VsY29tZSkuXG4gICAqL1xuICBzdGF0aWMgZG9ja2VyKCk6IFJ1bm5lckltYWdlQ29tcG9uZW50IHtcbiAgICByZXR1cm4gbmV3IGNsYXNzIGV4dGVuZHMgUnVubmVySW1hZ2VDb21wb25lbnQge1xuICAgICAgbmFtZSA9ICdEb2NrZXInO1xuXG4gICAgICBnZXRDb21tYW5kcyhvczogT3MsIGFyY2hpdGVjdHVyZTogQXJjaGl0ZWN0dXJlKSB7XG4gICAgICAgIGlmIChvcy5pcyhPcy5MSU5VWF9VQlVOVFUpKSB7XG4gICAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICAgICdjdXJsIC1mc1NMIGh0dHBzOi8vZG93bmxvYWQuZG9ja2VyLmNvbS9saW51eC91YnVudHUvZ3BnIHwgc3VkbyBncGcgLS1kZWFybW9yIC1vIC91c3Ivc2hhcmUva2V5cmluZ3MvZG9ja2VyLmdwZycsXG4gICAgICAgICAgICAnZWNobyAnICtcbiAgICAgICAgICAgICAgICAnICBcImRlYiBbYXJjaD0kKGRwa2cgLS1wcmludC1hcmNoaXRlY3R1cmUpIHNpZ25lZC1ieT0vdXNyL3NoYXJlL2tleXJpbmdzL2RvY2tlci5ncGddIGh0dHBzOi8vZG93bmxvYWQuZG9ja2VyLmNvbS9saW51eC91YnVudHUgJyArXG4gICAgICAgICAgICAgICAgJyAgJChsc2JfcmVsZWFzZSAtY3MpIHN0YWJsZVwiIHwgc3VkbyB0ZWUgL2V0Yy9hcHQvc291cmNlcy5saXN0LmQvZG9ja2VyLmxpc3QgPiAvZGV2L251bGwnLFxuICAgICAgICAgICAgJ2FwdC1nZXQgdXBkYXRlJyxcbiAgICAgICAgICAgICdERUJJQU5fRlJPTlRFTkQ9bm9uaW50ZXJhY3RpdmUgYXB0LWdldCBpbnN0YWxsIC15IGRvY2tlci1jZSBkb2NrZXItY2UtY2xpIGNvbnRhaW5lcmQuaW8gZG9ja2VyLWNvbXBvc2UtcGx1Z2luJyxcbiAgICAgICAgICAgICd1c2VybW9kIC1hRyBkb2NrZXIgcnVubmVyJyxcbiAgICAgICAgICAgICdsbiAtcyAvdXNyL2xpYmV4ZWMvZG9ja2VyL2NsaS1wbHVnaW5zL2RvY2tlci1jb21wb3NlIC91c3IvYmluL2RvY2tlci1jb21wb3NlJyxcbiAgICAgICAgICBdO1xuICAgICAgICB9IGVsc2UgaWYgKG9zLmlzKE9zLkxJTlVYX0FNQVpPTl8yKSkge1xuICAgICAgICAgIHJldHVybiBbXG4gICAgICAgICAgICAneXVtIGluc3RhbGwgLXkgZG9ja2VyJyxcbiAgICAgICAgICBdO1xuICAgICAgICB9IGVsc2UgaWYgKG9zLmlzKE9zLldJTkRPV1MpKSB7XG4gICAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICAgIC8vIGZpZ3VyZSBvdXQgbGF0ZXN0IGRvY2tlciB2ZXJzaW9uXG4gICAgICAgICAgICAnY21kIC9jIGN1cmwgLXcgXCIle3JlZGlyZWN0X3VybH1cIiAtZnNTIGh0dHBzOi8vZ2l0aHViLmNvbS9tb2J5L21vYnkvcmVsZWFzZXMvbGF0ZXN0ID4gJEVudjpURU1QXFxcXGxhdGVzdC1kb2NrZXInLFxuICAgICAgICAgICAgJyRMYXRlc3RVcmwgPSBHZXQtQ29udGVudCAkRW52OlRFTVBcXFxcbGF0ZXN0LWRvY2tlcicsXG4gICAgICAgICAgICAnJERPQ0tFUl9WRVJTSU9OID0gKCRMYXRlc3RVcmwgLVNwbGl0IFxcJy9cXCcpWy0xXS5zdWJzdHJpbmcoMSknLFxuICAgICAgICAgICAgLy8gZG93bmxvYWQgc3RhdGljIGJpbmFyaWVzXG4gICAgICAgICAgICAnSW52b2tlLVdlYlJlcXVlc3QgLVVzZUJhc2ljUGFyc2luZyAtVXJpIFwiaHR0cHM6Ly9kb3dubG9hZC5kb2NrZXIuY29tL3dpbi9zdGF0aWMvc3RhYmxlL3g4Nl82NC9kb2NrZXItJHtET0NLRVJfVkVSU0lPTn0uemlwXCIgLU91dEZpbGUgZG9ja2VyLnppcCcsXG4gICAgICAgICAgICAvLyBleHRyYWN0IHRvIEM6XFxQcm9ncmFtIEZpbGVzXFxEb2NrZXJcbiAgICAgICAgICAgICdFeHBhbmQtQXJjaGl2ZSBkb2NrZXIuemlwIC1EZXN0aW5hdGlvblBhdGggXCIkRW52OlByb2dyYW1GaWxlc1wiJyxcbiAgICAgICAgICAgICdkZWwgZG9ja2VyLnppcCcsXG4gICAgICAgICAgICAvLyBhZGQgdG8gcGF0aFxuICAgICAgICAgICAgJyRwZXJzaXN0ZWRQYXRocyA9IFtFbnZpcm9ubWVudF06OkdldEVudmlyb25tZW50VmFyaWFibGUoXFwnUGF0aFxcJywgW0Vudmlyb25tZW50VmFyaWFibGVUYXJnZXRdOjpNYWNoaW5lKScsXG4gICAgICAgICAgICAnW0Vudmlyb25tZW50XTo6U2V0RW52aXJvbm1lbnRWYXJpYWJsZShcIlBBVEhcIiwgJHBlcnNpc3RlZFBhdGhzICsgXCI7JEVudjpQcm9ncmFtRmlsZXNcXFxcRG9ja2VyXCIsIFtFbnZpcm9ubWVudFZhcmlhYmxlVGFyZ2V0XTo6TWFjaGluZSknLFxuICAgICAgICAgICAgJyRlbnY6UEFUSCA9ICRlbnY6UEFUSCArIFwiOyRFbnY6UHJvZ3JhbUZpbGVzXFxcXERvY2tlclwiJyxcbiAgICAgICAgICAgIC8vIHJlZ2lzdGVyIGRvY2tlciBzZXJ2aWNlXG4gICAgICAgICAgICAnZG9ja2VyZCAtLXJlZ2lzdGVyLXNlcnZpY2UnLFxuICAgICAgICAgICAgJ2lmICgkTEFTVEVYSVRDT0RFIC1uZSAwKSB7IHRocm93IFwiRXhpdCBjb2RlIGlzICRMQVNURVhJVENPREVcIiB9JyxcbiAgICAgICAgICAgIC8vIGVuYWJsZSBjb250YWluZXJzIGZlYXR1cmVcbiAgICAgICAgICAgICdFbmFibGUtV2luZG93c09wdGlvbmFsRmVhdHVyZSAtT25saW5lIC1GZWF0dXJlTmFtZSBjb250YWluZXJzIC1BbGwgLU5vUmVzdGFydCcsXG4gICAgICAgICAgICAvLyBpbnN0YWxsIGRvY2tlci1jb21wb3NlXG4gICAgICAgICAgICAnY21kIC9jIGN1cmwgLXcgXCIle3JlZGlyZWN0X3VybH1cIiAtZnNTIGh0dHBzOi8vZ2l0aHViLmNvbS9kb2NrZXIvY29tcG9zZS9yZWxlYXNlcy9sYXRlc3QgPiAkRW52OlRFTVBcXFxcbGF0ZXN0LWRvY2tlci1jb21wb3NlJyxcbiAgICAgICAgICAgICckTGF0ZXN0VXJsID0gR2V0LUNvbnRlbnQgJEVudjpURU1QXFxcXGxhdGVzdC1kb2NrZXItY29tcG9zZScsXG4gICAgICAgICAgICAnJExhdGVzdERvY2tlckNvbXBvc2UgPSAoJExhdGVzdFVybCAtU3BsaXQgXFwnL1xcJylbLTFdJyxcbiAgICAgICAgICAgICdJbnZva2UtV2ViUmVxdWVzdCAtVXNlQmFzaWNQYXJzaW5nIC1VcmkgIFwiaHR0cHM6Ly9naXRodWIuY29tL2RvY2tlci9jb21wb3NlL3JlbGVhc2VzL2Rvd25sb2FkLyR7TGF0ZXN0RG9ja2VyQ29tcG9zZX0vZG9ja2VyLWNvbXBvc2UtV2luZG93cy14ODZfNjQuZXhlXCIgLU91dEZpbGUgJEVudjpQcm9ncmFtRmlsZXNcXFxcRG9ja2VyXFxcXGRvY2tlci1jb21wb3NlLmV4ZScsXG4gICAgICAgICAgICAnTmV3LUl0ZW0gLUl0ZW1UeXBlIGRpcmVjdG9yeSAtUGF0aCBcIiRFbnY6UHJvZ3JhbUZpbGVzXFxcXERvY2tlclxcXFxjbGktcGx1Z2luc1wiJyxcbiAgICAgICAgICAgICdDb3B5LUl0ZW0gLVBhdGggXCIkRW52OlByb2dyYW1GaWxlc1xcXFxEb2NrZXJcXFxcZG9ja2VyLWNvbXBvc2UuZXhlXCIgLURlc3RpbmF0aW9uIFwiJEVudjpQcm9ncmFtRmlsZXNcXFxcRG9ja2VyXFxcXGNsaS1wbHVnaW5zXFxcXGRvY2tlci1jb21wb3NlLmV4ZVwiJyxcbiAgICAgICAgICBdO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbmtub3duIG9zL2FyY2hpdGVjdHVyZSBjb21ibyBmb3IgZG9ja2VyOiAke29zLm5hbWV9LyR7YXJjaGl0ZWN0dXJlLm5hbWV9YCk7XG4gICAgICB9XG5cbiAgICAgIHNob3VsZFJlYm9vdChvczogT3MsIF9hcmNoaXRlY3R1cmU6IEFyY2hpdGVjdHVyZSk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gb3MuaXMoT3MuV0lORE9XUyk7XG4gICAgICB9XG4gICAgfSgpO1xuICB9XG5cbiAgLyoqXG4gICAqIEEgY29tcG9uZW50IHRvIGluc3RhbGwgRG9ja2VyLWluLURvY2tlci5cbiAgICovXG4gIHN0YXRpYyBkb2NrZXJJbkRvY2tlcigpOiBSdW5uZXJJbWFnZUNvbXBvbmVudCB7XG4gICAgcmV0dXJuIG5ldyBjbGFzcyBleHRlbmRzIFJ1bm5lckltYWdlQ29tcG9uZW50IHtcbiAgICAgIG5hbWUgPSAnRG9ja2VyLWluLURvY2tlcic7XG5cbiAgICAgIGdldENvbW1hbmRzKG9zOiBPcywgYXJjaGl0ZWN0dXJlOiBBcmNoaXRlY3R1cmUpIHtcbiAgICAgICAgaWYgKG9zLmlzKE9zLkxJTlVYX1VCVU5UVSkgfHwgb3MuaXMoT3MuTElOVVhfQU1BWk9OXzIpKSB7XG4gICAgICAgICAgbGV0IGFyY2hVcmw6IHN0cmluZztcbiAgICAgICAgICBpZiAoYXJjaGl0ZWN0dXJlLmlzKEFyY2hpdGVjdHVyZS5YODZfNjQpKSB7XG4gICAgICAgICAgICBhcmNoVXJsID0gJ3g4Nl82NCc7XG4gICAgICAgICAgfSBlbHNlIGlmIChhcmNoaXRlY3R1cmUuaXMoQXJjaGl0ZWN0dXJlLkFSTTY0KSkge1xuICAgICAgICAgICAgYXJjaFVybCA9ICdhYXJjaDY0JztcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbnN1cHBvcnRlZCBhcmNoaXRlY3R1cmUgZm9yIERvY2tlci1pbi1Eb2NrZXI6ICR7YXJjaGl0ZWN0dXJlLm5hbWV9YCk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICAgIG9zLmlzKE9zLkxJTlVYX1VCVU5UVSkgPyAnREVCSUFOX0ZST05URU5EPW5vbmludGVyYWN0aXZlIGFwdC1nZXQgaW5zdGFsbCAteSBzb2NhdCcgOiAneXVtIGluc3RhbGwgLXkgc29jYXQnLCAvLyBmb3IgRUNTXG4gICAgICAgICAgICAnRE9DS0VSX0NIQU5ORUw9XCJzdGFibGVcIicsXG4gICAgICAgICAgICAnRElORF9DT01NSVQ9XCI0MmIxMTc1ZWRhMDcxYzBlOTEyMWUxZDY0MzQ1OTI4Mzg0YTkzZGYxXCInLFxuICAgICAgICAgICAgJ0RPQ0tFUl9WRVJTSU9OPVwiMjAuMTAuMThcIicsXG4gICAgICAgICAgICAnRE9DS0VSX0NPTVBPU0VfVkVSU0lPTj1cIjIuMTEuMFwiJyxcbiAgICAgICAgICAgIGBjdXJsIC1mc1NMIFwiaHR0cHM6Ly9kb3dubG9hZC5kb2NrZXIuY29tL2xpbnV4L3N0YXRpYy9cXCR7RE9DS0VSX0NIQU5ORUx9LyR7YXJjaFVybH0vZG9ja2VyLVxcJHtET0NLRVJfVkVSU0lPTn0udGd6XCIgLW8gZG9ja2VyLnRnemAsXG4gICAgICAgICAgICAndGFyIC0tc3RyaXAtY29tcG9uZW50cyAxIC1DIC91c3IvbG9jYWwvYmluLyAteHpmIGRvY2tlci50Z3onLFxuICAgICAgICAgICAgJ3JtIGRvY2tlci50Z3onLFxuICAgICAgICAgICAgJyMgc2V0IHVwIHN1YnVpZC9zdWJnaWQgc28gdGhhdCBcIi0tdXNlcm5zLXJlbWFwPWRlZmF1bHRcIiB3b3JrcyBvdXQtb2YtdGhlIGJveCcsXG4gICAgICAgICAgICAnYWRkZ3JvdXAgZG9ja3JlbWFwJyxcbiAgICAgICAgICAgICd1c2VyYWRkIC1nIGRvY2tyZW1hcCBkb2NrcmVtYXAnLFxuICAgICAgICAgICAgJ2VjaG8gXFwnZG9ja3JlbWFwOjE2NTUzNjo2NTUzNlxcJyA+PiAvZXRjL3N1YnVpZCcsXG4gICAgICAgICAgICAnZWNobyBcXCdkb2NrcmVtYXA6MTY1NTM2OjY1NTM2XFwnID4+IC9ldGMvc3ViZ2lkJyxcbiAgICAgICAgICAgICdjdXJsIC1mc1NMIFwiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2RvY2tlci9kb2NrZXIvJHtESU5EX0NPTU1JVH0vaGFjay9kaW5kXCIgLW8gL3Vzci9sb2NhbC9iaW4vZGluZCcsXG4gICAgICAgICAgICBgY3VybCAtZnNTTCBodHRwczovL2dpdGh1Yi5jb20vZG9ja2VyL2NvbXBvc2UvcmVsZWFzZXMvZG93bmxvYWQvdlxcJHtET0NLRVJfQ09NUE9TRV9WRVJTSU9OfS9kb2NrZXItY29tcG9zZS1saW51eC0ke2FyY2hVcmx9IC1vIC91c3IvbG9jYWwvYmluL2RvY2tlci1jb21wb3NlYCxcbiAgICAgICAgICAgICdta2RpciAtcCAvaG9tZS9ydW5uZXIvLmRvY2tlci9jbGktcGx1Z2lucyAmJiBsbiAtcyAvdXNyL2xvY2FsL2Jpbi9kb2NrZXItY29tcG9zZSAvaG9tZS9ydW5uZXIvLmRvY2tlci9jbGktcGx1Z2lucy9kb2NrZXItY29tcG9zZScsXG4gICAgICAgICAgICAnY2hvd24gLVIgcnVubmVyIC9ob21lL3J1bm5lci8uZG9ja2VyJyxcbiAgICAgICAgICAgICdjaG1vZCAreCAvdXNyL2xvY2FsL2Jpbi9kaW5kIC91c3IvbG9jYWwvYmluL2RvY2tlci1jb21wb3NlJyxcbiAgICAgICAgICAgICdhZGRncm91cCBkb2NrZXIgJiYgdXNlcm1vZCAtYUcgZG9ja2VyIHJ1bm5lcicsXG4gICAgICAgICAgXTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgVW5rbm93biBvcy9hcmNoaXRlY3R1cmUgY29tYm8gZm9yIERvY2tlci1pbi1Eb2NrZXI6ICR7b3MubmFtZX0vJHthcmNoaXRlY3R1cmUubmFtZX1gKTtcbiAgICAgIH1cbiAgICB9KCk7XG4gIH1cblxuICAvKipcbiAgICogQSBjb21wb25lbnQgdG8gYWRkIGEgdHJ1c3RlZCBjZXJ0aWZpY2F0ZSBhdXRob3JpdHkuIFRoaXMgY2FuIGJlIHVzZWQgdG8gc3VwcG9ydCBHaXRIdWIgRW50ZXJwcmlzZSBTZXJ2ZXIgd2l0aCBzZWxmLXNpZ25lZCBjZXJ0aWZpY2F0ZS5cbiAgICpcbiAgICogQHBhcmFtIHNvdXJjZSBwYXRoIHRvIGNlcnRpZmljYXRlIGZpbGUgaW4gUEVNIGZvcm1hdFxuICAgKiBAcGFyYW0gbmFtZSB1bmlxdWUgY2VydGlmaWNhdGUgbmFtZSB0byBiZSB1c2VkIG9uIHJ1bm5lciBmaWxlIHN5c3RlbVxuICAgKi9cbiAgc3RhdGljIGV4dHJhQ2VydGlmaWNhdGVzKHNvdXJjZTogc3RyaW5nLCBuYW1lOiBzdHJpbmcpOiBSdW5uZXJJbWFnZUNvbXBvbmVudCB7XG4gICAgcmV0dXJuIG5ldyBjbGFzcyBleHRlbmRzIFJ1bm5lckltYWdlQ29tcG9uZW50IHtcbiAgICAgIG5hbWUgPSBgRXh0cmEtQ2VydGlmaWNhdGVzLSR7bmFtZX1gO1xuXG4gICAgICBnZXRDb21tYW5kcyhvczogT3MsIGFyY2hpdGVjdHVyZTogQXJjaGl0ZWN0dXJlKSB7XG4gICAgICAgIGlmICghbmFtZS5tYXRjaCgvXlthLXpBLVowLTlfLV0rJC8pKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIGNlcnRpZmljYXRlIG5hbWU6ICR7bmFtZX0uIE5hbWUgbXVzdCBvbmx5IGNvbnRhaW4gYWxwaGFudW1lcmljIGNoYXJhY3RlcnMsIGRhc2hlcyBhbmQgdW5kZXJzY29yZXMuYCk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAob3MuaXMoT3MuTElOVVhfVUJVTlRVKSkge1xuICAgICAgICAgIHJldHVybiBbXG4gICAgICAgICAgICAndXBkYXRlLWNhLWNlcnRpZmljYXRlcycsXG4gICAgICAgICAgXTtcbiAgICAgICAgfSBlbHNlIGlmIChvcy5pcyhPcy5MSU5VWF9BTUFaT05fMikpIHtcbiAgICAgICAgICByZXR1cm4gW1xuICAgICAgICAgICAgJ3VwZGF0ZS1jYS10cnVzdCcsXG4gICAgICAgICAgXTtcbiAgICAgICAgfSBlbHNlIGlmIChvcy5pcyhPcy5XSU5ET1dTKSkge1xuICAgICAgICAgIHJldHVybiBbXG4gICAgICAgICAgICBgSW1wb3J0LUNlcnRpZmljYXRlIC1GaWxlUGF0aCBDOlxcXFwke25hbWV9LmNydCAtQ2VydFN0b3JlTG9jYXRpb24gQ2VydDpcXFxcTG9jYWxNYWNoaW5lXFxcXFJvb3RgLFxuICAgICAgICAgICAgYFJlbW92ZS1JdGVtIEM6XFxcXCR7bmFtZX0uY3J0YCxcbiAgICAgICAgICBdO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbmtub3duIG9zL2FyY2hpdGVjdHVyZSBjb21ibyBmb3IgZXh0cmEgY2VydGlmaWNhdGVzOiAke29zLm5hbWV9LyR7YXJjaGl0ZWN0dXJlLm5hbWV9YCk7XG4gICAgICB9XG5cbiAgICAgIGdldEFzc2V0cyhvczogT3MsIF9hcmNoaXRlY3R1cmU6IEFyY2hpdGVjdHVyZSk6IFJ1bm5lckltYWdlQXNzZXRbXSB7XG4gICAgICAgIGlmIChvcy5pcyhPcy5MSU5VWF9VQlVOVFUpKSB7XG4gICAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICAgIHsgc291cmNlLCB0YXJnZXQ6IGAvdXNyL2xvY2FsL3NoYXJlL2NhLWNlcnRpZmljYXRlcy8ke25hbWV9LmNydGAgfSxcbiAgICAgICAgICBdO1xuICAgICAgICB9IGVsc2UgaWYgKG9zLmlzKE9zLkxJTlVYX0FNQVpPTl8yKSkge1xuICAgICAgICAgIHJldHVybiBbXG4gICAgICAgICAgICB7IHNvdXJjZSwgdGFyZ2V0OiBgL2V0Yy9wa2kvY2EtdHJ1c3Qvc291cmNlL2FuY2hvcnMvJHtuYW1lfS5jcnRgIH0sXG4gICAgICAgICAgXTtcbiAgICAgICAgfSBlbHNlIGlmIChvcy5pcyhPcy5XSU5ET1dTKSkge1xuICAgICAgICAgIHJldHVybiBbXG4gICAgICAgICAgICB7IHNvdXJjZSwgdGFyZ2V0OiBgQzpcXFxcJHtuYW1lfS5jcnRgIH0sXG4gICAgICAgICAgXTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgVW5zdXBwb3J0ZWQgT1MgZm9yIGV4dHJhIGNlcnRpZmljYXRlczogJHtvcy5uYW1lfWApO1xuICAgICAgfVxuICAgIH0oKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBIGNvbXBvbmVudCB0byBzZXQgdXAgdGhlIHJlcXVpcmVkIExhbWJkYSBlbnRyeXBvaW50IGZvciBMYW1iZGEgcnVubmVycy5cbiAgICovXG4gIHN0YXRpYyBsYW1iZGFFbnRyeXBvaW50KCk6IFJ1bm5lckltYWdlQ29tcG9uZW50IHtcbiAgICByZXR1cm4gbmV3IGNsYXNzIGV4dGVuZHMgUnVubmVySW1hZ2VDb21wb25lbnQge1xuICAgICAgbmFtZSA9ICdMYW1iZGEtRW50cnlwb2ludCc7XG5cbiAgICAgIGdldENvbW1hbmRzKG9zOiBPcywgX2FyY2hpdGVjdHVyZTogQXJjaGl0ZWN0dXJlKSB7XG4gICAgICAgIGlmICghb3MuaXMoT3MuTElOVVhfQU1BWk9OXzIpICYmICFvcy5pcyhPcy5MSU5VWF9VQlVOVFUpKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbnN1cHBvcnRlZCBPUyBmb3IgTGFtYmRhIGVudHJ5cG9pbnQ6ICR7b3MubmFtZX1gKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBbXTtcbiAgICAgIH1cblxuICAgICAgZ2V0QXNzZXRzKF9vczogT3MsIF9hcmNoaXRlY3R1cmU6IEFyY2hpdGVjdHVyZSk6IFJ1bm5lckltYWdlQXNzZXRbXSB7XG4gICAgICAgIHJldHVybiBbXG4gICAgICAgICAge1xuICAgICAgICAgICAgc291cmNlOiBwYXRoLmpvaW4oX19kaXJuYW1lLCAnLi4nLCAncHJvdmlkZXJzJywgJ2RvY2tlci1pbWFnZXMnLCAnbGFtYmRhJywgJ2xpbnV4LXg2NCcsICdydW5uZXIuanMnKSxcbiAgICAgICAgICAgIHRhcmdldDogJyR7TEFNQkRBX1RBU0tfUk9PVH0vcnVubmVyLmpzJyxcbiAgICAgICAgICB9LFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIHNvdXJjZTogcGF0aC5qb2luKF9fZGlybmFtZSwgJy4uJywgJ3Byb3ZpZGVycycsICdkb2NrZXItaW1hZ2VzJywgJ2xhbWJkYScsICdsaW51eC14NjQnLCAncnVubmVyLnNoJyksXG4gICAgICAgICAgICB0YXJnZXQ6ICcke0xBTUJEQV9UQVNLX1JPT1R9L3J1bm5lci5zaCcsXG4gICAgICAgICAgfSxcbiAgICAgICAgXTtcbiAgICAgIH1cblxuICAgICAgZ2V0RG9ja2VyQ29tbWFuZHMoX29zOiBPcywgX2FyY2hpdGVjdHVyZTogQXJjaGl0ZWN0dXJlKTogc3RyaW5nW10ge1xuICAgICAgICByZXR1cm4gW1xuICAgICAgICAgICdXT1JLRElSICR7TEFNQkRBX1RBU0tfUk9PVH0nLFxuICAgICAgICAgICdDTUQgW1wicnVubmVyLmhhbmRsZXJcIl0nLFxuICAgICAgICBdO1xuICAgICAgfVxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogQ29tcG9uZW50IG5hbWUuXG4gICAqXG4gICAqIFVzZWQgdG8gaWRlbnRpZnkgY29tcG9uZW50IGluIGltYWdlIGJ1aWxkIGxvZ3MsIGFuZCBmb3Ige0BsaW5rIFJ1bm5lckltYWdlQnVpbGRlci5yZW1vdmVDb21wb25lbnR9XG4gICAqL1xuICBhYnN0cmFjdCByZWFkb25seSBuYW1lOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFJldHVybnMgY29tbWFuZHMgdG8gcnVuIHRvIGluIGJ1aWx0IGltYWdlLiBDYW4gYmUgdXNlZCB0byBpbnN0YWxsIHBhY2thZ2VzLCBzZXR1cCBidWlsZCBwcmVyZXF1aXNpdGVzLCBldGMuXG4gICAqL1xuICBhYnN0cmFjdCBnZXRDb21tYW5kcyhfb3M6IE9zLCBfYXJjaGl0ZWN0dXJlOiBBcmNoaXRlY3R1cmUpOiBzdHJpbmdbXTtcblxuICAvKipcbiAgICogUmV0dXJucyBhc3NldHMgdG8gY29weSBpbnRvIHRoZSBidWlsdCBpbWFnZS4gQ2FuIGJlIHVzZWQgdG8gY29weSBmaWxlcyBpbnRvIHRoZSBpbWFnZS5cbiAgICovXG4gIGdldEFzc2V0cyhfb3M6IE9zLCBfYXJjaGl0ZWN0dXJlOiBBcmNoaXRlY3R1cmUpOiBSdW5uZXJJbWFnZUFzc2V0W10ge1xuICAgIHJldHVybiBbXTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIERvY2tlciBjb21tYW5kcyB0byBydW4gdG8gaW4gYnVpbHQgaW1hZ2UuIENhbiBiZSB1c2VkIHRvIGFkZCBjb21tYW5kcyBsaWtlIGBWT0xVTUVgLCBgRU5UUllQT0lOVGAsIGBDTURgLCBldGMuXG4gICAqXG4gICAqIERvY2tlciBjb21tYW5kcyBhcmUgYWRkZWQgYWZ0ZXIgYXNzZXRzIGFuZCBub3JtYWwgY29tbWFuZHMuXG4gICAqL1xuICBnZXREb2NrZXJDb21tYW5kcyhfb3M6IE9zLCBfYXJjaGl0ZWN0dXJlOiBBcmNoaXRlY3R1cmUpOiBzdHJpbmdbXSB7XG4gICAgcmV0dXJuIFtdO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdHJ1ZSBpZiB0aGUgaW1hZ2UgYnVpbGRlciBzaG91bGQgYmUgcmVib290ZWQgYWZ0ZXIgdGhpcyBjb21wb25lbnQgaXMgaW5zdGFsbGVkLlxuICAgKi9cbiAgc2hvdWxkUmVib290KF9vczogT3MsIF9hcmNoaXRlY3R1cmU6IEFyY2hpdGVjdHVyZSk6IGJvb2xlYW4ge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDb252ZXJ0IGNvbXBvbmVudCB0byBhbiBBV1MgSW1hZ2UgQnVpbGRlciBjb21wb25lbnQuXG4gICAqXG4gICAqIEBpbnRlcm5hbFxuICAgKi9cbiAgX2FzQXdzSW1hZ2VCdWlsZGVyQ29tcG9uZW50KHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIG9zOiBPcywgYXJjaGl0ZWN0dXJlOiBBcmNoaXRlY3R1cmUpIHtcbiAgICBsZXQgcGxhdGZvcm06ICdMaW51eCcgfCAnV2luZG93cyc7XG4gICAgaWYgKG9zLmlzKE9zLkxJTlVYX1VCVU5UVSkgfHwgb3MuaXMoT3MuTElOVVhfQU1BWk9OXzIpKSB7XG4gICAgICBwbGF0Zm9ybSA9ICdMaW51eCc7XG4gICAgfSBlbHNlIGlmIChvcy5pcyhPcy5XSU5ET1dTKSkge1xuICAgICAgcGxhdGZvcm0gPSAnV2luZG93cyc7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgVW5rbm93biBvcy9hcmNoaXRlY3R1cmUgY29tYm8gZm9yIGltYWdlIGJ1aWxkZXIgY29tcG9uZW50OiAke29zLm5hbWV9LyR7YXJjaGl0ZWN0dXJlLm5hbWV9YCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIG5ldyBJbWFnZUJ1aWxkZXJDb21wb25lbnQoc2NvcGUsIGlkLCB7XG4gICAgICBwbGF0Zm9ybTogcGxhdGZvcm0sXG4gICAgICBjb21tYW5kczogdGhpcy5nZXRDb21tYW5kcyhvcywgYXJjaGl0ZWN0dXJlKSxcbiAgICAgIGFzc2V0czogdGhpcy5nZXRBc3NldHMob3MsIGFyY2hpdGVjdHVyZSkubWFwKChhc3NldCwgaW5kZXgpID0+IHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBhc3NldDogbmV3IHMzX2Fzc2V0cy5Bc3NldChzY29wZSwgYCR7aWR9IGFzc2V0ICR7aW5kZXh9YCwgeyBwYXRoOiBhc3NldC5zb3VyY2UgfSksXG4gICAgICAgICAgcGF0aDogYXNzZXQudGFyZ2V0LFxuICAgICAgICB9O1xuICAgICAgfSksXG4gICAgICBkaXNwbGF5TmFtZTogaWQsXG4gICAgICBkZXNjcmlwdGlvbjogaWQsXG4gICAgICByZWJvb3Q6IHRoaXMuc2hvdWxkUmVib290KG9zLCBhcmNoaXRlY3R1cmUpLFxuICAgIH0pO1xuICB9XG59XG5cbiJdfQ==
|