videojs-media-session.js 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554
  1. (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.videojsMediaSession = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
  2. (function (process){
  3. // Copyright Joyent, Inc. and other Node contributors.
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a
  6. // copy of this software and associated documentation files (the
  7. // "Software"), to deal in the Software without restriction, including
  8. // without limitation the rights to use, copy, modify, merge, publish,
  9. // distribute, sublicense, and/or sell copies of the Software, and to permit
  10. // persons to whom the Software is furnished to do so, subject to the
  11. // following conditions:
  12. //
  13. // The above copyright notice and this permission notice shall be included
  14. // in all copies or substantial portions of the Software.
  15. //
  16. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  17. // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  18. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
  19. // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
  20. // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  21. // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
  22. // USE OR OTHER DEALINGS IN THE SOFTWARE.
  23. // resolves . and .. elements in a path array with directory names there
  24. // must be no slashes, empty elements, or device names (c:\) in the array
  25. // (so also no leading and trailing slashes - it does not distinguish
  26. // relative and absolute paths)
  27. function normalizeArray(parts, allowAboveRoot) {
  28. // if the path tries to go above the root, `up` ends up > 0
  29. var up = 0;
  30. for (var i = parts.length - 1; i >= 0; i--) {
  31. var last = parts[i];
  32. if (last === '.') {
  33. parts.splice(i, 1);
  34. } else if (last === '..') {
  35. parts.splice(i, 1);
  36. up++;
  37. } else if (up) {
  38. parts.splice(i, 1);
  39. up--;
  40. }
  41. }
  42. // if the path is allowed to go above the root, restore leading ..s
  43. if (allowAboveRoot) {
  44. for (; up--; up) {
  45. parts.unshift('..');
  46. }
  47. }
  48. return parts;
  49. }
  50. // Split a filename into [root, dir, basename, ext], unix version
  51. // 'root' is just a slash, or nothing.
  52. var splitPathRe =
  53. /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
  54. var splitPath = function(filename) {
  55. return splitPathRe.exec(filename).slice(1);
  56. };
  57. // path.resolve([from ...], to)
  58. // posix version
  59. exports.resolve = function() {
  60. var resolvedPath = '',
  61. resolvedAbsolute = false;
  62. for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
  63. var path = (i >= 0) ? arguments[i] : process.cwd();
  64. // Skip empty and invalid entries
  65. if (typeof path !== 'string') {
  66. throw new TypeError('Arguments to path.resolve must be strings');
  67. } else if (!path) {
  68. continue;
  69. }
  70. resolvedPath = path + '/' + resolvedPath;
  71. resolvedAbsolute = path.charAt(0) === '/';
  72. }
  73. // At this point the path should be resolved to a full absolute path, but
  74. // handle relative paths to be safe (might happen when process.cwd() fails)
  75. // Normalize the path
  76. resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) {
  77. return !!p;
  78. }), !resolvedAbsolute).join('/');
  79. return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
  80. };
  81. // path.normalize(path)
  82. // posix version
  83. exports.normalize = function(path) {
  84. var isAbsolute = exports.isAbsolute(path),
  85. trailingSlash = substr(path, -1) === '/';
  86. // Normalize the path
  87. path = normalizeArray(filter(path.split('/'), function(p) {
  88. return !!p;
  89. }), !isAbsolute).join('/');
  90. if (!path && !isAbsolute) {
  91. path = '.';
  92. }
  93. if (path && trailingSlash) {
  94. path += '/';
  95. }
  96. return (isAbsolute ? '/' : '') + path;
  97. };
  98. // posix version
  99. exports.isAbsolute = function(path) {
  100. return path.charAt(0) === '/';
  101. };
  102. // posix version
  103. exports.join = function() {
  104. var paths = Array.prototype.slice.call(arguments, 0);
  105. return exports.normalize(filter(paths, function(p, index) {
  106. if (typeof p !== 'string') {
  107. throw new TypeError('Arguments to path.join must be strings');
  108. }
  109. return p;
  110. }).join('/'));
  111. };
  112. // path.relative(from, to)
  113. // posix version
  114. exports.relative = function(from, to) {
  115. from = exports.resolve(from).substr(1);
  116. to = exports.resolve(to).substr(1);
  117. function trim(arr) {
  118. var start = 0;
  119. for (; start < arr.length; start++) {
  120. if (arr[start] !== '') break;
  121. }
  122. var end = arr.length - 1;
  123. for (; end >= 0; end--) {
  124. if (arr[end] !== '') break;
  125. }
  126. if (start > end) return [];
  127. return arr.slice(start, end - start + 1);
  128. }
  129. var fromParts = trim(from.split('/'));
  130. var toParts = trim(to.split('/'));
  131. var length = Math.min(fromParts.length, toParts.length);
  132. var samePartsLength = length;
  133. for (var i = 0; i < length; i++) {
  134. if (fromParts[i] !== toParts[i]) {
  135. samePartsLength = i;
  136. break;
  137. }
  138. }
  139. var outputParts = [];
  140. for (var i = samePartsLength; i < fromParts.length; i++) {
  141. outputParts.push('..');
  142. }
  143. outputParts = outputParts.concat(toParts.slice(samePartsLength));
  144. return outputParts.join('/');
  145. };
  146. exports.sep = '/';
  147. exports.delimiter = ':';
  148. exports.dirname = function(path) {
  149. var result = splitPath(path),
  150. root = result[0],
  151. dir = result[1];
  152. if (!root && !dir) {
  153. // No dirname whatsoever
  154. return '.';
  155. }
  156. if (dir) {
  157. // It has a dirname, strip trailing slash
  158. dir = dir.substr(0, dir.length - 1);
  159. }
  160. return root + dir;
  161. };
  162. exports.basename = function(path, ext) {
  163. var f = splitPath(path)[2];
  164. // TODO: make this comparison case-insensitive on windows?
  165. if (ext && f.substr(-1 * ext.length) === ext) {
  166. f = f.substr(0, f.length - ext.length);
  167. }
  168. return f;
  169. };
  170. exports.extname = function(path) {
  171. return splitPath(path)[3];
  172. };
  173. function filter (xs, f) {
  174. if (xs.filter) return xs.filter(f);
  175. var res = [];
  176. for (var i = 0; i < xs.length; i++) {
  177. if (f(xs[i], i, xs)) res.push(xs[i]);
  178. }
  179. return res;
  180. }
  181. // String.prototype.substr - negative index don't work in IE8
  182. var substr = 'ab'.substr(-1) === 'b'
  183. ? function (str, start, len) { return str.substr(start, len) }
  184. : function (str, start, len) {
  185. if (start < 0) start = str.length + start;
  186. return str.substr(start, len);
  187. }
  188. ;
  189. }).call(this,require(2))
  190. },{"2":2}],2:[function(require,module,exports){
  191. // shim for using process in browser
  192. var process = module.exports = {};
  193. // cached from whatever global is present so that test runners that stub it
  194. // don't break things. But we need to wrap it in a try catch in case it is
  195. // wrapped in strict mode code which doesn't define any globals. It's inside a
  196. // function because try/catches deoptimize in certain engines.
  197. var cachedSetTimeout;
  198. var cachedClearTimeout;
  199. function defaultSetTimout() {
  200. throw new Error('setTimeout has not been defined');
  201. }
  202. function defaultClearTimeout () {
  203. throw new Error('clearTimeout has not been defined');
  204. }
  205. (function () {
  206. try {
  207. if (typeof setTimeout === 'function') {
  208. cachedSetTimeout = setTimeout;
  209. } else {
  210. cachedSetTimeout = defaultSetTimout;
  211. }
  212. } catch (e) {
  213. cachedSetTimeout = defaultSetTimout;
  214. }
  215. try {
  216. if (typeof clearTimeout === 'function') {
  217. cachedClearTimeout = clearTimeout;
  218. } else {
  219. cachedClearTimeout = defaultClearTimeout;
  220. }
  221. } catch (e) {
  222. cachedClearTimeout = defaultClearTimeout;
  223. }
  224. } ())
  225. function runTimeout(fun) {
  226. if (cachedSetTimeout === setTimeout) {
  227. //normal enviroments in sane situations
  228. return setTimeout(fun, 0);
  229. }
  230. // if setTimeout wasn't available but was latter defined
  231. if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
  232. cachedSetTimeout = setTimeout;
  233. return setTimeout(fun, 0);
  234. }
  235. try {
  236. // when when somebody has screwed with setTimeout but no I.E. maddness
  237. return cachedSetTimeout(fun, 0);
  238. } catch(e){
  239. try {
  240. // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
  241. return cachedSetTimeout.call(null, fun, 0);
  242. } catch(e){
  243. // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
  244. return cachedSetTimeout.call(this, fun, 0);
  245. }
  246. }
  247. }
  248. function runClearTimeout(marker) {
  249. if (cachedClearTimeout === clearTimeout) {
  250. //normal enviroments in sane situations
  251. return clearTimeout(marker);
  252. }
  253. // if clearTimeout wasn't available but was latter defined
  254. if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
  255. cachedClearTimeout = clearTimeout;
  256. return clearTimeout(marker);
  257. }
  258. try {
  259. // when when somebody has screwed with setTimeout but no I.E. maddness
  260. return cachedClearTimeout(marker);
  261. } catch (e){
  262. try {
  263. // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
  264. return cachedClearTimeout.call(null, marker);
  265. } catch (e){
  266. // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
  267. // Some versions of I.E. have different rules for clearTimeout vs setTimeout
  268. return cachedClearTimeout.call(this, marker);
  269. }
  270. }
  271. }
  272. var queue = [];
  273. var draining = false;
  274. var currentQueue;
  275. var queueIndex = -1;
  276. function cleanUpNextTick() {
  277. if (!draining || !currentQueue) {
  278. return;
  279. }
  280. draining = false;
  281. if (currentQueue.length) {
  282. queue = currentQueue.concat(queue);
  283. } else {
  284. queueIndex = -1;
  285. }
  286. if (queue.length) {
  287. drainQueue();
  288. }
  289. }
  290. function drainQueue() {
  291. if (draining) {
  292. return;
  293. }
  294. var timeout = runTimeout(cleanUpNextTick);
  295. draining = true;
  296. var len = queue.length;
  297. while(len) {
  298. currentQueue = queue;
  299. queue = [];
  300. while (++queueIndex < len) {
  301. if (currentQueue) {
  302. currentQueue[queueIndex].run();
  303. }
  304. }
  305. queueIndex = -1;
  306. len = queue.length;
  307. }
  308. currentQueue = null;
  309. draining = false;
  310. runClearTimeout(timeout);
  311. }
  312. process.nextTick = function (fun) {
  313. var args = new Array(arguments.length - 1);
  314. if (arguments.length > 1) {
  315. for (var i = 1; i < arguments.length; i++) {
  316. args[i - 1] = arguments[i];
  317. }
  318. }
  319. queue.push(new Item(fun, args));
  320. if (queue.length === 1 && !draining) {
  321. runTimeout(drainQueue);
  322. }
  323. };
  324. // v8 likes predictible objects
  325. function Item(fun, array) {
  326. this.fun = fun;
  327. this.array = array;
  328. }
  329. Item.prototype.run = function () {
  330. this.fun.apply(null, this.array);
  331. };
  332. process.title = 'browser';
  333. process.browser = true;
  334. process.env = {};
  335. process.argv = [];
  336. process.version = ''; // empty string to avoid regexp issues
  337. process.versions = {};
  338. function noop() {}
  339. process.on = noop;
  340. process.addListener = noop;
  341. process.once = noop;
  342. process.off = noop;
  343. process.removeListener = noop;
  344. process.removeAllListeners = noop;
  345. process.emit = noop;
  346. process.binding = function (name) {
  347. throw new Error('process.binding is not supported');
  348. };
  349. process.cwd = function () { return '/' };
  350. process.chdir = function (dir) {
  351. throw new Error('process.chdir is not supported');
  352. };
  353. process.umask = function() { return 0; };
  354. },{}],3:[function(require,module,exports){
  355. (function (global){
  356. 'use strict';
  357. var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
  358. var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
  359. function _interopDefault(ex) {
  360. return ex && (typeof ex === 'undefined' ? 'undefined' : _typeof(ex)) === 'object' && 'default' in ex ? ex['default'] : ex;
  361. }
  362. var videojs = _interopDefault((typeof window !== "undefined" ? window['videojs'] : typeof global !== "undefined" ? global['videojs'] : null));
  363. var path = _interopDefault(require(1));
  364. // Default options for the plugin.
  365. var defaults = {};
  366. // Cross-compatibility for Video.js 5 and 6.
  367. var registerPlugin = videojs.registerPlugin || videojs.plugin;
  368. // const dom = videojs.dom || videojs;
  369. var MEDIA_SESSION_EXISTS = Boolean(navigator.mediaSession);
  370. var SKIP_TIME = 10;
  371. /**
  372. * Function to invoke when the player is ready.
  373. *
  374. * This is a great place for your plugin to initialize itself. When this
  375. * function is called, the player will have its DOM and child components
  376. * in place.
  377. *
  378. * @function onPlayerReady
  379. * @param {Player} player
  380. * A Video.js player.
  381. * @param {Object} [options={}]
  382. * An object of options left to the plugin author to define.
  383. */
  384. var onPlayerReady = function onPlayerReady(player, options) {
  385. if (!MEDIA_SESSION_EXISTS) {
  386. videojs.log.warn('Media Session is not available on this device.\n Please try Chrome for Android 57');
  387. return;
  388. }
  389. setUpSkips(player);
  390. if (player.playlist) {
  391. setUpPlaylist(player);
  392. }
  393. player.on('loadstart', function () {
  394. return updateMediaSession(player);
  395. });
  396. updateMediaSession(player);
  397. player.addClass('vjs-media-session');
  398. };
  399. var updateMediaSession = function updateMediaSession(player) {
  400. var curSrc = void 0;
  401. if (player.playlist) {
  402. var playlist = player.playlist();
  403. curSrc = _extends({}, playlist[player.playlist.currentItem()]);
  404. } else {
  405. curSrc = _extends({}, player.currentSource());
  406. }
  407. curSrc.title = curSrc.name;
  408. if (!curSrc.artwork) {
  409. var poster = player.poster();
  410. if (curSrc.thumbnail) {
  411. curSrc.artwork = curSrc.thumbnail.map(function (thumb) {
  412. return {
  413. src: thumb.srcset || thumb.src,
  414. type: thumb.type || path.extname(thumb.src).slice(1)
  415. };
  416. });
  417. } else if (poster) {
  418. curSrc.artwork = [{
  419. src: poster,
  420. type: 'image/' + path.extname(poster).slice(1)
  421. }];
  422. }
  423. }
  424. curSrc.src = player.currentSrc();
  425. navigator.mediaSession.metadata = new MediaMetadata(curSrc);
  426. };
  427. var setUpSkips = function setUpSkips(player) {
  428. navigator.mediaSession.setActionHandler('seekbackward', function () {
  429. player.currentTime(player.currentTime() - SKIP_TIME);
  430. });
  431. navigator.mediaSession.setActionHandler('seekforward', function () {
  432. player.currentTime(player.currentTime() + SKIP_TIME);
  433. });
  434. };
  435. var setUpPlaylist = function setUpPlaylist(player) {
  436. navigator.mediaSession.setActionHandler('previoustrack', function () {
  437. player.playlist.previous();
  438. });
  439. navigator.mediaSession.setActionHandler('nexttrack', function () {
  440. player.playlist.next();
  441. });
  442. };
  443. /**
  444. * A video.js plugin.
  445. *
  446. * In the plugin function, the value of `this` is a video.js `Player`
  447. * instance. You cannot rely on the player being in a "ready" state here,
  448. * depending on how the plugin is invoked. This may or may not be important
  449. * to you; if not, remove the wait for "ready"!
  450. *
  451. * @function mediaSession
  452. * @param {Object} [options={}]
  453. * An object of options left to the plugin author to define.
  454. */
  455. var mediaSession = function mediaSession(options) {
  456. var _this = this;
  457. this.ready(function () {
  458. onPlayerReady(_this, videojs.mergeOptions(defaults, options));
  459. });
  460. };
  461. // Register the plugin with video.js.
  462. registerPlugin('mediaSession', mediaSession);
  463. // Include the version number.
  464. mediaSession.VERSION = '1.0.0';
  465. module.exports = mediaSession;
  466. }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
  467. },{"1":1}]},{},[3])(3)
  468. });
  469. //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy92aWRlb2pzLXNwZWxsYm9vay9ub2RlX21vZHVsZXMvYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvYnJvd3Nlci1wYWNrL19wcmVsdWRlLmpzIiwibm9kZV9tb2R1bGVzL3ZpZGVvanMtc3BlbGxib29rL25vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9wYXRoLWJyb3dzZXJpZnkvaW5kZXguanMiLCJub2RlX21vZHVsZXMvdmlkZW9qcy1zcGVsbGJvb2svbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL3Byb2Nlc3MvYnJvd3Nlci5qcyIsInNyYy9qcy9pbmRleC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7QUNoT0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQ3BMQTs7Ozs7O0FBRUEsU0FBUyxlQUFULENBQTBCLEVBQTFCLEVBQThCO0FBQUUsU0FBUSxNQUFPLFFBQU8sRUFBUCx5Q0FBTyxFQUFQLE9BQWMsUUFBckIsSUFBa0MsYUFBYSxFQUFoRCxHQUFzRCxHQUFHLFNBQUgsQ0FBdEQsR0FBc0UsRUFBN0U7QUFBa0Y7O0FBRWxILElBQUksVUFBVSxnQkFBZ0IsUUFBUSxVQUFSLENBQWhCLENBQWQ7QUFDQSxJQUFJLE9BQU8sZ0JBQWdCLFFBQVEsTUFBUixDQUFoQixDQUFYOztBQUVBO0FBQ0EsSUFBTSxXQUFXLEVBQWpCOztBQUVBO0FBQ0EsSUFBTSxpQkFBaUIsUUFBUSxjQUFSLElBQTBCLFFBQVEsTUFBekQ7QUFDQTs7QUFFQSxJQUFNLHVCQUF1QixRQUFRLFVBQVUsWUFBbEIsQ0FBN0I7O0FBRUEsSUFBTSxZQUFZLEVBQWxCOztBQUVBOzs7Ozs7Ozs7Ozs7O0FBYUEsSUFBTSxnQkFBZ0IsU0FBaEIsYUFBZ0IsQ0FBQyxNQUFELEVBQVMsT0FBVCxFQUFxQjtBQUN6QyxNQUFJLENBQUMsb0JBQUwsRUFBMkI7QUFDekIsWUFBUSxHQUFSLENBQVksSUFBWjtBQUVBO0FBQ0Q7O0FBRUQsYUFBVyxNQUFYOztBQUVBLE1BQUksT0FBTyxRQUFYLEVBQXFCO0FBQ25CLGtCQUFjLE1BQWQ7QUFDRDs7QUFFRCxTQUFPLEVBQVAsQ0FBVSxXQUFWLEVBQXVCO0FBQUEsV0FBTSxtQkFBbUIsTUFBbkIsQ0FBTjtBQUFBLEdBQXZCO0FBQ0EscUJBQW1CLE1BQW5CO0FBQ0EsU0FBTyxRQUFQLENBQWdCLG1CQUFoQjtBQUVELENBakJEOztBQW1CQSxJQUFNLHFCQUFxQixTQUFyQixrQkFBcUIsQ0FBQyxNQUFELEVBQVk7QUFDckMsTUFBSSxlQUFKOztBQUVBLE1BQUksT0FBTyxRQUFYLEVBQXFCO0FBQ25CLFFBQU0sV0FBVyxPQUFPLFFBQVAsRUFBakI7QUFDQSxhQUFTLFNBQWMsRUFBZCxFQUFrQixTQUFTLE9BQU8sUUFBUCxDQUFnQixXQUFoQixFQUFULENBQWxCLENBQVQ7QUFDRCxHQUhELE1BR087QUFDTCxhQUFTLFNBQWMsRUFBZCxFQUFrQixPQUFPLGFBQVAsRUFBbEIsQ0FBVDtBQUNEOztBQUVELFNBQU8sS0FBUCxHQUFlLE9BQU8sSUFBdEI7O0FBRUEsTUFBSSxDQUFDLE9BQU8sT0FBWixFQUFxQjtBQUNuQixRQUFNLFNBQVMsT0FBTyxNQUFQLEVBQWY7O0FBRUEsUUFBSSxPQUFPLFNBQVgsRUFBc0I7QUFDcEIsYUFBTyxPQUFQLEdBQWlCLE9BQU8sU0FBUCxDQUFpQixHQUFqQixDQUFxQixVQUFDLEtBQUQ7QUFBQSxlQUFZO0FBQ2hELGVBQUssTUFBTSxNQUFOLElBQWdCLE1BQU0sR0FEcUI7QUFFaEQsZ0JBQU0sTUFBTSxJQUFOLElBQWMsS0FBSyxPQUFMLENBQWEsTUFBTSxHQUFuQixFQUF3QixLQUF4QixDQUE4QixDQUE5QjtBQUY0QixTQUFaO0FBQUEsT0FBckIsQ0FBakI7QUFJRCxLQUxELE1BS08sSUFBSSxNQUFKLEVBQVk7QUFDakIsYUFBTyxPQUFQLEdBQWlCLENBQUM7QUFDaEIsYUFBSyxNQURXO0FBRWhCLGNBQU0sV0FBVyxLQUFLLE9BQUwsQ0FBYSxNQUFiLEVBQXFCLEtBQXJCLENBQTJCLENBQTNCO0FBRkQsT0FBRCxDQUFqQjtBQUlEO0FBQ0Y7O0FBRUQsU0FBTyxHQUFQLEdBQWEsT0FBTyxVQUFQLEVBQWI7QUFDQSxZQUFVLFlBQVYsQ0FBdUIsUUFBdkIsR0FBa0MsSUFBSSxhQUFKLENBQWtCLE1BQWxCLENBQWxDO0FBQ0QsQ0E5QkQ7O0FBZ0NBLElBQU0sYUFBYSxTQUFiLFVBQWEsQ0FBQyxNQUFELEVBQVk7QUFDN0IsWUFBVSxZQUFWLENBQXVCLGdCQUF2QixDQUF3QyxjQUF4QyxFQUF3RCxZQUFXO0FBQ2pFLFdBQU8sV0FBUCxDQUFtQixPQUFPLFdBQVAsS0FBdUIsU0FBMUM7QUFDRCxHQUZEO0FBR0EsWUFBVSxZQUFWLENBQXVCLGdCQUF2QixDQUF3QyxhQUF4QyxFQUF1RCxZQUFXO0FBQ2hFLFdBQU8sV0FBUCxDQUFtQixPQUFPLFdBQVAsS0FBdUIsU0FBMUM7QUFDRCxHQUZEO0FBR0QsQ0FQRDs7QUFTQSxJQUFNLGdCQUFnQixTQUFoQixhQUFnQixDQUFDLE1BQUQsRUFBWTtBQUNoQyxZQUFVLFlBQVYsQ0FBdUIsZ0JBQXZCLENBQXdDLGVBQXhDLEVBQXlELFlBQVc7QUFDbEUsV0FBTyxRQUFQLENBQWdCLFFBQWhCO0FBQ0QsR0FGRDtBQUdBLFlBQVUsWUFBVixDQUF1QixnQkFBdkIsQ0FBd0MsV0FBeEMsRUFBcUQsWUFBVztBQUM5RCxXQUFPLFFBQVAsQ0FBZ0IsSUFBaEI7QUFDRCxHQUZEO0FBR0QsQ0FQRDs7QUFTQTs7Ozs7Ozs7Ozs7O0FBWUEsSUFBTSxlQUFlLFNBQWYsWUFBZSxDQUFTLE9BQVQsRUFBa0I7QUFBQTs7QUFDckMsT0FBSyxLQUFMLENBQVcsWUFBTTtBQUNmLHlCQUFvQixRQUFRLFlBQVIsQ0FBcUIsUUFBckIsRUFBK0IsT0FBL0IsQ0FBcEI7QUFDRCxHQUZEO0FBR0QsQ0FKRDs7QUFNQTtBQUNBLGVBQWUsY0FBZixFQUErQixZQUEvQjs7QUFFQTtBQUNBLGFBQWEsT0FBYixHQUF1QixhQUF2Qjs7QUFFQSxPQUFPLE9BQVAsR0FBaUIsWUFBakIiLCJmaWxlIjoiZ2VuZXJhdGVkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXNDb250ZW50IjpbIihmdW5jdGlvbiBlKHQsbixyKXtmdW5jdGlvbiBzKG8sdSl7aWYoIW5bb10pe2lmKCF0W29dKXt2YXIgYT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2lmKCF1JiZhKXJldHVybiBhKG8sITApO2lmKGkpcmV0dXJuIGkobywhMCk7dmFyIGY9bmV3IEVycm9yKFwiQ2Fubm90IGZpbmQgbW9kdWxlICdcIitvK1wiJ1wiKTt0aHJvdyBmLmNvZGU9XCJNT0RVTEVfTk9UX0ZPVU5EXCIsZn12YXIgbD1uW29dPXtleHBvcnRzOnt9fTt0W29dWzBdLmNhbGwobC5leHBvcnRzLGZ1bmN0aW9uKGUpe3ZhciBuPXRbb11bMV1bZV07cmV0dXJuIHMobj9uOmUpfSxsLGwuZXhwb3J0cyxlLHQsbixyKX1yZXR1cm4gbltvXS5leHBvcnRzfXZhciBpPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7Zm9yKHZhciBvPTA7bzxyLmxlbmd0aDtvKyspcyhyW29dKTtyZXR1cm4gc30pIiwiLy8gQ29weXJpZ2h0IEpveWVudCwgSW5jLiBhbmQgb3RoZXIgTm9kZSBjb250cmlidXRvcnMuXG4vL1xuLy8gUGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueSBwZXJzb24gb2J0YWluaW5nIGFcbi8vIGNvcHkgb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZCBkb2N1bWVudGF0aW9uIGZpbGVzICh0aGVcbi8vIFwiU29mdHdhcmVcIiksIHRvIGRlYWwgaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZ1xuLy8gd2l0aG91dCBsaW1pdGF0aW9uIHRoZSByaWdodHMgdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLCBwdWJsaXNoLFxuLy8gZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yIHNlbGwgY29waWVzIG9mIHRoZSBTb2Z0d2FyZSwgYW5kIHRvIHBlcm1pdFxuLy8gcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpcyBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlXG4vLyBmb2xsb3dpbmcgY29uZGl0aW9uczpcbi8vXG4vLyBUaGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQgdGhpcyBwZXJtaXNzaW9uIG5vdGljZSBzaGFsbCBiZSBpbmNsdWRlZFxuLy8gaW4gYWxsIGNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuXG4vL1xuLy8gVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEIFwiQVMgSVNcIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTU1xuLy8gT1IgSU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRCBUTyBUSEUgV0FSUkFOVElFUyBPRlxuLy8gTUVSQ0hBTlRBQklMSVRZLCBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSBBTkQgTk9OSU5GUklOR0VNRU5ULiBJTlxuLy8gTk8gRVZFTlQgU0hBTEwgVEhFIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sXG4vLyBEQU1BR0VTIE9SIE9USEVSIExJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1QsIFRPUlQgT1Jcbi8vIE9USEVSV0lTRSwgQVJJU0lORyBGUk9NLCBPVVQgT0YgT1IgSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBTT0ZUV0FSRSBPUiBUSEVcbi8vIFVTRSBPUiBPVEhFUiBERUFMSU5HUyBJTiBUSEUgU09GVFdBUkUuXG5cbi8vIHJlc29sdmVzIC4gYW5kIC4uIGVsZW1lbnRzIGluIGEgcGF0aCBhcnJheSB3aXRoIGRpcmVjdG9yeSBuYW1lcyB0aGVyZVxuLy8gbXVzdCBiZSBubyBzbGFzaGVzLCBlbXB0eSBlbGVtZW50cywgb3IgZGV2aWNlIG5hbWVzIChjOlxcKSBpbiB0aGUgYXJyYXlcbi8vIChzbyBhbHNvIG5vIGxlYWRpbmcgYW5kIHRyYWlsaW5nIHNsYXNoZXMgLSBpdCBkb2VzIG5vdCBkaXN0aW5ndWlzaFxuLy8gcmVsYXRpdmUgYW5kIGFic29sdXRlIHBhdGhzKVxuZnVuY3Rpb24gbm9ybWFsaXplQXJyYXkocGFydHMsIGFsbG93QWJvdmVSb290KSB7XG4gIC8vIGlmIHRoZSBwYXRoIHRyaWVzIHRvIGdvIGFib3ZlIHRoZSByb290LCBgdXBgIGVuZHMgdXAgPiAwXG4gIHZhciB1cCA9IDA7XG4gIGZvciAodmFyIGkgPSBwYXJ0cy5sZW5ndGggLSAxOyBpID49IDA7IGktLSkge1xuICAgIHZhciBsYXN0ID0gcGFydHNbaV07XG4gICAgaWYgKGxhc3QgPT09ICcuJykge1xuICAgICAgcGFydHMuc3BsaWNlKGksIDEpO1xuICAgIH0gZWxzZSBpZiAobGFzdCA9PT0gJy4uJykge1xuICAgICAgcGFydHMuc3BsaWNlKGksIDEpO1xuICAgICAgdXArKztcbiAgICB9IGVsc2UgaWYgKHVwKSB7XG4gICAgICBwYXJ0cy5zcGxpY2UoaSwgMSk7XG4gICAgICB1cC0tO1xuICAgIH1cbiAgfVxuXG4gIC8vIGlmIHRoZSBwYXRoIGlzIGFsbG93ZWQgdG8gZ28gYWJvdmUgdGhlIHJvb3QsIHJlc3RvcmUgbGVhZGluZyAuLnNcbiAgaWYgKGFsbG93QWJvdmVSb290KSB7XG4gICAgZm9yICg7IHVwLS07IHVwKSB7XG4gICAgICBwYXJ0cy51bnNoaWZ0KCcuLicpO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiBwYXJ0cztcbn1cblxuLy8gU3BsaXQgYSBmaWxlbmFtZSBpbnRvIFtyb290LCBkaXIsIGJhc2VuYW1lLCBleHRdLCB1bml4IHZlcnNpb25cbi8vICdyb290JyBpcyBqdXN0IGEgc2xhc2gsIG9yIG5vdGhpbmcuXG52YXIgc3BsaXRQYXRoUmUgPVxuICAgIC9eKFxcLz98KShbXFxzXFxTXSo/KSgoPzpcXC57MSwyfXxbXlxcL10rP3wpKFxcLlteLlxcL10qfCkpKD86W1xcL10qKSQvO1xudmFyIHNwbGl0UGF0aCA9IGZ1bmN0aW9uKGZpbGVuYW1lKSB7XG4gIHJldHVybiBzcGxpdFBhdGhSZS5leGVjKGZpbGVuYW1lKS5zbGljZSgxKTtcbn07XG5cbi8vIHBhdGgucmVzb2x2ZShbZnJvbSAuLi5dLCB0bylcbi8vIHBvc2l4IHZlcnNpb25cbmV4cG9ydHMucmVzb2x2ZSA9IGZ1bmN0aW9uKCkge1xuICB2YXIgcmVzb2x2ZWRQYXRoID0gJycsXG4gICAgICByZXNvbHZlZEFic29sdXRlID0gZmFsc2U7XG5cbiAgZm9yICh2YXIgaSA9IGFyZ3VtZW50cy5sZW5ndGggLSAxOyBpID49IC0xICYmICFyZXNvbHZlZEFic29sdXRlOyBpLS0pIHtcbiAgICB2YXIgcGF0aCA9IChpID49IDApID8gYXJndW1lbnRzW2ldIDogcHJvY2Vzcy5jd2QoKTtcblxuICAgIC8vIFNraXAgZW1wdHkgYW5kIGludmFsaWQgZW50cmllc1xuICAgIGlmICh0eXBlb2YgcGF0aCAhPT0gJ3N0cmluZycpIHtcbiAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ0FyZ3VtZW50cyB0byBwYXRoLnJlc29sdmUgbXVzdCBiZSBzdHJpbmdzJyk7XG4gICAgfSBlbHNlIGlmICghcGF0aCkge1xuICAgICAgY29udGludWU7XG4gICAgfVxuXG4gICAgcmVzb2x2ZWRQYXRoID0gcGF0aCArICcvJyArIHJlc29sdmVkUGF0aDtcbiAgICByZXNvbHZlZEFic29sdXRlID0gcGF0aC5jaGFyQXQoMCkgPT09ICcvJztcbiAgfVxuXG4gIC8vIEF0IHRoaXMgcG9pbnQgdGhlIHBhdGggc2hvdWxkIGJlIHJlc29sdmVkIHRvIGEgZnVsbCBhYnNvbHV0ZSBwYXRoLCBidXRcbiAgLy8gaGFuZGxlIHJlbGF0aXZlIHBhdGhzIHRvIGJlIHNhZmUgKG1pZ2h0IGhhcHBlbiB3aGVuIHByb2Nlc3MuY3dkKCkgZmFpbHMpXG5cbiAgLy8gTm9ybWFsaXplIHRoZSBwYXRoXG4gIHJlc29sdmVkUGF0aCA9IG5vcm1hbGl6ZUFycmF5KGZpbHRlcihyZXNvbHZlZFBhdGguc3BsaXQoJy8nKSwgZnVuY3Rpb24ocCkge1xuICAgIHJldHVybiAhIXA7XG4gIH0pLCAhcmVzb2x2ZWRBYnNvbHV0ZSkuam9pbignLycpO1xuXG4gIHJldHVybiAoKHJlc29sdmVkQWJzb2x1dGUgPyAnLycgOiAnJykgKyByZXNvbHZlZFBhdGgpIHx8ICcuJztcbn07XG5cbi8vIHBhdGgubm9ybWFsaXplKHBhdGgpXG4vLyBwb3NpeCB2ZXJzaW9uXG5leHBvcnRzLm5vcm1hbGl6ZSA9IGZ1bmN0aW9uKHBhdGgpIHtcbiAgdmFyIGlzQWJzb2x1dGUgPSBleHBvcnRzLmlzQWJzb2x1dGUocGF0aCksXG4gICAgICB0cmFpbGluZ1NsYXNoID0gc3Vic3RyKHBhdGgsIC0xKSA9PT0gJy8nO1xuXG4gIC8vIE5vcm1hbGl6ZSB0aGUgcGF0aFxuICBwYXRoID0gbm9ybWFsaXplQXJyYXkoZmlsdGVyKHBhdGguc3BsaXQoJy8nKSwgZnVuY3Rpb24ocCkge1xuICAgIHJldHVybiAhIXA7XG4gIH0pLCAhaXNBYnNvbHV0ZSkuam9pbignLycpO1xuXG4gIGlmICghcGF0aCAmJiAhaXNBYnNvbHV0ZSkge1xuICAgIHBhdGggPSAnLic7XG4gIH1cbiAgaWYgKHBhdGggJiYgdHJhaWxpbmdTbGFzaCkge1xuICAgIHBhdGggKz0gJy8nO1xuICB9XG5cbiAgcmV0dXJuIChpc0Fic29sdXRlID8gJy8nIDogJycpICsgcGF0aDtcbn07XG5cbi8vIHBvc2l4IHZlcnNpb25cbmV4cG9ydHMuaXNBYnNvbHV0ZSA9IGZ1bmN0aW9uKHBhdGgpIHtcbiAgcmV0dXJuIHBhdGguY2hhckF0KDApID09PSAnLyc7XG59O1xuXG4vLyBwb3NpeCB2ZXJzaW9uXG5leHBvcnRzLmpvaW4gPSBmdW5jdGlvbigpIHtcbiAgdmFyIHBhdGhzID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAwKTtcbiAgcmV0dXJuIGV4cG9ydHMubm9ybWFsaXplKGZpbHRlcihwYXRocywgZnVuY3Rpb24ocCwgaW5kZXgpIHtcbiAgICBpZiAodHlwZW9mIHAgIT09ICdzdHJpbmcnKSB7XG4gICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdBcmd1bWVudHMgdG8gcGF0aC5qb2luIG11c3QgYmUgc3RyaW5ncycpO1xuICAgIH1cbiAgICByZXR1cm4gcDtcbiAgfSkuam9pbignLycpKTtcbn07XG5cblxuLy8gcGF0aC5yZWxhdGl2ZShmcm9tLCB0bylcbi8vIHBvc2l4IHZlcnNpb25cbmV4cG9ydHMucmVsYXRpdmUgPSBmdW5jdGlvbihmcm9tLCB0bykge1xuICBmcm9tID0gZXhwb3J0cy5yZXNvbHZlKGZyb20pLnN1YnN0cigxKTtcbiAgdG8gPSBleHBvcnRzLnJlc29sdmUodG8pLnN1YnN0cigxKTtcblxuICBmdW5jdGlvbiB0cmltKGFycikge1xuICAgIHZhciBzdGFydCA9IDA7XG4gICAgZm9yICg7IHN0YXJ0IDwgYXJyLmxlbmd0aDsgc3RhcnQrKykge1xuICAgICAgaWYgKGFycltzdGFydF0gIT09ICcnKSBicmVhaztcbiAgICB9XG5cbiAgICB2YXIgZW5kID0gYXJyLmxlbmd0aCAtIDE7XG4gICAgZm9yICg7IGVuZCA+PSAwOyBlbmQtLSkge1xuICAgICAgaWYgKGFycltlbmRdICE9PSAnJykgYnJlYWs7XG4gICAgfVxuXG4gICAgaWYgKHN0YXJ0ID4gZW5kKSByZXR1cm4gW107XG4gICAgcmV0dXJuIGFyci5zbGljZShzdGFydCwgZW5kIC0gc3RhcnQgKyAxKTtcbiAgfVxuXG4gIHZhciBmcm9tUGFydHMgPSB0cmltKGZyb20uc3BsaXQoJy8nKSk7XG4gIHZhciB0b1BhcnRzID0gdHJpbSh0by5zcGxpdCgnLycpKTtcblxuICB2YXIgbGVuZ3RoID0gTWF0aC5taW4oZnJvbVBhcnRzLmxlbmd0aCwgdG9QYXJ0cy5sZW5ndGgpO1xuICB2YXIgc2FtZVBhcnRzTGVuZ3RoID0gbGVuZ3RoO1xuICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgaWYgKGZyb21QYXJ0c1tpXSAhPT0gdG9QYXJ0c1tpXSkge1xuICAgICAgc2FtZVBhcnRzTGVuZ3RoID0gaTtcbiAgICAgIGJyZWFrO1xuICAgIH1cbiAgfVxuXG4gIHZhciBvdXRwdXRQYXJ0cyA9IFtdO1xuICBmb3IgKHZhciBpID0gc2FtZVBhcnRzTGVuZ3RoOyBpIDwgZnJvbVBhcnRzLmxlbmd0aDsgaSsrKSB7XG4gICAgb3V0cHV0UGFydHMucHVzaCgnLi4nKTtcbiAgfVxuXG4gIG91dHB1dFBhcnRzID0gb3V0cHV0UGFydHMuY29uY2F0KHRvUGFydHMuc2xpY2Uoc2FtZVBhcnRzTGVuZ3RoKSk7XG5cbiAgcmV0dXJuIG91dHB1dFBhcnRzLmpvaW4oJy8nKTtcbn07XG5cbmV4cG9ydHMuc2VwID0gJy8nO1xuZXhwb3J0cy5kZWxpbWl0ZXIgPSAnOic7XG5cbmV4cG9ydHMuZGlybmFtZSA9IGZ1bmN0aW9uKHBhdGgpIHtcbiAgdmFyIHJlc3VsdCA9IHNwbGl0UGF0aChwYXRoKSxcbiAgICAgIHJvb3QgPSByZXN1bHRbMF0sXG4gICAgICBkaXIgPSByZXN1bHRbMV07XG5cbiAgaWYgKCFyb290ICYmICFkaXIpIHtcbiAgICAvLyBObyBkaXJuYW1lIHdoYXRzb2V2ZXJcbiAgICByZXR1cm4gJy4nO1xuICB9XG5cbiAgaWYgKGRpcikge1xuICAgIC8vIEl0IGhhcyBhIGRpcm5hbWUsIHN0cmlwIHRyYWlsaW5nIHNsYXNoXG4gICAgZGlyID0gZGlyLnN1YnN0cigwLCBkaXIubGVuZ3RoIC0gMSk7XG4gIH1cblxuICByZXR1cm4gcm9vdCArIGRpcjtcbn07XG5cblxuZXhwb3J0cy5iYXNlbmFtZSA9IGZ1bmN0aW9uKHBhdGgsIGV4dCkge1xuICB2YXIgZiA9IHNwbGl0UGF0aChwYXRoKVsyXTtcbiAgLy8gVE9ETzogbWFrZSB0aGlzIGNvbXBhcmlzb24gY2FzZS1pbnNlbnNpdGl2ZSBvbiB3aW5kb3dzP1xuICBpZiAoZXh0ICYmIGYuc3Vic3RyKC0xICogZXh0Lmxlbmd0aCkgPT09IGV4dCkge1xuICAgIGYgPSBmLnN1YnN0cigwLCBmLmxlbmd0aCAtIGV4dC5sZW5ndGgpO1xuICB9XG4gIHJldHVybiBmO1xufTtcblxuXG5leHBvcnRzLmV4dG5hbWUgPSBmdW5jdGlvbihwYXRoKSB7XG4gIHJldHVybiBzcGxpdFBhdGgocGF0aClbM107XG59O1xuXG5mdW5jdGlvbiBmaWx0ZXIgKHhzLCBmKSB7XG4gICAgaWYgKHhzLmZpbHRlcikgcmV0dXJuIHhzLmZpbHRlcihmKTtcbiAgICB2YXIgcmVzID0gW107XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCB4cy5sZW5ndGg7IGkrKykge1xuICAgICAgICBpZiAoZih4c1tpXSwgaSwgeHMpKSByZXMucHVzaCh4c1tpXSk7XG4gICAgfVxuICAgIHJldHVybiByZXM7XG59XG5cbi8vIFN0cmluZy5wcm90b3R5cGUuc3Vic3RyIC0gbmVnYXRpdmUgaW5kZXggZG9uJ3Qgd29yayBpbiBJRThcbnZhciBzdWJzdHIgPSAnYWInLnN1YnN0cigtMSkgPT09ICdiJ1xuICAgID8gZnVuY3Rpb24gKHN0ciwgc3RhcnQsIGxlbikgeyByZXR1cm4gc3RyLnN1YnN0cihzdGFydCwgbGVuKSB9XG4gICAgOiBmdW5jdGlvbiAoc3RyLCBzdGFydCwgbGVuKSB7XG4gICAgICAgIGlmIChzdGFydCA8IDApIHN0YXJ0ID0gc3RyLmxlbmd0aCArIHN0YXJ0O1xuICAgICAgICByZXR1cm4gc3RyLnN1YnN0cihzdGFydCwgbGVuKTtcbiAgICB9XG47XG4iLCIvLyBzaGltIGZvciB1c2luZyBwcm9jZXNzIGluIGJyb3dzZXJcbnZhciBwcm9jZXNzID0gbW9kdWxlLmV4cG9ydHMgPSB7fTtcblxuLy8gY2FjaGVkIGZyb20gd2hhdGV2ZXIgZ2xvYmFsIGlzIHByZXNlbnQgc28gdGhhdCB0ZXN0IHJ1bm5lcnMgdGhhdCBzdHViIGl0XG4vLyBkb24ndCBicmVhayB0aGluZ3MuICBCdXQgd2UgbmVlZCB0byB3cmFwIGl0IGluIGEgdHJ5IGNhdGNoIGluIGNhc2UgaXQgaXNcbi8vIHdyYXBwZWQgaW4gc3RyaWN0IG1vZGUgY29kZSB3aGljaCBkb2Vzbid0IGRlZmluZSBhbnkgZ2xvYmFscy4gIEl0J3MgaW5zaWRlIGFcbi8vIGZ1bmN0aW9uIGJlY2F1c2UgdHJ5L2NhdGNoZXMgZGVvcHRpbWl6ZSBpbiBjZXJ0YWluIGVuZ2luZXMuXG5cbnZhciBjYWNoZWRTZXRUaW1lb3V0O1xudmFyIGNhY2hlZENsZWFyVGltZW91dDtcblxuZnVuY3Rpb24gZGVmYXVsdFNldFRpbW91dCgpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ3NldFRpbWVvdXQgaGFzIG5vdCBiZWVuIGRlZmluZWQnKTtcbn1cbmZ1bmN0aW9uIGRlZmF1bHRDbGVhclRpbWVvdXQgKCkge1xuICAgIHRocm93IG5ldyBFcnJvcignY2xlYXJUaW1lb3V0IGhhcyBub3QgYmVlbiBkZWZpbmVkJyk7XG59XG4oZnVuY3Rpb24gKCkge1xuICAgIHRyeSB7XG4gICAgICAgIGlmICh0eXBlb2Ygc2V0VGltZW91dCA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgY2FjaGVkU2V0VGltZW91dCA9IHNldFRpbWVvdXQ7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjYWNoZWRTZXRUaW1lb3V0ID0gZGVmYXVsdFNldFRpbW91dDtcbiAgICAgICAgfVxuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgY2FjaGVkU2V0VGltZW91dCA9IGRlZmF1bHRTZXRUaW1vdXQ7XG4gICAgfVxuICAgIHRyeSB7XG4gICAgICAgIGlmICh0eXBlb2YgY2xlYXJUaW1lb3V0ID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICBjYWNoZWRDbGVhclRpbWVvdXQgPSBjbGVhclRpbWVvdXQ7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjYWNoZWRDbGVhclRpbWVvdXQgPSBkZWZhdWx0Q2xlYXJUaW1lb3V0O1xuICAgICAgICB9XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgICBjYWNoZWRDbGVhclRpbWVvdXQgPSBkZWZhdWx0Q2xlYXJUaW1lb3V0O1xuICAgIH1cbn0gKCkpXG5mdW5jdGlvbiBydW5UaW1lb3V0KGZ1bikge1xuICAgIGlmIChjYWNoZWRTZXRUaW1lb3V0ID09PSBzZXRUaW1lb3V0KSB7XG4gICAgICAgIC8vbm9ybWFsIGVudmlyb21lbnRzIGluIHNhbmUgc2l0dWF0aW9uc1xuICAgICAgICByZXR1cm4gc2V0VGltZW91dChmdW4sIDApO1xuICAgIH1cbiAgICAvLyBpZiBzZXRUaW1lb3V0IHdhc24ndCBhdmFpbGFibGUgYnV0IHdhcyBsYXR0ZXIgZGVmaW5lZFxuICAgIGlmICgoY2FjaGVkU2V0VGltZW91dCA9PT0gZGVmYXVsdFNldFRpbW91dCB8fCAhY2FjaGVkU2V0VGltZW91dCkgJiYgc2V0VGltZW91dCkge1xuICAgICAgICBjYWNoZWRTZXRUaW1lb3V0ID0gc2V0VGltZW91dDtcbiAgICAgICAgcmV0dXJuIHNldFRpbWVvdXQoZnVuLCAwKTtcbiAgICB9XG4gICAgdHJ5IHtcbiAgICAgICAgLy8gd2hlbiB3aGVuIHNvbWVib2R5IGhhcyBzY3Jld2VkIHdpdGggc2V0VGltZW91dCBidXQgbm8gSS5FLiBtYWRkbmVzc1xuICAgICAgICByZXR1cm4gY2FjaGVkU2V0VGltZW91dChmdW4sIDApO1xuICAgIH0gY2F0Y2goZSl7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICAvLyBXaGVuIHdlIGFyZSBpbiBJLkUuIGJ1dCB0aGUgc2NyaXB0IGhhcyBiZWVuIGV2YWxlZCBzbyBJLkUuIGRvZXNuJ3QgdHJ1c3QgdGhlIGdsb2JhbCBvYmplY3Qgd2hlbiBjYWxsZWQgbm9ybWFsbHlcbiAgICAgICAgICAgIHJldHVybiBjYWNoZWRTZXRUaW1lb3V0LmNhbGwobnVsbCwgZnVuLCAwKTtcbiAgICAgICAgfSBjYXRjaChlKXtcbiAgICAgICAgICAgIC8vIHNhbWUgYXMgYWJvdmUgYnV0IHdoZW4gaXQncyBhIHZlcnNpb24gb2YgSS5FLiB0aGF0IG11c3QgaGF2ZSB0aGUgZ2xvYmFsIG9iamVjdCBmb3IgJ3RoaXMnLCBob3BmdWxseSBvdXIgY29udGV4dCBjb3JyZWN0IG90aGVyd2lzZSBpdCB3aWxsIHRocm93IGEgZ2xvYmFsIGVycm9yXG4gICAgICAgICAgICByZXR1cm4gY2FjaGVkU2V0VGltZW91dC5jYWxsKHRoaXMsIGZ1biwgMCk7XG4gICAgICAgIH1cbiAgICB9XG5cblxufVxuZnVuY3Rpb24gcnVuQ2xlYXJUaW1lb3V0KG1hcmtlcikge1xuICAgIGlmIChjYWNoZWRDbGVhclRpbWVvdXQgPT09IGNsZWFyVGltZW91dCkge1xuICAgICAgICAvL25vcm1hbCBlbnZpcm9tZW50cyBpbiBzYW5lIHNpdHVhdGlvbnNcbiAgICAgICAgcmV0dXJuIGNsZWFyVGltZW91dChtYXJrZXIpO1xuICAgIH1cbiAgICAvLyBpZiBjbGVhclRpbWVvdXQgd2Fzbid0IGF2YWlsYWJsZSBidXQgd2FzIGxhdHRlciBkZWZpbmVkXG4gICAgaWYgKChjYWNoZWRDbGVhclRpbWVvdXQgPT09IGRlZmF1bHRDbGVhclRpbWVvdXQgfHwgIWNhY2hlZENsZWFyVGltZW91dCkgJiYgY2xlYXJUaW1lb3V0KSB7XG4gICAgICAgIGNhY2hlZENsZWFyVGltZW91dCA9IGNsZWFyVGltZW91dDtcbiAgICAgICAgcmV0dXJuIGNsZWFyVGltZW91dChtYXJrZXIpO1xuICAgIH1cbiAgICB0cnkge1xuICAgICAgICAvLyB3aGVuIHdoZW4gc29tZWJvZHkgaGFzIHNjcmV3ZWQgd2l0aCBzZXRUaW1lb3V0IGJ1dCBubyBJLkUuIG1hZGRuZXNzXG4gICAgICAgIHJldHVybiBjYWNoZWRDbGVhclRpbWVvdXQobWFya2VyKTtcbiAgICB9IGNhdGNoIChlKXtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIC8vIFdoZW4gd2UgYXJlIGluIEkuRS4gYnV0IHRoZSBzY3JpcHQgaGFzIGJlZW4gZXZhbGVkIHNvIEkuRS4gZG9lc24ndCAgdHJ1c3QgdGhlIGdsb2JhbCBvYmplY3Qgd2hlbiBjYWxsZWQgbm9ybWFsbHlcbiAgICAgICAgICAgIHJldHVybiBjYWNoZWRDbGVhclRpbWVvdXQuY2FsbChudWxsLCBtYXJrZXIpO1xuICAgICAgICB9IGNhdGNoIChlKXtcbiAgICAgICAgICAgIC8vIHNhbWUgYXMgYWJvdmUgYnV0IHdoZW4gaXQncyBhIHZlcnNpb24gb2YgSS5FLiB0aGF0IG11c3QgaGF2ZSB0aGUgZ2xvYmFsIG9iamVjdCBmb3IgJ3RoaXMnLCBob3BmdWxseSBvdXIgY29udGV4dCBjb3JyZWN0IG90aGVyd2lzZSBpdCB3aWxsIHRocm93IGEgZ2xvYmFsIGVycm9yLlxuICAgICAgICAgICAgLy8gU29tZSB2ZXJzaW9ucyBvZiBJLkUuIGhhdmUgZGlmZmVyZW50IHJ1bGVzIGZvciBjbGVhclRpbWVvdXQgdnMgc2V0VGltZW91dFxuICAgICAgICAgICAgcmV0dXJuIGNhY2hlZENsZWFyVGltZW91dC5jYWxsKHRoaXMsIG1hcmtlcik7XG4gICAgICAgIH1cbiAgICB9XG5cblxuXG59XG52YXIgcXVldWUgPSBbXTtcbnZhciBkcmFpbmluZyA9IGZhbHNlO1xudmFyIGN1cnJlbnRRdWV1ZTtcbnZhciBxdWV1ZUluZGV4ID0gLTE7XG5cbmZ1bmN0aW9uIGNsZWFuVXBOZXh0VGljaygpIHtcbiAgICBpZiAoIWRyYWluaW5nIHx8ICFjdXJyZW50UXVldWUpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBkcmFpbmluZyA9IGZhbHNlO1xuICAgIGlmIChjdXJyZW50UXVldWUubGVuZ3RoKSB7XG4gICAgICAgIHF1ZXVlID0gY3VycmVudFF1ZXVlLmNvbmNhdChxdWV1ZSk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgcXVldWVJbmRleCA9IC0xO1xuICAgIH1cbiAgICBpZiAocXVldWUubGVuZ3RoKSB7XG4gICAgICAgIGRyYWluUXVldWUoKTtcbiAgICB9XG59XG5cbmZ1bmN0aW9uIGRyYWluUXVldWUoKSB7XG4gICAgaWYgKGRyYWluaW5nKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdmFyIHRpbWVvdXQgPSBydW5UaW1lb3V0KGNsZWFuVXBOZXh0VGljayk7XG4gICAgZHJhaW5pbmcgPSB0cnVlO1xuXG4gICAgdmFyIGxlbiA9IHF1ZXVlLmxlbmd0aDtcbiAgICB3aGlsZShsZW4pIHtcbiAgICAgICAgY3VycmVudFF1ZXVlID0gcXVldWU7XG4gICAgICAgIHF1ZXVlID0gW107XG4gICAgICAgIHdoaWxlICgrK3F1ZXVlSW5kZXggPCBsZW4pIHtcbiAgICAgICAgICAgIGlmIChjdXJyZW50UXVldWUpIHtcbiAgICAgICAgICAgICAgICBjdXJyZW50UXVldWVbcXVldWVJbmRleF0ucnVuKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcXVldWVJbmRleCA9IC0xO1xuICAgICAgICBsZW4gPSBxdWV1ZS5sZW5ndGg7XG4gICAgfVxuICAgIGN1cnJlbnRRdWV1ZSA9IG51bGw7XG4gICAgZHJhaW5pbmcgPSBmYWxzZTtcbiAgICBydW5DbGVhclRpbWVvdXQodGltZW91dCk7XG59XG5cbnByb2Nlc3MubmV4dFRpY2sgPSBmdW5jdGlvbiAoZnVuKSB7XG4gICAgdmFyIGFyZ3MgPSBuZXcgQXJyYXkoYXJndW1lbnRzLmxlbmd0aCAtIDEpO1xuICAgIGlmIChhcmd1bWVudHMubGVuZ3RoID4gMSkge1xuICAgICAgICBmb3IgKHZhciBpID0gMTsgaSA8IGFyZ3VtZW50cy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgYXJnc1tpIC0gMV0gPSBhcmd1bWVudHNbaV07XG4gICAgICAgIH1cbiAgICB9XG4gICAgcXVldWUucHVzaChuZXcgSXRlbShmdW4sIGFyZ3MpKTtcbiAgICBpZiAocXVldWUubGVuZ3RoID09PSAxICYmICFkcmFpbmluZykge1xuICAgICAgICBydW5UaW1lb3V0KGRyYWluUXVldWUpO1xuICAgIH1cbn07XG5cbi8vIHY4IGxpa2VzIHByZWRpY3RpYmxlIG9iamVjdHNcbmZ1bmN0aW9uIEl0ZW0oZnVuLCBhcnJheSkge1xuICAgIHRoaXMuZnVuID0gZnVuO1xuICAgIHRoaXMuYXJyYXkgPSBhcnJheTtcbn1cbkl0ZW0ucHJvdG90eXBlLnJ1biA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLmZ1bi5hcHBseShudWxsLCB0aGlzLmFycmF5KTtcbn07XG5wcm9jZXNzLnRpdGxlID0gJ2Jyb3dzZXInO1xucHJvY2Vzcy5icm93c2VyID0gdHJ1ZTtcbnByb2Nlc3MuZW52ID0ge307XG5wcm9jZXNzLmFyZ3YgPSBbXTtcbnByb2Nlc3MudmVyc2lvbiA9ICcnOyAvLyBlbXB0eSBzdHJpbmcgdG8gYXZvaWQgcmVnZXhwIGlzc3Vlc1xucHJvY2Vzcy52ZXJzaW9ucyA9IHt9O1xuXG5mdW5jdGlvbiBub29wKCkge31cblxucHJvY2Vzcy5vbiA9IG5vb3A7XG5wcm9jZXNzLmFkZExpc3RlbmVyID0gbm9vcDtcbnByb2Nlc3Mub25jZSA9IG5vb3A7XG5wcm9jZXNzLm9mZiA9IG5vb3A7XG5wcm9jZXNzLnJlbW92ZUxpc3RlbmVyID0gbm9vcDtcbnByb2Nlc3MucmVtb3ZlQWxsTGlzdGVuZXJzID0gbm9vcDtcbnByb2Nlc3MuZW1pdCA9IG5vb3A7XG5cbnByb2Nlc3MuYmluZGluZyA9IGZ1bmN0aW9uIChuYW1lKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdwcm9jZXNzLmJpbmRpbmcgaXMgbm90IHN1cHBvcnRlZCcpO1xufTtcblxucHJvY2Vzcy5jd2QgPSBmdW5jdGlvbiAoKSB7IHJldHVybiAnLycgfTtcbnByb2Nlc3MuY2hkaXIgPSBmdW5jdGlvbiAoZGlyKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdwcm9jZXNzLmNoZGlyIGlzIG5vdCBzdXBwb3J0ZWQnKTtcbn07XG5wcm9jZXNzLnVtYXNrID0gZnVuY3Rpb24oKSB7IHJldHVybiAwOyB9O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG5mdW5jdGlvbiBfaW50ZXJvcERlZmF1bHQgKGV4KSB7IHJldHVybiAoZXggJiYgKHR5cGVvZiBleCA9PT0gJ29iamVjdCcpICYmICdkZWZhdWx0JyBpbiBleCkgPyBleFsnZGVmYXVsdCddIDogZXg7IH1cblxudmFyIHZpZGVvanMgPSBfaW50ZXJvcERlZmF1bHQocmVxdWlyZSgndmlkZW8uanMnKSk7XG52YXIgcGF0aCA9IF9pbnRlcm9wRGVmYXVsdChyZXF1aXJlKCdwYXRoJykpO1xuXG4vLyBEZWZhdWx0IG9wdGlvbnMgZm9yIHRoZSBwbHVnaW4uXG5jb25zdCBkZWZhdWx0cyA9IHt9O1xuXG4vLyBDcm9zcy1jb21wYXRpYmlsaXR5IGZvciBWaWRlby5qcyA1IGFuZCA2LlxuY29uc3QgcmVnaXN0ZXJQbHVnaW4gPSB2aWRlb2pzLnJlZ2lzdGVyUGx1Z2luIHx8IHZpZGVvanMucGx1Z2luO1xuLy8gY29uc3QgZG9tID0gdmlkZW9qcy5kb20gfHwgdmlkZW9qcztcblxuY29uc3QgTUVESUFfU0VTU0lPTl9FWElTVFMgPSBCb29sZWFuKG5hdmlnYXRvci5tZWRpYVNlc3Npb24pO1xuXG5jb25zdCBTS0lQX1RJTUUgPSAxMDtcblxuLyoqXG4gKiBGdW5jdGlvbiB0byBpbnZva2Ugd2hlbiB0aGUgcGxheWVyIGlzIHJlYWR5LlxuICpcbiAqIFRoaXMgaXMgYSBncmVhdCBwbGFjZSBmb3IgeW91ciBwbHVnaW4gdG8gaW5pdGlhbGl6ZSBpdHNlbGYuIFdoZW4gdGhpc1xuICogZnVuY3Rpb24gaXMgY2FsbGVkLCB0aGUgcGxheWVyIHdpbGwgaGF2ZSBpdHMgRE9NIGFuZCBjaGlsZCBjb21wb25lbnRzXG4gKiBpbiBwbGFjZS5cbiAqXG4gKiBAZnVuY3Rpb24gb25QbGF5ZXJSZWFkeVxuICogQHBhcmFtICAgIHtQbGF5ZXJ9IHBsYXllclxuICogICAgICAgICAgIEEgVmlkZW8uanMgcGxheWVyLlxuICogQHBhcmFtICAgIHtPYmplY3R9IFtvcHRpb25zPXt9XVxuICogICAgICAgICAgIEFuIG9iamVjdCBvZiBvcHRpb25zIGxlZnQgdG8gdGhlIHBsdWdpbiBhdXRob3IgdG8gZGVmaW5lLlxuICovXG5jb25zdCBvblBsYXllclJlYWR5ID0gKHBsYXllciwgb3B0aW9ucykgPT4ge1xuICBpZiAoIU1FRElBX1NFU1NJT05fRVhJU1RTKSB7XG4gICAgdmlkZW9qcy5sb2cud2FybihgTWVkaWEgU2Vzc2lvbiBpcyBub3QgYXZhaWxhYmxlIG9uIHRoaXMgZGV2aWNlLlxuICAgICAgICAgICAgICAgICAgICAgIFBsZWFzZSB0cnkgQ2hyb21lIGZvciBBbmRyb2lkIDU3YCk7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgc2V0VXBTa2lwcyhwbGF5ZXIpO1xuXG4gIGlmIChwbGF5ZXIucGxheWxpc3QpIHtcbiAgICBzZXRVcFBsYXlsaXN0KHBsYXllcik7XG4gIH1cblxuICBwbGF5ZXIub24oJ2xvYWRzdGFydCcsICgpID0+IHVwZGF0ZU1lZGlhU2Vzc2lvbihwbGF5ZXIpKTtcbiAgdXBkYXRlTWVkaWFTZXNzaW9uKHBsYXllcik7XG4gIHBsYXllci5hZGRDbGFzcygndmpzLW1lZGlhLXNlc3Npb24nKTtcblxufTtcblxuY29uc3QgdXBkYXRlTWVkaWFTZXNzaW9uID0gKHBsYXllcikgPT4ge1xuICBsZXQgY3VyU3JjO1xuXG4gIGlmIChwbGF5ZXIucGxheWxpc3QpIHtcbiAgICBjb25zdCBwbGF5bGlzdCA9IHBsYXllci5wbGF5bGlzdCgpO1xuICAgIGN1clNyYyA9IE9iamVjdC5hc3NpZ24oe30sIHBsYXlsaXN0W3BsYXllci5wbGF5bGlzdC5jdXJyZW50SXRlbSgpXSk7XG4gIH0gZWxzZSB7XG4gICAgY3VyU3JjID0gT2JqZWN0LmFzc2lnbih7fSwgcGxheWVyLmN1cnJlbnRTb3VyY2UoKSk7XG4gIH1cblxuICBjdXJTcmMudGl0bGUgPSBjdXJTcmMubmFtZTtcblxuICBpZiAoIWN1clNyYy5hcnR3b3JrKSB7XG4gICAgY29uc3QgcG9zdGVyID0gcGxheWVyLnBvc3RlcigpO1xuXG4gICAgaWYgKGN1clNyYy50aHVtYm5haWwpIHtcbiAgICAgIGN1clNyYy5hcnR3b3JrID0gY3VyU3JjLnRodW1ibmFpbC5tYXAoKHRodW1iKSA9PiAoe1xuICAgICAgICBzcmM6IHRodW1iLnNyY3NldCB8fCB0aHVtYi5zcmMsXG4gICAgICAgIHR5cGU6IHRodW1iLnR5cGUgfHwgcGF0aC5leHRuYW1lKHRodW1iLnNyYykuc2xpY2UoMSlcbiAgICAgIH0pKTtcbiAgICB9IGVsc2UgaWYgKHBvc3Rlcikge1xuICAgICAgY3VyU3JjLmFydHdvcmsgPSBbe1xuICAgICAgICBzcmM6IHBvc3RlcixcbiAgICAgICAgdHlwZTogJ2ltYWdlLycgKyBwYXRoLmV4dG5hbWUocG9zdGVyKS5zbGljZSgxKVxuICAgICAgfV07XG4gICAgfVxuICB9XG5cbiAgY3VyU3JjLnNyYyA9IHBsYXllci5jdXJyZW50U3JjKCk7XG4gIG5hdmlnYXRvci5tZWRpYVNlc3Npb24ubWV0YWRhdGEgPSBuZXcgTWVkaWFNZXRhZGF0YShjdXJTcmMpO1xufTtcblxuY29uc3Qgc2V0VXBTa2lwcyA9IChwbGF5ZXIpID0+IHtcbiAgbmF2aWdhdG9yLm1lZGlhU2Vzc2lvbi5zZXRBY3Rpb25IYW5kbGVyKCdzZWVrYmFja3dhcmQnLCBmdW5jdGlvbigpIHtcbiAgICBwbGF5ZXIuY3VycmVudFRpbWUocGxheWVyLmN1cnJlbnRUaW1lKCkgLSBTS0lQX1RJTUUpO1xuICB9KTtcbiAgbmF2aWdhdG9yLm1lZGlhU2Vzc2lvbi5zZXRBY3Rpb25IYW5kbGVyKCdzZWVrZm9yd2FyZCcsIGZ1bmN0aW9uKCkge1xuICAgIHBsYXllci5jdXJyZW50VGltZShwbGF5ZXIuY3VycmVudFRpbWUoKSArIFNLSVBfVElNRSk7XG4gIH0pO1xufTtcblxuY29uc3Qgc2V0VXBQbGF5bGlzdCA9IChwbGF5ZXIpID0+IHtcbiAgbmF2aWdhdG9yLm1lZGlhU2Vzc2lvbi5zZXRBY3Rpb25IYW5kbGVyKCdwcmV2aW91c3RyYWNrJywgZnVuY3Rpb24oKSB7XG4gICAgcGxheWVyLnBsYXlsaXN0LnByZXZpb3VzKCk7XG4gIH0pO1xuICBuYXZpZ2F0b3IubWVkaWFTZXNzaW9uLnNldEFjdGlvbkhhbmRsZXIoJ25leHR0cmFjaycsIGZ1bmN0aW9uKCkge1xuICAgIHBsYXllci5wbGF5bGlzdC5uZXh0KCk7XG4gIH0pO1xufTtcblxuLyoqXG4gKiBBIHZpZGVvLmpzIHBsdWdpbi5cbiAqXG4gKiBJbiB0aGUgcGx1Z2luIGZ1bmN0aW9uLCB0aGUgdmFsdWUgb2YgYHRoaXNgIGlzIGEgdmlkZW8uanMgYFBsYXllcmBcbiAqIGluc3RhbmNlLiBZb3UgY2Fubm90IHJlbHkgb24gdGhlIHBsYXllciBiZWluZyBpbiBhIFwicmVhZHlcIiBzdGF0ZSBoZXJlLFxuICogZGVwZW5kaW5nIG9uIGhvdyB0aGUgcGx1Z2luIGlzIGludm9rZWQuIFRoaXMgbWF5IG9yIG1heSBub3QgYmUgaW1wb3J0YW50XG4gKiB0byB5b3U7IGlmIG5vdCwgcmVtb3ZlIHRoZSB3YWl0IGZvciBcInJlYWR5XCIhXG4gKlxuICogQGZ1bmN0aW9uIG1lZGlhU2Vzc2lvblxuICogQHBhcmFtICAgIHtPYmplY3R9IFtvcHRpb25zPXt9XVxuICogICAgICAgICAgIEFuIG9iamVjdCBvZiBvcHRpb25zIGxlZnQgdG8gdGhlIHBsdWdpbiBhdXRob3IgdG8gZGVmaW5lLlxuICovXG5jb25zdCBtZWRpYVNlc3Npb24gPSBmdW5jdGlvbihvcHRpb25zKSB7XG4gIHRoaXMucmVhZHkoKCkgPT4ge1xuICAgIG9uUGxheWVyUmVhZHkodGhpcywgdmlkZW9qcy5tZXJnZU9wdGlvbnMoZGVmYXVsdHMsIG9wdGlvbnMpKTtcbiAgfSk7XG59O1xuXG4vLyBSZWdpc3RlciB0aGUgcGx1Z2luIHdpdGggdmlkZW8uanMuXG5yZWdpc3RlclBsdWdpbignbWVkaWFTZXNzaW9uJywgbWVkaWFTZXNzaW9uKTtcblxuLy8gSW5jbHVkZSB0aGUgdmVyc2lvbiBudW1iZXIuXG5tZWRpYVNlc3Npb24uVkVSU0lPTiA9ICdfX1ZFUlNJT05fXyc7XG5cbm1vZHVsZS5leHBvcnRzID0gbWVkaWFTZXNzaW9uO1xuIl19