1/* Hunt v4.1.0 - 2017 Jeremias Menichelli - MIT License */ 2(function (global, factory) { 3 typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : 4 typeof define === 'function' && define.amd ? define(factory) : 5 (global.Hunt = factory()); 6}(this, (function () { 'use strict'; 7 8 var DEFAULT_THROTTLE_INTERVAL = 100; 9 10 /** 11 * Fallback function 12 * @method noop 13 * @returns {undefined} 14 */ 15 var noop = function() {}; 16 17 /** 18 * Prevents unnecessary calls through time interval polling 19 * @method throttle 20 * @param {Function} fn 21 * @returns {Function} 22 */ 23 var throttle = function(fn, interval) { 24 var inThrottle; 25 var lastFunc; 26 var lastRan; 27 28 return function() { 29 var args = arguments; 30 31 if (inThrottle === true) { 32 clearTimeout(lastFunc); 33 lastFunc = setTimeout(function () { 34 if (Date.now() - lastRan >= interval) { 35 fn.apply(this, args); 36 lastRan = Date.now(); 37 } 38 }, interval - (Date.now() - lastRan)); 39 } else { 40 fn.apply(this, args); 41 lastRan = Date.now(); 42 inThrottle = true; 43 } 44 }; 45 }; 46 47 /** 48 * Assign throttled actions and add listeners 49 * @param {Number} throttleInterval 50 * @method _connect 51 */ 52 var _connect = function(throttleInterval) { 53 // throttle actions 54 this._throttledHuntElements = throttle(this._huntElements.bind(this), throttleInterval); 55 this._throttledUpdateMetrics = throttle(this._updateMetrics.bind(this), throttleInterval); 56 57 // add listeners 58 window.addEventListener('scroll', this._throttledHuntElements); 59 window.addEventListener('resize', this._throttledUpdateMetrics); 60 61 // run first check 62 this._huntElements(); 63 }; 64 65 /** 66 * Constructor for element that should be hunted 67 * @constructor Hunted 68 * @param {Node} element 69 * @param {Object} config 70 */ 71 var Hunted = function(element, config) { 72 this.element = element; 73 74 // instantiate element as not visible 75 this.visible = false; 76 77 for (var prop in config) { 78 if (Object.hasOwnProperty.call(config, prop)) { 79 this[prop] = config[prop]; 80 } 81 } 82 83 if (typeof element.dataset !== 'undefined') { 84 // replace options with dataset if present 85 if (typeof element.dataset.huntPersist !== 'undefined') { 86 try { 87 this.persist = JSON.parse(element.dataset.huntPersist); 88 } catch (e) { 89 console.log('hunt: invalid data-hunt-persist value', e); 90 } 91 } 92 93 if (typeof element.dataset.huntOffset !== 'undefined') { 94 try { 95 this.offset = JSON.parse(element.dataset.huntOffset); 96 } catch (e) { 97 console.log('hunt: invalid data-hunt-offset value', e); 98 } 99 } 100 } 101 }; 102 103 // by default offset is zero 104 Hunted.prototype.offset = 0; 105 106 // by default trigger events only once 107 Hunted.prototype.persist = false; 108 109 // fallback enter function to avoid sanity check 110 Hunted.prototype.enter = noop; 111 112 // fallback leave function to avoid sanity check 113 Hunted.prototype.leave = noop; 114 115 /** 116 * Creates and initializes observer 117 * @constructor HuntObserver 118 * @param {Node|Array} elements 119 * @param {Object} options 120 */ 121 var HuntObserver = function(elements, options) { 122 // sanity check for first argument 123 if (elements instanceof Node === false && typeof elements.length !== 'number') { 124 throw new TypeError('hunt: observer first argument should be a node or a list of nodes'); 125 } 126 127 // sanity check for second argument 128 if (typeof options !== 'object') { 129 throw new TypeError('hunt: observer second argument should be an object'); 130 } 131 132 // treat single node as array 133 if (elements instanceof Node === true) { 134 elements = [ elements ]; 135 } 136 137 // track viewport height internally 138 this._viewportHeight = window.innerHeight; 139 140 // add elements to general hunted array 141 this._huntedElements = []; 142 143 var i = 0; 144 var len = elements.length; 145 146 for (; i < len; i++) { 147 this._huntedElements.push(new Hunted(elements[i], options)); 148 } 149 150 // set up throttle interval 151 var throttleInterval = options.throttleInterval || DEFAULT_THROTTLE_INTERVAL; 152 153 // connect observer and pass in throttle interval 154 _connect.call(this, throttleInterval); 155 156 i = len = null; 157 158 // Return observer instance 159 return this; 160 }; 161 162 /** 163 * Checks if hunted elements are visible and apply callbacks 164 * @method _huntElements 165 */ 166 HuntObserver.prototype._huntElements = function() { 167 var len = this._huntedElements.length; 168 var hunted; 169 var rect; 170 var isOnViewport; 171 172 while (len) { 173 --len; 174 175 hunted = this._huntedElements[len]; 176 rect = hunted.element.getBoundingClientRect(); 177 isOnViewport = rect.top - hunted.offset < this._viewportHe
177ight && rect.top >= -(rect.height + hunted.offset); 178 179 /* 180 * trigger (enter) event if element comes from a non visible state and the scrolled 181 * viewport has reached the visible range of the element without exceeding it 182 */ 183 if (hunted.visible === false && isOnViewport === true) { 184 hunted.enter.call(null, hunted.element); 185 hunted.visible = true; 186 187 // when the leave callback method is not set and hunting should not persist remove element 188 if (hunted.leave === noop && hunted.persist !== true) { 189 this._huntedElements.splice(len, 1); 190 191 // end observer activity when there are no more elements 192 if (this._huntedElements.length === 0) { 193 this.disconnect(); 194 } 195 } 196 } 197 198 /* 199 * trigger (out) event if element comes from a visible state 200 * and it's out of the visible range its bottom or top limit 201 */ 202 if (hunted.visible === true && isOnViewport === false) { 203 hunted.leave.call(null, hunted.element); 204 hunted.visible = false; 205 206 // when hunting should not persist remove element 207 if (hunted.persist !== true) { 208 this._huntedElements.splice(len, 1); 209 210 // end observer activity when there are no more elements 211 if (this._huntedElements.length === 0) { 212 this.disconnect(); 213 } 214 } 215 } 216 } 217 218 len = hunted = rect = isOnViewport = null; 219 }; 220 221 /** 222 * _huntElements public alias 223 * @method trigger 224 */ 225 HuntObserver.prototype.trigger = HuntObserver.prototype._huntElements; 226 227 /** 228 * Update viewport tracked height and runs a check 229 * @method _updateMetrics 230 */ 231 HuntObserver.prototype._updateMetrics = function() { 232 this._viewportHeight = window.innerHeight; 233 this._huntElements(); 234 }; 235 236 /** 237 * Remove listeners 238 * @method disconnect 239 */ 240 HuntObserver.prototype.disconnect = function() { 241 // remove listeners 242 window.removeEventListener('scroll', this._throttledHuntElements); 243 window.removeEventListener('resize', this._throttledUpdateMetrics); 244 }; 245 246 return HuntObserver; 247 248}))); 249 250//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiIiwic291cmNlcyI6WyJhc3NldHNfc2l0ZV9jb3JlX3ZpbGxlL2pzL2xpYi9odW50LmpzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qIEh1bnQgdjQuMS4wIC0gMjAxNyBKZXJlbWlhcyBNZW5pY2hlbGxpIC0gTUlUIExpY2Vuc2UgKi9cclxuKGZ1bmN0aW9uIChnbG9iYWwsIGZhY3RvcnkpIHtcclxuICB0eXBlb2YgZXhwb3J0cyA9PT0gJ29iamVjdCcgJiYgdHlwZW9mIG1vZHVsZSAhPT0gJ3VuZGVmaW5lZCcgPyBtb2R1bGUuZXhwb3J0cyA9IGZhY3RvcnkoKSA6XHJcbiAgdHlwZW9mIGRlZmluZSA9PT0gJ2Z1bmN0aW9uJyAmJiBkZWZpbmUuYW1kID8gZGVmaW5lKGZhY3RvcnkpIDpcclxuICAoZ2xvYmFsLkh1bnQgPSBmYWN0b3J5KCkpO1xyXG59KHRoaXMsIChmdW5jdGlvbiAoKSB7ICd1c2Ugc3RyaWN0JztcclxuXHJcbiAgdmFyIERFRkFVTFRfVEhST1RUTEVfSU5URVJWQUwgPSAxMDA7XHJcblxyXG4gIC8qKlxyXG4gICAqIEZhbGxiYWNrIGZ1bmN0aW9uXHJcbiAgICogQG1ldGhvZCBub29wXHJcbiAgICogQHJldHVybnMge3VuZGVmaW5lZH1cclxuICAgKi9cclxuICB2YXIgbm9vcCA9IGZ1bmN0aW9uKCkge307XHJcblxyXG4gIC8qKlxyXG4gICAqIFByZXZlbnRzIHVubmVjZXNzYXJ5IGNhbGxzIHRocm91Z2ggdGltZSBpbnRlcnZhbCBwb2xsaW5nXHJcbiAgICogQG1ldGhvZCB0aHJvdHRsZVxyXG4gICAqIEBwYXJhbSB7RnVuY3Rpb259IGZuXHJcbiAgICogQHJldHVybnMge0Z1bmN0aW9ufVxyXG4gICAqL1xyXG4gIHZhciB0aHJvdHRsZSA9IGZ1bmN0aW9uKGZuLCBpbnRlcnZhbCkge1xyXG4gICAgdmFyIGluVGhyb3R0bGU7XHJcbiAgICB2YXIgbGFzdEZ1bmM7XHJcbiAgICB2YXIgbGFzdFJhbjtcclxuXHJcbiAgICByZXR1cm4gZnVuY3Rpb24oKSB7XHJcbiAgICAgIHZhciBhcmdzID0gYXJndW1lbnRzO1xyXG5cclxuICAgICAgaWYgKGluVGhyb3R0bGUgPT09IHRydWUpIHtcclxuICAgICAgICBjbGVhclRpbWVvdXQobGFzdEZ1bmMpO1xyXG4gICAgICAgIGxhc3RGdW5jID0gc2V0VGltZW91dChmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICBpZiAoRGF0ZS5ub3coKSAtIGxhc3RSYW4gPj0gaW50ZXJ2YWwpIHtcclxuICAgICAgICAgICAgZm4uYXBwbHkodGhpcywgYXJncyk7XHJcbiAgICAgICAgICAgIGxhc3RSYW4gPSBEYXRlLm5vdygpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH0sIGludGVydmFsIC0gKERhdGUubm93KCkgLSBsYXN0UmFuKSk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgZm4uYXBwbHkodGhpcywgYXJncyk7XHJcbiAgICAgICAgbGFzdFJhbiA9IERhdGUubm93KCk7XHJcbiAgICAgICAgaW5UaHJvdHRsZSA9IHRydWU7XHJcbiAgICAgIH1cclxuICAgIH07XHJcbiAgfTtcclxuXHJcbiAgLyoqXHJcbiAgICogQXNzaWduIHRocm90dGxlZCBhY3Rpb25zIGFuZCBhZGQgbGlzdGVuZXJzXHJcbiAgICogQHBhcmFtIHtOdW1iZXJ9IHRocm90dGxlSW50ZXJ2YWxcclxuICAgKiBAbWV0aG9kIF9jb25uZWN0XHJcbiAgICovXHJcbiAgdmFyIF9jb25uZWN0ID0gZnVuY3Rpb24odGhyb3R0bGVJbnRlcnZhbCkge1xyXG4gICAgLy8gdGhyb3R0bGUgYW
250N0aW9uc1xyXG4gICAgdGhpcy5fdGhyb3R0bGVkSHVudEVsZW1lbnRzID0gdGhyb3R0bGUodGhpcy5faHVudEVsZW1lbnRzLmJpbmQodGhpcyksIHRocm90dGxlSW50ZXJ2YWwpO1xyXG4gICAgdGhpcy5fdGhyb3R0bGVkVXBkYXRlTWV0cmljcyA9IHRocm90dGxlKHRoaXMuX3VwZGF0ZU1ldHJpY3MuYmluZCh0aGlzKSwgdGhyb3R0bGVJbnRlcnZhbCk7XHJcblxyXG4gICAgLy8gYWRkIGxpc3RlbmVyc1xyXG4gICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ3Njcm9sbCcsIHRoaXMuX3Rocm90dGxlZEh1bnRFbGVtZW50cyk7XHJcbiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcigncmVzaXplJywgdGhpcy5fdGhyb3R0bGVkVXBkYXRlTWV0cmljcyk7XHJcblxyXG4gICAgLy8gcnVuIGZpcnN0IGNoZWNrXHJcbiAgICB0aGlzLl9odW50RWxlbWVudHMoKTtcclxuICB9O1xyXG5cclxuICAvKipcclxuICAgKiBDb25zdHJ1Y3RvciBmb3IgZWxlbWVudCB0aGF0IHNob3VsZCBiZSBodW50ZWRcclxuICAgKiBAY29uc3RydWN0b3IgSHVudGVkXHJcbiAgICogQHBhcmFtIHtOb2RlfSBlbGVtZW50XHJcbiAgICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZ1xyXG4gICAqL1xyXG4gIHZhciBIdW50ZWQgPSBmdW5jdGlvbihlbGVtZW50LCBjb25maWcpIHtcclxuICAgIHRoaXMuZWxlbWVudCA9IGVsZW1lbnQ7XHJcblxyXG4gICAgLy8gaW5zdGFudGlhdGUgZWxlbWVudCBhcyBub3QgdmlzaWJsZVxyXG4gICAgdGhpcy52aXNpYmxlID0gZmFsc2U7XHJcblxyXG4gICAgZm9yICh2YXIgcHJvcCBpbiBjb25maWcpIHtcclxuICAgICAgaWYgKE9iamVjdC5oYXNPd25Qcm9wZXJ0eS5jYWxsKGNvbmZpZywgcHJvcCkpIHtcclxuICAgICAgICB0aGlzW3Byb3BdID0gY29uZmlnW3Byb3BdO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHR5cGVvZiBlbGVtZW50LmRhdGFzZXQgIT09ICd1bmRlZmluZWQnKSB7XHJcbiAgICAgIC8vIHJlcGxhY2Ugb3B0aW9ucyB3aXRoIGRhdGFzZXQgaWYgcHJlc2VudFxyXG4gICAgICBpZiAodHlwZW9mIGVsZW1lbnQuZGF0YXNldC5odW50UGVyc2lzdCAhPT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgICB0cnkge1xyXG4gICAgICAgICAgdGhpcy5wZXJzaXN0ID0gSlNPTi5wYXJzZShlbGVtZW50LmRhdGFzZXQuaHVudFBlcnNpc3QpO1xyXG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcclxuICAgICAgICAgIGNvbnNvbGUubG9nKCdodW50OiBpbnZhbGlkIGRhdGEtaHVudC1wZXJzaXN0IHZhbHVlJywgZSk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAodHlwZW9mIGVsZW1lbnQuZGF0YXNldC5odW50T2Zmc2V0ICE9PSAndW5kZWZpbmVkJykge1xyXG4gICAgICAgIHRyeSB7XHJcbiAgICAgICAgICB0aGlzLm9mZnNldCA9IEpTT04ucGFyc2UoZWxlbWVudC5kYXRhc2V0Lmh1bnRPZmZzZXQpO1xyXG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcclxuICAgICAgICAgIGNvbnNvbGUubG9nKCdodW50OiBpbnZhbGlkIGRhdGEtaHVudC1vZmZzZXQgdmFsdWUnLCBlKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9O1xyXG5cclxuICAvLyBieSBkZWZhdWx0IG9mZnNldCBpcyB6ZXJvXHJcbiAgSHVudGVkLnByb3RvdHlwZS5vZmZzZXQgPSAwO1xyXG5cclxuICAvLyBieSBkZWZhdWx0IHRyaWdnZXIgZXZlbnRzIG9ubHkgb25jZVxyXG4gIEh1bnRlZC5wcm90b3R5cGUucGVyc2lzdCA9IGZhbHNlO1xyXG5cclxuICAvLyBmYWxsYmFjayBlbnRlciBmdW5jdGlvbiB0byBhdm9pZCBzYW5pdHkgY2hlY2tcclxuICBIdW50ZWQucHJvdG90eXBlLmVudGVyID0gbm9vcDtcclxuXHJcbiAgLy8gZmFsbGJhY2sgbGVhdmUgZnVuY3Rpb24gdG8gYXZvaWQgc2FuaXR5IGNoZWNrXHJcbiAgSHVudGVkLnByb3RvdHlwZS5sZWF2ZSA9IG5vb3A7XHJcblxyXG4gIC8qKlxyXG4gICAqIENyZWF0ZXMgYW5kIGluaXRpYWxpemVzIG9ic2VydmVyXHJcbiAgICogQGNvbnN0cnVjdG9yIEh1bnRPYnNlcnZlclxyXG4gICAqIEBwYXJhbSB7Tm9kZXxBcnJheX0gZWxlbWVudHNcclxuICAgKiBAcGFyYW0ge09iamVjdH0gb3B0aW9uc1xyXG4gICAqL1xyXG4gIHZhciBIdW50T2JzZXJ2ZXIgPSBmdW5jdGlvbihlbGVtZW50cywgb3B0aW9ucykge1xyXG4gICAgLy8gc2FuaXR5IGNoZWNrIGZvciBmaXJzdCBhcmd1bWVudFxyXG4gICAgaWYgKGVsZW1lbnRzIGluc3RhbmNlb2YgTm9kZSA9PT0gZmFsc2UgJiYgdHlwZW9mIGVsZW1lbnRzLmxlbmd0aCAhPT0gJ251bWJlcicpIHtcclxuICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcignaHVudDogb2JzZXJ2ZXIgZmlyc3QgYXJndW1lbnQgc2hvdWxkIGJlIGEgbm9kZSBvciBhIGxpc3Qgb2Ygbm9kZXMnKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBzYW5pdHkgY2hlY2sgZm9yIHNlY29uZCBhcmd1bWVudFxyXG4gICAgaWYgKHR5cGVvZiBvcHRpb25zICE9PSAnb2JqZWN0Jykge1xyXG4gICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdodW50OiBvYnNlcnZlciBzZWNvbmQgYXJndW1lbnQgc2hvdWxkIGJlIGFuIG9iamVjdCcpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIHRyZWF0IHNpbmdsZSBub2RlIGFzIGFycmF5XHJcbiAgICBpZiAoZWxlbWVudHMgaW5zdGFuY2VvZiBOb2RlID09PSB0cnVlKSB7XHJcbiAgICAgIGVsZW1lbnRzID0gWyBlbGVtZW50cyBdO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIHRyYWNrIHZpZXdwb3J0IGhlaWdodCBpbnRlcm5hbGx5XHJcbiAgICB0aGlzLl92aWV3cG9ydEhlaWdodCA9IHdpbmRvdy5pbm5lckhlaWdodDtcclxuXHJcbiAgICAvLyBhZGQgZWxlbWVudHMgdG8gZ2VuZXJhbCBodW50ZWQgYXJyYXlcclxuICAgIHRoaXMuX2h1bnRlZEVsZW1lbnRzID0gW107XHJcblxyXG4gICAgdmFyIGkgPSAwO1xyXG4gICAgdmFyIGxlbiA9IGVsZW1lbnRzLmxlbmd0aDtcclxuXHJcbiAgICBmb3IgKDsgaSA8IGxlbjsgaSsrKSB7XHJcbiAgICAgIHRoaXMuX2h1bnRlZEVsZW1lbnRzLnB1c2gobmV3IEh1bnRlZChlbGVtZW50c1tpXSwgb3B0aW9ucykpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIHNldCB1cCB0aHJvdHRsZSBpbnRlcnZhbFxyXG4gICAgdmFyIHRocm90dGxlSW50ZXJ2YWwgPSBvcHRpb25zLnRocm90dGxlSW50ZXJ2YWwgfHwgREVGQVVMVF9USFJPVFRMRV9JTlRFUlZBTDtcclxuXHJcbiAgICAvLyBjb25uZWN0IG9ic2VydmVyIGFuZCBwYXNzIGluIHRocm90dGxlIGludGVydmFsXHJcbiAgICBfY29ubmVjdC5jYWxsKHRoaXMsIHR
250ocm90dGxlSW50ZXJ2YWwpO1xyXG5cclxuICAgIGkgPSBsZW4gPSBudWxsO1xyXG5cclxuICAgIC8vIFJldHVybiBvYnNlcnZlciBpbnN0YW5jZVxyXG4gICAgcmV0dXJuIHRoaXM7XHJcbiAgfTtcclxuXHJcbiAgLyoqXHJcbiAgICogQ2hlY2tzIGlmIGh1bnRlZCBlbGVtZW50cyBhcmUgdmlzaWJsZSBhbmQgYXBwbHkgY2FsbGJhY2tzXHJcbiAgICogQG1ldGhvZCBfaHVudEVsZW1lbnRzXHJcbiAgICovXHJcbiAgSHVudE9ic2VydmVyLnByb3RvdHlwZS5faHVudEVsZW1lbnRzID0gZnVuY3Rpb24oKSB7XHJcbiAgICB2YXIgbGVuID0gdGhpcy5faHVudGVkRWxlbWVudHMubGVuZ3RoO1xyXG4gICAgdmFyIGh1bnRlZDtcclxuICAgIHZhciByZWN0O1xyXG4gICAgdmFyIGlzT25WaWV3cG9ydDtcclxuXHJcbiAgICB3aGlsZSAobGVuKSB7XHJcbiAgICAgIC0tbGVuO1xyXG5cclxuICAgICAgaHVudGVkID0gdGhpcy5faHVudGVkRWxlbWVudHNbbGVuXTtcclxuICAgICAgcmVjdCA9IGh1bnRlZC5lbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xyXG4gICAgICBpc09uVmlld3BvcnQgPSByZWN0LnRvcCAtIGh1bnRlZC5vZmZzZXQgPCB0aGlzLl92aWV3cG9ydEhlaWdodCAmJiByZWN0LnRvcCA+PSAtKHJlY3QuaGVpZ2h0ICsgaHVudGVkLm9mZnNldCk7XHJcblxyXG4gICAgICAvKlxyXG4gICAgICAgKiB0cmlnZ2VyIChlbnRlcikgZXZlbnQgaWYgZWxlbWVudCBjb21lcyBmcm9tIGEgbm9uIHZpc2libGUgc3RhdGUgYW5kIHRoZSBzY3JvbGxlZFxyXG4gICAgICAgKiB2aWV3cG9ydCBoYXMgcmVhY2hlZCB0aGUgdmlzaWJsZSByYW5nZSBvZiB0aGUgZWxlbWVudCB3aXRob3V0IGV4Y2VlZGluZyBpdFxyXG4gICAgICAgKi9cclxuICAgICAgaWYgKGh1bnRlZC52aXNpYmxlID09PSBmYWxzZSAmJiBpc09uVmlld3BvcnQgPT09IHRydWUpIHtcclxuICAgICAgICAgIGh1bnRlZC5lbnRlci5jYWxsKG51bGwsIGh1bnRlZC5lbGVtZW50KTtcclxuICAgICAgICAgIGh1bnRlZC52aXNpYmxlID0gdHJ1ZTtcclxuXHJcbiAgICAgICAgICAvLyB3aGVuIHRoZSBsZWF2ZSBjYWxsYmFjayBtZXRob2QgaXMgbm90IHNldCBhbmQgaHVudGluZyBzaG91bGQgbm90IHBlcnNpc3QgcmVtb3ZlIGVsZW1lbnRcclxuICAgICAgICAgIGlmIChodW50ZWQubGVhdmUgPT09IG5vb3AgJiYgaHVudGVkLnBlcnNpc3QgIT09IHRydWUpIHtcclxuICAgICAgICAgICAgdGhpcy5faHVudGVkRWxlbWVudHMuc3BsaWNlKGxlbiwgMSk7XHJcblxyXG4gICAgICAgICAgICAvLyBlbmQgb2JzZXJ2ZXIgYWN0aXZpdHkgd2hlbiB0aGVyZSBhcmUgbm8gbW9yZSBlbGVtZW50c1xyXG4gICAgICAgICAgICBpZiAodGhpcy5faHVudGVkRWxlbWVudHMubGVuZ3RoID09PSAwKSB7XHJcbiAgICAgICAgICAgICAgdGhpcy5kaXNjb25uZWN0KCk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICAvKlxyXG4gICAgICAgKiB0cmlnZ2VyIChvdXQpIGV2ZW50IGlmIGVsZW1lbnQgY29tZXMgZnJvbSBhIHZpc2libGUgc3RhdGVcclxuICAgICAgICogYW5kIGl0J3Mgb3V0IG9mIHRoZSB2aXNpYmxlIHJhbmdlIGl0cyBib3R0b20gb3IgdG9wIGxpbWl0XHJcbiAgICAgICAqL1xyXG4gICAgICBpZiAoaHVudGVkLnZpc2libGUgPT09IHRydWUgJiYgaXNPblZpZXdwb3J0ID09PSBmYWxzZSkge1xyXG4gICAgICAgIGh1bnRlZC5sZWF2ZS5jYWxsKG51bGwsIGh1bnRlZC5lbGVtZW50KTtcclxuICAgICAgICBodW50ZWQudmlzaWJsZSA9IGZhbHNlO1xyXG5cclxuICAgICAgICAvLyB3aGVuIGh1bnRpbmcgc2hvdWxkIG5vdCBwZXJzaXN0IHJlbW92ZSBlbGVtZW50XHJcbiAgICAgICAgaWYgKGh1bnRlZC5wZXJzaXN0ICE9PSB0cnVlKSB7XHJcbiAgICAgICAgICB0aGlzLl9odW50ZWRFbGVtZW50cy5zcGxpY2UobGVuLCAxKTtcclxuXHJcbiAgICAgICAgICAvLyBlbmQgb2JzZXJ2ZXIgYWN0aXZpdHkgd2hlbiB0aGVyZSBhcmUgbm8gbW9yZSBlbGVtZW50c1xyXG4gICAgICAgICAgaWYgKHRoaXMuX2h1bnRlZEVsZW1lbnRzLmxlbmd0aCA9PT0gMCkge1xyXG4gICAgICAgICAgICB0aGlzLmRpc2Nvbm5lY3QoKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBsZW4gPSBodW50ZWQgPSByZWN0ID0gaXNPblZpZXdwb3J0ID0gbnVsbDtcclxuICB9O1xyXG5cclxuICAvKipcclxuICAgKiBfaHVudEVsZW1lbnRzIHB1YmxpYyBhbGlhc1xyXG4gICAqIEBtZXRob2QgdHJpZ2dlclxyXG4gICAqL1xyXG4gIEh1bnRPYnNlcnZlci5wcm90b3R5cGUudHJpZ2dlciA9IEh1bnRPYnNlcnZlci5wcm90b3R5cGUuX2h1bnRFbGVtZW50cztcclxuXHJcbiAgLyoqXHJcbiAgICogVXBkYXRlIHZpZXdwb3J0IHRyYWNrZWQgaGVpZ2h0IGFuZCBydW5zIGEgY2hlY2tcclxuICAgKiBAbWV0aG9kIF91cGRhdGVNZXRyaWNzXHJcbiAgICovXHJcbiAgSHVudE9ic2VydmVyLnByb3RvdHlwZS5fdXBkYXRlTWV0cmljcyA9IGZ1bmN0aW9uKCkge1xyXG4gICAgdGhpcy5fdmlld3BvcnRIZWlnaHQgPSB3aW5kb3cuaW5uZXJIZWlnaHQ7XHJcbiAgICB0aGlzLl9odW50RWxlbWVudHMoKTtcclxuICB9O1xyXG5cclxuICAvKipcclxuICAgKiBSZW1vdmUgbGlzdGVuZXJzXHJcbiAgICogQG1ldGhvZCBkaXNjb25uZWN0XHJcbiAgICovXHJcbiAgSHVudE9ic2VydmVyLnByb3RvdHlwZS5kaXNjb25uZWN0ID0gZnVuY3Rpb24oKSB7XHJcbiAgICAvLyByZW1vdmUgbGlzdGVuZXJzXHJcbiAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcignc2Nyb2xsJywgdGhpcy5fdGhyb3R0bGVkSHVudEVsZW1lbnRzKTtcclxuICAgIHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKCdyZXNpemUnLCB0aGlzLl90aHJvdHRsZWRVcGRhdGVNZXRyaWNzKTtcclxuICB9O1xyXG5cclxuICByZXR1cm4gSHVudE9ic2VydmVyO1xyXG5cclxufSkpKTtcclxuIl0sImZpbGUiOiJhc3NldHNfc2l0ZV9jb3JlX3ZpbGxlL2pzL2xpYi9odW50Lm1pbi5qcyJ9
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.