merge.js 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. const normalize_1 = require("./normalize");
  4. const range_tree_1 = require("./range-tree");
  5. /**
  6. * Merges a list of process coverages.
  7. *
  8. * The result is normalized.
  9. * The input values may be mutated, it is not safe to use them after passing
  10. * them to this function.
  11. * The computation is synchronous.
  12. *
  13. * @param processCovs Process coverages to merge.
  14. * @return Merged process coverage.
  15. */
  16. function mergeProcessCovs(processCovs) {
  17. if (processCovs.length === 0) {
  18. return { result: [] };
  19. }
  20. const urlToScripts = new Map();
  21. for (const processCov of processCovs) {
  22. for (const scriptCov of processCov.result) {
  23. let scriptCovs = urlToScripts.get(scriptCov.url);
  24. if (scriptCovs === undefined) {
  25. scriptCovs = [];
  26. urlToScripts.set(scriptCov.url, scriptCovs);
  27. }
  28. scriptCovs.push(scriptCov);
  29. }
  30. }
  31. const result = [];
  32. for (const scripts of urlToScripts.values()) {
  33. // assert: `scripts.length > 0`
  34. result.push(mergeScriptCovs(scripts));
  35. }
  36. const merged = { result };
  37. normalize_1.normalizeProcessCov(merged);
  38. return merged;
  39. }
  40. exports.mergeProcessCovs = mergeProcessCovs;
  41. /**
  42. * Merges a list of matching script coverages.
  43. *
  44. * Scripts are matching if they have the same `url`.
  45. * The result is normalized.
  46. * The input values may be mutated, it is not safe to use them after passing
  47. * them to this function.
  48. * The computation is synchronous.
  49. *
  50. * @param scriptCovs Process coverages to merge.
  51. * @return Merged script coverage, or `undefined` if the input list was empty.
  52. */
  53. function mergeScriptCovs(scriptCovs) {
  54. if (scriptCovs.length === 0) {
  55. return undefined;
  56. }
  57. else if (scriptCovs.length === 1) {
  58. const merged = scriptCovs[0];
  59. normalize_1.deepNormalizeScriptCov(merged);
  60. return merged;
  61. }
  62. const first = scriptCovs[0];
  63. const scriptId = first.scriptId;
  64. const url = first.url;
  65. const rangeToFuncs = new Map();
  66. for (const scriptCov of scriptCovs) {
  67. for (const funcCov of scriptCov.functions) {
  68. const rootRange = stringifyFunctionRootRange(funcCov);
  69. let funcCovs = rangeToFuncs.get(rootRange);
  70. if (funcCovs === undefined ||
  71. // if the entry in rangeToFuncs is function-level granularity and
  72. // the new coverage is block-level, prefer block-level.
  73. (!funcCovs[0].isBlockCoverage && funcCov.isBlockCoverage)) {
  74. funcCovs = [];
  75. rangeToFuncs.set(rootRange, funcCovs);
  76. }
  77. else if (funcCovs[0].isBlockCoverage && !funcCov.isBlockCoverage) {
  78. // if the entry in rangeToFuncs is block-level granularity, we should
  79. // not append function level granularity.
  80. continue;
  81. }
  82. funcCovs.push(funcCov);
  83. }
  84. }
  85. const functions = [];
  86. for (const funcCovs of rangeToFuncs.values()) {
  87. // assert: `funcCovs.length > 0`
  88. functions.push(mergeFunctionCovs(funcCovs));
  89. }
  90. const merged = { scriptId, url, functions };
  91. normalize_1.normalizeScriptCov(merged);
  92. return merged;
  93. }
  94. exports.mergeScriptCovs = mergeScriptCovs;
  95. /**
  96. * Returns a string representation of the root range of the function.
  97. *
  98. * This string can be used to match function with same root range.
  99. * The string is derived from the start and end offsets of the root range of
  100. * the function.
  101. * This assumes that `ranges` is non-empty (true for valid function coverages).
  102. *
  103. * @param funcCov Function coverage with the range to stringify
  104. * @internal
  105. */
  106. function stringifyFunctionRootRange(funcCov) {
  107. const rootRange = funcCov.ranges[0];
  108. return `${rootRange.startOffset.toString(10)};${rootRange.endOffset.toString(10)}`;
  109. }
  110. /**
  111. * Merges a list of matching function coverages.
  112. *
  113. * Functions are matching if their root ranges have the same span.
  114. * The result is normalized.
  115. * The input values may be mutated, it is not safe to use them after passing
  116. * them to this function.
  117. * The computation is synchronous.
  118. *
  119. * @param funcCovs Function coverages to merge.
  120. * @return Merged function coverage, or `undefined` if the input list was empty.
  121. */
  122. function mergeFunctionCovs(funcCovs) {
  123. if (funcCovs.length === 0) {
  124. return undefined;
  125. }
  126. else if (funcCovs.length === 1) {
  127. const merged = funcCovs[0];
  128. normalize_1.normalizeFunctionCov(merged);
  129. return merged;
  130. }
  131. const functionName = funcCovs[0].functionName;
  132. const trees = [];
  133. for (const funcCov of funcCovs) {
  134. // assert: `fn.ranges.length > 0`
  135. // assert: `fn.ranges` is sorted
  136. trees.push(range_tree_1.RangeTree.fromSortedRanges(funcCov.ranges));
  137. }
  138. // assert: `trees.length > 0`
  139. const mergedTree = mergeRangeTrees(trees);
  140. normalize_1.normalizeRangeTree(mergedTree);
  141. const ranges = mergedTree.toRanges();
  142. const isBlockCoverage = !(ranges.length === 1 && ranges[0].count === 0);
  143. const merged = { functionName, ranges, isBlockCoverage };
  144. // assert: `merged` is normalized
  145. return merged;
  146. }
  147. exports.mergeFunctionCovs = mergeFunctionCovs;
  148. /**
  149. * @precondition Same `start` and `end` for all the trees
  150. */
  151. function mergeRangeTrees(trees) {
  152. if (trees.length <= 1) {
  153. return trees[0];
  154. }
  155. const first = trees[0];
  156. let delta = 0;
  157. for (const tree of trees) {
  158. delta += tree.delta;
  159. }
  160. const children = mergeRangeTreeChildren(trees);
  161. return new range_tree_1.RangeTree(first.start, first.end, delta, children);
  162. }
  163. class RangeTreeWithParent {
  164. constructor(parentIndex, tree) {
  165. this.parentIndex = parentIndex;
  166. this.tree = tree;
  167. }
  168. }
  169. class StartEvent {
  170. constructor(offset, trees) {
  171. this.offset = offset;
  172. this.trees = trees;
  173. }
  174. static compare(a, b) {
  175. return a.offset - b.offset;
  176. }
  177. }
  178. class StartEventQueue {
  179. constructor(queue) {
  180. this.queue = queue;
  181. this.nextIndex = 0;
  182. this.pendingOffset = 0;
  183. this.pendingTrees = undefined;
  184. }
  185. static fromParentTrees(parentTrees) {
  186. const startToTrees = new Map();
  187. for (const [parentIndex, parentTree] of parentTrees.entries()) {
  188. for (const child of parentTree.children) {
  189. let trees = startToTrees.get(child.start);
  190. if (trees === undefined) {
  191. trees = [];
  192. startToTrees.set(child.start, trees);
  193. }
  194. trees.push(new RangeTreeWithParent(parentIndex, child));
  195. }
  196. }
  197. const queue = [];
  198. for (const [startOffset, trees] of startToTrees) {
  199. queue.push(new StartEvent(startOffset, trees));
  200. }
  201. queue.sort(StartEvent.compare);
  202. return new StartEventQueue(queue);
  203. }
  204. setPendingOffset(offset) {
  205. this.pendingOffset = offset;
  206. }
  207. pushPendingTree(tree) {
  208. if (this.pendingTrees === undefined) {
  209. this.pendingTrees = [];
  210. }
  211. this.pendingTrees.push(tree);
  212. }
  213. next() {
  214. const pendingTrees = this.pendingTrees;
  215. const nextEvent = this.queue[this.nextIndex];
  216. if (pendingTrees === undefined) {
  217. this.nextIndex++;
  218. return nextEvent;
  219. }
  220. else if (nextEvent === undefined) {
  221. this.pendingTrees = undefined;
  222. return new StartEvent(this.pendingOffset, pendingTrees);
  223. }
  224. else {
  225. if (this.pendingOffset < nextEvent.offset) {
  226. this.pendingTrees = undefined;
  227. return new StartEvent(this.pendingOffset, pendingTrees);
  228. }
  229. else {
  230. if (this.pendingOffset === nextEvent.offset) {
  231. this.pendingTrees = undefined;
  232. for (const tree of pendingTrees) {
  233. nextEvent.trees.push(tree);
  234. }
  235. }
  236. this.nextIndex++;
  237. return nextEvent;
  238. }
  239. }
  240. }
  241. }
  242. function mergeRangeTreeChildren(parentTrees) {
  243. const result = [];
  244. const startEventQueue = StartEventQueue.fromParentTrees(parentTrees);
  245. const parentToNested = new Map();
  246. let openRange;
  247. while (true) {
  248. const event = startEventQueue.next();
  249. if (event === undefined) {
  250. break;
  251. }
  252. if (openRange !== undefined && openRange.end <= event.offset) {
  253. result.push(nextChild(openRange, parentToNested));
  254. openRange = undefined;
  255. }
  256. if (openRange === undefined) {
  257. let openRangeEnd = event.offset + 1;
  258. for (const { parentIndex, tree } of event.trees) {
  259. openRangeEnd = Math.max(openRangeEnd, tree.end);
  260. insertChild(parentToNested, parentIndex, tree);
  261. }
  262. startEventQueue.setPendingOffset(openRangeEnd);
  263. openRange = { start: event.offset, end: openRangeEnd };
  264. }
  265. else {
  266. for (const { parentIndex, tree } of event.trees) {
  267. if (tree.end > openRange.end) {
  268. const right = tree.split(openRange.end);
  269. startEventQueue.pushPendingTree(new RangeTreeWithParent(parentIndex, right));
  270. }
  271. insertChild(parentToNested, parentIndex, tree);
  272. }
  273. }
  274. }
  275. if (openRange !== undefined) {
  276. result.push(nextChild(openRange, parentToNested));
  277. }
  278. return result;
  279. }
  280. function insertChild(parentToNested, parentIndex, tree) {
  281. let nested = parentToNested.get(parentIndex);
  282. if (nested === undefined) {
  283. nested = [];
  284. parentToNested.set(parentIndex, nested);
  285. }
  286. nested.push(tree);
  287. }
  288. function nextChild(openRange, parentToNested) {
  289. const matchingTrees = [];
  290. for (const nested of parentToNested.values()) {
  291. if (nested.length === 1 && nested[0].start === openRange.start && nested[0].end === openRange.end) {
  292. matchingTrees.push(nested[0]);
  293. }
  294. else {
  295. matchingTrees.push(new range_tree_1.RangeTree(openRange.start, openRange.end, 0, nested));
  296. }
  297. }
  298. parentToNested.clear();
  299. return mergeRangeTrees(matchingTrees);
  300. }
  301. //# sourceMappingURL=data:application/json;charset=utf8;base64,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QUM7QUFDekMsQ0FBQyIsImZpbGUiOiJtZXJnZS5qcyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIGRlZXBOb3JtYWxpemVTY3JpcHRDb3YsXG4gIG5vcm1hbGl6ZUZ1bmN0aW9uQ292LFxuICBub3JtYWxpemVQcm9jZXNzQ292LFxuICBub3JtYWxpemVSYW5nZVRyZWUsXG4gIG5vcm1hbGl6ZVNjcmlwdENvdixcbn0gZnJvbSBcIi4vbm9ybWFsaXplXCI7XG5pbXBvcnQgeyBSYW5nZVRyZWUgfSBmcm9tIFwiLi9yYW5nZS10cmVlXCI7XG5pbXBvcnQgeyBGdW5jdGlvbkNvdiwgUHJvY2Vzc0NvdiwgUmFuZ2UsIFJhbmdlQ292LCBTY3JpcHRDb3YgfSBmcm9tIFwiLi90eXBlc1wiO1xuXG4vKipcbiAqIE1lcmdlcyBhIGxpc3Qgb2YgcHJvY2VzcyBjb3ZlcmFnZXMuXG4gKlxuICogVGhlIHJlc3VsdCBpcyBub3JtYWxpemVkLlxuICogVGhlIGlucHV0IHZhbHVlcyBtYXkgYmUgbXV0YXRlZCwgaXQgaXMgbm90IHNhZmUgdG8gdXNlIHRoZW0gYWZ0ZXIgcGFzc2luZ1xuICogdGhlbSB0byB0aGlzIGZ1bmN0aW9uLlxuICogVGhlIGNvbXB1dGF0aW9uIGlzIHN5bmNocm9ub3VzLlxuICpcbiAqIEBwYXJhbSBwcm9jZXNzQ292cyBQcm9jZXNzIGNvdmVyYWdlcyB0byBtZXJnZS5cbiAqIEByZXR1cm4gTWVyZ2VkIHByb2Nlc3MgY292ZXJhZ2UuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBtZXJnZVByb2Nlc3NDb3ZzKHByb2Nlc3NDb3ZzOiBSZWFkb25seUFycmF5PFByb2Nlc3NDb3Y+KTogUHJvY2Vzc0NvdiB7XG4gIGlmIChwcm9jZXNzQ292cy5sZW5ndGggPT09IDApIHtcbiAgICByZXR1cm4ge3Jlc3VsdDogW119O1xuICB9XG5cbiAgY29uc3QgdXJsVG9TY3JpcHRzOiBNYXA8c3RyaW5nLCBTY3JpcHRDb3ZbXT4gPSBuZXcgTWFwKCk7XG4gIGZvciAoY29uc3QgcHJvY2Vzc0NvdiBvZiBwcm9jZXNzQ292cykge1xuICAgIGZvciAoY29uc3Qgc2NyaXB0Q292IG9mIHByb2Nlc3NDb3YucmVzdWx0KSB7XG4gICAgICBsZXQgc2NyaXB0Q292czogU2NyaXB0Q292W10gfCB1bmRlZmluZWQgPSB1cmxUb1NjcmlwdHMuZ2V0KHNjcmlwdENvdi51cmwpO1xuICAgICAgaWYgKHNjcmlwdENvdnMgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICBzY3JpcHRDb3ZzID0gW107XG4gICAgICAgIHVybFRvU2NyaXB0cy5zZXQoc2NyaXB0Q292LnVybCwgc2NyaXB0Q292cyk7XG4gICAgICB9XG4gICAgICBzY3JpcHRDb3ZzLnB1c2goc2NyaXB0Q292KTtcbiAgICB9XG4gIH1cblxuICBjb25zdCByZXN1bHQ6IFNjcmlwdENvdltdID0gW107XG4gIGZvciAoY29uc3Qgc2NyaXB0cyBvZiB1cmxUb1NjcmlwdHMudmFsdWVzKCkpIHtcbiAgICAvLyBhc3NlcnQ6IGBzY3JpcHRzLmxlbmd0aCA+IDBgXG4gICAgcmVzdWx0LnB1c2gobWVyZ2VTY3JpcHRDb3ZzKHNjcmlwdHMpISk7XG4gIH1cbiAgY29uc3QgbWVyZ2VkOiBQcm9jZXNzQ292ID0ge3Jlc3VsdH07XG5cbiAgbm9ybWFsaXplUHJvY2Vzc0NvdihtZXJnZWQpO1xuICByZXR1cm4gbWVyZ2VkO1xufVxuXG4vKipcbiAqIE1lcmdlcyBhIGxpc3Qgb2YgbWF0Y2hpbmcgc2NyaXB0IGNvdmVyYWdlcy5cbiAqXG4gKiBTY3JpcHRzIGFyZSBtYXRjaGluZyBpZiB0aGV5IGhhdmUgdGhlIHNhbWUgYHVybGAuXG4gKiBUaGUgcmVzdWx0IGlzIG5vcm1hbGl6ZWQuXG4gKiBUaGUgaW5wdXQgdmFsdWVzIG1heSBiZSBtdXRhdGVkLCBpdCBpcyBub3Qgc2FmZSB0byB1c2UgdGhlbSBhZnRlciBwYXNzaW5nXG4gKiB0aGVtIHRvIHRoaXMgZnVuY3Rpb24uXG4gKiBUaGUgY29tcHV0YXRpb24gaXMgc3luY2hyb25vdXMuXG4gKlxuICogQHBhcmFtIHNjcmlwdENvdnMgUHJvY2VzcyBjb3ZlcmFnZXMgdG8gbWVyZ2UuXG4gKiBAcmV0dXJuIE1lcmdlZCBzY3JpcHQgY292ZXJhZ2UsIG9yIGB1bmRlZmluZWRgIGlmIHRoZSBpbnB1dCBsaXN0IHdhcyBlbXB0eS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG1lcmdlU2NyaXB0Q292cyhzY3JpcHRDb3ZzOiBSZWFkb25seUFycmF5PFNjcmlwdENvdj4pOiBTY3JpcHRDb3YgfCB1bmRlZmluZWQge1xuICBpZiAoc2NyaXB0Q292cy5sZW5ndGggPT09IDApIHtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9IGVsc2UgaWYgKHNjcmlwdENvdnMubGVuZ3RoID09PSAxKSB7XG4gICAgY29uc3QgbWVyZ2VkOiBTY3JpcHRDb3YgPSBzY3JpcHRDb3ZzWzBdO1xuICAgIGRlZXBOb3JtYWxpemVTY3JpcHRDb3YobWVyZ2VkKTtcbiAgICByZXR1cm4gbWVyZ2VkO1xuICB9XG5cbiAgY29uc3QgZmlyc3Q6IFNjcmlwdENvdiA9IHNjcmlwdENvdnNbMF07XG4gIGNvbnN0IHNjcmlwdElkOiBzdHJpbmcgPSBmaXJzdC5zY3JpcHRJZDtcbiAgY29uc3QgdXJsOiBzdHJpbmcgPSBmaXJzdC51cmw7XG5cbiAgY29uc3QgcmFuZ2VUb0Z1bmNzOiBNYXA8c3RyaW5nLCBGdW5jdGlvbkNvdltdPiA9IG5ldyBNYXAoKTtcbiAgZm9yIChjb25zdCBzY3JpcHRDb3Ygb2Ygc2NyaXB0Q292cykge1xuICAgIGZvciAoY29uc3QgZnVuY0NvdiBvZiBzY3JpcHRDb3YuZnVuY3Rpb25zKSB7XG4gICAgICBjb25zdCByb290UmFuZ2U6IHN0cmluZyA9IHN0cmluZ2lmeUZ1bmN0aW9uUm9vdFJhbmdlKGZ1bmNDb3YpO1xuICAgICAgbGV0IGZ1bmNDb3ZzOiBGdW5jdGlvbkNvdltdIHwgdW5kZWZpbmVkID0gcmFuZ2VUb0Z1bmNzLmdldChyb290UmFuZ2UpO1xuXG4gICAgICBpZiAoZnVuY0NvdnMgPT09IHVuZGVmaW5lZCB8fFxuICAgICAgICAvLyBpZiB0aGUgZW50cnkgaW4gcmFuZ2VUb0Z1bmNzIGlzIGZ1bmN0aW9uLWxldmVsIGdyYW51bGFyaXR5IGFuZFxuICAgICAgICAvLyB0aGUgbmV3IGNvdmVyYWdlIGlzIGJsb2NrLWxldmVsLCBwcmVmZXIgYmxvY2stbGV2ZWwuXG4gICAgICAgICghZnVuY0NvdnNbMF0uaXNCbG9ja0NvdmVyYWdlICYmIGZ1bmNDb3YuaXNCbG9ja0NvdmVyYWdlKSkge1xuICAgICAgICBmdW5jQ292cyA9IFtdO1xuICAgICAgICByYW5nZVRvRnVuY3Muc2V0KHJvb3RSYW5nZSwgZnVuY0NvdnMpO1xuICAgICAgfSBlbHNlIGlmIChmdW5jQ292c1swXS5pc0Jsb2NrQ292ZXJhZ2UgJiYgIWZ1bmNDb3YuaXNCbG9ja0NvdmVyYWdlKSB7XG4gICAgICAgIC8vIGlmIHRoZSBlbnRyeSBpbiByYW5nZVRvRnVuY3MgaXMgYmxvY2stbGV2ZWwgZ3JhbnVsYXJpdHksIHdlIHNob3VsZFxuICAgICAgICAvLyBub3QgYXBwZW5kIGZ1bmN0aW9uIGxldmVsIGdyYW51bGFyaXR5LlxuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cbiAgICAgIGZ1bmNDb3ZzLnB1c2goZnVuY0Nvdik7XG4gICAgfVxuICB9XG5cbiAgY29uc3QgZnVuY3Rpb25zOiBGdW5jdGlvbkNvdltdID0gW107XG4gIGZvciAoY29uc3QgZnVuY0NvdnMgb2YgcmFuZ2VUb0Z1bmNzLnZhbHVlcygpKSB7XG4gICAgLy8gYXNzZXJ0OiBgZnVuY0NvdnMubGVuZ3RoID4gMGBcbiAgICBmdW5jdGlvbnMucHVzaChtZXJnZUZ1bmN0aW9uQ292cyhmdW5jQ292cykhKTtcbiAgfVxuXG4gIGNvbnN0IG1lcmdlZDogU2NyaXB0Q292ID0ge3NjcmlwdElkLCB1cmwsIGZ1bmN0aW9uc307XG4gIG5vcm1hbGl6ZVNjcmlwdENvdihtZXJnZWQpO1xuICByZXR1cm4gbWVyZ2VkO1xufVxuXG4vKipcbiAqIFJldHVybnMgYSBzdHJpbmcgcmVwcmVzZW50YXRpb24gb2YgdGhlIHJvb3QgcmFuZ2Ugb2YgdGhlIGZ1bmN0aW9uLlxuICpcbiAqIFRoaXMgc3RyaW5nIGNhbiBiZSB1c2VkIHRvIG1hdGNoIGZ1bmN0aW9uIHdpdGggc2FtZSByb290IHJhbmdlLlxuICogVGhlIHN0cmluZyBpcyBkZXJpdmVkIGZyb20gdGhlIHN0YXJ0IGFuZCBlbmQgb2Zmc2V0cyBvZiB0aGUgcm9vdCByYW5nZSBvZlxuICogdGhlIGZ1bmN0aW9uLlxuICogVGhpcyBhc3N1bWVzIHRoYXQgYHJhbmdlc2AgaXMgbm9uLWVtcHR5ICh0cnVlIGZvciB2YWxpZCBmdW5jdGlvbiBjb3ZlcmFnZXMpLlxuICpcbiAqIEBwYXJhbSBmdW5jQ292IEZ1bmN0aW9uIGNvdmVyYWdlIHdpdGggdGhlIHJhbmdlIHRvIHN0cmluZ2lmeVxuICogQGludGVybmFsXG4gKi9cbmZ1bmN0aW9uIHN0cmluZ2lmeUZ1bmN0aW9uUm9vdFJhbmdlKGZ1bmNDb3Y6IFJlYWRvbmx5PEZ1bmN0aW9uQ292Pik6IHN0cmluZyB7XG4gIGNvbnN0IHJvb3RSYW5nZTogUmFuZ2VDb3YgPSBmdW5jQ292LnJhbmdlc1swXTtcbiAgcmV0dXJuIGAke3Jvb3RSYW5nZS5zdGFydE9mZnNldC50b1N0cmluZygxMCl9OyR7cm9vdFJhbmdlLmVuZE9mZnNldC50b1N0cmluZygxMCl9YDtcbn1cblxuLyoqXG4gKiBNZXJnZXMgYSBsaXN0IG9mIG1hdGNoaW5nIGZ1bmN0aW9uIGNvdmVyYWdlcy5cbiAqXG4gKiBGdW5jdGlvbnMgYXJlIG1hdGNoaW5nIGlmIHRoZWlyIHJvb3QgcmFuZ2VzIGhhdmUgdGhlIHNhbWUgc3Bhbi5cbiAqIFRoZSByZXN1bHQgaXMgbm9ybWFsaXplZC5cbiAqIFRoZSBpbnB1dCB2YWx1ZXMgbWF5IGJlIG11dGF0ZWQsIGl0IGlzIG5vdCBzYWZlIHRvIHVzZSB0aGVtIGFmdGVyIHBhc3NpbmdcbiAqIHRoZW0gdG8gdGhpcyBmdW5jdGlvbi5cbiAqIFRoZSBjb21wdXRhdGlvbiBpcyBzeW5jaHJvbm91cy5cbiAqXG4gKiBAcGFyYW0gZnVuY0NvdnMgRnVuY3Rpb24gY292ZXJhZ2VzIHRvIG1lcmdlLlxuICogQHJldHVybiBNZXJnZWQgZnVuY3Rpb24gY292ZXJhZ2UsIG9yIGB1bmRlZmluZWRgIGlmIHRoZSBpbnB1dCBsaXN0IHdhcyBlbXB0eS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG1lcmdlRnVuY3Rpb25Db3ZzKGZ1bmNDb3ZzOiBSZWFkb25seUFycmF5PEZ1bmN0aW9uQ292Pik6IEZ1bmN0aW9uQ292IHwgdW5kZWZpbmVkIHtcbiAgaWYgKGZ1bmNDb3ZzLmxlbmd0aCA9PT0gMCkge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH0gZWxzZSBpZiAoZnVuY0NvdnMubGVuZ3RoID09PSAxKSB7XG4gICAgY29uc3QgbWVyZ2VkOiBGdW5jdGlvbkNvdiA9IGZ1bmNDb3ZzWzBdO1xuICAgIG5vcm1hbGl6ZUZ1bmN0aW9uQ292KG1lcmdlZCk7XG4gICAgcmV0dXJuIG1lcmdlZDtcbiAgfVxuXG4gIGNvbnN0IGZ1bmN0aW9uTmFtZTogc3RyaW5nID0gZnVuY0NvdnNbMF0uZnVuY3Rpb25OYW1lO1xuXG4gIGNvbnN0IHRyZWVzOiBSYW5nZVRyZWVbXSA9IFtdO1xuICBmb3IgKGNvbnN0IGZ1bmNDb3Ygb2YgZnVuY0NvdnMpIHtcbiAgICAvLyBhc3NlcnQ6IGBmbi5yYW5nZXMubGVuZ3RoID4gMGBcbiAgICAvLyBhc3NlcnQ6IGBmbi5yYW5nZXNgIGlzIHNvcnRlZFxuICAgIHRyZWVzLnB1c2goUmFuZ2VUcmVlLmZyb21Tb3J0ZWRSYW5nZXMoZnVuY0Nvdi5yYW5nZXMpISk7XG4gIH1cblxuICAvLyBhc3NlcnQ6IGB0cmVlcy5sZW5ndGggPiAwYFxuICBjb25zdCBtZXJnZWRUcmVlOiBSYW5nZVRyZWUgPSBtZXJnZVJhbmdlVHJlZXModHJlZXMpITtcbiAgbm9ybWFsaXplUmFuZ2VUcmVlKG1lcmdlZFRyZWUpO1xuICBjb25zdCByYW5nZXM6IFJhbmdlQ292W10gPSBtZXJnZWRUcmVlLnRvUmFuZ2VzKCk7XG4gIGNvbnN0IGlzQmxvY2tDb3ZlcmFnZTogYm9vbGVhbiA9ICEocmFuZ2VzLmxlbmd0aCA9PT0gMSAmJiByYW5nZXNbMF0uY291bnQgPT09IDApO1xuXG4gIGNvbnN0IG1lcmdlZDogRnVuY3Rpb25Db3YgPSB7ZnVuY3Rpb25OYW1lLCByYW5nZXMsIGlzQmxvY2tDb3ZlcmFnZX07XG4gIC8vIGFzc2VydDogYG1lcmdlZGAgaXMgbm9ybWFsaXplZFxuICByZXR1cm4gbWVyZ2VkO1xufVxuXG4vKipcbiAqIEBwcmVjb25kaXRpb24gU2FtZSBgc3RhcnRgIGFuZCBgZW5kYCBmb3IgYWxsIHRoZSB0cmVlc1xuICovXG5mdW5jdGlvbiBtZXJnZVJhbmdlVHJlZXModHJlZXM6IFJlYWRvbmx5QXJyYXk8UmFuZ2VUcmVlPik6IFJhbmdlVHJlZSB8IHVuZGVmaW5lZCB7XG4gIGlmICh0cmVlcy5sZW5ndGggPD0gMSkge1xuICAgIHJldHVybiB0cmVlc1swXTtcbiAgfVxuICBjb25zdCBmaXJzdDogUmFuZ2VUcmVlID0gdHJlZXNbMF07XG4gIGxldCBkZWx0YTogbnVtYmVyID0gMDtcbiAgZm9yIChjb25zdCB0cmVlIG9mIHRyZWVzKSB7XG4gICAgZGVsdGEgKz0gdHJlZS5kZWx0YTtcbiAgfVxuICBjb25zdCBjaGlsZHJlbjogUmFuZ2VUcmVlW10gPSBtZXJnZVJhbmdlVHJlZUNoaWxkcmVuKHRyZWVzKTtcbiAgcmV0dXJuIG5ldyBSYW5nZVRyZWUoZmlyc3Quc3RhcnQsIGZpcnN0LmVuZCwgZGVsdGEsIGNoaWxkcmVuKTtcbn1cblxuY2xhc3MgUmFuZ2VUcmVlV2l0aFBhcmVudCB7XG4gIHJlYWRvbmx5IHBhcmVudEluZGV4OiBudW1iZXI7XG4gIHJlYWRvbmx5IHRyZWU6IFJhbmdlVHJlZTtcblxuICBjb25zdHJ1Y3RvcihwYXJlbnRJbmRleDogbnVtYmVyLCB0cmVlOiBSYW5nZVRyZWUpIHtcbiAgICB0aGlzLnBhcmVudEluZGV4ID0gcGFyZW50SW5kZXg7XG4gICAgdGhpcy50cmVlID0gdHJlZTtcbiAgfVxufVxuXG5jbGFzcyBTdGFydEV2ZW50IHtcbiAgcmVhZG9ubHkgb2Zmc2V0OiBudW1iZXI7XG4gIHJlYWRvbmx5IHRyZWVzOiBSYW5nZVRyZWVXaXRoUGFyZW50W107XG5cbiAgY29uc3RydWN0b3Iob2Zmc2V0OiBudW1iZXIsIHRyZWVzOiBSYW5nZVRyZWVXaXRoUGFyZW50W10pIHtcbiAgICB0aGlzLm9mZnNldCA9IG9mZnNldDtcbiAgICB0aGlzLnRyZWVzID0gdHJlZXM7XG4gIH1cblxuICBzdGF0aWMgY29tcGFyZShhOiBTdGFydEV2ZW50LCBiOiBTdGFydEV2ZW50KTogbnVtYmVyIHtcbiAgICByZXR1cm4gYS5vZmZzZXQgLSBiLm9mZnNldDtcbiAgfVxufVxuXG5jbGFzcyBTdGFydEV2ZW50UXVldWUge1xuICBwcml2YXRlIHJlYWRvbmx5IHF1ZXVlOiBTdGFydEV2ZW50W107XG4gIHByaXZhdGUgbmV4dEluZGV4OiBudW1iZXI7XG4gIHByaXZhdGUgcGVuZGluZ09mZnNldDogbnVtYmVyO1xuICBwcml2YXRlIHBlbmRpbmdUcmVlczogUmFuZ2VUcmVlV2l0aFBhcmVudFtdIHwgdW5kZWZpbmVkO1xuXG4gIHByaXZhdGUgY29uc3RydWN0b3IocXVldWU6IFN0YXJ0RXZlbnRbXSkge1xuICAgIHRoaXMucXVldWUgPSBxdWV1ZTtcbiAgICB0aGlzLm5leHRJbmRleCA9IDA7XG4gICAgdGhpcy5wZW5kaW5nT2Zmc2V0ID0gMDtcbiAgICB0aGlzLnBlbmRpbmdUcmVlcyA9IHVuZGVmaW5lZDtcbiAgfVxuXG4gIHN0YXRpYyBmcm9tUGFyZW50VHJlZXMocGFyZW50VHJlZXM6IFJlYWRvbmx5QXJyYXk8UmFuZ2VUcmVlPik6IFN0YXJ0RXZlbnRRdWV1ZSB7XG4gICAgY29uc3Qgc3RhcnRUb1RyZWVzOiBNYXA8bnVtYmVyLCBSYW5nZVRyZWVXaXRoUGFyZW50W10+ID0gbmV3IE1hcCgpO1xuICAgIGZvciAoY29uc3QgW3BhcmVudEluZGV4LCBwYXJlbnRUcmVlXSBvZiBwYXJlbnRUcmVlcy5lbnRyaWVzKCkpIHtcbiAgICAgIGZvciAoY29uc3QgY2hpbGQgb2YgcGFyZW50VHJlZS5jaGlsZHJlbikge1xuICAgICAgICBsZXQgdHJlZXM6IFJhbmdlVHJlZVdpdGhQYXJlbnRbXSB8IHVuZGVmaW5lZCA9IHN0YXJ0VG9UcmVlcy5nZXQoY2hpbGQuc3RhcnQpO1xuICAgICAgICBpZiAodHJlZXMgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgIHRyZWVzID0gW107XG4gICAgICAgICAgc3RhcnRUb1RyZWVzLnNldChjaGlsZC5zdGFydCwgdHJlZXMpO1xuICAgICAgICB9XG4gICAgICAgIHRyZWVzLnB1c2gobmV3IFJhbmdlVHJlZVdpdGhQYXJlbnQocGFyZW50SW5kZXgsIGNoaWxkKSk7XG4gICAgICB9XG4gICAgfVxuICAgIGNvbnN0IHF1ZXVlOiBTdGFydEV2ZW50W10gPSBbXTtcbiAgICBmb3IgKGNvbnN0IFtzdGFydE9mZnNldCwgdHJlZXNdIG9mIHN0YXJ0VG9UcmVlcykge1xuICAgICAgcXVldWUucHVzaChuZXcgU3RhcnRFdmVudChzdGFydE9mZnNldCwgdHJlZXMpKTtcbiAgICB9XG4gICAgcXVldWUuc29ydChTdGFydEV2ZW50LmNvbXBhcmUpO1xuICAgIHJldHVybiBuZXcgU3RhcnRFdmVudFF1ZXVlKHF1ZXVlKTtcbiAgfVxuXG4gIHNldFBlbmRpbmdPZmZzZXQob2Zmc2V0OiBudW1iZXIpOiB2b2lkIHtcbiAgICB0aGlzLnBlbmRpbmdPZmZzZXQgPSBvZmZzZXQ7XG4gIH1cblxuICBwdXNoUGVuZGluZ1RyZWUodHJlZTogUmFuZ2VUcmVlV2l0aFBhcmVudCk6IHZvaWQge1xuICAgIGlmICh0aGlzLnBlbmRpbmdUcmVlcyA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aGlzLnBlbmRpbmdUcmVlcyA9IFtdO1xuICAgIH1cbiAgICB0aGlzLnBlbmRpbmdUcmVlcy5wdXNoKHRyZWUpO1xuICB9XG5cbiAgbmV4dCgpOiBTdGFydEV2ZW50IHwgdW5kZWZpbmVkIHtcbiAgICBjb25zdCBwZW5kaW5nVHJlZXM6IFJhbmdlVHJlZVdpdGhQYXJlbnRbXSB8IHVuZGVmaW5lZCA9IHRoaXMucGVuZGluZ1RyZWVzO1xuICAgIGNvbnN0IG5leHRFdmVudDogU3RhcnRFdmVudCB8IHVuZGVmaW5lZCA9IHRoaXMucXVldWVbdGhpcy5uZXh0SW5kZXhdO1xuICAgIGlmIChwZW5kaW5nVHJlZXMgPT09IHVuZGVmaW5lZCkge1xuICAgICAgdGhpcy5uZXh0SW5kZXgrKztcbiAgICAgIHJldHVybiBuZXh0RXZlbnQ7XG4gICAgfSBlbHNlIGlmIChuZXh0RXZlbnQgPT09IHVuZGVmaW5lZCkge1xuICAgICAgdGhpcy5wZW5kaW5nVHJlZXMgPSB1bmRlZmluZWQ7XG4gICAgICByZXR1cm4gbmV3IFN0YXJ0RXZlbnQodGhpcy5wZW5kaW5nT2Zmc2V0LCBwZW5kaW5nVHJlZXMpO1xuICAgIH0gZWxzZSB7XG4gICAgICBpZiAodGhpcy5wZW5kaW5nT2Zmc2V0IDwgbmV4dEV2ZW50Lm9mZnNldCkge1xuICAgICAgICB0aGlzLnBlbmRpbmdUcmVlcyA9IHVuZGVmaW5lZDtcbiAgICAgICAgcmV0dXJuIG5ldyBTdGFydEV2ZW50KHRoaXMucGVuZGluZ09mZnNldCwgcGVuZGluZ1RyZWVzKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGlmICh0aGlzLnBlbmRpbmdPZmZzZXQgPT09IG5leHRFdmVudC5vZmZzZXQpIHtcbiAgICAgICAgICB0aGlzLnBlbmRpbmdUcmVlcyA9IHVuZGVmaW5lZDtcbiAgICAgICAgICBmb3IgKGNvbnN0IHRyZWUgb2YgcGVuZGluZ1RyZWVzKSB7XG4gICAgICAgICAgICBuZXh0RXZlbnQudHJlZXMucHVzaCh0cmVlKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5uZXh0SW5kZXgrKztcbiAgICAgICAgcmV0dXJuIG5leHRFdmVudDtcbiAgICAgIH1cbiAgICB9XG4gIH1cbn1cblxuZnVuY3Rpb24gbWVyZ2VSYW5nZVRyZWVDaGlsZHJlbihwYXJlbnRUcmVlczogUmVhZG9ubHlBcnJheTxSYW5nZVRyZWU+KTogUmFuZ2VUcmVlW10ge1xuICBjb25zdCByZXN1bHQ6IFJhbmdlVHJlZVtdID0gW107XG4gIGNvbnN0IHN0YXJ0RXZlbnRRdWV1ZTogU3RhcnRFdmVudFF1ZXVlID0gU3RhcnRFdmVudFF1ZXVlLmZyb21QYXJlbnRUcmVlcyhwYXJlbnRUcmVlcyk7XG4gIGNvbnN0IHBhcmVudFRvTmVzdGVkOiBNYXA8bnVtYmVyLCBSYW5nZVRyZWVbXT4gPSBuZXcgTWFwKCk7XG4gIGxldCBvcGVuUmFuZ2U6IFJhbmdlIHwgdW5kZWZpbmVkO1xuXG4gIHdoaWxlICh0cnVlKSB7XG4gICAgY29uc3QgZXZlbnQ6IFN0YXJ0RXZlbnQgfCB1bmRlZmluZWQgPSBzdGFydEV2ZW50UXVldWUubmV4dCgpO1xuICAgIGlmIChldmVudCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICBicmVhaztcbiAgICB9XG5cbiAgICBpZiAob3BlblJhbmdlICE9PSB1bmRlZmluZWQgJiYgb3BlblJhbmdlLmVuZCA8PSBldmVudC5vZmZzZXQpIHtcbiAgICAgIHJlc3VsdC5wdXNoKG5leHRDaGlsZChvcGVuUmFuZ2UsIHBhcmVudFRvTmVzdGVkKSk7XG4gICAgICBvcGVuUmFuZ2UgPSB1bmRlZmluZWQ7XG4gICAgfVxuXG4gICAgaWYgKG9wZW5SYW5nZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICBsZXQgb3BlblJhbmdlRW5kOiBudW1iZXIgPSBldmVudC5vZmZzZXQgKyAxO1xuICAgICAgZm9yIChjb25zdCB7cGFyZW50SW5kZXgsIHRyZWV9IG9mIGV2ZW50LnRyZWVzKSB7XG4gICAgICAgIG9wZW5SYW5nZUVuZCA9IE1hdGgubWF4KG9wZW5SYW5nZUVuZCwgdHJlZS5lbmQpO1xuICAgICAgICBpbnNlcnRDaGlsZChwYXJlbnRUb05lc3RlZCwgcGFyZW50SW5kZXgsIHRyZWUpO1xuICAgICAgfVxuICAgICAgc3RhcnRFdmVudFF1ZXVlLnNldFBlbmRpbmdPZmZzZXQob3BlblJhbmdlRW5kKTtcbiAgICAgIG9wZW5SYW5nZSA9IHtzdGFydDogZXZlbnQub2Zmc2V0LCBlbmQ6IG9wZW5SYW5nZUVuZH07XG4gICAgfSBlbHNlIHtcbiAgICAgIGZvciAoY29uc3Qge3BhcmVudEluZGV4LCB0cmVlfSBvZiBldmVudC50cmVlcykge1xuICAgICAgICBpZiAodHJlZS5lbmQgPiBvcGVuUmFuZ2UuZW5kKSB7XG4gICAgICAgICAgY29uc3QgcmlnaHQ6IFJhbmdlVHJlZSA9IHRyZWUuc3BsaXQob3BlblJhbmdlLmVuZCk7XG4gICAgICAgICAgc3RhcnRFdmVudFF1ZXVlLnB1c2hQZW5kaW5nVHJlZShuZXcgUmFuZ2VUcmVlV2l0aFBhcmVudChwYXJlbnRJbmRleCwgcmlnaHQpKTtcbiAgICAgICAgfVxuICAgICAgICBpbnNlcnRDaGlsZChwYXJlbnRUb05lc3RlZCwgcGFyZW50SW5kZXgsIHRyZWUpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuICBpZiAob3BlblJhbmdlICE9PSB1bmRlZmluZWQpIHtcbiAgICByZXN1bHQucHVzaChuZXh0Q2hpbGQob3BlblJhbmdlLCBwYXJlbnRUb05lc3RlZCkpO1xuICB9XG5cbiAgcmV0dXJuIHJlc3VsdDtcbn1cblxuZnVuY3Rpb24gaW5zZXJ0Q2hpbGQocGFyZW50VG9OZXN0ZWQ6IE1hcDxudW1iZXIsIFJhbmdlVHJlZVtdPiwgcGFyZW50SW5kZXg6IG51bWJlciwgdHJlZTogUmFuZ2VUcmVlKTogdm9pZCB7XG4gIGxldCBuZXN0ZWQ6IFJhbmdlVHJlZVtdIHwgdW5kZWZpbmVkID0gcGFyZW50VG9OZXN0ZWQuZ2V0KHBhcmVudEluZGV4KTtcbiAgaWYgKG5lc3RlZCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgbmVzdGVkID0gW107XG4gICAgcGFyZW50VG9OZXN0ZWQuc2V0KHBhcmVudEluZGV4LCBuZXN0ZWQpO1xuICB9XG4gIG5lc3RlZC5wdXNoKHRyZWUpO1xufVxuXG5mdW5jdGlvbiBuZXh0Q2hpbGQob3BlblJhbmdlOiBSYW5nZSwgcGFyZW50VG9OZXN0ZWQ6IE1hcDxudW1iZXIsIFJhbmdlVHJlZVtdPik6IFJhbmdlVHJlZSB7XG4gIGNvbnN0IG1hdGNoaW5nVHJlZXM6IFJhbmdlVHJlZVtdID0gW107XG5cbiAgZm9yIChjb25zdCBuZXN0ZWQgb2YgcGFyZW50VG9OZXN0ZWQudmFsdWVzKCkpIHtcbiAgICBpZiAobmVzdGVkLmxlbmd0aCA9PT0gMSAmJiBuZXN0ZWRbMF0uc3RhcnQgPT09IG9wZW5SYW5nZS5zdGFydCAmJiBuZXN0ZWRbMF0uZW5kID09PSBvcGVuUmFuZ2UuZW5kKSB7XG4gICAgICBtYXRjaGluZ1RyZWVzLnB1c2gobmVzdGVkWzBdKTtcbiAgICB9IGVsc2Uge1xuICAgICAgbWF0Y2hpbmdUcmVlcy5wdXNoKG5ldyBSYW5nZVRyZWUoXG4gICAgICAgIG9wZW5SYW5nZS5zdGFydCxcbiAgICAgICAgb3BlblJhbmdlLmVuZCxcbiAgICAgICAgMCxcbiAgICAgICAgbmVzdGVkLFxuICAgICAgKSk7XG4gICAgfVxuICB9XG4gIHBhcmVudFRvTmVzdGVkLmNsZWFyKCk7XG4gIHJldHVybiBtZXJnZVJhbmdlVHJlZXMobWF0Y2hpbmdUcmVlcykhO1xufVxuIl0sInNvdXJjZVJvb3QiOiIifQ==