Merge branch 'master' into regexp
diff --git a/pkgs/markdown/benchmark/input.md b/pkgs/markdown/benchmark/input.md
index 31f5f57..1af6a7e 100644
--- a/pkgs/markdown/benchmark/input.md
+++ b/pkgs/markdown/benchmark/input.md
@@ -1,10 +1,16 @@
 **TODO: Add more examples to cover all of the syntax.**
 
+# Regressions
+
+Bad backtracking in the HR parser:
+
+-------------------------- | -------------------------------------------------
+
+# Real-world sample
+
 This input was taken from the test package's README to get a representative
 sample of real-world markdown:
 
-## Writing Tests
-
 Tests are specified using the top-level [`test()`][test] function, and test
 assertions are made using [`expect()`][expect]:
 
diff --git a/pkgs/markdown/benchmark/output.html b/pkgs/markdown/benchmark/output.html
index 6c49aae..71e5771 100644
--- a/pkgs/markdown/benchmark/output.html
+++ b/pkgs/markdown/benchmark/output.html
@@ -1,7 +1,10 @@
 <p><strong>TODO: Add more examples to cover all of the syntax.</strong></p>
+<h1>Regressions</h1>
+<p>Bad backtracking in the HR parser:</p>
+<p>-------------------------- | -------------------------------------------------</p>
+<h1>Real-world sample</h1>
 <p>This input was taken from the test package's README to get a representative
 sample of real-world markdown:</p>
-<h2>Writing Tests</h2>
 <p>Tests are specified using the top-level <a href="http://www.dartdocs.org/documentation/test/latest/index.html#test/test@id_test"><code>test()</code></a> function, and test
 assertions are made using <a href="http://www.dartdocs.org/documentation/test/latest/index.html#test/test@id_expect"><code>expect()</code></a>:</p>
 <pre class="dart"><code>import "package:test/test.dart";
diff --git a/pkgs/markdown/lib/src/block_parser.dart b/pkgs/markdown/lib/src/block_parser.dart
index 504fdbb..5bdc111 100644
--- a/pkgs/markdown/lib/src/block_parser.dart
+++ b/pkgs/markdown/lib/src/block_parser.dart
@@ -9,13 +9,16 @@
 import 'util.dart';
 
 /// The line contains only whitespace or is empty.
-final _emptyPattern = new RegExp(r'^([ \t]*)$');
+final _emptyPattern = new RegExp(r'^(?:[ \t]*)$');
 
 /// A series of `=` or `-` (on the next line) define setext-style headers.
-final _setextPattern = new RegExp(r'^((=+)|(-+))$');
+final _setextPattern = new RegExp(r'^(=+|-+)$');
 
 /// Leading (and trailing) `#` define atx-style headers.
-final _headerPattern = new RegExp(r'^(#{1,6})(.*?)#*$');
+///
+/// Starts with 1-6 unescaped `#` characters which must not be followed by a
+/// non-space character. Line may end with any number of `#` characters,.
+final _headerPattern = new RegExp(r'^(#{1,6})[ \x09\x0b\x0c](.*?)#*$');
 
 /// The line starts with `>` with one optional space after.
 final _blockquotePattern = new RegExp(r'^[ ]{0,3}>[ ]?(.*)$');
@@ -24,14 +27,12 @@
 final _indentPattern = new RegExp(r'^(?:    |\t)(.*)$');
 
 /// Fenced code block.
-final _codePattern = new RegExp(r'^(`{3,}|~{3,})(.*)$');
+final _codePattern = new RegExp(r'^[ ]{0,3}(`{3,}|~{3,})(.*)$');
 
 /// Three or more hyphens, asterisks or underscores by themselves. Note that
 /// a line like `----` is valid as both HR and SETEXT. In case of a tie,
 /// SETEXT should win.
-final _hrPattern = new RegExp(r'^[ ]{0,3}((-+[ ]{0,2}){3,}|'
-    r'(_+[ ]{0,2}){3,}|'
-    r'(\*+[ ]{0,2}){3,})$');
+final _hrPattern = new RegExp(r'^ {0,3}([-*_]) *\1 *\1(?:\1| )*$');
 
 /// Really hacky way to detect block-level embedded HTML. Just looks for
 /// "<somename".
diff --git a/pkgs/markdown/test/markdown_test.dart b/pkgs/markdown/test/markdown_test.dart
index 4facb3b..b747289 100644
--- a/pkgs/markdown/test/markdown_test.dart
+++ b/pkgs/markdown/test/markdown_test.dart
@@ -236,6 +236,24 @@
         ''');
 
     validate(
+        'h7 is not a header',
+        '''
+        ####### header
+        ''',
+        '''
+        <p>####### header</p>
+        ''');
+
+    validate(
+        'h6 must not be followed by non-space ',
+        '''
+        ######A header
+        ''',
+        '''
+        <p>######A header</p>
+        ''');
+
+    validate(
         'trailing "#" are removed',
         '''
         # header ######