diff --git a/src/Main.java b/src/Main.java
index db3c0ff20b675352bdde51d4eabd7f5230222477..ec16db1494800f43bae2ba9076e14ad40522fa79 100644
--- a/src/Main.java
+++ b/src/Main.java
@@ -1,13 +1,28 @@
 import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Scanner;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 import org.json.simple.parser.ParseException;
 
 import data.BioTree;
 import data.DataStore;
+import data.Date;
 import data.FileProcessor;
 import data.Record;
+import data.WormsAPI;
+import search.BST;
 import search.BasicSearch;
+import search.BasicSearchResult;
+import search.Histogram;
+import sort.Bound;
+import sort.GeneralRange;
 import sort.KDT;
+import sort.RangeHelper;
+import utils.Stopwatch;
 
 public class Main {
 	public static void main(String[] args) {
@@ -27,7 +42,7 @@ public class Main {
 			BioTree.write("data/biotree/");
 			DataStore.records.writeToFile("data/kdt.ser");
 		};
-		BasicSearch.init();
+		init();
 	}
 	
 	private static void printLogo() {
@@ -53,4 +68,135 @@ public class Main {
 				"                      `-'             `````````");
 		System.out.println("Loading.......");
 	}
+	
+	public static void init() {
+		System.out.println("Welcome!");
+		while(true) {
+			System.out.println("Main Menu");
+			System.out.println("Available commands:");
+			System.out.println("\ttree [taxonId / scientific name]");
+			System.out.println("\trecords (taxonId / scientific name) [-t start end]");
+			System.out.print("> ");
+			Pattern pat = Pattern.compile("([a-zA-Z]+)[ ]?([0-9a-zA-Z ]+[0-9a-zA-Z])?[ ]?[-]?([a-zA-Z])?[ ]?([A-Za-z0-9]+)?[ ]?([A-Za-z0-9]+)?[ ]?([A-Za-z0-9]+)?[ ]?([A-Za-z0-9]+)?[ ]?([A-Za-z0-9]+)?[ ]?");
+			Scanner s = new Scanner(System.in);
+			String line = s.nextLine();
+			Matcher matcher = pat.matcher(line);
+			if (!matcher.find()) continue;
+			
+			//tree
+			//tree taxonId
+			//tree scientific name
+			//records taxonId
+			//records scientific name
+			String command = matcher.group(1);
+			
+			if (command.equals("records"))
+				rangeSearch(matcher);
+			else if (command.equals("tree"))
+				printTree(matcher);
+		}
+	}
+	
+	private static void rangeSearch(Matcher matcher) {
+		Integer start = null;
+		Integer end = null;
+		if (matcher.group(3) != null)
+			if (matcher.group(3).equals("t")) {
+				if (matcher.group(4) != null)
+					start = Integer.parseInt(matcher.group(4));
+				if (matcher.group(5) != null)
+					end = Integer.parseInt(matcher.group(5));
+			}
+		
+		Integer taxonId = null;
+		try {
+			taxonId = Integer.parseInt(matcher.group(2));
+		} catch (NumberFormatException e) {
+			if (taxonId == null) {
+				try {
+					taxonId = WormsAPI.nameToRecordID(matcher.group(2));
+				} catch (IOException e1) {
+					// TODO Auto-generated catch block
+					e.printStackTrace();
+				} catch (ParseException e1) {
+					// TODO Auto-generated catch block
+					e.printStackTrace();
+				}
+			}
+		}
+		
+		BasicSearchResult result = BasicSearch.range(taxonId, start, end);
+		
+		System.out.println("Found " + result.n() + " records in " + result.time() + " seconds.");
+		
+		while(true) {
+			System.out.println("Available commands: list, histogram, sum, exit");
+			System.out.print("> ");
+			
+			Scanner s = new Scanner(System.in);
+			String command = s.nextLine();
+			
+			if (command.equals("list"))
+				printRecords(result.results());
+			else if (command.equals("histogram")) {
+				printHistogram(result.histogram());
+			} else if (command.equals("exit"))
+				return;
+			else if (command.equals("sum")) {
+				System.out.println(result.sum());
+			}
+		}
+	}
+	
+	private static void printRecords(Iterable<Record> results) {
+		String format = "|%1$-45s|%2$-15s|%3$-15s|%4$-15s|%5$-15s|%6$-15s\n";
+		System.out.format(format, "Scientific Name", "IndividualCount", "Latitude", "Longitude","Year","Month","Day");
+		for (Record r: results) {
+			System.out.println(r);
+		}
+	}
+	
+	private static void printTree(Matcher matcher) {
+		Integer taxonId;
+		String name;
+		if (matcher.group(2) == null)
+			BioTree.printTree();
+		else {
+			name = matcher.group(2);
+			try {
+				taxonId = Integer.parseInt(name);
+				BioTree.printTree(taxonId);
+			} catch (Exception e) {
+				BioTree.printTree(name);
+			}
+		}
+		System.out.println();
+	}
+	
+	/**
+	 * Prints a histogram based on a BST of records
+	 * 
+	 * @param record -An BST of records
+	 */
+	public static void printHistogram(BST<Integer,Integer> record) {
+		int max = 0;
+		int scale = 100;
+		Iterable<Integer> results = record.keys();
+		for (Integer year: results) {
+			if (max < record.get(year)) max =record.get(year);
+
+		}
+		System.out.println("     |" + (new String(new char[scale]).replace('\0', '-')) + "|");
+		String format = "%1$-5d|%2$-" + (scale + 1) + "s";
+		for (Integer year: results) {
+			String s = "=";
+			int loopc = (int) ((float)(record.get(year)/ (float) max) * scale);
+			for (int j=0; j< loopc; j++) {
+				s+="=";
+			}
+			System.out.format(format, year, s);
+			System.out.println("| " + record.get(year));
+		}
+		System.out.format("Scale: one = is %d individuals.\n", max / scale);
+	}
 }
diff --git a/src/search/BasicSearch.java b/src/search/BasicSearch.java
index 97cdb49d90124c76e19b0a2b4023a232cc1988eb..ec7894aa92b82a9f8d845bf7091c968987bfc82c 100644
--- a/src/search/BasicSearch.java
+++ b/src/search/BasicSearch.java
@@ -1,84 +1,37 @@
 package search;
 
-import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Scanner;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import org.json.simple.parser.ParseException;
-
 import utils.Stopwatch;
 import data.BioTree;
 import data.DataStore;
 import data.Date;
 import data.Record;
-import data.WormsAPI;
 import sort.Bound;
 import sort.GeneralRange;
 import sort.RangeHelper;
 
+/**
+ * Provides functionality for range searching the Record database.
+ * @author Christopher W. Schankula
+ *
+ */
 public class BasicSearch {
-	public static void init() {
-		System.out.println("Welcome!");
-		while(true) {
-			System.out.println("Main Menu");
-			System.out.println("Available commands:");
-			System.out.println("\ttree [taxonId / scientific name]");
-			System.out.println("\trecords (taxonId / scientific name) [-t start end]");
-			System.out.print("> ");
-			Pattern pat = Pattern.compile("([a-zA-Z]+)[ ]?([0-9a-zA-Z ]+[0-9a-zA-Z])?[ ]?[-]?([a-zA-Z])?[ ]?([A-Za-z0-9]+)?[ ]?([A-Za-z0-9]+)?[ ]?([A-Za-z0-9]+)?[ ]?([A-Za-z0-9]+)?[ ]?([A-Za-z0-9]+)?[ ]?");
-			Scanner s = new Scanner(System.in);
-			String line = s.nextLine();
-			Matcher matcher = pat.matcher(line);
-			if (!matcher.find()) continue;
-			
-			//tree
-			//tree taxonId
-			//tree scientific name
-			//records taxonId
-			//records scientific name
-			String command = matcher.group(1);
-			
-			if (command.equals("records"))
-				rangeSearch(matcher);
-			else if (command.equals("tree"))
-				printTree(matcher);
-		}
-	}
-	
-	private static void rangeSearch(Matcher matcher) {
-		Integer start = null;
-		Integer end = null;
+	/**
+	 * Returns all records matching any of the children of the given TaxonID and in the 
+	 * date range given
+	 * @param taxonId The TaxonID for which to search
+	 * @param yearLo The lower bound on the year range
+	 * @param yearHi The upper bound on the year range
+	 * @return
+	 */
+	public static BasicSearchResult range(Integer taxonId, Integer yearLo, Integer yearHi){
 		GeneralRange<Record> a0 = RangeHelper.date(Bound.ANY);
-		if (matcher.group(3) != null)
-			if (matcher.group(3).equals("t")) {
-				if (matcher.group(4) != null)
-					start = Integer.parseInt(matcher.group(4));
-				if (matcher.group(5) != null)
-					end = Integer.parseInt(matcher.group(5));
-				Date lower = new Date(start,01,01);
-				Date upper = new Date(end+1,01,01);
-				
-				a0 = RangeHelper.date(Bound.LOWHIGH, lower, upper);
-			}
 		
-		Integer taxonId = null;
-		try {
-			taxonId = Integer.parseInt(matcher.group(2));
-		} catch (NumberFormatException e) {
-			if (taxonId == null) {
-				try {
-					taxonId = WormsAPI.nameToRecordID(matcher.group(2));
-				} catch (IOException e1) {
-					// TODO Auto-generated catch block
-					e.printStackTrace();
-				} catch (ParseException e1) {
-					// TODO Auto-generated catch block
-					e.printStackTrace();
-				}
-			}
+		if ((yearLo != null) && (yearHi != null)) {
+			Date lower = new Date(yearLo,01,01);
+			Date upper = new Date(yearHi+1,01,01);
+			a0 = RangeHelper.date(Bound.LOWHIGH, lower, upper);
 		}
 		
 		GeneralRange<Record> a2 = r -> 0;
@@ -86,9 +39,9 @@ public class BasicSearch {
 		
 		GeneralRange<Record> a1;
 		
-		Stopwatch sw = new Stopwatch();
 		Iterable<Integer> searches = BioTree.getNonEmptyChildren(taxonId);
 		
+		Stopwatch sw = new Stopwatch();
 		ArrayList<Record> results = new ArrayList<Record>();
 		for (Integer txId: searches) {
 			a1 = RangeHelper.taxonID(Bound.EQUALS, txId);
@@ -98,53 +51,8 @@ public class BasicSearch {
 			
 			results.addAll((Collection<? extends Record>) DataStore.records.rangeSearch(axes));
 		}
+		double time = sw.elapsedTime();
 		
-		double elapsed = sw.elapsedTime();
-		
-		System.out.println("Found " + ((ArrayList<Record>) results).size() + " records in " + elapsed + " seconds.");
-		
-		while(true) {
-			System.out.println("Available commands: list, histogram, sum, exit");
-			System.out.print("> ");
-			
-			Scanner s = new Scanner(System.in);
-			String command = s.nextLine();
-			
-			if (command.equals("list"))
-				printRecords(results);
-			else if (command.equals("histogram")) {
-				Histogram.printHistogram(Histogram.histogram(results));
-			} else if (command.equals("exit"))
-				return;
-			else if (command.equals("sum")) {
-				int sum = Histogram.sum(results);
-				System.out.println(sum);
-			}
-		}
-	}
-	
-	private static void printRecords(Iterable<Record> results) {
-		String format = "|%1$-45s|%2$-15s|%3$-15s|%4$-15s|%5$-15s|%6$-15s\n";
-		System.out.format(format, "Scientific Name", "IndividualCount", "Latitude", "Longitude","Year","Month","Day");
-		for (Record r: results) {
-			System.out.println(r);
-		}
-	}
-	
-	private static void printTree(Matcher matcher) {
-		Integer taxonId;
-		String name;
-		if (matcher.group(2) == null)
-			BioTree.printTree();
-		else {
-			name = matcher.group(2);
-			try {
-				taxonId = Integer.parseInt(name);
-				BioTree.printTree(taxonId);
-			} catch (Exception e) {
-				BioTree.printTree(name);
-			}
-		}
-		System.out.println();
+		return new BasicSearchResult(results, time);
 	}
 }
diff --git a/src/search/BasicSearchResult.java b/src/search/BasicSearchResult.java
new file mode 100644
index 0000000000000000000000000000000000000000..c32548625c5495301b84a63c670785c47a91ca17
--- /dev/null
+++ b/src/search/BasicSearchResult.java
@@ -0,0 +1,44 @@
+package search;
+
+import java.util.ArrayList;
+
+import data.Record;
+
+public class BasicSearchResult {
+	private ArrayList<Record> results;
+	private final double time;
+	private BST<Integer, Integer> histogram;
+	private Integer sum;
+	
+	public BasicSearchResult(ArrayList<Record> results, double time) {
+		this.results = results;
+		this.time = time;
+	}
+
+	public Iterable<Record> results() {
+		return (Iterable<Record>) results;
+	}
+	
+	public int n() {
+		return results.size();
+	}
+	
+	public double time() {
+		return time;
+	}
+	
+	public BST<Integer, Integer> histogram() {
+		if (this.histogram == null)
+			this.histogram = Histogram.histogram(results());
+		return histogram;
+	}
+	
+	public int sum() {
+		if (sum == null) {
+			sum = 0;
+			for (Record r: results())
+				sum += r.getCount();
+		}
+		return this.sum;
+	}
+}
diff --git a/src/search/Histogram.java b/src/search/Histogram.java
index 3e8ef105d2187c466f6dc3cf167c22ce6f742a71..f514a9866df93ea9c28b65cc47186fa899121faa 100644
--- a/src/search/Histogram.java
+++ b/src/search/Histogram.java
@@ -27,35 +27,7 @@ public class Histogram {
 				tree.put(year, rec.getCount());
 		}
 		return tree;
-	}
-
-	/**
-	 * Prints a histogram based on a BST of records
-	 * 
-	 * @param record -An BST of records
-	 */
-	public static void printHistogram(BST<Integer,Integer> record) {
-		int max = 0;
-		int scale = 100;
-		Iterable<Integer> results = record.keys();
-		for (Integer year: results) {
-			if (max < record.get(year)) max =record.get(year);
-
-		}
-		System.out.println("     |" + (new String(new char[scale]).replace('\0', '-')) + "|");
-		String format = "%1$-5d|%2$-" + (scale + 1) + "s";
-		for (Integer year: results) {
-			String s = "=";
-			int loopc = (int) ((float)(record.get(year)/ (float) max) * scale);
-			for (int j=0; j< loopc; j++) {
-				s+="=";
-			}
-			System.out.format(format, year, s);
-			System.out.println("| " + record.get(year));
-		}
-		System.out.format("Scale: one = is %d individuals.\n", max / scale);
-	}
-		
+	}		
 	
 	public static int sum(Iterable<Record> records) {
 		int sum = 0;