diff --git a/Dorkbox-Util/src/dorkbox/util/collections/Bias.java b/Dorkbox-Util/src/dorkbox/util/collections/Bias.java
new file mode 100644
index 0000000..a0f474e
--- /dev/null
+++ b/Dorkbox-Util/src/dorkbox/util/collections/Bias.java
@@ -0,0 +1,54 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2013 Tim Boudreau.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package dorkbox.util.collections;
+
+/**
+ * Bias used to decide how to resolve ambiguity, for example in a binary search
+ * with a list of timestamps - if the requested timestamp lies between two
+ * actual data snapshots, should we return the next, previous, nearest one, or
+ * none unless there is an exact match.
+ *
+ * @author Tim Boudreau
+ */
+public enum Bias {
+
+ /**
+ * If a search result falls between two elements, prefer the next element
+ */
+ FORWARD,
+ /**
+ * If a search result falls between two elements, prefer the previous element
+ */
+ BACKWARD,
+ /**
+ * If a search result falls between two elements, prefer the element with
+ * the minimum distance
+ */
+ NEAREST,
+ /**
+ * If a search result falls between two elements, return no element unless
+ * there is an exact match
+ */
+ NONE;
+}
\ No newline at end of file
diff --git a/Dorkbox-Util/src/dorkbox/util/collections/BinarySearch.java b/Dorkbox-Util/src/dorkbox/util/collections/BinarySearch.java
new file mode 100644
index 0000000..2b6a112
--- /dev/null
+++ b/Dorkbox-Util/src/dorkbox/util/collections/BinarySearch.java
@@ -0,0 +1,190 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2013 Tim Boudreau.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package dorkbox.util.collections;
+
+import java.util.List;
+
+/**
+ * General-purpose binary search algorithm; you pass in an array or list
+ * wrapped in an instance of Indexed
, and an
+ * Evaluator
which converts the contents of the list into
+ * numbers used by the binary search algorithm. Note that the data
+ * (as returned by the Indexed array/list) must be in order from
+ * low to high. The indices need not be contiguous (presumably
+ * they are not or you wouldn't be using this class), but they must be
+ * sorted. If assertions are enabled, this is enforced; if not, very
+ * bad things (endless loops, etc.) can happen as a consequence of passing
+ * unsorted data in.
+ *
+ * This class is not thread-safe and the size and contents of the Indexed
+ * should not change while a search is being performed.
+ *
+ * @author Tim Boudreau
+ */
+public class BinarySearch {
+
+ private final Evaluator eval;
+ private final Indexed indexed;
+
+ /**
+ * Create a new binary search.
+ *
+ * @param eval The thing which converts elements into numbers
+ * @param indexed A collection, list or array
+ */
+ public BinarySearch(Evaluator eval, Indexed indexed) {
+ this.eval = eval;
+ this.indexed = indexed;
+ assert checkSorted();
+ }
+
+ public BinarySearch(Evaluator eval, List l) {
+ this (eval, new ListWrap(l));
+ }
+
+ private boolean checkSorted() {
+ long val = Long.MIN_VALUE;
+ long sz = this.indexed.size();
+ for (long i=0; i < sz; i++) {
+ T t = this.indexed.get(i);
+ long nue = this.eval.getValue(t);
+ if (val != Long.MIN_VALUE) {
+ if (nue < val) {
+ throw new IllegalArgumentException("Collection is not sorted at " + i + " - " + this.indexed);
+ }
+ }
+ val = nue;
+ }
+ return true;
+ }
+
+ public long search(long value, Bias bias) {
+ return search(0, this.indexed.size()-1, value, bias);
+ }
+
+ public T match(T prototype, Bias bias) {
+ long value = this.eval.getValue(prototype);
+ long index = search(value, bias);
+ return index == -1 ? null : this.indexed.get(index);
+ }
+
+ public T searchFor(long value, Bias bias) {
+ long index = search(value, bias);
+ return index == -1 ? null : this.indexed.get(index);
+ }
+
+ private long search(long start, long end, long value, Bias bias) {
+ long range = end - start;
+ if (range == 0) {
+ return start;
+ }
+ if (range == 1) {
+ T ahead = this.indexed.get(end);
+ T behind = this.indexed.get(start);
+ long v1 = this.eval.getValue(behind);
+ long v2 = this.eval.getValue(ahead);
+ switch (bias) {
+ case BACKWARD:
+ return start;
+ case FORWARD:
+ return end;
+ case NEAREST:
+ if (v1 == value) {
+ return start;
+ } else if (v2 == value) {
+ return end;
+ } else {
+ if (Math.abs(v1 - value) < Math.abs(v2 - value)) {
+ return start;
+ } else {
+ return end;
+ }
+ }
+ case NONE:
+ if (v1 == value) {
+ return start;
+ } else if (v2 == value) {
+ return end;
+ } else {
+ return -1;
+ }
+ default:
+ throw new AssertionError(bias);
+
+ }
+ }
+ long mid = start + range / 2;
+ long vm = this.eval.getValue(this.indexed.get(mid));
+ if (value >= vm) {
+ return search(mid, end, value, bias);
+ } else {
+ return search(start, mid, value, bias);
+ }
+ }
+
+ /**
+ * Converts an object into a numeric value that is used to
+ * perform binary search
+ * @param
+ */
+ public interface Evaluator {
+
+ public long getValue(T obj);
+ }
+
+ /**
+ * Abstraction for list-like things which have a length and indices
+ * @param
+ */
+ public interface Indexed {
+
+ public T get(long index);
+
+ public long size();
+ }
+
+ private static final class ListWrap implements Indexed {
+
+ private final List l;
+
+ ListWrap(List l) {
+ this.l = l;
+ }
+
+ @Override
+ public T get(long index) {
+ return this.l.get((int) index);
+ }
+
+ @Override
+ public long size() {
+ return this.l.size();
+ }
+
+ @Override
+ public String toString() {
+ return super.toString() + '{' + this.l + '}';
+ }
+ }
+}
\ No newline at end of file
diff --git a/Dorkbox-Util/src/dorkbox/util/collections/ConcurrentHashMapV8.java b/Dorkbox-Util/src/dorkbox/util/collections/ConcurrentHashMapV8.java
index 98b4ab8..c2be6fd 100644
--- a/Dorkbox-Util/src/dorkbox/util/collections/ConcurrentHashMapV8.java
+++ b/Dorkbox-Util/src/dorkbox/util/collections/ConcurrentHashMapV8.java
@@ -3,7 +3,7 @@
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
*/
-package dorkbox.util;
+package dorkbox.util.collections;
import java.io.ObjectStreamField;
import java.io.Serializable;
diff --git a/Dorkbox-Util/src/dorkbox/util/collections/IntArray.java b/Dorkbox-Util/src/dorkbox/util/collections/IntArray.java
index 2b202d4..aae26f0 100644
--- a/Dorkbox-Util/src/dorkbox/util/collections/IntArray.java
+++ b/Dorkbox-Util/src/dorkbox/util/collections/IntArray.java
@@ -16,7 +16,7 @@
// from libGDX
-package dorkbox.util.primativeCollections;
+package dorkbox.util.collections;
import java.util.Arrays;
diff --git a/Dorkbox-Util/src/dorkbox/util/collections/IntMap.java b/Dorkbox-Util/src/dorkbox/util/collections/IntMap.java
index b671c6b..5b306bd 100644
--- a/Dorkbox-Util/src/dorkbox/util/collections/IntMap.java
+++ b/Dorkbox-Util/src/dorkbox/util/collections/IntMap.java
@@ -16,7 +16,7 @@
// slightly tweaked from libGDX
-package dorkbox.util.primativeCollections;
+package dorkbox.util.collections;
import java.util.Iterator;
diff --git a/Dorkbox-Util/src/dorkbox/util/collections/ObjectIntMap.java b/Dorkbox-Util/src/dorkbox/util/collections/ObjectIntMap.java
index 5665bcf..3c35848 100644
--- a/Dorkbox-Util/src/dorkbox/util/collections/ObjectIntMap.java
+++ b/Dorkbox-Util/src/dorkbox/util/collections/ObjectIntMap.java
@@ -1,5 +1,5 @@
-package dorkbox.util.primativeCollections;
+package dorkbox.util.collections;
import com.esotericsoftware.kryo.util.ObjectMap;