Files
homebridge/public/vendor/diffsync.js
Nick Farina dbedf7fe01 Convert to ES5, add web server
* No compilation step
 * Beginnings of web interface
 * Simple express server; React-based frontend
 * CommonJS style across codebase; auto-converts to RequireJS for browser
 * Using diffsync for realtime UI
 * "Provider" -> "Plugin"
 * Plugins expose one or more Providers
2015-08-11 22:27:59 -07:00

4170 lines
123 KiB
JavaScript

!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.diffsync=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
function EventEmitter() {
this._events = this._events || {};
this._maxListeners = this._maxListeners || undefined;
}
module.exports = EventEmitter;
// Backwards-compat with node 0.10.x
EventEmitter.EventEmitter = EventEmitter;
EventEmitter.prototype._events = undefined;
EventEmitter.prototype._maxListeners = undefined;
// By default EventEmitters will print a warning if more than 10 listeners are
// added to it. This is a useful default which helps finding memory leaks.
EventEmitter.defaultMaxListeners = 10;
// Obviously not all Emitters should be limited to 10. This function allows
// that to be increased. Set to zero for unlimited.
EventEmitter.prototype.setMaxListeners = function(n) {
if (!isNumber(n) || n < 0 || isNaN(n))
throw TypeError('n must be a positive number');
this._maxListeners = n;
return this;
};
EventEmitter.prototype.emit = function(type) {
var er, handler, len, args, i, listeners;
if (!this._events)
this._events = {};
// If there is no 'error' event listener then throw.
if (type === 'error') {
if (!this._events.error ||
(isObject(this._events.error) && !this._events.error.length)) {
er = arguments[1];
if (er instanceof Error) {
throw er; // Unhandled 'error' event
}
throw TypeError('Uncaught, unspecified "error" event.');
}
}
handler = this._events[type];
if (isUndefined(handler))
return false;
if (isFunction(handler)) {
switch (arguments.length) {
// fast cases
case 1:
handler.call(this);
break;
case 2:
handler.call(this, arguments[1]);
break;
case 3:
handler.call(this, arguments[1], arguments[2]);
break;
// slower
default:
len = arguments.length;
args = new Array(len - 1);
for (i = 1; i < len; i++)
args[i - 1] = arguments[i];
handler.apply(this, args);
}
} else if (isObject(handler)) {
len = arguments.length;
args = new Array(len - 1);
for (i = 1; i < len; i++)
args[i - 1] = arguments[i];
listeners = handler.slice();
len = listeners.length;
for (i = 0; i < len; i++)
listeners[i].apply(this, args);
}
return true;
};
EventEmitter.prototype.addListener = function(type, listener) {
var m;
if (!isFunction(listener))
throw TypeError('listener must be a function');
if (!this._events)
this._events = {};
// To avoid recursion in the case that type === "newListener"! Before
// adding it to the listeners, first emit "newListener".
if (this._events.newListener)
this.emit('newListener', type,
isFunction(listener.listener) ?
listener.listener : listener);
if (!this._events[type])
// Optimize the case of one listener. Don't need the extra array object.
this._events[type] = listener;
else if (isObject(this._events[type]))
// If we've already got an array, just append.
this._events[type].push(listener);
else
// Adding the second element, need to change to array.
this._events[type] = [this._events[type], listener];
// Check for listener leak
if (isObject(this._events[type]) && !this._events[type].warned) {
var m;
if (!isUndefined(this._maxListeners)) {
m = this._maxListeners;
} else {
m = EventEmitter.defaultMaxListeners;
}
if (m && m > 0 && this._events[type].length > m) {
this._events[type].warned = true;
console.error('(node) warning: possible EventEmitter memory ' +
'leak detected. %d listeners added. ' +
'Use emitter.setMaxListeners() to increase limit.',
this._events[type].length);
if (typeof console.trace === 'function') {
// not supported in IE 10
console.trace();
}
}
}
return this;
};
EventEmitter.prototype.on = EventEmitter.prototype.addListener;
EventEmitter.prototype.once = function(type, listener) {
if (!isFunction(listener))
throw TypeError('listener must be a function');
var fired = false;
function g() {
this.removeListener(type, g);
if (!fired) {
fired = true;
listener.apply(this, arguments);
}
}
g.listener = listener;
this.on(type, g);
return this;
};
// emits a 'removeListener' event iff the listener was removed
EventEmitter.prototype.removeListener = function(type, listener) {
var list, position, length, i;
if (!isFunction(listener))
throw TypeError('listener must be a function');
if (!this._events || !this._events[type])
return this;
list = this._events[type];
length = list.length;
position = -1;
if (list === listener ||
(isFunction(list.listener) && list.listener === listener)) {
delete this._events[type];
if (this._events.removeListener)
this.emit('removeListener', type, listener);
} else if (isObject(list)) {
for (i = length; i-- > 0;) {
if (list[i] === listener ||
(list[i].listener && list[i].listener === listener)) {
position = i;
break;
}
}
if (position < 0)
return this;
if (list.length === 1) {
list.length = 0;
delete this._events[type];
} else {
list.splice(position, 1);
}
if (this._events.removeListener)
this.emit('removeListener', type, listener);
}
return this;
};
EventEmitter.prototype.removeAllListeners = function(type) {
var key, listeners;
if (!this._events)
return this;
// not listening for removeListener, no need to emit
if (!this._events.removeListener) {
if (arguments.length === 0)
this._events = {};
else if (this._events[type])
delete this._events[type];
return this;
}
// emit removeListener for all listeners on all events
if (arguments.length === 0) {
for (key in this._events) {
if (key === 'removeListener') continue;
this.removeAllListeners(key);
}
this.removeAllListeners('removeListener');
this._events = {};
return this;
}
listeners = this._events[type];
if (isFunction(listeners)) {
this.removeListener(type, listeners);
} else {
// LIFO order
while (listeners.length)
this.removeListener(type, listeners[listeners.length - 1]);
}
delete this._events[type];
return this;
};
EventEmitter.prototype.listeners = function(type) {
var ret;
if (!this._events || !this._events[type])
ret = [];
else if (isFunction(this._events[type]))
ret = [this._events[type]];
else
ret = this._events[type].slice();
return ret;
};
EventEmitter.listenerCount = function(emitter, type) {
var ret;
if (!emitter._events || !emitter._events[type])
ret = 0;
else if (isFunction(emitter._events[type]))
ret = 1;
else
ret = emitter._events[type].length;
return ret;
};
function isFunction(arg) {
return typeof arg === 'function';
}
function isNumber(arg) {
return typeof arg === 'number';
}
function isObject(arg) {
return typeof arg === 'object' && arg !== null;
}
function isUndefined(arg) {
return arg === void 0;
}
},{}],2:[function(require,module,exports){
module.exports = {
Client: require('./src/client'),
Server: require('./src/server'),
COMMANDS: require('./src/commands'),
InMemoryDataAdapter: require('./src/adapter')
};
},{"./src/adapter":43,"./src/client":44,"./src/commands":45,"./src/server":46}],3:[function(require,module,exports){
var Pipe = require('../pipe').Pipe;
var Context = function Context(){
};
Context.prototype.setResult = function(result) {
this.result = result;
this.hasResult = true;
return this;
};
Context.prototype.exit = function() {
this.exiting = true;
return this;
};
Context.prototype.switchTo = function(next, pipe) {
if (typeof next === 'string' || next instanceof Pipe) {
this.nextPipe = next;
} else {
this.next = next;
if (pipe) {
this.nextPipe = pipe;
}
}
return this;
};
Context.prototype.push = function(child, name) {
child.parent = this;
if (typeof name !== 'undefined') {
child.childName = name;
}
child.root = this.root || this;
child.options = child.options || this.options;
if (!this.children) {
this.children = [child];
this.nextAfterChildren = this.next || null;
this.next = child;
} else {
this.children[this.children.length - 1].next = child;
this.children.push(child);
}
child.next = this;
return this;
};
exports.Context = Context;
},{"../pipe":17}],4:[function(require,module,exports){
var Context = require('./context').Context;
var DiffContext = function DiffContext(left, right) {
this.left = left;
this.right = right;
this.pipe = 'diff';
};
DiffContext.prototype = new Context();
exports.DiffContext = DiffContext;
},{"./context":3}],5:[function(require,module,exports){
var Context = require('./context').Context;
var PatchContext = function PatchContext(left, delta) {
this.left = left;
this.delta = delta;
this.pipe = 'patch';
};
PatchContext.prototype = new Context();
exports.PatchContext = PatchContext;
},{"./context":3}],6:[function(require,module,exports){
var Context = require('./context').Context;
var ReverseContext = function ReverseContext(delta) {
this.delta = delta;
this.pipe = 'reverse';
};
ReverseContext.prototype = new Context();
exports.ReverseContext = ReverseContext;
},{"./context":3}],7:[function(require,module,exports){
// use as 2nd parameter for JSON.parse to revive Date instances
module.exports = function dateReviver(key, value) {
var parts;
if (typeof value === 'string') {
parts = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.(\d*))?(Z|([+\-])(\d{2}):(\d{2}))$/.exec(value);
if (parts) {
return new Date(Date.UTC(+parts[1], +parts[2] - 1, +parts[3], +parts[4], +parts[5], +parts[6], +(parts[7] || 0)));
}
}
return value;
};
},{}],8:[function(require,module,exports){
var Processor = require('./processor').Processor;
var Pipe = require('./pipe').Pipe;
var DiffContext = require('./contexts/diff').DiffContext;
var PatchContext = require('./contexts/patch').PatchContext;
var ReverseContext = require('./contexts/reverse').ReverseContext;
var trivial = require('./filters/trivial');
var nested = require('./filters/nested');
var arrays = require('./filters/arrays');
var dates = require('./filters/dates');
var texts = require('./filters/texts');
var DiffPatcher = function DiffPatcher(options) {
this.processor = new Processor(options);
this.processor.pipe(new Pipe('diff').append(
nested.collectChildrenDiffFilter,
trivial.diffFilter,
dates.diffFilter,
texts.diffFilter,
nested.objectsDiffFilter,
arrays.diffFilter
).shouldHaveResult());
this.processor.pipe(new Pipe('patch').append(
nested.collectChildrenPatchFilter,
arrays.collectChildrenPatchFilter,
trivial.patchFilter,
texts.patchFilter,
nested.patchFilter,
arrays.patchFilter
).shouldHaveResult());
this.processor.pipe(new Pipe('reverse').append(
nested.collectChildrenReverseFilter,
arrays.collectChildrenReverseFilter,
trivial.reverseFilter,
texts.reverseFilter,
nested.reverseFilter,
arrays.reverseFilter
).shouldHaveResult());
};
DiffPatcher.prototype.options = function() {
return this.processor.options.apply(this.processor, arguments);
};
DiffPatcher.prototype.diff = function(left, right) {
return this.processor.process(new DiffContext(left, right));
};
DiffPatcher.prototype.patch = function(left, delta) {
return this.processor.process(new PatchContext(left, delta));
};
DiffPatcher.prototype.reverse = function(delta) {
return this.processor.process(new ReverseContext(delta));
};
DiffPatcher.prototype.unpatch = function(right, delta) {
return this.patch(right, this.reverse(delta));
};
exports.DiffPatcher = DiffPatcher;
},{"./contexts/diff":4,"./contexts/patch":5,"./contexts/reverse":6,"./filters/arrays":10,"./filters/dates":11,"./filters/nested":13,"./filters/texts":14,"./filters/trivial":15,"./pipe":17,"./processor":18}],9:[function(require,module,exports){
exports.isBrowser = typeof window !== 'undefined';
},{}],10:[function(require,module,exports){
var DiffContext = require('../contexts/diff').DiffContext;
var PatchContext = require('../contexts/patch').PatchContext;
var ReverseContext = require('../contexts/reverse').ReverseContext;
var lcs = require('./lcs');
var ARRAY_MOVE = 3;
var isArray = (typeof Array.isArray === 'function') ?
// use native function
Array.isArray :
// use instanceof operator
function(a) {
return a instanceof Array;
};
var arrayIndexOf = typeof Array.prototype.indexOf === 'function' ?
function(array, item) {
return array.indexOf(item);
} : function(array, item) {
var length = array.length;
for (var i = 0; i < length; i++) {
if (array[i] === item) {
return i;
}
}
return -1;
};
function arraysHaveMatchByRef(array1, array2, len1, len2) {
for (var index1 = 0; index1 < len1; index1++) {
var val1 = array1[index1];
for (var index2 = 0; index2 < len2; index2++) {
var val2 = array2[index2];
if (val1 === val2) {
return true;
}
}
}
}
function matchItems(array1, array2, index1, index2, context) {
var value1 = array1[index1];
var value2 = array2[index2];
if (value1 === value2) {
return true;
}
if (typeof value1 !== 'object' || typeof value2 !== 'object') {
return false;
}
var objectHash = context.objectHash;
if (!objectHash) {
// no way to match objects was provided, try match by position
return context.matchByPosition && index1 === index2;
}
var hash1;
var hash2;
if (typeof index1 === 'number') {
context.hashCache1 = context.hashCache1 || [];
hash1 = context.hashCache1[index1];
if (typeof hash1 === 'undefined') {
context.hashCache1[index1] = hash1 = objectHash(value1, index1);
}
} else {
hash1 = objectHash(value1);
}
if (typeof hash1 === 'undefined') {
return false;
}
if (typeof index2 === 'number') {
context.hashCache2 = context.hashCache2 || [];
hash2 = context.hashCache2[index2];
if (typeof hash2 === 'undefined') {
context.hashCache2[index2] = hash2 = objectHash(value2, index2);
}
} else {
hash2 = objectHash(value2);
}
if (typeof hash2 === 'undefined') {
return false;
}
return hash1 === hash2;
}
var diffFilter = function arraysDiffFilter(context) {
if (!context.leftIsArray) {
return;
}
var matchContext = {
objectHash: context.options && context.options.objectHash,
matchByPosition: context.options && context.options.matchByPosition
};
var commonHead = 0;
var commonTail = 0;
var index;
var index1;
var index2;
var array1 = context.left;
var array2 = context.right;
var len1 = array1.length;
var len2 = array2.length;
var child;
if (len1 > 0 && len2 > 0 && !matchContext.objectHash &&
typeof matchContext.matchByPosition !== 'boolean') {
matchContext.matchByPosition = !arraysHaveMatchByRef(array1, array2, len1, len2);
}
// separate common head
while (commonHead < len1 && commonHead < len2 &&
matchItems(array1, array2, commonHead, commonHead, matchContext)) {
index = commonHead;
child = new DiffContext(context.left[index], context.right[index]);
context.push(child, index);
commonHead++;
}
// separate common tail
while (commonTail + commonHead < len1 && commonTail + commonHead < len2 &&
matchItems(array1, array2, len1 - 1 - commonTail, len2 - 1 - commonTail, matchContext)) {
index1 = len1 - 1 - commonTail;
index2 = len2 - 1 - commonTail;
child = new DiffContext(context.left[index1], context.right[index2]);
context.push(child, index2);
commonTail++;
}
var result;
if (commonHead + commonTail === len1) {
if (len1 === len2) {
// arrays are identical
context.setResult(undefined).exit();
return;
}
// trivial case, a block (1 or more consecutive items) was added
result = result || {
_t: 'a'
};
for (index = commonHead; index < len2 - commonTail; index++) {
result[index] = [array2[index]];
}
context.setResult(result).exit();
return;
}
if (commonHead + commonTail === len2) {
// trivial case, a block (1 or more consecutive items) was removed
result = result || {
_t: 'a'
};
for (index = commonHead; index < len1 - commonTail; index++) {
result['_' + index] = [array1[index], 0, 0];
}
context.setResult(result).exit();
return;
}
// reset hash cache
delete matchContext.hashCache1;
delete matchContext.hashCache2;
// diff is not trivial, find the LCS (Longest Common Subsequence)
var trimmed1 = array1.slice(commonHead, len1 - commonTail);
var trimmed2 = array2.slice(commonHead, len2 - commonTail);
var seq = lcs.get(
trimmed1, trimmed2,
matchItems,
matchContext
);
var removedItems = [];
result = result || {
_t: 'a'
};
for (index = commonHead; index < len1 - commonTail; index++) {
if (arrayIndexOf(seq.indices1, index - commonHead) < 0) {
// removed
result['_' + index] = [array1[index], 0, 0];
removedItems.push(index);
}
}
var detectMove = true;
if (context.options && context.options.arrays && context.options.arrays.detectMove === false) {
detectMove = false;
}
var includeValueOnMove = false;
if (context.options && context.options.arrays && context.options.arrays.includeValueOnMove) {
includeValueOnMove = true;
}
var removedItemsLength = removedItems.length;
for (index = commonHead; index < len2 - commonTail; index++) {
var indexOnArray2 = arrayIndexOf(seq.indices2, index - commonHead);
if (indexOnArray2 < 0) {
// added, try to match with a removed item and register as position move
var isMove = false;
if (detectMove && removedItemsLength > 0) {
for (var removeItemIndex1 = 0; removeItemIndex1 < removedItemsLength; removeItemIndex1++) {
index1 = removedItems[removeItemIndex1];
if (matchItems(trimmed1, trimmed2, index1 - commonHead,
index - commonHead, matchContext)) {
// store position move as: [originalValue, newPosition, ARRAY_MOVE]
result['_' + index1].splice(1, 2, index, ARRAY_MOVE);
if (!includeValueOnMove) {
// don't include moved value on diff, to save bytes
result['_' + index1][0] = '';
}
index2 = index;
child = new DiffContext(context.left[index1], context.right[index2]);
context.push(child, index2);
removedItems.splice(removeItemIndex1, 1);
isMove = true;
break;
}
}
}
if (!isMove) {
// added
result[index] = [array2[index]];
}
} else {
// match, do inner diff
index1 = seq.indices1[indexOnArray2] + commonHead;
index2 = seq.indices2[indexOnArray2] + commonHead;
child = new DiffContext(context.left[index1], context.right[index2]);
context.push(child, index2);
}
}
context.setResult(result).exit();
};
diffFilter.filterName = 'arrays';
var compare = {
numerically: function(a, b) {
return a - b;
},
numericallyBy: function(name) {
return function(a, b) {
return a[name] - b[name];
};
}
};
var patchFilter = function nestedPatchFilter(context) {
if (!context.nested) {
return;
}
if (context.delta._t !== 'a') {
return;
}
var index, index1;
var delta = context.delta;
var array = context.left;
// first, separate removals, insertions and modifications
var toRemove = [];
var toInsert = [];
var toModify = [];
for (index in delta) {
if (index !== '_t') {
if (index[0] === '_') {
// removed item from original array
if (delta[index][2] === 0 || delta[index][2] === ARRAY_MOVE) {
toRemove.push(parseInt(index.slice(1), 10));
} else {
throw new Error('only removal or move can be applied at original array indices' +
', invalid diff type: ' + delta[index][2]);
}
} else {
if (delta[index].length === 1) {
// added item at new array
toInsert.push({
index: parseInt(index, 10),
value: delta[index][0]
});
} else {
// modified item at new array
toModify.push({
index: parseInt(index, 10),
delta: delta[index]
});
}
}
}
}
// remove items, in reverse order to avoid sawing our own floor
toRemove = toRemove.sort(compare.numerically);
for (index = toRemove.length - 1; index >= 0; index--) {
index1 = toRemove[index];
var indexDiff = delta['_' + index1];
var removedValue = array.splice(index1, 1)[0];
if (indexDiff[2] === ARRAY_MOVE) {
// reinsert later
toInsert.push({
index: indexDiff[1],
value: removedValue
});
}
}
// insert items, in reverse order to avoid moving our own floor
toInsert = toInsert.sort(compare.numericallyBy('index'));
var toInsertLength = toInsert.length;
for (index = 0; index < toInsertLength; index++) {
var insertion = toInsert[index];
array.splice(insertion.index, 0, insertion.value);
}
// apply modifications
var toModifyLength = toModify.length;
var child;
if (toModifyLength > 0) {
for (index = 0; index < toModifyLength; index++) {
var modification = toModify[index];
child = new PatchContext(context.left[modification.index], modification.delta);
context.push(child, modification.index);
}
}
if (!context.children) {
context.setResult(context.left).exit();
return;
}
context.exit();
};
patchFilter.filterName = 'arrays';
var collectChildrenPatchFilter = function collectChildrenPatchFilter(context) {
if (!context || !context.children) {
return;
}
if (context.delta._t !== 'a') {
return;
}
var length = context.children.length;
var child;
for (var index = 0; index < length; index++) {
child = context.children[index];
context.left[child.childName] = child.result;
}
context.setResult(context.left).exit();
};
collectChildrenPatchFilter.filterName = 'arraysCollectChildren';
var reverseFilter = function arraysReverseFilter(context) {
if (!context.nested) {
if (context.delta[2] === ARRAY_MOVE) {
context.newName = '_' + context.delta[1];
context.setResult([context.delta[0], parseInt(context.childName.substr(1), 10), ARRAY_MOVE]).exit();
}
return;
}
if (context.delta._t !== 'a') {
return;
}
var name, child;
for (name in context.delta) {
if (name === '_t') {
continue;
}
child = new ReverseContext(context.delta[name]);
context.push(child, name);
}
context.exit();
};
reverseFilter.filterName = 'arrays';
var reverseArrayDeltaIndex = function(delta, index, itemDelta) {
if (typeof index === 'string' && index[0] === '_') {
return parseInt(index.substr(1), 10);
} else if (isArray(itemDelta) && itemDelta[2] === 0) {
return '_' + index;
}
var reverseIndex = +index;
for (var deltaIndex in delta) {
var deltaItem = delta[deltaIndex];
if (isArray(deltaItem)) {
if (deltaItem[2] === ARRAY_MOVE) {
var moveFromIndex = parseInt(deltaIndex.substr(1), 10);
var moveToIndex = deltaItem[1];
if (moveToIndex === +index) {
return moveFromIndex;
}
if (moveFromIndex <= reverseIndex && moveToIndex > reverseIndex) {
reverseIndex++;
} else if (moveFromIndex >= reverseIndex && moveToIndex < reverseIndex) {
reverseIndex--;
}
} else if (deltaItem[2] === 0) {
var deleteIndex = parseInt(deltaIndex.substr(1), 10);
if (deleteIndex <= reverseIndex) {
reverseIndex++;
}
} else if (deltaItem.length === 1 && deltaIndex <= reverseIndex) {
reverseIndex--;
}
}
}
return reverseIndex;
};
var collectChildrenReverseFilter = function collectChildrenReverseFilter(context) {
if (!context || !context.children) {
return;
}
if (context.delta._t !== 'a') {
return;
}
var length = context.children.length;
var child;
var delta = {
_t: 'a'
};
for (var index = 0; index < length; index++) {
child = context.children[index];
var name = child.newName;
if (typeof name === 'undefined') {
name = reverseArrayDeltaIndex(context.delta, child.childName, child.result);
}
if (delta[name] !== child.result) {
delta[name] = child.result;
}
}
context.setResult(delta).exit();
};
collectChildrenReverseFilter.filterName = 'arraysCollectChildren';
exports.diffFilter = diffFilter;
exports.patchFilter = patchFilter;
exports.collectChildrenPatchFilter = collectChildrenPatchFilter;
exports.reverseFilter = reverseFilter;
exports.collectChildrenReverseFilter = collectChildrenReverseFilter;
},{"../contexts/diff":4,"../contexts/patch":5,"../contexts/reverse":6,"./lcs":12}],11:[function(require,module,exports){
var diffFilter = function datesDiffFilter(context) {
if (context.left instanceof Date) {
if (context.right instanceof Date) {
if (context.left.getTime() !== context.right.getTime()) {
context.setResult([context.left, context.right]);
} else {
context.setResult(undefined);
}
} else {
context.setResult([context.left, context.right]);
}
context.exit();
} else if (context.right instanceof Date) {
context.setResult([context.left, context.right]).exit();
}
};
diffFilter.filterName = 'dates';
exports.diffFilter = diffFilter;
},{}],12:[function(require,module,exports){
/*
LCS implementation that supports arrays or strings
reference: http://en.wikipedia.org/wiki/Longest_common_subsequence_problem
*/
var defaultMatch = function(array1, array2, index1, index2) {
return array1[index1] === array2[index2];
};
var lengthMatrix = function(array1, array2, match, context) {
var len1 = array1.length;
var len2 = array2.length;
var x, y;
// initialize empty matrix of len1+1 x len2+1
var matrix = [len1 + 1];
for (x = 0; x < len1 + 1; x++) {
matrix[x] = [len2 + 1];
for (y = 0; y < len2 + 1; y++) {
matrix[x][y] = 0;
}
}
matrix.match = match;
// save sequence lengths for each coordinate
for (x = 1; x < len1 + 1; x++) {
for (y = 1; y < len2 + 1; y++) {
if (match(array1, array2, x - 1, y - 1, context)) {
matrix[x][y] = matrix[x - 1][y - 1] + 1;
} else {
matrix[x][y] = Math.max(matrix[x - 1][y], matrix[x][y - 1]);
}
}
}
return matrix;
};
var backtrack = function(matrix, array1, array2, index1, index2, context) {
if (index1 === 0 || index2 === 0) {
return {
sequence: [],
indices1: [],
indices2: []
};
}
if (matrix.match(array1, array2, index1 - 1, index2 - 1, context)) {
var subsequence = backtrack(matrix, array1, array2, index1 - 1, index2 - 1, context);
subsequence.sequence.push(array1[index1 - 1]);
subsequence.indices1.push(index1 - 1);
subsequence.indices2.push(index2 - 1);
return subsequence;
}
if (matrix[index1][index2 - 1] > matrix[index1 - 1][index2]) {
return backtrack(matrix, array1, array2, index1, index2 - 1, context);
} else {
return backtrack(matrix, array1, array2, index1 - 1, index2, context);
}
};
var get = function(array1, array2, match, context) {
context = context || {};
var matrix = lengthMatrix(array1, array2, match || defaultMatch, context);
var result = backtrack(matrix, array1, array2, array1.length, array2.length, context);
if (typeof array1 === 'string' && typeof array2 === 'string') {
result.sequence = result.sequence.join('');
}
return result;
};
exports.get = get;
},{}],13:[function(require,module,exports){
var DiffContext = require('../contexts/diff').DiffContext;
var PatchContext = require('../contexts/patch').PatchContext;
var ReverseContext = require('../contexts/reverse').ReverseContext;
var collectChildrenDiffFilter = function collectChildrenDiffFilter(context) {
if (!context || !context.children) {
return;
}
var length = context.children.length;
var child;
var result = context.result;
for (var index = 0; index < length; index++) {
child = context.children[index];
if (typeof child.result === 'undefined') {
continue;
}
result = result || {};
result[child.childName] = child.result;
}
if (result && context.leftIsArray) {
result._t = 'a';
}
context.setResult(result).exit();
};
collectChildrenDiffFilter.filterName = 'collectChildren';
var objectsDiffFilter = function objectsDiffFilter(context) {
if (context.leftIsArray || context.leftType !== 'object') {
return;
}
var name, child;
for (name in context.left) {
child = new DiffContext(context.left[name], context.right[name]);
context.push(child, name);
}
for (name in context.right) {
if (typeof context.left[name] === 'undefined') {
child = new DiffContext(undefined, context.right[name]);
context.push(child, name);
}
}
if (!context.children || context.children.length === 0) {
context.setResult(undefined).exit();
return;
}
context.exit();
};
objectsDiffFilter.filterName = 'objects';
var patchFilter = function nestedPatchFilter(context) {
if (!context.nested) {
return;
}
if (context.delta._t) {
return;
}
var name, child;
for (name in context.delta) {
child = new PatchContext(context.left[name], context.delta[name]);
context.push(child, name);
}
context.exit();
};
patchFilter.filterName = 'objects';
var collectChildrenPatchFilter = function collectChildrenPatchFilter(context) {
if (!context || !context.children) {
return;
}
if (context.delta._t) {
return;
}
var length = context.children.length;
var child;
for (var index = 0; index < length; index++) {
child = context.children[index];
if (context.left.hasOwnProperty(child.childName) && child.result === undefined) {
delete context.left[child.childName];
} else if (context.left[child.childName] !== child.result) {
context.left[child.childName] = child.result;
}
}
context.setResult(context.left).exit();
};
collectChildrenPatchFilter.filterName = 'collectChildren';
var reverseFilter = function nestedReverseFilter(context) {
if (!context.nested) {
return;
}
if (context.delta._t) {
return;
}
var name, child;
for (name in context.delta) {
child = new ReverseContext(context.delta[name]);
context.push(child, name);
}
context.exit();
};
reverseFilter.filterName = 'objects';
var collectChildrenReverseFilter = function collectChildrenReverseFilter(context) {
if (!context || !context.children) {
return;
}
if (context.delta._t) {
return;
}
var length = context.children.length;
var child;
var delta = {};
for (var index = 0; index < length; index++) {
child = context.children[index];
if (delta[child.childName] !== child.result) {
delta[child.childName] = child.result;
}
}
context.setResult(delta).exit();
};
collectChildrenReverseFilter.filterName = 'collectChildren';
exports.collectChildrenDiffFilter = collectChildrenDiffFilter;
exports.objectsDiffFilter = objectsDiffFilter;
exports.patchFilter = patchFilter;
exports.collectChildrenPatchFilter = collectChildrenPatchFilter;
exports.reverseFilter = reverseFilter;
exports.collectChildrenReverseFilter = collectChildrenReverseFilter;
},{"../contexts/diff":4,"../contexts/patch":5,"../contexts/reverse":6}],14:[function(require,module,exports){
/* global diff_match_patch */
var TEXT_DIFF = 2;
var DEFAULT_MIN_LENGTH = 60;
var cachedDiffPatch = null;
var getDiffMatchPatch = function() {
/*jshint camelcase: false */
if (!cachedDiffPatch) {
var instance;
if (typeof diff_match_patch !== 'undefined') {
// already loaded, probably a browser
instance = typeof diff_match_patch === 'function' ?
new diff_match_patch() : new diff_match_patch.diff_match_patch();
} else if (typeof require === 'function') {
try {
var dmpModuleName = 'diff_match_patch_uncompressed';
var dmp = require('../../public/external/' + dmpModuleName);
instance = new dmp.diff_match_patch();
} catch (err) {
instance = null;
}
}
if (!instance) {
var error = new Error('text diff_match_patch library not found');
error.diff_match_patch_not_found = true;
throw error;
}
cachedDiffPatch = {
diff: function(txt1, txt2) {
return instance.patch_toText(instance.patch_make(txt1, txt2));
},
patch: function(txt1, patch) {
var results = instance.patch_apply(instance.patch_fromText(patch), txt1);
for (var i = 0; i < results[1].length; i++) {
if (!results[1][i]) {
var error = new Error('text patch failed');
error.textPatchFailed = true;
}
}
return results[0];
}
};
}
return cachedDiffPatch;
};
var diffFilter = function textsDiffFilter(context) {
if (context.leftType !== 'string') {
return;
}
var minLength = (context.options && context.options.textDiff &&
context.options.textDiff.minLength) || DEFAULT_MIN_LENGTH;
if (context.left.length < minLength ||
context.right.length < minLength) {
context.setResult([context.left, context.right]).exit();
return;
}
// large text, use a text-diff algorithm
var diff = getDiffMatchPatch().diff;
context.setResult([diff(context.left, context.right), 0, TEXT_DIFF]).exit();
};
diffFilter.filterName = 'texts';
var patchFilter = function textsPatchFilter(context) {
if (context.nested) {
return;
}
if (context.delta[2] !== TEXT_DIFF) {
return;
}
// text-diff, use a text-patch algorithm
var patch = getDiffMatchPatch().patch;
context.setResult(patch(context.left, context.delta[0])).exit();
};
patchFilter.filterName = 'texts';
var textDeltaReverse = function(delta) {
var i, l, lines, line, lineTmp, header = null,
headerRegex = /^@@ +\-(\d+),(\d+) +\+(\d+),(\d+) +@@$/,
lineHeader, lineAdd, lineRemove;
lines = delta.split('\n');
for (i = 0, l = lines.length; i < l; i++) {
line = lines[i];
var lineStart = line.slice(0, 1);
if (lineStart === '@') {
header = headerRegex.exec(line);
lineHeader = i;
lineAdd = null;
lineRemove = null;
// fix header
lines[lineHeader] = '@@ -' + header[3] + ',' + header[4] + ' +' + header[1] + ',' + header[2] + ' @@';
} else if (lineStart === '+') {
lineAdd = i;
lines[i] = '-' + lines[i].slice(1);
if (lines[i - 1].slice(0, 1) === '+') {
// swap lines to keep default order (-+)
lineTmp = lines[i];
lines[i] = lines[i - 1];
lines[i - 1] = lineTmp;
}
} else if (lineStart === '-') {
lineRemove = i;
lines[i] = '+' + lines[i].slice(1);
}
}
return lines.join('\n');
};
var reverseFilter = function textsReverseFilter(context) {
if (context.nested) {
return;
}
if (context.delta[2] !== TEXT_DIFF) {
return;
}
// text-diff, use a text-diff algorithm
context.setResult([textDeltaReverse(context.delta[0]), 0, TEXT_DIFF]).exit();
};
reverseFilter.filterName = 'texts';
exports.diffFilter = diffFilter;
exports.patchFilter = patchFilter;
exports.reverseFilter = reverseFilter;
},{}],15:[function(require,module,exports){
var isArray = (typeof Array.isArray === 'function') ?
// use native function
Array.isArray :
// use instanceof operator
function(a) {
return a instanceof Array;
};
var diffFilter = function trivialMatchesDiffFilter(context) {
if (context.left === context.right) {
context.setResult(undefined).exit();
return;
}
if (typeof context.left === 'undefined') {
if (typeof context.right === 'function') {
throw new Error('functions are not supported');
}
context.setResult([context.right]).exit();
return;
}
if (typeof context.right === 'undefined') {
context.setResult([context.left, 0, 0]).exit();
return;
}
if (typeof context.left === 'function' || typeof context.right === 'function') {
throw new Error('functions are not supported');
}
context.leftType = context.left === null ? 'null' : typeof context.left;
context.rightType = context.right === null ? 'null' : typeof context.right;
if (context.leftType !== context.rightType) {
context.setResult([context.left, context.right]).exit();
return;
}
if (context.leftType === 'boolean' || context.leftType === 'number') {
context.setResult([context.left, context.right]).exit();
return;
}
if (context.leftType === 'object') {
context.leftIsArray = isArray(context.left);
}
if (context.rightType === 'object') {
context.rightIsArray = isArray(context.right);
}
if (context.leftIsArray !== context.rightIsArray) {
context.setResult([context.left, context.right]).exit();
return;
}
};
diffFilter.filterName = 'trivial';
var patchFilter = function trivialMatchesPatchFilter(context) {
if (typeof context.delta === 'undefined') {
context.setResult(context.left).exit();
return;
}
context.nested = !isArray(context.delta);
if (context.nested) {
return;
}
if (context.delta.length === 1) {
context.setResult(context.delta[0]).exit();
return;
}
if (context.delta.length === 2) {
context.setResult(context.delta[1]).exit();
return;
}
if (context.delta.length === 3 && context.delta[2] === 0) {
context.setResult(undefined).exit();
return;
}
};
patchFilter.filterName = 'trivial';
var reverseFilter = function trivialReferseFilter(context) {
if (typeof context.delta === 'undefined') {
context.setResult(context.delta).exit();
return;
}
context.nested = !isArray(context.delta);
if (context.nested) {
return;
}
if (context.delta.length === 1) {
context.setResult([context.delta[0], 0, 0]).exit();
return;
}
if (context.delta.length === 2) {
context.setResult([context.delta[1], context.delta[0]]).exit();
return;
}
if (context.delta.length === 3 && context.delta[2] === 0) {
context.setResult([context.delta[0]]).exit();
return;
}
};
reverseFilter.filterName = 'trivial';
exports.diffFilter = diffFilter;
exports.patchFilter = patchFilter;
exports.reverseFilter = reverseFilter;
},{}],16:[function(require,module,exports){
var environment = require('./environment');
var DiffPatcher = require('./diffpatcher').DiffPatcher;
exports.DiffPatcher = DiffPatcher;
exports.create = function(options){
return new DiffPatcher(options);
};
exports.dateReviver = require('./date-reviver');
var defaultInstance;
exports.diff = function() {
if (!defaultInstance) {
defaultInstance = new DiffPatcher();
}
return defaultInstance.diff.apply(defaultInstance, arguments);
};
exports.patch = function() {
if (!defaultInstance) {
defaultInstance = new DiffPatcher();
}
return defaultInstance.patch.apply(defaultInstance, arguments);
};
exports.unpatch = function() {
if (!defaultInstance) {
defaultInstance = new DiffPatcher();
}
return defaultInstance.unpatch.apply(defaultInstance, arguments);
};
exports.reverse = function() {
if (!defaultInstance) {
defaultInstance = new DiffPatcher();
}
return defaultInstance.reverse.apply(defaultInstance, arguments);
};
if (environment.isBrowser) {
exports.homepage = '{{package-homepage}}';
exports.version = '{{package-version}}';
} else {
var packageInfoModuleName = '../package.json';
var packageInfo = require(packageInfoModuleName);
exports.homepage = packageInfo.homepage;
exports.version = packageInfo.version;
var formatterModuleName = './formatters';
var formatters = require(formatterModuleName);
exports.formatters = formatters;
// shortcut for console
exports.console = formatters.console;
}
},{"./date-reviver":7,"./diffpatcher":8,"./environment":9}],17:[function(require,module,exports){
var Pipe = function Pipe(name) {
this.name = name;
this.filters = [];
};
Pipe.prototype.process = function(input) {
if (!this.processor) {
throw new Error('add this pipe to a processor before using it');
}
var debug = this.debug;
var length = this.filters.length;
var context = input;
for (var index = 0; index < length; index++) {
var filter = this.filters[index];
if (debug) {
this.log('filter: ' + filter.filterName);
}
filter(context);
if (typeof context === 'object' && context.exiting) {
context.exiting = false;
break;
}
}
if (!context.next && this.resultCheck) {
this.resultCheck(context);
}
};
Pipe.prototype.log = function(msg) {
console.log('[jsondiffpatch] ' + this.name + ' pipe, ' + msg);
};
Pipe.prototype.append = function() {
this.filters.push.apply(this.filters, arguments);
return this;
};
Pipe.prototype.prepend = function() {
this.filters.unshift.apply(this.filters, arguments);
return this;
};
Pipe.prototype.indexOf = function(filterName) {
if (!filterName) {
throw new Error('a filter name is required');
}
for (var index = 0; index < this.filters.length; index++) {
var filter = this.filters[index];
if (filter.filterName === filterName) {
return index;
}
}
throw new Error('filter not found: ' + filterName);
};
Pipe.prototype.list = function() {
var names = [];
for (var index = 0; index < this.filters.length; index++) {
var filter = this.filters[index];
names.push(filter.filterName);
}
return names;
};
Pipe.prototype.after = function(filterName) {
var index = this.indexOf(filterName);
var params = Array.prototype.slice.call(arguments, 1);
if (!params.length) {
throw new Error('a filter is required');
}
params.unshift(index + 1, 0);
Array.prototype.splice.apply(this.filters, params);
return this;
};
Pipe.prototype.before = function(filterName) {
var index = this.indexOf(filterName);
var params = Array.prototype.slice.call(arguments, 1);
if (!params.length) {
throw new Error('a filter is required');
}
params.unshift(index, 0);
Array.prototype.splice.apply(this.filters, params);
return this;
};
Pipe.prototype.clear = function() {
this.filters.length = 0;
return this;
};
Pipe.prototype.shouldHaveResult = function(should) {
if (should === false) {
this.resultCheck = null;
return;
}
if (this.resultCheck) {
return;
}
var pipe = this;
this.resultCheck = function(context) {
if (!context.hasResult) {
console.log(context);
var error = new Error(pipe.name + ' failed');
error.noResult = true;
throw error;
}
};
return this;
};
exports.Pipe = Pipe;
},{}],18:[function(require,module,exports){
var Processor = function Processor(options){
this.selfOptions = options;
this.pipes = {};
};
Processor.prototype.options = function(options) {
if (options) {
this.selfOptions = options;
}
return this.selfOptions;
};
Processor.prototype.pipe = function(name, pipe) {
if (typeof name === 'string') {
if (typeof pipe === 'undefined') {
return this.pipes[name];
} else {
this.pipes[name] = pipe;
}
}
if (name && name.name) {
pipe = name;
if (pipe.processor === this) { return pipe; }
this.pipes[pipe.name] = pipe;
}
pipe.processor = this;
return pipe;
};
Processor.prototype.process = function(input, pipe) {
var context = input;
context.options = this.options();
var nextPipe = pipe || input.pipe || 'default';
var lastPipe, lastContext;
while (nextPipe) {
if (typeof context.nextAfterChildren !== 'undefined') {
// children processed and coming back to parent
context.next = context.nextAfterChildren;
context.nextAfterChildren = null;
}
if (typeof nextPipe === 'string') {
nextPipe = this.pipe(nextPipe);
}
nextPipe.process(context);
lastContext = context;
lastPipe = nextPipe;
nextPipe = null;
if (context) {
if (context.next) {
context = context.next;
nextPipe = lastContext.nextPipe || context.pipe || lastPipe;
}
}
}
return context.hasResult ? context.result : undefined;
};
exports.Processor = Processor;
},{}],19:[function(require,module,exports){
/**
* lodash 3.2.0 (Custom Build) <https://lodash.com/>
* Build: `lodash modern modularize exports="npm" -o ./`
* Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
* Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
* Available under MIT license <https://lodash.com/license>
*/
var baseAssign = require('lodash._baseassign'),
createAssigner = require('lodash._createassigner'),
keys = require('lodash.keys');
/**
* A specialized version of `_.assign` for customizing assigned values without
* support for argument juggling, multiple sources, and `this` binding `customizer`
* functions.
*
* @private
* @param {Object} object The destination object.
* @param {Object} source The source object.
* @param {Function} customizer The function to customize assigned values.
* @returns {Object} Returns `object`.
*/
function assignWith(object, source, customizer) {
var index = -1,
props = keys(source),
length = props.length;
while (++index < length) {
var key = props[index],
value = object[key],
result = customizer(value, source[key], key, object, source);
if ((result === result ? (result !== value) : (value === value)) ||
(value === undefined && !(key in object))) {
object[key] = result;
}
}
return object;
}
/**
* Assigns own enumerable properties of source object(s) to the destination
* object. Subsequent sources overwrite property assignments of previous sources.
* If `customizer` is provided it is invoked to produce the assigned values.
* The `customizer` is bound to `thisArg` and invoked with five arguments:
* (objectValue, sourceValue, key, object, source).
*
* **Note:** This method mutates `object` and is based on
* [`Object.assign`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.assign).
*
* @static
* @memberOf _
* @alias extend
* @category Object
* @param {Object} object The destination object.
* @param {...Object} [sources] The source objects.
* @param {Function} [customizer] The function to customize assigned values.
* @param {*} [thisArg] The `this` binding of `customizer`.
* @returns {Object} Returns `object`.
* @example
*
* _.assign({ 'user': 'barney' }, { 'age': 40 }, { 'user': 'fred' });
* // => { 'user': 'fred', 'age': 40 }
*
* // using a customizer callback
* var defaults = _.partialRight(_.assign, function(value, other) {
* return _.isUndefined(value) ? other : value;
* });
*
* defaults({ 'user': 'barney' }, { 'age': 36 }, { 'user': 'fred' });
* // => { 'user': 'barney', 'age': 36 }
*/
var assign = createAssigner(function(object, source, customizer) {
return customizer
? assignWith(object, source, customizer)
: baseAssign(object, source);
});
module.exports = assign;
},{"lodash._baseassign":20,"lodash._createassigner":22,"lodash.keys":26}],20:[function(require,module,exports){
/**
* lodash 3.2.0 (Custom Build) <https://lodash.com/>
* Build: `lodash modern modularize exports="npm" -o ./`
* Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
* Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
* Available under MIT license <https://lodash.com/license>
*/
var baseCopy = require('lodash._basecopy'),
keys = require('lodash.keys');
/**
* The base implementation of `_.assign` without support for argument juggling,
* multiple sources, and `customizer` functions.
*
* @private
* @param {Object} object The destination object.
* @param {Object} source The source object.
* @returns {Object} Returns `object`.
*/
function baseAssign(object, source) {
return source == null
? object
: baseCopy(source, keys(source), object);
}
module.exports = baseAssign;
},{"lodash._basecopy":21,"lodash.keys":26}],21:[function(require,module,exports){
/**
* lodash 3.0.1 (Custom Build) <https://lodash.com/>
* Build: `lodash modern modularize exports="npm" -o ./`
* Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
* Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
* Available under MIT license <https://lodash.com/license>
*/
/**
* Copies properties of `source` to `object`.
*
* @private
* @param {Object} source The object to copy properties from.
* @param {Array} props The property names to copy.
* @param {Object} [object={}] The object to copy properties to.
* @returns {Object} Returns `object`.
*/
function baseCopy(source, props, object) {
object || (object = {});
var index = -1,
length = props.length;
while (++index < length) {
var key = props[index];
object[key] = source[key];
}
return object;
}
module.exports = baseCopy;
},{}],22:[function(require,module,exports){
/**
* lodash 3.1.1 (Custom Build) <https://lodash.com/>
* Build: `lodash modern modularize exports="npm" -o ./`
* Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
* Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
* Available under MIT license <https://lodash.com/license>
*/
var bindCallback = require('lodash._bindcallback'),
isIterateeCall = require('lodash._isiterateecall'),
restParam = require('lodash.restparam');
/**
* Creates a function that assigns properties of source object(s) to a given
* destination object.
*
* **Note:** This function is used to create `_.assign`, `_.defaults`, and `_.merge`.
*
* @private
* @param {Function} assigner The function to assign values.
* @returns {Function} Returns the new assigner function.
*/
function createAssigner(assigner) {
return restParam(function(object, sources) {
var index = -1,
length = object == null ? 0 : sources.length,
customizer = length > 2 ? sources[length - 2] : undefined,
guard = length > 2 ? sources[2] : undefined,
thisArg = length > 1 ? sources[length - 1] : undefined;
if (typeof customizer == 'function') {
customizer = bindCallback(customizer, thisArg, 5);
length -= 2;
} else {
customizer = typeof thisArg == 'function' ? thisArg : undefined;
length -= (customizer ? 1 : 0);
}
if (guard && isIterateeCall(sources[0], sources[1], guard)) {
customizer = length < 3 ? undefined : customizer;
length = 1;
}
while (++index < length) {
var source = sources[index];
if (source) {
assigner(object, source, customizer);
}
}
return object;
});
}
module.exports = createAssigner;
},{"lodash._bindcallback":23,"lodash._isiterateecall":24,"lodash.restparam":25}],23:[function(require,module,exports){
/**
* lodash 3.0.1 (Custom Build) <https://lodash.com/>
* Build: `lodash modern modularize exports="npm" -o ./`
* Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
* Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
* Available under MIT license <https://lodash.com/license>
*/
/**
* A specialized version of `baseCallback` which only supports `this` binding
* and specifying the number of arguments to provide to `func`.
*
* @private
* @param {Function} func The function to bind.
* @param {*} thisArg The `this` binding of `func`.
* @param {number} [argCount] The number of arguments to provide to `func`.
* @returns {Function} Returns the callback.
*/
function bindCallback(func, thisArg, argCount) {
if (typeof func != 'function') {
return identity;
}
if (thisArg === undefined) {
return func;
}
switch (argCount) {
case 1: return function(value) {
return func.call(thisArg, value);
};
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);
};
case 5: return function(value, other, key, object, source) {
return func.call(thisArg, value, other, key, object, source);
};
}
return function() {
return func.apply(thisArg, arguments);
};
}
/**
* This method returns the first argument provided to it.
*
* @static
* @memberOf _
* @category Utility
* @param {*} value Any value.
* @returns {*} Returns `value`.
* @example
*
* var object = { 'user': 'fred' };
*
* _.identity(object) === object;
* // => true
*/
function identity(value) {
return value;
}
module.exports = bindCallback;
},{}],24:[function(require,module,exports){
/**
* lodash 3.0.9 (Custom Build) <https://lodash.com/>
* Build: `lodash modern modularize exports="npm" -o ./`
* Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
* Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
* Available under MIT license <https://lodash.com/license>
*/
/** Used to detect unsigned integer values. */
var reIsUint = /^\d+$/;
/**
* Used as the [maximum length](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-number.max_safe_integer)
* of an array-like value.
*/
var MAX_SAFE_INTEGER = 9007199254740991;
/**
* The base implementation of `_.property` without support for deep paths.
*
* @private
* @param {string} key The key of the property to get.
* @returns {Function} Returns the new function.
*/
function baseProperty(key) {
return function(object) {
return object == null ? undefined : object[key];
};
}
/**
* Gets the "length" property value of `object`.
*
* **Note:** This function is used to avoid a [JIT bug](https://bugs.webkit.org/show_bug.cgi?id=142792)
* that affects Safari on at least iOS 8.1-8.3 ARM64.
*
* @private
* @param {Object} object The object to query.
* @returns {*} Returns the "length" value.
*/
var getLength = baseProperty('length');
/**
* Checks if `value` is array-like.
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is array-like, else `false`.
*/
function isArrayLike(value) {
return value != null && isLength(getLength(value));
}
/**
* Checks if `value` is a valid array-like index.
*
* @private
* @param {*} value The value to check.
* @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.
* @returns {boolean} Returns `true` if `value` is a valid index, else `false`.
*/
function isIndex(value, length) {
value = (typeof value == 'number' || reIsUint.test(value)) ? +value : -1;
length = length == null ? MAX_SAFE_INTEGER : length;
return value > -1 && value % 1 == 0 && value < length;
}
/**
* Checks if the provided arguments are from an iteratee call.
*
* @private
* @param {*} value The potential iteratee value argument.
* @param {*} index The potential iteratee index or key argument.
* @param {*} object The potential iteratee object argument.
* @returns {boolean} Returns `true` if the arguments are from an iteratee call, else `false`.
*/
function isIterateeCall(value, index, object) {
if (!isObject(object)) {
return false;
}
var type = typeof index;
if (type == 'number'
? (isArrayLike(object) && isIndex(index, object.length))
: (type == 'string' && index in object)) {
var other = object[index];
return value === value ? (value === other) : (other !== other);
}
return false;
}
/**
* Checks if `value` is a valid array-like length.
*
* **Note:** This function is based on [`ToLength`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength).
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
*/
function isLength(value) {
return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
}
/**
* Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`.
* (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
*
* @static
* @memberOf _
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is an object, else `false`.
* @example
*
* _.isObject({});
* // => true
*
* _.isObject([1, 2, 3]);
* // => true
*
* _.isObject(1);
* // => false
*/
function isObject(value) {
// Avoid a V8 JIT bug in Chrome 19-20.
// See https://code.google.com/p/v8/issues/detail?id=2291 for more details.
var type = typeof value;
return !!value && (type == 'object' || type == 'function');
}
module.exports = isIterateeCall;
},{}],25:[function(require,module,exports){
/**
* lodash 3.6.1 (Custom Build) <https://lodash.com/>
* Build: `lodash modern modularize exports="npm" -o ./`
* Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
* Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
* Available under MIT license <https://lodash.com/license>
*/
/** Used as the `TypeError` message for "Functions" methods. */
var FUNC_ERROR_TEXT = 'Expected a function';
/* Native method references for those with the same name as other `lodash` methods. */
var nativeMax = Math.max;
/**
* Creates a function that invokes `func` with the `this` binding of the
* created function and arguments from `start` and beyond provided as an array.
*
* **Note:** This method is based on the [rest parameter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters).
*
* @static
* @memberOf _
* @category Function
* @param {Function} func The function to apply a rest parameter to.
* @param {number} [start=func.length-1] The start position of the rest parameter.
* @returns {Function} Returns the new function.
* @example
*
* var say = _.restParam(function(what, names) {
* return what + ' ' + _.initial(names).join(', ') +
* (_.size(names) > 1 ? ', & ' : '') + _.last(names);
* });
*
* say('hello', 'fred', 'barney', 'pebbles');
* // => 'hello fred, barney, & pebbles'
*/
function restParam(func, start) {
if (typeof func != 'function') {
throw new TypeError(FUNC_ERROR_TEXT);
}
start = nativeMax(start === undefined ? (func.length - 1) : (+start || 0), 0);
return function() {
var args = arguments,
index = -1,
length = nativeMax(args.length - start, 0),
rest = Array(length);
while (++index < length) {
rest[index] = args[start + index];
}
switch (start) {
case 0: return func.call(this, rest);
case 1: return func.call(this, args[0], rest);
case 2: return func.call(this, args[0], args[1], rest);
}
var otherArgs = Array(start + 1);
index = -1;
while (++index < start) {
otherArgs[index] = args[index];
}
otherArgs[start] = rest;
return func.apply(this, otherArgs);
};
}
module.exports = restParam;
},{}],26:[function(require,module,exports){
/**
* lodash 3.1.2 (Custom Build) <https://lodash.com/>
* Build: `lodash modern modularize exports="npm" -o ./`
* Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
* Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
* Available under MIT license <https://lodash.com/license>
*/
var getNative = require('lodash._getnative'),
isArguments = require('lodash.isarguments'),
isArray = require('lodash.isarray');
/** Used to detect unsigned integer values. */
var reIsUint = /^\d+$/;
/** Used for native method references. */
var objectProto = Object.prototype;
/** Used to check objects for own properties. */
var hasOwnProperty = objectProto.hasOwnProperty;
/* Native method references for those with the same name as other `lodash` methods. */
var nativeKeys = getNative(Object, 'keys');
/**
* Used as the [maximum length](http://ecma-international.org/ecma-262/6.0/#sec-number.max_safe_integer)
* of an array-like value.
*/
var MAX_SAFE_INTEGER = 9007199254740991;
/**
* The base implementation of `_.property` without support for deep paths.
*
* @private
* @param {string} key The key of the property to get.
* @returns {Function} Returns the new function.
*/
function baseProperty(key) {
return function(object) {
return object == null ? undefined : object[key];
};
}
/**
* Gets the "length" property value of `object`.
*
* **Note:** This function is used to avoid a [JIT bug](https://bugs.webkit.org/show_bug.cgi?id=142792)
* that affects Safari on at least iOS 8.1-8.3 ARM64.
*
* @private
* @param {Object} object The object to query.
* @returns {*} Returns the "length" value.
*/
var getLength = baseProperty('length');
/**
* Checks if `value` is array-like.
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is array-like, else `false`.
*/
function isArrayLike(value) {
return value != null && isLength(getLength(value));
}
/**
* Checks if `value` is a valid array-like index.
*
* @private
* @param {*} value The value to check.
* @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.
* @returns {boolean} Returns `true` if `value` is a valid index, else `false`.
*/
function isIndex(value, length) {
value = (typeof value == 'number' || reIsUint.test(value)) ? +value : -1;
length = length == null ? MAX_SAFE_INTEGER : length;
return value > -1 && value % 1 == 0 && value < length;
}
/**
* Checks if `value` is a valid array-like length.
*
* **Note:** This function is based on [`ToLength`](http://ecma-international.org/ecma-262/6.0/#sec-tolength).
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
*/
function isLength(value) {
return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
}
/**
* A fallback implementation of `Object.keys` which creates an array of the
* own enumerable property names of `object`.
*
* @private
* @param {Object} object The object to query.
* @returns {Array} Returns the array of property names.
*/
function shimKeys(object) {
var props = keysIn(object),
propsLength = props.length,
length = propsLength && object.length;
var allowIndexes = !!length && isLength(length) &&
(isArray(object) || isArguments(object));
var index = -1,
result = [];
while (++index < propsLength) {
var key = props[index];
if ((allowIndexes && isIndex(key, length)) || hasOwnProperty.call(object, key)) {
result.push(key);
}
}
return result;
}
/**
* Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`.
* (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
*
* @static
* @memberOf _
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is an object, else `false`.
* @example
*
* _.isObject({});
* // => true
*
* _.isObject([1, 2, 3]);
* // => true
*
* _.isObject(1);
* // => false
*/
function isObject(value) {
// Avoid a V8 JIT bug in Chrome 19-20.
// See https://code.google.com/p/v8/issues/detail?id=2291 for more details.
var type = typeof value;
return !!value && (type == 'object' || type == 'function');
}
/**
* Creates an array of the own enumerable property names of `object`.
*
* **Note:** Non-object values are coerced to objects. See the
* [ES spec](http://ecma-international.org/ecma-262/6.0/#sec-object.keys)
* for more details.
*
* @static
* @memberOf _
* @category Object
* @param {Object} object The object to query.
* @returns {Array} Returns the array of property names.
* @example
*
* function Foo() {
* this.a = 1;
* this.b = 2;
* }
*
* Foo.prototype.c = 3;
*
* _.keys(new Foo);
* // => ['a', 'b'] (iteration order is not guaranteed)
*
* _.keys('hi');
* // => ['0', '1']
*/
var keys = !nativeKeys ? shimKeys : function(object) {
var Ctor = object == null ? undefined : object.constructor;
if ((typeof Ctor == 'function' && Ctor.prototype === object) ||
(typeof object != 'function' && isArrayLike(object))) {
return shimKeys(object);
}
return isObject(object) ? nativeKeys(object) : [];
};
/**
* Creates an array of the own and inherited enumerable property names of `object`.
*
* **Note:** Non-object values are coerced to objects.
*
* @static
* @memberOf _
* @category Object
* @param {Object} object The object to query.
* @returns {Array} Returns the array of property names.
* @example
*
* function Foo() {
* this.a = 1;
* this.b = 2;
* }
*
* Foo.prototype.c = 3;
*
* _.keysIn(new Foo);
* // => ['a', 'b', 'c'] (iteration order is not guaranteed)
*/
function keysIn(object) {
if (object == null) {
return [];
}
if (!isObject(object)) {
object = Object(object);
}
var length = object.length;
length = (length && isLength(length) &&
(isArray(object) || isArguments(object)) && length) || 0;
var Ctor = object.constructor,
index = -1,
isProto = typeof Ctor == 'function' && Ctor.prototype === object,
result = Array(length),
skipIndexes = length > 0;
while (++index < length) {
result[index] = (index + '');
}
for (var key in object) {
if (!(skipIndexes && isIndex(key, length)) &&
!(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) {
result.push(key);
}
}
return result;
}
module.exports = keys;
},{"lodash._getnative":27,"lodash.isarguments":28,"lodash.isarray":29}],27:[function(require,module,exports){
/**
* lodash 3.9.1 (Custom Build) <https://lodash.com/>
* Build: `lodash modern modularize exports="npm" -o ./`
* Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
* Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
* Available under MIT license <https://lodash.com/license>
*/
/** `Object#toString` result references. */
var funcTag = '[object Function]';
/** Used to detect host constructors (Safari > 5). */
var reIsHostCtor = /^\[object .+?Constructor\]$/;
/**
* Checks if `value` is object-like.
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is object-like, else `false`.
*/
function isObjectLike(value) {
return !!value && typeof value == 'object';
}
/** Used for native method references. */
var objectProto = Object.prototype;
/** Used to resolve the decompiled source of functions. */
var fnToString = Function.prototype.toString;
/** Used to check objects for own properties. */
var hasOwnProperty = objectProto.hasOwnProperty;
/**
* Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)
* of values.
*/
var objToString = objectProto.toString;
/** Used to detect if a method is native. */
var reIsNative = RegExp('^' +
fnToString.call(hasOwnProperty).replace(/[\\^$.*+?()[\]{}|]/g, '\\$&')
.replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
);
/**
* Gets the native function at `key` of `object`.
*
* @private
* @param {Object} object The object to query.
* @param {string} key The key of the method to get.
* @returns {*} Returns the function if it's native, else `undefined`.
*/
function getNative(object, key) {
var value = object == null ? undefined : object[key];
return isNative(value) ? value : undefined;
}
/**
* Checks if `value` is classified as a `Function` object.
*
* @static
* @memberOf _
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
* @example
*
* _.isFunction(_);
* // => true
*
* _.isFunction(/abc/);
* // => false
*/
function isFunction(value) {
// The use of `Object#toString` avoids issues with the `typeof` operator
// in older versions of Chrome and Safari which return 'function' for regexes
// and Safari 8 equivalents which return 'object' for typed array constructors.
return isObject(value) && objToString.call(value) == funcTag;
}
/**
* Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`.
* (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
*
* @static
* @memberOf _
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is an object, else `false`.
* @example
*
* _.isObject({});
* // => true
*
* _.isObject([1, 2, 3]);
* // => true
*
* _.isObject(1);
* // => false
*/
function isObject(value) {
// Avoid a V8 JIT bug in Chrome 19-20.
// See https://code.google.com/p/v8/issues/detail?id=2291 for more details.
var type = typeof value;
return !!value && (type == 'object' || type == 'function');
}
/**
* Checks if `value` is a native function.
*
* @static
* @memberOf _
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a native function, else `false`.
* @example
*
* _.isNative(Array.prototype.push);
* // => true
*
* _.isNative(_);
* // => false
*/
function isNative(value) {
if (value == null) {
return false;
}
if (isFunction(value)) {
return reIsNative.test(fnToString.call(value));
}
return isObjectLike(value) && reIsHostCtor.test(value);
}
module.exports = getNative;
},{}],28:[function(require,module,exports){
/**
* lodash 3.0.4 (Custom Build) <https://lodash.com/>
* Build: `lodash modern modularize exports="npm" -o ./`
* Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
* Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
* Available under MIT license <https://lodash.com/license>
*/
/**
* Checks if `value` is object-like.
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is object-like, else `false`.
*/
function isObjectLike(value) {
return !!value && typeof value == 'object';
}
/** Used for native method references. */
var objectProto = Object.prototype;
/** Used to check objects for own properties. */
var hasOwnProperty = objectProto.hasOwnProperty;
/** Native method references. */
var propertyIsEnumerable = objectProto.propertyIsEnumerable;
/**
* Used as the [maximum length](http://ecma-international.org/ecma-262/6.0/#sec-number.max_safe_integer)
* of an array-like value.
*/
var MAX_SAFE_INTEGER = 9007199254740991;
/**
* The base implementation of `_.property` without support for deep paths.
*
* @private
* @param {string} key The key of the property to get.
* @returns {Function} Returns the new function.
*/
function baseProperty(key) {
return function(object) {
return object == null ? undefined : object[key];
};
}
/**
* Gets the "length" property value of `object`.
*
* **Note:** This function is used to avoid a [JIT bug](https://bugs.webkit.org/show_bug.cgi?id=142792)
* that affects Safari on at least iOS 8.1-8.3 ARM64.
*
* @private
* @param {Object} object The object to query.
* @returns {*} Returns the "length" value.
*/
var getLength = baseProperty('length');
/**
* Checks if `value` is array-like.
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is array-like, else `false`.
*/
function isArrayLike(value) {
return value != null && isLength(getLength(value));
}
/**
* Checks if `value` is a valid array-like length.
*
* **Note:** This function is based on [`ToLength`](http://ecma-international.org/ecma-262/6.0/#sec-tolength).
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
*/
function isLength(value) {
return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
}
/**
* Checks if `value` is classified as an `arguments` object.
*
* @static
* @memberOf _
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
* @example
*
* _.isArguments(function() { return arguments; }());
* // => true
*
* _.isArguments([1, 2, 3]);
* // => false
*/
function isArguments(value) {
return isObjectLike(value) && isArrayLike(value) &&
hasOwnProperty.call(value, 'callee') && !propertyIsEnumerable.call(value, 'callee');
}
module.exports = isArguments;
},{}],29:[function(require,module,exports){
/**
* lodash 3.0.4 (Custom Build) <https://lodash.com/>
* Build: `lodash modern modularize exports="npm" -o ./`
* Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
* Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
* Available under MIT license <https://lodash.com/license>
*/
/** `Object#toString` result references. */
var arrayTag = '[object Array]',
funcTag = '[object Function]';
/** Used to detect host constructors (Safari > 5). */
var reIsHostCtor = /^\[object .+?Constructor\]$/;
/**
* Checks if `value` is object-like.
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is object-like, else `false`.
*/
function isObjectLike(value) {
return !!value && typeof value == 'object';
}
/** Used for native method references. */
var objectProto = Object.prototype;
/** Used to resolve the decompiled source of functions. */
var fnToString = Function.prototype.toString;
/** Used to check objects for own properties. */
var hasOwnProperty = objectProto.hasOwnProperty;
/**
* Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)
* of values.
*/
var objToString = objectProto.toString;
/** Used to detect if a method is native. */
var reIsNative = RegExp('^' +
fnToString.call(hasOwnProperty).replace(/[\\^$.*+?()[\]{}|]/g, '\\$&')
.replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
);
/* Native method references for those with the same name as other `lodash` methods. */
var nativeIsArray = getNative(Array, 'isArray');
/**
* Used as the [maximum length](http://ecma-international.org/ecma-262/6.0/#sec-number.max_safe_integer)
* of an array-like value.
*/
var MAX_SAFE_INTEGER = 9007199254740991;
/**
* Gets the native function at `key` of `object`.
*
* @private
* @param {Object} object The object to query.
* @param {string} key The key of the method to get.
* @returns {*} Returns the function if it's native, else `undefined`.
*/
function getNative(object, key) {
var value = object == null ? undefined : object[key];
return isNative(value) ? value : undefined;
}
/**
* Checks if `value` is a valid array-like length.
*
* **Note:** This function is based on [`ToLength`](http://ecma-international.org/ecma-262/6.0/#sec-tolength).
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
*/
function isLength(value) {
return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
}
/**
* Checks if `value` is classified as an `Array` object.
*
* @static
* @memberOf _
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
* @example
*
* _.isArray([1, 2, 3]);
* // => true
*
* _.isArray(function() { return arguments; }());
* // => false
*/
var isArray = nativeIsArray || function(value) {
return isObjectLike(value) && isLength(value.length) && objToString.call(value) == arrayTag;
};
/**
* Checks if `value` is classified as a `Function` object.
*
* @static
* @memberOf _
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
* @example
*
* _.isFunction(_);
* // => true
*
* _.isFunction(/abc/);
* // => false
*/
function isFunction(value) {
// The use of `Object#toString` avoids issues with the `typeof` operator
// in older versions of Chrome and Safari which return 'function' for regexes
// and Safari 8 equivalents which return 'object' for typed array constructors.
return isObject(value) && objToString.call(value) == funcTag;
}
/**
* Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`.
* (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
*
* @static
* @memberOf _
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is an object, else `false`.
* @example
*
* _.isObject({});
* // => true
*
* _.isObject([1, 2, 3]);
* // => true
*
* _.isObject(1);
* // => false
*/
function isObject(value) {
// Avoid a V8 JIT bug in Chrome 19-20.
// See https://code.google.com/p/v8/issues/detail?id=2291 for more details.
var type = typeof value;
return !!value && (type == 'object' || type == 'function');
}
/**
* Checks if `value` is a native function.
*
* @static
* @memberOf _
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a native function, else `false`.
* @example
*
* _.isNative(Array.prototype.push);
* // => true
*
* _.isNative(_);
* // => false
*/
function isNative(value) {
if (value == null) {
return false;
}
if (isFunction(value)) {
return reIsNative.test(fnToString.call(value));
}
return isObjectLike(value) && reIsHostCtor.test(value);
}
module.exports = isArray;
},{}],30:[function(require,module,exports){
/**
* lodash 3.1.0 (Custom Build) <https://lodash.com/>
* Build: `lodash modern modularize exports="npm" -o ./`
* Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
* Based on Underscore.js 1.8.2 <http://underscorejs.org/LICENSE>
* Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
* Available under MIT license <https://lodash.com/license>
*/
var createWrapper = require('lodash._createwrapper'),
replaceHolders = require('lodash._replaceholders'),
restParam = require('lodash.restparam');
/** Used to compose bitmasks for wrapper metadata. */
var BIND_FLAG = 1,
PARTIAL_FLAG = 32;
/**
* Creates a function that invokes `func` with the `this` binding of `thisArg`
* and prepends any additional `_.bind` arguments to those provided to the
* bound function.
*
* The `_.bind.placeholder` value, which defaults to `_` in monolithic builds,
* may be used as a placeholder for partially applied arguments.
*
* **Note:** Unlike native `Function#bind` this method does not set the `length`
* property of bound functions.
*
* @static
* @memberOf _
* @category Function
* @param {Function} func The function to bind.
* @param {*} thisArg The `this` binding of `func`.
* @param {...*} [partials] The arguments to be partially applied.
* @returns {Function} Returns the new bound function.
* @example
*
* var greet = function(greeting, punctuation) {
* return greeting + ' ' + this.user + punctuation;
* };
*
* var object = { 'user': 'fred' };
*
* var bound = _.bind(greet, object, 'hi');
* bound('!');
* // => 'hi fred!'
*
* // using placeholders
* var bound = _.bind(greet, object, _, '!');
* bound('hi');
* // => 'hi fred!'
*/
var bind = restParam(function(func, thisArg, partials) {
var bitmask = BIND_FLAG;
if (partials.length) {
var holders = replaceHolders(partials, bind.placeholder);
bitmask |= PARTIAL_FLAG;
}
return createWrapper(func, bitmask, thisArg, partials, holders);
});
// Assign default placeholders.
bind.placeholder = {};
module.exports = bind;
},{"lodash._createwrapper":31,"lodash._replaceholders":34,"lodash.restparam":35}],31:[function(require,module,exports){
(function (global){
/**
* lodash 3.0.7 (Custom Build) <https://lodash.com/>
* Build: `lodash modern modularize exports="npm" -o ./`
* Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
* Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
* Available under MIT license <https://lodash.com/license>
*/
var arrayCopy = require('lodash._arraycopy'),
baseCreate = require('lodash._basecreate'),
replaceHolders = require('lodash._replaceholders');
/** Used to compose bitmasks for wrapper metadata. */
var BIND_FLAG = 1,
BIND_KEY_FLAG = 2,
CURRY_BOUND_FLAG = 4,
CURRY_FLAG = 8,
CURRY_RIGHT_FLAG = 16,
PARTIAL_FLAG = 32,
PARTIAL_RIGHT_FLAG = 64,
ARY_FLAG = 128;
/** Used as the `TypeError` message for "Functions" methods. */
var FUNC_ERROR_TEXT = 'Expected a function';
/** Used to detect unsigned integer values. */
var reIsUint = /^\d+$/;
/* Native method references for those with the same name as other `lodash` methods. */
var nativeMax = Math.max,
nativeMin = Math.min;
/**
* Used as the [maximum length](http://ecma-international.org/ecma-262/6.0/#sec-number.max_safe_integer)
* of an array-like value.
*/
var MAX_SAFE_INTEGER = 9007199254740991;
/**
* Creates an array that is the composition of partially applied arguments,
* placeholders, and provided arguments into a single array of arguments.
*
* @private
* @param {Array|Object} args The provided arguments.
* @param {Array} partials The arguments to prepend to those provided.
* @param {Array} holders The `partials` placeholder indexes.
* @returns {Array} Returns the new array of composed arguments.
*/
function composeArgs(args, partials, holders) {
var holdersLength = holders.length,
argsIndex = -1,
argsLength = nativeMax(args.length - holdersLength, 0),
leftIndex = -1,
leftLength = partials.length,
result = Array(leftLength + argsLength);
while (++leftIndex < leftLength) {
result[leftIndex] = partials[leftIndex];
}
while (++argsIndex < holdersLength) {
result[holders[argsIndex]] = args[argsIndex];
}
while (argsLength--) {
result[leftIndex++] = args[argsIndex++];
}
return result;
}
/**
* This function is like `composeArgs` except that the arguments composition
* is tailored for `_.partialRight`.
*
* @private
* @param {Array|Object} args The provided arguments.
* @param {Array} partials The arguments to append to those provided.
* @param {Array} holders The `partials` placeholder indexes.
* @returns {Array} Returns the new array of composed arguments.
*/
function composeArgsRight(args, partials, holders) {
var holdersIndex = -1,
holdersLength = holders.length,
argsIndex = -1,
argsLength = nativeMax(args.length - holdersLength, 0),
rightIndex = -1,
rightLength = partials.length,
result = Array(argsLength + rightLength);
while (++argsIndex < argsLength) {
result[argsIndex] = args[argsIndex];
}
var offset = argsIndex;
while (++rightIndex < rightLength) {
result[offset + rightIndex] = partials[rightIndex];
}
while (++holdersIndex < holdersLength) {
result[offset + holders[holdersIndex]] = args[argsIndex++];
}
return result;
}
/**
* Creates a function that wraps `func` and invokes it with the `this`
* binding of `thisArg`.
*
* @private
* @param {Function} func The function to bind.
* @param {*} [thisArg] The `this` binding of `func`.
* @returns {Function} Returns the new bound function.
*/
function createBindWrapper(func, thisArg) {
var Ctor = createCtorWrapper(func);
function wrapper() {
var fn = (this && this !== global && this instanceof wrapper) ? Ctor : func;
return fn.apply(thisArg, arguments);
}
return wrapper;
}
/**
* Creates a function that produces an instance of `Ctor` regardless of
* whether it was invoked as part of a `new` expression or by `call` or `apply`.
*
* @private
* @param {Function} Ctor The constructor to wrap.
* @returns {Function} Returns the new wrapped function.
*/
function createCtorWrapper(Ctor) {
return function() {
// Use a `switch` statement to work with class constructors.
// See http://ecma-international.org/ecma-262/6.0/#sec-ecmascript-function-objects-call-thisargument-argumentslist
// for more details.
var args = arguments;
switch (args.length) {
case 0: return new Ctor;
case 1: return new Ctor(args[0]);
case 2: return new Ctor(args[0], args[1]);
case 3: return new Ctor(args[0], args[1], args[2]);
case 4: return new Ctor(args[0], args[1], args[2], args[3]);
case 5: return new Ctor(args[0], args[1], args[2], args[3], args[4]);
case 6: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5]);
case 7: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
}
var thisBinding = baseCreate(Ctor.prototype),
result = Ctor.apply(thisBinding, args);
// Mimic the constructor's `return` behavior.
// See https://es5.github.io/#x13.2.2 for more details.
return isObject(result) ? result : thisBinding;
};
}
/**
* Creates a function that wraps `func` and invokes it with optional `this`
* binding of, partial application, and currying.
*
* @private
* @param {Function|string} func The function or method name to reference.
* @param {number} bitmask The bitmask of flags. See `createWrapper` for more details.
* @param {*} [thisArg] The `this` binding of `func`.
* @param {Array} [partials] The arguments to prepend to those provided to the new function.
* @param {Array} [holders] The `partials` placeholder indexes.
* @param {Array} [partialsRight] The arguments to append to those provided to the new function.
* @param {Array} [holdersRight] The `partialsRight` placeholder indexes.
* @param {Array} [argPos] The argument positions of the new function.
* @param {number} [ary] The arity cap of `func`.
* @param {number} [arity] The arity of `func`.
* @returns {Function} Returns the new wrapped function.
*/
function createHybridWrapper(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) {
var isAry = bitmask & ARY_FLAG,
isBind = bitmask & BIND_FLAG,
isBindKey = bitmask & BIND_KEY_FLAG,
isCurry = bitmask & CURRY_FLAG,
isCurryBound = bitmask & CURRY_BOUND_FLAG,
isCurryRight = bitmask & CURRY_RIGHT_FLAG,
Ctor = isBindKey ? undefined : createCtorWrapper(func);
function wrapper() {
// Avoid `arguments` object use disqualifying optimizations by
// converting it to an array before providing it to other functions.
var length = arguments.length,
index = length,
args = Array(length);
while (index--) {
args[index] = arguments[index];
}
if (partials) {
args = composeArgs(args, partials, holders);
}
if (partialsRight) {
args = composeArgsRight(args, partialsRight, holdersRight);
}
if (isCurry || isCurryRight) {
var placeholder = wrapper.placeholder,
argsHolders = replaceHolders(args, placeholder);
length -= argsHolders.length;
if (length < arity) {
var newArgPos = argPos ? arrayCopy(argPos) : undefined,
newArity = nativeMax(arity - length, 0),
newsHolders = isCurry ? argsHolders : undefined,
newHoldersRight = isCurry ? undefined : argsHolders,
newPartials = isCurry ? args : undefined,
newPartialsRight = isCurry ? undefined : args;
bitmask |= (isCurry ? PARTIAL_FLAG : PARTIAL_RIGHT_FLAG);
bitmask &= ~(isCurry ? PARTIAL_RIGHT_FLAG : PARTIAL_FLAG);
if (!isCurryBound) {
bitmask &= ~(BIND_FLAG | BIND_KEY_FLAG);
}
var result = createHybridWrapper(func, bitmask, thisArg, newPartials, newsHolders, newPartialsRight, newHoldersRight, newArgPos, ary, newArity);
result.placeholder = placeholder;
return result;
}
}
var thisBinding = isBind ? thisArg : this,
fn = isBindKey ? thisBinding[func] : func;
if (argPos) {
args = reorder(args, argPos);
}
if (isAry && ary < args.length) {
args.length = ary;
}
if (this && this !== global && this instanceof wrapper) {
fn = Ctor || createCtorWrapper(func);
}
return fn.apply(thisBinding, args);
}
return wrapper;
}
/**
* Creates a function that wraps `func` and invokes it with the optional `this`
* binding of `thisArg` and the `partials` prepended to those provided to
* the wrapper.
*
* @private
* @param {Function} func The function to partially apply arguments to.
* @param {number} bitmask The bitmask of flags. See `createWrapper` for more details.
* @param {*} thisArg The `this` binding of `func`.
* @param {Array} partials The arguments to prepend to those provided to the new function.
* @returns {Function} Returns the new bound function.
*/
function createPartialWrapper(func, bitmask, thisArg, partials) {
var isBind = bitmask & BIND_FLAG,
Ctor = createCtorWrapper(func);
function wrapper() {
// Avoid `arguments` object use disqualifying optimizations by
// converting it to an array before providing it `func`.
var argsIndex = -1,
argsLength = arguments.length,
leftIndex = -1,
leftLength = partials.length,
args = Array(leftLength + argsLength);
while (++leftIndex < leftLength) {
args[leftIndex] = partials[leftIndex];
}
while (argsLength--) {
args[leftIndex++] = arguments[++argsIndex];
}
var fn = (this && this !== global && this instanceof wrapper) ? Ctor : func;
return fn.apply(isBind ? thisArg : this, args);
}
return wrapper;
}
/**
* Creates a function that either curries or invokes `func` with 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 flags.
* The bitmask may be composed of the following flags:
* 1 - `_.bind`
* 2 - `_.bindKey`
* 4 - `_.curry` or `_.curryRight` of a bound function
* 8 - `_.curry`
* 16 - `_.curryRight`
* 32 - `_.partial`
* 64 - `_.partialRight`
* 128 - `_.rearg`
* 256 - `_.ary`
* @param {*} [thisArg] The `this` binding of `func`.
* @param {Array} [partials] The arguments to be partially applied.
* @param {Array} [holders] The `partials` placeholder indexes.
* @param {Array} [argPos] The argument positions of the new function.
* @param {number} [ary] The arity cap of `func`.
* @param {number} [arity] The arity of `func`.
* @returns {Function} Returns the new wrapped function.
*/
function createWrapper(func, bitmask, thisArg, partials, holders, argPos, ary, arity) {
var isBindKey = bitmask & BIND_KEY_FLAG;
if (!isBindKey && typeof func != 'function') {
throw new TypeError(FUNC_ERROR_TEXT);
}
var length = partials ? partials.length : 0;
if (!length) {
bitmask &= ~(PARTIAL_FLAG | PARTIAL_RIGHT_FLAG);
partials = holders = undefined;
}
length -= (holders ? holders.length : 0);
if (bitmask & PARTIAL_RIGHT_FLAG) {
var partialsRight = partials,
holdersRight = holders;
partials = holders = undefined;
}
var newData = [func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity];
newData[9] = arity == null
? (isBindKey ? 0 : func.length)
: (nativeMax(arity - length, 0) || 0);
if (bitmask == BIND_FLAG) {
var result = createBindWrapper(newData[0], newData[2]);
} else if ((bitmask == PARTIAL_FLAG || bitmask == (BIND_FLAG | PARTIAL_FLAG)) && !newData[4].length) {
result = createPartialWrapper.apply(undefined, newData);
} else {
result = createHybridWrapper.apply(undefined, newData);
}
return result;
}
/**
* Checks if `value` is a valid array-like index.
*
* @private
* @param {*} value The value to check.
* @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.
* @returns {boolean} Returns `true` if `value` is a valid index, else `false`.
*/
function isIndex(value, length) {
value = (typeof value == 'number' || reIsUint.test(value)) ? +value : -1;
length = length == null ? MAX_SAFE_INTEGER : length;
return value > -1 && value % 1 == 0 && value < length;
}
/**
* Reorder `array` according to the specified indexes where the element at
* the first index is assigned as the first element, the element at
* the second index is assigned as the second element, and so on.
*
* @private
* @param {Array} array The array to reorder.
* @param {Array} indexes The arranged array indexes.
* @returns {Array} Returns `array`.
*/
function reorder(array, indexes) {
var arrLength = array.length,
length = nativeMin(indexes.length, arrLength),
oldArray = arrayCopy(array);
while (length--) {
var index = indexes[length];
array[length] = isIndex(index, arrLength) ? oldArray[index] : undefined;
}
return array;
}
/**
* Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`.
* (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
*
* @static
* @memberOf _
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is an object, else `false`.
* @example
*
* _.isObject({});
* // => true
*
* _.isObject([1, 2, 3]);
* // => true
*
* _.isObject(1);
* // => false
*/
function isObject(value) {
// Avoid a V8 JIT bug in Chrome 19-20.
// See https://code.google.com/p/v8/issues/detail?id=2291 for more details.
var type = typeof value;
return !!value && (type == 'object' || type == 'function');
}
module.exports = createWrapper;
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"lodash._arraycopy":32,"lodash._basecreate":33,"lodash._replaceholders":34}],32:[function(require,module,exports){
/**
* lodash 3.0.0 (Custom Build) <https://lodash.com/>
* Build: `lodash modern modularize exports="npm" -o ./`
* Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
* Based on Underscore.js 1.7.0 <http://underscorejs.org/LICENSE>
* Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
* Available under MIT license <https://lodash.com/license>
*/
/**
* Copies the values of `source` to `array`.
*
* @private
* @param {Array} source The array to copy values from.
* @param {Array} [array=[]] The array to copy values to.
* @returns {Array} Returns `array`.
*/
function arrayCopy(source, array) {
var index = -1,
length = source.length;
array || (array = Array(length));
while (++index < length) {
array[index] = source[index];
}
return array;
}
module.exports = arrayCopy;
},{}],33:[function(require,module,exports){
/**
* lodash 3.0.3 (Custom Build) <https://lodash.com/>
* Build: `lodash modern modularize exports="npm" -o ./`
* Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
* Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
* Available under MIT license <https://lodash.com/license>
*/
/**
* 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.
*/
var baseCreate = (function() {
function object() {}
return function(prototype) {
if (isObject(prototype)) {
object.prototype = prototype;
var result = new object;
object.prototype = undefined;
}
return result || {};
};
}());
/**
* Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`.
* (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
*
* @static
* @memberOf _
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is an object, else `false`.
* @example
*
* _.isObject({});
* // => true
*
* _.isObject([1, 2, 3]);
* // => true
*
* _.isObject(1);
* // => false
*/
function isObject(value) {
// Avoid a V8 JIT bug in Chrome 19-20.
// See https://code.google.com/p/v8/issues/detail?id=2291 for more details.
var type = typeof value;
return !!value && (type == 'object' || type == 'function');
}
module.exports = baseCreate;
},{}],34:[function(require,module,exports){
/**
* lodash 3.0.0 (Custom Build) <https://lodash.com/>
* Build: `lodash modern modularize exports="npm" -o ./`
* Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
* Based on Underscore.js 1.7.0 <http://underscorejs.org/LICENSE>
* Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
* Available under MIT license <https://lodash.com/license>
*/
/** Used as the internal argument placeholder. */
var PLACEHOLDER = '__lodash_placeholder__';
/**
* Replaces all `placeholder` elements in `array` with an internal placeholder
* and returns an array of their indexes.
*
* @private
* @param {Array} array The array to modify.
* @param {*} placeholder The placeholder to replace.
* @returns {Array} Returns the new array of placeholder indexes.
*/
function replaceHolders(array, placeholder) {
var index = -1,
length = array.length,
resIndex = -1,
result = [];
while (++index < length) {
if (array[index] === placeholder) {
array[index] = PLACEHOLDER;
result[++resIndex] = index;
}
}
return result;
}
module.exports = replaceHolders;
},{}],35:[function(require,module,exports){
arguments[4][25][0].apply(exports,arguments)
},{"dup":25}],36:[function(require,module,exports){
/**
* lodash 3.0.4 (Custom Build) <https://lodash.com/>
* Build: `lodash modern modularize exports="npm" -o ./`
* Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
* Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
* Available under MIT license <https://lodash.com/license>
*/
var isArguments = require('lodash.isarguments'),
isArray = require('lodash.isarray'),
isFunction = require('lodash.isfunction'),
isString = require('lodash.isstring'),
keys = require('lodash.keys');
/**
* Checks if `value` is object-like.
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is object-like, else `false`.
*/
function isObjectLike(value) {
return !!value && typeof value == 'object';
}
/**
* Used as the [maximum length](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-number.max_safe_integer)
* of an array-like value.
*/
var MAX_SAFE_INTEGER = 9007199254740991;
/**
* The base implementation of `_.property` without support for deep paths.
*
* @private
* @param {string} key The key of the property to get.
* @returns {Function} Returns the new function.
*/
function baseProperty(key) {
return function(object) {
return object == null ? undefined : object[key];
};
}
/**
* Gets the "length" property value of `object`.
*
* **Note:** This function is used to avoid a [JIT bug](https://bugs.webkit.org/show_bug.cgi?id=142792)
* that affects Safari on at least iOS 8.1-8.3 ARM64.
*
* @private
* @param {Object} object The object to query.
* @returns {*} Returns the "length" value.
*/
var getLength = baseProperty('length');
/**
* Checks if `value` is array-like.
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is array-like, else `false`.
*/
function isArrayLike(value) {
return value != null && isLength(getLength(value));
}
/**
* Checks if `value` is a valid array-like length.
*
* **Note:** This function is based on [`ToLength`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength).
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
*/
function isLength(value) {
return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
}
/**
* Checks if `value` is empty. A value is considered empty unless it is an
* `arguments` object, array, string, or jQuery-like collection with a length
* greater than `0` or an object with own enumerable properties.
*
* @static
* @memberOf _
* @category Lang
* @param {Array|Object|string} value The value to inspect.
* @returns {boolean} Returns `true` if `value` is empty, else `false`.
* @example
*
* _.isEmpty(null);
* // => true
*
* _.isEmpty(true);
* // => true
*
* _.isEmpty(1);
* // => true
*
* _.isEmpty([1, 2, 3]);
* // => false
*
* _.isEmpty({ 'a': 1 });
* // => false
*/
function isEmpty(value) {
if (value == null) {
return true;
}
if (isArrayLike(value) && (isArray(value) || isString(value) || isArguments(value) ||
(isObjectLike(value) && isFunction(value.splice)))) {
return !value.length;
}
return !keys(value).length;
}
module.exports = isEmpty;
},{"lodash.isarguments":37,"lodash.isarray":38,"lodash.isfunction":39,"lodash.isstring":40,"lodash.keys":41}],37:[function(require,module,exports){
arguments[4][28][0].apply(exports,arguments)
},{"dup":28}],38:[function(require,module,exports){
arguments[4][29][0].apply(exports,arguments)
},{"dup":29}],39:[function(require,module,exports){
/**
* lodash 3.0.6 (Custom Build) <https://lodash.com/>
* Build: `lodash modern modularize exports="npm" -o ./`
* Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
* Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
* Available under MIT license <https://lodash.com/license>
*/
/** `Object#toString` result references. */
var funcTag = '[object Function]';
/** Used for native method references. */
var objectProto = Object.prototype;
/**
* Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)
* of values.
*/
var objToString = objectProto.toString;
/**
* Checks if `value` is classified as a `Function` object.
*
* @static
* @memberOf _
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
* @example
*
* _.isFunction(_);
* // => true
*
* _.isFunction(/abc/);
* // => false
*/
function isFunction(value) {
// The use of `Object#toString` avoids issues with the `typeof` operator
// in older versions of Chrome and Safari which return 'function' for regexes
// and Safari 8 equivalents which return 'object' for typed array constructors.
return isObject(value) && objToString.call(value) == funcTag;
}
/**
* Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`.
* (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
*
* @static
* @memberOf _
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is an object, else `false`.
* @example
*
* _.isObject({});
* // => true
*
* _.isObject([1, 2, 3]);
* // => true
*
* _.isObject(1);
* // => false
*/
function isObject(value) {
// Avoid a V8 JIT bug in Chrome 19-20.
// See https://code.google.com/p/v8/issues/detail?id=2291 for more details.
var type = typeof value;
return !!value && (type == 'object' || type == 'function');
}
module.exports = isFunction;
},{}],40:[function(require,module,exports){
/**
* lodash 3.0.1 (Custom Build) <https://lodash.com/>
* Build: `lodash modern modularize exports="npm" -o ./`
* Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
* Based on Underscore.js 1.8.2 <http://underscorejs.org/LICENSE>
* Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
* Available under MIT license <https://lodash.com/license>
*/
/** `Object#toString` result references. */
var stringTag = '[object String]';
/**
* Checks if `value` is object-like.
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is object-like, else `false`.
*/
function isObjectLike(value) {
return !!value && typeof value == 'object';
}
/** Used for native method references. */
var objectProto = Object.prototype;
/**
* Used to resolve the [`toStringTag`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring)
* of values.
*/
var objToString = objectProto.toString;
/**
* Checks if `value` is classified as a `String` primitive or object.
*
* @static
* @memberOf _
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
* @example
*
* _.isString('abc');
* // => true
*
* _.isString(1);
* // => false
*/
function isString(value) {
return typeof value == 'string' || (isObjectLike(value) && objToString.call(value) == stringTag);
}
module.exports = isString;
},{}],41:[function(require,module,exports){
arguments[4][26][0].apply(exports,arguments)
},{"dup":26,"lodash._getnative":42,"lodash.isarguments":37,"lodash.isarray":38}],42:[function(require,module,exports){
arguments[4][27][0].apply(exports,arguments)
},{"dup":27}],43:[function(require,module,exports){
/**
* A dumb in-memory data store. Do not use in production.
* Only for demo purposes.
* @param {Object} cache
*/
var InMemoryDataAdapter = function(cache){
// `stores` all data
this.cache = cache || {};
};
/**
* Get the data specified by the id
* @param {String/Number} id ID for the requested data
* @param {Function} cb
*/
InMemoryDataAdapter.prototype.getData = function(id, cb){
var data = this.cache[id];
if(!data){
this.cache[id] = {};
}
cb(null, this.cache[id]);
};
/**
* Stores `data` at `id`
*/
InMemoryDataAdapter.prototype.storeData = function(id, data, cb){
this.cache[id] = data;
if(cb){ cb(null); }
};
module.exports = InMemoryDataAdapter;
},{}],44:[function(require,module,exports){
var assign = require('lodash.assign'),
bind = require('lodash.bind'),
isEmpty = require('lodash.isempty'),
EventEmitter = require('events').EventEmitter,
jsondiffpatch = require('jsondiffpatch'),
COMMANDS = require('./commands'),
utils = require('./utils'),
Client;
Client = function(socket, room, diffOptions){
if(!socket){ throw new Error('No socket specified'); }
if(!room){ room = ''; }
if(!diffOptions){ diffOptions = {}; }
this.socket = socket;
this.room = room;
this.syncing = false;
this.initialized = false;
this.scheduled = false;
this.doc = {
localVersion: 0,
serverVersion: 0,
shadow: {},
localCopy: {},
edits: []
};
// set up the jsondiffpatch options
// see here for options: https://github.com/benjamine/jsondiffpatch#options
diffOptions = assign({
objectHash: function(obj) { return obj.id || obj._id || JSON.stringify(obj); }
}, diffOptions);
this.jsondiffpatch = jsondiffpatch.create(diffOptions);
// let client be an EventEmitter
EventEmitter.call(this);
// bind functions
var methodsToBind = ['_onConnected', 'syncWithServer', 'applyServerEdit', 'applyServerEdits', 'schedule', 'onRemoteUpdate'],
method;
for(var index in methodsToBind){
method = methodsToBind[index];
this[method] = bind(this[method], this);
}
};
// inherit from EventEmitter
Client.prototype = new EventEmitter();
/**
* Get the data
* @return {Object} [description]
*/
Client.prototype.getData = function(){
return this.doc.localCopy;
};
/**
* Initializes the sync session
*/
Client.prototype.initialize = function(){
// connect, join room and initialize
this.syncing = true;
this.socket.emit(COMMANDS.join, this.room, this._onConnected);
};
/**
* Sets up the local version and listens to server updates
* Will notify the `onConnected` callback.
* @param {Object} initialVersion The initial version from the server
*/
Client.prototype._onConnected = function(initialVersion){
// client is not syncing anymore and is initialized
this.syncing = false;
this.initialized = true;
// set up shadow doc, local doc and initial server version
// IMPORTANT: the shadow needs to be a deep copy of the initial version
// because otherwise changes to the local object will also result in changes
// to the shadow object because they are pointing to the same doc
this.doc.shadow = utils.deepCopy(initialVersion);
this.doc.localCopy = initialVersion;
this.doc.serverVersion = 0;
// listen to incoming updates from the server
this.socket.on(COMMANDS.remoteUpdateIncoming, this.onRemoteUpdate);
// notify about established connection
this.emit('connected');
};
/**
* Handler for remote updates
* @param {String} fromId id from the socket that initiated the update
*/
Client.prototype.onRemoteUpdate = function(fromId){
// only schedule if the update was not initiated by this client
if(this.socket.id !== fromId){
this.schedule();
}
};
/**
* Schedule a sync cycle. This method should be used from the outside to
* trigger syncs.
*/
Client.prototype.schedule = function(){
// do nothing if already scheduled
if(this.scheduled){ return; }
this.scheduled = true;
// try to sync now
this.syncWithServer();
};
/**
* Alias function for `sync`
*/
Client.prototype.sync = function(){
this.schedule();
};
/**
* Starts a sync cycle. Should not be called from third parties
*/
Client.prototype.syncWithServer = function(){
if(this.syncing || !this.initialized){ return false; }
if(this.scheduled){ this.scheduled = false; }
// initiate syncing cycle
this.syncing = true;
// 1) create a diff of local copy and shadow
var diff = this.createDiff(this.doc.shadow, this.doc.localCopy);
var basedOnLocalVersion = this.doc.localVersion;
// 2) add the difference to the local edits stack if the diff is not empty
if(!isEmpty(diff)){
this.doc.edits.push(this.createDiffMessage(diff, basedOnLocalVersion));
this.doc.localVersion++;
}
// 3) create an edit message with all relevant version numbers
var editMessage = this.createEditMessage(basedOnLocalVersion);
// 4) apply the patch to the local shadow
this.applyPatchTo(this.doc.shadow, utils.deepCopy(diff));
// 5) send the edits to the server
this.sendEdits(editMessage);
// yes, we're syncing
return true;
};
/**
* Returns a diff of the passed documents
* @param {Object} docA
* @param {Object} docB
* @return {Diff} The diff of both documents
*/
Client.prototype.createDiff = function(docA, docB){
return this.jsondiffpatch.diff(docA, docB);
};
/**
* Applies the path to the specified object
* WARNING: The patch is applied in place!
* @param {Object} obj
* @param {Diff} patch
*/
Client.prototype.applyPatchTo = function(obj, patch){
this.jsondiffpatch.patch(obj, patch);
};
/**
* Creates a message for the specified diff
* @param {Diff} diff the diff that will be sent
* @param {Number} baseVersion the version of which the diff is based
* @return {Object} a diff message
*/
Client.prototype.createDiffMessage = function(diff, baseVersion){
return {
serverVersion: this.doc.serverVersion,
localVersion: baseVersion,
diff: diff
};
};
/**
* Creates a message representing a set of edits
* An edit message contains all edits since the last sync has happened.
* @param {Number} baseVersion The version that these edits are based on
* @return {Object} An edit message
*/
Client.prototype.createEditMessage = function(baseVersion){
return {
room: this.room,
edits: this.doc.edits,
localVersion: baseVersion,
serverVersion: this.doc.serverVersion
};
};
/**
* Send the the edits to the server and applies potential updates from the server
*/
Client.prototype.sendEdits = function(editMessage){
this.socket.emit(COMMANDS.syncWithServer, editMessage, this.applyServerEdits);
};
/**
* Applies all edits from the server and notfies about changes
* @param {Object} serverEdits The edits message
*/
Client.prototype.applyServerEdits = function(serverEdits){
if(serverEdits && serverEdits.localVersion === this.doc.localVersion){
// 0) delete all previous edits
this.doc.edits = [];
// 1) iterate over all edits
serverEdits.edits.forEach(this.applyServerEdit);
}else{
// Rejected patch because localVersions don't match
this.emit('error', 'REJECTED_PATCH');
}
// we are not syncing any more
this.syncing = false;
// notify about sync
this.emit('synced');
// if a sync has been scheduled, sync again
if(this.scheduled) {
this.syncWithServer();
}
};
/**
* Applies a single edit message to the local copy and the shadow
* @param {[type]} editMessage [description]
* @return {[type]} [description]
*/
Client.prototype.applyServerEdit = function(editMessage){
// 2) check the version numbers
if(editMessage.localVersion === this.doc.localVersion &&
editMessage.serverVersion === this.doc.serverVersion){
if(!isEmpty(editMessage.diff)){
// versions match
// 3) patch the shadow
this.applyPatchTo(this.doc.shadow, editMessage.diff);
// 4) increase the version number for the shadow if diff not empty
this.doc.serverVersion++;
// apply the patch to the local document
// IMPORTANT: Use a copy of the diff, or newly created objects will be copied by reference!
this.applyPatchTo(this.doc.localCopy, utils.deepCopy(editMessage.diff));
}
return true;
}else{
// TODO: check in the algo paper what should happen in the case of not matching version numbers
return false;
}
};
module.exports = Client;
},{"./commands":45,"./utils":47,"events":1,"jsondiffpatch":16,"lodash.assign":19,"lodash.bind":30,"lodash.isempty":36}],45:[function(require,module,exports){
module.exports = {
join: 'diffsync-join',
syncWithServer: 'diffsync-send-edit',
remoteUpdateIncoming: 'diffsync-updated-doc',
error: 'diffsync-error'
};
},{}],46:[function(require,module,exports){
var assign = require('lodash.assign'),
bind = require('lodash.bind'),
isEmpty = require('lodash.isempty'),
jsondiffpatch = require('jsondiffpatch'),
COMMANDS = require('./commands'),
utils = require('./utils'),
Server;
Server = function(adapter, transport, diffOptions){
if(!(adapter && transport)){ throw new Error('Need to specify an adapter and a transport'); }
if(!diffOptions){ diffOptions = {}; }
this.adapter = adapter;
this.transport = transport;
this.data = {};
this.requests = {};
this.saveRequests = {};
this.saveQueue = {};
// bind functions
this.trackConnection = bind(this.trackConnection, this);
// set up the jsondiffpatch options
// see here for options: https://github.com/benjamine/jsondiffpatch#options
diffOptions = assign({
objectHash: function(obj) { return obj.id || obj._id || JSON.stringify(obj); }
}, diffOptions);
this.jsondiffpatch = jsondiffpatch.create(diffOptions);
this.transport.on('connection', this.trackConnection);
};
/**
* Registers the correct event listeners
* @param {Connection} connection The connection that should get tracked
*/
Server.prototype.trackConnection = function(connection){
connection.on(COMMANDS.join, this.joinConnection.bind(this, connection));
connection.on(COMMANDS.syncWithServer, this.receiveEdit.bind(this, connection));
};
/**
* Joins a connection to a room and send the initial data
* @param {Connection} connection
* @param {String} room room identifier
* @param {Function} initializeClient Callback that is being used for initialization of the client
*/
Server.prototype.joinConnection = function(connection, room, initializeClient){
this.getData(room, function(error, data){
// connect to the room
connection.join(room);
// set up the client version for this socket
// each connection has a backup and a shadow
// and a set of edits
data.clientVersions[connection.id] = {
backup: {
doc: utils.deepCopy(data.serverCopy),
serverVersion: 0
},
shadow: {
doc: utils.deepCopy(data.serverCopy),
serverVersion: 0,
localVersion: 0
},
edits: []
};
// send the current server version
initializeClient(data.serverCopy);
});
};
/**
* Gets data for a room from the internal cache or from the adapter
* @param {String} room room identifier
* @param {Function} callback notifier-callback
*/
Server.prototype.getData = function(room, callback){
var cachedVersion = this.data[room],
cache = this.data,
requests = this.requests;
if(cachedVersion){
callback(null, cachedVersion);
}else{
// if there is no request for this room
// ask the adapter for the data
// do nothing in the else case because this operation
// should only happen once
if(!requests[room]){
requests[room] = true;
this.adapter.getData(room, function(error, data){
cache[room] = {
registeredSockets: [],
clientVersions: {},
serverCopy: data
};
requests[room] = false;
callback(null, cache[room]);
});
}else{
requests[room] = true;
}
}
};
/**
* Applies the sent edits to the shadow and the server copy, notifies all connected sockets and saves a snapshot
* @param {Object} connection The connection that sent the edits
* @param {Object} editMessage The message containing all edits
* @param {Function} sendToClient The callback that sends the server changes back to the client
*/
Server.prototype.receiveEdit = function(connection, editMessage, sendToClient){
// -1) The algorithm actually says we should use a checksum here, I don't think that's necessary
// 0) get the relevant doc
this.getData(editMessage.room, function(err, doc){
// 0.a) get the client versions
var clientDoc = doc.clientVersions[connection.id];
// no client doc could be found, client needs to re-auth
if(err || !clientDoc){
connection.emit(COMMANDS.error, 'Need to re-connect!');
return;
}
// when the versions match, remove old edits stack
if(editMessage.serverVersion === clientDoc.shadow.serverVersion){
clientDoc.edits = [];
}
// 1) iterate over all edits
editMessage.edits.forEach(function(edit){
// 2) check the version numbers
if(edit.serverVersion === clientDoc.shadow.serverVersion &&
edit.localVersion === clientDoc.shadow.localVersion){
// versions match
// backup! TODO: is this the right place to do that?
clientDoc.backup.doc = utils.deepCopy(clientDoc.shadow.doc);
// 3) patch the shadow
// var snapshot = utils.deepCopy(clientDoc.shadow.doc);
this.jsondiffpatch.patch(clientDoc.shadow.doc, utils.deepCopy(edit.diff));
// clientDoc.shadow.doc = snapshot;
// apply the patch to the server's document
// snapshot = utils.deepCopy(doc.serverCopy);
this.jsondiffpatch.patch(doc.serverCopy, utils.deepCopy(edit.diff));
// doc.serverCopy = snapshot;
// 3.a) increase the version number for the shadow if diff not empty
if(!isEmpty(edit.diff)){
clientDoc.shadow.localVersion++;
}
}else{
// TODO: implement backup workflow
// has a low priority since `packets are not lost` - but don't quote me on that :P
console.log('error', 'patch rejected!!', edit.serverVersion, '->', clientDoc.shadow.serverVersion, ':',
edit.localVersion, '->', clientDoc.shadow.localVersion);
}
}.bind(this));
// 4) save a snapshot of the document
this.saveSnapshot(editMessage.room);
// notify all sockets about the update, if not empty
if(editMessage.edits.length > 0){
this.transport.to(editMessage.room).emit(COMMANDS.remoteUpdateIncoming, connection.id);
}
this.sendServerChanges(doc, clientDoc, sendToClient);
}.bind(this));
};
Server.prototype.saveSnapshot = function(room){
var noRequestInProgress = !this.saveRequests[room],
checkQueueAndSaveAgain = function(){
// if another save request is in the queue, save again
var anotherRequestScheduled = this.saveQueue[room] === true;
this.saveRequests[room] = false;
if(anotherRequestScheduled){
this.saveQueue[room] = false;
this.saveSnapshot(room);
}
}.bind(this);
// only save if no save going on at the moment
if(noRequestInProgress){
this.saveRequests[room] = true;
// get data for saving
this.getData(room, function(err, data){
// store data
if(!err && data){
this.adapter.storeData(room, data.serverCopy, checkQueueAndSaveAgain);
}else{
checkQueueAndSaveAgain();
}
}.bind(this));
}else{
// schedule a new save request
this.saveQueue[room] = true;
}
};
Server.prototype.sendServerChanges = function(doc, clientDoc, send){
// create a diff from the current server version to the client's shadow
var diff = this.jsondiffpatch.diff(clientDoc.shadow.doc, doc.serverCopy);
var basedOnServerVersion = clientDoc.shadow.serverVersion;
// add the difference to the server's edit stack
if(!isEmpty(diff)){
clientDoc.edits.push({
serverVersion: basedOnServerVersion,
localVersion: clientDoc.shadow.localVersion,
diff: diff
});
// update the server version
clientDoc.shadow.serverVersion++;
// apply the patch to the server shadow
this.jsondiffpatch.patch(clientDoc.shadow.doc, utils.deepCopy(diff));
}
// we explicitly want empty diffs to get sent as well
send({
localVersion: clientDoc.shadow.localVersion,
serverVersion: basedOnServerVersion,
edits: clientDoc.edits
});
};
module.exports = Server;
},{"./commands":45,"./utils":47,"jsondiffpatch":16,"lodash.assign":19,"lodash.bind":30,"lodash.isempty":36}],47:[function(require,module,exports){
module.exports = {
deepCopy: function(obj){
if (obj === null || obj === undefined) {
return obj;
}
return JSON.parse(JSON.stringify(obj));
}
};
},{}]},{},[2])(2)
});