appium-adb 9.10.2 → 9.10.3
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/README.md +1 -1
- package/lib/helpers.js +26 -3
- package/lib/tools/apk-signing.js +3 -4
- package/package.json +39 -26
- package/build/index.js +0 -30
- package/build/lib/adb.js +0 -132
- package/build/lib/helpers.js +0 -957
- package/build/lib/logcat.js +0 -221
- package/build/lib/logger.js +0 -18
- package/build/lib/tools/aab-utils.js +0 -157
- package/build/lib/tools/adb-commands.js +0 -1150
- package/build/lib/tools/adb-emu-commands.js +0 -397
- package/build/lib/tools/android-manifest.js +0 -231
- package/build/lib/tools/apk-signing.js +0 -333
- package/build/lib/tools/apk-utils.js +0 -992
- package/build/lib/tools/apks-utils.js +0 -219
- package/build/lib/tools/index.js +0 -49
- package/build/lib/tools/keyboard-commands.js +0 -71
- package/build/lib/tools/lockmgmt.js +0 -224
- package/build/lib/tools/settings-client-commands.js +0 -362
- package/build/lib/tools/system-calls.js +0 -1064
|
@@ -1,333 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
-
|
|
5
|
-
Object.defineProperty(exports, "__esModule", {
|
|
6
|
-
value: true
|
|
7
|
-
});
|
|
8
|
-
exports.default = void 0;
|
|
9
|
-
|
|
10
|
-
require("source-map-support/register");
|
|
11
|
-
|
|
12
|
-
var _lodash = _interopRequireDefault(require("lodash"));
|
|
13
|
-
|
|
14
|
-
var _fs2 = _interopRequireDefault(require("fs"));
|
|
15
|
-
|
|
16
|
-
var _teen_process = require("teen_process");
|
|
17
|
-
|
|
18
|
-
var _path = _interopRequireDefault(require("path"));
|
|
19
|
-
|
|
20
|
-
var _logger = _interopRequireDefault(require("../logger.js"));
|
|
21
|
-
|
|
22
|
-
var _support = require("@appium/support");
|
|
23
|
-
|
|
24
|
-
var _lruCache = _interopRequireDefault(require("lru-cache"));
|
|
25
|
-
|
|
26
|
-
var _helpers = require("../helpers.js");
|
|
27
|
-
|
|
28
|
-
const DEFAULT_PRIVATE_KEY = _path.default.resolve(_helpers.rootDir, 'keys', 'testkey.pk8');
|
|
29
|
-
|
|
30
|
-
const DEFAULT_CERTIFICATE = _path.default.resolve(_helpers.rootDir, 'keys', 'testkey.x509.pem');
|
|
31
|
-
|
|
32
|
-
const BUNDLETOOL_TUTORIAL = 'https://developer.android.com/studio/command-line/bundletool';
|
|
33
|
-
const APKSIGNER_VERIFY_FAIL = 'DOES NOT VERIFY';
|
|
34
|
-
const SHA1 = 'sha1';
|
|
35
|
-
const SHA256 = 'sha256';
|
|
36
|
-
const SHA512 = 'sha512';
|
|
37
|
-
const MD5 = 'md5';
|
|
38
|
-
const DEFAULT_CERT_HASH = {
|
|
39
|
-
[SHA256]: 'a40da80a59d170caa950cf15c18c454d47a39b26989d8b640ecd745ba71bf5dc'
|
|
40
|
-
};
|
|
41
|
-
const JAVA_PROPS_INIT_ERROR = 'java.lang.Error: Properties init';
|
|
42
|
-
const SIGNED_APPS_CACHE = new _lruCache.default({
|
|
43
|
-
max: 30
|
|
44
|
-
});
|
|
45
|
-
const apkSigningMethods = {};
|
|
46
|
-
|
|
47
|
-
apkSigningMethods.executeApksigner = async function executeApksigner(args = []) {
|
|
48
|
-
const apkSignerJar = await (0, _helpers.getApksignerForOs)(this);
|
|
49
|
-
const fullCmd = [await (0, _helpers.getJavaForOs)(), '-Xmx1024M', '-Xss1m', '-jar', apkSignerJar, ...args];
|
|
50
|
-
|
|
51
|
-
_logger.default.debug(`Starting apksigner: ${_support.util.quote(fullCmd)}`);
|
|
52
|
-
|
|
53
|
-
const {
|
|
54
|
-
stdout,
|
|
55
|
-
stderr
|
|
56
|
-
} = await (0, _teen_process.exec)(fullCmd[0], fullCmd.slice(1), {
|
|
57
|
-
cwd: _path.default.dirname(apkSignerJar),
|
|
58
|
-
windowsVerbatimArguments: _support.system.isWindows()
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
for (let [name, stream] of [['stdout', stdout], ['stderr', stderr]]) {
|
|
62
|
-
if (!_lodash.default.trim(stream)) {
|
|
63
|
-
continue;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (name === 'stdout') {
|
|
67
|
-
stream = stream.split('\n').filter(line => !line.includes('WARNING:')).join('\n');
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
_logger.default.debug(`apksigner ${name}: ${stream}`);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
return stdout;
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
apkSigningMethods.signWithDefaultCert = async function signWithDefaultCert(apk) {
|
|
77
|
-
_logger.default.debug(`Signing '${apk}' with default cert`);
|
|
78
|
-
|
|
79
|
-
if (!(await _support.fs.exists(apk))) {
|
|
80
|
-
throw new Error(`${apk} file doesn't exist.`);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const args = ['sign', '--key', DEFAULT_PRIVATE_KEY, '--cert', DEFAULT_CERTIFICATE, apk];
|
|
84
|
-
|
|
85
|
-
try {
|
|
86
|
-
await this.executeApksigner(args);
|
|
87
|
-
} catch (e) {
|
|
88
|
-
throw new Error(`Could not sign '${apk}' with the default certificate. ` + `Original error: ${e.stderr || e.stdout || e.message}`);
|
|
89
|
-
}
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
apkSigningMethods.signWithCustomCert = async function signWithCustomCert(apk) {
|
|
93
|
-
_logger.default.debug(`Signing '${apk}' with custom cert`);
|
|
94
|
-
|
|
95
|
-
if (!(await _support.fs.exists(this.keystorePath))) {
|
|
96
|
-
throw new Error(`Keystore: ${this.keystorePath} doesn't exist.`);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
if (!(await _support.fs.exists(apk))) {
|
|
100
|
-
throw new Error(`'${apk}' doesn't exist.`);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
try {
|
|
104
|
-
await this.executeApksigner(['sign', '--ks', this.keystorePath, '--ks-key-alias', this.keyAlias, '--ks-pass', `pass:${this.keystorePassword}`, '--key-pass', `pass:${this.keyPassword}`, apk]);
|
|
105
|
-
} catch (err) {
|
|
106
|
-
_logger.default.warn(`Cannot use apksigner tool for signing. Defaulting to jarsigner. ` + `Original error: ${err.stderr || err.stdout || err.message}`);
|
|
107
|
-
|
|
108
|
-
try {
|
|
109
|
-
if (await (0, _helpers.unsignApk)(apk)) {
|
|
110
|
-
_logger.default.debug(`'${apk}' has been successfully unsigned`);
|
|
111
|
-
} else {
|
|
112
|
-
_logger.default.debug(`'${apk}' does not need to be unsigned`);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
const jarsigner = _path.default.resolve(await (0, _helpers.getJavaHome)(), 'bin', `jarsigner${_support.system.isWindows() ? '.exe' : ''}`);
|
|
116
|
-
|
|
117
|
-
const fullCmd = [jarsigner, '-sigalg', 'MD5withRSA', '-digestalg', 'SHA1', '-keystore', this.keystorePath, '-storepass', this.keystorePassword, '-keypass', this.keyPassword, apk, this.keyAlias];
|
|
118
|
-
|
|
119
|
-
_logger.default.debug(`Starting jarsigner: ${_support.util.quote(fullCmd)}`);
|
|
120
|
-
|
|
121
|
-
await (0, _teen_process.exec)(fullCmd[0], fullCmd.slice(1), {
|
|
122
|
-
windowsVerbatimArguments: _support.system.isWindows()
|
|
123
|
-
});
|
|
124
|
-
} catch (e) {
|
|
125
|
-
throw new Error(`Could not sign with custom certificate. ` + `Original error: ${e.stderr || e.message}`);
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
};
|
|
129
|
-
|
|
130
|
-
apkSigningMethods.sign = async function sign(appPath) {
|
|
131
|
-
if (appPath.endsWith(_helpers.APKS_EXTENSION)) {
|
|
132
|
-
let message = 'Signing of .apks-files is not supported. ';
|
|
133
|
-
|
|
134
|
-
if (this.useKeystore) {
|
|
135
|
-
message += 'Consider manual application bundle signing with the custom keystore ' + `like it is described at ${BUNDLETOOL_TUTORIAL}`;
|
|
136
|
-
} else {
|
|
137
|
-
message += `Consider manual application bundle signing with the key at '${DEFAULT_PRIVATE_KEY}' ` + `and the certificate at '${DEFAULT_CERTIFICATE}'. Read ${BUNDLETOOL_TUTORIAL} for more details.`;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
_logger.default.warn(message);
|
|
141
|
-
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
await this.zipAlignApk(appPath);
|
|
146
|
-
|
|
147
|
-
if (this.useKeystore) {
|
|
148
|
-
await this.signWithCustomCert(appPath);
|
|
149
|
-
} else {
|
|
150
|
-
await this.signWithDefaultCert(appPath);
|
|
151
|
-
}
|
|
152
|
-
};
|
|
153
|
-
|
|
154
|
-
apkSigningMethods.zipAlignApk = async function zipAlignApk(apk) {
|
|
155
|
-
await this.initZipAlign();
|
|
156
|
-
|
|
157
|
-
try {
|
|
158
|
-
await (0, _teen_process.exec)(this.binaries.zipalign, ['-c', '4', apk]);
|
|
159
|
-
|
|
160
|
-
_logger.default.debug(`${apk}' is already zip-aligned. Doing nothing`);
|
|
161
|
-
|
|
162
|
-
return false;
|
|
163
|
-
} catch (e) {
|
|
164
|
-
_logger.default.debug(`'${apk}' is not zip-aligned. Aligning`);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
try {
|
|
168
|
-
await _support.fs.access(apk, _fs2.default.W_OK);
|
|
169
|
-
} catch (e) {
|
|
170
|
-
throw new Error(`The file at '${apk}' is not writeable. ` + `Please grant write permissions to this file or to its parent folder '${_path.default.dirname(apk)}' ` + `for the Appium process, so it can zip-align the file`);
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
const alignedApk = await _support.tempDir.path({
|
|
174
|
-
prefix: 'appium',
|
|
175
|
-
suffix: '.tmp'
|
|
176
|
-
});
|
|
177
|
-
await (0, _support.mkdirp)(_path.default.dirname(alignedApk));
|
|
178
|
-
|
|
179
|
-
try {
|
|
180
|
-
await (0, _teen_process.exec)(this.binaries.zipalign, ['-f', '4', apk, alignedApk]);
|
|
181
|
-
await _support.fs.mv(alignedApk, apk, {
|
|
182
|
-
mkdirp: true
|
|
183
|
-
});
|
|
184
|
-
return true;
|
|
185
|
-
} catch (e) {
|
|
186
|
-
if (await _support.fs.exists(alignedApk)) {
|
|
187
|
-
await _support.fs.unlink(alignedApk);
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
throw new Error(`zipAlignApk failed. Original error: ${e.stderr || e.message}`);
|
|
191
|
-
}
|
|
192
|
-
};
|
|
193
|
-
|
|
194
|
-
apkSigningMethods.checkApkCert = async function checkApkCert(appPath, pkg, opts = {}) {
|
|
195
|
-
_logger.default.debug(`Checking app cert for ${appPath}`);
|
|
196
|
-
|
|
197
|
-
if (!(await _support.fs.exists(appPath))) {
|
|
198
|
-
_logger.default.debug(`'${appPath}' does not exist`);
|
|
199
|
-
|
|
200
|
-
return false;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
if (_path.default.extname(appPath) === _helpers.APKS_EXTENSION) {
|
|
204
|
-
appPath = await this.extractBaseApk(appPath);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
const hashMatches = (apksignerOutput, expectedHashes) => {
|
|
208
|
-
for (const [name, value] of _lodash.default.toPairs(expectedHashes)) {
|
|
209
|
-
if (new RegExp(`digest:\\s+${value}\\b`, 'i').test(apksignerOutput)) {
|
|
210
|
-
_logger.default.debug(`${name} hash did match for '${_path.default.basename(appPath)}'`);
|
|
211
|
-
|
|
212
|
-
return true;
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
return false;
|
|
217
|
-
};
|
|
218
|
-
|
|
219
|
-
const {
|
|
220
|
-
requireDefaultCert = true
|
|
221
|
-
} = opts;
|
|
222
|
-
const appHash = await _support.fs.hash(appPath);
|
|
223
|
-
|
|
224
|
-
if (SIGNED_APPS_CACHE.has(appHash)) {
|
|
225
|
-
_logger.default.debug(`Using the previously cached signature entry for '${_path.default.basename(appPath)}'`);
|
|
226
|
-
|
|
227
|
-
const {
|
|
228
|
-
keystorePath,
|
|
229
|
-
output,
|
|
230
|
-
expected
|
|
231
|
-
} = SIGNED_APPS_CACHE.get(appHash);
|
|
232
|
-
|
|
233
|
-
if (this.useKeystore && this.keystorePath === keystorePath || !this.useKeystore) {
|
|
234
|
-
return !this.useKeystore && !requireDefaultCert || hashMatches(output, expected);
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
const expected = this.useKeystore ? await this.getKeystoreHash(appPath, pkg) : DEFAULT_CERT_HASH;
|
|
239
|
-
|
|
240
|
-
try {
|
|
241
|
-
await (0, _helpers.getApksignerForOs)(this);
|
|
242
|
-
const output = await this.executeApksigner(['verify', '--print-certs', appPath]);
|
|
243
|
-
const hasMatch = hashMatches(output, expected);
|
|
244
|
-
|
|
245
|
-
if (hasMatch) {
|
|
246
|
-
_logger.default.info(`'${appPath}' is signed with the ` + `${this.useKeystore ? 'keystore' : 'default'} certificate`);
|
|
247
|
-
} else {
|
|
248
|
-
_logger.default.info(`'${appPath}' is signed with a ` + `non-${this.useKeystore ? 'keystore' : 'default'} certificate`);
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
const isSigned = !this.useKeystore && !requireDefaultCert || hasMatch;
|
|
252
|
-
|
|
253
|
-
if (isSigned) {
|
|
254
|
-
SIGNED_APPS_CACHE.set(appHash, {
|
|
255
|
-
output,
|
|
256
|
-
expected,
|
|
257
|
-
keystorePath: this.keystorePath
|
|
258
|
-
});
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
return isSigned;
|
|
262
|
-
} catch (err) {
|
|
263
|
-
if (_lodash.default.includes(err.stderr, APKSIGNER_VERIFY_FAIL)) {
|
|
264
|
-
_logger.default.info(`'${appPath}' is not signed`);
|
|
265
|
-
|
|
266
|
-
return false;
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
const errMsg = err.stderr || err.stdout || err.message;
|
|
270
|
-
|
|
271
|
-
if (_lodash.default.includes(errMsg, JAVA_PROPS_INIT_ERROR)) {
|
|
272
|
-
_logger.default.warn(errMsg);
|
|
273
|
-
|
|
274
|
-
_logger.default.warn(`Assuming '${appPath}' is already signed and continuing anyway`);
|
|
275
|
-
|
|
276
|
-
return true;
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
throw new Error(`Cannot verify the signature of '${appPath}'. ` + `Original error: ${errMsg}`);
|
|
280
|
-
}
|
|
281
|
-
};
|
|
282
|
-
|
|
283
|
-
apkSigningMethods.getKeystoreHash = async function getKeystoreHash() {
|
|
284
|
-
_logger.default.debug(`Getting hash of the '${this.keystorePath}' keystore`);
|
|
285
|
-
|
|
286
|
-
const keytool = _path.default.resolve(await (0, _helpers.getJavaHome)(), 'bin', `keytool${_support.system.isWindows() ? '.exe' : ''}`);
|
|
287
|
-
|
|
288
|
-
if (!(await _support.fs.exists(keytool))) {
|
|
289
|
-
throw new Error(`The keytool utility cannot be found at '${keytool}'`);
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
const args = ['-v', '-list', '-alias', this.keyAlias, '-keystore', this.keystorePath, '-storepass', this.keystorePassword];
|
|
293
|
-
|
|
294
|
-
_logger.default.info(`Running '${keytool}' with arguments: ${_support.util.quote(args)}`);
|
|
295
|
-
|
|
296
|
-
try {
|
|
297
|
-
const {
|
|
298
|
-
stdout
|
|
299
|
-
} = await (0, _teen_process.exec)(keytool, args, {
|
|
300
|
-
windowsVerbatimArguments: _support.system.isWindows()
|
|
301
|
-
});
|
|
302
|
-
const result = {};
|
|
303
|
-
|
|
304
|
-
for (const hashName of [SHA512, SHA256, SHA1, MD5]) {
|
|
305
|
-
const hashRe = new RegExp(`^\\s*${hashName}:\\s*([a-f0-9:]+)`, 'mi');
|
|
306
|
-
const match = hashRe.exec(stdout);
|
|
307
|
-
|
|
308
|
-
if (!match) {
|
|
309
|
-
continue;
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
result[hashName] = match[1].replace(/:/g, '').toLowerCase();
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
if (_lodash.default.isEmpty(result)) {
|
|
316
|
-
_logger.default.debug(stdout);
|
|
317
|
-
|
|
318
|
-
throw new Error('Cannot parse the hash value from the keytool output');
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
_logger.default.debug(`Keystore hash: ${JSON.stringify(result)}`);
|
|
322
|
-
|
|
323
|
-
return result;
|
|
324
|
-
} catch (e) {
|
|
325
|
-
throw new Error(`Cannot get the hash of '${this.keystorePath}' keystore. ` + `Original error: ${e.stderr || e.message}`);
|
|
326
|
-
}
|
|
327
|
-
};
|
|
328
|
-
|
|
329
|
-
var _default = apkSigningMethods;
|
|
330
|
-
exports.default = _default;require('source-map-support').install();
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGliL3Rvb2xzL2Fway1zaWduaW5nLmpzIiwibmFtZXMiOlsiREVGQVVMVF9QUklWQVRFX0tFWSIsInBhdGgiLCJyZXNvbHZlIiwicm9vdERpciIsIkRFRkFVTFRfQ0VSVElGSUNBVEUiLCJCVU5ETEVUT09MX1RVVE9SSUFMIiwiQVBLU0lHTkVSX1ZFUklGWV9GQUlMIiwiU0hBMSIsIlNIQTI1NiIsIlNIQTUxMiIsIk1ENSIsIkRFRkFVTFRfQ0VSVF9IQVNIIiwiSkFWQV9QUk9QU19JTklUX0VSUk9SIiwiU0lHTkVEX0FQUFNfQ0FDSEUiLCJMUlUiLCJtYXgiLCJhcGtTaWduaW5nTWV0aG9kcyIsImV4ZWN1dGVBcGtzaWduZXIiLCJhcmdzIiwiYXBrU2lnbmVySmFyIiwiZ2V0QXBrc2lnbmVyRm9yT3MiLCJmdWxsQ21kIiwiZ2V0SmF2YUZvck9zIiwibG9nIiwiZGVidWciLCJ1dGlsIiwicXVvdGUiLCJzdGRvdXQiLCJzdGRlcnIiLCJleGVjIiwic2xpY2UiLCJjd2QiLCJkaXJuYW1lIiwid2luZG93c1ZlcmJhdGltQXJndW1lbnRzIiwic3lzdGVtIiwiaXNXaW5kb3dzIiwibmFtZSIsInN0cmVhbSIsIl8iLCJ0cmltIiwic3BsaXQiLCJmaWx0ZXIiLCJsaW5lIiwiaW5jbHVkZXMiLCJqb2luIiwic2lnbldpdGhEZWZhdWx0Q2VydCIsImFwayIsImZzIiwiZXhpc3RzIiwiRXJyb3IiLCJlIiwibWVzc2FnZSIsInNpZ25XaXRoQ3VzdG9tQ2VydCIsImtleXN0b3JlUGF0aCIsImtleUFsaWFzIiwia2V5c3RvcmVQYXNzd29yZCIsImtleVBhc3N3b3JkIiwiZXJyIiwid2FybiIsInVuc2lnbkFwayIsImphcnNpZ25lciIsImdldEphdmFIb21lIiwic2lnbiIsImFwcFBhdGgiLCJlbmRzV2l0aCIsIkFQS1NfRVhURU5TSU9OIiwidXNlS2V5c3RvcmUiLCJ6aXBBbGlnbkFwayIsImluaXRaaXBBbGlnbiIsImJpbmFyaWVzIiwiemlwYWxpZ24iLCJhY2Nlc3MiLCJfZnMiLCJXX09LIiwiYWxpZ25lZEFwayIsInRlbXBEaXIiLCJwcmVmaXgiLCJzdWZmaXgiLCJta2RpcnAiLCJtdiIsInVubGluayIsImNoZWNrQXBrQ2VydCIsInBrZyIsIm9wdHMiLCJleHRuYW1lIiwiZXh0cmFjdEJhc2VBcGsiLCJoYXNoTWF0Y2hlcyIsImFwa3NpZ25lck91dHB1dCIsImV4cGVjdGVkSGFzaGVzIiwidmFsdWUiLCJ0b1BhaXJzIiwiUmVnRXhwIiwidGVzdCIsImJhc2VuYW1lIiwicmVxdWlyZURlZmF1bHRDZXJ0IiwiYXBwSGFzaCIsImhhc2giLCJoYXMiLCJvdXRwdXQiLCJleHBlY3RlZCIsImdldCIsImdldEtleXN0b3JlSGFzaCIsImhhc01hdGNoIiwiaW5mbyIsImlzU2lnbmVkIiwic2V0IiwiZXJyTXNnIiwia2V5dG9vbCIsInJlc3VsdCIsImhhc2hOYW1lIiwiaGFzaFJlIiwibWF0Y2giLCJyZXBsYWNlIiwidG9Mb3dlckNhc2UiLCJpc0VtcHR5IiwiSlNPTiIsInN0cmluZ2lmeSJdLCJzb3VyY2VSb290IjoiLi4vLi4vLi4iLCJzb3VyY2VzIjpbImxpYi90b29scy9hcGstc2lnbmluZy5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgXyBmcm9tICdsb2Rhc2gnO1xuaW1wb3J0IF9mcyBmcm9tICdmcyc7XG5pbXBvcnQgeyBleGVjIH0gZnJvbSAndGVlbl9wcm9jZXNzJztcbmltcG9ydCBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0IGxvZyBmcm9tICcuLi9sb2dnZXIuanMnO1xuaW1wb3J0IHsgdGVtcERpciwgc3lzdGVtLCBta2RpcnAsIGZzLCB1dGlsIH0gZnJvbSAnQGFwcGl1bS9zdXBwb3J0JztcbmltcG9ydCBMUlUgZnJvbSAnbHJ1LWNhY2hlJztcbmltcG9ydCB7XG4gIGdldEphdmFGb3JPcywgZ2V0QXBrc2lnbmVyRm9yT3MsIGdldEphdmFIb21lLFxuICByb290RGlyLCBBUEtTX0VYVEVOU0lPTiwgdW5zaWduQXBrLFxufSBmcm9tICcuLi9oZWxwZXJzLmpzJztcblxuY29uc3QgREVGQVVMVF9QUklWQVRFX0tFWSA9IHBhdGgucmVzb2x2ZShyb290RGlyLCAna2V5cycsICd0ZXN0a2V5LnBrOCcpO1xuY29uc3QgREVGQVVMVF9DRVJUSUZJQ0FURSA9IHBhdGgucmVzb2x2ZShyb290RGlyLCAna2V5cycsICd0ZXN0a2V5Lng1MDkucGVtJyk7XG5jb25zdCBCVU5ETEVUT09MX1RVVE9SSUFMID0gJ2h0dHBzOi8vZGV2ZWxvcGVyLmFuZHJvaWQuY29tL3N0dWRpby9jb21tYW5kLWxpbmUvYnVuZGxldG9vbCc7XG5jb25zdCBBUEtTSUdORVJfVkVSSUZZX0ZBSUwgPSAnRE9FUyBOT1QgVkVSSUZZJztcbmNvbnN0IFNIQTEgPSAnc2hhMSc7XG5jb25zdCBTSEEyNTYgPSAnc2hhMjU2JztcbmNvbnN0IFNIQTUxMiA9ICdzaGE1MTInO1xuY29uc3QgTUQ1ID0gJ21kNSc7XG5jb25zdCBERUZBVUxUX0NFUlRfSEFTSCA9IHtcbiAgW1NIQTI1Nl06ICdhNDBkYTgwYTU5ZDE3MGNhYTk1MGNmMTVjMThjNDU0ZDQ3YTM5YjI2OTg5ZDhiNjQwZWNkNzQ1YmE3MWJmNWRjJ1xufTtcbmNvbnN0IEpBVkFfUFJPUFNfSU5JVF9FUlJPUiA9ICdqYXZhLmxhbmcuRXJyb3I6IFByb3BlcnRpZXMgaW5pdCc7XG5jb25zdCBTSUdORURfQVBQU19DQUNIRSA9IG5ldyBMUlUoe1xuICBtYXg6IDMwLFxufSk7XG5cblxuY29uc3QgYXBrU2lnbmluZ01ldGhvZHMgPSB7fTtcblxuLyoqXG4gKiBFeGVjdXRlIGFwa3NpZ25lciB1dGlsaXR5IHdpdGggZ2l2ZW4gYXJndW1lbnRzLlxuICpcbiAqIEBwYXJhbSB7P0FycmF5PFN0cmluZz59IGFyZ3MgLSBUaGUgbGlzdCBvZiB0b29sIGFyZ3VtZW50cy5cbiAqIEByZXR1cm4ge3N0cmluZ30gLSBDb21tYW5kIHN0ZG91dFxuICogQHRocm93cyB7RXJyb3J9IElmIGFwa3NpZ25lciBiaW5hcnkgaXMgbm90IHByZXNlbnQgb24gdGhlIGxvY2FsIGZpbGUgc3lzdGVtXG4gKiAgICAgICAgICAgICAgICAgb3IgdGhlIHJldHVybiBjb2RlIGlzIG5vdCBlcXVhbCB0byB6ZXJvLlxuICovXG5hcGtTaWduaW5nTWV0aG9kcy5leGVjdXRlQXBrc2lnbmVyID0gYXN5bmMgZnVuY3Rpb24gZXhlY3V0ZUFwa3NpZ25lciAoYXJncyA9IFtdKSB7XG4gIGNvbnN0IGFwa1NpZ25lckphciA9IGF3YWl0IGdldEFwa3NpZ25lckZvck9zKHRoaXMpO1xuICBjb25zdCBmdWxsQ21kID0gW1xuICAgIGF3YWl0IGdldEphdmFGb3JPcygpLCAnLVhteDEwMjRNJywgJy1Yc3MxbScsXG4gICAgJy1qYXInLCBhcGtTaWduZXJKYXIsXG4gICAgLi4uYXJnc1xuICBdO1xuICBsb2cuZGVidWcoYFN0YXJ0aW5nIGFwa3NpZ25lcjogJHt1dGlsLnF1b3RlKGZ1bGxDbWQpfWApO1xuICAvLyBJdCBpcyBuZWNlc3NhcnkgdG8gc3BlY2lmeSBDV0QgZXhwbGljaXRseTsgc2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9hcHBpdW0vYXBwaXVtL2lzc3Vlcy8xNDcyNCNpc3N1ZWNvbW1lbnQtNzM3NDQ2NzE1XG4gIGNvbnN0IHtzdGRvdXQsIHN0ZGVycn0gPSBhd2FpdCBleGVjKGZ1bGxDbWRbMF0sIGZ1bGxDbWQuc2xpY2UoMSksIHtcbiAgICBjd2Q6IHBhdGguZGlybmFtZShhcGtTaWduZXJKYXIpLCB3aW5kb3dzVmVyYmF0aW1Bcmd1bWVudHM6IHN5c3RlbS5pc1dpbmRvd3MoKVxuICB9KTtcbiAgZm9yIChsZXQgW25hbWUsIHN0cmVhbV0gb2YgW1snc3Rkb3V0Jywgc3Rkb3V0XSwgWydzdGRlcnInLCBzdGRlcnJdXSkge1xuICAgIGlmICghXy50cmltKHN0cmVhbSkpIHtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cblxuICAgIGlmIChuYW1lID09PSAnc3Rkb3V0Jykge1xuICAgICAgLy8gTWFrZSB0aGUgb3V0cHV0IGxlc3MgdGFsa2F0aXZlXG4gICAgICBzdHJlYW0gPSBzdHJlYW0uc3BsaXQoJ1xcbicpXG4gICAgICAgIC5maWx0ZXIoKGxpbmUpID0+ICFsaW5lLmluY2x1ZGVzKCdXQVJOSU5HOicpKVxuICAgICAgICAuam9pbignXFxuJyk7XG4gICAgfVxuICAgIGxvZy5kZWJ1ZyhgYXBrc2lnbmVyICR7bmFtZX06ICR7c3RyZWFtfWApO1xuICB9XG4gIHJldHVybiBzdGRvdXQ7XG59O1xuXG4vKipcbiAqIChSZSlzaWduIHRoZSBnaXZlbiBhcGsgZmlsZSBvbiB0aGUgbG9jYWwgZmlsZSBzeXN0ZW0gd2l0aCB0aGUgZGVmYXVsdCBjZXJ0aWZpY2F0ZS5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gYXBrIC0gVGhlIGZ1bGwgcGF0aCB0byB0aGUgbG9jYWwgYXBrIGZpbGUuXG4gKiBAdGhyb3dzIHtFcnJvcn0gSWYgc2lnbmluZyBmYWlscy5cbiAqL1xuYXBrU2lnbmluZ01ldGhvZHMuc2lnbldpdGhEZWZhdWx0Q2VydCA9IGFzeW5jIGZ1bmN0aW9uIHNpZ25XaXRoRGVmYXVsdENlcnQgKGFwaykge1xuICBsb2cuZGVidWcoYFNpZ25pbmcgJyR7YXBrfScgd2l0aCBkZWZhdWx0IGNlcnRgKTtcbiAgaWYgKCEoYXdhaXQgZnMuZXhpc3RzKGFwaykpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGAke2Fwa30gZmlsZSBkb2Vzbid0IGV4aXN0LmApO1xuICB9XG5cbiAgY29uc3QgYXJncyA9IFtcbiAgICAnc2lnbicsXG4gICAgJy0ta2V5JywgREVGQVVMVF9QUklWQVRFX0tFWSxcbiAgICAnLS1jZXJ0JywgREVGQVVMVF9DRVJUSUZJQ0FURSxcbiAgICBhcGssXG4gIF07XG4gIHRyeSB7XG4gICAgYXdhaXQgdGhpcy5leGVjdXRlQXBrc2lnbmVyKGFyZ3MpO1xuICB9IGNhdGNoIChlKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBDb3VsZCBub3Qgc2lnbiAnJHthcGt9JyB3aXRoIHRoZSBkZWZhdWx0IGNlcnRpZmljYXRlLiBgICtcbiAgICAgIGBPcmlnaW5hbCBlcnJvcjogJHtlLnN0ZGVyciB8fCBlLnN0ZG91dCB8fCBlLm1lc3NhZ2V9YCk7XG4gIH1cbn07XG5cbi8qKlxuICogKFJlKXNpZ24gdGhlIGdpdmVuIGFwayBmaWxlIG9uIHRoZSBsb2NhbCBmaWxlIHN5c3RlbSB3aXRoIGEgY3VzdG9tIGNlcnRpZmljYXRlLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBhcGsgLSBUaGUgZnVsbCBwYXRoIHRvIHRoZSBsb2NhbCBhcGsgZmlsZS5cbiAqIEB0aHJvd3Mge0Vycm9yfSBJZiBzaWduaW5nIGZhaWxzLlxuICovXG5hcGtTaWduaW5nTWV0aG9kcy5zaWduV2l0aEN1c3RvbUNlcnQgPSBhc3luYyBmdW5jdGlvbiBzaWduV2l0aEN1c3RvbUNlcnQgKGFwaykge1xuICBsb2cuZGVidWcoYFNpZ25pbmcgJyR7YXBrfScgd2l0aCBjdXN0b20gY2VydGApO1xuICBpZiAoIShhd2FpdCBmcy5leGlzdHModGhpcy5rZXlzdG9yZVBhdGgpKSkge1xuICAgIHRocm93IG5ldyBFcnJvcihgS2V5c3RvcmU6ICR7dGhpcy5rZXlzdG9yZVBhdGh9IGRvZXNuJ3QgZXhpc3QuYCk7XG4gIH1cbiAgaWYgKCEoYXdhaXQgZnMuZXhpc3RzKGFwaykpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGAnJHthcGt9JyBkb2Vzbid0IGV4aXN0LmApO1xuICB9XG5cbiAgdHJ5IHtcbiAgICBhd2FpdCB0aGlzLmV4ZWN1dGVBcGtzaWduZXIoWydzaWduJyxcbiAgICAgICctLWtzJywgdGhpcy5rZXlzdG9yZVBhdGgsXG4gICAgICAnLS1rcy1rZXktYWxpYXMnLCB0aGlzLmtleUFsaWFzLFxuICAgICAgJy0ta3MtcGFzcycsIGBwYXNzOiR7dGhpcy5rZXlzdG9yZVBhc3N3b3JkfWAsXG4gICAgICAnLS1rZXktcGFzcycsIGBwYXNzOiR7dGhpcy5rZXlQYXNzd29yZH1gLFxuICAgICAgYXBrXSk7XG4gIH0gY2F0Y2ggKGVycikge1xuICAgIGxvZy53YXJuKGBDYW5ub3QgdXNlIGFwa3NpZ25lciB0b29sIGZvciBzaWduaW5nLiBEZWZhdWx0aW5nIHRvIGphcnNpZ25lci4gYCArXG4gICAgICBgT3JpZ2luYWwgZXJyb3I6ICR7ZXJyLnN0ZGVyciB8fCBlcnIuc3Rkb3V0IHx8IGVyci5tZXNzYWdlfWApO1xuICAgIHRyeSB7XG4gICAgICBpZiAoYXdhaXQgdW5zaWduQXBrKGFwaykpIHtcbiAgICAgICAgbG9nLmRlYnVnKGAnJHthcGt9JyBoYXMgYmVlbiBzdWNjZXNzZnVsbHkgdW5zaWduZWRgKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGxvZy5kZWJ1ZyhgJyR7YXBrfScgZG9lcyBub3QgbmVlZCB0byBiZSB1bnNpZ25lZGApO1xuICAgICAgfVxuICAgICAgY29uc3QgamFyc2lnbmVyID0gcGF0aC5yZXNvbHZlKGF3YWl0IGdldEphdmFIb21lKCksICdiaW4nLFxuICAgICAgICBgamFyc2lnbmVyJHtzeXN0ZW0uaXNXaW5kb3dzKCkgPyAnLmV4ZScgOiAnJ31gKTtcbiAgICAgIGNvbnN0IGZ1bGxDbWQgPSBbamFyc2lnbmVyLFxuICAgICAgICAnLXNpZ2FsZycsICdNRDV3aXRoUlNBJyxcbiAgICAgICAgJy1kaWdlc3RhbGcnLCAnU0hBMScsXG4gICAgICAgICcta2V5c3RvcmUnLCB0aGlzLmtleXN0b3JlUGF0aCxcbiAgICAgICAgJy1zdG9yZXBhc3MnLCB0aGlzLmtleXN0b3JlUGFzc3dvcmQsXG4gICAgICAgICcta2V5cGFzcycsIHRoaXMua2V5UGFzc3dvcmQsXG4gICAgICAgIGFwaywgdGhpcy5rZXlBbGlhc107XG4gICAgICBsb2cuZGVidWcoYFN0YXJ0aW5nIGphcnNpZ25lcjogJHt1dGlsLnF1b3RlKGZ1bGxDbWQpfWApO1xuICAgICAgYXdhaXQgZXhlYyhmdWxsQ21kWzBdLCBmdWxsQ21kLnNsaWNlKDEpLCB7IHdpbmRvd3NWZXJiYXRpbUFyZ3VtZW50czogc3lzdGVtLmlzV2luZG93cygpIH0pO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgQ291bGQgbm90IHNpZ24gd2l0aCBjdXN0b20gY2VydGlmaWNhdGUuIGAgK1xuICAgICAgICBgT3JpZ2luYWwgZXJyb3I6ICR7ZS5zdGRlcnIgfHwgZS5tZXNzYWdlfWApO1xuICAgIH1cbiAgfVxufTtcblxuLyoqXG4gKiAoUmUpc2lnbiB0aGUgZ2l2ZW4gYXBrIGZpbGUgb24gdGhlIGxvY2FsIGZpbGUgc3lzdGVtIHdpdGggZWl0aGVyXG4gKiBjdXN0b20gb3IgZGVmYXVsdCBjZXJ0aWZpY2F0ZSBiYXNlZCBvbiBfdGhpcy51c2VLZXlzdG9yZV8gcHJvcGVydHkgdmFsdWVcbiAqIGFuZCBaaXAtYWxpZ25zIGl0IGFmdGVyIHNpZ25pbmcuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IGFwcFBhdGggLSBUaGUgZnVsbCBwYXRoIHRvIHRoZSBsb2NhbCAuYXBrKHMpIGZpbGUuXG4gKiBAdGhyb3dzIHtFcnJvcn0gSWYgc2lnbmluZyBmYWlscy5cbiAqL1xuYXBrU2lnbmluZ01ldGhvZHMuc2lnbiA9IGFzeW5jIGZ1bmN0aW9uIHNpZ24gKGFwcFBhdGgpIHtcbiAgaWYgKGFwcFBhdGguZW5kc1dpdGgoQVBLU19FWFRFTlNJT04pKSB7XG4gICAgbGV0IG1lc3NhZ2UgPSAnU2lnbmluZyBvZiAuYXBrcy1maWxlcyBpcyBub3Qgc3VwcG9ydGVkLiAnO1xuICAgIGlmICh0aGlzLnVzZUtleXN0b3JlKSB7XG4gICAgICBtZXNzYWdlICs9ICdDb25zaWRlciBtYW51YWwgYXBwbGljYXRpb24gYnVuZGxlIHNpZ25pbmcgd2l0aCB0aGUgY3VzdG9tIGtleXN0b3JlICcgK1xuICAgICAgICBgbGlrZSBpdCBpcyBkZXNjcmliZWQgYXQgJHtCVU5ETEVUT09MX1RVVE9SSUFMfWA7XG4gICAgfSBlbHNlIHtcbiAgICAgIG1lc3NhZ2UgKz0gYENvbnNpZGVyIG1hbnVhbCBhcHBsaWNhdGlvbiBidW5kbGUgc2lnbmluZyB3aXRoIHRoZSBrZXkgYXQgJyR7REVGQVVMVF9QUklWQVRFX0tFWX0nIGAgK1xuICAgICAgICBgYW5kIHRoZSBjZXJ0aWZpY2F0ZSBhdCAnJHtERUZBVUxUX0NFUlRJRklDQVRFfScuIFJlYWQgJHtCVU5ETEVUT09MX1RVVE9SSUFMfSBmb3IgbW9yZSBkZXRhaWxzLmA7XG4gICAgfVxuICAgIGxvZy53YXJuKG1lc3NhZ2UpO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIC8vIGl0IGlzIG5lY2Vzc2FyeSB0byBhcHBseSB6aXBhbGlnbiBvbmx5IGJlZm9yZSBzaWduaW5nXG4gIC8vIGlmIGFwa3NpZ25lciBpcyB1c2VkXG4gIGF3YWl0IHRoaXMuemlwQWxpZ25BcGsoYXBwUGF0aCk7XG5cbiAgaWYgKHRoaXMudXNlS2V5c3RvcmUpIHtcbiAgICBhd2FpdCB0aGlzLnNpZ25XaXRoQ3VzdG9tQ2VydChhcHBQYXRoKTtcbiAgfSBlbHNlIHtcbiAgICBhd2FpdCB0aGlzLnNpZ25XaXRoRGVmYXVsdENlcnQoYXBwUGF0aCk7XG4gIH1cbn07XG5cbi8qKlxuICogUGVyZm9ybSB6aXAtYWxpZ25pbmcgdG8gdGhlIGdpdmVuIGxvY2FsIGFwayBmaWxlLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBhcGsgLSBUaGUgZnVsbCBwYXRoIHRvIHRoZSBsb2NhbCBhcGsgZmlsZS5cbiAqIEByZXR1cm5zIHtib29sZWFufSBUcnVlIGlmIHRoZSBhcGsgaGFzIGJlZW4gc3VjY2Vzc2Z1bGx5IGFsaWduZWRcbiAqIG9yIGZhbHNlIGlmIHRoZSBhcGsgaGFzIGJlZW4gYWxyZWFkeSBhbGlnbmVkLlxuICogQHRocm93cyB7RXJyb3J9IElmIHppcC1hbGlnbiBmYWlscy5cbiAqL1xuYXBrU2lnbmluZ01ldGhvZHMuemlwQWxpZ25BcGsgPSBhc3luYyBmdW5jdGlvbiB6aXBBbGlnbkFwayAoYXBrKSB7XG4gIGF3YWl0IHRoaXMuaW5pdFppcEFsaWduKCk7XG4gIHRyeSB7XG4gICAgYXdhaXQgZXhlYyh0aGlzLmJpbmFyaWVzLnppcGFsaWduLCBbJy1jJywgJzQnLCBhcGtdKTtcbiAgICBsb2cuZGVidWcoYCR7YXBrfScgaXMgYWxyZWFkeSB6aXAtYWxpZ25lZC4gRG9pbmcgbm90aGluZ2ApO1xuICAgIHJldHVybiBmYWxzZTtcbiAgfSBjYXRjaCAoZSkge1xuICAgIGxvZy5kZWJ1ZyhgJyR7YXBrfScgaXMgbm90IHppcC1hbGlnbmVkLiBBbGlnbmluZ2ApO1xuICB9XG4gIHRyeSB7XG4gICAgYXdhaXQgZnMuYWNjZXNzKGFwaywgX2ZzLldfT0spO1xuICB9IGNhdGNoIChlKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBUaGUgZmlsZSBhdCAnJHthcGt9JyBpcyBub3Qgd3JpdGVhYmxlLiBgICtcbiAgICAgIGBQbGVhc2UgZ3JhbnQgd3JpdGUgcGVybWlzc2lvbnMgdG8gdGhpcyBmaWxlIG9yIHRvIGl0cyBwYXJlbnQgZm9sZGVyICcke3BhdGguZGlybmFtZShhcGspfScgYCArXG4gICAgICBgZm9yIHRoZSBBcHBpdW0gcHJvY2Vzcywgc28gaXQgY2FuIHppcC1hbGlnbiB0aGUgZmlsZWApO1xuICB9XG4gIGNvbnN0IGFsaWduZWRBcGsgPSBhd2FpdCB0ZW1wRGlyLnBhdGgoe3ByZWZpeDogJ2FwcGl1bScsIHN1ZmZpeDogJy50bXAnfSk7XG4gIGF3YWl0IG1rZGlycChwYXRoLmRpcm5hbWUoYWxpZ25lZEFwaykpO1xuICB0cnkge1xuICAgIGF3YWl0IGV4ZWModGhpcy5iaW5hcmllcy56aXBhbGlnbiwgWyctZicsICc0JywgYXBrLCBhbGlnbmVkQXBrXSk7XG4gICAgYXdhaXQgZnMubXYoYWxpZ25lZEFwaywgYXBrLCB7IG1rZGlycDogdHJ1ZSB9KTtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfSBjYXRjaCAoZSkge1xuICAgIGlmIChhd2FpdCBmcy5leGlzdHMoYWxpZ25lZEFwaykpIHtcbiAgICAgIGF3YWl0IGZzLnVubGluayhhbGlnbmVkQXBrKTtcbiAgICB9XG4gICAgdGhyb3cgbmV3IEVycm9yKGB6aXBBbGlnbkFwayBmYWlsZWQuIE9yaWdpbmFsIGVycm9yOiAke2Uuc3RkZXJyIHx8IGUubWVzc2FnZX1gKTtcbiAgfVxufTtcblxuLyoqXG4gKiBAdHlwZWRlZiB7T2JqZWN0fSBDZXJ0Q2hlY2tPcHRpb25zXG4gKiBAcHJvcGVydHkge2Jvb2xlYW59IHJlcXVpcmVEZWZhdWx0Q2VydCBbdHJ1ZV0gV2hldGhlciB0byByZXF1aXJlIHRoYXQgdGhlIGRlc3RpbmF0aW9uIEFQS1xuICogaXMgc2lnbmVkIHdpdGggdGhlIGRlZmF1bHQgQXBwaXVtIGNlcnRpZmljYXRlIG9yIGFueSB2YWxpZCBjZXJ0aWZpY2F0ZS4gVGhpcyBvcHRpb25cbiAqIG9ubHkgaGFzIGVmZmVjdCBpZiBgdXNlS2V5c3RvcmVgIHByb3BlcnR5IGlzIHVuc2V0LlxuICovXG5cbi8qKlxuICogQ2hlY2sgaWYgdGhlIGFwcCBpcyBhbHJlYWR5IHNpZ25lZCB3aXRoIHRoZSBkZWZhdWx0IEFwcGl1bSBjZXJ0aWZpY2F0ZS5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gYXBwUGF0aCAtIFRoZSBmdWxsIHBhdGggdG8gdGhlIGxvY2FsIC5hcGsocykgZmlsZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBwZ2sgLSBUaGUgbmFtZSBvZiBhcHBsaWNhdGlvbiBwYWNrYWdlLlxuICogQHBhcmFtIHtDZXJ0Q2hlY2tPcHRpb25zfSBvcHRzIC0gQ2VydGlmaWNhdGUgY2hlY2tpbmcgb3B0aW9uc1xuICogQHJldHVybiB7Ym9vbGVhbn0gVHJ1ZSBpZiBnaXZlbiBhcHBsaWNhdGlvbiBpcyBhbHJlYWR5IHNpZ25lZC5cbiAqL1xuYXBrU2lnbmluZ01ldGhvZHMuY2hlY2tBcGtDZXJ0ID0gYXN5bmMgZnVuY3Rpb24gY2hlY2tBcGtDZXJ0IChhcHBQYXRoLCBwa2csIG9wdHMgPSB7fSkge1xuICBsb2cuZGVidWcoYENoZWNraW5nIGFwcCBjZXJ0IGZvciAke2FwcFBhdGh9YCk7XG4gIGlmICghYXdhaXQgZnMuZXhpc3RzKGFwcFBhdGgpKSB7XG4gICAgbG9nLmRlYnVnKGAnJHthcHBQYXRofScgZG9lcyBub3QgZXhpc3RgKTtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICBpZiAocGF0aC5leHRuYW1lKGFwcFBhdGgpID09PSBBUEtTX0VYVEVOU0lPTikge1xuICAgIGFwcFBhdGggPSBhd2FpdCB0aGlzLmV4dHJhY3RCYXNlQXBrKGFwcFBhdGgpO1xuICB9XG5cbiAgY29uc3QgaGFzaE1hdGNoZXMgPSAoYXBrc2lnbmVyT3V0cHV0LCBleHBlY3RlZEhhc2hlcykgPT4ge1xuICAgIGZvciAoY29uc3QgW25hbWUsIHZhbHVlXSBvZiBfLnRvUGFpcnMoZXhwZWN0ZWRIYXNoZXMpKSB7XG4gICAgICBpZiAobmV3IFJlZ0V4cChgZGlnZXN0OlxcXFxzKyR7dmFsdWV9XFxcXGJgLCAnaScpLnRlc3QoYXBrc2lnbmVyT3V0cHV0KSkge1xuICAgICAgICBsb2cuZGVidWcoYCR7bmFtZX0gaGFzaCBkaWQgbWF0Y2ggZm9yICcke3BhdGguYmFzZW5hbWUoYXBwUGF0aCl9J2ApO1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9O1xuXG4gIGNvbnN0IHtcbiAgICByZXF1aXJlRGVmYXVsdENlcnQgPSB0cnVlLFxuICB9ID0gb3B0cztcblxuICBjb25zdCBhcHBIYXNoID0gYXdhaXQgZnMuaGFzaChhcHBQYXRoKTtcbiAgaWYgKFNJR05FRF9BUFBTX0NBQ0hFLmhhcyhhcHBIYXNoKSkge1xuICAgIGxvZy5kZWJ1ZyhgVXNpbmcgdGhlIHByZXZpb3VzbHkgY2FjaGVkIHNpZ25hdHVyZSBlbnRyeSBmb3IgJyR7cGF0aC5iYXNlbmFtZShhcHBQYXRoKX0nYCk7XG4gICAgY29uc3Qge2tleXN0b3JlUGF0aCwgb3V0cHV0LCBleHBlY3RlZH0gPSBTSUdORURfQVBQU19DQUNIRS5nZXQoYXBwSGFzaCk7XG4gICAgaWYgKHRoaXMudXNlS2V5c3RvcmUgJiYgdGhpcy5rZXlzdG9yZVBhdGggPT09IGtleXN0b3JlUGF0aCB8fCAhdGhpcy51c2VLZXlzdG9yZSkge1xuICAgICAgcmV0dXJuICghdGhpcy51c2VLZXlzdG9yZSAmJiAhcmVxdWlyZURlZmF1bHRDZXJ0KSB8fCBoYXNoTWF0Y2hlcyhvdXRwdXQsIGV4cGVjdGVkKTtcbiAgICB9XG4gIH1cblxuICBjb25zdCBleHBlY3RlZCA9IHRoaXMudXNlS2V5c3RvcmVcbiAgICA/IGF3YWl0IHRoaXMuZ2V0S2V5c3RvcmVIYXNoKGFwcFBhdGgsIHBrZylcbiAgICA6IERFRkFVTFRfQ0VSVF9IQVNIO1xuICB0cnkge1xuICAgIGF3YWl0IGdldEFwa3NpZ25lckZvck9zKHRoaXMpO1xuICAgIGNvbnN0IG91dHB1dCA9IGF3YWl0IHRoaXMuZXhlY3V0ZUFwa3NpZ25lcihbJ3ZlcmlmeScsICctLXByaW50LWNlcnRzJywgYXBwUGF0aF0pO1xuICAgIGNvbnN0IGhhc01hdGNoID0gaGFzaE1hdGNoZXMob3V0cHV0LCBleHBlY3RlZCk7XG4gICAgaWYgKGhhc01hdGNoKSB7XG4gICAgICBsb2cuaW5mbyhgJyR7YXBwUGF0aH0nIGlzIHNpZ25lZCB3aXRoIHRoZSBgICtcbiAgICAgICAgYCR7dGhpcy51c2VLZXlzdG9yZSA/ICdrZXlzdG9yZScgOiAnZGVmYXVsdCd9IGNlcnRpZmljYXRlYCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGxvZy5pbmZvKGAnJHthcHBQYXRofScgaXMgc2lnbmVkIHdpdGggYSBgICtcbiAgICAgICAgYG5vbi0ke3RoaXMudXNlS2V5c3RvcmUgPyAna2V5c3RvcmUnIDogJ2RlZmF1bHQnfSBjZXJ0aWZpY2F0ZWApO1xuICAgIH1cbiAgICBjb25zdCBpc1NpZ25lZCA9ICghdGhpcy51c2VLZXlzdG9yZSAmJiAhcmVxdWlyZURlZmF1bHRDZXJ0KSB8fCBoYXNNYXRjaDtcbiAgICBpZiAoaXNTaWduZWQpIHtcbiAgICAgIFNJR05FRF9BUFBTX0NBQ0hFLnNldChhcHBIYXNoLCB7XG4gICAgICAgIG91dHB1dCxcbiAgICAgICAgZXhwZWN0ZWQsXG4gICAgICAgIGtleXN0b3JlUGF0aDogdGhpcy5rZXlzdG9yZVBhdGgsXG4gICAgICB9KTtcbiAgICB9XG4gICAgcmV0dXJuIGlzU2lnbmVkO1xuICB9IGNhdGNoIChlcnIpIHtcbiAgICAvLyBjaGVjayBpZiB0aGVyZSBpcyBubyBzaWduYXR1cmVcbiAgICBpZiAoXy5pbmNsdWRlcyhlcnIuc3RkZXJyLCBBUEtTSUdORVJfVkVSSUZZX0ZBSUwpKSB7XG4gICAgICBsb2cuaW5mbyhgJyR7YXBwUGF0aH0nIGlzIG5vdCBzaWduZWRgKTtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgY29uc3QgZXJyTXNnID0gZXJyLnN0ZGVyciB8fCBlcnIuc3Rkb3V0IHx8IGVyci5tZXNzYWdlO1xuICAgIGlmIChfLmluY2x1ZGVzKGVyck1zZywgSkFWQV9QUk9QU19JTklUX0VSUk9SKSkge1xuICAgICAgLy8gVGhpcyBlcnJvciBwb3BzIHVwIHJhbmRvbWx5IGFuZCB3ZSBhcmUgbm90IHF1aXRlIHN1cmUgd2h5LlxuICAgICAgLy8gTXkgZ3Vlc3MgLSBhIHJhY2UgY29uZGl0aW9uIGluIGphdmEgdm0gaW5pdGlhbGl6YXRpb24uXG4gICAgICAvLyBOZXZlcnRoZWxlc3MsIGxldHMgbWFrZSBBcHBpdW0gdG8gYmVsaWV2ZSB0aGUgZmlsZSBpcyBhbHJlYWR5IHNpZ25lZCxcbiAgICAgIC8vIGJlY2F1c2UgaXQgd291bGQgYmUgdHJ1ZSBmb3IgOTklIG9mIFVJQXV0b21hdG9yMi1iYXNlZFxuICAgICAgLy8gdGVzdHMsIHdoZXJlIHdlIHByZXNpZ24gc2VydmVyIGJpbmFyaWVzIHdoaWxlIHB1Ymxpc2hpbmcgdGhlaXIgTlBNIG1vZHVsZS5cbiAgICAgIC8vIElmIHRoZXNlIGFyZSBub3Qgc2lnbmVkLCBlLmcuIGluIGNhc2Ugb2YgRXNwcmVzc28sIHRoZW4gdGhlIG5leHQgc3RlcChzKVxuICAgICAgLy8gd291bGQgYW55d2F5IGZhaWwuXG4gICAgICAvLyBTZWUgaHR0cHM6Ly9naXRodWIuY29tL2FwcGl1bS9hcHBpdW0vaXNzdWVzLzE0NzI0IGZvciBtb3JlIGRldGFpbHMuXG4gICAgICBsb2cud2FybihlcnJNc2cpO1xuICAgICAgbG9nLndhcm4oYEFzc3VtaW5nICcke2FwcFBhdGh9JyBpcyBhbHJlYWR5IHNpZ25lZCBhbmQgY29udGludWluZyBhbnl3YXlgKTtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgICB0aHJvdyBuZXcgRXJyb3IoYENhbm5vdCB2ZXJpZnkgdGhlIHNpZ25hdHVyZSBvZiAnJHthcHBQYXRofScuIGAgK1xuICAgICAgYE9yaWdpbmFsIGVycm9yOiAke2Vyck1zZ31gKTtcbiAgfVxufTtcblxuLyoqXG4gKiBAdHlwZWRlZiB7T2JqZWN0fSBLZXlzdG9yZUhhc2hcbiAqIEBwcm9wZXJ0eSB7P3N0cmluZ30gbWQ1IHRoZSBtZDUgaGFzaCB2YWx1ZSBvZiB0aGUga2V5c3RvcmVcbiAqIEBwcm9wZXJ0eSB7P3N0cmluZ30gc2hhMSB0aGUgc2hhMSBoYXNoIHZhbHVlIG9mIHRoZSBrZXlzdG9yZVxuICogQHByb3BlcnR5IHs/c3RyaW5nfSBzaGEyNTYgdGhlIHNoYTI1NiBoYXNoIHZhbHVlIG9mIHRoZSBrZXlzdG9yZVxuICogQHByb3BlcnR5IHs/c3RyaW5nfSBzaGE1MTIgdGhlIHNoYTUxMiBoYXNoIHZhbHVlIG9mIHRoZSBrZXlzdG9yZVxuICovXG5cbi8qKlxuICogUmV0cmlldmUgdGhlIHRoZSBoYXNoIG9mIHRoZSBnaXZlbiBrZXlzdG9yZS5cbiAqXG4gKiBAcmV0dXJuIHtLZXlzdG9yZUhhc2h9XG4gKiBAdGhyb3dzIHtFcnJvcn0gSWYgZ2V0dGluZyBrZXlzdG9yZSBoYXNoIGZhaWxzLlxuICovXG5hcGtTaWduaW5nTWV0aG9kcy5nZXRLZXlzdG9yZUhhc2ggPSBhc3luYyBmdW5jdGlvbiBnZXRLZXlzdG9yZUhhc2ggKCkge1xuICBsb2cuZGVidWcoYEdldHRpbmcgaGFzaCBvZiB0aGUgJyR7dGhpcy5rZXlzdG9yZVBhdGh9JyBrZXlzdG9yZWApO1xuICBjb25zdCBrZXl0b29sID0gcGF0aC5yZXNvbHZlKGF3YWl0IGdldEphdmFIb21lKCksICdiaW4nLFxuICAgIGBrZXl0b29sJHtzeXN0ZW0uaXNXaW5kb3dzKCkgPyAnLmV4ZScgOiAnJ31gKTtcbiAgaWYgKCFhd2FpdCBmcy5leGlzdHMoa2V5dG9vbCkpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYFRoZSBrZXl0b29sIHV0aWxpdHkgY2Fubm90IGJlIGZvdW5kIGF0ICcke2tleXRvb2x9J2ApO1xuICB9XG4gIGNvbnN0IGFyZ3MgPSBbXG4gICAgJy12JywgJy1saXN0JyxcbiAgICAnLWFsaWFzJywgdGhpcy5rZXlBbGlhcyxcbiAgICAnLWtleXN0b3JlJywgdGhpcy5rZXlzdG9yZVBhdGgsXG4gICAgJy1zdG9yZXBhc3MnLCB0aGlzLmtleXN0b3JlUGFzc3dvcmRcbiAgXTtcbiAgbG9nLmluZm8oYFJ1bm5pbmcgJyR7a2V5dG9vbH0nIHdpdGggYXJndW1lbnRzOiAke3V0aWwucXVvdGUoYXJncyl9YCk7XG4gIHRyeSB7XG4gICAgY29uc3Qge3N0ZG91dH0gPSBhd2FpdCBleGVjKGtleXRvb2wsIGFyZ3MsIHsgd2luZG93c1ZlcmJhdGltQXJndW1lbnRzOiBzeXN0ZW0uaXNXaW5kb3dzKCkgfSk7XG4gICAgY29uc3QgcmVzdWx0ID0ge307XG4gICAgZm9yIChjb25zdCBoYXNoTmFtZSBvZiBbU0hBNTEyLCBTSEEyNTYsIFNIQTEsIE1ENV0pIHtcbiAgICAgIGNvbnN0IGhhc2hSZSA9IG5ldyBSZWdFeHAoYF5cXFxccyoke2hhc2hOYW1lfTpcXFxccyooW2EtZjAtOTpdKylgLCAnbWknKTtcbiAgICAgIGNvbnN0IG1hdGNoID0gaGFzaFJlLmV4ZWMoc3Rkb3V0KTtcbiAgICAgIGlmICghbWF0Y2gpIHtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG4gICAgICByZXN1bHRbaGFzaE5hbWVdID0gbWF0Y2hbMV0ucmVwbGFjZSgvOi9nLCAnJykudG9Mb3dlckNhc2UoKTtcbiAgICB9XG4gICAgaWYgKF8uaXNFbXB0eShyZXN1bHQpKSB7XG4gICAgICBsb2cuZGVidWcoc3Rkb3V0KTtcbiAgICAgIHRocm93IG5ldyBFcnJvcignQ2Fubm90IHBhcnNlIHRoZSBoYXNoIHZhbHVlIGZyb20gdGhlIGtleXRvb2wgb3V0cHV0Jyk7XG4gICAgfVxuICAgIGxvZy5kZWJ1ZyhgS2V5c3RvcmUgaGFzaDogJHtKU09OLnN0cmluZ2lmeShyZXN1bHQpfWApO1xuICAgIHJldHVybiByZXN1bHQ7XG4gIH0gY2F0Y2ggKGUpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYENhbm5vdCBnZXQgdGhlIGhhc2ggb2YgJyR7dGhpcy5rZXlzdG9yZVBhdGh9JyBrZXlzdG9yZS4gYCArXG4gICAgICBgT3JpZ2luYWwgZXJyb3I6ICR7ZS5zdGRlcnIgfHwgZS5tZXNzYWdlfWApO1xuICB9XG59O1xuXG5leHBvcnQgZGVmYXVsdCBhcGtTaWduaW5nTWV0aG9kcztcbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7QUFBQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFLQSxNQUFNQSxtQkFBbUIsR0FBR0MsYUFBQSxDQUFLQyxPQUFMLENBQWFDLGdCQUFiLEVBQXNCLE1BQXRCLEVBQThCLGFBQTlCLENBQTVCOztBQUNBLE1BQU1DLG1CQUFtQixHQUFHSCxhQUFBLENBQUtDLE9BQUwsQ0FBYUMsZ0JBQWIsRUFBc0IsTUFBdEIsRUFBOEIsa0JBQTlCLENBQTVCOztBQUNBLE1BQU1FLG1CQUFtQixHQUFHLDhEQUE1QjtBQUNBLE1BQU1DLHFCQUFxQixHQUFHLGlCQUE5QjtBQUNBLE1BQU1DLElBQUksR0FBRyxNQUFiO0FBQ0EsTUFBTUMsTUFBTSxHQUFHLFFBQWY7QUFDQSxNQUFNQyxNQUFNLEdBQUcsUUFBZjtBQUNBLE1BQU1DLEdBQUcsR0FBRyxLQUFaO0FBQ0EsTUFBTUMsaUJBQWlCLEdBQUc7RUFDeEIsQ0FBQ0gsTUFBRCxHQUFVO0FBRGMsQ0FBMUI7QUFHQSxNQUFNSSxxQkFBcUIsR0FBRyxrQ0FBOUI7QUFDQSxNQUFNQyxpQkFBaUIsR0FBRyxJQUFJQyxpQkFBSixDQUFRO0VBQ2hDQyxHQUFHLEVBQUU7QUFEMkIsQ0FBUixDQUExQjtBQUtBLE1BQU1DLGlCQUFpQixHQUFHLEVBQTFCOztB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
|