UNPKG

ng-repeat-fast

Version:

Faster ng-repeat realization that caches DOM nodes.

381 lines (314 loc) 31 kB
(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.ngRepeatFast = 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){ 'use strict'; var DIFF_NOT_MODIFIED = 0; var DIFF_CREATED = 1; var DIFF_MOVED = 2; var DIFF_DELETED = -1; var lastUniqueId = 0; /** * Returns auto incremental unique ID as integer. * @returns {number} integers starting from 0 */ function getUniqueId() { return lastUniqueId++; } /** * Returns x if it is not undefined, y otherwise. * @param x * @param y * @returns {*} */ function maybe(x, y) { if (x !== undefined) return x; return y; } /** * @param {Array} list * @param {string} primaryKey * @returns {{}} */ function buildHashToIndexMap(list, primaryKey) { var map = {}; for (var i = 0; i < list.length; ++i) { var item = list[i]; map[item[primaryKey]] = i; } return map; } /** * Calculates difference between two arrays. * Returns array of { item: T, state: int }. * Where state means: 0 - not modified, 1 - created, -1 - deleted. * @param {Array} newList * @param {Array} oldList * @param {string} primaryKey item's unique index field name */ function diff(newList, oldList, primaryKey) { var diff = []; var newIndex = 0; var oldIndex = 0; var newIndexMap = buildHashToIndexMap(newList, primaryKey); var oldIndexMap = buildHashToIndexMap(oldList, primaryKey); function addEntry(item, state, newIndex, prevIndex) { diff.push({ item: item, state: state, oldIndex: prevIndex, newIndex: newIndex }); } for (; newIndex < newList.length || oldIndex < oldList.length;) { var newItem = newList[newIndex]; var oldItem = oldList[oldIndex]; if (newIndex >= newList.length) { addEntry(oldItem, DIFF_DELETED, -1, oldIndex); ++oldIndex; } else if (oldIndex >= oldList.length) { addEntry(newItem, DIFF_CREATED, newIndex, -1); ++newIndex; } else if (newItem !== oldItem) { var indexOfNewItemInOldList = maybe(oldIndexMap[newItem[primaryKey]], -1); var indexOfOldItemInNewList = maybe(newIndexMap[oldItem[primaryKey]], -1); var isCreated = indexOfNewItemInOldList === -1; var isDeleted = indexOfOldItemInNewList === -1; // created if (isCreated) { addEntry(newItem, DIFF_CREATED, newIndex, -1); ++newIndex; } // moved if (!isCreated && !isDeleted) { addEntry(newItem, DIFF_MOVED, newIndex, indexOfOldItemInNewList); ++newIndex; ++oldIndex; } // deleted if (isDeleted) { addEntry(oldItem, DIFF_DELETED, -1, oldIndex); ++oldIndex; } } else { addEntry(oldItem, DIFF_NOT_MODIFIED, newIndex, oldIndex); ++newIndex; ++oldIndex; } } return diff; } // exports //////////////////////////////////////////////////////////////// diff.NOT_MODIFIED = DIFF_NOT_MODIFIED; diff.CREATED = DIFF_CREATED; diff.MOVED = DIFF_MOVED; diff.DELETED = DIFF_DELETED; diff.getUniqueId = getUniqueId; diff.buildHashToIndexMap = buildHashToIndexMap; module.exports = diff; },{}],2:[function(require,module,exports){ (function (factory) { /* istanbul ignore next */ if (typeof require == 'function') { var diff = require('f-xyz-diff'); factory(module.exports, diff); } else { factory(window, window.diff); } })(function (exports, diff) { 'use strict'; /////////////////////////////////////////////////////////////////////////// exports.ngRepeatFast = angular .module('ngRepeatFast', []) .directive('ngRepeatFast', [ '$parse', '$compile', ngRepeatFastFactory ]); function ngRepeatFastFactory($parse, $compile) { return { scope: true, restrict: 'A', priority: 1000, terminal: true, link: function ($scope, $element, $attrs) { ngRepeatFastLink($scope, $element, $attrs, $parse, $compile); } }; } /////////////////////////////////////////////////////////////////////////// function ngRepeatFastLink($scope, $element, $attrs, $parse, $compile) { // todo - animations support // todo - garbage collection for DOM nodes (?) timer-based? var HASH_KEY = '$$hashKey'; if ('ngInclude' in $attrs) { throw Error('ngRepeatFast: ngInclude on repeating ' + 'element is not supported. ' + 'Please create nested element with ng-include.'); } // parse ng-repeat expression ///////////////////////////////////////// var rx = /^\s*(\w+)\sin\s(.+?)(\strack by\s(.+?))?$/; var match = $attrs.ngRepeatFast.match(rx); if (!match) { throw Error('ngRepeatFast: expected ngRepeatFast in form of ' + '`{item} in {array} [| filter, etc]` [track by \'{field}\'] ' + 'but got `' + $attrs.ngRepeatFast + '`'); } var iteratorName = match[1]; var expression = match[2]; var trackBy = match[4] || HASH_KEY; var model = getModel(); if (!Array.isArray(model)) { throw Error('ngRepeatFast: expected model `' + $attrs.ngRepeatFast + '` ' + 'to be an array but got: ' + model); } // build DOM ////////////////////////////////////////////////////////// var itemHashToNodeMap = {}; var elementNode = $element[0]; var elementParentNode = elementNode.parentNode; var elementNodeIndex = getNodeIndex(elementNode, true); var templateNode = elementNode.cloneNode(true); templateNode.removeAttribute('ng-repeat-fast'); var prevNode = elementNode; model.forEach(function (item) { var node = createNode(item); insertAfter(node, prevNode); prevNode = node; // store node if (trackBy === HASH_KEY) { item[trackBy] = diff.getUniqueId(); } itemHashToNodeMap[item[trackBy]] = node; }); hideNode(elementNode); // watch model for changes if it is not one-time binding var unwatchModel; if (!/^::/.test(expression)) { unwatchModel = $scope.$watchCollection(getModel, renderChanges); } /////////////////////////////////////////////////////////////////// function getModel() { return $parse(expression)($scope); } function renderChanges(list, prev) { if (list === prev) return; var difference = diff(list, prev, trackBy); syncDom(difference); } function syncDom(difference) { var prevNode = elementNode; // insert new node after me difference.forEach(function (diffEntry, i) { var item = diffEntry.item; var node = itemHashToNodeMap[item[trackBy]]; var nodeIndex; switch (diffEntry.state) { case diff.CREATED: if (node) { nodeIndex = getNodeIndex(node); if (nodeIndex != i) { insertAfter(node, prevNode); } showNode(node); } else { node = createNode(item); insertAfter(node, prevNode); var hashKey = diff.getUniqueId(); item[trackBy] = hashKey; itemHashToNodeMap[hashKey] = node; } break; case diff.MOVED: case diff.NOT_MODIFIED: nodeIndex = getNodeIndex(node); if (nodeIndex != i) { insertAfter(node, prevNode); } break; case diff.DELETED: hideNode(node); //deleteNode(node); //delete itemHashToNodeMap[item[trackBy]]; break; } prevNode = node; }); } // DOM operations ///////////////////////////////////////////////// function insertAfter(node, afterNode) { if (afterNode.nextSibling) { elementParentNode.insertBefore(node, afterNode.nextSibling); } else { elementParentNode.appendChild(node); } } function createNode(item) { var scope = $scope.$new(); scope[iteratorName] = item; var node = templateNode.cloneNode(true); amendItemScope(scope, node); $compile(node)(scope); return node; } function amendItemScope(scope, node) { Object.defineProperties(scope, { $index: { enumerable: true, get: function () { return getNodeIndex(node); } }, $first: { enumerable: true, get: function () { return getNodeIndex(node) === 0; } }, $last: { enumerable: true, get: function () { var length = getModel().length; return getNodeIndex(node) === length-1; } }, $middle: { enumerable: true, get: function () { return !this.$first && !this.$last; } }, $even: { enumerable: true, get: function () { return this.$index % 2 === 0; } }, $odd: { enumerable: true, get: function () { return this.$index % 2 === 1; } } }); return scope; } function showNode(node) { node.className = node.className.slice(0, -8); } function hideNode(node) { node.className += ' ng-hide'; } function getNodeIndex(node, absolute) { var nodeList = elementParentNode.childNodes; var index = [].indexOf.call(nodeList, node); if (!absolute) { index = index - elementNodeIndex - 1; } return index; } /////////////////////////////////////////////////////////////////////////// $scope.$on('$destroy', function () { unwatchModel(); }); } }); },{"f-xyz-diff":1}]},{},[2])(2) }); //# sourceMappingURL=data:application/json;charset:utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJub2RlX21vZHVsZXMvZi14eXotZGlmZi9pbmRleC5qcyIsInNyYy9pbmRleC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtBQ0FBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuSUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyIoZnVuY3Rpb24gZSh0LG4scil7ZnVuY3Rpb24gcyhvLHUpe2lmKCFuW29dKXtpZighdFtvXSl7dmFyIGE9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtpZighdSYmYSlyZXR1cm4gYShvLCEwKTtpZihpKXJldHVybiBpKG8sITApO3ZhciBmPW5ldyBFcnJvcihcIkNhbm5vdCBmaW5kIG1vZHVsZSAnXCIrbytcIidcIik7dGhyb3cgZi5jb2RlPVwiTU9EVUxFX05PVF9GT1VORFwiLGZ9dmFyIGw9bltvXT17ZXhwb3J0czp7fX07dFtvXVswXS5jYWxsKGwuZXhwb3J0cyxmdW5jdGlvbihlKXt2YXIgbj10W29dWzFdW2VdO3JldHVybiBzKG4/bjplKX0sbCxsLmV4cG9ydHMsZSx0LG4scil9cmV0dXJuIG5bb10uZXhwb3J0c312YXIgaT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2Zvcih2YXIgbz0wO288ci5sZW5ndGg7bysrKXMocltvXSk7cmV0dXJuIHN9KSIsIid1c2Ugc3RyaWN0JztcblxudmFyIERJRkZfTk9UX01PRElGSUVEID0gMDtcbnZhciBESUZGX0NSRUFURUQgPSAxO1xudmFyIERJRkZfTU9WRUQgPSAyO1xudmFyIERJRkZfREVMRVRFRCA9IC0xO1xuXG52YXIgbGFzdFVuaXF1ZUlkID0gMDtcblxuLyoqXG4gKiBSZXR1cm5zIGF1dG8gaW5jcmVtZW50YWwgdW5pcXVlIElEIGFzIGludGVnZXIuXG4gKiBAcmV0dXJucyB7bnVtYmVyfSBpbnRlZ2VycyBzdGFydGluZyBmcm9tIDBcbiAqL1xuZnVuY3Rpb24gZ2V0VW5pcXVlSWQoKSB7XG4gICAgcmV0dXJuIGxhc3RVbmlxdWVJZCsrO1xufVxuXG4vKipcbiAqIFJldHVybnMgeCBpZiBpdCBpcyBub3QgdW5kZWZpbmVkLCB5IG90aGVyd2lzZS5cbiAqIEBwYXJhbSB4XG4gKiBAcGFyYW0geVxuICogQHJldHVybnMgeyp9XG4gKi9cbmZ1bmN0aW9uIG1heWJlKHgsIHkpIHtcbiAgICBpZiAoeCAhPT0gdW5kZWZpbmVkKSByZXR1cm4geDtcbiAgICByZXR1cm4geTtcbn1cblxuLyoqXG4gKiBAcGFyYW0ge0FycmF5fSBsaXN0XG4gKiBAcGFyYW0ge3N0cmluZ30gcHJpbWFyeUtleVxuICogQHJldHVybnMge3t9fVxuICovXG5mdW5jdGlvbiBidWlsZEhhc2hUb0luZGV4TWFwKGxpc3QsIHByaW1hcnlLZXkpIHtcbiAgICB2YXIgbWFwID0ge307XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBsaXN0Lmxlbmd0aDsgKytpKSB7XG4gICAgICAgIHZhciBpdGVtID0gbGlzdFtpXTtcbiAgICAgICAgbWFwW2l0ZW1bcHJpbWFyeUtleV1dID0gaTtcbiAgICB9XG4gICAgcmV0dXJuIG1hcDtcbn1cblxuLyoqXG4gKiBDYWxjdWxhdGVzIGRpZmZlcmVuY2UgYmV0d2VlbiB0d28gYXJyYXlzLlxuICogUmV0dXJucyBhcnJheSBvZiB7IGl0ZW06IFQsIHN0YXRlOiBpbnQgfS5cbiAqIFdoZXJlIHN0YXRlIG1lYW5zOiAwIC0gbm90IG1vZGlmaWVkLCAxIC0gY3JlYXRlZCwgLTEgLSBkZWxldGVkLlxuICogQHBhcmFtIHtBcnJheX0gbmV3TGlzdFxuICogQHBhcmFtIHtBcnJheX0gb2xkTGlzdFxuICogQHBhcmFtIHtzdHJpbmd9IHByaW1hcnlLZXkgaXRlbSdzIHVuaXF1ZSBpbmRleCBmaWVsZCBuYW1lXG4gKi9cbmZ1bmN0aW9uIGRpZmYobmV3TGlzdCwgb2xkTGlzdCwgcHJpbWFyeUtleSkge1xuICAgIHZhciBkaWZmID0gW107XG4gICAgdmFyIG5ld0luZGV4ID0gMDtcbiAgICB2YXIgb2xkSW5kZXggPSAwO1xuXG4gICAgdmFyIG5ld0luZGV4TWFwID0gYnVpbGRIYXNoVG9JbmRleE1hcChuZXdMaXN0LCBwcmltYXJ5S2V5KTtcbiAgICB2YXIgb2xkSW5kZXhNYXAgPSBidWlsZEhhc2hUb0luZGV4TWFwKG9sZExpc3QsIHByaW1hcnlLZXkpO1xuXG4gICAgZnVuY3Rpb24gYWRkRW50cnkoaXRlbSwgc3RhdGUsIG5ld0luZGV4LCBwcmV2SW5kZXgpIHtcbiAgICAgICAgZGlmZi5wdXNoKHtcbiAgICAgICAgICAgIGl0ZW06IGl0ZW0sXG4gICAgICAgICAgICBzdGF0ZTogc3RhdGUsXG4gICAgICAgICAgICBvbGRJbmRleDogcHJldkluZGV4LFxuICAgICAgICAgICAgbmV3SW5kZXg6IG5ld0luZGV4XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIGZvciAoOyBuZXdJbmRleCA8IG5ld0xpc3QubGVuZ3RoIHx8IG9sZEluZGV4IDwgb2xkTGlzdC5sZW5ndGg7KSB7XG4gICAgICAgIHZhciBuZXdJdGVtID0gbmV3TGlzdFtuZXdJbmRleF07XG4gICAgICAgIHZhciBvbGRJdGVtID0gb2xkTGlzdFtvbGRJbmRleF07XG5cbiAgICAgICAgaWYgKG5ld0luZGV4ID49IG5ld0xpc3QubGVuZ3RoKSB7XG5cbiAgICAgICAgICAgIGFkZEVudHJ5KG9sZEl0ZW0sIERJRkZfREVMRVRFRCwgLTEsIG9sZEluZGV4KTtcbiAgICAgICAgICAgICsrb2xkSW5kZXg7XG5cbiAgICAgICAgfSBlbHNlIGlmIChvbGRJbmRleCA+PSBvbGRMaXN0Lmxlbmd0aCkge1xuXG4gICAgICAgICAgICBhZGRFbnRyeShuZXdJdGVtLCBESUZGX0NSRUFURUQsIG5ld0luZGV4LCAtMSk7XG4gICAgICAgICAgICArK25ld0luZGV4O1xuXG4gICAgICAgIH0gZWxzZSBpZiAobmV3SXRlbSAhPT0gb2xkSXRlbSkge1xuXG4gICAgICAgICAgICB2YXIgaW5kZXhPZk5ld0l0ZW1Jbk9sZExpc3QgPVxuICAgICAgICAgICAgICAgIG1heWJlKG9sZEluZGV4TWFwW25ld0l0ZW1bcHJpbWFyeUtleV1dLCAtMSk7XG5cbiAgICAgICAgICAgIHZhciBpbmRleE9mT2xkSXRlbUluTmV3TGlzdCA9XG4gICAgICAgICAgICAgICAgbWF5YmUobmV3SW5kZXhNYXBbb2xkSXRlbVtwcmltYXJ5S2V5XV0sIC0xKTtcblxuICAgICAgICAgICAgdmFyIGlzQ3JlYXRlZCA9IGluZGV4T2ZOZXdJdGVtSW5PbGRMaXN0ID09PSAtMTtcbiAgICAgICAgICAgIHZhciBpc0RlbGV0ZWQgPSBpbmRleE9mT2xkSXRlbUluTmV3TGlzdCA9PT0gLTE7XG5cbiAgICAgICAgICAgIC8vIGNyZWF0ZWRcbiAgICAgICAgICAgIGlmIChpc0NyZWF0ZWQpIHtcbiAgICAgICAgICAgICAgICBhZGRFbnRyeShuZXdJdGVtLCBESUZGX0NSRUFURUQsIG5ld0luZGV4LCAtMSk7XG4gICAgICAgICAgICAgICAgKytuZXdJbmRleDtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gbW92ZWRcbiAgICAgICAgICAgIGlmICghaXNDcmVhdGVkICYmICFpc0RlbGV0ZWQpIHtcbiAgICAgICAgICAgICAgICBhZGRFbnRyeShuZXdJdGVtLCBESUZGX01PVkVELCBuZXdJbmRleCwgaW5kZXhPZk9sZEl0ZW1Jbk5ld0xpc3QpO1xuICAgICAgICAgICAgICAgICsrbmV3SW5kZXg7XG4gICAgICAgICAgICAgICAgKytvbGRJbmRleDtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gZGVsZXRlZFxuICAgICAgICAgICAgaWYgKGlzRGVsZXRlZCkge1xuICAgICAgICAgICAgICAgIGFkZEVudHJ5KG9sZEl0ZW0sIERJRkZfREVMRVRFRCwgLTEsIG9sZEluZGV4KTtcbiAgICAgICAgICAgICAgICArK29sZEluZGV4O1xuICAgICAgICAgICAgfVxuXG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBhZGRFbnRyeShvbGRJdGVtLCBESUZGX05PVF9NT0RJRklFRCwgbmV3SW5kZXgsIG9sZEluZGV4KTtcbiAgICAgICAgICAgICsrbmV3SW5kZXg7XG4gICAgICAgICAgICArK29sZEluZGV4O1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIGRpZmY7XG59XG5cbi8vIGV4cG9ydHMgLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vL1xuXG5kaWZmLk5PVF9NT0RJRklFRCA9IERJRkZfTk9UX01PRElGSUVEO1xuZGlmZi5DUkVBVEVEID0gRElGRl9DUkVBVEVEO1xuZGlmZi5NT1ZFRCA9IERJRkZfTU9WRUQ7XG5kaWZmLkRFTEVURUQgPSBESUZGX0RFTEVURUQ7XG5kaWZmLmdldFVuaXF1ZUlkID0gZ2V0VW5pcXVlSWQ7XG5kaWZmLmJ1aWxkSGFzaFRvSW5kZXhNYXAgPSBidWlsZEhhc2hUb0luZGV4TWFwO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGRpZmY7XG4iLCIoZnVuY3Rpb24gKGZhY3RvcnkpIHtcbiAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuICAgIGlmICh0eXBlb2YgcmVxdWlyZSA9PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIHZhciBkaWZmID0gcmVxdWlyZSgnZi14eXotZGlmZicpO1xuICAgICAgICBmYWN0b3J5KG1vZHVsZS5leHBvcnRzLCBkaWZmKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICBmYWN0b3J5KHdpbmRvdywgd2luZG93LmRpZmYpO1xuICAgIH1cbn0pKGZ1bmN0aW9uIChleHBvcnRzLCBkaWZmKSB7XG4gICAgJ3VzZSBzdHJpY3QnO1xuXG4gICAgLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vXG5cbiAgICBleHBvcnRzLm5nUmVwZWF0RmFzdCA9IGFuZ3VsYXJcbiAgICAgICAgLm1vZHVsZSgnbmdSZXBlYXRGYXN0JywgW10pXG4gICAgICAgIC5kaXJlY3RpdmUoJ25nUmVwZWF0RmFzdCcsIFtcbiAgICAgICAgICAgICckcGFyc2UnLCAnJGNvbXBpbGUnLFxuICAgICAgICAgICAgbmdSZXBlYXRGYXN0RmFjdG9yeVxuICAgICAgICBdKTtcblxuICAgIGZ1bmN0aW9uIG5nUmVwZWF0RmFzdEZhY3RvcnkoJHBhcnNlLCAkY29tcGlsZSkge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgc2NvcGU6IHRydWUsXG4gICAgICAgICAgICByZXN0cmljdDogJ0EnLFxuICAgICAgICAgICAgcHJpb3JpdHk6IDEwMDAsXG4gICAgICAgICAgICB0ZXJtaW5hbDogdHJ1ZSxcbiAgICAgICAgICAgIGxpbms6IGZ1bmN0aW9uICgkc2NvcGUsICRlbGVtZW50LCAkYXR0cnMpIHtcbiAgICAgICAgICAgICAgICBuZ1JlcGVhdEZhc3RMaW5rKCRzY29wZSwgJGVsZW1lbnQsICRhdHRycywgJHBhcnNlLCAkY29tcGlsZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vXG5cbiAgICBmdW5jdGlvbiBuZ1JlcGVhdEZhc3RMaW5rKCRzY29wZSwgJGVsZW1lbnQsICRhdHRycywgJHBhcnNlLCAkY29tcGlsZSkge1xuXG4gICAgICAgIC8vIHRvZG8gLSBhbmltYXRpb25zIHN1cHBvcnRcbiAgICAgICAgLy8gdG9kbyAtIGdhcmJhZ2UgY29sbGVjdGlvbiBmb3IgRE9NIG5vZGVzICg/KSB0aW1lci1iYXNlZD9cblxuICAgICAgICB2YXIgSEFTSF9LRVkgPSAnJCRoYXNoS2V5JztcblxuICAgICAgICBpZiAoJ25nSW5jbHVkZScgaW4gJGF0dHJzKSB7XG4gICAgICAgICAgICB0aHJvdyBFcnJvcignbmdSZXBlYXRGYXN0OiBuZ0luY2x1ZGUgb24gcmVwZWF0aW5nICcgK1xuICAgICAgICAgICAgICAgICAgICAgICAgJ2VsZW1lbnQgaXMgbm90IHN1cHBvcnRlZC4gJyArXG4gICAgICAgICAgICAgICAgICAgICAgICAnUGxlYXNlIGNyZWF0ZSBuZXN0ZWQgZWxlbWVudCB3aXRoIG5nLWluY2x1ZGUuJyk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBwYXJzZSBuZy1yZXBlYXQgZXhwcmVzc2lvbiAvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vL1xuXG4gICAgICAgIHZhciByeCA9IC9eXFxzKihcXHcrKVxcc2luXFxzKC4rPykoXFxzdHJhY2sgYnlcXHMoLis/KSk/JC87XG4gICAgICAgIHZhciBtYXRjaCA9ICRhdHRycy5uZ1JlcGVhdEZhc3QubWF0Y2gocngpO1xuICAgICAgICBpZiAoIW1hdGNoKSB7XG4gICAgICAgICAgICB0aHJvdyBFcnJvcignbmdSZXBlYXRGYXN0OiBleHBlY3RlZCBuZ1JlcGVhdEZhc3QgaW4gZm9ybSBvZiAnICtcbiAgICAgICAgICAgICAgICAgICAgICAgICdge2l0ZW19IGluIHthcnJheX0gW3wgZmlsdGVyLCBldGNdYCBbdHJhY2sgYnkgXFwne2ZpZWxkfVxcJ10gJyArXG4gICAgICAgICAgICAgICAgICAgICAgICAnYnV0IGdvdCBgJyArICRhdHRycy5uZ1JlcGVhdEZhc3QgKyAnYCcpO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGl0ZXJhdG9yTmFtZSA9IG1hdGNoWzFdO1xuICAgICAgICB2YXIgZXhwcmVzc2lvbiA9IG1hdGNoWzJdO1xuICAgICAgICB2YXIgdHJhY2tCeSA9IG1hdGNoWzRdIHx8IEhBU0hfS0VZO1xuICAgICAgICB2YXIgbW9kZWwgPSBnZXRNb2RlbCgpO1xuICAgICAgICBpZiAoIUFycmF5LmlzQXJyYXkobW9kZWwpKSB7XG4gICAgICAgICAgICB0aHJvdyBFcnJvcignbmdSZXBlYXRGYXN0OiBleHBlY3RlZCBtb2RlbCBgJyArICRhdHRycy5uZ1JlcGVhdEZhc3QgKyAnYCAnICtcbiAgICAgICAgICAgICAgICAgICAgICAgICd0byBiZSBhbiBhcnJheSBidXQgZ290OiAnICsgbW9kZWwpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gYnVpbGQgRE9NIC8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy9cblxuICAgICAgICB2YXIgaXRlbUhhc2hUb05vZGVNYXAgPSB7fTtcblxuICAgICAgICB2YXIgZWxlbWVudE5vZGUgPSAkZWxlbWVudFswXTtcbiAgICAgICAgdmFyIGVsZW1lbnRQYXJlbnROb2RlID0gZWxlbWVudE5vZGUucGFyZW50Tm9kZTtcbiAgICAgICAgdmFyIGVsZW1lbnROb2RlSW5kZXggPSBnZXROb2RlSW5kZXgoZWxlbWVudE5vZGUsIHRydWUpO1xuICAgICAgICB2YXIgdGVtcGxhdGVOb2RlID0gZWxlbWVudE5vZGUuY2xvbmVOb2RlKHRydWUpO1xuICAgICAgICB0ZW1wbGF0ZU5vZGUucmVtb3ZlQXR0cmlidXRlKCduZy1yZXBlYXQtZmFzdCcpO1xuXG4gICAgICAgIHZhciBwcmV2Tm9kZSA9IGVsZW1lbnROb2RlO1xuICAgICAgICBtb2RlbC5mb3JFYWNoKGZ1bmN0aW9uIChpdGVtKSB7XG4gICAgICAgICAgICB2YXIgbm9kZSA9IGNyZWF0ZU5vZGUoaXRlbSk7XG4gICAgICAgICAgICBpbnNlcnRBZnRlcihub2RlLCBwcmV2Tm9kZSk7XG4gICAgICAgICAgICBwcmV2Tm9kZSA9IG5vZGU7XG4gICAgICAgICAgICAvLyBzdG9yZSBub2RlXG4gICAgICAgICAgICBpZiAodHJhY2tCeSA9PT0gSEFTSF9LRVkpIHtcbiAgICAgICAgICAgICAgICBpdGVtW3RyYWNrQnldID0gZGlmZi5nZXRVbmlxdWVJZCgpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaXRlbUhhc2hUb05vZGVNYXBbaXRlbVt0cmFja0J5XV0gPSBub2RlO1xuICAgICAgICB9KTtcbiAgICAgICAgaGlkZU5vZGUoZWxlbWVudE5vZGUpO1xuXG4gICAgICAgIC8vIHdhdGNoIG1vZGVsIGZvciBjaGFuZ2VzIGlmIGl0IGlzIG5vdCBvbmUtdGltZSBiaW5kaW5nXG4gICAgICAgIHZhciB1bndhdGNoTW9kZWw7XG4gICAgICAgIGlmICghL146Oi8udGVzdChleHByZXNzaW9uKSkge1xuICAgICAgICAgICAgdW53YXRjaE1vZGVsID0gJHNjb3BlLiR3YXRjaENvbGxlY3Rpb24oZ2V0TW9kZWwsIHJlbmRlckNoYW5nZXMpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vL1xuXG4gICAgICAgIGZ1bmN0aW9uIGdldE1vZGVsKCkge1xuICAgICAgICAgICAgcmV0dXJuICRwYXJzZShleHByZXNzaW9uKSgkc2NvcGUpO1xuICAgICAgICB9XG5cbiAgICAgICAgZnVuY3Rpb24gcmVuZGVyQ2hhbmdlcyhsaXN0LCBwcmV2KSB7XG4gICAgICAgICAgICBpZiAobGlzdCA9PT0gcHJldikgcmV0dXJuO1xuXG4gICAgICAgICAgICB2YXIgZGlmZmVyZW5jZSA9IGRpZmYobGlzdCwgcHJldiwgdHJhY2tCeSk7XG5cbiAgICAgICAgICAgIHN5bmNEb20oZGlmZmVyZW5jZSk7XG4gICAgICAgIH1cblxuICAgICAgICBmdW5jdGlvbiBzeW5jRG9tKGRpZmZlcmVuY2UpIHtcbiAgICAgICAgICAgIHZhciBwcmV2Tm9kZSA9IGVsZW1lbnROb2RlOyAvLyBpbnNlcnQgbmV3IG5vZGUgYWZ0ZXIgbWVcbiAgICAgICAgICAgIGRpZmZlcmVuY2UuZm9yRWFjaChmdW5jdGlvbiAoZGlmZkVudHJ5LCBpKSB7XG4gICAgICAgICAgICAgICAgdmFyIGl0ZW0gPSBkaWZmRW50cnkuaXRlbTtcbiAgICAgICAgICAgICAgICB2YXIgbm9kZSA9IGl0ZW1IYXNoVG9Ob2RlTWFwW2l0ZW1bdHJhY2tCeV1dO1xuICAgICAgICAgICAgICAgIHZhciBub2RlSW5kZXg7XG5cbiAgICAgICAgICAgICAgICBzd2l0Y2ggKGRpZmZFbnRyeS5zdGF0ZSkge1xuXG4gICAgICAgICAgICAgICAgICAgIGNhc2UgZGlmZi5DUkVBVEVEOlxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG5vZGUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBub2RlSW5kZXggPSBnZXROb2RlSW5kZXgobm9kZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG5vZGVJbmRleCAhPSBpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluc2VydEFmdGVyKG5vZGUsIHByZXZOb2RlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hvd05vZGUobm9kZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vZGUgPSBjcmVhdGVOb2RlKGl0ZW0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluc2VydEFmdGVyKG5vZGUsIHByZXZOb2RlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgaGFzaEtleSA9IGRpZmYuZ2V0VW5pcXVlSWQoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpdGVtW3RyYWNrQnldID0gaGFzaEtleTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpdGVtSGFzaFRvTm9kZU1hcFtoYXNoS2V5XSA9IG5vZGU7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcblxuICAgICAgICAgICAgICAgICAgICBjYXNlIGRpZmYuTU9WRUQ6XG4gICAgICAgICAgICAgICAgICAgIGNhc2UgZGlmZi5OT1RfTU9ESUZJRUQ6XG4gICAgICAgICAgICAgICAgICAgICAgICBub2RlSW5kZXggPSBnZXROb2RlSW5kZXgobm9kZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAobm9kZUluZGV4ICE9IGkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbnNlcnRBZnRlcihub2RlLCBwcmV2Tm9kZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcblxuICAgICAgICAgICAgICAgICAgICBjYXNlIGRpZmYuREVMRVRFRDpcbiAgICAgICAgICAgICAgICAgICAgICAgIGhpZGVOb2RlKG5vZGUpO1xuICAgICAgICAgICAgICAgICAgICAgICAgLy9kZWxldGVOb2RlKG5vZGUpO1xuICAgICAgICAgICAgICAgICAgICAgICAgLy9kZWxldGUgaXRlbUhhc2hUb05vZGVNYXBbaXRlbVt0cmFja0J5XV07XG4gICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcHJldk5vZGUgPSBub2RlO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBET00gb3BlcmF0aW9ucyAvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vXG5cbiAgICAgICAgZnVuY3Rpb24gaW5zZXJ0QWZ0ZXIobm9kZSwgYWZ0ZXJOb2RlKSB7XG4gICAgICAgICAgICBpZiAoYWZ0ZXJOb2RlLm5leHRTaWJsaW5nKSB7XG4gICAgICAgICAgICAgICAgZWxlbWVudFBhcmVudE5vZGUuaW5zZXJ0QmVmb3JlKG5vZGUsIGFmdGVyTm9kZS5uZXh0U2libGluZyk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGVsZW1lbnRQYXJlbnROb2RlLmFwcGVuZENoaWxkKG5vZGUpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgZnVuY3Rpb24gY3JlYXRlTm9kZShpdGVtKSB7XG4gICAgICAgICAgICB2YXIgc2NvcGUgPSAkc2NvcGUuJG5ldygpO1xuICAgICAgICAgICAgc2NvcGVbaXRlcmF0b3JOYW1lXSA9IGl0ZW07XG5cbiAgICAgICAgICAgIHZhciBub2RlID0gdGVtcGxhdGVOb2RlLmNsb25lTm9kZSh0cnVlKTtcblxuICAgICAgICAgICAgYW1lbmRJdGVtU2NvcGUoc2NvcGUsIG5vZGUpO1xuICAgICAgICAgICAgJGNvbXBpbGUobm9kZSkoc2NvcGUpO1xuXG4gICAgICAgICAgICByZXR1cm4gbm9kZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGZ1bmN0aW9uIGFtZW5kSXRlbVNjb3BlKHNjb3BlLCBub2RlKSB7XG4gICAgICAgICAgICBPYmplY3QuZGVmaW5lUHJvcGVydGllcyhzY29wZSwge1xuICAgICAgICAgICAgICAgICRpbmRleDoge1xuICAgICAgICAgICAgICAgICAgICBlbnVtZXJhYmxlOiB0cnVlLFxuICAgICAgICAgICAgICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBnZXROb2RlSW5kZXgobm9kZSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICRmaXJzdDoge1xuICAgICAgICAgICAgICAgICAgICBlbnVtZXJhYmxlOiB0cnVlLFxuICAgICAgICAgICAgICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBnZXROb2RlSW5kZXgobm9kZSkgPT09IDA7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICRsYXN0OiB7XG4gICAgICAgICAgICAgICAgICAgIGVudW1lcmFibGU6IHRydWUsXG4gICAgICAgICAgICAgICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGxlbmd0aCA9IGdldE1vZGVsKCkubGVuZ3RoO1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGdldE5vZGVJbmRleChub2RlKSA9PT0gbGVuZ3RoLTE7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICRtaWRkbGU6IHtcbiAgICAgICAgICAgICAgICAgICAgZW51bWVyYWJsZTogdHJ1ZSxcbiAgICAgICAgICAgICAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gIXRoaXMuJGZpcnN0ICYmICF0aGlzLiRsYXN0O1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAkZXZlbjoge1xuICAgICAgICAgICAgICAgICAgICBlbnVtZXJhYmxlOiB0cnVlLFxuICAgICAgICAgICAgICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLiRpbmRleCAlIDIgPT09IDA7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICRvZGQ6IHtcbiAgICAgICAgICAgICAgICAgICAgZW51bWVyYWJsZTogdHJ1ZSxcbiAgICAgICAgICAgICAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy4kaW5kZXggJSAyID09PSAxO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICByZXR1cm4gc2NvcGU7XG4gICAgICAgIH1cblxuICAgICAgICBmdW5jdGlvbiBzaG93Tm9kZShub2RlKSB7XG4gICAgICAgICAgICBub2RlLmNsYXNzTmFtZSA9IG5vZGUuY2xhc3NOYW1lLnNsaWNlKDAsIC04KTtcbiAgICAgICAgfVxuXG4gICAgICAgIGZ1bmN0aW9uIGhpZGVOb2RlKG5vZGUpIHtcbiAgICAgICAgICAgIG5vZGUuY2xhc3NOYW1lICs9ICcgbmctaGlkZSc7XG4gICAgICAgIH1cblxuICAgICAgICBmdW5jdGlvbiBnZXROb2RlSW5kZXgobm9kZSwgYWJzb2x1dGUpIHtcbiAgICAgICAgICAgIHZhciBub2RlTGlzdCA9IGVsZW1lbnRQYXJlbnROb2RlLmNoaWxkTm9kZXM7XG4gICAgICAgICAgICB2YXIgaW5kZXggPSBbXS5pbmRleE9mLmNhbGwobm9kZUxpc3QsIG5vZGUpO1xuICAgICAgICAgICAgaWYgKCFhYnNvbHV0ZSkge1xuICAgICAgICAgICAgICAgIGluZGV4ID0gaW5kZXggLSBlbGVtZW50Tm9kZUluZGV4IC0gMTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBpbmRleDtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vL1xuXG4gICAgICAgICRzY29wZS4kb24oJyRkZXN0cm95JywgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdW53YXRjaE1vZGVsKCk7XG4gICAgICAgIH0pO1xuICAgIH1cblxufSk7XG4iXX0=