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.
@@ -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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