UNPKG

scratchcard

Version:
1,890 lines (1,608 loc) 183 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.Scratchcard = 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){ /* jshint browserify: true */ 'use strict'; var defaults = require('lodash.defaults'); module.exports = exports = Painter; var defaultOptions = { color: 'silver', thickness: 50 }; function Painter(options) { this.options = defaults({}, options, defaultOptions); } Painter.prototype.reset = function reset(ctx, width, height) { ctx.fillStyle = this.options.color; ctx.globalCompositeOperation = 'source-over'; ctx.fillRect(0, 0, width, height); }; Painter.prototype.drawPoint = function drawPoint(ctx, point) { ctx.fillStyle = 'rgba(0,0,0,1)'; ctx.globalCompositeOperation = 'destination-out'; ctx.beginPath(); ctx.arc(point.x, point.y, this.options.thickness / 2, 0, 2 * Math.PI); ctx.fill(); }; Painter.prototype.drawLine = function drawLine(ctx, start, end) { ctx.lineWidth = this.options.thickness; ctx.lineCap = 'round'; ctx.lineJoin = 'round'; ctx.strokeStyle = 'rgba(0,0,0,1)'; ctx.globalCompositeOperation = 'destination-out'; ctx.beginPath(); ctx.moveTo(start.x, start.y); ctx.lineTo(end.x, end.y); ctx.stroke(); }; Painter.prototype.complete = function complete(ctx, width, height) { ctx.fillStyle = 'rgba(0,0,0,1)'; ctx.globalCompositeOperation = 'destination-out'; ctx.fillRect(0, 0, width, height); }; Painter.prototype.drawLayer = function drawLayer(ctx, width, height, index) {}; },{"lodash.defaults":13}],2:[function(require,module,exports){ /* jshint browserify: true */ 'use strict'; var EventEmitter = require('events').EventEmitter; var util = require('util'); var defaults = require('lodash.defaults'); var Painter = Scratchcard.Painter = require('./painter'); module.exports = exports = Scratchcard; var defaultOptions = { threshold: 255, realtime: false, layers: 0, painter: {}, animationFrame: null }; function Scratchcard(element, options) { if (isIeLessThan9()) { throw new Error('Internet Explorer not supported prior to version 9'); } EventEmitter.call(this); var self = this; var canvas = document.createElement('canvas'); if (!canvas.getContext) { throw new Error('HTML5 canvas not supported'); } var ctx = canvas.getContext('2d'); options = (options instanceof Painter) ? defaults({painter: options}, defaultOptions) : defaults({}, options, defaultOptions); var requestAnimationFrame = window.requestAnimationFrame; var animationFrame = options.animationFrame; if (animationFrame && animationFrame.request) { requestAnimationFrame = animationFrame.request.bind(animationFrame); } if (!requestAnimationFrame) { throw new Error('requestAnimationFrame not supported'); } var size = getSize(element); canvas.style.position = 'absolute'; canvas.width = size.width; canvas.height = size.height; canvas.style.zIndex = options.layers + 1; // Disable the blue overlay for some browsers canvas.style['-webkit-tap-highlight-color'] = 'rgba(0,0,0,0)'; var wrapper = document.createElement('div'); wrapper.className = 'scratchcard'; wrapper.style.position = 'relative'; wrapper.style.display = 'inline'; wrapper.style.verticalAlign = 'top'; wrapper.appendChild(canvas); var layers = []; for (var index = 0; index < options.layers; index++) { var layer = document.createElement('canvas'); layer.style.position = 'absolute'; layer.width = size.width; layer.height = size.height; layer.style.zIndex = index + 1; layer.style.pointerEvents = 'none'; layers.push({ canvas: layer, ctx: layer.getContext('2d') }); wrapper.appendChild(layer); } var painter = null; var previousFingers = {}; var previousFingersCount = 0; var currentFingers = {}; var currentFingersCount = 0; var updated = false; var progress = null; var completed = false; var animated = false; this.getElement = getElement; this.setElement = setElement; this.getPainter = getPainter; this.setPainter = setPainter; this.getWrapper = getWrapper; this.getCanvas = getCanvas; this.reset = reset; this.complete = complete; this.getProgress = getProgress; setPainter(options.painter); if (element) { element.parentNode.insertBefore(wrapper, element); element.style.visibility = 'visible'; canvas.addEventListener('mousedown', onMouseDown, true); canvas.addEventListener('touchstart', onTouchStart, true); animate(); } function getElement() { return element; } function setElement(newElement) { if (newElement) { element = newElement; synchronize(); canvas.addEventListener('mousedown', onMouseDown, true); canvas.addEventListener('touchstart', onTouchStart, true); if (!animated) { animate(); } } else if (element) { element = null; wrapper.parentNode.removeChild(wrapper); canvas.removeEventListener('mousedown', onMouseDown, true); canvas.removeEventListener('touchstart', onTouchStart, true); } } function getPainter() { return painter; } function setPainter(newPainter) { painter = (newPainter instanceof Painter) ? newPainter : new Painter(newPainter); redraw(); } function getWrapper() { return wrapper; } function getCanvas() { return canvas; } function reset() { painter.reset(ctx, canvas.width, canvas.height); updated = true; completed = false; canvas.style.pointerEvents = null; checkProgress(); } function drawPoint(point) { painter.drawPoint(ctx, point); updated = true; } function drawLine(start, end) { painter.drawLine(ctx, start, end); updated = true; } function complete() { painter.complete(ctx, canvas.width, canvas.height); updated = true; completed = true; canvas.style.pointerEvents = 'none'; checkProgress(); } function redraw() { if (completed) { painter.complete(ctx, canvas.width, canvas.height); } else { painter.reset(ctx, canvas.width, canvas.height); } updated = true; for (var index = 0, count = layers.length; index < count; index++) { var layer = layers[index]; painter.drawLayer(layer.ctx, layer.canvas.width, layer.canvas.height, index); } checkProgress(); } function getProgress() { var width = canvas.width; var height = canvas.height; var pixels = width * height; if (pixels === 0) { return 0; } var holes = 0; var data = ctx.getImageData(0, 0, width, height).data; for (var index = 3, count = data.length; index < count; index += 4) { if (data[index] >= options.threshold) { holes++; } } return (pixels - holes) / pixels; } function checkProgress() { if (!updated) { return; } var lastProgress = progress; progress = getProgress(); updated = false; if (progress !== lastProgress) { self.emit('progress', progress); if ((progress === 1) && (!completed)) { complete(); } } } function synchronize() { var parent = element.parentNode; if (!parent) { setElement(null); return; } if (wrapper.nextSibling !== element) { parent.insertBefore(wrapper, element); } var size = getSize(element); if ((canvas.width === size.width) && (canvas.height === size.height)) { return; } canvas.width = size.width; canvas.height = size.height; for (var index = 0, count = layers.length; index < count; index++) { var layer = layers[index].canvas; layer.width = size.width; layer.height = size.height; } redraw(); } function animate() { if (!element) { animated = false; return; } requestAnimationFrame(animate); animated = true; synchronize(); for (var identifier in currentFingers) { var previousFinger = previousFingers[identifier]; var currentFinger = currentFingers[identifier]; if (!previousFinger) { drawPoint(currentFinger); } else if ((currentFinger.x !== previousFinger.x) || (currentFinger.y !== previousFinger.y)) { drawLine(previousFinger, currentFinger); } } if (options.realtime || ((currentFingersCount === 0) && (previousFingersCount > 0))) { checkProgress(); } previousFingers = currentFingers; previousFingersCount = currentFingersCount; } function onMouseDown(event) { if (event.button !== 0) { return; } event.preventDefault(); // console.log('mousedown'); var boundingRect = canvas.getBoundingClientRect(); currentFingers = { mouse: { x: event.clientX - boundingRect.left, y: event.clientY - boundingRect.top } }; currentFingersCount = 1; window.addEventListener('mousemove', onMouseMove, true); window.addEventListener('mouseup', onMouseUp, true); canvas.removeEventListener('mousedown', onMouseDown, true); canvas.removeEventListener('touchstart', onTouchStart, true); } function onMouseMove(event) { if (event.button !== 0) { return; } event.preventDefault(); // console.log('mousemove'); var boundingRect = canvas.getBoundingClientRect(); currentFingers = { mouse: { x: event.clientX - boundingRect.left, y: event.clientY - boundingRect.top } }; currentFingersCount = 1; } function onMouseUp(event) { if (event.button !== 0) { return; } event.preventDefault(); // console.log('mouseup'); currentFingers = {}; currentFingersCount = 0; window.removeEventListener('mousemove', onMouseMove, true); window.removeEventListener('mouseup', onMouseUp, true); if (element) { canvas.addEventListener('mousedown', onMouseDown, true); canvas.addEventListener('touchstart', onTouchStart, true); } } function onTouchStart(event) { event.preventDefault(); // console.log('touchstart'); currentFingers = {}; currentFingersCount = event.touches.length; var boundingRect = canvas.getBoundingClientRect(); for (var index = 0; index < currentFingersCount; index++) { var touch = event.touches[index]; currentFingers[touch.identifier] = { x: touch.clientX - boundingRect.left, y: touch.clientY - boundingRect.top }; } window.addEventListener('touchstart', onTouch, true); window.addEventListener('touchmove', onTouch, true); window.addEventListener('touchend', onTouch, true); canvas.removeEventListener('mousedown', onMouseDown, true); canvas.removeEventListener('touchstart', onTouchStart, true); } function onTouch(event) { event.preventDefault(); // console.log(event.type); currentFingers = {}; currentFingersCount = event.touches.length; if (currentFingersCount > 0) { var boundingRect = canvas.getBoundingClientRect(); for (var index = 0; index < currentFingersCount; index++) { var touch = event.touches[index]; currentFingers[touch.identifier] = { x: touch.clientX - boundingRect.left, y: touch.clientY - boundingRect.top }; } } else { window.removeEventListener('touchstart', onTouch, true); window.removeEventListener('touchmove', onTouch, true); window.removeEventListener('touchend', onTouch, true); if (element) { canvas.addEventListener('mousedown', onMouseDown, true); canvas.addEventListener('touchstart', onTouchStart, true); } } } } util.inherits(Scratchcard, EventEmitter); function isIeLessThan9() { var div = document.createElement('div'); div.innerHTML = '<!--[if lt IE 9]><i></i><![endif]-->'; return (div.getElementsByTagName('i').length === 1); } var zero = {width: 0, height: 0}; function getSize(element) { if (!element) { return zero; } var rects = element.getClientRects(); if (rects.length === 0) { return zero; } var firstRect = rects[0]; return { width: Math.ceil(firstRect.right) - Math.floor(firstRect.left), height: Math.ceil(firstRect.bottom) - Math.floor(firstRect.top) }; } },{"./painter":1,"events":11,"lodash.defaults":13,"util":16}],3:[function(require,module,exports){ /* jshint browserify: true */ 'use strict'; var util = require('util'); var defaults = require('lodash.defaults'); var AnimationFrame = require('animation-frame'); var Scratchcard = require('./scratchcard'); var Painter = require('./painter'); StandaloneScratchard.Painter = Painter; module.exports = exports = StandaloneScratchard; function StandaloneScratchard(element, options) { options = (options instanceof Painter) ? {painter: options} : defaults({}, options); if (!(options.animationFrame instanceof AnimationFrame)) { options.animationFrame = new AnimationFrame(options.animationFrame); } Scratchcard.call(this, element, options); } util.inherits(StandaloneScratchard, Scratchcard); },{"./painter":1,"./scratchcard":2,"animation-frame":4,"lodash.defaults":13,"util":16}],4:[function(require,module,exports){ /** * An even better animation frame. * * @copyright Oleg Slobodskoi 2016 * @website https://github.com/kof/animationFrame * @license MIT */ module.exports = require('./lib/animation-frame') },{"./lib/animation-frame":5}],5:[function(require,module,exports){ 'use strict' var nativeImpl = require('./native') var now = require('./now') var performance = require('./performance') var root = require('./root') // Weird native implementation doesn't work if context is defined. var nativeRequest = nativeImpl.request var nativeCancel = nativeImpl.cancel /** * Animation frame constructor. * * Options: * - `useNative` use the native animation frame if possible, defaults to true * - `frameRate` pass a custom frame rate * * @param {Object|Number} options */ function AnimationFrame(options) { if (!(this instanceof AnimationFrame)) return new AnimationFrame(options) options || (options = {}) // Its a frame rate. if (typeof options == 'number') options = {frameRate: options} options.useNative != null || (options.useNative = true) this.options = options this.frameRate = options.frameRate || AnimationFrame.FRAME_RATE this._frameLength = 1000 / this.frameRate this._isCustomFrameRate = this.frameRate !== AnimationFrame.FRAME_RATE this._timeoutId = null this._callbacks = {} this._lastTickTime = 0 this._tickCounter = 0 } module.exports = AnimationFrame /** * Default frame rate used for shim implementation. Native implementation * will use the screen frame rate, but js have no way to detect it. * * If you know your target device, define it manually. * * @type {Number} * @api public */ AnimationFrame.FRAME_RATE = 60 /** * Replace the globally defined implementation or define it globally. * * @param {Object|Number} [options] * @api public */ AnimationFrame.shim = function(options) { var animationFrame = new AnimationFrame(options) root.requestAnimationFrame = function(callback) { return animationFrame.request(callback) } root.cancelAnimationFrame = function(id) { return animationFrame.cancel(id) } return animationFrame } /** * Request animation frame. * We will use the native RAF as soon as we know it does works. * * @param {Function} callback * @return {Number} timeout id or requested animation frame id * @api public */ AnimationFrame.prototype.request = function(callback) { var self = this // Alawys inc counter to ensure it never has a conflict with the native counter. // After the feature test phase we don't know exactly which implementation has been used. // Therefore on #cancel we do it for both. ++this._tickCounter if (nativeImpl.supported && this.options.useNative && !this._isCustomFrameRate) { return nativeRequest(callback) } if (!callback) throw new TypeError('Not enough arguments') if (this._timeoutId == null) { // Much faster than Math.max // http://jsperf.com/math-max-vs-comparison/3 // http://jsperf.com/date-now-vs-date-gettime/11 var delay = this._frameLength + this._lastTickTime - now() if (delay < 0) delay = 0 this._timeoutId = setTimeout(function() { self._lastTickTime = now() self._timeoutId = null ++self._tickCounter var callbacks = self._callbacks self._callbacks = {} for (var id in callbacks) { if (callbacks[id]) { if (nativeImpl.supported && self.options.useNative) { nativeRequest(callbacks[id]) } else { callbacks[id](performance.now()) } } } }, delay) } this._callbacks[this._tickCounter] = callback return this._tickCounter } /** * Cancel animation frame. * * @param {Number} timeout id or requested animation frame id * * @api public */ AnimationFrame.prototype.cancel = function(id) { if (nativeImpl.supported && this.options.useNative) nativeCancel(id) delete this._callbacks[id] } },{"./native":6,"./now":7,"./performance":9,"./root":10}],6:[function(require,module,exports){ 'use strict' var root = require('./root') // Test if we are within a foreign domain. Use raf from the top if possible. try { // Accessing .name will throw SecurityError within a foreign domain. root.top.name root = root.top } catch(e) {} exports.request = root.requestAnimationFrame exports.cancel = root.cancelAnimationFrame || root.cancelRequestAnimationFrame exports.supported = false var vendors = ['Webkit', 'Moz', 'ms', 'O'] // Grab the native implementation. for (var i = 0; i < vendors.length && !exports.request; i++) { exports.request = root[vendors[i] + 'RequestAnimationFrame'] exports.cancel = root[vendors[i] + 'CancelAnimationFrame'] || root[vendors[i] + 'CancelRequestAnimationFrame'] } // Test if native implementation works. // There are some issues on ios6 // http://shitwebkitdoes.tumblr.com/post/47186945856/native-requestanimationframe-broken-on-ios-6 // https://gist.github.com/KrofDrakula/5318048 if (exports.request) { exports.request.call(null, function() { exports.supported = true }) } },{"./root":10}],7:[function(require,module,exports){ 'use strict' /** * Crossplatform Date.now() * * @return {Number} time in ms * @api private */ module.exports = Date.now || function() { return (new Date).getTime() } },{}],8:[function(require,module,exports){ 'use strict' var now = require('./now') /** * Replacement for PerformanceTiming.navigationStart for the case when * performance.now is not implemented. * * https://developer.mozilla.org/en-US/docs/Web/API/PerformanceTiming.navigationStart * * @type {Number} * @api private */ exports.navigationStart = now() },{"./now":7}],9:[function(require,module,exports){ 'use strict' var now = require('./now') var PerformanceTiming = require('./performance-timing') var root = require('./root') /** * Crossplatform performance.now() * * https://developer.mozilla.org/en-US/docs/Web/API/Performance.now() * * @return {Number} relative time in ms * @api public */ exports.now = function () { if (root.performance && root.performance.now) return root.performance.now() return now() - PerformanceTiming.navigationStart } },{"./now":7,"./performance-timing":8,"./root":10}],10:[function(require,module,exports){ var root // Browser window if (typeof window !== 'undefined') { root = window // Web Worker } else if (typeof self !== 'undefined') { root = self // Other environments } else { root = this } module.exports = root },{}],11:[function(require,module,exports){ // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to permit // persons to whom the Software is furnished to do so, subject to the // following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. function EventEmitter() { this._events = this._events || {}; this._maxListeners = this._maxListeners || undefined; } module.exports = EventEmitter; // Backwards-compat with node 0.10.x EventEmitter.EventEmitter = EventEmitter; EventEmitter.prototype._events = undefined; EventEmitter.prototype._maxListeners = undefined; // By default EventEmitters will print a warning if more than 10 listeners are // added to it. This is a useful default which helps finding memory leaks. EventEmitter.defaultMaxListeners = 10; // Obviously not all Emitters should be limited to 10. This function allows // that to be increased. Set to zero for unlimited. EventEmitter.prototype.setMaxListeners = function(n) { if (!isNumber(n) || n < 0 || isNaN(n)) throw TypeError('n must be a positive number'); this._maxListeners = n; return this; }; EventEmitter.prototype.emit = function(type) { var er, handler, len, args, i, listeners; if (!this._events) this._events = {}; // If there is no 'error' event listener then throw. if (type === 'error') { if (!this._events.error || (isObject(this._events.error) && !this._events.error.length)) { er = arguments[1]; if (er instanceof Error) { throw er; // Unhandled 'error' event } else { // At least give some kind of context to the user var err = new Error('Uncaught, unspecified "error" event. (' + er + ')'); err.context = er; throw err; } } } handler = this._events[type]; if (isUndefined(handler)) return false; if (isFunction(handler)) { switch (arguments.length) { // fast cases case 1: handler.call(this); break; case 2: handler.call(this, arguments[1]); break; case 3: handler.call(this, arguments[1], arguments[2]); break; // slower default: args = Array.prototype.slice.call(arguments, 1); handler.apply(this, args); } } else if (isObject(handler)) { args = Array.prototype.slice.call(arguments, 1); listeners = handler.slice(); len = listeners.length; for (i = 0; i < len; i++) listeners[i].apply(this, args); } return true; }; EventEmitter.prototype.addListener = function(type, listener) { var m; if (!isFunction(listener)) throw TypeError('listener must be a function'); if (!this._events) this._events = {}; // To avoid recursion in the case that type === "newListener"! Before // adding it to the listeners, first emit "newListener". if (this._events.newListener) this.emit('newListener', type, isFunction(listener.listener) ? listener.listener : listener); if (!this._events[type]) // Optimize the case of one listener. Don't need the extra array object. this._events[type] = listener; else if (isObject(this._events[type])) // If we've already got an array, just append. this._events[type].push(listener); else // Adding the second element, need to change to array. this._events[type] = [this._events[type], listener]; // Check for listener leak if (isObject(this._events[type]) && !this._events[type].warned) { if (!isUndefined(this._maxListeners)) { m = this._maxListeners; } else { m = EventEmitter.defaultMaxListeners; } if (m && m > 0 && this._events[type].length > m) { this._events[type].warned = true; console.error('(node) warning: possible EventEmitter memory ' + 'leak detected. %d listeners added. ' + 'Use emitter.setMaxListeners() to increase limit.', this._events[type].length); if (typeof console.trace === 'function') { // not supported in IE 10 console.trace(); } } } return this; }; EventEmitter.prototype.on = EventEmitter.prototype.addListener; EventEmitter.prototype.once = function(type, listener) { if (!isFunction(listener)) throw TypeError('listener must be a function'); var fired = false; function g() { this.removeListener(type, g); if (!fired) { fired = true; listener.apply(this, arguments); } } g.listener = listener; this.on(type, g); return this; }; // emits a 'removeListener' event iff the listener was removed EventEmitter.prototype.removeListener = function(type, listener) { var list, position, length, i; if (!isFunction(listener)) throw TypeError('listener must be a function'); if (!this._events || !this._events[type]) return this; list = this._events[type]; length = list.length; position = -1; if (list === listener || (isFunction(list.listener) && list.listener === listener)) { delete this._events[type]; if (this._events.removeListener) this.emit('removeListener', type, listener); } else if (isObject(list)) { for (i = length; i-- > 0;) { if (list[i] === listener || (list[i].listener && list[i].listener === listener)) { position = i; break; } } if (position < 0) return this; if (list.length === 1) { list.length = 0; delete this._events[type]; } else { list.splice(position, 1); } if (this._events.removeListener) this.emit('removeListener', type, listener); } return this; }; EventEmitter.prototype.removeAllListeners = function(type) { var key, listeners; if (!this._events) return this; // not listening for removeListener, no need to emit if (!this._events.removeListener) { if (arguments.length === 0) this._events = {}; else if (this._events[type]) delete this._events[type]; return this; } // emit removeListener for all listeners on all events if (arguments.length === 0) { for (key in this._events) { if (key === 'removeListener') continue; this.removeAllListeners(key); } this.removeAllListeners('removeListener'); this._events = {}; return this; } listeners = this._events[type]; if (isFunction(listeners)) { this.removeListener(type, listeners); } else if (listeners) { // LIFO order while (listeners.length) this.removeListener(type, listeners[listeners.length - 1]); } delete this._events[type]; return this; }; EventEmitter.prototype.listeners = function(type) { var ret; if (!this._events || !this._events[type]) ret = []; else if (isFunction(this._events[type])) ret = [this._events[type]]; else ret = this._events[type].slice(); return ret; }; EventEmitter.prototype.listenerCount = function(type) { if (this._events) { var evlistener = this._events[type]; if (isFunction(evlistener)) return 1; else if (evlistener) return evlistener.length; } return 0; }; EventEmitter.listenerCount = function(emitter, type) { return emitter.listenerCount(type); }; function isFunction(arg) { return typeof arg === 'function'; } function isNumber(arg) { return typeof arg === 'number'; } function isObject(arg) { return typeof arg === 'object' && arg !== null; } function isUndefined(arg) { return arg === void 0; } },{}],12:[function(require,module,exports){ if (typeof Object.create === 'function') { // implementation from standard node.js 'util' module module.exports = function inherits(ctor, superCtor) { ctor.super_ = superCtor ctor.prototype = Object.create(superCtor.prototype, { constructor: { value: ctor, enumerable: false, writable: true, configurable: true } }); }; } else { // old school shim for old browsers module.exports = function inherits(ctor, superCtor) { ctor.super_ = superCtor var TempCtor = function () {} TempCtor.prototype = superCtor.prototype ctor.prototype = new TempCtor() ctor.prototype.constructor = ctor } } },{}],13:[function(require,module,exports){ (function (global){ /** * lodash (Custom Build) <https://lodash.com/> * Build: `lodash modularize exports="npm" -o ./` * Copyright jQuery Foundation and other contributors <https://jquery.org/> * Released under MIT license <https://lodash.com/license> * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE> * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors */ /** Used as references for various `Number` constants. */ var MAX_SAFE_INTEGER = 9007199254740991; /** `Object#toString` result references. */ var argsTag = '[object Arguments]', funcTag = '[object Function]', genTag = '[object GeneratorFunction]', stringTag = '[object String]'; /** Used to detect unsigned integer values. */ var reIsUint = /^(?:0|[1-9]\d*)$/; /** Detect free variable `global` from Node.js. */ var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; /** Detect free variable `self`. */ var freeSelf = typeof self == 'object' && self && self.Object === Object && self; /** Used as a reference to the global object. */ var root = freeGlobal || freeSelf || Function('return this')(); /** * A faster alternative to `Function#apply`, this function invokes `func` * with the `this` binding of `thisArg` and the arguments of `args`. * * @private * @param {Function} func The function to invoke. * @param {*} thisArg The `this` binding of `func`. * @param {Array} args The arguments to invoke `func` with. * @returns {*} Returns the result of `func`. */ function apply(func, thisArg, args) { switch (args.length) { case 0: return func.call(thisArg); case 1: return func.call(thisArg, args[0]); case 2: return func.call(thisArg, args[0], args[1]); case 3: return func.call(thisArg, args[0], args[1], args[2]); } return func.apply(thisArg, args); } /** * The base implementation of `_.property` without support for deep paths. * * @private * @param {string} key The key of the property to get. * @returns {Function} Returns the new accessor function. */ function baseProperty(key) { return function(object) { return object == null ? undefined : object[key]; }; } /** * The base implementation of `_.times` without support for iteratee shorthands * or max array length checks. * * @private * @param {number} n The number of times to invoke `iteratee`. * @param {Function} iteratee The function invoked per iteration. * @returns {Array} Returns the array of results. */ function baseTimes(n, iteratee) { var index = -1, result = Array(n); while (++index < n) { result[index] = iteratee(index); } return result; } /** * Converts `iterator` to an array. * * @private * @param {Object} iterator The iterator to convert. * @returns {Array} Returns the converted array. */ function iteratorToArray(iterator) { var data, result = []; while (!(data = iterator.next()).done) { result.push(data.value); } return result; } /** Used for built-in method references. */ var objectProto = Object.prototype; /** Used to check objects for own properties. */ var hasOwnProperty = objectProto.hasOwnProperty; /** * Used to resolve the * [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring) * of values. */ var objectToString = objectProto.toString; /** Built-in value references. */ var Reflect = root.Reflect, enumerate = Reflect ? Reflect.enumerate : undefined, propertyIsEnumerable = objectProto.propertyIsEnumerable; /* Built-in method references for those with the same name as other `lodash` methods. */ var nativeMax = Math.max; /** * Used by `_.defaults` to customize its `_.assignIn` use. * * @private * @param {*} objValue The destination value. * @param {*} srcValue The source value. * @param {string} key The key of the property to assign. * @param {Object} object The parent object of `objValue`. * @returns {*} Returns the value to assign. */ function assignInDefaults(objValue, srcValue, key, object) { if (objValue === undefined || (eq(objValue, objectProto[key]) && !hasOwnProperty.call(object, key))) { return srcValue; } return objValue; } /** * Assigns `value` to `key` of `object` if the existing value is not equivalent * using [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) * for equality comparisons. * * @private * @param {Object} object The object to modify. * @param {string} key The key of the property to assign. * @param {*} value The value to assign. */ function assignValue(object, key, value) { var objValue = object[key]; if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) || (value === undefined && !(key in object))) { object[key] = value; } } /** * The base implementation of `_.keysIn` which doesn't skip the constructor * property of prototypes or treat sparse arrays as dense. * * @private * @param {Object} object The object to query. * @returns {Array} Returns the array of property names. */ function baseKeysIn(object) { object = object == null ? object : Object(object); var result = []; for (var key in object) { result.push(key); } return result; } // Fallback for IE < 9 with es6-shim. if (enumerate && !propertyIsEnumerable.call({ 'valueOf': 1 }, 'valueOf')) { baseKeysIn = function(object) { return iteratorToArray(enumerate(object)); }; } /** * The base implementation of `_.rest` which doesn't validate or coerce arguments. * * @private * @param {Function} func The function to apply a rest parameter to. * @param {number} [start=func.length-1] The start position of the rest parameter. * @returns {Function} Returns the new function. */ function baseRest(func, start) { start = nativeMax(start === undefined ? (func.length - 1) : start, 0); return function() { var args = arguments, index = -1, length = nativeMax(args.length - start, 0), array = Array(length); while (++index < length) { array[index] = args[start + index]; } index = -1; var otherArgs = Array(start + 1); while (++index < start) { otherArgs[index] = args[index]; } otherArgs[start] = array; return apply(func, this, otherArgs); }; } /** * Copies properties of `source` to `object`. * * @private * @param {Object} source The object to copy properties from. * @param {Array} props The property identifiers to copy. * @param {Object} [object={}] The object to copy properties to. * @param {Function} [customizer] The function to customize copied values. * @returns {Object} Returns `object`. */ function copyObject(source, props, object, customizer) { object || (object = {}); var index = -1, length = props.length; while (++index < length) { var key = props[index]; var newValue = customizer ? customizer(object[key], source[key], key, object, source) : undefined; assignValue(object, key, newValue === undefined ? source[key] : newValue); } return object; } /** * Creates a function like `_.assign`. * * @private * @param {Function} assigner The function to assign values. * @returns {Function} Returns the new assigner function. */ function createAssigner(assigner) { return baseRest(function(object, sources) { var index = -1, length = sources.length, customizer = length > 1 ? sources[length - 1] : undefined, guard = length > 2 ? sources[2] : undefined; customizer = (assigner.length > 3 && typeof customizer == 'function') ? (length--, customizer) : undefined; if (guard && isIterateeCall(sources[0], sources[1], guard)) { customizer = length < 3 ? undefined : customizer; length = 1; } object = Object(object); while (++index < length) { var source = sources[index]; if (source) { assigner(object, source, index, customizer); } } return object; }); } /** * Gets the "length" property value of `object`. * * **Note:** This function is used to avoid a * [JIT bug](https://bugs.webkit.org/show_bug.cgi?id=142792) that affects * Safari on at least iOS 8.1-8.3 ARM64. * * @private * @param {Object} object The object to query. * @returns {*} Returns the "length" value. */ var getLength = baseProperty('length'); /** * Creates an array of index keys for `object` values of arrays, * `arguments` objects, and strings, otherwise `null` is returned. * * @private * @param {Object} object The object to query. * @returns {Array|null} Returns index keys, else `null`. */ function indexKeys(object) { var length = object ? object.length : undefined; if (isLength(length) && (isArray(object) || isString(object) || isArguments(object))) { return baseTimes(length, String); } return null; } /** * Checks if `value` is a valid array-like index. * * @private * @param {*} value The value to check. * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index. * @returns {boolean} Returns `true` if `value` is a valid index, else `false`. */ function isIndex(value, length) { length = length == null ? MAX_SAFE_INTEGER : length; return !!length && (typeof value == 'number' || reIsUint.test(value)) && (value > -1 && value % 1 == 0 && value < length); } /** * Checks if the given arguments are from an iteratee call. * * @private * @param {*} value The potential iteratee value argument. * @param {*} index The potential iteratee index or key argument. * @param {*} object The potential iteratee object argument. * @returns {boolean} Returns `true` if the arguments are from an iteratee call, * else `false`. */ function isIterateeCall(value, index, object) { if (!isObject(object)) { return false; } var type = typeof index; if (type == 'number' ? (isArrayLike(object) && isIndex(index, object.length)) : (type == 'string' && index in object) ) { return eq(object[index], value); } return false; } /** * Checks if `value` is likely a prototype object. * * @private * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a prototype, else `false`. */ function isPrototype(value) { var Ctor = value && value.constructor, proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto; return value === proto; } /** * Performs a * [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) * comparison between two values to determine if they are equivalent. * * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {*} value The value to compare. * @param {*} other The other value to compare. * @returns {boolean} Returns `true` if the values are equivalent, else `false`. * @example * * var object = { 'a': 1 }; * var other = { 'a': 1 }; * * _.eq(object, object); * // => true * * _.eq(object, other); * // => false * * _.eq('a', 'a'); * // => true * * _.eq('a', Object('a')); * // => false * * _.eq(NaN, NaN); * // => true */ function eq(value, other) { return value === other || (value !== value && other !== other); } /** * Checks if `value` is likely an `arguments` object. * * @static * @memberOf _ * @since 0.1.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is an `arguments` object, * else `false`. * @example * * _.isArguments(function() { return arguments; }()); * // => true * * _.isArguments([1, 2, 3]); * // => false */ function isArguments(value) { // Safari 8.1 incorrectly makes `arguments.callee` enumerable in strict mode. return isArrayLikeObject(value) && hasOwnProperty.call(value, 'callee') && (!propertyIsEnumerable.call(value, 'callee') || objectToString.call(value) == argsTag); } /** * Checks if `value` is classified as an `Array` object. * * @static * @memberOf _ * @since 0.1.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is an array, else `false`. * @example * * _.isArray([1, 2, 3]); * // => true * * _.isArray(document.body.children); * // => false * * _.isArray('abc'); * // => false * * _.isArray(_.noop); * // => false */ var isArray = Array.isArray; /** * Checks if `value` is array-like. A value is considered array-like if it's * not a function and has a `value.length` that's an integer greater than or * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`. * * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is array-like, else `false`. * @example * * _.isArrayLike([1, 2, 3]); * // => true * * _.isArrayLike(document.body.children); * // => true * * _.isArrayLike('abc'); * // => true * * _.isArrayLike(_.noop); * // => false */ function isArrayLike(value) { return value != null && isLength(getLength(value)) && !isFunction(value); } /** * This method is like `_.isArrayLike` except that it also checks if `value` * is an object. * * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is an array-like object, * else `false`. * @example * * _.isArrayLikeObject([1, 2, 3]); * // => true * * _.isArrayLikeObject(document.body.children); * // => true * * _.isArrayLikeObject('abc'); * // => false * * _.isArrayLikeObject(_.noop); * // => false */ function isArrayLikeObject(value) { return isObjectLike(value) && isArrayLike(value); } /** * Checks if `value` is classified as a `Function` object. * * @static * @memberOf _ * @since 0.1.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a function, else `false`. * @example * * _.isFunction(_); * // => true * * _.isFunction(/abc/); * // => false */ function isFunction(value) { // The use of `Object#toString` avoids issues with the `typeof` operator // in Safari 8 which returns 'object' for typed array and weak map constructors, // and PhantomJS 1.9 which returns 'function' for `NodeList` instances. var tag = isObject(value) ? objectToString.call(value) : ''; return tag == funcTag || tag == genTag; } /** * Checks if `value` is a valid array-like length. * * **Note:** This function is loosely based on * [`ToLength`](http://ecma-international.org/ecma-262/6.0/#sec-tolength). * * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a valid length, * else `false`. * @example * * _.isLength(3); * // => true * * _.isLength(Number.MIN_VALUE); * // => false * * _.isLength(Infinity); * // => false * * _.isLength('3'); * // => false */ function isLength(value) { return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; } /** * Checks if `value` is the * [language type](http://www.ecma-international.org/ecma-262/6.0/#sec-ecmascript-language-types) * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) * * @static * @memberOf _ * @since 0.1.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is an object, else `false`. * @example * * _.isObject({}); * // => true * * _.isObject([1, 2, 3]); * // => true * * _.isObject(_.noop); * // => true * * _.isObject(null); * // => false */ function isObject(value) { var type = typeof value; return !!value && (type == 'object' || type == 'function'); } /** * Checks if `value` is object-like. A value is object-like if it's not `null` * and has a `typeof` result of "object". * * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is object-like, else `false`. * @example * * _.isObjectLike({}); * // => true * * _.isObjectLike([1, 2, 3]); * // => true * * _.isObjectLike(_.noop); * // => false * * _.isObjectLike(null); * // => false */ function isObjectLike(value) { return !!value && typeof value == 'object'; } /** * Checks if `value` is classified as a `String` primitive or object. * * @static * @since 0.1.0 * @memberOf _ * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a string, else `false`. * @example * * _.isString('abc'); * // => true * * _.isString(1); * // => false */ function isString(value) { return typeof value == 'string' || (!isArray(value) && isObjectLike(value) && objectToString.call(value) == stringTag); } /** * This method is like `_.assignIn` except that it accepts `customizer` * which is invoked to produce the assigned values. If `customizer` returns * `undefined`, assignment is handled by the method instead. The `customizer` * is invoked with five arguments: (objValue, srcValue, key, object, source). * * **Note:** This method mutates `object`. * * @static * @memberOf _ * @since 4.0.0 * @alias extendWith * @category Object * @param {Object} object The destination object. * @param {...Object} sources The source objects. * @param {Function} [customizer] The function to customize assigned values. * @returns {Object} Returns `object`. * @see _.assignWith * @example * * function customizer(objValue, srcValue) { * return _.isUndefined(objValue) ? srcValue : objValue; * } * * var defaults = _.partialRight(_.assignInWith, customizer); * * defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 }); * // => { 'a': 1, 'b': 2 } */ var assignInWith = createAssigner(function(object, source, srcIndex, customizer) { copyObject(source, keysIn(source), object, customizer); }); /** * Assigns own and inherited enumerable string keyed properties of source * objects to the destination object for all destination properties that * resolve to `undefined`. Source objects are applied from left to right. * Once a property is set, additional values of the same property are ignored. * * **Note:** This method mutates `object`. * * @static * @since 0.1.0 * @memberOf _ * @category Object * @param {Object} object The destination object. * @param {...Object} [sources] The source objects. * @returns {Object} Returns `object`. * @see _.defaultsDeep * @example * * _.defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 }); * // => { 'a': 1, 'b': 2 } */ var defaults = baseRest(function(args) { args.push(undefined, assignInDefaults); return apply(assignInWith, undefined, args); }); /** * Creates an array of the own and inherited enumerable property names of `object`. * * **Note:** Non-object values are coerced to objects. * * @static * @memberOf _ * @since 3.0.0 * @category Object * @param {Object} object The object to query. * @returns {Array} Returns the array of property names. * @example * * function Foo() { * this.a = 1; * this.b = 2; * } * * Foo.prototype.c = 3; * * _.keysIn(new Foo); * // => ['a', 'b', 'c'] (iteration order is not guaranteed) */ function keysIn(object) { var index = -1, isProto = isPrototype(object), props = baseKeysIn(object), propsLength = props.length, indexes = indexKeys(object), skipIndexes = !!indexes, result = indexes || [], length = result.length; while (++index < propsLength) { var key = props[index]; if (!(skipIndexes && (key == 'length' || isIndex(key, length))) && !(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) { result.push(key); } } return result; } module.exports = defaults; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{}],14:[function(require,module,exports){ // shim for using process in browser var process = module.exports = {}; // cached from whatever global is present so that test runners that stub it // don't break things. But we need to wrap it in a try catch in case it is // wrapped in strict mode code which doesn't define any globals. It's inside a // function because try/catches deoptimize in certain engines. var cachedSetTimeout; var cachedClearTimeout; (function () { try { cachedSetTimeout = setTimeout; } catch (e) { cachedSetTimeout = function () { throw new Error('setTimeout is not defined'); } } try { cachedClearTimeout = clearTimeout; } catch (e) { cachedClearTimeout = function () { throw new Error('clearTimeout is not defined'); } } } ()) function runTimeout(fun) { if (cachedSetTimeout === setTimeout) { //normal enviroments in sane situations return setTimeout(fun, 0); } try { // when when somebody has screwed with setTimeout but no I.E. maddness return cache