aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSadaf Ebrahimi <sadafebrahimi@google.com>2022-11-04 20:35:11 +0000
committerSadaf Ebrahimi <sadafebrahimi@google.com>2022-11-04 20:35:11 +0000
commitd11b75301624f3c59c7243ad1e75243446f5c229 (patch)
tree1a110fa9fa982e746b1969458c5b9d373c70a38c
parentf94cfcb46cac5900c86c14ab81db9aac90978889 (diff)
downloadmarkdown-d11b75301624f3c59c7243ad1e75243446f5c229.tar.gz
Upgrade markdown to 3.4.1
This project was upgraded with external_updater. Usage: tools/external_updater/updater.sh update markdown For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md Test: TreeHugger Change-Id: I96b25097329b04dcfd580791826971ce299c12f1
-rw-r--r--.codecov.yml1
-rw-r--r--.coveragerc5
-rw-r--r--.gitattributes7
-rw-r--r--.github/workflows/deploy.yml53
-rw-r--r--.github/workflows/manual_deploy.yml30
-rw-r--r--.github/workflows/process.yml35
-rw-r--r--.github/workflows/tox.yml88
-rw-r--r--.gitignore81
-rw-r--r--.spell-dict163
-rw-r--r--CODE_OF_CONDUCT.md49
-rw-r--r--INSTALL.md9
-rw-r--r--LICENSE.md (renamed from docs/LICENSE)25
-rw-r--r--MANIFEST.in10
-rw-r--r--METADATA8
-rwxr-xr-xMarkdownTest/MarkdownTest.pl165
-rw-r--r--MarkdownTest/Tests_2004/Amps and angle encoding.text-out21
-rw-r--r--MarkdownTest/Tests_2004/Amps and angle encoding.text-res21
-rw-r--r--MarkdownTest/Tests_2004/Auto links.text-out28
-rw-r--r--MarkdownTest/Tests_2004/Auto links.text-res28
-rw-r--r--MarkdownTest/Tests_2004/Backslash escapes.text-out79
-rw-r--r--MarkdownTest/Tests_2004/Backslash escapes.text-res79
-rw-r--r--MarkdownTest/Tests_2004/Blockquotes with code blocks.text-out25
-rw-r--r--MarkdownTest/Tests_2004/Blockquotes with code blocks.text-res25
-rw-r--r--MarkdownTest/Tests_2004/Hard-wrapped paragraphs with list-like lines.text-out14
-rw-r--r--MarkdownTest/Tests_2004/Hard-wrapped paragraphs with list-like lines.text-res14
-rw-r--r--MarkdownTest/Tests_2004/Horizontal rules.text-out61
-rw-r--r--MarkdownTest/Tests_2004/Horizontal rules.text-res61
-rw-r--r--MarkdownTest/Tests_2004/Inline HTML (Advanced).text-out19
-rw-r--r--MarkdownTest/Tests_2004/Inline HTML (Advanced).text-res19
-rw-r--r--MarkdownTest/Tests_2004/Inline HTML (Simple).text-out59
-rw-r--r--MarkdownTest/Tests_2004/Inline HTML (Simple).text-res59
-rw-r--r--MarkdownTest/Tests_2004/Inline HTML comments.text-out18
-rw-r--r--MarkdownTest/Tests_2004/Inline HTML comments.text-res18
-rw-r--r--MarkdownTest/Tests_2004/Links, inline style.text-out17
-rw-r--r--MarkdownTest/Tests_2004/Links, inline style.text-res17
-rw-r--r--MarkdownTest/Tests_2004/Links, reference style.text-out22
-rw-r--r--MarkdownTest/Tests_2004/Links, reference style.text-res22
-rw-r--r--MarkdownTest/Tests_2004/Links-in-Headers.text-out9
-rw-r--r--MarkdownTest/Tests_2004/Links-in-Headers.text-res9
-rw-r--r--MarkdownTest/Tests_2004/Literal quotes in titles.text-out14
-rw-r--r--MarkdownTest/Tests_2004/Literal quotes in titles.text-res14
-rw-r--r--MarkdownTest/Tests_2004/Markdown Documentation - Basics.text-out321
-rw-r--r--MarkdownTest/Tests_2004/Markdown Documentation - Basics.text-res321
-rw-r--r--MarkdownTest/Tests_2004/Markdown Documentation - Syntax.text-out957
-rw-r--r--MarkdownTest/Tests_2004/Markdown Documentation - Syntax.text-res957
-rw-r--r--MarkdownTest/Tests_2004/Nested blockquotes.text-out17
-rw-r--r--MarkdownTest/Tests_2004/Nested blockquotes.text-res17
-rw-r--r--MarkdownTest/Tests_2004/Ordered and unordered lists.text-out159
-rw-r--r--MarkdownTest/Tests_2004/Ordered and unordered lists.text-res159
-rw-r--r--MarkdownTest/Tests_2004/Strong and em together.text-out14
-rw-r--r--MarkdownTest/Tests_2004/Strong and em together.text-res14
-rw-r--r--MarkdownTest/Tests_2004/Tabs.text-out37
-rw-r--r--MarkdownTest/Tests_2004/Tabs.text-res37
-rw-r--r--MarkdownTest/Tests_2004/Tidyness.text-out18
-rw-r--r--MarkdownTest/Tests_2004/Tidyness.text-res18
-rw-r--r--MarkdownTest/Tests_2004/Yuri-Attributes.text-out29
-rw-r--r--MarkdownTest/Tests_2004/Yuri-Attributes.text-res29
-rw-r--r--MarkdownTest/Tests_2004/Yuri-Attributes.text~24
-rw-r--r--MarkdownTest/Tests_2004/Yuri-Email.text-out17
-rw-r--r--MarkdownTest/Tests_2004/Yuri-Email.text-res17
-rw-r--r--MarkdownTest/Tests_2004/Yuri-Footnotes.text-out42
-rw-r--r--MarkdownTest/Tests_2004/Yuri-Footnotes.text-res55
-rw-r--r--MarkdownTest/Tests_2004/Yuri-Links-in-Headers.text-out18
-rw-r--r--MarkdownTest/Tests_2004/Yuri-Links-in-Headers.text-res18
-rw-r--r--MarkdownTest/readme.txt1
-rw-r--r--README.md64
-rwxr-xr-xbin/markdown42
-rwxr-xr-xchecklinks.sh31
-rwxr-xr-xcheckspelling.sh38
-rw-r--r--doc-requirements.txt2
-rw-r--r--docs/AUTHORS44
-rw-r--r--docs/CHANGE_LOG180
-rw-r--r--docs/INSTALL73
-rw-r--r--docs/README30
-rw-r--r--docs/README.html12
-rw-r--r--docs/authors.md70
-rw-r--r--docs/change_log/index.md321
-rw-r--r--docs/change_log/release-2.0.md (renamed from docs/release-2.0.txt)40
-rw-r--r--docs/change_log/release-2.1.md118
-rw-r--r--docs/change_log/release-2.2.md64
-rw-r--r--docs/change_log/release-2.3.md85
-rw-r--r--docs/change_log/release-2.4.md73
-rw-r--r--docs/change_log/release-2.5.md189
-rw-r--r--docs/change_log/release-2.6.md304
-rw-r--r--docs/change_log/release-3.0.md228
-rw-r--r--docs/change_log/release-3.1.md48
-rw-r--r--docs/change_log/release-3.2.md96
-rw-r--r--docs/change_log/release-3.3.md109
-rw-r--r--docs/change_log/release-3.4.md113
-rw-r--r--docs/cli.md189
-rw-r--r--docs/command_line.txt98
-rw-r--r--docs/contributing.md561
-rw-r--r--docs/extensions/Abbreviations.txt53
-rw-r--r--docs/extensions/CodeHilite.txt113
-rw-r--r--docs/extensions/Definition_Lists.txt55
-rw-r--r--docs/extensions/Fenced_Code_Blocks.txt63
-rw-r--r--docs/extensions/HTML_Tidy.txt27
-rw-r--r--docs/extensions/HeaderId.txt104
-rw-r--r--docs/extensions/ImageLinks.txt27
-rw-r--r--docs/extensions/Meta-Data.txt88
-rw-r--r--docs/extensions/RSS.txt35
-rw-r--r--docs/extensions/Tables.txt53
-rw-r--r--docs/extensions/Tables_of_Contents.txt50
-rw-r--r--docs/extensions/WikiLinks.txt144
-rw-r--r--docs/extensions/abbreviations.md51
-rw-r--r--docs/extensions/admonition.md115
-rw-r--r--docs/extensions/api.md886
-rw-r--r--docs/extensions/attr_list.md202
-rw-r--r--docs/extensions/code_hilite.md308
-rw-r--r--docs/extensions/definition_lists.md58
-rw-r--r--docs/extensions/extra.md62
-rw-r--r--docs/extensions/extra.txt43
-rw-r--r--docs/extensions/fenced_code_blocks.md269
-rw-r--r--docs/extensions/footnotes.md133
-rw-r--r--docs/extensions/footnotes.txt62
-rw-r--r--docs/extensions/index.md87
-rw-r--r--docs/extensions/index.txt44
-rw-r--r--docs/extensions/legacy_attrs.md66
-rw-r--r--docs/extensions/legacy_em.md31
-rw-r--r--docs/extensions/md_in_html.md237
-rw-r--r--docs/extensions/meta_data.md113
-rw-r--r--docs/extensions/nl2br.md41
-rw-r--r--docs/extensions/sane_lists.md104
-rw-r--r--docs/extensions/smarty.md84
-rw-r--r--docs/extensions/tables.md87
-rw-r--r--docs/extensions/toc.md232
-rw-r--r--docs/extensions/wikilinks.md154
-rw-r--r--docs/favicon.icobin0 -> 15086 bytes
-rw-r--r--docs/index.md112
-rw-r--r--docs/install.md32
-rw-r--r--docs/py.pngbin0 -> 695 bytes
-rw-r--r--docs/reference.md269
-rw-r--r--docs/release-2.0.1.txt16
-rw-r--r--docs/release-2.0.2.txt9
-rw-r--r--docs/test_tools.md178
-rw-r--r--docs/using_as_module.txt150
-rw-r--r--docs/writing_extensions.txt594
-rw-r--r--makefile63
-rw-r--r--markdown/__init__.py616
-rw-r--r--markdown/__main__.py151
-rw-r--r--markdown/__meta__.py49
-rw-r--r--markdown/blockparser.py92
-rw-r--r--markdown/blockprocessors.py423
-rw-r--r--markdown/commandline.py96
-rw-r--r--markdown/core.py407
-rw-r--r--markdown/etree_loader.py33
-rw-r--r--markdown/extensions/__init__.py86
-rw-r--r--markdown/extensions/abbr.py114
-rw-r--r--markdown/extensions/admonition.py170
-rw-r--r--markdown/extensions/attr_list.py166
-rw-r--r--markdown/extensions/codehilite.py400
-rw-r--r--markdown/extensions/def_list.py87
-rw-r--r--markdown/extensions/extra.py53
-rw-r--r--markdown/extensions/fenced_code.py223
-rw-r--r--markdown/extensions/footnotes.py474
-rw-r--r--markdown/extensions/headerid.py195
-rw-r--r--markdown/extensions/html_tidy.py62
-rw-r--r--markdown/extensions/imagelinks.py119
-rw-r--r--markdown/extensions/legacy_attrs.py67
-rw-r--r--markdown/extensions/legacy_em.py49
-rw-r--r--markdown/extensions/md_in_html.py364
-rw-r--r--markdown/extensions/meta.py83
-rw-r--r--markdown/extensions/nl2br.py33
-rw-r--r--markdown/extensions/rss.py114
-rw-r--r--markdown/extensions/sane_lists.py54
-rw-r--r--markdown/extensions/smarty.py257
-rw-r--r--markdown/extensions/tables.py223
-rw-r--r--markdown/extensions/toc.py472
-rw-r--r--markdown/extensions/wikilinks.py156
-rw-r--r--markdown/html4.py274
-rw-r--r--markdown/htmlparser.py323
-rw-r--r--markdown/inlinepatterns.py875
-rw-r--r--markdown/odict.py162
-rw-r--r--markdown/postprocessors.py124
-rw-r--r--markdown/preprocessors.py223
-rw-r--r--markdown/serializers.py189
-rw-r--r--markdown/test_tools.py220
-rw-r--r--markdown/treeprocessors.py307
-rw-r--r--markdown/util.py358
-rw-r--r--mkdocs.yml64
-rw-r--r--pyproject.toml4
-rwxr-xr-xregression-tests.py234
-rw-r--r--setup.cfg2
-rwxr-xr-xsetup.py193
-rwxr-xr-xtest-markdown.py347
-rw-r--r--tests/__init__.py20
-rw-r--r--tests/basic/amps-and-angle-encoding.html (renamed from tests/markdown-test/amps-and-angle-encoding.html)0
-rw-r--r--tests/basic/amps-and-angle-encoding.txt (renamed from tests/markdown-test/amps-and-angle-encoding.txt)0
-rw-r--r--tests/basic/angle-links-and-img.html (renamed from tests/markdown-test/angle-links-and-img.html)0
-rw-r--r--tests/basic/angle-links-and-img.txt (renamed from tests/markdown-test/angle-links-and-img.txt)0
-rw-r--r--tests/basic/auto-links.html (renamed from tests/markdown-test/auto-links.html)0
-rw-r--r--tests/basic/auto-links.txt (renamed from tests/markdown-test/auto-links.txt)0
-rw-r--r--tests/basic/backlash-escapes.html (renamed from tests/markdown-test/backlash-escapes.html)0
-rw-r--r--tests/basic/backlash-escapes.txt (renamed from tests/markdown-test/backlash-escapes.txt)0
-rw-r--r--tests/basic/blockquotes-with-code-blocks.html (renamed from tests/markdown-test/blockquotes-with-code-blocks.html)0
-rw-r--r--tests/basic/blockquotes-with-code-blocks.txt (renamed from tests/markdown-test/blockquotes-with-code-blocks.txt)0
-rw-r--r--tests/basic/codeblock-in-list.html (renamed from tests/markdown-test/codeblock-in-list.html)0
-rw-r--r--tests/basic/codeblock-in-list.txt (renamed from tests/markdown-test/codeblock-in-list.txt)0
-rw-r--r--tests/basic/hard-wrapped.html (renamed from tests/markdown-test/hard-wrapped.html)0
-rw-r--r--tests/basic/hard-wrapped.txt (renamed from tests/markdown-test/hard-wrapped.txt)0
-rw-r--r--tests/basic/horizontal-rules.html (renamed from tests/markdown-test/horizontal-rules.html)0
-rw-r--r--tests/basic/horizontal-rules.txt (renamed from tests/markdown-test/horizontal-rules.txt)0
-rw-r--r--tests/basic/links-inline.html (renamed from tests/markdown-test/links-inline.html)0
-rw-r--r--tests/basic/links-inline.txt (renamed from tests/markdown-test/links-inline.txt)0
-rw-r--r--tests/basic/links-reference.html22
-rw-r--r--tests/basic/links-reference.txt61
-rw-r--r--tests/basic/literal-quotes.html (renamed from tests/markdown-test/literal-quotes.html)0
-rw-r--r--tests/basic/literal-quotes.txt (renamed from tests/markdown-test/literal-quotes.txt)0
-rw-r--r--tests/basic/markdown-documentation-basics.html (renamed from tests/markdown-test/markdown-documentation-basics.html)8
-rw-r--r--tests/basic/markdown-documentation-basics.txt (renamed from tests/markdown-test/markdown-documentation-basics.txt)8
-rw-r--r--tests/basic/markdown-syntax.html (renamed from tests/extensions-x-def_list/markdown-syntax.html)16
-rw-r--r--tests/basic/markdown-syntax.txt (renamed from tests/extensions-x-def_list/markdown-syntax.txt)6
-rw-r--r--tests/basic/nested-blockquotes.html (renamed from tests/markdown-test/nested-blockquotes.html)0
-rw-r--r--tests/basic/nested-blockquotes.txt (renamed from tests/markdown-test/nested-blockquotes.txt)0
-rw-r--r--tests/basic/ordered-and-unordered-list.html (renamed from tests/markdown-test/ordered-and-unordered-list.html)0
-rw-r--r--tests/basic/ordered-and-unordered-list.txt (renamed from tests/markdown-test/ordered-and-unordered-list.txt)0
-rw-r--r--tests/basic/strong-and-em-together.html (renamed from tests/markdown-test/strong-and-em-together.html)0
-rw-r--r--tests/basic/strong-and-em-together.txt (renamed from tests/markdown-test/strong-and-em-together.txt)0
-rw-r--r--tests/basic/tabs.html (renamed from tests/markdown-test/tabs.html)4
-rw-r--r--tests/basic/tabs.txt (renamed from tests/markdown-test/tabs.txt)0
-rw-r--r--tests/basic/tidyness.html (renamed from tests/markdown-test/tidyness.html)0
-rw-r--r--tests/basic/tidyness.txt (renamed from tests/markdown-test/tidyness.txt)0
-rw-r--r--tests/extensions-x-abbr/abbr.html4
-rw-r--r--tests/extensions-x-abbr/abbr.txt13
-rw-r--r--tests/extensions-x-footnotes/footnote.html29
-rw-r--r--tests/extensions-x-footnotes/footnote.txt14
-rw-r--r--tests/extensions-x-footnotes/named_markers.html24
-rw-r--r--tests/extensions-x-tables/tables.html119
-rw-r--r--tests/extensions-x-tables/tables.txt34
-rw-r--r--tests/extensions-x-toc/nested.html16
-rw-r--r--tests/extensions-x-wikilinks/wikilinks.html6
-rw-r--r--tests/extensions/admonition.html48
-rw-r--r--tests/extensions/admonition.txt45
-rw-r--r--tests/extensions/attr_list.html69
-rw-r--r--tests/extensions/attr_list.txt94
-rw-r--r--tests/extensions/codehilite.html (renamed from tests/extensions-x-codehilite/code.html)0
-rw-r--r--tests/extensions/codehilite.txt (renamed from tests/extensions-x-codehilite/code.txt)0
-rw-r--r--tests/extensions/extra/def-in-list.html25
-rw-r--r--tests/extensions/extra/def-in-list.txt15
-rw-r--r--tests/extensions/extra/extra_config.html9
-rw-r--r--tests/extensions/extra/extra_config.txt5
-rw-r--r--tests/extensions/extra/footnote.html71
-rw-r--r--tests/extensions/extra/footnote.txt62
-rw-r--r--tests/extensions/extra/footnote_many_footnotes.html4801
-rw-r--r--tests/extensions/extra/footnote_many_footnotes.txt4796
-rw-r--r--tests/extensions/extra/footnote_placeholder.html9
-rw-r--r--tests/extensions/extra/footnote_placeholder.txt5
-rw-r--r--tests/extensions/extra/footnote_placeholder_depth.html13
-rw-r--r--tests/extensions/extra/footnote_placeholder_depth.txt5
-rw-r--r--tests/extensions/extra/loose_def_list.html (renamed from tests/extensions-x-def_list/loose_def_list.html)12
-rw-r--r--tests/extensions/extra/loose_def_list.txt (renamed from tests/extensions-x-def_list/loose_def_list.txt)11
-rw-r--r--tests/extensions/extra/markdown-syntax.html (renamed from tests/markdown-test/markdown-syntax.html)16
-rw-r--r--tests/extensions/extra/markdown-syntax.txt (renamed from tests/markdown-test/markdown-syntax.txt)6
-rw-r--r--tests/extensions/extra/named_markers.html20
-rw-r--r--tests/extensions/extra/named_markers.txt (renamed from tests/extensions-x-footnotes/named_markers.txt)0
-rw-r--r--tests/extensions/extra/raw-html.html123
-rw-r--r--tests/extensions/extra/raw-html.txt184
-rw-r--r--tests/extensions/extra/simple_def-lists.html (renamed from tests/extensions-x-def_list/simple_def-lists.html)6
-rw-r--r--tests/extensions/extra/simple_def-lists.txt (renamed from tests/extensions-x-def_list/simple_def-lists.txt)6
-rw-r--r--tests/extensions/github_flavored.html40
-rw-r--r--tests/extensions/github_flavored.txt45
-rw-r--r--tests/extensions/nl2br_w_attr_list.html1
-rw-r--r--tests/extensions/nl2br_w_attr_list.txt2
-rw-r--r--tests/extensions/sane_lists.html32
-rw-r--r--tests/extensions/sane_lists.txt26
-rw-r--r--tests/extensions/smarty.html32
-rw-r--r--tests/extensions/smarty.txt40
-rw-r--r--tests/extensions/toc.html (renamed from tests/extensions-x-toc/syntax-toc.html)16
-rw-r--r--tests/extensions/toc.txt (renamed from tests/extensions-x-toc/syntax-toc.txt)6
-rw-r--r--tests/extensions/toc_invalid.html (renamed from tests/extensions-x-toc/invalid.html)0
-rw-r--r--tests/extensions/toc_invalid.txt (renamed from tests/extensions-x-toc/invalid.txt)0
-rw-r--r--tests/extensions/toc_nested.html16
-rw-r--r--tests/extensions/toc_nested.txt (renamed from tests/extensions-x-toc/nested.txt)2
-rw-r--r--tests/extensions/toc_nested2.html14
-rw-r--r--tests/extensions/toc_nested2.txt10
-rw-r--r--tests/extensions/toc_nested_list.html30
-rw-r--r--tests/extensions/toc_nested_list.txt19
-rw-r--r--tests/extensions/toc_out_of_order.html8
-rw-r--r--tests/extensions/toc_out_of_order.txt5
-rw-r--r--tests/extensions/wikilinks.html9
-rw-r--r--tests/extensions/wikilinks.txt (renamed from tests/extensions-x-wikilinks/wikilinks.txt)0
-rw-r--r--tests/html4/html4.html2
-rw-r--r--tests/html4/html4.txt2
-rw-r--r--tests/markdown-test/benchmark.dat20
-rw-r--r--tests/markdown-test/inline-html-advanced.html12
-rw-r--r--tests/markdown-test/inline-html-advanced.txt14
-rw-r--r--tests/markdown-test/inline-html-comments.html11
-rw-r--r--tests/markdown-test/inline-html-comments.txt13
-rw-r--r--tests/markdown-test/inline-html-simple.html58
-rw-r--r--tests/markdown-test/inline-html-simple.txt69
-rw-r--r--tests/markdown-test/links-reference.html10
-rw-r--r--tests/markdown-test/links-reference.txt31
-rw-r--r--tests/misc/amp-in-url.html1
-rw-r--r--tests/misc/amp-in-url.txt1
-rw-r--r--tests/misc/ampersand.html2
-rw-r--r--tests/misc/ampersand.txt5
-rw-r--r--tests/misc/attributes2.html6
-rw-r--r--tests/misc/attributes2.txt10
-rw-r--r--tests/misc/backtick-escape.html5
-rw-r--r--tests/misc/backtick-escape.txt5
-rw-r--r--tests/misc/bidi.html4
-rw-r--r--tests/misc/bidi.txt4
-rw-r--r--tests/misc/blank-block-quote.html2
-rw-r--r--tests/misc/blank_lines_in_codeblocks.html61
-rw-r--r--tests/misc/blank_lines_in_codeblocks.txt73
-rw-r--r--tests/misc/blockquote-hr.html9
-rw-r--r--tests/misc/blockquote-hr.txt6
-rw-r--r--tests/misc/br.html2
-rw-r--r--tests/misc/br.txt2
-rw-r--r--tests/misc/brackets-in-img-title.html9
-rw-r--r--tests/misc/brackets-in-img-title.txt12
-rw-r--r--tests/misc/comments.html5
-rw-r--r--tests/misc/comments.txt7
-rw-r--r--tests/misc/div.html4
-rw-r--r--tests/misc/div.txt5
-rw-r--r--tests/misc/em-around-links.html15
-rw-r--r--tests/misc/em-around-links.txt10
-rw-r--r--tests/misc/em_strong.html3
-rw-r--r--tests/misc/em_strong.txt1
-rw-r--r--tests/misc/em_strong_complex.html14
-rw-r--r--tests/misc/em_strong_complex.txt27
-rw-r--r--tests/misc/email.html3
-rw-r--r--tests/misc/email.txt2
-rw-r--r--tests/misc/escaped_links.html4
-rw-r--r--tests/misc/escaped_links.txt9
-rw-r--r--tests/misc/h1.html4
-rw-r--r--tests/misc/h1.txt6
-rw-r--r--tests/misc/header-in-lists.html20
-rw-r--r--tests/misc/header-in-lists.txt14
-rw-r--r--tests/misc/html-comments.html2
-rw-r--r--tests/misc/html-comments.txt2
-rw-r--r--tests/misc/html.html9
-rw-r--r--tests/misc/html.txt13
-rw-r--r--tests/misc/image.html1
-rw-r--r--tests/misc/image.txt2
-rw-r--r--tests/misc/ins-at-start-of-paragraph.html1
-rw-r--r--tests/misc/ins-at-start-of-paragraph.txt1
-rw-r--r--tests/misc/lists3.html4
-rw-r--r--tests/misc/lists7.html98
-rw-r--r--tests/misc/lists7.txt44
-rw-r--r--tests/misc/lists8.html39
-rw-r--r--tests/misc/lists8.txt16
-rw-r--r--tests/misc/markup-inside-p.html21
-rw-r--r--tests/misc/markup-inside-p.txt21
-rw-r--r--tests/misc/mismatched-tags.html11
-rw-r--r--tests/misc/mismatched-tags.txt9
-rw-r--r--tests/misc/more_comments.html7
-rw-r--r--tests/misc/more_comments.txt9
-rw-r--r--tests/misc/multi-line-tags.html4
-rw-r--r--tests/misc/multi-line-tags.txt6
-rw-r--r--tests/misc/multi-paragraph-block-quote.html2
-rw-r--r--tests/misc/multi-test.html2
-rw-r--r--tests/misc/multi-test.txt6
-rw-r--r--tests/misc/multiline-comments.html16
-rw-r--r--tests/misc/multiline-comments.txt18
-rw-r--r--tests/misc/nested-lists.html13
-rw-r--r--tests/misc/nested-lists.txt9
-rw-r--r--tests/misc/nested-patterns.html17
-rw-r--r--tests/misc/nested-patterns.txt20
-rw-r--r--tests/misc/para-with-hr.html5
-rw-r--r--tests/misc/para-with-hr.txt3
-rw-r--r--tests/misc/php.html11
-rw-r--r--tests/misc/php.txt13
-rw-r--r--tests/misc/pre.html13
-rw-r--r--tests/misc/pre.txt14
-rw-r--r--tests/misc/some-test.html6
-rw-r--r--tests/misc/tabs-in-lists.html2
-rw-r--r--tests/misc/two-spaces.html6
-rw-r--r--tests/misc/uche.html2
-rw-r--r--tests/misc/uche.txt3
-rw-r--r--tests/misc/underscores.html2
-rw-r--r--tests/php/Auto Links.text3
-rw-r--r--tests/php/Auto Links.xhtml3
-rw-r--r--tests/php/Backslash escapes.text1
-rw-r--r--tests/php/Backslash escapes.xhtml1
-rw-r--r--tests/php/Code Spans.text6
-rw-r--r--tests/php/Code Spans.xhtml6
-rw-r--r--tests/php/Code block in a list item.text15
-rw-r--r--tests/php/Code block in a list item.xhtml18
-rw-r--r--tests/php/Code block on second line.text2
-rw-r--r--tests/php/Code block on second line.xhtml2
-rw-r--r--tests/php/Email auto links.text3
-rw-r--r--tests/php/Email auto links.xhtml3
-rw-r--r--tests/php/Emphasis.text80
-rw-r--r--tests/php/Emphasis.xhtml83
-rw-r--r--tests/php/Empty List Item.text35
-rw-r--r--tests/php/Empty List Item.xhtml47
-rw-r--r--tests/php/Headers.text9
-rw-r--r--tests/php/Headers.xhtml39
-rw-r--r--tests/php/Horizontal Rules.text29
-rw-r--r--tests/php/Horizontal Rules.xhtml30
-rw-r--r--tests/php/Inline HTML (Simple).text15
-rw-r--r--tests/php/Inline HTML (Simple).xhtml15
-rw-r--r--tests/php/Inline HTML (Span).text4
-rw-r--r--tests/php/Inline HTML (Span).xhtml4
-rw-r--r--tests/php/Inline HTML comments.text9
-rw-r--r--tests/php/Inline HTML comments.xhtml9
-rw-r--r--tests/php/Ins & del.text17
-rw-r--r--tests/php/Ins & del.xhtml17
-rw-r--r--tests/php/License339
-rw-r--r--tests/php/Links, inline style.text1
-rw-r--r--tests/php/Links, inline style.xhtml1
-rw-r--r--tests/php/MD5 Hashes.text11
-rw-r--r--tests/php/MD5 Hashes.xhtml11
-rw-r--r--tests/php/Mixed OLs and ULs.text13
-rw-r--r--tests/php/Mixed OLs and ULs.xhtml21
-rw-r--r--tests/php/Nesting.text11
-rw-r--r--tests/php/Nesting.xhtml11
-rw-r--r--tests/php/PHP-Specific Bugs.text22
-rw-r--r--tests/php/PHP-Specific Bugs.xhtml17
-rw-r--r--tests/php/Parens in URL.text14
-rw-r--r--tests/php/Parens in URL.xhtml11
-rw-r--r--tests/php/Quotes in attributes.text5
-rw-r--r--tests/php/Quotes in attributes.xhtml5
-rw-r--r--tests/php/Tight blocks.text1
-rw-r--r--tests/php/Tight blocks.xhtml21
-rw-r--r--tests/php/extra/Abbr.text31
-rw-r--r--tests/php/extra/Abbr.xhtml15
-rw-r--r--tests/php/extra/Definition Lists.text115
-rw-r--r--tests/php/extra/Definition Lists.xhtml155
-rw-r--r--tests/php/extra/Emphasis.text80
-rw-r--r--tests/php/extra/Emphasis.xhtml83
-rw-r--r--tests/php/extra/Fenced Code Blocks.text60
-rw-r--r--tests/php/extra/Fenced Code Blocks.xhtml53
-rw-r--r--tests/php/extra/Footnotes.text61
-rw-r--r--tests/php/extra/Footnotes.xhtml96
-rw-r--r--tests/php/extra/Inline HTML with Markdown content.text104
-rw-r--r--tests/php/extra/Inline HTML with Markdown content.xhtml125
-rw-r--r--tests/php/extra/Tables.text104
-rw-r--r--tests/php/extra/Tables.xhtml310
-rw-r--r--tests/pl/Tests_2004/Amps and angle encoding.html (renamed from MarkdownTest/Tests_2004/Amps and angle encoding.html)0
-rw-r--r--tests/pl/Tests_2004/Amps and angle encoding.text (renamed from MarkdownTest/Tests_2004/Amps and angle encoding.text)0
-rw-r--r--tests/pl/Tests_2004/Auto links.html (renamed from MarkdownTest/Tests_2004/Auto links.html)0
-rw-r--r--tests/pl/Tests_2004/Auto links.text (renamed from MarkdownTest/Tests_2004/Auto links.text)0
-rw-r--r--tests/pl/Tests_2004/Backslash escapes.html (renamed from MarkdownTest/Tests_2004/Backslash escapes.html)0
-rw-r--r--tests/pl/Tests_2004/Backslash escapes.text (renamed from MarkdownTest/Tests_2004/Backslash escapes.text)0
-rw-r--r--tests/pl/Tests_2004/Blockquotes with code blocks.html (renamed from MarkdownTest/Tests_2004/Blockquotes with code blocks.html)0
-rw-r--r--tests/pl/Tests_2004/Blockquotes with code blocks.text (renamed from MarkdownTest/Tests_2004/Blockquotes with code blocks.text)0
-rw-r--r--tests/pl/Tests_2004/Hard-wrapped paragraphs with list-like lines.html (renamed from MarkdownTest/Tests_2004/Hard-wrapped paragraphs with list-like lines.html)0
-rw-r--r--tests/pl/Tests_2004/Hard-wrapped paragraphs with list-like lines.text (renamed from MarkdownTest/Tests_2004/Hard-wrapped paragraphs with list-like lines.text)0
-rw-r--r--tests/pl/Tests_2004/Horizontal rules.html (renamed from MarkdownTest/Tests_2004/Horizontal rules.html)0
-rw-r--r--tests/pl/Tests_2004/Horizontal rules.text (renamed from MarkdownTest/Tests_2004/Horizontal rules.text)0
-rw-r--r--tests/pl/Tests_2004/Inline HTML (Advanced).html (renamed from MarkdownTest/Tests_2004/Inline HTML (Advanced).html)0
-rw-r--r--tests/pl/Tests_2004/Inline HTML (Advanced).text (renamed from MarkdownTest/Tests_2004/Inline HTML (Advanced).text)0
-rw-r--r--tests/pl/Tests_2004/Inline HTML (Simple).html (renamed from MarkdownTest/Tests_2004/Inline HTML (Simple).html)0
-rw-r--r--tests/pl/Tests_2004/Inline HTML (Simple).text (renamed from MarkdownTest/Tests_2004/Inline HTML (Simple).text)0
-rw-r--r--tests/pl/Tests_2004/Inline HTML comments.html (renamed from MarkdownTest/Tests_2004/Inline HTML comments.html)0
-rw-r--r--tests/pl/Tests_2004/Inline HTML comments.text (renamed from MarkdownTest/Tests_2004/Inline HTML comments.text)0
-rw-r--r--tests/pl/Tests_2004/Links, inline style.html (renamed from MarkdownTest/Tests_2004/Links, inline style.html)0
-rw-r--r--tests/pl/Tests_2004/Links, inline style.text (renamed from MarkdownTest/Tests_2004/Links, inline style.text)0
-rw-r--r--tests/pl/Tests_2004/Links, reference style.html (renamed from MarkdownTest/Tests_2004/Links, reference style.html)0
-rw-r--r--tests/pl/Tests_2004/Links, reference style.text (renamed from MarkdownTest/Tests_2004/Links, reference style.text)0
-rw-r--r--tests/pl/Tests_2004/Literal quotes in titles.html (renamed from MarkdownTest/Tests_2004/Literal quotes in titles.html)0
-rw-r--r--tests/pl/Tests_2004/Literal quotes in titles.text (renamed from MarkdownTest/Tests_2004/Literal quotes in titles.text)0
-rw-r--r--tests/pl/Tests_2004/Markdown Documentation - Basics.html (renamed from MarkdownTest/Tests_2004/Markdown Documentation - Basics.html)2
-rw-r--r--tests/pl/Tests_2004/Markdown Documentation - Basics.text (renamed from MarkdownTest/Tests_2004/Markdown Documentation - Basics.text)2
-rw-r--r--tests/pl/Tests_2004/Markdown Documentation - Syntax.html (renamed from MarkdownTest/Tests_2004/Markdown Documentation - Syntax.html)4
-rw-r--r--tests/pl/Tests_2004/Markdown Documentation - Syntax.text (renamed from MarkdownTest/Tests_2004/Markdown Documentation - Syntax.text)4
-rw-r--r--tests/pl/Tests_2004/Nested blockquotes.html (renamed from MarkdownTest/Tests_2004/Nested blockquotes.html)0
-rw-r--r--tests/pl/Tests_2004/Nested blockquotes.text (renamed from MarkdownTest/Tests_2004/Nested blockquotes.text)0
-rw-r--r--tests/pl/Tests_2004/Ordered and unordered lists.html (renamed from MarkdownTest/Tests_2004/Ordered and unordered lists.html)0
-rw-r--r--tests/pl/Tests_2004/Ordered and unordered lists.text (renamed from MarkdownTest/Tests_2004/Ordered and unordered lists.text)0
-rw-r--r--tests/pl/Tests_2004/Strong and em together.html (renamed from MarkdownTest/Tests_2004/Strong and em together.html)0
-rw-r--r--tests/pl/Tests_2004/Strong and em together.text (renamed from MarkdownTest/Tests_2004/Strong and em together.text)0
-rw-r--r--tests/pl/Tests_2004/Tabs.html (renamed from MarkdownTest/Tests_2004/Tabs.html)0
-rw-r--r--tests/pl/Tests_2004/Tabs.text (renamed from MarkdownTest/Tests_2004/Tabs.text)0
-rw-r--r--tests/pl/Tests_2004/Tidyness.html (renamed from MarkdownTest/Tests_2004/Tidyness.html)0
-rw-r--r--tests/pl/Tests_2004/Tidyness.text (renamed from MarkdownTest/Tests_2004/Tidyness.text)0
-rw-r--r--tests/pl/Tests_2004/Yuri-Attributes.html (renamed from MarkdownTest/Tests_2004/Yuri-Attributes.html)0
-rw-r--r--tests/pl/Tests_2004/Yuri-Attributes.text (renamed from MarkdownTest/Tests_2004/Yuri-Attributes.text)0
-rw-r--r--tests/pl/Tests_2004/Yuri-Email.html (renamed from MarkdownTest/Tests_2004/Yuri-Email.html)0
-rw-r--r--tests/pl/Tests_2004/Yuri-Email.text (renamed from MarkdownTest/Tests_2004/Yuri-Email.text)0
-rw-r--r--tests/pl/Tests_2004/Yuri-Footnotes.html (renamed from MarkdownTest/Tests_2004/Yuri-Footnotes.html)0
-rw-r--r--tests/pl/Tests_2004/Yuri-Footnotes.text (renamed from MarkdownTest/Tests_2004/Yuri-Footnotes.text)0
-rw-r--r--tests/pl/Tests_2004/Yuri-Links-in-Headers.html (renamed from MarkdownTest/Tests_2004/Yuri-Links-in-Headers.html)0
-rw-r--r--tests/pl/Tests_2004/Yuri-Links-in-Headers.text (renamed from MarkdownTest/Tests_2004/Yuri-Links-in-Headers.text)0
-rw-r--r--tests/pl/Tests_2007/Amps and angle encoding.html (renamed from MarkdownTest/Tests_2007/Amps and angle encoding.html)0
-rw-r--r--tests/pl/Tests_2007/Amps and angle encoding.text (renamed from MarkdownTest/Tests_2007/Amps and angle encoding.text)0
-rw-r--r--tests/pl/Tests_2007/Auto links.html (renamed from MarkdownTest/Tests_2007/Auto links.html)0
-rw-r--r--tests/pl/Tests_2007/Auto links.text (renamed from MarkdownTest/Tests_2007/Auto links.text)0
-rw-r--r--tests/pl/Tests_2007/Backslash escapes.html (renamed from MarkdownTest/Tests_2007/Backslash escapes.html)0
-rw-r--r--tests/pl/Tests_2007/Backslash escapes.text (renamed from MarkdownTest/Tests_2007/Backslash escapes.text)0
-rw-r--r--tests/pl/Tests_2007/Blockquotes with code blocks.html (renamed from MarkdownTest/Tests_2007/Blockquotes with code blocks.html)0
-rw-r--r--tests/pl/Tests_2007/Blockquotes with code blocks.text (renamed from MarkdownTest/Tests_2007/Blockquotes with code blocks.text)0
-rw-r--r--tests/pl/Tests_2007/Code Blocks.html (renamed from MarkdownTest/Tests_2007/Code Blocks.html)0
-rw-r--r--tests/pl/Tests_2007/Code Blocks.text (renamed from MarkdownTest/Tests_2007/Code Blocks.text)0
-rw-r--r--tests/pl/Tests_2007/Code Spans.html (renamed from MarkdownTest/Tests_2007/Code Spans.html)0
-rw-r--r--tests/pl/Tests_2007/Code Spans.text (renamed from MarkdownTest/Tests_2007/Code Spans.text)0
-rw-r--r--tests/pl/Tests_2007/Hard-wrapped paragraphs with list-like lines.html (renamed from MarkdownTest/Tests_2007/Hard-wrapped paragraphs with list-like lines.html)0
-rw-r--r--tests/pl/Tests_2007/Hard-wrapped paragraphs with list-like lines.text (renamed from MarkdownTest/Tests_2007/Hard-wrapped paragraphs with list-like lines.text)0
-rw-r--r--tests/pl/Tests_2007/Horizontal rules.html (renamed from MarkdownTest/Tests_2007/Horizontal rules.html)0
-rw-r--r--tests/pl/Tests_2007/Horizontal rules.text (renamed from MarkdownTest/Tests_2007/Horizontal rules.text)0
-rw-r--r--tests/pl/Tests_2007/Images.html (renamed from MarkdownTest/Tests_2007/Images.html)0
-rw-r--r--tests/pl/Tests_2007/Images.text (renamed from MarkdownTest/Tests_2007/Images.text)0
-rw-r--r--tests/pl/Tests_2007/Inline HTML (Advanced).html (renamed from MarkdownTest/Tests_2007/Inline HTML (Advanced).html)0
-rw-r--r--tests/pl/Tests_2007/Inline HTML (Advanced).text (renamed from MarkdownTest/Tests_2007/Inline HTML (Advanced).text)0
-rw-r--r--tests/pl/Tests_2007/Inline HTML (Simple).html (renamed from MarkdownTest/Tests_2007/Inline HTML (Simple).html)0
-rw-r--r--tests/pl/Tests_2007/Inline HTML (Simple).text (renamed from MarkdownTest/Tests_2007/Inline HTML (Simple).text)0
-rw-r--r--tests/pl/Tests_2007/Inline HTML comments.html (renamed from MarkdownTest/Tests_2007/Inline HTML comments.html)0
-rw-r--r--tests/pl/Tests_2007/Inline HTML comments.text (renamed from MarkdownTest/Tests_2007/Inline HTML comments.text)0
-rw-r--r--tests/pl/Tests_2007/Links, inline style.html (renamed from MarkdownTest/Tests_2007/Links, inline style.html)0
-rw-r--r--tests/pl/Tests_2007/Links, inline style.text (renamed from MarkdownTest/Tests_2007/Links, inline style.text)0
-rw-r--r--tests/pl/Tests_2007/Links, reference style.html (renamed from MarkdownTest/Tests_2007/Links, reference style.html)0
-rw-r--r--tests/pl/Tests_2007/Links, reference style.text (renamed from MarkdownTest/Tests_2007/Links, reference style.text)0
-rw-r--r--[-rwxr-xr-x]tests/pl/Tests_2007/Links, shortcut references.html (renamed from MarkdownTest/Tests_2007/Links, shortcut references.html)0
-rw-r--r--[-rwxr-xr-x]tests/pl/Tests_2007/Links, shortcut references.text (renamed from MarkdownTest/Tests_2007/Links, shortcut references.text)0
-rw-r--r--tests/pl/Tests_2007/Literal quotes in titles.html (renamed from MarkdownTest/Tests_2007/Literal quotes in titles.html)0
-rw-r--r--tests/pl/Tests_2007/Literal quotes in titles.text (renamed from MarkdownTest/Tests_2007/Literal quotes in titles.text)0
-rw-r--r--tests/pl/Tests_2007/Markdown Documentation - Basics.html (renamed from MarkdownTest/Tests_2007/Markdown Documentation - Basics.html)2
-rw-r--r--tests/pl/Tests_2007/Markdown Documentation - Basics.text (renamed from MarkdownTest/Tests_2007/Markdown Documentation - Basics.text)2
-rw-r--r--tests/pl/Tests_2007/Markdown Documentation - Syntax.html (renamed from MarkdownTest/Tests_2007/Markdown Documentation - Syntax.html)4
-rw-r--r--tests/pl/Tests_2007/Markdown Documentation - Syntax.text (renamed from MarkdownTest/Tests_2007/Markdown Documentation - Syntax.text)4
-rw-r--r--tests/pl/Tests_2007/Nested blockquotes.html (renamed from MarkdownTest/Tests_2007/Nested blockquotes.html)0
-rw-r--r--tests/pl/Tests_2007/Nested blockquotes.text (renamed from MarkdownTest/Tests_2007/Nested blockquotes.text)0
-rw-r--r--tests/pl/Tests_2007/Ordered and unordered lists.html (renamed from MarkdownTest/Tests_2007/Ordered and unordered lists.html)0
-rw-r--r--tests/pl/Tests_2007/Ordered and unordered lists.text (renamed from MarkdownTest/Tests_2007/Ordered and unordered lists.text)0
-rw-r--r--tests/pl/Tests_2007/Strong and em together.html (renamed from MarkdownTest/Tests_2007/Strong and em together.html)0
-rw-r--r--tests/pl/Tests_2007/Strong and em together.text (renamed from MarkdownTest/Tests_2007/Strong and em together.text)0
-rw-r--r--tests/pl/Tests_2007/Tabs.html (renamed from MarkdownTest/Tests_2007/Tabs.html)0
-rw-r--r--tests/pl/Tests_2007/Tabs.text (renamed from MarkdownTest/Tests_2007/Tabs.text)0
-rw-r--r--tests/pl/Tests_2007/Tidyness.html (renamed from MarkdownTest/Tests_2007/Tidyness.html)0
-rw-r--r--tests/pl/Tests_2007/Tidyness.text (renamed from MarkdownTest/Tests_2007/Tidyness.text)0
-rw-r--r--tests/safe_mode/inline-html-advanced.html11
-rw-r--r--tests/safe_mode/inline-html-advanced.txt14
-rw-r--r--tests/safe_mode/inline-html-comments.html8
-rw-r--r--tests/safe_mode/inline-html-comments.txt13
-rw-r--r--tests/safe_mode/inline-html-simple.html45
-rw-r--r--tests/safe_mode/inline-html-simple.txt69
-rw-r--r--tests/safe_mode/script_tags.html28
-rw-r--r--tests/safe_mode/script_tags.txt33
-rw-r--r--tests/safe_mode/unsafe_urls.html20
-rw-r--r--tests/safe_mode/unsafe_urls.txt27
-rw-r--r--tests/test_apis.py957
-rw-r--r--tests/test_extensions.py665
-rw-r--r--tests/test_legacy.py194
-rw-r--r--tests/test_meta.py24
-rw-r--r--tests/test_syntax/__init__.py20
-rw-r--r--tests/test_syntax/blocks/__init__.py20
-rw-r--r--tests/test_syntax/blocks/test_blockquotes.py51
-rw-r--r--tests/test_syntax/blocks/test_code_blocks.py88
-rw-r--r--tests/test_syntax/blocks/test_headers.py729
-rw-r--r--tests/test_syntax/blocks/test_hr.py402
-rw-r--r--tests/test_syntax/blocks/test_html_blocks.py1619
-rw-r--r--tests/test_syntax/blocks/test_paragraphs.py229
-rw-r--r--tests/test_syntax/extensions/__init__.py20
-rw-r--r--tests/test_syntax/extensions/test_abbr.py242
-rw-r--r--tests/test_syntax/extensions/test_admonition.py245
-rw-r--r--tests/test_syntax/extensions/test_attr_list.py80
-rw-r--r--tests/test_syntax/extensions/test_code_hilite.py764
-rw-r--r--tests/test_syntax/extensions/test_def_list.py323
-rw-r--r--tests/test_syntax/extensions/test_fenced_code.py1020
-rw-r--r--tests/test_syntax/extensions/test_footnotes.py338
-rw-r--r--tests/test_syntax/extensions/test_legacy_attrs.py67
-rw-r--r--tests/test_syntax/extensions/test_legacy_em.py66
-rw-r--r--tests/test_syntax/extensions/test_md_in_html.py1216
-rw-r--r--tests/test_syntax/extensions/test_smarty.py36
-rw-r--r--tests/test_syntax/extensions/test_tables.py922
-rw-r--r--tests/test_syntax/extensions/test_toc.py614
-rw-r--r--tests/test_syntax/inline/__init__.py20
-rw-r--r--tests/test_syntax/inline/test_autolinks.py63
-rw-r--r--tests/test_syntax/inline/test_emphasis.py130
-rw-r--r--tests/test_syntax/inline/test_entities.py43
-rw-r--r--tests/test_syntax/inline/test_images.py184
-rw-r--r--tests/test_syntax/inline/test_links.py386
-rw-r--r--tests/test_syntax/inline/test_raw_html.py30
-rw-r--r--tox.ini43
566 files changed, 38980 insertions, 11414 deletions
diff --git a/.codecov.yml b/.codecov.yml
new file mode 100644
index 0000000..db24720
--- /dev/null
+++ b/.codecov.yml
@@ -0,0 +1 @@
+comment: off
diff --git a/.coveragerc b/.coveragerc
new file mode 100644
index 0000000..c785d90
--- /dev/null
+++ b/.coveragerc
@@ -0,0 +1,5 @@
+[run]
+omit=
+ *site-packages*
+ tests/*
+ markdown/test_tools.py
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..2ef1d0d
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,7 @@
+tests/basic/** linguist-vendored
+tests/extensions/** linguist-vendored
+tests/misc/** linguist-vendored
+tests/options/** linguist-vendored
+tests/php/** linguist-vendored
+tests/pl/** linguist-vendored
+tests/safe_mode/** linguist-vendored
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
new file mode 100644
index 0000000..fca5318
--- /dev/null
+++ b/.github/workflows/deploy.yml
@@ -0,0 +1,53 @@
+name: deploy
+
+on:
+ push:
+ tags:
+ - '*'
+
+jobs:
+
+ pypi:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - name: Setup Python
+ uses: actions/setup-python@v1
+ with:
+ python-version: 3.7
+ - name: Install dependencies
+ run: |
+ python -m pip install --upgrade pip setuptools wheel
+ - name: Build
+ run: |
+ python setup.py bdist_wheel sdist --formats gztar
+ - name: Publish
+ if: success()
+ uses: pypa/gh-action-pypi-publish@v1.1.0
+ with:
+ user: __token__
+ password: ${{ secrets.PYPI_PASSWORD }}
+
+ ghpages:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - name: Setup Python
+ uses: actions/setup-python@v1
+ with:
+ python-version: 3.7
+ - name: Install dependencies
+ run: |
+ python -m pip install --upgrade pip setuptools
+ python -m pip install -r doc-requirements.txt
+ - name: Build
+ run: |
+ python -m mkdocs build --clean --verbose
+ - name: Publish
+ if: success()
+ uses: peaceiris/actions-gh-pages@v3
+ with:
+ deploy_key: ${{ secrets.PAGES_DEPLOY_KEY }}
+ external_repository: Python-Markdown/Python-Markdown.github.io
+ publish_branch: master
+ publish_dir: ./site
diff --git a/.github/workflows/manual_deploy.yml b/.github/workflows/manual_deploy.yml
new file mode 100644
index 0000000..b2ce06b
--- /dev/null
+++ b/.github/workflows/manual_deploy.yml
@@ -0,0 +1,30 @@
+name: manual deploy
+
+on:
+ workflow_dispatch
+
+jobs:
+
+ ghpages:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - name: Setup Python
+ uses: actions/setup-python@v1
+ with:
+ python-version: 3.7
+ - name: Install dependencies
+ run: |
+ python -m pip install --upgrade pip setuptools
+ python -m pip install -r doc-requirements.txt
+ - name: Build
+ run: |
+ python -m mkdocs build --clean --verbose
+ - name: Publish
+ if: success()
+ uses: peaceiris/actions-gh-pages@v3
+ with:
+ deploy_key: ${{ secrets.PAGES_DEPLOY_KEY }}
+ external_repository: Python-Markdown/Python-Markdown.github.io
+ publish_branch: master
+ publish_dir: ./site
diff --git a/.github/workflows/process.yml b/.github/workflows/process.yml
new file mode 100644
index 0000000..d6d4c94
--- /dev/null
+++ b/.github/workflows/process.yml
@@ -0,0 +1,35 @@
+name: bot
+
+on:
+ pull_request:
+ branches:
+ - '**'
+
+jobs:
+ require_changelog:
+
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - uses: mskelton/changelog-reminder-action@v1
+ with:
+ # Match any file in the docs/change_log/ dir.
+ changelogRegex: "docs/change_log/.*"
+ # Only require changelog update if changes were made in markdown/
+ include: "markdown/.*"
+ message: |
+ @${{ github.actor }}, thank you for your contribution. It appears that you have not added a comment to the
+ change log describing the changes you have made. Doing so will help to ensure your contribution is accepted.
+
+ Please see the [Contributing Guide](https://python-markdown.github.io/contributing/#pull-requests) for details.
+
+ markdown-link-check:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - uses: gaurav-nelson/github-action-markdown-link-check@v1
+ with:
+ use-quiet-mode: yes
+ use-verbose-mode: yes
+ check-modified-files-only: yes
+ base-branch: master
diff --git a/.github/workflows/tox.yml b/.github/workflows/tox.yml
new file mode 100644
index 0000000..e2004ad
--- /dev/null
+++ b/.github/workflows/tox.yml
@@ -0,0 +1,88 @@
+# This workflow will install dependencies and run tests/linters with a matrix of tox environments.
+
+name: CI
+
+on:
+ push:
+ branches:
+ - master
+ tags:
+ - '**'
+ pull_request:
+ branches:
+ - '**'
+
+jobs:
+ test:
+
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ max-parallel: 4
+ matrix:
+ tox-env: [py37, py38, py39, py310, pypy37, pypy38, pypy39, pygments]
+ include:
+ - tox-env: py37
+ python-version: '3.7'
+ - tox-env: py38
+ python-version: '3.8'
+ - tox-env: py39
+ python-version: '3.9'
+ - tox-env: py310
+ python-version: '3.10'
+ - tox-env: pypy37
+ python-version: pypy-3.7
+ - tox-env: pypy38
+ python-version: pypy-3.8
+ - tox-env: pypy39
+ python-version: pypy-3.9
+ - tox-env: pygments
+ python-version: '3.7'
+
+ env:
+ TOXENV: ${{ matrix.tox-env }}
+
+ steps:
+ - uses: actions/checkout@v2
+ - name: Setup Python ${{ matrix.python-version }}
+ uses: actions/setup-python@v3
+ with:
+ python-version: ${{ matrix.python-version }}
+ - name: Install dependencies
+ run: |
+ sudo apt-get install libtidy-dev
+ python -m pip install --upgrade pip tox coverage codecov
+ - name: Run tox
+ run: python -m tox
+ - name: Upload Results
+ if: success()
+ uses: codecov/codecov-action@v1
+ with:
+ file: ./coverage.xml
+ flags: unittests
+ name: ${{ matrix.tox-env }}
+ fail_ci_if_error: false
+
+ lint:
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ max-parallel: 4
+ matrix:
+ tox-env: [flake8, pep517check, checkspelling]
+
+ env:
+ TOXENV: ${{ matrix.tox-env }}
+
+ steps:
+ - uses: actions/checkout@v2
+ - name: Setup Python
+ uses: actions/setup-python@v2
+ with:
+ python-version: 3.7
+ - name: Install dependencies
+ run: |
+ python -m pip install --upgrade pip tox
+ if [[ "$TOXENV" == 'checkspelling' ]]; then sudo apt-get install aspell aspell-en; fi
+ - name: Run tox
+ run: python -m tox
diff --git a/.gitignore b/.gitignore
index 0238e63..6de88e3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,74 @@
-*.pyc
-*.bak
-*.tmp
-*.swp
-tmp/*
-build/*
-dist/*
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+env/
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*,cover
+.hypothesis/
+test-output.html
+
+# Translations
+*.mo
+*.pot
+
+# Scrapy stuff:
+.scrapy
+
+# PyBuilder
+target/
+
+# IPython Notebook
+.ipynb_checkpoints
+
+# pyenv
+.python-version
+
+# virtualenv
+venv/
+ENV/
+
+# MkDocs documentation
+site/
+
+# Mac files
+.DS_Store
diff --git a/.spell-dict b/.spell-dict
new file mode 100644
index 0000000..6408100
--- /dev/null
+++ b/.spell-dict
@@ -0,0 +1,163 @@
+facelessuser
+mitya
+waylan
+Abrahamsen
+Altmayer
+API
+Artem
+aspell
+Babelmark
+backtick
+backticks
+Balogh
+BlockParser
+Blockprocessor
+Blockprocessors
+blockquote
+blockquotes
+boolean
+CamelCase
+Chodarev
+CLI
+CodeHilite
+codehilite
+Cogumbreiro
+convertFile
+CSS
+dedent
+deliminators
+deregister
+Dmitry
+docdata
+ElementTree
+encodings
+extendMarkdown
+Fauske
+formatter
+Fortin
+GitHub
+globals
+Gruber
+GSoC
+hacky
+HeaderId
+HTTPS
+html
+implementers
+InlineProcessor
+Jiryu
+JSON
+Kjell
+Krech
+kwargs
+Limberg
+MacOS
+Magne
+MAILTO
+makeExtension
+Manfed
+markdownFromFile
+Maruku
+md
+metadata
+MkDocs
+multi
+MultiMarkdown
+munge
+namespace
+NanoDOM
+Neale
+nosetests
+OrderedDict
+OrderedDicts
+OSX
+ol
+Ph
+PHP
+Posix
+postprocessor
+postprocessors
+prepend
+prepended
+preprocessor
+preprocessors
+Pygments
+PyPI
+PyPy
+PYTHONPATH
+PyTidyLib
+PyYAML
+rc
+refactor
+refactored
+refactors
+registerExtension
+richeland
+RSS
+rST
+ryneeverett
+sanitizer
+sanitizers
+Sauder
+schemeless
+setuptools
+Sergej
+serializer
+serializers
+Shachnev
+sitemap
+slugify
+SmartyPants
+Sourceforge
+StackOverflow
+Stansifer
+stdout
+Stelios
+Stienstra
+subclasses
+SuperFences
+svn
+Swartz
+Szakmeister
+Takteyev
+Tiago
+toc
+tokenized
+tox
+Trac
+traceback
+Tredinnick
+Treeprocessor
+Treeprocessors
+tuple
+tuples
+unclosed
+unescape
+unescaping
+unittest
+unordered
+untrusted
+UTF
+uTidylib
+versa
+versioning
+Waylan
+whitelist
+whitespace
+WikiLink
+WikiLinks
+Wolever
+workflow
+Xanthakis
+XHTML
+xhtml
+YAML
+Yunusov
+inline
+wiki
+JavaScript
+plugin
+plugins
+configs
+pre
+formatters
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000..a30e62f
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,49 @@
+# Contributor Code of Conduct
+
+As contributors and maintainers of this project, and in the interest of
+fostering an open and welcoming community, we pledge to respect all people who
+contribute through reporting issues, posting feature requests, updating
+documentation, submitting pull requests or patches, and other activities.
+
+We are committed to making participation in this project a harassment-free
+experience for everyone, regardless of level of experience, gender, gender
+identity and expression, sexual orientation, disability, personal appearance,
+body size, race, ethnicity, age, religion, or nationality.
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery
+* Personal attacks
+* Trolling or insulting/derogatory comments
+* Public or private harassment
+* Publishing other's private information, such as physical or electronic
+ addresses, without explicit permission
+* Other unethical or unprofessional conduct
+
+Project maintainers have the right and responsibility to remove, edit, or
+reject comments, commits, code, wiki edits, issues, and other contributions
+that are not aligned to this Code of Conduct, or to ban temporarily or
+permanently any contributor for other behaviors that they deem inappropriate,
+threatening, offensive, or harmful.
+
+By adopting this Code of Conduct, project maintainers commit themselves to
+fairly and consistently applying these principles to every aspect of managing
+this project. Project maintainers who do not follow or enforce the Code of
+Conduct may be permanently removed from the project team.
+
+This Code of Conduct applies both within project spaces and in public spaces
+when an individual is representing the project or its community.
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported by contacting a project maintainer at python.markdown@gmail.com. All
+complaints will be reviewed and investigated and will result in a response that
+is deemed necessary and appropriate to the circumstances. Maintainers are
+obligated to maintain confidentiality with regard to the reporter of an
+incident.
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage],
+version 1.3.0, available at
+[https://www.contributor-covenant.org/version/1/3/0/][version]
+
+[homepage]: https://www.contributor-covenant.org/
+[version]: https://www.contributor-covenant.org/version/1/3/0/
diff --git a/INSTALL.md b/INSTALL.md
new file mode 100644
index 0000000..a314fb6
--- /dev/null
+++ b/INSTALL.md
@@ -0,0 +1,9 @@
+Installing Python-Markdown
+==========================
+
+As an Admin/Root user on your system do:
+
+ pip install markdown
+
+Or for more specific instructions, view the documentation in `docs/install.md`
+or on the website at <https://Python-Markdown.github.io/install/>.
diff --git a/docs/LICENSE b/LICENSE.md
index 4cd8b14..2652d97 100644
--- a/docs/LICENSE
+++ b/LICENSE.md
@@ -1,20 +1,20 @@
-Copyright 2007, 2008 The Python Markdown Project (v. 1.7 and later)
-Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
-Copyright 2004 Manfred Stienstra (the original version)
+Copyright 2007, 2008 The Python Markdown Project (v. 1.7 and later)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
-
-* Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-* Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-* Neither the name of the <organization> nor the
- names of its contributors may be used to endorse or promote products
- derived from this software without specific prior written permission.
+
+* Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+* Neither the name of the Python Markdown Project nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE PYTHON MARKDOWN PROJECT ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -27,4 +27,3 @@ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
-
diff --git a/MANIFEST.in b/MANIFEST.in
index 4558938..4d3c6a2 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,6 +1,12 @@
-recursive-include bin *
recursive-include markdown *.py
recursive-include docs *
-prune markdown/extensions/legacy.py
+recursive-include tests *.txt *.html *.py
include setup.py
+include setup.cfg
+include makefile
+include LICENSE.md
+include README.md
+include INSTALL.md
include MANIFEST
+include *-requirements.txt
+include mkdocs.yml
diff --git a/METADATA b/METADATA
index f01d58a..3897cf4 100644
--- a/METADATA
+++ b/METADATA
@@ -3,7 +3,7 @@
# For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md
name: "markdown"
-description: "This is a Python implementation of John Gruber's Markdown. It is almost completely compliant with the reference implementation, though there are a few known issues."
+description: "This is a Python implementation of John Gruber\'s Markdown. It is almost completely compliant with the reference implementation, though there are a few known issues."
third_party {
url {
type: HOMEPAGE
@@ -11,13 +11,13 @@ third_party {
}
url {
type: ARCHIVE
- value: "https://github.com/Python-Markdown/markdown/archive/refs/tags/2.0.3.zip"
+ value: "https://github.com/Python-Markdown/markdown/archive/3.4.1.zip"
}
- version: "2.0.3"
+ version: "3.4.1"
license_type: NOTICE
last_upgrade_date {
year: 2022
month: 11
- day: 3
+ day: 4
}
}
diff --git a/MarkdownTest/MarkdownTest.pl b/MarkdownTest/MarkdownTest.pl
deleted file mode 100755
index 8e7048f..0000000
--- a/MarkdownTest/MarkdownTest.pl
+++ /dev/null
@@ -1,165 +0,0 @@
-#!/usr/bin/perl
-
-#
-# MarkdownTester -- Run tests for Markdown implementations
-#
-# Copyright (c) 2004-2005 John Gruber
-# <http://daringfireball.net/projects/markdown/>
-#
-
-use strict;
-use warnings;
-use Getopt::Long;
-use Benchmark;
-
-our $VERSION = '1.0.2';
-# Sat 24 Dec 2005
-
-my $time_start = new Benchmark;
-my $test_dir = "Tests";
-my $script = "./Markdown.pl";
-my $use_tidy = 0;
-my ($flag_version);
-
-GetOptions (
- "script=s" => \$script,
- "testdir=s" => \$test_dir,
- "tidy" => \$use_tidy,
- "version" => \$flag_version,
- );
-
-if($flag_version) {
- my $progname = $0;
- $progname =~ s{.*/}{};
- die "$progname version $VERSION\n";
-}
-
-unless (-d $test_dir) { die "'$test_dir' is not a directory.\n"; }
-unless (-f $script) { die "$script does not exist.\n"; }
-unless (-x $script) { die "$script is not executable.\n"; }
-
-my $tests_passed = 0;
-my $tests_failed = 0;
-
-TEST:
-foreach my $testfile (glob "$test_dir/*.text") {
- my $testname = $testfile;
- $testname =~ s{.*/(.+)\.text$}{$1}i;
- print "$testname ... ";
-
- # Look for a corresponding .html file for each .text file:
- my $resultfile = $testfile;
- $resultfile =~ s{\.text$}{\.html}i;
- unless (-f $resultfile) {
- print "'$resultfile' does not exist.\n\n";
- next TEST;
- }
-
- # open(TEST, $testfile) || die("Can't open testfile: $!");
- open(RESULT, $resultfile) || die("Can't open resultfile: $!");
- undef $/;
- # my $t_input = <TEST>;
- my $t_result = <RESULT>;
-
- my $t_output = `'$script' '$testfile'`;
-
- # Normalize the output and expected result strings:
- $t_result =~ s/\s+\z//; # trim trailing whitespace
- $t_output =~ s/\s+\z//; # trim trailing whitespace
- if ($use_tidy) {
- # Escape the strings, pass them through to CLI tidy tool for tag-level equivalency
- $t_result =~ s{'}{'\\''}g; # escape ' chars for shell
- $t_output =~ s{'}{'\\''}g;
- $t_result = `echo '$t_result' | tidy -quiet --show-warnings n`;
- $t_output = `echo '$t_output' | tidy -quiet --show-warnings n`;
- }
-
- if ($t_output eq $t_result) {
- print "OK\n";
- $tests_passed++;
- }
- else {
- print "FAILED\n\n";
- $tests_failed++;
- }
-}
-
-print "\n\n";
-print "$tests_passed passed; $tests_failed failed.\n";
-
-my $time_end = new Benchmark;
-my $time_diff = timediff($time_end, $time_start);
-print "Benchmark: ", timestr($time_diff), "\n";
-
-
-__END__
-
-=pod
-
-=head1 NAME
-
-B<MarkdownTest>
-
-
-=head1 SYNOPSIS
-
-B<MarkdownTest.pl> [ B<--options> ] [ I<file> ... ]
-
-
-=head1 DESCRIPTION
-
-
-=head1 OPTIONS
-
-Use "--" to end switch parsing. For example, to open a file named "-z", use:
-
- MarkdownTest.pl -- -z
-
-=over 4
-
-=item B<--script>
-
-Specify the path to the Markdown script to test. Defaults to
-"./Markdown.pl". Example:
-
- ./MarkdownTest.pl --script ./PHP-Markdown/php-markdown
-
-=item B<--testdir>
-
-Specify the path to a directory containing test data. Defaults to "Tests".
-
-=item B<--tidy>
-
-Flag to turn on using the command line 'tidy' tool to normalize HTML
-output before comparing script output to the expected test result.
-Assumes that the 'tidy' command is available in your PATH. Defaults to
-off.
-
-=back
-
-
-
-=head1 BUGS
-
-
-
-=head1 VERSION HISTORY
-
-1.0 Mon 13 Dec 2004-2005
-
-1.0.1 Mon 19 Sep 2005
-
- + Better handling of case when foo.text exists, but foo.html doesn't.
- It now prints a message and moves on, rather than dying.
-
-
-=head1 COPYRIGHT AND LICENSE
-
-Copyright (c) 2004-2005 John Gruber
-<http://daringfireball.net/>
-All rights reserved.
-
-This is free software; you may redistribute it and/or modify it under
-the same terms as Perl itself.
-
-=cut
diff --git a/MarkdownTest/Tests_2004/Amps and angle encoding.text-out b/MarkdownTest/Tests_2004/Amps and angle encoding.text-out
deleted file mode 100644
index d52a97e..0000000
--- a/MarkdownTest/Tests_2004/Amps and angle encoding.text-out
+++ /dev/null
@@ -1,21 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
-<html>
-<head>
-<meta name="generator" content=
-"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org">
-<title></title>
-</head>
-<body>
-<p>AT&amp;T has an ampersand in their name.</p>
-<p>AT&amp;T is another way to write it.</p>
-<p>This &amp; that.</p>
-<p>4 &lt; 5.</p>
-<p>6 &gt; 5.</p>
-<p>Here's a <a href="http://example.com/?foo=1&amp;bar=2">link</a>
-with an ampersand in the URL.</p>
-<p>Here's a link with an amersand in the link text: <a href=
-"http://att.com/" title="AT&amp;T">AT&amp;T</a>.</p>
-<p>Here's an inline <a href="/script?foo=1&amp;bar=2">link</a>.</p>
-<p>Here's an inline <a href="/script?foo=1&amp;bar=2">link</a>.</p>
-</body>
-</html>
diff --git a/MarkdownTest/Tests_2004/Amps and angle encoding.text-res b/MarkdownTest/Tests_2004/Amps and angle encoding.text-res
deleted file mode 100644
index d52a97e..0000000
--- a/MarkdownTest/Tests_2004/Amps and angle encoding.text-res
+++ /dev/null
@@ -1,21 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
-<html>
-<head>
-<meta name="generator" content=
-"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org">
-<title></title>
-</head>
-<body>
-<p>AT&amp;T has an ampersand in their name.</p>
-<p>AT&amp;T is another way to write it.</p>
-<p>This &amp; that.</p>
-<p>4 &lt; 5.</p>
-<p>6 &gt; 5.</p>
-<p>Here's a <a href="http://example.com/?foo=1&amp;bar=2">link</a>
-with an ampersand in the URL.</p>
-<p>Here's a link with an amersand in the link text: <a href=
-"http://att.com/" title="AT&amp;T">AT&amp;T</a>.</p>
-<p>Here's an inline <a href="/script?foo=1&amp;bar=2">link</a>.</p>
-<p>Here's an inline <a href="/script?foo=1&amp;bar=2">link</a>.</p>
-</body>
-</html>
diff --git a/MarkdownTest/Tests_2004/Auto links.text-out b/MarkdownTest/Tests_2004/Auto links.text-out
deleted file mode 100644
index 3b20890..0000000
--- a/MarkdownTest/Tests_2004/Auto links.text-out
+++ /dev/null
@@ -1,28 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
-<html>
-<head>
-<meta name="generator" content=
-"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org">
-<title></title>
-</head>
-<body>
-<p>Link: <a href="http://example.com/">http://example.com/</a>.</p>
-<p>With an ampersand: <a href=
-"http://example.com/?foo=1&amp;bar=2">http://example.com/?foo=1&amp;bar=2</a></p>
-<ul>
-<li>In a list?</li>
-<li><a href="http://example.com/">http://example.com/</a></li>
-<li>It should.</li>
-</ul>
-<blockquote>
-<p>Blockquoted: <a href=
-"http://example.com/">http://example.com/</a></p>
-</blockquote>
-<p>Auto-links should not occur here:
-<code>&lt;http://example.com/&gt;</code></p>
-<pre>
-<code>or here: &lt;http://example.com/&gt;
-</code>
-</pre>
-</body>
-</html>
diff --git a/MarkdownTest/Tests_2004/Auto links.text-res b/MarkdownTest/Tests_2004/Auto links.text-res
deleted file mode 100644
index 3b20890..0000000
--- a/MarkdownTest/Tests_2004/Auto links.text-res
+++ /dev/null
@@ -1,28 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
-<html>
-<head>
-<meta name="generator" content=
-"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org">
-<title></title>
-</head>
-<body>
-<p>Link: <a href="http://example.com/">http://example.com/</a>.</p>
-<p>With an ampersand: <a href=
-"http://example.com/?foo=1&amp;bar=2">http://example.com/?foo=1&amp;bar=2</a></p>
-<ul>
-<li>In a list?</li>
-<li><a href="http://example.com/">http://example.com/</a></li>
-<li>It should.</li>
-</ul>
-<blockquote>
-<p>Blockquoted: <a href=
-"http://example.com/">http://example.com/</a></p>
-</blockquote>
-<p>Auto-links should not occur here:
-<code>&lt;http://example.com/&gt;</code></p>
-<pre>
-<code>or here: &lt;http://example.com/&gt;
-</code>
-</pre>
-</body>
-</html>
diff --git a/MarkdownTest/Tests_2004/Backslash escapes.text-out b/MarkdownTest/Tests_2004/Backslash escapes.text-out
deleted file mode 100644
index 1aae6cc..0000000
--- a/MarkdownTest/Tests_2004/Backslash escapes.text-out
+++ /dev/null
@@ -1,79 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
-<html>
-<head>
-<meta name="generator" content=
-"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org">
-<title></title>
-</head>
-<body>
-<p>These should all get escaped:</p>
-<p>Backslash: \</p>
-<p>Backtick: `</p>
-<p>Asterisk: *</p>
-<p>Underscore: _</p>
-<p>Left brace: {</p>
-<p>Right brace: }</p>
-<p>Left bracket: [</p>
-<p>Right bracket: ]</p>
-<p>Left paren: (</p>
-<p>Right paren: )</p>
-<p>Greater-than: &gt;</p>
-<p>Hash: #</p>
-<p>Period: .</p>
-<p>Bang: !</p>
-<p>Plus: +</p>
-<p>Minus: -</p>
-<p>These should not, because they occur within a code block:</p>
-<pre>
-<code>Backslash: \
-
-Backtick: \`
-
-Asterisk: \*
-
-Underscore: \_
-
-Left brace: \{
-
-Right brace: \}
-
-Left bracket: \[
-
-Right bracket: \]
-
-Left paren: \(
-
-Right paren: \)
-
-Greater-than: \&gt;
-
-Hash: \#
-
-Period: \.
-
-Bang: \!
-
-Plus: \+
-
-Minus: \-
-</code>
-</pre>
-<p>Nor should these, which occur in code spans:</p>
-<p>Backslash: <code>\</code></p>
-<p>Backtick: <code>\`</code></p>
-<p>Asterisk: <code>\*</code></p>
-<p>Underscore: <code>\_</code></p>
-<p>Left brace: <code>\{</code></p>
-<p>Right brace: <code>\}</code></p>
-<p>Left bracket: <code>\[</code></p>
-<p>Right bracket: <code>\]</code></p>
-<p>Left paren: <code>\(</code></p>
-<p>Right paren: <code>\)</code></p>
-<p>Greater-than: <code>\&gt;</code></p>
-<p>Hash: <code>\#</code></p>
-<p>Period: <code>\.</code></p>
-<p>Bang: <code>\!</code></p>
-<p>Plus: <code>\+</code></p>
-<p>Minus: <code>\-</code></p>
-</body>
-</html>
diff --git a/MarkdownTest/Tests_2004/Backslash escapes.text-res b/MarkdownTest/Tests_2004/Backslash escapes.text-res
deleted file mode 100644
index 1aae6cc..0000000
--- a/MarkdownTest/Tests_2004/Backslash escapes.text-res
+++ /dev/null
@@ -1,79 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
-<html>
-<head>
-<meta name="generator" content=
-"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org">
-<title></title>
-</head>
-<body>
-<p>These should all get escaped:</p>
-<p>Backslash: \</p>
-<p>Backtick: `</p>
-<p>Asterisk: *</p>
-<p>Underscore: _</p>
-<p>Left brace: {</p>
-<p>Right brace: }</p>
-<p>Left bracket: [</p>
-<p>Right bracket: ]</p>
-<p>Left paren: (</p>
-<p>Right paren: )</p>
-<p>Greater-than: &gt;</p>
-<p>Hash: #</p>
-<p>Period: .</p>
-<p>Bang: !</p>
-<p>Plus: +</p>
-<p>Minus: -</p>
-<p>These should not, because they occur within a code block:</p>
-<pre>
-<code>Backslash: \
-
-Backtick: \`
-
-Asterisk: \*
-
-Underscore: \_
-
-Left brace: \{
-
-Right brace: \}
-
-Left bracket: \[
-
-Right bracket: \]
-
-Left paren: \(
-
-Right paren: \)
-
-Greater-than: \&gt;
-
-Hash: \#
-
-Period: \.
-
-Bang: \!
-
-Plus: \+
-
-Minus: \-
-</code>
-</pre>
-<p>Nor should these, which occur in code spans:</p>
-<p>Backslash: <code>\</code></p>
-<p>Backtick: <code>\`</code></p>
-<p>Asterisk: <code>\*</code></p>
-<p>Underscore: <code>\_</code></p>
-<p>Left brace: <code>\{</code></p>
-<p>Right brace: <code>\}</code></p>
-<p>Left bracket: <code>\[</code></p>
-<p>Right bracket: <code>\]</code></p>
-<p>Left paren: <code>\(</code></p>
-<p>Right paren: <code>\)</code></p>
-<p>Greater-than: <code>\&gt;</code></p>
-<p>Hash: <code>\#</code></p>
-<p>Period: <code>\.</code></p>
-<p>Bang: <code>\!</code></p>
-<p>Plus: <code>\+</code></p>
-<p>Minus: <code>\-</code></p>
-</body>
-</html>
diff --git a/MarkdownTest/Tests_2004/Blockquotes with code blocks.text-out b/MarkdownTest/Tests_2004/Blockquotes with code blocks.text-out
deleted file mode 100644
index 75ef055..0000000
--- a/MarkdownTest/Tests_2004/Blockquotes with code blocks.text-out
+++ /dev/null
@@ -1,25 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
-<html>
-<head>
-<meta name="generator" content=
-"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org">
-<title></title>
-</head>
-<body>
-<blockquote>
-<p>Example:</p>
-<pre>
-<code>sub status {
- print "working";
-}
-</code>
-</pre>
-<p>Or:</p>
-<pre>
-<code>sub status {
- return "working";
-}
-</code>
-</pre></blockquote>
-</body>
-</html>
diff --git a/MarkdownTest/Tests_2004/Blockquotes with code blocks.text-res b/MarkdownTest/Tests_2004/Blockquotes with code blocks.text-res
deleted file mode 100644
index 75ef055..0000000
--- a/MarkdownTest/Tests_2004/Blockquotes with code blocks.text-res
+++ /dev/null
@@ -1,25 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
-<html>
-<head>
-<meta name="generator" content=
-"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org">
-<title></title>
-</head>
-<body>
-<blockquote>
-<p>Example:</p>
-<pre>
-<code>sub status {
- print "working";
-}
-</code>
-</pre>
-<p>Or:</p>
-<pre>
-<code>sub status {
- return "working";
-}
-</code>
-</pre></blockquote>
-</body>
-</html>
diff --git a/MarkdownTest/Tests_2004/Hard-wrapped paragraphs with list-like lines.text-out b/MarkdownTest/Tests_2004/Hard-wrapped paragraphs with list-like lines.text-out
deleted file mode 100644
index e044b46..0000000
--- a/MarkdownTest/Tests_2004/Hard-wrapped paragraphs with list-like lines.text-out
+++ /dev/null
@@ -1,14 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
-<html>
-<head>
-<meta name="generator" content=
-"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org">
-<title></title>
-</head>
-<body>
-<p>In Markdown 1.0.0 and earlier. Version 8. This line turns into a
-list item. Because a hard-wrapped line in the middle of a paragraph
-looked like a list item.</p>
-<p>Here's one with a bullet. * criminey.</p>
-</body>
-</html>
diff --git a/MarkdownTest/Tests_2004/Hard-wrapped paragraphs with list-like lines.text-res b/MarkdownTest/Tests_2004/Hard-wrapped paragraphs with list-like lines.text-res
deleted file mode 100644
index e044b46..0000000
--- a/MarkdownTest/Tests_2004/Hard-wrapped paragraphs with list-like lines.text-res
+++ /dev/null
@@ -1,14 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
-<html>
-<head>
-<meta name="generator" content=
-"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org">
-<title></title>
-</head>
-<body>
-<p>In Markdown 1.0.0 and earlier. Version 8. This line turns into a
-list item. Because a hard-wrapped line in the middle of a paragraph
-looked like a list item.</p>
-<p>Here's one with a bullet. * criminey.</p>
-</body>
-</html>
diff --git a/MarkdownTest/Tests_2004/Horizontal rules.text-out b/MarkdownTest/Tests_2004/Horizontal rules.text-out
deleted file mode 100644
index 71e4d27..0000000
--- a/MarkdownTest/Tests_2004/Horizontal rules.text-out
+++ /dev/null
@@ -1,61 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
-<html>
-<head>
-<meta name="generator" content=
-"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org">
-<title></title>
-</head>
-<body>
-<p>Dashes:</p>
-<hr>
-<hr>
-<hr>
-<hr>
-<pre>
-<code>---
-</code>
-</pre>
-<hr>
-<hr>
-<hr>
-<hr>
-<pre>
-<code>- - -
-</code>
-</pre>
-<p>Asterisks:</p>
-<hr>
-<hr>
-<hr>
-<hr>
-<pre>
-<code>***
-</code>
-</pre>
-<hr>
-<hr>
-<hr>
-<hr>
-<pre>
-<code>* * *
-</code>
-</pre>
-<p>Underscores:</p>
-<hr>
-<hr>
-<hr>
-<hr>
-<pre>
-<code>___
-</code>
-</pre>
-<hr>
-<hr>
-<hr>
-<hr>
-<pre>
-<code>_ _ _
-</code>
-</pre>
-</body>
-</html>
diff --git a/MarkdownTest/Tests_2004/Horizontal rules.text-res b/MarkdownTest/Tests_2004/Horizontal rules.text-res
deleted file mode 100644
index 71e4d27..0000000
--- a/MarkdownTest/Tests_2004/Horizontal rules.text-res
+++ /dev/null
@@ -1,61 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
-<html>
-<head>
-<meta name="generator" content=
-"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org">
-<title></title>
-</head>
-<body>
-<p>Dashes:</p>
-<hr>
-<hr>
-<hr>
-<hr>
-<pre>
-<code>---
-</code>
-</pre>
-<hr>
-<hr>
-<hr>
-<hr>
-<pre>
-<code>- - -
-</code>
-</pre>
-<p>Asterisks:</p>
-<hr>
-<hr>
-<hr>
-<hr>
-<pre>
-<code>***
-</code>
-</pre>
-<hr>
-<hr>
-<hr>
-<hr>
-<pre>
-<code>* * *
-</code>
-</pre>
-<p>Underscores:</p>
-<hr>
-<hr>
-<hr>
-<hr>
-<pre>
-<code>___
-</code>
-</pre>
-<hr>
-<hr>
-<hr>
-<hr>
-<pre>
-<code>_ _ _
-</code>
-</pre>
-</body>
-</html>
diff --git a/MarkdownTest/Tests_2004/Inline HTML (Advanced).text-out b/MarkdownTest/Tests_2004/Inline HTML (Advanced).text-out
deleted file mode 100644
index ee84e31..0000000
--- a/MarkdownTest/Tests_2004/Inline HTML (Advanced).text-out
+++ /dev/null
@@ -1,19 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
-<html>
-<head>
-<meta name="generator" content=
-"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org">
-<title></title>
-</head>
-<body>
-<p>Simple block on one line:</p>
-<div>foo</div>
-<p>And nested without indentation:</p>
-<div>
-<div>
-<div>foo</div>
-</div>
-<div>bar</div>
-</div>
-</body>
-</html>
diff --git a/MarkdownTest/Tests_2004/Inline HTML (Advanced).text-res b/MarkdownTest/Tests_2004/Inline HTML (Advanced).text-res
deleted file mode 100644
index ee84e31..0000000
--- a/MarkdownTest/Tests_2004/Inline HTML (Advanced).text-res
+++ /dev/null
@@ -1,19 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
-<html>
-<head>
-<meta name="generator" content=
-"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org">
-<title></title>
-</head>
-<body>
-<p>Simple block on one line:</p>
-<div>foo</div>
-<p>And nested without indentation:</p>
-<div>
-<div>
-<div>foo</div>
-</div>
-<div>bar</div>
-</div>
-</body>
-</html>
diff --git a/MarkdownTest/Tests_2004/Inline HTML (Simple).text-out b/MarkdownTest/Tests_2004/Inline HTML (Simple).text-out
deleted file mode 100644
index a5022e0..0000000
--- a/MarkdownTest/Tests_2004/Inline HTML (Simple).text-out
+++ /dev/null
@@ -1,59 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
-<html>
-<head>
-<meta name="generator" content=
-"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org">
-<title></title>
-</head>
-<body>
-<p>Here's a simple block:</p>
-<div>foo</div>
-<p>This should be a code block, though:</p>
-<pre>
-<code>&lt;div&gt;
- foo
-&lt;/div&gt;
-</code>
-</pre>
-<p>As should this:</p>
-<pre>
-<code>&lt;div&gt;foo&lt;/div&gt;
-</code>
-</pre>
-<p>Now, nested:</p>
-<div>
-<div>
-<div>foo</div>
-</div>
-</div>
-<p>This should just be an HTML comment:</p>
-<!-- Comment -->
-<p>Multiline:</p>
-<!--
-Blah
-Blah
--->
-<p>Code block:</p>
-<pre>
-<code>&lt;!-- Comment --&gt;
-</code>
-</pre>
-<p>Just plain comment, with trailing spaces on the line:</p>
-<!-- foo -->
-<p>Code:</p>
-<pre>
-<code>&lt;hr /&gt;
-</code>
-</pre>
-<p>Hr's:</p>
-<hr>
-<hr>
-<hr>
-<hr>
-<hr>
-<hr>
-<hr class="foo" id="bar">
-<hr class="foo" id="bar">
-<hr class="foo" id="bar">
-</body>
-</html>
diff --git a/MarkdownTest/Tests_2004/Inline HTML (Simple).text-res b/MarkdownTest/Tests_2004/Inline HTML (Simple).text-res
deleted file mode 100644
index a5022e0..0000000
--- a/MarkdownTest/Tests_2004/Inline HTML (Simple).text-res
+++ /dev/null
@@ -1,59 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
-<html>
-<head>
-<meta name="generator" content=
-"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org">
-<title></title>
-</head>
-<body>
-<p>Here's a simple block:</p>
-<div>foo</div>
-<p>This should be a code block, though:</p>
-<pre>
-<code>&lt;div&gt;
- foo
-&lt;/div&gt;
-</code>
-</pre>
-<p>As should this:</p>
-<pre>
-<code>&lt;div&gt;foo&lt;/div&gt;
-</code>
-</pre>
-<p>Now, nested:</p>
-<div>
-<div>
-<div>foo</div>
-</div>
-</div>
-<p>This should just be an HTML comment:</p>
-<!-- Comment -->
-<p>Multiline:</p>
-<!--
-Blah
-Blah
--->
-<p>Code block:</p>
-<pre>
-<code>&lt;!-- Comment --&gt;
-</code>
-</pre>
-<p>Just plain comment, with trailing spaces on the line:</p>
-<!-- foo -->
-<p>Code:</p>
-<pre>
-<code>&lt;hr /&gt;
-</code>
-</pre>
-<p>Hr's:</p>
-<hr>
-<hr>
-<hr>
-<hr>
-<hr>
-<hr>
-<hr class="foo" id="bar">
-<hr class="foo" id="bar">
-<hr class="foo" id="bar">
-</body>
-</html>
diff --git a/MarkdownTest/Tests_2004/Inline HTML comments.text-out b/MarkdownTest/Tests_2004/Inline HTML comments.text-out
deleted file mode 100644
index 6e2f425..0000000
--- a/MarkdownTest/Tests_2004/Inline HTML comments.text-out
+++ /dev/null
@@ -1,18 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
-<html>
-<head>
-<meta name="generator" content=
-"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org">
-<title></title>
-</head>
-<body>
-<p>Paragraph one.</p>
-<!-- This is a simple comment -->
-<!--
- This is another comment.
--->
-<p>Paragraph two.</p>
-<!-- one comment block == == with two comments -->
-<p>The end.</p>
-</body>
-</html>
diff --git a/MarkdownTest/Tests_2004/Inline HTML comments.text-res b/MarkdownTest/Tests_2004/Inline HTML comments.text-res
deleted file mode 100644
index 6e2f425..0000000
--- a/MarkdownTest/Tests_2004/Inline HTML comments.text-res
+++ /dev/null
@@ -1,18 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
-<html>
-<head>
-<meta name="generator" content=
-"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org">
-<title></title>
-</head>
-<body>
-<p>Paragraph one.</p>
-<!-- This is a simple comment -->
-<!--
- This is another comment.
--->
-<p>Paragraph two.</p>
-<!-- one comment block == == with two comments -->
-<p>The end.</p>
-</body>
-</html>
diff --git a/MarkdownTest/Tests_2004/Links, inline style.text-out b/MarkdownTest/Tests_2004/Links, inline style.text-out
deleted file mode 100644
index 0125b63..0000000
--- a/MarkdownTest/Tests_2004/Links, inline style.text-out
+++ /dev/null
@@ -1,17 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
-<html>
-<head>
-<meta name="generator" content=
-"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org">
-<title></title>
-</head>
-<body>
-<p>Just a <a href="/url/">URL</a>.</p>
-<p><a href="/url/" title="title">URL and title</a>.</p>
-<p><a href="/url/" title="title preceded by two spaces">URL and
-title</a>.</p>
-<p><a href="/url/" title="title preceded by a tab">URL and
-title</a>.</p>
-<p><a href="">Empty</a>.</p>
-</body>
-</html>
diff --git a/MarkdownTest/Tests_2004/Links, inline style.text-res b/MarkdownTest/Tests_2004/Links, inline style.text-res
deleted file mode 100644
index 0125b63..0000000
--- a/MarkdownTest/Tests_2004/Links, inline style.text-res
+++ /dev/null
@@ -1,17 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
-<html>
-<head>
-<meta name="generator" content=
-"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org">
-<title></title>
-</head>
-<body>
-<p>Just a <a href="/url/">URL</a>.</p>
-<p><a href="/url/" title="title">URL and title</a>.</p>
-<p><a href="/url/" title="title preceded by two spaces">URL and
-title</a>.</p>
-<p><a href="/url/" title="title preceded by a tab">URL and
-title</a>.</p>
-<p><a href="">Empty</a>.</p>
-</body>
-</html>
diff --git a/MarkdownTest/Tests_2004/Links, reference style.text-out b/MarkdownTest/Tests_2004/Links, reference style.text-out
deleted file mode 100644
index 04ae0cd..0000000
--- a/MarkdownTest/Tests_2004/Links, reference style.text-out
+++ /dev/null
@@ -1,22 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
-<html>
-<head>
-<meta name="generator" content=
-"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org">
-<title></title>
-</head>
-<body>
-<p>Foo <a href="/url/" title="Title">bar</a>.</p>
-<p>Foo <a href="/url/" title="Title">bar</a>.</p>
-<p>Foo <a href="/url/" title="Title">bar</a>.</p>
-<p>With <a href="/url/">embedded [brackets]</a>.</p>
-<p>Indented <a href="/url">once</a>.</p>
-<p>Indented <a href="/url">twice</a>.</p>
-<p>Indented <a href="/url">thrice</a>.</p>
-<p>Indented [four][] times.</p>
-<pre>
-<code>[four]: /url
-</code>
-</pre>
-</body>
-</html>
diff --git a/MarkdownTest/Tests_2004/Links, reference style.text-res b/MarkdownTest/Tests_2004/Links, reference style.text-res
deleted file mode 100644
index 04ae0cd..0000000
--- a/MarkdownTest/Tests_2004/Links, reference style.text-res
+++ /dev/null
@@ -1,22 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
-<html>
-<head>
-<meta name="generator" content=
-"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org">
-<title></title>
-</head>
-<body>
-<p>Foo <a href="/url/" title="Title">bar</a>.</p>
-<p>Foo <a href="/url/" title="Title">bar</a>.</p>
-<p>Foo <a href="/url/" title="Title">bar</a>.</p>
-<p>With <a href="/url/">embedded [brackets]</a>.</p>
-<p>Indented <a href="/url">once</a>.</p>
-<p>Indented <a href="/url">twice</a>.</p>
-<p>Indented <a href="/url">thrice</a>.</p>
-<p>Indented [four][] times.</p>
-<pre>
-<code>[four]: /url
-</code>
-</pre>
-</body>
-</html>
diff --git a/MarkdownTest/Tests_2004/Links-in-Headers.text-out b/MarkdownTest/Tests_2004/Links-in-Headers.text-out
deleted file mode 100644
index defddbf..0000000
--- a/MarkdownTest/Tests_2004/Links-in-Headers.text-out
+++ /dev/null
@@ -1,9 +0,0 @@
-<h2>A plain header</h2>
-<p>Let's first have a plain header</p>
-<h1>An underlined header</h1>
-<p>(That's also useful)</p>
-<h1>A header with a <a href="http://www.link.com">link</a></h1>
-<p>First with a hash</p>
-<h2>Another with a <a href="http://www.link.com/">link</a></h2>
-<p>This time underlined</p>
-
diff --git a/MarkdownTest/Tests_2004/Links-in-Headers.text-res b/MarkdownTest/Tests_2004/Links-in-Headers.text-res
deleted file mode 100644
index cc6cfcf..0000000
--- a/MarkdownTest/Tests_2004/Links-in-Headers.text-res
+++ /dev/null
@@ -1,9 +0,0 @@
-<h2><span class="markdown">A plain header</span></h2>
-<p>Let's first have a plain header</p>
-<h1>An underlined header</h1>
-<p>(That's also useful)</p>
-<h1>A header with a <a href="http://www.link.com">link</a></h1>
-<p>First with a hash</p>
-<h2>Another with a <a href="http://www.link.com/">link</a></h2>
-<p>This time underlined</p>
-
diff --git a/MarkdownTest/Tests_2004/Literal quotes in titles.text-out b/MarkdownTest/Tests_2004/Literal quotes in titles.text-out
deleted file mode 100644
index 3fd6fbc..0000000
--- a/MarkdownTest/Tests_2004/Literal quotes in titles.text-out
+++ /dev/null
@@ -1,14 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
-<html>
-<head>
-<meta name="generator" content=
-"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org">
-<title></title>
-</head>
-<body>
-<p>Foo <a href="/url/" title=
-"Title with &quot;quotes&quot; inside">bar</a>.</p>
-<p>Foo <a href="/url/" title=
-"Title with &quot;quotes&quot; inside">bar</a>.</p>
-</body>
-</html>
diff --git a/MarkdownTest/Tests_2004/Literal quotes in titles.text-res b/MarkdownTest/Tests_2004/Literal quotes in titles.text-res
deleted file mode 100644
index 3fd6fbc..0000000
--- a/MarkdownTest/Tests_2004/Literal quotes in titles.text-res
+++ /dev/null
@@ -1,14 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
-<html>
-<head>
-<meta name="generator" content=
-"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org">
-<title></title>
-</head>
-<body>
-<p>Foo <a href="/url/" title=
-"Title with &quot;quotes&quot; inside">bar</a>.</p>
-<p>Foo <a href="/url/" title=
-"Title with &quot;quotes&quot; inside">bar</a>.</p>
-</body>
-</html>
diff --git a/MarkdownTest/Tests_2004/Markdown Documentation - Basics.text-out b/MarkdownTest/Tests_2004/Markdown Documentation - Basics.text-out
deleted file mode 100644
index 65b90fa..0000000
--- a/MarkdownTest/Tests_2004/Markdown Documentation - Basics.text-out
+++ /dev/null
@@ -1,321 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
-<html>
-<head>
-<meta name="generator" content=
-"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org">
-<title></title>
-</head>
-<body>
-<h1>Markdown: Basics</h1>
-<ul id="ProjectSubmenu">
-<li><a href="/projects/markdown/" title=
-"Markdown Project Page">Main</a></li>
-<li><a class="selected" title="Markdown Basics">Basics</a></li>
-<li><a href="/projects/markdown/syntax" title=
-"Markdown Syntax Documentation">Syntax</a></li>
-<li><a href="/projects/markdown/license" title=
-"Pricing and License Information">License</a></li>
-<li><a href="/projects/markdown/dingus" title=
-"Online Markdown Web Form">Dingus</a></li>
-</ul>
-<h2>Getting the Gist of Markdown's Formatting Syntax</h2>
-<p>This page offers a brief overview of what it's like to use
-Markdown. The <a href="/projects/markdown/syntax" title=
-"Markdown Syntax">syntax page</a> provides complete, detailed
-documentation for every feature, but Markdown should be very easy
-to pick up simply by looking at a few examples of it in action. The
-examples on this page are written in a before/after style, showing
-example syntax and the HTML output produced by Markdown.</p>
-<p>It's also helpful to simply try Markdown out; the <a href=
-"/projects/markdown/dingus" title="Markdown Dingus">Dingus</a> is a
-web application that allows you type your own Markdown-formatted
-text and translate it to XHTML.</p>
-<p><strong>Note:</strong> This document is itself written using
-Markdown; you can <a href="/projects/markdown/basics.text">see the
-source for it by adding '.text' to the URL</a>.</p>
-<h2>Paragraphs, Headers, Blockquotes</h2>
-<p>A paragraph is simply one or more consecutive lines of text,
-separated by one or more blank lines. (A blank line is any line
-that looks like a blank line -- a line containing nothing spaces or
-tabs is considered blank.) Normal paragraphs should not be intended
-with spaces or tabs.</p>
-<p>Markdown offers two styles of headers: <em>Setext</em> and
-<em>atx</em>. Setext-style headers for <code>&lt;h1&gt;</code> and
-<code>&lt;h2&gt;</code> are created by "underlining" with equal
-signs (<code>=</code>) and hyphens (<code>-</code>), respectively.
-To create an atx-style header, you put 1-6 hash marks
-(<code>#</code>) at the beginning of the line -- the number of
-hashes equals the resulting HTML header level.</p>
-<p>Blockquotes are indicated using email-style '<code>&gt;</code>'
-angle brackets.</p>
-<p>Markdown:</p>
-<pre>
-<code>A First Level Header
-====================
-
-A Second Level Header
----------------------
-
-Now is the time for all good men to come to
-the aid of their country. This is just a
-regular paragraph.
-
-The quick brown fox jumped over the lazy
-dog's back.
-
-### Header 3
-
-&gt; This is a blockquote.
-&gt;
-&gt; This is the second paragraph in the blockquote.
-&gt;
-&gt; ## This is an H2 in a blockquote
-</code>
-</pre>
-<p>Output:</p>
-<pre>
-<code>&lt;h1&gt;A First Level Header&lt;/h1&gt;
-
-&lt;h2&gt;A Second Level Header&lt;/h2&gt;
-
-&lt;p&gt;Now is the time for all good men to come to
-the aid of their country. This is just a
-regular paragraph.&lt;/p&gt;
-
-&lt;p&gt;The quick brown fox jumped over the lazy
-dog's back.&lt;/p&gt;
-
-&lt;h3&gt;Header 3&lt;/h3&gt;
-
-&lt;blockquote&gt;
- &lt;p&gt;This is a blockquote.&lt;/p&gt;
-
- &lt;p&gt;This is the second paragraph in the blockquote.&lt;/p&gt;
-
- &lt;h2&gt;This is an H2 in a blockquote&lt;/h2&gt;
-&lt;/blockquote&gt;
-</code>
-</pre>
-<h3>Phrase Emphasis</h3>
-<p>Markdown uses asterisks and underscores to indicate spans of
-emphasis.</p>
-<p>Markdown:</p>
-<pre>
-<code>Some of these words *are emphasized*.
-Some of these words _are emphasized also_.
-
-Use two asterisks for **strong emphasis**.
-Or, if you prefer, __use two underscores instead__.
-</code>
-</pre>
-<p>Output:</p>
-<pre>
-<code>&lt;p&gt;Some of these words &lt;em&gt;are emphasized&lt;/em&gt;.
-Some of these words &lt;em&gt;are emphasized also&lt;/em&gt;.&lt;/p&gt;
-
-&lt;p&gt;Use two asterisks for &lt;strong&gt;strong emphasis&lt;/strong&gt;.
-Or, if you prefer, &lt;strong&gt;use two underscores instead&lt;/strong&gt;.&lt;/p&gt;
-</code>
-</pre>
-<h2>Lists</h2>
-<p>Unordered (bulleted) lists use asterisks, pluses, and hyphens
-(<code>*</code>, <code>+</code>, and <code>-</code>) as list
-markers. These three markers are interchangable; this:</p>
-<pre>
-<code>* Candy.
-* Gum.
-* Booze.
-</code>
-</pre>
-<p>this:</p>
-<pre>
-<code>+ Candy.
-+ Gum.
-+ Booze.
-</code>
-</pre>
-<p>and this:</p>
-<pre>
-<code>- Candy.
-- Gum.
-- Booze.
-</code>
-</pre>
-<p>all produce the same output:</p>
-<pre>
-<code>&lt;ul&gt;
-&lt;li&gt;Candy.&lt;/li&gt;
-&lt;li&gt;Gum.&lt;/li&gt;
-&lt;li&gt;Booze.&lt;/li&gt;
-&lt;/ul&gt;
-</code>
-</pre>
-<p>Ordered (numbered) lists use regular numbers, followed by
-periods, as list markers:</p>
-<pre>
-<code>1. Red
-2. Green
-3. Blue
-</code>
-</pre>
-<p>Output:</p>
-<pre>
-<code>&lt;ol&gt;
-&lt;li&gt;Red&lt;/li&gt;
-&lt;li&gt;Green&lt;/li&gt;
-&lt;li&gt;Blue&lt;/li&gt;
-&lt;/ol&gt;
-</code>
-</pre>
-<p>If you put blank lines between items, you'll get
-<code>&lt;p&gt;</code> tags for the list item text. You can create
-multi-paragraph list items by indenting the paragraphs by 4 spaces
-or 1 tab:</p>
-<pre>
-<code>* A list item.
-
- With multiple paragraphs.
-
-* Another item in the list.
-</code>
-</pre>
-<p>Output:</p>
-<pre>
-<code>&lt;ul&gt;
-&lt;li&gt;&lt;p&gt;A list item.&lt;/p&gt;
-&lt;p&gt;With multiple paragraphs.&lt;/p&gt;&lt;/li&gt;
-&lt;li&gt;&lt;p&gt;Another item in the list.&lt;/p&gt;&lt;/li&gt;
-&lt;/ul&gt;
-</code>
-</pre>
-<h3>Links</h3>
-<p>Markdown supports two styles for creating links: <em>inline</em>
-and <em>reference</em>. With both styles, you use square brackets
-to delimit the text you want to turn into a link.</p>
-<p>Inline-style links use parentheses immediately after the link
-text. For example:</p>
-<pre>
-<code>This is an [example link](http://example.com/).
-</code>
-</pre>
-<p>Output:</p>
-<pre>
-<code>&lt;p&gt;This is an &lt;a href="http://example.com/"&gt;
-example link&lt;/a&gt;.&lt;/p&gt;
-</code>
-</pre>
-<p>Optionally, you may include a title attribute in the
-parentheses:</p>
-<pre>
-<code>This is an [example link](http://example.com/ "With a Title").
-</code>
-</pre>
-<p>Output:</p>
-<pre>
-<code>&lt;p&gt;This is an &lt;a href="http://example.com/" title="With a Title"&gt;
-example link&lt;/a&gt;.&lt;/p&gt;
-</code>
-</pre>
-<p>Reference-style links allow you to refer to your links by names,
-which you define elsewhere in your document:</p>
-<pre>
-<code>I get 10 times more traffic from [Google][1] than from
-[Yahoo][2] or [MSN][3].
-
-[1]: http://google.com/ "Google"
-[2]: http://search.yahoo.com/ "Yahoo Search"
-[3]: http://search.msn.com/ "MSN Search"
-</code>
-</pre>
-<p>Output:</p>
-<pre>
-<code>&lt;p&gt;I get 10 times more traffic from &lt;a href="http://google.com/"
-title="Google"&gt;Google&lt;/a&gt; than from &lt;a href="http://search.yahoo.com/"
-title="Yahoo Search"&gt;Yahoo&lt;/a&gt; or &lt;a href="http://search.msn.com/"
-title="MSN Search"&gt;MSN&lt;/a&gt;.&lt;/p&gt;
-</code>
-</pre>
-<p>The title attribute is optional. Link names may contain letters,
-numbers and spaces, but are <em>not</em> case sensitive:</p>
-<pre>
-<code>I start my morning with a cup of coffee and
-[The New York Times][NY Times].
-
-[ny times]: http://www.nytimes.com/
-</code>
-</pre>
-<p>Output:</p>
-<pre>
-<code>&lt;p&gt;I start my morning with a cup of coffee and
-&lt;a href="http://www.nytimes.com/"&gt;The New York Times&lt;/a&gt;.&lt;/p&gt;
-</code>
-</pre>
-<h3>Images</h3>
-<p>Image syntax is very much like link syntax.</p>
-<p>Inline (titles are optional):</p>
-<pre>
-<code>![alt text](/path/to/img.jpg "Title")
-</code>
-</pre>
-<p>Reference-style:</p>
-<pre>
-<code>![alt text][id]
-
-[id]: /path/to/img.jpg "Title"
-</code>
-</pre>
-<p>Both of the above examples produce the same output:</p>
-<pre>
-<code>&lt;img src="/path/to/img.jpg" alt="alt text" title="Title" /&gt;
-</code>
-</pre>
-<h3>Code</h3>
-<p>In a regular paragraph, you can create code span by wrapping
-text in backtick quotes. Any ampersands (<code>&amp;</code>) and
-angle brackets (<code>&lt;</code> or <code>&gt;</code>) will
-automatically be translated into HTML entities. This makes it easy
-to use Markdown to write about HTML example code:</p>
-<pre>
-<code>I strongly recommend against using any `&lt;blink&gt;` tags.
-
-I wish SmartyPants used named entities like `&amp;mdash;`
-instead of decimal-encoded entites like `&amp;#8212;`.
-</code>
-</pre>
-<p>Output:</p>
-<pre>
-<code>&lt;p&gt;I strongly recommend against using any
-&lt;code&gt;&amp;lt;blink&amp;gt;&lt;/code&gt; tags.&lt;/p&gt;
-
-&lt;p&gt;I wish SmartyPants used named entities like
-&lt;code&gt;&amp;amp;mdash;&lt;/code&gt; instead of decimal-encoded
-entites like &lt;code&gt;&amp;amp;#8212;&lt;/code&gt;.&lt;/p&gt;
-</code>
-</pre>
-<p>To specify an entire block of pre-formatted code, indent every
-line of the block by 4 spaces or 1 tab. Just like with code spans,
-<code>&amp;</code>, <code>&lt;</code>, and <code>&gt;</code>
-characters will be escaped automatically.</p>
-<p>Markdown:</p>
-<pre>
-<code>If you want your page to validate under XHTML 1.0 Strict,
-you've got to put paragraph tags in your blockquotes:
-
- &lt;blockquote&gt;
- &lt;p&gt;For example.&lt;/p&gt;
- &lt;/blockquote&gt;
-</code>
-</pre>
-<p>Output:</p>
-<pre>
-<code>&lt;p&gt;If you want your page to validate under XHTML 1.0 Strict,
-you've got to put paragraph tags in your blockquotes:&lt;/p&gt;
-
-&lt;pre&gt;&lt;code&gt;&amp;lt;blockquote&amp;gt;
- &amp;lt;p&amp;gt;For example.&amp;lt;/p&amp;gt;
-&amp;lt;/blockquote&amp;gt;
-&lt;/code&gt;&lt;/pre&gt;
-</code>
-</pre>
-</body>
-</html>
diff --git a/MarkdownTest/Tests_2004/Markdown Documentation - Basics.text-res b/MarkdownTest/Tests_2004/Markdown Documentation - Basics.text-res
deleted file mode 100644
index 65b90fa..0000000
--- a/MarkdownTest/Tests_2004/Markdown Documentation - Basics.text-res
+++ /dev/null
@@ -1,321 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
-<html>
-<head>
-<meta name="generator" content=
-"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org">
-<title></title>
-</head>
-<body>
-<h1>Markdown: Basics</h1>
-<ul id="ProjectSubmenu">
-<li><a href="/projects/markdown/" title=
-"Markdown Project Page">Main</a></li>
-<li><a class="selected" title="Markdown Basics">Basics</a></li>
-<li><a href="/projects/markdown/syntax" title=
-"Markdown Syntax Documentation">Syntax</a></li>
-<li><a href="/projects/markdown/license" title=
-"Pricing and License Information">License</a></li>
-<li><a href="/projects/markdown/dingus" title=
-"Online Markdown Web Form">Dingus</a></li>
-</ul>
-<h2>Getting the Gist of Markdown's Formatting Syntax</h2>
-<p>This page offers a brief overview of what it's like to use
-Markdown. The <a href="/projects/markdown/syntax" title=
-"Markdown Syntax">syntax page</a> provides complete, detailed
-documentation for every feature, but Markdown should be very easy
-to pick up simply by looking at a few examples of it in action. The
-examples on this page are written in a before/after style, showing
-example syntax and the HTML output produced by Markdown.</p>
-<p>It's also helpful to simply try Markdown out; the <a href=
-"/projects/markdown/dingus" title="Markdown Dingus">Dingus</a> is a
-web application that allows you type your own Markdown-formatted
-text and translate it to XHTML.</p>
-<p><strong>Note:</strong> This document is itself written using
-Markdown; you can <a href="/projects/markdown/basics.text">see the
-source for it by adding '.text' to the URL</a>.</p>
-<h2>Paragraphs, Headers, Blockquotes</h2>
-<p>A paragraph is simply one or more consecutive lines of text,
-separated by one or more blank lines. (A blank line is any line
-that looks like a blank line -- a line containing nothing spaces or
-tabs is considered blank.) Normal paragraphs should not be intended
-with spaces or tabs.</p>
-<p>Markdown offers two styles of headers: <em>Setext</em> and
-<em>atx</em>. Setext-style headers for <code>&lt;h1&gt;</code> and
-<code>&lt;h2&gt;</code> are created by "underlining" with equal
-signs (<code>=</code>) and hyphens (<code>-</code>), respectively.
-To create an atx-style header, you put 1-6 hash marks
-(<code>#</code>) at the beginning of the line -- the number of
-hashes equals the resulting HTML header level.</p>
-<p>Blockquotes are indicated using email-style '<code>&gt;</code>'
-angle brackets.</p>
-<p>Markdown:</p>
-<pre>
-<code>A First Level Header
-====================
-
-A Second Level Header
----------------------
-
-Now is the time for all good men to come to
-the aid of their country. This is just a
-regular paragraph.
-
-The quick brown fox jumped over the lazy
-dog's back.
-
-### Header 3
-
-&gt; This is a blockquote.
-&gt;
-&gt; This is the second paragraph in the blockquote.
-&gt;
-&gt; ## This is an H2 in a blockquote
-</code>
-</pre>
-<p>Output:</p>
-<pre>
-<code>&lt;h1&gt;A First Level Header&lt;/h1&gt;
-
-&lt;h2&gt;A Second Level Header&lt;/h2&gt;
-
-&lt;p&gt;Now is the time for all good men to come to
-the aid of their country. This is just a
-regular paragraph.&lt;/p&gt;
-
-&lt;p&gt;The quick brown fox jumped over the lazy
-dog's back.&lt;/p&gt;
-
-&lt;h3&gt;Header 3&lt;/h3&gt;
-
-&lt;blockquote&gt;
- &lt;p&gt;This is a blockquote.&lt;/p&gt;
-
- &lt;p&gt;This is the second paragraph in the blockquote.&lt;/p&gt;
-
- &lt;h2&gt;This is an H2 in a blockquote&lt;/h2&gt;
-&lt;/blockquote&gt;
-</code>
-</pre>
-<h3>Phrase Emphasis</h3>
-<p>Markdown uses asterisks and underscores to indicate spans of
-emphasis.</p>
-<p>Markdown:</p>
-<pre>
-<code>Some of these words *are emphasized*.
-Some of these words _are emphasized also_.
-
-Use two asterisks for **strong emphasis**.
-Or, if you prefer, __use two underscores instead__.
-</code>
-</pre>
-<p>Output:</p>
-<pre>
-<code>&lt;p&gt;Some of these words &lt;em&gt;are emphasized&lt;/em&gt;.
-Some of these words &lt;em&gt;are emphasized also&lt;/em&gt;.&lt;/p&gt;
-
-&lt;p&gt;Use two asterisks for &lt;strong&gt;strong emphasis&lt;/strong&gt;.
-Or, if you prefer, &lt;strong&gt;use two underscores instead&lt;/strong&gt;.&lt;/p&gt;
-</code>
-</pre>
-<h2>Lists</h2>
-<p>Unordered (bulleted) lists use asterisks, pluses, and hyphens
-(<code>*</code>, <code>+</code>, and <code>-</code>) as list
-markers. These three markers are interchangable; this:</p>
-<pre>
-<code>* Candy.
-* Gum.
-* Booze.
-</code>
-</pre>
-<p>this:</p>
-<pre>
-<code>+ Candy.
-+ Gum.
-+ Booze.
-</code>
-</pre>
-<p>and this:</p>
-<pre>
-<code>- Candy.
-- Gum.
-- Booze.
-</code>
-</pre>
-<p>all produce the same output:</p>
-<pre>
-<code>&lt;ul&gt;
-&lt;li&gt;Candy.&lt;/li&gt;
-&lt;li&gt;Gum.&lt;/li&gt;
-&lt;li&gt;Booze.&lt;/li&gt;
-&lt;/ul&gt;
-</code>
-</pre>
-<p>Ordered (numbered) lists use regular numbers, followed by
-periods, as list markers:</p>
-<pre>
-<code>1. Red
-2. Green
-3. Blue
-</code>
-</pre>
-<p>Output:</p>
-<pre>
-<code>&lt;ol&gt;
-&lt;li&gt;Red&lt;/li&gt;
-&lt;li&gt;Green&lt;/li&gt;
-&lt;li&gt;Blue&lt;/li&gt;
-&lt;/ol&gt;
-</code>
-</pre>
-<p>If you put blank lines between items, you'll get
-<code>&lt;p&gt;</code> tags for the list item text. You can create
-multi-paragraph list items by indenting the paragraphs by 4 spaces
-or 1 tab:</p>
-<pre>
-<code>* A list item.
-
- With multiple paragraphs.
-
-* Another item in the list.
-</code>
-</pre>
-<p>Output:</p>
-<pre>
-<code>&lt;ul&gt;
-&lt;li&gt;&lt;p&gt;A list item.&lt;/p&gt;
-&lt;p&gt;With multiple paragraphs.&lt;/p&gt;&lt;/li&gt;
-&lt;li&gt;&lt;p&gt;Another item in the list.&lt;/p&gt;&lt;/li&gt;
-&lt;/ul&gt;
-</code>
-</pre>
-<h3>Links</h3>
-<p>Markdown supports two styles for creating links: <em>inline</em>
-and <em>reference</em>. With both styles, you use square brackets
-to delimit the text you want to turn into a link.</p>
-<p>Inline-style links use parentheses immediately after the link
-text. For example:</p>
-<pre>
-<code>This is an [example link](http://example.com/).
-</code>
-</pre>
-<p>Output:</p>
-<pre>
-<code>&lt;p&gt;This is an &lt;a href="http://example.com/"&gt;
-example link&lt;/a&gt;.&lt;/p&gt;
-</code>
-</pre>
-<p>Optionally, you may include a title attribute in the
-parentheses:</p>
-<pre>
-<code>This is an [example link](http://example.com/ "With a Title").
-</code>
-</pre>
-<p>Output:</p>
-<pre>
-<code>&lt;p&gt;This is an &lt;a href="http://example.com/" title="With a Title"&gt;
-example link&lt;/a&gt;.&lt;/p&gt;
-</code>
-</pre>
-<p>Reference-style links allow you to refer to your links by names,
-which you define elsewhere in your document:</p>
-<pre>
-<code>I get 10 times more traffic from [Google][1] than from
-[Yahoo][2] or [MSN][3].
-
-[1]: http://google.com/ "Google"
-[2]: http://search.yahoo.com/ "Yahoo Search"
-[3]: http://search.msn.com/ "MSN Search"
-</code>
-</pre>
-<p>Output:</p>
-<pre>
-<code>&lt;p&gt;I get 10 times more traffic from &lt;a href="http://google.com/"
-title="Google"&gt;Google&lt;/a&gt; than from &lt;a href="http://search.yahoo.com/"
-title="Yahoo Search"&gt;Yahoo&lt;/a&gt; or &lt;a href="http://search.msn.com/"
-title="MSN Search"&gt;MSN&lt;/a&gt;.&lt;/p&gt;
-</code>
-</pre>
-<p>The title attribute is optional. Link names may contain letters,
-numbers and spaces, but are <em>not</em> case sensitive:</p>
-<pre>
-<code>I start my morning with a cup of coffee and
-[The New York Times][NY Times].
-
-[ny times]: http://www.nytimes.com/
-</code>
-</pre>
-<p>Output:</p>
-<pre>
-<code>&lt;p&gt;I start my morning with a cup of coffee and
-&lt;a href="http://www.nytimes.com/"&gt;The New York Times&lt;/a&gt;.&lt;/p&gt;
-</code>
-</pre>
-<h3>Images</h3>
-<p>Image syntax is very much like link syntax.</p>
-<p>Inline (titles are optional):</p>
-<pre>
-<code>![alt text](/path/to/img.jpg "Title")
-</code>
-</pre>
-<p>Reference-style:</p>
-<pre>
-<code>![alt text][id]
-
-[id]: /path/to/img.jpg "Title"
-</code>
-</pre>
-<p>Both of the above examples produce the same output:</p>
-<pre>
-<code>&lt;img src="/path/to/img.jpg" alt="alt text" title="Title" /&gt;
-</code>
-</pre>
-<h3>Code</h3>
-<p>In a regular paragraph, you can create code span by wrapping
-text in backtick quotes. Any ampersands (<code>&amp;</code>) and
-angle brackets (<code>&lt;</code> or <code>&gt;</code>) will
-automatically be translated into HTML entities. This makes it easy
-to use Markdown to write about HTML example code:</p>
-<pre>
-<code>I strongly recommend against using any `&lt;blink&gt;` tags.
-
-I wish SmartyPants used named entities like `&amp;mdash;`
-instead of decimal-encoded entites like `&amp;#8212;`.
-</code>
-</pre>
-<p>Output:</p>
-<pre>
-<code>&lt;p&gt;I strongly recommend against using any
-&lt;code&gt;&amp;lt;blink&amp;gt;&lt;/code&gt; tags.&lt;/p&gt;
-
-&lt;p&gt;I wish SmartyPants used named entities like
-&lt;code&gt;&amp;amp;mdash;&lt;/code&gt; instead of decimal-encoded
-entites like &lt;code&gt;&amp;amp;#8212;&lt;/code&gt;.&lt;/p&gt;
-</code>
-</pre>
-<p>To specify an entire block of pre-formatted code, indent every
-line of the block by 4 spaces or 1 tab. Just like with code spans,
-<code>&amp;</code>, <code>&lt;</code>, and <code>&gt;</code>
-characters will be escaped automatically.</p>
-<p>Markdown:</p>
-<pre>
-<code>If you want your page to validate under XHTML 1.0 Strict,
-you've got to put paragraph tags in your blockquotes:
-
- &lt;blockquote&gt;
- &lt;p&gt;For example.&lt;/p&gt;
- &lt;/blockquote&gt;
-</code>
-</pre>
-<p>Output:</p>
-<pre>
-<code>&lt;p&gt;If you want your page to validate under XHTML 1.0 Strict,
-you've got to put paragraph tags in your blockquotes:&lt;/p&gt;
-
-&lt;pre&gt;&lt;code&gt;&amp;lt;blockquote&amp;gt;
- &amp;lt;p&amp;gt;For example.&amp;lt;/p&amp;gt;
-&amp;lt;/blockquote&amp;gt;
-&lt;/code&gt;&lt;/pre&gt;
-</code>
-</pre>
-</body>
-</html>
diff --git a/MarkdownTest/Tests_2004/Markdown Documentation - Syntax.text-out b/MarkdownTest/Tests_2004/Markdown Documentation - Syntax.text-out
deleted file mode 100644
index ecf2e70..0000000
--- a/MarkdownTest/Tests_2004/Markdown Documentation - Syntax.text-out
+++ /dev/null
@@ -1,957 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
-<html>
-<head>
-<meta name="generator" content=
-"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org">
-<title></title>
-</head>
-<body>
-<h1>Markdown: Syntax</h1>
-<ul id="ProjectSubmenu">
-<li><a href="/projects/markdown/" title=
-"Markdown Project Page">Main</a></li>
-<li><a href="/projects/markdown/basics" title=
-"Markdown Basics">Basics</a></li>
-<li><a class="selected" title=
-"Markdown Syntax Documentation">Syntax</a></li>
-<li><a href="/projects/markdown/license" title=
-"Pricing and License Information">License</a></li>
-<li><a href="/projects/markdown/dingus" title=
-"Online Markdown Web Form">Dingus</a></li>
-</ul>
-<ul>
-<li><a href="#overview">Overview</a>
-<ul>
-<li><a href="#philosophy">Philosophy</a></li>
-<li><a href="#html">Inline HTML</a></li>
-<li><a href="#autoescape">Automatic Escaping for Special
-Characters</a></li>
-</ul>
-</li>
-<li><a href="#block">Block Elements</a>
-<ul>
-<li><a href="#p">Paragraphs and Line Breaks</a></li>
-<li><a href="#header">Headers</a></li>
-<li><a href="#blockquote">Blockquotes</a></li>
-<li><a href="#list">Lists</a></li>
-<li><a href="#precode">Code Blocks</a></li>
-<li><a href="#hr">Horizontal Rules</a></li>
-</ul>
-</li>
-<li><a href="#span">Span Elements</a>
-<ul>
-<li><a href="#link">Links</a></li>
-<li><a href="#em">Emphasis</a></li>
-<li><a href="#code">Code</a></li>
-<li><a href="#img">Images</a></li>
-</ul>
-</li>
-<li><a href="#misc">Miscellaneous</a>
-<ul>
-<li><a href="#backslash">Backslash Escapes</a></li>
-<li><a href="#autolink">Automatic Links</a></li>
-</ul>
-</li>
-</ul>
-<p><strong>Note:</strong> This document is itself written using
-Markdown; you can <a href="/projects/markdown/syntax.text">see the
-source for it by adding '.text' to the URL</a>.</p>
-<hr>
-<h2 id="overview">Overview</h2>
-<h3 id="philosophy">Philosophy</h3>
-<p>Markdown is intended to be as easy-to-read and easy-to-write as
-is feasible.</p>
-<p>Readability, however, is emphasized above all else. A
-Markdown-formatted document should be publishable as-is, as plain
-text, without looking like it's been marked up with tags or
-formatting instructions. While Markdown's syntax has been
-influenced by several existing text-to-HTML filters -- including
-<a href=
-"http://docutils.sourceforge.net/mirror/setext.html">Setext</a>,
-<a href="http://www.aaronsw.com/2002/atx/">atx</a>, <a href=
-"http://textism.com/tools/textile/">Textile</a>, <a href=
-"http://docutils.sourceforge.net/rst.html">reStructuredText</a>,
-<a href=
-"http://www.triptico.com/software/grutatxt.html">Grutatext</a>, and
-<a href="http://ettext.taint.org/doc/">EtText</a> -- the single
-biggest source of inspiration for Markdown's syntax is the format
-of plain text email.</p>
-<p>To this end, Markdown's syntax is comprised entirely of
-punctuation characters, which punctuation characters have been
-carefully chosen so as to look like what they mean. E.g., asterisks
-around a word actually look like *emphasis*. Markdown lists look
-like, well, lists. Even blockquotes look like quoted passages of
-text, assuming you've ever used email.</p>
-<h3 id="html">Inline HTML</h3>
-<p>Markdown's syntax is intended for one purpose: to be used as a
-format for <em>writing</em> for the web.</p>
-<p>Markdown is not a replacement for HTML, or even close to it. Its
-syntax is very small, corresponding only to a very small subset of
-HTML tags. The idea is <em>not</em> to create a syntax that makes
-it easier to insert HTML tags. In my opinion, HTML tags are already
-easy to insert. The idea for Markdown is to make it easy to read,
-write, and edit prose. HTML is a <em>publishing</em> format;
-Markdown is a <em>writing</em> format. Thus, Markdown's formatting
-syntax only addresses issues that can be conveyed in plain
-text.</p>
-<p>For any markup that is not covered by Markdown's syntax, you
-simply use HTML itself. There's no need to preface it or delimit it
-to indicate that you're switching from Markdown to HTML; you just
-use the tags.</p>
-<p>The only restrictions are that block-level HTML elements -- e.g.
-<code>&lt;div&gt;</code>, <code>&lt;table&gt;</code>,
-<code>&lt;pre&gt;</code>, <code>&lt;p&gt;</code>, etc. -- must be
-separated from surrounding content by blank lines, and the start
-and end tags of the block should not be indented with tabs or
-spaces. Markdown is smart enough not to add extra (unwanted)
-<code>&lt;p&gt;</code> tags around HTML block-level tags.</p>
-<p>For example, to add an HTML table to a Markdown article:</p>
-<pre>
-<code>This is a regular paragraph.
-
-&lt;table&gt;
- &lt;tr&gt;
- &lt;td&gt;Foo&lt;/td&gt;
- &lt;/tr&gt;
-&lt;/table&gt;
-
-This is another regular paragraph.
-</code>
-</pre>
-<p>Note that Markdown formatting syntax is not processed within
-block-level HTML tags. E.g., you can't use Markdown-style
-<code>*emphasis*</code> inside an HTML block.</p>
-<p>Span-level HTML tags -- e.g. <code>&lt;span&gt;</code>,
-<code>&lt;cite&gt;</code>, or <code>&lt;del&gt;</code> -- can be
-used anywhere in a Markdown paragraph, list item, or header. If you
-want, you can even use HTML tags instead of Markdown formatting;
-e.g. if you'd prefer to use HTML <code>&lt;a&gt;</code> or
-<code>&lt;img&gt;</code> tags instead of Markdown's link or image
-syntax, go right ahead.</p>
-<p>Unlike block-level HTML tags, Markdown syntax <em>is</em>
-processed within span-level tags.</p>
-<h3 id="autoescape">Automatic Escaping for Special Characters</h3>
-<p>In HTML, there are two characters that demand special treatment:
-<code>&lt;</code> and <code>&amp;</code>. Left angle brackets are
-used to start tags; ampersands are used to denote HTML entities. If
-you want to use them as literal characters, you must escape them as
-entities, e.g. <code>&amp;lt;</code>, and
-<code>&amp;amp;</code>.</p>
-<p>Ampersands in particular are bedeviling for web writers. If you
-want to write about 'AT&amp;T', you need to write
-'<code>AT&amp;amp;T</code>'. You even need to escape ampersands
-within URLs. Thus, if you want to link to:</p>
-<pre>
-<code>http://images.google.com/images?num=30&amp;q=larry+bird
-</code>
-</pre>
-<p>you need to encode the URL as:</p>
-<pre>
-<code>http://images.google.com/images?num=30&amp;amp;q=larry+bird
-</code>
-</pre>
-<p>in your anchor tag <code>href</code> attribute. Needless to say,
-this is easy to forget, and is probably the single most common
-source of HTML validation errors in otherwise well-marked-up web
-sites.</p>
-<p>Markdown allows you to use these characters naturally, taking
-care of all the necessary escaping for you. If you use an ampersand
-as part of an HTML entity, it remains unchanged; otherwise it will
-be translated into <code>&amp;amp;</code>.</p>
-<p>So, if you want to include a copyright symbol in your article,
-you can write:</p>
-<pre>
-<code>&amp;copy;
-</code>
-</pre>
-<p>and Markdown will leave it alone. But if you write:</p>
-<pre>
-<code>AT&amp;T
-</code>
-</pre>
-<p>Markdown will translate it to:</p>
-<pre>
-<code>AT&amp;amp;T
-</code>
-</pre>
-<p>Similarly, because Markdown supports <a href="#html">inline
-HTML</a>, if you use angle brackets as delimiters for HTML tags,
-Markdown will treat them as such. But if you write:</p>
-<pre>
-<code>4 &lt; 5
-</code>
-</pre>
-<p>Markdown will translate it to:</p>
-<pre>
-<code>4 &amp;lt; 5
-</code>
-</pre>
-<p>However, inside Markdown code spans and blocks, angle brackets
-and ampersands are <em>always</em> encoded automatically. This
-makes it easy to use Markdown to write about HTML code. (As opposed
-to raw HTML, which is a terrible format for writing about HTML
-syntax, because every single <code>&lt;</code> and
-<code>&amp;</code> in your example code needs to be escaped.)</p>
-<hr>
-<h2 id="block">Block Elements</h2>
-<h3 id="p">Paragraphs and Line Breaks</h3>
-<p>A paragraph is simply one or more consecutive lines of text,
-separated by one or more blank lines. (A blank line is any line
-that looks like a blank line -- a line containing nothing but
-spaces or tabs is considered blank.) Normal paragraphs should not
-be intended with spaces or tabs.</p>
-<p>The implication of the "one or more consecutive lines of text"
-rule is that Markdown supports "hard-wrapped" text paragraphs. This
-differs significantly from most other text-to-HTML formatters
-(including Movable Type's "Convert Line Breaks" option) which
-translate every line break character in a paragraph into a
-<code>&lt;br /&gt;</code> tag.</p>
-<p>When you <em>do</em> want to insert a <code>&lt;br /&gt;</code>
-break tag using Markdown, you end a line with two or more spaces,
-then type return.</p>
-<p>Yes, this takes a tad more effort to create a <code>&lt;br
-/&gt;</code>, but a simplistic "every line break is a <code>&lt;br
-/&gt;</code>" rule wouldn't work for Markdown. Markdown's
-email-style <a href="#blockquote">blockquoting</a> and
-multi-paragraph <a href="#list">list items</a> work best -- and
-look better -- when you format them with hard breaks.</p>
-<h3 id="header">Headers</h3>
-<p>Markdown supports two styles of headers, <a href=
-"http://docutils.sourceforge.net/mirror/setext.html">Setext</a> and
-<a href="http://www.aaronsw.com/2002/atx/">atx</a>.</p>
-<p>Setext-style headers are "underlined" using equal signs (for
-first-level headers) and dashes (for second-level headers). For
-example:</p>
-<pre>
-<code>This is an H1
-=============
-
-This is an H2
--------------
-</code>
-</pre>
-<p>Any number of underlining <code>=</code>'s or <code>-</code>'s
-will work.</p>
-<p>Atx-style headers use 1-6 hash characters at the start of the
-line, corresponding to header levels 1-6. For example:</p>
-<pre>
-<code># This is an H1
-
-## This is an H2
-
-###### This is an H6
-</code>
-</pre>
-<p>Optionally, you may "close" atx-style headers. This is purely
-cosmetic -- you can use this if you think it looks better. The
-closing hashes don't even need to match the number of hashes used
-to open the header. (The number of opening hashes determines the
-header level.) :</p>
-<pre>
-<code># This is an H1 #
-
-## This is an H2 ##
-
-### This is an H3 ######
-</code>
-</pre>
-<h3 id="blockquote">Blockquotes</h3>
-<p>Markdown uses email-style <code>&gt;</code> characters for
-blockquoting. If you're familiar with quoting passages of text in
-an email message, then you know how to create a blockquote in
-Markdown. It looks best if you hard wrap the text and put a
-<code>&gt;</code> before every line:</p>
-<pre>
-<code>&gt; This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
-&gt; consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
-&gt; Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
-&gt;
-&gt; Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
-&gt; id sem consectetuer libero luctus adipiscing.
-</code>
-</pre>
-<p>Markdown allows you to be lazy and only put the
-<code>&gt;</code> before the first line of a hard-wrapped
-paragraph:</p>
-<pre>
-<code>&gt; This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
-consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
-Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
-
-&gt; Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
-id sem consectetuer libero luctus adipiscing.
-</code>
-</pre>
-<p>Blockquotes can be nested (i.e. a blockquote-in-a-blockquote) by
-adding additional levels of <code>&gt;</code>:</p>
-<pre>
-<code>&gt; This is the first level of quoting.
-&gt;
-&gt; &gt; This is nested blockquote.
-&gt;
-&gt; Back to the first level.
-</code>
-</pre>
-<p>Blockquotes can contain other Markdown elements, including
-headers, lists, and code blocks:</p>
-<pre>
-<code>&gt; ## This is a header.
-&gt;
-&gt; 1. This is the first list item.
-&gt; 2. This is the second list item.
-&gt;
-&gt; Here's some example code:
-&gt;
-&gt; return shell_exec("echo $input | $markdown_script");
-</code>
-</pre>
-<p>Any decent text editor should make email-style quoting easy. For
-example, with BBEdit, you can make a selection and choose Increase
-Quote Level from the Text menu.</p>
-<h3 id="list">Lists</h3>
-<p>Markdown supports ordered (numbered) and unordered (bulleted)
-lists.</p>
-<p>Unordered lists use asterisks, pluses, and hyphens --
-interchangably -- as list markers:</p>
-<pre>
-<code>* Red
-* Green
-* Blue
-</code>
-</pre>
-<p>is equivalent to:</p>
-<pre>
-<code>+ Red
-+ Green
-+ Blue
-</code>
-</pre>
-<p>and:</p>
-<pre>
-<code>- Red
-- Green
-- Blue
-</code>
-</pre>
-<p>Ordered lists use numbers followed by periods:</p>
-<pre>
-<code>1. Bird
-2. McHale
-3. Parish
-</code>
-</pre>
-<p>It's important to note that the actual numbers you use to mark
-the list have no effect on the HTML output Markdown produces. The
-HTML Markdown produces from the above list is:</p>
-<pre>
-<code>&lt;ol&gt;
-&lt;li&gt;Bird&lt;/li&gt;
-&lt;li&gt;McHale&lt;/li&gt;
-&lt;li&gt;Parish&lt;/li&gt;
-&lt;/ol&gt;
-</code>
-</pre>
-<p>If you instead wrote the list in Markdown like this:</p>
-<pre>
-<code>1. Bird
-1. McHale
-1. Parish
-</code>
-</pre>
-<p>or even:</p>
-<pre>
-<code>3. Bird
-1. McHale
-8. Parish
-</code>
-</pre>
-<p>you'd get the exact same HTML output. The point is, if you want
-to, you can use ordinal numbers in your ordered Markdown lists, so
-that the numbers in your source match the numbers in your published
-HTML. But if you want to be lazy, you don't have to.</p>
-<p>If you do use lazy list numbering, however, you should still
-start the list with the number 1. At some point in the future,
-Markdown may support starting ordered lists at an arbitrary
-number.</p>
-<p>List markers typically start at the left margin, but may be
-indented by up to three spaces. List markers must be followed by
-one or more spaces or a tab.</p>
-<p>To make lists look nice, you can wrap items with hanging
-indents:</p>
-<pre>
-<code>* Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
- Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
- viverra nec, fringilla in, laoreet vitae, risus.
-* Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
- Suspendisse id sem consectetuer libero luctus adipiscing.
-</code>
-</pre>
-<p>But if you want to be lazy, you don't have to:</p>
-<pre>
-<code>* Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
-Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
-viverra nec, fringilla in, laoreet vitae, risus.
-* Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
-Suspendisse id sem consectetuer libero luctus adipiscing.
-</code>
-</pre>
-<p>If list items are separated by blank lines, Markdown will wrap
-the items in <code>&lt;p&gt;</code> tags in the HTML output. For
-example, this input:</p>
-<pre>
-<code>* Bird
-* Magic
-</code>
-</pre>
-<p>will turn into:</p>
-<pre>
-<code>&lt;ul&gt;
-&lt;li&gt;Bird&lt;/li&gt;
-&lt;li&gt;Magic&lt;/li&gt;
-&lt;/ul&gt;
-</code>
-</pre>
-<p>But this:</p>
-<pre>
-<code>* Bird
-
-* Magic
-</code>
-</pre>
-<p>will turn into:</p>
-<pre>
-<code>&lt;ul&gt;
-&lt;li&gt;&lt;p&gt;Bird&lt;/p&gt;&lt;/li&gt;
-&lt;li&gt;&lt;p&gt;Magic&lt;/p&gt;&lt;/li&gt;
-&lt;/ul&gt;
-</code>
-</pre>
-<p>List items may consist of multiple paragraphs. Each subsequent
-paragraph in a list item must be intended by either 4 spaces or one
-tab:</p>
-<pre>
-<code>1. This is a list item with two paragraphs. Lorem ipsum dolor
- sit amet, consectetuer adipiscing elit. Aliquam hendrerit
- mi posuere lectus.
-
- Vestibulum enim wisi, viverra nec, fringilla in, laoreet
- vitae, risus. Donec sit amet nisl. Aliquam semper ipsum
- sit amet velit.
-
-2. Suspendisse id sem consectetuer libero luctus adipiscing.
-</code>
-</pre>
-<p>It looks nice if you indent every line of the subsequent
-paragraphs, but here again, Markdown will allow you to be lazy:</p>
-<pre>
-<code>* This is a list item with two paragraphs.
-
- This is the second paragraph in the list item. You're
-only required to indent the first line. Lorem ipsum dolor
-sit amet, consectetuer adipiscing elit.
-
-* Another item in the same list.
-</code>
-</pre>
-<p>To put a blockquote within a list item, the blockquote's
-<code>&gt;</code> delimiters need to be indented:</p>
-<pre>
-<code>* A list item with a blockquote:
-
- &gt; This is a blockquote
- &gt; inside a list item.
-</code>
-</pre>
-<p>To put a code block within a list item, the code block needs to
-be indented <em>twice</em> -- 8 spaces or two tabs:</p>
-<pre>
-<code>* A list item with a code block:
-
- &lt;code goes here&gt;
-</code>
-</pre>
-<p>It's worth noting that it's possible to trigger an ordered list
-by accident, by writing something like this:</p>
-<pre>
-<code>1986. What a great season.
-</code>
-</pre>
-<p>In other words, a <em>number-period-space</em> sequence at the
-beginning of a line. To avoid this, you can backslash-escape the
-period:</p>
-<pre>
-<code>1986\. What a great season.
-</code>
-</pre>
-<h3 id="precode">Code Blocks</h3>
-<p>Pre-formatted code blocks are used for writing about programming
-or markup source code. Rather than forming normal paragraphs, the
-lines of a code block are interpreted literally. Markdown wraps a
-code block in both <code>&lt;pre&gt;</code> and
-<code>&lt;code&gt;</code> tags.</p>
-<p>To produce a code block in Markdown, simply indent every line of
-the block by at least 4 spaces or 1 tab. For example, given this
-input:</p>
-<pre>
-<code>This is a normal paragraph:
-
- This is a code block.
-</code>
-</pre>
-<p>Markdown will generate:</p>
-<pre>
-<code>&lt;p&gt;This is a normal paragraph:&lt;/p&gt;
-
-&lt;pre&gt;&lt;code&gt;This is a code block.
-&lt;/code&gt;&lt;/pre&gt;
-</code>
-</pre>
-<p>One level of indentation -- 4 spaces or 1 tab -- is removed from
-each line of the code block. For example, this:</p>
-<pre>
-<code>Here is an example of AppleScript:
-
- tell application "Foo"
- beep
- end tell
-</code>
-</pre>
-<p>will turn into:</p>
-<pre>
-<code>&lt;p&gt;Here is an example of AppleScript:&lt;/p&gt;
-
-&lt;pre&gt;&lt;code&gt;tell application "Foo"
- beep
-end tell
-&lt;/code&gt;&lt;/pre&gt;
-</code>
-</pre>
-<p>A code block continues until it reaches a line that is not
-indented (or the end of the article).</p>
-<p>Within a code block, ampersands (<code>&amp;</code>) and angle
-brackets (<code>&lt;</code> and <code>&gt;</code>) are
-automatically converted into HTML entities. This makes it very easy
-to include example HTML source code using Markdown -- just paste it
-and indent it, and Markdown will handle the hassle of encoding the
-ampersands and angle brackets. For example, this:</p>
-<pre>
-<code> &lt;div class="footer"&gt;
- &amp;copy; 2004 Foo Corporation
- &lt;/div&gt;
-</code>
-</pre>
-<p>will turn into:</p>
-<pre>
-<code>&lt;pre&gt;&lt;code&gt;&amp;lt;div class="footer"&amp;gt;
- &amp;amp;copy; 2004 Foo Corporation
-&amp;lt;/div&amp;gt;
-&lt;/code&gt;&lt;/pre&gt;
-</code>
-</pre>
-<p>Regular Markdown syntax is not processed within code blocks.
-E.g., asterisks are just literal asterisks within a code block.
-This means it's also easy to use Markdown to write about Markdown's
-own syntax.</p>
-<h3 id="hr">Horizontal Rules</h3>
-<p>You can produce a horizontal rule tag (<code>&lt;hr
-/&gt;</code>) by placing three or more hyphens, asterisks, or
-underscores on a line by themselves. If you wish, you may use
-spaces between the hyphens or asterisks. Each of the following
-lines will produce a horizontal rule:</p>
-<pre>
-<code>* * *
-
-***
-
-*****
-
-- - -
-
----------------------------------------
-
-_ _ _
-</code>
-</pre>
-<hr>
-<h2 id="span">Span Elements</h2>
-<h3 id="link">Links</h3>
-<p>Markdown supports two style of links: <em>inline</em> and
-<em>reference</em>.</p>
-<p>In both styles, the link text is delimited by [square
-brackets].</p>
-<p>To create an inline link, use a set of regular parentheses
-immediately after the link text's closing square bracket. Inside
-the parentheses, put the URL where you want the link to point,
-along with an <em>optional</em> title for the link, surrounded in
-quotes. For example:</p>
-<pre>
-<code>This is [an example](http://example.com/ "Title") inline link.
-
-[This link](http://example.net/) has no title attribute.
-</code>
-</pre>
-<p>Will produce:</p>
-<pre>
-<code>&lt;p&gt;This is &lt;a href="http://example.com/" title="Title"&gt;
-an example&lt;/a&gt; inline link.&lt;/p&gt;
-
-&lt;p&gt;&lt;a href="http://example.net/"&gt;This link&lt;/a&gt; has no
-title attribute.&lt;/p&gt;
-</code>
-</pre>
-<p>If you're referring to a local resource on the same server, you
-can use relative paths:</p>
-<pre>
-<code>See my [About](/about/) page for details.
-</code>
-</pre>
-<p>Reference-style links use a second set of square brackets,
-inside which you place a label of your choosing to identify the
-link:</p>
-<pre>
-<code>This is [an example][id] reference-style link.
-</code>
-</pre>
-<p>You can optionally use a space to separate the sets of
-brackets:</p>
-<pre>
-<code>This is [an example] [id] reference-style link.
-</code>
-</pre>
-<p>Then, anywhere in the document, you define your link label like
-this, on a line by itself:</p>
-<pre>
-<code>[id]: http://example.com/ "Optional Title Here"
-</code>
-</pre>
-<p>That is:</p>
-<ul>
-<li>Square brackets containing the link identifier (optionally
-indented from the left margin using up to three spaces);</li>
-<li>followed by a colon;</li>
-<li>followed by one or more spaces (or tabs);</li>
-<li>followed by the URL for the link;</li>
-<li>optionally followed by a title attribute for the link, enclosed
-in double or single quotes.</li>
-</ul>
-<p>The link URL may, optionally, be surrounded by angle
-brackets:</p>
-<pre>
-<code>[id]: &lt;http://example.com/&gt; "Optional Title Here"
-</code>
-</pre>
-<p>You can put the title attribute on the next line and use extra
-spaces or tabs for padding, which tends to look better with longer
-URLs:</p>
-<pre>
-<code>[id]: http://example.com/longish/path/to/resource/here
- "Optional Title Here"
-</code>
-</pre>
-<p>Link definitions are only used for creating links during
-Markdown processing, and are stripped from your document in the
-HTML output.</p>
-<p>Link definition names may constist of letters, numbers, spaces,
-and punctuation -- but they are <em>not</em> case sensitive. E.g.
-these two links:</p>
-<pre>
-<code>[link text][a]
-[link text][A]
-</code>
-</pre>
-<p>are equivalent.</p>
-<p>The <em>implicit link name</em> shortcut allows you to omit the
-name of the link, in which case the link text itself is used as the
-name. Just use an empty set of square brackets -- e.g., to link the
-word "Google" to the google.com web site, you could simply
-write:</p>
-<pre>
-<code>[Google][]
-</code>
-</pre>
-<p>And then define the link:</p>
-<pre>
-<code>[Google]: http://google.com/
-</code>
-</pre>
-<p>Because link names may contain spaces, this shortcut even works
-for multiple words in the link text:</p>
-<pre>
-<code>Visit [Daring Fireball][] for more information.
-</code>
-</pre>
-<p>And then define the link:</p>
-<pre>
-<code>[Daring Fireball]: http://daringfireball.net/
-</code>
-</pre>
-<p>Link definitions can be placed anywhere in your Markdown
-document. I tend to put them immediately after each paragraph in
-which they're used, but if you want, you can put them all at the
-end of your document, sort of like footnotes.</p>
-<p>Here's an example of reference links in action:</p>
-<pre>
-<code>I get 10 times more traffic from [Google] [1] than from
-[Yahoo] [2] or [MSN] [3].
-
- [1]: http://google.com/ "Google"
- [2]: http://search.yahoo.com/ "Yahoo Search"
- [3]: http://search.msn.com/ "MSN Search"
-</code>
-</pre>
-<p>Using the implicit link name shortcut, you could instead
-write:</p>
-<pre>
-<code>I get 10 times more traffic from [Google][] than from
-[Yahoo][] or [MSN][].
-
- [google]: http://google.com/ "Google"
- [yahoo]: http://search.yahoo.com/ "Yahoo Search"
- [msn]: http://search.msn.com/ "MSN Search"
-</code>
-</pre>
-<p>Both of the above examples will produce the following HTML
-output:</p>
-<pre>
-<code>&lt;p&gt;I get 10 times more traffic from &lt;a href="http://google.com/"
-title="Google"&gt;Google&lt;/a&gt; than from
-&lt;a href="http://search.yahoo.com/" title="Yahoo Search"&gt;Yahoo&lt;/a&gt;
-or &lt;a href="http://search.msn.com/" title="MSN Search"&gt;MSN&lt;/a&gt;.&lt;/p&gt;
-</code>
-</pre>
-<p>For comparison, here is the same paragraph written using
-Markdown's inline link style:</p>
-<pre>
-<code>I get 10 times more traffic from [Google](http://google.com/ "Google")
-than from [Yahoo](http://search.yahoo.com/ "Yahoo Search") or
-[MSN](http://search.msn.com/ "MSN Search").
-</code>
-</pre>
-<p>The point of reference-style links is not that they're easier to
-write. The point is that with reference-style links, your document
-source is vastly more readable. Compare the above examples: using
-reference-style links, the paragraph itself is only 81 characters
-long; with inline-style links, it's 176 characters; and as raw
-HTML, it's 234 characters. In the raw HTML, there's more markup
-than there is text.</p>
-<p>With Markdown's reference-style links, a source document much
-more closely resembles the final output, as rendered in a browser.
-By allowing you to move the markup-related metadata out of the
-paragraph, you can add links without interrupting the narrative
-flow of your prose.</p>
-<h3 id="em">Emphasis</h3>
-<p>Markdown treats asterisks (<code>*</code>) and underscores
-(<code>_</code>) as indicators of emphasis. Text wrapped with one
-<code>*</code> or <code>_</code> will be wrapped with an HTML
-<code>&lt;em&gt;</code> tag; double <code>*</code>'s or
-<code>_</code>'s will be wrapped with an HTML
-<code>&lt;strong&gt;</code> tag. E.g., this input:</p>
-<pre>
-<code>*single asterisks*
-
-_single underscores_
-
-**double asterisks**
-
-__double underscores__
-</code>
-</pre>
-<p>will produce:</p>
-<pre>
-<code>&lt;em&gt;single asterisks&lt;/em&gt;
-
-&lt;em&gt;single underscores&lt;/em&gt;
-
-&lt;strong&gt;double asterisks&lt;/strong&gt;
-
-&lt;strong&gt;double underscores&lt;/strong&gt;
-</code>
-</pre>
-<p>You can use whichever style you prefer; the lone restriction is
-that the same character must be used to open and close an emphasis
-span.</p>
-<p>Emphasis can be used in the middle of a word:</p>
-<pre>
-<code>un*fucking*believable
-</code>
-</pre>
-<p>But if you surround an <code>*</code> or <code>_</code> with
-spaces, it'll be treated as a literal asterisk or underscore.</p>
-<p>To produce a literal asterisk or underscore at a position where
-it would otherwise be used as an emphasis delimiter, you can
-backslash escape it:</p>
-<pre>
-<code>\*this text is surrounded by literal asterisks\*
-</code>
-</pre>
-<h3 id="code">Code</h3>
-<p>To indicate a span of code, wrap it with backtick quotes
-(<code>`</code>). Unlike a pre-formatted code block, a code span
-indicates code within a normal paragraph. For example:</p>
-<pre>
-<code>Use the `printf()` function.
-</code>
-</pre>
-<p>will produce:</p>
-<pre>
-<code>&lt;p&gt;Use the &lt;code&gt;printf()&lt;/code&gt; function.&lt;/p&gt;
-</code>
-</pre>
-<p>To include a literal backtick character within a code span, you
-can use multiple backticks as the opening and closing
-delimiters:</p>
-<pre>
-<code>``There is a literal backtick (`) here.``
-</code>
-</pre>
-<p>which will produce this:</p>
-<pre>
-<code>&lt;p&gt;&lt;code&gt;There is a literal backtick (`) here.&lt;/code&gt;&lt;/p&gt;
-</code>
-</pre>
-<p>The backtick delimiters surrounding a code span may include
-spaces -- one after the opening, one before the closing. This
-allows you to place literal backtick characters at the beginning or
-end of a code span:</p>
-<pre>
-<code>A single backtick in a code span: `` ` ``
-
-A backtick-delimited string in a code span: `` `foo` ``
-</code>
-</pre>
-<p>will produce:</p>
-<pre>
-<code>&lt;p&gt;A single backtick in a code span: &lt;code&gt;`&lt;/code&gt;&lt;/p&gt;
-
-&lt;p&gt;A backtick-delimited string in a code span: &lt;code&gt;`foo`&lt;/code&gt;&lt;/p&gt;
-</code>
-</pre>
-<p>With a code span, ampersands and angle brackets are encoded as
-HTML entities automatically, which makes it easy to include example
-HTML tags. Markdown will turn this:</p>
-<pre>
-<code>Please don't use any `&lt;blink&gt;` tags.
-</code>
-</pre>
-<p>into:</p>
-<pre>
-<code>&lt;p&gt;Please don't use any &lt;code&gt;&amp;lt;blink&amp;gt;&lt;/code&gt; tags.&lt;/p&gt;
-</code>
-</pre>
-<p>You can write this:</p>
-<pre>
-<code>`&amp;#8212;` is the decimal-encoded equivalent of `&amp;mdash;`.
-</code>
-</pre>
-<p>to produce:</p>
-<pre>
-<code>&lt;p&gt;&lt;code&gt;&amp;amp;#8212;&lt;/code&gt; is the decimal-encoded
-equivalent of &lt;code&gt;&amp;amp;mdash;&lt;/code&gt;.&lt;/p&gt;
-</code>
-</pre>
-<h3 id="img">Images</h3>
-<p>Admittedly, it's fairly difficult to devise a "natural" syntax
-for placing images into a plain text document format.</p>
-<p>Markdown uses an image syntax that is intended to resemble the
-syntax for links, allowing for two styles: <em>inline</em> and
-<em>reference</em>.</p>
-<p>Inline image syntax looks like this:</p>
-<pre>
-<code>![Alt text](/path/to/img.jpg)
-
-![Alt text](/path/to/img.jpg "Optional title")
-</code>
-</pre>
-<p>That is:</p>
-<ul>
-<li>An exclamation mark: <code>!</code>;</li>
-<li>followed by a set of square brackets, containing the
-<code>alt</code> attribute text for the image;</li>
-<li>followed by a set of parentheses, containing the URL or path to
-the image, and an optional <code>title</code> attribute enclosed in
-double or single quotes.</li>
-</ul>
-<p>Reference-style image syntax looks like this:</p>
-<pre>
-<code>![Alt text][id]
-</code>
-</pre>
-<p>Where "id" is the name of a defined image reference. Image
-references are defined using syntax identical to link
-references:</p>
-<pre>
-<code>[id]: url/to/image "Optional title attribute"
-</code>
-</pre>
-<p>As of this writing, Markdown has no syntax for specifying the
-dimensions of an image; if this is important to you, you can simply
-use regular HTML <code>&lt;img&gt;</code> tags.</p>
-<hr>
-<h2 id="misc">Miscellaneous</h2>
-<h3 id="autolink">Automatic Links</h3>
-<p>Markdown supports a shortcut style for creating "automatic"
-links for URLs and email addresses: simply surround the URL or
-email address with angle brackets. What this means is that if you
-want to show the actual text of a URL or email address, and also
-have it be a clickable link, you can do this:</p>
-<pre>
-<code>&lt;http://example.com/&gt;
-</code>
-</pre>
-<p>Markdown will turn this into:</p>
-<pre>
-<code>&lt;a href="http://example.com/"&gt;http://example.com/&lt;/a&gt;
-</code>
-</pre>
-<p>Automatic links for email addresses work similarly, except that
-Markdown will also perform a bit of randomized decimal and hex
-entity-encoding to help obscure your address from
-address-harvesting spambots. For example, Markdown will turn
-this:</p>
-<pre>
-<code>&lt;address@example.com&gt;
-</code>
-</pre>
-<p>into something like this:</p>
-<pre>
-<code>&lt;a href="&amp;#x6D;&amp;#x61;i&amp;#x6C;&amp;#x74;&amp;#x6F;:&amp;#x61;&amp;#x64;&amp;#x64;&amp;#x72;&amp;#x65;
-&amp;#115;&amp;#115;&amp;#64;&amp;#101;&amp;#120;&amp;#x61;&amp;#109;&amp;#x70;&amp;#x6C;e&amp;#x2E;&amp;#99;&amp;#111;
-&amp;#109;"&gt;&amp;#x61;&amp;#x64;&amp;#x64;&amp;#x72;&amp;#x65;&amp;#115;&amp;#115;&amp;#64;&amp;#101;&amp;#120;&amp;#x61;
-&amp;#109;&amp;#x70;&amp;#x6C;e&amp;#x2E;&amp;#99;&amp;#111;&amp;#109;&lt;/a&gt;
-</code>
-</pre>
-<p>which will render in a browser as a clickable link to
-"address@example.com".</p>
-<p>(This sort of entity-encoding trick will indeed fool many, if
-not most, address-harvesting bots, but it definitely won't fool all
-of them. It's better than nothing, but an address published in this
-way will probably eventually start receiving spam.)</p>
-<h3 id="backslash">Backslash Escapes</h3>
-<p>Markdown allows you to use backslash escapes to generate literal
-characters which would otherwise have special meaning in Markdown's
-formatting syntax. For example, if you wanted to surround a word
-with literal asterisks (instead of an HTML <code>&lt;em&gt;</code>
-tag), you can backslashes before the asterisks, like this:</p>
-<pre>
-<code>\*literal asterisks\*
-</code>
-</pre>
-<p>Markdown provides backslash escapes for the following
-characters:</p>
-<pre>
-<code>\ backslash
-` backtick
-* asterisk
-_ underscore
-{} curly braces
-[] square brackets
-() parentheses
-# hash mark
-+ plus sign
-- minus sign (hyphen)
-. dot
-! exclamation mark
-</code>
-</pre>
-</body>
-</html>
diff --git a/MarkdownTest/Tests_2004/Markdown Documentation - Syntax.text-res b/MarkdownTest/Tests_2004/Markdown Documentation - Syntax.text-res
deleted file mode 100644
index ecf2e70..0000000
--- a/MarkdownTest/Tests_2004/Markdown Documentation - Syntax.text-res
+++ /dev/null
@@ -1,957 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
-<html>
-<head>
-<meta name="generator" content=
-"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org">
-<title></title>
-</head>
-<body>
-<h1>Markdown: Syntax</h1>
-<ul id="ProjectSubmenu">
-<li><a href="/projects/markdown/" title=
-"Markdown Project Page">Main</a></li>
-<li><a href="/projects/markdown/basics" title=
-"Markdown Basics">Basics</a></li>
-<li><a class="selected" title=
-"Markdown Syntax Documentation">Syntax</a></li>
-<li><a href="/projects/markdown/license" title=
-"Pricing and License Information">License</a></li>
-<li><a href="/projects/markdown/dingus" title=
-"Online Markdown Web Form">Dingus</a></li>
-</ul>
-<ul>
-<li><a href="#overview">Overview</a>
-<ul>
-<li><a href="#philosophy">Philosophy</a></li>
-<li><a href="#html">Inline HTML</a></li>
-<li><a href="#autoescape">Automatic Escaping for Special
-Characters</a></li>
-</ul>
-</li>
-<li><a href="#block">Block Elements</a>
-<ul>
-<li><a href="#p">Paragraphs and Line Breaks</a></li>
-<li><a href="#header">Headers</a></li>
-<li><a href="#blockquote">Blockquotes</a></li>
-<li><a href="#list">Lists</a></li>
-<li><a href="#precode">Code Blocks</a></li>
-<li><a href="#hr">Horizontal Rules</a></li>
-</ul>
-</li>
-<li><a href="#span">Span Elements</a>
-<ul>
-<li><a href="#link">Links</a></li>
-<li><a href="#em">Emphasis</a></li>
-<li><a href="#code">Code</a></li>
-<li><a href="#img">Images</a></li>
-</ul>
-</li>
-<li><a href="#misc">Miscellaneous</a>
-<ul>
-<li><a href="#backslash">Backslash Escapes</a></li>
-<li><a href="#autolink">Automatic Links</a></li>
-</ul>
-</li>
-</ul>
-<p><strong>Note:</strong> This document is itself written using
-Markdown; you can <a href="/projects/markdown/syntax.text">see the
-source for it by adding '.text' to the URL</a>.</p>
-<hr>
-<h2 id="overview">Overview</h2>
-<h3 id="philosophy">Philosophy</h3>
-<p>Markdown is intended to be as easy-to-read and easy-to-write as
-is feasible.</p>
-<p>Readability, however, is emphasized above all else. A
-Markdown-formatted document should be publishable as-is, as plain
-text, without looking like it's been marked up with tags or
-formatting instructions. While Markdown's syntax has been
-influenced by several existing text-to-HTML filters -- including
-<a href=
-"http://docutils.sourceforge.net/mirror/setext.html">Setext</a>,
-<a href="http://www.aaronsw.com/2002/atx/">atx</a>, <a href=
-"http://textism.com/tools/textile/">Textile</a>, <a href=
-"http://docutils.sourceforge.net/rst.html">reStructuredText</a>,
-<a href=
-"http://www.triptico.com/software/grutatxt.html">Grutatext</a>, and
-<a href="http://ettext.taint.org/doc/">EtText</a> -- the single
-biggest source of inspiration for Markdown's syntax is the format
-of plain text email.</p>
-<p>To this end, Markdown's syntax is comprised entirely of
-punctuation characters, which punctuation characters have been
-carefully chosen so as to look like what they mean. E.g., asterisks
-around a word actually look like *emphasis*. Markdown lists look
-like, well, lists. Even blockquotes look like quoted passages of
-text, assuming you've ever used email.</p>
-<h3 id="html">Inline HTML</h3>
-<p>Markdown's syntax is intended for one purpose: to be used as a
-format for <em>writing</em> for the web.</p>
-<p>Markdown is not a replacement for HTML, or even close to it. Its
-syntax is very small, corresponding only to a very small subset of
-HTML tags. The idea is <em>not</em> to create a syntax that makes
-it easier to insert HTML tags. In my opinion, HTML tags are already
-easy to insert. The idea for Markdown is to make it easy to read,
-write, and edit prose. HTML is a <em>publishing</em> format;
-Markdown is a <em>writing</em> format. Thus, Markdown's formatting
-syntax only addresses issues that can be conveyed in plain
-text.</p>
-<p>For any markup that is not covered by Markdown's syntax, you
-simply use HTML itself. There's no need to preface it or delimit it
-to indicate that you're switching from Markdown to HTML; you just
-use the tags.</p>
-<p>The only restrictions are that block-level HTML elements -- e.g.
-<code>&lt;div&gt;</code>, <code>&lt;table&gt;</code>,
-<code>&lt;pre&gt;</code>, <code>&lt;p&gt;</code>, etc. -- must be
-separated from surrounding content by blank lines, and the start
-and end tags of the block should not be indented with tabs or
-spaces. Markdown is smart enough not to add extra (unwanted)
-<code>&lt;p&gt;</code> tags around HTML block-level tags.</p>
-<p>For example, to add an HTML table to a Markdown article:</p>
-<pre>
-<code>This is a regular paragraph.
-
-&lt;table&gt;
- &lt;tr&gt;
- &lt;td&gt;Foo&lt;/td&gt;
- &lt;/tr&gt;
-&lt;/table&gt;
-
-This is another regular paragraph.
-</code>
-</pre>
-<p>Note that Markdown formatting syntax is not processed within
-block-level HTML tags. E.g., you can't use Markdown-style
-<code>*emphasis*</code> inside an HTML block.</p>
-<p>Span-level HTML tags -- e.g. <code>&lt;span&gt;</code>,
-<code>&lt;cite&gt;</code>, or <code>&lt;del&gt;</code> -- can be
-used anywhere in a Markdown paragraph, list item, or header. If you
-want, you can even use HTML tags instead of Markdown formatting;
-e.g. if you'd prefer to use HTML <code>&lt;a&gt;</code> or
-<code>&lt;img&gt;</code> tags instead of Markdown's link or image
-syntax, go right ahead.</p>
-<p>Unlike block-level HTML tags, Markdown syntax <em>is</em>
-processed within span-level tags.</p>
-<h3 id="autoescape">Automatic Escaping for Special Characters</h3>
-<p>In HTML, there are two characters that demand special treatment:
-<code>&lt;</code> and <code>&amp;</code>. Left angle brackets are
-used to start tags; ampersands are used to denote HTML entities. If
-you want to use them as literal characters, you must escape them as
-entities, e.g. <code>&amp;lt;</code>, and
-<code>&amp;amp;</code>.</p>
-<p>Ampersands in particular are bedeviling for web writers. If you
-want to write about 'AT&amp;T', you need to write
-'<code>AT&amp;amp;T</code>'. You even need to escape ampersands
-within URLs. Thus, if you want to link to:</p>
-<pre>
-<code>http://images.google.com/images?num=30&amp;q=larry+bird
-</code>
-</pre>
-<p>you need to encode the URL as:</p>
-<pre>
-<code>http://images.google.com/images?num=30&amp;amp;q=larry+bird
-</code>
-</pre>
-<p>in your anchor tag <code>href</code> attribute. Needless to say,
-this is easy to forget, and is probably the single most common
-source of HTML validation errors in otherwise well-marked-up web
-sites.</p>
-<p>Markdown allows you to use these characters naturally, taking
-care of all the necessary escaping for you. If you use an ampersand
-as part of an HTML entity, it remains unchanged; otherwise it will
-be translated into <code>&amp;amp;</code>.</p>
-<p>So, if you want to include a copyright symbol in your article,
-you can write:</p>
-<pre>
-<code>&amp;copy;
-</code>
-</pre>
-<p>and Markdown will leave it alone. But if you write:</p>
-<pre>
-<code>AT&amp;T
-</code>
-</pre>
-<p>Markdown will translate it to:</p>
-<pre>
-<code>AT&amp;amp;T
-</code>
-</pre>
-<p>Similarly, because Markdown supports <a href="#html">inline
-HTML</a>, if you use angle brackets as delimiters for HTML tags,
-Markdown will treat them as such. But if you write:</p>
-<pre>
-<code>4 &lt; 5
-</code>
-</pre>
-<p>Markdown will translate it to:</p>
-<pre>
-<code>4 &amp;lt; 5
-</code>
-</pre>
-<p>However, inside Markdown code spans and blocks, angle brackets
-and ampersands are <em>always</em> encoded automatically. This
-makes it easy to use Markdown to write about HTML code. (As opposed
-to raw HTML, which is a terrible format for writing about HTML
-syntax, because every single <code>&lt;</code> and
-<code>&amp;</code> in your example code needs to be escaped.)</p>
-<hr>
-<h2 id="block">Block Elements</h2>
-<h3 id="p">Paragraphs and Line Breaks</h3>
-<p>A paragraph is simply one or more consecutive lines of text,
-separated by one or more blank lines. (A blank line is any line
-that looks like a blank line -- a line containing nothing but
-spaces or tabs is considered blank.) Normal paragraphs should not
-be intended with spaces or tabs.</p>
-<p>The implication of the "one or more consecutive lines of text"
-rule is that Markdown supports "hard-wrapped" text paragraphs. This
-differs significantly from most other text-to-HTML formatters
-(including Movable Type's "Convert Line Breaks" option) which
-translate every line break character in a paragraph into a
-<code>&lt;br /&gt;</code> tag.</p>
-<p>When you <em>do</em> want to insert a <code>&lt;br /&gt;</code>
-break tag using Markdown, you end a line with two or more spaces,
-then type return.</p>
-<p>Yes, this takes a tad more effort to create a <code>&lt;br
-/&gt;</code>, but a simplistic "every line break is a <code>&lt;br
-/&gt;</code>" rule wouldn't work for Markdown. Markdown's
-email-style <a href="#blockquote">blockquoting</a> and
-multi-paragraph <a href="#list">list items</a> work best -- and
-look better -- when you format them with hard breaks.</p>
-<h3 id="header">Headers</h3>
-<p>Markdown supports two styles of headers, <a href=
-"http://docutils.sourceforge.net/mirror/setext.html">Setext</a> and
-<a href="http://www.aaronsw.com/2002/atx/">atx</a>.</p>
-<p>Setext-style headers are "underlined" using equal signs (for
-first-level headers) and dashes (for second-level headers). For
-example:</p>
-<pre>
-<code>This is an H1
-=============
-
-This is an H2
--------------
-</code>
-</pre>
-<p>Any number of underlining <code>=</code>'s or <code>-</code>'s
-will work.</p>
-<p>Atx-style headers use 1-6 hash characters at the start of the
-line, corresponding to header levels 1-6. For example:</p>
-<pre>
-<code># This is an H1
-
-## This is an H2
-
-###### This is an H6
-</code>
-</pre>
-<p>Optionally, you may "close" atx-style headers. This is purely
-cosmetic -- you can use this if you think it looks better. The
-closing hashes don't even need to match the number of hashes used
-to open the header. (The number of opening hashes determines the
-header level.) :</p>
-<pre>
-<code># This is an H1 #
-
-## This is an H2 ##
-
-### This is an H3 ######
-</code>
-</pre>
-<h3 id="blockquote">Blockquotes</h3>
-<p>Markdown uses email-style <code>&gt;</code> characters for
-blockquoting. If you're familiar with quoting passages of text in
-an email message, then you know how to create a blockquote in
-Markdown. It looks best if you hard wrap the text and put a
-<code>&gt;</code> before every line:</p>
-<pre>
-<code>&gt; This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
-&gt; consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
-&gt; Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
-&gt;
-&gt; Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
-&gt; id sem consectetuer libero luctus adipiscing.
-</code>
-</pre>
-<p>Markdown allows you to be lazy and only put the
-<code>&gt;</code> before the first line of a hard-wrapped
-paragraph:</p>
-<pre>
-<code>&gt; This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
-consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
-Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
-
-&gt; Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
-id sem consectetuer libero luctus adipiscing.
-</code>
-</pre>
-<p>Blockquotes can be nested (i.e. a blockquote-in-a-blockquote) by
-adding additional levels of <code>&gt;</code>:</p>
-<pre>
-<code>&gt; This is the first level of quoting.
-&gt;
-&gt; &gt; This is nested blockquote.
-&gt;
-&gt; Back to the first level.
-</code>
-</pre>
-<p>Blockquotes can contain other Markdown elements, including
-headers, lists, and code blocks:</p>
-<pre>
-<code>&gt; ## This is a header.
-&gt;
-&gt; 1. This is the first list item.
-&gt; 2. This is the second list item.
-&gt;
-&gt; Here's some example code:
-&gt;
-&gt; return shell_exec("echo $input | $markdown_script");
-</code>
-</pre>
-<p>Any decent text editor should make email-style quoting easy. For
-example, with BBEdit, you can make a selection and choose Increase
-Quote Level from the Text menu.</p>
-<h3 id="list">Lists</h3>
-<p>Markdown supports ordered (numbered) and unordered (bulleted)
-lists.</p>
-<p>Unordered lists use asterisks, pluses, and hyphens --
-interchangably -- as list markers:</p>
-<pre>
-<code>* Red
-* Green
-* Blue
-</code>
-</pre>
-<p>is equivalent to:</p>
-<pre>
-<code>+ Red
-+ Green
-+ Blue
-</code>
-</pre>
-<p>and:</p>
-<pre>
-<code>- Red
-- Green
-- Blue
-</code>
-</pre>
-<p>Ordered lists use numbers followed by periods:</p>
-<pre>
-<code>1. Bird
-2. McHale
-3. Parish
-</code>
-</pre>
-<p>It's important to note that the actual numbers you use to mark
-the list have no effect on the HTML output Markdown produces. The
-HTML Markdown produces from the above list is:</p>
-<pre>
-<code>&lt;ol&gt;
-&lt;li&gt;Bird&lt;/li&gt;
-&lt;li&gt;McHale&lt;/li&gt;
-&lt;li&gt;Parish&lt;/li&gt;
-&lt;/ol&gt;
-</code>
-</pre>
-<p>If you instead wrote the list in Markdown like this:</p>
-<pre>
-<code>1. Bird
-1. McHale
-1. Parish
-</code>
-</pre>
-<p>or even:</p>
-<pre>
-<code>3. Bird
-1. McHale
-8. Parish
-</code>
-</pre>
-<p>you'd get the exact same HTML output. The point is, if you want
-to, you can use ordinal numbers in your ordered Markdown lists, so
-that the numbers in your source match the numbers in your published
-HTML. But if you want to be lazy, you don't have to.</p>
-<p>If you do use lazy list numbering, however, you should still
-start the list with the number 1. At some point in the future,
-Markdown may support starting ordered lists at an arbitrary
-number.</p>
-<p>List markers typically start at the left margin, but may be
-indented by up to three spaces. List markers must be followed by
-one or more spaces or a tab.</p>
-<p>To make lists look nice, you can wrap items with hanging
-indents:</p>
-<pre>
-<code>* Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
- Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
- viverra nec, fringilla in, laoreet vitae, risus.
-* Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
- Suspendisse id sem consectetuer libero luctus adipiscing.
-</code>
-</pre>
-<p>But if you want to be lazy, you don't have to:</p>
-<pre>
-<code>* Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
-Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
-viverra nec, fringilla in, laoreet vitae, risus.
-* Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
-Suspendisse id sem consectetuer libero luctus adipiscing.
-</code>
-</pre>
-<p>If list items are separated by blank lines, Markdown will wrap
-the items in <code>&lt;p&gt;</code> tags in the HTML output. For
-example, this input:</p>
-<pre>
-<code>* Bird
-* Magic
-</code>
-</pre>
-<p>will turn into:</p>
-<pre>
-<code>&lt;ul&gt;
-&lt;li&gt;Bird&lt;/li&gt;
-&lt;li&gt;Magic&lt;/li&gt;
-&lt;/ul&gt;
-</code>
-</pre>
-<p>But this:</p>
-<pre>
-<code>* Bird
-
-* Magic
-</code>
-</pre>
-<p>will turn into:</p>
-<pre>
-<code>&lt;ul&gt;
-&lt;li&gt;&lt;p&gt;Bird&lt;/p&gt;&lt;/li&gt;
-&lt;li&gt;&lt;p&gt;Magic&lt;/p&gt;&lt;/li&gt;
-&lt;/ul&gt;
-</code>
-</pre>
-<p>List items may consist of multiple paragraphs. Each subsequent
-paragraph in a list item must be intended by either 4 spaces or one
-tab:</p>
-<pre>
-<code>1. This is a list item with two paragraphs. Lorem ipsum dolor
- sit amet, consectetuer adipiscing elit. Aliquam hendrerit
- mi posuere lectus.
-
- Vestibulum enim wisi, viverra nec, fringilla in, laoreet
- vitae, risus. Donec sit amet nisl. Aliquam semper ipsum
- sit amet velit.
-
-2. Suspendisse id sem consectetuer libero luctus adipiscing.
-</code>
-</pre>
-<p>It looks nice if you indent every line of the subsequent
-paragraphs, but here again, Markdown will allow you to be lazy:</p>
-<pre>
-<code>* This is a list item with two paragraphs.
-
- This is the second paragraph in the list item. You're
-only required to indent the first line. Lorem ipsum dolor
-sit amet, consectetuer adipiscing elit.
-
-* Another item in the same list.
-</code>
-</pre>
-<p>To put a blockquote within a list item, the blockquote's
-<code>&gt;</code> delimiters need to be indented:</p>
-<pre>
-<code>* A list item with a blockquote:
-
- &gt; This is a blockquote
- &gt; inside a list item.
-</code>
-</pre>
-<p>To put a code block within a list item, the code block needs to
-be indented <em>twice</em> -- 8 spaces or two tabs:</p>
-<pre>
-<code>* A list item with a code block:
-
- &lt;code goes here&gt;
-</code>
-</pre>
-<p>It's worth noting that it's possible to trigger an ordered list
-by accident, by writing something like this:</p>
-<pre>
-<code>1986. What a great season.
-</code>
-</pre>
-<p>In other words, a <em>number-period-space</em> sequence at the
-beginning of a line. To avoid this, you can backslash-escape the
-period:</p>
-<pre>
-<code>1986\. What a great season.
-</code>
-</pre>
-<h3 id="precode">Code Blocks</h3>
-<p>Pre-formatted code blocks are used for writing about programming
-or markup source code. Rather than forming normal paragraphs, the
-lines of a code block are interpreted literally. Markdown wraps a
-code block in both <code>&lt;pre&gt;</code> and
-<code>&lt;code&gt;</code> tags.</p>
-<p>To produce a code block in Markdown, simply indent every line of
-the block by at least 4 spaces or 1 tab. For example, given this
-input:</p>
-<pre>
-<code>This is a normal paragraph:
-
- This is a code block.
-</code>
-</pre>
-<p>Markdown will generate:</p>
-<pre>
-<code>&lt;p&gt;This is a normal paragraph:&lt;/p&gt;
-
-&lt;pre&gt;&lt;code&gt;This is a code block.
-&lt;/code&gt;&lt;/pre&gt;
-</code>
-</pre>
-<p>One level of indentation -- 4 spaces or 1 tab -- is removed from
-each line of the code block. For example, this:</p>
-<pre>
-<code>Here is an example of AppleScript:
-
- tell application "Foo"
- beep
- end tell
-</code>
-</pre>
-<p>will turn into:</p>
-<pre>
-<code>&lt;p&gt;Here is an example of AppleScript:&lt;/p&gt;
-
-&lt;pre&gt;&lt;code&gt;tell application "Foo"
- beep
-end tell
-&lt;/code&gt;&lt;/pre&gt;
-</code>
-</pre>
-<p>A code block continues until it reaches a line that is not
-indented (or the end of the article).</p>
-<p>Within a code block, ampersands (<code>&amp;</code>) and angle
-brackets (<code>&lt;</code> and <code>&gt;</code>) are
-automatically converted into HTML entities. This makes it very easy
-to include example HTML source code using Markdown -- just paste it
-and indent it, and Markdown will handle the hassle of encoding the
-ampersands and angle brackets. For example, this:</p>
-<pre>
-<code> &lt;div class="footer"&gt;
- &amp;copy; 2004 Foo Corporation
- &lt;/div&gt;
-</code>
-</pre>
-<p>will turn into:</p>
-<pre>
-<code>&lt;pre&gt;&lt;code&gt;&amp;lt;div class="footer"&amp;gt;
- &amp;amp;copy; 2004 Foo Corporation
-&amp;lt;/div&amp;gt;
-&lt;/code&gt;&lt;/pre&gt;
-</code>
-</pre>
-<p>Regular Markdown syntax is not processed within code blocks.
-E.g., asterisks are just literal asterisks within a code block.
-This means it's also easy to use Markdown to write about Markdown's
-own syntax.</p>
-<h3 id="hr">Horizontal Rules</h3>
-<p>You can produce a horizontal rule tag (<code>&lt;hr
-/&gt;</code>) by placing three or more hyphens, asterisks, or
-underscores on a line by themselves. If you wish, you may use
-spaces between the hyphens or asterisks. Each of the following
-lines will produce a horizontal rule:</p>
-<pre>
-<code>* * *
-
-***
-
-*****
-
-- - -
-
----------------------------------------
-
-_ _ _
-</code>
-</pre>
-<hr>
-<h2 id="span">Span Elements</h2>
-<h3 id="link">Links</h3>
-<p>Markdown supports two style of links: <em>inline</em> and
-<em>reference</em>.</p>
-<p>In both styles, the link text is delimited by [square
-brackets].</p>
-<p>To create an inline link, use a set of regular parentheses
-immediately after the link text's closing square bracket. Inside
-the parentheses, put the URL where you want the link to point,
-along with an <em>optional</em> title for the link, surrounded in
-quotes. For example:</p>
-<pre>
-<code>This is [an example](http://example.com/ "Title") inline link.
-
-[This link](http://example.net/) has no title attribute.
-</code>
-</pre>
-<p>Will produce:</p>
-<pre>
-<code>&lt;p&gt;This is &lt;a href="http://example.com/" title="Title"&gt;
-an example&lt;/a&gt; inline link.&lt;/p&gt;
-
-&lt;p&gt;&lt;a href="http://example.net/"&gt;This link&lt;/a&gt; has no
-title attribute.&lt;/p&gt;
-</code>
-</pre>
-<p>If you're referring to a local resource on the same server, you
-can use relative paths:</p>
-<pre>
-<code>See my [About](/about/) page for details.
-</code>
-</pre>
-<p>Reference-style links use a second set of square brackets,
-inside which you place a label of your choosing to identify the
-link:</p>
-<pre>
-<code>This is [an example][id] reference-style link.
-</code>
-</pre>
-<p>You can optionally use a space to separate the sets of
-brackets:</p>
-<pre>
-<code>This is [an example] [id] reference-style link.
-</code>
-</pre>
-<p>Then, anywhere in the document, you define your link label like
-this, on a line by itself:</p>
-<pre>
-<code>[id]: http://example.com/ "Optional Title Here"
-</code>
-</pre>
-<p>That is:</p>
-<ul>
-<li>Square brackets containing the link identifier (optionally
-indented from the left margin using up to three spaces);</li>
-<li>followed by a colon;</li>
-<li>followed by one or more spaces (or tabs);</li>
-<li>followed by the URL for the link;</li>
-<li>optionally followed by a title attribute for the link, enclosed
-in double or single quotes.</li>
-</ul>
-<p>The link URL may, optionally, be surrounded by angle
-brackets:</p>
-<pre>
-<code>[id]: &lt;http://example.com/&gt; "Optional Title Here"
-</code>
-</pre>
-<p>You can put the title attribute on the next line and use extra
-spaces or tabs for padding, which tends to look better with longer
-URLs:</p>
-<pre>
-<code>[id]: http://example.com/longish/path/to/resource/here
- "Optional Title Here"
-</code>
-</pre>
-<p>Link definitions are only used for creating links during
-Markdown processing, and are stripped from your document in the
-HTML output.</p>
-<p>Link definition names may constist of letters, numbers, spaces,
-and punctuation -- but they are <em>not</em> case sensitive. E.g.
-these two links:</p>
-<pre>
-<code>[link text][a]
-[link text][A]
-</code>
-</pre>
-<p>are equivalent.</p>
-<p>The <em>implicit link name</em> shortcut allows you to omit the
-name of the link, in which case the link text itself is used as the
-name. Just use an empty set of square brackets -- e.g., to link the
-word "Google" to the google.com web site, you could simply
-write:</p>
-<pre>
-<code>[Google][]
-</code>
-</pre>
-<p>And then define the link:</p>
-<pre>
-<code>[Google]: http://google.com/
-</code>
-</pre>
-<p>Because link names may contain spaces, this shortcut even works
-for multiple words in the link text:</p>
-<pre>
-<code>Visit [Daring Fireball][] for more information.
-</code>
-</pre>
-<p>And then define the link:</p>
-<pre>
-<code>[Daring Fireball]: http://daringfireball.net/
-</code>
-</pre>
-<p>Link definitions can be placed anywhere in your Markdown
-document. I tend to put them immediately after each paragraph in
-which they're used, but if you want, you can put them all at the
-end of your document, sort of like footnotes.</p>
-<p>Here's an example of reference links in action:</p>
-<pre>
-<code>I get 10 times more traffic from [Google] [1] than from
-[Yahoo] [2] or [MSN] [3].
-
- [1]: http://google.com/ "Google"
- [2]: http://search.yahoo.com/ "Yahoo Search"
- [3]: http://search.msn.com/ "MSN Search"
-</code>
-</pre>
-<p>Using the implicit link name shortcut, you could instead
-write:</p>
-<pre>
-<code>I get 10 times more traffic from [Google][] than from
-[Yahoo][] or [MSN][].
-
- [google]: http://google.com/ "Google"
- [yahoo]: http://search.yahoo.com/ "Yahoo Search"
- [msn]: http://search.msn.com/ "MSN Search"
-</code>
-</pre>
-<p>Both of the above examples will produce the following HTML
-output:</p>
-<pre>
-<code>&lt;p&gt;I get 10 times more traffic from &lt;a href="http://google.com/"
-title="Google"&gt;Google&lt;/a&gt; than from
-&lt;a href="http://search.yahoo.com/" title="Yahoo Search"&gt;Yahoo&lt;/a&gt;
-or &lt;a href="http://search.msn.com/" title="MSN Search"&gt;MSN&lt;/a&gt;.&lt;/p&gt;
-</code>
-</pre>
-<p>For comparison, here is the same paragraph written using
-Markdown's inline link style:</p>
-<pre>
-<code>I get 10 times more traffic from [Google](http://google.com/ "Google")
-than from [Yahoo](http://search.yahoo.com/ "Yahoo Search") or
-[MSN](http://search.msn.com/ "MSN Search").
-</code>
-</pre>
-<p>The point of reference-style links is not that they're easier to
-write. The point is that with reference-style links, your document
-source is vastly more readable. Compare the above examples: using
-reference-style links, the paragraph itself is only 81 characters
-long; with inline-style links, it's 176 characters; and as raw
-HTML, it's 234 characters. In the raw HTML, there's more markup
-than there is text.</p>
-<p>With Markdown's reference-style links, a source document much
-more closely resembles the final output, as rendered in a browser.
-By allowing you to move the markup-related metadata out of the
-paragraph, you can add links without interrupting the narrative
-flow of your prose.</p>
-<h3 id="em">Emphasis</h3>
-<p>Markdown treats asterisks (<code>*</code>) and underscores
-(<code>_</code>) as indicators of emphasis. Text wrapped with one
-<code>*</code> or <code>_</code> will be wrapped with an HTML
-<code>&lt;em&gt;</code> tag; double <code>*</code>'s or
-<code>_</code>'s will be wrapped with an HTML
-<code>&lt;strong&gt;</code> tag. E.g., this input:</p>
-<pre>
-<code>*single asterisks*
-
-_single underscores_
-
-**double asterisks**
-
-__double underscores__
-</code>
-</pre>
-<p>will produce:</p>
-<pre>
-<code>&lt;em&gt;single asterisks&lt;/em&gt;
-
-&lt;em&gt;single underscores&lt;/em&gt;
-
-&lt;strong&gt;double asterisks&lt;/strong&gt;
-
-&lt;strong&gt;double underscores&lt;/strong&gt;
-</code>
-</pre>
-<p>You can use whichever style you prefer; the lone restriction is
-that the same character must be used to open and close an emphasis
-span.</p>
-<p>Emphasis can be used in the middle of a word:</p>
-<pre>
-<code>un*fucking*believable
-</code>
-</pre>
-<p>But if you surround an <code>*</code> or <code>_</code> with
-spaces, it'll be treated as a literal asterisk or underscore.</p>
-<p>To produce a literal asterisk or underscore at a position where
-it would otherwise be used as an emphasis delimiter, you can
-backslash escape it:</p>
-<pre>
-<code>\*this text is surrounded by literal asterisks\*
-</code>
-</pre>
-<h3 id="code">Code</h3>
-<p>To indicate a span of code, wrap it with backtick quotes
-(<code>`</code>). Unlike a pre-formatted code block, a code span
-indicates code within a normal paragraph. For example:</p>
-<pre>
-<code>Use the `printf()` function.
-</code>
-</pre>
-<p>will produce:</p>
-<pre>
-<code>&lt;p&gt;Use the &lt;code&gt;printf()&lt;/code&gt; function.&lt;/p&gt;
-</code>
-</pre>
-<p>To include a literal backtick character within a code span, you
-can use multiple backticks as the opening and closing
-delimiters:</p>
-<pre>
-<code>``There is a literal backtick (`) here.``
-</code>
-</pre>
-<p>which will produce this:</p>
-<pre>
-<code>&lt;p&gt;&lt;code&gt;There is a literal backtick (`) here.&lt;/code&gt;&lt;/p&gt;
-</code>
-</pre>
-<p>The backtick delimiters surrounding a code span may include
-spaces -- one after the opening, one before the closing. This
-allows you to place literal backtick characters at the beginning or
-end of a code span:</p>
-<pre>
-<code>A single backtick in a code span: `` ` ``
-
-A backtick-delimited string in a code span: `` `foo` ``
-</code>
-</pre>
-<p>will produce:</p>
-<pre>
-<code>&lt;p&gt;A single backtick in a code span: &lt;code&gt;`&lt;/code&gt;&lt;/p&gt;
-
-&lt;p&gt;A backtick-delimited string in a code span: &lt;code&gt;`foo`&lt;/code&gt;&lt;/p&gt;
-</code>
-</pre>
-<p>With a code span, ampersands and angle brackets are encoded as
-HTML entities automatically, which makes it easy to include example
-HTML tags. Markdown will turn this:</p>
-<pre>
-<code>Please don't use any `&lt;blink&gt;` tags.
-</code>
-</pre>
-<p>into:</p>
-<pre>
-<code>&lt;p&gt;Please don't use any &lt;code&gt;&amp;lt;blink&amp;gt;&lt;/code&gt; tags.&lt;/p&gt;
-</code>
-</pre>
-<p>You can write this:</p>
-<pre>
-<code>`&amp;#8212;` is the decimal-encoded equivalent of `&amp;mdash;`.
-</code>
-</pre>
-<p>to produce:</p>
-<pre>
-<code>&lt;p&gt;&lt;code&gt;&amp;amp;#8212;&lt;/code&gt; is the decimal-encoded
-equivalent of &lt;code&gt;&amp;amp;mdash;&lt;/code&gt;.&lt;/p&gt;
-</code>
-</pre>
-<h3 id="img">Images</h3>
-<p>Admittedly, it's fairly difficult to devise a "natural" syntax
-for placing images into a plain text document format.</p>
-<p>Markdown uses an image syntax that is intended to resemble the
-syntax for links, allowing for two styles: <em>inline</em> and
-<em>reference</em>.</p>
-<p>Inline image syntax looks like this:</p>
-<pre>
-<code>![Alt text](/path/to/img.jpg)
-
-![Alt text](/path/to/img.jpg "Optional title")
-</code>
-</pre>
-<p>That is:</p>
-<ul>
-<li>An exclamation mark: <code>!</code>;</li>
-<li>followed by a set of square brackets, containing the
-<code>alt</code> attribute text for the image;</li>
-<li>followed by a set of parentheses, containing the URL or path to
-the image, and an optional <code>title</code> attribute enclosed in
-double or single quotes.</li>
-</ul>
-<p>Reference-style image syntax looks like this:</p>
-<pre>
-<code>![Alt text][id]
-</code>
-</pre>
-<p>Where "id" is the name of a defined image reference. Image
-references are defined using syntax identical to link
-references:</p>
-<pre>
-<code>[id]: url/to/image "Optional title attribute"
-</code>
-</pre>
-<p>As of this writing, Markdown has no syntax for specifying the
-dimensions of an image; if this is important to you, you can simply
-use regular HTML <code>&lt;img&gt;</code> tags.</p>
-<hr>
-<h2 id="misc">Miscellaneous</h2>
-<h3 id="autolink">Automatic Links</h3>
-<p>Markdown supports a shortcut style for creating "automatic"
-links for URLs and email addresses: simply surround the URL or
-email address with angle brackets. What this means is that if you
-want to show the actual text of a URL or email address, and also
-have it be a clickable link, you can do this:</p>
-<pre>
-<code>&lt;http://example.com/&gt;
-</code>
-</pre>
-<p>Markdown will turn this into:</p>
-<pre>
-<code>&lt;a href="http://example.com/"&gt;http://example.com/&lt;/a&gt;
-</code>
-</pre>
-<p>Automatic links for email addresses work similarly, except that
-Markdown will also perform a bit of randomized decimal and hex
-entity-encoding to help obscure your address from
-address-harvesting spambots. For example, Markdown will turn
-this:</p>
-<pre>
-<code>&lt;address@example.com&gt;
-</code>
-</pre>
-<p>into something like this:</p>
-<pre>
-<code>&lt;a href="&amp;#x6D;&amp;#x61;i&amp;#x6C;&amp;#x74;&amp;#x6F;:&amp;#x61;&amp;#x64;&amp;#x64;&amp;#x72;&amp;#x65;
-&amp;#115;&amp;#115;&amp;#64;&amp;#101;&amp;#120;&amp;#x61;&amp;#109;&amp;#x70;&amp;#x6C;e&amp;#x2E;&amp;#99;&amp;#111;
-&amp;#109;"&gt;&amp;#x61;&amp;#x64;&amp;#x64;&amp;#x72;&amp;#x65;&amp;#115;&amp;#115;&amp;#64;&amp;#101;&amp;#120;&amp;#x61;
-&amp;#109;&amp;#x70;&amp;#x6C;e&amp;#x2E;&amp;#99;&amp;#111;&amp;#109;&lt;/a&gt;
-</code>
-</pre>
-<p>which will render in a browser as a clickable link to
-"address@example.com".</p>
-<p>(This sort of entity-encoding trick will indeed fool many, if
-not most, address-harvesting bots, but it definitely won't fool all
-of them. It's better than nothing, but an address published in this
-way will probably eventually start receiving spam.)</p>
-<h3 id="backslash">Backslash Escapes</h3>
-<p>Markdown allows you to use backslash escapes to generate literal
-characters which would otherwise have special meaning in Markdown's
-formatting syntax. For example, if you wanted to surround a word
-with literal asterisks (instead of an HTML <code>&lt;em&gt;</code>
-tag), you can backslashes before the asterisks, like this:</p>
-<pre>
-<code>\*literal asterisks\*
-</code>
-</pre>
-<p>Markdown provides backslash escapes for the following
-characters:</p>
-<pre>
-<code>\ backslash
-` backtick
-* asterisk
-_ underscore
-{} curly braces
-[] square brackets
-() parentheses
-# hash mark
-+ plus sign
-- minus sign (hyphen)
-. dot
-! exclamation mark
-</code>
-</pre>
-</body>
-</html>
diff --git a/MarkdownTest/Tests_2004/Nested blockquotes.text-out b/MarkdownTest/Tests_2004/Nested blockquotes.text-out
deleted file mode 100644
index 291201e..0000000
--- a/MarkdownTest/Tests_2004/Nested blockquotes.text-out
+++ /dev/null
@@ -1,17 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
-<html>
-<head>
-<meta name="generator" content=
-"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org">
-<title></title>
-</head>
-<body>
-<blockquote>
-<p>foo</p>
-<blockquote>
-<p>bar</p>
-</blockquote>
-<p>foo</p>
-</blockquote>
-</body>
-</html>
diff --git a/MarkdownTest/Tests_2004/Nested blockquotes.text-res b/MarkdownTest/Tests_2004/Nested blockquotes.text-res
deleted file mode 100644
index 291201e..0000000
--- a/MarkdownTest/Tests_2004/Nested blockquotes.text-res
+++ /dev/null
@@ -1,17 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
-<html>
-<head>
-<meta name="generator" content=
-"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org">
-<title></title>
-</head>
-<body>
-<blockquote>
-<p>foo</p>
-<blockquote>
-<p>bar</p>
-</blockquote>
-<p>foo</p>
-</blockquote>
-</body>
-</html>
diff --git a/MarkdownTest/Tests_2004/Ordered and unordered lists.text-out b/MarkdownTest/Tests_2004/Ordered and unordered lists.text-out
deleted file mode 100644
index 5e19e71..0000000
--- a/MarkdownTest/Tests_2004/Ordered and unordered lists.text-out
+++ /dev/null
@@ -1,159 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
-<html>
-<head>
-<meta name="generator" content=
-"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org">
-<title></title>
-</head>
-<body>
-<h2>Unordered</h2>
-<p>Asterisks tight:</p>
-<ul>
-<li>asterisk 1</li>
-<li>asterisk 2</li>
-<li>asterisk 3</li>
-</ul>
-<p>Asterisks loose:</p>
-<ul>
-<li>
-<p>asterisk 1</p>
-</li>
-<li>
-<p>asterisk 2</p>
-</li>
-<li>
-<p>asterisk 3</p>
-</li>
-</ul>
-<hr>
-<p>Pluses tight:</p>
-<ul>
-<li>Plus 1</li>
-<li>Plus 2</li>
-<li>Plus 3</li>
-</ul>
-<p>Pluses loose:</p>
-<ul>
-<li>
-<p>Plus 1</p>
-</li>
-<li>
-<p>Plus 2</p>
-</li>
-<li>
-<p>Plus 3</p>
-</li>
-</ul>
-<hr>
-<p>Minuses tight:</p>
-<ul>
-<li>Minus 1</li>
-<li>Minus 2</li>
-<li>Minus 3</li>
-</ul>
-<p>Minuses loose:</p>
-<ul>
-<li>
-<p>Minus 1</p>
-</li>
-<li>
-<p>Minus 2</p>
-</li>
-<li>
-<p>Minus 3</p>
-</li>
-</ul>
-<h2>Ordered</h2>
-<p>Tight:</p>
-<ol>
-<li>First</li>
-<li>Second</li>
-<li>Third</li>
-</ol>
-<p>and:</p>
-<ol>
-<li>One</li>
-<li>Two</li>
-<li>Three</li>
-</ol>
-<p>Loose using tabs:</p>
-<ol>
-<li>
-<p>First</p>
-</li>
-<li>
-<p>Second</p>
-</li>
-<li>
-<p>Third</p>
-</li>
-</ol>
-<p>and using spaces:</p>
-<ol>
-<li>
-<p>One</p>
-</li>
-<li>
-<p>Two</p>
-</li>
-<li>
-<p>Three</p>
-</li>
-</ol>
-<p>Multiple paragraphs:</p>
-<ol>
-<li>
-<p>Item 1, graf one.</p>
-<p>Item 2. graf two. The quick brown fox jumped over the lazy dog's
-back.</p>
-</li>
-<li>
-<p>Item 2.</p>
-</li>
-<li>
-<p>Item 3.</p>
-</li>
-</ol>
-<h2>Nested</h2>
-<ul>
-<li>Tab
-<ul>
-<li>Tab
-<ul>
-<li>Tab</li>
-</ul>
-</li>
-</ul>
-</li>
-</ul>
-<p>Here's another:</p>
-<ol>
-<li>First</li>
-<li>Second:
-<ul>
-<li>Fee</li>
-<li>Fie</li>
-<li>Foe</li>
-</ul>
-</li>
-<li>Third</li>
-</ol>
-<p>Same thing but with paragraphs:</p>
-<ol>
-<li>
-<p>First</p>
-</li>
-<li>
-<p>Second:</p>
-<ul>
-<li>Fee</li>
-<li>Fie</li>
-<li>Foe</li>
-</ul>
-</li>
-<li>
-<p>Third</p>
-</li>
-</ol>
-</body>
-</html>
diff --git a/MarkdownTest/Tests_2004/Ordered and unordered lists.text-res b/MarkdownTest/Tests_2004/Ordered and unordered lists.text-res
deleted file mode 100644
index 5e19e71..0000000
--- a/MarkdownTest/Tests_2004/Ordered and unordered lists.text-res
+++ /dev/null
@@ -1,159 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
-<html>
-<head>
-<meta name="generator" content=
-"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org">
-<title></title>
-</head>
-<body>
-<h2>Unordered</h2>
-<p>Asterisks tight:</p>
-<ul>
-<li>asterisk 1</li>
-<li>asterisk 2</li>
-<li>asterisk 3</li>
-</ul>
-<p>Asterisks loose:</p>
-<ul>
-<li>
-<p>asterisk 1</p>
-</li>
-<li>
-<p>asterisk 2</p>
-</li>
-<li>
-<p>asterisk 3</p>
-</li>
-</ul>
-<hr>
-<p>Pluses tight:</p>
-<ul>
-<li>Plus 1</li>
-<li>Plus 2</li>
-<li>Plus 3</li>
-</ul>
-<p>Pluses loose:</p>
-<ul>
-<li>
-<p>Plus 1</p>
-</li>
-<li>
-<p>Plus 2</p>
-</li>
-<li>
-<p>Plus 3</p>
-</li>
-</ul>
-<hr>
-<p>Minuses tight:</p>
-<ul>
-<li>Minus 1</li>
-<li>Minus 2</li>
-<li>Minus 3</li>
-</ul>
-<p>Minuses loose:</p>
-<ul>
-<li>
-<p>Minus 1</p>
-</li>
-<li>
-<p>Minus 2</p>
-</li>
-<li>
-<p>Minus 3</p>
-</li>
-</ul>
-<h2>Ordered</h2>
-<p>Tight:</p>
-<ol>
-<li>First</li>
-<li>Second</li>
-<li>Third</li>
-</ol>
-<p>and:</p>
-<ol>
-<li>One</li>
-<li>Two</li>
-<li>Three</li>
-</ol>
-<p>Loose using tabs:</p>
-<ol>
-<li>
-<p>First</p>
-</li>
-<li>
-<p>Second</p>
-</li>
-<li>
-<p>Third</p>
-</li>
-</ol>
-<p>and using spaces:</p>
-<ol>
-<li>
-<p>One</p>
-</li>
-<li>
-<p>Two</p>
-</li>
-<li>
-<p>Three</p>
-</li>
-</ol>
-<p>Multiple paragraphs:</p>
-<ol>
-<li>
-<p>Item 1, graf one.</p>
-<p>Item 2. graf two. The quick brown fox jumped over the lazy dog's
-back.</p>
-</li>
-<li>
-<p>Item 2.</p>
-</li>
-<li>
-<p>Item 3.</p>
-</li>
-</ol>
-<h2>Nested</h2>
-<ul>
-<li>Tab
-<ul>
-<li>Tab
-<ul>
-<li>Tab</li>
-</ul>
-</li>
-</ul>
-</li>
-</ul>
-<p>Here's another:</p>
-<ol>
-<li>First</li>
-<li>Second:
-<ul>
-<li>Fee</li>
-<li>Fie</li>
-<li>Foe</li>
-</ul>
-</li>
-<li>Third</li>
-</ol>
-<p>Same thing but with paragraphs:</p>
-<ol>
-<li>
-<p>First</p>
-</li>
-<li>
-<p>Second:</p>
-<ul>
-<li>Fee</li>
-<li>Fie</li>
-<li>Foe</li>
-</ul>
-</li>
-<li>
-<p>Third</p>
-</li>
-</ol>
-</body>
-</html>
diff --git a/MarkdownTest/Tests_2004/Strong and em together.text-out b/MarkdownTest/Tests_2004/Strong and em together.text-out
deleted file mode 100644
index b596c19..0000000
--- a/MarkdownTest/Tests_2004/Strong and em together.text-out
+++ /dev/null
@@ -1,14 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
-<html>
-<head>
-<meta name="generator" content=
-"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org">
-<title></title>
-</head>
-<body>
-<p><strong><em>This is strong and em.</em></strong></p>
-<p>So is <strong><em>this</em></strong> word.</p>
-<p><strong><em>This is strong and em.</em></strong></p>
-<p>So is <strong><em>this</em></strong> word.</p>
-</body>
-</html>
diff --git a/MarkdownTest/Tests_2004/Strong and em together.text-res b/MarkdownTest/Tests_2004/Strong and em together.text-res
deleted file mode 100644
index b596c19..0000000
--- a/MarkdownTest/Tests_2004/Strong and em together.text-res
+++ /dev/null
@@ -1,14 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
-<html>
-<head>
-<meta name="generator" content=
-"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org">
-<title></title>
-</head>
-<body>
-<p><strong><em>This is strong and em.</em></strong></p>
-<p>So is <strong><em>this</em></strong> word.</p>
-<p><strong><em>This is strong and em.</em></strong></p>
-<p>So is <strong><em>this</em></strong> word.</p>
-</body>
-</html>
diff --git a/MarkdownTest/Tests_2004/Tabs.text-out b/MarkdownTest/Tests_2004/Tabs.text-out
deleted file mode 100644
index 0cd92b1..0000000
--- a/MarkdownTest/Tests_2004/Tabs.text-out
+++ /dev/null
@@ -1,37 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
-<html>
-<head>
-<meta name="generator" content=
-"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org">
-<title></title>
-</head>
-<body>
-<ul>
-<li>
-<p>this is a list item indented with tabs</p>
-</li>
-<li>
-<p>this is a list item indented with spaces</p>
-</li>
-</ul>
-<p>Code:</p>
-<pre>
-<code>this code block is indented by one tab
-</code>
-</pre>
-<p>And:</p>
-<pre>
-<code> this code block is indented by two tabs
-</code>
-</pre>
-<p>And:</p>
-<pre>
-<code>+ this is an example list item
- indented with tabs
-
-+ this is an example list item
- indented with spaces
-</code>
-</pre>
-</body>
-</html>
diff --git a/MarkdownTest/Tests_2004/Tabs.text-res b/MarkdownTest/Tests_2004/Tabs.text-res
deleted file mode 100644
index 0cd92b1..0000000
--- a/MarkdownTest/Tests_2004/Tabs.text-res
+++ /dev/null
@@ -1,37 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
-<html>
-<head>
-<meta name="generator" content=
-"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org">
-<title></title>
-</head>
-<body>
-<ul>
-<li>
-<p>this is a list item indented with tabs</p>
-</li>
-<li>
-<p>this is a list item indented with spaces</p>
-</li>
-</ul>
-<p>Code:</p>
-<pre>
-<code>this code block is indented by one tab
-</code>
-</pre>
-<p>And:</p>
-<pre>
-<code> this code block is indented by two tabs
-</code>
-</pre>
-<p>And:</p>
-<pre>
-<code>+ this is an example list item
- indented with tabs
-
-+ this is an example list item
- indented with spaces
-</code>
-</pre>
-</body>
-</html>
diff --git a/MarkdownTest/Tests_2004/Tidyness.text-out b/MarkdownTest/Tests_2004/Tidyness.text-out
deleted file mode 100644
index ebae4c4..0000000
--- a/MarkdownTest/Tests_2004/Tidyness.text-out
+++ /dev/null
@@ -1,18 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
-<html>
-<head>
-<meta name="generator" content=
-"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org">
-<title></title>
-</head>
-<body>
-<blockquote>
-<p>A list within a blockquote:</p>
-<ul>
-<li>asterisk 1</li>
-<li>asterisk 2</li>
-<li>asterisk 3</li>
-</ul>
-</blockquote>
-</body>
-</html>
diff --git a/MarkdownTest/Tests_2004/Tidyness.text-res b/MarkdownTest/Tests_2004/Tidyness.text-res
deleted file mode 100644
index ebae4c4..0000000
--- a/MarkdownTest/Tests_2004/Tidyness.text-res
+++ /dev/null
@@ -1,18 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
-<html>
-<head>
-<meta name="generator" content=
-"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org">
-<title></title>
-</head>
-<body>
-<blockquote>
-<p>A list within a blockquote:</p>
-<ul>
-<li>asterisk 1</li>
-<li>asterisk 2</li>
-<li>asterisk 3</li>
-</ul>
-</blockquote>
-</body>
-</html>
diff --git a/MarkdownTest/Tests_2004/Yuri-Attributes.text-out b/MarkdownTest/Tests_2004/Yuri-Attributes.text-out
deleted file mode 100644
index 38fd233..0000000
--- a/MarkdownTest/Tests_2004/Yuri-Attributes.text-out
+++ /dev/null
@@ -1,29 +0,0 @@
-<html>
-<head>
-<meta name="generator" content=
-"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org">
-<title></title>
-</head>
-<body>
-<h1 id="lorem">Lorem ipsum</h1>
-<p>Dolor sit amet, consectetur adipisicing elit, sed do eiusmod
-tempor incididunt ut labore et dolore magna aliqua.</p>
-<ul>
-<li>
-<p class="first_item">Ut enim ad minim veniam, quis nostrud
-exercitation ullamco laboris nisi ut aliquip ex ea commodo
-consequat.</p>
-</li>
-<li>
-<p>Duis aute irure dolor in reprehenderit in voluptate velit esse
-cillum dolore eu fugiat nulla pariatur2. Excepteur sint occaecat
-cupidatat non proident, sunt in culpa qui officia deserunt mollit
-anim id est laborum.</p>
-</li>
-</ul>
-<p>Duis aute <strong type="term">irure</strong> dolor in
-reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
-pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
-culpa qui officia deserunt mollit anim id est laborum.</p>
-</body>
-</html>
diff --git a/MarkdownTest/Tests_2004/Yuri-Attributes.text-res b/MarkdownTest/Tests_2004/Yuri-Attributes.text-res
deleted file mode 100644
index 38fd233..0000000
--- a/MarkdownTest/Tests_2004/Yuri-Attributes.text-res
+++ /dev/null
@@ -1,29 +0,0 @@
-<html>
-<head>
-<meta name="generator" content=
-"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org">
-<title></title>
-</head>
-<body>
-<h1 id="lorem">Lorem ipsum</h1>
-<p>Dolor sit amet, consectetur adipisicing elit, sed do eiusmod
-tempor incididunt ut labore et dolore magna aliqua.</p>
-<ul>
-<li>
-<p class="first_item">Ut enim ad minim veniam, quis nostrud
-exercitation ullamco laboris nisi ut aliquip ex ea commodo
-consequat.</p>
-</li>
-<li>
-<p>Duis aute irure dolor in reprehenderit in voluptate velit esse
-cillum dolore eu fugiat nulla pariatur2. Excepteur sint occaecat
-cupidatat non proident, sunt in culpa qui officia deserunt mollit
-anim id est laborum.</p>
-</li>
-</ul>
-<p>Duis aute <strong type="term">irure</strong> dolor in
-reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
-pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
-culpa qui officia deserunt mollit anim id est laborum.</p>
-</body>
-</html>
diff --git a/MarkdownTest/Tests_2004/Yuri-Attributes.text~ b/MarkdownTest/Tests_2004/Yuri-Attributes.text~
deleted file mode 100644
index ba8fecd..0000000
--- a/MarkdownTest/Tests_2004/Yuri-Attributes.text~
+++ /dev/null
@@ -1,24 +0,0 @@
-
-Lorem ipsum {@id=lorem}
-=================================
-
-Dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor
-incididunt ut labore et dolore magna aliqua1. Ut enim ad minim veniam,
-quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
-commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
-velit esse cillum dolore eu fugiat nulla pariatur2. Excepteur sint
-occaecat cupidatat non proident, sunt in culpa qui officia deserunt
-mollit anim id est laborum.
-
-
-
- * Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore3 magna aliqua.
-
-Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
-
- 1. Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.%G↩%@
- 2. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt.
-
- Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. %G↩%@
- 3. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. %G↩%@
-
diff --git a/MarkdownTest/Tests_2004/Yuri-Email.text-out b/MarkdownTest/Tests_2004/Yuri-Email.text-out
deleted file mode 100644
index 2fc9c74..0000000
--- a/MarkdownTest/Tests_2004/Yuri-Email.text-out
+++ /dev/null
@@ -1,17 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
-<html>
-<head>
-<meta name="generator" content=
-"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org">
-<title></title>
-</head>
-<body>
-<p>Lorem ipsum <a href=
-"mailto:yuri@domain.org">yuri@domain.org</a>, etc.</p>
-<ul>
-<li>An email address in a list</li>
-<li><a href="mailto:yuri@domain.org">yuri@domain.org</a></li>
-<li>Another item.</li>
-</ul>
-</body>
-</html>
diff --git a/MarkdownTest/Tests_2004/Yuri-Email.text-res b/MarkdownTest/Tests_2004/Yuri-Email.text-res
deleted file mode 100644
index 2fc9c74..0000000
--- a/MarkdownTest/Tests_2004/Yuri-Email.text-res
+++ /dev/null
@@ -1,17 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
-<html>
-<head>
-<meta name="generator" content=
-"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org">
-<title></title>
-</head>
-<body>
-<p>Lorem ipsum <a href=
-"mailto:yuri@domain.org">yuri@domain.org</a>, etc.</p>
-<ul>
-<li>An email address in a list</li>
-<li><a href="mailto:yuri@domain.org">yuri@domain.org</a></li>
-<li>Another item.</li>
-</ul>
-</body>
-</html>
diff --git a/MarkdownTest/Tests_2004/Yuri-Footnotes.text-out b/MarkdownTest/Tests_2004/Yuri-Footnotes.text-out
deleted file mode 100644
index b934c10..0000000
--- a/MarkdownTest/Tests_2004/Yuri-Footnotes.text-out
+++ /dev/null
@@ -1,42 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
-<html>
-<head>
-<meta name="generator" content=
-"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org">
-<title></title>
-</head>
-<body>
-<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do
-eiusmod tempor incididunt ut labore et dolore magna aliqua[^2]. Ut
-enim ad minim veniam, quis nostrud exercitation ullamco laboris
-nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in
-reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
-pariatur[^1]. Excepteur sint occaecat cupidatat non proident, sunt
-in culpa qui officia deserunt mollit anim id est laborum.</p>
-<p>[^1]: Nemo enim ipsam voluptatem quia voluptas sit aspernatur
-aut odit aut fugit, sed quia consequuntur magni dolores eos qui
-ratione voluptatem sequi nesciunt.</p>
-<pre>
-<code> Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet,
- consectetur, adipisci velit, sed quia non numquam eius modi
- tempora incidunt ut labore et dolore magnam aliquam quaerat
- voluptatem.
-</code>
-</pre>
-<p>[^2]: Sed ut perspiciatis unde omnis iste natus error sit
-voluptatem accusantium doloremque laudantium, totam rem aperiam,
-eaque ipsa quae ab illo inventore veritatis et quasi architecto
-beatae vitae dicta sunt explicabo.</p>
-<ul>
-<li>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed
-do eiusmod tempor incididunt ut labore et dolore[^foo] magna
-aliqua.</li>
-</ul>
-<p>[^foo]: Ut enim ad minim veniam, quis nostrud exercitation
-ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
-<p>Duis aute irure dolor in reprehenderit in voluptate velit esse
-cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
-cupidatat non proident, sunt in culpa qui officia deserunt mollit
-anim id est laborum.</p>
-</body>
-</html>
diff --git a/MarkdownTest/Tests_2004/Yuri-Footnotes.text-res b/MarkdownTest/Tests_2004/Yuri-Footnotes.text-res
deleted file mode 100644
index 5752e27..0000000
--- a/MarkdownTest/Tests_2004/Yuri-Footnotes.text-res
+++ /dev/null
@@ -1,55 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
-<html>
-<head>
-<meta name="generator" content=
-"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org">
-<title></title>
-</head>
-<body>
-<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do
-eiusmod tempor incididunt ut labore et dolore magna
-aliqua<sup><a href="#fn1-903162597" id="fnr1-903162597" name=
-"fnr1-903162597">1</a></sup>. Ut enim ad minim veniam, quis nostrud
-exercitation ullamco laboris nisi ut aliquip ex ea commodo
-consequat. Duis aute irure dolor in reprehenderit in voluptate
-velit esse cillum dolore eu fugiat nulla pariatur<sup><a href=
-"#fn2-903162597" id="fnr2-903162597" name=
-"fnr2-903162597">2</a></sup>. Excepteur sint occaecat cupidatat non
-proident, sunt in culpa qui officia deserunt mollit anim id est
-laborum.</p>
-<ul>
-<li>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed
-do eiusmod tempor incididunt ut labore et dolore<sup><a href=
-"#fn3-903162597" id="fnr3-903162597" name=
-"fnr3-903162597">3</a></sup> magna aliqua.</li>
-</ul>
-<p>Duis aute irure dolor in reprehenderit in voluptate velit esse
-cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
-cupidatat non proident, sunt in culpa qui officia deserunt mollit
-anim id est laborum.</p>
-<div class="footnote">
-<hr>
-<ol>
-<li id="fn1-903162597">Sed ut perspiciatis unde omnis iste natus
-error sit voluptatem accusantium doloremque laudantium, totam rem
-aperiam, eaque ipsa quae ab illo inventore veritatis et quasi
-architecto beatae vitae dicta sunt explicabo.<a href=
-"#fnr1-903162597" class="footnoteBackLink" title=
-"Jump back to footnote 1 in the text">&#8617;</a></li>
-<li id="fn2-903162597">Nemo enim ipsam voluptatem quia voluptas sit
-aspernatur aut odit aut fugit, sed quia consequuntur magni dolores
-eos qui ratione voluptatem sequi nesciunt.
-<p>Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet,
-consectetur, adipisci velit, sed quia non numquam eius modi tempora
-incidunt ut labore et dolore magnam aliquam quaerat voluptatem.
-<a href="#fnr2-903162597" class="footnoteBackLink" title=
-"Jump back to footnote 1 in the text">&#8617;</a></p>
-</li>
-<li id="fn3-903162597">Ut enim ad minim veniam, quis nostrud
-exercitation ullamco laboris nisi ut aliquip ex ea commodo
-consequat. <a href="#fnr3-903162597" class="footnoteBackLink"
-title="Jump back to footnote 1 in the text">&#8617;</a></li>
-</ol>
-</div>
-</body>
-</html>
diff --git a/MarkdownTest/Tests_2004/Yuri-Links-in-Headers.text-out b/MarkdownTest/Tests_2004/Yuri-Links-in-Headers.text-out
deleted file mode 100644
index 1c5cf77..0000000
--- a/MarkdownTest/Tests_2004/Yuri-Links-in-Headers.text-out
+++ /dev/null
@@ -1,18 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
-<html>
-<head>
-<meta name="generator" content=
-"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org">
-<title></title>
-</head>
-<body>
-<h2>A plain header</h2>
-<p>Let's first have a plain header</p>
-<h1>An underlined header</h1>
-<p>(That's also useful)</p>
-<h1>A header with a <a href="http://www.link.com">link</a></h1>
-<p>First with a hash</p>
-<h2>Another with a <a href="http://www.link.com/">link</a></h2>
-<p>This time underlined</p>
-</body>
-</html>
diff --git a/MarkdownTest/Tests_2004/Yuri-Links-in-Headers.text-res b/MarkdownTest/Tests_2004/Yuri-Links-in-Headers.text-res
deleted file mode 100644
index 1c5cf77..0000000
--- a/MarkdownTest/Tests_2004/Yuri-Links-in-Headers.text-res
+++ /dev/null
@@ -1,18 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
-<html>
-<head>
-<meta name="generator" content=
-"HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org">
-<title></title>
-</head>
-<body>
-<h2>A plain header</h2>
-<p>Let's first have a plain header</p>
-<h1>An underlined header</h1>
-<p>(That's also useful)</p>
-<h1>A header with a <a href="http://www.link.com">link</a></h1>
-<p>First with a hash</p>
-<h2>Another with a <a href="http://www.link.com/">link</a></h2>
-<p>This time underlined</p>
-</body>
-</html>
diff --git a/MarkdownTest/readme.txt b/MarkdownTest/readme.txt
deleted file mode 100644
index 68047b5..0000000
--- a/MarkdownTest/readme.txt
+++ /dev/null
@@ -1 +0,0 @@
-MarkdownTest_1.0_2007-05-09 updated for the new version of tidy.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..c2c573e
--- /dev/null
+++ b/README.md
@@ -0,0 +1,64 @@
+[Python-Markdown][]
+===================
+
+[![Build Status][build-button]][build]
+[![Coverage Status][codecov-button]][codecov]
+[![Latest Version][mdversion-button]][md-pypi]
+[![Python Versions][pyversion-button]][md-pypi]
+[![BSD License][bsdlicense-button]][bsdlicense]
+[![Code of Conduct][codeofconduct-button]][Code of Conduct]
+
+[build-button]: https://github.com/Python-Markdown/markdown/workflows/CI/badge.svg?event=push
+[build]: https://github.com/Python-Markdown/markdown/actions?query=workflow%3ACI+event%3Apush
+[codecov-button]: https://codecov.io/gh/Python-Markdown/markdown/branch/master/graph/badge.svg
+[codecov]: https://codecov.io/gh/Python-Markdown/markdown
+[mdversion-button]: https://img.shields.io/pypi/v/Markdown.svg
+[md-pypi]: https://pypi.org/project/Markdown/
+[pyversion-button]: https://img.shields.io/pypi/pyversions/Markdown.svg
+[bsdlicense-button]: https://img.shields.io/badge/license-BSD-yellow.svg
+[bsdlicense]: https://opensource.org/licenses/BSD-3-Clause
+[codeofconduct-button]: https://img.shields.io/badge/code%20of%20conduct-contributor%20covenant-green.svg?style=flat-square
+[Code of Conduct]: https://github.com/Python-Markdown/markdown/blob/master/CODE_OF_CONDUCT.md
+
+This is a Python implementation of John Gruber's [Markdown][].
+It is almost completely compliant with the reference implementation,
+though there are a few known issues. See [Features][] for information
+on what exactly is supported and what is not. Additional features are
+supported by the [Available Extensions][].
+
+[Python-Markdown]: https://Python-Markdown.github.io/
+[Markdown]: https://daringfireball.net/projects/markdown/
+[Features]: https://Python-Markdown.github.io#Features
+[Available Extensions]: https://Python-Markdown.github.io/extensions
+
+Documentation
+-------------
+
+```bash
+pip install markdown
+```
+```python
+import markdown
+html = markdown.markdown(your_text_string)
+```
+
+For more advanced [installation] and [usage] documentation, see the `docs/` directory
+of the distribution or the project website at <https://Python-Markdown.github.io/>.
+
+[installation]: https://python-markdown.github.io/install/
+[usage]: https://python-markdown.github.io/reference/
+
+See the change log at <https://Python-Markdown.github.io/change_log>.
+
+Support
+-------
+
+You may report bugs, ask for help, and discuss various other issues on the [bug tracker][].
+
+[bug tracker]: https://github.com/Python-Markdown/markdown/issues
+
+Code of Conduct
+---------------
+
+Everyone interacting in the Python-Markdown project's code bases, issue trackers,
+and mailing lists is expected to follow the [Code of Conduct].
diff --git a/bin/markdown b/bin/markdown
deleted file mode 100755
index 8d04cc9..0000000
--- a/bin/markdown
+++ /dev/null
@@ -1,42 +0,0 @@
-#!/usr/bin/env python
-"""
-Python Markdown, the Command Line Script
-========================================
-
-This is the command line script for Python Markdown.
-
-Basic use from the command line:
-
- markdown source.txt > destination.html
-
-Run "markdown --help" to see more options.
-
-See markdown/__init__.py for information on using Python Markdown as a module.
-
-## Authors and License
-
-Started by [Manfred Stienstra](http://www.dwerg.net/). Continued and
-maintained by [Yuri Takhteyev](http://www.freewisdom.org), [Waylan
-Limberg](http://achinghead.com/) and [Artem Yunusov](http://blog.splyer.com).
-
-Contact: markdown@freewisdom.org
-
-Copyright 2007, 2008 The Python Markdown Project (v. 1.7 and later)
-Copyright 200? Django Software Foundation (OrderedDict implementation)
-Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
-Copyright 2004 Manfred Stienstra (the original version)
-
-License: BSD (see docs/LICENSE for details).
-"""
-
-import logging
-from markdown import COMMAND_LINE_LOGGING_LEVEL
-from markdown import commandline
-
-# Setup a logger manually for compatibility with Python 2.3
-logger = logging.getLogger('MARKDOWN')
-logger.setLevel(COMMAND_LINE_LOGGING_LEVEL)
-logger.addHandler(logging.StreamHandler())
-
-if __name__ == '__main__':
- commandline.run()
diff --git a/checklinks.sh b/checklinks.sh
new file mode 100755
index 0000000..dd9262b
--- /dev/null
+++ b/checklinks.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+echo "Checking links in documentation..."
+
+# List of files in docs dir
+docs=$(find . -path './docs/*.md')
+# List of files in project root (README, etc)
+extras=$(find . -maxdepth 1 -name '*.md')
+# Combined list of files to check
+files=("${docs[@]}" "${extras[@]}")
+
+let "fails=0"
+let "count=0"
+
+for file in ${files[@]}; do
+ let "count++"
+ markdown-link-check -q "$file"
+ if [ $? -ne 0 ]; then
+ let "fails++"
+ fi
+done
+
+echo -e "\n\033[0;33m$count files checked."
+
+if [ $fails -gt 0 ]; then
+ echo -e "\033[0;31mERROR: $fails files with dead links found!"
+ exit 1
+else
+ echo -e "\033[0;32mCongratulations! No dead links found."
+ exit 0
+fi
diff --git a/checkspelling.sh b/checkspelling.sh
new file mode 100755
index 0000000..acd504e
--- /dev/null
+++ b/checkspelling.sh
@@ -0,0 +1,38 @@
+#!/bin/bash
+
+echo "Building docs..."
+mkdocs build --strict
+if [ $? -ne 0 ]; then
+ exit 1
+fi
+echo "Compiling Dictionary..."
+aspell --lang=en create master ./tmp <.spell-dict
+if [ $? -ne 0 ]; then
+ exit 1
+fi
+echo "Checking spelling..."
+
+let "fails=0"
+
+for file in $(find site/ -type f -name "*.html"); do
+ words=$(aspell list --lang=en --mode=html --add-html-skip=code --extra-dicts=./tmp <$file)
+ if [ "$words" ]; then
+ uniquewords=$(tr ' ' '\n' <<< "${words[@]}" | sort -u | tr '\n' ' ')
+ let "fails++"
+ echo "Misspelled words in '$file':"
+ echo "-----------------------------------------------------------------"
+ for word in ${uniquewords[@]}; do
+ echo $word
+ done
+ echo "-----------------------------------------------------------------"
+ fi
+done
+rm -f ./tmp
+rm -rf site
+
+if [ $fails -gt 0 ]; then
+ echo "$fails files with misspelled words."
+ exit 1
+else
+ exit 0
+fi
diff --git a/doc-requirements.txt b/doc-requirements.txt
new file mode 100644
index 0000000..45acbd4
--- /dev/null
+++ b/doc-requirements.txt
@@ -0,0 +1,2 @@
+mkdocs>=1.0
+mkdocs-nature
diff --git a/docs/AUTHORS b/docs/AUTHORS
deleted file mode 100644
index 2843b56..0000000
--- a/docs/AUTHORS
+++ /dev/null
@@ -1,44 +0,0 @@
-Primary Authors
-===============
-
-Yuri Takteyev <http://freewisdom.org/>, who has written much of the current code
-while procrastingating his Ph.D.
-
-Waylan Limberg <http://achinghead.com/>, who has written most of the available
-extensions and later was asked to join Yuri, fixing nummrious bugs, adding
-documentation and making general improvements to the existing codebase,
-included a complete refactor of the core.
-
-Artem Yunusov, who as part of a 2008 GSoC project, has refactored inline
-patterns, replaced the NanoDOM with ElementTree support and made various other
-improvements.
-
-Manfed Stienstra <http://www.dwerg.net/>, who wrote the original version of
-the script and is responsible for various parts of the existing codebase.
-
-David Wolever, who refactored the extension API and made other improvements
-as he helped to integrate Markdown into Dr.Project.
-
-Other Contributors
-==================
-
-The incomplete list of individuals below have provided patches or otherwise
-contributed to the project in various ways. We would like to thank everyone
-who has contributed to the progect in any way.
-
-Eric Abrahamsen
-Jeff Balogh
-Sergej Chodarev
-Chris Clark
-Tiago Cogumbreiro
-Kjell Magne Fauske
-G. Clark Haynes
-Daniel Krech
-Steward Midwinter
-Jack Miller
-Neale Pickett
-Paul Stansifer
-John Szakmeister
-Malcolm Tredinnick
-Ben Wilson
-and many others who helped by reporting bugs
diff --git a/docs/CHANGE_LOG b/docs/CHANGE_LOG
deleted file mode 100644
index e005ff8..0000000
--- a/docs/CHANGE_LOG
+++ /dev/null
@@ -1,180 +0,0 @@
-PYTHON MARKDOWN CHANGELOG
-=========================
-
-Sept 28, 2009: Released version 2.0.2-Final.
-
-May 20, 2009: Released version 2.0.1-Final.
-
-Mar 30, 2009: Released version 2.0-Final.
-
-Mar 8, 2009: Release Candidate 2.0-rc-1.
-
-Feb 2009: Added support for multi-level lists to new Blockprocessors.
-
-Jan 2009: Added HTML 4 output as an option (thanks Eric Abrahamsen)
-
-Nov 2008: Added Definistion List ext. Replaced old core with BlockProcessors.
-Broken up into multiple files.
-
-Oct 2008: Changed logging behavior to work better with other systems.
-Refactored tree tarversing. Added treap implementation, then replaced with
-OrderedDEict. Renamed various processors to better reflect what they actually
-do. Refactored footnote ext to match php Extra's output.
-
-Sept 2008: Moved prettifyTree to a Postprocessor, replaced wikilink ext
-with wikilinks (note the s) ext (uses bracketed links instead of CamelCase)
-and various bug fixes.
-
-August 18 2008: Reorganized directory structure. Added a 'docs' dir
-and moved all extensions into a 'markdown-extensions' package.
-Added additional documentation and a few bug fixes. (v2.0-beta)
-
-August 4 2008: Updated included extensions to ElementTree. Added a
-seperate commanline script. (v2.0-alpha)
-
-July 2008: Switched from home-grown NanoDOM to ElementTree and
-various related bugs (thanks Artem Yunusov).
-
-June 2008: Fixed issues with nested inline patterns and cleaned
-up testing framework (thanks Artem Yunusov).
-
-May 2008: Added a number of additional extensions to the
-distribution and other minor changes. Moved repo to git from svn.
-
-Mar 2008: Refactored extension api to accept either an
-extension name (as a string) or an instance of an extension
-(Thanks David Wolever). Fixed various bugs and added doc strings.
-
-Feb 2008: Various bugfixes mostly regarding extensions.
-
-Feb 18, 2008: Version 1.7.
-
-Feb 13, 2008: A little code cleanup and better documentation
-and inheritance for pre/post proccessors.
-
-Feb 9, 2008: Doublequotes no longer html escaped and rawhtml
-honors <?foo>, <@foo>, and <%foo> for those who run markdown on
-template syntax.
-
-Dec 12, 2007: Updated docs. Removed encoding arg from Markdown
-and markdown as per list discussion. Clean up in prep for 1.7.
-
-Nov 29, 2007: Added support for images inside links. Also fixed
-a few bugs in the footnote extension.
-
-Nov 19, 2007: `message` now uses python's logging module. Also removed
-limit imposed by recursion in _process_section(). You can now parse as
-long of a document as your memory can handle.
-
-Nov 5, 2007: Moved safe_mode code to a textPostprocessor and added
-escaping option.
-
-Nov 3, 2007: Fixed convert method to accept empty strings.
-
-Oct 30, 2007: Fixed BOM removal (thanks Malcolm Tredinnick). Fixed
-infinite loop in bracket regex for inline links.
-
-Oct 11, 2007: LineBreaks is now an inlinePattern. Fixed HR in
-blockquotes. Refactored _processSection method (see tracker #1793419).
-
-Oct 9, 2007: Added textPreprocessor (from 1.6b).
-
-Oct 8, 2008: Fixed Lazy Blockquote. Fixed code block on first line.
-Fixed empty inline image link.
-
-Oct 7, 2007: Limit recursion on inlinePatterns. Added a 'safe' tag
-to htmlStash.
-
-March 18, 2007: Fixed or merged a bunch of minor bugs, including
-multi-line comments and markup inside links. (Tracker #s: 1683066,
-1671153, 1661751, 1627935, 1544371, 1458139.) -> v. 1.6b
-
-Oct 10, 2006: Fixed a bug that caused some text to be lost after
-comments. Added "safe mode" (user's html tags are removed).
-
-Sept 6, 2006: Added exception for PHP tags when handling html blocks.
-
-August 7, 2006: Incorporated Sergej Chodarev's patch to fix a problem
-with ampersand normalization and html blocks.
-
-July 10, 2006: Switched to using optparse. Added proper support for
-unicode.
-
-July 9, 2006: Fixed the <!--@address.com> problem (Tracker #1501354).
-
-May 18, 2006: Stopped catching unquoted titles in reference links.
-Stopped creating blank headers.
-
-May 15, 2006: A bug with lists, recursion on block-level elements,
-run-in headers, spaces before headers, unicode input (thanks to Aaron
-Swartz). Sourceforge tracker #s: 1489313, 1489312, 1489311, 1488370,
-1485178, 1485176. (v. 1.5)
-
-Mar. 24, 2006: Switched to a not-so-recursive algorithm with
-_handleInline. (Version 1.4)
-
-Mar. 15, 2006: Replaced some instance variables with class variables
-(a patch from Stelios Xanthakis). Chris Clark's new regexps that do
-not trigger midword underlining.
-
-Feb. 28, 2006: Clean-up and command-line handling by Stewart
-Midwinter. (Version 1.3)
-
-Feb. 24, 2006: Fixed a bug with the last line of the list appearing
-again as a separate paragraph. Incorporated Chris Clark's "mailto"
-patch. Added support for <br /> at the end of lines ending in two or
-more spaces. Fixed a crashing bug when using ImageReferencePattern.
-Added several utility methods to Nanodom. (Version 1.2)
-
-Jan. 31, 2006: Added "hr" and "hr/" to BLOCK_LEVEL_ELEMENTS and
-changed <hr/> to <hr />. (Thanks to Sergej Chodarev.)
-
-Nov. 26, 2005: Fixed a bug with certain tabbed lines inside lists
-getting wrapped in <pre><code>. (v. 1.1)
-
-Nov. 19, 2005: Made "<!...", "<?...", etc. behave like block-level
-HTML tags.
-
-Nov. 14, 2005: Added entity code and email autolink fix by Tiago
-Cogumbreiro. Fixed some small issues with backticks to get 100%
-compliance with John's test suite. (v. 1.0)
-
-Nov. 7, 2005: Added an unlink method for documents to aid with memory
-collection (per Doug Sauder's suggestion).
-
-Oct. 29, 2005: Restricted a set of html tags that get treated as
-block-level elements.
-
-Sept. 18, 2005: Refactored the whole script to make it easier to
-customize it and made footnote functionality into an extension.
-(v. 0.9)
-
-Sept. 5, 2005: Fixed a bug with multi-paragraph footnotes. Added
-attribute support.
-
-Sept. 1, 2005: Changed the way headers are handled to allow inline
-syntax in headers (e.g. links) and got the lists to use p-tags
-correctly (v. 0.8)
-
-Aug. 29, 2005: Added flexible tabs, fixed a few small issues, added
-basic support for footnotes. Got rid of xml.dom.minidom and added
-pretty-printing. (v. 0.7)
-
-Aug. 13, 2005: Fixed a number of small bugs in order to conform to the
-test suite. (v. 0.6)
-
-Aug. 11, 2005: Added support for inline html and entities, inline
-images, autolinks, underscore emphasis. Cleaned up and refactored the
-code, added some more comments.
-
-Feb. 19, 2005: Rewrote the handling of high-level elements to allow
-multi-line list items and all sorts of nesting.
-
-Feb. 3, 2005: Reference-style links, single-line lists, backticks,
-escape, emphasis in the beginning of the paragraph.
-
-Nov. 2004: Added links, blockquotes, html blocks to Manfred
-Stienstra's code
-
-Apr. 2004: Manfred's version at http://www.dwerg.net/projects/markdown/
-
diff --git a/docs/INSTALL b/docs/INSTALL
deleted file mode 100644
index d8feade..0000000
--- a/docs/INSTALL
+++ /dev/null
@@ -1,73 +0,0 @@
-Installing Python-Markdown
-==========================
-
-Checking Dependencies
----------------------
-
-Python-Markdown requires the ElementTree module to be installed. In Python2.5+
-ElementTree is included as part of the standard library. For earlier versions
-of Python, open a Python shell and type the following:
-
- >>> import cElementTree
- >>> import ElementTree
-
-If at least one of those does not generate any errors, then you have a working
-copy of ElementTree installed on your system. As cElementTree is faster, you
-may want to install that if you don't already have it and it's available for
-your system.
-
-See <http://effbot.org/zone/element-index.htm> for more information or to
-download the latest version of ElementTree.
-
-The East Way
-------------
-
-The simplest way to install Python-Markdown is by using SetupTools. As and
-Admin/Root user on your system do:
-
- easy_install ElementTree
- easy_install Markdown
-
-That's it, your done.
-
-Installing on Windows
----------------------
-
-Download the Windows installer (.exe) from PyPI:
-<http://pypi.python.org/pypi/Markdown>
-
-Double-click the file and follow the instructions.
-
-If you prefer to manually install Python-Markdown in Windows, download the
-Zip file, unzip it, and on the command line in the directory you unzipped to:
-
- python setup.py install
-
-If you plan to use the provided command line script, you need to make sure your
-script directory is on your system path. On a typical Python install of Windows
-the Scripts directory is `C:\Python25\Scripts\`. Adjust according to your
-system and add that to your system path.
-
-Installing on *nix Systems
---------------------------
-
-From the command line do the following:
-
- wget http://pypi.python.org/packages/source/M/Markdown/Markdown-2.0.tar.gz
- tar xvzf Markdown-2.0.tar.gz
- cd markdown-2.0/
- sudo python setup.py install
-
-Using the Git Repository
-------------------------
-
-If your the type that like to live on the edge, you may want to keep up with
-the latest additions and bug fixes in the repository between releases.
-Python-Markdown is maintained in a Git repository on Gitorious.org. To
-get a copy of Python-Markdown from the repository do the following from the
-command line:
-
- git clone git://gitorious.org/python-markdown/mainline.git python-markdown
- cd python-markdown
- python setup.py install
-
diff --git a/docs/README b/docs/README
deleted file mode 100644
index d19a1ea..0000000
--- a/docs/README
+++ /dev/null
@@ -1,30 +0,0 @@
-[Python-Markdown][]
-===================
-
-This is a Python implementation of John Gruber's [Markdown][].
-It is almost completely compliant with the reference implementation,
-though there are a few known issues. See [Features][] for information
-on what exactly is supported and what is not. Additional features are
-supported by the [Available Extensions][].
-
-[Python-Markdown]: http://freewisdom.org/projects/python-markdown
-[Markdown]: http://daringfireball.net/projects/markdown/
-[Features]: http://www.freewisdom.org/projects/python-markdown/Features
-[Available Extensions]: http://www.freewisdom.org/projects/python-markdown/Available_Extensions
-
-
-Documentation
--------------
-
-Installation and usage documentation is available in the `docs/` directory
-of the distribution and on the project website at
-<http://freewisdom.org/projects/python-markdown>.
-
-Support
--------
-
-You may ask for help and discuss various other issues on the [mailing list][] and report bugs on the [bug tracker][].
-
-[mailing list]: http://lists.sourceforge.net/lists/listinfo/python-markdown-discuss
-[bug tracker]: http://www.freewisdom.org/projects/python-markdown/Tickets
-
diff --git a/docs/README.html b/docs/README.html
deleted file mode 100644
index 49e3b07..0000000
--- a/docs/README.html
+++ /dev/null
@@ -1,12 +0,0 @@
-<h1><a href="http://freewisdom.org/projects/python-markdown">Python-Markdown</a></h1>
-<p>This is a Python implementation of John Gruber's <a href="http://daringfireball.net/projects/markdown/">Markdown</a>.
-It is almost completely compliant with the reference implementation,
-though there are a few known issues. See <a href="http://www.freewisdom.org/projects/python-markdown/Features">Features</a> for information
-on what exactly is supported and what is not. Additional features are
-supported by the <a href="http://www.freewisdom.org/projects/python-markdown/Available_Extensions">Available Extensions</a>.</p>
-<h2>Documentation</h2>
-<p>Installation and usage documentation is available in the <code>docs/</code> directory
-of the distribution and on the project website at
-<a href="http://freewisdom.org/projects/python-markdown">http://freewisdom.org/projects/python-markdown</a>.</p>
-<h2>Support</h2>
-<p>You may ask for help and discuss various other issues on the <a href="http://lists.sourceforge.net/lists/listinfo/python-markdown-discuss">mailing list</a> and report bugs on the <a href="http://www.freewisdom.org/projects/python-markdown/Tickets">bug tracker</a>.</p> \ No newline at end of file
diff --git a/docs/authors.md b/docs/authors.md
new file mode 100644
index 0000000..114227d
--- /dev/null
+++ b/docs/authors.md
@@ -0,0 +1,70 @@
+title: Authors
+
+Primary Authors
+===============
+
+* __[Waylan Limberg](https://github.com/waylan)__
+
+ @waylan is the current maintainer of the code and has written much of the
+ current code base, including a complete refactor of the core for version 2.0.
+ He started out by authoring many of the available extensions and later was
+ asked to join Yuri, where he began fixing numerous bugs, adding
+ documentation and making general improvements to the existing code base.
+
+* __[Dmitry Shachnev](https://github.com/mitya57)__
+
+ @mitya57 joined the team after providing a number of helpful patches and has
+ been assisting with maintenance, reviewing pull requests and ticket triage.
+
+* __[Isaac Muse](https://github.com/facelessuser)__
+
+ @facelessuser joined the team after providing a number of helpful patches
+ and has been assisting with maintenance, reviewing pull requests and ticket
+ triage.
+
+* __[Yuri Takteyev](https://github.com/yuri)__
+
+ Yuri wrote most of the code found in version 1.x while procrastinating his
+ Ph.D. Various pieces of his code still exist, most notably the basic
+ structure.
+
+* __Manfed Stienstra__
+
+ Manfed wrote the original version of the script and is responsible for
+ various parts of the existing code base.
+
+* __Artem Yunusov__
+
+ Artem, who as part of a 2008 GSoC project, refactored inline patterns,
+ replaced the NanoDOM with ElementTree support and made various other
+ improvements.
+
+* __David Wolever__
+
+ David refactored the extension API and made other improvements
+ as he helped to integrate Markdown into Dr.Project.
+
+Other Contributors
+==================
+
+The incomplete list of individuals below have provided patches or otherwise
+contributed to the project prior to the project being hosted on GitHub. See the
+GitHub commit log for a list of recent contributors. We would like to thank
+everyone who has contributed to the project in any way.
+
+* Eric Abrahamsen
+* Jeff Balogh
+* Sergej Chodarev
+* Chris Clark
+* Tiago Cogumbreiro
+* Kjell Magne Fauske
+* G. Clark Haynes
+* Daniel Krech
+* Steward Midwinter
+* Jack Miller
+* Neale Pickett
+* Paul Stansifer
+* John Szakmeister
+* Malcolm Tredinnick
+* Ben Wilson
+* and many others who helped by reporting bugs
diff --git a/docs/change_log/index.md b/docs/change_log/index.md
new file mode 100644
index 0000000..9626900
--- /dev/null
+++ b/docs/change_log/index.md
@@ -0,0 +1,321 @@
+title: Change Log
+
+Python-Markdown Change Log
+=========================
+
+July 15, 2022: version 3.4.1 (a bug-fix release).
+
+* Fix an import issue with `importlib.util` (#1274).
+
+July 15, 2022: version 3.4 ([Notes](release-3.4.md)).
+
+May 5, 2022: version 3.3.7 (a bug-fix release).
+
+* Disallow square brackets in reference link ids (#1209).
+* Retain configured `pygments_style` after first code block (#1240).
+* Ensure fenced code attributes are properly escaped (#1247).
+
+Nov 17, 2021: version 3.3.6 (a bug-fix release).
+
+* Fix a dependency issue (#1195, #1196).
+
+Nov 16, 2021: version 3.3.5 (a bug-fix release).
+
+* Make the `slugify_unicode` function not remove diacritical marks (#1118).
+* Fix `[toc]` detection when used with `nl2br` extension (#1160).
+* Re-use compiled regex for block level checks (#1169).
+* Don't process shebangs in fenced code blocks when using CodeHilite (#1156).
+* Improve email address validation for Automatic Links (#1165).
+* Ensure `<summary>` tags are parsed correctly (#1079).
+* Support Python 3.10 (#1124).
+
+Feb 24, 2021: version 3.3.4 (a bug-fix release).
+
+* Properly parse unclosed tags in code spans (#1066).
+* Properly parse processing instructions in md_in_html (#1070).
+* Properly parse code spans in md_in_html (#1069).
+* Preserve text immediately before an admonition (#1092).
+* Simplified regex for HTML placeholders (#928) addressing (#932).
+* Ensure `permalinks` and `anchorlinks` are not restricted by `toc_depth` (#1107).
+* Fix corner cases with lists under admonitions (#1102).
+
+Oct 25, 2020: version 3.3.3 (a bug-fix release).
+
+* Unify all block-level tags (#1047).
+* Fix issue where some empty elements would have text rendered as `None` when using `md_in_html` (#1049).
+* Avoid catastrophic backtracking in `hr` regex (#1055).
+* Fix `hr` HTML handling (#1053).
+
+Oct 19, 2020: version 3.3.2 (a bug-fix release).
+
+* Properly parse inline HTML in md_in_html (#1040 & #1045).
+* Avoid crashing when md_in_html fails (#1040).
+
+Oct 12, 2020: version 3.3.1 (a bug-fix release).
+
+* Correctly parse raw `script` and `style` tags (#1036).
+* Ensure consistent class handling by `fenced_code` and `codehilite` (#1032).
+
+Oct 6, 2020: version 3.3 ([Notes](release-3.3.md)).
+
+May 8, 2020: version 3.2.2 (a bug-fix release).
+
+* Add `checklinks` tox environment to ensure all links in documentation are good.
+* Refactor extension API documentation (#729).
+* Load entry_points (for extensions) only once using `importlib.metadata`.
+* Do not double escape entities in TOC.
+* Correctly report if an extension raises a `TypeError` (#939).
+* Raise a `KeyError` when attempting to delete a nonexistent key from the
+ extension registry (#939).
+* Remove import of `packaging` (or `pkg_resources` fallback) entirely.
+* Remove `setuptools` as a run-time dependency (`install_required`).
+
+Feb 12, 2020: Released version 3.2.1 (a bug-fix release).
+
+* The `name` property in `toc_tokens` from the TOC extension now
+ escapes HTML special characters (`<`, `>`, and `&`).
+
+Feb 7, 2020: Released version 3.2 ([Notes](release-3.2.md)).
+
+May 20, 2019: Released version 3.1.1 (a bug-fix release).
+
+* Fixed import failure in `setup.py` when the source directory is not
+ on `sys.path` (#823).
+* Prefer public `packaging` module to pkg_resources' private copy of
+ it (#825).
+
+Mar 25, 2019: Released version 3.1 ([Notes](release-3.1.md)).
+
+Sept 28, 2018: Released version 3.0.1 (a bug-fix release).
+
+* Brought back the `version` and `version_info` variables (#709).
+* Added support for hexadecimal HTML entities (#712).
+
+Sept 21, 2018: Released version 3.0 ([Notes](release-3.0.md)).
+
+Jan 4, 2018: Released version 2.6.11 (a bug-fix release). Added a new
+`BACKLINK-TITLE` option to the footnote extension so that non-English
+users can provide a custom title to back links (see #610).
+
+Dec 7, 2017: Released version 2.6.10 (a documentation update).
+
+Aug 17, 2017: Released version 2.6.9 (a bug-fix release).
+
+Jan 25, 2017: Released version 2.6.8 (a bug-fix release).
+
+Sept 23, 2016: Released version 2.6.7 (a bug-fix release).
+
+Mar 20, 2016: Released version 2.6.6 (a bug-fix release).
+
+Nov 24, 2015: Released version 2.6.5 (a bug-fix release).
+
+Nov 6, 2015: Released version 2.6.4 (a bug-fix release).
+
+Oct 26, 2015: Released version 2.6.3 (a bug-fix release).
+
+Apr 20, 2015: Released version 2.6.2 (a bug-fix release).
+
+Mar 8, 2015: Released version 2.6.1 (a bug-fix release). The (new)
+`yaml` option has been removed from the Meta-Data Extension as it was buggy
+(see [#390](https://github.com/Python-Markdown/markdown/issues/390)).
+
+Feb 19, 2015: Released version 2.6 ([Notes](release-2.6.md)).
+
+Nov 19, 2014: Released version 2.5.2 (a bug-fix release).
+
+Sept 26, 2014: Released version 2.5.1 (a bug-fix release).
+
+Sept 12, 2014: Released version 2.5.0 ([Notes](release-2.5.md)).
+
+Feb 16, 2014: Released version 2.4.0 ([Notes](release-2.4.md)).
+
+Mar 22, 2013: Released version 2.3.1 (a bug-fix release).
+
+Mar 14, 2013: Released version 2.3.0 ([Notes](release-2.3.md))
+
+Nov 4, 2012: Released version 2.2.1 (a bug-fix release).
+
+Jul 5, 2012: Released version 2.2.0 ([Notes](release-2.2.md)).
+
+Jan 22, 2012: Released version 2.1.1 (a bug-fix release).
+
+Nov 24, 2011: Released version 2.1.0 ([Notes](release-2.1.md)).
+
+Oct 7, 2009: Released version 2.0.3. (a bug-fix release).
+
+Sept 28, 2009: Released version 2.0.2 (a bug-fix release).
+
+May 20, 2009: Released version 2.0.1 (a bug-fix release).
+
+Mar 30, 2009: Released version 2.0 ([Notes](release-2.0.md)).
+
+Mar 8, 2009: Release Candidate 2.0-rc-1.
+
+Feb 2009: Added support for multi-level lists to new Blockprocessors.
+
+Jan 2009: Added HTML 4 output as an option (thanks Eric Abrahamsen)
+
+Nov 2008: Added Definition List ext. Replaced old core with Blockprocessors.
+Broken up into multiple files.
+
+Oct 2008: Changed logging behavior to work better with other systems.
+Refactored tree traversing. Added `treap` implementation, then replaced with
+OrderedDict. Renamed various processors to better reflect what they actually
+do. Refactored footnote ext to match PHP Extra's output.
+
+Sept 2008: Moved `prettifyTree` to a Postprocessor, replaced WikiLink ext
+with WikiLinks (note the s) ext (uses bracketed links instead of CamelCase)
+and various bug fixes.
+
+August 18 2008: Reorganized directory structure. Added a 'docs' directory
+and moved all extensions into a 'markdown-extensions' package.
+Added additional documentation and a few bug fixes. (v2.0-beta)
+
+August 4 2008: Updated included extensions to ElementTree. Added a
+separate command line script. (v2.0-alpha)
+
+July 2008: Switched from home-grown NanoDOM to ElementTree and
+various related bugs (thanks Artem Yunusov).
+
+June 2008: Fixed issues with nested inline patterns and cleaned
+up testing framework (thanks Artem Yunusov).
+
+May 2008: Added a number of additional extensions to the
+distribution and other minor changes. Moved repository to git from svn.
+
+Mar 2008: Refactored extension API to accept either an
+extension name (as a string) or an instance of an extension
+(Thanks David Wolever). Fixed various bugs and added doc strings.
+
+Feb 2008: Various bug-fixes mostly regarding extensions.
+
+Feb 18, 2008: Version 1.7.
+
+Feb 13, 2008: A little code cleanup and better documentation
+and inheritance for Preprocessors/Postprocessors.
+
+Feb 9, 2008: Double-quotes no longer HTML escaped and raw HTML
+honors `<?foo>`, `<@foo>`, and `<%foo>` for those who run markdown on
+template syntax.
+
+Dec 12, 2007: Updated docs. Removed encoding argument from Markdown
+and markdown as per list discussion. Clean up in prep for 1.7.
+
+Nov 29, 2007: Added support for images inside links. Also fixed
+a few bugs in the footnote extension.
+
+Nov 19, 2007: `message` now uses python's logging module. Also removed
+limit imposed by recursion in `_process_section()`. You can now parse as
+long of a document as your memory can handle.
+
+Nov 5, 2007: Moved `safe_mode` code to a `textPostprocessor` and added
+escaping option.
+
+Nov 3, 2007: Fixed convert method to accept empty strings.
+
+Oct 30, 2007: Fixed `BOM` removal (thanks Malcolm Tredinnick). Fixed
+infinite loop in bracket regular expression for inline links.
+
+Oct 11, 2007: `LineBreaks` is now an `inlinePattern`. Fixed `HR` in
+blockquotes. Refactored `_processSection` method (see tracker #1793419).
+
+Oct 9, 2007: Added `textPreprocessor` (from 1.6b).
+
+Oct 8, 2008: Fixed Lazy Blockquote. Fixed code block on first line.
+Fixed empty inline image link.
+
+Oct 7, 2007: Limit recursion on inline patterns. Added a 'safe' tag
+to `htmlStash`.
+
+March 18, 2007: Fixed or merged a bunch of minor bugs, including
+multi-line comments and markup inside links. (Tracker #s: 1683066,
+1671153, 1661751, 1627935, 1544371, 1458139.) -> v. 1.6b
+
+Oct 10, 2006: Fixed a bug that caused some text to be lost after
+comments. Added "safe mode" (user's HTML tags are removed).
+
+Sept 6, 2006: Added exception for PHP tags when handling HTML blocks.
+
+August 7, 2006: Incorporated Sergej Chodarev's patch to fix a problem
+with ampersand normalization and HTML blocks.
+
+July 10, 2006: Switched to using `optparse`. Added proper support for
+Unicode.
+
+July 9, 2006: Fixed the `<!--@address.com>` problem (Tracker #1501354).
+
+May 18, 2006: Stopped catching unquoted titles in reference links.
+Stopped creating blank headers.
+
+May 15, 2006: A bug with lists, recursion on block-level elements,
+run-in headers, spaces before headers, Unicode input (thanks to Aaron
+Swartz). Sourceforge tracker #s: 1489313, 1489312, 1489311, 1488370,
+1485178, 1485176. (v. 1.5)
+
+Mar. 24, 2006: Switched to a not-so-recursive algorithm with
+`_handleInline`. (Version 1.4)
+
+Mar. 15, 2006: Replaced some instance variables with class variables
+(a patch from Stelios Xanthakis). Chris Clark's new regexps that do
+not trigger mid-word underlining.
+
+Feb. 28, 2006: Clean-up and command-line handling by Stewart
+Midwinter. (Version 1.3)
+
+Feb. 24, 2006: Fixed a bug with the last line of the list appearing
+again as a separate paragraph. Incorporated Chris Clark's "mail-to"
+patch. Added support for `<br />` at the end of lines ending in two or
+more spaces. Fixed a crashing bug when using `ImageReferencePattern`.
+Added several utility methods to `Nanodom`. (Version 1.2)
+
+Jan. 31, 2006: Added `hr` and `hr/` to BLOCK_LEVEL_ELEMENTS and
+changed `<hr/>` to `<hr />`. (Thanks to Sergej Chodarev.)
+
+Nov. 26, 2005: Fixed a bug with certain tabbed lines inside lists
+getting wrapped in `<pre><code>`. (v. 1.1)
+
+Nov. 19, 2005: Made `<!...`, `<?...`, etc. behave like block-level
+HTML tags.
+
+Nov. 14, 2005: Added entity code and email auto-link fix by Tiago
+Cogumbreiro. Fixed some small issues with backticks to get 100%
+compliance with John's test suite. (v. 1.0)
+
+Nov. 7, 2005: Added an `unlink` method for documents to aid with memory
+collection (per Doug Sauder's suggestion).
+
+Oct. 29, 2005: Restricted a set of HTML tags that get treated as
+block-level elements.
+
+Sept. 18, 2005: Refactored the whole script to make it easier to
+customize it and made footnote functionality into an extension.
+(v. 0.9)
+
+Sept. 5, 2005: Fixed a bug with multi-paragraph footnotes. Added
+attribute support.
+
+Sept. 1, 2005: Changed the way headers are handled to allow inline
+syntax in headers (e.g. links) and got the lists to use p-tags
+correctly (v. 0.8)
+
+Aug. 29, 2005: Added flexible tabs, fixed a few small issues, added
+basic support for footnotes. Got rid of xml.dom.minidom and added
+pretty-printing. (v. 0.7)
+
+Aug. 13, 2005: Fixed a number of small bugs in order to conform to the
+test suite. (v. 0.6)
+
+Aug. 11, 2005: Added support for inline HTML and entities, inline
+images, auto-links, underscore emphasis. Cleaned up and refactored the
+code, added some more comments.
+
+Feb. 19, 2005: Rewrote the handling of high-level elements to allow
+multi-line list items and all sorts of nesting.
+
+Feb. 3, 2005: Reference-style links, single-line lists, backticks,
+escape, emphasis in the beginning of the paragraph.
+
+Nov. 2004: Added links, blockquotes, HTML blocks to Manfred
+Stienstra's code
+
+Apr. 2004: Manfred's version at `http://www.dwerg.net/projects/markdown/`
diff --git a/docs/release-2.0.txt b/docs/change_log/release-2.0.md
index b1f71ad..abd8d29 100644
--- a/docs/release-2.0.txt
+++ b/docs/change_log/release-2.0.md
@@ -1,34 +1,36 @@
+title: Release Notes for v2.0
+
Python-Markdown 2.0 Release Notes
=================================
-We are happy to release Python-Markdown 2.0, which has been over a year in the
-making. We have rewritten significant portions of the code, dramatically
-extending the extension API, increased performance, and added numerous
+We are happy to release Python-Markdown 2.0, which has been over a year in the
+making. We have rewritten significant portions of the code, dramatically
+extending the extension API, increased performance, and added numerous
extensions to the distribution (including an extension that mimics PHP Markdown
Extra), all while maintaining backward compatibility with the end user API in
version 1.7.
-Python-Markdown supports Python versions 2.3, 2.4, 2.5, and 2.6. We've even
+Python-Markdown supports Python versions 2.3, 2.4, 2.5, and 2.6. We have even
released a version converted to Python 3.0!
Backwards-incompatible Changes
------------------------------
-While Python-Markdown has experienced numerous internal changes, those changes
-should only affect extension authors. If you have not written your own
-extensions, then you should not need to make any changes to your code.
+While Python-Markdown has experienced numerous internal changes, those changes
+should only affect extension authors. If you have not written your own
+extensions, then you should not need to make any changes to your code.
However, you may want to ensure that any third party extensions you are using
are compatible with the new API.
-The new extension API is fully documented in [[writing_extensions]]. Below is a
-summary of the significant changes:
+The new extension API is fully [documented](../extensions/api.md) in the docs.
+Below is a summary of the significant changes:
* The old home-grown NanoDOM has been replaced with ElementTree. Therefore all
extensions must use ElementTree rather than the old NanoDOM.
-* The various processors and patterns are now stored with OrderedDicts rather
- than lists. Any code adding processors and/or patterns into Python-Markdown
+* The various processors and patterns are now stored with OrderedDicts rather
+ than lists. Any code adding processors and/or patterns into Python-Markdown
will need to be adjusted to use the new API using OrderedDicts.
-* The various types of processors available have been either combined, added,
+* The various types of processors available have been either combined, added,
or removed. Ensure that your processors match the currently supported types.
What's New in Python-Markdown 2.0
@@ -39,20 +41,20 @@ ElementTree internally to build the (X)HTML document from markdown source text.
This has resolved various issues with the older home-grown NanoDOM and made
notable increases in performance.
-Artem also refactored the Inline Patterns to better support nested patterns
-which has resolved many inconsistencies in Python-Markdown's parsing of the
+Artem also refactored the Inline Patterns to better support nested patterns
+which has resolved many inconsistencies in Python-Markdown's parsing of the
markdown syntax.
-The core parser had been completely rewritten, increasing performance and, for
+The core parser had been completely rewritten, increasing performance and, for
the first time, making it possible to override/add/change the way block level
content is parsed.
-Python-Markdown now parses markdown source text more closely to the other
+Python-Markdown now parses markdown source text more closely to the other
popular implementations (Perl, PHP, etc.) than it ever has before. With the
exception of a few minor insignificant differences, any difference should be
considered a bug, rather than a limitation of the parser.
-The option to return HTML4 output as apposed to XHTML has been added. In
+The option to return HTML4 output as apposed to XHTML has been added. In
addition, extensions should be able to easily add additional output formats.
As part of implementing markdown in the Dr. Project project (a Trac fork), among
@@ -61,7 +63,7 @@ accepts either the extension names as strings or instances of extensions. This
makes it possible to include multiple extensions in a single module.
Numerous extensions are included in the distribution by default. See
-[[available_extensions]] for a complete list.
+[available_extensions](../extensions/index.md) for a complete list.
-See the [[change_log]] for a full list of changes.
+See the [Change Log](index.md) for a full list of changes.
diff --git a/docs/change_log/release-2.1.md b/docs/change_log/release-2.1.md
new file mode 100644
index 0000000..4f7ba75
--- /dev/null
+++ b/docs/change_log/release-2.1.md
@@ -0,0 +1,118 @@
+title: Release Notes for v2.1
+
+Python-Markdown 2.1 Release Notes
+=================================
+
+We are pleased to release Python-Markdown 2.1 which makes many
+improvements on 2.0. In fact, we consider 2.1 to be what 2.0 should have been.
+While 2.1 consists mostly of bug fixes, bringing Python-Markdown more inline
+with other implementations, some internal improvements were made to the parser,
+a few new built-in extensions were added, and HTML5 support was added.
+
+Python-Markdown supports Python versions 2.4, 2.5, 2.6, 2.7, 3.1, and 3.2 out
+of the box. In fact, the same code base installs on Python 3.1 and 3.2 with no
+extra work by the end user.
+
+Backwards-incompatible Changes
+------------------------------
+
+While Python-Markdown has received only minor internal changes since the last
+release, there are a few backward-incompatible changes to note:
+
+* Support had been dropped for Python 2.3. No guarantees are made that the
+ library will work in any version of Python lower than 2.4. Additionally, while
+ the library had been tested with Python 2.4, consider Python 2.4 support to be
+ depreciated. It is not likely that any future versions will continue to
+ support any version of Python less than 2.5. Note that Python 3.0 is not
+ supported due to a bug in its 2to3 tool. If you must use Python-Markdown with
+ Python 3.0, it is suggested you manually use Python 3.1's 2to3 tool to do a
+ conversion.
+
+* Python-Markdown previously accepted positional arguments on its class and
+ wrapper methods. It now expects keyword arguments. Currently, the positional
+ arguments should continue to work, but the solution feels hacky and may be
+ removed in a future version. All users are encouraged to use keyword arguments
+ as documented in the [Library Reference](../reference.md).
+
+* Past versions of Python-Markdown provided module level Global variables which
+ controlled the behavior of a few different aspects of the parser. Those global
+ variables have been replaced with attributes on the Markdown class.
+ Additionally, those attributes are settable as keyword arguments when
+ initializing a class instance. Therefore, if you were editing the global
+ variables (either by editing the source or by overriding them in your code),
+ you should now set them on the class. See the [Library
+ Reference](../reference.md) for the options available.
+
+* If you have been using the HeaderId extension to
+ define custom ids on headers, you will want to switch to using the new
+ [Attribute List](../extensions/attr_list.md) extension. The HeaderId extension
+ now only auto-generates ids on headers which have not already had ids defined.
+ Note that the [Extra](../extensions/extra.md) extension has been switched to
+ use Attribute Lists instead of HeaderId as it did previously.
+
+* Some code was moved into the `markdown.util` namespace which was previously in
+ the `markdown` namespace. Extension authors may need to adjust a few import
+ statements in their extensions to work with the changes.
+
+* The command line script name was changed to `markdown_py`. The previous name
+ (`markdown`) was conflicting with people (and Linux package systems) who also
+ had markdown.pl installed on there system as markdown.pl's command line script
+ was also named `markdown`. Be aware that installing Python-Markdown 2.1 will
+ not remove the old versions of the script with different names. You may want
+ to remove them yourself as they are unlikely to work properly.
+
+What's New in Python-Markdown 2.1
+---------------------------------
+
+Three new extensions were added. [Attribute Lists](../extensions/attr_list.md),
+which was inspired by Maruku's feature of the same name, [Newline to
+Break](../extensions/nl2br.md), which was inspired by GitHub Flavored Markdown,
+and Smart Strong, which fills a hole in the Extra extension.
+
+HTML5 is now supported. All this really means is that new block level elements
+introduced in the HTML5 spec are now properly recognized as raw HTML. As
+valid HTML5 can consist of either HTML4 or XHTML1, there is no need to add a
+new HTML5 serializers. That said, `html5` and `xhtml5` have been added as
+aliases of the `html4` and `xhtml1` serializers respectively.
+
+An XHTML serializer has been added. Previously, ElementTree's XML serializer
+was being used for XHTML output. With the new serializer we are able to avoid
+more invalid output like empty elements (i.e., `<p />`) which can choke
+browsers.
+
+Improved support for Python 3.x. Now when running `setupy.py install` in
+Python 3.1 or greater the 2to3 tool is run automatically. Note that Python 3.0
+is not supported due to a bug in its 2to3 tool. If you must use Python-Markdown
+with Python 3.0, it is suggested you manually use Python 3.1's 2to3 tool to
+do a conversion.
+
+Methods on instances of the Markdown class that do not return results can now
+be changed allowing one to do `md.reset().convert(moretext)`.
+
+The Markdown class was refactored so that a subclass could define its own
+`build_parser` method which would build a completely different parser. In
+other words, one could use the basic machinery in the markdown library to
+build a parser of a different markup language without the overhead of building
+the markdown parser and throwing it away.
+
+Import statements within markdown have been improved so that third party
+libraries can embed the markdown library if they desire (licensing permitting).
+
+Added support for Python's `-m` command line option. You can run the markdown
+package as a command line script. Do `python -m markdown [options] [args]`.
+Note that this is only fully supported in Python 2.7+. Python 2.5 & 2.6
+require you to call the module directly (`markdown.__main__`) rather than
+the package (`markdown`). This does not work in Python 2.4.
+
+The command line script has been renamed to `markdown_py` which avoids all the
+various problems we had with previous names. Also improved the command line
+script to accept input on `stdin`.
+
+The testing framework has been completely rebuilt using the Nose testing
+framework. This provides a number of benefits including the ability to better
+test the built-in extensions and other options available to change the parsing
+behavior. See the Test Suite documentation for details.
+
+Various bug fixes have been made, which are too numerous to list here. See the
+[commit log](https://github.com/Python-Markdown/markdown/commits/master) for a
+complete history of the changes.
diff --git a/docs/change_log/release-2.2.md b/docs/change_log/release-2.2.md
new file mode 100644
index 0000000..75f47fa
--- /dev/null
+++ b/docs/change_log/release-2.2.md
@@ -0,0 +1,64 @@
+title: Release Notes for v2.2
+
+Python-Markdown 2.2 Release Notes
+=================================
+
+We are pleased to release Python-Markdown 2.2 which makes improvements on 2.1.
+While 2.2 is primarily a bug fix release, some internal improvements were made
+to the parser, and a few security issues were resolved.
+
+Python-Markdown supports Python versions 2.5, 2.6, 2.7, 3.1, and 3.2 out
+of the box.
+
+Backwards-incompatible Changes
+------------------------------
+
+While Python-Markdown has received only minor internal changes since the last
+release, there are a few backward-incompatible changes to note:
+
+* Support had been dropped for Python 2.4. No guarantees are made that the
+ library will work in any version of Python lower than 2.5. Additionally, while
+ the library had been tested with Python 2.5, consider Python 2.5 support to be
+ depreciated. It is not likely that any future versions will continue to
+ support any version of Python less than 2.6.
+
+* For many years Python-Markdown has identified `<ins>` and `<del>` tags in raw
+ HTML input as block level tags. As they are actually inline level tags, this
+ behavior has been changed. This may result in slightly different output. While
+ in most cases, the new output is more correct, there may be a few edge cases
+ where a document author has relied on the previous incorrect behavior. It is
+ likely that a few adjustments may need to be made to those documents.
+
+* The behavior of the `enable_attributes` keyword has been slightly altered. If
+ authors have been using attributes in documents with `safe_mode` on, those
+ attributes will no longer be parsed unless `enable_attributes` is explicitly
+ set to `True`. This change was made to prevent untrusted authors from
+ injecting potentially harmful JavaScript in documents. This change had no
+ effect when not in `safe_mode`.
+
+What's New in Python-Markdown 2.2
+---------------------------------
+
+The docs were refactored and can now be found at
+`http://packages.python.org/Markdown/`. The docs are now maintained in the
+Repository and are generated by the `setup.py build_docs` command.
+
+The [Sane_Lists](../extensions/sane_lists.md)
+extension was added. The Sane Lists Extension alters the behavior of the
+Markdown List syntax to be less surprising by not allowing the mixing of list
+types. In other words, an ordered list will not continue when an unordered list
+item is encountered and vice versa.
+
+Markdown now excepts a full path to an extension module. In other words, your
+extensions no longer need to be in the primary namespace (and start with `mdx_`)
+for Markdown to find them. Just do `Markdown(extension=['path.to.some.module'])`.
+As long as the provided module contains a compatible extension, the extension
+will be loaded.
+
+The BlockParser API was slightly altered to allow `blockprocessor.run` to return
+`True` or `False` which provides more control to the block processor loop from
+within any Blockprocessor instance.
+
+Various bug fixes have been made. See the
+[commit log](https://github.com/Python-Markdown/markdown/commits/master)
+for a complete history of the changes.
diff --git a/docs/change_log/release-2.3.md b/docs/change_log/release-2.3.md
new file mode 100644
index 0000000..f60e426
--- /dev/null
+++ b/docs/change_log/release-2.3.md
@@ -0,0 +1,85 @@
+title: Release Notes for v2.3
+
+Python-Markdown 2.3 Release Notes
+=================================
+
+We are pleased to release Python-Markdown 2.3 which adds one new extension,
+removes a few old (obsolete) extensions, and now runs on both Python 2 and
+Python 3 without running the 2to3 conversion tool. See the list of changes
+below for details.
+
+Python-Markdown supports Python versions 2.6, 2.7, 3.1, 3.2, and 3.3.
+
+Backwards-incompatible Changes
+------------------------------
+
+* Support has been dropped for Python 2.5. No guarantees are made that the
+ library will work in any version of Python lower than 2.6. As all supported
+ Python versions include the ElementTree library, Python-Markdown will no
+ longer try to import a third-party installation of ElementTree.
+
+* All classes are now "new-style" classes. In other words, all classes subclass
+ from 'object'. While this is not likely to affect most users, extension
+ authors may need to make a few minor adjustments to their code.
+
+* "safe_mode" has been further restricted. Markdown formatted links must be of a
+ known white-listed scheme when in "safe_mode" or the URL is discarded. The
+ white-listed schemes are: 'HTTP', 'HTTPS', 'FTP', 'FTPS', 'MAILTO', and
+ 'news'. Schemeless URLs are also permitted, but are checked in other ways - as
+ they have been for some time.
+
+* The ids assigned to footnotes now contain a dash (`-`) rather than a colon
+ (`:`) when `output_format` it set to `"html5"` or `"xhtml5"`. If you are
+ making reference to those ids in your JavaScript or CSS and using the HTML5
+ output, you will need to update your code accordingly. No changes are
+ necessary if you are outputting XHTML (the default) or HTML4.
+
+* The `force_linenos` configuration setting of the CodeHilite extension has been
+ marked as **Pending Deprecation** and a new setting `linenums` has been added
+ to replace it. See documentation for the [CodeHilite Extension] for an
+ explanation of the new `linenums` setting. The new setting will honor the old
+ `force_linenos` if it is set, but it will raise a `PendingDeprecationWarning`
+ and will likely be removed in a future version of Python-Markdown.
+
+[CodeHilite Extension]: ../extensions/code_hilite.md
+
+* The "RSS" extension has been removed and no longer ships with Python-Markdown.
+ If you would like to continue using the extension (not recommended), it is
+ archived on [GitHub](https://gist.github.com/waylan/4773365).
+
+* The "HTML Tidy" Extension has been removed and no longer ships with
+ Python-Markdown. If you would like to continue using the extension (not
+ recommended), it is archived on
+ [GitHub](https://gist.github.com/waylan/5152650). Note that the underlying
+ library, uTidylib, is not Python 3 compatible. Instead, it is recommended that
+ the newer [PyTidyLib] (version 0.2.2+ for Python 3 comparability - install
+ from GitHub not PyPI) be used. As the API for that library is rather simple,
+ it is recommended that the output of Markdown be wrapped in a call to
+ PyTidyLib rather than using an extension (for example:
+ `tidylib.tidy_fragment(markdown.markdown(source), options={...})`).
+
+[PyTidyLib]: http://countergram.github.io/pytidylib/
+
+What's New in Python-Markdown 2.3
+---------------------------------
+
+* The entire code base now universally runs in Python 2 and Python 3 without any
+ need for running the 2to3 conversion tool. This not only simplifies testing,
+ but by using Unicode_literals, results in more consistent behavior across
+ Python versions. Additionally, the relative imports (made possible in Python 2
+ via absolute_import) allows the entire library to more easily be embedded in a
+ sub-directory of another project. The various files within the library will
+ still import each other properly even though 'markdown' may not be in Python's
+ root namespace.
+
+* The [Admonition Extension] has been added, which implements [rST-style][rST]
+ admonitions in the Markdown syntax. However, be warned that this extension is
+ experimental and the syntax and behavior is still subject to change. Please
+ try it out and report bugs and/or improvements.
+
+[Admonition Extension]: ../extensions/admonition.md
+[rST]: http://docutils.sourceforge.net/docs/ref/rst/directives.html#specific-admonitions
+
+* Various bug fixes have been made. See the [commit
+ log](https://github.com/Python-Markdown/markdown/commits/master) for a
+ complete history of the changes.
diff --git a/docs/change_log/release-2.4.md b/docs/change_log/release-2.4.md
new file mode 100644
index 0000000..1f4ab23
--- /dev/null
+++ b/docs/change_log/release-2.4.md
@@ -0,0 +1,73 @@
+title: Release Notes for v2.4
+
+Python-Markdown 2.4 Release Notes
+=================================
+
+We are pleased to release Python-Markdown 2.4 which adds one new extension
+and fixes various bugs. See the list of changes below for details.
+
+Python-Markdown supports Python versions 2.6, 2.7, 3.1, 3.2, and 3.3.
+
+Backwards-incompatible Changes
+------------------------------
+
+* The `force_linenos` configuration setting of the CodeHilite extension has been
+ marked as **Deprecated**. It had previously been marked as "Pending
+ Deprecation" in version 2.3 when a new setting `linenums` was added to replace
+ it. See documentation for the [CodeHilite Extension] for an explanation of the
+ new `linenums` setting. The new setting will honor the old `force_linenos` if
+ it is set, but `force_linenos` will raise a `DeprecationWarning` and will
+ likely be removed in a future version of Python-Markdown.
+
+[CodeHilite Extension]: ../extensions/code_hilite.md
+
+* URLs are no longer percent-encoded. This improves compatibility with the
+ original (written in Perl) Markdown implementation. Please percent-encode your
+ URLs manually when needed.
+
+What's New in Python-Markdown 2.4
+---------------------------------
+
+* Thanks to the hard work of [Dmitry Shachnev] the [Smarty Extension] has been
+ added, which implements [SmartyPants] using Python-Markdown's Extension API.
+ This offers a few benefits over a third party script. The HTML does not need
+ to be "tokenized" twice, no hacks are required to combine SmartyPants and code
+ highlighting, and we get markdown's escaping feature for free. Please try it
+ out and report bugs and/or improvements.
+
+[Dmitry Shachnev]: https://github.com/mitya57
+[Smarty Extension]: ../extensions/smarty.md
+[SmartyPants]: https://daringfireball.net/projects/smartypants/
+
+* The [Table of Contents Extension] now supports new `permalink` option for
+ creating [Sphinx]-style anchor links.
+
+[Table of Contents Extension]: ../extensions/toc.md
+[Sphinx]: http://sphinx-doc.org/
+
+* It is now possible to enable Markdown formatting inside HTML blocks by
+ appending `markdown=1` to opening tag attributes. See [Markdown Inside HTML
+ Blocks] section for details. Thanks to [ryneeverett] for implementing this
+ feature.
+
+[Markdown Inside HTML Blocks]: ../extensions/extra.md#nested-markdown-inside-html-blocks
+[ryneeverett]: https://github.com/ryneeverett
+
+* The code blocks now support emphasizing some of the code lines. To use this
+ feature, specify `hl_lines` option after language name, for example (using the
+ [Fenced Code Extension]):
+
+ ```.python hl_lines="1 3"
+ # This line will be emphasized.
+ # This one won't.
+ # This one will be also emphasized.
+ ```
+
+ Thanks to [A. Jesse Jiryu Davis] for implementing this feature.
+
+[Fenced Code Extension]: ../extensions/fenced_code_blocks.md
+[A. Jesse Jiryu Davis]: https://github.com/ajdavis
+
+* Various bug fixes have been made. See the [commit
+ log](https://github.com/Python-Markdown/markdown/commits/master) for a
+ complete history of the changes.
diff --git a/docs/change_log/release-2.5.md b/docs/change_log/release-2.5.md
new file mode 100644
index 0000000..519f013
--- /dev/null
+++ b/docs/change_log/release-2.5.md
@@ -0,0 +1,189 @@
+title: Release Notes for v2.5
+
+Python-Markdown 2.5 Release Notes
+=================================
+
+We are pleased to release Python-Markdown 2.5 which adds a few new features
+and fixes various bugs. See the list of changes below for details.
+
+Python-Markdown version 2.5 supports Python versions 2.7, 3.2, 3.3, and 3.4.
+
+Backwards-incompatible Changes
+------------------------------
+
+* Python-Markdown no longer supports Python version 2.6. You must be using Python
+ versions 2.7, 3.2, 3.3, or 3.4.
+
+[importlib]: https://pypi.org/project/importlib/
+
+* The `force_linenos` configuration key on the [CodeHilite Extension] has been **deprecated**
+ and will raise a `KeyError` if provided. In the previous release (2.4), it was
+ issuing a `DeprecationWarning`. The [`linenums`][linenums] keyword should be used
+ instead, which provides more control of the output.
+
+[CodeHilite Extension]: ../extensions/code_hilite.md
+[linenums]: ../extensions/code_hilite.md#usage
+
+* Both `safe_mode` and the associated `html_replacement_text` keywords will be
+ deprecated in version 2.6 and will raise a **`PendingDeprecationWarning`** in
+ 2.5. The so-called "safe mode" was never actually "safe" which has resulted in
+ many people having a false sense of security when using it. As an alternative,
+ the developers of Python-Markdown recommend that any untrusted content be
+ passed through an HTML sanitizer (like [Bleach]) after being converted to HTML
+ by markdown.
+
+ If your code previously looked like this:
+
+ html = markdown.markdown(text, same_mode=True)
+
+ Then it is recommended that you change your code to read something like this:
+
+ import bleach
+ html = bleach.clean(markdown.markdown(text))
+
+ If you are not interested in sanitizing untrusted text, but simply desire to
+ escape raw HTML, then that can be accomplished through an extension which
+ removes HTML parsing:
+
+ from markdown.extensions import Extension
+
+ class EscapeHtml(Extension):
+ def extendMarkdown(self, md, md_globals):
+ del md.preprocessors['html_block']
+ del md.inlinePatterns['html']
+
+ html = markdown.markdown(text, extensions=[EscapeHtml()])
+
+ As the HTML would not be parsed with the above Extension, then the
+ serializer will escape the raw HTML, which is exactly what happens now when
+ `safe_mode="escape"`.
+
+[Bleach]: https://bleach.readthedocs.io/
+
+* Positional arguments on the `markdown.Markdown()` are pending deprecation as are
+ all except the `text` argument on the `markdown.markdown()` wrapper function.
+ Only keyword arguments should be used. For example, if your code previously
+ looked like this:
+
+ html = markdown.markdown(text, ['extra'])
+
+ Then it is recommended that you change it to read something like this:
+
+ html = markdown.markdown(text, extensions=['extra'])
+
+ !!! Note
+ This change is being made as a result of deprecating `"safe_mode"` as the
+ `safe_mode` argument was one of the positional arguments. When that argument
+ is removed, the two arguments following it will no longer be at the correct
+ position. It is recommended that you always use keywords when they are supported
+ for this reason.
+
+* In previous versions of Python-Markdown, the built-in extensions received
+ special status and did not require the full path to be provided. Additionally,
+ third party extensions whose name started with `"mdx_"` received the same
+ special treatment. This behavior will be deprecated in version 2.6 and will
+ raise a **`PendingDeprecationWarning`** in 2.5. Ensure that you always use the
+ full path to your extensions. For example, if you previously did the
+ following:
+
+ markdown.markdown(text, extensions=['extra'])
+
+ You should change your code to the following:
+
+ markdown.markdown(text, extensions=['markdown.extensions.extra'])
+
+ The same applies to the command line:
+
+ $ python -m markdown -x markdown.extensions.extra input.txt
+
+ See the [documentation](../reference.md#extensions) for a full explanation
+ of the current behavior.
+
+* The previously documented method of appending the extension configuration as
+ a string to the extension name will be deprecated in Python-Markdown
+ version 2.6 and will raise a **`PendingDeprecationWarning`** in 2.5. The
+ [`extension_configs`](../reference.md#extension_configs) keyword should
+ be used instead. See the [documentation](../reference.md#extension-configs)
+ for a full explanation of the current behavior.
+
+What's New in Python-Markdown 2.5
+---------------------------------
+
+* The [Smarty Extension] has had a number of additional configuration settings
+ added, which allows one to define their own substitutions to better support
+ languages other than English. Thanks to [Martin Altmayer] for implementing this
+ feature.
+
+[Smarty Extension]: ../extensions/smarty.md
+[Martin Altmayer]:https://github.com/MartinAltmayer
+
+* Named Extensions (strings passed to the [`extensions`][ex] keyword of
+ `markdown.Markdown`) can now point to any module and/or Class on your
+ PYTHONPATH. While dot notation was previously supported, a module could not
+ be at the root of your PYTHONPATH. The name had to contain at least one dot
+ (requiring it to be a sub-module). This restriction no longer exists.
+
+ Additionally, a Class may be specified in the name. The class must be at the
+ end of the name (which uses dot notation from PYTHONPATH) and be separated
+ by a colon from the module.
+
+ Therefore, if you were to import the class like this:
+
+ from path.to.module import SomeExtensionClass
+
+ Then the named extension would comprise this string:
+
+ "path.to.module:SomeExtensionClass"
+
+ This allows multiple extensions to be implemented within the same module and
+ still accessible when the user is not able to import the extension directly
+ (perhaps from a template filter or the command line).
+
+ This also means that extension modules are no longer required to include the
+ `makeExtension` function which returns an instance of the extension class.
+ However, if the user does not specify the class name (she only provides
+ `"path.to.module"`) the extension will fail to load without the
+ `makeExtension` function included in the module. Extension authors will want
+ to document carefully what is required to load their extensions.
+
+[ex]: ../reference.md#extensions
+
+* The Extension Configuration code has been refactored to make it a little
+ easier for extension authors to work with configuration settings. As a
+ result, the [`extension_configs`][ec] keyword now accepts a dictionary
+ rather than requiring a list of tuples. A list of tuples is still supported
+ so no one needs to change their existing code. This should also simplify the
+ learning curve for new users.
+
+ Extension authors are encouraged to review the new methods available on the
+ `markdown.extnesions.Extension` class for handling configuration and adjust
+ their code going forward. The included extensions provide a model for best
+ practices. See the [API] documentation for a full explanation.
+
+[ec]: ../reference.md#extension_configs
+[API]: ../extensions/api.md#configsettings
+
+* The [Command Line Interface][cli] now accepts a `--extensions_config` (or
+ `-c`) option which accepts a file name and passes the parsed content of a
+ [YAML] or [JSON] file to the [`extension_configs`][ec] keyword of the
+ `markdown.Markdown` class. The contents of the YAML or JSON must map to a
+ Python Dictionary which matches the format required by the
+ `extension_configs` keyword. Note that [PyYAML] is required to parse YAML
+ files.
+
+[cli]: ../cli.md#using-extensions
+[YAML]: https://yaml.org/
+[JSON]: https://json.org/
+[PyYAML]: https://pyyaml.org/
+
+* The [Admonition Extension][ae] is no longer considered "experimental."
+
+[ae]: ../extensions/admonition.md
+
+* There have been various refactors of the testing framework. While those
+ changes will not directly effect end users, the code is being better tested
+ which will benefit everyone.
+
+* Various bug fixes have been made. See the [commit
+ log](https://github.com/Python-Markdown/markdown/commits/master) for a
+ complete history of the changes.
diff --git a/docs/change_log/release-2.6.md b/docs/change_log/release-2.6.md
new file mode 100644
index 0000000..f117eb8
--- /dev/null
+++ b/docs/change_log/release-2.6.md
@@ -0,0 +1,304 @@
+title: Release Notes for v2.6
+
+# Python-Markdown 2.6 Release Notes
+
+We are pleased to release Python-Markdown 2.6 which adds a few new features
+and fixes various bugs. See the list of changes below for details.
+
+Python-Markdown version 2.6 supports Python versions 2.7, 3.2, 3.3, and 3.4 as
+well as PyPy.
+
+## Backwards-incompatible Changes
+
+### `safe_mode` Deprecated
+
+Both `safe_mode` and the associated `html_replacement_text` keywords are
+deprecated in version 2.6 and will raise a **`DeprecationWarning`**. The
+`safe_mode` and `html_replacement_text` keywords will be ignored in the next
+release. The so-called "safe mode" was never actually "safe" which has resulted
+in many people having a false sense of security when using it. As an
+alternative, the developers of Python-Markdown recommend that any untrusted
+content be passed through an HTML sanitizer (like [Bleach]) after being
+converted to HTML by markdown. In fact, [Bleach Whitelist] provides a curated
+list of tags, attributes, and styles suitable for filtering user-provided HTML
+using bleach.
+
+If your code previously looked like this:
+
+```python
+html = markdown.markdown(text, safe_mode=True)
+```
+
+Then it is recommended that you change your code to read something like this:
+
+```python
+import bleach
+from bleach_whitelist import markdown_tags, markdown_attrs
+html = bleach.clean(markdown.markdown(text), markdown_tags, markdown_attrs)
+```
+
+If you are not interested in sanitizing untrusted text, but simply desire to
+escape raw HTML, then that can be accomplished through an extension which
+removes HTML parsing:
+
+```python
+from markdown.extensions import Extension
+
+class EscapeHtml(Extension):
+ def extendMarkdown(self, md, md_globals):
+ del md.preprocessors['html_block']
+ del md.inlinePatterns['html']
+
+html = markdown.markdown(text, extensions=[EscapeHtml()])
+```
+
+As the HTML would not be parsed with the above Extension, then the serializer
+will escape the raw HTML, which is exactly what happens now when
+`safe_mode="escape"`.
+
+[Bleach]: https://bleach.readthedocs.io/
+[Bleach Whitelist]: https://github.com/yourcelf/bleach-whitelist
+
+### Positional Arguments Deprecated
+
+Positional arguments on the `markdown.Markdown()` class are deprecated as are
+all except the `text` argument on the `markdown.markdown()` wrapper function.
+Using positional arguments will raise a **`DeprecationWarning`** in 2.6 and an
+error in the next release. Only keyword arguments should be used. For example,
+if your code previously looked like this:
+
+```python
+html = markdown.markdown(text, [SomeExtension()])
+```
+
+Then it is recommended that you change it to read something like this:
+
+```python
+html = markdown.markdown(text, extensions=[SomeExtension()])
+```
+
+!!! Note
+ This change is being made as a result of deprecating `"safe_mode"` as the
+ `safe_mode` argument was one of the positional arguments. When that argument
+ is removed, the two arguments following it will no longer be at the correct
+ position. It is recommended that you always use keywords when they are
+ supported for this reason.
+
+### "Shortened" Extension Names Deprecated
+
+In previous versions of Python-Markdown, the built-in extensions received
+special status and did not require the full path to be provided. Additionally,
+third party extensions whose name started with `"mdx_"` received the same
+special treatment. This behavior is deprecated and will raise a
+**`DeprecationWarning`** in version 2.6 and an error in the next release. Ensure
+that you always use the full path to your extensions. For example, if you
+previously did the following:
+
+```python
+markdown.markdown(text, extensions=['extra'])
+```
+
+You should change your code to the following:
+
+```python
+markdown.markdown(text, extensions=['markdown.extensions.extra'])
+```
+
+The same applies to the command line:
+
+```python
+python -m markdown -x markdown.extensions.extra input.txt
+```
+
+Similarly, if you have used a third party extension (for example `mdx_math`),
+previously you might have called it like this:
+
+```python
+markdown.markdown(text, extensions=['math'])
+```
+
+As the `"mdx"` prefix will no longer be appended, you will need to change your
+code as follows (assuming the file `mdx_math.py` is installed at the root of
+your PYTHONPATH):
+
+```python
+markdown.markdown(text, extensions=['mdx_math'])
+```
+
+Extension authors will want to update their documentation to reflect the new
+behavior.
+
+See the [documentation](../reference.md#extensions) for a full explanation
+of the current behavior.
+
+### Extension Configuration as Part of Extension Name Deprecated
+
+The previously documented method of appending the extension configuration
+options as a string to the extension name is deprecated and will raise a
+**`DeprecationWarning`** in version 2.6 and an error in 2.7. The
+[`extension_configs`](../reference.md#extension_configs) keyword should be used
+instead. See the [documentation](../reference.md#extension-configs) for a full
+explanation of the current behavior.
+
+### HeaderId Extension Pending Deprecation
+
+The HeaderId Extension is pending deprecation and will raise a
+**`PendingDeprecationWarning`** in version 2.6. The extension will be deprecated
+in the next release and raise an error in the release after that. Use the [Table
+of Contents][TOC] Extension instead, which offers most of the features of the
+HeaderId Extension and more (support for meta data is missing).
+
+Extension authors who have been using the `slugify` and `unique` functions
+defined in the HeaderId Extension should note that those functions are now
+defined in the Table of Contents extension and should adjust their import
+statements accordingly (`from markdown.extensions.toc import slugify, unique`).
+
+### The `configs` Keyword is Deprecated
+
+Positional arguments and the `configs` keyword on the
+`markdown.extension.Extension` class (and its subclasses) are deprecated. Each
+individual configuration option should be passed to the class as a keyword/value
+pair. For example. one might have previously initiated an extension subclass
+like this:
+
+```python
+ext = SomeExtension(configs={'somekey': 'somevalue'})
+```
+
+That code should be updated to pass in the options directly:
+
+```python
+ext = SomeExtension(somekey='somevalue')
+```
+
+Extension authors will want to note that this affects the `makeExtension`
+function as well. Previously it was common for the function to be defined as
+follows:
+
+```python
+def makeExtension(configs=None):
+ return SomeExtension(configs=configs)
+```
+
+Extension authors will want to update their code to the following instead:
+
+```python
+def makeExtension(**kwargs):
+ return SomeExtension(**kwargs)
+```
+
+Failing to do so will result in a **`DeprecationWarning`** and will raise an
+error in the next release. See the [Extension API][mext] documentation for more
+information.
+
+In the event that an `markdown.extension.Extension` subclass overrides the
+`__init__` method and implements its own configuration handling, then the above
+may not apply. However, it is recommended that the subclass still calls the
+parent `__init__` method to handle configuration options like so:
+
+```python
+class SomeExtension(markdown.extension.Extension):
+ def __init__(**kwargs):
+ # Do pre-config stuff here
+ # Set config defaults
+ self.config = {
+ 'option1' : ['value1', 'description1'],
+ 'option2' : ['value2', 'description2']
+ }
+ # Set user defined configs
+ super(MyExtension, self).__init__(**kwargs)
+ # Do post-config stuff here
+```
+
+Note the call to `super` to get the benefits of configuration handling from the
+parent class. See the [documentation][config] for more information.
+
+[config]: ../extensions/api.md#configsettings
+[mext]: ../extensions/api.md#makeextension
+
+## What's New in Python-Markdown 2.6
+
+### Official Support for PyPy
+
+Official support for [PyPy] has been added. While Python-Markdown has most
+likely worked on PyPy for some time, it is now officially supported and tested
+on PyPy.
+
+[PyPy]: https://pypy.org/
+
+### YAML Style Meta-Data
+
+<del>The [Meta-Data] Extension now includes optional support for [YAML] style
+meta-data.</del> By default, the YAML deliminators are recognized, however, the
+actual data is parsed as previously. This follows the syntax of [MultiMarkdown],
+which inspired this extension.
+
+<del>Alternatively, if the `yaml` option is set, then the data is parsed as
+YAML.</del> <ins>As the `yaml` option was buggy, it was removed in 2.6.1. It is
+suggested that a preprocessor (like [docdata]) or a third party extension be
+used if you want true YAML support. See [Issue #390][#390] for a full
+explanation.</ins>
+
+[MultiMarkdown]: https://fletcherpenney.net/multimarkdown/#metadata
+[Meta-Data]: ../extensions/meta_data.md
+[YAML]: https://yaml.org/
+[#390]: https://github.com/Python-Markdown/markdown/issues/390
+[docdata]: https://github.com/waylan/docdata
+
+### Table of Contents Extension Refactored
+
+The [Table of Contents][TOC] Extension has been refactored and some new features
+have been added. See the documentation for a full explanation of each feature
+listed below:
+
+* The extension now assigns the Table of Contents to the `toc` attribute of
+ the Markdown class regardless of whether a "marker" was found in the
+ document. Third party frameworks no longer need to insert a "marker," run
+ the document through Markdown, then extract the Table of Contents from the
+ document.
+
+* The Table of Contents Extension is now a "registered extension." Therefore,
+ when the `reset` method of the Markdown class is called, the `toc` attribute
+ on the Markdown class is cleared (set to an empty string).
+
+* When the `marker` configuration option is set to an empty string, the parser
+ completely skips the process of searching the document for markers. This
+ should save parsing time when the Table of Contents Extension is being used
+ only to assign ids to headers.
+
+* A `separator` configuration option has been added allowing users to override
+ the separator character used by the slugify function.
+
+* A `baselevel` configuration option has been added allowing users to set the
+ base level of headers in their documents (h1-h6). This allows the header
+ levels to be automatically adjusted to fit within the hierarchy of an HTML
+ template.
+
+[TOC]: ../extensions/toc.md
+
+### Pygments can now be disabled
+
+The [CodeHilite][ch] Extension has gained a new configuration option:
+`use_pygments`. The option is `True` by default, however, it allows one to turn
+off Pygments code highlighting (set to `False`) while preserving the language
+detection features of the extension. Note that Pygments language guessing is not
+used as that would 'use Pygments'. If a language is defined for a code block, it
+will be assigned to the `<code>` tag as a class in the manner suggested by the
+[HTML5 spec][spec] (alternate output will not be entertained) and could
+potentially be used by a JavaScript library in the browser to highlight the code
+block.
+
+[ch]: ../extensions/code_hilite.md
+[spec]: https://www.w3.org/TR/html5/text-level-semantics.html#the-code-element
+
+### Miscellaneous
+
+Test coverage has been improved including running [flake8]. While those changes
+will not directly effect end users, the code is being better tested which will
+benefit everyone.
+
+[flake8]: https://flake8.readthedocs.io/en/latest/
+
+Various bug fixes have been made. See the
+[commit log](https://github.com/Python-Markdown/markdown/commits/master)
+for a complete history of the changes.
diff --git a/docs/change_log/release-3.0.md b/docs/change_log/release-3.0.md
new file mode 100644
index 0000000..29cdc4d
--- /dev/null
+++ b/docs/change_log/release-3.0.md
@@ -0,0 +1,228 @@
+title: Release Notes for v3.0
+
+# Python-Markdown 3.0 Release Notes
+
+We are pleased to release Python-Markdown 3.0 which adds a few new features and
+fixes various bugs and deprecates various old features. See the list of changes
+below for details.
+
+Python-Markdown version 3.0 supports Python versions 2.7, 3.4, 3.5, 3.6, 3.7,
+PyPy and PyPy3.
+
+## Backwards-incompatible changes
+
+### `enable_attributes` keyword deprecated
+
+The `enable_attributes` keyword is deprecated in version 3.0 and will be
+ignored. Previously the keyword was `True` by default and enabled an
+undocumented way to define attributes on document elements. The feature has been
+removed from version 3.0. As most users did not use the undocumented feature, it
+should not affect most users. For the few who did use the feature, it can be
+enabled by using the [Legacy Attributes](../extensions/legacy_attrs.md)
+extension.
+
+### `smart_emphasis` keyword and `smart_strong` extension deprecated
+
+The `smart_emphasis` keyword is deprecated in version 3.0 and will be ignored.
+Previously the keyword was `True` by default and caused the parser to ignore
+middle-word emphasis. Additionally, the optional `smart_strong` extension
+provided the same behavior for strong emphasis. Both of those features are now
+part of the default behavior, and the [Legacy
+Emphasis](../extensions/legacy_em.md) extension is available to disable that
+behavior.
+
+### `output_formats` simplified to `html` and `xhtml`.
+
+The `output_formats` keyword now only accepts two options: `html` and `xhtml`
+Note that if `(x)html1`, `(x)html4` or `(x)html5` are passed in, the number is
+stripped and ignored.
+
+### `safe_mode` and `html_replacement_text` keywords deprecated
+
+Both `safe_mode` and the associated `html_replacement_text` keywords are
+deprecated in version 3.0 and will be ignored. The so-called "safe mode" was
+never actually "safe" which has resulted in many people having a false sense of
+security when using it. As an alternative, the developers of Python-Markdown
+recommend that any untrusted content be passed through an HTML sanitizer (like
+[Bleach]) after being converted to HTML by markdown. In fact, [Bleach Whitelist]
+provides a curated list of tags, attributes, and styles suitable for filtering
+user-provided HTML using bleach.
+
+If your code previously looked like this:
+
+```python
+html = markdown.markdown(text, safe_mode=True)
+```
+
+Then it is recommended that you change your code to read something like this:
+
+```python
+import bleach
+from bleach_whitelist import markdown_tags, markdown_attrs
+html = bleach.clean(markdown.markdown(text), markdown_tags, markdown_attrs)
+```
+
+If you are not interested in sanitizing untrusted text, but simply desire to
+escape raw HTML, then that can be accomplished through an extension which
+removes HTML parsing:
+
+```python
+from markdown.extensions import Extension
+
+class EscapeHtml(Extension):
+ def extendMarkdown(self, md):
+ md.preprocessors.deregister('html_block')
+ md.inlinePatterns.deregister('html')
+
+html = markdown.markdown(text, extensions=[EscapeHtml()])
+```
+
+As the HTML would not be parsed with the above Extension, then the serializer
+will escape the raw HTML, which is exactly what happened in previous versions
+with `safe_mode="escape"`.
+
+[Bleach]: https://bleach.readthedocs.io/
+[Bleach Whitelist]: https://github.com/yourcelf/bleach-whitelist
+
+### Positional arguments deprecated
+
+Positional arguments on the `markdown.Markdown()` class are deprecated as are
+all except the `text` argument on the `markdown.markdown()` wrapper function.
+Using positional arguments will raise an error. Only keyword arguments should be
+used. For example, if your code previously looked like this:
+
+```python
+html = markdown.markdown(text, [SomeExtension()])
+```
+
+Then it is recommended that you change it to read something like this:
+
+```python
+html = markdown.markdown(text, extensions=[SomeExtension()])
+```
+
+!!! Note
+ This change is being made as a result of deprecating `"safe_mode"` as the
+ `safe_mode` argument was one of the positional arguments. When that argument
+ is removed, the two arguments following it will no longer be at the correct
+ position. It is recommended that you always use keywords when they are
+ supported for this reason.
+
+### Extension name behavior has changed
+
+In previous versions of Python-Markdown, the built-in extensions received
+special status and did not require the full path to be provided. Additionally,
+third party extensions whose name started with `"mdx_"` received the same
+special treatment. This is no longer the case.
+
+Support has been added for extensions to define an [entry
+point](../extensions/api.md#entry_point). An entry point is a string name which
+can be used to point to an `Extension` class. The built-in extensions now have
+entry points which match the old short names. And any third-party extensions
+which define entry points can now get the same behavior. See the documentation
+for each specific extension to find the assigned name.
+
+If an extension does not define an entry point, then the full path to the
+extension must be used. See the [documentation](../reference.md#extensions) for
+a full explanation of the current behavior.
+
+### Extension configuration as part of extension name deprecated
+
+The previously documented method of appending the extension configuration
+options as a string to the extension name is deprecated and will raise an error.
+The [`extension_configs`](../reference.md#extension_configs) keyword should be
+used instead. See the [documentation](../reference.md#extension_configs) for a
+full explanation of the current behavior.
+
+### HeaderId extension deprecated
+
+The HeaderId Extension is deprecated and will raise an error if specified. Use
+the [Table of Contents](../extensions/toc.md) Extension instead, which offers
+most of the features of the HeaderId Extension and more (support for meta data
+is missing).
+
+Extension authors who have been using the `slugify` and `unique` functions
+defined in the HeaderId Extension should note that those functions are now
+defined in the Table of Contents extension and should adjust their import
+statements accordingly (`from markdown.extensions.toc import slugify, unique`).
+
+### Homegrown `OrderedDict` has been replaced with a purpose-built `Registry`
+
+All processors and patterns now get "registered" to a
+[Registry](../extensions/api.md#registry). A backwards compatible shim is
+included so that existing simple extensions should continue to work.
+A `DeprecationWarning` will be raised for any code which calls the old API.
+
+### Markdown class instance references.
+
+Previously, instances of the `Markdown` class were represented as any one of
+`md`, `md_instance`, or `markdown`. This inconsistency made it difficult when
+developing extensions, or just maintaining the existing code. Now, all instances
+are consistently represented as `md`.
+
+The old attributes on class instances still exist, but raise a
+`DeprecationWarning` when accessed. Also on classes where the instance was
+optional, the attribute always exists now and is simply `None` if no instance
+was provided (previously the attribute would not exist).
+
+### `markdown.util.isBlockLevel` deprecated
+
+The `markdown.util.isBlockLevel` function is deprecated and will raise a
+`DeprecationWarning`. Instead, extensions should use the `isBlockLevel` method
+of the `Markdown` class instance. Additionally, a list of block level elements
+is defined in the `block_level_elements` attribute of the `Markdown` class which
+extensions can access to alter the list of elements which are treated as block
+level elements.
+
+### `md_globals` keyword deprecated from extension API
+
+Previously, the `extendMarkdown` method of a `markdown.extensions.Extension`
+subclasses accepted an `md_globals` keyword, which contained the value returned
+by Python's `globals()` built-in function. As all of the configuration is now
+held within the `Markdown` class instance, access to the globals is no longer
+necessary and any extensions which expect the keyword will raise a
+`DeprecationWarning`. A future release will raise an error.
+
+### `markdown.version` and `markdown.version_info` deprecated
+
+Historically, version numbers were acquired via the attributes
+`markdown.version` and `markdown.version_info`. Moving forward, a more
+standardized approach is being followed and versions are acquired via the
+`markdown.__version__` and `markdown.__version_info__` attributes. The legacy
+attributes are still available to allow distinguishing versions between the
+legacy Markdown 2.0 series and the Markdown 3.0 series, but in the future the
+legacy attributes will be removed.
+
+### Added new, more flexible `InlineProcessor` class
+
+A new `InlineProcessor` class handles inline processing much better and allows
+for more flexibility. The new `InlineProcessor` classes no longer utilize
+unnecessary pretext and post-text captures. New class can accept the buffer that
+is being worked on and manually process the text without regular expressions and
+return new replacement bounds. This helps us to handle links in a better way and
+handle nested brackets and logic that is too much for regular expression.
+
+## New features
+
+The following new features have been included in the release:
+
+* A new [testing framework](../test_tools.md) is included as a part of the
+ Markdown library, which can also be used by third party extensions.
+
+* A new `toc_depth` parameter has been added to the
+ [Table of Contents Extension](../extensions/toc.md).
+
+* A new `toc_tokens` attribute has been added to the Markdown class by the
+ [Table of Contents Extension](../extensions/toc.md), which contains the raw
+ tokens used to build the Table of Contents. Users can use this to build their
+ own custom Table of Contents rather than needing to parse the HTML available
+ on the `toc` attribute of the Markdown class.
+
+* When the [Table of Contents Extension](../extensions/toc.md) is used in
+ conjunction with the [Attribute Lists Extension](../extensions/attr_list.md)
+ and a `data-toc-label` attribute is defined on a header, the content of the
+ `data-toc-label` attribute is now used as the content of the Table of Contents
+ item for that header.
+
+* Additional CSS class names can be appended to
+ [Admonitions](../extensions/admonition.md).
diff --git a/docs/change_log/release-3.1.md b/docs/change_log/release-3.1.md
new file mode 100644
index 0000000..b05cd23
--- /dev/null
+++ b/docs/change_log/release-3.1.md
@@ -0,0 +1,48 @@
+title: Release Notes for v3.1
+
+# Python-Markdown 3.1 Release Notes
+
+Python-Markdown version 3.1 supports Python versions 2.7, 3.5, 3.6, 3.7,
+PyPy and PyPy3.
+
+## Backwards-incompatible changes
+
+### `markdown.version` and `markdown.version_info` deprecated
+
+Historically, version numbers were acquired via the attributes
+`markdown.version` and `markdown.version_info`. As of 3.0, a more standardized
+approach is being followed and versions are acquired via the
+`markdown.__version__` and `markdown.__version_info__` attributes. As of 3.1
+the legacy attributes will raise a `DeprecationWarning` if they are accessed. In
+a future release the legacy attributes will be removed.
+
+## New features
+
+The following new features have been included in the release:
+
+* A [Contributing Guide](../contributing.md) has been added (#732).
+
+* A new configuration option to set the footnote separator has been added. Also,
+ the `rel` and `rev` attributes have been removed from footnotes as they are
+ not valid in HTML5. The `refs` and `backrefs` classes already exist and
+ serve the same purpose (#723).
+
+* A new option for `toc_depth` to set not only the bottom section level,
+ but also the top section level. A string consisting of two digits
+ separated by a hyphen in between (`"2-5"`), defines the top (`t`) and the
+ bottom (`b`) (`<ht>..<hb>`). A single integer still defines the bottom
+ section level (`<h1>..<hb>`) only. (#787).
+
+## Bug fixes
+
+The following bug fixes are included in the 3.1 release:
+
+* Update CLI to support PyYAML 5.1.
+* Overlapping raw HTML matches no longer leave placeholders behind (#458).
+* Emphasis patterns now recognize newline characters as whitespace (#783).
+* Version format had been updated to be PEP 440 compliant (#736).
+* Block level elements are defined per instance, not as class attributes
+ (#731).
+* Double escaping of block code has been eliminated (#725).
+* Problems with newlines in references has been fixed (#742).
+* Escaped `#` are now handled in header syntax (#762).
diff --git a/docs/change_log/release-3.2.md b/docs/change_log/release-3.2.md
new file mode 100644
index 0000000..f9452cc
--- /dev/null
+++ b/docs/change_log/release-3.2.md
@@ -0,0 +1,96 @@
+title: Release Notes for v3.2
+
+# Python-Markdown 3.2 Release Notes
+
+Python-Markdown version 3.2 supports Python versions 3.5, 3.6, 3.7, 3.8, and
+PyPy3.
+
+## Backwards-incompatible changes
+
+### Drop support for Python 2.7
+
+Python 2.7 reaches end-of-life on 2020-01-01 and Python-Markdown 3.2 has dropped
+support for it. Please upgrade to Python 3, or use Python-Markdown 3.1.
+
+### `em` and `strong` inline processor changes
+
+In order to fix issue #792, `em`/`strong` inline processors were refactored. This
+translated into removing many of the existing inline processors that handled this
+logic:
+
+* `em_strong`
+* `strong`
+* `emphasis`
+* `strong2`
+* `emphasis`
+
+These processors were replaced with two new ones:
+
+* `em_strong`
+* `em_strong2`
+
+The [`legacy_em`](../extensions/legacy_em.md) extension was also modified with new,
+refactored logic and simply overrides the `em_strong2` inline processor.
+
+### CodeHilite now always wraps with `<code>` tags
+
+Before, the HTML generated by CodeHilite looked like:
+- `<pre><code>foo = 'bar'</code></pre>` if you **were not** using Pygments.
+- `<pre>foo = 'bar'</pre>` if you **were** using Pygments.
+
+To make the cases more consistent (and adhere to many Markdown specifications and
+HTML code block markup suggestions), CodeHilite will now always additionally wrap
+code with `<code>` tags. See #862 for more details.
+
+This change does not alter the Python-Markdown API, but users relying on the old
+markup will find their output now changed.
+
+Internally, this change relies on the Pygments 2.4, so you must be using at least
+that version to see this effect. Users with earlier Pygments versions will
+continue to see the old behavior.
+
+### `markdown.util.etree` deprecated
+
+Previously, Python-Markdown was using either the `xml.etree.cElementTree` module
+or the `xml.etree.ElementTree` module, based on their availability. In modern
+Python versions, the former is a deprecated alias for the latter. Thus, the
+compatibility layer is deprecated and extensions are advised to use
+`xml.etree.ElementTree` directly. Importing `markdown.util.etree` will raise
+a `DeprecationWarning` beginning in version 3.2 and may be removed in a future
+release.
+
+Therefore, extension developers are encouraged to replace
+`from markdown.util import etree` with
+`import xml.etree.ElementTree as etree` in their code.
+
+## New features
+
+The following new features have been included in the release:
+
+* Some new configuration options have been added to the [toc](../extensions/toc.md)
+ extension:
+
+ * The `anchorlink_class` and `permalink_class` options allow class(es) to be
+ assigned to the `anchorlink` and `permalink` respectively. This allows using
+ icon fonts from CSS for the links. Therefore, an empty string passed to
+ `permalink` now generates an empty `permalink`. Previously no `permalink`
+ would have been generated. (#776)
+
+ * The `permalink_title` option allows the title attribute of a `permalink` to be
+ set to something other than the default English string `Permanent link`. (#877)
+
+* Document thread safety (#812).
+
+* Markdown parsing in HTML has been exposed via a separate extension called
+ [`md_in_html`](../extensions/md_in_html.md).
+
+* Add support for Python 3.8.
+
+## Bug fixes
+
+The following bug fixes are included in the 3.2 release:
+
+* HTML tag placeholders are no longer included in `.toc_tokens` (#899).
+* Unescape backslash-escaped characters in TOC ids (#864).
+* Refactor bold and italic logic in order to solve complex nesting issues (#792).
+* Always wrap CodeHilite code in `code` tags (#862).
diff --git a/docs/change_log/release-3.3.md b/docs/change_log/release-3.3.md
new file mode 100644
index 0000000..79e22b2
--- /dev/null
+++ b/docs/change_log/release-3.3.md
@@ -0,0 +1,109 @@
+title: Release Notes for v3.3
+
+# Python-Markdown 3.3 Release Notes
+
+Python-Markdown version 3.3 supports Python versions 3.6, 3.7, 3.8, 3.9 and PyPy3.
+
+## Backwards-incompatible changes
+
+### The prefix `language-` is now prepended to all language classes by default on code blocks.
+
+The [HTML5 spec][spec] recommends that the class defining the language of a code block be prefixed with `language-`.
+Therefore, by default, both the [fenced_code] and [codehilite] extensions now prepend the prefix when code
+highlighting is disabled.
+
+If you have previously been including the prefix manually in your fenced code blocks, then you will not want a second
+instance of the prefix. Similarly, if you are using a third party syntax highlighting tool which does not recognize
+the prefix, or requires a different prefix, then you will want to redefine the prefix globally using the `lang_prefix`
+configuration option of either the `fenced_code` or `codehilite` extensions.
+
+For example, to configure `fenced_code` to not apply any prefix (the previous behavior), set the option to an empty string:
+
+```python
+from markdown.extensions.fenced_code import FencedCodeExtension
+
+markdown.markdown(src, extensions=[FencedCodeExtension(lang_prefix='')])
+```
+
+!!! note
+ When code highlighting is [enabled], the output from Pygments is used unaltered. Currently, Pygments does not
+ provide an option to include the language class in the output, let alone prefix it. Therefore, any language prefix
+ is only applied when syntax highlighting is disabled.
+
+### Attribute Lists are more strict (#898).
+
+Empty curly braces are now completely ignored by the [Attribute List] extension. Previously, the extension would
+recognize them as attribute lists and remove them from the document. Therefore, it is no longer necessary to backslash
+escape a set of curly braces which are empty or only contain whitespace.
+
+Despite not being documented, previously an attribute list could be defined anywhere within a table cell and get
+applied to the cell (`<td>` element). Now the attribute list must be defined at the end of the cell content and must
+be separated from the rest of the content by at least one space. This makes it easy to differentiate between attribute
+lists defined on inline elements within a cell and the attribute list for the cell itself. It is also more consistent
+with how attribute lists are defined on other types of elements.
+
+The extension has also added support for defining attribute lists on table header cells (`<th>` elements) in the same
+manner as data cells (`<td>` elements).
+
+In addition, the documentation for the extensions received an overhaul. The features (#987) and limitations (#965) of the extension are now fully documented.
+
+## New features
+
+The following new features have been included in the 3.3 release:
+
+* All Pygments' options are now available for syntax highlighting (#816).
+ - The [Codehilite](../extensions/code_hilite.md) extension now accepts any options
+ which Pygments supports as global configuration settings on the extension.
+ - [Fenced Code Blocks](../extensions/fenced_code_blocks.md) will accept any of the
+ same options on individual code blocks.
+ - Any of the previously supported aliases to Pygments' options continue to be
+ supported at this time. However, it is recommended that the Pygments option names
+ be used directly to ensure continued compatibility in the future.
+
+* [Fenced Code Blocks](../extensions/fenced_code_blocks.md) now work with
+ [Attribute Lists](../extensions/attr_list.md) when syntax highlighting is disabled.
+ Any random HTML attribute can be defined and set on the `<code>` tag of fenced code
+ blocks when the `attr_list` extension is enabled (#816).
+
+* The HTML parser has been completely replaced. The new HTML parser is built on Python's
+ [html.parser.HTMLParser](https://docs.python.org/3/library/html.parser.html), which
+ alleviates various bugs and simplify maintenance of the code (#803, #830).
+
+* The [Markdown in HTML](../extensions/md_in_html.md) extension has been rebuilt on the
+ new HTML Parser, which drastically simplifies it. Note that raw HTML elements with a
+ `markdown` attribute defined are now converted to ElementTree Elements and are rendered
+ by the serializer. Various bugs have been fixed (#803, #595, #780, and #1012).
+
+* Link reference parsing, abbreviation reference parsing and footnote reference parsing
+ has all been moved from `preprocessors` to `blockprocessors`, which allows them to be
+ nested within other block level elements. Specifically, this change was necessary to
+ maintain the current behavior in the rebuilt Markdown in HTML extension. A few random
+ edge-case bugs (see the included tests) were resolved in the process (#803).
+
+* An alternate function `markdown.extensions.headerid.slugify_unicode` has been included
+ with the [Table of Contents](../extensions/toc.md) extension which supports Unicode
+ characters in table of contents slugs. The old `markdown.extensions.headerid.slugify`
+ method which removes non-ASCII characters remains the default. Import and pass
+ `markdown.extensions.headerid.slugify_unicode` to the `slugify` configuration option
+ to use the new behavior.
+
+* Support was added for Python 3.9 and dropped for Python 3.5.
+
+## Bug fixes
+
+The following bug fixes are included in the 3.3 release:
+
+* Document how to pass configuration options to Extra (#1019).
+* Fix HR which follows strong em (#897).
+* Support short reference image links (#894).
+* Avoid a `RecursionError` from deeply nested blockquotes (#799).
+* Fix issues with complex emphasis (#979).
+* Fix unescaping of HTML characters `<>` in CodeHilite (#990).
+* Fix complex scenarios involving lists and admonitions (#1004).
+* Fix complex scenarios with nested ordered and unordered lists in a definition list (#918).
+
+[spec]: https://www.w3.org/TR/html5/text-level-semantics.html#the-code-element
+[fenced_code]: ../extensions/fenced_code_blocks.md
+[codehilite]: ../extensions/code_hilite.md
+[enabled]: ../extensions/fenced_code_blocks.md#enabling-syntax-highlighting
+[Attribute List]: ../extensions/attr_list.md
diff --git a/docs/change_log/release-3.4.md b/docs/change_log/release-3.4.md
new file mode 100644
index 0000000..bfa8075
--- /dev/null
+++ b/docs/change_log/release-3.4.md
@@ -0,0 +1,113 @@
+title: Release Notes for v3.4
+
+# Python-Markdown 3.4 Release Notes
+
+Python-Markdown version 3.4 supports Python versions 3.7, 3.8, 3.9, 3.10 and
+PyPy3.
+
+## Backwards-incompatible changes
+
+### The `tables` extension now uses a `style` attribute instead of an `align` attribute for alignment.
+
+The [HTML4 spec][spec4] specifically deprecates the use of the `align` attribute
+and it does not appear at all in the [HTML5 spec][spec5]. Therefore, by default,
+the [tables] extension will now use the `style` attribute (setting just the
+`text-align` property) in `td` and `th` blocks.
+
+[spec4]: https://www.w3.org/TR/html4/present/graphics.html#h-15.1.2
+[spec5]: https://www.w3.org/TR/html53/tabular-data.html#attributes-common-to-td-and-th-elements
+[tables]: ../extensions/tables.md
+
+The former behavior is available by setting the `use_align_attribute`
+configuration option to `True` when enabling the extension.
+
+For example, to configure the old `align` behavior:
+
+```python
+from markdown.extensions.tables import TableExtension
+
+markdown.markdown(src, extensions=[TableExtension(use_align_attribute=True)])
+```
+
+### Backslash unescaping moved to Treeprocessor (#1131).
+
+Unescaping backslash escapes has been moved to a Treeprocessor, which enables
+proper HTML escaping during serialization. However, it is recognized that
+various third-party extensions may be calling the old class at
+`postprocessors.UnescapePostprocessor`. Therefore, the old class remains in the
+code base, but has been deprecated and will be removed in a future release. The
+new class `treeprocessors.UnescapeTreeprocessor` should be used instead.
+
+### Previously deprecated objects have been removed
+
+Various objects were deprecated in version 3.0 and began raising deprecation
+warnings (see the [version 3.0 release notes] for details). Any of those objects
+which remained in version 3.3 have been removed from the code base in version 3.4
+and will now raise errors. The relevant objects are listed below.
+
+[version 3.0 release notes]: release-3.0.md
+
+| Deprecated Object | Replacement Object |
+|----------------------------------------|-------------------------------------|
+| `markdown.version` | `markdown.__version__` |
+| `markdown.version_info` | `markdown.__version_info__` |
+| `markdown.util.etree` | `xml.etree.ElementTree` |
+| `markdown.util.string_type` | `str` |
+| `markdown.util.text_type` | `str` |
+| `markdown.util.int2str` | `chr` |
+| `markdown.util.iterrange` | `range` |
+| `markdown.util.isBlockLevel` | `markdown.Markdown().is_block_level`|
+| `markdown.util.Processor().markdown` | `markdown.util.Processor().md` |
+| `markdown.util.Registry().__setitem__` | `markdown.util.Registry().register` |
+| `markdown.util.Registry().__delitem__` |`markdown.util.Registry().deregister`|
+| `markdown.util.Registry().add` | `markdown.util.Registry().register` |
+
+In addition, the `md_globals` parameter of
+`Markdown.extensions.Extension.extendMarkdown()` is no longer recognized as a
+valid parameter and will raise an error if provided.
+
+## New features
+
+The following new features have been included in the 3.4 release:
+
+
+* Some new configuration options have been added to the
+ [footnotes](../extensions/footnotes.md) extension (#1218):
+
+ * Small refactor of the `BACKLINK_TITLE` option; The use of `format()`
+ instead of "old" `%d` formatter allows one to specify text without the
+ need to have the number of the footnote in it (like footnotes on
+ Wikipedia for example). The modification is backward compatible so no
+ configuration change is required.
+
+ * Addition of a new option `SUPERSCRIPT_TEXT` that allows one to specify a
+ custom placeholder for the footnote itself in the text.
+ Ex: `[{}]` will give `<sup>[1]</sup>`, `({})` will give `<sup>(1)</sup>`,
+ or by default, the current behavior: `<sup>1</sup>`.
+
+* The [Table of Contents](../extensions/toc.md) extension now accepts a
+ `toc_class` parameter which can be used to set the CSS class(es) on the
+ `<div>` that contains the Table of Contents (#1224).
+
+* The CodeHilite extension now supports a `pygments_formatter` option that can
+ be set to a custom formatter class (#1187).
+
+ - If `pygments_formatter` is set to a string (ex: `'html'`), Pygments'
+ default formatter by that name is used.
+ - If `pygments_formatter` is set to a formatter class (or any callable
+ which returns a formatter instance), then an instance of that class is
+ used.
+
+ The formatter class is now passed an additional option, `lang_str`, to
+ denote the language of the code block (#1258). While Pygments' built-in
+ formatters will ignore the option, a custom formatter assigned to the
+ `pygments_formatter` option can make use of the `lang_str` to include the
+ code block's language in the output.
+
+## Bug fixes
+
+The following bug fixes are included in the 3.4 release:
+
+* Extension entry-points are only loaded if needed (#1216).
+* Added additional checks to the `<pre><code>` handling of
+ `PrettifyTreeprocessor` (#1261, #1263).
diff --git a/docs/cli.md b/docs/cli.md
new file mode 100644
index 0000000..50e9ec2
--- /dev/null
+++ b/docs/cli.md
@@ -0,0 +1,189 @@
+title: Command Line
+
+Using Python-Markdown on the Command Line
+=========================================
+
+While Python-Markdown is primarily a python library, a command line script is
+included as well. While there are many other command line implementations
+of Markdown, you may not have them installed, or you may prefer to use
+Python-Markdown's various extensions.
+
+Generally, you will want to have the Markdown library fully installed on your
+system to run the command line script. See the
+[Installation instructions](install.md) for details.
+
+Python-Markdown's command line script takes advantage of Python's `-m` flag.
+Therefore, assuming the python executable is on your system path, use the
+following format:
+
+```bash
+python -m markdown [options] [args]
+```
+
+That will run the module as a script with the options and arguments provided.
+
+At its most basic usage, one would simply pass in a file name as the only argument:
+
+```bash
+python -m markdown input_file.txt
+```
+
+Piping input and output (on `STDIN` and `STDOUT`) is fully supported as well.
+For example:
+
+```bash
+echo "Some **Markdown** text." | python -m markdown > output.html
+```
+
+Use the `--help` option for a list all available options and arguments:
+
+```bash
+python -m markdown --help
+```
+
+If you don't want to call the python executable directly (using the `-m` flag),
+follow the instructions below to use a wrapper script:
+
+Setup
+-----
+
+Upon installation, the `markdown_py` script will have been copied to
+your Python "Scripts" directory. Different systems require different methods to
+ensure that any files in the Python "Scripts" directory are on your system
+path.
+
+* **Windows**:
+
+ Assuming a default install of Python on Windows, your "Scripts" directory
+ is most likely something like `C:\\Python37\Scripts`. Verify the location
+ of your "Scripts" directory and add it to you system path.
+
+ Calling `markdown_py` from the command line will call the wrapper batch
+ file `markdown_py.bat` in the `"Scripts"` directory created during install.
+
+* __*nix__ (Linux, OSX, BSD, Unix, etc.):
+
+ As each \*nix distribution is different and we can't possibly document all
+ of them here, we'll provide a few helpful pointers:
+
+ * Some systems will automatically install the script on your path. Try it
+ and see if it works. Just run `markdown_py` from the command line.
+
+ * Other systems may maintain a separate "Scripts" ("bin") directory which
+ you need to add to your path. Find it (check with your distribution) and
+ either add it to your path or make a symbolic link to it from your path.
+
+ * If you are sure `markdown_py` is on your path, but it still is not being
+ found, check the permissions of the file and make sure it is executable.
+
+ As an alternative, you could just `cd` into the directory which contains
+ the source distribution, and run it from there. However, remember that your
+ markdown text files will not likely be in that directory, so it is much
+ more convenient to have `markdown_py` on your path.
+
+!!!Note
+ Python-Markdown uses `"markdown_py"` as a script name because the Perl
+ implementation has already taken the more obvious name "markdown".
+ Additionally, the default Python configuration on some systems would cause a
+ script named `"markdown.py"` to fail by importing itself rather than the
+ markdown library. Therefore, the script has been named `"markdown_py"` as a
+ compromise. If you prefer a different name for the script on your system, it
+ is suggested that you create a symbolic link to `markdown_py` with your
+ preferred name.
+
+Usage
+-----
+
+To use `markdown_py` from the command line, run it as
+
+```bash
+markdown_py input_file.txt
+```
+
+or
+
+```bash
+markdown_py input_file.txt > output_file.html
+```
+
+For a complete list of options, run
+
+```bash
+markdown_py --help
+```
+
+Using Extensions
+----------------
+
+To load a Python-Markdown extension from the command line use the `-x`
+(or `--extension`) option. The extension module must be on your `PYTHONPATH`
+(see the [Extension API](extensions/api.md) for details). The extension can
+then be invoked by the name assigned to an entry point or using Python's dot
+notation to point to an extension
+
+For example, to load an extension with the assigned entry point name `myext`,
+run the following command:
+
+```bash
+python -m markdown -x myext input.txt
+```
+
+And to load an extension with Python's dot notation:
+
+```bash
+python -m markdown -x path.to.module:MyExtClass input.txt
+```
+
+To load multiple extensions, specify an `-x` option for each extension:
+
+```bash
+python -m markdown -x myext -x path.to.module:MyExtClass input.txt
+```
+
+If the extension supports configuration options (see the documentation for the
+extension you are using to determine what settings it supports, if any), you
+can pass them in as well:
+
+```bash
+python -m markdown -x myext -c config.yml input.txt
+```
+
+The `-c` (or `--extension_configs`) option accepts a file name. The file must be
+in either the [YAML] or [JSON] format and contain YAML or JSON data that would
+map to a Python Dictionary in the format required by the
+[`extension_configs`][ec] keyword of the `markdown.Markdown` class. Therefore,
+the file `config.yaml` referenced in the above example might look like this:
+
+```yaml
+myext:
+ option1: 'value1'
+ option2: True
+```
+
+Similarly, a JSON configuration file might look like this:
+
+```json
+{
+ "myext":
+ {
+ "option1": "value1",
+ "option2": "value2"
+ }
+}
+```
+
+Note that while the `--extension_configs` option does specify the
+`myext` extension, you still need to load the extension with the `-x` option,
+or the configuration for that extension will be ignored. Further, if an
+extension requires a value that cannot be parsed in JSON (for example a
+reference to a function), one has to use a YAML configuration file.
+
+The `--extension_configs` option will only support YAML configuration files if
+[PyYAML] is installed on your system. JSON should work with no additional
+dependencies. The format of your configuration file is automatically detected.
+
+[ec]: reference.md#extension_configs
+[YAML]: https://yaml.org/
+[JSON]: https://json.org/
+[PyYAML]: https://pyyaml.org/
+[2.5 release notes]: change_log/release-2.5.md
diff --git a/docs/command_line.txt b/docs/command_line.txt
deleted file mode 100644
index d0134ea..0000000
--- a/docs/command_line.txt
+++ /dev/null
@@ -1,98 +0,0 @@
-Using Python-Markdown on the Command Line
-=========================================
-
-While Python-Markdown is primarily a python library, a command line script is
-included as well. While there are many other command line implementations
-of Markdown, you may not have them installed, or you may prefer to use
-Python-Markdown's various extensions.
-
-Setup
------
-
-Generally, you may simply call the ``markdown`` file from the command
-line. However, if you have fully installed Markdown (``setup.py install`` or
-``easy_install``), then the ``markdown`` script will have been copied to
-you Python "Scripts" directory. Different systems require different methods to
-ensure that any files in the Python "Scripts" directory are on your system
-path.
-
-* **Windows**:
-
- Assuming a default install on Windows, your "Scripts" directory is most
- likely something like ``C:\\Python25\Scripts``. Verify the location of
- your "Scripts" directory and add it to you system path.
-
- Calling ``markdown`` from th ecommand line will call the wrapper batch file
- ``markdown.bat`` in the "Scripts" directory created during install.
-
-* **Linux**:
-
- As each Linux distribution is different and we can't possibly document all
- of them here, we'll provide a few helpful pointers:
-
- * Some systems will automatically install the script on your path. Try it
- and see if it works. Just run ``markdown`` from the command line.
-
- * Other systems may maintain a separate "Scripts" directory which you
- need to add to your path. Find it (check with your distribution) and
- either add it to your path or make a symbolic link to it from your path.
-
- * If you are sure ``markdown`` is on your path, but it still isn't being
- found, check the permissions of the file and make sure it is executable.
-
- As an alternative, you could just ``cd`` into the directory which contains
- the source distribution, and run it from there. However, remember that your
- markdown text files will not likely be in that directory, so it is much more
- convenient to have ``markdown`` on your path.
-
-The Basics
-----------
-
-To use ``markdown`` from the command line, run it as
-
- $ markdown input_file.txt
-
-or
-
- $ markdown input_file.txt > output_file.html
-
-More Options
-------------
-
-If you are using Python 2.3 or higher, you can also use advanced
-command line options to specify encoding or to run extensions.
-
- $ markdown --help
- Usage: markdown INPUTFILE [options]
-
- Options:
- -h, --help show this help message and exit
- -f OUTPUT_FILE, --file=OUTPUT_FILE
- write output to OUTPUT_FILE
- -e ENCODING, --encoding=ENCODING
- encoding for input and output files
- -q, --quiet suppress all messages
- -v, --verbose print info messages
- -s SAFE_MODE, --safe=SAFE_MODE
- safe mode ('replace', 'remove' or 'escape' user's
- HTML tag)
- -o OUTPUT_FORMAT, --output_format=OUTPUT_FORMAT
- Format of output. One of 'xhtml1' (default) or
- 'html4'.
- --noisy print debug messages
- -x EXTENSION, --extension=EXTENSION
- load extension EXTENSION
-
-Using Extensions
-----------------
-
-For an extension to be ran this way it must be provided in a module
-which should be in your python path (see [[writing_extensions]] for details).
-It can then be invoked by the name of that module:
-
- $ markdown -x footnotes text_with_footnotes.txt > output.html
-
-If the extension supports config options, you can pass them in as well:
-
- $ markdown -x "footnotes(PLACE_MARKER=~~~~~~~~)" input.txt
-
diff --git a/docs/contributing.md b/docs/contributing.md
new file mode 100644
index 0000000..5022e45
--- /dev/null
+++ b/docs/contributing.md
@@ -0,0 +1,561 @@
+# Contributing to Python-Markdown
+
+The following is a set of guidelines for contributing to Python-Markdown and its
+extensions, which are hosted in the [Python-Markdown Organization] on GitHub.
+These are mostly guidelines, not rules. Use your best judgment, and feel free to
+propose changes to this document in a pull request.
+
+## Code of Conduct
+
+This project and everyone participating in it is governed by the
+[Python-Markdown Code of Conduct]. By participating, you are expected to uphold
+this code. Please report unacceptable behavior to <python.markdown@gmail.com>.
+
+## Project Organization
+
+The core Python-Markdown code base and any built-in extensions are hosted in the
+[Python-Markdown/markdown] project on GitHub. Other extensions maintained by the
+Python-Markdown project may be hosted as separate repositories in the
+[Python-Markdown Organization] on GitHub and must follow best practices for
+third-party extensions.
+
+The [Python-Markdown/markdown] project is organized as follows:
+
+* Branch `master` should generally be stable and release-ready at all times.
+* Version branches should be used for bug-fixes back-ported to the most recent
+ PATCH release.
+* No other branches should be created. Any other branches which exist are
+ preserved for historical reasons only.
+
+## Issues
+
+Feature requests, bug reports, usage questions, and other issues can all be
+raised on the GitHub [issue tracker].
+
+When describing issues try to phrase your ticket in terms of the behavior you
+think needs to change rather than the code you think needs to change.
+
+Make sure you're running the latest version of Python-Markdown before reporting
+an issue.
+
+Search the issue list first for related items. Be sure to check closed issues
+and pull requests. GitHub's search only checks open issues by default.
+
+You may want to check the [syntax rules] and/or [Babelmark] to confirm that your
+expectations align with the rules and/or other implementations of Markdown.
+
+If reporting a syntax bug, you must provide the minimal input which exhibits the
+behavior, the actual output and the output you expected. All three items must be
+provided as textual code blocks (screen-shots are not helpful). It may also be
+helpful to point to the [syntax rules] which specifically address the area of
+concern.
+
+Feature requests will often be closed with a recommendation that they be
+implemented as third party extensions outside of the core Python-Markdown
+library. Keeping new feature requests implemented as third party extensions
+allows us to keep the maintenance overhead of Python-Markdown to a minimum, so
+that the focus can be on continued stability, bug fixes, and documentation.
+
+Closing an issue does not necessarily mean the end of a discussion. If you
+believe your issue has been closed incorrectly, explain why and we'll consider
+if it needs to be reopened.
+
+## Pull Requests
+
+A pull request often represents the start of a discussion, and does not
+necessarily need to be the final, finished submission. In fact, if you discover
+an issue and intend to provide a fix for it, there is no need to open an issue
+first. You can report the issue and provide the fix together in a pull request.
+
+All pull requests should be made from your personal fork of the library hosted
+in your personal GitHub account. Do not create branches on the
+[Python-Markdown/markdown] project for pull requests. All pull requests should
+be implemented in a new branch with a unique name. Remember that if you have an
+outstanding pull request, pushing new commits to the related branch of your
+GitHub repository will also automatically update the pull request. It may help
+to review GitHub's documentation on [Creating a pull request from a fork].
+
+If you are providing a fix for a previously reported issue, you must reference
+the issue in your commit message. Be sure to prefix the reference with one of
+GitHub's [action words] which will automatically close the issue when the pull
+request is merged. For example, `fixes #42` and `closes #42` would be
+acceptable, whereas `ref #42` would not. Of course, if merging a pull request
+should not cause an issue to be closed, then the action word should not be
+included when referencing that issue.
+
+Before being accepted, each pull request must include the applicable code, new
+tests of all new features, updated tests for any changed features, documentation
+updates, and an appropriate update to the release notes. All changes must follow
+the applicable style guides. Failure to meet any one of the requirements is
+likely to delay any serious consideration of your pull request and may even
+cause it to be closed. Of course, if you are in the early stages of development,
+you may include a note in the pull request acknowledging that it is incomplete
+along with a request for feedback.
+
+Pull requests will generally not be accepted if any tests are failing.
+Therefore, it is recommended that you run the tests before submitting your pull
+request. After making a pull request, check the build status in the
+GitHub interface to ensure that all tests are running as expected. If any checks
+fail, you may push additional commits to your branch. GitHub will add those
+commits to the pull request and rerun the checks.
+
+## Style Guides
+
+In an effort to maintain consistency, Python-Markdown adheres to the following
+style guides in its code and documentation. A pull request may be rejected if it
+fails to match the relevant style guides.
+
+### Code Style Guide
+
+Except as noted below, all pull requests should follow Python's standard [PEP8
+Style Guide] and are run through [Flake8] to ensure that the style guide is
+followed.
+
+Legacy code which does not follow the guidelines should only be updated if and
+when other changes (bug fix, feature addition, etc.) are being made to that
+section of code. While new features should be given names that follow modern
+Python naming conventions, existing names should be preserved to avoid backward
+incompatible changes.
+
+Line length is limited to a maximum of 119 characters.
+
+When a line of code does not fit within the line length limit, continuation
+lines should align elements wrapped inside parentheses, brackets and braces
+using a *hanging indent*. When using a hanging indent there should be no
+arguments on the first line and further indentation should be used to clearly
+distinguish itself as a continuation line. The closing parenthesis, bracket or
+brace should be on a line by itself and should line up under the first character
+of the line that starts the multi-line construct.
+
+```python
+my_list = [
+ 1, 2, 3,
+ 4, 5, 6,
+]
+result = some_function_that_takes_arguments(
+ 'a', 'b', 'c',
+ 'd', 'e', 'f',
+)
+```
+
+When the conditional part of an `if`-statement is long enough to require that it
+be written across multiple lines, extra indentation should be included on the
+conditional continuation line.
+
+```python
+if (this_is_one_thing
+ and that_is_another_thing):
+ do_something()
+```
+
+### Documentation Style Guide
+
+Documentation should be in American English. The tone of the documentation
+should be simple, plain, objective and well-balanced where possible.
+
+Keep paragraphs reasonably short.
+
+With the exception of code blocks, limit line length to 79 characters. You may
+want to use your editor's tools to automatically hard wrap lines of text.
+
+Don't use abbreviations such as 'e.g.' but instead use the long form, such as
+'For example'.
+
+The documentation is built from the [Markdown] source files in the [`docs`
+directory][docs directory] by the [MkDocs] static site generator. In addition to
+the basic Markdown syntax, the following extensions are supported: [extra],
+[admonition], [smarty], [codehilite], and [toc].
+
+There are a few conventions you should follow when working on the
+documentation.
+
+#### Headers
+
+Headers should use the hash style. For example:
+
+```md
+## Some important topic
+```
+
+The underline style should not be used. Don't do this:
+
+```md
+Some important topic
+====================
+```
+
+#### Links
+
+Links should always use the reference style, with the referenced hyperlinks kept
+at the end of the document.
+
+```md
+Here is a link to [some other thing][other-thing].
+
+More text...
+
+[other-thing]: http://example.com/other/thing
+```
+
+This style helps keep the documentation source consistent and readable.
+
+If you are linking to another document within Python-Markdown's documentation,
+you should use a relative link, and link to the `.md` suffix. If applicable, it
+is preferred that the link includes a hash fragment pointing to the specific
+section of the page. For example:
+
+```md
+[authentication]: reference.md#Markdown
+```
+
+Linking in this style ensures that the links work when browsing the
+documentation on GitHub. If your Markdown editor makes links clickable, they
+will work there as well. When the documentation is built, these links will be
+converted into regular links which point to the built HTML pages.
+
+#### Notes and Warnings
+
+If you want to draw attention to a note or warning, use the syntax defined in
+Python-Markdown's [Admonition Extension]:
+
+```md
+!!! note
+
+ This is the content of the note.
+```
+
+### Commit Message Style Guide
+
+Use the present tense ("Add feature" not "Added feature").
+
+Use the imperative mood ("Move item to..." not "Moves item to...").
+
+Limit the first line to 72 characters or less.
+
+Reference issues and pull requests liberally after the first line. Include a
+summary of the changes/additions made without replicating the content of the
+documentation or release notes. This is where an explanation of the choices made
+should be found. References to issues and pull requests should only provide the
+context in which a choice was made. However, the commit should be able to stand
+on its own.
+
+## Development Environment
+
+To start developing on Python-Markdown is it best to create a [fork] of the
+project on GitHub. After [cloning your fork] to your local system, you will want
+to [configure a remote] that points to the upstream repository so that you can
+[sync changes] made in the original repository with your fork.
+
+It is recommended that all development be done from within a Python [virtual
+environment], which isolates any experimental code from the general system. To
+create a virtual environment, use the following command from the root of the
+local working copy of your GitHub fork:
+
+```sh
+virtualenv venv
+```
+
+That creates a virtual environment which is contained in the `venv` directory
+within your local working copy. Note that the repository is configured so that
+git will ignore any files within a directory named `venv` or `ENV` for this
+very reason.
+
+On Posix systems (Linux, BSD, MacOS, etc.), use the following command to
+activate the environment:
+
+```sh
+source venv/bin/activate
+```
+
+On Windows, use this command instead:
+
+```sh
+venv/Scripts/activate
+```
+
+See the [User Guide] for more information on using virtual environments.
+
+To be able to run the Markdown library directly while working on it, install the
+working copy into the environment in [Development Mode] after activating the
+virtual environment for the first time:
+
+```sh
+pip install --editable .
+```
+
+Now any saved changes will immediately be available within the virtual
+environment.
+
+You can run the command line script with the following command:
+
+```sh
+python -m markdown
+```
+
+And you can directly run the tests with:
+
+```sh
+python -m unittest discover tests
+```
+
+!!! note
+
+ Some tests require the [PyTidyLib] library, which depends on the [HTML Tidy]
+ library. If you do not have PyTidyLib installed, the tests which depend upon
+ it will be skipped. Given the difficulty in installing the HTML Tidy library
+ on many systems, you may choose to leave both libraries uninstalled and
+ depend on the Travis server to run those tests when you submit a pull
+ request.
+
+The above setup will only run tests against the code in one version of Python.
+However, Python-Markdown supports multiple versions of Python. Therefore, a
+[tox] configuration is included in the repository, which includes test
+environments for all supported Python versions, a [Flake8] test environment, and
+a spellchecker for the documentation. While it is generally fine to leave those
+tests for the Travis server to run when a pull request is submitted, for more
+advanced changes, you may want to run those tests locally. To do so, simply
+install tox:
+
+```sh
+pip install tox
+```
+
+Then, to run all configured test environments, simply call the command `tox`
+with no arguments. See help (`tox -h`) for more options.
+
+!!! note
+
+ The tox environments expect that some dependencies are already installed on
+ your system. For example, by default, any Python version specific
+ environment will fail if that version of Python is not installed.
+ Additionally, the tox environments assume that the [HTML Tidy] library is
+ installed and may fail when attempting to install [PyTidyLib] if it is not.
+ Finally, the `spellchecker` environment requires [aspell] and the
+ `aspell-en` dictionary to be installed. Unfortunately, installing those
+ dependencies may differ significantly from system to system and is outside
+ the scope of this guide.
+
+!!! seealso "See Also"
+
+ Python-Markdown provides [test tools] which simply testing Markdown syntax.
+ Understanding those tools will often help in understanding why a test may be
+ failing.
+
+## Versions
+
+Python-Markdown follows [Semantic Versioning] and uses the
+`MAJOR.MINOR.PATCH[.dev#|a#|b#|rc#]` format for identifying releases. The status
+of the `master` branch should always be identified in the `__version_info__`
+tuple defined in [`markdown/__meta__.py`][markdown/__meta__.py]. The contents of
+that tuple will automatically be converted into a normalized version which
+conforms to [PEP 440]. An invalid `__version_info__` tuple will raise an error,
+preventing the library from running and the package from building.
+
+### Version Status
+
+A MAJOR version is in development status when the MINOR version is `0`, the
+PATCH version is `0`, and the version includes a `dev` segment.
+
+A MINOR version is in development status when the MINOR version is not `0`, the
+PATCH version is `0`, and the version includes a `dev` segment.
+
+At all other times, the code is considered stable and release-ready.
+
+MAJOR and MINOR releases may or may not get pre-releases (alpha, beta, release
+candidate, etc.) at the discretion of the project maintainers.
+
+### Version Workflow
+
+Bug fixes may be merged from a pull request to the `master` branch at any time
+so long as all tests pass, including one or more new tests which would have
+failed prior to the change.
+
+New features and backward incompatible changes may only be merged to the
+`master` branch when the MAJOR and/or MINOR version is in development status
+pursuant to [Semantic Versioning].
+
+A separate commit to the `master` branch should be made to bump up the MAJOR
+and/or MINOR version and set development status. Only then will any pull
+requests implementing new features or backward incompatible changes be accepted.
+
+If a bug fix is deemed to be important and the `master` branch is in development
+status, a back-port of the fix should be committed to a version branch. If the
+appropriate version branch does not exist, then it should be created and a pull
+request back-porting the fix made against that branch. The version branch should
+be named with the most recently released MINOR version. For example, if the
+`master` branch is at `3.1.dev0` and the most recent MINOR release was `3.0.4`,
+then the version branch would be named `3.0` and any releases from that branch
+would increment the PATCH version only (`3.0.5`, `3.0.6`...).
+
+## Release Process
+
+When a new release is being prepared, the release manager should follow the
+following steps:
+
+1. Verify that all outstanding issues and pull requests related to the release
+ have been resolved.
+
+2. Confirm that the release notes and change log have been updated and indicate
+ the date of the new release.
+
+3. Update the version defined in [`markdown/__meta__.py`][markdown/__meta__.py].
+
+4. Build a local copy of the documentation, browse through the pages and
+ confirm that no obvious issues exist with the documentation.
+
+5. Create a pull request with a commit message in the following format:
+
+ Bump version to X.X.X
+
+6. After all checks have passed, merge the pull request.
+
+7. Create a git tag with the new version as the tag name and push to the
+ [Python-Markdown/markdown] repository. The new tag should trigger a GitHub
+ workflow which will automatically deploy the release to PyPI and update the
+ documentation.
+
+ In the event that the deployment fails, the following steps can be taken to
+ deploy manually:
+
+ - Deploy the release to [PyPI] with the command `make deploy`.
+
+ - Deploy an update to the documentation using [MkDocs]. The following example
+ assumes that local clones of the [Python-Markdown/markdown] and
+ [Python-Markdown/Python-Markdown.github.io] repositories are in sibling
+ directories named `markdown` and `Python-Markdown.github.io` respectively.
+
+ cd Python-Markdown.github.io
+ mkdocs gh-deploy --config-file ../markdown/mkdocs.yml --remote-branch master
+
+## Issue and Pull Request Labels
+
+Below are the labels used to track and manages issues and pull requests. The
+labels are loosely grouped by their purpose, but it is not necessary for every
+issue to have a label from every group, and an issue may have more than one
+label from the same group.
+
+### Type of Issue or Pull Request
+
+| Label name | Description |
+| ---------------------------- | ---------------- |
+| `bug`{ .label .bug } | Bug report. |
+| `feature`{ .label .feature } | Feature request. |
+| `support`{ .label .support } | Support request. |
+| `process`{ .label .process } | Discussions regarding policies and development process. |
+
+### Category of Issue or Pull Request
+
+| Label name | Description |
+| -------------------------------- | ---------------------------------------- |
+| `core`{ .label .core } | Related to the core parser code. |
+| `extension`{ .label .extension } | Related to one or more of the included extensions. |
+| `docs`{ .label .docs } | Related to the project documentation. |
+
+### Status of Issue
+
+| Label name | Description |
+| --------------------------------------- | --------------------------------- |
+| `more-info-needed`{ .label .pending } | More information needs to be provided. |
+| `needs-confirmation`{ .label .pending } | The alleged behavior needs to be confirmed. |
+| `needs-decision`{ .label .pending } | A decision needs to be made regarding request. |
+| `confirmed`{ .label .approved } | Confirmed bug report or approved feature request. |
+| `someday-maybe`{ .label .low } | Approved **low priority** request. |
+| `duplicate`{ .label .rejected } | The issue has been previously reported. |
+| `wontfix`{ .label .rejected } | The issue will not be fixed for the stated reasons. |
+| `invalid`{ .label .rejected } | Invalid report (user error, upstream issue, etc). |
+| `3rd-party`{ .label .rejected } | Should be implemented as a third party extension. |
+
+
+### Status of Pull Request
+
+| Label name | Description |
+| ------------------------------------- | ----------------------------------- |
+| `work-in-progress`{ .label .pending } | A partial solution. More changes will be coming. |
+| `needs-review`{ .label .pending } | Needs to be reviewed and/or approved. |
+| `requires-changes`{ .label .pending } | Awaiting updates after a review. |
+| `approved`{ .label .approved } | The pull request is ready to be merged. |
+| `rejected`{ .label .rejected } | The pull request is rejected for the stated reasons. |
+
+[Python-Markdown Organization]: https://github.com/Python-Markdown
+[Python-Markdown Code of Conduct]: https://github.com/Python-Markdown/markdown/blob/master/CODE_OF_CONDUCT.md
+[Python-Markdown/markdown]: https://github.com/Python-Markdown/markdown
+[issue tracker]: https://github.com/Python-Markdown/markdown/issues
+[syntax rules]: https://daringfireball.net/projects/markdown/syntax
+[Babelmark]: https://johnmacfarlane.net/babelmark2/
+[Creating a pull request from a fork]: https://help.github.com/articles/creating-a-pull-request-from-a-fork/
+[action words]: https://help.github.com/articles/closing-issues-using-keywords/
+[PEP8 Style Guide]: https://www.python.org/dev/peps/pep-0008/
+[Flake8]: http://flake8.pycqa.org/en/latest/index.html
+[Markdown]: https://daringfireball.net/projects/markdown/basics
+[docs directory]: https://github.com/Python-Markdown/markdown/tree/master/docs
+[MkDocs]: https://www.mkdocs.org/
+[extra]: extensions/extra.md
+[admonition]: extensions/admonition.md
+[smarty]: extensions/smarty.md
+[codehilite]: extensions/code_hilite.md
+[toc]: extensions/toc.md
+[Admonition Extension]: extensions/admonition.md#syntax
+[fork]: https://help.github.com/articles/about-forks
+[cloning your fork]: https://help.github.com/articles/cloning-a-repository/
+[configure a remote]: https://help.github.com/articles/configuring-a-remote-for-a-fork
+[sync changes]: https://help.github.com/articles/syncing-a-fork
+[virtual environment]: https://virtualenv.pypa.io/en/stable/
+[User Guide]: https://virtualenv.pypa.io/en/stable/user_guide.html
+[Development Mode]: https://setuptools.readthedocs.io/en/latest/setuptools.html#development-mode
+[PyTidyLib]: https://countergram.github.io/pytidylib/
+[HTML Tidy]: https://www.html-tidy.org/
+[tox]: https://tox.readthedocs.io/en/latest/
+[aspell]: http://aspell.net/
+[test tools]: test_tools.md
+[Semantic Versioning]: https://semver.org/
+[markdown/__meta__.py]: https://github.com/Python-Markdown/markdown/blob/master/markdown/__meta__.py#L29
+[PEP 440]: https://www.python.org/dev/peps/pep-0440/
+[PyPI]: https://pypi.org/project/Markdown/
+[Python-Markdown/Python-Markdown.github.io]: https://github.com/Python-Markdown/Python-Markdown.github.io
+
+<style type="text/css">
+ /* GitHub Label Styles */
+
+ code.label {
+ color: #000000;
+ font-weight: 600;
+ line-height: 15px;
+ display: inline-block;
+ padding: 4px 6px;
+ }
+ code.bug {
+ background-color: #c45b46;
+ }
+ code.feature {
+ background-color: #7b17d8;
+ color: #ffffff;
+ }
+ code.support {
+ background-color: #efbe62;
+ }
+ code.process {
+ background-color: #eec9ff;
+ }
+ code.core {
+ background-color: #0b02e1;
+ color: #ffffff;
+ }
+ code.extension {
+ background-color: #709ad8;
+ }
+ code.docs {
+ background-color: #b2ffeb;
+ }
+ code.approved {
+ background-color: #beed6d;
+ }
+ code.low {
+ background-color: #dddddd;
+ }
+ code.pending {
+ background-color: #f0f49a;
+ }
+ code.rejected {
+ background-color: #f7c7be;
+ }
+</style>
diff --git a/docs/extensions/Abbreviations.txt b/docs/extensions/Abbreviations.txt
deleted file mode 100644
index fa54d3c..0000000
--- a/docs/extensions/Abbreviations.txt
+++ /dev/null
@@ -1,53 +0,0 @@
-Abbreviations
--------------
-
-Summary
--------
-
-The Markdown Abbreviation Extension adds the ability to define abbreviations.
-Specifically, any defined abbreviation is wrapped in an `<abbr>` tag.
-
-The Abbreviation extension is included in the standard Markdown library.
-
-Syntax
-------
-
-Abbreviations are defined using the syntax established in
-[PHP Markdown Extra][php].
-
-[php]: http://www.michelf.com/projects/php-markdown/extra/#abbr
-
-Thus, the following text (taken from the above referenced PHP documentation):
-
- The HTML specification
- is maintained by the W3C.
-
- *[HTML]: Hyper Text Markup Language
- *[W3C]: World Wide Web Consortium
-
-will be rendered like so:
-
- <p>The <abbr title="Hyper Text Markup Language">HTML</abbr> specification
- is maintained by the <abbr title="World Wide Web Consortium">W3C</abbr>.</p>
-
-Usage
------
-
-From the Python interpreter:
-
- >>> import markdown
- >>> text = """
- ... Some text with an ABBR.
- ...
- ... *[ABBR]: Abbreviation
- ... """
- >>> html = markdown.markdown(text, ['abbr'])
-
-To use with other extensions, just add them to the list, like this:
-
- >>> html = markdown.markdown(text, ['abbr', 'footnotes'])
-
-Abbreviations can also be called from the command line using Markdown's `-x`
-parameter, like so:
-
- markdown.py -x abbr source.txt > output.html
diff --git a/docs/extensions/CodeHilite.txt b/docs/extensions/CodeHilite.txt
deleted file mode 100644
index 482ad60..0000000
--- a/docs/extensions/CodeHilite.txt
+++ /dev/null
@@ -1,113 +0,0 @@
-CodeHilite
-==========
-
-Summary
--------
-
-The CodeHilite Extension adds code/syntax highlighting to standard
-Python-Markdown code blocks using [Pygments][].
-
-[Python-Markdown]: http://www.freewisdom.org/projects/python-markdown/
-[Pygments]: http://pygments.org/
-
-This extension is included in the Markdown library.
-
-Setup
------
-
-You will also need to [download][dl] and install the Pygments package on your
-`PYTHONPATH`. You will need to determine the appropriate CSS classes and create
-appropriate rules for them, which are either defined in or linked from the
-header of your HTML templates. See the excellent [documentation][] for more
-details. If no language is defined, Pygments will attempt to guess the
-language. When that fails, the code block will display as un-highlighted code.
-
-[dl]: http://pygments.org/download/
-[documentation]: http://pygments.org/docs
-
-**Note:** The css and/or javascript is not included as part of this extension
-but shall always be provided by the end user.
-
-Syntax
-------
-
-The CodeHilite Extension follows the same [syntax][] as regular Markdown code
-blocks, with one exception. The hiliter needs to know what language to use for
-the code block. There are three ways to tell the hiliter what language the code
-block contains and each one has a different result.
-
-[syntax]: http://daringfireball.net/projects/markdown/syntax#precode
-
-###SheBang (with path)
-
-If the first line of the codeblock contains a shebang, the language is derived
-from that and line numbers are used.
-
- #!/usr/bin/python
- # Code goes here ...
-
-Will result in:
-
- #!/usr/bin/python
- # Code goes here ...
-
-
-###SheBang (no path)
-
-If the first line contains a shebang, but the shebang line does not contain a
-path (a single `/` or even a space), then that line is removed from the code
-block before processing. Line numbers are used.
-
- #!python
- # Code goes here ...
-
-Will result in:
-
- # Code goes here ...
-
-####Colons
-
-If the first line begins with three or more colons, the text following the
-colons identifies the language. The first line is removed from the code block
-before processing and line numbers are not used.
-
- :::python
- # Code goes here ...
-
-Will result in:
-
- # Code goes here ...
-
-###When No Language is Defined
-
-CodeHilite is completely backward compatible so that if a code block is
-encountered that does not define a language, the block is simple wrapped in
-`<pre>` tags and output. Note: one exception would be that the Pygments
-highlighting engine will try to guess the language. Upon failure, the same
-behavior will happen as described here.
-
- # Code goes here ...
-
-Will result in:
-
- # Code goes here ...
-
-Lets see the source for that:
-
- <div class="codehilite" ><pre><code># Code goes here ...
- </code></pre></div>
-
-Usage
------
-
-From the Python interpreter:
-
- >>> html = markdown.markdown(text, ['codehilite'])
-
-If you want every code block to have line numbers, even when using colons
-(`:::`) for language identification, the setting `force_linenos` is available
-to do so.
-
- >>> html = markdown.markdown(text,
- ... ['codehilite(force_linenos=True)']
- ... )
diff --git a/docs/extensions/Definition_Lists.txt b/docs/extensions/Definition_Lists.txt
deleted file mode 100644
index 983070d..0000000
--- a/docs/extensions/Definition_Lists.txt
+++ /dev/null
@@ -1,55 +0,0 @@
-Definition Lists
-----------------
-
-Summary
--------
-
-The Definition List Extension adds the ability to create definition list in
-Markdown documents.
-
-This extension is included in the standard Markdown library.
-
-Syntax
-------
-
-Definition lists are defined using the syntax established in
-[PHP Markdown Extra][php].
-
-[php]: http://www.michelf.com/projects/php-markdown/extra/#def-list
-
-Thus, the following text (taken from the above referenced PHP documentation):
-
- Apple
- : Pomaceous fruit of plants of the genus Malus in
- the family Rosaceae.
-
- Orange
- : The fruit of an evergreen tree of the genus Citrus.
-
-will be rendered like so:
-
- <dl>
- <dt>Apple</dt>
- <dd>Pomaceous fruit of plants of the genus Malus in
- the family Rosaceae.</dd>
-
- <dt>Orange</dt>
- <dd>The fruit of an evergreen tree of the genus Citrus.</dd>
- </dl>
-
-
-Usage
------
-
-From the Python interpreter:
-
- >>> html = markdown.markdown(text, ['def_list'])
-
-To use with other extensions, just add them to the list, like this:
-
- >>> html = markdown.markdown(text, ['def_list', 'footnotes'])
-
-The extension can also be called from the command line using Markdown's `-x`
-parameter:
-
- markdown.py -x def_list source.txt > output.html
diff --git a/docs/extensions/Fenced_Code_Blocks.txt b/docs/extensions/Fenced_Code_Blocks.txt
deleted file mode 100644
index 6b1ba76..0000000
--- a/docs/extensions/Fenced_Code_Blocks.txt
+++ /dev/null
@@ -1,63 +0,0 @@
-Fenced Code Blocks
-==================
-
-Summary
--------
-
-This extension adds a secondary way to define code blocks which overcomes a few
-limitations of the indented code blocks.
-
-This extension is included in the standard Markdown library.
-
-Syntax
-------
-
-Fenced Code Blocks are defined using the syntax established in
-[PHP Markdown Extra][php].
-
-[php]: http://www.michelf.com/projects/php-markdown/extra/#fenced-code-blocks
-
-Thus, the following text (taken from the above referenced PHP documentation):
-
- This is a paragraph introducing:
-
- ~~~~~~~~~~~~~~~~~~~~
- a one-line code block
- ~~~~~~~~~~~~~~~~~~~~
-
-Fenced code blocks can have a blank line as the first and/or last line of a
-code block and they can also come immediately after a list item without becoming
-part of the list.
-
-In addition to PHP Extra's syntax, you can define the language of the code
-block for use by syntax highlighters etc. The language will be assigned as a
-class attribute of the ``<code>`` element in the output. Therefore, you should
-define the language as you would a css class - ``.language``. For consistency
-with other markdown syntax, the language can *optionally* be wrapped in curly
-brackets:
-
- ~~~~{.python}
- # python code
- ~~~~
-
- ~~~~.html
- <p>HTML Document</p>
- ~~~~
-
-The above will output:
-
- <pre><code class="python"># python code
- </code></pre>
-
- <pre><code class="html">&lt;p&gt;HTML Document&lt;/p&gt;
- </code></pre>
-
-Usage
------
-
-From the Python interpreter:
-
- >>> html = markdown.markdown(text, ['fenced_code'])
-
-
-
diff --git a/docs/extensions/HTML_Tidy.txt b/docs/extensions/HTML_Tidy.txt
deleted file mode 100644
index 52f991f..0000000
--- a/docs/extensions/HTML_Tidy.txt
+++ /dev/null
@@ -1,27 +0,0 @@
-HTML Tidy
-=========
-
-Runs [HTML Tidy][] on the output of Python-Markdown using the [uTidylib][]
-Python wrapper. Both libtidy and uTidylib must be installed on your system.
-
-This extension is available in the standard Markdown library since version 2.0.
-
-[HTML Tidy]: http://tidy.sourceforge.net/
-[uTidylib]: http://utidylib.berlios.de/
-
-Note than any Tidy [options][] can be passed in as extension configs. So,
-for example, to output HTML rather than XHTML, set ``output_xhtml=0``. To
-indent the output, set ``indent=auto`` and to have Tidy wrap the output in
-``<html>`` and ``<body>`` tags, set ``show_body_only=0``. See Tidy's
-[options][] for a full list of the available options. The defaults are set to
-most closely match Markdowns defaults with the exception that you get much
-better pretty-printing.
-
-[options]: http://tidy.sourceforge.net/docs/quickref.html
-
-Note that options set in this extension will override most any other settings
-passed on to Markdown (such as "output_format"). Unlike Markdown, this extension
-will also treat raw HTML no different than that output by Markdown. In other
-words, it may munge a document authors carefully crafted HTML. Of course, it
-may also transform poorly formed raw HTML into nice, valid HTML. Take these
-things into consideration when electing to use this extension.
diff --git a/docs/extensions/HeaderId.txt b/docs/extensions/HeaderId.txt
deleted file mode 100644
index efd1eb8..0000000
--- a/docs/extensions/HeaderId.txt
+++ /dev/null
@@ -1,104 +0,0 @@
-HeaderId
-========
-
-Summary
--------
-
-An extension to Python-Markdown that adds an 'id' attribute to HTML header
-elements (h1-h6) in markdown's output.
-
-This extension is included in the standard Markdown library.
-
-Syntax
-------
-
-The basic syntax follows [PHP Markdown Extra][]'s implementation:
-
-[PHP Markdown Extra]: http://michelf.com/projects/php-markdown/extra/#header-id
-
- Header 1 {#header1}
- ========
-
- ## Header 2 ## {#header2}
-
-will result in the following HTML:
-
- <h1 id="header1">Header 1</h1>
-
- <h2 id="header2">Header 2</h2>
-
-However, there is much more that this extension does.
-
-By default, all headers will automatically have unique "id" attributes
-generated based upon the text of the header (See below to turn this off).
-Note this example in which all three headers would have the same "id":
-
- #Header
- #Another Header {#header}
- #Header
-
-Results in:
-
- <h1 id="header">Header</h1>
- <h1 id="header_1">Another Header</h1>
- <h1 id="header_2">Third Header</h1>
-
-Configuring the Output
-----------------------
-
-The HeaderId extension has two configuration settings:
-
-* **level**: Base level for headers.
-
- Default: `1`
-
-* **forceid**: Force all headers to have an id.
-
- Default: `True`
-
-The `level` setting allows you to automatically adjust the header levels to fit
-within the hierarchy of your html templates. For example, the markdown text for
-this page should not contain any headers higher than level 3 (`<h3>`).
-Therefore, do the following:
-
- >>> text = '''
- ... #Some Header
- ... ## Next Level'''
- >>> html = markdown.markdown(text, ['headerid(level=3)'])
- >>> print html
- <h3 id="some_header">Some Header</h3>
- <h4 id="next_level">Next Level</h4>'
-
-The `forceid` setting turns on or off the automatically generated ids for
-headers that do not have one explicitly defined.
-
- >>> text = '''
- ... # Some Header
- ... # Header with ID # { #foo }'''
- >>> html = markdown.markdown(text, ['headerid(forceid=False)'])
- >>> print html
- <h1>Some Header</h1>
- <h1 id="foo">Header with ID</h1>
-
-Using with Meta-Data
---------------------
-
-The HeaderId Extension also supports the [[Meta-Data]] Extension. Please see the documentation for that extension for specifics. The supported meta-data keywords are:
-
-* `header_level`
-* `header_forceid`
-
-When used, the meta-data will override the settings provided through the
-`extension_configs` interface.
-
-This document:
-
- header_level: 2
- header_forceid: Off
-
- # A Header
-
-
-Will result in the following output:
-
- <h2>A Header</h2>
diff --git a/docs/extensions/ImageLinks.txt b/docs/extensions/ImageLinks.txt
deleted file mode 100644
index db4f99f..0000000
--- a/docs/extensions/ImageLinks.txt
+++ /dev/null
@@ -1,27 +0,0 @@
-ImageLinks
-==========
-
-Summary
--------
-
-ImageLinks is a Python-Markdown extension that provides a mechanism for
-defining mini-photo galleries within a markdown document.
-
-This extension is part of the Markdown library since 2.0.
-
-Syntax
-------
-
-Turns paragraphs like
-
- <~~~~~~~~~~~~~~~~~~~~~~~~
- dir/subdir
- dir/subdir
- dir/subdir
- ~~~~~~~~~~~~~~
- dir/subdir
- dir/subdir
- dir/subdir
- ~~~~~~~~~~~~~~~~~~~>
-
-Into mini-photo galleries.
diff --git a/docs/extensions/Meta-Data.txt b/docs/extensions/Meta-Data.txt
deleted file mode 100644
index 982ea67..0000000
--- a/docs/extensions/Meta-Data.txt
+++ /dev/null
@@ -1,88 +0,0 @@
-Meta-Data
-=========
-
-Summary
--------
-
-An extension to Python-Markdown that adds a syntax for defining meta-data about
-a document. The Meta-Data extension is inspired by and follows the syntax of
-[MultiMarkdown][]. Currently, this extension does not use the meta-data in any
-way, but simply provides it as a `Meta` attribute of a markdown instance for
-use by other extensions or directly by your python code.
-
-[MultiMarkdown]: http://fletcherpenney.net/MultiMarkdown_Syntax_Guide#metadata
-
-This extension has been a part of the Markdown library since 2.0.
-
-Syntax
-------
-
-Meta-data consists of a series of keywords and values defined at the beginning
-of a markdown document like this:
-
- Title: My Document
- Summary: A brief description of my document.
- Authors: Waylan Limberg
- John Doe
- Date: October 2, 2007
- blank-value:
- base_url: http://example.com
-
- This is the first paragraph of the document.
-
-The keywords are case-insensitive and may consist of letters, numbers,
-underscores and dashes and must end with a colon. The values consist of
-anything following the colon on the line and may even be blank. If a line is
-indented 4 or more spaces, that line is assumed to be an additional line of the
-value for the previous keyword. A keyword may have as many lines as desired.
-The first blank line ends all meta-data for the document. Therefore, the first
-line of a document must not be blank. All meta-data is stripped from the
-document prior to any further processing by markdown.
-
-Accessing the Meta-Data
------------------------
-
-The meta-data is made available as a python Dict in the `Meta` attribute of an
-instance of the Markdown class. For example, using the above document:
-
- >>> md = markdown.Markdown(extensions = ['meta'])
- >>> html = md.convert(text)
- >>> # Meta-data has been stripped from output
- >>> print html
- <p>This is the first paragraph of the document.</p>
-
- >>> # View meta-data
- >>> print md.Meta
- {
- 'title' : ['My Document'],
- 'summary' : ['A brief description of my document.'],
- 'authors' : ['Waylan Limberg', 'John Doe'],
- 'date' : ['October 2, 2007'],
- 'blank-value' : [''],
- 'base_url' : ['http://example.com']
- }
-
-Note that the keys are all lowercase and the values consist of a list of
-strings where each item is one line for that key. This way, one could preserve
-line breaks if desired. Or the items could be joined where appropriate. No
-assumptions are made regarding the data. It is simply passed as found to the
-`Meta` attribute.
-
-Perhaps the meta-data could be passed into a template system, or used by
-various markdown extensions. The possibilities are left to the imagination of
-the developer.
-
-Compatible Extensions
----------------------
-
-The following are extensions currently known to work with the Meta-Data
-Extension and the keywords they are known to support:
-
-* [[HeaderId]]
- * `header_level`
- * `header_forceid`
-* [[WikiLinks]]
- * `wiki_base_url`
- * `wiki_end_url`
- * `wiki_html_class`
-
diff --git a/docs/extensions/RSS.txt b/docs/extensions/RSS.txt
deleted file mode 100644
index f2ecf0c..0000000
--- a/docs/extensions/RSS.txt
+++ /dev/null
@@ -1,35 +0,0 @@
-RSS
-===
-
-Summary
--------
-
-An extension to Python-Markdown that outputs a markdown document as RSS. This
-extension has been included with Python-Markdown since 1.7 and should be
-available to anyone who has a typical install of Python-Markdown.
-
-Usage
------
-
-From the Python interpreter:
-
- >>> import markdown
- >>> text = "Some markdown document."
- >>> rss = markdown.markdown(text, ['rss'])
-
-Configuring the Output
-----------------------
-
-An RSS document includes some data about the document (URI, author, title) that
-will likely need to be configured for your needs. Therefore, three configuration
-options are available:
-
-* **URL** : The Main URL for the document.
-* **CREATOR** : The Feed creator's name.
-* **TITLE** : The title for the feed.
-
-An example:
-
- >>> rss = markdown.markdown(text, extensions = \
- ... ['rss(URL=http://example.com,CREATOR=JOHN DOE,TITLE=My Document)']
- ... )
diff --git a/docs/extensions/Tables.txt b/docs/extensions/Tables.txt
deleted file mode 100644
index 63d6849..0000000
--- a/docs/extensions/Tables.txt
+++ /dev/null
@@ -1,53 +0,0 @@
-Tables
-----------------
-
-Summary
--------
-
-The Table Extension adds the ability to create tables in Markdown documents.
-
-This extension is included in the standard Markdown library.
-
-Syntax
-------
-
-Tables are defined using the syntax established in [PHP Markdown Extra][php].
-
-[php]: http://www.michelf.com/projects/php-markdown/extra/#table
-
-Thus, the following text (taken from the above referenced PHP documentation):
-
-First Header | Second Header
-------------- | -------------
-Content Cell | Content Cell
-Content Cell | Content Cell
-
-will be rendered as:
-
-<table>
-<thead>
-<tr>
-<th>First Header</th>
-<th>Second Header</th>
-</tr>
-</thead>
-<tbody>
-<tr>
-<td>Content Cell</td>
-<td>Content Cell</td>
-
-</tr>
-<tr>
-<td>Content Cell</td>
-<td>Content Cell</td>
-</tr>
-</tbody>
-</table>
-
-Usage
------
-
-From the Python interpreter:
-
- >>> html = markdown.markdown(text, ['tables'])
-
diff --git a/docs/extensions/Tables_of_Contents.txt b/docs/extensions/Tables_of_Contents.txt
deleted file mode 100644
index 032c25c..0000000
--- a/docs/extensions/Tables_of_Contents.txt
+++ /dev/null
@@ -1,50 +0,0 @@
-Table of Contents
-=================
-
-Summary
--------
-
-Adds a Table of Contents to a Markdown document.
-
-This extension is included with the Markdown library since version 2.0.
-
-Syntax
-------
-
-Place a marker in the document where you would like the table of contents to
-appear. Then, a nested list of all the headers in the document will replace the
-marker. The marker defaults to ``[TOC]`` so the following document:
-
- [TOC]
-
- # Header 1
-
- ## Header 2
-
-would generate the following output:
-
- <div class="toc">
- <ul>
- <li><a href="#header-1">Header 1</a></li>
- <ul>
- <li><a href="#header-2">Header 2</a></li>
- </ul>
- </ul>
- </div>
- <h1 id="header-1">Header 1</h1>
- <h1 id="header-2">Header 2</h1>
-
-Configuration Options
----------------------
-
-The following options are provided to configure the output:
-
-* **marker**: Text to find and replace with the Table of Contents. Defaults
- to ``[TOC]``.
-* **slugify**: Callable to generate anchors based on header text. Defaults to a
- built in ``slugify`` method. The callable must accept one argument which
- contains the text content of the header and return a string which will be
- used as the anchor text.
-* **title**: Title to insert in TOC ``<div>``. Defaults to ``None``.
-* **anchorlink**: Set to ``True`` to have the headers link to themselves.
- Default is ``False``.
diff --git a/docs/extensions/WikiLinks.txt b/docs/extensions/WikiLinks.txt
deleted file mode 100644
index 8bbead5..0000000
--- a/docs/extensions/WikiLinks.txt
+++ /dev/null
@@ -1,144 +0,0 @@
-WikiLinks
-=========
-
-Summary
--------
-
-An extension to Python-Markdown that adds [WikiLinks][]. Specifically, any
-``[[bracketed]]`` word is converted to a link.
-
-[WikiLinks]: http://en.wikipedia.org/wiki/Wikilink
-
-This extension has been included in the Markdown library since 2.0.
-
-Syntax
-------
-
-A ``[[bracketed]]`` word is any combination of upper or lower case letters,
-number, dashes, underscores and spaces surrounded by double brackets. Therefore
-
- [[Bracketed]]
-
-Would produce the following html:
-
- <a href="/Bracketed/" class="wikilink">Bracketed</a>
-
-Note that wikilinks are automatically assigned `class="wikilink"` making it
-easy to style wikilinks differently from other links on a page if one so
-desires. See below for ways to alter the class.
-
-You should also note that when a space is used, the space is converted to an
-underscore in the link but left as-is in the label. Perhaps an example
-would illustrate this best:
-
- [[Wiki Link]]
-
-Becomes
-
- <a href="/Wiki_Link/" class="wikilink">Wiki Link</a>
-
-Usage
------
-
-From the Python interpreter:
-
- >>> text = "Some text with a [[WikiLink]]."
- >>> html = markdown.markdown(text, ['wikilink'])
-
-The default behavior is to point each link to the document root of the current
-domain and close with a trailing slash. Additionally, each link is assigned to
-the html class `wikilink`. This may not always be desirable. Therefore, one can
-customize that behavior within Python code. Three settings are provided to
-change the default behavior:
-
-1. **base_url**: String to append to beginning of URL.
-
- Default: `'/'`
-
-2. **end_url**: String to append to end of URL.
-
- Default: `'/'`
-
-3. **html_class**: CSS hook. Leave blank for none.
-
- Default: `'wikilink'`
-
-4. **build_url**: Callable which formats the URL from it's parts.
-
-For an example, let us suppose links should always point to the subdirectory
-`/wiki/` and end with `.html`
-
- >>> html = markdown.markdown(text,
- ... ['wikilink(base_url=/wiki/,end_url=.html)']
- ... )
-
-The above would result in the following link for `[[WikiLink]]`.
-
- <a href="/wiki/WikiLink.html" class="wikilink">WikiLink</a>
-
-If you want to do more that just alter the base and/or end of the URL, you
-could also pass in a callable which must accept three arguments (``label``,
-``base``, and ``end``). The callable must return the URL in it's entirety.
-
- def my_url_builder(label, base, end):
- # do stuff
- return url
-
- md = markdown.Markdown(
- extensions=['wikilinks],
- extension_configs={'wikilinks' : [('build_url', my_url_builder)]}
- )
-
-
-The option is also provided to change or remove the class attribute.
-
- >>> html = markdown.markdown(text,
- ... ['wikilink(base_url=myclass)']
- ... )
-
-Would cause all wikilinks to be assigned to the class `myclass`.
-
- <a href="/WikiLink/" class="myclass">WikiLink</a>
-
-The same options can be used on the command line as well:
-
- python markdown.py -x wikilink(base_url=http://example.com/,end_url=.html,html_class=foo) src.txt
-
-Some may prefer the more complex format when calling the `Markdown` class directly:
-
- >>> md = markdown.Markdown(
- ... extensions = ['wikilink'],
- ... extension_configs = {'wikilink': [
- ... ('base_url', 'http://example.com/'),
- ... ('end_url', '.html'),
- ... ('html_class', '') ]},
- ... safe_mode = True
- ... )
- >>> html = md.convert(text)
-
-Using with Meta-Data
---------------------
-
-The WikiLink Extension also supports the [[Meta-Data]] Extension. Please see
-the documentation for that extension for specifics. The supported meta-data
-keywords are:
-
-* `wiki_base_url`
-* `wiki_end_url`
-* `wiki_html_class`
-
-When used, the meta-data will override the settings provided through the
-`extension_configs` interface.
-
-This document:
-
- wiki_base_url: http://example.com/
- wiki_end_url: .html
- wiki_html_class:
-
- A [[WikiLink]] in the first paragraph.
-
-would result in the following output (notice the blank `wiki_html_class`):
-
- <p>A <a href="http://example.com/WikiLink.html">WikiLink</a> in the first paragraph.</p>
-
diff --git a/docs/extensions/abbreviations.md b/docs/extensions/abbreviations.md
new file mode 100644
index 0000000..d03651f
--- /dev/null
+++ b/docs/extensions/abbreviations.md
@@ -0,0 +1,51 @@
+title: Abbreviations Extension
+
+Abbreviations
+=============
+
+Summary
+-------
+
+The Abbreviations extension adds the ability to define abbreviations.
+Specifically, any defined abbreviation is wrapped in an `<abbr>` tag.
+
+The Abbreviations extension is included in the standard Markdown library.
+
+Syntax
+------
+
+Abbreviations are defined using the syntax established in
+[PHP Markdown Extra][php].
+
+[php]: http://www.michelf.com/projects/php-markdown/extra/#abbr
+
+Thus, the following text (taken from the above referenced PHP documentation):
+
+```md
+The HTML specification
+is maintained by the W3C.
+
+*[HTML]: Hyper Text Markup Language
+*[W3C]: World Wide Web Consortium
+```
+
+will be rendered as:
+
+```html
+<p>The <abbr title="Hyper Text Markup Language">HTML</abbr> specification
+is maintained by the <abbr title="World Wide Web Consortium">W3C</abbr>.</p>
+```
+
+Usage
+-----
+
+See [Extensions](index.md) for general extension usage. Use `abbr` as the name
+of the extension.
+
+This extension does not accept any special configuration options.
+
+A trivial example:
+
+```python
+markdown.markdown(some_text, extensions=['abbr'])
+```
diff --git a/docs/extensions/admonition.md b/docs/extensions/admonition.md
new file mode 100644
index 0000000..4f79d48
--- /dev/null
+++ b/docs/extensions/admonition.md
@@ -0,0 +1,115 @@
+title: Admonition Extension
+
+Admonition
+==========
+
+Summary
+-------
+
+The Admonition extension adds [rST-style][rST] admonitions to Markdown documents.
+
+This extension is included in the standard Markdown library.
+
+[rST]: http://docutils.sourceforge.net/docs/ref/rst/directives.html#specific-admonitions
+
+Syntax
+------
+
+Admonitions are created using the following syntax:
+
+```md
+!!! type "optional explicit title within double quotes"
+ Any number of other indented markdown elements.
+
+ This is the second paragraph.
+```
+
+`type` will be used as the CSS class name and as default title. It must be a
+single word. So, for instance:
+
+```md
+!!! note
+ You should note that the title will be automatically capitalized.
+```
+
+will render:
+
+```html
+<div class="admonition note">
+<p class="admonition-title">Note</p>
+<p>You should note that the title will be automatically capitalized.</p>
+</div>
+```
+
+Optionally, you can use custom titles. For instance:
+
+```md
+!!! danger "Don't try this at home"
+ ...
+```
+
+will render:
+
+```html
+<div class="admonition danger">
+<p class="admonition-title">Don't try this at home</p>
+<p>...</p>
+</div>
+```
+
+If you don't want a title, use a blank string `""`:
+
+```md
+!!! important ""
+ This is an admonition box without a title.
+```
+
+results in:
+
+```html
+<div class="admonition important">
+<p>This is an admonition box without a title.</p>
+</div>
+```
+
+You can also provide additional CSS class names separated by spaces. The first
+class should be the "type." For example:
+
+```md
+!!! danger highlight blink "Don't try this at home"
+ ...
+```
+
+will render:
+
+```html
+<div class="admonition danger highlight blink">
+<p class="admonition-title">Don't try this at home</p>
+<p>...</p>
+</div>
+```
+
+rST suggests the following "types": `attention`, `caution`, `danger`, `error`,
+`hint`, `important`, `note`, `tip`, and `warning`; however, you're free to use
+whatever you want.
+
+Styling
+-------
+
+There is no CSS included as part of this extension. Check out the default
+[Sphinx][sphinx] theme for inspiration.
+
+[sphinx]: https://www.sphinx-doc.org/en/master/
+
+## Usage
+
+See [Extensions](index.md) for general extension usage. Use `admonition` as the
+name of the extension.
+
+This extension does not accept any special configuration options.
+
+A trivial example:
+
+```python
+markdown.markdown(some_text, extensions=['admonition'])
+```
diff --git a/docs/extensions/api.md b/docs/extensions/api.md
new file mode 100644
index 0000000..d7eb689
--- /dev/null
+++ b/docs/extensions/api.md
@@ -0,0 +1,886 @@
+title: Extensions API
+
+# Writing Extensions for Python-Markdown
+
+Python-Markdown includes an API for extension writers to plug their own custom functionality and syntax into the
+parser. An extension will patch into one or more stages of the parser:
+
+* [*Preprocessors*](#preprocessors) alter the source before it is passed to the parser.
+* [*Block Processors*](#blockprocessors) work with blocks of text separated by blank lines.
+* [*Tree Processors*](#treeprocessors) modify the constructed ElementTree
+* [*Inline Processors*](#inlineprocessors) are common tree processors for inline elements, such as `*strong*`.
+* [*Postprocessors*](#postprocessors) munge of the output of the parser just before it is returned.
+
+The parser loads text, applies the preprocessors, creates and builds an [ElementTree][ElementTree] object from the
+block processors and inline processors, renders the ElementTree object as Unicode text, and then then applies the
+postprocessors.
+
+There are classes and helpers provided to ease writing your extension. Each part of the API is discussed in its
+respective section below. Additionally, you can walk through the [Tutorial on Writing Extensions][tutorial]; look at
+some of the [Available Extensions][] and their [source code][extension source]. As always, you may report bugs, ask
+for help, and discuss various other issues on the [bug tracker].
+
+## Phases of processing {: #stages }
+
+### Preprocessors {: #preprocessors }
+
+Preprocessors munge the source text before it is passed to the Markdown parser. This is an excellent place to clean up
+bad characters or to extract portions for later processing that the parser may otherwise choke on.
+
+Preprocessors inherit from `markdown.preprocessors.Preprocessor` and implement a `run` method, which takes a single
+parameter `lines`. This parameter is the entire source text stored as a list of Unicode strings, one per line. `run`
+should return its processed list of Unicode strings, one per line.
+
+#### Example
+
+This simple example removes any lines with 'NO RENDER' before processing:
+
+```python
+from markdown.preprocessors import Preprocessor
+import re
+
+class NoRender(Preprocessor):
+ """ Skip any line with words 'NO RENDER' in it. """
+ def run(self, lines):
+ new_lines = []
+ for line in lines:
+ m = re.search("NO RENDER", line)
+ if not m:
+ # any line without NO RENDER is passed through
+ new_lines.append(line)
+ return new_lines
+```
+
+#### Usages
+
+Some preprocessors in the Markdown source tree include:
+
+| Class | Kind | Description |
+| ------------------------------|-----------|------------------------------------------------- |
+| [`NormalizeWhiteSpace`][c1] | built-in | Normalizes whitespace by expanding tabs, fixing `\r` line endings, etc. |
+| [`HtmlBlockPreprocessor`][c2] | built-in | Removes html blocks from the text and stores them for later processing |
+| [`ReferencePreprocessor`][c3] | built-in | Removes reference definitions from text and stores for later processing |
+| [`MetaPreprocessor`][c4] | extension | Strips and records meta data at top of documents |
+| [`FootnotesPreprocessor`][c5] | extension | Removes footnote blocks from the text and stores them for later processing |
+
+[c1]: https://github.com/Python-Markdown/markdown/blob/master/markdown/preprocessors.py
+[c2]: https://github.com/Python-Markdown/markdown/blob/master/markdown/preprocessors.py
+[c3]: https://github.com/Python-Markdown/markdown/blob/master/markdown/preprocessors.py
+[c4]: https://github.com/Python-Markdown/markdown/blob/master/markdown/extensions/meta.py
+[c5]: https://github.com/Python-Markdown/markdown/blob/master/markdown/extensions/footnotes.py
+
+### Block Processors {: #blockprocessors }
+
+A block processor parses blocks of text and adds new elements to the `ElementTree`. Blocks of text, separated from
+other text by blank lines, may have a different syntax and produce a differently structured tree than other Markdown.
+Block processors excel at code formatting, equation layouts, and tables.
+
+Block processors inherit from `markdown.blockprocessors.BlockProcessor`, are passed `md.parser` on initialization, and
+implement both the `test` and `run` methods:
+
+* `test(self, parent, block)` takes two parameters: `parent` is the parent `ElementTree` element and `block` is a
+ single, multi-line, Unicode string of the current block. `test`, often a regular expression match, returns a true
+ value if the block processor's `run` method should be called to process starting at that block.
+* `run(self, parent, blocks)` has the same `parent` parameter as `test`; and `blocks` is the list of all remaining
+ blocks in the document, starting with the `block` passed to `test`. `run` may return `False` (not `None`) to signal
+ failure, meaning that it did not process the blocks after all. On success, `run` is expected to `pop` one or more
+ blocks from the front of `blocks` and attach new nodes to `parent`.
+
+Crafting block processors is more involved and flexible than the other processors, involving controlling recursive
+parsing of the block's contents and managing state across invocations. For example, a blank line is allowed in
+indented code, so the second invocation of the inline code processor appends to the element tree generated by the
+previous call. Other block processors may insert new text into the `blocks` list, signal to future calls of itself,
+and more.
+
+To make writing these complex beasts more tractable, three convenience functions have been provided by the
+`BlockProcessor` parent class:
+
+* `lastChild(parent)` returns the last child of the given element or `None` if it has no children.
+* `detab(text)` removes one level of indent (four spaces by default) from the front of each line of the given
+ multi-line, text string, until a non-blank line is indented less.
+* `looseDetab(text, level)` removes multiple levels
+ of indent from the front of each line of `text` but does not affect lines indented less.
+
+Also, `BlockProcessor` provides the fields `self.tab_length`, the tab length (default 4), and `self.parser`, the
+current `BlockParser` instance.
+
+#### BlockParser
+
+`BlockParser`, not to be confused with `BlockProcessor`, is the class used by Markdown to cycle through all the
+registered block processors. You should never need to create your own instance; use `self.parser` instead.
+
+The `BlockParser` instance provides a stack of strings for its current state, which your processor can push with
+`self.parser.set(state)`, pop with `self.parser.reset()`, or check the the top state with
+`self.parser.isstate(state)`. Be sure your code pops the states it pushes.
+
+The `BlockParser` instance can also be called recursively, that is, to process blocks from within your block
+processor. There are three methods:
+
+* `parseDocument(lines)` parses a list of lines, each a single-line Unicode string, returning a complete
+ `ElementTree`.
+* `parseChunk(parent, text)` parses a single, multi-line, possibly multi-block, Unicode string `text` and attaches the
+ resulting tree to `parent`.
+* `parseBlocks(parent, blocks)` takes a list of `blocks`, each a multi-line Unicode string without blank lines, and
+ attaches the resulting tree to `parent`.
+
+For perspective, Markdown calls `parseDocument` which calls `parseChunk` which calls `parseBlocks` which calls your
+block processor, which, in turn, might call one of these routines.
+
+#### Example
+
+This example calls out important paragraphs by giving them a border. It looks for a fence line of exclamation points
+before and after and renders the fenced blocks into a new, styled `div`. If it does not find the ending fence line,
+it does nothing.
+
+Our code, like most block processors, is longer than other examples:
+
+```python
+def test_block_processor():
+ class BoxBlockProcessor(BlockProcessor):
+ RE_FENCE_START = r'^ *!{3,} *\n' # start line, e.g., ` !!!! `
+ RE_FENCE_END = r'\n *!{3,}\s*$' # last non-blank line, e.g, '!!!\n \n\n'
+
+ def test(self, parent, block):
+ return re.match(self.RE_FENCE_START, block)
+
+ def run(self, parent, blocks):
+ original_block = blocks[0]
+ blocks[0] = re.sub(self.RE_FENCE_START, '', blocks[0])
+
+ # Find block with ending fence
+ for block_num, block in enumerate(blocks):
+ if re.search(self.RE_FENCE_END, block):
+ # remove fence
+ blocks[block_num] = re.sub(self.RE_FENCE_END, '', block)
+ # render fenced area inside a new div
+ e = etree.SubElement(parent, 'div')
+ e.set('style', 'display: inline-block; border: 1px solid red;')
+ self.parser.parseBlocks(e, blocks[0:block_num + 1])
+ # remove used blocks
+ for i in range(0, block_num + 1):
+ blocks.pop(0)
+ return True # or could have had no return statement
+ # No closing marker! Restore and do nothing
+ blocks[0] = original_block
+ return False # equivalent to our test() routine returning False
+
+ class BoxExtension(Extension):
+ def extendMarkdown(self, md):
+ md.parser.blockprocessors.register(BoxBlockProcessor(md.parser), 'box', 175)
+```
+
+Start with this example input:
+
+``` text
+A regular paragraph of text.
+
+!!!!!
+First paragraph of wrapped text.
+
+Second Paragraph of **wrapped** text.
+!!!!!
+
+Another regular paragraph of text.
+```
+
+The fenced text adds one node with two children to the tree:
+
+* `div`, with a `style` attribute. It renders as
+ `<div style="display: inline-block; border: 1px solid red;">...</div>`
+ * `p` with text `First paragraph of wrapped text.`
+ * `p` with text `Second Paragraph of **wrapped** text`. The conversion to a `<strong>` tag will happen when
+ running the inline processors, which will happen after all of the block processors have completed.
+
+The example output might display as follows:
+
+!!! note ""
+ <p>A regular paragraph of text.</p>
+ <div style="display: inline-block; border: 1px solid red;">
+ <p>First paragraph of wrapped text.</p>
+ <p>Second Paragraph of **wrapped** text.</p>
+ </div>
+ <p>Another regular paragraph of text.</p>
+
+#### Usages
+
+Some block processors in the Markdown source tree include:
+
+| Class | Kind | Description |
+| ----------------------------|-----------|---------------------------------------------|
+| [`HashHeaderProcessor`][b1] | built-in | Title hashes (`#`), which may split blocks |
+| [`HRProcessor`][b2] | built-in | Horizontal lines, e.g., `---` |
+| [`OListProcessor`][b3] | built-in | Ordered lists; complex and using `state` |
+| [`Admonition`][b4] | extension | Render each [Admonition][] in a new `div` |
+
+[b1]: https://github.com/Python-Markdown/markdown/blob/master/markdown/blockprocessors.py
+[b2]: https://github.com/Python-Markdown/markdown/blob/master/markdown/blockprocessors.py
+[b3]: https://github.com/Python-Markdown/markdown/blob/master/markdown/blockprocessors.py
+[Admonition]: https://python-markdown.github.io/extensions/admonition/
+[b4]: https://github.com/Python-Markdown/markdown/blob/master/markdown/extensions/admonition.py
+
+### Tree processors {: #treeprocessors }
+
+Tree processors manipulate the tree created by block processors. They can even create an entirely new ElementTree
+object. This is an excellent place for creating summaries, adding collected references, or last minute adjustments.
+
+A tree processor must inherit from `markdown.treeprocessors.Treeprocessor` (note the capitalization). A tree processor
+must implement a `run` method which takes a single argument `root`. In most cases `root` would be an
+`xml.etree.ElementTree.Element` instance; however, in rare cases it could be some other type of ElementTree object.
+The `run` method may return `None`, in which case the (possibly modified) original `root` object is used, or it may
+return an entirely new `Element` object, which will replace the existing `root` object and all of its children. It is
+generally preferred to modify `root` in place and return `None`, which avoids creating multiple copies of the entire
+document tree in memory.
+
+For specifics on manipulating the ElementTree, see [Working with the ElementTree][workingwithetree] below.
+
+#### Example
+
+A pseudo example:
+
+```python
+from markdown.treeprocessors import Treeprocessor
+
+class MyTreeprocessor(Treeprocessor):
+ def run(self, root):
+ root.text = 'modified content'
+ # No return statement is same as `return None`
+```
+
+#### Usages
+
+The core `InlineProcessor` class is a tree processor. It walks the tree, matches patterns, and splits and creates
+nodes on matches.
+
+Additional tree processors in the Markdown source tree include:
+
+| Class | Kind | Description |
+| ----------------------------------|-----------|---------------------------------------------------------------|
+| [`PrettifyTreeprocessor`][e1] | built-in | Add line breaks to the html document |
+| [`TocTreeprocessor`][e2] | extension | Builds a [table of contents][] from the finished tree |
+| [`FootnoteTreeprocessor`][e3] | extension | Create [footnote][] div at end of document |
+| [`FootnotePostTreeprocessor`][e4] | extension | Amend div created by `FootnoteTreeprocessor` with duplicates |
+
+[e1]: https://github.com/Python-Markdown/markdown/blob/master/markdown/treeprocessors.py
+[e2]: https://github.com/Python-Markdown/markdown/blob/master/markdown/extensions/toc.py
+[e3]: https://github.com/Python-Markdown/markdown/blob/master/markdown/extensions/footnotes.py
+[e4]: https://github.com/Python-Markdown/markdown/blob/master/markdown/extensions/footnotes.py
+[table of contents]: https://python-markdown.github.io/extensions/toc/
+[footnote]: https://python-markdown.github.io/extensions/footnotes/
+
+### Inline Processors {: #inlineprocessors }
+
+Inline processors, previously called inline patterns, are used to add formatting, such as `**emphasis**`, by replacing
+a matched pattern with a new element tree node. It is an excellent for adding new syntax for inline tags. Inline
+processor code is often quite short.
+
+Inline processors inherit from `InlineProcessor`, are initialized, and implement `handleMatch`:
+
+* `__init__(self, pattern, md=None)` is the inherited constructor. You do not need to implement your own.
+ * `pattern` is the regular expression string that must match the code block in order for the `handleMatch` method
+ to be called.
+ * `md`, an optional parameter, is a pointer to the instance of `markdown.Markdown` and is available as `self.md`
+ on the `InlineProcessor` instance.
+
+* `handleMatch(self, m, data)` must be implemented in all `InlineProcessor` subclasses.
+ * `m` is the regular expression [match object][] found by the `pattern` passed to `__init__`.
+ * `data` is a single, multi-line, Unicode string containing the entire block of text around the pattern. A block
+ is text set apart by blank lines.
+ * Returns either `(None, None, None)`, indicating the provided match was rejected or `(el, start, end)`, if the
+ match was successfully processed. On success, `el` is the element being added the tree, `start` and `end` are
+ indexes in `data` that were "consumed" by the pattern. The "consumed" span will be replaced by a placeholder.
+ The same inline processor may be called several times on the same block.
+
+Inline Processors can define the property `ANCESTOR_EXCLUDES` which is either a list or tuple of undesirable ancestors.
+The processor will be skipped if it would cause the content to be a descendant of one of the listed tag names.
+
+##### Convenience Classes
+
+Convenience subclasses of `InlineProcessor` are provide for common operations:
+
+* [`SimpleTextInlineProcessor`][i1] returns the text of `group(1)` of the match.
+* [`SubstituteTagInlineProcessor`][i4] is initialized as `SubstituteTagInlineProcessor(pattern, tag)`. It returns a
+ new element `tag` whenever `pattern` is matched.
+* [`SimpleTagInlineProcessor`][i3] is initialized as `SimpleTagInlineProcessor(pattern, tag)`. It returns an element
+ `tag` with a text field of `group(2)` of the match.
+
+##### Example
+
+This example changes `--strike--` to `<del>strike</del>`.
+
+```python
+from markdown.inlinepatterns import InlineProcessor
+from markdown.extensions import Extension
+import xml.etree.ElementTree as etree
+
+
+class DelInlineProcessor(InlineProcessor):
+ def handleMatch(self, m, data):
+ el = etree.Element('del')
+ el.text = m.group(1)
+ return el, m.start(0), m.end(0)
+
+class DelExtension(Extension):
+ def extendMarkdown(self, md):
+ DEL_PATTERN = r'--(.*?)--' # like --del--
+ md.inlinePatterns.register(DelInlineProcessor(DEL_PATTERN, md), 'del', 175)
+```
+
+Use this input example:
+
+``` text
+First line of the block.
+This is --strike one--.
+This is --strike two--.
+End of the block.
+```
+
+The example output might display as follows:
+
+!!! note ""
+ <p>First line of the block.
+ This is <del>strike one</del>.
+ This is <del>strike two</del>.
+ End of the block.</p>
+
+* On the first call to `handleMatch`
+ * `m` will be the match for `--strike one--`
+ * `data` will be the string:
+ `First line of the block.\nThis is --strike one--.\nThis is --strike two--.\nEnd of the block.`
+
+ Because the match was successful, the region between the returned `start` and `end` are replaced with a
+ placeholder token and the new element is added to the tree.
+
+* On the second call to `handleMatch`
+ * `m` will be the match for `--strike two--`
+ * `data` will be the string
+ `First line of the block.\nThis is klzzwxh:0000.\nThis is --strike two--.\nEnd of the block.`
+
+Note the placeholder token `klzzwxh:0000`. This allows the regular expression to be run against the entire block,
+not just the the text contained in an individual element. The placeholders will later be swapped back out for the
+actual elements by the parser.
+
+Actually it would not be necessary to create the above inline processor. The fact is, that example is not very DRY
+(Don't Repeat Yourself). A pattern for `**strong**` text would be almost identical, with the exception that it would
+create a `strong` element. Therefore, Markdown provides a number of generic `InlineProcessor` subclasses that can
+provide some common functionality. For example, strike could be implemented with an instance of the
+`SimpleTagInlineProcessor` class as demonstrated below. Feel free to use or extend any of the `InlineProcessor`
+subclasses found at `markdown.inlinepatterns`.
+
+```python
+from markdown.inlinepatterns import SimpleTagInlineProcessor
+from markdown.extensions import Extension
+
+class DelExtension(Extension):
+ def extendMarkdown(self, md):
+ md.inlinePatterns.register(SimpleTagInlineProcessor(r'()--(.*?)--', 'del'), 'del', 175)
+```
+
+
+##### Usages
+
+Here are some convenience functions and other examples:
+
+| Class | Kind | Description |
+| ---------------------------------|-----------|---------------------------------------------------------------|
+| [`AsteriskProcessor`][i5] | built-in | Emphasis processor for handling strong and em matches inside asterisks |
+| [`AbbrInlineProcessor`][i6] | extension | Apply tag to abbreviation registered by preprocessor |
+| [`WikiLinksInlineProcessor`][i7] | extension | Link `[[article names]]` to wiki given in metadata |
+| [`FootnoteInlineProcessor`][i8] | extension | Replaces footnote in text with link to footnote div at bottom |
+
+[i1]: https://github.com/Python-Markdown/markdown/blob/master/markdown/inlinepatterns.py
+[i2]: https://github.com/Python-Markdown/markdown/blob/master/markdown/inlinepatterns.py
+[i3]: https://github.com/Python-Markdown/markdown/blob/master/markdown/inlinepatterns.py
+[i4]: https://github.com/Python-Markdown/markdown/blob/master/markdown/inlinepatterns.py
+[i5]: https://github.com/Python-Markdown/markdown/blob/master/markdown/inlinepatterns.py
+[i6]: https://github.com/Python-Markdown/markdown/blob/master/markdown/extensions/abbr.py
+[i7]: https://github.com/Python-Markdown/markdown/blob/master/markdown/extensions/wikilinks.py
+[i8]: https://github.com/Python-Markdown/markdown/blob/master/markdown/extensions/footnotes.py
+
+### Patterns
+
+In version 3.0, a new, more flexible inline processor was added, `markdown.inlinepatterns.InlineProcessor`. The
+original inline patterns, which inherit from `markdown.inlinepatterns.Pattern` or one of its children are still
+supported, though users are encouraged to migrate.
+
+#### Comparison with new `InlineProcessor`
+
+The new `InlineProcessor` provides two major enhancements to `Patterns`:
+
+1. Inline Processors no longer need to match the entire block, so regular expressions no longer need to start with
+ `r'^(.*?)'` and end with `r'(.*?)%'`. This runs faster. The returned [match object][] will only contain what is
+ explicitly matched in the pattern, and extension pattern groups now start with `m.group(1)`.
+
+2. The `handleMatch` method now takes an additional input called `data`, which is the entire block under analysis,
+ not just what is matched with the specified pattern. The method now returns the element *and* the indexes relative
+ to `data` that the return element is replacing (usually `m.start(0)` and `m.end(0)`). If the boundaries are
+ returned as `None`, it is assumed that the match did not take place, and nothing will be altered in `data`.
+
+ This allows handling of more complex constructs than regular expressions can handle, e.g., matching nested
+ brackets, and explicit control of the span "consumed" by the processor.
+
+#### Inline Patterns
+
+Inline Patterns can implement inline HTML element syntax for Markdown such as `*emphasis*` or
+`[links](http://example.com)`. Pattern objects should be instances of classes that inherit from
+`markdown.inlinepatterns.Pattern` or one of its children. Each pattern object uses a single regular expression and
+must have the following methods:
+
+* **`getCompiledRegExp()`**:
+
+ Returns a compiled regular expression.
+
+* **`handleMatch(m)`**:
+
+ Accepts a match object and returns an ElementTree element of a plain Unicode string.
+
+Inline Patterns can define the property `ANCESTOR_EXCLUDES` with is either a list or tuple of undesirable ancestors.
+The pattern will be skipped if it would cause the content to be a descendant of one of the listed tag names.
+
+Note that any regular expression returned by `getCompiledRegExp` must capture the whole block. Therefore, they should
+all start with `r'^(.*?)'` and end with `r'(.*?)!'`. When using the default `getCompiledRegExp()` method provided in
+the `Pattern` you can pass in a regular expression without that and `getCompiledRegExp` will wrap your expression for
+you and set the `re.DOTALL` and `re.UNICODE` flags. This means that the first group of your match will be `m.group(2)`
+as `m.group(1)` will match everything before the pattern.
+
+For an example, consider this simplified emphasis pattern:
+
+```python
+from markdown.inlinepatterns import Pattern
+import xml.etree.ElementTree as etree
+
+class EmphasisPattern(Pattern):
+ def handleMatch(self, m):
+ el = etree.Element('em')
+ el.text = m.group(2)
+ return el
+```
+
+As discussed in [Integrating Your Code Into Markdown][], an instance of this class will need to be provided to
+Markdown. That instance would be created like so:
+
+```python
+# an oversimplified regex
+MYPATTERN = r'\*([^*]+)\*'
+# pass in pattern and create instance
+emphasis = EmphasisPattern(MYPATTERN)
+```
+
+### Postprocessors {: #postprocessors }
+
+Postprocessors munge the document after the ElementTree has been serialized into a string. Postprocessors should be
+used to work with the text just before output. Usually, they are used add back sections that were extracted in a
+preprocessor, fix up outgoing encodings, or wrap the whole document.
+
+Postprocessors inherit from `markdown.postprocessors.Postprocessor` and implement a `run` method which takes a single
+parameter `text`, the entire HTML document as a single Unicode string. `run` should return a single Unicode string
+ready for output. Note that preprocessors use a list of lines while postprocessors use a single multi-line string.
+
+#### Example
+
+Here is a simple example that changes the output to one big page showing the raw html.
+
+```python
+from markdown.postprocessors import Postprocessor
+import re
+
+class ShowActualHtmlPostprocesor(Postprocessor):
+ """ Wrap entire output in <pre> tags as a diagnostic. """
+ def run(self, text):
+ return '<pre>\n' + re.sub('<', '&lt;', text) + '</pre>\n'
+```
+
+#### Usages
+
+Some postprocessors in the Markdown source tree include:
+
+| Class | Kind | Description |
+| ------------------------------|-----------|----------------------------------------------------|
+| [`raw_html`][p1] | built-in | Restore raw html from `htmlStash`, stored by `HTMLBlockPreprocessor`, and code highlighters |
+| [`amp_substitute`][p2] | built-in | Convert ampersand substitutes to `&`; used in links |
+| [`unescape`][p3] | built-in | Convert some escaped characters back from integers; used in links |
+| [`FootnotePostProcessor`][p4] | extension | Replace footnote placeholders with html entities; as set by other stages |
+
+ [p1]: https://github.com/Python-Markdown/markdown/blob/master/markdown/postprocessors.py
+ [p2]: https://github.com/Python-Markdown/markdown/blob/master/markdown/postprocessors.py
+ [p3]: https://github.com/Python-Markdown/markdown/blob/master/markdown/postprocessors.py
+ [p4]: https://github.com/Python-Markdown/markdown/blob/master/markdown/extensions/footnotes.py
+
+
+## Working with the ElementTree {: #working_with_et }
+
+As mentioned, the Markdown parser converts a source document to an [ElementTree][ElementTree] object before
+serializing that back to Unicode text. Markdown has provided some helpers to ease that manipulation within the context
+of the Markdown module.
+
+First, import the ElementTree module:
+
+```python
+import xml.etree.ElementTree as etree
+```
+Sometimes you may want text inserted into an element to be parsed by [Inline Patterns][]. In such a situation, simply
+insert the text as you normally would and the text will be automatically run through the Inline Patterns. However, if
+you do *not* want some text to be parsed by Inline Patterns, then insert the text as an `AtomicString`.
+
+```python
+from markdown.util import AtomicString
+some_element.text = AtomicString(some_text)
+```
+
+Here's a basic example which creates an HTML table (note that the contents of the second cell (`td2`) will be run
+through Inline Patterns latter):
+
+```python
+table = etree.Element("table")
+table.set("cellpadding", "2") # Set cellpadding to 2
+tr = etree.SubElement(table, "tr") # Add child tr to table
+td1 = etree.SubElement(tr, "td") # Add child td1 to tr
+td1.text = markdown.util.AtomicString("Cell content") # Add plain text content
+td2 = etree.SubElement(tr, "td") # Add second td to tr
+td2.text = "*text* with **inline** formatting." # Add markup text
+table.tail = "Text after table" # Add text after table
+```
+
+You can also manipulate an existing tree. Consider the following example which adds a `class` attribute to `<a>`
+elements:
+
+```python
+def set_link_class(self, element):
+ for child in element:
+ if child.tag == "a":
+ child.set("class", "myclass") #set the class attribute
+ set_link_class(child) # run recursively on children
+```
+
+For more information about working with ElementTree see the [ElementTree
+Documentation][ElementTree].
+
+## Working with Raw HTML {: #working_with_raw_html }
+
+Occasionally an extension may need to call out to a third party library which returns a pre-made string
+of raw HTML that needs to be inserted into the document unmodified. Raw strings can be stashed for later
+retrieval using an `htmlStash` instance, rather than converting them into `ElementTree` objects. A raw string
+(which may or may not be raw HTML) passed to `self.md.htmlStash.store()` will be saved to the stash and a
+placeholder string will be returned which should be inserted into the tree instead. After the tree is
+serialized, a postprocessor will replace the placeholder with the raw string. This prevents subsequent
+processing steps from modifying the HTML data. For example,
+
+```python
+html = "<p>This is some <em>raw</em> HTML data</p>"
+el = etree.Element("div")
+el.text = self.md.htmlStash.store(html)
+```
+
+For the global `htmlStash` instance to be available from a processor, the `markdown.Markdown` instance must
+be passed to the processor from [extendMarkdown](#extendmarkdown) and will be available as `self.md.htmlStash`.
+
+## Integrating Your Code Into Markdown {: #integrating_into_markdown }
+
+Once you have the various pieces of your extension built, you need to tell Markdown about them and ensure that they
+are run in the proper sequence. Markdown accepts an `Extension` instance for each extension. Therefore, you will need
+to define a class that extends `markdown.extensions.Extension` and over-rides the `extendMarkdown` method. Within this
+class you will manage configuration options for your extension and attach the various processors and patterns to the
+Markdown instance.
+
+It is important to note that the order of the various processors and patterns matters. For example, if we replace
+`http://...` links with `<a>` elements, and *then* try to deal with inline HTML, we will end up with a mess.
+Therefore, the various types of processors and patterns are stored within an instance of the `markdown.Markdown` class
+in a [Registry][]. Your `Extension` class will need to manipulate those registries appropriately. You may `register`
+instances of your processors and patterns with an appropriate priority, `deregister` built-in instances, or replace a
+built-in instance with your own.
+
+### `extendMarkdown` {: #extendmarkdown }
+
+The `extendMarkdown` method of a `markdown.extensions.Extension` class accepts one argument:
+
+* **`md`**:
+
+ A pointer to the instance of the `markdown.Markdown` class. You should use this to access the
+ [Registries][Registry] of processors and patterns. They are found under the following attributes:
+
+ * `md.preprocessors`
+ * `md.inlinePatterns`
+ * `md.parser.blockprocessors`
+ * `md.treeprocessors`
+ * `md.postprocessors`
+
+ Some other things you may want to access on the `markdown.Markdown` instance are:
+
+ * `md.htmlStash`
+ * `md.output_formats`
+ * `md.set_output_format()`
+ * `md.output_format`
+ * `md.serializer`
+ * `md.registerExtension()`
+ * `md.tab_length`
+ * `md.block_level_elements`
+ * `md.isBlockLevel()`
+
+!!! Warning
+ With access to the above items, theoretically you have the option to change anything through various
+ [monkey_patching][] techniques. However, you should be aware that the various undocumented parts of Markdown may
+ change without notice and your monkey_patches may break with a new release. Therefore, what you really should be
+ doing is inserting processors and patterns into the Markdown pipeline. Consider yourself warned!
+
+[monkey_patching]: https://en.wikipedia.org/wiki/Monkey_patch
+
+A simple example:
+
+```python
+from markdown.extensions import Extension
+
+class MyExtension(Extension):
+ def extendMarkdown(self, md):
+ # Register instance of 'mypattern' with a priority of 175
+ md.inlinePatterns.register(MyPattern(md), 'mypattern', 175)
+```
+
+### registerExtension {: #registerextension }
+
+Some extensions may need to have their state reset between multiple runs of the `markdown.Markdown` class. For
+example, consider the following use of the [Footnotes][] extension:
+
+```python
+md = markdown.Markdown(extensions=['footnotes'])
+html1 = md.convert(text_with_footnote)
+md.reset()
+html2 = md.convert(text_without_footnote)
+```
+
+Without calling `reset`, the footnote definitions from the first document will be inserted into the second document as
+they are still stored within the class instance. Therefore the `Extension` class needs to define a `reset` method that
+will reset the state of the extension (i.e.: `self.footnotes = {}`). However, as many extensions do not have a need
+for `reset`, `reset` is only called on extensions that are registered.
+
+To register an extension, call `md.registerExtension` from within your `extendMarkdown` method:
+
+```python
+def extendMarkdown(self, md):
+ md.registerExtension(self)
+ # insert processors and patterns here
+```
+
+Then, each time `reset` is called on the `markdown.Markdown` instance, the `reset` method of each registered extension
+will be called as well. You should also note that `reset` will be called on each registered extension after it is
+initialized the first time. Keep that in mind when over-riding the extension's `reset` method.
+
+### Configuration Settings {: #configsettings }
+
+If an extension uses any parameters that the user may want to change, those parameters should be stored in
+`self.config` of your `markdown.extensions.Extension` class in the following format:
+
+```python
+class MyExtension(markdown.extensions.Extension):
+ def __init__(self, **kwargs):
+ self.config = {
+ 'option1' : ['value1', 'description1'],
+ 'option2' : ['value2', 'description2']
+ }
+ super(MyExtension, self).__init__(**kwargs)
+```
+
+When implemented this way the configuration parameters can be over-ridden at run time (thus the call to `super`). For
+example:
+
+```python
+markdown.Markdown(extensions=[MyExtension(option1='other value')])
+```
+
+Note that if a keyword is passed in that is not already defined in `self.config`, then a `KeyError` is raised.
+
+The `markdown.extensions.Extension` class and its subclasses have the following methods available to assist in working
+with configuration settings:
+
+* **`getConfig(key [, default])`**:
+
+ Returns the stored value for the given `key` or `default` if the `key` does not exist. If not set, `default`
+ returns an empty string.
+
+* **`getConfigs()`**:
+
+ Returns a dict of all key/value pairs.
+
+* **`getConfigInfo()`**:
+
+ Returns all configuration descriptions as a list of tuples.
+
+* **`setConfig(key, value)`**:
+
+ Sets a configuration setting for `key` with the given `value`. If `key` is unknown, a `KeyError` is raised. If the
+ previous value of `key` was a Boolean value, then `value` is converted to a Boolean value. If the previous value
+ of `key` is `None`, then `value` is converted to a Boolean value except when it is `None`. No conversion takes
+ place when the previous value of `key` is a string.
+
+* **`setConfigs(items)`**:
+
+ Sets multiple configuration settings given a dict of key/value pairs.
+
+### Naming an Extension { #naming_an_extension }
+
+As noted in the [library reference] an instance of an extension can be passed directly to `markdown.Markdown`. In
+fact, this is the preferred way to use third-party extensions.
+
+For example:
+
+```python
+import markdown
+from path.to.module import MyExtension
+md = markdown.Markdown(extensions=[MyExtension(option='value')])
+```
+
+However, Markdown also accepts "named" third party extensions for those occasions when it is impractical to import an
+extension directly (from the command line or from within templates). A "name" can either be a registered [entry
+point](#entry_point) or a string using Python's [dot notation](#dot_notation).
+
+#### Entry Point { #entry_point }
+
+[Entry points] are defined in a Python package's `setup.py` script. The script must use [setuptools] to support entry
+points. Python-Markdown extensions must be assigned to the `markdown.extensions` group. An entry point definition
+might look like this:
+
+```python
+from setuptools import setup
+
+setup(
+ # ...
+ entry_points={
+ 'markdown.extensions': ['myextension = path.to.module:MyExtension']
+ }
+)
+```
+
+After a user installs your extension using the above script, they could then call the extension using the
+`myextension` string name like this:
+
+```python
+markdown.markdown(text, extensions=['myextension'])
+```
+
+Note that if two or more entry points within the same group are assigned the same name, Python-Markdown will only ever
+use the first one found and ignore all others. Therefore, be sure to give your extension a unique name.
+
+For more information on writing `setup.py` scripts, see the Python documentation on [Packaging and Distributing
+Projects].
+
+#### Dot Notation { #dot_notation }
+
+If an extension does not have a registered entry point, Python's dot notation may be used instead. The extension must
+be installed as a Python module on your PYTHONPATH. Generally, a class should be specified in the name. The class must
+be at the end of the name and be separated by a colon from the module.
+
+Therefore, if you were to import the class like this:
+
+```python
+from path.to.module import MyExtension
+```
+
+Then the extension can be loaded as follows:
+
+```python
+markdown.markdown(text, extensions=['path.to.module:MyExtension'])
+```
+
+You do not need to do anything special to support this feature. As long as your extension class is able to be
+imported, a user can include it with the above syntax.
+
+The above two methods are especially useful if you need to implement a large number of extensions with more than one
+residing in a module. However, if you do not want to require that your users include the class name in their string,
+you must define only one extension per module and that module must contain a module-level function called
+`makeExtension` that accepts `**kwargs` and returns an extension instance.
+
+For example:
+
+```python
+class MyExtension(markdown.extensions.Extension)
+ # Define extension here...
+
+def makeExtension(**kwargs):
+ return MyExtension(**kwargs)
+```
+
+When `markdown.Markdown` is passed the "name" of your extension as a dot notation string that does not include a class
+(for example `path.to.module`), it will import the module and call the `makeExtension` function to initiate your
+extension.
+
+## Registries
+
+The `markdown.util.Registry` class is a priority sorted registry which Markdown uses internally to determine the
+processing order of its various processors and patterns.
+
+A `Registry` instance provides two public methods to alter the data of the registry: `register` and `deregister`. Use
+`register` to add items and `deregister` to remove items. See each method for specifics.
+
+When registering an item, a "name" and a "priority" must be provided. All items are automatically sorted by the value
+of the "priority" parameter such that the item with the highest value will be processed first. The "name" is used to
+remove (`deregister`) and get items.
+
+A `Registry` instance is like a list (which maintains order) when reading data. You may iterate over the items, get an
+item and get a count (length) of all items. You may also check that the registry contains an item.
+
+When getting an item you may use either the index of the item or the string-based "name". For example:
+
+```python
+registry = Registry()
+registry.register(SomeItem(), 'itemname', 20)
+# Get the item by index
+item = registry[0]
+# Get the item by name
+item = registry['itemname']
+```
+
+When checking that the registry contains an item, you may use either the string-based "name", or a reference to the
+actual item. For example:
+
+```python
+someitem = SomeItem()
+registry.register(someitem, 'itemname', 20)
+# Contains the name
+assert 'itemname' in registry
+# Contains the item instance
+assert someitem in registry
+```
+
+`markdown.util.Registry` has the following methods:
+
+### `Registry.register(self, item, name, priority)` {: #registry.register data-toc-label='Registry.register'}
+
+: Add an item to the registry with the given name and priority.
+
+ Parameters:
+
+ * `item`: The item being registered.
+ * `name`: A string used to reference the item.
+ * `priority`: An integer or float used to sort against all items.
+
+ If an item is registered with a "name" which already exists, the existing item is replaced with the new item.
+ Be careful as the old item is lost with no way to recover it. The new item will be sorted according to its
+ priority and will **not** retain the position of the old item.
+
+### `Registry.deregister(self, name, strict=True)` {: #registry.deregister data-toc-label='Registry.deregister'}
+
+: Remove an item from the registry.
+
+ Set `strict=False` to fail silently.
+
+### `Registry.get_index_for_name(self, name)` {: #registry.get_index_for_name data-toc-label='Registry.get_index_for_name'}
+
+: Return the index of the given `name`.
+
+[match object]: https://docs.python.org/3/library/re.html#match-objects
+[bug tracker]: https://github.com/Python-Markdown/markdown/issues
+[extension source]: https://github.com/Python-Markdown/markdown/tree/master/markdown/extensions
+[tutorial]: https://github.com/Python-Markdown/markdown/wiki/Tutorial-1---Writing-Extensions-for-Python-Markdown
+[workingwithetree]: #working_with_et
+[Integrating your code into Markdown]: #integrating_into_markdown
+[extendMarkdown]: #extendmarkdown
+[Registry]: #registry
+[registerExtension]: #registerextension
+[Config Settings]: #configsettings
+[makeExtension]: #makeextension
+[ElementTree]: https://docs.python.org/3/library/xml.etree.elementtree.html
+[Available Extensions]: index.md
+[Footnotes]: https://github.com/Python-Markdown/markdown/blob/master/markdown/extensions/footnotes.py
+[Definition Lists]: https://github.com/Python-Markdown/markdown/blob/master/markdown/extensions/definition_lists
+[library reference]: ../reference.md
+[setuptools]: https://packaging.python.org/key_projects/#setuptools
+[Entry points]: https://setuptools.readthedocs.io/en/latest/setuptools.html#dynamic-discovery-of-services-and-plugins
+[Packaging and Distributing Projects]: https://packaging.python.org/tutorials/distributing-packages/
diff --git a/docs/extensions/attr_list.md b/docs/extensions/attr_list.md
new file mode 100644
index 0000000..d3d5e12
--- /dev/null
+++ b/docs/extensions/attr_list.md
@@ -0,0 +1,202 @@
+title: Attribute Lists Extension
+
+# Attribute Lists
+
+## Summary
+
+The Attribute Lists extension adds a syntax to define attributes on the various
+HTML elements in markdown's output.
+
+This extension is included in the standard Markdown library.
+
+## Syntax
+
+The basic syntax was inspired by Maruku's Attribute Lists feature (see [web archive][Maruku]).
+
+[Maruku]: https://web.archive.org/web/20170324172643/http://maruku.rubyforge.org/proposal.html
+
+### The List
+
+An example attribute list might look like this:
+
+```text
+{: #someid .someclass somekey='some value' }
+```
+
+A word which starts with a hash (`#`) will set the id of an element.
+
+A word which starts with a dot (`.`) will be added to the list of classes
+assigned to an element.
+
+A key/value pair (`somekey='some value'`) will assign that pair to the element.
+
+Be aware that while the dot syntax will add to a class, using key/value pairs
+will always override the previously defined attribute. Consider the following:
+
+```text
+{: #id1 .class1 id=id2 class="class2 class3" .class4 }
+```
+
+The above example would result in the following attributes being defined:
+
+```text
+id="id2" class="class2 class3 class4"
+```
+
+HTML includes support for some attributes to be a single term, like `checked`, for example. Therefore, the attribute
+list `{: checked }` would result in `checked` if the [output format](../reference.md#output_format) is `html` or
+`checked="checked"` if the output format is `xhtml`.
+
+Curly braces can be backslash escaped to avoid being identified as an attribute list.
+
+```text
+\{ not an attribute list }
+```
+
+Opening and closing curly braces which are empty or only contain whitespace are ignored whether they are escaped or
+not. Additionally, any attribute lists which are not located in the specific locations documented below are ignored.
+
+The colon after the opening brace is optional, but is supported to maintain consistency with other implementations.
+Therefore, the following is also a valid attribute list:
+
+```text
+{ #someid .someclass somekey='some value' }
+```
+
+In addition, the spaces after the opening brace and before the closing brace are optional. They are recommended as
+they improve readability, but they are not required.
+
+The Attribute List extension does not have any knowledge of which keys and/or values are valid in HTML. Therefore, it
+is up to the document author to ensure that valid keys and values are used. However, the extension will escape any
+characters in the key which are not valid by replacing them with an underscore. Multiple consecutive invalid
+characters are reduced to a single underscore.
+
+### Block Level
+
+To define attributes for a block level element, the attribute list should
+be defined on the last line of the block by itself.
+
+```text
+This is a paragraph.
+{: #an_id .a_class }
+```
+
+The above results in the following output:
+
+```html
+<p id="an_id" class="a_class">This is a paragraph.</p>
+```
+
+An exception is headers, as they are only ever allowed on one line.
+
+```text
+A setext style header {: #setext}
+=================================
+
+### A hash style header ### {: #hash }
+```
+
+The above results in the following output:
+
+```html
+<h1 id="setext">A setext style header</h1>
+<h3 id="hash">A hash style header</h3>
+```
+
+!!! seealso "See Also"
+ By default, the [Fenced Code Blocks](./fenced_code_blocks.md#attributes) extension includes limited support for
+ attribute lists. To get [full support](./fenced_code_blocks.md#keyvalue-pairs), both extensions must be enabled.
+
+### Inline
+
+To define attributes on inline elements, the attribute list should be defined
+immediately after the inline element with no white space.
+
+```text
+[link](http://example.com){: class="foo bar" title="Some title!" }
+```
+
+The above results in the following output:
+
+```html
+<p><a href="http://example.com" class="foo bar" title="Some title!">link</a></p>
+```
+
+If the [tables](./tables.md) extension is enabled, attribute lists can be defined on table cells. To differentiate
+attributes for an inline element from attributes for the containing cell, the attribute list must be separated from
+the content by at least one space and be defined at the end of the cell content. As table cells can only ever be on
+a single line, the attribute list must remain on the same line as the content of the cell.
+
+```text
+| set on td | set on em |
+|--------------|-------------|
+| *a* { .foo } | *b*{ .foo } |
+```
+
+The above example results in the following output:
+
+```html
+<table>
+ <thead>
+ <tr>
+ <th>set on td</th>
+ <th>set on em</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td class="foo"><em>a</em></td>
+ <td><em class="foo">b</em></td>
+ </tr>
+ </tbody>
+</table>
+```
+
+Note that in the first column, the attribute list is preceded by a space; therefore, it is assigned to the table cell
+(`<td>` element). However, in the second column, the attribute list is not preceded by a space; therefore, it is
+assigned to the inline element (`<em>`) which immediately preceded it.
+
+Attribute lists may also be defined on table header cells (`<th>` elements) in the same manner.
+
+### Limitations
+
+There are a few types of elements which attribute lists do not work with. As a reminder, Markdown is a subset of HTML
+and anything which cannot be expressed in Markdown can always be expressed with raw HTML directly.
+
+__Code Blocks:__
+
+: Code blocks are unique in that they must be able to display Markdown syntax. Therefore, there is no way to
+ determine if an attribute list is intended to be part of the code block or intended to define attributes on the
+ wrapping element. For that reason, the extension ignores code blocks. To define attributes on code blocks, the
+ [codehilite] and [fenced code blocks] extensions provide some options.
+
+[codehilite]: code_hilite.md
+[fenced code blocks]: fenced_code_blocks.md
+
+__Nested Elements:__
+
+: Markdown provides mechanisms for nesting various block level elements within other elements. However, attribute
+ lists only ever get applied to the immediate parent. There is no way to specify that an attribute list should be
+ applied some number of levels up the document tree. For example, when including an attribute list within a
+ blockquote, the attribute list is only ever applied to the paragraph the list is defined in. There is no way to
+ define attributes on the `blockquote` element itself.
+
+__Implied Elements:__
+
+: There are various HTML elements which are not represented in Markdown text, but only implied. For example, the
+ `ul` and `ol` elements do not exist in Markdown. They are only implied by the presence of list items (`li`). There
+ is no way to use an attribute list to define attributes on implied elements, including but not limited to the
+ following: `ul`, `ol`, `dl`, `table`, `thead`, `tbody`, and `tr`.
+
+## Usage
+
+See [Extensions](index.md) for general extension usage. Use `attr_list` as the
+name of the extension.
+
+This extension does not accept any special configuration options.
+
+A trivial example:
+
+```python
+markdown.markdown(some_text, extensions=['attr_list'])
+```
diff --git a/docs/extensions/code_hilite.md b/docs/extensions/code_hilite.md
new file mode 100644
index 0000000..19b9d52
--- /dev/null
+++ b/docs/extensions/code_hilite.md
@@ -0,0 +1,308 @@
+title: CodeHilite Extension
+
+# CodeHilite
+
+## Summary
+
+The CodeHilite extension adds code/syntax highlighting to standard
+Python-Markdown code blocks using [Pygments][].
+
+[Pygments]: http://pygments.org/
+
+This extension is included in the standard Markdown library.
+
+## Setup
+
+### Step 1: Download and Install Pygments
+
+You will also need to [download][dl] and install the Pygments package on your
+`PYTHONPATH`. The CodeHilite extension will produce HTML output without
+Pygments, but it won't highlight anything (same behavior as setting
+`use_pygments` to `False`).
+
+[dl]: http://pygments.org/download/
+
+### Step 2: Add CSS Classes
+
+You will need to define the appropriate CSS classes with appropriate rules.
+The CSS rules either need to be defined in or linked from the header of your
+HTML templates. Pygments can generate CSS rules for you. Just run the following
+command from the command line:
+
+```bash
+pygmentize -S default -f html -a .codehilite > styles.css
+```
+
+If you are using a different `css_class` (default: `.codehilite`), then
+set the value of the `-a` option to that class name. The CSS rules will be
+written to the `styles.css` file which you can copy to your site and link from
+your HTML templates.
+
+If you would like to use a different theme, swap out `default` for the desired
+theme. For a list of themes installed on your system (additional themes can be
+installed via Pygments plugins), run the following command:
+
+```bash
+pygmentize -L style
+```
+
+See Pygments' excellent [documentation] for more details. If no language is
+defined, Pygments will attempt to guess the language. When that fails, the code
+block will not be highlighted.
+
+!!! seealso "See Also"
+
+ GitHub user [richeland] has provided a number of different [CSS style
+ sheets][rich] which work with Pygments along with a [preview] of each theme.
+ The `css_class` used is `.highlight`. Therefore, one would need to override the
+ [`css_class`](#css_class) option when using richeland's CSS styles. However, the
+ Python-Markdown project makes no guarantee that richeland's CSS styles will
+ work with the version of Pygments you are using. To ensure complete
+ compatibility, you should generate the CSS rules from your own installation
+ of Pygments.
+
+[richeland]: https://github.com/richleland
+[rich]: https://github.com/richleland/pygments-css
+[preview]: https://richleland.github.io/pygments-css/
+[documentation]: http://pygments.org/docs/
+
+## Syntax
+
+The CodeHilite extension follows the same [syntax][] as regular Markdown code
+blocks, with one exception. The highlighter needs to know what language to use for
+the code block. There are three ways to tell the highlighter what language the
+code block contains and each one has a different result.
+
+!!! Note
+ The format of the language identifier only effects the display of line numbers
+ if `linenums` is set to `None` (the default). If set to `True` or `False`
+ (see [Usage](#usage) below) the format of the identifier has no effect on the
+ display of line numbers -- it only serves as a means to define the language
+ of the code block.
+
+[syntax]: https://daringfireball.net/projects/markdown/syntax#precode
+
+### Shebang (with path)
+
+If the first line of the code block contains a shebang, the language is derived
+from that and line numbers are used.
+
+```md
+ #!/usr/bin/python
+ # Code goes here ...
+```
+
+Will result in:
+
+ #!/usr/bin/python
+ # Code goes here ...
+
+### Shebang (no path)
+
+If the first line contains a shebang, but the shebang line does not contain a
+path (a single `/` or even a space), then that line is removed from the code
+block before processing. Line numbers are used.
+
+```md
+ #!python
+ # Code goes here ...
+```
+
+Will result in:
+
+ #!python
+ # Code goes here ...
+
+### Colons
+
+If the first line begins with three or more colons, the text following the
+colons identifies the language. The first line is removed from the code block
+before processing and line numbers are not used.
+
+```md
+ :::python
+ # Code goes here ...
+```
+
+Will result in:
+
+ :::python
+ # Code goes here ...
+
+Certain lines can be selected for emphasis with the colon syntax. When
+using Pygments' default CSS styles, emphasized lines have a yellow background.
+This is useful to direct the reader's attention to specific lines.
+
+```md
+ :::python hl_lines="1 3"
+ # This line is emphasized
+ # This line isn't
+ # This line is emphasized
+```
+
+Will result in:
+
+ :::python hl_lines="1 3"
+ # This line is emphasized
+ # This line isn't
+ # This line is emphasized
+
+!!! Note
+ `hl_lines` is named for Pygments' option meaning "highlighted lines".
+
+### When No Language is Defined
+
+CodeHilite is completely backwards compatible so that if a code block is
+encountered that does not define a language, the block is simply wrapped in
+`<pre>` tags and output.
+
+```md
+ # Code goes here ...
+```
+
+Will result in:
+
+ # Code goes here ...
+
+Lets see the source for that:
+
+```html
+<div class="codehilite"><pre><code># Code goes here ...
+</code></pre></div>
+```
+
+!!! Note
+ When no language is defined, the Pygments highlighting engine will try to guess
+ the language (unless `guess_lang` is set to `False`). Upon failure, the same
+ behavior will happen as described above.
+
+## Usage
+
+See [Extensions](index.md) for general extension usage. Use `codehilite` as the
+name of the extension.
+
+See the [Library Reference](../reference.md#extensions) for information about
+configuring extensions.
+
+The following options are provided to configure the output:
+
+* **`linenums`**{ #linenums }:
+ An alias to Pygments' `linenos` formatter option. Possible values are `True` for yes, `False` for no and `None`
+ for auto. Defaults to `None`.
+
+ Using `True` will force every code block to have line numbers, even when
+ using colons (`:::`) for language identification.
+
+ Using `False` will turn off all line numbers, even when using shebangs
+ (`#!`) for language identification.
+
+* **`guess_lang`**{ #guess_lang }:
+ Automatic language detection. Defaults to `True`.
+
+ Using `False` will prevent Pygments from guessing the language, and thus
+ highlighting blocks only when you explicitly set the language.
+
+* **`css_class`**{ #css_class }:
+ An alias to Pygments `cssclass` formatter option. Set CSS class name for the wrapper `<div>` tag. Defaults to
+ `codehilite`.
+
+* **`pygments_style`**{ #pygments_style }:
+ Pygments HTML Formatter Style (`ColorScheme`). Defaults to `default`.
+
+ !!! Note
+ This is useful only when `noclasses` is set to `True`, otherwise the
+ CSS styles must be provided by the end user.
+
+* **`noclasses`**{ #noclasses }:
+ Use inline styles instead of CSS classes. Defaults to `False`.
+
+* **`use_pygments`**{ #use_pygments }:
+ Specifies the use of Pygments in generating the output.
+
+ If `True` (the default) and Pygments is available, CodeHilite will use
+ Pygments to analyze and format the output. Additionally, if using Pygments
+ &gt;= 2.4, the output will be wrapped in `<code>` tags, whereas earlier
+ versions will not.
+
+ Otherwise, Pygments will not be used. If a language is defined for a code block, it will be assigned to the
+ `<code>` tag as a class in the manner suggested by the [HTML5 spec][spec] and may be used by a JavaScript library
+ in the browser to highlight the code block. See the [`lang_prefix`](#lang_prefix) option to customize the prefix.
+
+* **`lang_prefix`**{ #lang_prefix }:
+ The prefix prepended to the language class assigned to the HTML `<code>` tag. Default: `language-`.
+
+* **`pygments_formatter`**{ #pygments_formatter }:
+ This option can be used to change the Pygments formatter used for highlighting code blocks. By default, this
+ is set to the string `'html'`, which means it'll use the default `HtmlFormatter` provided by Pygments.
+
+ This can be set to a string representing any of the other default formatters, or set to a formatter class (or
+ any callable).
+
+ The code's language is always passed to the formatter as an extra option `lang_str`, with the value formatted as
+ `{lang_prefix}{lang}`. If the language is unspecified, the language guessed by Pygments will be used. While
+ this option has no effect to the Pygments's builtin formatters, a user can make use of the language in their custom
+ formatter. See an example below.
+
+ To see what formatters are available and how to subclass an existing formatter, please visit [Pygments
+ documentation on this topic][pygments formatters].
+
+* Any other Pygments' options:
+
+ All other options are accepted and passed on to Pygments' lexer and formatter. Therefore,
+ valid options include any options which are accepted by the [html formatter] or
+ whichever [lexer] the code's language uses. Invalid options are ignored without error.
+
+A trivial example:
+
+```python
+markdown.markdown(some_text, extensions=['codehilite'])
+```
+
+To keep the code block's language in the Pygments generated HTML output, one can provide a custom Pygments formatter
+that takes the `lang_str` option. For example,
+
+```python
+from pygments.formatters import HtmlFormatter
+from markdown.extensions.codehilite import CodeHiliteExtension
+
+
+class CustomHtmlFormatter(HtmlFormatter):
+ def __init__(self, lang_str='', **options):
+ super().__init__(**options)
+ # lang_str has the value {lang_prefix}{lang}
+ # specified by the CodeHilite's options
+ self.lang_str = lang_str
+
+ def _wrap_code(self, source):
+ yield 0, f'<code class="{self.lang_str}">'
+ yield from source
+ yield 0, '</code>'
+
+
+some_text = '''\
+ :::python
+ print('hellow world')
+'''
+
+markdown.markdown(
+ some_text,
+ extensions=[CodeHiliteExtension(pygments_formatter=CustomHtmlFormatter)],
+)
+```
+
+The formatter above will output the following HTML structure for a code block:
+
+```html
+<div class="codehilite">
+ <pre>
+ <code class="language-python">
+ ...
+ </code>
+ </pre>
+</div>
+```
+
+[html formatter]: https://pygments.org/docs/formatters/#HtmlFormatter
+[lexer]: https://pygments.org/docs/lexers/
+[spec]: https://www.w3.org/TR/html5/text-level-semantics.html#the-code-element
+[pygments formatters]: https://pygments.org/docs/formatters/
diff --git a/docs/extensions/definition_lists.md b/docs/extensions/definition_lists.md
new file mode 100644
index 0000000..047996a
--- /dev/null
+++ b/docs/extensions/definition_lists.md
@@ -0,0 +1,58 @@
+title: Definition Lists Extension
+
+Definition Lists
+================
+
+Summary
+-------
+
+The Definition Lists extension adds the ability to create definition lists in
+Markdown documents.
+
+This extension is included in the standard Markdown library.
+
+Syntax
+------
+
+Definition lists are defined using the syntax established in
+[PHP Markdown Extra][php].
+
+[php]: http://www.michelf.com/projects/php-markdown/extra/#def-list
+
+Thus, the following text (taken from the above referenced PHP documentation):
+
+```md
+Apple
+: Pomaceous fruit of plants of the genus Malus in
+ the family Rosaceae.
+
+Orange
+: The fruit of an evergreen tree of the genus Citrus.
+```
+
+will be rendered as:
+
+```html
+<dl>
+<dt>Apple</dt>
+<dd>Pomaceous fruit of plants of the genus Malus in
+the family Rosaceae.</dd>
+
+<dt>Orange</dt>
+<dd>The fruit of an evergreen tree of the genus Citrus.</dd>
+</dl>
+```
+
+Usage
+-----
+
+See [Extensions](index.md) for general extension usage. Use `def_list` as the
+name of the extension.
+
+This extension does not accept any special configuration options.
+
+A trivial example:
+
+```python
+markdown.markdown(some_text, extensions=['def_list'])
+```
diff --git a/docs/extensions/extra.md b/docs/extensions/extra.md
new file mode 100644
index 0000000..77f5de0
--- /dev/null
+++ b/docs/extensions/extra.md
@@ -0,0 +1,62 @@
+title: Extra Extension
+
+# Python-Markdown Extra
+
+## Summary
+
+A compilation of various Python-Markdown extensions that (mostly) imitates
+[PHP Markdown Extra](http://michelf.com/projects/php-markdown/extra/).
+
+The supported extensions include:
+
+* [Abbreviations](abbreviations.md)
+* [Attribute Lists](attr_list.md)
+* [Definition Lists](definition_lists.md)
+* [Fenced Code Blocks](fenced_code_blocks.md)
+* [Footnotes](footnotes.md)
+* [Tables](tables.md)
+* [Markdown in HTML](md_in_html.md)
+
+See each individual extension for syntax documentation. Extra and all its
+supported extensions are included in the standard Markdown library.
+
+## Usage
+
+From the Python interpreter:
+
+```pycon
+>>> import markdown
+>>> html = markdown.markdown(text, extensions=['extra'])
+```
+
+To pass configuration options to the extensions included with Extra, they must be passed to Extra, with the
+underlying extension identified as well. In that way Extra will have access to the options and can pass them on to
+the appropriate underlying extension.
+
+```python
+config = {
+ 'extra': {
+ 'footnotes': {
+ 'UNIQUE_IDS': True
+ },
+ 'fenced_code': {
+ 'lang_prefix': 'lang-'
+ }
+ },
+ 'toc': {
+ 'permalink': True
+ }
+}
+
+html = markdown.markdown(text, extensions=['extra', 'toc'], extension_configs=config)
+```
+
+Note that in the above example, `footnotes` and `fenced_code` are both nested under the `extra` key as those
+extensions are included with Extra. However, the `toc` extension is not included with `extra` and therefore its
+configuration options are not nested under the `extra` key.
+
+See each individual extension for a list of supported configuration options.
+
+There are many other [extensions](index.md) which are distributed with Python-Markdown that are not included here in
+Extra. The features of those extensions are not part of PHP Markdown Extra, and therefore, not part of Python-Markdown
+Extra.
diff --git a/docs/extensions/extra.txt b/docs/extensions/extra.txt
deleted file mode 100644
index 817d58f..0000000
--- a/docs/extensions/extra.txt
+++ /dev/null
@@ -1,43 +0,0 @@
-Python-Markdown Extra
-=====================
-
-Summary
--------
-
-A compilation of various Python-Markdown extensions that (mostly) imitates
-[PHP Markdown Extra](http://michelf.com/projects/php-markdown/extra/).
-
-The supported extensions include:
-
-* [[Abbreviations]]
-* [[Definition_Lists]]
-* [[Fenced_Code_Blocks]]
-* [[Footnotes]]
-* [[HeaderId]]
-* [[Tables]]
-
-See each individual extension for syntax documentation. Extra and all it's
-supported extensions are included in the standard Markdown library.
-
-Usage
------
-
-From the Python interpreter:
-
- >>> import markdown
- >>> html = markdown.markdown(text, ['extra'])
-
-In the unlikely event that one or more of the supported extensions are not
-available for import, Markdown will simply continue without that
-extension. If you would like to be notified of such failures,
-you may set Python-Markdown's logger level to "WARN".
-
-There may be additional extensions that are distributed with
-Python-Markdown that are not included here in Extra. Those extensions
-are not part of PHP Markdown Extra, and therefore, not part of
-Python-Markdown Extra. If you really would like Extra to include
-additional extensions, we suggest creating your own clone of Extra
-under a different name (see [[Writing Extensions]]). You could also
-edit the `extensions` global variable defined in the source, but be
-aware that such changes may be lost when you upgrade to any future
-version of Python-Markdown.
diff --git a/docs/extensions/fenced_code_blocks.md b/docs/extensions/fenced_code_blocks.md
new file mode 100644
index 0000000..fc5c9ca
--- /dev/null
+++ b/docs/extensions/fenced_code_blocks.md
@@ -0,0 +1,269 @@
+title: Fenced Code Blocks Extension
+
+# Fenced Code Blocks
+
+## Summary
+
+The Fenced Code Blocks extension adds a secondary way to define code blocks, which overcomes a few limitations of
+indented code blocks.
+
+This extension is included in the standard Markdown library.
+
+## Syntax
+
+Fenced Code Blocks are defined using the syntax originally established in [PHP Markdown Extra][php] and popularized by
+[GitHub Flavored Markdown][gfm].
+
+Fenced code blocks begin with three or more backticks (` ``` `) or tildes (`~~~`) on a line by themselves and end with
+a matching set of backticks or tildes on a line by themselves. The closing set must contain the same number and type
+of characters as the opening set. It is recommended that a blank line be placed before and after the code block.
+
+````md
+A paragraph before the code block.
+
+```
+a one-line code block
+```
+
+A paragraph after the code block.
+````
+
+While backticks seem to be more popular among users, tildes may be used as well.
+
+````md
+~~~
+a one-line code block
+~~~
+````
+
+To include a set of backticks (or tildes) within a code block, use a different number of backticks for the
+deliminators.
+
+`````md
+````
+```
+````
+`````
+
+Fenced code blocks can have a blank line as the first and/or last line of the code block and those lines will be
+preserved.
+
+````md
+```
+
+a three-line code block
+
+```
+````
+
+Unlike indented code blocks, a fenced code block can immediately follow a list item without becoming
+part of the list.
+
+````md
+* A list item.
+
+```
+not part of the list
+```
+````
+
+!!! warning
+
+ Fenced Code Blocks are only supported at the document root level. Therefore, they cannot be nested inside lists or
+ blockquotes. If you need to nest fenced code blocks, you may want to try the third party extension [SuperFences]
+ instead.
+
+### Attributes
+
+Various attributes may be defined on a per-code-block basis by defining them immediately following the opening
+deliminator. The attributes should be wrapped in curly braces `{}` and be on the same line as the deliminator. It is
+generally best to separate the attribute list from the deliminator with a space. Attributes within the list must be
+separated by a space.
+
+````md
+``` { attributes go here }
+a code block with attributes
+```
+````
+
+How those attributes will affect the output will depend on various factors as described below.
+
+#### Language
+
+The language of the code within a code block can be specified for use by syntax highlighters, etc. The language should
+be prefixed with a dot and not contain any whitespace (`.language-name`).
+
+````md
+``` { .html }
+<p>HTML Document</p>
+```
+````
+
+So long as the language is the only option specified, the curly brackets and/or the dot may be excluded:
+
+````md
+``` html
+<p>HTML Document</p>
+```
+````
+
+Either of the above examples will output the following HTML:
+
+```html
+<pre><code class="language-html">&lt;p&gt;HTML Document&lt;/p&gt;
+</code></pre>
+```
+
+Note that the language name has been prefixed with `language-` and it has been assigned to the `class` attribute on
+the `<code>` tag, which is the format suggested by the [HTML 5 Specification][html5] (see the second "example" in the
+Specification). While `language` is the default prefix, the prefix may be overridden using the
+[`lang_prefix`](#lang_prefix) configuration option.
+
+#### Classes
+
+In addition to the language, additional classes may be defined by prefixing them with a dot, just like the language.
+
+````md
+``` { .html .foo .bar }
+<p>HTML Document</p>
+```
+````
+
+When defining multiple classes, only the first class will be used as the "language" for the code block. All others are
+assigned to the `<pre>` tag unaltered. Additionally, the curly braces and dot are required for all classes, including
+the language class if more than one class is defined.
+
+The above example will output the following HTML:
+
+```html
+<pre class="foo bar"><code class="language-html">&lt;p&gt;HTML Document&lt;/p&gt;
+</code></pre>
+```
+
+#### ID
+
+An `id` can be defined for a code block, which would allow a link to point directly to the code block using a URL
+hash. IDs must be prefixed with a hash character (`#`) and only contain characters permitted in HTML `id` attributes.
+
+````md
+``` { #example }
+A linkable code block
+```
+````
+
+The `id` attribute is assigned to the `<pre>` tag of the output. The above example will output the following HTML:
+
+```html
+<pre id="example"><code>A linkable code block
+</code></pre>
+```
+
+From elsewhere within the same document, one could link to the code block with `[link](#example)`.
+
+IDs may be defined along with the language, other classes, or any other supported attributes. The order of items does
+not matter.
+
+````md
+``` { #example .lang .foo .bar }
+A linkable code block
+```
+````
+
+#### Key/Value Pairs
+
+If the `fenced_code` and [`attr_list`][attr_list] extensions are both enabled, then key/value pairs can be defined in
+the attribute list. So long as code highlighting is not enabled (see below), the key/value pairs will be assigned as
+attributes on the `<code>` tag in the output. Key/value pairs must be defined using the syntax documented for the
+`attr_list` extension (for example, values with whitespace must be wrapped in quotes).
+
+````md
+``` { .lang #example style="color: #333; background: #f8f8f8;" }
+A code block with inline styles. Fancy!
+```
+````
+
+The above example will output the following HTML:
+
+```html
+<pre id="example"><code class="language-lang" style="color: #333; background: #f8f8f8;">A code block with inline styles. Fancy!
+</code></pre>
+```
+
+If the `attr_list` extension is not enabled, then the key/value pairs will be ignored.
+
+#### Syntax Highlighting
+
+If the `fenced_code` extension and syntax highlighting are both enabled, then the [`codehilite`][codehilite]
+extension will be used for syntax highlighting the contents of the code block. The language defined in the attribute
+list will be passed to `codehilite` to ensure that the correct language is used. If no language is specified and
+language guessing is not disabled for the `codehilite` extension, then the language will be guessed.
+
+The `codehilite` extension uses the [Pygments] engine to do syntax highlighting. Any valid Pygments options can be
+defined as key/value pairs in the attribute list and will be passed on to Pygments.
+
+````md
+``` { .lang linenos=true linenostart=42 hl_lines="43-44 50" title="An Example Code Block" }`
+A truncated code block...
+```
+````
+
+Valid options include any option accepted by Pygments' [`HTMLFormatter`][HTMLFormatter] except for the `full` option,
+as well as any options accepted by the relevant [lexer][lexer] (each language has its own lexer). While most lexers
+don't have options that are all that useful in this context, there are a few important exceptions. For example, the
+[PHP lexer's] `startinline` option eliminates the need to start each code fragment with `<?php`.
+
+!!! note
+
+ The `fenced_code` extension does not alter the output provided by Pygments. Therefore, only options which Pygments
+ provides can be utilized. As Pygments does not currently provide a way to define an ID, any ID defined in an
+ attribute list will be ignored when syntax highlighting is enabled. Additionally, any key/value pairs which are not Pygments options will be ignored, regardless of whether the `attr_list` extension is enabled.
+
+##### Enabling Syntax Highlighting
+
+To enable syntax highlighting, the [`codehilite`][codehilite] extension must be enabled and the `codehilite`
+extension's `use_pygments` option must be set to `True` (the default).
+
+Alternatively, so long as the `codehilite` extension is enabled, you can override a global `use_pygments=False`
+option for an individual code block by including `use_pygments=true` in the attribute list. While the `use_pygments`
+key/value pair will not be included in the output, all other attributes will behave as they would if syntax
+highlighting was enabled only for that code block.
+
+Conversely, to disable syntax highlighting on an individual code block, include `use_pygments=false` in the attribute
+list. While the `use_pygments` key/value pair will not be included in the output, all other attributes will behave as
+they would if syntax highlighting was disabled for that code block regardless of any global setting.
+
+!!! seealso "See Also"
+
+ You will need to properly install and setup Pygments for syntax highlighting to work. See the `codehilite`
+ extension's [documentation][setup] for details.
+
+## Usage
+
+See [Extensions] for general extension usage. Use `fenced_code` as the name of the extension.
+
+See the [Library Reference] for information about configuring extensions.
+
+The following option is provided to configure the output:
+
+* **`lang_prefix`**{#lang_prefix}:
+ The prefix prepended to the language class assigned to the HTML `<code>` tag. Default: `language-`.
+
+A trivial example:
+
+```python
+markdown.markdown(some_text, extensions=['fenced_code'])
+```
+
+[php]: http://www.michelf.com/projects/php-markdown/extra/#fenced-code-blocks
+[gfm]: https://help.github.com/en/github/writing-on-github/creating-and-highlighting-code-blocks
+[SuperFences]: https://facelessuser.github.io/pymdown-extensions/extensions/superfences/
+[html5]: https://html.spec.whatwg.org/#the-code-element
+[attr_list]: ./attr_list.md
+[codehilite]: ./code_hilite.md
+[Pygments]: http://pygments.org/
+[HTMLFormatter]: https://pygments.org/docs/formatters/#HtmlFormatter
+[lexer]: https://pygments.org/docs/lexers/
+[PHP lexer's]: https://pygments.org/docs/lexers/#lexers-for-php-and-related-languages
+[setup]: ./code_hilite.md#setup
+[Extensions]: ./index.md
+[Library Reference]: ../reference.md#extensions
diff --git a/docs/extensions/footnotes.md b/docs/extensions/footnotes.md
new file mode 100644
index 0000000..e841a32
--- /dev/null
+++ b/docs/extensions/footnotes.md
@@ -0,0 +1,133 @@
+title: Footnotes Extension
+
+Footnotes
+=========
+
+Summary
+-------
+
+The Footnotes extension adds syntax for defining footnotes in Markdown
+documents.
+
+This extension is included in the standard Markdown library.
+
+Syntax
+------
+
+Python-Markdown's Footnote syntax follows the generally accepted syntax of the
+Markdown community at large and almost exactly matches [PHP Markdown Extra][]'s
+implementation of footnotes. The only differences involve a few subtleties in
+the output.
+
+[PHP Markdown Extra]: http://michelf.com/projects/php-markdown/extra/#footnotes
+
+Example:
+
+```md
+Footnotes[^1] have a label[^@#$%] and the footnote's content.
+
+[^1]: This is a footnote content.
+[^@#$%]: A footnote on the label: "@#$%".
+```
+
+A footnote label must start with a caret `^` and may contain any inline text
+(including spaces) between a set of square brackets `[]`. Only the first
+caret has any special meaning.
+
+A footnote content must start with the label followed by a colon and at least
+one space. The label used to define the content must exactly match the label used
+in the body (including capitalization and white space). The content would then
+follow the label either on the same line or on the next line. The content may
+contain multiple lines, paragraphs, code blocks, blockquotes and most any other
+markdown syntax. The additional lines must be indented one level (four spaces or
+one tab).
+
+When working with multiple blocks, it may be helpful to start the content on a
+separate line from the label which defines the content. This way the entire block
+is indented consistently and any errors are more easily discernible by the author.
+
+```md
+[^1]:
+ The first paragraph of the definition.
+
+ Paragraph two of the definition.
+
+ > A blockquote with
+ > multiple lines.
+
+ a code block
+
+ A final paragraph.
+```
+
+Usage
+-----
+
+See [Extensions](index.md) for general extension usage. Use `footnotes` as the
+name of the extension.
+
+See the [Library Reference](../reference.md#extensions) for information about
+configuring extensions.
+
+The following options are provided to configure the output:
+
+* **`PLACE_MARKER`**:
+ A text string used to mark the position where the footnotes are rendered.
+ Defaults to `///Footnotes Go Here///`.
+
+ If the place marker text is not found in the document, the footnote
+ definitions are placed at the end of the resulting HTML document.
+
+* **`UNIQUE_IDS`**:
+ Whether to avoid collisions across multiple calls to `reset()`. Defaults to
+ `False`.
+
+* **`BACKLINK_TEXT`**:
+ The text string that links from the footnote definition back to the position
+ in the document. Defaults to `&#8617;`.
+
+* **`SUPERSCRIPT_TEXT`**:
+ The text string that links from the position in the document to the footnote
+ definition. Defaults to `{}`, i.e. only the footnote's number.
+
+* **`BACKLINK_TITLE`**:
+ The text string for the `title` HTML attribute of the footnote definition link.
+ The placeholder `{}` will be replaced by the footnote number. Defaults to
+ `Jump back to footnote {} in the text`.
+
+* **`SEPARATOR`**:
+ The text string used to set the footnote separator. Defaults to `:`.
+
+A trivial example:
+
+```python
+markdown.markdown(some_text, extensions=['footnotes'])
+```
+
+Resetting Instance State
+-----
+
+Footnote definitions are stored within the `markdown.Markdown` class instance between
+multiple runs of the class. This allows footnotes from all runs to be included in
+output, with links and references that are unique, even though the class has been
+called multiple times.
+
+However, if needed, the definitions can be cleared between runs by calling `reset`.
+
+For instance, the home page of a blog might include the content from multiple documents.
+By not calling `reset`, all of the footnotes will be rendered, and they will all have
+unique links and references.
+
+On the other hand, individual blog post pages might need the content from only one
+document, and should have footnotes pertaining only to that page. By calling `reset`
+between runs, the footnote definitions from the first document will be cleared before
+the second document is rendered.
+
+An example of calling `reset`:
+
+```python
+md = markdown.Markdown(extensions=['footnotes'])
+html1 = md.convert(text_with_footnote)
+md.reset()
+html2 = md.convert(text_without_footnote)
+```
diff --git a/docs/extensions/footnotes.txt b/docs/extensions/footnotes.txt
deleted file mode 100644
index 7188f44..0000000
--- a/docs/extensions/footnotes.txt
+++ /dev/null
@@ -1,62 +0,0 @@
-Footnotes
-=========
-
-Summary
--------
-
-An extension to Python-Markdown that adds footnote syntax. This extension has
-been included with Python-Markdown since 1.7 and should be available to anyone
-who has a typical install of Python-Markdown.
-
-Syntax
-------
-
-Python-Markdown's Footnote syntax follows the generally accepted syntax of the
-Markdown community at large and almost exactly matches [PHP Markdown Extra][]'s
-implementation of footnotes. The only differences involve a few subtleties in
-the output.
-
-[PHP Markdown Extra]: http://michelf.com/projects/php-markdown/extra/#footnotes
-
-Example:
-
- Footnotes[^1] have a label[^label] and a definition[^!DEF].
-
- [^1]: This is a footnote
- [^label]: A footnote on "label"
- [^!DEF]: The definition of a footnote.
-
-A footnote definition may contain multiple lines, paragraphs, code blocks,
-blockquotes and most any other markdown syntax. The additional line simply
-must be indented at least an additional four spaces.
-
- [^1]: The first paragraph of the definition.
-
- Paragraph two of the definition.
-
- > A blockquote with
- > multiple lines.
-
- a code block
-
- A final paragraph.
-
-By default, the footnote definitions are placed at the end of the resulting
-HTML document. However, you may want the footnotes in another location within
-the document. Simply place the following text at that location within your
-markdown document (See how to configure this text below):
-
- ///Footnotes Go Here///
-
-Usage
------
-
-From the Python interpreter:
-
- >>> html = markdown.markdown(text, ['footnotes'])
-
-To configure the place marker for footnote definitions (just be sure not to
-use any existing markdown syntax):
-
- >>> html = markdown.markdown(text, ['footnotes(PLACE_MARKER=+++my marker+++)'])
-
diff --git a/docs/extensions/index.md b/docs/extensions/index.md
new file mode 100644
index 0000000..6481caa
--- /dev/null
+++ b/docs/extensions/index.md
@@ -0,0 +1,87 @@
+title: Extensions
+
+# Extensions
+
+Python Markdown offers a flexible extension mechanism, which makes it possible
+to change and/or extend the behavior of the parser without having to edit the
+actual source files.
+
+To use an extension, pass it to markdown with the `extensions` keyword.
+
+```python
+markdown.markdown(some_text, extensions=[MyExtClass(), 'myext', 'path.to.my.ext:MyExtClass'])
+```
+
+See the [Library Reference](../reference.md#extensions) for more details.
+
+From the command line, specify an extension with the `-x` option.
+
+```bash
+python -m markdown -x myext -x path.to.module:MyExtClass input.txt > output.html
+```
+
+See the [Command Line docs](../cli.md) or use the `--help` option for more details.
+
+!!! seealso "See Also"
+ If you would like to write your own extensions, see the
+ [Extension API](api.md) for details.
+
+Officially Supported Extensions
+-------------------------------
+
+The extensions listed below are included with (at least) the most recent release
+and are officially supported by Python-Markdown. Any documentation is
+maintained here and all bug reports should be made to the project. If you
+have a typical install of Python-Markdown, these extensions are already
+available to you using the "Entry Point" name listed in the second column below.
+
+Extension | Entry Point | Dot Notation
+---------------------------------- | -------------- | ------------
+[Extra] | `extra` | `markdown.extensions.extra`
+&nbsp; &nbsp; [Abbreviations] | `abbr` | `markdown.extensions.abbr`
+&nbsp; &nbsp; [Attribute Lists] | `attr_list` | `markdown.extensions.attr_list`
+&nbsp; &nbsp; [Definition Lists] | `def_list` | `markdown.extensions.def_list`
+&nbsp; &nbsp; [Fenced Code Blocks] | `fenced_code` | `markdown.extensions.fenced_code`
+&nbsp; &nbsp; [Footnotes] | `footnotes` | `markdown.extensions.footnotes`
+&nbsp; &nbsp; [Markdown in HTML] | `md_in_html` | `markdown.extensions.md_in_html`
+&nbsp; &nbsp; [Tables] | `tables` | `markdown.extensions.tables`
+[Admonition] | `admonition` | `markdown.extensions.admonition`
+[CodeHilite] | `codehilite` | `markdown.extensions.codehilite`
+[Legacy Attributes] | `legacy_attrs` | `markdown.extensions.legacy_attrs`
+[Legacy Emphasis] | `legacy_em` | `markdown.extensions.legacy_em`
+[Meta-Data] | `meta` | `markdown.extensions.meta`
+[New Line to Break] | `nl2br` | `markdown.extensions.nl2br`
+[Sane Lists] | `sane_lists` | `markdown.extensions.sane_lists`
+[SmartyPants] | `smarty` | `markdown.extensions.smarty`
+[Table of Contents] | `toc` | `markdown.extensions.toc`
+[WikiLinks] | `wikilinks` | `markdown.extensions.wikilinks`
+
+[Extra]: extra.md
+[Abbreviations]: abbreviations.md
+[Attribute Lists]: attr_list.md
+[Definition Lists]: definition_lists.md
+[Fenced Code Blocks]: fenced_code_blocks.md
+[Footnotes]: footnotes.md
+[Tables]: tables.md
+[Admonition]: admonition.md
+[CodeHilite]: code_hilite.md
+[Legacy Attributes]: legacy_attrs.md
+[Legacy Emphasis]: legacy_em.md
+[Meta-Data]: meta_data.md
+[New Line to Break]: nl2br.md
+[Markdown in HTML]: md_in_html.md
+[Sane Lists]: sane_lists.md
+[SmartyPants]: smarty.md
+[Table of Contents]: toc.md
+[WikiLinks]: wikilinks.md
+
+Third Party Extensions
+----------------------
+
+Various individuals and/or organizations have developed extensions which they
+have made available to the public. A [list of third party extensions][list]
+is maintained on the wiki for your convenience. The Python-Markdown team
+offers no official support for these extensions. Please see the developer of
+each extension for support.
+
+[list]: https://github.com/Python-Markdown/markdown/wiki/Third-Party-Extensions
diff --git a/docs/extensions/index.txt b/docs/extensions/index.txt
deleted file mode 100644
index 71d857c..0000000
--- a/docs/extensions/index.txt
+++ /dev/null
@@ -1,44 +0,0 @@
-Available Extensions
-====================
-
-Officially Supported Extensions
--------------------------------
-
-These extensions are included with (at least) the most recent release and are
-officially supported by the Python-Markdown developers. Any documentation is
-maintained here and all bug reports should be made to the project. If you
-have a typical install of Python-Markdown, these extensions are already
-available to you.
-
-* [[Extra]]
- * [[Abbreviations]]
- * [[Definition_Lists]]
- * [[Fenced_Code_Blocks]]
- * [[Footnotes]]
- * [[HeaderId]]
- * [[Tables]]
-* [[CodeHilite]]
-* [[HTML_Tidy]]
-* [[ImageLinks]]
-* [[Meta-Data]]
-* [[RSS]]
-* [[Table_of_Contents]]
-* [[WikiLinks]]
-
-Unofficially Supported Extensions
----------------------------------
-
-These extensions have not yet been included in any official Python-Markdown
-release. However, the code is maintained in the projects
-[mainline git repository](http://gitorious.org/projects/python-markdown/repos/mainline)
-by the Python-Markdown developers and the official documentation is maintained
-here. All bug reports should be made to the project. It is anticipated that
-these extensions will be included with some future official release, at which
-time they will be moved to the above list of official extensions.
-
-* [[Legacy]]
-
-
-
-
-
diff --git a/docs/extensions/legacy_attrs.md b/docs/extensions/legacy_attrs.md
new file mode 100644
index 0000000..daa566d
--- /dev/null
+++ b/docs/extensions/legacy_attrs.md
@@ -0,0 +1,66 @@
+title: Legacy Attributes Extension
+
+# Legacy Attributes
+
+## Summary
+
+The Legacy Attributes extension restores Python-Markdown's original attribute
+setting syntax. Older versions of Python Markdown (prior to 3.0) included
+built-in and undocumented support for defining attributes on elements. Most
+users have never made use of the syntax and it has been deprecated in favor of
+[Attribute Lists](attr_list.md). This extension restores the legacy behavior for
+users who have existing documents which use the syntax.
+
+## Syntax
+
+Attributes are defined by including the following within the element you wish to
+assign the attributes to:
+
+```md
+{@key=value}
+```
+
+For example, to define a class to a paragraph:
+
+```md
+A paragraph with the attribute defined {@class=foo}anywhere within.
+```
+
+Which results in the following output:
+
+```html
+<p class="foo">A paragraph with the attribute defined anywhere within.</p>
+```
+
+The same applies for inline elements:
+
+```md
+Some *emphasized{@id=bar}* text.
+```
+
+```html
+<p>Some <em id="bar">emphasized</em> text.</p>
+```
+
+You can also define attributes in images:
+
+```md
+![Alt text{@id=baz}](path/to/image.jpg)
+```
+
+```html
+<p><img alt="Alt text" id="baz" src="path/to/image.jpg" /></p>
+```
+
+## Usage
+
+See [Extensions](index.md) for general extension usage. Use `legacy_attrs` as the
+name of the extension.
+
+This extension does not accept any special configuration options.
+
+A trivial example:
+
+```python
+markdown.markdown(some_text, extensions=['legacy_attrs'])
+```
diff --git a/docs/extensions/legacy_em.md b/docs/extensions/legacy_em.md
new file mode 100644
index 0000000..67c6cd0
--- /dev/null
+++ b/docs/extensions/legacy_em.md
@@ -0,0 +1,31 @@
+title: Legacy EM Extension
+
+# Legacy EM
+
+## Summary
+
+The Legacy EM extension restores Markdown's original behavior for emphasis and
+strong syntax when using underscores.
+
+By default Python-Markdown treats `_connected_words_` intelligently by
+recognizing that mid-word underscores should not be used for emphasis. In other
+words, by default, that input would result in this output:
+`<em>connected_words</em>`.
+
+However, that behavior is not consistent with the original rules or the behavior
+of the reference implementation. Therefore, this extension can be used to better
+match the reference implementation. With the extension enabled, the above input
+would result in this output: `<em>connected</em>words_`.
+
+## Usage
+
+See [Extensions](index.md) for general extension usage. Use `legacy_em` as the
+name of the extension.
+
+This extension does not accept any special configuration options.
+
+A trivial example:
+
+```python
+markdown.markdown(some_text, extensions=['legacy_em'])
+```
diff --git a/docs/extensions/md_in_html.md b/docs/extensions/md_in_html.md
new file mode 100644
index 0000000..978f5c3
--- /dev/null
+++ b/docs/extensions/md_in_html.md
@@ -0,0 +1,237 @@
+title: Markdown in HTML Extension
+
+# Markdown in HTML
+
+## Summary
+
+An extension that parses Markdown inside of HTML tags.
+
+## Syntax
+
+By default, Markdown ignores any content within a raw HTML block-level element. With the `md-in-html` extension
+enabled, the content of a raw HTML block-level element can be parsed as Markdown by including a `markdown` attribute
+on the opening tag. The `markdown` attribute will be stripped from the output, while all other attributes will be
+preserved.
+
+The `markdown` attribute can be assigned one of three values: [`"1"`](#1), [`"block"`](#block), or [`"span"`](#span).
+
+!!! note
+
+ The expressions "block-level" and "span-level" as used in this document refer to an element's designation
+ according to the HTML specification. Whereas the `"span"` and `"block"` values assigned to the `markdown`
+ attribute refer to the Markdown parser's behavior.
+
+### `markdown="1"` { #1 }
+
+When the `markdown` attribute is set to `"1"`, then the parser will use the default behavior for that specific tag.
+
+The following tags have the `block` behavior by default: `article`, `aside`, `blockquote`, `body`, `colgroup`,
+`details`, `div`, `dl`, `fieldset`, `figcaption`, `figure`, `footer`, `form`, `group`, `header`, `hgroup`, `hr`,
+`iframe`, `main`, `map`, `menu`, `nav`, `noscript`, `object`, `ol`, `output`, `progress`, `section`, `table`,
+`tbody`, `tfoot`, `thead`, `tr`, `ul` and `video`.
+
+For example, the following:
+
+```
+<div markdown="1">
+This is a *Markdown* Paragraph.
+</div>
+```
+
+... is rendered as:
+
+``` html
+<div>
+<p>This is a <em>Markdown</em> Paragraph.</p>
+</div>
+```
+
+The following tags have the `span` behavior by default: `address`, `dd`, `dt`, `h[1-6]`, `legend`, `li`, `p`, `td`,
+and `th`.
+
+For example, the following:
+
+```
+<p markdown="1">
+This is not a *Markdown* Paragraph.
+</p>
+```
+
+... is rendered as:
+
+``` html
+<p>
+This is not a <em>Markdown</em> Paragraph.
+</p>
+```
+
+### `markdown="block"` { #block }
+
+When the `markdown` attribute is set to `"block"`, then the parser will force the `block` behavior on the contents of
+the element so long as it is one of the `block` or `span` tags.
+
+The content of a `block` element is parsed into block-level content. In other words, the text is rendered as
+paragraphs, headers, lists, blockquotes, etc. Any inline syntax within those elements is processed as well.
+
+For example, the following:
+
+```
+<section markdown="block">
+# A header.
+
+A *Markdown* paragraph.
+
+* A list item.
+* A second list item.
+
+</section>
+```
+
+... is rendered as:
+
+``` html
+<section>
+<h1>A header.</h1>
+<p>A <em>Markdown</em> paragraph.</p>
+<ul>
+<li>A list item.</li>
+<li>A second list item.</li>
+</ul>
+</section>
+```
+
+!!! warning
+
+ Forcing elements to be parsed as `block` elements when they are not by default could result in invalid HTML.
+ For example, one could force a `<p>` element to be nested within another `<p>` element. In most cases it is
+ recommended to use the default behavior of `markdown="1"`. Explicitly setting `markdown="block"` should be
+ reserved for advanced users who understand the HTML specification and how browsers parse and render HTML.
+
+### `markdown="span"` { #span }
+
+When the `markdown` attribute is set to `"span"`, then the parser will force the `span` behavior on the contents
+of the element so long as it is one of the `block` or `span` tags.
+
+The content of a `span` element is not parsed into block-level content. In other words, the content will not be
+rendered as paragraphs, headers, etc. Only inline syntax will be rendered, such as links, strong, emphasis, etc.
+
+For example, the following:
+
+```
+<div markdown="span">
+# *Not* a header
+</div>
+```
+
+... is rendered as:
+
+``` html
+<div>
+# <em>Not</em> a header
+</div>
+```
+
+### Ignored Elements
+
+The following tags are always ignored, regardless of any `markdown` attribute: `canvas`, `math`, `option`, `pre`,
+`script`, `style`, and `textarea`. All other raw HTML tags are treated as span-level tags and are not affected by this
+extension.
+
+### Nesting
+
+When nesting multiple levels of raw HTML elements, a `markdown` attribute must be defined for each block-level
+element. For any block-level element which does not have a `markdown` attribute, everything inside that element is
+ignored, including child elements with `markdown` attributes.
+
+For example, the following:
+
+```
+<article id="my-article" markdown="1">
+# Article Title
+
+A Markdown paragraph.
+
+<section id="section-1" markdown="1">
+## Section 1 Title
+
+<p>Custom raw **HTML** which gets ignored.</p>
+
+</section>
+
+<section id="section-2" markdown="1">
+## Section 2 Title
+
+<p markdown="1">**Markdown** content.</p>
+
+</section>
+
+</article>
+```
+
+... is rendered as:
+
+```html
+<article id="my-article">
+<h1>Article Title</h1>
+<p>A Markdown paragraph.</p>
+<section id="section-1">
+<h2>Section 1 Title</h2>
+<p>Custom raw **HTML** which gets ignored.</p>
+</section>
+<section id="section-2">
+<h2>Section 2 Title</h2>
+<p><strong>Markdown</strong> content.</p>
+</section>
+</article>
+```
+
+When the value of an element's `markdown` attribute is more permissive that its parent, then the parent's stricter
+behavior is enforced. For example, a `block` element nested within a `span` element will be parsed using the `span`
+behavior. However, if the value of an element's `markdown` attribute is the same as, or more restrictive than, its
+parent, the the child element's behavior is observed. For example, a `block` element may contain either `block`
+elements or `span` elements as children and each element will be parsed using the specified behavior.
+
+### Tag Normalization
+
+While the default behavior is for Markdown to not alter raw HTML, as this extension is parsing the content of raw HTML elements, it will do some normalization of the tags of block-level elements. For example, the following raw HTML:
+
+```
+<div markdown="1">
+<p markdown="1">A Markdown paragraph with *no* closing tag.
+<p>A raw paragraph with *no* closing tag.
+</div>
+```
+
+... is rendered as:
+
+``` html
+<div>
+<p>A Markdown paragraph with <em>no</em> closing tag.
+</p>
+<p>A raw paragraph with *no* closing tag.
+</p>
+</div>
+```
+
+Notice that the parser properly recognizes that an unclosed `<p>` tag ends when another `<p>` tag begins or when the
+parent element ends. In both cases, a closing `</p>` was added to the end of the element, regardless of whether a
+`markdown` attribute was assigned to the element.
+
+To avoid any normalization, an element must not be a descendant of any block-level element which has a `markdown`
+attribute defined.
+
+!!! warning
+
+ The normalization behavior is only documented here so that document authors are not surprised when their carefully
+ crafted raw HTML is altered by Markdown. This extension should not be relied on to normalize and generate valid
+ HTML. For the best results, always include valid raw HTML (with both opening and closing tags) in your Markdown
+ documents.
+
+## Usage
+
+From the Python interpreter:
+
+``` pycon
+>>> import markdown
+>>> html = markdown.markdown(text, extensions=['md_in_html'])
+```
diff --git a/docs/extensions/meta_data.md b/docs/extensions/meta_data.md
new file mode 100644
index 0000000..d5a4c87
--- /dev/null
+++ b/docs/extensions/meta_data.md
@@ -0,0 +1,113 @@
+title: Meta-Data Extension
+
+Meta-Data
+=========
+
+Summary
+-------
+
+The Meta-Data extension adds a syntax for defining meta-data about a document.
+It is inspired by and follows the syntax of [MultiMarkdown][]. Currently,
+this extension does not use the meta-data in any way, but simply provides it as
+a `Meta` attribute of a Markdown instance for use by other extensions or
+directly by your python code.
+
+This extension is included in the standard Markdown library.
+
+[MultiMarkdown]: https://fletcherpenney.net/multimarkdown/#metadata
+
+Syntax
+------
+
+Meta-data consists of a series of keywords and values defined at the beginning
+of a markdown document like this:
+
+```md
+Title: My Document
+Summary: A brief description of my document.
+Authors: Waylan Limberg
+ John Doe
+Date: October 2, 2007
+blank-value:
+base_url: http://example.com
+
+This is the first paragraph of the document.
+```
+
+The keywords are case-insensitive and may consist of letters, numbers,
+underscores and dashes and must end with a colon. The values consist of
+anything following the colon on the line and may even be blank.
+
+If a line is indented by 4 or more spaces, that line is assumed to be an
+additional line of the value for the previous keyword. A keyword may have as
+many lines as desired.
+
+The first blank line ends all meta-data for the document. Therefore, the first
+line of a document must not be blank.
+
+Alternatively, You may use YAML style deliminators to mark the start and/or end
+of your meta-data. When doing so, the first line of your document must be `---`.
+The meta-data ends at the first blank line or the first line containing an end
+deliminator (either `---` or `...`), whichever comes first. Even though YAML
+deliminators are supported, meta-data is not parsed as YAML.
+
+All meta-data is stripped from the document prior to any further processing
+by Markdown.
+
+Usage
+-----
+
+See [Extensions](index.md) for general extension usage. Use `meta` as the name
+of the extension.
+
+A trivial example:
+
+```python
+markdown.markdown(some_text, extensions=['meta'])
+```
+
+Accessing the Meta-Data
+-----------------------
+
+The meta-data is made available as a python Dict in the `Meta` attribute of an
+instance of the Markdown class. For example, using the above document:
+
+```pycon
+>>> md = markdown.Markdown(extensions = ['meta'])
+>>> html = md.convert(text)
+>>> # Meta-data has been stripped from output
+>>> print html
+<p>This is the first paragraph of the document.</p>
+
+>>> # View meta-data
+>>> print md.Meta
+{
+'title' : ['My Document'],
+'summary' : ['A brief description of my document.'],
+'authors' : ['Waylan Limberg', 'John Doe'],
+'date' : ['October 2, 2007'],
+'blank-value' : [''],
+'base_url' : ['http://example.com']
+}
+```
+
+Note that the keys are all lowercase and the values consist of a list of
+strings where each item is one line for that key. This way, one could preserve
+line breaks if desired. Or the items could be joined where appropriate. No
+assumptions are made regarding the data. It is simply passed as found to the
+`Meta` attribute.
+
+Perhaps the meta-data could be passed into a template system, or used by
+various Markdown extensions. The possibilities are left to the imagination of
+the developer.
+
+Compatible Extensions
+---------------------
+
+The following extensions are currently known to work with the Meta-Data
+extension. The keywords they are known to support are also listed.
+
+* [WikiLinks](wikilinks.md)
+ * `wiki_base_url`
+ * `wiki_end_url`
+ * `wiki_html_class`
diff --git a/docs/extensions/nl2br.md b/docs/extensions/nl2br.md
new file mode 100644
index 0000000..2c7a1a5
--- /dev/null
+++ b/docs/extensions/nl2br.md
@@ -0,0 +1,41 @@
+title: New Line to Break Extension
+
+New-Line-to-Break Extension
+===========================
+
+Summary
+-------
+
+The New-Line-to-Break (`nl2br`) Extension will cause newlines to be treated as
+hard breaks; like StackOverflow and [GitHub][] flavored Markdown do.
+
+[Github]: https://github.github.com/github-flavored-markdown/
+
+Example
+-------
+
+```pycon
+>>> import markdown
+>>> text = """
+... Line 1
+... Line 2
+... """
+>>> html = markdown.markdown(text, extensions=['nl2br'])
+>>> print html
+<p>Line 1<br />
+Line 2</p>
+```
+
+Usage
+-----
+
+See [Extensions](index.md) for general extension usage. Use `nl2br` as the name
+of the extension.
+
+This extension does not accept any special configuration options.
+
+A trivial example:
+
+```python
+markdown.markdown(some_text, extensions=['nl2br'])
+```
diff --git a/docs/extensions/sane_lists.md b/docs/extensions/sane_lists.md
new file mode 100644
index 0000000..bb43833
--- /dev/null
+++ b/docs/extensions/sane_lists.md
@@ -0,0 +1,104 @@
+title: Sane Lists Extension
+
+Sane Lists
+==========
+
+Summary
+-------
+
+The Sane Lists extension alters the behavior of the Markdown List syntax
+to be less surprising.
+
+This extension is included in the standard Markdown library.
+
+Syntax
+------
+
+Sane Lists do not allow the mixing of list types. In other words, an ordered
+list will not continue when an unordered list item is encountered and
+vice versa. For example:
+
+```md
+1. Ordered item 1
+2. Ordered item 2
+
+* Unordered item 1
+* Unordered item 2
+```
+
+will result in the following output:
+
+```html
+<ol>
+ <li>Ordered item 1</li>
+ <li>Ordered item 2</li>
+</ol>
+
+<ul>
+ <li>Unordered item 1</li>
+ <li>Unordered item 2</li>
+</ul>
+```
+
+Whereas the default Markdown behavior would be to generate an unordered list.
+
+Note that, unlike the default Markdown behavior, if a blank line is not
+included between list items, the different list type is ignored completely.
+This corresponds to the behavior of paragraphs. For example:
+
+```md
+A Paragraph.
+* Not a list item.
+
+1. Ordered list item.
+* Not a separate list item.
+```
+
+With this extension the above will result in the following output:
+
+```html
+<p>A Paragraph.
+* Not a list item.</p>
+
+<ol>
+ <li>Ordered list item.
+ * Not a separate list item.</li>
+</ol>
+```
+
+Sane lists also recognize the number used in ordered lists. Given the following
+list:
+
+```md
+4. Apples
+5. Oranges
+6. Pears
+```
+
+By default markdown will ignore the fact that the first line started
+with item number "4" and the HTML list will start with a number "1".
+This extension will result in the following HTML output:
+
+```html
+<ol start="4">
+ <li>Apples</li>
+ <li>Oranges</li>
+ <li>Pears</li>
+</ol>
+```
+
+In all other ways, Sane Lists should behave as normal Markdown lists.
+
+Usage
+-----
+
+See [Extensions](index.md) for general extension usage. Use `sane_lists` as the
+name of the extension.
+
+This extension does not accept any special configuration options.
+
+A trivial example:
+
+```python
+markdown.markdown(some_text, extensions=['sane_lists'])
+```
diff --git a/docs/extensions/smarty.md b/docs/extensions/smarty.md
new file mode 100644
index 0000000..d7211c0
--- /dev/null
+++ b/docs/extensions/smarty.md
@@ -0,0 +1,84 @@
+title: SmartyPants Extension
+
+SmartyPants
+===========
+
+Summary
+-------
+
+The SmartyPants extension converts ASCII dashes, quotes and ellipses to
+their HTML entity equivalents.
+
+ASCII symbol | Replacements | HTML Entities | Substitution Keys
+------------ | --------------- | ------------------- | ----------------------------------------
+`'` | &lsquo; &rsquo; | `&lsquo;` `&rsquo;` | `'left-single-quote'`, `'right-single-quote'`
+`"` | &ldquo; &rdquo; | `&ldquo;` `&rdquo;` | `'left-double-quote'`, `'right-double-quote'`
+`<< >>` | &laquo; &raquo; | `&laquo;` `&raquo;` | `'left-angle-quote'`, `'right-angle-quote'`
+`...` | &hellip; | `&hellip;` | `'ellipsis'`
+`--` | &ndash; | `&ndash;` | `'ndash'`
+`---` | &mdash; | `&mdash;` | `'mdash'`
+
+Using the configuration option 'substitutions' you can overwrite the
+default substitutions. Just pass a dict mapping (a subset of) the
+keys to the substitution strings.
+
+For example, one might use the following configuration to get correct quotes for
+the German language:
+
+```python
+extension_configs = {
+ 'smarty': {
+ 'substitutions': {
+ 'left-single-quote': '&sbquo;', # sb is not a typo!
+ 'right-single-quote': '&lsquo;',
+ 'left-double-quote': '&bdquo;',
+ 'right-double-quote': '&ldquo;'
+ }
+ }
+}
+```
+
+!!! note
+ This extension re-implements the Python [SmartyPants]
+ library by integrating it into the markdown parser.
+ While this does not provide any additional features,
+ it does offer a few advantages. Notably, it will not
+ try to work on highlighted code blocks (using the
+ [CodeHilite] Extension) like the third party library
+ has been known to do.
+
+[SmartyPants]: https://pythonhosted.org/smartypants/
+[CodeHilite]: code_hilite.md
+
+Usage
+-----
+
+See [Extensions](index.md) for general extension usage. Use `smarty` as the
+name of the extension.
+
+See the [Library Reference](../reference.md#extensions) for information about
+configuring extensions.
+
+The following options are provided to configure the output:
+
+Option | Default value | Description
+------ | ------------- | -----------
+`smart_dashes` | `True` | whether to convert dashes
+`smart_quotes` | `True` | whether to convert straight quotes
+`smart_angled_quotes` | `False` | whether to convert angled quotes
+`smart_ellipses` | `True` | whether to convert ellipses
+`substitutions` | `{}` | overwrite default substitutions
+
+A trivial example:
+
+```python
+markdown.markdown(some_text, extensions=['smarty'])
+```
+
+Further reading
+---------------
+
+SmartyPants extension is based on the original SmartyPants implementation
+by John Gruber. Please read its [documentation][1] for details.
+
+[1]: https://daringfireball.net/projects/smartypants/
diff --git a/docs/extensions/tables.md b/docs/extensions/tables.md
new file mode 100644
index 0000000..aaffc09
--- /dev/null
+++ b/docs/extensions/tables.md
@@ -0,0 +1,87 @@
+title: Tables Extension
+
+Tables
+======
+
+Summary
+-------
+
+The Tables extension adds the ability to create tables in Markdown documents.
+
+This extension is included in the standard Markdown library.
+
+Syntax
+------
+
+Tables are defined using the syntax established in [PHP Markdown Extra][php].
+
+[php]: http://www.michelf.com/projects/php-markdown/extra/#table
+
+Thus, the following text (taken from the above referenced PHP documentation):
+
+```md
+First Header | Second Header
+------------- | -------------
+Content Cell | Content Cell
+Content Cell | Content Cell
+```
+
+will be rendered as:
+
+```html
+<table>
+ <thead>
+ <tr>
+ <th>First Header</th>
+ <th>Second Header</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>Content Cell</td>
+ <td>Content Cell</td>
+ </tr>
+ <tr>
+ <td>Content Cell</td>
+ <td>Content Cell</td>
+ </tr>
+ </tbody>
+</table>
+```
+
+!!! seealso "See Also"
+ The [Attribute Lists](./attr_list.md) extension includes support for defining attributes on table cells.
+
+Usage
+-----
+
+See [Extensions](index.md) for general extension usage. Use `tables` as the
+name of the extension.
+
+See the [Library Reference](../reference.md#extensions) for information about
+configuring extensions.
+
+The following options are provided to change the default behavior:
+
+* **`use_align_attribute`**: Set to `True` to use `align` instead of an appropriate `style` attribute
+
+ Default: `'False'`
+
+
+A trivial example:
+
+```python
+markdown.markdown(some_text, extensions=['tables'])
+```
+
+### Examples
+
+For an example, let us suppose that alignment should be controlled by the legacy `align`
+attribute.
+
+```pycon
+>>> from markdown.extensions.tables import TableExtension
+>>> html = markdown.markdown(text,
+... extensions=[TableExtension(use_align_attribute=True)]
+... )
+```
diff --git a/docs/extensions/toc.md b/docs/extensions/toc.md
new file mode 100644
index 0000000..8d7bd35
--- /dev/null
+++ b/docs/extensions/toc.md
@@ -0,0 +1,232 @@
+title: Table of Contents Extension
+
+Table of Contents
+=================
+
+Summary
+-------
+
+The Table of Contents extension generates a Table of Contents from a Markdown
+document and adds it into the resulting HTML document.
+
+This extension is included in the standard Markdown library.
+
+Syntax
+------
+
+By default, all headers will automatically have unique `id` attributes
+generated based upon the text of the header. Note this example, in which all
+three headers would have the same `id`:
+
+```md
+#Header
+#Header
+#Header
+```
+
+Results in:
+
+```html
+<h1 id="header">Header</h1>
+<h1 id="header_1">Header</h1>
+<h1 id="header_2">Header</h1>
+```
+
+Place a marker in the document where you would like the Table of Contents to
+appear. Then, a nested list of all the headers in the document will replace the
+marker. The marker defaults to `[TOC]` so the following document:
+
+```md
+[TOC]
+
+# Header 1
+
+## Header 2
+```
+
+would generate the following output:
+
+```html
+<div class="toc">
+ <ul>
+ <li><a href="#header-1">Header 1</a></li>
+ <ul>
+ <li><a href="#header-2">Header 2</a></li>
+ </ul>
+ </ul>
+</div>
+<h1 id="header-1">Header 1</h1>
+<h2 id="header-2">Header 2</h2>
+```
+
+Regardless of whether a `marker` is found in the document (or disabled), the
+Table of Contents is available as an attribute (`toc`) on the Markdown class.
+This allows one to insert the Table of Contents elsewhere in their page
+template. For example:
+
+```pycon
+>>> md = markdown.Markdown(extensions=['toc'])
+>>> html = md.convert(text)
+>>> page = render_some_template(context={'body': html, 'toc': md.toc})
+```
+
+The `toc_tokens` attribute is also available on the Markdown class and contains
+a nested list of dict objects. For example, the above document would result in
+the following object at `md.toc_tokens`:
+
+```python
+[
+ {
+ 'level': 1,
+ 'id': 'header-1',
+ 'name': 'Header 1',
+ 'children': [
+ {'level': 2, 'id': 'header-2', 'name': 'Header 2', 'children':[]}
+ ]
+ }
+]
+```
+
+Note that the `level` refers to the `hn` level. In other words, `<h1>` is level
+`1` and `<h2>` is level `2`, etc. Be aware that improperly nested levels in the
+input may result in odd nesting of the output.
+
+### Custom Labels
+
+In most cases, the text label in the Table of Contents should match the text of
+the header. However, occasionally that is not desirable. In that case, if this
+extension is used in conjunction with the [Attribute Lists Extension] and a
+`data-toc-label` attribute is defined on the header, then the contents of that
+attribute will be used as the text label for the item in the Table of Contents.
+For example, the following Markdown:
+
+[Attribute Lists Extension]: attr_list.md
+
+```md
+[TOC]
+
+# Functions
+
+## `markdown.markdown(text [, **kwargs])` { #markdown data-toc-label='markdown.markdown' }
+```
+would generate the following output:
+
+```html
+<div class="toc">
+ <ul>
+ <li><a href="#functions">Functions</a></li>
+ <ul>
+ <li><a href="#markdown">markdown.markdown</a></li>
+ </ul>
+ </ul>
+</div>
+<h1 id="functions">Functions</h1>
+<h2 id="markdown"><code>markdown.markdown(text [, **kwargs])</code></h2>
+```
+
+Notice that the text in the Table of Contents is much cleaner and easier to read
+in the context of a Table of Contents. The `data-toc-label` is not included in
+the HTML header element. Also note that the ID was manually defined in the
+attribute list to provide a cleaner URL when linking to the header. If the ID is
+not manually defined, it is always derived from the text of the header, never
+from the `data-toc-label` attribute.
+
+Usage
+-----
+
+See [Extensions](index.md) for general extension usage. Use `toc` as the name
+of the extension.
+
+See the [Library Reference](../reference.md#extensions) for information about
+configuring extensions.
+
+The following options are provided to configure the output:
+
+* **`marker`**:
+ Text to find and replace with the Table of Contents. Defaults to `[TOC]`.
+
+ Set to an empty string to disable searching for a marker, which may save
+ some time, especially on long documents.
+
+* **`title`**:
+ Title to insert in the Table of Contents' `<div>`. Defaults to `None`.
+
+* **`toc_class`**:
+ CSS class(es) used for the `<div>` containing the Table of Contents. Defaults to `toc`.
+
+* **`anchorlink`**:
+ Set to `True` to cause all headers to link to themselves. Default is `False`.
+
+* **`anchorlink_class`**:
+ CSS class(es) used for the link. Defaults to `toclink`.
+
+* **`permalink`**:
+ Set to `True` or a string to generate permanent links at the end of each header.
+ Useful with Sphinx style sheets.
+
+ When set to `True` the paragraph symbol (&para; or "`&para;`") is used as
+ the link text. When set to a string, the provided string is used as the link
+ text.
+
+* **`permalink_class`**:
+ CSS class(es) used for the link. Defaults to `headerlink`.
+
+* **`permalink_title`**:
+ Title attribute of the permanent link. Defaults to `Permanent link`.
+
+* **`baselevel`**:
+ Base level for headers. Defaults to `1`.
+
+ The `baselevel` setting allows the header levels to be automatically
+ adjusted to fit within the hierarchy of your HTML templates. For example,
+ suppose the Markdown text for a page should not contain any headers higher
+ than level 3 (`<h3>`). The following will accomplish that:
+
+ :::pycon
+ >>> text = '''
+ ... #Some Header
+ ... ## Next Level'''
+ >>> from markdown.extensions.toc import TocExtension
+ >>> html = markdown.markdown(text, extensions=[TocExtension(baselevel=3)])
+ >>> print html
+ <h3 id="some_header">Some Header</h3>
+ <h4 id="next_level">Next Level</h4>'
+
+* **`slugify`**:
+ Callable to generate anchors.
+
+ Default: `markdown.extensions.headerid.slugify`
+
+ In order to use a different algorithm to define the id attributes, define and
+ pass in a callable which takes the following two arguments:
+
+ * `value`: The string to slugify.
+ * `separator`: The Word Separator.
+
+ The callable must return a string appropriate for use in HTML `id` attributes.
+
+ An alternate version of the default callable supporting Unicode strings is also
+ provided as `markdown.extensions.headerid.slugify_unicode`.
+
+* **`separator`**:
+ Word separator. Character which replaces white space in id. Defaults to "`-`".
+
+* **`toc_depth`**
+ Define the range of section levels to include in the Table of Contents.
+ A single integer (`b`) defines the bottom section level (`<h1>..<hb>`) only.
+ A string consisting of two digits separated by a hyphen in between (`"2-5"`),
+ define the top (`t`) and the bottom (`b`) (`<ht>..<hb>`). Defaults to `6` (bottom).
+
+ When used with conjunction with `baselevel`, this parameter will not
+ take the fitted hierarchy from `baselevel` into account. That is, if
+ both `toc_depth` and `baselevel` are `3`, then only the highest level
+ will be present in the table. If you set `baselevel` to `3` and
+ `toc_depth` to `"2-6"`, the *first* headline will be `<h3>` and so still
+ included in the Table of Contents. To exclude this first level, you
+ have to set `toc_depth` to `"4-6"`.
+
+A trivial example:
+
+```python
+markdown.markdown(some_text, extensions=['toc'])
+```
diff --git a/docs/extensions/wikilinks.md b/docs/extensions/wikilinks.md
new file mode 100644
index 0000000..cd355f7
--- /dev/null
+++ b/docs/extensions/wikilinks.md
@@ -0,0 +1,154 @@
+title: WikiLinks Extension
+
+# WikiLinks
+
+## Summary
+
+The WikiLinks extension adds support for [WikiLinks][]. Specifically, any
+``[[bracketed]]`` word is converted to a link.
+
+This extension is included in the standard Markdown library.
+
+[WikiLinks]: https://en.wikipedia.org/wiki/Wikilink
+
+## Syntax
+
+A ``[[bracketed]]`` word is any combination of upper or lower case letters,
+number, dashes, underscores and spaces surrounded by double brackets. Therefore
+
+```md
+[[Bracketed]]
+```
+
+would produce the following HTML:
+
+```html
+<a href="/Bracketed/" class="wikilink">Bracketed</a>
+```
+
+Note that WikiLinks are automatically assigned `class="wikilink"` making it
+easy to style WikiLinks differently from other links on a page if one so
+desires. See below for ways to alter the class.
+
+Also note that when a space is used, the space is converted to an underscore in
+the link but left as-is in the label. Perhaps an example would illustrate this
+best:
+
+```md
+[[Wiki Link]]
+```
+
+becomes
+
+```html
+<a href="/Wiki_Link/" class="wikilink">Wiki Link</a>
+```
+
+## Usage
+
+See [Extensions](index.md) for general extension usage. Use `wikilinks` as the
+name of the extension.
+
+See the [Library Reference](../reference.md#extensions) for information about
+configuring extensions.
+
+The default behavior is to point each link to the document root of the current
+domain and close with a trailing slash. Additionally, each link is assigned to
+the HTML class `wikilink`.
+
+The following options are provided to change the default behavior:
+
+* **`base_url`**: String to append to beginning of URL.
+
+ Default: `'/'`
+
+* **`end_url`**: String to append to end of URL.
+
+ Default: `'/'`
+
+* **`html_class`**: CSS class. Leave blank for none.
+
+ Default: `'wikilink'`
+
+* **`build_url`**: Callable which formats the URL from its parts.
+
+A trivial example:
+
+```python
+markdown.markdown(some_text, extensions=['wikilinks'])
+```
+
+### Examples
+
+For an example, let us suppose links should always point to the sub-directory
+`/wiki/` and end with `.html`
+
+```pycon
+>>> from markdown.extensions.wikilinks import WikiLinkExtension
+>>> html = markdown.markdown(text,
+... extensions=[WikiLinkExtension(base_url='/wiki/', end_url='.html')]
+... )
+```
+
+The above would result in the following link for `[[WikiLink]]`.
+
+```html
+<a href="/wiki/WikiLink.html" class="wikilink">WikiLink</a>
+```
+
+If you want to do more that just alter the base and/or end of the URL, you
+could also pass in a callable which must accept three arguments (``label``,
+``base``, and ``end``). The callable must return the URL in it's entirety.
+
+```pycon
+>>> def my_url_builder(label, base, end):
+... # do stuff
+... return url
+...
+>>> html = markdown.markdown(text,
+... extensions=[WikiLinkExtension(build_url=my_url_builder)],
+... )
+```
+
+The option is also provided to change or remove the class attribute.
+
+```pycon
+>>> html = markdown.markdown(text,
+... extensions=[WikiLinkExtension(html_class='myclass')]
+... )
+```
+
+Would cause all WikiLinks to be assigned to the class `myclass`.
+
+```html
+<a href="/WikiLink/" class="myclass">WikiLink</a>
+```
+
+## Using with Meta-Data extension
+
+The WikiLink extension also supports the [Meta-Data](meta_data.md) extension.
+Please see the documentation for that extension for specifics. The supported
+meta-data keywords are:
+
+* `wiki_base_url`
+* `wiki_end_url`
+* `wiki_html_class`
+
+When used, the meta-data will override the settings provided through the
+`extension_configs` interface.
+
+This document:
+
+```md
+wiki_base_url: http://example.com/
+wiki_end_url: .html
+wiki_html_class:
+
+A [[WikiLink]] in the first paragraph.
+```
+
+would result in the following output (notice the blank `wiki_html_class`):
+
+```html
+<p>A <a href="http://example.com/WikiLink.html">WikiLink</a> in the first paragraph.</p>
+```
diff --git a/docs/favicon.ico b/docs/favicon.ico
new file mode 100644
index 0000000..c9efc58
--- /dev/null
+++ b/docs/favicon.ico
Binary files differ
diff --git a/docs/index.md b/docs/index.md
new file mode 100644
index 0000000..0388070
--- /dev/null
+++ b/docs/index.md
@@ -0,0 +1,112 @@
+title: Python-Markdown
+
+Python-Markdown
+===============
+
+This is a Python implementation of John Gruber's
+[Markdown](https://daringfireball.net/projects/markdown/).
+It is almost completely compliant with the reference implementation,
+though there are a few very minor [differences](#differences). See John's
+[Syntax Documentation](https://daringfireball.net/projects/markdown/syntax)
+for the syntax rules.
+
+To get started, see the [installation instructions](install.md), the [library
+reference](reference.md), and the [command line interface](cli.md).
+
+Goals
+-----
+
+The Python-Markdown project is developed with the following goals in mind:
+
+* Maintain a Python library (with an optional CLI wrapper) suited to use in web
+ server environments (never raise an exception, never write to stdout, etc.) as
+ an implementation of the markdown parser that follows the
+ [syntax rules](https://daringfireball.net/projects/markdown/syntax) and the
+ behavior of the original (markdown.pl) implementation as reasonably as
+ possible (see [differences](#differences) for a few exceptions).
+
+* Provide an [Extension API](extensions/api.md) which makes it possible
+ to change and/or extend the behavior of the parser.
+
+Features
+--------
+
+In addition to the basic markdown syntax, Python-Markdown supports the following
+features:
+
+* __International Input__
+
+ Python-Markdown will accept [input](reference.md#text) in any language
+ supported by Unicode including bi-directional text. In fact the test suite
+ includes documents written in Russian and Arabic.
+
+* __Extensions__
+
+ Various [extensions](extensions/index.md) are provided (including
+ [extra](extensions/extra.md)) to change and/or extend the base syntax.
+ Additionally, a public [Extension API](extensions/api.md) is available
+ to write your own extensions.
+
+* __Output Formats__
+
+ Python-Markdown can output documents with either HTML or XHTML style tags.
+ See the [Library Reference](reference.md#output_format) for details.
+
+* __Command Line Interface__
+
+ In addition to being a Python Library, a
+ [command line script](cli.md) is available for your convenience.
+
+Differences
+-----------
+
+While Python-Markdown strives to fully implement markdown as described in the
+[syntax rules](https://daringfireball.net/projects/markdown/syntax), the rules
+can be interpreted in different ways and different implementations
+occasionally vary in their behavior (see the
+[Babelmark FAQ](https://johnmacfarlane.net/babelmark2/faq.html#what-are-some-examples-of-interesting-divergences-between-implementations)
+for some examples). Known and intentional differences found in Python-Markdown
+are summarized below:
+
+* __Middle-Word Emphasis__
+
+ Python-Markdown defaults to ignoring middle-word emphasis (and strong
+ emphasis). In other words, `some_long_filename.txt` will not become
+ `some<em>long</em>filename.txt`. This can be switched off if desired. See
+ the [Legacy EM Extension](extensions/legacy_em.md) for details.
+
+* __Indentation/Tab Length__
+
+ The [syntax rules](https://daringfireball.net/projects/markdown/syntax#list)
+ clearly state that when a list item consists of multiple paragraphs, "each
+ subsequent paragraph in a list item **must** be indented by either 4 spaces
+ or one tab" (emphasis added). However, many implementations do not enforce
+ this rule and allow less than 4 spaces of indentation. The implementers of
+ Python-Markdown consider it a bug to not enforce this rule.
+
+ This applies to any block level elements nested in a list, including
+ paragraphs, sub-lists, blockquotes, code blocks, etc. They **must** always
+ be indented by at least four spaces (or one tab) for each level of nesting.
+
+ In the event that one would prefer different behavior,
+ [tab_length](reference.md#tab_length) can be set to whatever length is
+ desired. Be warned however, as this will affect indentation for all aspects
+ of the syntax (including root level code blocks). Alternatively, a
+ [third party extension] may offer a solution that meets your needs.
+
+* __Consecutive Lists__
+
+ While the syntax rules are not clear on this, many implementations (including
+ the original) do not end one list and start a second list when the list marker
+ (asterisks, pluses, hyphens, and numbers) changes. For consistency,
+ Python-Markdown maintains the same behavior with no plans to change in the
+ foreseeable future. That said, the [Sane List Extension](extensions/sane_lists.md)
+ is available to provide a less surprising behavior.
+
+Support
+-------
+
+You may report bugs, ask for help, and discuss various other issues on the [bug tracker][].
+
+[third party extension]: https://github.com/Python-Markdown/markdown/wiki/Third-Party-Extensions
+[bug tracker]: https://github.com/Python-Markdown/markdown/issues
diff --git a/docs/install.md b/docs/install.md
new file mode 100644
index 0000000..25530d6
--- /dev/null
+++ b/docs/install.md
@@ -0,0 +1,32 @@
+title: Installation
+
+# Installing Python-Markdown
+
+## The Easy Way
+
+The easiest way to install Python-Markdown is simply to type the
+following command from the command line:
+
+```bash
+pip install markdown
+```
+
+That's it! You're ready to [use](reference.md) Python-Markdown. Enjoy!
+
+For more detailed instructions on installing Python packages, see the
+[Installing Packages] tutorial in the [Python Packaging User Guide].
+
+[Installing Packages]: https://packaging.python.org/tutorials/installing-packages/
+[Python Packaging User Guide]: https://packaging.python.org/
+
+## Using the Git Repository {: #git }
+
+If you're the type that likes to live on the edge, you may want to keep up with
+the latest additions and bug fixes in the repository between releases.
+Python-Markdown is maintained in a Git repository on GitHub.com. To
+get a copy of Python-Markdown from the repository do the following from the
+command line:
+
+```bash
+pip install git+https://github.com/Python-Markdown/markdown.git
+```
diff --git a/docs/py.png b/docs/py.png
new file mode 100644
index 0000000..93e4a02
--- /dev/null
+++ b/docs/py.png
Binary files differ
diff --git a/docs/reference.md b/docs/reference.md
new file mode 100644
index 0000000..8153ebe
--- /dev/null
+++ b/docs/reference.md
@@ -0,0 +1,269 @@
+title: Library Reference
+
+# Using Markdown as a Python Library
+
+First and foremost, Python-Markdown is intended to be a python library module
+used by various projects to convert Markdown syntax into HTML.
+
+## The Basics
+
+To use markdown as a module:
+
+```python
+import markdown
+html = markdown.markdown(your_text_string)
+```
+
+## The Details
+
+Python-Markdown provides two public functions ([`markdown.markdown`](#markdown)
+and [`markdown.markdownFromFile`](#markdownFromFile)) both of which wrap the
+public class [`markdown.Markdown`](#Markdown). If you're processing one
+document at a time, these functions will serve your needs. However, if you need
+to process multiple documents, it may be advantageous to create a single
+instance of the `markdown.Markdown` class and pass multiple documents through
+it. If you do use a single instance though, make sure to call the `reset`
+method appropriately ([see below](#convert)).
+
+### markdown.markdown(text [, **kwargs]) {: #markdown data-toc-label='markdown.markdown' }
+
+The following options are available on the `markdown.markdown` function:
+
+__text__{: #text }
+
+: The source Unicode string. (required)
+
+ !!! note "Important"
+ Python-Markdown expects a **Unicode** string as input (some simple ASCII binary strings *may* work only by
+ coincidence) and returns output as a Unicode string. Do not pass binary strings to it! If your input is
+ encoded, (e.g. as UTF-8), it is your responsibility to decode it. For example:
+
+ :::python
+ with open("some_file.txt", "r", encoding="utf-8") as input_file:
+ text = input_file.read()
+ html = markdown.markdown(text)
+
+ If you want to write the output to disk, you *must* encode it yourself:
+
+ :::python
+ with open("some_file.html", "w", encoding="utf-8", errors="xmlcharrefreplace") as output_file:
+ output_file.write(html)
+
+__extensions__{: #extensions }
+
+: A list of extensions.
+
+ Python-Markdown provides an [API](extensions/api.md) for third parties to
+ write extensions to the parser adding their own additions or changes to the
+ syntax. A few commonly used extensions are shipped with the markdown
+ library. See the [extension documentation](extensions/index.md) for a
+ list of available extensions.
+
+ The list of extensions may contain instances of extensions and/or strings
+ of extension names.
+
+ :::python
+ extensions=[MyExtClass(), 'myext', 'path.to.my.ext:MyExtClass']
+
+ !!! note
+ The preferred method is to pass in an instance of an extension. Strings
+ should only be used when it is impossible to import the Extension Class
+ directly (from the command line or in a template).
+
+ When passing in extension instances, each class instance must be a subclass
+ of `markdown.extensions.Extension` and any configuration options should be
+ defined when initiating the class instance rather than using the
+ [`extension_configs`](#extension_configs) keyword. For example:
+
+ :::python
+ from markdown.extensions import Extension
+ class MyExtClass(Extension):
+ # define your extension here...
+
+ markdown.markdown(text, extensions=[MyExtClass(option='value')])
+
+ If an extension name is provided as a string, the string must either be the
+ registered entry point of any installed extension or the importable path
+ using Python's dot notation.
+
+ See the documentation specific to an extension for the string name assigned
+ to an extension as an entry point. Simply include the defined name as
+ a string in the list of extensions. For example, if an extension has the
+ name `myext` assigned to it and the extension is properly installed, then
+ do the following:
+
+ :::python
+ markdown.markdown(text, extensions=['myext'])
+
+ If an extension does not have a registered entry point, Python's dot
+ notation may be used instead. The extension must be installed as a
+ Python module on your PYTHONPATH. Generally, a class should be specified in
+ the name. The class must be at the end of the name and be separated by a
+ colon from the module.
+
+ Therefore, if you were to import the class like this:
+
+ :::python
+ from path.to.module import MyExtClass
+
+ Then load the extension as follows:
+
+ :::python
+ markdown.markdown(text, extensions=['path.to.module:MyExtClass'])
+
+ If only one extension is defined within a module and the module includes a
+ `makeExtension` function which returns an instance of the extension, then
+ the class name is not necessary. For example, in that case one could do
+ `extensions=['path.to.module']`. Check the documentation for a specific
+ extension to determine if it supports this feature.
+
+ When loading an extension by name (as a string), you can only pass in
+ configuration settings to the extension by using the
+ [`extension_configs`](#extension_configs) keyword.
+
+ !!! seealso "See Also"
+ See the documentation of the [Extension API](extensions/api.md) for
+ assistance in creating extensions.
+
+__extension_configs__{: #extension_configs }
+
+: A dictionary of configuration settings for extensions.
+
+ Any configuration settings will only be passed to extensions loaded by name
+ (as a string). When loading extensions as class instances, pass the
+ configuration settings directly to the class when initializing it.
+
+ !!! Note
+ The preferred method is to pass in an instance of an extension, which
+ does not require use of the `extension_configs` keyword at all.
+ See the [extensions](#extensions) keyword for details.
+
+ The dictionary of configuration settings must be in the following format:
+
+ :::python
+ extension_configs = {
+ 'extension_name_1': {
+ 'option_1': 'value_1',
+ 'option_2': 'value_2'
+ },
+ 'extension_name_2': {
+ 'option_1': 'value_1'
+ }
+ }
+
+ When specifying the extension name, be sure to use the exact same
+ string as is used in the [extensions](#extensions) keyword to load the
+ extension. Otherwise, the configuration settings will not be applied to
+ the extension. In other words, you cannot use the entry point in on
+ place and Python dot notation in the other. While both may be valid for
+ a given extension, they will not be recognized as being the same
+ extension by Markdown.
+
+ See the documentation specific to the extension you are using for help in
+ specifying configuration settings for that extension.
+
+__output_format__{: #output_format }:
+
+: Format of output.
+
+ Supported formats are:
+
+ * `"xhtml"`: Outputs XHTML style tags. **Default**.
+ * `"html5"`: Outputs HTML style tags.
+
+ The values can be in either lowercase or uppercase.
+
+__tab_length__{: #tab_length }:
+
+: Length of tabs in the source. Default: 4
+
+### `markdown.markdownFromFile (**kwargs)` {: #markdownFromFile data-toc-label='markdown.markdownFromFile' }
+
+With a few exceptions, `markdown.markdownFromFile` accepts the same options as
+`markdown.markdown`. It does **not** accept a `text` (or Unicode) string.
+Instead, it accepts the following required options:
+
+__input__{: #input } (required)
+
+: The source text file.
+
+ `input` may be set to one of three options:
+
+ * a string which contains a path to a readable file on the file system,
+ * a readable file-like object,
+ * or `None` (default) which will read from `stdin`.
+
+__output__{: #output }
+
+: The target which output is written to.
+
+ `output` may be set to one of three options:
+
+ * a string which contains a path to a writable file on the file system,
+ * a writable file-like object,
+ * or `None` (default) which will write to `stdout`.
+
+__encoding__{: #encoding }
+
+: The encoding of the source text file.
+
+ Defaults to `"utf-8"`. The same encoding will always be used for input and output.
+ The `xmlcharrefreplace` error handler is used when encoding the output.
+
+ !!! Note
+ This is the only place that decoding and encoding of Unicode
+ takes place in Python-Markdown. If this rather naive solution does not
+ meet your specific needs, it is suggested that you write your own code
+ to handle your encoding/decoding needs.
+
+### markdown.Markdown([**kwargs]) {: #Markdown data-toc-label='markdown.Markdown' }
+
+The same options are available when initializing the `markdown.Markdown` class
+as on the [`markdown.markdown`](#markdown) function, except that the class does
+**not** accept a source text string on initialization. Rather, the source text
+string must be passed to one of two instance methods.
+
+!!! warning
+
+ Instances of the `markdown.Markdown` class are only thread safe within
+ the thread they were created in. A single instance should not be accessed
+ from multiple threads.
+
+#### Markdown.convert(source) {: #convert data-toc-label='Markdown.convert' }
+
+The `source` text must meet the same requirements as the [`text`](#text)
+argument of the [`markdown.markdown`](#markdown) function.
+
+You should also use this method if you want to process multiple strings
+without creating a new instance of the class for each string.
+
+```python
+md = markdown.Markdown()
+html1 = md.convert(text1)
+html2 = md.convert(text2)
+```
+
+Depending on which options and/or extensions are being used, the parser may
+need its state reset between each call to `convert`.
+
+```python
+html1 = md.convert(text1)
+md.reset()
+html2 = md.convert(text2)
+```
+
+To make this easier, you can also chain calls to `reset` together:
+
+```python
+html3 = md.reset().convert(text3)
+```
+
+#### Markdown.convertFile(**kwargs) {: #convertFile data-toc-label='Markdown.convertFile' }
+
+The arguments of this method are identical to the arguments of the same
+name on the `markdown.markdownFromFile` function ([`input`](#input),
+[`output`](#output), and [`encoding`](#encoding)). As with the
+[`convert`](#convert) method, this method should be used to
+process multiple files without creating a new instance of the class for
+each document. State may need to be `reset` between each call to
+`convertFile` as is the case with `convert`.
diff --git a/docs/release-2.0.1.txt b/docs/release-2.0.1.txt
deleted file mode 100644
index e5946b2..0000000
--- a/docs/release-2.0.1.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-Python-Markdown 2.0.1 Release Notes
-===================================
-
-Python-Markdown 2.0.1 is a bug-fix release. No new features have been added.
-Most notably, various issues with the command line script have been fixed.
-There have also been a few fixes for minor parsing bugs in some edge cases.
-For a full list of changes, see the git log.
-
-Backwards-incompatible Changes
-------------------------------
-
-Due to various complications in how Python handles command line scripts in
-differance systems and with differant installation tools, we were forced to
-rename the commandline script to ``markdown`` (no ".py"). A matching batch
-script will get installed on Windows. Any shell scripts which call
-``markdown.py`` will need to be altered to call ``markdown`` instead.
diff --git a/docs/release-2.0.2.txt b/docs/release-2.0.2.txt
deleted file mode 100644
index 8ae9a3d..0000000
--- a/docs/release-2.0.2.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-Python-Markdown 2.0.2 Release Notes
-===================================
-
-Python-Markdown 2.0.2 is a bug-fix release. No new features have been added.
-Most notably, the setup script has been updated to include a dependency on
-ElementTree on older versions of Python (< 2.5). There have also been a few
-fixes for minor parsing bugs in some edge cases. For a full list of changes,
-see the git log.
-
diff --git a/docs/test_tools.md b/docs/test_tools.md
new file mode 100644
index 0000000..f3ed4e5
--- /dev/null
+++ b/docs/test_tools.md
@@ -0,0 +1,178 @@
+title: Test Tools
+
+# Test Tools
+
+Python-Markdown provides some testing tools which simplify testing actual
+Markdown output against expected output. The tools are built on the Python
+standard library [`unittest`][unittest]. Therefore, no additional libraries are
+required. While Python-Markdown uses the tools for its own tests, they were
+designed and built so that third party extensions could use them as well.
+Therefore, the tools are importable from `markdown.test_tools`.
+
+The test tools include two different `unittest.TestCase` subclasses:
+`markdown.test_tools.TestCase` and `markdown.test_tools.LegacyTestCase`.
+
+## markdown.test_tools.TestCase
+
+The `markdown.test_tools.TestCase` class is a `unittest.TestCase` subclass with
+a few additional helpers to make testing Markdown output easier.
+
+Properties
+: `default_kwargs`: A `dict` of keywords to pass to Markdown for each
+test. The defaults can be overridden on individual tests.
+
+Methods
+: `assertMarkdownRenders`: accepts the source text, the expected output, an optional
+ dictionary of `expected_attrs`, and any keywords to pass to Markdown. The
+ `default_kwargs` defined on the class are used except where overridden by
+ keyword arguments. The output and expected output are passed to
+ `TestCase.assertMultiLineEqual`. An `AssertionError` is raised with a diff
+ if the actual output does not equal the expected output. The optional
+ keyword `expected_attrs` accepts a dictionary of attribute names as keys with
+ expected values. Each value is checked against the attribute of that
+ name on the instance of the `Markdown` class using `TestCase.assertEqual`. An
+ `AssertionError` is raised if any value does not match the expected value.
+
+: `dedent`: Dedent triple-quoted strings.
+
+In all other respects, `markdown.test_tools.TestCase` behaves as
+`unittest.TestCase`. In fact, `assertMarkdownRenders` tests could be mixed with
+other `unittest` style tests within the same test class.
+
+An example Markdown test might look like this:
+
+```python
+from markdown.test_tools import TestCase
+
+class TestHr(TestCase):
+ def test_hr_before_paragraph(self):
+ self.assertMarkdownRenders(
+ # The Markdown source text used as input
+ self.dedent(
+ """
+ ***
+ An HR followed by a paragraph with no blank line.
+ """
+ ),
+ # The expected HTML output
+ self.dedent(
+ """
+ <hr>
+ <p>An HR followed by a paragraph with no blank line.</p>
+ """
+ ),
+ # Other keyword arguments to pass to `markdown.markdown`
+ output_format='html'
+ )
+```
+
+## markdown.test_tools.LegacyTestCase
+
+In the past Python-Markdown exclusively used file-based tests. Many of those
+tests still exist in Python-Markdown's test suite, including the test files from
+the [reference implementation][perl] (`markdown.pl`) and [PHP Markdown][PHP].
+Each test consists of a matching pair of text and HTML files. The text file
+contains a snippet of Markdown source text formatted for a specific syntax
+feature and the HTML file contains the expected HTML output of that snippet.
+When the test suite is run, each text file is run through Markdown and the
+output is compared with the HTML file as a separate unit test. When a test
+fails, the error report includes a diff of the expected output compared to the
+actual output to easily identify any problems.
+
+A separate `markdown.test_tools.LegacyTestCase` subclass must be created for
+each directory of test files. Various properties can be defined within the
+subclass to point to a directory of text-based test files and define various
+behaviors/defaults for those tests. The following properties are supported:
+
+* `location`: A path to the directory of test files. An absolute path is
+ preferred.
+* `exclude`: A list of tests to skip. Each test name should comprise of a
+ file name without an extension.
+* `normalize`: A boolean value indicating if the HTML should be normalized.
+ Default: `False`. Note: Normalization of HTML requires that [PyTidyLib] be
+ installed on the system. If PyTidyLib is not installed and `normalize` is set
+ to `True`, then the test will be skipped, regardless of any other settings.
+* `input_ext`: A string containing the file extension of input files.
+ Default: `.txt`.
+* `output_ext`: A string containing the file extension of expected output files.
+ Default: `html`.
+* `default_kwargs`: A `markdown.test_tools.Kwargs` instance which stores the
+ default set of keyword arguments for all test files in the directory.
+
+In addition, properties can be defined for each individual set of test files
+within the directory. The property should be given the name of the file without
+the file extension. Any spaces and dashes in the file name should be replaced
+with underscores. The value of the property should be a
+`markdown.test_tools.Kwargs` instance which contains the keyword arguments that
+should be passed to `markdown.markdown` for that test file. The keyword
+arguments will "update" the `default_kwargs`.
+
+When the class instance is created during a test run, it will walk the given
+directory and create a separate unit test for each set of test files using the
+naming scheme: `test_filename`. One unit test will be run for each set of input
+and output files.
+
+The definition of an example set of tests might look like this:
+
+```python
+from markdown.test_tools import LegacyTestCase, Kwargs
+import os
+
+# Get location of this file and use to find text file dirs.
+parent_test_dir = os.path.abspath(os.path.dirname(__file__))
+
+
+class TestFoo(LegacyTestCase):
+ # Define location of text file directory. In this case, the directory is
+ # named "foo" and is in the same parent directory as this file.
+ location = os.path.join(parent_test_dir, 'foo')
+ # Define default keyword arguments. In this case, unless specified
+ # differently, all tests should use the output format "html".
+ default_kwargs = Kwargs(output_format='html')
+
+ # The "xhtml" test should override the output format and use "xhtml".
+ xhtml = Kwargs(output_format='xhtml')
+
+ # The "toc" test should use the "toc" extension with a custom permalink
+ # setting.
+ toc = Kwargs(
+ extensions=['markdown.extensions.toc'],
+ extension_configs={'markdown.extensions.toc': {'permalink': "[link]"}}
+ )
+```
+
+Note that in the above example, the text file directory may contain many more
+text-based test files than `xhtml` (`xhtml.txt` and `xhtml.html`) and `toc`
+(`toc.txt` and `toc.html`). As long as each set of files exists as a pair, a
+test will be created and run for each of them. Only the `xhtml` and `toc` tests
+needed to be specifically identified as they had specific, non-default settings
+which needed to be defined.
+
+## Running Python-Markdown's Tests
+
+As all of the tests for the `markdown` library are unit tests, standard
+`unittest` methods of calling tests can be used. For example, to run all of
+Python-Markdown's tests, from the root of the git repository, run the following
+command:
+
+```sh
+python -m unittest discover tests
+```
+
+That simple command will search everything in the `tests` directory and it's
+sub-directories and run all `unittest` tests that it finds, including
+`unittest.TestCase`, `markdown.test_tools.TestCase`, and
+`markdown.test_tools.LegacyTestCase` subclasses. Normal [unittest] discovery
+rules apply.
+
+!!! seealso "See Also"
+
+ See the [Contributing Guide] for instructions on setting up a
+ [development environment] for running the tests.
+
+[unittest]: https://docs.python.org/3/library/unittest.html
+[Perl]: https://daringfireball.net/projects/markdown/
+[PHP]: http://michelf.com/projects/php-markdown/
+[PyTidyLib]: http://countergram.github.io/pytidylib/
+[Contributing Guide]: contributing.md
+[development environment]: contributing.md#development-environment
diff --git a/docs/using_as_module.txt b/docs/using_as_module.txt
deleted file mode 100644
index 130d0a7..0000000
--- a/docs/using_as_module.txt
+++ /dev/null
@@ -1,150 +0,0 @@
-Using Markdown as Python Library
-================================
-
-First and foremost, Python-Markdown is intended to be a python library module
-used by various projects to convert Markdown syntax into HTML.
-
-The Basics
-----------
-
-To use markdown as a module:
-
- import markdown
- html = markdown.markdown(your_text_string)
-
-Encoded Text
-------------
-
-Note that ``markdown()`` expects **Unicode** as input (although a simple ASCII
-string should work) and returns output as Unicode. Do not pass encoded strings to it!
-If your input is encoded, e.g. as UTF-8, it is your responsibility to decode
-it. E.g.:
-
- input_file = codecs.open("some_file.txt", mode="r", encoding="utf-8")
- text = input_file.read()
- html = markdown.markdown(text, extensions)
-
-If you later want to write it to disk, you should encode it yourself:
-
- output_file = codecs.open("some_file.html", "w", encoding="utf-8")
- output_file.write(html)
-
-More Options
-------------
-
-If you want to pass more options, you can create an instance of the ``Markdown``
-class yourself and then use ``convert()`` to generate HTML:
-
- import markdown
- md = markdown.Markdown(
- extensions=['footnotes'],
- extension_configs= {'footnotes' : ('PLACE_MARKER','~~~~~~~~')},
- safe_mode=True,
- output_format='html4'
- )
- return md.convert(some_text)
-
-You should also use this method if you want to process multiple strings:
-
- md = markdown.Markdown()
- html1 = md.convert(text1)
- html2 = md.convert(text2)
-
-Working with Files
-------------------
-
-While the Markdown class is only intended to work with Unicode text, some
-encoding/decoding is required for the command line features. These functions
-and methods are only intended to fit the common use case.
-
-The ``Markdown`` class has the method ``convertFile`` which reads in a file and
-writes out to a file-like-object:
-
- md = markdown.Markdown()
- md.convertFile(input="in.txt", output="out.html", encoding="utf-8")
-
-The markdown module also includes a shortcut function ``markdownFromFile`` that
-wraps the above method.
-
- markdown.markdownFromFile(input="in.txt",
- output="out.html",
- extensions=[],
- encoding="utf-8",
- safe=False)
-
-In either case, if the ``output`` keyword is passed a file name (i.e.:
-``output="out.html"``), it will try to write to a file by that name. If
-``output`` is passed a file-like-object (i.e. ``output=StringIO.StringIO()``),
-it will attempt to write out to that object. Finally, if ``output`` is
-set to ``None``, it will write to ``stdout``.
-
-Using Extensions
-----------------
-
-One of the parameters that you can pass is a list of Extensions. Extensions
-must be available as python modules either within the ``markdown.extensions``
-package or on your PYTHONPATH with names starting with `mdx_`, followed by the
-name of the extension. Thus, ``extensions=['footnotes']`` will first look for
-the module ``markdown.extensions.footnotes``, then a module named
-``mdx_footnotes``. See the documentation specific to the extension you are
-using for help in specifying configuration settings for that extension.
-
-Note that some extensions may need their state reset between each call to
-``convert``:
-
- html1 = md.convert(text1)
- md.reset()
- html2 = md.convert(text2)
-
-Safe Mode
----------
-
-If you are using Markdown on a web system which will transform text provided
-by untrusted users, you may want to use the "safe_mode" option which ensures
-that the user's HTML tags are either replaced, removed or escaped. (They can
-still create links using Markdown syntax.)
-
-* To replace HTML, set ``safe_mode="replace"`` (``safe_mode=True`` still works
- for backward compatibility with older versions). The HTML will be replaced
- with the text defined in ``markdown.HTML_REMOVED_TEXT`` which defaults to
- ``[HTML_REMOVED]``. To replace the HTML with something else:
-
- markdown.HTML_REMOVED_TEXT = "--RAW HTML IS NOT ALLOWED--"
- md = markdown.Markdown(safe_mode="replace")
-
- **Note**: You could edit the value of ``HTML_REMOVED_TEXT`` directly in
- markdown/__init__.py but you will need to remember to do so every time you
- upgrade to a newer version of Markdown. Therefore, this is not recommended.
-
-* To remove HTML, set ``safe_mode="remove"``. Any raw HTML will be completely
- stripped from the text with no warning to the author.
-
-* To escape HTML, set ``safe_mode="escape"``. The HTML will be escaped and
- included in the document.
-
-Output Formats
---------------
-
-If Markdown is outputing (X)HTML as part of a web page, most likely you will
-want the output to match the (X)HTML version used by the rest of your page/site.
-Currently, Markdown offers two output formats out of the box; "HTML4" and
-"XHTML1" (the default) . Markdown will also accept the formats "HTML" and
-"XHTML" which currently map to "HTML4" and "XHTML" respectively. However,
-you should use the more explicit keys as the general keys may change in the
-future if it makes sense at that time. The keys can either be lowercase or
-uppercase.
-
-To set the output format do:
-
- html = markdown.markdown(text, output_format='html4')
-
-Or, when using the Markdown class:
-
- md = markdown.Markdown(output_format='html4')
- html = md.convert(text)
-
-Note that the output format is only set once for the class and cannot be
-specified each time ``convert()`` is called. If you really must change the
-output format for the class, you can use the ``set_output_format`` method:
-
- md.set_output_format('xhtml1')
diff --git a/docs/writing_extensions.txt b/docs/writing_extensions.txt
deleted file mode 100644
index 3aad74a..0000000
--- a/docs/writing_extensions.txt
+++ /dev/null
@@ -1,594 +0,0 @@
-Writing Extensions for Python-Markdown
-======================================
-
-Overview
---------
-
-Python-Markdown includes an API for extension writers to plug their own
-custom functionality and/or syntax into the parser. There are preprocessors
-which allow you to alter the source before it is passed to the parser,
-inline patterns which allow you to add, remove or override the syntax of
-any inline elements, and postprocessors which allow munging of the
-output of the parser before it is returned. If you really want to dive in,
-there are also blockprocessors which are part of the core BlockParser.
-
-As the parser builds an [ElementTree][] object which is later rendered
-as Unicode text, there are also some helpers provided to ease manipulation of
-the tree. Each part of the API is discussed in its respective section below.
-Additionaly, reading the source of some [[Available Extensions]] may be helpful.
-For example, the [[Footnotes]] extension uses most of the features documented
-here.
-
-* [Preprocessors][]
-* [InlinePatterns][]
-* [Treeprocessors][]
-* [Postprocessors][]
-* [BlockParser][]
-* [Working with the ElementTree][]
-* [Integrating your code into Markdown][]
- * [extendMarkdown][]
- * [OrderedDict][]
- * [registerExtension][]
- * [Config Settings][]
- * [makeExtension][]
-
-<h3 id="preprocessors">Preprocessors</h3>
-
-Preprocessors munge the source text before it is passed into the Markdown
-core. This is an excellent place to clean up bad syntax, extract things the
-parser may otherwise choke on and perhaps even store it for later retrieval.
-
-Preprocessors should inherit from ``markdown.preprocessors.Preprocessor`` and
-implement a ``run`` method with one argument ``lines``. The ``run`` method of
-each Preprocessor will be passed the entire source text as a list of Unicode
-strings. Each string will contain one line of text. The ``run`` method should
-return either that list, or an altered list of Unicode strings.
-
-A pseudo example:
-
- class MyPreprocessor(markdown.preprocessors.Preprocessor):
- def run(self, lines):
- new_lines = []
- for line in lines:
- m = MYREGEX.match(line)
- if m:
- # do stuff
- else:
- new_lines.append(line)
- return new_lines
-
-<h3 id="inlinepatterns">Inline Patterns</h3>
-
-Inline Patterns implement the inline HTML element syntax for Markdown such as
-``*emphasis*`` or ``[links](http://example.com)``. Pattern objects should be
-instances of classes that inherit from ``markdown.inlinepatterns.Pattern`` or
-one of its children. Each pattern object uses a single regular expression and
-must have the following methods:
-
-* **``getCompiledRegExp()``**:
-
- Returns a compiled regular expression.
-
-* **``handleMatch(m)``**:
-
- Accepts a match object and returns an ElementTree element of a plain
- Unicode string.
-
-Note that any regular expression returned by ``getCompiledRegExp`` must capture
-the whole block. Therefore, they should all start with ``r'^(.*?)'`` and end
-with ``r'(.*?)!'``. When using the default ``getCompiledRegExp()`` method
-provided in the ``Pattern`` you can pass in a regular expression without that
-and ``getCompiledRegExp`` will wrap your expression for you. This means that
-the first group of your match will be ``m.group(2)`` as ``m.group(1)`` will
-match everything before the pattern.
-
-For an example, consider this simplified emphasis pattern:
-
- class EmphasisPattern(markdown.inlinepatterns.Pattern):
- def handleMatch(self, m):
- el = markdown.etree.Element('em')
- el.text = m.group(3)
- return el
-
-As discussed in [Integrating Your Code Into Markdown][], an instance of this
-class will need to be provided to Markdown. That instance would be created
-like so:
-
- # an oversimplified regex
- MYPATTERN = r'\*([^*]+)\*'
- # pass in pattern and create instance
- emphasis = EmphasisPattern(MYPATTERN)
-
-Actually it would not be necessary to create that pattern (and not just because
-a more sophisticated emphasis pattern already exists in Markdown). The fact is,
-that example pattern is not very DRY. A pattern for `**strong**` text would
-be almost identical, with the exception that it would create a 'strong' element.
-Therefore, Markdown provides a number of generic pattern classes that can
-provide some common functionality. For example, both emphasis and strong are
-implemented with separate instances of the ``SimpleTagPettern`` listed below.
-Feel free to use or extend any of these Pattern classes.
-
-**Generic Pattern Classes**
-
-* **``SimpleTextPattern(pattern)``**:
-
- Returns simple text of ``group(2)`` of a ``pattern``.
-
-* **``SimpleTagPattern(pattern, tag)``**:
-
- Returns an element of type "`tag`" with a text attribute of ``group(3)``
- of a ``pattern``. ``tag`` should be a string of a HTML element (i.e.: 'em').
-
-* **``SubstituteTagPattern(pattern, tag)``**:
-
- Returns an element of type "`tag`" with no children or text (i.e.: 'br').
-
-There may be other Pattern classes in the Markdown source that you could extend
-or use as well. Read through the source and see if there is anything you can
-use. You might even get a few ideas for different approaches to your specific
-situation.
-
-<h3 id="treeprocessors">Treeprocessors</h3>
-
-Treeprocessors manipulate an ElemenTree object after it has passed through the
-core BlockParser. This is where additional manipulation of the tree takes
-place. Additionally, the InlineProcessor is a Treeprocessor which steps through
-the tree and runs the InlinePatterns on the text of each Element in the tree.
-
-A Treeprocessor should inherit from ``markdown.treeprocessors.Treeprocessor``,
-over-ride the ``run`` method which takes one argument ``root`` (an Elementree
-object) and returns either that root element or a modified root element.
-
-A pseudo example:
-
- class MyTreeprocessor(markdown.treeprocessors.Treeprocessor):
- def run(self, root):
- #do stuff
- return my_modified_root
-
-For specifics on manipulating the ElementTree, see
-[Working with the ElementTree][] below.
-
-<h3 id="postprocessors">Postprocessors</h3>
-
-Postprocessors manipulate the document after the ElementTree has been
-serialized into a string. Postprocessors should be used to work with the
-text just before output.
-
-A Postprocessor should inherit from ``markdown.postprocessors.Postprocessor``
-and over-ride the ``run`` method which takes one argument ``text`` and returns
-a Unicode string.
-
-Postprocessors are run after the ElementTree has been serialized back into
-Unicode text. For example, this may be an appropriate place to add a table of
-contents to a document:
-
- class TocPostprocessor(markdown.postprocessors.Postprocessor):
- def run(self, text):
- return MYMARKERRE.sub(MyToc, text)
-
-<h3 id="blockparser">BlockParser</h3>
-
-Sometimes, pre/tree/postprocessors and Inline Patterns aren't going to do what
-you need. Perhaps you want a new type of block type that needs to be integrated
-into the core parsing. In such a situation, you can add/change/remove
-functionality of the core ``BlockParser``. The BlockParser is composed of a
-number of Blockproccessors. The BlockParser steps through each block of text
-(split by blank lines) and passes each block to the appropriate Blockprocessor.
-That Blockprocessor parses the block and adds it to the ElementTree. The
-[[Definition Lists]] extension would be a good example of an extension that
-adds/modifies Blockprocessors.
-
-A Blockprocessor should inherit from ``markdown.blockprocessors.BlockProcessor``
-and implement both the ``test`` and ``run`` methods.
-
-The ``test`` method is used by BlockParser to identify the type of block.
-Therefore the ``test`` method must return a boolean value. If the test returns
-``True``, then the BlockParser will call that Blockprocessor's ``run`` method.
-If it returns ``False``, the BlockParser will move on to the next
-BlockProcessor.
-
-The **``test``** method takes two arguments:
-
-* **``parent``**: The parent etree Element of the block. This can be useful as
- the block may need to be treated differently if it is inside a list, for
- example.
-
-* **``block``**: A string of the current block of text. The test may be a
- simple string method (such as ``block.startswith(some_text)``) or a complex
- regular expression.
-
-The **``run``** method takes two arguments:
-
-* **``parent``**: A pointer to the parent etree Element of the block. The run
- method will most likely attach additional nodes to this parent. Note that
- nothing is returned by the method. The Elementree object is altered in place.
-
-* **``blocks``**: A list of all remaining blocks of the document. Your run
- method must remove (pop) the first block from the list (which it altered in
- place - not returned) and parse that block. You may find that a block of text
- legitimately contains multiple block types. Therefore, after processing the
- first type, your processor can insert the remaining text into the beginning
- of the ``blocks`` list for future parsing.
-
-Please be aware that a single block can span multiple text blocks. For example,
-The official Markdown syntax rules state that a blank line does not end a
-Code Block. If the next block of text is also indented, then it is part of
-the previous block. Therefore, the BlockParser was specifically designed to
-address these types of situations. If you notice the ``CodeBlockProcessor``,
-in the core, you will note that it checks the last child of the ``parent``.
-If the last child is a code block (``<pre><code>...</code></pre>``), then it
-appends that block to the previous code block rather than creating a new
-code block.
-
-Each BlockProcessor has the following utility methods available:
-
-* **``lastChild(parent)``**:
-
- Returns the last child of the given etree Element or ``None`` if it had no
- children.
-
-* **``detab(text)``**:
-
- Removes one level of indent (four spaces by default) from the front of each
- line of the given text string.
-
-* **``looseDetab(text, level)``**:
-
- Removes "level" levels of indent (defaults to 1) from the front of each line
- of the given text string. However, this methods allows secondary lines to
- not be indented as does some parts of the Markdown syntax.
-
-Each BlockProcessor also has a pointer to the containing BlockParser instance at
-``self.parser``, which can be used to check or alter the state of the parser.
-The BlockParser tracks it's state in a stack at ``parser.state``. The state
-stack is an instance of the ``State`` class.
-
-**``State``** is a subclass of ``list`` and has the additional methods:
-
-* **``set(state)``**:
-
- Set a new state to string ``state``. The new state is appended to the end
- of the stack.
-
-* **``reset()``**:
-
- Step back one step in the stack. The last state at the end is removed from
- the stack.
-
-* **``isstate(state)``**:
-
- Test that the top (current) level of the stack is of the given string
- ``state``.
-
-Note that to ensure that the state stack doesn't become corrupted, each time a
-state is set for a block, that state *must* be reset when the parser finishes
-parsing that block.
-
-An instance of the **``BlockParser``** is found at ``Markdown.parser``.
-``BlockParser`` has the following methods:
-
-* **``parseDocument(lines)``**:
-
- Given a list of lines, an ElementTree object is returned. This should be
- passed an entire document and is the only method the ``Markdown`` class
- calls directly.
-
-* **``parseChunk(parent, text)``**:
-
- Parses a chunk of markdown text composed of multiple blocks and attaches
- those blocks to the ``parent`` Element. The ``parent`` is altered in place
- and nothing is returned. Extensions would most likely use this method for
- block parsing.
-
-* **``parseBlocks(parent, blocks)``**:
-
- Parses a list of blocks of text and attaches those blocks to the ``parent``
- Element. The ``parent`` is altered in place and nothing is returned. This
- method will generally only be used internally to recursively parse nested
- blocks of text.
-
-While is is not recommended, an extension could subclass or completely replace
-the ``BlockParser``. The new class would have to provide the same public API.
-However, be aware that other extensions may expect the core parser provided
-and will not work with such a drastically different parser.
-
-<h3 id="working_with_et">Working with the ElementTree</h3>
-
-As mentioned, the Markdown parser converts a source document to an
-[ElementTree][] object before serializing that back to Unicode text.
-Markdown has provided some helpers to ease that manipulation within the context
-of the Markdown module.
-
-First, to get access to the ElementTree module import ElementTree from
-``markdown`` rather than importing it directly. This will ensure you are using
-the same version of ElementTree as markdown. The module is named ``etree``
-within Markdown.
-
- from markdown import etree
-
-``markdown.etree`` tries to import ElementTree from any known location, first
-as a standard library module (from ``xml.etree`` in Python 2.5), then as a third
-party package (``Elementree``). In each instance, ``cElementTree`` is tried
-first, then ``ElementTree`` if the faster C implementation is not available on
-your system.
-
-Sometimes you may want text inserted into an element to be parsed by
-[InlinePatterns][]. In such a situation, simply insert the text as you normally
-would and the text will be automatically run through the InlinePatterns.
-However, if you do *not* want some text to be parsed by InlinePatterns,
-then insert the text as an ``AtomicString``.
-
- some_element.text = markdown.AtomicString(some_text)
-
-Here's a basic example which creates an HTML table (note that the contents of
-the second cell (``td2``) will be run through InlinePatterns latter):
-
- table = etree.Element("table")
- table.set("cellpadding", "2") # Set cellpadding to 2
- tr = etree.SubElement(table, "tr") # Add child tr to table
- td1 = etree.SubElement(tr, "td") # Add child td1 to tr
- td1.text = markdown.AtomicString("Cell content") # Add plain text content
- td2 = etree.SubElement(tr, "td") # Add second td to tr
- td2.text = "*text* with **inline** formatting." # Add markup text
- table.tail = "Text after table" # Add text after table
-
-You can also manipulate an existing tree. Consider the following example which
-adds a ``class`` attribute to ``<a>`` elements:
-
- def set_link_class(self, element):
- for child in element:
- if child.tag == "a":
- child.set("class", "myclass") #set the class attribute
- set_link_class(child) # run recursively on children
-
-For more information about working with ElementTree see the ElementTree
-[Documentation](http://effbot.org/zone/element-index.htm)
-([Python Docs](http://docs.python.org/lib/module-xml.etree.ElementTree.html)).
-
-<h3 id="integrating_into_markdown">Integrating Your Code Into Markdown</h3>
-
-Once you have the various pieces of your extension built, you need to tell
-Markdown about them and ensure that they are run in the proper sequence.
-Markdown accepts a ``Extension`` instance for each extension. Therefore, you
-will need to define a class that extends ``markdown.Extension`` and over-rides
-the ``extendMarkdown`` method. Within this class you will manage configuration
-options for your extension and attach the various processors and patterns to
-the Markdown instance.
-
-It is important to note that the order of the various processors and patterns
-matters. For example, if we replace ``http://...`` links with <a> elements, and
-*then* try to deal with inline html, we will end up with a mess. Therefore,
-the various types of processors and patterns are stored within an instance of
-the Markdown class in [OrderedDict][]s. Your ``Extension`` class will need to
-manipulate those OrderedDicts appropriately. You may insert instances of your
-processors and patterns into the appropriate location in an OrderedDict, remove
-a built-in instance, or replace a built-in instance with your own.
-
-<h4 id="extendmarkdown">extendMarkdown</h4>
-
-The ``extendMarkdown`` method of a ``markdown.Extension`` class accepts two
-arguments:
-
-* **``md``**:
-
- A pointer to the instance of the Markdown class. You should use this to
- access the [OrderedDict][]s of processors and patterns. They are found
- under the following attributes:
-
- * ``md.preprocessors``
- * ``md.inlinePatterns``
- * ``md.parser.blockprocessors``
- * ``md.treepreprocessors``
- * ``md.postprocessors``
-
- Some other things you may want to access in the markdown instance are:
-
- * ``md.htmlStash``
- * ``md.output_formats``
- * ``md.set_output_format()``
- * ``md.registerExtension()``
-
-* **``md_globals``**:
-
- Contains all the various global variables within the markdown module.
-
-Of course, with access to those items, theoretically you have the option to
-changing anything through various [monkey_patching][] techniques. However, you
-should be aware that the various undocumented or private parts of markdown
-may change without notice and your monkey_patches may break with a new release.
-Therefore, what you really should be doing is inserting processors and patterns
-into the markdown pipeline. Consider yourself warned.
-
-[monkey_patching]: http://en.wikipedia.org/wiki/Monkey_patch
-
-A simple example:
-
- class MyExtension(markdown.Extension):
- def extendMarkdown(self, md, md_globals):
- # Insert instance of 'mypattern' before 'references' pattern
- md.inlinePatterns.add('mypattern', MyPattern(md), '<references')
-
-<h4 id="ordereddict">OrderedDict</h4>
-
-An OrderedDict is a dictionary like object that retains the order of it's
-items. The items are ordered in the order in which they were appended to
-the OrderedDict. However, an item can also be inserted into the OrderedDict
-in a specific location in relation to the existing items.
-
-Think of OrderedDict as a combination of a list and a dictionary as it has
-methods common to both. For example, you can get and set items using the
-``od[key] = value`` syntax and the methods ``keys()``, ``values()``, and
-``items()`` work as expected with the keys, values and items returned in the
-proper order. At the same time, you can use ``insert()``, ``append()``, and
-``index()`` as you would with a list.
-
-Generally speaking, within Markdown extensions you will be using the special
-helper method ``add()`` to add additional items to an existing OrderedDict.
-
-The ``add()`` method accepts three arguments:
-
-* **``key``**: A string. The key is used for later reference to the item.
-
-* **``value``**: The object instance stored in this item.
-
-* **``location``**: Optional. The items location in relation to other items.
-
- Note that the location can consist of a few different values:
-
- * The special strings ``"_begin"`` and ``"_end"`` insert that item at the
- beginning or end of the OrderedDict respectively.
-
- * A less-than sign (``<``) followed by an existing key (i.e.:
- ``"<somekey"``) inserts that item before the existing key.
-
- * A greater-than sign (``>``) followed by an existing key (i.e.:
- ``">somekey"``) inserts that item after the existing key.
-
-Consider the following example:
-
- >>> import markdown
- >>> od = markdown.OrderedDict()
- >>> od['one'] = 1 # The same as: od.add('one', 1, '_begin')
- >>> od['three'] = 3 # The same as: od.add('three', 3, '>one')
- >>> od['four'] = 4 # The same as: od.add('four', 4, '_end')
- >>> od.items()
- [("one", 1), ("three", 3), ("four", 4)]
-
-Note that when building an OrderedDict in order, the extra features of the
-``add`` method offer no real value and are not necessary. However, when
-manipulating an existing OrderedDict, ``add`` can be very helpful. So let's
-insert another item into the OrderedDict.
-
- >>> od.add('two', 2, '>one') # Insert after 'one'
- >>> od.values()
- [1, 2, 3, 4]
-
-Now let's insert another item.
-
- >>> od.add('twohalf', 2.5, '<three') # Insert before 'three'
- >>> od.keys()
- ["one", "two", "twohalf", "three", "four"]
-
-Note that we also could have set the location of "twohalf" to be 'after two'
-(i.e.: ``'>two'``). However, it's unlikely that you will have control over the
-order in which extensions will be loaded, and this could affect the final
-sorted order of an OrderedDict. For example, suppose an extension adding
-'twohalf' in the above examples was loaded before a separate extension which
-adds 'two'. You may need to take this into consideration when adding your
-extension components to the various markdown OrderedDicts.
-
-Once an OrderedDict is created, the items are available via key:
-
- MyNode = od['somekey']
-
-Therefore, to delete an existing item:
-
- del od['somekey']
-
-To change the value of an existing item (leaving location unchanged):
-
- od['somekey'] = MyNewObject()
-
-To change the location of an existing item:
-
- t.link('somekey', '<otherkey')
-
-<h4 id="registerextension">registerExtension</h4>
-
-Some extensions may need to have their state reset between multiple runs of the
-Markdown class. For example, consider the following use of the [[Footnotes]]
-extension:
-
- md = markdown.Markdown(extensions=['footnotes'])
- html1 = md.convert(text_with_footnote)
- md.reset()
- html2 = md.convert(text_without_footnote)
-
-Without calling ``reset``, the footnote definitions from the first document will
-be inserted into the second document as they are still stored within the class
-instance. Therefore the ``Extension`` class needs to define a ``reset`` method
-that will reset the state of the extension (i.e.: ``self.footnotes = {}``).
-However, as many extensions do not have a need for ``reset``, ``reset`` is only
-called on extensions that are registered.
-
-To register an extension, call ``md.registerExtension`` from within your
-``extendMarkdown`` method:
-
-
- def extendMarkdown(self, md, md_globals):
- md.registerExtension(self)
- # insert processors and patterns here
-
-Then, each time ``reset`` is called on the Markdown instance, the ``reset``
-method of each registered extension will be called as well. You should also
-note that ``reset`` will be called on each registered extension after it is
-initialized the first time. Keep that in mind when over-riding the extension's
-``reset`` method.
-
-<h4 id="configsettings">Config Settings</h4>
-
-If an extension uses any parameters that the user may want to change,
-those parameters should be stored in ``self.config`` of your
-``markdown.Extension`` class in the following format:
-
- self.config = {parameter_1_name : [value1, description1],
- parameter_2_name : [value2, description2] }
-
-When stored this way the config parameters can be over-ridden from the
-command line or at the time Markdown is initiated:
-
- markdown.py -x myextension(SOME_PARAM=2) inputfile.txt > output.txt
-
-Note that parameters should always be assumed to be set to string
-values, and should be converted at run time. For example:
-
- i = int(self.getConfig("SOME_PARAM"))
-
-<h4 id="makeextension">makeExtension</h4>
-
-Each extension should ideally be placed in its own module starting
-with the ``mdx_`` prefix (e.g. ``mdx_footnotes.py``). The module must
-provide a module-level function called ``makeExtension`` that takes
-an optional parameter consisting of a dictionary of configuration over-rides
-and returns an instance of the extension. An example from the footnote
-extension:
-
- def makeExtension(configs=None) :
- return FootnoteExtension(configs=configs)
-
-By following the above example, when Markdown is passed the name of your
-extension as a string (i.e.: ``'footnotes'``), it will automatically import
-the module and call the ``makeExtension`` function initiating your extension.
-
-You may have noted that the extensions packaged with Python-Markdown do not
-use the ``mdx_`` prefix in their module names. This is because they are all
-part of the ``markdown.extensions`` package. Markdown will first try to import
-from ``markdown.extensions.extname`` and upon failure, ``mdx_extname``. If both
-fail, Markdown will continue without the extension.
-
-However, Markdown will also accept an already existing instance of an extension.
-For example:
-
- import markdown
- import myextension
- configs = {...}
- myext = myextension.MyExtension(configs=configs)
- md = markdown.Markdown(extensions=[myext])
-
-This is useful if you need to implement a large number of extensions with more
-than one residing in a module.
-
-[Preprocessors]: #preprocessors
-[InlinePatterns]: #inlinepatterns
-[Treeprocessors]: #treeprocessors
-[Postprocessors]: #postprocessors
-[BlockParser]: #blockparser
-[Working with the ElementTree]: #working_with_et
-[Integrating your code into Markdown]: #integrating_into_markdown
-[extendMarkdown]: #extendmarkdown
-[OrderedDict]: #ordereddict
-[registerExtension]: #registerextension
-[Config Settings]: #configsettings
-[makeExtension]: #makeextension
-[ElementTree]: http://effbot.org/zone/element-index.htm
diff --git a/makefile b/makefile
new file mode 100644
index 0000000..2fbe695
--- /dev/null
+++ b/makefile
@@ -0,0 +1,63 @@
+# Python-Markdown makefile
+
+.PHONY : help
+help:
+ @echo 'Usage: make <subcommand>'
+ @echo ''
+ @echo 'Subcommands:'
+ @echo ' install Install Python-Markdown locally'
+ @echo ' deploy Register and upload a new release to PyPI'
+ @echo ' build Build a source distribution'
+ @echo ' build-win Build a Windows exe distribution'
+ @echo ' docs Build documentation'
+ @echo ' test Run all tests'
+ @echo ' clean Clean up the source directories'
+
+.PHONY : install
+install:
+ python setup.py install
+
+.PHONY : deploy
+deploy:
+ rm -rf build
+ rm -rf dist
+ python setup.py bdist_wheel sdist --formats gztar
+ twine upload dist/*
+
+.PHONY : build
+build:
+ rm -rf build
+ rm -rf dist
+ python setup.py bdist_wheel sdist --formats gztar
+
+.PHONY : build-win
+build-win:
+ python setup.py bdist_wininst
+
+.PHONY : docs
+docs:
+ mkdocs build --clean
+
+.PHONY : test
+test:
+ coverage run --source=markdown -m unittest discover tests
+ coverage report --show-missing
+
+.PHONY : clean
+clean:
+ rm -f MANIFEST
+ rm -f test-output.html
+ rm -f *.pyc
+ rm -f markdown/*.pyc
+ rm -f markdown/extensions/*.pyc
+ rm -f *.bak
+ rm -f markdown/*.bak
+ rm -f markdown/extensions/*.bak
+ rm -f *.swp
+ rm -f markdown/*.swp
+ rm -f markdown/extensions/*.swp
+ rm -rf build
+ rm -rf dist
+ rm -rf tmp
+ rm -rf site
+ # git clean -dfx'
diff --git a/markdown/__init__.py b/markdown/__init__.py
index bd52113..d88b1e9 100644
--- a/markdown/__init__.py
+++ b/markdown/__init__.py
@@ -1,614 +1,28 @@
"""
Python Markdown
-===============
-Python Markdown converts Markdown to HTML and can be used as a library or
-called from the command line.
+A Python implementation of John Gruber's Markdown.
-## Basic usage as a module:
+Documentation: https://python-markdown.github.io/
+GitHub: https://github.com/Python-Markdown/markdown/
+PyPI: https://pypi.org/project/Markdown/
- import markdown
- md = Markdown()
- html = md.convert(your_text_string)
+Started by Manfred Stienstra (http://www.dwerg.net/).
+Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
+Currently maintained by Waylan Limberg (https://github.com/waylan),
+Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
-## Basic use from the command line:
-
- markdown source.txt > destination.html
-
-Run "markdown --help" to see more options.
-
-## Extensions
-
-See <http://www.freewisdom.org/projects/python-markdown/> for more
-information and instructions on how to extend the functionality of
-Python Markdown. Read that before you try modifying this file.
-
-## Authors and License
-
-Started by [Manfred Stienstra](http://www.dwerg.net/). Continued and
-maintained by [Yuri Takhteyev](http://www.freewisdom.org), [Waylan
-Limberg](http://achinghead.com/) and [Artem Yunusov](http://blog.splyer.com).
-
-Contact: markdown@freewisdom.org
-
-Copyright 2007, 2008 The Python Markdown Project (v. 1.7 and later)
-Copyright 200? Django Software Foundation (OrderedDict implementation)
+Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later)
Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
Copyright 2004 Manfred Stienstra (the original version)
-License: BSD (see docs/LICENSE for details).
-"""
-
-version = "2.0.3"
-version_info = (2,0,3, "Final")
-
-import re
-import codecs
-import sys
-import warnings
-import logging
-from logging import DEBUG, INFO, WARN, ERROR, CRITICAL
-
-
-"""
-CONSTANTS
-=============================================================================
-"""
-
-"""
-Constants you might want to modify
------------------------------------------------------------------------------
-"""
-
-# default logging level for command-line use
-COMMAND_LINE_LOGGING_LEVEL = CRITICAL
-TAB_LENGTH = 4 # expand tabs to this many spaces
-ENABLE_ATTRIBUTES = True # @id = xyz -> <... id="xyz">
-SMART_EMPHASIS = True # this_or_that does not become this<i>or</i>that
-DEFAULT_OUTPUT_FORMAT = 'xhtml1' # xhtml or html4 output
-HTML_REMOVED_TEXT = "[HTML_REMOVED]" # text used instead of HTML in safe mode
-BLOCK_LEVEL_ELEMENTS = re.compile("p|div|h[1-6]|blockquote|pre|table|dl|ol|ul"
- "|script|noscript|form|fieldset|iframe|math"
- "|ins|del|hr|hr/|style|li|dt|dd|thead|tbody"
- "|tr|th|td")
-DOC_TAG = "div" # Element used to wrap document - later removed
-
-# Placeholders
-STX = u'\u0002' # Use STX ("Start of text") for start-of-placeholder
-ETX = u'\u0003' # Use ETX ("End of text") for end-of-placeholder
-INLINE_PLACEHOLDER_PREFIX = STX+"klzzwxh:"
-INLINE_PLACEHOLDER = INLINE_PLACEHOLDER_PREFIX + "%s" + ETX
-AMP_SUBSTITUTE = STX+"amp"+ETX
-
-
-"""
-Constants you probably do not need to change
------------------------------------------------------------------------------
-"""
-
-RTL_BIDI_RANGES = ( (u'\u0590', u'\u07FF'),
- # Hebrew (0590-05FF), Arabic (0600-06FF),
- # Syriac (0700-074F), Arabic supplement (0750-077F),
- # Thaana (0780-07BF), Nko (07C0-07FF).
- (u'\u2D30', u'\u2D7F'), # Tifinagh
- )
-
-
-"""
-AUXILIARY GLOBAL FUNCTIONS
-=============================================================================
-"""
-
-
-def message(level, text):
- """ A wrapper method for logging debug messages. """
- logger = logging.getLogger('MARKDOWN')
- if logger.handlers:
- # The logger is configured
- logger.log(level, text)
- if level > WARN:
- sys.exit(0)
- elif level > WARN:
- raise MarkdownException, text
- else:
- warnings.warn(text, MarkdownWarning)
-
-
-def isBlockLevel(tag):
- """Check if the tag is a block level HTML tag."""
- return BLOCK_LEVEL_ELEMENTS.match(tag)
-
-"""
-MISC AUXILIARY CLASSES
-=============================================================================
+License: BSD (see LICENSE.md for details).
"""
-class AtomicString(unicode):
- """A string which should not be further processed."""
- pass
-
-
-class MarkdownException(Exception):
- """ A Markdown Exception. """
- pass
-
-
-class MarkdownWarning(Warning):
- """ A Markdown Warning. """
- pass
-
-
-"""
-OVERALL DESIGN
-=============================================================================
-
-Markdown processing takes place in four steps:
-
-1. A bunch of "preprocessors" munge the input text.
-2. BlockParser() parses the high-level structural elements of the
- pre-processed text into an ElementTree.
-3. A bunch of "treeprocessors" are run against the ElementTree. One such
- treeprocessor runs InlinePatterns against the ElementTree, detecting inline
- markup.
-4. Some post-processors are run against the text after the ElementTree has
- been serialized into text.
-5. The output is written to a string.
-
-Those steps are put together by the Markdown() class.
-
-"""
-
-import preprocessors
-import blockprocessors
-import treeprocessors
-import inlinepatterns
-import postprocessors
-import blockparser
-import etree_loader
-import odict
-
-# Extensions should use "markdown.etree" instead of "etree" (or do `from
-# markdown import etree`). Do not import it by yourself.
-
-etree = etree_loader.importETree()
-
-# Adds the ability to output html4
-import html4
-
-
-class Markdown:
- """Convert Markdown to HTML."""
-
- def __init__(self,
- extensions=[],
- extension_configs={},
- safe_mode = False,
- output_format=DEFAULT_OUTPUT_FORMAT):
- """
- Creates a new Markdown instance.
-
- Keyword arguments:
-
- * extensions: A list of extensions.
- If they are of type string, the module mdx_name.py will be loaded.
- If they are a subclass of markdown.Extension, they will be used
- as-is.
- * extension-configs: Configuration setting for extensions.
- * safe_mode: Disallow raw html. One of "remove", "replace" or "escape".
- * output_format: Format of output. Supported formats are:
- * "xhtml1": Outputs XHTML 1.x. Default.
- * "xhtml": Outputs latest supported version of XHTML (currently XHTML 1.1).
- * "html4": Outputs HTML 4
- * "html": Outputs latest supported version of HTML (currently HTML 4).
- Note that it is suggested that the more specific formats ("xhtml1"
- and "html4") be used as "xhtml" or "html" may change in the future
- if it makes sense at that time.
-
- """
-
- self.safeMode = safe_mode
- self.registeredExtensions = []
- self.docType = ""
- self.stripTopLevelTags = True
-
- # Preprocessors
- self.preprocessors = odict.OrderedDict()
- self.preprocessors["html_block"] = \
- preprocessors.HtmlBlockPreprocessor(self)
- self.preprocessors["reference"] = \
- preprocessors.ReferencePreprocessor(self)
- # footnote preprocessor will be inserted with "<reference"
-
- # Block processors - ran by the parser
- self.parser = blockparser.BlockParser()
- self.parser.blockprocessors['empty'] = \
- blockprocessors.EmptyBlockProcessor(self.parser)
- self.parser.blockprocessors['indent'] = \
- blockprocessors.ListIndentProcessor(self.parser)
- self.parser.blockprocessors['code'] = \
- blockprocessors.CodeBlockProcessor(self.parser)
- self.parser.blockprocessors['hashheader'] = \
- blockprocessors.HashHeaderProcessor(self.parser)
- self.parser.blockprocessors['setextheader'] = \
- blockprocessors.SetextHeaderProcessor(self.parser)
- self.parser.blockprocessors['hr'] = \
- blockprocessors.HRProcessor(self.parser)
- self.parser.blockprocessors['olist'] = \
- blockprocessors.OListProcessor(self.parser)
- self.parser.blockprocessors['ulist'] = \
- blockprocessors.UListProcessor(self.parser)
- self.parser.blockprocessors['quote'] = \
- blockprocessors.BlockQuoteProcessor(self.parser)
- self.parser.blockprocessors['paragraph'] = \
- blockprocessors.ParagraphProcessor(self.parser)
-
-
- #self.prePatterns = []
-
- # Inline patterns - Run on the tree
- self.inlinePatterns = odict.OrderedDict()
- self.inlinePatterns["backtick"] = \
- inlinepatterns.BacktickPattern(inlinepatterns.BACKTICK_RE)
- self.inlinePatterns["escape"] = \
- inlinepatterns.SimpleTextPattern(inlinepatterns.ESCAPE_RE)
- self.inlinePatterns["reference"] = \
- inlinepatterns.ReferencePattern(inlinepatterns.REFERENCE_RE, self)
- self.inlinePatterns["link"] = \
- inlinepatterns.LinkPattern(inlinepatterns.LINK_RE, self)
- self.inlinePatterns["image_link"] = \
- inlinepatterns.ImagePattern(inlinepatterns.IMAGE_LINK_RE, self)
- self.inlinePatterns["image_reference"] = \
- inlinepatterns.ImageReferencePattern(inlinepatterns.IMAGE_REFERENCE_RE, self)
- self.inlinePatterns["autolink"] = \
- inlinepatterns.AutolinkPattern(inlinepatterns.AUTOLINK_RE, self)
- self.inlinePatterns["automail"] = \
- inlinepatterns.AutomailPattern(inlinepatterns.AUTOMAIL_RE, self)
- self.inlinePatterns["linebreak2"] = \
- inlinepatterns.SubstituteTagPattern(inlinepatterns.LINE_BREAK_2_RE, 'br')
- self.inlinePatterns["linebreak"] = \
- inlinepatterns.SubstituteTagPattern(inlinepatterns.LINE_BREAK_RE, 'br')
- self.inlinePatterns["html"] = \
- inlinepatterns.HtmlPattern(inlinepatterns.HTML_RE, self)
- self.inlinePatterns["entity"] = \
- inlinepatterns.HtmlPattern(inlinepatterns.ENTITY_RE, self)
- self.inlinePatterns["not_strong"] = \
- inlinepatterns.SimpleTextPattern(inlinepatterns.NOT_STRONG_RE)
- self.inlinePatterns["strong_em"] = \
- inlinepatterns.DoubleTagPattern(inlinepatterns.STRONG_EM_RE, 'strong,em')
- self.inlinePatterns["strong"] = \
- inlinepatterns.SimpleTagPattern(inlinepatterns.STRONG_RE, 'strong')
- self.inlinePatterns["emphasis"] = \
- inlinepatterns.SimpleTagPattern(inlinepatterns.EMPHASIS_RE, 'em')
- self.inlinePatterns["emphasis2"] = \
- inlinepatterns.SimpleTagPattern(inlinepatterns.EMPHASIS_2_RE, 'em')
- # The order of the handlers matters!!!
-
-
- # Tree processors - run once we have a basic parse.
- self.treeprocessors = odict.OrderedDict()
- self.treeprocessors["inline"] = treeprocessors.InlineProcessor(self)
- self.treeprocessors["prettify"] = \
- treeprocessors.PrettifyTreeprocessor(self)
-
- # Postprocessors - finishing touches.
- self.postprocessors = odict.OrderedDict()
- self.postprocessors["raw_html"] = \
- postprocessors.RawHtmlPostprocessor(self)
- self.postprocessors["amp_substitute"] = \
- postprocessors.AndSubstitutePostprocessor()
- # footnote postprocessor will be inserted with ">amp_substitute"
-
- # Map format keys to serializers
- self.output_formats = {
- 'html' : html4.to_html_string,
- 'html4' : html4.to_html_string,
- 'xhtml' : etree.tostring,
- 'xhtml1': etree.tostring,
- }
-
- self.references = {}
- self.htmlStash = preprocessors.HtmlStash()
- self.registerExtensions(extensions = extensions,
- configs = extension_configs)
- self.set_output_format(output_format)
- self.reset()
-
- def registerExtensions(self, extensions, configs):
- """
- Register extensions with this instance of Markdown.
-
- Keyword aurguments:
-
- * extensions: A list of extensions, which can either
- be strings or objects. See the docstring on Markdown.
- * configs: A dictionary mapping module names to config options.
-
- """
- for ext in extensions:
- if isinstance(ext, basestring):
- ext = load_extension(ext, configs.get(ext, []))
- if isinstance(ext, Extension):
- try:
- ext.extendMarkdown(self, globals())
- except NotImplementedError, e:
- message(ERROR, e)
- else:
- message(ERROR, 'Extension "%s.%s" must be of type: "markdown.Extension".' \
- % (ext.__class__.__module__, ext.__class__.__name__))
-
- def registerExtension(self, extension):
- """ This gets called by the extension """
- self.registeredExtensions.append(extension)
-
- def reset(self):
- """
- Resets all state variables so that we can start with a new text.
- """
- self.htmlStash.reset()
- self.references.clear()
-
- for extension in self.registeredExtensions:
- extension.reset()
-
- def set_output_format(self, format):
- """ Set the output format for the class instance. """
- try:
- self.serializer = self.output_formats[format.lower()]
- except KeyError:
- message(CRITICAL, 'Invalid Output Format: "%s". Use one of %s.' \
- % (format, self.output_formats.keys()))
-
- def convert(self, source):
- """
- Convert markdown to serialized XHTML or HTML.
-
- Keyword arguments:
-
- * source: Source text as a Unicode string.
-
- """
-
- # Fixup the source text
- if not source.strip():
- return u"" # a blank unicode string
- try:
- source = unicode(source)
- except UnicodeDecodeError:
- message(CRITICAL, 'UnicodeDecodeError: Markdown only accepts unicode or ascii input.')
- return u""
-
- source = source.replace(STX, "").replace(ETX, "")
- source = source.replace("\r\n", "\n").replace("\r", "\n") + "\n\n"
- source = re.sub(r'\n\s+\n', '\n\n', source)
- source = source.expandtabs(TAB_LENGTH)
-
- # Split into lines and run the line preprocessors.
- self.lines = source.split("\n")
- for prep in self.preprocessors.values():
- self.lines = prep.run(self.lines)
-
- # Parse the high-level elements.
- root = self.parser.parseDocument(self.lines).getroot()
-
- # Run the tree-processors
- for treeprocessor in self.treeprocessors.values():
- newRoot = treeprocessor.run(root)
- if newRoot:
- root = newRoot
-
- # Serialize _properly_. Strip top-level tags.
- output, length = codecs.utf_8_decode(self.serializer(root, encoding="utf-8"))
- if self.stripTopLevelTags:
- try:
- start = output.index('<%s>'%DOC_TAG)+len(DOC_TAG)+2
- end = output.rindex('</%s>'%DOC_TAG)
- output = output[start:end].strip()
- except ValueError:
- if output.strip().endswith('<%s />'%DOC_TAG):
- # We have an empty document
- output = ''
- else:
- # We have a serious problem
- message(CRITICAL, 'Failed to strip top level tags.')
-
- # Run the text post-processors
- for pp in self.postprocessors.values():
- output = pp.run(output)
-
- return output.strip()
-
- def convertFile(self, input=None, output=None, encoding=None):
- """Converts a markdown file and returns the HTML as a unicode string.
-
- Decodes the file using the provided encoding (defaults to utf-8),
- passes the file content to markdown, and outputs the html to either
- the provided stream or the file with provided name, using the same
- encoding as the source file.
-
- **Note:** This is the only place that decoding and encoding of unicode
- takes place in Python-Markdown. (All other code is unicode-in /
- unicode-out.)
-
- Keyword arguments:
-
- * input: Name of source text file.
- * output: Name of output file. Writes to stdout if `None`.
- * encoding: Encoding of input and output files. Defaults to utf-8.
-
- """
-
- encoding = encoding or "utf-8"
-
- # Read the source
- input_file = codecs.open(input, mode="r", encoding=encoding)
- text = input_file.read()
- input_file.close()
- text = text.lstrip(u'\ufeff') # remove the byte-order mark
-
- # Convert
- html = self.convert(text)
-
- # Write to file or stdout
- if isinstance(output, (str, unicode)):
- output_file = codecs.open(output, "w", encoding=encoding)
- output_file.write(html)
- output_file.close()
- else:
- output.write(html.encode(encoding))
-
-
-"""
-Extensions
------------------------------------------------------------------------------
-"""
-
-class Extension:
- """ Base class for extensions to subclass. """
- def __init__(self, configs = {}):
- """Create an instance of an Extention.
-
- Keyword arguments:
-
- * configs: A dict of configuration setting used by an Extension.
- """
- self.config = configs
-
- def getConfig(self, key):
- """ Return a setting for the given key or an empty string. """
- if key in self.config:
- return self.config[key][0]
- else:
- return ""
-
- def getConfigInfo(self):
- """ Return all config settings as a list of tuples. """
- return [(key, self.config[key][1]) for key in self.config.keys()]
-
- def setConfig(self, key, value):
- """ Set a config setting for `key` with the given `value`. """
- self.config[key][0] = value
-
- def extendMarkdown(self, md, md_globals):
- """
- Add the various proccesors and patterns to the Markdown Instance.
-
- This method must be overriden by every extension.
-
- Keyword arguments:
-
- * md: The Markdown instance.
-
- * md_globals: Global variables in the markdown module namespace.
-
- """
- raise NotImplementedError, 'Extension "%s.%s" must define an "extendMarkdown"' \
- 'method.' % (self.__class__.__module__, self.__class__.__name__)
-
-
-def load_extension(ext_name, configs = []):
- """Load extension by name, then return the module.
-
- The extension name may contain arguments as part of the string in the
- following format: "extname(key1=value1,key2=value2)"
-
- """
-
- # Parse extensions config params (ignore the order)
- configs = dict(configs)
- pos = ext_name.find("(") # find the first "("
- if pos > 0:
- ext_args = ext_name[pos+1:-1]
- ext_name = ext_name[:pos]
- pairs = [x.split("=") for x in ext_args.split(",")]
- configs.update([(x.strip(), y.strip()) for (x, y) in pairs])
-
- # Setup the module names
- ext_module = 'markdown.extensions'
- module_name_new_style = '.'.join([ext_module, ext_name])
- module_name_old_style = '_'.join(['mdx', ext_name])
-
- # Try loading the extention first from one place, then another
- try: # New style (markdown.extensons.<extension>)
- module = __import__(module_name_new_style, {}, {}, [ext_module])
- except ImportError:
- try: # Old style (mdx.<extension>)
- module = __import__(module_name_old_style)
- except ImportError:
- message(WARN, "Failed loading extension '%s' from '%s' or '%s'"
- % (ext_name, module_name_new_style, module_name_old_style))
- # Return None so we don't try to initiate none-existant extension
- return None
-
- # If the module is loaded successfully, we expect it to define a
- # function called makeExtension()
- try:
- return module.makeExtension(configs.items())
- except AttributeError:
- message(CRITICAL, "Failed to initiate extension '%s'" % ext_name)
-
-
-def load_extensions(ext_names):
- """Loads multiple extensions"""
- extensions = []
- for ext_name in ext_names:
- extension = load_extension(ext_name)
- if extension:
- extensions.append(extension)
- return extensions
-
-
-"""
-EXPORTED FUNCTIONS
-=============================================================================
-
-Those are the two functions we really mean to export: markdown() and
-markdownFromFile().
-"""
-
-def markdown(text,
- extensions = [],
- safe_mode = False,
- output_format = DEFAULT_OUTPUT_FORMAT):
- """Convert a markdown string to HTML and return HTML as a unicode string.
-
- This is a shortcut function for `Markdown` class to cover the most
- basic use case. It initializes an instance of Markdown, loads the
- necessary extensions and runs the parser on the given text.
-
- Keyword arguments:
-
- * text: Markdown formatted text as Unicode or ASCII string.
- * extensions: A list of extensions or extension names (may contain config args).
- * safe_mode: Disallow raw html. One of "remove", "replace" or "escape".
- * output_format: Format of output. Supported formats are:
- * "xhtml1": Outputs XHTML 1.x. Default.
- * "xhtml": Outputs latest supported version of XHTML (currently XHTML 1.1).
- * "html4": Outputs HTML 4
- * "html": Outputs latest supported version of HTML (currently HTML 4).
- Note that it is suggested that the more specific formats ("xhtml1"
- and "html4") be used as "xhtml" or "html" may change in the future
- if it makes sense at that time.
-
- Returns: An HTML document as a string.
-
- """
- md = Markdown(extensions=load_extensions(extensions),
- safe_mode=safe_mode,
- output_format=output_format)
- return md.convert(text)
-
-
-def markdownFromFile(input = None,
- output = None,
- extensions = [],
- encoding = None,
- safe_mode = False,
- output_format = DEFAULT_OUTPUT_FORMAT):
- """Read markdown code from a file and write it to a file or a stream."""
- md = Markdown(extensions=load_extensions(extensions),
- safe_mode=safe_mode,
- output_format=output_format)
- md.convertFile(input, output, encoding)
-
+from .core import Markdown, markdown, markdownFromFile
+from .__meta__ import __version__, __version_info__ # noqa
+# For backward compatibility as some extensions expect it...
+from .extensions import Extension # noqa
+__all__ = ['Markdown', 'markdown', 'markdownFromFile']
diff --git a/markdown/__main__.py b/markdown/__main__.py
new file mode 100644
index 0000000..0184008
--- /dev/null
+++ b/markdown/__main__.py
@@ -0,0 +1,151 @@
+"""
+Python Markdown
+
+A Python implementation of John Gruber's Markdown.
+
+Documentation: https://python-markdown.github.io/
+GitHub: https://github.com/Python-Markdown/markdown/
+PyPI: https://pypi.org/project/Markdown/
+
+Started by Manfred Stienstra (http://www.dwerg.net/).
+Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
+Currently maintained by Waylan Limberg (https://github.com/waylan),
+Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
+
+Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see LICENSE.md for details).
+"""
+
+import sys
+import optparse
+import codecs
+import warnings
+import markdown
+try:
+ # We use `unsafe_load` because users may need to pass in actual Python
+ # objects. As this is only available from the CLI, the user has much
+ # worse problems if an attacker can use this as an attach vector.
+ from yaml import unsafe_load as yaml_load
+except ImportError: # pragma: no cover
+ try:
+ # Fall back to PyYAML <5.1
+ from yaml import load as yaml_load
+ except ImportError:
+ # Fall back to JSON
+ from json import load as yaml_load
+
+import logging
+from logging import DEBUG, WARNING, CRITICAL
+
+logger = logging.getLogger('MARKDOWN')
+
+
+def parse_options(args=None, values=None):
+ """
+ Define and parse `optparse` options for command-line usage.
+ """
+ usage = """%prog [options] [INPUTFILE]
+ (STDIN is assumed if no INPUTFILE is given)"""
+ desc = "A Python implementation of John Gruber's Markdown. " \
+ "https://Python-Markdown.github.io/"
+ ver = "%%prog %s" % markdown.__version__
+
+ parser = optparse.OptionParser(usage=usage, description=desc, version=ver)
+ parser.add_option("-f", "--file", dest="filename", default=None,
+ help="Write output to OUTPUT_FILE. Defaults to STDOUT.",
+ metavar="OUTPUT_FILE")
+ parser.add_option("-e", "--encoding", dest="encoding",
+ help="Encoding for input and output files.",)
+ parser.add_option("-o", "--output_format", dest="output_format",
+ default='xhtml', metavar="OUTPUT_FORMAT",
+ help="Use output format 'xhtml' (default) or 'html'.")
+ parser.add_option("-n", "--no_lazy_ol", dest="lazy_ol",
+ action='store_false', default=True,
+ help="Observe number of first item of ordered lists.")
+ parser.add_option("-x", "--extension", action="append", dest="extensions",
+ help="Load extension EXTENSION.", metavar="EXTENSION")
+ parser.add_option("-c", "--extension_configs",
+ dest="configfile", default=None,
+ help="Read extension configurations from CONFIG_FILE. "
+ "CONFIG_FILE must be of JSON or YAML format. YAML "
+ "format requires that a python YAML library be "
+ "installed. The parsed JSON or YAML must result in a "
+ "python dictionary which would be accepted by the "
+ "'extension_configs' keyword on the markdown.Markdown "
+ "class. The extensions must also be loaded with the "
+ "`--extension` option.",
+ metavar="CONFIG_FILE")
+ parser.add_option("-q", "--quiet", default=CRITICAL,
+ action="store_const", const=CRITICAL+10, dest="verbose",
+ help="Suppress all warnings.")
+ parser.add_option("-v", "--verbose",
+ action="store_const", const=WARNING, dest="verbose",
+ help="Print all warnings.")
+ parser.add_option("--noisy",
+ action="store_const", const=DEBUG, dest="verbose",
+ help="Print debug messages.")
+
+ (options, args) = parser.parse_args(args, values)
+
+ if len(args) == 0:
+ input_file = None
+ else:
+ input_file = args[0]
+
+ if not options.extensions:
+ options.extensions = []
+
+ extension_configs = {}
+ if options.configfile:
+ with codecs.open(
+ options.configfile, mode="r", encoding=options.encoding
+ ) as fp:
+ try:
+ extension_configs = yaml_load(fp)
+ except Exception as e:
+ message = "Failed parsing extension config file: %s" % \
+ options.configfile
+ e.args = (message,) + e.args[1:]
+ raise
+
+ opts = {
+ 'input': input_file,
+ 'output': options.filename,
+ 'extensions': options.extensions,
+ 'extension_configs': extension_configs,
+ 'encoding': options.encoding,
+ 'output_format': options.output_format,
+ 'lazy_ol': options.lazy_ol
+ }
+
+ return opts, options.verbose
+
+
+def run(): # pragma: no cover
+ """Run Markdown from the command line."""
+
+ # Parse options and adjust logging level if necessary
+ options, logging_level = parse_options()
+ if not options:
+ sys.exit(2)
+ logger.setLevel(logging_level)
+ console_handler = logging.StreamHandler()
+ logger.addHandler(console_handler)
+ if logging_level <= WARNING:
+ # Ensure deprecation warnings get displayed
+ warnings.filterwarnings('default')
+ logging.captureWarnings(True)
+ warn_logger = logging.getLogger('py.warnings')
+ warn_logger.addHandler(console_handler)
+
+ # Run
+ markdown.markdownFromFile(**options)
+
+
+if __name__ == '__main__': # pragma: no cover
+ # Support running module as a commandline command.
+ # `python -m markdown [options] [args]`.
+ run()
diff --git a/markdown/__meta__.py b/markdown/__meta__.py
new file mode 100644
index 0000000..ccabee5
--- /dev/null
+++ b/markdown/__meta__.py
@@ -0,0 +1,49 @@
+"""
+Python Markdown
+
+A Python implementation of John Gruber's Markdown.
+
+Documentation: https://python-markdown.github.io/
+GitHub: https://github.com/Python-Markdown/markdown/
+PyPI: https://pypi.org/project/Markdown/
+
+Started by Manfred Stienstra (http://www.dwerg.net/).
+Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
+Currently maintained by Waylan Limberg (https://github.com/waylan),
+Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
+
+Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see LICENSE.md for details).
+"""
+
+# __version_info__ format:
+# (major, minor, patch, dev/alpha/beta/rc/final, #)
+# (1, 1, 2, 'dev', 0) => "1.1.2.dev0"
+# (1, 1, 2, 'alpha', 1) => "1.1.2a1"
+# (1, 2, 0, 'beta', 2) => "1.2b2"
+# (1, 2, 0, 'rc', 4) => "1.2rc4"
+# (1, 2, 0, 'final', 0) => "1.2"
+__version_info__ = (3, 4, 1, 'final', 0)
+
+
+def _get_version(version_info):
+ " Returns a PEP 440-compliant version number from version_info. "
+ assert len(version_info) == 5
+ assert version_info[3] in ('dev', 'alpha', 'beta', 'rc', 'final')
+
+ parts = 2 if version_info[2] == 0 else 3
+ v = '.'.join(map(str, version_info[:parts]))
+
+ if version_info[3] == 'dev':
+ v += '.dev' + str(version_info[4])
+ elif version_info[3] != 'final':
+ mapping = {'alpha': 'a', 'beta': 'b', 'rc': 'rc'}
+ v += mapping[version_info[3]] + str(version_info[4])
+
+ return v
+
+
+__version__ = _get_version(__version_info__)
diff --git a/markdown/blockparser.py b/markdown/blockparser.py
index e18b338..b0ca4b1 100644
--- a/markdown/blockparser.py
+++ b/markdown/blockparser.py
@@ -1,16 +1,38 @@
+"""
+Python Markdown
+
+A Python implementation of John Gruber's Markdown.
+
+Documentation: https://python-markdown.github.io/
+GitHub: https://github.com/Python-Markdown/markdown/
+PyPI: https://pypi.org/project/Markdown/
+
+Started by Manfred Stienstra (http://www.dwerg.net/).
+Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
+Currently maintained by Waylan Limberg (https://github.com/waylan),
+Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
+
+Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see LICENSE.md for details).
+"""
+
+import xml.etree.ElementTree as etree
+from . import util
-import markdown
class State(list):
- """ Track the current and nested state of the parser.
-
- This utility class is used to track the state of the BlockParser and
+ """ Track the current and nested state of the parser.
+
+ This utility class is used to track the state of the BlockParser and
support multiple levels if nesting. It's just a simple API wrapped around
a list. Each time a state is set, that state is appended to the end of the
list. Each time a state is reset, that state is removed from the end of
the list.
- Therefore, each time a state is set for a nested block, that state must be
+ Therefore, each time a state is set for a nested block, that state must be
reset when we back out of that level of nesting or the state could be
corrupted.
@@ -34,62 +56,64 @@ class State(list):
else:
return False
+
class BlockParser:
- """ Parse Markdown blocks into an ElementTree object.
-
+ """ Parse Markdown blocks into an ElementTree object.
+
A wrapper class that stitches the various BlockProcessors together,
looping through them and creating an ElementTree object.
"""
- def __init__(self):
- self.blockprocessors = markdown.odict.OrderedDict()
+ def __init__(self, md):
+ self.blockprocessors = util.Registry()
self.state = State()
+ self.md = md
def parseDocument(self, lines):
- """ Parse a markdown document into an ElementTree.
-
- Given a list of lines, an ElementTree object (not just a parent Element)
- is created and the root element is passed to the parser as the parent.
- The ElementTree object is returned.
-
+ """ Parse a markdown document into an ElementTree.
+
+ Given a list of lines, an ElementTree object (not just a parent
+ Element) is created and the root element is passed to the parser
+ as the parent. The ElementTree object is returned.
+
This should only be called on an entire document, not pieces.
"""
# Create a ElementTree from the lines
- self.root = markdown.etree.Element(markdown.DOC_TAG)
+ self.root = etree.Element(self.md.doc_tag)
self.parseChunk(self.root, '\n'.join(lines))
- return markdown.etree.ElementTree(self.root)
+ return etree.ElementTree(self.root)
def parseChunk(self, parent, text):
- """ Parse a chunk of markdown text and attach to given etree node.
-
+ """ Parse a chunk of markdown text and attach to given etree node.
+
While the ``text`` argument is generally assumed to contain multiple
blocks which will be split on blank lines, it could contain only one
block. Generally, this method would be called by extensions when
- block parsing is required.
-
- The ``parent`` etree Element passed in is altered in place.
+ block parsing is required.
+
+ The ``parent`` etree Element passed in is altered in place.
Nothing is returned.
"""
self.parseBlocks(parent, text.split('\n\n'))
def parseBlocks(self, parent, blocks):
- """ Process blocks of markdown text and attach to given etree node.
-
+ """ Process blocks of markdown text and attach to given etree node.
+
Given a list of ``blocks``, each blockprocessor is stepped through
until there are no blocks left. While an extension could potentially
- call this method directly, it's generally expected to be used internally.
+ call this method directly, it's generally expected to be used
+ internally.
- This is a public method as an extension may need to add/alter additional
- BlockProcessors which call this method to recursively parse a nested
- block.
+ This is a public method as an extension may need to add/alter
+ additional BlockProcessors which call this method to recursively
+ parse a nested block.
"""
while blocks:
- for processor in self.blockprocessors.values():
- if processor.test(parent, blocks[0]):
- processor.run(parent, blocks)
- break
-
-
+ for processor in self.blockprocessors:
+ if processor.test(parent, blocks[0]):
+ if processor.run(parent, blocks) is not False:
+ # run returns True or None
+ break
diff --git a/markdown/blockprocessors.py b/markdown/blockprocessors.py
index 7d3b137..3d0ff86 100644
--- a/markdown/blockprocessors.py
+++ b/markdown/blockprocessors.py
@@ -1,23 +1,64 @@
"""
+Python Markdown
+
+A Python implementation of John Gruber's Markdown.
+
+Documentation: https://python-markdown.github.io/
+GitHub: https://github.com/Python-Markdown/markdown/
+PyPI: https://pypi.org/project/Markdown/
+
+Started by Manfred Stienstra (http://www.dwerg.net/).
+Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
+Currently maintained by Waylan Limberg (https://github.com/waylan),
+Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
+
+Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see LICENSE.md for details).
+
CORE MARKDOWN BLOCKPARSER
-=============================================================================
+===========================================================================
-This parser handles basic parsing of Markdown blocks. It doesn't concern itself
-with inline elements such as **bold** or *italics*, but rather just catches
-blocks, lists, quotes, etc.
+This parser handles basic parsing of Markdown blocks. It doesn't concern
+itself with inline elements such as **bold** or *italics*, but rather just
+catches blocks, lists, quotes, etc.
-The BlockParser is made up of a bunch of BlockProssors, each handling a
+The BlockParser is made up of a bunch of BlockProcessors, each handling a
different type of block. Extensions may add/replace/remove BlockProcessors
as they need to alter how markdown blocks are parsed.
-
"""
+import logging
import re
-import markdown
+import xml.etree.ElementTree as etree
+from . import util
+from .blockparser import BlockParser
+
+logger = logging.getLogger('MARKDOWN')
+
+
+def build_block_parser(md, **kwargs):
+ """ Build the default block parser used by Markdown. """
+ parser = BlockParser(md)
+ parser.blockprocessors.register(EmptyBlockProcessor(parser), 'empty', 100)
+ parser.blockprocessors.register(ListIndentProcessor(parser), 'indent', 90)
+ parser.blockprocessors.register(CodeBlockProcessor(parser), 'code', 80)
+ parser.blockprocessors.register(HashHeaderProcessor(parser), 'hashheader', 70)
+ parser.blockprocessors.register(SetextHeaderProcessor(parser), 'setextheader', 60)
+ parser.blockprocessors.register(HRProcessor(parser), 'hr', 50)
+ parser.blockprocessors.register(OListProcessor(parser), 'olist', 40)
+ parser.blockprocessors.register(UListProcessor(parser), 'ulist', 30)
+ parser.blockprocessors.register(BlockQuoteProcessor(parser), 'quote', 20)
+ parser.blockprocessors.register(ReferenceProcessor(parser), 'reference', 15)
+ parser.blockprocessors.register(ParagraphProcessor(parser), 'paragraph', 10)
+ return parser
+
class BlockProcessor:
- """ Base class for block processors.
-
+ """ Base class for block processors.
+
Each subclass will provide the methods below to work with the source and
tree. Each processor will need to define it's own ``test`` and ``run``
methods. The ``test`` method should return True or False, to indicate
@@ -26,8 +67,9 @@ class BlockProcessor:
"""
- def __init__(self, parser=None):
+ def __init__(self, parser):
self.parser = parser
+ self.tab_length = parser.md.tab_length
def lastChild(self, parent):
""" Return the last child of an etree element. """
@@ -36,13 +78,15 @@ class BlockProcessor:
else:
return None
- def detab(self, text):
+ def detab(self, text, length=None):
""" Remove a tab from the front of each line of the given text. """
+ if length is None:
+ length = self.tab_length
newtext = []
lines = text.split('\n')
for line in lines:
- if line.startswith(' '*markdown.TAB_LENGTH):
- newtext.append(line[markdown.TAB_LENGTH:])
+ if line.startswith(' ' * length):
+ newtext.append(line[length:])
elif not line.strip():
newtext.append('')
else:
@@ -53,37 +97,37 @@ class BlockProcessor:
""" Remove a tab from front of lines but allowing dedented lines. """
lines = text.split('\n')
for i in range(len(lines)):
- if lines[i].startswith(' '*markdown.TAB_LENGTH*level):
- lines[i] = lines[i][markdown.TAB_LENGTH*level:]
+ if lines[i].startswith(' '*self.tab_length*level):
+ lines[i] = lines[i][self.tab_length*level:]
return '\n'.join(lines)
def test(self, parent, block):
- """ Test for block type. Must be overridden by subclasses.
-
- As the parser loops through processors, it will call the ``test`` method
- on each to determine if the given block of text is of that type. This
- method must return a boolean ``True`` or ``False``. The actual method of
- testing is left to the needs of that particular block type. It could
- be as simple as ``block.startswith(some_string)`` or a complex regular
- expression. As the block type may be different depending on the parent
- of the block (i.e. inside a list), the parent etree element is also
- provided and may be used as part of the test.
+ """ Test for block type. Must be overridden by subclasses.
+
+ As the parser loops through processors, it will call the ``test``
+ method on each to determine if the given block of text is of that
+ type. This method must return a boolean ``True`` or ``False``. The
+ actual method of testing is left to the needs of that particular
+ block type. It could be as simple as ``block.startswith(some_string)``
+ or a complex regular expression. As the block type may be different
+ depending on the parent of the block (i.e. inside a list), the parent
+ etree element is also provided and may be used as part of the test.
Keywords:
-
+
* ``parent``: A etree element which will be the parent of the block.
- * ``block``: A block of text from the source which has been split at
+ * ``block``: A block of text from the source which has been split at
blank lines.
"""
- pass
+ pass # pragma: no cover
def run(self, parent, blocks):
- """ Run processor. Must be overridden by subclasses.
-
+ """ Run processor. Must be overridden by subclasses.
+
When the parser determines the appropriate type of a block, the parser
will call the corresponding processor's ``run`` method. This method
should parse the individual lines of the block and append them to
- the etree.
+ the etree.
Note that both the ``parent`` and ``etree`` keywords are pointers
to instances of the objects which should be edited in place. Each
@@ -99,12 +143,12 @@ class BlockProcessor:
* ``parent``: A etree element which is the parent of the current block.
* ``blocks``: A list of all remaining blocks of the document.
"""
- pass
+ pass # pragma: no cover
class ListIndentProcessor(BlockProcessor):
- """ Process children of list items.
-
+ """ Process children of list items.
+
Example:
* a list item
process this part
@@ -113,18 +157,19 @@ class ListIndentProcessor(BlockProcessor):
"""
- INDENT_RE = re.compile(r'^(([ ]{%s})+)'% markdown.TAB_LENGTH)
ITEM_TYPES = ['li']
LIST_TYPES = ['ul', 'ol']
+ def __init__(self, *args):
+ super().__init__(*args)
+ self.INDENT_RE = re.compile(r'^(([ ]{%s})+)' % self.tab_length)
+
def test(self, parent, block):
- return block.startswith(' '*markdown.TAB_LENGTH) and \
- not self.parser.state.isstate('detabbed') and \
- (parent.tag in self.ITEM_TYPES or \
- (len(parent) and parent[-1] and \
- (parent[-1].tag in self.LIST_TYPES)
- )
- )
+ return block.startswith(' '*self.tab_length) and \
+ not self.parser.state.isstate('detabbed') and \
+ (parent.tag in self.ITEM_TYPES or
+ (len(parent) and parent[-1] is not None and
+ (parent[-1].tag in self.LIST_TYPES)))
def run(self, parent, blocks):
block = blocks.pop(0)
@@ -133,8 +178,16 @@ class ListIndentProcessor(BlockProcessor):
self.parser.state.set('detabbed')
if parent.tag in self.ITEM_TYPES:
- # The parent is already a li. Just parse the child block.
- self.parser.parseBlocks(parent, [block])
+ # It's possible that this parent has a 'ul' or 'ol' child list
+ # with a member. If that is the case, then that should be the
+ # parent. This is intended to catch the edge case of an indented
+ # list whose first member was parsed previous to this point
+ # see OListProcessor
+ if len(parent) and parent[-1].tag in self.LIST_TYPES:
+ self.parser.parseBlocks(parent[-1], [block])
+ else:
+ # The parent is already a li. Just parse the child block.
+ self.parser.parseBlocks(parent, [block])
elif sibling.tag in self.ITEM_TYPES:
# The sibling is a li. Use it as parent.
self.parser.parseBlocks(sibling, [block])
@@ -143,8 +196,12 @@ class ListIndentProcessor(BlockProcessor):
# Assume the last child li is the parent of this block.
if sibling[-1].text:
# If the parent li has text, that text needs to be moved to a p
- block = '%s\n\n%s' % (sibling[-1].text, block)
+ # The p must be 'inserted' at beginning of list in the event
+ # that other children already exist i.e.; a nested sublist.
+ p = etree.Element('p')
+ p.text = sibling[-1].text
sibling[-1].text = ''
+ sibling[-1].insert(0, p)
self.parser.parseChunk(sibling[-1], block)
else:
self.create_item(sibling, block)
@@ -152,15 +209,15 @@ class ListIndentProcessor(BlockProcessor):
def create_item(self, parent, block):
""" Create a new li and parse the block with it as the parent. """
- li = markdown.etree.SubElement(parent, 'li')
+ li = etree.SubElement(parent, 'li')
self.parser.parseBlocks(li, [block])
-
+
def get_level(self, parent, block):
""" Get level of indent based on list level. """
# Get indent level
m = self.INDENT_RE.match(block)
if m:
- indent_level = len(m.group(1))/markdown.TAB_LENGTH
+ indent_level = len(m.group(1))/self.tab_length
else:
indent_level = 0
if self.parser.state.isstate('list'):
@@ -172,7 +229,8 @@ class ListIndentProcessor(BlockProcessor):
# Step through children of tree to find matching indent level.
while indent_level > level:
child = self.lastChild(parent)
- if child and (child.tag in self.LIST_TYPES or child.tag in self.ITEM_TYPES):
+ if (child is not None and
+ (child.tag in self.LIST_TYPES or child.tag in self.ITEM_TYPES)):
if child.tag in self.LIST_TYPES:
level += 1
parent = child
@@ -187,28 +245,30 @@ class CodeBlockProcessor(BlockProcessor):
""" Process code blocks. """
def test(self, parent, block):
- return block.startswith(' '*markdown.TAB_LENGTH)
-
+ return block.startswith(' '*self.tab_length)
+
def run(self, parent, blocks):
sibling = self.lastChild(parent)
block = blocks.pop(0)
theRest = ''
- if sibling and sibling.tag == "pre" and len(sibling) \
- and sibling[0].tag == "code":
+ if (sibling is not None and sibling.tag == "pre" and
+ len(sibling) and sibling[0].tag == "code"):
# The previous block was a code block. As blank lines do not start
# new code blocks, append this block to the previous, adding back
# linebreaks removed from the split into a list.
code = sibling[0]
block, theRest = self.detab(block)
- code.text = markdown.AtomicString('%s\n%s\n' % (code.text, block.rstrip()))
+ code.text = util.AtomicString(
+ '{}\n{}\n'.format(code.text, util.code_escape(block.rstrip()))
+ )
else:
# This is a new codeblock. Create the elements and insert text.
- pre = markdown.etree.SubElement(parent, 'pre')
- code = markdown.etree.SubElement(pre, 'code')
+ pre = etree.SubElement(parent, 'pre')
+ code = etree.SubElement(pre, 'code')
block, theRest = self.detab(block)
- code.text = markdown.AtomicString('%s\n' % block.rstrip())
+ code.text = util.AtomicString('%s\n' % util.code_escape(block.rstrip()))
if theRest:
- # This block contained unindented line(s) after the first indented
+ # This block contained unindented line(s) after the first indented
# line. Insert these lines as the first block of the master blocks
# list for future processing.
blocks.insert(0, theRest)
@@ -219,27 +279,31 @@ class BlockQuoteProcessor(BlockProcessor):
RE = re.compile(r'(^|\n)[ ]{0,3}>[ ]?(.*)')
def test(self, parent, block):
- return bool(self.RE.search(block))
+ return bool(self.RE.search(block)) and not util.nearing_recursion_limit()
def run(self, parent, blocks):
block = blocks.pop(0)
m = self.RE.search(block)
if m:
- before = block[:m.start()] # Lines before blockquote
- # Pass lines before blockquote in recursively for parsing forst.
+ before = block[:m.start()] # Lines before blockquote
+ # Pass lines before blockquote in recursively for parsing first.
self.parser.parseBlocks(parent, [before])
- # Remove ``> `` from begining of each line.
- block = '\n'.join([self.clean(line) for line in
- block[m.start():].split('\n')])
+ # Remove ``> `` from beginning of each line.
+ block = '\n'.join(
+ [self.clean(line) for line in block[m.start():].split('\n')]
+ )
sibling = self.lastChild(parent)
- if sibling and sibling.tag == "blockquote":
+ if sibling is not None and sibling.tag == "blockquote":
# Previous block was a blockquote so set that as this blocks parent
quote = sibling
else:
# This is a new blockquote. Create a new parent element.
- quote = markdown.etree.SubElement(parent, 'blockquote')
+ quote = etree.SubElement(parent, 'blockquote')
# Recursively parse block with blockquote as parent.
+ # change parser state so blockquotes embedded in lists use p tags
+ self.parser.state.set('blockquote')
self.parser.parseChunk(quote, block)
+ self.parser.state.reset()
def clean(self, line):
""" Remove ``>`` from beginning of a line. """
@@ -251,16 +315,31 @@ class BlockQuoteProcessor(BlockProcessor):
else:
return line
+
class OListProcessor(BlockProcessor):
""" Process ordered list blocks. """
TAG = 'ol'
- # Detect an item (``1. item``). ``group(1)`` contains contents of item.
- RE = re.compile(r'^[ ]{0,3}\d+\.[ ]+(.*)')
- # Detect items on secondary lines. they can be of either list type.
- CHILD_RE = re.compile(r'^[ ]{0,3}((\d+\.)|[*+-])[ ]+(.*)')
- # Detect indented (nested) items of either type
- INDENT_RE = re.compile(r'^[ ]{4,7}((\d+\.)|[*+-])[ ]+.*')
+ # The integer (python string) with which the lists starts (default=1)
+ # Eg: If list is initialized as)
+ # 3. Item
+ # The ol tag will get starts="3" attribute
+ STARTSWITH = '1'
+ # Lazy ol - ignore startswith
+ LAZY_OL = True
+ # List of allowed sibling tags.
+ SIBLING_TAGS = ['ol', 'ul']
+
+ def __init__(self, parser):
+ super().__init__(parser)
+ # Detect an item (``1. item``). ``group(1)`` contains contents of item.
+ self.RE = re.compile(r'^[ ]{0,%d}\d+\.[ ]+(.*)' % (self.tab_length - 1))
+ # Detect items on secondary lines. they can be of either list type.
+ self.CHILD_RE = re.compile(r'^[ ]{0,%d}((\d+\.)|[*+-])[ ]+(.*)' %
+ (self.tab_length - 1))
+ # Detect indented (nested) items of either type
+ self.INDENT_RE = re.compile(r'^[ ]{%d,%d}((\d+\.)|[*+-])[ ]+.*' %
+ (self.tab_length, self.tab_length * 2 - 1))
def test(self, parent, block):
return bool(self.RE.match(block))
@@ -269,33 +348,58 @@ class OListProcessor(BlockProcessor):
# Check fr multiple items in one block.
items = self.get_items(blocks.pop(0))
sibling = self.lastChild(parent)
- if sibling and sibling.tag in ['ol', 'ul']:
+
+ if sibling is not None and sibling.tag in self.SIBLING_TAGS:
# Previous block was a list item, so set that as parent
lst = sibling
- # make sure previous item is in a p.
- if len(lst) and lst[-1].text and not len(lst[-1]):
- p = markdown.etree.SubElement(lst[-1], 'p')
+ # make sure previous item is in a p- if the item has text,
+ # then it isn't in a p
+ if lst[-1].text:
+ # since it's possible there are other children for this
+ # sibling, we can't just SubElement the p, we need to
+ # insert it as the first item.
+ p = etree.Element('p')
p.text = lst[-1].text
lst[-1].text = ''
+ lst[-1].insert(0, p)
+ # if the last item has a tail, then the tail needs to be put in a p
+ # likely only when a header is not followed by a blank line
+ lch = self.lastChild(lst[-1])
+ if lch is not None and lch.tail:
+ p = etree.SubElement(lst[-1], 'p')
+ p.text = lch.tail.lstrip()
+ lch.tail = ''
+
# parse first block differently as it gets wrapped in a p.
- li = markdown.etree.SubElement(lst, 'li')
+ li = etree.SubElement(lst, 'li')
self.parser.state.set('looselist')
firstitem = items.pop(0)
self.parser.parseBlocks(li, [firstitem])
self.parser.state.reset()
+ elif parent.tag in ['ol', 'ul']:
+ # this catches the edge case of a multi-item indented list whose
+ # first item is in a blank parent-list item:
+ # * * subitem1
+ # * subitem2
+ # see also ListIndentProcessor
+ lst = parent
else:
# This is a new list so create parent with appropriate tag.
- lst = markdown.etree.SubElement(parent, self.TAG)
+ lst = etree.SubElement(parent, self.TAG)
+ # Check if a custom start integer is set
+ if not self.LAZY_OL and self.STARTSWITH != '1':
+ lst.attrib['start'] = self.STARTSWITH
+
self.parser.state.set('list')
# Loop through items in block, recursively parsing each with the
# appropriate parent.
for item in items:
- if item.startswith(' '*markdown.TAB_LENGTH):
+ if item.startswith(' '*self.tab_length):
# Item is indented. Parse with last item as parent
self.parser.parseBlocks(lst[-1], [item])
else:
# New item. Create li and parse with it as parent
- li = markdown.etree.SubElement(lst, 'li')
+ li = etree.SubElement(lst, 'li')
self.parser.parseBlocks(li, [item])
self.parser.state.reset()
@@ -305,18 +409,24 @@ class OListProcessor(BlockProcessor):
for line in block.split('\n'):
m = self.CHILD_RE.match(line)
if m:
- # This is a new item. Append
+ # This is a new list item
+ # Check first item for the start index
+ if not items and self.TAG == 'ol':
+ # Detect the integer value of first list item
+ INTEGER_RE = re.compile(r'(\d+)')
+ self.STARTSWITH = INTEGER_RE.match(m.group(1)).group()
+ # Append to the list
items.append(m.group(3))
elif self.INDENT_RE.match(line):
# This is an indented (possibly nested) item.
- if items[-1].startswith(' '*markdown.TAB_LENGTH):
+ if items[-1].startswith(' '*self.tab_length):
# Previous item was indented. Append to that item.
- items[-1] = '%s\n%s' % (items[-1], line)
+ items[-1] = '{}\n{}'.format(items[-1], line)
else:
items.append(line)
else:
# This is another line of previous item. Append to that item.
- items[-1] = '%s\n%s' % (items[-1], line)
+ items[-1] = '{}\n{}'.format(items[-1], line)
return items
@@ -324,14 +434,18 @@ class UListProcessor(OListProcessor):
""" Process unordered list blocks. """
TAG = 'ul'
- RE = re.compile(r'^[ ]{0,3}[*+-][ ]+(.*)')
+
+ def __init__(self, parser):
+ super().__init__(parser)
+ # Detect an item (``1. item``). ``group(1)`` contains contents of item.
+ self.RE = re.compile(r'^[ ]{0,%d}[*+-][ ]+(.*)' % (self.tab_length - 1))
class HashHeaderProcessor(BlockProcessor):
""" Process Hash Headers. """
# Detect a header at start of any line in block
- RE = re.compile(r'(^|\n)(?P<level>#{1,6})(?P<header>.*?)#*(\n|$)')
+ RE = re.compile(r'(?:^|\n)(?P<level>#{1,6})(?P<header>(?:\\.|[^\\])*?)#*(?:\n|$)')
def test(self, parent, block):
return bool(self.RE.search(block))
@@ -340,29 +454,29 @@ class HashHeaderProcessor(BlockProcessor):
block = blocks.pop(0)
m = self.RE.search(block)
if m:
- before = block[:m.start()] # All lines before header
- after = block[m.end():] # All lines after header
+ before = block[:m.start()] # All lines before header
+ after = block[m.end():] # All lines after header
if before:
# As the header was not the first line of the block and the
# lines before the header must be parsed first,
# recursively parse this lines as a block.
self.parser.parseBlocks(parent, [before])
# Create header using named groups from RE
- h = markdown.etree.SubElement(parent, 'h%d' % len(m.group('level')))
+ h = etree.SubElement(parent, 'h%d' % len(m.group('level')))
h.text = m.group('header').strip()
if after:
# Insert remaining lines as first block for future parsing.
blocks.insert(0, after)
- else:
+ else: # pragma: no cover
# This should never happen, but just in case...
- message(CRITICAL, "We've got a problem header!")
+ logger.warn("We've got a problem header: %r" % block)
class SetextHeaderProcessor(BlockProcessor):
""" Process Setext-style Headers. """
# Detect Setext-style header. Must be first 2 lines of block.
- RE = re.compile(r'^.*?\n[=-]{3,}', re.MULTILINE)
+ RE = re.compile(r'^.*?\n[=-]+[ ]*(\n|$)', re.MULTILINE)
def test(self, parent, block):
return bool(self.RE.match(block))
@@ -374,7 +488,7 @@ class SetextHeaderProcessor(BlockProcessor):
level = 1
else:
level = 2
- h = markdown.etree.SubElement(parent, 'h%d' % level)
+ h = etree.SubElement(parent, 'h%d' % level)
h.text = lines[0].strip()
if len(lines) > 2:
# Block contains additional lines. Add to master blocks for later.
@@ -384,58 +498,91 @@ class SetextHeaderProcessor(BlockProcessor):
class HRProcessor(BlockProcessor):
""" Process Horizontal Rules. """
- RE = r'[ ]{0,3}(?P<ch>[*_-])[ ]?((?P=ch)[ ]?){2,}[ ]*'
+ # Python's re module doesn't officially support atomic grouping. However you can fake it.
+ # See https://stackoverflow.com/a/13577411/866026
+ RE = r'^[ ]{0,3}(?=(?P<atomicgroup>(-+[ ]{0,2}){3,}|(_+[ ]{0,2}){3,}|(\*+[ ]{0,2}){3,}))(?P=atomicgroup)[ ]*$'
# Detect hr on any line of a block.
- SEARCH_RE = re.compile(r'(^|\n)%s(\n|$)' % RE)
- # Match a hr on a single line of text.
- MATCH_RE = re.compile(r'^%s$' % RE)
+ SEARCH_RE = re.compile(RE, re.MULTILINE)
def test(self, parent, block):
- return bool(self.SEARCH_RE.search(block))
+ m = self.SEARCH_RE.search(block)
+ if m:
+ # Save match object on class instance so we can use it later.
+ self.match = m
+ return True
+ return False
def run(self, parent, blocks):
- lines = blocks.pop(0).split('\n')
- prelines = []
+ block = blocks.pop(0)
+ match = self.match
# Check for lines in block before hr.
- for line in lines:
- m = self.MATCH_RE.match(line)
- if m:
- break
- else:
- prelines.append(line)
- if len(prelines):
+ prelines = block[:match.start()].rstrip('\n')
+ if prelines:
# Recursively parse lines before hr so they get parsed first.
- self.parser.parseBlocks(parent, ['\n'.join(prelines)])
+ self.parser.parseBlocks(parent, [prelines])
# create hr
- hr = markdown.etree.SubElement(parent, 'hr')
+ etree.SubElement(parent, 'hr')
# check for lines in block after hr.
- lines = lines[len(prelines)+1:]
- if len(lines):
+ postlines = block[match.end():].lstrip('\n')
+ if postlines:
# Add lines after hr to master blocks for later parsing.
- blocks.insert(0, '\n'.join(lines))
+ blocks.insert(0, postlines)
class EmptyBlockProcessor(BlockProcessor):
- """ Process blocks and start with an empty line. """
+ """ Process blocks that are empty or start with an empty line. """
- # Detect a block that only contains whitespace
- # or only whitespace on the first line.
- RE = re.compile(r'^\s*\n')
+ def test(self, parent, block):
+ return not block or block.startswith('\n')
+
+ def run(self, parent, blocks):
+ block = blocks.pop(0)
+ filler = '\n\n'
+ if block:
+ # Starts with empty line
+ # Only replace a single line.
+ filler = '\n'
+ # Save the rest for later.
+ theRest = block[1:]
+ if theRest:
+ # Add remaining lines to master blocks for later.
+ blocks.insert(0, theRest)
+ sibling = self.lastChild(parent)
+ if (sibling is not None and sibling.tag == 'pre' and
+ len(sibling) and sibling[0].tag == 'code'):
+ # Last block is a codeblock. Append to preserve whitespace.
+ sibling[0].text = util.AtomicString(
+ '{}{}'.format(sibling[0].text, filler)
+ )
+
+
+class ReferenceProcessor(BlockProcessor):
+ """ Process link references. """
+ RE = re.compile(
+ r'^[ ]{0,3}\[([^\[\]]*)\]:[ ]*\n?[ ]*([^\s]+)[ ]*(?:\n[ ]*)?((["\'])(.*)\4[ ]*|\((.*)\)[ ]*)?$', re.MULTILINE
+ )
def test(self, parent, block):
- return bool(self.RE.match(block))
+ return True
def run(self, parent, blocks):
block = blocks.pop(0)
- m = self.RE.match(block)
+ m = self.RE.search(block)
if m:
- # Add remaining line to master blocks for later.
- blocks.insert(0, block[m.end():])
- sibling = self.lastChild(parent)
- if sibling and sibling.tag == 'pre' and sibling[0] and \
- sibling[0].tag == 'code':
- # Last block is a codeblock. Append to preserve whitespace.
- sibling[0].text = markdown.AtomicString('%s/n/n/n' % sibling[0].text )
+ id = m.group(1).strip().lower()
+ link = m.group(2).lstrip('<').rstrip('>')
+ title = m.group(5) or m.group(6)
+ self.parser.md.references[id] = (link, title)
+ if block[m.end():].strip():
+ # Add any content after match back to blocks as separate block
+ blocks.insert(0, block[m.end():].lstrip('\n'))
+ if block[:m.start()].strip():
+ # Add any content before match back to blocks as separate block
+ blocks.insert(0, block[:m.start()].rstrip('\n'))
+ return True
+ # No match. Restore block.
+ blocks.insert(0, block)
+ return False
class ParagraphProcessor(BlockProcessor):
@@ -449,12 +596,28 @@ class ParagraphProcessor(BlockProcessor):
if block.strip():
# Not a blank block. Add to parent, otherwise throw it away.
if self.parser.state.isstate('list'):
- # The parent is a tight-list. Append to parent.text
- if parent.text:
- parent.text = '%s\n%s' % (parent.text, block)
+ # The parent is a tight-list.
+ #
+ # Check for any children. This will likely only happen in a
+ # tight-list when a header isn't followed by a blank line.
+ # For example:
+ #
+ # * # Header
+ # Line 2 of list item - not part of header.
+ sibling = self.lastChild(parent)
+ if sibling is not None:
+ # Insetrt after sibling.
+ if sibling.tail:
+ sibling.tail = '{}\n{}'.format(sibling.tail, block)
+ else:
+ sibling.tail = '\n%s' % block
else:
- parent.text = block.lstrip()
+ # Append to parent.text
+ if parent.text:
+ parent.text = '{}\n{}'.format(parent.text, block)
+ else:
+ parent.text = block.lstrip()
else:
# Create a regular paragraph
- p = markdown.etree.SubElement(parent, 'p')
+ p = etree.SubElement(parent, 'p')
p.text = block.lstrip()
diff --git a/markdown/commandline.py b/markdown/commandline.py
deleted file mode 100644
index 1eedc6d..0000000
--- a/markdown/commandline.py
+++ /dev/null
@@ -1,96 +0,0 @@
-"""
-COMMAND-LINE SPECIFIC STUFF
-=============================================================================
-
-The rest of the code is specifically for handling the case where Python
-Markdown is called from the command line.
-"""
-
-import markdown
-import sys
-import logging
-from logging import DEBUG, INFO, WARN, ERROR, CRITICAL
-
-EXECUTABLE_NAME_FOR_USAGE = "python markdown.py"
-""" The name used in the usage statement displayed for python versions < 2.3.
-(With python 2.3 and higher the usage statement is generated by optparse
-and uses the actual name of the executable called.) """
-
-OPTPARSE_WARNING = """
-Python 2.3 or higher required for advanced command line options.
-For lower versions of Python use:
-
- %s INPUT_FILE > OUTPUT_FILE
-
-""" % EXECUTABLE_NAME_FOR_USAGE
-
-def parse_options():
- """
- Define and parse `optparse` options for command-line usage.
- """
-
- try:
- optparse = __import__("optparse")
- except:
- if len(sys.argv) == 2:
- return {'input': sys.argv[1],
- 'output': None,
- 'safe': False,
- 'extensions': [],
- 'encoding': None }, CRITICAL
- else:
- print OPTPARSE_WARNING
- return None, None
-
- parser = optparse.OptionParser(usage="%prog INPUTFILE [options]")
- parser.add_option("-f", "--file", dest="filename", default=sys.stdout,
- help="write output to OUTPUT_FILE",
- metavar="OUTPUT_FILE")
- parser.add_option("-e", "--encoding", dest="encoding",
- help="encoding for input and output files",)
- parser.add_option("-q", "--quiet", default = CRITICAL,
- action="store_const", const=CRITICAL+10, dest="verbose",
- help="suppress all messages")
- parser.add_option("-v", "--verbose",
- action="store_const", const=INFO, dest="verbose",
- help="print info messages")
- parser.add_option("-s", "--safe", dest="safe", default=False,
- metavar="SAFE_MODE",
- help="safe mode ('replace', 'remove' or 'escape' user's HTML tag)")
- parser.add_option("-o", "--output_format", dest="output_format",
- default='xhtml1', metavar="OUTPUT_FORMAT",
- help="Format of output. One of 'xhtml1' (default) or 'html4'.")
- parser.add_option("--noisy",
- action="store_const", const=DEBUG, dest="verbose",
- help="print debug messages")
- parser.add_option("-x", "--extension", action="append", dest="extensions",
- help = "load extension EXTENSION", metavar="EXTENSION")
-
- (options, args) = parser.parse_args()
-
- if not len(args) == 1:
- parser.print_help()
- return None, None
- else:
- input_file = args[0]
-
- if not options.extensions:
- options.extensions = []
-
- return {'input': input_file,
- 'output': options.filename,
- 'safe_mode': options.safe,
- 'extensions': options.extensions,
- 'encoding': options.encoding,
- 'output_format': options.output_format}, options.verbose
-
-def run():
- """Run Markdown from the command line."""
-
- # Parse options and adjust logging level if necessary
- options, logging_level = parse_options()
- if not options: sys.exit(0)
- if logging_level: logging.getLogger('MARKDOWN').setLevel(logging_level)
-
- # Run
- markdown.markdownFromFile(**options)
diff --git a/markdown/core.py b/markdown/core.py
new file mode 100644
index 0000000..f6a171c
--- /dev/null
+++ b/markdown/core.py
@@ -0,0 +1,407 @@
+"""
+Python Markdown
+
+A Python implementation of John Gruber's Markdown.
+
+Documentation: https://python-markdown.github.io/
+GitHub: https://github.com/Python-Markdown/markdown/
+PyPI: https://pypi.org/project/Markdown/
+
+Started by Manfred Stienstra (http://www.dwerg.net/).
+Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
+Currently maintained by Waylan Limberg (https://github.com/waylan),
+Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
+
+Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see LICENSE.md for details).
+"""
+
+import codecs
+import sys
+import logging
+import importlib
+from . import util
+from .preprocessors import build_preprocessors
+from .blockprocessors import build_block_parser
+from .treeprocessors import build_treeprocessors
+from .inlinepatterns import build_inlinepatterns
+from .postprocessors import build_postprocessors
+from .extensions import Extension
+from .serializers import to_html_string, to_xhtml_string
+
+__all__ = ['Markdown', 'markdown', 'markdownFromFile']
+
+
+logger = logging.getLogger('MARKDOWN')
+
+
+class Markdown:
+ """Convert Markdown to HTML."""
+
+ doc_tag = "div" # Element used to wrap document - later removed
+
+ output_formats = {
+ 'html': to_html_string,
+ 'xhtml': to_xhtml_string,
+ }
+
+ def __init__(self, **kwargs):
+ """
+ Creates a new Markdown instance.
+
+ Keyword arguments:
+
+ * extensions: A list of extensions.
+ If an item is an instance of a subclass of `markdown.extension.Extension`, the instance will be used
+ as-is. If an item is of type string, first an entry point will be loaded. If that fails, the string is
+ assumed to use Python dot notation (`path.to.module:ClassName`) to load a markdown.Extension subclass. If
+ no class is specified, then a `makeExtension` function is called within the specified module.
+ * extension_configs: Configuration settings for extensions.
+ * output_format: Format of output. Supported formats are:
+ * "xhtml": Outputs XHTML style tags. Default.
+ * "html": Outputs HTML style tags.
+ * tab_length: Length of tabs in the source. Default: 4
+
+ """
+
+ self.tab_length = kwargs.get('tab_length', 4)
+
+ self.ESCAPED_CHARS = ['\\', '`', '*', '_', '{', '}', '[', ']',
+ '(', ')', '>', '#', '+', '-', '.', '!']
+
+ self.block_level_elements = [
+ # Elements which are invalid to wrap in a `<p>` tag.
+ # See https://w3c.github.io/html/grouping-content.html#the-p-element
+ 'address', 'article', 'aside', 'blockquote', 'details', 'div', 'dl',
+ 'fieldset', 'figcaption', 'figure', 'footer', 'form', 'h1', 'h2', 'h3',
+ 'h4', 'h5', 'h6', 'header', 'hgroup', 'hr', 'main', 'menu', 'nav', 'ol',
+ 'p', 'pre', 'section', 'table', 'ul',
+ # Other elements which Markdown should not be mucking up the contents of.
+ 'canvas', 'colgroup', 'dd', 'body', 'dt', 'group', 'iframe', 'li', 'legend',
+ 'math', 'map', 'noscript', 'output', 'object', 'option', 'progress', 'script',
+ 'style', 'summary', 'tbody', 'td', 'textarea', 'tfoot', 'th', 'thead', 'tr', 'video'
+ ]
+
+ self.registeredExtensions = []
+ self.docType = ""
+ self.stripTopLevelTags = True
+
+ self.build_parser()
+
+ self.references = {}
+ self.htmlStash = util.HtmlStash()
+ self.registerExtensions(extensions=kwargs.get('extensions', []),
+ configs=kwargs.get('extension_configs', {}))
+ self.set_output_format(kwargs.get('output_format', 'xhtml'))
+ self.reset()
+
+ def build_parser(self):
+ """ Build the parser from the various parts. """
+ self.preprocessors = build_preprocessors(self)
+ self.parser = build_block_parser(self)
+ self.inlinePatterns = build_inlinepatterns(self)
+ self.treeprocessors = build_treeprocessors(self)
+ self.postprocessors = build_postprocessors(self)
+ return self
+
+ def registerExtensions(self, extensions, configs):
+ """
+ Register extensions with this instance of Markdown.
+
+ Keyword arguments:
+
+ * extensions: A list of extensions, which can either
+ be strings or objects.
+ * configs: A dictionary mapping extension names to config options.
+
+ """
+ for ext in extensions:
+ if isinstance(ext, str):
+ ext = self.build_extension(ext, configs.get(ext, {}))
+ if isinstance(ext, Extension):
+ ext.extendMarkdown(self)
+ logger.debug(
+ 'Successfully loaded extension "%s.%s".'
+ % (ext.__class__.__module__, ext.__class__.__name__)
+ )
+ elif ext is not None:
+ raise TypeError(
+ 'Extension "{}.{}" must be of type: "{}.{}"'.format(
+ ext.__class__.__module__, ext.__class__.__name__,
+ Extension.__module__, Extension.__name__
+ )
+ )
+ return self
+
+ def build_extension(self, ext_name, configs):
+ """
+ Build extension from a string name, then return an instance.
+
+ First attempt to load an entry point. The string name must be registered as an entry point in the
+ `markdown.extensions` group which points to a subclass of the `markdown.extensions.Extension` class.
+ If multiple distributions have registered the same name, the first one found is returned.
+
+ If no entry point is found, assume dot notation (`path.to.module:ClassName`). Load the specified class and
+ return an instance. If no class is specified, import the module and call a `makeExtension` function and return
+ the Extension instance returned by that function.
+ """
+ configs = dict(configs)
+
+ entry_points = [ep for ep in util.get_installed_extensions() if ep.name == ext_name]
+ if entry_points:
+ ext = entry_points[0].load()
+ return ext(**configs)
+
+ # Get class name (if provided): `path.to.module:ClassName`
+ ext_name, class_name = ext_name.split(':', 1) if ':' in ext_name else (ext_name, '')
+
+ try:
+ module = importlib.import_module(ext_name)
+ logger.debug(
+ 'Successfully imported extension module "%s".' % ext_name
+ )
+ except ImportError as e:
+ message = 'Failed loading extension "%s".' % ext_name
+ e.args = (message,) + e.args[1:]
+ raise
+
+ if class_name:
+ # Load given class name from module.
+ return getattr(module, class_name)(**configs)
+ else:
+ # Expect makeExtension() function to return a class.
+ try:
+ return module.makeExtension(**configs)
+ except AttributeError as e:
+ message = e.args[0]
+ message = "Failed to initiate extension " \
+ "'%s': %s" % (ext_name, message)
+ e.args = (message,) + e.args[1:]
+ raise
+
+ def registerExtension(self, extension):
+ """ This gets called by the extension """
+ self.registeredExtensions.append(extension)
+ return self
+
+ def reset(self):
+ """
+ Resets all state variables so that we can start with a new text.
+ """
+ self.htmlStash.reset()
+ self.references.clear()
+
+ for extension in self.registeredExtensions:
+ if hasattr(extension, 'reset'):
+ extension.reset()
+
+ return self
+
+ def set_output_format(self, format):
+ """ Set the output format for the class instance. """
+ self.output_format = format.lower().rstrip('145') # ignore num
+ try:
+ self.serializer = self.output_formats[self.output_format]
+ except KeyError as e:
+ valid_formats = list(self.output_formats.keys())
+ valid_formats.sort()
+ message = 'Invalid Output Format: "%s". Use one of %s.' \
+ % (self.output_format,
+ '"' + '", "'.join(valid_formats) + '"')
+ e.args = (message,) + e.args[1:]
+ raise
+ return self
+
+ def is_block_level(self, tag):
+ """Check if the tag is a block level HTML tag."""
+ if isinstance(tag, str):
+ return tag.lower().rstrip('/') in self.block_level_elements
+ # Some ElementTree tags are not strings, so return False.
+ return False
+
+ def convert(self, source):
+ """
+ Convert markdown to serialized XHTML or HTML.
+
+ Keyword arguments:
+
+ * source: Source text as a Unicode string.
+
+ Markdown processing takes place in five steps:
+
+ 1. A bunch of "preprocessors" munge the input text.
+ 2. BlockParser() parses the high-level structural elements of the
+ pre-processed text into an ElementTree.
+ 3. A bunch of "treeprocessors" are run against the ElementTree. One
+ such treeprocessor runs InlinePatterns against the ElementTree,
+ detecting inline markup.
+ 4. Some post-processors are run against the text after the ElementTree
+ has been serialized into text.
+ 5. The output is written to a string.
+
+ """
+
+ # Fixup the source text
+ if not source.strip():
+ return '' # a blank unicode string
+
+ try:
+ source = str(source)
+ except UnicodeDecodeError as e: # pragma: no cover
+ # Customise error message while maintaining original trackback
+ e.reason += '. -- Note: Markdown only accepts unicode input!'
+ raise
+
+ # Split into lines and run the line preprocessors.
+ self.lines = source.split("\n")
+ for prep in self.preprocessors:
+ self.lines = prep.run(self.lines)
+
+ # Parse the high-level elements.
+ root = self.parser.parseDocument(self.lines).getroot()
+
+ # Run the tree-processors
+ for treeprocessor in self.treeprocessors:
+ newRoot = treeprocessor.run(root)
+ if newRoot is not None:
+ root = newRoot
+
+ # Serialize _properly_. Strip top-level tags.
+ output = self.serializer(root)
+ if self.stripTopLevelTags:
+ try:
+ start = output.index(
+ '<%s>' % self.doc_tag) + len(self.doc_tag) + 2
+ end = output.rindex('</%s>' % self.doc_tag)
+ output = output[start:end].strip()
+ except ValueError as e: # pragma: no cover
+ if output.strip().endswith('<%s />' % self.doc_tag):
+ # We have an empty document
+ output = ''
+ else:
+ # We have a serious problem
+ raise ValueError('Markdown failed to strip top-level '
+ 'tags. Document=%r' % output.strip()) from e
+
+ # Run the text post-processors
+ for pp in self.postprocessors:
+ output = pp.run(output)
+
+ return output.strip()
+
+ def convertFile(self, input=None, output=None, encoding=None):
+ """Converts a markdown file and returns the HTML as a unicode string.
+
+ Decodes the file using the provided encoding (defaults to utf-8),
+ passes the file content to markdown, and outputs the html to either
+ the provided stream or the file with provided name, using the same
+ encoding as the source file. The 'xmlcharrefreplace' error handler is
+ used when encoding the output.
+
+ **Note:** This is the only place that decoding and encoding of unicode
+ takes place in Python-Markdown. (All other code is unicode-in /
+ unicode-out.)
+
+ Keyword arguments:
+
+ * input: File object or path. Reads from stdin if `None`.
+ * output: File object or path. Writes to stdout if `None`.
+ * encoding: Encoding of input and output files. Defaults to utf-8.
+
+ """
+
+ encoding = encoding or "utf-8"
+
+ # Read the source
+ if input:
+ if isinstance(input, str):
+ input_file = codecs.open(input, mode="r", encoding=encoding)
+ else:
+ input_file = codecs.getreader(encoding)(input)
+ text = input_file.read()
+ input_file.close()
+ else:
+ text = sys.stdin.read()
+ if not isinstance(text, str): # pragma: no cover
+ text = text.decode(encoding)
+
+ text = text.lstrip('\ufeff') # remove the byte-order mark
+
+ # Convert
+ html = self.convert(text)
+
+ # Write to file or stdout
+ if output:
+ if isinstance(output, str):
+ output_file = codecs.open(output, "w",
+ encoding=encoding,
+ errors="xmlcharrefreplace")
+ output_file.write(html)
+ output_file.close()
+ else:
+ writer = codecs.getwriter(encoding)
+ output_file = writer(output, errors="xmlcharrefreplace")
+ output_file.write(html)
+ # Don't close here. User may want to write more.
+ else:
+ # Encode manually and write bytes to stdout.
+ html = html.encode(encoding, "xmlcharrefreplace")
+ try:
+ # Write bytes directly to buffer (Python 3).
+ sys.stdout.buffer.write(html)
+ except AttributeError: # pragma: no cover
+ # Probably Python 2, which works with bytes by default.
+ sys.stdout.write(html)
+
+ return self
+
+
+"""
+EXPORTED FUNCTIONS
+=============================================================================
+
+Those are the two functions we really mean to export: markdown() and
+markdownFromFile().
+"""
+
+
+def markdown(text, **kwargs):
+ """Convert a markdown string to HTML and return HTML as a unicode string.
+
+ This is a shortcut function for `Markdown` class to cover the most
+ basic use case. It initializes an instance of Markdown, loads the
+ necessary extensions and runs the parser on the given text.
+
+ Keyword arguments:
+
+ * text: Markdown formatted text as Unicode or ASCII string.
+ * Any arguments accepted by the Markdown class.
+
+ Returns: An HTML document as a string.
+
+ """
+ md = Markdown(**kwargs)
+ return md.convert(text)
+
+
+def markdownFromFile(**kwargs):
+ """Read markdown code from a file and write it to a file or a stream.
+
+ This is a shortcut function which initializes an instance of Markdown,
+ and calls the convertFile method rather than convert.
+
+ Keyword arguments:
+
+ * input: a file name or readable object.
+ * output: a file name or writable object.
+ * encoding: Encoding of input and output.
+ * Any arguments accepted by the Markdown class.
+
+ """
+ md = Markdown(**kwargs)
+ md.convertFile(kwargs.get('input', None),
+ kwargs.get('output', None),
+ kwargs.get('encoding', None))
diff --git a/markdown/etree_loader.py b/markdown/etree_loader.py
deleted file mode 100644
index e2599b2..0000000
--- a/markdown/etree_loader.py
+++ /dev/null
@@ -1,33 +0,0 @@
-
-from markdown import message, CRITICAL
-import sys
-
-## Import
-def importETree():
- """Import the best implementation of ElementTree, return a module object."""
- etree_in_c = None
- try: # Is it Python 2.5+ with C implemenation of ElementTree installed?
- import xml.etree.cElementTree as etree_in_c
- except ImportError:
- try: # Is it Python 2.5+ with Python implementation of ElementTree?
- import xml.etree.ElementTree as etree
- except ImportError:
- try: # An earlier version of Python with cElementTree installed?
- import cElementTree as etree_in_c
- except ImportError:
- try: # An earlier version of Python with Python ElementTree?
- import elementtree.ElementTree as etree
- except ImportError:
- message(CRITICAL, "Failed to import ElementTree")
- sys.exit(1)
- if etree_in_c and etree_in_c.VERSION < "1.0":
- message(CRITICAL, "For cElementTree version 1.0 or higher is required.")
- sys.exit(1)
- elif etree_in_c :
- return etree_in_c
- elif etree.VERSION < "1.1":
- message(CRITICAL, "For ElementTree version 1.1 or higher is required")
- sys.exit(1)
- else :
- return etree
-
diff --git a/markdown/extensions/__init__.py b/markdown/extensions/__init__.py
index e69de29..2d8d72a 100644
--- a/markdown/extensions/__init__.py
+++ b/markdown/extensions/__init__.py
@@ -0,0 +1,86 @@
+"""
+Python Markdown
+
+A Python implementation of John Gruber's Markdown.
+
+Documentation: https://python-markdown.github.io/
+GitHub: https://github.com/Python-Markdown/markdown/
+PyPI: https://pypi.org/project/Markdown/
+
+Started by Manfred Stienstra (http://www.dwerg.net/).
+Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
+Currently maintained by Waylan Limberg (https://github.com/waylan),
+Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
+
+Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see LICENSE.md for details).
+"""
+
+from ..util import parseBoolValue
+
+
+class Extension:
+ """ Base class for extensions to subclass. """
+
+ # Default config -- to be overridden by a subclass
+ # Must be of the following format:
+ # {
+ # 'key': ['value', 'description']
+ # }
+ # Note that Extension.setConfig will raise a KeyError
+ # if a default is not set here.
+ config = {}
+
+ def __init__(self, **kwargs):
+ """ Initiate Extension and set up configs. """
+ self.setConfigs(kwargs)
+
+ def getConfig(self, key, default=''):
+ """ Return a setting for the given key or an empty string. """
+ if key in self.config:
+ return self.config[key][0]
+ else:
+ return default
+
+ def getConfigs(self):
+ """ Return all configs settings as a dict. """
+ return {key: self.getConfig(key) for key in self.config.keys()}
+
+ def getConfigInfo(self):
+ """ Return all config descriptions as a list of tuples. """
+ return [(key, self.config[key][1]) for key in self.config.keys()]
+
+ def setConfig(self, key, value):
+ """ Set a config setting for `key` with the given `value`. """
+ if isinstance(self.config[key][0], bool):
+ value = parseBoolValue(value)
+ if self.config[key][0] is None:
+ value = parseBoolValue(value, preserve_none=True)
+ self.config[key][0] = value
+
+ def setConfigs(self, items):
+ """ Set multiple config settings given a dict or list of tuples. """
+ if hasattr(items, 'items'):
+ # it's a dict
+ items = items.items()
+ for key, value in items:
+ self.setConfig(key, value)
+
+ def extendMarkdown(self, md):
+ """
+ Add the various processors and patterns to the Markdown Instance.
+
+ This method must be overridden by every extension.
+
+ Keyword arguments:
+
+ * md: The Markdown instance.
+
+ """
+ raise NotImplementedError(
+ 'Extension "%s.%s" must define an "extendMarkdown"'
+ 'method.' % (self.__class__.__module__, self.__class__.__name__)
+ )
diff --git a/markdown/extensions/abbr.py b/markdown/extensions/abbr.py
index 783220e..9879314 100644
--- a/markdown/extensions/abbr.py
+++ b/markdown/extensions/abbr.py
@@ -4,67 +4,74 @@ Abbreviation Extension for Python-Markdown
This extension adds abbreviation handling to Python-Markdown.
-Simple Usage:
-
- >>> import markdown
- >>> text = """
- ... Some text with an ABBR and a REF. Ignore REFERENCE and ref.
- ...
- ... *[ABBR]: Abbreviation
- ... *[REF]: Abbreviation Reference
- ... """
- >>> markdown.markdown(text, ['abbr'])
- u'<p>Some text with an <abbr title="Abbreviation">ABBR</abbr> and a <abbr title="Abbreviation Reference">REF</abbr>. Ignore REFERENCE and ref.</p>'
-
-Copyright 2007-2008
-* [Waylan Limberg](http://achinghead.com/)
-* [Seemant Kulleen](http://www.kulleen.org/)
-
+See <https://Python-Markdown.github.io/extensions/abbreviations>
+for documentation.
+
+Oringinal code Copyright 2007-2008 [Waylan Limberg](http://achinghead.com/) and
+ [Seemant Kulleen](http://www.kulleen.org/)
+
+All changes Copyright 2008-2014 The Python Markdown Project
+
+License: [BSD](https://opensource.org/licenses/bsd-license.php)
'''
-import markdown, re
-from markdown import etree
+from . import Extension
+from ..blockprocessors import BlockProcessor
+from ..inlinepatterns import InlineProcessor
+from ..util import AtomicString
+import re
+import xml.etree.ElementTree as etree
-# Global Vars
-ABBR_REF_RE = re.compile(r'[*]\[(?P<abbr>[^\]]*)\][ ]?:\s*(?P<title>.*)')
-class AbbrExtension(markdown.Extension):
+class AbbrExtension(Extension):
""" Abbreviation Extension for Python-Markdown. """
- def extendMarkdown(self, md, md_globals):
+ def extendMarkdown(self, md):
""" Insert AbbrPreprocessor before ReferencePreprocessor. """
- md.preprocessors.add('abbr', AbbrPreprocessor(md), '<reference')
-
-
-class AbbrPreprocessor(markdown.preprocessors.Preprocessor):
+ md.parser.blockprocessors.register(AbbrPreprocessor(md.parser), 'abbr', 16)
+
+
+class AbbrPreprocessor(BlockProcessor):
""" Abbreviation Preprocessor - parse text for abbr references. """
- def run(self, lines):
+ RE = re.compile(r'^[*]\[(?P<abbr>[^\]]*)\][ ]?:[ ]*\n?[ ]*(?P<title>.*)$', re.MULTILINE)
+
+ def test(self, parent, block):
+ return True
+
+ def run(self, parent, blocks):
'''
Find and remove all Abbreviation references from the text.
Each reference is set as a new AbbrPattern in the markdown instance.
-
+
'''
- new_text = []
- for line in lines:
- m = ABBR_REF_RE.match(line)
- if m:
- abbr = m.group('abbr').strip()
- title = m.group('title').strip()
- self.markdown.inlinePatterns['abbr-%s'%abbr] = \
- AbbrPattern(self._generate_pattern(abbr), title)
- else:
- new_text.append(line)
- return new_text
-
+ block = blocks.pop(0)
+ m = self.RE.search(block)
+ if m:
+ abbr = m.group('abbr').strip()
+ title = m.group('title').strip()
+ self.parser.md.inlinePatterns.register(
+ AbbrInlineProcessor(self._generate_pattern(abbr), title), 'abbr-%s' % abbr, 2
+ )
+ if block[m.end():].strip():
+ # Add any content after match back to blocks as separate block
+ blocks.insert(0, block[m.end():].lstrip('\n'))
+ if block[:m.start()].strip():
+ # Add any content before match back to blocks as separate block
+ blocks.insert(0, block[:m.start()].rstrip('\n'))
+ return True
+ # No match. Restore block.
+ blocks.insert(0, block)
+ return False
+
def _generate_pattern(self, text):
'''
- Given a string, returns an regex pattern to match that string.
-
- 'HTML' -> r'(?P<abbr>[H][T][M][L])'
-
- Note: we force each char as a literal match (in brackets) as we don't
+ Given a string, returns an regex pattern to match that string.
+
+ 'HTML' -> r'(?P<abbr>[H][T][M][L])'
+
+ Note: we force each char as a literal match (in brackets) as we don't
know what they will be beforehand.
'''
@@ -74,22 +81,19 @@ class AbbrPreprocessor(markdown.preprocessors.Preprocessor):
return r'(?P<abbr>\b%s\b)' % (r''.join(chars))
-class AbbrPattern(markdown.inlinepatterns.Pattern):
+class AbbrInlineProcessor(InlineProcessor):
""" Abbreviation inline pattern. """
def __init__(self, pattern, title):
- markdown.inlinepatterns.Pattern.__init__(self, pattern)
+ super().__init__(pattern)
self.title = title
- def handleMatch(self, m):
+ def handleMatch(self, m, data):
abbr = etree.Element('abbr')
- abbr.text = m.group('abbr')
+ abbr.text = AtomicString(m.group('abbr'))
abbr.set('title', self.title)
- return abbr
+ return abbr, m.start(0), m.end(0)
-def makeExtension(configs=None):
- return AbbrExtension(configs=configs)
-if __name__ == "__main__":
- import doctest
- doctest.testmod()
+def makeExtension(**kwargs): # pragma: no cover
+ return AbbrExtension(**kwargs)
diff --git a/markdown/extensions/admonition.py b/markdown/extensions/admonition.py
new file mode 100644
index 0000000..cb8d901
--- /dev/null
+++ b/markdown/extensions/admonition.py
@@ -0,0 +1,170 @@
+"""
+Admonition extension for Python-Markdown
+========================================
+
+Adds rST-style admonitions. Inspired by [rST][] feature with the same name.
+
+[rST]: http://docutils.sourceforge.net/docs/ref/rst/directives.html#specific-admonitions # noqa
+
+See <https://Python-Markdown.github.io/extensions/admonition>
+for documentation.
+
+Original code Copyright [Tiago Serafim](https://www.tiagoserafim.com/).
+
+All changes Copyright The Python Markdown Project
+
+License: [BSD](https://opensource.org/licenses/bsd-license.php)
+
+"""
+
+from . import Extension
+from ..blockprocessors import BlockProcessor
+import xml.etree.ElementTree as etree
+import re
+
+
+class AdmonitionExtension(Extension):
+ """ Admonition extension for Python-Markdown. """
+
+ def extendMarkdown(self, md):
+ """ Add Admonition to Markdown instance. """
+ md.registerExtension(self)
+
+ md.parser.blockprocessors.register(AdmonitionProcessor(md.parser), 'admonition', 105)
+
+
+class AdmonitionProcessor(BlockProcessor):
+
+ CLASSNAME = 'admonition'
+ CLASSNAME_TITLE = 'admonition-title'
+ RE = re.compile(r'(?:^|\n)!!! ?([\w\-]+(?: +[\w\-]+)*)(?: +"(.*?)")? *(?:\n|$)')
+ RE_SPACES = re.compile(' +')
+
+ def __init__(self, parser):
+ """Initialization."""
+
+ super().__init__(parser)
+
+ self.current_sibling = None
+ self.content_indention = 0
+
+ def parse_content(self, parent, block):
+ """Get sibling admonition.
+
+ Retrieve the appropriate sibling element. This can get tricky when
+ dealing with lists.
+
+ """
+
+ old_block = block
+ the_rest = ''
+
+ # We already acquired the block via test
+ if self.current_sibling is not None:
+ sibling = self.current_sibling
+ block, the_rest = self.detab(block, self.content_indent)
+ self.current_sibling = None
+ self.content_indent = 0
+ return sibling, block, the_rest
+
+ sibling = self.lastChild(parent)
+
+ if sibling is None or sibling.get('class', '').find(self.CLASSNAME) == -1:
+ sibling = None
+ else:
+ # If the last child is a list and the content is sufficiently indented
+ # to be under it, then the content's sibling is in the list.
+ last_child = self.lastChild(sibling)
+ indent = 0
+ while last_child:
+ if (
+ sibling and block.startswith(' ' * self.tab_length * 2) and
+ last_child and last_child.tag in ('ul', 'ol', 'dl')
+ ):
+
+ # The expectation is that we'll find an <li> or <dt>.
+ # We should get its last child as well.
+ sibling = self.lastChild(last_child)
+ last_child = self.lastChild(sibling) if sibling else None
+
+ # Context has been lost at this point, so we must adjust the
+ # text's indentation level so it will be evaluated correctly
+ # under the list.
+ block = block[self.tab_length:]
+ indent += self.tab_length
+ else:
+ last_child = None
+
+ if not block.startswith(' ' * self.tab_length):
+ sibling = None
+
+ if sibling is not None:
+ indent += self.tab_length
+ block, the_rest = self.detab(old_block, indent)
+ self.current_sibling = sibling
+ self.content_indent = indent
+
+ return sibling, block, the_rest
+
+ def test(self, parent, block):
+
+ if self.RE.search(block):
+ return True
+ else:
+ return self.parse_content(parent, block)[0] is not None
+
+ def run(self, parent, blocks):
+ block = blocks.pop(0)
+ m = self.RE.search(block)
+
+ if m:
+ if m.start() > 0:
+ self.parser.parseBlocks(parent, [block[:m.start()]])
+ block = block[m.end():] # removes the first line
+ block, theRest = self.detab(block)
+ else:
+ sibling, block, theRest = self.parse_content(parent, block)
+
+ if m:
+ klass, title = self.get_class_and_title(m)
+ div = etree.SubElement(parent, 'div')
+ div.set('class', '{} {}'.format(self.CLASSNAME, klass))
+ if title:
+ p = etree.SubElement(div, 'p')
+ p.text = title
+ p.set('class', self.CLASSNAME_TITLE)
+ else:
+ # Sibling is a list item, but we need to wrap it's content should be wrapped in <p>
+ if sibling.tag in ('li', 'dd') and sibling.text:
+ text = sibling.text
+ sibling.text = ''
+ p = etree.SubElement(sibling, 'p')
+ p.text = text
+
+ div = sibling
+
+ self.parser.parseChunk(div, block)
+
+ if theRest:
+ # This block contained unindented line(s) after the first indented
+ # line. Insert these lines as the first block of the master blocks
+ # list for future processing.
+ blocks.insert(0, theRest)
+
+ def get_class_and_title(self, match):
+ klass, title = match.group(1).lower(), match.group(2)
+ klass = self.RE_SPACES.sub(' ', klass)
+ if title is None:
+ # no title was provided, use the capitalized classname as title
+ # e.g.: `!!! note` will render
+ # `<p class="admonition-title">Note</p>`
+ title = klass.split(' ', 1)[0].capitalize()
+ elif title == '':
+ # an explicit blank title should not be rendered
+ # e.g.: `!!! warning ""` will *not* render `p` with a title
+ title = None
+ return klass, title
+
+
+def makeExtension(**kwargs): # pragma: no cover
+ return AdmonitionExtension(**kwargs)
diff --git a/markdown/extensions/attr_list.py b/markdown/extensions/attr_list.py
new file mode 100644
index 0000000..9a67551
--- /dev/null
+++ b/markdown/extensions/attr_list.py
@@ -0,0 +1,166 @@
+"""
+Attribute List Extension for Python-Markdown
+============================================
+
+Adds attribute list syntax. Inspired by
+[maruku](http://maruku.rubyforge.org/proposal.html#attribute_lists)'s
+feature of the same name.
+
+See <https://Python-Markdown.github.io/extensions/attr_list>
+for documentation.
+
+Original code Copyright 2011 [Waylan Limberg](http://achinghead.com/).
+
+All changes Copyright 2011-2014 The Python Markdown Project
+
+License: [BSD](https://opensource.org/licenses/bsd-license.php)
+
+"""
+
+from . import Extension
+from ..treeprocessors import Treeprocessor
+import re
+
+
+def _handle_double_quote(s, t):
+ k, v = t.split('=', 1)
+ return k, v.strip('"')
+
+
+def _handle_single_quote(s, t):
+ k, v = t.split('=', 1)
+ return k, v.strip("'")
+
+
+def _handle_key_value(s, t):
+ return t.split('=', 1)
+
+
+def _handle_word(s, t):
+ if t.startswith('.'):
+ return '.', t[1:]
+ if t.startswith('#'):
+ return 'id', t[1:]
+ return t, t
+
+
+_scanner = re.Scanner([
+ (r'[^ =]+=".*?"', _handle_double_quote),
+ (r"[^ =]+='.*?'", _handle_single_quote),
+ (r'[^ =]+=[^ =]+', _handle_key_value),
+ (r'[^ =]+', _handle_word),
+ (r' ', None)
+])
+
+
+def get_attrs(str):
+ """ Parse attribute list and return a list of attribute tuples. """
+ return _scanner.scan(str)[0]
+
+
+def isheader(elem):
+ return elem.tag in ['h1', 'h2', 'h3', 'h4', 'h5', 'h6']
+
+
+class AttrListTreeprocessor(Treeprocessor):
+
+ BASE_RE = r'\{\:?[ ]*([^\}\n ][^\}\n]*)[ ]*\}'
+ HEADER_RE = re.compile(r'[ ]+{}[ ]*$'.format(BASE_RE))
+ BLOCK_RE = re.compile(r'\n[ ]*{}[ ]*$'.format(BASE_RE))
+ INLINE_RE = re.compile(r'^{}'.format(BASE_RE))
+ NAME_RE = re.compile(r'[^A-Z_a-z\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u02ff'
+ r'\u0370-\u037d\u037f-\u1fff\u200c-\u200d'
+ r'\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff'
+ r'\uf900-\ufdcf\ufdf0-\ufffd'
+ r'\:\-\.0-9\u00b7\u0300-\u036f\u203f-\u2040]+')
+
+ def run(self, doc):
+ for elem in doc.iter():
+ if self.md.is_block_level(elem.tag):
+ # Block level: check for attrs on last line of text
+ RE = self.BLOCK_RE
+ if isheader(elem) or elem.tag in ['dt', 'td', 'th']:
+ # header, def-term, or table cell: check for attrs at end of element
+ RE = self.HEADER_RE
+ if len(elem) and elem.tag == 'li':
+ # special case list items. children may include a ul or ol.
+ pos = None
+ # find the ul or ol position
+ for i, child in enumerate(elem):
+ if child.tag in ['ul', 'ol']:
+ pos = i
+ break
+ if pos is None and elem[-1].tail:
+ # use tail of last child. no ul or ol.
+ m = RE.search(elem[-1].tail)
+ if m:
+ self.assign_attrs(elem, m.group(1))
+ elem[-1].tail = elem[-1].tail[:m.start()]
+ elif pos is not None and pos > 0 and elem[pos-1].tail:
+ # use tail of last child before ul or ol
+ m = RE.search(elem[pos-1].tail)
+ if m:
+ self.assign_attrs(elem, m.group(1))
+ elem[pos-1].tail = elem[pos-1].tail[:m.start()]
+ elif elem.text:
+ # use text. ul is first child.
+ m = RE.search(elem.text)
+ if m:
+ self.assign_attrs(elem, m.group(1))
+ elem.text = elem.text[:m.start()]
+ elif len(elem) and elem[-1].tail:
+ # has children. Get from tail of last child
+ m = RE.search(elem[-1].tail)
+ if m:
+ self.assign_attrs(elem, m.group(1))
+ elem[-1].tail = elem[-1].tail[:m.start()]
+ if isheader(elem):
+ # clean up trailing #s
+ elem[-1].tail = elem[-1].tail.rstrip('#').rstrip()
+ elif elem.text:
+ # no children. Get from text.
+ m = RE.search(elem.text)
+ if m:
+ self.assign_attrs(elem, m.group(1))
+ elem.text = elem.text[:m.start()]
+ if isheader(elem):
+ # clean up trailing #s
+ elem.text = elem.text.rstrip('#').rstrip()
+ else:
+ # inline: check for attrs at start of tail
+ if elem.tail:
+ m = self.INLINE_RE.match(elem.tail)
+ if m:
+ self.assign_attrs(elem, m.group(1))
+ elem.tail = elem.tail[m.end():]
+
+ def assign_attrs(self, elem, attrs):
+ """ Assign attrs to element. """
+ for k, v in get_attrs(attrs):
+ if k == '.':
+ # add to class
+ cls = elem.get('class')
+ if cls:
+ elem.set('class', '{} {}'.format(cls, v))
+ else:
+ elem.set('class', v)
+ else:
+ # assign attr k with v
+ elem.set(self.sanitize_name(k), v)
+
+ def sanitize_name(self, name):
+ """
+ Sanitize name as 'an XML Name, minus the ":"'.
+ See https://www.w3.org/TR/REC-xml-names/#NT-NCName
+ """
+ return self.NAME_RE.sub('_', name)
+
+
+class AttrListExtension(Extension):
+ def extendMarkdown(self, md):
+ md.treeprocessors.register(AttrListTreeprocessor(md), 'attr_list', 8)
+ md.registerExtension(self)
+
+
+def makeExtension(**kwargs): # pragma: no cover
+ return AttrListExtension(**kwargs)
diff --git a/markdown/extensions/codehilite.py b/markdown/extensions/codehilite.py
index c5d496b..a54ba21 100644
--- a/markdown/extensions/codehilite.py
+++ b/markdown/extensions/codehilite.py
@@ -1,156 +1,216 @@
-#!/usr/bin/python
-
"""
CodeHilite Extension for Python-Markdown
========================================
Adds code/syntax highlighting to standard Python-Markdown code blocks.
-Copyright 2006-2008 [Waylan Limberg](http://achinghead.com/).
+See <https://Python-Markdown.github.io/extensions/code_hilite>
+for documentation.
+
+Original code Copyright 2006-2008 [Waylan Limberg](http://achinghead.com/).
+
+All changes Copyright 2008-2014 The Python Markdown Project
-Project website: <http://www.freewisdom.org/project/python-markdown/CodeHilite>
-Contact: markdown@freewisdom.org
-
-License: BSD (see ../docs/LICENSE for details)
-
-Dependencies:
-* [Python 2.3+](http://python.org/)
-* [Markdown 2.0+](http://www.freewisdom.org/projects/python-markdown/)
-* [Pygments](http://pygments.org/)
+License: [BSD](https://opensource.org/licenses/bsd-license.php)
"""
-import markdown
+from . import Extension
+from ..treeprocessors import Treeprocessor
+from ..util import parseBoolValue
+
+try: # pragma: no cover
+ from pygments import highlight
+ from pygments.lexers import get_lexer_by_name, guess_lexer
+ from pygments.formatters import get_formatter_by_name
+ from pygments.util import ClassNotFound
+ pygments = True
+except ImportError: # pragma: no cover
+ pygments = False
+
-# --------------- CONSTANTS YOU MIGHT WANT TO MODIFY -----------------
+def parse_hl_lines(expr):
+ """Support our syntax for emphasizing certain lines of code.
-try:
- TAB_LENGTH = markdown.TAB_LENGTH
-except AttributeError:
- TAB_LENGTH = 4
+ expr should be like '1 2' to emphasize lines 1 and 2 of a code block.
+ Returns a list of ints, the line numbers to emphasize.
+ """
+ if not expr:
+ return []
+
+ try:
+ return list(map(int, expr.split()))
+ except ValueError: # pragma: no cover
+ return []
# ------------------ The Main CodeHilite Class ----------------------
class CodeHilite:
"""
- Determine language of source code, and pass it into the pygments hilighter.
+ Determine language of source code, and pass it on to the Pygments highlighter.
+
+ Usage:
+ code = CodeHilite(src=some_code, lang='python')
+ html = code.hilite()
- Basic Usage:
- >>> code = CodeHilite(src = 'some text')
- >>> html = code.hilite()
-
+ Arguments:
* src: Source string or any object with a .readline attribute.
-
- * linenos: (Boolen) Turn line numbering 'on' or 'off' (off by default).
-
- * css_class: Set class name of wrapper div ('codehilite' by default).
-
- Low Level Usage:
- >>> code = CodeHilite()
- >>> code.src = 'some text' # String or anything with a .readline attr.
- >>> code.linenos = True # True or False; Turns line numbering on or of.
- >>> html = code.hilite()
-
+
+ * lang: String name of Pygments lexer to use for highlighting. Default: `None`.
+
+ * guess_lang: Auto-detect which lexer to use. Ignored if `lang` is set to a valid
+ value. Default: `True`.
+
+ * use_pygments: Pass code to pygments for code highlighting. If `False`, the code is
+ instead wrapped for highlighting by a JavaScript library. Default: `True`.
+
+ * pygments_formatter: The name of a Pygments formatter or a formatter class used for
+ highlighting the code blocks. Default: `html`.
+
+ * linenums: An alias to Pygments `linenos` formatter option. Default: `None`.
+
+ * css_class: An alias to Pygments `cssclass` formatter option. Default: 'codehilite'.
+
+ * lang_prefix: Prefix prepended to the language. Default: "language-".
+
+ Other Options:
+ Any other options are accepted and passed on to the lexer and formatter. Therefore,
+ valid options include any options which are accepted by the `html` formatter or
+ whichever lexer the code's language uses. Note that most lexers do not have any
+ options. However, a few have very useful options, such as PHP's `startinline` option.
+ Any invalid options are ignored without error.
+
+ Formatter options: https://pygments.org/docs/formatters/#HtmlFormatter
+ Lexer Options: https://pygments.org/docs/lexers/
+
+ Additionally, when Pygments is enabled, the code's language is passed to the
+ formatter as an extra option `lang_str`, whose value being `{lang_prefix}{lang}`.
+ This option has no effect to the Pygments's builtin formatters.
+
+ Advanced Usage:
+ code = CodeHilite(
+ src = some_code,
+ lang = 'php',
+ startinline = True, # Lexer option. Snippet does not start with `<?php`.
+ linenostart = 42, # Formatter option. Snippet starts on line 42.
+ hl_lines = [45, 49, 50], # Formatter option. Highlight lines 45, 49, and 50.
+ linenos = 'inline' # Formatter option. Avoid alignment problems.
+ )
+ html = code.hilite()
+
"""
- def __init__(self, src=None, linenos=False, css_class="codehilite"):
+ def __init__(self, src, **options):
self.src = src
- self.lang = None
- self.linenos = linenos
- self.css_class = css_class
-
- def hilite(self):
+ self.lang = options.pop('lang', None)
+ self.guess_lang = options.pop('guess_lang', True)
+ self.use_pygments = options.pop('use_pygments', True)
+ self.lang_prefix = options.pop('lang_prefix', 'language-')
+ self.pygments_formatter = options.pop('pygments_formatter', 'html')
+
+ if 'linenos' not in options:
+ options['linenos'] = options.pop('linenums', None)
+ if 'cssclass' not in options:
+ options['cssclass'] = options.pop('css_class', 'codehilite')
+ if 'wrapcode' not in options:
+ # Override pygments default
+ options['wrapcode'] = True
+ # Disallow use of `full` option
+ options['full'] = False
+
+ self.options = options
+
+ def hilite(self, shebang=True):
"""
- Pass code to the [Pygments](http://pygments.pocoo.org/) highliter with
- optional line numbers. The output should then be styled with css to
- your liking. No styles are applied by default - only styling hooks
- (i.e.: <span class="k">).
+ Pass code to the [Pygments](http://pygments.pocoo.org/) highliter with
+ optional line numbers. The output should then be styled with css to
+ your liking. No styles are applied by default - only styling hooks
+ (i.e.: <span class="k">).
returns : A string of html.
-
+
"""
self.src = self.src.strip('\n')
-
- self._getLang()
-
- try:
- from pygments import highlight
- from pygments.lexers import get_lexer_by_name, guess_lexer, \
- TextLexer
- from pygments.formatters import HtmlFormatter
- except ImportError:
- # just escape and pass through
- txt = self._escape(self.src)
- if self.linenos:
- txt = self._number(txt)
- else :
- txt = '<div class="%s"><pre>%s</pre></div>\n'% \
- (self.css_class, txt)
- return txt
- else:
+
+ if self.lang is None and shebang:
+ self._parseHeader()
+
+ if pygments and self.use_pygments:
try:
- lexer = get_lexer_by_name(self.lang)
+ lexer = get_lexer_by_name(self.lang, **self.options)
except ValueError:
try:
- lexer = guess_lexer(self.src)
- except ValueError:
- lexer = TextLexer()
- formatter = HtmlFormatter(linenos=self.linenos,
- cssclass=self.css_class)
+ if self.guess_lang:
+ lexer = guess_lexer(self.src, **self.options)
+ else:
+ lexer = get_lexer_by_name('text', **self.options)
+ except ValueError: # pragma: no cover
+ lexer = get_lexer_by_name('text', **self.options)
+ if not self.lang:
+ # Use the guessed lexer's language instead
+ self.lang = lexer.aliases[0]
+ lang_str = f'{self.lang_prefix}{self.lang}'
+ if isinstance(self.pygments_formatter, str):
+ try:
+ formatter = get_formatter_by_name(self.pygments_formatter, **self.options)
+ except ClassNotFound:
+ formatter = get_formatter_by_name('html', **self.options)
+ else:
+ formatter = self.pygments_formatter(lang_str=lang_str, **self.options)
return highlight(self.src, lexer, formatter)
-
- def _escape(self, txt):
- """ basic html escaping """
- txt = txt.replace('&', '&amp;')
- txt = txt.replace('<', '&lt;')
- txt = txt.replace('>', '&gt;')
- txt = txt.replace('"', '&quot;')
- return txt
-
- def _number(self, txt):
- """ Use <ol> for line numbering """
- # Fix Whitespace
- txt = txt.replace('\t', ' '*TAB_LENGTH)
- txt = txt.replace(" "*4, "&nbsp; &nbsp; ")
- txt = txt.replace(" "*3, "&nbsp; &nbsp;")
- txt = txt.replace(" "*2, "&nbsp; ")
-
- # Add line numbers
- lines = txt.splitlines()
- txt = '<div class="codehilite"><pre><ol>\n'
- for line in lines:
- txt += '\t<li>%s</li>\n'% line
- txt += '</ol></pre></div>\n'
- return txt
-
-
- def _getLang(self):
- """
- Determines language of a code block from shebang lines and whether said
- line should be removed or left in place. If the sheband line contains a
- path (even a single /) then it is assumed to be a real shebang lines and
- left alone. However, if no path is given (e.i.: #!python or :::python)
- then it is assumed to be a mock shebang for language identifitation of a
- code fragment and removed from the code block prior to processing for
- code highlighting. When a mock shebang (e.i: #!python) is found, line
- numbering is turned on. When colons are found in place of a shebang
- (e.i.: :::python), line numbering is left in the current state - off
- by default.
-
+ else:
+ # just escape and build markup usable by JS highlighting libs
+ txt = self.src.replace('&', '&amp;')
+ txt = txt.replace('<', '&lt;')
+ txt = txt.replace('>', '&gt;')
+ txt = txt.replace('"', '&quot;')
+ classes = []
+ if self.lang:
+ classes.append('{}{}'.format(self.lang_prefix, self.lang))
+ if self.options['linenos']:
+ classes.append('linenums')
+ class_str = ''
+ if classes:
+ class_str = ' class="{}"'.format(' '.join(classes))
+ return '<pre class="{}"><code{}>{}\n</code></pre>\n'.format(
+ self.options['cssclass'],
+ class_str,
+ txt
+ )
+
+ def _parseHeader(self):
+ """
+ Determines language of a code block from shebang line and whether the
+ said line should be removed or left in place. If the sheband line
+ contains a path (even a single /) then it is assumed to be a real
+ shebang line and left alone. However, if no path is given
+ (e.i.: #!python or :::python) then it is assumed to be a mock shebang
+ for language identification of a code fragment and removed from the
+ code block prior to processing for code highlighting. When a mock
+ shebang (e.i: #!python) is found, line numbering is turned on. When
+ colons are found in place of a shebang (e.i.: :::python), line
+ numbering is left in the current state - off by default.
+
+ Also parses optional list of highlight lines, like:
+
+ :::python hl_lines="1 3"
"""
import re
-
- #split text into lines
+
+ # split text into lines
lines = self.src.split("\n")
- #pull first line to examine
+ # pull first line to examine
fl = lines.pop(0)
-
+
c = re.compile(r'''
- (?:(?:::+)|(?P<shebang>[#]!)) # Shebang or 2 or more colons.
- (?P<path>(?:/\w+)*[/ ])? # Zero or 1 path
- (?P<lang>[\w+-]*) # The language
+ (?:(?:^::+)|(?P<shebang>^[#]!)) # Shebang or 2 or more colons
+ (?P<path>(?:/\w+)*[/ ])? # Zero or 1 path
+ (?P<lang>[\w#.+-]*) # The language
+ \s* # Arbitrary whitespace
+ # Optional highlight lines, single- or double-quote-delimited
+ (hl_lines=(?P<quot>"|')(?P<hl_lines>.*?)(?P=quot))?
''', re.VERBOSE)
# search first line for shebang
m = c.search(fl)
@@ -158,67 +218,113 @@ class CodeHilite:
# we have a match
try:
self.lang = m.group('lang').lower()
- except IndexError:
+ except IndexError: # pragma: no cover
self.lang = None
if m.group('path'):
# path exists - restore first line
lines.insert(0, fl)
- if m.group('shebang'):
- # shebang exists - use line numbers
- self.linenos = True
+ if self.options['linenos'] is None and m.group('shebang'):
+ # Overridable and Shebang exists - use line numbers
+ self.options['linenos'] = True
+
+ self.options['hl_lines'] = parse_hl_lines(m.group('hl_lines'))
else:
# No match
lines.insert(0, fl)
-
- self.src = "\n".join(lines).strip("\n")
+ self.src = "\n".join(lines).strip("\n")
# ------------------ The Markdown Extension -------------------------------
-class HiliteTreeprocessor(markdown.treeprocessors.Treeprocessor):
- """ Hilight source code in code blocks. """
+
+
+class HiliteTreeprocessor(Treeprocessor):
+ """ Highlight source code in code blocks. """
+
+ def code_unescape(self, text):
+ """Unescape code."""
+ text = text.replace("&lt;", "<")
+ text = text.replace("&gt;", ">")
+ # Escaped '&' should be replaced at the end to avoid
+ # conflicting with < and >.
+ text = text.replace("&amp;", "&")
+ return text
def run(self, root):
""" Find code blocks and store in htmlStash. """
- blocks = root.getiterator('pre')
+ blocks = root.iter('pre')
for block in blocks:
- children = block.getchildren()
- if len(children) == 1 and children[0].tag == 'code':
- code = CodeHilite(children[0].text,
- linenos=self.config['force_linenos'][0],
- css_class=self.config['css_class'][0])
- placeholder = self.markdown.htmlStash.store(code.hilite(),
- safe=True)
+ if len(block) == 1 and block[0].tag == 'code':
+ local_config = self.config.copy()
+ code = CodeHilite(
+ self.code_unescape(block[0].text),
+ tab_length=self.md.tab_length,
+ style=local_config.pop('pygments_style', 'default'),
+ **local_config
+ )
+ placeholder = self.md.htmlStash.store(code.hilite())
# Clear codeblock in etree instance
block.clear()
- # Change to p element which will later
+ # Change to p element which will later
# be removed when inserting raw html
block.tag = 'p'
block.text = placeholder
-class CodeHiliteExtension(markdown.Extension):
- """ Add source code hilighting to markdown codeblocks. """
+class CodeHiliteExtension(Extension):
+ """ Add source code highlighting to markdown codeblocks. """
- def __init__(self, configs):
+ def __init__(self, **kwargs):
# define default configs
self.config = {
- 'force_linenos' : [False, "Force line numbers - Default: False"],
- 'css_class' : ["codehilite",
- "Set class name for wrapper <div> - Default: codehilite"],
+ 'linenums': [None,
+ "Use lines numbers. True|table|inline=yes, False=no, None=auto"],
+ 'guess_lang': [True,
+ "Automatic language detection - Default: True"],
+ 'css_class': ["codehilite",
+ "Set class name for wrapper <div> - "
+ "Default: codehilite"],
+ 'pygments_style': ['default',
+ 'Pygments HTML Formatter Style '
+ '(Colorscheme) - Default: default'],
+ 'noclasses': [False,
+ 'Use inline styles instead of CSS classes - '
+ 'Default false'],
+ 'use_pygments': [True,
+ 'Use Pygments to Highlight code blocks. '
+ 'Disable if using a JavaScript library. '
+ 'Default: True'],
+ 'lang_prefix': [
+ 'language-',
+ 'Prefix prepended to the language when use_pygments is false. Default: "language-"'
+ ],
+ 'pygments_formatter': ['html',
+ 'Use a specific formatter for Pygments highlighting.'
+ 'Default: "html"',
+ ],
}
-
- # Override defaults with user settings
- for key, value in configs:
- self.setConfig(key, value)
- def extendMarkdown(self, md, md_globals):
+ for key, value in kwargs.items():
+ if key in self.config:
+ self.setConfig(key, value)
+ else:
+ # manually set unknown keywords.
+ if isinstance(value, str):
+ try:
+ # Attempt to parse str as a bool value
+ value = parseBoolValue(value, preserve_none=True)
+ except ValueError:
+ pass # Assume it's not a bool value. Use as-is.
+ self.config[key] = [value, '']
+
+ def extendMarkdown(self, md):
""" Add HilitePostprocessor to Markdown instance. """
hiliter = HiliteTreeprocessor(md)
- hiliter.config = self.config
- md.treeprocessors.add("hilite", hiliter, "_begin")
+ hiliter.config = self.getConfigs()
+ md.treeprocessors.register(hiliter, 'hilite', 30)
+ md.registerExtension(self)
-def makeExtension(configs={}):
- return CodeHiliteExtension(configs=configs)
+def makeExtension(**kwargs): # pragma: no cover
+ return CodeHiliteExtension(**kwargs)
diff --git a/markdown/extensions/def_list.py b/markdown/extensions/def_list.py
index 73a1c85..17549f0 100644
--- a/markdown/extensions/def_list.py
+++ b/markdown/extensions/def_list.py
@@ -1,61 +1,71 @@
-#!/usr/bin/env Python
"""
Definition List Extension for Python-Markdown
=============================================
-Added parsing of Definition Lists to Python-Markdown.
+Adds parsing of Definition Lists to Python-Markdown.
-A simple example:
+See <https://Python-Markdown.github.io/extensions/definition_lists>
+for documentation.
- Apple
- : Pomaceous fruit of plants of the genus Malus in
- the family Rosaceae.
- : An american computer company.
+Original code Copyright 2008 [Waylan Limberg](http://achinghead.com)
- Orange
- : The fruit of an evergreen tree of the genus Citrus.
+All changes Copyright 2008-2014 The Python Markdown Project
-Copyright 2008 - [Waylan Limberg](http://achinghead.com)
+License: [BSD](https://opensource.org/licenses/bsd-license.php)
"""
-import markdown, re
-from markdown import etree
+from . import Extension
+from ..blockprocessors import BlockProcessor, ListIndentProcessor
+import xml.etree.ElementTree as etree
+import re
-class DefListProcessor(markdown.blockprocessors.BlockProcessor):
+class DefListProcessor(BlockProcessor):
""" Process Definition Lists. """
RE = re.compile(r'(^|\n)[ ]{0,3}:[ ]{1,3}(.*?)(\n|$)')
+ NO_INDENT_RE = re.compile(r'^[ ]{0,3}[^ :]')
def test(self, parent, block):
return bool(self.RE.search(block))
def run(self, parent, blocks):
- block = blocks.pop(0)
- m = self.RE.search(block)
- terms = [l.strip() for l in block[:m.start()].split('\n') if l.strip()]
- d, theRest = self.detab(block[m.end():])
+
+ raw_block = blocks.pop(0)
+ m = self.RE.search(raw_block)
+ terms = [term.strip() for term in
+ raw_block[:m.start()].split('\n') if term.strip()]
+ block = raw_block[m.end():]
+ no_indent = self.NO_INDENT_RE.match(block)
+ if no_indent:
+ d, theRest = (block, None)
+ else:
+ d, theRest = self.detab(block)
if d:
- d = '%s\n%s' % (m.group(2), d)
+ d = '{}\n{}'.format(m.group(2), d)
else:
d = m.group(2)
- #import ipdb; ipdb.set_trace()
sibling = self.lastChild(parent)
+ if not terms and sibling is None:
+ # This is not a definition item. Most likely a paragraph that
+ # starts with a colon at the beginning of a document or list.
+ blocks.insert(0, raw_block)
+ return False
if not terms and sibling.tag == 'p':
# The previous paragraph contains the terms
state = 'looselist'
terms = sibling.text.split('\n')
parent.remove(sibling)
- # Aquire new sibling
+ # Acquire new sibling
sibling = self.lastChild(parent)
else:
state = 'list'
- if sibling and sibling.tag == 'dl':
+ if sibling is not None and sibling.tag == 'dl':
# This is another item on an existing list
dl = sibling
- if len(dl) and dl[-1].tag == 'dd' and len(dl[-1]):
+ if not terms and len(dl) and dl[-1].tag == 'dd' and len(dl[-1]):
state = 'looselist'
else:
# This is a new list
@@ -73,32 +83,29 @@ class DefListProcessor(markdown.blockprocessors.BlockProcessor):
if theRest:
blocks.insert(0, theRest)
-class DefListIndentProcessor(markdown.blockprocessors.ListIndentProcessor):
+
+class DefListIndentProcessor(ListIndentProcessor):
""" Process indented children of definition list items. """
- ITEM_TYPES = ['dd']
- LIST_TYPES = ['dl']
+ # Definition lists need to be aware of all list types
+ ITEM_TYPES = ['dd', 'li']
+ LIST_TYPES = ['dl', 'ol', 'ul']
- def create_item(parent, block):
- """ Create a new dd and parse the block with it as the parent. """
- dd = markdown.etree.SubElement(parent, 'dd')
+ def create_item(self, parent, block):
+ """ Create a new dd or li (depending on parent) and parse the block with it as the parent. """
+
+ dd = etree.SubElement(parent, 'dd')
self.parser.parseBlocks(dd, [block])
-
-class DefListExtension(markdown.Extension):
+class DefListExtension(Extension):
""" Add definition lists to Markdown. """
- def extendMarkdown(self, md, md_globals):
+ def extendMarkdown(self, md):
""" Add an instance of DefListProcessor to BlockParser. """
- md.parser.blockprocessors.add('defindent',
- DefListIndentProcessor(md.parser),
- '>indent')
- md.parser.blockprocessors.add('deflist',
- DefListProcessor(md.parser),
- '>ulist')
-
+ md.parser.blockprocessors.register(DefListIndentProcessor(md.parser), 'defindent', 85)
+ md.parser.blockprocessors.register(DefListProcessor(md.parser), 'deflist', 25)
-def makeExtension(configs={}):
- return DefListExtension(configs=configs)
+def makeExtension(**kwargs): # pragma: no cover
+ return DefListExtension(**kwargs)
diff --git a/markdown/extensions/extra.py b/markdown/extensions/extra.py
index 4a2ffbf..909ba07 100644
--- a/markdown/extensions/extra.py
+++ b/markdown/extensions/extra.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
"""
Python-Markdown Extra Extension
===============================
@@ -7,43 +6,53 @@ A compilation of various Python-Markdown extensions that imitates
[PHP Markdown Extra](http://michelf.com/projects/php-markdown/extra/).
Note that each of the individual extensions still need to be available
-on your PYTHONPATH. This extension simply wraps them all up as a
+on your PYTHONPATH. This extension simply wraps them all up as a
convenience so that only one extension needs to be listed when
initiating Markdown. See the documentation for each individual
extension for specifics about that extension.
-In the event that one or more of the supported extensions are not
-available for import, Markdown will issue a warning and simply continue
-without that extension.
-
-There may be additional extensions that are distributed with
+There may be additional extensions that are distributed with
Python-Markdown that are not included here in Extra. Those extensions
are not part of PHP Markdown Extra, and therefore, not part of
Python-Markdown Extra. If you really would like Extra to include
additional extensions, we suggest creating your own clone of Extra
-under a differant name. You could also edit the `extensions` global
-variable defined below, but be aware that such changes may be lost
+under a different name. You could also edit the `extensions` global
+variable defined below, but be aware that such changes may be lost
when you upgrade to any future version of Python-Markdown.
+See <https://Python-Markdown.github.io/extensions/extra>
+for documentation.
+
+Copyright The Python Markdown Project
+
+License: [BSD](https://opensource.org/licenses/bsd-license.php)
+
"""
-import markdown
+from . import Extension
-extensions = ['fenced_code',
- 'footnotes',
- 'headerid',
- 'def_list',
- 'tables',
- 'abbr',
- ]
-
+extensions = [
+ 'fenced_code',
+ 'footnotes',
+ 'attr_list',
+ 'def_list',
+ 'tables',
+ 'abbr',
+ 'md_in_html'
+]
-class ExtraExtension(markdown.Extension):
+
+class ExtraExtension(Extension):
""" Add various extensions to Markdown class."""
- def extendMarkdown(self, md, md_globals):
+ def __init__(self, **kwargs):
+ """ config is a dumb holder which gets passed to actual ext later. """
+ self.config = kwargs
+
+ def extendMarkdown(self, md):
""" Register extension instances. """
md.registerExtensions(extensions, self.config)
-def makeExtension(configs={}):
- return ExtraExtension(configs=dict(configs))
+
+def makeExtension(**kwargs): # pragma: no cover
+ return ExtraExtension(**kwargs)
diff --git a/markdown/extensions/fenced_code.py b/markdown/extensions/fenced_code.py
index 307b1dc..409166a 100644
--- a/markdown/extensions/fenced_code.py
+++ b/markdown/extensions/fenced_code.py
@@ -1,104 +1,166 @@
-#!/usr/bin/env python
-
"""
Fenced Code Extension for Python Markdown
=========================================
This extension adds Fenced Code Blocks to Python-Markdown.
- >>> import markdown
- >>> text = '''
- ... A paragraph before a fenced code block:
- ...
- ... ~~~
- ... Fenced code block
- ... ~~~
- ... '''
- >>> html = markdown.markdown(text, extensions=['fenced_code'])
- >>> html
- u'<p>A paragraph before a fenced code block:</p>\\n<pre><code>Fenced code block\\n</code></pre>'
-
-Works with safe_mode also (we check this because we are using the HtmlStash):
-
- >>> markdown.markdown(text, extensions=['fenced_code'], safe_mode='replace')
- u'<p>A paragraph before a fenced code block:</p>\\n<pre><code>Fenced code block\\n</code></pre>'
-
-Include tilde's in a code block and wrap with blank lines:
-
- >>> text = '''
- ... ~~~~~~~~
- ...
- ... ~~~~
- ...
- ... ~~~~~~~~'''
- >>> markdown.markdown(text, extensions=['fenced_code'])
- u'<pre><code>\\n~~~~\\n\\n</code></pre>'
-
-Multiple blocks and language tags:
-
- >>> text = '''
- ... ~~~~{.python}
- ... block one
- ... ~~~~
- ...
- ... ~~~~.html
- ... <p>block two</p>
- ... ~~~~'''
- >>> markdown.markdown(text, extensions=['fenced_code'])
- u'<pre><code class="python">block one\\n</code></pre>\\n\\n<pre><code class="html">&lt;p&gt;block two&lt;/p&gt;\\n</code></pre>'
-
-Copyright 2007-2008 [Waylan Limberg](http://achinghead.com/).
-
-Project website: <http://www.freewisdom.org/project/python-markdown/Fenced__Code__Blocks>
-Contact: markdown@freewisdom.org
-
-License: BSD (see ../docs/LICENSE for details)
-
-Dependencies:
-* [Python 2.3+](http://python.org)
-* [Markdown 2.0+](http://www.freewisdom.org/projects/python-markdown/)
+See <https://Python-Markdown.github.io/extensions/fenced_code_blocks>
+for documentation.
+
+Original code Copyright 2007-2008 [Waylan Limberg](http://achinghead.com/).
+
+
+All changes Copyright 2008-2014 The Python Markdown Project
+License: [BSD](https://opensource.org/licenses/bsd-license.php)
"""
-import markdown, re
-# Global vars
-FENCED_BLOCK_RE = re.compile( \
- r'(?P<fence>^~{3,})[ ]*(\{?\.(?P<lang>[a-zA-Z0-9_-]*)\}?)?[ ]*\n(?P<code>.*?)(?P=fence)[ ]*$',
- re.MULTILINE|re.DOTALL
- )
-CODE_WRAP = '<pre><code%s>%s</code></pre>'
-LANG_TAG = ' class="%s"'
+from textwrap import dedent
+from . import Extension
+from ..preprocessors import Preprocessor
+from .codehilite import CodeHilite, CodeHiliteExtension, parse_hl_lines
+from .attr_list import get_attrs, AttrListExtension
+from ..util import parseBoolValue
+from ..serializers import _escape_attrib_html
+import re
-class FencedCodeExtension(markdown.Extension):
+class FencedCodeExtension(Extension):
+ def __init__(self, **kwargs):
+ self.config = {
+ 'lang_prefix': ['language-', 'Prefix prepended to the language. Default: "language-"']
+ }
+ super().__init__(**kwargs)
- def extendMarkdown(self, md, md_globals):
+ def extendMarkdown(self, md):
""" Add FencedBlockPreprocessor to the Markdown instance. """
+ md.registerExtension(self)
+
+ md.preprocessors.register(FencedBlockPreprocessor(md, self.getConfigs()), 'fenced_code_block', 25)
+
+
+class FencedBlockPreprocessor(Preprocessor):
+ FENCED_BLOCK_RE = re.compile(
+ dedent(r'''
+ (?P<fence>^(?:~{3,}|`{3,}))[ ]* # opening fence
+ ((\{(?P<attrs>[^\}\n]*)\})| # (optional {attrs} or
+ (\.?(?P<lang>[\w#.+-]*)[ ]*)? # optional (.)lang
+ (hl_lines=(?P<quot>"|')(?P<hl_lines>.*?)(?P=quot)[ ]*)?) # optional hl_lines)
+ \n # newline (end of opening fence)
+ (?P<code>.*?)(?<=\n) # the code block
+ (?P=fence)[ ]*$ # closing fence
+ '''),
+ re.MULTILINE | re.DOTALL | re.VERBOSE
+ )
- md.preprocessors.add('fenced_code_block',
- FencedBlockPreprocessor(md),
- "_begin")
-
+ def __init__(self, md, config):
+ super().__init__(md)
+ self.config = config
+ self.checked_for_deps = False
+ self.codehilite_conf = {}
+ self.use_attr_list = False
+ # List of options to convert to bool values
+ self.bool_options = [
+ 'linenums',
+ 'guess_lang',
+ 'noclasses',
+ 'use_pygments'
+ ]
-class FencedBlockPreprocessor(markdown.preprocessors.Preprocessor):
-
def run(self, lines):
""" Match and store Fenced Code Blocks in the HtmlStash. """
+
+ # Check for dependent extensions
+ if not self.checked_for_deps:
+ for ext in self.md.registeredExtensions:
+ if isinstance(ext, CodeHiliteExtension):
+ self.codehilite_conf = ext.getConfigs()
+ if isinstance(ext, AttrListExtension):
+ self.use_attr_list = True
+
+ self.checked_for_deps = True
+
text = "\n".join(lines)
while 1:
- m = FENCED_BLOCK_RE.search(text)
+ m = self.FENCED_BLOCK_RE.search(text)
if m:
- lang = ''
- if m.group('lang'):
- lang = LANG_TAG % m.group('lang')
- code = CODE_WRAP % (lang, self._escape(m.group('code')))
- placeholder = self.markdown.htmlStash.store(code, safe=True)
- text = '%s\n%s\n%s'% (text[:m.start()], placeholder, text[m.end():])
+ lang, id, classes, config = None, '', [], {}
+ if m.group('attrs'):
+ id, classes, config = self.handle_attrs(get_attrs(m.group('attrs')))
+ if len(classes):
+ lang = classes.pop(0)
+ else:
+ if m.group('lang'):
+ lang = m.group('lang')
+ if m.group('hl_lines'):
+ # Support hl_lines outside of attrs for backward-compatibility
+ config['hl_lines'] = parse_hl_lines(m.group('hl_lines'))
+
+ # If config is not empty, then the codehighlite extension
+ # is enabled, so we call it to highlight the code
+ if self.codehilite_conf and self.codehilite_conf['use_pygments'] and config.get('use_pygments', True):
+ local_config = self.codehilite_conf.copy()
+ local_config.update(config)
+ # Combine classes with cssclass. Ensure cssclass is at end
+ # as pygments appends a suffix under certain circumstances.
+ # Ignore ID as Pygments does not offer an option to set it.
+ if classes:
+ local_config['css_class'] = '{} {}'.format(
+ ' '.join(classes),
+ local_config['css_class']
+ )
+ highliter = CodeHilite(
+ m.group('code'),
+ lang=lang,
+ style=local_config.pop('pygments_style', 'default'),
+ **local_config
+ )
+
+ code = highliter.hilite(shebang=False)
+ else:
+ id_attr = lang_attr = class_attr = kv_pairs = ''
+ if lang:
+ prefix = self.config.get('lang_prefix', 'language-')
+ lang_attr = f' class="{prefix}{_escape_attrib_html(lang)}"'
+ if classes:
+ class_attr = f' class="{_escape_attrib_html(" ".join(classes))}"'
+ if id:
+ id_attr = f' id="{_escape_attrib_html(id)}"'
+ if self.use_attr_list and config and not config.get('use_pygments', False):
+ # Only assign key/value pairs to code element if attr_list ext is enabled, key/value pairs
+ # were defined on the code block, and the `use_pygments` key was not set to True. The
+ # `use_pygments` key could be either set to False or not defined. It is omitted from output.
+ kv_pairs = ''.join(
+ f' {k}="{_escape_attrib_html(v)}"' for k, v in config.items() if k != 'use_pygments'
+ )
+ code = self._escape(m.group('code'))
+ code = f'<pre{id_attr}{class_attr}><code{lang_attr}{kv_pairs}>{code}</code></pre>'
+
+ placeholder = self.md.htmlStash.store(code)
+ text = f'{text[:m.start()]}\n{placeholder}\n{text[m.end():]}'
else:
break
return text.split("\n")
+ def handle_attrs(self, attrs):
+ """ Return tuple: (id, [list, of, classes], {configs}) """
+ id = ''
+ classes = []
+ configs = {}
+ for k, v in attrs:
+ if k == 'id':
+ id = v
+ elif k == '.':
+ classes.append(v)
+ elif k == 'hl_lines':
+ configs[k] = parse_hl_lines(v)
+ elif k in self.bool_options:
+ configs[k] = parseBoolValue(v, fail_on_errors=False, preserve_none=True)
+ else:
+ configs[k] = v
+ return id, classes, configs
+
def _escape(self, txt):
""" basic html escaping """
txt = txt.replace('&', '&amp;')
@@ -108,10 +170,5 @@ class FencedBlockPreprocessor(markdown.preprocessors.Preprocessor):
return txt
-def makeExtension(configs=None):
- return FencedCodeExtension()
-
-
-if __name__ == "__main__":
- import doctest
- doctest.testmod()
+def makeExtension(**kwargs): # pragma: no cover
+ return FencedCodeExtension(**kwargs)
diff --git a/markdown/extensions/footnotes.py b/markdown/extensions/footnotes.py
index e1a9cda..96ed5c2 100644
--- a/markdown/extensions/footnotes.py
+++ b/markdown/extensions/footnotes.py
@@ -1,81 +1,126 @@
"""
-========================= FOOTNOTES =================================
+Footnotes Extension for Python-Markdown
+=======================================
-This section adds footnote handling to markdown. It can be used as
-an example for extending python-markdown with relatively complex
-functionality. While in this case the extension is included inside
-the module itself, it could just as easily be added from outside the
-module. Not that all markdown classes above are ignorant about
-footnotes. All footnote functionality is provided separately and
-then added to the markdown instance at the run time.
+Adds footnote handling to Python-Markdown.
-Footnote functionality is attached by calling extendMarkdown()
-method of FootnoteExtension. The method also registers the
-extension to allow it's state to be reset by a call to reset()
-method.
+See <https://Python-Markdown.github.io/extensions/footnotes>
+for documentation.
-Example:
- Footnotes[^1] have a label[^label] and a definition[^!DEF].
+Copyright The Python Markdown Project
- [^1]: This is a footnote
- [^label]: A footnote on "label"
- [^!DEF]: The footnote for definition
+License: [BSD](https://opensource.org/licenses/bsd-license.php)
"""
-import re, markdown
-from markdown import etree
+from . import Extension
+from ..blockprocessors import BlockProcessor
+from ..inlinepatterns import InlineProcessor
+from ..treeprocessors import Treeprocessor
+from ..postprocessors import Postprocessor
+from .. import util
+from collections import OrderedDict
+import re
+import copy
+import xml.etree.ElementTree as etree
-FN_BACKLINK_TEXT = "zz1337820767766393qq"
-NBSP_PLACEHOLDER = "qq3936677670287331zz"
-DEF_RE = re.compile(r'(\ ?\ ?\ ?)\[\^([^\]]*)\]:\s*(.*)')
-TABBED_RE = re.compile(r'((\t)|( ))(.*)')
+FN_BACKLINK_TEXT = util.STX + "zz1337820767766393qq" + util.ETX
+NBSP_PLACEHOLDER = util.STX + "qq3936677670287331zz" + util.ETX
+RE_REF_ID = re.compile(r'(fnref)(\d+)')
-class FootnoteExtension(markdown.Extension):
+
+class FootnoteExtension(Extension):
""" Footnote Extension. """
- def __init__ (self, configs):
+ def __init__(self, **kwargs):
""" Setup configs. """
- self.config = {'PLACE_MARKER':
- ["///Footnotes Go Here///",
- "The text string that marks where the footnotes go"],
- 'UNIQUE_IDS':
- [False,
- "Avoid name collisions across "
- "multiple calls to reset()."]}
- for key, value in configs:
- self.config[key][0] = value
+ self.config = {
+ 'PLACE_MARKER':
+ ["///Footnotes Go Here///",
+ "The text string that marks where the footnotes go"],
+ 'UNIQUE_IDS':
+ [False,
+ "Avoid name collisions across "
+ "multiple calls to reset()."],
+ "BACKLINK_TEXT":
+ ["&#8617;",
+ "The text string that links from the footnote "
+ "to the reader's place."],
+ "SUPERSCRIPT_TEXT":
+ ["{}",
+ "The text string that links from the reader's place "
+ "to the footnote."],
+ "BACKLINK_TITLE":
+ ["Jump back to footnote %d in the text",
+ "The text string used for the title HTML attribute "
+ "of the backlink. %d will be replaced by the "
+ "footnote number."],
+ "SEPARATOR":
+ [":",
+ "Footnote separator."]
+ }
+ super().__init__(**kwargs)
# In multiple invocations, emit links that don't get tangled.
self.unique_prefix = 0
+ self.found_refs = {}
+ self.used_refs = set()
self.reset()
- def extendMarkdown(self, md, md_globals):
+ def extendMarkdown(self, md):
""" Add pieces to Markdown. """
md.registerExtension(self)
self.parser = md.parser
- # Insert a preprocessor before ReferencePreprocessor
- md.preprocessors.add("footnote", FootnotePreprocessor(self),
- "<reference")
+ self.md = md
+ # Insert a blockprocessor before ReferencePreprocessor
+ md.parser.blockprocessors.register(FootnoteBlockProcessor(self), 'footnote', 17)
+
# Insert an inline pattern before ImageReferencePattern
- FOOTNOTE_RE = r'\[\^([^\]]*)\]' # blah blah [^1] blah
- md.inlinePatterns.add("footnote", FootnotePattern(FOOTNOTE_RE, self),
- "<reference")
+ FOOTNOTE_RE = r'\[\^([^\]]*)\]' # blah blah [^1] blah
+ md.inlinePatterns.register(FootnoteInlineProcessor(FOOTNOTE_RE, self), 'footnote', 175)
# Insert a tree-processor that would actually add the footnote div
- # This must be before the inline treeprocessor so inline patterns
- # run on the contents of the div.
- md.treeprocessors.add("footnote", FootnoteTreeprocessor(self),
- "<inline")
- # Insert a postprocessor after amp_substitute oricessor
- md.postprocessors.add("footnote", FootnotePostprocessor(self),
- ">amp_substitute")
+ # This must be before all other treeprocessors (i.e., inline and
+ # codehilite) so they can run on the the contents of the div.
+ md.treeprocessors.register(FootnoteTreeprocessor(self), 'footnote', 50)
+
+ # Insert a tree-processor that will run after inline is done.
+ # In this tree-processor we want to check our duplicate footnote tracker
+ # And add additional backrefs to the footnote pointing back to the
+ # duplicated references.
+ md.treeprocessors.register(FootnotePostTreeprocessor(self), 'footnote-duplicate', 15)
+
+ # Insert a postprocessor after amp_substitute processor
+ md.postprocessors.register(FootnotePostprocessor(self), 'footnote', 25)
def reset(self):
- """ Clear the footnotes on reset, and prepare for a distinct document. """
- self.footnotes = markdown.odict.OrderedDict()
+ """ Clear footnotes on reset, and prepare for distinct document. """
+ self.footnotes = OrderedDict()
self.unique_prefix += 1
+ self.found_refs = {}
+ self.used_refs = set()
+
+ def unique_ref(self, reference, found=False):
+ """ Get a unique reference if there are duplicates. """
+ if not found:
+ return reference
+
+ original_ref = reference
+ while reference in self.used_refs:
+ ref, rest = reference.split(self.get_separator(), 1)
+ m = RE_REF_ID.match(ref)
+ if m:
+ reference = '%s%d%s%s' % (m.group(1), int(m.group(2))+1, self.get_separator(), rest)
+ else:
+ reference = '%s%d%s%s' % (ref, 2, self.get_separator(), rest)
+
+ self.used_refs.add(reference)
+ if original_ref in self.found_refs:
+ self.found_refs[original_ref] += 1
+ else:
+ self.found_refs[original_ref] = 1
+ return reference
def findFootnotesPlaceholder(self, root):
""" Return ElementTree Element that contains Footnote placeholder. """
@@ -83,13 +128,15 @@ class FootnoteExtension(markdown.Extension):
for child in element:
if child.text:
if child.text.find(self.getConfig("PLACE_MARKER")) > -1:
- return child, True
+ return child, element, True
if child.tail:
if child.tail.find(self.getConfig("PLACE_MARKER")) > -1:
- return (child, element), False
- finder(child)
+ return child, element, False
+ child_res = finder(child)
+ if child_res is not None:
+ return child_res
return None
-
+
res = finder(root)
return res
@@ -97,43 +144,59 @@ class FootnoteExtension(markdown.Extension):
""" Store a footnote for later retrieval. """
self.footnotes[id] = text
+ def get_separator(self):
+ """ Get the footnote separator. """
+ return self.getConfig("SEPARATOR")
+
def makeFootnoteId(self, id):
""" Return footnote link id. """
if self.getConfig("UNIQUE_IDS"):
- return 'fn:%d-%s' % (self.unique_prefix, id)
+ return 'fn%s%d-%s' % (self.get_separator(), self.unique_prefix, id)
else:
- return 'fn:%s' % id
+ return 'fn{}{}'.format(self.get_separator(), id)
- def makeFootnoteRefId(self, id):
+ def makeFootnoteRefId(self, id, found=False):
""" Return footnote back-link id. """
if self.getConfig("UNIQUE_IDS"):
- return 'fnref:%d-%s' % (self.unique_prefix, id)
+ return self.unique_ref('fnref%s%d-%s' % (self.get_separator(), self.unique_prefix, id), found)
else:
- return 'fnref:%s' % id
+ return self.unique_ref('fnref{}{}'.format(self.get_separator(), id), found)
def makeFootnotesDiv(self, root):
""" Return div of footnotes as et Element. """
- if not self.footnotes.keys():
+ if not list(self.footnotes.keys()):
return None
div = etree.Element("div")
div.set('class', 'footnote')
- hr = etree.SubElement(div, "hr")
+ etree.SubElement(div, "hr")
ol = etree.SubElement(div, "ol")
+ surrogate_parent = etree.Element("div")
+
+ # Backward compatibility with old '%d' placeholder
+ backlink_title = self.getConfig("BACKLINK_TITLE").replace("%d", "{}")
- for id in self.footnotes.keys():
+ for index, id in enumerate(self.footnotes.keys(), start=1):
li = etree.SubElement(ol, "li")
li.set("id", self.makeFootnoteId(id))
- self.parser.parseChunk(li, self.footnotes[id])
+ # Parse footnote with surrogate parent as li cannot be used.
+ # List block handlers have special logic to deal with li.
+ # When we are done parsing, we will copy everything over to li.
+ self.parser.parseChunk(surrogate_parent, self.footnotes[id])
+ for el in list(surrogate_parent):
+ li.append(el)
+ surrogate_parent.remove(el)
backlink = etree.Element("a")
backlink.set("href", "#" + self.makeFootnoteRefId(id))
- backlink.set("rev", "footnote")
- backlink.set("title", "Jump back to footnote %d in the text" % \
- (self.footnotes.index(id)+1))
+ backlink.set("class", "footnote-backref")
+ backlink.set(
+ "title",
+ backlink_title.format(index)
+ )
backlink.text = FN_BACKLINK_TEXT
- if li.getchildren():
+ if len(li):
node = li[-1]
if node.tag == "p":
node.text = node.text + NBSP_PLACEHOLDER
@@ -144,164 +207,205 @@ class FootnoteExtension(markdown.Extension):
return div
-class FootnotePreprocessor(markdown.preprocessors.Preprocessor):
+class FootnoteBlockProcessor(BlockProcessor):
""" Find all footnote references and store for later use. """
- def __init__ (self, footnotes):
- self.footnotes = footnotes
-
- def run(self, lines):
- lines = self._handleFootnoteDefinitions(lines)
- text = "\n".join(lines)
- return text.split("\n")
+ RE = re.compile(r'^[ ]{0,3}\[\^([^\]]*)\]:[ ]*(.*)$', re.MULTILINE)
- def _handleFootnoteDefinitions(self, lines):
- """
- Recursively find all footnote definitions in lines.
-
- Keywords:
+ def __init__(self, footnotes):
+ super().__init__(footnotes.parser)
+ self.footnotes = footnotes
- * lines: A list of lines of text
-
- Return: A list of lines with footnote definitions removed.
-
- """
- i, id, footnote = self._findFootnoteDefinition(lines)
-
- if id :
- plain = lines[:i]
- detabbed, theRest = self.detectTabbed(lines[i+1:])
- self.footnotes.setFootnote(id,
- footnote + "\n"
- + "\n".join(detabbed))
- more_plain = self._handleFootnoteDefinitions(theRest)
- return plain + [""] + more_plain
- else :
- return lines
-
- def _findFootnoteDefinition(self, lines):
- """
- Find the parts of a footnote definition.
+ def test(self, parent, block):
+ return True
+
+ def run(self, parent, blocks):
+ """ Find, set, and remove footnote definitions. """
+ block = blocks.pop(0)
+ m = self.RE.search(block)
+ if m:
+ id = m.group(1)
+ fn_blocks = [m.group(2)]
+
+ # Handle rest of block
+ therest = block[m.end():].lstrip('\n')
+ m2 = self.RE.search(therest)
+ if m2:
+ # Another footnote exists in the rest of this block.
+ # Any content before match is continuation of this footnote, which may be lazily indented.
+ before = therest[:m2.start()].rstrip('\n')
+ fn_blocks[0] = '\n'.join([fn_blocks[0], self.detab(before)]).lstrip('\n')
+ # Add back to blocks everything from beginning of match forward for next iteration.
+ blocks.insert(0, therest[m2.start():])
+ else:
+ # All remaining lines of block are continuation of this footnote, which may be lazily indented.
+ fn_blocks[0] = '\n'.join([fn_blocks[0], self.detab(therest)]).strip('\n')
- Keywords:
+ # Check for child elements in remaining blocks.
+ fn_blocks.extend(self.detectTabbed(blocks))
- * lines: A list of lines of text.
+ footnote = "\n\n".join(fn_blocks)
+ self.footnotes.setFootnote(id, footnote.rstrip())
- Return: A three item tuple containing the index of the first line of a
- footnote definition, the id of the definition and the body of the
- definition.
-
- """
- counter = 0
- for line in lines:
- m = DEF_RE.match(line)
- if m:
- return counter, m.group(2), m.group(3)
- counter += 1
- return counter, None, None
+ if block[:m.start()].strip():
+ # Add any content before match back to blocks as separate block
+ blocks.insert(0, block[:m.start()].rstrip('\n'))
+ return True
+ # No match. Restore block.
+ blocks.insert(0, block)
+ return False
- def detectTabbed(self, lines):
+ def detectTabbed(self, blocks):
""" Find indented text and remove indent before further proccesing.
- Keyword arguments:
-
- * lines: an array of strings
-
- Returns: a list of post processed items and the unused
- remainder of the original list
-
+ Returns: a list of blocks with indentation removed.
"""
- items = []
- item = -1
- i = 0 # to keep track of where we are
-
- def detab(line):
- match = TABBED_RE.match(line)
- if match:
- return match.group(4)
-
- for line in lines:
- if line.strip(): # Non-blank line
- line = detab(line)
- if line:
- items.append(line)
- i += 1
- continue
- else:
- return items, lines[i:]
-
- else: # Blank line: _maybe_ we are done.
- i += 1 # advance
-
- # Find the next non-blank line
- for j in range(i, len(lines)):
- if lines[j].strip():
- next_line = lines[j]; break
+ fn_blocks = []
+ while blocks:
+ if blocks[0].startswith(' '*4):
+ block = blocks.pop(0)
+ # Check for new footnotes within this block and split at new footnote.
+ m = self.RE.search(block)
+ if m:
+ # Another footnote exists in this block.
+ # Any content before match is continuation of this footnote, which may be lazily indented.
+ before = block[:m.start()].rstrip('\n')
+ fn_blocks.append(self.detab(before))
+ # Add back to blocks everything from beginning of match forward for next iteration.
+ blocks.insert(0, block[m.start():])
+ # End of this footnote.
+ break
else:
- break # There is no more text; we are done.
+ # Entire block is part of this footnote.
+ fn_blocks.append(self.detab(block))
+ else:
+ # End of this footnote.
+ break
+ return fn_blocks
- # Check if the next non-blank line is tabbed
- if detab(next_line): # Yes, more work to do.
- items.append("")
- continue
- else:
- break # No, we are done.
- else:
- i += 1
+ def detab(self, block):
+ """ Remove one level of indent from a block.
- return items, lines[i:]
+ Preserve lazily indented blocks by only removing indent from indented lines.
+ """
+ lines = block.split('\n')
+ for i, line in enumerate(lines):
+ if line.startswith(' '*4):
+ lines[i] = line[4:]
+ return '\n'.join(lines)
-class FootnotePattern(markdown.inlinepatterns.Pattern):
+class FootnoteInlineProcessor(InlineProcessor):
""" InlinePattern for footnote markers in a document's body text. """
def __init__(self, pattern, footnotes):
- markdown.inlinepatterns.Pattern.__init__(self, pattern)
+ super().__init__(pattern)
self.footnotes = footnotes
- def handleMatch(self, m):
- sup = etree.Element("sup")
- a = etree.SubElement(sup, "a")
- id = m.group(2)
- sup.set('id', self.footnotes.makeFootnoteRefId(id))
- a.set('href', '#' + self.footnotes.makeFootnoteId(id))
- a.set('rel', 'footnote')
- a.text = str(self.footnotes.footnotes.index(id) + 1)
- return sup
+ def handleMatch(self, m, data):
+ id = m.group(1)
+ if id in self.footnotes.footnotes.keys():
+ sup = etree.Element("sup")
+ a = etree.SubElement(sup, "a")
+ sup.set('id', self.footnotes.makeFootnoteRefId(id, found=True))
+ a.set('href', '#' + self.footnotes.makeFootnoteId(id))
+ a.set('class', 'footnote-ref')
+ a.text = self.footnotes.getConfig("SUPERSCRIPT_TEXT").format(
+ list(self.footnotes.footnotes.keys()).index(id) + 1
+ )
+ return sup, m.start(0), m.end(0)
+ else:
+ return None, None, None
+
+
+class FootnotePostTreeprocessor(Treeprocessor):
+ """ Amend footnote div with duplicates. """
+
+ def __init__(self, footnotes):
+ self.footnotes = footnotes
+ def add_duplicates(self, li, duplicates):
+ """ Adjust current li and add the duplicates: fnref2, fnref3, etc. """
+ for link in li.iter('a'):
+ # Find the link that needs to be duplicated.
+ if link.attrib.get('class', '') == 'footnote-backref':
+ ref, rest = link.attrib['href'].split(self.footnotes.get_separator(), 1)
+ # Duplicate link the number of times we need to
+ # and point the to the appropriate references.
+ links = []
+ for index in range(2, duplicates + 1):
+ sib_link = copy.deepcopy(link)
+ sib_link.attrib['href'] = '%s%d%s%s' % (ref, index, self.footnotes.get_separator(), rest)
+ links.append(sib_link)
+ self.offset += 1
+ # Add all the new duplicate links.
+ el = list(li)[-1]
+ for link in links:
+ el.append(link)
+ break
+
+ def get_num_duplicates(self, li):
+ """ Get the number of duplicate refs of the footnote. """
+ fn, rest = li.attrib.get('id', '').split(self.footnotes.get_separator(), 1)
+ link_id = '{}ref{}{}'.format(fn, self.footnotes.get_separator(), rest)
+ return self.footnotes.found_refs.get(link_id, 0)
+
+ def handle_duplicates(self, parent):
+ """ Find duplicate footnotes and format and add the duplicates. """
+ for li in list(parent):
+ # Check number of duplicates footnotes and insert
+ # additional links if needed.
+ count = self.get_num_duplicates(li)
+ if count > 1:
+ self.add_duplicates(li, count)
-class FootnoteTreeprocessor(markdown.treeprocessors.Treeprocessor):
+ def run(self, root):
+ """ Crawl the footnote div and add missing duplicate footnotes. """
+ self.offset = 0
+ for div in root.iter('div'):
+ if div.attrib.get('class', '') == 'footnote':
+ # Footnotes should be under the first ordered list under
+ # the footnote div. So once we find it, quit.
+ for ol in div.iter('ol'):
+ self.handle_duplicates(ol)
+ break
+
+
+class FootnoteTreeprocessor(Treeprocessor):
""" Build and append footnote div to end of document. """
- def __init__ (self, footnotes):
+ def __init__(self, footnotes):
self.footnotes = footnotes
def run(self, root):
footnotesDiv = self.footnotes.makeFootnotesDiv(root)
- if footnotesDiv:
+ if footnotesDiv is not None:
result = self.footnotes.findFootnotesPlaceholder(root)
if result:
- node, isText = result
+ child, parent, isText = result
+ ind = list(parent).index(child)
if isText:
- node.text = None
- node.getchildren().insert(0, footnotesDiv)
+ parent.remove(child)
+ parent.insert(ind, footnotesDiv)
else:
- child, element = node
- ind = element.getchildren().find(child)
- element.getchildren().insert(ind + 1, footnotesDiv)
+ parent.insert(ind + 1, footnotesDiv)
child.tail = None
- fnPlaceholder.parent.replaceChild(fnPlaceholder, footnotesDiv)
else:
root.append(footnotesDiv)
-class FootnotePostprocessor(markdown.postprocessors.Postprocessor):
+
+class FootnotePostprocessor(Postprocessor):
""" Replace placeholders with html entities. """
+ def __init__(self, footnotes):
+ self.footnotes = footnotes
def run(self, text):
- text = text.replace(FN_BACKLINK_TEXT, "&#8617;")
+ text = text.replace(
+ FN_BACKLINK_TEXT, self.footnotes.getConfig("BACKLINK_TEXT")
+ )
return text.replace(NBSP_PLACEHOLDER, "&#160;")
-def makeExtension(configs=[]):
- """ Return an instance of the FootnoteExtension """
- return FootnoteExtension(configs=configs)
+def makeExtension(**kwargs): # pragma: no cover
+ """ Return an instance of the FootnoteExtension """
+ return FootnoteExtension(**kwargs)
diff --git a/markdown/extensions/headerid.py b/markdown/extensions/headerid.py
deleted file mode 100644
index f70a7a9..0000000
--- a/markdown/extensions/headerid.py
+++ /dev/null
@@ -1,195 +0,0 @@
-#!/usr/bin/python
-
-"""
-HeaderID Extension for Python-Markdown
-======================================
-
-Adds ability to set HTML IDs for headers.
-
-Basic usage:
-
- >>> import markdown
- >>> text = "# Some Header # {#some_id}"
- >>> md = markdown.markdown(text, ['headerid'])
- >>> md
- u'<h1 id="some_id">Some Header</h1>'
-
-All header IDs are unique:
-
- >>> text = '''
- ... #Header
- ... #Another Header {#header}
- ... #Third Header {#header}'''
- >>> md = markdown.markdown(text, ['headerid'])
- >>> md
- u'<h1 id="header">Header</h1>\\n<h1 id="header_1">Another Header</h1>\\n<h1 id="header_2">Third Header</h1>'
-
-To fit within a html template's hierarchy, set the header base level:
-
- >>> text = '''
- ... #Some Header
- ... ## Next Level'''
- >>> md = markdown.markdown(text, ['headerid(level=3)'])
- >>> md
- u'<h3 id="some_header">Some Header</h3>\\n<h4 id="next_level">Next Level</h4>'
-
-Turn off auto generated IDs:
-
- >>> text = '''
- ... # Some Header
- ... # Header with ID # { #foo }'''
- >>> md = markdown.markdown(text, ['headerid(forceid=False)'])
- >>> md
- u'<h1>Some Header</h1>\\n<h1 id="foo">Header with ID</h1>'
-
-Use with MetaData extension:
-
- >>> text = '''header_level: 2
- ... header_forceid: Off
- ...
- ... # A Header'''
- >>> md = markdown.markdown(text, ['headerid', 'meta'])
- >>> md
- u'<h2>A Header</h2>'
-
-Copyright 2007-2008 [Waylan Limberg](http://achinghead.com/).
-
-Project website: <http://www.freewisdom.org/project/python-markdown/HeaderId>
-Contact: markdown@freewisdom.org
-
-License: BSD (see ../docs/LICENSE for details)
-
-Dependencies:
-* [Python 2.3+](http://python.org)
-* [Markdown 2.0+](http://www.freewisdom.org/projects/python-markdown/)
-
-"""
-
-import markdown
-from markdown import etree
-import re
-from string import ascii_lowercase, digits, punctuation
-
-ID_CHARS = ascii_lowercase + digits + '-_'
-IDCOUNT_RE = re.compile(r'^(.*)_([0-9]+)$')
-
-
-class HeaderIdProcessor(markdown.blockprocessors.BlockProcessor):
- """ Replacement BlockProcessor for Header IDs. """
-
- # Detect a header at start of any line in block
- RE = re.compile(r"""(^|\n)
- (?P<level>\#{1,6}) # group('level') = string of hashes
- (?P<header>.*?) # group('header') = Header text
- \#* # optional closing hashes
- (?:[ \t]*\{[ \t]*\#(?P<id>[-_:a-zA-Z0-9]+)[ \t]*\})?
- (\n|$) # ^^ group('id') = id attribute
- """,
- re.VERBOSE)
-
- IDs = []
-
- def test(self, parent, block):
- return bool(self.RE.search(block))
-
- def run(self, parent, blocks):
- block = blocks.pop(0)
- m = self.RE.search(block)
- if m:
- before = block[:m.start()] # All lines before header
- after = block[m.end():] # All lines after header
- if before:
- # As the header was not the first line of the block and the
- # lines before the header must be parsed first,
- # recursively parse this lines as a block.
- self.parser.parseBlocks(parent, [before])
- # Create header using named groups from RE
- start_level, force_id = self._get_meta()
- level = len(m.group('level')) + start_level
- if level > 6:
- level = 6
- h = markdown.etree.SubElement(parent, 'h%d' % level)
- h.text = m.group('header').strip()
- if m.group('id'):
- h.set('id', self._unique_id(m.group('id')))
- elif force_id:
- h.set('id', self._create_id(m.group('header').strip()))
- if after:
- # Insert remaining lines as first block for future parsing.
- blocks.insert(0, after)
- else:
- # This should never happen, but just in case...
- message(CRITICAL, "We've got a problem header!")
-
- def _get_meta(self):
- """ Return meta data suported by this ext as a tuple """
- level = int(self.config['level'][0]) - 1
- force = self._str2bool(self.config['forceid'][0])
- if hasattr(self.md, 'Meta'):
- if self.md.Meta.has_key('header_level'):
- level = int(self.md.Meta['header_level'][0]) - 1
- if self.md.Meta.has_key('header_forceid'):
- force = self._str2bool(self.md.Meta['header_forceid'][0])
- return level, force
-
- def _str2bool(self, s, default=False):
- """ Convert a string to a booleen value. """
- s = str(s)
- if s.lower() in ['0', 'f', 'false', 'off', 'no', 'n']:
- return False
- elif s.lower() in ['1', 't', 'true', 'on', 'yes', 'y']:
- return True
- return default
-
- def _unique_id(self, id):
- """ Ensure ID is unique. Append '_1', '_2'... if not """
- while id in self.IDs:
- m = IDCOUNT_RE.match(id)
- if m:
- id = '%s_%d'% (m.group(1), int(m.group(2))+1)
- else:
- id = '%s_%d'% (id, 1)
- self.IDs.append(id)
- return id
-
- def _create_id(self, header):
- """ Return ID from Header text. """
- h = ''
- for c in header.lower().replace(' ', '_'):
- if c in ID_CHARS:
- h += c
- elif c not in punctuation:
- h += '+'
- return self._unique_id(h)
-
-
-class HeaderIdExtension (markdown.Extension):
- def __init__(self, configs):
- # set defaults
- self.config = {
- 'level' : ['1', 'Base level for headers.'],
- 'forceid' : ['True', 'Force all headers to have an id.']
- }
-
- for key, value in configs:
- self.setConfig(key, value)
-
- def extendMarkdown(self, md, md_globals):
- md.registerExtension(self)
- self.processor = HeaderIdProcessor(md.parser)
- self.processor.md = md
- self.processor.config = self.config
- # Replace existing hasheader in place.
- md.parser.blockprocessors['hashheader'] = self.processor
-
- def reset(self):
- self.processor.IDs = []
-
-
-def makeExtension(configs=None):
- return HeaderIdExtension(configs=configs)
-
-if __name__ == "__main__":
- import doctest
- doctest.testmod()
-
diff --git a/markdown/extensions/html_tidy.py b/markdown/extensions/html_tidy.py
deleted file mode 100644
index 5105e33..0000000
--- a/markdown/extensions/html_tidy.py
+++ /dev/null
@@ -1,62 +0,0 @@
-#!/usr/bin/env python
-
-"""
-HTML Tidy Extension for Python-Markdown
-=======================================
-
-Runs [HTML Tidy][] on the output of Python-Markdown using the [uTidylib][]
-Python wrapper. Both libtidy and uTidylib must be installed on your system.
-
-Note than any Tidy [options][] can be passed in as extension configs. So,
-for example, to output HTML rather than XHTML, set ``output_xhtml=0``. To
-indent the output, set ``indent=auto`` and to have Tidy wrap the output in
-``<html>`` and ``<body>`` tags, set ``show_body_only=0``.
-
-[HTML Tidy]: http://tidy.sourceforge.net/
-[uTidylib]: http://utidylib.berlios.de/
-[options]: http://tidy.sourceforge.net/docs/quickref.html
-
-Copyright (c)2008 [Waylan Limberg](http://achinghead.com)
-
-License: [BSD](http://www.opensource.org/licenses/bsd-license.php)
-
-Dependencies:
-* [Python2.3+](http://python.org)
-* [Markdown 2.0+](http://www.freewisdom.org/projects/python-markdown/)
-* [HTML Tidy](http://utidylib.berlios.de/)
-* [uTidylib](http://utidylib.berlios.de/)
-
-"""
-
-import markdown
-import tidy
-
-class TidyExtension(markdown.Extension):
-
- def __init__(self, configs):
- # Set defaults to match typical markdown behavior.
- self.config = dict(output_xhtml=1,
- show_body_only=1,
- )
- # Merge in user defined configs overriding any present if nessecary.
- for c in configs:
- self.config[c[0]] = c[1]
-
- def extendMarkdown(self, md, md_globals):
- # Save options to markdown instance
- md.tidy_options = self.config
- # Add TidyProcessor to postprocessors
- md.postprocessors['tidy'] = TidyProcessor(md)
-
-
-class TidyProcessor(markdown.postprocessors.Postprocessor):
-
- def run(self, text):
- # Pass text to Tidy. As Tidy does not accept unicode we need to encode
- # it and decode its return value.
- return unicode(tidy.parseString(text.encode('utf-8'),
- **self.markdown.tidy_options))
-
-
-def makeExtension(configs=None):
- return TidyExtension(configs=configs)
diff --git a/markdown/extensions/imagelinks.py b/markdown/extensions/imagelinks.py
deleted file mode 100644
index ee0b708..0000000
--- a/markdown/extensions/imagelinks.py
+++ /dev/null
@@ -1,119 +0,0 @@
-"""
-========================= IMAGE LINKS =================================
-
-
-Turns paragraphs like
-
-<~~~~~~~~~~~~~~~~~~~~~~~~
-dir/subdir
-dir/subdir
-dir/subdir
-~~~~~~~~~~~~~~
-dir/subdir
-dir/subdir
-dir/subdir
-~~~~~~~~~~~~~~~~~~~>
-
-Into mini-photo galleries.
-
-"""
-
-import re, markdown
-import url_manager
-
-
-IMAGE_LINK = """<a href="%s"><img src="%s" title="%s"/></a>"""
-SLIDESHOW_LINK = """<a href="%s" target="_blank">[slideshow]</a>"""
-ALBUM_LINK = """&nbsp;<a href="%s">[%s]</a>"""
-
-
-class ImageLinksExtension(markdown.Extension):
-
- def extendMarkdown(self, md, md_globals):
-
- md.preprocessors.add("imagelink", ImageLinkPreprocessor(md), "_begin")
-
-
-class ImageLinkPreprocessor(markdown.preprocessors.Preprocessor):
-
- def run(self, lines):
-
- url = url_manager.BlogEntryUrl(url_manager.BlogUrl("all"),
- "2006/08/29/the_rest_of_our")
-
-
- all_images = []
- blocks = []
- in_image_block = False
-
- new_lines = []
-
- for line in lines:
-
- if line.startswith("<~~~~~~~"):
- albums = []
- rows = []
- in_image_block = True
-
- if not in_image_block:
-
- new_lines.append(line)
-
- else:
-
- line = line.strip()
-
- if line.endswith("~~~~~~>") or not line:
- in_image_block = False
- new_block = "<div><br/><center><span class='image-links'>\n"
-
- album_url_hash = {}
-
- for row in rows:
- for photo_url, title in row:
- new_block += "&nbsp;"
- new_block += IMAGE_LINK % (photo_url,
- photo_url.get_thumbnail(),
- title)
-
- album_url_hash[str(photo_url.get_album())] = 1
-
- new_block += "<br/>"
-
- new_block += "</span>"
- new_block += SLIDESHOW_LINK % url.get_slideshow()
-
- album_urls = album_url_hash.keys()
- album_urls.sort()
-
- if len(album_urls) == 1:
- new_block += ALBUM_LINK % (album_urls[0], "complete album")
- else :
- for i in range(len(album_urls)) :
- new_block += ALBUM_LINK % (album_urls[i],
- "album %d" % (i + 1) )
-
- new_lines.append(new_block + "</center><br/></div>")
-
- elif line[1:6] == "~~~~~" :
- rows.append([]) # start a new row
- else :
- parts = line.split()
- line = parts[0]
- title = " ".join(parts[1:])
-
- album, photo = line.split("/")
- photo_url = url.get_photo(album, photo,
- len(all_images)+1)
- all_images.append(photo_url)
- rows[-1].append((photo_url, title))
-
- if not album in albums :
- albums.append(album)
-
- return new_lines
-
-
-def makeExtension(configs):
- return ImageLinksExtension(configs)
-
diff --git a/markdown/extensions/legacy_attrs.py b/markdown/extensions/legacy_attrs.py
new file mode 100644
index 0000000..445aba1
--- /dev/null
+++ b/markdown/extensions/legacy_attrs.py
@@ -0,0 +1,67 @@
+"""
+Python Markdown
+
+A Python implementation of John Gruber's Markdown.
+
+Documentation: https://python-markdown.github.io/
+GitHub: https://github.com/Python-Markdown/markdown/
+PyPI: https://pypi.org/project/Markdown/
+
+Started by Manfred Stienstra (http://www.dwerg.net/).
+Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
+Currently maintained by Waylan Limberg (https://github.com/waylan),
+Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
+
+Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see LICENSE.md for details).
+
+Legacy Attributes Extension
+===========================
+
+An extension to Python Markdown which implements legacy attributes.
+
+Prior to Python-Markdown version 3.0, the Markdown class had an `enable_attributes`
+keyword which was on by default and provided for attributes to be defined for elements
+using the format `{@key=value}`. This extension is provided as a replacement for
+backward compatibility. New documents should be authored using attr_lists. However,
+numerious documents exist which have been using the old attribute format for many
+years. This extension can be used to continue to render those documents correctly.
+"""
+
+import re
+from markdown.treeprocessors import Treeprocessor, isString
+from markdown.extensions import Extension
+
+
+ATTR_RE = re.compile(r'\{@([^\}]*)=([^\}]*)}') # {@id=123}
+
+
+class LegacyAttrs(Treeprocessor):
+ def run(self, doc):
+ """Find and set values of attributes ({@key=value}). """
+ for el in doc.iter():
+ alt = el.get('alt', None)
+ if alt is not None:
+ el.set('alt', self.handleAttributes(el, alt))
+ if el.text and isString(el.text):
+ el.text = self.handleAttributes(el, el.text)
+ if el.tail and isString(el.tail):
+ el.tail = self.handleAttributes(el, el.tail)
+
+ def handleAttributes(self, el, txt):
+ """ Set attributes and return text without definitions. """
+ def attributeCallback(match):
+ el.set(match.group(1), match.group(2).replace('\n', ' '))
+ return ATTR_RE.sub(attributeCallback, txt)
+
+
+class LegacyAttrExtension(Extension):
+ def extendMarkdown(self, md):
+ md.treeprocessors.register(LegacyAttrs(md), 'legacyattrs', 15)
+
+
+def makeExtension(**kwargs): # pragma: no cover
+ return LegacyAttrExtension(**kwargs)
diff --git a/markdown/extensions/legacy_em.py b/markdown/extensions/legacy_em.py
new file mode 100644
index 0000000..360988b
--- /dev/null
+++ b/markdown/extensions/legacy_em.py
@@ -0,0 +1,49 @@
+'''
+Legacy Em Extension for Python-Markdown
+=======================================
+
+This extension provides legacy behavior for _connected_words_.
+
+Copyright 2015-2018 The Python Markdown Project
+
+License: [BSD](https://opensource.org/licenses/bsd-license.php)
+
+'''
+
+from . import Extension
+from ..inlinepatterns import UnderscoreProcessor, EmStrongItem, EM_STRONG2_RE, STRONG_EM2_RE
+import re
+
+# _emphasis_
+EMPHASIS_RE = r'(_)([^_]+)\1'
+
+# __strong__
+STRONG_RE = r'(_{2})(.+?)\1'
+
+# __strong_em___
+STRONG_EM_RE = r'(_)\1(?!\1)([^_]+?)\1(?!\1)(.+?)\1{3}'
+
+
+class LegacyUnderscoreProcessor(UnderscoreProcessor):
+ """Emphasis processor for handling strong and em matches inside underscores."""
+
+ PATTERNS = [
+ EmStrongItem(re.compile(EM_STRONG2_RE, re.DOTALL | re.UNICODE), 'double', 'strong,em'),
+ EmStrongItem(re.compile(STRONG_EM2_RE, re.DOTALL | re.UNICODE), 'double', 'em,strong'),
+ EmStrongItem(re.compile(STRONG_EM_RE, re.DOTALL | re.UNICODE), 'double2', 'strong,em'),
+ EmStrongItem(re.compile(STRONG_RE, re.DOTALL | re.UNICODE), 'single', 'strong'),
+ EmStrongItem(re.compile(EMPHASIS_RE, re.DOTALL | re.UNICODE), 'single', 'em')
+ ]
+
+
+class LegacyEmExtension(Extension):
+ """ Add legacy_em extension to Markdown class."""
+
+ def extendMarkdown(self, md):
+ """ Modify inline patterns. """
+ md.inlinePatterns.register(LegacyUnderscoreProcessor(r'_'), 'em_strong2', 50)
+
+
+def makeExtension(**kwargs): # pragma: no cover
+ """ Return an instance of the LegacyEmExtension """
+ return LegacyEmExtension(**kwargs)
diff --git a/markdown/extensions/md_in_html.py b/markdown/extensions/md_in_html.py
new file mode 100644
index 0000000..ec7dcba
--- /dev/null
+++ b/markdown/extensions/md_in_html.py
@@ -0,0 +1,364 @@
+"""
+Python-Markdown Markdown in HTML Extension
+===============================
+
+An implementation of [PHP Markdown Extra](http://michelf.com/projects/php-markdown/extra/)'s
+parsing of Markdown syntax in raw HTML.
+
+See <https://Python-Markdown.github.io/extensions/raw_html>
+for documentation.
+
+Copyright The Python Markdown Project
+
+License: [BSD](https://opensource.org/licenses/bsd-license.php)
+
+"""
+
+from . import Extension
+from ..blockprocessors import BlockProcessor
+from ..preprocessors import Preprocessor
+from ..postprocessors import RawHtmlPostprocessor
+from .. import util
+from ..htmlparser import HTMLExtractor, blank_line_re
+import xml.etree.ElementTree as etree
+
+
+class HTMLExtractorExtra(HTMLExtractor):
+ """
+ Override HTMLExtractor and create etree Elements for any elements which should have content parsed as Markdown.
+ """
+
+ def __init__(self, md, *args, **kwargs):
+ # All block-level tags.
+ self.block_level_tags = set(md.block_level_elements.copy())
+ # Block-level tags in which the content only gets span level parsing
+ self.span_tags = set(
+ ['address', 'dd', 'dt', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'legend', 'li', 'p', 'summary', 'td', 'th']
+ )
+ # Block-level tags which never get their content parsed.
+ self.raw_tags = set(['canvas', 'math', 'option', 'pre', 'script', 'style', 'textarea'])
+
+ super().__init__(md, *args, **kwargs)
+
+ # Block-level tags in which the content gets parsed as blocks
+ self.block_tags = set(self.block_level_tags) - (self.span_tags | self.raw_tags | self.empty_tags)
+ self.span_and_blocks_tags = self.block_tags | self.span_tags
+
+ def reset(self):
+ """Reset this instance. Loses all unprocessed data."""
+ self.mdstack = [] # When markdown=1, stack contains a list of tags
+ self.treebuilder = etree.TreeBuilder()
+ self.mdstate = [] # one of 'block', 'span', 'off', or None
+ super().reset()
+
+ def close(self):
+ """Handle any buffered data."""
+ super().close()
+ # Handle any unclosed tags.
+ if self.mdstack:
+ # Close the outermost parent. handle_endtag will close all unclosed children.
+ self.handle_endtag(self.mdstack[0])
+
+ def get_element(self):
+ """ Return element from treebuilder and reset treebuilder for later use. """
+ element = self.treebuilder.close()
+ self.treebuilder = etree.TreeBuilder()
+ return element
+
+ def get_state(self, tag, attrs):
+ """ Return state from tag and `markdown` attr. One of 'block', 'span', or 'off'. """
+ md_attr = attrs.get('markdown', '0')
+ if md_attr == 'markdown':
+ # `<tag markdown>` is the same as `<tag markdown='1'>`.
+ md_attr = '1'
+ parent_state = self.mdstate[-1] if self.mdstate else None
+ if parent_state == 'off' or (parent_state == 'span' and md_attr != '0'):
+ # Only use the parent state if it is more restrictive than the markdown attribute.
+ md_attr = parent_state
+ if ((md_attr == '1' and tag in self.block_tags) or
+ (md_attr == 'block' and tag in self.span_and_blocks_tags)):
+ return 'block'
+ elif ((md_attr == '1' and tag in self.span_tags) or
+ (md_attr == 'span' and tag in self.span_and_blocks_tags)):
+ return 'span'
+ elif tag in self.block_level_tags:
+ return 'off'
+ else: # pragma: no cover
+ return None
+
+ def handle_starttag(self, tag, attrs):
+ # Handle tags that should always be empty and do not specify a closing tag
+ if tag in self.empty_tags and (self.at_line_start() or self.intail):
+ attrs = {key: value if value is not None else key for key, value in attrs}
+ if "markdown" in attrs:
+ attrs.pop('markdown')
+ element = etree.Element(tag, attrs)
+ data = etree.tostring(element, encoding='unicode', method='html')
+ else:
+ data = self.get_starttag_text()
+ self.handle_empty_tag(data, True)
+ return
+
+ if tag in self.block_level_tags and (self.at_line_start() or self.intail):
+ # Valueless attr (ex: `<tag checked>`) results in `[('checked', None)]`.
+ # Convert to `{'checked': 'checked'}`.
+ attrs = {key: value if value is not None else key for key, value in attrs}
+ state = self.get_state(tag, attrs)
+ if self.inraw or (state in [None, 'off'] and not self.mdstack):
+ # fall back to default behavior
+ attrs.pop('markdown', None)
+ super().handle_starttag(tag, attrs)
+ else:
+ if 'p' in self.mdstack and tag in self.block_level_tags:
+ # Close unclosed 'p' tag
+ self.handle_endtag('p')
+ self.mdstate.append(state)
+ self.mdstack.append(tag)
+ attrs['markdown'] = state
+ self.treebuilder.start(tag, attrs)
+ else:
+ # Span level tag
+ if self.inraw:
+ super().handle_starttag(tag, attrs)
+ else:
+ text = self.get_starttag_text()
+ if self.mdstate and self.mdstate[-1] == "off":
+ self.handle_data(self.md.htmlStash.store(text))
+ else:
+ self.handle_data(text)
+ if tag in self.CDATA_CONTENT_ELEMENTS:
+ # This is presumably a standalone tag in a code span (see #1036).
+ self.clear_cdata_mode()
+
+ def handle_endtag(self, tag):
+ if tag in self.block_level_tags:
+ if self.inraw:
+ super().handle_endtag(tag)
+ elif tag in self.mdstack:
+ # Close element and any unclosed children
+ while self.mdstack:
+ item = self.mdstack.pop()
+ self.mdstate.pop()
+ self.treebuilder.end(item)
+ if item == tag:
+ break
+ if not self.mdstack:
+ # Last item in stack is closed. Stash it
+ element = self.get_element()
+ # Get last entry to see if it ends in newlines
+ # If it is an element, assume there is no newlines
+ item = self.cleandoc[-1] if self.cleandoc else ''
+ # If we only have one newline before block element, add another
+ if not item.endswith('\n\n') and item.endswith('\n'):
+ self.cleandoc.append('\n')
+ self.cleandoc.append(self.md.htmlStash.store(element))
+ self.cleandoc.append('\n\n')
+ self.state = []
+ # Check if element has a tail
+ if not blank_line_re.match(
+ self.rawdata[self.line_offset + self.offset + len(self.get_endtag_text(tag)):]):
+ # More content exists after endtag.
+ self.intail = True
+ else:
+ # Treat orphan closing tag as a span level tag.
+ text = self.get_endtag_text(tag)
+ if self.mdstate and self.mdstate[-1] == "off":
+ self.handle_data(self.md.htmlStash.store(text))
+ else:
+ self.handle_data(text)
+ else:
+ # Span level tag
+ if self.inraw:
+ super().handle_endtag(tag)
+ else:
+ text = self.get_endtag_text(tag)
+ if self.mdstate and self.mdstate[-1] == "off":
+ self.handle_data(self.md.htmlStash.store(text))
+ else:
+ self.handle_data(text)
+
+ def handle_startendtag(self, tag, attrs):
+ if tag in self.empty_tags:
+ attrs = {key: value if value is not None else key for key, value in attrs}
+ if "markdown" in attrs:
+ attrs.pop('markdown')
+ element = etree.Element(tag, attrs)
+ data = etree.tostring(element, encoding='unicode', method='html')
+ else:
+ data = self.get_starttag_text()
+ else:
+ data = self.get_starttag_text()
+ self.handle_empty_tag(data, is_block=self.md.is_block_level(tag))
+
+ def handle_data(self, data):
+ if self.intail and '\n' in data:
+ self.intail = False
+ if self.inraw or not self.mdstack:
+ super().handle_data(data)
+ else:
+ self.treebuilder.data(data)
+
+ def handle_empty_tag(self, data, is_block):
+ if self.inraw or not self.mdstack:
+ super().handle_empty_tag(data, is_block)
+ else:
+ if self.at_line_start() and is_block:
+ self.handle_data('\n' + self.md.htmlStash.store(data) + '\n\n')
+ else:
+ self.handle_data(self.md.htmlStash.store(data))
+
+ def parse_pi(self, i):
+ if self.at_line_start() or self.intail or self.mdstack:
+ # The same override exists in HTMLExtractor without the check
+ # for mdstack. Therefore, use HTMLExtractor's parent instead.
+ return super(HTMLExtractor, self).parse_pi(i)
+ # This is not the beginning of a raw block so treat as plain data
+ # and avoid consuming any tags which may follow (see #1066).
+ self.handle_data('<?')
+ return i + 2
+
+ def parse_html_declaration(self, i):
+ if self.at_line_start() or self.intail or self.mdstack:
+ # The same override exists in HTMLExtractor without the check
+ # for mdstack. Therefore, use HTMLExtractor's parent instead.
+ return super(HTMLExtractor, self).parse_html_declaration(i)
+ # This is not the beginning of a raw block so treat as plain data
+ # and avoid consuming any tags which may follow (see #1066).
+ self.handle_data('<!')
+ return i + 2
+
+
+class HtmlBlockPreprocessor(Preprocessor):
+ """Remove html blocks from the text and store them for later retrieval."""
+
+ def run(self, lines):
+ source = '\n'.join(lines)
+ parser = HTMLExtractorExtra(self.md)
+ parser.feed(source)
+ parser.close()
+ return ''.join(parser.cleandoc).split('\n')
+
+
+class MarkdownInHtmlProcessor(BlockProcessor):
+ """Process Markdown Inside HTML Blocks which have been stored in the HtmlStash."""
+
+ def test(self, parent, block):
+ # ALways return True. `run` will return `False` it not a valid match.
+ return True
+
+ def parse_element_content(self, element):
+ """
+ Recursively parse the text content of an etree Element as Markdown.
+
+ Any block level elements generated from the Markdown will be inserted as children of the element in place
+ of the text content. All `markdown` attributes are removed. For any elements in which Markdown parsing has
+ been disabled, the text content of it and its chidlren are wrapped in an `AtomicString`.
+ """
+
+ md_attr = element.attrib.pop('markdown', 'off')
+
+ if md_attr == 'block':
+ # Parse content as block level
+ # The order in which the different parts are parsed (text, children, tails) is important here as the
+ # order of elements needs to be preserved. We can't be inserting items at a later point in the current
+ # iteration as we don't want to do raw processing on elements created from parsing Markdown text (for
+ # example). Therefore, the order of operations is children, tails, text.
+
+ # Recursively parse existing children from raw HTML
+ for child in list(element):
+ self.parse_element_content(child)
+
+ # Parse Markdown text in tail of children. Do this separate to avoid raw HTML parsing.
+ # Save the position of each item to be inserted later in reverse.
+ tails = []
+ for pos, child in enumerate(element):
+ if child.tail:
+ block = child.tail.rstrip('\n')
+ child.tail = ''
+ # Use a dummy placeholder element.
+ dummy = etree.Element('div')
+ self.parser.parseBlocks(dummy, block.split('\n\n'))
+ children = list(dummy)
+ children.reverse()
+ tails.append((pos + 1, children))
+
+ # Insert the elements created from the tails in reverse.
+ tails.reverse()
+ for pos, tail in tails:
+ for item in tail:
+ element.insert(pos, item)
+
+ # Parse Markdown text content. Do this last to avoid raw HTML parsing.
+ if element.text:
+ block = element.text.rstrip('\n')
+ element.text = ''
+ # Use a dummy placeholder element as the content needs to get inserted before existing children.
+ dummy = etree.Element('div')
+ self.parser.parseBlocks(dummy, block.split('\n\n'))
+ children = list(dummy)
+ children.reverse()
+ for child in children:
+ element.insert(0, child)
+
+ elif md_attr == 'span':
+ # Span level parsing will be handled by inlineprocessors.
+ # Walk children here to remove any `markdown` attributes.
+ for child in list(element):
+ self.parse_element_content(child)
+
+ else:
+ # Disable inline parsing for everything else
+ if element.text is None:
+ element.text = ''
+ element.text = util.AtomicString(element.text)
+ for child in list(element):
+ self.parse_element_content(child)
+ if child.tail:
+ child.tail = util.AtomicString(child.tail)
+
+ def run(self, parent, blocks):
+ m = util.HTML_PLACEHOLDER_RE.match(blocks[0])
+ if m:
+ index = int(m.group(1))
+ element = self.parser.md.htmlStash.rawHtmlBlocks[index]
+ if isinstance(element, etree.Element):
+ # We have a matched element. Process it.
+ blocks.pop(0)
+ self.parse_element_content(element)
+ parent.append(element)
+ # Cleanup stash. Replace element with empty string to avoid confusing postprocessor.
+ self.parser.md.htmlStash.rawHtmlBlocks.pop(index)
+ self.parser.md.htmlStash.rawHtmlBlocks.insert(index, '')
+ # Confirm the match to the blockparser.
+ return True
+ # No match found.
+ return False
+
+
+class MarkdownInHTMLPostprocessor(RawHtmlPostprocessor):
+ def stash_to_string(self, text):
+ """ Override default to handle any etree elements still in the stash. """
+ if isinstance(text, etree.Element):
+ return self.md.serializer(text)
+ else:
+ return str(text)
+
+
+class MarkdownInHtmlExtension(Extension):
+ """Add Markdown parsing in HTML to Markdown class."""
+
+ def extendMarkdown(self, md):
+ """ Register extension instances. """
+
+ # Replace raw HTML preprocessor
+ md.preprocessors.register(HtmlBlockPreprocessor(md), 'html_block', 20)
+ # Add blockprocessor which handles the placeholders for etree elements
+ md.parser.blockprocessors.register(
+ MarkdownInHtmlProcessor(md.parser), 'markdown_block', 105
+ )
+ # Replace raw HTML postprocessor
+ md.postprocessors.register(MarkdownInHTMLPostprocessor(md), 'raw_html', 30)
+
+
+def makeExtension(**kwargs): # pragma: no cover
+ return MarkdownInHtmlExtension(**kwargs)
diff --git a/markdown/extensions/meta.py b/markdown/extensions/meta.py
index 1b555b2..10dee11 100644
--- a/markdown/extensions/meta.py
+++ b/markdown/extensions/meta.py
@@ -1,75 +1,68 @@
-#!usr/bin/python
-
"""
Meta Data Extension for Python-Markdown
=======================================
This extension adds Meta Data handling to markdown.
-Basic Usage:
-
- >>> import markdown
- >>> text = '''Title: A Test Doc.
- ... Author: Waylan Limberg
- ... John Doe
- ... Blank_Data:
- ...
- ... The body. This is paragraph one.
- ... '''
- >>> md = markdown.Markdown(['meta'])
- >>> md.convert(text)
- u'<p>The body. This is paragraph one.</p>'
- >>> md.Meta
- {u'blank_data': [u''], u'author': [u'Waylan Limberg', u'John Doe'], u'title': [u'A Test Doc.']}
-
-Make sure text without Meta Data still works (markdown < 1.6b returns a <p>).
+See <https://Python-Markdown.github.io/extensions/meta_data>
+for documentation.
- >>> text = ' Some Code - not extra lines of meta data.'
- >>> md = markdown.Markdown(['meta'])
- >>> md.convert(text)
- u'<pre><code>Some Code - not extra lines of meta data.\\n</code></pre>'
- >>> md.Meta
- {}
+Original code Copyright 2007-2008 [Waylan Limberg](http://achinghead.com).
-Copyright 2007-2008 [Waylan Limberg](http://achinghead.com).
+All changes Copyright 2008-2014 The Python Markdown Project
-Project website: <http://www.freewisdom.org/project/python-markdown/Meta-Data>
-Contact: markdown@freewisdom.org
-
-License: BSD (see ../docs/LICENSE for details)
+License: [BSD](https://opensource.org/licenses/bsd-license.php)
"""
-import markdown, re
+from . import Extension
+from ..preprocessors import Preprocessor
+import re
+import logging
+
+log = logging.getLogger('MARKDOWN')
# Global Vars
META_RE = re.compile(r'^[ ]{0,3}(?P<key>[A-Za-z0-9_-]+):\s*(?P<value>.*)')
META_MORE_RE = re.compile(r'^[ ]{4,}(?P<value>.*)')
+BEGIN_RE = re.compile(r'^-{3}(\s.*)?')
+END_RE = re.compile(r'^(-{3}|\.{3})(\s.*)?')
+
-class MetaExtension (markdown.Extension):
+class MetaExtension (Extension):
""" Meta-Data extension for Python-Markdown. """
- def extendMarkdown(self, md, md_globals):
+ def extendMarkdown(self, md):
""" Add MetaPreprocessor to Markdown instance. """
+ md.registerExtension(self)
+ self.md = md
+ md.preprocessors.register(MetaPreprocessor(md), 'meta', 27)
- md.preprocessors.add("meta", MetaPreprocessor(md), "_begin")
+ def reset(self):
+ self.md.Meta = {}
-class MetaPreprocessor(markdown.preprocessors.Preprocessor):
+class MetaPreprocessor(Preprocessor):
""" Get Meta-Data. """
def run(self, lines):
""" Parse Meta-Data and store in Markdown.Meta. """
meta = {}
key = None
- while 1:
+ if lines and BEGIN_RE.match(lines[0]):
+ lines.pop(0)
+ while lines:
line = lines.pop(0)
- if line.strip() == '':
- break # blank line - done
m1 = META_RE.match(line)
+ if line.strip() == '' or END_RE.match(line):
+ break # blank line or end of YAML header - done
if m1:
key = m1.group('key').lower().strip()
- meta[key] = [m1.group('value').strip()]
+ value = m1.group('value').strip()
+ try:
+ meta[key].append(value)
+ except KeyError:
+ meta[key] = [value]
else:
m2 = META_MORE_RE.match(line)
if m2 and key:
@@ -77,14 +70,10 @@ class MetaPreprocessor(markdown.preprocessors.Preprocessor):
meta[key].append(m2.group('value').strip())
else:
lines.insert(0, line)
- break # no meta data - done
- self.markdown.Meta = meta
+ break # no meta data - done
+ self.md.Meta = meta
return lines
-
-def makeExtension(configs={}):
- return MetaExtension(configs=configs)
-if __name__ == "__main__":
- import doctest
- doctest.testmod()
+def makeExtension(**kwargs): # pragma: no cover
+ return MetaExtension(**kwargs)
diff --git a/markdown/extensions/nl2br.py b/markdown/extensions/nl2br.py
new file mode 100644
index 0000000..6c7491b
--- /dev/null
+++ b/markdown/extensions/nl2br.py
@@ -0,0 +1,33 @@
+"""
+NL2BR Extension
+===============
+
+A Python-Markdown extension to treat newlines as hard breaks; like
+GitHub-flavored Markdown does.
+
+See <https://Python-Markdown.github.io/extensions/nl2br>
+for documentation.
+
+Oringinal code Copyright 2011 [Brian Neal](https://deathofagremmie.com/)
+
+All changes Copyright 2011-2014 The Python Markdown Project
+
+License: [BSD](https://opensource.org/licenses/bsd-license.php)
+
+"""
+
+from . import Extension
+from ..inlinepatterns import SubstituteTagInlineProcessor
+
+BR_RE = r'\n'
+
+
+class Nl2BrExtension(Extension):
+
+ def extendMarkdown(self, md):
+ br_tag = SubstituteTagInlineProcessor(BR_RE, 'br')
+ md.inlinePatterns.register(br_tag, 'nl', 5)
+
+
+def makeExtension(**kwargs): # pragma: no cover
+ return Nl2BrExtension(**kwargs)
diff --git a/markdown/extensions/rss.py b/markdown/extensions/rss.py
deleted file mode 100644
index 1274da2..0000000
--- a/markdown/extensions/rss.py
+++ /dev/null
@@ -1,114 +0,0 @@
-import markdown
-from markdown import etree
-
-DEFAULT_URL = "http://www.freewisdom.org/projects/python-markdown/"
-DEFAULT_CREATOR = "Yuri Takhteyev"
-DEFAULT_TITLE = "Markdown in Python"
-GENERATOR = "http://www.freewisdom.org/projects/python-markdown/markdown2rss"
-
-month_map = { "Jan" : "01",
- "Feb" : "02",
- "March" : "03",
- "April" : "04",
- "May" : "05",
- "June" : "06",
- "July" : "07",
- "August" : "08",
- "September" : "09",
- "October" : "10",
- "November" : "11",
- "December" : "12" }
-
-def get_time(heading):
-
- heading = heading.split("-")[0]
- heading = heading.strip().replace(",", " ").replace(".", " ")
-
- month, date, year = heading.split()
- month = month_map[month]
-
- return rdftime(" ".join((month, date, year, "12:00:00 AM")))
-
-def rdftime(time):
-
- time = time.replace(":", " ")
- time = time.replace("/", " ")
- time = time.split()
- return "%s-%s-%sT%s:%s:%s-08:00" % (time[0], time[1], time[2],
- time[3], time[4], time[5])
-
-
-def get_date(text):
- return "date"
-
-class RssExtension (markdown.Extension):
-
- def extendMarkdown(self, md, md_globals):
-
- self.config = { 'URL' : [DEFAULT_URL, "Main URL"],
- 'CREATOR' : [DEFAULT_CREATOR, "Feed creator's name"],
- 'TITLE' : [DEFAULT_TITLE, "Feed title"] }
-
- md.xml_mode = True
-
- # Insert a tree-processor that would actually add the title tag
- treeprocessor = RssTreeProcessor(md)
- treeprocessor.ext = self
- md.treeprocessors['rss'] = treeprocessor
- md.stripTopLevelTags = 0
- md.docType = '<?xml version="1.0" encoding="utf-8"?>\n'
-
-class RssTreeProcessor(markdown.treeprocessors.Treeprocessor):
-
- def run (self, root):
-
- rss = etree.Element("rss")
- rss.set("version", "2.0")
-
- channel = etree.SubElement(rss, "channel")
-
- for tag, text in (("title", self.ext.getConfig("TITLE")),
- ("link", self.ext.getConfig("URL")),
- ("description", None)):
-
- element = etree.SubElement(channel, tag)
- element.text = text
-
- for child in root:
-
- if child.tag in ["h1", "h2", "h3", "h4", "h5"]:
-
- heading = child.text.strip()
- item = etree.SubElement(channel, "item")
- link = etree.SubElement(item, "link")
- link.text = self.ext.getConfig("URL")
- title = etree.SubElement(item, "title")
- title.text = heading
-
- guid = ''.join([x for x in heading if x.isalnum()])
- guidElem = etree.SubElement(item, "guid")
- guidElem.text = guid
- guidElem.set("isPermaLink", "false")
-
- elif child.tag in ["p"]:
- try:
- description = etree.SubElement(item, "description")
- except UnboundLocalError:
- # Item not defined - moving on
- pass
- else:
- if len(child):
- content = "\n".join([etree.tostring(node)
- for node in child])
- else:
- content = child.text
- pholder = self.markdown.htmlStash.store(
- "<![CDATA[ %s]]>" % content)
- description.text = pholder
-
- return rss
-
-
-def makeExtension(configs):
-
- return RssExtension(configs)
diff --git a/markdown/extensions/sane_lists.py b/markdown/extensions/sane_lists.py
new file mode 100644
index 0000000..e27eb18
--- /dev/null
+++ b/markdown/extensions/sane_lists.py
@@ -0,0 +1,54 @@
+"""
+Sane List Extension for Python-Markdown
+=======================================
+
+Modify the behavior of Lists in Python-Markdown to act in a sane manor.
+
+See <https://Python-Markdown.github.io/extensions/sane_lists>
+for documentation.
+
+Original code Copyright 2011 [Waylan Limberg](http://achinghead.com)
+
+All changes Copyright 2011-2014 The Python Markdown Project
+
+License: [BSD](https://opensource.org/licenses/bsd-license.php)
+
+"""
+
+from . import Extension
+from ..blockprocessors import OListProcessor, UListProcessor
+import re
+
+
+class SaneOListProcessor(OListProcessor):
+
+ SIBLING_TAGS = ['ol']
+ LAZY_OL = False
+
+ def __init__(self, parser):
+ super().__init__(parser)
+ self.CHILD_RE = re.compile(r'^[ ]{0,%d}((\d+\.))[ ]+(.*)' %
+ (self.tab_length - 1))
+
+
+class SaneUListProcessor(UListProcessor):
+
+ SIBLING_TAGS = ['ul']
+
+ def __init__(self, parser):
+ super().__init__(parser)
+ self.CHILD_RE = re.compile(r'^[ ]{0,%d}(([*+-]))[ ]+(.*)' %
+ (self.tab_length - 1))
+
+
+class SaneListExtension(Extension):
+ """ Add sane lists to Markdown. """
+
+ def extendMarkdown(self, md):
+ """ Override existing Processors. """
+ md.parser.blockprocessors.register(SaneOListProcessor(md.parser), 'olist', 40)
+ md.parser.blockprocessors.register(SaneUListProcessor(md.parser), 'ulist', 30)
+
+
+def makeExtension(**kwargs): # pragma: no cover
+ return SaneListExtension(**kwargs)
diff --git a/markdown/extensions/smarty.py b/markdown/extensions/smarty.py
new file mode 100644
index 0000000..c4bfd58
--- /dev/null
+++ b/markdown/extensions/smarty.py
@@ -0,0 +1,257 @@
+'''
+Smarty extension for Python-Markdown
+====================================
+
+Adds conversion of ASCII dashes, quotes and ellipses to their HTML
+entity equivalents.
+
+See <https://Python-Markdown.github.io/extensions/smarty>
+for documentation.
+
+Author: 2013, Dmitry Shachnev <mitya57@gmail.com>
+
+All changes Copyright 2013-2014 The Python Markdown Project
+
+License: [BSD](https://opensource.org/licenses/bsd-license.php)
+
+SmartyPants license:
+
+ Copyright (c) 2003 John Gruber <https://daringfireball.net/>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ * Neither the name "SmartyPants" nor the names of its contributors
+ may be used to endorse or promote products derived from this
+ software without specific prior written permission.
+
+ This software is provided by the copyright holders and contributors "as
+ is" and any express or implied warranties, including, but not limited
+ to, the implied warranties of merchantability and fitness for a
+ particular purpose are disclaimed. In no event shall the copyright
+ owner or contributors be liable for any direct, indirect, incidental,
+ special, exemplary, or consequential damages (including, but not
+ limited to, procurement of substitute goods or services; loss of use,
+ data, or profits; or business interruption) however caused and on any
+ theory of liability, whether in contract, strict liability, or tort
+ (including negligence or otherwise) arising in any way out of the use
+ of this software, even if advised of the possibility of such damage.
+
+
+smartypants.py license:
+
+ smartypants.py is a derivative work of SmartyPants.
+ Copyright (c) 2004, 2007 Chad Miller <http://web.chad.org/>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ This software is provided by the copyright holders and contributors "as
+ is" and any express or implied warranties, including, but not limited
+ to, the implied warranties of merchantability and fitness for a
+ particular purpose are disclaimed. In no event shall the copyright
+ owner or contributors be liable for any direct, indirect, incidental,
+ special, exemplary, or consequential damages (including, but not
+ limited to, procurement of substitute goods or services; loss of use,
+ data, or profits; or business interruption) however caused and on any
+ theory of liability, whether in contract, strict liability, or tort
+ (including negligence or otherwise) arising in any way out of the use
+ of this software, even if advised of the possibility of such damage.
+
+'''
+
+
+from . import Extension
+from ..inlinepatterns import HtmlInlineProcessor, HTML_RE
+from ..treeprocessors import InlineProcessor
+from ..util import Registry
+
+
+# Constants for quote education.
+punctClass = r"""[!"#\$\%'()*+,-.\/:;<=>?\@\[\\\]\^_`{|}~]"""
+endOfWordClass = r"[\s.,;:!?)]"
+closeClass = r"[^\ \t\r\n\[\{\(\-\u0002\u0003]"
+
+openingQuotesBase = (
+ r'(\s' # a whitespace char
+ r'|&nbsp;' # or a non-breaking space entity
+ r'|--' # or dashes
+ r'|–|—' # or unicode
+ r'|&[mn]dash;' # or named dash entities
+ r'|&#8211;|&#8212;' # or decimal entities
+ r')'
+)
+
+substitutions = {
+ 'mdash': '&mdash;',
+ 'ndash': '&ndash;',
+ 'ellipsis': '&hellip;',
+ 'left-angle-quote': '&laquo;',
+ 'right-angle-quote': '&raquo;',
+ 'left-single-quote': '&lsquo;',
+ 'right-single-quote': '&rsquo;',
+ 'left-double-quote': '&ldquo;',
+ 'right-double-quote': '&rdquo;',
+}
+
+
+# Special case if the very first character is a quote
+# followed by punctuation at a non-word-break. Close the quotes by brute force:
+singleQuoteStartRe = r"^'(?=%s\B)" % punctClass
+doubleQuoteStartRe = r'^"(?=%s\B)' % punctClass
+
+# Special case for double sets of quotes, e.g.:
+# <p>He said, "'Quoted' words in a larger quote."</p>
+doubleQuoteSetsRe = r""""'(?=\w)"""
+singleQuoteSetsRe = r"""'"(?=\w)"""
+
+# Special case for decade abbreviations (the '80s):
+decadeAbbrRe = r"(?<!\w)'(?=\d{2}s)"
+
+# Get most opening double quotes:
+openingDoubleQuotesRegex = r'%s"(?=\w)' % openingQuotesBase
+
+# Double closing quotes:
+closingDoubleQuotesRegex = r'"(?=\s)'
+closingDoubleQuotesRegex2 = '(?<=%s)"' % closeClass
+
+# Get most opening single quotes:
+openingSingleQuotesRegex = r"%s'(?=\w)" % openingQuotesBase
+
+# Single closing quotes:
+closingSingleQuotesRegex = r"(?<=%s)'(?!\s|s\b|\d)" % closeClass
+closingSingleQuotesRegex2 = r"(?<=%s)'(\s|s\b)" % closeClass
+
+# All remaining quotes should be opening ones
+remainingSingleQuotesRegex = r"'"
+remainingDoubleQuotesRegex = r'"'
+
+HTML_STRICT_RE = HTML_RE + r'(?!\>)'
+
+
+class SubstituteTextPattern(HtmlInlineProcessor):
+ def __init__(self, pattern, replace, md):
+ """ Replaces matches with some text. """
+ HtmlInlineProcessor.__init__(self, pattern)
+ self.replace = replace
+ self.md = md
+
+ def handleMatch(self, m, data):
+ result = ''
+ for part in self.replace:
+ if isinstance(part, int):
+ result += m.group(part)
+ else:
+ result += self.md.htmlStash.store(part)
+ return result, m.start(0), m.end(0)
+
+
+class SmartyExtension(Extension):
+ def __init__(self, **kwargs):
+ self.config = {
+ 'smart_quotes': [True, 'Educate quotes'],
+ 'smart_angled_quotes': [False, 'Educate angled quotes'],
+ 'smart_dashes': [True, 'Educate dashes'],
+ 'smart_ellipses': [True, 'Educate ellipses'],
+ 'substitutions': [{}, 'Overwrite default substitutions'],
+ }
+ super().__init__(**kwargs)
+ self.substitutions = dict(substitutions)
+ self.substitutions.update(self.getConfig('substitutions', default={}))
+
+ def _addPatterns(self, md, patterns, serie, priority):
+ for ind, pattern in enumerate(patterns):
+ pattern += (md,)
+ pattern = SubstituteTextPattern(*pattern)
+ name = 'smarty-%s-%d' % (serie, ind)
+ self.inlinePatterns.register(pattern, name, priority-ind)
+
+ def educateDashes(self, md):
+ emDashesPattern = SubstituteTextPattern(
+ r'(?<!-)---(?!-)', (self.substitutions['mdash'],), md
+ )
+ enDashesPattern = SubstituteTextPattern(
+ r'(?<!-)--(?!-)', (self.substitutions['ndash'],), md
+ )
+ self.inlinePatterns.register(emDashesPattern, 'smarty-em-dashes', 50)
+ self.inlinePatterns.register(enDashesPattern, 'smarty-en-dashes', 45)
+
+ def educateEllipses(self, md):
+ ellipsesPattern = SubstituteTextPattern(
+ r'(?<!\.)\.{3}(?!\.)', (self.substitutions['ellipsis'],), md
+ )
+ self.inlinePatterns.register(ellipsesPattern, 'smarty-ellipses', 10)
+
+ def educateAngledQuotes(self, md):
+ leftAngledQuotePattern = SubstituteTextPattern(
+ r'\<\<', (self.substitutions['left-angle-quote'],), md
+ )
+ rightAngledQuotePattern = SubstituteTextPattern(
+ r'\>\>', (self.substitutions['right-angle-quote'],), md
+ )
+ self.inlinePatterns.register(leftAngledQuotePattern, 'smarty-left-angle-quotes', 40)
+ self.inlinePatterns.register(rightAngledQuotePattern, 'smarty-right-angle-quotes', 35)
+
+ def educateQuotes(self, md):
+ lsquo = self.substitutions['left-single-quote']
+ rsquo = self.substitutions['right-single-quote']
+ ldquo = self.substitutions['left-double-quote']
+ rdquo = self.substitutions['right-double-quote']
+ patterns = (
+ (singleQuoteStartRe, (rsquo,)),
+ (doubleQuoteStartRe, (rdquo,)),
+ (doubleQuoteSetsRe, (ldquo + lsquo,)),
+ (singleQuoteSetsRe, (lsquo + ldquo,)),
+ (decadeAbbrRe, (rsquo,)),
+ (openingSingleQuotesRegex, (1, lsquo)),
+ (closingSingleQuotesRegex, (rsquo,)),
+ (closingSingleQuotesRegex2, (rsquo, 1)),
+ (remainingSingleQuotesRegex, (lsquo,)),
+ (openingDoubleQuotesRegex, (1, ldquo)),
+ (closingDoubleQuotesRegex, (rdquo,)),
+ (closingDoubleQuotesRegex2, (rdquo,)),
+ (remainingDoubleQuotesRegex, (ldquo,))
+ )
+ self._addPatterns(md, patterns, 'quotes', 30)
+
+ def extendMarkdown(self, md):
+ configs = self.getConfigs()
+ self.inlinePatterns = Registry()
+ if configs['smart_ellipses']:
+ self.educateEllipses(md)
+ if configs['smart_quotes']:
+ self.educateQuotes(md)
+ if configs['smart_angled_quotes']:
+ self.educateAngledQuotes(md)
+ # Override HTML_RE from inlinepatterns.py so that it does not
+ # process tags with duplicate closing quotes.
+ md.inlinePatterns.register(HtmlInlineProcessor(HTML_STRICT_RE, md), 'html', 90)
+ if configs['smart_dashes']:
+ self.educateDashes(md)
+ inlineProcessor = InlineProcessor(md)
+ inlineProcessor.inlinePatterns = self.inlinePatterns
+ md.treeprocessors.register(inlineProcessor, 'smarty', 2)
+ md.ESCAPED_CHARS.extend(['"', "'"])
+
+
+def makeExtension(**kwargs): # pragma: no cover
+ return SmartyExtension(**kwargs)
diff --git a/markdown/extensions/tables.py b/markdown/extensions/tables.py
index 1d3c920..c8b1024 100644
--- a/markdown/extensions/tables.py
+++ b/markdown/extensions/tables.py
@@ -1,44 +1,88 @@
-#!/usr/bin/env Python
"""
Tables Extension for Python-Markdown
====================================
Added parsing of tables to Python-Markdown.
-A simple example:
+See <https://Python-Markdown.github.io/extensions/tables>
+for documentation.
- First Header | Second Header
- ------------- | -------------
- Content Cell | Content Cell
- Content Cell | Content Cell
+Original code Copyright 2009 [Waylan Limberg](http://achinghead.com)
+
+All changes Copyright 2008-2014 The Python Markdown Project
+
+License: [BSD](https://opensource.org/licenses/bsd-license.php)
-Copyright 2009 - [Waylan Limberg](http://achinghead.com)
"""
-import markdown
-from markdown import etree
+
+from . import Extension
+from ..blockprocessors import BlockProcessor
+import xml.etree.ElementTree as etree
+import re
+PIPE_NONE = 0
+PIPE_LEFT = 1
+PIPE_RIGHT = 2
-class TableProcessor(markdown.blockprocessors.BlockProcessor):
+class TableProcessor(BlockProcessor):
""" Process Tables. """
+ RE_CODE_PIPES = re.compile(r'(?:(\\\\)|(\\`+)|(`+)|(\\\|)|(\|))')
+ RE_END_BORDER = re.compile(r'(?<!\\)(?:\\\\)*\|$')
+
+ def __init__(self, parser, config):
+ self.border = False
+ self.separator = ''
+ self.config = config
+
+ super().__init__(parser)
+
def test(self, parent, block):
- rows = block.split('\n')
- return (len(rows) > 2 and '|' in rows[0] and
- '|' in rows[1] and '-' in rows[1] and
- rows[1][0] in ['|', ':', '-'])
+ """
+ Ensure first two rows (column header and separator row) are valid table rows.
+
+ Keep border check and separator row do avoid repeating the work.
+ """
+ is_table = False
+ rows = [row.strip(' ') for row in block.split('\n')]
+ if len(rows) > 1:
+ header0 = rows[0]
+ self.border = PIPE_NONE
+ if header0.startswith('|'):
+ self.border |= PIPE_LEFT
+ if self.RE_END_BORDER.search(header0) is not None:
+ self.border |= PIPE_RIGHT
+ row = self._split_row(header0)
+ row0_len = len(row)
+ is_table = row0_len > 1
+
+ # Each row in a single column table needs at least one pipe.
+ if not is_table and row0_len == 1 and self.border:
+ for index in range(1, len(rows)):
+ is_table = rows[index].startswith('|')
+ if not is_table:
+ is_table = self.RE_END_BORDER.search(rows[index]) is not None
+ if not is_table:
+ break
+
+ if is_table:
+ row = self._split_row(rows[1])
+ is_table = (len(row) == row0_len) and set(''.join(row)) <= set('|:- ')
+ if is_table:
+ self.separator = row
+
+ return is_table
def run(self, parent, blocks):
""" Parse a table block and build table. """
block = blocks.pop(0).split('\n')
- header = block[:2]
- rows = block[2:]
- # Get format type (bordered by pipes or not)
- border = False
- if header[0].startswith('|'):
- border = True
+ header = block[0].strip(' ')
+ rows = [] if len(block) < 3 else block[2:]
+
# Get alignment of columns
align = []
- for c in self._split_row(header[1], border):
+ for c in self.separator:
+ c = c.strip(' ')
if c.startswith(':') and c.endswith(':'):
align.append('center')
elif c.startswith(':'):
@@ -47,51 +91,146 @@ class TableProcessor(markdown.blockprocessors.BlockProcessor):
align.append('right')
else:
align.append(None)
+
# Build table
table = etree.SubElement(parent, 'table')
thead = etree.SubElement(table, 'thead')
- self._build_row(header[0], thead, align, border)
+ self._build_row(header, thead, align)
tbody = etree.SubElement(table, 'tbody')
- for row in rows:
- self._build_row(row, tbody, align, border)
+ if len(rows) == 0:
+ # Handle empty table
+ self._build_empty_row(tbody, align)
+ else:
+ for row in rows:
+ self._build_row(row.strip(' '), tbody, align)
+
+ def _build_empty_row(self, parent, align):
+ """Build an empty row."""
+ tr = etree.SubElement(parent, 'tr')
+ count = len(align)
+ while count:
+ etree.SubElement(tr, 'td')
+ count -= 1
- def _build_row(self, row, parent, align, border):
+ def _build_row(self, row, parent, align):
""" Given a row of text, build table cells. """
tr = etree.SubElement(parent, 'tr')
tag = 'td'
if parent.tag == 'thead':
tag = 'th'
- cells = self._split_row(row, border)
- # We use align here rather than cells to ensure every row
+ cells = self._split_row(row)
+ # We use align here rather than cells to ensure every row
# contains the same number of columns.
for i, a in enumerate(align):
c = etree.SubElement(tr, tag)
try:
- c.text = cells[i].strip()
- except IndexError:
+ c.text = cells[i].strip(' ')
+ except IndexError: # pragma: no cover
c.text = ""
if a:
- c.set('align', a)
+ if self.config['use_align_attribute']:
+ c.set('align', a)
+ else:
+ c.set('style', f'text-align: {a};')
- def _split_row(self, row, border):
+ def _split_row(self, row):
""" split a row of text into list of cells. """
- if border:
+ if self.border:
if row.startswith('|'):
row = row[1:]
- if row.endswith('|'):
- row = row[:-1]
- return row.split('|')
+ row = self.RE_END_BORDER.sub('', row)
+ return self._split(row)
+ def _split(self, row):
+ """ split a row of text with some code into a list of cells. """
+ elements = []
+ pipes = []
+ tics = []
+ tic_points = []
+ tic_region = []
+ good_pipes = []
+
+ # Parse row
+ # Throw out \\, and \|
+ for m in self.RE_CODE_PIPES.finditer(row):
+ # Store ` data (len, start_pos, end_pos)
+ if m.group(2):
+ # \`+
+ # Store length of each tic group: subtract \
+ tics.append(len(m.group(2)) - 1)
+ # Store start of group, end of group, and escape length
+ tic_points.append((m.start(2), m.end(2) - 1, 1))
+ elif m.group(3):
+ # `+
+ # Store length of each tic group
+ tics.append(len(m.group(3)))
+ # Store start of group, end of group, and escape length
+ tic_points.append((m.start(3), m.end(3) - 1, 0))
+ # Store pipe location
+ elif m.group(5):
+ pipes.append(m.start(5))
+
+ # Pair up tics according to size if possible
+ # Subtract the escape length *only* from the opening.
+ # Walk through tic list and see if tic has a close.
+ # Store the tic region (start of region, end of region).
+ pos = 0
+ tic_len = len(tics)
+ while pos < tic_len:
+ try:
+ tic_size = tics[pos] - tic_points[pos][2]
+ if tic_size == 0:
+ raise ValueError
+ index = tics[pos + 1:].index(tic_size) + 1
+ tic_region.append((tic_points[pos][0], tic_points[pos + index][1]))
+ pos += index + 1
+ except ValueError:
+ pos += 1
-class TableExtension(markdown.Extension):
+ # Resolve pipes. Check if they are within a tic pair region.
+ # Walk through pipes comparing them to each region.
+ # - If pipe position is less that a region, it isn't in a region
+ # - If it is within a region, we don't want it, so throw it out
+ # - If we didn't throw it out, it must be a table pipe
+ for pipe in pipes:
+ throw_out = False
+ for region in tic_region:
+ if pipe < region[0]:
+ # Pipe is not in a region
+ break
+ elif region[0] <= pipe <= region[1]:
+ # Pipe is within a code region. Throw it out.
+ throw_out = True
+ break
+ if not throw_out:
+ good_pipes.append(pipe)
+
+ # Split row according to table delimiters.
+ pos = 0
+ for pipe in good_pipes:
+ elements.append(row[pos:pipe])
+ pos = pipe + 1
+ elements.append(row[pos:])
+ return elements
+
+
+class TableExtension(Extension):
""" Add tables to Markdown. """
- def extendMarkdown(self, md, md_globals):
+ def __init__(self, **kwargs):
+ self.config = {
+ 'use_align_attribute': [False, 'True to use align attribute instead of style.'],
+ }
+
+ super().__init__(**kwargs)
+
+ def extendMarkdown(self, md):
""" Add an instance of TableProcessor to BlockParser. """
- md.parser.blockprocessors.add('table',
- TableProcessor(md.parser),
- '<hashheader')
+ if '|' not in md.ESCAPED_CHARS:
+ md.ESCAPED_CHARS.append('|')
+ processor = TableProcessor(md.parser, self.getConfigs())
+ md.parser.blockprocessors.register(processor, 'table', 75)
-def makeExtension(configs={}):
- return TableExtension(configs=configs)
+def makeExtension(**kwargs): # pragma: no cover
+ return TableExtension(**kwargs)
diff --git a/markdown/extensions/toc.py b/markdown/extensions/toc.py
index 1d9489c..1ded18d 100644
--- a/markdown/extensions/toc.py
+++ b/markdown/extensions/toc.py
@@ -1,136 +1,384 @@
"""
Table of Contents Extension for Python-Markdown
-* * *
+===============================================
-(c) 2008 [Jack Miller](http://codezen.org)
+See <https://Python-Markdown.github.io/extensions/toc>
+for documentation.
-Dependencies:
-* [Markdown 2.0+](http://www.freewisdom.org/projects/python-markdown/)
+Oringinal code Copyright 2008 [Jack Miller](https://codezen.org/)
+
+All changes Copyright 2008-2014 The Python Markdown Project
+
+License: [BSD](https://opensource.org/licenses/bsd-license.php)
"""
-import markdown
-from markdown import etree
+
+from . import Extension
+from ..treeprocessors import Treeprocessor
+from ..util import code_escape, parseBoolValue, AMP_SUBSTITUTE, HTML_PLACEHOLDER_RE, AtomicString
+from ..treeprocessors import UnescapeTreeprocessor
import re
+import html
+import unicodedata
+import xml.etree.ElementTree as etree
-class TocTreeprocessor(markdown.treeprocessors.Treeprocessor):
- # Iterator wrapper to get parent and child all at once
- def iterparent(self, root):
- for parent in root.getiterator():
- for child in parent:
- yield parent, child
- def run(self, doc):
- div = etree.Element("div")
- div.attrib["class"] = "toc"
- last_li = None
+def slugify(value, separator, unicode=False):
+ """ Slugify a string, to make it URL friendly. """
+ if not unicode:
+ # Replace Extended Latin characters with ASCII, i.e. žlutý → zluty
+ value = unicodedata.normalize('NFKD', value)
+ value = value.encode('ascii', 'ignore').decode('ascii')
+ value = re.sub(r'[^\w\s-]', '', value).strip().lower()
+ return re.sub(r'[{}\s]+'.format(separator), separator, value)
- # Add title to the div
- if self.config["title"][0]:
- header = etree.SubElement(div, "span")
- header.attrib["class"] = "toctitle"
- header.text = self.config["title"][0]
- level = 0
- list_stack=[div]
- header_rgx = re.compile("[Hh][123456]")
+def slugify_unicode(value, separator):
+ """ Slugify a string, to make it URL friendly while preserving Unicode characters. """
+ return slugify(value, separator, unicode=True)
- # Get a list of id attributes
- used_ids = []
- for c in doc.getiterator():
- if "id" in c.attrib:
- used_ids.append(c.attrib["id"])
- for (p, c) in self.iterparent(doc):
- if not c.text:
+IDCOUNT_RE = re.compile(r'^(.*)_([0-9]+)$')
+
+
+def unique(id, ids):
+ """ Ensure id is unique in set of ids. Append '_1', '_2'... if not """
+ while id in ids or not id:
+ m = IDCOUNT_RE.match(id)
+ if m:
+ id = '%s_%d' % (m.group(1), int(m.group(2))+1)
+ else:
+ id = '%s_%d' % (id, 1)
+ ids.add(id)
+ return id
+
+
+def get_name(el):
+ """Get title name."""
+
+ text = []
+ for c in el.itertext():
+ if isinstance(c, AtomicString):
+ text.append(html.unescape(c))
+ else:
+ text.append(c)
+ return ''.join(text).strip()
+
+
+def stashedHTML2text(text, md, strip_entities=True):
+ """ Extract raw HTML from stash, reduce to plain text and swap with placeholder. """
+ def _html_sub(m):
+ """ Substitute raw html with plain text. """
+ try:
+ raw = md.htmlStash.rawHtmlBlocks[int(m.group(1))]
+ except (IndexError, TypeError): # pragma: no cover
+ return m.group(0)
+ # Strip out tags and/or entities - leaving text
+ res = re.sub(r'(<[^>]+>)', '', raw)
+ if strip_entities:
+ res = re.sub(r'(&[\#a-zA-Z0-9]+;)', '', res)
+ return res
+
+ return HTML_PLACEHOLDER_RE.sub(_html_sub, text)
+
+
+def unescape(text):
+ """ Unescape escaped text. """
+ c = UnescapeTreeprocessor()
+ return c.unescape(text)
+
+
+def nest_toc_tokens(toc_list):
+ """Given an unsorted list with errors and skips, return a nested one.
+ [{'level': 1}, {'level': 2}]
+ =>
+ [{'level': 1, 'children': [{'level': 2, 'children': []}]}]
+
+ A wrong list is also converted:
+ [{'level': 2}, {'level': 1}]
+ =>
+ [{'level': 2, 'children': []}, {'level': 1, 'children': []}]
+ """
+
+ ordered_list = []
+ if len(toc_list):
+ # Initialize everything by processing the first entry
+ last = toc_list.pop(0)
+ last['children'] = []
+ levels = [last['level']]
+ ordered_list.append(last)
+ parents = []
+
+ # Walk the rest nesting the entries properly
+ while toc_list:
+ t = toc_list.pop(0)
+ current_level = t['level']
+ t['children'] = []
+
+ # Reduce depth if current level < last item's level
+ if current_level < levels[-1]:
+ # Pop last level since we know we are less than it
+ levels.pop()
+
+ # Pop parents and levels we are less than or equal to
+ to_pop = 0
+ for p in reversed(parents):
+ if current_level <= p['level']:
+ to_pop += 1
+ else: # pragma: no cover
+ break
+ if to_pop:
+ levels = levels[:-to_pop]
+ parents = parents[:-to_pop]
+
+ # Note current level as last
+ levels.append(current_level)
+
+ # Level is the same, so append to
+ # the current parent (if available)
+ if current_level == levels[-1]:
+ (parents[-1]['children'] if parents
+ else ordered_list).append(t)
+
+ # Current level is > last item's level,
+ # So make last item a parent and append current as child
+ else:
+ last['children'].append(t)
+ parents.append(last)
+ levels.append(current_level)
+ last = t
+
+ return ordered_list
+
+
+class TocTreeprocessor(Treeprocessor):
+ def __init__(self, md, config):
+ super().__init__(md)
+
+ self.marker = config["marker"]
+ self.title = config["title"]
+ self.base_level = int(config["baselevel"]) - 1
+ self.slugify = config["slugify"]
+ self.sep = config["separator"]
+ self.toc_class = config["toc_class"]
+ self.use_anchors = parseBoolValue(config["anchorlink"])
+ self.anchorlink_class = config["anchorlink_class"]
+ self.use_permalinks = parseBoolValue(config["permalink"], False)
+ if self.use_permalinks is None:
+ self.use_permalinks = config["permalink"]
+ self.permalink_class = config["permalink_class"]
+ self.permalink_title = config["permalink_title"]
+ self.header_rgx = re.compile("[Hh][123456]")
+ if isinstance(config["toc_depth"], str) and '-' in config["toc_depth"]:
+ self.toc_top, self.toc_bottom = [int(x) for x in config["toc_depth"].split('-')]
+ else:
+ self.toc_top = 1
+ self.toc_bottom = int(config["toc_depth"])
+
+ def iterparent(self, node):
+ ''' Iterator wrapper to get allowed parent and child all at once. '''
+
+ # We do not allow the marker inside a header as that
+ # would causes an enless loop of placing a new TOC
+ # inside previously generated TOC.
+ for child in node:
+ if not self.header_rgx.match(child.tag) and child.tag not in ['pre', 'code']:
+ yield node, child
+ yield from self.iterparent(child)
+
+ def replace_marker(self, root, elem):
+ ''' Replace marker with elem. '''
+ for (p, c) in self.iterparent(root):
+ text = ''.join(c.itertext()).strip()
+ if not text:
continue
# To keep the output from screwing up the
# validation by putting a <div> inside of a <p>
# we actually replace the <p> in its entirety.
- # We do not allow the marker inside a header as that
- # would causes an enless loop of placing a new TOC
- # inside previously generated TOC.
- if c.text.find(self.config["marker"][0]) > -1 and not header_rgx.match(c.tag):
+ # The <p> element may contain more than a single text content
+ # (nl2br can introduce a <br>). In this situation, c.text returns
+ # the very first content, ignore children contents or tail content.
+ # len(c) == 0 is here to ensure there is only text in the <p>.
+ if c.text and c.text.strip() == self.marker and len(c) == 0:
for i in range(len(p)):
if p[i] == c:
- p[i] = div
+ p[i] = elem
break
-
- if header_rgx.match(c.tag):
- tag_level = int(c.tag[-1])
-
- while tag_level < level:
- list_stack.pop()
- level -= 1
-
- if tag_level > level:
- newlist = etree.Element("ul")
- if last_li:
- last_li.append(newlist)
- else:
- list_stack[-1].append(newlist)
- list_stack.append(newlist)
- level += 1
-
- # Do not override pre-existing ids
- if not "id" in c.attrib:
- id = self.config["slugify"][0](c.text)
- if id in used_ids:
- ctr = 1
- while "%s_%d" % (id, ctr) in used_ids:
- ctr += 1
- id = "%s_%d" % (id, ctr)
- used_ids.append(id)
- c.attrib["id"] = id
- else:
- id = c.attrib["id"]
+ def set_level(self, elem):
+ ''' Adjust header level according to base level. '''
+ level = int(elem.tag[-1]) + self.base_level
+ if level > 6:
+ level = 6
+ elem.tag = 'h%d' % level
+
+ def add_anchor(self, c, elem_id): # @ReservedAssignment
+ anchor = etree.Element("a")
+ anchor.text = c.text
+ anchor.attrib["href"] = "#" + elem_id
+ anchor.attrib["class"] = self.anchorlink_class
+ c.text = ""
+ for elem in c:
+ anchor.append(elem)
+ while len(c):
+ c.remove(c[0])
+ c.append(anchor)
+
+ def add_permalink(self, c, elem_id):
+ permalink = etree.Element("a")
+ permalink.text = ("%spara;" % AMP_SUBSTITUTE
+ if self.use_permalinks is True
+ else self.use_permalinks)
+ permalink.attrib["href"] = "#" + elem_id
+ permalink.attrib["class"] = self.permalink_class
+ if self.permalink_title:
+ permalink.attrib["title"] = self.permalink_title
+ c.append(permalink)
+
+ def build_toc_div(self, toc_list):
+ """ Return a string div given a toc list. """
+ div = etree.Element("div")
+ div.attrib["class"] = self.toc_class
+
+ # Add title to the div
+ if self.title:
+ header = etree.SubElement(div, "span")
+ header.attrib["class"] = "toctitle"
+ header.text = self.title
+
+ def build_etree_ul(toc_list, parent):
+ ul = etree.SubElement(parent, "ul")
+ for item in toc_list:
# List item link, to be inserted into the toc div
- last_li = etree.Element("li")
- link = etree.SubElement(last_li, "a")
- link.text = c.text
- link.attrib["href"] = '#' + id
-
- if int(self.config["anchorlink"][0]):
- anchor = etree.SubElement(c, "a")
- anchor.text = c.text
- anchor.attrib["href"] = "#" + id
- anchor.attrib["class"] = "toclink"
- c.text = ""
-
- list_stack[-1].append(last_li)
-
-class TocExtension(markdown.Extension):
- def __init__(self, configs):
- self.config = { "marker" : ["[TOC]",
- "Text to find and replace with Table of Contents -"
- "Defaults to \"[TOC]\""],
- "slugify" : [self.slugify,
- "Function to generate anchors based on header text-"
- "Defaults to a built in slugify function."],
- "title" : [None,
- "Title to insert into TOC <div> - "
- "Defaults to None"],
- "anchorlink" : [0,
- "1 if header should be a self link"
- "Defaults to 0"]}
-
- for key, value in configs:
- self.setConfig(key, value)
-
- # This is exactly the same as Django's slugify
- def slugify(self, value):
- """ Slugify a string, to make it URL friendly. """
- import unicodedata
- value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore')
- value = unicode(re.sub('[^\w\s-]', '', value).strip().lower())
- return re.sub('[-\s]+','-',value)
-
- def extendMarkdown(self, md, md_globals):
- tocext = TocTreeprocessor(md)
- tocext.config = self.config
- md.treeprocessors.add("toc", tocext, "_begin")
-
-def makeExtension(configs={}):
- return TocExtension(configs=configs)
+ li = etree.SubElement(ul, "li")
+ link = etree.SubElement(li, "a")
+ link.text = item.get('name', '')
+ link.attrib["href"] = '#' + item.get('id', '')
+ if item['children']:
+ build_etree_ul(item['children'], li)
+ return ul
+
+ build_etree_ul(toc_list, div)
+
+ if 'prettify' in self.md.treeprocessors:
+ self.md.treeprocessors['prettify'].run(div)
+
+ return div
+
+ def run(self, doc):
+ # Get a list of id attributes
+ used_ids = set()
+ for el in doc.iter():
+ if "id" in el.attrib:
+ used_ids.add(el.attrib["id"])
+
+ toc_tokens = []
+ for el in doc.iter():
+ if isinstance(el.tag, str) and self.header_rgx.match(el.tag):
+ self.set_level(el)
+ text = get_name(el)
+
+ # Do not override pre-existing ids
+ if "id" not in el.attrib:
+ innertext = unescape(stashedHTML2text(text, self.md))
+ el.attrib["id"] = unique(self.slugify(innertext, self.sep), used_ids)
+
+ if int(el.tag[-1]) >= self.toc_top and int(el.tag[-1]) <= self.toc_bottom:
+ toc_tokens.append({
+ 'level': int(el.tag[-1]),
+ 'id': el.attrib["id"],
+ 'name': stashedHTML2text(
+ code_escape(el.attrib.get('data-toc-label', text)),
+ self.md, strip_entities=False
+ )
+ })
+
+ # Remove the data-toc-label attribute as it is no longer needed
+ if 'data-toc-label' in el.attrib:
+ del el.attrib['data-toc-label']
+
+ if self.use_anchors:
+ self.add_anchor(el, el.attrib["id"])
+ if self.use_permalinks not in [False, None]:
+ self.add_permalink(el, el.attrib["id"])
+
+ toc_tokens = nest_toc_tokens(toc_tokens)
+ div = self.build_toc_div(toc_tokens)
+ if self.marker:
+ self.replace_marker(doc, div)
+
+ # serialize and attach to markdown instance.
+ toc = self.md.serializer(div)
+ for pp in self.md.postprocessors:
+ toc = pp.run(toc)
+ self.md.toc_tokens = toc_tokens
+ self.md.toc = toc
+
+
+class TocExtension(Extension):
+
+ TreeProcessorClass = TocTreeprocessor
+
+ def __init__(self, **kwargs):
+ self.config = {
+ "marker": ['[TOC]',
+ 'Text to find and replace with Table of Contents - '
+ 'Set to an empty string to disable. Defaults to "[TOC]"'],
+ "title": ["",
+ "Title to insert into TOC <div> - "
+ "Defaults to an empty string"],
+ "toc_class": ['toc',
+ 'CSS class(es) used for the link. '
+ 'Defaults to "toclink"'],
+ "anchorlink": [False,
+ "True if header should be a self link - "
+ "Defaults to False"],
+ "anchorlink_class": ['toclink',
+ 'CSS class(es) used for the link. '
+ 'Defaults to "toclink"'],
+ "permalink": [0,
+ "True or link text if a Sphinx-style permalink should "
+ "be added - Defaults to False"],
+ "permalink_class": ['headerlink',
+ 'CSS class(es) used for the link. '
+ 'Defaults to "headerlink"'],
+ "permalink_title": ["Permanent link",
+ "Title attribute of the permalink - "
+ "Defaults to 'Permanent link'"],
+ "baselevel": ['1', 'Base level for headers.'],
+ "slugify": [slugify,
+ "Function to generate anchors based on header text - "
+ "Defaults to the headerid ext's slugify function."],
+ 'separator': ['-', 'Word separator. Defaults to "-".'],
+ "toc_depth": [6,
+ 'Define the range of section levels to include in'
+ 'the Table of Contents. A single integer (b) defines'
+ 'the bottom section level (<h1>..<hb>) only.'
+ 'A string consisting of two digits separated by a hyphen'
+ 'in between ("2-5"), define the top (t) and the'
+ 'bottom (b) (<ht>..<hb>). Defaults to `6` (bottom).'],
+ }
+
+ super().__init__(**kwargs)
+
+ def extendMarkdown(self, md):
+ md.registerExtension(self)
+ self.md = md
+ self.reset()
+ tocext = self.TreeProcessorClass(md, self.getConfigs())
+ # Headerid ext is set to '>prettify'. With this set to '_end',
+ # it should always come after headerid ext (and honor ids assigned
+ # by the header id extension) if both are used. Same goes for
+ # attr_list extension. This must come last because we don't want
+ # to redefine ids after toc is created. But we do want toc prettified.
+ md.treeprocessors.register(tocext, 'toc', 5)
+
+ def reset(self):
+ self.md.toc = ''
+ self.md.toc_tokens = []
+
+
+def makeExtension(**kwargs): # pragma: no cover
+ return TocExtension(**kwargs)
diff --git a/markdown/extensions/wikilinks.py b/markdown/extensions/wikilinks.py
index df44e1c..cddee7a 100644
--- a/markdown/extensions/wikilinks.py
+++ b/markdown/extensions/wikilinks.py
@@ -1,155 +1,87 @@
-#!/usr/bin/env python
-
'''
WikiLinks Extension for Python-Markdown
======================================
-Converts [[WikiLinks]] to relative links. Requires Python-Markdown 2.0+
-
-Basic usage:
-
- >>> import markdown
- >>> text = "Some text with a [[WikiLink]]."
- >>> html = markdown.markdown(text, ['wikilinks'])
- >>> html
- u'<p>Some text with a <a class="wikilink" href="/WikiLink/">WikiLink</a>.</p>'
-
-Whitespace behavior:
-
- >>> markdown.markdown('[[ foo bar_baz ]]', ['wikilinks'])
- u'<p><a class="wikilink" href="/foo_bar_baz/">foo bar_baz</a></p>'
- >>> markdown.markdown('foo [[ ]] bar', ['wikilinks'])
- u'<p>foo bar</p>'
-
-To define custom settings the simple way:
-
- >>> markdown.markdown(text,
- ... ['wikilinks(base_url=/wiki/,end_url=.html,html_class=foo)']
- ... )
- u'<p>Some text with a <a class="foo" href="/wiki/WikiLink.html">WikiLink</a>.</p>'
-
-Custom settings the complex way:
-
- >>> md = markdown.Markdown(
- ... extensions = ['wikilinks'],
- ... extension_configs = {'wikilinks': [
- ... ('base_url', 'http://example.com/'),
- ... ('end_url', '.html'),
- ... ('html_class', '') ]},
- ... safe_mode = True)
- >>> md.convert(text)
- u'<p>Some text with a <a href="http://example.com/WikiLink.html">WikiLink</a>.</p>'
-
-Use MetaData with mdx_meta.py (Note the blank html_class in MetaData):
-
- >>> text = """wiki_base_url: http://example.com/
- ... wiki_end_url: .html
- ... wiki_html_class:
- ...
- ... Some text with a [[WikiLink]]."""
- >>> md = markdown.Markdown(extensions=['meta', 'wikilinks'])
- >>> md.convert(text)
- u'<p>Some text with a <a href="http://example.com/WikiLink.html">WikiLink</a>.</p>'
-
-MetaData should not carry over to next document:
+Converts [[WikiLinks]] to relative links.
- >>> md.convert("No [[MetaData]] here.")
- u'<p>No <a class="wikilink" href="/MetaData/">MetaData</a> here.</p>'
+See <https://Python-Markdown.github.io/extensions/wikilinks>
+for documentation.
-Define a custom URL builder:
+Original code Copyright [Waylan Limberg](http://achinghead.com/).
- >>> def my_url_builder(label, base, end):
- ... return '/bar/'
- >>> md = markdown.Markdown(extensions=['wikilinks'],
- ... extension_configs={'wikilinks' : [('build_url', my_url_builder)]})
- >>> md.convert('[[foo]]')
- u'<p><a class="wikilink" href="/bar/">foo</a></p>'
+All changes Copyright The Python Markdown Project
-From the command line:
+License: [BSD](https://opensource.org/licenses/bsd-license.php)
- python markdown.py -x wikilinks(base_url=http://example.com/,end_url=.html,html_class=foo) src.txt
-
-By [Waylan Limberg](http://achinghead.com/).
-
-License: [BSD](http://www.opensource.org/licenses/bsd-license.php)
-
-Dependencies:
-* [Python 2.3+](http://python.org)
-* [Markdown 2.0+](http://www.freewisdom.org/projects/python-markdown/)
'''
-import markdown
+from . import Extension
+from ..inlinepatterns import InlineProcessor
+import xml.etree.ElementTree as etree
import re
+
def build_url(label, base, end):
""" Build a url from the label, a base, and an end. """
clean_label = re.sub(r'([ ]+_)|(_[ ]+)|([ ]+)', '_', label)
- return '%s%s%s'% (base, clean_label, end)
+ return '{}{}{}'.format(base, clean_label, end)
+
+class WikiLinkExtension(Extension):
-class WikiLinkExtension(markdown.Extension):
- def __init__(self, configs):
- # set extension defaults
+ def __init__(self, **kwargs):
self.config = {
- 'base_url' : ['/', 'String to append to beginning or URL.'],
- 'end_url' : ['/', 'String to append to end of URL.'],
- 'html_class' : ['wikilink', 'CSS hook. Leave blank for none.'],
- 'build_url' : [build_url, 'Callable formats URL from label.'],
+ 'base_url': ['/', 'String to append to beginning or URL.'],
+ 'end_url': ['/', 'String to append to end of URL.'],
+ 'html_class': ['wikilink', 'CSS hook. Leave blank for none.'],
+ 'build_url': [build_url, 'Callable formats URL from label.'],
}
-
- # Override defaults with user settings
- for key, value in configs :
- self.setConfig(key, value)
-
- def extendMarkdown(self, md, md_globals):
+
+ super().__init__(**kwargs)
+
+ def extendMarkdown(self, md):
self.md = md
-
+
# append to end of inline patterns
- WIKILINK_RE = r'\[\[([A-Za-z0-9_ -]+)\]\]'
- wikilinkPattern = WikiLinks(WIKILINK_RE, self.config)
+ WIKILINK_RE = r'\[\[([\w0-9_ -]+)\]\]'
+ wikilinkPattern = WikiLinksInlineProcessor(WIKILINK_RE, self.getConfigs())
wikilinkPattern.md = md
- md.inlinePatterns.add('wikilink', wikilinkPattern, "<not_strong")
+ md.inlinePatterns.register(wikilinkPattern, 'wikilink', 75)
-class WikiLinks(markdown.inlinepatterns.Pattern):
+class WikiLinksInlineProcessor(InlineProcessor):
def __init__(self, pattern, config):
- markdown.inlinepatterns.Pattern.__init__(self, pattern)
+ super().__init__(pattern)
self.config = config
-
- def handleMatch(self, m):
- if m.group(2).strip():
+
+ def handleMatch(self, m, data):
+ if m.group(1).strip():
base_url, end_url, html_class = self._getMeta()
- label = m.group(2).strip()
- url = self.config['build_url'][0](label, base_url, end_url)
- a = markdown.etree.Element('a')
- a.text = label
+ label = m.group(1).strip()
+ url = self.config['build_url'](label, base_url, end_url)
+ a = etree.Element('a')
+ a.text = label
a.set('href', url)
if html_class:
a.set('class', html_class)
else:
a = ''
- return a
+ return a, m.start(0), m.end(0)
def _getMeta(self):
""" Return meta data or config data. """
- base_url = self.config['base_url'][0]
- end_url = self.config['end_url'][0]
- html_class = self.config['html_class'][0]
+ base_url = self.config['base_url']
+ end_url = self.config['end_url']
+ html_class = self.config['html_class']
if hasattr(self.md, 'Meta'):
- if self.md.Meta.has_key('wiki_base_url'):
+ if 'wiki_base_url' in self.md.Meta:
base_url = self.md.Meta['wiki_base_url'][0]
- if self.md.Meta.has_key('wiki_end_url'):
+ if 'wiki_end_url' in self.md.Meta:
end_url = self.md.Meta['wiki_end_url'][0]
- if self.md.Meta.has_key('wiki_html_class'):
+ if 'wiki_html_class' in self.md.Meta:
html_class = self.md.Meta['wiki_html_class'][0]
return base_url, end_url, html_class
-
-
-def makeExtension(configs=None) :
- return WikiLinkExtension(configs=configs)
-
-if __name__ == "__main__":
- import doctest
- doctest.testmod()
+def makeExtension(**kwargs): # pragma: no cover
+ return WikiLinkExtension(**kwargs)
diff --git a/markdown/html4.py b/markdown/html4.py
deleted file mode 100644
index 08f241d..0000000
--- a/markdown/html4.py
+++ /dev/null
@@ -1,274 +0,0 @@
-# markdown/html4.py
-#
-# Add html4 serialization to older versions of Elementree
-# Taken from ElementTree 1.3 preview with slight modifications
-#
-# Copyright (c) 1999-2007 by Fredrik Lundh. All rights reserved.
-#
-# fredrik@pythonware.com
-# http://www.pythonware.com
-#
-# --------------------------------------------------------------------
-# The ElementTree toolkit is
-#
-# Copyright (c) 1999-2007 by Fredrik Lundh
-#
-# By obtaining, using, and/or copying this software and/or its
-# associated documentation, you agree that you have read, understood,
-# and will comply with the following terms and conditions:
-#
-# Permission to use, copy, modify, and distribute this software and
-# its associated documentation for any purpose and without fee is
-# hereby granted, provided that the above copyright notice appears in
-# all copies, and that both that copyright notice and this permission
-# notice appear in supporting documentation, and that the name of
-# Secret Labs AB or the author not be used in advertising or publicity
-# pertaining to distribution of the software without specific, written
-# prior permission.
-#
-# SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
-# TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT-
-# ABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR
-# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
-# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
-# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
-# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
-# OF THIS SOFTWARE.
-# --------------------------------------------------------------------
-
-
-import markdown
-ElementTree = markdown.etree.ElementTree
-QName = markdown.etree.QName
-Comment = markdown.etree.Comment
-PI = markdown.etree.PI
-ProcessingInstruction = markdown.etree.ProcessingInstruction
-
-HTML_EMPTY = ("area", "base", "basefont", "br", "col", "frame", "hr",
- "img", "input", "isindex", "link", "meta" "param")
-
-try:
- HTML_EMPTY = set(HTML_EMPTY)
-except NameError:
- pass
-
-_namespace_map = {
- # "well-known" namespace prefixes
- "http://www.w3.org/XML/1998/namespace": "xml",
- "http://www.w3.org/1999/xhtml": "html",
- "http://www.w3.org/1999/02/22-rdf-syntax-ns#": "rdf",
- "http://schemas.xmlsoap.org/wsdl/": "wsdl",
- # xml schema
- "http://www.w3.org/2001/XMLSchema": "xs",
- "http://www.w3.org/2001/XMLSchema-instance": "xsi",
- # dublic core
- "http://purl.org/dc/elements/1.1/": "dc",
-}
-
-
-def _raise_serialization_error(text):
- raise TypeError(
- "cannot serialize %r (type %s)" % (text, type(text).__name__)
- )
-
-def _encode(text, encoding):
- try:
- return text.encode(encoding, "xmlcharrefreplace")
- except (TypeError, AttributeError):
- _raise_serialization_error(text)
-
-def _escape_cdata(text, encoding):
- # escape character data
- try:
- # it's worth avoiding do-nothing calls for strings that are
- # shorter than 500 character, or so. assume that's, by far,
- # the most common case in most applications.
- if "&" in text:
- text = text.replace("&", "&amp;")
- if "<" in text:
- text = text.replace("<", "&lt;")
- if ">" in text:
- text = text.replace(">", "&gt;")
- return text.encode(encoding, "xmlcharrefreplace")
- except (TypeError, AttributeError):
- _raise_serialization_error(text)
-
-
-def _escape_attrib(text, encoding):
- # escape attribute value
- try:
- if "&" in text:
- text = text.replace("&", "&amp;")
- if "<" in text:
- text = text.replace("<", "&lt;")
- if ">" in text:
- text = text.replace(">", "&gt;")
- if "\"" in text:
- text = text.replace("\"", "&quot;")
- if "\n" in text:
- text = text.replace("\n", "&#10;")
- return text.encode(encoding, "xmlcharrefreplace")
- except (TypeError, AttributeError):
- _raise_serialization_error(text)
-
-def _escape_attrib_html(text, encoding):
- # escape attribute value
- try:
- if "&" in text:
- text = text.replace("&", "&amp;")
- if ">" in text:
- text = text.replace(">", "&gt;")
- if "\"" in text:
- text = text.replace("\"", "&quot;")
- return text.encode(encoding, "xmlcharrefreplace")
- except (TypeError, AttributeError):
- _raise_serialization_error(text)
-
-
-def _serialize_html(write, elem, encoding, qnames, namespaces):
- tag = elem.tag
- text = elem.text
- if tag is Comment:
- write("<!--%s-->" % _escape_cdata(text, encoding))
- elif tag is ProcessingInstruction:
- write("<?%s?>" % _escape_cdata(text, encoding))
- else:
- tag = qnames[tag]
- if tag is None:
- if text:
- write(_escape_cdata(text, encoding))
- for e in elem:
- _serialize_html(write, e, encoding, qnames, None)
- else:
- write("<" + tag)
- items = elem.items()
- if items or namespaces:
- items.sort() # lexical order
- for k, v in items:
- if isinstance(k, QName):
- k = k.text
- if isinstance(v, QName):
- v = qnames[v.text]
- else:
- v = _escape_attrib_html(v, encoding)
- # FIXME: handle boolean attributes
- write(" %s=\"%s\"" % (qnames[k], v))
- if namespaces:
- items = namespaces.items()
- items.sort(key=lambda x: x[1]) # sort on prefix
- for v, k in items:
- if k:
- k = ":" + k
- write(" xmlns%s=\"%s\"" % (
- k.encode(encoding),
- _escape_attrib(v, encoding)
- ))
- write(">")
- tag = tag.lower()
- if text:
- if tag == "script" or tag == "style":
- write(_encode(text, encoding))
- else:
- write(_escape_cdata(text, encoding))
- for e in elem:
- _serialize_html(write, e, encoding, qnames, None)
- if tag not in HTML_EMPTY:
- write("</" + tag + ">")
- if elem.tail:
- write(_escape_cdata(elem.tail, encoding))
-
-def write_html(root, f,
- # keyword arguments
- encoding="us-ascii",
- default_namespace=None):
- assert root is not None
- if not hasattr(f, "write"):
- f = open(f, "wb")
- write = f.write
- if not encoding:
- encoding = "us-ascii"
- qnames, namespaces = _namespaces(
- root, encoding, default_namespace
- )
- _serialize_html(
- write, root, encoding, qnames, namespaces
- )
-
-# --------------------------------------------------------------------
-# serialization support
-
-def _namespaces(elem, encoding, default_namespace=None):
- # identify namespaces used in this tree
-
- # maps qnames to *encoded* prefix:local names
- qnames = {None: None}
-
- # maps uri:s to prefixes
- namespaces = {}
- if default_namespace:
- namespaces[default_namespace] = ""
-
- def encode(text):
- return text.encode(encoding)
-
- def add_qname(qname):
- # calculate serialized qname representation
- try:
- if qname[:1] == "{":
- uri, tag = qname[1:].split("}", 1)
- prefix = namespaces.get(uri)
- if prefix is None:
- prefix = _namespace_map.get(uri)
- if prefix is None:
- prefix = "ns%d" % len(namespaces)
- if prefix != "xml":
- namespaces[uri] = prefix
- if prefix:
- qnames[qname] = encode("%s:%s" % (prefix, tag))
- else:
- qnames[qname] = encode(tag) # default element
- else:
- if default_namespace:
- # FIXME: can this be handled in XML 1.0?
- raise ValueError(
- "cannot use non-qualified names with "
- "default_namespace option"
- )
- qnames[qname] = encode(qname)
- except TypeError:
- _raise_serialization_error(qname)
-
- # populate qname and namespaces table
- try:
- iterate = elem.iter
- except AttributeError:
- iterate = elem.getiterator # cET compatibility
- for elem in iterate():
- tag = elem.tag
- if isinstance(tag, QName) and tag.text not in qnames:
- add_qname(tag.text)
- elif isinstance(tag, basestring):
- if tag not in qnames:
- add_qname(tag)
- elif tag is not None and tag is not Comment and tag is not PI:
- _raise_serialization_error(tag)
- for key, value in elem.items():
- if isinstance(key, QName):
- key = key.text
- if key not in qnames:
- add_qname(key)
- if isinstance(value, QName) and value.text not in qnames:
- add_qname(value.text)
- text = elem.text
- if isinstance(text, QName) and text.text not in qnames:
- add_qname(text.text)
- return qnames, namespaces
-
-def to_html_string(element, encoding=None):
- class dummy:
- pass
- data = []
- file = dummy()
- file.write = data.append
- write_html(ElementTree(element).getroot(),file,encoding)
- return "".join(data)
diff --git a/markdown/htmlparser.py b/markdown/htmlparser.py
new file mode 100644
index 0000000..3512d1a
--- /dev/null
+++ b/markdown/htmlparser.py
@@ -0,0 +1,323 @@
+"""
+Python Markdown
+
+A Python implementation of John Gruber's Markdown.
+
+Documentation: https://python-markdown.github.io/
+GitHub: https://github.com/Python-Markdown/markdown/
+PyPI: https://pypi.org/project/Markdown/
+
+Started by Manfred Stienstra (http://www.dwerg.net/).
+Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
+Currently maintained by Waylan Limberg (https://github.com/waylan),
+Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
+
+Copyright 2007-2020 The Python Markdown Project (v. 1.7 and later)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see LICENSE.md for details).
+"""
+
+import re
+import importlib.util
+import sys
+
+
+# Import a copy of the html.parser lib as `htmlparser` so we can monkeypatch it.
+# Users can still do `from html import parser` and get the default behavior.
+spec = importlib.util.find_spec('html.parser')
+htmlparser = importlib.util.module_from_spec(spec)
+spec.loader.exec_module(htmlparser)
+sys.modules['htmlparser'] = htmlparser
+
+# Monkeypatch HTMLParser to only accept `?>` to close Processing Instructions.
+htmlparser.piclose = re.compile(r'\?>')
+# Monkeypatch HTMLParser to only recognize entity references with a closing semicolon.
+htmlparser.entityref = re.compile(r'&([a-zA-Z][-.a-zA-Z0-9]*);')
+# Monkeypatch HTMLParser to no longer support partial entities. We are always feeding a complete block,
+# so the 'incomplete' functionality is unnecessary. As the entityref regex is run right before incomplete,
+# and the two regex are the same, then incomplete will simply never match and we avoid the logic within.
+htmlparser.incomplete = htmlparser.entityref
+# Monkeypatch HTMLParser to not accept a backtick in a tag name, attribute name, or bare value.
+htmlparser.locatestarttagend_tolerant = re.compile(r"""
+ <[a-zA-Z][^`\t\n\r\f />\x00]* # tag name <= added backtick here
+ (?:[\s/]* # optional whitespace before attribute name
+ (?:(?<=['"\s/])[^`\s/>][^\s/=>]* # attribute name <= added backtick here
+ (?:\s*=+\s* # value indicator
+ (?:'[^']*' # LITA-enclosed value
+ |"[^"]*" # LIT-enclosed value
+ |(?!['"])[^`>\s]* # bare value <= added backtick here
+ )
+ (?:\s*,)* # possibly followed by a comma
+ )?(?:\s|/(?!>))*
+ )*
+ )?
+ \s* # trailing whitespace
+""", re.VERBOSE)
+
+# Match a blank line at the start of a block of text (two newlines).
+# The newlines may be preceded by additional whitespace.
+blank_line_re = re.compile(r'^([ ]*\n){2}')
+
+
+class HTMLExtractor(htmlparser.HTMLParser):
+ """
+ Extract raw HTML from text.
+
+ The raw HTML is stored in the `htmlStash` of the Markdown instance passed
+ to `md` and the remaining text is stored in `cleandoc` as a list of strings.
+ """
+
+ def __init__(self, md, *args, **kwargs):
+ if 'convert_charrefs' not in kwargs:
+ kwargs['convert_charrefs'] = False
+
+ # Block tags that should contain no content (self closing)
+ self.empty_tags = set(['hr'])
+
+ # This calls self.reset
+ super().__init__(*args, **kwargs)
+ self.md = md
+
+ def reset(self):
+ """Reset this instance. Loses all unprocessed data."""
+ self.inraw = False
+ self.intail = False
+ self.stack = [] # When inraw==True, stack contains a list of tags
+ self._cache = []
+ self.cleandoc = []
+ super().reset()
+
+ def close(self):
+ """Handle any buffered data."""
+ super().close()
+ if len(self.rawdata):
+ # Temp fix for https://bugs.python.org/issue41989
+ # TODO: remove this when the bug is fixed in all supported Python versions.
+ if self.convert_charrefs and not self.cdata_elem: # pragma: no cover
+ self.handle_data(htmlparser.unescape(self.rawdata))
+ else:
+ self.handle_data(self.rawdata)
+ # Handle any unclosed tags.
+ if len(self._cache):
+ self.cleandoc.append(self.md.htmlStash.store(''.join(self._cache)))
+ self._cache = []
+
+ @property
+ def line_offset(self):
+ """Returns char index in self.rawdata for the start of the current line. """
+ if self.lineno > 1 and '\n' in self.rawdata:
+ m = re.match(r'([^\n]*\n){{{}}}'.format(self.lineno-1), self.rawdata)
+ if m:
+ return m.end()
+ else: # pragma: no cover
+ # Value of self.lineno must exceed total number of lines.
+ # Find index of beginning of last line.
+ return self.rawdata.rfind('\n')
+ return 0
+
+ def at_line_start(self):
+ """
+ Returns True if current position is at start of line.
+
+ Allows for up to three blank spaces at start of line.
+ """
+ if self.offset == 0:
+ return True
+ if self.offset > 3:
+ return False
+ # Confirm up to first 3 chars are whitespace
+ return self.rawdata[self.line_offset:self.line_offset + self.offset].strip() == ''
+
+ def get_endtag_text(self, tag):
+ """
+ Returns the text of the end tag.
+
+ If it fails to extract the actual text from the raw data, it builds a closing tag with `tag`.
+ """
+ # Attempt to extract actual tag from raw source text
+ start = self.line_offset + self.offset
+ m = htmlparser.endendtag.search(self.rawdata, start)
+ if m:
+ return self.rawdata[start:m.end()]
+ else: # pragma: no cover
+ # Failed to extract from raw data. Assume well formed and lowercase.
+ return '</{}>'.format(tag)
+
+ def handle_starttag(self, tag, attrs):
+ # Handle tags that should always be empty and do not specify a closing tag
+ if tag in self.empty_tags:
+ self.handle_startendtag(tag, attrs)
+ return
+
+ if self.md.is_block_level(tag) and (self.intail or (self.at_line_start() and not self.inraw)):
+ # Started a new raw block. Prepare stack.
+ self.inraw = True
+ self.cleandoc.append('\n')
+
+ text = self.get_starttag_text()
+ if self.inraw:
+ self.stack.append(tag)
+ self._cache.append(text)
+ else:
+ self.cleandoc.append(text)
+ if tag in self.CDATA_CONTENT_ELEMENTS:
+ # This is presumably a standalone tag in a code span (see #1036).
+ self.clear_cdata_mode()
+
+ def handle_endtag(self, tag):
+ text = self.get_endtag_text(tag)
+
+ if self.inraw:
+ self._cache.append(text)
+ if tag in self.stack:
+ # Remove tag from stack
+ while self.stack:
+ if self.stack.pop() == tag:
+ break
+ if len(self.stack) == 0:
+ # End of raw block.
+ if blank_line_re.match(self.rawdata[self.line_offset + self.offset + len(text):]):
+ # Preserve blank line and end of raw block.
+ self._cache.append('\n')
+ else:
+ # More content exists after endtag.
+ self.intail = True
+ # Reset stack.
+ self.inraw = False
+ self.cleandoc.append(self.md.htmlStash.store(''.join(self._cache)))
+ # Insert blank line between this and next line.
+ self.cleandoc.append('\n\n')
+ self._cache = []
+ else:
+ self.cleandoc.append(text)
+
+ def handle_data(self, data):
+ if self.intail and '\n' in data:
+ self.intail = False
+ if self.inraw:
+ self._cache.append(data)
+ else:
+ self.cleandoc.append(data)
+
+ def handle_empty_tag(self, data, is_block):
+ """ Handle empty tags (`<data>`). """
+ if self.inraw or self.intail:
+ # Append this to the existing raw block
+ self._cache.append(data)
+ elif self.at_line_start() and is_block:
+ # Handle this as a standalone raw block
+ if blank_line_re.match(self.rawdata[self.line_offset + self.offset + len(data):]):
+ # Preserve blank line after tag in raw block.
+ data += '\n'
+ else:
+ # More content exists after tag.
+ self.intail = True
+ item = self.cleandoc[-1] if self.cleandoc else ''
+ # If we only have one newline before block element, add another
+ if not item.endswith('\n\n') and item.endswith('\n'):
+ self.cleandoc.append('\n')
+ self.cleandoc.append(self.md.htmlStash.store(data))
+ # Insert blank line between this and next line.
+ self.cleandoc.append('\n\n')
+ else:
+ self.cleandoc.append(data)
+
+ def handle_startendtag(self, tag, attrs):
+ self.handle_empty_tag(self.get_starttag_text(), is_block=self.md.is_block_level(tag))
+
+ def handle_charref(self, name):
+ self.handle_empty_tag('&#{};'.format(name), is_block=False)
+
+ def handle_entityref(self, name):
+ self.handle_empty_tag('&{};'.format(name), is_block=False)
+
+ def handle_comment(self, data):
+ self.handle_empty_tag('<!--{}-->'.format(data), is_block=True)
+
+ def handle_decl(self, data):
+ self.handle_empty_tag('<!{}>'.format(data), is_block=True)
+
+ def handle_pi(self, data):
+ self.handle_empty_tag('<?{}?>'.format(data), is_block=True)
+
+ def unknown_decl(self, data):
+ end = ']]>' if data.startswith('CDATA[') else ']>'
+ self.handle_empty_tag('<![{}{}'.format(data, end), is_block=True)
+
+ def parse_pi(self, i):
+ if self.at_line_start() or self.intail:
+ return super().parse_pi(i)
+ # This is not the beginning of a raw block so treat as plain data
+ # and avoid consuming any tags which may follow (see #1066).
+ self.handle_data('<?')
+ return i + 2
+
+ def parse_html_declaration(self, i):
+ if self.at_line_start() or self.intail:
+ return super().parse_html_declaration(i)
+ # This is not the beginning of a raw block so treat as plain data
+ # and avoid consuming any tags which may follow (see #1066).
+ self.handle_data('<!')
+ return i + 2
+
+ # The rest has been copied from base class in standard lib to address #1036.
+ # As __startag_text is private, all references to it must be in this subclass.
+ # The last few lines of parse_starttag are reversed so that handle_starttag
+ # can override cdata_mode in certain situations (in a code span).
+ __starttag_text = None
+
+ def get_starttag_text(self):
+ """Return full source of start tag: '<...>'."""
+ return self.__starttag_text
+
+ def parse_starttag(self, i): # pragma: no cover
+ self.__starttag_text = None
+ endpos = self.check_for_whole_start_tag(i)
+ if endpos < 0:
+ return endpos
+ rawdata = self.rawdata
+ self.__starttag_text = rawdata[i:endpos]
+
+ # Now parse the data between i+1 and j into a tag and attrs
+ attrs = []
+ match = htmlparser.tagfind_tolerant.match(rawdata, i+1)
+ assert match, 'unexpected call to parse_starttag()'
+ k = match.end()
+ self.lasttag = tag = match.group(1).lower()
+ while k < endpos:
+ m = htmlparser.attrfind_tolerant.match(rawdata, k)
+ if not m:
+ break
+ attrname, rest, attrvalue = m.group(1, 2, 3)
+ if not rest:
+ attrvalue = None
+ elif attrvalue[:1] == '\'' == attrvalue[-1:] or \
+ attrvalue[:1] == '"' == attrvalue[-1:]: # noqa: E127
+ attrvalue = attrvalue[1:-1]
+ if attrvalue:
+ attrvalue = htmlparser.unescape(attrvalue)
+ attrs.append((attrname.lower(), attrvalue))
+ k = m.end()
+
+ end = rawdata[k:endpos].strip()
+ if end not in (">", "/>"):
+ lineno, offset = self.getpos()
+ if "\n" in self.__starttag_text:
+ lineno = lineno + self.__starttag_text.count("\n")
+ offset = len(self.__starttag_text) \
+ - self.__starttag_text.rfind("\n") # noqa: E127
+ else:
+ offset = offset + len(self.__starttag_text)
+ self.handle_data(rawdata[i:endpos])
+ return endpos
+ if end.endswith('/>'):
+ # XHTML-style empty tag: <span attr="value" />
+ self.handle_startendtag(tag, attrs)
+ else:
+ # *** set cdata_mode first so we can override it in handle_starttag (see #1036) ***
+ if tag in self.CDATA_CONTENT_ELEMENTS:
+ self.set_cdata_mode(tag)
+ self.handle_starttag(tag, attrs)
+ return endpos
diff --git a/markdown/inlinepatterns.py b/markdown/inlinepatterns.py
index 917a9d3..eb313bd 100644
--- a/markdown/inlinepatterns.py
+++ b/markdown/inlinepatterns.py
@@ -1,4 +1,23 @@
"""
+Python Markdown
+
+A Python implementation of John Gruber's Markdown.
+
+Documentation: https://python-markdown.github.io/
+GitHub: https://github.com/Python-Markdown/markdown/
+PyPI: https://pypi.org/project/Markdown/
+
+Started by Manfred Stienstra (http://www.dwerg.net/).
+Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
+Currently maintained by Waylan Limberg (https://github.com/waylan),
+Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
+
+Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see LICENSE.md for details).
+
INLINE PATTERNS
=============================================================================
@@ -41,71 +60,129 @@ So, we apply the expressions in the following order:
* finally we apply strong and emphasis
"""
-import markdown
+from . import util
+from collections import namedtuple
import re
-from urlparse import urlparse, urlunparse
-import sys
-if sys.version >= "3.0":
- from html import entities as htmlentitydefs
-else:
- import htmlentitydefs
+import xml.etree.ElementTree as etree
+try: # pragma: no cover
+ from html import entities
+except ImportError: # pragma: no cover
+ import htmlentitydefs as entities
+
+
+def build_inlinepatterns(md, **kwargs):
+ """ Build the default set of inline patterns for Markdown. """
+ inlinePatterns = util.Registry()
+ inlinePatterns.register(BacktickInlineProcessor(BACKTICK_RE), 'backtick', 190)
+ inlinePatterns.register(EscapeInlineProcessor(ESCAPE_RE, md), 'escape', 180)
+ inlinePatterns.register(ReferenceInlineProcessor(REFERENCE_RE, md), 'reference', 170)
+ inlinePatterns.register(LinkInlineProcessor(LINK_RE, md), 'link', 160)
+ inlinePatterns.register(ImageInlineProcessor(IMAGE_LINK_RE, md), 'image_link', 150)
+ inlinePatterns.register(
+ ImageReferenceInlineProcessor(IMAGE_REFERENCE_RE, md), 'image_reference', 140
+ )
+ inlinePatterns.register(
+ ShortReferenceInlineProcessor(REFERENCE_RE, md), 'short_reference', 130
+ )
+ inlinePatterns.register(
+ ShortImageReferenceInlineProcessor(IMAGE_REFERENCE_RE, md), 'short_image_ref', 125
+ )
+ inlinePatterns.register(AutolinkInlineProcessor(AUTOLINK_RE, md), 'autolink', 120)
+ inlinePatterns.register(AutomailInlineProcessor(AUTOMAIL_RE, md), 'automail', 110)
+ inlinePatterns.register(SubstituteTagInlineProcessor(LINE_BREAK_RE, 'br'), 'linebreak', 100)
+ inlinePatterns.register(HtmlInlineProcessor(HTML_RE, md), 'html', 90)
+ inlinePatterns.register(HtmlInlineProcessor(ENTITY_RE, md), 'entity', 80)
+ inlinePatterns.register(SimpleTextInlineProcessor(NOT_STRONG_RE), 'not_strong', 70)
+ inlinePatterns.register(AsteriskProcessor(r'\*'), 'em_strong', 60)
+ inlinePatterns.register(UnderscoreProcessor(r'_'), 'em_strong2', 50)
+ return inlinePatterns
+
"""
The actual regular expressions for patterns
-----------------------------------------------------------------------------
"""
-NOBRACKET = r'[^\]\[]*'
-BRK = ( r'\[('
- + (NOBRACKET + r'(\[')*6
- + (NOBRACKET+ r'\])*')*6
- + NOBRACKET + r')\]' )
NOIMG = r'(?<!\!)'
-BACKTICK_RE = r'(?<!\\)(`+)(.+?)(?<!`)\2(?!`)' # `e=f()` or ``e=f("`")``
-ESCAPE_RE = r'\\(.)' # \<
-EMPHASIS_RE = r'(\*)([^\*]+)\2' # *emphasis*
-STRONG_RE = r'(\*{2}|_{2})(.+?)\2' # **strong**
-STRONG_EM_RE = r'(\*{3}|_{3})(.+?)\2' # ***strong***
+# `e=f()` or ``e=f("`")``
+BACKTICK_RE = r'(?:(?<!\\)((?:\\{2})+)(?=`+)|(?<!\\)(`+)(.+?)(?<!`)\2(?!`))'
+
+# \<
+ESCAPE_RE = r'\\(.)'
+
+# *emphasis*
+EMPHASIS_RE = r'(\*)([^\*]+)\1'
+
+# **strong**
+STRONG_RE = r'(\*{2})(.+?)\1'
+
+# __smart__strong__
+SMART_STRONG_RE = r'(?<!\w)(_{2})(?!_)(.+?)(?<!_)\1(?!\w)'
-if markdown.SMART_EMPHASIS:
- EMPHASIS_2_RE = r'(?<!\w)(_)(\S.+?)\2(?!\w)' # _emphasis_
-else:
- EMPHASIS_2_RE = r'(_)(.+?)\2' # _emphasis_
+# _smart_emphasis_
+SMART_EMPHASIS_RE = r'(?<!\w)(_)(?!_)(.+?)(?<!_)\1(?!\w)'
-LINK_RE = NOIMG + BRK + \
-r'''\(\s*(<.*?>|((?:(?:\(.*?\))|[^\(\)]))*?)\s*((['"])(.*?)\12)?\)'''
-# [text](url) or [text](<url>)
+# __strong _em__
+SMART_STRONG_EM_RE = r'(?<!\w)(\_)\1(?!\1)(.+?)(?<!\w)\1(?!\1)(.+?)\1{3}(?!\w)'
+
+# ***strongem*** or ***em*strong**
+EM_STRONG_RE = r'(\*)\1{2}(.+?)\1(.*?)\1{2}'
+
+# ___strongem___ or ___em_strong__
+EM_STRONG2_RE = r'(_)\1{2}(.+?)\1(.*?)\1{2}'
+
+# ***strong**em*
+STRONG_EM_RE = r'(\*)\1{2}(.+?)\1{2}(.*?)\1'
+
+# ___strong__em_
+STRONG_EM2_RE = r'(_)\1{2}(.+?)\1{2}(.*?)\1'
+
+# **strong*em***
+STRONG_EM3_RE = r'(\*)\1(?!\1)([^*]+?)\1(?!\1)(.+?)\1{3}'
+
+# [text](url) or [text](<url>) or [text](url "title")
+LINK_RE = NOIMG + r'\['
-IMAGE_LINK_RE = r'\!' + BRK + r'\s*\((<.*?>|([^\)]*))\)'
# ![alttxt](http://x.com/) or ![alttxt](<http://x.com/>)
-REFERENCE_RE = NOIMG + BRK+ r'\s*\[([^\]]*)\]' # [Google][3]
-IMAGE_REFERENCE_RE = r'\!' + BRK + '\s*\[([^\]]*)\]' # ![alt text][2]
-NOT_STRONG_RE = r'((^| )(\*|_)( |$))' # stand-alone * or _
-AUTOLINK_RE = r'<((?:f|ht)tps?://[^>]*)>' # <http://www.123.com>
-AUTOMAIL_RE = r'<([^> \!]*@[^> ]*)>' # <me@example.com>
+IMAGE_LINK_RE = r'\!\['
+
+# [Google][3]
+REFERENCE_RE = LINK_RE
+
+# ![alt text][2]
+IMAGE_REFERENCE_RE = IMAGE_LINK_RE
+
+# stand-alone * or _
+NOT_STRONG_RE = r'((^|\s)(\*|_)(\s|$))'
+
+# <http://www.123.com>
+AUTOLINK_RE = r'<((?:[Ff]|[Hh][Tt])[Tt][Pp][Ss]?://[^<>]*)>'
-HTML_RE = r'(\<([a-zA-Z/][^\>]*?|\!--.*?--)\>)' # <...>
-ENTITY_RE = r'(&[\#a-zA-Z0-9]*;)' # &amp;
-LINE_BREAK_RE = r' \n' # two spaces at end of line
-LINE_BREAK_2_RE = r' $' # two spaces at end of text
+# <me@example.com>
+AUTOMAIL_RE = r'<([^<> !]+@[^@<> ]+)>'
+
+# <...>
+HTML_RE = r'(<(\/?[a-zA-Z][^<>@ ]*( [^<>]*)?|!--(?:(?!<!--|-->).)*--)>)'
+
+# "&#38;" (decimal) or "&#x26;" (hex) or "&amp;" (named)
+ENTITY_RE = r'(&(?:\#[0-9]+|\#x[0-9a-fA-F]+|[a-zA-Z0-9]+);)'
+
+# two spaces at end of line
+LINE_BREAK_RE = r' \n'
def dequote(string):
"""Remove quotes from around a string."""
- if ( ( string.startswith('"') and string.endswith('"'))
- or (string.startswith("'") and string.endswith("'")) ):
+ if ((string.startswith('"') and string.endswith('"')) or
+ (string.startswith("'") and string.endswith("'"))):
return string[1:-1]
else:
return string
-ATTR_RE = re.compile("\{@([^\}]*)=([^\}]*)}") # {@id=123}
-def handleAttributes(text, parent):
- """Set values of an element based on attribute definitions ({@id=123})."""
- def attributeCallback(match):
- parent.set(match.group(1), match.group(2).replace('\n', ' '))
- return ATTR_RE.sub(attributeCallback, text)
+class EmStrongItem(namedtuple('EmStrongItem', ['pattern', 'builder', 'tags'])):
+ """Emphasis/strong pattern item."""
"""
@@ -113,10 +190,13 @@ The pattern classes
-----------------------------------------------------------------------------
"""
-class Pattern:
+
+class Pattern: # pragma: no cover
"""Base class that inline patterns subclass. """
- def __init__ (self, pattern, markdown_instance=None):
+ ANCESTOR_EXCLUDES = tuple()
+
+ def __init__(self, pattern, md=None):
"""
Create an instant of an inline pattern.
@@ -126,14 +206,12 @@ class Pattern:
"""
self.pattern = pattern
- self.compiled_re = re.compile("^(.*?)%s(.*?)$" % pattern, re.DOTALL)
+ self.compiled_re = re.compile(r"^(.*?)%s(.*)$" % pattern,
+ re.DOTALL | re.UNICODE)
- # Api for Markdown to pass safe_mode into instance
- self.safe_mode = False
- if markdown_instance:
- self.markdown = markdown_instance
+ self.md = md
- def getCompiledRegExp (self):
+ def getCompiledRegExp(self):
""" Return a compiled regular expression. """
return self.compiled_re
@@ -147,57 +225,163 @@ class Pattern:
* m: A re match object containing a match of the pattern.
"""
- pass
+ pass # pragma: no cover
def type(self):
""" Return class name, to define pattern type """
return self.__class__.__name__
-BasePattern = Pattern # for backward compatibility
+ def unescape(self, text):
+ """ Return unescaped text given text with an inline placeholder. """
+ try:
+ stash = self.md.treeprocessors['inline'].stashed_nodes
+ except KeyError: # pragma: no cover
+ return text
+
+ def get_stash(m):
+ id = m.group(1)
+ if id in stash:
+ value = stash.get(id)
+ if isinstance(value, str):
+ return value
+ else:
+ # An etree Element - return text content only
+ return ''.join(value.itertext())
+ return util.INLINE_PLACEHOLDER_RE.sub(get_stash, text)
+
+
+class InlineProcessor(Pattern):
+ """
+ Base class that inline patterns subclass.
+
+ This is the newer style inline processor that uses a more
+ efficient and flexible search approach.
+ """
+
+ def __init__(self, pattern, md=None):
+ """
+ Create an instant of an inline pattern.
+
+ Keyword arguments:
+
+ * pattern: A regular expression that matches a pattern
+
+ """
+ self.pattern = pattern
+ self.compiled_re = re.compile(pattern, re.DOTALL | re.UNICODE)
+
+ # Api for Markdown to pass safe_mode into instance
+ self.safe_mode = False
+ self.md = md
+
+ def handleMatch(self, m, data):
+ """Return a ElementTree element from the given match and the
+ start and end index of the matched text.
+
+ If `start` and/or `end` are returned as `None`, it will be
+ assumed that the processor did not find a valid region of text.
+
+ Subclasses should override this method.
+
+ Keyword arguments:
+
+ * m: A re match object containing a match of the pattern.
+ * data: The buffer current under analysis
-class SimpleTextPattern (Pattern):
+ Returns:
+
+ * el: The ElementTree element, text or None.
+ * start: The start of the region that has been matched or None.
+ * end: The end of the region that has been matched or None.
+
+ """
+ pass # pragma: no cover
+
+
+class SimpleTextPattern(Pattern): # pragma: no cover
""" Return a simple text of group(2) of a Pattern. """
def handleMatch(self, m):
- text = m.group(2)
- if text == markdown.INLINE_PLACEHOLDER_PREFIX:
- return None
- return text
+ return m.group(2)
+
+
+class SimpleTextInlineProcessor(InlineProcessor):
+ """ Return a simple text of group(1) of a Pattern. """
+ def handleMatch(self, m, data):
+ return m.group(1), m.start(0), m.end(0)
+
+
+class EscapeInlineProcessor(InlineProcessor):
+ """ Return an escaped character. """
-class SimpleTagPattern (Pattern):
+ def handleMatch(self, m, data):
+ char = m.group(1)
+ if char in self.md.ESCAPED_CHARS:
+ return '{}{}{}'.format(util.STX, ord(char), util.ETX), m.start(0), m.end(0)
+ else:
+ return None, m.start(0), m.end(0)
+
+
+class SimpleTagPattern(Pattern): # pragma: no cover
"""
Return element of type `tag` with a text attribute of group(3)
of a Pattern.
"""
- def __init__ (self, pattern, tag):
+ def __init__(self, pattern, tag):
Pattern.__init__(self, pattern)
self.tag = tag
def handleMatch(self, m):
- el = markdown.etree.Element(self.tag)
+ el = etree.Element(self.tag)
el.text = m.group(3)
return el
-class SubstituteTagPattern (SimpleTagPattern):
- """ Return a eLement of type `tag` with no children. """
- def handleMatch (self, m):
- return markdown.etree.Element(self.tag)
+class SimpleTagInlineProcessor(InlineProcessor):
+ """
+ Return element of type `tag` with a text attribute of group(2)
+ of a Pattern.
+ """
+ def __init__(self, pattern, tag):
+ InlineProcessor.__init__(self, pattern)
+ self.tag = tag
-class BacktickPattern (Pattern):
- """ Return a `<code>` element containing the matching text. """
- def __init__ (self, pattern):
- Pattern.__init__(self, pattern)
- self.tag = "code"
+ def handleMatch(self, m, data): # pragma: no cover
+ el = etree.Element(self.tag)
+ el.text = m.group(2)
+ return el, m.start(0), m.end(0)
+
+class SubstituteTagPattern(SimpleTagPattern): # pragma: no cover
+ """ Return an element of type `tag` with no children. """
def handleMatch(self, m):
- el = markdown.etree.Element(self.tag)
- el.text = markdown.AtomicString(m.group(3).strip())
- return el
+ return etree.Element(self.tag)
+
+
+class SubstituteTagInlineProcessor(SimpleTagInlineProcessor):
+ """ Return an element of type `tag` with no children. """
+ def handleMatch(self, m, data):
+ return etree.Element(self.tag), m.start(0), m.end(0)
+
+
+class BacktickInlineProcessor(InlineProcessor):
+ """ Return a `<code>` element containing the matching text. """
+ def __init__(self, pattern):
+ InlineProcessor.__init__(self, pattern)
+ self.ESCAPED_BSLASH = '{}{}{}'.format(util.STX, ord('\\'), util.ETX)
+ self.tag = 'code'
+
+ def handleMatch(self, m, data):
+ if m.group(3):
+ el = etree.Element(self.tag)
+ el.text = util.AtomicString(util.code_escape(m.group(3).strip()))
+ return el, m.start(0), m.end(0)
+ else:
+ return m.group(1).replace('\\\\', self.ESCAPED_BSLASH), m.start(0), m.end(0)
-class DoubleTagPattern (SimpleTagPattern):
+class DoubleTagPattern(SimpleTagPattern): # pragma: no cover
"""Return a ElementTree element nested in tag2 nested in tag1.
Useful for strong emphasis etc.
@@ -205,117 +389,432 @@ class DoubleTagPattern (SimpleTagPattern):
"""
def handleMatch(self, m):
tag1, tag2 = self.tag.split(",")
- el1 = markdown.etree.Element(tag1)
- el2 = markdown.etree.SubElement(el1, tag2)
+ el1 = etree.Element(tag1)
+ el2 = etree.SubElement(el1, tag2)
el2.text = m.group(3)
+ if len(m.groups()) == 5:
+ el2.tail = m.group(4)
return el1
-class HtmlPattern (Pattern):
+class DoubleTagInlineProcessor(SimpleTagInlineProcessor):
+ """Return a ElementTree element nested in tag2 nested in tag1.
+
+ Useful for strong emphasis etc.
+
+ """
+ def handleMatch(self, m, data): # pragma: no cover
+ tag1, tag2 = self.tag.split(",")
+ el1 = etree.Element(tag1)
+ el2 = etree.SubElement(el1, tag2)
+ el2.text = m.group(2)
+ if len(m.groups()) == 3:
+ el2.tail = m.group(3)
+ return el1, m.start(0), m.end(0)
+
+
+class HtmlInlineProcessor(InlineProcessor):
""" Store raw inline html and return a placeholder. """
- def handleMatch (self, m):
- rawhtml = m.group(2)
- inline = True
- place_holder = self.markdown.htmlStash.store(rawhtml)
- return place_holder
+ def handleMatch(self, m, data):
+ rawhtml = self.unescape(m.group(1))
+ place_holder = self.md.htmlStash.store(rawhtml)
+ return place_holder, m.start(0), m.end(0)
+
+ def unescape(self, text):
+ """ Return unescaped text given text with an inline placeholder. """
+ try:
+ stash = self.md.treeprocessors['inline'].stashed_nodes
+ except KeyError: # pragma: no cover
+ return text
+
+ def get_stash(m):
+ id = m.group(1)
+ value = stash.get(id)
+ if value is not None:
+ try:
+ return self.md.serializer(value)
+ except Exception:
+ return r'\%s' % value
+
+ return util.INLINE_PLACEHOLDER_RE.sub(get_stash, text)
+
+
+class AsteriskProcessor(InlineProcessor):
+ """Emphasis processor for handling strong and em matches inside asterisks."""
+
+ PATTERNS = [
+ EmStrongItem(re.compile(EM_STRONG_RE, re.DOTALL | re.UNICODE), 'double', 'strong,em'),
+ EmStrongItem(re.compile(STRONG_EM_RE, re.DOTALL | re.UNICODE), 'double', 'em,strong'),
+ EmStrongItem(re.compile(STRONG_EM3_RE, re.DOTALL | re.UNICODE), 'double2', 'strong,em'),
+ EmStrongItem(re.compile(STRONG_RE, re.DOTALL | re.UNICODE), 'single', 'strong'),
+ EmStrongItem(re.compile(EMPHASIS_RE, re.DOTALL | re.UNICODE), 'single', 'em')
+ ]
+
+ def build_single(self, m, tag, idx):
+ """Return single tag."""
+ el1 = etree.Element(tag)
+ text = m.group(2)
+ self.parse_sub_patterns(text, el1, None, idx)
+ return el1
+ def build_double(self, m, tags, idx):
+ """Return double tag."""
-class LinkPattern (Pattern):
- """ Return a link element from the given match. """
- def handleMatch(self, m):
- el = markdown.etree.Element("a")
- el.text = m.group(2)
- title = m.group(11)
- href = m.group(9)
+ tag1, tag2 = tags.split(",")
+ el1 = etree.Element(tag1)
+ el2 = etree.Element(tag2)
+ text = m.group(2)
+ self.parse_sub_patterns(text, el2, None, idx)
+ el1.append(el2)
+ if len(m.groups()) == 3:
+ text = m.group(3)
+ self.parse_sub_patterns(text, el1, el2, idx)
+ return el1
- if href:
- if href[0] == "<":
- href = href[1:-1]
- el.set("href", self.sanitize_url(href.strip()))
- else:
- el.set("href", "")
+ def build_double2(self, m, tags, idx):
+ """Return double tags (variant 2): `<strong>text <em>text</em></strong>`."""
- if title:
- title = dequote(title) #.replace('"', "&quot;")
- el.set("title", title)
- return el
+ tag1, tag2 = tags.split(",")
+ el1 = etree.Element(tag1)
+ el2 = etree.Element(tag2)
+ text = m.group(2)
+ self.parse_sub_patterns(text, el1, None, idx)
+ text = m.group(3)
+ el1.append(el2)
+ self.parse_sub_patterns(text, el2, None, idx)
+ return el1
- def sanitize_url(self, url):
+ def parse_sub_patterns(self, data, parent, last, idx):
"""
- Sanitize a url against xss attacks in "safe_mode".
-
- Rather than specifically blacklisting `javascript:alert("XSS")` and all
- its aliases (see <http://ha.ckers.org/xss.html>), we whitelist known
- safe url formats. Most urls contain a network location, however some
- are known not to (i.e.: mailto links). Script urls do not contain a
- location. Additionally, for `javascript:...`, the scheme would be
- "javascript" but some aliases will appear to `urlparse()` to have no
- scheme. On top of that relative links (i.e.: "foo/bar.html") have no
- scheme. Therefore we must check "path", "parameters", "query" and
- "fragment" for any literal colons. We don't check "scheme" for colons
- because it *should* never have any and "netloc" must allow the form:
- `username:password@host:port`.
+ Parses sub patterns.
+
+ `data` (`str`):
+ text to evaluate.
+
+ `parent` (`etree.Element`):
+ Parent to attach text and sub elements to.
+
+ `last` (`etree.Element`):
+ Last appended child to parent. Can also be None if parent has no children.
+
+ `idx` (`int`):
+ Current pattern index that was used to evaluate the parent.
"""
- locless_schemes = ['', 'mailto', 'news']
- scheme, netloc, path, params, query, fragment = url = urlparse(url)
- safe_url = False
- if netloc != '' or scheme in locless_schemes:
- safe_url = True
-
- for part in url[2:]:
- if ":" in part:
- safe_url = False
-
- if self.markdown.safeMode and not safe_url:
- return ''
+
+ offset = 0
+ pos = 0
+
+ length = len(data)
+ while pos < length:
+ # Find the start of potential emphasis or strong tokens
+ if self.compiled_re.match(data, pos):
+ matched = False
+ # See if the we can match an emphasis/strong pattern
+ for index, item in enumerate(self.PATTERNS):
+ # Only evaluate patterns that are after what was used on the parent
+ if index <= idx:
+ continue
+ m = item.pattern.match(data, pos)
+ if m:
+ # Append child nodes to parent
+ # Text nodes should be appended to the last
+ # child if present, and if not, it should
+ # be added as the parent's text node.
+ text = data[offset:m.start(0)]
+ if text:
+ if last is not None:
+ last.tail = text
+ else:
+ parent.text = text
+ el = self.build_element(m, item.builder, item.tags, index)
+ parent.append(el)
+ last = el
+ # Move our position past the matched hunk
+ offset = pos = m.end(0)
+ matched = True
+ if not matched:
+ # We matched nothing, move on to the next character
+ pos += 1
+ else:
+ # Increment position as no potential emphasis start was found.
+ pos += 1
+
+ # Append any leftover text as a text node.
+ text = data[offset:]
+ if text:
+ if last is not None:
+ last.tail = text
+ else:
+ parent.text = text
+
+ def build_element(self, m, builder, tags, index):
+ """Element builder."""
+
+ if builder == 'double2':
+ return self.build_double2(m, tags, index)
+ elif builder == 'double':
+ return self.build_double(m, tags, index)
else:
- return urlunparse(url)
+ return self.build_single(m, tags, index)
+
+ def handleMatch(self, m, data):
+ """Parse patterns."""
+
+ el = None
+ start = None
+ end = None
+
+ for index, item in enumerate(self.PATTERNS):
+ m1 = item.pattern.match(data, m.start(0))
+ if m1:
+ start = m1.start(0)
+ end = m1.end(0)
+ el = self.build_element(m1, item.builder, item.tags, index)
+ break
+ return el, start, end
-class ImagePattern(LinkPattern):
+
+class UnderscoreProcessor(AsteriskProcessor):
+ """Emphasis processor for handling strong and em matches inside underscores."""
+
+ PATTERNS = [
+ EmStrongItem(re.compile(EM_STRONG2_RE, re.DOTALL | re.UNICODE), 'double', 'strong,em'),
+ EmStrongItem(re.compile(STRONG_EM2_RE, re.DOTALL | re.UNICODE), 'double', 'em,strong'),
+ EmStrongItem(re.compile(SMART_STRONG_EM_RE, re.DOTALL | re.UNICODE), 'double2', 'strong,em'),
+ EmStrongItem(re.compile(SMART_STRONG_RE, re.DOTALL | re.UNICODE), 'single', 'strong'),
+ EmStrongItem(re.compile(SMART_EMPHASIS_RE, re.DOTALL | re.UNICODE), 'single', 'em')
+ ]
+
+
+class LinkInlineProcessor(InlineProcessor):
+ """ Return a link element from the given match. """
+ RE_LINK = re.compile(r'''\(\s*(?:(<[^<>]*>)\s*(?:('[^']*'|"[^"]*")\s*)?\))?''', re.DOTALL | re.UNICODE)
+ RE_TITLE_CLEAN = re.compile(r'\s')
+
+ def handleMatch(self, m, data):
+ text, index, handled = self.getText(data, m.end(0))
+
+ if not handled:
+ return None, None, None
+
+ href, title, index, handled = self.getLink(data, index)
+ if not handled:
+ return None, None, None
+
+ el = etree.Element("a")
+ el.text = text
+
+ el.set("href", href)
+
+ if title is not None:
+ el.set("title", title)
+
+ return el, m.start(0), index
+
+ def getLink(self, data, index):
+ """Parse data between `()` of `[Text]()` allowing recursive `()`. """
+
+ href = ''
+ title = None
+ handled = False
+
+ m = self.RE_LINK.match(data, pos=index)
+ if m and m.group(1):
+ # Matches [Text](<link> "title")
+ href = m.group(1)[1:-1].strip()
+ if m.group(2):
+ title = m.group(2)[1:-1]
+ index = m.end(0)
+ handled = True
+ elif m:
+ # Track bracket nesting and index in string
+ bracket_count = 1
+ backtrack_count = 1
+ start_index = m.end()
+ index = start_index
+ last_bracket = -1
+
+ # Primary (first found) quote tracking.
+ quote = None
+ start_quote = -1
+ exit_quote = -1
+ ignore_matches = False
+
+ # Secondary (second found) quote tracking.
+ alt_quote = None
+ start_alt_quote = -1
+ exit_alt_quote = -1
+
+ # Track last character
+ last = ''
+
+ for pos in range(index, len(data)):
+ c = data[pos]
+ if c == '(':
+ # Count nested (
+ # Don't increment the bracket count if we are sure we're in a title.
+ if not ignore_matches:
+ bracket_count += 1
+ elif backtrack_count > 0:
+ backtrack_count -= 1
+ elif c == ')':
+ # Match nested ) to (
+ # Don't decrement if we are sure we are in a title that is unclosed.
+ if ((exit_quote != -1 and quote == last) or (exit_alt_quote != -1 and alt_quote == last)):
+ bracket_count = 0
+ elif not ignore_matches:
+ bracket_count -= 1
+ elif backtrack_count > 0:
+ backtrack_count -= 1
+ # We've found our backup end location if the title doesn't resolve.
+ if backtrack_count == 0:
+ last_bracket = index + 1
+
+ elif c in ("'", '"'):
+ # Quote has started
+ if not quote:
+ # We'll assume we are now in a title.
+ # Brackets are quoted, so no need to match them (except for the final one).
+ ignore_matches = True
+ backtrack_count = bracket_count
+ bracket_count = 1
+ start_quote = index + 1
+ quote = c
+ # Secondary quote (in case the first doesn't resolve): [text](link'"title")
+ elif c != quote and not alt_quote:
+ start_alt_quote = index + 1
+ alt_quote = c
+ # Update primary quote match
+ elif c == quote:
+ exit_quote = index + 1
+ # Update secondary quote match
+ elif alt_quote and c == alt_quote:
+ exit_alt_quote = index + 1
+
+ index += 1
+
+ # Link is closed, so let's break out of the loop
+ if bracket_count == 0:
+ # Get the title if we closed a title string right before link closed
+ if exit_quote >= 0 and quote == last:
+ href = data[start_index:start_quote - 1]
+ title = ''.join(data[start_quote:exit_quote - 1])
+ elif exit_alt_quote >= 0 and alt_quote == last:
+ href = data[start_index:start_alt_quote - 1]
+ title = ''.join(data[start_alt_quote:exit_alt_quote - 1])
+ else:
+ href = data[start_index:index - 1]
+ break
+
+ if c != ' ':
+ last = c
+
+ # We have a scenario: [test](link"notitle)
+ # When we enter a string, we stop tracking bracket resolution in the main counter,
+ # but we do keep a backup counter up until we discover where we might resolve all brackets
+ # if the title string fails to resolve.
+ if bracket_count != 0 and backtrack_count == 0:
+ href = data[start_index:last_bracket - 1]
+ index = last_bracket
+ bracket_count = 0
+
+ handled = bracket_count == 0
+
+ if title is not None:
+ title = self.RE_TITLE_CLEAN.sub(' ', dequote(self.unescape(title.strip())))
+
+ href = self.unescape(href).strip()
+
+ return href, title, index, handled
+
+ def getText(self, data, index):
+ """Parse the content between `[]` of the start of an image or link
+ resolving nested square brackets.
+
+ """
+ bracket_count = 1
+ text = []
+ for pos in range(index, len(data)):
+ c = data[pos]
+ if c == ']':
+ bracket_count -= 1
+ elif c == '[':
+ bracket_count += 1
+ index += 1
+ if bracket_count == 0:
+ break
+ text.append(c)
+ return ''.join(text), index, bracket_count == 0
+
+
+class ImageInlineProcessor(LinkInlineProcessor):
""" Return a img element from the given match. """
- def handleMatch(self, m):
- el = markdown.etree.Element("img")
- src_parts = m.group(9).split()
- if src_parts:
- src = src_parts[0]
- if src[0] == "<" and src[-1] == ">":
- src = src[1:-1]
- el.set('src', self.sanitize_url(src))
- else:
- el.set('src', "")
- if len(src_parts) > 1:
- el.set('title', dequote(" ".join(src_parts[1:])))
- if markdown.ENABLE_ATTRIBUTES:
- truealt = handleAttributes(m.group(2), el)
- else:
- truealt = m.group(2)
+ def handleMatch(self, m, data):
+ text, index, handled = self.getText(data, m.end(0))
+ if not handled:
+ return None, None, None
- el.set('alt', truealt)
- return el
+ src, title, index, handled = self.getLink(data, index)
+ if not handled:
+ return None, None, None
-class ReferencePattern(LinkPattern):
+ el = etree.Element("img")
+
+ el.set("src", src)
+
+ if title is not None:
+ el.set("title", title)
+
+ el.set('alt', self.unescape(text))
+ return el, m.start(0), index
+
+
+class ReferenceInlineProcessor(LinkInlineProcessor):
""" Match to a stored reference and return link element. """
- def handleMatch(self, m):
- if m.group(9):
- id = m.group(9).lower()
- else:
- # if we got something like "[Google][]"
- # we'll use "google" as the id
- id = m.group(2).lower()
+ NEWLINE_CLEANUP_RE = re.compile(r'\s+', re.MULTILINE)
- if not id in self.markdown.references: # ignore undefined refs
- return None
- href, title = self.markdown.references[id]
+ RE_LINK = re.compile(r'\s?\[([^\]]*)\]', re.DOTALL | re.UNICODE)
- text = m.group(2)
- return self.makeTag(href, title, text)
+ def handleMatch(self, m, data):
+ text, index, handled = self.getText(data, m.end(0))
+ if not handled:
+ return None, None, None
+
+ id, end, handled = self.evalId(data, index, text)
+ if not handled:
+ return None, None, None
+
+ # Clean up linebreaks in id
+ id = self.NEWLINE_CLEANUP_RE.sub(' ', id)
+ if id not in self.md.references: # ignore undefined refs
+ return None, m.start(0), end
+
+ href, title = self.md.references[id]
+
+ return self.makeTag(href, title, text), m.start(0), end
+
+ def evalId(self, data, index, text):
+ """
+ Evaluate the id portion of [ref][id].
+
+ If [ref][] use [ref].
+ """
+ m = self.RE_LINK.match(data, pos=index)
+ if not m:
+ return None, index, False
+ else:
+ id = m.group(1).lower()
+ end = m.end(0)
+ if not id:
+ id = text.lower()
+ return id, end, True
def makeTag(self, href, title, text):
- el = markdown.etree.Element('a')
+ el = etree.Element('a')
- el.set('href', self.sanitize_url(href))
+ el.set('href', href)
if title:
el.set('title', title)
@@ -323,49 +822,65 @@ class ReferencePattern(LinkPattern):
return el
-class ImageReferencePattern (ReferencePattern):
+class ShortReferenceInlineProcessor(ReferenceInlineProcessor):
+ """Short form of reference: [google]. """
+ def evalId(self, data, index, text):
+ """Evaluate the id from of [ref] """
+
+ return text.lower(), index, True
+
+
+class ImageReferenceInlineProcessor(ReferenceInlineProcessor):
""" Match to a stored reference and return img element. """
def makeTag(self, href, title, text):
- el = markdown.etree.Element("img")
- el.set("src", self.sanitize_url(href))
+ el = etree.Element("img")
+ el.set("src", href)
if title:
el.set("title", title)
- el.set("alt", text)
+ el.set("alt", self.unescape(text))
return el
-class AutolinkPattern (Pattern):
+class ShortImageReferenceInlineProcessor(ImageReferenceInlineProcessor):
+ """ Short form of inage reference: ![ref]. """
+ def evalId(self, data, index, text):
+ """Evaluate the id from of [ref] """
+
+ return text.lower(), index, True
+
+
+class AutolinkInlineProcessor(InlineProcessor):
""" Return a link Element given an autolink (`<http://example/com>`). """
- def handleMatch(self, m):
- el = markdown.etree.Element("a")
- el.set('href', m.group(2))
- el.text = markdown.AtomicString(m.group(2))
- return el
+ def handleMatch(self, m, data):
+ el = etree.Element("a")
+ el.set('href', self.unescape(m.group(1)))
+ el.text = util.AtomicString(m.group(1))
+ return el, m.start(0), m.end(0)
+
-class AutomailPattern (Pattern):
+class AutomailInlineProcessor(InlineProcessor):
"""
Return a mailto link Element given an automail link (`<foo@example.com>`).
"""
- def handleMatch(self, m):
- el = markdown.etree.Element('a')
- email = m.group(2)
+ def handleMatch(self, m, data):
+ el = etree.Element('a')
+ email = self.unescape(m.group(1))
if email.startswith("mailto:"):
email = email[len("mailto:"):]
def codepoint2name(code):
"""Return entity definition by code, or the code if not defined."""
- entity = htmlentitydefs.codepoint2name.get(code)
+ entity = entities.codepoint2name.get(code)
if entity:
- return "%s%s;" % (markdown.AMP_SUBSTITUTE, entity)
+ return "{}{};".format(util.AMP_SUBSTITUTE, entity)
else:
- return "%s#%d;" % (markdown.AMP_SUBSTITUTE, code)
+ return "%s#%d;" % (util.AMP_SUBSTITUTE, code)
letters = [codepoint2name(ord(letter)) for letter in email]
- el.text = markdown.AtomicString(''.join(letters))
+ el.text = util.AtomicString(''.join(letters))
mailto = "mailto:" + email
- mailto = "".join([markdown.AMP_SUBSTITUTE + '#%d;' %
+ mailto = "".join([util.AMP_SUBSTITUTE + '#%d;' %
ord(letter) for letter in mailto])
el.set('href', mailto)
- return el
-
+ return el, m.start(0), m.end(0)
diff --git a/markdown/odict.py b/markdown/odict.py
deleted file mode 100644
index bf3ef07..0000000
--- a/markdown/odict.py
+++ /dev/null
@@ -1,162 +0,0 @@
-class OrderedDict(dict):
- """
- A dictionary that keeps its keys in the order in which they're inserted.
-
- Copied from Django's SortedDict with some modifications.
-
- """
- def __new__(cls, *args, **kwargs):
- instance = super(OrderedDict, cls).__new__(cls, *args, **kwargs)
- instance.keyOrder = []
- return instance
-
- def __init__(self, data=None):
- if data is None:
- data = {}
- super(OrderedDict, self).__init__(data)
- if isinstance(data, dict):
- self.keyOrder = data.keys()
- else:
- self.keyOrder = []
- for key, value in data:
- if key not in self.keyOrder:
- self.keyOrder.append(key)
-
- def __deepcopy__(self, memo):
- from copy import deepcopy
- return self.__class__([(key, deepcopy(value, memo))
- for key, value in self.iteritems()])
-
- def __setitem__(self, key, value):
- super(OrderedDict, self).__setitem__(key, value)
- if key not in self.keyOrder:
- self.keyOrder.append(key)
-
- def __delitem__(self, key):
- super(OrderedDict, self).__delitem__(key)
- self.keyOrder.remove(key)
-
- def __iter__(self):
- for k in self.keyOrder:
- yield k
-
- def pop(self, k, *args):
- result = super(OrderedDict, self).pop(k, *args)
- try:
- self.keyOrder.remove(k)
- except ValueError:
- # Key wasn't in the dictionary in the first place. No problem.
- pass
- return result
-
- def popitem(self):
- result = super(OrderedDict, self).popitem()
- self.keyOrder.remove(result[0])
- return result
-
- def items(self):
- return zip(self.keyOrder, self.values())
-
- def iteritems(self):
- for key in self.keyOrder:
- yield key, super(OrderedDict, self).__getitem__(key)
-
- def keys(self):
- return self.keyOrder[:]
-
- def iterkeys(self):
- return iter(self.keyOrder)
-
- def values(self):
- return [super(OrderedDict, self).__getitem__(k) for k in self.keyOrder]
-
- def itervalues(self):
- for key in self.keyOrder:
- yield super(OrderedDict, self).__getitem__(key)
-
- def update(self, dict_):
- for k, v in dict_.items():
- self.__setitem__(k, v)
-
- def setdefault(self, key, default):
- if key not in self.keyOrder:
- self.keyOrder.append(key)
- return super(OrderedDict, self).setdefault(key, default)
-
- def value_for_index(self, index):
- """Return the value of the item at the given zero-based index."""
- return self[self.keyOrder[index]]
-
- def insert(self, index, key, value):
- """Insert the key, value pair before the item with the given index."""
- if key in self.keyOrder:
- n = self.keyOrder.index(key)
- del self.keyOrder[n]
- if n < index:
- index -= 1
- self.keyOrder.insert(index, key)
- super(OrderedDict, self).__setitem__(key, value)
-
- def copy(self):
- """Return a copy of this object."""
- # This way of initializing the copy means it works for subclasses, too.
- obj = self.__class__(self)
- obj.keyOrder = self.keyOrder[:]
- return obj
-
- def __repr__(self):
- """
- Replace the normal dict.__repr__ with a version that returns the keys
- in their sorted order.
- """
- return '{%s}' % ', '.join(['%r: %r' % (k, v) for k, v in self.items()])
-
- def clear(self):
- super(OrderedDict, self).clear()
- self.keyOrder = []
-
- def index(self, key):
- """ Return the index of a given key. """
- return self.keyOrder.index(key)
-
- def index_for_location(self, location):
- """ Return index or None for a given location. """
- if location == '_begin':
- i = 0
- elif location == '_end':
- i = None
- elif location.startswith('<') or location.startswith('>'):
- i = self.index(location[1:])
- if location.startswith('>'):
- if i >= len(self):
- # last item
- i = None
- else:
- i += 1
- else:
- raise ValueError('Not a valid location: "%s". Location key '
- 'must start with a ">" or "<".' % location)
- return i
-
- def add(self, key, value, location):
- """ Insert by key location. """
- i = self.index_for_location(location)
- if i is not None:
- self.insert(i, key, value)
- else:
- self.__setitem__(key, value)
-
- def link(self, key, location):
- """ Change location of an existing item. """
- n = self.keyOrder.index(key)
- del self.keyOrder[n]
- i = self.index_for_location(location)
- try:
- if i is not None:
- self.keyOrder.insert(i, key)
- else:
- self.keyOrder.append(key)
- except Error:
- # restore to prevent data loss and reraise
- self.keyOrder.insert(n, key)
- raise Error
diff --git a/markdown/postprocessors.py b/markdown/postprocessors.py
index 80227bb..498f7e8 100644
--- a/markdown/postprocessors.py
+++ b/markdown/postprocessors.py
@@ -1,4 +1,23 @@
"""
+Python Markdown
+
+A Python implementation of John Gruber's Markdown.
+
+Documentation: https://python-markdown.github.io/
+GitHub: https://github.com/Python-Markdown/markdown/
+PyPI: https://pypi.org/project/Markdown/
+
+Started by Manfred Stienstra (http://www.dwerg.net/).
+Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
+Currently maintained by Waylan Limberg (https://github.com/waylan),
+Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
+
+Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see LICENSE.md for details).
+
POST-PROCESSORS
=============================================================================
@@ -8,15 +27,20 @@ processing.
"""
+from collections import OrderedDict
+from . import util
+import re
+
-import markdown
+def build_postprocessors(md, **kwargs):
+ """ Build the default postprocessors for Markdown. """
+ postprocessors = util.Registry()
+ postprocessors.register(RawHtmlPostprocessor(md), 'raw_html', 30)
+ postprocessors.register(AndSubstitutePostprocessor(), 'amp_substitute', 20)
+ return postprocessors
-class Processor:
- def __init__(self, markdown_instance=None):
- if markdown_instance:
- self.markdown = markdown_instance
-class Postprocessor(Processor):
+class Postprocessor(util.Processor):
"""
Postprocessors are run after the ElementTree it converted back into text.
@@ -34,44 +58,80 @@ class Postprocessor(Processor):
(possibly modified) string.
"""
- pass
+ pass # pragma: no cover
class RawHtmlPostprocessor(Postprocessor):
""" Restore raw html to the document. """
+ BLOCK_LEVEL_REGEX = re.compile(r'^\<\/?([^ >]+)')
+
def run(self, text):
- """ Iterate over html stash and restore "safe" html. """
- for i in range(self.markdown.htmlStash.html_counter):
- html, safe = self.markdown.htmlStash.rawHtmlBlocks[i]
- if self.markdown.safeMode and not safe:
- if str(self.markdown.safeMode).lower() == 'escape':
- html = self.escape(html)
- elif str(self.markdown.safeMode).lower() == 'remove':
- html = ''
+ """ Iterate over html stash and restore html. """
+ replacements = OrderedDict()
+ for i in range(self.md.htmlStash.html_counter):
+ html = self.stash_to_string(self.md.htmlStash.rawHtmlBlocks[i])
+ if self.isblocklevel(html):
+ replacements["<p>{}</p>".format(
+ self.md.htmlStash.get_placeholder(i))] = html
+ replacements[self.md.htmlStash.get_placeholder(i)] = html
+
+ def substitute_match(m):
+ key = m.group(0)
+
+ if key not in replacements:
+ if key[3:-4] in replacements:
+ return f'<p>{ replacements[key[3:-4]] }</p>'
else:
- html = markdown.HTML_REMOVED_TEXT
- if safe or not self.markdown.safeMode:
- text = text.replace("<p>%s</p>" %
- (markdown.preprocessors.HTML_PLACEHOLDER % i),
- html + "\n")
- text = text.replace(markdown.preprocessors.HTML_PLACEHOLDER % i,
- html)
- return text
+ return key
+
+ return replacements[key]
- def escape(self, html):
- """ Basic html escaping """
- html = html.replace('&', '&amp;')
- html = html.replace('<', '&lt;')
- html = html.replace('>', '&gt;')
- return html.replace('"', '&quot;')
+ if replacements:
+ base_placeholder = util.HTML_PLACEHOLDER % r'([0-9]+)'
+ pattern = re.compile(f'<p>{ base_placeholder }</p>|{ base_placeholder }')
+ processed_text = pattern.sub(substitute_match, text)
+ else:
+ return text
+
+ if processed_text == text:
+ return processed_text
+ else:
+ return self.run(processed_text)
+
+ def isblocklevel(self, html):
+ m = self.BLOCK_LEVEL_REGEX.match(html)
+ if m:
+ if m.group(1)[0] in ('!', '?', '@', '%'):
+ # Comment, php etc...
+ return True
+ return self.md.is_block_level(m.group(1))
+ return False
+
+ def stash_to_string(self, text):
+ """ Convert a stashed object to a string. """
+ return str(text)
class AndSubstitutePostprocessor(Postprocessor):
""" Restore valid entities """
- def __init__(self):
- pass
def run(self, text):
- text = text.replace(markdown.AMP_SUBSTITUTE, "&")
+ text = text.replace(util.AMP_SUBSTITUTE, "&")
return text
+
+
+@util.deprecated(
+ "This class will be removed in the future; "
+ "use 'treeprocessors.UnescapeTreeprocessor' instead."
+)
+class UnescapePostprocessor(Postprocessor):
+ """ Restore escaped chars """
+
+ RE = re.compile(r'{}(\d+){}'.format(util.STX, util.ETX))
+
+ def unescape(self, m):
+ return chr(int(m.group(1)))
+
+ def run(self, text):
+ return self.RE.sub(self.unescape, text)
diff --git a/markdown/preprocessors.py b/markdown/preprocessors.py
index ef04cab..e1023c5 100644
--- a/markdown/preprocessors.py
+++ b/markdown/preprocessors.py
@@ -1,24 +1,44 @@
-
"""
+Python Markdown
+
+A Python implementation of John Gruber's Markdown.
+
+Documentation: https://python-markdown.github.io/
+GitHub: https://github.com/Python-Markdown/markdown/
+PyPI: https://pypi.org/project/Markdown/
+
+Started by Manfred Stienstra (http://www.dwerg.net/).
+Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
+Currently maintained by Waylan Limberg (https://github.com/waylan),
+Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
+
+Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see LICENSE.md for details).
+
PRE-PROCESSORS
=============================================================================
Preprocessors work on source text before we start doing anything too
-complicated.
+complicated.
"""
+from . import util
+from .htmlparser import HTMLExtractor
import re
-import markdown
-HTML_PLACEHOLDER_PREFIX = markdown.STX+"wzxhzdk:"
-HTML_PLACEHOLDER = HTML_PLACEHOLDER_PREFIX + "%d" + markdown.ETX
-class Processor:
- def __init__(self, markdown_instance=None):
- if markdown_instance:
- self.markdown = markdown_instance
+def build_preprocessors(md, **kwargs):
+ """ Build the default set of preprocessors used by Markdown. """
+ preprocessors = util.Registry()
+ preprocessors.register(NormalizeWhitespace(md), 'normalize_whitespace', 30)
+ preprocessors.register(HtmlBlockPreprocessor(md), 'html_block', 20)
+ return preprocessors
+
-class Preprocessor (Processor):
+class Preprocessor(util.Processor):
"""
Preprocessors are run after the text is broken into lines.
@@ -36,180 +56,27 @@ class Preprocessor (Processor):
the (possibly modified) list of lines.
"""
- pass
+ pass # pragma: no cover
-class HtmlStash:
- """
- This class is used for stashing HTML objects that we extract
- in the beginning and replace with place-holders.
- """
- def __init__ (self):
- """ Create a HtmlStash. """
- self.html_counter = 0 # for counting inline html segments
- self.rawHtmlBlocks=[]
+class NormalizeWhitespace(Preprocessor):
+ """ Normalize whitespace for consistent parsing. """
- def store(self, html, safe=False):
- """
- Saves an HTML segment for later reinsertion. Returns a
- placeholder string that needs to be inserted into the
- document.
-
- Keyword arguments:
-
- * html: an html segment
- * safe: label an html segment as safe for safemode
-
- Returns : a placeholder string
-
- """
- self.rawHtmlBlocks.append((html, safe))
- placeholder = HTML_PLACEHOLDER % self.html_counter
- self.html_counter += 1
- return placeholder
-
- def reset(self):
- self.html_counter = 0
- self.rawHtmlBlocks = []
+ def run(self, lines):
+ source = '\n'.join(lines)
+ source = source.replace(util.STX, "").replace(util.ETX, "")
+ source = source.replace("\r\n", "\n").replace("\r", "\n") + "\n\n"
+ source = source.expandtabs(self.md.tab_length)
+ source = re.sub(r'(?<=\n) +\n', '\n', source)
+ return source.split('\n')
class HtmlBlockPreprocessor(Preprocessor):
"""Remove html blocks from the text and store them for later retrieval."""
- right_tag_patterns = ["</%s>", "%s>"]
-
- def _get_left_tag(self, block):
- return block[1:].replace(">", " ", 1).split()[0].lower()
-
- def _get_right_tag(self, left_tag, block):
- for p in self.right_tag_patterns:
- tag = p % left_tag
- i = block.rfind(tag)
- if i > 2:
- return tag.lstrip("<").rstrip(">"), i + len(p)-2 + len(left_tag)
- return block.rstrip()[-len(left_tag)-2:-1].lower(), len(block)
-
- def _equal_tags(self, left_tag, right_tag):
- if left_tag == 'div' or left_tag[0] in ['?', '@', '%']: # handle PHP, etc.
- return True
- if ("/" + left_tag) == right_tag:
- return True
- if (right_tag == "--" and left_tag == "--"):
- return True
- elif left_tag == right_tag[1:] \
- and right_tag[0] != "<":
- return True
- else:
- return False
-
- def _is_oneliner(self, tag):
- return (tag in ['hr', 'hr/'])
-
def run(self, lines):
- text = "\n".join(lines)
- new_blocks = []
- text = text.split("\n\n")
- items = []
- left_tag = ''
- right_tag = ''
- in_tag = False # flag
-
- while text:
- block = text[0]
- if block.startswith("\n"):
- block = block[1:]
- text = text[1:]
-
- if block.startswith("\n"):
- block = block[1:]
-
- if not in_tag:
- if block.startswith("<"):
- left_tag = self._get_left_tag(block)
- right_tag, data_index = self._get_right_tag(left_tag, block)
-
- if block[1] == "!":
- # is a comment block
- left_tag = "--"
- right_tag, data_index = self._get_right_tag(left_tag, block)
- # keep checking conditions below and maybe just append
-
- if data_index < len(block) \
- and markdown.isBlockLevel(left_tag):
- text.insert(0, block[data_index:])
- block = block[:data_index]
-
- if not (markdown.isBlockLevel(left_tag) \
- or block[1] in ["!", "?", "@", "%"]):
- new_blocks.append(block)
- continue
-
- if self._is_oneliner(left_tag):
- new_blocks.append(block.strip())
- continue
-
- if block.rstrip().endswith(">") \
- and self._equal_tags(left_tag, right_tag):
- new_blocks.append(
- self.markdown.htmlStash.store(block.strip()))
- continue
- else: #if not block[1] == "!":
- # if is block level tag and is not complete
-
- if markdown.isBlockLevel(left_tag) or left_tag == "--" \
- and not block.rstrip().endswith(">"):
- items.append(block.strip())
- in_tag = True
- else:
- new_blocks.append(
- self.markdown.htmlStash.store(block.strip()))
-
- continue
-
- new_blocks.append(block)
-
- else:
- items.append(block.strip())
-
- right_tag, data_index = self._get_right_tag(left_tag, block)
-
- if self._equal_tags(left_tag, right_tag):
- # if find closing tag
- in_tag = False
- new_blocks.append(
- self.markdown.htmlStash.store('\n\n'.join(items)))
- items = []
-
- if items:
- new_blocks.append(self.markdown.htmlStash.store('\n\n'.join(items)))
- new_blocks.append('\n')
-
- new_text = "\n\n".join(new_blocks)
- return new_text.split("\n")
-
-
-class ReferencePreprocessor(Preprocessor):
- """ Remove reference definitions from text and store for later use. """
-
- RE = re.compile(r'^(\ ?\ ?\ ?)\[([^\]]*)\]:\s*([^ ]*)(.*)$', re.DOTALL)
-
- def run (self, lines):
- new_text = [];
- for line in lines:
- m = self.RE.match(line)
- if m:
- id = m.group(2).strip().lower()
- t = m.group(4).strip() # potential title
- if not t:
- self.markdown.references[id] = (m.group(3), t)
- elif (len(t) >= 2
- and (t[0] == t[-1] == "\""
- or t[0] == t[-1] == "\'"
- or (t[0] == "(" and t[-1] == ")") ) ):
- self.markdown.references[id] = (m.group(3), t[1:-1])
- else:
- new_text.append(line)
- else:
- new_text.append(line)
-
- return new_text #+ "\n"
+ source = '\n'.join(lines)
+ parser = HTMLExtractor(self.md)
+ parser.feed(source)
+ parser.close()
+ return ''.join(parser.cleandoc).split('\n')
diff --git a/markdown/serializers.py b/markdown/serializers.py
new file mode 100644
index 0000000..59bab18
--- /dev/null
+++ b/markdown/serializers.py
@@ -0,0 +1,189 @@
+# markdown/searializers.py
+#
+# Add x/html serialization to Elementree
+# Taken from ElementTree 1.3 preview with slight modifications
+#
+# Copyright (c) 1999-2007 by Fredrik Lundh. All rights reserved.
+#
+# fredrik@pythonware.com
+# https://www.pythonware.com/
+#
+# --------------------------------------------------------------------
+# The ElementTree toolkit is
+#
+# Copyright (c) 1999-2007 by Fredrik Lundh
+#
+# By obtaining, using, and/or copying this software and/or its
+# associated documentation, you agree that you have read, understood,
+# and will comply with the following terms and conditions:
+#
+# Permission to use, copy, modify, and distribute this software and
+# its associated documentation for any purpose and without fee is
+# hereby granted, provided that the above copyright notice appears in
+# all copies, and that both that copyright notice and this permission
+# notice appear in supporting documentation, and that the name of
+# Secret Labs AB or the author not be used in advertising or publicity
+# pertaining to distribution of the software without specific, written
+# prior permission.
+#
+# SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+# TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT-
+# ABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR
+# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+# --------------------------------------------------------------------
+
+
+from xml.etree.ElementTree import ProcessingInstruction
+from xml.etree.ElementTree import Comment, ElementTree, QName
+import re
+
+__all__ = ['to_html_string', 'to_xhtml_string']
+
+HTML_EMPTY = ("area", "base", "basefont", "br", "col", "frame", "hr",
+ "img", "input", "isindex", "link", "meta", "param")
+RE_AMP = re.compile(r'&(?!(?:\#[0-9]+|\#x[0-9a-f]+|[0-9a-z]+);)', re.I)
+
+try:
+ HTML_EMPTY = set(HTML_EMPTY)
+except NameError: # pragma: no cover
+ pass
+
+
+def _raise_serialization_error(text): # pragma: no cover
+ raise TypeError(
+ "cannot serialize {!r} (type {})".format(text, type(text).__name__)
+ )
+
+
+def _escape_cdata(text):
+ # escape character data
+ try:
+ # it's worth avoiding do-nothing calls for strings that are
+ # shorter than 500 character, or so. assume that's, by far,
+ # the most common case in most applications.
+ if "&" in text:
+ # Only replace & when not part of an entity
+ text = RE_AMP.sub('&amp;', text)
+ if "<" in text:
+ text = text.replace("<", "&lt;")
+ if ">" in text:
+ text = text.replace(">", "&gt;")
+ return text
+ except (TypeError, AttributeError): # pragma: no cover
+ _raise_serialization_error(text)
+
+
+def _escape_attrib(text):
+ # escape attribute value
+ try:
+ if "&" in text:
+ # Only replace & when not part of an entity
+ text = RE_AMP.sub('&amp;', text)
+ if "<" in text:
+ text = text.replace("<", "&lt;")
+ if ">" in text:
+ text = text.replace(">", "&gt;")
+ if "\"" in text:
+ text = text.replace("\"", "&quot;")
+ if "\n" in text:
+ text = text.replace("\n", "&#10;")
+ return text
+ except (TypeError, AttributeError): # pragma: no cover
+ _raise_serialization_error(text)
+
+
+def _escape_attrib_html(text):
+ # escape attribute value
+ try:
+ if "&" in text:
+ # Only replace & when not part of an entity
+ text = RE_AMP.sub('&amp;', text)
+ if "<" in text:
+ text = text.replace("<", "&lt;")
+ if ">" in text:
+ text = text.replace(">", "&gt;")
+ if "\"" in text:
+ text = text.replace("\"", "&quot;")
+ return text
+ except (TypeError, AttributeError): # pragma: no cover
+ _raise_serialization_error(text)
+
+
+def _serialize_html(write, elem, format):
+ tag = elem.tag
+ text = elem.text
+ if tag is Comment:
+ write("<!--%s-->" % _escape_cdata(text))
+ elif tag is ProcessingInstruction:
+ write("<?%s?>" % _escape_cdata(text))
+ elif tag is None:
+ if text:
+ write(_escape_cdata(text))
+ for e in elem:
+ _serialize_html(write, e, format)
+ else:
+ namespace_uri = None
+ if isinstance(tag, QName):
+ # QNAME objects store their data as a string: `{uri}tag`
+ if tag.text[:1] == "{":
+ namespace_uri, tag = tag.text[1:].split("}", 1)
+ else:
+ raise ValueError('QName objects must define a tag.')
+ write("<" + tag)
+ items = elem.items()
+ if items:
+ items = sorted(items) # lexical order
+ for k, v in items:
+ if isinstance(k, QName):
+ # Assume a text only QName
+ k = k.text
+ if isinstance(v, QName):
+ # Assume a text only QName
+ v = v.text
+ else:
+ v = _escape_attrib_html(v)
+ if k == v and format == 'html':
+ # handle boolean attributes
+ write(" %s" % v)
+ else:
+ write(' {}="{}"'.format(k, v))
+ if namespace_uri:
+ write(' xmlns="%s"' % (_escape_attrib(namespace_uri)))
+ if format == "xhtml" and tag.lower() in HTML_EMPTY:
+ write(" />")
+ else:
+ write(">")
+ if text:
+ if tag.lower() in ["script", "style"]:
+ write(text)
+ else:
+ write(_escape_cdata(text))
+ for e in elem:
+ _serialize_html(write, e, format)
+ if tag.lower() not in HTML_EMPTY:
+ write("</" + tag + ">")
+ if elem.tail:
+ write(_escape_cdata(elem.tail))
+
+
+def _write_html(root, format="html"):
+ assert root is not None
+ data = []
+ write = data.append
+ _serialize_html(write, root, format)
+ return "".join(data)
+
+
+# --------------------------------------------------------------------
+# public functions
+
+def to_html_string(element):
+ return _write_html(ElementTree(element).getroot(), format="html")
+
+
+def to_xhtml_string(element):
+ return _write_html(ElementTree(element).getroot(), format="xhtml")
diff --git a/markdown/test_tools.py b/markdown/test_tools.py
new file mode 100644
index 0000000..2ce0e74
--- /dev/null
+++ b/markdown/test_tools.py
@@ -0,0 +1,220 @@
+"""
+Python Markdown
+
+A Python implementation of John Gruber's Markdown.
+
+Documentation: https://python-markdown.github.io/
+GitHub: https://github.com/Python-Markdown/markdown/
+PyPI: https://pypi.org/project/Markdown/
+
+Started by Manfred Stienstra (http://www.dwerg.net/).
+Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
+Currently maintained by Waylan Limberg (https://github.com/waylan),
+Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
+
+Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see LICENSE.md for details).
+"""
+
+import os
+import sys
+import unittest
+import textwrap
+from . import markdown, Markdown, util
+
+try:
+ import tidylib
+except ImportError:
+ tidylib = None
+
+__all__ = ['TestCase', 'LegacyTestCase', 'Kwargs']
+
+
+class TestCase(unittest.TestCase):
+ """
+ A unittest.TestCase subclass with helpers for testing Markdown output.
+
+ Define `default_kwargs` as a dict of keywords to pass to Markdown for each
+ test. The defaults can be overridden on individual tests.
+
+ The `assertMarkdownRenders` method accepts the source text, the expected
+ output, and any keywords to pass to Markdown. The `default_kwargs` are used
+ except where overridden by `kwargs`. The output and expected output are passed
+ to `TestCase.assertMultiLineEqual`. An AssertionError is raised with a diff
+ if the actual output does not equal the expected output.
+
+ The `dedent` method is available to dedent triple-quoted strings if
+ necessary.
+
+ In all other respects, behaves as unittest.TestCase.
+ """
+
+ default_kwargs = {}
+
+ def assertMarkdownRenders(self, source, expected, expected_attrs=None, **kwargs):
+ """
+ Test that source Markdown text renders to expected output with given keywords.
+
+ `expected_attrs` accepts a dict. Each key should be the name of an attribute
+ on the `Markdown` instance and the value should be the expected value after
+ the source text is parsed by Markdown. After the expected output is tested,
+ the expected value for each attribute is compared against the actual
+ attribute of the `Markdown` instance using `TestCase.assertEqual`.
+ """
+
+ expected_attrs = expected_attrs or {}
+ kws = self.default_kwargs.copy()
+ kws.update(kwargs)
+ md = Markdown(**kws)
+ output = md.convert(source)
+ self.assertMultiLineEqual(output, expected)
+ for key, value in expected_attrs.items():
+ self.assertEqual(getattr(md, key), value)
+
+ def dedent(self, text):
+ """
+ Dedent text.
+ """
+
+ # TODO: If/when actual output ends with a newline, then use:
+ # return textwrap.dedent(text.strip('/n'))
+ return textwrap.dedent(text).strip()
+
+
+class recursionlimit:
+ """
+ A context manager which temporarily modifies the Python recursion limit.
+
+ The testing framework, coverage, etc. may add an arbitrary number of levels to the depth. To maintain consistency
+ in the tests, the current stack depth is determined when called, then added to the provided limit.
+
+ Example usage:
+
+ with recursionlimit(20):
+ # test code here
+
+ See https://stackoverflow.com/a/50120316/866026
+ """
+
+ def __init__(self, limit):
+ self.limit = util._get_stack_depth() + limit
+ self.old_limit = sys.getrecursionlimit()
+
+ def __enter__(self):
+ sys.setrecursionlimit(self.limit)
+
+ def __exit__(self, type, value, tb):
+ sys.setrecursionlimit(self.old_limit)
+
+
+#########################
+# Legacy Test Framework #
+#########################
+
+
+class Kwargs(dict):
+ """ A dict like class for holding keyword arguments. """
+ pass
+
+
+def _normalize_whitespace(text):
+ """ Normalize whitespace for a string of html using tidylib. """
+ output, errors = tidylib.tidy_fragment(text, options={
+ 'drop_empty_paras': 0,
+ 'fix_backslash': 0,
+ 'fix_bad_comments': 0,
+ 'fix_uri': 0,
+ 'join_styles': 0,
+ 'lower_literals': 0,
+ 'merge_divs': 0,
+ 'output_xhtml': 1,
+ 'quote_ampersand': 0,
+ 'newline': 'LF'
+ })
+ return output
+
+
+class LegacyTestMeta(type):
+ def __new__(cls, name, bases, dct):
+
+ def generate_test(infile, outfile, normalize, kwargs):
+ def test(self):
+ with open(infile, encoding="utf-8") as f:
+ input = f.read()
+ with open(outfile, encoding="utf-8") as f:
+ # Normalize line endings
+ # (on Windows, git may have altered line endings).
+ expected = f.read().replace("\r\n", "\n")
+ output = markdown(input, **kwargs)
+ if tidylib and normalize:
+ try:
+ expected = _normalize_whitespace(expected)
+ output = _normalize_whitespace(output)
+ except OSError:
+ self.skipTest("Tidylib's c library not available.")
+ elif normalize:
+ self.skipTest('Tidylib not available.')
+ self.assertMultiLineEqual(output, expected)
+ return test
+
+ location = dct.get('location', '')
+ exclude = dct.get('exclude', [])
+ normalize = dct.get('normalize', False)
+ input_ext = dct.get('input_ext', '.txt')
+ output_ext = dct.get('output_ext', '.html')
+ kwargs = dct.get('default_kwargs', Kwargs())
+
+ if os.path.isdir(location):
+ for file in os.listdir(location):
+ infile = os.path.join(location, file)
+ if os.path.isfile(infile):
+ tname, ext = os.path.splitext(file)
+ if ext == input_ext:
+ outfile = os.path.join(location, tname + output_ext)
+ tname = tname.replace(' ', '_').replace('-', '_')
+ kws = kwargs.copy()
+ if tname in dct:
+ kws.update(dct[tname])
+ test_name = 'test_%s' % tname
+ if tname not in exclude:
+ dct[test_name] = generate_test(infile, outfile, normalize, kws)
+ else:
+ dct[test_name] = unittest.skip('Excluded')(lambda: None)
+
+ return type.__new__(cls, name, bases, dct)
+
+
+class LegacyTestCase(unittest.TestCase, metaclass=LegacyTestMeta):
+ """
+ A `unittest.TestCase` subclass for running Markdown's legacy file-based tests.
+
+ A subclass should define various properties which point to a directory of
+ text-based test files and define various behaviors/defaults for those tests.
+ The following properties are supported:
+
+ location: A path to the directory of test files. An absolute path is preferred.
+ exclude: A list of tests to exclude. Each test name should comprise the filename
+ without an extension.
+ normalize: A boolean value indicating if the HTML should be normalized.
+ Default: `False`.
+ input_ext: A string containing the file extension of input files. Default: `.txt`.
+ ouput_ext: A string containing the file extension of expected output files.
+ Default: `html`.
+ default_kwargs: A `Kwargs` instance which stores the default set of keyword
+ arguments for all test files in the directory.
+
+ In addition, properties can be defined for each individual set of test files within
+ the directory. The property should be given the name of the file without the file
+ extension. Any spaces and dashes in the filename should be replaced with
+ underscores. The value of the property should be a `Kwargs` instance which
+ contains the keyword arguments that should be passed to `Markdown` for that
+ test file. The keyword arguments will "update" the `default_kwargs`.
+
+ When the class instance is created, it will walk the given directory and create
+ a separate unitttest for each set of test files using the naming scheme:
+ `test_filename`. One unittest will be run for each set of input and output files.
+ """
+ pass
diff --git a/markdown/treeprocessors.py b/markdown/treeprocessors.py
index 1dc612a..e9f48ca 100644
--- a/markdown/treeprocessors.py
+++ b/markdown/treeprocessors.py
@@ -1,16 +1,47 @@
-import markdown
+"""
+Python Markdown
+
+A Python implementation of John Gruber's Markdown.
+
+Documentation: https://python-markdown.github.io/
+GitHub: https://github.com/Python-Markdown/markdown/
+PyPI: https://pypi.org/project/Markdown/
+
+Started by Manfred Stienstra (http://www.dwerg.net/).
+Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
+Currently maintained by Waylan Limberg (https://github.com/waylan),
+Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
+
+Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see LICENSE.md for details).
+"""
+
import re
+import xml.etree.ElementTree as etree
+from . import util
+from . import inlinepatterns
+
+
+def build_treeprocessors(md, **kwargs):
+ """ Build the default treeprocessors for Markdown. """
+ treeprocessors = util.Registry()
+ treeprocessors.register(InlineProcessor(md), 'inline', 20)
+ treeprocessors.register(PrettifyTreeprocessor(md), 'prettify', 10)
+ treeprocessors.register(UnescapeTreeprocessor(md), 'unescape', 0)
+ return treeprocessors
+
def isString(s):
""" Check if it's string """
- return isinstance(s, unicode) or isinstance(s, str)
+ if not isinstance(s, util.AtomicString):
+ return isinstance(s, str)
+ return False
-class Processor:
- def __init__(self, markdown_instance=None):
- if markdown_instance:
- self.markdown = markdown_instance
-class Treeprocessor(Processor):
+class Treeprocessor(util.Processor):
"""
Treeprocessors are run on the ElementTree object before serialization.
@@ -24,11 +55,11 @@ class Treeprocessor(Processor):
def run(self, root):
"""
Subclasses of Treeprocessor should implement a `run` method, which
- takes a root ElementTree. This method can return another ElementTree
- object, and the existing root ElementTree will be replaced, or it can
+ takes a root ElementTree. This method can return another ElementTree
+ object, and the existing root ElementTree will be replaced, or it can
modify the current tree and return None.
"""
- pass
+ pass # pragma: no cover
class InlineProcessor(Treeprocessor):
@@ -36,18 +67,20 @@ class InlineProcessor(Treeprocessor):
A Treeprocessor that traverses a tree, applying inline patterns.
"""
- def __init__ (self, md):
- self.__placeholder_prefix = markdown.INLINE_PLACEHOLDER_PREFIX
- self.__placeholder_suffix = markdown.ETX
+ def __init__(self, md):
+ self.__placeholder_prefix = util.INLINE_PLACEHOLDER_PREFIX
+ self.__placeholder_suffix = util.ETX
self.__placeholder_length = 4 + len(self.__placeholder_prefix) \
+ len(self.__placeholder_suffix)
- self.__placeholder_re = re.compile(markdown.INLINE_PLACEHOLDER % r'([0-9]{4})')
- self.markdown = md
+ self.__placeholder_re = util.INLINE_PLACEHOLDER_RE
+ self.md = md
+ self.inlinePatterns = md.inlinePatterns
+ self.ancestors = []
def __makePlaceholder(self, type):
""" Generate a placeholder """
id = "%04d" % len(self.stashed_nodes)
- hash = markdown.INLINE_PLACEHOLDER % id
+ hash = util.INLINE_PLACEHOLDER % id
return hash, id
def __findPlaceholder(self, data, index):
@@ -60,8 +93,8 @@ class InlineProcessor(Treeprocessor):
* index: index, from which we start search
Returns: placeholder id and string index, after the found placeholder.
- """
+ """
m = self.__placeholder_re.search(data, index)
if m:
return m.group(1), m.end()
@@ -87,12 +120,13 @@ class InlineProcessor(Treeprocessor):
Returns: String with placeholders.
"""
- if not isinstance(data, markdown.AtomicString):
+ if not isinstance(data, util.AtomicString):
startIndex = 0
- while patternIndex < len(self.markdown.inlinePatterns):
+ count = len(self.inlinePatterns)
+ while patternIndex < count:
data, matched, startIndex = self.__applyPattern(
- self.markdown.inlinePatterns.value_for_index(patternIndex),
- data, patternIndex, startIndex)
+ self.inlinePatterns[patternIndex], data, patternIndex, startIndex
+ )
if not matched:
patternIndex += 1
return data
@@ -118,19 +152,18 @@ class InlineProcessor(Treeprocessor):
text = subnode.tail
subnode.tail = None
- childResult = self.__processPlaceholders(text, subnode)
+ childResult = self.__processPlaceholders(text, subnode, isText)
if not isText and node is not subnode:
- pos = node.getchildren().index(subnode)
- node.remove(subnode)
+ pos = list(node).index(subnode) + 1
else:
pos = 0
childResult.reverse()
for newChild in childResult:
- node.insert(pos, newChild)
+ node.insert(pos, newChild[0])
- def __processPlaceholders(self, data, parent):
+ def __processPlaceholders(self, data, parent, isText=True):
"""
Process string with placeholders and generate ElementTree tree.
@@ -140,20 +173,25 @@ class InlineProcessor(Treeprocessor):
* parent: Element, which contains processing inline data
Returns: list with ElementTree elements with applied inline patterns.
+
"""
def linkText(text):
if text:
if result:
- if result[-1].tail:
- result[-1].tail += text
+ if result[-1][0].tail:
+ result[-1][0].tail += text
+ else:
+ result[-1][0].tail = text
+ elif not isText:
+ if parent.tail:
+ parent.tail += text
else:
- result[-1].tail = text
+ parent.tail = text
else:
if parent.text:
parent.text += text
else:
parent.text = text
-
result = []
strartIndex = 0
while data:
@@ -168,28 +206,33 @@ class InlineProcessor(Treeprocessor):
text = data[strartIndex:index]
linkText(text)
- if not isString(node): # it's Element
- for child in [node] + node.getchildren():
+ if not isString(node): # it's Element
+ for child in [node] + list(node):
if child.tail:
if child.tail.strip():
- self.__processElementText(node, child, False)
+ self.__processElementText(
+ node, child, False
+ )
if child.text:
if child.text.strip():
self.__processElementText(child, child)
- else: # it's just a string
+ else: # it's just a string
linkText(node)
strartIndex = phEndIndex
continue
strartIndex = phEndIndex
- result.append(node)
+ result.append((node, self.ancestors[:]))
- else: # wrong placeholder
- end = index + len(prefix)
+ else: # wrong placeholder
+ end = index + len(self.__placeholder_prefix)
linkText(data[strartIndex:end])
strartIndex = end
else:
text = data[strartIndex:]
+ if isinstance(data, util.AtomicString):
+ # We don't want to loose the AtomicString
+ text = util.AtomicString(text)
linkText(text)
data = ""
@@ -205,94 +248,149 @@ class InlineProcessor(Treeprocessor):
* data: the text to be processed
* pattern: the pattern to be checked
* patternIndex: index of current pattern
- * startIndex: string index, from which we starting search
+ * startIndex: string index, from which we start searching
Returns: String with placeholders instead of ElementTree elements.
"""
- match = pattern.getCompiledRegExp().match(data[startIndex:])
- leftData = data[:startIndex]
+ new_style = isinstance(pattern, inlinepatterns.InlineProcessor)
+
+ for exclude in pattern.ANCESTOR_EXCLUDES:
+ if exclude.lower() in self.ancestors:
+ return data, False, 0
+
+ if new_style:
+ match = None
+ # Since handleMatch may reject our first match,
+ # we iterate over the buffer looking for matches
+ # until we can't find any more.
+ for match in pattern.getCompiledRegExp().finditer(data, startIndex):
+ node, start, end = pattern.handleMatch(match, data)
+ if start is None or end is None:
+ startIndex += match.end(0)
+ match = None
+ continue
+ break
+ else: # pragma: no cover
+ match = pattern.getCompiledRegExp().match(data[startIndex:])
+ leftData = data[:startIndex]
if not match:
return data, False, 0
- node = pattern.handleMatch(match)
+ if not new_style: # pragma: no cover
+ node = pattern.handleMatch(match)
+ start = match.start(0)
+ end = match.end(0)
if node is None:
- return data, True, len(leftData) + match.span(len(match.groups()))[0]
+ return data, True, end
if not isString(node):
- if not isinstance(node.text, markdown.AtomicString):
+ if not isinstance(node.text, util.AtomicString):
# We need to process current node too
- for child in [node] + node.getchildren():
+ for child in [node] + list(node):
if not isString(node):
if child.text:
- child.text = self.__handleInline(child.text,
- patternIndex + 1)
+ self.ancestors.append(child.tag.lower())
+ child.text = self.__handleInline(
+ child.text, patternIndex + 1
+ )
+ self.ancestors.pop()
if child.tail:
- child.tail = self.__handleInline(child.tail,
- patternIndex)
+ child.tail = self.__handleInline(
+ child.tail, patternIndex
+ )
placeholder = self.__stashNode(node, pattern.type())
- return "%s%s%s%s" % (leftData,
- match.group(1),
- placeholder, match.groups()[-1]), True, 0
-
- def run(self, tree):
+ if new_style:
+ return "{}{}{}".format(data[:start],
+ placeholder, data[end:]), True, 0
+ else: # pragma: no cover
+ return "{}{}{}{}".format(leftData,
+ match.group(1),
+ placeholder, match.groups()[-1]), True, 0
+
+ def __build_ancestors(self, parent, parents):
+ """Build the ancestor list."""
+ ancestors = []
+ while parent is not None:
+ if parent is not None:
+ ancestors.append(parent.tag.lower())
+ parent = self.parent_map.get(parent)
+ ancestors.reverse()
+ parents.extend(ancestors)
+
+ def run(self, tree, ancestors=None):
"""Apply inline patterns to a parsed Markdown tree.
Iterate over ElementTree, find elements with inline tag, apply inline
patterns and append newly created Elements to tree. If you don't
- want process your data with inline paterns, instead of normal string,
- use subclass AtomicString:
+ want to process your data with inline patterns, instead of normal
+ string, use subclass AtomicString:
- node.text = markdown.AtomicString("data won't be processed with inline patterns")
+ node.text = markdown.AtomicString("This will not be processed.")
Arguments:
- * markdownTree: ElementTree object, representing Markdown tree.
+ * tree: ElementTree object, representing Markdown tree.
+ * ancestors: List of parent tag names that precede the tree node (if needed).
Returns: ElementTree object with applied inline patterns.
"""
self.stashed_nodes = {}
- stack = [tree]
+ # Ensure a valid parent list, but copy passed in lists
+ # to ensure we don't have the user accidentally change it on us.
+ tree_parents = [] if ancestors is None else ancestors[:]
+
+ self.parent_map = {c: p for p in tree.iter() for c in p}
+ stack = [(tree, tree_parents)]
while stack:
- currElement = stack.pop()
+ currElement, parents = stack.pop()
+
+ self.ancestors = parents
+ self.__build_ancestors(currElement, self.ancestors)
+
insertQueue = []
- for child in currElement.getchildren():
- if child.text and not isinstance(child.text, markdown.AtomicString):
+ for child in currElement:
+ if child.text and not isinstance(
+ child.text, util.AtomicString
+ ):
+ self.ancestors.append(child.tag.lower())
text = child.text
child.text = None
- lst = self.__processPlaceholders(self.__handleInline(
- text), child)
+ lst = self.__processPlaceholders(
+ self.__handleInline(text), child
+ )
+ for item in lst:
+ self.parent_map[item[0]] = child
stack += lst
insertQueue.append((child, lst))
-
- if child.getchildren():
- stack.append(child)
+ self.ancestors.pop()
+ if child.tail:
+ tail = self.__handleInline(child.tail)
+ dumby = etree.Element('d')
+ child.tail = None
+ tailResult = self.__processPlaceholders(tail, dumby, False)
+ if dumby.tail:
+ child.tail = dumby.tail
+ pos = list(currElement).index(child) + 1
+ tailResult.reverse()
+ for newChild in tailResult:
+ self.parent_map[newChild[0]] = currElement
+ currElement.insert(pos, newChild[0])
+ if len(child):
+ self.parent_map[child] = currElement
+ stack.append((child, self.ancestors[:]))
for element, lst in insertQueue:
- if element.text:
- element.text = \
- markdown.inlinepatterns.handleAttributes(element.text,
- element)
- i = 0
- for newChild in lst:
- # Processing attributes
- if newChild.tail:
- newChild.tail = \
- markdown.inlinepatterns.handleAttributes(newChild.tail,
- element)
- if newChild.text:
- newChild.text = \
- markdown.inlinepatterns.handleAttributes(newChild.text,
- newChild)
+ for i, obj in enumerate(lst):
+ newChild = obj[0]
element.insert(i, newChild)
- i += 1
return tree
@@ -303,15 +401,13 @@ class PrettifyTreeprocessor(Treeprocessor):
""" Recursively add linebreaks to ElementTree children. """
i = "\n"
- if markdown.isBlockLevel(elem.tag) and elem.tag not in ['code', 'pre']:
+ if self.md.is_block_level(elem.tag) and elem.tag not in ['code', 'pre']:
if (not elem.text or not elem.text.strip()) \
- and len(elem) and markdown.isBlockLevel(elem[0].tag):
+ and len(elem) and self.md.is_block_level(elem[0].tag):
elem.text = i
for e in elem:
- if markdown.isBlockLevel(e.tag):
+ if self.md.is_block_level(e.tag):
self._prettifyETree(e)
- if not elem.tail or not elem.tail.strip():
- elem.tail = i
if not elem.tail or not elem.tail.strip():
elem.tail = i
@@ -319,11 +415,44 @@ class PrettifyTreeprocessor(Treeprocessor):
""" Add linebreaks to ElementTree root object. """
self._prettifyETree(root)
- # Do <br />'s seperately as they are often in the middle of
+ # Do <br />'s separately as they are often in the middle of
# inline content and missed by _prettifyETree.
- brs = root.getiterator('br')
+ brs = root.iter('br')
for br in brs:
if not br.tail or not br.tail.strip():
br.tail = '\n'
else:
br.tail = '\n%s' % br.tail
+ # Clean up extra empty lines at end of code blocks.
+ pres = root.iter('pre')
+ for pre in pres:
+ if len(pre) and pre[0].tag == 'code':
+ code = pre[0]
+ # Only prettify code containing text only
+ if not len(code) and code.text is not None:
+ code.text = util.AtomicString(code.text.rstrip() + '\n')
+
+
+class UnescapeTreeprocessor(Treeprocessor):
+ """ Restore escaped chars """
+
+ RE = re.compile(r'{}(\d+){}'.format(util.STX, util.ETX))
+
+ def _unescape(self, m):
+ return chr(int(m.group(1)))
+
+ def unescape(self, text):
+ return self.RE.sub(self._unescape, text)
+
+ def run(self, root):
+ """ Loop over all elements and unescape all text. """
+ for elem in root.iter():
+ # Unescape text content
+ if elem.text and not elem.tag == 'code':
+ elem.text = self.unescape(elem.text)
+ # Unescape tail content
+ if elem.tail:
+ elem.tail = self.unescape(elem.tail)
+ # Unescape attribute values
+ for key, value in elem.items():
+ elem.set(key, self.unescape(value))
diff --git a/markdown/util.py b/markdown/util.py
new file mode 100644
index 0000000..e6b08e5
--- /dev/null
+++ b/markdown/util.py
@@ -0,0 +1,358 @@
+"""
+Python Markdown
+
+A Python implementation of John Gruber's Markdown.
+
+Documentation: https://python-markdown.github.io/
+GitHub: https://github.com/Python-Markdown/markdown/
+PyPI: https://pypi.org/project/Markdown/
+
+Started by Manfred Stienstra (http://www.dwerg.net/).
+Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
+Currently maintained by Waylan Limberg (https://github.com/waylan),
+Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
+
+Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see LICENSE.md for details).
+"""
+
+import re
+import sys
+import warnings
+from collections import namedtuple
+from functools import wraps, lru_cache
+from itertools import count
+
+
+"""
+Constants you might want to modify
+-----------------------------------------------------------------------------
+"""
+
+
+BLOCK_LEVEL_ELEMENTS = [
+ # Elements which are invalid to wrap in a `<p>` tag.
+ # See https://w3c.github.io/html/grouping-content.html#the-p-element
+ 'address', 'article', 'aside', 'blockquote', 'details', 'div', 'dl',
+ 'fieldset', 'figcaption', 'figure', 'footer', 'form', 'h1', 'h2', 'h3',
+ 'h4', 'h5', 'h6', 'header', 'hgroup', 'hr', 'main', 'menu', 'nav', 'ol',
+ 'p', 'pre', 'section', 'table', 'ul',
+ # Other elements which Markdown should not be mucking up the contents of.
+ 'canvas', 'colgroup', 'dd', 'body', 'dt', 'group', 'iframe', 'li', 'legend',
+ 'math', 'map', 'noscript', 'output', 'object', 'option', 'progress', 'script',
+ 'style', 'tbody', 'td', 'textarea', 'tfoot', 'th', 'thead', 'tr', 'video'
+]
+
+# Placeholders
+STX = '\u0002' # Use STX ("Start of text") for start-of-placeholder
+ETX = '\u0003' # Use ETX ("End of text") for end-of-placeholder
+INLINE_PLACEHOLDER_PREFIX = STX+"klzzwxh:"
+INLINE_PLACEHOLDER = INLINE_PLACEHOLDER_PREFIX + "%s" + ETX
+INLINE_PLACEHOLDER_RE = re.compile(INLINE_PLACEHOLDER % r'([0-9]+)')
+AMP_SUBSTITUTE = STX+"amp"+ETX
+HTML_PLACEHOLDER = STX + "wzxhzdk:%s" + ETX
+HTML_PLACEHOLDER_RE = re.compile(HTML_PLACEHOLDER % r'([0-9]+)')
+TAG_PLACEHOLDER = STX + "hzzhzkh:%s" + ETX
+
+
+"""
+Constants you probably do not need to change
+-----------------------------------------------------------------------------
+"""
+
+RTL_BIDI_RANGES = (
+ ('\u0590', '\u07FF'),
+ # Hebrew (0590-05FF), Arabic (0600-06FF),
+ # Syriac (0700-074F), Arabic supplement (0750-077F),
+ # Thaana (0780-07BF), Nko (07C0-07FF).
+ ('\u2D30', '\u2D7F') # Tifinagh
+)
+
+
+"""
+AUXILIARY GLOBAL FUNCTIONS
+=============================================================================
+"""
+
+
+@lru_cache(maxsize=None)
+def get_installed_extensions():
+ if sys.version_info >= (3, 10):
+ from importlib import metadata
+ else: # <PY310 use backport
+ import importlib_metadata as metadata
+ # Only load extension entry_points once.
+ return metadata.entry_points(group='markdown.extensions')
+
+
+def deprecated(message, stacklevel=2):
+ """
+ Raise a DeprecationWarning when wrapped function/method is called.
+
+ Usage:
+ @deprecated("This method will be removed in version X; use Y instead.")
+ def some_method()"
+ pass
+ """
+ def wrapper(func):
+ @wraps(func)
+ def deprecated_func(*args, **kwargs):
+ warnings.warn(
+ f"'{func.__name__}' is deprecated. {message}",
+ category=DeprecationWarning,
+ stacklevel=stacklevel
+ )
+ return func(*args, **kwargs)
+ return deprecated_func
+ return wrapper
+
+
+def parseBoolValue(value, fail_on_errors=True, preserve_none=False):
+ """Parses a string representing bool value. If parsing was successful,
+ returns True or False. If preserve_none=True, returns True, False,
+ or None. If parsing was not successful, raises ValueError, or, if
+ fail_on_errors=False, returns None."""
+ if not isinstance(value, str):
+ if preserve_none and value is None:
+ return value
+ return bool(value)
+ elif preserve_none and value.lower() == 'none':
+ return None
+ elif value.lower() in ('true', 'yes', 'y', 'on', '1'):
+ return True
+ elif value.lower() in ('false', 'no', 'n', 'off', '0', 'none'):
+ return False
+ elif fail_on_errors:
+ raise ValueError('Cannot parse bool value: %r' % value)
+
+
+def code_escape(text):
+ """Escape code."""
+ if "&" in text:
+ text = text.replace("&", "&amp;")
+ if "<" in text:
+ text = text.replace("<", "&lt;")
+ if ">" in text:
+ text = text.replace(">", "&gt;")
+ return text
+
+
+def _get_stack_depth(size=2):
+ """Get current stack depth, performantly.
+ """
+ frame = sys._getframe(size)
+
+ for size in count(size):
+ frame = frame.f_back
+ if not frame:
+ return size
+
+
+def nearing_recursion_limit():
+ """Return true if current stack depth is within 100 of maximum limit."""
+ return sys.getrecursionlimit() - _get_stack_depth() < 100
+
+
+"""
+MISC AUXILIARY CLASSES
+=============================================================================
+"""
+
+
+class AtomicString(str):
+ """A string which should not be further processed."""
+ pass
+
+
+class Processor:
+ def __init__(self, md=None):
+ self.md = md
+
+
+class HtmlStash:
+ """
+ This class is used for stashing HTML objects that we extract
+ in the beginning and replace with place-holders.
+ """
+
+ def __init__(self):
+ """ Create a HtmlStash. """
+ self.html_counter = 0 # for counting inline html segments
+ self.rawHtmlBlocks = []
+ self.tag_counter = 0
+ self.tag_data = [] # list of dictionaries in the order tags appear
+
+ def store(self, html):
+ """
+ Saves an HTML segment for later reinsertion. Returns a
+ placeholder string that needs to be inserted into the
+ document.
+
+ Keyword arguments:
+
+ * html: an html segment
+
+ Returns : a placeholder string
+
+ """
+ self.rawHtmlBlocks.append(html)
+ placeholder = self.get_placeholder(self.html_counter)
+ self.html_counter += 1
+ return placeholder
+
+ def reset(self):
+ self.html_counter = 0
+ self.rawHtmlBlocks = []
+
+ def get_placeholder(self, key):
+ return HTML_PLACEHOLDER % key
+
+ def store_tag(self, tag, attrs, left_index, right_index):
+ """Store tag data and return a placeholder."""
+ self.tag_data.append({'tag': tag, 'attrs': attrs,
+ 'left_index': left_index,
+ 'right_index': right_index})
+ placeholder = TAG_PLACEHOLDER % str(self.tag_counter)
+ self.tag_counter += 1 # equal to the tag's index in self.tag_data
+ return placeholder
+
+
+# Used internally by `Registry` for each item in its sorted list.
+# Provides an easier to read API when editing the code later.
+# For example, `item.name` is more clear than `item[0]`.
+_PriorityItem = namedtuple('PriorityItem', ['name', 'priority'])
+
+
+class Registry:
+ """
+ A priority sorted registry.
+
+ A `Registry` instance provides two public methods to alter the data of the
+ registry: `register` and `deregister`. Use `register` to add items and
+ `deregister` to remove items. See each method for specifics.
+
+ When registering an item, a "name" and a "priority" must be provided. All
+ items are automatically sorted by "priority" from highest to lowest. The
+ "name" is used to remove ("deregister") and get items.
+
+ A `Registry` instance it like a list (which maintains order) when reading
+ data. You may iterate over the items, get an item and get a count (length)
+ of all items. You may also check that the registry contains an item.
+
+ When getting an item you may use either the index of the item or the
+ string-based "name". For example:
+
+ registry = Registry()
+ registry.register(SomeItem(), 'itemname', 20)
+ # Get the item by index
+ item = registry[0]
+ # Get the item by name
+ item = registry['itemname']
+
+ When checking that the registry contains an item, you may use either the
+ string-based "name", or a reference to the actual item. For example:
+
+ someitem = SomeItem()
+ registry.register(someitem, 'itemname', 20)
+ # Contains the name
+ assert 'itemname' in registry
+ # Contains the item instance
+ assert someitem in registry
+
+ The method `get_index_for_name` is also available to obtain the index of
+ an item using that item's assigned "name".
+ """
+
+ def __init__(self):
+ self._data = {}
+ self._priority = []
+ self._is_sorted = False
+
+ def __contains__(self, item):
+ if isinstance(item, str):
+ # Check if an item exists by this name.
+ return item in self._data.keys()
+ # Check if this instance exists.
+ return item in self._data.values()
+
+ def __iter__(self):
+ self._sort()
+ return iter([self._data[k] for k, p in self._priority])
+
+ def __getitem__(self, key):
+ self._sort()
+ if isinstance(key, slice):
+ data = Registry()
+ for k, p in self._priority[key]:
+ data.register(self._data[k], k, p)
+ return data
+ if isinstance(key, int):
+ return self._data[self._priority[key].name]
+ return self._data[key]
+
+ def __len__(self):
+ return len(self._priority)
+
+ def __repr__(self):
+ return '<{}({})>'.format(self.__class__.__name__, list(self))
+
+ def get_index_for_name(self, name):
+ """
+ Return the index of the given name.
+ """
+ if name in self:
+ self._sort()
+ return self._priority.index(
+ [x for x in self._priority if x.name == name][0]
+ )
+ raise ValueError('No item named "{}" exists.'.format(name))
+
+ def register(self, item, name, priority):
+ """
+ Add an item to the registry with the given name and priority.
+
+ Parameters:
+
+ * `item`: The item being registered.
+ * `name`: A string used to reference the item.
+ * `priority`: An integer or float used to sort against all items.
+
+ If an item is registered with a "name" which already exists, the
+ existing item is replaced with the new item. Treat carefully as the
+ old item is lost with no way to recover it. The new item will be
+ sorted according to its priority and will **not** retain the position
+ of the old item.
+ """
+ if name in self:
+ # Remove existing item of same name first
+ self.deregister(name)
+ self._is_sorted = False
+ self._data[name] = item
+ self._priority.append(_PriorityItem(name, priority))
+
+ def deregister(self, name, strict=True):
+ """
+ Remove an item from the registry.
+
+ Set `strict=False` to fail silently.
+ """
+ try:
+ index = self.get_index_for_name(name)
+ del self._priority[index]
+ del self._data[name]
+ except ValueError:
+ if strict:
+ raise
+
+ def _sort(self):
+ """
+ Sort the registry by priority from highest to lowest.
+
+ This method is called internally and should never be explicitly called.
+ """
+ if not self._is_sorted:
+ self._priority.sort(key=lambda item: item.priority, reverse=True)
+ self._is_sorted = True
diff --git a/mkdocs.yml b/mkdocs.yml
new file mode 100644
index 0000000..4c53ac3
--- /dev/null
+++ b/mkdocs.yml
@@ -0,0 +1,64 @@
+site_name: Python-Markdown
+site_url: https://Python-Markdown.github.io/
+repo_url: https://github.com/Python-Markdown/markdown
+site_author: "The Python-Markdown Project"
+copyright: "Copyright &copy; 2010-2017"
+
+use_directory_urls: true
+
+theme:
+ name: nature
+ icon: py.png
+ release: !!python/name:markdown.__version__
+ issue_tracker: https://github.com/Python-Markdown/markdown/issues
+
+nav:
+ - Python-Markdown: index.md
+ - Installation: install.md
+ - Library Reference: reference.md
+ - Command Line: cli.md
+ - Extensions: extensions/index.md
+ - Officially Supported Extensions:
+ - Abbreviations: extensions/abbreviations.md
+ - Admonition: extensions/admonition.md
+ - Attribute Lists: extensions/attr_list.md
+ - CodeHilite: extensions/code_hilite.md
+ - Definition Lists: extensions/definition_lists.md
+ - Extra: extensions/extra.md
+ - Fenced Code Blocks: extensions/fenced_code_blocks.md
+ - Footnotes: extensions/footnotes.md
+ - Legacy Attributes: extensions/legacy_attrs.md
+ - Legacy Emphasis: extensions/legacy_em.md
+ - Meta-Data: extensions/meta_data.md
+ - New Line to Break: extensions/nl2br.md
+ - Markdown in HTML: extensions/md_in_html.md
+ - Sane Lists: extensions/sane_lists.md
+ - SmartyPants: extensions/smarty.md
+ - Table of Contents: extensions/toc.md
+ - Tables: extensions/tables.md
+ - WikiLinks: extensions/wikilinks.md
+ - Extension API: extensions/api.md
+ - Test Tools: test_tools.md
+ - Contributing to Python-Markdown: contributing.md
+ - Change Log: change_log/index.md
+ - Release Notes for v.3.4: change_log/release-3.4.md
+ - Release Notes for v.3.3: change_log/release-3.3.md
+ - Release Notes for v.3.2: change_log/release-3.2.md
+ - Release Notes for v.3.1: change_log/release-3.1.md
+ - Release Notes for v.3.0: change_log/release-3.0.md
+ - Release Notes for v.2.6: change_log/release-2.6.md
+ - Release Notes for v.2.5: change_log/release-2.5.md
+ - Release Notes for v.2.4: change_log/release-2.4.md
+ - Release Notes for v.2.3: change_log/release-2.3.md
+ - Release Notes for v.2.2: change_log/release-2.2.md
+ - Release Notes for v.2.1: change_log/release-2.1.md
+ - Release Notes for v.2.0: change_log/release-2.0.md
+ - Authors: authors.md
+
+markdown_extensions:
+ - extra
+ - admonition
+ - smarty
+ - codehilite
+ - toc:
+ permalink: true
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000..39d9d77
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,4 @@
+[build-system]
+# Minimum requirements for the build system to execute.
+requires = ["setuptools>=36.6", "wheel"]
+build-backend = "setuptools.build_meta"
diff --git a/regression-tests.py b/regression-tests.py
deleted file mode 100755
index 7601061..0000000
--- a/regression-tests.py
+++ /dev/null
@@ -1,234 +0,0 @@
-#!/usr/bin/python
-"""
-Python-Markdown Regression Tests
-================================
-
-Tests of the various APIs with the python markdown lib.
-
-"""
-
-import unittest
-from doctest import DocTestSuite
-import os
-import markdown
-
-class TestMarkdown(unittest.TestCase):
- """ Tests basics of the Markdown class. """
-
- def setUp(self):
- """ Create instance of Markdown. """
- self.md = markdown.Markdown()
-
- def testBlankInput(self):
- """ Test blank input. """
- self.assertEqual(self.md.convert(''), '')
-
- def testWhitespaceOnly(self):
- """ Test input of only whitespace. """
- self.assertEqual(self.md.convert(' '), '')
-
- def testSimpleInput(self):
- """ Test simple input. """
- self.assertEqual(self.md.convert('foo'), '<p>foo</p>')
-
-class TestBlockParser(unittest.TestCase):
- """ Tests of the BlockParser class. """
-
- def setUp(self):
- """ Create instance of BlockParser. """
- self.parser = markdown.Markdown().parser
-
- def testParseChunk(self):
- """ Test BlockParser.parseChunk. """
- root = markdown.etree.Element("div")
- text = 'foo'
- self.parser.parseChunk(root, text)
- self.assertEqual(markdown.etree.tostring(root), "<div><p>foo</p></div>")
-
- def testParseDocument(self):
- """ Test BlockParser.parseDocument. """
- lines = ['#foo', '', 'bar', '', ' baz']
- tree = self.parser.parseDocument(lines)
- self.assert_(isinstance(tree, markdown.etree.ElementTree))
- self.assert_(markdown.etree.iselement(tree.getroot()))
- self.assertEqual(markdown.etree.tostring(tree.getroot()),
- "<div><h1>foo</h1><p>bar</p><pre><code>baz\n</code></pre></div>")
-
-
-class TestBlockParserState(unittest.TestCase):
- """ Tests of the State class for BlockParser. """
-
- def setUp(self):
- self.state = markdown.blockparser.State()
-
- def testBlankState(self):
- """ Test State when empty. """
- self.assertEqual(self.state, [])
-
- def testSetSate(self):
- """ Test State.set(). """
- self.state.set('a_state')
- self.assertEqual(self.state, ['a_state'])
- self.state.set('state2')
- self.assertEqual(self.state, ['a_state', 'state2'])
-
- def testIsSate(self):
- """ Test State.isstate(). """
- self.assertEqual(self.state.isstate('anything'), False)
- self.state.set('a_state')
- self.assertEqual(self.state.isstate('a_state'), True)
- self.state.set('state2')
- self.assertEqual(self.state.isstate('state2'), True)
- self.assertEqual(self.state.isstate('a_state'), False)
- self.assertEqual(self.state.isstate('missing'), False)
-
- def testReset(self):
- """ Test State.reset(). """
- self.state.set('a_state')
- self.state.reset()
- self.assertEqual(self.state, [])
- self.state.set('state1')
- self.state.set('state2')
- self.state.reset()
- self.assertEqual(self.state, ['state1'])
-
-class TestHtmlStash(unittest.TestCase):
- """ Test Markdown's HtmlStash. """
-
- def setUp(self):
- self.stash = markdown.preprocessors.HtmlStash()
- self.placeholder = self.stash.store('foo')
-
- def testSimpleStore(self):
- """ Test HtmlStash.store. """
- self.assertEqual(self.placeholder,
- markdown.preprocessors.HTML_PLACEHOLDER % 0)
- self.assertEqual(self.stash.html_counter, 1)
- self.assertEqual(self.stash.rawHtmlBlocks, [('foo', False)])
-
- def testStoreMore(self):
- """ Test HtmlStash.store with additional blocks. """
- placeholder = self.stash.store('bar')
- self.assertEqual(placeholder,
- markdown.preprocessors.HTML_PLACEHOLDER % 1)
- self.assertEqual(self.stash.html_counter, 2)
- self.assertEqual(self.stash.rawHtmlBlocks,
- [('foo', False), ('bar', False)])
-
- def testSafeStore(self):
- """ Test HtmlStash.store with 'safe' html. """
- self.stash.store('bar', True)
- self.assertEqual(self.stash.rawHtmlBlocks,
- [('foo', False), ('bar', True)])
-
- def testReset(self):
- """ Test HtmlStash.reset. """
- self.stash.reset()
- self.assertEqual(self.stash.html_counter, 0)
- self.assertEqual(self.stash.rawHtmlBlocks, [])
-
-class TestOrderedDict(unittest.TestCase):
- """ Test OrderedDict storage class. """
-
- def setUp(self):
- self.odict = markdown.odict.OrderedDict()
- self.odict['first'] = 'This'
- self.odict['third'] = 'a'
- self.odict['fourth'] = 'self'
- self.odict['fifth'] = 'test'
-
- def testValues(self):
- """ Test output of OrderedDict.values(). """
- self.assertEqual(self.odict.values(), ['This', 'a', 'self', 'test'])
-
- def testKeys(self):
- """ Test output of OrderedDict.keys(). """
- self.assertEqual(self.odict.keys(),
- ['first', 'third', 'fourth', 'fifth'])
-
- def testItems(self):
- """ Test output of OrderedDict.items(). """
- self.assertEqual(self.odict.items(),
- [('first', 'This'), ('third', 'a'),
- ('fourth', 'self'), ('fifth', 'test')])
-
- def testAddBefore(self):
- """ Test adding an OrderedDict item before a given key. """
- self.odict.add('second', 'is', '<third')
- self.assertEqual(self.odict.items(),
- [('first', 'This'), ('second', 'is'), ('third', 'a'),
- ('fourth', 'self'), ('fifth', 'test')])
-
- def testAddAfter(self):
- """ Test adding an OrderDict item after a given key. """
- self.odict.add('second', 'is', '>first')
- self.assertEqual(self.odict.items(),
- [('first', 'This'), ('second', 'is'), ('third', 'a'),
- ('fourth', 'self'), ('fifth', 'test')])
-
- def testAddAfterEnd(self):
- """ Test adding an OrderedDict item after the last key. """
- self.odict.add('sixth', '.', '>fifth')
- self.assertEqual(self.odict.items(),
- [('first', 'This'), ('third', 'a'),
- ('fourth', 'self'), ('fifth', 'test'), ('sixth', '.')])
-
- def testAdd_begin(self):
- """ Test adding an OrderedDict item using "_begin". """
- self.odict.add('zero', 'CRAZY', '_begin')
- self.assertEqual(self.odict.items(),
- [('zero', 'CRAZY'), ('first', 'This'), ('third', 'a'),
- ('fourth', 'self'), ('fifth', 'test')])
-
- def testAdd_end(self):
- """ Test adding an OrderedDict item using "_end". """
- self.odict.add('sixth', '.', '_end')
- self.assertEqual(self.odict.items(),
- [('first', 'This'), ('third', 'a'),
- ('fourth', 'self'), ('fifth', 'test'), ('sixth', '.')])
-
- def testAddBadLocation(self):
- """ Test Error on bad location in OrderedDict.add(). """
- self.assertRaises(ValueError, self.odict.add, 'sixth', '.', '<seventh')
- self.assertRaises(ValueError, self.odict.add, 'second', 'is', 'third')
-
- def testDeleteItem(self):
- """ Test deletion of an OrderedDict item. """
- del self.odict['fourth']
- self.assertEqual(self.odict.items(),
- [('first', 'This'), ('third', 'a'), ('fifth', 'test')])
-
- def testChangeValue(self):
- """ Test OrderedDict change value. """
- self.odict['fourth'] = 'CRAZY'
- self.assertEqual(self.odict.items(),
- [('first', 'This'), ('third', 'a'),
- ('fourth', 'CRAZY'), ('fifth', 'test')])
-
- def testChangeOrder(self):
- """ Test OrderedDict change order. """
- self.odict.link('fourth', '<third')
- self.assertEqual(self.odict.items(),
- [('first', 'This'), ('fourth', 'self'),
- ('third', 'a'), ('fifth', 'test')])
-
-def suite():
- """ Build a test suite of the above tests and extension doctests. """
- suite = unittest.TestSuite()
- suite.addTest(unittest.makeSuite(TestMarkdown))
- suite.addTest(unittest.makeSuite(TestBlockParser))
- suite.addTest(unittest.makeSuite(TestBlockParserState))
- suite.addTest(unittest.makeSuite(TestHtmlStash))
- suite.addTest(unittest.makeSuite(TestOrderedDict))
-
- for filename in os.listdir('markdown/extensions'):
- if filename.endswith('.py'):
- module = 'markdown.extensions.%s' % filename[:-3]
- try:
- suite.addTest(DocTestSuite(module))
- except: ValueError
- # No tests
- return suite
-
-if __name__ == '__main__':
- unittest.TextTestRunner(verbosity=2).run(suite())
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 0000000..21934a2
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,2 @@
+[metadata]
+license_file = LICENSE.md
diff --git a/setup.py b/setup.py
index 42939d3..c6eb6af 100755
--- a/setup.py
+++ b/setup.py
@@ -1,65 +1,132 @@
#!/usr/bin/env python
+"""
+Python Markdown
-import sys, os
-from distutils.core import setup
-from distutils.command.install_scripts import install_scripts
-
-version = '2.0.3'
-
-class md_install_scripts(install_scripts):
- """ Customized install_scripts. Create markdown.bat for win32. """
- def run(self):
- install_scripts.run(self)
-
- if sys.platform == 'win32':
- try:
- script_dir = os.path.join(sys.prefix, 'Scripts')
- script_path = os.path.join(script_dir, 'markdown')
- bat_str = '@"%s" "%s" %%*' % (sys.executable, script_path)
- bat_path = os.path.join(self.install_dir, 'markdown.bat')
- f = file(bat_path, 'w')
- f.write(bat_str)
- f.close()
- print 'Created:', bat_path
- except Exception, e:
- print 'ERROR: Unable to create %s: %s' % (bat_path, e)
-
-data = dict(
- name = 'Markdown',
- version = version,
- url = 'http://www.freewisdom.org/projects/python-markdown',
- download_url = 'http://pypi.python.org/packages/source/M/Markdown/Markdown-%s.tar.gz' % version,
- description = 'Python implementation of Markdown.',
- author = 'Manfred Stienstra and Yuri takhteyev',
- author_email = 'yuri [at] freewisdom.org',
- maintainer = 'Waylan Limberg',
- maintainer_email = 'waylan [at] gmail.com',
- license = 'BSD License',
- packages = ['markdown', 'markdown.extensions'],
- scripts = ['bin/markdown'],
- cmdclass = {'install_scripts': md_install_scripts},
- classifiers = ['Development Status :: 5 - Production/Stable',
- 'License :: OSI Approved :: BSD License',
- 'Operating System :: OS Independent',
- 'Programming Language :: Python',
- 'Programming Language :: Python :: 2',
- 'Programming Language :: Python :: 2.3',
- 'Programming Language :: Python :: 2.4',
- 'Programming Language :: Python :: 2.5',
- 'Programming Language :: Python :: 2.6',
- 'Programming Language :: Python :: 3',
- 'Programming Language :: Python :: 3.0',
- 'Topic :: Communications :: Email :: Filters',
- 'Topic :: Internet :: WWW/HTTP :: Dynamic Content :: CGI Tools/Libraries',
- 'Topic :: Internet :: WWW/HTTP :: Site Management',
- 'Topic :: Software Development :: Documentation',
- 'Topic :: Software Development :: Libraries :: Python Modules',
- 'Topic :: Text Processing :: Filters',
- 'Topic :: Text Processing :: Markup :: HTML',
- ],
- )
-
-if sys.version[:3] < '2.5':
- data['install_requires'] = ['elementtree']
-
-setup(**data)
+A Python implementation of John Gruber's Markdown.
+
+Documentation: https://python-markdown.github.io/
+GitHub: https://github.com/Python-Markdown/markdown/
+PyPI: https://pypi.org/project/Markdown/
+
+Started by Manfred Stienstra (http://www.dwerg.net/).
+Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
+Currently maintained by Waylan Limberg (https://github.com/waylan),
+Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
+
+Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see LICENSE.md for details).
+"""
+
+
+import os
+from setuptools import setup
+
+
+def get_version():
+ """Get version and version_info from markdown/__meta__.py file."""
+ module_path = os.path.join(os.path.dirname('__file__'), 'markdown', '__meta__.py')
+
+ import importlib.util
+ spec = importlib.util.spec_from_file_location('__meta__', module_path)
+ meta = importlib.util.module_from_spec(spec)
+ spec.loader.exec_module(meta)
+ return meta.__version__, meta.__version_info__
+
+
+__version__, __version_info__ = get_version()
+
+# Get development Status for classifiers
+dev_status_map = {
+ 'dev': '2 - Pre-Alpha',
+ 'alpha': '3 - Alpha',
+ 'beta': '4 - Beta',
+ 'rc': '4 - Beta',
+ 'final': '5 - Production/Stable'
+}
+DEVSTATUS = dev_status_map[__version_info__[3]]
+
+# The command line script name. Currently set to "markdown_py" so as not to
+# conflict with the perl implementation (which uses "markdown").
+SCRIPT_NAME = 'markdown_py'
+
+with open('README.md') as f:
+ long_description = f.read()
+
+setup(
+ name='Markdown',
+ version=__version__,
+ url='https://Python-Markdown.github.io/',
+ project_urls={
+ 'Documentation': 'https://Python-Markdown.github.io/',
+ 'GitHub Project': 'https://github.com/Python-Markdown/markdown',
+ 'Issue Tracker': 'https://github.com/Python-Markdown/markdown/issues'
+ },
+ description='Python implementation of Markdown.',
+ long_description=long_description,
+ long_description_content_type='text/markdown',
+ author='Manfred Stienstra, Yuri takhteyev and Waylan limberg',
+ author_email='python.markdown@gmail.com',
+ maintainer='Waylan Limberg',
+ maintainer_email='python.markdown@gmail.com',
+ license='BSD License',
+ packages=['markdown', 'markdown.extensions'],
+ python_requires='>=3.7',
+ install_requires=["importlib-metadata>=4.4;python_version<'3.10'"],
+ extras_require={
+ 'testing': [
+ 'coverage',
+ 'pyyaml',
+ ],
+ },
+ entry_points={
+ 'console_scripts': [
+ '%s = markdown.__main__:run' % SCRIPT_NAME,
+ ],
+ # Register the built in extensions
+ 'markdown.extensions': [
+ 'abbr = markdown.extensions.abbr:AbbrExtension',
+ 'admonition = markdown.extensions.admonition:AdmonitionExtension',
+ 'attr_list = markdown.extensions.attr_list:AttrListExtension',
+ 'codehilite = markdown.extensions.codehilite:CodeHiliteExtension',
+ 'def_list = markdown.extensions.def_list:DefListExtension',
+ 'extra = markdown.extensions.extra:ExtraExtension',
+ 'fenced_code = markdown.extensions.fenced_code:FencedCodeExtension',
+ 'footnotes = markdown.extensions.footnotes:FootnoteExtension',
+ 'md_in_html = markdown.extensions.md_in_html:MarkdownInHtmlExtension',
+ 'meta = markdown.extensions.meta:MetaExtension',
+ 'nl2br = markdown.extensions.nl2br:Nl2BrExtension',
+ 'sane_lists = markdown.extensions.sane_lists:SaneListExtension',
+ 'smarty = markdown.extensions.smarty:SmartyExtension',
+ 'tables = markdown.extensions.tables:TableExtension',
+ 'toc = markdown.extensions.toc:TocExtension',
+ 'wikilinks = markdown.extensions.wikilinks:WikiLinkExtension',
+ 'legacy_attrs = markdown.extensions.legacy_attrs:LegacyAttrExtension',
+ 'legacy_em = markdown.extensions.legacy_em:LegacyEmExtension',
+ ]
+ },
+ classifiers=[
+ 'Development Status :: %s' % DEVSTATUS,
+ 'License :: OSI Approved :: BSD License',
+ 'Operating System :: OS Independent',
+ 'Programming Language :: Python',
+ 'Programming Language :: Python :: 3',
+ 'Programming Language :: Python :: 3.7',
+ 'Programming Language :: Python :: 3.8',
+ 'Programming Language :: Python :: 3.9',
+ 'Programming Language :: Python :: 3.10',
+ 'Programming Language :: Python :: 3 :: Only',
+ 'Programming Language :: Python :: Implementation :: CPython',
+ 'Programming Language :: Python :: Implementation :: PyPy',
+ 'Topic :: Communications :: Email :: Filters',
+ 'Topic :: Internet :: WWW/HTTP :: Dynamic Content :: CGI Tools/Libraries',
+ 'Topic :: Internet :: WWW/HTTP :: Site Management',
+ 'Topic :: Software Development :: Documentation',
+ 'Topic :: Software Development :: Libraries :: Python Modules',
+ 'Topic :: Text Processing :: Filters',
+ 'Topic :: Text Processing :: Markup :: HTML',
+ 'Topic :: Text Processing :: Markup :: Markdown'
+ ]
+)
diff --git a/test-markdown.py b/test-markdown.py
deleted file mode 100755
index e5dd870..0000000
--- a/test-markdown.py
+++ /dev/null
@@ -1,347 +0,0 @@
-#!/usr/bin/env python
-
-import os, difflib, time, gc, codecs, platform, sys
-from pprint import pprint
-import textwrap
-
-# Setup a logger manually for compatibility with Python 2.3
-import logging
-logging.getLogger('MARKDOWN').addHandler(logging.StreamHandler())
-import markdown
-
-TEST_DIR = "tests"
-TMP_DIR = "./tmp/"
-WRITE_BENCHMARK = True
-WRITE_BENCHMARK = False
-ACTUALLY_MEASURE_MEMORY = True
-
-######################################################################
-
-if platform.system().lower() == "darwin": # Darwin
- _proc_status = '/proc/%d/stat' % os.getpid()
-else: # Linux
- _proc_status = '/proc/%d/status' % os.getpid()
-
-_scale = {'kB': 1024.0, 'mB': 1024.0*1024.0,
- 'KB': 1024.0, 'MB': 1024.0*1024.0}
-
-def _VmB(VmKey):
- '''Private.
- '''
- global _proc_status, _scale
- # get pseudo file /proc/<pid>/status
- try:
- t = open(_proc_status)
- v = t.read()
- t.close()
- except:
- return 0.0 # non-Linux?
- # get VmKey line e.g. 'VmRSS: 9999 kB\n ...'
- i = v.index(VmKey)
- v = v[i:].split(None, 3) # whitespace
- if len(v) < 3:
- return 0.0 # invalid format?
- # convert Vm value to bytes
- return float(v[1]) * _scale[v[2]]
-
-
-def memory(since=0.0):
- '''Return memory usage in bytes.
- '''
- if ACTUALLY_MEASURE_MEMORY :
- return _VmB('VmSize:') - since
-
-
-def resident(since=0.0):
- '''Return resident memory usage in bytes.
- '''
- return _VmB('VmRSS:') - since
-
-
-def stacksize(since=0.0):
- '''Return stack size in bytes.
- '''
- return _VmB('VmStk:') - since
-
-
-############################################################
-
-DIFF_FILE_TEMPLATE = """
-<html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
- <style>
- td {
- padding-left: 10px;
- padding-right: 10px;
- }
- colgroup {
- margin: 10px;
- }
- .diff_header {
- color: gray;
- }
- .ok {
- color: green;
- }
- .gray {
- color: gray;
- }
- .failed a {
- color: red;
- }
- .failed {
- color: red;
- }
- </style>
-</head>
-<body>
-<h1>Results Summary</h1>
-<table rules="groups" >
- <colgroup></colgroup>
- <colgroup></colgroup>
- <colgroup></colgroup>
- <colgroup></colgroup>
- <colgroup></colgroup>
- <th>
- <td></td>
- <td>Seconds</td>
- <td></td>
- <td>Memory</td>
- </th>
- <tbody>
- """
-
-FOOTER = """
-</body>
-</html>
-"""
-
-DIFF_TABLE_TEMPLATE = """
- <table class="diff" rules="groups" >
- <colgroup></colgroup>
- <colgroup></colgroup>
- <colgroup></colgroup>
- <colgroup></colgroup>
- <colgroup></colgroup>
- <colgroup></colgroup>
- <th>
- <td></td>
- <td>Expected</td>
- <td></td>
- <td></td>
- <td>Actual</td>
- </th>
- <tbody>
- %s
- </tbody>
- </table>
-"""
-
-
-def smart_split(text) :
- result = []
- for x in text.splitlines() :
- for y in textwrap.wrap(textwrap.dedent(x), 40):
- result.append(y)
- return result
-
-
-differ = difflib.Differ()
-try :
- htmldiff = difflib.HtmlDiff()
-except:
- htmldiff = None
-
-class TestRunner :
-
- def __init__ (self) :
- self.failedTests = []
- if not os.path.exists(TMP_DIR):
- os.mkdir(TMP_DIR)
-
- def test_directory(self, dir, measure_time=False, safe_mode=False, encoding="utf-8", output_format='xhtml1') :
- self.encoding = encoding
- benchmark_file_name = os.path.join(dir, "benchmark.dat")
- self.saved_benchmarks = {}
-
- if measure_time :
- if os.path.exists(benchmark_file_name) :
- file = open(benchmark_file_name)
- for line in file.readlines() :
- test, str_time, str_mem = line.strip().split(":")
- self.saved_benchmarks[test] = (float(str_time), float(str_mem))
- repeat = range(10)
- else :
- repeat = (0,)
-
- # First, determine from the name of the directory if any extensions
- # need to be loaded.
-
- parts = os.path.split(dir)[-1].split("-x-")
- if len(parts) > 1 :
- extensions = parts[1].split("-")
- print extensions
- else :
- extensions = []
-
- mem = memory()
- start = time.clock()
- self.md = markdown.Markdown(extensions=extensions, safe_mode = safe_mode, output_format=output_format)
- construction_time = time.clock() - start
- construction_mem = memory(mem)
-
- self.benchmark_buffer = "construction:%f:%f\n" % (construction_time,
- construction_mem)
-
- html_diff_file_path = os.path.join(TMP_DIR, os.path.split(dir)[-1]) + ".html"
- self.html_diff_file = codecs.open(html_diff_file_path, "w", encoding=encoding)
- self.html_diff_file.write(DIFF_FILE_TEMPLATE)
-
- self.diffs_buffer = ""
-
- tests = [x.replace(".txt", "")
- for x in os.listdir(dir) if x.endswith(".txt")]
- tests.sort()
- for test in tests :
- self.run_test(dir, test, repeat)
-
- self.html_diff_file.write("</table>")
-
- if sys.version < "3.0":
- self.html_diff_file.write(self.diffs_buffer.decode("utf-8"))
-
- self.html_diff_file.write(FOOTER)
- self.html_diff_file.close()
- print "Diff written to %s" % html_diff_file_path
-
- benchmark_output_file_name = benchmark_file_name
-
- if not WRITE_BENCHMARK:
- benchmark_output_file_name += ".tmp"
-
- self.benchmark_file = open(benchmark_output_file_name, "w")
- self.benchmark_file.write(self.benchmark_buffer)
- self.benchmark_file.close()
-
-
-####################
-
-
- def run_test(self, dir, test, repeat):
-
- print "--- %s ---" % test
- self.html_diff_file.write("<tr><td>%s</td>" % test)
- input_file = os.path.join(dir, test + ".txt")
- output_file = os.path.join(dir, test + ".html")
-
- expected_output = codecs.open(output_file, encoding=self.encoding).read()
- input = codecs.open(input_file, encoding=self.encoding).read()
- actual_output = ""
- actual_lines = []
- self.md.source = ""
- gc.collect()
- mem = memory()
- start = time.clock()
- for x in repeat:
- actual_output = self.md.convert(input)
- conversion_time = time.clock() - start
- conversion_mem = memory(mem)
- self.md.reset()
-
- expected_lines = [x.encode("utf-8") for x in smart_split(expected_output)]
- actual_lines = [x.encode("utf-8") for x in smart_split(actual_output)]
-
- #diff = difflib.ndiff(expected_output.split("\n"),
- # actual_output.split("\n"))
-
- diff = [x for x in differ.compare(expected_lines,
- actual_lines)
- if not x.startswith(" ")]
-
- if not diff:
- self.html_diff_file.write("<td class='ok'>OK</td>")
- else :
- self.failedTests.append(test)
- self.html_diff_file.write("<td class='failed'>" +
- "<a href='#diff-%s'>FAILED</a></td>" % test)
- print "MISMATCH on %s/%s.txt" % (dir, test)
- print
- for line in diff :
- print line
- if htmldiff!=None :
- htmlDiff = htmldiff.make_table(expected_lines, actual_lines,
- context=True)
- htmlDiff = "\n".join( [x for x in htmlDiff.splitlines()
- if x.strip().startswith("<tr>")] )
- self.diffs_buffer += "<a name='diff-%s'/><h2>%s</h2>" % (test, test)
- self.diffs_buffer += DIFF_TABLE_TEMPLATE % htmlDiff
-
- expected_time, expected_mem = self.saved_benchmarks.get(test, ("na", "na"))
-
- self.html_diff_file.write(get_benchmark_html(conversion_time, expected_time))
- self.html_diff_file.write(get_benchmark_html(conversion_mem, expected_mem))
- self.html_diff_file.write("</tr>\n")
-
- self.benchmark_buffer += "%s:%f:%f\n" % (test,
- conversion_time, conversion_mem)
-
-
-
-
-
-def get_benchmark_html (actual, expected) :
- buffer = ""
- if not expected == "na":
- if actual > expected * 1.5:
- tdiff = "failed"
- elif actual * 1.5 < expected :
- tdiff = "ok"
- else :
- tdiff = "same"
- if ( (actual <= 0 and expected < 0.015) or
- (expected <= 0 and actual < 0.015)) :
- tdiff = "same"
- else :
- tdiff = "same"
- buffer += "<td class='%s'>%.2f</td>" % (tdiff, actual)
- if not expected == "na":
- buffer += "<td class='gray'>%.2f</td>" % (expected)
- return buffer
-
-
-def run_tests() :
-
- tester = TestRunner()
- #test.test_directory("tests/basic")
- tester.test_directory("tests/markdown-test", measure_time=True)
- tester.test_directory("tests/misc", measure_time=True)
- tester.test_directory("tests/extensions-x-tables")
- tester.test_directory("tests/extensions-x-footnotes")
- #tester.test_directory("tests/extensions-x-ext1-ext2")
- tester.test_directory("tests/safe_mode", measure_time=True, safe_mode="escape")
- tester.test_directory("tests/extensions-x-wikilinks")
- tester.test_directory("tests/extensions-x-toc")
- tester.test_directory("tests/extensions-x-def_list")
- tester.test_directory("tests/extensions-x-abbr")
- tester.test_directory("tests/html4", output_format='html4')
-
- try:
- import pygments
- except ImportError:
- # Dependancy not avalable - skip test
- pass
- else:
- tester.test_directory("tests/extensions-x-codehilite")
-
- print "\n### Final result ###"
- if len(tester.failedTests):
- print "%d failed tests: %s" % (len(tester.failedTests), str(tester.failedTests))
- else:
- print "All tests passed, no errors!"
-
-run_tests()
-
-
-
-
diff --git a/tests/__init__.py b/tests/__init__.py
new file mode 100644
index 0000000..564ba3b
--- /dev/null
+++ b/tests/__init__.py
@@ -0,0 +1,20 @@
+"""
+Python Markdown
+
+A Python implementation of John Gruber's Markdown.
+
+Documentation: https://python-markdown.github.io/
+GitHub: https://github.com/Python-Markdown/markdown/
+PyPI: https://pypi.org/project/Markdown/
+
+Started by Manfred Stienstra (http://www.dwerg.net/).
+Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
+Currently maintained by Waylan Limberg (https://github.com/waylan),
+Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
+
+Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see LICENSE.md for details).
+"""
diff --git a/tests/markdown-test/amps-and-angle-encoding.html b/tests/basic/amps-and-angle-encoding.html
index 2c466c1..2c466c1 100644
--- a/tests/markdown-test/amps-and-angle-encoding.html
+++ b/tests/basic/amps-and-angle-encoding.html
diff --git a/tests/markdown-test/amps-and-angle-encoding.txt b/tests/basic/amps-and-angle-encoding.txt
index 0e9527f..0e9527f 100644
--- a/tests/markdown-test/amps-and-angle-encoding.txt
+++ b/tests/basic/amps-and-angle-encoding.txt
diff --git a/tests/markdown-test/angle-links-and-img.html b/tests/basic/angle-links-and-img.html
index 1ca3b0b..1ca3b0b 100644
--- a/tests/markdown-test/angle-links-and-img.html
+++ b/tests/basic/angle-links-and-img.html
diff --git a/tests/markdown-test/angle-links-and-img.txt b/tests/basic/angle-links-and-img.txt
index 1dbf404..1dbf404 100644
--- a/tests/markdown-test/angle-links-and-img.txt
+++ b/tests/basic/angle-links-and-img.txt
diff --git a/tests/markdown-test/auto-links.html b/tests/basic/auto-links.html
index 7481fe2..7481fe2 100644
--- a/tests/markdown-test/auto-links.html
+++ b/tests/basic/auto-links.html
diff --git a/tests/markdown-test/auto-links.txt b/tests/basic/auto-links.txt
index a188b40..a188b40 100644
--- a/tests/markdown-test/auto-links.txt
+++ b/tests/basic/auto-links.txt
diff --git a/tests/markdown-test/backlash-escapes.html b/tests/basic/backlash-escapes.html
index 876775f..876775f 100644
--- a/tests/markdown-test/backlash-escapes.html
+++ b/tests/basic/backlash-escapes.html
diff --git a/tests/markdown-test/backlash-escapes.txt b/tests/basic/backlash-escapes.txt
index 16447a0..16447a0 100644
--- a/tests/markdown-test/backlash-escapes.txt
+++ b/tests/basic/backlash-escapes.txt
diff --git a/tests/markdown-test/blockquotes-with-code-blocks.html b/tests/basic/blockquotes-with-code-blocks.html
index 5fc98b1..5fc98b1 100644
--- a/tests/markdown-test/blockquotes-with-code-blocks.html
+++ b/tests/basic/blockquotes-with-code-blocks.html
diff --git a/tests/markdown-test/blockquotes-with-code-blocks.txt b/tests/basic/blockquotes-with-code-blocks.txt
index c31d171..c31d171 100644
--- a/tests/markdown-test/blockquotes-with-code-blocks.txt
+++ b/tests/basic/blockquotes-with-code-blocks.txt
diff --git a/tests/markdown-test/codeblock-in-list.html b/tests/basic/codeblock-in-list.html
index 49edd56..49edd56 100644
--- a/tests/markdown-test/codeblock-in-list.html
+++ b/tests/basic/codeblock-in-list.html
diff --git a/tests/markdown-test/codeblock-in-list.txt b/tests/basic/codeblock-in-list.txt
index 87d4e3b..87d4e3b 100644
--- a/tests/markdown-test/codeblock-in-list.txt
+++ b/tests/basic/codeblock-in-list.txt
diff --git a/tests/markdown-test/hard-wrapped.html b/tests/basic/hard-wrapped.html
index e28e900..e28e900 100644
--- a/tests/markdown-test/hard-wrapped.html
+++ b/tests/basic/hard-wrapped.html
diff --git a/tests/markdown-test/hard-wrapped.txt b/tests/basic/hard-wrapped.txt
index f8a5b27..f8a5b27 100644
--- a/tests/markdown-test/hard-wrapped.txt
+++ b/tests/basic/hard-wrapped.txt
diff --git a/tests/markdown-test/horizontal-rules.html b/tests/basic/horizontal-rules.html
index 478e8c5..478e8c5 100644
--- a/tests/markdown-test/horizontal-rules.html
+++ b/tests/basic/horizontal-rules.html
diff --git a/tests/markdown-test/horizontal-rules.txt b/tests/basic/horizontal-rules.txt
index 1594bda..1594bda 100644
--- a/tests/markdown-test/horizontal-rules.txt
+++ b/tests/basic/horizontal-rules.txt
diff --git a/tests/markdown-test/links-inline.html b/tests/basic/links-inline.html
index 707937a..707937a 100644
--- a/tests/markdown-test/links-inline.html
+++ b/tests/basic/links-inline.html
diff --git a/tests/markdown-test/links-inline.txt b/tests/basic/links-inline.txt
index 4d0c1c2..4d0c1c2 100644
--- a/tests/markdown-test/links-inline.txt
+++ b/tests/basic/links-inline.txt
diff --git a/tests/basic/links-reference.html b/tests/basic/links-reference.html
new file mode 100644
index 0000000..63f242d
--- /dev/null
+++ b/tests/basic/links-reference.html
@@ -0,0 +1,22 @@
+<p>Foo <a href="/url/" title="Title">bar</a>.</p>
+<p>Foo <a href="/url/" title="Title">bar</a>.</p>
+<p>Foo <a href="/url/" title="Title">bar</a>.</p>
+<p>With <a href="/url/">embedded [brackets]</a>.</p>
+<p>Indented <a href="/url">once</a>.</p>
+<p>Indented <a href="/url">twice</a>.</p>
+<p>Indented <a href="/url">thrice</a>.</p>
+<p>Indented [four][] times.</p>
+<pre><code>[four]: /url
+</code></pre>
+<p>With <a href="http://example.com/" title="Angle Brackets">angle brackets</a>.</p>
+<p>And <a href="http://example.com/" title="Without angle brackets.">without</a>.</p>
+<p>With <a href="http://example.com" title="Yes this works">line
+breaks</a></p>
+<p>and <a href="http://example.com" title="Yes this works">line
+breaks</a> with one space.</p>
+<p>and [line<br />
+breaks[] with two spaces.</p>
+<p><a href="http://example.com" title="No more hanging empty bracket!">short ref</a></p>
+<p><a href="http://example.com" title="No more hanging empty bracket!">short
+ref</a></p>
+<p><a href="http://example.com" title="Title on next line.">a ref</a></p> \ No newline at end of file
diff --git a/tests/basic/links-reference.txt b/tests/basic/links-reference.txt
new file mode 100644
index 0000000..3d636e5
--- /dev/null
+++ b/tests/basic/links-reference.txt
@@ -0,0 +1,61 @@
+Foo [bar] [1].
+
+Foo [bar][1].
+
+Foo [bar]
+[1].
+
+[1]: /url/ "Title"
+
+
+With [embedded [brackets]] [b].
+
+
+Indented [once][].
+
+Indented [twice][].
+
+Indented [thrice][].
+
+Indented [four][] times.
+
+ [once]: /url
+
+ [twice]: /url
+
+ [thrice]: /url
+
+ [four]: /url
+
+
+[b]: /url/
+
+With [angle brackets][].
+
+And [without][].
+
+[angle brackets]: <http://example.com/> "Angle Brackets"
+[without]: http://example.com/ "Without angle brackets."
+
+With [line
+breaks][]
+
+and [line
+breaks][] with one space.
+
+and [line
+breaks[] with two spaces.
+
+[line breaks]: http://example.com "Yes this works"
+
+[short ref]
+
+[short
+ref]
+
+[short ref]: http://example.com "No more hanging empty bracket!"
+
+[a ref]
+
+[a ref]: http://example.com
+ "Title on next line."
diff --git a/tests/markdown-test/literal-quotes.html b/tests/basic/literal-quotes.html
index 0342589..0342589 100644
--- a/tests/markdown-test/literal-quotes.html
+++ b/tests/basic/literal-quotes.html
diff --git a/tests/markdown-test/literal-quotes.txt b/tests/basic/literal-quotes.txt
index 29d0e42..29d0e42 100644
--- a/tests/markdown-test/literal-quotes.txt
+++ b/tests/basic/literal-quotes.txt
diff --git a/tests/markdown-test/markdown-documentation-basics.html b/tests/basic/markdown-documentation-basics.html
index 3bcaea9..fd2e687 100644
--- a/tests/markdown-test/markdown-documentation-basics.html
+++ b/tests/basic/markdown-documentation-basics.html
@@ -23,7 +23,7 @@ can <a href="/projects/markdown/basics.text">see the source for it by adding '.t
<p>A paragraph is simply one or more consecutive lines of text, separated
by one or more blank lines. (A blank line is any line that looks like a
blank line -- a line containing nothing spaces or tabs is considered
-blank.) Normal paragraphs should not be intended with spaces or tabs.</p>
+blank.) Normal paragraphs should not be indented with spaces or tabs.</p>
<p>Markdown offers two styles of headers: <em>Setext</em> and <em>atx</em>.
Setext-style headers for <code>&lt;h1&gt;</code> and <code>&lt;h2&gt;</code> are created by
"underlining" with equal signs (<code>=</code>) and hyphens (<code>-</code>), respectively.
@@ -94,7 +94,7 @@ Or, if you prefer, &lt;strong&gt;use two underscores instead&lt;/strong&gt;.&lt;
<h2>Lists</h2>
<p>Unordered (bulleted) lists use asterisks, pluses, and hyphens (<code>*</code>,
<code>+</code>, and <code>-</code>) as list markers. These three markers are
-interchangable; this:</p>
+interchangeable; this:</p>
<pre><code>* Candy.
* Gum.
* Booze.
@@ -211,7 +211,7 @@ it easy to use Markdown to write about HTML example code:</p>
<pre><code>I strongly recommend against using any `&lt;blink&gt;` tags.
I wish SmartyPants used named entities like `&amp;mdash;`
-instead of decimal-encoded entites like `&amp;#8212;`.
+instead of decimal-encoded entities like `&amp;#8212;`.
</code></pre>
<p>Output:</p>
<pre><code>&lt;p&gt;I strongly recommend against using any
@@ -219,7 +219,7 @@ instead of decimal-encoded entites like `&amp;#8212;`.
&lt;p&gt;I wish SmartyPants used named entities like
&lt;code&gt;&amp;amp;mdash;&lt;/code&gt; instead of decimal-encoded
-entites like &lt;code&gt;&amp;amp;#8212;&lt;/code&gt;.&lt;/p&gt;
+entities like &lt;code&gt;&amp;amp;#8212;&lt;/code&gt;.&lt;/p&gt;
</code></pre>
<p>To specify an entire block of pre-formatted code, indent every line of
the block by 4 spaces or 1 tab. Just like with code spans, <code>&amp;</code>, <code>&lt;</code>,
diff --git a/tests/markdown-test/markdown-documentation-basics.txt b/tests/basic/markdown-documentation-basics.txt
index 486055c..b0932f3 100644
--- a/tests/markdown-test/markdown-documentation-basics.txt
+++ b/tests/basic/markdown-documentation-basics.txt
@@ -37,7 +37,7 @@ can [see the source for it by adding '.text' to the URL] [src].
A paragraph is simply one or more consecutive lines of text, separated
by one or more blank lines. (A blank line is any line that looks like a
blank line -- a line containing nothing spaces or tabs is considered
-blank.) Normal paragraphs should not be intended with spaces or tabs.
+blank.) Normal paragraphs should not be indented with spaces or tabs.
Markdown offers two styles of headers: *Setext* and *atx*.
Setext-style headers for `<h1>` and `<h2>` are created by
@@ -123,7 +123,7 @@ Output:
Unordered (bulleted) lists use asterisks, pluses, and hyphens (`*`,
`+`, and `-`) as list markers. These three markers are
-interchangable; this:
+interchangeable; this:
* Candy.
* Gum.
@@ -270,7 +270,7 @@ it easy to use Markdown to write about HTML example code:
I strongly recommend against using any `<blink>` tags.
I wish SmartyPants used named entities like `&mdash;`
- instead of decimal-encoded entites like `&#8212;`.
+ instead of decimal-encoded entities like `&#8212;`.
Output:
@@ -279,7 +279,7 @@ Output:
<p>I wish SmartyPants used named entities like
<code>&amp;mdash;</code> instead of decimal-encoded
- entites like <code>&amp;#8212;</code>.</p>
+ entities like <code>&amp;#8212;</code>.</p>
To specify an entire block of pre-formatted code, indent every line of
diff --git a/tests/extensions-x-def_list/markdown-syntax.html b/tests/basic/markdown-syntax.html
index 2f63b4b..cd7ba17 100644
--- a/tests/extensions-x-def_list/markdown-syntax.html
+++ b/tests/basic/markdown-syntax.html
@@ -151,7 +151,7 @@ and <code>&amp;</code> in your example code needs to be escaped.)</p>
<p>A paragraph is simply one or more consecutive lines of text, separated
by one or more blank lines. (A blank line is any line that looks like a
blank line -- a line containing nothing but spaces or tabs is considered
-blank.) Normal paragraphs should not be intended with spaces or tabs.</p>
+blank.) Normal paragraphs should not be indented with spaces or tabs.</p>
<p>The implication of the "one or more consecutive lines of text" rule is
that Markdown supports "hard-wrapped" text paragraphs. This differs
significantly from most other text-to-HTML formatters (including Movable
@@ -241,7 +241,7 @@ Quote Level from the Text menu.</p>
<h3 id="list">Lists</h3>
<p>Markdown supports ordered (numbered) and unordered (bulleted) lists.</p>
-<p>Unordered lists use asterisks, pluses, and hyphens -- interchangably
+<p>Unordered lists use asterisks, pluses, and hyphens -- interchangeably
-- as list markers:</p>
<pre><code>* Red
* Green
@@ -328,7 +328,7 @@ items in <code>&lt;p&gt;</code> tags in the HTML output. For example, this input
&lt;/ul&gt;
</code></pre>
<p>List items may consist of multiple paragraphs. Each subsequent
-paragraph in a list item must be intended by either 4 spaces
+paragraph in a list item must be indented by either 4 spaces
or one tab:</p>
<pre><code>1. This is a list item with two paragraphs. Lorem ipsum dolor
sit amet, consectetuer adipiscing elit. Aliquam hendrerit
@@ -484,12 +484,12 @@ on a line by itself:</p>
<p>That is:</p>
<ul>
<li>Square brackets containing the link identifier (optionally
-indented from the left margin using up to three spaces);</li>
+ indented from the left margin using up to three spaces);</li>
<li>followed by a colon;</li>
<li>followed by one or more spaces (or tabs);</li>
<li>followed by the URL for the link;</li>
<li>optionally followed by a title attribute for the link, enclosed
-in double or single quotes.</li>
+ in double or single quotes.</li>
</ul>
<p>The link URL may, optionally, be surrounded by angle brackets:</p>
<pre><code>[id]: &lt;http://example.com/&gt; "Optional Title Here"
@@ -660,10 +660,10 @@ for links, allowing for two styles: <em>inline</em> and <em>reference</em>.</p>
<ul>
<li>An exclamation mark: <code>!</code>;</li>
<li>followed by a set of square brackets, containing the <code>alt</code>
-attribute text for the image;</li>
+ attribute text for the image;</li>
<li>followed by a set of parentheses, containing the URL or path to
-the image, and an optional <code>title</code> attribute enclosed in double
-or single quotes.</li>
+ the image, and an optional <code>title</code> attribute enclosed in double
+ or single quotes.</li>
</ul>
<p>Reference-style image syntax looks like this:</p>
<pre><code>![Alt text][id]
diff --git a/tests/extensions-x-def_list/markdown-syntax.txt b/tests/basic/markdown-syntax.txt
index dabd75c..38f6e78 100644
--- a/tests/extensions-x-def_list/markdown-syntax.txt
+++ b/tests/basic/markdown-syntax.txt
@@ -186,7 +186,7 @@ and `&` in your example code needs to be escaped.)
A paragraph is simply one or more consecutive lines of text, separated
by one or more blank lines. (A blank line is any line that looks like a
blank line -- a line containing nothing but spaces or tabs is considered
-blank.) Normal paragraphs should not be intended with spaces or tabs.
+blank.) Normal paragraphs should not be indented with spaces or tabs.
The implication of the "one or more consecutive lines of text" rule is
that Markdown supports "hard-wrapped" text paragraphs. This differs
@@ -298,7 +298,7 @@ Quote Level from the Text menu.
Markdown supports ordered (numbered) and unordered (bulleted) lists.
-Unordered lists use asterisks, pluses, and hyphens -- interchangably
+Unordered lists use asterisks, pluses, and hyphens -- interchangeably
-- as list markers:
* Red
@@ -401,7 +401,7 @@ will turn into:
</ul>
List items may consist of multiple paragraphs. Each subsequent
-paragraph in a list item must be intended by either 4 spaces
+paragraph in a list item must be indented by either 4 spaces
or one tab:
1. This is a list item with two paragraphs. Lorem ipsum dolor
diff --git a/tests/markdown-test/nested-blockquotes.html b/tests/basic/nested-blockquotes.html
index f1b017e..f1b017e 100644
--- a/tests/markdown-test/nested-blockquotes.html
+++ b/tests/basic/nested-blockquotes.html
diff --git a/tests/markdown-test/nested-blockquotes.txt b/tests/basic/nested-blockquotes.txt
index ed3c624..ed3c624 100644
--- a/tests/markdown-test/nested-blockquotes.txt
+++ b/tests/basic/nested-blockquotes.txt
diff --git a/tests/markdown-test/ordered-and-unordered-list.html b/tests/basic/ordered-and-unordered-list.html
index 090c43c..090c43c 100644
--- a/tests/markdown-test/ordered-and-unordered-list.html
+++ b/tests/basic/ordered-and-unordered-list.html
diff --git a/tests/markdown-test/ordered-and-unordered-list.txt b/tests/basic/ordered-and-unordered-list.txt
index 621db58..621db58 100644
--- a/tests/markdown-test/ordered-and-unordered-list.txt
+++ b/tests/basic/ordered-and-unordered-list.txt
diff --git a/tests/markdown-test/strong-and-em-together.html b/tests/basic/strong-and-em-together.html
index 7bf5163..7bf5163 100644
--- a/tests/markdown-test/strong-and-em-together.html
+++ b/tests/basic/strong-and-em-together.html
diff --git a/tests/markdown-test/strong-and-em-together.txt b/tests/basic/strong-and-em-together.txt
index 95ee690..95ee690 100644
--- a/tests/markdown-test/strong-and-em-together.txt
+++ b/tests/basic/strong-and-em-together.txt
diff --git a/tests/markdown-test/tabs.html b/tests/basic/tabs.html
index b26391b..3c11f14 100644
--- a/tests/markdown-test/tabs.html
+++ b/tests/basic/tabs.html
@@ -1,11 +1,11 @@
<ul>
<li>
<p>this is a list item
-indented with tabs</p>
+ indented with tabs</p>
</li>
<li>
<p>this is a list item
-indented with spaces</p>
+ indented with spaces</p>
</li>
</ul>
<p>Code:</p>
diff --git a/tests/markdown-test/tabs.txt b/tests/basic/tabs.txt
index 589d113..589d113 100644
--- a/tests/markdown-test/tabs.txt
+++ b/tests/basic/tabs.txt
diff --git a/tests/markdown-test/tidyness.html b/tests/basic/tidyness.html
index 52b2eaf..52b2eaf 100644
--- a/tests/markdown-test/tidyness.html
+++ b/tests/basic/tidyness.html
diff --git a/tests/markdown-test/tidyness.txt b/tests/basic/tidyness.txt
index 5f18b8d..5f18b8d 100644
--- a/tests/markdown-test/tidyness.txt
+++ b/tests/basic/tidyness.txt
diff --git a/tests/extensions-x-abbr/abbr.html b/tests/extensions-x-abbr/abbr.html
deleted file mode 100644
index 456524e..0000000
--- a/tests/extensions-x-abbr/abbr.html
+++ /dev/null
@@ -1,4 +0,0 @@
-<p>An <abbr title="Abbreviation">ABBR</abbr>: "<abbr title="Reference">REF</abbr>".
-ref and REFERENCE should be ignored.</p>
-<p>The <abbr title="Hyper Text Markup Language">HTML</abbr> specification
-is maintained by the <abbr title="World Wide Web Consortium">W3C</abbr>.</p> \ No newline at end of file
diff --git a/tests/extensions-x-abbr/abbr.txt b/tests/extensions-x-abbr/abbr.txt
deleted file mode 100644
index 991bf15..0000000
--- a/tests/extensions-x-abbr/abbr.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-An ABBR: "REF".
-ref and REFERENCE should be ignored.
-
-*[REF]: Reference
-*[ABBR]: This gets overriden by the next one.
-*[ABBR]: Abbreviation
-
-The HTML specification
-is maintained by the W3C.
-
-*[HTML]: Hyper Text Markup Language
-*[W3C]: World Wide Web Consortium
-
diff --git a/tests/extensions-x-footnotes/footnote.html b/tests/extensions-x-footnotes/footnote.html
deleted file mode 100644
index 6556dab..0000000
--- a/tests/extensions-x-footnotes/footnote.html
+++ /dev/null
@@ -1,29 +0,0 @@
-<p>This is the body with a footnote<sup id="fnref:1"><a href="#fn:1" rel="footnote">1</a></sup> or two<sup id="fnref:2"><a href="#fn:2" rel="footnote">2</a></sup> or more<sup id="fnref:3"><a href="#fn:3" rel="footnote">3</a></sup> <sup id="fnref:4"><a href="#fn:4" rel="footnote">4</a></sup>.</p>
-<div class="footnote">
-<hr />
-<ol>
-<li id="fn:1">
-<p>Footnote that ends with a list:</p>
-<ul>
-<li>item 1</li>
-<li>item 2</li>
-</ul>
-<p><a href="#fnref:1" rev="footnote" title="Jump back to footnote 1 in the text">&#8617;</a></p>
-</li>
-<li id="fn:2">
-<blockquote>
-<p>This footnote is a blockquote.
-</p>
-</blockquote>
-<p><a href="#fnref:2" rev="footnote" title="Jump back to footnote 2 in the text">&#8617;</a></p>
-</li>
-<li id="fn:3">
-<p>A simple oneliner.
-&#160;<a href="#fnref:3" rev="footnote" title="Jump back to footnote 3 in the text">&#8617;</a></p>
-</li>
-<li id="fn:4">
-<p>A footnote with multiple paragraphs.</p>
-<p>Paragraph two.&#160;<a href="#fnref:4" rev="footnote" title="Jump back to footnote 4 in the text">&#8617;</a></p>
-</li>
-</ol>
-</div> \ No newline at end of file
diff --git a/tests/extensions-x-footnotes/footnote.txt b/tests/extensions-x-footnotes/footnote.txt
deleted file mode 100644
index 07188d0..0000000
--- a/tests/extensions-x-footnotes/footnote.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-This is the body with a footnote[^1] or two[^2] or more[^3] [^4].
-
-[^1]: Footnote that ends with a list:
-
- * item 1
- * item 2
-
-[^2]: > This footnote is a blockquote.
-
-[^3]: A simple oneliner.
-
-[^4]: A footnote with multiple paragraphs.
-
- Paragraph two.
diff --git a/tests/extensions-x-footnotes/named_markers.html b/tests/extensions-x-footnotes/named_markers.html
deleted file mode 100644
index 6996b5f..0000000
--- a/tests/extensions-x-footnotes/named_markers.html
+++ /dev/null
@@ -1,24 +0,0 @@
-<p>This is the body with footnotes<sup id="fnref:foo"><a href="#fn:foo" rel="footnote">1</a></sup>
-that have named<sup id="fnref:bar"><a href="#fn:bar" rel="footnote">2</a></sup> markers and
-oddly<sup id="fnref:56"><a href="#fn:56" rel="footnote">3</a></sup> numbered<sup id="fnref:99"><a href="#fn:99" rel="footnote">4</a></sup> markers.</p>
-<div class="footnote">
-<hr />
-<ol>
-<li id="fn:foo">
-<p>Footnote marked <code>foo</code>.
-&#160;<a href="#fnref:foo" rev="footnote" title="Jump back to footnote 1 in the text">&#8617;</a></p>
-</li>
-<li id="fn:bar">
-<p>This one is marked <em>bar</em>.
-&#160;<a href="#fnref:bar" rev="footnote" title="Jump back to footnote 2 in the text">&#8617;</a></p>
-</li>
-<li id="fn:56">
-<p>A <strong>numbered</strong> footnote.
-&#160;<a href="#fnref:56" rev="footnote" title="Jump back to footnote 3 in the text">&#8617;</a></p>
-</li>
-<li id="fn:99">
-<p>The last one.
-&#160;<a href="#fnref:99" rev="footnote" title="Jump back to footnote 4 in the text">&#8617;</a></p>
-</li>
-</ol>
-</div> \ No newline at end of file
diff --git a/tests/extensions-x-tables/tables.html b/tests/extensions-x-tables/tables.html
deleted file mode 100644
index c931e6a..0000000
--- a/tests/extensions-x-tables/tables.html
+++ /dev/null
@@ -1,119 +0,0 @@
-<h2>Table Tests</h2>
-<table>
-<thead>
-<tr>
-<th>First Header</th>
-<th>Second Header</th>
-</tr>
-</thead>
-<tbody>
-<tr>
-<td>Content Cell</td>
-<td>Content Cell</td>
-</tr>
-<tr>
-<td>Content Cell</td>
-<td>Content Cell</td>
-</tr>
-</tbody>
-</table>
-<table>
-<thead>
-<tr>
-<th>First Header</th>
-<th>Second Header</th>
-</tr>
-</thead>
-<tbody>
-<tr>
-<td>Content Cell</td>
-<td>Content Cell</td>
-</tr>
-<tr>
-<td>Content Cell</td>
-<td>Content Cell</td>
-</tr>
-</tbody>
-</table>
-<table>
-<thead>
-<tr>
-<th>Item</th>
-<th align="right">Value</th>
-</tr>
-</thead>
-<tbody>
-<tr>
-<td>Computer</td>
-<td align="right">$1600</td>
-</tr>
-<tr>
-<td>Phone</td>
-<td align="right">$12</td>
-</tr>
-<tr>
-<td>Pipe</td>
-<td align="right">$1</td>
-</tr>
-</tbody>
-</table>
-<table>
-<thead>
-<tr>
-<th>Function name</th>
-<th>Description</th>
-</tr>
-</thead>
-<tbody>
-<tr>
-<td><code>help()</code></td>
-<td>Display the help window.</td>
-</tr>
-<tr>
-<td><code>destroy()</code></td>
-<td><strong>Destroy your computer!</strong></td>
-</tr>
-</tbody>
-</table>
-<table>
-<thead>
-<tr>
-<th align="left">foo</th>
-<th align="center">bar</th>
-<th align="right">baz</th>
-</tr>
-</thead>
-<tbody>
-<tr>
-<td align="left" />
-<td align="center">Q</td>
-<td align="right" />
-</tr>
-<tr>
-<td align="left">W</td>
-<td align="center" />
-<td align="right">W</td>
-</tr>
-</tbody>
-</table>
-<table>
-<thead>
-<tr>
-<th>foo</th>
-<th>bar</th>
-<th>baz</th>
-</tr>
-</thead>
-<tbody>
-<tr>
-<td />
-<td>Q</td>
-<td />
-</tr>
-<tr>
-<td>W</td>
-<td />
-<td>W</td>
-</tr>
-</tbody>
-</table> \ No newline at end of file
diff --git a/tests/extensions-x-tables/tables.txt b/tests/extensions-x-tables/tables.txt
deleted file mode 100644
index 64917ab..0000000
--- a/tests/extensions-x-tables/tables.txt
+++ /dev/null
@@ -1,34 +0,0 @@
-Table Tests
------------
-
-First Header | Second Header
-------------- | -------------
-Content Cell | Content Cell
-Content Cell | Content Cell
-
-| First Header | Second Header |
-| ------------- | ------------- |
-| Content Cell | Content Cell |
-| Content Cell | Content Cell |
-
-| Item | Value |
-| :-------- | -----:|
-| Computer | $1600 |
-| Phone | $12 |
-| Pipe | $1 |
-
-| Function name | Description |
-| ------------- | ------------------------------ |
-| `help()` | Display the help window. |
-| `destroy()` | **Destroy your computer!** |
-
-|foo|bar|baz|
-|:--|:-:|--:|
-| | Q | |
-|W | | W|
-
-foo|bar|baz
----|---|---
- | Q |
- W | | W
-
diff --git a/tests/extensions-x-toc/nested.html b/tests/extensions-x-toc/nested.html
deleted file mode 100644
index a8a1583..0000000
--- a/tests/extensions-x-toc/nested.html
+++ /dev/null
@@ -1,16 +0,0 @@
-<h1 id="header-a">Header A</h1>
-<h2 id="header-1">Header 1</h2>
-<h3 id="header-i">Header i</h3>
-<h1 id="header-b">Header B</h1>
-<div class="toc">
-<ul>
-<li><a href="#header-a">Header A</a><ul>
-<li><a href="#header-1">Header 1</a><ul>
-<li><a href="#header-i">Header i</a></li>
-</ul>
-</li>
-</ul>
-</li>
-<li><a href="#header-b">Header B</a></li>
-</ul>
-</div> \ No newline at end of file
diff --git a/tests/extensions-x-wikilinks/wikilinks.html b/tests/extensions-x-wikilinks/wikilinks.html
deleted file mode 100644
index 1a38535..0000000
--- a/tests/extensions-x-wikilinks/wikilinks.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<p>Some text with a <a class="wikilink" href="/WikiLink/">WikiLink</a>.</p>
-<p>A link with <a class="wikilink" href="/white_space_and_underscores/">white space and_underscores</a> and a empty one.</p>
-<p>And a <a href="http://example.com/RealLink">RealLink</a>.</p>
-<p><a href="http://example.com/And_A_AutoLink">http://example.com/And_A_AutoLink</a></p>
-<p>And a <a href="/MarkdownLink/" title="A MarkdownLink">MarkdownLink</a> for
-completeness.</p> \ No newline at end of file
diff --git a/tests/extensions/admonition.html b/tests/extensions/admonition.html
new file mode 100644
index 0000000..8812dcb
--- /dev/null
+++ b/tests/extensions/admonition.html
@@ -0,0 +1,48 @@
+<p>Some text</p>
+<div class="admonition note">
+<p class="admonition-title">Note</p>
+<p>A normal paragraph here</p>
+<ol>
+<li>first</li>
+<li>second</li>
+</ol>
+<blockquote>
+<p>Some important quote</p>
+<p>another paragraph in the quote</p>
+</blockquote>
+<pre><code>int main() {
+ // insert some code
+}
+</code></pre>
+</div>
+<p>More text and stuff.</p>
+<div class="admonition note">
+<p class="admonition-title">Did you know?</p>
+<p>You can customize the title of the admonition</p>
+</div>
+<p>Not part of an Admonition!</p>
+<div class="admonition mycustomcssclass">
+<p class="admonition-title">And now...</p>
+<p>For something completely different.</p>
+<p>You can also use a custom CSS class name.</p>
+</div>
+<div class="admonition class1 class2 class3">
+<p class="admonition-title">And now...</p>
+<p>For something completely different.</p>
+<p>Several class names can be separated by space chars.</p>
+</div>
+<div class="admonition note anotherclass">
+<p class="admonition-title">Note</p>
+<p>The default title is the capitalized first class name.</p>
+</div>
+<div class="admonition tip">
+<p>An explicitly empty string prevents the title from being rendered.</p>
+</div>
+<p>No body:</p>
+<div class="admonition note">
+<p class="admonition-title">Note</p>
+</div>
+<p>Extra whitespace after the title should not alter output:</p>
+<div class="admonition note">
+<p class="admonition-title">Note</p>
+</div> \ No newline at end of file
diff --git a/tests/extensions/admonition.txt b/tests/extensions/admonition.txt
new file mode 100644
index 0000000..03ff4e9
--- /dev/null
+++ b/tests/extensions/admonition.txt
@@ -0,0 +1,45 @@
+Some text
+
+!!! note
+ A normal paragraph here
+
+ 1. first
+ 2. second
+
+ > Some important quote
+
+ > another paragraph in the quote
+
+ int main() {
+ // insert some code
+ }
+
+More text and stuff.
+
+!!! Note "Did you know?"
+ You can customize the title of the admonition
+Not part of an Admonition!
+
+!!! mycustomcssclass "And now..."
+ For something completely different.
+
+ You can also use a custom CSS class name.
+
+!!! class1 class2 class3 "And now..."
+ For something completely different.
+
+ Several class names can be separated by space chars.
+
+!!! note anotherclass
+ The default title is the capitalized first class name.
+
+!!! tip ""
+ An explicitly empty string prevents the title from being rendered.
+
+No body:
+
+!!! note
+
+Extra whitespace after the title should not alter output:
+
+!!! note
diff --git a/tests/extensions/attr_list.html b/tests/extensions/attr_list.html
new file mode 100644
index 0000000..e7bfe0b
--- /dev/null
+++ b/tests/extensions/attr_list.html
@@ -0,0 +1,69 @@
+<h1 id="setext">This is a sextext header</h1>
+<p class="myclass" id="par1">A paragraph with some text.
+Line two of the paragraph.</p>
+<h2 class="someclass" id="sextext2">This is another</h2>
+<p>Test some <em class="inline">inline</em> text.
+A <a class="linkkyclass" href="http://example.com" title="A title.">link</a>
+And a <strong class="nest">nested <a class="linky2" href="http://example.com" title="Some title">link</a></strong></p>
+<h3 id="hash">This is a hash Header</h3>
+<p bar="b az" baz="blah blah" foo="foo" title="I wasn't kidding!">And now some random attributes.</p>
+<h3 id="hash2">No closing hash header</h3>
+<p class="foo bar addme" id="overridden">Now test overrides</p>
+<pre><code># A code block which contains attr_list syntax
+# This should be ignored.
+{: #someid .someclass }
+</code></pre>
+<h3 id="hash3">No colon for compatibility with Headerid ext</h3>
+<p id="the_end">Also a codespan: <code class="foo">{: .someclass}</code>.</p>
+<h3 _:="{:" id="hash5">Bad Syntax</h3>
+<ul>
+<li class="item">Item1</li>
+<li class="item">Item2<ul>
+<li class="subitem">Item2-1</li>
+</ul>
+</li>
+<li class="item"><em class="emph">Item3</em><ul>
+<li class="subitem"><em class="emph">Item3-1</em></li>
+</ul>
+</li>
+<li>Item4<ul>
+<li>Item4-1</li>
+</ul>
+</li>
+<li>Item5</li>
+</ul>
+<h1>And ordered lists <em class="inline">too</em></h1>
+<ol>
+<li class="item">Item1</li>
+<li class="item">Item2<ol>
+<li class="subitem">Item2-1</li>
+</ol>
+</li>
+<li class="item"><em class="emph">Item3</em><ol>
+<li class="subitem"><em class="emph">Item3-1</em></li>
+</ol>
+</li>
+<li>Item4<ol>
+<li>Item4-1</li>
+</ol>
+</li>
+<li>Item5</li>
+</ol>
+<h1 class="block">Definition <em>lists</em></h1>
+<dl>
+<dt class="term">DT1</dt>
+<dt class="term">DT2</dt>
+<dd class="def">Some dd</dd>
+<dd><em class="inline">dd</em></dd>
+<dt><em class="inline">DT3</em></dt>
+<dd>Some dd</dd>
+</dl>
+<h1>Bad attributes</h1>
+<p>Key without <em foo="foo">value</em></p>
+<p>Value without <em>key</em></p>
+<p>No <em>key or value</em></p>
+<p><em>Weirdness</em></p>
+<p><em>More weirdness</em></p>
+<p>This should not cause a <em foo="a">crash</em></p>
+<p>Attr_lists do not contain <em>newlines</em>{ foo=bar
+key=value }</p> \ No newline at end of file
diff --git a/tests/extensions/attr_list.txt b/tests/extensions/attr_list.txt
new file mode 100644
index 0000000..465ce4f
--- /dev/null
+++ b/tests/extensions/attr_list.txt
@@ -0,0 +1,94 @@
+This is a sextext header {: #setext}
+====================================
+
+A paragraph with some text.
+Line two of the paragraph.
+{: #par1 .myclass }
+
+This is another {: #sextext2 .someclass}
+----------------------------------------
+
+Test some _inline_{: .inline} text.
+A [link](http://example.com){: .linkkyclass title="A title."}
+And a __nested [link][]{: .linky2}__{: .nest}
+
+[link]: http://example.com "Some title"
+
+### This is a hash Header ### {: #hash}
+
+And now some random attributes.
+{:foo bar='b az' baz="blah blah" title="I wasn't kidding!" }
+
+### No closing hash header {: #hash2}
+
+Now test overrides
+{: #overrideme .andme id=overridden class='foo bar' .addme }
+
+ # A code block which contains attr_list syntax
+ # This should be ignored.
+ {: #someid .someclass }
+
+### No colon for compatibility with Headerid ext { #hash3 }
+
+Also a codespan: `{: .someclass}`{: .foo}.
+{: #the_end}
+
+### Bad Syntax { {: #hash5 }
+
+* Item1
+ {: .item }
+* Item2
+ {: .item }
+ * Item2-1
+ {: .subitem }
+* _Item3_{: .emph }
+ {: .item }
+ * _Item3-1_{: .emph }
+ {: .subitem }
+* Item4
+ * Item4-1
+* Item5
+
+# And ordered lists *too*{.inline}
+
+1. Item1
+ {: .item }
+2. Item2
+ {: .item }
+ 1. Item2-1
+ {: .subitem }
+3. _Item3_{: .emph }
+ {: .item }
+ 1. _Item3-1_{: .emph }
+ {: .subitem }
+4. Item4
+ 1. Item4-1
+5. Item5
+
+# Definition *lists* {.block}
+
+DT1 {.term}
+DT2 {.term}
+: Some dd
+ {.def}
+: *dd*{.inline}
+
+*DT3*{.inline}
+: Some dd
+
+# Bad attributes
+
+Key without *value*{ foo= }
+
+Value without *key*{ =bar }
+
+No *key or value*{ = }
+
+*Weirdness*{ == }
+
+*More weirdness*{ === }
+
+This should not cause a *crash*{ foo=a=b }
+
+Attr_lists do not contain *newlines*{ foo=bar
+key=value }
diff --git a/tests/extensions-x-codehilite/code.html b/tests/extensions/codehilite.html
index 6a8ee91..6a8ee91 100644
--- a/tests/extensions-x-codehilite/code.html
+++ b/tests/extensions/codehilite.html
diff --git a/tests/extensions-x-codehilite/code.txt b/tests/extensions/codehilite.txt
index 6c62e6a..6c62e6a 100644
--- a/tests/extensions-x-codehilite/code.txt
+++ b/tests/extensions/codehilite.txt
diff --git a/tests/extensions/extra/def-in-list.html b/tests/extensions/extra/def-in-list.html
new file mode 100644
index 0000000..21cddaa
--- /dev/null
+++ b/tests/extensions/extra/def-in-list.html
@@ -0,0 +1,25 @@
+<p>: a paragraph that starts with a colon</p>
+<ul>
+<li>A List item</li>
+<li>
+<dl>
+<dt>A def term</dt>
+<dd>A def item</dd>
+<dd>a second</dd>
+</dl>
+</li>
+<li>
+<dl>
+<dt>Another def term</dt>
+<dd>
+<p>a loose item</p>
+</dd>
+<dd>
+<p>a second</p>
+</dd>
+</dl>
+</li>
+<li>
+<p>: a list item that starts with a colon</p>
+</li>
+</ul> \ No newline at end of file
diff --git a/tests/extensions/extra/def-in-list.txt b/tests/extensions/extra/def-in-list.txt
new file mode 100644
index 0000000..7a292ab
--- /dev/null
+++ b/tests/extensions/extra/def-in-list.txt
@@ -0,0 +1,15 @@
+: a paragraph that starts with a colon
+
+* A List item
+*
+ A def term
+ : A def item
+ : a second
+
+* Another def term
+
+ : a loose item
+
+ : a second
+
+* : a list item that starts with a colon
diff --git a/tests/extensions/extra/extra_config.html b/tests/extensions/extra/extra_config.html
new file mode 100644
index 0000000..cbad740
--- /dev/null
+++ b/tests/extensions/extra/extra_config.html
@@ -0,0 +1,9 @@
+<div class="footnote">
+<hr />
+<ol>
+<li id="fn:1">
+<p>A Footnote.&#160;<a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text">&#8617;</a></p>
+</li>
+</ol>
+</div>
+<p>Some text with a footnote<sup id="fnref:1"><a class="footnote-ref" href="#fn:1">1</a></sup>.</p> \ No newline at end of file
diff --git a/tests/extensions/extra/extra_config.txt b/tests/extensions/extra/extra_config.txt
new file mode 100644
index 0000000..2d29819
--- /dev/null
+++ b/tests/extensions/extra/extra_config.txt
@@ -0,0 +1,5 @@
+~~~placemarker~~~
+
+Some text with a footnote[^1].
+
+[^1]: A Footnote.
diff --git a/tests/extensions/extra/footnote.html b/tests/extensions/extra/footnote.html
new file mode 100644
index 0000000..4d86421
--- /dev/null
+++ b/tests/extensions/extra/footnote.html
@@ -0,0 +1,71 @@
+<p>This is the body with a footnote<sup id="fnref:1"><a class="footnote-ref" href="#fn:1">1</a></sup> or two<sup id="fnref:2"><a class="footnote-ref" href="#fn:2">2</a></sup> or more<sup id="fnref:3"><a class="footnote-ref" href="#fn:3">3</a></sup> <sup id="fnref:4"><a class="footnote-ref" href="#fn:4">4</a></sup> <sup id="fnref:5"><a class="footnote-ref" href="#fn:5">5</a></sup>.</p>
+<p>Also a reference that does not exist[^6].</p>
+<p>Duplicate<sup id="fnref:a"><a class="footnote-ref" href="#fn:a">6</a></sup> footnotes<sup id="fnref2:a"><a class="footnote-ref" href="#fn:a">6</a></sup> test<sup id="fnref3:a"><a class="footnote-ref" href="#fn:a">6</a></sup>.</p>
+<p>Duplicate<sup id="fnref:b"><a class="footnote-ref" href="#fn:b">7</a></sup> footnotes<sup id="fnref2:b"><a class="footnote-ref" href="#fn:b">7</a></sup> test<sup id="fnref3:b"><a class="footnote-ref" href="#fn:b">7</a></sup>.</p>
+<p>Single after duplicates<sup id="fnref:c"><a class="footnote-ref" href="#fn:c">8</a></sup>.</p>
+<p>Test emphasis at end of footnote<sup id="fnref:d"><a class="footnote-ref" href="#fn:d">9</a></sup></p>
+<p>Complex footnote content<sup id="fnref:e"><a class="footnote-ref" href="#fn:e">10</a></sup></p>
+<div class="footnote">
+<hr />
+<ol>
+<li id="fn:1">
+<p>Footnote that ends with a list:</p>
+<ul>
+<li>item 1</li>
+<li>item 2</li>
+</ul>
+<p><a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text">&#8617;</a></p>
+</li>
+<li id="fn:2">
+<blockquote>
+<p>This footnote is a blockquote.</p>
+</blockquote>
+<p><a class="footnote-backref" href="#fnref:2" title="Jump back to footnote 2 in the text">&#8617;</a></p>
+</li>
+<li id="fn:3">
+<p>A simple oneliner.&#160;<a class="footnote-backref" href="#fnref:3" title="Jump back to footnote 3 in the text">&#8617;</a></p>
+</li>
+<li id="fn:4">
+<p>A footnote with multiple paragraphs.</p>
+<p>Paragraph two.&#160;<a class="footnote-backref" href="#fnref:4" title="Jump back to footnote 4 in the text">&#8617;</a></p>
+</li>
+<li id="fn:5">
+<p>First line of first paragraph.
+Second line of first paragraph is not intended.
+Nor is third...&#160;<a class="footnote-backref" href="#fnref:5" title="Jump back to footnote 5 in the text">&#8617;</a></p>
+</li>
+<li id="fn:a">
+<p>1&#160;<a class="footnote-backref" href="#fnref:a" title="Jump back to footnote 6 in the text">&#8617;</a><a class="footnote-backref" href="#fnref2:a" title="Jump back to footnote 6 in the text">&#8617;</a><a class="footnote-backref" href="#fnref3:a" title="Jump back to footnote 6 in the text">&#8617;</a></p>
+</li>
+<li id="fn:b">
+<p>2&#160;<a class="footnote-backref" href="#fnref:b" title="Jump back to footnote 7 in the text">&#8617;</a><a class="footnote-backref" href="#fnref2:b" title="Jump back to footnote 7 in the text">&#8617;</a><a class="footnote-backref" href="#fnref3:b" title="Jump back to footnote 7 in the text">&#8617;</a></p>
+</li>
+<li id="fn:c">
+<p>3&#160;<a class="footnote-backref" href="#fnref:c" title="Jump back to footnote 8 in the text">&#8617;</a></p>
+</li>
+<li id="fn:d">
+<p><em>emphasis works</em></p>
+<p><em>emphasis still works</em>&#160;<a class="footnote-backref" href="#fnref:d" title="Jump back to footnote 9 in the text">&#8617;</a></p>
+</li>
+<li id="fn:e">
+<ol>
+<li>
+<p>The top couple half figure, contrary sides and hands across with bottom couple,</p>
+<p>Half figure back on your own sides, and turn partner to places,</p>
+<p>Swing partners with right hands into straight line long-ways, as in a reel, and</p>
+<p>Set,</p>
+<p>Hey and return to places,</p>
+<p>The other three couples do the same.</p>
+</li>
+<li>
+<p>Top and bottom couples meet and set,</p>
+<p>Then each gentleman leas the opposite lady to the couple on his left, and set,</p>
+<p>Aach four right and left,</p>
+<p>Swing side couples to places, and turn partners all eight,</p>
+<p>The other two couple o the same.</p>
+</li>
+</ol>
+<p><a class="footnote-backref" href="#fnref:e" title="Jump back to footnote 10 in the text">&#8617;</a></p>
+</li>
+</ol>
+</div> \ No newline at end of file
diff --git a/tests/extensions/extra/footnote.txt b/tests/extensions/extra/footnote.txt
new file mode 100644
index 0000000..93b5869
--- /dev/null
+++ b/tests/extensions/extra/footnote.txt
@@ -0,0 +1,62 @@
+This is the body with a footnote[^1] or two[^2] or more[^3] [^4] [^5].
+
+Also a reference that does not exist[^6].
+
+Duplicate[^a] footnotes[^a] test[^a].
+
+Duplicate[^b] footnotes[^b] test[^b].
+
+Single after duplicates[^c].
+
+Test emphasis at end of footnote[^d]
+
+Complex footnote content[^e]
+
+[^1]: Footnote that ends with a list:
+
+ * item 1
+ * item 2
+
+[^2]: > This footnote is a blockquote.
+
+[^3]: A simple oneliner.
+
+[^4]: A footnote with multiple paragraphs.
+
+ Paragraph two.
+
+[^5]: First line of first paragraph.
+Second line of first paragraph is not intended.
+Nor is third...
+
+[^a]: 1
+[^b]: 2
+[^c]: 3
+
+[^d]:
+ _emphasis works_
+
+ _emphasis still works_
+
+[^e]:
+ 1. The top couple half figure, contrary sides and hands across with bottom couple,
+
+ Half figure back on your own sides, and turn partner to places,
+
+ Swing partners with right hands into straight line long-ways, as in a reel, and
+
+ Set,
+
+ Hey and return to places,
+
+ The other three couples do the same.
+
+ 2. Top and bottom couples meet and set,
+
+ Then each gentleman leas the opposite lady to the couple on his left, and set,
+
+ Aach four right and left,
+
+ Swing side couples to places, and turn partners all eight,
+
+ The other two couple o the same.
diff --git a/tests/extensions/extra/footnote_many_footnotes.html b/tests/extensions/extra/footnote_many_footnotes.html
new file mode 100644
index 0000000..00de949
--- /dev/null
+++ b/tests/extensions/extra/footnote_many_footnotes.html
@@ -0,0 +1,4801 @@
+<p>Something<sup id="fnref:1"><a class="footnote-ref" href="#fn:1">1</a></sup></p>
+<p>Something<sup id="fnref:2"><a class="footnote-ref" href="#fn:2">2</a></sup></p>
+<p>Something<sup id="fnref:3"><a class="footnote-ref" href="#fn:3">3</a></sup></p>
+<p>Something<sup id="fnref:4"><a class="footnote-ref" href="#fn:4">4</a></sup></p>
+<p>Something<sup id="fnref:5"><a class="footnote-ref" href="#fn:5">5</a></sup></p>
+<p>Something<sup id="fnref:6"><a class="footnote-ref" href="#fn:6">6</a></sup></p>
+<p>Something<sup id="fnref:7"><a class="footnote-ref" href="#fn:7">7</a></sup></p>
+<p>Something<sup id="fnref:8"><a class="footnote-ref" href="#fn:8">8</a></sup></p>
+<p>Something<sup id="fnref:9"><a class="footnote-ref" href="#fn:9">9</a></sup></p>
+<p>Something<sup id="fnref:10"><a class="footnote-ref" href="#fn:10">10</a></sup></p>
+<p>Something<sup id="fnref:11"><a class="footnote-ref" href="#fn:11">11</a></sup></p>
+<p>Something<sup id="fnref:12"><a class="footnote-ref" href="#fn:12">12</a></sup></p>
+<p>Something<sup id="fnref:13"><a class="footnote-ref" href="#fn:13">13</a></sup></p>
+<p>Something<sup id="fnref:14"><a class="footnote-ref" href="#fn:14">14</a></sup></p>
+<p>Something<sup id="fnref:15"><a class="footnote-ref" href="#fn:15">15</a></sup></p>
+<p>Something<sup id="fnref:16"><a class="footnote-ref" href="#fn:16">16</a></sup></p>
+<p>Something<sup id="fnref:17"><a class="footnote-ref" href="#fn:17">17</a></sup></p>
+<p>Something<sup id="fnref:18"><a class="footnote-ref" href="#fn:18">18</a></sup></p>
+<p>Something<sup id="fnref:19"><a class="footnote-ref" href="#fn:19">19</a></sup></p>
+<p>Something<sup id="fnref:20"><a class="footnote-ref" href="#fn:20">20</a></sup></p>
+<p>Something<sup id="fnref:21"><a class="footnote-ref" href="#fn:21">21</a></sup></p>
+<p>Something<sup id="fnref:22"><a class="footnote-ref" href="#fn:22">22</a></sup></p>
+<p>Something<sup id="fnref:23"><a class="footnote-ref" href="#fn:23">23</a></sup></p>
+<p>Something<sup id="fnref:24"><a class="footnote-ref" href="#fn:24">24</a></sup></p>
+<p>Something<sup id="fnref:25"><a class="footnote-ref" href="#fn:25">25</a></sup></p>
+<p>Something<sup id="fnref:26"><a class="footnote-ref" href="#fn:26">26</a></sup></p>
+<p>Something<sup id="fnref:27"><a class="footnote-ref" href="#fn:27">27</a></sup></p>
+<p>Something<sup id="fnref:28"><a class="footnote-ref" href="#fn:28">28</a></sup></p>
+<p>Something<sup id="fnref:29"><a class="footnote-ref" href="#fn:29">29</a></sup></p>
+<p>Something<sup id="fnref:30"><a class="footnote-ref" href="#fn:30">30</a></sup></p>
+<p>Something<sup id="fnref:31"><a class="footnote-ref" href="#fn:31">31</a></sup></p>
+<p>Something<sup id="fnref:32"><a class="footnote-ref" href="#fn:32">32</a></sup></p>
+<p>Something<sup id="fnref:33"><a class="footnote-ref" href="#fn:33">33</a></sup></p>
+<p>Something<sup id="fnref:34"><a class="footnote-ref" href="#fn:34">34</a></sup></p>
+<p>Something<sup id="fnref:35"><a class="footnote-ref" href="#fn:35">35</a></sup></p>
+<p>Something<sup id="fnref:36"><a class="footnote-ref" href="#fn:36">36</a></sup></p>
+<p>Something<sup id="fnref:37"><a class="footnote-ref" href="#fn:37">37</a></sup></p>
+<p>Something<sup id="fnref:38"><a class="footnote-ref" href="#fn:38">38</a></sup></p>
+<p>Something<sup id="fnref:39"><a class="footnote-ref" href="#fn:39">39</a></sup></p>
+<p>Something<sup id="fnref:40"><a class="footnote-ref" href="#fn:40">40</a></sup></p>
+<p>Something<sup id="fnref:41"><a class="footnote-ref" href="#fn:41">41</a></sup></p>
+<p>Something<sup id="fnref:42"><a class="footnote-ref" href="#fn:42">42</a></sup></p>
+<p>Something<sup id="fnref:43"><a class="footnote-ref" href="#fn:43">43</a></sup></p>
+<p>Something<sup id="fnref:44"><a class="footnote-ref" href="#fn:44">44</a></sup></p>
+<p>Something<sup id="fnref:45"><a class="footnote-ref" href="#fn:45">45</a></sup></p>
+<p>Something<sup id="fnref:46"><a class="footnote-ref" href="#fn:46">46</a></sup></p>
+<p>Something<sup id="fnref:47"><a class="footnote-ref" href="#fn:47">47</a></sup></p>
+<p>Something<sup id="fnref:48"><a class="footnote-ref" href="#fn:48">48</a></sup></p>
+<p>Something<sup id="fnref:49"><a class="footnote-ref" href="#fn:49">49</a></sup></p>
+<p>Something<sup id="fnref:50"><a class="footnote-ref" href="#fn:50">50</a></sup></p>
+<p>Something<sup id="fnref:51"><a class="footnote-ref" href="#fn:51">51</a></sup></p>
+<p>Something<sup id="fnref:52"><a class="footnote-ref" href="#fn:52">52</a></sup></p>
+<p>Something<sup id="fnref:53"><a class="footnote-ref" href="#fn:53">53</a></sup></p>
+<p>Something<sup id="fnref:54"><a class="footnote-ref" href="#fn:54">54</a></sup></p>
+<p>Something<sup id="fnref:55"><a class="footnote-ref" href="#fn:55">55</a></sup></p>
+<p>Something<sup id="fnref:56"><a class="footnote-ref" href="#fn:56">56</a></sup></p>
+<p>Something<sup id="fnref:57"><a class="footnote-ref" href="#fn:57">57</a></sup></p>
+<p>Something<sup id="fnref:58"><a class="footnote-ref" href="#fn:58">58</a></sup></p>
+<p>Something<sup id="fnref:59"><a class="footnote-ref" href="#fn:59">59</a></sup></p>
+<p>Something<sup id="fnref:60"><a class="footnote-ref" href="#fn:60">60</a></sup></p>
+<p>Something<sup id="fnref:61"><a class="footnote-ref" href="#fn:61">61</a></sup></p>
+<p>Something<sup id="fnref:62"><a class="footnote-ref" href="#fn:62">62</a></sup></p>
+<p>Something<sup id="fnref:63"><a class="footnote-ref" href="#fn:63">63</a></sup></p>
+<p>Something<sup id="fnref:64"><a class="footnote-ref" href="#fn:64">64</a></sup></p>
+<p>Something<sup id="fnref:65"><a class="footnote-ref" href="#fn:65">65</a></sup></p>
+<p>Something<sup id="fnref:66"><a class="footnote-ref" href="#fn:66">66</a></sup></p>
+<p>Something<sup id="fnref:67"><a class="footnote-ref" href="#fn:67">67</a></sup></p>
+<p>Something<sup id="fnref:68"><a class="footnote-ref" href="#fn:68">68</a></sup></p>
+<p>Something<sup id="fnref:69"><a class="footnote-ref" href="#fn:69">69</a></sup></p>
+<p>Something<sup id="fnref:70"><a class="footnote-ref" href="#fn:70">70</a></sup></p>
+<p>Something<sup id="fnref:71"><a class="footnote-ref" href="#fn:71">71</a></sup></p>
+<p>Something<sup id="fnref:72"><a class="footnote-ref" href="#fn:72">72</a></sup></p>
+<p>Something<sup id="fnref:73"><a class="footnote-ref" href="#fn:73">73</a></sup></p>
+<p>Something<sup id="fnref:74"><a class="footnote-ref" href="#fn:74">74</a></sup></p>
+<p>Something<sup id="fnref:75"><a class="footnote-ref" href="#fn:75">75</a></sup></p>
+<p>Something<sup id="fnref:76"><a class="footnote-ref" href="#fn:76">76</a></sup></p>
+<p>Something<sup id="fnref:77"><a class="footnote-ref" href="#fn:77">77</a></sup></p>
+<p>Something<sup id="fnref:78"><a class="footnote-ref" href="#fn:78">78</a></sup></p>
+<p>Something<sup id="fnref:79"><a class="footnote-ref" href="#fn:79">79</a></sup></p>
+<p>Something<sup id="fnref:80"><a class="footnote-ref" href="#fn:80">80</a></sup></p>
+<p>Something<sup id="fnref:81"><a class="footnote-ref" href="#fn:81">81</a></sup></p>
+<p>Something<sup id="fnref:82"><a class="footnote-ref" href="#fn:82">82</a></sup></p>
+<p>Something<sup id="fnref:83"><a class="footnote-ref" href="#fn:83">83</a></sup></p>
+<p>Something<sup id="fnref:84"><a class="footnote-ref" href="#fn:84">84</a></sup></p>
+<p>Something<sup id="fnref:85"><a class="footnote-ref" href="#fn:85">85</a></sup></p>
+<p>Something<sup id="fnref:86"><a class="footnote-ref" href="#fn:86">86</a></sup></p>
+<p>Something<sup id="fnref:87"><a class="footnote-ref" href="#fn:87">87</a></sup></p>
+<p>Something<sup id="fnref:88"><a class="footnote-ref" href="#fn:88">88</a></sup></p>
+<p>Something<sup id="fnref:89"><a class="footnote-ref" href="#fn:89">89</a></sup></p>
+<p>Something<sup id="fnref:90"><a class="footnote-ref" href="#fn:90">90</a></sup></p>
+<p>Something<sup id="fnref:91"><a class="footnote-ref" href="#fn:91">91</a></sup></p>
+<p>Something<sup id="fnref:92"><a class="footnote-ref" href="#fn:92">92</a></sup></p>
+<p>Something<sup id="fnref:93"><a class="footnote-ref" href="#fn:93">93</a></sup></p>
+<p>Something<sup id="fnref:94"><a class="footnote-ref" href="#fn:94">94</a></sup></p>
+<p>Something<sup id="fnref:95"><a class="footnote-ref" href="#fn:95">95</a></sup></p>
+<p>Something<sup id="fnref:96"><a class="footnote-ref" href="#fn:96">96</a></sup></p>
+<p>Something<sup id="fnref:97"><a class="footnote-ref" href="#fn:97">97</a></sup></p>
+<p>Something<sup id="fnref:98"><a class="footnote-ref" href="#fn:98">98</a></sup></p>
+<p>Something<sup id="fnref:99"><a class="footnote-ref" href="#fn:99">99</a></sup></p>
+<p>Something<sup id="fnref:100"><a class="footnote-ref" href="#fn:100">100</a></sup></p>
+<p>Something<sup id="fnref:101"><a class="footnote-ref" href="#fn:101">101</a></sup></p>
+<p>Something<sup id="fnref:102"><a class="footnote-ref" href="#fn:102">102</a></sup></p>
+<p>Something<sup id="fnref:103"><a class="footnote-ref" href="#fn:103">103</a></sup></p>
+<p>Something<sup id="fnref:104"><a class="footnote-ref" href="#fn:104">104</a></sup></p>
+<p>Something<sup id="fnref:105"><a class="footnote-ref" href="#fn:105">105</a></sup></p>
+<p>Something<sup id="fnref:106"><a class="footnote-ref" href="#fn:106">106</a></sup></p>
+<p>Something<sup id="fnref:107"><a class="footnote-ref" href="#fn:107">107</a></sup></p>
+<p>Something<sup id="fnref:108"><a class="footnote-ref" href="#fn:108">108</a></sup></p>
+<p>Something<sup id="fnref:109"><a class="footnote-ref" href="#fn:109">109</a></sup></p>
+<p>Something<sup id="fnref:110"><a class="footnote-ref" href="#fn:110">110</a></sup></p>
+<p>Something<sup id="fnref:111"><a class="footnote-ref" href="#fn:111">111</a></sup></p>
+<p>Something<sup id="fnref:112"><a class="footnote-ref" href="#fn:112">112</a></sup></p>
+<p>Something<sup id="fnref:113"><a class="footnote-ref" href="#fn:113">113</a></sup></p>
+<p>Something<sup id="fnref:114"><a class="footnote-ref" href="#fn:114">114</a></sup></p>
+<p>Something<sup id="fnref:115"><a class="footnote-ref" href="#fn:115">115</a></sup></p>
+<p>Something<sup id="fnref:116"><a class="footnote-ref" href="#fn:116">116</a></sup></p>
+<p>Something<sup id="fnref:117"><a class="footnote-ref" href="#fn:117">117</a></sup></p>
+<p>Something<sup id="fnref:118"><a class="footnote-ref" href="#fn:118">118</a></sup></p>
+<p>Something<sup id="fnref:119"><a class="footnote-ref" href="#fn:119">119</a></sup></p>
+<p>Something<sup id="fnref:120"><a class="footnote-ref" href="#fn:120">120</a></sup></p>
+<p>Something<sup id="fnref:121"><a class="footnote-ref" href="#fn:121">121</a></sup></p>
+<p>Something<sup id="fnref:122"><a class="footnote-ref" href="#fn:122">122</a></sup></p>
+<p>Something<sup id="fnref:123"><a class="footnote-ref" href="#fn:123">123</a></sup></p>
+<p>Something<sup id="fnref:124"><a class="footnote-ref" href="#fn:124">124</a></sup></p>
+<p>Something<sup id="fnref:125"><a class="footnote-ref" href="#fn:125">125</a></sup></p>
+<p>Something<sup id="fnref:126"><a class="footnote-ref" href="#fn:126">126</a></sup></p>
+<p>Something<sup id="fnref:127"><a class="footnote-ref" href="#fn:127">127</a></sup></p>
+<p>Something<sup id="fnref:128"><a class="footnote-ref" href="#fn:128">128</a></sup></p>
+<p>Something<sup id="fnref:129"><a class="footnote-ref" href="#fn:129">129</a></sup></p>
+<p>Something<sup id="fnref:130"><a class="footnote-ref" href="#fn:130">130</a></sup></p>
+<p>Something<sup id="fnref:131"><a class="footnote-ref" href="#fn:131">131</a></sup></p>
+<p>Something<sup id="fnref:132"><a class="footnote-ref" href="#fn:132">132</a></sup></p>
+<p>Something<sup id="fnref:133"><a class="footnote-ref" href="#fn:133">133</a></sup></p>
+<p>Something<sup id="fnref:134"><a class="footnote-ref" href="#fn:134">134</a></sup></p>
+<p>Something<sup id="fnref:135"><a class="footnote-ref" href="#fn:135">135</a></sup></p>
+<p>Something<sup id="fnref:136"><a class="footnote-ref" href="#fn:136">136</a></sup></p>
+<p>Something<sup id="fnref:137"><a class="footnote-ref" href="#fn:137">137</a></sup></p>
+<p>Something<sup id="fnref:138"><a class="footnote-ref" href="#fn:138">138</a></sup></p>
+<p>Something<sup id="fnref:139"><a class="footnote-ref" href="#fn:139">139</a></sup></p>
+<p>Something<sup id="fnref:140"><a class="footnote-ref" href="#fn:140">140</a></sup></p>
+<p>Something<sup id="fnref:141"><a class="footnote-ref" href="#fn:141">141</a></sup></p>
+<p>Something<sup id="fnref:142"><a class="footnote-ref" href="#fn:142">142</a></sup></p>
+<p>Something<sup id="fnref:143"><a class="footnote-ref" href="#fn:143">143</a></sup></p>
+<p>Something<sup id="fnref:144"><a class="footnote-ref" href="#fn:144">144</a></sup></p>
+<p>Something<sup id="fnref:145"><a class="footnote-ref" href="#fn:145">145</a></sup></p>
+<p>Something<sup id="fnref:146"><a class="footnote-ref" href="#fn:146">146</a></sup></p>
+<p>Something<sup id="fnref:147"><a class="footnote-ref" href="#fn:147">147</a></sup></p>
+<p>Something<sup id="fnref:148"><a class="footnote-ref" href="#fn:148">148</a></sup></p>
+<p>Something<sup id="fnref:149"><a class="footnote-ref" href="#fn:149">149</a></sup></p>
+<p>Something<sup id="fnref:150"><a class="footnote-ref" href="#fn:150">150</a></sup></p>
+<p>Something<sup id="fnref:151"><a class="footnote-ref" href="#fn:151">151</a></sup></p>
+<p>Something<sup id="fnref:152"><a class="footnote-ref" href="#fn:152">152</a></sup></p>
+<p>Something<sup id="fnref:153"><a class="footnote-ref" href="#fn:153">153</a></sup></p>
+<p>Something<sup id="fnref:154"><a class="footnote-ref" href="#fn:154">154</a></sup></p>
+<p>Something<sup id="fnref:155"><a class="footnote-ref" href="#fn:155">155</a></sup></p>
+<p>Something<sup id="fnref:156"><a class="footnote-ref" href="#fn:156">156</a></sup></p>
+<p>Something<sup id="fnref:157"><a class="footnote-ref" href="#fn:157">157</a></sup></p>
+<p>Something<sup id="fnref:158"><a class="footnote-ref" href="#fn:158">158</a></sup></p>
+<p>Something<sup id="fnref:159"><a class="footnote-ref" href="#fn:159">159</a></sup></p>
+<p>Something<sup id="fnref:160"><a class="footnote-ref" href="#fn:160">160</a></sup></p>
+<p>Something<sup id="fnref:161"><a class="footnote-ref" href="#fn:161">161</a></sup></p>
+<p>Something<sup id="fnref:162"><a class="footnote-ref" href="#fn:162">162</a></sup></p>
+<p>Something<sup id="fnref:163"><a class="footnote-ref" href="#fn:163">163</a></sup></p>
+<p>Something<sup id="fnref:164"><a class="footnote-ref" href="#fn:164">164</a></sup></p>
+<p>Something<sup id="fnref:165"><a class="footnote-ref" href="#fn:165">165</a></sup></p>
+<p>Something<sup id="fnref:166"><a class="footnote-ref" href="#fn:166">166</a></sup></p>
+<p>Something<sup id="fnref:167"><a class="footnote-ref" href="#fn:167">167</a></sup></p>
+<p>Something<sup id="fnref:168"><a class="footnote-ref" href="#fn:168">168</a></sup></p>
+<p>Something<sup id="fnref:169"><a class="footnote-ref" href="#fn:169">169</a></sup></p>
+<p>Something<sup id="fnref:170"><a class="footnote-ref" href="#fn:170">170</a></sup></p>
+<p>Something<sup id="fnref:171"><a class="footnote-ref" href="#fn:171">171</a></sup></p>
+<p>Something<sup id="fnref:172"><a class="footnote-ref" href="#fn:172">172</a></sup></p>
+<p>Something<sup id="fnref:173"><a class="footnote-ref" href="#fn:173">173</a></sup></p>
+<p>Something<sup id="fnref:174"><a class="footnote-ref" href="#fn:174">174</a></sup></p>
+<p>Something<sup id="fnref:175"><a class="footnote-ref" href="#fn:175">175</a></sup></p>
+<p>Something<sup id="fnref:176"><a class="footnote-ref" href="#fn:176">176</a></sup></p>
+<p>Something<sup id="fnref:177"><a class="footnote-ref" href="#fn:177">177</a></sup></p>
+<p>Something<sup id="fnref:178"><a class="footnote-ref" href="#fn:178">178</a></sup></p>
+<p>Something<sup id="fnref:179"><a class="footnote-ref" href="#fn:179">179</a></sup></p>
+<p>Something<sup id="fnref:180"><a class="footnote-ref" href="#fn:180">180</a></sup></p>
+<p>Something<sup id="fnref:181"><a class="footnote-ref" href="#fn:181">181</a></sup></p>
+<p>Something<sup id="fnref:182"><a class="footnote-ref" href="#fn:182">182</a></sup></p>
+<p>Something<sup id="fnref:183"><a class="footnote-ref" href="#fn:183">183</a></sup></p>
+<p>Something<sup id="fnref:184"><a class="footnote-ref" href="#fn:184">184</a></sup></p>
+<p>Something<sup id="fnref:185"><a class="footnote-ref" href="#fn:185">185</a></sup></p>
+<p>Something<sup id="fnref:186"><a class="footnote-ref" href="#fn:186">186</a></sup></p>
+<p>Something<sup id="fnref:187"><a class="footnote-ref" href="#fn:187">187</a></sup></p>
+<p>Something<sup id="fnref:188"><a class="footnote-ref" href="#fn:188">188</a></sup></p>
+<p>Something<sup id="fnref:189"><a class="footnote-ref" href="#fn:189">189</a></sup></p>
+<p>Something<sup id="fnref:190"><a class="footnote-ref" href="#fn:190">190</a></sup></p>
+<p>Something<sup id="fnref:191"><a class="footnote-ref" href="#fn:191">191</a></sup></p>
+<p>Something<sup id="fnref:192"><a class="footnote-ref" href="#fn:192">192</a></sup></p>
+<p>Something<sup id="fnref:193"><a class="footnote-ref" href="#fn:193">193</a></sup></p>
+<p>Something<sup id="fnref:194"><a class="footnote-ref" href="#fn:194">194</a></sup></p>
+<p>Something<sup id="fnref:195"><a class="footnote-ref" href="#fn:195">195</a></sup></p>
+<p>Something<sup id="fnref:196"><a class="footnote-ref" href="#fn:196">196</a></sup></p>
+<p>Something<sup id="fnref:197"><a class="footnote-ref" href="#fn:197">197</a></sup></p>
+<p>Something<sup id="fnref:198"><a class="footnote-ref" href="#fn:198">198</a></sup></p>
+<p>Something<sup id="fnref:199"><a class="footnote-ref" href="#fn:199">199</a></sup></p>
+<p>Something<sup id="fnref:200"><a class="footnote-ref" href="#fn:200">200</a></sup></p>
+<p>Something<sup id="fnref:201"><a class="footnote-ref" href="#fn:201">201</a></sup></p>
+<p>Something<sup id="fnref:202"><a class="footnote-ref" href="#fn:202">202</a></sup></p>
+<p>Something<sup id="fnref:203"><a class="footnote-ref" href="#fn:203">203</a></sup></p>
+<p>Something<sup id="fnref:204"><a class="footnote-ref" href="#fn:204">204</a></sup></p>
+<p>Something<sup id="fnref:205"><a class="footnote-ref" href="#fn:205">205</a></sup></p>
+<p>Something<sup id="fnref:206"><a class="footnote-ref" href="#fn:206">206</a></sup></p>
+<p>Something<sup id="fnref:207"><a class="footnote-ref" href="#fn:207">207</a></sup></p>
+<p>Something<sup id="fnref:208"><a class="footnote-ref" href="#fn:208">208</a></sup></p>
+<p>Something<sup id="fnref:209"><a class="footnote-ref" href="#fn:209">209</a></sup></p>
+<p>Something<sup id="fnref:210"><a class="footnote-ref" href="#fn:210">210</a></sup></p>
+<p>Something<sup id="fnref:211"><a class="footnote-ref" href="#fn:211">211</a></sup></p>
+<p>Something<sup id="fnref:212"><a class="footnote-ref" href="#fn:212">212</a></sup></p>
+<p>Something<sup id="fnref:213"><a class="footnote-ref" href="#fn:213">213</a></sup></p>
+<p>Something<sup id="fnref:214"><a class="footnote-ref" href="#fn:214">214</a></sup></p>
+<p>Something<sup id="fnref:215"><a class="footnote-ref" href="#fn:215">215</a></sup></p>
+<p>Something<sup id="fnref:216"><a class="footnote-ref" href="#fn:216">216</a></sup></p>
+<p>Something<sup id="fnref:217"><a class="footnote-ref" href="#fn:217">217</a></sup></p>
+<p>Something<sup id="fnref:218"><a class="footnote-ref" href="#fn:218">218</a></sup></p>
+<p>Something<sup id="fnref:219"><a class="footnote-ref" href="#fn:219">219</a></sup></p>
+<p>Something<sup id="fnref:220"><a class="footnote-ref" href="#fn:220">220</a></sup></p>
+<p>Something<sup id="fnref:221"><a class="footnote-ref" href="#fn:221">221</a></sup></p>
+<p>Something<sup id="fnref:222"><a class="footnote-ref" href="#fn:222">222</a></sup></p>
+<p>Something<sup id="fnref:223"><a class="footnote-ref" href="#fn:223">223</a></sup></p>
+<p>Something<sup id="fnref:224"><a class="footnote-ref" href="#fn:224">224</a></sup></p>
+<p>Something<sup id="fnref:225"><a class="footnote-ref" href="#fn:225">225</a></sup></p>
+<p>Something<sup id="fnref:226"><a class="footnote-ref" href="#fn:226">226</a></sup></p>
+<p>Something<sup id="fnref:227"><a class="footnote-ref" href="#fn:227">227</a></sup></p>
+<p>Something<sup id="fnref:228"><a class="footnote-ref" href="#fn:228">228</a></sup></p>
+<p>Something<sup id="fnref:229"><a class="footnote-ref" href="#fn:229">229</a></sup></p>
+<p>Something<sup id="fnref:230"><a class="footnote-ref" href="#fn:230">230</a></sup></p>
+<p>Something<sup id="fnref:231"><a class="footnote-ref" href="#fn:231">231</a></sup></p>
+<p>Something<sup id="fnref:232"><a class="footnote-ref" href="#fn:232">232</a></sup></p>
+<p>Something<sup id="fnref:233"><a class="footnote-ref" href="#fn:233">233</a></sup></p>
+<p>Something<sup id="fnref:234"><a class="footnote-ref" href="#fn:234">234</a></sup></p>
+<p>Something<sup id="fnref:235"><a class="footnote-ref" href="#fn:235">235</a></sup></p>
+<p>Something<sup id="fnref:236"><a class="footnote-ref" href="#fn:236">236</a></sup></p>
+<p>Something<sup id="fnref:237"><a class="footnote-ref" href="#fn:237">237</a></sup></p>
+<p>Something<sup id="fnref:238"><a class="footnote-ref" href="#fn:238">238</a></sup></p>
+<p>Something<sup id="fnref:239"><a class="footnote-ref" href="#fn:239">239</a></sup></p>
+<p>Something<sup id="fnref:240"><a class="footnote-ref" href="#fn:240">240</a></sup></p>
+<p>Something<sup id="fnref:241"><a class="footnote-ref" href="#fn:241">241</a></sup></p>
+<p>Something<sup id="fnref:242"><a class="footnote-ref" href="#fn:242">242</a></sup></p>
+<p>Something<sup id="fnref:243"><a class="footnote-ref" href="#fn:243">243</a></sup></p>
+<p>Something<sup id="fnref:244"><a class="footnote-ref" href="#fn:244">244</a></sup></p>
+<p>Something<sup id="fnref:245"><a class="footnote-ref" href="#fn:245">245</a></sup></p>
+<p>Something<sup id="fnref:246"><a class="footnote-ref" href="#fn:246">246</a></sup></p>
+<p>Something<sup id="fnref:247"><a class="footnote-ref" href="#fn:247">247</a></sup></p>
+<p>Something<sup id="fnref:248"><a class="footnote-ref" href="#fn:248">248</a></sup></p>
+<p>Something<sup id="fnref:249"><a class="footnote-ref" href="#fn:249">249</a></sup></p>
+<p>Something<sup id="fnref:250"><a class="footnote-ref" href="#fn:250">250</a></sup></p>
+<p>Something<sup id="fnref:251"><a class="footnote-ref" href="#fn:251">251</a></sup></p>
+<p>Something<sup id="fnref:252"><a class="footnote-ref" href="#fn:252">252</a></sup></p>
+<p>Something<sup id="fnref:253"><a class="footnote-ref" href="#fn:253">253</a></sup></p>
+<p>Something<sup id="fnref:254"><a class="footnote-ref" href="#fn:254">254</a></sup></p>
+<p>Something<sup id="fnref:255"><a class="footnote-ref" href="#fn:255">255</a></sup></p>
+<p>Something<sup id="fnref:256"><a class="footnote-ref" href="#fn:256">256</a></sup></p>
+<p>Something<sup id="fnref:257"><a class="footnote-ref" href="#fn:257">257</a></sup></p>
+<p>Something<sup id="fnref:258"><a class="footnote-ref" href="#fn:258">258</a></sup></p>
+<p>Something<sup id="fnref:259"><a class="footnote-ref" href="#fn:259">259</a></sup></p>
+<p>Something<sup id="fnref:260"><a class="footnote-ref" href="#fn:260">260</a></sup></p>
+<p>Something<sup id="fnref:261"><a class="footnote-ref" href="#fn:261">261</a></sup></p>
+<p>Something<sup id="fnref:262"><a class="footnote-ref" href="#fn:262">262</a></sup></p>
+<p>Something<sup id="fnref:263"><a class="footnote-ref" href="#fn:263">263</a></sup></p>
+<p>Something<sup id="fnref:264"><a class="footnote-ref" href="#fn:264">264</a></sup></p>
+<p>Something<sup id="fnref:265"><a class="footnote-ref" href="#fn:265">265</a></sup></p>
+<p>Something<sup id="fnref:266"><a class="footnote-ref" href="#fn:266">266</a></sup></p>
+<p>Something<sup id="fnref:267"><a class="footnote-ref" href="#fn:267">267</a></sup></p>
+<p>Something<sup id="fnref:268"><a class="footnote-ref" href="#fn:268">268</a></sup></p>
+<p>Something<sup id="fnref:269"><a class="footnote-ref" href="#fn:269">269</a></sup></p>
+<p>Something<sup id="fnref:270"><a class="footnote-ref" href="#fn:270">270</a></sup></p>
+<p>Something<sup id="fnref:271"><a class="footnote-ref" href="#fn:271">271</a></sup></p>
+<p>Something<sup id="fnref:272"><a class="footnote-ref" href="#fn:272">272</a></sup></p>
+<p>Something<sup id="fnref:273"><a class="footnote-ref" href="#fn:273">273</a></sup></p>
+<p>Something<sup id="fnref:274"><a class="footnote-ref" href="#fn:274">274</a></sup></p>
+<p>Something<sup id="fnref:275"><a class="footnote-ref" href="#fn:275">275</a></sup></p>
+<p>Something<sup id="fnref:276"><a class="footnote-ref" href="#fn:276">276</a></sup></p>
+<p>Something<sup id="fnref:277"><a class="footnote-ref" href="#fn:277">277</a></sup></p>
+<p>Something<sup id="fnref:278"><a class="footnote-ref" href="#fn:278">278</a></sup></p>
+<p>Something<sup id="fnref:279"><a class="footnote-ref" href="#fn:279">279</a></sup></p>
+<p>Something<sup id="fnref:280"><a class="footnote-ref" href="#fn:280">280</a></sup></p>
+<p>Something<sup id="fnref:281"><a class="footnote-ref" href="#fn:281">281</a></sup></p>
+<p>Something<sup id="fnref:282"><a class="footnote-ref" href="#fn:282">282</a></sup></p>
+<p>Something<sup id="fnref:283"><a class="footnote-ref" href="#fn:283">283</a></sup></p>
+<p>Something<sup id="fnref:284"><a class="footnote-ref" href="#fn:284">284</a></sup></p>
+<p>Something<sup id="fnref:285"><a class="footnote-ref" href="#fn:285">285</a></sup></p>
+<p>Something<sup id="fnref:286"><a class="footnote-ref" href="#fn:286">286</a></sup></p>
+<p>Something<sup id="fnref:287"><a class="footnote-ref" href="#fn:287">287</a></sup></p>
+<p>Something<sup id="fnref:288"><a class="footnote-ref" href="#fn:288">288</a></sup></p>
+<p>Something<sup id="fnref:289"><a class="footnote-ref" href="#fn:289">289</a></sup></p>
+<p>Something<sup id="fnref:290"><a class="footnote-ref" href="#fn:290">290</a></sup></p>
+<p>Something<sup id="fnref:291"><a class="footnote-ref" href="#fn:291">291</a></sup></p>
+<p>Something<sup id="fnref:292"><a class="footnote-ref" href="#fn:292">292</a></sup></p>
+<p>Something<sup id="fnref:293"><a class="footnote-ref" href="#fn:293">293</a></sup></p>
+<p>Something<sup id="fnref:294"><a class="footnote-ref" href="#fn:294">294</a></sup></p>
+<p>Something<sup id="fnref:295"><a class="footnote-ref" href="#fn:295">295</a></sup></p>
+<p>Something<sup id="fnref:296"><a class="footnote-ref" href="#fn:296">296</a></sup></p>
+<p>Something<sup id="fnref:297"><a class="footnote-ref" href="#fn:297">297</a></sup></p>
+<p>Something<sup id="fnref:298"><a class="footnote-ref" href="#fn:298">298</a></sup></p>
+<p>Something<sup id="fnref:299"><a class="footnote-ref" href="#fn:299">299</a></sup></p>
+<p>Something<sup id="fnref:300"><a class="footnote-ref" href="#fn:300">300</a></sup></p>
+<p>Something<sup id="fnref:301"><a class="footnote-ref" href="#fn:301">301</a></sup></p>
+<p>Something<sup id="fnref:302"><a class="footnote-ref" href="#fn:302">302</a></sup></p>
+<p>Something<sup id="fnref:303"><a class="footnote-ref" href="#fn:303">303</a></sup></p>
+<p>Something<sup id="fnref:304"><a class="footnote-ref" href="#fn:304">304</a></sup></p>
+<p>Something<sup id="fnref:305"><a class="footnote-ref" href="#fn:305">305</a></sup></p>
+<p>Something<sup id="fnref:306"><a class="footnote-ref" href="#fn:306">306</a></sup></p>
+<p>Something<sup id="fnref:307"><a class="footnote-ref" href="#fn:307">307</a></sup></p>
+<p>Something<sup id="fnref:308"><a class="footnote-ref" href="#fn:308">308</a></sup></p>
+<p>Something<sup id="fnref:309"><a class="footnote-ref" href="#fn:309">309</a></sup></p>
+<p>Something<sup id="fnref:310"><a class="footnote-ref" href="#fn:310">310</a></sup></p>
+<p>Something<sup id="fnref:311"><a class="footnote-ref" href="#fn:311">311</a></sup></p>
+<p>Something<sup id="fnref:312"><a class="footnote-ref" href="#fn:312">312</a></sup></p>
+<p>Something<sup id="fnref:313"><a class="footnote-ref" href="#fn:313">313</a></sup></p>
+<p>Something<sup id="fnref:314"><a class="footnote-ref" href="#fn:314">314</a></sup></p>
+<p>Something<sup id="fnref:315"><a class="footnote-ref" href="#fn:315">315</a></sup></p>
+<p>Something<sup id="fnref:316"><a class="footnote-ref" href="#fn:316">316</a></sup></p>
+<p>Something<sup id="fnref:317"><a class="footnote-ref" href="#fn:317">317</a></sup></p>
+<p>Something<sup id="fnref:318"><a class="footnote-ref" href="#fn:318">318</a></sup></p>
+<p>Something<sup id="fnref:319"><a class="footnote-ref" href="#fn:319">319</a></sup></p>
+<p>Something<sup id="fnref:320"><a class="footnote-ref" href="#fn:320">320</a></sup></p>
+<p>Something<sup id="fnref:321"><a class="footnote-ref" href="#fn:321">321</a></sup></p>
+<p>Something<sup id="fnref:322"><a class="footnote-ref" href="#fn:322">322</a></sup></p>
+<p>Something<sup id="fnref:323"><a class="footnote-ref" href="#fn:323">323</a></sup></p>
+<p>Something<sup id="fnref:324"><a class="footnote-ref" href="#fn:324">324</a></sup></p>
+<p>Something<sup id="fnref:325"><a class="footnote-ref" href="#fn:325">325</a></sup></p>
+<p>Something<sup id="fnref:326"><a class="footnote-ref" href="#fn:326">326</a></sup></p>
+<p>Something<sup id="fnref:327"><a class="footnote-ref" href="#fn:327">327</a></sup></p>
+<p>Something<sup id="fnref:328"><a class="footnote-ref" href="#fn:328">328</a></sup></p>
+<p>Something<sup id="fnref:329"><a class="footnote-ref" href="#fn:329">329</a></sup></p>
+<p>Something<sup id="fnref:330"><a class="footnote-ref" href="#fn:330">330</a></sup></p>
+<p>Something<sup id="fnref:331"><a class="footnote-ref" href="#fn:331">331</a></sup></p>
+<p>Something<sup id="fnref:332"><a class="footnote-ref" href="#fn:332">332</a></sup></p>
+<p>Something<sup id="fnref:333"><a class="footnote-ref" href="#fn:333">333</a></sup></p>
+<p>Something<sup id="fnref:334"><a class="footnote-ref" href="#fn:334">334</a></sup></p>
+<p>Something<sup id="fnref:335"><a class="footnote-ref" href="#fn:335">335</a></sup></p>
+<p>Something<sup id="fnref:336"><a class="footnote-ref" href="#fn:336">336</a></sup></p>
+<p>Something<sup id="fnref:337"><a class="footnote-ref" href="#fn:337">337</a></sup></p>
+<p>Something<sup id="fnref:338"><a class="footnote-ref" href="#fn:338">338</a></sup></p>
+<p>Something<sup id="fnref:339"><a class="footnote-ref" href="#fn:339">339</a></sup></p>
+<p>Something<sup id="fnref:340"><a class="footnote-ref" href="#fn:340">340</a></sup></p>
+<p>Something<sup id="fnref:341"><a class="footnote-ref" href="#fn:341">341</a></sup></p>
+<p>Something<sup id="fnref:342"><a class="footnote-ref" href="#fn:342">342</a></sup></p>
+<p>Something<sup id="fnref:343"><a class="footnote-ref" href="#fn:343">343</a></sup></p>
+<p>Something<sup id="fnref:344"><a class="footnote-ref" href="#fn:344">344</a></sup></p>
+<p>Something<sup id="fnref:345"><a class="footnote-ref" href="#fn:345">345</a></sup></p>
+<p>Something<sup id="fnref:346"><a class="footnote-ref" href="#fn:346">346</a></sup></p>
+<p>Something<sup id="fnref:347"><a class="footnote-ref" href="#fn:347">347</a></sup></p>
+<p>Something<sup id="fnref:348"><a class="footnote-ref" href="#fn:348">348</a></sup></p>
+<p>Something<sup id="fnref:349"><a class="footnote-ref" href="#fn:349">349</a></sup></p>
+<p>Something<sup id="fnref:350"><a class="footnote-ref" href="#fn:350">350</a></sup></p>
+<p>Something<sup id="fnref:351"><a class="footnote-ref" href="#fn:351">351</a></sup></p>
+<p>Something<sup id="fnref:352"><a class="footnote-ref" href="#fn:352">352</a></sup></p>
+<p>Something<sup id="fnref:353"><a class="footnote-ref" href="#fn:353">353</a></sup></p>
+<p>Something<sup id="fnref:354"><a class="footnote-ref" href="#fn:354">354</a></sup></p>
+<p>Something<sup id="fnref:355"><a class="footnote-ref" href="#fn:355">355</a></sup></p>
+<p>Something<sup id="fnref:356"><a class="footnote-ref" href="#fn:356">356</a></sup></p>
+<p>Something<sup id="fnref:357"><a class="footnote-ref" href="#fn:357">357</a></sup></p>
+<p>Something<sup id="fnref:358"><a class="footnote-ref" href="#fn:358">358</a></sup></p>
+<p>Something<sup id="fnref:359"><a class="footnote-ref" href="#fn:359">359</a></sup></p>
+<p>Something<sup id="fnref:360"><a class="footnote-ref" href="#fn:360">360</a></sup></p>
+<p>Something<sup id="fnref:361"><a class="footnote-ref" href="#fn:361">361</a></sup></p>
+<p>Something<sup id="fnref:362"><a class="footnote-ref" href="#fn:362">362</a></sup></p>
+<p>Something<sup id="fnref:363"><a class="footnote-ref" href="#fn:363">363</a></sup></p>
+<p>Something<sup id="fnref:364"><a class="footnote-ref" href="#fn:364">364</a></sup></p>
+<p>Something<sup id="fnref:365"><a class="footnote-ref" href="#fn:365">365</a></sup></p>
+<p>Something<sup id="fnref:366"><a class="footnote-ref" href="#fn:366">366</a></sup></p>
+<p>Something<sup id="fnref:367"><a class="footnote-ref" href="#fn:367">367</a></sup></p>
+<p>Something<sup id="fnref:368"><a class="footnote-ref" href="#fn:368">368</a></sup></p>
+<p>Something<sup id="fnref:369"><a class="footnote-ref" href="#fn:369">369</a></sup></p>
+<p>Something<sup id="fnref:370"><a class="footnote-ref" href="#fn:370">370</a></sup></p>
+<p>Something<sup id="fnref:371"><a class="footnote-ref" href="#fn:371">371</a></sup></p>
+<p>Something<sup id="fnref:372"><a class="footnote-ref" href="#fn:372">372</a></sup></p>
+<p>Something<sup id="fnref:373"><a class="footnote-ref" href="#fn:373">373</a></sup></p>
+<p>Something<sup id="fnref:374"><a class="footnote-ref" href="#fn:374">374</a></sup></p>
+<p>Something<sup id="fnref:375"><a class="footnote-ref" href="#fn:375">375</a></sup></p>
+<p>Something<sup id="fnref:376"><a class="footnote-ref" href="#fn:376">376</a></sup></p>
+<p>Something<sup id="fnref:377"><a class="footnote-ref" href="#fn:377">377</a></sup></p>
+<p>Something<sup id="fnref:378"><a class="footnote-ref" href="#fn:378">378</a></sup></p>
+<p>Something<sup id="fnref:379"><a class="footnote-ref" href="#fn:379">379</a></sup></p>
+<p>Something<sup id="fnref:380"><a class="footnote-ref" href="#fn:380">380</a></sup></p>
+<p>Something<sup id="fnref:381"><a class="footnote-ref" href="#fn:381">381</a></sup></p>
+<p>Something<sup id="fnref:382"><a class="footnote-ref" href="#fn:382">382</a></sup></p>
+<p>Something<sup id="fnref:383"><a class="footnote-ref" href="#fn:383">383</a></sup></p>
+<p>Something<sup id="fnref:384"><a class="footnote-ref" href="#fn:384">384</a></sup></p>
+<p>Something<sup id="fnref:385"><a class="footnote-ref" href="#fn:385">385</a></sup></p>
+<p>Something<sup id="fnref:386"><a class="footnote-ref" href="#fn:386">386</a></sup></p>
+<p>Something<sup id="fnref:387"><a class="footnote-ref" href="#fn:387">387</a></sup></p>
+<p>Something<sup id="fnref:388"><a class="footnote-ref" href="#fn:388">388</a></sup></p>
+<p>Something<sup id="fnref:389"><a class="footnote-ref" href="#fn:389">389</a></sup></p>
+<p>Something<sup id="fnref:390"><a class="footnote-ref" href="#fn:390">390</a></sup></p>
+<p>Something<sup id="fnref:391"><a class="footnote-ref" href="#fn:391">391</a></sup></p>
+<p>Something<sup id="fnref:392"><a class="footnote-ref" href="#fn:392">392</a></sup></p>
+<p>Something<sup id="fnref:393"><a class="footnote-ref" href="#fn:393">393</a></sup></p>
+<p>Something<sup id="fnref:394"><a class="footnote-ref" href="#fn:394">394</a></sup></p>
+<p>Something<sup id="fnref:395"><a class="footnote-ref" href="#fn:395">395</a></sup></p>
+<p>Something<sup id="fnref:396"><a class="footnote-ref" href="#fn:396">396</a></sup></p>
+<p>Something<sup id="fnref:397"><a class="footnote-ref" href="#fn:397">397</a></sup></p>
+<p>Something<sup id="fnref:398"><a class="footnote-ref" href="#fn:398">398</a></sup></p>
+<p>Something<sup id="fnref:399"><a class="footnote-ref" href="#fn:399">399</a></sup></p>
+<p>Something<sup id="fnref:400"><a class="footnote-ref" href="#fn:400">400</a></sup></p>
+<p>Something<sup id="fnref:401"><a class="footnote-ref" href="#fn:401">401</a></sup></p>
+<p>Something<sup id="fnref:402"><a class="footnote-ref" href="#fn:402">402</a></sup></p>
+<p>Something<sup id="fnref:403"><a class="footnote-ref" href="#fn:403">403</a></sup></p>
+<p>Something<sup id="fnref:404"><a class="footnote-ref" href="#fn:404">404</a></sup></p>
+<p>Something<sup id="fnref:405"><a class="footnote-ref" href="#fn:405">405</a></sup></p>
+<p>Something<sup id="fnref:406"><a class="footnote-ref" href="#fn:406">406</a></sup></p>
+<p>Something<sup id="fnref:407"><a class="footnote-ref" href="#fn:407">407</a></sup></p>
+<p>Something<sup id="fnref:408"><a class="footnote-ref" href="#fn:408">408</a></sup></p>
+<p>Something<sup id="fnref:409"><a class="footnote-ref" href="#fn:409">409</a></sup></p>
+<p>Something<sup id="fnref:410"><a class="footnote-ref" href="#fn:410">410</a></sup></p>
+<p>Something<sup id="fnref:411"><a class="footnote-ref" href="#fn:411">411</a></sup></p>
+<p>Something<sup id="fnref:412"><a class="footnote-ref" href="#fn:412">412</a></sup></p>
+<p>Something<sup id="fnref:413"><a class="footnote-ref" href="#fn:413">413</a></sup></p>
+<p>Something<sup id="fnref:414"><a class="footnote-ref" href="#fn:414">414</a></sup></p>
+<p>Something<sup id="fnref:415"><a class="footnote-ref" href="#fn:415">415</a></sup></p>
+<p>Something<sup id="fnref:416"><a class="footnote-ref" href="#fn:416">416</a></sup></p>
+<p>Something<sup id="fnref:417"><a class="footnote-ref" href="#fn:417">417</a></sup></p>
+<p>Something<sup id="fnref:418"><a class="footnote-ref" href="#fn:418">418</a></sup></p>
+<p>Something<sup id="fnref:419"><a class="footnote-ref" href="#fn:419">419</a></sup></p>
+<p>Something<sup id="fnref:420"><a class="footnote-ref" href="#fn:420">420</a></sup></p>
+<p>Something<sup id="fnref:421"><a class="footnote-ref" href="#fn:421">421</a></sup></p>
+<p>Something<sup id="fnref:422"><a class="footnote-ref" href="#fn:422">422</a></sup></p>
+<p>Something<sup id="fnref:423"><a class="footnote-ref" href="#fn:423">423</a></sup></p>
+<p>Something<sup id="fnref:424"><a class="footnote-ref" href="#fn:424">424</a></sup></p>
+<p>Something<sup id="fnref:425"><a class="footnote-ref" href="#fn:425">425</a></sup></p>
+<p>Something<sup id="fnref:426"><a class="footnote-ref" href="#fn:426">426</a></sup></p>
+<p>Something<sup id="fnref:427"><a class="footnote-ref" href="#fn:427">427</a></sup></p>
+<p>Something<sup id="fnref:428"><a class="footnote-ref" href="#fn:428">428</a></sup></p>
+<p>Something<sup id="fnref:429"><a class="footnote-ref" href="#fn:429">429</a></sup></p>
+<p>Something<sup id="fnref:430"><a class="footnote-ref" href="#fn:430">430</a></sup></p>
+<p>Something<sup id="fnref:431"><a class="footnote-ref" href="#fn:431">431</a></sup></p>
+<p>Something<sup id="fnref:432"><a class="footnote-ref" href="#fn:432">432</a></sup></p>
+<p>Something<sup id="fnref:433"><a class="footnote-ref" href="#fn:433">433</a></sup></p>
+<p>Something<sup id="fnref:434"><a class="footnote-ref" href="#fn:434">434</a></sup></p>
+<p>Something<sup id="fnref:435"><a class="footnote-ref" href="#fn:435">435</a></sup></p>
+<p>Something<sup id="fnref:436"><a class="footnote-ref" href="#fn:436">436</a></sup></p>
+<p>Something<sup id="fnref:437"><a class="footnote-ref" href="#fn:437">437</a></sup></p>
+<p>Something<sup id="fnref:438"><a class="footnote-ref" href="#fn:438">438</a></sup></p>
+<p>Something<sup id="fnref:439"><a class="footnote-ref" href="#fn:439">439</a></sup></p>
+<p>Something<sup id="fnref:440"><a class="footnote-ref" href="#fn:440">440</a></sup></p>
+<p>Something<sup id="fnref:441"><a class="footnote-ref" href="#fn:441">441</a></sup></p>
+<p>Something<sup id="fnref:442"><a class="footnote-ref" href="#fn:442">442</a></sup></p>
+<p>Something<sup id="fnref:443"><a class="footnote-ref" href="#fn:443">443</a></sup></p>
+<p>Something<sup id="fnref:444"><a class="footnote-ref" href="#fn:444">444</a></sup></p>
+<p>Something<sup id="fnref:445"><a class="footnote-ref" href="#fn:445">445</a></sup></p>
+<p>Something<sup id="fnref:446"><a class="footnote-ref" href="#fn:446">446</a></sup></p>
+<p>Something<sup id="fnref:447"><a class="footnote-ref" href="#fn:447">447</a></sup></p>
+<p>Something<sup id="fnref:448"><a class="footnote-ref" href="#fn:448">448</a></sup></p>
+<p>Something<sup id="fnref:449"><a class="footnote-ref" href="#fn:449">449</a></sup></p>
+<p>Something<sup id="fnref:450"><a class="footnote-ref" href="#fn:450">450</a></sup></p>
+<p>Something<sup id="fnref:451"><a class="footnote-ref" href="#fn:451">451</a></sup></p>
+<p>Something<sup id="fnref:452"><a class="footnote-ref" href="#fn:452">452</a></sup></p>
+<p>Something<sup id="fnref:453"><a class="footnote-ref" href="#fn:453">453</a></sup></p>
+<p>Something<sup id="fnref:454"><a class="footnote-ref" href="#fn:454">454</a></sup></p>
+<p>Something<sup id="fnref:455"><a class="footnote-ref" href="#fn:455">455</a></sup></p>
+<p>Something<sup id="fnref:456"><a class="footnote-ref" href="#fn:456">456</a></sup></p>
+<p>Something<sup id="fnref:457"><a class="footnote-ref" href="#fn:457">457</a></sup></p>
+<p>Something<sup id="fnref:458"><a class="footnote-ref" href="#fn:458">458</a></sup></p>
+<p>Something<sup id="fnref:459"><a class="footnote-ref" href="#fn:459">459</a></sup></p>
+<p>Something<sup id="fnref:460"><a class="footnote-ref" href="#fn:460">460</a></sup></p>
+<p>Something<sup id="fnref:461"><a class="footnote-ref" href="#fn:461">461</a></sup></p>
+<p>Something<sup id="fnref:462"><a class="footnote-ref" href="#fn:462">462</a></sup></p>
+<p>Something<sup id="fnref:463"><a class="footnote-ref" href="#fn:463">463</a></sup></p>
+<p>Something<sup id="fnref:464"><a class="footnote-ref" href="#fn:464">464</a></sup></p>
+<p>Something<sup id="fnref:465"><a class="footnote-ref" href="#fn:465">465</a></sup></p>
+<p>Something<sup id="fnref:466"><a class="footnote-ref" href="#fn:466">466</a></sup></p>
+<p>Something<sup id="fnref:467"><a class="footnote-ref" href="#fn:467">467</a></sup></p>
+<p>Something<sup id="fnref:468"><a class="footnote-ref" href="#fn:468">468</a></sup></p>
+<p>Something<sup id="fnref:469"><a class="footnote-ref" href="#fn:469">469</a></sup></p>
+<p>Something<sup id="fnref:470"><a class="footnote-ref" href="#fn:470">470</a></sup></p>
+<p>Something<sup id="fnref:471"><a class="footnote-ref" href="#fn:471">471</a></sup></p>
+<p>Something<sup id="fnref:472"><a class="footnote-ref" href="#fn:472">472</a></sup></p>
+<p>Something<sup id="fnref:473"><a class="footnote-ref" href="#fn:473">473</a></sup></p>
+<p>Something<sup id="fnref:474"><a class="footnote-ref" href="#fn:474">474</a></sup></p>
+<p>Something<sup id="fnref:475"><a class="footnote-ref" href="#fn:475">475</a></sup></p>
+<p>Something<sup id="fnref:476"><a class="footnote-ref" href="#fn:476">476</a></sup></p>
+<p>Something<sup id="fnref:477"><a class="footnote-ref" href="#fn:477">477</a></sup></p>
+<p>Something<sup id="fnref:478"><a class="footnote-ref" href="#fn:478">478</a></sup></p>
+<p>Something<sup id="fnref:479"><a class="footnote-ref" href="#fn:479">479</a></sup></p>
+<p>Something<sup id="fnref:480"><a class="footnote-ref" href="#fn:480">480</a></sup></p>
+<p>Something<sup id="fnref:481"><a class="footnote-ref" href="#fn:481">481</a></sup></p>
+<p>Something<sup id="fnref:482"><a class="footnote-ref" href="#fn:482">482</a></sup></p>
+<p>Something<sup id="fnref:483"><a class="footnote-ref" href="#fn:483">483</a></sup></p>
+<p>Something<sup id="fnref:484"><a class="footnote-ref" href="#fn:484">484</a></sup></p>
+<p>Something<sup id="fnref:485"><a class="footnote-ref" href="#fn:485">485</a></sup></p>
+<p>Something<sup id="fnref:486"><a class="footnote-ref" href="#fn:486">486</a></sup></p>
+<p>Something<sup id="fnref:487"><a class="footnote-ref" href="#fn:487">487</a></sup></p>
+<p>Something<sup id="fnref:488"><a class="footnote-ref" href="#fn:488">488</a></sup></p>
+<p>Something<sup id="fnref:489"><a class="footnote-ref" href="#fn:489">489</a></sup></p>
+<p>Something<sup id="fnref:490"><a class="footnote-ref" href="#fn:490">490</a></sup></p>
+<p>Something<sup id="fnref:491"><a class="footnote-ref" href="#fn:491">491</a></sup></p>
+<p>Something<sup id="fnref:492"><a class="footnote-ref" href="#fn:492">492</a></sup></p>
+<p>Something<sup id="fnref:493"><a class="footnote-ref" href="#fn:493">493</a></sup></p>
+<p>Something<sup id="fnref:494"><a class="footnote-ref" href="#fn:494">494</a></sup></p>
+<p>Something<sup id="fnref:495"><a class="footnote-ref" href="#fn:495">495</a></sup></p>
+<p>Something<sup id="fnref:496"><a class="footnote-ref" href="#fn:496">496</a></sup></p>
+<p>Something<sup id="fnref:497"><a class="footnote-ref" href="#fn:497">497</a></sup></p>
+<p>Something<sup id="fnref:498"><a class="footnote-ref" href="#fn:498">498</a></sup></p>
+<p>Something<sup id="fnref:499"><a class="footnote-ref" href="#fn:499">499</a></sup></p>
+<p>Something<sup id="fnref:500"><a class="footnote-ref" href="#fn:500">500</a></sup></p>
+<p>Something<sup id="fnref:501"><a class="footnote-ref" href="#fn:501">501</a></sup></p>
+<p>Something<sup id="fnref:502"><a class="footnote-ref" href="#fn:502">502</a></sup></p>
+<p>Something<sup id="fnref:503"><a class="footnote-ref" href="#fn:503">503</a></sup></p>
+<p>Something<sup id="fnref:504"><a class="footnote-ref" href="#fn:504">504</a></sup></p>
+<p>Something<sup id="fnref:505"><a class="footnote-ref" href="#fn:505">505</a></sup></p>
+<p>Something<sup id="fnref:506"><a class="footnote-ref" href="#fn:506">506</a></sup></p>
+<p>Something<sup id="fnref:507"><a class="footnote-ref" href="#fn:507">507</a></sup></p>
+<p>Something<sup id="fnref:508"><a class="footnote-ref" href="#fn:508">508</a></sup></p>
+<p>Something<sup id="fnref:509"><a class="footnote-ref" href="#fn:509">509</a></sup></p>
+<p>Something<sup id="fnref:510"><a class="footnote-ref" href="#fn:510">510</a></sup></p>
+<p>Something<sup id="fnref:511"><a class="footnote-ref" href="#fn:511">511</a></sup></p>
+<p>Something<sup id="fnref:512"><a class="footnote-ref" href="#fn:512">512</a></sup></p>
+<p>Something<sup id="fnref:513"><a class="footnote-ref" href="#fn:513">513</a></sup></p>
+<p>Something<sup id="fnref:514"><a class="footnote-ref" href="#fn:514">514</a></sup></p>
+<p>Something<sup id="fnref:515"><a class="footnote-ref" href="#fn:515">515</a></sup></p>
+<p>Something<sup id="fnref:516"><a class="footnote-ref" href="#fn:516">516</a></sup></p>
+<p>Something<sup id="fnref:517"><a class="footnote-ref" href="#fn:517">517</a></sup></p>
+<p>Something<sup id="fnref:518"><a class="footnote-ref" href="#fn:518">518</a></sup></p>
+<p>Something<sup id="fnref:519"><a class="footnote-ref" href="#fn:519">519</a></sup></p>
+<p>Something<sup id="fnref:520"><a class="footnote-ref" href="#fn:520">520</a></sup></p>
+<p>Something<sup id="fnref:521"><a class="footnote-ref" href="#fn:521">521</a></sup></p>
+<p>Something<sup id="fnref:522"><a class="footnote-ref" href="#fn:522">522</a></sup></p>
+<p>Something<sup id="fnref:523"><a class="footnote-ref" href="#fn:523">523</a></sup></p>
+<p>Something<sup id="fnref:524"><a class="footnote-ref" href="#fn:524">524</a></sup></p>
+<p>Something<sup id="fnref:525"><a class="footnote-ref" href="#fn:525">525</a></sup></p>
+<p>Something<sup id="fnref:526"><a class="footnote-ref" href="#fn:526">526</a></sup></p>
+<p>Something<sup id="fnref:527"><a class="footnote-ref" href="#fn:527">527</a></sup></p>
+<p>Something<sup id="fnref:528"><a class="footnote-ref" href="#fn:528">528</a></sup></p>
+<p>Something<sup id="fnref:529"><a class="footnote-ref" href="#fn:529">529</a></sup></p>
+<p>Something<sup id="fnref:530"><a class="footnote-ref" href="#fn:530">530</a></sup></p>
+<p>Something<sup id="fnref:531"><a class="footnote-ref" href="#fn:531">531</a></sup></p>
+<p>Something<sup id="fnref:532"><a class="footnote-ref" href="#fn:532">532</a></sup></p>
+<p>Something<sup id="fnref:533"><a class="footnote-ref" href="#fn:533">533</a></sup></p>
+<p>Something<sup id="fnref:534"><a class="footnote-ref" href="#fn:534">534</a></sup></p>
+<p>Something<sup id="fnref:535"><a class="footnote-ref" href="#fn:535">535</a></sup></p>
+<p>Something<sup id="fnref:536"><a class="footnote-ref" href="#fn:536">536</a></sup></p>
+<p>Something<sup id="fnref:537"><a class="footnote-ref" href="#fn:537">537</a></sup></p>
+<p>Something<sup id="fnref:538"><a class="footnote-ref" href="#fn:538">538</a></sup></p>
+<p>Something<sup id="fnref:539"><a class="footnote-ref" href="#fn:539">539</a></sup></p>
+<p>Something<sup id="fnref:540"><a class="footnote-ref" href="#fn:540">540</a></sup></p>
+<p>Something<sup id="fnref:541"><a class="footnote-ref" href="#fn:541">541</a></sup></p>
+<p>Something<sup id="fnref:542"><a class="footnote-ref" href="#fn:542">542</a></sup></p>
+<p>Something<sup id="fnref:543"><a class="footnote-ref" href="#fn:543">543</a></sup></p>
+<p>Something<sup id="fnref:544"><a class="footnote-ref" href="#fn:544">544</a></sup></p>
+<p>Something<sup id="fnref:545"><a class="footnote-ref" href="#fn:545">545</a></sup></p>
+<p>Something<sup id="fnref:546"><a class="footnote-ref" href="#fn:546">546</a></sup></p>
+<p>Something<sup id="fnref:547"><a class="footnote-ref" href="#fn:547">547</a></sup></p>
+<p>Something<sup id="fnref:548"><a class="footnote-ref" href="#fn:548">548</a></sup></p>
+<p>Something<sup id="fnref:549"><a class="footnote-ref" href="#fn:549">549</a></sup></p>
+<p>Something<sup id="fnref:550"><a class="footnote-ref" href="#fn:550">550</a></sup></p>
+<p>Something<sup id="fnref:551"><a class="footnote-ref" href="#fn:551">551</a></sup></p>
+<p>Something<sup id="fnref:552"><a class="footnote-ref" href="#fn:552">552</a></sup></p>
+<p>Something<sup id="fnref:553"><a class="footnote-ref" href="#fn:553">553</a></sup></p>
+<p>Something<sup id="fnref:554"><a class="footnote-ref" href="#fn:554">554</a></sup></p>
+<p>Something<sup id="fnref:555"><a class="footnote-ref" href="#fn:555">555</a></sup></p>
+<p>Something<sup id="fnref:556"><a class="footnote-ref" href="#fn:556">556</a></sup></p>
+<p>Something<sup id="fnref:557"><a class="footnote-ref" href="#fn:557">557</a></sup></p>
+<p>Something<sup id="fnref:558"><a class="footnote-ref" href="#fn:558">558</a></sup></p>
+<p>Something<sup id="fnref:559"><a class="footnote-ref" href="#fn:559">559</a></sup></p>
+<p>Something<sup id="fnref:560"><a class="footnote-ref" href="#fn:560">560</a></sup></p>
+<p>Something<sup id="fnref:561"><a class="footnote-ref" href="#fn:561">561</a></sup></p>
+<p>Something<sup id="fnref:562"><a class="footnote-ref" href="#fn:562">562</a></sup></p>
+<p>Something<sup id="fnref:563"><a class="footnote-ref" href="#fn:563">563</a></sup></p>
+<p>Something<sup id="fnref:564"><a class="footnote-ref" href="#fn:564">564</a></sup></p>
+<p>Something<sup id="fnref:565"><a class="footnote-ref" href="#fn:565">565</a></sup></p>
+<p>Something<sup id="fnref:566"><a class="footnote-ref" href="#fn:566">566</a></sup></p>
+<p>Something<sup id="fnref:567"><a class="footnote-ref" href="#fn:567">567</a></sup></p>
+<p>Something<sup id="fnref:568"><a class="footnote-ref" href="#fn:568">568</a></sup></p>
+<p>Something<sup id="fnref:569"><a class="footnote-ref" href="#fn:569">569</a></sup></p>
+<p>Something<sup id="fnref:570"><a class="footnote-ref" href="#fn:570">570</a></sup></p>
+<p>Something<sup id="fnref:571"><a class="footnote-ref" href="#fn:571">571</a></sup></p>
+<p>Something<sup id="fnref:572"><a class="footnote-ref" href="#fn:572">572</a></sup></p>
+<p>Something<sup id="fnref:573"><a class="footnote-ref" href="#fn:573">573</a></sup></p>
+<p>Something<sup id="fnref:574"><a class="footnote-ref" href="#fn:574">574</a></sup></p>
+<p>Something<sup id="fnref:575"><a class="footnote-ref" href="#fn:575">575</a></sup></p>
+<p>Something<sup id="fnref:576"><a class="footnote-ref" href="#fn:576">576</a></sup></p>
+<p>Something<sup id="fnref:577"><a class="footnote-ref" href="#fn:577">577</a></sup></p>
+<p>Something<sup id="fnref:578"><a class="footnote-ref" href="#fn:578">578</a></sup></p>
+<p>Something<sup id="fnref:579"><a class="footnote-ref" href="#fn:579">579</a></sup></p>
+<p>Something<sup id="fnref:580"><a class="footnote-ref" href="#fn:580">580</a></sup></p>
+<p>Something<sup id="fnref:581"><a class="footnote-ref" href="#fn:581">581</a></sup></p>
+<p>Something<sup id="fnref:582"><a class="footnote-ref" href="#fn:582">582</a></sup></p>
+<p>Something<sup id="fnref:583"><a class="footnote-ref" href="#fn:583">583</a></sup></p>
+<p>Something<sup id="fnref:584"><a class="footnote-ref" href="#fn:584">584</a></sup></p>
+<p>Something<sup id="fnref:585"><a class="footnote-ref" href="#fn:585">585</a></sup></p>
+<p>Something<sup id="fnref:586"><a class="footnote-ref" href="#fn:586">586</a></sup></p>
+<p>Something<sup id="fnref:587"><a class="footnote-ref" href="#fn:587">587</a></sup></p>
+<p>Something<sup id="fnref:588"><a class="footnote-ref" href="#fn:588">588</a></sup></p>
+<p>Something<sup id="fnref:589"><a class="footnote-ref" href="#fn:589">589</a></sup></p>
+<p>Something<sup id="fnref:590"><a class="footnote-ref" href="#fn:590">590</a></sup></p>
+<p>Something<sup id="fnref:591"><a class="footnote-ref" href="#fn:591">591</a></sup></p>
+<p>Something<sup id="fnref:592"><a class="footnote-ref" href="#fn:592">592</a></sup></p>
+<p>Something<sup id="fnref:593"><a class="footnote-ref" href="#fn:593">593</a></sup></p>
+<p>Something<sup id="fnref:594"><a class="footnote-ref" href="#fn:594">594</a></sup></p>
+<p>Something<sup id="fnref:595"><a class="footnote-ref" href="#fn:595">595</a></sup></p>
+<p>Something<sup id="fnref:596"><a class="footnote-ref" href="#fn:596">596</a></sup></p>
+<p>Something<sup id="fnref:597"><a class="footnote-ref" href="#fn:597">597</a></sup></p>
+<p>Something<sup id="fnref:598"><a class="footnote-ref" href="#fn:598">598</a></sup></p>
+<p>Something<sup id="fnref:599"><a class="footnote-ref" href="#fn:599">599</a></sup></p>
+<p>Something<sup id="fnref:600"><a class="footnote-ref" href="#fn:600">600</a></sup></p>
+<p>Something<sup id="fnref:601"><a class="footnote-ref" href="#fn:601">601</a></sup></p>
+<p>Something<sup id="fnref:602"><a class="footnote-ref" href="#fn:602">602</a></sup></p>
+<p>Something<sup id="fnref:603"><a class="footnote-ref" href="#fn:603">603</a></sup></p>
+<p>Something<sup id="fnref:604"><a class="footnote-ref" href="#fn:604">604</a></sup></p>
+<p>Something<sup id="fnref:605"><a class="footnote-ref" href="#fn:605">605</a></sup></p>
+<p>Something<sup id="fnref:606"><a class="footnote-ref" href="#fn:606">606</a></sup></p>
+<p>Something<sup id="fnref:607"><a class="footnote-ref" href="#fn:607">607</a></sup></p>
+<p>Something<sup id="fnref:608"><a class="footnote-ref" href="#fn:608">608</a></sup></p>
+<p>Something<sup id="fnref:609"><a class="footnote-ref" href="#fn:609">609</a></sup></p>
+<p>Something<sup id="fnref:610"><a class="footnote-ref" href="#fn:610">610</a></sup></p>
+<p>Something<sup id="fnref:611"><a class="footnote-ref" href="#fn:611">611</a></sup></p>
+<p>Something<sup id="fnref:612"><a class="footnote-ref" href="#fn:612">612</a></sup></p>
+<p>Something<sup id="fnref:613"><a class="footnote-ref" href="#fn:613">613</a></sup></p>
+<p>Something<sup id="fnref:614"><a class="footnote-ref" href="#fn:614">614</a></sup></p>
+<p>Something<sup id="fnref:615"><a class="footnote-ref" href="#fn:615">615</a></sup></p>
+<p>Something<sup id="fnref:616"><a class="footnote-ref" href="#fn:616">616</a></sup></p>
+<p>Something<sup id="fnref:617"><a class="footnote-ref" href="#fn:617">617</a></sup></p>
+<p>Something<sup id="fnref:618"><a class="footnote-ref" href="#fn:618">618</a></sup></p>
+<p>Something<sup id="fnref:619"><a class="footnote-ref" href="#fn:619">619</a></sup></p>
+<p>Something<sup id="fnref:620"><a class="footnote-ref" href="#fn:620">620</a></sup></p>
+<p>Something<sup id="fnref:621"><a class="footnote-ref" href="#fn:621">621</a></sup></p>
+<p>Something<sup id="fnref:622"><a class="footnote-ref" href="#fn:622">622</a></sup></p>
+<p>Something<sup id="fnref:623"><a class="footnote-ref" href="#fn:623">623</a></sup></p>
+<p>Something<sup id="fnref:624"><a class="footnote-ref" href="#fn:624">624</a></sup></p>
+<p>Something<sup id="fnref:625"><a class="footnote-ref" href="#fn:625">625</a></sup></p>
+<p>Something<sup id="fnref:626"><a class="footnote-ref" href="#fn:626">626</a></sup></p>
+<p>Something<sup id="fnref:627"><a class="footnote-ref" href="#fn:627">627</a></sup></p>
+<p>Something<sup id="fnref:628"><a class="footnote-ref" href="#fn:628">628</a></sup></p>
+<p>Something<sup id="fnref:629"><a class="footnote-ref" href="#fn:629">629</a></sup></p>
+<p>Something<sup id="fnref:630"><a class="footnote-ref" href="#fn:630">630</a></sup></p>
+<p>Something<sup id="fnref:631"><a class="footnote-ref" href="#fn:631">631</a></sup></p>
+<p>Something<sup id="fnref:632"><a class="footnote-ref" href="#fn:632">632</a></sup></p>
+<p>Something<sup id="fnref:633"><a class="footnote-ref" href="#fn:633">633</a></sup></p>
+<p>Something<sup id="fnref:634"><a class="footnote-ref" href="#fn:634">634</a></sup></p>
+<p>Something<sup id="fnref:635"><a class="footnote-ref" href="#fn:635">635</a></sup></p>
+<p>Something<sup id="fnref:636"><a class="footnote-ref" href="#fn:636">636</a></sup></p>
+<p>Something<sup id="fnref:637"><a class="footnote-ref" href="#fn:637">637</a></sup></p>
+<p>Something<sup id="fnref:638"><a class="footnote-ref" href="#fn:638">638</a></sup></p>
+<p>Something<sup id="fnref:639"><a class="footnote-ref" href="#fn:639">639</a></sup></p>
+<p>Something<sup id="fnref:640"><a class="footnote-ref" href="#fn:640">640</a></sup></p>
+<p>Something<sup id="fnref:641"><a class="footnote-ref" href="#fn:641">641</a></sup></p>
+<p>Something<sup id="fnref:642"><a class="footnote-ref" href="#fn:642">642</a></sup></p>
+<p>Something<sup id="fnref:643"><a class="footnote-ref" href="#fn:643">643</a></sup></p>
+<p>Something<sup id="fnref:644"><a class="footnote-ref" href="#fn:644">644</a></sup></p>
+<p>Something<sup id="fnref:645"><a class="footnote-ref" href="#fn:645">645</a></sup></p>
+<p>Something<sup id="fnref:646"><a class="footnote-ref" href="#fn:646">646</a></sup></p>
+<p>Something<sup id="fnref:647"><a class="footnote-ref" href="#fn:647">647</a></sup></p>
+<p>Something<sup id="fnref:648"><a class="footnote-ref" href="#fn:648">648</a></sup></p>
+<p>Something<sup id="fnref:649"><a class="footnote-ref" href="#fn:649">649</a></sup></p>
+<p>Something<sup id="fnref:650"><a class="footnote-ref" href="#fn:650">650</a></sup></p>
+<p>Something<sup id="fnref:651"><a class="footnote-ref" href="#fn:651">651</a></sup></p>
+<p>Something<sup id="fnref:652"><a class="footnote-ref" href="#fn:652">652</a></sup></p>
+<p>Something<sup id="fnref:653"><a class="footnote-ref" href="#fn:653">653</a></sup></p>
+<p>Something<sup id="fnref:654"><a class="footnote-ref" href="#fn:654">654</a></sup></p>
+<p>Something<sup id="fnref:655"><a class="footnote-ref" href="#fn:655">655</a></sup></p>
+<p>Something<sup id="fnref:656"><a class="footnote-ref" href="#fn:656">656</a></sup></p>
+<p>Something<sup id="fnref:657"><a class="footnote-ref" href="#fn:657">657</a></sup></p>
+<p>Something<sup id="fnref:658"><a class="footnote-ref" href="#fn:658">658</a></sup></p>
+<p>Something<sup id="fnref:659"><a class="footnote-ref" href="#fn:659">659</a></sup></p>
+<p>Something<sup id="fnref:660"><a class="footnote-ref" href="#fn:660">660</a></sup></p>
+<p>Something<sup id="fnref:661"><a class="footnote-ref" href="#fn:661">661</a></sup></p>
+<p>Something<sup id="fnref:662"><a class="footnote-ref" href="#fn:662">662</a></sup></p>
+<p>Something<sup id="fnref:663"><a class="footnote-ref" href="#fn:663">663</a></sup></p>
+<p>Something<sup id="fnref:664"><a class="footnote-ref" href="#fn:664">664</a></sup></p>
+<p>Something<sup id="fnref:665"><a class="footnote-ref" href="#fn:665">665</a></sup></p>
+<p>Something<sup id="fnref:666"><a class="footnote-ref" href="#fn:666">666</a></sup></p>
+<p>Something<sup id="fnref:667"><a class="footnote-ref" href="#fn:667">667</a></sup></p>
+<p>Something<sup id="fnref:668"><a class="footnote-ref" href="#fn:668">668</a></sup></p>
+<p>Something<sup id="fnref:669"><a class="footnote-ref" href="#fn:669">669</a></sup></p>
+<p>Something<sup id="fnref:670"><a class="footnote-ref" href="#fn:670">670</a></sup></p>
+<p>Something<sup id="fnref:671"><a class="footnote-ref" href="#fn:671">671</a></sup></p>
+<p>Something<sup id="fnref:672"><a class="footnote-ref" href="#fn:672">672</a></sup></p>
+<p>Something<sup id="fnref:673"><a class="footnote-ref" href="#fn:673">673</a></sup></p>
+<p>Something<sup id="fnref:674"><a class="footnote-ref" href="#fn:674">674</a></sup></p>
+<p>Something<sup id="fnref:675"><a class="footnote-ref" href="#fn:675">675</a></sup></p>
+<p>Something<sup id="fnref:676"><a class="footnote-ref" href="#fn:676">676</a></sup></p>
+<p>Something<sup id="fnref:677"><a class="footnote-ref" href="#fn:677">677</a></sup></p>
+<p>Something<sup id="fnref:678"><a class="footnote-ref" href="#fn:678">678</a></sup></p>
+<p>Something<sup id="fnref:679"><a class="footnote-ref" href="#fn:679">679</a></sup></p>
+<p>Something<sup id="fnref:680"><a class="footnote-ref" href="#fn:680">680</a></sup></p>
+<p>Something<sup id="fnref:681"><a class="footnote-ref" href="#fn:681">681</a></sup></p>
+<p>Something<sup id="fnref:682"><a class="footnote-ref" href="#fn:682">682</a></sup></p>
+<p>Something<sup id="fnref:683"><a class="footnote-ref" href="#fn:683">683</a></sup></p>
+<p>Something<sup id="fnref:684"><a class="footnote-ref" href="#fn:684">684</a></sup></p>
+<p>Something<sup id="fnref:685"><a class="footnote-ref" href="#fn:685">685</a></sup></p>
+<p>Something<sup id="fnref:686"><a class="footnote-ref" href="#fn:686">686</a></sup></p>
+<p>Something<sup id="fnref:687"><a class="footnote-ref" href="#fn:687">687</a></sup></p>
+<p>Something<sup id="fnref:688"><a class="footnote-ref" href="#fn:688">688</a></sup></p>
+<p>Something<sup id="fnref:689"><a class="footnote-ref" href="#fn:689">689</a></sup></p>
+<p>Something<sup id="fnref:690"><a class="footnote-ref" href="#fn:690">690</a></sup></p>
+<p>Something<sup id="fnref:691"><a class="footnote-ref" href="#fn:691">691</a></sup></p>
+<p>Something<sup id="fnref:692"><a class="footnote-ref" href="#fn:692">692</a></sup></p>
+<p>Something<sup id="fnref:693"><a class="footnote-ref" href="#fn:693">693</a></sup></p>
+<p>Something<sup id="fnref:694"><a class="footnote-ref" href="#fn:694">694</a></sup></p>
+<p>Something<sup id="fnref:695"><a class="footnote-ref" href="#fn:695">695</a></sup></p>
+<p>Something<sup id="fnref:696"><a class="footnote-ref" href="#fn:696">696</a></sup></p>
+<p>Something<sup id="fnref:697"><a class="footnote-ref" href="#fn:697">697</a></sup></p>
+<p>Something<sup id="fnref:698"><a class="footnote-ref" href="#fn:698">698</a></sup></p>
+<p>Something<sup id="fnref:699"><a class="footnote-ref" href="#fn:699">699</a></sup></p>
+<p>Something<sup id="fnref:700"><a class="footnote-ref" href="#fn:700">700</a></sup></p>
+<p>Something<sup id="fnref:701"><a class="footnote-ref" href="#fn:701">701</a></sup></p>
+<p>Something<sup id="fnref:702"><a class="footnote-ref" href="#fn:702">702</a></sup></p>
+<p>Something<sup id="fnref:703"><a class="footnote-ref" href="#fn:703">703</a></sup></p>
+<p>Something<sup id="fnref:704"><a class="footnote-ref" href="#fn:704">704</a></sup></p>
+<p>Something<sup id="fnref:705"><a class="footnote-ref" href="#fn:705">705</a></sup></p>
+<p>Something<sup id="fnref:706"><a class="footnote-ref" href="#fn:706">706</a></sup></p>
+<p>Something<sup id="fnref:707"><a class="footnote-ref" href="#fn:707">707</a></sup></p>
+<p>Something<sup id="fnref:708"><a class="footnote-ref" href="#fn:708">708</a></sup></p>
+<p>Something<sup id="fnref:709"><a class="footnote-ref" href="#fn:709">709</a></sup></p>
+<p>Something<sup id="fnref:710"><a class="footnote-ref" href="#fn:710">710</a></sup></p>
+<p>Something<sup id="fnref:711"><a class="footnote-ref" href="#fn:711">711</a></sup></p>
+<p>Something<sup id="fnref:712"><a class="footnote-ref" href="#fn:712">712</a></sup></p>
+<p>Something<sup id="fnref:713"><a class="footnote-ref" href="#fn:713">713</a></sup></p>
+<p>Something<sup id="fnref:714"><a class="footnote-ref" href="#fn:714">714</a></sup></p>
+<p>Something<sup id="fnref:715"><a class="footnote-ref" href="#fn:715">715</a></sup></p>
+<p>Something<sup id="fnref:716"><a class="footnote-ref" href="#fn:716">716</a></sup></p>
+<p>Something<sup id="fnref:717"><a class="footnote-ref" href="#fn:717">717</a></sup></p>
+<p>Something<sup id="fnref:718"><a class="footnote-ref" href="#fn:718">718</a></sup></p>
+<p>Something<sup id="fnref:719"><a class="footnote-ref" href="#fn:719">719</a></sup></p>
+<p>Something<sup id="fnref:720"><a class="footnote-ref" href="#fn:720">720</a></sup></p>
+<p>Something<sup id="fnref:721"><a class="footnote-ref" href="#fn:721">721</a></sup></p>
+<p>Something<sup id="fnref:722"><a class="footnote-ref" href="#fn:722">722</a></sup></p>
+<p>Something<sup id="fnref:723"><a class="footnote-ref" href="#fn:723">723</a></sup></p>
+<p>Something<sup id="fnref:724"><a class="footnote-ref" href="#fn:724">724</a></sup></p>
+<p>Something<sup id="fnref:725"><a class="footnote-ref" href="#fn:725">725</a></sup></p>
+<p>Something<sup id="fnref:726"><a class="footnote-ref" href="#fn:726">726</a></sup></p>
+<p>Something<sup id="fnref:727"><a class="footnote-ref" href="#fn:727">727</a></sup></p>
+<p>Something<sup id="fnref:728"><a class="footnote-ref" href="#fn:728">728</a></sup></p>
+<p>Something<sup id="fnref:729"><a class="footnote-ref" href="#fn:729">729</a></sup></p>
+<p>Something<sup id="fnref:730"><a class="footnote-ref" href="#fn:730">730</a></sup></p>
+<p>Something<sup id="fnref:731"><a class="footnote-ref" href="#fn:731">731</a></sup></p>
+<p>Something<sup id="fnref:732"><a class="footnote-ref" href="#fn:732">732</a></sup></p>
+<p>Something<sup id="fnref:733"><a class="footnote-ref" href="#fn:733">733</a></sup></p>
+<p>Something<sup id="fnref:734"><a class="footnote-ref" href="#fn:734">734</a></sup></p>
+<p>Something<sup id="fnref:735"><a class="footnote-ref" href="#fn:735">735</a></sup></p>
+<p>Something<sup id="fnref:736"><a class="footnote-ref" href="#fn:736">736</a></sup></p>
+<p>Something<sup id="fnref:737"><a class="footnote-ref" href="#fn:737">737</a></sup></p>
+<p>Something<sup id="fnref:738"><a class="footnote-ref" href="#fn:738">738</a></sup></p>
+<p>Something<sup id="fnref:739"><a class="footnote-ref" href="#fn:739">739</a></sup></p>
+<p>Something<sup id="fnref:740"><a class="footnote-ref" href="#fn:740">740</a></sup></p>
+<p>Something<sup id="fnref:741"><a class="footnote-ref" href="#fn:741">741</a></sup></p>
+<p>Something<sup id="fnref:742"><a class="footnote-ref" href="#fn:742">742</a></sup></p>
+<p>Something<sup id="fnref:743"><a class="footnote-ref" href="#fn:743">743</a></sup></p>
+<p>Something<sup id="fnref:744"><a class="footnote-ref" href="#fn:744">744</a></sup></p>
+<p>Something<sup id="fnref:745"><a class="footnote-ref" href="#fn:745">745</a></sup></p>
+<p>Something<sup id="fnref:746"><a class="footnote-ref" href="#fn:746">746</a></sup></p>
+<p>Something<sup id="fnref:747"><a class="footnote-ref" href="#fn:747">747</a></sup></p>
+<p>Something<sup id="fnref:748"><a class="footnote-ref" href="#fn:748">748</a></sup></p>
+<p>Something<sup id="fnref:749"><a class="footnote-ref" href="#fn:749">749</a></sup></p>
+<p>Something<sup id="fnref:750"><a class="footnote-ref" href="#fn:750">750</a></sup></p>
+<p>Something<sup id="fnref:751"><a class="footnote-ref" href="#fn:751">751</a></sup></p>
+<p>Something<sup id="fnref:752"><a class="footnote-ref" href="#fn:752">752</a></sup></p>
+<p>Something<sup id="fnref:753"><a class="footnote-ref" href="#fn:753">753</a></sup></p>
+<p>Something<sup id="fnref:754"><a class="footnote-ref" href="#fn:754">754</a></sup></p>
+<p>Something<sup id="fnref:755"><a class="footnote-ref" href="#fn:755">755</a></sup></p>
+<p>Something<sup id="fnref:756"><a class="footnote-ref" href="#fn:756">756</a></sup></p>
+<p>Something<sup id="fnref:757"><a class="footnote-ref" href="#fn:757">757</a></sup></p>
+<p>Something<sup id="fnref:758"><a class="footnote-ref" href="#fn:758">758</a></sup></p>
+<p>Something<sup id="fnref:759"><a class="footnote-ref" href="#fn:759">759</a></sup></p>
+<p>Something<sup id="fnref:760"><a class="footnote-ref" href="#fn:760">760</a></sup></p>
+<p>Something<sup id="fnref:761"><a class="footnote-ref" href="#fn:761">761</a></sup></p>
+<p>Something<sup id="fnref:762"><a class="footnote-ref" href="#fn:762">762</a></sup></p>
+<p>Something<sup id="fnref:763"><a class="footnote-ref" href="#fn:763">763</a></sup></p>
+<p>Something<sup id="fnref:764"><a class="footnote-ref" href="#fn:764">764</a></sup></p>
+<p>Something<sup id="fnref:765"><a class="footnote-ref" href="#fn:765">765</a></sup></p>
+<p>Something<sup id="fnref:766"><a class="footnote-ref" href="#fn:766">766</a></sup></p>
+<p>Something<sup id="fnref:767"><a class="footnote-ref" href="#fn:767">767</a></sup></p>
+<p>Something<sup id="fnref:768"><a class="footnote-ref" href="#fn:768">768</a></sup></p>
+<p>Something<sup id="fnref:769"><a class="footnote-ref" href="#fn:769">769</a></sup></p>
+<p>Something<sup id="fnref:770"><a class="footnote-ref" href="#fn:770">770</a></sup></p>
+<p>Something<sup id="fnref:771"><a class="footnote-ref" href="#fn:771">771</a></sup></p>
+<p>Something<sup id="fnref:772"><a class="footnote-ref" href="#fn:772">772</a></sup></p>
+<p>Something<sup id="fnref:773"><a class="footnote-ref" href="#fn:773">773</a></sup></p>
+<p>Something<sup id="fnref:774"><a class="footnote-ref" href="#fn:774">774</a></sup></p>
+<p>Something<sup id="fnref:775"><a class="footnote-ref" href="#fn:775">775</a></sup></p>
+<p>Something<sup id="fnref:776"><a class="footnote-ref" href="#fn:776">776</a></sup></p>
+<p>Something<sup id="fnref:777"><a class="footnote-ref" href="#fn:777">777</a></sup></p>
+<p>Something<sup id="fnref:778"><a class="footnote-ref" href="#fn:778">778</a></sup></p>
+<p>Something<sup id="fnref:779"><a class="footnote-ref" href="#fn:779">779</a></sup></p>
+<p>Something<sup id="fnref:780"><a class="footnote-ref" href="#fn:780">780</a></sup></p>
+<p>Something<sup id="fnref:781"><a class="footnote-ref" href="#fn:781">781</a></sup></p>
+<p>Something<sup id="fnref:782"><a class="footnote-ref" href="#fn:782">782</a></sup></p>
+<p>Something<sup id="fnref:783"><a class="footnote-ref" href="#fn:783">783</a></sup></p>
+<p>Something<sup id="fnref:784"><a class="footnote-ref" href="#fn:784">784</a></sup></p>
+<p>Something<sup id="fnref:785"><a class="footnote-ref" href="#fn:785">785</a></sup></p>
+<p>Something<sup id="fnref:786"><a class="footnote-ref" href="#fn:786">786</a></sup></p>
+<p>Something<sup id="fnref:787"><a class="footnote-ref" href="#fn:787">787</a></sup></p>
+<p>Something<sup id="fnref:788"><a class="footnote-ref" href="#fn:788">788</a></sup></p>
+<p>Something<sup id="fnref:789"><a class="footnote-ref" href="#fn:789">789</a></sup></p>
+<p>Something<sup id="fnref:790"><a class="footnote-ref" href="#fn:790">790</a></sup></p>
+<p>Something<sup id="fnref:791"><a class="footnote-ref" href="#fn:791">791</a></sup></p>
+<p>Something<sup id="fnref:792"><a class="footnote-ref" href="#fn:792">792</a></sup></p>
+<p>Something<sup id="fnref:793"><a class="footnote-ref" href="#fn:793">793</a></sup></p>
+<p>Something<sup id="fnref:794"><a class="footnote-ref" href="#fn:794">794</a></sup></p>
+<p>Something<sup id="fnref:795"><a class="footnote-ref" href="#fn:795">795</a></sup></p>
+<p>Something<sup id="fnref:796"><a class="footnote-ref" href="#fn:796">796</a></sup></p>
+<p>Something<sup id="fnref:797"><a class="footnote-ref" href="#fn:797">797</a></sup></p>
+<p>Something<sup id="fnref:798"><a class="footnote-ref" href="#fn:798">798</a></sup></p>
+<p>Something<sup id="fnref:799"><a class="footnote-ref" href="#fn:799">799</a></sup></p>
+<p>Something<sup id="fnref:800"><a class="footnote-ref" href="#fn:800">800</a></sup></p>
+<p>Something<sup id="fnref:801"><a class="footnote-ref" href="#fn:801">801</a></sup></p>
+<p>Something<sup id="fnref:802"><a class="footnote-ref" href="#fn:802">802</a></sup></p>
+<p>Something<sup id="fnref:803"><a class="footnote-ref" href="#fn:803">803</a></sup></p>
+<p>Something<sup id="fnref:804"><a class="footnote-ref" href="#fn:804">804</a></sup></p>
+<p>Something<sup id="fnref:805"><a class="footnote-ref" href="#fn:805">805</a></sup></p>
+<p>Something<sup id="fnref:806"><a class="footnote-ref" href="#fn:806">806</a></sup></p>
+<p>Something<sup id="fnref:807"><a class="footnote-ref" href="#fn:807">807</a></sup></p>
+<p>Something<sup id="fnref:808"><a class="footnote-ref" href="#fn:808">808</a></sup></p>
+<p>Something<sup id="fnref:809"><a class="footnote-ref" href="#fn:809">809</a></sup></p>
+<p>Something<sup id="fnref:810"><a class="footnote-ref" href="#fn:810">810</a></sup></p>
+<p>Something<sup id="fnref:811"><a class="footnote-ref" href="#fn:811">811</a></sup></p>
+<p>Something<sup id="fnref:812"><a class="footnote-ref" href="#fn:812">812</a></sup></p>
+<p>Something<sup id="fnref:813"><a class="footnote-ref" href="#fn:813">813</a></sup></p>
+<p>Something<sup id="fnref:814"><a class="footnote-ref" href="#fn:814">814</a></sup></p>
+<p>Something<sup id="fnref:815"><a class="footnote-ref" href="#fn:815">815</a></sup></p>
+<p>Something<sup id="fnref:816"><a class="footnote-ref" href="#fn:816">816</a></sup></p>
+<p>Something<sup id="fnref:817"><a class="footnote-ref" href="#fn:817">817</a></sup></p>
+<p>Something<sup id="fnref:818"><a class="footnote-ref" href="#fn:818">818</a></sup></p>
+<p>Something<sup id="fnref:819"><a class="footnote-ref" href="#fn:819">819</a></sup></p>
+<p>Something<sup id="fnref:820"><a class="footnote-ref" href="#fn:820">820</a></sup></p>
+<p>Something<sup id="fnref:821"><a class="footnote-ref" href="#fn:821">821</a></sup></p>
+<p>Something<sup id="fnref:822"><a class="footnote-ref" href="#fn:822">822</a></sup></p>
+<p>Something<sup id="fnref:823"><a class="footnote-ref" href="#fn:823">823</a></sup></p>
+<p>Something<sup id="fnref:824"><a class="footnote-ref" href="#fn:824">824</a></sup></p>
+<p>Something<sup id="fnref:825"><a class="footnote-ref" href="#fn:825">825</a></sup></p>
+<p>Something<sup id="fnref:826"><a class="footnote-ref" href="#fn:826">826</a></sup></p>
+<p>Something<sup id="fnref:827"><a class="footnote-ref" href="#fn:827">827</a></sup></p>
+<p>Something<sup id="fnref:828"><a class="footnote-ref" href="#fn:828">828</a></sup></p>
+<p>Something<sup id="fnref:829"><a class="footnote-ref" href="#fn:829">829</a></sup></p>
+<p>Something<sup id="fnref:830"><a class="footnote-ref" href="#fn:830">830</a></sup></p>
+<p>Something<sup id="fnref:831"><a class="footnote-ref" href="#fn:831">831</a></sup></p>
+<p>Something<sup id="fnref:832"><a class="footnote-ref" href="#fn:832">832</a></sup></p>
+<p>Something<sup id="fnref:833"><a class="footnote-ref" href="#fn:833">833</a></sup></p>
+<p>Something<sup id="fnref:834"><a class="footnote-ref" href="#fn:834">834</a></sup></p>
+<p>Something<sup id="fnref:835"><a class="footnote-ref" href="#fn:835">835</a></sup></p>
+<p>Something<sup id="fnref:836"><a class="footnote-ref" href="#fn:836">836</a></sup></p>
+<p>Something<sup id="fnref:837"><a class="footnote-ref" href="#fn:837">837</a></sup></p>
+<p>Something<sup id="fnref:838"><a class="footnote-ref" href="#fn:838">838</a></sup></p>
+<p>Something<sup id="fnref:839"><a class="footnote-ref" href="#fn:839">839</a></sup></p>
+<p>Something<sup id="fnref:840"><a class="footnote-ref" href="#fn:840">840</a></sup></p>
+<p>Something<sup id="fnref:841"><a class="footnote-ref" href="#fn:841">841</a></sup></p>
+<p>Something<sup id="fnref:842"><a class="footnote-ref" href="#fn:842">842</a></sup></p>
+<p>Something<sup id="fnref:843"><a class="footnote-ref" href="#fn:843">843</a></sup></p>
+<p>Something<sup id="fnref:844"><a class="footnote-ref" href="#fn:844">844</a></sup></p>
+<p>Something<sup id="fnref:845"><a class="footnote-ref" href="#fn:845">845</a></sup></p>
+<p>Something<sup id="fnref:846"><a class="footnote-ref" href="#fn:846">846</a></sup></p>
+<p>Something<sup id="fnref:847"><a class="footnote-ref" href="#fn:847">847</a></sup></p>
+<p>Something<sup id="fnref:848"><a class="footnote-ref" href="#fn:848">848</a></sup></p>
+<p>Something<sup id="fnref:849"><a class="footnote-ref" href="#fn:849">849</a></sup></p>
+<p>Something<sup id="fnref:850"><a class="footnote-ref" href="#fn:850">850</a></sup></p>
+<p>Something<sup id="fnref:851"><a class="footnote-ref" href="#fn:851">851</a></sup></p>
+<p>Something<sup id="fnref:852"><a class="footnote-ref" href="#fn:852">852</a></sup></p>
+<p>Something<sup id="fnref:853"><a class="footnote-ref" href="#fn:853">853</a></sup></p>
+<p>Something<sup id="fnref:854"><a class="footnote-ref" href="#fn:854">854</a></sup></p>
+<p>Something<sup id="fnref:855"><a class="footnote-ref" href="#fn:855">855</a></sup></p>
+<p>Something<sup id="fnref:856"><a class="footnote-ref" href="#fn:856">856</a></sup></p>
+<p>Something<sup id="fnref:857"><a class="footnote-ref" href="#fn:857">857</a></sup></p>
+<p>Something<sup id="fnref:858"><a class="footnote-ref" href="#fn:858">858</a></sup></p>
+<p>Something<sup id="fnref:859"><a class="footnote-ref" href="#fn:859">859</a></sup></p>
+<p>Something<sup id="fnref:860"><a class="footnote-ref" href="#fn:860">860</a></sup></p>
+<p>Something<sup id="fnref:861"><a class="footnote-ref" href="#fn:861">861</a></sup></p>
+<p>Something<sup id="fnref:862"><a class="footnote-ref" href="#fn:862">862</a></sup></p>
+<p>Something<sup id="fnref:863"><a class="footnote-ref" href="#fn:863">863</a></sup></p>
+<p>Something<sup id="fnref:864"><a class="footnote-ref" href="#fn:864">864</a></sup></p>
+<p>Something<sup id="fnref:865"><a class="footnote-ref" href="#fn:865">865</a></sup></p>
+<p>Something<sup id="fnref:866"><a class="footnote-ref" href="#fn:866">866</a></sup></p>
+<p>Something<sup id="fnref:867"><a class="footnote-ref" href="#fn:867">867</a></sup></p>
+<p>Something<sup id="fnref:868"><a class="footnote-ref" href="#fn:868">868</a></sup></p>
+<p>Something<sup id="fnref:869"><a class="footnote-ref" href="#fn:869">869</a></sup></p>
+<p>Something<sup id="fnref:870"><a class="footnote-ref" href="#fn:870">870</a></sup></p>
+<p>Something<sup id="fnref:871"><a class="footnote-ref" href="#fn:871">871</a></sup></p>
+<p>Something<sup id="fnref:872"><a class="footnote-ref" href="#fn:872">872</a></sup></p>
+<p>Something<sup id="fnref:873"><a class="footnote-ref" href="#fn:873">873</a></sup></p>
+<p>Something<sup id="fnref:874"><a class="footnote-ref" href="#fn:874">874</a></sup></p>
+<p>Something<sup id="fnref:875"><a class="footnote-ref" href="#fn:875">875</a></sup></p>
+<p>Something<sup id="fnref:876"><a class="footnote-ref" href="#fn:876">876</a></sup></p>
+<p>Something<sup id="fnref:877"><a class="footnote-ref" href="#fn:877">877</a></sup></p>
+<p>Something<sup id="fnref:878"><a class="footnote-ref" href="#fn:878">878</a></sup></p>
+<p>Something<sup id="fnref:879"><a class="footnote-ref" href="#fn:879">879</a></sup></p>
+<p>Something<sup id="fnref:880"><a class="footnote-ref" href="#fn:880">880</a></sup></p>
+<p>Something<sup id="fnref:881"><a class="footnote-ref" href="#fn:881">881</a></sup></p>
+<p>Something<sup id="fnref:882"><a class="footnote-ref" href="#fn:882">882</a></sup></p>
+<p>Something<sup id="fnref:883"><a class="footnote-ref" href="#fn:883">883</a></sup></p>
+<p>Something<sup id="fnref:884"><a class="footnote-ref" href="#fn:884">884</a></sup></p>
+<p>Something<sup id="fnref:885"><a class="footnote-ref" href="#fn:885">885</a></sup></p>
+<p>Something<sup id="fnref:886"><a class="footnote-ref" href="#fn:886">886</a></sup></p>
+<p>Something<sup id="fnref:887"><a class="footnote-ref" href="#fn:887">887</a></sup></p>
+<p>Something<sup id="fnref:888"><a class="footnote-ref" href="#fn:888">888</a></sup></p>
+<p>Something<sup id="fnref:889"><a class="footnote-ref" href="#fn:889">889</a></sup></p>
+<p>Something<sup id="fnref:890"><a class="footnote-ref" href="#fn:890">890</a></sup></p>
+<p>Something<sup id="fnref:891"><a class="footnote-ref" href="#fn:891">891</a></sup></p>
+<p>Something<sup id="fnref:892"><a class="footnote-ref" href="#fn:892">892</a></sup></p>
+<p>Something<sup id="fnref:893"><a class="footnote-ref" href="#fn:893">893</a></sup></p>
+<p>Something<sup id="fnref:894"><a class="footnote-ref" href="#fn:894">894</a></sup></p>
+<p>Something<sup id="fnref:895"><a class="footnote-ref" href="#fn:895">895</a></sup></p>
+<p>Something<sup id="fnref:896"><a class="footnote-ref" href="#fn:896">896</a></sup></p>
+<p>Something<sup id="fnref:897"><a class="footnote-ref" href="#fn:897">897</a></sup></p>
+<p>Something<sup id="fnref:898"><a class="footnote-ref" href="#fn:898">898</a></sup></p>
+<p>Something<sup id="fnref:899"><a class="footnote-ref" href="#fn:899">899</a></sup></p>
+<p>Something<sup id="fnref:900"><a class="footnote-ref" href="#fn:900">900</a></sup></p>
+<p>Something<sup id="fnref:901"><a class="footnote-ref" href="#fn:901">901</a></sup></p>
+<p>Something<sup id="fnref:902"><a class="footnote-ref" href="#fn:902">902</a></sup></p>
+<p>Something<sup id="fnref:903"><a class="footnote-ref" href="#fn:903">903</a></sup></p>
+<p>Something<sup id="fnref:904"><a class="footnote-ref" href="#fn:904">904</a></sup></p>
+<p>Something<sup id="fnref:905"><a class="footnote-ref" href="#fn:905">905</a></sup></p>
+<p>Something<sup id="fnref:906"><a class="footnote-ref" href="#fn:906">906</a></sup></p>
+<p>Something<sup id="fnref:907"><a class="footnote-ref" href="#fn:907">907</a></sup></p>
+<p>Something<sup id="fnref:908"><a class="footnote-ref" href="#fn:908">908</a></sup></p>
+<p>Something<sup id="fnref:909"><a class="footnote-ref" href="#fn:909">909</a></sup></p>
+<p>Something<sup id="fnref:910"><a class="footnote-ref" href="#fn:910">910</a></sup></p>
+<p>Something<sup id="fnref:911"><a class="footnote-ref" href="#fn:911">911</a></sup></p>
+<p>Something<sup id="fnref:912"><a class="footnote-ref" href="#fn:912">912</a></sup></p>
+<p>Something<sup id="fnref:913"><a class="footnote-ref" href="#fn:913">913</a></sup></p>
+<p>Something<sup id="fnref:914"><a class="footnote-ref" href="#fn:914">914</a></sup></p>
+<p>Something<sup id="fnref:915"><a class="footnote-ref" href="#fn:915">915</a></sup></p>
+<p>Something<sup id="fnref:916"><a class="footnote-ref" href="#fn:916">916</a></sup></p>
+<p>Something<sup id="fnref:917"><a class="footnote-ref" href="#fn:917">917</a></sup></p>
+<p>Something<sup id="fnref:918"><a class="footnote-ref" href="#fn:918">918</a></sup></p>
+<p>Something<sup id="fnref:919"><a class="footnote-ref" href="#fn:919">919</a></sup></p>
+<p>Something<sup id="fnref:920"><a class="footnote-ref" href="#fn:920">920</a></sup></p>
+<p>Something<sup id="fnref:921"><a class="footnote-ref" href="#fn:921">921</a></sup></p>
+<p>Something<sup id="fnref:922"><a class="footnote-ref" href="#fn:922">922</a></sup></p>
+<p>Something<sup id="fnref:923"><a class="footnote-ref" href="#fn:923">923</a></sup></p>
+<p>Something<sup id="fnref:924"><a class="footnote-ref" href="#fn:924">924</a></sup></p>
+<p>Something<sup id="fnref:925"><a class="footnote-ref" href="#fn:925">925</a></sup></p>
+<p>Something<sup id="fnref:926"><a class="footnote-ref" href="#fn:926">926</a></sup></p>
+<p>Something<sup id="fnref:927"><a class="footnote-ref" href="#fn:927">927</a></sup></p>
+<p>Something<sup id="fnref:928"><a class="footnote-ref" href="#fn:928">928</a></sup></p>
+<p>Something<sup id="fnref:929"><a class="footnote-ref" href="#fn:929">929</a></sup></p>
+<p>Something<sup id="fnref:930"><a class="footnote-ref" href="#fn:930">930</a></sup></p>
+<p>Something<sup id="fnref:931"><a class="footnote-ref" href="#fn:931">931</a></sup></p>
+<p>Something<sup id="fnref:932"><a class="footnote-ref" href="#fn:932">932</a></sup></p>
+<p>Something<sup id="fnref:933"><a class="footnote-ref" href="#fn:933">933</a></sup></p>
+<p>Something<sup id="fnref:934"><a class="footnote-ref" href="#fn:934">934</a></sup></p>
+<p>Something<sup id="fnref:935"><a class="footnote-ref" href="#fn:935">935</a></sup></p>
+<p>Something<sup id="fnref:936"><a class="footnote-ref" href="#fn:936">936</a></sup></p>
+<p>Something<sup id="fnref:937"><a class="footnote-ref" href="#fn:937">937</a></sup></p>
+<p>Something<sup id="fnref:938"><a class="footnote-ref" href="#fn:938">938</a></sup></p>
+<p>Something<sup id="fnref:939"><a class="footnote-ref" href="#fn:939">939</a></sup></p>
+<p>Something<sup id="fnref:940"><a class="footnote-ref" href="#fn:940">940</a></sup></p>
+<p>Something<sup id="fnref:941"><a class="footnote-ref" href="#fn:941">941</a></sup></p>
+<p>Something<sup id="fnref:942"><a class="footnote-ref" href="#fn:942">942</a></sup></p>
+<p>Something<sup id="fnref:943"><a class="footnote-ref" href="#fn:943">943</a></sup></p>
+<p>Something<sup id="fnref:944"><a class="footnote-ref" href="#fn:944">944</a></sup></p>
+<p>Something<sup id="fnref:945"><a class="footnote-ref" href="#fn:945">945</a></sup></p>
+<p>Something<sup id="fnref:946"><a class="footnote-ref" href="#fn:946">946</a></sup></p>
+<p>Something<sup id="fnref:947"><a class="footnote-ref" href="#fn:947">947</a></sup></p>
+<p>Something<sup id="fnref:948"><a class="footnote-ref" href="#fn:948">948</a></sup></p>
+<p>Something<sup id="fnref:949"><a class="footnote-ref" href="#fn:949">949</a></sup></p>
+<p>Something<sup id="fnref:950"><a class="footnote-ref" href="#fn:950">950</a></sup></p>
+<p>Something<sup id="fnref:951"><a class="footnote-ref" href="#fn:951">951</a></sup></p>
+<p>Something<sup id="fnref:952"><a class="footnote-ref" href="#fn:952">952</a></sup></p>
+<p>Something<sup id="fnref:953"><a class="footnote-ref" href="#fn:953">953</a></sup></p>
+<p>Something<sup id="fnref:954"><a class="footnote-ref" href="#fn:954">954</a></sup></p>
+<p>Something<sup id="fnref:955"><a class="footnote-ref" href="#fn:955">955</a></sup></p>
+<p>Something<sup id="fnref:956"><a class="footnote-ref" href="#fn:956">956</a></sup></p>
+<p>Something<sup id="fnref:957"><a class="footnote-ref" href="#fn:957">957</a></sup></p>
+<p>Something<sup id="fnref:958"><a class="footnote-ref" href="#fn:958">958</a></sup></p>
+<p>Something<sup id="fnref:959"><a class="footnote-ref" href="#fn:959">959</a></sup></p>
+<p>Something<sup id="fnref:960"><a class="footnote-ref" href="#fn:960">960</a></sup></p>
+<p>Something<sup id="fnref:961"><a class="footnote-ref" href="#fn:961">961</a></sup></p>
+<p>Something<sup id="fnref:962"><a class="footnote-ref" href="#fn:962">962</a></sup></p>
+<p>Something<sup id="fnref:963"><a class="footnote-ref" href="#fn:963">963</a></sup></p>
+<p>Something<sup id="fnref:964"><a class="footnote-ref" href="#fn:964">964</a></sup></p>
+<p>Something<sup id="fnref:965"><a class="footnote-ref" href="#fn:965">965</a></sup></p>
+<p>Something<sup id="fnref:966"><a class="footnote-ref" href="#fn:966">966</a></sup></p>
+<p>Something<sup id="fnref:967"><a class="footnote-ref" href="#fn:967">967</a></sup></p>
+<p>Something<sup id="fnref:968"><a class="footnote-ref" href="#fn:968">968</a></sup></p>
+<p>Something<sup id="fnref:969"><a class="footnote-ref" href="#fn:969">969</a></sup></p>
+<p>Something<sup id="fnref:970"><a class="footnote-ref" href="#fn:970">970</a></sup></p>
+<p>Something<sup id="fnref:971"><a class="footnote-ref" href="#fn:971">971</a></sup></p>
+<p>Something<sup id="fnref:972"><a class="footnote-ref" href="#fn:972">972</a></sup></p>
+<p>Something<sup id="fnref:973"><a class="footnote-ref" href="#fn:973">973</a></sup></p>
+<p>Something<sup id="fnref:974"><a class="footnote-ref" href="#fn:974">974</a></sup></p>
+<p>Something<sup id="fnref:975"><a class="footnote-ref" href="#fn:975">975</a></sup></p>
+<p>Something<sup id="fnref:976"><a class="footnote-ref" href="#fn:976">976</a></sup></p>
+<p>Something<sup id="fnref:977"><a class="footnote-ref" href="#fn:977">977</a></sup></p>
+<p>Something<sup id="fnref:978"><a class="footnote-ref" href="#fn:978">978</a></sup></p>
+<p>Something<sup id="fnref:979"><a class="footnote-ref" href="#fn:979">979</a></sup></p>
+<p>Something<sup id="fnref:980"><a class="footnote-ref" href="#fn:980">980</a></sup></p>
+<p>Something<sup id="fnref:981"><a class="footnote-ref" href="#fn:981">981</a></sup></p>
+<p>Something<sup id="fnref:982"><a class="footnote-ref" href="#fn:982">982</a></sup></p>
+<p>Something<sup id="fnref:983"><a class="footnote-ref" href="#fn:983">983</a></sup></p>
+<p>Something<sup id="fnref:984"><a class="footnote-ref" href="#fn:984">984</a></sup></p>
+<p>Something<sup id="fnref:985"><a class="footnote-ref" href="#fn:985">985</a></sup></p>
+<p>Something<sup id="fnref:986"><a class="footnote-ref" href="#fn:986">986</a></sup></p>
+<p>Something<sup id="fnref:987"><a class="footnote-ref" href="#fn:987">987</a></sup></p>
+<p>Something<sup id="fnref:988"><a class="footnote-ref" href="#fn:988">988</a></sup></p>
+<p>Something<sup id="fnref:989"><a class="footnote-ref" href="#fn:989">989</a></sup></p>
+<p>Something<sup id="fnref:990"><a class="footnote-ref" href="#fn:990">990</a></sup></p>
+<p>Something<sup id="fnref:991"><a class="footnote-ref" href="#fn:991">991</a></sup></p>
+<p>Something<sup id="fnref:992"><a class="footnote-ref" href="#fn:992">992</a></sup></p>
+<p>Something<sup id="fnref:993"><a class="footnote-ref" href="#fn:993">993</a></sup></p>
+<p>Something<sup id="fnref:994"><a class="footnote-ref" href="#fn:994">994</a></sup></p>
+<p>Something<sup id="fnref:995"><a class="footnote-ref" href="#fn:995">995</a></sup></p>
+<p>Something<sup id="fnref:996"><a class="footnote-ref" href="#fn:996">996</a></sup></p>
+<p>Something<sup id="fnref:997"><a class="footnote-ref" href="#fn:997">997</a></sup></p>
+<p>Something<sup id="fnref:998"><a class="footnote-ref" href="#fn:998">998</a></sup></p>
+<p>Something<sup id="fnref:999"><a class="footnote-ref" href="#fn:999">999</a></sup></p>
+<p>Something<sup id="fnref:1000"><a class="footnote-ref" href="#fn:1000">1000</a></sup></p>
+<p>Something<sup id="fnref:1001"><a class="footnote-ref" href="#fn:1001">1001</a></sup></p>
+<p>Something<sup id="fnref:1002"><a class="footnote-ref" href="#fn:1002">1002</a></sup></p>
+<p>Something<sup id="fnref:1003"><a class="footnote-ref" href="#fn:1003">1003</a></sup></p>
+<p>Something<sup id="fnref:1004"><a class="footnote-ref" href="#fn:1004">1004</a></sup></p>
+<p>Something<sup id="fnref:1005"><a class="footnote-ref" href="#fn:1005">1005</a></sup></p>
+<p>Something<sup id="fnref:1006"><a class="footnote-ref" href="#fn:1006">1006</a></sup></p>
+<p>Something<sup id="fnref:1007"><a class="footnote-ref" href="#fn:1007">1007</a></sup></p>
+<p>Something<sup id="fnref:1008"><a class="footnote-ref" href="#fn:1008">1008</a></sup></p>
+<p>Something<sup id="fnref:1009"><a class="footnote-ref" href="#fn:1009">1009</a></sup></p>
+<p>Something<sup id="fnref:1010"><a class="footnote-ref" href="#fn:1010">1010</a></sup></p>
+<p>Something<sup id="fnref:1011"><a class="footnote-ref" href="#fn:1011">1011</a></sup></p>
+<p>Something<sup id="fnref:1012"><a class="footnote-ref" href="#fn:1012">1012</a></sup></p>
+<p>Something<sup id="fnref:1013"><a class="footnote-ref" href="#fn:1013">1013</a></sup></p>
+<p>Something<sup id="fnref:1014"><a class="footnote-ref" href="#fn:1014">1014</a></sup></p>
+<p>Something<sup id="fnref:1015"><a class="footnote-ref" href="#fn:1015">1015</a></sup></p>
+<p>Something<sup id="fnref:1016"><a class="footnote-ref" href="#fn:1016">1016</a></sup></p>
+<p>Something<sup id="fnref:1017"><a class="footnote-ref" href="#fn:1017">1017</a></sup></p>
+<p>Something<sup id="fnref:1018"><a class="footnote-ref" href="#fn:1018">1018</a></sup></p>
+<p>Something<sup id="fnref:1019"><a class="footnote-ref" href="#fn:1019">1019</a></sup></p>
+<p>Something<sup id="fnref:1020"><a class="footnote-ref" href="#fn:1020">1020</a></sup></p>
+<p>Something<sup id="fnref:1021"><a class="footnote-ref" href="#fn:1021">1021</a></sup></p>
+<p>Something<sup id="fnref:1022"><a class="footnote-ref" href="#fn:1022">1022</a></sup></p>
+<p>Something<sup id="fnref:1023"><a class="footnote-ref" href="#fn:1023">1023</a></sup></p>
+<p>Something<sup id="fnref:1024"><a class="footnote-ref" href="#fn:1024">1024</a></sup></p>
+<p>Something<sup id="fnref:1025"><a class="footnote-ref" href="#fn:1025">1025</a></sup></p>
+<p>Something<sup id="fnref:1026"><a class="footnote-ref" href="#fn:1026">1026</a></sup></p>
+<p>Something<sup id="fnref:1027"><a class="footnote-ref" href="#fn:1027">1027</a></sup></p>
+<p>Something<sup id="fnref:1028"><a class="footnote-ref" href="#fn:1028">1028</a></sup></p>
+<p>Something<sup id="fnref:1029"><a class="footnote-ref" href="#fn:1029">1029</a></sup></p>
+<p>Something<sup id="fnref:1030"><a class="footnote-ref" href="#fn:1030">1030</a></sup></p>
+<p>Something<sup id="fnref:1031"><a class="footnote-ref" href="#fn:1031">1031</a></sup></p>
+<p>Something<sup id="fnref:1032"><a class="footnote-ref" href="#fn:1032">1032</a></sup></p>
+<p>Something<sup id="fnref:1033"><a class="footnote-ref" href="#fn:1033">1033</a></sup></p>
+<p>Something<sup id="fnref:1034"><a class="footnote-ref" href="#fn:1034">1034</a></sup></p>
+<p>Something<sup id="fnref:1035"><a class="footnote-ref" href="#fn:1035">1035</a></sup></p>
+<p>Something<sup id="fnref:1036"><a class="footnote-ref" href="#fn:1036">1036</a></sup></p>
+<p>Something<sup id="fnref:1037"><a class="footnote-ref" href="#fn:1037">1037</a></sup></p>
+<p>Something<sup id="fnref:1038"><a class="footnote-ref" href="#fn:1038">1038</a></sup></p>
+<p>Something<sup id="fnref:1039"><a class="footnote-ref" href="#fn:1039">1039</a></sup></p>
+<p>Something<sup id="fnref:1040"><a class="footnote-ref" href="#fn:1040">1040</a></sup></p>
+<p>Something<sup id="fnref:1041"><a class="footnote-ref" href="#fn:1041">1041</a></sup></p>
+<p>Something<sup id="fnref:1042"><a class="footnote-ref" href="#fn:1042">1042</a></sup></p>
+<p>Something<sup id="fnref:1043"><a class="footnote-ref" href="#fn:1043">1043</a></sup></p>
+<p>Something<sup id="fnref:1044"><a class="footnote-ref" href="#fn:1044">1044</a></sup></p>
+<p>Something<sup id="fnref:1045"><a class="footnote-ref" href="#fn:1045">1045</a></sup></p>
+<p>Something<sup id="fnref:1046"><a class="footnote-ref" href="#fn:1046">1046</a></sup></p>
+<p>Something<sup id="fnref:1047"><a class="footnote-ref" href="#fn:1047">1047</a></sup></p>
+<p>Something<sup id="fnref:1048"><a class="footnote-ref" href="#fn:1048">1048</a></sup></p>
+<p>Something<sup id="fnref:1049"><a class="footnote-ref" href="#fn:1049">1049</a></sup></p>
+<p>Something<sup id="fnref:1050"><a class="footnote-ref" href="#fn:1050">1050</a></sup></p>
+<p>Something<sup id="fnref:1051"><a class="footnote-ref" href="#fn:1051">1051</a></sup></p>
+<p>Something<sup id="fnref:1052"><a class="footnote-ref" href="#fn:1052">1052</a></sup></p>
+<p>Something<sup id="fnref:1053"><a class="footnote-ref" href="#fn:1053">1053</a></sup></p>
+<p>Something<sup id="fnref:1054"><a class="footnote-ref" href="#fn:1054">1054</a></sup></p>
+<p>Something<sup id="fnref:1055"><a class="footnote-ref" href="#fn:1055">1055</a></sup></p>
+<p>Something<sup id="fnref:1056"><a class="footnote-ref" href="#fn:1056">1056</a></sup></p>
+<p>Something<sup id="fnref:1057"><a class="footnote-ref" href="#fn:1057">1057</a></sup></p>
+<p>Something<sup id="fnref:1058"><a class="footnote-ref" href="#fn:1058">1058</a></sup></p>
+<p>Something<sup id="fnref:1059"><a class="footnote-ref" href="#fn:1059">1059</a></sup></p>
+<p>Something<sup id="fnref:1060"><a class="footnote-ref" href="#fn:1060">1060</a></sup></p>
+<p>Something<sup id="fnref:1061"><a class="footnote-ref" href="#fn:1061">1061</a></sup></p>
+<p>Something<sup id="fnref:1062"><a class="footnote-ref" href="#fn:1062">1062</a></sup></p>
+<p>Something<sup id="fnref:1063"><a class="footnote-ref" href="#fn:1063">1063</a></sup></p>
+<p>Something<sup id="fnref:1064"><a class="footnote-ref" href="#fn:1064">1064</a></sup></p>
+<p>Something<sup id="fnref:1065"><a class="footnote-ref" href="#fn:1065">1065</a></sup></p>
+<p>Something<sup id="fnref:1066"><a class="footnote-ref" href="#fn:1066">1066</a></sup></p>
+<p>Something<sup id="fnref:1067"><a class="footnote-ref" href="#fn:1067">1067</a></sup></p>
+<p>Something<sup id="fnref:1068"><a class="footnote-ref" href="#fn:1068">1068</a></sup></p>
+<p>Something<sup id="fnref:1069"><a class="footnote-ref" href="#fn:1069">1069</a></sup></p>
+<p>Something<sup id="fnref:1070"><a class="footnote-ref" href="#fn:1070">1070</a></sup></p>
+<p>Something<sup id="fnref:1071"><a class="footnote-ref" href="#fn:1071">1071</a></sup></p>
+<p>Something<sup id="fnref:1072"><a class="footnote-ref" href="#fn:1072">1072</a></sup></p>
+<p>Something<sup id="fnref:1073"><a class="footnote-ref" href="#fn:1073">1073</a></sup></p>
+<p>Something<sup id="fnref:1074"><a class="footnote-ref" href="#fn:1074">1074</a></sup></p>
+<p>Something<sup id="fnref:1075"><a class="footnote-ref" href="#fn:1075">1075</a></sup></p>
+<p>Something<sup id="fnref:1076"><a class="footnote-ref" href="#fn:1076">1076</a></sup></p>
+<p>Something<sup id="fnref:1077"><a class="footnote-ref" href="#fn:1077">1077</a></sup></p>
+<p>Something<sup id="fnref:1078"><a class="footnote-ref" href="#fn:1078">1078</a></sup></p>
+<p>Something<sup id="fnref:1079"><a class="footnote-ref" href="#fn:1079">1079</a></sup></p>
+<p>Something<sup id="fnref:1080"><a class="footnote-ref" href="#fn:1080">1080</a></sup></p>
+<p>Something<sup id="fnref:1081"><a class="footnote-ref" href="#fn:1081">1081</a></sup></p>
+<p>Something<sup id="fnref:1082"><a class="footnote-ref" href="#fn:1082">1082</a></sup></p>
+<p>Something<sup id="fnref:1083"><a class="footnote-ref" href="#fn:1083">1083</a></sup></p>
+<p>Something<sup id="fnref:1084"><a class="footnote-ref" href="#fn:1084">1084</a></sup></p>
+<p>Something<sup id="fnref:1085"><a class="footnote-ref" href="#fn:1085">1085</a></sup></p>
+<p>Something<sup id="fnref:1086"><a class="footnote-ref" href="#fn:1086">1086</a></sup></p>
+<p>Something<sup id="fnref:1087"><a class="footnote-ref" href="#fn:1087">1087</a></sup></p>
+<p>Something<sup id="fnref:1088"><a class="footnote-ref" href="#fn:1088">1088</a></sup></p>
+<p>Something<sup id="fnref:1089"><a class="footnote-ref" href="#fn:1089">1089</a></sup></p>
+<p>Something<sup id="fnref:1090"><a class="footnote-ref" href="#fn:1090">1090</a></sup></p>
+<p>Something<sup id="fnref:1091"><a class="footnote-ref" href="#fn:1091">1091</a></sup></p>
+<p>Something<sup id="fnref:1092"><a class="footnote-ref" href="#fn:1092">1092</a></sup></p>
+<p>Something<sup id="fnref:1093"><a class="footnote-ref" href="#fn:1093">1093</a></sup></p>
+<p>Something<sup id="fnref:1094"><a class="footnote-ref" href="#fn:1094">1094</a></sup></p>
+<p>Something<sup id="fnref:1095"><a class="footnote-ref" href="#fn:1095">1095</a></sup></p>
+<p>Something<sup id="fnref:1096"><a class="footnote-ref" href="#fn:1096">1096</a></sup></p>
+<p>Something<sup id="fnref:1097"><a class="footnote-ref" href="#fn:1097">1097</a></sup></p>
+<p>Something<sup id="fnref:1098"><a class="footnote-ref" href="#fn:1098">1098</a></sup></p>
+<p>Something<sup id="fnref:1099"><a class="footnote-ref" href="#fn:1099">1099</a></sup></p>
+<p>Something<sup id="fnref:1100"><a class="footnote-ref" href="#fn:1100">1100</a></sup></p>
+<p>Something<sup id="fnref:1101"><a class="footnote-ref" href="#fn:1101">1101</a></sup></p>
+<p>Something<sup id="fnref:1102"><a class="footnote-ref" href="#fn:1102">1102</a></sup></p>
+<p>Something<sup id="fnref:1103"><a class="footnote-ref" href="#fn:1103">1103</a></sup></p>
+<p>Something<sup id="fnref:1104"><a class="footnote-ref" href="#fn:1104">1104</a></sup></p>
+<p>Something<sup id="fnref:1105"><a class="footnote-ref" href="#fn:1105">1105</a></sup></p>
+<p>Something<sup id="fnref:1106"><a class="footnote-ref" href="#fn:1106">1106</a></sup></p>
+<p>Something<sup id="fnref:1107"><a class="footnote-ref" href="#fn:1107">1107</a></sup></p>
+<p>Something<sup id="fnref:1108"><a class="footnote-ref" href="#fn:1108">1108</a></sup></p>
+<p>Something<sup id="fnref:1109"><a class="footnote-ref" href="#fn:1109">1109</a></sup></p>
+<p>Something<sup id="fnref:1110"><a class="footnote-ref" href="#fn:1110">1110</a></sup></p>
+<p>Something<sup id="fnref:1111"><a class="footnote-ref" href="#fn:1111">1111</a></sup></p>
+<p>Something<sup id="fnref:1112"><a class="footnote-ref" href="#fn:1112">1112</a></sup></p>
+<p>Something<sup id="fnref:1113"><a class="footnote-ref" href="#fn:1113">1113</a></sup></p>
+<p>Something<sup id="fnref:1114"><a class="footnote-ref" href="#fn:1114">1114</a></sup></p>
+<p>Something<sup id="fnref:1115"><a class="footnote-ref" href="#fn:1115">1115</a></sup></p>
+<p>Something<sup id="fnref:1116"><a class="footnote-ref" href="#fn:1116">1116</a></sup></p>
+<p>Something<sup id="fnref:1117"><a class="footnote-ref" href="#fn:1117">1117</a></sup></p>
+<p>Something<sup id="fnref:1118"><a class="footnote-ref" href="#fn:1118">1118</a></sup></p>
+<p>Something<sup id="fnref:1119"><a class="footnote-ref" href="#fn:1119">1119</a></sup></p>
+<p>Something<sup id="fnref:1120"><a class="footnote-ref" href="#fn:1120">1120</a></sup></p>
+<p>Something<sup id="fnref:1121"><a class="footnote-ref" href="#fn:1121">1121</a></sup></p>
+<p>Something<sup id="fnref:1122"><a class="footnote-ref" href="#fn:1122">1122</a></sup></p>
+<p>Something<sup id="fnref:1123"><a class="footnote-ref" href="#fn:1123">1123</a></sup></p>
+<p>Something<sup id="fnref:1124"><a class="footnote-ref" href="#fn:1124">1124</a></sup></p>
+<p>Something<sup id="fnref:1125"><a class="footnote-ref" href="#fn:1125">1125</a></sup></p>
+<p>Something<sup id="fnref:1126"><a class="footnote-ref" href="#fn:1126">1126</a></sup></p>
+<p>Something<sup id="fnref:1127"><a class="footnote-ref" href="#fn:1127">1127</a></sup></p>
+<p>Something<sup id="fnref:1128"><a class="footnote-ref" href="#fn:1128">1128</a></sup></p>
+<p>Something<sup id="fnref:1129"><a class="footnote-ref" href="#fn:1129">1129</a></sup></p>
+<p>Something<sup id="fnref:1130"><a class="footnote-ref" href="#fn:1130">1130</a></sup></p>
+<p>Something<sup id="fnref:1131"><a class="footnote-ref" href="#fn:1131">1131</a></sup></p>
+<p>Something<sup id="fnref:1132"><a class="footnote-ref" href="#fn:1132">1132</a></sup></p>
+<p>Something<sup id="fnref:1133"><a class="footnote-ref" href="#fn:1133">1133</a></sup></p>
+<p>Something<sup id="fnref:1134"><a class="footnote-ref" href="#fn:1134">1134</a></sup></p>
+<p>Something<sup id="fnref:1135"><a class="footnote-ref" href="#fn:1135">1135</a></sup></p>
+<p>Something<sup id="fnref:1136"><a class="footnote-ref" href="#fn:1136">1136</a></sup></p>
+<p>Something<sup id="fnref:1137"><a class="footnote-ref" href="#fn:1137">1137</a></sup></p>
+<p>Something<sup id="fnref:1138"><a class="footnote-ref" href="#fn:1138">1138</a></sup></p>
+<p>Something<sup id="fnref:1139"><a class="footnote-ref" href="#fn:1139">1139</a></sup></p>
+<p>Something<sup id="fnref:1140"><a class="footnote-ref" href="#fn:1140">1140</a></sup></p>
+<p>Something<sup id="fnref:1141"><a class="footnote-ref" href="#fn:1141">1141</a></sup></p>
+<p>Something<sup id="fnref:1142"><a class="footnote-ref" href="#fn:1142">1142</a></sup></p>
+<p>Something<sup id="fnref:1143"><a class="footnote-ref" href="#fn:1143">1143</a></sup></p>
+<p>Something<sup id="fnref:1144"><a class="footnote-ref" href="#fn:1144">1144</a></sup></p>
+<p>Something<sup id="fnref:1145"><a class="footnote-ref" href="#fn:1145">1145</a></sup></p>
+<p>Something<sup id="fnref:1146"><a class="footnote-ref" href="#fn:1146">1146</a></sup></p>
+<p>Something<sup id="fnref:1147"><a class="footnote-ref" href="#fn:1147">1147</a></sup></p>
+<p>Something<sup id="fnref:1148"><a class="footnote-ref" href="#fn:1148">1148</a></sup></p>
+<p>Something<sup id="fnref:1149"><a class="footnote-ref" href="#fn:1149">1149</a></sup></p>
+<p>Something<sup id="fnref:1150"><a class="footnote-ref" href="#fn:1150">1150</a></sup></p>
+<p>Something<sup id="fnref:1151"><a class="footnote-ref" href="#fn:1151">1151</a></sup></p>
+<p>Something<sup id="fnref:1152"><a class="footnote-ref" href="#fn:1152">1152</a></sup></p>
+<p>Something<sup id="fnref:1153"><a class="footnote-ref" href="#fn:1153">1153</a></sup></p>
+<p>Something<sup id="fnref:1154"><a class="footnote-ref" href="#fn:1154">1154</a></sup></p>
+<p>Something<sup id="fnref:1155"><a class="footnote-ref" href="#fn:1155">1155</a></sup></p>
+<p>Something<sup id="fnref:1156"><a class="footnote-ref" href="#fn:1156">1156</a></sup></p>
+<p>Something<sup id="fnref:1157"><a class="footnote-ref" href="#fn:1157">1157</a></sup></p>
+<p>Something<sup id="fnref:1158"><a class="footnote-ref" href="#fn:1158">1158</a></sup></p>
+<p>Something<sup id="fnref:1159"><a class="footnote-ref" href="#fn:1159">1159</a></sup></p>
+<p>Something<sup id="fnref:1160"><a class="footnote-ref" href="#fn:1160">1160</a></sup></p>
+<p>Something<sup id="fnref:1161"><a class="footnote-ref" href="#fn:1161">1161</a></sup></p>
+<p>Something<sup id="fnref:1162"><a class="footnote-ref" href="#fn:1162">1162</a></sup></p>
+<p>Something<sup id="fnref:1163"><a class="footnote-ref" href="#fn:1163">1163</a></sup></p>
+<p>Something<sup id="fnref:1164"><a class="footnote-ref" href="#fn:1164">1164</a></sup></p>
+<p>Something<sup id="fnref:1165"><a class="footnote-ref" href="#fn:1165">1165</a></sup></p>
+<p>Something<sup id="fnref:1166"><a class="footnote-ref" href="#fn:1166">1166</a></sup></p>
+<p>Something<sup id="fnref:1167"><a class="footnote-ref" href="#fn:1167">1167</a></sup></p>
+<p>Something<sup id="fnref:1168"><a class="footnote-ref" href="#fn:1168">1168</a></sup></p>
+<p>Something<sup id="fnref:1169"><a class="footnote-ref" href="#fn:1169">1169</a></sup></p>
+<p>Something<sup id="fnref:1170"><a class="footnote-ref" href="#fn:1170">1170</a></sup></p>
+<p>Something<sup id="fnref:1171"><a class="footnote-ref" href="#fn:1171">1171</a></sup></p>
+<p>Something<sup id="fnref:1172"><a class="footnote-ref" href="#fn:1172">1172</a></sup></p>
+<p>Something<sup id="fnref:1173"><a class="footnote-ref" href="#fn:1173">1173</a></sup></p>
+<p>Something<sup id="fnref:1174"><a class="footnote-ref" href="#fn:1174">1174</a></sup></p>
+<p>Something<sup id="fnref:1175"><a class="footnote-ref" href="#fn:1175">1175</a></sup></p>
+<p>Something<sup id="fnref:1176"><a class="footnote-ref" href="#fn:1176">1176</a></sup></p>
+<p>Something<sup id="fnref:1177"><a class="footnote-ref" href="#fn:1177">1177</a></sup></p>
+<p>Something<sup id="fnref:1178"><a class="footnote-ref" href="#fn:1178">1178</a></sup></p>
+<p>Something<sup id="fnref:1179"><a class="footnote-ref" href="#fn:1179">1179</a></sup></p>
+<p>Something<sup id="fnref:1180"><a class="footnote-ref" href="#fn:1180">1180</a></sup></p>
+<p>Something<sup id="fnref:1181"><a class="footnote-ref" href="#fn:1181">1181</a></sup></p>
+<p>Something<sup id="fnref:1182"><a class="footnote-ref" href="#fn:1182">1182</a></sup></p>
+<p>Something<sup id="fnref:1183"><a class="footnote-ref" href="#fn:1183">1183</a></sup></p>
+<p>Something<sup id="fnref:1184"><a class="footnote-ref" href="#fn:1184">1184</a></sup></p>
+<p>Something<sup id="fnref:1185"><a class="footnote-ref" href="#fn:1185">1185</a></sup></p>
+<p>Something<sup id="fnref:1186"><a class="footnote-ref" href="#fn:1186">1186</a></sup></p>
+<p>Something<sup id="fnref:1187"><a class="footnote-ref" href="#fn:1187">1187</a></sup></p>
+<p>Something<sup id="fnref:1188"><a class="footnote-ref" href="#fn:1188">1188</a></sup></p>
+<p>Something<sup id="fnref:1189"><a class="footnote-ref" href="#fn:1189">1189</a></sup></p>
+<p>Something<sup id="fnref:1190"><a class="footnote-ref" href="#fn:1190">1190</a></sup></p>
+<p>Something<sup id="fnref:1191"><a class="footnote-ref" href="#fn:1191">1191</a></sup></p>
+<p>Something<sup id="fnref:1192"><a class="footnote-ref" href="#fn:1192">1192</a></sup></p>
+<p>Something<sup id="fnref:1193"><a class="footnote-ref" href="#fn:1193">1193</a></sup></p>
+<p>Something<sup id="fnref:1194"><a class="footnote-ref" href="#fn:1194">1194</a></sup></p>
+<p>Something<sup id="fnref:1195"><a class="footnote-ref" href="#fn:1195">1195</a></sup></p>
+<p>Something<sup id="fnref:1196"><a class="footnote-ref" href="#fn:1196">1196</a></sup></p>
+<p>Something<sup id="fnref:1197"><a class="footnote-ref" href="#fn:1197">1197</a></sup></p>
+<p>Something<sup id="fnref:1198"><a class="footnote-ref" href="#fn:1198">1198</a></sup></p>
+<p>Something<sup id="fnref:1199"><a class="footnote-ref" href="#fn:1199">1199</a></sup></p>
+<div class="footnote">
+<hr />
+<ol>
+<li id="fn:1">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text">&#8617;</a></p>
+</li>
+<li id="fn:2">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:2" title="Jump back to footnote 2 in the text">&#8617;</a></p>
+</li>
+<li id="fn:3">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:3" title="Jump back to footnote 3 in the text">&#8617;</a></p>
+</li>
+<li id="fn:4">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:4" title="Jump back to footnote 4 in the text">&#8617;</a></p>
+</li>
+<li id="fn:5">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:5" title="Jump back to footnote 5 in the text">&#8617;</a></p>
+</li>
+<li id="fn:6">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:6" title="Jump back to footnote 6 in the text">&#8617;</a></p>
+</li>
+<li id="fn:7">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:7" title="Jump back to footnote 7 in the text">&#8617;</a></p>
+</li>
+<li id="fn:8">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:8" title="Jump back to footnote 8 in the text">&#8617;</a></p>
+</li>
+<li id="fn:9">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:9" title="Jump back to footnote 9 in the text">&#8617;</a></p>
+</li>
+<li id="fn:10">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:10" title="Jump back to footnote 10 in the text">&#8617;</a></p>
+</li>
+<li id="fn:11">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:11" title="Jump back to footnote 11 in the text">&#8617;</a></p>
+</li>
+<li id="fn:12">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:12" title="Jump back to footnote 12 in the text">&#8617;</a></p>
+</li>
+<li id="fn:13">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:13" title="Jump back to footnote 13 in the text">&#8617;</a></p>
+</li>
+<li id="fn:14">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:14" title="Jump back to footnote 14 in the text">&#8617;</a></p>
+</li>
+<li id="fn:15">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:15" title="Jump back to footnote 15 in the text">&#8617;</a></p>
+</li>
+<li id="fn:16">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:16" title="Jump back to footnote 16 in the text">&#8617;</a></p>
+</li>
+<li id="fn:17">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:17" title="Jump back to footnote 17 in the text">&#8617;</a></p>
+</li>
+<li id="fn:18">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:18" title="Jump back to footnote 18 in the text">&#8617;</a></p>
+</li>
+<li id="fn:19">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:19" title="Jump back to footnote 19 in the text">&#8617;</a></p>
+</li>
+<li id="fn:20">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:20" title="Jump back to footnote 20 in the text">&#8617;</a></p>
+</li>
+<li id="fn:21">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:21" title="Jump back to footnote 21 in the text">&#8617;</a></p>
+</li>
+<li id="fn:22">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:22" title="Jump back to footnote 22 in the text">&#8617;</a></p>
+</li>
+<li id="fn:23">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:23" title="Jump back to footnote 23 in the text">&#8617;</a></p>
+</li>
+<li id="fn:24">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:24" title="Jump back to footnote 24 in the text">&#8617;</a></p>
+</li>
+<li id="fn:25">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:25" title="Jump back to footnote 25 in the text">&#8617;</a></p>
+</li>
+<li id="fn:26">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:26" title="Jump back to footnote 26 in the text">&#8617;</a></p>
+</li>
+<li id="fn:27">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:27" title="Jump back to footnote 27 in the text">&#8617;</a></p>
+</li>
+<li id="fn:28">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:28" title="Jump back to footnote 28 in the text">&#8617;</a></p>
+</li>
+<li id="fn:29">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:29" title="Jump back to footnote 29 in the text">&#8617;</a></p>
+</li>
+<li id="fn:30">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:30" title="Jump back to footnote 30 in the text">&#8617;</a></p>
+</li>
+<li id="fn:31">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:31" title="Jump back to footnote 31 in the text">&#8617;</a></p>
+</li>
+<li id="fn:32">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:32" title="Jump back to footnote 32 in the text">&#8617;</a></p>
+</li>
+<li id="fn:33">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:33" title="Jump back to footnote 33 in the text">&#8617;</a></p>
+</li>
+<li id="fn:34">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:34" title="Jump back to footnote 34 in the text">&#8617;</a></p>
+</li>
+<li id="fn:35">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:35" title="Jump back to footnote 35 in the text">&#8617;</a></p>
+</li>
+<li id="fn:36">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:36" title="Jump back to footnote 36 in the text">&#8617;</a></p>
+</li>
+<li id="fn:37">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:37" title="Jump back to footnote 37 in the text">&#8617;</a></p>
+</li>
+<li id="fn:38">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:38" title="Jump back to footnote 38 in the text">&#8617;</a></p>
+</li>
+<li id="fn:39">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:39" title="Jump back to footnote 39 in the text">&#8617;</a></p>
+</li>
+<li id="fn:40">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:40" title="Jump back to footnote 40 in the text">&#8617;</a></p>
+</li>
+<li id="fn:41">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:41" title="Jump back to footnote 41 in the text">&#8617;</a></p>
+</li>
+<li id="fn:42">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:42" title="Jump back to footnote 42 in the text">&#8617;</a></p>
+</li>
+<li id="fn:43">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:43" title="Jump back to footnote 43 in the text">&#8617;</a></p>
+</li>
+<li id="fn:44">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:44" title="Jump back to footnote 44 in the text">&#8617;</a></p>
+</li>
+<li id="fn:45">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:45" title="Jump back to footnote 45 in the text">&#8617;</a></p>
+</li>
+<li id="fn:46">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:46" title="Jump back to footnote 46 in the text">&#8617;</a></p>
+</li>
+<li id="fn:47">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:47" title="Jump back to footnote 47 in the text">&#8617;</a></p>
+</li>
+<li id="fn:48">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:48" title="Jump back to footnote 48 in the text">&#8617;</a></p>
+</li>
+<li id="fn:49">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:49" title="Jump back to footnote 49 in the text">&#8617;</a></p>
+</li>
+<li id="fn:50">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:50" title="Jump back to footnote 50 in the text">&#8617;</a></p>
+</li>
+<li id="fn:51">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:51" title="Jump back to footnote 51 in the text">&#8617;</a></p>
+</li>
+<li id="fn:52">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:52" title="Jump back to footnote 52 in the text">&#8617;</a></p>
+</li>
+<li id="fn:53">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:53" title="Jump back to footnote 53 in the text">&#8617;</a></p>
+</li>
+<li id="fn:54">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:54" title="Jump back to footnote 54 in the text">&#8617;</a></p>
+</li>
+<li id="fn:55">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:55" title="Jump back to footnote 55 in the text">&#8617;</a></p>
+</li>
+<li id="fn:56">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:56" title="Jump back to footnote 56 in the text">&#8617;</a></p>
+</li>
+<li id="fn:57">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:57" title="Jump back to footnote 57 in the text">&#8617;</a></p>
+</li>
+<li id="fn:58">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:58" title="Jump back to footnote 58 in the text">&#8617;</a></p>
+</li>
+<li id="fn:59">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:59" title="Jump back to footnote 59 in the text">&#8617;</a></p>
+</li>
+<li id="fn:60">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:60" title="Jump back to footnote 60 in the text">&#8617;</a></p>
+</li>
+<li id="fn:61">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:61" title="Jump back to footnote 61 in the text">&#8617;</a></p>
+</li>
+<li id="fn:62">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:62" title="Jump back to footnote 62 in the text">&#8617;</a></p>
+</li>
+<li id="fn:63">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:63" title="Jump back to footnote 63 in the text">&#8617;</a></p>
+</li>
+<li id="fn:64">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:64" title="Jump back to footnote 64 in the text">&#8617;</a></p>
+</li>
+<li id="fn:65">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:65" title="Jump back to footnote 65 in the text">&#8617;</a></p>
+</li>
+<li id="fn:66">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:66" title="Jump back to footnote 66 in the text">&#8617;</a></p>
+</li>
+<li id="fn:67">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:67" title="Jump back to footnote 67 in the text">&#8617;</a></p>
+</li>
+<li id="fn:68">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:68" title="Jump back to footnote 68 in the text">&#8617;</a></p>
+</li>
+<li id="fn:69">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:69" title="Jump back to footnote 69 in the text">&#8617;</a></p>
+</li>
+<li id="fn:70">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:70" title="Jump back to footnote 70 in the text">&#8617;</a></p>
+</li>
+<li id="fn:71">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:71" title="Jump back to footnote 71 in the text">&#8617;</a></p>
+</li>
+<li id="fn:72">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:72" title="Jump back to footnote 72 in the text">&#8617;</a></p>
+</li>
+<li id="fn:73">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:73" title="Jump back to footnote 73 in the text">&#8617;</a></p>
+</li>
+<li id="fn:74">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:74" title="Jump back to footnote 74 in the text">&#8617;</a></p>
+</li>
+<li id="fn:75">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:75" title="Jump back to footnote 75 in the text">&#8617;</a></p>
+</li>
+<li id="fn:76">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:76" title="Jump back to footnote 76 in the text">&#8617;</a></p>
+</li>
+<li id="fn:77">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:77" title="Jump back to footnote 77 in the text">&#8617;</a></p>
+</li>
+<li id="fn:78">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:78" title="Jump back to footnote 78 in the text">&#8617;</a></p>
+</li>
+<li id="fn:79">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:79" title="Jump back to footnote 79 in the text">&#8617;</a></p>
+</li>
+<li id="fn:80">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:80" title="Jump back to footnote 80 in the text">&#8617;</a></p>
+</li>
+<li id="fn:81">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:81" title="Jump back to footnote 81 in the text">&#8617;</a></p>
+</li>
+<li id="fn:82">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:82" title="Jump back to footnote 82 in the text">&#8617;</a></p>
+</li>
+<li id="fn:83">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:83" title="Jump back to footnote 83 in the text">&#8617;</a></p>
+</li>
+<li id="fn:84">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:84" title="Jump back to footnote 84 in the text">&#8617;</a></p>
+</li>
+<li id="fn:85">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:85" title="Jump back to footnote 85 in the text">&#8617;</a></p>
+</li>
+<li id="fn:86">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:86" title="Jump back to footnote 86 in the text">&#8617;</a></p>
+</li>
+<li id="fn:87">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:87" title="Jump back to footnote 87 in the text">&#8617;</a></p>
+</li>
+<li id="fn:88">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:88" title="Jump back to footnote 88 in the text">&#8617;</a></p>
+</li>
+<li id="fn:89">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:89" title="Jump back to footnote 89 in the text">&#8617;</a></p>
+</li>
+<li id="fn:90">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:90" title="Jump back to footnote 90 in the text">&#8617;</a></p>
+</li>
+<li id="fn:91">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:91" title="Jump back to footnote 91 in the text">&#8617;</a></p>
+</li>
+<li id="fn:92">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:92" title="Jump back to footnote 92 in the text">&#8617;</a></p>
+</li>
+<li id="fn:93">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:93" title="Jump back to footnote 93 in the text">&#8617;</a></p>
+</li>
+<li id="fn:94">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:94" title="Jump back to footnote 94 in the text">&#8617;</a></p>
+</li>
+<li id="fn:95">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:95" title="Jump back to footnote 95 in the text">&#8617;</a></p>
+</li>
+<li id="fn:96">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:96" title="Jump back to footnote 96 in the text">&#8617;</a></p>
+</li>
+<li id="fn:97">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:97" title="Jump back to footnote 97 in the text">&#8617;</a></p>
+</li>
+<li id="fn:98">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:98" title="Jump back to footnote 98 in the text">&#8617;</a></p>
+</li>
+<li id="fn:99">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:99" title="Jump back to footnote 99 in the text">&#8617;</a></p>
+</li>
+<li id="fn:100">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:100" title="Jump back to footnote 100 in the text">&#8617;</a></p>
+</li>
+<li id="fn:101">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:101" title="Jump back to footnote 101 in the text">&#8617;</a></p>
+</li>
+<li id="fn:102">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:102" title="Jump back to footnote 102 in the text">&#8617;</a></p>
+</li>
+<li id="fn:103">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:103" title="Jump back to footnote 103 in the text">&#8617;</a></p>
+</li>
+<li id="fn:104">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:104" title="Jump back to footnote 104 in the text">&#8617;</a></p>
+</li>
+<li id="fn:105">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:105" title="Jump back to footnote 105 in the text">&#8617;</a></p>
+</li>
+<li id="fn:106">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:106" title="Jump back to footnote 106 in the text">&#8617;</a></p>
+</li>
+<li id="fn:107">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:107" title="Jump back to footnote 107 in the text">&#8617;</a></p>
+</li>
+<li id="fn:108">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:108" title="Jump back to footnote 108 in the text">&#8617;</a></p>
+</li>
+<li id="fn:109">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:109" title="Jump back to footnote 109 in the text">&#8617;</a></p>
+</li>
+<li id="fn:110">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:110" title="Jump back to footnote 110 in the text">&#8617;</a></p>
+</li>
+<li id="fn:111">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:111" title="Jump back to footnote 111 in the text">&#8617;</a></p>
+</li>
+<li id="fn:112">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:112" title="Jump back to footnote 112 in the text">&#8617;</a></p>
+</li>
+<li id="fn:113">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:113" title="Jump back to footnote 113 in the text">&#8617;</a></p>
+</li>
+<li id="fn:114">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:114" title="Jump back to footnote 114 in the text">&#8617;</a></p>
+</li>
+<li id="fn:115">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:115" title="Jump back to footnote 115 in the text">&#8617;</a></p>
+</li>
+<li id="fn:116">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:116" title="Jump back to footnote 116 in the text">&#8617;</a></p>
+</li>
+<li id="fn:117">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:117" title="Jump back to footnote 117 in the text">&#8617;</a></p>
+</li>
+<li id="fn:118">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:118" title="Jump back to footnote 118 in the text">&#8617;</a></p>
+</li>
+<li id="fn:119">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:119" title="Jump back to footnote 119 in the text">&#8617;</a></p>
+</li>
+<li id="fn:120">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:120" title="Jump back to footnote 120 in the text">&#8617;</a></p>
+</li>
+<li id="fn:121">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:121" title="Jump back to footnote 121 in the text">&#8617;</a></p>
+</li>
+<li id="fn:122">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:122" title="Jump back to footnote 122 in the text">&#8617;</a></p>
+</li>
+<li id="fn:123">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:123" title="Jump back to footnote 123 in the text">&#8617;</a></p>
+</li>
+<li id="fn:124">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:124" title="Jump back to footnote 124 in the text">&#8617;</a></p>
+</li>
+<li id="fn:125">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:125" title="Jump back to footnote 125 in the text">&#8617;</a></p>
+</li>
+<li id="fn:126">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:126" title="Jump back to footnote 126 in the text">&#8617;</a></p>
+</li>
+<li id="fn:127">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:127" title="Jump back to footnote 127 in the text">&#8617;</a></p>
+</li>
+<li id="fn:128">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:128" title="Jump back to footnote 128 in the text">&#8617;</a></p>
+</li>
+<li id="fn:129">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:129" title="Jump back to footnote 129 in the text">&#8617;</a></p>
+</li>
+<li id="fn:130">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:130" title="Jump back to footnote 130 in the text">&#8617;</a></p>
+</li>
+<li id="fn:131">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:131" title="Jump back to footnote 131 in the text">&#8617;</a></p>
+</li>
+<li id="fn:132">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:132" title="Jump back to footnote 132 in the text">&#8617;</a></p>
+</li>
+<li id="fn:133">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:133" title="Jump back to footnote 133 in the text">&#8617;</a></p>
+</li>
+<li id="fn:134">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:134" title="Jump back to footnote 134 in the text">&#8617;</a></p>
+</li>
+<li id="fn:135">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:135" title="Jump back to footnote 135 in the text">&#8617;</a></p>
+</li>
+<li id="fn:136">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:136" title="Jump back to footnote 136 in the text">&#8617;</a></p>
+</li>
+<li id="fn:137">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:137" title="Jump back to footnote 137 in the text">&#8617;</a></p>
+</li>
+<li id="fn:138">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:138" title="Jump back to footnote 138 in the text">&#8617;</a></p>
+</li>
+<li id="fn:139">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:139" title="Jump back to footnote 139 in the text">&#8617;</a></p>
+</li>
+<li id="fn:140">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:140" title="Jump back to footnote 140 in the text">&#8617;</a></p>
+</li>
+<li id="fn:141">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:141" title="Jump back to footnote 141 in the text">&#8617;</a></p>
+</li>
+<li id="fn:142">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:142" title="Jump back to footnote 142 in the text">&#8617;</a></p>
+</li>
+<li id="fn:143">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:143" title="Jump back to footnote 143 in the text">&#8617;</a></p>
+</li>
+<li id="fn:144">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:144" title="Jump back to footnote 144 in the text">&#8617;</a></p>
+</li>
+<li id="fn:145">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:145" title="Jump back to footnote 145 in the text">&#8617;</a></p>
+</li>
+<li id="fn:146">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:146" title="Jump back to footnote 146 in the text">&#8617;</a></p>
+</li>
+<li id="fn:147">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:147" title="Jump back to footnote 147 in the text">&#8617;</a></p>
+</li>
+<li id="fn:148">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:148" title="Jump back to footnote 148 in the text">&#8617;</a></p>
+</li>
+<li id="fn:149">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:149" title="Jump back to footnote 149 in the text">&#8617;</a></p>
+</li>
+<li id="fn:150">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:150" title="Jump back to footnote 150 in the text">&#8617;</a></p>
+</li>
+<li id="fn:151">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:151" title="Jump back to footnote 151 in the text">&#8617;</a></p>
+</li>
+<li id="fn:152">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:152" title="Jump back to footnote 152 in the text">&#8617;</a></p>
+</li>
+<li id="fn:153">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:153" title="Jump back to footnote 153 in the text">&#8617;</a></p>
+</li>
+<li id="fn:154">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:154" title="Jump back to footnote 154 in the text">&#8617;</a></p>
+</li>
+<li id="fn:155">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:155" title="Jump back to footnote 155 in the text">&#8617;</a></p>
+</li>
+<li id="fn:156">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:156" title="Jump back to footnote 156 in the text">&#8617;</a></p>
+</li>
+<li id="fn:157">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:157" title="Jump back to footnote 157 in the text">&#8617;</a></p>
+</li>
+<li id="fn:158">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:158" title="Jump back to footnote 158 in the text">&#8617;</a></p>
+</li>
+<li id="fn:159">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:159" title="Jump back to footnote 159 in the text">&#8617;</a></p>
+</li>
+<li id="fn:160">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:160" title="Jump back to footnote 160 in the text">&#8617;</a></p>
+</li>
+<li id="fn:161">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:161" title="Jump back to footnote 161 in the text">&#8617;</a></p>
+</li>
+<li id="fn:162">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:162" title="Jump back to footnote 162 in the text">&#8617;</a></p>
+</li>
+<li id="fn:163">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:163" title="Jump back to footnote 163 in the text">&#8617;</a></p>
+</li>
+<li id="fn:164">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:164" title="Jump back to footnote 164 in the text">&#8617;</a></p>
+</li>
+<li id="fn:165">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:165" title="Jump back to footnote 165 in the text">&#8617;</a></p>
+</li>
+<li id="fn:166">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:166" title="Jump back to footnote 166 in the text">&#8617;</a></p>
+</li>
+<li id="fn:167">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:167" title="Jump back to footnote 167 in the text">&#8617;</a></p>
+</li>
+<li id="fn:168">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:168" title="Jump back to footnote 168 in the text">&#8617;</a></p>
+</li>
+<li id="fn:169">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:169" title="Jump back to footnote 169 in the text">&#8617;</a></p>
+</li>
+<li id="fn:170">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:170" title="Jump back to footnote 170 in the text">&#8617;</a></p>
+</li>
+<li id="fn:171">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:171" title="Jump back to footnote 171 in the text">&#8617;</a></p>
+</li>
+<li id="fn:172">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:172" title="Jump back to footnote 172 in the text">&#8617;</a></p>
+</li>
+<li id="fn:173">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:173" title="Jump back to footnote 173 in the text">&#8617;</a></p>
+</li>
+<li id="fn:174">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:174" title="Jump back to footnote 174 in the text">&#8617;</a></p>
+</li>
+<li id="fn:175">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:175" title="Jump back to footnote 175 in the text">&#8617;</a></p>
+</li>
+<li id="fn:176">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:176" title="Jump back to footnote 176 in the text">&#8617;</a></p>
+</li>
+<li id="fn:177">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:177" title="Jump back to footnote 177 in the text">&#8617;</a></p>
+</li>
+<li id="fn:178">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:178" title="Jump back to footnote 178 in the text">&#8617;</a></p>
+</li>
+<li id="fn:179">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:179" title="Jump back to footnote 179 in the text">&#8617;</a></p>
+</li>
+<li id="fn:180">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:180" title="Jump back to footnote 180 in the text">&#8617;</a></p>
+</li>
+<li id="fn:181">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:181" title="Jump back to footnote 181 in the text">&#8617;</a></p>
+</li>
+<li id="fn:182">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:182" title="Jump back to footnote 182 in the text">&#8617;</a></p>
+</li>
+<li id="fn:183">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:183" title="Jump back to footnote 183 in the text">&#8617;</a></p>
+</li>
+<li id="fn:184">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:184" title="Jump back to footnote 184 in the text">&#8617;</a></p>
+</li>
+<li id="fn:185">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:185" title="Jump back to footnote 185 in the text">&#8617;</a></p>
+</li>
+<li id="fn:186">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:186" title="Jump back to footnote 186 in the text">&#8617;</a></p>
+</li>
+<li id="fn:187">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:187" title="Jump back to footnote 187 in the text">&#8617;</a></p>
+</li>
+<li id="fn:188">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:188" title="Jump back to footnote 188 in the text">&#8617;</a></p>
+</li>
+<li id="fn:189">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:189" title="Jump back to footnote 189 in the text">&#8617;</a></p>
+</li>
+<li id="fn:190">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:190" title="Jump back to footnote 190 in the text">&#8617;</a></p>
+</li>
+<li id="fn:191">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:191" title="Jump back to footnote 191 in the text">&#8617;</a></p>
+</li>
+<li id="fn:192">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:192" title="Jump back to footnote 192 in the text">&#8617;</a></p>
+</li>
+<li id="fn:193">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:193" title="Jump back to footnote 193 in the text">&#8617;</a></p>
+</li>
+<li id="fn:194">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:194" title="Jump back to footnote 194 in the text">&#8617;</a></p>
+</li>
+<li id="fn:195">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:195" title="Jump back to footnote 195 in the text">&#8617;</a></p>
+</li>
+<li id="fn:196">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:196" title="Jump back to footnote 196 in the text">&#8617;</a></p>
+</li>
+<li id="fn:197">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:197" title="Jump back to footnote 197 in the text">&#8617;</a></p>
+</li>
+<li id="fn:198">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:198" title="Jump back to footnote 198 in the text">&#8617;</a></p>
+</li>
+<li id="fn:199">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:199" title="Jump back to footnote 199 in the text">&#8617;</a></p>
+</li>
+<li id="fn:200">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:200" title="Jump back to footnote 200 in the text">&#8617;</a></p>
+</li>
+<li id="fn:201">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:201" title="Jump back to footnote 201 in the text">&#8617;</a></p>
+</li>
+<li id="fn:202">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:202" title="Jump back to footnote 202 in the text">&#8617;</a></p>
+</li>
+<li id="fn:203">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:203" title="Jump back to footnote 203 in the text">&#8617;</a></p>
+</li>
+<li id="fn:204">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:204" title="Jump back to footnote 204 in the text">&#8617;</a></p>
+</li>
+<li id="fn:205">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:205" title="Jump back to footnote 205 in the text">&#8617;</a></p>
+</li>
+<li id="fn:206">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:206" title="Jump back to footnote 206 in the text">&#8617;</a></p>
+</li>
+<li id="fn:207">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:207" title="Jump back to footnote 207 in the text">&#8617;</a></p>
+</li>
+<li id="fn:208">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:208" title="Jump back to footnote 208 in the text">&#8617;</a></p>
+</li>
+<li id="fn:209">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:209" title="Jump back to footnote 209 in the text">&#8617;</a></p>
+</li>
+<li id="fn:210">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:210" title="Jump back to footnote 210 in the text">&#8617;</a></p>
+</li>
+<li id="fn:211">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:211" title="Jump back to footnote 211 in the text">&#8617;</a></p>
+</li>
+<li id="fn:212">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:212" title="Jump back to footnote 212 in the text">&#8617;</a></p>
+</li>
+<li id="fn:213">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:213" title="Jump back to footnote 213 in the text">&#8617;</a></p>
+</li>
+<li id="fn:214">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:214" title="Jump back to footnote 214 in the text">&#8617;</a></p>
+</li>
+<li id="fn:215">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:215" title="Jump back to footnote 215 in the text">&#8617;</a></p>
+</li>
+<li id="fn:216">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:216" title="Jump back to footnote 216 in the text">&#8617;</a></p>
+</li>
+<li id="fn:217">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:217" title="Jump back to footnote 217 in the text">&#8617;</a></p>
+</li>
+<li id="fn:218">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:218" title="Jump back to footnote 218 in the text">&#8617;</a></p>
+</li>
+<li id="fn:219">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:219" title="Jump back to footnote 219 in the text">&#8617;</a></p>
+</li>
+<li id="fn:220">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:220" title="Jump back to footnote 220 in the text">&#8617;</a></p>
+</li>
+<li id="fn:221">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:221" title="Jump back to footnote 221 in the text">&#8617;</a></p>
+</li>
+<li id="fn:222">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:222" title="Jump back to footnote 222 in the text">&#8617;</a></p>
+</li>
+<li id="fn:223">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:223" title="Jump back to footnote 223 in the text">&#8617;</a></p>
+</li>
+<li id="fn:224">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:224" title="Jump back to footnote 224 in the text">&#8617;</a></p>
+</li>
+<li id="fn:225">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:225" title="Jump back to footnote 225 in the text">&#8617;</a></p>
+</li>
+<li id="fn:226">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:226" title="Jump back to footnote 226 in the text">&#8617;</a></p>
+</li>
+<li id="fn:227">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:227" title="Jump back to footnote 227 in the text">&#8617;</a></p>
+</li>
+<li id="fn:228">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:228" title="Jump back to footnote 228 in the text">&#8617;</a></p>
+</li>
+<li id="fn:229">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:229" title="Jump back to footnote 229 in the text">&#8617;</a></p>
+</li>
+<li id="fn:230">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:230" title="Jump back to footnote 230 in the text">&#8617;</a></p>
+</li>
+<li id="fn:231">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:231" title="Jump back to footnote 231 in the text">&#8617;</a></p>
+</li>
+<li id="fn:232">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:232" title="Jump back to footnote 232 in the text">&#8617;</a></p>
+</li>
+<li id="fn:233">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:233" title="Jump back to footnote 233 in the text">&#8617;</a></p>
+</li>
+<li id="fn:234">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:234" title="Jump back to footnote 234 in the text">&#8617;</a></p>
+</li>
+<li id="fn:235">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:235" title="Jump back to footnote 235 in the text">&#8617;</a></p>
+</li>
+<li id="fn:236">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:236" title="Jump back to footnote 236 in the text">&#8617;</a></p>
+</li>
+<li id="fn:237">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:237" title="Jump back to footnote 237 in the text">&#8617;</a></p>
+</li>
+<li id="fn:238">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:238" title="Jump back to footnote 238 in the text">&#8617;</a></p>
+</li>
+<li id="fn:239">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:239" title="Jump back to footnote 239 in the text">&#8617;</a></p>
+</li>
+<li id="fn:240">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:240" title="Jump back to footnote 240 in the text">&#8617;</a></p>
+</li>
+<li id="fn:241">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:241" title="Jump back to footnote 241 in the text">&#8617;</a></p>
+</li>
+<li id="fn:242">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:242" title="Jump back to footnote 242 in the text">&#8617;</a></p>
+</li>
+<li id="fn:243">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:243" title="Jump back to footnote 243 in the text">&#8617;</a></p>
+</li>
+<li id="fn:244">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:244" title="Jump back to footnote 244 in the text">&#8617;</a></p>
+</li>
+<li id="fn:245">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:245" title="Jump back to footnote 245 in the text">&#8617;</a></p>
+</li>
+<li id="fn:246">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:246" title="Jump back to footnote 246 in the text">&#8617;</a></p>
+</li>
+<li id="fn:247">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:247" title="Jump back to footnote 247 in the text">&#8617;</a></p>
+</li>
+<li id="fn:248">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:248" title="Jump back to footnote 248 in the text">&#8617;</a></p>
+</li>
+<li id="fn:249">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:249" title="Jump back to footnote 249 in the text">&#8617;</a></p>
+</li>
+<li id="fn:250">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:250" title="Jump back to footnote 250 in the text">&#8617;</a></p>
+</li>
+<li id="fn:251">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:251" title="Jump back to footnote 251 in the text">&#8617;</a></p>
+</li>
+<li id="fn:252">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:252" title="Jump back to footnote 252 in the text">&#8617;</a></p>
+</li>
+<li id="fn:253">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:253" title="Jump back to footnote 253 in the text">&#8617;</a></p>
+</li>
+<li id="fn:254">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:254" title="Jump back to footnote 254 in the text">&#8617;</a></p>
+</li>
+<li id="fn:255">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:255" title="Jump back to footnote 255 in the text">&#8617;</a></p>
+</li>
+<li id="fn:256">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:256" title="Jump back to footnote 256 in the text">&#8617;</a></p>
+</li>
+<li id="fn:257">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:257" title="Jump back to footnote 257 in the text">&#8617;</a></p>
+</li>
+<li id="fn:258">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:258" title="Jump back to footnote 258 in the text">&#8617;</a></p>
+</li>
+<li id="fn:259">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:259" title="Jump back to footnote 259 in the text">&#8617;</a></p>
+</li>
+<li id="fn:260">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:260" title="Jump back to footnote 260 in the text">&#8617;</a></p>
+</li>
+<li id="fn:261">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:261" title="Jump back to footnote 261 in the text">&#8617;</a></p>
+</li>
+<li id="fn:262">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:262" title="Jump back to footnote 262 in the text">&#8617;</a></p>
+</li>
+<li id="fn:263">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:263" title="Jump back to footnote 263 in the text">&#8617;</a></p>
+</li>
+<li id="fn:264">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:264" title="Jump back to footnote 264 in the text">&#8617;</a></p>
+</li>
+<li id="fn:265">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:265" title="Jump back to footnote 265 in the text">&#8617;</a></p>
+</li>
+<li id="fn:266">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:266" title="Jump back to footnote 266 in the text">&#8617;</a></p>
+</li>
+<li id="fn:267">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:267" title="Jump back to footnote 267 in the text">&#8617;</a></p>
+</li>
+<li id="fn:268">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:268" title="Jump back to footnote 268 in the text">&#8617;</a></p>
+</li>
+<li id="fn:269">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:269" title="Jump back to footnote 269 in the text">&#8617;</a></p>
+</li>
+<li id="fn:270">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:270" title="Jump back to footnote 270 in the text">&#8617;</a></p>
+</li>
+<li id="fn:271">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:271" title="Jump back to footnote 271 in the text">&#8617;</a></p>
+</li>
+<li id="fn:272">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:272" title="Jump back to footnote 272 in the text">&#8617;</a></p>
+</li>
+<li id="fn:273">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:273" title="Jump back to footnote 273 in the text">&#8617;</a></p>
+</li>
+<li id="fn:274">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:274" title="Jump back to footnote 274 in the text">&#8617;</a></p>
+</li>
+<li id="fn:275">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:275" title="Jump back to footnote 275 in the text">&#8617;</a></p>
+</li>
+<li id="fn:276">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:276" title="Jump back to footnote 276 in the text">&#8617;</a></p>
+</li>
+<li id="fn:277">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:277" title="Jump back to footnote 277 in the text">&#8617;</a></p>
+</li>
+<li id="fn:278">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:278" title="Jump back to footnote 278 in the text">&#8617;</a></p>
+</li>
+<li id="fn:279">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:279" title="Jump back to footnote 279 in the text">&#8617;</a></p>
+</li>
+<li id="fn:280">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:280" title="Jump back to footnote 280 in the text">&#8617;</a></p>
+</li>
+<li id="fn:281">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:281" title="Jump back to footnote 281 in the text">&#8617;</a></p>
+</li>
+<li id="fn:282">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:282" title="Jump back to footnote 282 in the text">&#8617;</a></p>
+</li>
+<li id="fn:283">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:283" title="Jump back to footnote 283 in the text">&#8617;</a></p>
+</li>
+<li id="fn:284">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:284" title="Jump back to footnote 284 in the text">&#8617;</a></p>
+</li>
+<li id="fn:285">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:285" title="Jump back to footnote 285 in the text">&#8617;</a></p>
+</li>
+<li id="fn:286">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:286" title="Jump back to footnote 286 in the text">&#8617;</a></p>
+</li>
+<li id="fn:287">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:287" title="Jump back to footnote 287 in the text">&#8617;</a></p>
+</li>
+<li id="fn:288">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:288" title="Jump back to footnote 288 in the text">&#8617;</a></p>
+</li>
+<li id="fn:289">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:289" title="Jump back to footnote 289 in the text">&#8617;</a></p>
+</li>
+<li id="fn:290">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:290" title="Jump back to footnote 290 in the text">&#8617;</a></p>
+</li>
+<li id="fn:291">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:291" title="Jump back to footnote 291 in the text">&#8617;</a></p>
+</li>
+<li id="fn:292">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:292" title="Jump back to footnote 292 in the text">&#8617;</a></p>
+</li>
+<li id="fn:293">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:293" title="Jump back to footnote 293 in the text">&#8617;</a></p>
+</li>
+<li id="fn:294">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:294" title="Jump back to footnote 294 in the text">&#8617;</a></p>
+</li>
+<li id="fn:295">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:295" title="Jump back to footnote 295 in the text">&#8617;</a></p>
+</li>
+<li id="fn:296">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:296" title="Jump back to footnote 296 in the text">&#8617;</a></p>
+</li>
+<li id="fn:297">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:297" title="Jump back to footnote 297 in the text">&#8617;</a></p>
+</li>
+<li id="fn:298">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:298" title="Jump back to footnote 298 in the text">&#8617;</a></p>
+</li>
+<li id="fn:299">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:299" title="Jump back to footnote 299 in the text">&#8617;</a></p>
+</li>
+<li id="fn:300">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:300" title="Jump back to footnote 300 in the text">&#8617;</a></p>
+</li>
+<li id="fn:301">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:301" title="Jump back to footnote 301 in the text">&#8617;</a></p>
+</li>
+<li id="fn:302">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:302" title="Jump back to footnote 302 in the text">&#8617;</a></p>
+</li>
+<li id="fn:303">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:303" title="Jump back to footnote 303 in the text">&#8617;</a></p>
+</li>
+<li id="fn:304">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:304" title="Jump back to footnote 304 in the text">&#8617;</a></p>
+</li>
+<li id="fn:305">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:305" title="Jump back to footnote 305 in the text">&#8617;</a></p>
+</li>
+<li id="fn:306">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:306" title="Jump back to footnote 306 in the text">&#8617;</a></p>
+</li>
+<li id="fn:307">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:307" title="Jump back to footnote 307 in the text">&#8617;</a></p>
+</li>
+<li id="fn:308">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:308" title="Jump back to footnote 308 in the text">&#8617;</a></p>
+</li>
+<li id="fn:309">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:309" title="Jump back to footnote 309 in the text">&#8617;</a></p>
+</li>
+<li id="fn:310">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:310" title="Jump back to footnote 310 in the text">&#8617;</a></p>
+</li>
+<li id="fn:311">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:311" title="Jump back to footnote 311 in the text">&#8617;</a></p>
+</li>
+<li id="fn:312">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:312" title="Jump back to footnote 312 in the text">&#8617;</a></p>
+</li>
+<li id="fn:313">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:313" title="Jump back to footnote 313 in the text">&#8617;</a></p>
+</li>
+<li id="fn:314">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:314" title="Jump back to footnote 314 in the text">&#8617;</a></p>
+</li>
+<li id="fn:315">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:315" title="Jump back to footnote 315 in the text">&#8617;</a></p>
+</li>
+<li id="fn:316">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:316" title="Jump back to footnote 316 in the text">&#8617;</a></p>
+</li>
+<li id="fn:317">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:317" title="Jump back to footnote 317 in the text">&#8617;</a></p>
+</li>
+<li id="fn:318">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:318" title="Jump back to footnote 318 in the text">&#8617;</a></p>
+</li>
+<li id="fn:319">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:319" title="Jump back to footnote 319 in the text">&#8617;</a></p>
+</li>
+<li id="fn:320">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:320" title="Jump back to footnote 320 in the text">&#8617;</a></p>
+</li>
+<li id="fn:321">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:321" title="Jump back to footnote 321 in the text">&#8617;</a></p>
+</li>
+<li id="fn:322">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:322" title="Jump back to footnote 322 in the text">&#8617;</a></p>
+</li>
+<li id="fn:323">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:323" title="Jump back to footnote 323 in the text">&#8617;</a></p>
+</li>
+<li id="fn:324">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:324" title="Jump back to footnote 324 in the text">&#8617;</a></p>
+</li>
+<li id="fn:325">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:325" title="Jump back to footnote 325 in the text">&#8617;</a></p>
+</li>
+<li id="fn:326">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:326" title="Jump back to footnote 326 in the text">&#8617;</a></p>
+</li>
+<li id="fn:327">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:327" title="Jump back to footnote 327 in the text">&#8617;</a></p>
+</li>
+<li id="fn:328">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:328" title="Jump back to footnote 328 in the text">&#8617;</a></p>
+</li>
+<li id="fn:329">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:329" title="Jump back to footnote 329 in the text">&#8617;</a></p>
+</li>
+<li id="fn:330">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:330" title="Jump back to footnote 330 in the text">&#8617;</a></p>
+</li>
+<li id="fn:331">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:331" title="Jump back to footnote 331 in the text">&#8617;</a></p>
+</li>
+<li id="fn:332">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:332" title="Jump back to footnote 332 in the text">&#8617;</a></p>
+</li>
+<li id="fn:333">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:333" title="Jump back to footnote 333 in the text">&#8617;</a></p>
+</li>
+<li id="fn:334">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:334" title="Jump back to footnote 334 in the text">&#8617;</a></p>
+</li>
+<li id="fn:335">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:335" title="Jump back to footnote 335 in the text">&#8617;</a></p>
+</li>
+<li id="fn:336">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:336" title="Jump back to footnote 336 in the text">&#8617;</a></p>
+</li>
+<li id="fn:337">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:337" title="Jump back to footnote 337 in the text">&#8617;</a></p>
+</li>
+<li id="fn:338">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:338" title="Jump back to footnote 338 in the text">&#8617;</a></p>
+</li>
+<li id="fn:339">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:339" title="Jump back to footnote 339 in the text">&#8617;</a></p>
+</li>
+<li id="fn:340">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:340" title="Jump back to footnote 340 in the text">&#8617;</a></p>
+</li>
+<li id="fn:341">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:341" title="Jump back to footnote 341 in the text">&#8617;</a></p>
+</li>
+<li id="fn:342">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:342" title="Jump back to footnote 342 in the text">&#8617;</a></p>
+</li>
+<li id="fn:343">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:343" title="Jump back to footnote 343 in the text">&#8617;</a></p>
+</li>
+<li id="fn:344">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:344" title="Jump back to footnote 344 in the text">&#8617;</a></p>
+</li>
+<li id="fn:345">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:345" title="Jump back to footnote 345 in the text">&#8617;</a></p>
+</li>
+<li id="fn:346">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:346" title="Jump back to footnote 346 in the text">&#8617;</a></p>
+</li>
+<li id="fn:347">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:347" title="Jump back to footnote 347 in the text">&#8617;</a></p>
+</li>
+<li id="fn:348">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:348" title="Jump back to footnote 348 in the text">&#8617;</a></p>
+</li>
+<li id="fn:349">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:349" title="Jump back to footnote 349 in the text">&#8617;</a></p>
+</li>
+<li id="fn:350">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:350" title="Jump back to footnote 350 in the text">&#8617;</a></p>
+</li>
+<li id="fn:351">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:351" title="Jump back to footnote 351 in the text">&#8617;</a></p>
+</li>
+<li id="fn:352">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:352" title="Jump back to footnote 352 in the text">&#8617;</a></p>
+</li>
+<li id="fn:353">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:353" title="Jump back to footnote 353 in the text">&#8617;</a></p>
+</li>
+<li id="fn:354">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:354" title="Jump back to footnote 354 in the text">&#8617;</a></p>
+</li>
+<li id="fn:355">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:355" title="Jump back to footnote 355 in the text">&#8617;</a></p>
+</li>
+<li id="fn:356">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:356" title="Jump back to footnote 356 in the text">&#8617;</a></p>
+</li>
+<li id="fn:357">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:357" title="Jump back to footnote 357 in the text">&#8617;</a></p>
+</li>
+<li id="fn:358">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:358" title="Jump back to footnote 358 in the text">&#8617;</a></p>
+</li>
+<li id="fn:359">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:359" title="Jump back to footnote 359 in the text">&#8617;</a></p>
+</li>
+<li id="fn:360">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:360" title="Jump back to footnote 360 in the text">&#8617;</a></p>
+</li>
+<li id="fn:361">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:361" title="Jump back to footnote 361 in the text">&#8617;</a></p>
+</li>
+<li id="fn:362">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:362" title="Jump back to footnote 362 in the text">&#8617;</a></p>
+</li>
+<li id="fn:363">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:363" title="Jump back to footnote 363 in the text">&#8617;</a></p>
+</li>
+<li id="fn:364">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:364" title="Jump back to footnote 364 in the text">&#8617;</a></p>
+</li>
+<li id="fn:365">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:365" title="Jump back to footnote 365 in the text">&#8617;</a></p>
+</li>
+<li id="fn:366">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:366" title="Jump back to footnote 366 in the text">&#8617;</a></p>
+</li>
+<li id="fn:367">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:367" title="Jump back to footnote 367 in the text">&#8617;</a></p>
+</li>
+<li id="fn:368">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:368" title="Jump back to footnote 368 in the text">&#8617;</a></p>
+</li>
+<li id="fn:369">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:369" title="Jump back to footnote 369 in the text">&#8617;</a></p>
+</li>
+<li id="fn:370">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:370" title="Jump back to footnote 370 in the text">&#8617;</a></p>
+</li>
+<li id="fn:371">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:371" title="Jump back to footnote 371 in the text">&#8617;</a></p>
+</li>
+<li id="fn:372">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:372" title="Jump back to footnote 372 in the text">&#8617;</a></p>
+</li>
+<li id="fn:373">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:373" title="Jump back to footnote 373 in the text">&#8617;</a></p>
+</li>
+<li id="fn:374">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:374" title="Jump back to footnote 374 in the text">&#8617;</a></p>
+</li>
+<li id="fn:375">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:375" title="Jump back to footnote 375 in the text">&#8617;</a></p>
+</li>
+<li id="fn:376">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:376" title="Jump back to footnote 376 in the text">&#8617;</a></p>
+</li>
+<li id="fn:377">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:377" title="Jump back to footnote 377 in the text">&#8617;</a></p>
+</li>
+<li id="fn:378">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:378" title="Jump back to footnote 378 in the text">&#8617;</a></p>
+</li>
+<li id="fn:379">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:379" title="Jump back to footnote 379 in the text">&#8617;</a></p>
+</li>
+<li id="fn:380">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:380" title="Jump back to footnote 380 in the text">&#8617;</a></p>
+</li>
+<li id="fn:381">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:381" title="Jump back to footnote 381 in the text">&#8617;</a></p>
+</li>
+<li id="fn:382">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:382" title="Jump back to footnote 382 in the text">&#8617;</a></p>
+</li>
+<li id="fn:383">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:383" title="Jump back to footnote 383 in the text">&#8617;</a></p>
+</li>
+<li id="fn:384">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:384" title="Jump back to footnote 384 in the text">&#8617;</a></p>
+</li>
+<li id="fn:385">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:385" title="Jump back to footnote 385 in the text">&#8617;</a></p>
+</li>
+<li id="fn:386">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:386" title="Jump back to footnote 386 in the text">&#8617;</a></p>
+</li>
+<li id="fn:387">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:387" title="Jump back to footnote 387 in the text">&#8617;</a></p>
+</li>
+<li id="fn:388">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:388" title="Jump back to footnote 388 in the text">&#8617;</a></p>
+</li>
+<li id="fn:389">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:389" title="Jump back to footnote 389 in the text">&#8617;</a></p>
+</li>
+<li id="fn:390">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:390" title="Jump back to footnote 390 in the text">&#8617;</a></p>
+</li>
+<li id="fn:391">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:391" title="Jump back to footnote 391 in the text">&#8617;</a></p>
+</li>
+<li id="fn:392">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:392" title="Jump back to footnote 392 in the text">&#8617;</a></p>
+</li>
+<li id="fn:393">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:393" title="Jump back to footnote 393 in the text">&#8617;</a></p>
+</li>
+<li id="fn:394">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:394" title="Jump back to footnote 394 in the text">&#8617;</a></p>
+</li>
+<li id="fn:395">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:395" title="Jump back to footnote 395 in the text">&#8617;</a></p>
+</li>
+<li id="fn:396">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:396" title="Jump back to footnote 396 in the text">&#8617;</a></p>
+</li>
+<li id="fn:397">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:397" title="Jump back to footnote 397 in the text">&#8617;</a></p>
+</li>
+<li id="fn:398">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:398" title="Jump back to footnote 398 in the text">&#8617;</a></p>
+</li>
+<li id="fn:399">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:399" title="Jump back to footnote 399 in the text">&#8617;</a></p>
+</li>
+<li id="fn:400">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:400" title="Jump back to footnote 400 in the text">&#8617;</a></p>
+</li>
+<li id="fn:401">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:401" title="Jump back to footnote 401 in the text">&#8617;</a></p>
+</li>
+<li id="fn:402">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:402" title="Jump back to footnote 402 in the text">&#8617;</a></p>
+</li>
+<li id="fn:403">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:403" title="Jump back to footnote 403 in the text">&#8617;</a></p>
+</li>
+<li id="fn:404">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:404" title="Jump back to footnote 404 in the text">&#8617;</a></p>
+</li>
+<li id="fn:405">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:405" title="Jump back to footnote 405 in the text">&#8617;</a></p>
+</li>
+<li id="fn:406">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:406" title="Jump back to footnote 406 in the text">&#8617;</a></p>
+</li>
+<li id="fn:407">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:407" title="Jump back to footnote 407 in the text">&#8617;</a></p>
+</li>
+<li id="fn:408">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:408" title="Jump back to footnote 408 in the text">&#8617;</a></p>
+</li>
+<li id="fn:409">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:409" title="Jump back to footnote 409 in the text">&#8617;</a></p>
+</li>
+<li id="fn:410">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:410" title="Jump back to footnote 410 in the text">&#8617;</a></p>
+</li>
+<li id="fn:411">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:411" title="Jump back to footnote 411 in the text">&#8617;</a></p>
+</li>
+<li id="fn:412">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:412" title="Jump back to footnote 412 in the text">&#8617;</a></p>
+</li>
+<li id="fn:413">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:413" title="Jump back to footnote 413 in the text">&#8617;</a></p>
+</li>
+<li id="fn:414">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:414" title="Jump back to footnote 414 in the text">&#8617;</a></p>
+</li>
+<li id="fn:415">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:415" title="Jump back to footnote 415 in the text">&#8617;</a></p>
+</li>
+<li id="fn:416">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:416" title="Jump back to footnote 416 in the text">&#8617;</a></p>
+</li>
+<li id="fn:417">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:417" title="Jump back to footnote 417 in the text">&#8617;</a></p>
+</li>
+<li id="fn:418">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:418" title="Jump back to footnote 418 in the text">&#8617;</a></p>
+</li>
+<li id="fn:419">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:419" title="Jump back to footnote 419 in the text">&#8617;</a></p>
+</li>
+<li id="fn:420">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:420" title="Jump back to footnote 420 in the text">&#8617;</a></p>
+</li>
+<li id="fn:421">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:421" title="Jump back to footnote 421 in the text">&#8617;</a></p>
+</li>
+<li id="fn:422">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:422" title="Jump back to footnote 422 in the text">&#8617;</a></p>
+</li>
+<li id="fn:423">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:423" title="Jump back to footnote 423 in the text">&#8617;</a></p>
+</li>
+<li id="fn:424">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:424" title="Jump back to footnote 424 in the text">&#8617;</a></p>
+</li>
+<li id="fn:425">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:425" title="Jump back to footnote 425 in the text">&#8617;</a></p>
+</li>
+<li id="fn:426">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:426" title="Jump back to footnote 426 in the text">&#8617;</a></p>
+</li>
+<li id="fn:427">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:427" title="Jump back to footnote 427 in the text">&#8617;</a></p>
+</li>
+<li id="fn:428">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:428" title="Jump back to footnote 428 in the text">&#8617;</a></p>
+</li>
+<li id="fn:429">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:429" title="Jump back to footnote 429 in the text">&#8617;</a></p>
+</li>
+<li id="fn:430">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:430" title="Jump back to footnote 430 in the text">&#8617;</a></p>
+</li>
+<li id="fn:431">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:431" title="Jump back to footnote 431 in the text">&#8617;</a></p>
+</li>
+<li id="fn:432">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:432" title="Jump back to footnote 432 in the text">&#8617;</a></p>
+</li>
+<li id="fn:433">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:433" title="Jump back to footnote 433 in the text">&#8617;</a></p>
+</li>
+<li id="fn:434">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:434" title="Jump back to footnote 434 in the text">&#8617;</a></p>
+</li>
+<li id="fn:435">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:435" title="Jump back to footnote 435 in the text">&#8617;</a></p>
+</li>
+<li id="fn:436">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:436" title="Jump back to footnote 436 in the text">&#8617;</a></p>
+</li>
+<li id="fn:437">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:437" title="Jump back to footnote 437 in the text">&#8617;</a></p>
+</li>
+<li id="fn:438">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:438" title="Jump back to footnote 438 in the text">&#8617;</a></p>
+</li>
+<li id="fn:439">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:439" title="Jump back to footnote 439 in the text">&#8617;</a></p>
+</li>
+<li id="fn:440">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:440" title="Jump back to footnote 440 in the text">&#8617;</a></p>
+</li>
+<li id="fn:441">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:441" title="Jump back to footnote 441 in the text">&#8617;</a></p>
+</li>
+<li id="fn:442">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:442" title="Jump back to footnote 442 in the text">&#8617;</a></p>
+</li>
+<li id="fn:443">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:443" title="Jump back to footnote 443 in the text">&#8617;</a></p>
+</li>
+<li id="fn:444">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:444" title="Jump back to footnote 444 in the text">&#8617;</a></p>
+</li>
+<li id="fn:445">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:445" title="Jump back to footnote 445 in the text">&#8617;</a></p>
+</li>
+<li id="fn:446">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:446" title="Jump back to footnote 446 in the text">&#8617;</a></p>
+</li>
+<li id="fn:447">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:447" title="Jump back to footnote 447 in the text">&#8617;</a></p>
+</li>
+<li id="fn:448">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:448" title="Jump back to footnote 448 in the text">&#8617;</a></p>
+</li>
+<li id="fn:449">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:449" title="Jump back to footnote 449 in the text">&#8617;</a></p>
+</li>
+<li id="fn:450">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:450" title="Jump back to footnote 450 in the text">&#8617;</a></p>
+</li>
+<li id="fn:451">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:451" title="Jump back to footnote 451 in the text">&#8617;</a></p>
+</li>
+<li id="fn:452">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:452" title="Jump back to footnote 452 in the text">&#8617;</a></p>
+</li>
+<li id="fn:453">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:453" title="Jump back to footnote 453 in the text">&#8617;</a></p>
+</li>
+<li id="fn:454">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:454" title="Jump back to footnote 454 in the text">&#8617;</a></p>
+</li>
+<li id="fn:455">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:455" title="Jump back to footnote 455 in the text">&#8617;</a></p>
+</li>
+<li id="fn:456">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:456" title="Jump back to footnote 456 in the text">&#8617;</a></p>
+</li>
+<li id="fn:457">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:457" title="Jump back to footnote 457 in the text">&#8617;</a></p>
+</li>
+<li id="fn:458">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:458" title="Jump back to footnote 458 in the text">&#8617;</a></p>
+</li>
+<li id="fn:459">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:459" title="Jump back to footnote 459 in the text">&#8617;</a></p>
+</li>
+<li id="fn:460">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:460" title="Jump back to footnote 460 in the text">&#8617;</a></p>
+</li>
+<li id="fn:461">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:461" title="Jump back to footnote 461 in the text">&#8617;</a></p>
+</li>
+<li id="fn:462">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:462" title="Jump back to footnote 462 in the text">&#8617;</a></p>
+</li>
+<li id="fn:463">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:463" title="Jump back to footnote 463 in the text">&#8617;</a></p>
+</li>
+<li id="fn:464">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:464" title="Jump back to footnote 464 in the text">&#8617;</a></p>
+</li>
+<li id="fn:465">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:465" title="Jump back to footnote 465 in the text">&#8617;</a></p>
+</li>
+<li id="fn:466">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:466" title="Jump back to footnote 466 in the text">&#8617;</a></p>
+</li>
+<li id="fn:467">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:467" title="Jump back to footnote 467 in the text">&#8617;</a></p>
+</li>
+<li id="fn:468">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:468" title="Jump back to footnote 468 in the text">&#8617;</a></p>
+</li>
+<li id="fn:469">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:469" title="Jump back to footnote 469 in the text">&#8617;</a></p>
+</li>
+<li id="fn:470">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:470" title="Jump back to footnote 470 in the text">&#8617;</a></p>
+</li>
+<li id="fn:471">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:471" title="Jump back to footnote 471 in the text">&#8617;</a></p>
+</li>
+<li id="fn:472">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:472" title="Jump back to footnote 472 in the text">&#8617;</a></p>
+</li>
+<li id="fn:473">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:473" title="Jump back to footnote 473 in the text">&#8617;</a></p>
+</li>
+<li id="fn:474">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:474" title="Jump back to footnote 474 in the text">&#8617;</a></p>
+</li>
+<li id="fn:475">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:475" title="Jump back to footnote 475 in the text">&#8617;</a></p>
+</li>
+<li id="fn:476">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:476" title="Jump back to footnote 476 in the text">&#8617;</a></p>
+</li>
+<li id="fn:477">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:477" title="Jump back to footnote 477 in the text">&#8617;</a></p>
+</li>
+<li id="fn:478">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:478" title="Jump back to footnote 478 in the text">&#8617;</a></p>
+</li>
+<li id="fn:479">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:479" title="Jump back to footnote 479 in the text">&#8617;</a></p>
+</li>
+<li id="fn:480">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:480" title="Jump back to footnote 480 in the text">&#8617;</a></p>
+</li>
+<li id="fn:481">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:481" title="Jump back to footnote 481 in the text">&#8617;</a></p>
+</li>
+<li id="fn:482">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:482" title="Jump back to footnote 482 in the text">&#8617;</a></p>
+</li>
+<li id="fn:483">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:483" title="Jump back to footnote 483 in the text">&#8617;</a></p>
+</li>
+<li id="fn:484">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:484" title="Jump back to footnote 484 in the text">&#8617;</a></p>
+</li>
+<li id="fn:485">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:485" title="Jump back to footnote 485 in the text">&#8617;</a></p>
+</li>
+<li id="fn:486">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:486" title="Jump back to footnote 486 in the text">&#8617;</a></p>
+</li>
+<li id="fn:487">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:487" title="Jump back to footnote 487 in the text">&#8617;</a></p>
+</li>
+<li id="fn:488">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:488" title="Jump back to footnote 488 in the text">&#8617;</a></p>
+</li>
+<li id="fn:489">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:489" title="Jump back to footnote 489 in the text">&#8617;</a></p>
+</li>
+<li id="fn:490">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:490" title="Jump back to footnote 490 in the text">&#8617;</a></p>
+</li>
+<li id="fn:491">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:491" title="Jump back to footnote 491 in the text">&#8617;</a></p>
+</li>
+<li id="fn:492">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:492" title="Jump back to footnote 492 in the text">&#8617;</a></p>
+</li>
+<li id="fn:493">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:493" title="Jump back to footnote 493 in the text">&#8617;</a></p>
+</li>
+<li id="fn:494">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:494" title="Jump back to footnote 494 in the text">&#8617;</a></p>
+</li>
+<li id="fn:495">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:495" title="Jump back to footnote 495 in the text">&#8617;</a></p>
+</li>
+<li id="fn:496">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:496" title="Jump back to footnote 496 in the text">&#8617;</a></p>
+</li>
+<li id="fn:497">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:497" title="Jump back to footnote 497 in the text">&#8617;</a></p>
+</li>
+<li id="fn:498">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:498" title="Jump back to footnote 498 in the text">&#8617;</a></p>
+</li>
+<li id="fn:499">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:499" title="Jump back to footnote 499 in the text">&#8617;</a></p>
+</li>
+<li id="fn:500">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:500" title="Jump back to footnote 500 in the text">&#8617;</a></p>
+</li>
+<li id="fn:501">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:501" title="Jump back to footnote 501 in the text">&#8617;</a></p>
+</li>
+<li id="fn:502">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:502" title="Jump back to footnote 502 in the text">&#8617;</a></p>
+</li>
+<li id="fn:503">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:503" title="Jump back to footnote 503 in the text">&#8617;</a></p>
+</li>
+<li id="fn:504">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:504" title="Jump back to footnote 504 in the text">&#8617;</a></p>
+</li>
+<li id="fn:505">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:505" title="Jump back to footnote 505 in the text">&#8617;</a></p>
+</li>
+<li id="fn:506">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:506" title="Jump back to footnote 506 in the text">&#8617;</a></p>
+</li>
+<li id="fn:507">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:507" title="Jump back to footnote 507 in the text">&#8617;</a></p>
+</li>
+<li id="fn:508">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:508" title="Jump back to footnote 508 in the text">&#8617;</a></p>
+</li>
+<li id="fn:509">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:509" title="Jump back to footnote 509 in the text">&#8617;</a></p>
+</li>
+<li id="fn:510">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:510" title="Jump back to footnote 510 in the text">&#8617;</a></p>
+</li>
+<li id="fn:511">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:511" title="Jump back to footnote 511 in the text">&#8617;</a></p>
+</li>
+<li id="fn:512">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:512" title="Jump back to footnote 512 in the text">&#8617;</a></p>
+</li>
+<li id="fn:513">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:513" title="Jump back to footnote 513 in the text">&#8617;</a></p>
+</li>
+<li id="fn:514">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:514" title="Jump back to footnote 514 in the text">&#8617;</a></p>
+</li>
+<li id="fn:515">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:515" title="Jump back to footnote 515 in the text">&#8617;</a></p>
+</li>
+<li id="fn:516">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:516" title="Jump back to footnote 516 in the text">&#8617;</a></p>
+</li>
+<li id="fn:517">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:517" title="Jump back to footnote 517 in the text">&#8617;</a></p>
+</li>
+<li id="fn:518">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:518" title="Jump back to footnote 518 in the text">&#8617;</a></p>
+</li>
+<li id="fn:519">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:519" title="Jump back to footnote 519 in the text">&#8617;</a></p>
+</li>
+<li id="fn:520">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:520" title="Jump back to footnote 520 in the text">&#8617;</a></p>
+</li>
+<li id="fn:521">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:521" title="Jump back to footnote 521 in the text">&#8617;</a></p>
+</li>
+<li id="fn:522">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:522" title="Jump back to footnote 522 in the text">&#8617;</a></p>
+</li>
+<li id="fn:523">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:523" title="Jump back to footnote 523 in the text">&#8617;</a></p>
+</li>
+<li id="fn:524">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:524" title="Jump back to footnote 524 in the text">&#8617;</a></p>
+</li>
+<li id="fn:525">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:525" title="Jump back to footnote 525 in the text">&#8617;</a></p>
+</li>
+<li id="fn:526">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:526" title="Jump back to footnote 526 in the text">&#8617;</a></p>
+</li>
+<li id="fn:527">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:527" title="Jump back to footnote 527 in the text">&#8617;</a></p>
+</li>
+<li id="fn:528">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:528" title="Jump back to footnote 528 in the text">&#8617;</a></p>
+</li>
+<li id="fn:529">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:529" title="Jump back to footnote 529 in the text">&#8617;</a></p>
+</li>
+<li id="fn:530">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:530" title="Jump back to footnote 530 in the text">&#8617;</a></p>
+</li>
+<li id="fn:531">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:531" title="Jump back to footnote 531 in the text">&#8617;</a></p>
+</li>
+<li id="fn:532">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:532" title="Jump back to footnote 532 in the text">&#8617;</a></p>
+</li>
+<li id="fn:533">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:533" title="Jump back to footnote 533 in the text">&#8617;</a></p>
+</li>
+<li id="fn:534">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:534" title="Jump back to footnote 534 in the text">&#8617;</a></p>
+</li>
+<li id="fn:535">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:535" title="Jump back to footnote 535 in the text">&#8617;</a></p>
+</li>
+<li id="fn:536">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:536" title="Jump back to footnote 536 in the text">&#8617;</a></p>
+</li>
+<li id="fn:537">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:537" title="Jump back to footnote 537 in the text">&#8617;</a></p>
+</li>
+<li id="fn:538">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:538" title="Jump back to footnote 538 in the text">&#8617;</a></p>
+</li>
+<li id="fn:539">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:539" title="Jump back to footnote 539 in the text">&#8617;</a></p>
+</li>
+<li id="fn:540">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:540" title="Jump back to footnote 540 in the text">&#8617;</a></p>
+</li>
+<li id="fn:541">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:541" title="Jump back to footnote 541 in the text">&#8617;</a></p>
+</li>
+<li id="fn:542">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:542" title="Jump back to footnote 542 in the text">&#8617;</a></p>
+</li>
+<li id="fn:543">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:543" title="Jump back to footnote 543 in the text">&#8617;</a></p>
+</li>
+<li id="fn:544">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:544" title="Jump back to footnote 544 in the text">&#8617;</a></p>
+</li>
+<li id="fn:545">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:545" title="Jump back to footnote 545 in the text">&#8617;</a></p>
+</li>
+<li id="fn:546">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:546" title="Jump back to footnote 546 in the text">&#8617;</a></p>
+</li>
+<li id="fn:547">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:547" title="Jump back to footnote 547 in the text">&#8617;</a></p>
+</li>
+<li id="fn:548">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:548" title="Jump back to footnote 548 in the text">&#8617;</a></p>
+</li>
+<li id="fn:549">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:549" title="Jump back to footnote 549 in the text">&#8617;</a></p>
+</li>
+<li id="fn:550">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:550" title="Jump back to footnote 550 in the text">&#8617;</a></p>
+</li>
+<li id="fn:551">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:551" title="Jump back to footnote 551 in the text">&#8617;</a></p>
+</li>
+<li id="fn:552">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:552" title="Jump back to footnote 552 in the text">&#8617;</a></p>
+</li>
+<li id="fn:553">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:553" title="Jump back to footnote 553 in the text">&#8617;</a></p>
+</li>
+<li id="fn:554">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:554" title="Jump back to footnote 554 in the text">&#8617;</a></p>
+</li>
+<li id="fn:555">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:555" title="Jump back to footnote 555 in the text">&#8617;</a></p>
+</li>
+<li id="fn:556">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:556" title="Jump back to footnote 556 in the text">&#8617;</a></p>
+</li>
+<li id="fn:557">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:557" title="Jump back to footnote 557 in the text">&#8617;</a></p>
+</li>
+<li id="fn:558">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:558" title="Jump back to footnote 558 in the text">&#8617;</a></p>
+</li>
+<li id="fn:559">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:559" title="Jump back to footnote 559 in the text">&#8617;</a></p>
+</li>
+<li id="fn:560">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:560" title="Jump back to footnote 560 in the text">&#8617;</a></p>
+</li>
+<li id="fn:561">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:561" title="Jump back to footnote 561 in the text">&#8617;</a></p>
+</li>
+<li id="fn:562">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:562" title="Jump back to footnote 562 in the text">&#8617;</a></p>
+</li>
+<li id="fn:563">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:563" title="Jump back to footnote 563 in the text">&#8617;</a></p>
+</li>
+<li id="fn:564">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:564" title="Jump back to footnote 564 in the text">&#8617;</a></p>
+</li>
+<li id="fn:565">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:565" title="Jump back to footnote 565 in the text">&#8617;</a></p>
+</li>
+<li id="fn:566">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:566" title="Jump back to footnote 566 in the text">&#8617;</a></p>
+</li>
+<li id="fn:567">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:567" title="Jump back to footnote 567 in the text">&#8617;</a></p>
+</li>
+<li id="fn:568">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:568" title="Jump back to footnote 568 in the text">&#8617;</a></p>
+</li>
+<li id="fn:569">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:569" title="Jump back to footnote 569 in the text">&#8617;</a></p>
+</li>
+<li id="fn:570">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:570" title="Jump back to footnote 570 in the text">&#8617;</a></p>
+</li>
+<li id="fn:571">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:571" title="Jump back to footnote 571 in the text">&#8617;</a></p>
+</li>
+<li id="fn:572">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:572" title="Jump back to footnote 572 in the text">&#8617;</a></p>
+</li>
+<li id="fn:573">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:573" title="Jump back to footnote 573 in the text">&#8617;</a></p>
+</li>
+<li id="fn:574">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:574" title="Jump back to footnote 574 in the text">&#8617;</a></p>
+</li>
+<li id="fn:575">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:575" title="Jump back to footnote 575 in the text">&#8617;</a></p>
+</li>
+<li id="fn:576">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:576" title="Jump back to footnote 576 in the text">&#8617;</a></p>
+</li>
+<li id="fn:577">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:577" title="Jump back to footnote 577 in the text">&#8617;</a></p>
+</li>
+<li id="fn:578">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:578" title="Jump back to footnote 578 in the text">&#8617;</a></p>
+</li>
+<li id="fn:579">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:579" title="Jump back to footnote 579 in the text">&#8617;</a></p>
+</li>
+<li id="fn:580">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:580" title="Jump back to footnote 580 in the text">&#8617;</a></p>
+</li>
+<li id="fn:581">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:581" title="Jump back to footnote 581 in the text">&#8617;</a></p>
+</li>
+<li id="fn:582">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:582" title="Jump back to footnote 582 in the text">&#8617;</a></p>
+</li>
+<li id="fn:583">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:583" title="Jump back to footnote 583 in the text">&#8617;</a></p>
+</li>
+<li id="fn:584">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:584" title="Jump back to footnote 584 in the text">&#8617;</a></p>
+</li>
+<li id="fn:585">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:585" title="Jump back to footnote 585 in the text">&#8617;</a></p>
+</li>
+<li id="fn:586">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:586" title="Jump back to footnote 586 in the text">&#8617;</a></p>
+</li>
+<li id="fn:587">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:587" title="Jump back to footnote 587 in the text">&#8617;</a></p>
+</li>
+<li id="fn:588">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:588" title="Jump back to footnote 588 in the text">&#8617;</a></p>
+</li>
+<li id="fn:589">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:589" title="Jump back to footnote 589 in the text">&#8617;</a></p>
+</li>
+<li id="fn:590">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:590" title="Jump back to footnote 590 in the text">&#8617;</a></p>
+</li>
+<li id="fn:591">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:591" title="Jump back to footnote 591 in the text">&#8617;</a></p>
+</li>
+<li id="fn:592">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:592" title="Jump back to footnote 592 in the text">&#8617;</a></p>
+</li>
+<li id="fn:593">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:593" title="Jump back to footnote 593 in the text">&#8617;</a></p>
+</li>
+<li id="fn:594">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:594" title="Jump back to footnote 594 in the text">&#8617;</a></p>
+</li>
+<li id="fn:595">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:595" title="Jump back to footnote 595 in the text">&#8617;</a></p>
+</li>
+<li id="fn:596">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:596" title="Jump back to footnote 596 in the text">&#8617;</a></p>
+</li>
+<li id="fn:597">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:597" title="Jump back to footnote 597 in the text">&#8617;</a></p>
+</li>
+<li id="fn:598">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:598" title="Jump back to footnote 598 in the text">&#8617;</a></p>
+</li>
+<li id="fn:599">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:599" title="Jump back to footnote 599 in the text">&#8617;</a></p>
+</li>
+<li id="fn:600">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:600" title="Jump back to footnote 600 in the text">&#8617;</a></p>
+</li>
+<li id="fn:601">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:601" title="Jump back to footnote 601 in the text">&#8617;</a></p>
+</li>
+<li id="fn:602">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:602" title="Jump back to footnote 602 in the text">&#8617;</a></p>
+</li>
+<li id="fn:603">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:603" title="Jump back to footnote 603 in the text">&#8617;</a></p>
+</li>
+<li id="fn:604">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:604" title="Jump back to footnote 604 in the text">&#8617;</a></p>
+</li>
+<li id="fn:605">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:605" title="Jump back to footnote 605 in the text">&#8617;</a></p>
+</li>
+<li id="fn:606">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:606" title="Jump back to footnote 606 in the text">&#8617;</a></p>
+</li>
+<li id="fn:607">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:607" title="Jump back to footnote 607 in the text">&#8617;</a></p>
+</li>
+<li id="fn:608">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:608" title="Jump back to footnote 608 in the text">&#8617;</a></p>
+</li>
+<li id="fn:609">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:609" title="Jump back to footnote 609 in the text">&#8617;</a></p>
+</li>
+<li id="fn:610">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:610" title="Jump back to footnote 610 in the text">&#8617;</a></p>
+</li>
+<li id="fn:611">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:611" title="Jump back to footnote 611 in the text">&#8617;</a></p>
+</li>
+<li id="fn:612">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:612" title="Jump back to footnote 612 in the text">&#8617;</a></p>
+</li>
+<li id="fn:613">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:613" title="Jump back to footnote 613 in the text">&#8617;</a></p>
+</li>
+<li id="fn:614">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:614" title="Jump back to footnote 614 in the text">&#8617;</a></p>
+</li>
+<li id="fn:615">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:615" title="Jump back to footnote 615 in the text">&#8617;</a></p>
+</li>
+<li id="fn:616">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:616" title="Jump back to footnote 616 in the text">&#8617;</a></p>
+</li>
+<li id="fn:617">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:617" title="Jump back to footnote 617 in the text">&#8617;</a></p>
+</li>
+<li id="fn:618">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:618" title="Jump back to footnote 618 in the text">&#8617;</a></p>
+</li>
+<li id="fn:619">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:619" title="Jump back to footnote 619 in the text">&#8617;</a></p>
+</li>
+<li id="fn:620">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:620" title="Jump back to footnote 620 in the text">&#8617;</a></p>
+</li>
+<li id="fn:621">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:621" title="Jump back to footnote 621 in the text">&#8617;</a></p>
+</li>
+<li id="fn:622">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:622" title="Jump back to footnote 622 in the text">&#8617;</a></p>
+</li>
+<li id="fn:623">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:623" title="Jump back to footnote 623 in the text">&#8617;</a></p>
+</li>
+<li id="fn:624">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:624" title="Jump back to footnote 624 in the text">&#8617;</a></p>
+</li>
+<li id="fn:625">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:625" title="Jump back to footnote 625 in the text">&#8617;</a></p>
+</li>
+<li id="fn:626">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:626" title="Jump back to footnote 626 in the text">&#8617;</a></p>
+</li>
+<li id="fn:627">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:627" title="Jump back to footnote 627 in the text">&#8617;</a></p>
+</li>
+<li id="fn:628">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:628" title="Jump back to footnote 628 in the text">&#8617;</a></p>
+</li>
+<li id="fn:629">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:629" title="Jump back to footnote 629 in the text">&#8617;</a></p>
+</li>
+<li id="fn:630">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:630" title="Jump back to footnote 630 in the text">&#8617;</a></p>
+</li>
+<li id="fn:631">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:631" title="Jump back to footnote 631 in the text">&#8617;</a></p>
+</li>
+<li id="fn:632">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:632" title="Jump back to footnote 632 in the text">&#8617;</a></p>
+</li>
+<li id="fn:633">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:633" title="Jump back to footnote 633 in the text">&#8617;</a></p>
+</li>
+<li id="fn:634">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:634" title="Jump back to footnote 634 in the text">&#8617;</a></p>
+</li>
+<li id="fn:635">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:635" title="Jump back to footnote 635 in the text">&#8617;</a></p>
+</li>
+<li id="fn:636">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:636" title="Jump back to footnote 636 in the text">&#8617;</a></p>
+</li>
+<li id="fn:637">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:637" title="Jump back to footnote 637 in the text">&#8617;</a></p>
+</li>
+<li id="fn:638">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:638" title="Jump back to footnote 638 in the text">&#8617;</a></p>
+</li>
+<li id="fn:639">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:639" title="Jump back to footnote 639 in the text">&#8617;</a></p>
+</li>
+<li id="fn:640">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:640" title="Jump back to footnote 640 in the text">&#8617;</a></p>
+</li>
+<li id="fn:641">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:641" title="Jump back to footnote 641 in the text">&#8617;</a></p>
+</li>
+<li id="fn:642">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:642" title="Jump back to footnote 642 in the text">&#8617;</a></p>
+</li>
+<li id="fn:643">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:643" title="Jump back to footnote 643 in the text">&#8617;</a></p>
+</li>
+<li id="fn:644">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:644" title="Jump back to footnote 644 in the text">&#8617;</a></p>
+</li>
+<li id="fn:645">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:645" title="Jump back to footnote 645 in the text">&#8617;</a></p>
+</li>
+<li id="fn:646">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:646" title="Jump back to footnote 646 in the text">&#8617;</a></p>
+</li>
+<li id="fn:647">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:647" title="Jump back to footnote 647 in the text">&#8617;</a></p>
+</li>
+<li id="fn:648">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:648" title="Jump back to footnote 648 in the text">&#8617;</a></p>
+</li>
+<li id="fn:649">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:649" title="Jump back to footnote 649 in the text">&#8617;</a></p>
+</li>
+<li id="fn:650">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:650" title="Jump back to footnote 650 in the text">&#8617;</a></p>
+</li>
+<li id="fn:651">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:651" title="Jump back to footnote 651 in the text">&#8617;</a></p>
+</li>
+<li id="fn:652">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:652" title="Jump back to footnote 652 in the text">&#8617;</a></p>
+</li>
+<li id="fn:653">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:653" title="Jump back to footnote 653 in the text">&#8617;</a></p>
+</li>
+<li id="fn:654">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:654" title="Jump back to footnote 654 in the text">&#8617;</a></p>
+</li>
+<li id="fn:655">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:655" title="Jump back to footnote 655 in the text">&#8617;</a></p>
+</li>
+<li id="fn:656">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:656" title="Jump back to footnote 656 in the text">&#8617;</a></p>
+</li>
+<li id="fn:657">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:657" title="Jump back to footnote 657 in the text">&#8617;</a></p>
+</li>
+<li id="fn:658">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:658" title="Jump back to footnote 658 in the text">&#8617;</a></p>
+</li>
+<li id="fn:659">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:659" title="Jump back to footnote 659 in the text">&#8617;</a></p>
+</li>
+<li id="fn:660">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:660" title="Jump back to footnote 660 in the text">&#8617;</a></p>
+</li>
+<li id="fn:661">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:661" title="Jump back to footnote 661 in the text">&#8617;</a></p>
+</li>
+<li id="fn:662">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:662" title="Jump back to footnote 662 in the text">&#8617;</a></p>
+</li>
+<li id="fn:663">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:663" title="Jump back to footnote 663 in the text">&#8617;</a></p>
+</li>
+<li id="fn:664">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:664" title="Jump back to footnote 664 in the text">&#8617;</a></p>
+</li>
+<li id="fn:665">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:665" title="Jump back to footnote 665 in the text">&#8617;</a></p>
+</li>
+<li id="fn:666">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:666" title="Jump back to footnote 666 in the text">&#8617;</a></p>
+</li>
+<li id="fn:667">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:667" title="Jump back to footnote 667 in the text">&#8617;</a></p>
+</li>
+<li id="fn:668">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:668" title="Jump back to footnote 668 in the text">&#8617;</a></p>
+</li>
+<li id="fn:669">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:669" title="Jump back to footnote 669 in the text">&#8617;</a></p>
+</li>
+<li id="fn:670">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:670" title="Jump back to footnote 670 in the text">&#8617;</a></p>
+</li>
+<li id="fn:671">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:671" title="Jump back to footnote 671 in the text">&#8617;</a></p>
+</li>
+<li id="fn:672">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:672" title="Jump back to footnote 672 in the text">&#8617;</a></p>
+</li>
+<li id="fn:673">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:673" title="Jump back to footnote 673 in the text">&#8617;</a></p>
+</li>
+<li id="fn:674">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:674" title="Jump back to footnote 674 in the text">&#8617;</a></p>
+</li>
+<li id="fn:675">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:675" title="Jump back to footnote 675 in the text">&#8617;</a></p>
+</li>
+<li id="fn:676">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:676" title="Jump back to footnote 676 in the text">&#8617;</a></p>
+</li>
+<li id="fn:677">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:677" title="Jump back to footnote 677 in the text">&#8617;</a></p>
+</li>
+<li id="fn:678">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:678" title="Jump back to footnote 678 in the text">&#8617;</a></p>
+</li>
+<li id="fn:679">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:679" title="Jump back to footnote 679 in the text">&#8617;</a></p>
+</li>
+<li id="fn:680">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:680" title="Jump back to footnote 680 in the text">&#8617;</a></p>
+</li>
+<li id="fn:681">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:681" title="Jump back to footnote 681 in the text">&#8617;</a></p>
+</li>
+<li id="fn:682">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:682" title="Jump back to footnote 682 in the text">&#8617;</a></p>
+</li>
+<li id="fn:683">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:683" title="Jump back to footnote 683 in the text">&#8617;</a></p>
+</li>
+<li id="fn:684">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:684" title="Jump back to footnote 684 in the text">&#8617;</a></p>
+</li>
+<li id="fn:685">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:685" title="Jump back to footnote 685 in the text">&#8617;</a></p>
+</li>
+<li id="fn:686">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:686" title="Jump back to footnote 686 in the text">&#8617;</a></p>
+</li>
+<li id="fn:687">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:687" title="Jump back to footnote 687 in the text">&#8617;</a></p>
+</li>
+<li id="fn:688">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:688" title="Jump back to footnote 688 in the text">&#8617;</a></p>
+</li>
+<li id="fn:689">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:689" title="Jump back to footnote 689 in the text">&#8617;</a></p>
+</li>
+<li id="fn:690">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:690" title="Jump back to footnote 690 in the text">&#8617;</a></p>
+</li>
+<li id="fn:691">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:691" title="Jump back to footnote 691 in the text">&#8617;</a></p>
+</li>
+<li id="fn:692">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:692" title="Jump back to footnote 692 in the text">&#8617;</a></p>
+</li>
+<li id="fn:693">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:693" title="Jump back to footnote 693 in the text">&#8617;</a></p>
+</li>
+<li id="fn:694">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:694" title="Jump back to footnote 694 in the text">&#8617;</a></p>
+</li>
+<li id="fn:695">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:695" title="Jump back to footnote 695 in the text">&#8617;</a></p>
+</li>
+<li id="fn:696">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:696" title="Jump back to footnote 696 in the text">&#8617;</a></p>
+</li>
+<li id="fn:697">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:697" title="Jump back to footnote 697 in the text">&#8617;</a></p>
+</li>
+<li id="fn:698">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:698" title="Jump back to footnote 698 in the text">&#8617;</a></p>
+</li>
+<li id="fn:699">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:699" title="Jump back to footnote 699 in the text">&#8617;</a></p>
+</li>
+<li id="fn:700">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:700" title="Jump back to footnote 700 in the text">&#8617;</a></p>
+</li>
+<li id="fn:701">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:701" title="Jump back to footnote 701 in the text">&#8617;</a></p>
+</li>
+<li id="fn:702">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:702" title="Jump back to footnote 702 in the text">&#8617;</a></p>
+</li>
+<li id="fn:703">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:703" title="Jump back to footnote 703 in the text">&#8617;</a></p>
+</li>
+<li id="fn:704">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:704" title="Jump back to footnote 704 in the text">&#8617;</a></p>
+</li>
+<li id="fn:705">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:705" title="Jump back to footnote 705 in the text">&#8617;</a></p>
+</li>
+<li id="fn:706">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:706" title="Jump back to footnote 706 in the text">&#8617;</a></p>
+</li>
+<li id="fn:707">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:707" title="Jump back to footnote 707 in the text">&#8617;</a></p>
+</li>
+<li id="fn:708">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:708" title="Jump back to footnote 708 in the text">&#8617;</a></p>
+</li>
+<li id="fn:709">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:709" title="Jump back to footnote 709 in the text">&#8617;</a></p>
+</li>
+<li id="fn:710">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:710" title="Jump back to footnote 710 in the text">&#8617;</a></p>
+</li>
+<li id="fn:711">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:711" title="Jump back to footnote 711 in the text">&#8617;</a></p>
+</li>
+<li id="fn:712">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:712" title="Jump back to footnote 712 in the text">&#8617;</a></p>
+</li>
+<li id="fn:713">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:713" title="Jump back to footnote 713 in the text">&#8617;</a></p>
+</li>
+<li id="fn:714">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:714" title="Jump back to footnote 714 in the text">&#8617;</a></p>
+</li>
+<li id="fn:715">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:715" title="Jump back to footnote 715 in the text">&#8617;</a></p>
+</li>
+<li id="fn:716">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:716" title="Jump back to footnote 716 in the text">&#8617;</a></p>
+</li>
+<li id="fn:717">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:717" title="Jump back to footnote 717 in the text">&#8617;</a></p>
+</li>
+<li id="fn:718">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:718" title="Jump back to footnote 718 in the text">&#8617;</a></p>
+</li>
+<li id="fn:719">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:719" title="Jump back to footnote 719 in the text">&#8617;</a></p>
+</li>
+<li id="fn:720">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:720" title="Jump back to footnote 720 in the text">&#8617;</a></p>
+</li>
+<li id="fn:721">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:721" title="Jump back to footnote 721 in the text">&#8617;</a></p>
+</li>
+<li id="fn:722">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:722" title="Jump back to footnote 722 in the text">&#8617;</a></p>
+</li>
+<li id="fn:723">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:723" title="Jump back to footnote 723 in the text">&#8617;</a></p>
+</li>
+<li id="fn:724">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:724" title="Jump back to footnote 724 in the text">&#8617;</a></p>
+</li>
+<li id="fn:725">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:725" title="Jump back to footnote 725 in the text">&#8617;</a></p>
+</li>
+<li id="fn:726">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:726" title="Jump back to footnote 726 in the text">&#8617;</a></p>
+</li>
+<li id="fn:727">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:727" title="Jump back to footnote 727 in the text">&#8617;</a></p>
+</li>
+<li id="fn:728">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:728" title="Jump back to footnote 728 in the text">&#8617;</a></p>
+</li>
+<li id="fn:729">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:729" title="Jump back to footnote 729 in the text">&#8617;</a></p>
+</li>
+<li id="fn:730">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:730" title="Jump back to footnote 730 in the text">&#8617;</a></p>
+</li>
+<li id="fn:731">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:731" title="Jump back to footnote 731 in the text">&#8617;</a></p>
+</li>
+<li id="fn:732">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:732" title="Jump back to footnote 732 in the text">&#8617;</a></p>
+</li>
+<li id="fn:733">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:733" title="Jump back to footnote 733 in the text">&#8617;</a></p>
+</li>
+<li id="fn:734">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:734" title="Jump back to footnote 734 in the text">&#8617;</a></p>
+</li>
+<li id="fn:735">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:735" title="Jump back to footnote 735 in the text">&#8617;</a></p>
+</li>
+<li id="fn:736">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:736" title="Jump back to footnote 736 in the text">&#8617;</a></p>
+</li>
+<li id="fn:737">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:737" title="Jump back to footnote 737 in the text">&#8617;</a></p>
+</li>
+<li id="fn:738">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:738" title="Jump back to footnote 738 in the text">&#8617;</a></p>
+</li>
+<li id="fn:739">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:739" title="Jump back to footnote 739 in the text">&#8617;</a></p>
+</li>
+<li id="fn:740">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:740" title="Jump back to footnote 740 in the text">&#8617;</a></p>
+</li>
+<li id="fn:741">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:741" title="Jump back to footnote 741 in the text">&#8617;</a></p>
+</li>
+<li id="fn:742">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:742" title="Jump back to footnote 742 in the text">&#8617;</a></p>
+</li>
+<li id="fn:743">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:743" title="Jump back to footnote 743 in the text">&#8617;</a></p>
+</li>
+<li id="fn:744">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:744" title="Jump back to footnote 744 in the text">&#8617;</a></p>
+</li>
+<li id="fn:745">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:745" title="Jump back to footnote 745 in the text">&#8617;</a></p>
+</li>
+<li id="fn:746">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:746" title="Jump back to footnote 746 in the text">&#8617;</a></p>
+</li>
+<li id="fn:747">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:747" title="Jump back to footnote 747 in the text">&#8617;</a></p>
+</li>
+<li id="fn:748">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:748" title="Jump back to footnote 748 in the text">&#8617;</a></p>
+</li>
+<li id="fn:749">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:749" title="Jump back to footnote 749 in the text">&#8617;</a></p>
+</li>
+<li id="fn:750">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:750" title="Jump back to footnote 750 in the text">&#8617;</a></p>
+</li>
+<li id="fn:751">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:751" title="Jump back to footnote 751 in the text">&#8617;</a></p>
+</li>
+<li id="fn:752">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:752" title="Jump back to footnote 752 in the text">&#8617;</a></p>
+</li>
+<li id="fn:753">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:753" title="Jump back to footnote 753 in the text">&#8617;</a></p>
+</li>
+<li id="fn:754">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:754" title="Jump back to footnote 754 in the text">&#8617;</a></p>
+</li>
+<li id="fn:755">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:755" title="Jump back to footnote 755 in the text">&#8617;</a></p>
+</li>
+<li id="fn:756">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:756" title="Jump back to footnote 756 in the text">&#8617;</a></p>
+</li>
+<li id="fn:757">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:757" title="Jump back to footnote 757 in the text">&#8617;</a></p>
+</li>
+<li id="fn:758">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:758" title="Jump back to footnote 758 in the text">&#8617;</a></p>
+</li>
+<li id="fn:759">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:759" title="Jump back to footnote 759 in the text">&#8617;</a></p>
+</li>
+<li id="fn:760">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:760" title="Jump back to footnote 760 in the text">&#8617;</a></p>
+</li>
+<li id="fn:761">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:761" title="Jump back to footnote 761 in the text">&#8617;</a></p>
+</li>
+<li id="fn:762">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:762" title="Jump back to footnote 762 in the text">&#8617;</a></p>
+</li>
+<li id="fn:763">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:763" title="Jump back to footnote 763 in the text">&#8617;</a></p>
+</li>
+<li id="fn:764">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:764" title="Jump back to footnote 764 in the text">&#8617;</a></p>
+</li>
+<li id="fn:765">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:765" title="Jump back to footnote 765 in the text">&#8617;</a></p>
+</li>
+<li id="fn:766">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:766" title="Jump back to footnote 766 in the text">&#8617;</a></p>
+</li>
+<li id="fn:767">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:767" title="Jump back to footnote 767 in the text">&#8617;</a></p>
+</li>
+<li id="fn:768">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:768" title="Jump back to footnote 768 in the text">&#8617;</a></p>
+</li>
+<li id="fn:769">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:769" title="Jump back to footnote 769 in the text">&#8617;</a></p>
+</li>
+<li id="fn:770">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:770" title="Jump back to footnote 770 in the text">&#8617;</a></p>
+</li>
+<li id="fn:771">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:771" title="Jump back to footnote 771 in the text">&#8617;</a></p>
+</li>
+<li id="fn:772">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:772" title="Jump back to footnote 772 in the text">&#8617;</a></p>
+</li>
+<li id="fn:773">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:773" title="Jump back to footnote 773 in the text">&#8617;</a></p>
+</li>
+<li id="fn:774">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:774" title="Jump back to footnote 774 in the text">&#8617;</a></p>
+</li>
+<li id="fn:775">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:775" title="Jump back to footnote 775 in the text">&#8617;</a></p>
+</li>
+<li id="fn:776">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:776" title="Jump back to footnote 776 in the text">&#8617;</a></p>
+</li>
+<li id="fn:777">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:777" title="Jump back to footnote 777 in the text">&#8617;</a></p>
+</li>
+<li id="fn:778">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:778" title="Jump back to footnote 778 in the text">&#8617;</a></p>
+</li>
+<li id="fn:779">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:779" title="Jump back to footnote 779 in the text">&#8617;</a></p>
+</li>
+<li id="fn:780">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:780" title="Jump back to footnote 780 in the text">&#8617;</a></p>
+</li>
+<li id="fn:781">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:781" title="Jump back to footnote 781 in the text">&#8617;</a></p>
+</li>
+<li id="fn:782">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:782" title="Jump back to footnote 782 in the text">&#8617;</a></p>
+</li>
+<li id="fn:783">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:783" title="Jump back to footnote 783 in the text">&#8617;</a></p>
+</li>
+<li id="fn:784">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:784" title="Jump back to footnote 784 in the text">&#8617;</a></p>
+</li>
+<li id="fn:785">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:785" title="Jump back to footnote 785 in the text">&#8617;</a></p>
+</li>
+<li id="fn:786">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:786" title="Jump back to footnote 786 in the text">&#8617;</a></p>
+</li>
+<li id="fn:787">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:787" title="Jump back to footnote 787 in the text">&#8617;</a></p>
+</li>
+<li id="fn:788">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:788" title="Jump back to footnote 788 in the text">&#8617;</a></p>
+</li>
+<li id="fn:789">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:789" title="Jump back to footnote 789 in the text">&#8617;</a></p>
+</li>
+<li id="fn:790">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:790" title="Jump back to footnote 790 in the text">&#8617;</a></p>
+</li>
+<li id="fn:791">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:791" title="Jump back to footnote 791 in the text">&#8617;</a></p>
+</li>
+<li id="fn:792">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:792" title="Jump back to footnote 792 in the text">&#8617;</a></p>
+</li>
+<li id="fn:793">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:793" title="Jump back to footnote 793 in the text">&#8617;</a></p>
+</li>
+<li id="fn:794">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:794" title="Jump back to footnote 794 in the text">&#8617;</a></p>
+</li>
+<li id="fn:795">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:795" title="Jump back to footnote 795 in the text">&#8617;</a></p>
+</li>
+<li id="fn:796">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:796" title="Jump back to footnote 796 in the text">&#8617;</a></p>
+</li>
+<li id="fn:797">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:797" title="Jump back to footnote 797 in the text">&#8617;</a></p>
+</li>
+<li id="fn:798">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:798" title="Jump back to footnote 798 in the text">&#8617;</a></p>
+</li>
+<li id="fn:799">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:799" title="Jump back to footnote 799 in the text">&#8617;</a></p>
+</li>
+<li id="fn:800">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:800" title="Jump back to footnote 800 in the text">&#8617;</a></p>
+</li>
+<li id="fn:801">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:801" title="Jump back to footnote 801 in the text">&#8617;</a></p>
+</li>
+<li id="fn:802">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:802" title="Jump back to footnote 802 in the text">&#8617;</a></p>
+</li>
+<li id="fn:803">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:803" title="Jump back to footnote 803 in the text">&#8617;</a></p>
+</li>
+<li id="fn:804">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:804" title="Jump back to footnote 804 in the text">&#8617;</a></p>
+</li>
+<li id="fn:805">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:805" title="Jump back to footnote 805 in the text">&#8617;</a></p>
+</li>
+<li id="fn:806">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:806" title="Jump back to footnote 806 in the text">&#8617;</a></p>
+</li>
+<li id="fn:807">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:807" title="Jump back to footnote 807 in the text">&#8617;</a></p>
+</li>
+<li id="fn:808">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:808" title="Jump back to footnote 808 in the text">&#8617;</a></p>
+</li>
+<li id="fn:809">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:809" title="Jump back to footnote 809 in the text">&#8617;</a></p>
+</li>
+<li id="fn:810">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:810" title="Jump back to footnote 810 in the text">&#8617;</a></p>
+</li>
+<li id="fn:811">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:811" title="Jump back to footnote 811 in the text">&#8617;</a></p>
+</li>
+<li id="fn:812">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:812" title="Jump back to footnote 812 in the text">&#8617;</a></p>
+</li>
+<li id="fn:813">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:813" title="Jump back to footnote 813 in the text">&#8617;</a></p>
+</li>
+<li id="fn:814">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:814" title="Jump back to footnote 814 in the text">&#8617;</a></p>
+</li>
+<li id="fn:815">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:815" title="Jump back to footnote 815 in the text">&#8617;</a></p>
+</li>
+<li id="fn:816">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:816" title="Jump back to footnote 816 in the text">&#8617;</a></p>
+</li>
+<li id="fn:817">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:817" title="Jump back to footnote 817 in the text">&#8617;</a></p>
+</li>
+<li id="fn:818">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:818" title="Jump back to footnote 818 in the text">&#8617;</a></p>
+</li>
+<li id="fn:819">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:819" title="Jump back to footnote 819 in the text">&#8617;</a></p>
+</li>
+<li id="fn:820">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:820" title="Jump back to footnote 820 in the text">&#8617;</a></p>
+</li>
+<li id="fn:821">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:821" title="Jump back to footnote 821 in the text">&#8617;</a></p>
+</li>
+<li id="fn:822">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:822" title="Jump back to footnote 822 in the text">&#8617;</a></p>
+</li>
+<li id="fn:823">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:823" title="Jump back to footnote 823 in the text">&#8617;</a></p>
+</li>
+<li id="fn:824">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:824" title="Jump back to footnote 824 in the text">&#8617;</a></p>
+</li>
+<li id="fn:825">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:825" title="Jump back to footnote 825 in the text">&#8617;</a></p>
+</li>
+<li id="fn:826">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:826" title="Jump back to footnote 826 in the text">&#8617;</a></p>
+</li>
+<li id="fn:827">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:827" title="Jump back to footnote 827 in the text">&#8617;</a></p>
+</li>
+<li id="fn:828">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:828" title="Jump back to footnote 828 in the text">&#8617;</a></p>
+</li>
+<li id="fn:829">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:829" title="Jump back to footnote 829 in the text">&#8617;</a></p>
+</li>
+<li id="fn:830">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:830" title="Jump back to footnote 830 in the text">&#8617;</a></p>
+</li>
+<li id="fn:831">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:831" title="Jump back to footnote 831 in the text">&#8617;</a></p>
+</li>
+<li id="fn:832">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:832" title="Jump back to footnote 832 in the text">&#8617;</a></p>
+</li>
+<li id="fn:833">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:833" title="Jump back to footnote 833 in the text">&#8617;</a></p>
+</li>
+<li id="fn:834">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:834" title="Jump back to footnote 834 in the text">&#8617;</a></p>
+</li>
+<li id="fn:835">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:835" title="Jump back to footnote 835 in the text">&#8617;</a></p>
+</li>
+<li id="fn:836">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:836" title="Jump back to footnote 836 in the text">&#8617;</a></p>
+</li>
+<li id="fn:837">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:837" title="Jump back to footnote 837 in the text">&#8617;</a></p>
+</li>
+<li id="fn:838">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:838" title="Jump back to footnote 838 in the text">&#8617;</a></p>
+</li>
+<li id="fn:839">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:839" title="Jump back to footnote 839 in the text">&#8617;</a></p>
+</li>
+<li id="fn:840">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:840" title="Jump back to footnote 840 in the text">&#8617;</a></p>
+</li>
+<li id="fn:841">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:841" title="Jump back to footnote 841 in the text">&#8617;</a></p>
+</li>
+<li id="fn:842">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:842" title="Jump back to footnote 842 in the text">&#8617;</a></p>
+</li>
+<li id="fn:843">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:843" title="Jump back to footnote 843 in the text">&#8617;</a></p>
+</li>
+<li id="fn:844">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:844" title="Jump back to footnote 844 in the text">&#8617;</a></p>
+</li>
+<li id="fn:845">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:845" title="Jump back to footnote 845 in the text">&#8617;</a></p>
+</li>
+<li id="fn:846">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:846" title="Jump back to footnote 846 in the text">&#8617;</a></p>
+</li>
+<li id="fn:847">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:847" title="Jump back to footnote 847 in the text">&#8617;</a></p>
+</li>
+<li id="fn:848">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:848" title="Jump back to footnote 848 in the text">&#8617;</a></p>
+</li>
+<li id="fn:849">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:849" title="Jump back to footnote 849 in the text">&#8617;</a></p>
+</li>
+<li id="fn:850">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:850" title="Jump back to footnote 850 in the text">&#8617;</a></p>
+</li>
+<li id="fn:851">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:851" title="Jump back to footnote 851 in the text">&#8617;</a></p>
+</li>
+<li id="fn:852">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:852" title="Jump back to footnote 852 in the text">&#8617;</a></p>
+</li>
+<li id="fn:853">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:853" title="Jump back to footnote 853 in the text">&#8617;</a></p>
+</li>
+<li id="fn:854">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:854" title="Jump back to footnote 854 in the text">&#8617;</a></p>
+</li>
+<li id="fn:855">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:855" title="Jump back to footnote 855 in the text">&#8617;</a></p>
+</li>
+<li id="fn:856">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:856" title="Jump back to footnote 856 in the text">&#8617;</a></p>
+</li>
+<li id="fn:857">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:857" title="Jump back to footnote 857 in the text">&#8617;</a></p>
+</li>
+<li id="fn:858">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:858" title="Jump back to footnote 858 in the text">&#8617;</a></p>
+</li>
+<li id="fn:859">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:859" title="Jump back to footnote 859 in the text">&#8617;</a></p>
+</li>
+<li id="fn:860">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:860" title="Jump back to footnote 860 in the text">&#8617;</a></p>
+</li>
+<li id="fn:861">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:861" title="Jump back to footnote 861 in the text">&#8617;</a></p>
+</li>
+<li id="fn:862">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:862" title="Jump back to footnote 862 in the text">&#8617;</a></p>
+</li>
+<li id="fn:863">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:863" title="Jump back to footnote 863 in the text">&#8617;</a></p>
+</li>
+<li id="fn:864">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:864" title="Jump back to footnote 864 in the text">&#8617;</a></p>
+</li>
+<li id="fn:865">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:865" title="Jump back to footnote 865 in the text">&#8617;</a></p>
+</li>
+<li id="fn:866">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:866" title="Jump back to footnote 866 in the text">&#8617;</a></p>
+</li>
+<li id="fn:867">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:867" title="Jump back to footnote 867 in the text">&#8617;</a></p>
+</li>
+<li id="fn:868">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:868" title="Jump back to footnote 868 in the text">&#8617;</a></p>
+</li>
+<li id="fn:869">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:869" title="Jump back to footnote 869 in the text">&#8617;</a></p>
+</li>
+<li id="fn:870">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:870" title="Jump back to footnote 870 in the text">&#8617;</a></p>
+</li>
+<li id="fn:871">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:871" title="Jump back to footnote 871 in the text">&#8617;</a></p>
+</li>
+<li id="fn:872">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:872" title="Jump back to footnote 872 in the text">&#8617;</a></p>
+</li>
+<li id="fn:873">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:873" title="Jump back to footnote 873 in the text">&#8617;</a></p>
+</li>
+<li id="fn:874">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:874" title="Jump back to footnote 874 in the text">&#8617;</a></p>
+</li>
+<li id="fn:875">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:875" title="Jump back to footnote 875 in the text">&#8617;</a></p>
+</li>
+<li id="fn:876">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:876" title="Jump back to footnote 876 in the text">&#8617;</a></p>
+</li>
+<li id="fn:877">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:877" title="Jump back to footnote 877 in the text">&#8617;</a></p>
+</li>
+<li id="fn:878">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:878" title="Jump back to footnote 878 in the text">&#8617;</a></p>
+</li>
+<li id="fn:879">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:879" title="Jump back to footnote 879 in the text">&#8617;</a></p>
+</li>
+<li id="fn:880">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:880" title="Jump back to footnote 880 in the text">&#8617;</a></p>
+</li>
+<li id="fn:881">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:881" title="Jump back to footnote 881 in the text">&#8617;</a></p>
+</li>
+<li id="fn:882">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:882" title="Jump back to footnote 882 in the text">&#8617;</a></p>
+</li>
+<li id="fn:883">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:883" title="Jump back to footnote 883 in the text">&#8617;</a></p>
+</li>
+<li id="fn:884">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:884" title="Jump back to footnote 884 in the text">&#8617;</a></p>
+</li>
+<li id="fn:885">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:885" title="Jump back to footnote 885 in the text">&#8617;</a></p>
+</li>
+<li id="fn:886">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:886" title="Jump back to footnote 886 in the text">&#8617;</a></p>
+</li>
+<li id="fn:887">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:887" title="Jump back to footnote 887 in the text">&#8617;</a></p>
+</li>
+<li id="fn:888">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:888" title="Jump back to footnote 888 in the text">&#8617;</a></p>
+</li>
+<li id="fn:889">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:889" title="Jump back to footnote 889 in the text">&#8617;</a></p>
+</li>
+<li id="fn:890">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:890" title="Jump back to footnote 890 in the text">&#8617;</a></p>
+</li>
+<li id="fn:891">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:891" title="Jump back to footnote 891 in the text">&#8617;</a></p>
+</li>
+<li id="fn:892">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:892" title="Jump back to footnote 892 in the text">&#8617;</a></p>
+</li>
+<li id="fn:893">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:893" title="Jump back to footnote 893 in the text">&#8617;</a></p>
+</li>
+<li id="fn:894">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:894" title="Jump back to footnote 894 in the text">&#8617;</a></p>
+</li>
+<li id="fn:895">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:895" title="Jump back to footnote 895 in the text">&#8617;</a></p>
+</li>
+<li id="fn:896">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:896" title="Jump back to footnote 896 in the text">&#8617;</a></p>
+</li>
+<li id="fn:897">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:897" title="Jump back to footnote 897 in the text">&#8617;</a></p>
+</li>
+<li id="fn:898">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:898" title="Jump back to footnote 898 in the text">&#8617;</a></p>
+</li>
+<li id="fn:899">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:899" title="Jump back to footnote 899 in the text">&#8617;</a></p>
+</li>
+<li id="fn:900">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:900" title="Jump back to footnote 900 in the text">&#8617;</a></p>
+</li>
+<li id="fn:901">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:901" title="Jump back to footnote 901 in the text">&#8617;</a></p>
+</li>
+<li id="fn:902">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:902" title="Jump back to footnote 902 in the text">&#8617;</a></p>
+</li>
+<li id="fn:903">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:903" title="Jump back to footnote 903 in the text">&#8617;</a></p>
+</li>
+<li id="fn:904">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:904" title="Jump back to footnote 904 in the text">&#8617;</a></p>
+</li>
+<li id="fn:905">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:905" title="Jump back to footnote 905 in the text">&#8617;</a></p>
+</li>
+<li id="fn:906">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:906" title="Jump back to footnote 906 in the text">&#8617;</a></p>
+</li>
+<li id="fn:907">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:907" title="Jump back to footnote 907 in the text">&#8617;</a></p>
+</li>
+<li id="fn:908">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:908" title="Jump back to footnote 908 in the text">&#8617;</a></p>
+</li>
+<li id="fn:909">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:909" title="Jump back to footnote 909 in the text">&#8617;</a></p>
+</li>
+<li id="fn:910">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:910" title="Jump back to footnote 910 in the text">&#8617;</a></p>
+</li>
+<li id="fn:911">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:911" title="Jump back to footnote 911 in the text">&#8617;</a></p>
+</li>
+<li id="fn:912">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:912" title="Jump back to footnote 912 in the text">&#8617;</a></p>
+</li>
+<li id="fn:913">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:913" title="Jump back to footnote 913 in the text">&#8617;</a></p>
+</li>
+<li id="fn:914">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:914" title="Jump back to footnote 914 in the text">&#8617;</a></p>
+</li>
+<li id="fn:915">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:915" title="Jump back to footnote 915 in the text">&#8617;</a></p>
+</li>
+<li id="fn:916">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:916" title="Jump back to footnote 916 in the text">&#8617;</a></p>
+</li>
+<li id="fn:917">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:917" title="Jump back to footnote 917 in the text">&#8617;</a></p>
+</li>
+<li id="fn:918">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:918" title="Jump back to footnote 918 in the text">&#8617;</a></p>
+</li>
+<li id="fn:919">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:919" title="Jump back to footnote 919 in the text">&#8617;</a></p>
+</li>
+<li id="fn:920">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:920" title="Jump back to footnote 920 in the text">&#8617;</a></p>
+</li>
+<li id="fn:921">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:921" title="Jump back to footnote 921 in the text">&#8617;</a></p>
+</li>
+<li id="fn:922">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:922" title="Jump back to footnote 922 in the text">&#8617;</a></p>
+</li>
+<li id="fn:923">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:923" title="Jump back to footnote 923 in the text">&#8617;</a></p>
+</li>
+<li id="fn:924">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:924" title="Jump back to footnote 924 in the text">&#8617;</a></p>
+</li>
+<li id="fn:925">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:925" title="Jump back to footnote 925 in the text">&#8617;</a></p>
+</li>
+<li id="fn:926">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:926" title="Jump back to footnote 926 in the text">&#8617;</a></p>
+</li>
+<li id="fn:927">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:927" title="Jump back to footnote 927 in the text">&#8617;</a></p>
+</li>
+<li id="fn:928">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:928" title="Jump back to footnote 928 in the text">&#8617;</a></p>
+</li>
+<li id="fn:929">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:929" title="Jump back to footnote 929 in the text">&#8617;</a></p>
+</li>
+<li id="fn:930">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:930" title="Jump back to footnote 930 in the text">&#8617;</a></p>
+</li>
+<li id="fn:931">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:931" title="Jump back to footnote 931 in the text">&#8617;</a></p>
+</li>
+<li id="fn:932">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:932" title="Jump back to footnote 932 in the text">&#8617;</a></p>
+</li>
+<li id="fn:933">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:933" title="Jump back to footnote 933 in the text">&#8617;</a></p>
+</li>
+<li id="fn:934">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:934" title="Jump back to footnote 934 in the text">&#8617;</a></p>
+</li>
+<li id="fn:935">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:935" title="Jump back to footnote 935 in the text">&#8617;</a></p>
+</li>
+<li id="fn:936">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:936" title="Jump back to footnote 936 in the text">&#8617;</a></p>
+</li>
+<li id="fn:937">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:937" title="Jump back to footnote 937 in the text">&#8617;</a></p>
+</li>
+<li id="fn:938">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:938" title="Jump back to footnote 938 in the text">&#8617;</a></p>
+</li>
+<li id="fn:939">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:939" title="Jump back to footnote 939 in the text">&#8617;</a></p>
+</li>
+<li id="fn:940">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:940" title="Jump back to footnote 940 in the text">&#8617;</a></p>
+</li>
+<li id="fn:941">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:941" title="Jump back to footnote 941 in the text">&#8617;</a></p>
+</li>
+<li id="fn:942">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:942" title="Jump back to footnote 942 in the text">&#8617;</a></p>
+</li>
+<li id="fn:943">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:943" title="Jump back to footnote 943 in the text">&#8617;</a></p>
+</li>
+<li id="fn:944">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:944" title="Jump back to footnote 944 in the text">&#8617;</a></p>
+</li>
+<li id="fn:945">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:945" title="Jump back to footnote 945 in the text">&#8617;</a></p>
+</li>
+<li id="fn:946">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:946" title="Jump back to footnote 946 in the text">&#8617;</a></p>
+</li>
+<li id="fn:947">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:947" title="Jump back to footnote 947 in the text">&#8617;</a></p>
+</li>
+<li id="fn:948">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:948" title="Jump back to footnote 948 in the text">&#8617;</a></p>
+</li>
+<li id="fn:949">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:949" title="Jump back to footnote 949 in the text">&#8617;</a></p>
+</li>
+<li id="fn:950">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:950" title="Jump back to footnote 950 in the text">&#8617;</a></p>
+</li>
+<li id="fn:951">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:951" title="Jump back to footnote 951 in the text">&#8617;</a></p>
+</li>
+<li id="fn:952">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:952" title="Jump back to footnote 952 in the text">&#8617;</a></p>
+</li>
+<li id="fn:953">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:953" title="Jump back to footnote 953 in the text">&#8617;</a></p>
+</li>
+<li id="fn:954">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:954" title="Jump back to footnote 954 in the text">&#8617;</a></p>
+</li>
+<li id="fn:955">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:955" title="Jump back to footnote 955 in the text">&#8617;</a></p>
+</li>
+<li id="fn:956">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:956" title="Jump back to footnote 956 in the text">&#8617;</a></p>
+</li>
+<li id="fn:957">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:957" title="Jump back to footnote 957 in the text">&#8617;</a></p>
+</li>
+<li id="fn:958">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:958" title="Jump back to footnote 958 in the text">&#8617;</a></p>
+</li>
+<li id="fn:959">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:959" title="Jump back to footnote 959 in the text">&#8617;</a></p>
+</li>
+<li id="fn:960">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:960" title="Jump back to footnote 960 in the text">&#8617;</a></p>
+</li>
+<li id="fn:961">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:961" title="Jump back to footnote 961 in the text">&#8617;</a></p>
+</li>
+<li id="fn:962">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:962" title="Jump back to footnote 962 in the text">&#8617;</a></p>
+</li>
+<li id="fn:963">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:963" title="Jump back to footnote 963 in the text">&#8617;</a></p>
+</li>
+<li id="fn:964">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:964" title="Jump back to footnote 964 in the text">&#8617;</a></p>
+</li>
+<li id="fn:965">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:965" title="Jump back to footnote 965 in the text">&#8617;</a></p>
+</li>
+<li id="fn:966">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:966" title="Jump back to footnote 966 in the text">&#8617;</a></p>
+</li>
+<li id="fn:967">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:967" title="Jump back to footnote 967 in the text">&#8617;</a></p>
+</li>
+<li id="fn:968">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:968" title="Jump back to footnote 968 in the text">&#8617;</a></p>
+</li>
+<li id="fn:969">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:969" title="Jump back to footnote 969 in the text">&#8617;</a></p>
+</li>
+<li id="fn:970">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:970" title="Jump back to footnote 970 in the text">&#8617;</a></p>
+</li>
+<li id="fn:971">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:971" title="Jump back to footnote 971 in the text">&#8617;</a></p>
+</li>
+<li id="fn:972">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:972" title="Jump back to footnote 972 in the text">&#8617;</a></p>
+</li>
+<li id="fn:973">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:973" title="Jump back to footnote 973 in the text">&#8617;</a></p>
+</li>
+<li id="fn:974">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:974" title="Jump back to footnote 974 in the text">&#8617;</a></p>
+</li>
+<li id="fn:975">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:975" title="Jump back to footnote 975 in the text">&#8617;</a></p>
+</li>
+<li id="fn:976">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:976" title="Jump back to footnote 976 in the text">&#8617;</a></p>
+</li>
+<li id="fn:977">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:977" title="Jump back to footnote 977 in the text">&#8617;</a></p>
+</li>
+<li id="fn:978">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:978" title="Jump back to footnote 978 in the text">&#8617;</a></p>
+</li>
+<li id="fn:979">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:979" title="Jump back to footnote 979 in the text">&#8617;</a></p>
+</li>
+<li id="fn:980">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:980" title="Jump back to footnote 980 in the text">&#8617;</a></p>
+</li>
+<li id="fn:981">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:981" title="Jump back to footnote 981 in the text">&#8617;</a></p>
+</li>
+<li id="fn:982">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:982" title="Jump back to footnote 982 in the text">&#8617;</a></p>
+</li>
+<li id="fn:983">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:983" title="Jump back to footnote 983 in the text">&#8617;</a></p>
+</li>
+<li id="fn:984">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:984" title="Jump back to footnote 984 in the text">&#8617;</a></p>
+</li>
+<li id="fn:985">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:985" title="Jump back to footnote 985 in the text">&#8617;</a></p>
+</li>
+<li id="fn:986">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:986" title="Jump back to footnote 986 in the text">&#8617;</a></p>
+</li>
+<li id="fn:987">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:987" title="Jump back to footnote 987 in the text">&#8617;</a></p>
+</li>
+<li id="fn:988">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:988" title="Jump back to footnote 988 in the text">&#8617;</a></p>
+</li>
+<li id="fn:989">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:989" title="Jump back to footnote 989 in the text">&#8617;</a></p>
+</li>
+<li id="fn:990">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:990" title="Jump back to footnote 990 in the text">&#8617;</a></p>
+</li>
+<li id="fn:991">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:991" title="Jump back to footnote 991 in the text">&#8617;</a></p>
+</li>
+<li id="fn:992">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:992" title="Jump back to footnote 992 in the text">&#8617;</a></p>
+</li>
+<li id="fn:993">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:993" title="Jump back to footnote 993 in the text">&#8617;</a></p>
+</li>
+<li id="fn:994">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:994" title="Jump back to footnote 994 in the text">&#8617;</a></p>
+</li>
+<li id="fn:995">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:995" title="Jump back to footnote 995 in the text">&#8617;</a></p>
+</li>
+<li id="fn:996">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:996" title="Jump back to footnote 996 in the text">&#8617;</a></p>
+</li>
+<li id="fn:997">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:997" title="Jump back to footnote 997 in the text">&#8617;</a></p>
+</li>
+<li id="fn:998">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:998" title="Jump back to footnote 998 in the text">&#8617;</a></p>
+</li>
+<li id="fn:999">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:999" title="Jump back to footnote 999 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1000">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1000" title="Jump back to footnote 1000 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1001">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1001" title="Jump back to footnote 1001 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1002">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1002" title="Jump back to footnote 1002 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1003">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1003" title="Jump back to footnote 1003 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1004">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1004" title="Jump back to footnote 1004 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1005">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1005" title="Jump back to footnote 1005 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1006">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1006" title="Jump back to footnote 1006 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1007">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1007" title="Jump back to footnote 1007 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1008">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1008" title="Jump back to footnote 1008 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1009">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1009" title="Jump back to footnote 1009 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1010">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1010" title="Jump back to footnote 1010 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1011">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1011" title="Jump back to footnote 1011 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1012">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1012" title="Jump back to footnote 1012 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1013">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1013" title="Jump back to footnote 1013 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1014">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1014" title="Jump back to footnote 1014 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1015">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1015" title="Jump back to footnote 1015 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1016">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1016" title="Jump back to footnote 1016 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1017">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1017" title="Jump back to footnote 1017 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1018">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1018" title="Jump back to footnote 1018 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1019">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1019" title="Jump back to footnote 1019 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1020">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1020" title="Jump back to footnote 1020 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1021">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1021" title="Jump back to footnote 1021 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1022">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1022" title="Jump back to footnote 1022 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1023">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1023" title="Jump back to footnote 1023 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1024">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1024" title="Jump back to footnote 1024 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1025">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1025" title="Jump back to footnote 1025 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1026">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1026" title="Jump back to footnote 1026 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1027">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1027" title="Jump back to footnote 1027 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1028">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1028" title="Jump back to footnote 1028 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1029">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1029" title="Jump back to footnote 1029 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1030">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1030" title="Jump back to footnote 1030 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1031">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1031" title="Jump back to footnote 1031 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1032">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1032" title="Jump back to footnote 1032 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1033">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1033" title="Jump back to footnote 1033 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1034">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1034" title="Jump back to footnote 1034 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1035">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1035" title="Jump back to footnote 1035 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1036">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1036" title="Jump back to footnote 1036 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1037">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1037" title="Jump back to footnote 1037 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1038">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1038" title="Jump back to footnote 1038 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1039">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1039" title="Jump back to footnote 1039 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1040">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1040" title="Jump back to footnote 1040 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1041">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1041" title="Jump back to footnote 1041 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1042">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1042" title="Jump back to footnote 1042 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1043">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1043" title="Jump back to footnote 1043 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1044">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1044" title="Jump back to footnote 1044 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1045">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1045" title="Jump back to footnote 1045 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1046">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1046" title="Jump back to footnote 1046 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1047">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1047" title="Jump back to footnote 1047 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1048">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1048" title="Jump back to footnote 1048 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1049">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1049" title="Jump back to footnote 1049 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1050">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1050" title="Jump back to footnote 1050 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1051">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1051" title="Jump back to footnote 1051 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1052">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1052" title="Jump back to footnote 1052 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1053">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1053" title="Jump back to footnote 1053 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1054">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1054" title="Jump back to footnote 1054 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1055">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1055" title="Jump back to footnote 1055 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1056">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1056" title="Jump back to footnote 1056 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1057">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1057" title="Jump back to footnote 1057 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1058">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1058" title="Jump back to footnote 1058 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1059">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1059" title="Jump back to footnote 1059 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1060">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1060" title="Jump back to footnote 1060 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1061">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1061" title="Jump back to footnote 1061 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1062">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1062" title="Jump back to footnote 1062 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1063">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1063" title="Jump back to footnote 1063 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1064">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1064" title="Jump back to footnote 1064 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1065">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1065" title="Jump back to footnote 1065 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1066">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1066" title="Jump back to footnote 1066 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1067">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1067" title="Jump back to footnote 1067 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1068">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1068" title="Jump back to footnote 1068 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1069">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1069" title="Jump back to footnote 1069 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1070">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1070" title="Jump back to footnote 1070 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1071">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1071" title="Jump back to footnote 1071 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1072">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1072" title="Jump back to footnote 1072 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1073">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1073" title="Jump back to footnote 1073 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1074">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1074" title="Jump back to footnote 1074 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1075">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1075" title="Jump back to footnote 1075 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1076">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1076" title="Jump back to footnote 1076 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1077">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1077" title="Jump back to footnote 1077 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1078">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1078" title="Jump back to footnote 1078 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1079">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1079" title="Jump back to footnote 1079 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1080">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1080" title="Jump back to footnote 1080 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1081">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1081" title="Jump back to footnote 1081 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1082">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1082" title="Jump back to footnote 1082 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1083">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1083" title="Jump back to footnote 1083 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1084">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1084" title="Jump back to footnote 1084 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1085">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1085" title="Jump back to footnote 1085 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1086">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1086" title="Jump back to footnote 1086 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1087">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1087" title="Jump back to footnote 1087 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1088">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1088" title="Jump back to footnote 1088 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1089">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1089" title="Jump back to footnote 1089 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1090">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1090" title="Jump back to footnote 1090 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1091">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1091" title="Jump back to footnote 1091 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1092">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1092" title="Jump back to footnote 1092 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1093">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1093" title="Jump back to footnote 1093 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1094">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1094" title="Jump back to footnote 1094 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1095">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1095" title="Jump back to footnote 1095 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1096">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1096" title="Jump back to footnote 1096 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1097">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1097" title="Jump back to footnote 1097 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1098">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1098" title="Jump back to footnote 1098 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1099">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1099" title="Jump back to footnote 1099 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1100">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1100" title="Jump back to footnote 1100 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1101">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1101" title="Jump back to footnote 1101 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1102">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1102" title="Jump back to footnote 1102 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1103">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1103" title="Jump back to footnote 1103 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1104">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1104" title="Jump back to footnote 1104 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1105">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1105" title="Jump back to footnote 1105 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1106">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1106" title="Jump back to footnote 1106 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1107">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1107" title="Jump back to footnote 1107 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1108">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1108" title="Jump back to footnote 1108 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1109">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1109" title="Jump back to footnote 1109 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1110">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1110" title="Jump back to footnote 1110 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1111">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1111" title="Jump back to footnote 1111 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1112">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1112" title="Jump back to footnote 1112 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1113">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1113" title="Jump back to footnote 1113 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1114">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1114" title="Jump back to footnote 1114 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1115">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1115" title="Jump back to footnote 1115 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1116">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1116" title="Jump back to footnote 1116 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1117">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1117" title="Jump back to footnote 1117 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1118">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1118" title="Jump back to footnote 1118 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1119">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1119" title="Jump back to footnote 1119 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1120">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1120" title="Jump back to footnote 1120 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1121">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1121" title="Jump back to footnote 1121 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1122">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1122" title="Jump back to footnote 1122 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1123">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1123" title="Jump back to footnote 1123 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1124">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1124" title="Jump back to footnote 1124 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1125">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1125" title="Jump back to footnote 1125 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1126">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1126" title="Jump back to footnote 1126 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1127">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1127" title="Jump back to footnote 1127 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1128">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1128" title="Jump back to footnote 1128 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1129">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1129" title="Jump back to footnote 1129 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1130">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1130" title="Jump back to footnote 1130 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1131">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1131" title="Jump back to footnote 1131 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1132">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1132" title="Jump back to footnote 1132 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1133">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1133" title="Jump back to footnote 1133 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1134">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1134" title="Jump back to footnote 1134 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1135">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1135" title="Jump back to footnote 1135 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1136">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1136" title="Jump back to footnote 1136 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1137">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1137" title="Jump back to footnote 1137 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1138">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1138" title="Jump back to footnote 1138 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1139">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1139" title="Jump back to footnote 1139 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1140">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1140" title="Jump back to footnote 1140 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1141">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1141" title="Jump back to footnote 1141 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1142">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1142" title="Jump back to footnote 1142 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1143">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1143" title="Jump back to footnote 1143 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1144">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1144" title="Jump back to footnote 1144 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1145">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1145" title="Jump back to footnote 1145 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1146">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1146" title="Jump back to footnote 1146 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1147">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1147" title="Jump back to footnote 1147 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1148">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1148" title="Jump back to footnote 1148 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1149">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1149" title="Jump back to footnote 1149 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1150">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1150" title="Jump back to footnote 1150 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1151">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1151" title="Jump back to footnote 1151 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1152">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1152" title="Jump back to footnote 1152 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1153">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1153" title="Jump back to footnote 1153 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1154">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1154" title="Jump back to footnote 1154 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1155">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1155" title="Jump back to footnote 1155 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1156">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1156" title="Jump back to footnote 1156 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1157">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1157" title="Jump back to footnote 1157 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1158">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1158" title="Jump back to footnote 1158 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1159">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1159" title="Jump back to footnote 1159 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1160">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1160" title="Jump back to footnote 1160 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1161">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1161" title="Jump back to footnote 1161 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1162">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1162" title="Jump back to footnote 1162 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1163">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1163" title="Jump back to footnote 1163 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1164">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1164" title="Jump back to footnote 1164 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1165">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1165" title="Jump back to footnote 1165 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1166">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1166" title="Jump back to footnote 1166 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1167">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1167" title="Jump back to footnote 1167 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1168">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1168" title="Jump back to footnote 1168 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1169">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1169" title="Jump back to footnote 1169 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1170">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1170" title="Jump back to footnote 1170 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1171">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1171" title="Jump back to footnote 1171 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1172">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1172" title="Jump back to footnote 1172 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1173">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1173" title="Jump back to footnote 1173 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1174">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1174" title="Jump back to footnote 1174 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1175">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1175" title="Jump back to footnote 1175 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1176">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1176" title="Jump back to footnote 1176 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1177">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1177" title="Jump back to footnote 1177 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1178">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1178" title="Jump back to footnote 1178 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1179">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1179" title="Jump back to footnote 1179 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1180">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1180" title="Jump back to footnote 1180 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1181">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1181" title="Jump back to footnote 1181 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1182">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1182" title="Jump back to footnote 1182 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1183">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1183" title="Jump back to footnote 1183 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1184">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1184" title="Jump back to footnote 1184 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1185">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1185" title="Jump back to footnote 1185 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1186">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1186" title="Jump back to footnote 1186 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1187">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1187" title="Jump back to footnote 1187 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1188">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1188" title="Jump back to footnote 1188 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1189">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1189" title="Jump back to footnote 1189 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1190">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1190" title="Jump back to footnote 1190 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1191">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1191" title="Jump back to footnote 1191 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1192">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1192" title="Jump back to footnote 1192 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1193">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1193" title="Jump back to footnote 1193 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1194">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1194" title="Jump back to footnote 1194 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1195">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1195" title="Jump back to footnote 1195 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1196">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1196" title="Jump back to footnote 1196 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1197">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1197" title="Jump back to footnote 1197 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1198">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1198" title="Jump back to footnote 1198 in the text">&#8617;</a></p>
+</li>
+<li id="fn:1199">
+<p>Another thing&#160;<a class="footnote-backref" href="#fnref:1199" title="Jump back to footnote 1199 in the text">&#8617;</a></p>
+</li>
+</ol>
+</div> \ No newline at end of file
diff --git a/tests/extensions/extra/footnote_many_footnotes.txt b/tests/extensions/extra/footnote_many_footnotes.txt
new file mode 100644
index 0000000..cd5ee8d
--- /dev/null
+++ b/tests/extensions/extra/footnote_many_footnotes.txt
@@ -0,0 +1,4796 @@
+Something[^1]
+
+Something[^2]
+
+Something[^3]
+
+Something[^4]
+
+Something[^5]
+
+Something[^6]
+
+Something[^7]
+
+Something[^8]
+
+Something[^9]
+
+Something[^10]
+
+Something[^11]
+
+Something[^12]
+
+Something[^13]
+
+Something[^14]
+
+Something[^15]
+
+Something[^16]
+
+Something[^17]
+
+Something[^18]
+
+Something[^19]
+
+Something[^20]
+
+Something[^21]
+
+Something[^22]
+
+Something[^23]
+
+Something[^24]
+
+Something[^25]
+
+Something[^26]
+
+Something[^27]
+
+Something[^28]
+
+Something[^29]
+
+Something[^30]
+
+Something[^31]
+
+Something[^32]
+
+Something[^33]
+
+Something[^34]
+
+Something[^35]
+
+Something[^36]
+
+Something[^37]
+
+Something[^38]
+
+Something[^39]
+
+Something[^40]
+
+Something[^41]
+
+Something[^42]
+
+Something[^43]
+
+Something[^44]
+
+Something[^45]
+
+Something[^46]
+
+Something[^47]
+
+Something[^48]
+
+Something[^49]
+
+Something[^50]
+
+Something[^51]
+
+Something[^52]
+
+Something[^53]
+
+Something[^54]
+
+Something[^55]
+
+Something[^56]
+
+Something[^57]
+
+Something[^58]
+
+Something[^59]
+
+Something[^60]
+
+Something[^61]
+
+Something[^62]
+
+Something[^63]
+
+Something[^64]
+
+Something[^65]
+
+Something[^66]
+
+Something[^67]
+
+Something[^68]
+
+Something[^69]
+
+Something[^70]
+
+Something[^71]
+
+Something[^72]
+
+Something[^73]
+
+Something[^74]
+
+Something[^75]
+
+Something[^76]
+
+Something[^77]
+
+Something[^78]
+
+Something[^79]
+
+Something[^80]
+
+Something[^81]
+
+Something[^82]
+
+Something[^83]
+
+Something[^84]
+
+Something[^85]
+
+Something[^86]
+
+Something[^87]
+
+Something[^88]
+
+Something[^89]
+
+Something[^90]
+
+Something[^91]
+
+Something[^92]
+
+Something[^93]
+
+Something[^94]
+
+Something[^95]
+
+Something[^96]
+
+Something[^97]
+
+Something[^98]
+
+Something[^99]
+
+Something[^100]
+
+Something[^101]
+
+Something[^102]
+
+Something[^103]
+
+Something[^104]
+
+Something[^105]
+
+Something[^106]
+
+Something[^107]
+
+Something[^108]
+
+Something[^109]
+
+Something[^110]
+
+Something[^111]
+
+Something[^112]
+
+Something[^113]
+
+Something[^114]
+
+Something[^115]
+
+Something[^116]
+
+Something[^117]
+
+Something[^118]
+
+Something[^119]
+
+Something[^120]
+
+Something[^121]
+
+Something[^122]
+
+Something[^123]
+
+Something[^124]
+
+Something[^125]
+
+Something[^126]
+
+Something[^127]
+
+Something[^128]
+
+Something[^129]
+
+Something[^130]
+
+Something[^131]
+
+Something[^132]
+
+Something[^133]
+
+Something[^134]
+
+Something[^135]
+
+Something[^136]
+
+Something[^137]
+
+Something[^138]
+
+Something[^139]
+
+Something[^140]
+
+Something[^141]
+
+Something[^142]
+
+Something[^143]
+
+Something[^144]
+
+Something[^145]
+
+Something[^146]
+
+Something[^147]
+
+Something[^148]
+
+Something[^149]
+
+Something[^150]
+
+Something[^151]
+
+Something[^152]
+
+Something[^153]
+
+Something[^154]
+
+Something[^155]
+
+Something[^156]
+
+Something[^157]
+
+Something[^158]
+
+Something[^159]
+
+Something[^160]
+
+Something[^161]
+
+Something[^162]
+
+Something[^163]
+
+Something[^164]
+
+Something[^165]
+
+Something[^166]
+
+Something[^167]
+
+Something[^168]
+
+Something[^169]
+
+Something[^170]
+
+Something[^171]
+
+Something[^172]
+
+Something[^173]
+
+Something[^174]
+
+Something[^175]
+
+Something[^176]
+
+Something[^177]
+
+Something[^178]
+
+Something[^179]
+
+Something[^180]
+
+Something[^181]
+
+Something[^182]
+
+Something[^183]
+
+Something[^184]
+
+Something[^185]
+
+Something[^186]
+
+Something[^187]
+
+Something[^188]
+
+Something[^189]
+
+Something[^190]
+
+Something[^191]
+
+Something[^192]
+
+Something[^193]
+
+Something[^194]
+
+Something[^195]
+
+Something[^196]
+
+Something[^197]
+
+Something[^198]
+
+Something[^199]
+
+Something[^200]
+
+Something[^201]
+
+Something[^202]
+
+Something[^203]
+
+Something[^204]
+
+Something[^205]
+
+Something[^206]
+
+Something[^207]
+
+Something[^208]
+
+Something[^209]
+
+Something[^210]
+
+Something[^211]
+
+Something[^212]
+
+Something[^213]
+
+Something[^214]
+
+Something[^215]
+
+Something[^216]
+
+Something[^217]
+
+Something[^218]
+
+Something[^219]
+
+Something[^220]
+
+Something[^221]
+
+Something[^222]
+
+Something[^223]
+
+Something[^224]
+
+Something[^225]
+
+Something[^226]
+
+Something[^227]
+
+Something[^228]
+
+Something[^229]
+
+Something[^230]
+
+Something[^231]
+
+Something[^232]
+
+Something[^233]
+
+Something[^234]
+
+Something[^235]
+
+Something[^236]
+
+Something[^237]
+
+Something[^238]
+
+Something[^239]
+
+Something[^240]
+
+Something[^241]
+
+Something[^242]
+
+Something[^243]
+
+Something[^244]
+
+Something[^245]
+
+Something[^246]
+
+Something[^247]
+
+Something[^248]
+
+Something[^249]
+
+Something[^250]
+
+Something[^251]
+
+Something[^252]
+
+Something[^253]
+
+Something[^254]
+
+Something[^255]
+
+Something[^256]
+
+Something[^257]
+
+Something[^258]
+
+Something[^259]
+
+Something[^260]
+
+Something[^261]
+
+Something[^262]
+
+Something[^263]
+
+Something[^264]
+
+Something[^265]
+
+Something[^266]
+
+Something[^267]
+
+Something[^268]
+
+Something[^269]
+
+Something[^270]
+
+Something[^271]
+
+Something[^272]
+
+Something[^273]
+
+Something[^274]
+
+Something[^275]
+
+Something[^276]
+
+Something[^277]
+
+Something[^278]
+
+Something[^279]
+
+Something[^280]
+
+Something[^281]
+
+Something[^282]
+
+Something[^283]
+
+Something[^284]
+
+Something[^285]
+
+Something[^286]
+
+Something[^287]
+
+Something[^288]
+
+Something[^289]
+
+Something[^290]
+
+Something[^291]
+
+Something[^292]
+
+Something[^293]
+
+Something[^294]
+
+Something[^295]
+
+Something[^296]
+
+Something[^297]
+
+Something[^298]
+
+Something[^299]
+
+Something[^300]
+
+Something[^301]
+
+Something[^302]
+
+Something[^303]
+
+Something[^304]
+
+Something[^305]
+
+Something[^306]
+
+Something[^307]
+
+Something[^308]
+
+Something[^309]
+
+Something[^310]
+
+Something[^311]
+
+Something[^312]
+
+Something[^313]
+
+Something[^314]
+
+Something[^315]
+
+Something[^316]
+
+Something[^317]
+
+Something[^318]
+
+Something[^319]
+
+Something[^320]
+
+Something[^321]
+
+Something[^322]
+
+Something[^323]
+
+Something[^324]
+
+Something[^325]
+
+Something[^326]
+
+Something[^327]
+
+Something[^328]
+
+Something[^329]
+
+Something[^330]
+
+Something[^331]
+
+Something[^332]
+
+Something[^333]
+
+Something[^334]
+
+Something[^335]
+
+Something[^336]
+
+Something[^337]
+
+Something[^338]
+
+Something[^339]
+
+Something[^340]
+
+Something[^341]
+
+Something[^342]
+
+Something[^343]
+
+Something[^344]
+
+Something[^345]
+
+Something[^346]
+
+Something[^347]
+
+Something[^348]
+
+Something[^349]
+
+Something[^350]
+
+Something[^351]
+
+Something[^352]
+
+Something[^353]
+
+Something[^354]
+
+Something[^355]
+
+Something[^356]
+
+Something[^357]
+
+Something[^358]
+
+Something[^359]
+
+Something[^360]
+
+Something[^361]
+
+Something[^362]
+
+Something[^363]
+
+Something[^364]
+
+Something[^365]
+
+Something[^366]
+
+Something[^367]
+
+Something[^368]
+
+Something[^369]
+
+Something[^370]
+
+Something[^371]
+
+Something[^372]
+
+Something[^373]
+
+Something[^374]
+
+Something[^375]
+
+Something[^376]
+
+Something[^377]
+
+Something[^378]
+
+Something[^379]
+
+Something[^380]
+
+Something[^381]
+
+Something[^382]
+
+Something[^383]
+
+Something[^384]
+
+Something[^385]
+
+Something[^386]
+
+Something[^387]
+
+Something[^388]
+
+Something[^389]
+
+Something[^390]
+
+Something[^391]
+
+Something[^392]
+
+Something[^393]
+
+Something[^394]
+
+Something[^395]
+
+Something[^396]
+
+Something[^397]
+
+Something[^398]
+
+Something[^399]
+
+Something[^400]
+
+Something[^401]
+
+Something[^402]
+
+Something[^403]
+
+Something[^404]
+
+Something[^405]
+
+Something[^406]
+
+Something[^407]
+
+Something[^408]
+
+Something[^409]
+
+Something[^410]
+
+Something[^411]
+
+Something[^412]
+
+Something[^413]
+
+Something[^414]
+
+Something[^415]
+
+Something[^416]
+
+Something[^417]
+
+Something[^418]
+
+Something[^419]
+
+Something[^420]
+
+Something[^421]
+
+Something[^422]
+
+Something[^423]
+
+Something[^424]
+
+Something[^425]
+
+Something[^426]
+
+Something[^427]
+
+Something[^428]
+
+Something[^429]
+
+Something[^430]
+
+Something[^431]
+
+Something[^432]
+
+Something[^433]
+
+Something[^434]
+
+Something[^435]
+
+Something[^436]
+
+Something[^437]
+
+Something[^438]
+
+Something[^439]
+
+Something[^440]
+
+Something[^441]
+
+Something[^442]
+
+Something[^443]
+
+Something[^444]
+
+Something[^445]
+
+Something[^446]
+
+Something[^447]
+
+Something[^448]
+
+Something[^449]
+
+Something[^450]
+
+Something[^451]
+
+Something[^452]
+
+Something[^453]
+
+Something[^454]
+
+Something[^455]
+
+Something[^456]
+
+Something[^457]
+
+Something[^458]
+
+Something[^459]
+
+Something[^460]
+
+Something[^461]
+
+Something[^462]
+
+Something[^463]
+
+Something[^464]
+
+Something[^465]
+
+Something[^466]
+
+Something[^467]
+
+Something[^468]
+
+Something[^469]
+
+Something[^470]
+
+Something[^471]
+
+Something[^472]
+
+Something[^473]
+
+Something[^474]
+
+Something[^475]
+
+Something[^476]
+
+Something[^477]
+
+Something[^478]
+
+Something[^479]
+
+Something[^480]
+
+Something[^481]
+
+Something[^482]
+
+Something[^483]
+
+Something[^484]
+
+Something[^485]
+
+Something[^486]
+
+Something[^487]
+
+Something[^488]
+
+Something[^489]
+
+Something[^490]
+
+Something[^491]
+
+Something[^492]
+
+Something[^493]
+
+Something[^494]
+
+Something[^495]
+
+Something[^496]
+
+Something[^497]
+
+Something[^498]
+
+Something[^499]
+
+Something[^500]
+
+Something[^501]
+
+Something[^502]
+
+Something[^503]
+
+Something[^504]
+
+Something[^505]
+
+Something[^506]
+
+Something[^507]
+
+Something[^508]
+
+Something[^509]
+
+Something[^510]
+
+Something[^511]
+
+Something[^512]
+
+Something[^513]
+
+Something[^514]
+
+Something[^515]
+
+Something[^516]
+
+Something[^517]
+
+Something[^518]
+
+Something[^519]
+
+Something[^520]
+
+Something[^521]
+
+Something[^522]
+
+Something[^523]
+
+Something[^524]
+
+Something[^525]
+
+Something[^526]
+
+Something[^527]
+
+Something[^528]
+
+Something[^529]
+
+Something[^530]
+
+Something[^531]
+
+Something[^532]
+
+Something[^533]
+
+Something[^534]
+
+Something[^535]
+
+Something[^536]
+
+Something[^537]
+
+Something[^538]
+
+Something[^539]
+
+Something[^540]
+
+Something[^541]
+
+Something[^542]
+
+Something[^543]
+
+Something[^544]
+
+Something[^545]
+
+Something[^546]
+
+Something[^547]
+
+Something[^548]
+
+Something[^549]
+
+Something[^550]
+
+Something[^551]
+
+Something[^552]
+
+Something[^553]
+
+Something[^554]
+
+Something[^555]
+
+Something[^556]
+
+Something[^557]
+
+Something[^558]
+
+Something[^559]
+
+Something[^560]
+
+Something[^561]
+
+Something[^562]
+
+Something[^563]
+
+Something[^564]
+
+Something[^565]
+
+Something[^566]
+
+Something[^567]
+
+Something[^568]
+
+Something[^569]
+
+Something[^570]
+
+Something[^571]
+
+Something[^572]
+
+Something[^573]
+
+Something[^574]
+
+Something[^575]
+
+Something[^576]
+
+Something[^577]
+
+Something[^578]
+
+Something[^579]
+
+Something[^580]
+
+Something[^581]
+
+Something[^582]
+
+Something[^583]
+
+Something[^584]
+
+Something[^585]
+
+Something[^586]
+
+Something[^587]
+
+Something[^588]
+
+Something[^589]
+
+Something[^590]
+
+Something[^591]
+
+Something[^592]
+
+Something[^593]
+
+Something[^594]
+
+Something[^595]
+
+Something[^596]
+
+Something[^597]
+
+Something[^598]
+
+Something[^599]
+
+Something[^600]
+
+Something[^601]
+
+Something[^602]
+
+Something[^603]
+
+Something[^604]
+
+Something[^605]
+
+Something[^606]
+
+Something[^607]
+
+Something[^608]
+
+Something[^609]
+
+Something[^610]
+
+Something[^611]
+
+Something[^612]
+
+Something[^613]
+
+Something[^614]
+
+Something[^615]
+
+Something[^616]
+
+Something[^617]
+
+Something[^618]
+
+Something[^619]
+
+Something[^620]
+
+Something[^621]
+
+Something[^622]
+
+Something[^623]
+
+Something[^624]
+
+Something[^625]
+
+Something[^626]
+
+Something[^627]
+
+Something[^628]
+
+Something[^629]
+
+Something[^630]
+
+Something[^631]
+
+Something[^632]
+
+Something[^633]
+
+Something[^634]
+
+Something[^635]
+
+Something[^636]
+
+Something[^637]
+
+Something[^638]
+
+Something[^639]
+
+Something[^640]
+
+Something[^641]
+
+Something[^642]
+
+Something[^643]
+
+Something[^644]
+
+Something[^645]
+
+Something[^646]
+
+Something[^647]
+
+Something[^648]
+
+Something[^649]
+
+Something[^650]
+
+Something[^651]
+
+Something[^652]
+
+Something[^653]
+
+Something[^654]
+
+Something[^655]
+
+Something[^656]
+
+Something[^657]
+
+Something[^658]
+
+Something[^659]
+
+Something[^660]
+
+Something[^661]
+
+Something[^662]
+
+Something[^663]
+
+Something[^664]
+
+Something[^665]
+
+Something[^666]
+
+Something[^667]
+
+Something[^668]
+
+Something[^669]
+
+Something[^670]
+
+Something[^671]
+
+Something[^672]
+
+Something[^673]
+
+Something[^674]
+
+Something[^675]
+
+Something[^676]
+
+Something[^677]
+
+Something[^678]
+
+Something[^679]
+
+Something[^680]
+
+Something[^681]
+
+Something[^682]
+
+Something[^683]
+
+Something[^684]
+
+Something[^685]
+
+Something[^686]
+
+Something[^687]
+
+Something[^688]
+
+Something[^689]
+
+Something[^690]
+
+Something[^691]
+
+Something[^692]
+
+Something[^693]
+
+Something[^694]
+
+Something[^695]
+
+Something[^696]
+
+Something[^697]
+
+Something[^698]
+
+Something[^699]
+
+Something[^700]
+
+Something[^701]
+
+Something[^702]
+
+Something[^703]
+
+Something[^704]
+
+Something[^705]
+
+Something[^706]
+
+Something[^707]
+
+Something[^708]
+
+Something[^709]
+
+Something[^710]
+
+Something[^711]
+
+Something[^712]
+
+Something[^713]
+
+Something[^714]
+
+Something[^715]
+
+Something[^716]
+
+Something[^717]
+
+Something[^718]
+
+Something[^719]
+
+Something[^720]
+
+Something[^721]
+
+Something[^722]
+
+Something[^723]
+
+Something[^724]
+
+Something[^725]
+
+Something[^726]
+
+Something[^727]
+
+Something[^728]
+
+Something[^729]
+
+Something[^730]
+
+Something[^731]
+
+Something[^732]
+
+Something[^733]
+
+Something[^734]
+
+Something[^735]
+
+Something[^736]
+
+Something[^737]
+
+Something[^738]
+
+Something[^739]
+
+Something[^740]
+
+Something[^741]
+
+Something[^742]
+
+Something[^743]
+
+Something[^744]
+
+Something[^745]
+
+Something[^746]
+
+Something[^747]
+
+Something[^748]
+
+Something[^749]
+
+Something[^750]
+
+Something[^751]
+
+Something[^752]
+
+Something[^753]
+
+Something[^754]
+
+Something[^755]
+
+Something[^756]
+
+Something[^757]
+
+Something[^758]
+
+Something[^759]
+
+Something[^760]
+
+Something[^761]
+
+Something[^762]
+
+Something[^763]
+
+Something[^764]
+
+Something[^765]
+
+Something[^766]
+
+Something[^767]
+
+Something[^768]
+
+Something[^769]
+
+Something[^770]
+
+Something[^771]
+
+Something[^772]
+
+Something[^773]
+
+Something[^774]
+
+Something[^775]
+
+Something[^776]
+
+Something[^777]
+
+Something[^778]
+
+Something[^779]
+
+Something[^780]
+
+Something[^781]
+
+Something[^782]
+
+Something[^783]
+
+Something[^784]
+
+Something[^785]
+
+Something[^786]
+
+Something[^787]
+
+Something[^788]
+
+Something[^789]
+
+Something[^790]
+
+Something[^791]
+
+Something[^792]
+
+Something[^793]
+
+Something[^794]
+
+Something[^795]
+
+Something[^796]
+
+Something[^797]
+
+Something[^798]
+
+Something[^799]
+
+Something[^800]
+
+Something[^801]
+
+Something[^802]
+
+Something[^803]
+
+Something[^804]
+
+Something[^805]
+
+Something[^806]
+
+Something[^807]
+
+Something[^808]
+
+Something[^809]
+
+Something[^810]
+
+Something[^811]
+
+Something[^812]
+
+Something[^813]
+
+Something[^814]
+
+Something[^815]
+
+Something[^816]
+
+Something[^817]
+
+Something[^818]
+
+Something[^819]
+
+Something[^820]
+
+Something[^821]
+
+Something[^822]
+
+Something[^823]
+
+Something[^824]
+
+Something[^825]
+
+Something[^826]
+
+Something[^827]
+
+Something[^828]
+
+Something[^829]
+
+Something[^830]
+
+Something[^831]
+
+Something[^832]
+
+Something[^833]
+
+Something[^834]
+
+Something[^835]
+
+Something[^836]
+
+Something[^837]
+
+Something[^838]
+
+Something[^839]
+
+Something[^840]
+
+Something[^841]
+
+Something[^842]
+
+Something[^843]
+
+Something[^844]
+
+Something[^845]
+
+Something[^846]
+
+Something[^847]
+
+Something[^848]
+
+Something[^849]
+
+Something[^850]
+
+Something[^851]
+
+Something[^852]
+
+Something[^853]
+
+Something[^854]
+
+Something[^855]
+
+Something[^856]
+
+Something[^857]
+
+Something[^858]
+
+Something[^859]
+
+Something[^860]
+
+Something[^861]
+
+Something[^862]
+
+Something[^863]
+
+Something[^864]
+
+Something[^865]
+
+Something[^866]
+
+Something[^867]
+
+Something[^868]
+
+Something[^869]
+
+Something[^870]
+
+Something[^871]
+
+Something[^872]
+
+Something[^873]
+
+Something[^874]
+
+Something[^875]
+
+Something[^876]
+
+Something[^877]
+
+Something[^878]
+
+Something[^879]
+
+Something[^880]
+
+Something[^881]
+
+Something[^882]
+
+Something[^883]
+
+Something[^884]
+
+Something[^885]
+
+Something[^886]
+
+Something[^887]
+
+Something[^888]
+
+Something[^889]
+
+Something[^890]
+
+Something[^891]
+
+Something[^892]
+
+Something[^893]
+
+Something[^894]
+
+Something[^895]
+
+Something[^896]
+
+Something[^897]
+
+Something[^898]
+
+Something[^899]
+
+Something[^900]
+
+Something[^901]
+
+Something[^902]
+
+Something[^903]
+
+Something[^904]
+
+Something[^905]
+
+Something[^906]
+
+Something[^907]
+
+Something[^908]
+
+Something[^909]
+
+Something[^910]
+
+Something[^911]
+
+Something[^912]
+
+Something[^913]
+
+Something[^914]
+
+Something[^915]
+
+Something[^916]
+
+Something[^917]
+
+Something[^918]
+
+Something[^919]
+
+Something[^920]
+
+Something[^921]
+
+Something[^922]
+
+Something[^923]
+
+Something[^924]
+
+Something[^925]
+
+Something[^926]
+
+Something[^927]
+
+Something[^928]
+
+Something[^929]
+
+Something[^930]
+
+Something[^931]
+
+Something[^932]
+
+Something[^933]
+
+Something[^934]
+
+Something[^935]
+
+Something[^936]
+
+Something[^937]
+
+Something[^938]
+
+Something[^939]
+
+Something[^940]
+
+Something[^941]
+
+Something[^942]
+
+Something[^943]
+
+Something[^944]
+
+Something[^945]
+
+Something[^946]
+
+Something[^947]
+
+Something[^948]
+
+Something[^949]
+
+Something[^950]
+
+Something[^951]
+
+Something[^952]
+
+Something[^953]
+
+Something[^954]
+
+Something[^955]
+
+Something[^956]
+
+Something[^957]
+
+Something[^958]
+
+Something[^959]
+
+Something[^960]
+
+Something[^961]
+
+Something[^962]
+
+Something[^963]
+
+Something[^964]
+
+Something[^965]
+
+Something[^966]
+
+Something[^967]
+
+Something[^968]
+
+Something[^969]
+
+Something[^970]
+
+Something[^971]
+
+Something[^972]
+
+Something[^973]
+
+Something[^974]
+
+Something[^975]
+
+Something[^976]
+
+Something[^977]
+
+Something[^978]
+
+Something[^979]
+
+Something[^980]
+
+Something[^981]
+
+Something[^982]
+
+Something[^983]
+
+Something[^984]
+
+Something[^985]
+
+Something[^986]
+
+Something[^987]
+
+Something[^988]
+
+Something[^989]
+
+Something[^990]
+
+Something[^991]
+
+Something[^992]
+
+Something[^993]
+
+Something[^994]
+
+Something[^995]
+
+Something[^996]
+
+Something[^997]
+
+Something[^998]
+
+Something[^999]
+
+Something[^1000]
+
+Something[^1001]
+
+Something[^1002]
+
+Something[^1003]
+
+Something[^1004]
+
+Something[^1005]
+
+Something[^1006]
+
+Something[^1007]
+
+Something[^1008]
+
+Something[^1009]
+
+Something[^1010]
+
+Something[^1011]
+
+Something[^1012]
+
+Something[^1013]
+
+Something[^1014]
+
+Something[^1015]
+
+Something[^1016]
+
+Something[^1017]
+
+Something[^1018]
+
+Something[^1019]
+
+Something[^1020]
+
+Something[^1021]
+
+Something[^1022]
+
+Something[^1023]
+
+Something[^1024]
+
+Something[^1025]
+
+Something[^1026]
+
+Something[^1027]
+
+Something[^1028]
+
+Something[^1029]
+
+Something[^1030]
+
+Something[^1031]
+
+Something[^1032]
+
+Something[^1033]
+
+Something[^1034]
+
+Something[^1035]
+
+Something[^1036]
+
+Something[^1037]
+
+Something[^1038]
+
+Something[^1039]
+
+Something[^1040]
+
+Something[^1041]
+
+Something[^1042]
+
+Something[^1043]
+
+Something[^1044]
+
+Something[^1045]
+
+Something[^1046]
+
+Something[^1047]
+
+Something[^1048]
+
+Something[^1049]
+
+Something[^1050]
+
+Something[^1051]
+
+Something[^1052]
+
+Something[^1053]
+
+Something[^1054]
+
+Something[^1055]
+
+Something[^1056]
+
+Something[^1057]
+
+Something[^1058]
+
+Something[^1059]
+
+Something[^1060]
+
+Something[^1061]
+
+Something[^1062]
+
+Something[^1063]
+
+Something[^1064]
+
+Something[^1065]
+
+Something[^1066]
+
+Something[^1067]
+
+Something[^1068]
+
+Something[^1069]
+
+Something[^1070]
+
+Something[^1071]
+
+Something[^1072]
+
+Something[^1073]
+
+Something[^1074]
+
+Something[^1075]
+
+Something[^1076]
+
+Something[^1077]
+
+Something[^1078]
+
+Something[^1079]
+
+Something[^1080]
+
+Something[^1081]
+
+Something[^1082]
+
+Something[^1083]
+
+Something[^1084]
+
+Something[^1085]
+
+Something[^1086]
+
+Something[^1087]
+
+Something[^1088]
+
+Something[^1089]
+
+Something[^1090]
+
+Something[^1091]
+
+Something[^1092]
+
+Something[^1093]
+
+Something[^1094]
+
+Something[^1095]
+
+Something[^1096]
+
+Something[^1097]
+
+Something[^1098]
+
+Something[^1099]
+
+Something[^1100]
+
+Something[^1101]
+
+Something[^1102]
+
+Something[^1103]
+
+Something[^1104]
+
+Something[^1105]
+
+Something[^1106]
+
+Something[^1107]
+
+Something[^1108]
+
+Something[^1109]
+
+Something[^1110]
+
+Something[^1111]
+
+Something[^1112]
+
+Something[^1113]
+
+Something[^1114]
+
+Something[^1115]
+
+Something[^1116]
+
+Something[^1117]
+
+Something[^1118]
+
+Something[^1119]
+
+Something[^1120]
+
+Something[^1121]
+
+Something[^1122]
+
+Something[^1123]
+
+Something[^1124]
+
+Something[^1125]
+
+Something[^1126]
+
+Something[^1127]
+
+Something[^1128]
+
+Something[^1129]
+
+Something[^1130]
+
+Something[^1131]
+
+Something[^1132]
+
+Something[^1133]
+
+Something[^1134]
+
+Something[^1135]
+
+Something[^1136]
+
+Something[^1137]
+
+Something[^1138]
+
+Something[^1139]
+
+Something[^1140]
+
+Something[^1141]
+
+Something[^1142]
+
+Something[^1143]
+
+Something[^1144]
+
+Something[^1145]
+
+Something[^1146]
+
+Something[^1147]
+
+Something[^1148]
+
+Something[^1149]
+
+Something[^1150]
+
+Something[^1151]
+
+Something[^1152]
+
+Something[^1153]
+
+Something[^1154]
+
+Something[^1155]
+
+Something[^1156]
+
+Something[^1157]
+
+Something[^1158]
+
+Something[^1159]
+
+Something[^1160]
+
+Something[^1161]
+
+Something[^1162]
+
+Something[^1163]
+
+Something[^1164]
+
+Something[^1165]
+
+Something[^1166]
+
+Something[^1167]
+
+Something[^1168]
+
+Something[^1169]
+
+Something[^1170]
+
+Something[^1171]
+
+Something[^1172]
+
+Something[^1173]
+
+Something[^1174]
+
+Something[^1175]
+
+Something[^1176]
+
+Something[^1177]
+
+Something[^1178]
+
+Something[^1179]
+
+Something[^1180]
+
+Something[^1181]
+
+Something[^1182]
+
+Something[^1183]
+
+Something[^1184]
+
+Something[^1185]
+
+Something[^1186]
+
+Something[^1187]
+
+Something[^1188]
+
+Something[^1189]
+
+Something[^1190]
+
+Something[^1191]
+
+Something[^1192]
+
+Something[^1193]
+
+Something[^1194]
+
+Something[^1195]
+
+Something[^1196]
+
+Something[^1197]
+
+Something[^1198]
+
+Something[^1199]
+
+[^1]: Another thing
+
+[^2]: Another thing
+
+[^3]: Another thing
+
+[^4]: Another thing
+
+[^5]: Another thing
+
+[^6]: Another thing
+
+[^7]: Another thing
+
+[^8]: Another thing
+
+[^9]: Another thing
+
+[^10]: Another thing
+
+[^11]: Another thing
+
+[^12]: Another thing
+
+[^13]: Another thing
+
+[^14]: Another thing
+
+[^15]: Another thing
+
+[^16]: Another thing
+
+[^17]: Another thing
+
+[^18]: Another thing
+
+[^19]: Another thing
+
+[^20]: Another thing
+
+[^21]: Another thing
+
+[^22]: Another thing
+
+[^23]: Another thing
+
+[^24]: Another thing
+
+[^25]: Another thing
+
+[^26]: Another thing
+
+[^27]: Another thing
+
+[^28]: Another thing
+
+[^29]: Another thing
+
+[^30]: Another thing
+
+[^31]: Another thing
+
+[^32]: Another thing
+
+[^33]: Another thing
+
+[^34]: Another thing
+
+[^35]: Another thing
+
+[^36]: Another thing
+
+[^37]: Another thing
+
+[^38]: Another thing
+
+[^39]: Another thing
+
+[^40]: Another thing
+
+[^41]: Another thing
+
+[^42]: Another thing
+
+[^43]: Another thing
+
+[^44]: Another thing
+
+[^45]: Another thing
+
+[^46]: Another thing
+
+[^47]: Another thing
+
+[^48]: Another thing
+
+[^49]: Another thing
+
+[^50]: Another thing
+
+[^51]: Another thing
+
+[^52]: Another thing
+
+[^53]: Another thing
+
+[^54]: Another thing
+
+[^55]: Another thing
+
+[^56]: Another thing
+
+[^57]: Another thing
+
+[^58]: Another thing
+
+[^59]: Another thing
+
+[^60]: Another thing
+
+[^61]: Another thing
+
+[^62]: Another thing
+
+[^63]: Another thing
+
+[^64]: Another thing
+
+[^65]: Another thing
+
+[^66]: Another thing
+
+[^67]: Another thing
+
+[^68]: Another thing
+
+[^69]: Another thing
+
+[^70]: Another thing
+
+[^71]: Another thing
+
+[^72]: Another thing
+
+[^73]: Another thing
+
+[^74]: Another thing
+
+[^75]: Another thing
+
+[^76]: Another thing
+
+[^77]: Another thing
+
+[^78]: Another thing
+
+[^79]: Another thing
+
+[^80]: Another thing
+
+[^81]: Another thing
+
+[^82]: Another thing
+
+[^83]: Another thing
+
+[^84]: Another thing
+
+[^85]: Another thing
+
+[^86]: Another thing
+
+[^87]: Another thing
+
+[^88]: Another thing
+
+[^89]: Another thing
+
+[^90]: Another thing
+
+[^91]: Another thing
+
+[^92]: Another thing
+
+[^93]: Another thing
+
+[^94]: Another thing
+
+[^95]: Another thing
+
+[^96]: Another thing
+
+[^97]: Another thing
+
+[^98]: Another thing
+
+[^99]: Another thing
+
+[^100]: Another thing
+
+[^101]: Another thing
+
+[^102]: Another thing
+
+[^103]: Another thing
+
+[^104]: Another thing
+
+[^105]: Another thing
+
+[^106]: Another thing
+
+[^107]: Another thing
+
+[^108]: Another thing
+
+[^109]: Another thing
+
+[^110]: Another thing
+
+[^111]: Another thing
+
+[^112]: Another thing
+
+[^113]: Another thing
+
+[^114]: Another thing
+
+[^115]: Another thing
+
+[^116]: Another thing
+
+[^117]: Another thing
+
+[^118]: Another thing
+
+[^119]: Another thing
+
+[^120]: Another thing
+
+[^121]: Another thing
+
+[^122]: Another thing
+
+[^123]: Another thing
+
+[^124]: Another thing
+
+[^125]: Another thing
+
+[^126]: Another thing
+
+[^127]: Another thing
+
+[^128]: Another thing
+
+[^129]: Another thing
+
+[^130]: Another thing
+
+[^131]: Another thing
+
+[^132]: Another thing
+
+[^133]: Another thing
+
+[^134]: Another thing
+
+[^135]: Another thing
+
+[^136]: Another thing
+
+[^137]: Another thing
+
+[^138]: Another thing
+
+[^139]: Another thing
+
+[^140]: Another thing
+
+[^141]: Another thing
+
+[^142]: Another thing
+
+[^143]: Another thing
+
+[^144]: Another thing
+
+[^145]: Another thing
+
+[^146]: Another thing
+
+[^147]: Another thing
+
+[^148]: Another thing
+
+[^149]: Another thing
+
+[^150]: Another thing
+
+[^151]: Another thing
+
+[^152]: Another thing
+
+[^153]: Another thing
+
+[^154]: Another thing
+
+[^155]: Another thing
+
+[^156]: Another thing
+
+[^157]: Another thing
+
+[^158]: Another thing
+
+[^159]: Another thing
+
+[^160]: Another thing
+
+[^161]: Another thing
+
+[^162]: Another thing
+
+[^163]: Another thing
+
+[^164]: Another thing
+
+[^165]: Another thing
+
+[^166]: Another thing
+
+[^167]: Another thing
+
+[^168]: Another thing
+
+[^169]: Another thing
+
+[^170]: Another thing
+
+[^171]: Another thing
+
+[^172]: Another thing
+
+[^173]: Another thing
+
+[^174]: Another thing
+
+[^175]: Another thing
+
+[^176]: Another thing
+
+[^177]: Another thing
+
+[^178]: Another thing
+
+[^179]: Another thing
+
+[^180]: Another thing
+
+[^181]: Another thing
+
+[^182]: Another thing
+
+[^183]: Another thing
+
+[^184]: Another thing
+
+[^185]: Another thing
+
+[^186]: Another thing
+
+[^187]: Another thing
+
+[^188]: Another thing
+
+[^189]: Another thing
+
+[^190]: Another thing
+
+[^191]: Another thing
+
+[^192]: Another thing
+
+[^193]: Another thing
+
+[^194]: Another thing
+
+[^195]: Another thing
+
+[^196]: Another thing
+
+[^197]: Another thing
+
+[^198]: Another thing
+
+[^199]: Another thing
+
+[^200]: Another thing
+
+[^201]: Another thing
+
+[^202]: Another thing
+
+[^203]: Another thing
+
+[^204]: Another thing
+
+[^205]: Another thing
+
+[^206]: Another thing
+
+[^207]: Another thing
+
+[^208]: Another thing
+
+[^209]: Another thing
+
+[^210]: Another thing
+
+[^211]: Another thing
+
+[^212]: Another thing
+
+[^213]: Another thing
+
+[^214]: Another thing
+
+[^215]: Another thing
+
+[^216]: Another thing
+
+[^217]: Another thing
+
+[^218]: Another thing
+
+[^219]: Another thing
+
+[^220]: Another thing
+
+[^221]: Another thing
+
+[^222]: Another thing
+
+[^223]: Another thing
+
+[^224]: Another thing
+
+[^225]: Another thing
+
+[^226]: Another thing
+
+[^227]: Another thing
+
+[^228]: Another thing
+
+[^229]: Another thing
+
+[^230]: Another thing
+
+[^231]: Another thing
+
+[^232]: Another thing
+
+[^233]: Another thing
+
+[^234]: Another thing
+
+[^235]: Another thing
+
+[^236]: Another thing
+
+[^237]: Another thing
+
+[^238]: Another thing
+
+[^239]: Another thing
+
+[^240]: Another thing
+
+[^241]: Another thing
+
+[^242]: Another thing
+
+[^243]: Another thing
+
+[^244]: Another thing
+
+[^245]: Another thing
+
+[^246]: Another thing
+
+[^247]: Another thing
+
+[^248]: Another thing
+
+[^249]: Another thing
+
+[^250]: Another thing
+
+[^251]: Another thing
+
+[^252]: Another thing
+
+[^253]: Another thing
+
+[^254]: Another thing
+
+[^255]: Another thing
+
+[^256]: Another thing
+
+[^257]: Another thing
+
+[^258]: Another thing
+
+[^259]: Another thing
+
+[^260]: Another thing
+
+[^261]: Another thing
+
+[^262]: Another thing
+
+[^263]: Another thing
+
+[^264]: Another thing
+
+[^265]: Another thing
+
+[^266]: Another thing
+
+[^267]: Another thing
+
+[^268]: Another thing
+
+[^269]: Another thing
+
+[^270]: Another thing
+
+[^271]: Another thing
+
+[^272]: Another thing
+
+[^273]: Another thing
+
+[^274]: Another thing
+
+[^275]: Another thing
+
+[^276]: Another thing
+
+[^277]: Another thing
+
+[^278]: Another thing
+
+[^279]: Another thing
+
+[^280]: Another thing
+
+[^281]: Another thing
+
+[^282]: Another thing
+
+[^283]: Another thing
+
+[^284]: Another thing
+
+[^285]: Another thing
+
+[^286]: Another thing
+
+[^287]: Another thing
+
+[^288]: Another thing
+
+[^289]: Another thing
+
+[^290]: Another thing
+
+[^291]: Another thing
+
+[^292]: Another thing
+
+[^293]: Another thing
+
+[^294]: Another thing
+
+[^295]: Another thing
+
+[^296]: Another thing
+
+[^297]: Another thing
+
+[^298]: Another thing
+
+[^299]: Another thing
+
+[^300]: Another thing
+
+[^301]: Another thing
+
+[^302]: Another thing
+
+[^303]: Another thing
+
+[^304]: Another thing
+
+[^305]: Another thing
+
+[^306]: Another thing
+
+[^307]: Another thing
+
+[^308]: Another thing
+
+[^309]: Another thing
+
+[^310]: Another thing
+
+[^311]: Another thing
+
+[^312]: Another thing
+
+[^313]: Another thing
+
+[^314]: Another thing
+
+[^315]: Another thing
+
+[^316]: Another thing
+
+[^317]: Another thing
+
+[^318]: Another thing
+
+[^319]: Another thing
+
+[^320]: Another thing
+
+[^321]: Another thing
+
+[^322]: Another thing
+
+[^323]: Another thing
+
+[^324]: Another thing
+
+[^325]: Another thing
+
+[^326]: Another thing
+
+[^327]: Another thing
+
+[^328]: Another thing
+
+[^329]: Another thing
+
+[^330]: Another thing
+
+[^331]: Another thing
+
+[^332]: Another thing
+
+[^333]: Another thing
+
+[^334]: Another thing
+
+[^335]: Another thing
+
+[^336]: Another thing
+
+[^337]: Another thing
+
+[^338]: Another thing
+
+[^339]: Another thing
+
+[^340]: Another thing
+
+[^341]: Another thing
+
+[^342]: Another thing
+
+[^343]: Another thing
+
+[^344]: Another thing
+
+[^345]: Another thing
+
+[^346]: Another thing
+
+[^347]: Another thing
+
+[^348]: Another thing
+
+[^349]: Another thing
+
+[^350]: Another thing
+
+[^351]: Another thing
+
+[^352]: Another thing
+
+[^353]: Another thing
+
+[^354]: Another thing
+
+[^355]: Another thing
+
+[^356]: Another thing
+
+[^357]: Another thing
+
+[^358]: Another thing
+
+[^359]: Another thing
+
+[^360]: Another thing
+
+[^361]: Another thing
+
+[^362]: Another thing
+
+[^363]: Another thing
+
+[^364]: Another thing
+
+[^365]: Another thing
+
+[^366]: Another thing
+
+[^367]: Another thing
+
+[^368]: Another thing
+
+[^369]: Another thing
+
+[^370]: Another thing
+
+[^371]: Another thing
+
+[^372]: Another thing
+
+[^373]: Another thing
+
+[^374]: Another thing
+
+[^375]: Another thing
+
+[^376]: Another thing
+
+[^377]: Another thing
+
+[^378]: Another thing
+
+[^379]: Another thing
+
+[^380]: Another thing
+
+[^381]: Another thing
+
+[^382]: Another thing
+
+[^383]: Another thing
+
+[^384]: Another thing
+
+[^385]: Another thing
+
+[^386]: Another thing
+
+[^387]: Another thing
+
+[^388]: Another thing
+
+[^389]: Another thing
+
+[^390]: Another thing
+
+[^391]: Another thing
+
+[^392]: Another thing
+
+[^393]: Another thing
+
+[^394]: Another thing
+
+[^395]: Another thing
+
+[^396]: Another thing
+
+[^397]: Another thing
+
+[^398]: Another thing
+
+[^399]: Another thing
+
+[^400]: Another thing
+
+[^401]: Another thing
+
+[^402]: Another thing
+
+[^403]: Another thing
+
+[^404]: Another thing
+
+[^405]: Another thing
+
+[^406]: Another thing
+
+[^407]: Another thing
+
+[^408]: Another thing
+
+[^409]: Another thing
+
+[^410]: Another thing
+
+[^411]: Another thing
+
+[^412]: Another thing
+
+[^413]: Another thing
+
+[^414]: Another thing
+
+[^415]: Another thing
+
+[^416]: Another thing
+
+[^417]: Another thing
+
+[^418]: Another thing
+
+[^419]: Another thing
+
+[^420]: Another thing
+
+[^421]: Another thing
+
+[^422]: Another thing
+
+[^423]: Another thing
+
+[^424]: Another thing
+
+[^425]: Another thing
+
+[^426]: Another thing
+
+[^427]: Another thing
+
+[^428]: Another thing
+
+[^429]: Another thing
+
+[^430]: Another thing
+
+[^431]: Another thing
+
+[^432]: Another thing
+
+[^433]: Another thing
+
+[^434]: Another thing
+
+[^435]: Another thing
+
+[^436]: Another thing
+
+[^437]: Another thing
+
+[^438]: Another thing
+
+[^439]: Another thing
+
+[^440]: Another thing
+
+[^441]: Another thing
+
+[^442]: Another thing
+
+[^443]: Another thing
+
+[^444]: Another thing
+
+[^445]: Another thing
+
+[^446]: Another thing
+
+[^447]: Another thing
+
+[^448]: Another thing
+
+[^449]: Another thing
+
+[^450]: Another thing
+
+[^451]: Another thing
+
+[^452]: Another thing
+
+[^453]: Another thing
+
+[^454]: Another thing
+
+[^455]: Another thing
+
+[^456]: Another thing
+
+[^457]: Another thing
+
+[^458]: Another thing
+
+[^459]: Another thing
+
+[^460]: Another thing
+
+[^461]: Another thing
+
+[^462]: Another thing
+
+[^463]: Another thing
+
+[^464]: Another thing
+
+[^465]: Another thing
+
+[^466]: Another thing
+
+[^467]: Another thing
+
+[^468]: Another thing
+
+[^469]: Another thing
+
+[^470]: Another thing
+
+[^471]: Another thing
+
+[^472]: Another thing
+
+[^473]: Another thing
+
+[^474]: Another thing
+
+[^475]: Another thing
+
+[^476]: Another thing
+
+[^477]: Another thing
+
+[^478]: Another thing
+
+[^479]: Another thing
+
+[^480]: Another thing
+
+[^481]: Another thing
+
+[^482]: Another thing
+
+[^483]: Another thing
+
+[^484]: Another thing
+
+[^485]: Another thing
+
+[^486]: Another thing
+
+[^487]: Another thing
+
+[^488]: Another thing
+
+[^489]: Another thing
+
+[^490]: Another thing
+
+[^491]: Another thing
+
+[^492]: Another thing
+
+[^493]: Another thing
+
+[^494]: Another thing
+
+[^495]: Another thing
+
+[^496]: Another thing
+
+[^497]: Another thing
+
+[^498]: Another thing
+
+[^499]: Another thing
+
+[^500]: Another thing
+
+[^501]: Another thing
+
+[^502]: Another thing
+
+[^503]: Another thing
+
+[^504]: Another thing
+
+[^505]: Another thing
+
+[^506]: Another thing
+
+[^507]: Another thing
+
+[^508]: Another thing
+
+[^509]: Another thing
+
+[^510]: Another thing
+
+[^511]: Another thing
+
+[^512]: Another thing
+
+[^513]: Another thing
+
+[^514]: Another thing
+
+[^515]: Another thing
+
+[^516]: Another thing
+
+[^517]: Another thing
+
+[^518]: Another thing
+
+[^519]: Another thing
+
+[^520]: Another thing
+
+[^521]: Another thing
+
+[^522]: Another thing
+
+[^523]: Another thing
+
+[^524]: Another thing
+
+[^525]: Another thing
+
+[^526]: Another thing
+
+[^527]: Another thing
+
+[^528]: Another thing
+
+[^529]: Another thing
+
+[^530]: Another thing
+
+[^531]: Another thing
+
+[^532]: Another thing
+
+[^533]: Another thing
+
+[^534]: Another thing
+
+[^535]: Another thing
+
+[^536]: Another thing
+
+[^537]: Another thing
+
+[^538]: Another thing
+
+[^539]: Another thing
+
+[^540]: Another thing
+
+[^541]: Another thing
+
+[^542]: Another thing
+
+[^543]: Another thing
+
+[^544]: Another thing
+
+[^545]: Another thing
+
+[^546]: Another thing
+
+[^547]: Another thing
+
+[^548]: Another thing
+
+[^549]: Another thing
+
+[^550]: Another thing
+
+[^551]: Another thing
+
+[^552]: Another thing
+
+[^553]: Another thing
+
+[^554]: Another thing
+
+[^555]: Another thing
+
+[^556]: Another thing
+
+[^557]: Another thing
+
+[^558]: Another thing
+
+[^559]: Another thing
+
+[^560]: Another thing
+
+[^561]: Another thing
+
+[^562]: Another thing
+
+[^563]: Another thing
+
+[^564]: Another thing
+
+[^565]: Another thing
+
+[^566]: Another thing
+
+[^567]: Another thing
+
+[^568]: Another thing
+
+[^569]: Another thing
+
+[^570]: Another thing
+
+[^571]: Another thing
+
+[^572]: Another thing
+
+[^573]: Another thing
+
+[^574]: Another thing
+
+[^575]: Another thing
+
+[^576]: Another thing
+
+[^577]: Another thing
+
+[^578]: Another thing
+
+[^579]: Another thing
+
+[^580]: Another thing
+
+[^581]: Another thing
+
+[^582]: Another thing
+
+[^583]: Another thing
+
+[^584]: Another thing
+
+[^585]: Another thing
+
+[^586]: Another thing
+
+[^587]: Another thing
+
+[^588]: Another thing
+
+[^589]: Another thing
+
+[^590]: Another thing
+
+[^591]: Another thing
+
+[^592]: Another thing
+
+[^593]: Another thing
+
+[^594]: Another thing
+
+[^595]: Another thing
+
+[^596]: Another thing
+
+[^597]: Another thing
+
+[^598]: Another thing
+
+[^599]: Another thing
+
+[^600]: Another thing
+
+[^601]: Another thing
+
+[^602]: Another thing
+
+[^603]: Another thing
+
+[^604]: Another thing
+
+[^605]: Another thing
+
+[^606]: Another thing
+
+[^607]: Another thing
+
+[^608]: Another thing
+
+[^609]: Another thing
+
+[^610]: Another thing
+
+[^611]: Another thing
+
+[^612]: Another thing
+
+[^613]: Another thing
+
+[^614]: Another thing
+
+[^615]: Another thing
+
+[^616]: Another thing
+
+[^617]: Another thing
+
+[^618]: Another thing
+
+[^619]: Another thing
+
+[^620]: Another thing
+
+[^621]: Another thing
+
+[^622]: Another thing
+
+[^623]: Another thing
+
+[^624]: Another thing
+
+[^625]: Another thing
+
+[^626]: Another thing
+
+[^627]: Another thing
+
+[^628]: Another thing
+
+[^629]: Another thing
+
+[^630]: Another thing
+
+[^631]: Another thing
+
+[^632]: Another thing
+
+[^633]: Another thing
+
+[^634]: Another thing
+
+[^635]: Another thing
+
+[^636]: Another thing
+
+[^637]: Another thing
+
+[^638]: Another thing
+
+[^639]: Another thing
+
+[^640]: Another thing
+
+[^641]: Another thing
+
+[^642]: Another thing
+
+[^643]: Another thing
+
+[^644]: Another thing
+
+[^645]: Another thing
+
+[^646]: Another thing
+
+[^647]: Another thing
+
+[^648]: Another thing
+
+[^649]: Another thing
+
+[^650]: Another thing
+
+[^651]: Another thing
+
+[^652]: Another thing
+
+[^653]: Another thing
+
+[^654]: Another thing
+
+[^655]: Another thing
+
+[^656]: Another thing
+
+[^657]: Another thing
+
+[^658]: Another thing
+
+[^659]: Another thing
+
+[^660]: Another thing
+
+[^661]: Another thing
+
+[^662]: Another thing
+
+[^663]: Another thing
+
+[^664]: Another thing
+
+[^665]: Another thing
+
+[^666]: Another thing
+
+[^667]: Another thing
+
+[^668]: Another thing
+
+[^669]: Another thing
+
+[^670]: Another thing
+
+[^671]: Another thing
+
+[^672]: Another thing
+
+[^673]: Another thing
+
+[^674]: Another thing
+
+[^675]: Another thing
+
+[^676]: Another thing
+
+[^677]: Another thing
+
+[^678]: Another thing
+
+[^679]: Another thing
+
+[^680]: Another thing
+
+[^681]: Another thing
+
+[^682]: Another thing
+
+[^683]: Another thing
+
+[^684]: Another thing
+
+[^685]: Another thing
+
+[^686]: Another thing
+
+[^687]: Another thing
+
+[^688]: Another thing
+
+[^689]: Another thing
+
+[^690]: Another thing
+
+[^691]: Another thing
+
+[^692]: Another thing
+
+[^693]: Another thing
+
+[^694]: Another thing
+
+[^695]: Another thing
+
+[^696]: Another thing
+
+[^697]: Another thing
+
+[^698]: Another thing
+
+[^699]: Another thing
+
+[^700]: Another thing
+
+[^701]: Another thing
+
+[^702]: Another thing
+
+[^703]: Another thing
+
+[^704]: Another thing
+
+[^705]: Another thing
+
+[^706]: Another thing
+
+[^707]: Another thing
+
+[^708]: Another thing
+
+[^709]: Another thing
+
+[^710]: Another thing
+
+[^711]: Another thing
+
+[^712]: Another thing
+
+[^713]: Another thing
+
+[^714]: Another thing
+
+[^715]: Another thing
+
+[^716]: Another thing
+
+[^717]: Another thing
+
+[^718]: Another thing
+
+[^719]: Another thing
+
+[^720]: Another thing
+
+[^721]: Another thing
+
+[^722]: Another thing
+
+[^723]: Another thing
+
+[^724]: Another thing
+
+[^725]: Another thing
+
+[^726]: Another thing
+
+[^727]: Another thing
+
+[^728]: Another thing
+
+[^729]: Another thing
+
+[^730]: Another thing
+
+[^731]: Another thing
+
+[^732]: Another thing
+
+[^733]: Another thing
+
+[^734]: Another thing
+
+[^735]: Another thing
+
+[^736]: Another thing
+
+[^737]: Another thing
+
+[^738]: Another thing
+
+[^739]: Another thing
+
+[^740]: Another thing
+
+[^741]: Another thing
+
+[^742]: Another thing
+
+[^743]: Another thing
+
+[^744]: Another thing
+
+[^745]: Another thing
+
+[^746]: Another thing
+
+[^747]: Another thing
+
+[^748]: Another thing
+
+[^749]: Another thing
+
+[^750]: Another thing
+
+[^751]: Another thing
+
+[^752]: Another thing
+
+[^753]: Another thing
+
+[^754]: Another thing
+
+[^755]: Another thing
+
+[^756]: Another thing
+
+[^757]: Another thing
+
+[^758]: Another thing
+
+[^759]: Another thing
+
+[^760]: Another thing
+
+[^761]: Another thing
+
+[^762]: Another thing
+
+[^763]: Another thing
+
+[^764]: Another thing
+
+[^765]: Another thing
+
+[^766]: Another thing
+
+[^767]: Another thing
+
+[^768]: Another thing
+
+[^769]: Another thing
+
+[^770]: Another thing
+
+[^771]: Another thing
+
+[^772]: Another thing
+
+[^773]: Another thing
+
+[^774]: Another thing
+
+[^775]: Another thing
+
+[^776]: Another thing
+
+[^777]: Another thing
+
+[^778]: Another thing
+
+[^779]: Another thing
+
+[^780]: Another thing
+
+[^781]: Another thing
+
+[^782]: Another thing
+
+[^783]: Another thing
+
+[^784]: Another thing
+
+[^785]: Another thing
+
+[^786]: Another thing
+
+[^787]: Another thing
+
+[^788]: Another thing
+
+[^789]: Another thing
+
+[^790]: Another thing
+
+[^791]: Another thing
+
+[^792]: Another thing
+
+[^793]: Another thing
+
+[^794]: Another thing
+
+[^795]: Another thing
+
+[^796]: Another thing
+
+[^797]: Another thing
+
+[^798]: Another thing
+
+[^799]: Another thing
+
+[^800]: Another thing
+
+[^801]: Another thing
+
+[^802]: Another thing
+
+[^803]: Another thing
+
+[^804]: Another thing
+
+[^805]: Another thing
+
+[^806]: Another thing
+
+[^807]: Another thing
+
+[^808]: Another thing
+
+[^809]: Another thing
+
+[^810]: Another thing
+
+[^811]: Another thing
+
+[^812]: Another thing
+
+[^813]: Another thing
+
+[^814]: Another thing
+
+[^815]: Another thing
+
+[^816]: Another thing
+
+[^817]: Another thing
+
+[^818]: Another thing
+
+[^819]: Another thing
+
+[^820]: Another thing
+
+[^821]: Another thing
+
+[^822]: Another thing
+
+[^823]: Another thing
+
+[^824]: Another thing
+
+[^825]: Another thing
+
+[^826]: Another thing
+
+[^827]: Another thing
+
+[^828]: Another thing
+
+[^829]: Another thing
+
+[^830]: Another thing
+
+[^831]: Another thing
+
+[^832]: Another thing
+
+[^833]: Another thing
+
+[^834]: Another thing
+
+[^835]: Another thing
+
+[^836]: Another thing
+
+[^837]: Another thing
+
+[^838]: Another thing
+
+[^839]: Another thing
+
+[^840]: Another thing
+
+[^841]: Another thing
+
+[^842]: Another thing
+
+[^843]: Another thing
+
+[^844]: Another thing
+
+[^845]: Another thing
+
+[^846]: Another thing
+
+[^847]: Another thing
+
+[^848]: Another thing
+
+[^849]: Another thing
+
+[^850]: Another thing
+
+[^851]: Another thing
+
+[^852]: Another thing
+
+[^853]: Another thing
+
+[^854]: Another thing
+
+[^855]: Another thing
+
+[^856]: Another thing
+
+[^857]: Another thing
+
+[^858]: Another thing
+
+[^859]: Another thing
+
+[^860]: Another thing
+
+[^861]: Another thing
+
+[^862]: Another thing
+
+[^863]: Another thing
+
+[^864]: Another thing
+
+[^865]: Another thing
+
+[^866]: Another thing
+
+[^867]: Another thing
+
+[^868]: Another thing
+
+[^869]: Another thing
+
+[^870]: Another thing
+
+[^871]: Another thing
+
+[^872]: Another thing
+
+[^873]: Another thing
+
+[^874]: Another thing
+
+[^875]: Another thing
+
+[^876]: Another thing
+
+[^877]: Another thing
+
+[^878]: Another thing
+
+[^879]: Another thing
+
+[^880]: Another thing
+
+[^881]: Another thing
+
+[^882]: Another thing
+
+[^883]: Another thing
+
+[^884]: Another thing
+
+[^885]: Another thing
+
+[^886]: Another thing
+
+[^887]: Another thing
+
+[^888]: Another thing
+
+[^889]: Another thing
+
+[^890]: Another thing
+
+[^891]: Another thing
+
+[^892]: Another thing
+
+[^893]: Another thing
+
+[^894]: Another thing
+
+[^895]: Another thing
+
+[^896]: Another thing
+
+[^897]: Another thing
+
+[^898]: Another thing
+
+[^899]: Another thing
+
+[^900]: Another thing
+
+[^901]: Another thing
+
+[^902]: Another thing
+
+[^903]: Another thing
+
+[^904]: Another thing
+
+[^905]: Another thing
+
+[^906]: Another thing
+
+[^907]: Another thing
+
+[^908]: Another thing
+
+[^909]: Another thing
+
+[^910]: Another thing
+
+[^911]: Another thing
+
+[^912]: Another thing
+
+[^913]: Another thing
+
+[^914]: Another thing
+
+[^915]: Another thing
+
+[^916]: Another thing
+
+[^917]: Another thing
+
+[^918]: Another thing
+
+[^919]: Another thing
+
+[^920]: Another thing
+
+[^921]: Another thing
+
+[^922]: Another thing
+
+[^923]: Another thing
+
+[^924]: Another thing
+
+[^925]: Another thing
+
+[^926]: Another thing
+
+[^927]: Another thing
+
+[^928]: Another thing
+
+[^929]: Another thing
+
+[^930]: Another thing
+
+[^931]: Another thing
+
+[^932]: Another thing
+
+[^933]: Another thing
+
+[^934]: Another thing
+
+[^935]: Another thing
+
+[^936]: Another thing
+
+[^937]: Another thing
+
+[^938]: Another thing
+
+[^939]: Another thing
+
+[^940]: Another thing
+
+[^941]: Another thing
+
+[^942]: Another thing
+
+[^943]: Another thing
+
+[^944]: Another thing
+
+[^945]: Another thing
+
+[^946]: Another thing
+
+[^947]: Another thing
+
+[^948]: Another thing
+
+[^949]: Another thing
+
+[^950]: Another thing
+
+[^951]: Another thing
+
+[^952]: Another thing
+
+[^953]: Another thing
+
+[^954]: Another thing
+
+[^955]: Another thing
+
+[^956]: Another thing
+
+[^957]: Another thing
+
+[^958]: Another thing
+
+[^959]: Another thing
+
+[^960]: Another thing
+
+[^961]: Another thing
+
+[^962]: Another thing
+
+[^963]: Another thing
+
+[^964]: Another thing
+
+[^965]: Another thing
+
+[^966]: Another thing
+
+[^967]: Another thing
+
+[^968]: Another thing
+
+[^969]: Another thing
+
+[^970]: Another thing
+
+[^971]: Another thing
+
+[^972]: Another thing
+
+[^973]: Another thing
+
+[^974]: Another thing
+
+[^975]: Another thing
+
+[^976]: Another thing
+
+[^977]: Another thing
+
+[^978]: Another thing
+
+[^979]: Another thing
+
+[^980]: Another thing
+
+[^981]: Another thing
+
+[^982]: Another thing
+
+[^983]: Another thing
+
+[^984]: Another thing
+
+[^985]: Another thing
+
+[^986]: Another thing
+
+[^987]: Another thing
+
+[^988]: Another thing
+
+[^989]: Another thing
+
+[^990]: Another thing
+
+[^991]: Another thing
+
+[^992]: Another thing
+
+[^993]: Another thing
+
+[^994]: Another thing
+
+[^995]: Another thing
+
+[^996]: Another thing
+
+[^997]: Another thing
+
+[^998]: Another thing
+
+[^999]: Another thing
+
+[^1000]: Another thing
+
+[^1001]: Another thing
+
+[^1002]: Another thing
+
+[^1003]: Another thing
+
+[^1004]: Another thing
+
+[^1005]: Another thing
+
+[^1006]: Another thing
+
+[^1007]: Another thing
+
+[^1008]: Another thing
+
+[^1009]: Another thing
+
+[^1010]: Another thing
+
+[^1011]: Another thing
+
+[^1012]: Another thing
+
+[^1013]: Another thing
+
+[^1014]: Another thing
+
+[^1015]: Another thing
+
+[^1016]: Another thing
+
+[^1017]: Another thing
+
+[^1018]: Another thing
+
+[^1019]: Another thing
+
+[^1020]: Another thing
+
+[^1021]: Another thing
+
+[^1022]: Another thing
+
+[^1023]: Another thing
+
+[^1024]: Another thing
+
+[^1025]: Another thing
+
+[^1026]: Another thing
+
+[^1027]: Another thing
+
+[^1028]: Another thing
+
+[^1029]: Another thing
+
+[^1030]: Another thing
+
+[^1031]: Another thing
+
+[^1032]: Another thing
+
+[^1033]: Another thing
+
+[^1034]: Another thing
+
+[^1035]: Another thing
+
+[^1036]: Another thing
+
+[^1037]: Another thing
+
+[^1038]: Another thing
+
+[^1039]: Another thing
+
+[^1040]: Another thing
+
+[^1041]: Another thing
+
+[^1042]: Another thing
+
+[^1043]: Another thing
+
+[^1044]: Another thing
+
+[^1045]: Another thing
+
+[^1046]: Another thing
+
+[^1047]: Another thing
+
+[^1048]: Another thing
+
+[^1049]: Another thing
+
+[^1050]: Another thing
+
+[^1051]: Another thing
+
+[^1052]: Another thing
+
+[^1053]: Another thing
+
+[^1054]: Another thing
+
+[^1055]: Another thing
+
+[^1056]: Another thing
+
+[^1057]: Another thing
+
+[^1058]: Another thing
+
+[^1059]: Another thing
+
+[^1060]: Another thing
+
+[^1061]: Another thing
+
+[^1062]: Another thing
+
+[^1063]: Another thing
+
+[^1064]: Another thing
+
+[^1065]: Another thing
+
+[^1066]: Another thing
+
+[^1067]: Another thing
+
+[^1068]: Another thing
+
+[^1069]: Another thing
+
+[^1070]: Another thing
+
+[^1071]: Another thing
+
+[^1072]: Another thing
+
+[^1073]: Another thing
+
+[^1074]: Another thing
+
+[^1075]: Another thing
+
+[^1076]: Another thing
+
+[^1077]: Another thing
+
+[^1078]: Another thing
+
+[^1079]: Another thing
+
+[^1080]: Another thing
+
+[^1081]: Another thing
+
+[^1082]: Another thing
+
+[^1083]: Another thing
+
+[^1084]: Another thing
+
+[^1085]: Another thing
+
+[^1086]: Another thing
+
+[^1087]: Another thing
+
+[^1088]: Another thing
+
+[^1089]: Another thing
+
+[^1090]: Another thing
+
+[^1091]: Another thing
+
+[^1092]: Another thing
+
+[^1093]: Another thing
+
+[^1094]: Another thing
+
+[^1095]: Another thing
+
+[^1096]: Another thing
+
+[^1097]: Another thing
+
+[^1098]: Another thing
+
+[^1099]: Another thing
+
+[^1100]: Another thing
+
+[^1101]: Another thing
+
+[^1102]: Another thing
+
+[^1103]: Another thing
+
+[^1104]: Another thing
+
+[^1105]: Another thing
+
+[^1106]: Another thing
+
+[^1107]: Another thing
+
+[^1108]: Another thing
+
+[^1109]: Another thing
+
+[^1110]: Another thing
+
+[^1111]: Another thing
+
+[^1112]: Another thing
+
+[^1113]: Another thing
+
+[^1114]: Another thing
+
+[^1115]: Another thing
+
+[^1116]: Another thing
+
+[^1117]: Another thing
+
+[^1118]: Another thing
+
+[^1119]: Another thing
+
+[^1120]: Another thing
+
+[^1121]: Another thing
+
+[^1122]: Another thing
+
+[^1123]: Another thing
+
+[^1124]: Another thing
+
+[^1125]: Another thing
+
+[^1126]: Another thing
+
+[^1127]: Another thing
+
+[^1128]: Another thing
+
+[^1129]: Another thing
+
+[^1130]: Another thing
+
+[^1131]: Another thing
+
+[^1132]: Another thing
+
+[^1133]: Another thing
+
+[^1134]: Another thing
+
+[^1135]: Another thing
+
+[^1136]: Another thing
+
+[^1137]: Another thing
+
+[^1138]: Another thing
+
+[^1139]: Another thing
+
+[^1140]: Another thing
+
+[^1141]: Another thing
+
+[^1142]: Another thing
+
+[^1143]: Another thing
+
+[^1144]: Another thing
+
+[^1145]: Another thing
+
+[^1146]: Another thing
+
+[^1147]: Another thing
+
+[^1148]: Another thing
+
+[^1149]: Another thing
+
+[^1150]: Another thing
+
+[^1151]: Another thing
+
+[^1152]: Another thing
+
+[^1153]: Another thing
+
+[^1154]: Another thing
+
+[^1155]: Another thing
+
+[^1156]: Another thing
+
+[^1157]: Another thing
+
+[^1158]: Another thing
+
+[^1159]: Another thing
+
+[^1160]: Another thing
+
+[^1161]: Another thing
+
+[^1162]: Another thing
+
+[^1163]: Another thing
+
+[^1164]: Another thing
+
+[^1165]: Another thing
+
+[^1166]: Another thing
+
+[^1167]: Another thing
+
+[^1168]: Another thing
+
+[^1169]: Another thing
+
+[^1170]: Another thing
+
+[^1171]: Another thing
+
+[^1172]: Another thing
+
+[^1173]: Another thing
+
+[^1174]: Another thing
+
+[^1175]: Another thing
+
+[^1176]: Another thing
+
+[^1177]: Another thing
+
+[^1178]: Another thing
+
+[^1179]: Another thing
+
+[^1180]: Another thing
+
+[^1181]: Another thing
+
+[^1182]: Another thing
+
+[^1183]: Another thing
+
+[^1184]: Another thing
+
+[^1185]: Another thing
+
+[^1186]: Another thing
+
+[^1187]: Another thing
+
+[^1188]: Another thing
+
+[^1189]: Another thing
+
+[^1190]: Another thing
+
+[^1191]: Another thing
+
+[^1192]: Another thing
+
+[^1193]: Another thing
+
+[^1194]: Another thing
+
+[^1195]: Another thing
+
+[^1196]: Another thing
+
+[^1197]: Another thing
+
+[^1198]: Another thing
+
+[^1199]: Another thing
+
diff --git a/tests/extensions/extra/footnote_placeholder.html b/tests/extensions/extra/footnote_placeholder.html
new file mode 100644
index 0000000..cbad740
--- /dev/null
+++ b/tests/extensions/extra/footnote_placeholder.html
@@ -0,0 +1,9 @@
+<div class="footnote">
+<hr />
+<ol>
+<li id="fn:1">
+<p>A Footnote.&#160;<a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text">&#8617;</a></p>
+</li>
+</ol>
+</div>
+<p>Some text with a footnote<sup id="fnref:1"><a class="footnote-ref" href="#fn:1">1</a></sup>.</p> \ No newline at end of file
diff --git a/tests/extensions/extra/footnote_placeholder.txt b/tests/extensions/extra/footnote_placeholder.txt
new file mode 100644
index 0000000..0b0af42
--- /dev/null
+++ b/tests/extensions/extra/footnote_placeholder.txt
@@ -0,0 +1,5 @@
+///Footnotes Go Here///
+
+Some text with a footnote[^1].
+
+[^1]: A Footnote.
diff --git a/tests/extensions/extra/footnote_placeholder_depth.html b/tests/extensions/extra/footnote_placeholder_depth.html
new file mode 100644
index 0000000..60c2bbb
--- /dev/null
+++ b/tests/extensions/extra/footnote_placeholder_depth.html
@@ -0,0 +1,13 @@
+<blockquote>
+<blockquote>
+<div class="footnote">
+<hr />
+<ol>
+<li id="fn:1">
+<p>A Footnote.&#160;<a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text">&#8617;</a></p>
+</li>
+</ol>
+</div>
+<p>Some text with a footnote<sup id="fnref:1"><a class="footnote-ref" href="#fn:1">1</a></sup>.</p>
+</blockquote>
+</blockquote> \ No newline at end of file
diff --git a/tests/extensions/extra/footnote_placeholder_depth.txt b/tests/extensions/extra/footnote_placeholder_depth.txt
new file mode 100644
index 0000000..cfe87c0
--- /dev/null
+++ b/tests/extensions/extra/footnote_placeholder_depth.txt
@@ -0,0 +1,5 @@
+>> ///Footnotes Go Here///
+>>
+>> Some text with a footnote[^1].
+
+[^1]: A Footnote.
diff --git a/tests/extensions-x-def_list/loose_def_list.html b/tests/extensions/extra/loose_def_list.html
index 98fdec8..0de6eb6 100644
--- a/tests/extensions-x-def_list/loose_def_list.html
+++ b/tests/extensions/extra/loose_def_list.html
@@ -18,4 +18,14 @@ line 2 of def 2-1</p>
<p>par 2 of def2-2</p>
</dd>
</dl>
-<p>more text</p> \ No newline at end of file
+<p>more text</p>
+<dl>
+<dt>term 4</dt>
+<dd>not loose</dd>
+<dt>term 5</dt>
+<dd>
+<p>loose</p>
+</dd>
+<dt>term 6</dt>
+<dd>also not loose</dd>
+</dl> \ No newline at end of file
diff --git a/tests/extensions-x-def_list/loose_def_list.txt b/tests/extensions/extra/loose_def_list.txt
index 24cd6a4..909d12b 100644
--- a/tests/extensions-x-def_list/loose_def_list.txt
+++ b/tests/extensions/extra/loose_def_list.txt
@@ -18,3 +18,14 @@ term 3
more text
+term 4
+: not loose
+
+
+term 5
+
+: loose
+
+term 6
+: also not loose
+
diff --git a/tests/markdown-test/markdown-syntax.html b/tests/extensions/extra/markdown-syntax.html
index 2f63b4b..cd7ba17 100644
--- a/tests/markdown-test/markdown-syntax.html
+++ b/tests/extensions/extra/markdown-syntax.html
@@ -151,7 +151,7 @@ and <code>&amp;</code> in your example code needs to be escaped.)</p>
<p>A paragraph is simply one or more consecutive lines of text, separated
by one or more blank lines. (A blank line is any line that looks like a
blank line -- a line containing nothing but spaces or tabs is considered
-blank.) Normal paragraphs should not be intended with spaces or tabs.</p>
+blank.) Normal paragraphs should not be indented with spaces or tabs.</p>
<p>The implication of the "one or more consecutive lines of text" rule is
that Markdown supports "hard-wrapped" text paragraphs. This differs
significantly from most other text-to-HTML formatters (including Movable
@@ -241,7 +241,7 @@ Quote Level from the Text menu.</p>
<h3 id="list">Lists</h3>
<p>Markdown supports ordered (numbered) and unordered (bulleted) lists.</p>
-<p>Unordered lists use asterisks, pluses, and hyphens -- interchangably
+<p>Unordered lists use asterisks, pluses, and hyphens -- interchangeably
-- as list markers:</p>
<pre><code>* Red
* Green
@@ -328,7 +328,7 @@ items in <code>&lt;p&gt;</code> tags in the HTML output. For example, this input
&lt;/ul&gt;
</code></pre>
<p>List items may consist of multiple paragraphs. Each subsequent
-paragraph in a list item must be intended by either 4 spaces
+paragraph in a list item must be indented by either 4 spaces
or one tab:</p>
<pre><code>1. This is a list item with two paragraphs. Lorem ipsum dolor
sit amet, consectetuer adipiscing elit. Aliquam hendrerit
@@ -484,12 +484,12 @@ on a line by itself:</p>
<p>That is:</p>
<ul>
<li>Square brackets containing the link identifier (optionally
-indented from the left margin using up to three spaces);</li>
+ indented from the left margin using up to three spaces);</li>
<li>followed by a colon;</li>
<li>followed by one or more spaces (or tabs);</li>
<li>followed by the URL for the link;</li>
<li>optionally followed by a title attribute for the link, enclosed
-in double or single quotes.</li>
+ in double or single quotes.</li>
</ul>
<p>The link URL may, optionally, be surrounded by angle brackets:</p>
<pre><code>[id]: &lt;http://example.com/&gt; "Optional Title Here"
@@ -660,10 +660,10 @@ for links, allowing for two styles: <em>inline</em> and <em>reference</em>.</p>
<ul>
<li>An exclamation mark: <code>!</code>;</li>
<li>followed by a set of square brackets, containing the <code>alt</code>
-attribute text for the image;</li>
+ attribute text for the image;</li>
<li>followed by a set of parentheses, containing the URL or path to
-the image, and an optional <code>title</code> attribute enclosed in double
-or single quotes.</li>
+ the image, and an optional <code>title</code> attribute enclosed in double
+ or single quotes.</li>
</ul>
<p>Reference-style image syntax looks like this:</p>
<pre><code>![Alt text][id]
diff --git a/tests/markdown-test/markdown-syntax.txt b/tests/extensions/extra/markdown-syntax.txt
index dabd75c..38f6e78 100644
--- a/tests/markdown-test/markdown-syntax.txt
+++ b/tests/extensions/extra/markdown-syntax.txt
@@ -186,7 +186,7 @@ and `&` in your example code needs to be escaped.)
A paragraph is simply one or more consecutive lines of text, separated
by one or more blank lines. (A blank line is any line that looks like a
blank line -- a line containing nothing but spaces or tabs is considered
-blank.) Normal paragraphs should not be intended with spaces or tabs.
+blank.) Normal paragraphs should not be indented with spaces or tabs.
The implication of the "one or more consecutive lines of text" rule is
that Markdown supports "hard-wrapped" text paragraphs. This differs
@@ -298,7 +298,7 @@ Quote Level from the Text menu.
Markdown supports ordered (numbered) and unordered (bulleted) lists.
-Unordered lists use asterisks, pluses, and hyphens -- interchangably
+Unordered lists use asterisks, pluses, and hyphens -- interchangeably
-- as list markers:
* Red
@@ -401,7 +401,7 @@ will turn into:
</ul>
List items may consist of multiple paragraphs. Each subsequent
-paragraph in a list item must be intended by either 4 spaces
+paragraph in a list item must be indented by either 4 spaces
or one tab:
1. This is a list item with two paragraphs. Lorem ipsum dolor
diff --git a/tests/extensions/extra/named_markers.html b/tests/extensions/extra/named_markers.html
new file mode 100644
index 0000000..fd40245
--- /dev/null
+++ b/tests/extensions/extra/named_markers.html
@@ -0,0 +1,20 @@
+<p>This is the body with footnotes<sup id="fnref:foo"><a class="footnote-ref" href="#fn:foo">1</a></sup>
+that have named<sup id="fnref:bar"><a class="footnote-ref" href="#fn:bar">2</a></sup> markers and
+oddly<sup id="fnref:56"><a class="footnote-ref" href="#fn:56">3</a></sup> numbered<sup id="fnref:99"><a class="footnote-ref" href="#fn:99">4</a></sup> markers.</p>
+<div class="footnote">
+<hr />
+<ol>
+<li id="fn:foo">
+<p>Footnote marked <code>foo</code>.&#160;<a class="footnote-backref" href="#fnref:foo" title="Jump back to footnote 1 in the text">&#8617;</a></p>
+</li>
+<li id="fn:bar">
+<p>This one is marked <em>bar</em>.&#160;<a class="footnote-backref" href="#fnref:bar" title="Jump back to footnote 2 in the text">&#8617;</a></p>
+</li>
+<li id="fn:56">
+<p>A <strong>numbered</strong> footnote.&#160;<a class="footnote-backref" href="#fnref:56" title="Jump back to footnote 3 in the text">&#8617;</a></p>
+</li>
+<li id="fn:99">
+<p>The last one.&#160;<a class="footnote-backref" href="#fnref:99" title="Jump back to footnote 4 in the text">&#8617;</a></p>
+</li>
+</ol>
+</div> \ No newline at end of file
diff --git a/tests/extensions-x-footnotes/named_markers.txt b/tests/extensions/extra/named_markers.txt
index d246524..d246524 100644
--- a/tests/extensions-x-footnotes/named_markers.txt
+++ b/tests/extensions/extra/named_markers.txt
diff --git a/tests/extensions/extra/raw-html.html b/tests/extensions/extra/raw-html.html
new file mode 100644
index 0000000..ef94cb3
--- /dev/null
+++ b/tests/extensions/extra/raw-html.html
@@ -0,0 +1,123 @@
+<div>
+<p><em>foo</em></p>
+</div>
+<div class="baz">
+<p><em>bar</em></p>
+</div>
+<div>
+<p><em>blah</em></p>
+</div>
+<div name="Example">
+<p>The text of the <code>Example</code> element.</p>
+<div name="DefaultBlockMode">
+<p>This text gets wrapped in <code>p</code> tags.</p>
+</div>
+<p>The tail of the <code>DefaultBlockMode</code> subelement.</p>
+<p name="DefaultSpanMode">
+This text <em>is not</em> wrapped in additional <code>p</code> tags.
+</p>
+<p>The tail of the <code>DefaultSpanMode</code> subelement.</p>
+<div name="SpanModeOverride">
+This <code>div</code> block is not wrapped in paragraph tags.
+Note: Subelements are not required to have tail text.
+</div>
+<p name="BlockModeOverride">
+<p>This <code>p</code> block <em>is</em> foolishly wrapped in further paragraph tags.</p>
+</p>
+<p>The tail of the <code>BlockModeOverride</code> subelement.</p>
+<div name="RawHtml">
+Raw html blocks may also be nested.
+</div>
+</div>
+<p>This text is after the markdown in html.</p>
+<div name="issue308">
+<p><span>1</span>
+<span>2</span></p>
+</div>
+<div name="issue368">
+<p>Markdown is <em>active</em> here.</p>
+<div name="RawHtml">
+Raw html blocks may also be nested.
+</div>
+<p>Markdown is <em>still</em> active here.</p>
+</div>
+<p>Markdown is <em>active again</em> here.</p>
+<div>
+<p>foo bar</p>
+<p><em>bar</em></p>
+</div>
+<div name="issue584">
+<div>
+<p><a href="http://example.com">link</a></p>
+</div>
+</div>
+<div name="issue584">
+<div>
+<p><abbr title="Abbreviation">abbr</abbr></p>
+</div>
+</div>
+<div name="issue584">
+<div>
+<p>footnote<sup id="fnref:1"><a class="footnote-ref" href="#fn:1">1</a></sup></p>
+</div>
+</div>
+<div name="issue584">
+<div>
+<p><a href="http://example.com">link</a></p>
+</div>
+</div>
+<div name="issue584">
+<div>
+<p><abbr title="Abbreviation">abbr</abbr></p>
+</div>
+</div>
+<div name="issue584">
+<div>
+<p>footnote<sup id="fnref:2"><a class="footnote-ref" href="#fn:2">2</a></sup></p>
+</div>
+</div>
+<div class="footnote">
+<hr />
+<ol>
+<li id="fn:1">
+<ol>
+<li>
+<p>The top couple half figure, contrary sides and hands across with bottom couple,</p>
+<p>Half figure back on your own sides, and turn partner to places,</p>
+<p>Swing partners with right hands into straight line long-ways, as in a reel, and</p>
+<p>Set,</p>
+<p>Hey and return to places,</p>
+<p>The other three couples do the same.</p>
+</li>
+<li>
+<p>Top and bottom couples meet and set,</p>
+<p>Then each gentleman leas the opposite lady to the couple on his left, and set,</p>
+<p>Aach four right and left,</p>
+<p>Swing side couples to places, and turn partners all eight,</p>
+<p>The other two couple o the same.</p>
+</li>
+</ol>
+<p><a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text">&#8617;</a></p>
+</li>
+<li id="fn:2">
+<ol>
+<li>
+<p>The top couple half figure, contrary sides and hands across with bottom couple,</p>
+<p>Half figure back on your own sides, and turn partner to places,</p>
+<p>Swing partners with right hands into straight line long-ways, as in a reel, and</p>
+<p>Set,</p>
+<p>Hey and return to places,</p>
+<p>The other three couples do the same.</p>
+</li>
+<li>
+<p>Top and bottom couples meet and set,</p>
+<p>Then each gentleman leas the opposite lady to the couple on his left, and set,</p>
+<p>Aach four right and left,</p>
+<p>Swing side couples to places, and turn partners all eight,</p>
+<p>The other two couple o the same.</p>
+</li>
+</ol>
+<p><a class="footnote-backref" href="#fnref:2" title="Jump back to footnote 2 in the text">&#8617;</a></p>
+</li>
+</ol>
+</div> \ No newline at end of file
diff --git a/tests/extensions/extra/raw-html.txt b/tests/extensions/extra/raw-html.txt
new file mode 100644
index 0000000..c82ddbb
--- /dev/null
+++ b/tests/extensions/extra/raw-html.txt
@@ -0,0 +1,184 @@
+<div markdown="1">_foo_</div>
+
+<div markdown=1 class="baz">
+_bar_
+</div>
+
+<div markdown>
+
+_blah_
+
+</div>
+
+<div markdown="1" name="Example">
+
+The text of the `Example` element.
+
+<div markdown="1" name="DefaultBlockMode">
+This text gets wrapped in `p` tags.
+</div>
+
+The tail of the `DefaultBlockMode` subelement.
+
+<p markdown="1" name="DefaultSpanMode">
+This text *is not* wrapped in additional `p` tags.
+</p>
+
+The tail of the `DefaultSpanMode` subelement.
+
+<div markdown="span" name="SpanModeOverride">
+This `div` block is not wrapped in paragraph tags.
+Note: Subelements are not required to have tail text.
+</div>
+
+<p markdown="block" name="BlockModeOverride">
+This `p` block *is* foolishly wrapped in further paragraph tags.
+</p>
+
+The tail of the `BlockModeOverride` subelement.
+
+<div name="RawHtml">
+Raw html blocks may also be nested.
+</div>
+
+</div>
+
+This text is after the markdown in html.
+
+<div markdown="1" name="issue308">
+
+<span>1</span>
+<span>2</span>
+
+</div>
+
+<div markdown="1" name="issue368">
+
+Markdown is *active* here.
+
+<div name="RawHtml">
+Raw html blocks may also be nested.
+</div>
+
+Markdown is *still* active here.
+
+</div>
+
+Markdown is *active again* here.
+
+<div markdown=1>
+foo bar
+
+<em>bar</em>
+</div>
+
+<div markdown="1" name="issue584">
+
+[link]: http://example.com
+
+<div markdown="1">
+[link][link]
+</div>
+
+</div>
+
+<div markdown="1" name="issue584">
+
+*[abbr]: Abbreviation
+
+<div markdown="1">
+abbr
+</div>
+
+</div>
+
+<div markdown="1" name="issue584">
+
+[^1]:
+ 1. The top couple half figure, contrary sides and hands across with bottom couple,
+
+ Half figure back on your own sides, and turn partner to places,
+
+ Swing partners with right hands into straight line long-ways, as in a reel, and
+
+ Set,
+
+ Hey and return to places,
+
+ The other three couples do the same.
+
+ 2. Top and bottom couples meet and set,
+
+ Then each gentleman leas the opposite lady to the couple on his left, and set,
+
+ Aach four right and left,
+
+ Swing side couples to places, and turn partners all eight,
+
+ The other two couple o the same.
+
+<div markdown="1">
+footnote[^1]
+</div>
+
+</div>
+
+<div markdown="1" name="issue584">
+
+[link]: http://example.com
+
+
+
+
+<div markdown="1">
+[link][link]
+</div>
+
+</div>
+
+<div markdown="1" name="issue584">
+
+*[abbr]: Abbreviation
+
+
+
+
+<div markdown="1">
+abbr
+</div>
+
+</div>
+
+<div markdown="1" name="issue584">
+
+[^2]:
+ 1. The top couple half figure, contrary sides and hands across with bottom couple,
+
+ Half figure back on your own sides, and turn partner to places,
+
+ Swing partners with right hands into straight line long-ways, as in a reel, and
+
+ Set,
+
+ Hey and return to places,
+
+ The other three couples do the same.
+
+ 2. Top and bottom couples meet and set,
+
+ Then each gentleman leas the opposite lady to the couple on his left, and set,
+
+ Aach four right and left,
+
+ Swing side couples to places, and turn partners all eight,
+
+ The other two couple o the same.
+
+
+
+
+<div markdown="1">
+footnote[^2]
+</div>
+
+</div>
diff --git a/tests/extensions-x-def_list/simple_def-lists.html b/tests/extensions/extra/simple_def-lists.html
index 278e1ec..9448773 100644
--- a/tests/extensions-x-def_list/simple_def-lists.html
+++ b/tests/extensions/extra/simple_def-lists.html
@@ -34,4 +34,10 @@ line <strong>2</strong> of def 3</p>
</ul>
</dd>
</dl>
+<p>and more text.</p>
+<dl>
+<dt>term 4</dt>
+<dd>def4
+ line 2 of def 4</dd>
+</dl>
<p>final text.</p> \ No newline at end of file
diff --git a/tests/extensions-x-def_list/simple_def-lists.txt b/tests/extensions/extra/simple_def-lists.txt
index 20c028a..20e9afa 100644
--- a/tests/extensions-x-def_list/simple_def-lists.txt
+++ b/tests/extensions/extra/simple_def-lists.txt
@@ -26,4 +26,10 @@ term *3*
* > blockquote in list
+and more text.
+
+term 4
+: def4
+ line 2 of def 4
+
final text.
diff --git a/tests/extensions/github_flavored.html b/tests/extensions/github_flavored.html
new file mode 100644
index 0000000..98dc82a
--- /dev/null
+++ b/tests/extensions/github_flavored.html
@@ -0,0 +1,40 @@
+<p>index 0000000..6e956a9</p>
+<pre><code class="language-diff">--- /dev/null
++++ b/test/data/stripped_text/mike-30-lili
+@@ -0,0 +1,27 @@
++Summary:
++ drift_mod.py | 1 +
++ 1 files changed, 1 insertions(+), 0 deletions(-)
++
++commit da4bfb04debdd994683740878d09988b2641513d
++Author: Mike Dirolf &lt;mike@dirolf.com&gt;
++Date: Tue Jan 17 13:42:28 2012 -0500
++
++```
++minor: just wanted to push something.
++```
++
++diff --git a/drift_mod.py b/drift_mod.py
++index 34dfba6..8a88a69 100644
++
++```
++--- a/drift_mod.py
+++++ b/drift_mod.py
++@@ -281,6 +281,7 @@ CONTEXT_DIFF_LINE_PATTERN = re.compile(r'^('
++ '|\+ .*'
++ '|- .*'
++ ')$')
+++
++ def wrap_context_diffs(message_text):
++ return _wrap_diff(CONTEXT_DIFF_HEADER_PATTERN,
++ CONTEXT_DIFF_LINE_PATTERN,
++```
+</code></pre>
+<p>Test support for foo+bar lexer names.</p>
+<pre><code class="language-html+jinja">&lt;title&gt;{% block title %}{% endblock %}&lt;/title&gt;
+&lt;ul&gt;
+{% for user in users %}
+ &lt;li&gt;&lt;a href=&quot;{{ user.url }}&quot;&gt;{{ user.username }}&lt;/a&gt;&lt;/li&gt;
+{% endfor %}
+&lt;/ul&gt;
+</code></pre> \ No newline at end of file
diff --git a/tests/extensions/github_flavored.txt b/tests/extensions/github_flavored.txt
new file mode 100644
index 0000000..4f362b7
--- /dev/null
+++ b/tests/extensions/github_flavored.txt
@@ -0,0 +1,45 @@
+index 0000000..6e956a9
+
+```diff
+--- /dev/null
++++ b/test/data/stripped_text/mike-30-lili
+@@ -0,0 +1,27 @@
++Summary:
++ drift_mod.py | 1 +
++ 1 files changed, 1 insertions(+), 0 deletions(-)
++
++commit da4bfb04debdd994683740878d09988b2641513d
++Author: Mike Dirolf <mike@dirolf.com>
++Date: Tue Jan 17 13:42:28 2012 -0500
++
++```
++minor: just wanted to push something.
++```
++
++diff --git a/drift_mod.py b/drift_mod.py
++index 34dfba6..8a88a69 100644
++
++```
++--- a/drift_mod.py
+++++ b/drift_mod.py
++@@ -281,6 +281,7 @@ CONTEXT_DIFF_LINE_PATTERN = re.compile(r'^('
++ '|\+ .*'
++ '|- .*'
++ ')$')
+++
++ def wrap_context_diffs(message_text):
++ return _wrap_diff(CONTEXT_DIFF_HEADER_PATTERN,
++ CONTEXT_DIFF_LINE_PATTERN,
++```
+```
+
+Test support for foo+bar lexer names.
+
+```html+jinja
+<title>{% block title %}{% endblock %}</title>
+<ul>
+{% for user in users %}
+ <li><a href="{{ user.url }}">{{ user.username }}</a></li>
+{% endfor %}
+</ul>
+```
diff --git a/tests/extensions/nl2br_w_attr_list.html b/tests/extensions/nl2br_w_attr_list.html
new file mode 100644
index 0000000..e5e7eb2
--- /dev/null
+++ b/tests/extensions/nl2br_w_attr_list.html
@@ -0,0 +1 @@
+<p id="bar">Foo<br /></p> \ No newline at end of file
diff --git a/tests/extensions/nl2br_w_attr_list.txt b/tests/extensions/nl2br_w_attr_list.txt
new file mode 100644
index 0000000..4b520b5
--- /dev/null
+++ b/tests/extensions/nl2br_w_attr_list.txt
@@ -0,0 +1,2 @@
+Foo
+{: #bar} \ No newline at end of file
diff --git a/tests/extensions/sane_lists.html b/tests/extensions/sane_lists.html
new file mode 100644
index 0000000..ed51b4d
--- /dev/null
+++ b/tests/extensions/sane_lists.html
@@ -0,0 +1,32 @@
+<ol>
+<li>Ordered</li>
+<li>List</li>
+</ol>
+<ul>
+<li>Unordered</li>
+<li>List</li>
+</ul>
+<ol>
+<li>Ordered again</li>
+</ol>
+<p>Paragraph
+* not a list item</p>
+<ol>
+<li>More ordered
+* not a list item</li>
+</ol>
+<ul>
+<li>Unordered again
+1. not a list item</li>
+</ul>
+<ol start="3">
+<li>Bird</li>
+<li>McHale</li>
+<li>Parish</li>
+</ol>
+<p>Not a list</p>
+<ol start="3">
+<li>Bird</li>
+<li>McHale</li>
+<li>Parish</li>
+</ol> \ No newline at end of file
diff --git a/tests/extensions/sane_lists.txt b/tests/extensions/sane_lists.txt
new file mode 100644
index 0000000..464149f
--- /dev/null
+++ b/tests/extensions/sane_lists.txt
@@ -0,0 +1,26 @@
+1. Ordered
+2. List
+
+* Unordered
+* List
+
+1. Ordered again
+
+Paragraph
+* not a list item
+
+1. More ordered
+* not a list item
+
+* Unordered again
+1. not a list item
+
+3. Bird
+1. McHale
+8. Parish
+
+Not a list
+
+3. Bird
+1. McHale
+8. Parish \ No newline at end of file
diff --git a/tests/extensions/smarty.html b/tests/extensions/smarty.html
new file mode 100644
index 0000000..e37e377
--- /dev/null
+++ b/tests/extensions/smarty.html
@@ -0,0 +1,32 @@
+<p>&rsquo;.<br />
+1440&ndash;80&rsquo;s<br />
+1440&ndash;&rsquo;80s<br />
+1440&mdash;&rsquo;80s<br />
+1960s<br />
+1960&rsquo;s<br />
+one two &rsquo;60s<br />
+&rsquo;60s</p>
+<p>It&rsquo;s fun. What&rsquo;s fun?<br />
+&ldquo;Isn&rsquo;t this fun&rdquo;? &mdash; she said&hellip;<br />
+&ldquo;&lsquo;Quoted&rsquo; words in a larger quote.&rdquo;<br />
+&lsquo;Quoted &ldquo;words&rdquo; in a larger quote.&rsquo;<br />
+&ldquo;quoted&rdquo; text and <strong>bold &ldquo;quoted&rdquo; text</strong><br />
+&lsquo;quoted&rsquo; text and <strong>bold &lsquo;quoted&rsquo; text</strong><br />
+em-dashes (&mdash;) and ellipes (&hellip;)<br />
+&ldquo;<a href="http://example.com">Link</a>&rdquo; &mdash; she said.</p>
+<p>&ldquo;Ellipsis within quotes&hellip;&rdquo;</p>
+<p>Кавычки-&laquo;ёлочки&raquo;<br />
+&laquo;hello&raquo;<br />
+Anführungszeichen-&raquo;Chevrons&laquo;</p>
+<hr />
+<p>Escaped -- ndash<br />
+'Escaped' "quotes"<br />
+Escaped ellipsis...</p>
+<p>&lsquo;Escaped "quotes" in real ones&rsquo;<br />
+'&ldquo;Real&rdquo; quotes in escaped ones'</p>
+<p>Skip <code>&lt;&lt;all&gt;&gt; "code" -- --- 'spans' ...</code>.</p>
+<pre><code>Also skip "code" 'blocks'
+foo -- bar --- baz ...
+</code></pre>
+<p>A line that &lsquo;wraps&rsquo; with
+<em>emphasis</em> at the beginning of the next line.</p> \ No newline at end of file
diff --git a/tests/extensions/smarty.txt b/tests/extensions/smarty.txt
new file mode 100644
index 0000000..12e5c95
--- /dev/null
+++ b/tests/extensions/smarty.txt
@@ -0,0 +1,40 @@
+'.
+1440--80's
+1440--'80s
+1440---'80s
+1960s
+1960's
+one two '60s
+'60s
+
+It's fun. What's fun?
+"Isn't this fun"? --- she said...
+"'Quoted' words in a larger quote."
+'Quoted "words" in a larger quote.'
+"quoted" text and **bold "quoted" text**
+'quoted' text and **bold 'quoted' text**
+em-dashes (---) and ellipes (...)
+"[Link](http://example.com)" --- she said.
+
+"Ellipsis within quotes..."
+
+Кавычки-<<ёлочки>>
+<<hello>>
+Anführungszeichen->>Chevrons<<
+
+--- -- ---
+
+Escaped \-- ndash
+\'Escaped\' \"quotes\"
+Escaped ellipsis\...
+
+'Escaped \"quotes\" in real ones'
+\'"Real" quotes in escaped ones\'
+
+Skip `<<all>> "code" -- --- 'spans' ...`.
+
+ Also skip "code" 'blocks'
+ foo -- bar --- baz ...
+
+A line that 'wraps' with
+*emphasis* at the beginning of the next line.
diff --git a/tests/extensions-x-toc/syntax-toc.html b/tests/extensions/toc.html
index eea5347..1f06b68 100644
--- a/tests/extensions-x-toc/syntax-toc.html
+++ b/tests/extensions/toc.html
@@ -135,7 +135,7 @@ and <code>&amp;</code> in your example code needs to be escaped.)</p>
<p>A paragraph is simply one or more consecutive lines of text, separated
by one or more blank lines. (A blank line is any line that looks like a
blank line -- a line containing nothing but spaces or tabs is considered
-blank.) Normal paragraphs should not be intended with spaces or tabs.</p>
+blank.) Normal paragraphs should not be indented with spaces or tabs.</p>
<p>The implication of the "one or more consecutive lines of text" rule is
that Markdown supports "hard-wrapped" text paragraphs. This differs
significantly from most other text-to-HTML formatters (including Movable
@@ -222,7 +222,7 @@ example, with BBEdit, you can make a selection and choose Increase
Quote Level from the Text menu.</p>
<h2 id="lists">Lists</h2>
<p>Markdown supports ordered (numbered) and unordered (bulleted) lists.</p>
-<p>Unordered lists use asterisks, pluses, and hyphens -- interchangably
+<p>Unordered lists use asterisks, pluses, and hyphens -- interchangeably
-- as list markers:</p>
<pre><code>* Red
* Green
@@ -309,7 +309,7 @@ items in <code>&lt;p&gt;</code> tags in the HTML output. For example, this input
&lt;/ul&gt;
</code></pre>
<p>List items may consist of multiple paragraphs. Each subsequent
-paragraph in a list item must be intended by either 4 spaces
+paragraph in a list item must be indented by either 4 spaces
or one tab:</p>
<pre><code>1. This is a list item with two paragraphs. Lorem ipsum dolor
sit amet, consectetuer adipiscing elit. Aliquam hendrerit
@@ -461,12 +461,12 @@ on a line by itself:</p>
<p>That is:</p>
<ul>
<li>Square brackets containing the link identifier (optionally
-indented from the left margin using up to three spaces);</li>
+ indented from the left margin using up to three spaces);</li>
<li>followed by a colon;</li>
<li>followed by one or more spaces (or tabs);</li>
<li>followed by the URL for the link;</li>
<li>optionally followed by a title attribute for the link, enclosed
-in double or single quotes.</li>
+ in double or single quotes.</li>
</ul>
<p>The link URL may, optionally, be surrounded by angle brackets:</p>
<pre><code>[id]: &lt;http://example.com/&gt; "Optional Title Here"
@@ -634,10 +634,10 @@ for links, allowing for two styles: <em>inline</em> and <em>reference</em>.</p>
<ul>
<li>An exclamation mark: <code>!</code>;</li>
<li>followed by a set of square brackets, containing the <code>alt</code>
-attribute text for the image;</li>
+ attribute text for the image;</li>
<li>followed by a set of parentheses, containing the URL or path to
-the image, and an optional <code>title</code> attribute enclosed in double
-or single quotes.</li>
+ the image, and an optional <code>title</code> attribute enclosed in double
+ or single quotes.</li>
</ul>
<p>Reference-style image syntax looks like this:</p>
<pre><code>![Alt text][id]
diff --git a/tests/extensions-x-toc/syntax-toc.txt b/tests/extensions/toc.txt
index f297200..1a1de34 100644
--- a/tests/extensions-x-toc/syntax-toc.txt
+++ b/tests/extensions/toc.txt
@@ -149,7 +149,7 @@ and `&` in your example code needs to be escaped.)
A paragraph is simply one or more consecutive lines of text, separated
by one or more blank lines. (A blank line is any line that looks like a
blank line -- a line containing nothing but spaces or tabs is considered
-blank.) Normal paragraphs should not be intended with spaces or tabs.
+blank.) Normal paragraphs should not be indented with spaces or tabs.
The implication of the "one or more consecutive lines of text" rule is
that Markdown supports "hard-wrapped" text paragraphs. This differs
@@ -261,7 +261,7 @@ Quote Level from the Text menu.
Markdown supports ordered (numbered) and unordered (bulleted) lists.
-Unordered lists use asterisks, pluses, and hyphens -- interchangably
+Unordered lists use asterisks, pluses, and hyphens -- interchangeably
-- as list markers:
* Red
@@ -364,7 +364,7 @@ will turn into:
</ul>
List items may consist of multiple paragraphs. Each subsequent
-paragraph in a list item must be intended by either 4 spaces
+paragraph in a list item must be indented by either 4 spaces
or one tab:
1. This is a list item with two paragraphs. Lorem ipsum dolor
diff --git a/tests/extensions-x-toc/invalid.html b/tests/extensions/toc_invalid.html
index 41a3b1f..41a3b1f 100644
--- a/tests/extensions-x-toc/invalid.html
+++ b/tests/extensions/toc_invalid.html
diff --git a/tests/extensions-x-toc/invalid.txt b/tests/extensions/toc_invalid.txt
index f6c4ec4..f6c4ec4 100644
--- a/tests/extensions-x-toc/invalid.txt
+++ b/tests/extensions/toc_invalid.txt
diff --git a/tests/extensions/toc_nested.html b/tests/extensions/toc_nested.html
new file mode 100644
index 0000000..27af9df
--- /dev/null
+++ b/tests/extensions/toc_nested.html
@@ -0,0 +1,16 @@
+<h1 id="header-a">Header A<a class="headerlink" href="#header-a" title="Permanent link">&para;</a></h1>
+<h2 id="header-1">Header 1<a class="headerlink" href="#header-1" title="Permanent link">&para;</a></h2>
+<h3 id="header-i">Header i<a class="headerlink" href="#header-i" title="Permanent link">&para;</a></h3>
+<h1 id="header-b">Header <em>B</em><a class="headerlink" href="#header-b" title="Permanent link">&para;</a></h1>
+<div class="toc">
+<ul>
+<li><a href="#header-a">Header A</a><ul>
+<li><a href="#header-1">Header 1</a><ul>
+<li><a href="#header-i">Header i</a></li>
+</ul>
+</li>
+</ul>
+</li>
+<li><a href="#header-b">Header B</a></li>
+</ul>
+</div> \ No newline at end of file
diff --git a/tests/extensions-x-toc/nested.txt b/tests/extensions/toc_nested.txt
index 9b515f9..0f897b2 100644
--- a/tests/extensions-x-toc/nested.txt
+++ b/tests/extensions/toc_nested.txt
@@ -4,6 +4,6 @@
### Header i
-# Header B
+# Header *B*
[TOC]
diff --git a/tests/extensions/toc_nested2.html b/tests/extensions/toc_nested2.html
new file mode 100644
index 0000000..2d8fa2d
--- /dev/null
+++ b/tests/extensions/toc_nested2.html
@@ -0,0 +1,14 @@
+<div class="toc">
+<ul>
+<li><a href="#start-with-header-other-than-one">Start with header other than one.</a></li>
+<li><a href="#header-3">Header 3</a><ul>
+<li><a href="#header-4">Header 4</a></li>
+</ul>
+</li>
+<li><a href="#header-3_1">Header 3</a></li>
+</ul>
+</div>
+<h3 id="start-with-header-other-than-one">Start with header other than one.<a class="headerlink" href="#start-with-header-other-than-one" title="Permanent link">[link]</a></h3>
+<h3 id="header-3">Header 3<a class="headerlink" href="#header-3" title="Permanent link">[link]</a></h3>
+<h4 id="header-4">Header 4<a class="headerlink" href="#header-4" title="Permanent link">[link]</a></h4>
+<h3 id="header-3_1">Header 3<a class="headerlink" href="#header-3_1" title="Permanent link">[link]</a></h3> \ No newline at end of file
diff --git a/tests/extensions/toc_nested2.txt b/tests/extensions/toc_nested2.txt
new file mode 100644
index 0000000..9db4d8c
--- /dev/null
+++ b/tests/extensions/toc_nested2.txt
@@ -0,0 +1,10 @@
+[TOC]
+
+### Start with header other than one.
+
+### Header 3
+
+#### Header 4
+
+### Header 3
+
diff --git a/tests/extensions/toc_nested_list.html b/tests/extensions/toc_nested_list.html
new file mode 100644
index 0000000..6912411
--- /dev/null
+++ b/tests/extensions/toc_nested_list.html
@@ -0,0 +1,30 @@
+<h1 id="title">Title</h1>
+<div class="toc">
+<ul>
+<li><a href="#title">Title</a><ul>
+<li><a href="#section-1">Section 1</a><ul>
+<li><a href="#subsection-1">Subsection 1</a></li>
+<li><a href="#subsection-2">Subsection 2</a></li>
+</ul>
+</li>
+<li><a href="#section-2">Section 2</a></li>
+<li><a href="#section-3">Section 3</a></li>
+</ul>
+</li>
+</ul>
+</div>
+<h2 id="section-1">Section 1</h2>
+<ol>
+<li>
+<p>List Item 1</p>
+<h3 id="subsection-1">Subsection 1</h3>
+<p>Explanation 1</p>
+</li>
+<li>
+<p>List Item 2</p>
+<h3 id="subsection-2">Subsection 2</h3>
+<p>Explanation 2</p>
+</li>
+</ol>
+<h2 id="section-2">Section 2</h2>
+<h2 id="section-3">Section 3</h2> \ No newline at end of file
diff --git a/tests/extensions/toc_nested_list.txt b/tests/extensions/toc_nested_list.txt
new file mode 100644
index 0000000..d83e96f
--- /dev/null
+++ b/tests/extensions/toc_nested_list.txt
@@ -0,0 +1,19 @@
+# Title
+
+[TOC]
+
+## Section 1
+
+1. List Item 1
+
+ ### Subsection 1
+ Explanation 1
+
+2. List Item 2
+
+ ### Subsection 2
+ Explanation 2
+
+## Section 2
+
+## Section 3 \ No newline at end of file
diff --git a/tests/extensions/toc_out_of_order.html b/tests/extensions/toc_out_of_order.html
new file mode 100644
index 0000000..93d8b04
--- /dev/null
+++ b/tests/extensions/toc_out_of_order.html
@@ -0,0 +1,8 @@
+<div class="toc">
+<ul>
+<li><a href="#header-2">Header 2</a></li>
+<li><a href="#header-1">Header 1</a></li>
+</ul>
+</div>
+<h2 id="header-2">Header 2</h2>
+<h1 id="header-1">Header 1</h1> \ No newline at end of file
diff --git a/tests/extensions/toc_out_of_order.txt b/tests/extensions/toc_out_of_order.txt
new file mode 100644
index 0000000..f08bdbc
--- /dev/null
+++ b/tests/extensions/toc_out_of_order.txt
@@ -0,0 +1,5 @@
+[TOC]
+
+## Header 2
+
+# Header 1
diff --git a/tests/extensions/wikilinks.html b/tests/extensions/wikilinks.html
new file mode 100644
index 0000000..a76a693
--- /dev/null
+++ b/tests/extensions/wikilinks.html
@@ -0,0 +1,9 @@
+<p>Some text with a <a class="wikilink" href="/WikiLink/">WikiLink</a>.</p>
+<p>A link with <a class="wikilink" href="/white_space_and_underscores/">white space and_underscores</a> and a empty one.</p>
+<p>Another with <a class="wikilink" href="/double_spaces/">double spaces</a> and <a class="wikilink" href="/double__underscores/">double__underscores</a> and
+one that <a class="wikilink" href="/has_emphasis_inside/">has <em>emphasis</em> inside</a> and one <a class="wikilink" href="/with_multiple_underscores/">with_multiple_underscores</a>
+and one that is <em><a class="wikilink" href="/emphasised/">emphasised</a></em>.</p>
+<p>And a <a href="http://example.com/RealLink">RealLink</a>.</p>
+<p><a href="http://example.com/And_A_AutoLink">http://example.com/And_A_AutoLink</a></p>
+<p>And a <a href="/MarkdownLink/" title="A MarkdownLink">MarkdownLink</a> for
+completeness.</p> \ No newline at end of file
diff --git a/tests/extensions-x-wikilinks/wikilinks.txt b/tests/extensions/wikilinks.txt
index 8e6911b..8e6911b 100644
--- a/tests/extensions-x-wikilinks/wikilinks.txt
+++ b/tests/extensions/wikilinks.txt
diff --git a/tests/html4/html4.html b/tests/html4/html4.html
deleted file mode 100644
index 7c88ad7..0000000
--- a/tests/html4/html4.html
+++ /dev/null
@@ -1,2 +0,0 @@
-<p>A test of the most<br>
-basic of html/xhtml differences.</p> \ No newline at end of file
diff --git a/tests/html4/html4.txt b/tests/html4/html4.txt
deleted file mode 100644
index fddaf8e..0000000
--- a/tests/html4/html4.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-A test of the most
-basic of html/xhtml differences. \ No newline at end of file
diff --git a/tests/markdown-test/benchmark.dat b/tests/markdown-test/benchmark.dat
deleted file mode 100644
index 3d549dd..0000000
--- a/tests/markdown-test/benchmark.dat
+++ /dev/null
@@ -1,20 +0,0 @@
-construction:0.000000:0.000000
-amps-and-angle-encoding:0.070000:131072.000000
-auto-links:0.080000:397312.000000
-backlash-escapes:0.270000:884736.000000
-blockquotes-with-dode-blocks:0.020000:0.000000
-hard-wrapped:0.020000:0.000000
-horizontal-rules:0.180000:135168.000000
-inline-html-advanced:0.070000:0.000000
-inline-html-comments:0.080000:0.000000
-inline-html-simple:0.210000:0.000000
-links-inline:0.140000:0.000000
-links-reference:0.170000:0.000000
-literal-quotes:0.090000:0.000000
-markdown-documentation-basics:0.690000:1806336.000000
-markdown-syntax:3.310000:6696960.000000
-nested-blockquotes:0.200000:0.000000
-ordered-and-unordered-list:0.530000:0.000000
-strong-and-em-together:0.200000:0.000000
-tabs:0.200000:0.000000
-tidyness:0.200000:0.000000
diff --git a/tests/markdown-test/inline-html-advanced.html b/tests/markdown-test/inline-html-advanced.html
deleted file mode 100644
index af1dec1..0000000
--- a/tests/markdown-test/inline-html-advanced.html
+++ /dev/null
@@ -1,12 +0,0 @@
-<p>Simple block on one line:</p>
-<div>foo</div>
-
-<p>And nested without indentation:</p>
-<div>
-<div>
-<div>
-foo
-</div>
-</div>
-<div>bar</div>
-</div> \ No newline at end of file
diff --git a/tests/markdown-test/inline-html-advanced.txt b/tests/markdown-test/inline-html-advanced.txt
deleted file mode 100644
index 9d71ddc..0000000
--- a/tests/markdown-test/inline-html-advanced.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-Simple block on one line:
-
-<div>foo</div>
-
-And nested without indentation:
-
-<div>
-<div>
-<div>
-foo
-</div>
-</div>
-<div>bar</div>
-</div>
diff --git a/tests/markdown-test/inline-html-comments.html b/tests/markdown-test/inline-html-comments.html
deleted file mode 100644
index 0d4cad9..0000000
--- a/tests/markdown-test/inline-html-comments.html
+++ /dev/null
@@ -1,11 +0,0 @@
-<p>Paragraph one.</p>
-<!-- This is a simple comment -->
-
-<!--
- This is another comment.
--->
-
-<p>Paragraph two.</p>
-<!-- one comment block -- -- with two comments -->
-
-<p>The end.</p> \ No newline at end of file
diff --git a/tests/markdown-test/inline-html-comments.txt b/tests/markdown-test/inline-html-comments.txt
deleted file mode 100644
index 41d830d..0000000
--- a/tests/markdown-test/inline-html-comments.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-Paragraph one.
-
-<!-- This is a simple comment -->
-
-<!--
- This is another comment.
--->
-
-Paragraph two.
-
-<!-- one comment block -- -- with two comments -->
-
-The end.
diff --git a/tests/markdown-test/inline-html-simple.html b/tests/markdown-test/inline-html-simple.html
deleted file mode 100644
index cb10451..0000000
--- a/tests/markdown-test/inline-html-simple.html
+++ /dev/null
@@ -1,58 +0,0 @@
-<p>Here's a simple block:</p>
-<div>
- foo
-</div>
-
-<p>This should be a code block, though:</p>
-<pre><code>&lt;div&gt;
- foo
-&lt;/div&gt;
-</code></pre>
-<p>As should this:</p>
-<pre><code>&lt;div&gt;foo&lt;/div&gt;
-</code></pre>
-<p>Now, nested:</p>
-<div>
- <div>
- <div>
- foo
- </div>
- </div>
-</div>
-
-<p>This should just be an HTML comment:</p>
-<!-- Comment -->
-
-<p>Multiline:</p>
-<!--
-Blah
-Blah
--->
-
-<p>Code block:</p>
-<pre><code>&lt;!-- Comment --&gt;
-</code></pre>
-<p>Just plain comment, with trailing spaces on the line:</p>
-<!-- foo -->
-
-<p>Code:</p>
-<pre><code>&lt;hr /&gt;
-</code></pre>
-<p>Hr's:</p>
-<hr>
-
-<hr/>
-
-<hr />
-
-<hr>
-
-<hr/>
-
-<hr />
-
-<hr class="foo" id="bar" />
-
-<hr class="foo" id="bar"/>
-
-<hr class="foo" id="bar" > \ No newline at end of file
diff --git a/tests/markdown-test/inline-html-simple.txt b/tests/markdown-test/inline-html-simple.txt
deleted file mode 100644
index 14aa2dc..0000000
--- a/tests/markdown-test/inline-html-simple.txt
+++ /dev/null
@@ -1,69 +0,0 @@
-Here's a simple block:
-
-<div>
- foo
-</div>
-
-This should be a code block, though:
-
- <div>
- foo
- </div>
-
-As should this:
-
- <div>foo</div>
-
-Now, nested:
-
-<div>
- <div>
- <div>
- foo
- </div>
- </div>
-</div>
-
-This should just be an HTML comment:
-
-<!-- Comment -->
-
-Multiline:
-
-<!--
-Blah
-Blah
--->
-
-Code block:
-
- <!-- Comment -->
-
-Just plain comment, with trailing spaces on the line:
-
-<!-- foo -->
-
-Code:
-
- <hr />
-
-Hr's:
-
-<hr>
-
-<hr/>
-
-<hr />
-
-<hr>
-
-<hr/>
-
-<hr />
-
-<hr class="foo" id="bar" />
-
-<hr class="foo" id="bar"/>
-
-<hr class="foo" id="bar" >
-
diff --git a/tests/markdown-test/links-reference.html b/tests/markdown-test/links-reference.html
deleted file mode 100644
index 165c71a..0000000
--- a/tests/markdown-test/links-reference.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<p>Foo <a href="/url/" title="Title">bar</a>.</p>
-<p>Foo <a href="/url/" title="Title">bar</a>.</p>
-<p>Foo <a href="/url/" title="Title">bar</a>.</p>
-<p>With <a href="/url/">embedded [brackets]</a>.</p>
-<p>Indented <a href="/url">once</a>.</p>
-<p>Indented <a href="/url">twice</a>.</p>
-<p>Indented <a href="/url">thrice</a>.</p>
-<p>Indented [four][] times.</p>
-<pre><code>[four]: /url
-</code></pre> \ No newline at end of file
diff --git a/tests/markdown-test/links-reference.txt b/tests/markdown-test/links-reference.txt
deleted file mode 100644
index b2fa734..0000000
--- a/tests/markdown-test/links-reference.txt
+++ /dev/null
@@ -1,31 +0,0 @@
-Foo [bar] [1].
-
-Foo [bar][1].
-
-Foo [bar]
-[1].
-
-[1]: /url/ "Title"
-
-
-With [embedded [brackets]] [b].
-
-
-Indented [once][].
-
-Indented [twice][].
-
-Indented [thrice][].
-
-Indented [four][] times.
-
- [once]: /url
-
- [twice]: /url
-
- [thrice]: /url
-
- [four]: /url
-
-
-[b]: /url/
diff --git a/tests/misc/amp-in-url.html b/tests/misc/amp-in-url.html
deleted file mode 100644
index 2170a54..0000000
--- a/tests/misc/amp-in-url.html
+++ /dev/null
@@ -1 +0,0 @@
-<p><a href="http://www.freewisdom.org/this&amp;that">link</a></p> \ No newline at end of file
diff --git a/tests/misc/amp-in-url.txt b/tests/misc/amp-in-url.txt
deleted file mode 100644
index 471106e..0000000
--- a/tests/misc/amp-in-url.txt
+++ /dev/null
@@ -1 +0,0 @@
-[link](http://www.freewisdom.org/this&that)
diff --git a/tests/misc/ampersand.html b/tests/misc/ampersand.html
deleted file mode 100644
index 94ed80c..0000000
--- a/tests/misc/ampersand.html
+++ /dev/null
@@ -1,2 +0,0 @@
-<p>&amp;</p>
-<p>AT&amp;T</p> \ No newline at end of file
diff --git a/tests/misc/ampersand.txt b/tests/misc/ampersand.txt
deleted file mode 100644
index 367d32c..0000000
--- a/tests/misc/ampersand.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-&
-
-AT&T
-
-
diff --git a/tests/misc/attributes2.html b/tests/misc/attributes2.html
deleted file mode 100644
index 5971cc8..0000000
--- a/tests/misc/attributes2.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<p id="TABLE.OF.CONTENTS" />
-<ul>
-<li id="TABLEOFCONTENTS" />
-</ul>
-<p id="TABLEOFCONTENTS">Or in the middle of the text </p>
-<p id="tableofcontents" /> \ No newline at end of file
diff --git a/tests/misc/attributes2.txt b/tests/misc/attributes2.txt
deleted file mode 100644
index d635cb2..0000000
--- a/tests/misc/attributes2.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-{@id=TABLE.OF.CONTENTS}
-
-
-* {@id=TABLEOFCONTENTS}
-
-
-Or in the middle of the text {@id=TABLEOFCONTENTS}
-
-{@id=tableofcontents}
-
diff --git a/tests/misc/backtick-escape.html b/tests/misc/backtick-escape.html
index 07f5115..da30541 100644
--- a/tests/misc/backtick-escape.html
+++ b/tests/misc/backtick-escape.html
@@ -1,3 +1,4 @@
-<p>\`This should not be in code.\`
-`This also should not be in code.`
+<p>`This should not be in code.`
+\<code>This should be in code.\\</code>
+\`This should not be in code.\`
`And finally this should not be in code.`</p> \ No newline at end of file
diff --git a/tests/misc/backtick-escape.txt b/tests/misc/backtick-escape.txt
index b4d80b2..c019463 100644
--- a/tests/misc/backtick-escape.txt
+++ b/tests/misc/backtick-escape.txt
@@ -1,3 +1,4 @@
-\\`This should not be in code.\\`
-\`This also should not be in code.\`
+\`This should not be in code.\`
+\\`This should be in code.\\`
+\\\`This should not be in code.\\\`
\`And finally this should not be in code.`
diff --git a/tests/misc/bidi.html b/tests/misc/bidi.html
index ffe04dc..3cc0444 100644
--- a/tests/misc/bidi.html
+++ b/tests/misc/bidi.html
@@ -1,7 +1,7 @@
<p><strong>Python</strong>(パイソン)は、<a href="http://en.wikipedia.org/wiki/Guido_van_Rossum">Guido van Rossum</a> によって作られたオープンソースのオブジェクト指向スクリプト言語。<a href="http://ja.wikipedia.org/wiki/Perl">Perl</a>とともに欧米で広く普及している。イギリスのテレビ局 BBC が製作したコメディ番組『空飛ぶモンティ・パイソン』にちなんで名付けられた。 (Pythonには、爬虫類のニシキヘビの意味があり、Python言語のマスコットやアイコンとして使われることがある。)</p>
<p>|||||||||||||||||||||||||||||THIS SHOULD BE LTR|||||||||||||||||||||||||</p>
-<p dir="rtl">|||||||||||||||||||||||||||||THIS SHOULD BE RTL||||||||||||||||||||||||| </p>
-<p dir="ltr">(<strong>بايثون</strong> لغة برمجة حديثة بسيطة، واضحة، سريعة ، تستخدم أسلوب البرمجة الكائنية (THIS SHOULD BE LTR ) وقابلة للتطوير بالإضافة إلى أنها مجانية و مفتوح </p>
+<p>|||||||||||||||||||||||||||||THIS SHOULD BE RTL||||||||||||||||||||||||| </p>
+<p>(<strong>بايثون</strong> لغة برمجة حديثة بسيطة، واضحة، سريعة ، تستخدم أسلوب البرمجة الكائنية (THIS SHOULD BE LTR ) وقابلة للتطوير بالإضافة إلى أنها مجانية و مفتوح </p>
<p>پایتون زبان برنامه‌نویسی تفسیری و سطح بالا ، شی‌گرا و یک زبان برنامه‌نویسی تفسیری سمت سرور قدرتمند است که توسط گیدو ون روسوم در سال ۱۹۹۰ ساخته شد. این زبان در ویژگی‌ها شبیه پرل، روبی، اسکیم، اسمال‌تاک و تی‌سی‌ال است و از مدیریت خودکار حافظه استفاده می‌کند</p>
<p>Python,是一种面向对象的、直譯式的计算机程序设计语言,也是一种功能强大而完善的通用型语言,已经具有十多年的发展历史,成熟且稳定。</p>
<p>ބްލޫ ވޭލްގެ ދޫ މަތީގައި އެއްފަހަރާ 50 މީހުންނަށް ތިބެވިދާނެވެ. ބޮޑު މަހުގެ ދުލަކީ އެހާމެ ބޮޑު އެއްޗެކެވެ.</p>
diff --git a/tests/misc/bidi.txt b/tests/misc/bidi.txt
index f11ff1c..7e6dbea 100644
--- a/tests/misc/bidi.txt
+++ b/tests/misc/bidi.txt
@@ -2,10 +2,10 @@
|||||||||||||||||||||||||||||THIS SHOULD BE LTR|||||||||||||||||||||||||
-|||||||||||||||||||||||||||||THIS SHOULD BE RTL||||||||||||||||||||||||| {@dir=rtl}
+|||||||||||||||||||||||||||||THIS SHOULD BE RTL|||||||||||||||||||||||||
-(**بايثون** لغة برمجة حديثة بسيطة، واضحة، سريعة ، تستخدم أسلوب البرمجة الكائنية (THIS SHOULD BE LTR ) وقابلة للتطوير {@dir=ltr} بالإضافة إلى أنها مجانية و مفتوح
+(**بايثون** لغة برمجة حديثة بسيطة، واضحة، سريعة ، تستخدم أسلوب البرمجة الكائنية (THIS SHOULD BE LTR ) وقابلة للتطوير بالإضافة إلى أنها مجانية و مفتوح
diff --git a/tests/misc/blank-block-quote.html b/tests/misc/blank-block-quote.html
index 23df17a..966078c 100644
--- a/tests/misc/blank-block-quote.html
+++ b/tests/misc/blank-block-quote.html
@@ -1,3 +1,3 @@
<p>aaaaaaaaaaa</p>
-<blockquote />
+<blockquote></blockquote>
<p>bbbbbbbbbbb</p> \ No newline at end of file
diff --git a/tests/misc/blank_lines_in_codeblocks.html b/tests/misc/blank_lines_in_codeblocks.html
new file mode 100644
index 0000000..57a4c36
--- /dev/null
+++ b/tests/misc/blank_lines_in_codeblocks.html
@@ -0,0 +1,61 @@
+<p>Preserve blank lines in code blocks with tabs:</p>
+<pre><code>a code block
+
+two tabbed lines
+
+
+three tabbed lines
+
+
+
+four tabbed lines
+
+
+
+
+five tabbed lines
+
+
+
+
+
+six tabbed lines
+
+
+
+
+
+
+End of tabbed block
+</code></pre>
+<p>And without tabs:</p>
+<pre><code>a code block
+
+two blank lines
+
+
+three blank lines
+
+
+
+four blank lines
+
+
+
+
+five blank lines
+
+
+
+
+
+six blank lines
+
+
+
+
+
+
+End of block
+</code></pre>
+<p>End of document</p> \ No newline at end of file
diff --git a/tests/misc/blank_lines_in_codeblocks.txt b/tests/misc/blank_lines_in_codeblocks.txt
new file mode 100644
index 0000000..e7ae102
--- /dev/null
+++ b/tests/misc/blank_lines_in_codeblocks.txt
@@ -0,0 +1,73 @@
+Preserve blank lines in code blocks with tabs:
+
+ a code block
+
+ two tabbed lines
+
+
+ three tabbed lines
+
+
+
+ four tabbed lines
+
+
+
+
+ five tabbed lines
+
+
+
+
+
+ six tabbed lines
+
+
+
+
+
+
+ End of tabbed block
+
+
+
+
+
+
+And without tabs:
+
+ a code block
+
+ two blank lines
+
+
+ three blank lines
+
+
+
+ four blank lines
+
+
+
+
+ five blank lines
+
+
+
+
+
+ six blank lines
+
+
+
+
+
+
+ End of block
+
+
+
+
+
+
+End of document \ No newline at end of file
diff --git a/tests/misc/blockquote-hr.html b/tests/misc/blockquote-hr.html
index 61c1a3c..e13784f 100644
--- a/tests/misc/blockquote-hr.html
+++ b/tests/misc/blockquote-hr.html
@@ -13,4 +13,13 @@ With multiple lines.
Even a lazy line.</p>
<hr />
<p>The last line.</p>
+</blockquote>
+<p>foo</p>
+<blockquote>
+<p>bar</p>
+<hr />
+</blockquote>
+<hr />
+<blockquote>
+<p>baz</p>
</blockquote> \ No newline at end of file
diff --git a/tests/misc/blockquote-hr.txt b/tests/misc/blockquote-hr.txt
index ef9c44f..8f67b24 100644
--- a/tests/misc/blockquote-hr.txt
+++ b/tests/misc/blockquote-hr.txt
@@ -19,3 +19,9 @@ Even a lazy line.
> ---
> The last line.
+
+foo
+> bar
+> ***
+---
+> baz
diff --git a/tests/misc/br.html b/tests/misc/br.html
index 08563a5..e8e6fdf 100644
--- a/tests/misc/br.html
+++ b/tests/misc/br.html
@@ -8,4 +8,4 @@ Or, if you prefer, &lt;strong&gt;use two underscores instead&lt;/strong&gt;.&lt;
<h2>Lists</h2>
<p>Unordered (bulleted) lists use asterisks, pluses, and hyphens (<code>*</code>,
<code>+</code>, and <code>-</code>) as list markers. These three markers are
-interchangable; this:</p> \ No newline at end of file
+interchangeable; this:</p> \ No newline at end of file
diff --git a/tests/misc/br.txt b/tests/misc/br.txt
index 59d29e0..19f4cf1 100644
--- a/tests/misc/br.txt
+++ b/tests/misc/br.txt
@@ -12,5 +12,5 @@ Output:
Unordered (bulleted) lists use asterisks, pluses, and hyphens (`*`,
`+`, and `-`) as list markers. These three markers are
-interchangable; this:
+interchangeable; this:
diff --git a/tests/misc/brackets-in-img-title.html b/tests/misc/brackets-in-img-title.html
new file mode 100644
index 0000000..3677139
--- /dev/null
+++ b/tests/misc/brackets-in-img-title.html
@@ -0,0 +1,9 @@
+<p><img alt="alt" src="local-img.jpg" />
+<img alt="alt" src="local-img.jpg" title="" />
+<img alt="alt" src="local-img.jpg" title="normal title" /></p>
+<p><img alt="alt" src="local-img.jpg" title="(just title in brackets)" />
+<img alt="alt" src="local-img.jpg" title="title with brackets (I think)" /></p>
+<p><img alt="alt" src="local-img.jpg" title="(" />
+<img alt="alt" src="local-img.jpg" title="(open only" />
+<img alt="alt" src="local-img.jpg" title=")" />
+<img alt="alt" src="local-img.jpg" title="close only)" /></p> \ No newline at end of file
diff --git a/tests/misc/brackets-in-img-title.txt b/tests/misc/brackets-in-img-title.txt
new file mode 100644
index 0000000..01fcd4e
--- /dev/null
+++ b/tests/misc/brackets-in-img-title.txt
@@ -0,0 +1,12 @@
+![alt](local-img.jpg)
+![alt](local-img.jpg "")
+![alt](local-img.jpg "normal title")
+
+![alt](local-img.jpg "(just title in brackets)")
+![alt](local-img.jpg "title with brackets (I think)")
+
+![alt](local-img.jpg "(")
+![alt](local-img.jpg "(open only")
+![alt](local-img.jpg ")")
+![alt](local-img.jpg "close only)")
+
diff --git a/tests/misc/comments.html b/tests/misc/comments.html
deleted file mode 100644
index 005a755..0000000
--- a/tests/misc/comments.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<p>X&lt;0</p>
-<p>X&gt;0</p>
-<!-- A comment -->
-
-<div>as if</div> \ No newline at end of file
diff --git a/tests/misc/comments.txt b/tests/misc/comments.txt
deleted file mode 100644
index 68302b0..0000000
--- a/tests/misc/comments.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-X<0
-
-X>0
-
-<!-- A comment -->
-
-<div>as if</div>
diff --git a/tests/misc/div.html b/tests/misc/div.html
deleted file mode 100644
index 7cd0d6d..0000000
--- a/tests/misc/div.html
+++ /dev/null
@@ -1,4 +0,0 @@
-<div id="sidebar">
-
-<p><em>foo</em></p>
-</div> \ No newline at end of file
diff --git a/tests/misc/div.txt b/tests/misc/div.txt
deleted file mode 100644
index ca87745..0000000
--- a/tests/misc/div.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-<div id="sidebar">
-
- _foo_
-
-</div>
diff --git a/tests/misc/em-around-links.html b/tests/misc/em-around-links.html
index 06bfa8e..cc415f5 100644
--- a/tests/misc/em-around-links.html
+++ b/tests/misc/em-around-links.html
@@ -1,16 +1,13 @@
<h1>Title</h1>
-
<ul>
- <li><em><a href="http://www.freewisdom.org/projects/python-markdown/">Python in Markdown</a> by some
+<li><em><a href="http://example.com">Python in Markdown</a> by some
great folks</em> - This <em>does</em> work as expected.</li>
- <li><em><a href="http://www.freewisdom.org/projects/python-markdown/">Python in Markdown</a> by some
+<li><em><a href="http://example.com">Python in Markdown</a> by some
great folks</em> - This <em>does</em> work as expected.</li>
- <li><a href="http://www.freewisdom.org/projects/python-markdown/"><em>Python in Markdown</em></a> by some
+<li><a href="http://example.com"><em>Python in Markdown</em></a> by some
great folks - This <em>does</em> work as expected.</li>
- <li><a href="http://www.freewisdom.org/projects/python-markdown/"><em>Python in Markdown</em></a> <em>by some
+<li><a href="http://example.com"><em>Python in Markdown</em></a> <em>by some
great folks</em> - This <em>does</em> work as expected.</li>
</ul>
-
-<p><em><a href="http://www.freewisdom.org/projects/python-markdown/">Python in Markdown</a> by some
- great folks</em> - This <em>does</em> work as expected.</p>
-
+<p><em><a href="http://example.com">Python in Markdown</a> by some
+great folks</em> - This <em>does</em> work as expected.</p> \ No newline at end of file
diff --git a/tests/misc/em-around-links.txt b/tests/misc/em-around-links.txt
index 5b15be4..dbc3644 100644
--- a/tests/misc/em-around-links.txt
+++ b/tests/misc/em-around-links.txt
@@ -1,14 +1,14 @@
# Title
- - *[Python in Markdown](http://www.freewisdom.org/projects/python-markdown/) by some
+ - *[Python in Markdown](http://example.com) by some
great folks* - This *does* work as expected.
- - _[Python in Markdown](http://www.freewisdom.org/projects/python-markdown/) by some
+ - _[Python in Markdown](http://example.com) by some
great folks_ - This *does* work as expected.
- - [_Python in Markdown_](http://www.freewisdom.org/projects/python-markdown/) by some
+ - [_Python in Markdown_](http://example.com) by some
great folks - This *does* work as expected.
- - [_Python in Markdown_](http://www.freewisdom.org/projects/python-markdown/) _by some
+ - [_Python in Markdown_](http://example.com) _by some
great folks_ - This *does* work as expected.
-_[Python in Markdown](http://www.freewisdom.org/projects/python-markdown/) by some
+_[Python in Markdown](http://example.com) by some
great folks_ - This *does* work as expected.
diff --git a/tests/misc/em_strong.html b/tests/misc/em_strong.html
index 75c92d8..776381b 100644
--- a/tests/misc/em_strong.html
+++ b/tests/misc/em_strong.html
@@ -7,4 +7,5 @@
<p>three asterisks: ***</p>
<p>with spaces: * * *</p>
<p>three underscores: ___</p>
-<p>with spaces: _ _ _</p> \ No newline at end of file
+<p>with spaces: _ _ _</p>
+<p>One char: <em>a</em></p> \ No newline at end of file
diff --git a/tests/misc/em_strong.txt b/tests/misc/em_strong.txt
index d0774ad..1285665 100644
--- a/tests/misc/em_strong.txt
+++ b/tests/misc/em_strong.txt
@@ -18,3 +18,4 @@ three underscores: ___
with spaces: _ _ _
+One char: _a_
diff --git a/tests/misc/em_strong_complex.html b/tests/misc/em_strong_complex.html
new file mode 100644
index 0000000..65faddf
--- /dev/null
+++ b/tests/misc/em_strong_complex.html
@@ -0,0 +1,14 @@
+<p><em><strong>test test</strong> test test</em></p>
+<p><strong><em>test test</em> test test</strong></p>
+<p><strong><em>test</em></strong></p>
+<p><strong>test</strong></p>
+<p><strong><em>test</em> test</strong>_</p>
+<p><strong><em>test</em> test</strong></p>
+<p><em>test_test test_test</em></p>
+<p><em><strong>test test</strong> test test</em></p>
+<p><strong><em>test test</em> test test</strong></p>
+<p>*<em>test</em></p>
+<p><strong><em>test</em></strong></p>
+<p><strong>test</strong>*</p>
+<p><strong><em>test</em> test</strong></p>
+<p><em>test</em>test test<em>test</em></p> \ No newline at end of file
diff --git a/tests/misc/em_strong_complex.txt b/tests/misc/em_strong_complex.txt
new file mode 100644
index 0000000..0425971
--- /dev/null
+++ b/tests/misc/em_strong_complex.txt
@@ -0,0 +1,27 @@
+___test test__ test test_
+
+___test test_ test test__
+
+___test___
+
+__test__
+
+___test_ test___
+
+___test_ test__
+
+_test_test test_test_
+
+***test test** test test*
+
+***test test* test test**
+
+**test*
+
+***test***
+
+**test***
+
+***test* test**
+
+*test*test test*test* \ No newline at end of file
diff --git a/tests/misc/email.html b/tests/misc/email.html
index 0d033bb..8ef799f 100644
--- a/tests/misc/email.html
+++ b/tests/misc/email.html
@@ -1,2 +1,3 @@
<p>asdfasdfadsfasd <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#121;&#117;&#114;&#105;&#64;&#102;&#114;&#101;&#101;&#119;&#105;&#115;&#100;&#111;&#109;&#46;&#111;&#114;&#103;">&#121;&#117;&#114;&#105;&#64;&#102;&#114;&#101;&#101;&#119;&#105;&#115;&#100;&#111;&#109;&#46;&#111;&#114;&#103;</a> or you can say
-instead <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#121;&#117;&#114;&#105;&#64;&#102;&#114;&#101;&#101;&#119;&#105;&#115;&#100;&#111;&#109;&#46;&#111;&#114;&#103;">&#121;&#117;&#114;&#105;&#64;&#102;&#114;&#101;&#101;&#119;&#105;&#115;&#100;&#111;&#109;&#46;&#111;&#114;&#103;</a></p> \ No newline at end of file
+instead <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#121;&#117;&#114;&#105;&#64;&#102;&#114;&#101;&#101;&#119;&#105;&#115;&#100;&#111;&#109;&#46;&#111;&#114;&#103;">&#121;&#117;&#114;&#105;&#64;&#102;&#114;&#101;&#101;&#119;&#105;&#115;&#100;&#111;&#109;&#46;&#111;&#114;&#103;</a></p>
+<p><a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#98;&#111;&#98;&#38;&#115;&#117;&#101;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;">&#98;&#111;&#98;&amp;&#115;&#117;&#101;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;</a></p> \ No newline at end of file
diff --git a/tests/misc/email.txt b/tests/misc/email.txt
index ece8801..c557c73 100644
--- a/tests/misc/email.txt
+++ b/tests/misc/email.txt
@@ -1,3 +1,5 @@
asdfasdfadsfasd <yuri@freewisdom.org> or you can say
instead <mailto:yuri@freewisdom.org>
+
+<bob&sue@example.com>
diff --git a/tests/misc/escaped_links.html b/tests/misc/escaped_links.html
new file mode 100644
index 0000000..b2a7c96
--- /dev/null
+++ b/tests/misc/escaped_links.html
@@ -0,0 +1,4 @@
+<p>Backslashed in links:</p>
+<p><a href="/query?q=go:GO\:0000307">q=go:GO\:0000307</a></p>
+<p><a href="/query?q=go:GO\:0000308" title="/query?q=go:GO\:0000308">q=go:GO\:0000308</a></p>
+<p>a \non-escaped char.</p> \ No newline at end of file
diff --git a/tests/misc/escaped_links.txt b/tests/misc/escaped_links.txt
new file mode 100644
index 0000000..c64ab26
--- /dev/null
+++ b/tests/misc/escaped_links.txt
@@ -0,0 +1,9 @@
+Backslashed in links:
+
+[q=go:GO\\:0000307](/query?q=go:GO\\:0000307)
+
+[q=go:GO\\:0000308][foo]
+
+[foo]: /query?q=go:GO\:0000308 "/query?q=go:GO\:0000308"
+
+a \non-escaped char. \ No newline at end of file
diff --git a/tests/misc/h1.html b/tests/misc/h1.html
index fbf9b4d..886b61e 100644
--- a/tests/misc/h1.html
+++ b/tests/misc/h1.html
@@ -1,3 +1,5 @@
<h2>Header</h2>
<h1>Header 2</h1>
-<h3>H3</h3> \ No newline at end of file
+<h3>H3</h3>
+<h1>H1</h1>
+<h2>H2</h2> \ No newline at end of file
diff --git a/tests/misc/h1.txt b/tests/misc/h1.txt
index 0a1c8f9..f67b921 100644
--- a/tests/misc/h1.txt
+++ b/tests/misc/h1.txt
@@ -5,3 +5,9 @@ Header 2
========
### H3
+
+H1
+=
+
+H2
+--
diff --git a/tests/misc/header-in-lists.html b/tests/misc/header-in-lists.html
new file mode 100644
index 0000000..351b44a
--- /dev/null
+++ b/tests/misc/header-in-lists.html
@@ -0,0 +1,20 @@
+<p>Tight List:</p>
+<ul>
+<li>
+<h1>Header1</h1>
+Line 1-2 - <strong>not</strong> a header <em>or</em> paragraph!</li>
+<li>
+<h1>Header2</h1>
+Line 2-2 - not a header or paragraph!</li>
+</ul>
+<p>Loose List:</p>
+<ul>
+<li>
+<h1>Header1</h1>
+<p>Line 1-2 - <em>a</em> paragraph</p>
+</li>
+<li>
+<h1>Header2</h1>
+<p>Line 2-2 - a paragraph</p>
+</li>
+</ul> \ No newline at end of file
diff --git a/tests/misc/header-in-lists.txt b/tests/misc/header-in-lists.txt
new file mode 100644
index 0000000..b22083e
--- /dev/null
+++ b/tests/misc/header-in-lists.txt
@@ -0,0 +1,14 @@
+Tight List:
+
+* #Header1
+Line 1-2 - **not** a header *or* paragraph!
+* #Header2
+Line 2-2 - not a header or paragraph!
+
+Loose List:
+
+* #Header1
+Line 1-2 - *a* paragraph
+
+* #Header2
+Line 2-2 - a paragraph
diff --git a/tests/misc/html-comments.html b/tests/misc/html-comments.html
deleted file mode 100644
index 7b36246..0000000
--- a/tests/misc/html-comments.html
+++ /dev/null
@@ -1,2 +0,0 @@
-<p>Here is HTML <!-- **comment** -->
-and once more <p><!--comment--></p></p> \ No newline at end of file
diff --git a/tests/misc/html-comments.txt b/tests/misc/html-comments.txt
deleted file mode 100644
index cac4da5..0000000
--- a/tests/misc/html-comments.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-Here is HTML <!-- **comment** -->
-and once more <p><!--comment--></p>
diff --git a/tests/misc/html.html b/tests/misc/html.html
deleted file mode 100644
index 81ac5ee..0000000
--- a/tests/misc/html.html
+++ /dev/null
@@ -1,9 +0,0 @@
-<h1>Block level html</h1>
-
-<p>Some inline <b>stuff<b>.<br />
-</p>
-<p>Now some <arbitrary>arbitrary tags</arbitrary>.</p>
-<div>More block level html.</div>
-
-<p>And of course <script>blah</script>.</p>
-<p><a href="script&gt;stuff&lt;/script">this <script>link</a></p> \ No newline at end of file
diff --git a/tests/misc/html.txt b/tests/misc/html.txt
deleted file mode 100644
index 3ac3ae0..0000000
--- a/tests/misc/html.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-
-<h1>Block level html</h1>
-
-Some inline <b>stuff<b>.
-
-Now some <arbitrary>arbitrary tags</arbitrary>.
-
-<div>More block level html.</div>
-
-And of course <script>blah</script>.
-
-[this <script>link](<script>stuff</script>)
-
diff --git a/tests/misc/image.html b/tests/misc/image.html
deleted file mode 100644
index 16be2d5..0000000
--- a/tests/misc/image.html
+++ /dev/null
@@ -1 +0,0 @@
-<p><img alt="Poster" src="http://humane_man.jpg" title="The most humane man." /></p> \ No newline at end of file
diff --git a/tests/misc/image.txt b/tests/misc/image.txt
deleted file mode 100644
index 5553bd4..0000000
--- a/tests/misc/image.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-
-![Poster](http://humane_man.jpg "The most humane man.")
diff --git a/tests/misc/ins-at-start-of-paragraph.html b/tests/misc/ins-at-start-of-paragraph.html
new file mode 100644
index 0000000..a08524e
--- /dev/null
+++ b/tests/misc/ins-at-start-of-paragraph.html
@@ -0,0 +1 @@
+<p><ins>Hello, fellow developer</ins> this ins should be wrapped in a p.</p> \ No newline at end of file
diff --git a/tests/misc/ins-at-start-of-paragraph.txt b/tests/misc/ins-at-start-of-paragraph.txt
new file mode 100644
index 0000000..2aee0bc
--- /dev/null
+++ b/tests/misc/ins-at-start-of-paragraph.txt
@@ -0,0 +1 @@
+<ins>Hello, fellow developer</ins> this ins should be wrapped in a p.
diff --git a/tests/misc/lists3.html b/tests/misc/lists3.html
index 991395b..7cfe001 100644
--- a/tests/misc/lists3.html
+++ b/tests/misc/lists3.html
@@ -1,5 +1,5 @@
<ul>
<li>blah blah blah
-sdf asdf asdf asdf asdf
-asda asdf asdfasd</li>
+ sdf asdf asdf asdf asdf
+ asda asdf asdfasd</li>
</ul> \ No newline at end of file
diff --git a/tests/misc/lists7.html b/tests/misc/lists7.html
new file mode 100644
index 0000000..81c1daa
--- /dev/null
+++ b/tests/misc/lists7.html
@@ -0,0 +1,98 @@
+<ul>
+<li>item 1</li>
+<li>
+<ul>
+<li>item 2-1</li>
+<li>item 2-2</li>
+<li>item 2-3</li>
+<li>item 2-4</li>
+</ul>
+</li>
+<li>item 3</li>
+<li>
+<ul>
+<li>
+<p>item 4-1</p>
+</li>
+<li>
+<p>item 4-2</p>
+</li>
+<li>
+<p>item 4-3</p>
+</li>
+<li>
+<p>item 4-4</p>
+</li>
+</ul>
+</li>
+</ul>
+<h2>same as above, different spacing</h2>
+<ul>
+<li>item 1</li>
+<li>
+<ul>
+<li>item 2-1</li>
+<li>item 2-2</li>
+</ul>
+</li>
+<li>item 3</li>
+<li>
+<ul>
+<li>
+<p>item 4-1</p>
+</li>
+<li>
+<p>item 4-2</p>
+</li>
+</ul>
+</li>
+</ul>
+<h2>only 1 item in nested list ##</h2>
+<ul>
+<li>item 1</li>
+<li>
+<ul>
+<li>item 2-1</li>
+</ul>
+</li>
+<li>item 3</li>
+<li>
+<ul>
+<li>item 4-1</li>
+</ul>
+</li>
+</ul>
+<h2>Something ludicrous ##</h2>
+<ul>
+<li>item 1</li>
+<li>
+<ul>
+<li>item 2-1</li>
+<li>item 2-2</li>
+<li>
+<ul>
+<li>item 2-2-1</li>
+<li>item 2-2-2</li>
+</ul>
+</li>
+<li>item 2-3</li>
+</ul>
+</li>
+<li>item 3</li>
+<li>
+<ul>
+<li>
+<p>item 4-1</p>
+</li>
+<li>
+<ul>
+<li>item 4-1-1</li>
+<li>item 4-1-2</li>
+</ul>
+</li>
+<li>
+<p>item 4-2</p>
+</li>
+</ul>
+</li>
+</ul> \ No newline at end of file
diff --git a/tests/misc/lists7.txt b/tests/misc/lists7.txt
new file mode 100644
index 0000000..77181c8
--- /dev/null
+++ b/tests/misc/lists7.txt
@@ -0,0 +1,44 @@
+* item 1
+* * item 2-1
+ * item 2-2
+ * item 2-3
+ * item 2-4
+* item 3
+* * item 4-1
+
+ * item 4-2
+
+ * item 4-3
+
+ * item 4-4
+
+## same as above, different spacing
+* item 1
+* * item 2-1
+ * item 2-2
+* item 3
+* * item 4-1
+
+ * item 4-2
+
+## only 1 item in nested list ##
+* item 1
+* * item 2-1
+* item 3
+* * item 4-1
+
+## Something ludicrous ##
+* item 1
+* * item 2-1
+ * item 2-2
+ * * item 2-2-1
+ * item 2-2-2
+ * item 2-3
+* item 3
+* * item 4-1
+
+ * * item 4-1-1
+ * item 4-1-2
+
+ * item 4-2
+
diff --git a/tests/misc/lists8.html b/tests/misc/lists8.html
new file mode 100644
index 0000000..8a93a51
--- /dev/null
+++ b/tests/misc/lists8.html
@@ -0,0 +1,39 @@
+<h1>Lists with blockquotes</h1>
+<ol>
+<li>
+<blockquote>
+<p>Four-score and seven years ago...</p>
+</blockquote>
+</li>
+<li>
+<blockquote>
+<p>We have nothing to fear...</p>
+</blockquote>
+</li>
+<li>
+<blockquote>
+<p>This is it...</p>
+</blockquote>
+</li>
+</ol>
+<h1>Multi-line blockquotes</h1>
+<ul>
+<li>
+<blockquote>
+<p>Four-score and sever years ago
+our fathers brought forth</p>
+</blockquote>
+</li>
+<li>
+<blockquote>
+<p>We have nothing to fear
+but fear itself</p>
+</blockquote>
+</li>
+<li>
+<blockquote>
+<p>This is it
+as far as I'm concerned</p>
+</blockquote>
+</li>
+</ul> \ No newline at end of file
diff --git a/tests/misc/lists8.txt b/tests/misc/lists8.txt
new file mode 100644
index 0000000..8ab6767
--- /dev/null
+++ b/tests/misc/lists8.txt
@@ -0,0 +1,16 @@
+# Lists with blockquotes
+1. > Four-score and seven years ago...
+
+2. > We have nothing to fear...
+
+3. > This is it...
+
+# Multi-line blockquotes
+* > Four-score and sever years ago
+ > our fathers brought forth
+
+* > We have nothing to fear
+ > but fear itself
+
+* > This is it
+ > as far as I'm concerned
diff --git a/tests/misc/markup-inside-p.html b/tests/misc/markup-inside-p.html
deleted file mode 100644
index 1b6b420..0000000
--- a/tests/misc/markup-inside-p.html
+++ /dev/null
@@ -1,21 +0,0 @@
-<p>
-
-_foo_
-
-</p>
-
-<p>
-_foo_
-</p>
-
-<p>_foo_</p>
-
-<p>
-
-_foo_
-</p>
-
-<p>
-_foo_
-
-</p> \ No newline at end of file
diff --git a/tests/misc/markup-inside-p.txt b/tests/misc/markup-inside-p.txt
deleted file mode 100644
index ab7dd0f..0000000
--- a/tests/misc/markup-inside-p.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-<p>
-
-_foo_
-
-</p>
-
-<p>
-_foo_
-</p>
-
-<p>_foo_</p>
-
-<p>
-
-_foo_
-</p>
-
-<p>
-_foo_
-
-</p>
diff --git a/tests/misc/mismatched-tags.html b/tests/misc/mismatched-tags.html
deleted file mode 100644
index ec087e1..0000000
--- a/tests/misc/mismatched-tags.html
+++ /dev/null
@@ -1,11 +0,0 @@
-<p>Some text</p>
-
-<div>some more text</div>
-
-<p>and a bit more</p>
-<p>And this output</p>
-
-<p><em>Compatible with PHP Markdown Extra 1.2.2 and Markdown.pl1.0.2b8:</em></p>
-<!-- comment --><p><div>text</div><br /></p><br />
-
-<p>Should be in p</p> \ No newline at end of file
diff --git a/tests/misc/mismatched-tags.txt b/tests/misc/mismatched-tags.txt
deleted file mode 100644
index 8e6a52f..0000000
--- a/tests/misc/mismatched-tags.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-<p>Some text</p><div>some more text</div>
-
-and a bit more
-
-<p>And this output</p> *Compatible with PHP Markdown Extra 1.2.2 and Markdown.pl1.0.2b8:*
-
-<!-- comment --><p><div>text</div><br /></p><br />
-
-Should be in p
diff --git a/tests/misc/more_comments.html b/tests/misc/more_comments.html
deleted file mode 100644
index 97074d5..0000000
--- a/tests/misc/more_comments.html
+++ /dev/null
@@ -1,7 +0,0 @@
-<!--asd@asdfd.com>
-
-<!asd@asdfd.com>
-
-<asd!@asdfd.com>
-
-<p>Test</p> \ No newline at end of file
diff --git a/tests/misc/more_comments.txt b/tests/misc/more_comments.txt
deleted file mode 100644
index 0397f9c..0000000
--- a/tests/misc/more_comments.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-<!--asd@asdfd.com>
-
-
-<!asd@asdfd.com>
-
-
-<asd!@asdfd.com>
-
-Test
diff --git a/tests/misc/multi-line-tags.html b/tests/misc/multi-line-tags.html
deleted file mode 100644
index 763a050..0000000
--- a/tests/misc/multi-line-tags.html
+++ /dev/null
@@ -1,4 +0,0 @@
-<div>
-
-<p>asdf asdfasd</p>
-</div> \ No newline at end of file
diff --git a/tests/misc/multi-line-tags.txt b/tests/misc/multi-line-tags.txt
deleted file mode 100644
index 4ea3b02..0000000
--- a/tests/misc/multi-line-tags.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-
-<div>
-
-asdf asdfasd
-
-</div>
diff --git a/tests/misc/multi-paragraph-block-quote.html b/tests/misc/multi-paragraph-block-quote.html
index e13986a..f01b5e4 100644
--- a/tests/misc/multi-paragraph-block-quote.html
+++ b/tests/misc/multi-paragraph-block-quote.html
@@ -1,6 +1,6 @@
<blockquote>
<p>This is line one of paragraph one
- This is line two of paragraph one</p>
+This is line two of paragraph one</p>
<p>This is line one of paragraph two</p>
<p>This is another blockquote.</p>
</blockquote> \ No newline at end of file
diff --git a/tests/misc/multi-test.html b/tests/misc/multi-test.html
index 2c8fe9e..9fe9648 100644
--- a/tests/misc/multi-test.html
+++ b/tests/misc/multi-test.html
@@ -1,5 +1,3 @@
-<h1 id="inthebeginning">Header </h1>
-<p>Now, let's try something <em class="special">inline</em>, to see if it works</p>
<p>Blah blah blah <a href="http://www.slashdot.org">http://www.slashdot.org</a></p>
<ul>
<li>Basic list</li>
diff --git a/tests/misc/multi-test.txt b/tests/misc/multi-test.txt
index c4ab1c1..feaac31 100644
--- a/tests/misc/multi-test.txt
+++ b/tests/misc/multi-test.txt
@@ -1,9 +1,3 @@
-
-# Header {@id=inthebeginning}
-
-Now, let's try something *inline{@class=special}*, to see if it works
-
-
Blah blah blah <http://www.slashdot.org>
* Basic list
diff --git a/tests/misc/multiline-comments.html b/tests/misc/multiline-comments.html
deleted file mode 100644
index 547ba0b..0000000
--- a/tests/misc/multiline-comments.html
+++ /dev/null
@@ -1,16 +0,0 @@
-<!--
-
-foo
-
--->
-
-<p>
-
-foo
-
-</p>
-
-<div>
-
-<p>foo</p>
-</div> \ No newline at end of file
diff --git a/tests/misc/multiline-comments.txt b/tests/misc/multiline-comments.txt
deleted file mode 100644
index 71bc418..0000000
--- a/tests/misc/multiline-comments.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-<!--
-
-foo
-
--->
-
-<p>
-
-foo
-
-</p>
-
-
-<div>
-
-foo
-
-</div>
diff --git a/tests/misc/nested-lists.html b/tests/misc/nested-lists.html
index bb73784..9af441a 100644
--- a/tests/misc/nested-lists.html
+++ b/tests/misc/nested-lists.html
@@ -36,4 +36,17 @@
</ul>
</li>
<li>item 2</li>
+<li>item 3</li>
+<li>
+<p>item 4</p>
+<ul>
+<li>item 4-1</li>
+<li>item 4-2</li>
+<li>
+<p>item 4-3</p>
+<p>Paragraph under item 4-3</p>
+</li>
+</ul>
+<p>Paragraph under item 4</p>
+</li>
</ul> \ No newline at end of file
diff --git a/tests/misc/nested-lists.txt b/tests/misc/nested-lists.txt
index 38aae15..a2704b4 100644
--- a/tests/misc/nested-lists.txt
+++ b/tests/misc/nested-lists.txt
@@ -22,3 +22,12 @@ plain text
* item 1-2
* item 1-2-1
* item 2
+* item 3
+* item 4
+ * item 4-1
+ * item 4-2
+ * item 4-3
+
+ Paragraph under item 4-3
+
+ Paragraph under item 4
diff --git a/tests/misc/nested-patterns.html b/tests/misc/nested-patterns.html
index b90d46d..1c7bb43 100644
--- a/tests/misc/nested-patterns.html
+++ b/tests/misc/nested-patterns.html
@@ -1,7 +1,10 @@
-<p><strong><em><a href="http://www.freewisdom.org">link</a></em></strong>
-<strong><em><a href="http://www.freewisdom.org">link</a></em></strong>
-<strong><a href="http://www.freewisdom.org"><em>link</em></a></strong>
-<strong><a href="http://www.freewisdom.org"><em>link</em></a></strong>
-<strong><a href="http://www.freewisdom.org"><em>link</em></a></strong>
-<strong><a href="http://www.freewisdom.org"><em>link</em></a></strong>
-<a href="http://www.freewisdom.org"><strong><em>link</em></strong></a></p> \ No newline at end of file
+<p><strong><em><a href="http://example.com">link</a></em></strong>
+<strong><em><a href="http://example.com">link</a></em></strong>
+<strong><a href="http://example.com"><em>link</em></a></strong>
+<strong><a href="http://example.com"><em>link</em></a></strong>
+<strong><a href="http://example.com"><em>link</em></a></strong>
+<strong><a href="http://example.com"><em>link</em></a></strong>
+<a href="http://example.com"><strong><em>link</em></strong></a></p>
+<p><strong><em>I am <strong><em>italic</em> and</strong> bold</em> I am <code>just</code> bold</strong></p>
+<p>Example <strong><em>bold italic</em></strong> on the same line <strong><em>bold italic</em></strong>.</p>
+<p>Example <strong><em>bold italic</em></strong> on the same line <strong><em>bold italic</em></strong>.</p> \ No newline at end of file
diff --git a/tests/misc/nested-patterns.txt b/tests/misc/nested-patterns.txt
index 3f5dc3e..9032cf1 100644
--- a/tests/misc/nested-patterns.txt
+++ b/tests/misc/nested-patterns.txt
@@ -1,7 +1,13 @@
-___[link](http://www.freewisdom.org)___
-***[link](http://www.freewisdom.org)***
-**[*link*](http://www.freewisdom.org)**
-__[_link_](http://www.freewisdom.org)__
-__[*link*](http://www.freewisdom.org)__
-**[_link_](http://www.freewisdom.org)**
-[***link***](http://www.freewisdom.org)
+___[link](http://example.com)___
+***[link](http://example.com)***
+**[*link*](http://example.com)**
+__[_link_](http://example.com)__
+__[*link*](http://example.com)__
+**[_link_](http://example.com)**
+[***link***](http://example.com)
+
+***I am ___italic_ and__ bold* I am `just` bold**
+
+Example __*bold italic*__ on the same line __*bold italic*__.
+
+Example **_bold italic_** on the same line **_bold italic_**.
diff --git a/tests/misc/para-with-hr.html b/tests/misc/para-with-hr.html
index 8569fec..7607449 100644
--- a/tests/misc/para-with-hr.html
+++ b/tests/misc/para-with-hr.html
@@ -1,3 +1,6 @@
<p>Here is a paragraph, followed by a horizontal rule.</p>
<hr />
-<p>Followed by another paragraph.</p> \ No newline at end of file
+<p>Followed by another paragraph.</p>
+<p>Here is another paragraph, followed by:
+*** not an HR.
+Followed by more of the same paragraph.</p> \ No newline at end of file
diff --git a/tests/misc/para-with-hr.txt b/tests/misc/para-with-hr.txt
index 20735fb..165bbe3 100644
--- a/tests/misc/para-with-hr.txt
+++ b/tests/misc/para-with-hr.txt
@@ -2,3 +2,6 @@ Here is a paragraph, followed by a horizontal rule.
***
Followed by another paragraph.
+Here is another paragraph, followed by:
+*** not an HR.
+Followed by more of the same paragraph.
diff --git a/tests/misc/php.html b/tests/misc/php.html
deleted file mode 100644
index 8cd4ed5..0000000
--- a/tests/misc/php.html
+++ /dev/null
@@ -1,11 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
- "http://www.w3.org/TR/html4/strict.dtd">
-
-<p><b>This should have a p tag</b></p>
-<!--This is a comment -->
-
-<div>This shouldn't</div>
-
-<?php echo "block_level";?>
-
-<p>&lt;?php echo "not_block_level";?&gt;</p> \ No newline at end of file
diff --git a/tests/misc/php.txt b/tests/misc/php.txt
deleted file mode 100644
index ca5be45..0000000
--- a/tests/misc/php.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
- "http://www.w3.org/TR/html4/strict.dtd">
-
-<b>This should have a p tag</b>
-
-<!--This is a comment -->
-
-<div>This shouldn't</div>
-
-<?php echo "block_level";?>
-
- <?php echo "not_block_level";?>
-
diff --git a/tests/misc/pre.html b/tests/misc/pre.html
deleted file mode 100644
index a44ae12..0000000
--- a/tests/misc/pre.html
+++ /dev/null
@@ -1,13 +0,0 @@
-<pre>
-
-aaa
-
-bbb
-</pre>
-
-<pre>
-* and this is pre-formatted content
-* and it should be printed just like this
-* and not formatted as a list
-
-</pre> \ No newline at end of file
diff --git a/tests/misc/pre.txt b/tests/misc/pre.txt
deleted file mode 100644
index 31243b5..0000000
--- a/tests/misc/pre.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-<pre>
-
-aaa
-
-bbb
-</pre>
-
-<pre>
-* and this is pre-formatted content
-* and it should be printed just like this
-* and not formatted as a list
-
-</pre>
-
diff --git a/tests/misc/some-test.html b/tests/misc/some-test.html
index a36d1ee..b78683f 100644
--- a/tests/misc/some-test.html
+++ b/tests/misc/some-test.html
@@ -24,8 +24,10 @@
</ul>
<p>Markdown</p>
<ul>
-<li>Python
- is ok<ul>
+<li>
+<p>Python
+ is ok</p>
+<ul>
<li>Therefore i am</li>
</ul>
</li>
diff --git a/tests/misc/tabs-in-lists.html b/tests/misc/tabs-in-lists.html
index a1a92ec..fdb7cb6 100644
--- a/tests/misc/tabs-in-lists.html
+++ b/tests/misc/tabs-in-lists.html
@@ -19,7 +19,7 @@
<p>Now a list with 4 spaces and some text:</p>
<ul>
<li>A
-abcdef</li>
+ abcdef</li>
<li>B</li>
</ul>
<p>Now with a tab and an extra space:</p>
diff --git a/tests/misc/two-spaces.html b/tests/misc/two-spaces.html
index 102d1db..97b54b4 100644
--- a/tests/misc/two-spaces.html
+++ b/tests/misc/two-spaces.html
@@ -4,14 +4,12 @@ but this line has three <br />
and this is the second from last line
in this test message</p>
<ul>
-<li>This list item has two spaces.<br />
-</li>
+<li>This list item has two spaces. </li>
<li>
<p>This has none.
This line has three. <br />
This line has none.
- And this line two.<br />
-</p>
+ And this line two. </p>
<p>This line has none.</p>
</li>
<li>
diff --git a/tests/misc/uche.html b/tests/misc/uche.html
index e62329d..9134e95 100644
--- a/tests/misc/uche.html
+++ b/tests/misc/uche.html
@@ -1,3 +1,3 @@
<p><img alt="asif" src="http://fourthought.com/images/ftlogo.png" title="Fourthought logo" /></p>
-<p><a href="http://fourthought.com/"><img alt="" src="http://fourthought.com/images/ftlogo.png" style="float: left; margin: 10px; border: none;" title="Fourthought logo" /></a></p>
+<p><a href="http://fourthought.com/"><img alt="Alt text" src="http://fourthought.com/images/ftlogo.png" title="Fourthought logo" /></a></p>
<p><a href="http://link.com/"><img alt="text" src="x" /></a></p> \ No newline at end of file
diff --git a/tests/misc/uche.txt b/tests/misc/uche.txt
index a3dda1a..625d2ae 100644
--- a/tests/misc/uche.txt
+++ b/tests/misc/uche.txt
@@ -1,7 +1,6 @@
![asif](http://fourthought.com/images/ftlogo.png "Fourthought logo")
-[![{@style=float: left; margin: 10px; border:
-none;}](http://fourthought.com/images/ftlogo.png "Fourthought
+[![Alt text](http://fourthought.com/images/ftlogo.png "Fourthought
logo")](http://fourthought.com/)
[![text](x)](http://link.com/)
diff --git a/tests/misc/underscores.html b/tests/misc/underscores.html
index 54bd9f9..72d51b8 100644
--- a/tests/misc/underscores.html
+++ b/tests/misc/underscores.html
@@ -1,6 +1,6 @@
<p>THIS_SHOULD_STAY_AS_IS</p>
<p>Here is some <em>emphasis</em>, ok?</p>
<p>Ok, at least <em>this</em> should work.</p>
-<p>THIS<strong>SHOULD</strong>STAY</p>
+<p>THIS__SHOULD__STAY</p>
<p>Here is some <strong>strong</strong> stuff.</p>
<p>THIS<strong><em>SHOULD</em></strong>STAY?</p> \ No newline at end of file
diff --git a/tests/php/Auto Links.text b/tests/php/Auto Links.text
new file mode 100644
index 0000000..4b10d32
--- /dev/null
+++ b/tests/php/Auto Links.text
@@ -0,0 +1,3 @@
+<HTTP://WWW.SOMEURL.COM>
+
+<hr@company.com> \ No newline at end of file
diff --git a/tests/php/Auto Links.xhtml b/tests/php/Auto Links.xhtml
new file mode 100644
index 0000000..259c47f
--- /dev/null
+++ b/tests/php/Auto Links.xhtml
@@ -0,0 +1,3 @@
+<p><a href="HTTP://WWW.SOMEURL.COM">HTTP://WWW.SOMEURL.COM</a></p>
+
+<p><a href="mailto:hr@company.com">hr@company.com</a></p> \ No newline at end of file
diff --git a/tests/php/Backslash escapes.text b/tests/php/Backslash escapes.text
new file mode 100644
index 0000000..a5e769b
--- /dev/null
+++ b/tests/php/Backslash escapes.text
@@ -0,0 +1 @@
+Tricky combinaisons: backslash with \\-- two dashes backslash with \\> greater than \\\[test](not a link) \\\*no emphasis* \ No newline at end of file
diff --git a/tests/php/Backslash escapes.xhtml b/tests/php/Backslash escapes.xhtml
new file mode 100644
index 0000000..08fb8ef
--- /dev/null
+++ b/tests/php/Backslash escapes.xhtml
@@ -0,0 +1 @@
+<p>Tricky combinaisons:</p> <p>backslash with \-- two dashes</p> <p>backslash with \> greater than</p> <p>\[test](not a link)</p> <p>\*no emphasis*</p> \ No newline at end of file
diff --git a/tests/php/Code Spans.text b/tests/php/Code Spans.text
new file mode 100644
index 0000000..43f2bcf
--- /dev/null
+++ b/tests/php/Code Spans.text
@@ -0,0 +1,6 @@
+From `<!--` to `-->`
+on two lines.
+
+From `<!--`
+to `-->`
+on three lines.
diff --git a/tests/php/Code Spans.xhtml b/tests/php/Code Spans.xhtml
new file mode 100644
index 0000000..9ed0df8
--- /dev/null
+++ b/tests/php/Code Spans.xhtml
@@ -0,0 +1,6 @@
+<p>From <code>&lt;!--</code> to <code>--&gt;</code>
+on two lines.</p>
+
+<p>From <code>&lt;!--</code>
+to <code>--&gt;</code>
+on three lines.</p>
diff --git a/tests/php/Code block in a list item.text b/tests/php/Code block in a list item.text
new file mode 100644
index 0000000..5093348
--- /dev/null
+++ b/tests/php/Code block in a list item.text
@@ -0,0 +1,15 @@
+
+* List Item:
+
+ code block
+
+ with a blank line
+
+ within a list item.
+
+* code block
+ as first element of a list item
+
+* List Item:
+
+ code block with whitespace on preceding line \ No newline at end of file
diff --git a/tests/php/Code block in a list item.xhtml b/tests/php/Code block in a list item.xhtml
new file mode 100644
index 0000000..361c1ae
--- /dev/null
+++ b/tests/php/Code block in a list item.xhtml
@@ -0,0 +1,18 @@
+<ul>
+<li><p>List Item:</p>
+
+<pre><code>code block
+
+with a blank line
+</code></pre>
+
+<p>within a list item.</p></li>
+<li><pre><code>code block
+as first element of a list item
+</code></pre></li>
+
+<li><p>List Item:</p>
+
+<pre><code>code block with whitespace on preceding line
+</code></pre></li>
+</ul> \ No newline at end of file
diff --git a/tests/php/Code block on second line.text b/tests/php/Code block on second line.text
new file mode 100644
index 0000000..b7fcd97
--- /dev/null
+++ b/tests/php/Code block on second line.text
@@ -0,0 +1,2 @@
+
+ Codeblock on second line
diff --git a/tests/php/Code block on second line.xhtml b/tests/php/Code block on second line.xhtml
new file mode 100644
index 0000000..25abb16
--- /dev/null
+++ b/tests/php/Code block on second line.xhtml
@@ -0,0 +1,2 @@
+<pre><code>Codeblock on second line
+</code></pre>
diff --git a/tests/php/Email auto links.text b/tests/php/Email auto links.text
new file mode 100644
index 0000000..a8af4ec
--- /dev/null
+++ b/tests/php/Email auto links.text
@@ -0,0 +1,3 @@
+<michel.fortin@michelf.com>
+
+International domain names: <help@tūdaliņ.lv> \ No newline at end of file
diff --git a/tests/php/Email auto links.xhtml b/tests/php/Email auto links.xhtml
new file mode 100644
index 0000000..a32c408
--- /dev/null
+++ b/tests/php/Email auto links.xhtml
@@ -0,0 +1,3 @@
+<p><a href="&#109;&#x61;&#105;&#x6c;&#116;&#x6f;&#58;&#x6d;&#105;&#x63;&#104;&#x65;&#108;&#x2e;&#102;&#x6f;&#114;&#x74;&#105;&#x6e;&#64;&#x6d;&#105;&#x63;&#104;&#x65;&#108;&#x66;&#46;&#x63;&#111;&#x6d;">&#x6d;&#105;&#x63;&#104;&#x65;&#108;&#x2e;&#102;&#x6f;&#114;&#x74;&#105;&#x6e;&#64;&#x6d;&#105;&#x63;&#104;&#x65;&#108;&#x66;&#46;&#x63;&#111;&#x6d;</a></p>
+
+<p>International domain names: <a href="&#x6d;&#97;&#105;&#x6c;&#x74;&#111;&#58;&#x68;&#x65;&#108;&#112;&#x40;&#x74;ū&#x64;&#x61;&#108;&#105;ņ&#46;&#108;&#x76;">&#x68;&#x65;&#108;&#112;&#x40;&#x74;ū&#x64;&#x61;&#108;&#105;ņ&#46;&#108;&#x76;</a></p>
diff --git a/tests/php/Emphasis.text b/tests/php/Emphasis.text
new file mode 100644
index 0000000..88e93d4
--- /dev/null
+++ b/tests/php/Emphasis.text
@@ -0,0 +1,80 @@
+Combined emphasis:
+
+1. ***test test***
+2. ___test test___
+3. *test **test***
+4. **test *test***
+5. ***test* test**
+6. ***test** test*
+7. ***test* test**
+8. **test *test***
+9. *test **test***
+10. _test __test___
+11. __test _test___
+12. ___test_ test__
+13. ___test__ test_
+14. ___test_ test__
+15. __test _test___
+16. _test __test___
+
+
+Incorrect nesting:
+
+1. *test **test* test**
+2. _test __test_ test__
+3. **test *test** test*
+4. __test _test__ test_
+5. *test *test* test*
+6. _test _test_ test_
+7. **test **test** test**
+8. __test __test__ test__
+
+
+
+No emphasis:
+
+1. test* test *test
+2. test** test **test
+3. test_ test _test
+4. test__ test __test
+
+
+
+Middle-word emphasis (asterisks):
+
+1. *a*b
+2. a*b*
+3. a*b*c
+4. **a**b
+5. a**b**
+6. a**b**c
+
+
+Middle-word emphasis (underscore):
+
+1. _a_b
+2. a_b_
+3. a_b_c
+4. __a__b
+5. a__b__
+6. a__b__c
+
+my_precious_file.txt
+
+
+## Tricky Cases
+
+E**. **Test** TestTestTest
+
+E**. **Test** Test Test Test
+
+
+## Overlong emphasis
+
+Name: ____________
+Organization: ____
+Region/Country: __
+
+_____Cut here_____
+
+____Cut here____
diff --git a/tests/php/Emphasis.xhtml b/tests/php/Emphasis.xhtml
new file mode 100644
index 0000000..4879070
--- /dev/null
+++ b/tests/php/Emphasis.xhtml
@@ -0,0 +1,83 @@
+<p>Combined emphasis:</p>
+
+<ol>
+<li><strong><em>test test</em></strong></li>
+<li><strong><em>test test</em></strong></li>
+<li><em>test <strong>test</strong></em></li>
+<li><strong>test <em>test</em></strong></li>
+<li><strong><em>test</em> test</strong></li>
+<li><em><strong>test</strong> test</em></li>
+<li><strong><em>test</em> test</strong></li>
+<li><strong>test <em>test</em></strong></li>
+<li><em>test <strong>test</strong></em></li>
+<li><em>test <strong>test</strong></em></li>
+<li><strong>test <em>test</em></strong></li>
+<li><strong><em>test</em> test</strong></li>
+<li><em><strong>test</strong> test</em></li>
+<li><strong><em>test</em> test</strong></li>
+<li><strong>test <em>test</em></strong></li>
+<li><em>test <strong>test</strong></em></li>
+</ol>
+
+<p>Incorrect nesting:</p>
+
+<ol>
+<li>*test <strong>test* test</strong></li>
+<li>_test <strong>test_ test</strong></li>
+<li><strong>test *test</strong> test*</li>
+<li><strong>test _test</strong> test_</li>
+<li><em>test *test</em> test*</li>
+<li><em>test _test</em> test_</li>
+<li><strong>test **test</strong> test**</li>
+<li><strong>test __test</strong> test__</li>
+</ol>
+
+<p>No emphasis:</p>
+
+<ol>
+<li>test* test *test</li>
+<li>test** test **test</li>
+<li>test_ test _test</li>
+<li>test__ test __test</li>
+</ol>
+
+<p>Middle-word emphasis (asterisks):</p>
+
+<ol>
+<li><em>a</em>b</li>
+<li>a<em>b</em></li>
+<li>a<em>b</em>c</li>
+<li><strong>a</strong>b</li>
+<li>a<strong>b</strong></li>
+<li>a<strong>b</strong>c</li>
+</ol>
+
+<p>Middle-word emphasis (underscore):</p>
+
+<ol>
+<li><em>a</em>b</li>
+<li>a<em>b</em></li>
+<li>a<em>b</em>c</li>
+<li><strong>a</strong>b</li>
+<li>a<strong>b</strong></li>
+<li>a<strong>b</strong>c</li>
+</ol>
+
+<p>my<em>precious</em>file.txt</p>
+
+<h2>Tricky Cases</h2>
+
+<p>E**. <strong>Test</strong> TestTestTest</p>
+
+<p>E**. <strong>Test</strong> Test Test Test</p>
+
+
+<h2>Overlong emphasis</h2>
+
+<p>Name: ____________<br />
+Organization: ____<br />
+Region/Country: __</p>
+
+<p>_____Cut here_____</p>
+
+<p>____Cut here____</p> \ No newline at end of file
diff --git a/tests/php/Empty List Item.text b/tests/php/Empty List Item.text
new file mode 100644
index 0000000..3c4edba
--- /dev/null
+++ b/tests/php/Empty List Item.text
@@ -0,0 +1,35 @@
+With asterisks
+
+ * List item
+ *
+ * List item
+
+With numbers
+
+1. List item
+2.
+3. List item
+
+With hyphens
+
+- List item
+-
+- List item
+
+With asterisks
+
+ * List item
+ * List item
+ *
+
+With numbers
+
+1. List item
+2. List item
+3.
+
+With hyphens
+
+- List item
+- List item
+-
diff --git a/tests/php/Empty List Item.xhtml b/tests/php/Empty List Item.xhtml
new file mode 100644
index 0000000..02d86ed
--- /dev/null
+++ b/tests/php/Empty List Item.xhtml
@@ -0,0 +1,47 @@
+<p>With asterisks</p>
+
+<ul>
+<li>List item</li>
+<li></li>
+<li>List item</li>
+</ul>
+
+<p>With numbers</p>
+
+<ol>
+<li>List item</li>
+<li></li>
+<li>List item</li>
+</ol>
+
+<p>With hyphens</p>
+
+<ul>
+<li>List item</li>
+<li></li>
+<li>List item</li>
+</ul>
+
+<p>With asterisks</p>
+
+<ul>
+<li>List item</li>
+<li>List item</li>
+<li></li>
+</ul>
+
+<p>With numbers</p>
+
+<ol>
+<li>List item</li>
+<li>List item</li>
+<li></li>
+</ol>
+
+<p>With hyphens</p>
+
+<ul>
+<li>List item</li>
+<li>List item</li>
+<li></li>
+</ul> \ No newline at end of file
diff --git a/tests/php/Headers.text b/tests/php/Headers.text
new file mode 100644
index 0000000..3a39174
--- /dev/null
+++ b/tests/php/Headers.text
@@ -0,0 +1,9 @@
+Header ====== Header ------ ### Header
+
+ - - -
+
+Header ====== Paragraph Header ------ Paragraph ### Header Paragraph
+
+ - - -
+
+Paragraph Header ====== Paragraph Paragraph Header ------ Paragraph Paragraph ### Header Paragraph \ No newline at end of file
diff --git a/tests/php/Headers.xhtml b/tests/php/Headers.xhtml
new file mode 100644
index 0000000..3adb470
--- /dev/null
+++ b/tests/php/Headers.xhtml
@@ -0,0 +1,39 @@
+<h1>Header</h1>
+
+<h2>Header</h2>
+
+<h3>Header</h3>
+
+<hr />
+
+<h1>Header</h1>
+
+<p>Paragraph</p>
+
+<h2>Header</h2>
+
+<p>Paragraph</p>
+
+<h3>Header</h3>
+
+<p>Paragraph</p>
+
+<hr />
+
+<p>Paragraph</p>
+
+<h1>Header</h1>
+
+<p>Paragraph</p>
+
+<p>Paragraph</p>
+
+<h2>Header</h2>
+
+<p>Paragraph</p>
+
+<p>Paragraph</p>
+
+<h3>Header</h3>
+
+<p>Paragraph</p>
diff --git a/tests/php/Horizontal Rules.text b/tests/php/Horizontal Rules.text
new file mode 100644
index 0000000..8e2da0b
--- /dev/null
+++ b/tests/php/Horizontal Rules.text
@@ -0,0 +1,29 @@
+Horizontal rules:
+
+- - -
+
+* * *
+
+***
+
+---
+
+___
+
+Not horizontal rules (testing for a bug in 1.0.1j):
+
++++
+
+,,,
+
+===
+
+???
+
+AAA
+
+jjj
+
+j j j
+
+n n n
diff --git a/tests/php/Horizontal Rules.xhtml b/tests/php/Horizontal Rules.xhtml
new file mode 100644
index 0000000..b9170b1
--- /dev/null
+++ b/tests/php/Horizontal Rules.xhtml
@@ -0,0 +1,30 @@
+<p>Horizontal rules:</p>
+
+<hr />
+
+<hr />
+
+<hr />
+
+<hr />
+
+<hr />
+
+<p>Not horizontal rules (testing for a bug in 1.0.1j):</p>
+
+<p>+++</p>
+
+<p>,,,</p>
+
+<p>===</p>
+
+<p>???</p>
+
+<p>AAA</p>
+
+<p>jjj</p>
+
+<p>j j j</p>
+
+<p>n n n</p>
+
diff --git a/tests/php/Inline HTML (Simple).text b/tests/php/Inline HTML (Simple).text
new file mode 100644
index 0000000..9177105
--- /dev/null
+++ b/tests/php/Inline HTML (Simple).text
@@ -0,0 +1,15 @@
+With some attributes:
+
+<div id="test">
+ foo
+</div>
+
+<div id="test"
+ class="nono">
+ foo
+</div>
+
+Hr's:
+
+<hr class="foo"
+ id="bar" >
diff --git a/tests/php/Inline HTML (Simple).xhtml b/tests/php/Inline HTML (Simple).xhtml
new file mode 100644
index 0000000..facfefb
--- /dev/null
+++ b/tests/php/Inline HTML (Simple).xhtml
@@ -0,0 +1,15 @@
+<p>With some attributes:</p>
+
+<div id="test">
+ foo
+</div>
+
+<div id="test"
+ class="nono">
+ foo
+</div>
+
+<p>Hr's:</p>
+
+<hr class="foo"
+ id="bar" > \ No newline at end of file
diff --git a/tests/php/Inline HTML (Span).text b/tests/php/Inline HTML (Span).text
new file mode 100644
index 0000000..19028bb
--- /dev/null
+++ b/tests/php/Inline HTML (Span).text
@@ -0,0 +1,4 @@
+<abbr title="` **Attribute Content Is Not A Code Span** `">ACINACS</abbr>
+
+<abbr title="`first backtick!">SB</abbr>
+<abbr title="`second backtick!">SB</abbr> \ No newline at end of file
diff --git a/tests/php/Inline HTML (Span).xhtml b/tests/php/Inline HTML (Span).xhtml
new file mode 100644
index 0000000..4d18aff
--- /dev/null
+++ b/tests/php/Inline HTML (Span).xhtml
@@ -0,0 +1,4 @@
+<p><abbr title="` **Attribute Content Is Not A Code Span** `">ACINACS</abbr></p>
+
+<p><abbr title="`first backtick!">SB</abbr>
+<abbr title="`second backtick!">SB</abbr></p> \ No newline at end of file
diff --git a/tests/php/Inline HTML comments.text b/tests/php/Inline HTML comments.text
new file mode 100644
index 0000000..d57d00a
--- /dev/null
+++ b/tests/php/Inline HTML comments.text
@@ -0,0 +1,9 @@
+Paragraph one.
+
+<!-- double--dash (invalid SGML comment) -->
+
+Paragraph two.
+
+<!-- enclosed tag </div> -->
+
+The end.
diff --git a/tests/php/Inline HTML comments.xhtml b/tests/php/Inline HTML comments.xhtml
new file mode 100644
index 0000000..b45f014
--- /dev/null
+++ b/tests/php/Inline HTML comments.xhtml
@@ -0,0 +1,9 @@
+<p>Paragraph one.</p>
+
+<!-- double--dash (invalid SGML comment) -->
+
+<p>Paragraph two.</p>
+
+<!-- enclosed tag </div> -->
+
+<p>The end.</p>
diff --git a/tests/php/Ins & del.text b/tests/php/Ins & del.text
new file mode 100644
index 0000000..2d54c66
--- /dev/null
+++ b/tests/php/Ins & del.text
@@ -0,0 +1,17 @@
+Here is a block tag ins:
+
+<ins>
+<p>Some text</p>
+</ins>
+
+<ins>And here it is inside a paragraph.</ins>
+
+And here it is <ins>in the middle of</ins> a paragraph.
+
+<del>
+<p>Some text</p>
+</del>
+
+<del>And here is ins as a paragraph.</del>
+
+And here it is <del>in the middle of</del> a paragraph.
diff --git a/tests/php/Ins & del.xhtml b/tests/php/Ins & del.xhtml
new file mode 100644
index 0000000..60e8c5f
--- /dev/null
+++ b/tests/php/Ins & del.xhtml
@@ -0,0 +1,17 @@
+<p>Here is a block tag ins:</p>
+
+<ins>
+<p>Some text</p>
+</ins>
+
+<p><ins>And here it is inside a paragraph.</ins></p>
+
+<p>And here it is <ins>in the middle of</ins> a paragraph.</p>
+
+<del>
+<p>Some text</p>
+</del>
+
+<p><del>And here is ins as a paragraph.</del></p>
+
+<p>And here it is <del>in the middle of</del> a paragraph.</p>
diff --git a/tests/php/License b/tests/php/License
new file mode 100644
index 0000000..d511905
--- /dev/null
+++ b/tests/php/License
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/tests/php/Links, inline style.text b/tests/php/Links, inline style.text
new file mode 100644
index 0000000..600a044
--- /dev/null
+++ b/tests/php/Links, inline style.text
@@ -0,0 +1 @@
+[silly URL w/ angle brackets](<?}]*+|&)>).
diff --git a/tests/php/Links, inline style.xhtml b/tests/php/Links, inline style.xhtml
new file mode 100644
index 0000000..d3e4d11
--- /dev/null
+++ b/tests/php/Links, inline style.xhtml
@@ -0,0 +1 @@
+<p><a href="?}]*+|&amp;)">silly URL w/ angle brackets</a>.</p>
diff --git a/tests/php/MD5 Hashes.text b/tests/php/MD5 Hashes.text
new file mode 100644
index 0000000..7e03221
--- /dev/null
+++ b/tests/php/MD5 Hashes.text
@@ -0,0 +1,11 @@
+# Character Escapes
+
+The MD5 value for `+` is "26b17225b626fb9238849fd60eabdf60".
+
+# HTML Blocks
+
+<p>test</p>
+
+The MD5 value for `<p>test</p>` is:
+
+6205333b793f34273d75379350b36826 \ No newline at end of file
diff --git a/tests/php/MD5 Hashes.xhtml b/tests/php/MD5 Hashes.xhtml
new file mode 100644
index 0000000..894e4aa
--- /dev/null
+++ b/tests/php/MD5 Hashes.xhtml
@@ -0,0 +1,11 @@
+<h1>Character Escapes</h1>
+
+<p>The MD5 value for <code>+</code> is "26b17225b626fb9238849fd60eabdf60".</p>
+
+<h1>HTML Blocks</h1>
+
+<p>test</p>
+
+<p>The MD5 value for <code>&lt;p&gt;test&lt;/p&gt;</code> is:</p>
+
+<p>6205333b793f34273d75379350b36826</p>
diff --git a/tests/php/Mixed OLs and ULs.text b/tests/php/Mixed OLs and ULs.text
new file mode 100644
index 0000000..cecde21
--- /dev/null
+++ b/tests/php/Mixed OLs and ULs.text
@@ -0,0 +1,13 @@
+* test
++ test
+- test
+
+1. test
+2. test
+
+* test
++ test
+- test
+
+1. test
+2. test
diff --git a/tests/php/Mixed OLs and ULs.xhtml b/tests/php/Mixed OLs and ULs.xhtml
new file mode 100644
index 0000000..0872aaa
--- /dev/null
+++ b/tests/php/Mixed OLs and ULs.xhtml
@@ -0,0 +1,21 @@
+<ul>
+<li>test</li>
+<li>test</li>
+<li>test</li>
+</ul>
+
+<ol>
+<li>test</li>
+<li>test</li>
+</ol>
+
+<ul>
+<li>test</li>
+<li>test</li>
+<li>test</li>
+</ul>
+
+<ol>
+<li>test</li>
+<li>test</li>
+</ol>
diff --git a/tests/php/Nesting.text b/tests/php/Nesting.text
new file mode 100644
index 0000000..791538c
--- /dev/null
+++ b/tests/php/Nesting.text
@@ -0,0 +1,11 @@
+Valid nesting:
+
+**[Link](url)**
+
+[**Link**](url)
+
+**[**Link**](url)**
+
+Invalid nesting:
+
+[[Link](url)](url) \ No newline at end of file
diff --git a/tests/php/Nesting.xhtml b/tests/php/Nesting.xhtml
new file mode 100644
index 0000000..37845d3
--- /dev/null
+++ b/tests/php/Nesting.xhtml
@@ -0,0 +1,11 @@
+<p>Valid nesting:</p>
+
+<p><strong><a href="url">Link</a></strong></p>
+
+<p><a href="url"><strong>Link</strong></a></p>
+
+<p><strong><a href="url"><strong>Link</strong></a></strong></p>
+
+<p>Invalid nesting:</p>
+
+<p><a href="url">[Link](url)</a></p>
diff --git a/tests/php/PHP-Specific Bugs.text b/tests/php/PHP-Specific Bugs.text
new file mode 100644
index 0000000..246b60d
--- /dev/null
+++ b/tests/php/PHP-Specific Bugs.text
@@ -0,0 +1,22 @@
+This tests for a bug where quotes escaped by PHP when using
+`preg_replace` with the `/e` modifier must be correctly unescaped
+(hence the `_UnslashQuotes` function found only in PHP Markdown).
+
+
+
+Headers below should appear exactly as they are typed (no backslash
+added or removed).
+
+Header "quoted\" again \\""
+===========================
+
+Header "quoted\" again \\""
+---------------------------
+
+### Header "quoted\" again \\"" ###
+
+
+
+Test with tabs for `_Detab`:
+
+ Code 'block' with some "tabs" and "quotes"
diff --git a/tests/php/PHP-Specific Bugs.xhtml b/tests/php/PHP-Specific Bugs.xhtml
new file mode 100644
index 0000000..c982417
--- /dev/null
+++ b/tests/php/PHP-Specific Bugs.xhtml
@@ -0,0 +1,17 @@
+<p>This tests for a bug where quotes escaped by PHP when using
+<code>preg_replace</code> with the <code>/e</code> modifier must be correctly unescaped
+(hence the <code>_UnslashQuotes</code> function found only in PHP Markdown).</p>
+
+<p>Headers below should appear exactly as they are typed (no backslash
+added or removed).</p>
+
+<h1>Header "quoted\" again \""</h1>
+
+<h2>Header "quoted\" again \""</h2>
+
+<h3>Header "quoted\" again \""</h3>
+
+<p>Test with tabs for <code>_Detab</code>:</p>
+
+<pre><code>Code 'block' with some "tabs" and "quotes"
+</code></pre>
diff --git a/tests/php/Parens in URL.text b/tests/php/Parens in URL.text
new file mode 100644
index 0000000..bb7be4f
--- /dev/null
+++ b/tests/php/Parens in URL.text
@@ -0,0 +1,14 @@
+[Inline link 1 with parens](/url\(test\) "title").
+
+[Inline link 2 with parens](</url\(test\)> "title").
+
+[Inline link 3 with non-escaped parens](/url(test) "title").
+
+[Inline link 4 with non-escaped parens](</url(test)> "title").
+
+[Reference link 1 with parens][1].
+
+[Reference link 2 with parens][2].
+
+ [1]: /url(test) "title"
+ [2]: </url(test)> "title"
diff --git a/tests/php/Parens in URL.xhtml b/tests/php/Parens in URL.xhtml
new file mode 100644
index 0000000..a81aa02
--- /dev/null
+++ b/tests/php/Parens in URL.xhtml
@@ -0,0 +1,11 @@
+<p><a href="/url(test)" title="title">Inline link 1 with parens</a>.</p>
+
+<p><a href="/url(test)" title="title">Inline link 2 with parens</a>.</p>
+
+<p><a href="/url(test)" title="title">Inline link 3 with non-escaped parens</a>.</p>
+
+<p><a href="/url(test)" title="title">Inline link 4 with non-escaped parens</a>.</p>
+
+<p><a href="/url(test)" title="title">Reference link 1 with parens</a>.</p>
+
+<p><a href="/url(test)" title="title">Reference link 2 with parens</a>.</p> \ No newline at end of file
diff --git a/tests/php/Quotes in attributes.text b/tests/php/Quotes in attributes.text
new file mode 100644
index 0000000..9792286
--- /dev/null
+++ b/tests/php/Quotes in attributes.text
@@ -0,0 +1,5 @@
+[Test](/"style="color:red)
+[Test](/'style='color:red)
+
+![](/"style="border-color:red;border-size:1px;border-style:solid)
+![](/'style='border-color:red;border-size:1px;border-style:solid)
diff --git a/tests/php/Quotes in attributes.xhtml b/tests/php/Quotes in attributes.xhtml
new file mode 100644
index 0000000..e3fcfd2
--- /dev/null
+++ b/tests/php/Quotes in attributes.xhtml
@@ -0,0 +1,5 @@
+<p><a href="/&quot;style=&quot;color:red">Test</a>
+<a href="/'style='color:red">Test</a></p>
+
+<p><img src="/&quot;style=&quot;border-color:red;border-size:1px;border-style:solid" alt="" />
+<img src="/'style='border-color:red;border-size:1px;border-style:solid" alt="" /></p>
diff --git a/tests/php/Tight blocks.text b/tests/php/Tight blocks.text
new file mode 100644
index 0000000..ae4cdcb
--- /dev/null
+++ b/tests/php/Tight blocks.text
@@ -0,0 +1 @@
+Paragraph and no space: * ciao Paragraph and 1 space: * ciao Paragraph and 3 spaces: * ciao Paragraph and 4 spaces: * ciao Paragraph before header: #Header Paragraph before blockquote: >Some quote. \ No newline at end of file
diff --git a/tests/php/Tight blocks.xhtml b/tests/php/Tight blocks.xhtml
new file mode 100644
index 0000000..8655430
--- /dev/null
+++ b/tests/php/Tight blocks.xhtml
@@ -0,0 +1,21 @@
+<p>Paragraph and no space:
+* ciao</p>
+
+<p>Paragraph and 1 space:
+ * ciao</p>
+
+<p>Paragraph and 3 spaces:
+ * ciao</p>
+
+<p>Paragraph and 4 spaces:
+ * ciao</p>
+
+<p>Paragraph before header:</p>
+
+<h1>Header</h1>
+
+<p>Paragraph before blockquote:</p>
+
+<blockquote>
+ <p>Some quote.</p>
+</blockquote>
diff --git a/tests/php/extra/Abbr.text b/tests/php/extra/Abbr.text
new file mode 100644
index 0000000..ae72f4e
--- /dev/null
+++ b/tests/php/extra/Abbr.text
@@ -0,0 +1,31 @@
+Some text about HTML, SGML and HTML4.
+
+Let's talk about the U.S.A., (É.U. or É.-U. d'A. in French).
+
+*[HTML4]: Hyper Text Markup Language version 4
+*[HTML]: Hyper Text Markup Language
+*[SGML]: Standard Generalized Markup Language
+*[U.S.A.]: United States of America
+*[É.U.] : États-Unis d'Amérique
+*[É.-U. d'A.] : États-Unis d'Amérique
+
+And here we have a CD, some CDs, and some other CD's.
+
+*[CD]: Compact Disk
+
+Let's transfert documents through TCP/IP, using TCP packets.
+
+*[IP]: Internet Protocol
+*[TCP]: Transmission Control Protocol
+
+ ---
+
+Bienvenue sur [CMS](http://www.bidulecms.com "Bidule CMS").
+
+*[CMS]: Content Management System
+
+ ---
+
+ATCCE
+
+*[ATCCE]: Abbreviation "Testing" Correct 'Character' < Escapes > \ No newline at end of file
diff --git a/tests/php/extra/Abbr.xhtml b/tests/php/extra/Abbr.xhtml
new file mode 100644
index 0000000..8beaa2e
--- /dev/null
+++ b/tests/php/extra/Abbr.xhtml
@@ -0,0 +1,15 @@
+<p>Some text about <abbr title="Hyper Text Markup Language">HTML</abbr>, <abbr title="Standard Generalized Markup Language">SGML</abbr> and <abbr title="Hyper Text Markup Language version 4">HTML4</abbr>.</p>
+
+<p>Let's talk about the <abbr title="United States of America">U.S.A.</abbr>, (<abbr title="États-Unis d'Amérique">É.U.</abbr> or <abbr title="États-Unis d'Amérique">É.-U. d'A.</abbr> in French).</p>
+
+<p>And here we have a <abbr title="Compact Disk">CD</abbr>, some CDs, and some other <abbr title="Compact Disk">CD</abbr>'s.</p>
+
+<p>Let's transfert documents through <abbr title="Transmission Control Protocol">TCP</abbr>/<abbr title="Internet Protocol">IP</abbr>, using <abbr title="Transmission Control Protocol">TCP</abbr> packets.</p>
+
+<hr />
+
+<p>Bienvenue sur <a href="http://www.bidulecms.com" title="Bidule CMS"><abbr title="Content Management System">CMS</abbr></a>.</p>
+
+<hr />
+
+<p><abbr title="Abbreviation &quot;Testing&quot; Correct 'Character' &lt; Escapes &gt;">ATCCE</abbr></p>
diff --git a/tests/php/extra/Definition Lists.text b/tests/php/extra/Definition Lists.text
new file mode 100644
index 0000000..5b3bdb6
--- /dev/null
+++ b/tests/php/extra/Definition Lists.text
@@ -0,0 +1,115 @@
+A simple definition list:
+
+Term 1
+: Definition 1
+
+Term 2
+: Definition 2
+
+With multiple terms:
+
+Term 1
+Term 2
+: Definition 1
+
+Term 3
+Term 4
+: Definition 2
+
+With multiple definitions:
+
+Term 1
+: Definition 1
+: Definition 2
+
+Term 2
+: Definition 3
+: Definition 4
+
+With multiple lines per definition:
+
+Term 1
+: Definition 1 line 1 ...
+Definition 1 line 2
+: Definition 2 line 1 ...
+Definition 2 line 2
+
+Term 2
+: Definition 3 line 2 ...
+ Definition 3 line 2
+: Definition 4 line 2 ...
+ Definition 4 line 2
+
+With paragraphs:
+
+Term 1
+
+: Definition 1 (paragraph)
+
+Term 2
+
+: Definition 2 (paragraph)
+
+With multiple paragraphs:
+
+Term 1
+
+: Definition 1 paragraph 1 line 1 ...
+ Definition 1 paragraph 1 line 2
+
+ Definition 1 paragraph 2 line 1 ...
+ Definition 1 paragraph 2 line 2
+
+Term 2
+
+: Definition 1 paragraph 1 line 1 ...
+Definition 1 paragraph 1 line 2 (lazy)
+
+ Definition 1 paragraph 2 line 1 ...
+Definition 1 paragraph 2 line 2 (lazy)
+
+* * *
+
+A mix:
+
+Term 1
+Term 2
+
+: Definition 1 paragraph 1 line 1 ...
+Definition 1 paragraph 1 line 2 (lazy)
+
+ Definition 1 paragraph 2 line 1 ...
+ Definition 1 paragraph 2 line 2
+
+: Definition 2 paragraph 1 line 1 ...
+Definition 2 paragraph 1 line 2 (lazy)
+
+Term 3
+: Definition 3 (no paragraph)
+: Definition 4 (no paragraph)
+: Definition 5 line 1 ...
+ Definition 5 line 2 (no paragraph)
+
+: Definition 6 paragraph 1 line 1 ...
+Definition 6 paragraph 1 line 2
+: Definition 7 (no paragraph)
+: Definition 8 paragraph 1 line 1 (forced paragraph) ...
+ Definition 8 paragraph 1 line 2
+
+ Definition 8 paragraph 2 line 1
+
+Term 4
+: Definition 9 paragraph 1 line 1 (forced paragraph) ...
+ Definition 9 paragraph 1 line 2
+
+ Definition 9 paragraph 2 line 1
+: Definition 10 (no paragraph)
+
+* * *
+
+Special cases:
+
+Term
+
+: code block
+ as first element of a definition \ No newline at end of file
diff --git a/tests/php/extra/Definition Lists.xhtml b/tests/php/extra/Definition Lists.xhtml
new file mode 100644
index 0000000..f99f456
--- /dev/null
+++ b/tests/php/extra/Definition Lists.xhtml
@@ -0,0 +1,155 @@
+<p>A simple definition list:</p>
+
+<dl>
+<dt>Term 1</dt>
+<dd>Definition 1</dd>
+
+<dt>Term 2</dt>
+<dd>Definition 2</dd>
+</dl>
+
+<p>With multiple terms:</p>
+
+<dl>
+<dt>Term 1</dt>
+<dt>Term 2</dt>
+<dd>Definition 1</dd>
+
+<dt>Term 3</dt>
+<dt>Term 4</dt>
+<dd>Definition 2</dd>
+</dl>
+
+<p>With multiple definitions:</p>
+
+<dl>
+<dt>Term 1</dt>
+<dd>Definition 1</dd>
+
+<dd>Definition 2</dd>
+
+<dt>Term 2</dt>
+<dd>Definition 3</dd>
+
+<dd>Definition 4</dd>
+</dl>
+
+<p>With multiple lines per definition:</p>
+
+<dl>
+<dt>Term 1</dt>
+<dd>Definition 1 line 1 ...
+Definition 1 line 2</dd>
+
+<dd>Definition 2 line 1 ...
+Definition 2 line 2</dd>
+
+<dt>Term 2</dt>
+<dd>Definition 3 line 2 ...
+Definition 3 line 2</dd>
+
+<dd>Definition 4 line 2 ...
+Definition 4 line 2</dd>
+</dl>
+
+<p>With paragraphs:</p>
+
+<dl>
+<dt>Term 1</dt>
+<dd>
+<p>Definition 1 (paragraph)</p>
+</dd>
+
+<dt>Term 2</dt>
+<dd>
+<p>Definition 2 (paragraph)</p>
+</dd>
+</dl>
+
+<p>With multiple paragraphs:</p>
+
+<dl>
+<dt>Term 1</dt>
+<dd>
+<p>Definition 1 paragraph 1 line 1 ...
+Definition 1 paragraph 1 line 2</p>
+
+<p>Definition 1 paragraph 2 line 1 ...
+Definition 1 paragraph 2 line 2</p>
+</dd>
+
+<dt>Term 2</dt>
+<dd>
+<p>Definition 1 paragraph 1 line 1 ...
+Definition 1 paragraph 1 line 2 (lazy)</p>
+
+<p>Definition 1 paragraph 2 line 1 ...
+Definition 1 paragraph 2 line 2 (lazy)</p>
+</dd>
+</dl>
+
+<hr />
+
+<p>A mix:</p>
+
+<dl>
+<dt>Term 1</dt>
+<dt>Term 2</dt>
+<dd>
+<p>Definition 1 paragraph 1 line 1 ...
+Definition 1 paragraph 1 line 2 (lazy)</p>
+
+<p>Definition 1 paragraph 2 line 1 ...
+Definition 1 paragraph 2 line 2</p>
+</dd>
+
+<dd>
+<p>Definition 2 paragraph 1 line 1 ...
+Definition 2 paragraph 1 line 2 (lazy)</p>
+</dd>
+
+<dt>Term 3</dt>
+<dd>Definition 3 (no paragraph)</dd>
+
+<dd>Definition 4 (no paragraph)</dd>
+
+<dd>Definition 5 line 1 ...
+Definition 5 line 2 (no paragraph)</dd>
+
+<dd>
+<p>Definition 6 paragraph 1 line 1 ...
+Definition 6 paragraph 1 line 2</p>
+</dd>
+
+<dd>Definition 7 (no paragraph)</dd>
+
+<dd>
+<p>Definition 8 paragraph 1 line 1 (forced paragraph) ...
+Definition 8 paragraph 1 line 2</p>
+
+<p>Definition 8 paragraph 2 line 1</p>
+</dd>
+
+<dt>Term 4</dt>
+<dd>
+<p>Definition 9 paragraph 1 line 1 (forced paragraph) ...
+Definition 9 paragraph 1 line 2</p>
+
+<p>Definition 9 paragraph 2 line 1</p>
+</dd>
+
+<dd>Definition 10 (no paragraph)</dd>
+</dl>
+
+<hr />
+
+<p>Special cases:</p>
+
+<dl>
+<dt>Term</dt>
+<dd>
+<pre><code>code block
+as first element of a definition
+</code></pre>
+</dd>
+</dl>
diff --git a/tests/php/extra/Emphasis.text b/tests/php/extra/Emphasis.text
new file mode 100644
index 0000000..88e93d4
--- /dev/null
+++ b/tests/php/extra/Emphasis.text
@@ -0,0 +1,80 @@
+Combined emphasis:
+
+1. ***test test***
+2. ___test test___
+3. *test **test***
+4. **test *test***
+5. ***test* test**
+6. ***test** test*
+7. ***test* test**
+8. **test *test***
+9. *test **test***
+10. _test __test___
+11. __test _test___
+12. ___test_ test__
+13. ___test__ test_
+14. ___test_ test__
+15. __test _test___
+16. _test __test___
+
+
+Incorrect nesting:
+
+1. *test **test* test**
+2. _test __test_ test__
+3. **test *test** test*
+4. __test _test__ test_
+5. *test *test* test*
+6. _test _test_ test_
+7. **test **test** test**
+8. __test __test__ test__
+
+
+
+No emphasis:
+
+1. test* test *test
+2. test** test **test
+3. test_ test _test
+4. test__ test __test
+
+
+
+Middle-word emphasis (asterisks):
+
+1. *a*b
+2. a*b*
+3. a*b*c
+4. **a**b
+5. a**b**
+6. a**b**c
+
+
+Middle-word emphasis (underscore):
+
+1. _a_b
+2. a_b_
+3. a_b_c
+4. __a__b
+5. a__b__
+6. a__b__c
+
+my_precious_file.txt
+
+
+## Tricky Cases
+
+E**. **Test** TestTestTest
+
+E**. **Test** Test Test Test
+
+
+## Overlong emphasis
+
+Name: ____________
+Organization: ____
+Region/Country: __
+
+_____Cut here_____
+
+____Cut here____
diff --git a/tests/php/extra/Emphasis.xhtml b/tests/php/extra/Emphasis.xhtml
new file mode 100644
index 0000000..1fa8218
--- /dev/null
+++ b/tests/php/extra/Emphasis.xhtml
@@ -0,0 +1,83 @@
+<p>Combined emphasis:</p>
+
+<ol>
+<li><strong><em>test test</em></strong></li>
+<li><strong><em>test test</em></strong></li>
+<li><em>test <strong>test</strong></em></li>
+<li><strong>test <em>test</em></strong></li>
+<li><strong><em>test</em> test</strong></li>
+<li><em><strong>test</strong> test</em></li>
+<li><strong><em>test</em> test</strong></li>
+<li><strong>test <em>test</em></strong></li>
+<li><em>test <strong>test</strong></em></li>
+<li><em>test <strong>test</strong></em></li>
+<li><strong>test <em>test</em></strong></li>
+<li><strong><em>test</em> test</strong></li>
+<li><em><strong>test</strong> test</em></li>
+<li><strong><em>test</em> test</strong></li>
+<li><strong>test <em>test</em></strong></li>
+<li><em>test <strong>test</strong></em></li>
+</ol>
+
+<p>Incorrect nesting:</p>
+
+<ol>
+<li>*test <strong>test* test</strong></li>
+<li>_test <strong>test_ test</strong></li>
+<li><strong>test *test</strong> test*</li>
+<li><strong>test _test</strong> test_</li>
+<li><em>test *test</em> test*</li>
+<li><em>test _test</em> test_</li>
+<li><strong>test **test</strong> test**</li>
+<li><strong>test __test</strong> test__</li>
+</ol>
+
+<p>No emphasis:</p>
+
+<ol>
+<li>test* test *test</li>
+<li>test** test **test</li>
+<li>test_ test _test</li>
+<li>test__ test __test</li>
+</ol>
+
+<p>Middle-word emphasis (asterisks):</p>
+
+<ol>
+<li><em>a</em>b</li>
+<li>a<em>b</em></li>
+<li>a<em>b</em>c</li>
+<li><strong>a</strong>b</li>
+<li>a<strong>b</strong></li>
+<li>a<strong>b</strong>c</li>
+</ol>
+
+<p>Middle-word emphasis (underscore):</p>
+
+<ol>
+<li>_a_b</li>
+<li>a_b_</li>
+<li>a_b_c</li>
+<li>__a__b</li>
+<li>a__b__</li>
+<li>a__b__c</li>
+</ol>
+
+<p>my_precious_file.txt</p>
+
+<h2>Tricky Cases</h2>
+
+<p>E**. <strong>Test</strong> TestTestTest</p>
+
+<p>E**. <strong>Test</strong> Test Test Test</p>
+
+
+<h2>Overlong emphasis</h2>
+
+<p>Name: ____________<br />
+Organization: ____<br />
+Region/Country: __</p>
+
+<p>_____Cut here_____</p>
+
+<p>____Cut here____</p>
diff --git a/tests/php/extra/Fenced Code Blocks.text b/tests/php/extra/Fenced Code Blocks.text
new file mode 100644
index 0000000..f2400ff
--- /dev/null
+++ b/tests/php/extra/Fenced Code Blocks.text
@@ -0,0 +1,60 @@
+~~~
+Fenced
+~~~
+
+Code block starting and ending with empty lines:
+~~~
+
+
+Fenced
+
+
+~~~
+
+Indented code block containing fenced code block sample:
+
+ ~~~
+ Fenced
+ ~~~
+
+Fenced code block with indented code block sample:
+
+~~~
+Some text
+
+ Indented code block sample code
+~~~
+
+Fenced code block with long markers:
+
+~~~~~~~~~~~~~~~~~~
+Fenced
+~~~~~~~~~~~~~~~~~~
+
+Fenced code block with fenced code block markers of different length in it:
+
+~~~~
+In code block
+~~~
+Still in code block
+~~~~~
+Still in code block
+~~~~
+
+Fenced code block with Markdown header and horizontal rule:
+
+~~~
+#test
+---
+~~~
+
+Fenced code block with link definitions, footnote definition and
+abbreviation definitions:
+
+~~~
+[example]: http://example.com/
+
+[^1]: Footnote def
+
+*[HTML]: HyperText Markup Language
+~~~ \ No newline at end of file
diff --git a/tests/php/extra/Fenced Code Blocks.xhtml b/tests/php/extra/Fenced Code Blocks.xhtml
new file mode 100644
index 0000000..518908c
--- /dev/null
+++ b/tests/php/extra/Fenced Code Blocks.xhtml
@@ -0,0 +1,53 @@
+<pre><code>Fenced
+</code></pre>
+
+<p>Code block starting and ending with empty lines:</p>
+
+<pre><code><br /><br />Fenced
+
+
+</code></pre>
+
+<p>Indented code block containing fenced code block sample:</p>
+
+<pre><code>~~~
+Fenced
+~~~
+</code></pre>
+
+<p>Fenced code block with indented code block sample:</p>
+
+<pre><code>Some text
+
+ Indented code block sample code
+</code></pre>
+
+<p>Fenced code block with long markers:</p>
+
+<pre><code>Fenced
+</code></pre>
+
+<p>Fenced code block with fenced code block markers of different length in it:</p>
+
+<pre><code>In code block
+~~~
+Still in code block
+~~~~~
+Still in code block
+</code></pre>
+
+<p>Fenced code block with Markdown header and horizontal rule:</p>
+
+<pre><code>#test
+---
+</code></pre>
+
+<p>Fenced code block with link definitions, footnote definition and
+abbreviation definitions:</p>
+
+<pre><code>[example]: http://example.com/
+
+[^1]: Footnote def
+
+*[HTML]: HyperText Markup Language
+</code></pre>
diff --git a/tests/php/extra/Footnotes.text b/tests/php/extra/Footnotes.text
new file mode 100644
index 0000000..40192e9
--- /dev/null
+++ b/tests/php/extra/Footnotes.text
@@ -0,0 +1,61 @@
+This is the first paragraph.[^first]
+
+[^first]: This is the first note.
+
+* List item one.[^second]
+* List item two.[^third]
+
+[^third]: This is the third note, defined out of order.
+[^second]: This is the second note.
+[^fourth]: This is the fourth note.
+
+# Header[^fourth]
+
+Some paragraph with a footnote[^1], and another[^2].
+
+[^1]: Content for fifth footnote.
+[^2]: Content for sixth footnote spaning on
+ three lines, with some span-level markup like
+ _emphasis_, a [link][].
+
+[link]: http://www.michelf.com/
+
+Another paragraph with a named footnote[^fn-name].
+
+[^fn-name]:
+ Footnote beginning on the line next to the marker.
+
+This paragraph should not have a footnote marker since
+the footnote is undefined.[^3]
+
+This paragraph should not have a footnote marker since
+the footnote has already been used before.[^1]
+
+This paragraph links to a footnote with plenty of
+block-level content.[^block]
+
+[^block]:
+ Paragraph.
+
+ * List item
+
+ > Blockquote
+
+ Code block
+
+This paragraph host the footnote reference within a
+footnote test[^reference].
+
+[^reference]:
+ This footnote has a footnote of its own.[^nested]
+
+[^nested]:
+ This footnote should appear even though as it is refered
+ from another footnote. But [^reference] should be litteral
+ since the footnote with that name has already been used.
+
+ - - -
+
+Testing unusual footnote name[^1$^!"'].
+
+[^1$^!"']: Haha!
diff --git a/tests/php/extra/Footnotes.xhtml b/tests/php/extra/Footnotes.xhtml
new file mode 100644
index 0000000..e33639d
--- /dev/null
+++ b/tests/php/extra/Footnotes.xhtml
@@ -0,0 +1,96 @@
+<p>This is the first paragraph.<sup id="fnref:first"><a href="#fn:first" rel="footnote">1</a></sup></p>
+
+<ul>
+<li>List item one.<sup id="fnref:second"><a href="#fn:second" rel="footnote">2</a></sup></li>
+<li>List item two.<sup id="fnref:third"><a href="#fn:third" rel="footnote">3</a></sup></li>
+</ul>
+
+<h1>Header<sup id="fnref:fourth"><a href="#fn:fourth" rel="footnote">4</a></sup></h1>
+
+<p>Some paragraph with a footnote<sup id="fnref:1"><a href="#fn:1" rel="footnote">5</a></sup>, and another<sup id="fnref:2"><a href="#fn:2" rel="footnote">6</a></sup>.</p>
+
+<p>Another paragraph with a named footnote<sup id="fnref:fn-name"><a href="#fn:fn-name" rel="footnote">7</a></sup>.</p>
+
+<p>This paragraph should not have a footnote marker since
+the footnote is undefined.[^3]</p>
+
+<p>This paragraph should not have a footnote marker since
+the footnote has already been used before.[^1]</p>
+
+<p>This paragraph links to a footnote with plenty of
+block-level content.<sup id="fnref:block"><a href="#fn:block" rel="footnote">8</a></sup></p>
+
+<p>This paragraph host the footnote reference within a
+footnote test<sup id="fnref:reference"><a href="#fn:reference" rel="footnote">9</a></sup>.</p>
+
+<hr />
+
+<p>Testing unusual footnote name<sup id="fnref:1$^!&quot;'"><a href="#fn:1$^!&quot;'" rel="footnote">10</a></sup>.</p>
+
+<div class="footnotes">
+<hr />
+<ol>
+
+<li id="fn:first">
+<p>This is the first note.&#160;<a href="#fnref:first" rev="footnote">&#8617;</a></p>
+</li>
+
+<li id="fn:second">
+<p>This is the second note.&#160;<a href="#fnref:second" rev="footnote">&#8617;</a></p>
+</li>
+
+<li id="fn:third">
+<p>This is the third note, defined out of order.&#160;<a href="#fnref:third" rev="footnote">&#8617;</a></p>
+</li>
+
+<li id="fn:fourth">
+<p>This is the fourth note.&#160;<a href="#fnref:fourth" rev="footnote">&#8617;</a></p>
+</li>
+
+<li id="fn:1">
+<p>Content for fifth footnote.&#160;<a href="#fnref:1" rev="footnote">&#8617;</a></p>
+</li>
+
+<li id="fn:2">
+<p>Content for sixth footnote spaning on
+three lines, with some span-level markup like
+<em>emphasis</em>, a <a href="http://www.michelf.com/">link</a>.&#160;<a href="#fnref:2" rev="footnote">&#8617;</a></p>
+</li>
+
+<li id="fn:fn-name">
+<p>Footnote beginning on the line next to the marker.&#160;<a href="#fnref:fn-name" rev="footnote">&#8617;</a></p>
+</li>
+
+<li id="fn:block">
+<p>Paragraph.</p>
+
+<ul>
+<li>List item</li>
+</ul>
+
+<blockquote>
+ <p>Blockquote</p>
+</blockquote>
+
+<pre><code>Code block
+</code></pre>
+
+<p><a href="#fnref:block" rev="footnote">&#8617;</a></p>
+</li>
+
+<li id="fn:reference">
+<p>This footnote has a footnote of its own.<sup id="fnref:nested"><a href="#fn:nested" rel="footnote">11</a></sup>&#160;<a href="#fnref:reference" rev="footnote">&#8617;</a></p>
+</li>
+
+<li id="fn:1$^!&quot;'">
+<p>Haha!&#160;<a href="#fnref:1$^!&quot;'" rev="footnote">&#8617;</a></p>
+</li>
+
+<li id="fn:nested">
+<p>This footnote should appear even though as it is refered
+from another footnote. But [^reference] should be litteral
+since the footnote with that name has already been used.&#160;<a href="#fnref:nested" rev="footnote">&#8617;</a></p>
+</li>
+
+</ol>
+</div>
diff --git a/tests/php/extra/Inline HTML with Markdown content.text b/tests/php/extra/Inline HTML with Markdown content.text
new file mode 100644
index 0000000..1eb5450
--- /dev/null
+++ b/tests/php/extra/Inline HTML with Markdown content.text
@@ -0,0 +1,104 @@
+# Markdown inside code blocks
+
+<div markdown="1">
+foo
+</div>
+
+<div markdown='1'>
+foo
+</div>
+
+<div markdown=1>
+foo
+</div>
+
+<table>
+<tr><td markdown="1">test _emphasis_ (span)</td></tr>
+</table>
+
+<table>
+<tr><td markdown="span">test _emphasis_ (span)</td></tr>
+</table>
+
+<table>
+<tr><td markdown="block">test _emphasis_ (block)</td></tr>
+</table>
+
+## More complicated
+
+<table>
+<tr><td markdown="1">
+* this is _not_ a list item</td></tr>
+<tr><td markdown="span">
+* this is _not_ a list item</td></tr>
+<tr><td markdown="block">
+* this _is_ a list item
+</td></tr>
+</table>
+
+## With indent
+
+<div>
+ <div markdown="1">
+ This text is no code block: if it was, the
+ closing `<div>` would be too and the HTML block
+ would be invalid.
+
+ Markdown content in HTML blocks is assumed to be
+ indented the same as the block opening tag.
+
+ **This should be the third paragraph after the header.**
+ </div>
+</div>
+
+## Code block with rogue `</div>`s in Markdown code span and block
+
+<div>
+ <div markdown="1">
+
+ This is a code block however:
+
+ </div>
+
+ Funny isn't it? Here is a code span: `</div>`.
+
+ </div>
+</div>
+
+<div>
+ <div markdown="1">
+ * List item, not a code block
+
+Some text
+
+ This is a code block.
+ </div>
+</div>
+
+## No code block in markdown span mode
+
+<p markdown="1">
+ This is not a code block since Markdown parse paragraph
+ content as span. Code spans like `</p>` are allowed though.
+</p>
+
+<p markdown="1">_Hello_ _world_</p>
+
+## Preserving attributes and tags on more than one line:
+
+<p class="test" markdown="1"
+id="12">
+Some _span_ content.
+</p>
+
+
+## Header confusion bug
+
+<table class="canvas">
+<tr>
+<td id="main" markdown="1">Hello World!
+============
+
+Hello World!</td>
+</tr>
+</table>
diff --git a/tests/php/extra/Inline HTML with Markdown content.xhtml b/tests/php/extra/Inline HTML with Markdown content.xhtml
new file mode 100644
index 0000000..4751f78
--- /dev/null
+++ b/tests/php/extra/Inline HTML with Markdown content.xhtml
@@ -0,0 +1,125 @@
+<h1>Markdown inside code blocks</h1>
+
+<div>
+
+<p>foo</p>
+
+</div>
+
+<div>
+
+<p>foo</p>
+
+</div>
+
+<div>
+
+<p>foo</p>
+
+</div>
+
+<table>
+<tr><td>test <em>emphasis</em> (span)</td></tr>
+</table>
+
+<table>
+<tr><td>test <em>emphasis</em> (span)</td></tr>
+</table>
+
+<table>
+<tr><td>
+
+<p>test <em>emphasis</em> (block)</p>
+
+</td></tr>
+</table>
+
+<h2>More complicated</h2>
+
+<table>
+<tr><td>
+* this is <em>not</em> a list item</td></tr>
+<tr><td>
+* this is <em>not</em> a list item</td></tr>
+<tr><td>
+
+<ul>
+<li>this <em>is</em> a list item</li>
+</ul>
+
+</td></tr>
+</table>
+
+<h2>With indent</h2>
+
+<div>
+ <div>
+
+<p>This text is no code block: if it was, the
+closing <code>&lt;div&gt;</code> would be too and the HTML block
+would be invalid.</p>
+
+<p>Markdown content in HTML blocks is assumed to be
+indented the same as the block opening tag.</p>
+
+<p><strong>This should be the third paragraph after the header.</strong></p>
+
+</div>
+</div>
+
+<h2>Code block with rogue <code>&lt;/div&gt;</code>s in Markdown code span and block</h2>
+
+<div>
+ <div>
+
+<p>This is a code block however:</p>
+
+<pre><code>&lt;/div&gt;
+</code></pre>
+
+<p>Funny isn't it? Here is a code span: <code>&lt;/div&gt;</code>.</p>
+
+</div>
+</div>
+
+<div>
+ <div>
+
+<ul>
+<li>List item, not a code block</li>
+</ul>
+
+<p>Some text</p>
+
+<pre><code>This is a code block.
+</code></pre>
+
+</div>
+</div>
+
+<h2>No code block in markdown span mode</h2>
+
+<p>
+ This is not a code block since Markdown parse paragraph
+ content as span. Code spans like <code>&lt;/p&gt;</code> are allowed though.
+</p>
+
+<p><em>Hello</em> <em>world</em></p>
+
+<h2>Preserving attributes and tags on more than one line:</h2>
+
+<p class="test"
+id="12">
+Some <em>span</em> content.
+</p>
+
+<h2>Header confusion bug</h2>
+
+<table class="canvas">
+<tr>
+<td id="main">Hello World!
+============
+
+Hello World!</td>
+</tr>
+</table> \ No newline at end of file
diff --git a/tests/php/extra/Tables.text b/tests/php/extra/Tables.text
new file mode 100644
index 0000000..71b93ca
--- /dev/null
+++ b/tests/php/extra/Tables.text
@@ -0,0 +1,104 @@
+# Simple tables
+
+Header 1 | Header 2
+--------- | ---------
+Cell 1 | Cell 2
+Cell 3 | Cell 4
+
+With leading pipes:
+
+| Header 1 | Header 2
+| --------- | ---------
+| Cell 1 | Cell 2
+| Cell 3 | Cell 4
+
+With tailing pipes:
+
+Header 1 | Header 2 |
+--------- | --------- |
+Cell 1 | Cell 2 |
+Cell 3 | Cell 4 |
+
+With leading and tailing pipes:
+
+| Header 1 | Header 2 |
+| --------- | --------- |
+| Cell 1 | Cell 2 |
+| Cell 3 | Cell 4 |
+
+* * *
+
+# One-column one-row table
+
+With leading pipes:
+
+| Header
+| -------
+| Cell
+
+With tailing pipes:
+
+Header |
+------- |
+Cell |
+
+With leading and tailing pipes:
+
+| Header |
+| ------- |
+| Cell |
+
+* * *
+
+Table alignement:
+
+| Default | Right | Center | Left |
+| --------- |:--------- |:---------:| ---------:|
+| Long Cell | Long Cell | Long Cell | Long Cell |
+| Cell | Cell | Cell | Cell |
+
+Table alignement (alternate spacing):
+
+| Default | Right | Center | Left |
+| --------- | :-------- | :-------: | --------: |
+| Long Cell | Long Cell | Long Cell | Long Cell |
+| Cell | Cell | Cell | Cell |
+
+* * *
+
+# Empty cells
+
+| Header 1 | Header 2 |
+| --------- | --------- |
+| A | B |
+| C | |
+
+Header 1 | Header 2
+--------- | ---------
+A | B
+ | D
+
+* * *
+
+# Missing tailing pipe
+
+Header 1 | Header 2
+--------- | --------- |
+Cell | Cell |
+Cell | Cell |
+
+Header 1 | Header 2 |
+--------- | ---------
+Cell | Cell |
+Cell | Cell |
+
+Header 1 | Header 2 |
+--------- | --------- |
+Cell | Cell
+Cell | Cell |
+
+Header 1 | Header 2 |
+--------- | --------- |
+Cell | Cell |
+Cell | Cell
+
diff --git a/tests/php/extra/Tables.xhtml b/tests/php/extra/Tables.xhtml
new file mode 100644
index 0000000..e36286c
--- /dev/null
+++ b/tests/php/extra/Tables.xhtml
@@ -0,0 +1,310 @@
+<h1>Simple tables</h1>
+
+<table>
+<thead>
+<tr>
+ <th>Header 1</th>
+ <th>Header 2</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <td>Cell 1</td>
+ <td>Cell 2</td>
+</tr>
+<tr>
+ <td>Cell 3</td>
+ <td>Cell 4</td>
+</tr>
+</tbody>
+</table>
+
+<p>With leading pipes:</p>
+
+<table>
+<thead>
+<tr>
+ <th>Header 1</th>
+ <th>Header 2</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <td>Cell 1</td>
+ <td>Cell 2</td>
+</tr>
+<tr>
+ <td>Cell 3</td>
+ <td>Cell 4</td>
+</tr>
+</tbody>
+</table>
+
+<p>With tailing pipes:</p>
+
+<table>
+<thead>
+<tr>
+ <th>Header 1</th>
+ <th>Header 2</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <td>Cell 1</td>
+ <td>Cell 2</td>
+</tr>
+<tr>
+ <td>Cell 3</td>
+ <td>Cell 4</td>
+</tr>
+</tbody>
+</table>
+
+<p>With leading and tailing pipes:</p>
+
+<table>
+<thead>
+<tr>
+ <th>Header 1</th>
+ <th>Header 2</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <td>Cell 1</td>
+ <td>Cell 2</td>
+</tr>
+<tr>
+ <td>Cell 3</td>
+ <td>Cell 4</td>
+</tr>
+</tbody>
+</table>
+
+<hr />
+
+<h1>One-column one-row table</h1>
+
+<p>With leading pipes:</p>
+
+<table>
+<thead>
+<tr>
+ <th>Header</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <td>Cell</td>
+</tr>
+</tbody>
+</table>
+
+<p>With tailing pipes:</p>
+
+<table>
+<thead>
+<tr>
+ <th>Header</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <td>Cell</td>
+</tr>
+</tbody>
+</table>
+
+<p>With leading and tailing pipes:</p>
+
+<table>
+<thead>
+<tr>
+ <th>Header</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <td>Cell</td>
+</tr>
+</tbody>
+</table>
+
+<hr />
+
+<p>Table alignement:</p>
+
+<table>
+<thead>
+<tr>
+ <th>Default</th>
+ <th align="left">Right</th>
+ <th align="center">Center</th>
+ <th align="right">Left</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <td>Long Cell</td>
+ <td align="left">Long Cell</td>
+ <td align="center">Long Cell</td>
+ <td align="right">Long Cell</td>
+</tr>
+<tr>
+ <td>Cell</td>
+ <td align="left">Cell</td>
+ <td align="center">Cell</td>
+ <td align="right">Cell</td>
+</tr>
+</tbody>
+</table>
+
+<p>Table alignement (alternate spacing):</p>
+
+<table>
+<thead>
+<tr>
+ <th>Default</th>
+ <th align="left">Right</th>
+ <th align="center">Center</th>
+ <th align="right">Left</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <td>Long Cell</td>
+ <td align="left">Long Cell</td>
+ <td align="center">Long Cell</td>
+ <td align="right">Long Cell</td>
+</tr>
+<tr>
+ <td>Cell</td>
+ <td align="left">Cell</td>
+ <td align="center">Cell</td>
+ <td align="right">Cell</td>
+</tr>
+</tbody>
+</table>
+
+<hr />
+
+<h1>Empty cells</h1>
+
+<table>
+<thead>
+<tr>
+ <th>Header 1</th>
+ <th>Header 2</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <td>A</td>
+ <td>B</td>
+</tr>
+<tr>
+ <td>C</td>
+ <td></td>
+</tr>
+</tbody>
+</table>
+
+<table>
+<thead>
+<tr>
+ <th>Header 1</th>
+ <th>Header 2</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <td>A</td>
+ <td>B</td>
+</tr>
+<tr>
+ <td></td>
+ <td>D</td>
+</tr>
+</tbody>
+</table>
+
+<hr />
+
+<h1>Missing tailing pipe</h1>
+
+<table>
+<thead>
+<tr>
+ <th>Header 1</th>
+ <th>Header 2</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <td>Cell</td>
+ <td>Cell</td>
+</tr>
+<tr>
+ <td>Cell</td>
+ <td>Cell</td>
+</tr>
+</tbody>
+</table>
+
+<table>
+<thead>
+<tr>
+ <th>Header 1</th>
+ <th>Header 2</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <td>Cell</td>
+ <td>Cell</td>
+</tr>
+<tr>
+ <td>Cell</td>
+ <td>Cell</td>
+</tr>
+</tbody>
+</table>
+
+<table>
+<thead>
+<tr>
+ <th>Header 1</th>
+ <th>Header 2</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <td>Cell</td>
+ <td>Cell</td>
+</tr>
+<tr>
+ <td>Cell</td>
+ <td>Cell</td>
+</tr>
+</tbody>
+</table>
+
+<table>
+<thead>
+<tr>
+ <th>Header 1</th>
+ <th>Header 2</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+ <td>Cell</td>
+ <td>Cell</td>
+</tr>
+<tr>
+ <td>Cell</td>
+ <td>Cell</td>
+</tr>
+</tbody>
+</table> \ No newline at end of file
diff --git a/MarkdownTest/Tests_2004/Amps and angle encoding.html b/tests/pl/Tests_2004/Amps and angle encoding.html
index 9606860..9606860 100644
--- a/MarkdownTest/Tests_2004/Amps and angle encoding.html
+++ b/tests/pl/Tests_2004/Amps and angle encoding.html
diff --git a/MarkdownTest/Tests_2004/Amps and angle encoding.text b/tests/pl/Tests_2004/Amps and angle encoding.text
index 0e9527f..0e9527f 100644
--- a/MarkdownTest/Tests_2004/Amps and angle encoding.text
+++ b/tests/pl/Tests_2004/Amps and angle encoding.text
diff --git a/MarkdownTest/Tests_2004/Auto links.html b/tests/pl/Tests_2004/Auto links.html
index f8df985..f8df985 100644
--- a/MarkdownTest/Tests_2004/Auto links.html
+++ b/tests/pl/Tests_2004/Auto links.html
diff --git a/MarkdownTest/Tests_2004/Auto links.text b/tests/pl/Tests_2004/Auto links.text
index abbc488..abbc488 100644
--- a/MarkdownTest/Tests_2004/Auto links.text
+++ b/tests/pl/Tests_2004/Auto links.text
diff --git a/MarkdownTest/Tests_2004/Backslash escapes.html b/tests/pl/Tests_2004/Backslash escapes.html
index 77823c3..77823c3 100644
--- a/MarkdownTest/Tests_2004/Backslash escapes.html
+++ b/tests/pl/Tests_2004/Backslash escapes.html
diff --git a/MarkdownTest/Tests_2004/Backslash escapes.text b/tests/pl/Tests_2004/Backslash escapes.text
index 16447a0..16447a0 100644
--- a/MarkdownTest/Tests_2004/Backslash escapes.text
+++ b/tests/pl/Tests_2004/Backslash escapes.text
diff --git a/MarkdownTest/Tests_2004/Blockquotes with code blocks.html b/tests/pl/Tests_2004/Blockquotes with code blocks.html
index 990202a..990202a 100644
--- a/MarkdownTest/Tests_2004/Blockquotes with code blocks.html
+++ b/tests/pl/Tests_2004/Blockquotes with code blocks.html
diff --git a/MarkdownTest/Tests_2004/Blockquotes with code blocks.text b/tests/pl/Tests_2004/Blockquotes with code blocks.text
index c31d171..c31d171 100644
--- a/MarkdownTest/Tests_2004/Blockquotes with code blocks.text
+++ b/tests/pl/Tests_2004/Blockquotes with code blocks.text
diff --git a/MarkdownTest/Tests_2004/Hard-wrapped paragraphs with list-like lines.html b/tests/pl/Tests_2004/Hard-wrapped paragraphs with list-like lines.html
index e21ac79..e21ac79 100644
--- a/MarkdownTest/Tests_2004/Hard-wrapped paragraphs with list-like lines.html
+++ b/tests/pl/Tests_2004/Hard-wrapped paragraphs with list-like lines.html
diff --git a/MarkdownTest/Tests_2004/Hard-wrapped paragraphs with list-like lines.text b/tests/pl/Tests_2004/Hard-wrapped paragraphs with list-like lines.text
index f8a5b27..f8a5b27 100644
--- a/MarkdownTest/Tests_2004/Hard-wrapped paragraphs with list-like lines.text
+++ b/tests/pl/Tests_2004/Hard-wrapped paragraphs with list-like lines.text
diff --git a/MarkdownTest/Tests_2004/Horizontal rules.html b/tests/pl/Tests_2004/Horizontal rules.html
index 2dc2ab6..2dc2ab6 100644
--- a/MarkdownTest/Tests_2004/Horizontal rules.html
+++ b/tests/pl/Tests_2004/Horizontal rules.html
diff --git a/MarkdownTest/Tests_2004/Horizontal rules.text b/tests/pl/Tests_2004/Horizontal rules.text
index 1594bda..1594bda 100644
--- a/MarkdownTest/Tests_2004/Horizontal rules.text
+++ b/tests/pl/Tests_2004/Horizontal rules.text
diff --git a/MarkdownTest/Tests_2004/Inline HTML (Advanced).html b/tests/pl/Tests_2004/Inline HTML (Advanced).html
index 1972d87..1972d87 100644
--- a/MarkdownTest/Tests_2004/Inline HTML (Advanced).html
+++ b/tests/pl/Tests_2004/Inline HTML (Advanced).html
diff --git a/MarkdownTest/Tests_2004/Inline HTML (Advanced).text b/tests/pl/Tests_2004/Inline HTML (Advanced).text
index 9d71ddc..9d71ddc 100644
--- a/MarkdownTest/Tests_2004/Inline HTML (Advanced).text
+++ b/tests/pl/Tests_2004/Inline HTML (Advanced).text
diff --git a/MarkdownTest/Tests_2004/Inline HTML (Simple).html b/tests/pl/Tests_2004/Inline HTML (Simple).html
index 6bf78f8..6bf78f8 100644
--- a/MarkdownTest/Tests_2004/Inline HTML (Simple).html
+++ b/tests/pl/Tests_2004/Inline HTML (Simple).html
diff --git a/MarkdownTest/Tests_2004/Inline HTML (Simple).text b/tests/pl/Tests_2004/Inline HTML (Simple).text
index 14aa2dc..14aa2dc 100644
--- a/MarkdownTest/Tests_2004/Inline HTML (Simple).text
+++ b/tests/pl/Tests_2004/Inline HTML (Simple).text
diff --git a/MarkdownTest/Tests_2004/Inline HTML comments.html b/tests/pl/Tests_2004/Inline HTML comments.html
index 3f167a1..3f167a1 100644
--- a/MarkdownTest/Tests_2004/Inline HTML comments.html
+++ b/tests/pl/Tests_2004/Inline HTML comments.html
diff --git a/MarkdownTest/Tests_2004/Inline HTML comments.text b/tests/pl/Tests_2004/Inline HTML comments.text
index 41d830d..41d830d 100644
--- a/MarkdownTest/Tests_2004/Inline HTML comments.text
+++ b/tests/pl/Tests_2004/Inline HTML comments.text
diff --git a/MarkdownTest/Tests_2004/Links, inline style.html b/tests/pl/Tests_2004/Links, inline style.html
index bdfabb5..bdfabb5 100644
--- a/MarkdownTest/Tests_2004/Links, inline style.html
+++ b/tests/pl/Tests_2004/Links, inline style.html
diff --git a/MarkdownTest/Tests_2004/Links, inline style.text b/tests/pl/Tests_2004/Links, inline style.text
index 4d0c1c2..4d0c1c2 100644
--- a/MarkdownTest/Tests_2004/Links, inline style.text
+++ b/tests/pl/Tests_2004/Links, inline style.text
diff --git a/MarkdownTest/Tests_2004/Links, reference style.html b/tests/pl/Tests_2004/Links, reference style.html
index cf4d833..cf4d833 100644
--- a/MarkdownTest/Tests_2004/Links, reference style.html
+++ b/tests/pl/Tests_2004/Links, reference style.html
diff --git a/MarkdownTest/Tests_2004/Links, reference style.text b/tests/pl/Tests_2004/Links, reference style.text
index b2fa734..b2fa734 100644
--- a/MarkdownTest/Tests_2004/Links, reference style.text
+++ b/tests/pl/Tests_2004/Links, reference style.text
diff --git a/MarkdownTest/Tests_2004/Literal quotes in titles.html b/tests/pl/Tests_2004/Literal quotes in titles.html
index 611c1ac..611c1ac 100644
--- a/MarkdownTest/Tests_2004/Literal quotes in titles.html
+++ b/tests/pl/Tests_2004/Literal quotes in titles.html
diff --git a/MarkdownTest/Tests_2004/Literal quotes in titles.text b/tests/pl/Tests_2004/Literal quotes in titles.text
index 29d0e42..29d0e42 100644
--- a/MarkdownTest/Tests_2004/Literal quotes in titles.text
+++ b/tests/pl/Tests_2004/Literal quotes in titles.text
diff --git a/MarkdownTest/Tests_2004/Markdown Documentation - Basics.html b/tests/pl/Tests_2004/Markdown Documentation - Basics.html
index d5bdbb2..342f0c1 100644
--- a/MarkdownTest/Tests_2004/Markdown Documentation - Basics.html
+++ b/tests/pl/Tests_2004/Markdown Documentation - Basics.html
@@ -29,7 +29,7 @@ can <a href="/projects/markdown/basics.text">see the source for it by adding '.t
<p>A paragraph is simply one or more consecutive lines of text, separated
by one or more blank lines. (A blank line is any line that looks like a
blank line -- a line containing nothing spaces or tabs is considered
-blank.) Normal paragraphs should not be intended with spaces or tabs.</p>
+blank.) Normal paragraphs should not be indented with spaces or tabs.</p>
<p>Markdown offers two styles of headers: <em>Setext</em> and <em>atx</em>.
Setext-style headers for <code>&lt;h1&gt;</code> and <code>&lt;h2&gt;</code> are created by
diff --git a/MarkdownTest/Tests_2004/Markdown Documentation - Basics.text b/tests/pl/Tests_2004/Markdown Documentation - Basics.text
index 486055c..2abe24a 100644
--- a/MarkdownTest/Tests_2004/Markdown Documentation - Basics.text
+++ b/tests/pl/Tests_2004/Markdown Documentation - Basics.text
@@ -37,7 +37,7 @@ can [see the source for it by adding '.text' to the URL] [src].
A paragraph is simply one or more consecutive lines of text, separated
by one or more blank lines. (A blank line is any line that looks like a
blank line -- a line containing nothing spaces or tabs is considered
-blank.) Normal paragraphs should not be intended with spaces or tabs.
+blank.) Normal paragraphs should not be indented with spaces or tabs.
Markdown offers two styles of headers: *Setext* and *atx*.
Setext-style headers for `<h1>` and `<h2>` are created by
diff --git a/MarkdownTest/Tests_2004/Markdown Documentation - Syntax.html b/tests/pl/Tests_2004/Markdown Documentation - Syntax.html
index 5c01306..7847793 100644
--- a/MarkdownTest/Tests_2004/Markdown Documentation - Syntax.html
+++ b/tests/pl/Tests_2004/Markdown Documentation - Syntax.html
@@ -186,7 +186,7 @@ and <code>&amp;</code> in your example code needs to be escaped.)</p>
<p>A paragraph is simply one or more consecutive lines of text, separated
by one or more blank lines. (A blank line is any line that looks like a
blank line -- a line containing nothing but spaces or tabs is considered
-blank.) Normal paragraphs should not be intended with spaces or tabs.</p>
+blank.) Normal paragraphs should not be indented with spaces or tabs.</p>
<p>The implication of the "one or more consecutive lines of text" rule is
that Markdown supports "hard-wrapped" text paragraphs. This differs
@@ -414,7 +414,7 @@ items in <code>&lt;p&gt;</code> tags in the HTML output. For example, this input
</code></pre>
<p>List items may consist of multiple paragraphs. Each subsequent
-paragraph in a list item must be intended by either 4 spaces
+paragraph in a list item must be indented by either 4 spaces
or one tab:</p>
<pre><code>1. This is a list item with two paragraphs. Lorem ipsum dolor
diff --git a/MarkdownTest/Tests_2004/Markdown Documentation - Syntax.text b/tests/pl/Tests_2004/Markdown Documentation - Syntax.text
index dabd75c..e0a3d1c 100644
--- a/MarkdownTest/Tests_2004/Markdown Documentation - Syntax.text
+++ b/tests/pl/Tests_2004/Markdown Documentation - Syntax.text
@@ -186,7 +186,7 @@ and `&` in your example code needs to be escaped.)
A paragraph is simply one or more consecutive lines of text, separated
by one or more blank lines. (A blank line is any line that looks like a
blank line -- a line containing nothing but spaces or tabs is considered
-blank.) Normal paragraphs should not be intended with spaces or tabs.
+blank.) Normal paragraphs should not be indented with spaces or tabs.
The implication of the "one or more consecutive lines of text" rule is
that Markdown supports "hard-wrapped" text paragraphs. This differs
@@ -401,7 +401,7 @@ will turn into:
</ul>
List items may consist of multiple paragraphs. Each subsequent
-paragraph in a list item must be intended by either 4 spaces
+paragraph in a list item must be indented by either 4 spaces
or one tab:
1. This is a list item with two paragraphs. Lorem ipsum dolor
diff --git a/MarkdownTest/Tests_2004/Nested blockquotes.html b/tests/pl/Tests_2004/Nested blockquotes.html
index d8ec7f8..d8ec7f8 100644
--- a/MarkdownTest/Tests_2004/Nested blockquotes.html
+++ b/tests/pl/Tests_2004/Nested blockquotes.html
diff --git a/MarkdownTest/Tests_2004/Nested blockquotes.text b/tests/pl/Tests_2004/Nested blockquotes.text
index ed3c624..ed3c624 100644
--- a/MarkdownTest/Tests_2004/Nested blockquotes.text
+++ b/tests/pl/Tests_2004/Nested blockquotes.text
diff --git a/MarkdownTest/Tests_2004/Ordered and unordered lists.html b/tests/pl/Tests_2004/Ordered and unordered lists.html
index ce85c3a..ce85c3a 100644
--- a/MarkdownTest/Tests_2004/Ordered and unordered lists.html
+++ b/tests/pl/Tests_2004/Ordered and unordered lists.html
diff --git a/MarkdownTest/Tests_2004/Ordered and unordered lists.text b/tests/pl/Tests_2004/Ordered and unordered lists.text
index 621db58..621db58 100644
--- a/MarkdownTest/Tests_2004/Ordered and unordered lists.text
+++ b/tests/pl/Tests_2004/Ordered and unordered lists.text
diff --git a/MarkdownTest/Tests_2004/Strong and em together.html b/tests/pl/Tests_2004/Strong and em together.html
index 71ec78c..71ec78c 100644
--- a/MarkdownTest/Tests_2004/Strong and em together.html
+++ b/tests/pl/Tests_2004/Strong and em together.html
diff --git a/MarkdownTest/Tests_2004/Strong and em together.text b/tests/pl/Tests_2004/Strong and em together.text
index 95ee690..95ee690 100644
--- a/MarkdownTest/Tests_2004/Strong and em together.text
+++ b/tests/pl/Tests_2004/Strong and em together.text
diff --git a/MarkdownTest/Tests_2004/Tabs.html b/tests/pl/Tests_2004/Tabs.html
index 3301ba8..3301ba8 100644
--- a/MarkdownTest/Tests_2004/Tabs.html
+++ b/tests/pl/Tests_2004/Tabs.html
diff --git a/MarkdownTest/Tests_2004/Tabs.text b/tests/pl/Tests_2004/Tabs.text
index 589d113..589d113 100644
--- a/MarkdownTest/Tests_2004/Tabs.text
+++ b/tests/pl/Tests_2004/Tabs.text
diff --git a/MarkdownTest/Tests_2004/Tidyness.html b/tests/pl/Tests_2004/Tidyness.html
index f2a8ce7..f2a8ce7 100644
--- a/MarkdownTest/Tests_2004/Tidyness.html
+++ b/tests/pl/Tests_2004/Tidyness.html
diff --git a/MarkdownTest/Tests_2004/Tidyness.text b/tests/pl/Tests_2004/Tidyness.text
index 5f18b8d..5f18b8d 100644
--- a/MarkdownTest/Tests_2004/Tidyness.text
+++ b/tests/pl/Tests_2004/Tidyness.text
diff --git a/MarkdownTest/Tests_2004/Yuri-Attributes.html b/tests/pl/Tests_2004/Yuri-Attributes.html
index 057da2f..057da2f 100644
--- a/MarkdownTest/Tests_2004/Yuri-Attributes.html
+++ b/tests/pl/Tests_2004/Yuri-Attributes.html
diff --git a/MarkdownTest/Tests_2004/Yuri-Attributes.text b/tests/pl/Tests_2004/Yuri-Attributes.text
index 8ee512d..8ee512d 100644
--- a/MarkdownTest/Tests_2004/Yuri-Attributes.text
+++ b/tests/pl/Tests_2004/Yuri-Attributes.text
diff --git a/MarkdownTest/Tests_2004/Yuri-Email.html b/tests/pl/Tests_2004/Yuri-Email.html
index bf1d149..bf1d149 100644
--- a/MarkdownTest/Tests_2004/Yuri-Email.html
+++ b/tests/pl/Tests_2004/Yuri-Email.html
diff --git a/MarkdownTest/Tests_2004/Yuri-Email.text b/tests/pl/Tests_2004/Yuri-Email.text
index 8f9c779..8f9c779 100644
--- a/MarkdownTest/Tests_2004/Yuri-Email.text
+++ b/tests/pl/Tests_2004/Yuri-Email.text
diff --git a/MarkdownTest/Tests_2004/Yuri-Footnotes.html b/tests/pl/Tests_2004/Yuri-Footnotes.html
index cadb040..cadb040 100644
--- a/MarkdownTest/Tests_2004/Yuri-Footnotes.html
+++ b/tests/pl/Tests_2004/Yuri-Footnotes.html
diff --git a/MarkdownTest/Tests_2004/Yuri-Footnotes.text b/tests/pl/Tests_2004/Yuri-Footnotes.text
index 16fe402..16fe402 100644
--- a/MarkdownTest/Tests_2004/Yuri-Footnotes.text
+++ b/tests/pl/Tests_2004/Yuri-Footnotes.text
diff --git a/MarkdownTest/Tests_2004/Yuri-Links-in-Headers.html b/tests/pl/Tests_2004/Yuri-Links-in-Headers.html
index 6afc56e..6afc56e 100644
--- a/MarkdownTest/Tests_2004/Yuri-Links-in-Headers.html
+++ b/tests/pl/Tests_2004/Yuri-Links-in-Headers.html
diff --git a/MarkdownTest/Tests_2004/Yuri-Links-in-Headers.text b/tests/pl/Tests_2004/Yuri-Links-in-Headers.text
index d06a9e1..d06a9e1 100644
--- a/MarkdownTest/Tests_2004/Yuri-Links-in-Headers.text
+++ b/tests/pl/Tests_2004/Yuri-Links-in-Headers.text
diff --git a/MarkdownTest/Tests_2007/Amps and angle encoding.html b/tests/pl/Tests_2007/Amps and angle encoding.html
index 9606860..9606860 100644
--- a/MarkdownTest/Tests_2007/Amps and angle encoding.html
+++ b/tests/pl/Tests_2007/Amps and angle encoding.html
diff --git a/MarkdownTest/Tests_2007/Amps and angle encoding.text b/tests/pl/Tests_2007/Amps and angle encoding.text
index 0e9527f..0e9527f 100644
--- a/MarkdownTest/Tests_2007/Amps and angle encoding.text
+++ b/tests/pl/Tests_2007/Amps and angle encoding.text
diff --git a/MarkdownTest/Tests_2007/Auto links.html b/tests/pl/Tests_2007/Auto links.html
index f8df985..f8df985 100644
--- a/MarkdownTest/Tests_2007/Auto links.html
+++ b/tests/pl/Tests_2007/Auto links.html
diff --git a/MarkdownTest/Tests_2007/Auto links.text b/tests/pl/Tests_2007/Auto links.text
index abbc488..abbc488 100644
--- a/MarkdownTest/Tests_2007/Auto links.text
+++ b/tests/pl/Tests_2007/Auto links.text
diff --git a/MarkdownTest/Tests_2007/Backslash escapes.html b/tests/pl/Tests_2007/Backslash escapes.html
index 29870da..29870da 100644
--- a/MarkdownTest/Tests_2007/Backslash escapes.html
+++ b/tests/pl/Tests_2007/Backslash escapes.html
diff --git a/MarkdownTest/Tests_2007/Backslash escapes.text b/tests/pl/Tests_2007/Backslash escapes.text
index 5b014cb..5b014cb 100644
--- a/MarkdownTest/Tests_2007/Backslash escapes.text
+++ b/tests/pl/Tests_2007/Backslash escapes.text
diff --git a/MarkdownTest/Tests_2007/Blockquotes with code blocks.html b/tests/pl/Tests_2007/Blockquotes with code blocks.html
index 990202a..990202a 100644
--- a/MarkdownTest/Tests_2007/Blockquotes with code blocks.html
+++ b/tests/pl/Tests_2007/Blockquotes with code blocks.html
diff --git a/MarkdownTest/Tests_2007/Blockquotes with code blocks.text b/tests/pl/Tests_2007/Blockquotes with code blocks.text
index c31d171..c31d171 100644
--- a/MarkdownTest/Tests_2007/Blockquotes with code blocks.text
+++ b/tests/pl/Tests_2007/Blockquotes with code blocks.text
diff --git a/MarkdownTest/Tests_2007/Code Blocks.html b/tests/pl/Tests_2007/Code Blocks.html
index 32703f5..32703f5 100644
--- a/MarkdownTest/Tests_2007/Code Blocks.html
+++ b/tests/pl/Tests_2007/Code Blocks.html
diff --git a/MarkdownTest/Tests_2007/Code Blocks.text b/tests/pl/Tests_2007/Code Blocks.text
index b54b092..b54b092 100644
--- a/MarkdownTest/Tests_2007/Code Blocks.text
+++ b/tests/pl/Tests_2007/Code Blocks.text
diff --git a/MarkdownTest/Tests_2007/Code Spans.html b/tests/pl/Tests_2007/Code Spans.html
index b057457..b057457 100644
--- a/MarkdownTest/Tests_2007/Code Spans.html
+++ b/tests/pl/Tests_2007/Code Spans.html
diff --git a/MarkdownTest/Tests_2007/Code Spans.text b/tests/pl/Tests_2007/Code Spans.text
index 5c229c7..5c229c7 100644
--- a/MarkdownTest/Tests_2007/Code Spans.text
+++ b/tests/pl/Tests_2007/Code Spans.text
diff --git a/MarkdownTest/Tests_2007/Hard-wrapped paragraphs with list-like lines.html b/tests/pl/Tests_2007/Hard-wrapped paragraphs with list-like lines.html
index e21ac79..e21ac79 100644
--- a/MarkdownTest/Tests_2007/Hard-wrapped paragraphs with list-like lines.html
+++ b/tests/pl/Tests_2007/Hard-wrapped paragraphs with list-like lines.html
diff --git a/MarkdownTest/Tests_2007/Hard-wrapped paragraphs with list-like lines.text b/tests/pl/Tests_2007/Hard-wrapped paragraphs with list-like lines.text
index f8a5b27..f8a5b27 100644
--- a/MarkdownTest/Tests_2007/Hard-wrapped paragraphs with list-like lines.text
+++ b/tests/pl/Tests_2007/Hard-wrapped paragraphs with list-like lines.text
diff --git a/MarkdownTest/Tests_2007/Horizontal rules.html b/tests/pl/Tests_2007/Horizontal rules.html
index 2dc2ab6..2dc2ab6 100644
--- a/MarkdownTest/Tests_2007/Horizontal rules.html
+++ b/tests/pl/Tests_2007/Horizontal rules.html
diff --git a/MarkdownTest/Tests_2007/Horizontal rules.text b/tests/pl/Tests_2007/Horizontal rules.text
index 1594bda..1594bda 100644
--- a/MarkdownTest/Tests_2007/Horizontal rules.text
+++ b/tests/pl/Tests_2007/Horizontal rules.text
diff --git a/MarkdownTest/Tests_2007/Images.html b/tests/pl/Tests_2007/Images.html
index 217f028..217f028 100644
--- a/MarkdownTest/Tests_2007/Images.html
+++ b/tests/pl/Tests_2007/Images.html
diff --git a/MarkdownTest/Tests_2007/Images.text b/tests/pl/Tests_2007/Images.text
index 5707590..5707590 100644
--- a/MarkdownTest/Tests_2007/Images.text
+++ b/tests/pl/Tests_2007/Images.text
diff --git a/MarkdownTest/Tests_2007/Inline HTML (Advanced).html b/tests/pl/Tests_2007/Inline HTML (Advanced).html
index 884f14c..884f14c 100644
--- a/MarkdownTest/Tests_2007/Inline HTML (Advanced).html
+++ b/tests/pl/Tests_2007/Inline HTML (Advanced).html
diff --git a/MarkdownTest/Tests_2007/Inline HTML (Advanced).text b/tests/pl/Tests_2007/Inline HTML (Advanced).text
index 3633f81..3633f81 100644
--- a/MarkdownTest/Tests_2007/Inline HTML (Advanced).text
+++ b/tests/pl/Tests_2007/Inline HTML (Advanced).text
diff --git a/MarkdownTest/Tests_2007/Inline HTML (Simple).html b/tests/pl/Tests_2007/Inline HTML (Simple).html
index 6bf78f8..6bf78f8 100644
--- a/MarkdownTest/Tests_2007/Inline HTML (Simple).html
+++ b/tests/pl/Tests_2007/Inline HTML (Simple).html
diff --git a/MarkdownTest/Tests_2007/Inline HTML (Simple).text b/tests/pl/Tests_2007/Inline HTML (Simple).text
index 14aa2dc..14aa2dc 100644
--- a/MarkdownTest/Tests_2007/Inline HTML (Simple).text
+++ b/tests/pl/Tests_2007/Inline HTML (Simple).text
diff --git a/MarkdownTest/Tests_2007/Inline HTML comments.html b/tests/pl/Tests_2007/Inline HTML comments.html
index 3f167a1..3f167a1 100644
--- a/MarkdownTest/Tests_2007/Inline HTML comments.html
+++ b/tests/pl/Tests_2007/Inline HTML comments.html
diff --git a/MarkdownTest/Tests_2007/Inline HTML comments.text b/tests/pl/Tests_2007/Inline HTML comments.text
index 41d830d..41d830d 100644
--- a/MarkdownTest/Tests_2007/Inline HTML comments.text
+++ b/tests/pl/Tests_2007/Inline HTML comments.text
diff --git a/MarkdownTest/Tests_2007/Links, inline style.html b/tests/pl/Tests_2007/Links, inline style.html
index 9f351ef..9f351ef 100644
--- a/MarkdownTest/Tests_2007/Links, inline style.html
+++ b/tests/pl/Tests_2007/Links, inline style.html
diff --git a/MarkdownTest/Tests_2007/Links, inline style.text b/tests/pl/Tests_2007/Links, inline style.text
index aba9658..aba9658 100644
--- a/MarkdownTest/Tests_2007/Links, inline style.text
+++ b/tests/pl/Tests_2007/Links, inline style.text
diff --git a/MarkdownTest/Tests_2007/Links, reference style.html b/tests/pl/Tests_2007/Links, reference style.html
index 8e70c32..8e70c32 100644
--- a/MarkdownTest/Tests_2007/Links, reference style.html
+++ b/tests/pl/Tests_2007/Links, reference style.html
diff --git a/MarkdownTest/Tests_2007/Links, reference style.text b/tests/pl/Tests_2007/Links, reference style.text
index 341ec88..341ec88 100644
--- a/MarkdownTest/Tests_2007/Links, reference style.text
+++ b/tests/pl/Tests_2007/Links, reference style.text
diff --git a/MarkdownTest/Tests_2007/Links, shortcut references.html b/tests/pl/Tests_2007/Links, shortcut references.html
index bf81e93..bf81e93 100755..100644
--- a/MarkdownTest/Tests_2007/Links, shortcut references.html
+++ b/tests/pl/Tests_2007/Links, shortcut references.html
diff --git a/MarkdownTest/Tests_2007/Links, shortcut references.text b/tests/pl/Tests_2007/Links, shortcut references.text
index 8c44c98..8c44c98 100755..100644
--- a/MarkdownTest/Tests_2007/Links, shortcut references.text
+++ b/tests/pl/Tests_2007/Links, shortcut references.text
diff --git a/MarkdownTest/Tests_2007/Literal quotes in titles.html b/tests/pl/Tests_2007/Literal quotes in titles.html
index 611c1ac..611c1ac 100644
--- a/MarkdownTest/Tests_2007/Literal quotes in titles.html
+++ b/tests/pl/Tests_2007/Literal quotes in titles.html
diff --git a/MarkdownTest/Tests_2007/Literal quotes in titles.text b/tests/pl/Tests_2007/Literal quotes in titles.text
index 29d0e42..29d0e42 100644
--- a/MarkdownTest/Tests_2007/Literal quotes in titles.text
+++ b/tests/pl/Tests_2007/Literal quotes in titles.text
diff --git a/MarkdownTest/Tests_2007/Markdown Documentation - Basics.html b/tests/pl/Tests_2007/Markdown Documentation - Basics.html
index d5bdbb2..342f0c1 100644
--- a/MarkdownTest/Tests_2007/Markdown Documentation - Basics.html
+++ b/tests/pl/Tests_2007/Markdown Documentation - Basics.html
@@ -29,7 +29,7 @@ can <a href="/projects/markdown/basics.text">see the source for it by adding '.t
<p>A paragraph is simply one or more consecutive lines of text, separated
by one or more blank lines. (A blank line is any line that looks like a
blank line -- a line containing nothing spaces or tabs is considered
-blank.) Normal paragraphs should not be intended with spaces or tabs.</p>
+blank.) Normal paragraphs should not be indented with spaces or tabs.</p>
<p>Markdown offers two styles of headers: <em>Setext</em> and <em>atx</em>.
Setext-style headers for <code>&lt;h1&gt;</code> and <code>&lt;h2&gt;</code> are created by
diff --git a/MarkdownTest/Tests_2007/Markdown Documentation - Basics.text b/tests/pl/Tests_2007/Markdown Documentation - Basics.text
index 486055c..2abe24a 100644
--- a/MarkdownTest/Tests_2007/Markdown Documentation - Basics.text
+++ b/tests/pl/Tests_2007/Markdown Documentation - Basics.text
@@ -37,7 +37,7 @@ can [see the source for it by adding '.text' to the URL] [src].
A paragraph is simply one or more consecutive lines of text, separated
by one or more blank lines. (A blank line is any line that looks like a
blank line -- a line containing nothing spaces or tabs is considered
-blank.) Normal paragraphs should not be intended with spaces or tabs.
+blank.) Normal paragraphs should not be indented with spaces or tabs.
Markdown offers two styles of headers: *Setext* and *atx*.
Setext-style headers for `<h1>` and `<h2>` are created by
diff --git a/MarkdownTest/Tests_2007/Markdown Documentation - Syntax.html b/tests/pl/Tests_2007/Markdown Documentation - Syntax.html
index 5c01306..7847793 100644
--- a/MarkdownTest/Tests_2007/Markdown Documentation - Syntax.html
+++ b/tests/pl/Tests_2007/Markdown Documentation - Syntax.html
@@ -186,7 +186,7 @@ and <code>&amp;</code> in your example code needs to be escaped.)</p>
<p>A paragraph is simply one or more consecutive lines of text, separated
by one or more blank lines. (A blank line is any line that looks like a
blank line -- a line containing nothing but spaces or tabs is considered
-blank.) Normal paragraphs should not be intended with spaces or tabs.</p>
+blank.) Normal paragraphs should not be indented with spaces or tabs.</p>
<p>The implication of the "one or more consecutive lines of text" rule is
that Markdown supports "hard-wrapped" text paragraphs. This differs
@@ -414,7 +414,7 @@ items in <code>&lt;p&gt;</code> tags in the HTML output. For example, this input
</code></pre>
<p>List items may consist of multiple paragraphs. Each subsequent
-paragraph in a list item must be intended by either 4 spaces
+paragraph in a list item must be indented by either 4 spaces
or one tab:</p>
<pre><code>1. This is a list item with two paragraphs. Lorem ipsum dolor
diff --git a/MarkdownTest/Tests_2007/Markdown Documentation - Syntax.text b/tests/pl/Tests_2007/Markdown Documentation - Syntax.text
index 57360a1..f175fa9 100644
--- a/MarkdownTest/Tests_2007/Markdown Documentation - Syntax.text
+++ b/tests/pl/Tests_2007/Markdown Documentation - Syntax.text
@@ -186,7 +186,7 @@ and `&` in your example code needs to be escaped.)
A paragraph is simply one or more consecutive lines of text, separated
by one or more blank lines. (A blank line is any line that looks like a
blank line -- a line containing nothing but spaces or tabs is considered
-blank.) Normal paragraphs should not be intended with spaces or tabs.
+blank.) Normal paragraphs should not be indented with spaces or tabs.
The implication of the "one or more consecutive lines of text" rule is
that Markdown supports "hard-wrapped" text paragraphs. This differs
@@ -401,7 +401,7 @@ will turn into:
</ul>
List items may consist of multiple paragraphs. Each subsequent
-paragraph in a list item must be intended by either 4 spaces
+paragraph in a list item must be indented by either 4 spaces
or one tab:
1. This is a list item with two paragraphs. Lorem ipsum dolor
diff --git a/MarkdownTest/Tests_2007/Nested blockquotes.html b/tests/pl/Tests_2007/Nested blockquotes.html
index d8ec7f8..d8ec7f8 100644
--- a/MarkdownTest/Tests_2007/Nested blockquotes.html
+++ b/tests/pl/Tests_2007/Nested blockquotes.html
diff --git a/MarkdownTest/Tests_2007/Nested blockquotes.text b/tests/pl/Tests_2007/Nested blockquotes.text
index ed3c624..ed3c624 100644
--- a/MarkdownTest/Tests_2007/Nested blockquotes.text
+++ b/tests/pl/Tests_2007/Nested blockquotes.text
diff --git a/MarkdownTest/Tests_2007/Ordered and unordered lists.html b/tests/pl/Tests_2007/Ordered and unordered lists.html
index ba71eab..ba71eab 100644
--- a/MarkdownTest/Tests_2007/Ordered and unordered lists.html
+++ b/tests/pl/Tests_2007/Ordered and unordered lists.html
diff --git a/MarkdownTest/Tests_2007/Ordered and unordered lists.text b/tests/pl/Tests_2007/Ordered and unordered lists.text
index 7f3b497..7f3b497 100644
--- a/MarkdownTest/Tests_2007/Ordered and unordered lists.text
+++ b/tests/pl/Tests_2007/Ordered and unordered lists.text
diff --git a/MarkdownTest/Tests_2007/Strong and em together.html b/tests/pl/Tests_2007/Strong and em together.html
index 71ec78c..71ec78c 100644
--- a/MarkdownTest/Tests_2007/Strong and em together.html
+++ b/tests/pl/Tests_2007/Strong and em together.html
diff --git a/MarkdownTest/Tests_2007/Strong and em together.text b/tests/pl/Tests_2007/Strong and em together.text
index 95ee690..95ee690 100644
--- a/MarkdownTest/Tests_2007/Strong and em together.text
+++ b/tests/pl/Tests_2007/Strong and em together.text
diff --git a/MarkdownTest/Tests_2007/Tabs.html b/tests/pl/Tests_2007/Tabs.html
index 3301ba8..3301ba8 100644
--- a/MarkdownTest/Tests_2007/Tabs.html
+++ b/tests/pl/Tests_2007/Tabs.html
diff --git a/MarkdownTest/Tests_2007/Tabs.text b/tests/pl/Tests_2007/Tabs.text
index 589d113..589d113 100644
--- a/MarkdownTest/Tests_2007/Tabs.text
+++ b/tests/pl/Tests_2007/Tabs.text
diff --git a/MarkdownTest/Tests_2007/Tidyness.html b/tests/pl/Tests_2007/Tidyness.html
index f2a8ce7..f2a8ce7 100644
--- a/MarkdownTest/Tests_2007/Tidyness.html
+++ b/tests/pl/Tests_2007/Tidyness.html
diff --git a/MarkdownTest/Tests_2007/Tidyness.text b/tests/pl/Tests_2007/Tidyness.text
index 5f18b8d..5f18b8d 100644
--- a/MarkdownTest/Tests_2007/Tidyness.text
+++ b/tests/pl/Tests_2007/Tidyness.text
diff --git a/tests/safe_mode/inline-html-advanced.html b/tests/safe_mode/inline-html-advanced.html
deleted file mode 100644
index e9dd2ec..0000000
--- a/tests/safe_mode/inline-html-advanced.html
+++ /dev/null
@@ -1,11 +0,0 @@
-<p>Simple block on one line:</p>
-<p>&lt;div&gt;foo&lt;/div&gt;</p>
-<p>And nested without indentation:</p>
-<p>&lt;div&gt;
-&lt;div&gt;
-&lt;div&gt;
-foo
-&lt;/div&gt;
-&lt;/div&gt;
-&lt;div&gt;bar&lt;/div&gt;
-&lt;/div&gt;</p> \ No newline at end of file
diff --git a/tests/safe_mode/inline-html-advanced.txt b/tests/safe_mode/inline-html-advanced.txt
deleted file mode 100644
index 9d71ddc..0000000
--- a/tests/safe_mode/inline-html-advanced.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-Simple block on one line:
-
-<div>foo</div>
-
-And nested without indentation:
-
-<div>
-<div>
-<div>
-foo
-</div>
-</div>
-<div>bar</div>
-</div>
diff --git a/tests/safe_mode/inline-html-comments.html b/tests/safe_mode/inline-html-comments.html
deleted file mode 100644
index 0f1e417..0000000
--- a/tests/safe_mode/inline-html-comments.html
+++ /dev/null
@@ -1,8 +0,0 @@
-<p>Paragraph one.</p>
-<p>&lt;!-- This is a simple comment --&gt;</p>
-<p>&lt;!--
- This is another comment.
---&gt;</p>
-<p>Paragraph two.</p>
-<p>&lt;!-- one comment block -- -- with two comments --&gt;</p>
-<p>The end.</p> \ No newline at end of file
diff --git a/tests/safe_mode/inline-html-comments.txt b/tests/safe_mode/inline-html-comments.txt
deleted file mode 100644
index 41d830d..0000000
--- a/tests/safe_mode/inline-html-comments.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-Paragraph one.
-
-<!-- This is a simple comment -->
-
-<!--
- This is another comment.
--->
-
-Paragraph two.
-
-<!-- one comment block -- -- with two comments -->
-
-The end.
diff --git a/tests/safe_mode/inline-html-simple.html b/tests/safe_mode/inline-html-simple.html
deleted file mode 100644
index ad19a77..0000000
--- a/tests/safe_mode/inline-html-simple.html
+++ /dev/null
@@ -1,45 +0,0 @@
-<p>Here's a simple block:</p>
-<p>&lt;div&gt;
- foo
-&lt;/div&gt;</p>
-<p>This should be a code block, though:</p>
-<pre><code>&lt;div&gt;
- foo
-&lt;/div&gt;
-</code></pre>
-<p>As should this:</p>
-<pre><code>&lt;div&gt;foo&lt;/div&gt;
-</code></pre>
-<p>Now, nested:</p>
-<p>&lt;div&gt;
- &lt;div&gt;
- &lt;div&gt;
- foo
- &lt;/div&gt;
- &lt;/div&gt;
-&lt;/div&gt;</p>
-<p>This should just be an HTML comment:</p>
-<p>&lt;!-- Comment --&gt;</p>
-<p>Multiline:</p>
-<p>&lt;!--
-Blah
-Blah
---&gt;</p>
-<p>Code block:</p>
-<pre><code>&lt;!-- Comment --&gt;
-</code></pre>
-<p>Just plain comment, with trailing spaces on the line:</p>
-<p>&lt;!-- foo --&gt;</p>
-<p>Code:</p>
-<pre><code>&lt;hr /&gt;
-</code></pre>
-<p>Hr's:</p>
-<p>&lt;hr&gt;</p>
-<p>&lt;hr/&gt;</p>
-<p>&lt;hr /&gt;</p>
-<p>&lt;hr&gt;</p>
-<p>&lt;hr/&gt;</p>
-<p>&lt;hr /&gt;</p>
-<p>&lt;hr class=&quot;foo&quot; id=&quot;bar&quot; /&gt;</p>
-<p>&lt;hr class=&quot;foo&quot; id=&quot;bar&quot;/&gt;</p>
-<p>&lt;hr class=&quot;foo&quot; id=&quot;bar&quot; &gt;</p> \ No newline at end of file
diff --git a/tests/safe_mode/inline-html-simple.txt b/tests/safe_mode/inline-html-simple.txt
deleted file mode 100644
index 14aa2dc..0000000
--- a/tests/safe_mode/inline-html-simple.txt
+++ /dev/null
@@ -1,69 +0,0 @@
-Here's a simple block:
-
-<div>
- foo
-</div>
-
-This should be a code block, though:
-
- <div>
- foo
- </div>
-
-As should this:
-
- <div>foo</div>
-
-Now, nested:
-
-<div>
- <div>
- <div>
- foo
- </div>
- </div>
-</div>
-
-This should just be an HTML comment:
-
-<!-- Comment -->
-
-Multiline:
-
-<!--
-Blah
-Blah
--->
-
-Code block:
-
- <!-- Comment -->
-
-Just plain comment, with trailing spaces on the line:
-
-<!-- foo -->
-
-Code:
-
- <hr />
-
-Hr's:
-
-<hr>
-
-<hr/>
-
-<hr />
-
-<hr>
-
-<hr/>
-
-<hr />
-
-<hr class="foo" id="bar" />
-
-<hr class="foo" id="bar"/>
-
-<hr class="foo" id="bar" >
-
diff --git a/tests/safe_mode/script_tags.html b/tests/safe_mode/script_tags.html
deleted file mode 100644
index df63ffc..0000000
--- a/tests/safe_mode/script_tags.html
+++ /dev/null
@@ -1,28 +0,0 @@
-<p>This should be stripped/escaped in safe_mode.</p>
-<p>&lt;script&gt;
-alert(&quot;Hello world!&quot;)
-&lt;/script&gt;</p>
-<p>With blank lines.</p>
-<p>&lt;script&gt;
-
-alert(&quot;Hello world!&quot;)
-
-&lt;/script&gt;</p>
-<p>Now with some weirdness</p>
-<p><code>&lt;script &lt;!--
-alert("Hello world!")
-&lt;/script &lt;&gt;</code> `</p>
-<p>Try another way.</p>
-<p>&lt;script &lt;!--
-alert(&quot;Hello world!&quot;)
-&lt;/script &lt;&gt;
-
-This time with blank lines.
-
-&lt;script &lt;!--
-
-alert(&quot;Hello world!&quot;)
-
-&lt;/script &lt;&gt;
-
-</p> \ No newline at end of file
diff --git a/tests/safe_mode/script_tags.txt b/tests/safe_mode/script_tags.txt
deleted file mode 100644
index 44041c2..0000000
--- a/tests/safe_mode/script_tags.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-This should be stripped/escaped in safe_mode.
-
-<script>
-alert("Hello world!")
-</script>
-
-With blank lines.
-
-<script>
-
-alert("Hello world!")
-
-</script>
-
-Now with some weirdness
-
-``<script <!--
-alert("Hello world!")
-</script <>`` `
-
-Try another way.
-
-<script <!--
-alert("Hello world!")
-</script <>
-
-This time with blank lines.
-
-<script <!--
-
-alert("Hello world!")
-
-</script <>
diff --git a/tests/safe_mode/unsafe_urls.html b/tests/safe_mode/unsafe_urls.html
deleted file mode 100644
index e617f35..0000000
--- a/tests/safe_mode/unsafe_urls.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<p>These links should be unsafe and not allowed in safe_mode</p>
-<p><a href="">link</a>
-<a href="">link</a>
-<a href="">link</a>
-<a href="">link</a>
-<a href="">link</a>
-<a href="">link</a>
-<a href="">link</a>
-<a href="">link</a>
-<a href="">link</a>
-<a href="">link</a>
-<a href="">link</a></p>
-<p><img alt="img" src="" />
-<a href="">ref</a>
-<img alt="imgref" src="" /></p>
-<p>These should work regardless:</p>
-<p><a href="relative/url.html">relative</a>
-<a href="mailto:foo@bar.com">email</a>
-<a href="news:some.news.group.com">news scheme</a>
-<a href="http://example.com">http link</a></p> \ No newline at end of file
diff --git a/tests/safe_mode/unsafe_urls.txt b/tests/safe_mode/unsafe_urls.txt
deleted file mode 100644
index 7bfd81d..0000000
--- a/tests/safe_mode/unsafe_urls.txt
+++ /dev/null
@@ -1,27 +0,0 @@
-These links should be unsafe and not allowed in safe_mode
-
-[link](javascript:alert%28'Hello%20world!'%29)
-[link](vbscript:msgbox%28%22Hello%20world!%22%29)
-[link](livescript:alert%28'Hello%20world!'%29)
-[link](mocha:[code])
-[link](jAvAsCrIpT:alert%28'Hello%20world!'%29)
-[link](ja&#32;vas&#32;cr&#32;ipt:alert%28'Hello%20world!'%29)
-[link](ja&#00032;vas&#32;cr&#32;ipt:alert%28'Hello%20world!'%29)
-[link](ja&#x00020;vas&#32;cr&#32;ipt:alert%28'Hello%20world!'%29)
-[link](ja%09&#x20;%0Avas&#32;cr&#x0a;ipt:alert%28'Hello%20world!'%29)
-[link](ja%20vas%20cr%20ipt:alert%28'Hello%20world!'%29)
-[link](live%20script:alert%28'Hello%20world!'%29)
-
-![img](javascript:alert%29'XSS'%29)
-[ref][]
-![imgref][]
-
-[ref]: javascript:alert%29'XSS'%29
-[imgref]: javascript:alert%29'XSS'%29
-
-These should work regardless:
-
-[relative](relative/url.html)
-[email](mailto:foo@bar.com)
-[news scheme](news:some.news.group.com)
-[http link](http://example.com)
diff --git a/tests/test_apis.py b/tests/test_apis.py
new file mode 100644
index 0000000..1a38be6
--- /dev/null
+++ b/tests/test_apis.py
@@ -0,0 +1,957 @@
+"""
+Python Markdown
+
+A Python implementation of John Gruber's Markdown.
+
+Documentation: https://python-markdown.github.io/
+GitHub: https://github.com/Python-Markdown/markdown/
+PyPI: https://pypi.org/project/Markdown/
+
+Started by Manfred Stienstra (http://www.dwerg.net/).
+Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
+Currently maintained by Waylan Limberg (https://github.com/waylan),
+Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
+
+Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see LICENSE.md for details).
+
+Python-Markdown Regression Tests
+================================
+
+Tests of the various APIs with the python markdown lib.
+"""
+
+import unittest
+import sys
+import os
+import markdown
+import warnings
+from markdown.__main__ import parse_options
+from logging import DEBUG, WARNING, CRITICAL
+import yaml
+import tempfile
+from io import BytesIO
+import xml.etree.ElementTree as etree
+from xml.etree.ElementTree import ProcessingInstruction
+
+
+class TestMarkdownBasics(unittest.TestCase):
+ """ Tests basics of the Markdown class. """
+
+ def setUp(self):
+ """ Create instance of Markdown. """
+ self.md = markdown.Markdown()
+
+ def testBlankInput(self):
+ """ Test blank input. """
+ self.assertEqual(self.md.convert(''), '')
+
+ def testWhitespaceOnly(self):
+ """ Test input of only whitespace. """
+ self.assertEqual(self.md.convert(' '), '')
+
+ def testSimpleInput(self):
+ """ Test simple input. """
+ self.assertEqual(self.md.convert('foo'), '<p>foo</p>')
+
+ def testInstanceExtension(self):
+ """ Test Extension loading with a class instance. """
+ from markdown.extensions.footnotes import FootnoteExtension
+ markdown.Markdown(extensions=[FootnoteExtension()])
+
+ def testEntryPointExtension(self):
+ """ Test Extension loading with an entry point. """
+ markdown.Markdown(extensions=['footnotes'])
+
+ def testDotNotationExtension(self):
+ """ Test Extension loading with Name (`path.to.module`). """
+ markdown.Markdown(extensions=['markdown.extensions.footnotes'])
+
+ def testDotNotationExtensionWithClass(self):
+ """ Test Extension loading with class name (`path.to.module:Class`). """
+ markdown.Markdown(extensions=['markdown.extensions.footnotes:FootnoteExtension'])
+
+
+class TestConvertFile(unittest.TestCase):
+ """ Tests of ConvertFile. """
+
+ def setUp(self):
+ self.saved = sys.stdin, sys.stdout
+ sys.stdin = BytesIO(bytes('foo', encoding='utf-8'))
+ sys.stdout = BytesIO()
+
+ def tearDown(self):
+ sys.stdin, sys.stdout = self.saved
+
+ def getTempFiles(self, src):
+ """ Return the file names for two temp files. """
+ infd, infile = tempfile.mkstemp(suffix='.txt')
+ with os.fdopen(infd, 'w') as fp:
+ fp.write(src)
+ outfd, outfile = tempfile.mkstemp(suffix='.html')
+ return infile, outfile, outfd
+
+ def testFileNames(self):
+ infile, outfile, outfd = self.getTempFiles('foo')
+ markdown.markdownFromFile(input=infile, output=outfile)
+ with os.fdopen(outfd, 'r') as fp:
+ output = fp.read()
+ self.assertEqual(output, '<p>foo</p>')
+
+ def testFileObjects(self):
+ infile = BytesIO(bytes('foo', encoding='utf-8'))
+ outfile = BytesIO()
+ markdown.markdownFromFile(input=infile, output=outfile)
+ outfile.seek(0)
+ self.assertEqual(outfile.read().decode('utf-8'), '<p>foo</p>')
+
+ def testStdinStdout(self):
+ markdown.markdownFromFile()
+ sys.stdout.seek(0)
+ self.assertEqual(sys.stdout.read().decode('utf-8'), '<p>foo</p>')
+
+
+class TestBlockParser(unittest.TestCase):
+ """ Tests of the BlockParser class. """
+
+ def setUp(self):
+ """ Create instance of BlockParser. """
+ self.parser = markdown.Markdown().parser
+
+ def testParseChunk(self):
+ """ Test BlockParser.parseChunk. """
+ root = etree.Element("div")
+ text = 'foo'
+ self.parser.parseChunk(root, text)
+ self.assertEqual(
+ markdown.serializers.to_xhtml_string(root),
+ "<div><p>foo</p></div>"
+ )
+
+ def testParseDocument(self):
+ """ Test BlockParser.parseDocument. """
+ lines = ['#foo', '', 'bar', '', ' baz']
+ tree = self.parser.parseDocument(lines)
+ self.assertIsInstance(tree, etree.ElementTree)
+ self.assertIs(etree.iselement(tree.getroot()), True)
+ self.assertEqual(
+ markdown.serializers.to_xhtml_string(tree.getroot()),
+ "<div><h1>foo</h1><p>bar</p><pre><code>baz\n</code></pre></div>"
+ )
+
+
+class TestBlockParserState(unittest.TestCase):
+ """ Tests of the State class for BlockParser. """
+
+ def setUp(self):
+ self.state = markdown.blockparser.State()
+
+ def testBlankState(self):
+ """ Test State when empty. """
+ self.assertEqual(self.state, [])
+
+ def testSetSate(self):
+ """ Test State.set(). """
+ self.state.set('a_state')
+ self.assertEqual(self.state, ['a_state'])
+ self.state.set('state2')
+ self.assertEqual(self.state, ['a_state', 'state2'])
+
+ def testIsSate(self):
+ """ Test State.isstate(). """
+ self.assertEqual(self.state.isstate('anything'), False)
+ self.state.set('a_state')
+ self.assertEqual(self.state.isstate('a_state'), True)
+ self.state.set('state2')
+ self.assertEqual(self.state.isstate('state2'), True)
+ self.assertEqual(self.state.isstate('a_state'), False)
+ self.assertEqual(self.state.isstate('missing'), False)
+
+ def testReset(self):
+ """ Test State.reset(). """
+ self.state.set('a_state')
+ self.state.reset()
+ self.assertEqual(self.state, [])
+ self.state.set('state1')
+ self.state.set('state2')
+ self.state.reset()
+ self.assertEqual(self.state, ['state1'])
+
+
+class TestHtmlStash(unittest.TestCase):
+ """ Test Markdown's HtmlStash. """
+
+ def setUp(self):
+ self.stash = markdown.util.HtmlStash()
+ self.placeholder = self.stash.store('foo')
+
+ def testSimpleStore(self):
+ """ Test HtmlStash.store. """
+ self.assertEqual(self.placeholder, self.stash.get_placeholder(0))
+ self.assertEqual(self.stash.html_counter, 1)
+ self.assertEqual(self.stash.rawHtmlBlocks, ['foo'])
+
+ def testStoreMore(self):
+ """ Test HtmlStash.store with additional blocks. """
+ placeholder = self.stash.store('bar')
+ self.assertEqual(placeholder, self.stash.get_placeholder(1))
+ self.assertEqual(self.stash.html_counter, 2)
+ self.assertEqual(
+ self.stash.rawHtmlBlocks,
+ ['foo', 'bar']
+ )
+
+ def testReset(self):
+ """ Test HtmlStash.reset. """
+ self.stash.reset()
+ self.assertEqual(self.stash.html_counter, 0)
+ self.assertEqual(self.stash.rawHtmlBlocks, [])
+
+
+class Item:
+ """ A dummy Registry item object for testing. """
+ def __init__(self, data):
+ self.data = data
+
+ def __repr__(self):
+ return repr(self.data)
+
+ def __eq__(self, other):
+ return self.data == other
+
+
+class RegistryTests(unittest.TestCase):
+ """ Test the processor registry. """
+
+ def testCreateRegistry(self):
+ r = markdown.util.Registry()
+ r.register(Item('a'), 'a', 20)
+ self.assertEqual(len(r), 1)
+ self.assertIsInstance(r, markdown.util.Registry)
+
+ def testRegisterWithoutPriority(self):
+ r = markdown.util.Registry()
+ with self.assertRaises(TypeError):
+ r.register(Item('a'))
+
+ def testSortRegistry(self):
+ r = markdown.util.Registry()
+ r.register(Item('a'), 'a', 20)
+ r.register(Item('b'), 'b', 21)
+ r.register(Item('c'), 'c', 20.5)
+ self.assertEqual(len(r), 3)
+ self.assertEqual(list(r), ['b', 'c', 'a'])
+
+ def testIsSorted(self):
+ r = markdown.util.Registry()
+ self.assertIs(r._is_sorted, False)
+ r.register(Item('a'), 'a', 20)
+ list(r)
+ self.assertIs(r._is_sorted, True)
+ r.register(Item('b'), 'b', 21)
+ self.assertIs(r._is_sorted, False)
+ r['a']
+ self.assertIs(r._is_sorted, True)
+ r._is_sorted = False
+ r.get_index_for_name('a')
+ self.assertIs(r._is_sorted, True)
+ r._is_sorted = False
+ repr(r)
+ self.assertIs(r._is_sorted, True)
+
+ def testDeregister(self):
+ r = markdown.util.Registry()
+ r.register(Item('a'), 'a', 20)
+ r.register(Item('b'), 'b', 30)
+ r.register(Item('c'), 'c', 40)
+ self.assertEqual(len(r), 3)
+ r.deregister('b')
+ self.assertEqual(len(r), 2)
+ r.deregister('c', strict=False)
+ self.assertEqual(len(r), 1)
+ # deregister non-existent item with strict=False
+ r.deregister('d', strict=False)
+ self.assertEqual(len(r), 1)
+ with self.assertRaises(ValueError):
+ # deregister non-existent item with strict=True
+ r.deregister('e')
+ self.assertEqual(list(r), ['a'])
+
+ def testRegistryContains(self):
+ r = markdown.util.Registry()
+ item = Item('a')
+ r.register(item, 'a', 20)
+ self.assertIs('a' in r, True)
+ self.assertIn(item, r)
+ self.assertNotIn('b', r)
+
+ def testRegistryIter(self):
+ r = markdown.util.Registry()
+ r.register(Item('a'), 'a', 20)
+ r.register(Item('b'), 'b', 30)
+ self.assertEqual(list(r), ['b', 'a'])
+
+ def testRegistryGetItemByIndex(self):
+ r = markdown.util.Registry()
+ r.register(Item('a'), 'a', 20)
+ r.register(Item('b'), 'b', 30)
+ self.assertEqual(r[0], 'b')
+ self.assertEqual(r[1], 'a')
+ with self.assertRaises(IndexError):
+ r[3]
+
+ def testRegistryGetItemByItem(self):
+ r = markdown.util.Registry()
+ r.register(Item('a'), 'a', 20)
+ r.register(Item('b'), 'b', 30)
+ self.assertEqual(r['a'], 'a')
+ self.assertEqual(r['b'], 'b')
+ with self.assertRaises(KeyError):
+ r['c']
+
+ def testRegistrySetItem(self):
+ r = markdown.util.Registry()
+ with self.assertRaises(TypeError):
+ r[0] = 'a'
+ with self.assertRaises(TypeError):
+ r['a'] = 'a'
+
+ def testRegistryDelItem(self):
+ r = markdown.util.Registry()
+ r.register(Item('a'), 'a', 20)
+ with self.assertRaises(TypeError):
+ del r[0]
+ with self.assertRaises(TypeError):
+ del r['a']
+
+ def testRegistrySlice(self):
+ r = markdown.util.Registry()
+ r.register(Item('a'), 'a', 20)
+ r.register(Item('b'), 'b', 30)
+ r.register(Item('c'), 'c', 40)
+ slc = r[1:]
+ self.assertEqual(len(slc), 2)
+ self.assertIsInstance(slc, markdown.util.Registry)
+ self.assertEqual(list(slc), ['b', 'a'])
+
+ def testGetIndexForName(self):
+ r = markdown.util.Registry()
+ r.register(Item('a'), 'a', 20)
+ r.register(Item('b'), 'b', 30)
+ self.assertEqual(r.get_index_for_name('a'), 1)
+ self.assertEqual(r.get_index_for_name('b'), 0)
+ with self.assertRaises(ValueError):
+ r.get_index_for_name('c')
+
+ def testRegisterDupplicate(self):
+ r = markdown.util.Registry()
+ r.register(Item('a'), 'a', 20)
+ r.register(Item('b1'), 'b', 10)
+ self.assertEqual(list(r), ['a', 'b1'])
+ self.assertEqual(len(r), 2)
+ r.register(Item('b2'), 'b', 30)
+ self.assertEqual(len(r), 2)
+ self.assertEqual(list(r), ['b2', 'a'])
+
+
+class TestErrors(unittest.TestCase):
+ """ Test Error Reporting. """
+
+ def setUp(self):
+ # Set warnings to be raised as errors
+ warnings.simplefilter('error')
+
+ def tearDown(self):
+ # Reset warning behavior back to default
+ warnings.simplefilter('default')
+
+ def testBadOutputFormat(self):
+ """ Test failure on bad output_format. """
+ self.assertRaises(KeyError, markdown.Markdown, output_format='invalid')
+
+ def testLoadExtensionFailure(self):
+ """ Test failure of an extension to load. """
+ self.assertRaises(
+ ImportError,
+ markdown.Markdown, extensions=['non_existant_ext']
+ )
+
+ def testLoadBadExtension(self):
+ """ Test loading of an Extension with no makeExtension function. """
+ self.assertRaises(AttributeError, markdown.Markdown, extensions=['markdown.util'])
+
+ def testNonExtension(self):
+ """ Test loading a non Extension object as an extension. """
+ self.assertRaises(TypeError, markdown.Markdown, extensions=[object])
+
+ def testDotNotationExtensionWithBadClass(self):
+ """ Test Extension loading with non-existent class name (`path.to.module:Class`). """
+ self.assertRaises(
+ AttributeError,
+ markdown.Markdown,
+ extensions=['markdown.extensions.footnotes:MissingExtension']
+ )
+
+ def testBaseExtention(self):
+ """ Test that the base Extension class will raise NotImplemented. """
+ self.assertRaises(
+ NotImplementedError,
+ markdown.Markdown, extensions=[markdown.extensions.Extension()]
+ )
+
+
+class testETreeComments(unittest.TestCase):
+ """
+ Test that ElementTree Comments work.
+
+ These tests should only be a concern when using cElementTree with third
+ party serializers (including markdown's (x)html serializer). While markdown
+ doesn't use ElementTree.Comment itself, we should certainly support any
+ third party extensions which may. Therefore, these tests are included to
+ ensure such support is maintained.
+ """
+
+ def setUp(self):
+ # Create comment node
+ self.comment = etree.Comment('foo')
+
+ def testCommentIsComment(self):
+ """ Test that an ElementTree Comment passes the `is Comment` test. """
+ self.assertIs(self.comment.tag, etree.Comment)
+
+ def testCommentIsBlockLevel(self):
+ """ Test that an ElementTree Comment is recognized as BlockLevel. """
+ md = markdown.Markdown()
+ self.assertIs(md.is_block_level(self.comment.tag), False)
+
+ def testCommentSerialization(self):
+ """ Test that an ElementTree Comment serializes properly. """
+ self.assertEqual(
+ markdown.serializers.to_html_string(self.comment),
+ '<!--foo-->'
+ )
+
+ def testCommentPrettify(self):
+ """ Test that an ElementTree Comment is prettified properly. """
+ pretty = markdown.treeprocessors.PrettifyTreeprocessor(markdown.Markdown())
+ pretty.run(self.comment)
+ self.assertEqual(
+ markdown.serializers.to_html_string(self.comment),
+ '<!--foo-->\n'
+ )
+
+
+class testElementTailTests(unittest.TestCase):
+ """ Element Tail Tests """
+ def setUp(self):
+ self.pretty = markdown.treeprocessors.PrettifyTreeprocessor(markdown.Markdown())
+
+ def testBrTailNoNewline(self):
+ """ Test that last <br> in tree has a new line tail """
+ root = etree.Element('root')
+ br = etree.SubElement(root, 'br')
+ self.assertEqual(br.tail, None)
+ self.pretty.run(root)
+ self.assertEqual(br.tail, "\n")
+
+
+class testElementPreCodeTests(unittest.TestCase):
+ """ Element PreCode Tests """
+ def setUp(self):
+ md = markdown.Markdown()
+ self.pretty = markdown.treeprocessors.PrettifyTreeprocessor(md)
+
+ def prettify(self, xml):
+ root = etree.fromstring(xml)
+ self.pretty.run(root)
+ return etree.tostring(root, encoding="unicode", short_empty_elements=False)
+
+ def testPreCodeEmpty(self):
+ xml = "<pre><code></code></pre>"
+ expected = "<pre><code></code></pre>\n"
+ self.assertEqual(expected, self.prettify(xml))
+
+ def testPreCodeWithChildren(self):
+ xml = "<pre><code> <span /></code></pre>"
+ expected = "<pre><code> <span></span></code></pre>\n"
+ self.assertEqual(expected, self.prettify(xml))
+
+ def testPreCodeWithSpaceOnly(self):
+ xml = "<pre><code> </code></pre>"
+ expected = "<pre><code>\n</code></pre>\n"
+ self.assertEqual(expected, self.prettify(xml))
+
+ def testPreCodeWithText(self):
+ xml = "<pre><code> hello</code></pre>"
+ expected = "<pre><code> hello\n</code></pre>\n"
+ self.assertEqual(expected, self.prettify(xml))
+
+ def testPreCodeWithTrailingSpace(self):
+ xml = "<pre><code> hello </code></pre>"
+ expected = "<pre><code> hello\n</code></pre>\n"
+ self.assertEqual(expected, self.prettify(xml))
+
+
+class testSerializers(unittest.TestCase):
+ """ Test the html and xhtml serializers. """
+
+ def testHtml(self):
+ """ Test HTML serialization. """
+ el = etree.Element('div')
+ el.set('id', 'foo<&">')
+ p = etree.SubElement(el, 'p')
+ p.text = 'foo <&escaped>'
+ p.set('hidden', 'hidden')
+ etree.SubElement(el, 'hr')
+ non_element = etree.SubElement(el, None)
+ non_element.text = 'non-element text'
+ script = etree.SubElement(non_element, 'script')
+ script.text = '<&"test\nescaping">'
+ el.tail = "tail text"
+ self.assertEqual(
+ markdown.serializers.to_html_string(el),
+ '<div id="foo&lt;&amp;&quot;&gt;">'
+ '<p hidden>foo &lt;&amp;escaped&gt;</p>'
+ '<hr>'
+ 'non-element text'
+ '<script><&"test\nescaping"></script>'
+ '</div>tail text'
+ )
+
+ def testXhtml(self):
+ """" Test XHTML serialization. """
+ el = etree.Element('div')
+ el.set('id', 'foo<&">')
+ p = etree.SubElement(el, 'p')
+ p.text = 'foo<&escaped>'
+ p.set('hidden', 'hidden')
+ etree.SubElement(el, 'hr')
+ non_element = etree.SubElement(el, None)
+ non_element.text = 'non-element text'
+ script = etree.SubElement(non_element, 'script')
+ script.text = '<&"test\nescaping">'
+ el.tail = "tail text"
+ self.assertEqual(
+ markdown.serializers.to_xhtml_string(el),
+ '<div id="foo&lt;&amp;&quot;&gt;">'
+ '<p hidden="hidden">foo&lt;&amp;escaped&gt;</p>'
+ '<hr />'
+ 'non-element text'
+ '<script><&"test\nescaping"></script>'
+ '</div>tail text'
+ )
+
+ def testMixedCaseTags(self):
+ """" Test preservation of tag case. """
+ el = etree.Element('MixedCase')
+ el.text = 'not valid '
+ em = etree.SubElement(el, 'EMPHASIS')
+ em.text = 'html'
+ etree.SubElement(el, 'HR')
+ self.assertEqual(
+ markdown.serializers.to_xhtml_string(el),
+ '<MixedCase>not valid <EMPHASIS>html</EMPHASIS><HR /></MixedCase>'
+ )
+
+ def testProsessingInstruction(self):
+ """ Test serialization of ProcessignInstruction. """
+ pi = ProcessingInstruction('foo', text='<&"test\nescaping">')
+ self.assertIs(pi.tag, ProcessingInstruction)
+ self.assertEqual(
+ markdown.serializers.to_xhtml_string(pi),
+ '<?foo &lt;&amp;"test\nescaping"&gt;?>'
+ )
+
+ def testQNameTag(self):
+ """ Test serialization of QName tag. """
+ div = etree.Element('div')
+ qname = etree.QName('http://www.w3.org/1998/Math/MathML', 'math')
+ math = etree.SubElement(div, qname)
+ math.set('display', 'block')
+ sem = etree.SubElement(math, 'semantics')
+ msup = etree.SubElement(sem, 'msup')
+ mi = etree.SubElement(msup, 'mi')
+ mi.text = 'x'
+ mn = etree.SubElement(msup, 'mn')
+ mn.text = '2'
+ ann = etree.SubElement(sem, 'annotations')
+ ann.text = 'x^2'
+ self.assertEqual(
+ markdown.serializers.to_xhtml_string(div),
+ '<div>'
+ '<math display="block" xmlns="http://www.w3.org/1998/Math/MathML">'
+ '<semantics>'
+ '<msup>'
+ '<mi>x</mi>'
+ '<mn>2</mn>'
+ '</msup>'
+ '<annotations>x^2</annotations>'
+ '</semantics>'
+ '</math>'
+ '</div>'
+ )
+
+ def testQNameAttribute(self):
+ """ Test serialization of QName attribute. """
+ div = etree.Element('div')
+ div.set(etree.QName('foo'), etree.QName('bar'))
+ self.assertEqual(
+ markdown.serializers.to_xhtml_string(div),
+ '<div foo="bar"></div>'
+ )
+
+ def testBadQNameTag(self):
+ """ Test serialization of QName with no tag. """
+ qname = etree.QName('http://www.w3.org/1998/Math/MathML')
+ el = etree.Element(qname)
+ self.assertRaises(ValueError, markdown.serializers.to_xhtml_string, el)
+
+ def testQNameEscaping(self):
+ """ Test QName escaping. """
+ qname = etree.QName('<&"test\nescaping">', 'div')
+ el = etree.Element(qname)
+ self.assertEqual(
+ markdown.serializers.to_xhtml_string(el),
+ '<div xmlns="&lt;&amp;&quot;test&#10;escaping&quot;&gt;"></div>'
+ )
+
+ def testQNamePreEscaping(self):
+ """ Test QName that is already partially escaped. """
+ qname = etree.QName('&lt;&amp;"test&#10;escaping"&gt;', 'div')
+ el = etree.Element(qname)
+ self.assertEqual(
+ markdown.serializers.to_xhtml_string(el),
+ '<div xmlns="&lt;&amp;&quot;test&#10;escaping&quot;&gt;"></div>'
+ )
+
+ def buildExtension(self):
+ """ Build an extension which registers fakeSerializer. """
+ def fakeSerializer(elem):
+ # Ignore input and return hardcoded output
+ return '<div><p>foo</p></div>'
+
+ class registerFakeSerializer(markdown.extensions.Extension):
+ def extendMarkdown(self, md):
+ md.output_formats['fake'] = fakeSerializer
+
+ return registerFakeSerializer()
+
+ def testRegisterSerializer(self):
+ self.assertEqual(
+ markdown.markdown(
+ 'baz', extensions=[self.buildExtension()], output_format='fake'
+ ),
+ '<p>foo</p>'
+ )
+
+ def testXHTMLOutput(self):
+ self.assertEqual(
+ markdown.markdown('foo \nbar', output_format='xhtml'),
+ '<p>foo<br />\nbar</p>'
+ )
+
+ def testHTMLOutput(self):
+ self.assertEqual(
+ markdown.markdown('foo \nbar', output_format='html'),
+ '<p>foo<br>\nbar</p>'
+ )
+
+
+class testAtomicString(unittest.TestCase):
+ """ Test that AtomicStrings are honored (not parsed). """
+
+ def setUp(self):
+ md = markdown.Markdown()
+ self.inlineprocessor = md.treeprocessors['inline']
+
+ def testString(self):
+ """ Test that a regular string is parsed. """
+ tree = etree.Element('div')
+ p = etree.SubElement(tree, 'p')
+ p.text = 'some *text*'
+ new = self.inlineprocessor.run(tree)
+ self.assertEqual(
+ markdown.serializers.to_html_string(new),
+ '<div><p>some <em>text</em></p></div>'
+ )
+
+ def testSimpleAtomicString(self):
+ """ Test that a simple AtomicString is not parsed. """
+ tree = etree.Element('div')
+ p = etree.SubElement(tree, 'p')
+ p.text = markdown.util.AtomicString('some *text*')
+ new = self.inlineprocessor.run(tree)
+ self.assertEqual(
+ markdown.serializers.to_html_string(new),
+ '<div><p>some *text*</p></div>'
+ )
+
+ def testNestedAtomicString(self):
+ """ Test that a nested AtomicString is not parsed. """
+ tree = etree.Element('div')
+ p = etree.SubElement(tree, 'p')
+ p.text = markdown.util.AtomicString('*some* ')
+ span1 = etree.SubElement(p, 'span')
+ span1.text = markdown.util.AtomicString('*more* ')
+ span2 = etree.SubElement(span1, 'span')
+ span2.text = markdown.util.AtomicString('*text* ')
+ span3 = etree.SubElement(span2, 'span')
+ span3.text = markdown.util.AtomicString('*here*')
+ span3.tail = markdown.util.AtomicString(' *to*')
+ span2.tail = markdown.util.AtomicString(' *test*')
+ span1.tail = markdown.util.AtomicString(' *with*')
+ new = self.inlineprocessor.run(tree)
+ self.assertEqual(
+ markdown.serializers.to_html_string(new),
+ '<div><p>*some* <span>*more* <span>*text* <span>*here*</span> '
+ '*to*</span> *test*</span> *with*</p></div>'
+ )
+
+
+class TestConfigParsing(unittest.TestCase):
+ def assertParses(self, value, result):
+ self.assertIs(markdown.util.parseBoolValue(value, False), result)
+
+ def testBooleansParsing(self):
+ self.assertParses(True, True)
+ self.assertParses('novalue', None)
+ self.assertParses('yES', True)
+ self.assertParses('FALSE', False)
+ self.assertParses(0., False)
+ self.assertParses('none', False)
+
+ def testPreserveNone(self):
+ self.assertIsNone(markdown.util.parseBoolValue('None', preserve_none=True))
+ self.assertIsNone(markdown.util.parseBoolValue(None, preserve_none=True))
+
+ def testInvalidBooleansParsing(self):
+ self.assertRaises(ValueError, markdown.util.parseBoolValue, 'novalue')
+
+
+class TestCliOptionParsing(unittest.TestCase):
+ """ Test parsing of Command Line Interface Options. """
+
+ def setUp(self):
+ self.default_options = {
+ 'input': None,
+ 'output': None,
+ 'encoding': None,
+ 'output_format': 'xhtml',
+ 'lazy_ol': True,
+ 'extensions': [],
+ 'extension_configs': {},
+ }
+ self.tempfile = ''
+
+ def tearDown(self):
+ if os.path.isfile(self.tempfile):
+ os.remove(self.tempfile)
+
+ def testNoOptions(self):
+ options, logging_level = parse_options([])
+ self.assertEqual(options, self.default_options)
+ self.assertEqual(logging_level, CRITICAL)
+
+ def testQuietOption(self):
+ options, logging_level = parse_options(['-q'])
+ self.assertGreater(logging_level, CRITICAL)
+
+ def testVerboseOption(self):
+ options, logging_level = parse_options(['-v'])
+ self.assertEqual(logging_level, WARNING)
+
+ def testNoisyOption(self):
+ options, logging_level = parse_options(['--noisy'])
+ self.assertEqual(logging_level, DEBUG)
+
+ def testInputFileOption(self):
+ options, logging_level = parse_options(['foo.txt'])
+ self.default_options['input'] = 'foo.txt'
+ self.assertEqual(options, self.default_options)
+
+ def testOutputFileOption(self):
+ options, logging_level = parse_options(['-f', 'foo.html'])
+ self.default_options['output'] = 'foo.html'
+ self.assertEqual(options, self.default_options)
+
+ def testInputAndOutputFileOptions(self):
+ options, logging_level = parse_options(['-f', 'foo.html', 'foo.txt'])
+ self.default_options['output'] = 'foo.html'
+ self.default_options['input'] = 'foo.txt'
+ self.assertEqual(options, self.default_options)
+
+ def testEncodingOption(self):
+ options, logging_level = parse_options(['-e', 'utf-8'])
+ self.default_options['encoding'] = 'utf-8'
+ self.assertEqual(options, self.default_options)
+
+ def testOutputFormatOption(self):
+ options, logging_level = parse_options(['-o', 'html'])
+ self.default_options['output_format'] = 'html'
+ self.assertEqual(options, self.default_options)
+
+ def testNoLazyOlOption(self):
+ options, logging_level = parse_options(['-n'])
+ self.default_options['lazy_ol'] = False
+ self.assertEqual(options, self.default_options)
+
+ def testExtensionOption(self):
+ options, logging_level = parse_options(['-x', 'markdown.extensions.footnotes'])
+ self.default_options['extensions'] = ['markdown.extensions.footnotes']
+ self.assertEqual(options, self.default_options)
+
+ def testMultipleExtensionOptions(self):
+ options, logging_level = parse_options([
+ '-x', 'markdown.extensions.footnotes',
+ '-x', 'markdown.extensions.smarty'
+ ])
+ self.default_options['extensions'] = [
+ 'markdown.extensions.footnotes',
+ 'markdown.extensions.smarty'
+ ]
+ self.assertEqual(options, self.default_options)
+
+ def create_config_file(self, config):
+ """ Helper to create temp config files. """
+ if not isinstance(config, str):
+ # convert to string
+ config = yaml.dump(config)
+ fd, self.tempfile = tempfile.mkstemp('.yml')
+ with os.fdopen(fd, 'w') as fp:
+ fp.write(config)
+
+ def testExtensionConfigOption(self):
+ config = {
+ 'markdown.extensions.wikilinks': {
+ 'base_url': 'http://example.com/',
+ 'end_url': '.html',
+ 'html_class': 'test',
+ },
+ 'markdown.extensions.footnotes:FootnotesExtension': {
+ 'PLACE_MARKER': '~~~footnotes~~~'
+ }
+ }
+ self.create_config_file(config)
+ options, logging_level = parse_options(['-c', self.tempfile])
+ self.default_options['extension_configs'] = config
+ self.assertEqual(options, self.default_options)
+
+ def textBoolExtensionConfigOption(self):
+ config = {
+ 'markdown.extensions.toc': {
+ 'title': 'Some Title',
+ 'anchorlink': True,
+ 'permalink': True
+ }
+ }
+ self.create_config_file(config)
+ options, logging_level = parse_options(['-c', self.tempfile])
+ self.default_options['extension_configs'] = config
+ self.assertEqual(options, self.default_options)
+
+ def testExtensionConfigOptionAsJSON(self):
+ config = {
+ 'markdown.extensions.wikilinks': {
+ 'base_url': 'http://example.com/',
+ 'end_url': '.html',
+ 'html_class': 'test',
+ },
+ 'markdown.extensions.footnotes:FootnotesExtension': {
+ 'PLACE_MARKER': '~~~footnotes~~~'
+ }
+ }
+ import json
+ self.create_config_file(json.dumps(config))
+ options, logging_level = parse_options(['-c', self.tempfile])
+ self.default_options['extension_configs'] = config
+ self.assertEqual(options, self.default_options)
+
+ def testExtensionConfigOptionMissingFile(self):
+ self.assertRaises(IOError, parse_options, ['-c', 'missing_file.yaml'])
+
+ def testExtensionConfigOptionBadFormat(self):
+ config = """
+[footnotes]
+PLACE_MARKER= ~~~footnotes~~~
+"""
+ self.create_config_file(config)
+ self.assertRaises(yaml.YAMLError, parse_options, ['-c', self.tempfile])
+
+
+class TestEscapeAppend(unittest.TestCase):
+ """ Tests escape character append. """
+
+ def testAppend(self):
+ """ Test that appended escapes are only in the current instance. """
+ md = markdown.Markdown()
+ md.ESCAPED_CHARS.append('|')
+ self.assertEqual('|' in md.ESCAPED_CHARS, True)
+ md2 = markdown.Markdown()
+ self.assertEqual('|' not in md2.ESCAPED_CHARS, True)
+
+
+class TestBlockAppend(unittest.TestCase):
+ """ Tests block kHTML append. """
+
+ def testBlockAppend(self):
+ """ Test that appended escapes are only in the current instance. """
+ md = markdown.Markdown()
+ md.block_level_elements.append('test')
+ self.assertEqual('test' in md.block_level_elements, True)
+ md2 = markdown.Markdown()
+ self.assertEqual('test' not in md2.block_level_elements, True)
+
+
+class TestAncestorExclusion(unittest.TestCase):
+ """ Tests exclusion of tags in ancestor list. """
+
+ class AncestorExample(markdown.inlinepatterns.SimpleTagInlineProcessor):
+ """ Ancestor Test. """
+
+ ANCESTOR_EXCLUDES = ('a',)
+
+ def handleMatch(self, m, data):
+ """ Handle match. """
+ el = etree.Element(self.tag)
+ el.text = m.group(2)
+ return el, m.start(0), m.end(0)
+
+ class AncestorExtension(markdown.Extension):
+
+ def __init__(self, *args, **kwargs):
+ """Initialize."""
+
+ self.config = {}
+
+ def extendMarkdown(self, md):
+ """Modify inline patterns."""
+
+ pattern = r'(\+)([^\+]+)\1'
+ md.inlinePatterns.register(TestAncestorExclusion.AncestorExample(pattern, 'strong'), 'ancestor-test', 0)
+
+ def setUp(self):
+ """Setup markdown object."""
+ self.md = markdown.Markdown(extensions=[TestAncestorExclusion.AncestorExtension()])
+
+ def test_ancestors(self):
+ """ Test that an extension can exclude parent tags. """
+ test = """
+Some +test+ and a [+link+](http://test.com)
+"""
+ result = """<p>Some <strong>test</strong> and a <a href="http://test.com">+link+</a></p>"""
+
+ self.md.reset()
+ self.assertEqual(self.md.convert(test), result)
+
+ def test_ancestors_tail(self):
+ """ Test that an extension can exclude parent tags when dealing with a tail. """
+ test = """
+[***+em+*+strong+**](http://test.com)
+"""
+ result = """<p><a href="http://test.com"><strong><em>+em+</em>+strong+</strong></a></p>"""
+
+ self.md.reset()
+ self.assertEqual(self.md.convert(test), result)
diff --git a/tests/test_extensions.py b/tests/test_extensions.py
new file mode 100644
index 0000000..b19d10a
--- /dev/null
+++ b/tests/test_extensions.py
@@ -0,0 +1,665 @@
+"""
+Python Markdown
+
+A Python implementation of John Gruber's Markdown.
+
+Documentation: https://python-markdown.github.io/
+GitHub: https://github.com/Python-Markdown/markdown/
+PyPI: https://pypi.org/project/Markdown/
+
+Started by Manfred Stienstra (http://www.dwerg.net/).
+Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
+Currently maintained by Waylan Limberg (https://github.com/waylan),
+Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
+
+Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see LICENSE.md for details).
+
+Python-Markdown Extension Regression Tests
+==========================================
+
+A collection of regression tests to confirm that the included extensions
+continue to work as advertised. This used to be accomplished by doctests.
+"""
+
+import unittest
+import markdown
+
+
+class TestCaseWithAssertStartsWith(unittest.TestCase):
+
+ def assertStartsWith(self, expectedPrefix, text, msg=None):
+ if not text.startswith(expectedPrefix):
+ if len(expectedPrefix) + 5 < len(text):
+ text = text[:len(expectedPrefix) + 5] + '...'
+ standardMsg = '{} not found at the start of {}'.format(repr(expectedPrefix),
+ repr(text))
+ self.fail(self._formatMessage(msg, standardMsg))
+
+
+class TestExtensionClass(unittest.TestCase):
+ """ Test markdown.extensions.Extension. """
+
+ def setUp(self):
+ class TestExtension(markdown.extensions.Extension):
+ config = {
+ 'foo': ['bar', 'Description of foo'],
+ 'bar': ['baz', 'Description of bar']
+ }
+
+ self.ext = TestExtension()
+ self.ExtKlass = TestExtension
+
+ def testGetConfig(self):
+ self.assertEqual(self.ext.getConfig('foo'), 'bar')
+
+ def testGetConfigDefault(self):
+ self.assertEqual(self.ext.getConfig('baz'), '')
+ self.assertEqual(self.ext.getConfig('baz', default='missing'), 'missing')
+
+ def testGetConfigs(self):
+ self.assertEqual(self.ext.getConfigs(), {'foo': 'bar', 'bar': 'baz'})
+
+ def testGetConfigInfo(self):
+ self.assertEqual(
+ dict(self.ext.getConfigInfo()),
+ dict([
+ ('foo', 'Description of foo'),
+ ('bar', 'Description of bar')
+ ])
+ )
+
+ def testSetConfig(self):
+ self.ext.setConfig('foo', 'baz')
+ self.assertEqual(self.ext.getConfigs(), {'foo': 'baz', 'bar': 'baz'})
+
+ def testSetConfigWithBadKey(self):
+ # self.ext.setConfig('bad', 'baz) ==> KeyError
+ self.assertRaises(KeyError, self.ext.setConfig, 'bad', 'baz')
+
+ def testConfigAsKwargsOnInit(self):
+ ext = self.ExtKlass(foo='baz', bar='blah')
+ self.assertEqual(ext.getConfigs(), {'foo': 'baz', 'bar': 'blah'})
+
+
+class TestAbbr(unittest.TestCase):
+ """ Test abbr extension. """
+
+ def setUp(self):
+ self.md = markdown.Markdown(extensions=['abbr'])
+
+ def testSimpleAbbr(self):
+ """ Test Abbreviations. """
+ text = 'Some text with an ABBR and a REF. Ignore REFERENCE and ref.' + \
+ '\n\n*[ABBR]: Abbreviation\n' + \
+ '*[REF]: Abbreviation Reference'
+ self.assertEqual(
+ self.md.convert(text),
+ '<p>Some text with an <abbr title="Abbreviation">ABBR</abbr> '
+ 'and a <abbr title="Abbreviation Reference">REF</abbr>. Ignore '
+ 'REFERENCE and ref.</p>'
+ )
+
+ def testNestedAbbr(self):
+ """ Test Nested Abbreviations. """
+ text = '[ABBR](/foo) and _ABBR_\n\n' + \
+ '*[ABBR]: Abbreviation'
+ self.assertEqual(
+ self.md.convert(text),
+ '<p><a href="/foo"><abbr title="Abbreviation">ABBR</abbr></a> '
+ 'and <em><abbr title="Abbreviation">ABBR</abbr></em></p>'
+ )
+
+
+class TestMetaData(unittest.TestCase):
+ """ Test MetaData extension. """
+
+ def setUp(self):
+ self.md = markdown.Markdown(extensions=['meta'])
+
+ def testBasicMetaData(self):
+ """ Test basic metadata. """
+
+ text = '''Title: A Test Doc.
+Author: Waylan Limberg
+ John Doe
+Blank_Data:
+
+The body. This is paragraph one.'''
+ self.assertEqual(
+ self.md.convert(text),
+ '<p>The body. This is paragraph one.</p>'
+ )
+ self.assertEqual(
+ self.md.Meta, {
+ 'author': ['Waylan Limberg', 'John Doe'],
+ 'blank_data': [''],
+ 'title': ['A Test Doc.']
+ }
+ )
+
+ def testYamlMetaData(self):
+ """ Test metadata specified as simple YAML. """
+
+ text = '''---
+Title: A Test Doc.
+Author: [Waylan Limberg, John Doe]
+Blank_Data:
+---
+
+The body. This is paragraph one.'''
+ self.assertEqual(
+ self.md.convert(text),
+ '<p>The body. This is paragraph one.</p>'
+ )
+ self.assertEqual(
+ self.md.Meta, {
+ 'author': ['[Waylan Limberg, John Doe]'],
+ 'blank_data': [''],
+ 'title': ['A Test Doc.']
+ }
+ )
+
+ def testMissingMetaData(self):
+ """ Test document without Meta Data. """
+
+ text = ' Some Code - not extra lines of meta data.'
+ self.assertEqual(
+ self.md.convert(text),
+ '<pre><code>Some Code - not extra lines of meta data.\n'
+ '</code></pre>'
+ )
+ self.assertEqual(self.md.Meta, {})
+
+ def testMetaDataWithoutNewline(self):
+ """ Test document with only metadata and no newline at end."""
+ text = 'title: No newline'
+ self.assertEqual(self.md.convert(text), '')
+ self.assertEqual(self.md.Meta, {'title': ['No newline']})
+
+ def testMetaDataReset(self):
+ """ Test that reset call remove Meta entirely """
+
+ text = '''Title: A Test Doc.
+Author: Waylan Limberg
+ John Doe
+Blank_Data:
+
+The body. This is paragraph one.'''
+ self.md.convert(text)
+
+ self.md.reset()
+ self.assertEqual(self.md.Meta, {})
+
+
+class TestWikiLinks(unittest.TestCase):
+ """ Test Wikilinks Extension. """
+
+ def setUp(self):
+ self.md = markdown.Markdown(extensions=['wikilinks'])
+ self.text = "Some text with a [[WikiLink]]."
+
+ def testBasicWikilinks(self):
+ """ Test [[wikilinks]]. """
+
+ self.assertEqual(
+ self.md.convert(self.text),
+ '<p>Some text with a '
+ '<a class="wikilink" href="/WikiLink/">WikiLink</a>.</p>'
+ )
+
+ def testWikilinkWhitespace(self):
+ """ Test whitespace in wikilinks. """
+ self.assertEqual(
+ self.md.convert('[[ foo bar_baz ]]'),
+ '<p><a class="wikilink" href="/foo_bar_baz/">foo bar_baz</a></p>'
+ )
+ self.assertEqual(
+ self.md.convert('foo [[ ]] bar'),
+ '<p>foo bar</p>'
+ )
+
+ def testSimpleSettings(self):
+ """ Test Simple Settings. """
+
+ self.assertEqual(markdown.markdown(
+ self.text, extensions=[
+ markdown.extensions.wikilinks.WikiLinkExtension(
+ base_url='/wiki/',
+ end_url='.html',
+ html_class='foo')
+ ]
+ ),
+ '<p>Some text with a '
+ '<a class="foo" href="/wiki/WikiLink.html">WikiLink</a>.</p>')
+
+ def testComplexSettings(self):
+ """ Test Complex Settings. """
+
+ md = markdown.Markdown(
+ extensions=['wikilinks'],
+ extension_configs={
+ 'wikilinks': [
+ ('base_url', 'http://example.com/'),
+ ('end_url', '.html'),
+ ('html_class', '')
+ ]
+ },
+ safe_mode=True
+ )
+ self.assertEqual(
+ md.convert(self.text),
+ '<p>Some text with a '
+ '<a href="http://example.com/WikiLink.html">WikiLink</a>.</p>'
+ )
+
+ def testWikilinksMetaData(self):
+ """ test MetaData with Wikilinks Extension. """
+
+ text = """wiki_base_url: http://example.com/
+wiki_end_url: .html
+wiki_html_class:
+
+Some text with a [[WikiLink]]."""
+ md = markdown.Markdown(extensions=['meta', 'wikilinks'])
+ self.assertEqual(
+ md.convert(text),
+ '<p>Some text with a '
+ '<a href="http://example.com/WikiLink.html">WikiLink</a>.</p>'
+ )
+
+ # MetaData should not carry over to next document:
+ self.assertEqual(
+ md.convert("No [[MetaData]] here."),
+ '<p>No <a class="wikilink" href="/MetaData/">MetaData</a> '
+ 'here.</p>'
+ )
+
+ def testURLCallback(self):
+ """ Test used of a custom URL builder. """
+
+ from markdown.extensions.wikilinks import WikiLinkExtension
+
+ def my_url_builder(label, base, end):
+ return '/bar/'
+
+ md = markdown.Markdown(extensions=[WikiLinkExtension(build_url=my_url_builder)])
+ self.assertEqual(
+ md.convert('[[foo]]'),
+ '<p><a class="wikilink" href="/bar/">foo</a></p>'
+ )
+
+
+class TestAdmonition(unittest.TestCase):
+ """ Test Admonition Extension. """
+
+ def setUp(self):
+ self.md = markdown.Markdown(extensions=['admonition'])
+
+ def testRE(self):
+ RE = self.md.parser.blockprocessors['admonition'].RE
+ tests = [
+ ('!!! note', ('note', None)),
+ ('!!! note "Please Note"', ('note', 'Please Note')),
+ ('!!! note ""', ('note', '')),
+ ]
+ for test, expected in tests:
+ self.assertEqual(RE.match(test).groups(), expected)
+
+
+class TestTOC(TestCaseWithAssertStartsWith):
+ """ Test TOC Extension. """
+
+ def setUp(self):
+ self.md = markdown.Markdown(extensions=['toc'])
+
+ def testMarker(self):
+ """ Test TOC with a Marker. """
+ text = '[TOC]\n\n# Header 1\n\n## Header 2'
+ self.assertEqual(
+ self.md.convert(text),
+ '<div class="toc">\n'
+ '<ul>\n' # noqa
+ '<li><a href="#header-1">Header 1</a>' # noqa
+ '<ul>\n' # noqa
+ '<li><a href="#header-2">Header 2</a></li>\n' # noqa
+ '</ul>\n' # noqa
+ '</li>\n' # noqa
+ '</ul>\n' # noqa
+ '</div>\n'
+ '<h1 id="header-1">Header 1</h1>\n'
+ '<h2 id="header-2">Header 2</h2>'
+ )
+
+ def testNoMarker(self):
+ """ Test TOC without a Marker. """
+ text = '# Header 1\n\n## Header 2'
+ self.assertEqual(
+ self.md.convert(text),
+ '<h1 id="header-1">Header 1</h1>\n'
+ '<h2 id="header-2">Header 2</h2>'
+ )
+ self.assertEqual(
+ self.md.toc,
+ '<div class="toc">\n'
+ '<ul>\n' # noqa
+ '<li><a href="#header-1">Header 1</a>' # noqa
+ '<ul>\n' # noqa
+ '<li><a href="#header-2">Header 2</a></li>\n' # noqa
+ '</ul>\n' # noqa
+ '</li>\n' # noqa
+ '</ul>\n' # noqa
+ '</div>\n'
+ )
+
+ def testAlternateMarker(self):
+ """ Test TOC with user defined marker. """
+ md = markdown.Markdown(
+ extensions=[markdown.extensions.toc.TocExtension(marker='{{marker}}')]
+ )
+ text = '{{marker}}\n\n# Header 1\n\n## Header 2'
+ self.assertEqual(
+ md.convert(text),
+ '<div class="toc">\n'
+ '<ul>\n' # noqa
+ '<li><a href="#header-1">Header 1</a>' # noqa
+ '<ul>\n' # noqa
+ '<li><a href="#header-2">Header 2</a></li>\n' # noqa
+ '</ul>\n' # noqa
+ '</li>\n' # noqa
+ '</ul>\n' # noqa
+ '</div>\n'
+ '<h1 id="header-1">Header 1</h1>\n'
+ '<h2 id="header-2">Header 2</h2>'
+ )
+
+ def testDisabledMarker(self):
+ """ Test TOC with disabled marker. """
+ md = markdown.Markdown(
+ extensions=[markdown.extensions.toc.TocExtension(marker='')]
+ )
+ text = '[TOC]\n\n# Header 1\n\n## Header 2'
+ self.assertEqual(
+ md.convert(text),
+ '<p>[TOC]</p>\n'
+ '<h1 id="header-1">Header 1</h1>\n'
+ '<h2 id="header-2">Header 2</h2>'
+ )
+ self.assertStartsWith('<div class="toc">', md.toc)
+
+ def testReset(self):
+ """ Test TOC Reset. """
+ self.assertEqual(self.md.toc, '')
+ self.md.convert('# Header 1\n\n## Header 2')
+ self.assertStartsWith('<div class="toc">', self.md.toc)
+ self.md.reset()
+ self.assertEqual(self.md.toc, '')
+ self.assertEqual(self.md.toc_tokens, [])
+
+ def testUniqueIds(self):
+ """ Test Unique IDs. """
+
+ text = '#Header\n#Header\n#Header'
+ self.assertEqual(
+ self.md.convert(text),
+ '<h1 id="header">Header</h1>\n'
+ '<h1 id="header_1">Header</h1>\n'
+ '<h1 id="header_2">Header</h1>'
+ )
+ self.assertEqual(
+ self.md.toc,
+ '<div class="toc">\n'
+ '<ul>\n' # noqa
+ '<li><a href="#header">Header</a></li>\n' # noqa
+ '<li><a href="#header_1">Header</a></li>\n' # noqa
+ '<li><a href="#header_2">Header</a></li>\n' # noqa
+ '</ul>\n' # noqa
+ '</div>\n'
+ )
+ self.assertEqual(self.md.toc_tokens, [
+ {'level': 1, 'id': 'header', 'name': 'Header', 'children': []},
+ {'level': 1, 'id': 'header_1', 'name': 'Header', 'children': []},
+ {'level': 1, 'id': 'header_2', 'name': 'Header', 'children': []},
+ ])
+
+ def testHtmlEntities(self):
+ """ Test Headers with HTML Entities. """
+ text = '# Foo &amp; bar'
+ self.assertEqual(
+ self.md.convert(text),
+ '<h1 id="foo-bar">Foo &amp; bar</h1>'
+ )
+ self.assertEqual(
+ self.md.toc,
+ '<div class="toc">\n'
+ '<ul>\n' # noqa
+ '<li><a href="#foo-bar">Foo &amp; bar</a></li>\n' # noqa
+ '</ul>\n' # noqa
+ '</div>\n'
+ )
+ self.assertEqual(self.md.toc_tokens, [
+ {'level': 1, 'id': 'foo-bar', 'name': 'Foo &amp; bar', 'children': []},
+ ])
+
+ def testHtmlSpecialChars(self):
+ """ Test Headers with HTML special characters. """
+ text = '# Foo > & bar'
+ self.assertEqual(
+ self.md.convert(text),
+ '<h1 id="foo-bar">Foo &gt; &amp; bar</h1>'
+ )
+ self.assertEqual(
+ self.md.toc,
+ '<div class="toc">\n'
+ '<ul>\n' # noqa
+ '<li><a href="#foo-bar">Foo &gt; &amp; bar</a></li>\n' # noqa
+ '</ul>\n' # noqa
+ '</div>\n'
+ )
+ self.assertEqual(self.md.toc_tokens, [
+ {'level': 1, 'id': 'foo-bar', 'name': 'Foo &gt; &amp; bar', 'children': []},
+ ])
+
+ def testRawHtml(self):
+ """ Test Headers with raw HTML. """
+ text = '# Foo <b>Bar</b> Baz.'
+ self.assertEqual(
+ self.md.convert(text),
+ '<h1 id="foo-bar-baz">Foo <b>Bar</b> Baz.</h1>'
+ )
+ self.assertEqual(
+ self.md.toc,
+ '<div class="toc">\n'
+ '<ul>\n' # noqa
+ '<li><a href="#foo-bar-baz">Foo Bar Baz.</a></li>\n' # noqa
+ '</ul>\n' # noqa
+ '</div>\n'
+ )
+ self.assertEqual(self.md.toc_tokens, [
+ {'level': 1, 'id': 'foo-bar-baz', 'name': 'Foo Bar Baz.', 'children': []},
+ ])
+
+ def testBaseLevel(self):
+ """ Test Header Base Level. """
+ md = markdown.Markdown(
+ extensions=[markdown.extensions.toc.TocExtension(baselevel=5)]
+ )
+ text = '# Some Header\n\n## Next Level\n\n### Too High'
+ self.assertEqual(
+ md.convert(text),
+ '<h5 id="some-header">Some Header</h5>\n'
+ '<h6 id="next-level">Next Level</h6>\n'
+ '<h6 id="too-high">Too High</h6>'
+ )
+ self.assertEqual(
+ md.toc,
+ '<div class="toc">\n'
+ '<ul>\n' # noqa
+ '<li><a href="#some-header">Some Header</a>' # noqa
+ '<ul>\n' # noqa
+ '<li><a href="#next-level">Next Level</a></li>\n' # noqa
+ '<li><a href="#too-high">Too High</a></li>\n' # noqa
+ '</ul>\n' # noqa
+ '</li>\n' # noqa
+ '</ul>\n' # noqa
+ '</div>\n'
+ )
+ self.assertEqual(md.toc_tokens, [
+ {'level': 5, 'id': 'some-header', 'name': 'Some Header', 'children': [
+ {'level': 6, 'id': 'next-level', 'name': 'Next Level', 'children': []},
+ {'level': 6, 'id': 'too-high', 'name': 'Too High', 'children': []},
+ ]},
+ ])
+
+ def testHeaderInlineMarkup(self):
+ """ Test Headers with inline markup. """
+
+ text = '#Some *Header* with [markup](http://example.com).'
+ self.assertEqual(
+ self.md.convert(text),
+ '<h1 id="some-header-with-markup">Some <em>Header</em> with '
+ '<a href="http://example.com">markup</a>.</h1>'
+ )
+ self.assertEqual(
+ self.md.toc,
+ '<div class="toc">\n'
+ '<ul>\n' # noqa
+ '<li><a href="#some-header-with-markup">' # noqa
+ 'Some Header with markup.</a></li>\n' # noqa
+ '</ul>\n' # noqa
+ '</div>\n'
+ )
+ self.assertEqual(self.md.toc_tokens, [
+ {'level': 1, 'id': 'some-header-with-markup', 'name': 'Some Header with markup.', 'children': []},
+ ])
+
+ def testTitle(self):
+ """ Test TOC Title. """
+ md = markdown.Markdown(
+ extensions=[markdown.extensions.toc.TocExtension(title='Table of Contents')]
+ )
+ md.convert('# Header 1\n\n## Header 2')
+ self.assertStartsWith(
+ '<div class="toc"><span class="toctitle">Table of Contents</span><ul>',
+ md.toc
+ )
+
+ def testWithAttrList(self):
+ """ Test TOC with attr_list Extension. """
+ md = markdown.Markdown(extensions=['toc', 'attr_list'])
+ text = ('# Header 1\n\n'
+ '## Header 2 { #foo }\n\n'
+ '## Header 3 { data-toc-label="Foo Bar" }\n\n'
+ '# Header 4 { data-toc-label="Foo > Baz" }\n\n'
+ '# Header 5 { data-toc-label="Foo <b>Quux</b>" }')
+
+ self.assertEqual(
+ md.convert(text),
+ '<h1 id="header-1">Header 1</h1>\n'
+ '<h2 id="foo">Header 2</h2>\n'
+ '<h2 id="header-3">Header 3</h2>\n'
+ '<h1 id="header-4">Header 4</h1>\n'
+ '<h1 id="header-5">Header 5</h1>'
+ )
+ self.assertEqual(
+ md.toc,
+ '<div class="toc">\n'
+ '<ul>\n' # noqa
+ '<li><a href="#header-1">Header 1</a>' # noqa
+ '<ul>\n' # noqa
+ '<li><a href="#foo">Header 2</a></li>\n' # noqa
+ '<li><a href="#header-3">Foo Bar</a></li>\n' # noqa
+ '</ul>\n' # noqa
+ '</li>\n' # noqa
+ '<li><a href="#header-4">Foo &gt; Baz</a></li>\n' # noqa
+ '<li><a href="#header-5">Foo Quux</a></li>\n' # noqa
+ '</ul>\n' # noqa
+ '</div>\n'
+ )
+ self.assertEqual(md.toc_tokens, [
+ {'level': 1, 'id': 'header-1', 'name': 'Header 1', 'children': [
+ {'level': 2, 'id': 'foo', 'name': 'Header 2', 'children': []},
+ {'level': 2, 'id': 'header-3', 'name': 'Foo Bar', 'children': []}
+ ]},
+ {'level': 1, 'id': 'header-4', 'name': 'Foo &gt; Baz', 'children': []},
+ {'level': 1, 'id': 'header-5', 'name': 'Foo Quux', 'children': []},
+ ])
+
+ def testUniqueFunc(self):
+ """ Test 'unique' function. """
+ from markdown.extensions.toc import unique
+ ids = {'foo'}
+ self.assertEqual(unique('foo', ids), 'foo_1')
+ self.assertEqual(ids, {'foo', 'foo_1'})
+
+ def testTocInHeaders(self):
+
+ text = '[TOC]\n#[TOC]'
+ self.assertEqual(
+ self.md.convert(text),
+ '<div class="toc">\n' # noqa
+ '<ul>\n' # noqa
+ '<li><a href="#toc">[TOC]</a></li>\n' # noqa
+ '</ul>\n' # noqa
+ '</div>\n' # noqa
+ '<h1 id="toc">[TOC]</h1>' # noqa
+ )
+
+ text = '#[TOC]\n[TOC]'
+ self.assertEqual(
+ self.md.convert(text),
+ '<h1 id="toc">[TOC]</h1>\n' # noqa
+ '<div class="toc">\n' # noqa
+ '<ul>\n' # noqa
+ '<li><a href="#toc">[TOC]</a></li>\n' # noqa
+ '</ul>\n' # noqa
+ '</div>' # noqa
+ )
+
+ text = '[TOC]\n# *[TOC]*'
+ self.assertEqual(
+ self.md.convert(text),
+ '<div class="toc">\n' # noqa
+ '<ul>\n' # noqa
+ '<li><a href="#toc">[TOC]</a></li>\n' # noqa
+ '</ul>\n' # noqa
+ '</div>\n' # noqa
+ '<h1 id="toc"><em>[TOC]</em></h1>' # noqa
+ )
+
+
+class TestSmarty(unittest.TestCase):
+ def setUp(self):
+ config = {
+ 'smarty': [
+ ('smart_angled_quotes', True),
+ ('substitutions', {
+ 'ndash': '\u2013',
+ 'mdash': '\u2014',
+ 'ellipsis': '\u2026',
+ 'left-single-quote': '&sbquo;', # sb is not a typo!
+ 'right-single-quote': '&lsquo;',
+ 'left-double-quote': '&bdquo;',
+ 'right-double-quote': '&ldquo;',
+ 'left-angle-quote': '[',
+ 'right-angle-quote': ']',
+ }),
+ ]
+ }
+ self.md = markdown.Markdown(
+ extensions=['smarty'],
+ extension_configs=config
+ )
+
+ def testCustomSubstitutions(self):
+ text = """<< The "Unicode char of the year 2014"
+is the 'mdash': ---
+Must not be confused with 'ndash' (--) ... >>
+"""
+ correct = """<p>[ The &bdquo;Unicode char of the year 2014&ldquo;
+is the &sbquo;mdash&lsquo;: \u2014
+Must not be confused with &sbquo;ndash&lsquo; (\u2013) \u2026 ]</p>"""
+ self.assertEqual(self.md.convert(text), correct)
diff --git a/tests/test_legacy.py b/tests/test_legacy.py
new file mode 100644
index 0000000..62bc075
--- /dev/null
+++ b/tests/test_legacy.py
@@ -0,0 +1,194 @@
+"""
+Python Markdown
+
+A Python implementation of John Gruber's Markdown.
+
+Documentation: https://python-markdown.github.io/
+GitHub: https://github.com/Python-Markdown/markdown/
+PyPI: https://pypi.org/project/Markdown/
+
+Started by Manfred Stienstra (http://www.dwerg.net/).
+Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
+Currently maintained by Waylan Limberg (https://github.com/waylan),
+Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
+
+Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see LICENSE.md for details).
+"""
+
+from markdown.test_tools import LegacyTestCase, Kwargs
+import os
+import warnings
+
+# Warnings should cause tests to fail...
+warnings.simplefilter('error')
+# Except for the warnings that shouldn't
+warnings.filterwarnings('default', category=PendingDeprecationWarning)
+warnings.filterwarnings('default', category=DeprecationWarning, module='markdown')
+
+parent_test_dir = os.path.abspath(os.path.dirname(__file__))
+
+
+class TestBasic(LegacyTestCase):
+ location = os.path.join(parent_test_dir, 'basic')
+
+
+class TestMisc(LegacyTestCase):
+ location = os.path.join(parent_test_dir, 'misc')
+
+
+class TestPhp(LegacyTestCase):
+ """
+ Notes on "excluded" tests:
+
+ Quotes in attributes: attributes get output in different order
+
+ Inline HTML (Span): Backtick in raw HTML attribute TODO: fixme
+
+ Backslash escapes: Weird whitespace issue in output
+
+ Ins & del: Our behavior follows markdown.pl I think PHP is wrong here
+
+ Auto Links: TODO: fix raw HTML so is doesn't match <hr@example.com> as a <hr>.
+
+ Empty List Item: We match markdown.pl here. Maybe someday we'll support this
+
+ Headers: TODO: fix headers to not require blank line before
+
+ Mixed OLs and ULs: We match markdown.pl here. I think PHP is wrong here
+
+ Emphasis: We have various minor differences in combined & incorrect em markup.
+ Maybe fix a few of them - but most aren't too important
+
+ Code block in a list item: We match markdown.pl - not sure how php gets that output??
+
+ PHP-Specific Bugs: Not sure what to make of the escaping stuff here.
+ Why is PHP not removing a blackslash?
+ """
+ location = os.path.join(parent_test_dir, 'php')
+ normalize = True
+ input_ext = '.text'
+ output_ext = '.xhtml'
+ exclude = [
+ 'Quotes_in_attributes',
+ 'Inline_HTML_(Span)',
+ 'Backslash_escapes',
+ 'Ins_&_del',
+ 'Auto_Links',
+ 'Empty_List_Item',
+ 'Headers',
+ 'Mixed_OLs_and_ULs',
+ 'Emphasis',
+ 'Code_block_in_a_list_item',
+ 'PHP_Specific_Bugs'
+ ]
+
+
+# class TestPhpExtra(LegacyTestCase):
+# location = os.path.join(parent_test_dir, 'php/extra')
+# normalize = True
+# input_ext = '.text'
+# output_ext = '.xhtml'
+# default_kwargs = Kwargs(extensions=['extra'])
+
+
+class TestPl2004(LegacyTestCase):
+ location = os.path.join(parent_test_dir, 'pl/Tests_2004')
+ normalize = True
+ input_ext = '.text'
+ exclude = ['Yuri_Footnotes', 'Yuri_Attributes']
+
+
+class TestPl2007(LegacyTestCase):
+ """
+ Notes on "excluded" tests:
+
+ Images: the attributes don't get ordered the same so we skip this
+
+ Code Blocks: some weird whitespace issue
+
+ Links, reference style: weird issue with nested brackets TODO: fixme
+
+ Backslash escapes: backticks in raw html attributes TODO: fixme
+
+ Code Spans: more backticks in raw html attributes TODO: fixme
+ """
+ location = os.path.join(parent_test_dir, 'pl/Tests_2007')
+ normalize = True
+ input_ext = '.text'
+ exclude = [
+ 'Images',
+ 'Code_Blocks',
+ 'Links,_reference_style',
+ 'Backslash_escapes',
+ 'Code_Spans'
+ ]
+
+
+class TestExtensions(LegacyTestCase):
+ location = os.path.join(parent_test_dir, 'extensions')
+ exclude = ['codehilite']
+
+ attr_list = Kwargs(extensions=['attr_list', 'def_list', 'smarty'])
+
+ codehilite = Kwargs(extensions=['codehilite'])
+
+ toc = Kwargs(extensions=['toc'])
+
+ toc_invalid = Kwargs(extensions=['toc'])
+
+ toc_out_of_order = Kwargs(extensions=['toc'])
+
+ toc_nested = Kwargs(
+ extensions=['toc'],
+ extension_configs={'toc': {'permalink': True}}
+ )
+
+ toc_nested2 = Kwargs(
+ extensions=['toc'],
+ extension_configs={'toc': {'permalink': "[link]"}}
+ )
+
+ toc_nested_list = Kwargs(extensions=['toc'])
+
+ wikilinks = Kwargs(extensions=['wikilinks'])
+
+ github_flavored = Kwargs(extensions=['fenced_code'])
+
+ sane_lists = Kwargs(extensions=['sane_lists'])
+
+ nl2br_w_attr_list = Kwargs(extensions=['nl2br', 'attr_list'])
+
+ admonition = Kwargs(extensions=['admonition'])
+
+ smarty = Kwargs(
+ extensions=['smarty'],
+ extension_configs={'smarty': {'smart_angled_quotes': True}}
+ )
+
+
+class TestExtensionsExtra(LegacyTestCase):
+ location = os.path.join(parent_test_dir, 'extensions/extra')
+ default_kwargs = Kwargs(extensions=['extra'])
+
+ loose_def_list = Kwargs(extensions=['def_list'])
+
+ simple_def_lists = Kwargs(extensions=['def_list'])
+
+ abbr = Kwargs(extensions=['abbr'])
+
+ footnotes = Kwargs(extensions=['footnotes'])
+
+ extra_config = Kwargs(
+ extensions=['extra'],
+ extension_configs={
+ 'extra': {
+ 'footnotes': {
+ 'PLACE_MARKER': '~~~placemarker~~~'
+ }
+ }
+ }
+ )
diff --git a/tests/test_meta.py b/tests/test_meta.py
new file mode 100644
index 0000000..10a2d33
--- /dev/null
+++ b/tests/test_meta.py
@@ -0,0 +1,24 @@
+import unittest
+from markdown.__meta__ import _get_version, __version__
+
+
+class TestVersion(unittest.TestCase):
+
+ def test_get_version(self):
+ """Test that _get_version formats __version_info__ as required by PEP 440."""
+
+ self.assertEqual(_get_version((1, 1, 2, 'dev', 0)), "1.1.2.dev0")
+ self.assertEqual(_get_version((1, 1, 2, 'alpha', 1)), "1.1.2a1")
+ self.assertEqual(_get_version((1, 2, 0, 'beta', 2)), "1.2b2")
+ self.assertEqual(_get_version((1, 2, 0, 'rc', 4)), "1.2rc4")
+ self.assertEqual(_get_version((1, 2, 0, 'final', 0)), "1.2")
+
+ def test__version__IsValid(self):
+ """Test that __version__ is valid and normalized."""
+
+ try:
+ import packaging.version
+ except ImportError:
+ from pkg_resources.extern import packaging
+
+ self.assertEqual(__version__, str(packaging.version.Version(__version__)))
diff --git a/tests/test_syntax/__init__.py b/tests/test_syntax/__init__.py
new file mode 100644
index 0000000..564ba3b
--- /dev/null
+++ b/tests/test_syntax/__init__.py
@@ -0,0 +1,20 @@
+"""
+Python Markdown
+
+A Python implementation of John Gruber's Markdown.
+
+Documentation: https://python-markdown.github.io/
+GitHub: https://github.com/Python-Markdown/markdown/
+PyPI: https://pypi.org/project/Markdown/
+
+Started by Manfred Stienstra (http://www.dwerg.net/).
+Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
+Currently maintained by Waylan Limberg (https://github.com/waylan),
+Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
+
+Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see LICENSE.md for details).
+"""
diff --git a/tests/test_syntax/blocks/__init__.py b/tests/test_syntax/blocks/__init__.py
new file mode 100644
index 0000000..564ba3b
--- /dev/null
+++ b/tests/test_syntax/blocks/__init__.py
@@ -0,0 +1,20 @@
+"""
+Python Markdown
+
+A Python implementation of John Gruber's Markdown.
+
+Documentation: https://python-markdown.github.io/
+GitHub: https://github.com/Python-Markdown/markdown/
+PyPI: https://pypi.org/project/Markdown/
+
+Started by Manfred Stienstra (http://www.dwerg.net/).
+Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
+Currently maintained by Waylan Limberg (https://github.com/waylan),
+Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
+
+Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see LICENSE.md for details).
+"""
diff --git a/tests/test_syntax/blocks/test_blockquotes.py b/tests/test_syntax/blocks/test_blockquotes.py
new file mode 100644
index 0000000..3422f9f
--- /dev/null
+++ b/tests/test_syntax/blocks/test_blockquotes.py
@@ -0,0 +1,51 @@
+"""
+Python Markdown
+
+A Python implementation of John Gruber's Markdown.
+
+Documentation: https://python-markdown.github.io/
+GitHub: https://github.com/Python-Markdown/markdown/
+PyPI: https://pypi.org/project/Markdown/
+
+Started by Manfred Stienstra (http://www.dwerg.net/).
+Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
+Currently maintained by Waylan Limberg (https://github.com/waylan),
+Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
+
+Copyright 2007-2020 The Python Markdown Project (v. 1.7 and later)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see LICENSE.md for details).
+"""
+
+from markdown.test_tools import TestCase, recursionlimit
+
+
+class TestBlockquoteBlocks(TestCase):
+
+ # TODO: Move legacy tests here
+
+ def test_nesting_limit(self):
+ # Test that the nesting limit is within 100 levels of recursion limit. Future code changes could cause the
+ # recursion limit to need adjusted here. We need to account for all of Markdown's internal calls. Finally, we
+ # need to account for the 100 level cushion which we are testing.
+ with recursionlimit(120):
+ self.assertMarkdownRenders(
+ '>>>>>>>>>>',
+ self.dedent(
+ """
+ <blockquote>
+ <blockquote>
+ <blockquote>
+ <blockquote>
+ <blockquote>
+ <p>&gt;&gt;&gt;&gt;&gt;</p>
+ </blockquote>
+ </blockquote>
+ </blockquote>
+ </blockquote>
+ </blockquote>
+ """
+ )
+ )
diff --git a/tests/test_syntax/blocks/test_code_blocks.py b/tests/test_syntax/blocks/test_code_blocks.py
new file mode 100644
index 0000000..54b6860
--- /dev/null
+++ b/tests/test_syntax/blocks/test_code_blocks.py
@@ -0,0 +1,88 @@
+"""
+Python Markdown
+
+A Python implementation of John Gruber's Markdown.
+
+Documentation: https://python-markdown.github.io/
+GitHub: https://github.com/Python-Markdown/markdown/
+PyPI: https://pypi.org/project/Markdown/
+
+Started by Manfred Stienstra (http://www.dwerg.net/).
+Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
+Currently maintained by Waylan Limberg (https://github.com/waylan),
+Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
+
+Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see LICENSE.md for details).
+"""
+
+from markdown.test_tools import TestCase
+
+
+class TestCodeBlocks(TestCase):
+
+ def test_spaced_codeblock(self):
+ self.assertMarkdownRenders(
+ ' # A code block.',
+
+ self.dedent(
+ """
+ <pre><code># A code block.
+ </code></pre>
+ """
+ )
+ )
+
+ def test_tabbed_codeblock(self):
+ self.assertMarkdownRenders(
+ '\t# A code block.',
+
+ self.dedent(
+ """
+ <pre><code># A code block.
+ </code></pre>
+ """
+ )
+ )
+
+ def test_multiline_codeblock(self):
+ self.assertMarkdownRenders(
+ ' # Line 1\n # Line 2\n',
+
+ self.dedent(
+ """
+ <pre><code># Line 1
+ # Line 2
+ </code></pre>
+ """
+ )
+ )
+
+ def test_codeblock_with_blankline(self):
+ self.assertMarkdownRenders(
+ ' # Line 1\n\n # Line 2\n',
+
+ self.dedent(
+ """
+ <pre><code># Line 1
+
+ # Line 2
+ </code></pre>
+ """
+ )
+ )
+
+ def test_codeblock_escape(self):
+ self.assertMarkdownRenders(
+ ' <foo & bar>',
+
+ self.dedent(
+ """
+ <pre><code>&lt;foo &amp; bar&gt;
+ </code></pre>
+ """
+ )
+ )
diff --git a/tests/test_syntax/blocks/test_headers.py b/tests/test_syntax/blocks/test_headers.py
new file mode 100644
index 0000000..ca065a5
--- /dev/null
+++ b/tests/test_syntax/blocks/test_headers.py
@@ -0,0 +1,729 @@
+"""
+Python Markdown
+
+A Python implementation of John Gruber's Markdown.
+
+Documentation: https://python-markdown.github.io/
+GitHub: https://github.com/Python-Markdown/markdown/
+PyPI: https://pypi.org/project/Markdown/
+
+Started by Manfred Stienstra (http://www.dwerg.net/).
+Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
+Currently maintained by Waylan Limberg (https://github.com/waylan),
+Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
+
+Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see LICENSE.md for details).
+"""
+
+import unittest
+from markdown.test_tools import TestCase
+
+
+class TestSetextHeaders(TestCase):
+
+ def test_setext_h1(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ This is an H1
+ =============
+ """
+ ),
+
+ '<h1>This is an H1</h1>'
+ )
+
+ def test_setext_h2(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ This is an H2
+ -------------
+ """
+ ),
+
+ '<h2>This is an H2</h2>'
+ )
+
+ def test_setext_h1_mismatched_length(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ This is an H1
+ ===
+ """
+ ),
+
+ '<h1>This is an H1</h1>'
+ )
+
+ def test_setext_h2_mismatched_length(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ This is an H2
+ ---
+ """
+ ),
+
+ '<h2>This is an H2</h2>'
+ )
+
+ def test_setext_h1_followed_by_p(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ This is an H1
+ =============
+ Followed by a Paragraph with no blank line.
+ """
+ ),
+ self.dedent(
+ """
+ <h1>This is an H1</h1>
+ <p>Followed by a Paragraph with no blank line.</p>
+ """
+ )
+ )
+
+ def test_setext_h2_followed_by_p(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ This is an H2
+ -------------
+ Followed by a Paragraph with no blank line.
+ """
+ ),
+ self.dedent(
+ """
+ <h2>This is an H2</h2>
+ <p>Followed by a Paragraph with no blank line.</p>
+ """
+ )
+ )
+
+ # TODO: fix this
+ # see https://johnmacfarlane.net/babelmark2/?normalize=1&text=Paragraph%0AAn+H1%0A%3D%3D%3D%3D%3D
+ @unittest.skip('This is broken in Python-Markdown')
+ def test_p_followed_by_setext_h1(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ This is a Paragraph.
+ Followed by an H1 with no blank line.
+ =====================================
+ """
+ ),
+ self.dedent(
+ """
+ <p>This is a Paragraph.</p>
+ <h1>Followed by an H1 with no blank line.</h1>
+ """
+ )
+ )
+
+ # TODO: fix this
+ # see https://johnmacfarlane.net/babelmark2/?normalize=1&text=Paragraph%0AAn+H2%0A-----
+ @unittest.skip('This is broken in Python-Markdown')
+ def test_p_followed_by_setext_h2(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ This is a Paragraph.
+ Followed by an H2 with no blank line.
+ -------------------------------------
+ """
+ ),
+ self.dedent(
+ """
+ <p>This is a Paragraph.</p>
+ <h2>Followed by an H2 with no blank line.</h2>
+ """
+ )
+ )
+
+
+class TestHashHeaders(TestCase):
+
+ def test_hash_h1_open(self):
+ self.assertMarkdownRenders(
+ '# This is an H1',
+
+ '<h1>This is an H1</h1>'
+ )
+
+ def test_hash_h2_open(self):
+ self.assertMarkdownRenders(
+ '## This is an H2',
+
+ '<h2>This is an H2</h2>'
+ )
+
+ def test_hash_h3_open(self):
+ self.assertMarkdownRenders(
+ '### This is an H3',
+
+ '<h3>This is an H3</h3>'
+ )
+
+ def test_hash_h4_open(self):
+ self.assertMarkdownRenders(
+ '#### This is an H4',
+
+ '<h4>This is an H4</h4>'
+ )
+
+ def test_hash_h5_open(self):
+ self.assertMarkdownRenders(
+ '##### This is an H5',
+
+ '<h5>This is an H5</h5>'
+ )
+
+ def test_hash_h6_open(self):
+ self.assertMarkdownRenders(
+ '###### This is an H6',
+
+ '<h6>This is an H6</h6>'
+ )
+
+ def test_hash_gt6_open(self):
+ self.assertMarkdownRenders(
+ '####### This is an H6',
+
+ '<h6># This is an H6</h6>'
+ )
+
+ def test_hash_h1_open_missing_space(self):
+ self.assertMarkdownRenders(
+ '#This is an H1',
+
+ '<h1>This is an H1</h1>'
+ )
+
+ def test_hash_h2_open_missing_space(self):
+ self.assertMarkdownRenders(
+ '##This is an H2',
+
+ '<h2>This is an H2</h2>'
+ )
+
+ def test_hash_h3_open_missing_space(self):
+ self.assertMarkdownRenders(
+ '###This is an H3',
+
+ '<h3>This is an H3</h3>'
+ )
+
+ def test_hash_h4_open_missing_space(self):
+ self.assertMarkdownRenders(
+ '####This is an H4',
+
+ '<h4>This is an H4</h4>'
+ )
+
+ def test_hash_h5_open_missing_space(self):
+ self.assertMarkdownRenders(
+ '#####This is an H5',
+
+ '<h5>This is an H5</h5>'
+ )
+
+ def test_hash_h6_open_missing_space(self):
+ self.assertMarkdownRenders(
+ '######This is an H6',
+
+ '<h6>This is an H6</h6>'
+ )
+
+ def test_hash_gt6_open_missing_space(self):
+ self.assertMarkdownRenders(
+ '#######This is an H6',
+
+ '<h6>#This is an H6</h6>'
+ )
+
+ def test_hash_h1_closed(self):
+ self.assertMarkdownRenders(
+ '# This is an H1 #',
+
+ '<h1>This is an H1</h1>'
+ )
+
+ def test_hash_h2_closed(self):
+ self.assertMarkdownRenders(
+ '## This is an H2 ##',
+
+ '<h2>This is an H2</h2>'
+ )
+
+ def test_hash_h3_closed(self):
+ self.assertMarkdownRenders(
+ '### This is an H3 ###',
+
+ '<h3>This is an H3</h3>'
+ )
+
+ def test_hash_h4_closed(self):
+ self.assertMarkdownRenders(
+ '#### This is an H4 ####',
+
+ '<h4>This is an H4</h4>'
+ )
+
+ def test_hash_h5_closed(self):
+ self.assertMarkdownRenders(
+ '##### This is an H5 #####',
+
+ '<h5>This is an H5</h5>'
+ )
+
+ def test_hash_h6_closed(self):
+ self.assertMarkdownRenders(
+ '###### This is an H6 ######',
+
+ '<h6>This is an H6</h6>'
+ )
+
+ def test_hash_gt6_closed(self):
+ self.assertMarkdownRenders(
+ '####### This is an H6 #######',
+
+ '<h6># This is an H6</h6>'
+ )
+
+ def test_hash_h1_closed_missing_space(self):
+ self.assertMarkdownRenders(
+ '#This is an H1#',
+
+ '<h1>This is an H1</h1>'
+ )
+
+ def test_hash_h2_closed_missing_space(self):
+ self.assertMarkdownRenders(
+ '##This is an H2##',
+
+ '<h2>This is an H2</h2>'
+ )
+
+ def test_hash_h3_closed_missing_space(self):
+ self.assertMarkdownRenders(
+ '###This is an H3###',
+
+ '<h3>This is an H3</h3>'
+ )
+
+ def test_hash_h4_closed_missing_space(self):
+ self.assertMarkdownRenders(
+ '####This is an H4####',
+
+ '<h4>This is an H4</h4>'
+ )
+
+ def test_hash_h5_closed_missing_space(self):
+ self.assertMarkdownRenders(
+ '#####This is an H5#####',
+
+ '<h5>This is an H5</h5>'
+ )
+
+ def test_hash_h6_closed_missing_space(self):
+ self.assertMarkdownRenders(
+ '######This is an H6######',
+
+ '<h6>This is an H6</h6>'
+ )
+
+ def test_hash_gt6_closed_missing_space(self):
+ self.assertMarkdownRenders(
+ '#######This is an H6#######',
+
+ '<h6>#This is an H6</h6>'
+ )
+
+ def test_hash_h1_closed_mismatch(self):
+ self.assertMarkdownRenders(
+ '# This is an H1 ##',
+
+ '<h1>This is an H1</h1>'
+ )
+
+ def test_hash_h2_closed_mismatch(self):
+ self.assertMarkdownRenders(
+ '## This is an H2 #',
+
+ '<h2>This is an H2</h2>'
+ )
+
+ def test_hash_h3_closed_mismatch(self):
+ self.assertMarkdownRenders(
+ '### This is an H3 #',
+
+ '<h3>This is an H3</h3>'
+ )
+
+ def test_hash_h4_closed_mismatch(self):
+ self.assertMarkdownRenders(
+ '#### This is an H4 #',
+
+ '<h4>This is an H4</h4>'
+ )
+
+ def test_hash_h5_closed_mismatch(self):
+ self.assertMarkdownRenders(
+ '##### This is an H5 #',
+
+ '<h5>This is an H5</h5>'
+ )
+
+ def test_hash_h6_closed_mismatch(self):
+ self.assertMarkdownRenders(
+ '###### This is an H6 #',
+
+ '<h6>This is an H6</h6>'
+ )
+
+ def test_hash_gt6_closed_mismatch(self):
+ self.assertMarkdownRenders(
+ '####### This is an H6 ##################',
+
+ '<h6># This is an H6</h6>'
+ )
+
+ def test_hash_h1_followed_by_p(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ # This is an H1
+ Followed by a Paragraph with no blank line.
+ """
+ ),
+ self.dedent(
+ """
+ <h1>This is an H1</h1>
+ <p>Followed by a Paragraph with no blank line.</p>
+ """
+ )
+ )
+
+ def test_hash_h2_followed_by_p(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ ## This is an H2
+ Followed by a Paragraph with no blank line.
+ """
+ ),
+ self.dedent(
+ """
+ <h2>This is an H2</h2>
+ <p>Followed by a Paragraph with no blank line.</p>
+ """
+ )
+ )
+
+ def test_hash_h3_followed_by_p(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ ### This is an H3
+ Followed by a Paragraph with no blank line.
+ """
+ ),
+ self.dedent(
+ """
+ <h3>This is an H3</h3>
+ <p>Followed by a Paragraph with no blank line.</p>
+ """
+ )
+ )
+
+ def test_hash_h4_followed_by_p(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ #### This is an H4
+ Followed by a Paragraph with no blank line.
+ """
+ ),
+ self.dedent(
+ """
+ <h4>This is an H4</h4>
+ <p>Followed by a Paragraph with no blank line.</p>
+ """
+ )
+ )
+
+ def test_hash_h5_followed_by_p(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ ##### This is an H5
+ Followed by a Paragraph with no blank line.
+ """
+ ),
+ self.dedent(
+ """
+ <h5>This is an H5</h5>
+ <p>Followed by a Paragraph with no blank line.</p>
+ """
+ )
+ )
+
+ def test_hash_h6_followed_by_p(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ ###### This is an H6
+ Followed by a Paragraph with no blank line.
+ """
+ ),
+ self.dedent(
+ """
+ <h6>This is an H6</h6>
+ <p>Followed by a Paragraph with no blank line.</p>
+ """
+ )
+ )
+
+ def test_hash_h1_leading_space(self):
+ self.assertMarkdownRenders(
+ ' # This is an H1',
+
+ '<p># This is an H1</p>'
+ )
+
+ def test_hash_h2_leading_space(self):
+ self.assertMarkdownRenders(
+ ' ## This is an H2',
+
+ '<p>## This is an H2</p>'
+ )
+
+ def test_hash_h3_leading_space(self):
+ self.assertMarkdownRenders(
+ ' ### This is an H3',
+
+ '<p>### This is an H3</p>'
+ )
+
+ def test_hash_h4_leading_space(self):
+ self.assertMarkdownRenders(
+ ' #### This is an H4',
+
+ '<p>#### This is an H4</p>'
+ )
+
+ def test_hash_h5_leading_space(self):
+ self.assertMarkdownRenders(
+ ' ##### This is an H5',
+
+ '<p>##### This is an H5</p>'
+ )
+
+ def test_hash_h6_leading_space(self):
+ self.assertMarkdownRenders(
+ ' ###### This is an H6',
+
+ '<p>###### This is an H6</p>'
+ )
+
+ def test_hash_h1_open_trailing_space(self):
+ self.assertMarkdownRenders(
+ '# This is an H1 ',
+
+ '<h1>This is an H1</h1>'
+ )
+
+ def test_hash_h2_open_trailing_space(self):
+ self.assertMarkdownRenders(
+ '## This is an H2 ',
+
+ '<h2>This is an H2</h2>'
+ )
+
+ def test_hash_h3_open_trailing_space(self):
+ self.assertMarkdownRenders(
+ '### This is an H3 ',
+
+ '<h3>This is an H3</h3>'
+ )
+
+ def test_hash_h4_open_trailing_space(self):
+ self.assertMarkdownRenders(
+ '#### This is an H4 ',
+
+ '<h4>This is an H4</h4>'
+ )
+
+ def test_hash_h5_open_trailing_space(self):
+ self.assertMarkdownRenders(
+ '##### This is an H5 ',
+
+ '<h5>This is an H5</h5>'
+ )
+
+ def test_hash_h6_open_trailing_space(self):
+ self.assertMarkdownRenders(
+ '###### This is an H6 ',
+
+ '<h6>This is an H6</h6>'
+ )
+
+ def test_hash_gt6_open_trailing_space(self):
+ self.assertMarkdownRenders(
+ '####### This is an H6 ',
+
+ '<h6># This is an H6</h6>'
+ )
+
+ # TODO: Possibly change the following behavior. While this follows the behavior
+ # of markdown.pl, it is rather uncommon and not necessarily intuitive.
+ # See: https://johnmacfarlane.net/babelmark2/?normalize=1&text=%23+This+is+an+H1+%23+
+ def test_hash_h1_closed_trailing_space(self):
+ self.assertMarkdownRenders(
+ '# This is an H1 # ',
+
+ '<h1>This is an H1 #</h1>'
+ )
+
+ def test_hash_h2_closed_trailing_space(self):
+ self.assertMarkdownRenders(
+ '## This is an H2 ## ',
+
+ '<h2>This is an H2 ##</h2>'
+ )
+
+ def test_hash_h3_closed_trailing_space(self):
+ self.assertMarkdownRenders(
+ '### This is an H3 ### ',
+
+ '<h3>This is an H3 ###</h3>'
+ )
+
+ def test_hash_h4_closed_trailing_space(self):
+ self.assertMarkdownRenders(
+ '#### This is an H4 #### ',
+
+ '<h4>This is an H4 ####</h4>'
+ )
+
+ def test_hash_h5_closed_trailing_space(self):
+ self.assertMarkdownRenders(
+ '##### This is an H5 ##### ',
+
+ '<h5>This is an H5 #####</h5>'
+ )
+
+ def test_hash_h6_closed_trailing_space(self):
+ self.assertMarkdownRenders(
+ '###### This is an H6 ###### ',
+
+ '<h6>This is an H6 ######</h6>'
+ )
+
+ def test_hash_gt6_closed_trailing_space(self):
+ self.assertMarkdownRenders(
+ '####### This is an H6 ####### ',
+
+ '<h6># This is an H6 #######</h6>'
+ )
+
+ def test_no_blank_lines_between_hashs(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ # This is an H1
+ ## This is an H2
+ """
+ ),
+ self.dedent(
+ """
+ <h1>This is an H1</h1>
+ <h2>This is an H2</h2>
+ """
+ )
+ )
+
+ def test_random_hash_levels(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ ### H3
+ ###### H6
+ # H1
+ ##### H5
+ #### H4
+ ## H2
+ ### H3
+ """
+ ),
+ self.dedent(
+ """
+ <h3>H3</h3>
+ <h6>H6</h6>
+ <h1>H1</h1>
+ <h5>H5</h5>
+ <h4>H4</h4>
+ <h2>H2</h2>
+ <h3>H3</h3>
+ """
+ )
+ )
+
+ def test_hash_followed_by_p(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ # This is an H1
+ Followed by a Paragraph with no blank line.
+ """
+ ),
+ self.dedent(
+ """
+ <h1>This is an H1</h1>
+ <p>Followed by a Paragraph with no blank line.</p>
+ """
+ )
+ )
+
+ def test_p_followed_by_hash(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ This is a Paragraph.
+ # Followed by an H1 with no blank line.
+ """
+ ),
+ self.dedent(
+ """
+ <p>This is a Paragraph.</p>
+ <h1>Followed by an H1 with no blank line.</h1>
+ """
+ )
+ )
+
+ def test_escaped_hash(self):
+ self.assertMarkdownRenders(
+ "### H3 \\###",
+ self.dedent(
+ """
+ <h3>H3 #</h3>
+ """
+ )
+ )
+
+ def test_unescaped_hash(self):
+ self.assertMarkdownRenders(
+ "### H3 \\\\###",
+ self.dedent(
+ """
+ <h3>H3 \\</h3>
+ """
+ )
+ )
diff --git a/tests/test_syntax/blocks/test_hr.py b/tests/test_syntax/blocks/test_hr.py
new file mode 100644
index 0000000..85a51b3
--- /dev/null
+++ b/tests/test_syntax/blocks/test_hr.py
@@ -0,0 +1,402 @@
+"""
+Python Markdown
+
+A Python implementation of John Gruber's Markdown.
+
+Documentation: https://python-markdown.github.io/
+GitHub: https://github.com/Python-Markdown/markdown/
+PyPI: https://pypi.org/project/Markdown/
+
+Started by Manfred Stienstra (http://www.dwerg.net/).
+Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
+Currently maintained by Waylan Limberg (https://github.com/waylan),
+Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
+
+Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see LICENSE.md for details).
+"""
+
+from markdown.test_tools import TestCase
+
+
+class TestHorizontalRules(TestCase):
+
+ def test_hr_asterisks(self):
+ self.assertMarkdownRenders(
+ '***',
+
+ '<hr />'
+ )
+
+ def test_hr_asterisks_spaces(self):
+ self.assertMarkdownRenders(
+ '* * *',
+
+ '<hr />'
+ )
+
+ def test_hr_asterisks_long(self):
+ self.assertMarkdownRenders(
+ '*******',
+
+ '<hr />'
+ )
+
+ def test_hr_asterisks_spaces_long(self):
+ self.assertMarkdownRenders(
+ '* * * * * * *',
+
+ '<hr />'
+ )
+
+ def test_hr_asterisks_1_indent(self):
+ self.assertMarkdownRenders(
+ ' ***',
+
+ '<hr />'
+ )
+
+ def test_hr_asterisks_spaces_1_indent(self):
+ self.assertMarkdownRenders(
+ ' * * *',
+
+ '<hr />'
+ )
+
+ def test_hr_asterisks_2_indent(self):
+ self.assertMarkdownRenders(
+ ' ***',
+
+ '<hr />'
+ )
+
+ def test_hr_asterisks_spaces_2_indent(self):
+ self.assertMarkdownRenders(
+ ' * * *',
+
+ '<hr />'
+ )
+
+ def test_hr_asterisks_3_indent(self):
+ self.assertMarkdownRenders(
+ ' ***',
+
+ '<hr />'
+ )
+
+ def test_hr_asterisks_spaces_3_indent(self):
+ self.assertMarkdownRenders(
+ ' * * *',
+
+ '<hr />'
+ )
+
+ def test_hr_asterisks_trailing_space(self):
+ self.assertMarkdownRenders(
+ '*** ',
+
+ '<hr />'
+ )
+
+ def test_hr_asterisks_spaces_trailing_space(self):
+ self.assertMarkdownRenders(
+ '* * * ',
+
+ '<hr />'
+ )
+
+ def test_hr_hyphens(self):
+ self.assertMarkdownRenders(
+ '---',
+
+ '<hr />'
+ )
+
+ def test_hr_hyphens_spaces(self):
+ self.assertMarkdownRenders(
+ '- - -',
+
+ '<hr />'
+ )
+
+ def test_hr_hyphens_long(self):
+ self.assertMarkdownRenders(
+ '-------',
+
+ '<hr />'
+ )
+
+ def test_hr_hyphens_spaces_long(self):
+ self.assertMarkdownRenders(
+ '- - - - - - -',
+
+ '<hr />'
+ )
+
+ def test_hr_hyphens_1_indent(self):
+ self.assertMarkdownRenders(
+ ' ---',
+
+ '<hr />'
+ )
+
+ def test_hr_hyphens_spaces_1_indent(self):
+ self.assertMarkdownRenders(
+ ' - - -',
+
+ '<hr />'
+ )
+
+ def test_hr_hyphens_2_indent(self):
+ self.assertMarkdownRenders(
+ ' ---',
+
+ '<hr />'
+ )
+
+ def test_hr_hyphens_spaces_2_indent(self):
+ self.assertMarkdownRenders(
+ ' - - -',
+
+ '<hr />'
+ )
+
+ def test_hr_hyphens_3_indent(self):
+ self.assertMarkdownRenders(
+ ' ---',
+
+ '<hr />'
+ )
+
+ def test_hr_hyphens_spaces_3_indent(self):
+ self.assertMarkdownRenders(
+ ' - - -',
+
+ '<hr />'
+ )
+
+ def test_hr_hyphens_trailing_space(self):
+ self.assertMarkdownRenders(
+ '--- ',
+
+ '<hr />'
+ )
+
+ def test_hr_hyphens_spaces_trailing_space(self):
+ self.assertMarkdownRenders(
+ '- - - ',
+
+ '<hr />'
+ )
+
+ def test_hr_underscores(self):
+ self.assertMarkdownRenders(
+ '___',
+
+ '<hr />'
+ )
+
+ def test_hr_underscores_spaces(self):
+ self.assertMarkdownRenders(
+ '_ _ _',
+
+ '<hr />'
+ )
+
+ def test_hr_underscores_long(self):
+ self.assertMarkdownRenders(
+ '_______',
+
+ '<hr />'
+ )
+
+ def test_hr_underscores_spaces_long(self):
+ self.assertMarkdownRenders(
+ '_ _ _ _ _ _ _',
+
+ '<hr />'
+ )
+
+ def test_hr_underscores_1_indent(self):
+ self.assertMarkdownRenders(
+ ' ___',
+
+ '<hr />'
+ )
+
+ def test_hr_underscores_spaces_1_indent(self):
+ self.assertMarkdownRenders(
+ ' _ _ _',
+
+ '<hr />'
+ )
+
+ def test_hr_underscores_2_indent(self):
+ self.assertMarkdownRenders(
+ ' ___',
+
+ '<hr />'
+ )
+
+ def test_hr_underscores_spaces_2_indent(self):
+ self.assertMarkdownRenders(
+ ' _ _ _',
+
+ '<hr />'
+ )
+
+ def test_hr_underscores_3_indent(self):
+ self.assertMarkdownRenders(
+ ' ___',
+
+ '<hr />'
+ )
+
+ def test_hr_underscores_spaces_3_indent(self):
+ self.assertMarkdownRenders(
+ ' _ _ _',
+
+ '<hr />'
+ )
+
+ def test_hr_underscores_trailing_space(self):
+ self.assertMarkdownRenders(
+ '___ ',
+
+ '<hr />'
+ )
+
+ def test_hr_underscores_spaces_trailing_space(self):
+ self.assertMarkdownRenders(
+ '_ _ _ ',
+
+ '<hr />'
+ )
+
+ def test_hr_before_paragraph(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ ***
+ An HR followed by a paragraph with no blank line.
+ """
+ ),
+ self.dedent(
+ """
+ <hr />
+ <p>An HR followed by a paragraph with no blank line.</p>
+ """
+ )
+ )
+
+ def test_hr_after_paragraph(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ A paragraph followed by an HR with no blank line.
+ ***
+ """
+ ),
+ self.dedent(
+ """
+ <p>A paragraph followed by an HR with no blank line.</p>
+ <hr />
+ """
+ )
+ )
+
+ def test_hr_after_emstrong(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ ***text***
+ ***
+ """
+ ),
+ self.dedent(
+ """
+ <p><strong><em>text</em></strong></p>
+ <hr />
+ """
+ )
+ )
+
+ def test_not_hr_2_asterisks(self):
+ self.assertMarkdownRenders(
+ '**',
+
+ '<p>**</p>'
+ )
+
+ def test_not_hr_2_asterisks_spaces(self):
+ self.assertMarkdownRenders(
+ '* *',
+
+ self.dedent(
+ """
+ <ul>
+ <li>*</li>
+ </ul>
+ """
+ )
+ )
+
+ def test_not_hr_2_hyphens(self):
+ self.assertMarkdownRenders(
+ '--',
+
+ '<p>--</p>'
+ )
+
+ def test_not_hr_2_hyphens_spaces(self):
+ self.assertMarkdownRenders(
+ '- -',
+
+ self.dedent(
+ """
+ <ul>
+ <li>-</li>
+ </ul>
+ """
+ )
+ )
+
+ def test_not_hr_2_underscores(self):
+ self.assertMarkdownRenders(
+ '__',
+
+ '<p>__</p>'
+ )
+
+ def test_not_hr_2_underscores_spaces(self):
+ self.assertMarkdownRenders(
+ '_ _',
+
+ '<p>_ _</p>'
+ )
+
+ def test_2_consecutive_hr(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ - - -
+ - - -
+ """
+ ),
+ self.dedent(
+ """
+ <hr />
+ <hr />
+ """
+ )
+ )
+
+ def test_not_hr_end_in_char(self):
+ self.assertMarkdownRenders(
+ '--------------------------------------c',
+
+ '<p>--------------------------------------c</p>'
+ )
diff --git a/tests/test_syntax/blocks/test_html_blocks.py b/tests/test_syntax/blocks/test_html_blocks.py
new file mode 100644
index 0000000..9ec0668
--- /dev/null
+++ b/tests/test_syntax/blocks/test_html_blocks.py
@@ -0,0 +1,1619 @@
+# -*- coding: utf-8 -*-
+"""
+Python Markdown
+
+A Python implementation of John Gruber's Markdown.
+
+Documentation: https://python-markdown.github.io/
+GitHub: https://github.com/Python-Markdown/markdown/
+PyPI: https://pypi.org/project/Markdown/
+
+Started by Manfred Stienstra (http://www.dwerg.net/).
+Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
+Currently maintained by Waylan Limberg (https://github.com/waylan),
+Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
+
+Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see LICENSE.md for details).
+"""
+
+from markdown.test_tools import TestCase
+import markdown
+
+
+class TestHTMLBlocks(TestCase):
+
+ def test_raw_paragraph(self):
+ self.assertMarkdownRenders(
+ '<p>A raw paragraph.</p>',
+ '<p>A raw paragraph.</p>'
+ )
+
+ def test_raw_skip_inline_markdown(self):
+ self.assertMarkdownRenders(
+ '<p>A *raw* paragraph.</p>',
+ '<p>A *raw* paragraph.</p>'
+ )
+
+ def test_raw_indent_one_space(self):
+ self.assertMarkdownRenders(
+ ' <p>A *raw* paragraph.</p>',
+ '<p>A *raw* paragraph.</p>'
+ )
+
+ def test_raw_indent_two_spaces(self):
+ self.assertMarkdownRenders(
+ ' <p>A *raw* paragraph.</p>',
+ '<p>A *raw* paragraph.</p>'
+ )
+
+ def test_raw_indent_three_spaces(self):
+ self.assertMarkdownRenders(
+ ' <p>A *raw* paragraph.</p>',
+ '<p>A *raw* paragraph.</p>'
+ )
+
+ def test_raw_indent_four_spaces(self):
+ self.assertMarkdownRenders(
+ ' <p>code block</p>',
+ self.dedent(
+ """
+ <pre><code>&lt;p&gt;code block&lt;/p&gt;
+ </code></pre>
+ """
+ )
+ )
+
+ def test_raw_span(self):
+ self.assertMarkdownRenders(
+ '<span>*inline*</span>',
+ '<p><span><em>inline</em></span></p>'
+ )
+
+ def test_code_span(self):
+ self.assertMarkdownRenders(
+ '`<p>code span</p>`',
+ '<p><code>&lt;p&gt;code span&lt;/p&gt;</code></p>'
+ )
+
+ def test_code_span_open_gt(self):
+ self.assertMarkdownRenders(
+ '*bar* `<` *foo*',
+ '<p><em>bar</em> <code>&lt;</code> <em>foo</em></p>'
+ )
+
+ def test_raw_empty(self):
+ self.assertMarkdownRenders(
+ '<p></p>',
+ '<p></p>'
+ )
+
+ def test_raw_empty_space(self):
+ self.assertMarkdownRenders(
+ '<p> </p>',
+ '<p> </p>'
+ )
+
+ def test_raw_empty_newline(self):
+ self.assertMarkdownRenders(
+ '<p>\n</p>',
+ '<p>\n</p>'
+ )
+
+ def test_raw_empty_blank_line(self):
+ self.assertMarkdownRenders(
+ '<p>\n\n</p>',
+ '<p>\n\n</p>'
+ )
+
+ def test_raw_uppercase(self):
+ self.assertMarkdownRenders(
+ '<DIV>*foo*</DIV>',
+ '<DIV>*foo*</DIV>'
+ )
+
+ def test_raw_uppercase_multiline(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <DIV>
+ *foo*
+ </DIV>
+ """
+ ),
+ self.dedent(
+ """
+ <DIV>
+ *foo*
+ </DIV>
+ """
+ )
+ )
+
+ def test_multiple_raw_single_line(self):
+ self.assertMarkdownRenders(
+ '<p>*foo*</p><div>*bar*</div>',
+ self.dedent(
+ """
+ <p>*foo*</p>
+ <div>*bar*</div>
+ """
+ )
+ )
+
+ def test_multiple_raw_single_line_with_pi(self):
+ self.assertMarkdownRenders(
+ "<p>*foo*</p><?php echo '>'; ?>",
+ self.dedent(
+ """
+ <p>*foo*</p>
+ <?php echo '>'; ?>
+ """
+ )
+ )
+
+ def test_multiline_raw(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <p>
+ A raw paragraph
+ with multiple lines.
+ </p>
+ """
+ ),
+ self.dedent(
+ """
+ <p>
+ A raw paragraph
+ with multiple lines.
+ </p>
+ """
+ )
+ )
+
+ def test_blank_lines_in_raw(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <p>
+
+ A raw paragraph...
+
+ with many blank lines.
+
+ </p>
+ """
+ ),
+ self.dedent(
+ """
+ <p>
+
+ A raw paragraph...
+
+ with many blank lines.
+
+ </p>
+ """
+ )
+ )
+
+ def test_raw_surrounded_by_Markdown(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ Some *Markdown* text.
+
+ <p>*Raw* HTML.</p>
+
+ More *Markdown* text.
+ """
+ ),
+ self.dedent(
+ """
+ <p>Some <em>Markdown</em> text.</p>
+ <p>*Raw* HTML.</p>
+
+ <p>More <em>Markdown</em> text.</p>
+ """
+ )
+ )
+
+ def test_raw_surrounded_by_text_without_blank_lines(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ Some *Markdown* text.
+ <p>*Raw* HTML.</p>
+ More *Markdown* text.
+ """
+ ),
+ self.dedent(
+ """
+ <p>Some <em>Markdown</em> text.</p>
+ <p>*Raw* HTML.</p>
+ <p>More <em>Markdown</em> text.</p>
+ """
+ )
+ )
+
+ def test_multiline_markdown_with_code_span(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ A paragraph with a block-level
+ `<p>code span</p>`, which is
+ at the start of a line.
+ """
+ ),
+ self.dedent(
+ """
+ <p>A paragraph with a block-level
+ <code>&lt;p&gt;code span&lt;/p&gt;</code>, which is
+ at the start of a line.</p>
+ """
+ )
+ )
+
+ def test_raw_block_preceded_by_markdown_code_span_with_unclosed_block_tag(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ A paragraph with a block-level code span: `<div>`.
+
+ <p>*not markdown*</p>
+
+ This is *markdown*
+ """
+ ),
+ self.dedent(
+ """
+ <p>A paragraph with a block-level code span: <code>&lt;div&gt;</code>.</p>
+ <p>*not markdown*</p>
+
+ <p>This is <em>markdown</em></p>
+ """
+ )
+ )
+
+ def test_raw_one_line_followed_by_text(self):
+ self.assertMarkdownRenders(
+ '<p>*foo*</p>*bar*',
+ self.dedent(
+ """
+ <p>*foo*</p>
+ <p><em>bar</em></p>
+ """
+ )
+ )
+
+ def test_raw_one_line_followed_by_span(self):
+ self.assertMarkdownRenders(
+ "<p>*foo*</p><span>*bar*</span>",
+ self.dedent(
+ """
+ <p>*foo*</p>
+ <p><span><em>bar</em></span></p>
+ """
+ )
+ )
+
+ def test_raw_with_markdown_blocks(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <div>
+ Not a Markdown paragraph.
+
+ * Not a list item.
+ * Another non-list item.
+
+ Another non-Markdown paragraph.
+ </div>
+ """
+ ),
+ self.dedent(
+ """
+ <div>
+ Not a Markdown paragraph.
+
+ * Not a list item.
+ * Another non-list item.
+
+ Another non-Markdown paragraph.
+ </div>
+ """
+ )
+ )
+
+ def test_adjacent_raw_blocks(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <p>A raw paragraph.</p>
+ <p>A second raw paragraph.</p>
+ """
+ ),
+ self.dedent(
+ """
+ <p>A raw paragraph.</p>
+ <p>A second raw paragraph.</p>
+ """
+ )
+ )
+
+ def test_adjacent_raw_blocks_with_blank_lines(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <p>A raw paragraph.</p>
+
+ <p>A second raw paragraph.</p>
+ """
+ ),
+ self.dedent(
+ """
+ <p>A raw paragraph.</p>
+
+ <p>A second raw paragraph.</p>
+ """
+ )
+ )
+
+ def test_nested_raw_one_line(self):
+ self.assertMarkdownRenders(
+ '<div><p>*foo*</p></div>',
+ '<div><p>*foo*</p></div>'
+ )
+
+ def test_nested_raw_block(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <div>
+ <p>A raw paragraph.</p>
+ </div>
+ """
+ ),
+ self.dedent(
+ """
+ <div>
+ <p>A raw paragraph.</p>
+ </div>
+ """
+ )
+ )
+
+ def test_nested_indented_raw_block(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <div>
+ <p>A raw paragraph.</p>
+ </div>
+ """
+ ),
+ self.dedent(
+ """
+ <div>
+ <p>A raw paragraph.</p>
+ </div>
+ """
+ )
+ )
+
+ def test_nested_raw_blocks(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <div>
+ <p>A raw paragraph.</p>
+ <p>A second raw paragraph.</p>
+ </div>
+ """
+ ),
+ self.dedent(
+ """
+ <div>
+ <p>A raw paragraph.</p>
+ <p>A second raw paragraph.</p>
+ </div>
+ """
+ )
+ )
+
+ def test_nested_raw_blocks_with_blank_lines(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <div>
+
+ <p>A raw paragraph.</p>
+
+ <p>A second raw paragraph.</p>
+
+ </div>
+ """
+ ),
+ self.dedent(
+ """
+ <div>
+
+ <p>A raw paragraph.</p>
+
+ <p>A second raw paragraph.</p>
+
+ </div>
+ """
+ )
+ )
+
+ def test_nested_inline_one_line(self):
+ self.assertMarkdownRenders(
+ '<p><em>foo</em><br></p>',
+ '<p><em>foo</em><br></p>'
+ )
+
+ def test_raw_nested_inline(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <div>
+ <p>
+ <span>*text*</span>
+ </p>
+ </div>
+ """
+ ),
+ self.dedent(
+ """
+ <div>
+ <p>
+ <span>*text*</span>
+ </p>
+ </div>
+ """
+ )
+ )
+
+ def test_raw_nested_inline_with_blank_lines(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <div>
+
+ <p>
+
+ <span>*text*</span>
+
+ </p>
+
+ </div>
+ """
+ ),
+ self.dedent(
+ """
+ <div>
+
+ <p>
+
+ <span>*text*</span>
+
+ </p>
+
+ </div>
+ """
+ )
+ )
+
+ def test_raw_html5(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <section>
+ <header>
+ <hgroup>
+ <h1>Hello :-)</h1>
+ </hgroup>
+ </header>
+ <figure>
+ <img src="image.png" alt="" />
+ <figcaption>Caption</figcaption>
+ </figure>
+ <footer>
+ <p>Some footer</p>
+ </footer>
+ </section>
+ """
+ ),
+ self.dedent(
+ """
+ <section>
+ <header>
+ <hgroup>
+ <h1>Hello :-)</h1>
+ </hgroup>
+ </header>
+ <figure>
+ <img src="image.png" alt="" />
+ <figcaption>Caption</figcaption>
+ </figure>
+ <footer>
+ <p>Some footer</p>
+ </footer>
+ </section>
+ """
+ )
+ )
+
+ def test_raw_pre_tag(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ Preserve whitespace in raw html
+
+ <pre>
+ class Foo():
+ bar = 'bar'
+
+ @property
+ def baz(self):
+ return self.bar
+ </pre>
+ """
+ ),
+ self.dedent(
+ """
+ <p>Preserve whitespace in raw html</p>
+ <pre>
+ class Foo():
+ bar = 'bar'
+
+ @property
+ def baz(self):
+ return self.bar
+ </pre>
+ """
+ )
+ )
+
+ def test_raw_pre_tag_nested_escaped_html(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <pre>
+ &lt;p&gt;foo&lt;/p&gt;
+ </pre>
+ """
+ ),
+ self.dedent(
+ """
+ <pre>
+ &lt;p&gt;foo&lt;/p&gt;
+ </pre>
+ """
+ )
+ )
+
+ def test_raw_p_no_end_tag(self):
+ self.assertMarkdownRenders(
+ '<p>*text*',
+ '<p>*text*'
+ )
+
+ def test_raw_multiple_p_no_end_tag(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <p>*text*'
+
+ <p>more *text*
+ """
+ ),
+ self.dedent(
+ """
+ <p>*text*'
+
+ <p>more *text*
+ """
+ )
+ )
+
+ def test_raw_p_no_end_tag_followed_by_blank_line(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <p>*raw text*'
+
+ Still part of *raw* text.
+ """
+ ),
+ self.dedent(
+ """
+ <p>*raw text*'
+
+ Still part of *raw* text.
+ """
+ )
+ )
+
+ def test_raw_nested_p_no_end_tag(self):
+ self.assertMarkdownRenders(
+ '<div><p>*text*</div>',
+ '<div><p>*text*</div>'
+ )
+
+ def test_raw_open_bracket_only(self):
+ self.assertMarkdownRenders(
+ '<',
+ '<p>&lt;</p>'
+ )
+
+ def test_raw_open_bracket_followed_by_space(self):
+ self.assertMarkdownRenders(
+ '< foo',
+ '<p>&lt; foo</p>'
+ )
+
+ def test_raw_missing_close_bracket(self):
+ self.assertMarkdownRenders(
+ '<foo',
+ '<p>&lt;foo</p>'
+ )
+
+ def test_raw_unclosed_tag_in_code_span(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ `<div`.
+
+ <div>
+ hello
+ </div>
+ """
+ ),
+ self.dedent(
+ """
+ <p><code>&lt;div</code>.</p>
+ <div>
+ hello
+ </div>
+ """
+ )
+ )
+
+ def test_raw_unclosed_tag_in_code_span_space(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ ` <div `.
+
+ <div>
+ hello
+ </div>
+ """
+ ),
+ self.dedent(
+ """
+ <p><code>&lt;div</code>.</p>
+ <div>
+ hello
+ </div>
+ """
+ )
+ )
+
+ def test_raw_attributes(self):
+ self.assertMarkdownRenders(
+ '<p id="foo", class="bar baz", style="margin: 15px; line-height: 1.5; text-align: center;">text</p>',
+ '<p id="foo", class="bar baz", style="margin: 15px; line-height: 1.5; text-align: center;">text</p>'
+ )
+
+ def test_raw_attributes_nested(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <div id="foo, class="bar", style="background: #ffe7e8; border: 2px solid #e66465;">
+ <p id="baz", style="margin: 15px; line-height: 1.5; text-align: center;">
+ <img scr="../foo.jpg" title="with 'quoted' text." valueless_attr weirdness="<i>foo</i>" />
+ </p>
+ </div>
+ """
+ ),
+ self.dedent(
+ """
+ <div id="foo, class="bar", style="background: #ffe7e8; border: 2px solid #e66465;">
+ <p id="baz", style="margin: 15px; line-height: 1.5; text-align: center;">
+ <img scr="../foo.jpg" title="with 'quoted' text." valueless_attr weirdness="<i>foo</i>" />
+ </p>
+ </div>
+ """
+ )
+ )
+
+ def test_raw_comment_one_line(self):
+ self.assertMarkdownRenders(
+ '<!-- *foo* -->',
+ '<!-- *foo* -->'
+ )
+
+ def test_raw_comment_one_line_with_tag(self):
+ self.assertMarkdownRenders(
+ '<!-- <tag> -->',
+ '<!-- <tag> -->'
+ )
+
+ def test_comment_in_code_span(self):
+ self.assertMarkdownRenders(
+ '`<!-- *foo* -->`',
+ '<p><code>&lt;!-- *foo* --&gt;</code></p>'
+ )
+
+ def test_raw_comment_one_line_followed_by_text(self):
+ self.assertMarkdownRenders(
+ '<!-- *foo* -->*bar*',
+ self.dedent(
+ """
+ <!-- *foo* -->
+ <p><em>bar</em></p>
+ """
+ )
+ )
+
+ def test_raw_comment_one_line_followed_by_html(self):
+ self.assertMarkdownRenders(
+ '<!-- *foo* --><p>*bar*</p>',
+ self.dedent(
+ """
+ <!-- *foo* -->
+ <p>*bar*</p>
+ """
+ )
+ )
+
+ # Note: Trailing (insignificant) whitespace is not preserved, which does not match the
+ # reference implementation. However, it is not a change in behavior for Python-Markdown.
+ def test_raw_comment_trailing_whitespace(self):
+ self.assertMarkdownRenders(
+ '<!-- *foo* --> ',
+ '<!-- *foo* -->'
+ )
+
+ # Note: this is a change in behavior for Python-Markdown, which does *not* match the reference
+ # implementation. However, it does match the HTML5 spec. Declarations must start with either
+ # `<!DOCTYPE` or `<![`. Anything else that starts with `<!` is a comment. According to the
+ # HTML5 spec, a comment without the hyphens is a "bogus comment", but a comment nonetheless.
+ # See https://www.w3.org/TR/html52/syntax.html#markup-declaration-open-state.
+ # If we wanted to change this behavior, we could override `HTMLParser.parse_bogus_comment()`.
+ def test_bogus_comment(self):
+ self.assertMarkdownRenders(
+ '<!*foo*>',
+ '<!--*foo*-->'
+ )
+
+ def test_raw_multiline_comment(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <!--
+ *foo*
+ -->
+ """
+ ),
+ self.dedent(
+ """
+ <!--
+ *foo*
+ -->
+ """
+ )
+ )
+
+ def test_raw_multiline_comment_with_tag(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <!--
+ <tag>
+ -->
+ """
+ ),
+ self.dedent(
+ """
+ <!--
+ <tag>
+ -->
+ """
+ )
+ )
+
+ def test_raw_multiline_comment_first_line(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <!-- *foo*
+ -->
+ """
+ ),
+ self.dedent(
+ """
+ <!-- *foo*
+ -->
+ """
+ )
+ )
+
+ def test_raw_multiline_comment_last_line(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <!--
+ *foo* -->
+ """
+ ),
+ self.dedent(
+ """
+ <!--
+ *foo* -->
+ """
+ )
+ )
+
+ def test_raw_comment_with_blank_lines(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <!--
+
+ *foo*
+
+ -->
+ """
+ ),
+ self.dedent(
+ """
+ <!--
+
+ *foo*
+
+ -->
+ """
+ )
+ )
+
+ def test_raw_comment_with_blank_lines_with_tag(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <!--
+
+ <tag>
+
+ -->
+ """
+ ),
+ self.dedent(
+ """
+ <!--
+
+ <tag>
+
+ -->
+ """
+ )
+ )
+
+ def test_raw_comment_with_blank_lines_first_line(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <!-- *foo*
+
+ -->
+ """
+ ),
+ self.dedent(
+ """
+ <!-- *foo*
+
+ -->
+ """
+ )
+ )
+
+ def test_raw_comment_with_blank_lines_last_line(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <!--
+
+ *foo* -->
+ """
+ ),
+ self.dedent(
+ """
+ <!--
+
+ *foo* -->
+ """
+ )
+ )
+
+ def test_raw_comment_indented(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <!--
+
+ *foo*
+
+ -->
+ """
+ ),
+ self.dedent(
+ """
+ <!--
+
+ *foo*
+
+ -->
+ """
+ )
+ )
+
+ def test_raw_comment_indented_with_tag(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <!--
+
+ <tag>
+
+ -->
+ """
+ ),
+ self.dedent(
+ """
+ <!--
+
+ <tag>
+
+ -->
+ """
+ )
+ )
+
+ def test_raw_comment_nested(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <div>
+ <!-- *foo* -->
+ </div>
+ """
+ ),
+ self.dedent(
+ """
+ <div>
+ <!-- *foo* -->
+ </div>
+ """
+ )
+ )
+
+ def test_comment_in_code_block(self):
+ self.assertMarkdownRenders(
+ ' <!-- *foo* -->',
+ self.dedent(
+ """
+ <pre><code>&lt;!-- *foo* --&gt;
+ </code></pre>
+ """
+ )
+ )
+
+ # Note: This is a change in behavior. Previously, Python-Markdown interpreted this in the same manner
+ # as browsers and all text after the opening comment tag was considered to be in a comment. However,
+ # that did not match the reference implementation. The new behavior does.
+ def test_unclosed_comment_(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <!-- unclosed comment
+
+ *not* a comment
+ """
+ ),
+ self.dedent(
+ """
+ <p>&lt;!-- unclosed comment</p>
+ <p><em>not</em> a comment</p>
+ """
+ )
+ )
+
+ def test_raw_processing_instruction_one_line(self):
+ self.assertMarkdownRenders(
+ "<?php echo '>'; ?>",
+ "<?php echo '>'; ?>"
+ )
+
+ # This is a change in behavior and does not match the reference implementation.
+ # We have no way to determine if text is on the same line, so we get this. TODO: reevaluate!
+ def test_raw_processing_instruction_one_line_followed_by_text(self):
+ self.assertMarkdownRenders(
+ "<?php echo '>'; ?>*bar*",
+ self.dedent(
+ """
+ <?php echo '>'; ?>
+ <p><em>bar</em></p>
+ """
+ )
+ )
+
+ def test_raw_multiline_processing_instruction(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <?php
+ echo '>';
+ ?>
+ """
+ ),
+ self.dedent(
+ """
+ <?php
+ echo '>';
+ ?>
+ """
+ )
+ )
+
+ def test_raw_processing_instruction_with_blank_lines(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <?php
+
+ echo '>';
+
+ ?>
+ """
+ ),
+ self.dedent(
+ """
+ <?php
+
+ echo '>';
+
+ ?>
+ """
+ )
+ )
+
+ def test_raw_processing_instruction_indented(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <?php
+
+ echo '>';
+
+ ?>
+ """
+ ),
+ self.dedent(
+ """
+ <?php
+
+ echo '>';
+
+ ?>
+ """
+ )
+ )
+
+ def test_raw_processing_instruction_code_span(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ `<?php`
+
+ <div>
+ foo
+ </div>
+ """
+ ),
+ self.dedent(
+ """
+ <p><code>&lt;?php</code></p>
+ <div>
+ foo
+ </div>
+ """
+ )
+ )
+
+ def test_raw_declaration_one_line(self):
+ self.assertMarkdownRenders(
+ '<!DOCTYPE html>',
+ '<!DOCTYPE html>'
+ )
+
+ # This is a change in behavior and does not match the reference implementation.
+ # We have no way to determine if text is on the same line, so we get this. TODO: reevaluate!
+ def test_raw_declaration_one_line_followed_by_text(self):
+ self.assertMarkdownRenders(
+ '<!DOCTYPE html>*bar*',
+ self.dedent(
+ """
+ <!DOCTYPE html>
+ <p><em>bar</em></p>
+ """
+ )
+ )
+
+ def test_raw_multiline_declaration(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <!DOCTYPE html PUBLIC
+ "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+ """
+ ),
+ self.dedent(
+ """
+ <!DOCTYPE html PUBLIC
+ "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+ """
+ )
+ )
+
+ def test_raw_declaration_code_span(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ `<!`
+
+ <div>
+ foo
+ </div>
+ """
+ ),
+ self.dedent(
+ """
+ <p><code>&lt;!</code></p>
+ <div>
+ foo
+ </div>
+ """
+ )
+ )
+
+ def test_raw_cdata_one_line(self):
+ self.assertMarkdownRenders(
+ '<![CDATA[ document.write(">"); ]]>',
+ '<![CDATA[ document.write(">"); ]]>'
+ )
+
+ # Note: this is a change. Neither previous output nor this match reference implementation.
+ def test_raw_cdata_one_line_followed_by_text(self):
+ self.assertMarkdownRenders(
+ '<![CDATA[ document.write(">"); ]]>*bar*',
+ self.dedent(
+ """
+ <![CDATA[ document.write(">"); ]]>
+ <p><em>bar</em></p>
+ """
+ )
+ )
+
+ def test_raw_multiline_cdata(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <![CDATA[
+ document.write(">");
+ ]]>
+ """
+ ),
+ self.dedent(
+ """
+ <![CDATA[
+ document.write(">");
+ ]]>
+ """
+ )
+ )
+
+ def test_raw_cdata_with_blank_lines(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <![CDATA[
+
+ document.write(">");
+
+ ]]>
+ """
+ ),
+ self.dedent(
+ """
+ <![CDATA[
+
+ document.write(">");
+
+ ]]>
+ """
+ )
+ )
+
+ def test_raw_cdata_indented(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <![CDATA[
+
+ document.write(">");
+
+ ]]>
+ """
+ ),
+ self.dedent(
+ """
+ <![CDATA[
+
+ document.write(">");
+
+ ]]>
+ """
+ )
+ )
+
+ def test_raw_cdata_code_span(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ `<![`
+
+ <div>
+ foo
+ </div>
+ """
+ ),
+ self.dedent(
+ """
+ <p><code>&lt;![</code></p>
+ <div>
+ foo
+ </div>
+ """
+ )
+ )
+
+ def test_charref(self):
+ self.assertMarkdownRenders(
+ '&sect;',
+ '<p>&sect;</p>'
+ )
+
+ def test_nested_charref(self):
+ self.assertMarkdownRenders(
+ '<p>&sect;</p>',
+ '<p>&sect;</p>'
+ )
+
+ def test_entityref(self):
+ self.assertMarkdownRenders(
+ '&#167;',
+ '<p>&#167;</p>'
+ )
+
+ def test_nested_entityref(self):
+ self.assertMarkdownRenders(
+ '<p>&#167;</p>',
+ '<p>&#167;</p>'
+ )
+
+ def test_amperstand(self):
+ self.assertMarkdownRenders(
+ 'AT&T & AT&amp;T',
+ '<p>AT&amp;T &amp; AT&amp;T</p>'
+ )
+
+ def test_startendtag(self):
+ self.assertMarkdownRenders(
+ '<hr>',
+ '<hr>'
+ )
+
+ def test_startendtag_with_attrs(self):
+ self.assertMarkdownRenders(
+ '<hr id="foo" class="bar">',
+ '<hr id="foo" class="bar">'
+ )
+
+ def test_startendtag_with_space(self):
+ self.assertMarkdownRenders(
+ '<hr >',
+ '<hr >'
+ )
+
+ def test_closed_startendtag(self):
+ self.assertMarkdownRenders(
+ '<hr />',
+ '<hr />'
+ )
+
+ def test_closed_startendtag_without_space(self):
+ self.assertMarkdownRenders(
+ '<hr/>',
+ '<hr/>'
+ )
+
+ def test_closed_startendtag_with_attrs(self):
+ self.assertMarkdownRenders(
+ '<hr id="foo" class="bar" />',
+ '<hr id="foo" class="bar" />'
+ )
+
+ def test_nested_startendtag(self):
+ self.assertMarkdownRenders(
+ '<div><hr></div>',
+ '<div><hr></div>'
+ )
+
+ def test_nested_closed_startendtag(self):
+ self.assertMarkdownRenders(
+ '<div><hr /></div>',
+ '<div><hr /></div>'
+ )
+
+ def test_auto_links_dont_break_parser(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <https://example.com>
+
+ <email@example.com>
+ """
+ ),
+ '<p><a href="https://example.com">https://example.com</a></p>\n'
+ '<p><a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#101;&#109;'
+ '&#97;&#105;&#108;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;'
+ '&#46;&#99;&#111;&#109;">&#101;&#109;&#97;&#105;&#108;&#64;&#101;'
+ '&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;</a></p>'
+ )
+
+ def test_text_links_ignored(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ https://example.com
+
+ email@example.com
+ """
+ ),
+ self.dedent(
+ """
+ <p>https://example.com</p>
+ <p>email@example.com</p>
+ """
+ ),
+ )
+
+ def text_invalid_tags(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <some [weird](http://example.com) stuff>
+
+ <some>> <<unbalanced>> <<brackets>
+ """
+ ),
+ self.dedent(
+ """
+ <p><some <a href="http://example.com">weird</a> stuff></p>
+ <p><some>&gt; &lt;<unbalanced>&gt; &lt;<brackets></p>
+ """
+ )
+ )
+
+ def test_script_tags(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <script>
+ *random stuff* <div> &amp;
+ </script>
+
+ <style>
+ **more stuff**
+ </style>
+ """
+ ),
+ self.dedent(
+ """
+ <script>
+ *random stuff* <div> &amp;
+ </script>
+
+ <style>
+ **more stuff**
+ </style>
+ """
+ )
+ )
+
+ def test_unclosed_script_tag(self):
+ # Ensure we have a working fix for https://bugs.python.org/issue41989
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <script>
+ *random stuff* <div> &amp;
+
+ Still part of the *script* tag
+ """
+ ),
+ self.dedent(
+ """
+ <script>
+ *random stuff* <div> &amp;
+
+ Still part of the *script* tag
+ """
+ )
+ )
+
+ def test_inline_script_tags(self):
+ # Ensure inline script tags doesn't cause the parser to eat content (see #1036).
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ Text `<script>` more *text*.
+
+ <div>
+ *foo*
+ </div>
+
+ <div>
+
+ bar
+
+ </div>
+
+ A new paragraph with a closing `</script>` tag.
+ """
+ ),
+ self.dedent(
+ """
+ <p>Text <code>&lt;script&gt;</code> more <em>text</em>.</p>
+ <div>
+ *foo*
+ </div>
+
+ <div>
+
+ bar
+
+ </div>
+
+ <p>A new paragraph with a closing <code>&lt;/script&gt;</code> tag.</p>
+ """
+ )
+ )
+
+ def test_hr_only_start(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ *emphasis1*
+ <hr>
+ *emphasis2*
+ """
+ ),
+ self.dedent(
+ """
+ <p><em>emphasis1</em></p>
+ <hr>
+ <p><em>emphasis2</em></p>
+ """
+ )
+ )
+
+ def test_hr_self_close(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ *emphasis1*
+ <hr/>
+ *emphasis2*
+ """
+ ),
+ self.dedent(
+ """
+ <p><em>emphasis1</em></p>
+ <hr/>
+ <p><em>emphasis2</em></p>
+ """
+ )
+ )
+
+ def test_hr_start_and_end(self):
+ # Browsers ignore ending hr tags, so we don't try to do anything to handle them special.
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ *emphasis1*
+ <hr></hr>
+ *emphasis2*
+ """
+ ),
+ self.dedent(
+ """
+ <p><em>emphasis1</em></p>
+ <hr>
+ <p></hr>
+ <em>emphasis2</em></p>
+ """
+ )
+ )
+
+ def test_hr_only_end(self):
+ # Browsers ignore ending hr tags, so we don't try to do anything to handle them special.
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ *emphasis1*
+ </hr>
+ *emphasis2*
+ """
+ ),
+ self.dedent(
+ """
+ <p><em>emphasis1</em>
+ </hr>
+ <em>emphasis2</em></p>
+ """
+ )
+ )
+
+ def test_hr_with_content(self):
+ # Browsers ignore ending hr tags, so we don't try to do anything to handle them special.
+ # Content is not allowed and will be treated as normal content between two hr tags.
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ *emphasis1*
+ <hr>
+ **content**
+ </hr>
+ *emphasis2*
+ """
+ ),
+ self.dedent(
+ """
+ <p><em>emphasis1</em></p>
+ <hr>
+ <p><strong>content</strong>
+ </hr>
+ <em>emphasis2</em></p>
+ """
+ )
+ )
+
+ def test_placeholder_in_source(self):
+ # This should never occur, but third party extensions could create weird edge cases.
+ md = markdown.Markdown()
+ # Ensure there is an htmlstash so relevant code (nested in `if replacements`) is run.
+ md.htmlStash.store('foo')
+ # Run with a placeholder which is not in the stash
+ placeholder = md.htmlStash.get_placeholder(md.htmlStash.html_counter + 1)
+ result = md.postprocessors['raw_html'].run(placeholder)
+ self.assertEqual(placeholder, result)
diff --git a/tests/test_syntax/blocks/test_paragraphs.py b/tests/test_syntax/blocks/test_paragraphs.py
new file mode 100644
index 0000000..9b7ba03
--- /dev/null
+++ b/tests/test_syntax/blocks/test_paragraphs.py
@@ -0,0 +1,229 @@
+"""
+Python Markdown
+
+A Python implementation of John Gruber's Markdown.
+
+Documentation: https://python-markdown.github.io/
+GitHub: https://github.com/Python-Markdown/markdown/
+PyPI: https://pypi.org/project/Markdown/
+
+Started by Manfred Stienstra (http://www.dwerg.net/).
+Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
+Currently maintained by Waylan Limberg (https://github.com/waylan),
+Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
+
+Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see LICENSE.md for details).
+"""
+
+from markdown.test_tools import TestCase
+
+
+class TestParagraphBlocks(TestCase):
+
+ def test_simple_paragraph(self):
+ self.assertMarkdownRenders(
+ 'A simple paragraph.',
+
+ '<p>A simple paragraph.</p>'
+ )
+
+ def test_blank_line_before_paragraph(self):
+ self.assertMarkdownRenders(
+ '\nA paragraph preceded by a blank line.',
+
+ '<p>A paragraph preceded by a blank line.</p>'
+ )
+
+ def test_multiline_paragraph(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ This is a paragraph
+ on multiple lines
+ with hard returns.
+ """
+ ),
+ self.dedent(
+ """
+ <p>This is a paragraph
+ on multiple lines
+ with hard returns.</p>
+ """
+ )
+ )
+
+ def test_paragraph_long_line(self):
+ self.assertMarkdownRenders(
+ 'A very long long long long long long long long long long long long long long long long long long long '
+ 'long long long long long long long long long long long long long paragraph on 1 line.',
+
+ '<p>A very long long long long long long long long long long long long long long long long long long '
+ 'long long long long long long long long long long long long long long paragraph on 1 line.</p>'
+ )
+
+ def test_2_paragraphs_long_line(self):
+ self.assertMarkdownRenders(
+ 'A very long long long long long long long long long long long long long long long long long long long '
+ 'long long long long long long long long long long long long long paragraph on 1 line.\n\n'
+
+ 'A new long long long long long long long long long long long long long long long '
+ 'long paragraph on 1 line.',
+
+ '<p>A very long long long long long long long long long long long long long long long long long long '
+ 'long long long long long long long long long long long long long long paragraph on 1 line.</p>\n'
+ '<p>A new long long long long long long long long long long long long long long long '
+ 'long paragraph on 1 line.</p>'
+ )
+
+ def test_consecutive_paragraphs(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ Paragraph 1.
+
+ Paragraph 2.
+ """
+ ),
+ self.dedent(
+ """
+ <p>Paragraph 1.</p>
+ <p>Paragraph 2.</p>
+ """
+ )
+ )
+
+ def test_consecutive_paragraphs_tab(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ Paragraph followed by a line with a tab only.
+ \t
+ Paragraph after a line with a tab only.
+ """
+ ),
+ self.dedent(
+ """
+ <p>Paragraph followed by a line with a tab only.</p>
+ <p>Paragraph after a line with a tab only.</p>
+ """
+ )
+ )
+
+ def test_consecutive_paragraphs_space(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ Paragraph followed by a line with a space only.
+
+ Paragraph after a line with a space only.
+ """
+ ),
+ self.dedent(
+ """
+ <p>Paragraph followed by a line with a space only.</p>
+ <p>Paragraph after a line with a space only.</p>
+ """
+ )
+ )
+
+ def test_consecutive_multiline_paragraphs(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ Paragraph 1, line 1.
+ Paragraph 1, line 2.
+
+ Paragraph 2, line 1.
+ Paragraph 2, line 2.
+ """
+ ),
+ self.dedent(
+ """
+ <p>Paragraph 1, line 1.
+ Paragraph 1, line 2.</p>
+ <p>Paragraph 2, line 1.
+ Paragraph 2, line 2.</p>
+ """
+ )
+ )
+
+ def test_paragraph_leading_space(self):
+ self.assertMarkdownRenders(
+ ' A paragraph with 1 leading space.',
+
+ '<p>A paragraph with 1 leading space.</p>'
+ )
+
+ def test_paragraph_2_leading_spaces(self):
+ self.assertMarkdownRenders(
+ ' A paragraph with 2 leading spaces.',
+
+ '<p>A paragraph with 2 leading spaces.</p>'
+ )
+
+ def test_paragraph_3_leading_spaces(self):
+ self.assertMarkdownRenders(
+ ' A paragraph with 3 leading spaces.',
+
+ '<p>A paragraph with 3 leading spaces.</p>'
+ )
+
+ def test_paragraph_trailing_leading_space(self):
+ self.assertMarkdownRenders(
+ ' A paragraph with 1 trailing and 1 leading space. ',
+
+ '<p>A paragraph with 1 trailing and 1 leading space. </p>'
+ )
+
+ def test_paragraph_trailing_tab(self):
+ self.assertMarkdownRenders(
+ 'A paragraph with 1 trailing tab.\t',
+
+ '<p>A paragraph with 1 trailing tab. </p>'
+ )
+
+ def test_paragraphs_CR(self):
+ self.assertMarkdownRenders(
+ 'Paragraph 1, line 1.\rParagraph 1, line 2.\r\rParagraph 2, line 1.\rParagraph 2, line 2.\r',
+
+ self.dedent(
+ """
+ <p>Paragraph 1, line 1.
+ Paragraph 1, line 2.</p>
+ <p>Paragraph 2, line 1.
+ Paragraph 2, line 2.</p>
+ """
+ )
+ )
+
+ def test_paragraphs_LF(self):
+ self.assertMarkdownRenders(
+ 'Paragraph 1, line 1.\nParagraph 1, line 2.\n\nParagraph 2, line 1.\nParagraph 2, line 2.\n',
+
+ self.dedent(
+ """
+ <p>Paragraph 1, line 1.
+ Paragraph 1, line 2.</p>
+ <p>Paragraph 2, line 1.
+ Paragraph 2, line 2.</p>
+ """
+ )
+ )
+
+ def test_paragraphs_CR_LF(self):
+ self.assertMarkdownRenders(
+ 'Paragraph 1, line 1.\r\nParagraph 1, line 2.\r\n\r\nParagraph 2, line 1.\r\nParagraph 2, line 2.\r\n',
+
+ self.dedent(
+ """
+ <p>Paragraph 1, line 1.
+ Paragraph 1, line 2.</p>
+ <p>Paragraph 2, line 1.
+ Paragraph 2, line 2.</p>
+ """
+ )
+ )
diff --git a/tests/test_syntax/extensions/__init__.py b/tests/test_syntax/extensions/__init__.py
new file mode 100644
index 0000000..564ba3b
--- /dev/null
+++ b/tests/test_syntax/extensions/__init__.py
@@ -0,0 +1,20 @@
+"""
+Python Markdown
+
+A Python implementation of John Gruber's Markdown.
+
+Documentation: https://python-markdown.github.io/
+GitHub: https://github.com/Python-Markdown/markdown/
+PyPI: https://pypi.org/project/Markdown/
+
+Started by Manfred Stienstra (http://www.dwerg.net/).
+Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
+Currently maintained by Waylan Limberg (https://github.com/waylan),
+Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
+
+Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see LICENSE.md for details).
+"""
diff --git a/tests/test_syntax/extensions/test_abbr.py b/tests/test_syntax/extensions/test_abbr.py
new file mode 100644
index 0000000..64388c2
--- /dev/null
+++ b/tests/test_syntax/extensions/test_abbr.py
@@ -0,0 +1,242 @@
+# -*- coding: utf-8 -*-
+"""
+Python Markdown
+
+A Python implementation of John Gruber's Markdown.
+
+Documentation: https://python-markdown.github.io/
+GitHub: https://github.com/Python-Markdown/markdown/
+PyPI: https://pypi.org/project/Markdown/
+
+Started by Manfred Stienstra (http://www.dwerg.net/).
+Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
+Currently maintained by Waylan Limberg (https://github.com/waylan),
+Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
+
+Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see LICENSE.md for details).
+"""
+
+from markdown.test_tools import TestCase
+
+
+class TestAbbr(TestCase):
+
+ default_kwargs = {'extensions': ['abbr']}
+
+ def test_abbr_upper(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ ABBR
+
+ *[ABBR]: Abbreviation
+ """
+ ),
+ self.dedent(
+ """
+ <p><abbr title="Abbreviation">ABBR</abbr></p>
+ """
+ )
+ )
+
+ def test_abbr_lower(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ abbr
+
+ *[abbr]: Abbreviation
+ """
+ ),
+ self.dedent(
+ """
+ <p><abbr title="Abbreviation">abbr</abbr></p>
+ """
+ )
+ )
+
+ def test_abbr_multiple(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ The HTML specification
+ is maintained by the W3C.
+
+ *[HTML]: Hyper Text Markup Language
+ *[W3C]: World Wide Web Consortium
+ """
+ ),
+ self.dedent(
+ """
+ <p>The <abbr title="Hyper Text Markup Language">HTML</abbr> specification
+ is maintained by the <abbr title="World Wide Web Consortium">W3C</abbr>.</p>
+ """
+ )
+ )
+
+ def test_abbr_override(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ ABBR
+
+ *[ABBR]: Ignored
+ *[ABBR]: The override
+ """
+ ),
+ self.dedent(
+ """
+ <p><abbr title="The override">ABBR</abbr></p>
+ """
+ )
+ )
+
+ def test_abbr_no_blank_Lines(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ ABBR
+ *[ABBR]: Abbreviation
+ ABBR
+ """
+ ),
+ self.dedent(
+ """
+ <p><abbr title="Abbreviation">ABBR</abbr></p>
+ <p><abbr title="Abbreviation">ABBR</abbr></p>
+ """
+ )
+ )
+
+ def test_abbr_no_space(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ ABBR
+
+ *[ABBR]:Abbreviation
+ """
+ ),
+ self.dedent(
+ """
+ <p><abbr title="Abbreviation">ABBR</abbr></p>
+ """
+ )
+ )
+
+ def test_abbr_extra_space(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ ABBR
+
+ *[ABBR] : Abbreviation
+ """
+ ),
+ self.dedent(
+ """
+ <p><abbr title="Abbreviation">ABBR</abbr></p>
+ """
+ )
+ )
+
+ def test_abbr_line_break(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ ABBR
+
+ *[ABBR]:
+ Abbreviation
+ """
+ ),
+ self.dedent(
+ """
+ <p><abbr title="Abbreviation">ABBR</abbr></p>
+ """
+ )
+ )
+
+ def test_abbr_ignore_unmatched_case(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ ABBR abbr
+
+ *[ABBR]: Abbreviation
+ """
+ ),
+ self.dedent(
+ """
+ <p><abbr title="Abbreviation">ABBR</abbr> abbr</p>
+ """
+ )
+ )
+
+ def test_abbr_partial_word(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ ABBR ABBREVIATION
+
+ *[ABBR]: Abbreviation
+ """
+ ),
+ self.dedent(
+ """
+ <p><abbr title="Abbreviation">ABBR</abbr> ABBREVIATION</p>
+ """
+ )
+ )
+
+ def test_abbr_unused(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ foo bar
+
+ *[ABBR]: Abbreviation
+ """
+ ),
+ self.dedent(
+ """
+ <p>foo bar</p>
+ """
+ )
+ )
+
+ def test_abbr_double_quoted(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ ABBR
+
+ *[ABBR]: "Abbreviation"
+ """
+ ),
+ self.dedent(
+ """
+ <p><abbr title="&quot;Abbreviation&quot;">ABBR</abbr></p>
+ """
+ )
+ )
+
+ def test_abbr_single_quoted(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ ABBR
+
+ *[ABBR]: 'Abbreviation'
+ """
+ ),
+ self.dedent(
+ """
+ <p><abbr title="'Abbreviation'">ABBR</abbr></p>
+ """
+ )
+ )
diff --git a/tests/test_syntax/extensions/test_admonition.py b/tests/test_syntax/extensions/test_admonition.py
new file mode 100644
index 0000000..44c70d1
--- /dev/null
+++ b/tests/test_syntax/extensions/test_admonition.py
@@ -0,0 +1,245 @@
+"""
+Python Markdown
+
+A Python implementation of John Gruber's Markdown.
+
+Documentation: https://python-markdown.github.io/
+GitHub: https://github.com/Python-Markdown/markdown/
+PyPI: https://pypi.org/project/Markdown/
+
+Started by Manfred Stienstra (http://www.dwerg.net/).
+Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
+Currently maintained by Waylan Limberg (https://github.com/waylan),
+Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
+
+Copyright 2007-2019 The Python Markdown Project (v. 1.7 and later)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see LICENSE.md for details).
+"""
+
+from markdown.test_tools import TestCase
+
+
+class TestAdmonition(TestCase):
+
+ def test_with_lists(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ - List
+
+ !!! note "Admontion"
+
+ - Paragraph
+
+ Paragraph
+ '''
+ ),
+ self.dedent(
+ '''
+ <ul>
+ <li>
+ <p>List</p>
+ <div class="admonition note">
+ <p class="admonition-title">Admontion</p>
+ <ul>
+ <li>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ </li>
+ </ul>
+ </div>
+ </li>
+ </ul>
+ '''
+ ),
+ extensions=['admonition']
+ )
+
+ def test_with_big_lists(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ - List
+
+ !!! note "Admontion"
+
+ - Paragraph
+
+ Paragraph
+
+ - Paragraph
+
+ paragraph
+ '''
+ ),
+ self.dedent(
+ '''
+ <ul>
+ <li>
+ <p>List</p>
+ <div class="admonition note">
+ <p class="admonition-title">Admontion</p>
+ <ul>
+ <li>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ </li>
+ <li>
+ <p>Paragraph</p>
+ <p>paragraph</p>
+ </li>
+ </ul>
+ </div>
+ </li>
+ </ul>
+ '''
+ ),
+ extensions=['admonition']
+ )
+
+ def test_with_complex_lists(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ - List
+
+ !!! note "Admontion"
+
+ - Paragraph
+
+ !!! note "Admontion"
+
+ 1. Paragraph
+
+ Paragraph
+ '''
+ ),
+ self.dedent(
+ '''
+ <ul>
+ <li>
+ <p>List</p>
+ <div class="admonition note">
+ <p class="admonition-title">Admontion</p>
+ <ul>
+ <li>
+ <p>Paragraph</p>
+ <div class="admonition note">
+ <p class="admonition-title">Admontion</p>
+ <ol>
+ <li>
+ <p>Paragraph</p>
+ <p>Paragraph</p>
+ </li>
+ </ol>
+ </div>
+ </li>
+ </ul>
+ </div>
+ </li>
+ </ul>
+ '''
+ ),
+ extensions=['admonition']
+ )
+
+ def test_definition_list(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ - List
+
+ !!! note "Admontion"
+
+ Term
+
+ : Definition
+
+ More text
+
+ : Another
+ definition
+
+ Even more text
+ '''
+ ),
+ self.dedent(
+ '''
+ <ul>
+ <li>
+ <p>List</p>
+ <div class="admonition note">
+ <p class="admonition-title">Admontion</p>
+ <dl>
+ <dt>Term</dt>
+ <dd>
+ <p>Definition</p>
+ <p>More text</p>
+ </dd>
+ <dd>
+ <p>Another
+ definition</p>
+ <p>Even more text</p>
+ </dd>
+ </dl>
+ </div>
+ </li>
+ </ul>
+ '''
+ ),
+ extensions=['admonition', 'def_list']
+ )
+
+ def test_with_preceding_text(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ foo
+ **foo**
+ !!! note "Admonition"
+ '''
+ ),
+ self.dedent(
+ '''
+ <p>foo
+ <strong>foo</strong></p>
+ <div class="admonition note">
+ <p class="admonition-title">Admonition</p>
+ </div>
+ '''
+ ),
+ extensions=['admonition']
+ )
+
+ def test_admontion_detabbing(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ !!! note "Admonition"
+ - Parent 1
+
+ - Child 1
+ - Child 2
+ '''
+ ),
+ self.dedent(
+ '''
+ <div class="admonition note">
+ <p class="admonition-title">Admonition</p>
+ <ul>
+ <li>
+ <p>Parent 1</p>
+ <ul>
+ <li>Child 1</li>
+ <li>Child 2</li>
+ </ul>
+ </li>
+ </ul>
+ </div>
+ '''
+ ),
+ extensions=['admonition']
+ )
diff --git a/tests/test_syntax/extensions/test_attr_list.py b/tests/test_syntax/extensions/test_attr_list.py
new file mode 100644
index 0000000..6baaafb
--- /dev/null
+++ b/tests/test_syntax/extensions/test_attr_list.py
@@ -0,0 +1,80 @@
+"""
+Python Markdown
+
+A Python implementation of John Gruber's Markdown.
+
+Documentation: https://python-markdown.github.io/
+GitHub: https://github.com/Python-Markdown/markdown/
+PyPI: https://pypi.org/project/Markdown/
+
+Started by Manfred Stienstra (http://www.dwerg.net/).
+Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
+Currently maintained by Waylan Limberg (https://github.com/waylan),
+Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
+
+Copyright 2007-2020 The Python Markdown Project (v. 1.7 and later)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see LICENSE.md for details).
+"""
+
+from markdown.test_tools import TestCase
+
+
+class TestAttrList(TestCase):
+
+ maxDiff = None
+
+ # TODO: Move the rest of the attr_list tests here.
+
+ def test_empty_list(self):
+ self.assertMarkdownRenders(
+ '*foo*{ }',
+ '<p><em>foo</em>{ }</p>',
+ extensions=['attr_list']
+ )
+
+ def test_table_td(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ | A { .foo } | *B*{ .foo } | C { } | D{ .foo } | E { .foo } F |
+ |-------------|-------------|-------|---------------|--------------|
+ | a { .foo } | *b*{ .foo } | c { } | d{ .foo } | e { .foo } f |
+ | valid on td | inline | empty | missing space | not at end |
+ """
+ ),
+ self.dedent(
+ """
+ <table>
+ <thead>
+ <tr>
+ <th class="foo">A</th>
+ <th><em class="foo">B</em></th>
+ <th>C { }</th>
+ <th>D{ .foo }</th>
+ <th>E { .foo } F</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td class="foo">a</td>
+ <td><em class="foo">b</em></td>
+ <td>c { }</td>
+ <td>d{ .foo }</td>
+ <td>e { .foo } f</td>
+ </tr>
+ <tr>
+ <td>valid on td</td>
+ <td>inline</td>
+ <td>empty</td>
+ <td>missing space</td>
+ <td>not at end</td>
+ </tr>
+ </tbody>
+ </table>
+ """
+ ),
+ extensions=['attr_list', 'tables']
+ )
diff --git a/tests/test_syntax/extensions/test_code_hilite.py b/tests/test_syntax/extensions/test_code_hilite.py
new file mode 100644
index 0000000..09dd523
--- /dev/null
+++ b/tests/test_syntax/extensions/test_code_hilite.py
@@ -0,0 +1,764 @@
+"""
+Python Markdown
+
+A Python implementation of John Gruber's Markdown.
+
+Documentation: https://python-markdown.github.io/
+GitHub: https://github.com/Python-Markdown/markdown/
+PyPI: https://pypi.org/project/Markdown/
+
+Started by Manfred Stienstra (http://www.dwerg.net/).
+Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
+Currently maintained by Waylan Limberg (https://github.com/waylan),
+Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
+
+Copyright 2007-2019 The Python Markdown Project (v. 1.7 and later)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see LICENSE.md for details).
+"""
+
+from markdown.test_tools import TestCase
+from markdown.extensions.codehilite import CodeHiliteExtension, CodeHilite
+import os
+
+try:
+ import pygments # noqa
+ has_pygments = True
+except ImportError:
+ has_pygments = False
+
+# The version required by the tests is the version specified and installed in the 'pygments' tox env.
+# In any environment where the PYGMENTS_VERSION environment variable is either not defined or doesn't
+# match the version of Pygments installed, all tests which rely in pygments will be skipped.
+required_pygments_version = os.environ.get('PYGMENTS_VERSION', '')
+
+
+class TestCodeHiliteClass(TestCase):
+ """ Test the markdown.extensions.codehilite.CodeHilite class. """
+
+ def setUp(self):
+ if has_pygments and pygments.__version__ != required_pygments_version:
+ self.skipTest(f'Pygments=={required_pygments_version} is required')
+
+ maxDiff = None
+
+ def assertOutputEquals(self, source, expected, **options):
+ """
+ Test that source code block results in the expected output with given options.
+ """
+
+ output = CodeHilite(source, **options).hilite()
+ self.assertMultiLineEqual(output.strip(), expected)
+
+ def test_codehilite_defaults(self):
+ if has_pygments:
+ # Odd result as no lang given and a single comment is not enough for guessing.
+ expected = (
+ '<div class="codehilite"><pre><span></span><code><span class="err"># A Code Comment</span>\n'
+ '</code></pre></div>'
+ )
+ else:
+ expected = (
+ '<pre class="codehilite"><code># A Code Comment\n'
+ '</code></pre>'
+ )
+ self.assertOutputEquals('# A Code Comment', expected)
+
+ def test_codehilite_guess_lang(self):
+ if has_pygments:
+ expected = (
+ '<div class="codehilite"><pre><span></span><code><span class="cp">&lt;?php</span> '
+ '<span class="k">print</span><span class="p">(</span><span class="s2">&quot;Hello World&quot;</span>'
+ '<span class="p">);</span> <span class="cp">?&gt;</span>\n'
+ '</code></pre></div>'
+ )
+ else:
+ expected = (
+ '<pre class="codehilite"><code>&lt;?php print(&quot;Hello World&quot;); ?&gt;\n'
+ '</code></pre>'
+ )
+ # Use PHP as the the starting `<?php` tag ensures an accurate guess.
+ self.assertOutputEquals('<?php print("Hello World"); ?>', expected, guess_lang=True)
+
+ def test_codehilite_guess_lang_plain_text(self):
+ if has_pygments:
+ expected = (
+ '<div class="codehilite"><pre><span></span><code><span class="err">plain text</span>\n'
+ '</code></pre></div>'
+ )
+ else:
+ expected = (
+ '<pre class="codehilite"><code>plain text\n'
+ '</code></pre>'
+ )
+ # This will be difficult to guess.
+ self.assertOutputEquals('plain text', expected, guess_lang=True)
+
+ def test_codehilite_set_lang(self):
+ if has_pygments:
+ # Note an extra `<span class="x">` is added to end of code block when lang explicitly set.
+ # Compare with expected output for `test_guess_lang`. Not sure why this happens.
+ expected = (
+ '<div class="codehilite"><pre><span></span><code><span class="cp">&lt;?php</span> '
+ '<span class="k">print</span><span class="p">(</span><span class="s2">&quot;Hello World&quot;</span>'
+ '<span class="p">);</span> <span class="cp">?&gt;</span><span class="x"></span>\n'
+ '</code></pre></div>'
+ )
+ else:
+ expected = (
+ '<pre class="codehilite"><code class="language-php">&lt;?php print(&quot;Hello World&quot;); ?&gt;\n'
+ '</code></pre>'
+ )
+ self.assertOutputEquals('<?php print("Hello World"); ?>', expected, lang='php')
+
+ def test_codehilite_bad_lang(self):
+ if has_pygments:
+ expected = (
+ '<div class="codehilite"><pre><span></span><code><span class="cp">&lt;?php</span> '
+ '<span class="k">print</span><span class="p">(</span><span class="s2">'
+ '&quot;Hello World&quot;</span><span class="p">);</span> <span class="cp">?&gt;</span>\n'
+ '</code></pre></div>'
+ )
+ else:
+ # Note that without pygments there is no way to check that the language name is bad.
+ expected = (
+ '<pre class="codehilite"><code class="language-unkown">'
+ '&lt;?php print(&quot;Hello World&quot;); ?&gt;\n'
+ '</code></pre>'
+ )
+ # The starting `<?php` tag ensures an accurate guess.
+ self.assertOutputEquals('<?php print("Hello World"); ?>', expected, lang='unkown')
+
+ def test_codehilite_use_pygments_false(self):
+ expected = (
+ '<pre class="codehilite"><code class="language-php">&lt;?php print(&quot;Hello World&quot;); ?&gt;\n'
+ '</code></pre>'
+ )
+ self.assertOutputEquals('<?php print("Hello World"); ?>', expected, lang='php', use_pygments=False)
+
+ def test_codehilite_lang_prefix_empty(self):
+ expected = (
+ '<pre class="codehilite"><code class="php">&lt;?php print(&quot;Hello World&quot;); ?&gt;\n'
+ '</code></pre>'
+ )
+ self.assertOutputEquals(
+ '<?php print("Hello World"); ?>', expected, lang='php', use_pygments=False, lang_prefix=''
+ )
+
+ def test_codehilite_lang_prefix(self):
+ expected = (
+ '<pre class="codehilite"><code class="lang-php">&lt;?php print(&quot;Hello World&quot;); ?&gt;\n'
+ '</code></pre>'
+ )
+ self.assertOutputEquals(
+ '<?php print("Hello World"); ?>', expected, lang='php', use_pygments=False, lang_prefix='lang-'
+ )
+
+ def test_codehilite_linenos_true(self):
+ if has_pygments:
+ expected = (
+ '<table class="codehilitetable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div>'
+ '</td><td class="code"><div class="codehilite"><pre><span></span><code>plain text\n'
+ '</code></pre></div>\n'
+ '</td></tr></table>'
+ )
+ else:
+ expected = (
+ '<pre class="codehilite"><code class="language-text linenums">plain text\n'
+ '</code></pre>'
+ )
+ self.assertOutputEquals('plain text', expected, lang='text', linenos=True)
+
+ def test_codehilite_linenos_false(self):
+ if has_pygments:
+ expected = (
+ '<div class="codehilite"><pre><span></span><code>plain text\n'
+ '</code></pre></div>'
+ )
+ else:
+ expected = (
+ '<pre class="codehilite"><code class="language-text">plain text\n'
+ '</code></pre>'
+ )
+ self.assertOutputEquals('plain text', expected, lang='text', linenos=False)
+
+ def test_codehilite_linenos_none(self):
+ if has_pygments:
+ expected = (
+ '<div class="codehilite"><pre><span></span><code>plain text\n'
+ '</code></pre></div>'
+ )
+ else:
+ expected = (
+ '<pre class="codehilite"><code class="language-text">plain text\n'
+ '</code></pre>'
+ )
+ self.assertOutputEquals('plain text', expected, lang='text', linenos=None)
+
+ def test_codehilite_linenos_table(self):
+ if has_pygments:
+ expected = (
+ '<table class="codehilitetable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div>'
+ '</td><td class="code"><div class="codehilite"><pre><span></span><code>plain text\n'
+ '</code></pre></div>\n'
+ '</td></tr></table>'
+ )
+ else:
+ expected = (
+ '<pre class="codehilite"><code class="language-text linenums">plain text\n'
+ '</code></pre>'
+ )
+ self.assertOutputEquals('plain text', expected, lang='text', linenos='table')
+
+ def test_codehilite_linenos_inline(self):
+ if has_pygments:
+ expected = (
+ '<div class="codehilite"><pre><span></span><code><span class="linenos">1</span>plain text\n'
+ '</code></pre></div>'
+ )
+ else:
+ expected = (
+ '<pre class="codehilite"><code class="language-text linenums">plain text\n'
+ '</code></pre>'
+ )
+ self.assertOutputEquals('plain text', expected, lang='text', linenos='inline')
+
+ def test_codehilite_linenums_true(self):
+ if has_pygments:
+ expected = (
+ '<table class="codehilitetable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div>'
+ '</td><td class="code"><div class="codehilite"><pre><span></span><code>plain text\n'
+ '</code></pre></div>\n'
+ '</td></tr></table>'
+ )
+ else:
+ expected = (
+ '<pre class="codehilite"><code class="language-text linenums">plain text\n'
+ '</code></pre>'
+ )
+ self.assertOutputEquals('plain text', expected, lang='text', linenums=True)
+
+ def test_codehilite_set_cssclass(self):
+ if has_pygments:
+ expected = (
+ '<div class="override"><pre><span></span><code>plain text\n'
+ '</code></pre></div>'
+ )
+ else:
+ expected = (
+ '<pre class="override"><code class="language-text">plain text\n'
+ '</code></pre>'
+ )
+ self.assertOutputEquals('plain text', expected, lang='text', cssclass='override')
+
+ def test_codehilite_set_css_class(self):
+ if has_pygments:
+ expected = (
+ '<div class="override"><pre><span></span><code>plain text\n'
+ '</code></pre></div>'
+ )
+ else:
+ expected = (
+ '<pre class="override"><code class="language-text">plain text\n'
+ '</code></pre>'
+ )
+ self.assertOutputEquals('plain text', expected, lang='text', css_class='override')
+
+ def test_codehilite_linenostart(self):
+ if has_pygments:
+ expected = (
+ '<div class="codehilite"><pre><span></span><code><span class="linenos">42</span>plain text\n'
+ '</code></pre></div>'
+ )
+ else:
+ # TODO: Implement linenostart for no-pygments. Will need to check what JS libs look for.
+ expected = (
+ '<pre class="codehilite"><code class="language-text linenums">plain text\n'
+ '</code></pre>'
+ )
+ self.assertOutputEquals('plain text', expected, lang='text', linenos='inline', linenostart=42)
+
+ def test_codehilite_linenos_hl_lines(self):
+ if has_pygments:
+ expected = (
+ '<div class="codehilite"><pre><span></span><code>'
+ '<span class="linenos">1</span><span class="hll">line 1\n'
+ '</span><span class="linenos">2</span>line 2\n'
+ '<span class="linenos">3</span><span class="hll">line 3\n'
+ '</span></code></pre></div>'
+ )
+ else:
+ expected = (
+ '<pre class="codehilite"><code class="language-text linenums">line 1\n'
+ 'line 2\n'
+ 'line 3\n'
+ '</code></pre>'
+ )
+ self.assertOutputEquals('line 1\nline 2\nline 3', expected, lang='text', linenos='inline', hl_lines=[1, 3])
+
+ def test_codehilite_linenos_linenostep(self):
+ if has_pygments:
+ expected = (
+ '<div class="codehilite"><pre><span></span><code><span class="linenos"> </span>line 1\n'
+ '<span class="linenos">2</span>line 2\n'
+ '<span class="linenos"> </span>line 3\n'
+ '</code></pre></div>'
+ )
+ else:
+ expected = (
+ '<pre class="codehilite"><code class="language-text linenums">line 1\n'
+ 'line 2\n'
+ 'line 3\n'
+ '</code></pre>'
+ )
+ self.assertOutputEquals('line 1\nline 2\nline 3', expected, lang='text', linenos='inline', linenostep=2)
+
+ def test_codehilite_linenos_linenospecial(self):
+ if has_pygments:
+ expected = (
+ '<div class="codehilite"><pre><span></span><code><span class="linenos">1</span>line 1\n'
+ '<span class="linenos special">2</span>line 2\n'
+ '<span class="linenos">3</span>line 3\n'
+ '</code></pre></div>'
+ )
+ else:
+ expected = (
+ '<pre class="codehilite"><code class="language-text linenums">line 1\n'
+ 'line 2\n'
+ 'line 3\n'
+ '</code></pre>'
+ )
+ self.assertOutputEquals('line 1\nline 2\nline 3', expected, lang='text', linenos='inline', linenospecial=2)
+
+ def test_codehilite_startinline(self):
+ if has_pygments:
+ expected = (
+ '<div class="codehilite"><pre><span></span><code><span class="k">print</span><span class="p">(</span>'
+ '<span class="s2">&quot;Hello World&quot;</span><span class="p">);</span>\n'
+ '</code></pre></div>'
+ )
+ else:
+ expected = (
+ '<pre class="codehilite"><code class="language-php">print(&quot;Hello World&quot;);\n'
+ '</code></pre>'
+ )
+ self.assertOutputEquals('print("Hello World");', expected, lang='php', startinline=True)
+
+
+class TestCodeHiliteExtension(TestCase):
+ """ Test codehilite extension. """
+
+ def setUp(self):
+ if has_pygments and pygments.__version__ != required_pygments_version:
+ self.skipTest(f'Pygments=={required_pygments_version} is required')
+
+ # Define a custom Pygments formatter (same example in the documentation)
+ if has_pygments:
+ class CustomAddLangHtmlFormatter(pygments.formatters.HtmlFormatter):
+ def __init__(self, lang_str='', **options):
+ super().__init__(**options)
+ self.lang_str = lang_str
+
+ def _wrap_code(self, source):
+ yield 0, f'<code class="{self.lang_str}">'
+ yield from source
+ yield 0, '</code>'
+ else:
+ CustomAddLangHtmlFormatter = None
+
+ self.custom_pygments_formatter = CustomAddLangHtmlFormatter
+
+ maxDiff = None
+
+ def testBasicCodeHilite(self):
+ if has_pygments:
+ # Odd result as no lang given and a single comment is not enough for guessing.
+ expected = (
+ '<div class="codehilite"><pre><span></span><code><span class="err"># A Code Comment</span>\n'
+ '</code></pre></div>'
+ )
+ else:
+ expected = (
+ '<pre class="codehilite"><code># A Code Comment\n'
+ '</code></pre>'
+ )
+ self.assertMarkdownRenders(
+ '\t# A Code Comment',
+ expected,
+ extensions=['codehilite']
+ )
+
+ def testLinenumsTrue(self):
+ if has_pygments:
+ expected = (
+ '<table class="codehilitetable"><tr>'
+ '<td class="linenos"><div class="linenodiv"><pre>1</pre></div></td>'
+ '<td class="code"><div class="codehilite"><pre><span></span>'
+ '<code><span class="err"># A Code Comment</span>\n'
+ '</code></pre></div>\n'
+ '</td></tr></table>'
+ )
+ else:
+ expected = (
+ '<pre class="codehilite"><code class="linenums"># A Code Comment\n'
+ '</code></pre>'
+ )
+ self.assertMarkdownRenders(
+ '\t# A Code Comment',
+ expected,
+ extensions=[CodeHiliteExtension(linenums=True)]
+ )
+
+ def testLinenumsFalse(self):
+ if has_pygments:
+ expected = (
+ '<div class="codehilite"><pre><span></span><code><span class="c1"># A Code Comment</span>\n'
+ '</code></pre></div>'
+ )
+ else:
+ expected = (
+ '<pre class="codehilite"><code class="language-python"># A Code Comment\n'
+ '</code></pre>'
+ )
+ self.assertMarkdownRenders(
+ (
+ '\t#!Python\n'
+ '\t# A Code Comment'
+ ),
+ expected,
+ extensions=[CodeHiliteExtension(linenums=False)]
+ )
+
+ def testLinenumsNone(self):
+ if has_pygments:
+ expected = (
+ '<div class="codehilite"><pre><span></span><code><span class="err"># A Code Comment</span>\n'
+ '</code></pre></div>'
+ )
+ else:
+ expected = (
+ '<pre class="codehilite"><code># A Code Comment\n'
+ '</code></pre>'
+ )
+ self.assertMarkdownRenders(
+ '\t# A Code Comment',
+ expected,
+ extensions=[CodeHiliteExtension(linenums=None)]
+ )
+
+ def testLinenumsNoneWithShebang(self):
+ if has_pygments:
+ expected = (
+ '<table class="codehilitetable"><tr>'
+ '<td class="linenos"><div class="linenodiv"><pre>1</pre></div></td>'
+ '<td class="code"><div class="codehilite"><pre><span></span>'
+ '<code><span class="c1"># A Code Comment</span>\n'
+ '</code></pre></div>\n'
+ '</td></tr></table>'
+ )
+ else:
+ expected = (
+ '<pre class="codehilite"><code class="language-python linenums"># A Code Comment\n'
+ '</code></pre>'
+ )
+ self.assertMarkdownRenders(
+ (
+ '\t#!Python\n'
+ '\t# A Code Comment'
+ ),
+ expected,
+ extensions=[CodeHiliteExtension(linenums=None)]
+ )
+
+ def testLinenumsNoneWithColon(self):
+ if has_pygments:
+ expected = (
+ '<div class="codehilite"><pre><span></span><code><span class="c1"># A Code Comment</span>\n'
+ '</code></pre></div>'
+ )
+ else:
+ expected = (
+ '<pre class="codehilite"><code class="language-python"># A Code Comment\n'
+ '</code></pre>'
+ )
+ self.assertMarkdownRenders(
+ (
+ '\t:::Python\n'
+ '\t# A Code Comment'
+ ),
+ expected,
+ extensions=[CodeHiliteExtension(linenums=None)]
+ )
+
+ def testHighlightLinesWithColon(self):
+ if has_pygments:
+ expected = (
+ '<div class="codehilite"><pre><span></span><code><span class="hll"><span class="c1">#line 1</span>\n'
+ '</span><span class="c1">#line 2</span>\n'
+ '<span class="c1">#line 3</span>\n'
+ '</code></pre></div>'
+ )
+ else:
+ expected = (
+ '<pre class="codehilite"><code class="language-python">#line 1\n'
+ '#line 2\n'
+ '#line 3\n'
+ '</code></pre>'
+ )
+ # Double quotes
+ self.assertMarkdownRenders(
+ (
+ '\t:::Python hl_lines="1"\n'
+ '\t#line 1\n'
+ '\t#line 2\n'
+ '\t#line 3'
+ ),
+ expected,
+ extensions=['codehilite']
+ )
+ # Single quotes
+ self.assertMarkdownRenders(
+ (
+ "\t:::Python hl_lines='1'\n"
+ '\t#line 1\n'
+ '\t#line 2\n'
+ '\t#line 3'
+ ),
+ expected,
+ extensions=['codehilite']
+ )
+
+ def testUsePygmentsFalse(self):
+ self.assertMarkdownRenders(
+ (
+ '\t:::Python\n'
+ '\t# A Code Comment'
+ ),
+ (
+ '<pre class="codehilite"><code class="language-python"># A Code Comment\n'
+ '</code></pre>'
+ ),
+ extensions=[CodeHiliteExtension(use_pygments=False)]
+ )
+
+ def testLangPrefixEmpty(self):
+ self.assertMarkdownRenders(
+ (
+ '\t:::Python\n'
+ '\t# A Code Comment'
+ ),
+ (
+ '<pre class="codehilite"><code class="python"># A Code Comment\n'
+ '</code></pre>'
+ ),
+ extensions=[CodeHiliteExtension(use_pygments=False, lang_prefix='')]
+ )
+
+ def testLangPrefix(self):
+ self.assertMarkdownRenders(
+ (
+ '\t:::Python\n'
+ '\t# A Code Comment'
+ ),
+ (
+ '<pre class="codehilite"><code class="lang-python"># A Code Comment\n'
+ '</code></pre>'
+ ),
+ extensions=[CodeHiliteExtension(use_pygments=False, lang_prefix='lang-')]
+ )
+
+ def testDoubleEscape(self):
+ if has_pygments:
+ expected = (
+ '<div class="codehilite"><pre>'
+ '<span></span>'
+ '<code><span class="p">&lt;</span><span class="nt">span</span><span class="p">&gt;</span>'
+ 'This<span class="ni">&amp;amp;</span>That'
+ '<span class="p">&lt;/</span><span class="nt">span</span><span class="p">&gt;</span>'
+ '\n</code></pre></div>'
+ )
+ else:
+ expected = (
+ '<pre class="codehilite"><code class="language-html">'
+ '&lt;span&gt;This&amp;amp;That&lt;/span&gt;\n'
+ '</code></pre>'
+ )
+ self.assertMarkdownRenders(
+ (
+ '\t:::html\n'
+ '\t<span>This&amp;That</span>'
+ ),
+ expected,
+ extensions=['codehilite']
+ )
+
+ def testEntitiesIntact(self):
+ if has_pygments:
+ expected = (
+ '<div class="codehilite"><pre>'
+ '<span></span>'
+ '<code>&lt; &amp;lt; and &gt; &amp;gt;'
+ '\n</code></pre></div>'
+ )
+ else:
+ expected = (
+ '<pre class="codehilite"><code class="language-text">'
+ '&lt; &amp;lt; and &gt; &amp;gt;\n'
+ '</code></pre>'
+ )
+ self.assertMarkdownRenders(
+ (
+ '\t:::text\n'
+ '\t< &lt; and > &gt;'
+ ),
+ expected,
+ extensions=['codehilite']
+ )
+
+ def testHighlightAmps(self):
+ if has_pygments:
+ expected = (
+ '<div class="codehilite"><pre><span></span><code>&amp;\n'
+ '&amp;amp;\n'
+ '&amp;amp;amp;\n'
+ '</code></pre></div>'
+ )
+ else:
+ expected = (
+ '<pre class="codehilite"><code class="language-text">&amp;\n'
+ '&amp;amp;\n'
+ '&amp;amp;amp;\n'
+ '</code></pre>'
+ )
+ self.assertMarkdownRenders(
+ (
+ '\t:::text\n'
+ '\t&\n'
+ '\t&amp;\n'
+ '\t&amp;amp;'
+ ),
+ expected,
+ extensions=['codehilite']
+ )
+
+ def testUnknownOption(self):
+ if has_pygments:
+ # Odd result as no lang given and a single comment is not enough for guessing.
+ expected = (
+ '<div class="codehilite"><pre><span></span><code><span class="err"># A Code Comment</span>\n'
+ '</code></pre></div>'
+ )
+ else:
+ expected = (
+ '<pre class="codehilite"><code># A Code Comment\n'
+ '</code></pre>'
+ )
+ self.assertMarkdownRenders(
+ '\t# A Code Comment',
+ expected,
+ extensions=[CodeHiliteExtension(unknown='some value')],
+ )
+
+ def testMultipleBlocksSameStyle(self):
+ if has_pygments:
+ # See also: https://github.com/Python-Markdown/markdown/issues/1240
+ expected = (
+ '<div class="codehilite" style="background: #202020"><pre style="line-height: 125%; margin: 0;">'
+ '<span></span><code><span style="color: #999999; font-style: italic"># First Code Block</span>\n'
+ '</code></pre></div>\n\n'
+ '<p>Normal paragraph</p>\n'
+ '<div class="codehilite" style="background: #202020"><pre style="line-height: 125%; margin: 0;">'
+ '<span></span><code><span style="color: #999999; font-style: italic"># Second Code Block</span>\n'
+ '</code></pre></div>'
+ )
+ else:
+ expected = (
+ '<pre class="codehilite"><code class="language-python"># First Code Block\n'
+ '</code></pre>\n\n'
+ '<p>Normal paragraph</p>\n'
+ '<pre class="codehilite"><code class="language-python"># Second Code Block\n'
+ '</code></pre>'
+ )
+ self.assertMarkdownRenders(
+ (
+ '\t:::Python\n'
+ '\t# First Code Block\n\n'
+ 'Normal paragraph\n\n'
+ '\t:::Python\n'
+ '\t# Second Code Block'
+ ),
+ expected,
+ extensions=[CodeHiliteExtension(pygments_style="native", noclasses=True)]
+ )
+
+ def testFormatterLangStr(self):
+ if has_pygments:
+ expected = (
+ '<div class="codehilite"><pre><span></span><code class="language-python">'
+ '<span class="c1"># A Code Comment</span>\n'
+ '</code></pre></div>'
+ )
+ else:
+ expected = (
+ '<pre class="codehilite"><code class="language-python"># A Code Comment\n'
+ '</code></pre>'
+ )
+
+ self.assertMarkdownRenders(
+ '\t:::Python\n'
+ '\t# A Code Comment',
+ expected,
+ extensions=[
+ CodeHiliteExtension(
+ guess_lang=False,
+ pygments_formatter=self.custom_pygments_formatter
+ )
+ ]
+ )
+
+ def testFormatterLangStrGuessLang(self):
+ if has_pygments:
+ expected = (
+ '<div class="codehilite"><pre><span></span>'
+ '<code class="language-js+php"><span class="cp">&lt;?php</span> '
+ '<span class="k">print</span><span class="p">(</span>'
+ '<span class="s2">&quot;Hello World&quot;</span>'
+ '<span class="p">);</span> <span class="cp">?&gt;</span>\n'
+ '</code></pre></div>'
+ )
+ else:
+ expected = (
+ '<pre class="codehilite"><code>&lt;?php print(&quot;Hello World&quot;); ?&gt;\n'
+ '</code></pre>'
+ )
+ # Use PHP as the the starting `<?php` tag ensures an accurate guess.
+ self.assertMarkdownRenders(
+ '\t<?php print("Hello World"); ?>',
+ expected,
+ extensions=[CodeHiliteExtension(pygments_formatter=self.custom_pygments_formatter)]
+ )
+
+ def testFormatterLangStrEmptyLang(self):
+ if has_pygments:
+ expected = (
+ '<div class="codehilite"><pre><span></span>'
+ '<code class="language-text"># A Code Comment\n'
+ '</code></pre></div>'
+ )
+ else:
+ expected = (
+ '<pre class="codehilite"><code># A Code Comment\n'
+ '</code></pre>'
+ )
+ self.assertMarkdownRenders(
+ '\t# A Code Comment',
+ expected,
+ extensions=[
+ CodeHiliteExtension(
+ guess_lang=False,
+ pygments_formatter=self.custom_pygments_formatter,
+ )
+ ]
+ )
diff --git a/tests/test_syntax/extensions/test_def_list.py b/tests/test_syntax/extensions/test_def_list.py
new file mode 100644
index 0000000..8273410
--- /dev/null
+++ b/tests/test_syntax/extensions/test_def_list.py
@@ -0,0 +1,323 @@
+"""
+Python Markdown
+
+A Python implementation of John Gruber's Markdown.
+
+Documentation: https://python-markdown.github.io/
+GitHub: https://github.com/Python-Markdown/markdown/
+PyPI: https://pypi.org/project/Markdown/
+
+Started by Manfred Stienstra (http://www.dwerg.net/).
+Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
+Currently maintained by Waylan Limberg (https://github.com/waylan),
+Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
+
+Copyright 2007-2019 The Python Markdown Project (v. 1.7 and later)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see LICENSE.md for details).
+"""
+
+from markdown.test_tools import TestCase
+
+
+class TestDefList(TestCase):
+
+ def test_def_list_with_ol(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+
+ term
+
+ : this is a definition for term. it has
+ multiple lines in the first paragraph.
+
+ 1. first thing
+
+ first thing details in a second paragraph.
+
+ 1. second thing
+
+ second thing details in a second paragraph.
+
+ 1. third thing
+
+ third thing details in a second paragraph.
+ '''
+ ),
+ self.dedent(
+ '''
+ <dl>
+ <dt>term</dt>
+ <dd>
+ <p>this is a definition for term. it has
+ multiple lines in the first paragraph.</p>
+ <ol>
+ <li>
+ <p>first thing</p>
+ <p>first thing details in a second paragraph.</p>
+ </li>
+ <li>
+ <p>second thing</p>
+ <p>second thing details in a second paragraph.</p>
+ </li>
+ <li>
+ <p>third thing</p>
+ <p>third thing details in a second paragraph.</p>
+ </li>
+ </ol>
+ </dd>
+ </dl>
+ '''
+ ),
+ extensions=['def_list']
+ )
+
+ def test_def_list_with_ul(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+
+ term
+
+ : this is a definition for term. it has
+ multiple lines in the first paragraph.
+
+ - first thing
+
+ first thing details in a second paragraph.
+
+ - second thing
+
+ second thing details in a second paragraph.
+
+ - third thing
+
+ third thing details in a second paragraph.
+ '''
+ ),
+ self.dedent(
+ '''
+ <dl>
+ <dt>term</dt>
+ <dd>
+ <p>this is a definition for term. it has
+ multiple lines in the first paragraph.</p>
+ <ul>
+ <li>
+ <p>first thing</p>
+ <p>first thing details in a second paragraph.</p>
+ </li>
+ <li>
+ <p>second thing</p>
+ <p>second thing details in a second paragraph.</p>
+ </li>
+ <li>
+ <p>third thing</p>
+ <p>third thing details in a second paragraph.</p>
+ </li>
+ </ul>
+ </dd>
+ </dl>
+ '''
+ ),
+ extensions=['def_list']
+ )
+
+ def test_def_list_with_nesting(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+
+ term
+
+ : this is a definition for term. it has
+ multiple lines in the first paragraph.
+
+ 1. first thing
+
+ first thing details in a second paragraph.
+
+ - first nested thing
+
+ second nested thing details
+ '''
+ ),
+ self.dedent(
+ '''
+ <dl>
+ <dt>term</dt>
+ <dd>
+ <p>this is a definition for term. it has
+ multiple lines in the first paragraph.</p>
+ <ol>
+ <li>
+ <p>first thing</p>
+ <p>first thing details in a second paragraph.</p>
+ <ul>
+ <li>
+ <p>first nested thing</p>
+ <p>second nested thing details</p>
+ </li>
+ </ul>
+ </li>
+ </ol>
+ </dd>
+ </dl>
+ '''
+ ),
+ extensions=['def_list']
+ )
+
+ def test_def_list_with_nesting_self(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+
+ term
+
+ : this is a definition for term. it has
+ multiple lines in the first paragraph.
+
+ inception
+
+ : this is a definition for term. it has
+ multiple lines in the first paragraph.
+
+ - bullet point
+
+ another paragraph
+ '''
+ ),
+ self.dedent(
+ '''
+ <dl>
+ <dt>term</dt>
+ <dd>
+ <p>this is a definition for term. it has
+ multiple lines in the first paragraph.</p>
+ <dl>
+ <dt>inception</dt>
+ <dd>
+ <p>this is a definition for term. it has
+ multiple lines in the first paragraph.</p>
+ <ul>
+ <li>bullet point</li>
+ </ul>
+ <p>another paragraph</p>
+ </dd>
+ </dl>
+ </dd>
+ </dl>
+ '''
+ ),
+ extensions=['def_list']
+ )
+
+ def test_def_list_unreasonable_nesting(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+
+ turducken
+
+ : this is a definition for term. it has
+ multiple lines in the first paragraph.
+
+ 1. ordered list
+
+ - nested list
+
+ term
+
+ : definition
+
+ - item 1 paragraph 1
+
+ item 1 paragraph 2
+ '''
+ ),
+ self.dedent(
+ '''
+ <dl>
+ <dt>turducken</dt>
+ <dd>
+ <p>this is a definition for term. it has
+ multiple lines in the first paragraph.</p>
+ <ol>
+ <li>
+ <p>ordered list</p>
+ <ul>
+ <li>
+ <p>nested list</p>
+ <dl>
+ <dt>term</dt>
+ <dd>
+ <p>definition</p>
+ <ul>
+ <li>
+ <p>item 1 paragraph 1</p>
+ <p>item 1 paragraph 2</p>
+ </li>
+ </ul>
+ </dd>
+ </dl>
+ </li>
+ </ul>
+ </li>
+ </ol>
+ </dd>
+ </dl>
+ '''
+ ),
+ extensions=['def_list']
+ )
+
+ def test_def_list_nested_admontions(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ term
+
+ : definition
+
+ !!! note "Admontion"
+
+ term
+
+ : definition
+
+ 1. list
+
+ continue
+ '''
+ ),
+ self.dedent(
+ '''
+ <dl>
+ <dt>term</dt>
+ <dd>
+ <p>definition</p>
+ <div class="admonition note">
+ <p class="admonition-title">Admontion</p>
+ <dl>
+ <dt>term</dt>
+ <dd>
+ <p>definition</p>
+ <ol>
+ <li>
+ <p>list</p>
+ <p>continue</p>
+ </li>
+ </ol>
+ </dd>
+ </dl>
+ </div>
+ </dd>
+ </dl>
+ '''
+ ),
+ extensions=['def_list', 'admonition']
+ )
diff --git a/tests/test_syntax/extensions/test_fenced_code.py b/tests/test_syntax/extensions/test_fenced_code.py
new file mode 100644
index 0000000..be3c215
--- /dev/null
+++ b/tests/test_syntax/extensions/test_fenced_code.py
@@ -0,0 +1,1020 @@
+"""
+Python Markdown
+
+A Python implementation of John Gruber's Markdown.
+
+Documentation: https://python-markdown.github.io/
+GitHub: https://github.com/Python-Markdown/markdown/
+PyPI: https://pypi.org/project/Markdown/
+
+Started by Manfred Stienstra (http://www.dwerg.net/).
+Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
+Currently maintained by Waylan Limberg (https://github.com/waylan),
+Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
+
+Copyright 2007-2019 The Python Markdown Project (v. 1.7 and later)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see LICENSE.md for details).
+"""
+
+from markdown.test_tools import TestCase
+import markdown
+import markdown.extensions.codehilite
+import os
+
+try:
+ import pygments # noqa
+ import pygments.formatters # noqa
+ has_pygments = True
+except ImportError:
+ has_pygments = False
+
+# The version required by the tests is the version specified and installed in the 'pygments' tox env.
+# In any environment where the PYGMENTS_VERSION environment variable is either not defined or doesn't
+# match the version of Pygments installed, all tests which rely in pygments will be skipped.
+required_pygments_version = os.environ.get('PYGMENTS_VERSION', '')
+
+
+class TestFencedCode(TestCase):
+
+ def testBasicFence(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ A paragraph before a fenced code block:
+
+ ```
+ Fenced code block
+ ```
+ '''
+ ),
+ self.dedent(
+ '''
+ <p>A paragraph before a fenced code block:</p>
+ <pre><code>Fenced code block
+ </code></pre>
+ '''
+ ),
+ extensions=['fenced_code']
+ )
+
+ def testNestedFence(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ ````
+
+ ```
+ ````
+ '''
+ ),
+ self.dedent(
+ '''
+ <pre><code>
+ ```
+ </code></pre>
+ '''
+ ),
+ extensions=['fenced_code']
+ )
+
+ def testFencedTildes(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ ~~~
+ # Arbitrary code
+ ``` # these backticks will not close the block
+ ~~~
+ '''
+ ),
+ self.dedent(
+ '''
+ <pre><code># Arbitrary code
+ ``` # these backticks will not close the block
+ </code></pre>
+ '''
+ ),
+ extensions=['fenced_code']
+ )
+
+ def testFencedLanguageNoDot(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ ``` python
+ # Some python code
+ ```
+ '''
+ ),
+ self.dedent(
+ '''
+ <pre><code class="language-python"># Some python code
+ </code></pre>
+ '''
+ ),
+ extensions=['fenced_code']
+ )
+
+ def testFencedLanguageWithDot(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ ``` .python
+ # Some python code
+ ```
+ '''
+ ),
+ self.dedent(
+ '''
+ <pre><code class="language-python"># Some python code
+ </code></pre>
+ '''
+ ),
+ extensions=['fenced_code']
+ )
+
+ def test_fenced_code_in_raw_html(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <details>
+ ```
+ Begone placeholders!
+ ```
+ </details>
+ """
+ ),
+ self.dedent(
+ """
+ <details>
+
+ <pre><code>Begone placeholders!
+ </code></pre>
+
+ </details>
+ """
+ ),
+ extensions=['fenced_code']
+ )
+
+ def testFencedLanguageInAttr(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ ``` {.python}
+ # Some python code
+ ```
+ '''
+ ),
+ self.dedent(
+ '''
+ <pre><code class="language-python"># Some python code
+ </code></pre>
+ '''
+ ),
+ extensions=['fenced_code']
+ )
+
+ def testFencedMultipleClassesInAttr(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ ``` {.python .foo .bar}
+ # Some python code
+ ```
+ '''
+ ),
+ self.dedent(
+ '''
+ <pre class="foo bar"><code class="language-python"># Some python code
+ </code></pre>
+ '''
+ ),
+ extensions=['fenced_code']
+ )
+
+ def testFencedIdInAttr(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ ``` { #foo }
+ # Some python code
+ ```
+ '''
+ ),
+ self.dedent(
+ '''
+ <pre id="foo"><code># Some python code
+ </code></pre>
+ '''
+ ),
+ extensions=['fenced_code']
+ )
+
+ def testFencedIdAndLangInAttr(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ ``` { .python #foo }
+ # Some python code
+ ```
+ '''
+ ),
+ self.dedent(
+ '''
+ <pre id="foo"><code class="language-python"># Some python code
+ </code></pre>
+ '''
+ ),
+ extensions=['fenced_code']
+ )
+
+ def testFencedIdAndLangAndClassInAttr(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ ``` { .python #foo .bar }
+ # Some python code
+ ```
+ '''
+ ),
+ self.dedent(
+ '''
+ <pre id="foo" class="bar"><code class="language-python"># Some python code
+ </code></pre>
+ '''
+ ),
+ extensions=['fenced_code']
+ )
+
+ def testFencedLanguageIdAndPygmentsDisabledInAttrNoCodehilite(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ ``` { .python #foo use_pygments=False }
+ # Some python code
+ ```
+ '''
+ ),
+ self.dedent(
+ '''
+ <pre id="foo"><code class="language-python"># Some python code
+ </code></pre>
+ '''
+ ),
+ extensions=['fenced_code']
+ )
+
+ def testFencedLanguageIdAndPygmentsEnabledInAttrNoCodehilite(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ ``` { .python #foo use_pygments=True }
+ # Some python code
+ ```
+ '''
+ ),
+ self.dedent(
+ '''
+ <pre id="foo"><code class="language-python"># Some python code
+ </code></pre>
+ '''
+ ),
+ extensions=['fenced_code']
+ )
+
+ def testFencedLanguageNoCodehiliteWithAttrList(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ ``` { .python foo=bar }
+ # Some python code
+ ```
+ '''
+ ),
+ self.dedent(
+ '''
+ <pre><code class="language-python" foo="bar"># Some python code
+ </code></pre>
+ '''
+ ),
+ extensions=['fenced_code', 'attr_list']
+ )
+
+ def testFencedLanguagePygmentsDisabledInAttrNoCodehiliteWithAttrList(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ ``` { .python foo=bar use_pygments=False }
+ # Some python code
+ ```
+ '''
+ ),
+ self.dedent(
+ '''
+ <pre><code class="language-python" foo="bar"># Some python code
+ </code></pre>
+ '''
+ ),
+ extensions=['fenced_code', 'attr_list']
+ )
+
+ def testFencedLanguagePygmentsEnabledInAttrNoCodehiliteWithAttrList(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ ``` { .python foo=bar use_pygments=True }
+ # Some python code
+ ```
+ '''
+ ),
+ self.dedent(
+ '''
+ <pre><code class="language-python"># Some python code
+ </code></pre>
+ '''
+ ),
+ extensions=['fenced_code', 'attr_list']
+ )
+
+ def testFencedLanguageNoPrefix(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ ``` python
+ # Some python code
+ ```
+ '''
+ ),
+ self.dedent(
+ '''
+ <pre><code class="python"># Some python code
+ </code></pre>
+ '''
+ ),
+ extensions=[markdown.extensions.fenced_code.FencedCodeExtension(lang_prefix='')]
+ )
+
+ def testFencedLanguageAltPrefix(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ ``` python
+ # Some python code
+ ```
+ '''
+ ),
+ self.dedent(
+ '''
+ <pre><code class="lang-python"># Some python code
+ </code></pre>
+ '''
+ ),
+ extensions=[markdown.extensions.fenced_code.FencedCodeExtension(lang_prefix='lang-')]
+ )
+
+ def testFencedCodeEscapedAttrs(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ ``` { ."weird #"foo bar=">baz }
+ # Some python code
+ ```
+ '''
+ ),
+ self.dedent(
+ '''
+ <pre id="&quot;foo"><code class="language-&quot;weird" bar="&quot;&gt;baz"># Some python code
+ </code></pre>
+ '''
+ ),
+ extensions=['fenced_code', 'attr_list']
+ )
+
+
+class TestFencedCodeWithCodehilite(TestCase):
+
+ def setUp(self):
+ if has_pygments and pygments.__version__ != required_pygments_version:
+ self.skipTest(f'Pygments=={required_pygments_version} is required')
+
+ def test_shebang(self):
+
+ if has_pygments:
+ expected = '''
+ <div class="codehilite"><pre><span></span><code>#!test
+ </code></pre></div>
+ '''
+ else:
+ expected = '''
+ <pre class="codehilite"><code>#!test
+ </code></pre>
+ '''
+
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ ```
+ #!test
+ ```
+ '''
+ ),
+ self.dedent(
+ expected
+ ),
+ extensions=[
+ markdown.extensions.codehilite.CodeHiliteExtension(linenums=None, guess_lang=False),
+ 'fenced_code'
+ ]
+ )
+
+ def testFencedCodeWithHighlightLines(self):
+ if has_pygments:
+ expected = self.dedent(
+ '''
+ <div class="codehilite"><pre><span></span><code><span class="hll">line 1
+ </span>line 2
+ <span class="hll">line 3
+ </span></code></pre></div>
+ '''
+ )
+ else:
+ expected = self.dedent(
+ '''
+ <pre class="codehilite"><code>line 1
+ line 2
+ line 3
+ </code></pre>
+ '''
+ )
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ ```hl_lines="1 3"
+ line 1
+ line 2
+ line 3
+ ```
+ '''
+ ),
+ expected,
+ extensions=[
+ markdown.extensions.codehilite.CodeHiliteExtension(linenums=None, guess_lang=False),
+ 'fenced_code'
+ ]
+ )
+
+ def testFencedLanguageAndHighlightLines(self):
+ if has_pygments:
+ expected = (
+ '<div class="codehilite"><pre><span></span><code>'
+ '<span class="hll"><span class="n">line</span> <span class="mi">1</span>\n'
+ '</span><span class="n">line</span> <span class="mi">2</span>\n'
+ '<span class="hll"><span class="n">line</span> <span class="mi">3</span>\n'
+ '</span></code></pre></div>'
+ )
+ else:
+ expected = self.dedent(
+ '''
+ <pre class="codehilite"><code class="language-python">line 1
+ line 2
+ line 3
+ </code></pre>
+ '''
+ )
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ ``` .python hl_lines="1 3"
+ line 1
+ line 2
+ line 3
+ ```
+ '''
+ ),
+ expected,
+ extensions=[
+ markdown.extensions.codehilite.CodeHiliteExtension(linenums=None, guess_lang=False),
+ 'fenced_code'
+ ]
+ )
+
+ def testFencedLanguageAndPygmentsDisabled(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ ``` .python
+ # Some python code
+ ```
+ '''
+ ),
+ self.dedent(
+ '''
+ <pre><code class="language-python"># Some python code
+ </code></pre>
+ '''
+ ),
+ extensions=[
+ markdown.extensions.codehilite.CodeHiliteExtension(use_pygments=False),
+ 'fenced_code'
+ ]
+ )
+
+ def testFencedLanguageDoubleEscape(self):
+ if has_pygments:
+ expected = (
+ '<div class="codehilite"><pre><span></span><code>'
+ '<span class="p">&lt;</span><span class="nt">span</span>'
+ '<span class="p">&gt;</span>This<span class="ni">&amp;amp;</span>'
+ 'That<span class="p">&lt;/</span><span class="nt">span</span>'
+ '<span class="p">&gt;</span>\n'
+ '</code></pre></div>'
+ )
+ else:
+ expected = (
+ '<pre class="codehilite"><code class="language-html">'
+ '&lt;span&gt;This&amp;amp;That&lt;/span&gt;\n'
+ '</code></pre>'
+ )
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ ```html
+ <span>This&amp;That</span>
+ ```
+ '''
+ ),
+ expected,
+ extensions=[
+ markdown.extensions.codehilite.CodeHiliteExtension(),
+ 'fenced_code'
+ ]
+ )
+
+ def testFencedAmps(self):
+ if has_pygments:
+ expected = self.dedent(
+ '''
+ <div class="codehilite"><pre><span></span><code>&amp;
+ &amp;amp;
+ &amp;amp;amp;
+ </code></pre></div>
+ '''
+ )
+ else:
+ expected = self.dedent(
+ '''
+ <pre class="codehilite"><code class="language-text">&amp;
+ &amp;amp;
+ &amp;amp;amp;
+ </code></pre>
+ '''
+ )
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ ```text
+ &
+ &amp;
+ &amp;amp;
+ ```
+ '''
+ ),
+ expected,
+ extensions=[
+ markdown.extensions.codehilite.CodeHiliteExtension(),
+ 'fenced_code'
+ ]
+ )
+
+ def testFencedCodeWithHighlightLinesInAttr(self):
+ if has_pygments:
+ expected = self.dedent(
+ '''
+ <div class="codehilite"><pre><span></span><code><span class="hll">line 1
+ </span>line 2
+ <span class="hll">line 3
+ </span></code></pre></div>
+ '''
+ )
+ else:
+ expected = self.dedent(
+ '''
+ <pre class="codehilite"><code>line 1
+ line 2
+ line 3
+ </code></pre>
+ '''
+ )
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ ```{ hl_lines="1 3" }
+ line 1
+ line 2
+ line 3
+ ```
+ '''
+ ),
+ expected,
+ extensions=[
+ markdown.extensions.codehilite.CodeHiliteExtension(linenums=None, guess_lang=False),
+ 'fenced_code'
+ ]
+ )
+
+ def testFencedLanguageAndHighlightLinesInAttr(self):
+ if has_pygments:
+ expected = (
+ '<div class="codehilite"><pre><span></span><code>'
+ '<span class="hll"><span class="n">line</span> <span class="mi">1</span>\n'
+ '</span><span class="n">line</span> <span class="mi">2</span>\n'
+ '<span class="hll"><span class="n">line</span> <span class="mi">3</span>\n'
+ '</span></code></pre></div>'
+ )
+ else:
+ expected = self.dedent(
+ '''
+ <pre class="codehilite"><code class="language-python">line 1
+ line 2
+ line 3
+ </code></pre>
+ '''
+ )
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ ``` { .python hl_lines="1 3" }
+ line 1
+ line 2
+ line 3
+ ```
+ '''
+ ),
+ expected,
+ extensions=[
+ markdown.extensions.codehilite.CodeHiliteExtension(linenums=None, guess_lang=False),
+ 'fenced_code'
+ ]
+ )
+
+ def testFencedLanguageIdInAttrAndPygmentsDisabled(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ ``` { .python #foo }
+ # Some python code
+ ```
+ '''
+ ),
+ self.dedent(
+ '''
+ <pre id="foo"><code class="language-python"># Some python code
+ </code></pre>
+ '''
+ ),
+ extensions=[
+ markdown.extensions.codehilite.CodeHiliteExtension(use_pygments=False),
+ 'fenced_code'
+ ]
+ )
+
+ def testFencedLanguageIdAndPygmentsDisabledInAttr(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ ``` { .python #foo use_pygments=False }
+ # Some python code
+ ```
+ '''
+ ),
+ self.dedent(
+ '''
+ <pre id="foo"><code class="language-python"># Some python code
+ </code></pre>
+ '''
+ ),
+ extensions=['codehilite', 'fenced_code']
+ )
+
+ def testFencedLanguageAttrCssclass(self):
+ if has_pygments:
+ expected = self.dedent(
+ '''
+ <div class="pygments"><pre><span></span><code><span class="c1"># Some python code</span>
+ </code></pre></div>
+ '''
+ )
+ else:
+ expected = (
+ '<pre class="pygments"><code class="language-python"># Some python code\n'
+ '</code></pre>'
+ )
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ ``` { .python css_class='pygments' }
+ # Some python code
+ ```
+ '''
+ ),
+ expected,
+ extensions=['codehilite', 'fenced_code']
+ )
+
+ def testFencedLanguageAttrLinenums(self):
+ if has_pygments:
+ expected = (
+ '<table class="codehilitetable"><tr>'
+ '<td class="linenos"><div class="linenodiv"><pre>1</pre></div></td>'
+ '<td class="code"><div class="codehilite"><pre><span></span>'
+ '<code><span class="c1"># Some python code</span>\n'
+ '</code></pre></div>\n'
+ '</td></tr></table>'
+ )
+ else:
+ expected = (
+ '<pre class="codehilite"><code class="language-python linenums"># Some python code\n'
+ '</code></pre>'
+ )
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ ``` { .python linenums=True }
+ # Some python code
+ ```
+ '''
+ ),
+ expected,
+ extensions=['codehilite', 'fenced_code']
+ )
+
+ def testFencedLanguageAttrGuesslang(self):
+ if has_pygments:
+ expected = self.dedent(
+ '''
+ <div class="codehilite"><pre><span></span><code># Some python code
+ </code></pre></div>
+ '''
+ )
+ else:
+ expected = (
+ '<pre class="codehilite"><code># Some python code\n'
+ '</code></pre>'
+ )
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ ``` { guess_lang=False }
+ # Some python code
+ ```
+ '''
+ ),
+ expected,
+ extensions=['codehilite', 'fenced_code']
+ )
+
+ def testFencedLanguageAttrNoclasses(self):
+ if has_pygments:
+ expected = (
+ '<div class="codehilite" style="background: #f8f8f8">'
+ '<pre style="line-height: 125%; margin: 0;"><span></span><code>'
+ '<span style="color: #408080; font-style: italic"># Some python code</span>\n'
+ '</code></pre></div>'
+ )
+ else:
+ expected = (
+ '<pre class="codehilite"><code class="language-python"># Some python code\n'
+ '</code></pre>'
+ )
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ ``` { .python noclasses=True }
+ # Some python code
+ ```
+ '''
+ ),
+ expected,
+ extensions=['codehilite', 'fenced_code']
+ )
+
+ def testFencedMultipleBlocksSameStyle(self):
+ if has_pygments:
+ # See also: https://github.com/Python-Markdown/markdown/issues/1240
+ expected = (
+ '<div class="codehilite" style="background: #202020"><pre style="line-height: 125%; margin: 0;">'
+ '<span></span><code><span style="color: #999999; font-style: italic"># First Code Block</span>\n'
+ '</code></pre></div>\n\n'
+ '<p>Normal paragraph</p>\n'
+ '<div class="codehilite" style="background: #202020"><pre style="line-height: 125%; margin: 0;">'
+ '<span></span><code><span style="color: #999999; font-style: italic"># Second Code Block</span>\n'
+ '</code></pre></div>'
+ )
+ else:
+ expected = '''
+ <pre class="codehilite"><code class="language-python"># First Code Block
+ </code></pre>
+
+ <p>Normal paragraph</p>
+ <pre class="codehilite"><code class="language-python"># Second Code Block
+ </code></pre>
+ '''
+
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ ``` { .python }
+ # First Code Block
+ ```
+
+ Normal paragraph
+
+ ``` { .python }
+ # Second Code Block
+ ```
+ '''
+ ),
+ self.dedent(
+ expected
+ ),
+ extensions=[
+ markdown.extensions.codehilite.CodeHiliteExtension(pygments_style="native", noclasses=True),
+ 'fenced_code'
+ ]
+ )
+
+ def testCustomPygmentsFormatter(self):
+ if has_pygments:
+ class CustomFormatter(pygments.formatters.HtmlFormatter):
+ def wrap(self, source, outfile):
+ return self._wrap_div(self._wrap_code(source))
+
+ def _wrap_code(self, source):
+ yield 0, '<code>'
+ for i, t in source:
+ if i == 1:
+ t += '<br>'
+ yield i, t
+ yield 0, '</code>'
+
+ expected = '''
+ <div class="codehilite"><code>hello world
+ <br>hello another world
+ <br></code></div>
+ '''
+
+ else:
+ CustomFormatter = None
+ expected = '''
+ <pre class="codehilite"><code>hello world
+ hello another world
+ </code></pre>
+ '''
+
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ ```
+ hello world
+ hello another world
+ ```
+ '''
+ ),
+ self.dedent(
+ expected
+ ),
+ extensions=[
+ markdown.extensions.codehilite.CodeHiliteExtension(
+ pygments_formatter=CustomFormatter,
+ guess_lang=False,
+ ),
+ 'fenced_code'
+ ]
+ )
+
+ def testPygmentsAddLangClassFormatter(self):
+ if has_pygments:
+ class CustomAddLangHtmlFormatter(pygments.formatters.HtmlFormatter):
+ def __init__(self, lang_str='', **options):
+ super().__init__(**options)
+ self.lang_str = lang_str
+
+ def _wrap_code(self, source):
+ yield 0, f'<code class="{self.lang_str}">'
+ yield from source
+ yield 0, '</code>'
+
+ expected = '''
+ <div class="codehilite"><pre><span></span><code class="language-text">hello world
+ hello another world
+ </code></pre></div>
+ '''
+ else:
+ CustomAddLangHtmlFormatter = None
+ expected = '''
+ <pre class="codehilite"><code class="language-text">hello world
+ hello another world
+ </code></pre>
+ '''
+
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ ```text
+ hello world
+ hello another world
+ ```
+ '''
+ ),
+ self.dedent(
+ expected
+ ),
+ extensions=[
+ markdown.extensions.codehilite.CodeHiliteExtension(
+ guess_lang=False,
+ pygments_formatter=CustomAddLangHtmlFormatter,
+ ),
+ 'fenced_code'
+ ]
+ )
+
+ def testSvgCustomPygmentsFormatter(self):
+ if has_pygments:
+ expected = '''
+ <?xml version="1.0"?>
+ <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+ <svg xmlns="http://www.w3.org/2000/svg">
+ <g font-family="monospace" font-size="14px">
+ <text x="0" y="14" xml:space="preserve">hello&#160;world</text>
+ <text x="0" y="33" xml:space="preserve">hello&#160;another&#160;world</text>
+ <text x="0" y="52" xml:space="preserve"></text></g></svg>
+ '''
+
+ else:
+ expected = '''
+ <pre class="codehilite"><code>hello world
+ hello another world
+ </code></pre>
+ '''
+
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ ```
+ hello world
+ hello another world
+ ```
+ '''
+ ),
+ self.dedent(
+ expected
+ ),
+ extensions=[
+ markdown.extensions.codehilite.CodeHiliteExtension(
+ pygments_formatter='svg',
+ linenos=False,
+ guess_lang=False,
+ ),
+ 'fenced_code'
+ ]
+ )
+
+ def testInvalidCustomPygmentsFormatter(self):
+ if has_pygments:
+ expected = '''
+ <div class="codehilite"><pre><span></span><code>hello world
+ hello another world
+ </code></pre></div>
+ '''
+
+ else:
+ expected = '''
+ <pre class="codehilite"><code>hello world
+ hello another world
+ </code></pre>
+ '''
+
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ ```
+ hello world
+ hello another world
+ ```
+ '''
+ ),
+ self.dedent(
+ expected
+ ),
+ extensions=[
+ markdown.extensions.codehilite.CodeHiliteExtension(
+ pygments_formatter='invalid',
+ guess_lang=False,
+ ),
+ 'fenced_code'
+ ]
+ )
diff --git a/tests/test_syntax/extensions/test_footnotes.py b/tests/test_syntax/extensions/test_footnotes.py
new file mode 100644
index 0000000..9a6b32a
--- /dev/null
+++ b/tests/test_syntax/extensions/test_footnotes.py
@@ -0,0 +1,338 @@
+"""
+Python Markdown
+
+A Python implementation of John Gruber's Markdown.
+
+Documentation: https://python-markdown.github.io/
+GitHub: https://github.com/Python-Markdown/markdown/
+PyPI: https://pypi.org/project/Markdown/
+
+Started by Manfred Stienstra (http://www.dwerg.net/).
+Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
+Currently maintained by Waylan Limberg (https://github.com/waylan),
+Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
+
+Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see LICENSE.md for details).
+"""
+
+from markdown.test_tools import TestCase
+
+
+class TestFootnotes(TestCase):
+
+ default_kwargs = {'extensions': ['footnotes']}
+ maxDiff = None
+
+ def test_basic_footnote(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ paragraph[^1]
+
+ [^1]: A Footnote
+ """
+ ),
+ '<p>paragraph<sup id="fnref:1"><a class="footnote-ref" href="#fn:1">1</a></sup></p>\n'
+ '<div class="footnote">\n'
+ '<hr />\n'
+ '<ol>\n'
+ '<li id="fn:1">\n'
+ '<p>A Footnote&#160;<a class="footnote-backref" href="#fnref:1"'
+ ' title="Jump back to footnote 1 in the text">&#8617;</a></p>\n'
+ '</li>\n'
+ '</ol>\n'
+ '</div>'
+ )
+
+ def test_multiple_footnotes(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ foo[^1]
+
+ bar[^2]
+
+ [^1]: Footnote 1
+ [^2]: Footnote 2
+ """
+ ),
+ '<p>foo<sup id="fnref:1"><a class="footnote-ref" href="#fn:1">1</a></sup></p>\n'
+ '<p>bar<sup id="fnref:2"><a class="footnote-ref" href="#fn:2">2</a></sup></p>\n'
+ '<div class="footnote">\n'
+ '<hr />\n'
+ '<ol>\n'
+ '<li id="fn:1">\n'
+ '<p>Footnote 1&#160;<a class="footnote-backref" href="#fnref:1"'
+ ' title="Jump back to footnote 1 in the text">&#8617;</a></p>\n'
+ '</li>\n'
+ '<li id="fn:2">\n'
+ '<p>Footnote 2&#160;<a class="footnote-backref" href="#fnref:2"'
+ ' title="Jump back to footnote 2 in the text">&#8617;</a></p>\n'
+ '</li>\n'
+ '</ol>\n'
+ '</div>'
+ )
+
+ def test_multiple_footnotes_multiline(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ foo[^1]
+
+ bar[^2]
+
+ [^1]: Footnote 1
+ line 2
+ [^2]: Footnote 2
+ """
+ ),
+ '<p>foo<sup id="fnref:1"><a class="footnote-ref" href="#fn:1">1</a></sup></p>\n'
+ '<p>bar<sup id="fnref:2"><a class="footnote-ref" href="#fn:2">2</a></sup></p>\n'
+ '<div class="footnote">\n'
+ '<hr />\n'
+ '<ol>\n'
+ '<li id="fn:1">\n'
+ '<p>Footnote 1\nline 2&#160;<a class="footnote-backref" href="#fnref:1"'
+ ' title="Jump back to footnote 1 in the text">&#8617;</a></p>\n'
+ '</li>\n'
+ '<li id="fn:2">\n'
+ '<p>Footnote 2&#160;<a class="footnote-backref" href="#fnref:2"'
+ ' title="Jump back to footnote 2 in the text">&#8617;</a></p>\n'
+ '</li>\n'
+ '</ol>\n'
+ '</div>'
+ )
+
+ def test_footnote_multi_line(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ paragraph[^1]
+ [^1]: A Footnote
+ line 2
+ """
+ ),
+ '<p>paragraph<sup id="fnref:1"><a class="footnote-ref" href="#fn:1">1</a></sup></p>\n'
+ '<div class="footnote">\n'
+ '<hr />\n'
+ '<ol>\n'
+ '<li id="fn:1">\n'
+ '<p>A Footnote\nline 2&#160;<a class="footnote-backref" href="#fnref:1"'
+ ' title="Jump back to footnote 1 in the text">&#8617;</a></p>\n'
+ '</li>\n'
+ '</ol>\n'
+ '</div>'
+ )
+
+ def test_footnote_multi_line_lazy_indent(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ paragraph[^1]
+ [^1]: A Footnote
+ line 2
+ """
+ ),
+ '<p>paragraph<sup id="fnref:1"><a class="footnote-ref" href="#fn:1">1</a></sup></p>\n'
+ '<div class="footnote">\n'
+ '<hr />\n'
+ '<ol>\n'
+ '<li id="fn:1">\n'
+ '<p>A Footnote\nline 2&#160;<a class="footnote-backref" href="#fnref:1"'
+ ' title="Jump back to footnote 1 in the text">&#8617;</a></p>\n'
+ '</li>\n'
+ '</ol>\n'
+ '</div>'
+ )
+
+ def test_footnote_multi_line_complex(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ paragraph[^1]
+
+ [^1]:
+
+ A Footnote
+ line 2
+
+ * list item
+
+ > blockquote
+ """
+ ),
+ '<p>paragraph<sup id="fnref:1"><a class="footnote-ref" href="#fn:1">1</a></sup></p>\n'
+ '<div class="footnote">\n'
+ '<hr />\n'
+ '<ol>\n'
+ '<li id="fn:1">\n'
+ '<p>A Footnote\nline 2</p>\n'
+ '<ul>\n<li>list item</li>\n</ul>\n'
+ '<blockquote>\n<p>blockquote</p>\n</blockquote>\n'
+ '<p><a class="footnote-backref" href="#fnref:1"'
+ ' title="Jump back to footnote 1 in the text">&#8617;</a></p>\n'
+ '</li>\n'
+ '</ol>\n'
+ '</div>'
+ )
+
+ def test_footnote_multple_complex(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ foo[^1]
+
+ bar[^2]
+
+ [^1]:
+
+ A Footnote
+ line 2
+
+ * list item
+
+ > blockquote
+
+ [^2]: Second footnote
+
+ paragraph 2
+ """
+ ),
+ '<p>foo<sup id="fnref:1"><a class="footnote-ref" href="#fn:1">1</a></sup></p>\n'
+ '<p>bar<sup id="fnref:2"><a class="footnote-ref" href="#fn:2">2</a></sup></p>\n'
+ '<div class="footnote">\n'
+ '<hr />\n'
+ '<ol>\n'
+ '<li id="fn:1">\n'
+ '<p>A Footnote\nline 2</p>\n'
+ '<ul>\n<li>list item</li>\n</ul>\n'
+ '<blockquote>\n<p>blockquote</p>\n</blockquote>\n'
+ '<p><a class="footnote-backref" href="#fnref:1"'
+ ' title="Jump back to footnote 1 in the text">&#8617;</a></p>\n'
+ '</li>\n'
+ '<li id="fn:2">\n'
+ '<p>Second footnote</p>\n'
+ '<p>paragraph 2&#160;<a class="footnote-backref" href="#fnref:2"'
+ ' title="Jump back to footnote 2 in the text">&#8617;</a></p>\n'
+ '</li>\n'
+ '</ol>\n'
+ '</div>'
+ )
+
+ def test_footnote_multple_complex_no_blank_line_between(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ foo[^1]
+
+ bar[^2]
+
+ [^1]:
+
+ A Footnote
+ line 2
+
+ * list item
+
+ > blockquote
+ [^2]: Second footnote
+
+ paragraph 2
+ """
+ ),
+ '<p>foo<sup id="fnref:1"><a class="footnote-ref" href="#fn:1">1</a></sup></p>\n'
+ '<p>bar<sup id="fnref:2"><a class="footnote-ref" href="#fn:2">2</a></sup></p>\n'
+ '<div class="footnote">\n'
+ '<hr />\n'
+ '<ol>\n'
+ '<li id="fn:1">\n'
+ '<p>A Footnote\nline 2</p>\n'
+ '<ul>\n<li>list item</li>\n</ul>\n'
+ '<blockquote>\n<p>blockquote</p>\n</blockquote>\n'
+ '<p><a class="footnote-backref" href="#fnref:1"'
+ ' title="Jump back to footnote 1 in the text">&#8617;</a></p>\n'
+ '</li>\n'
+ '<li id="fn:2">\n'
+ '<p>Second footnote</p>\n'
+ '<p>paragraph 2&#160;<a class="footnote-backref" href="#fnref:2"'
+ ' title="Jump back to footnote 2 in the text">&#8617;</a></p>\n'
+ '</li>\n'
+ '</ol>\n'
+ '</div>'
+ )
+
+ def test_backlink_text(self):
+ """Test backlink configuration."""
+
+ self.assertMarkdownRenders(
+ 'paragraph[^1]\n\n[^1]: A Footnote',
+ '<p>paragraph<sup id="fnref:1"><a class="footnote-ref" href="#fn:1">1</a></sup></p>\n'
+ '<div class="footnote">\n'
+ '<hr />\n'
+ '<ol>\n'
+ '<li id="fn:1">\n'
+ '<p>A Footnote&#160;<a class="footnote-backref" href="#fnref:1"'
+ ' title="Jump back to footnote 1 in the text">back</a></p>\n'
+ '</li>\n'
+ '</ol>\n'
+ '</div>',
+ extension_configs={'footnotes': {'BACKLINK_TEXT': 'back'}}
+ )
+
+ def test_footnote_separator(self):
+ """Test separator configuration."""
+
+ self.assertMarkdownRenders(
+ 'paragraph[^1]\n\n[^1]: A Footnote',
+ '<p>paragraph<sup id="fnref-1"><a class="footnote-ref" href="#fn-1">1</a></sup></p>\n'
+ '<div class="footnote">\n'
+ '<hr />\n'
+ '<ol>\n'
+ '<li id="fn-1">\n'
+ '<p>A Footnote&#160;<a class="footnote-backref" href="#fnref-1"'
+ ' title="Jump back to footnote 1 in the text">&#8617;</a></p>\n'
+ '</li>\n'
+ '</ol>\n'
+ '</div>',
+ extension_configs={'footnotes': {'SEPARATOR': '-'}}
+ )
+
+ def test_backlink_title(self):
+ """Test backlink title configuration without placeholder."""
+
+ self.assertMarkdownRenders(
+ 'paragraph[^1]\n\n[^1]: A Footnote',
+ '<p>paragraph<sup id="fnref:1"><a class="footnote-ref" href="#fn:1">1</a></sup></p>\n'
+ '<div class="footnote">\n'
+ '<hr />\n'
+ '<ol>\n'
+ '<li id="fn:1">\n'
+ '<p>A Footnote&#160;<a class="footnote-backref" href="#fnref:1"'
+ ' title="Jump back to footnote">&#8617;</a></p>\n'
+ '</li>\n'
+ '</ol>\n'
+ '</div>',
+ extension_configs={'footnotes': {'BACKLINK_TITLE': 'Jump back to footnote'}}
+ )
+
+ def test_superscript_text(self):
+ """Test superscript text configuration."""
+
+ self.assertMarkdownRenders(
+ 'paragraph[^1]\n\n[^1]: A Footnote',
+ '<p>paragraph<sup id="fnref:1"><a class="footnote-ref" href="#fn:1">[1]</a></sup></p>\n'
+ '<div class="footnote">\n'
+ '<hr />\n'
+ '<ol>\n'
+ '<li id="fn:1">\n'
+ '<p>A Footnote&#160;<a class="footnote-backref" href="#fnref:1"'
+ ' title="Jump back to footnote 1 in the text">&#8617;</a></p>\n'
+ '</li>\n'
+ '</ol>\n'
+ '</div>',
+ extension_configs={'footnotes': {'SUPERSCRIPT_TEXT': '[{}]'}}
+ )
diff --git a/tests/test_syntax/extensions/test_legacy_attrs.py b/tests/test_syntax/extensions/test_legacy_attrs.py
new file mode 100644
index 0000000..b4ba5e7
--- /dev/null
+++ b/tests/test_syntax/extensions/test_legacy_attrs.py
@@ -0,0 +1,67 @@
+"""
+Python Markdown
+
+A Python implementation of John Gruber's Markdown.
+
+Documentation: https://python-markdown.github.io/
+GitHub: https://github.com/Python-Markdown/markdown/
+PyPI: https://pypi.org/project/Markdown/
+
+Started by Manfred Stienstra (http://www.dwerg.net/).
+Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
+Currently maintained by Waylan Limberg (https://github.com/waylan),
+Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
+
+Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see LICENSE.md for details).
+"""
+
+from markdown.test_tools import TestCase
+
+
+class TestLegacyAtrributes(TestCase):
+
+ maxDiff = None
+
+ def testLegacyAttrs(self):
+ self.assertMarkdownRenders(
+ self.dedent("""
+ # Header {@id=inthebeginning}
+
+ Now, let's try something *inline{@class=special}*, to see if it works
+
+ @id=TABLE.OF.CONTENTS}
+
+
+ * {@id=TABLEOFCONTENTS}
+
+
+ Or in the middle of the text {@id=TABLEOFCONTENTS}
+
+ {@id=tableofcontents}
+
+ [![{@style=float: left; margin: 10px; border:
+ none;}](http://fourthought.com/images/ftlogo.png "Fourthought
+ logo")](http://fourthought.com/)
+
+ ![img{@id=foo}][img]
+
+ [img]: http://example.com/i.jpg
+ """),
+ self.dedent("""
+ <h1 id="inthebeginning">Header </h1>
+ <p>Now, let's try something <em class="special">inline</em>, to see if it works</p>
+ <p>@id=TABLE.OF.CONTENTS}</p>
+ <ul>
+ <li id="TABLEOFCONTENTS"></li>
+ </ul>
+ <p id="TABLEOFCONTENTS">Or in the middle of the text </p>
+ <p id="tableofcontents"></p>
+ <p><a href="http://fourthought.com/"><img alt="" src="http://fourthought.com/images/ftlogo.png" style="float: left; margin: 10px; border: none;" title="Fourthought logo" /></a></p>
+ <p><img alt="img" id="foo" src="http://example.com/i.jpg" /></p>
+ """), # noqa: E501
+ extensions=['legacy_attrs']
+ )
diff --git a/tests/test_syntax/extensions/test_legacy_em.py b/tests/test_syntax/extensions/test_legacy_em.py
new file mode 100644
index 0000000..c5daf1c
--- /dev/null
+++ b/tests/test_syntax/extensions/test_legacy_em.py
@@ -0,0 +1,66 @@
+"""
+Python Markdown
+
+A Python implementation of John Gruber's Markdown.
+
+Documentation: https://python-markdown.github.io/
+GitHub: https://github.com/Python-Markdown/markdown/
+PyPI: https://pypi.org/project/Markdown/
+
+Started by Manfred Stienstra (http://www.dwerg.net/).
+Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
+Currently maintained by Waylan Limberg (https://github.com/waylan),
+Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
+
+Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see LICENSE.md for details).
+"""
+
+from markdown.test_tools import TestCase
+
+
+class TestLegacyEm(TestCase):
+ def test_legacy_emphasis(self):
+ self.assertMarkdownRenders(
+ '_connected_words_',
+ '<p><em>connected</em>words_</p>',
+ extensions=['legacy_em']
+ )
+
+ def test_legacy_strong(self):
+ self.assertMarkdownRenders(
+ '__connected__words__',
+ '<p><strong>connected</strong>words__</p>',
+ extensions=['legacy_em']
+ )
+
+ def test_complex_emphasis_underscore(self):
+ self.assertMarkdownRenders(
+ 'This is text __bold _italic bold___ with more text',
+ '<p>This is text <strong>bold <em>italic bold</em></strong> with more text</p>',
+ extensions=['legacy_em']
+ )
+
+ def test_complex_emphasis_underscore_mid_word(self):
+ self.assertMarkdownRenders(
+ 'This is text __bold_italic bold___ with more text',
+ '<p>This is text <strong>bold<em>italic bold</em></strong> with more text</p>',
+ extensions=['legacy_em']
+ )
+
+ def test_complex_multple_underscore_type(self):
+
+ self.assertMarkdownRenders(
+ 'traced ___along___ bla __blocked__ if other ___or___',
+ '<p>traced <strong><em>along</em></strong> bla <strong>blocked</strong> if other <strong><em>or</em></strong></p>' # noqa: E501
+ )
+
+ def test_complex_multple_underscore_type_variant2(self):
+
+ self.assertMarkdownRenders(
+ 'on the __1-4 row__ of the AP Combat Table ___and___ receive',
+ '<p>on the <strong>1-4 row</strong> of the AP Combat Table <strong><em>and</em></strong> receive</p>'
+ )
diff --git a/tests/test_syntax/extensions/test_md_in_html.py b/tests/test_syntax/extensions/test_md_in_html.py
new file mode 100644
index 0000000..6c13f11
--- /dev/null
+++ b/tests/test_syntax/extensions/test_md_in_html.py
@@ -0,0 +1,1216 @@
+# -*- coding: utf-8 -*-
+"""
+Python Markdown
+
+A Python implementation of John Gruber's Markdown.
+
+Documentation: https://python-markdown.github.io/
+GitHub: https://github.com/Python-Markdown/markdown/
+PyPI: https://pypi.org/project/Markdown/
+
+Started by Manfred Stienstra (http://www.dwerg.net/).
+Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
+Currently maintained by Waylan Limberg (https://github.com/waylan),
+Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
+
+Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see LICENSE.md for details).
+"""
+
+from unittest import TestSuite
+from markdown.test_tools import TestCase
+from ..blocks.test_html_blocks import TestHTMLBlocks
+from markdown import Markdown
+from xml.etree.ElementTree import Element
+
+
+class TestMarkdownInHTMLPostProcessor(TestCase):
+ """ Ensure any remaining elements in HTML stash are properly serialized. """
+
+ def test_stash_to_string(self):
+ # There should be no known cases where this actually happens so we need to
+ # forcefully pass an etree Element to the method to ensure proper behavior.
+ element = Element('div')
+ element.text = 'Foo bar.'
+ md = Markdown(extensions=['md_in_html'])
+ result = md.postprocessors['raw_html'].stash_to_string(element)
+ self.assertEqual(result, '<div>Foo bar.</div>')
+
+
+class TestDefaultwMdInHTML(TestHTMLBlocks):
+ """ Ensure the md_in_html extension does not break the default behavior. """
+
+ default_kwargs = {'extensions': ['md_in_html']}
+
+
+class TestMdInHTML(TestCase):
+
+ default_kwargs = {'extensions': ['md_in_html']}
+
+ def test_md1_paragraph(self):
+ self.assertMarkdownRenders(
+ '<p markdown="1">*foo*</p>',
+ '<p><em>foo</em></p>'
+ )
+
+ def test_md1_p_linebreaks(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <p markdown="1">
+ *foo*
+ </p>
+ """
+ ),
+ self.dedent(
+ """
+ <p>
+ <em>foo</em>
+ </p>
+ """
+ )
+ )
+
+ def test_md1_p_blank_lines(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <p markdown="1">
+
+ *foo*
+
+ </p>
+ """
+ ),
+ self.dedent(
+ """
+ <p>
+
+ <em>foo</em>
+
+ </p>
+ """
+ )
+ )
+
+ def test_md1_div(self):
+ self.assertMarkdownRenders(
+ '<div markdown="1">*foo*</div>',
+ self.dedent(
+ """
+ <div>
+ <p><em>foo</em></p>
+ </div>
+ """
+ )
+ )
+
+ def test_md1_div_linebreaks(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <div markdown="1">
+ *foo*
+ </div>
+ """
+ ),
+ self.dedent(
+ """
+ <div>
+ <p><em>foo</em></p>
+ </div>
+ """
+ )
+ )
+
+ def test_md1_code_span(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <div markdown="1">
+ `<h1>code span</h1>`
+ </div>
+ """
+ ),
+ self.dedent(
+ """
+ <div>
+ <p><code>&lt;h1&gt;code span&lt;/h1&gt;</code></p>
+ </div>
+ """
+ )
+ )
+
+ def test_md1_code_span_oneline(self):
+ self.assertMarkdownRenders(
+ '<div markdown="1">`<h1>code span</h1>`</div>',
+ self.dedent(
+ """
+ <div>
+ <p><code>&lt;h1&gt;code span&lt;/h1&gt;</code></p>
+ </div>
+ """
+ )
+ )
+
+ def test_md1_code_span_unclosed(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <div markdown="1">
+ `<p>`
+ </div>
+ """
+ ),
+ self.dedent(
+ """
+ <div>
+ <p><code>&lt;p&gt;</code></p>
+ </div>
+ """
+ )
+ )
+
+ def test_md1_code_span_script_tag(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <div markdown="1">
+ `<script>`
+ </div>
+ """
+ ),
+ self.dedent(
+ """
+ <div>
+ <p><code>&lt;script&gt;</code></p>
+ </div>
+ """
+ )
+ )
+
+ def test_md1_div_blank_lines(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <div markdown="1">
+
+ *foo*
+
+ </div>
+ """
+ ),
+ self.dedent(
+ """
+ <div>
+ <p><em>foo</em></p>
+ </div>
+ """
+ )
+ )
+
+ def test_md1_div_multi(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <div markdown="1">
+
+ *foo*
+
+ __bar__
+
+ </div>
+ """
+ ),
+ self.dedent(
+ """
+ <div>
+ <p><em>foo</em></p>
+ <p><strong>bar</strong></p>
+ </div>
+ """
+ )
+ )
+
+ def test_md1_div_nested(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <div markdown="1">
+
+ <div markdown="1">
+ *foo*
+ </div>
+
+ </div>
+ """
+ ),
+ self.dedent(
+ """
+ <div>
+ <div>
+ <p><em>foo</em></p>
+ </div>
+ </div>
+ """
+ )
+ )
+
+ def test_md1_div_multi_nest(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <div markdown="1">
+
+ <div markdown="1">
+ <p markdown="1">*foo*</p>
+ </div>
+
+ </div>
+ """
+ ),
+ self.dedent(
+ """
+ <div>
+ <div>
+ <p><em>foo</em></p>
+ </div>
+ </div>
+ """
+ )
+ )
+
+ def text_md1_details(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <details markdown="1">
+ <summary>Click to expand</summary>
+ *foo*
+ </details>
+ """
+ ),
+ self.dedent(
+ """
+ <details>
+ <summary>Click to expand</summary>
+ <p><em>foo</em></p>
+ </details>
+ """
+ )
+ )
+
+ def test_md1_mix(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <div markdown="1">
+ A _Markdown_ paragraph before a raw child.
+
+ <p markdown="1">A *raw* child.</p>
+
+ A _Markdown_ tail to the raw child.
+ </div>
+ """
+ ),
+ self.dedent(
+ """
+ <div>
+ <p>A <em>Markdown</em> paragraph before a raw child.</p>
+ <p>A <em>raw</em> child.</p>
+ <p>A <em>Markdown</em> tail to the raw child.</p>
+ </div>
+ """
+ )
+ )
+
+ def test_md1_deep_mix(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <div markdown="1">
+
+ A _Markdown_ paragraph before a raw child.
+
+ A second Markdown paragraph
+ with two lines.
+
+ <div markdown="1">
+
+ A *raw* child.
+
+ <p markdown="1">*foo*</p>
+
+ Raw child tail.
+
+ </div>
+
+ A _Markdown_ tail to the raw child.
+
+ A second tail item
+ with two lines.
+
+ <p markdown="1">More raw.</p>
+
+ </div>
+ """
+ ),
+ self.dedent(
+ """
+ <div>
+ <p>A <em>Markdown</em> paragraph before a raw child.</p>
+ <p>A second Markdown paragraph
+ with two lines.</p>
+ <div>
+ <p>A <em>raw</em> child.</p>
+ <p><em>foo</em></p>
+ <p>Raw child tail.</p>
+ </div>
+ <p>A <em>Markdown</em> tail to the raw child.</p>
+ <p>A second tail item
+ with two lines.</p>
+ <p>More raw.</p>
+ </div>
+ """
+ )
+ )
+
+ def test_md1_div_raw_inline(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <div markdown="1">
+
+ <em>foo</em>
+
+ </div>
+ """
+ ),
+ self.dedent(
+ """
+ <div>
+ <p><em>foo</em></p>
+ </div>
+ """
+ )
+ )
+
+ def test_no_md1_paragraph(self):
+ self.assertMarkdownRenders(
+ '<p>*foo*</p>',
+ '<p>*foo*</p>'
+ )
+
+ def test_no_md1_nest(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <div markdown="1">
+ A _Markdown_ paragraph before a raw child.
+
+ <p>A *raw* child.</p>
+
+ A _Markdown_ tail to the raw child.
+ </div>
+ """
+ ),
+ self.dedent(
+ """
+ <div>
+ <p>A <em>Markdown</em> paragraph before a raw child.</p>
+ <p>A *raw* child.</p>
+ <p>A <em>Markdown</em> tail to the raw child.</p>
+ </div>
+ """
+ )
+ )
+
+ def test_md1_nested_empty(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <div markdown="1">
+ A _Markdown_ paragraph before a raw empty tag.
+
+ <img src="image.png" alt="An image" />
+
+ A _Markdown_ tail to the raw empty tag.
+ </div>
+ """
+ ),
+ self.dedent(
+ """
+ <div>
+ <p>A <em>Markdown</em> paragraph before a raw empty tag.</p>
+ <p><img src="image.png" alt="An image" /></p>
+ <p>A <em>Markdown</em> tail to the raw empty tag.</p>
+ </div>
+ """
+ )
+ )
+
+ def test_md1_nested_empty_block(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <div markdown="1">
+ A _Markdown_ paragraph before a raw empty tag.
+
+ <hr />
+
+ A _Markdown_ tail to the raw empty tag.
+ </div>
+ """
+ ),
+ self.dedent(
+ """
+ <div>
+ <p>A <em>Markdown</em> paragraph before a raw empty tag.</p>
+ <hr />
+ <p>A <em>Markdown</em> tail to the raw empty tag.</p>
+ </div>
+ """
+ )
+ )
+
+ def test_empty_tags(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <div markdown="1">
+ <div></div>
+ </div>
+ """
+ ),
+ self.dedent(
+ """
+ <div>
+ <div></div>
+ </div>
+ """
+ )
+ )
+
+ def test_orphan_end_tag_in_raw_html(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <div markdown="1">
+ <div>
+ Test
+
+ </pre>
+
+ Test
+ </div>
+ </div>
+ """
+ ),
+ self.dedent(
+ """
+ <div>
+ <div>
+ Test
+
+ </pre>
+
+ Test
+ </div>
+ </div>
+ """
+ )
+ )
+
+ def test_complex_nested_case(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <div markdown="1">
+ **test**
+ <div>
+ **test**
+ <img src=""/>
+ <code>Test</code>
+ <span>**test**</span>
+ <p>Test 2</p>
+ </div>
+ </div>
+ """
+ ),
+ self.dedent(
+ """
+ <div>
+ <p><strong>test</strong></p>
+ <div>
+ **test**
+ <img src=""/>
+ <code>Test</code>
+ <span>**test**</span>
+ <p>Test 2</p>
+ </div>
+ </div>
+ """
+ )
+ )
+
+ def test_complex_nested_case_whitespace(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ Text with space\t
+ <div markdown="1">\t
+ \t
+ <div>
+ **test**
+ <img src=""/>
+ <code>Test</code>
+ <span>**test**</span>
+ <div>With whitespace</div>
+ <p>Test 2</p>
+ </div>
+ **test**
+ </div>
+ """
+ ),
+ self.dedent(
+ """
+ <p>Text with space </p>
+ <div>
+ <div>
+ **test**
+ <img src=""/>
+ <code>Test</code>
+ <span>**test**</span>
+ <div>With whitespace</div>
+ <p>Test 2</p>
+ </div>
+ <p><strong>test</strong></p>
+ </div>
+ """
+ )
+ )
+
+ def test_md1_intail_md1(self):
+ self.assertMarkdownRenders(
+ '<div markdown="1">*foo*</div><div markdown="1">*bar*</div>',
+ self.dedent(
+ """
+ <div>
+ <p><em>foo</em></p>
+ </div>
+ <div>
+ <p><em>bar</em></p>
+ </div>
+ """
+ )
+ )
+
+ def test_md1_no_blank_line_before(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ A _Markdown_ paragraph with no blank line after.
+ <div markdown="1">
+ A _Markdown_ paragraph in an HTML block with no blank line before.
+ </div>
+ """
+ ),
+ self.dedent(
+ """
+ <p>A <em>Markdown</em> paragraph with no blank line after.</p>
+ <div>
+ <p>A <em>Markdown</em> paragraph in an HTML block with no blank line before.</p>
+ </div>
+ """
+ )
+ )
+
+ def test_md1_no_line_break(self):
+ # The div here is parsed as a span-level element. Bad input equals bad output!
+ self.assertMarkdownRenders(
+ 'A _Markdown_ paragraph with <div markdown="1">no _line break_.</div>',
+ '<p>A <em>Markdown</em> paragraph with <div markdown="1">no <em>line break</em>.</div></p>'
+ )
+
+ def test_md1_in_tail(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <div></div><div markdown="1">
+ A _Markdown_ paragraph in an HTML block in tail of previous element.
+ </div>
+ """
+ ),
+ self.dedent(
+ """
+ <div></div>
+ <div>
+ <p>A <em>Markdown</em> paragraph in an HTML block in tail of previous element.</p>
+ </div>
+ """
+ )
+ )
+
+ def test_md1_PI_oneliner(self):
+ self.assertMarkdownRenders(
+ '<div markdown="1"><?php print("foo"); ?></div>',
+ self.dedent(
+ """
+ <div>
+ <?php print("foo"); ?>
+ </div>
+ """
+ )
+ )
+
+ def test_md1_PI_multiline(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <div markdown="1">
+ <?php print("foo"); ?>
+ </div>
+ """
+ ),
+ self.dedent(
+ """
+ <div>
+ <?php print("foo"); ?>
+ </div>
+ """
+ )
+ )
+
+ def test_md1_PI_blank_lines(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <div markdown="1">
+
+ <?php print("foo"); ?>
+
+ </div>
+ """
+ ),
+ self.dedent(
+ """
+ <div>
+ <?php print("foo"); ?>
+ </div>
+ """
+ )
+ )
+
+ def test_md_span_paragraph(self):
+ self.assertMarkdownRenders(
+ '<p markdown="span">*foo*</p>',
+ '<p><em>foo</em></p>'
+ )
+
+ def test_md_block_paragraph(self):
+ self.assertMarkdownRenders(
+ '<p markdown="block">*foo*</p>',
+ self.dedent(
+ """
+ <p>
+ <p><em>foo</em></p>
+ </p>
+ """
+ )
+ )
+
+ def test_md_span_div(self):
+ self.assertMarkdownRenders(
+ '<div markdown="span">*foo*</div>',
+ '<div><em>foo</em></div>'
+ )
+
+ def test_md_block_div(self):
+ self.assertMarkdownRenders(
+ '<div markdown="block">*foo*</div>',
+ self.dedent(
+ """
+ <div>
+ <p><em>foo</em></p>
+ </div>
+ """
+ )
+ )
+
+ def test_md_span_nested_in_block(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <div markdown="block">
+ <div markdown="span">*foo*</div>
+ </div>
+ """
+ ),
+ self.dedent(
+ """
+ <div>
+ <div><em>foo</em></div>
+ </div>
+ """
+ )
+ )
+
+ def test_md_block_nested_in_span(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <div markdown="span">
+ <div markdown="block">*foo*</div>
+ </div>
+ """
+ ),
+ self.dedent(
+ """
+ <div>
+ <div><em>foo</em></div>
+ </div>
+ """
+ )
+ )
+
+ def test_md_block_after_span_nested_in_block(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <div markdown="block">
+ <div markdown="span">*foo*</div>
+ <div markdown="block">*bar*</div>
+ </div>
+ """
+ ),
+ self.dedent(
+ """
+ <div>
+ <div><em>foo</em></div>
+ <div>
+ <p><em>bar</em></p>
+ </div>
+ </div>
+ """
+ )
+ )
+
+ def test_nomd_nested_in_md1(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <div markdown="1">
+ *foo*
+ <div>
+ *foo*
+ <p>*bar*</p>
+ *baz*
+ </div>
+ *bar*
+ </div>
+ """
+ ),
+ self.dedent(
+ """
+ <div>
+ <p><em>foo</em></p>
+ <div>
+ *foo*
+ <p>*bar*</p>
+ *baz*
+ </div>
+ <p><em>bar</em></p>
+ </div>
+ """
+ )
+ )
+
+ def test_md1_nested_in_nomd(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <div>
+ <div markdown="1">*foo*</div>
+ </div>
+ """
+ ),
+ self.dedent(
+ """
+ <div>
+ <div markdown="1">*foo*</div>
+ </div>
+ """
+ )
+ )
+
+ def test_md1_single_quotes(self):
+ self.assertMarkdownRenders(
+ "<p markdown='1'>*foo*</p>",
+ '<p><em>foo</em></p>'
+ )
+
+ def test_md1_no_quotes(self):
+ self.assertMarkdownRenders(
+ '<p markdown=1>*foo*</p>',
+ '<p><em>foo</em></p>'
+ )
+
+ def test_md_no_value(self):
+ self.assertMarkdownRenders(
+ '<p markdown>*foo*</p>',
+ '<p><em>foo</em></p>'
+ )
+
+ def test_md1_preserve_attrs(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <div markdown="1" id="parent">
+
+ <div markdown="1" class="foo">
+ <p markdown="1" class="bar baz">*foo*</p>
+ </div>
+
+ </div>
+ """
+ ),
+ self.dedent(
+ """
+ <div id="parent">
+ <div class="foo">
+ <p class="bar baz"><em>foo</em></p>
+ </div>
+ </div>
+ """
+ )
+ )
+
+ def test_md1_unclosed_div(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <div markdown="1">
+
+ _foo_
+
+ <div class="unclosed">
+
+ _bar_
+
+ </div>
+ """
+ ),
+ self.dedent(
+ """
+ <div>
+ <p><em>foo</em></p>
+ <div class="unclosed">
+
+ _bar_
+
+ </div>
+ </div>
+ """
+ )
+ )
+
+ def test_md1_orphan_endtag(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <div markdown="1">
+
+ _foo_
+
+ </p>
+
+ _bar_
+
+ </div>
+ """
+ ),
+ self.dedent(
+ """
+ <div>
+ <p><em>foo</em></p>
+ </p>
+ <p><em>bar</em></p>
+ </div>
+ """
+ )
+ )
+
+ def test_md1_unclosed_p(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <p markdown="1">_foo_
+ <p markdown="1">_bar_
+ """
+ ),
+ self.dedent(
+ """
+ <p><em>foo</em>
+ </p>
+ <p><em>bar</em>
+
+ </p>
+ """
+ )
+ )
+
+ def test_md1_nested_unclosed_p(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <div markdown="1">
+ <p markdown="1">_foo_
+ <p markdown="1">_bar_
+ </div>
+ """
+ ),
+ self.dedent(
+ """
+ <div>
+ <p><em>foo</em>
+ </p>
+ <p><em>bar</em>
+ </p>
+ </div>
+ """
+ )
+ )
+
+ def test_md1_nested_comment(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <div markdown="1">
+ A *Markdown* paragraph.
+ <!-- foobar -->
+ A *Markdown* paragraph.
+ </div>
+ """
+ ),
+ self.dedent(
+ """
+ <div>
+ <p>A <em>Markdown</em> paragraph.</p>
+ <!-- foobar -->
+ <p>A <em>Markdown</em> paragraph.</p>
+ </div>
+ """
+ )
+ )
+
+ def test_md1_nested_link_ref(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <div markdown="1">
+ [link]: http://example.com
+ <div markdown="1">
+ [link][link]
+ </div>
+ </div>
+ """
+ ),
+ self.dedent(
+ """
+ <div>
+ <div>
+ <p><a href="http://example.com">link</a></p>
+ </div>
+ </div>
+ """
+ )
+ )
+
+ def test_md1_hr_only_start(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ *emphasis1*
+ <hr markdown="1">
+ *emphasis2*
+ """
+ ),
+ self.dedent(
+ """
+ <p><em>emphasis1</em></p>
+ <hr>
+ <p><em>emphasis2</em></p>
+ """
+ )
+ )
+
+ def test_md1_hr_self_close(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ *emphasis1*
+ <hr markdown="1" />
+ *emphasis2*
+ """
+ ),
+ self.dedent(
+ """
+ <p><em>emphasis1</em></p>
+ <hr>
+ <p><em>emphasis2</em></p>
+ """
+ )
+ )
+
+ def test_md1_hr_start_and_end(self):
+ # Browsers ignore ending hr tags, so we don't try to do anything to handle them special.
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ *emphasis1*
+ <hr markdown="1"></hr>
+ *emphasis2*
+ """
+ ),
+ self.dedent(
+ """
+ <p><em>emphasis1</em></p>
+ <hr>
+ <p></hr>
+ <em>emphasis2</em></p>
+ """
+ )
+ )
+
+ def test_md1_hr_only_end(self):
+ # Browsers ignore ending hr tags, so we don't try to do anything to handle them special.
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ *emphasis1*
+ </hr>
+ *emphasis2*
+ """
+ ),
+ self.dedent(
+ """
+ <p><em>emphasis1</em>
+ </hr>
+ <em>emphasis2</em></p>
+ """
+ )
+ )
+
+ def test_md1_hr_with_content(self):
+ # Browsers ignore ending hr tags, so we don't try to do anything to handle them special.
+ # Content is not allowed and will be treated as normal content between two hr tags
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ *emphasis1*
+ <hr markdown="1">
+ **content**
+ </hr>
+ *emphasis2*
+ """
+ ),
+ self.dedent(
+ """
+ <p><em>emphasis1</em></p>
+ <hr>
+ <p><strong>content</strong>
+ </hr>
+ <em>emphasis2</em></p>
+ """
+ )
+ )
+
+ def test_no_md1_hr_with_content(self):
+ # Browsers ignore ending hr tags, so we don't try to do anything to handle them special.
+ # Content is not allowed and will be treated as normal content between two hr tags
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ *emphasis1*
+ <hr>
+ **content**
+ </hr>
+ *emphasis2*
+ """
+ ),
+ self.dedent(
+ """
+ <p><em>emphasis1</em></p>
+ <hr>
+ <p><strong>content</strong>
+ </hr>
+ <em>emphasis2</em></p>
+ """
+ )
+ )
+
+ def test_md1_nested_abbr_ref(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <div markdown="1">
+ *[abbr]: Abbreviation
+ <div markdown="1">
+ abbr
+ </div>
+ </div>
+ """
+ ),
+ self.dedent(
+ """
+ <div>
+ <div>
+ <p><abbr title="Abbreviation">abbr</abbr></p>
+ </div>
+ </div>
+ """
+ ),
+ extensions=['md_in_html', 'abbr']
+ )
+
+ def test_md1_nested_footnote_ref(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ <div markdown="1">
+ [^1]: The footnote.
+ <div markdown="1">
+ Paragraph with a footnote.[^1]
+ </div>
+ </div>
+ """
+ ),
+ '<div>\n'
+ '<div>\n'
+ '<p>Paragraph with a footnote.<sup id="fnref:1"><a class="footnote-ref" href="#fn:1">1</a></sup></p>\n'
+ '</div>\n'
+ '</div>\n'
+ '<div class="footnote">\n'
+ '<hr />\n'
+ '<ol>\n'
+ '<li id="fn:1">\n'
+ '<p>The footnote.&#160;'
+ '<a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text">&#8617;</a>'
+ '</p>\n'
+ '</li>\n'
+ '</ol>\n'
+ '</div>',
+ extensions=['md_in_html', 'footnotes']
+ )
+
+
+def load_tests(loader, tests, pattern):
+ ''' Ensure TestHTMLBlocks doesn't get run twice by excluding it here. '''
+ suite = TestSuite()
+ for test_class in [TestDefaultwMdInHTML, TestMdInHTML, TestMarkdownInHTMLPostProcessor]:
+ tests = loader.loadTestsFromTestCase(test_class)
+ suite.addTests(tests)
+ return suite
diff --git a/tests/test_syntax/extensions/test_smarty.py b/tests/test_syntax/extensions/test_smarty.py
new file mode 100644
index 0000000..fc635ad
--- /dev/null
+++ b/tests/test_syntax/extensions/test_smarty.py
@@ -0,0 +1,36 @@
+# -*- coding: utf-8 -*-
+"""
+Python Markdown
+
+A Python implementation of John Gruber's Markdown.
+
+Documentation: https://python-markdown.github.io/
+GitHub: https://github.com/Python-Markdown/markdown/
+PyPI: https://pypi.org/project/Markdown/
+
+Started by Manfred Stienstra (http://www.dwerg.net/).
+Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
+Currently maintained by Waylan Limberg (https://github.com/waylan),
+Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
+
+Copyright 2007-2022 The Python Markdown Project (v. 1.7 and later)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see LICENSE.md for details).
+"""
+
+from markdown.test_tools import TestCase
+
+
+class TestSmarty(TestCase):
+
+ default_kwargs = {'extensions': ['smarty']}
+
+ def test_escaped_attr(self):
+ self.assertMarkdownRenders(
+ '![x\"x](x)',
+ '<p><img alt="x&quot;x" src="x" /></p>'
+ )
+
+ # TODO: Move rest of smarty tests here.
diff --git a/tests/test_syntax/extensions/test_tables.py b/tests/test_syntax/extensions/test_tables.py
new file mode 100644
index 0000000..cd3fbe4
--- /dev/null
+++ b/tests/test_syntax/extensions/test_tables.py
@@ -0,0 +1,922 @@
+"""
+Python Markdown
+
+A Python implementation of John Gruber's Markdown.
+
+Documentation: https://python-markdown.github.io/
+GitHub: https://github.com/Python-Markdown/markdown/
+PyPI: https://pypi.org/project/Markdown/
+
+Started by Manfred Stienstra (http://www.dwerg.net/).
+Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
+Currently maintained by Waylan Limberg (https://github.com/waylan),
+Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
+
+Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see LICENSE.md for details).
+"""
+
+from markdown.test_tools import TestCase
+from markdown.extensions.tables import TableExtension
+
+
+class TestTableBlocks(TestCase):
+
+ def test_empty_cells(self):
+ """Empty cells (nbsp)."""
+
+ text = """
+  | Second Header
+------------- | -------------
+  | Content Cell
+Content Cell |  
+"""
+
+ self.assertMarkdownRenders(
+ text,
+ self.dedent(
+ """
+ <table>
+ <thead>
+ <tr>
+ <th> </th>
+ <th>Second Header</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td> </td>
+ <td>Content Cell</td>
+ </tr>
+ <tr>
+ <td>Content Cell</td>
+ <td> </td>
+ </tr>
+ </tbody>
+ </table>
+ """
+ ),
+ extensions=['tables']
+ )
+
+ def test_no_sides(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ First Header | Second Header
+ ------------- | -------------
+ Content Cell | Content Cell
+ Content Cell | Content Cell
+ """
+ ),
+ self.dedent(
+ """
+ <table>
+ <thead>
+ <tr>
+ <th>First Header</th>
+ <th>Second Header</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>Content Cell</td>
+ <td>Content Cell</td>
+ </tr>
+ <tr>
+ <td>Content Cell</td>
+ <td>Content Cell</td>
+ </tr>
+ </tbody>
+ </table>
+ """
+ ),
+ extensions=['tables']
+ )
+
+ def test_both_sides(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ | First Header | Second Header |
+ | ------------- | ------------- |
+ | Content Cell | Content Cell |
+ | Content Cell | Content Cell |
+ """
+ ),
+ self.dedent(
+ """
+ <table>
+ <thead>
+ <tr>
+ <th>First Header</th>
+ <th>Second Header</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>Content Cell</td>
+ <td>Content Cell</td>
+ </tr>
+ <tr>
+ <td>Content Cell</td>
+ <td>Content Cell</td>
+ </tr>
+ </tbody>
+ </table>
+ """
+ ),
+ extensions=['tables']
+ )
+
+ def test_align_columns(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ | Item | Value |
+ | :-------- | -----:|
+ | Computer | $1600 |
+ | Phone | $12 |
+ | Pipe | $1 |
+ """
+ ),
+ self.dedent(
+ """
+ <table>
+ <thead>
+ <tr>
+ <th style="text-align: left;">Item</th>
+ <th style="text-align: right;">Value</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td style="text-align: left;">Computer</td>
+ <td style="text-align: right;">$1600</td>
+ </tr>
+ <tr>
+ <td style="text-align: left;">Phone</td>
+ <td style="text-align: right;">$12</td>
+ </tr>
+ <tr>
+ <td style="text-align: left;">Pipe</td>
+ <td style="text-align: right;">$1</td>
+ </tr>
+ </tbody>
+ </table>
+ """
+ ),
+ extensions=['tables']
+ )
+
+ def test_styles_in_tables(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ | Function name | Description |
+ | ------------- | ------------------------------ |
+ | `help()` | Display the help window. |
+ | `destroy()` | **Destroy your computer!** |
+ """
+ ),
+ self.dedent(
+ """
+ <table>
+ <thead>
+ <tr>
+ <th>Function name</th>
+ <th>Description</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td><code>help()</code></td>
+ <td>Display the help window.</td>
+ </tr>
+ <tr>
+ <td><code>destroy()</code></td>
+ <td><strong>Destroy your computer!</strong></td>
+ </tr>
+ </tbody>
+ </table>
+ """
+ ),
+ extensions=['tables']
+ )
+
+ def test_align_three(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ |foo|bar|baz|
+ |:--|:-:|--:|
+ | | Q | |
+ |W | | W|
+ """
+ ),
+ self.dedent(
+ """
+ <table>
+ <thead>
+ <tr>
+ <th style="text-align: left;">foo</th>
+ <th style="text-align: center;">bar</th>
+ <th style="text-align: right;">baz</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td style="text-align: left;"></td>
+ <td style="text-align: center;">Q</td>
+ <td style="text-align: right;"></td>
+ </tr>
+ <tr>
+ <td style="text-align: left;">W</td>
+ <td style="text-align: center;"></td>
+ <td style="text-align: right;">W</td>
+ </tr>
+ </tbody>
+ </table>
+ """
+ ),
+ extensions=['tables']
+ )
+
+ def test_three_columns(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ foo|bar|baz
+ ---|---|---
+ | Q |
+ W | | W
+ """
+ ),
+ self.dedent(
+ """
+ <table>
+ <thead>
+ <tr>
+ <th>foo</th>
+ <th>bar</th>
+ <th>baz</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td></td>
+ <td>Q</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>W</td>
+ <td></td>
+ <td>W</td>
+ </tr>
+ </tbody>
+ </table>
+ """
+ ),
+ extensions=['tables']
+ )
+
+ def test_three_spaces_prefix(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ Three spaces in front of a table:
+
+ First Header | Second Header
+ ------------ | -------------
+ Content Cell | Content Cell
+ Content Cell | Content Cell
+
+ | First Header | Second Header |
+ | ------------ | ------------- |
+ | Content Cell | Content Cell |
+ | Content Cell | Content Cell |
+ """),
+ self.dedent(
+ """
+ <p>Three spaces in front of a table:</p>
+ <table>
+ <thead>
+ <tr>
+ <th>First Header</th>
+ <th>Second Header</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>Content Cell</td>
+ <td>Content Cell</td>
+ </tr>
+ <tr>
+ <td>Content Cell</td>
+ <td>Content Cell</td>
+ </tr>
+ </tbody>
+ </table>
+ <table>
+ <thead>
+ <tr>
+ <th>First Header</th>
+ <th>Second Header</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>Content Cell</td>
+ <td>Content Cell</td>
+ </tr>
+ <tr>
+ <td>Content Cell</td>
+ <td>Content Cell</td>
+ </tr>
+ </tbody>
+ </table>
+ """
+ ),
+ extensions=['tables']
+ )
+
+ def test_code_block_table(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ Four spaces is a code block:
+
+ First Header | Second Header
+ ------------ | -------------
+ Content Cell | Content Cell
+ Content Cell | Content Cell
+
+ | First Header | Second Header |
+ | ------------ | ------------- |
+ """),
+ self.dedent(
+ """
+ <p>Four spaces is a code block:</p>
+ <pre><code>First Header | Second Header
+ ------------ | -------------
+ Content Cell | Content Cell
+ Content Cell | Content Cell
+ </code></pre>
+ <table>
+ <thead>
+ <tr>
+ <th>First Header</th>
+ <th>Second Header</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td></td>
+ <td></td>
+ </tr>
+ </tbody>
+ </table>
+ """
+ ),
+ extensions=['tables']
+ )
+
+ def test_inline_code_blocks(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ More inline code block tests
+
+ Column 1 | Column 2 | Column 3
+ ---------|----------|---------
+ word 1 | word 2 | word 3
+ word 1 | `word 2` | word 3
+ word 1 | \\`word 2 | word 3
+ word 1 | `word 2 | word 3
+ word 1 | `word |2` | word 3
+ words |`` some | code `` | more words
+ words |``` some | code ``` | more words
+ words |```` some | code ```` | more words
+ words |`` some ` | ` code `` | more words
+ words |``` some ` | ` code ``` | more words
+ words |```` some ` | ` code ```` | more words
+ """),
+ self.dedent(
+ """
+ <p>More inline code block tests</p>
+ <table>
+ <thead>
+ <tr>
+ <th>Column 1</th>
+ <th>Column 2</th>
+ <th>Column 3</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>word 1</td>
+ <td>word 2</td>
+ <td>word 3</td>
+ </tr>
+ <tr>
+ <td>word 1</td>
+ <td><code>word 2</code></td>
+ <td>word 3</td>
+ </tr>
+ <tr>
+ <td>word 1</td>
+ <td>`word 2</td>
+ <td>word 3</td>
+ </tr>
+ <tr>
+ <td>word 1</td>
+ <td>`word 2</td>
+ <td>word 3</td>
+ </tr>
+ <tr>
+ <td>word 1</td>
+ <td><code>word |2</code></td>
+ <td>word 3</td>
+ </tr>
+ <tr>
+ <td>words</td>
+ <td><code>some | code</code></td>
+ <td>more words</td>
+ </tr>
+ <tr>
+ <td>words</td>
+ <td><code>some | code</code></td>
+ <td>more words</td>
+ </tr>
+ <tr>
+ <td>words</td>
+ <td><code>some | code</code></td>
+ <td>more words</td>
+ </tr>
+ <tr>
+ <td>words</td>
+ <td><code>some ` | ` code</code></td>
+ <td>more words</td>
+ </tr>
+ <tr>
+ <td>words</td>
+ <td><code>some ` | ` code</code></td>
+ <td>more words</td>
+ </tr>
+ <tr>
+ <td>words</td>
+ <td><code>some ` | ` code</code></td>
+ <td>more words</td>
+ </tr>
+ </tbody>
+ </table>
+ """
+ ),
+ extensions=['tables']
+ )
+
+ def test_issue_440(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ A test for issue #440:
+
+ foo | bar
+ --- | ---
+ foo | (`bar`) and `baz`.
+ """),
+ self.dedent(
+ """
+ <p>A test for issue #440:</p>
+ <table>
+ <thead>
+ <tr>
+ <th>foo</th>
+ <th>bar</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>foo</td>
+ <td>(<code>bar</code>) and <code>baz</code>.</td>
+ </tr>
+ </tbody>
+ </table>
+ """
+ ),
+ extensions=['tables']
+ )
+
+ def test_lists_not_tables(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ Lists are not tables
+
+ - this | should | not
+ - be | a | table
+ """),
+ self.dedent(
+ """
+ <p>Lists are not tables</p>
+ <ul>
+ <li>this | should | not</li>
+ <li>be | a | table</li>
+ </ul>
+ """
+ ),
+ extensions=['tables']
+ )
+
+ def test_issue_449(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ r"""
+ Add tests for issue #449
+
+ Odd backticks | Even backticks
+ ------------ | -------------
+ ``[!\"\#$%&'()*+,\-./:;<=>?@\[\\\]^_`{|}~]`` | ``[!\"\#$%&'()*+,\-./:;<=>?@\[\\\]^`_`{|}~]``
+
+ Escapes | More Escapes
+ ------- | ------
+ `` `\`` | `\`
+
+ Only the first backtick can be escaped
+
+ Escaped | Bacticks
+ ------- | ------
+ \`` \` | \`\`
+
+ Test escaped pipes
+
+ Column 1 | Column 2
+ -------- | --------
+ `|` \| | Pipes are okay in code and escaped. \|
+
+ | Column 1 | Column 2 |
+ | -------- | -------- |
+ | row1 | row1 \|
+ | row2 | row2 |
+
+ Test header escapes
+
+ | `` `\`` \| | `\` \|
+ | ---------- | ---- |
+ | row1 | row1 |
+ | row2 | row2 |
+
+ Escaped pipes in format row should not be a table
+
+ | Column1 | Column2 |
+ | ------- \|| ------- |
+ | row1 | row1 |
+ | row2 | row2 |
+
+ Test escaped code in Table
+
+ Should not be code | Should be code
+ ------------------ | --------------
+ \`Not code\` | \\`code`
+ \\\`Not code\\\` | \\\\`code`
+ """),
+ self.dedent(
+ """
+ <p>Add tests for issue #449</p>
+ <table>
+ <thead>
+ <tr>
+ <th>Odd backticks</th>
+ <th>Even backticks</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td><code>[!\\"\\#$%&amp;'()*+,\\-./:;&lt;=&gt;?@\\[\\\\\\]^_`{|}~]</code></td>
+ <td><code>[!\\"\\#$%&amp;'()*+,\\-./:;&lt;=&gt;?@\\[\\\\\\]^`_`{|}~]</code></td>
+ </tr>
+ </tbody>
+ </table>
+ <table>
+ <thead>
+ <tr>
+ <th>Escapes</th>
+ <th>More Escapes</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td><code>`\\</code></td>
+ <td><code>\\</code></td>
+ </tr>
+ </tbody>
+ </table>
+ <p>Only the first backtick can be escaped</p>
+ <table>
+ <thead>
+ <tr>
+ <th>Escaped</th>
+ <th>Bacticks</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>`<code>\\</code></td>
+ <td>``</td>
+ </tr>
+ </tbody>
+ </table>
+ <p>Test escaped pipes</p>
+ <table>
+ <thead>
+ <tr>
+ <th>Column 1</th>
+ <th>Column 2</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td><code>|</code> |</td>
+ <td>Pipes are okay in code and escaped. |</td>
+ </tr>
+ </tbody>
+ </table>
+ <table>
+ <thead>
+ <tr>
+ <th>Column 1</th>
+ <th>Column 2</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>row1</td>
+ <td>row1 |</td>
+ </tr>
+ <tr>
+ <td>row2</td>
+ <td>row2</td>
+ </tr>
+ </tbody>
+ </table>
+ <p>Test header escapes</p>
+ <table>
+ <thead>
+ <tr>
+ <th><code>`\\</code> |</th>
+ <th><code>\\</code> |</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>row1</td>
+ <td>row1</td>
+ </tr>
+ <tr>
+ <td>row2</td>
+ <td>row2</td>
+ </tr>
+ </tbody>
+ </table>
+ <p>Escaped pipes in format row should not be a table</p>
+ <p>| Column1 | Column2 |
+ | ------- || ------- |
+ | row1 | row1 |
+ | row2 | row2 |</p>
+ <p>Test escaped code in Table</p>
+ <table>
+ <thead>
+ <tr>
+ <th>Should not be code</th>
+ <th>Should be code</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>`Not code`</td>
+ <td>\\<code>code</code></td>
+ </tr>
+ <tr>
+ <td>\\`Not code\\`</td>
+ <td>\\\\<code>code</code></td>
+ </tr>
+ </tbody>
+ </table>
+ """
+ ),
+ extensions=['tables']
+ )
+
+ def test_single_column_tables(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ Single column tables
+
+ | Is a Table |
+ | ---------- |
+
+ | Is a Table
+ | ----------
+
+ Is a Table |
+ ---------- |
+
+ | Is a Table |
+ | ---------- |
+ | row |
+
+ | Is a Table
+ | ----------
+ | row
+
+ Is a Table |
+ ---------- |
+ row |
+
+ | Is not a Table
+ --------------
+ | row
+
+ Is not a Table |
+ --------------
+ row |
+
+ | Is not a Table
+ | --------------
+ row
+
+ Is not a Table |
+ -------------- |
+ row
+ """),
+ self.dedent(
+ """
+ <p>Single column tables</p>
+ <table>
+ <thead>
+ <tr>
+ <th>Is a Table</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td></td>
+ </tr>
+ </tbody>
+ </table>
+ <table>
+ <thead>
+ <tr>
+ <th>Is a Table</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td></td>
+ </tr>
+ </tbody>
+ </table>
+ <table>
+ <thead>
+ <tr>
+ <th>Is a Table</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td></td>
+ </tr>
+ </tbody>
+ </table>
+ <table>
+ <thead>
+ <tr>
+ <th>Is a Table</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>row</td>
+ </tr>
+ </tbody>
+ </table>
+ <table>
+ <thead>
+ <tr>
+ <th>Is a Table</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>row</td>
+ </tr>
+ </tbody>
+ </table>
+ <table>
+ <thead>
+ <tr>
+ <th>Is a Table</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>row</td>
+ </tr>
+ </tbody>
+ </table>
+ <h2>| Is not a Table</h2>
+ <p>| row</p>
+ <h2>Is not a Table |</h2>
+ <p>row |</p>
+ <p>| Is not a Table
+ | --------------
+ row</p>
+ <p>Is not a Table |
+ -------------- |
+ row</p>
+ """
+ ),
+ extensions=['tables']
+ )
+
+ def test_align_columns_legacy(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ | Item | Value |
+ | :-------- | -----:|
+ | Computer | $1600 |
+ | Phone | $12 |
+ | Pipe | $1 |
+ """
+ ),
+ self.dedent(
+ """
+ <table>
+ <thead>
+ <tr>
+ <th align="left">Item</th>
+ <th align="right">Value</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td align="left">Computer</td>
+ <td align="right">$1600</td>
+ </tr>
+ <tr>
+ <td align="left">Phone</td>
+ <td align="right">$12</td>
+ </tr>
+ <tr>
+ <td align="left">Pipe</td>
+ <td align="right">$1</td>
+ </tr>
+ </tbody>
+ </table>
+ """
+ ),
+ extensions=[TableExtension(use_align_attribute=True)]
+ )
+
+ def test_align_three_legacy(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ |foo|bar|baz|
+ |:--|:-:|--:|
+ | | Q | |
+ |W | | W|
+ """
+ ),
+ self.dedent(
+ """
+ <table>
+ <thead>
+ <tr>
+ <th align="left">foo</th>
+ <th align="center">bar</th>
+ <th align="right">baz</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td align="left"></td>
+ <td align="center">Q</td>
+ <td align="right"></td>
+ </tr>
+ <tr>
+ <td align="left">W</td>
+ <td align="center"></td>
+ <td align="right">W</td>
+ </tr>
+ </tbody>
+ </table>
+ """
+ ),
+ extensions=[TableExtension(use_align_attribute=True)]
+ )
diff --git a/tests/test_syntax/extensions/test_toc.py b/tests/test_syntax/extensions/test_toc.py
new file mode 100644
index 0000000..d879f6e
--- /dev/null
+++ b/tests/test_syntax/extensions/test_toc.py
@@ -0,0 +1,614 @@
+"""
+Python Markdown
+
+A Python implementation of John Gruber's Markdown.
+
+Documentation: https://python-markdown.github.io/
+GitHub: https://github.com/Python-Markdown/markdown/
+PyPI: https://pypi.org/project/Markdown/
+
+Started by Manfred Stienstra (http://www.dwerg.net/).
+Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
+Currently maintained by Waylan Limberg (https://github.com/waylan),
+Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
+
+Copyright 2007-2019 The Python Markdown Project (v. 1.7 and later)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see LICENSE.md for details).
+"""
+
+from markdown.test_tools import TestCase
+from markdown.extensions.toc import TocExtension
+from markdown.extensions.nl2br import Nl2BrExtension
+
+
+class TestTOC(TestCase):
+ maxDiff = None
+
+ # TODO: Move the rest of the TOC tests here.
+
+ def testAnchorLink(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ # Header 1
+
+ ## Header *2*
+ '''
+ ),
+ self.dedent(
+ '''
+ <h1 id="header-1"><a class="toclink" href="#header-1">Header 1</a></h1>
+ <h2 id="header-2"><a class="toclink" href="#header-2">Header <em>2</em></a></h2>
+ '''
+ ),
+ extensions=[TocExtension(anchorlink=True)]
+ )
+
+ def testAnchorLinkWithSingleInlineCode(self):
+ self.assertMarkdownRenders(
+ '# This is `code`.',
+ '<h1 id="this-is-code">' # noqa
+ '<a class="toclink" href="#this-is-code">' # noqa
+ 'This is <code>code</code>.' # noqa
+ '</a>' # noqa
+ '</h1>', # noqa
+ extensions=[TocExtension(anchorlink=True)]
+ )
+
+ def testAnchorLinkWithDoubleInlineCode(self):
+ self.assertMarkdownRenders(
+ '# This is `code` and `this` too.',
+ '<h1 id="this-is-code-and-this-too">' # noqa
+ '<a class="toclink" href="#this-is-code-and-this-too">' # noqa
+ 'This is <code>code</code> and <code>this</code> too.' # noqa
+ '</a>' # noqa
+ '</h1>', # noqa
+ extensions=[TocExtension(anchorlink=True)]
+ )
+
+ def testPermalink(self):
+ self.assertMarkdownRenders(
+ '# Header',
+ '<h1 id="header">' # noqa
+ 'Header' # noqa
+ '<a class="headerlink" href="#header" title="Permanent link">&para;</a>' # noqa
+ '</h1>', # noqa
+ extensions=[TocExtension(permalink=True)]
+ )
+
+ def testPermalinkWithSingleInlineCode(self):
+ self.assertMarkdownRenders(
+ '# This is `code`.',
+ '<h1 id="this-is-code">' # noqa
+ 'This is <code>code</code>.' # noqa
+ '<a class="headerlink" href="#this-is-code" title="Permanent link">&para;</a>' # noqa
+ '</h1>', # noqa
+ extensions=[TocExtension(permalink=True)]
+ )
+
+ def testPermalinkWithDoubleInlineCode(self):
+ self.assertMarkdownRenders(
+ '# This is `code` and `this` too.',
+ '<h1 id="this-is-code-and-this-too">' # noqa
+ 'This is <code>code</code> and <code>this</code> too.' # noqa
+ '<a class="headerlink" href="#this-is-code-and-this-too" title="Permanent link">&para;</a>' # noqa
+ '</h1>', # noqa
+ extensions=[TocExtension(permalink=True)]
+ )
+
+ def testMinMaxLevel(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ # Header 1 not in TOC
+
+ ## Header 2 not in TOC
+
+ ### Header 3
+
+ #### Header 4
+
+ ##### Header 5 not in TOC
+ '''
+ ),
+ self.dedent(
+ '''
+ <h1 id="header-1-not-in-toc">Header 1 not in TOC</h1>
+ <h2 id="header-2-not-in-toc">Header 2 not in TOC</h2>
+ <h3 id="header-3">Header 3</h3>
+ <h4 id="header-4">Header 4</h4>
+ <h5 id="header-5-not-in-toc">Header 5 not in TOC</h5>
+ '''
+ ),
+ expected_attrs={
+ 'toc': (
+ '<div class="toc">\n'
+ '<ul>\n' # noqa
+ '<li><a href="#header-3">Header 3</a>' # noqa
+ '<ul>\n' # noqa
+ '<li><a href="#header-4">Header 4</a></li>\n' # noqa
+ '</ul>\n' # noqa
+ '</li>\n' # noqa
+ '</ul>\n' # noqa
+ '</div>\n' # noqa
+ ),
+ 'toc_tokens': [
+ {
+ 'level': 3,
+ 'id': 'header-3',
+ 'name': 'Header 3',
+ 'children': [
+ {
+ 'level': 4,
+ 'id': 'header-4',
+ 'name': 'Header 4',
+ 'children': []
+ }
+ ]
+ }
+ ]
+ },
+ extensions=[TocExtension(toc_depth='3-4')]
+ )
+
+ def testMaxLevel(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ # Header 1
+
+ ## Header 2
+
+ ### Header 3 not in TOC
+ '''
+ ),
+ self.dedent(
+ '''
+ <h1 id="header-1">Header 1</h1>
+ <h2 id="header-2">Header 2</h2>
+ <h3 id="header-3-not-in-toc">Header 3 not in TOC</h3>
+ '''
+ ),
+ expected_attrs={
+ 'toc': (
+ '<div class="toc">\n'
+ '<ul>\n' # noqa
+ '<li><a href="#header-1">Header 1</a>' # noqa
+ '<ul>\n' # noqa
+ '<li><a href="#header-2">Header 2</a></li>\n' # noqa
+ '</ul>\n' # noqa
+ '</li>\n' # noqa
+ '</ul>\n' # noqa
+ '</div>\n' # noqa
+ ),
+ 'toc_tokens': [
+ {
+ 'level': 1,
+ 'id': 'header-1',
+ 'name': 'Header 1',
+ 'children': [
+ {
+ 'level': 2,
+ 'id': 'header-2',
+ 'name': 'Header 2',
+ 'children': []
+ }
+ ]
+ }
+ ]
+ },
+ extensions=[TocExtension(toc_depth=2)]
+ )
+
+ def testMinMaxLevelwithAnchorLink(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ # Header 1 not in TOC
+
+ ## Header 2 not in TOC
+
+ ### Header 3
+
+ #### Header 4
+
+ ##### Header 5 not in TOC
+ '''
+ ),
+ '<h1 id="header-1-not-in-toc">' # noqa
+ '<a class="toclink" href="#header-1-not-in-toc">Header 1 not in TOC</a></h1>\n' # noqa
+ '<h2 id="header-2-not-in-toc">' # noqa
+ '<a class="toclink" href="#header-2-not-in-toc">Header 2 not in TOC</a></h2>\n' # noqa
+ '<h3 id="header-3">' # noqa
+ '<a class="toclink" href="#header-3">Header 3</a></h3>\n' # noqa
+ '<h4 id="header-4">' # noqa
+ '<a class="toclink" href="#header-4">Header 4</a></h4>\n' # noqa
+ '<h5 id="header-5-not-in-toc">' # noqa
+ '<a class="toclink" href="#header-5-not-in-toc">Header 5 not in TOC</a></h5>', # noqa
+ expected_attrs={
+ 'toc': (
+ '<div class="toc">\n'
+ '<ul>\n' # noqa
+ '<li><a href="#header-3">Header 3</a>' # noqa
+ '<ul>\n' # noqa
+ '<li><a href="#header-4">Header 4</a></li>\n' # noqa
+ '</ul>\n' # noqa
+ '</li>\n' # noqa
+ '</ul>\n' # noqa
+ '</div>\n' # noqa
+ ),
+ 'toc_tokens': [
+ {
+ 'level': 3,
+ 'id': 'header-3',
+ 'name': 'Header 3',
+ 'children': [
+ {
+ 'level': 4,
+ 'id': 'header-4',
+ 'name': 'Header 4',
+ 'children': []
+ }
+ ]
+ }
+ ]
+ },
+ extensions=[TocExtension(toc_depth='3-4', anchorlink=True)]
+ )
+
+ def testMinMaxLevelwithPermalink(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ # Header 1 not in TOC
+
+ ## Header 2 not in TOC
+
+ ### Header 3
+
+ #### Header 4
+
+ ##### Header 5 not in TOC
+ '''
+ ),
+ '<h1 id="header-1-not-in-toc">Header 1 not in TOC' # noqa
+ '<a class="headerlink" href="#header-1-not-in-toc" title="Permanent link">&para;</a></h1>\n' # noqa
+ '<h2 id="header-2-not-in-toc">Header 2 not in TOC' # noqa
+ '<a class="headerlink" href="#header-2-not-in-toc" title="Permanent link">&para;</a></h2>\n' # noqa
+ '<h3 id="header-3">Header 3' # noqa
+ '<a class="headerlink" href="#header-3" title="Permanent link">&para;</a></h3>\n' # noqa
+ '<h4 id="header-4">Header 4' # noqa
+ '<a class="headerlink" href="#header-4" title="Permanent link">&para;</a></h4>\n' # noqa
+ '<h5 id="header-5-not-in-toc">Header 5 not in TOC' # noqa
+ '<a class="headerlink" href="#header-5-not-in-toc" title="Permanent link">&para;</a></h5>', # noqa
+ expected_attrs={
+ 'toc': (
+ '<div class="toc">\n'
+ '<ul>\n' # noqa
+ '<li><a href="#header-3">Header 3</a>' # noqa
+ '<ul>\n' # noqa
+ '<li><a href="#header-4">Header 4</a></li>\n' # noqa
+ '</ul>\n' # noqa
+ '</li>\n' # noqa
+ '</ul>\n' # noqa
+ '</div>\n' # noqa
+ ),
+ 'toc_tokens': [
+ {
+ 'level': 3,
+ 'id': 'header-3',
+ 'name': 'Header 3',
+ 'children': [
+ {
+ 'level': 4,
+ 'id': 'header-4',
+ 'name': 'Header 4',
+ 'children': []
+ }
+ ]
+ }
+ ]
+ },
+ extensions=[TocExtension(toc_depth='3-4', permalink=True)]
+ )
+
+ def testMinMaxLevelwithBaseLevel(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ # First Header
+
+ ## Second Level
+
+ ### Third Level
+
+ #### Forth Level
+ '''
+ ),
+ self.dedent(
+ '''
+ <h3 id="first-header">First Header</h3>
+ <h4 id="second-level">Second Level</h4>
+ <h5 id="third-level">Third Level</h5>
+ <h6 id="forth-level">Forth Level</h6>
+ '''
+ ),
+ expected_attrs={
+ 'toc': (
+ '<div class="toc">\n'
+ '<ul>\n' # noqa
+ '<li><a href="#second-level">Second Level</a>' # noqa
+ '<ul>\n' # noqa
+ '<li><a href="#third-level">Third Level</a></li>\n' # noqa
+ '</ul>\n' # noqa
+ '</li>\n' # noqa
+ '</ul>\n' # noqa
+ '</div>\n' # noqa
+ ),
+ 'toc_tokens': [
+ {
+ 'level': 4,
+ 'id': 'second-level',
+ 'name': 'Second Level',
+ 'children': [
+ {
+ 'level': 5,
+ 'id': 'third-level',
+ 'name': 'Third Level',
+ 'children': []
+ }
+ ]
+ }
+ ]
+ },
+ extensions=[TocExtension(toc_depth='4-5', baselevel=3)]
+ )
+
+ def testMaxLevelwithBaseLevel(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ # Some Header
+
+ ## Next Level
+
+ ### Too High
+ '''
+ ),
+ self.dedent(
+ '''
+ <h2 id="some-header">Some Header</h2>
+ <h3 id="next-level">Next Level</h3>
+ <h4 id="too-high">Too High</h4>
+ '''
+ ),
+ expected_attrs={
+ 'toc': (
+ '<div class="toc">\n'
+ '<ul>\n' # noqa
+ '<li><a href="#some-header">Some Header</a>' # noqa
+ '<ul>\n' # noqa
+ '<li><a href="#next-level">Next Level</a></li>\n' # noqa
+ '</ul>\n' # noqa
+ '</li>\n' # noqa
+ '</ul>\n' # noqa
+ '</div>\n' # noqa
+ ),
+ 'toc_tokens': [
+ {
+ 'level': 2,
+ 'id': 'some-header',
+ 'name': 'Some Header',
+ 'children': [
+ {
+ 'level': 3,
+ 'id': 'next-level',
+ 'name': 'Next Level',
+ 'children': []
+ }
+ ]
+ }
+ ]
+ },
+ extensions=[TocExtension(toc_depth=3, baselevel=2)]
+ )
+
+ def test_escaped_code(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ [TOC]
+
+ # `<test>`
+ '''
+ ),
+ self.dedent(
+ '''
+ <div class="toc">
+ <ul>
+ <li><a href="#test">&lt;test&gt;</a></li>
+ </ul>
+ </div>
+ <h1 id="test"><code>&lt;test&gt;</code></h1>
+ '''
+ ),
+ extensions=['toc']
+ )
+
+ def test_escaped_char_in_id(self):
+ self.assertMarkdownRenders(
+ r'# escaped\_character',
+ '<h1 id="escaped_character">escaped_character</h1>',
+ extensions=['toc']
+ )
+
+ def testAnchorLinkWithCustomClass(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ # Header 1
+
+ ## Header *2*
+ '''
+ ),
+ self.dedent(
+ '''
+ <h1 id="header-1"><a class="custom" href="#header-1">Header 1</a></h1>
+ <h2 id="header-2"><a class="custom" href="#header-2">Header <em>2</em></a></h2>
+ '''
+ ),
+ extensions=[TocExtension(anchorlink=True, anchorlink_class="custom")]
+ )
+
+ def testAnchorLinkWithCustomClasses(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ # Header 1
+
+ ## Header *2*
+ '''
+ ),
+ self.dedent(
+ '''
+ <h1 id="header-1"><a class="custom1 custom2" href="#header-1">Header 1</a></h1>
+ <h2 id="header-2"><a class="custom1 custom2" href="#header-2">Header <em>2</em></a></h2>
+ '''
+ ),
+ extensions=[TocExtension(anchorlink=True, anchorlink_class="custom1 custom2")]
+ )
+
+ def testPermalinkWithEmptyText(self):
+ self.assertMarkdownRenders(
+ '# Header',
+ '<h1 id="header">' # noqa
+ 'Header' # noqa
+ '<a class="headerlink" href="#header" title="Permanent link"></a>' # noqa
+ '</h1>', # noqa
+ extensions=[TocExtension(permalink="")]
+ )
+
+ def testPermalinkWithCustomClass(self):
+ self.assertMarkdownRenders(
+ '# Header',
+ '<h1 id="header">' # noqa
+ 'Header' # noqa
+ '<a class="custom" href="#header" title="Permanent link">&para;</a>' # noqa
+ '</h1>', # noqa
+ extensions=[TocExtension(permalink=True, permalink_class="custom")]
+ )
+
+ def testPermalinkWithCustomClasses(self):
+ self.assertMarkdownRenders(
+ '# Header',
+ '<h1 id="header">' # noqa
+ 'Header' # noqa
+ '<a class="custom1 custom2" href="#header" title="Permanent link">&para;</a>' # noqa
+ '</h1>', # noqa
+ extensions=[TocExtension(permalink=True, permalink_class="custom1 custom2")]
+ )
+
+ def testPermalinkWithCustomTitle(self):
+ self.assertMarkdownRenders(
+ '# Header',
+ '<h1 id="header">' # noqa
+ 'Header' # noqa
+ '<a class="headerlink" href="#header" title="custom">&para;</a>' # noqa
+ '</h1>', # noqa
+ extensions=[TocExtension(permalink=True, permalink_title="custom")]
+ )
+
+ def testPermalinkWithEmptyTitle(self):
+ self.assertMarkdownRenders(
+ '# Header',
+ '<h1 id="header">' # noqa
+ 'Header' # noqa
+ '<a class="headerlink" href="#header">&para;</a>' # noqa
+ '</h1>', # noqa
+ extensions=[TocExtension(permalink=True, permalink_title="")]
+ )
+
+ def testPermalinkWithUnicodeInID(self):
+ from markdown.extensions.toc import slugify_unicode
+ self.assertMarkdownRenders(
+ '# Unicode ヘッダー',
+ '<h1 id="unicode-ヘッダー">' # noqa
+ 'Unicode ヘッダー' # noqa
+ '<a class="headerlink" href="#unicode-ヘッダー" title="Permanent link">&para;</a>' # noqa
+ '</h1>', # noqa
+ extensions=[TocExtension(permalink=True, slugify=slugify_unicode)]
+ )
+
+ def testPermalinkWithUnicodeTitle(self):
+ from markdown.extensions.toc import slugify_unicode
+ self.assertMarkdownRenders(
+ '# Unicode ヘッダー',
+ '<h1 id="unicode-ヘッダー">' # noqa
+ 'Unicode ヘッダー' # noqa
+ '<a class="headerlink" href="#unicode-ヘッダー" title="パーマリンク">&para;</a>' # noqa
+ '</h1>', # noqa
+ extensions=[TocExtension(permalink=True, permalink_title="パーマリンク", slugify=slugify_unicode)]
+ )
+
+ def testPermalinkWithExtendedLatinInID(self):
+ self.assertMarkdownRenders(
+ '# Théâtre',
+ '<h1 id="theatre">' # noqa
+ 'Théâtre' # noqa
+ '<a class="headerlink" href="#theatre" title="Permanent link">&para;</a>' # noqa
+ '</h1>', # noqa
+ extensions=[TocExtension(permalink=True)]
+ )
+
+ def testNl2brCompatibility(self):
+ self.assertMarkdownRenders(
+ '[TOC]\ntext',
+ '<p>[TOC]<br />\ntext</p>',
+ extensions=[TocExtension(), Nl2BrExtension()]
+ )
+
+ def testTOCWithCustomClass(self):
+
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ [TOC]
+ # Header
+ '''
+ ),
+ self.dedent(
+ '''
+ <div class="custom">
+ <ul>
+ <li><a href="#header">Header</a></li>
+ </ul>
+ </div>
+ <h1 id="header">Header</h1>
+ '''
+ ),
+ extensions=[TocExtension(toc_class="custom")]
+ )
+
+ def testTOCWithCustomClasses(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ '''
+ [TOC]
+ # Header
+ '''
+ ),
+ self.dedent(
+ '''
+ <div class="custom1 custom2">
+ <ul>
+ <li><a href="#header">Header</a></li>
+ </ul>
+ </div>
+ <h1 id="header">Header</h1>
+ '''
+ ),
+ extensions=[TocExtension(toc_class="custom1 custom2")]
+ )
diff --git a/tests/test_syntax/inline/__init__.py b/tests/test_syntax/inline/__init__.py
new file mode 100644
index 0000000..564ba3b
--- /dev/null
+++ b/tests/test_syntax/inline/__init__.py
@@ -0,0 +1,20 @@
+"""
+Python Markdown
+
+A Python implementation of John Gruber's Markdown.
+
+Documentation: https://python-markdown.github.io/
+GitHub: https://github.com/Python-Markdown/markdown/
+PyPI: https://pypi.org/project/Markdown/
+
+Started by Manfred Stienstra (http://www.dwerg.net/).
+Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
+Currently maintained by Waylan Limberg (https://github.com/waylan),
+Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
+
+Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see LICENSE.md for details).
+"""
diff --git a/tests/test_syntax/inline/test_autolinks.py b/tests/test_syntax/inline/test_autolinks.py
new file mode 100644
index 0000000..b6bd1cf
--- /dev/null
+++ b/tests/test_syntax/inline/test_autolinks.py
@@ -0,0 +1,63 @@
+"""
+Python Markdown
+
+A Python implementation of John Gruber's Markdown.
+
+Documentation: https://python-markdown.github.io/
+GitHub: https://github.com/Python-Markdown/markdown/
+PyPI: https://pypi.org/project/Markdown/
+
+Started by Manfred Stienstra (http://www.dwerg.net/).
+Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
+Currently maintained by Waylan Limberg (https://github.com/waylan),
+Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
+
+Copyright 2007-2021 The Python Markdown Project (v. 1.7 and later)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see LICENSE.md for details).
+"""
+
+from markdown.test_tools import TestCase
+
+
+class TestAutomaticLinks(TestCase):
+
+ def test_email_address(self):
+ self.assertMarkdownRenders(
+ 'asdfasdfadsfasd <yuri@freewisdom.org> or you can say ',
+ '<p>asdfasdfadsfasd <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#121;&#117;&#114;'
+ '&#105;&#64;&#102;&#114;&#101;&#101;&#119;&#105;&#115;&#100;&#111;&#109;&#46;&#111;&#114;'
+ '&#103;">&#121;&#117;&#114;&#105;&#64;&#102;&#114;&#101;&#101;&#119;&#105;&#115;&#100;'
+ '&#111;&#109;&#46;&#111;&#114;&#103;</a> or you can say </p>'
+ )
+
+ def test_mailto_email_address(self):
+ self.assertMarkdownRenders(
+ 'instead <mailto:yuri@freewisdom.org>',
+ '<p>instead <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#121;&#117;&#114;&#105;&#64;'
+ '&#102;&#114;&#101;&#101;&#119;&#105;&#115;&#100;&#111;&#109;&#46;&#111;&#114;&#103;">'
+ '&#121;&#117;&#114;&#105;&#64;&#102;&#114;&#101;&#101;&#119;&#105;&#115;&#100;&#111;&#109;'
+ '&#46;&#111;&#114;&#103;</a></p>'
+ )
+
+ def test_email_address_with_ampersand(self):
+ self.assertMarkdownRenders(
+ '<bob&sue@example.com>',
+ '<p><a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#98;&#111;&#98;&#38;&#115;&#117;&#101;'
+ '&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;">&#98;&#111;&#98;&amp;'
+ '&#115;&#117;&#101;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;</a></p>'
+ )
+
+ def test_invalid_email_address_local_part(self):
+ self.assertMarkdownRenders(
+ 'Missing local-part <@domain>',
+ '<p>Missing local-part &lt;@domain&gt;</p>'
+ )
+
+ def test_invalid_email_address_domain(self):
+ self.assertMarkdownRenders(
+ 'Missing domain <local-part@>',
+ '<p>Missing domain &lt;local-part@&gt;</p>'
+ )
diff --git a/tests/test_syntax/inline/test_emphasis.py b/tests/test_syntax/inline/test_emphasis.py
new file mode 100644
index 0000000..1e7fafa
--- /dev/null
+++ b/tests/test_syntax/inline/test_emphasis.py
@@ -0,0 +1,130 @@
+"""
+Python Markdown
+
+A Python implementation of John Gruber's Markdown.
+
+Documentation: https://python-markdown.github.io/
+GitHub: https://github.com/Python-Markdown/markdown/
+PyPI: https://pypi.org/project/Markdown/
+
+Started by Manfred Stienstra (http://www.dwerg.net/).
+Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
+Currently maintained by Waylan Limberg (https://github.com/waylan),
+Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
+
+Copyright 2007-2019 The Python Markdown Project (v. 1.7 and later)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see LICENSE.md for details).
+"""
+
+from markdown.test_tools import TestCase
+
+
+class TestNotEmphasis(TestCase):
+
+ def test_standalone_asterisk(self):
+ self.assertMarkdownRenders(
+ '*',
+ '<p>*</p>'
+ )
+
+ def test_standalone_understore(self):
+ self.assertMarkdownRenders(
+ '_',
+ '<p>_</p>'
+ )
+
+ def test_standalone_asterisk_in_text(self):
+ self.assertMarkdownRenders(
+ 'foo * bar',
+ '<p>foo * bar</p>'
+ )
+
+ def test_standalone_understore_in_text(self):
+ self.assertMarkdownRenders(
+ 'foo _ bar',
+ '<p>foo _ bar</p>'
+ )
+
+ def test_standalone_asterisks_in_text(self):
+ self.assertMarkdownRenders(
+ 'foo * bar * baz',
+ '<p>foo * bar * baz</p>'
+ )
+
+ def test_standalone_understores_in_text(self):
+ self.assertMarkdownRenders(
+ 'foo _ bar _ baz',
+ '<p>foo _ bar _ baz</p>'
+ )
+
+ def test_standalone_asterisks_with_newlines(self):
+ self.assertMarkdownRenders(
+ 'foo\n* bar *\nbaz',
+ '<p>foo\n* bar *\nbaz</p>'
+ )
+
+ def test_standalone_understores_with_newlines(self):
+ self.assertMarkdownRenders(
+ 'foo\n_ bar _\nbaz',
+ '<p>foo\n_ bar _\nbaz</p>'
+ )
+
+ def test_standalone_asterisks_at_end(self):
+ self.assertMarkdownRenders(
+ 'foo * bar *',
+ '<p>foo * bar *</p>'
+ )
+
+ def test_standalone_understores_at_begin_end(self):
+ self.assertMarkdownRenders(
+ '_ bar _',
+ '<p>_ bar _</p>'
+ )
+
+ def test_complex_emphasis_asterisk(self):
+ self.assertMarkdownRenders(
+ 'This is text **bold *italic bold*** with more text',
+ '<p>This is text <strong>bold <em>italic bold</em></strong> with more text</p>'
+ )
+
+ def test_complex_emphasis_asterisk_mid_word(self):
+ self.assertMarkdownRenders(
+ 'This is text **bold*italic bold*** with more text',
+ '<p>This is text <strong>bold<em>italic bold</em></strong> with more text</p>'
+ )
+
+ def test_complex_emphasis_smart_underscore(self):
+ self.assertMarkdownRenders(
+ 'This is text __bold _italic bold___ with more text',
+ '<p>This is text <strong>bold <em>italic bold</em></strong> with more text</p>'
+ )
+
+ def test_complex_emphasis_smart_underscore_mid_word(self):
+ self.assertMarkdownRenders(
+ 'This is text __bold_italic bold___ with more text',
+ '<p>This is text __bold_italic bold___ with more text</p>'
+ )
+
+ def test_nested_emphasis(self):
+
+ self.assertMarkdownRenders(
+ 'This text is **bold *italic* *italic* bold**',
+ '<p>This text is <strong>bold <em>italic</em> <em>italic</em> bold</strong></p>'
+ )
+
+ def test_complex_multple_emphasis_type(self):
+
+ self.assertMarkdownRenders(
+ 'traced ***along*** bla **blocked** if other ***or***',
+ '<p>traced <strong><em>along</em></strong> bla <strong>blocked</strong> if other <strong><em>or</em></strong></p>' # noqa: E501
+ )
+
+ def test_complex_multple_emphasis_type_variant2(self):
+
+ self.assertMarkdownRenders(
+ 'on the **1-4 row** of the AP Combat Table ***and*** receive',
+ '<p>on the <strong>1-4 row</strong> of the AP Combat Table <strong><em>and</em></strong> receive</p>'
+ )
diff --git a/tests/test_syntax/inline/test_entities.py b/tests/test_syntax/inline/test_entities.py
new file mode 100644
index 0000000..34cc2e7
--- /dev/null
+++ b/tests/test_syntax/inline/test_entities.py
@@ -0,0 +1,43 @@
+"""
+Python Markdown
+
+A Python implementation of John Gruber's Markdown.
+
+Documentation: https://python-markdown.github.io/
+GitHub: https://github.com/Python-Markdown/markdown/
+PyPI: https://pypi.org/project/Markdown/
+
+Started by Manfred Stienstra (http://www.dwerg.net/).
+Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
+Currently maintained by Waylan Limberg (https://github.com/waylan),
+Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
+
+Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see LICENSE.md for details).
+"""
+
+from markdown.test_tools import TestCase
+
+
+class TestEntities(TestCase):
+
+ def test_named_entities(self):
+ self.assertMarkdownRenders("&amp;", "<p>&amp;</p>")
+ self.assertMarkdownRenders("&sup2;", "<p>&sup2;</p>")
+ self.assertMarkdownRenders("&Aacute;", "<p>&Aacute;</p>")
+
+ def test_decimal_entities(self):
+ self.assertMarkdownRenders("&#38;", "<p>&#38;</p>")
+ self.assertMarkdownRenders("&#178;", "<p>&#178;</p>")
+
+ def test_hexadecimal_entities(self):
+ self.assertMarkdownRenders("&#x00026;", "<p>&#x00026;</p>")
+ self.assertMarkdownRenders("&#xB2;", "<p>&#xB2;</p>")
+
+ def test_false_entities(self):
+ self.assertMarkdownRenders("&not an entity;", "<p>&amp;not an entity;</p>")
+ self.assertMarkdownRenders("&#B2;", "<p>&amp;#B2;</p>")
+ self.assertMarkdownRenders("&#xnothex;", "<p>&amp;#xnothex;</p>")
diff --git a/tests/test_syntax/inline/test_images.py b/tests/test_syntax/inline/test_images.py
new file mode 100644
index 0000000..c9c7cb8
--- /dev/null
+++ b/tests/test_syntax/inline/test_images.py
@@ -0,0 +1,184 @@
+"""
+Python Markdown
+
+A Python implementation of John Gruber's Markdown.
+
+Documentation: https://python-markdown.github.io/
+GitHub: https://github.com/Python-Markdown/markdown/
+PyPI: https://pypi.org/project/Markdown/
+
+Started by Manfred Stienstra (http://www.dwerg.net/).
+Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
+Currently maintained by Waylan Limberg (https://github.com/waylan),
+Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
+
+Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see LICENSE.md for details).
+"""
+
+from markdown.test_tools import TestCase
+
+
+class TestAdvancedImages(TestCase):
+
+ def test_nested_square_brackets(self):
+ self.assertMarkdownRenders(
+ """![Text[[[[[[[]]]]]]][]](http://link.com/image.png) more text""",
+ """<p><img alt="Text[[[[[[[]]]]]]][]" src="http://link.com/image.png" /> more text</p>"""
+ )
+
+ def test_nested_round_brackets(self):
+ self.assertMarkdownRenders(
+ """![Text](http://link.com/(((((((()))))))()).png) more text""",
+ """<p><img alt="Text" src="http://link.com/(((((((()))))))()).png" /> more text</p>"""
+ )
+
+ def test_uneven_brackets_with_titles1(self):
+ self.assertMarkdownRenders(
+ """![Text](http://link.com/(.png"title") more text""",
+ """<p><img alt="Text" src="http://link.com/(.png" title="title" /> more text</p>"""
+ )
+
+ def test_uneven_brackets_with_titles2(self):
+ self.assertMarkdownRenders(
+ """![Text](http://link.com/('.png"title") more text""",
+ """<p><img alt="Text" src="http://link.com/('.png" title="title" /> more text</p>"""
+ )
+
+ def test_uneven_brackets_with_titles3(self):
+ self.assertMarkdownRenders(
+ """![Text](http://link.com/(.png"title)") more text""",
+ """<p><img alt="Text" src="http://link.com/(.png" title="title)" /> more text</p>"""
+ )
+
+ def test_uneven_brackets_with_titles4(self):
+ self.assertMarkdownRenders(
+ """![Text](http://link.com/(.png "title") more text""",
+ """<p><img alt="Text" src="http://link.com/(.png" title="title" /> more text</p>"""
+ )
+
+ def test_uneven_brackets_with_titles5(self):
+ self.assertMarkdownRenders(
+ """![Text](http://link.com/(.png "title)") more text""",
+ """<p><img alt="Text" src="http://link.com/(.png" title="title)" /> more text</p>"""
+ )
+
+ def test_mixed_title_quotes1(self):
+ self.assertMarkdownRenders(
+ """![Text](http://link.com/'.png"title") more text""",
+ """<p><img alt="Text" src="http://link.com/'.png" title="title" /> more text</p>"""
+ )
+
+ def test_mixed_title_quotes2(self):
+ self.assertMarkdownRenders(
+ """![Text](http://link.com/".png'title') more text""",
+ """<p><img alt="Text" src="http://link.com/&quot;.png" title="title" /> more text</p>"""
+ )
+
+ def test_mixed_title_quotes3(self):
+ self.assertMarkdownRenders(
+ """![Text](http://link.com/with spaces.png'"and quotes" 'and title') more text""",
+ """<p><img alt="Text" src="http://link.com/with spaces.png" title="&quot;and quotes&quot; 'and title" />"""
+ """ more text</p>"""
+ )
+
+ def test_mixed_title_quotes4(self):
+ self.assertMarkdownRenders(
+ """![Text](http://link.com/with spaces'.png"and quotes" 'and title") more text""",
+ """<p><img alt="Text" src="http://link.com/with spaces'.png" title="and quotes&quot; 'and title" />"""
+ """ more text</p>"""
+ )
+
+ def test_mixed_title_quotes5(self):
+ self.assertMarkdownRenders(
+ """![Text](http://link.com/with spaces .png'"and quotes" 'and title') more text""",
+ """<p><img alt="Text" src="http://link.com/with spaces .png" title="&quot;and quotes&quot;"""
+ """ 'and title" /> more text</p>"""
+ )
+
+ def test_mixed_title_quotes6(self):
+ self.assertMarkdownRenders(
+ """![Text](http://link.com/with spaces "and quotes".png 'and title') more text""",
+ """<p><img alt="Text" src="http://link.com/with spaces &quot;and quotes&quot;.png" title="and title" />"""
+ """ more text</p>"""
+ )
+
+ def test_single_quote(self):
+ self.assertMarkdownRenders(
+ """![test](link"notitle.png)""",
+ """<p><img alt="test" src="link&quot;notitle.png" /></p>"""
+ )
+
+ def test_angle_with_mixed_title_quotes(self):
+ self.assertMarkdownRenders(
+ """![Text](<http://link.com/with spaces '"and quotes".png> 'and title') more text""",
+ """<p><img alt="Text" src="http://link.com/with spaces '&quot;and quotes&quot;.png" title="and title" />"""
+ """ more text</p>"""
+ )
+
+ def test_misc(self):
+ self.assertMarkdownRenders(
+ """![Poster](http://humane_man.jpg "The most humane man.")""",
+ """<p><img alt="Poster" src="http://humane_man.jpg" title="The most humane man." /></p>"""
+ )
+
+ def test_misc_ref(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ ![Poster][]
+
+ [Poster]:http://humane_man.jpg "The most humane man."
+ """
+ ),
+ self.dedent(
+ """
+ <p><img alt="Poster" src="http://humane_man.jpg" title="The most humane man." /></p>
+ """
+ )
+ )
+
+ def test_misc_blank(self):
+ self.assertMarkdownRenders(
+ """![Blank]()""",
+ """<p><img alt="Blank" src="" /></p>"""
+ )
+
+ def test_misc_img_title(self):
+ self.assertMarkdownRenders(
+ """![Image](http://humane man.jpg "The most humane man.")""",
+ """<p><img alt="Image" src="http://humane man.jpg" title="The most humane man." /></p>"""
+ )
+
+ def test_misc_img(self):
+ self.assertMarkdownRenders(
+ """![Image](http://humane man.jpg)""",
+ """<p><img alt="Image" src="http://humane man.jpg" /></p>"""
+ )
+
+ def test_short_ref(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ ![ref]
+
+ [ref]: ./image.jpg
+ """
+ ),
+ '<p><img alt="ref" src="./image.jpg" /></p>'
+ )
+
+ def test_short_ref_in_link(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ [![img ref]](http://example.com/)
+
+ [img ref]: ./image.jpg
+ """
+ ),
+ '<p><a href="http://example.com/"><img alt="img ref" src="./image.jpg" /></a></p>'
+ )
diff --git a/tests/test_syntax/inline/test_links.py b/tests/test_syntax/inline/test_links.py
new file mode 100644
index 0000000..0458756
--- /dev/null
+++ b/tests/test_syntax/inline/test_links.py
@@ -0,0 +1,386 @@
+"""
+Python Markdown
+
+A Python implementation of John Gruber's Markdown.
+
+Documentation: https://python-markdown.github.io/
+GitHub: https://github.com/Python-Markdown/markdown/
+PyPI: https://pypi.org/project/Markdown/
+
+Started by Manfred Stienstra (http://www.dwerg.net/).
+Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
+Currently maintained by Waylan Limberg (https://github.com/waylan),
+Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
+
+Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see LICENSE.md for details).
+"""
+
+from markdown.test_tools import TestCase
+
+
+class TestInlineLinks(TestCase):
+
+ def test_nested_square_brackets(self):
+ self.assertMarkdownRenders(
+ """[Text[[[[[[[]]]]]]][]](http://link.com) more text""",
+ """<p><a href="http://link.com">Text[[[[[[[]]]]]]][]</a> more text</p>"""
+ )
+
+ def test_nested_round_brackets(self):
+ self.assertMarkdownRenders(
+ """[Text](http://link.com/(((((((()))))))())) more text""",
+ """<p><a href="http://link.com/(((((((()))))))())">Text</a> more text</p>"""
+ )
+
+ def test_uneven_brackets_with_titles1(self):
+ self.assertMarkdownRenders(
+ """[Text](http://link.com/("title") more text""",
+ """<p><a href="http://link.com/(" title="title">Text</a> more text</p>"""
+ )
+
+ def test_uneven_brackets_with_titles2(self):
+ self.assertMarkdownRenders(
+ """[Text](http://link.com/('"title") more text""",
+ """<p><a href="http://link.com/('" title="title">Text</a> more text</p>"""
+ )
+
+ def test_uneven_brackets_with_titles3(self):
+ self.assertMarkdownRenders(
+ """[Text](http://link.com/("title)") more text""",
+ """<p><a href="http://link.com/(" title="title)">Text</a> more text</p>"""
+ )
+
+ def test_uneven_brackets_with_titles4(self):
+ self.assertMarkdownRenders(
+ """[Text](http://link.com/( "title") more text""",
+ """<p><a href="http://link.com/(" title="title">Text</a> more text</p>"""
+ )
+
+ def test_uneven_brackets_with_titles5(self):
+ self.assertMarkdownRenders(
+ """[Text](http://link.com/( "title)") more text""",
+ """<p><a href="http://link.com/(" title="title)">Text</a> more text</p>"""
+ )
+
+ def test_mixed_title_quotes1(self):
+ self.assertMarkdownRenders(
+ """[Text](http://link.com/'"title") more text""",
+ """<p><a href="http://link.com/'" title="title">Text</a> more text</p>"""
+ )
+
+ def test_mixed_title_quotes2(self):
+ self.assertMarkdownRenders(
+ """[Text](http://link.com/"'title') more text""",
+ """<p><a href="http://link.com/&quot;" title="title">Text</a> more text</p>"""
+ )
+
+ def test_mixed_title_quotes3(self):
+ self.assertMarkdownRenders(
+ """[Text](http://link.com/with spaces'"and quotes" 'and title') more text""",
+ """<p><a href="http://link.com/with spaces" title="&quot;and quotes&quot; 'and title">"""
+ """Text</a> more text</p>"""
+ )
+
+ def test_mixed_title_quotes4(self):
+ self.assertMarkdownRenders(
+ """[Text](http://link.com/with spaces'"and quotes" 'and title") more text""",
+ """<p><a href="http://link.com/with spaces'" title="and quotes&quot; 'and title">Text</a> more text</p>"""
+ )
+
+ def test_mixed_title_quotes5(self):
+ self.assertMarkdownRenders(
+ """[Text](http://link.com/with spaces '"and quotes" 'and title') more text""",
+ """<p><a href="http://link.com/with spaces" title="&quot;and quotes&quot; 'and title">"""
+ """Text</a> more text</p>"""
+ )
+
+ def test_mixed_title_quotes6(self):
+ self.assertMarkdownRenders(
+ """[Text](http://link.com/with spaces "and quotes" 'and title') more text""",
+ """<p><a href="http://link.com/with spaces &quot;and quotes&quot;" title="and title">"""
+ """Text</a> more text</p>"""
+ )
+
+ def test_single_quote(self):
+ self.assertMarkdownRenders(
+ """[test](link"notitle)""",
+ """<p><a href="link&quot;notitle">test</a></p>"""
+ )
+
+ def test_angle_with_mixed_title_quotes(self):
+ self.assertMarkdownRenders(
+ """[Text](<http://link.com/with spaces '"and quotes"> 'and title') more text""",
+ """<p><a href="http://link.com/with spaces '&quot;and quotes&quot;" title="and title">"""
+ """Text</a> more text</p>"""
+ )
+
+ def test_amp_in_url(self):
+ """Test amp in URLs."""
+
+ self.assertMarkdownRenders(
+ '[link](http://www.freewisdom.org/this&that)',
+ '<p><a href="http://www.freewisdom.org/this&amp;that">link</a></p>'
+ )
+ self.assertMarkdownRenders(
+ '[title](http://example.com/?a=1&amp;b=2)',
+ '<p><a href="http://example.com/?a=1&amp;b=2">title</a></p>'
+ )
+ self.assertMarkdownRenders(
+ '[title](http://example.com/?a=1&#x26;b=2)',
+ '<p><a href="http://example.com/?a=1&#x26;b=2">title</a></p>'
+ )
+
+
+class TestReferenceLinks(TestCase):
+
+ def test_ref_link(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ [Text]
+
+ [Text]: http://example.com
+ """
+ ),
+ """<p><a href="http://example.com">Text</a></p>"""
+ )
+
+ def test_ref_link_angle_brackets(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ [Text]
+
+ [Text]: <http://example.com>
+ """
+ ),
+ """<p><a href="http://example.com">Text</a></p>"""
+ )
+
+ def test_ref_link_no_space(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ [Text]
+
+ [Text]:http://example.com
+ """
+ ),
+ """<p><a href="http://example.com">Text</a></p>"""
+ )
+
+ def test_ref_link_angle_brackets_no_space(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ [Text]
+
+ [Text]:<http://example.com>
+ """
+ ),
+ """<p><a href="http://example.com">Text</a></p>"""
+ )
+
+ def test_ref_link_angle_brackets_title(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ [Text]
+
+ [Text]: <http://example.com> "title"
+ """
+ ),
+ """<p><a href="http://example.com" title="title">Text</a></p>"""
+ )
+
+ def test_ref_link_title(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ [Text]
+
+ [Text]: http://example.com "title"
+ """
+ ),
+ """<p><a href="http://example.com" title="title">Text</a></p>"""
+ )
+
+ def test_ref_link_angle_brackets_title_no_space(self):
+ # TODO: Maybe reevaluate this?
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ [Text]
+
+ [Text]: <http://example.com>"title"
+ """
+ ),
+ """<p><a href="http://example.com&gt;&quot;title&quot;">Text</a></p>"""
+ )
+
+ def test_ref_link_title_no_space(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ [Text]
+
+ [Text]: http://example.com"title"
+ """
+ ),
+ """<p><a href="http://example.com&quot;title&quot;">Text</a></p>"""
+ )
+
+ def test_ref_link_single_quoted_title(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ [Text]
+
+ [Text]: http://example.com 'title'
+ """
+ ),
+ """<p><a href="http://example.com" title="title">Text</a></p>"""
+ )
+
+ def test_ref_link_title_nested_quote(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ [Text]
+
+ [Text]: http://example.com "title'"
+ """
+ ),
+ """<p><a href="http://example.com" title="title'">Text</a></p>"""
+ )
+
+ def test_ref_link_single_quoted_title_nested_quote(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ [Text]
+
+ [Text]: http://example.com 'title"'
+ """
+ ),
+ """<p><a href="http://example.com" title="title&quot;">Text</a></p>"""
+ )
+
+ def test_ref_link_override(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ [Text]
+
+ [Text]: http://example.com 'ignore'
+ [Text]: https://example.com 'override'
+ """
+ ),
+ """<p><a href="https://example.com" title="override">Text</a></p>"""
+ )
+
+ def test_ref_link_title_no_blank_lines(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ [Text]
+ [Text]: http://example.com "title"
+ [Text]
+ """
+ ),
+ self.dedent(
+ """
+ <p><a href="http://example.com" title="title">Text</a></p>
+ <p><a href="http://example.com" title="title">Text</a></p>
+ """
+ )
+ )
+
+ def test_ref_link_multi_line(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ [Text]
+
+ [Text]:
+ http://example.com
+ "title"
+ """
+ ),
+ """<p><a href="http://example.com" title="title">Text</a></p>"""
+ )
+
+ def test_reference_newlines(self):
+ """Test reference id whitespace cleanup."""
+
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ Two things:
+
+ - I would like to tell you about the [code of
+ conduct][] we are using in this project.
+ - Only one in fact.
+
+ [code of conduct]: https://github.com/Python-Markdown/markdown/blob/master/CODE_OF_CONDUCT.md
+ """
+ ),
+ '<p>Two things:</p>\n<ul>\n<li>I would like to tell you about the '
+ '<a href="https://github.com/Python-Markdown/markdown/blob/master/CODE_OF_CONDUCT.md">code of\n'
+ ' conduct</a> we are using in this project.</li>\n<li>Only one in fact.</li>\n</ul>'
+ )
+
+ def test_reference_across_blocks(self):
+ """Test references across blocks."""
+
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ I would like to tell you about the [code of
+
+ conduct][] we are using in this project.
+
+ [code of conduct]: https://github.com/Python-Markdown/markdown/blob/master/CODE_OF_CONDUCT.md
+ """
+ ),
+ '<p>I would like to tell you about the [code of</p>\n'
+ '<p>conduct][] we are using in this project.</p>'
+ )
+
+ def test_ref_link_nested_left_bracket(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ [Text[]
+
+ [Text[]: http://example.com
+ """
+ ),
+ self.dedent(
+ """
+ <p>[Text[]</p>
+ <p>[Text[]: http://example.com</p>
+ """
+ )
+ )
+
+ def test_ref_link_nested_right_bracket(self):
+ self.assertMarkdownRenders(
+ self.dedent(
+ """
+ [Text]]
+
+ [Text]]: http://example.com
+ """
+ ),
+ self.dedent(
+ """
+ <p>[Text]]</p>
+ <p>[Text]]: http://example.com</p>
+ """
+ )
+ )
diff --git a/tests/test_syntax/inline/test_raw_html.py b/tests/test_syntax/inline/test_raw_html.py
new file mode 100644
index 0000000..a9c4857
--- /dev/null
+++ b/tests/test_syntax/inline/test_raw_html.py
@@ -0,0 +1,30 @@
+"""
+Python Markdown
+
+A Python implementation of John Gruber's Markdown.
+
+Documentation: https://python-markdown.github.io/
+GitHub: https://github.com/Python-Markdown/markdown/
+PyPI: https://pypi.org/project/Markdown/
+
+Started by Manfred Stienstra (http://www.dwerg.net/).
+Maintained for a few years by Yuri Takhteyev (http://www.freewisdom.org).
+Currently maintained by Waylan Limberg (https://github.com/waylan),
+Dmitry Shachnev (https://github.com/mitya57) and Isaac Muse (https://github.com/facelessuser).
+
+Copyright 2007-2018 The Python Markdown Project (v. 1.7 and later)
+Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
+Copyright 2004 Manfred Stienstra (the original version)
+
+License: BSD (see LICENSE.md for details).
+"""
+
+from markdown.test_tools import TestCase
+
+
+class TestRawHtml(TestCase):
+ def test_inline_html_angle_brackets(self):
+ self.assertMarkdownRenders("<span>e<c</span>", "<p><span>e&lt;c</span></p>")
+ self.assertMarkdownRenders("<span>e>c</span>", "<p><span>e&gt;c</span></p>")
+ self.assertMarkdownRenders("<span>e < c</span>", "<p><span>e &lt; c</span></p>")
+ self.assertMarkdownRenders("<span>e > c</span>", "<p><span>e &gt; c</span></p>")
diff --git a/tox.ini b/tox.ini
new file mode 100644
index 0000000..0c76754
--- /dev/null
+++ b/tox.ini
@@ -0,0 +1,43 @@
+[tox]
+envlist = py{37, 38, 39, 310}, pypy{37, 38, 39}, pygments, flake8, checkspelling, pep517check, checklinks
+isolated_build = True
+
+[testenv]
+extras = testing
+deps = pytidylib
+commands =
+ coverage run --source=markdown -m unittest discover {toxinidir}/tests
+ coverage xml
+ coverage report --show-missing
+
+[testenv:pygments]
+# Run tests with pygments installed (override deps only).
+setenv =
+ PYGMENTS_VERSION = 2.7.1
+deps =
+ pytidylib
+ pygments=={env:PYGMENTS_VERSION}
+
+[testenv:flake8]
+deps = flake8
+commands = flake8 {toxinidir}/markdown {toxinidir}/tests {toxinidir}/setup.py
+skip_install = true
+
+[testenv:checkspelling]
+deps =
+ mkdocs
+ mkdocs_nature
+commands = {toxinidir}/checkspelling.sh
+
+[testenv:checklinks]
+whitelist_externals = markdown-link-check
+deps =
+commands = {toxinidir}/checklinks.sh
+
+[testenv:pep517check]
+deps = pep517
+commands = python -m pep517.check {toxinidir}
+skip_install = true
+
+[flake8]
+max-line-length = 119