docs: function bestRank(item, term, startingFrom){
  
      // If we've reached the end of our search term, add some extra points for being short
      if(term.length === 0) return startingFrom * 100 / item.length;
  
      // If we've reached the end of the item but not the term, then fail.
      if(item.length === 0) return -1;
  
      // Quick sanity check to make sure the remaining item has all the characters we need in order
      if(!item.slice(startingFrom).match(
        new RegExp( ('^.*' + escapeRegex(term.split('').join('~~K~~')) + '.*$').split('~~K~~').join('.*'), 'i' )
      )){
        return -1;
      }
  
      // Grab the first character that we're going to look at
      var firstSearchChar = term.charAt(0);
  
      // These variables store our best guess so far, and the character
      // indices to which it applies
      var bestRankSoFar = -1;
      var highlights;
  
      // Now loop over the item, and test all instances of `firstSearchChar` (case-insensitive)
      for(var i = startingFrom; i < item.length; i += 1){
        if(item.charAt(i).toLowerCase() !== firstSearchChar.toLowerCase()) continue;
  
        // Find out what the rest of the string scores against the rest of the term
        var subsequentRank = bestRank(item.substr(i), term.slice(1), 1);
        if(subsequentRank == -1) continue;
  
        // Inverse linear score for the character. Earlier in string = much better
        var characterScore = 400 / Math.max(1, i);
  
        // If, starting at this character, we have the whole of the search term in order, that's really
        // good. And if the term is really long, make it cubically good (quadratic scores added up)
        if(item.substr(i).toLowerCase().indexOf(term.toLowerCase()) === 0) characterScore += 3 * term.length * term.length;
  
        // Add on score for how much this character stands out
        characterScore += compareCharacters(
          item.charAt(i),
          i === 0 ? '/' : item.charAt(i - 1),
          i === item.length - 1 ? '/' : item.charAt(i + 1)
        );
  
        // Add on score from the rest of the string
        characterScore += subsequentRank;
  
        // If we've managed to better what we have so far, store it away
        if(characterScore > bestRankSoFar){
          bestRankSoFar = characterScore;
  
          // Save highlighted characters as well
          highlights = [i];
          var subsequentHighlights = subsequentRank.highlights || [];
          for(var j = 0; j < subsequentHighlights.length; j += 1){
            highlights.push(subsequentHighlights[j] + i);
          }
        }
      }
  
      // Return an object with valueOf so it can be directly compared using < and >
      // but also stores the highlight indices
      return {
        __score: bestRankSoFar,
        valueOf: function(){ return this.__score; },
        highlights: highlights
      };
    }