anchor.diff:  /// implementations in several ways:
   ///
   /// 1.  This one is way way WAY simpler.
  -/// 2.  All HTML tags at the block level will be treated as blocks. If you
  -///     start a paragraph with `<em>`, it will not wrap it in a `<p>` for you.
  -///     As soon as it sees something like HTML, it stops mucking with it until
  -///     it hits the next block.
  -/// 3.  Absolutely no HTML parsing or validation is done. We're a Markdown
  +/// 2.  Essentially no HTML parsing or validation is done. We're a Markdown
   ///     parser, not an HTML parser!
  -class BlockHtmlSyntax extends BlockSyntax {
  -  RegExp get pattern => _htmlPattern;
  -
  -  bool get canEndBlock => false;
  +abstract class BlockHtmlSyntax extends BlockSyntax {
  +  bool get canEndBlock => true;
   
     const BlockHtmlSyntax();
  +}
  +
  +class BlockTagBlockHtmlSyntax extends BlockHtmlSyntax {
  +  RegExp get pattern => new RegExp(
  +      r'^ {0,3}</?(?:address|article|aside|base|basefont|blockquote|body|'
  +      r'caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|'
  +      r'figcaption|figure|footer|form|frame|frameset|h1|head|header|hr|html|'
  +      r'iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|'
  +      r'option|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|'
  +      'title|tr|track|ul)'
  +      r'(?:\s|>|/>|$)');
  +
  +  const BlockTagBlockHtmlSyntax();
   
     Node parse(BlockParser parser) {
       var childLines = <String>[];
  
positive.code:   int _pos = 0;
  
    /// The collection of built-in block parsers.
    final List<BlockSyntax> standardBlockSyntaxes = const [
      const EmptyBlockSyntax(),
      const BlockHtmlSyntax(),
      const SetextHeaderSyntax(),
      const HeaderSyntax(),
      const CodeBlockSyntax(),
  
negative.code:       parser.advance();
      }
  
      return new Text(childLines.join('\n'));
    }
  }
  
  class OtherTagBlockHtmlSyntax extends BlockTagBlockHtmlSyntax {
    bool get canEndBlock => false;
  
    // Really hacky way to detect "other" HTML. This matches:
    //
    // * any opening spaces
    // * open bracket and maybe a slash ("<" or "</")
    // * some word characters
    // * either:
    //   * a close bracket, or
    //   * whitespace followed by not-brackets follwed by a close bracket
    // * possible whitespace and the end of the line.
    RegExp get pattern => new RegExp(r'^ {0,3}</?\w+(?:>|\s+[^>]*>)\s*$');
  
    const OtherTagBlockHtmlSyntax();
  }
  
  /// A BlockHtmlSyntax that has a specific [endPattern].
  ///
  /// In practice this means that the syntax dominates; it is allowed to eat
  /// many lines, including blank lines, before matching its [endPattern].
  class LongBlockHtmlSyntax extends BlockHtmlSyntax {
    RegExp _pattern;
    RegExp _endPattern;
  
    LongBlockHtmlSyntax(pattern, endPattern) {
      _pattern = new RegExp(pattern);
      _endPattern = new RegExp(endPattern);
    }
  
    RegExp get pattern => _pattern;
  
    Node parse(BlockParser parser) {
      var childLines = <String>[];
      // Eat until we hit [endPattern].
      while (!parser.isDone) {
        childLines.add(parser.current);
        if (parser.matches(_endPattern)) break;
        parser.advance();
      }
  
      parser.advance();
      return new Text(childLines.join('\n'));
    }
  }
  