Skip to content

Instantly share code, notes, and snippets.

@digitarald
Last active August 29, 2015 14:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save digitarald/11152632 to your computer and use it in GitHub Desktop.
Save digitarald/11152632 to your computer and use it in GitHub Desktop.
famo.us benchmark, 99 surfaces rotated by easing
<!DOCTYPE HTML>
<html>
<head>
<title>Famous test</title>
<meta name="viewport" content="width=device-width, maximum-scale=1, user-scalable=no" />
<meta name="mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
</head>
<body>
<script type="text/javascript" src="./main.bundle.js"></script>
</body>
</html>
/******/ (function(modules) { // webpackBootstrap
/******/
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
/******/
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ exports: {},
/******/ id: moduleId,
/******/ loaded: false
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.loaded = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
__webpack_require__(7);
var _ = __webpack_require__(6);
// import dependencies
var Engine = __webpack_require__(1);
var Transform = __webpack_require__(2);
var ImageSurface = __webpack_require__(3);
// var Modifier = require('famous/modifiers/Modifier');
var StateModifier = __webpack_require__(4);
var Easing = __webpack_require__(5);
// create the main context
var mainContext = Engine.createContext();
// your app here
var startPos = Transform.rotateZ(0);
var endPos = Transform.rotateZ(Math.PI);
var easeTransition = {
duration: 2500,
curve: Easing.inOutCubic
};
var transforms = _.times(99, function() {
var logo = new ImageSurface({
size: [200, 200],
content: 'https://raw.githubusercontent.com/Famous/generator-famous/master/app/templates/images/_famous_logo.png'
});
var logoModifier = new StateModifier({
origin: [Math.random(), Math.random()]
});
var transform = new StateModifier({
transform: startPos
});
mainContext.add(logoModifier).add(transform).add(logo);
return transform;
});
var to = false;
function loop() {
transforms.forEach(function(transform) {
transform.setTransform(to ? startPos : endPos, easeTransition, loop);
to = !to;
});
};
loop();
/***/ },
/* 1 */
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_RESULT__;/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Owner: mark@famo.us
* @license MPL 2.0
* @copyright Famous Industries, Inc. 2014
*/
!(__WEBPACK_AMD_DEFINE_RESULT__ = (function(require, exports, module) {
/**
* The singleton object initiated upon process
* startup which manages all active Context instances, runs
* the render dispatch loop, and acts as a listener and dispatcher
* for events. All methods are therefore static.
*
* On static initialization, window.requestAnimationFrame is called with
* the event loop function.
*
* Note: Any window in which Engine runs will prevent default
* scrolling behavior on the 'touchmove' event.
*
* @static
* @class Engine
*/
var Context = __webpack_require__(9);
var EventHandler = __webpack_require__(10);
var OptionsManager = __webpack_require__(11);
var Engine = {};
var contexts = [];
var nextTickQueue = [];
var deferQueue = [];
var lastTime = Date.now();
var frameTime;
var frameTimeLimit;
var loopEnabled = true;
var eventForwarders = {};
var eventHandler = new EventHandler();
var options = {
containerType: 'div',
containerClass: 'famous-container',
fpsCap: undefined,
runLoop: true
};
var optionsManager = new OptionsManager(options);
/** @const */
var MAX_DEFER_FRAME_TIME = 10;
/**
* Inside requestAnimationFrame loop, step() is called, which:
* calculates current FPS (throttling loop if it is over limit set in setFPSCap),
* emits dataless 'prerender' event on start of loop,
* calls in order any one-shot functions registered by nextTick on last loop,
* calls Context.update on all Context objects registered,
* and emits dataless 'postrender' event on end of loop.
*
* @static
* @private
* @method step
*/
Engine.step = function step() {
var currentTime = Date.now();
// skip frame if we're over our framerate cap
if (frameTimeLimit && currentTime - lastTime < frameTimeLimit) return;
var i = 0;
frameTime = currentTime - lastTime;
lastTime = currentTime;
eventHandler.emit('prerender');
// empty the queue
for (i = 0; i < nextTickQueue.length; i++) nextTickQueue[i].call(this);
nextTickQueue.splice(0);
// limit total execution time for deferrable functions
while (deferQueue.length && (Date.now() - currentTime) < MAX_DEFER_FRAME_TIME) {
deferQueue.shift().call(this);
}
for (i = 0; i < contexts.length; i++) contexts[i].update();
eventHandler.emit('postrender');
};
// engage requestAnimationFrame
function loop() {
if (options.runLoop) {
Engine.step();
requestAnimationFrame(loop);
}
else loopEnabled = false;
}
requestAnimationFrame(loop);
//
// Upon main document window resize (unless on an "input" HTML element):
// scroll to the top left corner of the window,
// and for each managed Context: emit the 'resize' event and update its size.
// @param {Object=} event document event
//
function handleResize(event) {
if (document.activeElement && document.activeElement.nodeName === 'INPUT') {
document.activeElement.addEventListener('blur', function deferredResize() {
this.removeEventListener('blur', deferredResize);
handleResize(event);
});
return;
}
window.scrollTo(0, 0);
for (var i = 0; i < contexts.length; i++) {
contexts[i].emit('resize');
}
eventHandler.emit('resize');
}
window.addEventListener('resize', handleResize, false);
handleResize();
// prevent scrolling via browser
window.addEventListener('touchmove', function(event) {
event.preventDefault();
}, true);
/**
* Add event handler object to set of downstream handlers.
*
* @method pipe
*
* @param {EventHandler} target event handler target object
* @return {EventHandler} passed event handler
*/
Engine.pipe = function pipe(target) {
if (target.subscribe instanceof Function) return target.subscribe(Engine);
else return eventHandler.pipe(target);
};
/**
* Remove handler object from set of downstream handlers.
* Undoes work of "pipe".
*
* @method unpipe
*
* @param {EventHandler} target target handler object
* @return {EventHandler} provided target
*/
Engine.unpipe = function unpipe(target) {
if (target.unsubscribe instanceof Function) return target.unsubscribe(Engine);
else return eventHandler.unpipe(target);
};
/**
* Bind a callback function to an event type handled by this object.
*
* @static
* @method "on"
*
* @param {string} type event type key (for example, 'click')
* @param {function(string, Object)} handler callback
* @return {EventHandler} this
*/
Engine.on = function on(type, handler) {
if (!(type in eventForwarders)) {
eventForwarders[type] = eventHandler.emit.bind(eventHandler, type);
document.body.addEventListener(type, eventForwarders[type]);
}
return eventHandler.on(type, handler);
};
/**
* Trigger an event, sending to all downstream handlers
* listening for provided 'type' key.
*
* @method emit
*
* @param {string} type event type key (for example, 'click')
* @param {Object} event event data
* @return {EventHandler} this
*/
Engine.emit = function emit(type, event) {
return eventHandler.emit(type, event);
};
/**
* Unbind an event by type and handler.
* This undoes the work of "on".
*
* @static
* @method removeListener
*
* @param {string} type event type key (for example, 'click')
* @param {function} handler function object to remove
* @return {EventHandler} internal event handler object (for chaining)
*/
Engine.removeListener = function removeListener(type, handler) {
return eventHandler.removeListener(type, handler);
};
/**
* Return the current calculated frames per second of the Engine.
*
* @static
* @method getFPS
*
* @return {Number} calculated fps
*/
Engine.getFPS = function getFPS() {
return 1000 / frameTime;
};
/**
* Set the maximum fps at which the system should run. If internal render
* loop is called at a greater frequency than this FPSCap, Engine will
* throttle render and update until this rate is achieved.
*
* @static
* @method setFPSCap
*
* @param {Number} fps maximum frames per second
*/
Engine.setFPSCap = function setFPSCap(fps) {
frameTimeLimit = Math.floor(1000 / fps);
};
/**
* Return engine options.
*
* @static
* @method getOptions
* @param {string} key
* @return {Object} engine options
*/
Engine.getOptions = function getOptions() {
return optionsManager.getOptions.apply(optionsManager, arguments);
};
/**
* Set engine options
*
* @static
* @method setOptions
*
* @param {Object} [options] overrides of default options
* @param {Number} [options.fpsCap] maximum fps at which the system should run
* @param {boolean} [options.runLoop=true] whether the run loop should continue
* @param {string} [options.containerType="div"] type of container element. Defaults to 'div'.
* @param {string} [options.containerClass="famous-container"] type of container element. Defaults to 'famous-container'.
*/
Engine.setOptions = function setOptions(options) {
return optionsManager.setOptions.apply(optionsManager, arguments);
};
/**
* Creates a new Context for rendering and event handling with
* provided document element as top of each tree. This will be tracked by the
* process-wide Engine.
*
* @static
* @method createContext
*
* @param {Node} el will be top of Famo.us document element tree
* @return {Context} new Context within el
*/
Engine.createContext = function createContext(el) {
if (el === undefined) {
el = document.createElement(options.containerType);
el.classList.add(options.containerClass);
document.body.appendChild(el);
}
else if (!(el instanceof Element)) {
el = document.createElement(options.containerType);
throw new Error('Tried to create context on non-existent element');
}
var context = new Context(el);
Engine.registerContext(context);
return context;
};
/**
* Registers an existing context to be updated within the run loop.
*
* @static
* @method registerContext
*
* @param {Context} context Context to register
* @return {FamousContext} provided context
*/
Engine.registerContext = function registerContext(context) {
contexts.push(context);
return context;
};
/**
* Queue a function to be executed on the next tick of the
* Engine.
*
* @static
* @method nextTick
*
* @param {function(Object)} fn function accepting window object
*/
Engine.nextTick = function nextTick(fn) {
nextTickQueue.push(fn);
};
/**
* Queue a function to be executed sometime soon, at a time that is
* unlikely to affect frame rate.
*
* @static
* @method defer
*
* @param {Function} fn
*/
Engine.defer = function defer(fn) {
deferQueue.push(fn);
};
optionsManager.on('change', function(data) {
if (data.id === 'fpsCap') Engine.setFPSCap(data.value);
else if (data.id === 'runLoop') {
// kick off the loop only if it was stopped
if (!loopEnabled && data.value) {
loopEnabled = true;
requestAnimationFrame(loop);
}
}
});
module.exports = Engine;
}.call(exports, __webpack_require__, exports, module)), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
/***/ },
/* 2 */
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_RESULT__;/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Owner: mark@famo.us
* @license MPL 2.0
* @copyright Famous Industries, Inc. 2014
*/
!(__WEBPACK_AMD_DEFINE_RESULT__ = (function(require, exports, module) {
/**
* A high-performance static matrix math library used to calculate
* affine transforms on surfaces and other renderables.
* Famo.us uses 4x4 matrices corresponding directly to
* WebKit matrices (column-major order).
*
* The internal "type" of a Matrix is a 16-long float array in
* row-major order, with:
* elements [0],[1],[2],[4],[5],[6],[8],[9],[10] forming the 3x3
* transformation matrix;
* elements [12], [13], [14] corresponding to the t_x, t_y, t_z
* translation;
* elements [3], [7], [11] set to 0;
* element [15] set to 1.
* All methods are static.
*
* @static
*
* @class Transform
*/
var Transform = {};
// WARNING: these matrices correspond to WebKit matrices, which are
// transposed from their math counterparts
Transform.precision = 1e-6;
Transform.identity = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
/**
* Multiply two or more Transform matrix types to return a Transform matrix.
*
* @method multiply4x4
* @static
* @param {Transform} a left matrix
* @param {Transform} b right matrix
* @return {Transform} the resulting matrix
*/
Transform.multiply4x4 = function multiply4x4(a, b) {
return [
a[0] * b[0] + a[4] * b[1] + a[8] * b[2] + a[12] * b[3],
a[1] * b[0] + a[5] * b[1] + a[9] * b[2] + a[13] * b[3],
a[2] * b[0] + a[6] * b[1] + a[10] * b[2] + a[14] * b[3],
a[3] * b[0] + a[7] * b[1] + a[11] * b[2] + a[15] * b[3],
a[0] * b[4] + a[4] * b[5] + a[8] * b[6] + a[12] * b[7],
a[1] * b[4] + a[5] * b[5] + a[9] * b[6] + a[13] * b[7],
a[2] * b[4] + a[6] * b[5] + a[10] * b[6] + a[14] * b[7],
a[3] * b[4] + a[7] * b[5] + a[11] * b[6] + a[15] * b[7],
a[0] * b[8] + a[4] * b[9] + a[8] * b[10] + a[12] * b[11],
a[1] * b[8] + a[5] * b[9] + a[9] * b[10] + a[13] * b[11],
a[2] * b[8] + a[6] * b[9] + a[10] * b[10] + a[14] * b[11],
a[3] * b[8] + a[7] * b[9] + a[11] * b[10] + a[15] * b[11],
a[0] * b[12] + a[4] * b[13] + a[8] * b[14] + a[12] * b[15],
a[1] * b[12] + a[5] * b[13] + a[9] * b[14] + a[13] * b[15],
a[2] * b[12] + a[6] * b[13] + a[10] * b[14] + a[14] * b[15],
a[3] * b[12] + a[7] * b[13] + a[11] * b[14] + a[15] * b[15]
];
};
/**
* Fast-multiply two or more Transform matrix types to return a
* Matrix, assuming bottom row on each is [0 0 0 1].
*
* @method multiply
* @static
* @param {Transform} a left matrix
* @param {Transform} b right matrix
* @return {Transform} the resulting matrix
*/
Transform.multiply = function multiply(a, b) {
return [
a[0] * b[0] + a[4] * b[1] + a[8] * b[2],
a[1] * b[0] + a[5] * b[1] + a[9] * b[2],
a[2] * b[0] + a[6] * b[1] + a[10] * b[2],
0,
a[0] * b[4] + a[4] * b[5] + a[8] * b[6],
a[1] * b[4] + a[5] * b[5] + a[9] * b[6],
a[2] * b[4] + a[6] * b[5] + a[10] * b[6],
0,
a[0] * b[8] + a[4] * b[9] + a[8] * b[10],
a[1] * b[8] + a[5] * b[9] + a[9] * b[10],
a[2] * b[8] + a[6] * b[9] + a[10] * b[10],
0,
a[0] * b[12] + a[4] * b[13] + a[8] * b[14] + a[12],
a[1] * b[12] + a[5] * b[13] + a[9] * b[14] + a[13],
a[2] * b[12] + a[6] * b[13] + a[10] * b[14] + a[14],
1
];
};
/**
* Return a Transform translated by additional amounts in each
* dimension. This is equivalent to the result of
*
* Matrix.multiply(Matrix.translate(t[0], t[1], t[2]), m).
*
* @method thenMove
* @static
* @param {Transform} m a matrix
* @param {Array.Number} t floats delta vector of length 2 or 3
* @return {Transform} the resulting translated matrix
*/
Transform.thenMove = function thenMove(m, t) {
if (!t[2]) t[2] = 0;
return [m[0], m[1], m[2], 0, m[4], m[5], m[6], 0, m[8], m[9], m[10], 0, m[12] + t[0], m[13] + t[1], m[14] + t[2], 1];
};
/**
* Return a Transform atrix which represents the result of a transform matrix
* applied after a move. This is faster than the equivalent multiply.
* This is equivalent to the result of:
*
* Transform.multiply(m, Transform.translate(t[0], t[1], t[2])).
*
* @method moveThen
* @static
* @param {Array.Number} v vector representing initial movement
* @param {Transform} m matrix to apply afterwards
* @return {Transform} the resulting matrix
*/
Transform.moveThen = function moveThen(v, m) {
if (!v[2]) v[2] = 0;
var t0 = v[0] * m[0] + v[1] * m[4] + v[2] * m[8];
var t1 = v[0] * m[1] + v[1] * m[5] + v[2] * m[9];
var t2 = v[0] * m[2] + v[1] * m[6] + v[2] * m[10];
return Transform.thenMove(m, [t0, t1, t2]);
};
/**
* Return a Transform which represents a translation by specified
* amounts in each dimension.
*
* @method translate
* @static
* @param {Number} x x translation
* @param {Number} y y translation
* @param {Number} z z translation
* @return {Transform} the resulting matrix
*/
Transform.translate = function translate(x, y, z) {
if (z === undefined) z = 0;
return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, x, y, z, 1];
};
/**
* Return a Transform scaled by a vector in each
* dimension. This is a more performant equivalent to the result of
*
* Transform.multiply(Transform.scale(s[0], s[1], s[2]), m).
*
* @method thenScale
* @static
* @param {Transform} m a matrix
* @param {Array.Number} s delta vector (array of floats &&
* array.length == 3)
* @return {Transform} the resulting translated matrix
*/
Transform.thenScale = function thenScale(m, s) {
return [
s[0] * m[0], s[1] * m[1], s[2] * m[2], 0,
s[0] * m[4], s[1] * m[5], s[2] * m[6], 0,
s[0] * m[8], s[1] * m[9], s[2] * m[10], 0,
s[0] * m[12], s[1] * m[13], s[2] * m[14], 1
];
};
/**
* Return a Transform which represents a scale by specified amounts
* in each dimension.
*
* @method scale
* @static
* @param {Number} x x scale factor
* @param {Number} y y scale factor
* @param {Number} z z scale factor
* @return {Transform} the resulting matrix
*/
Transform.scale = function scale(x, y, z) {
if (z === undefined) z = 1;
return [x, 0, 0, 0, 0, y, 0, 0, 0, 0, z, 0, 0, 0, 0, 1];
};
/**
* Return a Transform which represents a clockwise
* rotation around the x axis.
*
* @method rotateX
* @static
* @param {Number} theta radians
* @return {Transform} the resulting matrix
*/
Transform.rotateX = function rotateX(theta) {
var cosTheta = Math.cos(theta);
var sinTheta = Math.sin(theta);
return [1, 0, 0, 0, 0, cosTheta, sinTheta, 0, 0, -sinTheta, cosTheta, 0, 0, 0, 0, 1];
};
/**
* Return a Transform which represents a clockwise
* rotation around the y axis.
*
* @method rotateY
* @static
* @param {Number} theta radians
* @return {Transform} the resulting matrix
*/
Transform.rotateY = function rotateY(theta) {
var cosTheta = Math.cos(theta);
var sinTheta = Math.sin(theta);
return [cosTheta, 0, -sinTheta, 0, 0, 1, 0, 0, sinTheta, 0, cosTheta, 0, 0, 0, 0, 1];
};
/**
* Return a Transform which represents a clockwise
* rotation around the z axis.
*
* @method rotateZ
* @static
* @param {Number} theta radians
* @return {Transform} the resulting matrix
*/
Transform.rotateZ = function rotateZ(theta) {
var cosTheta = Math.cos(theta);
var sinTheta = Math.sin(theta);
return [cosTheta, sinTheta, 0, 0, -sinTheta, cosTheta, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
};
/**
* Return a Transform which represents composed clockwise
* rotations along each of the axes. Equivalent to the result of
* Matrix.multiply(rotateX(phi), rotateY(theta), rotateZ(psi)).
*
* @method rotate
* @static
* @param {Number} phi radians to rotate about the positive x axis
* @param {Number} theta radians to rotate about the positive y axis
* @param {Number} psi radians to rotate about the positive z axis
* @return {Transform} the resulting matrix
*/
Transform.rotate = function rotate(phi, theta, psi) {
var cosPhi = Math.cos(phi);
var sinPhi = Math.sin(phi);
var cosTheta = Math.cos(theta);
var sinTheta = Math.sin(theta);
var cosPsi = Math.cos(psi);
var sinPsi = Math.sin(psi);
var result = [
cosTheta * cosPsi,
cosPhi * sinPsi + sinPhi * sinTheta * cosPsi,
sinPhi * sinPsi - cosPhi * sinTheta * cosPsi,
0,
-cosTheta * sinPsi,
cosPhi * cosPsi - sinPhi * sinTheta * sinPsi,
sinPhi * cosPsi + cosPhi * sinTheta * sinPsi,
0,
sinTheta,
-sinPhi * cosTheta,
cosPhi * cosTheta,
0,
0, 0, 0, 1
];
return result;
};
/**
* Return a Transform which represents an axis-angle rotation
*
* @method rotateAxis
* @static
* @param {Array.Number} v unit vector representing the axis to rotate about
* @param {Number} theta radians to rotate clockwise about the axis
* @return {Transform} the resulting matrix
*/
Transform.rotateAxis = function rotateAxis(v, theta) {
var sinTheta = Math.sin(theta);
var cosTheta = Math.cos(theta);
var verTheta = 1 - cosTheta; // versine of theta
var xxV = v[0] * v[0] * verTheta;
var xyV = v[0] * v[1] * verTheta;
var xzV = v[0] * v[2] * verTheta;
var yyV = v[1] * v[1] * verTheta;
var yzV = v[1] * v[2] * verTheta;
var zzV = v[2] * v[2] * verTheta;
var xs = v[0] * sinTheta;
var ys = v[1] * sinTheta;
var zs = v[2] * sinTheta;
var result = [
xxV + cosTheta, xyV + zs, xzV - ys, 0,
xyV - zs, yyV + cosTheta, yzV + xs, 0,
xzV + ys, yzV - xs, zzV + cosTheta, 0,
0, 0, 0, 1
];
return result;
};
/**
* Return a Transform which represents a transform matrix applied about
* a separate origin point.
*
* @method aboutOrigin
* @static
* @param {Array.Number} v origin point to apply matrix
* @param {Transform} m matrix to apply
* @return {Transform} the resulting matrix
*/
Transform.aboutOrigin = function aboutOrigin(v, m) {
var t0 = v[0] - (v[0] * m[0] + v[1] * m[4] + v[2] * m[8]);
var t1 = v[1] - (v[0] * m[1] + v[1] * m[5] + v[2] * m[9]);
var t2 = v[2] - (v[0] * m[2] + v[1] * m[6] + v[2] * m[10]);
return Transform.thenMove(m, [t0, t1, t2]);
};
/**
* Return a Transform representation of a skew transformation
*
* @method skew
* @static
* @param {Number} phi scale factor skew in the x axis
* @param {Number} theta scale factor skew in the y axis
* @param {Number} psi scale factor skew in the z axis
* @return {Transform} the resulting matrix
*/
Transform.skew = function skew(phi, theta, psi) {
return [1, 0, 0, 0, Math.tan(psi), 1, 0, 0, Math.tan(theta), Math.tan(phi), 1, 0, 0, 0, 0, 1];
};
/**
* Returns a perspective Transform matrix
*
* @method perspective
* @static
* @param {Number} focusZ z position of focal point
* @return {Transform} the resulting matrix
*/
Transform.perspective = function perspective(focusZ) {
return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, -1 / focusZ, 0, 0, 0, 1];
};
/**
* Return translation vector component of given Transform
*
* @method getTranslate
* @static
* @param {Transform} m matrix
* @return {Array.Number} the translation vector [t_x, t_y, t_z]
*/
Transform.getTranslate = function getTranslate(m) {
return [m[12], m[13], m[14]];
};
/**
* Return inverse affine matrix for given Transform.
* Note: This assumes m[3] = m[7] = m[11] = 0, and m[15] = 1.
* Will provide incorrect results if not invertible or preconditions not met.
*
* @method inverse
* @static
* @param {Transform} m matrix
* @return {Transform} the resulting inverted matrix
*/
Transform.inverse = function inverse(m) {
// only need to consider 3x3 section for affine
var c0 = m[5] * m[10] - m[6] * m[9];
var c1 = m[4] * m[10] - m[6] * m[8];
var c2 = m[4] * m[9] - m[5] * m[8];
var c4 = m[1] * m[10] - m[2] * m[9];
var c5 = m[0] * m[10] - m[2] * m[8];
var c6 = m[0] * m[9] - m[1] * m[8];
var c8 = m[1] * m[6] - m[2] * m[5];
var c9 = m[0] * m[6] - m[2] * m[4];
var c10 = m[0] * m[5] - m[1] * m[4];
var detM = m[0] * c0 - m[1] * c1 + m[2] * c2;
var invD = 1 / detM;
var result = [
invD * c0, -invD * c4, invD * c8, 0,
-invD * c1, invD * c5, -invD * c9, 0,
invD * c2, -invD * c6, invD * c10, 0,
0, 0, 0, 1
];
result[12] = -m[12] * result[0] - m[13] * result[4] - m[14] * result[8];
result[13] = -m[12] * result[1] - m[13] * result[5] - m[14] * result[9];
result[14] = -m[12] * result[2] - m[13] * result[6] - m[14] * result[10];
return result;
};
/**
* Returns the transpose of a 4x4 matrix
*
* @method transpose
* @static
* @param {Transform} m matrix
* @return {Transform} the resulting transposed matrix
*/
Transform.transpose = function transpose(m) {
return [m[0], m[4], m[8], m[12], m[1], m[5], m[9], m[13], m[2], m[6], m[10], m[14], m[3], m[7], m[11], m[15]];
};
function _normSquared(v) {
return (v.length === 2) ? v[0] * v[0] + v[1] * v[1] : v[0] * v[0] + v[1] * v[1] + v[2] * v[2];
}
function _norm(v) {
return Math.sqrt(_normSquared(v));
}
function _sign(n) {
return (n < 0) ? -1 : 1;
}
/**
* Decompose Transform into separate .translate, .rotate, .scale,
* and .skew components.
*
* @method interpret
* @static
* @param {Transform} M tranform matrix
* @return {Object} matrix spec object with component matrices .translate,
* .rotate, .scale, .skew
*/
Transform.interpret = function interpret(M) {
// QR decomposition via Householder reflections
//FIRST ITERATION
//default Q1 to the identity matrix;
var x = [M[0], M[1], M[2]]; // first column vector
var sgn = _sign(x[0]); // sign of first component of x (for stability)
var xNorm = _norm(x); // norm of first column vector
var v = [x[0] + sgn * xNorm, x[1], x[2]]; // v = x + sign(x[0])|x|e1
var mult = 2 / _normSquared(v); // mult = 2/v'v
//bail out if our Matrix is singular
if (mult >= Infinity) {
return {translate: Transform.getTranslate(M), rotate: [0, 0, 0], scale: [0, 0, 0], skew: [0, 0, 0]};
}
//evaluate Q1 = I - 2vv'/v'v
var Q1 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1];
//diagonals
Q1[0] = 1 - mult * v[0] * v[0]; // 0,0 entry
Q1[5] = 1 - mult * v[1] * v[1]; // 1,1 entry
Q1[10] = 1 - mult * v[2] * v[2]; // 2,2 entry
//upper diagonal
Q1[1] = -mult * v[0] * v[1]; // 0,1 entry
Q1[2] = -mult * v[0] * v[2]; // 0,2 entry
Q1[6] = -mult * v[1] * v[2]; // 1,2 entry
//lower diagonal
Q1[4] = Q1[1]; // 1,0 entry
Q1[8] = Q1[2]; // 2,0 entry
Q1[9] = Q1[6]; // 2,1 entry
//reduce first column of M
var MQ1 = Transform.multiply(Q1, M);
//SECOND ITERATION on (1,1) minor
var x2 = [MQ1[5], MQ1[6]];
var sgn2 = _sign(x2[0]); // sign of first component of x (for stability)
var x2Norm = _norm(x2); // norm of first column vector
var v2 = [x2[0] + sgn2 * x2Norm, x2[1]]; // v = x + sign(x[0])|x|e1
var mult2 = 2 / _normSquared(v2); // mult = 2/v'v
//evaluate Q2 = I - 2vv'/v'v
var Q2 = [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1];
//diagonal
Q2[5] = 1 - mult2 * v2[0] * v2[0]; // 1,1 entry
Q2[10] = 1 - mult2 * v2[1] * v2[1]; // 2,2 entry
//off diagonals
Q2[6] = -mult2 * v2[0] * v2[1]; // 2,1 entry
Q2[9] = Q2[6]; // 1,2 entry
//calc QR decomposition. Q = Q1*Q2, R = Q'*M
var Q = Transform.multiply(Q2, Q1); //note: really Q transpose
var R = Transform.multiply(Q, M);
//remove negative scaling
var remover = Transform.scale(R[0] < 0 ? -1 : 1, R[5] < 0 ? -1 : 1, R[10] < 0 ? -1 : 1);
R = Transform.multiply(R, remover);
Q = Transform.multiply(remover, Q);
//decompose into rotate/scale/skew matrices
var result = {};
result.translate = Transform.getTranslate(M);
result.rotate = [Math.atan2(-Q[6], Q[10]), Math.asin(Q[2]), Math.atan2(-Q[1], Q[0])];
if (!result.rotate[0]) {
result.rotate[0] = 0;
result.rotate[2] = Math.atan2(Q[4], Q[5]);
}
result.scale = [R[0], R[5], R[10]];
result.skew = [Math.atan2(R[9], result.scale[2]), Math.atan2(R[8], result.scale[2]), Math.atan2(R[4], result.scale[0])];
//double rotation workaround
if (Math.abs(result.rotate[0]) + Math.abs(result.rotate[2]) > 1.5 * Math.PI) {
result.rotate[1] = Math.PI - result.rotate[1];
if (result.rotate[1] > Math.PI) result.rotate[1] -= 2 * Math.PI;
if (result.rotate[1] < -Math.PI) result.rotate[1] += 2 * Math.PI;
if (result.rotate[0] < 0) result.rotate[0] += Math.PI;
else result.rotate[0] -= Math.PI;
if (result.rotate[2] < 0) result.rotate[2] += Math.PI;
else result.rotate[2] -= Math.PI;
}
return result;
};
/**
* Weighted average between two matrices by averaging their
* translation, rotation, scale, skew components.
* f(M1,M2,t) = (1 - t) * M1 + t * M2
*
* @method average
* @static
* @param {Transform} M1 f(M1,M2,0) = M1
* @param {Transform} M2 f(M1,M2,1) = M2
* @param {Number} t
* @return {Transform} resulting matrix
*/
Transform.average = function average(M1, M2, t) {
t = (t === undefined) ? 0.5 : t;
var specM1 = Transform.interpret(M1);
var specM2 = Transform.interpret(M2);
var specAvg = {
translate: [0, 0, 0],
rotate: [0, 0, 0],
scale: [0, 0, 0],
skew: [0, 0, 0]
};
for (var i = 0; i < 3; i++) {
specAvg.translate[i] = (1 - t) * specM1.translate[i] + t * specM2.translate[i];
specAvg.rotate[i] = (1 - t) * specM1.rotate[i] + t * specM2.rotate[i];
specAvg.scale[i] = (1 - t) * specM1.scale[i] + t * specM2.scale[i];
specAvg.skew[i] = (1 - t) * specM1.skew[i] + t * specM2.skew[i];
}
return Transform.build(specAvg);
};
/**
* Compose .translate, .rotate, .scale, .skew components into
* Transform matrix
*
* @method build
* @static
* @param {matrixSpec} spec object with component matrices .translate,
* .rotate, .scale, .skew
* @return {Transform} composed martix
*/
Transform.build = function build(spec) {
var scaleMatrix = Transform.scale(spec.scale[0], spec.scale[1], spec.scale[2]);
var skewMatrix = Transform.skew(spec.skew[0], spec.skew[1], spec.skew[2]);
var rotateMatrix = Transform.rotate(spec.rotate[0], spec.rotate[1], spec.rotate[2]);
return Transform.thenMove(Transform.multiply(Transform.multiply(rotateMatrix, skewMatrix), scaleMatrix), spec.translate);
};
/**
* Determine if two Transforms are component-wise equal
* Warning: breaks on perspective Transforms
*
* @method equals
* @static
* @param {Transform} a matrix
* @param {Transform} b matrix
* @return {boolean}
*/
Transform.equals = function equals(a, b) {
return !Transform.notEquals(a, b);
};
/**
* Determine if two Transforms are component-wise unequal
* Warning: breaks on perspective Transforms
*
* @method notEquals
* @static
* @param {Transform} a matrix
* @param {Transform} b matrix
* @return {boolean}
*/
Transform.notEquals = function notEquals(a, b) {
if (a === b) return false;
if (!(a && b)) return true;
// shortci
return !(a && b) ||
a[12] !== b[12] || a[13] !== b[13] || a[14] !== b[14] ||
a[0] !== b[0] || a[1] !== b[1] || a[2] !== b[2] ||
a[4] !== b[4] || a[5] !== b[5] || a[6] !== b[6] ||
a[8] !== b[8] || a[9] !== b[9] || a[10] !== b[10];
};
/**
* Constrain angle-trio components to range of [-pi, pi).
*
* @method normalizeRotation
* @static
* @param {Array.Number} rotation phi, theta, psi (array of floats
* && array.length == 3)
* @return {Array.Number} new phi, theta, psi triplet
* (array of floats && array.length == 3)
*/
Transform.normalizeRotation = function normalizeRotation(rotation) {
var result = rotation.slice(0);
if (result[0] === Math.PI * 0.5 || result[0] === -Math.PI * 0.5) {
result[0] = -result[0];
result[1] = Math.PI - result[1];
result[2] -= Math.PI;
}
if (result[0] > Math.PI * 0.5) {
result[0] = result[0] - Math.PI;
result[1] = Math.PI - result[1];
result[2] -= Math.PI;
}
if (result[0] < -Math.PI * 0.5) {
result[0] = result[0] + Math.PI;
result[1] = -Math.PI - result[1];
result[2] -= Math.PI;
}
while (result[1] < -Math.PI) result[1] += 2 * Math.PI;
while (result[1] >= Math.PI) result[1] -= 2 * Math.PI;
while (result[2] < -Math.PI) result[2] += 2 * Math.PI;
while (result[2] >= Math.PI) result[2] -= 2 * Math.PI;
return result;
};
/**
* (Property) Array defining a translation forward in z by 1
*
* @property {array} inFront
* @static
* @final
*/
Transform.inFront = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1e-3, 1];
/**
* (Property) Array defining a translation backwards in z by 1
*
* @property {array} behind
* @static
* @final
*/
Transform.behind = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, -1e-3, 1];
module.exports = Transform;
}.call(exports, __webpack_require__, exports, module)), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
/***/ },
/* 3 */
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_RESULT__;
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Owner: mark@famo.us
* @license MPL 2.0
* @copyright Famous Industries, Inc. 2014
*/
!(__WEBPACK_AMD_DEFINE_RESULT__ = (function(require, exports, module) {
var Surface = __webpack_require__(15);
/**
* A surface containing image content.
* This extends the Surface class.
*
* @class ImageSurface
*
* @extends Surface
* @constructor
* @param {Object} [options] overrides of default options
*/
function ImageSurface(options) {
this._imageUrl = undefined;
Surface.apply(this, arguments);
}
ImageSurface.prototype = Object.create(Surface.prototype);
ImageSurface.prototype.constructor = ImageSurface;
ImageSurface.prototype.elementType = 'img';
ImageSurface.prototype.elementClass = 'famous-surface';
/**
* Set content URL. This will cause a re-rendering.
* @method setContent
* @param {string} imageUrl
*/
ImageSurface.prototype.setContent = function setContent(imageUrl) {
this._imageUrl = imageUrl;
this._contentDirty = true;
};
/**
* Place the document element that this component manages into the document.
*
* @private
* @method deploy
* @param {Node} target document parent of this container
*/
ImageSurface.prototype.deploy = function deploy(target) {
target.src = this._imageUrl || '';
};
/**
* Remove this component and contained content from the document
*
* @private
* @method recall
*
* @param {Node} target node to which the component was deployed
*/
ImageSurface.prototype.recall = function recall(target) {
target.src = '';
};
module.exports = ImageSurface;
}.call(exports, __webpack_require__, exports, module)), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
/***/ },
/* 4 */
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_RESULT__;/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Owner: mark@famo.us
* @license MPL 2.0
* @copyright Famous Industries, Inc. 2014
*/
!(__WEBPACK_AMD_DEFINE_RESULT__ = (function(require, exports, module) {
var Modifier = __webpack_require__(12);
var Transform = __webpack_require__(2);
var Transitionable = __webpack_require__(13);
var TransitionableTransform = __webpack_require__(14);
/**
* A collection of visual changes to be
* applied to another renderable component, strongly coupled with the state that defines
* those changes. This collection includes a
* transform matrix, an opacity constant, a size, an origin specifier.
* StateModifier objects can be added to any RenderNode or object
* capable of displaying renderables. The StateModifier's children and descendants
* are transformed by the amounts specified in the modifier's properties.
*
* @class StateModifier
* @constructor
* @param {Object} [options] overrides of default options
* @param {Transform} [options.transform] affine transformation matrix
* @param {Number} [options.opacity]
* @param {Array.Number} [options.origin] origin adjustment
* @param {Array.Number} [options.size] size to apply to descendants
*/
function StateModifier(options) {
this._transformState = new TransitionableTransform(Transform.identity);
this._opacityState = new Transitionable(1);
this._originState = new Transitionable([0, 0]);
this._sizeState = new Transitionable([0, 0]);
this._modifier = new Modifier({
transform: this._transformState,
opacity: this._opacityState,
origin: null,
size: null
});
this._hasOrigin = false;
this._hasSize = false;
if (options) {
if (options.transform) this.setTransform(options.transform);
if (options.opacity) this.setOpacity(options.opacity);
if (options.origin) this.setOrigin(options.origin);
if (options.size) this.setSize(options.size);
}
}
/**
* Set the transform matrix of this modifier, either statically or
* through a provided Transitionable.
*
* @method setTransform
*
* @param {Transform} transform Transform to transition to.
* @param {Transitionable} [transition] Valid transitionable object
* @param {Function} [callback] callback to call after transition completes
* @return {StateModifier} this
*/
StateModifier.prototype.setTransform = function setTransform(transform, transition, callback) {
this._transformState.set(transform, transition, callback);
return this;
};
/**
* Set the opacity of this modifier, either statically or
* through a provided Transitionable.
*
* @method setOpacity
*
* @param {Number} opacity Opacity value to transition to.
* @param {Transitionable} transition Valid transitionable object
* @param {Function} callback callback to call after transition completes
* @return {StateModifier} this
*/
StateModifier.prototype.setOpacity = function setOpacity(opacity, transition, callback) {
this._opacityState.set(opacity, transition, callback);
return this;
};
/**
* Set the origin of this modifier, either statically or
* through a provided Transitionable.
*
* @method setOrigin
*
* @param {Array.Number} origin two element array with values between 0 and 1.
* @param {Transitionable} transition Valid transitionable object
* @param {Function} callback callback to call after transition completes
* @return {StateModifier} this
*/
StateModifier.prototype.setOrigin = function setOrigin(origin, transition, callback) {
if (origin === null) {
if (this._hasOrigin) {
this._modifier.originFrom(null);
this._hasOrigin = false;
}
return this;
}
else if (!this._hasOrigin) {
this._hasOrigin = true;
this._modifier.originFrom(this._originState);
}
this._originState.set(origin, transition, callback);
return this;
};
/**
* Set the size of this modifier, either statically or
* through a provided Transitionable.
*
* @method setSize
*
* @param {Array.Number} size two element array with values between 0 and 1.
* @param {Transitionable} transition Valid transitionable object
* @param {Function} callback callback to call after transition completes
* @return {StateModifier} this
*/
StateModifier.prototype.setSize = function setSize(size, transition, callback) {
if (size === null) {
if (this._hasSize) {
this._modifier.sizeFrom(null);
this._hasSize = false;
}
return this;
}
else if (!this._hasSize) {
this._hasSize = true;
this._modifier.sizeFrom(this._sizeState);
}
this._sizeState.set(size, transition, callback);
return this;
};
/**
* Stop the transition.
*
* @method halt
*/
StateModifier.prototype.halt = function halt() {
this._transformState.halt();
this._opacityState.halt();
this._originState.halt();
this._sizeState.halt();
};
/**
* Get the current state of the transform matrix component.
*
* @method getTransform
* @return {Object} transform provider object
*/
StateModifier.prototype.getTransform = function getTransform() {
return this._transformState.get();
};
/**
* Get the destination state of the transform component.
*
* @method getFinalTransform
* @return {Transform} transform matrix
*/
StateModifier.prototype.getFinalTransform = function getFinalTransform() {
return this._transformState.getFinal();
};
/**
* Get the current state of the opacity component.
*
* @method getOpacity
* @return {Object} opacity provider object
*/
StateModifier.prototype.getOpacity = function getOpacity() {
return this._opacityState.get();
};
/**
* Get the current state of the origin component.
*
* @method getOrigin
* @return {Object} origin provider object
*/
StateModifier.prototype.getOrigin = function getOrigin() {
return this._hasOrigin ? this._originState.get() : null;
};
/**
* Get the current state of the size component.
*
* @method getSize
* @return {Object} size provider object
*/
StateModifier.prototype.getSize = function getSize() {
return this._hasSize ? this._sizeState.get() : null;
};
/**
* Return render spec for this StateModifier, applying to the provided
* target component. This is similar to render() for Surfaces.
*
* @private
* @method modify
*
* @param {Object} target (already rendered) render spec to
* which to apply the transform.
* @return {Object} render spec for this StateModifier, including the
* provided target
*/
StateModifier.prototype.modify = function modify(target) {
return this._modifier.modify(target);
};
module.exports = StateModifier;
}.call(exports, __webpack_require__, exports, module)), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
/***/ },
/* 5 */
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_RESULT__;/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Owner: david@famo.us
* @license MPL 2.0
* @copyright Famous Industries, Inc. 2014
*/
!(__WEBPACK_AMD_DEFINE_RESULT__ = (function(require, exports, module) {
/*
* A library of curves which map an animation explicitly as a function of time.
*
* @class Easing
*/
var Easing = {
/**
* @property inQuad
* @static
*/
inQuad: function(t) {
return t*t;
},
/**
* @property outQuad
* @static
*/
outQuad: function(t) {
return -(t-=1)*t+1;
},
/**
* @property inOutQuad
* @static
*/
inOutQuad: function(t) {
if ((t/=.5) < 1) return .5*t*t;
return -.5*((--t)*(t-2) - 1);
},
/**
* @property inCubic
* @static
*/
inCubic: function(t) {
return t*t*t;
},
/**
* @property outCubic
* @static
*/
outCubic: function(t) {
return ((--t)*t*t + 1);
},
/**
* @property inOutCubic
* @static
*/
inOutCubic: function(t) {
if ((t/=.5) < 1) return .5*t*t*t;
return .5*((t-=2)*t*t + 2);
},
/**
* @property inQuart
* @static
*/
inQuart: function(t) {
return t*t*t*t;
},
/**
* @property outQuart
* @static
*/
outQuart: function(t) {
return -((--t)*t*t*t - 1);
},
/**
* @property inOutQuart
* @static
*/
inOutQuart: function(t) {
if ((t/=.5) < 1) return .5*t*t*t*t;
return -.5 * ((t-=2)*t*t*t - 2);
},
/**
* @property inQuint
* @static
*/
inQuint: function(t) {
return t*t*t*t*t;
},
/**
* @property outQuint
* @static
*/
outQuint: function(t) {
return ((--t)*t*t*t*t + 1);
},
/**
* @property inQuad
* @static
*/
inOutQuint: function(t) {
if ((t/=.5) < 1) return .5*t*t*t*t*t;
return .5*((t-=2)*t*t*t*t + 2);
},
/**
* @property inSine
* @static
*/
inSine: function(t) {
return -1.0*Math.cos(t * (Math.PI/2)) + 1.0;
},
/**
* @property outSine
* @static
*/
outSine: function(t) {
return Math.sin(t * (Math.PI/2));
},
/**
* @property inOutSine
* @static
*/
inOutSine: function(t) {
return -.5*(Math.cos(Math.PI*t) - 1);
},
/**
* @property inExpo
* @static
*/
inExpo: function(t) {
return (t===0) ? 0.0 : Math.pow(2, 10 * (t - 1));
},
/**
* @property outExpo
* @static
*/
outExpo: function(t) {
return (t===1.0) ? 1.0 : (-Math.pow(2, -10 * t) + 1);
},
/**
* @property inOutExpo
* @static
*/
inOutExpo: function(t) {
if (t===0) return 0.0;
if (t===1.0) return 1.0;
if ((t/=.5) < 1) return .5 * Math.pow(2, 10 * (t - 1));
return .5 * (-Math.pow(2, -10 * --t) + 2);
},
/**
* @property inCirc
* @static
*/
inCirc: function(t) {
return -(Math.sqrt(1 - t*t) - 1);
},
/**
* @property outCirc
* @static
*/
outCirc: function(t) {
return Math.sqrt(1 - (--t)*t);
},
/**
* @property inOutCirc
* @static
*/
inOutCirc: function(t) {
if ((t/=.5) < 1) return -.5 * (Math.sqrt(1 - t*t) - 1);
return .5 * (Math.sqrt(1 - (t-=2)*t) + 1);
},
/**
* @property inElastic
* @static
*/
inElastic: function(t) {
var s=1.70158;var p=0;var a=1.0;
if (t===0) return 0.0; if (t===1) return 1.0; if (!p) p=.3;
s = p/(2*Math.PI) * Math.asin(1.0/a);
return -(a*Math.pow(2,10*(t-=1)) * Math.sin((t-s)*(2*Math.PI)/ p));
},
/**
* @property outElastic
* @static
*/
outElastic: function(t) {
var s=1.70158;var p=0;var a=1.0;
if (t===0) return 0.0; if (t===1) return 1.0; if (!p) p=.3;
s = p/(2*Math.PI) * Math.asin(1.0/a);
return a*Math.pow(2,-10*t) * Math.sin((t-s)*(2*Math.PI)/p) + 1.0;
},
/**
* @property inOutElastic
* @static
*/
inOutElastic: function(t) {
var s=1.70158;var p=0;var a=1.0;
if (t===0) return 0.0; if ((t/=.5)===2) return 1.0; if (!p) p=(.3*1.5);
s = p/(2*Math.PI) * Math.asin(1.0/a);
if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin((t-s)*(2*Math.PI)/p));
return a*Math.pow(2,-10*(t-=1)) * Math.sin((t-s)*(2*Math.PI)/p)*.5 + 1.0;
},
/**
* @property inBack
* @static
*/
inBack: function(t, s) {
if (s === undefined) s = 1.70158;
return t*t*((s+1)*t - s);
},
/**
* @property outBack
* @static
*/
outBack: function(t, s) {
if (s === undefined) s = 1.70158;
return ((--t)*t*((s+1)*t + s) + 1);
},
/**
* @property inOutBack
* @static
*/
inOutBack: function(t, s) {
if (s === undefined) s = 1.70158;
if ((t/=.5) < 1) return .5*(t*t*(((s*=(1.525))+1)*t - s));
return .5*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2);
},
/**
* @property inBounce
* @static
*/
inBounce: function(t) {
return 1.0 - Easing.outBounce(1.0-t);
},
/**
* @property outBounce
* @static
*/
outBounce: function(t) {
if (t < (1/2.75)) {
return (7.5625*t*t);
} else if (t < (2/2.75)) {
return (7.5625*(t-=(1.5/2.75))*t + .75);
} else if (t < (2.5/2.75)) {
return (7.5625*(t-=(2.25/2.75))*t + .9375);
} else {
return (7.5625*(t-=(2.625/2.75))*t + .984375);
}
},
/**
* @property inOutBounce
* @static
*/
inOutBounce: function(t) {
if (t < .5) return Easing.inBounce(t*2) * .5;
return Easing.outBounce(t*2-1.0) * .5 + .5;
}
};
module.exports = Easing;
}.call(exports, __webpack_require__, exports, module)), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
/***/ },
/* 6 */
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_RESULT__;/* WEBPACK VAR INJECTION */(function(module, global) {/**
* @license
* Lo-Dash 2.4.1 (Custom Build) <http://lodash.com/>
* Build: `lodash -o ./dist/lodash.compat.js`
* Copyright 2012-2013 The Dojo Foundation <http://dojofoundation.org/>
* Based on Underscore.js 1.5.2 <http://underscorejs.org/LICENSE>
* Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
* Available under MIT license <http://lodash.com/license>
*/
;(function() {
/** Used as a safe reference for `undefined` in pre ES5 environments */
var undefined;
/** Used to pool arrays and objects used internally */
var arrayPool = [],
objectPool = [];
/** Used to generate unique IDs */
var idCounter = 0;
/** Used internally to indicate various things */
var indicatorObject = {};
/** Used to prefix keys to avoid issues with `__proto__` and properties on `Object.prototype` */
var keyPrefix = +new Date + '';
/** Used as the size when optimizations are enabled for large arrays */
var largeArraySize = 75;
/** Used as the max size of the `arrayPool` and `objectPool` */
var maxPoolSize = 40;
/** Used to detect and test whitespace */
var whitespace = (
// whitespace
' \t\x0B\f\xA0\ufeff' +
// line terminators
'\n\r\u2028\u2029' +
// unicode category "Zs" space separators
'\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000'
);
/** Used to match empty string literals in compiled template source */
var reEmptyStringLeading = /\b__p \+= '';/g,
reEmptyStringMiddle = /\b(__p \+=) '' \+/g,
reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g;
/**
* Used to match ES6 template delimiters
* http://people.mozilla.org/~jorendorff/es6-draft.html#sec-literals-string-literals
*/
var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g;
/** Used to match regexp flags from their coerced string values */
var reFlags = /\w*$/;
/** Used to detected named functions */
var reFuncName = /^\s*function[ \n\r\t]+\w/;
/** Used to match "interpolate" template delimiters */
var reInterpolate = /<%=([\s\S]+?)%>/g;
/** Used to match leading whitespace and zeros to be removed */
var reLeadingSpacesAndZeros = RegExp('^[' + whitespace + ']*0+(?=.$)');
/** Used to ensure capturing order of template delimiters */
var reNoMatch = /($^)/;
/** Used to detect functions containing a `this` reference */
var reThis = /\bthis\b/;
/** Used to match unescaped characters in compiled string literals */
var reUnescapedString = /['\n\r\t\u2028\u2029\\]/g;
/** Used to assign default `context` object properties */
var contextProps = [
'Array', 'Boolean', 'Date', 'Error', 'Function', 'Math', 'Number', 'Object',
'RegExp', 'String', '_', 'attachEvent', 'clearTimeout', 'isFinite', 'isNaN',
'parseInt', 'setTimeout'
];
/** Used to fix the JScript [[DontEnum]] bug */
var shadowedProps = [
'constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable',
'toLocaleString', 'toString', 'valueOf'
];
/** Used to make template sourceURLs easier to identify */
var templateCounter = 0;
/** `Object#toString` result shortcuts */
var argsClass = '[object Arguments]',
arrayClass = '[object Array]',
boolClass = '[object Boolean]',
dateClass = '[object Date]',
errorClass = '[object Error]',
funcClass = '[object Function]',
numberClass = '[object Number]',
objectClass = '[object Object]',
regexpClass = '[object RegExp]',
stringClass = '[object String]';
/** Used to identify object classifications that `_.clone` supports */
var cloneableClasses = {};
cloneableClasses[funcClass] = false;
cloneableClasses[argsClass] = cloneableClasses[arrayClass] =
cloneableClasses[boolClass] = cloneableClasses[dateClass] =
cloneableClasses[numberClass] = cloneableClasses[objectClass] =
cloneableClasses[regexpClass] = cloneableClasses[stringClass] = true;
/** Used as an internal `_.debounce` options object */
var debounceOptions = {
'leading': false,
'maxWait': 0,
'trailing': false
};
/** Used as the property descriptor for `__bindData__` */
var descriptor = {
'configurable': false,
'enumerable': false,
'value': null,
'writable': false
};
/** Used as the data object for `iteratorTemplate` */
var iteratorData = {
'args': '',
'array': null,
'bottom': '',
'firstArg': '',
'init': '',
'keys': null,
'loop': '',
'shadowedProps': null,
'support': null,
'top': '',
'useHas': false
};
/** Used to determine if values are of the language type Object */
var objectTypes = {
'boolean': false,
'function': true,
'object': true,
'number': false,
'string': false,
'undefined': false
};
/** Used to escape characters for inclusion in compiled string literals */
var stringEscapes = {
'\\': '\\',
"'": "'",
'\n': 'n',
'\r': 'r',
'\t': 't',
'\u2028': 'u2028',
'\u2029': 'u2029'
};
/** Used as a reference to the global object */
var root = (objectTypes[typeof window] && window) || this;
/** Detect free variable `exports` */
var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports;
/** Detect free variable `module` */
var freeModule = objectTypes[typeof module] && module && !module.nodeType && module;
/** Detect the popular CommonJS extension `module.exports` */
var moduleExports = freeModule && freeModule.exports === freeExports && freeExports;
/** Detect free variable `global` from Node.js or Browserified code and use it as `root` */
var freeGlobal = objectTypes[typeof global] && global;
if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal)) {
root = freeGlobal;
}
/*--------------------------------------------------------------------------*/
/**
* The base implementation of `_.indexOf` without support for binary searches
* or `fromIndex` constraints.
*
* @private
* @param {Array} array The array to search.
* @param {*} value The value to search for.
* @param {number} [fromIndex=0] The index to search from.
* @returns {number} Returns the index of the matched value or `-1`.
*/
function baseIndexOf(array, value, fromIndex) {
var index = (fromIndex || 0) - 1,
length = array ? array.length : 0;
while (++index < length) {
if (array[index] === value) {
return index;
}
}
return -1;
}
/**
* An implementation of `_.contains` for cache objects that mimics the return
* signature of `_.indexOf` by returning `0` if the value is found, else `-1`.
*
* @private
* @param {Object} cache The cache object to inspect.
* @param {*} value The value to search for.
* @returns {number} Returns `0` if `value` is found, else `-1`.
*/
function cacheIndexOf(cache, value) {
var type = typeof value;
cache = cache.cache;
if (type == 'boolean' || value == null) {
return cache[value] ? 0 : -1;
}
if (type != 'number' && type != 'string') {
type = 'object';
}
var key = type == 'number' ? value : keyPrefix + value;
cache = (cache = cache[type]) && cache[key];
return type == 'object'
? (cache && baseIndexOf(cache, value) > -1 ? 0 : -1)
: (cache ? 0 : -1);
}
/**
* Adds a given value to the corresponding cache object.
*
* @private
* @param {*} value The value to add to the cache.
*/
function cachePush(value) {
var cache = this.cache,
type = typeof value;
if (type == 'boolean' || value == null) {
cache[value] = true;
} else {
if (type != 'number' && type != 'string') {
type = 'object';
}
var key = type == 'number' ? value : keyPrefix + value,
typeCache = cache[type] || (cache[type] = {});
if (type == 'object') {
(typeCache[key] || (typeCache[key] = [])).push(value);
} else {
typeCache[key] = true;
}
}
}
/**
* Used by `_.max` and `_.min` as the default callback when a given
* collection is a string value.
*
* @private
* @param {string} value The character to inspect.
* @returns {number} Returns the code unit of given character.
*/
function charAtCallback(value) {
return value.charCodeAt(0);
}
/**
* Used by `sortBy` to compare transformed `collection` elements, stable sorting
* them in ascending order.
*
* @private
* @param {Object} a The object to compare to `b`.
* @param {Object} b The object to compare to `a`.
* @returns {number} Returns the sort order indicator of `1` or `-1`.
*/
function compareAscending(a, b) {
var ac = a.criteria,
bc = b.criteria,
index = -1,
length = ac.length;
while (++index < length) {
var value = ac[index],
other = bc[index];
if (value !== other) {
if (value > other || typeof value == 'undefined') {
return 1;
}
if (value < other || typeof other == 'undefined') {
return -1;
}
}
}
// Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications
// that causes it, under certain circumstances, to return the same value for
// `a` and `b`. See https://github.com/jashkenas/underscore/pull/1247
//
// This also ensures a stable sort in V8 and other engines.
// See http://code.google.com/p/v8/issues/detail?id=90
return a.index - b.index;
}
/**
* Creates a cache object to optimize linear searches of large arrays.
*
* @private
* @param {Array} [array=[]] The array to search.
* @returns {null|Object} Returns the cache object or `null` if caching should not be used.
*/
function createCache(array) {
var index = -1,
length = array.length,
first = array[0],
mid = array[(length / 2) | 0],
last = array[length - 1];
if (first && typeof first == 'object' &&
mid && typeof mid == 'object' && last && typeof last == 'object') {
return false;
}
var cache = getObject();
cache['false'] = cache['null'] = cache['true'] = cache['undefined'] = false;
var result = getObject();
result.array = array;
result.cache = cache;
result.push = cachePush;
while (++index < length) {
result.push(array[index]);
}
return result;
}
/**
* Used by `template` to escape characters for inclusion in compiled
* string literals.
*
* @private
* @param {string} match The matched character to escape.
* @returns {string} Returns the escaped character.
*/
function escapeStringChar(match) {
return '\\' + stringEscapes[match];
}
/**
* Gets an array from the array pool or creates a new one if the pool is empty.
*
* @private
* @returns {Array} The array from the pool.
*/
function getArray() {
return arrayPool.pop() || [];
}
/**
* Gets an object from the object pool or creates a new one if the pool is empty.
*
* @private
* @returns {Object} The object from the pool.
*/
function getObject() {
return objectPool.pop() || {
'array': null,
'cache': null,
'criteria': null,
'false': false,
'index': 0,
'null': false,
'number': null,
'object': null,
'push': null,
'string': null,
'true': false,
'undefined': false,
'value': null
};
}
/**
* Checks if `value` is a DOM node in IE < 9.
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if the `value` is a DOM node, else `false`.
*/
function isNode(value) {
// IE < 9 presents DOM nodes as `Object` objects except they have `toString`
// methods that are `typeof` "string" and still can coerce nodes to strings
return typeof value.toString != 'function' && typeof (value + '') == 'string';
}
/**
* Releases the given array back to the array pool.
*
* @private
* @param {Array} [array] The array to release.
*/
function releaseArray(array) {
array.length = 0;
if (arrayPool.length < maxPoolSize) {
arrayPool.push(array);
}
}
/**
* Releases the given object back to the object pool.
*
* @private
* @param {Object} [object] The object to release.
*/
function releaseObject(object) {
var cache = object.cache;
if (cache) {
releaseObject(cache);
}
object.array = object.cache = object.criteria = object.object = object.number = object.string = object.value = null;
if (objectPool.length < maxPoolSize) {
objectPool.push(object);
}
}
/**
* Slices the `collection` from the `start` index up to, but not including,
* the `end` index.
*
* Note: This function is used instead of `Array#slice` to support node lists
* in IE < 9 and to ensure dense arrays are returned.
*
* @private
* @param {Array|Object|string} collection The collection to slice.
* @param {number} start The start index.
* @param {number} end The end index.
* @returns {Array} Returns the new array.
*/
function slice(array, start, end) {
start || (start = 0);
if (typeof end == 'undefined') {
end = array ? array.length : 0;
}
var index = -1,
length = end - start || 0,
result = Array(length < 0 ? 0 : length);
while (++index < length) {
result[index] = array[start + index];
}
return result;
}
/*--------------------------------------------------------------------------*/
/**
* Create a new `lodash` function using the given context object.
*
* @static
* @memberOf _
* @category Utilities
* @param {Object} [context=root] The context object.
* @returns {Function} Returns the `lodash` function.
*/
function runInContext(context) {
// Avoid issues with some ES3 environments that attempt to use values, named
// after built-in constructors like `Object`, for the creation of literals.
// ES5 clears this up by stating that literals must use built-in constructors.
// See http://es5.github.io/#x11.1.5.
context = context ? _.defaults(root.Object(), context, _.pick(root, contextProps)) : root;
/** Native constructor references */
var Array = context.Array,
Boolean = context.Boolean,
Date = context.Date,
Error = context.Error,
Function = context.Function,
Math = context.Math,
Number = context.Number,
Object = context.Object,
RegExp = context.RegExp,
String = context.String,
TypeError = context.TypeError;
/**
* Used for `Array` method references.
*
* Normally `Array.prototype` would suffice, however, using an array literal
* avoids issues in Narwhal.
*/
var arrayRef = [];
/** Used for native method references */
var errorProto = Error.prototype,
objectProto = Object.prototype,
stringProto = String.prototype;
/** Used to restore the original `_` reference in `noConflict` */
var oldDash = context._;
/** Used to resolve the internal [[Class]] of values */
var toString = objectProto.toString;
/** Used to detect if a method is native */
var reNative = RegExp('^' +
String(toString)
.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
.replace(/toString| for [^\]]+/g, '.*?') + '$'
);
/** Native method shortcuts */
var ceil = Math.ceil,
clearTimeout = context.clearTimeout,
floor = Math.floor,
fnToString = Function.prototype.toString,
getPrototypeOf = isNative(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf,
hasOwnProperty = objectProto.hasOwnProperty,
push = arrayRef.push,
propertyIsEnumerable = objectProto.propertyIsEnumerable,
setTimeout = context.setTimeout,
splice = arrayRef.splice,
unshift = arrayRef.unshift;
/** Used to set meta data on functions */
var defineProperty = (function() {
// IE 8 only accepts DOM elements
try {
var o = {},
func = isNative(func = Object.defineProperty) && func,
result = func(o, o, o) && func;
} catch(e) { }
return result;
}());
/* Native method shortcuts for methods with the same name as other `lodash` methods */
var nativeCreate = isNative(nativeCreate = Object.create) && nativeCreate,
nativeIsArray = isNative(nativeIsArray = Array.isArray) && nativeIsArray,
nativeIsFinite = context.isFinite,
nativeIsNaN = context.isNaN,
nativeKeys = isNative(nativeKeys = Object.keys) && nativeKeys,
nativeMax = Math.max,
nativeMin = Math.min,
nativeParseInt = context.parseInt,
nativeRandom = Math.random;
/** Used to lookup a built-in constructor by [[Class]] */
var ctorByClass = {};
ctorByClass[arrayClass] = Array;
ctorByClass[boolClass] = Boolean;
ctorByClass[dateClass] = Date;
ctorByClass[funcClass] = Function;
ctorByClass[objectClass] = Object;
ctorByClass[numberClass] = Number;
ctorByClass[regexpClass] = RegExp;
ctorByClass[stringClass] = String;
/** Used to avoid iterating non-enumerable properties in IE < 9 */
var nonEnumProps = {};
nonEnumProps[arrayClass] = nonEnumProps[dateClass] = nonEnumProps[numberClass] = { 'constructor': true, 'toLocaleString': true, 'toString': true, 'valueOf': true };
nonEnumProps[boolClass] = nonEnumProps[stringClass] = { 'constructor': true, 'toString': true, 'valueOf': true };
nonEnumProps[errorClass] = nonEnumProps[funcClass] = nonEnumProps[regexpClass] = { 'constructor': true, 'toString': true };
nonEnumProps[objectClass] = { 'constructor': true };
(function() {
var length = shadowedProps.length;
while (length--) {
var key = shadowedProps[length];
for (var className in nonEnumProps) {
if (hasOwnProperty.call(nonEnumProps, className) && !hasOwnProperty.call(nonEnumProps[className], key)) {
nonEnumProps[className][key] = false;
}
}
}
}());
/*--------------------------------------------------------------------------*/
/**
* Creates a `lodash` object which wraps the given value to enable intuitive
* method chaining.
*
* In addition to Lo-Dash methods, wrappers also have the following `Array` methods:
* `concat`, `join`, `pop`, `push`, `reverse`, `shift`, `slice`, `sort`, `splice`,
* and `unshift`
*
* Chaining is supported in custom builds as long as the `value` method is
* implicitly or explicitly included in the build.
*
* The chainable wrapper functions are:
* `after`, `assign`, `bind`, `bindAll`, `bindKey`, `chain`, `compact`,
* `compose`, `concat`, `countBy`, `create`, `createCallback`, `curry`,
* `debounce`, `defaults`, `defer`, `delay`, `difference`, `filter`, `flatten`,
* `forEach`, `forEachRight`, `forIn`, `forInRight`, `forOwn`, `forOwnRight`,
* `functions`, `groupBy`, `indexBy`, `initial`, `intersection`, `invert`,
* `invoke`, `keys`, `map`, `max`, `memoize`, `merge`, `min`, `object`, `omit`,
* `once`, `pairs`, `partial`, `partialRight`, `pick`, `pluck`, `pull`, `push`,
* `range`, `reject`, `remove`, `rest`, `reverse`, `shuffle`, `slice`, `sort`,
* `sortBy`, `splice`, `tap`, `throttle`, `times`, `toArray`, `transform`,
* `union`, `uniq`, `unshift`, `unzip`, `values`, `where`, `without`, `wrap`,
* and `zip`
*
* The non-chainable wrapper functions are:
* `clone`, `cloneDeep`, `contains`, `escape`, `every`, `find`, `findIndex`,
* `findKey`, `findLast`, `findLastIndex`, `findLastKey`, `has`, `identity`,
* `indexOf`, `isArguments`, `isArray`, `isBoolean`, `isDate`, `isElement`,
* `isEmpty`, `isEqual`, `isFinite`, `isFunction`, `isNaN`, `isNull`, `isNumber`,
* `isObject`, `isPlainObject`, `isRegExp`, `isString`, `isUndefined`, `join`,
* `lastIndexOf`, `mixin`, `noConflict`, `parseInt`, `pop`, `random`, `reduce`,
* `reduceRight`, `result`, `shift`, `size`, `some`, `sortedIndex`, `runInContext`,
* `template`, `unescape`, `uniqueId`, and `value`
*
* The wrapper functions `first` and `last` return wrapped values when `n` is
* provided, otherwise they return unwrapped values.
*
* Explicit chaining can be enabled by using the `_.chain` method.
*
* @name _
* @constructor
* @category Chaining
* @param {*} value The value to wrap in a `lodash` instance.
* @returns {Object} Returns a `lodash` instance.
* @example
*
* var wrapped = _([1, 2, 3]);
*
* // returns an unwrapped value
* wrapped.reduce(function(sum, num) {
* return sum + num;
* });
* // => 6
*
* // returns a wrapped value
* var squares = wrapped.map(function(num) {
* return num * num;
* });
*
* _.isArray(squares);
* // => false
*
* _.isArray(squares.value());
* // => true
*/
function lodash(value) {
// don't wrap if already wrapped, even if wrapped by a different `lodash` constructor
return (value && typeof value == 'object' && !isArray(value) && hasOwnProperty.call(value, '__wrapped__'))
? value
: new lodashWrapper(value);
}
/**
* A fast path for creating `lodash` wrapper objects.
*
* @private
* @param {*} value The value to wrap in a `lodash` instance.
* @param {boolean} chainAll A flag to enable chaining for all methods
* @returns {Object} Returns a `lodash` instance.
*/
function lodashWrapper(value, chainAll) {
this.__chain__ = !!chainAll;
this.__wrapped__ = value;
}
// ensure `new lodashWrapper` is an instance of `lodash`
lodashWrapper.prototype = lodash.prototype;
/**
* An object used to flag environments features.
*
* @static
* @memberOf _
* @type Object
*/
var support = lodash.support = {};
(function() {
var ctor = function() { this.x = 1; },
object = { '0': 1, 'length': 1 },
props = [];
ctor.prototype = { 'valueOf': 1, 'y': 1 };
for (var key in new ctor) { props.push(key); }
for (key in arguments) { }
/**
* Detect if an `arguments` object's [[Class]] is resolvable (all but Firefox < 4, IE < 9).
*
* @memberOf _.support
* @type boolean
*/
support.argsClass = toString.call(arguments) == argsClass;
/**
* Detect if `arguments` objects are `Object` objects (all but Narwhal and Opera < 10.5).
*
* @memberOf _.support
* @type boolean
*/
support.argsObject = arguments.constructor == Object && !(arguments instanceof Array);
/**
* Detect if `name` or `message` properties of `Error.prototype` are
* enumerable by default. (IE < 9, Safari < 5.1)
*
* @memberOf _.support
* @type boolean
*/
support.enumErrorProps = propertyIsEnumerable.call(errorProto, 'message') || propertyIsEnumerable.call(errorProto, 'name');
/**
* Detect if `prototype` properties are enumerable by default.
*
* Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1
* (if the prototype or a property on the prototype has been set)
* incorrectly sets a function's `prototype` property [[Enumerable]]
* value to `true`.
*
* @memberOf _.support
* @type boolean
*/
support.enumPrototypes = propertyIsEnumerable.call(ctor, 'prototype');
/**
* Detect if functions can be decompiled by `Function#toString`
* (all but PS3 and older Opera mobile browsers & avoided in Windows 8 apps).
*
* @memberOf _.support
* @type boolean
*/
support.funcDecomp = !isNative(context.WinRTError) && reThis.test(runInContext);
/**
* Detect if `Function#name` is supported (all but IE).
*
* @memberOf _.support
* @type boolean
*/
support.funcNames = typeof Function.name == 'string';
/**
* Detect if `arguments` object indexes are non-enumerable
* (Firefox < 4, IE < 9, PhantomJS, Safari < 5.1).
*
* @memberOf _.support
* @type boolean
*/
support.nonEnumArgs = key != 0;
/**
* Detect if properties shadowing those on `Object.prototype` are non-enumerable.
*
* In IE < 9 an objects own properties, shadowing non-enumerable ones, are
* made non-enumerable as well (a.k.a the JScript [[DontEnum]] bug).
*
* @memberOf _.support
* @type boolean
*/
support.nonEnumShadows = !/valueOf/.test(props);
/**
* Detect if own properties are iterated after inherited properties (all but IE < 9).
*
* @memberOf _.support
* @type boolean
*/
support.ownLast = props[0] != 'x';
/**
* Detect if `Array#shift` and `Array#splice` augment array-like objects correctly.
*
* Firefox < 10, IE compatibility mode, and IE < 9 have buggy Array `shift()`
* and `splice()` functions that fail to remove the last element, `value[0]`,
* of array-like objects even though the `length` property is set to `0`.
* The `shift()` method is buggy in IE 8 compatibility mode, while `splice()`
* is buggy regardless of mode in IE < 9 and buggy in compatibility mode in IE 9.
*
* @memberOf _.support
* @type boolean
*/
support.spliceObjects = (arrayRef.splice.call(object, 0, 1), !object[0]);
/**
* Detect lack of support for accessing string characters by index.
*
* IE < 8 can't access characters by index and IE 8 can only access
* characters by index on string literals.
*
* @memberOf _.support
* @type boolean
*/
support.unindexedChars = ('x'[0] + Object('x')[0]) != 'xx';
/**
* Detect if a DOM node's [[Class]] is resolvable (all but IE < 9)
* and that the JS engine errors when attempting to coerce an object to
* a string without a `toString` function.
*
* @memberOf _.support
* @type boolean
*/
try {
support.nodeClass = !(toString.call(document) == objectClass && !({ 'toString': 0 } + ''));
} catch(e) {
support.nodeClass = true;
}
}(1));
/**
* By default, the template delimiters used by Lo-Dash are similar to those in
* embedded Ruby (ERB). Change the following template settings to use alternative
* delimiters.
*
* @static
* @memberOf _
* @type Object
*/
lodash.templateSettings = {
/**
* Used to detect `data` property values to be HTML-escaped.
*
* @memberOf _.templateSettings
* @type RegExp
*/
'escape': /<%-([\s\S]+?)%>/g,
/**
* Used to detect code to be evaluated.
*
* @memberOf _.templateSettings
* @type RegExp
*/
'evaluate': /<%([\s\S]+?)%>/g,
/**
* Used to detect `data` property values to inject.
*
* @memberOf _.templateSettings
* @type RegExp
*/
'interpolate': reInterpolate,
/**
* Used to reference the data object in the template text.
*
* @memberOf _.templateSettings
* @type string
*/
'variable': '',
/**
* Used to import variables into the compiled template.
*
* @memberOf _.templateSettings
* @type Object
*/
'imports': {
/**
* A reference to the `lodash` function.
*
* @memberOf _.templateSettings.imports
* @type Function
*/
'_': lodash
}
};
/*--------------------------------------------------------------------------*/
/**
* The template used to create iterator functions.
*
* @private
* @param {Object} data The data object used to populate the text.
* @returns {string} Returns the interpolated text.
*/
var iteratorTemplate = function(obj) {
var __p = 'var index, iterable = ' +
(obj.firstArg) +
', result = ' +
(obj.init) +
';\nif (!iterable) return result;\n' +
(obj.top) +
';';
if (obj.array) {
__p += '\nvar length = iterable.length; index = -1;\nif (' +
(obj.array) +
') { ';
if (support.unindexedChars) {
__p += '\n if (isString(iterable)) {\n iterable = iterable.split(\'\')\n } ';
}
__p += '\n while (++index < length) {\n ' +
(obj.loop) +
';\n }\n}\nelse { ';
} else if (support.nonEnumArgs) {
__p += '\n var length = iterable.length; index = -1;\n if (length && isArguments(iterable)) {\n while (++index < length) {\n index += \'\';\n ' +
(obj.loop) +
';\n }\n } else { ';
}
if (support.enumPrototypes) {
__p += '\n var skipProto = typeof iterable == \'function\';\n ';
}
if (support.enumErrorProps) {
__p += '\n var skipErrorProps = iterable === errorProto || iterable instanceof Error;\n ';
}
var conditions = []; if (support.enumPrototypes) { conditions.push('!(skipProto && index == "prototype")'); } if (support.enumErrorProps) { conditions.push('!(skipErrorProps && (index == "message" || index == "name"))'); }
if (obj.useHas && obj.keys) {
__p += '\n var ownIndex = -1,\n ownProps = objectTypes[typeof iterable] && keys(iterable),\n length = ownProps ? ownProps.length : 0;\n\n while (++ownIndex < length) {\n index = ownProps[ownIndex];\n';
if (conditions.length) {
__p += ' if (' +
(conditions.join(' && ')) +
') {\n ';
}
__p +=
(obj.loop) +
'; ';
if (conditions.length) {
__p += '\n }';
}
__p += '\n } ';
} else {
__p += '\n for (index in iterable) {\n';
if (obj.useHas) { conditions.push("hasOwnProperty.call(iterable, index)"); } if (conditions.length) {
__p += ' if (' +
(conditions.join(' && ')) +
') {\n ';
}
__p +=
(obj.loop) +
'; ';
if (conditions.length) {
__p += '\n }';
}
__p += '\n } ';
if (support.nonEnumShadows) {
__p += '\n\n if (iterable !== objectProto) {\n var ctor = iterable.constructor,\n isProto = iterable === (ctor && ctor.prototype),\n className = iterable === stringProto ? stringClass : iterable === errorProto ? errorClass : toString.call(iterable),\n nonEnum = nonEnumProps[className];\n ';
for (k = 0; k < 7; k++) {
__p += '\n index = \'' +
(obj.shadowedProps[k]) +
'\';\n if ((!(isProto && nonEnum[index]) && hasOwnProperty.call(iterable, index))';
if (!obj.useHas) {
__p += ' || (!nonEnum[index] && iterable[index] !== objectProto[index])';
}
__p += ') {\n ' +
(obj.loop) +
';\n } ';
}
__p += '\n } ';
}
}
if (obj.array || support.nonEnumArgs) {
__p += '\n}';
}
__p +=
(obj.bottom) +
';\nreturn result';
return __p
};
/*--------------------------------------------------------------------------*/
/**
* The base implementation of `_.bind` that creates the bound function and
* sets its meta data.
*
* @private
* @param {Array} bindData The bind data array.
* @returns {Function} Returns the new bound function.
*/
function baseBind(bindData) {
var func = bindData[0],
partialArgs = bindData[2],
thisArg = bindData[4];
function bound() {
// `Function#bind` spec
// http://es5.github.io/#x15.3.4.5
if (partialArgs) {
// avoid `arguments` object deoptimizations by using `slice` instead
// of `Array.prototype.slice.call` and not assigning `arguments` to a
// variable as a ternary expression
var args = slice(partialArgs);
push.apply(args, arguments);
}
// mimic the constructor's `return` behavior
// http://es5.github.io/#x13.2.2
if (this instanceof bound) {
// ensure `new bound` is an instance of `func`
var thisBinding = baseCreate(func.prototype),
result = func.apply(thisBinding, args || arguments);
return isObject(result) ? result : thisBinding;
}
return func.apply(thisArg, args || arguments);
}
setBindData(bound, bindData);
return bound;
}
/**
* The base implementation of `_.clone` without argument juggling or support
* for `thisArg` binding.
*
* @private
* @param {*} value The value to clone.
* @param {boolean} [isDeep=false] Specify a deep clone.
* @param {Function} [callback] The function to customize cloning values.
* @param {Array} [stackA=[]] Tracks traversed source objects.
* @param {Array} [stackB=[]] Associates clones with source counterparts.
* @returns {*} Returns the cloned value.
*/
function baseClone(value, isDeep, callback, stackA, stackB) {
if (callback) {
var result = callback(value);
if (typeof result != 'undefined') {
return result;
}
}
// inspect [[Class]]
var isObj = isObject(value);
if (isObj) {
var className = toString.call(value);
if (!cloneableClasses[className] || (!support.nodeClass && isNode(value))) {
return value;
}
var ctor = ctorByClass[className];
switch (className) {
case boolClass:
case dateClass:
return new ctor(+value);
case numberClass:
case stringClass:
return new ctor(value);
case regexpClass:
result = ctor(value.source, reFlags.exec(value));
result.lastIndex = value.lastIndex;
return result;
}
} else {
return value;
}
var isArr = isArray(value);
if (isDeep) {
// check for circular references and return corresponding clone
var initedStack = !stackA;
stackA || (stackA = getArray());
stackB || (stackB = getArray());
var length = stackA.length;
while (length--) {
if (stackA[length] == value) {
return stackB[length];
}
}
result = isArr ? ctor(value.length) : {};
}
else {
result = isArr ? slice(value) : assign({}, value);
}
// add array properties assigned by `RegExp#exec`
if (isArr) {
if (hasOwnProperty.call(value, 'index')) {
result.index = value.index;
}
if (hasOwnProperty.call(value, 'input')) {
result.input = value.input;
}
}
// exit for shallow clone
if (!isDeep) {
return result;
}
// add the source value to the stack of traversed objects
// and associate it with its clone
stackA.push(value);
stackB.push(result);
// recursively populate clone (susceptible to call stack limits)
(isArr ? baseEach : forOwn)(value, function(objValue, key) {
result[key] = baseClone(objValue, isDeep, callback, stackA, stackB);
});
if (initedStack) {
releaseArray(stackA);
releaseArray(stackB);
}
return result;
}
/**
* The base implementation of `_.create` without support for assigning
* properties to the created object.
*
* @private
* @param {Object} prototype The object to inherit from.
* @returns {Object} Returns the new object.
*/
function baseCreate(prototype, properties) {
return isObject(prototype) ? nativeCreate(prototype) : {};
}
// fallback for browsers without `Object.create`
if (!nativeCreate) {
baseCreate = (function() {
function Object() {}
return function(prototype) {
if (isObject(prototype)) {
Object.prototype = prototype;
var result = new Object;
Object.prototype = null;
}
return result || context.Object();
};
}());
}
/**
* The base implementation of `_.createCallback` without support for creating
* "_.pluck" or "_.where" style callbacks.
*
* @private
* @param {*} [func=identity] The value to convert to a callback.
* @param {*} [thisArg] The `this` binding of the created callback.
* @param {number} [argCount] The number of arguments the callback accepts.
* @returns {Function} Returns a callback function.
*/
function baseCreateCallback(func, thisArg, argCount) {
if (typeof func != 'function') {
return identity;
}
// exit early for no `thisArg` or already bound by `Function#bind`
if (typeof thisArg == 'undefined' || !('prototype' in func)) {
return func;
}
var bindData = func.__bindData__;
if (typeof bindData == 'undefined') {
if (support.funcNames) {
bindData = !func.name;
}
bindData = bindData || !support.funcDecomp;
if (!bindData) {
var source = fnToString.call(func);
if (!support.funcNames) {
bindData = !reFuncName.test(source);
}
if (!bindData) {
// checks if `func` references the `this` keyword and stores the result
bindData = reThis.test(source);
setBindData(func, bindData);
}
}
}
// exit early if there are no `this` references or `func` is bound
if (bindData === false || (bindData !== true && bindData[1] & 1)) {
return func;
}
switch (argCount) {
case 1: return function(value) {
return func.call(thisArg, value);
};
case 2: return function(a, b) {
return func.call(thisArg, a, b);
};
case 3: return function(value, index, collection) {
return func.call(thisArg, value, index, collection);
};
case 4: return function(accumulator, value, index, collection) {
return func.call(thisArg, accumulator, value, index, collection);
};
}
return bind(func, thisArg);
}
/**
* The base implementation of `createWrapper` that creates the wrapper and
* sets its meta data.
*
* @private
* @param {Array} bindData The bind data array.
* @returns {Function} Returns the new function.
*/
function baseCreateWrapper(bindData) {
var func = bindData[0],
bitmask = bindData[1],
partialArgs = bindData[2],
partialRightArgs = bindData[3],
thisArg = bindData[4],
arity = bindData[5];
var isBind = bitmask & 1,
isBindKey = bitmask & 2,
isCurry = bitmask & 4,
isCurryBound = bitmask & 8,
key = func;
function bound() {
var thisBinding = isBind ? thisArg : this;
if (partialArgs) {
var args = slice(partialArgs);
push.apply(args, arguments);
}
if (partialRightArgs || isCurry) {
args || (args = slice(arguments));
if (partialRightArgs) {
push.apply(args, partialRightArgs);
}
if (isCurry && args.length < arity) {
bitmask |= 16 & ~32;
return baseCreateWrapper([func, (isCurryBound ? bitmask : bitmask & ~3), args, null, thisArg, arity]);
}
}
args || (args = arguments);
if (isBindKey) {
func = thisBinding[key];
}
if (this instanceof bound) {
thisBinding = baseCreate(func.prototype);
var result = func.apply(thisBinding, args);
return isObject(result) ? result : thisBinding;
}
return func.apply(thisBinding, args);
}
setBindData(bound, bindData);
return bound;
}
/**
* The base implementation of `_.difference` that accepts a single array
* of values to exclude.
*
* @private
* @param {Array} array The array to process.
* @param {Array} [values] The array of values to exclude.
* @returns {Array} Returns a new array of filtered values.
*/
function baseDifference(array, values) {
var index = -1,
indexOf = getIndexOf(),
length = array ? array.length : 0,
isLarge = length >= largeArraySize && indexOf === baseIndexOf,
result = [];
if (isLarge) {
var cache = createCache(values);
if (cache) {
indexOf = cacheIndexOf;
values = cache;
} else {
isLarge = false;
}
}
while (++index < length) {
var value = array[index];
if (indexOf(values, value) < 0) {
result.push(value);
}
}
if (isLarge) {
releaseObject(values);
}
return result;
}
/**
* The base implementation of `_.flatten` without support for callback
* shorthands or `thisArg` binding.
*
* @private
* @param {Array} array The array to flatten.
* @param {boolean} [isShallow=false] A flag to restrict flattening to a single level.
* @param {boolean} [isStrict=false] A flag to restrict flattening to arrays and `arguments` objects.
* @param {number} [fromIndex=0] The index to start from.
* @returns {Array} Returns a new flattened array.
*/
function baseFlatten(array, isShallow, isStrict, fromIndex) {
var index = (fromIndex || 0) - 1,
length = array ? array.length : 0,
result = [];
while (++index < length) {
var value = array[index];
if (value && typeof value == 'object' && typeof value.length == 'number'
&& (isArray(value) || isArguments(value))) {
// recursively flatten arrays (susceptible to call stack limits)
if (!isShallow) {
value = baseFlatten(value, isShallow, isStrict);
}
var valIndex = -1,
valLength = value.length,
resIndex = result.length;
result.length += valLength;
while (++valIndex < valLength) {
result[resIndex++] = value[valIndex];
}
} else if (!isStrict) {
result.push(value);
}
}
return result;
}
/**
* The base implementation of `_.isEqual`, without support for `thisArg` binding,
* that allows partial "_.where" style comparisons.
*
* @private
* @param {*} a The value to compare.
* @param {*} b The other value to compare.
* @param {Function} [callback] The function to customize comparing values.
* @param {Function} [isWhere=false] A flag to indicate performing partial comparisons.
* @param {Array} [stackA=[]] Tracks traversed `a` objects.
* @param {Array} [stackB=[]] Tracks traversed `b` objects.
* @returns {boolean} Returns `true` if the values are equivalent, else `false`.
*/
function baseIsEqual(a, b, callback, isWhere, stackA, stackB) {
// used to indicate that when comparing objects, `a` has at least the properties of `b`
if (callback) {
var result = callback(a, b);
if (typeof result != 'undefined') {
return !!result;
}
}
// exit early for identical values
if (a === b) {
// treat `+0` vs. `-0` as not equal
return a !== 0 || (1 / a == 1 / b);
}
var type = typeof a,
otherType = typeof b;
// exit early for unlike primitive values
if (a === a &&
!(a && objectTypes[type]) &&
!(b && objectTypes[otherType])) {
return false;
}
// exit early for `null` and `undefined` avoiding ES3's Function#call behavior
// http://es5.github.io/#x15.3.4.4
if (a == null || b == null) {
return a === b;
}
// compare [[Class]] names
var className = toString.call(a),
otherClass = toString.call(b);
if (className == argsClass) {
className = objectClass;
}
if (otherClass == argsClass) {
otherClass = objectClass;
}
if (className != otherClass) {
return false;
}
switch (className) {
case boolClass:
case dateClass:
// coerce dates and booleans to numbers, dates to milliseconds and booleans
// to `1` or `0` treating invalid dates coerced to `NaN` as not equal
return +a == +b;
case numberClass:
// treat `NaN` vs. `NaN` as equal
return (a != +a)
? b != +b
// but treat `+0` vs. `-0` as not equal
: (a == 0 ? (1 / a == 1 / b) : a == +b);
case regexpClass:
case stringClass:
// coerce regexes to strings (http://es5.github.io/#x15.10.6.4)
// treat string primitives and their corresponding object instances as equal
return a == String(b);
}
var isArr = className == arrayClass;
if (!isArr) {
// unwrap any `lodash` wrapped values
var aWrapped = hasOwnProperty.call(a, '__wrapped__'),
bWrapped = hasOwnProperty.call(b, '__wrapped__');
if (aWrapped || bWrapped) {
return baseIsEqual(aWrapped ? a.__wrapped__ : a, bWrapped ? b.__wrapped__ : b, callback, isWhere, stackA, stackB);
}
// exit for functions and DOM nodes
if (className != objectClass || (!support.nodeClass && (isNode(a) || isNode(b)))) {
return false;
}
// in older versions of Opera, `arguments` objects have `Array` constructors
var ctorA = !support.argsObject && isArguments(a) ? Object : a.constructor,
ctorB = !support.argsObject && isArguments(b) ? Object : b.constructor;
// non `Object` object instances with different constructors are not equal
if (ctorA != ctorB &&
!(isFunction(ctorA) && ctorA instanceof ctorA && isFunction(ctorB) && ctorB instanceof ctorB) &&
('constructor' in a && 'constructor' in b)
) {
return false;
}
}
// assume cyclic structures are equal
// the algorithm for detecting cyclic structures is adapted from ES 5.1
// section 15.12.3, abstract operation `JO` (http://es5.github.io/#x15.12.3)
var initedStack = !stackA;
stackA || (stackA = getArray());
stackB || (stackB = getArray());
var length = stackA.length;
while (length--) {
if (stackA[length] == a) {
return stackB[length] == b;
}
}
var size = 0;
result = true;
// add `a` and `b` to the stack of traversed objects
stackA.push(a);
stackB.push(b);
// recursively compare objects and arrays (susceptible to call stack limits)
if (isArr) {
// compare lengths to determine if a deep comparison is necessary
length = a.length;
size = b.length;
result = size == length;
if (result || isWhere) {
// deep compare the contents, ignoring non-numeric properties
while (size--) {
var index = length,
value = b[size];
if (isWhere) {
while (index--) {
if ((result = baseIsEqual(a[index], value, callback, isWhere, stackA, stackB))) {
break;
}
}
} else if (!(result = baseIsEqual(a[size], value, callback, isWhere, stackA, stackB))) {
break;
}
}
}
}
else {
// deep compare objects using `forIn`, instead of `forOwn`, to avoid `Object.keys`
// which, in this case, is more costly
forIn(b, function(value, key, b) {
if (hasOwnProperty.call(b, key)) {
// count the number of properties.
size++;
// deep compare each property value.
return (result = hasOwnProperty.call(a, key) && baseIsEqual(a[key], value, callback, isWhere, stackA, stackB));
}
});
if (result && !isWhere) {
// ensure both objects have the same number of properties
forIn(a, function(value, key, a) {
if (hasOwnProperty.call(a, key)) {
// `size` will be `-1` if `a` has more properties than `b`
return (result = --size > -1);
}
});
}
}
stackA.pop();
stackB.pop();
if (initedStack) {
releaseArray(stackA);
releaseArray(stackB);
}
return result;
}
/**
* The base implementation of `_.merge` without argument juggling or support
* for `thisArg` binding.
*
* @private
* @param {Object} object The destination object.
* @param {Object} source The source object.
* @param {Function} [callback] The function to customize merging properties.
* @param {Array} [stackA=[]] Tracks traversed source objects.
* @param {Array} [stackB=[]] Associates values with source counterparts.
*/
function baseMerge(object, source, callback, stackA, stackB) {
(isArray(source) ? forEach : forOwn)(source, function(source, key) {
var found,
isArr,
result = source,
value = object[key];
if (source && ((isArr = isArray(source)) || isPlainObject(source))) {
// avoid merging previously merged cyclic sources
var stackLength = stackA.length;
while (stackLength--) {
if ((found = stackA[stackLength] == source)) {
value = stackB[stackLength];
break;
}
}
if (!found) {
var isShallow;
if (callback) {
result = callback(value, source);
if ((isShallow = typeof result != 'undefined')) {
value = result;
}
}
if (!isShallow) {
value = isArr
? (isArray(value) ? value : [])
: (isPlainObject(value) ? value : {});
}
// add `source` and associated `value` to the stack of traversed objects
stackA.push(source);
stackB.push(value);
// recursively merge objects and arrays (susceptible to call stack limits)
if (!isShallow) {
baseMerge(value, source, callback, stackA, stackB);
}
}
}
else {
if (callback) {
result = callback(value, source);
if (typeof result == 'undefined') {
result = source;
}
}
if (typeof result != 'undefined') {
value = result;
}
}
object[key] = value;
});
}
/**
* The base implementation of `_.random` without argument juggling or support
* for returning floating-point numbers.
*
* @private
* @param {number} min The minimum possible value.
* @param {number} max The maximum possible value.
* @returns {number} Returns a random number.
*/
function baseRandom(min, max) {
return min + floor(nativeRandom() * (max - min + 1));
}
/**
* The base implementation of `_.uniq` without support for callback shorthands
* or `thisArg` binding.
*
* @private
* @param {Array} array The array to process.
* @param {boolean} [isSorted=false] A flag to indicate that `array` is sorted.
* @param {Function} [callback] The function called per iteration.
* @returns {Array} Returns a duplicate-value-free array.
*/
function baseUniq(array, isSorted, callback) {
var index = -1,
indexOf = getIndexOf(),
length = array ? array.length : 0,
result = [];
var isLarge = !isSorted && length >= largeArraySize && indexOf === baseIndexOf,
seen = (callback || isLarge) ? getArray() : result;
if (isLarge) {
var cache = createCache(seen);
indexOf = cacheIndexOf;
seen = cache;
}
while (++index < length) {
var value = array[index],
computed = callback ? callback(value, index, array) : value;
if (isSorted
? !index || seen[seen.length - 1] !== computed
: indexOf(seen, computed) < 0
) {
if (callback || isLarge) {
seen.push(computed);
}
result.push(value);
}
}
if (isLarge) {
releaseArray(seen.array);
releaseObject(seen);
} else if (callback) {
releaseArray(seen);
}
return result;
}
/**
* Creates a function that aggregates a collection, creating an object composed
* of keys generated from the results of running each element of the collection
* through a callback. The given `setter` function sets the keys and values
* of the composed object.
*
* @private
* @param {Function} setter The setter function.
* @returns {Function} Returns the new aggregator function.
*/
function createAggregator(setter) {
return function(collection, callback, thisArg) {
var result = {};
callback = lodash.createCallback(callback, thisArg, 3);
if (isArray(collection)) {
var index = -1,
length = collection.length;
while (++index < length) {
var value = collection[index];
setter(result, value, callback(value, index, collection), collection);
}
} else {
baseEach(collection, function(value, key, collection) {
setter(result, value, callback(value, key, collection), collection);
});
}
return result;
};
}
/**
* Creates a function that, when called, either curries or invokes `func`
* with an optional `this` binding and partially applied arguments.
*
* @private
* @param {Function|string} func The function or method name to reference.
* @param {number} bitmask The bitmask of method flags to compose.
* The bitmask may be composed of the following flags:
* 1 - `_.bind`
* 2 - `_.bindKey`
* 4 - `_.curry`
* 8 - `_.curry` (bound)
* 16 - `_.partial`
* 32 - `_.partialRight`
* @param {Array} [partialArgs] An array of arguments to prepend to those
* provided to the new function.
* @param {Array} [partialRightArgs] An array of arguments to append to those
* provided to the new function.
* @param {*} [thisArg] The `this` binding of `func`.
* @param {number} [arity] The arity of `func`.
* @returns {Function} Returns the new function.
*/
function createWrapper(func, bitmask, partialArgs, partialRightArgs, thisArg, arity) {
var isBind = bitmask & 1,
isBindKey = bitmask & 2,
isCurry = bitmask & 4,
isCurryBound = bitmask & 8,
isPartial = bitmask & 16,
isPartialRight = bitmask & 32;
if (!isBindKey && !isFunction(func)) {
throw new TypeError;
}
if (isPartial && !partialArgs.length) {
bitmask &= ~16;
isPartial = partialArgs = false;
}
if (isPartialRight && !partialRightArgs.length) {
bitmask &= ~32;
isPartialRight = partialRightArgs = false;
}
var bindData = func && func.__bindData__;
if (bindData && bindData !== true) {
// clone `bindData`
bindData = slice(bindData);
if (bindData[2]) {
bindData[2] = slice(bindData[2]);
}
if (bindData[3]) {
bindData[3] = slice(bindData[3]);
}
// set `thisBinding` is not previously bound
if (isBind && !(bindData[1] & 1)) {
bindData[4] = thisArg;
}
// set if previously bound but not currently (subsequent curried functions)
if (!isBind && bindData[1] & 1) {
bitmask |= 8;
}
// set curried arity if not yet set
if (isCurry && !(bindData[1] & 4)) {
bindData[5] = arity;
}
// append partial left arguments
if (isPartial) {
push.apply(bindData[2] || (bindData[2] = []), partialArgs);
}
// append partial right arguments
if (isPartialRight) {
unshift.apply(bindData[3] || (bindData[3] = []), partialRightArgs);
}
// merge flags
bindData[1] |= bitmask;
return createWrapper.apply(null, bindData);
}
// fast path for `_.bind`
var creater = (bitmask == 1 || bitmask === 17) ? baseBind : baseCreateWrapper;
return creater([func, bitmask, partialArgs, partialRightArgs, thisArg, arity]);
}
/**
* Creates compiled iteration functions.
*
* @private
* @param {...Object} [options] The compile options object(s).
* @param {string} [options.array] Code to determine if the iterable is an array or array-like.
* @param {boolean} [options.useHas] Specify using `hasOwnProperty` checks in the object loop.
* @param {Function} [options.keys] A reference to `_.keys` for use in own property iteration.
* @param {string} [options.args] A comma separated string of iteration function arguments.
* @param {string} [options.top] Code to execute before the iteration branches.
* @param {string} [options.loop] Code to execute in the object loop.
* @param {string} [options.bottom] Code to execute after the iteration branches.
* @returns {Function} Returns the compiled function.
*/
function createIterator() {
// data properties
iteratorData.shadowedProps = shadowedProps;
// iterator options
iteratorData.array = iteratorData.bottom = iteratorData.loop = iteratorData.top = '';
iteratorData.init = 'iterable';
iteratorData.useHas = true;
// merge options into a template data object
for (var object, index = 0; object = arguments[index]; index++) {
for (var key in object) {
iteratorData[key] = object[key];
}
}
var args = iteratorData.args;
iteratorData.firstArg = /^[^,]+/.exec(args)[0];
// create the function factory
var factory = Function(
'baseCreateCallback, errorClass, errorProto, hasOwnProperty, ' +
'indicatorObject, isArguments, isArray, isString, keys, objectProto, ' +
'objectTypes, nonEnumProps, stringClass, stringProto, toString',
'return function(' + args + ') {\n' + iteratorTemplate(iteratorData) + '\n}'
);
// return the compiled function
return factory(
baseCreateCallback, errorClass, errorProto, hasOwnProperty,
indicatorObject, isArguments, isArray, isString, iteratorData.keys, objectProto,
objectTypes, nonEnumProps, stringClass, stringProto, toString
);
}
/**
* Used by `escape` to convert characters to HTML entities.
*
* @private
* @param {string} match The matched character to escape.
* @returns {string} Returns the escaped character.
*/
function escapeHtmlChar(match) {
return htmlEscapes[match];
}
/**
* Gets the appropriate "indexOf" function. If the `_.indexOf` method is
* customized, this method returns the custom method, otherwise it returns
* the `baseIndexOf` function.
*
* @private
* @returns {Function} Returns the "indexOf" function.
*/
function getIndexOf() {
var result = (result = lodash.indexOf) === indexOf ? baseIndexOf : result;
return result;
}
/**
* Checks if `value` is a native function.
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if the `value` is a native function, else `false`.
*/
function isNative(value) {
return typeof value == 'function' && reNative.test(value);
}
/**
* Sets `this` binding data on a given function.
*
* @private
* @param {Function} func The function to set data on.
* @param {Array} value The data array to set.
*/
var setBindData = !defineProperty ? noop : function(func, value) {
descriptor.value = value;
defineProperty(func, '__bindData__', descriptor);
};
/**
* A fallback implementation of `isPlainObject` which checks if a given value
* is an object created by the `Object` constructor, assuming objects created
* by the `Object` constructor have no inherited enumerable properties and that
* there are no `Object.prototype` extensions.
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
*/
function shimIsPlainObject(value) {
var ctor,
result;
// avoid non Object objects, `arguments` objects, and DOM elements
if (!(value && toString.call(value) == objectClass) ||
(ctor = value.constructor, isFunction(ctor) && !(ctor instanceof ctor)) ||
(!support.argsClass && isArguments(value)) ||
(!support.nodeClass && isNode(value))) {
return false;
}
// IE < 9 iterates inherited properties before own properties. If the first
// iterated property is an object's own property then there are no inherited
// enumerable properties.
if (support.ownLast) {
forIn(value, function(value, key, object) {
result = hasOwnProperty.call(object, key);
return false;
});
return result !== false;
}
// In most environments an object's own properties are iterated before
// its inherited properties. If the last iterated property is an object's
// own property then there are no inherited enumerable properties.
forIn(value, function(value, key) {
result = key;
});
return typeof result == 'undefined' || hasOwnProperty.call(value, result);
}
/**
* Used by `unescape` to convert HTML entities to characters.
*
* @private
* @param {string} match The matched character to unescape.
* @returns {string} Returns the unescaped character.
*/
function unescapeHtmlChar(match) {
return htmlUnescapes[match];
}
/*--------------------------------------------------------------------------*/
/**
* Checks if `value` is an `arguments` object.
*
* @static
* @memberOf _
* @category Objects
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if the `value` is an `arguments` object, else `false`.
* @example
*
* (function() { return _.isArguments(arguments); })(1, 2, 3);
* // => true
*
* _.isArguments([1, 2, 3]);
* // => false
*/
function isArguments(value) {
return value && typeof value == 'object' && typeof value.length == 'number' &&
toString.call(value) == argsClass || false;
}
// fallback for browsers that can't detect `arguments` objects by [[Class]]
if (!support.argsClass) {
isArguments = function(value) {
return value && typeof value == 'object' && typeof value.length == 'number' &&
hasOwnProperty.call(value, 'callee') && !propertyIsEnumerable.call(value, 'callee') || false;
};
}
/**
* Checks if `value` is an array.
*
* @static
* @memberOf _
* @type Function
* @category Objects
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if the `value` is an array, else `false`.
* @example
*
* (function() { return _.isArray(arguments); })();
* // => false
*
* _.isArray([1, 2, 3]);
* // => true
*/
var isArray = nativeIsArray || function(value) {
return value && typeof value == 'object' && typeof value.length == 'number' &&
toString.call(value) == arrayClass || false;
};
/**
* A fallback implementation of `Object.keys` which produces an array of the
* given object's own enumerable property names.
*
* @private
* @type Function
* @param {Object} object The object to inspect.
* @returns {Array} Returns an array of property names.
*/
var shimKeys = createIterator({
'args': 'object',
'init': '[]',
'top': 'if (!(objectTypes[typeof object])) return result',
'loop': 'result.push(index)'
});
/**
* Creates an array composed of the own enumerable property names of an object.
*
* @static
* @memberOf _
* @category Objects
* @param {Object} object The object to inspect.
* @returns {Array} Returns an array of property names.
* @example
*
* _.keys({ 'one': 1, 'two': 2, 'three': 3 });
* // => ['one', 'two', 'three'] (property order is not guaranteed across environments)
*/
var keys = !nativeKeys ? shimKeys : function(object) {
if (!isObject(object)) {
return [];
}
if ((support.enumPrototypes && typeof object == 'function') ||
(support.nonEnumArgs && object.length && isArguments(object))) {
return shimKeys(object);
}
return nativeKeys(object);
};
/** Reusable iterator options shared by `each`, `forIn`, and `forOwn` */
var eachIteratorOptions = {
'args': 'collection, callback, thisArg',
'top': "callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3)",
'array': "typeof length == 'number'",
'keys': keys,
'loop': 'if (callback(iterable[index], index, collection) === false) return result'
};
/** Reusable iterator options for `assign` and `defaults` */
var defaultsIteratorOptions = {
'args': 'object, source, guard',
'top':
'var args = arguments,\n' +
' argsIndex = 0,\n' +
" argsLength = typeof guard == 'number' ? 2 : args.length;\n" +
'while (++argsIndex < argsLength) {\n' +
' iterable = args[argsIndex];\n' +
' if (iterable && objectTypes[typeof iterable]) {',
'keys': keys,
'loop': "if (typeof result[index] == 'undefined') result[index] = iterable[index]",
'bottom': ' }\n}'
};
/** Reusable iterator options for `forIn` and `forOwn` */
var forOwnIteratorOptions = {
'top': 'if (!objectTypes[typeof iterable]) return result;\n' + eachIteratorOptions.top,
'array': false
};
/**
* Used to convert characters to HTML entities:
*
* Though the `>` character is escaped for symmetry, characters like `>` and `/`
* don't require escaping in HTML and have no special meaning unless they're part
* of a tag or an unquoted attribute value.
* http://mathiasbynens.be/notes/ambiguous-ampersands (under "semi-related fun fact")
*/
var htmlEscapes = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#39;'
};
/** Used to convert HTML entities to characters */
var htmlUnescapes = invert(htmlEscapes);
/** Used to match HTML entities and HTML characters */
var reEscapedHtml = RegExp('(' + keys(htmlUnescapes).join('|') + ')', 'g'),
reUnescapedHtml = RegExp('[' + keys(htmlEscapes).join('') + ']', 'g');
/**
* A function compiled to iterate `arguments` objects, arrays, objects, and
* strings consistenly across environments, executing the callback for each
* element in the collection. The callback is bound to `thisArg` and invoked
* with three arguments; (value, index|key, collection). Callbacks may exit
* iteration early by explicitly returning `false`.
*
* @private
* @type Function
* @param {Array|Object|string} collection The collection to iterate over.
* @param {Function} [callback=identity] The function called per iteration.
* @param {*} [thisArg] The `this` binding of `callback`.
* @returns {Array|Object|string} Returns `collection`.
*/
var baseEach = createIterator(eachIteratorOptions);
/*--------------------------------------------------------------------------*/
/**
* Assigns own enumerable properties of source object(s) to the destination
* object. Subsequent sources will overwrite property assignments of previous
* sources. If a callback is provided it will be executed to produce the
* assigned values. The callback is bound to `thisArg` and invoked with two
* arguments; (objectValue, sourceValue).
*
* @static
* @memberOf _
* @type Function
* @alias extend
* @category Objects
* @param {Object} object The destination object.
* @param {...Object} [source] The source objects.
* @param {Function} [callback] The function to customize assigning values.
* @param {*} [thisArg] The `this` binding of `callback`.
* @returns {Object} Returns the destination object.
* @example
*
* _.assign({ 'name': 'fred' }, { 'employer': 'slate' });
* // => { 'name': 'fred', 'employer': 'slate' }
*
* var defaults = _.partialRight(_.assign, function(a, b) {
* return typeof a == 'undefined' ? b : a;
* });
*
* var object = { 'name': 'barney' };
* defaults(object, { 'name': 'fred', 'employer': 'slate' });
* // => { 'name': 'barney', 'employer': 'slate' }
*/
var assign = createIterator(defaultsIteratorOptions, {
'top':
defaultsIteratorOptions.top.replace(';',
';\n' +
"if (argsLength > 3 && typeof args[argsLength - 2] == 'function') {\n" +
' var callback = baseCreateCallback(args[--argsLength - 1], args[argsLength--], 2);\n' +
"} else if (argsLength > 2 && typeof args[argsLength - 1] == 'function') {\n" +
' callback = args[--argsLength];\n' +
'}'
),
'loop': 'result[index] = callback ? callback(result[index], iterable[index]) : iterable[index]'
});
/**
* Creates a clone of `value`. If `isDeep` is `true` nested objects will also
* be cloned, otherwise they will be assigned by reference. If a callback
* is provided it will be executed to produce the cloned values. If the
* callback returns `undefined` cloning will be handled by the method instead.
* The callback is bound to `thisArg` and invoked with one argument; (value).
*
* @static
* @memberOf _
* @category Objects
* @param {*} value The value to clone.
* @param {boolean} [isDeep=false] Specify a deep clone.
* @param {Function} [callback] The function to customize cloning values.
* @param {*} [thisArg] The `this` binding of `callback`.
* @returns {*} Returns the cloned value.
* @example
*
* var characters = [
* { 'name': 'barney', 'age': 36 },
* { 'name': 'fred', 'age': 40 }
* ];
*
* var shallow = _.clone(characters);
* shallow[0] === characters[0];
* // => true
*
* var deep = _.clone(characters, true);
* deep[0] === characters[0];
* // => false
*
* _.mixin({
* 'clone': _.partialRight(_.clone, function(value) {
* return _.isElement(value) ? value.cloneNode(false) : undefined;
* })
* });
*
* var clone = _.clone(document.body);
* clone.childNodes.length;
* // => 0
*/
function clone(value, isDeep, callback, thisArg) {
// allows working with "Collections" methods without using their `index`
// and `collection` arguments for `isDeep` and `callback`
if (typeof isDeep != 'boolean' && isDeep != null) {
thisArg = callback;
callback = isDeep;
isDeep = false;
}
return baseClone(value, isDeep, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 1));
}
/**
* Creates a deep clone of `value`. If a callback is provided it will be
* executed to produce the cloned values. If the callback returns `undefined`
* cloning will be handled by the method instead. The callback is bound to
* `thisArg` and invoked with one argument; (value).
*
* Note: This method is loosely based on the structured clone algorithm. Functions
* and DOM nodes are **not** cloned. The enumerable properties of `arguments` objects and
* objects created by constructors other than `Object` are cloned to plain `Object` objects.
* See http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm.
*
* @static
* @memberOf _
* @category Objects
* @param {*} value The value to deep clone.
* @param {Function} [callback] The function to customize cloning values.
* @param {*} [thisArg] The `this` binding of `callback`.
* @returns {*} Returns the deep cloned value.
* @example
*
* var characters = [
* { 'name': 'barney', 'age': 36 },
* { 'name': 'fred', 'age': 40 }
* ];
*
* var deep = _.cloneDeep(characters);
* deep[0] === characters[0];
* // => false
*
* var view = {
* 'label': 'docs',
* 'node': element
* };
*
* var clone = _.cloneDeep(view, function(value) {
* return _.isElement(value) ? value.cloneNode(true) : undefined;
* });
*
* clone.node == view.node;
* // => false
*/
function cloneDeep(value, callback, thisArg) {
return baseClone(value, true, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 1));
}
/**
* Creates an object that inherits from the given `prototype` object. If a
* `properties` object is provided its own enumerable properties are assigned
* to the created object.
*
* @static
* @memberOf _
* @category Objects
* @param {Object} prototype The object to inherit from.
* @param {Object} [properties] The properties to assign to the object.
* @returns {Object} Returns the new object.
* @example
*
* function Shape() {
* this.x = 0;
* this.y = 0;
* }
*
* function Circle() {
* Shape.call(this);
* }
*
* Circle.prototype = _.create(Shape.prototype, { 'constructor': Circle });
*
* var circle = new Circle;
* circle instanceof Circle;
* // => true
*
* circle instanceof Shape;
* // => true
*/
function create(prototype, properties) {
var result = baseCreate(prototype);
return properties ? assign(result, properties) : result;
}
/**
* Assigns own enumerable properties of source object(s) to the destination
* object for all destination properties that resolve to `undefined`. Once a
* property is set, additional defaults of the same property will be ignored.
*
* @static
* @memberOf _
* @type Function
* @category Objects
* @param {Object} object The destination object.
* @param {...Object} [source] The source objects.
* @param- {Object} [guard] Allows working with `_.reduce` without using its
* `key` and `object` arguments as sources.
* @returns {Object} Returns the destination object.
* @example
*
* var object = { 'name': 'barney' };
* _.defaults(object, { 'name': 'fred', 'employer': 'slate' });
* // => { 'name': 'barney', 'employer': 'slate' }
*/
var defaults = createIterator(defaultsIteratorOptions);
/**
* This method is like `_.findIndex` except that it returns the key of the
* first element that passes the callback check, instead of the element itself.
*
* If a property name is provided for `callback` the created "_.pluck" style
* callback will return the property value of the given element.
*
* If an object is provided for `callback` the created "_.where" style callback
* will return `true` for elements that have the properties of the given object,
* else `false`.
*
* @static
* @memberOf _
* @category Objects
* @param {Object} object The object to search.
* @param {Function|Object|string} [callback=identity] The function called per
* iteration. If a property name or object is provided it will be used to
* create a "_.pluck" or "_.where" style callback, respectively.
* @param {*} [thisArg] The `this` binding of `callback`.
* @returns {string|undefined} Returns the key of the found element, else `undefined`.
* @example
*
* var characters = {
* 'barney': { 'age': 36, 'blocked': false },
* 'fred': { 'age': 40, 'blocked': true },
* 'pebbles': { 'age': 1, 'blocked': false }
* };
*
* _.findKey(characters, function(chr) {
* return chr.age < 40;
* });
* // => 'barney' (property order is not guaranteed across environments)
*
* // using "_.where" callback shorthand
* _.findKey(characters, { 'age': 1 });
* // => 'pebbles'
*
* // using "_.pluck" callback shorthand
* _.findKey(characters, 'blocked');
* // => 'fred'
*/
function findKey(object, callback, thisArg) {
var result;
callback = lodash.createCallback(callback, thisArg, 3);
forOwn(object, function(value, key, object) {
if (callback(value, key, object)) {
result = key;
return false;
}
});
return result;
}
/**
* This method is like `_.findKey` except that it iterates over elements
* of a `collection` in the opposite order.
*
* If a property name is provided for `callback` the created "_.pluck" style
* callback will return the property value of the given element.
*
* If an object is provided for `callback` the created "_.where" style callback
* will return `true` for elements that have the properties of the given object,
* else `false`.
*
* @static
* @memberOf _
* @category Objects
* @param {Object} object The object to search.
* @param {Function|Object|string} [callback=identity] The function called per
* iteration. If a property name or object is provided it will be used to
* create a "_.pluck" or "_.where" style callback, respectively.
* @param {*} [thisArg] The `this` binding of `callback`.
* @returns {string|undefined} Returns the key of the found element, else `undefined`.
* @example
*
* var characters = {
* 'barney': { 'age': 36, 'blocked': true },
* 'fred': { 'age': 40, 'blocked': false },
* 'pebbles': { 'age': 1, 'blocked': true }
* };
*
* _.findLastKey(characters, function(chr) {
* return chr.age < 40;
* });
* // => returns `pebbles`, assuming `_.findKey` returns `barney`
*
* // using "_.where" callback shorthand
* _.findLastKey(characters, { 'age': 40 });
* // => 'fred'
*
* // using "_.pluck" callback shorthand
* _.findLastKey(characters, 'blocked');
* // => 'pebbles'
*/
function findLastKey(object, callback, thisArg) {
var result;
callback = lodash.createCallback(callback, thisArg, 3);
forOwnRight(object, function(value, key, object) {
if (callback(value, key, object)) {
result = key;
return false;
}
});
return result;
}
/**
* Iterates over own and inherited enumerable properties of an object,
* executing the callback for each property. The callback is bound to `thisArg`
* and invoked with three arguments; (value, key, object). Callbacks may exit
* iteration early by explicitly returning `false`.
*
* @static
* @memberOf _
* @type Function
* @category Objects
* @param {Object} object The object to iterate over.
* @param {Function} [callback=identity] The function called per iteration.
* @param {*} [thisArg] The `this` binding of `callback`.
* @returns {Object} Returns `object`.
* @example
*
* function Shape() {
* this.x = 0;
* this.y = 0;
* }
*
* Shape.prototype.move = function(x, y) {
* this.x += x;
* this.y += y;
* };
*
* _.forIn(new Shape, function(value, key) {
* console.log(key);
* });
* // => logs 'x', 'y', and 'move' (property order is not guaranteed across environments)
*/
var forIn = createIterator(eachIteratorOptions, forOwnIteratorOptions, {
'useHas': false
});
/**
* This method is like `_.forIn` except that it iterates over elements
* of a `collection` in the opposite order.
*
* @static
* @memberOf _
* @category Objects
* @param {Object} object The object to iterate over.
* @param {Function} [callback=identity] The function called per iteration.
* @param {*} [thisArg] The `this` binding of `callback`.
* @returns {Object} Returns `object`.
* @example
*
* function Shape() {
* this.x = 0;
* this.y = 0;
* }
*
* Shape.prototype.move = function(x, y) {
* this.x += x;
* this.y += y;
* };
*
* _.forInRight(new Shape, function(value, key) {
* console.log(key);
* });
* // => logs 'move', 'y', and 'x' assuming `_.forIn ` logs 'x', 'y', and 'move'
*/
function forInRight(object, callback, thisArg) {
var pairs = [];
forIn(object, function(value, key) {
pairs.push(key, value);
});
var length = pairs.length;
callback = baseCreateCallback(callback, thisArg, 3);
while (length--) {
if (callback(pairs[length--], pairs[length], object) === false) {
break;
}
}
return object;
}
/**
* Iterates over own enumerable properties of an object, executing the callback
* for each property. The callback is bound to `thisArg` and invoked with three
* arguments; (value, key, object). Callbacks may exit iteration early by
* explicitly returning `false`.
*
* @static
* @memberOf _
* @type Function
* @category Objects
* @param {Object} object The object to iterate over.
* @param {Function} [callback=identity] The function called per iteration.
* @param {*} [thisArg] The `this` binding of `callback`.
* @returns {Object} Returns `object`.
* @example
*
* _.forOwn({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) {
* console.log(key);
* });
* // => logs '0', '1', and 'length' (property order is not guaranteed across environments)
*/
var forOwn = createIterator(eachIteratorOptions, forOwnIteratorOptions);
/**
* This method is like `_.forOwn` except that it iterates over elements
* of a `collection` in the opposite order.
*
* @static
* @memberOf _
* @category Objects
* @param {Object} object The object to iterate over.
* @param {Function} [callback=identity] The function called per iteration.
* @param {*} [thisArg] The `this` binding of `callback`.
* @returns {Object} Returns `object`.
* @example
*
* _.forOwnRight({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) {
* console.log(key);
* });
* // => logs 'length', '1', and '0' assuming `_.forOwn` logs '0', '1', and 'length'
*/
function forOwnRight(object, callback, thisArg) {
var props = keys(object),
length = props.length;
callback = baseCreateCallback(callback, thisArg, 3);
while (length--) {
var key = props[length];
if (callback(object[key], key, object) === false) {
break;
}
}
return object;
}
/**
* Creates a sorted array of property names of all enumerable properties,
* own and inherited, of `object` that have function values.
*
* @static
* @memberOf _
* @alias methods
* @category Objects
* @param {Object} object The object to inspect.
* @returns {Array} Returns an array of property names that have function values.
* @example
*
* _.functions(_);
* // => ['all', 'any', 'bind', 'bindAll', 'clone', 'compact', 'compose', ...]
*/
function functions(object) {
var result = [];
forIn(object, function(value, key) {
if (isFunction(value)) {
result.push(key);
}
});
return result.sort();
}
/**
* Checks if the specified property name exists as a direct property of `object`,
* instead of an inherited property.
*
* @static
* @memberOf _
* @category Objects
* @param {Object} object The object to inspect.
* @param {string} key The name of the property to check.
* @returns {boolean} Returns `true` if key is a direct property, else `false`.
* @example
*
* _.has({ 'a': 1, 'b': 2, 'c': 3 }, 'b');
* // => true
*/
function has(object, key) {
return object ? hasOwnProperty.call(object, key) : false;
}
/**
* Creates an object composed of the inverted keys and values of the given object.
*
* @static
* @memberOf _
* @category Objects
* @param {Object} object The object to invert.
* @returns {Object} Returns the created inverted object.
* @example
*
* _.invert({ 'first': 'fred', 'second': 'barney' });
* // => { 'fred': 'first', 'barney': 'second' }
*/
function invert(object) {
var index = -1,
props = keys(object),
length = props.length,
result = {};
while (++index < length) {
var key = props[index];
result[object[key]] = key;
}
return result;
}
/**
* Checks if `value` is a boolean value.
*
* @static
* @memberOf _
* @category Objects
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if the `value` is a boolean value, else `false`.
* @example
*
* _.isBoolean(null);
* // => false
*/
function isBoolean(value) {
return value === true || value === false ||
value && typeof value == 'object' && toString.call(value) == boolClass || false;
}
/**
* Checks if `value` is a date.
*
* @static
* @memberOf _
* @category Objects
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if the `value` is a date, else `false`.
* @example
*
* _.isDate(new Date);
* // => true
*/
function isDate(value) {
return value && typeof value == 'object' && toString.call(value) == dateClass || false;
}
/**
* Checks if `value` is a DOM element.
*
* @static
* @memberOf _
* @category Objects
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if the `value` is a DOM element, else `false`.
* @example
*
* _.isElement(document.body);
* // => true
*/
function isElement(value) {
return value && value.nodeType === 1 || false;
}
/**
* Checks if `value` is empty. Arrays, strings, or `arguments` objects with a
* length of `0` and objects with no own enumerable properties are considered
* "empty".
*
* @static
* @memberOf _
* @category Objects
* @param {Array|Object|string} value The value to inspect.
* @returns {boolean} Returns `true` if the `value` is empty, else `false`.
* @example
*
* _.isEmpty([1, 2, 3]);
* // => false
*
* _.isEmpty({});
* // => true
*
* _.isEmpty('');
* // => true
*/
function isEmpty(value) {
var result = true;
if (!value) {
return result;
}
var className = toString.call(value),
length = value.length;
if ((className == arrayClass || className == stringClass ||
(support.argsClass ? className == argsClass : isArguments(value))) ||
(className == objectClass && typeof length == 'number' && isFunction(value.splice))) {
return !length;
}
forOwn(value, function() {
return (result = false);
});
return result;
}
/**
* Performs a deep comparison between two values to determine if they are
* equivalent to each other. If a callback is provided it will be executed
* to compare values. If the callback returns `undefined` comparisons will
* be handled by the method instead. The callback is bound to `thisArg` and
* invoked with two arguments; (a, b).
*
* @static
* @memberOf _
* @category Objects
* @param {*} a The value to compare.
* @param {*} b The other value to compare.
* @param {Function} [callback] The function to customize comparing values.
* @param {*} [thisArg] The `this` binding of `callback`.
* @returns {boolean} Returns `true` if the values are equivalent, else `false`.
* @example
*
* var object = { 'name': 'fred' };
* var copy = { 'name': 'fred' };
*
* object == copy;
* // => false
*
* _.isEqual(object, copy);
* // => true
*
* var words = ['hello', 'goodbye'];
* var otherWords = ['hi', 'goodbye'];
*
* _.isEqual(words, otherWords, function(a, b) {
* var reGreet = /^(?:hello|hi)$/i,
* aGreet = _.isString(a) && reGreet.test(a),
* bGreet = _.isString(b) && reGreet.test(b);
*
* return (aGreet || bGreet) ? (aGreet == bGreet) : undefined;
* });
* // => true
*/
function isEqual(a, b, callback, thisArg) {
return baseIsEqual(a, b, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 2));
}
/**
* Checks if `value` is, or can be coerced to, a finite number.
*
* Note: This is not the same as native `isFinite` which will return true for
* booleans and empty strings. See http://es5.github.io/#x15.1.2.5.
*
* @static
* @memberOf _
* @category Objects
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if the `value` is finite, else `false`.
* @example
*
* _.isFinite(-101);
* // => true
*
* _.isFinite('10');
* // => true
*
* _.isFinite(true);
* // => false
*
* _.isFinite('');
* // => false
*
* _.isFinite(Infinity);
* // => false
*/
function isFinite(value) {
return nativeIsFinite(value) && !nativeIsNaN(parseFloat(value));
}
/**
* Checks if `value` is a function.
*
* @static
* @memberOf _
* @category Objects
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if the `value` is a function, else `false`.
* @example
*
* _.isFunction(_);
* // => true
*/
function isFunction(value) {
return typeof value == 'function';
}
// fallback for older versions of Chrome and Safari
if (isFunction(/x/)) {
isFunction = function(value) {
return typeof value == 'function' && toString.call(value) == funcClass;
};
}
/**
* Checks if `value` is the language type of Object.
* (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
*
* @static
* @memberOf _
* @category Objects
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if the `value` is an object, else `false`.
* @example
*
* _.isObject({});
* // => true
*
* _.isObject([1, 2, 3]);
* // => true
*
* _.isObject(1);
* // => false
*/
function isObject(value) {
// check if the value is the ECMAScript language type of Object
// http://es5.github.io/#x8
// and avoid a V8 bug
// http://code.google.com/p/v8/issues/detail?id=2291
return !!(value && objectTypes[typeof value]);
}
/**
* Checks if `value` is `NaN`.
*
* Note: This is not the same as native `isNaN` which will return `true` for
* `undefined` and other non-numeric values. See http://es5.github.io/#x15.1.2.4.
*
* @static
* @memberOf _
* @category Objects
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if the `value` is `NaN`, else `false`.
* @example
*
* _.isNaN(NaN);
* // => true
*
* _.isNaN(new Number(NaN));
* // => true
*
* isNaN(undefined);
* // => true
*
* _.isNaN(undefined);
* // => false
*/
function isNaN(value) {
// `NaN` as a primitive is the only value that is not equal to itself
// (perform the [[Class]] check first to avoid errors with some host objects in IE)
return isNumber(value) && value != +value;
}
/**
* Checks if `value` is `null`.
*
* @static
* @memberOf _
* @category Objects
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if the `value` is `null`, else `false`.
* @example
*
* _.isNull(null);
* // => true
*
* _.isNull(undefined);
* // => false
*/
function isNull(value) {
return value === null;
}
/**
* Checks if `value` is a number.
*
* Note: `NaN` is considered a number. See http://es5.github.io/#x8.5.
*
* @static
* @memberOf _
* @category Objects
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if the `value` is a number, else `false`.
* @example
*
* _.isNumber(8.4 * 5);
* // => true
*/
function isNumber(value) {
return typeof value == 'number' ||
value && typeof value == 'object' && toString.call(value) == numberClass || false;
}
/**
* Checks if `value` is an object created by the `Object` constructor.
*
* @static
* @memberOf _
* @category Objects
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
* @example
*
* function Shape() {
* this.x = 0;
* this.y = 0;
* }
*
* _.isPlainObject(new Shape);
* // => false
*
* _.isPlainObject([1, 2, 3]);
* // => false
*
* _.isPlainObject({ 'x': 0, 'y': 0 });
* // => true
*/
var isPlainObject = !getPrototypeOf ? shimIsPlainObject : function(value) {
if (!(value && toString.call(value) == objectClass) || (!support.argsClass && isArguments(value))) {
return false;
}
var valueOf = value.valueOf,
objProto = isNative(valueOf) && (objProto = getPrototypeOf(valueOf)) && getPrototypeOf(objProto);
return objProto
? (value == objProto || getPrototypeOf(value) == objProto)
: shimIsPlainObject(value);
};
/**
* Checks if `value` is a regular expression.
*
* @static
* @memberOf _
* @category Objects
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if the `value` is a regular expression, else `false`.
* @example
*
* _.isRegExp(/fred/);
* // => true
*/
function isRegExp(value) {
return value && objectTypes[typeof value] && toString.call(value) == regexpClass || false;
}
/**
* Checks if `value` is a string.
*
* @static
* @memberOf _
* @category Objects
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if the `value` is a string, else `false`.
* @example
*
* _.isString('fred');
* // => true
*/
function isString(value) {
return typeof value == 'string' ||
value && typeof value == 'object' && toString.call(value) == stringClass || false;
}
/**
* Checks if `value` is `undefined`.
*
* @static
* @memberOf _
* @category Objects
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if the `value` is `undefined`, else `false`.
* @example
*
* _.isUndefined(void 0);
* // => true
*/
function isUndefined(value) {
return typeof value == 'undefined';
}
/**
* Creates an object with the same keys as `object` and values generated by
* running each own enumerable property of `object` through the callback.
* The callback is bound to `thisArg` and invoked with three arguments;
* (value, key, object).
*
* If a property name is provided for `callback` the created "_.pluck" style
* callback will return the property value of the given element.
*
* If an object is provided for `callback` the created "_.where" style callback
* will return `true` for elements that have the properties of the given object,
* else `false`.
*
* @static
* @memberOf _
* @category Objects
* @param {Object} object The object to iterate over.
* @param {Function|Object|string} [callback=identity] The function called
* per iteration. If a property name or object is provided it will be used
* to create a "_.pluck" or "_.where" style callback, respectively.
* @param {*} [thisArg] The `this` binding of `callback`.
* @returns {Array} Returns a new object with values of the results of each `callback` execution.
* @example
*
* _.mapValues({ 'a': 1, 'b': 2, 'c': 3} , function(num) { return num * 3; });
* // => { 'a': 3, 'b': 6, 'c': 9 }
*
* var characters = {
* 'fred': { 'name': 'fred', 'age': 40 },
* 'pebbles': { 'name': 'pebbles', 'age': 1 }
* };
*
* // using "_.pluck" callback shorthand
* _.mapValues(characters, 'age');
* // => { 'fred': 40, 'pebbles': 1 }
*/
function mapValues(object, callback, thisArg) {
var result = {};
callback = lodash.createCallback(callback, thisArg, 3);
forOwn(object, function(value, key, object) {
result[key] = callback(value, key, object);
});
return result;
}
/**
* Recursively merges own enumerable properties of the source object(s), that
* don't resolve to `undefined` into the destination object. Subsequent sources
* will overwrite property assignments of previous sources. If a callback is
* provided it will be executed to produce the merged values of the destination
* and source properties. If the callback returns `undefined` merging will
* be handled by the method instead. The callback is bound to `thisArg` and
* invoked with two arguments; (objectValue, sourceValue).
*
* @static
* @memberOf _
* @category Objects
* @param {Object} object The destination object.
* @param {...Object} [source] The source objects.
* @param {Function} [callback] The function to customize merging properties.
* @param {*} [thisArg] The `this` binding of `callback`.
* @returns {Object} Returns the destination object.
* @example
*
* var names = {
* 'characters': [
* { 'name': 'barney' },
* { 'name': 'fred' }
* ]
* };
*
* var ages = {
* 'characters': [
* { 'age': 36 },
* { 'age': 40 }
* ]
* };
*
* _.merge(names, ages);
* // => { 'characters': [{ 'name': 'barney', 'age': 36 }, { 'name': 'fred', 'age': 40 }] }
*
* var food = {
* 'fruits': ['apple'],
* 'vegetables': ['beet']
* };
*
* var otherFood = {
* 'fruits': ['banana'],
* 'vegetables': ['carrot']
* };
*
* _.merge(food, otherFood, function(a, b) {
* return _.isArray(a) ? a.concat(b) : undefined;
* });
* // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot] }
*/
function merge(object) {
var args = arguments,
length = 2;
if (!isObject(object)) {
return object;
}
// allows working with `_.reduce` and `_.reduceRight` without using
// their `index` and `collection` arguments
if (typeof args[2] != 'number') {
length = args.length;
}
if (length > 3 && typeof args[length - 2] == 'function') {
var callback = baseCreateCallback(args[--length - 1], args[length--], 2);
} else if (length > 2 && typeof args[length - 1] == 'function') {
callback = args[--length];
}
var sources = slice(arguments, 1, length),
index = -1,
stackA = getArray(),
stackB = getArray();
while (++index < length) {
baseMerge(object, sources[index], callback, stackA, stackB);
}
releaseArray(stackA);
releaseArray(stackB);
return object;
}
/**
* Creates a shallow clone of `object` excluding the specified properties.
* Property names may be specified as individual arguments or as arrays of
* property names. If a callback is provided it will be executed for each
* property of `object` omitting the properties the callback returns truey
* for. The callback is bound to `thisArg` and invoked with three arguments;
* (value, key, object).
*
* @static
* @memberOf _
* @category Objects
* @param {Object} object The source object.
* @param {Function|...string|string[]} [callback] The properties to omit or the
* function called per iteration.
* @param {*} [thisArg] The `this` binding of `callback`.
* @returns {Object} Returns an object without the omitted properties.
* @example
*
* _.omit({ 'name': 'fred', 'age': 40 }, 'age');
* // => { 'name': 'fred' }
*
* _.omit({ 'name': 'fred', 'age': 40 }, function(value) {
* return typeof value == 'number';
* });
* // => { 'name': 'fred' }
*/
function omit(object, callback, thisArg) {
var result = {};
if (typeof callback != 'function') {
var props = [];
forIn(object, function(value, key) {
props.push(key);
});
props = baseDifference(props, baseFlatten(arguments, true, false, 1));
var index = -1,
length = props.length;
while (++index < length) {
var key = props[index];
result[key] = object[key];
}
} else {
callback = lodash.createCallback(callback, thisArg, 3);
forIn(object, function(value, key, object) {
if (!callback(value, key, object)) {
result[key] = value;
}
});
}
return result;
}
/**
* Creates a two dimensional array of an object's key-value pairs,
* i.e. `[[key1, value1], [key2, value2]]`.
*
* @static
* @memberOf _
* @category Objects
* @param {Object} object The object to inspect.
* @returns {Array} Returns new array of key-value pairs.
* @example
*
* _.pairs({ 'barney': 36, 'fred': 40 });
* // => [['barney', 36], ['fred', 40]] (property order is not guaranteed across environments)
*/
function pairs(object) {
var index = -1,
props = keys(object),
length = props.length,
result = Array(length);
while (++index < length) {
var key = props[index];
result[index] = [key, object[key]];
}
return result;
}
/**
* Creates a shallow clone of `object` composed of the specified properties.
* Property names may be specified as individual arguments or as arrays of
* property names. If a callback is provided it will be executed for each
* property of `object` picking the properties the callback returns truey
* for. The callback is bound to `thisArg` and invoked with three arguments;
* (value, key, object).
*
* @static
* @memberOf _
* @category Objects
* @param {Object} object The source object.
* @param {Function|...string|string[]} [callback] The function called per
* iteration or property names to pick, specified as individual property
* names or arrays of property names.
* @param {*} [thisArg] The `this` binding of `callback`.
* @returns {Object} Returns an object composed of the picked properties.
* @example
*
* _.pick({ 'name': 'fred', '_userid': 'fred1' }, 'name');
* // => { 'name': 'fred' }
*
* _.pick({ 'name': 'fred', '_userid': 'fred1' }, function(value, key) {
* return key.charAt(0) != '_';
* });
* // => { 'name': 'fred' }
*/
function pick(object, callback, thisArg) {
var result = {};
if (typeof callback != 'function') {
var index = -1,
props = baseFlatten(arguments, true, false, 1),
length = isObject(object) ? props.length : 0;
while (++index < length) {
var key = props[index];
if (key in object) {
result[key] = object[key];
}
}
} else {
callback = lodash.createCallback(callback, thisArg, 3);
forIn(object, function(value, key, object) {
if (callback(value, key, object)) {
result[key] = value;
}
});
}
return result;
}
/**
* An alternative to `_.reduce` this method transforms `object` to a new
* `accumulator` object which is the result of running each of its own
* enumerable properties through a callback, with each callback execution
* potentially mutating the `accumulator` object. The callback is bound to
* `thisArg` and invoked with four arguments; (accumulator, value, key, object).
* Callbacks may exit iteration early by explicitly returning `false`.
*
* @static
* @memberOf _
* @category Objects
* @param {Array|Object} object The object to iterate over.
* @param {Function} [callback=identity] The function called per iteration.
* @param {*} [accumulator] The custom accumulator value.
* @param {*} [thisArg] The `this` binding of `callback`.
* @returns {*} Returns the accumulated value.
* @example
*
* var squares = _.transform([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], function(result, num) {
* num *= num;
* if (num % 2) {
* return result.push(num) < 3;
* }
* });
* // => [1, 9, 25]
*
* var mapped = _.transform({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) {
* result[key] = num * 3;
* });
* // => { 'a': 3, 'b': 6, 'c': 9 }
*/
function transform(object, callback, accumulator, thisArg) {
var isArr = isArray(object);
if (accumulator == null) {
if (isArr) {
accumulator = [];
} else {
var ctor = object && object.constructor,
proto = ctor && ctor.prototype;
accumulator = baseCreate(proto);
}
}
if (callback) {
callback = lodash.createCallback(callback, thisArg, 4);
(isArr ? baseEach : forOwn)(object, function(value, index, object) {
return callback(accumulator, value, index, object);
});
}
return accumulator;
}
/**
* Creates an array composed of the own enumerable property values of `object`.
*
* @static
* @memberOf _
* @category Objects
* @param {Object} object The object to inspect.
* @returns {Array} Returns an array of property values.
* @example
*
* _.values({ 'one': 1, 'two': 2, 'three': 3 });
* // => [1, 2, 3] (property order is not guaranteed across environments)
*/
function values(object) {
var index = -1,
props = keys(object),
length = props.length,
result = Array(length);
while (++index < length) {
result[index] = object[props[index]];
}
return result;
}
/*--------------------------------------------------------------------------*/
/**
* Creates an array of elements from the specified indexes, or keys, of the
* `collection`. Indexes may be specified as individual arguments or as arrays
* of indexes.
*
* @static
* @memberOf _
* @category Collections
* @param {Array|Object|string} collection The collection to iterate over.
* @param {...(number|number[]|string|string[])} [index] The indexes of `collection`
* to retrieve, specified as individual indexes or arrays of indexes.
* @returns {Array} Returns a new array of elements corresponding to the
* provided indexes.
* @example
*
* _.at(['a', 'b', 'c', 'd', 'e'], [0, 2, 4]);
* // => ['a', 'c', 'e']
*
* _.at(['fred', 'barney', 'pebbles'], 0, 2);
* // => ['fred', 'pebbles']
*/
function at(collection) {
var args = arguments,
index = -1,
props = baseFlatten(args, true, false, 1),
length = (args[2] && args[2][args[1]] === collection) ? 1 : props.length,
result = Array(length);
if (support.unindexedChars && isString(collection)) {
collection = collection.split('');
}
while(++index < length) {
result[index] = collection[props[index]];
}
return result;
}
/**
* Checks if a given value is present in a collection using strict equality
* for comparisons, i.e. `===`. If `fromIndex` is negative, it is used as the
* offset from the end of the collection.
*
* @static
* @memberOf _
* @alias include
* @category Collections
* @param {Array|Object|string} collection The collection to iterate over.
* @param {*} target The value to check for.
* @param {number} [fromIndex=0] The index to search from.
* @returns {boolean} Returns `true` if the `target` element is found, else `false`.
* @example
*
* _.contains([1, 2, 3], 1);
* // => true
*
* _.contains([1, 2, 3], 1, 2);
* // => false
*
* _.contains({ 'name': 'fred', 'age': 40 }, 'fred');
* // => true
*
* _.contains('pebbles', 'eb');
* // => true
*/
function contains(collection, target, fromIndex) {
var index = -1,
indexOf = getIndexOf(),
length = collection ? collection.length : 0,
result = false;
fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex) || 0;
if (isArray(collection)) {
result = indexOf(collection, target, fromIndex) > -1;
} else if (typeof length == 'number') {
result = (isString(collection) ? collection.indexOf(target, fromIndex) : indexOf(collection, target, fromIndex)) > -1;
} else {
baseEach(collection, function(value) {
if (++index >= fromIndex) {
return !(result = value === target);
}
});
}
return result;
}
/**
* Creates an object composed of keys generated from the results of running
* each element of `collection` through the callback. The corresponding value
* of each key is the number of times the key was returned by the callback.
* The callback is bound to `thisArg` and invoked with three arguments;
* (value, index|key, collection).
*
* If a property name is provided for `callback` the created "_.pluck" style
* callback will return the property value of the given element.
*
* If an object is provided for `callback` the created "_.where" style callback
* will return `true` for elements that have the properties of the given object,
* else `false`.
*
* @static
* @memberOf _
* @category Collections
* @param {Array|Object|string} collection The collection to iterate over.
* @param {Function|Object|string} [callback=identity] The function called
* per iteration. If a property name or object is provided it will be used
* to create a "_.pluck" or "_.where" style callback, respectively.
* @param {*} [thisArg] The `this` binding of `callback`.
* @returns {Object} Returns the composed aggregate object.
* @example
*
* _.countBy([4.3, 6.1, 6.4], function(num) { return Math.floor(num); });
* // => { '4': 1, '6': 2 }
*
* _.countBy([4.3, 6.1, 6.4], function(num) { return this.floor(num); }, Math);
* // => { '4': 1, '6': 2 }
*
* _.countBy(['one', 'two', 'three'], 'length');
* // => { '3': 2, '5': 1 }
*/
var countBy = createAggregator(function(result, value, key) {
(hasOwnProperty.call(result, key) ? result[key]++ : result[key] = 1);
});
/**
* Checks if the given callback returns truey value for **all** elements of
* a collection. The callback is bound to `thisArg` and invoked with three
* arguments; (value, index|key, collection).
*
* If a property name is provided for `callback` the created "_.pluck" style
* callback will return the property value of the given element.
*
* If an object is provided for `callback` the created "_.where" style callback
* will return `true` for elements that have the properties of the given object,
* else `false`.
*
* @static
* @memberOf _
* @alias all
* @category Collections
* @param {Array|Object|string} collection The collection to iterate over.
* @param {Function|Object|string} [callback=identity] The function called
* per iteration. If a property name or object is provided it will be used
* to create a "_.pluck" or "_.where" style callback, respectively.
* @param {*} [thisArg] The `this` binding of `callback`.
* @returns {boolean} Returns `true` if all elements passed the callback check,
* else `false`.
* @example
*
* _.every([true, 1, null, 'yes']);
* // => false
*
* var characters = [
* { 'name': 'barney', 'age': 36 },
* { 'name': 'fred', 'age': 40 }
* ];
*
* // using "_.pluck" callback shorthand
* _.every(characters, 'age');
* // => true
*
* // using "_.where" callback shorthand
* _.every(characters, { 'age': 36 });
* // => false
*/
function every(collection, callback, thisArg) {
var result = true;
callback = lodash.createCallback(callback, thisArg, 3);
if (isArray(collection)) {
var index = -1,
length = collection.length;
while (++index < length) {
if (!(result = !!callback(collection[index], index, collection))) {
break;
}
}
} else {
baseEach(collection, function(value, index, collection) {
return (result = !!callback(value, index, collection));
});
}
return result;
}
/**
* Iterates over elements of a collection, returning an array of all elements
* the callback returns truey for. The callback is bound to `thisArg` and
* invoked with three arguments; (value, index|key, collection).
*
* If a property name is provided for `callback` the created "_.pluck" style
* callback will return the property value of the given element.
*
* If an object is provided for `callback` the created "_.where" style callback
* will return `true` for elements that have the properties of the given object,
* else `false`.
*
* @static
* @memberOf _
* @alias select
* @category Collections
* @param {Array|Object|string} collection The collection to iterate over.
* @param {Function|Object|string} [callback=identity] The function called
* per iteration. If a property name or object is provided it will be used
* to create a "_.pluck" or "_.where" style callback, respectively.
* @param {*} [thisArg] The `this` binding of `callback`.
* @returns {Array} Returns a new array of elements that passed the callback check.
* @example
*
* var evens = _.filter([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
* // => [2, 4, 6]
*
* var characters = [
* { 'name': 'barney', 'age': 36, 'blocked': false },
* { 'name': 'fred', 'age': 40, 'blocked': true }
* ];
*
* // using "_.pluck" callback shorthand
* _.filter(characters, 'blocked');
* // => [{ 'name': 'fred', 'age': 40, 'blocked': true }]
*
* // using "_.where" callback shorthand
* _.filter(characters, { 'age': 36 });
* // => [{ 'name': 'barney', 'age': 36, 'blocked': false }]
*/
function filter(collection, callback, thisArg) {
var result = [];
callback = lodash.createCallback(callback, thisArg, 3);
if (isArray(collection)) {
var index = -1,
length = collection.length;
while (++index < length) {
var value = collection[index];
if (callback(value, index, collection)) {
result.push(value);
}
}
} else {
baseEach(collection, function(value, index, collection) {
if (callback(value, index, collection)) {
result.push(value);
}
});
}
return result;
}
/**
* Iterates over elements of a collection, returning the first element that
* the callback returns truey for. The callback is bound to `thisArg` and
* invoked with three arguments; (value, index|key, collection).
*
* If a property name is provided for `callback` the created "_.pluck" style
* callback will return the property value of the given element.
*
* If an object is provided for `callback` the created "_.where" style callback
* will return `true` for elements that have the properties of the given object,
* else `false`.
*
* @static
* @memberOf _
* @alias detect, findWhere
* @category Collections
* @param {Array|Object|string} collection The collection to iterate over.
* @param {Function|Object|string} [callback=identity] The function called
* per iteration. If a property name or object is provided it will be used
* to create a "_.pluck" or "_.where" style callback, respectively.
* @param {*} [thisArg] The `this` binding of `callback`.
* @returns {*} Returns the found element, else `undefined`.
* @example
*
* var characters = [
* { 'name': 'barney', 'age': 36, 'blocked': false },
* { 'name': 'fred', 'age': 40, 'blocked': true },
* { 'name': 'pebbles', 'age': 1, 'blocked': false }
* ];
*
* _.find(characters, function(chr) {
* return chr.age < 40;
* });
* // => { 'name': 'barney', 'age': 36, 'blocked': false }
*
* // using "_.where" callback shorthand
* _.find(characters, { 'age': 1 });
* // => { 'name': 'pebbles', 'age': 1, 'blocked': false }
*
* // using "_.pluck" callback shorthand
* _.find(characters, 'blocked');
* // => { 'name': 'fred', 'age': 40, 'blocked': true }
*/
function find(collection, callback, thisArg) {
callback = lodash.createCallback(callback, thisArg, 3);
if (isArray(collection)) {
var index = -1,
length = collection.length;
while (++index < length) {
var value = collection[index];
if (callback(value, index, collection)) {
return value;
}
}
} else {
var result;
baseEach(collection, function(value, index, collection) {
if (callback(value, index, collection)) {
result = value;
return false;
}
});
return result;
}
}
/**
* This method is like `_.find` except that it iterates over elements
* of a `collection` from right to left.
*
* @static
* @memberOf _
* @category Collections
* @param {Array|Object|string} collection The collection to iterate over.
* @param {Function|Object|string} [callback=identity] The function called
* per iteration. If a property name or object is provided it will be used
* to create a "_.pluck" or "_.where" style callback, respectively.
* @param {*} [thisArg] The `this` binding of `callback`.
* @returns {*} Returns the found element, else `undefined`.
* @example
*
* _.findLast([1, 2, 3, 4], function(num) {
* return num % 2 == 1;
* });
* // => 3
*/
function findLast(collection, callback, thisArg) {
var result;
callback = lodash.createCallback(callback, thisArg, 3);
forEachRight(collection, function(value, index, collection) {
if (callback(value, index, collection)) {
result = value;
return false;
}
});
return result;
}
/**
* Iterates over elements of a collection, executing the callback for each
* element. The callback is bound to `thisArg` and invoked with three arguments;
* (value, index|key, collection). Callbacks may exit iteration early by
* explicitly returning `false`.
*
* Note: As with other "Collections" methods, objects with a `length` property
* are iterated like arrays. To avoid this behavior `_.forIn` or `_.forOwn`
* may be used for object iteration.
*
* @static
* @memberOf _
* @alias each
* @category Collections
* @param {Array|Object|string} collection The collection to iterate over.
* @param {Function} [callback=identity] The function called per iteration.
* @param {*} [thisArg] The `this` binding of `callback`.
* @returns {Array|Object|string} Returns `collection`.
* @example
*
* _([1, 2, 3]).forEach(function(num) { console.log(num); }).join(',');
* // => logs each number and returns '1,2,3'
*
* _.forEach({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { console.log(num); });
* // => logs each number and returns the object (property order is not guaranteed across environments)
*/
function forEach(collection, callback, thisArg) {
if (callback && typeof thisArg == 'undefined' && isArray(collection)) {
var index = -1,
length = collection.length;
while (++index < length) {
if (callback(collection[index], index, collection) === false) {
break;
}
}
} else {
baseEach(collection, callback, thisArg);
}
return collection;
}
/**
* This method is like `_.forEach` except that it iterates over elements
* of a `collection` from right to left.
*
* @static
* @memberOf _
* @alias eachRight
* @category Collections
* @param {Array|Object|string} collection The collection to iterate over.
* @param {Function} [callback=identity] The function called per iteration.
* @param {*} [thisArg] The `this` binding of `callback`.
* @returns {Array|Object|string} Returns `collection`.
* @example
*
* _([1, 2, 3]).forEachRight(function(num) { console.log(num); }).join(',');
* // => logs each number from right to left and returns '3,2,1'
*/
function forEachRight(collection, callback, thisArg) {
var iterable = collection,
length = collection ? collection.length : 0;
callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3);
if (isArray(collection)) {
while (length--) {
if (callback(collection[length], length, collection) === false) {
break;
}
}
} else {
if (typeof length != 'number') {
var props = keys(collection);
length = props.length;
} else if (support.unindexedChars && isString(collection)) {
iterable = collection.split('');
}
baseEach(collection, function(value, key, collection) {
key = props ? props[--length] : --length;
return callback(iterable[key], key, collection);
});
}
return collection;
}
/**
* Creates an object composed of keys generated from the results of running
* each element of a collection through the callback. The corresponding value
* of each key is an array of the elements responsible for generating the key.
* The callback is bound to `thisArg` and invoked with three arguments;
* (value, index|key, collection).
*
* If a property name is provided for `callback` the created "_.pluck" style
* callback will return the property value of the given element.
*
* If an object is provided for `callback` the created "_.where" style callback
* will return `true` for elements that have the properties of the given object,
* else `false`
*
* @static
* @memberOf _
* @category Collections
* @param {Array|Object|string} collection The collection to iterate over.
* @param {Function|Object|string} [callback=identity] The function called
* per iteration. If a property name or object is provided it will be used
* to create a "_.pluck" or "_.where" style callback, respectively.
* @param {*} [thisArg] The `this` binding of `callback`.
* @returns {Object} Returns the composed aggregate object.
* @example
*
* _.groupBy([4.2, 6.1, 6.4], function(num) { return Math.floor(num); });
* // => { '4': [4.2], '6': [6.1, 6.4] }
*
* _.groupBy([4.2, 6.1, 6.4], function(num) { return this.floor(num); }, Math);
* // => { '4': [4.2], '6': [6.1, 6.4] }
*
* // using "_.pluck" callback shorthand
* _.groupBy(['one', 'two', 'three'], 'length');
* // => { '3': ['one', 'two'], '5': ['three'] }
*/
var groupBy = createAggregator(function(result, value, key) {
(hasOwnProperty.call(result, key) ? result[key] : result[key] = []).push(value);
});
/**
* Creates an object composed of keys generated from the results of running
* each element of the collection through the given callback. The corresponding
* value of each key is the last element responsible for generating the key.
* The callback is bound to `thisArg` and invoked with three arguments;
* (value, index|key, collection).
*
* If a property name is provided for `callback` the created "_.pluck" style
* callback will return the property value of the given element.
*
* If an object is provided for `callback` the created "_.where" style callback
* will return `true` for elements that have the properties of the given object,
* else `false`.
*
* @static
* @memberOf _
* @category Collections
* @param {Array|Object|string} collection The collection to iterate over.
* @param {Function|Object|string} [callback=identity] The function called
* per iteration. If a property name or object is provided it will be used
* to create a "_.pluck" or "_.where" style callback, respectively.
* @param {*} [thisArg] The `this` binding of `callback`.
* @returns {Object} Returns the composed aggregate object.
* @example
*
* var keys = [
* { 'dir': 'left', 'code': 97 },
* { 'dir': 'right', 'code': 100 }
* ];
*
* _.indexBy(keys, 'dir');
* // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } }
*
* _.indexBy(keys, function(key) { return String.fromCharCode(key.code); });
* // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
*
* _.indexBy(characters, function(key) { this.fromCharCode(key.code); }, String);
* // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
*/
var indexBy = createAggregator(function(result, value, key) {
result[key] = value;
});
/**
* Invokes the method named by `methodName` on each element in the `collection`
* returning an array of the results of each invoked method. Additional arguments
* will be provided to each invoked method. If `methodName` is a function it
* will be invoked for, and `this` bound to, each element in the `collection`.
*
* @static
* @memberOf _
* @category Collections
* @param {Array|Object|string} collection The collection to iterate over.
* @param {Function|string} methodName The name of the method to invoke or
* the function invoked per iteration.
* @param {...*} [arg] Arguments to invoke the method with.
* @returns {Array} Returns a new array of the results of each invoked method.
* @example
*
* _.invoke([[5, 1, 7], [3, 2, 1]], 'sort');
* // => [[1, 5, 7], [1, 2, 3]]
*
* _.invoke([123, 456], String.prototype.split, '');
* // => [['1', '2', '3'], ['4', '5', '6']]
*/
function invoke(collection, methodName) {
var args = slice(arguments, 2),
index = -1,
isFunc = typeof methodName == 'function',
length = collection ? collection.length : 0,
result = Array(typeof length == 'number' ? length : 0);
forEach(collection, function(value) {
result[++index] = (isFunc ? methodName : value[methodName]).apply(value, args);
});
return result;
}
/**
* Creates an array of values by running each element in the collection
* through the callback. The callback is bound to `thisArg` and invoked with
* three arguments; (value, index|key, collection).
*
* If a property name is provided for `callback` the created "_.pluck" style
* callback will return the property value of the given element.
*
* If an object is provided for `callback` the created "_.where" style callback
* will return `true` for elements that have the properties of the given object,
* else `false`.
*
* @static
* @memberOf _
* @alias collect
* @category Collections
* @param {Array|Object|string} collection The collection to iterate over.
* @param {Function|Object|string} [callback=identity] The function called
* per iteration. If a property name or object is provided it will be used
* to create a "_.pluck" or "_.where" style callback, respectively.
* @param {*} [thisArg] The `this` binding of `callback`.
* @returns {Array} Returns a new array of the results of each `callback` execution.
* @example
*
* _.map([1, 2, 3], function(num) { return num * 3; });
* // => [3, 6, 9]
*
* _.map({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { return num * 3; });
* // => [3, 6, 9] (property order is not guaranteed across environments)
*
* var characters = [
* { 'name': 'barney', 'age': 36 },
* { 'name': 'fred', 'age': 40 }
* ];
*
* // using "_.pluck" callback shorthand
* _.map(characters, 'name');
* // => ['barney', 'fred']
*/
function map(collection, callback, thisArg) {
var index = -1,
length = collection ? collection.length : 0,
result = Array(typeof length == 'number' ? length : 0);
callback = lodash.createCallback(callback, thisArg, 3);
if (isArray(collection)) {
while (++index < length) {
result[index] = callback(collection[index], index, collection);
}
} else {
baseEach(collection, function(value, key, collection) {
result[++index] = callback(value, key, collection);
});
}
return result;
}
/**
* Retrieves the maximum value of a collection. If the collection is empty or
* falsey `-Infinity` is returned. If a callback is provided it will be executed
* for each value in the collection to generate the criterion by which the value
* is ranked. The callback is bound to `thisArg` and invoked with three
* arguments; (value, index, collection).
*
* If a property name is provided for `callback` the created "_.pluck" style
* callback will return the property value of the given element.
*
* If an object is provided for `callback` the created "_.where" style callback
* will return `true` for elements that have the properties of the given object,
* else `false`.
*
* @static
* @memberOf _
* @category Collections
* @param {Array|Object|string} collection The collection to iterate over.
* @param {Function|Object|string} [callback=identity] The function called
* per iteration. If a property name or object is provided it will be used
* to create a "_.pluck" or "_.where" style callback, respectively.
* @param {*} [thisArg] The `this` binding of `callback`.
* @returns {*} Returns the maximum value.
* @example
*
* _.max([4, 2, 8, 6]);
* // => 8
*
* var characters = [
* { 'name': 'barney', 'age': 36 },
* { 'name': 'fred', 'age': 40 }
* ];
*
* _.max(characters, function(chr) { return chr.age; });
* // => { 'name': 'fred', 'age': 40 };
*
* // using "_.pluck" callback shorthand
* _.max(characters, 'age');
* // => { 'name': 'fred', 'age': 40 };
*/
function max(collection, callback, thisArg) {
var computed = -Infinity,
result = computed;
// allows working with functions like `_.map` without using
// their `index` argument as a callback
if (typeof callback != 'function' && thisArg && thisArg[callback] === collection) {
callback = null;
}
if (callback == null && isArray(collection)) {
var index = -1,
length = collection.length;
while (++index < length) {
var value = collection[index];
if (value > result) {
result = value;
}
}
} else {
callback = (callback == null && isString(collection))
? charAtCallback
: lodash.createCallback(callback, thisArg, 3);
baseEach(collection, function(value, index, collection) {
var current = callback(value, index, collection);
if (current > computed) {
computed = current;
result = value;
}
});
}
return result;
}
/**
* Retrieves the minimum value of a collection. If the collection is empty or
* falsey `Infinity` is returned. If a callback is provided it will be executed
* for each value in the collection to generate the criterion by which the value
* is ranked. The callback is bound to `thisArg` and invoked with three
* arguments; (value, index, collection).
*
* If a property name is provided for `callback` the created "_.pluck" style
* callback will return the property value of the given element.
*
* If an object is provided for `callback` the created "_.where" style callback
* will return `true` for elements that have the properties of the given object,
* else `false`.
*
* @static
* @memberOf _
* @category Collections
* @param {Array|Object|string} collection The collection to iterate over.
* @param {Function|Object|string} [callback=identity] The function called
* per iteration. If a property name or object is provided it will be used
* to create a "_.pluck" or "_.where" style callback, respectively.
* @param {*} [thisArg] The `this` binding of `callback`.
* @returns {*} Returns the minimum value.
* @example
*
* _.min([4, 2, 8, 6]);
* // => 2
*
* var characters = [
* { 'name': 'barney', 'age': 36 },
* { 'name': 'fred', 'age': 40 }
* ];
*
* _.min(characters, function(chr) { return chr.age; });
* // => { 'name': 'barney', 'age': 36 };
*
* // using "_.pluck" callback shorthand
* _.min(characters, 'age');
* // => { 'name': 'barney', 'age': 36 };
*/
function min(collection, callback, thisArg) {
var computed = Infinity,
result = computed;
// allows working with functions like `_.map` without using
// their `index` argument as a callback
if (typeof callback != 'function' && thisArg && thisArg[callback] === collection) {
callback = null;
}
if (callback == null && isArray(collection)) {
var index = -1,
length = collection.length;
while (++index < length) {
var value = collection[index];
if (value < result) {
result = value;
}
}
} else {
callback = (callback == null && isString(collection))
? charAtCallback
: lodash.createCallback(callback, thisArg, 3);
baseEach(collection, function(value, index, collection) {
var current = callback(value, index, collection);
if (current < computed) {
computed = current;
result = value;
}
});
}
return result;
}
/**
* Retrieves the value of a specified property from all elements in the collection.
*
* @static
* @memberOf _
* @type Function
* @category Collections
* @param {Array|Object|string} collection The collection to iterate over.
* @param {string} property The name of the property to pluck.
* @returns {Array} Returns a new array of property values.
* @example
*
* var characters = [
* { 'name': 'barney', 'age': 36 },
* { 'name': 'fred', 'age': 40 }
* ];
*
* _.pluck(characters, 'name');
* // => ['barney', 'fred']
*/
var pluck = map;
/**
* Reduces a collection to a value which is the accumulated result of running
* each element in the collection through the callback, where each successive
* callback execution consumes the return value of the previous execution. If
* `accumulator` is not provided the first element of the collection will be
* used as the initial `accumulator` value. The callback is bound to `thisArg`
* and invoked with four arguments; (accumulator, value, index|key, collection).
*
* @static
* @memberOf _
* @alias foldl, inject
* @category Collections
* @param {Array|Object|string} collection The collection to iterate over.
* @param {Function} [callback=identity] The function called per iteration.
* @param {*} [accumulator] Initial value of the accumulator.
* @param {*} [thisArg] The `this` binding of `callback`.
* @returns {*} Returns the accumulated value.
* @example
*
* var sum = _.reduce([1, 2, 3], function(sum, num) {
* return sum + num;
* });
* // => 6
*
* var mapped = _.reduce({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) {
* result[key] = num * 3;
* return result;
* }, {});
* // => { 'a': 3, 'b': 6, 'c': 9 }
*/
function reduce(collection, callback, accumulator, thisArg) {
var noaccum = arguments.length < 3;
callback = lodash.createCallback(callback, thisArg, 4);
if (isArray(collection)) {
var index = -1,
length = collection.length;
if (noaccum) {
accumulator = collection[++index];
}
while (++index < length) {
accumulator = callback(accumulator, collection[index], index, collection);
}
} else {
baseEach(collection, function(value, index, collection) {
accumulator = noaccum
? (noaccum = false, value)
: callback(accumulator, value, index, collection)
});
}
return accumulator;
}
/**
* This method is like `_.reduce` except that it iterates over elements
* of a `collection` from right to left.
*
* @static
* @memberOf _
* @alias foldr
* @category Collections
* @param {Array|Object|string} collection The collection to iterate over.
* @param {Function} [callback=identity] The function called per iteration.
* @param {*} [accumulator] Initial value of the accumulator.
* @param {*} [thisArg] The `this` binding of `callback`.
* @returns {*} Returns the accumulated value.
* @example
*
* var list = [[0, 1], [2, 3], [4, 5]];
* var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, []);
* // => [4, 5, 2, 3, 0, 1]
*/
function reduceRight(collection, callback, accumulator, thisArg) {
var noaccum = arguments.length < 3;
callback = lodash.createCallback(callback, thisArg, 4);
forEachRight(collection, function(value, index, collection) {
accumulator = noaccum
? (noaccum = false, value)
: callback(accumulator, value, index, collection);
});
return accumulator;
}
/**
* The opposite of `_.filter` this method returns the elements of a
* collection that the callback does **not** return truey for.
*
* If a property name is provided for `callback` the created "_.pluck" style
* callback will return the property value of the given element.
*
* If an object is provided for `callback` the created "_.where" style callback
* will return `true` for elements that have the properties of the given object,
* else `false`.
*
* @static
* @memberOf _
* @category Collections
* @param {Array|Object|string} collection The collection to iterate over.
* @param {Function|Object|string} [callback=identity] The function called
* per iteration. If a property name or object is provided it will be used
* to create a "_.pluck" or "_.where" style callback, respectively.
* @param {*} [thisArg] The `this` binding of `callback`.
* @returns {Array} Returns a new array of elements that failed the callback check.
* @example
*
* var odds = _.reject([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
* // => [1, 3, 5]
*
* var characters = [
* { 'name': 'barney', 'age': 36, 'blocked': false },
* { 'name': 'fred', 'age': 40, 'blocked': true }
* ];
*
* // using "_.pluck" callback shorthand
* _.reject(characters, 'blocked');
* // => [{ 'name': 'barney', 'age': 36, 'blocked': false }]
*
* // using "_.where" callback shorthand
* _.reject(characters, { 'age': 36 });
* // => [{ 'name': 'fred', 'age': 40, 'blocked': true }]
*/
function reject(collection, callback, thisArg) {
callback = lodash.createCallback(callback, thisArg, 3);
return filter(collection, function(value, index, collection) {
return !callback(value, index, collection);
});
}
/**
* Retrieves a random element or `n` random elements from a collection.
*
* @static
* @memberOf _
* @category Collections
* @param {Array|Object|string} collection The collection to sample.
* @param {number} [n] The number of elements to sample.
* @param- {Object} [guard] Allows working with functions like `_.map`
* without using their `index` arguments as `n`.
* @returns {Array} Returns the random sample(s) of `collection`.
* @example
*
* _.sample([1, 2, 3, 4]);
* // => 2
*
* _.sample([1, 2, 3, 4], 2);
* // => [3, 1]
*/
function sample(collection, n, guard) {
if (collection && typeof collection.length != 'number') {
collection = values(collection);
} else if (support.unindexedChars && isString(collection)) {
collection = collection.split('');
}
if (n == null || guard) {
return collection ? collection[baseRandom(0, collection.length - 1)] : undefined;
}
var result = shuffle(collection);
result.length = nativeMin(nativeMax(0, n), result.length);
return result;
}
/**
* Creates an array of shuffled values, using a version of the Fisher-Yates
* shuffle. See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle.
*
* @static
* @memberOf _
* @category Collections
* @param {Array|Object|string} collection The collection to shuffle.
* @returns {Array} Returns a new shuffled collection.
* @example
*
* _.shuffle([1, 2, 3, 4, 5, 6]);
* // => [4, 1, 6, 3, 5, 2]
*/
function shuffle(collection) {
var index = -1,
length = collection ? collection.length : 0,
result = Array(typeof length == 'number' ? length : 0);
forEach(collection, function(value) {
var rand = baseRandom(0, ++index);
result[index] = result[rand];
result[rand] = value;
});
return result;
}
/**
* Gets the size of the `collection` by returning `collection.length` for arrays
* and array-like objects or the number of own enumerable properties for objects.
*
* @static
* @memberOf _
* @category Collections
* @param {Array|Object|string} collection The collection to inspect.
* @returns {number} Returns `collection.length` or number of own enumerable properties.
* @example
*
* _.size([1, 2]);
* // => 2
*
* _.size({ 'one': 1, 'two': 2, 'three': 3 });
* // => 3
*
* _.size('pebbles');
* // => 7
*/
function size(collection) {
var length = collection ? collection.length : 0;
return typeof length == 'number' ? length : keys(collection).length;
}
/**
* Checks if the callback returns a truey value for **any** element of a
* collection. The function returns as soon as it finds a passing value and
* does not iterate over the entire collection. The callback is bound to
* `thisArg` and invoked with three arguments; (value, index|key, collection).
*
* If a property name is provided for `callback` the created "_.pluck" style
* callback will return the property value of the given element.
*
* If an object is provided for `callback` the created "_.where" style callback
* will return `true` for elements that have the properties of the given object,
* else `false`.
*
* @static
* @memberOf _
* @alias any
* @category Collections
* @param {Array|Object|string} collection The collection to iterate over.
* @param {Function|Object|string} [callback=identity] The function called
* per iteration. If a property name or object is provided it will be used
* to create a "_.pluck" or "_.where" style callback, respectively.
* @param {*} [thisArg] The `this` binding of `callback`.
* @returns {boolean} Returns `true` if any element passed the callback check,
* else `false`.
* @example
*
* _.some([null, 0, 'yes', false], Boolean);
* // => true
*
* var characters = [
* { 'name': 'barney', 'age': 36, 'blocked': false },
* { 'name': 'fred', 'age': 40, 'blocked': true }
* ];
*
* // using "_.pluck" callback shorthand
* _.some(characters, 'blocked');
* // => true
*
* // using "_.where" callback shorthand
* _.some(characters, { 'age': 1 });
* // => false
*/
function some(collection, callback, thisArg) {
var result;
callback = lodash.createCallback(callback, thisArg, 3);
if (isArray(collection)) {
var index = -1,
length = collection.length;
while (++index < length) {
if ((result = callback(collection[index], index, collection))) {
break;
}
}
} else {
baseEach(collection, function(value, index, collection) {
return !(result = callback(value, index, collection));
});
}
return !!result;
}
/**
* Creates an array of elements, sorted in ascending order by the results of
* running each element in a collection through the callback. This method
* performs a stable sort, that is, it will preserve the original sort order
* of equal elements. The callback is bound to `thisArg` and invoked with
* three arguments; (value, index|key, collection).
*
* If a property name is provided for `callback` the created "_.pluck" style
* callback will return the property value of the given element.
*
* If an array of property names is provided for `callback` the collection
* will be sorted by each property value.
*
* If an object is provided for `callback` the created "_.where" style callback
* will return `true` for elements that have the properties of the given object,
* else `false`.
*
* @static
* @memberOf _
* @category Collections
* @param {Array|Object|string} collection The collection to iterate over.
* @param {Array|Function|Object|string} [callback=identity] The function called
* per iteration. If a property name or object is provided it will be used
* to create a "_.pluck" or "_.where" style callback, respectively.
* @param {*} [thisArg] The `this` binding of `callback`.
* @returns {Array} Returns a new array of sorted elements.
* @example
*
* _.sortBy([1, 2, 3], function(num) { return Math.sin(num); });
* // => [3, 1, 2]
*
* _.sortBy([1, 2, 3], function(num) { return this.sin(num); }, Math);
* // => [3, 1, 2]
*
* var characters = [
* { 'name': 'barney', 'age': 36 },
* { 'name': 'fred', 'age': 40 },
* { 'name': 'barney', 'age': 26 },
* { 'name': 'fred', 'age': 30 }
* ];
*
* // using "_.pluck" callback shorthand
* _.map(_.sortBy(characters, 'age'), _.values);
* // => [['barney', 26], ['fred', 30], ['barney', 36], ['fred', 40]]
*
* // sorting by multiple properties
* _.map(_.sortBy(characters, ['name', 'age']), _.values);
* // = > [['barney', 26], ['barney', 36], ['fred', 30], ['fred', 40]]
*/
function sortBy(collection, callback, thisArg) {
var index = -1,
isArr = isArray(callback),
length = collection ? collection.length : 0,
result = Array(typeof length == 'number' ? length : 0);
if (!isArr) {
callback = lodash.createCallback(callback, thisArg, 3);
}
forEach(collection, function(value, key, collection) {
var object = result[++index] = getObject();
if (isArr) {
object.criteria = map(callback, function(key) { return value[key]; });
} else {
(object.criteria = getArray())[0] = callback(value, key, collection);
}
object.index = index;
object.value = value;
});
length = result.length;
result.sort(compareAscending);
while (length--) {
var object = result[length];
result[length] = object.value;
if (!isArr) {
releaseArray(object.criteria);
}
releaseObject(object);
}
return result;
}
/**
* Converts the `collection` to an array.
*
* @static
* @memberOf _
* @category Collections
* @param {Array|Object|string} collection The collection to convert.
* @returns {Array} Returns the new converted array.
* @example
*
* (function() { return _.toArray(arguments).slice(1); })(1, 2, 3, 4);
* // => [2, 3, 4]
*/
function toArray(collection) {
if (collection && typeof collection.length == 'number') {
return (support.unindexedChars && isString(collection))
? collection.split('')
: slice(collection);
}
return values(collection);
}
/**
* Performs a deep comparison of each element in a `collection` to the given
* `properties` object, returning an array of all elements that have equivalent
* property values.
*
* @static
* @memberOf _
* @type Function
* @category Collections
* @param {Array|Object|string} collection The collection to iterate over.
* @param {Object} props The object of property values to filter by.
* @returns {Array} Returns a new array of elements that have the given properties.
* @example
*
* var characters = [
* { 'name': 'barney', 'age': 36, 'pets': ['hoppy'] },
* { 'name': 'fred', 'age': 40, 'pets': ['baby puss', 'dino'] }
* ];
*
* _.where(characters, { 'age': 36 });
* // => [{ 'name': 'barney', 'age': 36, 'pets': ['hoppy'] }]
*
* _.where(characters, { 'pets': ['dino'] });
* // => [{ 'name': 'fred', 'age': 40, 'pets': ['baby puss', 'dino'] }]
*/
var where = filter;
/*--------------------------------------------------------------------------*/
/**
* Creates an array with all falsey values removed. The values `false`, `null`,
* `0`, `""`, `undefined`, and `NaN` are all falsey.
*
* @static
* @memberOf _
* @category Arrays
* @param {Array} array The array to compact.
* @returns {Array} Returns a new array of filtered values.
* @example
*
* _.compact([0, 1, false, 2, '', 3]);
* // => [1, 2, 3]
*/
function compact(array) {
var index = -1,
length = array ? array.length : 0,
result = [];
while (++index < length) {
var value = array[index];
if (value) {
result.push(value);
}
}
return result;
}
/**
* Creates an array excluding all values of the provided arrays using strict
* equality for comparisons, i.e. `===`.
*
* @static
* @memberOf _
* @category Arrays
* @param {Array} array The array to process.
* @param {...Array} [values] The arrays of values to exclude.
* @returns {Array} Returns a new array of filtered values.
* @example
*
* _.difference([1, 2, 3, 4, 5], [5, 2, 10]);
* // => [1, 3, 4]
*/
function difference(array) {
return baseDifference(array, baseFlatten(arguments, true, true, 1));
}
/**
* This method is like `_.find` except that it returns the index of the first
* element that passes the callback check, instead of the element itself.
*
* If a property name is provided for `callback` the created "_.pluck" style
* callback will return the property value of the given element.
*
* If an object is provided for `callback` the created "_.where" style callback
* will return `true` for elements that have the properties of the given object,
* else `false`.
*
* @static
* @memberOf _
* @category Arrays
* @param {Array} array The array to search.
* @param {Function|Object|string} [callback=identity] The function called
* per iteration. If a property name or object is provided it will be used
* to create a "_.pluck" or "_.where" style callback, respectively.
* @param {*} [thisArg] The `this` binding of `callback`.
* @returns {number} Returns the index of the found element, else `-1`.
* @example
*
* var characters = [
* { 'name': 'barney', 'age': 36, 'blocked': false },
* { 'name': 'fred', 'age': 40, 'blocked': true },
* { 'name': 'pebbles', 'age': 1, 'blocked': false }
* ];
*
* _.findIndex(characters, function(chr) {
* return chr.age < 20;
* });
* // => 2
*
* // using "_.where" callback shorthand
* _.findIndex(characters, { 'age': 36 });
* // => 0
*
* // using "_.pluck" callback shorthand
* _.findIndex(characters, 'blocked');
* // => 1
*/
function findIndex(array, callback, thisArg) {
var index = -1,
length = array ? array.length : 0;
callback = lodash.createCallback(callback, thisArg, 3);
while (++index < length) {
if (callback(array[index], index, array)) {
return index;
}
}
return -1;
}
/**
* This method is like `_.findIndex` except that it iterates over elements
* of a `collection` from right to left.
*
* If a property name is provided for `callback` the created "_.pluck" style
* callback will return the property value of the given element.
*
* If an object is provided for `callback` the created "_.where" style callback
* will return `true` for elements that have the properties of the given object,
* else `false`.
*
* @static
* @memberOf _
* @category Arrays
* @param {Array} array The array to search.
* @param {Function|Object|string} [callback=identity] The function called
* per iteration. If a property name or object is provided it will be used
* to create a "_.pluck" or "_.where" style callback, respectively.
* @param {*} [thisArg] The `this` binding of `callback`.
* @returns {number} Returns the index of the found element, else `-1`.
* @example
*
* var characters = [
* { 'name': 'barney', 'age': 36, 'blocked': true },
* { 'name': 'fred', 'age': 40, 'blocked': false },
* { 'name': 'pebbles', 'age': 1, 'blocked': true }
* ];
*
* _.findLastIndex(characters, function(chr) {
* return chr.age > 30;
* });
* // => 1
*
* // using "_.where" callback shorthand
* _.findLastIndex(characters, { 'age': 36 });
* // => 0
*
* // using "_.pluck" callback shorthand
* _.findLastIndex(characters, 'blocked');
* // => 2
*/
function findLastIndex(array, callback, thisArg) {
var length = array ? array.length : 0;
callback = lodash.createCallback(callback, thisArg, 3);
while (length--) {
if (callback(array[length], length, array)) {
return length;
}
}
return -1;
}
/**
* Gets the first element or first `n` elements of an array. If a callback
* is provided elements at the beginning of the array are returned as long
* as the callback returns truey. The callback is bound to `thisArg` and
* invoked with three arguments; (value, index, array).
*
* If a property name is provided for `callback` the created "_.pluck" style
* callback will return the property value of the given element.
*
* If an object is provided for `callback` the created "_.where" style callback
* will return `true` for elements that have the properties of the given object,
* else `false`.
*
* @static
* @memberOf _
* @alias head, take
* @category Arrays
* @param {Array} array The array to query.
* @param {Function|Object|number|string} [callback] The function called
* per element or the number of elements to return. If a property name or
* object is provided it will be used to create a "_.pluck" or "_.where"
* style callback, respectively.
* @param {*} [thisArg] The `this` binding of `callback`.
* @returns {*} Returns the first element(s) of `array`.
* @example
*
* _.first([1, 2, 3]);
* // => 1
*
* _.first([1, 2, 3], 2);
* // => [1, 2]
*
* _.first([1, 2, 3], function(num) {
* return num < 3;
* });
* // => [1, 2]
*
* var characters = [
* { 'name': 'barney', 'blocked': true, 'employer': 'slate' },
* { 'name': 'fred', 'blocked': false, 'employer': 'slate' },
* { 'name': 'pebbles', 'blocked': true, 'employer': 'na' }
* ];
*
* // using "_.pluck" callback shorthand
* _.first(characters, 'blocked');
* // => [{ 'name': 'barney', 'blocked': true, 'employer': 'slate' }]
*
* // using "_.where" callback shorthand
* _.pluck(_.first(characters, { 'employer': 'slate' }), 'name');
* // => ['barney', 'fred']
*/
function first(array, callback, thisArg) {
var n = 0,
length = array ? array.length : 0;
if (typeof callback != 'number' && callback != null) {
var index = -1;
callback = lodash.createCallback(callback, thisArg, 3);
while (++index < length && callback(array[index], index, array)) {
n++;
}
} else {
n = callback;
if (n == null || thisArg) {
return array ? array[0] : undefined;
}
}
return slice(array, 0, nativeMin(nativeMax(0, n), length));
}
/**
* Flattens a nested array (the nesting can be to any depth). If `isShallow`
* is truey, the array will only be flattened a single level. If a callback
* is provided each element of the array is passed through the callback before
* flattening. The callback is bound to `thisArg` and invoked with three
* arguments; (value, index, array).
*
* If a property name is provided for `callback` the created "_.pluck" style
* callback will return the property value of the given element.
*
* If an object is provided for `callback` the created "_.where" style callback
* will return `true` for elements that have the properties of the given object,
* else `false`.
*
* @static
* @memberOf _
* @category Arrays
* @param {Array} array The array to flatten.
* @param {boolean} [isShallow=false] A flag to restrict flattening to a single level.
* @param {Function|Object|string} [callback=identity] The function called
* per iteration. If a property name or object is provided it will be used
* to create a "_.pluck" or "_.where" style callback, respectively.
* @param {*} [thisArg] The `this` binding of `callback`.
* @returns {Array} Returns a new flattened array.
* @example
*
* _.flatten([1, [2], [3, [[4]]]]);
* // => [1, 2, 3, 4];
*
* _.flatten([1, [2], [3, [[4]]]], true);
* // => [1, 2, 3, [[4]]];
*
* var characters = [
* { 'name': 'barney', 'age': 30, 'pets': ['hoppy'] },
* { 'name': 'fred', 'age': 40, 'pets': ['baby puss', 'dino'] }
* ];
*
* // using "_.pluck" callback shorthand
* _.flatten(characters, 'pets');
* // => ['hoppy', 'baby puss', 'dino']
*/
function flatten(array, isShallow, callback, thisArg) {
// juggle arguments
if (typeof isShallow != 'boolean' && isShallow != null) {
thisArg = callback;
callback = (typeof isShallow != 'function' && thisArg && thisArg[isShallow] === array) ? null : isShallow;
isShallow = false;
}
if (callback != null) {
array = map(array, callback, thisArg);
}
return baseFlatten(array, isShallow);
}
/**
* Gets the index at which the first occurrence of `value` is found using
* strict equality for comparisons, i.e. `===`. If the array is already sorted
* providing `true` for `fromIndex` will run a faster binary search.
*
* @static
* @memberOf _
* @category Arrays
* @param {Array} array The array to search.
* @param {*} value The value to search for.
* @param {boolean|number} [fromIndex=0] The index to search from or `true`
* to perform a binary search on a sorted array.
* @returns {number} Returns the index of the matched value or `-1`.
* @example
*
* _.indexOf([1, 2, 3, 1, 2, 3], 2);
* // => 1
*
* _.indexOf([1, 2, 3, 1, 2, 3], 2, 3);
* // => 4
*
* _.indexOf([1, 1, 2, 2, 3, 3], 2, true);
* // => 2
*/
function indexOf(array, value, fromIndex) {
if (typeof fromIndex == 'number') {
var length = array ? array.length : 0;
fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex || 0);
} else if (fromIndex) {
var index = sortedIndex(array, value);
return array[index] === value ? index : -1;
}
return baseIndexOf(array, value, fromIndex);
}
/**
* Gets all but the last element or last `n` elements of an array. If a
* callback is provided elements at the end of the array are excluded from
* the result as long as the callback returns truey. The callback is bound
* to `thisArg` and invoked with three arguments; (value, index, array).
*
* If a property name is provided for `callback` the created "_.pluck" style
* callback will return the property value of the given element.
*
* If an object is provided for `callback` the created "_.where" style callback
* will return `true` for elements that have the properties of the given object,
* else `false`.
*
* @static
* @memberOf _
* @category Arrays
* @param {Array} array The array to query.
* @param {Function|Object|number|string} [callback=1] The function called
* per element or the number of elements to exclude. If a property name or
* object is provided it will be used to create a "_.pluck" or "_.where"
* style callback, respectively.
* @param {*} [thisArg] The `this` binding of `callback`.
* @returns {Array} Returns a slice of `array`.
* @example
*
* _.initial([1, 2, 3]);
* // => [1, 2]
*
* _.initial([1, 2, 3], 2);
* // => [1]
*
* _.initial([1, 2, 3], function(num) {
* return num > 1;
* });
* // => [1]
*
* var characters = [
* { 'name': 'barney', 'blocked': false, 'employer': 'slate' },
* { 'name': 'fred', 'blocked': true, 'employer': 'slate' },
* { 'name': 'pebbles', 'blocked': true, 'employer': 'na' }
* ];
*
* // using "_.pluck" callback shorthand
* _.initial(characters, 'blocked');
* // => [{ 'name': 'barney', 'blocked': false, 'employer': 'slate' }]
*
* // using "_.where" callback shorthand
* _.pluck(_.initial(characters, { 'employer': 'na' }), 'name');
* // => ['barney', 'fred']
*/
function initial(array, callback, thisArg) {
var n = 0,
length = array ? array.length : 0;
if (typeof callback != 'number' && callback != null) {
var index = length;
callback = lodash.createCallback(callback, thisArg, 3);
while (index-- && callback(array[index], index, array)) {
n++;
}
} else {
n = (callback == null || thisArg) ? 1 : callback || n;
}
return slice(array, 0, nativeMin(nativeMax(0, length - n), length));
}
/**
* Creates an array of unique values present in all provided arrays using
* strict equality for comparisons, i.e. `===`.
*
* @static
* @memberOf _
* @category Arrays
* @param {...Array} [array] The arrays to inspect.
* @returns {Array} Returns an array of shared values.
* @example
*
* _.intersection([1, 2, 3], [5, 2, 1, 4], [2, 1]);
* // => [1, 2]
*/
function intersection() {
var args = [],
argsIndex = -1,
argsLength = arguments.length,
caches = getArray(),
indexOf = getIndexOf(),
trustIndexOf = indexOf === baseIndexOf,
seen = getArray();
while (++argsIndex < argsLength) {
var value = arguments[argsIndex];
if (isArray(value) || isArguments(value)) {
args.push(value);
caches.push(trustIndexOf && value.length >= largeArraySize &&
createCache(argsIndex ? args[argsIndex] : seen));
}
}
var array = args[0],
index = -1,
length = array ? array.length : 0,
result = [];
outer:
while (++index < length) {
var cache = caches[0];
value = array[index];
if ((cache ? cacheIndexOf(cache, value) : indexOf(seen, value)) < 0) {
argsIndex = argsLength;
(cache || seen).push(value);
while (--argsIndex) {
cache = caches[argsIndex];
if ((cache ? cacheIndexOf(cache, value) : indexOf(args[argsIndex], value)) < 0) {
continue outer;
}
}
result.push(value);
}
}
while (argsLength--) {
cache = caches[argsLength];
if (cache) {
releaseObject(cache);
}
}
releaseArray(caches);
releaseArray(seen);
return result;
}
/**
* Gets the last element or last `n` elements of an array. If a callback is
* provided elements at the end of the array are returned as long as the
* callback returns truey. The callback is bound to `thisArg` and invoked
* with three arguments; (value, index, array).
*
* If a property name is provided for `callback` the created "_.pluck" style
* callback will return the property value of the given element.
*
* If an object is provided for `callback` the created "_.where" style callback
* will return `true` for elements that have the properties of the given object,
* else `false`.
*
* @static
* @memberOf _
* @category Arrays
* @param {Array} array The array to query.
* @param {Function|Object|number|string} [callback] The function called
* per element or the number of elements to return. If a property name or
* object is provided it will be used to create a "_.pluck" or "_.where"
* style callback, respectively.
* @param {*} [thisArg] The `this` binding of `callback`.
* @returns {*} Returns the last element(s) of `array`.
* @example
*
* _.last([1, 2, 3]);
* // => 3
*
* _.last([1, 2, 3], 2);
* // => [2, 3]
*
* _.last([1, 2, 3], function(num) {
* return num > 1;
* });
* // => [2, 3]
*
* var characters = [
* { 'name': 'barney', 'blocked': false, 'employer': 'slate' },
* { 'name': 'fred', 'blocked': true, 'employer': 'slate' },
* { 'name': 'pebbles', 'blocked': true, 'employer': 'na' }
* ];
*
* // using "_.pluck" callback shorthand
* _.pluck(_.last(characters, 'blocked'), 'name');
* // => ['fred', 'pebbles']
*
* // using "_.where" callback shorthand
* _.last(characters, { 'employer': 'na' });
* // => [{ 'name': 'pebbles', 'blocked': true, 'employer': 'na' }]
*/
function last(array, callback, thisArg) {
var n = 0,
length = array ? array.length : 0;
if (typeof callback != 'number' && callback != null) {
var index = length;
callback = lodash.createCallback(callback, thisArg, 3);
while (index-- && callback(array[index], index, array)) {
n++;
}
} else {
n = callback;
if (n == null || thisArg) {
return array ? array[length - 1] : undefined;
}
}
return slice(array, nativeMax(0, length - n));
}
/**
* Gets the index at which the last occurrence of `value` is found using strict
* equality for comparisons, i.e. `===`. If `fromIndex` is negative, it is used
* as the offset from the end of the collection.
*
* If a property name is provided for `callback` the created "_.pluck" style
* callback will return the property value of the given element.
*
* If an object is provided for `callback` the created "_.where" style callback
* will return `true` for elements that have the properties of the given object,
* else `false`.
*
* @static
* @memberOf _
* @category Arrays
* @param {Array} array The array to search.
* @param {*} value The value to search for.
* @param {number} [fromIndex=array.length-1] The index to search from.
* @returns {number} Returns the index of the matched value or `-1`.
* @example
*
* _.lastIndexOf([1, 2, 3, 1, 2, 3], 2);
* // => 4
*
* _.lastIndexOf([1, 2, 3, 1, 2, 3], 2, 3);
* // => 1
*/
function lastIndexOf(array, value, fromIndex) {
var index = array ? array.length : 0;
if (typeof fromIndex == 'number') {
index = (fromIndex < 0 ? nativeMax(0, index + fromIndex) : nativeMin(fromIndex, index - 1)) + 1;
}
while (index--) {
if (array[index] === value) {
return index;
}
}
return -1;
}
/**
* Removes all provided values from the given array using strict equality for
* comparisons, i.e. `===`.
*
* @static
* @memberOf _
* @category Arrays
* @param {Array} array The array to modify.
* @param {...*} [value] The values to remove.
* @returns {Array} Returns `array`.
* @example
*
* var array = [1, 2, 3, 1, 2, 3];
* _.pull(array, 2, 3);
* console.log(array);
* // => [1, 1]
*/
function pull(array) {
var args = arguments,
argsIndex = 0,
argsLength = args.length,
length = array ? array.length : 0;
while (++argsIndex < argsLength) {
var index = -1,
value = args[argsIndex];
while (++index < length) {
if (array[index] === value) {
splice.call(array, index--, 1);
length--;
}
}
}
return array;
}
/**
* Creates an array of numbers (positive and/or negative) progressing from
* `start` up to but not including `end`. If `start` is less than `stop` a
* zero-length range is created unless a negative `step` is specified.
*
* @static
* @memberOf _
* @category Arrays
* @param {number} [start=0] The start of the range.
* @param {number} end The end of the range.
* @param {number} [step=1] The value to increment or decrement by.
* @returns {Array} Returns a new range array.
* @example
*
* _.range(4);
* // => [0, 1, 2, 3]
*
* _.range(1, 5);
* // => [1, 2, 3, 4]
*
* _.range(0, 20, 5);
* // => [0, 5, 10, 15]
*
* _.range(0, -4, -1);
* // => [0, -1, -2, -3]
*
* _.range(1, 4, 0);
* // => [1, 1, 1]
*
* _.range(0);
* // => []
*/
function range(start, end, step) {
start = +start || 0;
step = typeof step == 'number' ? step : (+step || 1);
if (end == null) {
end = start;
start = 0;
}
// use `Array(length)` so engines like Chakra and V8 avoid slower modes
// http://youtu.be/XAqIpGU8ZZk#t=17m25s
var index = -1,
length = nativeMax(0, ceil((end - start) / (step || 1))),
result = Array(length);
while (++index < length) {
result[index] = start;
start += step;
}
return result;
}
/**
* Removes all elements from an array that the callback returns truey for
* and returns an array of removed elements. The callback is bound to `thisArg`
* and invoked with three arguments; (value, index, array).
*
* If a property name is provided for `callback` the created "_.pluck" style
* callback will return the property value of the given element.
*
* If an object is provided for `callback` the created "_.where" style callback
* will return `true` for elements that have the properties of the given object,
* else `false`.
*
* @static
* @memberOf _
* @category Arrays
* @param {Array} array The array to modify.
* @param {Function|Object|string} [callback=identity] The function called
* per iteration. If a property name or object is provided it will be used
* to create a "_.pluck" or "_.where" style callback, respectively.
* @param {*} [thisArg] The `this` binding of `callback`.
* @returns {Array} Returns a new array of removed elements.
* @example
*
* var array = [1, 2, 3, 4, 5, 6];
* var evens = _.remove(array, function(num) { return num % 2 == 0; });
*
* console.log(array);
* // => [1, 3, 5]
*
* console.log(evens);
* // => [2, 4, 6]
*/
function remove(array, callback, thisArg) {
var index = -1,
length = array ? array.length : 0,
result = [];
callback = lodash.createCallback(callback, thisArg, 3);
while (++index < length) {
var value = array[index];
if (callback(value, index, array)) {
result.push(value);
splice.call(array, index--, 1);
length--;
}
}
return result;
}
/**
* The opposite of `_.initial` this method gets all but the first element or
* first `n` elements of an array. If a callback function is provided elements
* at the beginning of the array are excluded from the result as long as the
* callback returns truey. The callback is bound to `thisArg` and invoked
* with three arguments; (value, index, array).
*
* If a property name is provided for `callback` the created "_.pluck" style
* callback will return the property value of the given element.
*
* If an object is provided for `callback` the created "_.where" style callback
* will return `true` for elements that have the properties of the given object,
* else `false`.
*
* @static
* @memberOf _
* @alias drop, tail
* @category Arrays
* @param {Array} array The array to query.
* @param {Function|Object|number|string} [callback=1] The function called
* per element or the number of elements to exclude. If a property name or
* object is provided it will be used to create a "_.pluck" or "_.where"
* style callback, respectively.
* @param {*} [thisArg] The `this` binding of `callback`.
* @returns {Array} Returns a slice of `array`.
* @example
*
* _.rest([1, 2, 3]);
* // => [2, 3]
*
* _.rest([1, 2, 3], 2);
* // => [3]
*
* _.rest([1, 2, 3], function(num) {
* return num < 3;
* });
* // => [3]
*
* var characters = [
* { 'name': 'barney', 'blocked': true, 'employer': 'slate' },
* { 'name': 'fred', 'blocked': false, 'employer': 'slate' },
* { 'name': 'pebbles', 'blocked': true, 'employer': 'na' }
* ];
*
* // using "_.pluck" callback shorthand
* _.pluck(_.rest(characters, 'blocked'), 'name');
* // => ['fred', 'pebbles']
*
* // using "_.where" callback shorthand
* _.rest(characters, { 'employer': 'slate' });
* // => [{ 'name': 'pebbles', 'blocked': true, 'employer': 'na' }]
*/
function rest(array, callback, thisArg) {
if (typeof callback != 'number' && callback != null) {
var n = 0,
index = -1,
length = array ? array.length : 0;
callback = lodash.createCallback(callback, thisArg, 3);
while (++index < length && callback(array[index], index, array)) {
n++;
}
} else {
n = (callback == null || thisArg) ? 1 : nativeMax(0, callback);
}
return slice(array, n);
}
/**
* Uses a binary search to determine the smallest index at which a value
* should be inserted into a given sorted array in order to maintain the sort
* order of the array. If a callback is provided it will be executed for
* `value` and each element of `array` to compute their sort ranking. The
* callback is bound to `thisArg` and invoked with one argument; (value).
*
* If a property name is provided for `callback` the created "_.pluck" style
* callback will return the property value of the given element.
*
* If an object is provided for `callback` the created "_.where" style callback
* will return `true` for elements that have the properties of the given object,
* else `false`.
*
* @static
* @memberOf _
* @category Arrays
* @param {Array} array The array to inspect.
* @param {*} value The value to evaluate.
* @param {Function|Object|string} [callback=identity] The function called
* per iteration. If a property name or object is provided it will be used
* to create a "_.pluck" or "_.where" style callback, respectively.
* @param {*} [thisArg] The `this` binding of `callback`.
* @returns {number} Returns the index at which `value` should be inserted
* into `array`.
* @example
*
* _.sortedIndex([20, 30, 50], 40);
* // => 2
*
* // using "_.pluck" callback shorthand
* _.sortedIndex([{ 'x': 20 }, { 'x': 30 }, { 'x': 50 }], { 'x': 40 }, 'x');
* // => 2
*
* var dict = {
* 'wordToNumber': { 'twenty': 20, 'thirty': 30, 'fourty': 40, 'fifty': 50 }
* };
*
* _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) {
* return dict.wordToNumber[word];
* });
* // => 2
*
* _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) {
* return this.wordToNumber[word];
* }, dict);
* // => 2
*/
function sortedIndex(array, value, callback, thisArg) {
var low = 0,
high = array ? array.length : low;
// explicitly reference `identity` for better inlining in Firefox
callback = callback ? lodash.createCallback(callback, thisArg, 1) : identity;
value = callback(value);
while (low < high) {
var mid = (low + high) >>> 1;
(callback(array[mid]) < value)
? low = mid + 1
: high = mid;
}
return low;
}
/**
* Creates an array of unique values, in order, of the provided arrays using
* strict equality for comparisons, i.e. `===`.
*
* @static
* @memberOf _
* @category Arrays
* @param {...Array} [array] The arrays to inspect.
* @returns {Array} Returns an array of combined values.
* @example
*
* _.union([1, 2, 3], [5, 2, 1, 4], [2, 1]);
* // => [1, 2, 3, 5, 4]
*/
function union() {
return baseUniq(baseFlatten(arguments, true, true));
}
/**
* Creates a duplicate-value-free version of an array using strict equality
* for comparisons, i.e. `===`. If the array is sorted, providing
* `true` for `isSorted` will use a faster algorithm. If a callback is provided
* each element of `array` is passed through the callback before uniqueness
* is computed. The callback is bound to `thisArg` and invoked with three
* arguments; (value, index, array).
*
* If a property name is provided for `callback` the created "_.pluck" style
* callback will return the property value of the given element.
*
* If an object is provided for `callback` the created "_.where" style callback
* will return `true` for elements that have the properties of the given object,
* else `false`.
*
* @static
* @memberOf _
* @alias unique
* @category Arrays
* @param {Array} array The array to process.
* @param {boolean} [isSorted=false] A flag to indicate that `array` is sorted.
* @param {Function|Object|string} [callback=identity] The function called
* per iteration. If a property name or object is provided it will be used
* to create a "_.pluck" or "_.where" style callback, respectively.
* @param {*} [thisArg] The `this` binding of `callback`.
* @returns {Array} Returns a duplicate-value-free array.
* @example
*
* _.uniq([1, 2, 1, 3, 1]);
* // => [1, 2, 3]
*
* _.uniq([1, 1, 2, 2, 3], true);
* // => [1, 2, 3]
*
* _.uniq(['A', 'b', 'C', 'a', 'B', 'c'], function(letter) { return letter.toLowerCase(); });
* // => ['A', 'b', 'C']
*
* _.uniq([1, 2.5, 3, 1.5, 2, 3.5], function(num) { return this.floor(num); }, Math);
* // => [1, 2.5, 3]
*
* // using "_.pluck" callback shorthand
* _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
* // => [{ 'x': 1 }, { 'x': 2 }]
*/
function uniq(array, isSorted, callback, thisArg) {
// juggle arguments
if (typeof isSorted != 'boolean' && isSorted != null) {
thisArg = callback;
callback = (typeof isSorted != 'function' && thisArg && thisArg[isSorted] === array) ? null : isSorted;
isSorted = false;
}
if (callback != null) {
callback = lodash.createCallback(callback, thisArg, 3);
}
return baseUniq(array, isSorted, callback);
}
/**
* Creates an array excluding all provided values using strict equality for
* comparisons, i.e. `===`.
*
* @static
* @memberOf _
* @category Arrays
* @param {Array} array The array to filter.
* @param {...*} [value] The values to exclude.
* @returns {Array} Returns a new array of filtered values.
* @example
*
* _.without([1, 2, 1, 0, 3, 1, 4], 0, 1);
* // => [2, 3, 4]
*/
function without(array) {
return baseDifference(array, slice(arguments, 1));
}
/**
* Creates an array that is the symmetric difference of the provided arrays.
* See http://en.wikipedia.org/wiki/Symmetric_difference.
*
* @static
* @memberOf _
* @category Arrays
* @param {...Array} [array] The arrays to inspect.
* @returns {Array} Returns an array of values.
* @example
*
* _.xor([1, 2, 3], [5, 2, 1, 4]);
* // => [3, 5, 4]
*
* _.xor([1, 2, 5], [2, 3, 5], [3, 4, 5]);
* // => [1, 4, 5]
*/
function xor() {
var index = -1,
length = arguments.length;
while (++index < length) {
var array = arguments[index];
if (isArray(array) || isArguments(array)) {
var result = result
? baseUniq(baseDifference(result, array).concat(baseDifference(array, result)))
: array;
}
}
return result || [];
}
/**
* Creates an array of grouped elements, the first of which contains the first
* elements of the given arrays, the second of which contains the second
* elements of the given arrays, and so on.
*
* @static
* @memberOf _
* @alias unzip
* @category Arrays
* @param {...Array} [array] Arrays to process.
* @returns {Array} Returns a new array of grouped elements.
* @example
*
* _.zip(['fred', 'barney'], [30, 40], [true, false]);
* // => [['fred', 30, true], ['barney', 40, false]]
*/
function zip() {
var array = arguments.length > 1 ? arguments : arguments[0],
index = -1,
length = array ? max(pluck(array, 'length')) : 0,
result = Array(length < 0 ? 0 : length);
while (++index < length) {
result[index] = pluck(array, index);
}
return result;
}
/**
* Creates an object composed from arrays of `keys` and `values`. Provide
* either a single two dimensional array, i.e. `[[key1, value1], [key2, value2]]`
* or two arrays, one of `keys` and one of corresponding `values`.
*
* @static
* @memberOf _
* @alias object
* @category Arrays
* @param {Array} keys The array of keys.
* @param {Array} [values=[]] The array of values.
* @returns {Object} Returns an object composed of the given keys and
* corresponding values.
* @example
*
* _.zipObject(['fred', 'barney'], [30, 40]);
* // => { 'fred': 30, 'barney': 40 }
*/
function zipObject(keys, values) {
var index = -1,
length = keys ? keys.length : 0,
result = {};
if (!values && length && !isArray(keys[0])) {
values = [];
}
while (++index < length) {
var key = keys[index];
if (values) {
result[key] = values[index];
} else if (key) {
result[key[0]] = key[1];
}
}
return result;
}
/*--------------------------------------------------------------------------*/
/**
* Creates a function that executes `func`, with the `this` binding and
* arguments of the created function, only after being called `n` times.
*
* @static
* @memberOf _
* @category Functions
* @param {number} n The number of times the function must be called before
* `func` is executed.
* @param {Function} func The function to restrict.
* @returns {Function} Returns the new restricted function.
* @example
*
* var saves = ['profile', 'settings'];
*
* var done = _.after(saves.length, function() {
* console.log('Done saving!');
* });
*
* _.forEach(saves, function(type) {
* asyncSave({ 'type': type, 'complete': done });
* });
* // => logs 'Done saving!', after all saves have completed
*/
function after(n, func) {
if (!isFunction(func)) {
throw new TypeError;
}
return function() {
if (--n < 1) {
return func.apply(this, arguments);
}
};
}
/**
* Creates a function that, when called, invokes `func` with the `this`
* binding of `thisArg` and prepends any additional `bind` arguments to those
* provided to the bound function.
*
* @static
* @memberOf _
* @category Functions
* @param {Function} func The function to bind.
* @param {*} [thisArg] The `this` binding of `func`.
* @param {...*} [arg] Arguments to be partially applied.
* @returns {Function} Returns the new bound function.
* @example
*
* var func = function(greeting) {
* return greeting + ' ' + this.name;
* };
*
* func = _.bind(func, { 'name': 'fred' }, 'hi');
* func();
* // => 'hi fred'
*/
function bind(func, thisArg) {
return arguments.length > 2
? createWrapper(func, 17, slice(arguments, 2), null, thisArg)
: createWrapper(func, 1, null, null, thisArg);
}
/**
* Binds methods of an object to the object itself, overwriting the existing
* method. Method names may be specified as individual arguments or as arrays
* of method names. If no method names are provided all the function properties
* of `object` will be bound.
*
* @static
* @memberOf _
* @category Functions
* @param {Object} object The object to bind and assign the bound methods to.
* @param {...string} [methodName] The object method names to
* bind, specified as individual method names or arrays of method names.
* @returns {Object} Returns `object`.
* @example
*
* var view = {
* 'label': 'docs',
* 'onClick': function() { console.log('clicked ' + this.label); }
* };
*
* _.bindAll(view);
* jQuery('#docs').on('click', view.onClick);
* // => logs 'clicked docs', when the button is clicked
*/
function bindAll(object) {
var funcs = arguments.length > 1 ? baseFlatten(arguments, true, false, 1) : functions(object),
index = -1,
length = funcs.length;
while (++index < length) {
var key = funcs[index];
object[key] = createWrapper(object[key], 1, null, null, object);
}
return object;
}
/**
* Creates a function that, when called, invokes the method at `object[key]`
* and prepends any additional `bindKey` arguments to those provided to the bound
* function. This method differs from `_.bind` by allowing bound functions to
* reference methods that will be redefined or don't yet exist.
* See http://michaux.ca/articles/lazy-function-definition-pattern.
*
* @static
* @memberOf _
* @category Functions
* @param {Object} object The object the method belongs to.
* @param {string} key The key of the method.
* @param {...*} [arg] Arguments to be partially applied.
* @returns {Function} Returns the new bound function.
* @example
*
* var object = {
* 'name': 'fred',
* 'greet': function(greeting) {
* return greeting + ' ' + this.name;
* }
* };
*
* var func = _.bindKey(object, 'greet', 'hi');
* func();
* // => 'hi fred'
*
* object.greet = function(greeting) {
* return greeting + 'ya ' + this.name + '!';
* };
*
* func();
* // => 'hiya fred!'
*/
function bindKey(object, key) {
return arguments.length > 2
? createWrapper(key, 19, slice(arguments, 2), null, object)
: createWrapper(key, 3, null, null, object);
}
/**
* Creates a function that is the composition of the provided functions,
* where each function consumes the return value of the function that follows.
* For example, composing the functions `f()`, `g()`, and `h()` produces `f(g(h()))`.
* Each function is executed with the `this` binding of the composed function.
*
* @static
* @memberOf _
* @category Functions
* @param {...Function} [func] Functions to compose.
* @returns {Function} Returns the new composed function.
* @example
*
* var realNameMap = {
* 'pebbles': 'penelope'
* };
*
* var format = function(name) {
* name = realNameMap[name.toLowerCase()] || name;
* return name.charAt(0).toUpperCase() + name.slice(1).toLowerCase();
* };
*
* var greet = function(formatted) {
* return 'Hiya ' + formatted + '!';
* };
*
* var welcome = _.compose(greet, format);
* welcome('pebbles');
* // => 'Hiya Penelope!'
*/
function compose() {
var funcs = arguments,
length = funcs.length;
while (length--) {
if (!isFunction(funcs[length])) {
throw new TypeError;
}
}
return function() {
var args = arguments,
length = funcs.length;
while (length--) {
args = [funcs[length].apply(this, args)];
}
return args[0];
};
}
/**
* Creates a function which accepts one or more arguments of `func` that when
* invoked either executes `func` returning its result, if all `func` arguments
* have been provided, or returns a function that accepts one or more of the
* remaining `func` arguments, and so on. The arity of `func` can be specified
* if `func.length` is not sufficient.
*
* @static
* @memberOf _
* @category Functions
* @param {Function} func The function to curry.
* @param {number} [arity=func.length] The arity of `func`.
* @returns {Function} Returns the new curried function.
* @example
*
* var curried = _.curry(function(a, b, c) {
* console.log(a + b + c);
* });
*
* curried(1)(2)(3);
* // => 6
*
* curried(1, 2)(3);
* // => 6
*
* curried(1, 2, 3);
* // => 6
*/
function curry(func, arity) {
arity = typeof arity == 'number' ? arity : (+arity || func.length);
return createWrapper(func, 4, null, null, null, arity);
}
/**
* Creates a function that will delay the execution of `func` until after
* `wait` milliseconds have elapsed since the last time it was invoked.
* Provide an options object to indicate that `func` should be invoked on
* the leading and/or trailing edge of the `wait` timeout. Subsequent calls
* to the debounced function will return the result of the last `func` call.
*
* Note: If `leading` and `trailing` options are `true` `func` will be called
* on the trailing edge of the timeout only if the the debounced function is
* invoked more than once during the `wait` timeout.
*
* @static
* @memberOf _
* @category Functions
* @param {Function} func The function to debounce.
* @param {number} wait The number of milliseconds to delay.
* @param {Object} [options] The options object.
* @param {boolean} [options.leading=false] Specify execution on the leading edge of the timeout.
* @param {number} [options.maxWait] The maximum time `func` is allowed to be delayed before it's called.
* @param {boolean} [options.trailing=true] Specify execution on the trailing edge of the timeout.
* @returns {Function} Returns the new debounced function.
* @example
*
* // avoid costly calculations while the window size is in flux
* var lazyLayout = _.debounce(calculateLayout, 150);
* jQuery(window).on('resize', lazyLayout);
*
* // execute `sendMail` when the click event is fired, debouncing subsequent calls
* jQuery('#postbox').on('click', _.debounce(sendMail, 300, {
* 'leading': true,
* 'trailing': false
* });
*
* // ensure `batchLog` is executed once after 1 second of debounced calls
* var source = new EventSource('/stream');
* source.addEventListener('message', _.debounce(batchLog, 250, {
* 'maxWait': 1000
* }, false);
*/
function debounce(func, wait, options) {
var args,
maxTimeoutId,
result,
stamp,
thisArg,
timeoutId,
trailingCall,
lastCalled = 0,
maxWait = false,
trailing = true;
if (!isFunction(func)) {
throw new TypeError;
}
wait = nativeMax(0, wait) || 0;
if (options === true) {
var leading = true;
trailing = false;
} else if (isObject(options)) {
leading = options.leading;
maxWait = 'maxWait' in options && (nativeMax(wait, options.maxWait) || 0);
trailing = 'trailing' in options ? options.trailing : trailing;
}
var delayed = function() {
var remaining = wait - (now() - stamp);
if (remaining <= 0) {
if (maxTimeoutId) {
clearTimeout(maxTimeoutId);
}
var isCalled = trailingCall;
maxTimeoutId = timeoutId = trailingCall = undefined;
if (isCalled) {
lastCalled = now();
result = func.apply(thisArg, args);
if (!timeoutId && !maxTimeoutId) {
args = thisArg = null;
}
}
} else {
timeoutId = setTimeout(delayed, remaining);
}
};
var maxDelayed = function() {
if (timeoutId) {
clearTimeout(timeoutId);
}
maxTimeoutId = timeoutId = trailingCall = undefined;
if (trailing || (maxWait !== wait)) {
lastCalled = now();
result = func.apply(thisArg, args);
if (!timeoutId && !maxTimeoutId) {
args = thisArg = null;
}
}
};
return function() {
args = arguments;
stamp = now();
thisArg = this;
trailingCall = trailing && (timeoutId || !leading);
if (maxWait === false) {
var leadingCall = leading && !timeoutId;
} else {
if (!maxTimeoutId && !leading) {
lastCalled = stamp;
}
var remaining = maxWait - (stamp - lastCalled),
isCalled = remaining <= 0;
if (isCalled) {
if (maxTimeoutId) {
maxTimeoutId = clearTimeout(maxTimeoutId);
}
lastCalled = stamp;
result = func.apply(thisArg, args);
}
else if (!maxTimeoutId) {
maxTimeoutId = setTimeout(maxDelayed, remaining);
}
}
if (isCalled && timeoutId) {
timeoutId = clearTimeout(timeoutId);
}
else if (!timeoutId && wait !== maxWait) {
timeoutId = setTimeout(delayed, wait);
}
if (leadingCall) {
isCalled = true;
result = func.apply(thisArg, args);
}
if (isCalled && !timeoutId && !maxTimeoutId) {
args = thisArg = null;
}
return result;
};
}
/**
* Defers executing the `func` function until the current call stack has cleared.
* Additional arguments will be provided to `func` when it is invoked.
*
* @static
* @memberOf _
* @category Functions
* @param {Function} func The function to defer.
* @param {...*} [arg] Arguments to invoke the function with.
* @returns {number} Returns the timer id.
* @example
*
* _.defer(function(text) { console.log(text); }, 'deferred');
* // logs 'deferred' after one or more milliseconds
*/
function defer(func) {
if (!isFunction(func)) {
throw new TypeError;
}
var args = slice(arguments, 1);
return setTimeout(function() { func.apply(undefined, args); }, 1);
}
/**
* Executes the `func` function after `wait` milliseconds. Additional arguments
* will be provided to `func` when it is invoked.
*
* @static
* @memberOf _
* @category Functions
* @param {Function} func The function to delay.
* @param {number} wait The number of milliseconds to delay execution.
* @param {...*} [arg] Arguments to invoke the function with.
* @returns {number} Returns the timer id.
* @example
*
* _.delay(function(text) { console.log(text); }, 1000, 'later');
* // => logs 'later' after one second
*/
function delay(func, wait) {
if (!isFunction(func)) {
throw new TypeError;
}
var args = slice(arguments, 2);
return setTimeout(function() { func.apply(undefined, args); }, wait);
}
/**
* Creates a function that memoizes the result of `func`. If `resolver` is
* provided it will be used to determine the cache key for storing the result
* based on the arguments provided to the memoized function. By default, the
* first argument provided to the memoized function is used as the cache key.
* The `func` is executed with the `this` binding of the memoized function.
* The result cache is exposed as the `cache` property on the memoized function.
*
* @static
* @memberOf _
* @category Functions
* @param {Function} func The function to have its output memoized.
* @param {Function} [resolver] A function used to resolve the cache key.
* @returns {Function} Returns the new memoizing function.
* @example
*
* var fibonacci = _.memoize(function(n) {
* return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);
* });
*
* fibonacci(9)
* // => 34
*
* var data = {
* 'fred': { 'name': 'fred', 'age': 40 },
* 'pebbles': { 'name': 'pebbles', 'age': 1 }
* };
*
* // modifying the result cache
* var get = _.memoize(function(name) { return data[name]; }, _.identity);
* get('pebbles');
* // => { 'name': 'pebbles', 'age': 1 }
*
* get.cache.pebbles.name = 'penelope';
* get('pebbles');
* // => { 'name': 'penelope', 'age': 1 }
*/
function memoize(func, resolver) {
if (!isFunction(func)) {
throw new TypeError;
}
var memoized = function() {
var cache = memoized.cache,
key = resolver ? resolver.apply(this, arguments) : keyPrefix + arguments[0];
return hasOwnProperty.call(cache, key)
? cache[key]
: (cache[key] = func.apply(this, arguments));
}
memoized.cache = {};
return memoized;
}
/**
* Creates a function that is restricted to execute `func` once. Repeat calls to
* the function will return the value of the first call. The `func` is executed
* with the `this` binding of the created function.
*
* @static
* @memberOf _
* @category Functions
* @param {Function} func The function to restrict.
* @returns {Function} Returns the new restricted function.
* @example
*
* var initialize = _.once(createApplication);
* initialize();
* initialize();
* // `initialize` executes `createApplication` once
*/
function once(func) {
var ran,
result;
if (!isFunction(func)) {
throw new TypeError;
}
return function() {
if (ran) {
return result;
}
ran = true;
result = func.apply(this, arguments);
// clear the `func` variable so the function may be garbage collected
func = null;
return result;
};
}
/**
* Creates a function that, when called, invokes `func` with any additional
* `partial` arguments prepended to those provided to the new function. This
* method is similar to `_.bind` except it does **not** alter the `this` binding.
*
* @static
* @memberOf _
* @category Functions
* @param {Function} func The function to partially apply arguments to.
* @param {...*} [arg] Arguments to be partially applied.
* @returns {Function} Returns the new partially applied function.
* @example
*
* var greet = function(greeting, name) { return greeting + ' ' + name; };
* var hi = _.partial(greet, 'hi');
* hi('fred');
* // => 'hi fred'
*/
function partial(func) {
return createWrapper(func, 16, slice(arguments, 1));
}
/**
* This method is like `_.partial` except that `partial` arguments are
* appended to those provided to the new function.
*
* @static
* @memberOf _
* @category Functions
* @param {Function} func The function to partially apply arguments to.
* @param {...*} [arg] Arguments to be partially applied.
* @returns {Function} Returns the new partially applied function.
* @example
*
* var defaultsDeep = _.partialRight(_.merge, _.defaults);
*
* var options = {
* 'variable': 'data',
* 'imports': { 'jq': $ }
* };
*
* defaultsDeep(options, _.templateSettings);
*
* options.variable
* // => 'data'
*
* options.imports
* // => { '_': _, 'jq': $ }
*/
function partialRight(func) {
return createWrapper(func, 32, null, slice(arguments, 1));
}
/**
* Creates a function that, when executed, will only call the `func` function
* at most once per every `wait` milliseconds. Provide an options object to
* indicate that `func` should be invoked on the leading and/or trailing edge
* of the `wait` timeout. Subsequent calls to the throttled function will
* return the result of the last `func` call.
*
* Note: If `leading` and `trailing` options are `true` `func` will be called
* on the trailing edge of the timeout only if the the throttled function is
* invoked more than once during the `wait` timeout.
*
* @static
* @memberOf _
* @category Functions
* @param {Function} func The function to throttle.
* @param {number} wait The number of milliseconds to throttle executions to.
* @param {Object} [options] The options object.
* @param {boolean} [options.leading=true] Specify execution on the leading edge of the timeout.
* @param {boolean} [options.trailing=true] Specify execution on the trailing edge of the timeout.
* @returns {Function} Returns the new throttled function.
* @example
*
* // avoid excessively updating the position while scrolling
* var throttled = _.throttle(updatePosition, 100);
* jQuery(window).on('scroll', throttled);
*
* // execute `renewToken` when the click event is fired, but not more than once every 5 minutes
* jQuery('.interactive').on('click', _.throttle(renewToken, 300000, {
* 'trailing': false
* }));
*/
function throttle(func, wait, options) {
var leading = true,
trailing = true;
if (!isFunction(func)) {
throw new TypeError;
}
if (options === false) {
leading = false;
} else if (isObject(options)) {
leading = 'leading' in options ? options.leading : leading;
trailing = 'trailing' in options ? options.trailing : trailing;
}
debounceOptions.leading = leading;
debounceOptions.maxWait = wait;
debounceOptions.trailing = trailing;
return debounce(func, wait, debounceOptions);
}
/**
* Creates a function that provides `value` to the wrapper function as its
* first argument. Additional arguments provided to the function are appended
* to those provided to the wrapper function. The wrapper is executed with
* the `this` binding of the created function.
*
* @static
* @memberOf _
* @category Functions
* @param {*} value The value to wrap.
* @param {Function} wrapper The wrapper function.
* @returns {Function} Returns the new function.
* @example
*
* var p = _.wrap(_.escape, function(func, text) {
* return '<p>' + func(text) + '</p>';
* });
*
* p('Fred, Wilma, & Pebbles');
* // => '<p>Fred, Wilma, &amp; Pebbles</p>'
*/
function wrap(value, wrapper) {
return createWrapper(wrapper, 16, [value]);
}
/*--------------------------------------------------------------------------*/
/**
* Creates a function that returns `value`.
*
* @static
* @memberOf _
* @category Utilities
* @param {*} value The value to return from the new function.
* @returns {Function} Returns the new function.
* @example
*
* var object = { 'name': 'fred' };
* var getter = _.constant(object);
* getter() === object;
* // => true
*/
function constant(value) {
return function() {
return value;
};
}
/**
* Produces a callback bound to an optional `thisArg`. If `func` is a property
* name the created callback will return the property value for a given element.
* If `func` is an object the created callback will return `true` for elements
* that contain the equivalent object properties, otherwise it will return `false`.
*
* @static
* @memberOf _
* @category Utilities
* @param {*} [func=identity] The value to convert to a callback.
* @param {*} [thisArg] The `this` binding of the created callback.
* @param {number} [argCount] The number of arguments the callback accepts.
* @returns {Function} Returns a callback function.
* @example
*
* var characters = [
* { 'name': 'barney', 'age': 36 },
* { 'name': 'fred', 'age': 40 }
* ];
*
* // wrap to create custom callback shorthands
* _.createCallback = _.wrap(_.createCallback, function(func, callback, thisArg) {
* var match = /^(.+?)__([gl]t)(.+)$/.exec(callback);
* return !match ? func(callback, thisArg) : function(object) {
* return match[2] == 'gt' ? object[match[1]] > match[3] : object[match[1]] < match[3];
* };
* });
*
* _.filter(characters, 'age__gt38');
* // => [{ 'name': 'fred', 'age': 40 }]
*/
function createCallback(func, thisArg, argCount) {
var type = typeof func;
if (func == null || type == 'function') {
return baseCreateCallback(func, thisArg, argCount);
}
// handle "_.pluck" style callback shorthands
if (type != 'object') {
return property(func);
}
var props = keys(func),
key = props[0],
a = func[key];
// handle "_.where" style callback shorthands
if (props.length == 1 && a === a && !isObject(a)) {
// fast path the common case of providing an object with a single
// property containing a primitive value
return function(object) {
var b = object[key];
return a === b && (a !== 0 || (1 / a == 1 / b));
};
}
return function(object) {
var length = props.length,
result = false;
while (length--) {
if (!(result = baseIsEqual(object[props[length]], func[props[length]], null, true))) {
break;
}
}
return result;
};
}
/**
* Converts the characters `&`, `<`, `>`, `"`, and `'` in `string` to their
* corresponding HTML entities.
*
* @static
* @memberOf _
* @category Utilities
* @param {string} string The string to escape.
* @returns {string} Returns the escaped string.
* @example
*
* _.escape('Fred, Wilma, & Pebbles');
* // => 'Fred, Wilma, &amp; Pebbles'
*/
function escape(string) {
return string == null ? '' : String(string).replace(reUnescapedHtml, escapeHtmlChar);
}
/**
* This method returns the first argument provided to it.
*
* @static
* @memberOf _
* @category Utilities
* @param {*} value Any value.
* @returns {*} Returns `value`.
* @example
*
* var object = { 'name': 'fred' };
* _.identity(object) === object;
* // => true
*/
function identity(value) {
return value;
}
/**
* Adds function properties of a source object to the destination object.
* If `object` is a function methods will be added to its prototype as well.
*
* @static
* @memberOf _
* @category Utilities
* @param {Function|Object} [object=lodash] object The destination object.
* @param {Object} source The object of functions to add.
* @param {Object} [options] The options object.
* @param {boolean} [options.chain=true] Specify whether the functions added are chainable.
* @example
*
* function capitalize(string) {
* return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase();
* }
*
* _.mixin({ 'capitalize': capitalize });
* _.capitalize('fred');
* // => 'Fred'
*
* _('fred').capitalize().value();
* // => 'Fred'
*
* _.mixin({ 'capitalize': capitalize }, { 'chain': false });
* _('fred').capitalize();
* // => 'Fred'
*/
function mixin(object, source, options) {
var chain = true,
methodNames = source && functions(source);
if (!source || (!options && !methodNames.length)) {
if (options == null) {
options = source;
}
ctor = lodashWrapper;
source = object;
object = lodash;
methodNames = functions(source);
}
if (options === false) {
chain = false;
} else if (isObject(options) && 'chain' in options) {
chain = options.chain;
}
var ctor = object,
isFunc = isFunction(ctor);
forEach(methodNames, function(methodName) {
var func = object[methodName] = source[methodName];
if (isFunc) {
ctor.prototype[methodName] = function() {
var chainAll = this.__chain__,
value = this.__wrapped__,
args = [value];
push.apply(args, arguments);
var result = func.apply(object, args);
if (chain || chainAll) {
if (value === result && isObject(result)) {
return this;
}
result = new ctor(result);
result.__chain__ = chainAll;
}
return result;
};
}
});
}
/**
* Reverts the '_' variable to its previous value and returns a reference to
* the `lodash` function.
*
* @static
* @memberOf _
* @category Utilities
* @returns {Function} Returns the `lodash` function.
* @example
*
* var lodash = _.noConflict();
*/
function noConflict() {
context._ = oldDash;
return this;
}
/**
* A no-operation function.
*
* @static
* @memberOf _
* @category Utilities
* @example
*
* var object = { 'name': 'fred' };
* _.noop(object) === undefined;
* // => true
*/
function noop() {
// no operation performed
}
/**
* Gets the number of milliseconds that have elapsed since the Unix epoch
* (1 January 1970 00:00:00 UTC).
*
* @static
* @memberOf _
* @category Utilities
* @example
*
* var stamp = _.now();
* _.defer(function() { console.log(_.now() - stamp); });
* // => logs the number of milliseconds it took for the deferred function to be called
*/
var now = isNative(now = Date.now) && now || function() {
return new Date().getTime();
};
/**
* Converts the given value into an integer of the specified radix.
* If `radix` is `undefined` or `0` a `radix` of `10` is used unless the
* `value` is a hexadecimal, in which case a `radix` of `16` is used.
*
* Note: This method avoids differences in native ES3 and ES5 `parseInt`
* implementations. See http://es5.github.io/#E.
*
* @static
* @memberOf _
* @category Utilities
* @param {string} value The value to parse.
* @param {number} [radix] The radix used to interpret the value to parse.
* @returns {number} Returns the new integer value.
* @example
*
* _.parseInt('08');
* // => 8
*/
var parseInt = nativeParseInt(whitespace + '08') == 8 ? nativeParseInt : function(value, radix) {
// Firefox < 21 and Opera < 15 follow the ES3 specified implementation of `parseInt`
return nativeParseInt(isString(value) ? value.replace(reLeadingSpacesAndZeros, '') : value, radix || 0);
};
/**
* Creates a "_.pluck" style function, which returns the `key` value of a
* given object.
*
* @static
* @memberOf _
* @category Utilities
* @param {string} key The name of the property to retrieve.
* @returns {Function} Returns the new function.
* @example
*
* var characters = [
* { 'name': 'fred', 'age': 40 },
* { 'name': 'barney', 'age': 36 }
* ];
*
* var getName = _.property('name');
*
* _.map(characters, getName);
* // => ['barney', 'fred']
*
* _.sortBy(characters, getName);
* // => [{ 'name': 'barney', 'age': 36 }, { 'name': 'fred', 'age': 40 }]
*/
function property(key) {
return function(object) {
return object[key];
};
}
/**
* Produces a random number between `min` and `max` (inclusive). If only one
* argument is provided a number between `0` and the given number will be
* returned. If `floating` is truey or either `min` or `max` are floats a
* floating-point number will be returned instead of an integer.
*
* @static
* @memberOf _
* @category Utilities
* @param {number} [min=0] The minimum possible value.
* @param {number} [max=1] The maximum possible value.
* @param {boolean} [floating=false] Specify returning a floating-point number.
* @returns {number} Returns a random number.
* @example
*
* _.random(0, 5);
* // => an integer between 0 and 5
*
* _.random(5);
* // => also an integer between 0 and 5
*
* _.random(5, true);
* // => a floating-point number between 0 and 5
*
* _.random(1.2, 5.2);
* // => a floating-point number between 1.2 and 5.2
*/
function random(min, max, floating) {
var noMin = min == null,
noMax = max == null;
if (floating == null) {
if (typeof min == 'boolean' && noMax) {
floating = min;
min = 1;
}
else if (!noMax && typeof max == 'boolean') {
floating = max;
noMax = true;
}
}
if (noMin && noMax) {
max = 1;
}
min = +min || 0;
if (noMax) {
max = min;
min = 0;
} else {
max = +max || 0;
}
if (floating || min % 1 || max % 1) {
var rand = nativeRandom();
return nativeMin(min + (rand * (max - min + parseFloat('1e-' + ((rand +'').length - 1)))), max);
}
return baseRandom(min, max);
}
/**
* Resolves the value of property `key` on `object`. If `key` is a function
* it will be invoked with the `this` binding of `object` and its result returned,
* else the property value is returned. If `object` is falsey then `undefined`
* is returned.
*
* @static
* @memberOf _
* @category Utilities
* @param {Object} object The object to inspect.
* @param {string} key The name of the property to resolve.
* @returns {*} Returns the resolved value.
* @example
*
* var object = {
* 'cheese': 'crumpets',
* 'stuff': function() {
* return 'nonsense';
* }
* };
*
* _.result(object, 'cheese');
* // => 'crumpets'
*
* _.result(object, 'stuff');
* // => 'nonsense'
*/
function result(object, key) {
if (object) {
var value = object[key];
return isFunction(value) ? object[key]() : value;
}
}
/**
* A micro-templating method that handles arbitrary delimiters, preserves
* whitespace, and correctly escapes quotes within interpolated code.
*
* Note: In the development build, `_.template` utilizes sourceURLs for easier
* debugging. See http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl
*
* For more information on precompiling templates see:
* http://lodash.com/custom-builds
*
* For more information on Chrome extension sandboxes see:
* http://developer.chrome.com/stable/extensions/sandboxingEval.html
*
* @static
* @memberOf _
* @category Utilities
* @param {string} text The template text.
* @param {Object} data The data object used to populate the text.
* @param {Object} [options] The options object.
* @param {RegExp} [options.escape] The "escape" delimiter.
* @param {RegExp} [options.evaluate] The "evaluate" delimiter.
* @param {Object} [options.imports] An object to import into the template as local variables.
* @param {RegExp} [options.interpolate] The "interpolate" delimiter.
* @param {string} [sourceURL] The sourceURL of the template's compiled source.
* @param {string} [variable] The data object variable name.
* @returns {Function|string} Returns a compiled function when no `data` object
* is given, else it returns the interpolated text.
* @example
*
* // using the "interpolate" delimiter to create a compiled template
* var compiled = _.template('hello <%= name %>');
* compiled({ 'name': 'fred' });
* // => 'hello fred'
*
* // using the "escape" delimiter to escape HTML in data property values
* _.template('<b><%- value %></b>', { 'value': '<script>' });
* // => '<b>&lt;script&gt;</b>'
*
* // using the "evaluate" delimiter to generate HTML
* var list = '<% _.forEach(people, function(name) { %><li><%- name %></li><% }); %>';
* _.template(list, { 'people': ['fred', 'barney'] });
* // => '<li>fred</li><li>barney</li>'
*
* // using the ES6 delimiter as an alternative to the default "interpolate" delimiter
* _.template('hello ${ name }', { 'name': 'pebbles' });
* // => 'hello pebbles'
*
* // using the internal `print` function in "evaluate" delimiters
* _.template('<% print("hello " + name); %>!', { 'name': 'barney' });
* // => 'hello barney!'
*
* // using a custom template delimiters
* _.templateSettings = {
* 'interpolate': /{{([\s\S]+?)}}/g
* };
*
* _.template('hello {{ name }}!', { 'name': 'mustache' });
* // => 'hello mustache!'
*
* // using the `imports` option to import jQuery
* var list = '<% jq.each(people, function(name) { %><li><%- name %></li><% }); %>';
* _.template(list, { 'people': ['fred', 'barney'] }, { 'imports': { 'jq': jQuery } });
* // => '<li>fred</li><li>barney</li>'
*
* // using the `sourceURL` option to specify a custom sourceURL for the template
* var compiled = _.template('hello <%= name %>', null, { 'sourceURL': '/basic/greeting.jst' });
* compiled(data);
* // => find the source of "greeting.jst" under the Sources tab or Resources panel of the web inspector
*
* // using the `variable` option to ensure a with-statement isn't used in the compiled template
* var compiled = _.template('hi <%= data.name %>!', null, { 'variable': 'data' });
* compiled.source;
* // => function(data) {
* var __t, __p = '', __e = _.escape;
* __p += 'hi ' + ((__t = ( data.name )) == null ? '' : __t) + '!';
* return __p;
* }
*
* // using the `source` property to inline compiled templates for meaningful
* // line numbers in error messages and a stack trace
* fs.writeFileSync(path.join(cwd, 'jst.js'), '\
* var JST = {\
* "main": ' + _.template(mainText).source + '\
* };\
* ');
*/
function template(text, data, options) {
// based on John Resig's `tmpl` implementation
// http://ejohn.org/blog/javascript-micro-templating/
// and Laura Doktorova's doT.js
// https://github.com/olado/doT
var settings = lodash.templateSettings;
text = String(text || '');
// avoid missing dependencies when `iteratorTemplate` is not defined
options = defaults({}, options, settings);
var imports = defaults({}, options.imports, settings.imports),
importsKeys = keys(imports),
importsValues = values(imports);
var isEvaluating,
index = 0,
interpolate = options.interpolate || reNoMatch,
source = "__p += '";
// compile the regexp to match each delimiter
var reDelimiters = RegExp(
(options.escape || reNoMatch).source + '|' +
interpolate.source + '|' +
(interpolate === reInterpolate ? reEsTemplate : reNoMatch).source + '|' +
(options.evaluate || reNoMatch).source + '|$'
, 'g');
text.replace(reDelimiters, function(match, escapeValue, interpolateValue, esTemplateValue, evaluateValue, offset) {
interpolateValue || (interpolateValue = esTemplateValue);
// escape characters that cannot be included in string literals
source += text.slice(index, offset).replace(reUnescapedString, escapeStringChar);
// replace delimiters with snippets
if (escapeValue) {
source += "' +\n__e(" + escapeValue + ") +\n'";
}
if (evaluateValue) {
isEvaluating = true;
source += "';\n" + evaluateValue + ";\n__p += '";
}
if (interpolateValue) {
source += "' +\n((__t = (" + interpolateValue + ")) == null ? '' : __t) +\n'";
}
index = offset + match.length;
// the JS engine embedded in Adobe products requires returning the `match`
// string in order to produce the correct `offset` value
return match;
});
source += "';\n";
// if `variable` is not specified, wrap a with-statement around the generated
// code to add the data object to the top of the scope chain
var variable = options.variable,
hasVariable = variable;
if (!hasVariable) {
variable = 'obj';
source = 'with (' + variable + ') {\n' + source + '\n}\n';
}
// cleanup code by stripping empty strings
source = (isEvaluating ? source.replace(reEmptyStringLeading, '') : source)
.replace(reEmptyStringMiddle, '$1')
.replace(reEmptyStringTrailing, '$1;');
// frame code as the function body
source = 'function(' + variable + ') {\n' +
(hasVariable ? '' : variable + ' || (' + variable + ' = {});\n') +
"var __t, __p = '', __e = _.escape" +
(isEvaluating
? ', __j = Array.prototype.join;\n' +
"function print() { __p += __j.call(arguments, '') }\n"
: ';\n'
) +
source +
'return __p\n}';
// Use a sourceURL for easier debugging.
// http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl
var sourceURL = '\n/*\n//# sourceURL=' + (options.sourceURL || '/lodash/template/source[' + (templateCounter++) + ']') + '\n*/';
try {
var result = Function(importsKeys, 'return ' + source + sourceURL).apply(undefined, importsValues);
} catch(e) {
e.source = source;
throw e;
}
if (data) {
return result(data);
}
// provide the compiled function's source by its `toString` method, in
// supported environments, or the `source` property as a convenience for
// inlining compiled templates during the build process
result.source = source;
return result;
}
/**
* Executes the callback `n` times, returning an array of the results
* of each callback execution. The callback is bound to `thisArg` and invoked
* with one argument; (index).
*
* @static
* @memberOf _
* @category Utilities
* @param {number} n The number of times to execute the callback.
* @param {Function} callback The function called per iteration.
* @param {*} [thisArg] The `this` binding of `callback`.
* @returns {Array} Returns an array of the results of each `callback` execution.
* @example
*
* var diceRolls = _.times(3, _.partial(_.random, 1, 6));
* // => [3, 6, 4]
*
* _.times(3, function(n) { mage.castSpell(n); });
* // => calls `mage.castSpell(n)` three times, passing `n` of `0`, `1`, and `2` respectively
*
* _.times(3, function(n) { this.cast(n); }, mage);
* // => also calls `mage.castSpell(n)` three times
*/
function times(n, callback, thisArg) {
n = (n = +n) > -1 ? n : 0;
var index = -1,
result = Array(n);
callback = baseCreateCallback(callback, thisArg, 1);
while (++index < n) {
result[index] = callback(index);
}
return result;
}
/**
* The inverse of `_.escape` this method converts the HTML entities
* `&amp;`, `&lt;`, `&gt;`, `&quot;`, and `&#39;` in `string` to their
* corresponding characters.
*
* @static
* @memberOf _
* @category Utilities
* @param {string} string The string to unescape.
* @returns {string} Returns the unescaped string.
* @example
*
* _.unescape('Fred, Barney &amp; Pebbles');
* // => 'Fred, Barney & Pebbles'
*/
function unescape(string) {
return string == null ? '' : String(string).replace(reEscapedHtml, unescapeHtmlChar);
}
/**
* Generates a unique ID. If `prefix` is provided the ID will be appended to it.
*
* @static
* @memberOf _
* @category Utilities
* @param {string} [prefix] The value to prefix the ID with.
* @returns {string} Returns the unique ID.
* @example
*
* _.uniqueId('contact_');
* // => 'contact_104'
*
* _.uniqueId();
* // => '105'
*/
function uniqueId(prefix) {
var id = ++idCounter;
return String(prefix == null ? '' : prefix) + id;
}
/*--------------------------------------------------------------------------*/
/**
* Creates a `lodash` object that wraps the given value with explicit
* method chaining enabled.
*
* @static
* @memberOf _
* @category Chaining
* @param {*} value The value to wrap.
* @returns {Object} Returns the wrapper object.
* @example
*
* var characters = [
* { 'name': 'barney', 'age': 36 },
* { 'name': 'fred', 'age': 40 },
* { 'name': 'pebbles', 'age': 1 }
* ];
*
* var youngest = _.chain(characters)
* .sortBy('age')
* .map(function(chr) { return chr.name + ' is ' + chr.age; })
* .first()
* .value();
* // => 'pebbles is 1'
*/
function chain(value) {
value = new lodashWrapper(value);
value.__chain__ = true;
return value;
}
/**
* Invokes `interceptor` with the `value` as the first argument and then
* returns `value`. The purpose of this method is to "tap into" a method
* chain in order to perform operations on intermediate results within
* the chain.
*
* @static
* @memberOf _
* @category Chaining
* @param {*} value The value to provide to `interceptor`.
* @param {Function} interceptor The function to invoke.
* @returns {*} Returns `value`.
* @example
*
* _([1, 2, 3, 4])
* .tap(function(array) { array.pop(); })
* .reverse()
* .value();
* // => [3, 2, 1]
*/
function tap(value, interceptor) {
interceptor(value);
return value;
}
/**
* Enables explicit method chaining on the wrapper object.
*
* @name chain
* @memberOf _
* @category Chaining
* @returns {*} Returns the wrapper object.
* @example
*
* var characters = [
* { 'name': 'barney', 'age': 36 },
* { 'name': 'fred', 'age': 40 }
* ];
*
* // without explicit chaining
* _(characters).first();
* // => { 'name': 'barney', 'age': 36 }
*
* // with explicit chaining
* _(characters).chain()
* .first()
* .pick('age')
* .value();
* // => { 'age': 36 }
*/
function wrapperChain() {
this.__chain__ = true;
return this;
}
/**
* Produces the `toString` result of the wrapped value.
*
* @name toString
* @memberOf _
* @category Chaining
* @returns {string} Returns the string result.
* @example
*
* _([1, 2, 3]).toString();
* // => '1,2,3'
*/
function wrapperToString() {
return String(this.__wrapped__);
}
/**
* Extracts the wrapped value.
*
* @name valueOf
* @memberOf _
* @alias value
* @category Chaining
* @returns {*} Returns the wrapped value.
* @example
*
* _([1, 2, 3]).valueOf();
* // => [1, 2, 3]
*/
function wrapperValueOf() {
return this.__wrapped__;
}
/*--------------------------------------------------------------------------*/
// add functions that return wrapped values when chaining
lodash.after = after;
lodash.assign = assign;
lodash.at = at;
lodash.bind = bind;
lodash.bindAll = bindAll;
lodash.bindKey = bindKey;
lodash.chain = chain;
lodash.compact = compact;
lodash.compose = compose;
lodash.constant = constant;
lodash.countBy = countBy;
lodash.create = create;
lodash.createCallback = createCallback;
lodash.curry = curry;
lodash.debounce = debounce;
lodash.defaults = defaults;
lodash.defer = defer;
lodash.delay = delay;
lodash.difference = difference;
lodash.filter = filter;
lodash.flatten = flatten;
lodash.forEach = forEach;
lodash.forEachRight = forEachRight;
lodash.forIn = forIn;
lodash.forInRight = forInRight;
lodash.forOwn = forOwn;
lodash.forOwnRight = forOwnRight;
lodash.functions = functions;
lodash.groupBy = groupBy;
lodash.indexBy = indexBy;
lodash.initial = initial;
lodash.intersection = intersection;
lodash.invert = invert;
lodash.invoke = invoke;
lodash.keys = keys;
lodash.map = map;
lodash.mapValues = mapValues;
lodash.max = max;
lodash.memoize = memoize;
lodash.merge = merge;
lodash.min = min;
lodash.omit = omit;
lodash.once = once;
lodash.pairs = pairs;
lodash.partial = partial;
lodash.partialRight = partialRight;
lodash.pick = pick;
lodash.pluck = pluck;
lodash.property = property;
lodash.pull = pull;
lodash.range = range;
lodash.reject = reject;
lodash.remove = remove;
lodash.rest = rest;
lodash.shuffle = shuffle;
lodash.sortBy = sortBy;
lodash.tap = tap;
lodash.throttle = throttle;
lodash.times = times;
lodash.toArray = toArray;
lodash.transform = transform;
lodash.union = union;
lodash.uniq = uniq;
lodash.values = values;
lodash.where = where;
lodash.without = without;
lodash.wrap = wrap;
lodash.xor = xor;
lodash.zip = zip;
lodash.zipObject = zipObject;
// add aliases
lodash.collect = map;
lodash.drop = rest;
lodash.each = forEach;
lodash.eachRight = forEachRight;
lodash.extend = assign;
lodash.methods = functions;
lodash.object = zipObject;
lodash.select = filter;
lodash.tail = rest;
lodash.unique = uniq;
lodash.unzip = zip;
// add functions to `lodash.prototype`
mixin(lodash);
/*--------------------------------------------------------------------------*/
// add functions that return unwrapped values when chaining
lodash.clone = clone;
lodash.cloneDeep = cloneDeep;
lodash.contains = contains;
lodash.escape = escape;
lodash.every = every;
lodash.find = find;
lodash.findIndex = findIndex;
lodash.findKey = findKey;
lodash.findLast = findLast;
lodash.findLastIndex = findLastIndex;
lodash.findLastKey = findLastKey;
lodash.has = has;
lodash.identity = identity;
lodash.indexOf = indexOf;
lodash.isArguments = isArguments;
lodash.isArray = isArray;
lodash.isBoolean = isBoolean;
lodash.isDate = isDate;
lodash.isElement = isElement;
lodash.isEmpty = isEmpty;
lodash.isEqual = isEqual;
lodash.isFinite = isFinite;
lodash.isFunction = isFunction;
lodash.isNaN = isNaN;
lodash.isNull = isNull;
lodash.isNumber = isNumber;
lodash.isObject = isObject;
lodash.isPlainObject = isPlainObject;
lodash.isRegExp = isRegExp;
lodash.isString = isString;
lodash.isUndefined = isUndefined;
lodash.lastIndexOf = lastIndexOf;
lodash.mixin = mixin;
lodash.noConflict = noConflict;
lodash.noop = noop;
lodash.now = now;
lodash.parseInt = parseInt;
lodash.random = random;
lodash.reduce = reduce;
lodash.reduceRight = reduceRight;
lodash.result = result;
lodash.runInContext = runInContext;
lodash.size = size;
lodash.some = some;
lodash.sortedIndex = sortedIndex;
lodash.template = template;
lodash.unescape = unescape;
lodash.uniqueId = uniqueId;
// add aliases
lodash.all = every;
lodash.any = some;
lodash.detect = find;
lodash.findWhere = find;
lodash.foldl = reduce;
lodash.foldr = reduceRight;
lodash.include = contains;
lodash.inject = reduce;
mixin(function() {
var source = {}
forOwn(lodash, function(func, methodName) {
if (!lodash.prototype[methodName]) {
source[methodName] = func;
}
});
return source;
}(), false);
/*--------------------------------------------------------------------------*/
// add functions capable of returning wrapped and unwrapped values when chaining
lodash.first = first;
lodash.last = last;
lodash.sample = sample;
// add aliases
lodash.take = first;
lodash.head = first;
forOwn(lodash, function(func, methodName) {
var callbackable = methodName !== 'sample';
if (!lodash.prototype[methodName]) {
lodash.prototype[methodName]= function(n, guard) {
var chainAll = this.__chain__,
result = func(this.__wrapped__, n, guard);
return !chainAll && (n == null || (guard && !(callbackable && typeof n == 'function')))
? result
: new lodashWrapper(result, chainAll);
};
}
});
/*--------------------------------------------------------------------------*/
/**
* The semantic version number.
*
* @static
* @memberOf _
* @type string
*/
lodash.VERSION = '2.4.1';
// add "Chaining" functions to the wrapper
lodash.prototype.chain = wrapperChain;
lodash.prototype.toString = wrapperToString;
lodash.prototype.value = wrapperValueOf;
lodash.prototype.valueOf = wrapperValueOf;
// add `Array` functions that return unwrapped values
baseEach(['join', 'pop', 'shift'], function(methodName) {
var func = arrayRef[methodName];
lodash.prototype[methodName] = function() {
var chainAll = this.__chain__,
result = func.apply(this.__wrapped__, arguments);
return chainAll
? new lodashWrapper(result, chainAll)
: result;
};
});
// add `Array` functions that return the existing wrapped value
baseEach(['push', 'reverse', 'sort', 'unshift'], function(methodName) {
var func = arrayRef[methodName];
lodash.prototype[methodName] = function() {
func.apply(this.__wrapped__, arguments);
return this;
};
});
// add `Array` functions that return new wrapped values
baseEach(['concat', 'slice', 'splice'], function(methodName) {
var func = arrayRef[methodName];
lodash.prototype[methodName] = function() {
return new lodashWrapper(func.apply(this.__wrapped__, arguments), this.__chain__);
};
});
// avoid array-like object bugs with `Array#shift` and `Array#splice`
// in IE < 9, Firefox < 10, Narwhal, and RingoJS
if (!support.spliceObjects) {
baseEach(['pop', 'shift', 'splice'], function(methodName) {
var func = arrayRef[methodName],
isSplice = methodName == 'splice';
lodash.prototype[methodName] = function() {
var chainAll = this.__chain__,
value = this.__wrapped__,
result = func.apply(value, arguments);
if (value.length === 0) {
delete value[0];
}
return (chainAll || isSplice)
? new lodashWrapper(result, chainAll)
: result;
};
});
}
return lodash;
}
/*--------------------------------------------------------------------------*/
// expose Lo-Dash
var _ = runInContext();
// some AMD build optimizers like r.js check for condition patterns like the following:
if (true) {
// Expose Lo-Dash to the global object even when an AMD loader is present in
// case Lo-Dash is loaded with a RequireJS shim config.
// See http://requirejs.org/docs/api.html#config-shim
root._ = _;
// define as an anonymous module so, through path mapping, it can be
// referenced as the "underscore" module
!(__WEBPACK_AMD_DEFINE_RESULT__ = (function() {
return _;
}.call(exports, __webpack_require__, exports, module)), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
}
// check for `exports` after `define` in case a build optimizer adds an `exports` object
else if (freeExports && freeModule) {
// in Node.js or RingoJS
if (moduleExports) {
(freeModule.exports = _)._ = _;
}
// in Narwhal or Rhino -require
else {
freeExports._ = _;
}
}
else {
// in a browser or Rhino
root._ = _;
}
}.call(this));
/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(24)(module), (function() { return this; }())))
/***/ },
/* 7 */
/***/ function(module, exports, __webpack_require__) {
// style-loader: Adds some css to the DOM by adding a <style> tag
var dispose = __webpack_require__(16)
// The css code:
(__webpack_require__(8))
if(false) {
module.hot.accept();
module.hot.dispose(dispose);
}
/***/ },
/* 8 */
/***/ function(module, exports, __webpack_require__) {
module.exports =
"/* This Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at http://mozilla.org/MPL/2.0/.\n *\n * Owner: mark@famo.us\n * @license MPL 2.0\n * @copyright Famous Industries, Inc. 2014\n */\n\n\nhtml {\n width: 100%;\n height: 100%;\n margin: 0px;\n padding: 0px;\n overflow: hidden;\n -webkit-transform-style: preserve-3d;\n transform-style: preserve-3d;\n}\n\nbody {\n position: absolute;\n width: 100%;\n height: 100%;\n margin: 0px;\n padding: 0px;\n -webkit-transform-style: preserve-3d;\n transform-style: preserve-3d;\n -webkit-font-smoothing: antialiased;\n -webkit-tap-highlight-color: transparent;\n -webkit-perspective: 0;\n perspective: none;\n overflow: hidden;\n}\n\n.famous-container, .famous-group {\n position: absolute;\n top: 0px;\n left: 0px;\n bottom: 0px;\n right: 0px;\n overflow: visible;\n -webkit-transform-style: preserve-3d;\n transform-style: preserve-3d;\n -webkit-backface-visibility: visible;\n backface-visibility: visible;\n pointer-events: none;\n}\n\n.famous-group {\n width: 0px;\n height: 0px;\n margin: 0px;\n padding: 0px;\n -webkit-transform-style: preserve-3d;\n transform-style: preserve-3d;\n}\n\n.famous-surface {\n position: absolute;\n -webkit-transform-origin: center center;\n transform-origin: center center;\n -webkit-backface-visibility: hidden;\n backface-visibility: hidden;\n -webkit-transform-style: flat;\n transform-style: preserve-3d; /* performance */\n -webkit-box-sizing: border-box;\n -moz-box-sizing: border-box;\n -webkit-tap-highlight-color: transparent;\n pointer-events: auto;\n}\n\n.famous-container-group {\n position: relative;\n width: 100%;\n height: 100%;\n}\n";
/***/ },
/* 9 */
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_RESULT__;/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Owner: mark@famo.us
* @license MPL 2.0
* @copyright Famous Industries, Inc. 2014
*/
!(__WEBPACK_AMD_DEFINE_RESULT__ = (function(require, exports, module) {
var RenderNode = __webpack_require__(17);
var EventHandler = __webpack_require__(10);
var ElementAllocator = __webpack_require__(18);
var Transform = __webpack_require__(2);
var Transitionable = __webpack_require__(13);
var _originZeroZero = [0, 0];
function _getElementSize(element) {
return [element.clientWidth, element.clientHeight];
}
/**
* The top-level container for a Famous-renderable piece of the document.
* It is directly updated by the process-wide Engine object, and manages one
* render tree root, which can contain other renderables.
*
* @class Context
* @constructor
* @private
* @param {Node} container Element in which content will be inserted
*/
function Context(container) {
this.container = container;
this._allocator = new ElementAllocator(container);
this._node = new RenderNode();
this._eventOutput = new EventHandler();
this._size = _getElementSize(this.container);
this._perspectiveState = new Transitionable(0);
this._perspective = undefined;
this._nodeContext = {
allocator: this._allocator,
transform: Transform.identity,
opacity: 1,
origin: _originZeroZero,
size: this._size
};
this._eventOutput.on('resize', function() {
this.setSize(_getElementSize(this.container));
}.bind(this));
}
// Note: Unused
Context.prototype.getAllocator = function getAllocator() {
return this._allocator;
};
/**
* Add renderables to this Context's render tree.
*
* @method add
*
* @param {Object} obj renderable object
* @return {RenderNode} RenderNode wrapping this object, if not already a RenderNode
*/
Context.prototype.add = function add(obj) {
return this._node.add(obj);
};
/**
* Move this Context to another containing document element.
*
* @method migrate
*
* @param {Node} container Element to which content will be migrated
*/
Context.prototype.migrate = function migrate(container) {
if (container === this.container) return;
this.container = container;
this._allocator.migrate(container);
};
/**
* Gets viewport size for Context.
*
* @method getSize
*
* @return {Array.Number} viewport size as [width, height]
*/
Context.prototype.getSize = function getSize() {
return this._size;
};
/**
* Sets viewport size for Context.
*
* @method setSize
*
* @param {Array.Number} size [width, height]. If unspecified, use size of root document element.
*/
Context.prototype.setSize = function setSize(size) {
if (!size) size = _getElementSize(this.container);
this._size[0] = size[0];
this._size[1] = size[1];
};
/**
* Commit this Context's content changes to the document.
*
* @private
* @method update
* @param {Object} contextParameters engine commit specification
*/
Context.prototype.update = function update(contextParameters) {
if (contextParameters) {
if (contextParameters.transform) this._nodeContext.transform = contextParameters.transform;
if (contextParameters.opacity) this._nodeContext.opacity = contextParameters.opacity;
if (contextParameters.origin) this._nodeContext.origin = contextParameters.origin;
if (contextParameters.size) this._nodeContext.size = contextParameters.size;
}
var perspective = this._perspectiveState.get();
if (perspective !== this._perspective) {
this.container.style.perspective = perspective ? perspective.toFixed() + 'px' : '';
this.container.style.webkitPerspective = perspective ? perspective.toFixed() : '';
this._perspective = perspective;
}
this._node.commit(this._nodeContext);
};
/**
* Get current perspective of this context in pixels.
*
* @method getPerspective
* @return {Number} depth perspective in pixels
*/
Context.prototype.getPerspective = function getPerspective() {
return this._perspectiveState.get();
};
/**
* Set current perspective of this context in pixels.
*
* @method getPerspective
* @param {Number} perspective in pixels
* @param {Object} [transition] Transitionable object for applying the change
* @param {function(Object)} callback function called on completion of transition
*/
Context.prototype.setPerspective = function setPerspective(perspective, transition, callback) {
return this._perspectiveState.set(perspective, transition, callback);
};
/**
* Trigger an event, sending to all downstream handlers
* listening for provided 'type' key.
*
* @method emit
*
* @param {string} type event type key (for example, 'click')
* @param {Object} event event data
* @return {EventHandler} this
*/
Context.prototype.emit = function emit(type, event) {
return this._eventOutput.emit(type, event);
};
/**
* Bind a callback function to an event type handled by this object.
*
* @method "on"
*
* @param {string} type event type key (for example, 'click')
* @param {function(string, Object)} handler callback
* @return {EventHandler} this
*/
Context.prototype.on = function on(type, handler) {
return this._eventOutput.on(type, handler);
};
/**
* Unbind an event by type and handler.
* This undoes the work of "on".
*
* @method removeListener
*
* @param {string} type event type key (for example, 'click')
* @param {function} handler function object to remove
* @return {EventHandler} internal event handler object (for chaining)
*/
Context.prototype.removeListener = function removeListener(type, handler) {
return this._eventOutput.removeListener(type, handler);
};
/**
* Add event handler object to set of downstream handlers.
*
* @method pipe
*
* @param {EventHandler} target event handler target object
* @return {EventHandler} passed event handler
*/
Context.prototype.pipe = function pipe(target) {
return this._eventOutput.pipe(target);
};
/**
* Remove handler object from set of downstream handlers.
* Undoes work of "pipe".
*
* @method unpipe
*
* @param {EventHandler} target target handler object
* @return {EventHandler} provided target
*/
Context.prototype.unpipe = function unpipe(target) {
return this._eventOutput.unpipe(target);
};
module.exports = Context;
}.call(exports, __webpack_require__, exports, module)), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
/***/ },
/* 10 */
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_RESULT__;/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Owner: mark@famo.us
* @license MPL 2.0
* @copyright Famous Industries, Inc. 2014
*/
!(__WEBPACK_AMD_DEFINE_RESULT__ = (function(require, exports, module) {
var EventEmitter = __webpack_require__(19);
/**
* EventHandler forwards received events to a set of provided callback functions.
* It allows events to be captured, processed, and optionally piped through to other event handlers.
*
* @class EventHandler
* @extends EventEmitter
* @constructor
*/
function EventHandler() {
EventEmitter.apply(this, arguments);
this.downstream = []; // downstream event handlers
this.downstreamFn = []; // downstream functions
this.upstream = []; // upstream event handlers
this.upstreamListeners = {}; // upstream listeners
}
EventHandler.prototype = Object.create(EventEmitter.prototype);
EventHandler.prototype.constructor = EventHandler;
/**
* Assign an event handler to receive an object's input events.
*
* @method setInputHandler
* @static
*
* @param {Object} object object to mix trigger, subscribe, and unsubscribe functions into
* @param {EventHandler} handler assigned event handler
*/
EventHandler.setInputHandler = function setInputHandler(object, handler) {
object.trigger = handler.trigger.bind(handler);
if (handler.subscribe && handler.unsubscribe) {
object.subscribe = handler.subscribe.bind(handler);
object.unsubscribe = handler.unsubscribe.bind(handler);
}
};
/**
* Assign an event handler to receive an object's output events.
*
* @method setOutputHandler
* @static
*
* @param {Object} object object to mix pipe, unpipe, on, addListener, and removeListener functions into
* @param {EventHandler} handler assigned event handler
*/
EventHandler.setOutputHandler = function setOutputHandler(object, handler) {
if (handler instanceof EventHandler) handler.bindThis(object);
object.pipe = handler.pipe.bind(handler);
object.unpipe = handler.unpipe.bind(handler);
object.on = handler.on.bind(handler);
object.addListener = handler.on;
object.removeListener = handler.removeListener.bind(handler);
};
/**
* Trigger an event, sending to all downstream handlers
* listening for provided 'type' key.
*
* @method emit
*
* @param {string} type event type key (for example, 'click')
* @param {Object} event event data
* @return {EventHandler} this
*/
EventHandler.prototype.emit = function emit(type, event) {
EventEmitter.prototype.emit.apply(this, arguments);
var i = 0;
for (i = 0; i < this.downstream.length; i++) {
this.downstream[i].trigger(type, event);
}
for (i = 0; i < this.downstreamFn.length; i++) {
this.downstreamFn[i](type, event);
}
return this;
};
/**
* Alias for emit
* @method addListener
*/
EventHandler.prototype.trigger = EventHandler.prototype.emit;
/**
* Add event handler object to set of downstream handlers.
*
* @method pipe
*
* @param {EventHandler} target event handler target object
* @return {EventHandler} passed event handler
*/
EventHandler.prototype.pipe = function pipe(target) {
if (target.subscribe instanceof Function) return target.subscribe(this);
var downstreamCtx = (target instanceof Function) ? this.downstreamFn : this.downstream;
var index = downstreamCtx.indexOf(target);
if (index < 0) downstreamCtx.push(target);
if (target instanceof Function) target('pipe', null);
else if (target.trigger) target.trigger('pipe', null);
return target;
};
/**
* Remove handler object from set of downstream handlers.
* Undoes work of "pipe".
*
* @method unpipe
*
* @param {EventHandler} target target handler object
* @return {EventHandler} provided target
*/
EventHandler.prototype.unpipe = function unpipe(target) {
if (target.unsubscribe instanceof Function) return target.unsubscribe(this);
var downstreamCtx = (target instanceof Function) ? this.downstreamFn : this.downstream;
var index = downstreamCtx.indexOf(target);
if (index >= 0) {
downstreamCtx.splice(index, 1);
if (target instanceof Function) target('unpipe', null);
else if (target.trigger) target.trigger('unpipe', null);
return target;
}
else return false;
};
/**
* Bind a callback function to an event type handled by this object.
*
* @method "on"
*
* @param {string} type event type key (for example, 'click')
* @param {function(string, Object)} handler callback
* @return {EventHandler} this
*/
EventHandler.prototype.on = function on(type, handler) {
EventEmitter.prototype.on.apply(this, arguments);
if (!(type in this.upstreamListeners)) {
var upstreamListener = this.trigger.bind(this, type);
this.upstreamListeners[type] = upstreamListener;
for (var i = 0; i < this.upstream.length; i++) {
this.upstream[i].on(type, upstreamListener);
}
}
return this;
};
/**
* Alias for "on"
* @method addListener
*/
EventHandler.prototype.addListener = EventHandler.prototype.on;
/**
* Listen for events from an upstream event handler.
*
* @method subscribe
*
* @param {EventEmitter} source source emitter object
* @return {EventHandler} this
*/
EventHandler.prototype.subscribe = function subscribe(source) {
var index = this.upstream.indexOf(source);
if (index < 0) {
this.upstream.push(source);
for (var type in this.upstreamListeners) {
source.on(type, this.upstreamListeners[type]);
}
}
return this;
};
/**
* Stop listening to events from an upstream event handler.
*
* @method unsubscribe
*
* @param {EventEmitter} source source emitter object
* @return {EventHandler} this
*/
EventHandler.prototype.unsubscribe = function unsubscribe(source) {
var index = this.upstream.indexOf(source);
if (index >= 0) {
this.upstream.splice(index, 1);
for (var type in this.upstreamListeners) {
source.removeListener(type, this.upstreamListeners[type]);
}
}
return this;
};
module.exports = EventHandler;
}.call(exports, __webpack_require__, exports, module)), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
/***/ },
/* 11 */
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_RESULT__;/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Owner: mark@famo.us
* @license MPL 2.0
* @copyright Famous Industries, Inc. 2014
*/
!(__WEBPACK_AMD_DEFINE_RESULT__ = (function(require, exports, module) {
var EventHandler = __webpack_require__(10);
/**
* A collection of methods for setting options which can be extended
* onto other classes.
*
*
* **** WARNING ****
* You can only pass through objects that will compile into valid JSON.
*
* Valid options:
* Strings,
* Arrays,
* Objects,
* Numbers,
* Nested Objects,
* Nested Arrays.
*
* This excludes:
* Document Fragments,
* Functions
* @class OptionsManager
* @constructor
* @param {Object} value options dictionary
*/
function OptionsManager(value) {
this._value = value;
this.eventOutput = null;
}
/**
* Create options manager from source dictionary with arguments overriden by patch dictionary.
*
* @static
* @method OptionsManager.patch
*
* @param {Object} source source arguments
* @param {...Object} data argument additions and overwrites
* @return {Object} source object
*/
OptionsManager.patch = function patchObject(source, data) {
var manager = new OptionsManager(source);
for (var i = 1; i < arguments.length; i++) manager.patch(arguments[i]);
return source;
};
function _createEventOutput() {
this.eventOutput = new EventHandler();
this.eventOutput.bindThis(this);
EventHandler.setOutputHandler(this, this.eventOutput);
}
/**
* Create OptionsManager from source with arguments overriden by patches.
* Triggers 'change' event on this object's event handler if the state of
* the OptionsManager changes as a result.
*
* @method patch
*
* @param {...Object} arguments list of patch objects
* @return {OptionsManager} this
*/
OptionsManager.prototype.patch = function patch() {
var myState = this._value;
for (var i = 0; i < arguments.length; i++) {
var data = arguments[i];
for (var k in data) {
if ((k in myState) && (data[k] && data[k].constructor === Object) && (myState[k] && myState[k].constructor === Object)) {
if (!myState.hasOwnProperty(k)) myState[k] = Object.create(myState[k]);
this.key(k).patch(data[k]);
if (this.eventOutput) this.eventOutput.emit('change', {id: k, value: this.key(k).value()});
}
else this.set(k, data[k]);
}
}
return this;
};
/**
* Alias for patch
*
* @method setOptions
*
*/
OptionsManager.prototype.setOptions = OptionsManager.prototype.patch;
/**
* Return OptionsManager based on sub-object retrieved by key
*
* @method key
*
* @param {string} identifier key
* @return {OptionsManager} new options manager with the value
*/
OptionsManager.prototype.key = function key(identifier) {
var result = new OptionsManager(this._value[identifier]);
if (!(result._value instanceof Object) || result._value instanceof Array) result._value = {};
return result;
};
/**
* Look up value by key
* @method get
*
* @param {string} key key
* @return {Object} associated object
*/
OptionsManager.prototype.get = function get(key) {
return this._value[key];
};
/**
* Alias for get
* @method getOptions
*/
OptionsManager.prototype.getOptions = OptionsManager.prototype.get;
/**
* Set key to value. Outputs 'change' event if a value is overwritten.
*
* @method set
*
* @param {string} key key string
* @param {Object} value value object
* @return {OptionsManager} new options manager based on the value object
*/
OptionsManager.prototype.set = function set(key, value) {
var originalValue = this.get(key);
this._value[key] = value;
if (this.eventOutput && value !== originalValue) this.eventOutput.emit('change', {id: key, value: value});
return this;
};
/**
* Return entire object contents of this OptionsManager.
*
* @method value
*
* @return {Object} current state of options
*/
OptionsManager.prototype.value = function value() {
return this._value;
};
/**
* Bind a callback function to an event type handled by this object.
*
* @method "on"
*
* @param {string} type event type key (for example, 'change')
* @param {function(string, Object)} handler callback
* @return {EventHandler} this
*/
OptionsManager.prototype.on = function on() {
_createEventOutput.call(this);
return this.on.apply(this, arguments);
};
/**
* Unbind an event by type and handler.
* This undoes the work of "on".
*
* @method removeListener
*
* @param {string} type event type key (for example, 'change')
* @param {function} handler function object to remove
* @return {EventHandler} internal event handler object (for chaining)
*/
OptionsManager.prototype.removeListener = function removeListener() {
_createEventOutput.call(this);
return this.removeListener.apply(this, arguments);
};
/**
* Add event handler object to set of downstream handlers.
*
* @method pipe
*
* @param {EventHandler} target event handler target object
* @return {EventHandler} passed event handler
*/
OptionsManager.prototype.pipe = function pipe() {
_createEventOutput.call(this);
return this.pipe.apply(this, arguments);
};
/**
* Remove handler object from set of downstream handlers.
* Undoes work of "pipe"
*
* @method unpipe
*
* @param {EventHandler} target target handler object
* @return {EventHandler} provided target
*/
OptionsManager.prototype.unpipe = function unpipe() {
_createEventOutput.call(this);
return this.unpipe.apply(this, arguments);
};
module.exports = OptionsManager;
}.call(exports, __webpack_require__, exports, module)), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
/***/ },
/* 12 */
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_RESULT__;/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Owner: mark@famo.us
* @license MPL 2.0
* @copyright Famous Industries, Inc. 2014
*/
!(__WEBPACK_AMD_DEFINE_RESULT__ = (function(require, exports, module) {
var Transform = __webpack_require__(2);
/* TODO: remove these dependencies when deprecation complete */
var Transitionable = __webpack_require__(13);
var TransitionableTransform = __webpack_require__(14);
/**
*
* A collection of visual changes to be
* applied to another renderable component. This collection includes a
* transform matrix, an opacity constant, a size, an origin specifier.
* Modifier objects can be added to any RenderNode or object
* capable of displaying renderables. The Modifier's children and descendants
* are transformed by the amounts specified in the Modifier's properties.
*
* @class Modifier
* @constructor
* @param {Object} [options] overrides of default options
* @param {Transform} [options.transform] affine transformation matrix
* @param {Number} [options.opacity]
* @param {Array.Number} [options.origin] origin adjustment
* @param {Array.Number} [options.size] size to apply to descendants
*/
function Modifier(options) {
this._transformGetter = null;
this._opacityGetter = null;
this._originGetter = null;
this._sizeGetter = null;
/* TODO: remove this when deprecation complete */
this._legacyStates = {};
this._output = {
transform: Transform.identity,
opacity: 1,
origin: null,
size: null,
target: null
};
if (options) {
if (options.transform) this.transformFrom(options.transform);
if (options.opacity !== undefined) this.opacityFrom(options.opacity);
if (options.origin) this.originFrom(options.origin);
if (options.size) this.sizeFrom(options.size);
}
}
/**
* Function, object, or static transform matrix which provides the transform.
* This is evaluated on every tick of the engine.
*
* @method transformFrom
*
* @param {Object} transform transform provider object
* @return {Modifier} this
*/
Modifier.prototype.transformFrom = function transformFrom(transform) {
if (transform instanceof Function) this._transformGetter = transform;
else if (transform instanceof Object && transform.get) this._transformGetter = transform.get.bind(transform);
else {
this._transformGetter = null;
this._output.transform = transform;
}
return this;
};
/**
* Set function, object, or number to provide opacity, in range [0,1].
*
* @method opacityFrom
*
* @param {Object} opacity provider object
* @return {Modifier} this
*/
Modifier.prototype.opacityFrom = function opacityFrom(opacity) {
if (opacity instanceof Function) this._opacityGetter = opacity;
else if (opacity instanceof Object && opacity.get) this._opacityGetter = opacity.get.bind(opacity);
else {
this._opacityGetter = null;
this._output.opacity = opacity;
}
return this;
};
/**
* Set function, object, or numerical array to provide origin, as [x,y],
* where x and y are in the range [0,1].
*
* @method originFrom
*
* @param {Object} origin provider object
* @return {Modifier} this
*/
Modifier.prototype.originFrom = function originFrom(origin) {
if (origin instanceof Function) this._originGetter = origin;
else if (origin instanceof Object && origin.get) this._originGetter = origin.get.bind(origin);
else {
this._originGetter = null;
this._output.origin = origin;
}
return this;
};
/**
* Set function, object, or numerical array to provide size, as [width, height].
*
* @method sizeFrom
*
* @param {Object} size provider object
* @return {Modifier} this
*/
Modifier.prototype.sizeFrom = function sizeFrom(size) {
if (size instanceof Function) this._sizeGetter = size;
else if (size instanceof Object && size.get) this._sizeGetter = size.get.bind(size);
else {
this._sizeGetter = null;
this._output.size = size;
}
return this;
};
/**
* Deprecated: Prefer transformFrom with static Transform, or use a TransitionableTransform.
* @deprecated
* @method setTransform
*
* @param {Transform} transform Transform to transition to
* @param {Transitionable} transition Valid transitionable object
* @param {Function} callback callback to call after transition completes
* @return {Modifier} this
*/
Modifier.prototype.setTransform = function setTransform(transform, transition, callback) {
if (transition || this._legacyStates.transform) {
if (!this._legacyStates.transform) {
this._legacyStates.transform = new TransitionableTransform(this._output.transform);
}
if (!this._transformGetter) this.transformFrom(this._legacyStates.transform);
this._legacyStates.transform.set(transform, transition, callback);
return this;
}
else return this.transformFrom(transform);
};
/**
* Deprecated: Prefer opacityFrom with static opacity array, or use a Transitionable with that opacity.
* @deprecated
* @method setOpacity
*
* @param {Number} opacity Opacity value to transition to.
* @param {Transitionable} transition Valid transitionable object
* @param {Function} callback callback to call after transition completes
* @return {Modifier} this
*/
Modifier.prototype.setOpacity = function setOpacity(opacity, transition, callback) {
if (transition || this._legacyStates.opacity) {
if (!this._legacyStates.opacity) {
this._legacyStates.opacity = new Transitionable(this._output.opacity);
}
if (!this._opacityGetter) this.opacityFrom(this._legacyStates.opacity);
return this._legacyStates.opacity.set(opacity, transition, callback);
}
else return this.opacityFrom(opacity);
};
/**
* Deprecated: Prefer originFrom with static origin array, or use a Transitionable with that origin.
* @deprecated
* @method setOrigin
*
* @param {Array.Number} origin two element array with values between 0 and 1.
* @param {Transitionable} transition Valid transitionable object
* @param {Function} callback callback to call after transition completes
* @return {Modifier} this
*/
Modifier.prototype.setOrigin = function setOrigin(origin, transition, callback) {
/* TODO: remove this if statement when deprecation complete */
if (transition || this._legacyStates.origin) {
if (!this._legacyStates.origin) {
this._legacyStates.origin = new Transitionable(this._output.origin || [0, 0]);
}
if (!this._originGetter) this.originFrom(this._legacyStates.origin);
this._legacyStates.origin.set(origin, transition, callback);
return this;
}
else return this.originFrom(origin);
};
/**
* Deprecated: Prefer sizeFrom with static origin array, or use a Transitionable with that size.
* @deprecated
* @method setSize
* @param {Array.Number} size two element array of [width, height]
* @param {Transitionable} transition Valid transitionable object
* @param {Function} callback callback to call after transition completes
* @return {Modifier} this
*/
Modifier.prototype.setSize = function setSize(size, transition, callback) {
if (size && (transition || this._legacyStates.size)) {
if (!this._legacyStates.size) {
this._legacyStates.size = new Transitionable(this._output.size || [0, 0]);
}
if (!this._sizeGetter) this.sizeFrom(this._legacyStates.size);
this._legacyStates.size.set(size, transition, callback);
return this;
}
else return this.sizeFrom(size);
};
/**
* Deprecated: Prefer to stop transform in your provider object.
* @deprecated
* @method halt
*/
Modifier.prototype.halt = function halt() {
if (this._legacyStates.transform) this._legacyStates.transform.halt();
if (this._legacyStates.opacity) this._legacyStates.opacity.halt();
if (this._legacyStates.origin) this._legacyStates.origin.halt();
if (this._legacyStates.size) this._legacyStates.size.halt();
this._transformGetter = null;
this._opacityGetter = null;
this._originGetter = null;
this._sizeGetter = null;
};
/**
* Deprecated: Prefer to use your provided transform or output of your transform provider.
* @deprecated
* @method getTransform
* @return {Object} transform provider object
*/
Modifier.prototype.getTransform = function getTransform() {
return this._transformGetter();
};
/**
* Deprecated: Prefer to determine the end state of your transform from your transform provider
* @deprecated
* @method getFinalTransform
* @return {Transform} transform matrix
*/
Modifier.prototype.getFinalTransform = function getFinalTransform() {
return this._legacyStates.transform ? this._legacyStates.transform.getFinal() : this._output.transform;
};
/**
* Deprecated: Prefer to use your provided opacity or output of your opacity provider.
* @deprecated
* @method getOpacity
* @return {Object} opacity provider object
*/
Modifier.prototype.getOpacity = function getOpacity() {
return this._opacityGetter();
};
/**
* Deprecated: Prefer to use your provided origin or output of your origin provider.
* @deprecated
* @method getOrigin
* @return {Object} origin provider object
*/
Modifier.prototype.getOrigin = function getOrigin() {
return this._originGetter();
};
/**
* Deprecated: Prefer to use your provided size or output of your size provider.
* @deprecated
* @method getSize
* @return {Object} size provider object
*/
Modifier.prototype.getSize = function getSize() {
return this._sizeGetter ? this._sizeGetter() : this._output.size;
};
// call providers on tick to receive render spec elements to apply
function _update() {
if (this._transformGetter) this._output.transform = this._transformGetter();
if (this._opacityGetter) this._output.opacity = this._opacityGetter();
if (this._originGetter) this._output.origin = this._originGetter();
if (this._sizeGetter) this._output.size = this._sizeGetter();
}
/**
* Return render spec for this Modifier, applying to the provided
* target component. This is similar to render() for Surfaces.
*
* @private
* @method modify
*
* @param {Object} target (already rendered) render spec to
* which to apply the transform.
* @return {Object} render spec for this Modifier, including the
* provided target
*/
Modifier.prototype.modify = function modify(target) {
_update.call(this);
this._output.target = target;
return this._output;
};
module.exports = Modifier;
}.call(exports, __webpack_require__, exports, module)), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
/***/ },
/* 13 */
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_RESULT__;/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Owner: david@famo.us
* @license MPL 2.0
* @copyright Famous Industries, Inc. 2014
*/
!(__WEBPACK_AMD_DEFINE_RESULT__ = (function(require, exports, module) {
var MultipleTransition = __webpack_require__(20);
var TweenTransition = __webpack_require__(21);
/**
* A state maintainer for a smooth transition between
* numerically-specified states. Example numeric states include floats or
* Transform objects.
*
* An initial state is set with the constructor or set(startState). A
* corresponding end state and transition are set with set(endState,
* transition). Subsequent calls to set(endState, transition) begin at
* the last state. Calls to get(timestamp) provide the interpolated state
* along the way.
*
* Note that there is no event loop here - calls to get() are the only way
* to find state projected to the current (or provided) time and are
* the only way to trigger callbacks. Usually this kind of object would
* be part of the render() path of a visible component.
*
* @class Transitionable
* @constructor
* @param {number|Array.Number|Object.<number|string, number>} start
* beginning state
*/
function Transitionable(start) {
this.currentAction = null;
this.actionQueue = [];
this.callbackQueue = [];
this.state = 0;
this.velocity = undefined;
this._callback = undefined;
this._engineInstance = null;
this._currentMethod = null;
this.set(start);
}
var transitionMethods = {};
Transitionable.registerMethod = function registerMethod(name, engineClass) {
if (!(name in transitionMethods)) {
transitionMethods[name] = engineClass;
return true;
}
else return false;
};
Transitionable.unregisterMethod = function unregisterMethod(name) {
if (name in transitionMethods) {
delete transitionMethods[name];
return true;
}
else return false;
};
function _loadNext() {
if (this._callback) {
var callback = this._callback;
this._callback = undefined;
callback();
}
if (this.actionQueue.length <= 0) {
this.set(this.get()); // no update required
return;
}
this.currentAction = this.actionQueue.shift();
this._callback = this.callbackQueue.shift();
var method = null;
var endValue = this.currentAction[0];
var transition = this.currentAction[1];
if (transition instanceof Object && transition.method) {
method = transition.method;
if (typeof method === 'string') method = transitionMethods[method];
}
else {
method = TweenTransition;
}
if (this._currentMethod !== method) {
if (!(endValue instanceof Object) || method.SUPPORTS_MULTIPLE === true || endValue.length <= method.SUPPORTS_MULTIPLE) {
this._engineInstance = new method();
}
else {
this._engineInstance = new MultipleTransition(method);
}
this._currentMethod = method;
}
this._engineInstance.reset(this.state, this.velocity);
if (this.velocity !== undefined) transition.velocity = this.velocity;
this._engineInstance.set(endValue, transition, _loadNext.bind(this));
}
/**
* Add transition to end state to the queue of pending transitions. Special
* Use: calling without a transition resets the object to that state with
* no pending actions
*
* @method set
*
* @param {number|FamousMatrix|Array.Number|Object.<number, number>} endState
* end state to which we interpolate
* @param {transition=} transition object of type {duration: number, curve:
* f[0,1] -> [0,1] or name}. If transition is omitted, change will be
* instantaneous.
* @param {function()=} callback Zero-argument function to call on observed
* completion (t=1)
*/
Transitionable.prototype.set = function set(endState, transition, callback) {
if (!transition) {
this.reset(endState);
if (callback) callback();
return this;
}
var action = [endState, transition];
this.actionQueue.push(action);
this.callbackQueue.push(callback);
if (!this.currentAction) _loadNext.call(this);
return this;
};
/**
* Cancel all transitions and reset to a stable state
*
* @method reset
*
* @param {number|Array.Number|Object.<number, number>} startState
* stable state to set to
*/
Transitionable.prototype.reset = function reset(startState, startVelocity) {
this._currentMethod = null;
this._engineInstance = null;
this.state = startState;
this.velocity = startVelocity;
this.currentAction = null;
this.actionQueue = [];
this.callbackQueue = [];
};
/**
* Add delay action to the pending action queue queue.
*
* @method delay
*
* @param {number} duration delay time (ms)
* @param {function} callback Zero-argument function to call on observed
* completion (t=1)
*/
Transitionable.prototype.delay = function delay(duration, callback) {
this.set(this._engineInstance.get(), {duration: duration,
curve: function() {
return 0;
}},
callback);
};
/**
* Get interpolated state of current action at provided time. If the last
* action has completed, invoke its callback.
*
* @method get
*
* @param {number=} timestamp Evaluate the curve at a normalized version of this
* time. If omitted, use current time. (Unix epoch time)
* @return {number|Object.<number|string, number>} beginning state
* interpolated to this point in time.
*/
Transitionable.prototype.get = function get(timestamp) {
if (this._engineInstance) {
if (this._engineInstance.getVelocity)
this.velocity = this._engineInstance.getVelocity();
this.state = this._engineInstance.get(timestamp);
}
return this.state;
};
/**
* Is there at least one action pending completion?
*
* @method isActive
*
* @return {boolean}
*/
Transitionable.prototype.isActive = function isActive() {
return !!this.currentAction;
};
/**
* Halt transition at current state and erase all pending actions.
*
* @method halt
*/
Transitionable.prototype.halt = function halt() {
this.set(this.get());
};
module.exports = Transitionable;
}.call(exports, __webpack_require__, exports, module)), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
/***/ },
/* 14 */
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_RESULT__;/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Owner: david@famo.us
* @license MPL 2.0
* @copyright Famous Industries, Inc. 2014
*/
!(__WEBPACK_AMD_DEFINE_RESULT__ = (function(require, exports, module) {
var Transitionable = __webpack_require__(13);
var Transform = __webpack_require__(2);
var Utility = __webpack_require__(23);
/**
* A class for transitioning the state of a Transform by transitioning
* its translate, scale, skew and rotate components independently.
*
* @class TransitionableTransform
* @constructor
*
* @param [transform=Transform.identity] {Transform} The initial transform state
*/
function TransitionableTransform(transform) {
this._final = Transform.identity.slice();
this.translate = new Transitionable([0, 0, 0]);
this.rotate = new Transitionable([0, 0, 0]);
this.skew = new Transitionable([0, 0, 0]);
this.scale = new Transitionable([1, 1, 1]);
if (transform) this.set(transform);
}
function _build() {
return Transform.build({
translate: this.translate.get(),
rotate: this.rotate.get(),
skew: this.skew.get(),
scale: this.scale.get()
});
}
/**
* An optimized way of setting only the translation component of a Transform
*
* @method setTranslate
* @chainable
*
* @param translate {Array} New translation state
* @param [transition] {Object} Transition definition
* @param [callback] {Function} Callback
* @return {TransitionableTransform}
*/
TransitionableTransform.prototype.setTranslate = function setTranslate(translate, transition, callback) {
this.translate.set(translate, transition, callback);
this._final = this._final.slice();
this._final[12] = translate[0];
this._final[13] = translate[1];
if (translate[2] !== undefined) this._final[14] = translate[2];
return this;
};
/**
* An optimized way of setting only the scale component of a Transform
*
* @method setTranslate
* @chainable
*
* @param scale {Array} New scale state
* @param [transition] {Object} Transition definition
* @param [callback] {Function} Callback
* @return {TransitionableTransform}
*/
TransitionableTransform.prototype.setScale = function setScale(scale, transition, callback) {
this.scale.set(scale, transition, callback);
this._final = this._final.slice();
this._final[0] = scale[0];
this._final[5] = scale[1];
if (scale[2] !== undefined) this._final[10] = scale[2];
return this;
};
/**
* An optimized way of setting only the rotational component of a Transform
*
* @method setTranslate
* @chainable
*
* @param eulerAngles {Array} Euler angles for new rotation state
* @param [transition] {Object} Transition definition
* @param [callback] {Function} Callback
* @return {TransitionableTransform}
*/
TransitionableTransform.prototype.setRotate = function setRotate(eulerAngles, transition, callback) {
this.rotate.set(eulerAngles, transition, callback);
this._final = _build.call(this);
this._final = Transform.build({
translate: this.translate.get(),
rotate: eulerAngles,
scale: this.scale.get(),
skew: this.skew.get()
});
return this;
};
/**
* An optimized way of setting only the skew component of a Transform
*
* @method setTranslate
* @chainable
*
* @param skewAngles {Array} New skew state
* @param [transition] {Object} Transition definition
* @param [callback] {Function} Callback
* @return {TransitionableTransform}
*/
TransitionableTransform.prototype.setSkew = function setSkew(skewAngles, transition, callback) {
this.skew.set(skewAngles, transition, callback);
this._final = Transform.build({
translate: this.translate.get(),
rotate: this.rotate.get(),
scale: this.scale.get(),
skew: skewAngles
});
return this;
};
/**
* Setter for a TransitionableTransform with optional parameters to transition
* between Transforms
*
* @method setTranslate
* @chainable
*
* @param transform {Array} New transform state
* @param [transition] {Object} Transition definition
* @param [callback] {Function} Callback
* @return {TransitionableTransform}
*/
TransitionableTransform.prototype.set = function set(transform, transition, callback) {
this._final = transform;
var components = Transform.interpret(transform);
var _callback = callback ? Utility.after(4, callback) : null;
this.translate.set(components.translate, transition, _callback);
this.rotate.set(components.rotate, transition, _callback);
this.skew.set(components.skew, transition, _callback);
this.scale.set(components.scale, transition, _callback);
return this;
};
/**
* Sets the default transition to use for transitioning betwen Transform states
*
* @method setDefaultTransition
*
* @param transition {Object} Transition definition
*/
TransitionableTransform.prototype.setDefaultTransition = function setDefaultTransition(transition) {
this.translate.setDefault(transition);
this.rotate.setDefault(transition);
this.skew.setDefault(transition);
this.scale.setDefault(transition);
};
/**
* Getter. Returns the current state of the Transform
*
* @method get
*
* @return {Transform}
*/
TransitionableTransform.prototype.get = function get() {
if (this.isActive()) {
return _build.call(this);
}
else return this._final;
};
/**
* Get the destination state of the Transform
*
* @method getFinal
*
* @return Transform {Transform}
*/
TransitionableTransform.prototype.getFinal = function getFinal() {
return this._final;
};
/**
* Determine if the TransitionalTransform is currently transitioning
*
* @method isActive
*
* @return {Boolean}
*/
TransitionableTransform.prototype.isActive = function isActive() {
return this.translate.isActive() || this.rotate.isActive() || this.scale.isActive() || this.skew.isActive();
};
/**
* Halts the transition
*
* @method halt
*/
TransitionableTransform.prototype.halt = function halt() {
this._final = this.get();
this.translate.halt();
this.rotate.halt();
this.skew.halt();
this.scale.halt();
};
module.exports = TransitionableTransform;
}.call(exports, __webpack_require__, exports, module)), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
/***/ },
/* 15 */
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_RESULT__;/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Owner: mark@famo.us
* @license MPL 2.0
* @copyright Famous Industries, Inc. 2014
*/
!(__WEBPACK_AMD_DEFINE_RESULT__ = (function(require, exports, module) {
var Entity = __webpack_require__(22);
var EventHandler = __webpack_require__(10);
var Transform = __webpack_require__(2);
var usePrefix = document.body.style.webkitTransform !== undefined;
/**
* A base class for viewable content and event
* targets inside a Famo.us application, containing a renderable document
* fragment. Like an HTML div, it can accept internal markup,
* properties, classes, and handle events.
*
* @class Surface
* @constructor
*
* @param {Object} [options] default option overrides
* @param {Array.Number} [options.size] [width, height] in pixels
* @param {Array.string} [options.classes] CSS classes to set on inner content
* @param {Array} [options.properties] string dictionary of HTML attributes to set on target div
* @param {string} [options.content] inner (HTML) content of surface
*/
function Surface(options) {
this.options = {};
this.properties = {};
this.content = '';
this.classList = [];
this.size = null;
this._classesDirty = true;
this._stylesDirty = true;
this._sizeDirty = true;
this._contentDirty = true;
this._dirtyClasses = [];
this._matrix = null;
this._opacity = 1;
this._origin = null;
this._size = null;
/** @ignore */
this.eventForwarder = function eventForwarder(event) {
this.emit(event.type, event);
}.bind(this);
this.eventHandler = new EventHandler();
this.eventHandler.bindThis(this);
this.id = Entity.register(this);
if (options) this.setOptions(options);
this._currTarget = null;
}
Surface.prototype.elementType = 'div';
Surface.prototype.elementClass = 'famous-surface';
/**
* Bind a callback function to an event type handled by this object.
*
* @method "on"
*
* @param {string} type event type key (for example, 'click')
* @param {function(string, Object)} fn handler callback
* @return {EventHandler} this
*/
Surface.prototype.on = function on(type, fn) {
if (this._currTarget) this._currTarget.addEventListener(type, this.eventForwarder);
this.eventHandler.on(type, fn);
};
/**
* Unbind an event by type and handler.
* This undoes the work of "on"
*
* @method removeListener
* @param {string} type event type key (for example, 'click')
* @param {function(string, Object)} fn handler
*/
Surface.prototype.removeListener = function removeListener(type, fn) {
this.eventHandler.removeListener(type, fn);
};
/**
* Trigger an event, sending to all downstream handlers
* listening for provided 'type' key.
*
* @method emit
*
* @param {string} type event type key (for example, 'click')
* @param {Object} event event data
* @return {EventHandler} this
*/
Surface.prototype.emit = function emit(type, event) {
if (event && !event.origin) event.origin = this;
var handled = this.eventHandler.emit(type, event);
if (handled && event.stopPropagation) event.stopPropagation();
return handled;
};
/**
* Add event handler object to set of downstream handlers.
*
* @method pipe
*
* @param {EventHandler} target event handler target object
* @return {EventHandler} passed event handler
*/
Surface.prototype.pipe = function pipe(target) {
return this.eventHandler.pipe(target);
};
/**
* Remove handler object from set of downstream handlers.
* Undoes work of "pipe"
*
* @method unpipe
*
* @param {EventHandler} target target handler object
* @return {EventHandler} provided target
*/
Surface.prototype.unpipe = function unpipe(target) {
return this.eventHandler.unpipe(target);
};
/**
* Return spec for this surface. Note that for a base surface, this is
* simply an id.
*
* @method render
* @private
* @return {Object} render spec for this surface (spec id)
*/
Surface.prototype.render = function render() {
return this.id;
};
/**
* Set CSS-style properties on this Surface. Note that this will cause
* dirtying and thus re-rendering, even if values do not change.
*
* @method setProperties
* @param {Object} properties property dictionary of "key" => "value"
*/
Surface.prototype.setProperties = function setProperties(properties) {
for (var n in properties) {
this.properties[n] = properties[n];
}
this._stylesDirty = true;
};
/**
* Get CSS-style properties on this Surface.
*
* @method getProperties
*
* @return {Object} Dictionary of this Surface's properties.
*/
Surface.prototype.getProperties = function getProperties() {
return this.properties;
};
/**
* Add CSS-style class to the list of classes on this Surface. Note
* this will map directly to the HTML property of the actual
* corresponding rendered <div>.
*
* @method addClass
* @param {string} className name of class to add
*/
Surface.prototype.addClass = function addClass(className) {
if (this.classList.indexOf(className) < 0) {
this.classList.push(className);
this._classesDirty = true;
}
};
/**
* Remove CSS-style class from the list of classes on this Surface.
* Note this will map directly to the HTML property of the actual
* corresponding rendered <div>.
*
* @method removeClass
* @param {string} className name of class to remove
*/
Surface.prototype.removeClass = function removeClass(className) {
var i = this.classList.indexOf(className);
if (i >= 0) {
this._dirtyClasses.push(this.classList.splice(i, 1)[0]);
this._classesDirty = true;
}
};
/**
* Reset class list to provided dictionary.
* @method setClasses
* @param {Array.string} classList
*/
Surface.prototype.setClasses = function setClasses(classList) {
var i = 0;
var removal = [];
for (i = 0; i < this.classList.length; i++) {
if (classList.indexOf(this.classList[i]) < 0) removal.push(this.classList[i]);
}
for (i = 0; i < removal.length; i++) this.removeClass(removal[i]);
// duplicates are already checked by addClass()
for (i = 0; i < classList.length; i++) this.addClass(classList[i]);
};
/**
* Get array of CSS-style classes attached to this div.
*
* @method getClasslist
* @return {Array.string} array of class names
*/
Surface.prototype.getClassList = function getClassList() {
return this.classList;
};
/**
* Set or overwrite inner (HTML) content of this surface. Note that this
* causes a re-rendering if the content has changed.
*
* @method setContent
* @param {string} content HTML content
*/
Surface.prototype.setContent = function setContent(content) {
if (this.content !== content) {
this.content = content;
this._contentDirty = true;
}
};
/**
* Return inner (HTML) content of this surface.
*
* @method getContent
*
* @return {string} inner (HTML) content
*/
Surface.prototype.getContent = function getContent() {
return this.content;
};
/**
* Set options for this surface
*
* @method setOptions
* @param {Object} [options] overrides for default options. See constructor.
*/
Surface.prototype.setOptions = function setOptions(options) {
if (options.size) this.setSize(options.size);
if (options.classes) this.setClasses(options.classes);
if (options.properties) this.setProperties(options.properties);
if (options.content) this.setContent(options.content);
};
// Attach Famous event handling to document events emanating from target
// document element. This occurs just after deployment to the document.
// Calling this enables methods like #on and #pipe.
function _addEventListeners(target) {
for (var i in this.eventHandler.listeners) {
target.addEventListener(i, this.eventForwarder);
}
}
// Detach Famous event handling from document events emanating from target
// document element. This occurs just before recall from the document.
function _removeEventListeners(target) {
for (var i in this.eventHandler.listeners) {
target.removeEventListener(i, this.eventForwarder);
}
}
// Apply to document all changes from removeClass() since last setup().
function _cleanupClasses(target) {
for (var i = 0; i < this._dirtyClasses.length; i++) target.classList.remove(this._dirtyClasses[i]);
this._dirtyClasses = [];
}
// Apply values of all Famous-managed styles to the document element.
// These will be deployed to the document on call to #setup().
function _applyStyles(target) {
for (var n in this.properties) {
target.style[n] = this.properties[n];
}
}
// Clear all Famous-managed styles from the document element.
// These will be deployed to the document on call to #setup().
function _cleanupStyles(target) {
for (var n in this.properties) {
target.style[n] = '';
}
}
/**
* Return a Matrix's webkit css representation to be used with the
* CSS3 -webkit-transform style.
* Example: -webkit-transform: matrix3d(1,0,0,0,0,1,0,0,0,0,1,0,716,243,0,1)
*
* @method _formatCSSTransform
* @private
* @param {FamousMatrix} m matrix
* @return {string} matrix3d CSS style representation of the transform
*/
function _formatCSSTransform(m) {
var result = 'matrix3d(';
for (var i = 0; i < 15; i++) {
result += (m[i] < 0.000001 && m[i] > -0.000001) ? '0,' : m[i] + ',';
}
result += m[15] + ')';
return result;
}
/**
* Directly apply given FamousMatrix to the document element as the
* appropriate webkit CSS style.
*
* @method setMatrix
*
* @static
* @private
* @param {Element} element document element
* @param {FamousMatrix} matrix
*/
var _setMatrix = usePrefix ? function(element, matrix) {
element.style.webkitTransform = _formatCSSTransform(matrix);
} : function(element, matrix) {
element.style.transform = _formatCSSTransform(matrix);
};
// format origin as CSS percentage string
function _formatCSSOrigin(origin) {
return (100 * origin[0]).toFixed(6) + '% ' + (100 * origin[1]).toFixed(6) + '%';
}
// Directly apply given origin coordinates to the document element as the
// appropriate webkit CSS style.
var _setOrigin = usePrefix ? function(element, origin) {
element.style.webkitTransformOrigin = _formatCSSOrigin(origin);
} : function(element, origin) {
element.style.transformOrigin = _formatCSSOrigin(origin);
};
// Shrink given document element until it is effectively invisible.
var _setInvisible = usePrefix ? function(element) {
element.style.webkitTransform = 'scale3d(0.0001,0.0001,1)';
element.style.opacity = 0;
} : function(element) {
element.style.transform = 'scale3d(0.0001,0.0001,1)';
element.style.opacity = 0;
};
function _xyNotEquals(a, b) {
return (a && b) ? (a[0] !== b[0] || a[1] !== b[1]) : a !== b;
}
/**
* One-time setup for an element to be ready for commits to document.
*
* @private
* @method setup
*
* @param {ElementAllocator} allocator document element pool for this context
*/
Surface.prototype.setup = function setup(allocator) {
var target = allocator.allocate(this.elementType);
if (this.elementClass) {
if (this.elementClass instanceof Array) {
for (var i = 0; i < this.elementClass.length; i++) {
target.classList.add(this.elementClass[i]);
}
}
else {
target.classList.add(this.elementClass);
}
}
target.style.display = '';
_addEventListeners.call(this, target);
_setOrigin(target, [0, 0]); // handled internally
this._currTarget = target;
this._stylesDirty = true;
this._classesDirty = true;
this._sizeDirty = true;
this._contentDirty = true;
this._matrix = null;
this._opacity = undefined;
this._origin = null;
this._size = null;
};
/**
* Apply changes from this component to the corresponding document element.
* This includes changes to classes, styles, size, content, opacity, origin,
* and matrix transforms.
*
* @private
* @method commit
* @param {Context} context commit context
*/
Surface.prototype.commit = function commit(context) {
if (!this._currTarget) this.setup(context.allocator);
var target = this._currTarget;
var matrix = context.transform;
var opacity = context.opacity;
var origin = context.origin;
var size = context.size;
if (this.size) {
var origSize = size;
size = [this.size[0], this.size[1]];
if (size[0] === undefined && origSize[0]) size[0] = origSize[0];
if (size[1] === undefined && origSize[1]) size[1] = origSize[1];
}
if (_xyNotEquals(this._size, size)) {
this._size = [size[0], size[1]];
this._sizeDirty = true;
}
if (!matrix && this._matrix) {
this._matrix = null;
this._opacity = 0;
_setInvisible(target);
return;
}
if (this._opacity !== opacity) {
this._opacity = opacity;
target.style.opacity = (opacity >= 1) ? '0.999999' : opacity;
}
if (_xyNotEquals(this._origin, origin) || Transform.notEquals(this._matrix, matrix)) {
if (!matrix) matrix = Transform.identity;
this._matrix = matrix;
var aaMatrix = matrix;
if (origin) {
if (!this._origin) this._origin = [0, 0];
this._origin[0] = origin[0];
this._origin[1] = origin[1];
aaMatrix = Transform.moveThen([-this._size[0] * origin[0], -this._size[1] * origin[1], 0], matrix);
}
_setMatrix(target, aaMatrix);
}
if (!(this._classesDirty || this._stylesDirty || this._sizeDirty || this._contentDirty)) return;
if (this._classesDirty) {
_cleanupClasses.call(this, target);
var classList = this.getClassList();
for (var i = 0; i < classList.length; i++) target.classList.add(classList[i]);
this._classesDirty = false;
}
if (this._stylesDirty) {
_applyStyles.call(this, target);
this._stylesDirty = false;
}
if (this._sizeDirty) {
if (this._size) {
target.style.width = (this._size[0] !== true) ? this._size[0] + 'px' : '';
target.style.height = (this._size[1] !== true) ? this._size[1] + 'px' : '';
}
this._sizeDirty = false;
}
if (this._contentDirty) {
this.deploy(target);
this.eventHandler.emit('deploy');
this._contentDirty = false;
}
};
/**
* Remove all Famous-relevant attributes from a document element.
* This is called by SurfaceManager's detach().
* This is in some sense the reverse of .deploy().
*
* @private
* @method cleanup
* @param {ElementAllocator} allocator
*/
Surface.prototype.cleanup = function cleanup(allocator) {
var i = 0;
var target = this._currTarget;
this.eventHandler.emit('recall');
this.recall(target);
target.style.display = 'none';
target.style.width = '';
target.style.height = '';
this._size = null;
_cleanupStyles.call(this, target);
var classList = this.getClassList();
_cleanupClasses.call(this, target);
for (i = 0; i < classList.length; i++) target.classList.remove(classList[i]);
if (this.elementClass) {
if (this.elementClass instanceof Array) {
for (i = 0; i < this.elementClass.length; i++) {
target.classList.remove(this.elementClass[i]);
}
}
else {
target.classList.remove(this.elementClass);
}
}
_removeEventListeners.call(this, target);
this._currTarget = null;
allocator.deallocate(target);
_setInvisible(target);
};
/**
* Place the document element that this component manages into the document.
*
* @private
* @method deploy
* @param {Node} target document parent of this container
*/
Surface.prototype.deploy = function deploy(target) {
var content = this.getContent();
if (content instanceof Node) {
while (target.hasChildNodes()) target.removeChild(target.firstChild);
target.appendChild(content);
}
else target.innerHTML = content;
};
/**
* Remove any contained document content associated with this surface
* from the actual document.
*
* @private
* @method recall
*/
Surface.prototype.recall = function recall(target) {
var df = document.createDocumentFragment();
while (target.hasChildNodes()) df.appendChild(target.firstChild);
this.setContent(df);
};
/**
* Get the x and y dimensions of the surface.
*
* @method getSize
* @param {boolean} actual return computed size rather than provided
* @return {Array.Number} [x,y] size of surface
*/
Surface.prototype.getSize = function getSize(actual) {
return actual ? this._size : (this.size || this._size);
};
/**
* Set x and y dimensions of the surface.
*
* @method setSize
* @param {Array.Number} size as [width, height]
*/
Surface.prototype.setSize = function setSize(size) {
this.size = size ? [size[0], size[1]] : null;
this._sizeDirty = true;
};
module.exports = Surface;
}.call(exports, __webpack_require__, exports, module)), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
/***/ },
/* 16 */
/***/ function(module, exports, __webpack_require__) {
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
module.exports = function addStyle(cssCode) {
if(false) {
if(typeof document !== "object") throw new Error("The style-loader cannot be used in a non-browser environment");
}
var styleElement = document.createElement("style");
styleElement.type = "text/css";
if (styleElement.styleSheet) {
styleElement.styleSheet.cssText = cssCode;
} else {
styleElement.appendChild(document.createTextNode(cssCode));
}
var head = document.getElementsByTagName("head")[0];
head.appendChild(styleElement);
return function() {
head.removeChild(styleElement);
};
}
/***/ },
/* 17 */
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_RESULT__;/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Owner: mark@famo.us
* @license MPL 2.0
* @copyright Famous Industries, Inc. 2014
*/
!(__WEBPACK_AMD_DEFINE_RESULT__ = (function(require, exports, module) {
var Entity = __webpack_require__(22);
var SpecParser = __webpack_require__(25);
/**
* A wrapper for inserting a renderable component (like a Modifer or
* Surface) into the render tree.
*
* @class RenderNode
* @constructor
*
* @param {Object} object Target renderable component
*/
function RenderNode(object) {
this._object = null;
this._child = null;
this._hasMultipleChildren = false;
this._isRenderable = false;
this._isModifier = false;
this._resultCache = {};
this._prevResults = {};
this._childResult = null;
if (object) this.set(object);
}
/**
* Append a renderable to the list of this node's children.
* This produces a new RenderNode in the tree.
* Note: Does not double-wrap if child is a RenderNode already.
*
* @method add
* @param {Object} child renderable object
* @return {RenderNode} new render node wrapping child
*/
RenderNode.prototype.add = function add(child) {
var childNode = (child instanceof RenderNode) ? child : new RenderNode(child);
if (this._child instanceof Array) this._child.push(childNode);
else if (this._child) {
this._child = [this._child, childNode];
this._hasMultipleChildren = true;
this._childResult = []; // to be used later
}
else this._child = childNode;
return childNode;
};
/**
* Return the single wrapped object. Returns null if this node has multiple child nodes.
*
* @method get
*
* @return {Ojbect} contained renderable object
*/
RenderNode.prototype.get = function get() {
return this._object || (this._hasMultipleChildren ? null : (this._child ? this._child.get() : null));
};
/**
* Overwrite the list of children to contain the single provided object
*
* @method set
* @param {Object} child renderable object
* @return {RenderNode} this render node, or child if it is a RenderNode
*/
RenderNode.prototype.set = function set(child) {
this._childResult = null;
this._hasMultipleChildren = false;
this._isRenderable = child.render ? true : false;
this._isModifier = child.modify ? true : false;
this._object = child;
this._child = null;
if (child instanceof RenderNode) return child;
else return this;
};
/**
* Get render size of contained object.
*
* @method getSize
* @return {Array.Number} size of this or size of single child.
*/
RenderNode.prototype.getSize = function getSize() {
var result = null;
var target = this.get();
if (target && target.getSize) result = target.getSize();
if (!result && this._child && this._child.getSize) result = this._child.getSize();
return result;
};
// apply results of rendering this subtree to the document
function _applyCommit(spec, context, cacheStorage) {
var result = SpecParser.parse(spec, context);
var keys = Object.keys(result);
for (var i = 0; i < keys.length; i++) {
var id = keys[i];
var childNode = Entity.get(id);
var commitParams = result[id];
commitParams.allocator = context.allocator;
var commitResult = childNode.commit(commitParams);
if (commitResult) _applyCommit(commitResult, context, cacheStorage);
else cacheStorage[id] = commitParams;
}
}
/**
* Commit the content change from this node to the document.
*
* @private
* @method commit
* @param {Context} context render context
*/
RenderNode.prototype.commit = function commit(context) {
// free up some divs from the last loop
var prevKeys = Object.keys(this._prevResults);
for (var i = 0; i < prevKeys.length; i++) {
var id = prevKeys[i];
if (this._resultCache[id] === undefined) {
var object = Entity.get(id);
if (object.cleanup) object.cleanup(context.allocator);
}
}
this._prevResults = this._resultCache;
this._resultCache = {};
_applyCommit(this.render(), context, this._resultCache);
};
/**
* Generate a render spec from the contents of the wrapped component.
*
* @private
* @method render
*
* @return {Object} render specification for the component subtree
* only under this node.
*/
RenderNode.prototype.render = function render() {
if (this._isRenderable) return this._object.render();
var result = null;
if (this._hasMultipleChildren) {
result = this._childResult;
var children = this._child;
for (var i = 0; i < children.length; i++) {
result[i] = children[i].render();
}
}
else if (this._child) result = this._child.render();
return this._isModifier ? this._object.modify(result) : result;
};
module.exports = RenderNode;
}.call(exports, __webpack_require__, exports, module)), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
/***/ },
/* 18 */
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_RESULT__;/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Owner: mark@famo.us
* @license MPL 2.0
* @copyright Famous Industries, Inc. 2014
*/
!(__WEBPACK_AMD_DEFINE_RESULT__ = (function(require, exports, module) {
/**
* Internal helper object to Context that handles the process of
* creating and allocating DOM elements within a managed div.
* Private.
*
* @class ElementAllocator
* @constructor
* @private
* @param {Node} container document element in which Famo.us content will be inserted
*/
function ElementAllocator(container) {
if (!container) container = document.createDocumentFragment();
this.container = container;
this.detachedNodes = {};
this.nodeCount = 0;
}
/**
* Move the document elements from their original container to a new one.
*
* @private
* @method migrate
*
* @param {Node} container document element to which Famo.us content will be migrated
*/
ElementAllocator.prototype.migrate = function migrate(container) {
var oldContainer = this.container;
if (container === oldContainer) return;
if (oldContainer instanceof DocumentFragment) {
container.appendChild(oldContainer);
}
else {
while (oldContainer.hasChildNodes()) {
container.appendChild(oldContainer.removeChild(oldContainer.firstChild));
}
}
this.container = container;
};
/**
* Allocate an element of specified type from the pool.
*
* @private
* @method allocate
*
* @param {string} type type of element, e.g. 'div'
* @return {Node} allocated document element
*/
ElementAllocator.prototype.allocate = function allocate(type) {
type = type.toLowerCase();
if (!(type in this.detachedNodes)) this.detachedNodes[type] = [];
var nodeStore = this.detachedNodes[type];
var result;
if (nodeStore.length > 0) {
result = nodeStore.pop();
}
else {
result = document.createElement(type);
this.container.appendChild(result);
}
this.nodeCount++;
return result;
};
/**
* De-allocate an element of specified type to the pool.
*
* @private
* @method deallocate
*
* @param {Node} element document element to deallocate
*/
ElementAllocator.prototype.deallocate = function deallocate(element) {
var nodeType = element.nodeName.toLowerCase();
var nodeStore = this.detachedNodes[nodeType];
nodeStore.push(element);
this.nodeCount--;
};
/**
* Get count of total allocated nodes in the document.
*
* @private
* @method getNodeCount
*
* @return {Number} total node count
*/
ElementAllocator.prototype.getNodeCount = function getNodeCount() {
return this.nodeCount;
};
module.exports = ElementAllocator;
}.call(exports, __webpack_require__, exports, module)), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
/***/ },
/* 19 */
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_RESULT__;/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Owner: mark@famo.us
* @license MPL 2.0
* @copyright Famous Industries, Inc. 2014
*/
!(__WEBPACK_AMD_DEFINE_RESULT__ = (function(require, exports, module) {
/**
* EventEmitter represents a channel for events.
*
* @class EventEmitter
* @constructor
*/
function EventEmitter() {
this.listeners = {};
this._owner = this;
}
/**
* Trigger an event, sending to all downstream handlers
* listening for provided 'type' key.
*
* @method emit
*
* @param {string} type event type key (for example, 'click')
* @param {Object} event event data
* @return {EventHandler} this
*/
EventEmitter.prototype.emit = function emit(type, event) {
var handlers = this.listeners[type];
if (handlers) {
for (var i = 0; i < handlers.length; i++) {
handlers[i].call(this._owner, event);
}
}
return this;
};
/**
* Bind a callback function to an event type handled by this object.
*
* @method "on"
*
* @param {string} type event type key (for example, 'click')
* @param {function(string, Object)} handler callback
* @return {EventHandler} this
*/
EventEmitter.prototype.on = function on(type, handler) {
if (!(type in this.listeners)) this.listeners[type] = [];
var index = this.listeners[type].indexOf(handler);
if (index < 0) this.listeners[type].push(handler);
return this;
};
/**
* Alias for "on".
* @method addListener
*/
EventEmitter.prototype.addListener = EventEmitter.prototype.on;
/**
* Unbind an event by type and handler.
* This undoes the work of "on".
*
* @method removeListener
*
* @param {string} type event type key (for example, 'click')
* @param {function} handler function object to remove
* @return {EventEmitter} this
*/
EventEmitter.prototype.removeListener = function removeListener(type, handler) {
var index = this.listeners[type].indexOf(handler);
if (index >= 0) this.listeners[type].splice(index, 1);
return this;
};
/**
* Call event handlers with this set to owner.
*
* @method bindThis
*
* @param {Object} owner object this EventEmitter belongs to
*/
EventEmitter.prototype.bindThis = function bindThis(owner) {
this._owner = owner;
};
module.exports = EventEmitter;
}.call(exports, __webpack_require__, exports, module)), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
/***/ },
/* 20 */
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_RESULT__;/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Owner: david@famo.us
* @license MPL 2.0
* @copyright Famous Industries, Inc. 2014
*/
!(__WEBPACK_AMD_DEFINE_RESULT__ = (function(require, exports, module) {
var Utility = __webpack_require__(23);
/**
* Transition meta-method to support transitioning multiple
* values with scalar-only methods.
*
*
* @class MultipleTransition
* @constructor
*
* @param {Object} method Transionable class to multiplex
*/
function MultipleTransition(method) {
this.method = method;
this._instances = [];
this.state = [];
}
MultipleTransition.SUPPORTS_MULTIPLE = true;
/**
* Get the state of each transition.
*
* @method get
*
* @return state {Number|Array} state array
*/
MultipleTransition.prototype.get = function get() {
for (var i = 0; i < this._instances.length; i++) {
this.state[i] = this._instances[i].get();
}
return this.state;
};
/**
* Set the end states with a shared transition, with optional callback.
*
* @method set
*
* @param {Number|Array} endState Final State. Use a multi-element argument for multiple transitions.
* @param {Object} transition Transition definition, shared among all instances
* @param {Function} callback called when all endStates have been reached.
*/
MultipleTransition.prototype.set = function set(endState, transition, callback) {
var _allCallback = Utility.after(endState.length, callback);
for (var i = 0; i < endState.length; i++) {
if (!this._instances[i]) this._instances[i] = new (this.method)();
this._instances[i].set(endState[i], transition, _allCallback);
}
};
/**
* Reset all transitions to start state.
*
* @method reset
*
* @param {Number|Array} startState Start state
*/
MultipleTransition.prototype.reset = function reset(startState) {
for (var i = 0; i < startState.length; i++) {
if (!this._instances[i]) this._instances[i] = new (this.method)();
this._instances[i].reset(startState[i]);
}
};
module.exports = MultipleTransition;
}.call(exports, __webpack_require__, exports, module)), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
/***/ },
/* 21 */
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_RESULT__;/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Owner: david@famo.us
* @license MPL 2.0
* @copyright Famous Industries, Inc. 2014
*/
!(__WEBPACK_AMD_DEFINE_RESULT__ = (function(require, exports, module) {
/**
*
* A state maintainer for a smooth transition between
* numerically-specified states. Example numeric states include floats or
* Transfornm objects.
*
* An initial state is set with the constructor or set(startValue). A
* corresponding end state and transition are set with set(endValue,
* transition). Subsequent calls to set(endValue, transition) begin at
* the last state. Calls to get(timestamp) provide the _interpolated state
* along the way.
*
* Note that there is no event loop here - calls to get() are the only way
* to find out state projected to the current (or provided) time and are
* the only way to trigger callbacks. Usually this kind of object would
* be part of the render() path of a visible component.
*
* @class TweenTransition
* @constructor
*
* @param {Object} options TODO
* beginning state
*/
function TweenTransition(options) {
this.options = Object.create(TweenTransition.DEFAULT_OPTIONS);
if (options) this.setOptions(options);
this._startTime = 0;
this._startValue = 0;
this._updateTime = 0;
this._endValue = 0;
this._curve = undefined;
this._duration = 0;
this._active = false;
this._callback = undefined;
this.state = 0;
this.velocity = undefined;
}
/**
* Transition curves mapping independent variable t from domain [0,1] to a
* range within [0,1]. Includes functions 'linear', 'easeIn', 'easeOut',
* 'easeInOut', 'easeOutBounce', 'spring'.
*
* @property {object} Curve
* @final
*/
TweenTransition.Curves = {
linear: function(t) {
return t;
},
easeIn: function(t) {
return t*t;
},
easeOut: function(t) {
return t*(2-t);
},
easeInOut: function(t) {
if (t <= 0.5) return 2*t*t;
else return -2*t*t + 4*t - 1;
},
easeOutBounce: function(t) {
return t*(3 - 2*t);
},
spring: function(t) {
return (1 - t) * Math.sin(6 * Math.PI * t) + t;
}
};
TweenTransition.SUPPORTS_MULTIPLE = true;
TweenTransition.DEFAULT_OPTIONS = {
curve: TweenTransition.Curves.linear,
duration: 500,
speed: 0 /* considered only if positive */
};
var registeredCurves = {};
/**
* Add "unit" curve to internal dictionary of registered curves.
*
* @method registerCurve
*
* @static
*
* @param {string} curveName dictionary key
* @param {unitCurve} curve function of one numeric variable mapping [0,1]
* to range inside [0,1]
* @return {boolean} false if key is taken, else true
*/
TweenTransition.registerCurve = function registerCurve(curveName, curve) {
if (!registeredCurves[curveName]) {
registeredCurves[curveName] = curve;
return true;
}
else {
return false;
}
};
/**
* Remove object with key "curveName" from internal dictionary of registered
* curves.
*
* @method unregisterCurve
*
* @static
*
* @param {string} curveName dictionary key
* @return {boolean} false if key has no dictionary value
*/
TweenTransition.unregisterCurve = function unregisterCurve(curveName) {
if (registeredCurves[curveName]) {
delete registeredCurves[curveName];
return true;
}
else {
return false;
}
};
/**
* Retrieve function with key "curveName" from internal dictionary of
* registered curves. Default curves are defined in the
* TweenTransition.Curves array, where the values represent
* unitCurve functions.
*
* @method getCurve
*
* @static
*
* @param {string} curveName dictionary key
* @return {unitCurve} curve function of one numeric variable mapping [0,1]
* to range inside [0,1]
*/
TweenTransition.getCurve = function getCurve(curveName) {
return registeredCurves[curveName];
};
/**
* Retrieve all available curves.
*
* @method getCurves
*
* @static
*
* @return {object} curve functions of one numeric variable mapping [0,1]
* to range inside [0,1]
*/
TweenTransition.getCurves = function getCurves() {
return registeredCurves;
};
// Interpolate: If a linear function f(0) = a, f(1) = b, then return f(t)
function _interpolate(a, b, t) {
return ((1 - t) * a) + (t * b);
}
function _clone(obj) {
if (obj instanceof Object) {
if (obj instanceof Array) return obj.slice(0);
else return Object.create(obj);
}
else return obj;
}
// Fill in missing properties in "transition" with those in defaultTransition, and
// convert internal named curve to function object, returning as new
// object.
function _normalize(transition, defaultTransition) {
var result = {curve: defaultTransition.curve};
if (defaultTransition.duration) result.duration = defaultTransition.duration;
if (defaultTransition.speed) result.speed = defaultTransition.speed;
if (transition instanceof Object) {
if (transition.duration !== undefined) result.duration = transition.duration;
if (transition.curve) result.curve = transition.curve;
if (transition.speed) result.speed = transition.speed;
}
if (typeof result.curve === 'string') result.curve = TweenTransition.getCurve(result.curve);
return result;
}
/**
* Set internal options, overriding any default options.
*
* @method setOptions
*
*
* @param {Object} options options object
* @param {Object} [options.curve] function mapping [0,1] to [0,1] or identifier
* @param {Number} [options.duration] duration in ms
* @param {Number} [options.speed] speed in pixels per ms
*/
TweenTransition.prototype.setOptions = function setOptions(options) {
if (options.curve !== undefined) this.options.curve = options.curve;
if (options.duration !== undefined) this.options.duration = options.duration;
if (options.speed !== undefined) this.options.speed = options.speed;
};
/**
* Add transition to end state to the queue of pending transitions. Special
* Use: calling without a transition resets the object to that state with
* no pending actions
*
* @method set
*
*
* @param {number|FamousMatrix|Array.Number|Object.<number, number>} endValue
* end state to which we _interpolate
* @param {transition=} transition object of type {duration: number, curve:
* f[0,1] -> [0,1] or name}. If transition is omitted, change will be
* instantaneous.
* @param {function()=} callback Zero-argument function to call on observed
* completion (t=1)
*/
TweenTransition.prototype.set = function set(endValue, transition, callback) {
if (!transition) {
this.reset(endValue);
if (callback) callback();
return;
}
this._startValue = _clone(this.get());
transition = _normalize(transition, this.options);
if (transition.speed) {
var startValue = this._startValue;
if (startValue instanceof Object) {
var variance = 0;
for (var i in startValue) variance += (endValue[i] - startValue[i]) * (endValue[i] - startValue[i]);
transition.duration = Math.sqrt(variance) / transition.speed;
}
else {
transition.duration = Math.abs(endValue - startValue) / transition.speed;
}
}
this._startTime = Date.now();
this._endValue = _clone(endValue);
this._startVelocity = _clone(transition.velocity);
this._duration = transition.duration;
this._curve = transition.curve;
this._active = true;
this._callback = callback;
};
/**
* Cancel all transitions and reset to a stable state
*
* @method reset
*
* @param {number|Array.Number|Object.<number, number>} startValue
* starting state
* @param {number} startVelocity
* starting velocity
*/
TweenTransition.prototype.reset = function reset(startValue, startVelocity) {
if (this._callback) {
var callback = this._callback;
this._callback = undefined;
callback();
}
this.state = _clone(startValue);
this.velocity = _clone(startVelocity);
this._startTime = 0;
this._duration = 0;
this._updateTime = 0;
this._startValue = this.state;
this._startVelocity = this.velocity;
this._endValue = this.state;
this._active = false;
};
/**
* Get current velocity
*
* @method getVelocity
*
* @returns {Number} velocity
*/
TweenTransition.prototype.getVelocity = function getVelocity() {
return this.velocity;
};
/**
* Get interpolated state of current action at provided time. If the last
* action has completed, invoke its callback.
*
* @method get
*
*
* @param {number=} timestamp Evaluate the curve at a normalized version of this
* time. If omitted, use current time. (Unix epoch time)
* @return {number|Object.<number|string, number>} beginning state
* _interpolated to this point in time.
*/
TweenTransition.prototype.get = function get(timestamp) {
this.update(timestamp);
return this.state;
};
function _calculateVelocity(current, start, curve, duration, t) {
var velocity;
var eps = 1e-7;
var speed = (curve(t) - curve(t - eps)) / eps;
if (current instanceof Array) {
velocity = [];
for (var i = 0; i < current.length; i++)
velocity[i] = speed * (current[i] - start[i]) / duration;
}
else velocity = speed * (current - start) / duration;
return velocity;
}
function _calculateState(start, end, t) {
var state;
if (start instanceof Array) {
state = [];
for (var i = 0; i < start.length; i++)
state[i] = _interpolate(start[i], end[i], t);
}
else state = _interpolate(start, end, t);
return state;
}
/**
* Update internal state to the provided timestamp. This may invoke the last
* callback and begin a new action.
*
* @method update
*
*
* @param {number=} timestamp Evaluate the curve at a normalized version of this
* time. If omitted, use current time. (Unix epoch time)
*/
TweenTransition.prototype.update = function update(timestamp) {
if (!this._active) {
if (this._callback) {
var callback = this._callback;
this._callback = undefined;
callback();
}
return;
}
if (!timestamp) timestamp = Date.now();
if (this._updateTime >= timestamp) return;
this._updateTime = timestamp;
var timeSinceStart = timestamp - this._startTime;
if (timeSinceStart >= this._duration) {
this.state = this._endValue;
this.velocity = _calculateVelocity(this.state, this._startValue, this._curve, this._duration, 1);
this._active = false;
}
else if (timeSinceStart < 0) {
this.state = this._startValue;
this.velocity = this._startVelocity;
}
else {
var t = timeSinceStart / this._duration;
this.state = _calculateState(this._startValue, this._endValue, this._curve(t));
this.velocity = _calculateVelocity(this.state, this._startValue, this._curve, this._duration, t);
}
};
/**
* Is there at least one action pending completion?
*
* @method isActive
*
*
* @return {boolean}
*/
TweenTransition.prototype.isActive = function isActive() {
return this._active;
};
/**
* Halt transition at current state and erase all pending actions.
*
* @method halt
*
*/
TweenTransition.prototype.halt = function halt() {
this.reset(this.get());
};
// Register all the default curves
TweenTransition.registerCurve('linear', TweenTransition.Curves.linear);
TweenTransition.registerCurve('easeIn', TweenTransition.Curves.easeIn);
TweenTransition.registerCurve('easeOut', TweenTransition.Curves.easeOut);
TweenTransition.registerCurve('easeInOut', TweenTransition.Curves.easeInOut);
TweenTransition.registerCurve('easeOutBounce', TweenTransition.Curves.easeOutBounce);
TweenTransition.registerCurve('spring', TweenTransition.Curves.spring);
TweenTransition.customCurve = function customCurve(v1, v2) {
v1 = v1 || 0; v2 = v2 || 0;
return function(t) {
return v1*t + (-2*v1 - v2 + 3)*t*t + (v1 + v2 - 2)*t*t*t;
};
};
module.exports = TweenTransition;
}.call(exports, __webpack_require__, exports, module)), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
/***/ },
/* 22 */
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_RESULT__;/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Owner: mark@famo.us
* @license MPL 2.0
* @copyright Famous Industries, Inc. 2014
*/
!(__WEBPACK_AMD_DEFINE_RESULT__ = (function(require, exports, module) {
/**
* A singleton that maintains a global registry of Surfaces.
* Private.
*
* @private
* @static
* @class Entity
*/
var entities = [];
/**
* Get entity from global index.
*
* @private
* @method get
* @param {Number} id entity reigstration id
* @return {Surface} entity in the global index
*/
function get(id) {
return entities[id];
}
/**
* Overwrite entity in the global index
*
* @private
* @method set
* @param {Number} id entity reigstration id
* @return {Surface} entity to add to the global index
*/
function set(id, entity) {
entities[id] = entity;
}
/**
* Add entity to global index
*
* @private
* @method register
* @param {Surface} entity to add to global index
* @return {Number} new id
*/
function register(entity) {
var id = entities.length;
set(id, entity);
return id;
}
/**
* Remove entity from global index
*
* @private
* @method unregister
* @param {Number} id entity reigstration id
*/
function unregister(id) {
set(id, null);
}
module.exports = {
register: register,
unregister: unregister,
get: get,
set: set
};
}.call(exports, __webpack_require__, exports, module)), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
/***/ },
/* 23 */
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_RESULT__;/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Owner: mark@famo.us
* @license MPL 2.0
* @copyright Famous Industries, Inc. 2014
*/
!(__WEBPACK_AMD_DEFINE_RESULT__ = (function(require, exports, module) {
/**
* This namespace holds standalone functionality.
* Currently includes name mapping for transition curves,
* name mapping for origin pairs, and the after() function.
*
* @class Utility
* @static
*/
var Utility = {};
/**
* Table of direction array positions
*
* @property {object} Direction
* @final
*/
Utility.Direction = {
X: 0,
Y: 1,
Z: 2
};
/**
* Return wrapper around callback function. Once the wrapper is called N
* times, invoke the callback function. Arguments and scope preserved.
*
* @method after
*
* @param {number} count number of calls before callback function invoked
* @param {Function} callback wrapped callback function
*
* @return {function} wrapped callback with coundown feature
*/
Utility.after = function after(count, callback) {
var counter = count;
return function() {
counter--;
if (counter === 0) callback.apply(this, arguments);
};
};
/**
* Load a URL and return its contents in a callback
*
* @method loadURL
*
* @param {string} url URL of object
* @param {function} callback callback to dispatch with content
*/
Utility.loadURL = function loadURL(url, callback) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function onreadystatechange() {
if (this.readyState === 4) {
if (callback) callback(this.responseText);
}
};
xhr.open('GET', url);
xhr.send();
};
/**
* Create a document fragment from a string of HTML
*
* @method createDocumentFragmentFromHTML
*
* @param {string} html HTML to convert to DocumentFragment
*
* @return {DocumentFragment} DocumentFragment representing input HTML
*/
Utility.createDocumentFragmentFromHTML = function createDocumentFragmentFromHTML(html) {
var element = document.createElement('div');
element.innerHTML = html;
var result = document.createDocumentFragment();
while (element.hasChildNodes()) result.appendChild(element.firstChild);
return result;
};
module.exports = Utility;
}.call(exports, __webpack_require__, exports, module)), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
/***/ },
/* 24 */
/***/ function(module, exports, __webpack_require__) {
module.exports = function(module) {
if(!module.webpackPolyfill) {
module.deprecate = function() {};
module.paths = [];
// module.parent = undefined by default
module.children = [];
module.webpackPolyfill = 1;
}
return module;
}
/***/ },
/* 25 */
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_RESULT__;
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Owner: mark@famo.us
* @license MPL 2.0
* @copyright Famous Industries, Inc. 2014
*/
!(__WEBPACK_AMD_DEFINE_RESULT__ = (function(require, exports, module) {
var Transform = __webpack_require__(2);
/**
*
* This object translates the rendering instructions ("render specs")
* that renderable components generate into document update
* instructions ("update specs"). Private.
*
* @private
* @class SpecParser
* @constructor
*/
function SpecParser() {
this.result = {};
}
SpecParser._instance = new SpecParser();
/**
* Convert a render spec coming from the context's render chain to an
* update spec for the update chain. This is the only major entry point
* for a consumer of this class.
*
* @method parse
* @static
* @private
*
* @param {renderSpec} spec input render spec
* @param {Object} context context to do the parse in
* @return {Object} the resulting update spec (if no callback
* specified, else none)
*/
SpecParser.parse = function parse(spec, context) {
return SpecParser._instance.parse(spec, context);
};
/**
* Convert a renderSpec coming from the context's render chain to an update
* spec for the update chain. This is the only major entrypoint for a
* consumer of this class.
*
* @method parse
*
* @private
* @param {renderSpec} spec input render spec
* @param {Context} context
* @return {updateSpec} the resulting update spec
*/
SpecParser.prototype.parse = function parse(spec, context) {
this.reset();
this._parseSpec(spec, context, Transform.identity);
return this.result;
};
/**
* Prepare SpecParser for re-use (or first use) by setting internal state
* to blank.
*
* @private
* @method reset
*/
SpecParser.prototype.reset = function reset() {
this.result = {};
};
// Multiply matrix M by vector v
function _vecInContext(v, m) {
return [
v[0] * m[0] + v[1] * m[4] + v[2] * m[8],
v[0] * m[1] + v[1] * m[5] + v[2] * m[9],
v[0] * m[2] + v[1] * m[6] + v[2] * m[10]
];
}
var _originZeroZero = [0, 0];
// From the provided renderSpec tree, recursively compose opacities,
// origins, transforms, and sizes corresponding to each surface id from
// the provided renderSpec tree structure. On completion, those
// properties of 'this' object should be ready to use to build an
// updateSpec.
SpecParser.prototype._parseSpec = function _parseSpec(spec, parentContext, sizeContext) {
var id;
var target;
var transform;
var opacity;
var origin;
var size;
if (typeof spec === 'number') {
id = spec;
transform = parentContext.transform;
if (parentContext.size && parentContext.origin && (parentContext.origin[0] || parentContext.origin[1])) {
var originAdjust = [parentContext.origin[0] * parentContext.size[0], parentContext.origin[1] * parentContext.size[1], 0];
transform = Transform.thenMove(transform, _vecInContext(originAdjust, sizeContext));
}
this.result[id] = {
transform: transform,
opacity: parentContext.opacity,
origin: parentContext.origin || _originZeroZero,
size: parentContext.size
};
}
else if (!spec) { // placed here so 0 will be cached earlier
return;
}
else if (spec instanceof Array) {
for (var i = 0; i < spec.length; i++) {
this._parseSpec(spec[i], parentContext, sizeContext);
}
}
else {
target = spec.target;
transform = parentContext.transform;
opacity = parentContext.opacity;
origin = parentContext.origin;
size = parentContext.size;
var nextSizeContext = sizeContext;
if (spec.opacity !== undefined) opacity = parentContext.opacity * spec.opacity;
if (spec.transform) transform = Transform.multiply(parentContext.transform, spec.transform);
if (spec.origin) {
origin = spec.origin;
nextSizeContext = parentContext.transform;
}
if (spec.size) {
var parentSize = parentContext.size;
size = [spec.size[0] || parentSize[0], spec.size[1] || parentSize[1]];
if (parentSize && origin && (origin[0] || origin[1])) {
transform = Transform.thenMove(transform, _vecInContext([origin[0] * parentSize[0], origin[1] * parentSize[1], 0], sizeContext));
transform = Transform.moveThen([-origin[0] * size[0], -origin[1] * size[1], 0], transform);
}
nextSizeContext = parentContext.transform;
origin = null;
}
this._parseSpec(target, {
transform: transform,
opacity: opacity,
origin: origin,
size: size
}, nextSizeContext);
}
};
module.exports = SpecParser;
}.call(exports, __webpack_require__, exports, module)), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
/***/ }
/******/ ])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment