         return serialized
     }
     
-    func updateDescription() {
+    private func updateDescription() {
         var arr = [final ? "1" : "0"]
         arr.appendContentsOf(edges.map({ "\($0.0)_\($0.1)" }))
         descr = arr.joinWithSeparator("_")

}

class DawgNode: CustomStringConvertible, Hashable {
    static var nextId = 0;
    
    typealias Edges = [Character: DawgNode]
    
    lazy var edges = Edges()
    var final: Bool = false
    var id: Int
    var descr: String = ""
    
    init() {
        self.id = self.dynamicType.nextId

    /// - returns: True if the word exists.
    func lookup(word: String) -> Bool {
        var node = rootNode
        for letter in word.lowercaseString.characters {
            guard let edgeNode = node.edges[letter] else { return false }
            node = edgeNode
        }
        return node.final
    }
    
    /// Calculates all possible words given a set of rack letters
    /// optionally providing fixed letters which can be used
    /// to indicate that these positions are already filled.
    /// - parameters:
    ///     - letters: Letter in rack to use.
    ///     - length: Length of word to return.
    ///     - prefix: Letters of current result already realised.
    ///     - fixedLetters: Letters that are already filled at given positions.
    ///     - root: Node in the Dawg tree we are currently using.
    /// - returns: Array of possible words.
    func anagramsOf(letters: [Character],
        length: Int,
        prefix: [Character]? = nil,
        filledLetters: [Int: Character]? = nil,
        filledCount: Int? = nil,
        root: DawgNode? = nil,
        inout results: [String])
    {
        // Realise any fields that are empty on first run.
        let _prefix = prefix ?? [Character]()
        let _prefixLength = _prefix.count
        var _filled = filledLetters ?? [Int: Character]()
        let _numFilled = filledCount ?? _filled.count
        let _source = root ?? rootNode
        
        // See if position exists in filled array.
        if let letter = _filled[_prefixLength],
            newSource = _source.edges[letter]
        {
            // Add letter to prefix
            var newPrefix = _prefix
            newPrefix.append(letter)
            _filled.removeValueForKey(_prefixLength)
            // Recurse with new prefix/letters
            anagramsOf(letters,
                length: length,
                prefix: newPrefix,
                filledLetters: _filled,
                filledCount: _numFilled,
                root: newSource,
                results: &results)
            return
        }
        
        // Check if the current prefix is actually a word.
        if _source.final &&
            _filled.count == 0 &&
            _prefixLength == length &&
            _prefixLength > _numFilled
        {
            results.append(String(_prefix))
        }
        
        // Check each edge of this node to see if any of the letters
        // exist in our rack letters (or we have a '?').
        _source.edges.forEach { (letter, node) in
            if let index = letters.indexOf(letter) ?? letters.indexOf("?") {
                // Copy letters, removing this letter
                var newLetters = letters
                newLetters.removeAtIndex(index)
                // Add letter to prefix
                var newPrefix = _prefix
                newPrefix.append(letter)
                // Recurse with new prefix/letters
                anagramsOf(newLetters,
                    length: length,
                    prefix: newPrefix,
                    filledLetters: _filled,
                    filledCount: _numFilled,
                    root: node,
                    results: &results)
            }
        }
    }
