anchor.diff:   *
    * Examples:
    *
  - * <pre>
  - *   element
  - *   .class
  - *   [attribute]
  - *   [attribute=value]
  - *   element[attribute1][attribute2=value]
  - *   :contains(/abc/)
  - * </pre>
  - *
  - *
  + *  * element
  + *  * .class
  + *  * [attribute]
  + *  * [attribute=value]
  + *  * element[attribute1][attribute2=value]
  + *  * :contains(/abc/)
    */
  +class DirectiveSelector {
  +  ElementBinderFactory _binderFactory;
  +  DirectiveMap _directives;
  +  var elementSelector;
  +  var attrSelector;
  +  var textSelector;
  +
  +  DirectiveSelector(this._directives, this._binderFactory) {
  +    elementSelector = new _ElementSelector('');
  +    attrSelector = <_ContainsSelector>[];
  +    textSelector = <_ContainsSelector>[];
  +    _directives.forEach((Directive annotation, Type type) {
  +      var match;
  +      var selector = annotation.selector;
  +      List<_SelectorPart> selectorParts;
  +      if (selector == null) {
  +        throw new ArgumentError('Missing selector annotation for $type');
  +      }
  +
  +      if ((match = _CONTAINS_REGEXP.firstMatch(selector)) != null) {
  +        textSelector.add(new _ContainsSelector(annotation, match.group(1)));
  +      } else if ((match = _ATTR_CONTAINS_REGEXP.firstMatch(selector)) != null) {
  +        attrSelector.add(new _ContainsSelector(annotation, match[1]));
  +      } else if ((selectorParts = _splitCss(selector, type)) != null){
  +        elementSelector.addDirective(selectorParts,
  +        new _Directive(type, annotation));
  +      } else {
  +        throw new ArgumentError('Unsupported Selector: $selector');
  +      }
  +    });
  +  }
  +
  +  ElementBinder matchElement(dom.Node node) {
  +    assert(node is dom.Element);
  +
  +    ElementBinderBuilder builder = _binderFactory.builder();
  +    List<_ElementSelector> partialSelection;
  +    var classes = <String, bool>{};
  +    Map<String, String> attrs = {};
  +
  +    dom.Element element = node;
  +    String nodeName = element.tagName.toLowerCase();
  +
  +    // Set default attribute
  +    if (nodeName == 'input' && !element.attributes.containsKey('type')) {
  +      element.attributes['type'] = 'text';
  +    }
  +
  +    // Select node
  +    partialSelection = elementSelector.selectNode(builder,
  +    partialSelection, element, nodeName);
  +
  +    // Select .name
  +    if ((element.classes) != null) {
  +      for (var name in element.classes) {
  +        classes[name] = true;
  +        partialSelection = elementSelector.selectClass(builder,
  +        partialSelection, element, name);
  +      }
  +    }
  +
  +    // Select [attributes]
  +    element.attributes.forEach((attrName, value) {
  +
  +      if (attrName.startsWith("on-")) {
  +        builder.onEvents[attrName] = value;
  +      } else if (attrName.startsWith("bind-")) {
  +        builder.bindAttrs[attrName] = value;
  +      }
  +
  +      attrs[attrName] = value;
  +      for (var k = 0; k < attrSelector.length; k++) {
  +        _ContainsSelector selectorRegExp = attrSelector[k];
  +        if (selectorRegExp.regexp.hasMatch(value)) {
  +          // this directive is matched on any attribute name, and so
  +          // we need to pass the name to the directive by prefixing it to
  +          // the value. Yes it is a bit of a hack.
  +          _directives[selectorRegExp.annotation].forEach((type) {
  +            builder.addDirective(new DirectiveRef(
  +                node, type, selectorRegExp.annotation, '$attrName=$value'));
  +          });
  +        }
  +      }
  +
  +      partialSelection = elementSelector.selectAttr(builder,
  +          partialSelection, node, attrName, value);
  +    });
  +
  +    while (partialSelection != null) {
  +      List<_ElementSelector> elementSelectors = partialSelection;
  +      partialSelection = null;
  +      elementSelectors.forEach((_ElementSelector elementSelector) {
  +        classes.forEach((className, _) {
  +          partialSelection = elementSelector.selectClass(builder,
  +          partialSelection, node, className);
  +        });
  +        attrs.forEach((attrName, value) {
  +          partialSelection = elementSelector.selectAttr(builder,
  +          partialSelection, node, attrName, value);
  +        });
  +      });
  +    }
  +    return builder.binder;
  +  }
  +
  +  ElementBinder matchText(dom.Node node) {
  +    ElementBinderBuilder builder = _binderFactory.builder();
  +
  +    var value = node.nodeValue;
  +    for (var k = 0; k < textSelector.length; k++) {
  +      var selectorRegExp = textSelector[k];
  +      if (selectorRegExp.regexp.hasMatch(value)) {
  +        _directives[selectorRegExp.annotation].forEach((type) {
  +          builder.addDirective(new DirectiveRef(node, type,
  +              selectorRegExp.annotation, value));
  +        });
  +      }
  +    }
  +    return builder.binder;
  +  }
  +
  +  ElementBinder matchComment(dom.Node node) =>
  +      _binderFactory.builder().binder;
  +}
  +
  +/**
  + * Factory for creating a [DirectiveSelector].
  + */
  +@Injectable()
  +class DirectiveSelectorFactory {
  +  ElementBinderFactory _binderFactory;
  +
  +  DirectiveSelectorFactory(this._binderFactory);
  +
  +  DirectiveSelector selector(DirectiveMap directives) =>
  +      new DirectiveSelector(directives, _binderFactory);
  +}
  +
   class _Directive {
     final Type type;
     final Directive annotation;
  
positive.code:   }
    return parts;
  }
  
  
  class DirectiveSelector {
    ElementBinderFactory _binderFactory;
    DirectiveMap _directives;
    var elementSelector;
    var attrSelector;
    var textSelector;
  
    DirectiveSelector(this._directives, this._binderFactory) {
      elementSelector = new _ElementSelector('');
      attrSelector = <_ContainsSelector>[];
      textSelector = <_ContainsSelector>[];
      _directives.forEach((Directive annotation, Type type) {
        var match;
        var selector = annotation.selector;
        List<_SelectorPart> selectorParts;
        if (selector == null) {
          throw new ArgumentError('Missing selector annotation for $type');
        }
  
        if ((match = _CONTAINS_REGEXP.firstMatch(selector)) != null) {
          textSelector.add(new _ContainsSelector(annotation, match.group(1)));
        } else if ((match = _ATTR_CONTAINS_REGEXP.firstMatch(selector)) != null) {
          attrSelector.add(new _ContainsSelector(annotation, match[1]));
        } else if ((selectorParts = _splitCss(selector, type)) != null){
          elementSelector.addDirective(selectorParts,
          new _Directive(type, annotation));
        } else {
          throw new ArgumentError('Unsupported Selector: $selector');
        }
      });
    }
  
    ElementBinder matchElement(dom.Node node) {
      assert(node is dom.Element);
  
      ElementBinderBuilder builder = _binderFactory.builder();
      List<_ElementSelector> partialSelection;
      var classes = <String, bool>{};
      Map<String, String> attrs = {};
  
      dom.Element element = node;
      String nodeName = element.tagName.toLowerCase();
  
      // Set default attribute
      if (nodeName == 'input' && !element.attributes.containsKey('type')) {
        element.attributes['type'] = 'text';
      }
  
      // Select node
      partialSelection = elementSelector.selectNode(builder,
      partialSelection, element, nodeName);
  
      // Select .name
      if ((element.classes) != null) {
        for (var name in element.classes) {
          classes[name] = true;
          partialSelection = elementSelector.selectClass(builder,
          partialSelection, element, name);
        }
      }
  
      // Select [attributes]
      element.attributes.forEach((attrName, value) {
  
        if (attrName.startsWith("on-")) {
          builder.onEvents[attrName] = value;
        }
  
        if (attrName.startsWith("bind-")) {
          builder.bindAttrs[attrName] = value;
        }
  
        attrs[attrName] = value;
        for (var k = 0; k < attrSelector.length; k++) {
          _ContainsSelector selectorRegExp = attrSelector[k];
          if (selectorRegExp.regexp.hasMatch(value)) {
            // this directive is matched on any attribute name, and so
            // we need to pass the name to the directive by prefixing it to
            // the value. Yes it is a bit of a hack.
            _directives[selectorRegExp.annotation].forEach((type) {
              builder.addDirective(new DirectiveRef(
                  node, type, selectorRegExp.annotation, '$attrName=$value'));
            });
          }
        }
  
        partialSelection = elementSelector.selectAttr(builder,
        partialSelection, node, attrName, value);
      });
  
      while (partialSelection != null) {
        List<_ElementSelector> elementSelectors = partialSelection;
        partialSelection = null;
        elementSelectors.forEach((_ElementSelector elementSelector) {
          classes.forEach((className, _) {
            partialSelection = elementSelector.selectClass(builder,
            partialSelection, node, className);
          });
          attrs.forEach((attrName, value) {
            partialSelection = elementSelector.selectAttr(builder,
            partialSelection, node, attrName, value);
          });
        });
      }
      return builder.binder;
    }
  
    ElementBinder matchText(dom.Node node) {
      ElementBinderBuilder builder = _binderFactory.builder();
  
      var value = node.nodeValue;
      for (var k = 0; k < textSelector.length; k++) {
        var selectorRegExp = textSelector[k];
        if (selectorRegExp.regexp.hasMatch(value)) {
          _directives[selectorRegExp.annotation].forEach((type) {
            builder.addDirective(new DirectiveRef(node, type,
            selectorRegExp.annotation, value));
          });
        }
      }
      return builder.binder;
    }
  
    ElementBinder matchComment(dom.Node node) {
      return _binderFactory.builder().binder;
    }
  }
  /**
   * Factory for creating a [DirectiveSelector].
   */
  @Injectable()
  class DirectiveSelectorFactory {
    ElementBinderFactory _binderFactory;
  
    DirectiveSelectorFactory(this._binderFactory);
  
    DirectiveSelector selector(DirectiveMap directives) {
      return new DirectiveSelector(directives, _binderFactory);
    }
  }
  
negative.code: 
    toString() => annotation.selector;
  }
  
  class _ContainsSelector {
    final Directive annotation;
  