d3_rails 2.8.0 → 2.8.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. data/.DS_Store +0 -0
  2. data/README.md +27 -5
  3. data/lib/d3_rails/version.rb +1 -1
  4. data/vendor/.DS_Store +0 -0
  5. data/vendor/assets/.DS_Store +0 -0
  6. data/vendor/assets/javascripts/.DS_Store +0 -0
  7. data/vendor/assets/javascripts/d3.v2.js +99 -80
  8. data/vendor/assets/javascripts/morris.js +1 -0
  9. data/vendor/assets/javascripts/morris/.DS_Store +0 -0
  10. data/vendor/assets/javascripts/morris/Makefile +10 -0
  11. data/vendor/assets/javascripts/morris/README.md +87 -0
  12. data/vendor/assets/javascripts/morris/examples/_template.html +18 -0
  13. data/vendor/assets/javascripts/morris/examples/days.html +36 -0
  14. data/vendor/assets/javascripts/morris/examples/decimal.html +31 -0
  15. data/vendor/assets/javascripts/morris/examples/lib/example.css +13 -0
  16. data/vendor/assets/javascripts/morris/examples/lib/example.js +4 -0
  17. data/vendor/assets/javascripts/morris/examples/lib/prettify.css +1 -0
  18. data/vendor/assets/javascripts/morris/examples/lib/prettify.js +28 -0
  19. data/vendor/assets/javascripts/morris/examples/months-no-smooth.html +37 -0
  20. data/vendor/assets/javascripts/morris/examples/negative.html +35 -0
  21. data/vendor/assets/javascripts/morris/examples/non-date.html +36 -0
  22. data/vendor/assets/javascripts/morris/examples/quarters.html +53 -0
  23. data/vendor/assets/javascripts/morris/examples/timestamps.html +37 -0
  24. data/vendor/assets/javascripts/morris/examples/weeks.html +52 -0
  25. data/vendor/assets/javascripts/morris/morris.coffee +444 -0
  26. data/vendor/assets/javascripts/morris/morris.js +493 -0
  27. data/vendor/assets/javascripts/morris/morris.min.js +1 -0
  28. data/vendor/assets/javascripts/tesseract.js +1 -0
  29. data/vendor/assets/javascripts/tesseract/.gitignore +2 -0
  30. data/vendor/assets/javascripts/tesseract/LICENSE +12 -0
  31. data/vendor/assets/javascripts/tesseract/Makefile +48 -0
  32. data/vendor/assets/javascripts/tesseract/README.md +11 -0
  33. data/vendor/assets/javascripts/tesseract/index.js +1 -0
  34. data/vendor/assets/javascripts/tesseract/lib/dart/AUTHORS +9 -0
  35. data/vendor/assets/javascripts/tesseract/lib/dart/LICENSE +25 -0
  36. data/vendor/assets/javascripts/tesseract/lib/dart/dual_pivot_quicksort.dart +342 -0
  37. data/vendor/assets/javascripts/tesseract/package.json +11 -0
  38. data/vendor/assets/javascripts/tesseract/src/array.js +32 -0
  39. data/vendor/assets/javascripts/tesseract/src/bisect.js +44 -0
  40. data/vendor/assets/javascripts/tesseract/src/filter.js +19 -0
  41. data/vendor/assets/javascripts/tesseract/src/heap.js +44 -0
  42. data/vendor/assets/javascripts/tesseract/src/heapselect.js +36 -0
  43. data/vendor/assets/javascripts/tesseract/src/identity.js +3 -0
  44. data/vendor/assets/javascripts/tesseract/src/insertionsort.js +18 -0
  45. data/vendor/assets/javascripts/tesseract/src/null.js +3 -0
  46. data/vendor/assets/javascripts/tesseract/src/package.js +14 -0
  47. data/vendor/assets/javascripts/tesseract/src/permute.js +8 -0
  48. data/vendor/assets/javascripts/tesseract/src/quicksort.js +282 -0
  49. data/vendor/assets/javascripts/tesseract/src/reduce.js +19 -0
  50. data/vendor/assets/javascripts/tesseract/src/tesseract.js +663 -0
  51. data/vendor/assets/javascripts/tesseract/src/version.js +1 -0
  52. data/vendor/assets/javascripts/tesseract/src/zero.js +3 -0
  53. data/vendor/assets/javascripts/tesseract/tesseract.js +1177 -0
  54. data/vendor/assets/javascripts/tesseract/tesseract.min.js +1 -0
  55. data/vendor/assets/javascripts/tesseract/test/benchmark.js +177 -0
  56. data/vendor/assets/javascripts/tesseract/test/bisect-test.js +206 -0
  57. data/vendor/assets/javascripts/tesseract/test/heap-test.js +44 -0
  58. data/vendor/assets/javascripts/tesseract/test/permute-test.js +51 -0
  59. data/vendor/assets/javascripts/tesseract/test/select-test.js +63 -0
  60. data/vendor/assets/javascripts/tesseract/test/sort-test.js +83 -0
  61. data/vendor/assets/javascripts/tesseract/test/tesseract-test.js +655 -0
  62. data/vendor/assets/javascripts/tesseract/test/version-test.js +16 -0
  63. metadata +63 -8
@@ -0,0 +1 @@
1
+ tesseract.version = "1.0.1";
@@ -0,0 +1,3 @@
1
+ function tesseract_zero() {
2
+ return 0;
3
+ }
@@ -0,0 +1,1177 @@
1
+ (function(exports){
2
+ tesseract.version = "1.0.1";
3
+ function tesseract_identity(d) {
4
+ return d;
5
+ }
6
+ tesseract.permute = permute;
7
+
8
+ function permute(array, index) {
9
+ for (var i = 0, n = index.length, copy = new Array(n); i < n; ++i) {
10
+ copy[i] = array[index[i]];
11
+ }
12
+ return copy;
13
+ }
14
+ var bisect = tesseract.bisect = bisect_by(tesseract_identity);
15
+
16
+ bisect.by = bisect_by;
17
+
18
+ function bisect_by(f) {
19
+
20
+ // Locate the insertion point for x in a to maintain sorted order. The
21
+ // arguments lo and hi may be used to specify a subset of the array which
22
+ // should be considered; by default the entire array is used. If x is already
23
+ // present in a, the insertion point will be before (to the left of) any
24
+ // existing entries. The return value is suitable for use as the first
25
+ // argument to `array.splice` assuming that a is already sorted.
26
+ //
27
+ // The returned insertion point i partitions the array a into two halves so
28
+ // that all v < x for v in a[lo:i] for the left side and all v >= x for v in
29
+ // a[i:hi] for the right side.
30
+ function bisectLeft(a, x, lo, hi) {
31
+ while (lo < hi) {
32
+ var mid = lo + hi >> 1;
33
+ if (f(a[mid]) < x) lo = mid + 1;
34
+ else hi = mid;
35
+ }
36
+ return lo;
37
+ }
38
+
39
+ // Similar to bisectLeft, but returns an insertion point which comes after (to
40
+ // the right of) any existing entries of x in a.
41
+ //
42
+ // The returned insertion point i partitions the array into two halves so that
43
+ // all v <= x for v in a[lo:i] for the left side and all v > x for v in
44
+ // a[i:hi] for the right side.
45
+ function bisectRight(a, x, lo, hi) {
46
+ while (lo < hi) {
47
+ var mid = lo + hi >> 1;
48
+ if (x < f(a[mid])) hi = mid;
49
+ else lo = mid + 1;
50
+ }
51
+ return lo;
52
+ }
53
+
54
+ bisectRight.right = bisectRight;
55
+ bisectRight.left = bisectLeft;
56
+ return bisectRight;
57
+ }
58
+ var heap = tesseract.heap = heap_by(tesseract_identity);
59
+
60
+ heap.by = heap_by;
61
+
62
+ function heap_by(f) {
63
+
64
+ // Builds a binary heap within the specified array a[lo:hi]. The heap has the
65
+ // property such that the parent a[lo+i] is always less than or equal to its
66
+ // two children: a[lo+2*i+1] and a[lo+2*i+2].
67
+ function heap(a, lo, hi) {
68
+ var n = hi - lo,
69
+ i = (n >>> 1) + 1;
70
+ while (--i > 0) sift(a, i, n, lo);
71
+ return a;
72
+ }
73
+
74
+ // Sorts the specified array a[lo:hi] in descending order, assuming it is
75
+ // already a heap.
76
+ function sort(a, lo, hi) {
77
+ var n = hi - lo,
78
+ t;
79
+ while (--n > 0) t = a[lo], a[lo] = a[lo + n], a[lo + n] = t, sift(a, 1, n, lo);
80
+ return a;
81
+ }
82
+
83
+ // Sifts the element a[lo+i-1] down the heap, where the heap is the contiguous
84
+ // slice of array a[lo:lo+n]. This method can also be used to update the heap
85
+ // incrementally, without incurring the full cost of reconstructing the heap.
86
+ function sift(a, i, n, lo) {
87
+ var d = a[--lo + i],
88
+ x = f(d),
89
+ child;
90
+ while ((child = i << 1) <= n) {
91
+ if (child < n && f(a[lo + child]) > f(a[lo + child + 1])) child++;
92
+ if (x <= f(a[lo + child])) break;
93
+ a[lo + i] = a[lo + child];
94
+ i = child;
95
+ }
96
+ a[lo + i] = d;
97
+ }
98
+
99
+ heap.sort = sort;
100
+ return heap;
101
+ }
102
+ var heapselect = tesseract.heapselect = heapselect_by(tesseract_identity);
103
+
104
+ heapselect.by = heapselect_by;
105
+
106
+ function heapselect_by(f) {
107
+ var heap = heap_by(f);
108
+
109
+ // Returns a new array containing the top k elements in the array a[lo:hi].
110
+ // The returned array is not sorted, but maintains the heap property. If k is
111
+ // greater than hi - lo, then fewer than k elements will be returned. The
112
+ // order of elements in a is unchanged by this operation.
113
+ function heapselect(a, lo, hi, k) {
114
+ var queue = new Array(k = Math.min(hi - lo, k)),
115
+ min,
116
+ i,
117
+ x,
118
+ d;
119
+
120
+ for (i = 0; i < k; ++i) queue[i] = a[lo++];
121
+ heap(queue, 0, k);
122
+
123
+ if (lo < hi) {
124
+ min = f(queue[0]);
125
+ do {
126
+ if (x = f(d = a[lo]) > min) {
127
+ queue[0] = d;
128
+ min = f(heap(queue, 0, k)[0]);
129
+ }
130
+ } while (++lo < hi);
131
+ }
132
+
133
+ return queue;
134
+ }
135
+
136
+ return heapselect;
137
+ }
138
+ var insertionsort = tesseract.insertionsort = insertionsort_by(tesseract_identity);
139
+
140
+ insertionsort.by = insertionsort_by;
141
+
142
+ function insertionsort_by(f) {
143
+
144
+ function insertionsort(a, lo, hi) {
145
+ for (var i = lo + 1; i < hi; ++i) {
146
+ for (var j = i, t = a[i], x = f(t); j > lo && f(a[j - 1]) > x; --j) {
147
+ a[j] = a[j - 1];
148
+ }
149
+ a[j] = t;
150
+ }
151
+ return a;
152
+ }
153
+
154
+ return insertionsort;
155
+ }
156
+ // Algorithm designed by Vladimir Yaroslavskiy.
157
+ // Implementation based on the Dart project; see lib/dart/LICENSE for details.
158
+
159
+ var quicksort = tesseract.quicksort = quicksort_by(tesseract_identity);
160
+
161
+ quicksort.by = quicksort_by;
162
+
163
+ function quicksort_by(f) {
164
+ var insertionsort = insertionsort_by(f);
165
+
166
+ function sort(a, lo, hi) {
167
+ return (hi - lo < quicksort_sizeThreshold
168
+ ? insertionsort
169
+ : quicksort)(a, lo, hi);
170
+ }
171
+
172
+ function quicksort(a, lo, hi) {
173
+
174
+ // Compute the two pivots by looking at 5 elements.
175
+ var sixth = (hi - lo) / 6 | 0,
176
+ i1 = lo + sixth,
177
+ i5 = hi - 1 - sixth,
178
+ i3 = lo + hi - 1 >> 1, // The midpoint.
179
+ i2 = i3 - sixth,
180
+ i4 = i3 + sixth;
181
+
182
+ var e1 = a[i1], x1 = f(e1),
183
+ e2 = a[i2], x2 = f(e2),
184
+ e3 = a[i3], x3 = f(e3),
185
+ e4 = a[i4], x4 = f(e4),
186
+ e5 = a[i5], x5 = f(e5);
187
+
188
+ // Sort the selected 5 elements using a sorting network.
189
+ if (x1 > x2) t = e1, e1 = e2, e2 = t, t = x1, x1 = x2, x2 = t;
190
+ if (x4 > x5) t = e4, e4 = e5, e5 = t, t = x4, x4 = x5, x5 = t;
191
+ if (x1 > x3) t = e1, e1 = e3, e3 = t, t = x1, x1 = x3, x3 = t;
192
+ if (x2 > x3) t = e2, e2 = e3, e3 = t, t = x2, x2 = x3, x3 = t;
193
+ if (x1 > x4) t = e1, e1 = e4, e4 = t, t = x1, x1 = x4, x4 = t;
194
+ if (x3 > x4) t = e3, e3 = e4, e4 = t, t = x3, x3 = x4, x4 = t;
195
+ if (x2 > x5) t = e2, e2 = e5, e5 = t, t = x2, x2 = x5, x5 = t;
196
+ if (x2 > x3) t = e2, e2 = e3, e3 = t, t = x2, x2 = x3, x3 = t;
197
+ if (x4 > x5) t = e4, e4 = e5, e5 = t, t = x4, x4 = x5, x5 = t;
198
+
199
+ var pivot1 = e2, pivotValue1 = x2,
200
+ pivot2 = e4, pivotValue2 = x4;
201
+
202
+ // e2 and e4 have been saved in the pivot variables. They will be written
203
+ // back, once the partitioning is finished.
204
+ a[i1] = e1;
205
+ a[i2] = a[lo];
206
+ a[i3] = e3;
207
+ a[i4] = a[hi - 1];
208
+ a[i5] = e5;
209
+
210
+ var less = lo + 1, // First element in the middle partition.
211
+ great = hi - 2; // Last element in the middle partition.
212
+
213
+ // Note that for value comparison, <, <=, >= and > coerce to a primitive via
214
+ // Object.prototype.valueOf; == and === do not, so in order to be consistent
215
+ // with natural order (such as for Date objects), we must do two compares.
216
+ var pivotsEqual = pivotValue1 <= pivotValue2 && pivotValue1 >= pivotValue2;
217
+ if (pivotsEqual) {
218
+
219
+ // Degenerated case where the partitioning becomes a dutch national flag
220
+ // problem.
221
+ //
222
+ // [ | < pivot | == pivot | unpartitioned | > pivot | ]
223
+ // ^ ^ ^ ^ ^
224
+ // left less k great right
225
+ //
226
+ // a[left] and a[right] are undefined and are filled after the
227
+ // partitioning.
228
+ //
229
+ // Invariants:
230
+ // 1) for x in ]left, less[ : x < pivot.
231
+ // 2) for x in [less, k[ : x == pivot.
232
+ // 3) for x in ]great, right[ : x > pivot.
233
+ for (var k = less; k <= great; ++k) {
234
+ var ek = a[k], xk = f(ek);
235
+ if (xk < pivotValue1) {
236
+ if (k !== less) {
237
+ a[k] = a[less];
238
+ a[less] = ek;
239
+ }
240
+ ++less;
241
+ } else if (xk > pivotValue1) {
242
+
243
+ // Find the first element <= pivot in the range [k - 1, great] and
244
+ // put [:ek:] there. We know that such an element must exist:
245
+ // When k == less, then el3 (which is equal to pivot) lies in the
246
+ // interval. Otherwise a[k - 1] == pivot and the search stops at k-1.
247
+ // Note that in the latter case invariant 2 will be violated for a
248
+ // short amount of time. The invariant will be restored when the
249
+ // pivots are put into their final positions.
250
+ while (true) {
251
+ var greatValue = f(a[great]);
252
+ if (greatValue > pivotValue1) {
253
+ great--;
254
+ // This is the only location in the while-loop where a new
255
+ // iteration is started.
256
+ continue;
257
+ } else if (greatValue < pivotValue1) {
258
+ // Triple exchange.
259
+ a[k] = a[less];
260
+ a[less++] = a[great];
261
+ a[great--] = ek;
262
+ break;
263
+ } else {
264
+ a[k] = a[great];
265
+ a[great--] = ek;
266
+ // Note: if great < k then we will exit the outer loop and fix
267
+ // invariant 2 (which we just violated).
268
+ break;
269
+ }
270
+ }
271
+ }
272
+ }
273
+ } else {
274
+
275
+ // We partition the list into three parts:
276
+ // 1. < pivot1
277
+ // 2. >= pivot1 && <= pivot2
278
+ // 3. > pivot2
279
+ //
280
+ // During the loop we have:
281
+ // [ | < pivot1 | >= pivot1 && <= pivot2 | unpartitioned | > pivot2 | ]
282
+ // ^ ^ ^ ^ ^
283
+ // left less k great right
284
+ //
285
+ // a[left] and a[right] are undefined and are filled after the
286
+ // partitioning.
287
+ //
288
+ // Invariants:
289
+ // 1. for x in ]left, less[ : x < pivot1
290
+ // 2. for x in [less, k[ : pivot1 <= x && x <= pivot2
291
+ // 3. for x in ]great, right[ : x > pivot2
292
+ for (var k = less; k <= great; k++) {
293
+ var ek = a[k], xk = f(ek);
294
+ if (xk < pivotValue1) {
295
+ if (k !== less) {
296
+ a[k] = a[less];
297
+ a[less] = ek;
298
+ }
299
+ ++less;
300
+ } else {
301
+ if (xk > pivotValue2) {
302
+ while (true) {
303
+ var greatValue = f(a[great]);
304
+ if (greatValue > pivotValue2) {
305
+ great--;
306
+ if (great < k) break;
307
+ // This is the only location inside the loop where a new
308
+ // iteration is started.
309
+ continue;
310
+ } else {
311
+ // a[great] <= pivot2.
312
+ if (greatValue < pivotValue1) {
313
+ // Triple exchange.
314
+ a[k] = a[less];
315
+ a[less++] = a[great];
316
+ a[great--] = ek;
317
+ } else {
318
+ // a[great] >= pivot1.
319
+ a[k] = a[great];
320
+ a[great--] = ek;
321
+ }
322
+ break;
323
+ }
324
+ }
325
+ }
326
+ }
327
+ }
328
+ }
329
+
330
+ // Move pivots into their final positions.
331
+ // We shrunk the list from both sides (a[left] and a[right] have
332
+ // meaningless values in them) and now we move elements from the first
333
+ // and third partition into these locations so that we can store the
334
+ // pivots.
335
+ a[lo] = a[less - 1];
336
+ a[less - 1] = pivot1;
337
+ a[hi - 1] = a[great + 1];
338
+ a[great + 1] = pivot2;
339
+
340
+ // The list is now partitioned into three partitions:
341
+ // [ < pivot1 | >= pivot1 && <= pivot2 | > pivot2 ]
342
+ // ^ ^ ^ ^
343
+ // left less great right
344
+
345
+ // Recursive descent. (Don't include the pivot values.)
346
+ sort(a, lo, less - 1);
347
+ sort(a, great + 2, hi);
348
+
349
+ if (pivotsEqual) {
350
+ // All elements in the second partition are equal to the pivot. No
351
+ // need to sort them.
352
+ return a;
353
+ }
354
+
355
+ // In theory it should be enough to call _doSort recursively on the second
356
+ // partition.
357
+ // The Android source however removes the pivot elements from the recursive
358
+ // call if the second partition is too large (more than 2/3 of the list).
359
+ if (less < i1 && great > i5) {
360
+ var lessValue, greatValue;
361
+ while ((lessValue = f(a[less])) <= pivotValue1 && lessValue >= pivotValue1) ++less;
362
+ while ((greatValue = f(a[great])) <= pivotValue2 && greatValue >= pivotValue2) --great;
363
+
364
+ // Copy paste of the previous 3-way partitioning with adaptions.
365
+ //
366
+ // We partition the list into three parts:
367
+ // 1. == pivot1
368
+ // 2. > pivot1 && < pivot2
369
+ // 3. == pivot2
370
+ //
371
+ // During the loop we have:
372
+ // [ == pivot1 | > pivot1 && < pivot2 | unpartitioned | == pivot2 ]
373
+ // ^ ^ ^
374
+ // less k great
375
+ //
376
+ // Invariants:
377
+ // 1. for x in [ *, less[ : x == pivot1
378
+ // 2. for x in [less, k[ : pivot1 < x && x < pivot2
379
+ // 3. for x in ]great, * ] : x == pivot2
380
+ for (var k = less; k <= great; k++) {
381
+ var ek = a[k], xk = f(ek);
382
+ if (xk <= pivotValue1 && xk >= pivotValue1) {
383
+ if (k !== less) {
384
+ a[k] = a[less];
385
+ a[less] = ek;
386
+ }
387
+ less++;
388
+ } else {
389
+ if (xk <= pivotValue2 && xk >= pivotValue2) {
390
+ while (true) {
391
+ var greatValue = f(a[great]);
392
+ if (greatValue <= pivotValue2 && greatValue >= pivotValue2) {
393
+ great--;
394
+ if (great < k) break;
395
+ // This is the only location inside the loop where a new
396
+ // iteration is started.
397
+ continue;
398
+ } else {
399
+ // a[great] < pivot2.
400
+ if (greatValue < pivotValue1) {
401
+ // Triple exchange.
402
+ a[k] = a[less];
403
+ a[less++] = a[great];
404
+ a[great--] = ek;
405
+ } else {
406
+ // a[great] == pivot1.
407
+ a[k] = a[great];
408
+ a[great--] = ek;
409
+ }
410
+ break;
411
+ }
412
+ }
413
+ }
414
+ }
415
+ }
416
+ }
417
+
418
+ // The second partition has now been cleared of pivot elements and looks
419
+ // as follows:
420
+ // [ * | > pivot1 && < pivot2 | * ]
421
+ // ^ ^
422
+ // less great
423
+ // Sort the second partition using recursive descent.
424
+
425
+ // The second partition looks as follows:
426
+ // [ * | >= pivot1 && <= pivot2 | * ]
427
+ // ^ ^
428
+ // less great
429
+ // Simply sort it by recursive descent.
430
+
431
+ return sort(a, less, great + 1);
432
+ }
433
+
434
+ return sort;
435
+ }
436
+
437
+ var quicksort_sizeThreshold = 32;
438
+ var tesseract_array8 = tesseract_arrayUntyped,
439
+ tesseract_array16 = tesseract_arrayUntyped,
440
+ tesseract_array32 = tesseract_arrayUntyped,
441
+ tesseract_arrayLengthen = tesseract_identity,
442
+ tesseract_arrayWiden = tesseract_identity;
443
+
444
+ if (typeof Uint8Array !== "undefined") {
445
+ tesseract_array8 = function(n) { return new Uint8Array(n); };
446
+ tesseract_array16 = function(n) { return new Uint16Array(n); };
447
+ tesseract_array32 = function(n) { return new Uint32Array(n); };
448
+
449
+ tesseract_arrayLengthen = function(array, length) {
450
+ var copy = new array.constructor(length);
451
+ copy.set(array);
452
+ return copy;
453
+ };
454
+
455
+ tesseract_arrayWiden = function(array, width) {
456
+ var copy;
457
+ switch (width) {
458
+ case 16: copy = tesseract_array16(array.length); break;
459
+ case 32: copy = tesseract_array32(array.length); break;
460
+ default: throw new Error("invalid array width!");
461
+ }
462
+ copy.set(array);
463
+ return copy;
464
+ };
465
+ }
466
+
467
+ function tesseract_arrayUntyped(n) {
468
+ return new Array(n);
469
+ }
470
+ function tesseract_filterExact(bisect, value) {
471
+ return function(values) {
472
+ var n = values.length;
473
+ return [bisect.left(values, value, 0, n), bisect.right(values, value, 0, n)];
474
+ };
475
+ }
476
+
477
+ function tesseract_filterRange(bisect, range) {
478
+ var min = range[0],
479
+ max = range[1];
480
+ return function(values) {
481
+ var n = values.length;
482
+ return [bisect.left(values, min, 0, n), bisect.left(values, max, 0, n)];
483
+ };
484
+ }
485
+
486
+ function tesseract_filterAll(values) {
487
+ return [0, values.length];
488
+ }
489
+ function tesseract_null() {
490
+ return null;
491
+ }
492
+ function tesseract_zero() {
493
+ return 0;
494
+ }
495
+ function tesseract_reduceIncrement(p) {
496
+ return p + 1;
497
+ }
498
+
499
+ function tesseract_reduceDecrement(p) {
500
+ return p - 1;
501
+ }
502
+
503
+ function tesseract_reduceAdd(f) {
504
+ return function(p, v) {
505
+ return p + +f(v);
506
+ };
507
+ }
508
+
509
+ function tesseract_reduceSubtract(f) {
510
+ return function(p, v) {
511
+ return p - f(v);
512
+ };
513
+ }
514
+ exports.tesseract = tesseract;
515
+
516
+ function tesseract() {
517
+ var tesseract = {
518
+ add: add,
519
+ dimension: dimension,
520
+ groupAll: groupAll,
521
+ size: size
522
+ };
523
+
524
+ var data = [], // the records
525
+ n = 0, // the number of records; data.length
526
+ m = 0, // number of dimensions in use
527
+ M = 8, // number of dimensions that can fit in `filters`
528
+ filters = tesseract_array8(0), // M bits per record; 1 is filtered out
529
+ filterListeners = [], // when the filters change
530
+ dataListeners = []; // when data is added
531
+
532
+ // Adds the specified new records to this tesseract.
533
+ function add(newData) {
534
+ var n0 = n,
535
+ n1 = newData.length;
536
+
537
+ // If there's actually new data to add…
538
+ // Merge the new data into the existing data.
539
+ // Lengthen the filter bitset to handle the new records.
540
+ // Notify listeners (dimensions and groups) that new data is available.
541
+ if (n1) {
542
+ data = data.concat(newData);
543
+ filters = tesseract_arrayLengthen(filters, n += n1);
544
+ dataListeners.forEach(function(l) { l(newData, n0, n1); });
545
+ }
546
+
547
+ return tesseract;
548
+ }
549
+
550
+ // Adds a new dimension with the specified value accessor function.
551
+ function dimension(value) {
552
+ var dimension = {
553
+ filter: filter,
554
+ filterExact: filterExact,
555
+ filterRange: filterRange,
556
+ filterAll: filterAll,
557
+ top: top,
558
+ group: group,
559
+ groupAll: groupAll
560
+ };
561
+
562
+ var one = 1 << m++, // bit mask, e.g., 00001000
563
+ zero = ~one, // inverted one, e.g., 11110111
564
+ values, // sorted, cached array
565
+ index, // value rank ↦ object id
566
+ newValues, // temporary array storing newly-added values
567
+ newIndex, // temporary array storing newly-added index
568
+ sort = quicksort_by(function(i) { return newValues[i]; }),
569
+ refilter = tesseract_filterAll, // for recomputing filter
570
+ indexListeners = [], // when data is added
571
+ lo0 = 0,
572
+ hi0 = 0;
573
+
574
+ // Updating a dimension is a two-stage process. First, we must update the
575
+ // associated filters for the newly-added records. Once all dimensions have
576
+ // updated their filters, the groups are notified to update.
577
+ dataListeners.unshift(preAdd);
578
+ dataListeners.push(postAdd);
579
+
580
+ // Incorporate any existing data into this dimension, and make sure that the
581
+ // filter bitset is wide enough to handle the new dimension.
582
+ if (m > M) filters = tesseract_arrayWiden(filters, M <<= 1);
583
+ preAdd(data, 0, n);
584
+ postAdd(data, 0, n);
585
+
586
+ // Incorporates the specified new records into this dimension.
587
+ // This function is responsible for updating filters, values, and index.
588
+ function preAdd(newData, n0, n1) {
589
+
590
+ // Permute new values into natural order using a sorted index.
591
+ newValues = newData.map(value);
592
+ newIndex = sort(tesseract_range(n1), 0, n1);
593
+ newValues = permute(newValues, newIndex);
594
+
595
+ // Bisect newValues to determine which new records are selected.
596
+ var bounds = refilter(newValues), lo1 = bounds[0], hi1 = bounds[1], i;
597
+ for (i = 0; i < lo1; ++i) filters[newIndex[i] + n0] |= one;
598
+ for (i = hi1; i < n1; ++i) filters[newIndex[i] + n0] |= one;
599
+
600
+ // If this dimension previously had no data, then we don't need to do the
601
+ // more expensive merge operation; use the new values and index as-is.
602
+ if (!n0) {
603
+ values = newValues;
604
+ index = newIndex;
605
+ lo0 = lo1;
606
+ hi0 = hi1;
607
+ return;
608
+ }
609
+
610
+ var oldValues = values,
611
+ oldIndex = index,
612
+ i0 = 0,
613
+ i1 = 0;
614
+
615
+ // Otherwise, create new arrays into which to merge new and old.
616
+ values = new Array(n);
617
+ index = tesseract_index(n, n);
618
+
619
+ // Merge the old and new sorted values, and old and new index.
620
+ for (i = 0; i0 < n0 && i1 < n1; ++i) {
621
+ if (oldValues[i0] < newValues[i1]) {
622
+ values[i] = oldValues[i0];
623
+ index[i] = oldIndex[i0++];
624
+ } else {
625
+ values[i] = newValues[i1];
626
+ index[i] = newIndex[i1++] + n0;
627
+ }
628
+ }
629
+
630
+ // Add any remaining old values.
631
+ for (; i0 < n0; ++i0, ++i) {
632
+ values[i] = oldValues[i0];
633
+ index[i] = oldIndex[i0];
634
+ }
635
+
636
+ // Add any remaining new values.
637
+ for (; i1 < n1; ++i1, ++i) {
638
+ values[i] = newValues[i1];
639
+ index[i] = newIndex[i1] + n0;
640
+ }
641
+
642
+ // Bisect again to recompute lo0 and hi0.
643
+ bounds = refilter(values), lo0 = bounds[0], hi0 = bounds[1];
644
+ }
645
+
646
+ // When all filters have updated, notify index listeners of the new values.
647
+ function postAdd(newData, n0, n1) {
648
+ indexListeners.forEach(function(l) { l(newValues, newIndex, n0, n1); });
649
+ newValues = newIndex = null;
650
+ }
651
+
652
+ // Updates the selected values based on the specified bounds [lo, hi].
653
+ // This implementation is used by all the public filter methods.
654
+ function filterIndex(bounds) {
655
+ var i,
656
+ j,
657
+ k,
658
+ lo1 = bounds[0],
659
+ hi1 = bounds[1],
660
+ added = [],
661
+ removed = [];
662
+
663
+ // Fast incremental update based on previous lo index.
664
+ if (lo1 < lo0) {
665
+ for (i = lo1, j = Math.min(lo0, hi1); i < j; ++i) {
666
+ filters[k = index[i]] ^= one;
667
+ added.push(k);
668
+ }
669
+ } else if (lo1 > lo0) {
670
+ for (i = lo0, j = Math.min(lo1, hi0); i < j; ++i) {
671
+ filters[k = index[i]] ^= one;
672
+ removed.push(k);
673
+ }
674
+ }
675
+
676
+ // Fast incremental update based on previous hi index.
677
+ if (hi1 > hi0) {
678
+ for (i = Math.max(lo1, hi0), j = hi1; i < j; ++i) {
679
+ filters[k = index[i]] ^= one;
680
+ added.push(k);
681
+ }
682
+ } else if (hi1 < hi0) {
683
+ for (i = Math.max(lo0, hi1), j = hi0; i < j; ++i) {
684
+ filters[k = index[i]] ^= one;
685
+ removed.push(k);
686
+ }
687
+ }
688
+
689
+ lo0 = lo1;
690
+ hi0 = hi1;
691
+ filterListeners.forEach(function(l) { l(one, added, removed); });
692
+ return dimension;
693
+ }
694
+
695
+ // Filters this dimension using the specified range, value, or null.
696
+ // If the range is null, this is equivalent to filterAll.
697
+ // If the range is an array, this is equivalent to filterRange.
698
+ // Otherwise, this is equivalent to filterExact.
699
+ function filter(range) {
700
+ return range == null
701
+ ? filterAll() : Array.isArray(range)
702
+ ? filterRange(range)
703
+ : filterExact(range);
704
+ }
705
+
706
+ // Filters this dimension to select the exact value.
707
+ function filterExact(value) {
708
+ return filterIndex((refilter = tesseract_filterExact(bisect, value))(values));
709
+ }
710
+
711
+ // Filters this dimension to select the specified range [lo, hi].
712
+ // The lower bound is inclusive, and the upper bound is exclusive.
713
+ function filterRange(range) {
714
+ return filterIndex((refilter = tesseract_filterRange(bisect, range))(values));
715
+ }
716
+
717
+ // Clears any filters on this dimension.
718
+ function filterAll() {
719
+ return filterIndex((refilter = tesseract_filterAll)(values));
720
+ }
721
+
722
+ // Returns the top K selected records, based on this dimension's order.
723
+ // Note: observes this dimension's filter, unlike group and groupAll.
724
+ function top(k) {
725
+ var array = [],
726
+ i = hi0,
727
+ j;
728
+
729
+ while (--i >= lo0 && k > 0) {
730
+ if (!filters[j = index[i]]) {
731
+ array.push(data[j]);
732
+ --k;
733
+ }
734
+ }
735
+
736
+ return array;
737
+ }
738
+
739
+ // Adds a new group to this dimension, using the specified key function.
740
+ function group(key) {
741
+ var group = {
742
+ top: top,
743
+ all: all,
744
+ reduce: reduce,
745
+ reduceCount: reduceCount,
746
+ reduceSum: reduceSum,
747
+ order: order,
748
+ orderNatural: orderNatural,
749
+ size: size
750
+ };
751
+
752
+ var groups, // array of {key, value}
753
+ groupIndex, // object id ↦ group id
754
+ groupWidth = 8,
755
+ groupCapacity = tesseract_capacity(groupWidth),
756
+ k = 0, // cardinality
757
+ select,
758
+ heap,
759
+ reduceAdd,
760
+ reduceRemove,
761
+ reduceInitial,
762
+ update = tesseract_null,
763
+ reset = tesseract_null,
764
+ resetNeeded = true;
765
+
766
+ if (arguments.length < 1) key = tesseract_identity;
767
+
768
+ // The group listens to the tesseract for when any dimension changes, so
769
+ // that it can update the associated reduce values. It must also listen to
770
+ // the parent dimension for when data is added, and compute new keys.
771
+ filterListeners.push(update);
772
+ indexListeners.push(add);
773
+
774
+ // Incorporate any existing data into the grouping.
775
+ add(values, index, 0, n);
776
+
777
+ // Incorporates the specified new values into this group.
778
+ // This function is responsible for updating groups and groupIndex.
779
+ function add(newValues, newIndex, n0, n1) {
780
+ var oldGroups = groups,
781
+ reIndex = tesseract_index(k, groupCapacity),
782
+ add = reduceAdd,
783
+ initial = reduceInitial,
784
+ k0 = k, // old cardinality
785
+ i0 = 0, // index of old group
786
+ i1 = 0, // index of new record
787
+ j, // object id
788
+ g0, // old group
789
+ x0, // old key
790
+ x1, // new key
791
+ g, // group to add
792
+ x; // key of group to add
793
+
794
+ // If a reset is needed, we don't need to update the reduce values.
795
+ if (resetNeeded) add = initial = tesseract_null;
796
+
797
+ // Reset the new groups (k is a lower bound).
798
+ // Also, make sure that groupIndex exists and is long enough.
799
+ groups = new Array(k), k = 0;
800
+ groupIndex = k0 > 1 ? tesseract_arrayLengthen(groupIndex, n) : tesseract_index(n, groupCapacity);
801
+
802
+ // Get the first old key (x0 of g0), if it exists.
803
+ if (k0) x0 = (g0 = oldGroups[0]).key;
804
+
805
+ // Find the first new key (x1), skipping NaN keys.
806
+ while (i1 < n1 && !((x1 = key(newValues[i1])) >= x1)) ++i1;
807
+
808
+ // While new keys remain…
809
+ while (i1 < n1) {
810
+
811
+ // Determine the lesser of the two current keys; new and old.
812
+ // If there are no old keys remaining, then always add the new key.
813
+ if (g0 && x0 <= x1) {
814
+ g = g0, x = x0;
815
+
816
+ // Record the new index of the old group.
817
+ reIndex[i0] = k;
818
+
819
+ // Retrieve the next old key.
820
+ if (g0 = oldGroups[++i0]) x0 = g0.key;
821
+ } else {
822
+ g = {key: x1, value: initial()}, x = x1;
823
+ }
824
+
825
+ // Add the lesser group.
826
+ groups[k] = g;
827
+
828
+ // Add any selected records belonging to the added group, while
829
+ // advancing the new key and populating the associated group index.
830
+ while (!(x1 > x)) {
831
+ groupIndex[j = newIndex[i1] + n0] = k;
832
+ if (!(filters[j] & zero)) g.value = add(g.value, data[j]);
833
+ if (++i1 >= n1) break;
834
+ x1 = key(newValues[i1]);
835
+ }
836
+
837
+ groupIncrement();
838
+ }
839
+
840
+ // Add any remaining old groups that were greater than all new keys.
841
+ // No incremental reduce is needed; these groups have no new records.
842
+ // Also record the new index of the old group.
843
+ while (i0 < k0) {
844
+ groups[reIndex[i0] = k] = oldGroups[i0++];
845
+ groupIncrement();
846
+ }
847
+
848
+ // If we added any new groups before any old groups,
849
+ // update the group index of all the old records.
850
+ if (k > i0) for (i0 = 0; i0 < n0; ++i0) {
851
+ groupIndex[i0] = reIndex[groupIndex[i0]];
852
+ }
853
+
854
+ // Modify the update and reset behavior based on the cardinality.
855
+ // If the cardinality is less than or equal to one, then the groupIndex
856
+ // is not needed. If the cardinality is zero, then there are no records
857
+ // and therefore no groups to update or reset. Note that we also must
858
+ // change the registered listener to point to the new method.
859
+ j = filterListeners.indexOf(update);
860
+ if (k > 1) {
861
+ update = updateMany;
862
+ reset = resetMany;
863
+ } else {
864
+ if (k === 1) {
865
+ update = updateOne;
866
+ reset = resetOne;
867
+ } else {
868
+ update = tesseract_null;
869
+ reset = tesseract_null;
870
+ }
871
+ groupIndex = null;
872
+ }
873
+ filterListeners[j] = update;
874
+
875
+ // Count the number of added groups,
876
+ // and widen the group index as needed.
877
+ function groupIncrement() {
878
+ if (++k === groupCapacity) {
879
+ reIndex = tesseract_arrayWiden(reIndex, groupWidth <<= 1);
880
+ groupIndex = tesseract_arrayWiden(groupIndex, groupWidth);
881
+ groupCapacity = tesseract_capacity(groupWidth);
882
+ }
883
+ }
884
+ }
885
+
886
+ // Reduces the specified selected or deselected records.
887
+ // This function is only used when the cardinality is greater than 1.
888
+ function updateMany(filterOne, added, removed) {
889
+ if (filterOne === one || resetNeeded) return;
890
+
891
+ var i,
892
+ k,
893
+ n;
894
+
895
+ // Add the added values.
896
+ for (i = 0, n = added.length; i < n; ++i) {
897
+ if (!(filters[k = added[i]] & zero)) {
898
+ g = groups[groupIndex[k]];
899
+ g.value = reduceAdd(g.value, data[k]);
900
+ }
901
+ }
902
+
903
+ // Remove the removed values.
904
+ for (i = 0, n = removed.length; i < n; ++i) {
905
+ if ((filters[k = removed[i]] & zero) === filterOne) {
906
+ g = groups[groupIndex[k]];
907
+ g.value = reduceRemove(g.value, data[k]);
908
+ }
909
+ }
910
+ }
911
+
912
+ // Reduces the specified selected or deselected records.
913
+ // This function is only used when the cardinality is 1.
914
+ function updateOne(filterOne, added, removed) {
915
+ if (filterOne === one || resetNeeded) return;
916
+
917
+ var i,
918
+ k,
919
+ n,
920
+ g = groups[0];
921
+
922
+ // Add the added values.
923
+ for (i = 0, n = added.length; i < n; ++i) {
924
+ if (!(filters[k = added[i]] & zero)) {
925
+ g.value = reduceAdd(g.value, data[k]);
926
+ }
927
+ }
928
+
929
+ // Remove the removed values.
930
+ for (i = 0, n = removed.length; i < n; ++i) {
931
+ if ((filters[k = removed[i]] & zero) === filterOne) {
932
+ g.value = reduceRemove(g.value, data[k]);
933
+ }
934
+ }
935
+ }
936
+
937
+ // Recomputes the group reduce values from scratch.
938
+ // This function is only used when the cardinality is greater than 1.
939
+ function resetMany() {
940
+ var i,
941
+ g;
942
+
943
+ // Reset all group values.
944
+ for (i = 0; i < k; ++i) {
945
+ groups[i].value = reduceInitial();
946
+ }
947
+
948
+ // Add any selected records.
949
+ for (i = 0; i < n; ++i) {
950
+ if (!(filters[i] & zero)) {
951
+ g = groups[groupIndex[i]];
952
+ g.value = reduceAdd(g.value, data[i]);
953
+ }
954
+ }
955
+ }
956
+
957
+ // Recomputes the group reduce values from scratch.
958
+ // This function is only used when the cardinality is 1.
959
+ function resetOne() {
960
+ var i,
961
+ g = groups[0];
962
+
963
+ // Reset the singleton group values.
964
+ g.value = reduceInitial();
965
+
966
+ // Add any selected records.
967
+ for (i = 0; i < n; ++i) {
968
+ if (!(filters[i] & zero)) {
969
+ g.value = reduceAdd(g.value, data[i]);
970
+ }
971
+ }
972
+ }
973
+
974
+ // Returns the array of group values, in the dimension's natural order.
975
+ function all() {
976
+ if (resetNeeded) reset(), resetNeeded = false;
977
+ return groups;
978
+ }
979
+
980
+ // Returns a new array containing the top K group values, in reduce order.
981
+ function top(k) {
982
+ var top = select(all(), 0, groups.length, k);
983
+ return heap.sort(top, 0, top.length);
984
+ }
985
+
986
+ // Sets the reduce behavior for this group to use the specified functions.
987
+ // This method lazily recomputes the reduce values, waiting until needed.
988
+ function reduce(add, remove, initial) {
989
+ reduceAdd = add;
990
+ reduceRemove = remove;
991
+ reduceInitial = initial;
992
+ resetNeeded = true;
993
+ return group;
994
+ }
995
+
996
+ // A convenience method for reducing by count.
997
+ function reduceCount() {
998
+ return reduce(tesseract_reduceIncrement, tesseract_reduceDecrement, tesseract_zero);
999
+ }
1000
+
1001
+ // A convenience method for reducing by sum(value).
1002
+ function reduceSum(value) {
1003
+ return reduce(tesseract_reduceAdd(value), tesseract_reduceSubtract(value), tesseract_zero);
1004
+ }
1005
+
1006
+ // Sets the reduce order, using the specified accessor.
1007
+ function order(value) {
1008
+ select = heapselect_by(valueOf);
1009
+ heap = heap_by(valueOf);
1010
+ function valueOf(d) { return value(d.value); }
1011
+ return group;
1012
+ }
1013
+
1014
+ // A convenience method for natural ordering by reduce value.
1015
+ function orderNatural() {
1016
+ return order(tesseract_identity);
1017
+ }
1018
+
1019
+ // Returns the cardinality of this group, irrespective of any filters.
1020
+ function size() {
1021
+ return k;
1022
+ }
1023
+
1024
+ return reduceCount().orderNatural();
1025
+ }
1026
+
1027
+ // A convenience function for generating a singleton group.
1028
+ function groupAll() {
1029
+ var g = group(tesseract_null), all = g.all;
1030
+ delete g.all;
1031
+ delete g.top;
1032
+ delete g.order;
1033
+ delete g.orderNatural;
1034
+ delete g.size;
1035
+ g.value = function() { return all()[0].value; };
1036
+ return g;
1037
+ }
1038
+
1039
+ return dimension;
1040
+ }
1041
+
1042
+ // A convenience method for groupAll on a dummy dimension.
1043
+ // This implementation can be optimized since it is always cardinality 1.
1044
+ function groupAll() {
1045
+ var group = {
1046
+ reduce: reduce,
1047
+ reduceCount: reduceCount,
1048
+ reduceSum: reduceSum,
1049
+ value: value
1050
+ };
1051
+
1052
+ var reduceValue,
1053
+ reduceAdd,
1054
+ reduceRemove,
1055
+ reduceInitial,
1056
+ resetNeeded = true;
1057
+
1058
+ // The group listens to the tesseract for when any dimension changes, so
1059
+ // that it can update the reduce value. It must also listen to the parent
1060
+ // dimension for when data is added.
1061
+ filterListeners.push(update);
1062
+ dataListeners.push(add);
1063
+
1064
+ // For consistency; actually a no-op since resetNeeded is true.
1065
+ add(data, 0, n);
1066
+
1067
+ // Incorporates the specified new values into this group.
1068
+ function add(newData, n0, n1) {
1069
+ var i;
1070
+
1071
+ if (resetNeeded) return;
1072
+
1073
+ // Add the added values.
1074
+ for (i = n0; i < n; ++i) {
1075
+ if (!filters[i]) {
1076
+ reduceValue = reduceAdd(reduceValue, data[i]);
1077
+ }
1078
+ }
1079
+ }
1080
+
1081
+ // Reduces the specified selected or deselected records.
1082
+ function update(filterOne, added, removed) {
1083
+ var i,
1084
+ k,
1085
+ n;
1086
+
1087
+ if (resetNeeded) return;
1088
+
1089
+ // Add the added values.
1090
+ for (i = 0, n = added.length; i < n; ++i) {
1091
+ if (!filters[k = added[i]]) {
1092
+ reduceValue = reduceAdd(reduceValue, data[k]);
1093
+ }
1094
+ }
1095
+
1096
+ // Remove the removed values.
1097
+ for (i = 0, n = removed.length; i < n; ++i) {
1098
+ if (filters[k = removed[i]] === filterOne) {
1099
+ reduceValue = reduceRemove(reduceValue, data[k]);
1100
+ }
1101
+ }
1102
+ }
1103
+
1104
+ // Recomputes the group reduce value from scratch.
1105
+ function reset() {
1106
+ var i;
1107
+
1108
+ reduceValue = reduceInitial();
1109
+
1110
+ for (i = 0; i < n; ++i) {
1111
+ if (!filters[i]) {
1112
+ reduceValue = reduceAdd(reduceValue, data[i]);
1113
+ }
1114
+ }
1115
+ }
1116
+
1117
+ // Sets the reduce behavior for this group to use the specified functions.
1118
+ // This method lazily recomputes the reduce value, waiting until needed.
1119
+ function reduce(add, remove, initial) {
1120
+ reduceAdd = add;
1121
+ reduceRemove = remove;
1122
+ reduceInitial = initial;
1123
+ resetNeeded = true;
1124
+ return group;
1125
+ }
1126
+
1127
+ // A convenience method for reducing by count.
1128
+ function reduceCount() {
1129
+ return reduce(tesseract_reduceIncrement, tesseract_reduceDecrement, tesseract_zero);
1130
+ }
1131
+
1132
+ // A convenience method for reducing by sum(value).
1133
+ function reduceSum(value) {
1134
+ return reduce(tesseract_reduceAdd(value), tesseract_reduceSubtract(value), tesseract_zero);
1135
+ }
1136
+
1137
+ // Returns the computed reduce value.
1138
+ function value() {
1139
+ if (resetNeeded) reset(), resetNeeded = false;
1140
+ return reduceValue;
1141
+ }
1142
+
1143
+ return reduceCount();
1144
+ }
1145
+
1146
+ // Returns the number of records in this tesseract, irrespective of any filters.
1147
+ function size() {
1148
+ return n;
1149
+ }
1150
+
1151
+ return arguments.length
1152
+ ? add(arguments[0])
1153
+ : tesseract;
1154
+ }
1155
+
1156
+ // Returns an array of size n, big enough to store ids up to m.
1157
+ function tesseract_index(n, m) {
1158
+ return (m < 0x101
1159
+ ? tesseract_array8 : m < 0x10001
1160
+ ? tesseract_array16
1161
+ : tesseract_array32)(n);
1162
+ }
1163
+
1164
+ // Constructs a new array of size n, with sequential values from 0 to n - 1.
1165
+ function tesseract_range(n) {
1166
+ var range = tesseract_index(n, n);
1167
+ for (var i = -1; ++i < n;) range[i] = i;
1168
+ return range;
1169
+ }
1170
+
1171
+ function tesseract_capacity(w) {
1172
+ return w === 8
1173
+ ? 0x100 : w === 16
1174
+ ? 0x10000
1175
+ : 0x100000000;
1176
+ }
1177
+ })(this);