UNPKG

48.1 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.default = void 0;
7
8var _fs = _interopRequireDefault(require("fs"));
9
10var _path = _interopRequireDefault(require("path"));
11
12var _lodash = _interopRequireDefault(require("lodash"));
13
14var _async = _interopRequireDefault(require("async"));
15
16var _mkdirp = _interopRequireDefault(require("mkdirp"));
17
18var _level = _interopRequireDefault(require("level"));
19
20var _lib = require("@verdaccio/commons-api/lib");
21
22var _localFs = _interopRequireWildcard(require("./local-fs"));
23
24var _pkgUtils = require("./pkg-utils");
25
26function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
27
28function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
29
30function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
31
32function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
33
34const DEPRECATED_DB_NAME = '.sinopia-db.json';
35const DB_NAME = '.verdaccio-db.json';
36const TOKEN_DB_NAME = '.token-db';
37
38/**
39 * Handle local database.
40 */
41class LocalDatabase {
42 /**
43 * Load an parse the local json database.
44 * @param {*} path the database path
45 */
46 constructor(config, logger) {
47 _defineProperty(this, "path", void 0);
48
49 _defineProperty(this, "logger", void 0);
50
51 _defineProperty(this, "data", void 0);
52
53 _defineProperty(this, "config", void 0);
54
55 _defineProperty(this, "locked", void 0);
56
57 _defineProperty(this, "tokenDb", void 0);
58
59 this.config = config;
60 this.path = this._buildStoragePath(config);
61 this.logger = logger;
62 this.locked = false;
63 this.data = this._fetchLocalPackages();
64 this.logger.trace({
65 config: this.config
66 }, '[local-storage]: configuration: @{config}');
67
68 this._sync();
69 }
70
71 getSecret() {
72 return Promise.resolve(this.data.secret);
73 }
74
75 setSecret(secret) {
76 return new Promise(resolve => {
77 this.data.secret = secret;
78 resolve(this._sync());
79 });
80 }
81 /**
82 * Add a new element.
83 * @param {*} name
84 * @return {Error|*}
85 */
86
87
88 add(name, cb) {
89 if (this.data.list.indexOf(name) === -1) {
90 this.data.list.push(name);
91 this.logger.debug({
92 name
93 }, '[local-storage]: the private package @{name} has been added');
94 cb(this._sync());
95 } else {
96 cb(null);
97 }
98 }
99
100 search(onPackage, onEnd, validateName) {
101 const storages = this._getCustomPackageLocalStorages();
102
103 this.logger.trace(`local-storage: [search]: ${JSON.stringify(storages)}`);
104
105 const base = _path.default.dirname(this.config.self_path);
106
107 const self = this;
108 const storageKeys = Object.keys(storages);
109 this.logger.trace(`local-storage: [search] base: ${base} keys ${storageKeys}`);
110
111 _async.default.eachSeries(storageKeys, function (storage, cb) {
112 const position = storageKeys.indexOf(storage);
113
114 const base2 = _path.default.join(position !== 0 ? storageKeys[0] : '');
115
116 const storagePath = _path.default.resolve(base, base2, storage);
117
118 self.logger.trace({
119 storagePath,
120 storage
121 }, 'local-storage: [search] search path: @{storagePath} : @{storage}');
122
123 _fs.default.readdir(storagePath, (err, files) => {
124 if (err) {
125 return cb(err);
126 }
127
128 _async.default.eachSeries(files, function (file, cb) {
129 self.logger.trace({
130 file
131 }, 'local-storage: [search] search file path: @{file}');
132
133 if (storageKeys.includes(file)) {
134 return cb();
135 }
136
137 if (file.match(/^@/)) {
138 // scoped
139 const fileLocation = _path.default.resolve(base, storage, file);
140
141 self.logger.trace({
142 fileLocation
143 }, 'local-storage: [search] search scoped file location: @{fileLocation}');
144
145 _fs.default.readdir(fileLocation, function (err, files) {
146 if (err) {
147 return cb(err);
148 }
149
150 _async.default.eachSeries(files, (file2, cb) => {
151 if (validateName(file2)) {
152 const packagePath = _path.default.resolve(base, storage, file, file2);
153
154 _fs.default.stat(packagePath, (err, stats) => {
155 if (_lodash.default.isNil(err) === false) {
156 return cb(err);
157 }
158
159 const item = {
160 name: `${file}/${file2}`,
161 path: packagePath,
162 time: stats.mtime.getTime()
163 };
164 onPackage(item, cb);
165 });
166 } else {
167 cb();
168 }
169 }, cb);
170 });
171 } else if (validateName(file)) {
172 const base2 = _path.default.join(position !== 0 ? storageKeys[0] : '');
173
174 const packagePath = _path.default.resolve(base, base2, storage, file);
175
176 self.logger.trace({
177 packagePath
178 }, 'local-storage: [search] search file location: @{packagePath}');
179
180 _fs.default.stat(packagePath, (err, stats) => {
181 if (_lodash.default.isNil(err) === false) {
182 return cb(err);
183 }
184
185 onPackage({
186 name: file,
187 path: packagePath,
188 time: self._getTime(stats.mtime.getTime(), stats.mtime)
189 }, cb);
190 });
191 } else {
192 cb();
193 }
194 }, cb);
195 });
196 }, onEnd);
197 }
198 /**
199 * Remove an element from the database.
200 * @param {*} name
201 * @return {Error|*}
202 */
203
204
205 remove(name, cb) {
206 this.get((err, data) => {
207 if (err) {
208 cb((0, _lib.getInternalError)('error remove private package'));
209 this.logger.error({
210 err
211 }, '[local-storage/remove]: remove the private package has failed @{err}');
212 }
213
214 const pkgName = data.indexOf(name);
215
216 if (pkgName !== -1) {
217 this.data.list.splice(pkgName, 1);
218 this.logger.trace({
219 name
220 }, 'local-storage: [remove] package @{name} has been removed');
221 }
222
223 cb(this._sync());
224 });
225 }
226 /**
227 * Return all database elements.
228 * @return {Array}
229 */
230
231
232 get(cb) {
233 const list = this.data.list;
234 const totalItems = this.data.list.length;
235 cb(null, list);
236 this.logger.trace({
237 totalItems
238 }, 'local-storage: [get] full list of packages (@{totalItems}) has been fetched');
239 }
240
241 getPackageStorage(packageName) {
242 const packageAccess = this.config.getMatchedPackagesSpec(packageName);
243
244 const packagePath = this._getLocalStoragePath(packageAccess ? packageAccess.storage : undefined);
245
246 this.logger.trace({
247 packagePath
248 }, '[local-storage/getPackageStorage]: storage selected: @{packagePath}');
249
250 if (_lodash.default.isString(packagePath) === false) {
251 this.logger.debug({
252 name: packageName
253 }, 'this package has no storage defined: @{name}');
254 return;
255 }
256
257 const packageStoragePath = _path.default.join(_path.default.resolve(_path.default.dirname(this.config.self_path || ''), packagePath), packageName);
258
259 this.logger.trace({
260 packageStoragePath
261 }, '[local-storage/getPackageStorage]: storage path: @{packageStoragePath}');
262 return new _localFs.default(packageStoragePath, this.logger);
263 }
264
265 clean() {
266 this._sync();
267 }
268
269 saveToken(token) {
270 const key = this._getTokenKey(token);
271
272 const db = this.getTokenDb();
273 return new Promise((resolve, reject) => {
274 db.put(key, token, err => {
275 if (err) {
276 reject(err);
277 return;
278 }
279
280 resolve();
281 });
282 });
283 }
284
285 deleteToken(user, tokenKey) {
286 const key = this._compoundTokenKey(user, tokenKey);
287
288 const db = this.getTokenDb();
289 return new Promise((resolve, reject) => {
290 db.del(key, err => {
291 if (err) {
292 reject(err);
293 return;
294 }
295
296 resolve();
297 });
298 });
299 }
300
301 readTokens(filter) {
302 return new Promise((resolve, reject) => {
303 const tokens = [];
304 const key = filter.user + ':';
305 const db = this.getTokenDb();
306 const stream = db.createReadStream({
307 gte: key,
308 lte: String.fromCharCode(key.charCodeAt(0) + 1)
309 });
310 stream.on('data', data => {
311 tokens.push(data.value);
312 });
313 stream.once('end', () => resolve(tokens));
314 stream.once('error', err => reject(err));
315 });
316 }
317
318 _getTime(time, mtime) {
319 return time ? time : mtime;
320 }
321
322 _getCustomPackageLocalStorages() {
323 const storages = {}; // add custom storage if exist
324
325 if (this.config.storage) {
326 storages[this.config.storage] = true;
327 }
328
329 const {
330 packages
331 } = this.config;
332
333 if (packages) {
334 const listPackagesConf = Object.keys(packages || {});
335 listPackagesConf.map(pkg => {
336 const storage = packages[pkg].storage;
337
338 if (storage) {
339 storages[storage] = false;
340 }
341 });
342 }
343
344 return storages;
345 }
346 /**
347 * Syncronize {create} database whether does not exist.
348 * @return {Error|*}
349 */
350
351
352 _sync() {
353 this.logger.debug('[local-storage/_sync]: init sync database');
354
355 if (this.locked) {
356 this.logger.error('Database is locked, please check error message printed during startup to prevent data loss.');
357 return new Error('Verdaccio database is locked, please contact your administrator to checkout logs during verdaccio startup.');
358 } // Uses sync to prevent ugly race condition
359
360
361 try {
362 // https://www.npmjs.com/package/mkdirp#mkdirpsyncdir-opts
363 const folderName = _path.default.dirname(this.path);
364
365 _mkdirp.default.sync(folderName);
366
367 this.logger.debug({
368 folderName
369 }, '[local-storage/_sync]: folder @{folderName} created succeed');
370 } catch (err) {
371 // perhaps a logger instance?
372 this.logger.debug({
373 err
374 }, '[local-storage/_sync/mkdirp.sync]: sync failed @{err}');
375 return null;
376 }
377
378 try {
379 _fs.default.writeFileSync(this.path, JSON.stringify(this.data));
380
381 this.logger.debug('[local-storage/_sync/writeFileSync]: sync write succeed');
382 return null;
383 } catch (err) {
384 this.logger.debug({
385 err
386 }, '[local-storage/_sync/writeFileSync]: sync failed @{err}');
387 return err;
388 }
389 }
390 /**
391 * Verify the right local storage location.
392 * @param {String} path
393 * @return {String}
394 * @private
395 */
396
397
398 _getLocalStoragePath(storage) {
399 const globalConfigStorage = this.config ? this.config.storage : undefined;
400
401 if (_lodash.default.isNil(globalConfigStorage)) {
402 throw new Error('global storage is required for this plugin');
403 } else {
404 if (_lodash.default.isNil(storage) === false && _lodash.default.isString(storage)) {
405 return _path.default.join(globalConfigStorage, storage);
406 }
407
408 return globalConfigStorage;
409 }
410 }
411 /**
412 * Build the local database path.
413 * @param {Object} config
414 * @return {string|String|*}
415 * @private
416 */
417
418
419 _buildStoragePath(config) {
420 const sinopiadbPath = this._dbGenPath(DEPRECATED_DB_NAME, config);
421
422 try {
423 _fs.default.accessSync(sinopiadbPath, _fs.default.constants.F_OK);
424
425 return sinopiadbPath;
426 } catch (err) {
427 if (err.code === _localFs.noSuchFile) {
428 return this._dbGenPath(DB_NAME, config);
429 }
430
431 throw err;
432 }
433 }
434
435 _dbGenPath(dbName, config) {
436 return _path.default.join(_path.default.resolve(_path.default.dirname(config.self_path || ''), config.storage, dbName));
437 }
438 /**
439 * Fetch local packages.
440 * @private
441 * @return {Object}
442 */
443
444
445 _fetchLocalPackages() {
446 const list = [];
447 const emptyDatabase = {
448 list,
449 secret: ''
450 };
451
452 try {
453 const db = (0, _pkgUtils.loadPrivatePackages)(this.path, this.logger);
454 return db;
455 } catch (err) {
456 // readFileSync is platform specific, macOS, Linux and Windows thrown an error
457 // Only recreate if file not found to prevent data loss
458 if (err.code !== _localFs.noSuchFile) {
459 this.locked = true;
460 this.logger.error('Failed to read package database file, please check the error printed below:\n', `File Path: ${this.path}\n\n ${err.message}`);
461 }
462
463 return emptyDatabase;
464 }
465 }
466
467 getTokenDb() {
468 if (!this.tokenDb) {
469 this.tokenDb = (0, _level.default)(this._dbGenPath(TOKEN_DB_NAME, this.config), {
470 valueEncoding: 'json'
471 });
472 }
473
474 return this.tokenDb;
475 }
476
477 _getTokenKey(token) {
478 const {
479 user,
480 key
481 } = token;
482 return this._compoundTokenKey(user, key);
483 }
484
485 _compoundTokenKey(user, key) {
486 return `${user}:${key}`;
487 }
488
489}
490
491var _default = LocalDatabase;
492exports.default = _default;
493//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9sb2NhbC1kYXRhYmFzZS50cyJdLCJuYW1lcyI6WyJERVBSRUNBVEVEX0RCX05BTUUiLCJEQl9OQU1FIiwiVE9LRU5fREJfTkFNRSIsIkxvY2FsRGF0YWJhc2UiLCJjb25zdHJ1Y3RvciIsImNvbmZpZyIsImxvZ2dlciIsInBhdGgiLCJfYnVpbGRTdG9yYWdlUGF0aCIsImxvY2tlZCIsImRhdGEiLCJfZmV0Y2hMb2NhbFBhY2thZ2VzIiwidHJhY2UiLCJfc3luYyIsImdldFNlY3JldCIsIlByb21pc2UiLCJyZXNvbHZlIiwic2VjcmV0Iiwic2V0U2VjcmV0IiwiYWRkIiwibmFtZSIsImNiIiwibGlzdCIsImluZGV4T2YiLCJwdXNoIiwiZGVidWciLCJzZWFyY2giLCJvblBhY2thZ2UiLCJvbkVuZCIsInZhbGlkYXRlTmFtZSIsInN0b3JhZ2VzIiwiX2dldEN1c3RvbVBhY2thZ2VMb2NhbFN0b3JhZ2VzIiwiSlNPTiIsInN0cmluZ2lmeSIsImJhc2UiLCJQYXRoIiwiZGlybmFtZSIsInNlbGZfcGF0aCIsInNlbGYiLCJzdG9yYWdlS2V5cyIsIk9iamVjdCIsImtleXMiLCJhc3luYyIsImVhY2hTZXJpZXMiLCJzdG9yYWdlIiwicG9zaXRpb24iLCJiYXNlMiIsImpvaW4iLCJzdG9yYWdlUGF0aCIsImZzIiwicmVhZGRpciIsImVyciIsImZpbGVzIiwiZmlsZSIsImluY2x1ZGVzIiwibWF0Y2giLCJmaWxlTG9jYXRpb24iLCJmaWxlMiIsInBhY2thZ2VQYXRoIiwic3RhdCIsInN0YXRzIiwiXyIsImlzTmlsIiwiaXRlbSIsInRpbWUiLCJtdGltZSIsImdldFRpbWUiLCJfZ2V0VGltZSIsInJlbW92ZSIsImdldCIsImVycm9yIiwicGtnTmFtZSIsInNwbGljZSIsInRvdGFsSXRlbXMiLCJsZW5ndGgiLCJnZXRQYWNrYWdlU3RvcmFnZSIsInBhY2thZ2VOYW1lIiwicGFja2FnZUFjY2VzcyIsImdldE1hdGNoZWRQYWNrYWdlc1NwZWMiLCJfZ2V0TG9jYWxTdG9yYWdlUGF0aCIsInVuZGVmaW5lZCIsImlzU3RyaW5nIiwicGFja2FnZVN0b3JhZ2VQYXRoIiwiTG9jYWxEcml2ZXIiLCJjbGVhbiIsInNhdmVUb2tlbiIsInRva2VuIiwia2V5IiwiX2dldFRva2VuS2V5IiwiZGIiLCJnZXRUb2tlbkRiIiwicmVqZWN0IiwicHV0IiwiZGVsZXRlVG9rZW4iLCJ1c2VyIiwidG9rZW5LZXkiLCJfY29tcG91bmRUb2tlbktleSIsImRlbCIsInJlYWRUb2tlbnMiLCJmaWx0ZXIiLCJ0b2tlbnMiLCJzdHJlYW0iLCJjcmVhdGVSZWFkU3RyZWFtIiwiZ3RlIiwibHRlIiwiU3RyaW5nIiwiZnJvbUNoYXJDb2RlIiwiY2hhckNvZGVBdCIsIm9uIiwidmFsdWUiLCJvbmNlIiwicGFja2FnZXMiLCJsaXN0UGFja2FnZXNDb25mIiwibWFwIiwicGtnIiwiRXJyb3IiLCJmb2xkZXJOYW1lIiwibWtkaXJwIiwic3luYyIsIndyaXRlRmlsZVN5bmMiLCJnbG9iYWxDb25maWdTdG9yYWdlIiwic2lub3BpYWRiUGF0aCIsIl9kYkdlblBhdGgiLCJhY2Nlc3NTeW5jIiwiY29uc3RhbnRzIiwiRl9PSyIsImNvZGUiLCJub1N1Y2hGaWxlIiwiZGJOYW1lIiwiZW1wdHlEYXRhYmFzZSIsIm1lc3NhZ2UiLCJ0b2tlbkRiIiwidmFsdWVFbmNvZGluZyJdLCJtYXBwaW5ncyI6Ijs7Ozs7OztBQUFBOztBQUNBOztBQUdBOztBQUNBOztBQUNBOztBQVlBOztBQUNBOztBQUVBOztBQUNBOzs7Ozs7Ozs7O0FBRUEsTUFBTUEsa0JBQWtCLEdBQUcsa0JBQTNCO0FBQ0EsTUFBTUMsT0FBTyxHQUFHLG9CQUFoQjtBQUNBLE1BQU1DLGFBQWEsR0FBRyxXQUF0Qjs7QUFZQTs7O0FBR0EsTUFBTUMsYUFBTixDQUFrRDtBQVFoRDs7OztBQUlPQyxFQUFBQSxXQUFQLENBQW1CQyxNQUFuQixFQUFtQ0MsTUFBbkMsRUFBbUQ7QUFBQTs7QUFBQTs7QUFBQTs7QUFBQTs7QUFBQTs7QUFBQTs7QUFDakQsU0FB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VCxVQUFMLENBQWdCeEgsYUFBaEIsRUFBK0IsS0FBS0csTUFBcEMsQ0FBTixFQUFtRDtBQUNoRStILFFBQUFBLGFBQWEsRUFBRTtBQURpRCxPQUFuRCxDQUFmO0FBR0Q7O0FBRUQsV0FBTyxLQUFLRCxPQUFaO0FBQ0Q7O0FBRU8zQyxFQUFBQSxZQUFSLENBQXFCRixLQUFyQixFQUEyQztBQUN6QyxVQUFNO0FBQUVRLE1BQUFBLElBQUY7QUFBUVAsTUFBQUE7QUFBUixRQUFnQkQsS0FBdEI7QUFDQSxXQUFPLEtBQUtVLGlCQUFMLENBQXVCRixJQUF2QixFQUE2QlAsR0FBN0IsQ0FBUDtBQUNEOztBQUVPUyxFQUFBQSxpQkFBUixDQUEwQkYsSUFBMUIsRUFBd0NQLEdBQXhDLEVBQTZEO0FBQzNELFdBQVEsR0FBRU8sSUFBSyxJQUFHUCxHQUFJLEVBQXRCO0FBQ0Q7O0FBelorQzs7ZUE0Wm5DcEYsYSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBmcyBmcm9tICdmcyc7XG5pbXBvcnQgUGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCBzdHJlYW0gZnJvbSAnc3RyZWFtJztcblxuaW1wb3J0IF8gZnJvbSAnbG9kYXNoJztcbmltcG9ydCBhc3luYyBmcm9tICdhc3luYyc7XG5pbXBvcnQgbWtkaXJwIGZyb20gJ21rZGlycCc7XG5pbXBvcnQge1xuICBDYWxsYmFjayxcbiAgQ29uZmlnLFxuICBJUGFja2FnZVN0b3JhZ2UsXG4gIElQbHVnaW5TdG9yYWdlLFxuICBMb2NhbFN0b3JhZ2UsXG4gIExvZ2dlcixcbiAgU3RvcmFnZUxpc3QsXG4gIFRva2VuLFxuICBUb2tlbkZpbHRlcixcbn0gZnJvbSAnQHZlcmRhY2Npby90eXBlcyc7XG5pbXBvcnQgbGV2ZWwgZnJvbSAnbGV2ZWwnO1xuaW1wb3J0IHsgZ2V0SW50ZXJuYWxFcnJvciB9IGZyb20gJ0B2ZXJkYWNjaW8vY29tbW9ucy1hcGkvbGliJztcblxuaW1wb3J0IExvY2FsRHJpdmVyLCB7IG5vU3VjaEZpbGUgfSBmcm9tICcuL2xvY2FsLWZzJztcbmltcG9ydCB7IGxvYWRQcml2YXRlUGFja2FnZXMgfSBmcm9tICcuL3BrZy11dGlscyc7XG5cbmNvbnN0IERFUFJFQ0FURURfREJfTkFNRSA9ICcuc2lub3BpYS1kYi5qc29uJztcbmNvbnN0IERCX05BTUUgPSAnLnZlcmRhY2Npby1kYi5qc29uJztcbmNvbnN0IFRPS0VOX0RCX05BTUUgPSAnLnRva2VuLWRiJztcblxuaW50ZXJmYWNlIExldmVsIHtcbiAgcHV0KGtleTogc3RyaW5nLCB0b2tlbiwgZm4/OiBGdW5jdGlvbik6IHZvaWQ7XG5cbiAgZ2V0KGtleTogc3RyaW5nLCBmbj86IEZ1bmN0aW9uKTogdm9pZDtcblxuICBkZWwoa2V5OiBzdHJpbmcsIGZuPzogRnVuY3Rpb24pOiB2b2lkO1xuXG4gIGNyZWF0ZVJlYWRTdHJlYW0ob3B0aW9ucz86IG9iamVjdCk6IHN0cmVhbS5SZWFkYWJsZTtcbn1cblxuLyoqXG4gKiBIYW5kbGUgbG9jYWwgZGF0YWJhc2UuXG4gKi9cbmNsYXNzIExvY2FsRGF0YWJhc2UgaW1wbGVtZW50cyBJUGx1Z2luU3RvcmFnZTx7fT4ge1xuICBwdWJsaWMgcGF0aDogc3RyaW5nO1xuICBwdWJsaWMgbG9nZ2VyOiBMb2dnZXI7XG4gIHB1YmxpYyBkYXRhOiBMb2NhbFN0b3JhZ2U7XG4gIHB1YmxpYyBjb25maWc6IENvbmZpZztcbiAgcHVibGljIGxvY2tlZDogYm9vbGVhbjtcbiAgcHVibGljIHRva2VuRGI7XG5cbiAgLyoqXG4gICAqIExvYWQgYW4gcGFyc2UgdGhlIGxvY2FsIGpzb24gZGF0YWJhc2UuXG4gICAqIEBwYXJhbSB7Kn0gcGF0aCB0aGUgZGF0YWJhc2UgcGF0aFxuICAgKi9cbiAgcHVibGljIGNvbnN0cnVjdG9yKGNvbmZpZzogQ29uZmlnLCBsb2dnZXI6IExvZ2dlcikge1xuICAgIHRoaXMuY29uZmlnID0gY29uZmlnO1xuICAgIHRoaXMucGF0aCA9IHRoaXMuX2J1aWxkU3RvcmFnZVBhdGgoY29uZmlnKTtcbiAgICB0aGlzLmxvZ2dlciA9IGxvZ2dlcjtcbiAgICB0aGlzLmxvY2tlZCA9IGZhbHNlO1xuICAgIHRoaXMuZGF0YSA9IHRoaXMuX2ZldGNoTG9jYWxQYWNrYWdlcygpO1xuXG4gICAgdGhpcy5sb2dnZXIudHJhY2UoeyBjb25maWc6IHRoaXMuY29uZmlnIH0sICdbbG9jYWwtc3RvcmFnZV06IGNvbmZpZ3VyYXRpb246IEB7Y29uZmlnfScpO1xuXG4gICAgdGhpcy5fc3luYygpO1xuICB9XG5cbiAgcHVibGljIGdldFNlY3JldCgpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUodGhpcy5kYXRhLnNlY3JldCk7XG4gIH1cblxuICBwdWJsaWMgc2V0U2VjcmV0KHNlY3JldDogc3RyaW5nKTogUHJvbWlzZTxFcnJvciB8IG51bGw+IHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUpOiB2b2lkID0+IHtcbiAgICAgIHRoaXMuZGF0YS5zZWNyZXQgPSBzZWNyZXQ7XG5cbiAgICAgIHJlc29sdmUodGhpcy5fc3luYygpKTtcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGQgYSBuZXcgZWxlbWVudC5cbiAgICogQHBhcmFtIHsqfSBuYW1lXG4gICAqIEByZXR1cm4ge0Vycm9yfCp9XG4gICAqL1xuICBwdWJsaWMgYWRkKG5hbWU6IHN0cmluZywgY2I6IENhbGxiYWNrKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuZGF0YS5saXN0LmluZGV4T2YobmFtZSkgPT09IC0xKSB7XG4gICAgICB0aGlzLmRhdGEubGlzdC5wdXNoKG5hbWUpO1xuXG4gICAgICB0aGlzLmxvZ2dlci5kZWJ1Zyh7IG5hbWUgfSwgJ1tsb2NhbC1zdG9yYWdlXTogdGhlIHByaXZhdGUgcGFja2FnZSBAe25hbWV9IGhhcyBiZWVuIGFkZGVkJyk7XG4gICAgICBjYih0aGlzLl9zeW5jKCkpO1xuICAgIH0gZWxzZSB7XG4gICAgICBjYihudWxsKTtcbiAgICB9XG4gIH1cblxuICBwdWJsaWMgc2VhcmNoKG9uUGFja2FnZTogQ2FsbGJhY2ssIG9uRW5kOiBDYWxsYmFjaywgdmFsaWRhdGVOYW1lOiAobmFtZTogc3RyaW5nKSA9PiBib29sZWFuKTogdm9pZCB7XG4gICAgY29uc3Qgc3RvcmFnZXMgPSB0aGlzLl9nZXRDdXN0b21QYWNrYWdlTG9jYWxTdG9yYWdlcygpO1xuICAgIHRoaXMubG9nZ2VyLnRyYWNlKGBsb2NhbC1zdG9yYWdlOiBbc2VhcmNoXTogJHtKU09OLnN0cmluZ2lmeShzdG9yYWdlcyl9YCk7XG4gICAgY29uc3QgYmFzZSA9IFBhdGguZGlybmFtZSh0aGlzLmNvbmZpZy5zZWxmX3BhdGgpO1xuICAgIGNvbnN0IHNlbGYgPSB0aGlzO1xuICAgIGNvbnN0IHN0b3JhZ2VLZXlzID0gT2JqZWN0LmtleXMoc3RvcmFnZXMpO1xuICAgIHRoaXMubG9nZ2VyLnRyYWNlKGBsb2NhbC1zdG9yYWdlOiBbc2VhcmNoXSBiYXNlOiAke2Jhc2V9IGtleXMgJHtzdG9yYWdlS2V5c31gKTtcblxuICAgIGFzeW5jLmVhY2hTZXJpZXMoXG4gICAgICBzdG9yYWdlS2V5cyxcbiAgICAgIGZ1bmN0aW9uKHN0b3JhZ2UsIGNiKSB7XG4gICAgICAgIGNvbnN0IHBvc2l0aW9uID0gc3RvcmFnZUtleXMuaW5kZXhPZihzdG9yYWdlKTtcbiAgICAgICAgY29uc3QgYmFzZTIgPSBQYXRoLmpvaW4ocG9zaXRpb24gIT09IDAgPyBzdG9yYWdlS2V5c1swXSA6ICcnKTtcbiAgICAgICAgY29uc3Qgc3RvcmFnZVBhdGg6IHN0cmluZyA9IFBhdGgucmVzb2x2ZShiYXNlLCBiYXNlMiwgc3RvcmFnZSk7XG4gICAgICAgIHNlbGYubG9nZ2VyLnRyYWNlKHsgc3RvcmFnZVBhdGgsIHN0b3JhZ2UgfSwgJ2xvY2FsLXN0b3JhZ2U6IFtzZWFyY2hdIHNlYXJjaCBwYXRoOiBAe3N0b3JhZ2VQYXRofSA6IEB7c3RvcmFnZX0nKTtcbiAgICAgICAgZnMucmVhZGRpcihzdG9yYWdlUGF0aCwgKGVyciwgZmlsZXMpID0+IHtcbiAgICAgICAgICBpZiAoZXJyKSB7XG4gICAgICAgICAgICByZXR1cm4gY2IoZXJyKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBhc3luYy5lYWNoU2VyaWVzKFxuICAgICAgICAgICAgZmlsZXMsXG4gICAgICAgICAgICBmdW5jdGlvbihmaWxlLCBjYikge1xuICAgICAgICAgICAgICBzZWxmLmxvZ2dlci50cmFjZSh7IGZpbGUgfSwgJ2xvY2FsLXN0b3JhZ2U6IFtzZWFyY2hdIHNlYXJjaCBmaWxlIHBhdGg6IEB7ZmlsZX0nKTtcbiAgICAgICAgICAgICAgaWYgKHN0b3JhZ2VLZXlzLmluY2x1ZGVzKGZpbGUpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGNiKCk7XG4gICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICBpZiAoZmlsZS5tYXRjaCgvXkAvKSkge1xuICAgICAgICAgICAgICAgIC8vIHNjb3BlZFxuICAgICAgICAgICAgICAgIGNvbnN0IGZpbGVMb2NhdGlvbiA9IFBhdGgucmVzb2x2ZShiYXNlLCBzdG9yYWdlLCBmaWxlKTtcbiAgICAgICAgICAgICAgICBzZWxmLmxvZ2dlci50cmFjZShcbiAgICAgICAgICAgICAgICAgIHsgZmlsZUxvY2F0aW9uIH0sXG4gICAgICAgICAgICAgICAgICAnbG9jYWwtc3RvcmFnZTogW3NlYXJjaF0gc2VhcmNoIHNjb3BlZCBmaWxlIGxvY2F0aW9uOiBAe2ZpbGVMb2NhdGlvbn0nXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICBmcy5yZWFkZGlyKGZpbGVMb2NhdGlvbiwgZnVuY3Rpb24oZXJyLCBmaWxlcykge1xuICAgICAgICAgICAgICAgICAgaWYgKGVycikge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gY2IoZXJyKTtcbiAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgYXN5bmMuZWFjaFNlcmllcyhcbiAgICAgICAgICAgICAgICAgICAgZmlsZXMsXG4gICAgICAgICAgICAgICAgICAgIChmaWxlMiwgY2IpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICBpZiAodmFsaWRhdGVOYW1lKGZpbGUyKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgcGFja2FnZVBhdGggPSBQYXRoLnJlc29sdmUoYmFzZSwgc3RvcmFnZSwgZmlsZSwgZmlsZTIpO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICBmcy5zdGF0KHBhY2thZ2VQYXRoLCAoZXJyLCBzdGF0cykgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoXy5pc05pbChlcnIpID09PSBmYWxzZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBjYihlcnIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGl0ZW0gPSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZTogYCR7ZmlsZX0vJHtmaWxlMn1gLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdGg6IHBhY2thZ2VQYXRoLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpbWU6IHN0YXRzLm10aW1lLmdldFRpbWUoKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgb25QYWNrYWdlKGl0ZW0sIGNiKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjYigpO1xuICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgY2JcbiAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgIH0gZWxzZSBpZiAodmFsaWRhdGVOYW1lKGZpbGUpKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgYmFzZTIgPSBQYXRoLmpvaW4ocG9zaXRpb24gIT09IDAgPyBzdG9yYWdlS2V5c1swXSA6ICcnKTtcbiAgICAgICAgICAgICAgICBjb25zdCBwYWNrYWdlUGF0aCA9IFBhdGgucmVzb2x2ZShiYXNlLCBiYXNlMiwgc3RvcmFnZSwgZmlsZSk7XG4gICAgICAgICAgICAgICAgc2VsZi5sb2dnZXIudHJhY2UoeyBwYWNrYWdlUGF0aCB9LCAnbG9jYWwtc3RvcmFnZTogW3NlYXJjaF0gc2VhcmNoIGZpbGUgbG9jYXRpb246IEB7cGFja2FnZVBhdGh9Jyk7XG4gICAgICAgICAgICAgICAgZnMuc3RhdChwYWNrYWdlUGF0aCwgKGVyciwgc3RhdHMpID0+IHtcbiAgICAgICAgICAgICAgICAgIGlmIChfLmlzTmlsKGVycikgPT09IGZhbHNlKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBjYihlcnIpO1xuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgb25QYWNrYWdlKFxuICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgbmFtZTogZmlsZSxcbiAgICAgICAgICAgICAgICAgICAgICBwYXRoOiBwYWNrYWdlUGF0aCxcbiAgICAgICAgICAgICAgICAgICAgICB0aW1lOiBzZWxmLl9nZXRUaW1lKHN0YXRzLm10aW1lLmdldFRpbWUoKSwgc3RhdHMubXRpbWUpLFxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICBjYlxuICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBjYigpO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgY2JcbiAgICAgICAgICApO1xuICAgICAgICB9KTtcbiAgICAgIH0sXG4gICAgICBvbkVuZFxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogUmVtb3ZlIGFuIGVsZW1lbnQgZnJvbSB0aGUgZGF0YWJhc2UuXG4gICAqIEBwYXJhbSB7Kn0gbmFtZVxuICAgKiBAcmV0dXJuIHtFcnJvcnwqfVxuICAgKi9cbiAgcHVibGljIHJlbW92ZShuYW1lOiBzdHJpbmcsIGNiOiBDYWxsYmFjayk6IHZvaWQge1xuICAgIHRoaXMuZ2V0KChlcnIsIGRhdGEpID0+IHtcbiAgICAgIGlmIChlcnIpIHtcbiAgICAgICAgY2IoZ2V0SW50ZXJuYWxFcnJvcignZXJyb3IgcmVtb3ZlIHByaXZhdGUgcGFja2FnZScpKTtcbiAgICAgICAgdGhpcy5sb2dnZXIuZXJyb3IoeyBlcnIgfSwgJ1tsb2NhbC1zdG9yYWdlL3JlbW92ZV06IHJlbW92ZSB0aGUgcHJpdmF0ZSBwYWNrYWdlIGhhcyBmYWlsZWQgQHtlcnJ9Jyk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHBrZ05hbWUgPSBkYXRhLmluZGV4T2YobmFtZSk7XG4gICAgICBpZiAocGtnTmFtZSAhPT0gLTEpIHtcbiAgICAgICAgdGhpcy5kYXRhLmxpc3Quc3BsaWNlKHBrZ05hbWUsIDEpO1xuXG4gICAgICAgIHRoaXMubG9nZ2VyLnRyYWNlKHsgbmFtZSB9LCAnbG9jYWwtc3RvcmFnZTogW3JlbW92ZV0gcGFja2FnZSBAe25hbWV9IGhhcyBiZWVuIHJlbW92ZWQnKTtcbiAgICAgIH1cblxuICAgICAgY2IodGhpcy5fc3luYygpKTtcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm4gYWxsIGRhdGFiYXNlIGVsZW1lbnRzLlxuICAgKiBAcmV0dXJuIHtBcnJheX1cbiAgICovXG4gIHB1YmxpYyBnZXQoY2I6IENhbGxiYWNrKTogdm9pZCB7XG4gICAgY29uc3QgbGlzdCA9IHRoaXMuZGF0YS5saXN0O1xuICAgIGNvbnN0IHRvdGFsSXRlbXMgPSB0aGlzLmRhdGEubGlzdC5sZW5ndGg7XG5cbiAgICBjYihudWxsLCBsaXN0KTtcblxuICAgIHRoaXMubG9nZ2VyLnRyYWNlKHsgdG90YWxJdGVtcyB9LCAnbG9jYWwtc3RvcmFnZTogW2dldF0gZnVsbCBsaXN0IG9mIHBhY2thZ2VzIChAe3RvdGFsSXRlbXN9KSBoYXMgYmVlbiBmZXRjaGVkJyk7XG4gIH1cblxuICBwdWJsaWMgZ2V0UGFja2FnZVN0b3JhZ2UocGFja2FnZU5hbWU6IHN0cmluZyk6IElQYWNrYWdlU3RvcmFnZSB7XG4gICAgY29uc3QgcGFja2FnZUFjY2VzcyA9IHRoaXMuY29uZmlnLmdldE1hdGNoZWRQYWNrYWdlc1NwZWMocGFja2FnZU5hbWUpO1xuXG4gICAgY29uc3QgcGFja2FnZVBhdGg6IHN0cmluZyA9IHRoaXMuX2dldExvY2FsU3RvcmFnZVBhdGgocGFja2FnZUFjY2VzcyA/IHBhY2thZ2VBY2Nlc3Muc3RvcmFnZSA6IHVuZGVmaW5lZCk7XG4gICAgdGhpcy5sb2dnZXIudHJhY2UoeyBwYWNrYWdlUGF0aCB9LCAnW2xvY2FsLXN0b3JhZ2UvZ2V0UGFja2FnZVN0b3JhZ2VdOiBzdG9yYWdlIHNlbGVjdGVkOiBAe3BhY2thZ2VQYXRofScpO1xuXG4gICAgaWYgKF8uaXNTdHJpbmcocGFja2FnZVBhdGgpID09PSBmYWxzZSkge1xuICAgICAgdGhpcy5sb2dnZXIuZGVidWcoeyBuYW1lOiBwYWNrYWdlTmFtZSB9LCAndGhpcyBwYWNrYWdlIGhhcyBubyBzdG9yYWdlIGRlZmluZWQ6IEB7bmFtZX0nKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBwYWNrYWdlU3RvcmFnZVBhdGg6IHN0cmluZyA9IFBhdGguam9pbihcbiAgICAgIFBhdGgucmVzb2x2ZShQYXRoLmRpcm5hbWUodGhpcy5jb25maWcuc2VsZl9wYXRoIHx8ICcnKSwgcGFja2FnZVBhdGgpLFxuICAgICAgcGFja2FnZU5hbWVcbiAgICApO1xuXG4gICAgdGhpcy5sb2dnZXIudHJhY2UoeyBwYWNrYWdlU3RvcmFnZVBhdGggfSwgJ1tsb2NhbC1zdG9yYWdlL2dldFBhY2thZ2VTdG9yYWdlXTogc3RvcmFnZSBwYXRoOiBAe3BhY2thZ2VTdG9yYWdlUGF0aH0nKTtcblxuICAgIHJldHVybiBuZXcgTG9jYWxEcml2ZXIocGFja2FnZVN0b3JhZ2VQYXRoLCB0aGlzLmxvZ2dlcik7XG4gIH1cblxuICBwdWJsaWMgY2xlYW4oKTogdm9pZCB7XG4gICAgdGhpcy5fc3luYygpO1xuICB9XG5cbiAgcHVibGljIHNhdmVUb2tlbih0b2tlbjogVG9rZW4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCBrZXkgPSB0aGlzLl9nZXRUb2tlbktleSh0b2tlbik7XG4gICAgY29uc3QgZGIgPSB0aGlzLmdldFRva2VuRGIoKTtcblxuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KTogdm9pZCA9PiB7XG4gICAgICBkYi5wdXQoa2V5LCB0b2tlbiwgZXJyID0+IHtcbiAgICAgICAgaWYgKGVycikge1xuICAgICAgICAgIHJlamVjdChlcnIpO1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICByZXNvbHZlKCk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuXG4gIHB1YmxpYyBkZWxldGVUb2tlbih1c2VyOiBzdHJpbmcsIHRva2VuS2V5OiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCBrZXkgPSB0aGlzLl9jb21wb3VuZFRva2VuS2V5KHVzZXIsIHRva2VuS2V5KTtcbiAgICBjb25zdCBkYiA9IHRoaXMuZ2V0VG9rZW5EYigpO1xuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KTogdm9pZCA9PiB7XG4gICAgICBkYi5kZWwoa2V5LCBlcnIgPT4ge1xuICAgICAgICBpZiAoZXJyKSB7XG4gICAgICAgICAgcmVqZWN0KGVycik7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHJlc29sdmUoKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9XG5cbiAgcHVibGljIHJlYWRUb2tlbnMoZmlsdGVyOiBUb2tlbkZpbHRlcik6IFByb21pc2U8VG9rZW5bXT4ge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KTogdm9pZCA9PiB7XG4gICAgICBjb25zdCB0b2tlbnM6IFRva2VuW10gPSBbXTtcbiAgICAgIGNvbnN0IGtleSA9IGZpbHRlci51c2VyICsgJzonO1xuICAgICAgY29uc3QgZGIgPSB0aGlzLmdldFRva2VuRGIoKTtcbiAgICAgIGNvbnN0IHN0cmVhbSA9IGRiLmNyZWF0ZVJlYWRTdHJlYW0oe1xuICAgICAgICBndGU6IGtleSxcbiAgICAgICAgbHRlOiBTdHJpbmcuZnJvbUNoYXJDb2RlKGtleS5jaGFyQ29kZUF0KDApICsgMSksXG4gICAgICB9KTtcblxuICAgICAgc3RyZWFtLm9uKCdkYXRhJywgZGF0YSA9PiB7XG4gICAgICAgIHRva2Vucy5wdXNoKGRhdGEudmFsdWUpO1xuICAgICAgfSk7XG5cbiAgICAgIHN0cmVhbS5vbmNlKCdlbmQnLCAoKSA9PiByZXNvbHZlKHRva2VucykpO1xuXG4gICAgICBzdHJlYW0ub25jZSgnZXJyb3InLCBlcnIgPT4gcmVqZWN0KGVycikpO1xuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBfZ2V0VGltZSh0aW1lOiBudW1iZXIsIG10aW1lOiBEYXRlKTogbnVtYmVyIHwgRGF0ZSB7XG4gICAgcmV0dXJuIHRpbWUgPyB0aW1lIDogbXRpbWU7XG4gIH1cblxuICBwcml2YXRlIF9nZXRDdXN0b21QYWNrYWdlTG9jYWxTdG9yYWdlcygpOiBvYmplY3Qge1xuICAgIGNvbnN0IHN0b3JhZ2VzID0ge307XG5cbiAgICAvLyBhZGQgY3VzdG9tIHN0b3JhZ2UgaWYgZXhpc3RcbiAgICBpZiAodGhpcy5jb25maWcuc3RvcmFnZSkge1xuICAgICAgc3RvcmFnZXNbdGhpcy5jb25maWcuc3RvcmFnZV0gPSB0cnVlO1xuICAgIH1cblxuICAgIGNvbnN0IHsgcGFja2FnZXMgfSA9IHRoaXMuY29uZmlnO1xuXG4gICAgaWYgKHBhY2thZ2VzKSB7XG4gICAgICBjb25zdCBsaXN0UGFja2FnZXNDb25mID0gT2JqZWN0LmtleXMocGFja2FnZXMgfHwge30pO1xuXG4gICAgICBsaXN0UGFja2FnZXNDb25mLm1hcChwa2cgPT4ge1xuICAgICAgICBjb25zdCBzdG9yYWdlID0gcGFja2FnZXNbcGtnXS5zdG9yYWdlO1xuICAgICAgICBpZiAoc3RvcmFnZSkge1xuICAgICAgICAgIHN0b3JhZ2VzW3N0b3JhZ2VdID0gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH1cblxuICAgIHJldHVybiBzdG9yYWdlcztcbiAgfVxuXG4gIC8qKlxuICAgKiBTeW5jcm9uaXplIHtjcmVhdGV9IGRhdGFiYXNlIHdoZXRoZXIgZG9lcyBub3QgZXhpc3QuXG4gICAqIEByZXR1cm4ge0Vycm9yfCp9XG4gICAqL1xuICBwcml2YXRlIF9zeW5jKCk6IEVycm9yIHwgbnVsbCB7XG4gICAgdGhpcy5sb2dnZXIuZGVidWcoJ1tsb2NhbC1zdG9yYWdlL19zeW5jXTogaW5pdCBzeW5jIGRhdGFiYXNlJyk7XG5cbiAgICBpZiAodGhpcy5sb2NrZWQpIHtcbiAgICAgIHRoaXMubG9nZ2VyLmVycm9yKCdEYXRhYmFzZSBpcyBsb2NrZWQsIHBsZWFzZSBjaGVjayBlcnJvciBtZXNzYWdlIHByaW50ZWQgZHVyaW5nIHN0YXJ0dXAgdG8gcHJldmVudCBkYXRhIGxvc3MuJyk7XG4gICAgICByZXR1cm4gbmV3IEVycm9yKFxuICAgICAgICAnVmVyZGFjY2lvIGRhdGFiYXNlIGlzIGxvY2tlZCwgcGxlYXNlIGNvbnRhY3QgeW91ciBhZG1pbmlzdHJhdG9yIHRvIGNoZWNrb3V0IGxvZ3MgZHVyaW5nIHZlcmRhY2NpbyBzdGFydHVwLidcbiAgICAgICk7XG4gICAgfVxuICAgIC8vIFVzZXMgc3luYyB0byBwcmV2ZW50IHVnbHkgcmFjZSBjb25kaXRpb25cbiAgICB0cnkge1xuICAgICAgLy8gaHR0cHM6Ly93d3cubnBtanMuY29tL3BhY2thZ2UvbWtkaXJwI21rZGlycHN5bmNkaXItb3B0c1xuICAgICAgY29uc3QgZm9sZGVyTmFtZSA9IFBhdGguZGlybmFtZSh0aGlzLnBhdGgpO1xuICAgICAgbWtkaXJwLnN5bmMoZm9sZGVyTmFtZSk7XG4gICAgICB0aGlzLmxvZ2dlci5kZWJ1Zyh7IGZvbGRlck5hbWUgfSwgJ1tsb2NhbC1zdG9yYWdlL19zeW5jXTogZm9sZGVyIEB7Zm9sZGVyTmFtZX0gY3JlYXRlZCBzdWNjZWVkJyk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAvLyBwZXJoYXBzIGEgbG9nZ2VyIGluc3RhbmNlP1xuICAgICAgdGhpcy5sb2dnZXIuZGVidWcoeyBlcnIgfSwgJ1tsb2NhbC1zdG9yYWdlL19zeW5jL21rZGlycC5zeW5jXTogc3luYyBmYWlsZWQgQHtlcnJ9Jyk7XG5cbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIHRyeSB7XG4gICAgICBmcy53cml0ZUZpbGVTeW5jKHRoaXMucGF0aCwgSlNPTi5zdHJpbmdpZnkodGhpcy5kYXRhKSk7XG4gICAgICB0aGlzLmxvZ2dlci5kZWJ1ZygnW2xvY2FsLXN0b3JhZ2UvX3N5bmMvd3JpdGVGaWxlU3luY106IHN5bmMgd3JpdGUgc3VjY2VlZCcpO1xuXG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIHRoaXMubG9nZ2VyLmRlYnVnKHsgZXJyIH0sICdbbG9jYWwtc3RvcmFnZS9fc3luYy93cml0ZUZpbGVTeW5jXTogc3luYyBmYWlsZWQgQHtlcnJ9Jyk7XG5cbiAgICAgIHJldHVybiBlcnI7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFZlcmlmeSB0aGUgcmlnaHQgbG9jYWwgc3RvcmFnZSBsb2NhdGlvbi5cbiAgICogQHBhcmFtIHtTdHJpbmd9IHBhdGhcbiAgICogQHJldHVybiB7U3RyaW5nfVxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgcHJpdmF0ZSBfZ2V0TG9jYWxTdG9yYWdlUGF0aChzdG9yYWdlOiBzdHJpbmcgfCB2b2lkKTogc3RyaW5nIHtcbiAgICBjb25zdCBnbG9iYWxDb25maWdTdG9yYWdlID0gdGhpcy5jb25maWcgPyB0aGlzLmNvbmZpZy5zdG9yYWdlIDogdW5kZWZpbmVkO1xuICAgIGlmIChfLmlzTmlsKGdsb2JhbENvbmZpZ1N0b3JhZ2UpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2dsb2JhbCBzdG9yYWdlIGlzIHJlcXVpcmVkIGZvciB0aGlzIHBsdWdpbicpO1xuICAgIH0gZWxzZSB7XG4gICAgICBpZiAoXy5pc05pbChzdG9yYWdlKSA9PT0gZmFsc2UgJiYgXy5pc1N0cmluZyhzdG9yYWdlKSkge1xuICAgICAgICByZXR1cm4gUGF0aC5qb2luKGdsb2JhbENvbmZpZ1N0b3JhZ2UgYXMgc3RyaW5nLCBzdG9yYWdlIGFzIHN0cmluZyk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBnbG9iYWxDb25maWdTdG9yYWdlIGFzIHN0cmluZztcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQnVpbGQgdGhlIGxvY2FsIGRhdGFiYXNlIHBhdGguXG4gICAqIEBwYXJhbSB7T2JqZWN0fSBjb25maWdcbiAgICogQHJldHVybiB7c3RyaW5nfFN0cmluZ3wqfVxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgcHJpdmF0ZSBfYnVpbGRTdG9yYWdlUGF0aChjb25maWc6IENvbmZpZyk6IHN0cmluZyB7XG4gICAgY29uc3Qgc2lub3BpYWRiUGF0aDogc3RyaW5nID0gdGhpcy5fZGJHZW5QYXRoKERFUFJFQ0FURURfREJfTkFNRSwgY29uZmlnKTtcbiAgICB0cnkge1xuICAgICAgZnMuYWNjZXNzU3luYyhzaW5vcGlhZGJQYXRoLCBmcy5jb25zdGFudHMuRl9PSyk7XG4gICAgICByZXR1cm4gc2lub3BpYWRiUGF0aDtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIGlmIChlcnIuY29kZSA9PT0gbm9TdWNoRmlsZSkge1xuICAgICAgICByZXR1cm4gdGhpcy5fZGJHZW5QYXRoKERCX05BTUUsIGNvbmZpZyk7XG4gICAgICB9XG5cbiAgICAgIHRocm93IGVycjtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIF9kYkdlblBhdGgoZGJOYW1lOiBzdHJpbmcsIGNvbmZpZzogQ29uZmlnKTogc3RyaW5nIHtcbiAgICByZXR1cm4gUGF0aC5qb2luKFBhdGgucmVzb2x2ZShQYXRoLmRpcm5hbWUoY29uZmlnLnNlbGZfcGF0aCB8fCAnJyksIGNvbmZpZy5zdG9yYWdlIGFzIHN0cmluZywgZGJOYW1lKSk7XG4gIH1cblxuICAvKipcbiAgICogRmV0Y2ggbG9jYWwgcGFja2FnZXMuXG4gICAqIEBwcml2YXRlXG4gICAqIEByZXR1cm4ge09iamVjdH1cbiAgICovXG4gIHByaXZhdGUgX2ZldGNoTG9jYWxQYWNrYWdlcygpOiBMb2NhbFN0b3JhZ2Uge1xuICAgIGNvbnN0IGxpc3Q6IFN0b3JhZ2VMaXN0ID0gW107XG4gICAgY29uc3QgZW1wdHlEYXRhYmFzZSA9IHsgbGlzdCwgc2VjcmV0OiAnJyB9O1xuXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGRiID0gbG9hZFByaXZhdGVQYWNrYWdlcyh0aGlzLnBhdGgsIHRoaXMubG9nZ2VyKTtcblxuICAgICAgcmV0dXJuIGRiO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgLy8gcmVhZEZpbGVTeW5jIGlzIHBsYXRmb3JtIHNwZWNpZmljLCBtYWNPUywgTGludXggYW5kIFdpbmRvd3MgdGhyb3duIGFuIGVycm9yXG4gICAgICAvLyBPbmx5IHJlY3JlYXRlIGlmIGZpbGUgbm90IGZvdW5kIHRvIHByZXZlbnQgZGF0YSBsb3NzXG4gICAgICBpZiAoZXJyLmNvZGUgIT09IG5vU3VjaEZpbGUpIHtcbiAgICAgICAgdGhpcy5sb2NrZWQgPSB0cnVlO1xuICAgICAgICB0aGlzLmxvZ2dlci5lcnJvcihcbiAgICAgICAgICAnRmFpbGVkIHRvIHJlYWQgcGFja2FnZSBkYXRhYmFzZSBmaWxlLCBwbGVhc2UgY2hlY2sgdGhlIGVycm9yIHByaW50ZWQgYmVsb3c6XFxuJyxcbiAgICAgICAgICBgRmlsZSBQYXRoOiAke3RoaXMucGF0aH1cXG5cXG4gJHtlcnIubWVzc2FnZX1gXG4gICAgICAgICk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBlbXB0eURhdGFiYXNlO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgZ2V0VG9rZW5EYigpOiBMZXZlbCB7XG4gICAgaWYgKCF0aGlzLnRva2VuRGIpIHtcbiAgICAgIHRoaXMudG9rZW5EYiA9IGxldmVsKHRoaXMuX2RiR2VuUGF0aChUT0tFTl9EQl9OQU1FLCB0aGlzLmNvbmZpZyksIHtcbiAgICAgICAgdmFsdWVFbmNvZGluZzogJ2pzb24nLFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMudG9rZW5EYjtcbiAgfVxuXG4gIHByaXZhdGUgX2dldFRva2VuS2V5KHRva2VuOiBUb2tlbik6IHN0cmluZyB7XG4gICAgY29uc3QgeyB1c2VyLCBrZXkgfSA9IHRva2VuO1xuICAgIHJldHVybiB0aGlzLl9jb21wb3VuZFRva2VuS2V5KHVzZXIsIGtleSk7XG4gIH1cblxuICBwcml2YXRlIF9jb21wb3VuZFRva2VuS2V5KHVzZXI6IHN0cmluZywga2V5OiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIHJldHVybiBgJHt1c2VyfToke2tleX1gO1xuICB9XG59XG5cbmV4cG9ydCBkZWZhdWx0IExvY2FsRGF0YWJhc2U7XG4iXX0=
\No newline at end of file