row-height-cache.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. /**
  2. * @fileoverview added by tsickle
  3. * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
  4. */
  5. /**
  6. * This object contains the cache of the various row heights that are present inside
  7. * the data table. Its based on Fenwick tree data structure that helps with
  8. * querying sums that have time complexity of log n.
  9. *
  10. * Fenwick Tree Credits: http://petr-mitrichev.blogspot.com/2013/05/fenwick-tree-range-updates.html
  11. * https://github.com/mikolalysenko/fenwick-tree
  12. *
  13. */
  14. var /**
  15. * This object contains the cache of the various row heights that are present inside
  16. * the data table. Its based on Fenwick tree data structure that helps with
  17. * querying sums that have time complexity of log n.
  18. *
  19. * Fenwick Tree Credits: http://petr-mitrichev.blogspot.com/2013/05/fenwick-tree-range-updates.html
  20. * https://github.com/mikolalysenko/fenwick-tree
  21. *
  22. */
  23. RowHeightCache = /** @class */ (function () {
  24. function RowHeightCache() {
  25. /**
  26. * Tree Array stores the cumulative information of the row heights to perform efficient
  27. * range queries and updates. Currently the tree is initialized to the base row
  28. * height instead of the detail row height.
  29. */
  30. this.treeArray = [];
  31. }
  32. /**
  33. * Clear the Tree array.
  34. */
  35. /**
  36. * Clear the Tree array.
  37. * @return {?}
  38. */
  39. RowHeightCache.prototype.clearCache = /**
  40. * Clear the Tree array.
  41. * @return {?}
  42. */
  43. function () {
  44. this.treeArray = [];
  45. };
  46. /**
  47. * Initialize the Fenwick tree with row Heights.
  48. *
  49. * @param rows The array of rows which contain the expanded status.
  50. * @param rowHeight The row height.
  51. * @param detailRowHeight The detail row height.
  52. */
  53. /**
  54. * Initialize the Fenwick tree with row Heights.
  55. *
  56. * @param {?} details
  57. * @return {?}
  58. */
  59. RowHeightCache.prototype.initCache = /**
  60. * Initialize the Fenwick tree with row Heights.
  61. *
  62. * @param {?} details
  63. * @return {?}
  64. */
  65. function (details) {
  66. var rows = details.rows, rowHeight = details.rowHeight, detailRowHeight = details.detailRowHeight, externalVirtual = details.externalVirtual, rowCount = details.rowCount, rowIndexes = details.rowIndexes, rowExpansions = details.rowExpansions;
  67. /** @type {?} */
  68. var isFn = typeof rowHeight === 'function';
  69. /** @type {?} */
  70. var isDetailFn = typeof detailRowHeight === 'function';
  71. if (!isFn && isNaN(rowHeight)) {
  72. throw new Error("Row Height cache initialization failed. Please ensure that 'rowHeight' is a\n valid number or function value: (" + rowHeight + ") when 'scrollbarV' is enabled.");
  73. }
  74. // Add this additional guard in case detailRowHeight is set to 'auto' as it wont work.
  75. if (!isDetailFn && isNaN(detailRowHeight)) {
  76. throw new Error("Row Height cache initialization failed. Please ensure that 'detailRowHeight' is a\n valid number or function value: (" + detailRowHeight + ") when 'scrollbarV' is enabled.");
  77. }
  78. /** @type {?} */
  79. var n = externalVirtual ? rowCount : rows.length;
  80. this.treeArray = new Array(n);
  81. for (var i = 0; i < n; ++i) {
  82. this.treeArray[i] = 0;
  83. }
  84. for (var i = 0; i < n; ++i) {
  85. /** @type {?} */
  86. var row = rows[i];
  87. /** @type {?} */
  88. var currentRowHeight = rowHeight;
  89. if (isFn) {
  90. currentRowHeight = rowHeight(row);
  91. }
  92. // Add the detail row height to the already expanded rows.
  93. // This is useful for the table that goes through a filter or sort.
  94. /** @type {?} */
  95. var expanded = rowExpansions.has(row);
  96. if (row && expanded) {
  97. if (isDetailFn) {
  98. /** @type {?} */
  99. var index = rowIndexes.get(row);
  100. currentRowHeight += detailRowHeight(row, index);
  101. }
  102. else {
  103. currentRowHeight += detailRowHeight;
  104. }
  105. }
  106. this.update(i, currentRowHeight);
  107. }
  108. };
  109. /**
  110. * Given the ScrollY position i.e. sum, provide the rowIndex
  111. * that is present in the current view port. Below handles edge cases.
  112. */
  113. /**
  114. * Given the ScrollY position i.e. sum, provide the rowIndex
  115. * that is present in the current view port. Below handles edge cases.
  116. * @param {?} scrollY
  117. * @return {?}
  118. */
  119. RowHeightCache.prototype.getRowIndex = /**
  120. * Given the ScrollY position i.e. sum, provide the rowIndex
  121. * that is present in the current view port. Below handles edge cases.
  122. * @param {?} scrollY
  123. * @return {?}
  124. */
  125. function (scrollY) {
  126. if (scrollY === 0)
  127. return 0;
  128. return this.calcRowIndex(scrollY);
  129. };
  130. /**
  131. * When a row is expanded or rowHeight is changed, update the height. This can
  132. * be utilized in future when Angular Data table supports dynamic row heights.
  133. */
  134. /**
  135. * When a row is expanded or rowHeight is changed, update the height. This can
  136. * be utilized in future when Angular Data table supports dynamic row heights.
  137. * @param {?} atRowIndex
  138. * @param {?} byRowHeight
  139. * @return {?}
  140. */
  141. RowHeightCache.prototype.update = /**
  142. * When a row is expanded or rowHeight is changed, update the height. This can
  143. * be utilized in future when Angular Data table supports dynamic row heights.
  144. * @param {?} atRowIndex
  145. * @param {?} byRowHeight
  146. * @return {?}
  147. */
  148. function (atRowIndex, byRowHeight) {
  149. if (!this.treeArray.length) {
  150. throw new Error("Update at index " + atRowIndex + " with value " + byRowHeight + " failed:\n Row Height cache not initialized.");
  151. }
  152. /** @type {?} */
  153. var n = this.treeArray.length;
  154. atRowIndex |= 0;
  155. while (atRowIndex < n) {
  156. this.treeArray[atRowIndex] += byRowHeight;
  157. atRowIndex |= atRowIndex + 1;
  158. }
  159. };
  160. /**
  161. * Range Sum query from 1 to the rowIndex
  162. */
  163. /**
  164. * Range Sum query from 1 to the rowIndex
  165. * @param {?} atIndex
  166. * @return {?}
  167. */
  168. RowHeightCache.prototype.query = /**
  169. * Range Sum query from 1 to the rowIndex
  170. * @param {?} atIndex
  171. * @return {?}
  172. */
  173. function (atIndex) {
  174. if (!this.treeArray.length) {
  175. throw new Error("query at index " + atIndex + " failed: Fenwick tree array not initialized.");
  176. }
  177. /** @type {?} */
  178. var sum = 0;
  179. atIndex |= 0;
  180. while (atIndex >= 0) {
  181. sum += this.treeArray[atIndex];
  182. atIndex = (atIndex & (atIndex + 1)) - 1;
  183. }
  184. return sum;
  185. };
  186. /**
  187. * Find the total height between 2 row indexes
  188. */
  189. /**
  190. * Find the total height between 2 row indexes
  191. * @param {?} atIndexA
  192. * @param {?} atIndexB
  193. * @return {?}
  194. */
  195. RowHeightCache.prototype.queryBetween = /**
  196. * Find the total height between 2 row indexes
  197. * @param {?} atIndexA
  198. * @param {?} atIndexB
  199. * @return {?}
  200. */
  201. function (atIndexA, atIndexB) {
  202. return this.query(atIndexB) - this.query(atIndexA - 1);
  203. };
  204. /**
  205. * Given the ScrollY position i.e. sum, provide the rowIndex
  206. * that is present in the current view port.
  207. */
  208. /**
  209. * Given the ScrollY position i.e. sum, provide the rowIndex
  210. * that is present in the current view port.
  211. * @private
  212. * @param {?} sum
  213. * @return {?}
  214. */
  215. RowHeightCache.prototype.calcRowIndex = /**
  216. * Given the ScrollY position i.e. sum, provide the rowIndex
  217. * that is present in the current view port.
  218. * @private
  219. * @param {?} sum
  220. * @return {?}
  221. */
  222. function (sum) {
  223. if (!this.treeArray.length)
  224. return 0;
  225. /** @type {?} */
  226. var pos = -1;
  227. /** @type {?} */
  228. var dataLength = this.treeArray.length;
  229. // Get the highest bit for the block size.
  230. /** @type {?} */
  231. var highestBit = Math.pow(2, dataLength.toString(2).length - 1);
  232. for (var blockSize = highestBit; blockSize !== 0; blockSize >>= 1) {
  233. /** @type {?} */
  234. var nextPos = pos + blockSize;
  235. if (nextPos < dataLength && sum >= this.treeArray[nextPos]) {
  236. sum -= this.treeArray[nextPos];
  237. pos = nextPos;
  238. }
  239. }
  240. return pos + 1;
  241. };
  242. return RowHeightCache;
  243. }());
  244. /**
  245. * This object contains the cache of the various row heights that are present inside
  246. * the data table. Its based on Fenwick tree data structure that helps with
  247. * querying sums that have time complexity of log n.
  248. *
  249. * Fenwick Tree Credits: http://petr-mitrichev.blogspot.com/2013/05/fenwick-tree-range-updates.html
  250. * https://github.com/mikolalysenko/fenwick-tree
  251. *
  252. */
  253. export { RowHeightCache };
  254. if (false) {
  255. /**
  256. * Tree Array stores the cumulative information of the row heights to perform efficient
  257. * range queries and updates. Currently the tree is initialized to the base row
  258. * height instead of the detail row height.
  259. * @type {?}
  260. * @private
  261. */
  262. RowHeightCache.prototype.treeArray;
  263. }
  264. //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm93LWhlaWdodC1jYWNoZS5qcyIsInNvdXJjZVJvb3QiOiJuZzovL0Bzd2ltbGFuZS9uZ3gtZGF0YXRhYmxlLyIsInNvdXJjZXMiOlsibGliL3V0aWxzL3Jvdy1oZWlnaHQtY2FjaGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7OztBQVNBOzs7Ozs7Ozs7O0lBQUE7Ozs7OztRQU1VLGNBQVMsR0FBYSxFQUFFLENBQUM7SUEySW5DLENBQUM7SUF6SUM7O09BRUc7Ozs7O0lBQ0gsbUNBQVU7Ozs7SUFBVjtRQUNFLElBQUksQ0FBQyxTQUFTLEdBQUcsRUFBRSxDQUFDO0lBQ3RCLENBQUM7SUFFRDs7Ozs7O09BTUc7Ozs7Ozs7SUFDSCxrQ0FBUzs7Ozs7O0lBQVQsVUFBVSxPQUFZO1FBQ1osSUFBQSxtQkFBSSxFQUFFLDZCQUFTLEVBQUUseUNBQWUsRUFBRSx5Q0FBZSxFQUFFLDJCQUFRLEVBQUUsK0JBQVUsRUFBRSxxQ0FBYTs7WUFDeEYsSUFBSSxHQUFHLE9BQU8sU0FBUyxLQUFLLFVBQVU7O1lBQ3RDLFVBQVUsR0FBRyxPQUFPLGVBQWUsS0FBSyxVQUFVO1FBRXhELElBQUksQ0FBQyxJQUFJLElBQUksS0FBSyxDQUFDLFNBQVMsQ0FBQyxFQUFFO1lBQzdCLE1BQU0sSUFBSSxLQUFLLENBQUMsMkhBQ3FCLFNBQVMsb0NBQWlDLENBQUMsQ0FBQztTQUNsRjtRQUVELHNGQUFzRjtRQUN0RixJQUFJLENBQUMsVUFBVSxJQUFJLEtBQUssQ0FBQyxlQUFlLENBQUMsRUFBRTtZQUN6QyxNQUFNLElBQUksS0FBSyxDQUFDLGlJQUNxQixlQUFlLG9DQUFpQyxDQUFDLENBQUM7U0FDeEY7O1lBRUssQ0FBQyxHQUFHLGVBQWUsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsTUFBTTtRQUNsRCxJQUFJLENBQUMsU0FBUyxHQUFHLElBQUksS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBRTlCLEtBQUssSUFBSSxDQUFD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LFNBQVMsQ0FBQyxNQUFNO1lBQUUsT0FBTyxDQUFDLENBQUM7O1lBRWpDLEdBQUcsR0FBRyxDQUFDLENBQUM7O1lBQ04sVUFBVSxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsTUFBTTs7O1lBR2xDLFVBQVUsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxVQUFVLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUM7UUFFakUsS0FBSyxJQUFJLFNBQVMsR0FBRyxVQUFVLEVBQUUsU0FBUyxLQUFLLENBQUMsRUFBRSxTQUFTLEtBQUssQ0FBQyxFQUFFOztnQkFDM0QsT0FBTyxHQUFHLEdBQUcsR0FBRyxTQUFTO1lBQy9CLElBQUksT0FBTyxHQUFHLFVBQVUsSUFBSSxHQUFHLElBQUksSUFBSSxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsRUFBRTtnQkFDMUQsR0FBRyxJQUFJLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLENBQUM7Z0JBQy9CLEdBQUcsR0FBRyxPQUFPLENBQUM7YUFDZjtTQUNGO1FBRUQsT0FBTyxHQUFHLEdBQUcsQ0FBQyxDQUFDO0lBQ2pCLENBQUM7SUFDSCxxQkFBQztBQUFELENBQUMsQUFqSkQsSUFpSkM7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7SUEzSUMsbUNBQWlDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBUaGlzIG9iamVjdCBjb250YWlucyB0aGUgY2FjaGUgb2YgdGhlIHZhcmlvdXMgcm93IGhlaWdodHMgdGhhdCBhcmUgcHJlc2VudCBpbnNpZGVcbiAqIHRoZSBkYXRhIHRhYmxlLiAgIEl0cyBiYXNlZCBvbiBGZW53aWNrIHRyZWUgZGF0YSBzdHJ1Y3R1cmUgdGhhdCBoZWxwcyB3aXRoXG4gKiBxdWVyeWluZyBzdW1zIHRoYXQgaGF2ZSB0aW1lIGNvbXBsZXhpdHkgb2YgbG9nIG4uXG4gKlxuICogRmVud2ljayBUcmVlIENyZWRpdHM6IGh0dHA6Ly9wZXRyLW1pdHJpY2hldi5ibG9nc3BvdC5jb20vMjAxMy8wNS9mZW53aWNrLXRyZWUtcmFuZ2UtdXBkYXRlcy5odG1sXG4gKiBodHRwczovL2dpdGh1Yi5jb20vbWlrb2xhbHlzZW5rby9mZW53aWNrLXRyZWVcbiAqXG4gKi9cbmV4cG9ydCBjbGFzcyBSb3dIZWlnaHRDYWNoZSB7XG4gIC8qKlxuICAgKiBUcmVlIEFycmF5IHN0b3JlcyB0aGUgY3VtdWxhdGl2ZSBpbmZvcm1hdGlvbiBvZiB0aGUgcm93IGhlaWdodHMgdG8gcGVyZm9ybSBlZmZpY2llbnRcbiAgICogcmFuZ2UgcXVlcmllcyBhbmQgdXBkYXRlcy4gIEN1cnJlbnRseSB0aGUgdHJlZSBpcyBpbml0aWFsaXplZCB0byB0aGUgYmFzZSByb3dcbiAgICogaGVpZ2h0IGluc3RlYWQgb2YgdGhlIGRldGFpbCByb3cgaGVpZ2h0LlxuICAgKi9cbiAgcHJpdmF0ZSB0cmVlQXJyYXk6IG51bWJlcltdID0gW107XG5cbiAgLyoqXG4gICAqIENsZWFyIHRoZSBUcmVlIGFycmF5LlxuICAgKi9cbiAgY2xlYXJDYWNoZSgpOiB2b2lkIHtcbiAgICB0aGlzLnRyZWVBcnJheSA9IFtdO1xuICB9XG5cbiAgLyoqXG4gICAqIEluaXRpYWxpemUgdGhlIEZlbndpY2sgdHJlZSB3aXRoIHJvdyBIZWlnaHRzLlxuICAgKlxuICAgKiBAcGFyYW0gcm93cyBUaGUgYXJyYXkgb2Ygcm93cyB3aGljaCBjb250YWluIHRoZSBleHBhbmRlZCBzdGF0dXMuXG4gICAqIEBwYXJhbSByb3dIZWlnaHQgVGhlIHJvdyBoZWlnaHQuXG4gICAqIEBwYXJhbSBkZXRhaWxSb3dIZWlnaHQgVGhlIGRldGFpbCByb3cgaGVpZ2h0LlxuICAgKi9cbiAgaW5pdENhY2hlKGRldGFpbHM6IGFueSk6IHZvaWQge1xuICAgIGNvbnN0IHsgcm93cywgcm93SGVpZ2h0LCBkZXRhaWxSb3dIZWlnaHQsIGV4dGVybmFsVmlydHVhbCwgcm93Q291bnQsIHJvd0luZGV4ZXMsIHJvd0V4cGFuc2lvbnMgfSA9IGRldGFpbHM7XG4gICAgY29uc3QgaXNGbiA9IHR5cGVvZiByb3dIZWlnaHQgPT09ICdmdW5jdGlvbic7XG4gICAgY29uc3QgaXNEZXRhaWxGbiA9IHR5cGVvZiBkZXRhaWxSb3dIZWlnaHQgPT09ICdmdW5jdGlvbic7XG5cbiAgICBpZiAoIWlzRm4gJiYgaXNOYU4ocm93SGVpZ2h0KSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBSb3cgSGVpZ2h0IGNhY2hlIGluaXRpYWxpemF0aW9uIGZhaWxlZC4gUGxlYXNlIGVuc3VyZSB0aGF0ICdyb3dIZWlnaHQnIGlzIGFcbiAgICAgICAgdmFsaWQgbnVtYmVyIG9yIGZ1bmN0aW9uIHZhbHVlOiAoJHtyb3dIZWlnaHR9KSB3aGVuICdzY3JvbGxiYXJWJyBpcyBlbmFibGVkLmApO1xuICAgIH1cblxuICAgIC8vIEFkZCB0aGlzIGFkZGl0aW9uYWwgZ3VhcmQgaW4gY2FzZSBkZXRhaWxSb3dIZWlnaHQgaXMgc2V0IHRvICdhdXRvJyBhcyBpdCB3b250IHdvcmsuXG4gICAgaWYgKCFpc0RldGFpbEZuICYmIGlzTmFOKGRldGFpbFJvd0hlaWdodCkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgUm93IEhlaWdodCBjYWNoZSBpbml0aWFsaXphdGlvbiBmYWlsZWQuIFBsZWFzZSBlbnN1cmUgdGhhdCAnZGV0YWlsUm93SGVpZ2h0JyBpcyBhXG4gICAgICAgIHZhbGlkIG51bWJlciBvciBmdW5jdGlvbiB2YWx1ZTogKCR7ZGV0YWlsUm93SGVpZ2h0fSkgd2hlbiAnc2Nyb2xsYmFyVicgaXMgZW5hYmxlZC5gKTtcbiAgICB9XG5cbiAgICBjb25zdCBuID0gZXh0ZXJuYWxWaXJ0dWFsID8gcm93Q291bnQgOiByb3dzLmxlbmd0aDtcbiAgICB0aGlzLnRyZWVBcnJheSA9IG5ldyBBcnJheShuKTtcblxuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgbjsgKytpKSB7XG4gICAgICB0aGlzLnRyZWVBcnJheVtpXSA9IDA7XG4gICAgfVxuXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBuOyArK2kpIHtcbiAgICAgIGNvbnN0IHJvdyA9IHJvd3NbaV07XG4gICAgICBsZXQgY3VycmVudFJvd0hlaWdodCA9IHJvd0hlaWdodDtcbiAgICAgIGlmIChpc0ZuKSB7XG4gICAgICAgIGN1cnJlbnRSb3dIZWlnaHQgPSByb3dIZWlnaHQocm93KTtcbiAgICAgIH1cblxuICAgICAgLy8gQWRkIHRoZSBkZXRhaWwgcm93IGhlaWdodCB0byB0aGUgYWxyZWFkeSBleHBhbmRlZCByb3dzLlxuICAgICAgLy8gVGhpcyBpcyB1c2VmdWwgZm9yIHRoZSB0YWJsZSB0aGF0IGdvZXMgdGhyb3VnaCBhIGZpbHRlciBvciBzb3J0LlxuICAgICAgY29uc3QgZXhwYW5kZWQgPSByb3dFeHBhbnNpb25zLmhhcyhyb3cpO1xuICAgICAgaWYgKHJvdyAmJiBleHBhbmRlZCkge1xuICAgICAgICBpZiAoaXNEZXRhaWxGbikge1xuICAgICAgICAgIGNvbnN0IGluZGV4ID0gcm93SW5kZXhlcy5nZXQocm93KTtcbiAgICAgICAgICBjdXJyZW50Um93SGVpZ2h0ICs9IGRldGFpbFJvd0hlaWdodChyb3csIGluZGV4KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBjdXJyZW50Um93SGVpZ2h0ICs9IGRldGFpbFJvd0hlaWdodDtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICB0aGlzLnVwZGF0ZShpLCBjdXJyZW50Um93SGVpZ2h0KTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogR2l2ZW4gdGhlIFNjcm9sbFkgcG9zaXRpb24gaS5lLiBzdW0sIHByb3ZpZGUgdGhlIHJvd0luZGV4XG4gICAqIHRoYXQgaXMgcHJlc2VudCBpbiB0aGUgY3VycmVudCB2aWV3IHBvcnQuICBCZWxvdyBoYW5kbGVzIGVkZ2UgY2FzZXMuXG4gICAqL1xuICBnZXRSb3dJbmRleChzY3JvbGxZOiBudW1iZXIpOiBudW1iZXIge1xuICAgIGlmIChzY3JvbGxZID09PSAwKSByZXR1cm4gMDtcbiAgICByZXR1cm4gdGhpcy5jYWxjUm93SW5kZXgoc2Nyb2xsWSk7XG4gIH1cblxuICAvKipcbiAgICogV2hlbiBhIHJvdyBpcyBleHBhbmRlZCBvciByb3dIZWlnaHQgaXMgY2hhbmdlZCwgdXBkYXRlIHRoZSBoZWlnaHQuICBUaGlzIGNhblxuICAgKiBiZSB1dGlsaXplZCBpbiBmdXR1cmUgd2hlbiBBbmd1bGFyIERhdGEgdGFibGUgc3VwcG9ydHMgZHluYW1pYyByb3cgaGVpZ2h0cy5cbiAgICovXG4gIHVwZGF0ZShhdFJvd0luZGV4OiBudW1iZXIsIGJ5Um93SGVpZ2h0OiBudW1iZXIpOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMudHJlZUFycmF5Lmxlbmd0aCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBVcGRhdGUgYXQgaW5kZXggJHthdFJvd0luZGV4fSB3aXRoIHZhbHVlICR7YnlSb3dIZWlnaHR9IGZhaWxlZDpcbiAgICAgICAgUm93IEhlaWdodCBjYWNoZSBub3QgaW5pdGlhbGl6ZWQuYCk7XG4gICAgfVxuXG4gICAgY29uc3QgbiA9IHRoaXMudHJlZUFycmF5Lmxlbmd0aDtcbiAgICBhdFJvd0luZGV4IHw9IDA7XG5cbiAgICB3aGlsZSAoYXRSb3dJbmRleCA8IG4pIHtcbiAgICAgIHRoaXMudHJlZUFycmF5W2F0Um93SW5kZXhdICs9IGJ5Um93SGVpZ2h0O1xuICAgICAgYXRSb3dJbmRleCB8PSBhdFJvd0luZGV4ICsgMTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUmFuZ2UgU3VtIHF1ZXJ5IGZyb20gMSB0byB0aGUgcm93SW5kZXhcbiAgICovXG4gIHF1ZXJ5KGF0SW5kZXg6IG51bWJlcik6IG51bWJlciB7XG4gICAgaWYgKCF0aGlzLnRyZWVBcnJheS5sZW5ndGgpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgcXVlcnkgYXQgaW5kZXggJHthdEluZGV4fSBmYWlsZWQ6IEZlbndpY2sgdHJlZSBhcnJheSBub3QgaW5pdGlhbGl6ZWQuYCk7XG4gICAgfVxuXG4gICAgbGV0IHN1bSA9IDA7XG4gICAgYXRJbmRleCB8PSAwO1xuXG4gICAgd2hpbGUgKGF0SW5kZXggPj0gMCkge1xuICAgICAgc3VtICs9IHRoaXMudHJlZUFycmF5W2F0SW5kZXhdO1xuICAgICAgYXRJbmRleCA9IChhdEluZGV4ICYgKGF0SW5kZXggKyAxKSkgLSAxO1xuICAgIH1cblxuICAgIHJldHVybiBzdW07XG4gIH1cblxuICAvKipcbiAgICogRmluZCB0aGUgdG90YWwgaGVpZ2h0IGJldHdlZW4gMiByb3cgaW5kZXhlc1xuICAgKi9cbiAgcXVlcnlCZXR3ZWVuKGF0SW5kZXhBOiBudW1iZXIsIGF0SW5kZXhCOiBudW1iZXIpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLnF1ZXJ5KGF0SW5kZXhCKSAtIHRoaXMucXVlcnkoYXRJbmRleEEgLSAxKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHaXZlbiB0aGUgU2Nyb2xsWSBwb3NpdGlvbiBpLmUuIHN1bSwgcHJvdmlkZSB0aGUgcm93SW5kZXhcbiAgICogdGhhdCBpcyBwcmVzZW50IGluIHRoZSBjdXJyZW50IHZpZXcgcG9ydC5cbiAgICovXG4gIHByaXZhdGUgY2FsY1Jvd0luZGV4KHN1bTogbnVtYmVyKTogbnVtYmVyIHtcbiAgICBpZiAoIXRoaXMudHJlZUFycmF5Lmxlbmd0aCkgcmV0dXJuIDA7XG5cbiAgICBsZXQgcG9zID0gLTE7XG4gICAgY29uc3QgZGF0YUxlbmd0aCA9IHRoaXMudHJlZUFycmF5Lmxlbmd0aDtcblxuICAgIC8vIEdldCB0aGUgaGlnaGVzdCBiaXQgZm9yIHRoZSBibG9jayBzaXplLlxuICAgIGNvbnN0IGhpZ2hlc3RCaXQgPSBNYXRoLnBvdygyLCBkYXRhTGVuZ3RoLnRvU3RyaW5nKDIpLmxlbmd0aCAtIDEpO1xuXG4gICAgZm9yIChsZXQgYmxvY2tTaXplID0gaGlnaGVzdEJpdDsgYmxvY2tTaXplICE9PSAwOyBibG9ja1NpemUgPj49IDEpIHtcbiAgICAgIGNvbnN0IG5leHRQb3MgPSBwb3MgKyBibG9ja1NpemU7XG4gICAgICBpZiAobmV4dFBvcyA8IGRhdGFMZW5ndGggJiYgc3VtID49IHRoaXMudHJlZUFycmF5W25leHRQb3NdKSB7XG4gICAgICAgIHN1bSAtPSB0aGlzLnRyZWVBcnJheVtuZXh0UG9zXTtcbiAgICAgICAgcG9zID0gbmV4dFBvcztcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gcG9zICsgMTtcbiAgfVxufVxuIl19