propane 3.11.0-java → 4.0.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/.mvn/extensions.xml +1 -1
  3. data/CHANGELOG.md +2 -0
  4. data/README.md +5 -5
  5. data/Rakefile +1 -1
  6. data/lib/propane/app.rb +2 -2
  7. data/lib/propane/version.rb +1 -1
  8. data/lib/propane-4.0.0.jar +0 -0
  9. data/library/slider/slider.rb +1 -1
  10. data/pom.rb +8 -8
  11. data/pom.xml +8 -8
  12. data/propane.gemspec +3 -3
  13. data/src/main/java/monkstone/ColorUtil.java +1 -1
  14. data/src/main/java/monkstone/MathToolModule.java +1 -1
  15. data/src/main/java/monkstone/PropaneLibrary.java +1 -1
  16. data/src/main/java/monkstone/fastmath/DegLutTables.java +10 -11
  17. data/src/main/java/monkstone/fastmath/Deglut.java +1 -1
  18. data/src/main/java/monkstone/filechooser/Chooser.java +1 -1
  19. data/src/main/java/monkstone/noise/LICENSE +121 -0
  20. data/src/main/java/monkstone/slider/CustomHorizontalSlider.java +1 -1
  21. data/src/main/java/monkstone/slider/CustomVerticalSlider.java +1 -1
  22. data/src/main/java/monkstone/slider/SimpleHorizontalSlider.java +1 -1
  23. data/src/main/java/monkstone/slider/SimpleVerticalSlider.java +1 -1
  24. data/src/main/java/monkstone/slider/SliderBar.java +1 -1
  25. data/src/main/java/monkstone/slider/SliderGroup.java +1 -1
  26. data/src/main/java/monkstone/slider/WheelHandler.java +1 -1
  27. data/src/main/java/monkstone/vecmath/package-info.java +1 -1
  28. data/src/main/java/monkstone/vecmath/vec2/Vec2.java +92 -68
  29. data/src/main/java/monkstone/vecmath/vec3/Vec3.java +1 -1
  30. data/src/main/java/monkstone/videoevent/CaptureEvent.java +1 -1
  31. data/src/main/java/monkstone/videoevent/MovieEvent.java +1 -1
  32. data/src/main/java/monkstone/videoevent/package-info.java +1 -1
  33. data/src/main/java/processing/awt/PGraphicsJava2D.java +0 -1
  34. data/src/main/java/processing/awt/PImageAWT.java +2 -4
  35. data/src/main/java/processing/core/PApplet.java +4 -4
  36. data/src/main/java/processing/core/PImage.java +3025 -3047
  37. data/src/main/java/processing/core/PMatrix.java +5 -2
  38. data/src/main/java/processing/data/DoubleDict.java +72 -43
  39. data/src/main/java/processing/data/DoubleList.java +6 -2
  40. data/src/main/java/processing/data/FloatDict.java +744 -756
  41. data/src/main/java/processing/data/FloatList.java +68 -26
  42. data/src/main/java/processing/data/IntDict.java +72 -45
  43. data/src/main/java/processing/data/IntList.java +63 -26
  44. data/src/main/java/processing/data/JSONArray.java +892 -931
  45. data/src/main/java/processing/data/JSONObject.java +1169 -1262
  46. data/src/main/java/processing/data/JSONTokener.java +30 -49
  47. data/src/main/java/processing/data/LongDict.java +699 -712
  48. data/src/main/java/processing/data/LongList.java +676 -700
  49. data/src/main/java/processing/data/Sort.java +1 -0
  50. data/src/main/java/processing/data/Table.java +4040 -3661
  51. data/src/main/java/processing/data/TableRow.java +16 -0
  52. data/src/main/java/processing/data/XML.java +1041 -956
  53. data/src/main/java/processing/event/TouchEvent.java +1 -1
  54. data/src/main/java/processing/opengl/FontTexture.java +2 -2
  55. data/src/main/java/processing/opengl/PGraphicsOpenGL.java +15 -18
  56. data/src/main/java/processing/opengl/PJOGL.java +2 -2
  57. data/src/main/java/processing/opengl/PShapeOpenGL.java +23 -24
  58. data/test/vecmath_spec_test.rb +14 -3
  59. data/vendors/Rakefile +1 -1
  60. metadata +9 -8
  61. data/lib/propane-3.11.0.jar +0 -0
@@ -7,7 +7,6 @@ import java.util.NoSuchElementException;
7
7
 
8
8
  import processing.core.PApplet;
9
9
 
10
-
11
10
  /**
12
11
  * A simple table class to use a String as a lookup for an float value.
13
12
  *
@@ -17,831 +16,820 @@ import processing.core.PApplet;
17
16
  */
18
17
  public class FloatDict {
19
18
 
20
- /** Number of elements in the table */
21
- protected int count;
22
-
23
- protected String[] keys;
24
- protected float[] values;
25
-
26
- /** Internal implementation for faster lookups */
27
- private HashMap<String, Integer> indices = new HashMap<>();
28
-
29
-
30
- public FloatDict() {
31
- count = 0;
32
- keys = new String[10];
33
- values = new float[10];
34
- }
35
-
36
-
37
- /**
38
- * Create a new lookup with a specific size. This is more efficient than not
39
- * specifying a size. Use it when you know the rough size of the thing you're creating.
40
- *
41
- * @nowebref
42
- */
43
- public FloatDict(int length) {
44
- count = 0;
45
- keys = new String[length];
46
- values = new float[length];
47
- }
48
-
49
-
50
- /**
51
- * Read a set of entries from a Reader that has each key/value pair on
52
- * a single line, separated by a tab.
53
- *
54
- * @nowebref
55
- */
56
- public FloatDict(BufferedReader reader) {
57
- String[] lines = PApplet.loadStrings(reader);
58
- keys = new String[lines.length];
59
- values = new float[lines.length];
60
-
61
- for (int i = 0; i < lines.length; i++) {
62
- String[] pieces = PApplet.split(lines[i], '\t');
63
- if (pieces.length == 2) {
64
- keys[count] = pieces[0];
65
- values[count] = PApplet.parseFloat(pieces[1]);
66
- indices.put(pieces[0], count);
67
- count++;
68
- }
19
+ /**
20
+ * Number of elements in the table
21
+ */
22
+ protected int count;
23
+
24
+ protected String[] keys;
25
+ protected float[] values;
26
+
27
+ /**
28
+ * Internal implementation for faster lookups
29
+ */
30
+ private HashMap<String, Integer> indices = new HashMap<>();
31
+
32
+ public FloatDict() {
33
+ count = 0;
34
+ keys = new String[10];
35
+ values = new float[10];
36
+ }
37
+
38
+ /**
39
+ * Create a new lookup with a specific size.This is more efficient than not
40
+ * specifying a size. Use it when you know the rough size of the thing
41
+ * you're creating.
42
+ *
43
+ * @param length
44
+ * @nowebref
45
+ */
46
+ public FloatDict(int length) {
47
+ count = 0;
48
+ keys = new String[length];
49
+ values = new float[length];
50
+ }
51
+
52
+ /**
53
+ * Read a set of entries from a Reader that has each key/value pair on a
54
+ * single line, separated by a tab.
55
+ *
56
+ * @param reader
57
+ * @nowebref
58
+ */
59
+ public FloatDict(BufferedReader reader) {
60
+ String[] lines = PApplet.loadStrings(reader);
61
+ keys = new String[lines.length];
62
+ values = new float[lines.length];
63
+
64
+ for (String line : lines) {
65
+ String[] pieces = PApplet.split(line, '\t');
66
+ if (pieces.length == 2) {
67
+ keys[count] = pieces[0];
68
+ values[count] = PApplet.parseFloat(pieces[1]);
69
+ indices.put(pieces[0], count);
70
+ count++;
71
+ }
72
+ }
69
73
  }
70
- }
71
74
 
72
-
73
- /**
74
- * @nowebref
75
- */
76
- public FloatDict(String[] keys, float[] values) {
77
- if (keys.length != values.length) {
78
- throw new IllegalArgumentException("key and value arrays must be the same length");
79
- }
80
- this.keys = keys;
81
- this.values = values;
82
- count = keys.length;
83
- for (int i = 0; i < count; i++) {
84
- indices.put(keys[i], i);
75
+ /**
76
+ * @param keys
77
+ * @param values
78
+ * @nowebref
79
+ */
80
+ public FloatDict(String[] keys, float[] values) {
81
+ if (keys.length != values.length) {
82
+ throw new IllegalArgumentException("key and value arrays must be the same length");
83
+ }
84
+ this.keys = keys;
85
+ this.values = values;
86
+ count = keys.length;
87
+ for (int i = 0; i < count; i++) {
88
+ indices.put(keys[i], i);
89
+ }
85
90
  }
86
- }
87
91
 
88
-
89
- /**
90
- * Constructor to allow (more intuitive) inline initialization, e.g.:
91
- * <pre>
92
- * new FloatDict(new Object[][] {
93
- * { "key1", 1 },
94
- * { "key2", 2 }
95
- * });
96
- * </pre>
97
- */
98
- public FloatDict(Object[][] pairs) {
99
- count = pairs.length;
100
- this.keys = new String[count];
101
- this.values = new float[count];
102
- for (int i = 0; i < count; i++) {
103
- keys[i] = (String) pairs[i][0];
104
- values[i] = (Float) pairs[i][1];
105
- indices.put(keys[i], i);
92
+ /**
93
+ * Constructor to allow (more intuitive) inline initialization, e.g.:
94
+ * <pre>
95
+ * new FloatDict(new Object[][] {
96
+ * { "key1", 1 },
97
+ * { "key2", 2 }
98
+ * });
99
+ * </pre>
100
+ *
101
+ * @param pairs
102
+ */
103
+ public FloatDict(Object[][] pairs) {
104
+ count = pairs.length;
105
+ this.keys = new String[count];
106
+ this.values = new float[count];
107
+ for (int i = 0; i < count; i++) {
108
+ keys[i] = (String) pairs[i][0];
109
+ values[i] = (Float) pairs[i][1];
110
+ indices.put(keys[i], i);
111
+ }
106
112
  }
107
- }
108
-
109
-
110
- /**
111
- * @webref floatdict:method
112
- * @brief Returns the number of key/value pairs
113
- */
114
- public int size() {
115
- return count;
116
- }
117
113
 
114
+ /**
115
+ * @return @webref floatdict:method
116
+ * @brief Returns the number of key/value pairs
117
+ */
118
+ public int size() {
119
+ return count;
120
+ }
121
+
122
+ /**
123
+ * Resize the internal data, this can only be used to shrink the
124
+ * list.Helpful for situations like sorting and then grabbing the top 50
125
+ * entries.
126
+ *
127
+ * @param length
128
+ */
129
+ public void resize(int length) {
130
+ if (length == count) {
131
+ return;
132
+ }
118
133
 
119
- /**
120
- * Resize the internal data, this can only be used to shrink the list.
121
- * Helpful for situations like sorting and then grabbing the top 50 entries.
122
- */
123
- public void resize(int length) {
124
- if (length == count) return;
134
+ if (length > count) {
135
+ throw new IllegalArgumentException("resize() can only be used to shrink the dictionary");
136
+ }
137
+ if (length < 1) {
138
+ throw new IllegalArgumentException("resize(" + length + ") is too small, use 1 or higher");
139
+ }
125
140
 
126
- if (length > count) {
127
- throw new IllegalArgumentException("resize() can only be used to shrink the dictionary");
128
- }
129
- if (length < 1) {
130
- throw new IllegalArgumentException("resize(" + length + ") is too small, use 1 or higher");
141
+ String[] newKeys = new String[length];
142
+ float[] newValues = new float[length];
143
+ PApplet.arrayCopy(keys, newKeys, length);
144
+ PApplet.arrayCopy(values, newValues, length);
145
+ keys = newKeys;
146
+ values = newValues;
147
+ count = length;
148
+ resetIndices();
149
+ }
150
+
151
+ /**
152
+ * Remove all entries.
153
+ *
154
+ * @webref floatdict:method
155
+ * @brief Remove all entries
156
+ */
157
+ public void clear() {
158
+ count = 0;
159
+ indices = new HashMap<>();
160
+ }
161
+
162
+ private void resetIndices() {
163
+ indices = new HashMap<>(count);
164
+ for (int i = 0; i < count; i++) {
165
+ indices.put(keys[i], i);
166
+ }
131
167
  }
132
168
 
133
- String[] newKeys = new String[length];
134
- float[] newValues = new float[length];
135
- PApplet.arrayCopy(keys, newKeys, length);
136
- PApplet.arrayCopy(values, newValues, length);
137
- keys = newKeys;
138
- values = newValues;
139
- count = length;
140
- resetIndices();
141
- }
142
-
169
+ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
170
+ public class Entry {
143
171
 
144
- /**
145
- * Remove all entries.
146
- *
147
- * @webref floatdict:method
148
- * @brief Remove all entries
149
- */
150
- public void clear() {
151
- count = 0;
152
- indices = new HashMap<>();
153
- }
172
+ public String key;
173
+ public float value;
154
174
 
155
-
156
- private void resetIndices() {
157
- indices = new HashMap<>(count);
158
- for (int i = 0; i < count; i++) {
159
- indices.put(keys[i], i);
175
+ Entry(String key, float value) {
176
+ this.key = key;
177
+ this.value = value;
178
+ }
160
179
  }
161
- }
162
-
163
-
164
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
165
-
166
-
167
- public class Entry {
168
- public String key;
169
- public float value;
170
180
 
171
- Entry(String key, float value) {
172
- this.key = key;
173
- this.value = value;
181
+ public Iterable<Entry> entries() {
182
+ return () -> entryIterator();
174
183
  }
175
- }
176
-
177
-
178
- public Iterable<Entry> entries() {
179
- return new Iterable<Entry>() {
180
-
181
- public Iterator<Entry> iterator() {
182
- return entryIterator();
183
- }
184
- };
185
- }
186
-
187
-
188
- public Iterator<Entry> entryIterator() {
189
- return new Iterator<Entry>() {
190
- int index = -1;
191
-
192
- public void remove() {
193
- removeIndex(index);
194
- index--;
195
- }
196
184
 
197
- public Entry next() {
198
- ++index;
199
- Entry e = new Entry(keys[index], values[index]);
200
- return e;
201
- }
185
+ public Iterator<Entry> entryIterator() {
186
+ return new Iterator<Entry>() {
187
+ int index = -1;
202
188
 
203
- public boolean hasNext() {
204
- return index+1 < size();
205
- }
206
- };
207
- }
208
-
209
-
210
- // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
211
-
212
-
213
- public String key(int index) {
214
- return keys[index];
215
- }
189
+ @Override
190
+ public void remove() {
191
+ removeIndex(index);
192
+ index--;
193
+ }
216
194
 
195
+ @Override
196
+ public Entry next() {
197
+ ++index;
198
+ Entry e = new Entry(keys[index], values[index]);
199
+ return e;
200
+ }
217
201
 
218
- protected void crop() {
219
- if (count != keys.length) {
220
- keys = PApplet.subset(keys, 0, count);
221
- values = PApplet.subset(values, 0, count);
202
+ @Override
203
+ public boolean hasNext() {
204
+ return index + 1 < size();
205
+ }
206
+ };
222
207
  }
223
- }
224
-
225
208
 
226
- public Iterable<String> keys() {
227
- return new Iterable<String>() {
228
-
229
- @Override
230
- public Iterator<String> iterator() {
231
- return keyIterator();
232
- }
233
- };
234
- }
235
-
236
-
237
- // Use this to iterate when you want to be able to remove elements along the way
238
- public Iterator<String> keyIterator() {
239
- return new Iterator<String>() {
240
- int index = -1;
241
-
242
- public void remove() {
243
- removeIndex(index);
244
- index--;
245
- }
209
+ // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
210
+ public String key(int index) {
211
+ return keys[index];
212
+ }
246
213
 
247
- public String next() {
248
- return key(++index);
249
- }
214
+ protected void crop() {
215
+ if (count != keys.length) {
216
+ keys = PApplet.subset(keys, 0, count);
217
+ values = PApplet.subset(values, 0, count);
218
+ }
219
+ }
250
220
 
251
- public boolean hasNext() {
252
- return index+1 < size();
253
- }
254
- };
255
- }
221
+ public Iterable<String> keys() {
222
+ return () -> keyIterator();
223
+ }
256
224
 
225
+ // Use this to iterate when you want to be able to remove elements along the way
226
+ public Iterator<String> keyIterator() {
227
+ return new Iterator<String>() {
228
+ int index = -1;
257
229
 
258
- /**
259
- * Return a copy of the internal keys array. This array can be modified.
260
- *
261
- * @webref floatdict:method
262
- * @brief Return a copy of the internal keys array
263
- */
264
- public String[] keyArray() {
265
- crop();
266
- return keyArray(null);
267
- }
230
+ @Override
231
+ public void remove() {
232
+ removeIndex(index);
233
+ index--;
234
+ }
268
235
 
236
+ @Override
237
+ public String next() {
238
+ return key(++index);
239
+ }
269
240
 
270
- public String[] keyArray(String[] outgoing) {
271
- if (outgoing == null || outgoing.length != count) {
272
- outgoing = new String[count];
241
+ @Override
242
+ public boolean hasNext() {
243
+ return index + 1 < size();
244
+ }
245
+ };
273
246
  }
274
- System.arraycopy(keys, 0, outgoing, 0, count);
275
- return outgoing;
276
- }
277
247
 
248
+ /**
249
+ * Return a copy of the internal keys array.This array can be modified.
250
+ *
251
+ * @return
252
+ * @webref floatdict:method
253
+ * @brief Return a copy of the internal keys array
254
+ */
255
+ public String[] keyArray() {
256
+ crop();
257
+ return keyArray(null);
258
+ }
278
259
 
279
- public float value(int index) {
280
- return values[index];
281
- }
282
-
260
+ public String[] keyArray(String[] outgoing) {
261
+ if (outgoing == null || outgoing.length != count) {
262
+ outgoing = new String[count];
263
+ }
264
+ System.arraycopy(keys, 0, outgoing, 0, count);
265
+ return outgoing;
266
+ }
283
267
 
284
- /**
285
- * @webref floatdict:method
286
- * @brief Return the internal array being used to store the values
287
- */
288
- public Iterable<Float> values() {
289
- return new Iterable<Float>() {
268
+ public float value(int index) {
269
+ return values[index];
270
+ }
290
271
 
291
- @Override
292
- public Iterator<Float> iterator() {
293
- return valueIterator();
294
- }
295
- };
296
- }
272
+ /**
273
+ * @return @webref floatdict:method
274
+ * @brief Return the internal array being used to store the values
275
+ */
276
+ public Iterable<Float> values() {
277
+ return () -> valueIterator();
278
+ }
297
279
 
280
+ public Iterator<Float> valueIterator() {
281
+ return new Iterator<Float>() {
282
+ int index = -1;
298
283
 
299
- public Iterator<Float> valueIterator() {
300
- return new Iterator<Float>() {
301
- int index = -1;
284
+ @Override
285
+ public void remove() {
286
+ removeIndex(index);
287
+ index--;
288
+ }
302
289
 
303
- public void remove() {
304
- removeIndex(index);
305
- index--;
306
- }
307
-
308
- public Float next() {
309
- return value(++index);
310
- }
311
-
312
- public boolean hasNext() {
313
- return index+1 < size();
314
- }
315
- };
316
- }
317
-
318
-
319
- /**
320
- * Create a new array and copy each of the values into it.
321
- *
322
- * @webref floatdict:method
323
- * @brief Create a new array and copy each of the values into it
324
- */
325
- public float[] valueArray() {
326
- crop();
327
- return valueArray(null);
328
- }
329
-
330
-
331
- /**
332
- * Fill an already-allocated array with the values (more efficient than
333
- * creating a new array each time). If 'array' is null, or not the same
334
- * size as the number of values, a new array will be allocated and returned.
335
- */
336
- public float[] valueArray(float[] array) {
337
- if (array == null || array.length != size()) {
338
- array = new float[count];
339
- }
340
- System.arraycopy(values, 0, array, 0, count);
341
- return array;
342
- }
343
-
344
-
345
- /**
346
- * Return a value for the specified key.
347
- *
348
- * @webref floatdict:method
349
- * @brief Return a value for the specified key
350
- */
351
- public float get(String key) {
352
- int index = index(key);
353
- if (index == -1) {
354
- throw new IllegalArgumentException("No key named '" + key + "'");
355
- }
356
- return values[index];
357
- }
358
-
359
-
360
- public float get(String key, float alternate) {
361
- int index = index(key);
362
- if (index == -1) {
363
- return alternate;
364
- }
365
- return values[index];
366
- }
367
-
368
-
369
- /**
370
- * @webref floatdict:method
371
- * @brief Create a new key/value pair or change the value of one
372
- */
373
- public void set(String key, float amount) {
374
- int index = index(key);
375
- if (index == -1) {
376
- create(key, amount);
377
- } else {
378
- values[index] = amount;
379
- }
380
- }
381
-
382
-
383
- public void setIndex(int index, String key, float value) {
384
- if (index < 0 || index >= count) {
385
- throw new ArrayIndexOutOfBoundsException(index);
386
- }
387
- keys[index] = key;
388
- values[index] = value;
389
- }
390
-
391
-
392
- /**
393
- * @webref floatdict:method
394
- * @brief Check if a key is a part of the data structure
395
- */
396
- public boolean hasKey(String key) {
397
- return index(key) != -1;
398
- }
399
-
400
-
401
- /**
402
- * @webref floatdict:method
403
- * @brief Add to a value
404
- */
405
- public void add(String key, float amount) {
406
- int index = index(key);
407
- if (index == -1) {
408
- create(key, amount);
409
- } else {
410
- values[index] += amount;
411
- }
412
- }
413
-
414
-
415
- /**
416
- * @webref floatdict:method
417
- * @brief Subtract from a value
418
- */
419
- public void sub(String key, float amount) {
420
- add(key, -amount);
421
- }
422
-
423
-
424
- /**
425
- * @webref floatdict:method
426
- * @brief Multiply a value
427
- */
428
- public void mult(String key, float amount) {
429
- int index = index(key);
430
- if (index != -1) {
431
- values[index] *= amount;
432
- }
433
- }
434
-
435
-
436
- /**
437
- * @webref floatdict:method
438
- * @brief Divide a value
439
- */
440
- public void div(String key, float amount) {
441
- int index = index(key);
442
- if (index != -1) {
443
- values[index] /= amount;
444
- }
445
- }
446
-
447
-
448
- private void checkMinMax(String functionName) {
449
- if (count == 0) {
450
- String msg =
451
- String.format("Cannot use %s() on an empty %s.",
452
- functionName, getClass().getSimpleName());
453
- throw new RuntimeException(msg);
454
- }
455
- }
456
-
457
-
458
- /**
459
- * @webref floatlist:method
460
- * @brief Return the smallest value
461
- */
462
- public int minIndex() {
463
- //checkMinMax("minIndex");
464
- if (count == 0) return -1;
465
-
466
- // Will still return NaN if there are 1 or more entries, and they're all NaN
467
- float m = Float.NaN;
468
- int mi = -1;
469
- for (int i = 0; i < count; i++) {
470
- // find one good value to start
471
- if (values[i] == values[i]) {
472
- m = values[i];
473
- mi = i;
474
-
475
- // calculate the rest
476
- for (int j = i+1; j < count; j++) {
477
- float d = values[j];
478
- if ((d == d) && (d < m)) {
479
- m = values[j];
480
- mi = j;
481
- }
482
- }
483
- break;
484
- }
485
- }
486
- return mi;
487
- }
488
-
489
-
490
- // return the key for the minimum value
491
- public String minKey() {
492
- checkMinMax("minKey");
493
- int index = minIndex();
494
- if (index == -1) {
495
- return null;
496
- }
497
- return keys[index];
498
- }
290
+ @Override
291
+ public Float next() {
292
+ return value(++index);
293
+ }
499
294
 
500
-
501
- // return the minimum value, or throw an error if there are no values
502
- public float minValue() {
503
- checkMinMax("minValue");
504
- int index = minIndex();
505
- if (index == -1) {
506
- return Float.NaN;
295
+ @Override
296
+ public boolean hasNext() {
297
+ return index + 1 < size();
298
+ }
299
+ };
300
+ }
301
+
302
+ /**
303
+ * Create a new array and copy each of the values into it.
304
+ *
305
+ * @return
306
+ * @webref floatdict:method
307
+ * @brief Create a new array and copy each of the values into it
308
+ */
309
+ public float[] valueArray() {
310
+ crop();
311
+ return valueArray(null);
312
+ }
313
+
314
+ /**
315
+ * Fill an already-allocated array with the values (more efficient than
316
+ * creating a new array each time).If 'array' is null, or not the same size
317
+ * as the number of values, a new array will be allocated and returned.
318
+ *
319
+ * @param array
320
+ * @return
321
+ */
322
+ public float[] valueArray(float[] array) {
323
+ if (array == null || array.length != size()) {
324
+ array = new float[count];
325
+ }
326
+ System.arraycopy(values, 0, array, 0, count);
327
+ return array;
328
+ }
329
+
330
+ /**
331
+ * Return a value for the specified key.
332
+ *
333
+ * @param key
334
+ * @return
335
+ * @webref floatdict:method
336
+ * @brief Return a value for the specified key
337
+ */
338
+ public float get(String key) {
339
+ int index = index(key);
340
+ if (index == -1) {
341
+ throw new IllegalArgumentException("No key named '" + key + "'");
342
+ }
343
+ return values[index];
507
344
  }
508
- return values[index];
509
- }
510
-
511
345
 
512
- /**
513
- * @webref floatlist:method
514
- * @brief Return the largest value
515
- */
516
- // The index of the entry that has the max value. Reference above is incorrect.
517
- public int maxIndex() {
518
- //checkMinMax("maxIndex");
519
- if (count == 0) {
520
- return -1;
346
+ public float get(String key, float alternate) {
347
+ int index = index(key);
348
+ if (index == -1) {
349
+ return alternate;
350
+ }
351
+ return values[index];
352
+ }
353
+
354
+ /**
355
+ * @param key
356
+ * @param amount
357
+ * @webref floatdict:method
358
+ * @brief Create a new key/value pair or change the value of one
359
+ */
360
+ public void set(String key, float amount) {
361
+ int index = index(key);
362
+ if (index == -1) {
363
+ create(key, amount);
364
+ } else {
365
+ values[index] = amount;
366
+ }
521
367
  }
522
- // Will still return NaN if there is 1 or more entries, and they're all NaN
523
- float m = Float.NaN;
524
- int mi = -1;
525
- for (int i = 0; i < count; i++) {
526
- // find one good value to start
527
- if (values[i] == values[i]) {
528
- m = values[i];
529
- mi = i;
530
-
531
- // calculate the rest
532
- for (int j = i+1; j < count; j++) {
533
- float d = values[j];
534
- if (!Float.isNaN(d) && (d > m)) {
535
- m = values[j];
536
- mi = j;
537
- }
538
- }
539
- break;
540
- }
541
- }
542
- return mi;
543
- }
544
-
545
-
546
- /** The key for a max value; null if empty or everything is NaN (no max). */
547
- public String maxKey() {
548
- //checkMinMax("maxKey");
549
- int index = maxIndex();
550
- if (index == -1) {
551
- return null;
552
- }
553
- return keys[index];
554
- }
555
-
556
-
557
- /** The max value. (Or NaN if no entries or they're all NaN.) */
558
- public float maxValue() {
559
- //checkMinMax("maxValue");
560
- int index = maxIndex();
561
- if (index == -1) {
562
- return Float.NaN;
563
- }
564
- return values[index];
565
- }
566
-
567
-
568
- public float sum() {
569
- double amount = sumDouble();
570
- if (amount > Float.MAX_VALUE) {
571
- throw new RuntimeException("sum() exceeds " + Float.MAX_VALUE + ", use sumDouble()");
572
- }
573
- if (amount < -Float.MAX_VALUE) {
574
- throw new RuntimeException("sum() lower than " + -Float.MAX_VALUE + ", use sumDouble()");
575
- }
576
- return (float) amount;
577
- }
578
-
579
368
 
580
- public double sumDouble() {
581
- double sum = 0;
582
- for (int i = 0; i < count; i++) {
583
- sum += values[i];
369
+ public void setIndex(int index, String key, float value) {
370
+ if (index < 0 || index >= count) {
371
+ throw new ArrayIndexOutOfBoundsException(index);
372
+ }
373
+ keys[index] = key;
374
+ values[index] = value;
375
+ }
376
+
377
+ /**
378
+ * @param key
379
+ * @return
380
+ * @webref floatdict:method
381
+ * @brief Check if a key is a part of the data structure
382
+ */
383
+ public boolean hasKey(String key) {
384
+ return index(key) != -1;
385
+ }
386
+
387
+ /**
388
+ * @param key
389
+ * @param amount
390
+ * @webref floatdict:method
391
+ * @brief Add to a value
392
+ */
393
+ public void add(String key, float amount) {
394
+ int index = index(key);
395
+ if (index == -1) {
396
+ create(key, amount);
397
+ } else {
398
+ values[index] += amount;
399
+ }
584
400
  }
585
- return sum;
586
- }
587
-
588
-
589
- public int index(String what) {
590
- Integer found = indices.get(what);
591
- return (found == null) ? -1 : found.intValue();
592
- }
593
-
594
401
 
595
- protected void create(String what, float much) {
596
- if (count == keys.length) {
597
- keys = PApplet.expand(keys);
598
- values = PApplet.expand(values);
402
+ /**
403
+ * @param key
404
+ * @param amount
405
+ * @webref floatdict:method
406
+ * @brief Subtract from a value
407
+ */
408
+ public void sub(String key, float amount) {
409
+ add(key, -amount);
410
+ }
411
+
412
+ /**
413
+ * @param key
414
+ * @param amount
415
+ * @webref floatdict:method
416
+ * @brief Multiply a value
417
+ */
418
+ public void mult(String key, float amount) {
419
+ int index = index(key);
420
+ if (index != -1) {
421
+ values[index] *= amount;
422
+ }
599
423
  }
600
- indices.put(what, Integer.valueOf(count));
601
- keys[count] = what;
602
- values[count] = much;
603
- count++;
604
- }
605
424
 
425
+ /**
426
+ * @param key
427
+ * @param amount
428
+ * @webref floatdict:method
429
+ * @brief Divide a value
430
+ */
431
+ public void div(String key, float amount) {
432
+ int index = index(key);
433
+ if (index != -1) {
434
+ values[index] /= amount;
435
+ }
436
+ }
606
437
 
607
- /**
608
- * @webref floatdict:method
609
- * @brief Remove a key/value pair
610
- */
611
- public float remove(String key) {
612
- int index = index(key);
613
- if (index == -1) {
614
- throw new NoSuchElementException("'" + key + "' not found");
615
- }
616
- float value = values[index];
617
- removeIndex(index);
618
- return value;
619
- }
438
+ private void checkMinMax(String functionName) {
439
+ if (count == 0) {
440
+ String msg
441
+ = String.format("Cannot use %s() on an empty %s.",
442
+ functionName, getClass().getSimpleName());
443
+ throw new RuntimeException(msg);
444
+ }
445
+ }
620
446
 
447
+ /**
448
+ * @return @webref floatlist:method
449
+ * @brief Return the smallest value
450
+ */
451
+ public int minIndex() {
452
+ //checkMinMax("minIndex");
453
+ if (count == 0) {
454
+ return -1;
455
+ }
621
456
 
622
- public float removeIndex(int index) {
623
- if (index < 0 || index >= count) {
624
- throw new ArrayIndexOutOfBoundsException(index);
625
- }
626
- float value = values[index];
627
- indices.remove(keys[index]);
628
- for (int i = index; i < count-1; i++) {
629
- keys[i] = keys[i+1];
630
- values[i] = values[i+1];
631
- indices.put(keys[i], i);
457
+ // Will still return NaN if there are 1 or more entries, and they're all NaN
458
+ float m = Float.NaN;
459
+ int mi = -1;
460
+ for (int i = 0; i < count; i++) {
461
+ // find one good value to start
462
+ if (values[i] == values[i]) {
463
+ m = values[i];
464
+ mi = i;
465
+
466
+ // calculate the rest
467
+ for (int j = i + 1; j < count; j++) {
468
+ float d = values[j];
469
+ if ((d == d) && (d < m)) {
470
+ m = values[j];
471
+ mi = j;
472
+ }
473
+ }
474
+ break;
475
+ }
476
+ }
477
+ return mi;
632
478
  }
633
- count--;
634
- keys[count] = null;
635
- values[count] = 0;
636
- return value;
637
- }
638
-
639
479
 
640
- public void swap(int a, int b) {
641
- String tkey = keys[a];
642
- float tvalue = values[a];
643
- keys[a] = keys[b];
644
- values[a] = values[b];
645
- keys[b] = tkey;
646
- values[b] = tvalue;
480
+ // return the key for the minimum value
481
+ public String minKey() {
482
+ checkMinMax("minKey");
483
+ int index = minIndex();
484
+ if (index == -1) {
485
+ return null;
486
+ }
487
+ return keys[index];
488
+ }
647
489
 
648
- // indices.put(keys[a], Integer.valueOf(a));
649
- // indices.put(keys[b], Integer.valueOf(b));
650
- }
651
-
652
-
653
- /**
654
- * Sort the keys alphabetically (ignoring case). Uses the value as a
655
- * tie-breaker (only really possible with a key that has a case change).
656
- *
657
- * @webref floatdict:method
658
- * @brief Sort the keys alphabetically
659
- */
660
- public void sortKeys() {
661
- sortImpl(true, false, true);
662
- }
663
-
664
-
665
- /**
666
- * @webref floatdict:method
667
- * @brief Sort the keys alphabetically in reverse
668
- */
669
- public void sortKeysReverse() {
670
- sortImpl(true, true, true);
671
- }
672
-
673
-
674
- /**
675
- * Sort by values in descending order (largest value will be at [0]).
676
- *
677
- * @webref floatdict:method
678
- * @brief Sort by values in ascending order
679
- */
680
- public void sortValues() {
681
- sortValues(true);
682
- }
683
-
684
-
685
- /**
686
- * Set true to ensure that the order returned is identical. Slightly
687
- * slower because the tie-breaker for identical values compares the keys.
688
- * @param stable
689
- */
690
- public void sortValues(boolean stable) {
691
- sortImpl(false, false, stable);
692
- }
693
-
694
-
695
- /**
696
- * @webref floatdict:method
697
- * @brief Sort by values in descending order
698
- */
699
- public void sortValuesReverse() {
700
- sortValuesReverse(true);
701
- }
702
-
703
-
704
- public void sortValuesReverse(boolean stable) {
705
- sortImpl(false, true, stable);
706
- }
707
-
708
-
709
- protected void sortImpl(final boolean useKeys, final boolean reverse,
710
- final boolean stable) {
711
- Sort s = new Sort() {
712
- @Override
713
- public int size() {
714
- if (useKeys) {
715
- return count; // don't worry about NaN values
716
-
717
- } else if (count == 0) { // skip the NaN check, it'll AIOOBE
718
- return 0;
719
-
720
- } else { // first move NaN values to the end of the list
721
- int right = count - 1;
722
- while (values[right] != values[right]) {
723
- right--;
724
- if (right == -1) {
725
- return 0; // all values are NaN
726
- }
727
- }
728
- for (int i = right; i >= 0; --i) {
729
- if (Float.isNaN(values[i])) {
730
- swap(i, right);
731
- --right;
490
+ // return the minimum value, or throw an error if there are no values
491
+ public float minValue() {
492
+ checkMinMax("minValue");
493
+ int index = minIndex();
494
+ if (index == -1) {
495
+ return Float.NaN;
496
+ }
497
+ return values[index];
498
+ }
499
+
500
+ /**
501
+ * @return @webref floatlist:method
502
+ * @brief Return the largest value
503
+ */
504
+ // The index of the entry that has the max value. Reference above is incorrect.
505
+ public int maxIndex() {
506
+ //checkMinMax("maxIndex");
507
+ if (count == 0) {
508
+ return -1;
509
+ }
510
+ // Will still return NaN if there is 1 or more entries, and they're all NaN
511
+ float m = Float.NaN;
512
+ int mi = -1;
513
+ for (int i = 0; i < count; i++) {
514
+ // find one good value to start
515
+ if (values[i] == values[i]) {
516
+ m = values[i];
517
+ mi = i;
518
+
519
+ // calculate the rest
520
+ for (int j = i + 1; j < count; j++) {
521
+ float d = values[j];
522
+ if (!Float.isNaN(d) && (d > m)) {
523
+ m = values[j];
524
+ mi = j;
525
+ }
526
+ }
527
+ break;
732
528
  }
733
- }
734
- return right + 1;
735
- }
736
- }
737
-
738
- @Override
739
- public int compare(int a, int b) {
740
- float diff = 0;
741
- if (useKeys) {
742
- diff = keys[a].compareToIgnoreCase(keys[b]);
743
- if (diff == 0) {
744
- diff = values[a] - values[b];
745
- }
746
- } else { // sort values
747
- diff = values[a] - values[b];
748
- if (diff == 0 && stable) {
749
- diff = keys[a].compareToIgnoreCase(keys[b]);
750
- }
751
- }
752
- if (diff == 0) {
753
- return 0;
754
- } else if (reverse) {
755
- return diff < 0 ? 1 : -1;
756
- } else {
757
- return diff < 0 ? -1 : 1;
758
529
  }
759
- }
530
+ return mi;
531
+ }
532
+
533
+ /**
534
+ * The key for a max value; null if empty or everything is NaN (no max).
535
+ *
536
+ * @return
537
+ */
538
+ public String maxKey() {
539
+ //checkMinMax("maxKey");
540
+ int index = maxIndex();
541
+ if (index == -1) {
542
+ return null;
543
+ }
544
+ return keys[index];
545
+ }
546
+
547
+ /**
548
+ * * The max value.(Or NaN if no entries or they're all NaN.)
549
+ *
550
+ * @return
551
+ */
552
+ public float maxValue() {
553
+ //checkMinMax("maxValue");
554
+ int index = maxIndex();
555
+ if (index == -1) {
556
+ return Float.NaN;
557
+ }
558
+ return values[index];
559
+ }
760
560
 
761
- @Override
762
- public void swap(int a, int b) {
763
- FloatDict.this.swap(a, b);
764
- }
765
- };
766
- s.run();
561
+ public float sum() {
562
+ double amount = sumDouble();
563
+ if (amount > Float.MAX_VALUE) {
564
+ throw new RuntimeException("sum() exceeds " + Float.MAX_VALUE + ", use sumDouble()");
565
+ }
566
+ if (amount < -Float.MAX_VALUE) {
567
+ throw new RuntimeException("sum() lower than " + -Float.MAX_VALUE + ", use sumDouble()");
568
+ }
569
+ return (float) amount;
570
+ }
767
571
 
768
- // Set the indices after sort/swaps (performance fix 160411)
769
- resetIndices();
770
- }
572
+ public double sumDouble() {
573
+ double sum = 0;
574
+ for (int i = 0; i < count; i++) {
575
+ sum += values[i];
576
+ }
577
+ return sum;
578
+ }
771
579
 
580
+ public int index(String what) {
581
+ Integer found = indices.get(what);
582
+ return (found == null) ? -1 : found;
583
+ }
772
584
 
773
- /**
774
- * Sum all of the values in this dictionary, then return a new FloatDict of
775
- * each key, divided by the total sum. The total for all values will be ~1.0.
776
- * @return a FloatDict with the original keys, mapped to their pct of the total
777
- */
778
- public FloatDict getPercent() {
779
- double sum = sum();
780
- FloatDict outgoing = new FloatDict();
781
- for (int i = 0; i < size(); i++) {
782
- double percent = value(i) / sum;
783
- outgoing.set(key(i), (float) percent);
585
+ protected void create(String what, float much) {
586
+ if (count == keys.length) {
587
+ keys = PApplet.expand(keys);
588
+ values = PApplet.expand(values);
589
+ }
590
+ indices.put(what, count);
591
+ keys[count] = what;
592
+ values[count] = much;
593
+ count++;
784
594
  }
785
- return outgoing;
786
- }
787
595
 
596
+ /**
597
+ * @param key
598
+ * @return
599
+ * @webref floatdict:method
600
+ * @brief Remove a key/value pair
601
+ */
602
+ public float remove(String key) {
603
+ int index = index(key);
604
+ if (index == -1) {
605
+ throw new NoSuchElementException("'" + key + "' not found");
606
+ }
607
+ float value = values[index];
608
+ removeIndex(index);
609
+ return value;
610
+ }
788
611
 
789
- /** Returns a duplicate copy of this object. */
790
- public FloatDict copy() {
791
- FloatDict outgoing = new FloatDict(count);
792
- System.arraycopy(keys, 0, outgoing.keys, 0, count);
793
- System.arraycopy(values, 0, outgoing.values, 0, count);
794
- for (int i = 0; i < count; i++) {
795
- outgoing.indices.put(keys[i], i);
612
+ public float removeIndex(int index) {
613
+ if (index < 0 || index >= count) {
614
+ throw new ArrayIndexOutOfBoundsException(index);
615
+ }
616
+ float value = values[index];
617
+ indices.remove(keys[index]);
618
+ for (int i = index; i < count - 1; i++) {
619
+ keys[i] = keys[i + 1];
620
+ values[i] = values[i + 1];
621
+ indices.put(keys[i], i);
622
+ }
623
+ count--;
624
+ keys[count] = null;
625
+ values[count] = 0;
626
+ return value;
796
627
  }
797
- outgoing.count = count;
798
- return outgoing;
799
- }
800
628
 
629
+ public void swap(int a, int b) {
630
+ String tkey = keys[a];
631
+ float tvalue = values[a];
632
+ keys[a] = keys[b];
633
+ values[a] = values[b];
634
+ keys[b] = tkey;
635
+ values[b] = tvalue;
801
636
 
802
- public void print() {
803
- for (int i = 0; i < size(); i++) {
804
- System.out.println(keys[i] + " = " + values[i]);
637
+ // indices.put(keys[a], Integer.valueOf(a));
638
+ // indices.put(keys[b], Integer.valueOf(b));
805
639
  }
806
- }
807
640
 
641
+ /**
642
+ * Sort the keys alphabetically (ignoring case). Uses the value as a
643
+ * tie-breaker (only really possible with a key that has a case change).
644
+ *
645
+ * @webref floatdict:method
646
+ * @brief Sort the keys alphabetically
647
+ */
648
+ public void sortKeys() {
649
+ sortImpl(true, false, true);
650
+ }
651
+
652
+ /**
653
+ * @webref floatdict:method
654
+ * @brief Sort the keys alphabetically in reverse
655
+ */
656
+ public void sortKeysReverse() {
657
+ sortImpl(true, true, true);
658
+ }
659
+
660
+ /**
661
+ * Sort by values in descending order (largest value will be at [0]).
662
+ *
663
+ * @webref floatdict:method
664
+ * @brief Sort by values in ascending order
665
+ */
666
+ public void sortValues() {
667
+ sortValues(true);
668
+ }
669
+
670
+ /**
671
+ * Set true to ensure that the order returned is identical. Slightly slower
672
+ * because the tie-breaker for identical values compares the keys.
673
+ *
674
+ * @param stable
675
+ */
676
+ public void sortValues(boolean stable) {
677
+ sortImpl(false, false, stable);
678
+ }
679
+
680
+ /**
681
+ * @webref floatdict:method
682
+ * @brief Sort by values in descending order
683
+ */
684
+ public void sortValuesReverse() {
685
+ sortValuesReverse(true);
686
+ }
687
+
688
+ public void sortValuesReverse(boolean stable) {
689
+ sortImpl(false, true, stable);
690
+ }
691
+
692
+ protected void sortImpl(final boolean useKeys, final boolean reverse,
693
+ final boolean stable) {
694
+ Sort s = new Sort() {
695
+ @Override
696
+ public int size() {
697
+ if (useKeys) {
698
+ return count; // don't worry about NaN values
699
+
700
+ } else if (count == 0) { // skip the NaN check, it'll AIOOBE
701
+ return 0;
702
+
703
+ } else { // first move NaN values to the end of the list
704
+ int right = count - 1;
705
+ while (values[right] != values[right]) {
706
+ right--;
707
+ if (right == -1) {
708
+ return 0; // all values are NaN
709
+ }
710
+ }
711
+ for (int i = right; i >= 0; --i) {
712
+ if (Float.isNaN(values[i])) {
713
+ swap(i, right);
714
+ --right;
715
+ }
716
+ }
717
+ return right + 1;
718
+ }
719
+ }
808
720
 
809
- /**
810
- * Save tab-delimited entries to a file (TSV format, UTF-8 encoding)
811
- */
812
- public void save(File file) {
813
- PrintWriter writer = PApplet.createWriter(file);
814
- write(writer);
815
- writer.close();
816
- }
817
-
721
+ @Override
722
+ public int compare(int a, int b) {
723
+ float diff = 0;
724
+ if (useKeys) {
725
+ diff = keys[a].compareToIgnoreCase(keys[b]);
726
+ if (diff == 0) {
727
+ diff = values[a] - values[b];
728
+ }
729
+ } else { // sort values
730
+ diff = values[a] - values[b];
731
+ if (diff == 0 && stable) {
732
+ diff = keys[a].compareToIgnoreCase(keys[b]);
733
+ }
734
+ }
735
+ if (diff == 0) {
736
+ return 0;
737
+ } else if (reverse) {
738
+ return diff < 0 ? 1 : -1;
739
+ } else {
740
+ return diff < 0 ? -1 : 1;
741
+ }
742
+ }
818
743
 
819
- /**
820
- * Write tab-delimited entries out to
821
- * @param writer
822
- */
823
- public void write(PrintWriter writer) {
824
- for (int i = 0; i < count; i++) {
825
- writer.println(keys[i] + "\t" + values[i]);
744
+ @Override
745
+ public void swap(int a, int b) {
746
+ FloatDict.this.swap(a, b);
747
+ }
748
+ };
749
+ s.run();
750
+
751
+ // Set the indices after sort/swaps (performance fix 160411)
752
+ resetIndices();
753
+ }
754
+
755
+ /**
756
+ * Sum all of the values in this dictionary, then return a new FloatDict of
757
+ * each key, divided by the total sum. The total for all values will be
758
+ * ~1.0.
759
+ *
760
+ * @return a FloatDict with the original keys, mapped to their pct of the
761
+ * total
762
+ */
763
+ public FloatDict getPercent() {
764
+ double sum = sum();
765
+ FloatDict outgoing = new FloatDict();
766
+ for (int i = 0; i < size(); i++) {
767
+ double percent = value(i) / sum;
768
+ outgoing.set(key(i), (float) percent);
769
+ }
770
+ return outgoing;
771
+ }
772
+
773
+ /**
774
+ * Returns a duplicate copy of this object.
775
+ *
776
+ * @return
777
+ */
778
+ public FloatDict copy() {
779
+ FloatDict outgoing = new FloatDict(count);
780
+ System.arraycopy(keys, 0, outgoing.keys, 0, count);
781
+ System.arraycopy(values, 0, outgoing.values, 0, count);
782
+ for (int i = 0; i < count; i++) {
783
+ outgoing.indices.put(keys[i], i);
784
+ }
785
+ outgoing.count = count;
786
+ return outgoing;
826
787
  }
827
- writer.flush();
828
- }
829
788
 
789
+ public void print() {
790
+ for (int i = 0; i < size(); i++) {
791
+ System.out.println(keys[i] + " = " + values[i]);
792
+ }
793
+ }
830
794
 
831
- /**
832
- * Return this dictionary as a String in JSON format.
833
- */
834
- public String toJSON() {
835
- StringList items = new StringList();
836
- for (int i = 0; i < count; i++) {
837
- items.append(JSONObject.quote(keys[i])+ ": " + values[i]);
795
+ /**
796
+ * Save tab-delimited entries to a file (TSV format, UTF-8 encoding)
797
+ *
798
+ * @param file
799
+ */
800
+ public void save(File file) {
801
+ try (PrintWriter writer = PApplet.createWriter(file)) {
802
+ write(writer);
803
+ }
838
804
  }
839
- return "{ " + items.join(", ") + " }";
840
- }
841
805
 
806
+ /**
807
+ * Write tab-delimited entries out to
808
+ *
809
+ * @param writer
810
+ */
811
+ public void write(PrintWriter writer) {
812
+ for (int i = 0; i < count; i++) {
813
+ writer.println(keys[i] + "\t" + values[i]);
814
+ }
815
+ writer.flush();
816
+ }
817
+
818
+ /**
819
+ * Return this dictionary as a String in JSON format.
820
+ *
821
+ * @return
822
+ */
823
+ public String toJSON() {
824
+ StringList items = new StringList();
825
+ for (int i = 0; i < count; i++) {
826
+ items.append(JSONObject.quote(keys[i]) + ": " + values[i]);
827
+ }
828
+ return "{ " + items.join(", ") + " }";
829
+ }
842
830
 
843
- @Override
844
- public String toString() {
845
- return getClass().getSimpleName() + " size=" + size() + " " + toJSON();
846
- }
831
+ @Override
832
+ public String toString() {
833
+ return getClass().getSimpleName() + " size=" + size() + " " + toJSON();
834
+ }
847
835
  }