Displaying currently-playing iTunes track in the Mac menu bar

In an attempt to teach myself Objective C, and because I couldn’t find anything that did what I wanted, I wrote a little utility to display the currently-playing iTunes track in the Mac taskbar. Originally I had it display the full track name right in the taskbar but it was too much text for such a small space (especially on a 1440×900 screen), so now you click a little musical note and it shows you the info in a menu.

Here’s a screenshot:

The code is all in github. If you’re looking for a similar utility, and are brave enough to try my first-ever Obj-C app, you can download it here. But the freshest version will probably be in the github project.

As an aside, I was surprised at how easy it was to cobble this together having never written ObjC before. I found some good examples that I mostly ripped off, but it was still remarkably easy to have the app listen to iTunes for track changes, etc.

Benchmarking DNS servers with Java

I’m currently in the process of moving our DNS over to another provider and I was curious as to whether the old or new provider offers faster lookups. dig shows query times, but I didn’t want to just run that over and over. I decided to write something to do this, in Java since I like Java. I found this post, which has the meat of the work done already. I also read some of Sun’s JNDI/DNS lookup info, which was pretty dense. All I want to do is specify the name server’s IP and do the lookup. I don’t even really care about the result, just how long the query takes.

The thing I wrote only looks up A records, but can easily be modified to do CNAMEs or whatever. Here’s how you call it:

$ java -jar DNSTester.jar 4.2.2.2 www.google.com 25
Resolved www.google.com to 74.125.235.19 against NS 4.2.2.2
Performed 25 lookups in 233.29 milliseconds.  Average 9.3316ms per lookup.

$ java -jar DNSTester.jar 8.8.4.4 www.google.com 25
Resolved www.google.com to 74.125.226.146 against NS 8.8.4.4
Performed 25 lookups in 450.034 milliseconds.  Average 18.00136ms per lookup.

Code is in github here. Jar is available here.

Teaching myself node.js: Part 3

I’ve been playing around with node, JavaScript & MongoDB a bit with this project and one of the things I ran into was MongoDB’s lack of a sequential ID. MongoDB defaults to ObjectIDs for primary keys in collections, and they have good reasons for doing so, but in writing this app, I’d rather have URLs look like “/question/423” than “/question/3001024e521e9c6500000000”.

Fortunately, there’s a relatively convenient workaround for this problem, detailed here. Essentially, create a collection in which each document is a counter. The ID for the document is its “name” and the property “next” contains the next value. This is similar to creating and using a sequence in PostgreSQL, though hopefully in the future they’ll provide an easier way to do this – perhaps a built-in sequence object.

First, in the mongo shell, I created the counter(name) function as specified in the Mongo wiki:

> counter
function counter(name) {
    var ret = db.counters.findAndModify({query:{_id:name}, update:{$inc:{next:1}}, 'new':true, upsert:true});
    return ret.next;
}

Then I created the counter document for the “questions” collection (so questions can have numeric IDs):

db.counters.insert({_id:"questions", next: 1});

This is optional – the counter() function will create the document in the counters collection if needed, with an initial value of 1.

That’s it. Each call to counter() will now return an incrementing number:

> db.counters.find();
{ "_id" : "questions", "next" : 3 }
> counter("joe");
1
> db.counters.find();
{ "_id" : "questions", "next" : 3 }
{ "_id" : "joe", "next" : 1 }
> counter("joe");
2
> counter("joe");
3

Cool. So how do we save the counter() function in the DB so we can use it in queries without having to define it every time? Fortunately Mongo makes saving functions on the server easy:

> db.system.js.save( { _id : "counter" , value : counter });
> db.system.js.find();
{ "_id" : "counter", "value" : function cf__2__f_counter(name) {
    var ret = db.counters.findAndModify({query:{_id:name}, update:{$inc:{next:1}}, 'new':true, upsert:true});
    return ret.next;
} }

Calling the stored procedure directly in the shell is sort of strange, but it works:

> db.eval("return counter('question')");
3
> db.eval("return counter('question')");
4
> bye
[Wed Jun 22 13:14:10 evan@EvanMBP 3 ~]$ ~/Downloads/mongodb-osx-x86_64-1.8.1/bin/mongo questionsMongoDB shell version: 1.8.1
connecting to: questions
> db.eval("return counter('question')");
5

Unfortunately, I was unable to figure out how to call the stored function from within the mongoskin driver, and ended up writing analogous code, calling findAndModify() within the app code. I finally got it:

        db.collection('counters').findAndModify(
                {_id:'questions'},
                [],
                {$inc : {next: 1}},
                true,
                true,
                function(err, counter) {
                        if (err) { throw new Error(err); }
                        var ins = { date: new Date(),
                                author: req.body.author, body: req.body.body,
                                tags: tags, tag_count: tagCount,
                                answers: [], votes: 0,
                                _id: counter.next
                        };
                        db.collection('questions').insert(ins, {});
                        res.end('Added new question: '+req.body.body);
                }
        );

Question detail
Question detail

I tried throwing some code in there to query by either ObjectId() or integer but it didn’t really work (Edit: I tried this again on Linux and it worked fine), so I just deleted all the documents with ObjectIds and everything seems to work fine now. I think the next step is going to have to be some sort of authentication/session stuff, because typing your name in every time kind of sucks (and makes it hard to do things like list questions by user).

Full code for this revision is here.

JavaScript regex for stripping leading & trailing whitespaces

I’m sure there are a bunch of libraries that do this, but sometimes wrestling with regexes is fun.

> var str = "           This string has some mighty fine whitespace.       ";
> str
'           This string has some mighty fine whitespace.       '
> str.replace(/^(\s*)((\S+\s*?)*)(\s*)$/,"$2");
'This string has some mighty fine whitespace.'

Teaching myself node.js: Part 1

I’ve been meaning for a while to learn node.js. I read a couple of books and plenty of blog posts but in the end I find, as usual, I can only learn by doing. I have most of the fundamentals to get started, I just need to have a project. The typical tutorials I’ve found focus on creating a blog; I’m thinking of something more along the lines of a Quora question/answer site. I’ll be trying to write this as I go, which will hopefully prod me into actually doing it this time. (I have a tendency to bounce around different tenses and I expect this will be worse than usual – stuff will likely be written in past/present/future at various points).
Continue reading “Teaching myself node.js: Part 1”

Java Code: searching a Binary Search Tree for the largest value strictly less than X

Someone recently asked me how to do this, so I figured I’d write it up in Java since it’s still the language I’m most comfortable with:

Node.java

package com.evanhoffman.bst;

import org.apache.log4j.Logger;

/**
 * Node in a binary search tree in which values = are in the right branch.
 * @author evan
 *
 * @param 
 */
public class Node<v extends Comparable> {
	private static Logger logger = Logger.getLogger(Node.class);

	private Node left = null;
	private Node right = null;
	private V value = null;

	public Node(V t) {
		this.value = t;
	}

	public V getValue() {
		return value;
	}
	public boolean isLeaf() {
		return (left == null && right == null);
	}


	public void addNode(Node node) {
		if (node.getValue().compareTo(value) < 0) {
			if (left == null) {
				left = node;
				logger.debug("Assigning "+node.getValue()+" "+
						"to left child of node "+value);
			} else {
				left.addNode(node);
			}
		} else {
			if (right == null) {
				right = node;
				logger.debug("Assigning "+node.getValue()+" "+
						"to right child of node "+value);
			} else {
				right.addNode(node);
			}
		}

	}

	public V findMaxStrictlyLessThan(V t) {
		return findMaxStrictlyLessThan(t, null);
	}

	/**
	 * Returns the greatest value in the tree strictly
	 * less than (as defined by {@link Comparable#compareTo(Object)} the given value.
	 * @param t
	 * @return
	 */
	private V findMaxStrictlyLessThan(V t, V currentMax) {
		if (t.compareTo(value) = current node "+value+", checking right (if exists)");
			currentMax = value;
			return right == null ? currentMax : right.findMaxStrictlyLessThan(t, currentMax);
		}

	}

	@Override
	public String toString() {
		if (isLeaf()) {
			return "{value="+value+"}";
		} else {
			return "{value="+value+", left="+left+", right="+right+"}";
		}
	}

}

IntBstBuilder.java:

package com.evanhoffman.bst;

import java.util.Random;

import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Logger;

public class IntBstBuilder {

	private static int min = 0;
	private static int max = 200;
	private static int size = 10;

	private static Random rng = new Random();
	private static Logger logger = Logger.getLogger(IntBstBuilder.class);

	public static void main(String args[]) {
		BasicConfigurator.configure();

		Node root = new Node((max - min)/2);
		for (int i = 0; i < size; i++) {
			int num = (Math.abs(rng.nextInt()) % (max - min)) + min;
			Node newNode = new Node(num);
			root.addNode(newNode);
		}

		logger.info(root);

		logger.info(root.findMaxStrictlyLessThan(50));
		logger.info(root.findMaxStrictlyLessThan(90));
		logger.info(root.findMaxStrictlyLessThan(130));
		logger.info(root.findMaxStrictlyLessThan(220));
		logger.info(root.findMaxStrictlyLessThan(-100));

	}
}

Output:

0 [main] DEBUG com.evanhoffman.bst.Node  - Assigning 192 to right child of node 100
1 [main] DEBUG com.evanhoffman.bst.Node  - Assigning 140 to left child of node 192
1 [main] DEBUG com.evanhoffman.bst.Node  - Assigning 162 to right child of node 140
1 [main] DEBUG com.evanhoffman.bst.Node  - Assigning 54 to left child of node 100
1 [main] DEBUG com.evanhoffman.bst.Node  - Assigning 155 to left child of node 162
1 [main] DEBUG com.evanhoffman.bst.Node  - Assigning 118 to left child of node 140
2 [main] DEBUG com.evanhoffman.bst.Node  - Assigning 52 to left child of node 54
2 [main] DEBUG com.evanhoffman.bst.Node  - Assigning 184 to right child of node 162
2 [main] DEBUG com.evanhoffman.bst.Node  - Assigning 41 to left child of node 52
2 [main] DEBUG com.evanhoffman.bst.Node  - Assigning 161 to right child of node 155
2 [main] INFO com.evanhoffman.bst.IntBstBuilder  - {value=100, left={value=54, left={value=52, left={value=41}, right=null}, right=null}, right={value=192, left={value=140, left={value=118}, right={value=162, left={value=155, left=null, right={value=161}}, right={value=184}}}, right=null}}
2 [main] DEBUG com.evanhoffman.bst.Node  - 50 is less than current node 100, checking left (if it exists)
2 [main] DEBUG com.evanhoffman.bst.Node  - 50 is less than current node 54, checking left (if it exists)
2 [main] DEBUG com.evanhoffman.bst.Node  - 50 is less than current node 52, checking left (if it exists)
2 [main] DEBUG com.evanhoffman.bst.Node  - 50 is >= current node 41, checking right (if exists)
2 [main] INFO com.evanhoffman.bst.IntBstBuilder  - 41
2 [main] DEBUG com.evanhoffman.bst.Node  - 90 is less than current node 100, checking left (if it exists)
2 [main] DEBUG com.evanhoffman.bst.Node  - 90 is >= current node 54, checking right (if exists)
2 [main] INFO com.evanhoffman.bst.IntBstBuilder  - 54
2 [main] DEBUG com.evanhoffman.bst.Node  - 130 is >= current node 100, checking right (if exists)
2 [main] DEBUG com.evanhoffman.bst.Node  - 130 is less than current node 192, checking left (if it exists)
3 [main] DEBUG com.evanhoffman.bst.Node  - 130 is less than current node 140, checking left (if it exists)
3 [main] DEBUG com.evanhoffman.bst.Node  - 130 is >= current node 118, checking right (if exists)
3 [main] INFO com.evanhoffman.bst.IntBstBuilder  - 118
3 [main] DEBUG com.evanhoffman.bst.Node  - 220 is >= current node 100, checking right (if exists)
3 [main] DEBUG com.evanhoffman.bst.Node  - 220 is >= current node 192, checking right (if exists)
3 [main] INFO com.evanhoffman.bst.IntBstBuilder  - 192
3 [main] DEBUG com.evanhoffman.bst.Node  - -100 is less than current node 100, checking left (if it exists)
3 [main] DEBUG com.evanhoffman.bst.Node  - -100 is less than current node 54, checking left (if it exists)
3 [main] DEBUG com.evanhoffman.bst.Node  - -100 is less than current node 52, checking left (if it exists)
3 [main] DEBUG com.evanhoffman.bst.Node  - -100 is less than current node 41, checking left (if it exists)
3 [main] INFO com.evanhoffman.bst.IntBstBuilder  -

StringBstBuilder.java:

package com.evanhoffman.bst;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Random;

import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Logger;

public class StringBstBuilder {

	private static int size = 100;

	private static Random rng = new Random();
	private static Logger logger = Logger.getLogger(StringBstBuilder.class);

	private ArrayList words = new ArrayList();

	public ArrayList getWords() {
		return words;
	}



	StringBstBuilder(File f, int maxLines) {

		logger.debug("Creating "+this.getClass()+" with word list file: "+f+" up to "+maxLines+" lines");

		int i = 0;
		try {
			BufferedReader br = new BufferedReader(new FileReader(f));
			String line = null;
			while ((i < maxLines) && (line = br.readLine()) != null) {
				words.add(line);
				i++;
			}
			logger.debug("Added "+words.size()+" words to list");

		} catch (FileNotFoundException fe) {
			logger.error("File not found: "+f,fe);
			throw new RuntimeException(fe);
		} catch (IOException ie) {
			logger.error("IO Exception: "+ie.getMessage(),ie);
			throw new RuntimeException(ie);
		}
	}



	public static void main(String args[]) {
		BasicConfigurator.configure();

		StringBstBuilder sbt = new StringBstBuilder(new File(args[0]), Integer.parseInt(args[1]));

		ArrayList words = sbt.getWords();

		int wordListSize = words.size();

		// Random number between 1/4 and 3/4 through the list.
		int seedWordIndex = (Math.abs(rng.nextInt()) % (wordListSize/2)) + (wordListSize / 4);

		Node root = new Node(words.get(seedWordIndex));
		logger.debug("Root word: "+root.getValue());

		for (int i = 0; i < size; i++) {
			int index = (Math.abs(rng.nextInt()) % (words.size()));
			Node newNode = new Node(words.get(index));
			root.addNode(newNode);
		}

		logger.info("Entire tree: "+root);

		String[] searches = {"andy", "joker", "kale", "moonshine", "zebra"};
		for (String str : searches) {
			logger.info("Search for "+str+": ");
			String s = root.findMaxStrictlyLessThan(str);
			logger.info("max word: "+s);
		}

	}
}

Output:

0 [main] DEBUG com.evanhoffman.bst.StringBstBuilder  - Creating class com.evanhoffman.bst.StringBstBuilder with word list file: /Users/evan/Downloads/scowl-7.1/final/english-words.20 up to 10000 lines
47 [main] DEBUG com.evanhoffman.bst.StringBstBuilder  - Added 7951 words to list
48 [main] DEBUG com.evanhoffman.bst.StringBstBuilder  - Root word: patient's
48 [main] DEBUG com.evanhoffman.bst.Node  - Assigning scroll's to right child of node patient's
48 [main] DEBUG com.evanhoffman.bst.Node  - Assigning dual to left child of node patient's
48 [main] DEBUG com.evanhoffman.bst.Node  - Assigning bat to left child of node dual
48 [main] DEBUG com.evanhoffman.bst.Node  - Assigning moderate to right child of node dual
48 [main] DEBUG com.evanhoffman.bst.Node  - Assigning abort to left child of node bat
48 [main] DEBUG com.evanhoffman.bst.Node  - Assigning migrates to left child of node moderate
48 [main] DEBUG com.evanhoffman.bst.Node  - Assigning terrifying to right child of node scroll's
48 [main] DEBUG com.evanhoffman.bst.Node  - Assigning equilibrium to left child of node migrates
48 [main] DEBUG com.evanhoffman.bst.Node  - Assigning polynomial to left child of node scroll's
48 [main] DEBUG com.evanhoffman.bst.Node  - Assigning tomatoes to right child of node terrifying
48 [main] DEBUG com.evanhoffman.bst.Node  - Assigning unusable to right child of node tomatoes
48 [main] DEBUG com.evanhoffman.bst.Node  - Assigning nailing to right child of node moderate
48 [main] DEBUG com.evanhoffman.bst.Node  - Assigning supporter to left child of node terrifying
49 [main] DEBUG com.evanhoffman.bst.Node  - Assigning prosecution to right child of node polynomial
49 [main] DEBUG com.evanhoffman.bst.Node  - Assigning management to right child of node equilibrium
49 [main] DEBUG com.evanhoffman.bst.Node  - Assigning disabled to right child of node bat
49 [main] DEBUG com.evanhoffman.bst.Node  - Assigning planted to left child of node polynomial
49 [main] DEBUG com.evanhoffman.bst.Node  - Assigning midday to right child of node management
49 [main] DEBUG com.evanhoffman.bst.Node  - Assigning cloth to left child of node disabled
49 [main] DEBUG com.evanhoffman.bst.Node  - Assigning hip to left child of node management
49 [main] DEBUG com.evanhoffman.bst.Node  - Assigning tune's to left child of node unusable
49 [main] DEBUG com.evanhoffman.bst.Node  - Assigning mortal to left child of node nailing
49 [main] DEBUG com.evanhoffman.bst.Node  - Assigning dangers to right child of node cloth
49 [main] DEBUG com.evanhoffman.bst.Node  - Assigning concentrate to left child of node dangers
49 [main] DEBUG com.evanhoffman.bst.Node  - Assigning intimate to right child of node hip
49 [main] DEBUG com.evanhoffman.bst.Node  - Assigning stairs to left child of node supporter
49 [main] DEBUG com.evanhoffman.bst.Node  - Assigning attorney to right child of node abort
49 [main] DEBUG com.evanhoffman.bst.Node  - Assigning globally to left child of node hip
49 [main] DEBUG com.evanhoffman.bst.Node  - Assigning vertical to right child of node unusable
49 [main] DEBUG com.evanhoffman.bst.Node  - Assigning close's to left child of node cloth
49 [main] DEBUG com.evanhoffman.bst.Node  - Assigning debatable to right child of node dangers
50 [main] DEBUG com.evanhoffman.bst.Node  - Assigning guarding to right child of node globally
50 [main] DEBUG com.evanhoffman.bst.Node  - Assigning aided to left child of node attorney
50 [main] DEBUG com.evanhoffman.bst.Node  - Assigning contend to right child of node concentrate
50 [main] DEBUG com.evanhoffman.bst.Node  - Assigning shined to left child of node stairs
50 [main] DEBUG com.evanhoffman.bst.Node  - Assigning journals to right child of node intimate
50 [main] DEBUG com.evanhoffman.bst.Node  - Assigning warmed to right child of node vertical
50 [main] DEBUG com.evanhoffman.bst.Node  - Assigning blaming to left child of node close's
50 [main] DEBUG com.evanhoffman.bst.Node  - Assigning ingredient to left child of node intimate
50 [main] DEBUG com.evanhoffman.bst.Node  - Assigning gleaning to left child of node globally
50 [main] DEBUG com.evanhoffman.bst.Node  - Assigning boys to right child of node blaming
50 [main] DEBUG com.evanhoffman.bst.Node  - Assigning stream's to right child of node stairs
50 [main] DEBUG com.evanhoffman.bst.Node  - Assigning tragedy to left child of node tune's
50 [main] DEBUG com.evanhoffman.bst.Node  - Assigning brands to right child of node boys
50 [main] DEBUG com.evanhoffman.bst.Node  - Assigning revenge to right child of node prosecution
50 [main] DEBUG com.evanhoffman.bst.Node  - Assigning knight to right child of node journals
50 [main] DEBUG com.evanhoffman.bst.Node  - Assigning discard to right child of node disabled
50 [main] DEBUG com.evanhoffman.bst.Node  - Assigning successor to right child of node stream's
51 [main] DEBUG com.evanhoffman.bst.Node  - Assigning synonymous to right child of node supporter
51 [main] DEBUG com.evanhoffman.bst.Node  - Assigning bow to left child of node boys
51 [main] DEBUG com.evanhoffman.bst.Node  - Assigning satisfaction to right child of node revenge
51 [main] DEBUG com.evanhoffman.bst.Node  - Assigning mutters to right child of node mortal
51 [main] DEBUG com.evanhoffman.bst.Node  - Assigning tray to right child of node tragedy
51 [main] DEBUG com.evanhoffman.bst.Node  - Assigning linkage to right child of node knight
51 [main] DEBUG com.evanhoffman.bst.Node  - Assigning face's to left child of node gleaning
51 [main] DEBUG com.evanhoffman.bst.Node  - Assigning decreasing to right child of node debatable
51 [main] DEBUG com.evanhoffman.bst.Node  - Assigning spoiling to right child of node shined
51 [main] DEBUG com.evanhoffman.bst.Node  - Assigning slave's to left child of node spoiling
51 [main] DEBUG com.evanhoffman.bst.Node  - Assigning clarified to right child of node brands
51 [main] DEBUG com.evanhoffman.bst.Node  - Assigning inspection to right child of node ingredient
51 [main] DEBUG com.evanhoffman.bst.Node  - Assigning technically to right child of node synonymous
51 [main] DEBUG com.evanhoffman.bst.Node  - Assigning supervises to right child of node successor
51 [main] DEBUG com.evanhoffman.bst.Node  - Assigning disconnect to right child of node discard
51 [main] DEBUG com.evanhoffman.bst.Node  - Assigning whence to right child of node warmed
51 [main] DEBUG com.evanhoffman.bst.Node  - Assigning creator to right child of node contend
52 [main] DEBUG com.evanhoffman.bst.Node  - Assigning oppress to right child of node nailing
52 [main] DEBUG com.evanhoffman.bst.Node  - Assigning magnificent to right child of node linkage
52 [main] DEBUG com.evanhoffman.bst.Node  - Assigning launch to left child of node linkage
52 [main] DEBUG com.evanhoffman.bst.Node  - Assigning compensation to left child of node concentrate
52 [main] DEBUG com.evanhoffman.bst.Node  - Assigning cave to left child of node clarified
52 [main] DEBUG com.evanhoffman.bst.Node  - Assigning unbearable to right child of node tune's
52 [main] DEBUG com.evanhoffman.bst.Node  - Assigning verifies to left child of node vertical
52 [main] DEBUG com.evanhoffman.bst.Node  - Assigning compact to left child of node compensation
52 [main] DEBUG com.evanhoffman.bst.Node  - Assigning immense to left child of node ingredient
52 [main] DEBUG com.evanhoffman.bst.Node  - Assigning empire to left child of node equilibrium
52 [main] DEBUG com.evanhoffman.bst.Node  - Assigning foreseeable to right child of node face's
52 [main] DEBUG com.evanhoffman.bst.Node  - Assigning joking to left child of node journals
52 [main] DEBUG com.evanhoffman.bst.Node  - Assigning opts to right child of node oppress
52 [main] DEBUG com.evanhoffman.bst.Node  - Assigning convicting to left child of node creator
52 [main] DEBUG com.evanhoffman.bst.Node  - Assigning divisions to right child of node disconnect
52 [main] DEBUG com.evanhoffman.bst.Node  - Assigning fascinate to left child of node foreseeable
52 [main] DEBUG com.evanhoffman.bst.Node  - Assigning reactions to left child of node revenge
52 [main] DEBUG com.evanhoffman.bst.Node  - Assigning discriminated to left child of node divisions
53 [main] DEBUG com.evanhoffman.bst.Node  - Assigning unrealistic to right child of node unbearable
53 [main] DEBUG com.evanhoffman.bst.Node  - Assigning crowds to right child of node creator
53 [main] DEBUG com.evanhoffman.bst.Node  - Assigning marketed to left child of node midday
53 [main] DEBUG com.evanhoffman.bst.Node  - Assigning broad to left child of node cave
53 [main] DEBUG com.evanhoffman.bst.Node  - Assigning socket to right child of node slave's
53 [main] DEBUG com.evanhoffman.bst.Node  - Assigning verbal to left child of node verifies
53 [main] DEBUG com.evanhoffman.bst.Node  - Assigning register's to right child of node reactions
53 [main] DEBUG com.evanhoffman.bst.Node  - Assigning attributes to right child of node attorney
53 [main] DEBUG com.evanhoffman.bst.Node  - Assigning clarity to right child of node clarified
53 [main] DEBUG com.evanhoffman.bst.Node  - Assigning engage to right child of node empire
53 [main] DEBUG com.evanhoffman.bst.Node  - Assigning succeeded to left child of node successor
53 [main] DEBUG com.evanhoffman.bst.Node  - Assigning resembled to right child of node register's
53 [main] DEBUG com.evanhoffman.bst.Node  - Assigning kernel to left child of node knight
53 [main] DEBUG com.evanhoffman.bst.Node  - Assigning dot to right child of node divisions
53 [main] DEBUG com.evanhoffman.bst.Node  - Assigning wrecked to right child of node whence
54 [main] DEBUG com.evanhoffman.bst.Node  - Assigning gratuitously to left child of node guarding
54 [main] DEBUG com.evanhoffman.bst.Node  - Assigning syndicate to left child of node synonymous
54 [main] INFO com.evanhoffman.bst.StringBstBuilder  - Entire tree: {value=patient's, left={value=dual, left={value=bat, left={value=abort, left=null, right={value=attorney, left={value=aided}, right={value=attributes}}}, right={value=disabled, left={value=cloth, left={value=close's, left={value=blaming, left=null, right={value=boys, left={value=bow}, right={value=brands, left=null, right={value=clarified, left={value=cave, left={value=broad}, right=null}, right={value=clarity}}}}}, right=null}, right={value=dangers, left={value=concentrate, left={value=compensation, left={value=compact}, right=null}, right={value=contend, left=null, right={value=creator, left={value=convicting}, right={value=crowds}}}}, right={value=debatable, left=null, right={value=decreasing}}}}, right={value=discard, left=null, right={value=disconnect, left=null, right={value=divisions, left={value=discriminated}, right={value=dot}}}}}}, right={value=moderate, left={value=migrates, left={value=equilibrium, left={value=empire, left=null, right={value=engage}}, right={value=management, left={value=hip, left={value=globally, left={value=gleaning, left={value=face's, left=null, right={value=foreseeable, left={value=fascinate}, right=null}}, right=null}, right={value=guarding, left={value=gratuitously}, right=null}}, right={value=intimate, left={value=ingredient, left={value=immense}, right={value=inspection}}, right={value=journals, left={value=joking}, right={value=knight, left={value=kernel}, right={value=linkage, left={value=launch}, right={value=magnificent}}}}}}, right={value=midday, left={value=marketed}, right=null}}}, right=null}, right={value=nailing, left={value=mortal, left=null, right={value=mutters}}, right={value=oppress, left=null, right={value=opts}}}}}, right={value=scroll's, left={value=polynomial, left={value=planted}, right={value=prosecution, left=null, right={value=revenge, left={value=reactions, left=null, right={value=register's, left=null, right={value=resembled}}}, right={value=satisfaction}}}}, right={value=terrifying, left={value=supporter, left={value=stairs, left={value=shined, left=null, right={value=spoiling, left={value=slave's, left=null, right={value=socket}}, right=null}}, right={value=stream's, left=null, right={value=successor, left={value=succeeded}, right={value=supervises}}}}, right={value=synonymous, left={value=syndicate}, right={value=technically}}}, right={value=tomatoes, left=null, right={value=unusable, left={value=tune's, left={value=tragedy, left=null, right={value=tray}}, right={value=unbearable, left=null, right={value=unrealistic}}}, right={value=vertical, left={value=verifies, left={value=verbal}, right=null}, right={value=warmed, left=null, right={value=whence, left=null, right={value=wrecked}}}}}}}}}
55 [main] INFO com.evanhoffman.bst.StringBstBuilder  - Search for andy:
55 [main] DEBUG com.evanhoffman.bst.Node  - andy is less than current node patient's, checking left (if it exists)
55 [main] DEBUG com.evanhoffman.bst.Node  - andy is less than current node dual, checking left (if it exists)
55 [main] DEBUG com.evanhoffman.bst.Node  - andy is less than current node bat, checking left (if it exists)
55 [main] DEBUG com.evanhoffman.bst.Node  - andy is >= current node abort, checking right (if exists)
55 [main] DEBUG com.evanhoffman.bst.Node  - andy is less than current node attorney, checking left (if it exists)
55 [main] DEBUG com.evanhoffman.bst.Node  - andy is >= current node aided, checking right (if exists)
55 [main] INFO com.evanhoffman.bst.StringBstBuilder  - max word: aided
56 [main] INFO com.evanhoffman.bst.StringBstBuilder  - Search for joker:
56 [main] DEBUG com.evanhoffman.bst.Node  - joker is less than current node patient's, checking left (if it exists)
56 [main] DEBUG com.evanhoffman.bst.Node  - joker is >= current node dual, checking right (if exists)
56 [main] DEBUG com.evanhoffman.bst.Node  - joker is less than current node moderate, checking left (if it exists)
56 [main] DEBUG com.evanhoffman.bst.Node  - joker is less than current node migrates, checking left (if it exists)
56 [main] DEBUG com.evanhoffman.bst.Node  - joker is >= current node equilibrium, checking right (if exists)
56 [main] DEBUG com.evanhoffman.bst.Node  - joker is less than current node management, checking left (if it exists)
56 [main] DEBUG com.evanhoffman.bst.Node  - joker is >= current node hip, checking right (if exists)
56 [main] DEBUG com.evanhoffman.bst.Node  - joker is >= current node intimate, checking right (if exists)
56 [main] DEBUG com.evanhoffman.bst.Node  - joker is less than current node journals, checking left (if it exists)
56 [main] DEBUG com.evanhoffman.bst.Node  - joker is less than current node joking, checking left (if it exists)
56 [main] INFO com.evanhoffman.bst.StringBstBuilder  - max word: intimate
56 [main] INFO com.evanhoffman.bst.StringBstBuilder  - Search for kale:
56 [main] DEBUG com.evanhoffman.bst.Node  - kale is less than current node patient's, checking left (if it exists)
56 [main] DEBUG com.evanhoffman.bst.Node  - kale is >= current node dual, checking right (if exists)
56 [main] DEBUG com.evanhoffman.bst.Node  - kale is less than current node moderate, checking left (if it exists)
56 [main] DEBUG com.evanhoffman.bst.Node  - kale is less than current node migrates, checking left (if it exists)
56 [main] DEBUG com.evanhoffman.bst.Node  - kale is >= current node equilibrium, checking right (if exists)
57 [main] DEBUG com.evanhoffman.bst.Node  - kale is less than current node management, checking left (if it exists)
57 [main] DEBUG com.evanhoffman.bst.Node  - kale is >= current node hip, checking right (if exists)
57 [main] DEBUG com.evanhoffman.bst.Node  - kale is >= current node intimate, checking right (if exists)
57 [main] DEBUG com.evanhoffman.bst.Node  - kale is >= current node journals, checking right (if exists)
57 [main] DEBUG com.evanhoffman.bst.Node  - kale is less than current node knight, checking left (if it exists)
57 [main] DEBUG com.evanhoffman.bst.Node  - kale is less than current node kernel, checking left (if it exists)
57 [main] INFO com.evanhoffman.bst.StringBstBuilder  - max word: journals
57 [main] INFO com.evanhoffman.bst.StringBstBuilder  - Search for moonshine:
57 [main] DEBUG com.evanhoffman.bst.Node  - moonshine is less than current node patient's, checking left (if it exists)
57 [main] DEBUG com.evanhoffman.bst.Node  - moonshine is >= current node dual, checking right (if exists)
57 [main] DEBUG com.evanhoffman.bst.Node  - moonshine is >= current node moderate, checking right (if exists)
57 [main] DEBUG com.evanhoffman.bst.Node  - moonshine is less than current node nailing, checking left (if it exists)
57 [main] DEBUG com.evanhoffman.bst.Node  - moonshine is less than current node mortal, checking left (if it exists)
57 [main] INFO com.evanhoffman.bst.StringBstBuilder  - max word: moderate
57 [main] INFO com.evanhoffman.bst.StringBstBuilder  - Search for zebra:
57 [main] DEBUG com.evanhoffman.bst.Node  - zebra is >= current node patient's, checking right (if exists)
57 [main] DEBUG com.evanhoffman.bst.Node  - zebra is >= current node scroll's, checking right (if exists)
57 [main] DEBUG com.evanhoffman.bst.Node  - zebra is >= current node terrifying, checking right (if exists)
58 [main] DEBUG com.evanhoffman.bst.Node  - zebra is >= current node tomatoes, checking right (if exists)
58 [main] DEBUG com.evanhoffman.bst.Node  - zebra is >= current node unusable, checking right (if exists)
58 [main] DEBUG com.evanhoffman.bst.Node  - zebra is >= current node vertical, checking right (if exists)
58 [main] DEBUG com.evanhoffman.bst.Node  - zebra is >= current node warmed, checking right (if exists)
58 [main] DEBUG com.evanhoffman.bst.Node  - zebra is >= current node whence, checking right (if exists)
58 [main] DEBUG com.evanhoffman.bst.Node  - zebra is >= current node wrecked, checking right (if exists)
58 [main] INFO com.evanhoffman.bst.StringBstBuilder  - max word: wrecked