UNPKG

serverless-webpack-layers

Version:

Plugin for the Serverless framework that offers AWS Lambda layer management using webpack

353 lines (295 loc) 40.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _pascalcase = _interopRequireDefault(require("pascalcase")); var _fs = _interopRequireDefault(require("fs")); var _path = _interopRequireDefault(require("path")); var _del = _interopRequireDefault(require("del")); var _external = require("./external"); var _utils = require("./utils"); var _constants = require("./constants"); var _minifyAllJs = _interopRequireDefault(require("minify-all-js")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _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; } const { LOG_LEVEL = 'info' } = process.env; const DEFAULT_CONFIG = { installLayers: true, exportLayers: true, bulkInstall: false, upgradeLayerReferences: true, exportPrefix: '${AWS::StackName}-', manageNodeFolder: false, packager: 'npm', resolutions: {}, webpack: { clean: true, minify: false, backupFileType: 'js', configPath: './webpack.config.js', discoverModules: true }, productionMode: true }; const LEVELS = { none: 0, info: 1, verbose: 2, debug: 3 }; function log(...s) { console.log('[webpack-layers]', ...s); } function verbose({ level }, ...s) { LEVELS[level] >= LEVELS.verbose && log(...s); } function info({ level }, ...s) { LEVELS[level] >= LEVELS.info && log(...s); } function debug({ level }, ...s) { LEVELS[level] >= LEVELS.debug && log(...s); } function getLayers(serverless) { return serverless.service.layers || {}; } function getConfig(serverless) { const custom = serverless.service.custom || {}; return { ...DEFAULT_CONFIG, ...custom.layerConfig, webpack: { ...DEFAULT_CONFIG.webpack, ...(custom.layerConfig.webpack ?? {}) } }; } class LayerManagerPlugin { constructor(sls, options = {}) { _defineProperty(this, "level", void 0); _defineProperty(this, "hooks", void 0); _defineProperty(this, "config", { webpack: {} }); this.level = options.v || options.verbose ? 'verbose' : LOG_LEVEL; debug(this, `Invoking webpack-layers plugin`); this.init(sls); this.hooks = { 'package:initialize': () => this.installLayers(sls), 'before:deploy:deploy': () => this.transformLayerResources(sls) }; } init(sls) { this.config = getConfig(sls); } async installLayer(sls, layer, layerName) { const { path: localPath } = layer; const layerRefName = `${layerName.replace(/^./, x => x.toUpperCase())}LambdaLayer`; const nodeLayerPath = `${localPath}/nodejs`; const packageJsonPath = _path.default.join(nodeLayerPath, 'package.json'); if (!this.config.manageNodeFolder && !_fs.default.existsSync(nodeLayerPath)) { return false; } if (this.config.manageNodeFolder) { await (0, _del.default)(`${nodeLayerPath}/**`); } if (!_fs.default.existsSync(nodeLayerPath) && this.config.manageNodeFolder) { await _fs.default.promises.mkdir(nodeLayerPath, { recursive: true }); } if (!this.config.webpack) { await _fs.default.promises.copyFile(_path.default.join(process.cwd(), 'package.json'), packageJsonPath); const fileName = _constants.PACKAGER_LOCK_FILE_NAMES[this.config.packager ?? 'npm']; try { await _fs.default.promises.copyFile(_path.default.join(process.cwd(), fileName), _path.default.join(nodeLayerPath, fileName)); } catch { info(this, `Unable to copy ${fileName} across, this will cause version inaccuracies`); } } else if (this.config.manageNodeFolder) { await _fs.default.promises.writeFile(packageJsonPath, '{}'); } verbose(this, `Installing nodejs layer ${localPath} with ${this.config.packager}`); const productionModeFlagEnvironmentAgnostic = process.platform === 'win32' ? 'set NODE_ENV=production &&' : 'NODE_ENV=production'; const productionModeFlag = this.config.productionMode ? productionModeFlagEnvironmentAgnostic : ''; let command = productionModeFlag + _constants.PACKAGER_INSTALL_COMMAND[this.config.packager ?? 'npm']; let installingPackages = false; if (this.config.webpack) { const packages = await (0, _external.getExternalModules)(sls, layerRefName); if (packages.length !== 0) { command = `${productionModeFlag} ${_constants.PACKAGER_ADD_COMMAND[this.config.packager ?? 'npm']} ${packages.join(' ').trim()}`; installingPackages = true; } else { command = 'ls'; } } info(this, `Running command ${command}`); if (this.config.packager === 'yarn' && Object.keys(this.config.resolutions ?? {}).length > 0) { try { const jsonString = await _fs.default.promises.readFile(packageJsonPath, { encoding: 'utf-8' }); const json = JSON.parse(jsonString); json['resolutions'] = this.config.resolutions; await _fs.default.promises.writeFile(packageJsonPath, JSON.stringify(json)); } catch (e) { console.error(`Unable to add resolutions`, e); } } await (0, _utils.exec)(command, { cwd: nodeLayerPath, encoding: null }); if (this.config.packager === 'yarn' && installingPackages) { await (0, _utils.exec)(`yarn autoclean --init`, { cwd: nodeLayerPath, encoding: null }); } return true; } async installLayers(sls) { verbose(this, `Config: `, this.config); const { installLayers, bulkInstall = false } = this.config; if (!installLayers) { verbose(this, `Skipping installation of layers as per config`); return { installedLayers: [] }; } const layers = getLayers(sls); let installedLayers = []; if (bulkInstall) { const attemptedInstallLayers = await Promise.all(Object.entries(layers).map(async ([layerName, layer]) => { if (typeof layer !== 'object') return; const installed = await this.installLayer(sls, layer, layerName); if (!installed) return; await this.delete(sls, layer.path); return layer; })); installedLayers = attemptedInstallLayers.filter(_utils.notEmpty); } else { for (const [layerName, layer] of Object.entries(layers)) { if (typeof layer !== 'object') continue; const installed = await this.installLayer(sls, layer, layerName); if (!installed) continue; await this.delete(sls, layer.path); installedLayers.push(layer); } } info(this, `Installed ${installedLayers.length} layer${installedLayers.length > 1 ? 's' : ''}`); return { installedLayers }; } async delete(sls, folder) { const { clean, minify } = this.config.webpack; if (!clean) return; const nodeLayerPath = `${folder}/nodejs`; const exclude = sls.service?.package?.exclude ?? sls.service?.package?.patterns?.filter(p => p.startsWith('!')).map(p => p.replace(/^!/, '')) ?? []; info(this, `Cleaning ${exclude.map(rule => _path.default.join(nodeLayerPath, rule)).join(', ')}`); const filesDeleted = await (0, _del.default)(exclude.map(rule => _path.default.join(nodeLayerPath, rule))); if (_fs.default.existsSync(nodeLayerPath) && minify) { await (0, _minifyAllJs.default)(nodeLayerPath, { compress_json: true, module: true, mangle: true, packagejson: true }); } info(this, `Cleaned ${filesDeleted.length} files at ${nodeLayerPath}`); } async transformLayerResources(sls) { if (!this.config) { log(this, 'Unable to add layers currently as config unavailable'); return { exportedLayers: [], upgradedLayerReferences: [] }; } const { exportLayers, exportPrefix, upgradeLayerReferences } = this.config; const layers = getLayers(sls); const { compiledCloudFormationTemplate: cf } = sls.service.provider; const layersKeys = Object.keys(layers); const transformedResources = layersKeys.reduce((result, id) => { if (!result) { result = { exportedLayers: [], upgradedLayerReferences: [] }; } const name = (0, _pascalcase.default)(id); const exportName = `${name}LambdaLayerQualifiedArn`; const output = (cf.Outputs ?? {})[exportName]; if (!output) { return result; } if (exportLayers) { output.Export = { Name: { 'Fn::Sub': exportPrefix + exportName } }; result.exportedLayers.push(output); } if (upgradeLayerReferences) { const resourceRef = `${name}LambdaLayer`; const versionedResourceRef = output.Value.Ref; if (resourceRef !== versionedResourceRef) { info(this, `Replacing references to ${resourceRef} with ${versionedResourceRef}`); const resources = cf.Resources; for (const resource of Object.entries(resources)) { const [id, { Type: type, Properties = {} }] = resource; const { Layers: layers = [] } = Properties; if (type === 'AWS::Lambda::Function') { for (const layer of layers) { if (layer.Ref === resourceRef) { verbose(this, `${id}: Updating reference to layer version ${versionedResourceRef}`); layer.Ref = versionedResourceRef; result.upgradedLayerReferences.push(layer); } } } } } } verbose(this, 'CF after transformation:\n', JSON.stringify(cf, null, 2)); return result; }, { exportedLayers: [], upgradedLayerReferences: [] }); return transformedResources ?? { exportedLayers: [], upgradedLayerReferences: [] }; } } exports.default = LayerManagerPlugin; module.exports = exports.default; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9pbmRleC50cyJdLCJuYW1lcyI6WyJMT0dfTEVWRUwiLCJwcm9jZXNzIiwiZW52IiwiREVGQVVMVF9DT05GSUciLCJpbnN0YWxsTGF5ZXJzIiwiZXhwb3J0TGF5ZXJzIiwiYnVsa0luc3RhbGwiLCJ1cGdyYWRlTGF5ZXJSZWZlcmVuY2VzIiwiZXhwb3J0UHJlZml4IiwibWFuYWdlTm9kZUZvbGRlciIsInBhY2thZ2VyIiwicmVzb2x1dGlvbnMiLCJ3ZWJwYWNrIiwiY2xlYW4iLCJtaW5pZnkiLCJiYWNrdXBGaWxlVHlwZSIsImNvbmZpZ1BhdGgiLCJkaXNjb3Zlck1vZHVsZXMiLCJwcm9kdWN0aW9uTW9kZSIsIkxFVkVMUyIsIm5vbmUiLCJpbmZvIiwidmVyYm9zZSIsImRlYnVnIiwibG9nIiwicyIsImNvbnNvbGUiLCJsZXZlbCIsImdldExheWVycyIsInNlcnZlcmxlc3MiLCJzZXJ2aWNlIiwibGF5ZXJzIiwiZ2V0Q29uZmlnIiwiY3VzdG9tIiwibGF5ZXJDb25maWciLCJMYXllck1hbmFnZXJQbHVnaW4iLCJjb25zdHJ1Y3RvciIsInNscyIsIm9wdGlvbnMiLCJ2IiwiaW5pdCIsImhvb2tzIiwidHJhbnNmb3JtTGF5ZXJSZXNvdXJjZXMiLCJjb25maWciLCJpbnN0YWxsTGF5ZXIiLCJsYXllciIsImxheWVyTmFtZSIsInBhdGgiLCJsb2NhbFBhdGgiLCJsYXllclJlZk5hbWUiLCJyZXBsYWNlIiwieCIsInRvVXBwZXJDYXNlIiwibm9kZUxheWVyUGF0aCIsInBhY2thZ2VKc29uUGF0aCIsImpvaW4iLCJmcyIsImV4aXN0c1N5bmMiLCJwcm9taXNlcyIsIm1rZGlyIiwicmVjdXJzaXZlIiwiY29weUZpbGUiLCJjd2QiLCJmaWxlTmFtZSIsIlBBQ0tBR0VSX0xPQ0tfRklMRV9OQU1FUyIsIndyaXRlRmlsZSIsInByb2R1Y3Rpb25Nb2RlRmxhZ0Vudmlyb25tZW50QWdub3N0aWMiLCJwbGF0Zm9ybSIsInByb2R1Y3Rpb25Nb2RlRmxhZyIsImNvbW1hbmQiLCJQQUNLQUdFUl9JTlNUQUxMX0NPTU1BTkQiLCJpbnN0YWxsaW5nUGFja2FnZXMiLCJwYWNrYWdlcyIsImxlbmd0aCIsIlBBQ0tBR0VSX0FERF9DT01NQU5EIiwidHJpbSIsIk9iamVjdCIsImtleXMiLCJqc29uU3RyaW5nIiwicmVhZEZpbGUiLCJlbmNvZGluZyIsImpzb24iLCJKU09OIiwicGFyc2UiLCJzdHJpbmdpZnkiLCJlIiwiZXJyb3IiLCJpbnN0YWxsZWRMYXllcnMiLCJhdHRlbXB0ZWRJbnN0YWxsTGF5ZXJzIiwiUHJvbWlzZSIsImFsbCIsImVudHJpZXMiLCJtYXAiLCJpbnN0YWxsZWQiLCJkZWxldGUiLCJmaWx0ZXIiLCJub3RFbXB0eSIsInB1c2giLCJmb2xkZXIiLCJleGNsdWRlIiwicGFja2FnZSIsInBhdHRlcm5zIiwicCIsInN0YXJ0c1dpdGgiLCJydWxlIiwiZmlsZXNEZWxldGVkIiwiY29tcHJlc3NfanNvbiIsIm1vZHVsZSIsIm1hbmdsZSIsInBhY2thZ2Vqc29uIiwiZXhwb3J0ZWRMYXllcnMiLCJ1cGdyYWRlZExheWVyUmVmZXJlbmNlcyIsImNvbXBpbGVkQ2xvdWRGb3JtYXRpb25UZW1wbGF0ZSIsImNmIiwicHJvdmlkZXIiLCJsYXllcnNLZXlzIiwidHJhbnNmb3JtZWRSZXNvdXJjZXMiLCJyZWR1Y2UiLCJyZXN1bHQiLCJpZCIsIm5hbWUiLCJleHBvcnROYW1lIiwib3V0cHV0IiwiT3V0cHV0cyIsIkV4cG9ydCIsIk5hbWUiLCJyZXNvdXJjZVJlZiIsInZlcnNpb25lZFJlc291cmNlUmVmIiwiVmFsdWUiLCJSZWYiLCJyZXNvdXJjZXMiLCJSZXNvdXJjZXMiLCJyZXNvdXJjZSIsIlR5cGUiLCJ0eXBlIiwiUHJvcGVydGllcyIsIkxheWVycyJdLCJtYXBwaW5ncyI6Ijs7Ozs7OztBQUFBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUVBOztBQUNBOztBQUdBOzs7Ozs7QUFFQSxNQUFNO0FBQUVBLEVBQUFBLFNBQVMsR0FBRztBQUFkLElBQXlCQyxPQUFP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QUFHO0FBRGIsZ0JBRW9Gd0csVUFGMUY7O0FBR0EsZ0JBQUlELElBQUksS0FBSyx1QkFBYixFQUFzQztBQUNwQyxtQkFBSyxNQUFNekYsS0FBWCxJQUFvQmQsTUFBcEIsRUFBNEI7QUFDMUIsb0JBQUljLEtBQUssQ0FBQ29GLEdBQU4sS0FBY0gsV0FBbEIsRUFBK0I7QUFDN0J4RyxrQkFBQUEsT0FBTyxDQUFDLElBQUQsRUFBUSxHQUFFaUcsRUFBRyx5Q0FBd0NRLG9CQUFxQixFQUExRSxDQUFQO0FBQ0FsRixrQkFBQUEsS0FBSyxDQUFDb0YsR0FBTixHQUFZRixvQkFBWjtBQUNBVCxrQkFBQUEsTUFBTSxDQUFDUCx1QkFBUCxDQUErQmQsSUFBL0IsQ0FBb0NwRCxLQUFwQztBQUNEO0FBQ0Y7QUFDRjtBQUNGO0FBQ0Y7QUFDRjs7QUFFRHZCLE1BQUFBLE9BQU8sQ0FBQyxJQUFELEVBQU8sNEJBQVAsRUFBcUM0RCxJQUFJLENBQUNFLFNBQUwsQ0FBZTZCLEVBQWYsRUFBbUIsSUFBbkIsRUFBeUIsQ0FBekIsQ0FBckMsQ0FBUDtBQUVBLGFBQU9LLE1BQVA7QUFDRCxLQXJEMEIsRUFzRDNCO0FBQ0VSLE1BQUFBLGNBQWMsRUFBRSxFQURsQjtBQUVFQyxNQUFBQSx1QkFBdUIsRUFBRTtBQUYzQixLQXREMkIsQ0FBN0I7QUEyREEsV0FDRUssb0JBQW9CLElBQUk7QUFDdEJOLE1BQUFBLGNBQWMsRUFBRSxFQURNO0FBRXRCQyxNQUFBQSx1QkFBdUIsRUFBRTtBQUZILEtBRDFCO0FBTUQ7O0FBcFBxQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBwYXNjYWxjYXNlIGZyb20gJ3Bhc2NhbGNhc2UnO1xuaW1wb3J0IGZzIGZyb20gJ2ZzJztcbmltcG9ydCBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0IGRlbCBmcm9tICdkZWwnO1xuaW1wb3J0IHsgZ2V0RXh0ZXJuYWxNb2R1bGVzIH0gZnJvbSAnLi9leHRlcm5hbCc7XG5pbXBvcnQgeyBQYWNrYWdlciwgTWF5YmUsIExheWVyLCBGdW5jdGlvbkxheWVyUmVmZXJlbmNlLCBUcmFuc2Zvcm1lZExheWVyUmVzb3VyY2VzIH0gZnJvbSAnLi90eXBlcyc7XG5pbXBvcnQgeyBub3RFbXB0eSwgZXhlYyB9IGZyb20gJy4vdXRpbHMnO1xuaW1wb3J0IHsgUEFDS0FHRVJfQUREX0NPTU1BTkQsIFBBQ0tBR0VSX0lOU1RBTExfQ09NTUFORCwgUEFDS0FHRVJfTE9DS19GSUxFX05BTUVTIH0gZnJvbSAnLi9jb25zdGFudHMnO1xuaW1wb3J0IFNlcnZlcmxlc3MgZnJvbSAnc2VydmVybGVzcyc7XG5pbXBvcnQgeyBDbG91ZEZvcm1hdGlvblJlc291cmNlLCBPdXRwdXQgfSBmcm9tICdzZXJ2ZXJsZXNzL2F3cyc7XG5pbXBvcnQgbWluaWZ5QWxsIGZyb20gJ21pbmlmeS1hbGwtanMnO1xuXG5jb25zdCB7IExPR19MRVZFTCA9ICdpbmZvJyB9ID0gcHJvY2Vzcy5lbnY7XG5cbmNvbnN0IERFRkFVTFRfQ09ORklHID0ge1xuICBpbnN0YWxsTGF5ZXJzOiB0cnVlLFxuICBleHBvcnRMYXllcnM6IHRydWUsXG4gIGJ1bGtJbnN0YWxsOiBmYWxzZSxcbiAgdXBncmFkZUxheWVyUmVmZXJlbmNlczogdHJ1ZSxcbiAgZXhwb3J0UHJlZml4OiAnJHtBV1M6OlN0YWNrTmFtZX0tJyxcbiAgbWFuYWdlTm9kZUZvbGRlcjogZmFsc2UsXG4gIHBhY2thZ2VyOiAnbnBtJyxcbiAgcmVzb2x1dGlvbnM6IHt9LFxuICB3ZWJwYWNrOiB7XG4gICAgY2xlYW46IHRydWUsXG4gICAgbWluaWZ5OiBmYWxzZSxcbiAgICBiYWNrdXBGaWxlVHlwZTogJ2pzJyxcbiAgICBjb25maWdQYXRoOiAnLi93ZWJwYWNrLmNvbmZpZy5qcycsXG4gICAgZGlzY292ZXJNb2R1bGVzOiB0cnVlLFxuICB9LFxuICBwcm9kdWN0aW9uTW9kZTogdHJ1ZSxcbn07XG5cbmNvbnN0IExFVkVMUyA9IHtcbiAgbm9uZTogMCxcbiAgaW5mbzogMSxcbiAgdmVyYm9zZTogMixcbiAgZGVidWc6IDMsXG59O1xuXG5mdW5jdGlvbiBsb2coLi4uczogdW5rbm93bltdKSB7XG4gIGNvbnNvbGUubG9nKCdbd2VicGFjay1sYXllcnNdJywgLi4ucyk7XG59XG5cbmZ1bmN0aW9uIHZlcmJvc2UoeyBsZXZlbCB9OiB7IGxldmVsOiBrZXlvZiB0eXBlb2YgTEVWRUxTIH0sIC4uLnM6IHVua25vd25bXSkge1xuICBMRVZFTFNbbGV2ZWxdID49IExFVkVMUy52ZXJib3NlICYmIGxvZyguLi5zKTtcbn1cblxuZnVuY3Rpb24gaW5mbyh7IGxldmVsIH06IHsgbGV2ZWw6IGtleW9mIHR5cGVvZiBMRVZFTFMgfSwgLi4uczogdW5rbm93bltdKSB7XG4gIExFVkVMU1tsZXZlbF0gPj0gTEVWRUxTLmluZm8gJiYgbG9nKC4uLnMpO1xufVxuXG5mdW5jdGlvbiBkZWJ1Zyh7IGxldmVsIH06IHsgbGV2ZWw6IGtleW9mIHR5cGVvZiBMRVZFTFMgfSwgLi4uczogdW5rbm93bltdKSB7XG4gIExFVkVMU1tsZXZlbF0gPj0gTEVWRUxTLmRlYnVnICYmIGxvZyguLi5zKTtcbn1cblxuZnVuY3Rpb24gZ2V0TGF5ZXJzKHNlcnZlcmxlc3M6IFNlcnZlcmxlc3MpOiB7IFtrZXk6IHN0cmluZ106IExheWVyIH0ge1xuICByZXR1cm4gc2VydmVybGVzcy5zZXJ2aWNlLmxheWVycyB8fCB7fTtcbn1cblxuZnVuY3Rpb24gZ2V0Q29uZmlnKHNlcnZlcmxlc3M6IFNlcnZlcmxlc3MpIHtcbiAgY29uc3QgY3VzdG9tID0gc2VydmVybGVzcy5zZXJ2aWNlLmN1c3RvbSB8fCB7fTtcblxuICByZXR1cm4ge1xuICAgIC4uLkRFRkFVTFRfQ09ORklHLFxuICAgIC4uLmN1c3RvbS5sYXllckNvbmZpZyxcbiAgICB3ZWJwYWNrOiB7XG4gICAgICAuLi5ERUZBVUxUX0NPTkZJRy53ZWJwYWNrLFxuICAgICAgLi4uKGN1c3RvbS5sYXllckNvbmZpZy53ZWJwYWNrID8/IHt9KSxcbiAgICB9LFxuICB9O1xufVxuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBMYXllck1hbmFnZXJQbHVnaW4ge1xuICBsZXZlbDoga2V5b2YgdHlwZW9mIExFVkVMUztcbiAgaG9va3M6IHtcbiAgICBba2V5OiBzdHJpbmddOiAoKSA9PiBQcm9taXNlPHVua25vd24+O1xuICB9O1xuICBjb25maWc6IHtcbiAgICBpbnN0YWxsTGF5ZXJzPzogYm9vbGVhbjtcbiAgICBidWxrSW5zdGFsbD86IGJvb2xlYW47XG4gICAgZXhwb3J0TGF5ZXJzPzogYm9vbGVhbjtcbiAgICB1cGdyYWRlTGF5ZXJSZWZlcmVuY2VzPzogYm9vbGVhbjtcbiAgICBleHBvcnRQcmVmaXg/OiBzdHJpbmc7XG4gICAgbWFuYWdlTm9kZUZvbGRlcj86IGJvb2xlYW47XG4gICAgcGFja2FnZXI/OiBQYWNrYWdlcjtcbiAgICByZXNvbHV0aW9ucz86IFJlY29yZDxzdHJpbmcsIHN0cmluZz47XG4gICAgd2VicGFjazogUGFydGlhbDx7XG4gICAgICBjbGVhbjogYm9vbGVhbjtcbiAgICAgIG1pbmlmeTogYm9vbGVhbjtcbiAgICAgIGJhY2t1cEZpbGVUeXBlOiAnanMnIHwgJ3RzJyB8ICdjanMnO1xuICAgICAgY29uZmlnUGF0aDogc3RyaW5nO1xuICAgICAgZGlzY292ZXJNb2R1bGVzOiBib29sZWFuO1xuICAgIH0+O1xuICAgIHByb2R1Y3Rpb25Nb2RlPzogYm9vbGVhbjtcbiAgfSA9IHsgd2VicGFjazoge30gfTtcbiAgY29uc3RydWN0b3Ioc2xzOiBTZXJ2ZXJsZXNzLCBvcHRpb25zOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9IHt9KSB7XG4gICAgdGhpcy5sZXZlbCA9IChvcHRpb25zLnYgfHwgb3B0aW9ucy52ZXJib3NlID8gJ3ZlcmJvc2UnIDogTE9HX0xFVkVMKSBhcyBrZXlvZiB0eXBlb2YgTEVWRUxTO1xuXG4gICAgZGVidWcodGhpcywgYEludm9raW5nIHdlYnBhY2stbGF5ZXJzIHBsdWdpbmApO1xuICAgIHRoaXMuaW5pdChzbHMpO1xuXG4gICAgdGhpcy5ob29rcyA9IHtcbiAgICAgICdwYWNrYWdlOmluaXRpYWxpemUnOiAoKSA9PiB0aGlzLmluc3RhbGxMYXllcnMoc2xzKSxcbiAgICAgICdiZWZvcmU6ZGVwbG95OmRlcGxveSc6ICgpID0+IHRoaXMudHJhbnNmb3JtTGF5ZXJSZXNvdXJjZXMoc2xzKSxcbiAgICB9O1xuICB9XG5cbiAgaW5pdChzbHM6IFNlcnZlcmxlc3MpOiB2b2lkIHtcbiAgICB0aGlzLmNvbmZpZyA9IGdldENvbmZpZyhzbHMpO1xuICB9XG5cbiAgYXN5bmMgaW5zdGFsbExheWVyKHNsczogU2VydmVybGVzcywgbGF5ZXI6IExheWVyLCBsYXllck5hbWU6IHN0cmluZyk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGNvbnN0IHsgcGF0aDogbG9jYWxQYXRoIH0gPSBsYXllcjtcbiAgICBjb25zdCBsYXllclJlZk5hbWUgPSBgJHtsYXllck5hbWUucmVwbGFjZSgvXi4vLCB4ID0+IHgudG9VcHBlckNhc2UoKSl9TGFtYmRhTGF5ZXJgO1xuICAgIGNvbnN0IG5vZGVMYXllclBhdGggPSBgJHtsb2NhbFBhdGh9L25vZGVqc2A7XG4gICAgY29uc3QgcGFja2FnZUpzb25QYXRoID0gcGF0aC5qb2luKG5vZGVMYXllclBhdGgsICdwYWNrYWdlLmpzb24nKTtcbiAgICBpZiAoIXRoaXMuY29uZmlnLm1hbmFnZU5vZGVGb2xkZXIgJiYgIWZzLmV4aXN0c1N5bmMobm9kZUxheWVyUGF0aCkpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgaWYgKHRoaXMuY29uZmlnLm1hbmFnZU5vZGVGb2xkZXIpIHtcbiAgICAgIGF3YWl0IGRlbChgJHtub2RlTGF5ZXJQYXRofS8qKmApO1xuICAgIH1cblxuICAgIGlmICghZnMuZXhpc3RzU3luYyhub2RlTGF5ZXJQYXRoKSAmJiB0aGlzLmNvbmZpZy5tYW5hZ2VOb2RlRm9sZGVyKSB7XG4gICAgICBhd2FpdCBmcy5wcm9taXNlcy5ta2Rpcihub2RlTGF5ZXJQYXRoLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcbiAgICB9XG4gICAgaWYgKCF0aGlzLmNvbmZpZy53ZWJwYWNrKSB7XG4gICAgICBhd2FpdCBmcy5wcm9taXNlcy5jb3B5RmlsZShwYXRoLmpvaW4ocHJvY2Vzcy5jd2QoKSwgJ3BhY2thZ2UuanNvbicpLCBwYWNrYWdlSnNvblBhdGgpO1xuICAgICAgY29uc3QgZmlsZU5hbWUgPSBQQUNLQUdFUl9MT0NLX0ZJTEVfTkFNRVNbdGhpcy5jb25maWcucGFja2FnZXIgPz8gJ25wbSddO1xuICAgICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgZnMucHJvbWlzZXMuY29weUZpbGUocGF0aC5qb2luKHByb2Nlc3MuY3dkKCksIGZpbGVOYW1lKSwgcGF0aC5qb2luKG5vZGVMYXllclBhdGgsIGZpbGVOYW1lKSk7XG4gICAgICB9IGNhdGNoIHtcbiAgICAgICAgaW5mbyh0aGlzLCBgVW5hYmxlIHRvIGNvcHkgJHtmaWxlTmFtZX0gYWNyb3NzLCB0aGlzIHdpbGwgY2F1c2UgdmVyc2lvbiBpbmFjY3VyYWNpZXNgKTtcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKHRoaXMuY29uZmlnLm1hbmFnZU5vZGVGb2xkZXIpIHtcbiAgICAgIGF3YWl0IGZzLnByb21pc2VzLndyaXRlRmlsZShwYWNrYWdlSnNvblBhdGgsICd7fScpO1xuICAgIH1cbiAgICB2ZXJib3NlKHRoaXMsIGBJbnN0YWxsaW5nIG5vZGVqcyBsYXllciAke2xvY2FsUGF0aH0gd2l0aCAke3RoaXMuY29uZmlnLnBhY2thZ2VyfWApO1xuXG4gICAgY29uc3QgcHJvZHVjdGlvbk1vZGVGbGFnRW52aXJvbm1lbnRBZ25vc3RpYyA9XG4gICAgICBwcm9jZXNzLnBsYXRmb3JtID09PSAnd2luMzInID8gJ3NldCBOT0RFX0VOVj1wcm9kdWN0aW9uICYmJyA6ICdOT0RFX0VOVj1wcm9kdWN0aW9uJztcbiAgICBjb25zdCBwcm9kdWN0aW9uTW9kZUZsYWcgPSB0aGlzLmNvbmZpZy5wcm9kdWN0aW9uTW9kZSA/IHByb2R1Y3Rpb25Nb2RlRmxhZ0Vudmlyb25tZW50QWdub3N0aWMgOiAnJztcbiAgICBsZXQgY29tbWFuZCA9IHByb2R1Y3Rpb25Nb2RlRmxhZyArIFBBQ0tBR0VSX0lOU1RBTExfQ09NTUFORFt0aGlzLmNvbmZpZy5wYWNrYWdlciA/PyAnbnBtJ107XG4gICAgbGV0IGluc3RhbGxpbmdQYWNrYWdlcyA9IGZhbHNlO1xuICAgIGlmICh0aGlzLmNvbmZpZy53ZWJwYWNrKSB7XG4gICAgICBjb25zdCBwYWNrYWdlcyA9IGF3YWl0IGdldEV4dGVybmFsTW9kdWxlcyhzbHMsIGxheWVyUmVmTmFtZSk7XG4gICAgICBpZiAocGFja2FnZXMubGVuZ3RoICE9PSAwKSB7XG4gICAgICAgIGNvbW1hbmQgPSBgJHtwcm9kdWN0aW9uTW9kZUZsYWd9ICR7UEFDS0FHRVJfQUREX0NPTU1BTkRbdGhpcy5jb25maWcucGFja2FnZXIgPz8gJ25wbSddfSAke3BhY2thZ2VzXG4gICAgICAgICAgLmpvaW4oJyAnKVxuICAgICAgICAgIC50cmltKCl9YDtcbiAgICAgICAgaW5zdGFsbGluZ1BhY2thZ2VzID0gdHJ1ZTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbW1hbmQgPSAnbHMnO1xuICAgICAgfVxuICAgIH1cbiAgICBpbmZvKHRoaXMsIGBSdW5uaW5nIGNvbW1hbmQgJHtjb21tYW5kfWApO1xuICAgIGlmICh0aGlzLmNvbmZpZy5wYWNrYWdlciA9PT0gJ3lhcm4nICYmIE9iamVjdC5rZXlzKHRoaXMuY29uZmlnLnJlc29sdXRpb25zID8/IHt9KS5sZW5ndGggPiAwKSB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCBqc29uU3RyaW5nID0gYXdhaXQgZnMucHJvbWlzZXMucmVhZEZpbGUocGFja2FnZUpzb25QYXRoLCB7XG4gICAgICAgICAgZW5jb2Rpbmc6ICd1dGYtOCcsXG4gICAgICAgIH0pO1xuICAgICAgICBjb25zdCBqc29uID0gSlNPTi5wYXJzZShqc29uU3RyaW5nKTtcbiAgICAgICAganNvblsncmVzb2x1dGlvbnMnXSA9IHRoaXMuY29uZmlnLnJlc29sdXRpb25zO1xuICAgICAgICBhd2FpdCBmcy5wcm9taXNlcy53cml0ZUZpbGUocGFja2FnZUpzb25QYXRoLCBKU09OLnN0cmluZ2lmeShqc29uKSk7XG4gICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoYFVuYWJsZSB0byBhZGQgcmVzb2x1dGlvbnNgLCBlKTtcbiAgICAgIH1cbiAgICB9XG4gICAgYXdhaXQgZXhlYyhjb21tYW5kLCB7XG4gICAgICBjd2Q6IG5vZGVMYXllclBhdGgsXG4gICAgICBlbmNvZGluZzogbnVsbCxcbiAgICB9KTtcbiAgICBpZiAodGhpcy5jb25maWcucGFja2FnZXIgPT09ICd5YXJuJyAmJiBpbnN0YWxsaW5nUGFja2FnZXMpIHtcbiAgICAgIGF3YWl0IGV4ZWMoYHlhcm4gYXV0b2NsZWFuIC0taW5pdGAsIHsgY3dkOiBub2RlTGF5ZXJQYXRoLCBlbmNvZGluZzogbnVsbCB9KTtcbiAgICB9XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICBhc3luYyBpbnN0YWxsTGF5ZXJzKHNsczogU2VydmVybGVzcyk6IFByb21pc2U8eyBpbnN0YWxsZWRMYXllcnM6IExheWVyW10gfT4ge1xuICAgIHZlcmJvc2UodGhpcywgYENvbmZpZzogYCwgdGhpcy5jb25maWcpO1xuICAgIGNvbnN0IHsgaW5zdGFsbExheWVycywgYnVsa0luc3RhbGwgPSBmYWxzZSB9ID0gdGhpcy5jb25maWc7XG5cbiAgICBpZiAoIWluc3RhbGxMYXllcnMpIHtcbiAgICAgIHZlcmJvc2UodGhpcywgYFNraXBwaW5nIGluc3RhbGxhdGlvbiBvZiBsYXllcnMgYXMgcGVyIGNvbmZpZ2ApO1xuICAgICAgcmV0dXJuIHsgaW5zdGFsbGVkTGF5ZXJzOiBbXSB9O1xuICAgIH1cblxuICAgIGNvbnN0IGxheWVycyA9IGdldExheWVycyhzbHMpO1xuICAgIGxldCBpbnN0YWxsZWRMYXllcnM6IExheWVyW10gPSBbXTtcbiAgICBpZiAoYnVsa0luc3RhbGwpIHtcbiAgICAgIGNvbnN0IGF0dGVtcHRlZEluc3RhbGxMYXllcnMgPSBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgICAgT2JqZWN0LmVudHJpZXMobGF5ZXJzKS5tYXAoYXN5bmMgKFtsYXllck5hbWUsIGxheWVyXSkgPT4ge1xuICAgICAgICAgIGlmICh0eXBlb2YgbGF5ZXIgIT09ICdvYmplY3QnKSByZXR1cm47XG4gICAgICAgICAgY29uc3QgaW5zdGFsbGVkID0gYXdhaXQgdGhpcy5pbnN0YWxsTGF5ZXIoc2xzLCBsYXllciwgbGF5ZXJOYW1lKTtcbiAgICAgICAgICBpZiAoIWluc3RhbGxlZCkgcmV0dXJuO1xuICAgICAgICAgIGF3YWl0IHRoaXMuZGVsZXRlKHNscywgbGF5ZXIucGF0aCk7XG4gICAgICAgICAgcmV0dXJuIGxheWVyO1xuICAgICAgICB9KVxuICAgICAgKTtcbiAgICAgIGluc3RhbGxlZExheWVycyA9IGF0dGVtcHRlZEluc3RhbGxMYXllcnMuZmlsdGVyKG5vdEVtcHR5KTtcbiAgICB9IGVsc2Uge1xuICAgICAgZm9yIChjb25zdCBbbGF5ZXJOYW1lLCBsYXllcl0gb2YgT2JqZWN0LmVudHJpZXMobGF5ZXJzKSkge1xuICAgICAgICBpZiAodHlwZW9mIGxheWVyICE9PSAnb2JqZWN0JykgY29udGludWU7XG4gICAgICAgIGNvbnN0IGluc3RhbGxlZCA9IGF3YWl0IHRoaXMuaW5zdGFsbExheWVyKHNscywgbGF5ZXIsIGxheWVyTmFtZSk7XG4gICAgICAgIGlmICghaW5zdGFsbGVkKSBjb250aW51ZTtcbiAgICAgICAgYXdhaXQgdGhpcy5kZWxldGUoc2xzLCBsYXllci5wYXRoKTtcbiAgICAgICAgaW5zdGFsbGVkTGF5ZXJzLnB1c2gobGF5ZXIpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGluZm8odGhpcywgYEluc3RhbGxlZCAke2luc3RhbGxlZExheWVycy5sZW5ndGh9IGxheWVyJHtpbnN0YWxsZWRMYXllcnMubGVuZ3RoID4gMSA/ICdzJyA6ICcnfWApO1xuICAgIHJldHVybiB7IGluc3RhbGxlZExheWVycyB9O1xuICB9XG5cbiAgYXN5bmMgZGVsZXRlKHNsczogU2VydmVybGVzcywgZm9sZGVyOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCB7IGNsZWFuLCBtaW5pZnkgfSA9IHRoaXMuY29uZmlnLndlYnBhY2s7XG4gICAgaWYgKCFjbGVhbikgcmV0dXJuO1xuICAgIGNvbnN0IG5vZGVMYXllclBhdGggPSBgJHtmb2xkZXJ9L25vZGVqc2A7XG4gICAgY29uc3QgZXhjbHVkZTogc3RyaW5nW10gPVxuICAgICAgc2xzLnNlcnZpY2U/LnBhY2thZ2U/LmV4Y2x1ZGUgPz9cbiAgICAgIHNscy5zZXJ2aWNlPy5wYWNrYWdlPy5wYXR0ZXJuc1xuICAgICAgICA/LmZpbHRlcigocDogc3RyaW5nKSA9PiBwLnN0YXJ0c1dpdGgoJyEnKSlcbiAgICAgICAgLm1hcCgocDogc3RyaW5nKSA9PiBwLnJlcGxhY2UoL14hLywgJycpKSA/P1xuICAgICAgW107XG4gICAgaW5mbyh0aGlzLCBgQ2xlYW5pbmcgJHtleGNsdWRlLm1hcChydWxlID0+IHBhdGguam9pbihub2RlTGF5ZXJQYXRoLCBydWxlKSkuam9pbignLCAnKX1gKTtcbiAgICBjb25zdCBmaWxlc0RlbGV0ZWQgPSBhd2FpdCBkZWwoZXhjbHVkZS5tYXAocnVsZSA9PiBwYXRoLmpvaW4obm9kZUxheWVyUGF0aCwgcnVsZSkpKTtcbiAgICBpZiAoZnMuZXhpc3RzU3luYyhub2RlTGF5ZXJQYXRoKSAmJiBtaW5pZnkpIHtcbiAgICAgIGF3YWl0IG1pbmlmeUFsbChub2RlTGF5ZXJQYXRoLCB7XG4gICAgICAgIGNvbXByZXNzX2pzb246IHRydWUsXG4gICAgICAgIG1vZHVsZTogdHJ1ZSxcbiAgICAgICAgbWFuZ2xlOiB0cnVlLFxuICAgICAgICBwYWNrYWdlanNvbjogdHJ1ZSxcbiAgICAgIH0pO1xuICAgIH1cbiAgICBpbmZvKHRoaXMsIGBDbGVhbmVkICR7ZmlsZXNEZWxldGVkLmxlbmd0aH0gZmlsZXMgYXQgJHtub2RlTGF5ZXJQYXRofWApO1xuICB9XG5cbiAgYXN5bmMgdHJhbnNmb3JtTGF5ZXJSZXNvdXJjZXMoc2xzOiBTZXJ2ZXJsZXNzKTogUHJvbWlzZTxUcmFuc2Zvcm1lZExheWVyUmVzb3VyY2VzPiB7XG4gICAgaWYgKCF0aGlzLmNvbmZpZykge1xuICAgICAgbG9nKHRoaXMsICdVbmFibGUgdG8gYWRkIGxheWVycyBjdXJyZW50bHkgYXMgY29uZmlnIHVuYXZhaWxhYmxlJyk7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBleHBvcnRlZExheWVyczogW10sXG4gICAgICAgIHVwZ3JhZGVkTGF5ZXJSZWZlcmVuY2VzOiBbXSxcbiAgICAgIH07XG4gICAgfVxuICAgIGNvbnN0IHsgZXhwb3J0TGF5ZXJzLCBleHBvcnRQcmVmaXgsIHVwZ3JhZGVMYXllclJlZmVyZW5jZXMgfSA9IHRoaXMuY29uZmlnO1xuICAgIGNvbnN0IGxheWVycyA9IGdldExheWVycyhzbHMpO1xuICAgIGNvbnN0IHsgY29tcGlsZWRDbG91ZEZvcm1hdGlvblRlbXBsYXRlOiBjZiB9ID0gc2xzLnNlcnZpY2UucHJvdmlkZXI7XG5cbiAgICBjb25zdCBsYXllcnNLZXlzID0gT2JqZWN0LmtleXMobGF5ZXJzKTtcblxuICAgIGNvbnN0IHRyYW5zZm9ybWVkUmVzb3VyY2VzID0gbGF5ZXJzS2V5cy5yZWR1Y2UoXG4gICAgICAocmVzdWx0OiBNYXliZTxUcmFuc2Zvcm1lZExheWVyUmVzb3VyY2VzPiwgaWQ6IHN0cmluZykgPT4ge1xuICAgICAgICBpZiAoIXJlc3VsdCkge1xuICAgICAgICAgIHJlc3VsdCA9IHtcbiAgICAgICAgICAgIGV4cG9ydGVkTGF5ZXJzOiBbXSxcbiAgICAgICAgICAgIHVwZ3JhZGVkTGF5ZXJSZWZlcmVuY2VzOiBbXSxcbiAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IG5hbWUgPSBwYXNjYWxjYXNlKGlkKTtcbiAgICAgICAgY29uc3QgZXhwb3J0TmFtZSA9IGAke25hbWV9TGFtYmRhTGF5ZXJRdWFsaWZpZWRBcm5gO1xuICAgICAgICBjb25zdCBvdXRwdXQ6IE1heWJlPE91dHB1dD4gPSAoY2YuT3V0cHV0cyA/PyB7fSlbZXhwb3J0TmFtZV07XG5cbiAgICAgICAgaWYgKCFvdXRwdXQpIHtcbiAgICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGV4cG9ydExheWVycykge1xuICAgICAgICAgIG91dHB1dC5FeHBvcnQgPSB7XG4gICAgICAgICAgICBOYW1lOiB7XG4gICAgICAgICAgICAgICdGbjo6U3ViJzogZXhwb3J0UHJlZml4ICsgZXhwb3J0TmFtZSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgfTtcbiAgICAgICAgICByZXN1bHQuZXhwb3J0ZWRMYXllcnMucHVzaChvdXRwdXQpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHVwZ3JhZGVMYXllclJlZmVyZW5jZXMpIHtcbiAgICAgICAgICBjb25zdCByZXNvdXJjZVJlZiA9IGAke25hbWV9TGFtYmRhTGF5ZXJgO1xuICAgICAgICAgIGNvbnN0IHZlcnNpb25lZFJlc291cmNlUmVmID0gb3V0cHV0LlZhbHVlLlJlZjtcblxuICAgICAgICAgIGlmIChyZXNvdXJjZVJlZiAhPT0gdmVyc2lvbmVkUmVzb3VyY2VSZWYpIHtcbiAgICAgICAgICAgIGluZm8odGhpcywgYFJlcGxhY2luZyByZWZlcmVuY2VzIHRvICR7cmVzb3VyY2VSZWZ9IHdpdGggJHt2ZXJzaW9uZWRSZXNvdXJjZVJlZn1gKTtcbiAgICAgICAgICAgIGNvbnN0IHJlc291cmNlcyA9IGNmLlJlc291cmNlcyBhcyB7IFtrZXk6IHN0cmluZ106IENsb3VkRm9ybWF0aW9uUmVzb3VyY2UgfTtcbiAgICAgICAgICAgIGZvciAoY29uc3QgcmVzb3VyY2Ugb2YgT2JqZWN0LmVudHJpZXMocmVzb3VyY2VzKSkge1xuICAgICAgICAgICAgICBjb25zdCBbaWQsIHsgVHlwZTogdHlwZSwgUHJvcGVydGllcyA9IHt9IH1dID0gcmVzb3VyY2U7XG4gICAgICAgICAgICAgIGNvbnN0IHtcbiAgICAgICAgICAgICAgICBMYXllcnM6IGxheWVycyA9IFtdLFxuICAgICAgICAgICAgICB9OiBQYXJ0aWFsPENsb3VkRm9ybWF0aW9uUmVzb3VyY2VbJ1Byb3BlcnRpZXMnXSAmIHsgTGF5ZXJzOiBGdW5jdGlvbkxheWVyUmVmZXJlbmNlW10gfT4gPSBQcm9wZXJ0aWVzO1xuICAgICAgICAgICAgICBpZiAodHlwZSA9PT0gJ0FXUzo6TGFtYmRhOjpGdW5jdGlvbicpIHtcbiAgICAgICAgICAgICAgICBmb3IgKGNvbnN0IGxheWVyIG9mIGxheWVycykge1xuICAgICAgICAgICAgICAgICAgaWYgKGxheWVyLlJlZiA9PT0gcmVzb3VyY2VSZWYpIHtcbiAgICAgICAgICAgICAgICAgICAgdmVyYm9zZSh0aGlzLCBgJHtpZH06IFVwZGF0aW5nIHJlZmVyZW5jZSB0byBsYXllciB2ZXJzaW9uICR7dmVyc2lvbmVkUmVzb3VyY2VSZWZ9YCk7XG4gICAgICAgICAgICAgICAgICAgIGxheWVyLlJlZiA9IHZlcnNpb25lZFJlc291cmNlUmVmO1xuICAgICAgICAgICAgICAgICAgICByZXN1bHQudXBncmFkZWRMYXllclJlZmVyZW5jZXMucHVzaChsYXllcik7XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgdmVyYm9zZSh0aGlzLCAnQ0YgYWZ0ZXIgdHJhbnNmb3JtYXRpb246XFxuJywgSlNPTi5zdHJpbmdpZnkoY2YsIG51bGwsIDIpKTtcblxuICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgfSxcbiAgICAgIHtcbiAgICAgICAgZXhwb3J0ZWRMYXllcnM6IFtdLFxuICAgICAgICB1cGdyYWRlZExheWVyUmVmZXJlbmNlczogW10sXG4gICAgICB9XG4gICAgKTtcbiAgICByZXR1cm4gKFxuICAgICAgdHJhbnNmb3JtZWRSZXNvdXJjZXMgPz8ge1xuICAgICAgICBleHBvcnRlZExheWVyczogW10sXG4gICAgICAgIHVwZ3JhZGVkTGF5ZXJSZWZlcmVuY2VzOiBbXSxcbiAgICAgIH1cbiAgICApO1xuICB9XG59XG4iXX0=