anchor.diff:   */
   class CharacterParser extends Parser {
   
  -  final _CharMatcher _matcher;
  +  final _CharacterPredicate _predicate;
   
     final String _message;
   
  -  CharacterParser(this._matcher, this._message);
  +  CharacterParser(this._predicate, this._message);
   
     @override
     Result parseOn(Context context) {
       var buffer = context.buffer;
       var position = context.position;
  -    if (position < buffer.length && _matcher.match(buffer.codeUnitAt(position))) {
  +    if (position < buffer.length && _predicate.test(buffer.codeUnitAt(position))) {
         return context.success(buffer[position], position + 1);
       }
       return context.failure(_message);
  
positive.code:   String toString() => '${super.toString()}[$_message]';
  
    @override
    Parser copy() => new CharacterParser(_matcher, _message);
  
    @override
    bool hasEqualProperties(CharacterParser other) {
      return super.hasEqualProperties(other)
          && _matcher == other._matcher
          && _message == other._message;
    }
  
  
negative.code:       message != null ? message : 'any of "$string" expected');
  }
  
  _CharacterPredicate _optimized(String characters) {
    var codeUnits = characters.codeUnits.toSet().toList()..sort();
    var groupedRanges = new Map();
    for (var i = 0; i < codeUnits.length; i++) {
  