anchor.diff:      removeKeys.forEach(_inverseIds.remove);
     }
   
  -  /// Search the index for [text], with a (term-match / document coverage percent)
  -  /// scoring. Longer tokens weight more in the relevance score.
  -  Map<String, double> search(String text, {double weight: 1.0}) {
  +  /// Match the text against the corpus and return the tokens that have match.
  +  TokenMatch lookupTokens(String text) {
  +    final TokenMatch tokenMatch = new TokenMatch();
       final Set<String> tokens = _tokenize(text, _minLength);
       if (tokens == null || tokens.isEmpty) {
  -      return const {};
  +      return tokenMatch;
       }
   
       // Check which tokens have documents, and assign their weight.
  -    final TokenMatch tokenMatch = new TokenMatch();
       for (String token in tokens) {
         final int foundCount = _inverseIds[token]?.length ?? 0;
         if (foundCount == 0) continue;
  
positive.code: 
      // post-process match weights
      for (String id in docScores.keys.toList()) {
        docScores[id] = weight * docScores[id] / queryWeight / _docSizes[id];
      }
      return docScores;
    }
  }
  
  
negative.code:     if (text != null && text.isNotEmpty) {
        final List<String> words = text.split(' ');
        final List<Score> wordScores = words.map((String word) {
          final name = new Score(_nameIndex.search(word));
          final descr = new Score(_descrIndex.search(word)).map((v) => v * 0.75);
          final readme = new Score(_readmeIndex.search(word)).map((v) => v * 0.5);
          return Score.max([name, descr, readme]).removeLowValues(
              fraction: 0.01, minValue: 0.001);
        }).toList();
  