summaryrefslogtreecommitdiff
path: root/www/crm/wp-content/plugins/civicrm/civicrm/bower_components/crossfilter2/crossfilter.js
diff options
context:
space:
mode:
Diffstat (limited to 'www/crm/wp-content/plugins/civicrm/civicrm/bower_components/crossfilter2/crossfilter.js')
-rw-r--r--www/crm/wp-content/plugins/civicrm/civicrm/bower_components/crossfilter2/crossfilter.js3167
1 files changed, 3167 insertions, 0 deletions
diff --git a/www/crm/wp-content/plugins/civicrm/civicrm/bower_components/crossfilter2/crossfilter.js b/www/crm/wp-content/plugins/civicrm/civicrm/bower_components/crossfilter2/crossfilter.js
new file mode 100644
index 00000000..cb70794b
--- /dev/null
+++ b/www/crm/wp-content/plugins/civicrm/civicrm/bower_components/crossfilter2/crossfilter.js
@@ -0,0 +1,3167 @@
+(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<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
+module.exports = require("./src/crossfilter").crossfilter;
+
+},{"./src/crossfilter":6}],2:[function(require,module,exports){
+(function (global){
+/**
+ * lodash (Custom Build) <https://lodash.com/>
+ * Build: `lodash modularize exports="npm" -o ./`
+ * Copyright jQuery Foundation and other contributors <https://jquery.org/>
+ * Released under MIT license <https://lodash.com/license>
+ * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
+ * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+ */
+
+/** Used as 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.7"}
+},{}],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<added.length; i++) {
+ filters[offset][added[i]] ^= one;
+ }
+
+ for(i=0; i<removed.length; i++) {
+ filters[offset][removed[i]] ^= one;
+ }
+
+ } else {
+ // For iterables, we need to figure out if the row has been completely removed vs partially included
+ // Only count a row as added if it is not already being aggregated. Only count a row
+ // as removed if the last element being aggregated is removed.
+
+ var newAdded = [];
+ var newRemoved = [];
+ for (i = 0; i < added.length; i++) {
+ iterablesIndexCount[added[i]]++
+ iterablesIndexFilterStatus[valueIndexAdded[i]] = 0;
+ if(iterablesIndexCount[added[i]] === 1) {
+ filters[offset][added[i]] ^= one;
+ newAdded.push(added[i]);
+ }
+ }
+ for (i = 0; i < removed.length; i++) {
+ iterablesIndexCount[removed[i]]--
+ iterablesIndexFilterStatus[valueIndexRemoved[i]] = 1;
+ if(iterablesIndexCount[removed[i]] === 0) {
+ filters[offset][removed[i]] ^= one;
+ newRemoved.push(removed[i]);
+ }
+ }
+
+ added = newAdded;
+ removed = newRemoved;
+
+ // Now handle empty rows.
+ if(bounds[0] === 0 && bounds[1] === values.length) {
+ for(i = 0; i < iterablesEmptyRows.length; i++) {
+ if((filters[offset][k = iterablesEmptyRows[i]] & one)) {
+ // Was not in the filter, so set the filter and add
+ filters[offset][k] ^= one;
+ added.push(k);
+ }
+ }
+ } else {
+ // filter in place - remove empty rows if necessary
+ for(i = 0; i < iterablesEmptyRows.length; i++) {
+ if(!(filters[offset][k = iterablesEmptyRows[i]] & one)) {
+ // Was in the filter, so set the filter and remove
+ filters[offset][k] ^= one;
+ removed.push(k);
+ }
+ }
+ }
+ }
+
+ lo0 = lo1;
+ hi0 = hi1;
+ filterListeners.forEach(function(l) { l(one, offset, added, removed); });
+ triggerOnChange('filtered');
+ return dimension;
+ }
+
+ // Filters this dimension using the specified range, value, or null.
+ // If the range is null, this is equivalent to filterAll.
+ // If the range is an array, this is equivalent to filterRange.
+ // Otherwise, this is equivalent to filterExact.
+ function filter(range) {
+ return range == null
+ ? filterAll() : Array.isArray(range)
+ ? filterRange(range) : typeof range === "function"
+ ? filterFunction(range)
+ : filterExact(range);
+ }
+
+ // Filters this dimension to select the exact value.
+ function filterExact(value) {
+ filterValue = value;
+ filterValuePresent = true;
+ return filterIndexBounds((refilter = xfilterFilter.filterExact(bisect, value))(values));
+ }
+
+ // Filters this dimension to select the specified range [lo, hi].
+ // The lower bound is inclusive, and the upper bound is exclusive.
+ function filterRange(range) {
+ filterValue = range;
+ filterValuePresent = true;
+ return filterIndexBounds((refilter = xfilterFilter.filterRange(bisect, range))(values));
+ }
+
+ // Clears any filters on this dimension.
+ function filterAll() {
+ filterValue = undefined;
+ filterValuePresent = false;
+ return filterIndexBounds((refilter = xfilterFilter.filterAll)(values));
+ }
+
+ // Filters this dimension using an arbitrary function.
+ function filterFunction(f) {
+ filterValue = f;
+ filterValuePresent = true;
+
+ refilterFunction = f;
+ refilter = xfilterFilter.filterAll;
+
+ filterIndexFunction(f, false);
+
+ var bounds = refilter(values);
+ lo0 = bounds[0], hi0 = bounds[1];
+
+ return dimension;
+ }
+
+ function filterIndexFunction(f, filterAll) {
+ var i,
+ k,
+ x,
+ added = [],
+ removed = [],
+ valueIndexAdded = [],
+ valueIndexRemoved = [],
+ indexLength = values.length;
+
+ if(!iterable) {
+ for (i = 0; i < indexLength; ++i) {
+ if (!(filters[offset][k = index[i]] & one) ^ !!(x = f(values[i], i))) {
+ if (x) added.push(k);
+ else removed.push(k);
+ }
+ }
+ }
+
+ if(iterable) {
+ for(i=0; i < indexLength; ++i) {
+ if(f(values[i], i)) {
+ added.push(index[i]);
+ valueIndexAdded.push(i);
+ } else {
+ removed.push(index[i]);
+ valueIndexRemoved.push(i);
+ }
+ }
+ }
+
+ if(!iterable) {
+ for(i=0; i<added.length; i++) {
+ if(filters[offset][added[i]] & one) filters[offset][added[i]] &= zero;
+ }
+
+ for(i=0; i<removed.length; i++) {
+ if(!(filters[offset][removed[i]] & one)) filters[offset][removed[i]] |= one;
+ }
+ } else {
+
+ var newAdded = [];
+ var newRemoved = [];
+ for (i = 0; i < added.length; i++) {
+ // First check this particular value needs to be added
+ if(iterablesIndexFilterStatus[valueIndexAdded[i]] === 1) {
+ iterablesIndexCount[added[i]]++
+ iterablesIndexFilterStatus[valueIndexAdded[i]] = 0;
+ if(iterablesIndexCount[added[i]] === 1) {
+ filters[offset][added[i]] ^= one;
+ newAdded.push(added[i]);
+ }
+ }
+ }
+ for (i = 0; i < removed.length; i++) {
+ // First check this particular value needs to be removed
+ if(iterablesIndexFilterStatus[valueIndexRemoved[i]] === 0) {
+ iterablesIndexCount[removed[i]]--
+ iterablesIndexFilterStatus[valueIndexRemoved[i]] = 1;
+ if(iterablesIndexCount[removed[i]] === 0) {
+ filters[offset][removed[i]] ^= one;
+ newRemoved.push(removed[i]);
+ }
+ }
+ }
+
+ added = newAdded;
+ removed = newRemoved;
+
+ // Now handle empty rows.
+ if(filterAll) {
+ for(i = 0; i < iterablesEmptyRows.length; i++) {
+ if((filters[offset][k = iterablesEmptyRows[i]] & one)) {
+ // Was not in the filter, so set the filter and add
+ filters[offset][k] ^= one;
+ added.push(k);
+ }
+ }
+ } else {
+ // filter in place - remove empty rows if necessary
+ for(i = 0; i < iterablesEmptyRows.length; i++) {
+ if(!(filters[offset][k = iterablesEmptyRows[i]] & one)) {
+ // Was in the filter, so set the filter and remove
+ filters[offset][k] ^= one;
+ removed.push(k);
+ }
+ }
+ }
+ }
+
+ filterListeners.forEach(function(l) { l(one, offset, added, removed); });
+ triggerOnChange('filtered');
+ }
+
+ function currentFilter() {
+ return filterValue;
+ }
+
+ function hasCurrentFilter() {
+ return filterValuePresent;
+ }
+
+ // Returns the top K selected records based on this dimension's order.
+ // Note: observes this dimension's filter, unlike group and groupAll.
+ function top(k, top_offset) {
+ var array = [],
+ i = hi0,
+ j,
+ toSkip = 0;
+
+ if(top_offset && top_offset > 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)
+});