Skip to content

Instantly share code, notes, and snippets.

@kasperlewau
Created May 22, 2017 10:03
Show Gist options
  • Save kasperlewau/34ce6887aca4662a8000c7a214b7380b to your computer and use it in GitHub Desktop.
Save kasperlewau/34ce6887aca4662a8000c7a214b7380b to your computer and use it in GitHub Desktop.
requirebin sketch
// Welcome! require() some modules from npm (like you were using browserify)
// and then hit Run Code to run your code on the right side.
// Modules get downloaded from browserify-cdn and bundled in your browser.
const HyperList = require('hyperlist')
const root = document.createElement('div')
const data = ['a', 'b', 'c', 'd']
const conf = {
height: 160,
itemHeight: 10,
total: 80,
generate: function (idx) {
const el = document.createElement('span')
el.innerHTML = `${data[idx] ? data[idx] : 'placeholder'}`
if (data[idx] && idx > 3) {
el.style.color = 'red'
}
return el
}
};
const list = new HyperList(root, conf);
document.body.appendChild(root)
setTimeout(function () {
data.push(...['e', 'f', 'g', 'h'])
list.refresh(root, conf)
const notice = document.createElement('span')
notice.innerHTML = 'Scroll down & then up please'
document.body.appendChild(notice)
}, 2500)
// scroll manually -> see the list
setTimeout(function(){
;require=(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})({"hyperlist":[function(require,module,exports){
(function (global){
(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.HyperList = 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(_dereq_,module,exports){
'use strict';
// Default configuration.
Object.defineProperty(exports, "__esModule", {
value: true
});
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var defaultConfig = {
width: '100%',
height: '100%'
};
// Check for valid number.
var isNumber = function isNumber(input) {
return Number(input) === Number(input);
};
/**
* Creates a HyperList instance that virtually scrolls very large amounts of
* data effortlessly.
*/
var HyperList = function () {
_createClass(HyperList, null, [{
key: 'create',
value: function create(element, userProvidedConfig) {
return new HyperList(element, userProvidedConfig);
}
/**
* Merge given css style on an element
* @param {DOMElement} element
* @param {Object} style
*/
}, {
key: 'mergeStyle',
value: function mergeStyle(element, style) {
for (var i in style) {
if (element.style[i] !== style[i]) {
element.style[i] = style[i];
}
}
}
}, {
key: 'getMaxBrowserHeight',
value: function getMaxBrowserHeight() {
// Create two elements, the wrapper is `1px` tall and is transparent and
// positioned at the top of the page. Inside that is an element that gets
// set to 1 billion pixels. Then reads the max height the browser can
// calculate.
var wrapper = document.createElement('div');
var fixture = document.createElement('div');
// As said above, these values get set to put the fixture elements into the
// right visual state.
HyperList.mergeStyle(wrapper, { position: 'absolute', height: '1px', opacity: 0 });
HyperList.mergeStyle(fixture, { height: '1e7px' });
// Add the fixture into the wrapper element.
wrapper.appendChild(fixture);
// Apply to the page, the values won't kick in unless this is attached.
document.body.appendChild(wrapper);
// Get the maximum element height in pixels.
var maxElementHeight = fixture.offsetHeight;
// Remove the element immediately after reading the value.
document.body.removeChild(wrapper);
return maxElementHeight;
}
}]);
function HyperList(element, userProvidedConfig) {
var _this = this;
_classCallCheck(this, HyperList);
this._config = {};
this._lastRepaint = null;
this._maxElementHeight = HyperList.getMaxBrowserHeight();
this.refresh(element, userProvidedConfig);
var config = this._config;
// Create internal render loop.
var render = function render() {
var scrollTop = _this._getScrollPosition();
var lastRepaint = _this._lastRepaint;
_this._renderAnimationFrame = window.requestAnimationFrame(render);
if (scrollTop === lastRepaint) {
return;
}
if (!lastRepaint || Math.abs(scrollTop - lastRepaint) > _this._averageHeight) {
var rendered = _this._renderChunk();
_this._lastRepaint = scrollTop;
if (rendered !== false && typeof config.afterRender === 'function') {
config.afterRender();
}
}
};
render();
}
_createClass(HyperList, [{
key: 'destroy',
value: function destroy() {
window.cancelAnimationFrame(this._renderAnimationFrame);
}
}, {
key: 'refresh',
value: function refresh(element, userProvidedConfig) {
var _this2 = this;
Object.assign(this._config, defaultConfig, userProvidedConfig);
if (!element || element.nodeType !== 1) {
throw new Error('HyperList requires a valid DOM Node container');
}
this._element = element;
var config = this._config;
var scroller = this._scroller || config.scroller || document.createElement(config.scrollerTagName || 'tr');
// Default configuration option `useFragment` to `true`.
if (typeof config.useFragment !== 'boolean') {
this._config.useFragment = true;
}
if (!config.generate) {
throw new Error('Missing required `generate` function');
}
if (!isNumber(config.total)) {
throw new Error('Invalid required `total` value, expected number');
}
if (!Array.isArray(config.itemHeight) && !isNumber(config.itemHeight)) {
throw new Error('\n Invalid required `itemHeight` value, expected number or array\n '.trim());
} else if (isNumber(config.itemHeight)) {
this._itemHeights = Array(config.total).fill(config.itemHeight);
} else {
this._itemHeights = config.itemHeight;
}
// Width and height should be coerced to string representations. Either in
// `%` or `px`.
Object.keys(defaultConfig).filter(function (prop) {
return prop in config;
}).forEach(function (prop) {
var value = config[prop];
var isValueNumber = isNumber(value);
var isValuePercent = isValueNumber ? false : value.slice(-1) === '%';
if (value && typeof value !== 'string' && typeof value !== 'number') {
var msg = 'Invalid optional `' + prop + '`, expected string or number';
throw new Error(msg);
} else if (isValueNumber) {
config[prop] = value + 'px';
}
if (prop !== 'height') {
return;
}
// Compute the containerHeight as number
var numberValue = isValueNumber ? value : parseInt(value.replace(/px|%/, ''), 10);
if (isValuePercent) {
_this2._containerHeight = window.innerHeight * numberValue / 100;
} else {
_this2._containerHeight = isNumber(value) ? value : numberValue;
}
});
// Decorate the container element with styles that will match
// the user supplied configuration.
var elementStyle = {
width: '' + config.width,
height: '' + config.height,
overflow: 'auto',
position: 'relative'
};
HyperList.mergeStyle(element, elementStyle);
var scrollerHeight = config.itemHeight * config.total;
var maxElementHeight = this._maxElementHeight;
if (scrollerHeight > maxElementHeight) {
console.warn(['HyperList: The maximum element height', maxElementHeight + 'px has', 'been exceeded; please reduce your item height.'].join(' '));
}
var scrollerStyle = {
opacity: '0',
position: 'absolute',
width: '1px',
height: scrollerHeight + 'px'
};
HyperList.mergeStyle(scroller, scrollerStyle);
// Only append the scroller element once.
if (!this._scroller) {
element.appendChild(scroller);
}
// Set the scroller instance.
this._scroller = scroller;
this._scrollHeight = this._computeScrollHeight();
// Reuse the item positions if refreshed, otherwise set to empty array.
this._itemPositions = this._itemPositions || Array(config.total).fill(0);
// Each index in the array should represent the position in the DOM.
this._computePositions(0);
// Render after refreshing.
this._renderChunk();
if (typeof config.afterRender === 'function') {
config.afterRender();
}
}
}, {
key: '_getRow',
value: function _getRow(i) {
var config = this._config;
var item = config.generate(i);
var height = item.height;
if (height !== undefined && isNumber(height)) {
item = item.element;
// The height isn't the same as predicted, compute positions again
if (height !== this._itemHeights) {
this._itemHeights[i] = height;
this._computePositions(i);
this._scrollHeight = this._computeScrollHeight(i);
}
} else {
height = this._itemHeights[i];
}
if (!item || item.nodeType !== 1) {
throw new Error('Generator did not return a DOM Node for index: ' + i);
}
var oldClass = item.getAttribute('class') || '';
item.setAttribute('class', oldClass + ' ' + (config.rowClassName || 'vrow'));
var top = this._itemPositions[i];
HyperList.mergeStyle(item, {
position: 'absolute',
top: top + 'px'
});
return item;
}
}, {
key: '_getScrollPosition',
value: function _getScrollPosition() {
var config = this._config;
if (typeof config.overrideScrollPosition === 'function') {
return config.overrideScrollPosition();
}
return this._element.scrollTop;
}
}, {
key: '_renderChunk',
value: function _renderChunk() {
var config = this._config;
var element = this._element;
var scrollTop = this._getScrollPosition();
var total = config.total;
var from = config.reverse ? this._getReverseFrom(scrollTop) : this._getFrom(scrollTop) - 1;
from = from < 0 ? 0 : from;
if (this._lastFrom === from) {
return false;
}
this._lastFrom = from;
var to = from + this._cachedItemsLen;
to = to > total ? total : to;
// Append all the new rows in a document fragment that we will later append
// to the parent node
var fragment = config.useFragment ? document.createDocumentFragment() : []
// Sometimes you'll pass fake elements to this tool and Fragments require
// real elements.
// The element that forces the container to scroll.
;var scroller = this._scroller;
// Keep the scroller in the list of children.
fragment[config.useFragment ? 'appendChild' : 'push'](scroller);
for (var i = from; i < to; i++) {
var row = this._getRow(i);
fragment[config.useFragment ? 'appendChild' : 'push'](row);
}
if (config.applyPatch) {
return config.applyPatch(element, fragment);
}
element.innerHTML = '';
element.appendChild(fragment);
}
}, {
key: '_computePositions',
value: function _computePositions() {
var from = arguments.length <= 0 || arguments[0] === undefined ? 1 : arguments[0];
var config = this._config;
var total = config.total;
var reverse = config.reverse;
if (from < 1 && !reverse) {
from = 1;
}
for (var i = from; i < total; i++) {
if (reverse) {
if (i === 0) {
this._itemPositions[0] = this._scrollHeight - this._itemHeights[0];
} else {
this._itemPositions[i] = this._itemPositions[i - 1] - this._itemHeights[i];
}
} else {
this._itemPositions[i] = this._itemHeights[i - 1] + this._itemPositions[i - 1];
}
}
}
}, {
key: '_computeScrollHeight',
value: function _computeScrollHeight() {
var _this3 = this;
var config = this._config;
var total = config.total;
var scrollHeight = this._itemHeights.reduce(function (a, b) {
return a + b;
}, 0);
HyperList.mergeStyle(this._scroller, {
opacity: 0,
position: 'absolute',
width: '1px',
height: scrollHeight + 'px'
});
var averageHeight = scrollHeight / total;
var containerHeight = this._element.innerHeight ? this._element.innerHeight : this._containerHeight;
this._screenItemsLen = Math.ceil(containerHeight / averageHeight);
this._containerHeight = containerHeight;
// Cache 3 times the number of items that fit in the container viewport.
this._cachedItemsLen = this._screenItemsLen * 3;
this._averageHeight = averageHeight;
if (config.reverse) {
window.requestAnimationFrame(function () {
_this3._element.scrollTop = scrollHeight;
});
}
return scrollHeight;
}
}, {
key: '_getFrom',
value: function _getFrom(scrollTop) {
var i = 0;
while (this._itemPositions[i] < scrollTop) {
i++;
}
return i;
}
}, {
key: '_getReverseFrom',
value: function _getReverseFrom(scrollTop) {
var i = this._config.total - 1;
while (i > 0 && this._itemPositions[i] < scrollTop + this._containerHeight) {
i--;
}
return i;
}
}]);
return HyperList;
}();
exports.default = HyperList;
module.exports = exports['default'];
},{}]},{},[1])(1)
});
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{}]},{},[])
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL2hvbWUvYWRtaW4vYnJvd3NlcmlmeS1jZG4vbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXItcGFjay9fcHJlbHVkZS5qcyIsImRpc3QvaHlwZXJsaXN0LmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztBQ0FBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uIGUodCxuLHIpe2Z1bmN0aW9uIHMobyx1KXtpZighbltvXSl7aWYoIXRbb10pe3ZhciBhPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7aWYoIXUmJmEpcmV0dXJuIGEobywhMCk7aWYoaSlyZXR1cm4gaShvLCEwKTt2YXIgZj1uZXcgRXJyb3IoXCJDYW5ub3QgZmluZCBtb2R1bGUgJ1wiK28rXCInXCIpO3Rocm93IGYuY29kZT1cIk1PRFVMRV9OT1RfRk9VTkRcIixmfXZhciBsPW5bb109e2V4cG9ydHM6e319O3Rbb11bMF0uY2FsbChsLmV4cG9ydHMsZnVuY3Rpb24oZSl7dmFyIG49dFtvXVsxXVtlXTtyZXR1cm4gcyhuP246ZSl9LGwsbC5leHBvcnRzLGUsdCxuLHIpfXJldHVybiBuW29dLmV4cG9ydHN9dmFyIGk9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtmb3IodmFyIG89MDtvPHIubGVuZ3RoO28rKylzKHJbb10pO3JldHVybiBzfSkiLCIoZnVuY3Rpb24oZil7aWYodHlwZW9mIGV4cG9ydHM9PT1cIm9iamVjdFwiJiZ0eXBlb2YgbW9kdWxlIT09XCJ1bmRlZmluZWRcIil7bW9kdWxlLmV4cG9ydHM9ZigpfWVsc2UgaWYodHlwZW9mIGRlZmluZT09PVwiZnVuY3Rpb25cIiYmZGVmaW5lLmFtZCl7ZGVmaW5lKFtdLGYpfWVsc2V7dmFyIGc7aWYodHlwZW9mIHdpbmRvdyE9PVwidW5kZWZpbmVkXCIpe2c9d2luZG93fWVsc2UgaWYodHlwZW9mIGdsb2JhbCE9PVwidW5kZWZpbmVkXCIpe2c9Z2xvYmFsfWVsc2UgaWYodHlwZW9mIHNlbGYhPT1cInVuZGVmaW5lZFwiKXtnPXNlbGZ9ZWxzZXtnPXRoaXN9Zy5IeXBlckxpc3QgPSBmKCl9fSkoZnVuY3Rpb24oKXt2YXIgZGVmaW5lLG1vZHVsZSxleHBvcnRzO3JldHVybiAoZnVuY3Rpb24gZSh0LG4scil7ZnVuY3Rpb24gcyhvLHUpe2lmKCFuW29dKXtpZighdFtvXSl7dmFyIGE9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtpZighdSYmYSlyZXR1cm4gYShvLCEwKTtpZihpKXJldHVybiBpKG8sITApO3ZhciBmPW5ldyBFcnJvcihcIkNhbm5vdCBmaW5kIG1vZHVsZSAnXCIrbytcIidcIik7dGhyb3cgZi5jb2RlPVwiTU9EVUxFX05PVF9GT1VORFwiLGZ9dmFyIGw9bltvXT17ZXhwb3J0czp7fX07dFtvXVswXS5jYWxsKGwuZXhwb3J0cyxmdW5jdGlvbihlKXt2YXIgbj10W29dWzFdW2VdO3JldHVybiBzKG4/bjplKX0sbCxsLmV4cG9ydHMsZSx0LG4scil9cmV0dXJuIG5bb10uZXhwb3J0c312YXIgaT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2Zvcih2YXIgbz0wO288ci5sZW5ndGg7bysrKXMocltvXSk7cmV0dXJuIHN9KSh7MTpbZnVuY3Rpb24oX2RlcmVxXyxtb2R1bGUsZXhwb3J0cyl7XG4ndXNlIHN0cmljdCc7XG5cbi8vIERlZmF1bHQgY29uZmlndXJhdGlvbi5cblxuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFwiX19lc01vZHVsZVwiLCB7XG4gIHZhbHVlOiB0cnVlXG59KTtcblxudmFyIF9jcmVhdGVDbGFzcyA9IGZ1bmN0aW9uICgpIHsgZnVuY3Rpb24gZGVmaW5lUHJvcGVydGllcyh0YXJnZXQsIHByb3BzKSB7IGZvciAodmFyIGkgPSAwOyBpIDwgcHJvcHMubGVuZ3RoOyBpKyspIHsgdmFyIGRlc2NyaXB0b3IgPSBwcm9wc1tpXTsgZGVzY3JpcHRvci5lbnVtZXJhYmxlID0gZGVzY3JpcHRvci5lbnVtZXJhYmxlIHx8IGZhbHNlOyBkZXNjcmlwdG9yLmNvbmZpZ3VyYWJsZSA9IHRydWU7IGlmIChcInZhbHVlXCIgaW4gZGVzY3JpcHRvcikgZGVzY3JpcHRvci53cml0YWJsZSA9IHRydWU7IE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0YXJnZXQsIGRlc2NyaXB0b3Iua2V5LCBkZXNjcmlwdG9yKTsgfSB9IHJldHVybiBmdW5jdGlvbiAoQ29uc3RydWN0b3IsIHByb3RvUHJvcHMsIHN0YXRpY1Byb3BzKSB7IGlmIChwcm90b1Byb3BzKSBkZWZpbmVQcm9wZXJ0aWVzKENvbnN0cnVjdG9yLnByb3RvdHlwZSwgcHJvdG9Qcm9wcyk7IGlmIChzdGF0aWNQcm9wcykgZGVmaW5lUHJvcGVydGllcyhDb25zdHJ1Y3Rvciwgc3RhdGljUHJvcHMpOyByZXR1cm4gQ29uc3RydWN0b3I7IH07IH0oKTtcblxuZnVuY3Rpb24gX2NsYXNzQ2FsbENoZWNrKGluc3RhbmNlLCBDb25zdHJ1Y3RvcikgeyBpZiAoIShpbnN0YW5jZSBpbnN0YW5jZW9mIENvbnN0cnVjdG9yKSkgeyB0aHJvdyBuZXcgVHlwZUVycm9yKFwiQ2Fubm90IGNhbGwgYSBjbGFzcyBhcyBhIGZ1bmN0aW9uXCIpOyB9IH1cblxudmFyIGRlZmF1bHRDb25maWcgPSB7XG4gIHdpZHRoOiAnMTAwJScsXG4gIGhlaWdodDogJzEwMCUnXG59O1xuXG4vLyBDaGVjayBmb3IgdmFsaWQgbnVtYmVyLlxudmFyIGlzTnVtYmVyID0gZnVuY3Rpb24gaXNOdW1iZXIoaW5wdXQpIHtcbiAgcmV0dXJuIE51bWJlcihpbnB1dCkgPT09IE51bWJlcihpbnB1dCk7XG59O1xuXG4vKipcbiAqIENyZWF0ZXMgYSBIeXBlckxpc3QgaW5zdGFuY2UgdGhhdCB2aXJ0dWFsbHkgc2Nyb2xscyB2ZXJ5IGxhcmdlIGFtb3VudHMgb2ZcbiAqIGRhdGEgZWZmb3J0bGVzc2x5LlxuICovXG5cbnZhciBIeXBlckxpc3QgPSBmdW5jdGlvbiAoKSB7XG4gIF9jcmVhdGVDbGFzcyhIeXBlckxpc3QsIG51bGwsIFt7XG4gICAga2V5OiAnY3JlYXRlJyxcbiAgICB2YWx1ZTogZnVuY3Rpb24gY3JlYXRlKGVsZW1lbnQsIHVzZXJQcm92aWRlZENvbmZpZykge1xuICAgICAgcmV0dXJuIG5ldyBIeXBlckxpc3QoZWxlbWVudCwgdXNlclByb3ZpZGVkQ29uZmlnKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBNZXJnZSBnaXZlbiBjc3Mgc3R5bGUgb24gYW4gZWxlbWVudFxuICAgICAqIEBwYXJhbSB7RE9NRWxlbWVudH0gZWxlbWVudFxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBzdHlsZVxuICAgICAqL1xuXG4gIH0sIHtcbiAgICBrZXk6ICdtZXJnZVN0eWxlJyxcbiAgICB2YWx1ZTogZnVuY3Rpb24gbWVyZ2VTdHlsZShlbGVtZW50LCBzdHlsZSkge1xuICAgICAgZm9yICh2YXIgaSBpbiBzdHlsZSkge1xuICAgICAgICBpZiAoZWxlbWVudC5zdHlsZVtpXSAhPT0gc3R5bGVbaV0pIHtcbiAgICAgICAgICBlbGVtZW50LnN0eWxlW2ldID0gc3R5bGVbaV07XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH0sIHtcbiAgICBrZXk6ICdnZXRNYXhCcm93c2VySGVpZ2h0JyxcbiAgICB2YWx1ZTogZnVuY3Rpb24gZ2V0TWF4QnJvd3NlckhlaWdodCgpIHtcbiAgICAgIC8vIENyZWF0ZSB0d28gZWxlbWVudHMsIHRoZSB3cmFwcGVyIGlzIGAxcHhgIHRhbGwgYW5kIGlzIHRyYW5zcGFyZW50IGFuZFxuICAgICAgLy8gcG9zaXRpb25lZCBhdCB0aGUgdG9wIG9mIHRoZSBwYWdlLiBJbnNpZGUgdGhhdCBpcyBhbiBlbGVtZW50IHRoYXQgZ2V0c1xuICAgICAgLy8gc2V0IHRvIDEgYmlsbGlvbiBwaXhlbHMuIFRoZW4gcmVhZHMgdGhlIG1heCBoZWlnaHQgdGhlIGJyb3dzZXIgY2FuXG4gICAgICAvLyBjYWxjdWxhdGUuXG4gICAgICB2YXIgd3JhcHBlciA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xuICAgICAgdmFyIGZpeHR1cmUgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKTtcblxuICAgICAgLy8gQXMgc2FpZCBhYm92ZSwgdGhlc2UgdmFsdWVzIGdldCBzZXQgdG8gcHV0IHRoZSBmaXh0dXJlIGVsZW1lbnRzIGludG8gdGhlXG4gICAgICAvLyByaWdodCB2aXN1YWwgc3RhdGUuXG4gICAgICBIeXBlckxpc3QubWVyZ2VTdHlsZSh3cmFwcGVyLCB7IHBvc2l0aW9uOiAnYWJzb2x1dGUnLCBoZWlnaHQ6ICcxcHgnLCBvcGFjaXR5OiAwIH0pO1xuICAgICAgSHlwZXJMaXN0Lm1lcmdlU3R5bGUoZml4dHVyZSwgeyBoZWlnaHQ6ICcxZTdweCcgfSk7XG5cbiAgICAgIC8vIEFkZCB0aGUgZml4dHVyZSBpbnRvIHRoZSB3cmFwcGVyIGVsZW1lbnQuXG4gICAgICB3cmFwcGVyLmFwcGVuZENoaWxkKGZpeHR1cmUpO1xuXG4gICAgICAvLyBBcHBseSB0byB0aGUgcGFnZSwgdGhlIHZhbHVlcyB3b24ndCBraWNrIGluIHVubGVzcyB0aGlzIGlzIGF0dGFjaGVkLlxuICAgICAgZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZCh3cmFwcGVyKTtcblxuICAgICAgLy8gR2V0IHRoZSBtYXhpbXVtIGVsZW1lbnQgaGVpZ2h0IGluIHBpeGVscy5cbiAgICAgIHZhciBtYXhFbGVtZW50SGVpZ2h0ID0gZml4dHVyZS5vZmZzZXRIZWlnaHQ7XG5cbiAgICAgIC8vIFJlbW92ZSB0aGUgZWxlbWVudCBpbW1lZGlhdGVseSBhZnRlciByZWFkaW5nIHRoZSB2YWx1ZS5cbiAgICAgIGRvY3VtZW50LmJvZHkucmVtb3ZlQ2hpbGQod3JhcHBlcik7XG5cbiAgICAgIHJldHVybiBtYXhFbGVtZW50SGVpZ2h0O1xuICAgIH1cbiAgfV0pO1xuXG4gIGZ1bmN0aW9uIEh5cGVyTGlzdChlbGVtZW50LCB1c2VyUHJvdmlkZWRDb25maWcpIHtcbiAgICB2YXIgX3RoaXMgPSB0aGlzO1xuXG4gICAgX2NsYXNzQ2FsbENoZWNrKHRoaXMsIEh5cGVyTGlzdCk7XG5cbiAgICB0aGlzLl9jb25maWcgPSB7fTtcbiAgICB0aGlzLl9sYXN0UmVwYWludCA9IG51bGw7XG4gICAgdGhpcy5fbWF4RWxlbWVudEhlaWdodCA9IEh5cGVyTGlzdC5nZXRNYXhCcm93c2VySGVpZ2h0KCk7XG5cbiAgICB0aGlzLnJlZnJlc2goZWxlbWVudCwgdXNlclByb3ZpZGVkQ29uZmlnKTtcblxuICAgIHZhciBjb25maWcgPSB0aGlzLl9jb25maWc7XG5cbiAgICAvLyBDcmVhdGUgaW50ZXJuYWwgcmVuZGVyIGxvb3AuXG4gICAgdmFyIHJlbmRlciA9IGZ1bmN0aW9uIHJlbmRlcigpIHtcbiAgICAgIHZhciBzY3JvbGxUb3AgPSBfdGhpcy5fZ2V0U2Nyb2xsUG9zaXRpb24oKTtcbiAgICAgIHZhciBsYXN0UmVwYWludCA9IF90aGlzLl9sYXN0UmVwYWludDtcblxuICAgICAgX3RoaXMuX3JlbmRlckFuaW1hdGlvbkZyYW1lID0gd2luZG93LnJlcXVlc3RBbmltYXRpb25GcmFtZShyZW5kZXIpO1xuXG4gICAgICBpZiAoc2Nyb2xsVG9wID09PSBsYXN0UmVwYWludCkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGlmICghbGFzdFJlcGFpbnQgfHwgTWF0aC5hYnMoc2Nyb2xsVG9wIC0gbGFzdFJlcGFpbnQpID4gX3RoaXMuX2F2ZXJhZ2VIZWlnaHQpIHtcbiAgICAgICAgdmFyIHJlbmRlcmVkID0gX3RoaXMuX3JlbmRlckNodW5rKCk7XG5cbiAgICAgICAgX3RoaXMuX2xhc3RSZXBhaW50ID0gc2Nyb2xsVG9wO1xuXG4gICAgICAgIGlmIChyZW5kZXJlZCAhPT0gZmFsc2UgJiYgdHlwZW9mIGNvbmZpZy5hZnRlclJlbmRlciA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgIGNvbmZpZy5hZnRlclJlbmRlcigpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfTtcblxuICAgIHJlbmRlcigpO1xuICB9XG5cbiAgX2NyZWF0ZUNsYXNzKEh5cGVyTGlzdCwgW3tcbiAgICBrZXk6ICdkZXN0cm95JyxcbiAgICB2YWx1ZTogZnVuY3Rpb24gZGVzdHJveSgpIHtcbiAgICAgIHdpbmRvdy5jYW5jZWxBbmltYXRpb25GcmFtZSh0aGlzLl9yZW5kZXJBbmltYXRpb25GcmFtZSk7XG4gICAgfVxuICB9LCB7XG4gICAga2V5OiAncmVmcmVzaCcsXG4gICAgdmFsdWU6IGZ1bmN0aW9uIHJlZnJlc2goZWxlbWVudCwgdXNlclByb3ZpZGVkQ29uZmlnKSB7XG4gICAgICB2YXIgX3RoaXMyID0gdGhpcztcblxuICAgICAgT2JqZWN0LmFzc2lnbih0aGlzLl9jb25maWcsIGRlZmF1bHRDb25maWcsIHVzZXJQcm92aWRlZENvbmZpZyk7XG5cbiAgICAgIGlmICghZWxlbWVudCB8fCBlbGVtZW50Lm5vZGVUeXBlICE9PSAxKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignSHlwZXJMaXN0IHJlcXVpcmVzIGEgdmFsaWQgRE9NIE5vZGUgY29udGFpbmVyJyk7XG4gICAgICB9XG5cbiAgICAgIHRoaXMuX2VsZW1lbnQgPSBlbGVtZW50O1xuXG4gICAgICB2YXIgY29uZmlnID0gdGhpcy5fY29uZmlnO1xuXG4gICAgICB2YXIgc2Nyb2xsZXIgPSB0aGlzLl9zY3JvbGxlciB8fCBjb25maWcuc2Nyb2xsZXIgfHwgZG9jdW1lbnQuY3JlYXRlRWxlbWVudChjb25maWcuc2Nyb2xsZXJUYWdOYW1lIHx8ICd0cicpO1xuXG4gICAgICAvLyBEZWZhdWx0IGNvbmZpZ3VyYXRpb24gb3B0aW9uIGB1c2VGcmFnbWVudGAgdG8gYHRydWVgLlxuICAgICAgaWYgKHR5cGVvZiBjb25maWcudXNlRnJhZ21lbnQgIT09ICdib29sZWFuJykge1xuICAgICAgICB0aGlzLl9jb25maWcudXNlRnJhZ21lbnQgPSB0cnVlO1xuICAgICAgfVxuXG4gICAgICBpZiAoIWNvbmZpZy5nZW5lcmF0ZSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ01pc3NpbmcgcmVxdWlyZWQgYGdlbmVyYXRlYCBmdW5jdGlvbicpO1xuICAgICAgfVxuXG4gICAgICBpZiAoIWlzTnVtYmVyKGNvbmZpZy50b3RhbCkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIHJlcXVpcmVkIGB0b3RhbGAgdmFsdWUsIGV4cGVjdGVkIG51bWJlcicpO1xuICAgICAgfVxuXG4gICAgICBpZiAoIUFycmF5LmlzQXJyYXkoY29uZmlnLml0ZW1IZWlnaHQpICYmICFpc051bWJlcihjb25maWcuaXRlbUhlaWdodCkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdcXG4gICAgICAgIEludmFsaWQgcmVxdWlyZWQgYGl0ZW1IZWlnaHRgIHZhbHVlLCBleHBlY3RlZCBudW1iZXIgb3IgYXJyYXlcXG4gICAgICAnLnRyaW0oKSk7XG4gICAgICB9IGVsc2UgaWYgKGlzTnVtYmVyKGNvbmZpZy5pdGVtSGVpZ2h0KSkge1xuICAgICAgICB0aGlzLl9pdGVtSGVpZ2h0cyA9IEFycmF5KGNvbmZpZy50b3RhbCkuZmlsbChjb25maWcuaXRlbUhlaWdodCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLl9pdGVtSGVpZ2h0cyA9IGNvbmZpZy5pdGVtSGVpZ2h0O1xuICAgICAgfVxuXG4gICAgICAvLyBXaWR0aCBhbmQgaGVpZ2h0IHNob3VsZCBiZSBjb2VyY2VkIHRvIHN0cmluZyByZXByZXNlbnRhdGlvbnMuIEVpdGhlciBpblxuICAgICAgLy8gYCVgIG9yIGBweGAuXG4gICAgICBPYmplY3Qua2V5cyhkZWZhdWx0Q29uZmlnKS5maWx0ZXIoZnVuY3Rpb24gKHByb3ApIHtcbiAgICAgICAgcmV0dXJuIHByb3AgaW4gY29uZmlnO1xuICAgICAgfSkuZm9yRWFjaChmdW5jdGlvbiAocHJvcCkge1xuICAgICAgICB2YXIgdmFsdWUgPSBjb25maWdbcHJvcF07XG4gICAgICAgIHZhciBpc1ZhbHVlTnVtYmVyID0gaXNOdW1iZXIodmFsdWUpO1xuICAgICAgICB2YXIgaXNWYWx1ZVBlcmNlbnQgPSBpc1ZhbHVlTnVtYmVyID8gZmFsc2UgOiB2YWx1ZS5zbGljZSgtMSkgPT09ICclJztcblxuICAgICAgICBpZiAodmFsdWUgJiYgdHlwZW9mIHZhbHVlICE9PSAnc3RyaW5nJyAmJiB0eXBlb2YgdmFsdWUgIT09ICdudW1iZXInKSB7XG4gICAgICAgICAgdmFyIG1zZyA9ICdJbnZhbGlkIG9wdGlvbmFsIGAnICsgcHJvcCArICdgLCBleHBlY3RlZCBzdHJpbmcgb3IgbnVtYmVyJztcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IobXNnKTtcbiAgICAgICAgfSBlbHNlIGlmIChpc1ZhbHVlTnVtYmVyKSB7XG4gICAgICAgICAgY29uZmlnW3Byb3BdID0gdmFsdWUgKyAncHgnO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHByb3AgIT09ICdoZWlnaHQnKSB7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gQ29tcHV0ZSB0aGUgY29udGFpbmVySGVpZ2h0IGFzIG51bWJlclxuICAgICAgICB2YXIgbnVtYmVyVmFsdWUgPSBpc1ZhbHVlTnVtYmVyID8gdmFsdWUgOiBwYXJzZUludCh2YWx1ZS5yZXBsYWNlKC9weHwlLywgJycpLCAxMCk7XG5cbiAgICAgICAgaWYgKGlzVmFsdWVQZXJjZW50KSB7XG4gICAgICAgICAgX3RoaXMyLl9jb250YWluZXJIZWlnaHQgPSB3aW5kb3cuaW5uZXJIZWlnaHQgKiBudW1iZXJWYWx1ZSAvIDEwMDtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBfdGhpczIuX2NvbnRhaW5lckhlaWdodCA9IGlzTnVtYmVyKHZhbHVlKSA/IHZhbHVlIDogbnVtYmVyVmFsdWU7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuXG4gICAgICAvLyBEZWNvcmF0ZSB0aGUgY29udGFpbmVyIGVsZW1lbnQgd2l0aCBzdHlsZXMgdGhhdCB3aWxsIG1hdGNoXG4gICAgICAvLyB0aGUgdXNlciBzdXBwbGllZCBjb25maWd1cmF0aW9uLlxuICAgICAgdmFyIGVsZW1lbnRTdHlsZSA9IHtcbiAgICAgICAgd2lkdGg6ICcnICsgY29uZmlnLndpZHRoLFxuICAgICAgICBoZWlnaHQ6ICcnICsgY29uZmlnLmhlaWdodCxcbiAgICAgICAgb3ZlcmZsb3c6ICdhdXRvJyxcbiAgICAgICAgcG9zaXRpb246ICdyZWxhdGl2ZSdcbiAgICAgIH07XG5cbiAgICAgIEh5cGVyTGlzdC5tZXJnZVN0eWxlKGVsZW1lbnQsIGVsZW1lbnRTdHlsZSk7XG5cbiAgICAgIHZhciBzY3JvbGxlckhlaWdodCA9IGNvbmZpZy5pdGVtSGVpZ2h0ICogY29uZmlnLnRvdGFsO1xuICAgICAgdmFyIG1heEVsZW1lbnRIZWlnaHQgPSB0aGlzLl9tYXhFbGVtZW50SGVpZ2h0O1xuXG4gICAgICBpZiAoc2Nyb2xsZXJIZWlnaHQgPiBtYXhFbGVtZW50SGVpZ2h0KSB7XG4gICAgICAgIGNvbnNvbGUud2FybihbJ0h5cGVyTGlzdDogVGhlIG1heGltdW0gZWxlbWVudCBoZWlnaHQnLCBtYXhFbGVtZW50SGVpZ2h0ICsgJ3B4IGhhcycsICdiZWVuIGV4Y2VlZGVkOyBwbGVhc2UgcmVkdWNlIHlvdXIgaXRlbSBoZWlnaHQuJ10uam9pbignICcpKTtcbiAgICAgIH1cblxuICAgICAgdmFyIHNjcm9sbGVyU3R5bGUgPSB7XG4gICAgICAgIG9wYWNpdHk6ICcwJyxcbiAgICAgICAgcG9zaXRpb246ICdhYnNvbHV0ZScsXG4gICAgICAgIHdpZHRoOiAnMXB4JyxcbiAgICAgICAgaGVpZ2h0OiBzY3JvbGxlckhlaWdodCArICdweCdcbiAgICAgIH07XG5cbiAgICAgIEh5cGVyTGlzdC5tZXJnZVN0eWxlKHNjcm9sbGVyLCBzY3JvbGxlclN0eWxlKTtcblxuICAgICAgLy8gT25seSBhcHBlbmQgdGhlIHNjcm9sbGVyIGVsZW1lbnQgb25jZS5cbiAgICAgIGlmICghdGhpcy5fc2Nyb2xsZXIpIHtcbiAgICAgICAgZWxlbWVudC5hcHBlbmRDaGlsZChzY3JvbGxlcik7XG4gICAgICB9XG5cbiAgICAgIC8vIFNldCB0aGUgc2Nyb2xsZXIgaW5zdGFuY2UuXG4gICAgICB0aGlzLl9zY3JvbGxlciA9IHNjcm9sbGVyO1xuICAgICAgdGhpcy5fc2Nyb2xsSGVpZ2h0ID0gdGhpcy5fY29tcHV0ZVNjcm9sbEhlaWdodCgpO1xuXG4gICAgICAvLyBSZXVzZSB0aGUgaXRlbSBwb3NpdGlvbnMgaWYgcmVmcmVzaGVkLCBvdGhlcndpc2Ugc2V0IHRvIGVtcHR5IGFycmF5LlxuICAgICAgdGhpcy5faXRlbVBvc2l0aW9ucyA9IHRoaXMuX2l0ZW1Qb3NpdGlvbnMgfHwgQXJyYXkoY29uZmlnLnRvdGFsKS5maWxsKDApO1xuXG4gICAgICAvLyBFYWNoIGluZGV4IGluIHRoZSBhcnJheSBzaG91bGQgcmVwcmVzZW50IHRoZSBwb3NpdGlvbiBpbiB0aGUgRE9NLlxuICAgICAgdGhpcy5fY29tcHV0ZVBvc2l0aW9ucygwKTtcblxuICAgICAgLy8gUmVuZGVyIGFmdGVyIHJlZnJlc2hpbmcuXG4gICAgICB0aGlzLl9yZW5kZXJDaHVuaygpO1xuXG4gICAgICBpZiAodHlwZW9mIGNvbmZpZy5hZnRlclJlbmRlciA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICBjb25maWcuYWZ0ZXJSZW5kZXIoKTtcbiAgICAgIH1cbiAgICB9XG4gIH0sIHtcbiAgICBrZXk6ICdfZ2V0Um93JyxcbiAgICB2YWx1ZTogZnVuY3Rpb24gX2dldFJvdyhpKSB7XG4gICAgICB2YXIgY29uZmlnID0gdGhpcy5fY29uZmlnO1xuICAgICAgdmFyIGl0ZW0gPSBjb25maWcuZ2VuZXJhdGUoaSk7XG4gICAgICB2YXIgaGVpZ2h0ID0gaXRlbS5oZWlnaHQ7XG5cbiAgICAgIGlmIChoZWlnaHQgIT09IHVuZGVmaW5lZCAmJiBpc051bWJlcihoZWlnaHQpKSB7XG4gICAgICAgIGl0ZW0gPSBpdGVtLmVsZW1lbnQ7XG5cbiAgICAgICAgLy8gVGhlIGhlaWdodCBpc24ndCB0aGUgc2FtZSBhcyBwcmVkaWN0ZWQsIGNvbXB1dGUgcG9zaXRpb25zIGFnYWluXG4gICAgICAgIGlmIChoZWlnaHQgIT09IHRoaXMuX2l0ZW1IZWlnaHRzKSB7XG4gICAgICAgICAgdGhpcy5faXRlbUhlaWdodHNbaV0gPSBoZWlnaHQ7XG4gICAgICAgICAgdGhpcy5fY29tcHV0ZVBvc2l0aW9ucyhpKTtcbiAgICAgICAgICB0aGlzLl9zY3JvbGxIZWlnaHQgPSB0aGlzLl9jb21wdXRlU2Nyb2xsSGVpZ2h0KGkpO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBoZWlnaHQgPSB0aGlzLl9pdGVtSGVpZ2h0c1tpXTtcbiAgICAgIH1cblxuICAgICAgaWYgKCFpdGVtIHx8IGl0ZW0ubm9kZVR5cGUgIT09IDEpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdHZW5lcmF0b3IgZGlkIG5vdCByZXR1cm4gYSBET00gTm9kZSBmb3IgaW5kZXg6ICcgKyBpKTtcbiAgICAgIH1cblxuICAgICAgdmFyIG9sZENsYXNzID0gaXRlbS5nZXRBdHRyaWJ1dGUoJ2NsYXNzJykgfHwgJyc7XG4gICAgICBpdGVtLnNldEF0dHJpYnV0ZSgnY2xhc3MnLCBvbGRDbGFzcyArICcgJyArIChjb25maWcucm93Q2xhc3NOYW1lIHx8ICd2cm93JykpO1xuXG4gICAgICB2YXIgdG9wID0gdGhpcy5faXRlbVBvc2l0aW9uc1tpXTtcblxuICAgICAgSHlwZXJMaXN0Lm1lcmdlU3R5bGUoaXRlbSwge1xuICAgICAgICBwb3NpdGlvbjogJ2Fic29sdXRlJyxcbiAgICAgICAgdG9wOiB0b3AgKyAncHgnXG4gICAgICB9KTtcblxuICAgICAgcmV0dXJuIGl0ZW07XG4gICAgfVxuICB9LCB7XG4gICAga2V5OiAnX2dldFNjcm9sbFBvc2l0aW9uJyxcbiAgICB2YWx1ZTogZnVuY3Rpb24gX2dldFNjcm9sbFBvc2l0aW9uKCkge1xuICAgICAgdmFyIGNvbmZpZyA9IHRoaXMuX2NvbmZpZztcblxuICAgICAgaWYgKHR5cGVvZiBjb25maWcub3ZlcnJpZGVTY3JvbGxQb3NpdGlvbiA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICByZXR1cm4gY29uZmlnLm92ZXJyaWRlU2Nyb2xsUG9zaXRpb24oKTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHRoaXMuX2VsZW1lbnQuc2Nyb2xsVG9wO1xuICAgIH1cbiAgfSwge1xuICAgIGtleTogJ19yZW5kZXJDaHVuaycsXG4gICAgdmFsdWU6IGZ1bmN0aW9uIF9yZW5kZXJDaHVuaygpIHtcbiAgICAgIHZhciBjb25maWcgPSB0aGlzLl9jb25maWc7XG4gICAgICB2YXIgZWxlbWVudCA9IHRoaXMuX2VsZW1lbnQ7XG4gICAgICB2YXIgc2Nyb2xsVG9wID0gdGhpcy5fZ2V0U2Nyb2xsUG9zaXRpb24oKTtcbiAgICAgIHZhciB0b3RhbCA9IGNvbmZpZy50b3RhbDtcblxuICAgICAgdmFyIGZyb20gPSBjb25maWcucmV2ZXJzZSA/IHRoaXMuX2dldFJldmVyc2VGcm9tKHNjcm9sbFRvcCkgOiB0aGlzLl9nZXRGcm9tKHNjcm9sbFRvcCkgLSAxO1xuICAgICAgZnJvbSA9IGZyb20gPCAwID8gMCA6IGZyb207XG5cbiAgICAgIGlmICh0aGlzLl9sYXN0RnJvbSA9PT0gZnJvbSkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9XG5cbiAgICAgIHRoaXMuX2xhc3RGcm9tID0gZnJvbTtcblxuICAgICAgdmFyIHRvID0gZnJvbSArIHRoaXMuX2NhY2hlZEl0ZW1zTGVuO1xuICAgICAgdG8gPSB0byA+IHRvdGFsID8gdG90YWwgOiB0bztcblxuICAgICAgLy8gQXBwZW5kIGFsbCB0aGUgbmV3IHJvd3MgaW4gYSBkb2N1bWVudCBmcmFnbWVudCB0aGF0IHdlIHdpbGwgbGF0ZXIgYXBwZW5kXG4gICAgICAvLyB0byB0aGUgcGFyZW50IG5vZGVcbiAgICAgIHZhciBmcmFnbWVudCA9IGNvbmZpZy51c2VGcmFnbWVudCA/IGRvY3VtZW50LmNyZWF0ZURvY3VtZW50RnJhZ21lbnQoKSA6IFtdXG4gICAgICAvLyBTb21ldGltZXMgeW91J2xsIHBhc3MgZmFrZSBlbGVtZW50cyB0byB0aGlzIHRvb2wgYW5kIEZyYWdtZW50cyByZXF1aXJlXG4gICAgICAvLyByZWFsIGVsZW1lbnRzLlxuXG5cbiAgICAgIC8vIFRoZSBlbGVtZW50IHRoYXQgZm9yY2VzIHRoZSBjb250YWluZXIgdG8gc2Nyb2xsLlxuICAgICAgO3ZhciBzY3JvbGxlciA9IHRoaXMuX3Njcm9sbGVyO1xuXG4gICAgICAvLyBLZWVwIHRoZSBzY3JvbGxlciBpbiB0aGUgbGlzdCBvZiBjaGlsZHJlbi5cbiAgICAgIGZyYWdtZW50W2NvbmZpZy51c2VGcmFnbWVudCA/ICdhcHBlbmRDaGlsZCcgOiAncHVzaCddKHNjcm9sbGVyKTtcblxuICAgICAgZm9yICh2YXIgaSA9IGZyb207IGkgPCB0bzsgaSsrKSB7XG4gICAgICAgIHZhciByb3cgPSB0aGlzLl9nZXRSb3coaSk7XG5cbiAgICAgICAgZnJhZ21lbnRbY29uZmlnLnVzZUZyYWdtZW50ID8gJ2FwcGVuZENoaWxkJyA6ICdwdXNoJ10ocm93KTtcbiAgICAgIH1cblxuICAgICAgaWYgKGNvbmZpZy5hcHBseVBhdGNoKSB7XG4gICAgICAgIHJldHVybiBjb25maWcuYXBwbHlQYXRjaChlbGVtZW50LCBmcmFnbWVudCk7XG4gICAgICB9XG5cbiAgICAgIGVsZW1lbnQuaW5uZXJIVE1MID0gJyc7XG4gICAgICBlbGVtZW50LmFwcGVuZENoaWxkKGZyYWdtZW50KTtcbiAgICB9XG4gIH0sIHtcbiAgICBrZXk6ICdfY29tcHV0ZVBvc2l0aW9ucycsXG4gICAgdmFsdWU6IGZ1bmN0aW9uIF9jb21wdXRlUG9zaXRpb25zKCkge1xuICAgICAgdmFyIGZyb20gPSBhcmd1bWVudHMubGVuZ3RoIDw9IDAgfHwgYXJndW1lbnRzWzBdID09PSB1bmRlZmluZWQgPyAxIDogYXJndW1lbnRzWzBdO1xuXG4gICAgICB2YXIgY29uZmlnID0gdGhpcy5fY29uZmlnO1xuICAgICAgdmFyIHRvdGFsID0gY29uZmlnLnRvdGFsO1xuICAgICAgdmFyIHJldmVyc2UgPSBjb25maWcucmV2ZXJzZTtcblxuICAgICAgaWYgKGZyb20gPCAxICYmICFyZXZlcnNlKSB7XG4gICAgICAgIGZyb20gPSAxO1xuICAgICAgfVxuXG4gICAgICBmb3IgKHZhciBpID0gZnJvbTsgaSA8IHRvdGFsOyBpKyspIHtcbiAgICAgICAgaWYgKHJldmVyc2UpIHtcbiAgICAgICAgICBpZiAoaSA9PT0gMCkge1xuICAgICAgICAgICAgdGhpcy5faXRlbVBvc2l0aW9uc1swXSA9IHRoaXMuX3Njcm9sbEhlaWdodCAtIHRoaXMuX2l0ZW1IZWlnaHRzWzBdO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLl9pdGVtUG9zaXRpb25zW2ldID0gdGhpcy5faXRlbVBvc2l0aW9uc1tpIC0gMV0gLSB0aGlzLl9pdGVtSGVpZ2h0c1tpXTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhpcy5faXRlbVBvc2l0aW9uc1tpXSA9IHRoaXMuX2l0ZW1IZWlnaHRzW2kgLSAxXSArIHRoaXMuX2l0ZW1Qb3NpdGlvbnNbaSAtIDFdO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9LCB7XG4gICAga2V5OiAnX2NvbXB1dGVTY3JvbGxIZWlnaHQnLFxuICAgIHZhbHVlOiBmdW5jdGlvbiBfY29tcHV0ZVNjcm9sbEhlaWdodCgpIHtcbiAgICAgIHZhciBfdGhpczMgPSB0aGlzO1xuXG4gICAgICB2YXIgY29uZmlnID0gdGhpcy5fY29uZmlnO1xuICAgICAgdmFyIHRvdGFsID0gY29uZmlnLnRvdGFsO1xuICAgICAgdmFyIHNjcm9sbEhlaWdodCA9IHRoaXMuX2l0ZW1IZWlnaHRzLnJlZHVjZShmdW5jdGlvbiAoYSwgYikge1xuICAgICAgICByZXR1cm4gYSArIGI7XG4gICAgICB9LCAwKTtcblxuICAgICAgSHlwZXJMaXN0Lm1lcmdlU3R5bGUodGhpcy5fc2Nyb2xsZXIsIHtcbiAgICAgICAgb3BhY2l0eTogMCxcbiAgICAgICAgcG9zaXRpb246ICdhYnNvbHV0ZScsXG4gICAgICAgIHdpZHRoOiAnMXB4JyxcbiAgICAgICAgaGVpZ2h0OiBzY3JvbGxIZWlnaHQgKyAncHgnXG4gICAgICB9KTtcblxuICAgICAgdmFyIGF2ZXJhZ2VIZWlnaHQgPSBzY3JvbGxIZWlnaHQgLyB0b3RhbDtcbiAgICAgIHZhciBjb250YWluZXJIZWlnaHQgPSB0aGlzLl9lbGVtZW50LmlubmVySGVpZ2h0ID8gdGhpcy5fZWxlbWVudC5pbm5lckhlaWdodCA6IHRoaXMuX2NvbnRhaW5lckhlaWdodDtcbiAgICAgIHRoaXMuX3NjcmVlbkl0ZW1zTGVuID0gTWF0aC5jZWlsKGNvbnRhaW5lckhlaWdodCAvIGF2ZXJhZ2VIZWlnaHQpO1xuICAgICAgdGhpcy5fY29udGFpbmVySGVpZ2h0ID0gY29udGFpbmVySGVpZ2h0O1xuXG4gICAgICAvLyBDYWNoZSAzIHRpbWVzIHRoZSBudW1iZXIgb2YgaXRlbXMgdGhhdCBmaXQgaW4gdGhlIGNvbnRhaW5lciB2aWV3cG9ydC5cbiAgICAgIHRoaXMuX2NhY2hlZEl0ZW1zTGVuID0gdGhpcy5fc2NyZWVuSXRlbXNMZW4gKiAzO1xuICAgICAgdGhpcy5fYXZlcmFnZUhlaWdodCA9IGF2ZXJhZ2VIZWlnaHQ7XG5cbiAgICAgIGlmIChjb25maWcucmV2ZXJzZSkge1xuICAgICAgICB3aW5kb3cucmVxdWVzdEFuaW1hdGlvbkZyYW1lKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICBfdGhpczMuX2VsZW1lbnQuc2Nyb2xsVG9wID0gc2Nyb2xsSGVpZ2h0O1xuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHNjcm9sbEhlaWdodDtcbiAgICB9XG4gIH0sIHtcbiAgICBrZXk6ICdfZ2V0RnJvbScsXG4gICAgdmFsdWU6IGZ1bmN0aW9uIF9nZXRGcm9tKHNjcm9sbFRvcCkge1xuICAgICAgdmFyIGkgPSAwO1xuXG4gICAgICB3aGlsZSAodGhpcy5faXRlbVBvc2l0aW9uc1tpXSA8IHNjcm9sbFRvcCkge1xuICAgICAgICBpKys7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBpO1xuICAgIH1cbiAgfSwge1xuICAgIGtleTogJ19nZXRSZXZlcnNlRnJvbScsXG4gICAgdmFsdWU6IGZ1bmN0aW9uIF9nZXRSZXZlcnNlRnJvbShzY3JvbGxUb3ApIHtcbiAgICAgIHZhciBpID0gdGhpcy5fY29uZmlnLnRvdGFsIC0gMTtcblxuICAgICAgd2hpbGUgKGkgPiAwICYmIHRoaXMuX2l0ZW1Qb3NpdGlvbnNbaV0gPCBzY3JvbGxUb3AgKyB0aGlzLl9jb250YWluZXJIZWlnaHQpIHtcbiAgICAgICAgaS0tO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gaTtcbiAgICB9XG4gIH1dKTtcblxuICByZXR1cm4gSHlwZXJMaXN0O1xufSgpO1xuXG5leHBvcnRzLmRlZmF1bHQgPSBIeXBlckxpc3Q7XG5tb2R1bGUuZXhwb3J0cyA9IGV4cG9ydHNbJ2RlZmF1bHQnXTtcblxufSx7fV19LHt9LFsxXSkoMSlcbn0pOyJdfQ==
// Welcome! require() some modules from npm (like you were using browserify)
// and then hit Run Code to run your code on the right side.
// Modules get downloaded from browserify-cdn and bundled in your browser.
const HyperList = require('hyperlist')
const root = document.createElement('div')
const data = ['a', 'b', 'c', 'd']
const conf = {
height: 160,
itemHeight: 10,
total: 80,
generate: function (idx) {
const el = document.createElement('span')
el.innerHTML = `${data[idx] ? data[idx] : 'placeholder'}`
if (data[idx] && idx > 3) {
el.style.color = 'red'
}
return el
}
};
const list = new HyperList(root, conf);
document.body.appendChild(root)
setTimeout(function () {
data.push(...['e', 'f', 'g', 'h'])
list.refresh(root, conf)
const notice = document.createElement('span')
notice.innerHTML = 'Scroll down & then up please'
document.body.appendChild(notice)
}, 2500)
// scroll manually -> see the list
;}, 0)
{
"name": "requirebin-sketch",
"version": "1.0.0",
"dependencies": {
"hyperlist": "1.0.0-alpha-7"
}
}
<!-- contents of this file will be placed inside the <body> -->
<!-- contents of this file will be placed inside the <head> -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment