(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.crossfilter = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i
* Build: `lodash modularize exports="npm" -o ./`
* Copyright jQuery Foundation and other contributors
* Released under MIT license
* Based on Underscore.js 1.8.3
* Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
*/
/** Used as the `TypeError` message for "Functions" methods. */
var FUNC_ERROR_TEXT = 'Expected a function';
/** Used to stand-in for `undefined` hash values. */
var HASH_UNDEFINED = '__lodash_hash_undefined__';
/** Used as references for various `Number` constants. */
var INFINITY = 1 / 0;
/** `Object#toString` result references. */
var funcTag = '[object Function]',
genTag = '[object GeneratorFunction]',
symbolTag = '[object Symbol]';
/** Used to match property names within property paths. */
var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,
reIsPlainProp = /^\w*$/,
reLeadingDot = /^\./,
rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g;
/**
* Used to match `RegExp`
* [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).
*/
var reRegExpChar = /[\\^$.*+?()[\]{}|]/g;
/** Used to match backslashes in property paths. */
var reEscapeChar = /\\(\\)?/g;
/** Used to detect host constructors (Safari). */
var reIsHostCtor = /^\[object .+?Constructor\]$/;
/** Detect free variable `global` from Node.js. */
var freeGlobal = typeof global == 'object' && global && global.Object === Object && global;
/** Detect free variable `self`. */
var freeSelf = typeof self == 'object' && self && self.Object === Object && self;
/** Used as a reference to the global object. */
var root = freeGlobal || freeSelf || Function('return this')();
/**
* Gets the value at `key` of `object`.
*
* @private
* @param {Object} [object] The object to query.
* @param {string} key The key of the property to get.
* @returns {*} Returns the property value.
*/
function getValue(object, key) {
return object == null ? undefined : object[key];
}
/**
* Checks if `value` is a host object in IE < 9.
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a host object, else `false`.
*/
function isHostObject(value) {
// Many host objects are `Object` objects that can coerce to strings
// despite having improperly defined `toString` methods.
var result = false;
if (value != null && typeof value.toString != 'function') {
try {
result = !!(value + '');
} catch (e) {}
}
return result;
}
/** Used for built-in method references. */
var arrayProto = Array.prototype,
funcProto = Function.prototype,
objectProto = Object.prototype;
/** Used to detect overreaching core-js shims. */
var coreJsData = root['__core-js_shared__'];
/** Used to detect methods masquerading as native. */
var maskSrcKey = (function() {
var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || '');
return uid ? ('Symbol(src)_1.' + uid) : '';
}());
/** Used to resolve the decompiled source of functions. */
var funcToString = funcProto.toString;
/** Used to check objects for own properties. */
var hasOwnProperty = objectProto.hasOwnProperty;
/**
* Used to resolve the
* [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
* of values.
*/
var objectToString = objectProto.toString;
/** Used to detect if a method is native. */
var reIsNative = RegExp('^' +
funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&')
.replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
);
/** Built-in value references. */
var Symbol = root.Symbol,
splice = arrayProto.splice;
/* Built-in method references that are verified to be native. */
var Map = getNative(root, 'Map'),
nativeCreate = getNative(Object, 'create');
/** Used to convert symbols to primitives and strings. */
var symbolProto = Symbol ? Symbol.prototype : undefined,
symbolToString = symbolProto ? symbolProto.toString : undefined;
/**
* Creates a hash object.
*
* @private
* @constructor
* @param {Array} [entries] The key-value pairs to cache.
*/
function Hash(entries) {
var index = -1,
length = entries ? entries.length : 0;
this.clear();
while (++index < length) {
var entry = entries[index];
this.set(entry[0], entry[1]);
}
}
/**
* Removes all key-value entries from the hash.
*
* @private
* @name clear
* @memberOf Hash
*/
function hashClear() {
this.__data__ = nativeCreate ? nativeCreate(null) : {};
}
/**
* Removes `key` and its value from the hash.
*
* @private
* @name delete
* @memberOf Hash
* @param {Object} hash The hash to modify.
* @param {string} key The key of the value to remove.
* @returns {boolean} Returns `true` if the entry was removed, else `false`.
*/
function hashDelete(key) {
return this.has(key) && delete this.__data__[key];
}
/**
* Gets the hash value for `key`.
*
* @private
* @name get
* @memberOf Hash
* @param {string} key The key of the value to get.
* @returns {*} Returns the entry value.
*/
function hashGet(key) {
var data = this.__data__;
if (nativeCreate) {
var result = data[key];
return result === HASH_UNDEFINED ? undefined : result;
}
return hasOwnProperty.call(data, key) ? data[key] : undefined;
}
/**
* Checks if a hash value for `key` exists.
*
* @private
* @name has
* @memberOf Hash
* @param {string} key The key of the entry to check.
* @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
*/
function hashHas(key) {
var data = this.__data__;
return nativeCreate ? data[key] !== undefined : hasOwnProperty.call(data, key);
}
/**
* Sets the hash `key` to `value`.
*
* @private
* @name set
* @memberOf Hash
* @param {string} key The key of the value to set.
* @param {*} value The value to set.
* @returns {Object} Returns the hash instance.
*/
function hashSet(key, value) {
var data = this.__data__;
data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value;
return this;
}
// Add methods to `Hash`.
Hash.prototype.clear = hashClear;
Hash.prototype['delete'] = hashDelete;
Hash.prototype.get = hashGet;
Hash.prototype.has = hashHas;
Hash.prototype.set = hashSet;
/**
* Creates an list cache object.
*
* @private
* @constructor
* @param {Array} [entries] The key-value pairs to cache.
*/
function ListCache(entries) {
var index = -1,
length = entries ? entries.length : 0;
this.clear();
while (++index < length) {
var entry = entries[index];
this.set(entry[0], entry[1]);
}
}
/**
* Removes all key-value entries from the list cache.
*
* @private
* @name clear
* @memberOf ListCache
*/
function listCacheClear() {
this.__data__ = [];
}
/**
* Removes `key` and its value from the list cache.
*
* @private
* @name delete
* @memberOf ListCache
* @param {string} key The key of the value to remove.
* @returns {boolean} Returns `true` if the entry was removed, else `false`.
*/
function listCacheDelete(key) {
var data = this.__data__,
index = assocIndexOf(data, key);
if (index < 0) {
return false;
}
var lastIndex = data.length - 1;
if (index == lastIndex) {
data.pop();
} else {
splice.call(data, index, 1);
}
return true;
}
/**
* Gets the list cache value for `key`.
*
* @private
* @name get
* @memberOf ListCache
* @param {string} key The key of the value to get.
* @returns {*} Returns the entry value.
*/
function listCacheGet(key) {
var data = this.__data__,
index = assocIndexOf(data, key);
return index < 0 ? undefined : data[index][1];
}
/**
* Checks if a list cache value for `key` exists.
*
* @private
* @name has
* @memberOf ListCache
* @param {string} key The key of the entry to check.
* @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
*/
function listCacheHas(key) {
return assocIndexOf(this.__data__, key) > -1;
}
/**
* Sets the list cache `key` to `value`.
*
* @private
* @name set
* @memberOf ListCache
* @param {string} key The key of the value to set.
* @param {*} value The value to set.
* @returns {Object} Returns the list cache instance.
*/
function listCacheSet(key, value) {
var data = this.__data__,
index = assocIndexOf(data, key);
if (index < 0) {
data.push([key, value]);
} else {
data[index][1] = value;
}
return this;
}
// Add methods to `ListCache`.
ListCache.prototype.clear = listCacheClear;
ListCache.prototype['delete'] = listCacheDelete;
ListCache.prototype.get = listCacheGet;
ListCache.prototype.has = listCacheHas;
ListCache.prototype.set = listCacheSet;
/**
* Creates a map cache object to store key-value pairs.
*
* @private
* @constructor
* @param {Array} [entries] The key-value pairs to cache.
*/
function MapCache(entries) {
var index = -1,
length = entries ? entries.length : 0;
this.clear();
while (++index < length) {
var entry = entries[index];
this.set(entry[0], entry[1]);
}
}
/**
* Removes all key-value entries from the map.
*
* @private
* @name clear
* @memberOf MapCache
*/
function mapCacheClear() {
this.__data__ = {
'hash': new Hash,
'map': new (Map || ListCache),
'string': new Hash
};
}
/**
* Removes `key` and its value from the map.
*
* @private
* @name delete
* @memberOf MapCache
* @param {string} key The key of the value to remove.
* @returns {boolean} Returns `true` if the entry was removed, else `false`.
*/
function mapCacheDelete(key) {
return getMapData(this, key)['delete'](key);
}
/**
* Gets the map value for `key`.
*
* @private
* @name get
* @memberOf MapCache
* @param {string} key The key of the value to get.
* @returns {*} Returns the entry value.
*/
function mapCacheGet(key) {
return getMapData(this, key).get(key);
}
/**
* Checks if a map value for `key` exists.
*
* @private
* @name has
* @memberOf MapCache
* @param {string} key The key of the entry to check.
* @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
*/
function mapCacheHas(key) {
return getMapData(this, key).has(key);
}
/**
* Sets the map `key` to `value`.
*
* @private
* @name set
* @memberOf MapCache
* @param {string} key The key of the value to set.
* @param {*} value The value to set.
* @returns {Object} Returns the map cache instance.
*/
function mapCacheSet(key, value) {
getMapData(this, key).set(key, value);
return this;
}
// Add methods to `MapCache`.
MapCache.prototype.clear = mapCacheClear;
MapCache.prototype['delete'] = mapCacheDelete;
MapCache.prototype.get = mapCacheGet;
MapCache.prototype.has = mapCacheHas;
MapCache.prototype.set = mapCacheSet;
/**
* Gets the index at which the `key` is found in `array` of key-value pairs.
*
* @private
* @param {Array} array The array to inspect.
* @param {*} key The key to search for.
* @returns {number} Returns the index of the matched value, else `-1`.
*/
function assocIndexOf(array, key) {
var length = array.length;
while (length--) {
if (eq(array[length][0], key)) {
return length;
}
}
return -1;
}
/**
* The base implementation of `_.isNative` without bad shim checks.
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a native function,
* else `false`.
*/
function baseIsNative(value) {
if (!isObject(value) || isMasked(value)) {
return false;
}
var pattern = (isFunction(value) || isHostObject(value)) ? reIsNative : reIsHostCtor;
return pattern.test(toSource(value));
}
/**
* The base implementation of `_.toString` which doesn't convert nullish
* values to empty strings.
*
* @private
* @param {*} value The value to process.
* @returns {string} Returns the string.
*/
function baseToString(value) {
// Exit early for strings to avoid a performance hit in some environments.
if (typeof value == 'string') {
return value;
}
if (isSymbol(value)) {
return symbolToString ? symbolToString.call(value) : '';
}
var result = (value + '');
return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;
}
/**
* Casts `value` to a path array if it's not one.
*
* @private
* @param {*} value The value to inspect.
* @returns {Array} Returns the cast property path array.
*/
function castPath(value) {
return isArray(value) ? value : stringToPath(value);
}
/**
* Gets the data for `map`.
*
* @private
* @param {Object} map The map to query.
* @param {string} key The reference key.
* @returns {*} Returns the map data.
*/
function getMapData(map, key) {
var data = map.__data__;
return isKeyable(key)
? data[typeof key == 'string' ? 'string' : 'hash']
: data.map;
}
/**
* 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 = getValue(object, key);
return baseIsNative(value) ? value : undefined;
}
/**
* Checks if `value` is a property name and not a property path.
*
* @private
* @param {*} value The value to check.
* @param {Object} [object] The object to query keys on.
* @returns {boolean} Returns `true` if `value` is a property name, else `false`.
*/
function isKey(value, object) {
if (isArray(value)) {
return false;
}
var type = typeof value;
if (type == 'number' || type == 'symbol' || type == 'boolean' ||
value == null || isSymbol(value)) {
return true;
}
return reIsPlainProp.test(value) || !reIsDeepProp.test(value) ||
(object != null && value in Object(object));
}
/**
* Checks if `value` is suitable for use as unique object key.
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is suitable, else `false`.
*/
function isKeyable(value) {
var type = typeof value;
return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')
? (value !== '__proto__')
: (value === null);
}
/**
* Checks if `func` has its source masked.
*
* @private
* @param {Function} func The function to check.
* @returns {boolean} Returns `true` if `func` is masked, else `false`.
*/
function isMasked(func) {
return !!maskSrcKey && (maskSrcKey in func);
}
/**
* Converts `string` to a property path array.
*
* @private
* @param {string} string The string to convert.
* @returns {Array} Returns the property path array.
*/
var stringToPath = memoize(function(string) {
string = toString(string);
var result = [];
if (reLeadingDot.test(string)) {
result.push('');
}
string.replace(rePropName, function(match, number, quote, string) {
result.push(quote ? string.replace(reEscapeChar, '$1') : (number || match));
});
return result;
});
/**
* Converts `value` to a string key if it's not a string or symbol.
*
* @private
* @param {*} value The value to inspect.
* @returns {string|symbol} Returns the key.
*/
function toKey(value) {
if (typeof value == 'string' || isSymbol(value)) {
return value;
}
var result = (value + '');
return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;
}
/**
* Converts `func` to its source code.
*
* @private
* @param {Function} func The function to process.
* @returns {string} Returns the source code.
*/
function toSource(func) {
if (func != null) {
try {
return funcToString.call(func);
} catch (e) {}
try {
return (func + '');
} catch (e) {}
}
return '';
}
/**
* Creates a function that memoizes the result of `func`. If `resolver` is
* provided, it determines the cache key for storing the result based on the
* arguments provided to the memoized function. By default, the first argument
* provided to the memoized function is used as the map cache key. The `func`
* is invoked with the `this` binding of the memoized function.
*
* **Note:** The cache is exposed as the `cache` property on the memoized
* function. Its creation may be customized by replacing the `_.memoize.Cache`
* constructor with one whose instances implement the
* [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object)
* method interface of `delete`, `get`, `has`, and `set`.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Function
* @param {Function} func The function to have its output memoized.
* @param {Function} [resolver] The function to resolve the cache key.
* @returns {Function} Returns the new memoized function.
* @example
*
* var object = { 'a': 1, 'b': 2 };
* var other = { 'c': 3, 'd': 4 };
*
* var values = _.memoize(_.values);
* values(object);
* // => [1, 2]
*
* values(other);
* // => [3, 4]
*
* object.a = 2;
* values(object);
* // => [1, 2]
*
* // Modify the result cache.
* values.cache.set(object, ['a', 'b']);
* values(object);
* // => ['a', 'b']
*
* // Replace `_.memoize.Cache`.
* _.memoize.Cache = WeakMap;
*/
function memoize(func, resolver) {
if (typeof func != 'function' || (resolver && typeof resolver != 'function')) {
throw new TypeError(FUNC_ERROR_TEXT);
}
var memoized = function() {
var args = arguments,
key = resolver ? resolver.apply(this, args) : args[0],
cache = memoized.cache;
if (cache.has(key)) {
return cache.get(key);
}
var result = func.apply(this, args);
memoized.cache = cache.set(key, result);
return result;
};
memoized.cache = new (memoize.Cache || MapCache);
return memoized;
}
// Assign cache to `_.memoize`.
memoize.Cache = MapCache;
/**
* Performs a
* [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
* comparison between two values to determine if they are equivalent.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Lang
* @param {*} value The value to compare.
* @param {*} other The other value to compare.
* @returns {boolean} Returns `true` if the values are equivalent, else `false`.
* @example
*
* var object = { 'a': 1 };
* var other = { 'a': 1 };
*
* _.eq(object, object);
* // => true
*
* _.eq(object, other);
* // => false
*
* _.eq('a', 'a');
* // => true
*
* _.eq('a', Object('a'));
* // => false
*
* _.eq(NaN, NaN);
* // => true
*/
function eq(value, other) {
return value === other || (value !== value && other !== other);
}
/**
* Checks if `value` is classified as an `Array` object.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is an array, else `false`.
* @example
*
* _.isArray([1, 2, 3]);
* // => true
*
* _.isArray(document.body.children);
* // => false
*
* _.isArray('abc');
* // => false
*
* _.isArray(_.noop);
* // => false
*/
var isArray = Array.isArray;
/**
* Checks if `value` is classified as a `Function` object.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a function, else `false`.
* @example
*
* _.isFunction(_);
* // => true
*
* _.isFunction(/abc/);
* // => false
*/
function isFunction(value) {
// The use of `Object#toString` avoids issues with the `typeof` operator
// in Safari 8-9 which returns 'object' for typed array and other constructors.
var tag = isObject(value) ? objectToString.call(value) : '';
return tag == funcTag || tag == genTag;
}
/**
* Checks if `value` is the
* [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
* of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
*
* @static
* @memberOf _
* @since 0.1.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is an object, else `false`.
* @example
*
* _.isObject({});
* // => true
*
* _.isObject([1, 2, 3]);
* // => true
*
* _.isObject(_.noop);
* // => true
*
* _.isObject(null);
* // => false
*/
function isObject(value) {
var type = typeof value;
return !!value && (type == 'object' || type == 'function');
}
/**
* Checks if `value` is object-like. A value is object-like if it's not `null`
* and has a `typeof` result of "object".
*
* @static
* @memberOf _
* @since 4.0.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is object-like, else `false`.
* @example
*
* _.isObjectLike({});
* // => true
*
* _.isObjectLike([1, 2, 3]);
* // => true
*
* _.isObjectLike(_.noop);
* // => false
*
* _.isObjectLike(null);
* // => false
*/
function isObjectLike(value) {
return !!value && typeof value == 'object';
}
/**
* Checks if `value` is classified as a `Symbol` primitive or object.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
* @example
*
* _.isSymbol(Symbol.iterator);
* // => true
*
* _.isSymbol('abc');
* // => false
*/
function isSymbol(value) {
return typeof value == 'symbol' ||
(isObjectLike(value) && objectToString.call(value) == symbolTag);
}
/**
* Converts `value` to a string. An empty string is returned for `null`
* and `undefined` values. The sign of `-0` is preserved.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Lang
* @param {*} value The value to process.
* @returns {string} Returns the string.
* @example
*
* _.toString(null);
* // => ''
*
* _.toString(-0);
* // => '-0'
*
* _.toString([1, 2, 3]);
* // => '1,2,3'
*/
function toString(value) {
return value == null ? '' : baseToString(value);
}
/**
* This method is like `_.get` except that if the resolved value is a
* function it's invoked with the `this` binding of its parent object and
* its result is returned.
*
* @static
* @since 0.1.0
* @memberOf _
* @category Object
* @param {Object} object The object to query.
* @param {Array|string} path The path of the property to resolve.
* @param {*} [defaultValue] The value returned for `undefined` resolved values.
* @returns {*} Returns the resolved value.
* @example
*
* var object = { 'a': [{ 'b': { 'c1': 3, 'c2': _.constant(4) } }] };
*
* _.result(object, 'a[0].b.c1');
* // => 3
*
* _.result(object, 'a[0].b.c2');
* // => 4
*
* _.result(object, 'a[0].b.c3', 'default');
* // => 'default'
*
* _.result(object, 'a[0].b.c3', _.constant('default'));
* // => 'default'
*/
function result(object, path, defaultValue) {
path = isKey(path, object) ? [path] : castPath(path);
var index = -1,
length = path.length;
// Ensure the loop is entered when path is empty.
if (!length) {
object = undefined;
length = 1;
}
while (++index < length) {
var value = object == null ? undefined : object[toKey(path[index])];
if (value === undefined) {
index = length;
value = defaultValue;
}
object = isFunction(value) ? value.call(object) : value;
}
return object;
}
module.exports = result;
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{}],3:[function(require,module,exports){
module.exports={"version":"1.4.6"}
},{}],4:[function(require,module,exports){
if (typeof Uint8Array !== "undefined") {
var crossfilter_array8 = function(n) { return new Uint8Array(n); };
var crossfilter_array16 = function(n) { return new Uint16Array(n); };
var crossfilter_array32 = function(n) { return new Uint32Array(n); };
var crossfilter_arrayLengthen = function(array, length) {
if (array.length >= length) return array;
var copy = new array.constructor(length);
copy.set(array);
return copy;
};
var crossfilter_arrayWiden = function(array, width) {
var copy;
switch (width) {
case 16: copy = crossfilter_array16(array.length); break;
case 32: copy = crossfilter_array32(array.length); break;
default: throw new Error("invalid array width!");
}
copy.set(array);
return copy;
};
}
function crossfilter_arrayUntyped(n) {
var array = new Array(n), i = -1;
while (++i < n) array[i] = 0;
return array;
}
function crossfilter_arrayLengthenUntyped(array, length) {
var n = array.length;
while (n < length) array[n++] = 0;
return array;
}
function crossfilter_arrayWidenUntyped(array, width) {
if (width > 32) throw new Error("invalid array width!");
return array;
}
// An arbitrarily-wide array of bitmasks
function crossfilter_bitarray(n) {
this.length = n;
this.subarrays = 1;
this.width = 8;
this.masks = {
0: 0
}
this[0] = crossfilter_array8(n);
}
crossfilter_bitarray.prototype.lengthen = function(n) {
var i, len;
for (i = 0, len = this.subarrays; i < len; ++i) {
this[i] = crossfilter_arrayLengthen(this[i], n);
}
this.length = n;
};
// Reserve a new bit index in the array, returns {offset, one}
crossfilter_bitarray.prototype.add = function() {
var m, w, one, i, len;
for (i = 0, len = this.subarrays; i < len; ++i) {
m = this.masks[i];
w = this.width - (32 * i);
one = ~m & -~m;
if (w >= 32 && !one) {
continue;
}
if (w < 32 && (one & (1 << w))) {
// widen this subarray
this[i] = crossfilter_arrayWiden(this[i], w <<= 1);
this.width = 32 * i + w;
}
this.masks[i] |= one;
return {
offset: i,
one: one
};
}
// add a new subarray
this[this.subarrays] = crossfilter_array8(this.length);
this.masks[this.subarrays] = 1;
this.width += 8;
return {
offset: this.subarrays++,
one: 1
};
};
// Copy record from index src to index dest
crossfilter_bitarray.prototype.copy = function(dest, src) {
var i, len;
for (i = 0, len = this.subarrays; i < len; ++i) {
this[i][dest] = this[i][src];
}
};
// Truncate the array to the given length
crossfilter_bitarray.prototype.truncate = function(n) {
var i, len;
for (i = 0, len = this.subarrays; i < len; ++i) {
for (var j = this.length - 1; j >= n; j--) {
this[i][j] = 0;
}
this[i].length = n;
}
this.length = n;
};
// Checks that all bits for the given index are 0
crossfilter_bitarray.prototype.zero = function(n) {
var i, len;
for (i = 0, len = this.subarrays; i < len; ++i) {
if (this[i][n]) {
return false;
}
}
return true;
};
// Checks that all bits for the given index are 0 except for possibly one
crossfilter_bitarray.prototype.zeroExcept = function(n, offset, zero) {
var i, len;
for (i = 0, len = this.subarrays; i < len; ++i) {
if (i === offset ? this[i][n] & zero : this[i][n]) {
return false;
}
}
return true;
};
// Checks that all bits for the given indez are 0 except for the specified mask.
// The mask should be an array of the same size as the filter subarrays width.
crossfilter_bitarray.prototype.zeroExceptMask = function(n, mask) {
var i, len;
for (i = 0, len = this.subarrays; i < len; ++i) {
if (this[i][n] & mask[i]) {
return false;
}
}
return true;
}
// Checks that only the specified bit is set for the given index
crossfilter_bitarray.prototype.only = function(n, offset, one) {
var i, len;
for (i = 0, len = this.subarrays; i < len; ++i) {
if (this[i][n] != (i === offset ? one : 0)) {
return false;
}
}
return true;
};
// Checks that only the specified bit is set for the given index except for possibly one other
crossfilter_bitarray.prototype.onlyExcept = function(n, offset, zero, onlyOffset, onlyOne) {
var mask;
var i, len;
for (i = 0, len = this.subarrays; i < len; ++i) {
mask = this[i][n];
if (i === offset)
mask &= zero;
if (mask != (i === onlyOffset ? onlyOne : 0)) {
return false;
}
}
return true;
};
module.exports = {
array8: crossfilter_arrayUntyped,
array16: crossfilter_arrayUntyped,
array32: crossfilter_arrayUntyped,
arrayLengthen: crossfilter_arrayLengthenUntyped,
arrayWiden: crossfilter_arrayWidenUntyped,
bitarray: crossfilter_bitarray
};
},{}],5:[function(require,module,exports){
'use strict';
var crossfilter_identity = require('./identity');
function bisect_by(f) {
// Locate the insertion point for x in a to maintain sorted order. The
// arguments lo and hi may be used to specify a subset of the array which
// should be considered; by default the entire array is used. If x is already
// present in a, the insertion point will be before (to the left of) any
// existing entries. The return value is suitable for use as the first
// argument to `array.splice` assuming that a is already sorted.
//
// The returned insertion point i partitions the array a into two halves so
// that all v < x for v in a[lo:i] for the left side and all v >= x for v in
// a[i:hi] for the right side.
function bisectLeft(a, x, lo, hi) {
while (lo < hi) {
var mid = lo + hi >>> 1;
if (f(a[mid]) < x) lo = mid + 1;
else hi = mid;
}
return lo;
}
// Similar to bisectLeft, but returns an insertion point which comes after (to
// the right of) any existing entries of x in a.
//
// The returned insertion point i partitions the array into two halves so that
// all v <= x for v in a[lo:i] for the left side and all v > x for v in
// a[i:hi] for the right side.
function bisectRight(a, x, lo, hi) {
while (lo < hi) {
var mid = lo + hi >>> 1;
if (x < f(a[mid])) hi = mid;
else lo = mid + 1;
}
return lo;
}
bisectRight.right = bisectRight;
bisectRight.left = bisectLeft;
return bisectRight;
}
module.exports = bisect_by(crossfilter_identity);
module.exports.by = bisect_by; // assign the raw function to the export as well
},{"./identity":10}],6:[function(require,module,exports){
'use strict';
var xfilterArray = require('./array');
var xfilterFilter = require('./filter');
var crossfilter_identity = require('./identity');
var crossfilter_null = require('./null');
var crossfilter_zero = require('./zero');
var xfilterHeapselect = require('./heapselect');
var xfilterHeap = require('./heap');
var bisect = require('./bisect');
var insertionsort = require('./insertionsort');
var permute = require('./permute');
var quicksort = require('./quicksort');
var xfilterReduce = require('./reduce');
var packageJson = require('./../package.json'); // require own package.json for the version field
var result = require('lodash.result');
// constants
var REMOVED_INDEX = -1;
// expose API exports
exports.crossfilter = crossfilter;
exports.crossfilter.heap = xfilterHeap;
exports.crossfilter.heapselect = xfilterHeapselect;
exports.crossfilter.bisect = bisect;
exports.crossfilter.insertionsort = insertionsort;
exports.crossfilter.permute = permute;
exports.crossfilter.quicksort = quicksort;
exports.crossfilter.version = packageJson.version; // please note use of "package-json-versionify" transform
function crossfilter() {
var crossfilter = {
add: add,
remove: removeData,
dimension: dimension,
groupAll: groupAll,
size: size,
all: all,
allFiltered: allFiltered,
onChange: onChange,
isElementFiltered: isElementFiltered
};
var data = [], // the records
n = 0, // the number of records; data.length
filters, // 1 is filtered out
filterListeners = [], // when the filters change
dataListeners = [], // when data is added
removeDataListeners = [], // when data is removed
callbacks = [];
filters = new xfilterArray.bitarray(0);
// Adds the specified new records to this crossfilter.
function add(newData) {
var n0 = n,
n1 = newData.length;
// If there's actually new data to add…
// Merge the new data into the existing data.
// Lengthen the filter bitset to handle the new records.
// Notify listeners (dimensions and groups) that new data is available.
if (n1) {
data = data.concat(newData);
filters.lengthen(n += n1);
dataListeners.forEach(function(l) { l(newData, n0, n1); });
triggerOnChange('dataAdded');
}
return crossfilter;
}
// Removes all records that match the current filters, or if a predicate function is passed,
// removes all records matching the predicate (ignoring filters).
function removeData(predicate) {
var // Mapping from old record indexes to new indexes (after records removed)
newIndex = crossfilter_index(n, n),
removed = [],
usePred = typeof predicate === 'function',
shouldRemove = function (i) {
return usePred ? predicate(data[i], i) : filters.zero(i)
};
for (var index1 = 0, index2 = 0; index1 < n; ++index1) {
if ( shouldRemove(index1) ) {
removed.push(index1);
newIndex[index1] = REMOVED_INDEX;
} else {
newIndex[index1] = index2++;
}
}
// Remove all matching records from groups.
filterListeners.forEach(function(l) { l(-1, -1, [], removed, true); });
// Update indexes.
removeDataListeners.forEach(function(l) { l(newIndex); });
// Remove old filters and data by overwriting.
for (var index3 = 0, index4 = 0; index3 < n; ++index3) {
if ( newIndex[index3] !== REMOVED_INDEX ) {
if (index3 !== index4) filters.copy(index4, index3), data[index4] = data[index3];
++index4;
}
}
data.length = n = index4;
filters.truncate(index4);
triggerOnChange('dataRemoved');
}
function maskForDimensions(dimensions) {
var n,
d,
len,
id,
mask = Array(filters.subarrays);
for (n = 0; n < filters.subarrays; n++) { mask[n] = ~0; }
for (d = 0, len = dimensions.length; d < len; d++) {
// The top bits of the ID are the subarray offset and the lower bits are the bit
// offset of the "one" mask.
id = dimensions[d].id();
mask[id >> 7] &= ~(0x1 << (id & 0x3f));
}
return mask;
}
// Return true if the data element at index i is filtered IN.
// Optionally, ignore the filters of any dimensions in the ignore_dimensions list.
function isElementFiltered(i, ignore_dimensions) {
var mask = maskForDimensions(ignore_dimensions || []);
return filters.zeroExceptMask(i,mask);
}
// Adds a new dimension with the specified value accessor function.
function dimension(value, iterable) {
if (typeof value === 'string') {
var accessorPath = value;
value = function(d) { return result(d, accessorPath); };
}
var dimension = {
filter: filter,
filterExact: filterExact,
filterRange: filterRange,
filterFunction: filterFunction,
filterAll: filterAll,
currentFilter: currentFilter,
hasCurrentFilter: hasCurrentFilter,
top: top,
bottom: bottom,
group: group,
groupAll: groupAll,
dispose: dispose,
remove: dispose, // for backwards-compatibility
accessor: value,
id: function() { return id; }
};
var one, // lowest unset bit as mask, e.g., 00001000
zero, // inverted one, e.g., 11110111
offset, // offset into the filters arrays
id, // unique ID for this dimension (reused when dimensions are disposed)
values, // sorted, cached array
index, // maps sorted value index -> record index (in data)
newValues, // temporary array storing newly-added values
newIndex, // temporary array storing newly-added index
iterablesIndexCount,
newIterablesIndexCount,
iterablesIndexFilterStatus,
newIterablesIndexFilterStatus,
iterablesEmptyRows = [],
sort = quicksort.by(function(i) { return newValues[i]; }),
refilter = xfilterFilter.filterAll, // for recomputing filter
refilterFunction, // the custom filter function in use
filterValue, // the value used for filtering (value, array, function or undefined)
filterValuePresent, // true if filterValue contains something
indexListeners = [], // when data is added
dimensionGroups = [],
lo0 = 0,
hi0 = 0,
t = 0,
k;
// Updating a dimension is a two-stage process. First, we must update the
// associated filters for the newly-added records. Once all dimensions have
// updated their filters, the groups are notified to update.
dataListeners.unshift(preAdd);
dataListeners.push(postAdd);
removeDataListeners.push(removeData);
// Add a new dimension in the filter bitmap and store the offset and bitmask.
var tmp = filters.add();
offset = tmp.offset;
one = tmp.one;
zero = ~one;
// Create a unique ID for the dimension
// IDs will be re-used if dimensions are disposed.
// For internal use the ID is the subarray offset shifted left 7 bits or'd with the
// bit offset of the set bit in the dimension's "one" mask.
id = (offset << 7) | (Math.log(one) / Math.log(2));
preAdd(data, 0, n);
postAdd(data, 0, n);
// Incorporates the specified new records into this dimension.
// This function is responsible for updating filters, values, and index.
function preAdd(newData, n0, n1) {
if (iterable){
// Count all the values
t = 0;
j = 0;
k = [];
for (var i0 = 0; i0 < newData.length; i0++) {
for(j = 0, k = value(newData[i0]); j < k.length; j++) {
t++;
}
}
newValues = [];
newIterablesIndexCount = crossfilter_range(newData.length);
newIterablesIndexFilterStatus = crossfilter_index(t,1);
var unsortedIndex = crossfilter_range(t);
for (var l = 0, index1 = 0; index1 < newData.length; index1++) {
k = value(newData[index1])
//
if(!k.length){
newIterablesIndexCount[index1] = 0;
iterablesEmptyRows.push(index1 + n0);
continue;
}
newIterablesIndexCount[index1] = k.length
for (j = 0; j < k.length; j++) {
newValues.push(k[j]);
unsortedIndex[l] = index1;
l++;
}
}
// Create the Sort map used to sort both the values and the valueToData indices
var sortMap = sort(crossfilter_range(t), 0, t);
// Use the sortMap to sort the newValues
newValues = permute(newValues, sortMap);
// Use the sortMap to sort the unsortedIndex map
// newIndex should be a map of sortedValue -> crossfilterData
newIndex = permute(unsortedIndex, sortMap)
} else{
// Permute new values into natural order using a standard sorted index.
newValues = newData.map(value);
newIndex = sort(crossfilter_range(n1), 0, n1);
newValues = permute(newValues, newIndex);
}
if(iterable) {
n1 = t;
}
// Bisect newValues to determine which new records are selected.
var bounds = refilter(newValues), lo1 = bounds[0], hi1 = bounds[1];
if (refilterFunction) {
for (var index2 = 0; index2 < n1; ++index2) {
if (!refilterFunction(newValues[index2], index2)) {
filters[offset][newIndex[index2] + n0] |= one;
if(iterable) newIterablesIndexFilterStatus[index2] = 1;
}
}
} else {
for (var index3 = 0; index3 < lo1; ++index3) {
filters[offset][newIndex[index3] + n0] |= one;
if(iterable) newIterablesIndexFilterStatus[index3] = 1;
}
for (var index4 = hi1; index4 < n1; ++index4) {
filters[offset][newIndex[index4] + n0] |= one;
if(iterable) newIterablesIndexFilterStatus[index4] = 1;
}
}
// If this dimension previously had no data, then we don't need to do the
// more expensive merge operation; use the new values and index as-is.
if (!n0) {
values = newValues;
index = newIndex;
iterablesIndexCount = newIterablesIndexCount;
iterablesIndexFilterStatus = newIterablesIndexFilterStatus;
lo0 = lo1;
hi0 = hi1;
return;
}
var oldValues = values,
oldIndex = index,
oldIterablesIndexFilterStatus = iterablesIndexFilterStatus,
old_n0,
i1 = 0;
i0 = 0;
if(iterable){
old_n0 = n0
n0 = oldValues.length;
n1 = t
}
// Otherwise, create new arrays into which to merge new and old.
values = iterable ? new Array(n0 + n1) : new Array(n);
index = iterable ? new Array(n0 + n1) : crossfilter_index(n, n);
if(iterable) iterablesIndexFilterStatus = crossfilter_index(n0 + n1, 1);
// Concatenate the newIterablesIndexCount onto the old one.
if(iterable) {
var oldiiclength = iterablesIndexCount.length;
iterablesIndexCount = xfilterArray.arrayLengthen(iterablesIndexCount, n);
for(var j=0; j+oldiiclength < n; j++) {
iterablesIndexCount[j+oldiiclength] = newIterablesIndexCount[j];
}
}
// Merge the old and new sorted values, and old and new index.
var index5 = 0;
for (; i0 < n0 && i1 < n1; ++index5) {
if (oldValues[i0] < newValues[i1]) {
values[index5] = oldValues[i0];
if(iterable) iterablesIndexFilterStatus[index5] = oldIterablesIndexFilterStatus[i0];
index[index5] = oldIndex[i0++];
} else {
values[index5] = newValues[i1];
if(iterable) iterablesIndexFilterStatus[index5] = newIterablesIndexFilterStatus[i1];
index[index5] = newIndex[i1++] + (iterable ? old_n0 : n0);
}
}
// Add any remaining old values.
for (; i0 < n0; ++i0, ++index5) {
values[index5] = oldValues[i0];
if(iterable) iterablesIndexFilterStatus[index5] = oldIterablesIndexFilterStatus[i0];
index[index5] = oldIndex[i0];
}
// Add any remaining new values.
for (; i1 < n1; ++i1, ++index5) {
values[index5] = newValues[i1];
if(iterable) iterablesIndexFilterStatus[index5] = newIterablesIndexFilterStatus[i1];
index[index5] = newIndex[i1] + (iterable ? old_n0 : n0);
}
// Bisect again to recompute lo0 and hi0.
bounds = refilter(values), lo0 = bounds[0], hi0 = bounds[1];
}
// When all filters have updated, notify index listeners of the new values.
function postAdd(newData, n0, n1) {
indexListeners.forEach(function(l) { l(newValues, newIndex, n0, n1); });
newValues = newIndex = null;
}
function removeData(reIndex) {
if (iterable) {
for (var i0 = 0, i1 = 0; i0 < iterablesEmptyRows.length; i0++) {
if (reIndex[iterablesEmptyRows[i0]] !== REMOVED_INDEX) {
iterablesEmptyRows[i1] = reIndex[iterablesEmptyRows[i0]];
i1++;
}
}
iterablesEmptyRows.length = i1;
for (i0 = 0, i1 = 0; i0 < n; i0++) {
if (reIndex[i0] !== REMOVED_INDEX) {
if (i1 !== i0) iterablesIndexCount[i1] = iterablesIndexCount[i0];
i1++;
}
}
iterablesIndexCount.length = i1;
}
// Rewrite our index, overwriting removed values
var n0 = values.length;
for (var i = 0, j = 0, oldDataIndex; i < n0; ++i) {
oldDataIndex = index[i];
if (reIndex[oldDataIndex] !== REMOVED_INDEX) {
if (i !== j) values[j] = values[i];
index[j] = reIndex[oldDataIndex];
if (iterable) {
iterablesIndexFilterStatus[j] = iterablesIndexFilterStatus[i];
}
++j;
}
}
values.length = j;
if (iterable) iterablesIndexFilterStatus.length = j;
while (j < n0) index[j++] = 0;
// Bisect again to recompute lo0 and hi0.
var bounds = refilter(values);
lo0 = bounds[0], hi0 = bounds[1];
}
// Updates the selected values based on the specified bounds [lo, hi].
// This implementation is used by all the public filter methods.
function filterIndexBounds(bounds) {
var lo1 = bounds[0],
hi1 = bounds[1];
if (refilterFunction) {
refilterFunction = null;
filterIndexFunction(function(d, i) { return lo1 <= i && i < hi1; }, bounds[0] === 0 && bounds[1] === values.length);
lo0 = lo1;
hi0 = hi1;
return dimension;
}
var i,
j,
k,
added = [],
removed = [],
valueIndexAdded = [],
valueIndexRemoved = [];
// Fast incremental update based on previous lo index.
if (lo1 < lo0) {
for (i = lo1, j = Math.min(lo0, hi1); i < j; ++i) {
added.push(index[i]);
valueIndexAdded.push(i);
}
} else if (lo1 > lo0) {
for (i = lo0, j = Math.min(lo1, hi0); i < j; ++i) {
removed.push(index[i]);
valueIndexRemoved.push(i);
}
}
// Fast incremental update based on previous hi index.
if (hi1 > hi0) {
for (i = Math.max(lo1, hi0), j = hi1; i < j; ++i) {
added.push(index[i]);
valueIndexAdded.push(i);
}
} else if (hi1 < hi0) {
for (i = Math.max(lo0, hi1), j = hi0; i < j; ++i) {
removed.push(index[i]);
valueIndexRemoved.push(i);
}
}
if(!iterable) {
// Flip filters normally.
for(i=0; i 0) toSkip = top_offset;
while (--i >= lo0 && k > 0) {
if (filters.zero(j = index[i])) {
if(toSkip > 0) {
//skip matching row
--toSkip;
} else {
array.push(data[j]);
--k;
}
}
}
if(iterable){
for(i = 0; i < iterablesEmptyRows.length && k > 0; i++) {
// Add row with empty iterable column at the end
if(filters.zero(j = iterablesEmptyRows[i])) {
if(toSkip > 0) {
//skip matching row
--toSkip;
} else {
array.push(data[j]);
--k;
}
}
}
}
return array;
}
// Returns the bottom K selected records based on this dimension's order.
// Note: observes this dimension's filter, unlike group and groupAll.
function bottom(k, bottom_offset) {
var array = [],
i,
j,
toSkip = 0;
if(bottom_offset && bottom_offset > 0) toSkip = bottom_offset;
if(iterable) {
// Add row with empty iterable column at the top
for(i = 0; i < iterablesEmptyRows.length && k > 0; i++) {
if(filters.zero(j = iterablesEmptyRows[i])) {
if(toSkip > 0) {
//skip matching row
--toSkip;
} else {
array.push(data[j]);
--k;
}
}
}
}
i = lo0;
while (i < hi0 && k > 0) {
if (filters.zero(j = index[i])) {
if(toSkip > 0) {
//skip matching row
--toSkip;
} else {
array.push(data[j]);
--k;
}
}
i++;
}
return array;
}
// Adds a new group to this dimension, using the specified key function.
function group(key) {
var group = {
top: top,
all: all,
reduce: reduce,
reduceCount: reduceCount,
reduceSum: reduceSum,
order: order,
orderNatural: orderNatural,
size: size,
dispose: dispose,
remove: dispose // for backwards-compatibility
};
// Ensure that this group will be removed when the dimension is removed.
dimensionGroups.push(group);
var groups, // array of {key, value}
groupIndex, // object id ↦ group id
groupWidth = 8,
groupCapacity = crossfilter_capacity(groupWidth),
k = 0, // cardinality
select,
heap,
reduceAdd,
reduceRemove,
reduceInitial,
update = crossfilter_null,
reset = crossfilter_null,
resetNeeded = true,
groupAll = key === crossfilter_null,
n0old;
if (arguments.length < 1) key = crossfilter_identity;
// The group listens to the crossfilter for when any dimension changes, so
// that it can update the associated reduce values. It must also listen to
// the parent dimension for when data is added, and compute new keys.
filterListeners.push(update);
indexListeners.push(add);
removeDataListeners.push(removeData);
// Incorporate any existing data into the grouping.
add(values, index, 0, n);
// Incorporates the specified new values into this group.
// This function is responsible for updating groups and groupIndex.
function add(newValues, newIndex, n0, n1) {
if(iterable) {
n0old = n0
n0 = values.length - newValues.length
n1 = newValues.length;
}
var oldGroups = groups,
reIndex = iterable ? [] : crossfilter_index(k, groupCapacity),
add = reduceAdd,
remove = reduceRemove,
initial = reduceInitial,
k0 = k, // old cardinality
i0 = 0, // index of old group
i1 = 0, // index of new record
j, // object id
g0, // old group
x0, // old key
x1, // new key
g, // group to add
x; // key of group to add
// If a reset is needed, we don't need to update the reduce values.
if (resetNeeded) add = initial = crossfilter_null;
if (resetNeeded) remove = initial = crossfilter_null;
// Reset the new groups (k is a lower bound).
// Also, make sure that groupIndex exists and is long enough.
groups = new Array(k), k = 0;
if(iterable){
groupIndex = k0 ? groupIndex : [];
}
else{
groupIndex = k0 > 1 ? xfilterArray.arrayLengthen(groupIndex, n) : crossfilter_index(n, groupCapacity);
}
// Get the first old key (x0 of g0), if it exists.
if (k0) x0 = (g0 = oldGroups[0]).key;
// Find the first new key (x1), skipping NaN keys.
while (i1 < n1 && !((x1 = key(newValues[i1])) >= x1)) ++i1;
// While new keys remain…
while (i1 < n1) {
// Determine the lesser of the two current keys; new and old.
// If there are no old keys remaining, then always add the new key.
if (g0 && x0 <= x1) {
g = g0, x = x0;
// Record the new index of the old group.
reIndex[i0] = k;
// Retrieve the next old key.
g0 = oldGroups[++i0];
if (g0) x0 = g0.key;
} else {
g = {key: x1, value: initial()}, x = x1;
}
// Add the lesser group.
groups[k] = g;
// Add any selected records belonging to the added group, while
// advancing the new key and populating the associated group index.
while (x1 <= x) {
j = newIndex[i1] + (iterable ? n0old : n0)
if(iterable){
if(groupIndex[j]){
groupIndex[j].push(k)
}
else{
groupIndex[j] = [k]
}
}
else{
groupIndex[j] = k;
}
// Always add new values to groups. Only remove when not in filter.
// This gives groups full information on data life-cycle.
g.value = add(g.value, data[j], true);
if (!filters.zeroExcept(j, offset, zero)) g.value = remove(g.value, data[j], false);
if (++i1 >= n1) break;
x1 = key(newValues[i1]);
}
groupIncrement();
}
// Add any remaining old groups that were greater th1an all new keys.
// No incremental reduce is needed; these groups have no new records.
// Also record the new index of the old group.
while (i0 < k0) {
groups[reIndex[i0] = k] = oldGroups[i0++];
groupIncrement();
}
// Fill in gaps with empty arrays where there may have been rows with empty iterables
if(iterable){
for (var index1 = 0; index1 < n; index1++) {
if(!groupIndex[index1]){
groupIndex[index1] = [];
}
}
}
// If we added any new groups before any old groups,
// update the group index of all the old records.
if(k > i0){
if(iterable){
for (i0 = 0; i0 < n0old; ++i0) {
for (index1 = 0; index1 < groupIndex[i0].length; index1++) {
groupIndex[i0][index1] = reIndex[groupIndex[i0][index1]];
}
}
}
else{
for (i0 = 0; i0 < n0; ++i0) {
groupIndex[i0] = reIndex[groupIndex[i0]];
}
}
}
// Modify the update and reset behavior based on the cardinality.
// If the cardinality is less than or equal to one, then the groupIndex
// is not needed. If the cardinality is zero, then there are no records
// and therefore no groups to update or reset. Note that we also must
// change the registered listener to point to the new method.
j = filterListeners.indexOf(update);
if (k > 1 || iterable) {
update = updateMany;
reset = resetMany;
} else {
if (!k && groupAll) {
k = 1;
groups = [{key: null, value: initial()}];
}
if (k === 1) {
update = updateOne;
reset = resetOne;
} else {
update = crossfilter_null;
reset = crossfilter_null;
}
groupIndex = null;
}
filterListeners[j] = update;
// Count the number of added groups,
// and widen the group index as needed.
function groupIncrement() {
if(iterable){
k++
return
}
if (++k === groupCapacity) {
reIndex = xfilterArray.arrayWiden(reIndex, groupWidth <<= 1);
groupIndex = xfilterArray.arrayWiden(groupIndex, groupWidth);
groupCapacity = crossfilter_capacity(groupWidth);
}
}
}
function removeData(reIndex) {
if (k > 1 || iterable) {
var oldK = k,
oldGroups = groups,
seenGroups = crossfilter_index(oldK, oldK),
i,
i0,
j;
// Filter out non-matches by copying matching group index entries to
// the beginning of the array.
if (!iterable) {
for (i = 0, j = 0; i < n; ++i) {
if (reIndex[i] !== REMOVED_INDEX) {
seenGroups[groupIndex[j] = groupIndex[i]] = 1;
++j;
}
}
} else {
for (i = 0, j = 0; i < n; ++i) {
if (reIndex[i] !== REMOVED_INDEX) {
groupIndex[j] = groupIndex[i];
for (i0 = 0; i0 < groupIndex[j].length; i0++) {
seenGroups[groupIndex[j][i0]] = 1;
}
++j;
}
}
}
// Reassemble groups including only those groups that were referred
// to by matching group index entries. Note the new group index in
// seenGroups.
groups = [], k = 0;
for (i = 0; i < oldK; ++i) {
if (seenGroups[i]) {
seenGroups[i] = k++;
groups.push(oldGroups[i]);
}
}
if (k > 1 || iterable) {
// Reindex the group index using seenGroups to find the new index.
if (!iterable) {
for (i = 0; i < j; ++i) groupIndex[i] = seenGroups[groupIndex[i]];
} else {
for (i = 0; i < j; ++i) {
for (i0 = 0; i0 < groupIndex[i].length; ++i0) {
groupIndex[i][i0] = seenGroups[groupIndex[i][i0]];
}
}
}
} else {
groupIndex = null;
}
filterListeners[filterListeners.indexOf(update)] = k > 1 || iterable
? (reset = resetMany, update = updateMany)
: k === 1 ? (reset = resetOne, update = updateOne)
: reset = update = crossfilter_null;
} else if (k === 1) {
if (groupAll) return;
for (var index3 = 0; index3 < n; ++index3) if (reIndex[index3] !== REMOVED_INDEX) return;
groups = [], k = 0;
filterListeners[filterListeners.indexOf(update)] =
update = reset = crossfilter_null;
}
}
// Reduces the specified selected or deselected records.
// This function is only used when the cardinality is greater than 1.
// notFilter indicates a crossfilter.add/remove operation.
function updateMany(filterOne, filterOffset, added, removed, notFilter) {
if ((filterOne === one && filterOffset === offset) || resetNeeded) return;
var i,
j,
k,
n,
g;
if(iterable){
// Add the added values.
for (i = 0, n = added.length; i < n; ++i) {
if (filters.zeroExcept(k = added[i], offset, zero)) {
for (j = 0; j < groupIndex[k].length; j++) {
g = groups[groupIndex[k][j]];
g.value = reduceAdd(g.value, data[k], false, j);
}
}
}
// Remove the removed values.
for (i = 0, n = removed.length; i < n; ++i) {
if (filters.onlyExcept(k = removed[i], offset, zero, filterOffset, filterOne)) {
for (j = 0; j < groupIndex[k].length; j++) {
g = groups[groupIndex[k][j]];
g.value = reduceRemove(g.value, data[k], notFilter, j);
}
}
}
return;
}
// Add the added values.
for (i = 0, n = added.length; i < n; ++i) {
if (filters.zeroExcept(k = added[i], offset, zero)) {
g = groups[groupIndex[k]];
g.value = reduceAdd(g.value, data[k], false);
}
}
// Remove the removed values.
for (i = 0, n = removed.length; i < n; ++i) {
if (filters.onlyExcept(k = removed[i], offset, zero, filterOffset, filterOne)) {
g = groups[groupIndex[k]];
g.value = reduceRemove(g.value, data[k], notFilter);
}
}
}
// Reduces the specified selected or deselected records.
// This function is only used when the cardinality is 1.
// notFilter indicates a crossfilter.add/remove operation.
function updateOne(filterOne, filterOffset, added, removed, notFilter) {
if ((filterOne === one && filterOffset === offset) || resetNeeded) return;
var i,
k,
n,
g = groups[0];
// Add the added values.
for (i = 0, n = added.length; i < n; ++i) {
if (filters.zeroExcept(k = added[i], offset, zero)) {
g.value = reduceAdd(g.value, data[k], false);
}
}
// Remove the removed values.
for (i = 0, n = removed.length; i < n; ++i) {
if (filters.onlyExcept(k = removed[i], offset, zero, filterOffset, filterOne)) {
g.value = reduceRemove(g.value, data[k], notFilter);
}
}
}
// Recomputes the group reduce values from scratch.
// This function is only used when the cardinality is greater than 1.
function resetMany() {
var i,
j,
g;
// Reset all group values.
for (i = 0; i < k; ++i) {
groups[i].value = reduceInitial();
}
// We add all records and then remove filtered records so that reducers
// can build an 'unfiltered' view even if there are already filters in
// place on other dimensions.
if(iterable){
for (i = 0; i < n; ++i) {
for (j = 0; j < groupIndex[i].length; j++) {
g = groups[groupIndex[i][j]];
g.value = reduceAdd(g.value, data[i], true, j);
}
}
for (i = 0; i < n; ++i) {
if (!filters.zeroExcept(i, offset, zero)) {
for (j = 0; j < groupIndex[i].length; j++) {
g = groups[groupIndex[i][j]];
g.value = reduceRemove(g.value, data[i], false, j);
}
}
}
return;
}
for (i = 0; i < n; ++i) {
g = groups[groupIndex[i]];
g.value = reduceAdd(g.value, data[i], true);
}
for (i = 0; i < n; ++i) {
if (!filters.zeroExcept(i, offset, zero)) {
g = groups[groupIndex[i]];
g.value = reduceRemove(g.value, data[i], false);
}
}
}
// Recomputes the group reduce values from scratch.
// This function is only used when the cardinality is 1.
function resetOne() {
var i,
g = groups[0];
// Reset the singleton group values.
g.value = reduceInitial();
// We add all records and then remove filtered records so that reducers
// can build an 'unfiltered' view even if there are already filters in
// place on other dimensions.
for (i = 0; i < n; ++i) {
g.value = reduceAdd(g.value, data[i], true);
}
for (i = 0; i < n; ++i) {
if (!filters.zeroExcept(i, offset, zero)) {
g.value = reduceRemove(g.value, data[i], false);
}
}
}
// Returns the array of group values, in the dimension's natural order.
function all() {
if (resetNeeded) reset(), resetNeeded = false;
return groups;
}
// Returns a new array containing the top K group values, in reduce order.
function top(k) {
var top = select(all(), 0, groups.length, k);
return heap.sort(top, 0, top.length);
}
// Sets the reduce behavior for this group to use the specified functions.
// This method lazily recomputes the reduce values, waiting until needed.
function reduce(add, remove, initial) {
reduceAdd = add;
reduceRemove = remove;
reduceInitial = initial;
resetNeeded = true;
return group;
}
// A convenience method for reducing by count.
function reduceCount() {
return reduce(xfilterReduce.reduceIncrement, xfilterReduce.reduceDecrement, crossfilter_zero);
}
// A convenience method for reducing by sum(value).
function reduceSum(value) {
return reduce(xfilterReduce.reduceAdd(value), xfilterReduce.reduceSubtract(value), crossfilter_zero);
}
// Sets the reduce order, using the specified accessor.
function order(value) {
select = xfilterHeapselect.by(valueOf);
heap = xfilterHeap.by(valueOf);
function valueOf(d) { return value(d.value); }
return group;
}
// A convenience method for natural ordering by reduce value.
function orderNatural() {
return order(crossfilter_identity);
}
// Returns the cardinality of this group, irrespective of any filters.
function size() {
return k;
}
// Removes this group and associated event listeners.
function dispose() {
var i = filterListeners.indexOf(update);
if (i >= 0) filterListeners.splice(i, 1);
i = indexListeners.indexOf(add);
if (i >= 0) indexListeners.splice(i, 1);
i = removeDataListeners.indexOf(removeData);
if (i >= 0) removeDataListeners.splice(i, 1);
i = dimensionGroups.indexOf(group);
if (i >= 0) dimensionGroups.splice(i, 1);
return group;
}
return reduceCount().orderNatural();
}
// A convenience function for generating a singleton group.
function groupAll() {
var g = group(crossfilter_null), all = g.all;
delete g.all;
delete g.top;
delete g.order;
delete g.orderNatural;
delete g.size;
g.value = function() { return all()[0].value; };
return g;
}
// Removes this dimension and associated groups and event listeners.
function dispose() {
dimensionGroups.forEach(function(group) { group.dispose(); });
var i = dataListeners.indexOf(preAdd);
if (i >= 0) dataListeners.splice(i, 1);
i = dataListeners.indexOf(postAdd);
if (i >= 0) dataListeners.splice(i, 1);
i = removeDataListeners.indexOf(removeData);
if (i >= 0) removeDataListeners.splice(i, 1);
filters.masks[offset] &= zero;
return filterAll();
}
return dimension;
}
// A convenience method for groupAll on a dummy dimension.
// This implementation can be optimized since it always has cardinality 1.
function groupAll() {
var group = {
reduce: reduce,
reduceCount: reduceCount,
reduceSum: reduceSum,
value: value,
dispose: dispose,
remove: dispose // for backwards-compatibility
};
var reduceValue,
reduceAdd,
reduceRemove,
reduceInitial,
resetNeeded = true;
// The group listens to the crossfilter for when any dimension changes, so
// that it can update the reduce value. It must also listen to the parent
// dimension for when data is added.
filterListeners.push(update);
dataListeners.push(add);
// For consistency; actually a no-op since resetNeeded is true.
add(data, 0, n);
// Incorporates the specified new values into this group.
function add(newData, n0) {
var i;
if (resetNeeded) return;
// Cycle through all the values.
for (i = n0; i < n; ++i) {
// Add all values all the time.
reduceValue = reduceAdd(reduceValue, data[i], true);
// Remove the value if filtered.
if (!filters.zero(i)) {
reduceValue = reduceRemove(reduceValue, data[i], false);
}
}
}
// Reduces the specified selected or deselected records.
function update(filterOne, filterOffset, added, removed, notFilter) {
var i,
k,
n;
if (resetNeeded) return;
// Add the added values.
for (i = 0, n = added.length; i < n; ++i) {
if (filters.zero(k = added[i])) {
reduceValue = reduceAdd(reduceValue, data[k], notFilter);
}
}
// Remove the removed values.
for (i = 0, n = removed.length; i < n; ++i) {
if (filters.only(k = removed[i], filterOffset, filterOne)) {
reduceValue = reduceRemove(reduceValue, data[k], notFilter);
}
}
}
// Recomputes the group reduce value from scratch.
function reset() {
var i;
reduceValue = reduceInitial();
// Cycle through all the values.
for (i = 0; i < n; ++i) {
// Add all values all the time.
reduceValue = reduceAdd(reduceValue, data[i], true);
// Remove the value if it is filtered.
if (!filters.zero(i)) {
reduceValue = reduceRemove(reduceValue, data[i], false);
}
}
}
// Sets the reduce behavior for this group to use the specified functions.
// This method lazily recomputes the reduce value, waiting until needed.
function reduce(add, remove, initial) {
reduceAdd = add;
reduceRemove = remove;
reduceInitial = initial;
resetNeeded = true;
return group;
}
// A convenience method for reducing by count.
function reduceCount() {
return reduce(xfilterReduce.reduceIncrement, xfilterReduce.reduceDecrement, crossfilter_zero);
}
// A convenience method for reducing by sum(value).
function reduceSum(value) {
return reduce(xfilterReduce.reduceAdd(value), xfilterReduce.reduceSubtract(value), crossfilter_zero);
}
// Returns the computed reduce value.
function value() {
if (resetNeeded) reset(), resetNeeded = false;
return reduceValue;
}
// Removes this group and associated event listeners.
function dispose() {
var i = filterListeners.indexOf(update);
if (i >= 0) filterListeners.splice(i, 1);
i = dataListeners.indexOf(add);
if (i >= 0) dataListeners.splice(i, 1);
return group;
}
return reduceCount();
}
// Returns the number of records in this crossfilter, irrespective of any filters.
function size() {
return n;
}
// Returns the raw row data contained in this crossfilter
function all(){
return data;
}
// Returns row data with all dimension filters applied, except for filters in ignore_dimensions
function allFiltered(ignore_dimensions) {
var array = [],
i = 0,
mask = maskForDimensions(ignore_dimensions || []);
for (i = 0; i < n; i++) {
if (filters.zeroExceptMask(i, mask)) {
array.push(data[i]);
}
}
return array;
}
function onChange(cb){
if(typeof cb !== 'function'){
/* eslint no-console: 0 */
console.warn('onChange callback parameter must be a function!');
return;
}
callbacks.push(cb);
return function(){
callbacks.splice(callbacks.indexOf(cb), 1);
};
}
function triggerOnChange(eventName){
for (var i = 0; i < callbacks.length; i++) {
callbacks[i](eventName);
}
}
return arguments.length
? add(arguments[0])
: crossfilter;
}
// Returns an array of size n, big enough to store ids up to m.
function crossfilter_index(n, m) {
return (m < 0x101
? xfilterArray.array8 : m < 0x10001
? xfilterArray.array16
: xfilterArray.array32)(n);
}
// Constructs a new array of size n, with sequential values from 0 to n - 1.
function crossfilter_range(n) {
var range = crossfilter_index(n, n);
for (var i = -1; ++i < n;) range[i] = i;
return range;
}
function crossfilter_capacity(w) {
return w === 8
? 0x100 : w === 16
? 0x10000
: 0x100000000;
}
},{"./../package.json":3,"./array":4,"./bisect":5,"./filter":7,"./heap":8,"./heapselect":9,"./identity":10,"./insertionsort":11,"./null":12,"./permute":13,"./quicksort":14,"./reduce":15,"./zero":16,"lodash.result":2}],7:[function(require,module,exports){
'use strict';
function crossfilter_filterExact(bisect, value) {
return function(values) {
var n = values.length;
return [bisect.left(values, value, 0, n), bisect.right(values, value, 0, n)];
};
}
function crossfilter_filterRange(bisect, range) {
var min = range[0],
max = range[1];
return function(values) {
var n = values.length;
return [bisect.left(values, min, 0, n), bisect.left(values, max, 0, n)];
};
}
function crossfilter_filterAll(values) {
return [0, values.length];
}
module.exports = {
filterExact: crossfilter_filterExact,
filterRange: crossfilter_filterRange,
filterAll: crossfilter_filterAll
};
},{}],8:[function(require,module,exports){
'use strict';
var crossfilter_identity = require('./identity');
function heap_by(f) {
// Builds a binary heap within the specified array a[lo:hi]. The heap has the
// property such that the parent a[lo+i] is always less than or equal to its
// two children: a[lo+2*i+1] and a[lo+2*i+2].
function heap(a, lo, hi) {
var n = hi - lo,
i = (n >>> 1) + 1;
while (--i > 0) sift(a, i, n, lo);
return a;
}
// Sorts the specified array a[lo:hi] in descending order, assuming it is
// already a heap.
function sort(a, lo, hi) {
var n = hi - lo,
t;
while (--n > 0) t = a[lo], a[lo] = a[lo + n], a[lo + n] = t, sift(a, 1, n, lo);
return a;
}
// Sifts the element a[lo+i-1] down the heap, where the heap is the contiguous
// slice of array a[lo:lo+n]. This method can also be used to update the heap
// incrementally, without incurring the full cost of reconstructing the heap.
function sift(a, i, n, lo) {
var d = a[--lo + i],
x = f(d),
child;
while ((child = i << 1) <= n) {
if (child < n && f(a[lo + child]) > f(a[lo + child + 1])) child++;
if (x <= f(a[lo + child])) break;
a[lo + i] = a[lo + child];
i = child;
}
a[lo + i] = d;
}
heap.sort = sort;
return heap;
}
module.exports = heap_by(crossfilter_identity);
module.exports.by = heap_by;
},{"./identity":10}],9:[function(require,module,exports){
'use strict';
var crossfilter_identity = require('./identity');
var xFilterHeap = require('./heap');
function heapselect_by(f) {
var heap = xFilterHeap.by(f);
// Returns a new array containing the top k elements in the array a[lo:hi].
// The returned array is not sorted, but maintains the heap property. If k is
// greater than hi - lo, then fewer than k elements will be returned. The
// order of elements in a is unchanged by this operation.
function heapselect(a, lo, hi, k) {
var queue = new Array(k = Math.min(hi - lo, k)),
min,
i,
d;
for (i = 0; i < k; ++i) queue[i] = a[lo++];
heap(queue, 0, k);
if (lo < hi) {
min = f(queue[0]);
do {
if (f(d = a[lo]) > min) {
queue[0] = d;
min = f(heap(queue, 0, k)[0]);
}
} while (++lo < hi);
}
return queue;
}
return heapselect;
}
module.exports = heapselect_by(crossfilter_identity);
module.exports.by = heapselect_by; // assign the raw function to the export as well
},{"./heap":8,"./identity":10}],10:[function(require,module,exports){
'use strict';
function crossfilter_identity(d) {
return d;
}
module.exports = crossfilter_identity;
},{}],11:[function(require,module,exports){
'use strict';
var crossfilter_identity = require('./identity');
function insertionsort_by(f) {
function insertionsort(a, lo, hi) {
for (var i = lo + 1; i < hi; ++i) {
for (var j = i, t = a[i], x = f(t); j > lo && f(a[j - 1]) > x; --j) {
a[j] = a[j - 1];
}
a[j] = t;
}
return a;
}
return insertionsort;
}
module.exports = insertionsort_by(crossfilter_identity);
module.exports.by = insertionsort_by;
},{"./identity":10}],12:[function(require,module,exports){
'use strict';
function crossfilter_null() {
return null;
}
module.exports = crossfilter_null;
},{}],13:[function(require,module,exports){
'use strict';
function permute(array, index, deep) {
for (var i = 0, n = index.length, copy = deep ? JSON.parse(JSON.stringify(array)) : new Array(n); i < n; ++i) {
copy[i] = array[index[i]];
}
return copy;
}
module.exports = permute;
},{}],14:[function(require,module,exports){
var crossfilter_identity = require('./identity');
var xFilterInsertionsort = require('./insertionsort');
// Algorithm designed by Vladimir Yaroslavskiy.
// Implementation based on the Dart project; see NOTICE and AUTHORS for details.
function quicksort_by(f) {
var insertionsort = xFilterInsertionsort.by(f);
function sort(a, lo, hi) {
return (hi - lo < quicksort_sizeThreshold
? insertionsort
: quicksort)(a, lo, hi);
}
function quicksort(a, lo, hi) {
// Compute the two pivots by looking at 5 elements.
var sixth = (hi - lo) / 6 | 0,
i1 = lo + sixth,
i5 = hi - 1 - sixth,
i3 = lo + hi - 1 >> 1, // The midpoint.
i2 = i3 - sixth,
i4 = i3 + sixth;
var e1 = a[i1], x1 = f(e1),
e2 = a[i2], x2 = f(e2),
e3 = a[i3], x3 = f(e3),
e4 = a[i4], x4 = f(e4),
e5 = a[i5], x5 = f(e5);
var t;
// Sort the selected 5 elements using a sorting network.
if (x1 > x2) t = e1, e1 = e2, e2 = t, t = x1, x1 = x2, x2 = t;
if (x4 > x5) t = e4, e4 = e5, e5 = t, t = x4, x4 = x5, x5 = t;
if (x1 > x3) t = e1, e1 = e3, e3 = t, t = x1, x1 = x3, x3 = t;
if (x2 > x3) t = e2, e2 = e3, e3 = t, t = x2, x2 = x3, x3 = t;
if (x1 > x4) t = e1, e1 = e4, e4 = t, t = x1, x1 = x4, x4 = t;
if (x3 > x4) t = e3, e3 = e4, e4 = t, t = x3, x3 = x4, x4 = t;
if (x2 > x5) t = e2, e2 = e5, e5 = t, t = x2, x2 = x5, x5 = t;
if (x2 > x3) t = e2, e2 = e3, e3 = t, t = x2, x2 = x3, x3 = t;
if (x4 > x5) t = e4, e4 = e5, e5 = t, t = x4, x4 = x5, x5 = t;
var pivot1 = e2, pivotValue1 = x2,
pivot2 = e4, pivotValue2 = x4;
// e2 and e4 have been saved in the pivot variables. They will be written
// back, once the partitioning is finished.
a[i1] = e1;
a[i2] = a[lo];
a[i3] = e3;
a[i4] = a[hi - 1];
a[i5] = e5;
var less = lo + 1, // First element in the middle partition.
great = hi - 2; // Last element in the middle partition.
// Note that for value comparison, <, <=, >= and > coerce to a primitive via
// Object.prototype.valueOf; == and === do not, so in order to be consistent
// with natural order (such as for Date objects), we must do two compares.
var pivotsEqual = pivotValue1 <= pivotValue2 && pivotValue1 >= pivotValue2;
if (pivotsEqual) {
// Degenerated case where the partitioning becomes a dutch national flag
// problem.
//
// [ | < pivot | == pivot | unpartitioned | > pivot | ]
// ^ ^ ^ ^ ^
// left less k great right
//
// a[left] and a[right] are undefined and are filled after the
// partitioning.
//
// Invariants:
// 1) for x in ]left, less[ : x < pivot.
// 2) for x in [less, k[ : x == pivot.
// 3) for x in ]great, right[ : x > pivot.
for (var k = less; k <= great; ++k) {
var ek = a[k], xk = f(ek);
if (xk < pivotValue1) {
if (k !== less) {
a[k] = a[less];
a[less] = ek;
}
++less;
} else if (xk > pivotValue1) {
// Find the first element <= pivot in the range [k - 1, great] and
// put [:ek:] there. We know that such an element must exist:
// When k == less, then el3 (which is equal to pivot) lies in the
// interval. Otherwise a[k - 1] == pivot and the search stops at k-1.
// Note that in the latter case invariant 2 will be violated for a
// short amount of time. The invariant will be restored when the
// pivots are put into their final positions.
/* eslint no-constant-condition: 0 */
while (true) {
var greatValue = f(a[great]);
if (greatValue > pivotValue1) {
great--;
// This is the only location in the while-loop where a new
// iteration is started.
continue;
} else if (greatValue < pivotValue1) {
// Triple exchange.
a[k] = a[less];
a[less++] = a[great];
a[great--] = ek;
break;
} else {
a[k] = a[great];
a[great--] = ek;
// Note: if great < k then we will exit the outer loop and fix
// invariant 2 (which we just violated).
break;
}
}
}
}
} else {
// We partition the list into three parts:
// 1. < pivot1
// 2. >= pivot1 && <= pivot2
// 3. > pivot2
//
// During the loop we have:
// [ | < pivot1 | >= pivot1 && <= pivot2 | unpartitioned | > pivot2 | ]
// ^ ^ ^ ^ ^
// left less k great right
//
// a[left] and a[right] are undefined and are filled after the
// partitioning.
//
// Invariants:
// 1. for x in ]left, less[ : x < pivot1
// 2. for x in [less, k[ : pivot1 <= x && x <= pivot2
// 3. for x in ]great, right[ : x > pivot2
(function () { // isolate scope
for (var k = less; k <= great; k++) {
var ek = a[k], xk = f(ek);
if (xk < pivotValue1) {
if (k !== less) {
a[k] = a[less];
a[less] = ek;
}
++less;
} else {
if (xk > pivotValue2) {
while (true) {
var greatValue = f(a[great]);
if (greatValue > pivotValue2) {
great--;
if (great < k) break;
// This is the only location inside the loop where a new
// iteration is started.
continue;
} else {
// a[great] <= pivot2.
if (greatValue < pivotValue1) {
// Triple exchange.
a[k] = a[less];
a[less++] = a[great];
a[great--] = ek;
} else {
// a[great] >= pivot1.
a[k] = a[great];
a[great--] = ek;
}
break;
}
}
}
}
}
})(); // isolate scope
}
// Move pivots into their final positions.
// We shrunk the list from both sides (a[left] and a[right] have
// meaningless values in them) and now we move elements from the first
// and third partition into these locations so that we can store the
// pivots.
a[lo] = a[less - 1];
a[less - 1] = pivot1;
a[hi - 1] = a[great + 1];
a[great + 1] = pivot2;
// The list is now partitioned into three partitions:
// [ < pivot1 | >= pivot1 && <= pivot2 | > pivot2 ]
// ^ ^ ^ ^
// left less great right
// Recursive descent. (Don't include the pivot values.)
sort(a, lo, less - 1);
sort(a, great + 2, hi);
if (pivotsEqual) {
// All elements in the second partition are equal to the pivot. No
// need to sort them.
return a;
}
// In theory it should be enough to call _doSort recursively on the second
// partition.
// The Android source however removes the pivot elements from the recursive
// call if the second partition is too large (more than 2/3 of the list).
if (less < i1 && great > i5) {
(function () { // isolate scope
var lessValue, greatValue;
while ((lessValue = f(a[less])) <= pivotValue1 && lessValue >= pivotValue1) ++less;
while ((greatValue = f(a[great])) <= pivotValue2 && greatValue >= pivotValue2) --great;
// Copy paste of the previous 3-way partitioning with adaptions.
//
// We partition the list into three parts:
// 1. == pivot1
// 2. > pivot1 && < pivot2
// 3. == pivot2
//
// During the loop we have:
// [ == pivot1 | > pivot1 && < pivot2 | unpartitioned | == pivot2 ]
// ^ ^ ^
// less k great
//
// Invariants:
// 1. for x in [ *, less[ : x == pivot1
// 2. for x in [less, k[ : pivot1 < x && x < pivot2
// 3. for x in ]great, * ] : x == pivot2
for (var k = less; k <= great; k++) {
var ek = a[k], xk = f(ek);
if (xk <= pivotValue1 && xk >= pivotValue1) {
if (k !== less) {
a[k] = a[less];
a[less] = ek;
}
less++;
} else {
if (xk <= pivotValue2 && xk >= pivotValue2) {
/* eslint no-constant-condition: 0 */
while (true) {
greatValue = f(a[great]);
if (greatValue <= pivotValue2 && greatValue >= pivotValue2) {
great--;
if (great < k) break;
// This is the only location inside the loop where a new
// iteration is started.
continue;
} else {
// a[great] < pivot2.
if (greatValue < pivotValue1) {
// Triple exchange.
a[k] = a[less];
a[less++] = a[great];
a[great--] = ek;
} else {
// a[great] == pivot1.
a[k] = a[great];
a[great--] = ek;
}
break;
}
}
}
}
}
})(); // isolate scope
}
// The second partition has now been cleared of pivot elements and looks
// as follows:
// [ * | > pivot1 && < pivot2 | * ]
// ^ ^
// less great
// Sort the second partition using recursive descent.
// The second partition looks as follows:
// [ * | >= pivot1 && <= pivot2 | * ]
// ^ ^
// less great
// Simply sort it by recursive descent.
return sort(a, less, great + 1);
}
return sort;
}
var quicksort_sizeThreshold = 32;
module.exports = quicksort_by(crossfilter_identity);
module.exports.by = quicksort_by;
},{"./identity":10,"./insertionsort":11}],15:[function(require,module,exports){
'use strict';
function crossfilter_reduceIncrement(p) {
return p + 1;
}
function crossfilter_reduceDecrement(p) {
return p - 1;
}
function crossfilter_reduceAdd(f) {
return function(p, v) {
return p + +f(v);
};
}
function crossfilter_reduceSubtract(f) {
return function(p, v) {
return p - f(v);
};
}
module.exports = {
reduceIncrement: crossfilter_reduceIncrement,
reduceDecrement: crossfilter_reduceDecrement,
reduceAdd: crossfilter_reduceAdd,
reduceSubtract: crossfilter_reduceSubtract
};
},{}],16:[function(require,module,exports){
'use strict';
function crossfilter_zero() {
return 0;
}
module.exports = crossfilter_zero;
},{}]},{},[1])(1)
});