FilesRouter.js 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.FilesRouter = void 0;
  6. var _express = _interopRequireDefault(require("express"));
  7. var _bodyParser = _interopRequireDefault(require("body-parser"));
  8. var Middlewares = _interopRequireWildcard(require("../middlewares"));
  9. var _node = _interopRequireDefault(require("parse/node"));
  10. var _Config = _interopRequireDefault(require("../Config"));
  11. var _mime = _interopRequireDefault(require("mime"));
  12. var _logger = _interopRequireDefault(require("../logger"));
  13. function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
  14. function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
  15. function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
  16. const triggers = require('../triggers');
  17. const http = require('http');
  18. const Utils = require('../Utils');
  19. const downloadFileFromURI = uri => {
  20. return new Promise((res, rej) => {
  21. http.get(uri, response => {
  22. response.setDefaultEncoding('base64');
  23. let body = `data:${response.headers['content-type']};base64,`;
  24. response.on('data', data => body += data);
  25. response.on('end', () => res(body));
  26. }).on('error', e => {
  27. rej(`Error downloading file from ${uri}: ${e.message}`);
  28. });
  29. });
  30. };
  31. const addFileDataIfNeeded = async file => {
  32. if (file._source.format === 'uri') {
  33. const base64 = await downloadFileFromURI(file._source.uri);
  34. file._previousSave = file;
  35. file._data = base64;
  36. file._requestTask = null;
  37. }
  38. return file;
  39. };
  40. class FilesRouter {
  41. expressRouter({
  42. maxUploadSize = '20Mb'
  43. } = {}) {
  44. var router = _express.default.Router();
  45. router.get('/files/:appId/:filename', this.getHandler);
  46. router.get('/files/:appId/metadata/:filename', this.metadataHandler);
  47. router.post('/files', function (req, res, next) {
  48. next(new _node.default.Error(_node.default.Error.INVALID_FILE_NAME, 'Filename not provided.'));
  49. });
  50. router.post('/files/:filename', _bodyParser.default.raw({
  51. type: () => {
  52. return true;
  53. },
  54. limit: maxUploadSize
  55. }),
  56. // Allow uploads without Content-Type, or with any Content-Type.
  57. Middlewares.handleParseHeaders, Middlewares.handleParseSession, this.createHandler);
  58. router.delete('/files/:filename', Middlewares.handleParseHeaders, Middlewares.handleParseSession, Middlewares.enforceMasterKeyAccess, this.deleteHandler);
  59. return router;
  60. }
  61. getHandler(req, res) {
  62. const config = _Config.default.get(req.params.appId);
  63. if (!config) {
  64. res.status(403);
  65. const err = new _node.default.Error(_node.default.Error.OPERATION_FORBIDDEN, 'Invalid application ID.');
  66. res.json({
  67. code: err.code,
  68. error: err.message
  69. });
  70. return;
  71. }
  72. const filesController = config.filesController;
  73. const filename = req.params.filename;
  74. const contentType = _mime.default.getType(filename);
  75. if (isFileStreamable(req, filesController)) {
  76. filesController.handleFileStream(config, filename, req, res, contentType).catch(() => {
  77. res.status(404);
  78. res.set('Content-Type', 'text/plain');
  79. res.end('File not found.');
  80. });
  81. } else {
  82. filesController.getFileData(config, filename).then(data => {
  83. res.status(200);
  84. res.set('Content-Type', contentType);
  85. res.set('Content-Length', data.length);
  86. res.end(data);
  87. }).catch(() => {
  88. res.status(404);
  89. res.set('Content-Type', 'text/plain');
  90. res.end('File not found.');
  91. });
  92. }
  93. }
  94. async createHandler(req, res, next) {
  95. var _config$fileUpload;
  96. const config = req.config;
  97. const user = req.auth.user;
  98. const isMaster = req.auth.isMaster;
  99. const isLinked = user && _node.default.AnonymousUtils.isLinked(user);
  100. if (!isMaster && !config.fileUpload.enableForAnonymousUser && isLinked) {
  101. next(new _node.default.Error(_node.default.Error.FILE_SAVE_ERROR, 'File upload by anonymous user is disabled.'));
  102. return;
  103. }
  104. if (!isMaster && !config.fileUpload.enableForAuthenticatedUser && !isLinked && user) {
  105. next(new _node.default.Error(_node.default.Error.FILE_SAVE_ERROR, 'File upload by authenticated user is disabled.'));
  106. return;
  107. }
  108. if (!isMaster && !config.fileUpload.enableForPublic && !user) {
  109. next(new _node.default.Error(_node.default.Error.FILE_SAVE_ERROR, 'File upload by public is disabled.'));
  110. return;
  111. }
  112. const filesController = config.filesController;
  113. const {
  114. filename
  115. } = req.params;
  116. const contentType = req.get('Content-type');
  117. if (!req.body || !req.body.length) {
  118. next(new _node.default.Error(_node.default.Error.FILE_SAVE_ERROR, 'Invalid file upload.'));
  119. return;
  120. }
  121. const error = filesController.validateFilename(filename);
  122. if (error) {
  123. next(error);
  124. return;
  125. }
  126. const fileExtensions = (_config$fileUpload = config.fileUpload) === null || _config$fileUpload === void 0 ? void 0 : _config$fileUpload.fileExtensions;
  127. if (!isMaster && fileExtensions) {
  128. var _extension;
  129. const isValidExtension = extension => {
  130. return fileExtensions.some(ext => {
  131. if (ext === '*') {
  132. return true;
  133. }
  134. const regex = new RegExp(ext);
  135. if (regex.test(extension)) {
  136. return true;
  137. }
  138. });
  139. };
  140. let extension = contentType;
  141. if (filename && filename.includes('.')) {
  142. extension = filename.substring(filename.lastIndexOf('.') + 1);
  143. } else if (contentType && contentType.includes('/')) {
  144. extension = contentType.split('/')[1];
  145. }
  146. extension = (_extension = extension) === null || _extension === void 0 || (_extension = _extension.split(' ')) === null || _extension === void 0 ? void 0 : _extension.join('');
  147. if (extension && !isValidExtension(extension)) {
  148. next(new _node.default.Error(_node.default.Error.FILE_SAVE_ERROR, `File upload of extension ${extension} is disabled.`));
  149. return;
  150. }
  151. }
  152. const base64 = req.body.toString('base64');
  153. const file = new _node.default.File(filename, {
  154. base64
  155. }, contentType);
  156. const {
  157. metadata = {},
  158. tags = {}
  159. } = req.fileData || {};
  160. try {
  161. // Scan request data for denied keywords
  162. Utils.checkProhibitedKeywords(config, metadata);
  163. Utils.checkProhibitedKeywords(config, tags);
  164. } catch (error) {
  165. next(new _node.default.Error(_node.default.Error.INVALID_KEY_NAME, error));
  166. return;
  167. }
  168. file.setTags(tags);
  169. file.setMetadata(metadata);
  170. const fileSize = Buffer.byteLength(req.body);
  171. const fileObject = {
  172. file,
  173. fileSize
  174. };
  175. try {
  176. // run beforeSaveFile trigger
  177. const triggerResult = await triggers.maybeRunFileTrigger(triggers.Types.beforeSave, fileObject, config, req.auth);
  178. let saveResult;
  179. // if a new ParseFile is returned check if it's an already saved file
  180. if (triggerResult instanceof _node.default.File) {
  181. fileObject.file = triggerResult;
  182. if (triggerResult.url()) {
  183. // set fileSize to null because we wont know how big it is here
  184. fileObject.fileSize = null;
  185. saveResult = {
  186. url: triggerResult.url(),
  187. name: triggerResult._name
  188. };
  189. }
  190. }
  191. // if the file returned by the trigger has already been saved skip saving anything
  192. if (!saveResult) {
  193. // if the ParseFile returned is type uri, download the file before saving it
  194. await addFileDataIfNeeded(fileObject.file);
  195. // update fileSize
  196. const bufferData = Buffer.from(fileObject.file._data, 'base64');
  197. fileObject.fileSize = Buffer.byteLength(bufferData);
  198. // prepare file options
  199. const fileOptions = {
  200. metadata: fileObject.file._metadata
  201. };
  202. // some s3-compatible providers (DigitalOcean, Linode) do not accept tags
  203. // so we do not include the tags option if it is empty.
  204. const fileTags = Object.keys(fileObject.file._tags).length > 0 ? {
  205. tags: fileObject.file._tags
  206. } : {};
  207. Object.assign(fileOptions, fileTags);
  208. // save file
  209. const createFileResult = await filesController.createFile(config, fileObject.file._name, bufferData, fileObject.file._source.type, fileOptions);
  210. // update file with new data
  211. fileObject.file._name = createFileResult.name;
  212. fileObject.file._url = createFileResult.url;
  213. fileObject.file._requestTask = null;
  214. fileObject.file._previousSave = Promise.resolve(fileObject.file);
  215. saveResult = {
  216. url: createFileResult.url,
  217. name: createFileResult.name
  218. };
  219. }
  220. // run afterSaveFile trigger
  221. await triggers.maybeRunFileTrigger(triggers.Types.afterSave, fileObject, config, req.auth);
  222. res.status(201);
  223. res.set('Location', saveResult.url);
  224. res.json(saveResult);
  225. } catch (e) {
  226. _logger.default.error('Error creating a file: ', e);
  227. const error = triggers.resolveError(e, {
  228. code: _node.default.Error.FILE_SAVE_ERROR,
  229. message: `Could not store file: ${fileObject.file._name}.`
  230. });
  231. next(error);
  232. }
  233. }
  234. async deleteHandler(req, res, next) {
  235. try {
  236. const {
  237. filesController
  238. } = req.config;
  239. const {
  240. filename
  241. } = req.params;
  242. // run beforeDeleteFile trigger
  243. const file = new _node.default.File(filename);
  244. file._url = await filesController.adapter.getFileLocation(req.config, filename);
  245. const fileObject = {
  246. file,
  247. fileSize: null
  248. };
  249. await triggers.maybeRunFileTrigger(triggers.Types.beforeDelete, fileObject, req.config, req.auth);
  250. // delete file
  251. await filesController.deleteFile(req.config, filename);
  252. // run afterDeleteFile trigger
  253. await triggers.maybeRunFileTrigger(triggers.Types.afterDelete, fileObject, req.config, req.auth);
  254. res.status(200);
  255. // TODO: return useful JSON here?
  256. res.end();
  257. } catch (e) {
  258. _logger.default.error('Error deleting a file: ', e);
  259. const error = triggers.resolveError(e, {
  260. code: _node.default.Error.FILE_DELETE_ERROR,
  261. message: 'Could not delete file.'
  262. });
  263. next(error);
  264. }
  265. }
  266. async metadataHandler(req, res) {
  267. try {
  268. const config = _Config.default.get(req.params.appId);
  269. const {
  270. filesController
  271. } = config;
  272. const {
  273. filename
  274. } = req.params;
  275. const data = await filesController.getMetadata(filename);
  276. res.status(200);
  277. res.json(data);
  278. } catch (e) {
  279. res.status(200);
  280. res.json({});
  281. }
  282. }
  283. }
  284. exports.FilesRouter = FilesRouter;
  285. function isFileStreamable(req, filesController) {
  286. const range = (req.get('Range') || '/-/').split('-');
  287. const start = Number(range[0]);
  288. const end = Number(range[1]);
  289. return (!isNaN(start) || !isNaN(end)) && typeof filesController.adapter.handleFileStream === 'function';
  290. }
  291. //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfZXhwcmVzcyIsIl9pbnRlcm9wUmVxdWlyZURlZmF1bHQiLCJyZXF1aXJlIiwiX2JvZHlQYXJzZXIiLCJNaWRkbGV3YXJlcyIsIl9pbnRlcm9wUmVxdWlyZVdpbGRjYXJkIiwiX25vZGUiLCJfQ29uZmlnIiwiX21pbWUiLCJfbG9nZ2VyIiwiX2dldFJlcXVpcmVXaWxkY2FyZENhY2hlIiwiZSIsIldlYWtNYXAiLCJyIiwidCIsIl9fZXNNb2R1bGUiLCJkZWZhdWx0IiwiaGFzIiwiZ2V0IiwibiIsIl9fcHJvdG9fXyIsImEiLCJPYmplY3QiLCJkZWZpbmVQcm9wZXJ0eSIsImdldE93blByb3BlcnR5RGVzY3JpcHRvciIsInUiLCJoYXNPd25Qcm9wZXJ0eSIsImNhbGwiLCJpIiwic2V0IiwidHJpZ2dlcnMiLCJodHRwIiwiVXRpbHMiLCJkb3dubG9hZEZpbGVGcm9tVVJJIiwidXJpIiwiUHJvbWlzZSIsInJlcyIsInJlaiIsInJlc3BvbnNlIiwic2V0RGVmYXVsdEVuY29kaW5nIiwiYm9keSIsImhlYWRlcnMiLCJvbiIsImRhdGEiLCJtZXNzYWdlIiwiYWRkRmlsZURhdGFJZk5lZWRlZCIsImZpbGUiLCJfc291cmNlIiwiZm9ybWF0IiwiYmFzZTY0IiwiX3ByZXZpb3VzU2F2ZSIsIl9kYXRhIiwiX3JlcXVlc3RUYXNrIiwiRmlsZXNSb3V0ZXIiLCJleHByZXNzUm91dGVyIiwibWF4VXBsb2FkU2l6ZSIsInJvdXRlciIsImV4cHJlc3MiLCJSb3V0ZXIiLCJnZXRIYW5kbGVyIiwibWV0YWRhdGFIYW5kbGVyIiwicG9zdCIsInJlcSIsIm5leHQiLCJQYXJzZSIsIkVycm9yIiwiSU5WQUxJRF9GSUxFX05BTUUiLCJCb2R5UGFyc2VyIiwicmF3IiwidHlwZSIsImxpbWl0IiwiaGFuZGxlUGFyc2VIZWFkZXJzIiwiaGFuZGxlUGFyc2VTZXNzaW9uIiwiY3JlYXRlSGFuZGxlciIsImRlbGV0ZSIsImVuZm9yY2VNYXN0ZXJLZXlBY2Nlc3MiLCJkZWxldGVIYW5kbGVyIiwiY29uZmlnIiwiQ29uZmlnIiwicGFyYW1zIiwiYXBwSWQiLCJzdGF0dXMiLCJlcnIiLCJPUEVSQVRJT05fRk9SQklEREVOIiwianNvbiIsImNvZGUiLCJlcnJvciIsImZpbGVzQ29udHJvbGxlciIsImZpbGVuYW1lIiwiY29udGVudFR5cGUiLCJtaW1lIiwiZ2V0VHlwZSIsImlzRmlsZVN0cmVhbWFibGUiLCJoYW5kbGVGaWxlU3RyZWFtIiwiY2F0Y2giLCJlbmQiLCJnZXRGaWxlRGF0YSIsInRoZW4iLCJsZW5ndGgiLCJfY29uZmlnJGZpbGVVcGxvYWQiLCJ1c2VyIiwiYXV0aCIsImlzTWFzdGVyIiwiaXNMaW5rZWQiLCJBbm9ueW1vdXNVdGlscyIsImZpbGVVcGxvYWQiLCJlbmFibGVGb3JBbm9ueW1vdXNVc2VyIiwiRklMRV9TQVZFX0VSUk9SIiwiZW5hYmxlRm9yQXV0aGVudGljYXRlZFVzZXIiLCJlbmFibGVGb3JQdWJsaWMiLCJ2YWxpZGF0ZUZpbGVuYW1lIiwiZmlsZUV4dGVuc2lvbnMiLCJfZXh0ZW5zaW9uIiwiaXNWYWxpZEV4dGVuc2lvbiIsImV4dGVuc2lvbiIsInNvbWUiLCJleHQiLCJyZWdleCIsIlJlZ0V4cCIsInRlc3QiLCJpbmNsdWRlcyIsInN1YnN0cmluZyIsImxhc3RJbmRleE9mIiwic3BsaXQiLCJqb2luIiwidG9TdHJpbmciLCJGaWxlIiwibWV0YWRhdGEiLCJ0YWdzIiwiZmlsZURhdGEiLCJjaGVja1Byb2hpYml0ZWRLZXl3b3JkcyIsIklOVkFMSURfS0VZX05BTUUiLCJzZXRUYWdzIiwic2V0TWV0YWRhdGEiLCJmaWxlU2l6ZSIsIkJ1ZmZlciIsImJ5dGVMZW5ndGgiLCJmaWxlT2JqZWN0IiwidHJpZ2dlclJlc3VsdCIsIm1heWJlUnVuRmlsZVRyaWdnZXIiLCJUeXBlcyIsImJlZm9yZVNhdmUiLCJzYXZlUmVzdWx0IiwidXJsIiwibmFtZSIsIl9uYW1lIiwiYnVmZmVyRGF0YSIsImZyb20iLCJmaWxlT3B0aW9ucyIsIl9tZXRhZGF0YSIsImZpbGVUYWdzIiwia2V5cyIsIl90YWdzIiwiYXNzaWduIiwiY3JlYXRlRmlsZVJlc3VsdCIsImNyZWF0ZUZpbGUiLCJfdXJsIiwicmVzb2x2ZSIsImFmdGVyU2F2ZSIsImxvZ2dlciIsInJlc29sdmVFcnJvciIsImFkYXB0ZXIiLCJnZXRGaWxlTG9jYXRpb24iLCJiZWZvcmVEZWxldGUiLCJkZWxldGVGaWxlIiwiYWZ0ZXJEZWxldGUiLCJGSUxFX0RFTEVURV9FUlJPUiIsImdldE1ldGFkYXRhIiwiZXhwb3J0cyIsInJhbmdlIiwic3RhcnQiLCJOdW1iZXIiLCJpc05hTiJdLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9Sb3V0ZXJzL0ZpbGVzUm91dGVyLmpzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBleHByZXNzIGZyb20gJ2V4cHJlc3MnO1xuaW1wb3J0IEJvZHlQYXJzZXIgZnJvbSAnYm9keS1wYXJzZXInO1xuaW1wb3J0ICogYXMgTWlkZGxld2FyZXMgZnJvbSAnLi4vbWlkZGxld2FyZXMnO1xuaW1wb3J0IFBhcnNlIGZyb20gJ3BhcnNlL25vZGUnO1xuaW1wb3J0IENvbmZpZyBmcm9tICcuLi9Db25maWcnO1xuaW1wb3J0IG1pbWUgZnJvbSAnbWltZSc7XG5pbXBvcnQgbG9nZ2VyIGZyb20gJy4uL2xvZ2dlcic7XG5jb25zdCB0cmlnZ2VycyA9IHJlcXVpcmUoJy4uL3RyaWdnZXJzJyk7XG5jb25zdCBodHRwID0gcmVxdWlyZSgnaHR0cCcpO1xuY29uc3QgVXRpbHMgPSByZXF1aXJlKCcuLi9VdGlscycpO1xuXG5jb25zdCBkb3dubG9hZEZpbGVGcm9tVVJJID0gdXJpID0+IHtcbiAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXMsIHJlaikgPT4ge1xuICAgIGh0dHBcbiAgICAgIC5nZXQodXJpLCByZXNwb25zZSA9PiB7XG4gICAgICAgIHJlc3BvbnNlLnNldERlZmF1bHRFbmNvZGluZygnYmFzZTY0Jyk7XG4gICAgICAgIGxldCBib2R5ID0gYGRhdGE6JHtyZXNwb25zZS5oZWFkZXJzWydjb250ZW50LXR5cGUnXX07YmFzZTY0LGA7XG4gICAgICAgIHJlc3BvbnNlLm9uKCdkYXRhJywgZGF0YSA9PiAoYm9keSArPSBkYXRhKSk7XG4gICAgICAgIHJlc3BvbnNlLm9uKCdlbmQnLCAoKSA9PiByZXMoYm9keSkpO1xuICAgICAgfSlcbiAgICAgIC5vbignZXJyb3InLCBlID0+IHtcbiAgICAgICAgcmVqKGBFcnJvciBkb3dubG9hZGluZyBmaWxlIGZyb20gJHt1cml9OiAke2UubWVzc2FnZX1gKTtcbiAgICAgIH0pO1xuICB9KTtcbn07XG5cbmNvbnN0IGFkZEZpbGVEYXRhSWZOZWVkZWQgPSBhc3luYyBmaWxlID0+IHtcbiAgaWYgKGZpbGUuX3NvdXJjZS5mb3JtYXQgPT09ICd1cmknKSB7XG4gICAgY29uc3QgYmFzZTY0ID0gYXdhaXQgZG93bmxvYWRGaWxlRnJvbVVSSShmaWxlLl9zb3VyY2UudXJpKTtcbiAgICBmaWxlLl9wcmV2aW91c1NhdmUgPSBmaWxlO1xuICAgIGZpbGUuX2RhdGEgPSBiYXNlNjQ7XG4gICAgZmlsZS5fcmVxdWVzdFRhc2sgPSBudWxsO1xuICB9XG4gIHJldHVybiBmaWxlO1xufTtcblxuZXhwb3J0IGNsYXNzIEZpbGVzUm91dGVyIHtcbiAgZXhwcmVzc1JvdXRlcih7IG1heFVwbG9hZFNpemUgPSAnMjBNYicgfSA9IHt9KSB7XG4gICAgdmFyIHJvdXRlciA9IGV4cHJlc3MuUm91dGVyKCk7XG4gICAgcm91dGVyLmdldCgnL2ZpbGVzLzphcHBJZC86ZmlsZW5hbWUnLCB0aGlzLmdldEhhbmRsZXIpO1xuICAgIHJvdXRlci5nZXQoJy9maWxlcy86YXBwSWQvbWV0YWRhdGEvOmZpbGVuYW1lJywgdGhpcy5tZXRhZGF0YUhhbmRsZXIpO1xuXG4gICAgcm91dGVyLnBvc3QoJy9maWxlcycsIGZ1bmN0aW9uIChyZXEsIHJlcywgbmV4dCkge1xuICAgICAgbmV4dChuZXcgUGFyc2UuRXJyb3IoUGFyc2UuRXJyb3IuSU5WQUxJRF9GSUxFX05BTUUsICdGaWxlbmFtZSBub3QgcHJvdmlkZWQuJykpO1xuICAgIH0pO1xuXG4gICAgcm91dGVyLnBvc3QoXG4gICAgICAnL2ZpbGVzLzpmaWxlbmFtZScsXG4gICAgICBCb2R5UGFyc2VyLnJhdyh7XG4gICAgICAgIHR5cGU6ICgpID0+IHtcbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfSxcbiAgICAgICAgbGltaXQ6IG1heFVwbG9hZFNpemUsXG4gICAgICB9KSwgLy8gQWxsb3cgdXBsb2FkcyB3aXRob3V0IENvbnRlbnQtVHlwZSwgb3Igd2l0aCBhbnkgQ29udGVudC1UeXBlLlxuICAgICAgTWlkZGxld2FyZXMuaGFuZGxlUGFyc2VIZWFkZXJzLFxuICAgICAgTWlkZGxld2FyZXMuaGFuZGxlUGFyc2VTZXNzaW9uLFxuICAgICAgdGhpcy5jcmVhdGVIYW5kbGVyXG4gICAgKTtcblxuICAgIHJvdXRlci5kZWxldGUoXG4gICAgICAnL2ZpbGVzLzpmaWxlbmFtZScsXG4gICAgICBNaWRkbGV3YXJlcy5oYW5kbGVQYXJzZUhlYWRlcnMsXG4gICAgICBNaWRkbGV3YXJlcy5oYW5kbGVQYXJzZVNlc3Npb24sXG4gICAgICBNaWRkbGV3YXJlcy5lbmZvcmNlTWFzdGVyS2V5QWNjZXNzLFxuICAgICAgdGhpcy5kZWxldGVIYW5kbGVyXG4gICAgKTtcbiAgICByZXR1cm4gcm91dGVyO1xuICB9XG5cbiAgZ2V0SGFuZGxlcihyZXEsIHJlcykge1xuICAgIGNvbnN0IGNvbmZpZyA9IENvbmZpZy5nZXQocmVxLnBhcmFtcy5hcHBJZCk7XG4gICAgaWYgKCFjb25maWcpIHtcbiAgICAgIHJlcy5zdGF0dXMoNDAzKTtcbiAgICAgIGNvbnN0IGVyciA9IG5ldyBQYXJzZS5FcnJvcihQYXJzZS5FcnJvci5PUEVSQVRJT05fRk9SQklEREVOLCAnSW52YWxpZCBhcHBsaWNhdGlvbiBJRC4nKTtcbiAgICAgIHJlcy5qc29uKHsgY29kZTogZXJyLmNvZGUsIGVycm9yOiBlcnIubWVzc2FnZSB9KTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3QgZmlsZXNDb250cm9sbGVyID0gY29uZmlnLmZpbGVzQ29udHJvbGxlcjtcbiAgICBjb25zdCBmaWxlbmFtZSA9IHJlcS5wYXJhbXMuZmlsZW5hbWU7XG4gICAgY29uc3QgY29udGVudFR5cGUgPSBtaW1lLmdldFR5cGUoZmlsZW5hbWUpO1xuICAgIGlmIChpc0ZpbGVTdHJlYW1hYmxlKHJlcSwgZmlsZXNDb250cm9sbGVyKSkge1xuICAgICAgZmlsZXNDb250cm9sbGVyLmhhbmRsZUZpbGVTdHJlYW0oY29uZmlnLCBmaWxlbmFtZSwgcmVxLCByZXMsIGNvbnRlbnRUeXBlKS5jYXRjaCgoKSA9PiB7XG4gICAgICAgIHJlcy5zdGF0dXMoNDA0KTtcbiAgICAgICAgcmVzLnNldCgnQ29udGVudC1UeXBlJywgJ3RleHQvcGxhaW4nKTtcbiAgICAgICAgcmVzLmVuZCgnRmlsZSBub3QgZm91bmQuJyk7XG4gICAgICB9KTtcbiAgICB9IGVsc2Uge1xuICAgICAgZmlsZXNDb250cm9sbGVyXG4gICAgICAgIC5nZXRGaWxlRGF0YShjb25maWcsIGZpbGVuYW1lKVxuICAgICAgICAudGhlbihkYXRhID0+IHtcbiAgICAgICAgICByZXMuc3RhdHVzKDIwMCk7XG4gICAgICAgICAgcmVzLnNldCgnQ29udGVudC1UeXBlJywgY29udGVudFR5cGUpO1xuICAgICAgICAgIHJlcy5zZXQoJ0NvbnRlbnQtTGVuZ3RoJywgZGF0YS5sZW5ndGgpO1xuICAgICAgICAgIHJlcy5lbmQoZGF0YSk7XG4gICAgICAgIH0pXG4gICAgICAgIC5jYXRjaCgoKSA9PiB7XG4gICAgICAgICAgcmVzLnN0YXR1cyg0MDQpO1xuICAgICAgICAgIHJlcy5zZXQoJ0NvbnRlbnQtVHlwZScsICd0ZXh0L3BsYWluJyk7XG4gICAgICAgICAgcmVzLmVuZCgnRmlsZSBub3QgZm91bmQuJyk7XG4gICAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIGFzeW5jIGNyZWF0ZUhhbmRsZXIocmVxLCByZXMsIG5leHQpIHtcbiAgICBjb25zdCBjb25maWcgPSByZXEuY29uZmlnO1xuICAgIGNvbnN0IHVzZXIgPSByZXEuYXV0aC51c2VyO1xuICAgIGNvbnN0IGlzTWFzdGVyID0gcmVxLmF1dGguaXNNYXN0ZXI7XG4gICAgY29uc3QgaXNMaW5rZWQgPSB1c2VyICYmIFBhcnNlLkFub255bW91c1V0aWxzLmlzTGlua2VkKHVzZXIpO1xuICAgIGlmICghaXNNYXN0ZXIgJiYgIWNvbmZpZy5maWxlVXBsb2FkLmVuYWJsZUZvckFub255bW91c1VzZXIgJiYgaXNMaW5rZWQpIHtcbiAgICAgIG5leHQoXG4gICAgICAgIG5ldyBQYXJzZS5FcnJvcihQYXJzZS5FcnJvci5GSUxFX1NBVkVfRVJST1IsICdGaWxlIHVwbG9hZCBieSBhbm9ueW1vdXMgdXNlciBpcyBkaXNhYmxlZC4nKVxuICAgICAgKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgaWYgKCFpc01hc3RlciAmJiAhY29uZmlnLmZpbGVVcGxvYWQuZW5hYmxlRm9yQXV0aGVudGljYXRlZFVzZXIgJiYgIWlzTGlua2VkICYmIHVzZXIpIHtcbiAgICAgIG5leHQoXG4gICAgICAgIG5ldyBQYXJzZS5FcnJvcihcbiAgICAgICAgICBQYXJzZS5FcnJvci5GSUxFX1NBVkVfRVJST1IsXG4gICAgICAgICAgJ0ZpbGUgdXBsb2FkIGJ5IGF1dGhlbnRpY2F0ZWQgdXNlciBpcyBkaXNhYmxlZC4nXG4gICAgICAgIClcbiAgICAgICk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGlmICghaXNNYXN0ZXIgJiYgIWNvbmZpZy5maWxlVXBsb2FkLmVuYWJsZUZvclB1YmxpYyAmJiAhdXNlcikge1xuICAgICAgbmV4dChuZXcgUGFyc2UuRXJyb3IoUGFyc2UuRXJyb3IuRklMRV9TQVZFX0VSUk9SLCAnRmlsZSB1cGxvYWQgYnkgcHVibGljIGlzIGRpc2FibGVkLicpKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3QgZmlsZXNDb250cm9sbGVyID0gY29uZmlnLmZpbGVzQ29udHJvbGxlcjtcbiAgICBjb25zdCB7IGZpbGVuYW1lIH0gPSByZXEucGFyYW1zO1xuICAgIGNvbnN0IGNvbnRlbnRUeXBlID0gcmVxLmdldCgnQ29udGVudC10eXBlJyk7XG5cbiAgICBpZiAoIXJlcS5ib2R5IHx8ICFyZXEuYm9keS5sZW5ndGgpIHtcbiAgICAgIG5leHQobmV3IFBhcnNlLkVycm9yKFBhcnNlLkVycm9yLkZJTEVfU0FWRV9FUlJPUiwgJ0ludmFsaWQgZmlsZSB1cGxvYWQuJykpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IGVycm9yID0gZmlsZXNDb250cm9sbGVyLnZhbGlkYXRlRmlsZW5hbWUoZmlsZW5hbWUpO1xuICAgIGlmIChlcnJvcikge1xuICAgICAgbmV4dChlcnJvcik7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgZmlsZUV4dGVuc2lvbnMgPSBjb25maWcuZmlsZVVwbG9hZD8uZmlsZUV4dGVuc2lvbnM7XG4gICAgaWYgKCFpc01hc3RlciAmJiBmaWxlRXh0ZW5zaW9ucykge1xuICAgICAgY29uc3QgaXNWYWxpZEV4dGVuc2lvbiA9IGV4dGVuc2lvbiA9PiB7XG4gICAgICAgIHJldHVybiBmaWxlRXh0ZW5zaW9ucy5zb21lKGV4dCA9PiB7XG4gICAgICAgICAgaWYgKGV4dCA9PT0gJyonKSB7XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICB9XG4gICAgICAgICAgY29uc3QgcmVnZXggPSBuZXcgUmVnRXhwKGV4dCk7XG4gICAgICAgICAgaWYgKHJlZ2V4LnRlc3QoZXh0ZW5zaW9uKSkge1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgIH07XG4gICAgICBsZXQgZXh0ZW5zaW9uID0gY29udGVudFR5cGU7XG4gICAgICBpZiAoZmlsZW5hbWUgJiYgZmlsZW5hbWUuaW5jbHVkZXMoJy4nKSkge1xuICAgICAgICBleHRlbnNpb24gPSBmaWxlbmFtZS5zdWJzdHJpbmcoZmlsZW5hbWUubGFzdEluZGV4T2YoJy4nKSArIDEpO1xuICAgICAgfSBlbHNlIGlmIChjb250ZW50VHlwZSAmJiBjb250ZW50VHlwZS5pbmNsdWRlcygnLycpKSB7XG4gICAgICAgIGV4dGVuc2lvbiA9IGNvbnRlbnRUeXBlLnNwbGl0KCcvJylbMV07XG4gICAgICB9XG4gICAgICBleHRlbnNpb24gPSBleHRlbnNpb24/LnNwbGl0KCcgJyk/LmpvaW4oJycpO1xuXG4gICAgICBpZiAoZXh0ZW5zaW9uICYmICFpc1ZhbGlkRXh0ZW5zaW9uKGV4dGVuc2lvbikpIHtcbiAgICAgICAgbmV4dChcbiAgICAgICAgICBuZXcgUGFyc2UuRXJyb3IoXG4gICAgICAgICAgICBQYXJzZS5FcnJvci5GSUxFX1NBVkVfRVJST1IsXG4gICAgICAgICAgICBgRmlsZSB1cGxvYWQgb2YgZXh0ZW5zaW9uICR7ZXh0ZW5zaW9ufSBpcyBkaXNhYmxlZC5gXG4gICAgICAgICAgKVxuICAgICAgICApO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgfVxuXG4gICAgY29uc3QgYmFzZTY0ID0gcmVxLmJvZHkudG9TdHJpbmcoJ2Jhc2U2NCcpO1xuICAgIGNvbnN0IGZpbGUgPSBuZXcgUGFyc2UuRmlsZShmaWxlbmFtZSwgeyBiYXNlNjQgfSwgY29udGVudFR5cGUpO1xuICAgIGNvbnN0IHsgbWV0YWRhdGEgPSB7fSwgdGFncyA9IHt9IH0gPSByZXEuZmlsZURhdGEgfHwge307XG4gICAgdHJ5IHtcbiAgICAgIC8vIFNjYW4gcmVxdWVzdCBkYXRhIGZvciBkZW5pZWQga2V5d29yZHNcbiAgICAgIFV0aWxzLmNoZWNrUHJvaGliaXRlZEtleXdvcmRzKGNvbmZpZywgbWV0YWRhdGEpO1xuICAgICAgVXRpbHMuY2hlY2tQcm9oaWJpdGVkS2V5d29yZHMoY29uZmlnLCB0YWdzKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgbmV4dChuZXcgUGFyc2UuRXJyb3IoUGFyc2UuRXJyb3IuSU5WQUxJRF9LRVlfTkFNRSwgZXJyb3IpKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgZmlsZS5zZXRUYWdzKHRhZ3MpO1xuICAgIGZpbGUuc2V0TWV0YWRhdGEobWV0YWRhdGEpO1xuICAgIGNvbnN0IGZpbGVTaXplID0gQnVmZmVyLmJ5dGVMZW5ndGgocmVxLmJvZHkpO1xuICAgIGNvbnN0IGZpbGVPYmplY3QgPSB7IGZpbGUsIGZpbGVTaXplIH07XG4gICAgdHJ5IHtcbiAgICAgIC8vIHJ1biBiZWZvcmVTYXZlRmlsZSB0cmlnZ2VyXG4gICAgICBjb25zdCB0cmlnZ2VyUmVzdWx0ID0gYXdhaXQgdHJpZ2dlcnMubWF5YmVSdW5GaWxlVHJpZ2dlcihcbiAgICAgICAgdHJpZ2dlcnMuVHlwZXMuYmVmb3JlU2F2ZSxcbiAgICAgICAgZmlsZU9iamVjdCxcbiAgICAgICAgY29uZmlnLFxuICAgICAgICByZXEuYXV0aFxuICAgICAgKTtcbiAgICAgIGxldCBzYXZlUmVzdWx0O1xuICAgICAgLy8gaWYgYSBuZXcgUGFyc2VGaWxlIGlzIHJldHVybmVkIGNoZWNrIGlmIGl0J3MgYW4gYWxyZWFkeSBzYXZlZCBmaWxlXG4gICAgICBpZiAodHJpZ2dlclJlc3VsdCBpbnN0YW5jZW9mIFBhcnNlLkZpbGUpIHtcbiAgICAgICAgZmlsZU9iamVjdC5maWxlID0gdHJpZ2dlclJlc3VsdDtcbiAgICAgICAgaWYgKHRyaWdnZXJSZXN1bHQudXJsKCkpIHtcbiAgICAgICAgICAvLyBzZXQgZmlsZVNpemUgdG8gbnVsbCBiZWNhdXNlIHdlIHdvbnQga25vdyBob3cgYmlnIGl0IGlzIGhlcmVcbiAgICAgICAgICBmaWxlT2JqZWN0LmZpbGVTaXplID0gbnVsbDtcbiAgICAgICAgICBzYXZlUmVzdWx0ID0ge1xuICAgICAgICAgICAgdXJsOiB0cmlnZ2VyUmVzdWx0LnVybCgpLFxuICAgICAgICAgICAgbmFtZTogdHJpZ2dlclJlc3VsdC5fbmFtZSxcbiAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICAvLyBpZiB0aGUgZmlsZSByZXR1cm5lZCBieSB0aGUgdHJpZ2dlciBoYXMgYWxyZWFkeSBiZWVuIHNhdmVkIHNraXAgc2F2aW5nIGFueXRoaW5nXG4gICAgICBpZiAoIXNhdmVSZXN1bHQpIHtcbiAgICAgICAgLy8gaWYgdGhlIFBhcnNlRmlsZSByZXR1cm5lZCBpcyB0eXBlIHVyaSwgZG93bmxvYWQgdGhlIGZpbGUgYmVmb3JlIHNhdmluZyBpdFxuICAgICAgICBhd2FpdCBhZGRGaWxlRGF0YUlmTmVlZGVkKGZpbGVPYmplY3QuZmlsZSk7XG4gICAgICAgIC8vIHVwZGF0ZSBmaWxlU2l6ZVxuICAgICAgICBjb25zdCBidWZmZXJEYXRhID0gQnVmZmVyLmZyb20oZmlsZU9iamVjdC5maWxlLl9kYXRhLCAnYmFzZTY0Jyk7XG4gICAgICAgIGZpbGVPYmplY3QuZmlsZVNpemUgPSBCdWZmZXIuYnl0ZUxlbmd0aChidWZmZXJEYXRhKTtcbiAgICAgICAgLy8gcHJlcGFyZSBmaWxlIG9wdGlvbnNcbiAgICAgICAgY29uc3QgZmlsZU9wdGlvbnMgPSB7XG4gICAgICAgICAgbWV0YWRhdGE6IGZpbGVPYmplY3QuZmlsZS5fbWV0YWRhdGEsXG4gICAgICAgIH07XG4gICAgICAgIC8vIHNvbWUgczMtY29tcGF0aWJsZSBwcm92aWRlcnMgKERpZ2l0YWxPY2VhbiwgTGlub2RlKSBkbyBub3QgYWNjZXB0IHRhZ3NcbiAgICAgICAgLy8gc28gd2UgZG8gbm90IGluY2x1ZGUgdGhlIHRhZ3Mgb3B0aW9uIGlmIGl0IGlzIGVtcHR5LlxuICAgICAgICBjb25zdCBmaWxlVGFncyA9XG4gICAgICAgICAgT2JqZWN0LmtleXMoZmlsZU9iamVjdC5maWxlLl90YWdzKS5sZW5ndGggPiAwID8geyB0YWdzOiBmaWxlT2JqZWN0LmZpbGUuX3RhZ3MgfSA6IHt9O1xuICAgICAgICBPYmplY3QuYXNzaWduKGZpbGVPcHRpb25zLCBmaWxlVGFncyk7XG4gICAgICAgIC8vIHNhdmUgZmlsZVxuICAgICAgICBjb25zdCBjcmVhdGVGaWxlUmVzdWx0ID0gYXdhaXQgZmlsZXNDb250cm9sbGVyLmNyZWF0ZUZpbGUoXG4gICAgICAgICAgY29uZmlnLFxuICAgICAgICAgIGZpbGVPYmplY3QuZmlsZS5fbmFtZSxcbiAgICAgICAgICBidWZmZXJEYXRhLFxuICAgICAgICAgIGZpbGVPYmplY3QuZmlsZS5fc291cmNlLnR5cGUsXG4gICAgICAgICAgZmlsZU9wdGlvbnNcbiAgICAgICAgKTtcbiAgICAgICAgLy8gdXBkYXRlIGZpbGUgd2l0aCBuZXcgZGF0YVxuICAgICAgICBmaWxlT2JqZWN0LmZpbGUuX25hbWUgPSBjcmVhdGVGaWxlUmVzdWx0Lm5hbWU7XG4gICAgICAgIGZpbGVPYmplY3QuZmlsZS5fdXJsID0gY3JlYXRlRmlsZVJlc3VsdC51cmw7XG4gICAgICAgIGZpbGVPYmplY3QuZmlsZS5fcmVxdWVzdFRhc2sgPSBudWxsO1xuICAgICAgICBmaWxlT2JqZWN0LmZpbGUuX3ByZXZpb3VzU2F2ZSA9IFByb21pc2UucmVzb2x2ZShmaWxlT2JqZWN0LmZpbGUpO1xuICAgICAgICBzYXZlUmVzdWx0ID0ge1xuICAgICAgICAgIHVybDogY3JlYXRlRmlsZVJlc3VsdC51cmwsXG4gICAgICAgICAgbmFtZTogY3JlYXRlRmlsZVJlc3VsdC5uYW1lLFxuICAgICAgICB9O1xuICAgICAgfVxuICAgICAgLy8gcnVuIGFmdGVyU2F2ZUZpbGUgdHJpZ2dlclxuICAgICAgYXdhaXQgdHJpZ2dlcnMubWF5YmVSdW5GaWxlVHJpZ2dlcih0cmlnZ2Vycy5UeXBlcy5hZnRlclNhdmUsIGZpbGVPYmplY3QsIGNvbmZpZywgcmVxLmF1dGgpO1xuICAgICAgcmVzLnN0YXR1cygyMDEpO1xuICAgICAgcmVzLnNldCgnTG9jYXRpb24nLCBzYXZlUmVzdWx0LnVybCk7XG4gICAgICByZXMuanNvbihzYXZlUmVzdWx0KTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICBsb2dnZXIuZXJyb3IoJ0Vycm9yIGNyZWF0aW5nIGEgZmlsZTogJywgZSk7XG4gICAgICBjb25zdCBlcnJvciA9IHRyaWdnZXJzLnJlc29sdmVFcnJvcihlLCB7XG4gICAgICAgIGNvZGU6IFBhcnNlLkVycm9yLkZJTEVfU0FWRV9FUlJPUixcbiAgICAgICAgbWVzc2FnZTogYENvdWxkIG5vdCBzdG9yZSBmaWxlOiAke2ZpbGVPYmplY3QuZmlsZS5fbmFtZX0uYCxcbiAgICAgIH0pO1xuICAgICAgbmV4dChlcnJvcik7XG4gICAgfVxuICB9XG5cbiAgYXN5bmMgZGVsZXRlSGFuZGxlcihyZXEsIHJlcywgbmV4dCkge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCB7IGZpbGVzQ29udHJvbGxlciB9ID0gcmVxLmNvbmZpZztcbiAgICAgIGNvbnN0IHsgZmlsZW5hbWUgfSA9IHJlcS5wYXJhbXM7XG4gICAgICAvLyBydW4gYmVmb3JlRGVsZXRlRmlsZSB0cmlnZ2VyXG4gICAgICBjb25zdCBmaWxlID0gbmV3IFBhcnNlLkZpbGUoZmlsZW5hbWUpO1xuICAgICAgZmlsZS5fdXJsID0gYXdhaXQgZmlsZXNDb250cm9sbGVyLmFkYXB0ZXIuZ2V0RmlsZUxvY2F0aW9uKHJlcS5jb25maWcsIGZpbGVuYW1lKTtcbiAgICAgIGNvbnN0IGZpbGVPYmplY3QgPSB7IGZpbGUsIGZpbGVTaXplOiBudWxsIH07XG4gICAgICBhd2FpdCB0cmlnZ2Vycy5tYXliZVJ1bkZpbGVUcmlnZ2VyKFxuICAgICAgICB0cmlnZ2Vycy5UeXBlcy5iZWZvcmVEZWxldGUsXG4gICAgICAgIGZpbGVPYmplY3QsXG4gICAgICAgIHJlcS5jb25maWcsXG4gICAgICAgIHJlcS5hdXRoXG4gICAgICApO1xuICAgICAgLy8gZGVsZXRlIGZpbGVcbiAgICAgIGF3YWl0IGZpbGVzQ29udHJvbGxlci5kZWxldGVGaWxlKHJlcS5jb25maWcsIGZpbGVuYW1lKTtcbiAgICAgIC8vIHJ1biBhZnRlckRlbGV0ZUZpbGUgdHJpZ2dlclxuICAgICAgYXdhaXQgdHJpZ2dlcnMubWF5YmVSdW5GaWxlVHJpZ2dlcihcbiAgICAgICAgdHJpZ2dlcnMuVHlwZXMuYWZ0ZXJEZWxldGUsXG4gICAgICAgIGZpbGVPYmplY3QsXG4gICAgICAgIHJlcS5jb25maWcsXG4gICAgICAgIHJlcS5hdXRoXG4gICAgICApO1xuICAgICAgcmVzLnN0YXR1cygyMDApO1xuICAgICAgLy8gVE9ETzogcmV0dXJuIHVzZWZ1bCBKU09OIGhlcmU/XG4gICAgICByZXMuZW5kKCk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgbG9nZ2VyLmVycm9yKCdFcnJvciBkZWxldGluZyBhIGZpbGU6ICcsIGUpO1xuICAgICAgY29uc3QgZXJyb3IgPSB0cmlnZ2Vycy5yZXNvbHZlRXJyb3IoZSwge1xuICAgICAgICBjb2RlOiBQYXJzZS5FcnJvci5GSUxFX0RFTEVURV9FUlJPUixcbiAgICAgICAgbWVzc2FnZTogJ0NvdWxkIG5vdCBkZWxldGUgZmlsZS4nLFxuICAgICAgfSk7XG4gICAgICBuZXh0KGVycm9yKTtcbiAgICB9XG4gIH1cblxuICBhc3luYyBtZXRhZGF0YUhhbmRsZXIocmVxLCByZXMpIHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgY29uZmlnID0gQ29uZmlnLmdldChyZXEucGFyYW1zLmFwcElkKTtcbiAgICAgIGNvbnN0IHsgZmlsZXNDb250cm9sbGVyIH0gPSBjb25maWc7XG4gICAgICBjb25zdCB7IGZpbGVuYW1lIH0gPSByZXEucGFyYW1zO1xuICAgICAgY29uc3QgZGF0YSA9IGF3YWl0IGZpbGVzQ29udHJvbGxlci5nZXRNZXRhZGF0YShmaWxlbmFtZSk7XG4gICAgICByZXMuc3RhdHVzKDIwMCk7XG4gICAgICByZXMuanNvbihkYXRhKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICByZXMuc3RhdHVzKDIwMCk7XG4gICAgICByZXMuanNvbih7fSk7XG4gICAgfVxuICB9XG59XG5cbmZ1bmN0aW9uIGlzRmlsZVN0cmVhbWFibGUocmVxLCBmaWxlc0NvbnRyb2xsZXIpIHtcbiAgY29uc3QgcmFuZ2UgPSAocmVxLmdldCgnUmFuZ2UnKSB8fCAnLy0vJykuc3BsaXQoJy0nKTtcbiAgY29uc3Qgc3RhcnQgPSBOdW1iZXIocmFuZ2VbMF0pO1xuICBjb25zdCBlbmQgPSBOdW1iZXIocmFuZ2VbMV0pO1xuICByZXR1cm4gKFxuICAgICghaXNOYU4oc3RhcnQpIHx8ICFpc05hTihlbmQpKSAmJiB0eXBlb2YgZmlsZXNDb250cm9sbGVyLmFkYXB0ZXIuaGFuZGxlRmlsZVN0cmVhbSA9PT0gJ2Z1bmN0aW9uJ1xuICApO1xufVxuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQSxJQUFBQSxRQUFBLEdBQUFDLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBQyxXQUFBLEdBQUFGLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBRSxXQUFBLEdBQUFDLHVCQUFBLENBQUFILE9BQUE7QUFDQSxJQUFBSSxLQUFBLEdBQUFMLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBSyxPQUFBLEdBQUFOLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBTSxLQUFBLEdBQUFQLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBTyxPQUFBLEdBQUFSLHNCQUFBLENBQUFDLE9BQUE7QUFBK0IsU0FBQVEseUJBQUFDLENBQUEsNkJBQUFDLE9BQUEsbUJBQUFDLENBQUEsT0FBQUQsT0FBQSxJQUFBRSxDQUFBLE9BQUFGLE9BQUEsWUFBQUYsd0JBQUEsWUFBQUEsQ0FBQUMsQ0FBQSxXQUFBQSxDQUFBLEdBQUFHLENBQUEsR0FBQUQsQ0FBQSxLQUFBRixDQUFBO0FBQUEsU0FBQU4sd0JBQUFNLENBQUEsRUFBQUUsQ0FBQSxTQUFBQSxDQUFBLElBQUFGLENBQUEsSUFBQUEsQ0FBQSxDQUFBSSxVQUFBLFNBQUFKLENBQUEsZUFBQUEsQ0FBQSx1QkFBQUEsQ0FBQSx5QkFBQUEsQ0FBQSxXQUFBSyxPQUFBLEVBQUFMLENBQUEsUUFBQUcsQ0FBQSxHQUFBSix3QkFBQSxDQUFBRyxDQUFBLE9BQUFDLENBQUEsSUFBQUEsQ0FBQSxDQUFBRyxHQUFBLENBQUFOLENBQUEsVUFBQUcsQ0FBQSxDQUFBSSxHQUFBLENBQUFQLENBQUEsT0FBQVEsQ0FBQSxLQUFBQyxTQUFBLFVBQUFDLENBQUEs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QUNySixDQUFDLEVBQUU7UUFDckMwRSxJQUFJLEVBQUVyQixhQUFLLENBQUNDLEtBQUssQ0FBQ3FHLGlCQUFpQjtRQUNuQzFILE9BQU8sRUFBRTtNQUNYLENBQUMsQ0FBQztNQUNGbUIsSUFBSSxDQUFDdUIsS0FBSyxDQUFDO0lBQ2I7RUFDRjtFQUVBLE1BQU0xQixlQUFlQSxDQUFDRSxHQUFHLEVBQUUxQixHQUFHLEVBQUU7SUFDOUIsSUFBSTtNQUNGLE1BQU15QyxNQUFNLEdBQUdDLGVBQU0sQ0FBQzVELEdBQUcsQ0FBQzRDLEdBQUcsQ0FBQ2lCLE1BQU0sQ0FBQ0MsS0FBSyxDQUFDO01BQzNDLE1BQU07UUFBRU87TUFBZ0IsQ0FBQyxHQUFHVixNQUFNO01BQ2xDLE1BQU07UUFBRVc7TUFBUyxDQUFDLEdBQUcxQixHQUFHLENBQUNpQixNQUFNO01BQy9CLE1BQU1wQyxJQUFJLEdBQUcsTUFBTTRDLGVBQWUsQ0FBQ2dGLFdBQVcsQ0FBQy9FLFFBQVEsQ0FBQztNQUN4RHBELEdBQUcsQ0FBQzZDLE1BQU0sQ0FBQyxHQUFHLENBQUM7TUFDZjdDLEdBQUcsQ0FBQ2dELElBQUksQ0FBQ3pDLElBQUksQ0FBQztJQUNoQixDQUFDLENBQUMsT0FBT2hDLENBQUMsRUFBRTtNQUNWeUIsR0FBRyxDQUFDNkMsTUFBTSxDQUFDLEdBQUcsQ0FBQztNQUNmN0MsR0FBRyxDQUFDZ0QsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ2Q7RUFDRjtBQUNGO0FBQUNvRixPQUFBLENBQUFuSCxXQUFBLEdBQUFBLFdBQUE7QUFFRCxTQUFTdUMsZ0JBQWdCQSxDQUFDOUIsR0FBRyxFQUFFeUIsZUFBZSxFQUFFO0VBQzlDLE1BQU1rRixLQUFLLEdBQUcsQ0FBQzNHLEdBQUcsQ0FBQzVDLEdBQUcsQ0FBQyxPQUFPLENBQUMsSUFBSSxLQUFLLEVBQUV5RyxLQUFLLENBQUMsR0FBRyxDQUFDO0VBQ3BELE1BQU0rQyxLQUFLLEdBQUdDLE1BQU0sQ0FBQ0YsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDO0VBQzlCLE1BQU0xRSxHQUFHLEdBQUc0RSxNQUFNLENBQUNGLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQztFQUM1QixPQUNFLENBQUMsQ0FBQ0csS0FBSyxDQUFDRixLQUFLLENBQUMsSUFBSSxDQUFDRSxLQUFLLENBQUM3RSxHQUFHLENBQUMsS0FBSyxPQUFPUixlQUFlLENBQUMwRSxPQUFPLENBQUNwRSxnQkFBZ0IsS0FBSyxVQUFVO0FBRXBHIiwiaWdub3JlTGlzdCI6W119