From 719fa614a395f82d81d7d98462236ebd3216225f Mon Sep 17 00:00:00 2001 From: christophe-g Date: Fri, 3 Nov 2017 15:35:08 +0100 Subject: [PATCH 1/5] added build files --- .gitignore | 2 - universe.js | 8852 +++++++++++++++++++++++++++++++++++++++++++++++ universe.min.js | 4 + 3 files changed, 8856 insertions(+), 2 deletions(-) create mode 100644 universe.js create mode 100644 universe.min.js diff --git a/.gitignore b/.gitignore index 2ce1fbb..db542fb 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,5 @@ node_modules/ npm-debug.log .coverrun coverage/coverage.html -/universe.js -/universe.min.js npm-debug.log* diff --git a/universe.js b/universe.js new file mode 100644 index 0000000..7bb20b4 --- /dev/null +++ b/universe.js @@ -0,0 +1,8852 @@ +(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.universe = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 1 ? values : keyVal +} + +function isStringSyntax(str) { + return ['$', '('].indexOf(str.charAt(0)) > -1 +} + +function parseAggregatorParams(keyString) { + var params = [] + var p1 = keyString.indexOf('(') + var p2 = keyString.indexOf(')') + var key = p1 > -1 ? keyString.substring(0, p1) : keyString + if (!aggregators[key]) { + return false + } + if (p1 > -1 && p2 > -1 && p2 > p1) { + params = keyString.substring(p1 + 1, p2).split(',') + } + + return { + aggregator: aggregators[key], + params: params + } +} + +function convertAggregatorString(keyString) { + // var obj = {} // obj is defined but not used + + // 1. unwrap top parentheses + // 2. detect arrays + + // parentheses + var outerParens = /\((.+)\)/g + // var innerParens = /\(([^\(\)]+)\)/g // innerParens is defined but not used + // comma not in () + var hasComma = /(?:\([^\(\)]*\))|(,)/g + + return JSON.parse('{' + unwrapParensAndCommas(keyString) + '}') + + function unwrapParensAndCommas(str) { + str = str.replace(' ', '') + return '"' + str.replace(outerParens, function (p, pr) { + if (hasComma.test(pr)) { + if (pr.charAt(0) === '$') { + return '":{"' + pr.replace(hasComma, function (p2/* , pr2 */) { + if (p2 === ',') { + return ',"' + } + return unwrapParensAndCommas(p2).trim() + }) + '}' + } + return ':["' + pr.replace(hasComma, function (/* p2 , pr2 */) { + return '","' + }) + '"]' + } + }) + } +} + +// Collection Aggregators + +function $sum(children) { + return children.reduce(function (a, b) { + return a + b + }, 0) +} + +function $avg(children) { + return children.reduce(function (a, b) { + return a + b + }, 0) / children.length +} + +function $max(children) { + return Math.max.apply(null, children) +} + +function $min(children) { + return Math.min.apply(null, children) +} + +function $count(children) { + return children.length +} + +/* function $med(children) { // $med is defined but not used + children.sort(function(a, b) { + return a - b + }) + var half = Math.floor(children.length / 2) + if (children.length % 2) + return children[half] + else + return (children[half - 1] + children[half]) / 2.0 +} */ + +function $first(children) { + return children[0] +} + +function $last(children) { + return children[children.length - 1] +} + +function $get(children, n) { + return children[n] +} + +function $nthLast(children, n) { + return children[children.length - n] +} + +function $nthPct(children, n) { + return children[Math.round(children.length * (n / 100))] +} + +function $map(children, n) { + return children.map(function (d) { + return d[n] + }) +} + +},{"./lodash":9}],2:[function(require,module,exports){ +'use strict' + +var Promise = require('q') +var _ = require('./lodash') + +module.exports = function (service) { + return function clear(def) { + // Clear a single or multiple column definitions + if (def) { + def = _.isArray(def) ? def : [def] + } + + if (!def) { + // Clear all of the column defenitions + return Promise.all(_.map(service.columns, disposeColumn)) + .then(function () { + service.columns = [] + return service + }) + } + + return Promise.all(_.map(def, function (d) { + if (_.isObject(d)) { + d = d.key + } + // Clear the column + var column = _.remove(service.columns, function (c) { + if (_.isArray(d)) { + return !_.xor(c.key, d).length + } + if (c.key === d) { + if (c.dynamicReference) { + return false + } + return true + } + })[0] + + if (!column) { + // console.info('Attempted to clear a column that is required for another query!', c) + return + } + + disposeColumn(column) + })) + .then(function () { + return service + }) + + function disposeColumn(column) { + var disposalActions = [] + // Dispose the dimension + if (column.removeListeners) { + disposalActions = _.map(column.removeListeners, function (listener) { + return Promise.resolve(listener()) + }) + } + var filterKey = column.key + if (column.complex === 'array') { + filterKey = JSON.stringify(column.key) + } + if (column.complex === 'function') { + filterKey = column.key.toString() + } + delete service.filters[filterKey] + if (column.dimension) { + disposalActions.push(Promise.resolve(column.dimension.dispose())) + } + return Promise.all(disposalActions) + } + } +} + +},{"./lodash":9,"q":33}],3:[function(require,module,exports){ +'use strict' + +var Promise = require('q') +var _ = require('./lodash') + +module.exports = function (service) { + var dimension = require('./dimension')(service) + + var columnFunc = column + columnFunc.find = findColumn + + return columnFunc + + function column(def) { + // Support groupAll dimension + if (_.isUndefined(def)) { + def = true + } + + // Always deal in bulk. Like Costco! + if (!_.isArray(def)) { + def = [def] + } + + // Mapp all column creation, wait for all to settle, then return the instance + return Promise.all(_.map(def, makeColumn)) + .then(function () { + return service + }) + } + + function findColumn(d) { + return _.find(service.columns, function (c) { + if (_.isArray(d)) { + return !_.xor(c.key, d).length + } + return c.key === d + }) + } + + function getType(d) { + if (_.isNumber(d)) { + return 'number' + } + if (_.isBoolean(d)) { + return 'bool' + } + if (_.isArray(d)) { + return 'array' + } + if (_.isObject(d)) { + return 'object' + } + return 'string' + } + + function makeColumn(d) { + var column = _.isObject(d) ? d : { + key: d, + } + + var existing = findColumn(column.key) + + if (existing) { + existing.temporary = false + if (existing.dynamicReference) { + existing.dynamicReference = false + } + return existing.promise + .then(function () { + return service + }) + } + + // for storing info about queries and post aggregations + column.queries = [] + service.columns.push(column) + + column.promise = Promise.try(function () { + return Promise.resolve(service.cf.all()) + }) + .then(function (all) { + var sample + + // Complex column Keys + if (_.isFunction(column.key)) { + column.complex = 'function' + sample = column.key(all[0]) + } else if (_.isString(column.key) && (column.key.indexOf('.') > -1 || column.key.indexOf('[') > -1)) { + column.complex = 'string' + sample = _.get(all[0], column.key) + } else if (_.isArray(column.key)) { + column.complex = 'array' + sample = _.values(_.pick(all[0], column.key)) + if (sample.length !== column.key.length) { + throw new Error('Column key does not exist in data!', column.key) + } + } else { + sample = all[0][column.key] + } + + // Index Column + if (!column.complex && column.key !== true && typeof sample === 'undefined') { + throw new Error('Column key does not exist in data!', column.key) + } + + // If the column exists, let's at least make sure it's marked + // as permanent. There is a slight chance it exists because + // of a filter, and the user decides to make it permanent + + if (column.key === true) { + column.type = 'all' + } else if (column.complex) { + column.type = 'complex' + } else if (column.array) { + column.type = 'array' + } else { + column.type = getType(sample) + } + + return dimension.make(column.key, column.type, column.complex) + }) + .then(function (dim) { + column.dimension = dim + column.filterCount = 0 + var stopListeningForData = service.onDataChange(buildColumnKeys) + column.removeListeners = [stopListeningForData] + + return buildColumnKeys() + + // Build the columnKeys + function buildColumnKeys(changes) { + if (column.key === true) { + return Promise.resolve() + } + + var accessor = dimension.makeAccessor(column.key, column.complex) + column.values = column.values || [] + + return Promise.try(function () { + if (changes && changes.added) { + return Promise.resolve(changes.added) + } + return Promise.resolve(column.dimension.bottom(Infinity)) + }) + .then(function (rows) { + var newValues + if (column.complex === 'string' || column.complex === 'function') { + newValues = _.map(rows, accessor) + // console.log(rows, accessor.toString(), newValues) + } else if (column.type === 'array') { + newValues = _.flatten(_.map(rows, accessor)) + } else { + newValues = _.map(rows, accessor) + } + column.values = _.uniq(column.values.concat(newValues)) + }) + } + }) + + return column.promise + .then(function () { + return service + }) + } +} + +},{"./dimension":6,"./lodash":9,"q":33}],4:[function(require,module,exports){ +'use strict' + +var Promise = require('q') +var crossfilter = require('crossfilter2') + +var _ = require('./lodash') + +module.exports = function (service) { + return { + build: build, + generateColumns: generateColumns, + add: add, + remove: remove, + } + + function build(c) { + if (_.isArray(c)) { + // This allows support for crossfilter async + return Promise.resolve(crossfilter(c)) + } + if (!c || typeof c.dimension !== 'function') { + return Promise.reject(new Error('No Crossfilter data or instance found!')) + } + return Promise.resolve(c) + } + + function generateColumns(data) { + if (!service.options.generatedColumns) { + return data + } + return _.map(data, function (d/* , i */) { + _.forEach(service.options.generatedColumns, function (val, key) { + d[key] = val(d) + }) + return d + }) + } + + function add(data) { + data = generateColumns(data) + return Promise.try(function () { + return Promise.resolve(service.cf.add(data)) + }) + .then(function () { + return Promise.serial(_.map(service.dataListeners, function (listener) { + return function () { + return listener({ + added: data + }) + } + })) + }) + .then(function () { + return service + }) + } + + function remove() { + return Promise.try(function () { + return Promise.resolve(service.cf.remove()) + }) + .then(function () { + return service + }) + } +} + +},{"./lodash":9,"crossfilter2":16,"q":33}],5:[function(require,module,exports){ +'use strict' + +var Promise = require('q') +// var _ = require('./lodash') // _ is defined but never used + +module.exports = function (service) { + return function destroy() { + return service.clear() + .then(function () { + service.cf.dataListeners = [] + service.cf.filterListeners = [] + return Promise.resolve(service.cf.remove()) + }) + .then(function () { + return service + }) + } +} + +},{"q":33}],6:[function(require,module,exports){ +'use strict' + +var Promise = require('q') +var _ = require('./lodash') + +module.exports = function (service) { + return { + make: make, + makeAccessor: makeAccessor, + } + + function make(key, type, complex) { + var accessor = makeAccessor(key, complex) + // Promise.resolve will handle promises or non promises, so + // this crossfilter async is supported if present + return Promise.resolve(service.cf.dimension(accessor, type === 'array')) + } + + function makeAccessor(key, complex) { + var accessorFunction + + if (complex === 'string') { + accessorFunction = function (d) { + return _.get(d, key) + } + } else if (complex === 'function') { + accessorFunction = key + } else if (complex === 'array') { + var arrayString = _.map(key, function (k) { + return 'd[\'' + k + '\']' + }) + accessorFunction = new Function('d', String('return ' + JSON.stringify(arrayString).replace(/"/g, ''))) // eslint-disable-line no-new-func + } else { + accessorFunction = + // Index Dimension + key === true ? function accessor(d, i) { + return i + } : + // Value Accessor Dimension + function (d) { + return d[key] + } + } + return accessorFunction + } +} + +},{"./lodash":9,"q":33}],7:[function(require,module,exports){ +'use strict' + +// var moment = require('moment') + +module.exports = { + // Getters + $field: $field, + // Booleans + $and: $and, + $or: $or, + $not: $not, + + // Expressions + $eq: $eq, + $gt: $gt, + $gte: $gte, + $lt: $lt, + $lte: $lte, + $ne: $ne, + $type: $type, + + // Array Expressions + $in: $in, + $nin: $nin, + $contains: $contains, + $excludes: $excludes, + $size: $size, +} + +// Getters +function $field(d, child) { + return d[child] +} + +// Operators + +function $and(d, child) { + child = child(d) + for (var i = 0; i < child.length; i++) { + if (!child[i]) { + return false + } + } + return true +} + +function $or(d, child) { + child = child(d) + for (var i = 0; i < child.length; i++) { + if (child[i]) { + return true + } + } + return false +} + +function $not(d, child) { + child = child(d) + for (var i = 0; i < child.length; i++) { + if (child[i]) { + return false + } + } + return true +} + +// Expressions + +function $eq(d, child) { + return d === child() +} + +function $gt(d, child) { + return d > child() +} + +function $gte(d, child) { + return d >= child() +} + +function $lt(d, child) { + return d < child() +} + +function $lte(d, child) { + return d <= child() +} + +function $ne(d, child) { + return d !== child() +} + +function $type(d, child) { + return typeof d === child() +} + +// Array Expressions + +function $in(d, child) { + return d.indexOf(child()) > -1 +} + +function $nin(d, child) { + return d.indexOf(child()) === -1 +} + +function $contains(d, child) { + return child().indexOf(d) > -1 +} + +function $excludes(d, child) { + return child().indexOf(d) === -1 +} + +function $size(d, child) { + return d.length === child() +} + +},{}],8:[function(require,module,exports){ +'use strict' + +var Promise = require('q') +var _ = require('./lodash') + +var expressions = require('./expressions') +var aggregation = require('./aggregation') + +module.exports = function (service) { + return { + filter: filter, + filterAll: filterAll, + applyFilters: applyFilters, + makeFunction: makeFunction, + scanForDynamicFilters: scanForDynamicFilters + } + + function filter(column, fil, isRange, replace) { + return getColumn(column) + .then(function (column) { + // Clone a copy of the new filters + var newFilters = _.assign({}, service.filters) + // Here we use the registered column key despite the filter key passed, just in case the filter key's ordering is ordered differently :) + var filterKey = column.key + if (column.complex === 'array') { + filterKey = JSON.stringify(column.key) + } + if (column.complex === 'function') { + filterKey = column.key.toString() + } + // Build the filter object + newFilters[filterKey] = buildFilterObject(fil, isRange, replace) + + return applyFilters(newFilters) + }) + } + + function getColumn(column) { + var exists = service.column.find(column) + // If the filters dimension doesn't exist yet, try and create it + return Promise.try(function () { + if (!exists) { + return service.column({ + key: column, + temporary: true, + }) + .then(function () { + // It was able to be created, so retrieve and return it + return service.column.find(column) + }) + } + // It exists, so just return what we found + return exists + }) + } + + function filterAll(fils) { + // If empty, remove all filters + if (!fils) { + service.columns.forEach(function (col) { + col.dimension.filterAll() + }) + return applyFilters({}) + } + + // Clone a copy for the new filters + var newFilters = _.assign({}, service.filters) + + var ds = _.map(fils, function (fil) { + return getColumn(fil.column) + .then(function (column) { + // Here we use the registered column key despite the filter key passed, just in case the filter key's ordering is ordered differently :) + var filterKey = column.complex ? JSON.stringify(column.key) : column.key + // Build the filter object + newFilters[filterKey] = buildFilterObject(fil.value, fil.isRange, fil.replace) + }) + }) + + return Promise.all(ds) + .then(function () { + return applyFilters(newFilters) + }) + } + + function buildFilterObject(fil, isRange, replace) { + if (_.isUndefined(fil)) { + return false + } + if (_.isFunction(fil)) { + return { + value: fil, + function: fil, + replace: true, + type: 'function', + } + } + if (_.isObject(fil)) { + return { + value: fil, + function: makeFunction(fil), + replace: true, + type: 'function' + } + } + if (_.isArray(fil)) { + return { + value: fil, + replace: isRange || replace, + type: isRange ? 'range' : 'inclusive', + } + } + return { + value: fil, + replace: replace, + type: 'exact', + } + } + + function applyFilters(newFilters) { + var ds = _.map(newFilters, function (fil, i) { + var existing = service.filters[i] + // Filters are the same, so no change is needed on this column + if (fil === existing) { + return Promise.resolve() + } + var column + // Retrieve complex columns by decoding the column key as json + if (i.charAt(0) === '[') { + column = service.column.find(JSON.parse(i)) + } else { + // Retrieve the column normally + column = service.column.find(i) + } + + // Toggling a filter value is a bit different from replacing them + if (fil && existing && !fil.replace) { + newFilters[i] = fil = toggleFilters(fil, existing) + } + + // If no filter, remove everything from the dimension + if (!fil) { + return Promise.resolve(column.dimension.filterAll()) + } + if (fil.type === 'exact') { + return Promise.resolve(column.dimension.filterExact(fil.value)) + } + if (fil.type === 'range') { + return Promise.resolve(column.dimension.filterRange(fil.value)) + } + if (fil.type === 'inclusive') { + return Promise.resolve(column.dimension.filterFunction(function (d) { + return fil.value.indexOf(d) > -1 + })) + } + if (fil.type === 'function') { + return Promise.resolve(column.dimension.filterFunction(fil.function)) + } + // By default if something craps up, just remove all filters + return Promise.resolve(column.dimension.filterAll()) + }) + + return Promise.all(ds) + .then(function () { + // Save the new filters satate + service.filters = newFilters + + // Pluck and remove falsey filters from the mix + var tryRemoval = [] + _.forEach(service.filters, function (val, key) { + if (!val) { + tryRemoval.push({ + key: key, + val: val, + }) + delete service.filters[key] + } + }) + + // If any of those filters are the last dependency for the column, then remove the column + return Promise.all(_.map(tryRemoval, function (v) { + var column = service.column.find((v.key.charAt(0) === '[') ? JSON.parse(v.key) : v.key) + if (column.temporary && !column.dynamicReference) { + return service.clear(column.key) + } + })) + }) + .then(function () { + // Call the filterListeners and wait for their return + return Promise.all(_.map(service.filterListeners, function (listener) { + return listener() + })) + }) + .then(function () { + return service + }) + } + + function toggleFilters(fil, existing) { + // Exact from Inclusive + if (fil.type === 'exact' && existing.type === 'inclusive') { + fil.value = _.xor([fil.value], existing.value) + } else if (fil.type === 'inclusive' && existing.type === 'exact') { // Inclusive from Exact + fil.value = _.xor(fil.value, [existing.value]) + } else if (fil.type === 'inclusive' && existing.type === 'inclusive') { // Inclusive / Inclusive Merge + fil.value = _.xor(fil.value, existing.value) + } else if (fil.type === 'exact' && existing.type === 'exact') { // Exact / Exact + // If the values are the same, remove the filter entirely + if (fil.value === existing.value) { + return false + } + // They they are different, make an array + fil.value = [fil.value, existing.value] + } + + // Set the new type based on the merged values + if (!fil.value.length) { + fil = false + } else if (fil.value.length === 1) { + fil.type = 'exact' + fil.value = fil.value[0] + } else { + fil.type = 'inclusive' + } + + return fil + } + + function scanForDynamicFilters(query) { + // Here we check to see if there are any relative references to the raw data + // being used in the filter. If so, we need to build those dimensions and keep + // them updated so the filters can be rebuilt if needed + // The supported keys right now are: $column, $data + var columns = [] + walk(query.filter) + return columns + + function walk(obj) { + _.forEach(obj, function (val, key) { + // find the data references, if any + var ref = findDataReferences(val, key) + if (ref) { + columns.push(ref) + } + // if it's a string + if (_.isString(val)) { + ref = findDataReferences(null, val) + if (ref) { + columns.push(ref) + } + } + // If it's another object, keep looking + if (_.isObject(val)) { + walk(val) + } + }) + } + } + + function findDataReferences(val, key) { + // look for the $data string as a value + if (key === '$data') { + return true + } + + // look for the $column key and it's value as a string + if (key && key === '$column') { + if (_.isString(val)) { + return val + } + console.warn('The value for filter "$column" must be a valid column key', val) + return false + } + } + + function makeFunction(obj, isAggregation) { + var subGetters + + // Detect raw $data reference + if (_.isString(obj)) { + var dataRef = findDataReferences(null, obj) + if (dataRef) { + var data = service.cf.all() + return function () { + return data + } + } + } + + if (_.isString(obj) || _.isNumber(obj) || _.isBoolean(obj)) { + return function (d) { + if (typeof d === 'undefined') { + return obj + } + return expressions.$eq(d, function () { + return obj + }) + } + } + + // If an array, recurse into each item and return as a map + if (_.isArray(obj)) { + subGetters = _.map(obj, function (o) { + return makeFunction(o, isAggregation) + }) + return function (d) { + return subGetters.map(function (s) { + return s(d) + }) + } + } + + // If object, return a recursion function that itself, returns the results of all of the object keys + if (_.isObject(obj)) { + subGetters = _.map(obj, function (val, key) { + // Get the child + var getSub = makeFunction(val, isAggregation) + + // Detect raw $column references + var dataRef = findDataReferences(val, key) + if (dataRef) { + var column = service.column.find(dataRef) + var data = column.values + return function () { + return data + } + } + + // If expression, pass the parentValue and the subGetter + if (expressions[key]) { + return function (d) { + return expressions[key](d, getSub) + } + } + + var aggregatorObj = aggregation.parseAggregatorParams(key) + if (aggregatorObj) { + // Make sure that any further operations are for aggregations + // and not filters + isAggregation = true + // here we pass true to makeFunction which denotes that + // an aggregatino chain has started and to stop using $AND + getSub = makeFunction(val, isAggregation) + // If it's an aggregation object, be sure to pass in the children, and then any additional params passed into the aggregation string + return function () { + return aggregatorObj.aggregator.apply(null, [getSub()].concat(aggregatorObj.params)) + } + } + + // It must be a string then. Pluck that string key from parent, and pass it as the new value to the subGetter + return function (d) { + d = d[key] + return getSub(d, getSub) + } + }) + + // All object expressions are basically AND's + // Return AND with a map of the subGetters + if (isAggregation) { + if (subGetters.length === 1) { + return function (d) { + return subGetters[0](d) + } + } + return function (d) { + return _.map(subGetters, function (getSub) { + return getSub(d) + }) + } + } + return function (d) { + return expressions.$and(d, function (d) { + return _.map(subGetters, function (getSub) { + return getSub(d) + }) + }) + } + } + + console.log('no expression found for ', obj) + return false + } +} + +},{"./aggregation":1,"./expressions":7,"./lodash":9,"q":33}],9:[function(require,module,exports){ +/* eslint no-prototype-builtins: 0 */ +'use strict' + +module.exports = { + assign: assign, + find: find, + remove: remove, + isArray: isArray, + isObject: isObject, + isBoolean: isBoolean, + isString: isString, + isNumber: isNumber, + isFunction: isFunction, + get: get, + set: set, + map: map, + keys: keys, + sortBy: sortBy, + forEach: forEach, + isUndefined: isUndefined, + pick: pick, + xor: xor, + clone: clone, + isEqual: isEqual, + replaceArray: replaceArray, + uniq: uniq, + flatten: flatten, + sort: sort, + values: values, + recurseObject: recurseObject, +} + +function assign(out) { + out = out || {} + for (var i = 1; i < arguments.length; i++) { + if (!arguments[i]) { + continue + } + for (var key in arguments[i]) { + if (arguments[i].hasOwnProperty(key)) { + out[key] = arguments[i][key] + } + } + } + return out +} + +function find(a, b) { + return a.find(b) +} + +function remove(a, b) { + return a.filter(function (o, i) { + var r = b(o) + if (r) { + a.splice(i, 1) + return true + } + return false + }) +} + +function isArray(a) { + return Array.isArray(a) +} + +function isObject(d) { + return typeof d === 'object' && !isArray(d) +} + +function isBoolean(d) { + return typeof d === 'boolean' +} + +function isString(d) { + return typeof d === 'string' +} + +function isNumber(d) { + return typeof d === 'number' +} + +function isFunction(a) { + return typeof a === 'function' +} + +function get(a, b) { + if (isArray(b)) { + b = b.join('.') + } + return b + .replace('[', '.').replace(']', '') + .split('.') + .reduce( + function (obj, property) { + return obj[property] + }, a + ) +} + +function set(obj, prop, value) { + if (typeof prop === 'string') { + prop = prop + .replace('[', '.').replace(']', '') + .split('.') + } + if (prop.length > 1) { + var e = prop.shift() + assign(obj[e] = + Object.prototype.toString.call(obj[e]) === '[object Object]' ? obj[e] : {}, + prop, + value) + } else { + obj[prop[0]] = value + } +} + +function map(a, b) { + var m + var key + if (isFunction(b)) { + if (isObject(a)) { + m = [] + for (key in a) { + if (a.hasOwnProperty(key)) { + m.push(b(a[key], key, a)) + } + } + return m + } + return a.map(b) + } + if (isObject(a)) { + m = [] + for (key in a) { + if (a.hasOwnProperty(key)) { + m.push(a[key]) + } + } + return m + } + return a.map(function (aa) { + return aa[b] + }) +} + +function keys(obj) { + return Object.keys(obj) +} + +function sortBy(a, b) { + if (isFunction(b)) { + return a.sort(function (aa, bb) { + if (b(aa) > b(bb)) { + return 1 + } + if (b(aa) < b(bb)) { + return -1 + } + // a must be equal to b + return 0 + }) + } +} + +function forEach(a, b) { + if (isObject(a)) { + for (var key in a) { + if (a.hasOwnProperty(key)) { + b(a[key], key, a) + } + } + return + } + if (isArray(a)) { + return a.forEach(b) + } +} + +function isUndefined(a) { + return typeof a === 'undefined' +} + +function pick(a, b) { + var c = {} + forEach(b, function (bb) { + if (typeof a[bb] !== 'undefined') { + c[bb] = a[bb] + } + }) + return c +} + +function xor(a, b) { + var unique = [] + forEach(a, function (aa) { + if (b.indexOf(aa) === -1) { + return unique.push(aa) + } + }) + forEach(b, function (bb) { + if (a.indexOf(bb) === -1) { + return unique.push(bb) + } + }) + return unique +} + +function clone(a) { + return JSON.parse(JSON.stringify(a, function replacer(key, value) { + if (typeof value === 'function') { + return value.toString() + } + return value + })) +} + +function isEqual(x, y) { + if ((typeof x === 'object' && x !== null) && (typeof y === 'object' && y !== null)) { + if (Object.keys(x).length !== Object.keys(y).length) { + return false + } + + for (var prop in x) { + if (y.hasOwnProperty(prop)) { + if (!isEqual(x[prop], y[prop])) { + return false + } + } + return false + } + + return true + } else if (x !== y) { + return false + } + return true +} + +function replaceArray(a, b) { + var al = a.length + var bl = b.length + if (al > bl) { + a.splice(bl, al - bl) + } else if (al < bl) { + a.push.apply(a, new Array(bl - al)) + } + forEach(a, function (val, key) { + a[key] = b[key] + }) + return a +} + +function uniq(a) { + var seen = new Set() + return a.filter(function (item) { + var allow = false + if (!seen.has(item)) { + seen.add(item) + allow = true + } + return allow + }) +} + +function flatten(aa) { + var flattened = [] + for (var i = 0; i < aa.length; ++i) { + var current = aa[i] + for (var j = 0; j < current.length; ++j) { + flattened.push(current[j]) + } + } + return flattened +} + +function sort(arr) { + for (var i = 1; i < arr.length; i++) { + var tmp = arr[i] + var j = i + while (arr[j - 1] > tmp) { + arr[j] = arr[j - 1]; + --j + } + arr[j] = tmp + } + + return arr +} + +function values(a) { + var values = [] + for (var key in a) { + if (a.hasOwnProperty(key)) { + values.push(a[key]) + } + } + return values +} + +function recurseObject(obj, cb) { + _recurseObject(obj, []) + return obj + function _recurseObject(obj, path) { + for (var k in obj) { // eslint-disable-line guard-for-in + var newPath = clone(path) + newPath.push(k) + if (typeof obj[k] === 'object' && obj[k] !== null) { + _recurseObject(obj[k], newPath) + } else { + if (!obj.hasOwnProperty(k)) { + continue + } + cb(obj[k], k, newPath) + } + } + } +} + +},{}],10:[function(require,module,exports){ +'use strict' + +var Promise = require('q') +var _ = require('./lodash') + +var aggregation = require('./aggregation') + +module.exports = function (/* service */) { + return { + post: post, + sortByKey: sortByKey, + limit: limit, + squash: squash, + change: change, + changeMap: changeMap, + } + + function post(query, parent, cb) { + query.data = cloneIfLocked(parent) + return Promise.resolve(cb(query, parent)) + } + + function sortByKey(query, parent, desc) { + query.data = cloneIfLocked(parent) + query.data = _.sortBy(query.data, function (d) { + return d.key + }) + if (desc) { + query.data.reverse() + } + } + + // Limit results to n, or from start to end + function limit(query, parent, start, end) { + query.data = cloneIfLocked(parent) + if (_.isUndefined(end)) { + end = start || 0 + start = 0 + } else { + start = start || 0 + end = end || query.data.length + } + query.data = query.data.splice(start, end - start) + } + + // Squash results to n, or from start to end + function squash(query, parent, start, end, aggObj, label) { + query.data = cloneIfLocked(parent) + start = start || 0 + end = end || query.data.length + var toSquash = query.data.splice(start, end - start) + var squashed = { + key: label || 'Other', + value: {} + } + _.recurseObject(aggObj, function (val, key, path) { + var items = [] + _.forEach(toSquash, function (record) { + items.push(_.get(record.value, path)) + }) + _.set(squashed.value, path, aggregation.aggregators[val](items)) + }) + query.data.splice(start, 0, squashed) + } + + function change(query, parent, start, end, aggObj) { + query.data = cloneIfLocked(parent) + start = start || 0 + end = end || query.data.length + var obj = { + key: [query.data[start].key, query.data[end].key], + value: {} + } + _.recurseObject(aggObj, function (val, key, path) { + var changePath = _.clone(path) + changePath.pop() + changePath.push(key + 'Change') + _.set(obj.value, changePath, _.get(query.data[end].value, path) - _.get(query.data[start].value, path)) + }) + query.data = obj + } + + function changeMap(query, parent, aggObj, defaultNull) { + defaultNull = _.isUndefined(defaultNull) ? 0 : defaultNull + query.data = cloneIfLocked(parent) + _.recurseObject(aggObj, function (val, key, path) { + var changePath = _.clone(path) + var fromStartPath = _.clone(path) + var fromEndPath = _.clone(path) + + changePath.pop() + fromStartPath.pop() + fromEndPath.pop() + + changePath.push(key + 'Change') + fromStartPath.push(key + 'ChangeFromStart') + fromEndPath.push(key + 'ChangeFromEnd') + + var start = _.get(query.data[0].value, path, defaultNull) + var end = _.get(query.data[query.data.length - 1].value, path, defaultNull) + + _.forEach(query.data, function (record, i) { + var previous = query.data[i - 1] || query.data[0] + _.set(query.data[i].value, changePath, _.get(record.value, path, defaultNull) - (previous ? _.get(previous.value, path, defaultNull) : defaultNull)) + _.set(query.data[i].value, fromStartPath, _.get(record.value, path, defaultNull) - start) + _.set(query.data[i].value, fromEndPath, _.get(record.value, path, defaultNull) - end) + }) + }) + } +} + +function cloneIfLocked(parent) { + return parent.locked ? _.clone(parent.data) : parent.data +} + +},{"./aggregation":1,"./lodash":9,"q":33}],11:[function(require,module,exports){ +'use strict' + +var Promise = require('q') +var _ = require('./lodash') + +Promise.serial = serial + +var isPromiseLike = function (obj) { + return obj && _.isFunction(obj.then) +} + +function serial(tasks) { + // Fake a "previous task" for our initial iteration + var prevPromise + var error = new Error() + _.forEach(tasks, function (task, key) { + var success = task.success || task + var fail = task.fail + var notify = task.notify + var nextPromise + + // First task + if (!prevPromise) { // eslint-disable-line no-negated-condition + nextPromise = success() + if (!isPromiseLike(nextPromise)) { + error.message = 'Task ' + key + ' did not return a promise.' + throw error + } + } else { + // Wait until the previous promise has resolved or rejected to execute the next task + nextPromise = prevPromise.then( + /* success */ + function (data) { + if (!success) { + return data + } + var ret = success(data) + if (!isPromiseLike(ret)) { + error.message = 'Task ' + key + ' did not return a promise.' + throw error + } + return ret + }, + /* failure */ + function (reason) { + if (!fail) { + return Promise.reject(reason) + } + var ret = fail(reason) + if (!isPromiseLike(ret)) { + error.message = 'Fail for task ' + key + ' did not return a promise.' + throw error + } + return ret + }, + notify) + } + prevPromise = nextPromise + }) + + return prevPromise || Promise.when() +} + +},{"./lodash":9,"q":33}],12:[function(require,module,exports){ +'use strict' + +var Promise = require('q') +var _ = require('./lodash') + +module.exports = function (service) { + var reductiofy = require('./reductiofy')(service) + var filters = require('./filters')(service) + var postAggregation = require('./postAggregation')(service) + + var postAggregationMethods = _.keys(postAggregation) + + return function doQuery(queryObj) { + var queryHash = JSON.stringify(queryObj) + + // Attempt to reuse an exact copy of this query that is present elsewhere + for (var i = 0; i < service.columns.length; i++) { + for (var j = 0; j < service.columns[i].queries.length; j++) { + if (service.columns[i].queries[j].hash === queryHash) { + return Promise.try(function () { // eslint-disable-line no-loop-func + return service.columns[i].queries[j] + }) + } + } + } + + var query = { + // Original query passed in to query method + original: queryObj, + hash: queryHash + } + + // Default queryObj + if (_.isUndefined(query.original)) { + query.original = {} + } + // Default select + if (_.isUndefined(query.original.select)) { + query.original.select = { + $count: true + } + } + // Default to groupAll + query.original.groupBy = query.original.groupBy || true + + // Attach the query api to the query object + query = newQueryObj(query) + + return createColumn(query) + .then(makeCrossfilterGroup) + .then(buildRequiredColumns) + .then(setupDataListeners) + .then(applyQuery) + + function createColumn(query) { + // Ensure column is created + return service.column({ + key: query.original.groupBy, + type: _.isUndefined(query.type) ? null : query.type, + array: Boolean(query.array) + }) + .then(function () { + // Attach the column to the query + var column = service.column.find(query.original.groupBy) + query.column = column + column.queries.push(query) + column.removeListeners.push(function () { + return query.clear() + }) + return query + }) + } + + function makeCrossfilterGroup(query) { + // Create the grouping on the columns dimension + // Using Promise Resolve allows support for crossfilter async + // TODO check if query already exists, and use the same base query // if possible + return Promise.resolve(query.column.dimension.group()) + .then(function (g) { + query.group = g + return query + }) + } + + function buildRequiredColumns(query) { + var requiredColumns = filters.scanForDynamicFilters(query.original) + // We need to scan the group for any filters that would require + // the group to be rebuilt when data is added or removed in any way. + if (requiredColumns.length) { + return Promise.all(_.map(requiredColumns, function (columnKey) { + return service.column({ + key: columnKey, + dynamicReference: query.group + }) + })) + .then(function () { + return query + }) + } + return query + } + + function setupDataListeners(query) { + // Here, we create a listener to recreate and apply the reducer to + // the group anytime underlying data changes + var stopDataListen = service.onDataChange(function () { + return applyQuery(query) + }) + query.removeListeners.push(stopDataListen) + + // This is a similar listener for filtering which will (if needed) + // run any post aggregations on the data after each filter action + var stopFilterListen = service.onFilter(function () { + return postAggregate(query) + }) + query.removeListeners.push(stopFilterListen) + + return query + } + + function applyQuery(query) { + return buildReducer(query) + .then(applyReducer) + .then(attachData) + .then(postAggregate) + } + + function buildReducer(query) { + return reductiofy(query.original) + .then(function (reducer) { + query.reducer = reducer + return query + }) + } + + function applyReducer(query) { + return Promise.resolve(query.reducer(query.group)) + .then(function () { + return query + }) + } + + function attachData(query) { + return Promise.resolve(query.group.all()) + .then(function (data) { + query.data = data + return query + }) + } + + function postAggregate(query) { + if (query.postAggregations.length > 1) { + // If the query is used by 2+ post aggregations, we need to lock + // it against getting mutated by the post-aggregations + query.locked = true + } + return Promise.all(_.map(query.postAggregations, function (post) { + return post() + })) + .then(function () { + return query + }) + } + + function newQueryObj(q, parent) { + var locked = false + if (!parent) { + parent = q + q = {} + locked = true + } + + // Assign the regular query properties + _.assign(q, { + // The Universe for continuous promise chaining + universe: service, + // Crossfilter instance + crossfilter: service.cf, + + // parent Information + parent: parent, + column: parent.column, + dimension: parent.dimension, + group: parent.group, + reducer: parent.reducer, + original: parent.original, + hash: parent.hash, + + // It's own removeListeners + removeListeners: [], + + // It's own postAggregations + postAggregations: [], + + // Data method + locked: locked, + lock: lock, + unlock: unlock, + // Disposal method + clear: clearQuery, + }) + + _.forEach(postAggregationMethods, function (method) { + q[method] = postAggregateMethodWrap(postAggregation[method]) + }) + + return q + + function lock(set) { + if (!_.isUndefined(set)) { + q.locked = Boolean(set) + return + } + q.locked = true + } + + function unlock() { + q.locked = false + } + + function clearQuery() { + _.forEach(q.removeListeners, function (l) { + l() + }) + return Promise.try(function () { + return q.group.dispose() + }) + .then(function () { + q.column.queries.splice(q.column.queries.indexOf(q), 1) + // Automatically recycle the column if there are no queries active on it + if (!q.column.queries.length) { + return service.clear(q.column.key) + } + }) + .then(function () { + return service + }) + } + + function postAggregateMethodWrap(postMethod) { + return function () { + var args = Array.prototype.slice.call(arguments) + var sub = {} + newQueryObj(sub, q) + args.unshift(sub, q) + + q.postAggregations.push(function () { + Promise.resolve(postMethod.apply(null, args)) + .then(postAggregateChildren) + }) + + return Promise.resolve(postMethod.apply(null, args)) + .then(postAggregateChildren) + + function postAggregateChildren() { + return postAggregate(sub) + .then(function () { + return sub + }) + } + } + } + } + } +} + +},{"./filters":8,"./lodash":9,"./postAggregation":10,"./reductiofy":14,"q":33}],13:[function(require,module,exports){ +'use strict' + +// var _ = require('./lodash') // _ is defined but never used + +module.exports = { + shorthandLabels: { + $count: 'count', + $sum: 'sum', + $avg: 'avg', + $min: 'min', + $max: 'max', + $med: 'med', + $sumSq: 'sumSq', + $std: 'std', + }, + aggregators: { + $count: $count, + $sum: $sum, + $avg: $avg, + $min: $min, + $max: $max, + $med: $med, + $sumSq: $sumSq, + $std: $std, + $valueList: $valueList, + $dataList: $dataList, + } +} + +// Aggregators + +function $count(reducer/* , value */) { + return reducer.count(true) +} + +function $sum(reducer, value) { + return reducer.sum(value) +} + +function $avg(reducer, value) { + return reducer.avg(value) +} + +function $min(reducer, value) { + return reducer.min(value) +} + +function $max(reducer, value) { + return reducer.max(value) +} + +function $med(reducer, value) { + return reducer.median(value) +} + +function $sumSq(reducer, value) { + return reducer.sumOfSq(value) +} + +function $std(reducer, value) { + return reducer.std(value) +} + +function $valueList(reducer, value) { + return reducer.valueList(value) +} + +function $dataList(reducer/* , value */) { + return reducer.dataList(true) +} + +// TODO histograms +// TODO exceptions + +},{}],14:[function(require,module,exports){ +'use strict' + +var reductio = require('reductio') + +var _ = require('./lodash') +var rAggregators = require('./reductioAggregators') +// var expressions = require('./expressions') // exporession is defined but never used +var aggregation = require('./aggregation') + +module.exports = function (service) { + var filters = require('./filters')(service) + + return function reductiofy(query) { + var reducer = reductio() + // var groupBy = query.groupBy // groupBy is defined but never used + aggregateOrNest(reducer, query.select) + + if (query.filter) { + var filterFunction = filters.makeFunction(query.filter) + if (filterFunction) { + reducer.filter(filterFunction) + } + } + + return Promise.resolve(reducer) + + // This function recursively find the first level of reductio methods in + // each object and adds that reduction method to reductio + function aggregateOrNest(reducer, selects) { + // Sort so nested values are calculated last by reductio's .value method + var sortedSelectKeyValue = _.sortBy( + _.map(selects, function (val, key) { + return { + key: key, + value: val + } + }), + function (s) { + if (rAggregators.aggregators[s.key]) { + return 0 + } + return 1 + }) + + // dive into each key/value + return _.forEach(sortedSelectKeyValue, function (s) { + // Found a Reductio Aggregation + if (rAggregators.aggregators[s.key]) { + // Build the valueAccessorFunction + var accessor = aggregation.makeValueAccessor(s.value) + // Add the reducer with the ValueAccessorFunction to the reducer + reducer = rAggregators.aggregators[s.key](reducer, accessor) + return + } + + // Found a top level key value that is not an aggregation or a + // nested object. This is unacceptable. + if (!_.isObject(s.value)) { + console.error('Nested selects must be an object', s.key) + return + } + + // It's another nested object, so just repeat this process on it + reducer = aggregateOrNest(reducer.value(s.key), s.value) + }) + } + } +} + +},{"./aggregation":1,"./filters":8,"./lodash":9,"./reductioAggregators":13,"reductio":54}],15:[function(require,module,exports){ +'use strict' + +require('./q.serial') + +// var Promise = require('q') // Promise is defined but never used +var _ = require('./lodash') + +module.exports = universe + +function universe(data, options) { + var service = { + options: _.assign({}, options), + columns: [], + filters: {}, + dataListeners: [], + filterListeners: [], + } + + var cf = require('./crossfilter')(service) + var filters = require('./filters')(service) + + data = cf.generateColumns(data) + + return cf.build(data) + .then(function (data) { + service.cf = data + return _.assign(service, { + add: cf.add, + remove: cf.remove, + column: require('./column')(service), + query: require('./query')(service), + filter: filters.filter, + filterAll: filters.filterAll, + applyFilters: filters.applyFilters, + clear: require('./clear')(service), + destroy: require('./destroy')(service), + onDataChange: onDataChange, + onFilter: onFilter, + }) + }) + + function onDataChange(cb) { + service.dataListeners.push(cb) + return function () { + service.dataListeners.splice(service.dataListeners.indexOf(cb), 1) + } + } + + function onFilter(cb) { + service.filterListeners.push(cb) + return function () { + service.filterListeners.splice(service.filterListeners.indexOf(cb), 1) + } + } +} + +},{"./clear":2,"./column":3,"./crossfilter":4,"./destroy":5,"./filters":8,"./lodash":9,"./q.serial":11,"./query":12}],16:[function(require,module,exports){ +module.exports = require("./src/crossfilter").crossfilter; + +},{"./src/crossfilter":20}],17:[function(require,module,exports){ +module.exports={ + "_args": [ + [ + { + "raw": "crossfilter2@1.4.0-alpha.6", + "scope": null, + "escapedName": "crossfilter2", + "name": "crossfilter2", + "rawSpec": "1.4.0-alpha.6", + "spec": "1.4.0-alpha.6", + "type": "version" + }, + "/home/christophe/Programming/Polymer/shared/bower_components_dev/universe" + ] + ], + "_from": "crossfilter2@1.4.0-alpha.6", + "_id": "crossfilter2@1.4.0-alpha.6", + "_inCache": true, + "_installable": true, + "_location": "/crossfilter2", + "_nodeVersion": "5.10.1", + "_npmOperationalInternal": { + "host": "packages-12-west.internal.npmjs.com", + "tmp": "tmp/crossfilter2-1.4.0-alpha.6.tgz_1463519571786_0.49269671249203384" + }, + "_npmUser": { + "name": "esjewett", + "email": "esjewett@gmail.com" + }, + "_npmVersion": "3.8.3", + "_phantomChildren": {}, + "_requested": { + "raw": "crossfilter2@1.4.0-alpha.6", + "scope": null, + "escapedName": "crossfilter2", + "name": "crossfilter2", + "rawSpec": "1.4.0-alpha.6", + "spec": "1.4.0-alpha.6", + "type": "version" + }, + "_requiredBy": [ + "/", + "/reductio" + ], + "_resolved": "https://registry.npmjs.org/crossfilter2/-/crossfilter2-1.4.0-alpha.6.tgz", + "_shasum": "f0197c6fab2d6a583b51254bfc6357093f80521b", + "_shrinkwrap": null, + "_spec": "crossfilter2@1.4.0-alpha.6", + "_where": "/home/christophe/Programming/Polymer/shared/bower_components_dev/universe", + "author": { + "name": "Mike Bostock", + "url": "http://bost.ocks.org/mike" + }, + "bugs": { + "url": "https://github.com/crossfilter/crossfilter/issues" + }, + "contributors": [ + { + "name": "Jason Davies", + "url": "http://www.jasondavies.com/" + } + ], + "dependencies": { + "lodash.result": "^4.4.0" + }, + "description": "Fast multidimensional filtering for coordinated views.", + "devDependencies": { + "browserify": "^13.0.0", + "d3": "3.5", + "package-json-versionify": "1.0.2", + "uglify-js": "2.4.0", + "vows": "0.7.0" + }, + "directories": {}, + "dist": { + "shasum": "f0197c6fab2d6a583b51254bfc6357093f80521b", + "tarball": "https://registry.npmjs.org/crossfilter2/-/crossfilter2-1.4.0-alpha.6.tgz" + }, + "files": [ + "src", + "index.js", + "crossfilter.js", + "crossfilter.min.js" + ], + "gitHead": "509a96798f5153a58d1b6cae5fb3e7893129ce7c", + "homepage": "http://crossfilter.github.com/crossfilter/", + "keywords": [ + "analytics", + "visualization", + "crossfilter" + ], + "main": "./index.js", + "maintainers": [ + { + "name": "esjewett", + "email": "esjewett@gmail.com" + }, + { + "name": "gordonwoodhull", + "email": "gordon@woodhull.com" + }, + { + "name": "tannerlinsley", + "email": "tannerlinsley@gmail.com" + } + ], + "name": "crossfilter2", + "optionalDependencies": {}, + "readme": "ERROR: No README data found!", + "repository": { + "type": "git", + "url": "git+ssh://git@github.com/crossfilter/crossfilter.git" + }, + "scripts": { + "benchmark": "node test/benchmark.js", + "build": "browserify index.js -t package-json-versionify --standalone crossfilter -o crossfilter.js && uglifyjs --compress --mangle --screw-ie8 crossfilter.js -o crossfilter.min.js", + "clean": "rm -f crossfilter.js crossfilter.min.js", + "test": "vows --verbose" + }, + "version": "1.4.0-alpha.6" +} + +},{}],18:[function(require,module,exports){ +if (typeof Uint8Array !== "undefined") { + crossfilter_array8 = function(n) { return new Uint8Array(n); }; + crossfilter_array16 = function(n) { return new Uint16Array(n); }; + crossfilter_array32 = function(n) { return new Uint32Array(n); }; + + crossfilter_arrayLengthen = function(array, length) { + if (array.length >= length) return array; + var copy = new array.constructor(length); + copy.set(array); + return copy; + }; + + 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 +}; + +},{}],19:[function(require,module,exports){ +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":24}],20:[function(require,module,exports){ +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'); +// 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, + 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. + function removeData() { + var newIndex = crossfilter_index(n, n), + removed = []; + for (var i = 0, j = 0; i < n; ++i) { + if (!filters.zero(i)) newIndex[i] = j++; + else removed.push(i); + } + + // 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 i = 0, j = 0; i < n; ++i) { + if (!filters.zero(i)) { + if (i !== j) filters.copy(j, i), data[j] = data[i]; + ++j; + } + } + + data.length = n = j; + filters.truncate(j); + triggerOnChange('dataRemoved'); + } + + // 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 n, + d, + id, + len, + mask = Array(filters.subarrays); + for (n = 0; n < filters.subarrays; n++) { mask[n] = ~0; } + if (ignore_dimensions) { + for (d = 0, len = ignore_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 = ignore_dimensions[d].id(); + mask[id >> 7] &= ~(0x1 << (id & 0x3f)); + } + } + 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, + 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, // value rank ↦ object id + oldValues, // temporary array storing previously-added values + oldIndex, // temporary array storing previously-added index + newValues, // temporary array storing newly-added values + newIndex, // temporary array storing newly-added index + iterablesIndexCount, + newIterablesIndexCount, + iterablesIndexFilterStatus, + newIterablesIndexFilterStatus, + oldIterablesIndexFilterStatus, + iterablesEmptyRows, + sort = quicksort.by(function(i) { return newValues[i]; }), + refilter = xfilterFilter.filterAll, // for recomputing filter + refilterFunction, // the custom filter function in use + indexListeners = [], // when data is added + dimensionGroups = [], + lo0 = 0, + hi0 = 0, + t = 0; + + // 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 (i = 0; i < newData.length; i++) { + for(j = 0, k = value(newData[i]); j < k.length; j++) { + t++; + } + } + + newValues = []; + newIterablesIndexCount = crossfilter_range(newData.length); + newIterablesIndexFilterStatus = crossfilter_index(t,1); + iterablesEmptyRows = []; + var unsortedIndex = crossfilter_range(t); + + for (l = 0, i = 0; i < newData.length; i++) { + k = value(newData[i]) + // + if(!k.length){ + newIterablesIndexCount[i] = 0; + iterablesEmptyRows.push(i); + continue; + } + newIterablesIndexCount[i] = k.length + for (j = 0; j < k.length; j++) { + newValues.push(k[j]); + unsortedIndex[l] = i; + 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 (i = 0; i < n1; ++i) { + if (!refilterFunction(newValues[i], i)) { + filters[offset][newIndex[i] + n0] |= one; + if(iterable) newIterablesIndexFilterStatus[i] = 1; + } + } + } else { + for (i = 0; i < lo1; ++i) { + filters[offset][newIndex[i] + n0] |= one; + if(iterable) newIterablesIndexFilterStatus[i] = 1; + } + for (i = hi1; i < n1; ++i) { + filters[offset][newIndex[i] + n0] |= one; + if(iterable) newIterablesIndexFilterStatus[i] = 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 + i0 = 0, + i1 = 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. + for (i = 0; i0 < n0 && i1 < n1; ++i) { + if (oldValues[i0] < newValues[i1]) { + values[i] = oldValues[i0]; + if(iterable) iterablesIndexFilterStatus[i] = oldIterablesIndexFilterStatus[i0]; + index[i] = oldIndex[i0++]; + } else { + values[i] = newValues[i1]; + if(iterable) iterablesIndexFilterStatus[i] = oldIterablesIndexFilterStatus[i1]; + index[i] = newIndex[i1++] + (iterable ? old_n0 : n0); + } + } + + // Add any remaining old values. + for (; i0 < n0; ++i0, ++i) { + values[i] = oldValues[i0]; + if(iterable) iterablesIndexFilterStatus[i] = oldIterablesIndexFilterStatus[i0]; + index[i] = oldIndex[i0]; + } + + // Add any remaining new values. + for (; i1 < n1; ++i1, ++i) { + values[i] = newValues[i1]; + if(iterable) iterablesIndexFilterStatus[i] = oldIterablesIndexFilterStatus[i1]; + index[i] = 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) { + for (var i = 0, j = 0, k; i < n; ++i) { + if (!filters.zero(k = index[i])) { + if (i !== j) values[j] = values[i]; + index[j] = reIndex[k]; + ++j; + } + } + values.length = j; + while (j < n) 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] === index.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; + + 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 > 1 ? 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. + if (g0 = oldGroups[++i0]) 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 (i = 0; i < n; i++) { + if(!groupIndex[i]){ + groupIndex[i] = [] + } + } + } + + // If we added any new groups before any old groups, + // update the group index of all the old records. + if(k > i0){ + if(iterable){ + groupIndex = permute(groupIndex, reIndex, true) + } + 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) { + 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() { + if (k > 1) { + var oldK = k, + oldGroups = groups, + seenGroups = crossfilter_index(oldK, oldK); + + // Filter out non-matches by copying matching group index entries to + // the beginning of the array. + for (var i = 0, j = 0; i < n; ++i) { + if (!filters.zero(i)) { + seenGroups[groupIndex[j] = groupIndex[i]] = 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) { + // Reindex the group index using seenGroups to find the new index. + for (var i = 0; i < j; ++i) groupIndex[i] = seenGroups[groupIndex[i]]; + } else { + groupIndex = null; + } + filterListeners[filterListeners.indexOf(update)] = k > 1 + ? (reset = resetMany, update = updateMany) + : k === 1 ? (reset = resetOne, update = updateOne) + : reset = update = crossfilter_null; + } else if (k === 1) { + if (groupAll) return; + for (var i = 0; i < n; ++i) if (!filters.zero(i)) 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); + 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); + i = dataListeners.indexOf(add); + if (i >= 0) dataListeners.splice(i); + 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; + } + + function onChange(cb){ + if(typeof cb !== 'function'){ + 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":17,"./array":18,"./bisect":19,"./filter":21,"./heap":22,"./heapselect":23,"./identity":24,"./insertionsort":25,"./null":26,"./permute":27,"./quicksort":28,"./reduce":29,"./zero":30,"lodash.result":31}],21:[function(require,module,exports){ +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 +}; + +},{}],22:[function(require,module,exports){ +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":24}],23:[function(require,module,exports){ +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, + x, + d; + + for (i = 0; i < k; ++i) queue[i] = a[lo++]; + heap(queue, 0, k); + + if (lo < hi) { + min = f(queue[0]); + do { + if (x = 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":22,"./identity":24}],24:[function(require,module,exports){ +function crossfilter_identity(d) { + return d; +} + +module.exports = crossfilter_identity; + +},{}],25:[function(require,module,exports){ +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":24}],26:[function(require,module,exports){ +function crossfilter_null() { + return null; +} + +module.exports = crossfilter_null; + +},{}],27:[function(require,module,exports){ +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; + +},{}],28:[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. + 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 + 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; + } + } + } + } + } + } + + // 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) { + 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) { + while (true) { + var 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; + } + } + } + } + } + } + + // 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":24,"./insertionsort":25}],29:[function(require,module,exports){ +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 +}; + +},{}],30:[function(require,module,exports){ +function crossfilter_zero() { + return 0; +} + +module.exports = crossfilter_zero; + +},{}],31:[function(require,module,exports){ +(function (global){ +/** + * lodash (Custom Build) + * 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 : {}) + +},{}],32:[function(require,module,exports){ +// shim for using process in browser +var process = module.exports = {}; + +// cached from whatever global is present so that test runners that stub it +// don't break things. But we need to wrap it in a try catch in case it is +// wrapped in strict mode code which doesn't define any globals. It's inside a +// function because try/catches deoptimize in certain engines. + +var cachedSetTimeout; +var cachedClearTimeout; + +function defaultSetTimout() { + throw new Error('setTimeout has not been defined'); +} +function defaultClearTimeout () { + throw new Error('clearTimeout has not been defined'); +} +(function () { + try { + if (typeof setTimeout === 'function') { + cachedSetTimeout = setTimeout; + } else { + cachedSetTimeout = defaultSetTimout; + } + } catch (e) { + cachedSetTimeout = defaultSetTimout; + } + try { + if (typeof clearTimeout === 'function') { + cachedClearTimeout = clearTimeout; + } else { + cachedClearTimeout = defaultClearTimeout; + } + } catch (e) { + cachedClearTimeout = defaultClearTimeout; + } +} ()) +function runTimeout(fun) { + if (cachedSetTimeout === setTimeout) { + //normal enviroments in sane situations + return setTimeout(fun, 0); + } + // if setTimeout wasn't available but was latter defined + if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { + cachedSetTimeout = setTimeout; + return setTimeout(fun, 0); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedSetTimeout(fun, 0); + } catch(e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedSetTimeout.call(null, fun, 0); + } catch(e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error + return cachedSetTimeout.call(this, fun, 0); + } + } + + +} +function runClearTimeout(marker) { + if (cachedClearTimeout === clearTimeout) { + //normal enviroments in sane situations + return clearTimeout(marker); + } + // if clearTimeout wasn't available but was latter defined + if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { + cachedClearTimeout = clearTimeout; + return clearTimeout(marker); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedClearTimeout(marker); + } catch (e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedClearTimeout.call(null, marker); + } catch (e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. + // Some versions of I.E. have different rules for clearTimeout vs setTimeout + return cachedClearTimeout.call(this, marker); + } + } + + + +} +var queue = []; +var draining = false; +var currentQueue; +var queueIndex = -1; + +function cleanUpNextTick() { + if (!draining || !currentQueue) { + return; + } + draining = false; + if (currentQueue.length) { + queue = currentQueue.concat(queue); + } else { + queueIndex = -1; + } + if (queue.length) { + drainQueue(); + } +} + +function drainQueue() { + if (draining) { + return; + } + var timeout = runTimeout(cleanUpNextTick); + draining = true; + + var len = queue.length; + while(len) { + currentQueue = queue; + queue = []; + while (++queueIndex < len) { + if (currentQueue) { + currentQueue[queueIndex].run(); + } + } + queueIndex = -1; + len = queue.length; + } + currentQueue = null; + draining = false; + runClearTimeout(timeout); +} + +process.nextTick = function (fun) { + var args = new Array(arguments.length - 1); + if (arguments.length > 1) { + for (var i = 1; i < arguments.length; i++) { + args[i - 1] = arguments[i]; + } + } + queue.push(new Item(fun, args)); + if (queue.length === 1 && !draining) { + runTimeout(drainQueue); + } +}; + +// v8 likes predictible objects +function Item(fun, array) { + this.fun = fun; + this.array = array; +} +Item.prototype.run = function () { + this.fun.apply(null, this.array); +}; +process.title = 'browser'; +process.browser = true; +process.env = {}; +process.argv = []; +process.version = ''; // empty string to avoid regexp issues +process.versions = {}; + +function noop() {} + +process.on = noop; +process.addListener = noop; +process.once = noop; +process.off = noop; +process.removeListener = noop; +process.removeAllListeners = noop; +process.emit = noop; + +process.binding = function (name) { + throw new Error('process.binding is not supported'); +}; + +process.cwd = function () { return '/' }; +process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); +}; +process.umask = function() { return 0; }; + +},{}],33:[function(require,module,exports){ +(function (process){ +// vim:ts=4:sts=4:sw=4: +/*! + * + * Copyright 2009-2012 Kris Kowal under the terms of the MIT + * license found at http://github.com/kriskowal/q/raw/master/LICENSE + * + * With parts by Tyler Close + * Copyright 2007-2009 Tyler Close under the terms of the MIT X license found + * at http://www.opensource.org/licenses/mit-license.html + * Forked at ref_send.js version: 2009-05-11 + * + * With parts by Mark Miller + * Copyright (C) 2011 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +(function (definition) { + "use strict"; + + // This file will function properly as a