serverless-webpack-layers
Version:
Plugin for the Serverless framework that offers AWS Lambda layer management using webpack
353 lines (295 loc) • 40.4 kB
JavaScript
;
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=