Diligent web site
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

jquery.typed.js 36KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. // The MIT License (MIT)
  2. // Typed.js | Copyright (c) 2014 Matt Boldt | www.mattboldt.com
  3. // Permission is hereby granted, free of charge, to any person obtaining a copy
  4. // of this software and associated documentation files (the "Software"), to deal
  5. // in the Software without restriction, including without limitation the rights
  6. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. // copies of the Software, and to permit persons to whom the Software is
  8. // furnished to do so, subject to the following conditions:
  9. // The above copyright notice and this permission notice shall be included in
  10. // all copies or substantial portions of the Software.
  11. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  12. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  13. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  14. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  15. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  16. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  17. // THE SOFTWARE.
  18. ! function($) {
  19. "use strict";
  20. var Typed = function(el, options) {
  21. // chosen element to manipulate text
  22. this.el = $(el);
  23. // options
  24. this.options = $.extend({}, $.fn.typed.defaults, options);
  25. // attribute to type into
  26. this.isInput = this.el.is('input');
  27. this.attr = this.options.attr;
  28. // show cursor
  29. this.showCursor = this.isInput ? false : this.options.showCursor;
  30. // text content of element
  31. this.elContent = this.attr ? this.el.attr(this.attr) : this.el.text()
  32. // html or plain text
  33. this.contentType = this.options.contentType;
  34. // typing speed
  35. this.typeSpeed = this.options.typeSpeed;
  36. // add a delay before typing starts
  37. this.startDelay = this.options.startDelay;
  38. // backspacing speed
  39. this.backSpeed = this.options.backSpeed;
  40. // amount of time to wait before backspacing
  41. this.backDelay = this.options.backDelay;
  42. // div containing strings
  43. this.stringsElement = this.options.stringsElement;
  44. // input strings of text
  45. this.strings = this.options.strings;
  46. // character number position of current string
  47. this.strPos = 0;
  48. // current array position
  49. this.arrayPos = 0;
  50. // number to stop backspacing on.
  51. // default 0, can change depending on how many chars
  52. // you want to remove at the time
  53. this.stopNum = 0;
  54. // Looping logic
  55. this.loop = this.options.loop;
  56. this.loopCount = this.options.loopCount;
  57. this.curLoop = 0;
  58. // for stopping
  59. this.stop = false;
  60. // custom cursor
  61. this.cursorChar = this.options.cursorChar;
  62. // shuffle the strings
  63. this.shuffle = this.options.shuffle;
  64. // the order of strings
  65. this.sequence = [];
  66. // All systems go!
  67. this.build();
  68. };
  69. Typed.prototype = {
  70. constructor: Typed
  71. ,
  72. init: function() {
  73. // begin the loop w/ first current string (global self.strings)
  74. // current string will be passed as an argument each time after this
  75. var self = this;
  76. self.timeout = setTimeout(function() {
  77. for (var i=0;i<self.strings.length;++i) self.sequence[i]=i;
  78. // shuffle the array if true
  79. if(self.shuffle) self.sequence = self.shuffleArray(self.sequence);
  80. // Start typing
  81. self.typewrite(self.strings[self.sequence[self.arrayPos]], self.strPos);
  82. }, self.startDelay);
  83. }
  84. ,
  85. build: function() {
  86. var self = this;
  87. // Insert cursor
  88. if (this.showCursor === true) {
  89. this.cursor = $("<span class=\"typed-cursor\">" + this.cursorChar + "</span>");
  90. this.el.after(this.cursor);
  91. }
  92. if (this.stringsElement) {
  93. self.strings = [];
  94. this.stringsElement.hide();
  95. var strings = this.stringsElement.find('p');
  96. $.each(strings, function(key, value){
  97. self.strings.push($(value).html());
  98. });
  99. }
  100. this.init();
  101. }
  102. // pass current string state to each function, types 1 char per call
  103. ,
  104. typewrite: function(curString, curStrPos) {
  105. // exit when stopped
  106. if (this.stop === true) {
  107. return;
  108. }
  109. // varying values for setTimeout during typing
  110. // can't be global since number changes each time loop is executed
  111. var humanize = Math.round(Math.random() * (100 - 30)) + this.typeSpeed;
  112. var self = this;
  113. // ------------- optional ------------- //
  114. // backpaces a certain string faster
  115. // ------------------------------------ //
  116. // if (self.arrayPos == 1){
  117. // self.backDelay = 50;
  118. // }
  119. // else{ self.backDelay = 500; }
  120. // contain typing function in a timeout humanize'd delay
  121. self.timeout = setTimeout(function() {
  122. // check for an escape character before a pause value
  123. // format: \^\d+ .. eg: ^1000 .. should be able to print the ^ too using ^^
  124. // single ^ are removed from string
  125. var charPause = 0;
  126. var substr = curString.substr(curStrPos);
  127. if (substr.charAt(0) === '^') {
  128. var skip = 1; // skip atleast 1
  129. if (/^\^\d+/.test(substr)) {
  130. substr = /\d+/.exec(substr)[0];
  131. skip += substr.length;
  132. charPause = parseInt(substr);
  133. }
  134. // strip out the escape character and pause value so they're not printed
  135. curString = curString.substring(0, curStrPos) + curString.substring(curStrPos + skip);
  136. }
  137. if (self.contentType === 'html') {
  138. // skip over html tags while typing
  139. var curChar = curString.substr(curStrPos).charAt(0)
  140. if (curChar === '<' || curChar === '&') {
  141. var tag = '';
  142. var endTag = '';
  143. if (curChar === '<') {
  144. endTag = '>'
  145. } else {
  146. endTag = ';'
  147. }
  148. while (curString.substr(curStrPos).charAt(0) !== endTag) {
  149. tag += curString.substr(curStrPos).charAt(0);
  150. curStrPos++;
  151. }
  152. curStrPos++;
  153. tag += endTag;
  154. }
  155. }
  156. // timeout for any pause after a character
  157. self.timeout = setTimeout(function() {
  158. if (curStrPos === curString.length) {
  159. // fires callback function
  160. self.options.onStringTyped(self.arrayPos);
  161. // is this the final string
  162. if (self.arrayPos === self.strings.length - 1) {
  163. // animation that occurs on the last typed string
  164. self.options.callback();
  165. self.curLoop++;
  166. // quit if we wont loop back
  167. if (self.loop === false || self.curLoop === self.loopCount)
  168. return;
  169. }
  170. self.timeout = setTimeout(function() {
  171. self.backspace(curString, curStrPos);
  172. }, self.backDelay);
  173. } else {
  174. /* call before functions if applicable */
  175. if (curStrPos === 0)
  176. self.options.preStringTyped(self.arrayPos);
  177. // start typing each new char into existing string
  178. // curString: arg, self.el.html: original text inside element
  179. var nextString = curString.substr(0, curStrPos + 1);
  180. if (self.attr) {
  181. self.el.attr(self.attr, nextString);
  182. } else {
  183. if (self.isInput) {
  184. self.el.val(nextString);
  185. } else if (self.contentType === 'html') {
  186. self.el.html(nextString);
  187. } else {
  188. self.el.text(nextString);
  189. }
  190. }
  191. // add characters one by one
  192. curStrPos++;
  193. // loop the function
  194. self.typewrite(curString, curStrPos);
  195. }
  196. // end of character pause
  197. }, charPause);
  198. // humanized value for typing
  199. }, humanize);
  200. }
  201. ,
  202. backspace: function(curString, curStrPos) {
  203. // exit when stopped
  204. if (this.stop === true) {
  205. return;
  206. }
  207. // varying values for setTimeout during typing
  208. // can't be global since number changes each time loop is executed
  209. var humanize = Math.round(Math.random() * (100 - 30)) + this.backSpeed;
  210. var self = this;
  211. self.timeout = setTimeout(function() {
  212. // ----- this part is optional ----- //
  213. // check string array position
  214. // on the first string, only delete one word
  215. // the stopNum actually represents the amount of chars to
  216. // keep in the current string. In my case it's 14.
  217. // if (self.arrayPos == 1){
  218. // self.stopNum = 14;
  219. // }
  220. //every other time, delete the whole typed string
  221. // else{
  222. // self.stopNum = 0;
  223. // }
  224. if (self.contentType === 'html') {
  225. // skip over html tags while backspacing
  226. if (curString.substr(curStrPos).charAt(0) === '>') {
  227. var tag = '';
  228. while (curString.substr(curStrPos).charAt(0) !== '<') {
  229. tag -= curString.substr(curStrPos).charAt(0);
  230. curStrPos--;
  231. }
  232. curStrPos--;
  233. tag += '<';
  234. }
  235. }
  236. // ----- continue important stuff ----- //
  237. // replace text with base text + typed characters
  238. var nextString = curString.substr(0, curStrPos);
  239. if (self.attr) {
  240. self.el.attr(self.attr, nextString);
  241. } else {
  242. if (self.isInput) {
  243. self.el.val(nextString);
  244. } else if (self.contentType === 'html') {
  245. self.el.html(nextString);
  246. } else {
  247. self.el.text(nextString);
  248. }
  249. }
  250. // if the number (id of character in current string) is
  251. // less than the stop number, keep going
  252. if (curStrPos > self.stopNum) {
  253. // subtract characters one by one
  254. curStrPos--;
  255. // loop the function
  256. self.backspace(curString, curStrPos);
  257. }
  258. // if the stop number has been reached, increase
  259. // array position to next string
  260. else if (curStrPos <= self.stopNum) {
  261. self.arrayPos++;
  262. if (self.arrayPos === self.strings.length) {
  263. self.arrayPos = 0;
  264. // Shuffle sequence again
  265. if(self.shuffle) self.sequence = self.shuffleArray(self.sequence);
  266. self.init();
  267. } else
  268. self.typewrite(self.strings[self.sequence[self.arrayPos]], curStrPos);
  269. }
  270. // humanized value for typing
  271. }, humanize);
  272. }
  273. /**
  274. * Shuffles the numbers in the given array.
  275. * @param {Array} array
  276. * @returns {Array}
  277. */
  278. ,shuffleArray: function(array) {
  279. var tmp, current, top = array.length;
  280. if(top) while(--top) {
  281. current = Math.floor(Math.random() * (top + 1));
  282. tmp = array[current];
  283. array[current] = array[top];
  284. array[top] = tmp;
  285. }
  286. return array;
  287. }
  288. // Start & Stop currently not working
  289. // , stop: function() {
  290. // var self = this;
  291. // self.stop = true;
  292. // clearInterval(self.timeout);
  293. // }
  294. // , start: function() {
  295. // var self = this;
  296. // if(self.stop === false)
  297. // return;
  298. // this.stop = false;
  299. // this.init();
  300. // }
  301. // Reset and rebuild the element
  302. ,
  303. reset: function() {
  304. var self = this;
  305. clearInterval(self.timeout);
  306. var id = this.el.attr('id');
  307. this.el.after('<span id="' + id + '"/>')
  308. this.el.remove();
  309. if (typeof this.cursor !== 'undefined') {
  310. this.cursor.remove();
  311. }
  312. // Send the callback
  313. self.options.resetCallback();
  314. }
  315. };
  316. $.fn.typed = function(option) {
  317. return this.each(function() {
  318. var $this = $(this),
  319. data = $this.data('typed'),
  320. options = typeof option == 'object' && option;
  321. if (!data) $this.data('typed', (data = new Typed(this, options)));
  322. if (typeof option == 'string') data[option]();
  323. });
  324. };
  325. $.fn.typed.defaults = {
  326. strings: ["These are the default values...", "You know what you should do?", "Use your own!", "Have a great day!"],
  327. stringsElement: null,
  328. // typing speed
  329. typeSpeed: 0,
  330. // time before typing starts
  331. startDelay: 0,
  332. // backspacing speed
  333. backSpeed: 0,
  334. // shuffle the strings
  335. shuffle: false,
  336. // time before backspacing
  337. backDelay: 500,
  338. // loop
  339. loop: false,
  340. // false = infinite
  341. loopCount: false,
  342. // show cursor
  343. showCursor: true,
  344. // character for cursor
  345. cursorChar: "|",
  346. // attribute to type (null == text)
  347. attr: null,
  348. // either html or text
  349. contentType: 'html',
  350. // call when done callback function
  351. callback: function() {},
  352. // starting callback function before each string
  353. preStringTyped: function() {},
  354. //callback for every typed string
  355. onStringTyped: function() {},
  356. // callback for reset
  357. resetCallback: function() {}
  358. };
  359. }(window.jQuery);
  360. //# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiIiwic291cmNlcyI6WyJqcXVlcnkudHlwZWQuanMiXSwic291cmNlc0NvbnRlbnQiOlsiLy8gVGhlIE1JVCBMaWNlbnNlIChNSVQpXG5cbi8vIFR5cGVkLmpzIHwgQ29weXJpZ2h0IChjKSAyMDE0IE1hdHQgQm9sZHQgfCB3d3cubWF0dGJvbGR0LmNvbVxuXG4vLyBQZXJtaXNzaW9uIGlzIGhlcmVieSBncmFudGVkLCBmcmVlIG9mIGNoYXJnZSwgdG8gYW55IHBlcnNvbiBvYnRhaW5pbmcgYSBjb3B5XG4vLyBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkIGRvY3VtZW50YXRpb24gZmlsZXMgKHRoZSBcIlNvZnR3YXJlXCIpLCB0byBkZWFsXG4vLyBpbiB0aGUgU29mdHdhcmUgd2l0aG91dCByZXN0cmljdGlvbiwgaW5jbHVkaW5nIHdpdGhvdXQgbGltaXRhdGlvbiB0aGUgcmlnaHRzXG4vLyB0byB1c2UsIGNvcHksIG1vZGlmeSwgbWVyZ2UsIHB1Ymxpc2gsIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsIGFuZC9vciBzZWxsXG4vLyBjb3BpZXMgb2YgdGhlIFNvZnR3YXJlLCBhbmQgdG8gcGVybWl0IHBlcnNvbnMgdG8gd2hvbSB0aGUgU29mdHdhcmUgaXNcbi8vIGZ1cm5pc2hlZCB0byBkbyBzbywgc3ViamVjdCB0byB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6XG5cbi8vIFRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlIHNoYWxsIGJlIGluY2x1ZGVkIGluXG4vLyBhbGwgY29waWVzIG9yIHN1YnN0YW50aWFsIHBvcnRpb25zIG9mIHRoZSBTb2Z0d2FyZS5cblxuLy8gVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEIFwiQVMgSVNcIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUlxuLy8gSU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRCBUTyBUSEUgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFksXG4vLyBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSBBTkQgTk9OSU5GUklOR0VNRU5ULiBJTiBOTyBFVkVOVCBTSEFMTCBUSEVcbi8vIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVJcbi8vIExJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJXSVNFLCBBUklTSU5HIEZST00sXG4vLyBPVVQgT0YgT1IgSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBTT0ZUV0FSRSBPUiBUSEUgVVNFIE9SIE9USEVSIERFQUxJTkdTIElOXG4vLyBUSEUgU09GVFdBUkUuXG5cblxuXG5cbiEgZnVuY3Rpb24oJCkge1xuXG4gICAgXCJ1c2Ugc3RyaWN0XCI7XG5cbiAgICB2YXIgVHlwZWQgPSBmdW5jdGlvbihlbCwgb3B0aW9ucykge1xuXG4gICAgICAgIC8vIGNob3NlbiBlbGVtZW50IHRvIG1hbmlwdWxhdGUgdGV4dFxuICAgICAgICB0aGlzLmVsID0gJChlbCk7XG5cbiAgICAgICAgLy8gb3B0aW9uc1xuICAgICAgICB0aGlzLm9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgJC5mbi50eXBlZC5kZWZhdWx0cywgb3B0aW9ucyk7XG5cbiAgICAgICAgLy8gYXR0cmlidXRlIHRvIHR5cGUgaW50b1xuICAgICAgICB0aGlzLmlzSW5wdXQgPSB0aGlzLmVsLmlzKCdpbnB1dCcpO1xuICAgICAgICB0aGlzLmF0dHIgPSB0aGlzLm9wdGlvbnMuYXR0cjtcblxuICAgICAgICAvLyBzaG93IGN1cnNvclxuICAgICAgICB0aGlzLnNob3dDdXJzb3IgPSB0aGlzLmlzSW5wdXQgPyBmYWxzZSA6IHRoaXMub3B0aW9ucy5zaG93Q3Vyc29yO1xuXG4gICAgICAgIC8vIHRleHQgY29udGVudCBvZiBlbGVtZW50XG4gICAgICAgIHRoaXMuZWxDb250ZW50ID0gdGhpcy5hdHRyID8gdGhpcy5lbC5hdHRyKHRoaXMuYXR0cikgOiB0aGlzLmVsLnRleHQoKVxuXG4gICAgICAgIC8vIGh0bWwgb3IgcGxhaW4gdGV4dFxuICAgICAgICB0aGlzLmNvbnRlbnRUeXBlID0gdGhpcy5vcHRpb25zLmNvbnRlbnRUeXBlO1xuXG4gICAgICAgIC8vIHR5cGluZyBzcGVlZFxuICAgICAgICB0aGlzLnR5cGVTcGVlZCA9IHRoaXMub3B0aW9ucy50eXBlU3BlZWQ7XG5cbiAgICAgICAgLy8gYWRkIGEgZGVsYXkgYmVmb3JlIHR5cGluZyBzdGFydHNcbiAgICAgICAgdGhpcy5zdGFydERlbGF5ID0gdGhpcy5vcHRpb25zLnN0YXJ0RGVsYXk7XG5cbiAgICAgICAgLy8gYmFja3NwYWNpbmcgc3BlZWRcbiAgICAgICAgdGhpcy5iYWNrU3BlZWQgPSB0aGlzLm9wdGlvbnMuYmFja1NwZWVkO1xuXG4gICAgICAgIC8vIGFtb3VudCBvZiB0aW1lIHRvIHdhaXQgYmVmb3JlIGJhY2tzcGFjaW5nXG4gICAgICAgIHRoaXMuYmFja0RlbGF5ID0gdGhpcy5vcHRpb25zLmJhY2tEZWxheTtcblxuICAgICAgICAvLyBkaXYgY29udGFpbmluZyBzdHJpbmdzXG4gICAgICAgIHRoaXMuc3RyaW5nc0VsZW1lbnQgPSB0aGlzLm9wdGlvbnMuc3RyaW5nc0VsZW1lbnQ7XG5cbiAgICAgICAgLy8gaW5wdXQgc3RyaW5ncyBvZiB0ZXh0XG4gICAgICAgIHRoaXMuc3RyaW5ncyA9IHRoaXMub3B0aW9ucy5zdHJpbmdzO1xuXG4gICAgICAgIC8vIGNoYXJhY3RlciBudW1iZXIgcG9zaXRpb24gb2YgY3VycmVudCBzdHJpbmdcbiAgICAgICAgdGhpcy5zdHJQb3MgPSAwO1xuXG4gICAgICAgIC8vIGN1cnJlbnQgYXJyYXkgcG9zaXRpb25cbiAgICAgICAgdGhpcy5hcnJheVBvcyA9IDA7XG5cbiAgICAgICAgLy8gbnVtYmVyIHRvIHN0b3AgYmFja3NwYWNpbmcgb24uXG4gICAgICAgIC8vIGRlZmF1bHQgMCwgY2FuIGNoYW5nZSBkZXBlbmRpbmcgb24gaG93IG1hbnkgY2hhcnNcbiAgICAgICAgLy8geW91IHdhbnQgdG8gcmVtb3ZlIGF0IHRoZSB0aW1lXG4gICAgICAgIHRoaXMuc3RvcE51bSA9IDA7XG5cbiAgICAgICAgLy8gTG9vcGluZyBsb2dpY1xuICAgICAgICB0aGlzLmxvb3AgPSB0aGlzLm9wdGlvbnMubG9vcDtcbiAgICAgICAgdGhpcy5sb29wQ291bnQgPSB0aGlzLm9wdGlvbnMubG9vcENvdW50O1xuICAgICAgICB0aGlzLmN1ckxvb3AgPSAwO1xuXG4gICAgICAgIC8vIGZvciBzdG9wcGluZ1xuICAgICAgICB0aGlzLnN0b3AgPSBmYWxzZTtcblxuICAgICAgICAvLyBjdXN0b20gY3Vyc29yXG4gICAgICAgIHRoaXMuY3Vyc29yQ2hhciA9IHRoaXMub3B0aW9ucy5jdXJzb3JDaGFyO1xuXG4gICAgICAgIC8vIHNodWZmbGUgdGhlIHN0cmluZ3NcbiAgICAgICAgdGhpcy5zaHVmZmxlID0gdGhpcy5vcHRpb25zLnNodWZmbGU7XG4gICAgICAgIC8vIHRoZSBvcmRlciBvZiBzdHJpbmdzXG4gICAgICAgIHRoaXMuc2VxdWVuY2UgPSBbXTtcblxuICAgICAgICAvLyBBbGwgc3lzdGVtcyBnbyFcbiAgICAgICAgdGhpcy5idWlsZCgpO1xuICAgIH07XG5cbiAgICBUeXBlZC5wcm90b3R5cGUgPSB7XG5cbiAgICAgICAgY29uc3RydWN0b3I6IFR5cGVkXG5cbiAgICAgICAgLFxuICAgICAgICBpbml0OiBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIC8vIGJlZ2luIHRoZSBsb29wIHcvIGZpcnN0IGN1cnJlbnQgc3RyaW5nIChnbG9iYWwgc2VsZi5zdHJpbmdzKVxuICAgICAgICAgICAgLy8gY3VycmVudCBzdHJpbmcgd2lsbCBiZSBwYXNzZWQgYXMgYW4gYXJndW1lbnQgZWFjaCB0aW1lIGFmdGVyIHRoaXNcbiAgICAgICAgICAgIHZhciBzZWxmID0gdGhpcztcbiAgICAgICAgICAgIHNlbGYudGltZW91dCA9IHNldFRpbWVvdXQoZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICAgICAgZm9yICh2YXIgaT0wO2k8c2VsZi5zdHJpbmdzLmxlbmd0aDsrK2kpIHNlbGYuc2VxdWVuY2VbaV09aTtcblxuICAgICAgICAgICAgICAgIC8vIHNodWZmbGUgdGhlIGFycmF5IGlmIHRydWVcbiAgICAgICAgICAgICAgICBpZihzZWxmLnNodWZmbGUpIHNlbGYuc2VxdWVuY2UgPSBzZWxmLnNodWZmbGVBcnJheShzZWxmLnNlcXVlbmNlKTtcblxuICAgICAgICAgICAgICAgIC8vIFN0YXJ0IHR5cGluZ1xuICAgICAgICAgICAgICAgIHNlbGYudHlwZXdyaXRlKHNlbGYuc3RyaW5nc1tzZWxmLnNlcXVlbmNlW3NlbGYuYXJyYXlQb3NdXSwgc2VsZi5zdHJQb3MpO1xuICAgICAgICAgICAgfSwgc2VsZi5zdGFydERlbGF5KTtcbiAgICAgICAgfVxuXG4gICAgICAgICxcbiAgICAgICAgYnVpbGQ6IGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgICAgICAgICAgLy8gSW5zZXJ0IGN1cnNvclxuICAgICAgICAgICAgaWYgKHRoaXMuc2hvd0N1cnNvciA9PT0gdHJ1ZSkge1xuICAgICAgICAgICAgICAgIHRoaXMuY3Vyc29yID0gJChcIjxzcGFuIGNsYXNzPVxcXCJ0eXBlZC1jdXJzb3JcXFwiPlwiICsgdGhpcy5jdXJzb3JDaGFyICsgXCI8L3NwYW4+XCIpO1xuICAgICAgICAgICAgICAgIHRoaXMuZWwuYWZ0ZXIodGhpcy5jdXJzb3IpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHRoaXMuc3RyaW5nc0VsZW1lbnQpIHtcbiAgICAgICAgICAgICAgICBzZWxmLnN0cmluZ3MgPSBbXTtcbiAgICAgICAgICAgICAgICB0aGlzLnN0cmluZ3NFbGVtZW50LmhpZGUoKTtcbiAgICAgICAgICAgICAgICB2YXIgc3RyaW5ncyA9IHRoaXMuc3RyaW5nc0VsZW1lbnQuZmluZCgncCcpO1xuICAgICAgICAgICAgICAgICQuZWFjaChzdHJpbmdzLCBmdW5jdGlvbihrZXksIHZhbHVlKXtcbiAgICAgICAgICAgICAgICAgICAgc2VsZi5zdHJpbmdzLnB1c2goJCh2YWx1ZSkuaHRtbCgpKTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRoaXMuaW5pdCgpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gcGFzcyBjdXJyZW50IHN0cmluZyBzdGF0ZSB0byBlYWNoIGZ1bmN0aW9uLCB0eXBlcyAxIGNoYXIgcGVyIGNhbGxcbiAgICAgICAgLFxuICAgICAgICB0eXBld3JpdGU6IGZ1bmN0aW9uKGN1clN0cmluZywgY3VyU3RyUG9zKSB7XG4gICAgICAgICAgICAvLyBleGl0IHdoZW4gc3RvcHBlZFxuICAgICAgICAgICAgaWYgKHRoaXMuc3RvcCA9PT0gdHJ1ZSkge1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gdmFyeWluZyB2YWx1ZXMgZm9yIHNldFRpbWVvdXQgZHVyaW5nIHR5cGluZ1xuICAgICAgICAgICAgLy8gY2FuJ3QgYmUgZ2xvYmFsIHNpbmNlIG51bWJlciBjaGFuZ2VzIGVhY2ggdGltZSBsb29wIGlzIGV4ZWN1dGVkXG4gICAgICAgICAgICB2YXIgaHVtYW5pemUgPSBNYXRoLnJvdW5kKE1hdGgucmFuZG9tKCkgKiAoMTAwIC0gMzApKSArIHRoaXMudHlwZVNwZWVkO1xuICAgICAgICAgICAgdmFyIHNlbGYgPSB0aGlzO1xuXG4gICAgICAgICAgICAvLyAtLS0tLS0tLS0tLS0tIG9wdGlvbmFsIC0tLS0tLS0tLS0tLS0gLy9cbiAgICAgICAgICAgIC8vIGJhY2twYWNlcyBhIGNlcnRhaW4gc3RyaW5nIGZhc3RlclxuICAgICAgICAgICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIC8vXG4gICAgICAgICAgICAvLyBpZiAoc2VsZi5hcnJheVBvcyA9PSAxKXtcbiAgICAgICAgICAgIC8vICBzZWxmLmJhY2tEZWxheSA9IDUwO1xuICAgICAgICAgICAgLy8gfVxuICAgICAgICAgICAgLy8gZWxzZXsgc2VsZi5iYWNrRGVsYXkgPSA1MDA7IH1cblxuICAgICAgICAgICAgLy8gY29udGFpbiB0eXBpbmcgZnVuY3Rpb24gaW4gYSB0aW1lb3V0IGh1bWFuaXplJ2QgZGVsYXlcbiAgICAgICAgICAgIHNlbGYudGltZW91dCA9IHNldFRpbWVvdXQoZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICAgICAgLy8gY2hlY2sgZm9yIGFuIGVzY2FwZSBjaGFyYWN0ZXIgYmVmb3JlIGEgcGF1c2UgdmFsdWVcbiAgICAgICAgICAgICAgICAvLyBmb3JtYXQ6IFxcXlxcZCsgLi4gZWc6IF4xMDAwIC4uIHNob3VsZCBiZSBhYmxlIHRvIHByaW50IHRoZSBeIHRvbyB1c2luZyBeXlxuICAgICAgICAgICAgICAgIC8vIHNpbmdsZSBeIGFyZSByZW1vdmVkIGZyb20gc3RyaW5nXG4gICAgICAgICAgICAgICAgdmFyIGNoYXJQYXVzZSA9IDA7XG4gICAgICAgICAgICAgICAgdmFyIHN1YnN0ciA9IGN1clN0cmluZy5zdWJzdHIoY3VyU3RyUG9zKTtcbiAgICAgICAgICAgICAgICBpZiAoc3Vic3RyLmNoYXJBdCgwKSA9PT0gJ14nKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBza2lwID0gMTsgLy8gc2tpcCBhdGxlYXN0IDFcbiAgICAgICAgICAgICAgICAgICAgaWYgKC9eXFxeXFxkKy8udGVzdChzdWJzdHIpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzdWJzdHIgPSAvXFxkKy8uZXhlYyhzdWJzdHIpWzBdO1xuICAgICAgICAgICAgICAgICAgICAgICAgc2tpcCArPSBzdWJzdHIubGVuZ3RoO1xuICAgICAgICAgICAgICAgICAgICAgICAgY2hhclBhdXNlID0gcGFyc2VJbnQoc3Vic3RyKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIC8vIHN0cmlwIG91dCB0aGUgZXNjYXBlIGNoYXJhY3RlciBhbmQgcGF1c2UgdmFsdWUgc28gdGhleSdyZSBub3QgcHJpbnRlZFxuICAgICAgICAgICAgICAgICAgICBjdXJTdHJpbmcgPSBjdXJTdHJpbmcuc3Vic3RyaW5nKDAsIGN1clN0clBvcykgKyBjdXJTdHJpbmcuc3Vic3RyaW5nKGN1clN0clBvcyArIHNraXApO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGlmIChzZWxmLmNvbnRlbnRUeXBlID09PSAnaHRtbCcpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gc2tpcCBvdmVyIGh0bWwgdGFncyB3aGlsZSB0eXBpbmdcbiAgICAgICAgICAgICAgICAgICAgdmFyIGN1ckNoYXIgPSBjdXJTdHJpbmcuc3Vic3RyKGN1clN0clBvcykuY2hhckF0KDApXG4gICAgICAgICAgICAgICAgICAgIGlmIChjdXJDaGFyID09PSAnPCcgfHwgY3VyQ2hhciA9PT0gJyYnKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgdGFnID0gJyc7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgZW5kVGFnID0gJyc7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoY3VyQ2hhciA9PT0gJzwnKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZW5kVGFnID0gJz4nXG4gICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuZFRhZyA9ICc7J1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgd2hpbGUgKGN1clN0cmluZy5zdWJzdHIoY3VyU3RyUG9zKS5jaGFyQXQoMCkgIT09IGVuZFRhZykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRhZyArPSBjdXJTdHJpbmcuc3Vic3RyKGN1clN0clBvcykuY2hhckF0KDApO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1clN0clBvcysrO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgY3VyU3RyUG9zKys7XG4gICAgICAgICAgICAgICAgICAgICAgICB0YWcgKz0gZW5kVGFnO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgLy8gdGltZW91dCBmb3IgYW55IHBhdXNlIGFmdGVyIGEgY2hhcmFjdGVyXG4gICAgICAgICAgICAgICAgc2VsZi50aW1lb3V0ID0gc2V0VGltZW91dChmdW5jdGlvbigpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGN1clN0clBvcyA9PT0gY3VyU3RyaW5nLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gZmlyZXMgY2FsbGJhY2sgZnVuY3Rpb25cbiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYub3B0aW9ucy5vblN0cmluZ1R5cGVkKHNlbGYuYXJyYXlQb3MpO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBpcyB0aGlzIHRoZSBmaW5hbCBzdHJpbmdcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChzZWxmLmFycmF5UG9zID09PSBzZWxmLnN0cmluZ3MubGVuZ3RoIC0gMSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGFuaW1hdGlvbiB0aGF0IG9jY3VycyBvbiB0aGUgbGFzdCB0eXBlZCBzdHJpbmdcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxmLm9wdGlvbnMuY2FsbGJhY2soKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuY3VyTG9vcCsrO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gcXVpdCBpZiB3ZSB3b250IGxvb3AgYmFja1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChzZWxmLmxvb3AgPT09IGZhbHNlIHx8IHNlbGYuY3VyTG9vcCA9PT0gc2VsZi5sb29wQ291bnQpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi50aW1lb3V0ID0gc2V0VGltZW91dChmdW5jdGlvbigpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxmLmJhY2tzcGFjZShjdXJTdHJpbmcsIGN1clN0clBvcyk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9LCBzZWxmLmJhY2tEZWxheSk7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8qIGNhbGwgYmVmb3JlIGZ1bmN0aW9ucyBpZiBhcHBsaWNhYmxlICovXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoY3VyU3RyUG9zID09PSAwKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYub3B0aW9ucy5wcmVTdHJpbmdUeXBlZChzZWxmLmFycmF5UG9zKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gc3RhcnQgdHlwaW5nIGVhY2ggbmV3IGNoYXIgaW50byBleGlzdGluZyBzdHJpbmdcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGN1clN0cmluZzogYXJnLCBzZWxmLmVsLmh0bWw6IG9yaWdpbmFsIHRleHQgaW5zaWRlIGVsZW1lbnRcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBuZXh0U3RyaW5nID0gY3VyU3RyaW5nLnN1YnN0cigwLCBjdXJTdHJQb3MgKyAxKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChzZWxmLmF0dHIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxmLmVsLmF0dHIoc2VsZi5hdHRyLCBuZXh0U3RyaW5nKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHNlbGYuaXNJbnB1dCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxmLmVsLnZhbChuZXh0U3RyaW5nKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHNlbGYuY29udGVudFR5cGUgPT09ICdodG1sJykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxmLmVsLmh0bWwobmV4dFN0cmluZyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5lbC50ZXh0KG5leHRTdHJpbmcpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gYWRkIGNoYXJhY3RlcnMgb25lIGJ5IG9uZVxuICAgICAgICAgICAgICAgICAgICAgICAgY3VyU3RyUG9zKys7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBsb29wIHRoZSBmdW5jdGlvblxuICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi50eXBld3JpdGUoY3VyU3RyaW5nLCBjdXJTdHJQb3MpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIC8vIGVuZCBvZiBjaGFyYWN0ZXIgcGF1c2VcbiAgICAgICAgICAgICAgICB9LCBjaGFyUGF1c2UpO1xuXG4gICAgICAgICAgICAgICAgLy8gaHVtYW5pemVkIHZhbHVlIGZvciB0eXBpbmdcbiAgICAgICAgICAgIH0sIGh1bWFuaXplKTtcblxuICAgICAgICB9XG5cbiAgICAgICAgLFxuICAgICAgICBiYWNrc3BhY2U6IGZ1bmN0aW9uKGN1clN0cmluZywgY3VyU3RyUG9zKSB7XG4gICAgICAgICAgICAvLyBleGl0IHdoZW4gc3RvcHBlZFxuICAgICAgICAgICAgaWYgKHRoaXMuc3RvcCA9PT0gdHJ1ZSkge1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gdmFyeWluZyB2YWx1ZXMgZm9yIHNldFRpbWVvdXQgZHVyaW5nIHR5cGluZ1xuICAgICAgICAgICAgLy8gY2FuJ3QgYmUgZ2xvYmFsIHNpbmNlIG51bWJlciBjaGFuZ2VzIGVhY2ggdGltZSBsb29wIGlzIGV4ZWN1dGVkXG4gICAgICAgICAgICB2YXIgaHVtYW5pemUgPSBNYXRoLnJvdW5kKE1hdGgucmFuZG9tKCkgKiAoMTAwIC0gMzApKSArIHRoaXMuYmFja1NwZWVkO1xuICAgICAgICAgICAgdmFyIHNlbGYgPSB0aGlzO1xuXG4gICAgICAgICAgICBzZWxmLnRpbWVvdXQgPSBzZXRUaW1lb3V0KGZ1bmN0aW9uKCkge1xuXG4gICAgICAgICAgICAgICAgLy8gLS0tLS0gdGhpcyBwYXJ0IGlzIG9wdGlvbmFsIC0tLS0tIC8vXG4gICAgICAgICAgICAgICAgLy8gY2hlY2sgc3RyaW5nIGFycmF5IHBvc2l0aW9uXG4gICAgICAgICAgICAgICAgLy8gb24gdGhlIGZpcnN0IHN0cmluZywgb25seSBkZWxldGUgb25lIHdvcmRcbiAgICAgICAgICAgICAgICAvLyB0aGUgc3RvcE51bSBhY3R1YWxseSByZXByZXNlbnRzIHRoZSBhbW91bnQgb2YgY2hhcnMgdG9cbiAgICAgICAgICAgICAgICAvLyBrZWVwIGluIHRoZSBjdXJyZW50IHN0cmluZy4gSW4gbXkgY2FzZSBpdCdzIDE0LlxuICAgICAgICAgICAgICAgIC8vIGlmIChzZWxmLmFycmF5UG9zID09IDEpe1xuICAgICAgICAgICAgICAgIC8vICBzZWxmLnN0b3BOdW0gPSAxNDtcbiAgICAgICAgICAgICAgICAvLyB9XG4gICAgICAgICAgICAgICAgLy9ldmVyeSBvdGhlciB0aW1lLCBkZWxldGUgdGhlIHdob2xlIHR5cGVkIHN0cmluZ1xuICAgICAgICAgICAgICAgIC8vIGVsc2V7XG4gICAgICAgICAgICAgICAgLy8gIHNlbGYuc3RvcE51bSA9IDA7XG4gICAgICAgICAgICAgICAgLy8gfVxuXG4gICAgICAgICAgICAgICAgaWYgKHNlbGYuY29udGVudFR5cGUgPT09ICdodG1sJykge1xuICAgICAgICAgICAgICAgICAgICAvLyBza2lwIG92ZXIgaHRtbCB0YWdzIHdoaWxlIGJhY2tzcGFjaW5nXG4gICAgICAgICAgICAgICAgICAgIGlmIChjdXJTdHJpbmcuc3Vic3RyKGN1clN0clBvcykuY2hhckF0KDApID09PSAnPicpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciB0YWcgPSAnJztcbiAgICAgICAgICAgICAgICAgICAgICAgIHdoaWxlIChjdXJTdHJpbmcuc3Vic3RyKGN1clN0clBvcykuY2hhckF0KDApICE9PSAnPCcpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YWcgLT0gY3VyU3RyaW5nLnN1YnN0cihjdXJTdHJQb3MpLmNoYXJBdCgwKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdXJTdHJQb3MtLTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIGN1clN0clBvcy0tO1xuICAgICAgICAgICAgICAgICAgICAgICAgdGFnICs9ICc8JztcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIC8vIC0tLS0tIGNvbnRpbnVlIGltcG9ydGFudCBzdHVmZiAtLS0tLSAvL1xuICAgICAgICAgICAgICAgIC8vIHJlcGxhY2UgdGV4dCB3aXRoIGJhc2UgdGV4dCArIHR5cGVkIGNoYXJhY3RlcnNcbiAgICAgICAgICAgICAgICB2YXIgbmV4dFN0cmluZyA9IGN1clN0cmluZy5zdWJzdHIoMCwgY3VyU3RyUG9zKTtcbiAgICAgICAgICAgICAgICBpZiAoc2VsZi5hdHRyKSB7XG4gICAgICAgICAgICAgICAgICAgIHNlbGYuZWwuYXR0cihzZWxmLmF0dHIsIG5leHRTdHJpbmcpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChzZWxmLmlzSW5wdXQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuZWwudmFsKG5leHRTdHJpbmcpO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHNlbGYuY29udGVudFR5cGUgPT09ICdodG1sJykge1xuICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5lbC5odG1sKG5leHRTdHJpbmcpO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5lbC50ZXh0KG5leHRTdHJpbmcpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgLy8gaWYgdGhlIG51bWJlciAoaWQgb2YgY2hhcmFjdGVyIGluIGN1cnJlbnQgc3RyaW5nKSBpc1xuICAgICAgICAgICAgICAgIC8vIGxlc3MgdGhhbiB0aGUgc3RvcCBudW1iZXIsIGtlZXAgZ29pbmdcbiAgICAgICAgICAgICAgICBpZiAoY3VyU3RyUG9zID4gc2VsZi5zdG9wTnVtKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIHN1YnRyYWN0IGNoYXJhY3RlcnMgb25lIGJ5IG9uZVxuICAgICAgICAgICAgICAgICAgICBjdXJTdHJQb3MtLTtcbiAgICAgICAgICAgICAgICAgICAgLy8gbG9vcCB0aGUgZnVuY3Rpb25cbiAgICAgICAgICAgICAgICAgICAgc2VsZi5iYWNrc3BhY2UoY3VyU3RyaW5nLCBjdXJTdHJQb3MpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAvLyBpZiB0aGUgc3RvcCBudW1iZXIgaGFzIGJlZW4gcmVhY2hlZCwgaW5jcmVhc2VcbiAgICAgICAgICAgICAgICAvLyBhcnJheSBwb3NpdGlvbiB0byBuZXh0IHN0cmluZ1xuICAgICAgICAgICAgICAgIGVsc2UgaWYgKGN1clN0clBvcyA8PSBzZWxmLnN0b3BOdW0pIHtcbiAgICAgICAgICAgICAgICAgICAgc2VsZi5hcnJheVBvcysrO1xuXG4gICAgICAgICAgICAgICAgICAgIGlmIChzZWxmLmFycmF5UG9zID09PSBzZWxmLnN0cmluZ3MubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzZWxmLmFycmF5UG9zID0gMDtcblxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gU2h1ZmZsZSBzZXF1ZW5jZSBhZ2FpblxuICAgICAgICAgICAgICAgICAgICAgICAgaWYoc2VsZi5zaHVmZmxlKSBzZWxmLnNlcXVlbmNlID0gc2VsZi5zaHVmZmxlQXJyYXkoc2VsZi5zZXF1ZW5jZSk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuaW5pdCgpO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2VcbiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYudHlwZXdyaXRlKHNlbGYuc3RyaW5nc1tzZWxmLnNlcXVlbmNlW3NlbGYuYXJyYXlQb3NdXSwgY3VyU3RyUG9zKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAvLyBodW1hbml6ZWQgdmFsdWUgZm9yIHR5cGluZ1xuICAgICAgICAgICAgfSwgaHVtYW5pemUpO1xuXG4gICAgICAgIH1cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNodWZmbGVzIHRoZSBudW1iZXJzIGluIHRoZSBnaXZlbiBhcnJheS5cbiAgICAgICAgICogQHBhcmFtIHtBcnJheX0gYXJyYXlcbiAgICAgICAgICogQHJldHVybnMge0FycmF5fVxuICAgICAgICAgKi9cbiAgICAgICAgLHNodWZmbGVBcnJheTogZnVuY3Rpb24oYXJyYXkpIHtcbiAgICAgICAgICAgIHZhciB0bXAsIGN1cnJlbnQsIHRvcCA9IGFycmF5Lmxlbmd0aDtcbiAgICAgICAgICAgIGlmKHRvcCkgd2hpbGUoLS10b3ApIHtcbiAgICAgICAgICAgICAgICBjdXJyZW50ID0gTWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpICogKHRvcCArIDEpKTtcbiAgICAgICAgICAgICAgICB0bXAgPSBhcnJheVtjdXJyZW50XTtcbiAgICAgICAgICAgICAgICBhcnJheVtjdXJyZW50XSA9IGFycmF5W3RvcF07XG4gICAgICAgICAgICAgICAgYXJyYXlbdG9wXSA9IHRtcDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBhcnJheTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFN0YXJ0ICYgU3RvcCBjdXJyZW50bHkgbm90IHdvcmtpbmdcblxuICAgICAgICAvLyAsIHN0b3A6IGZ1bmN0aW9uKCkge1xuICAgICAgICAvLyAgICAgdmFyIHNlbGYgPSB0aGlzO1xuXG4gICAgICAgIC8vICAgICBzZWxmLnN0b3AgPSB0cnVlO1xuICAgICAgICAvLyAgICAgY2xlYXJJbnRlcnZhbChzZWxmLnRpbWVvdXQpO1xuICAgICAgICAvLyB9XG5cbiAgICAgICAgLy8gLCBzdGFydDogZnVuY3Rpb24oKSB7XG4gICAgICAgIC8vICAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgICAgIC8vICAgICBpZihzZWxmLnN0b3AgPT09IGZhbHNlKVxuICAgICAgICAvLyAgICAgICAgcmV0dXJuO1xuXG4gICAgICAgIC8vICAgICB0aGlzLnN0b3AgPSBmYWxzZTtcbiAgICAgICAgLy8gICAgIHRoaXMuaW5pdCgpO1xuICAgICAgICAvLyB9XG5cbiAgICAgICAgLy8gUmVzZXQgYW5kIHJlYnVpbGQgdGhlIGVsZW1lbnRcbiAgICAgICAgLFxuICAgICAgICByZXNldDogZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgICAgICAgICBjbGVhckludGVydmFsKHNlbGYudGltZW91dCk7XG4gICAgICAgICAgICB2YXIgaWQgPSB0aGlzLmVsLmF0dHIoJ2lkJyk7XG4gICAgICAgICAgICB0aGlzLmVsLmFmdGVyKCc8c3BhbiBpZD1cIicgKyBpZCArICdcIi8+JylcbiAgICAgICAgICAgIHRoaXMuZWwucmVtb3ZlKCk7XG4gICAgICAgICAgICBpZiAodHlwZW9mIHRoaXMuY3Vyc29yICE9PSAndW5kZWZpbmVkJykge1xuICAgICAgICAgICAgICAgIHRoaXMuY3Vyc29yLnJlbW92ZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gU2VuZCB0aGUgY2FsbGJhY2tcbiAgICAgICAgICAgIHNlbGYub3B0aW9ucy5yZXNldENhbGxiYWNrKCk7XG4gICAgICAgIH1cblxuICAgIH07XG5cbiAgICAkLmZuLnR5cGVkID0gZnVuY3Rpb24ob3B0aW9uKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmVhY2goZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgJHRoaXMgPSAkKHRoaXMpLFxuICAgICAgICAgICAgICAgIGRhdGEgPSAkdGhpcy5kYXRhKCd0eXBlZCcpLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMgPSB0eXBlb2Ygb3B0aW9uID09ICdvYmplY3QnICYmIG9wdGlvbjtcbiAgICAgICAgICAgIGlmICghZGF0YSkgJHRoaXMuZGF0YSgndHlwZWQnLCAoZGF0YSA9IG5ldyBUeXBlZCh0aGlzLCBvcHRpb25zKSkpO1xuICAgICAgICAgICAgaWYgKHR5cGVvZiBvcHRpb24gPT0gJ3N0cmluZycpIGRhdGFbb3B0aW9uXSgpO1xuICAgICAgICB9KTtcbiAgICB9O1xuXG4gICAgJC5mbi50eXBlZC5kZWZhdWx0cyA9IHtcbiAgICAgICAgc3RyaW5nczogW1wiVGhlc2UgYXJlIHRoZSBkZWZhdWx0IHZhbHVlcy4uLlwiLCBcIllvdSBrbm93IHdoYXQgeW91IHNob3VsZCBkbz9cIiwgXCJVc2UgeW91ciBvd24hXCIsIFwiSGF2ZSBhIGdyZWF0IGRheSFcIl0sXG4gICAgICAgIHN0cmluZ3NFbGVtZW50OiBudWxsLFxuICAgICAgICAvLyB0eXBpbmcgc3BlZWRcbiAgICAgICAgdHlwZVNwZWVkOiAwLFxuICAgICAgICAvLyB0aW1lIGJlZm9yZSB0eXBpbmcgc3RhcnRzXG4gICAgICAgIHN0YXJ0RGVsYXk6IDAsXG4gICAgICAgIC8vIGJhY2tzcGFjaW5nIHNwZWVkXG4gICAgICAgIGJhY2tTcGVlZDogMCxcbiAgICAgICAgLy8gc2h1ZmZsZSB0aGUgc3RyaW5nc1xuICAgICAgICBzaHVmZmxlOiBmYWxzZSxcbiAgICAgICAgLy8gdGltZSBiZWZvcmUgYmFja3NwYWNpbmdcbiAgICAgICAgYmFja0RlbGF5OiA1MDAsXG4gICAgICAgIC8vIGxvb3BcbiAgICAgICAgbG9vcDogZmFsc2UsXG4gICAgICAgIC8vIGZhbHNlID0gaW5maW5pdGVcbiAgICAgICAgbG9vcENvdW50OiBmYWxzZSxcbiAgICAgICAgLy8gc2hvdyBjdXJzb3JcbiAgICAgICAgc2hvd0N1cnNvcjogdHJ1ZSxcbiAgICAgICAgLy8gY2hhcmFjdGVyIGZvciBjdXJzb3JcbiAgICAgICAgY3Vyc29yQ2hhcjogXCJ8XCIsXG4gICAgICAgIC8vIGF0dHJpYnV0ZSB0byB0eXBlIChudWxsID09IHRleHQpXG4gICAgICAgIGF0dHI6IG51bGwsXG4gICAgICAgIC8vIGVpdGhlciBodG1sIG9yIHRleHRcbiAgICAgICAgY29udGVudFR5cGU6ICdodG1sJyxcbiAgICAgICAgLy8gY2FsbCB3aGVuIGRvbmUgY2FsbGJhY2sgZnVuY3Rpb25cbiAgICAgICAgY2FsbGJhY2s6IGZ1bmN0aW9uKCkge30sXG4gICAgICAgIC8vIHN0YXJ0aW5nIGNhbGxiYWNrIGZ1bmN0aW9uIGJlZm9yZSBlYWNoIHN0cmluZ1xuICAgICAgICBwcmVTdHJpbmdUeXBlZDogZnVuY3Rpb24oKSB7fSxcbiAgICAgICAgLy9jYWxsYmFjayBmb3IgZXZlcnkgdHlwZWQgc3RyaW5nXG4gICAgICAgIG9uU3RyaW5nVHlwZWQ6IGZ1bmN0aW9uKCkge30sXG4gICAgICAgIC8vIGNhbGxiYWNrIGZvciByZXNldFxuICAgICAgICByZXNldENhbGxiYWNrOiBmdW5jdGlvbigpIHt9XG4gICAgfTtcblxuXG59KHdpbmRvdy5qUXVlcnkpOyJdLCJmaWxlIjoianF1ZXJ5LnR5cGVkLmpzIn0=