Merge `package:markdown` (#1208)
- [x] Move and fix workflow files, labeler.yaml, and badges in the
README.md
- [x] Rev the version of the package, so that pub.dev points to the
correct site
- [x] Add a line to the changelog:
```
* Move to `dart-lang/tools` monorepo.
```
- [x] Add the package to the top-level readme of the monorepo:
```
| [markdown](pkgs/markdown/) | A portable Markdown library written in Dart that can parse Markdown into HTML. | [](https://pub.dev/packages/markdown) |
```
- [ ] **Important!** Merge the PR with 'Create a merge commit' (enabling
then disabling the `Allow merge commits` admin setting)
- [x] Update the auto-publishing settings on
https://pub.dev/packages/markdown/admin
- [x] Add the following text to https://github.com/dart-lang/markdown/:'
```
> [!IMPORTANT]
> This repo has moved to https://github.com/dart-lang/tools/tree/main/pkgs/markdown
```
- [ ] Publish using the autopublish workflow
- [ ] Push tags to GitHub using
```git tag --list 'markdown*' | xargs git push origin```
- [x] Close open PRs in dart-lang/markdown with the following message:
```
Closing as the
[dart-lang/markdown](https://github.com/dart-lang/markdown) repository
is merged into the [dart-lang/tools](https://github.com/dart-lang/tools)
monorepo. Please re-open this PR there!
```
- [x] Transfer issues by running
```dart run pkgs/repo_manage/bin/report.dart transfer-issues
--source-repo dart-lang/markdown --target-repo dart-lang/tools
--add-label package:markdown --apply-changes```
- [ ] Archive https://github.com/dart-lang/markdown/
---
- [x] I’ve reviewed the contributor guide and applied the relevant
portions to this PR.
<details>
<summary>Contribution guidelines:</summary><br>
- See our [contributor
guide](https://github.com/dart-lang/.github/blob/main/CONTRIBUTING.md)
for general expectations for PRs.
- Larger or significant changes should be discussed in an issue before
creating a PR.
- Contributions to our repos should follow the [Dart style
guide](https://dart.dev/guides/language/effective-dart) and use `dart
format`.
- Most changes should add an entry to the changelog and may need to [rev
the pubspec package
version](https://github.com/dart-lang/sdk/blob/main/docs/External-Package-Maintenance.md#making-a-change).
- Changes to packages require [corresponding
tests](https://github.com/dart-lang/.github/blob/main/CONTRIBUTING.md#Testing).
Note that many Dart repos have a weekly cadence for reviewing PRs -
please allow for some latency before initial review feedback.
</details>
diff --git a/.github/ISSUE_TEMPLATE/markdown.md b/.github/ISSUE_TEMPLATE/markdown.md
new file mode 100644
index 0000000..24e9f16
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/markdown.md
@@ -0,0 +1,5 @@
+---
+name: "package:markdown"
+about: "Create a bug or file a feature request against package:markdown."
+labels: "package:markdown"
+---
\ No newline at end of file
diff --git a/.github/labeler.yml b/.github/labeler.yml
index 248532b..0bb7feb 100644
--- a/.github/labeler.yml
+++ b/.github/labeler.yml
@@ -72,6 +72,10 @@
- changed-files:
- any-glob-to-any-file: 'pkgs/json_rpc_2/**'
+'package:markdown':
+ - changed-files:
+ - any-glob-to-any-file: 'pkgs/markdown/**'
+
'package:mime':
- changed-files:
- any-glob-to-any-file: 'pkgs/mime/**'
diff --git a/.github/workflows/health.yaml b/.github/workflows/health.yaml
index f258f8b..3ac7e89 100644
--- a/.github/workflows/health.yaml
+++ b/.github/workflows/health.yaml
@@ -9,6 +9,6 @@
uses: dart-lang/ecosystem/.github/workflows/health.yaml@main
with:
ignore_coverage: "**.mock.dart,**.g.dart"
- ignore_license: "**.mock.dart,**.g.dart,**.mocks.dart"
+ ignore_license: "**.mock.dart,**.g.dart,**.mocks.dart,pkgs/markdown/**"
permissions:
pull-requests: write
diff --git a/.github/workflows/markdown.yaml b/.github/workflows/markdown.yaml
new file mode 100644
index 0000000..59654b7
--- /dev/null
+++ b/.github/workflows/markdown.yaml
@@ -0,0 +1,93 @@
+name: package:markdown
+
+on:
+ # Run on PRs and pushes to the default branch.
+ push:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/markdown.yaml'
+ - 'pkgs/markdown/**'
+ pull_request:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/markdown.yaml'
+ - 'pkgs/markdown/**'
+ schedule:
+ - cron: "0 0 * * 0"
+
+env:
+ PUB_ENVIRONMENT: bot.github
+
+
+defaults:
+ run:
+ working-directory: pkgs/markdown/
+
+
+jobs:
+ # Check code formatting and static analysis on a single OS (linux)
+ # against Dart dev.
+ analyze:
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ sdk: [dev]
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+ with:
+ sdk: ${{ matrix.sdk }}
+ - id: install
+ name: Install dependencies
+ run: dart pub get
+ - name: Check formatting
+ run: dart format --output=none --set-exit-if-changed .
+ if: always() && steps.install.outcome == 'success'
+ - name: Analyze code
+ run: dart analyze --fatal-infos
+ if: always() && steps.install.outcome == 'success'
+
+ # Run tests on a matrix consisting of two dimensions:
+ # 1. OS: ubuntu-latest, (macos-latest, windows-latest)
+ # 2. release channel: dev
+ test:
+ needs: analyze
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ # Add macos-latest and/or windows-latest if relevant for this package.
+ os: [ubuntu-latest]
+ sdk: [3.2, dev]
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+ with:
+ sdk: ${{ matrix.sdk }}
+ - id: install
+ name: Install dependencies
+ run: dart pub get
+ - name: Run VM tests
+ run: dart test --platform vm
+ if: always() && steps.install.outcome == 'success'
+
+ coverage:
+ needs: test
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+ with:
+ sdk: dev
+ - name: Install dependencies
+ run: dart pub get
+ - name: Install coverage
+ run: dart pub global activate coverage
+ - name: Collect and report coverage
+ run: dart pub global run coverage:test_with_coverage
+ - name: Upload coverage
+ uses: coverallsapp/github-action@master
+ with:
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+ path-to-lcov: pkgs/markdown/coverage/lcov.info
diff --git a/.github/workflows/markdown_crash_test.yaml b/.github/workflows/markdown_crash_test.yaml
new file mode 100644
index 0000000..ceacd77
--- /dev/null
+++ b/.github/workflows/markdown_crash_test.yaml
@@ -0,0 +1,27 @@
+# Run against all markdown files in latest version of packages on pub.dev to
+# see if any can provoke a crash
+
+name: package:markdown: crash tests
+
+on:
+ schedule:
+ # “At 00:00 (UTC) on Sunday.”
+ - cron: '0 0 * * 0'
+
+defaults:
+ run:
+ working-directory: pkgs/markdown/
+
+jobs:
+ crash-test:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+
+ - uses: dart-lang/setup-dart@e630b99d28a3b71860378cafdc2a067c71107f94
+
+ - name: Install dependencies
+ run: dart pub get
+
+ - name: Run crash_test.dart
+ run: dart test -P crash_test test/crash_test.dart
diff --git a/.github/workflows/markdown_flutter.yaml b/.github/workflows/markdown_flutter.yaml
new file mode 100644
index 0000000..1a6ad5d
--- /dev/null
+++ b/.github/workflows/markdown_flutter.yaml
@@ -0,0 +1,66 @@
+# Run a smoke test against package:flutter_markdown.
+
+name: package:markdown: flutter
+
+on:
+ # Run on PRs and pushes to the default branch.
+ push:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/markdown_flutter.yaml'
+ - 'pkgs/markdown/**'
+ pull_request:
+ branches: [ main ]
+ paths:
+ - '.github/workflows/markdown_flutter.yaml'
+ - 'pkgs/markdown/**'
+ schedule:
+ - cron: "0 0 * * 0"
+
+env:
+ PUB_ENVIRONMENT: bot.github
+
+jobs:
+ smoke-test:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: clone dart-lang/tools
+ uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ with:
+ repository: dart-lang/tools
+ path: tools_repo
+
+ - name: clone flutter/packages
+ uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
+ with:
+ repository: flutter/packages
+ path: flutter_packages
+
+ # Install the Flutter SDK using the subosito/flutter-action GitHub action.
+ - name: install the flutter sdk
+ uses: subosito/flutter-action@74af56c5ed2697ba4621264652728e8d217e53d3
+ with:
+ channel: beta
+
+ - name: flutter --version
+ run: flutter --version
+
+ - name: create pubspec_overrides.yaml
+ working-directory: flutter_packages/packages/flutter_markdown
+ run: |
+ echo "dependency_overrides:" > pubspec_overrides.yaml
+ echo " markdown:" >> pubspec_overrides.yaml
+ echo " path: ../../../tools_repo/pkgs/markdown" >> pubspec_overrides.yaml
+
+ - name: flutter pub get
+ working-directory: flutter_packages/packages/flutter_markdown
+ run: flutter pub get
+
+ - name: flutter analyze package:flutter_markdown
+ working-directory: flutter_packages/packages/flutter_markdown
+ run: flutter analyze
+
+ - name: flutter test package:flutter_markdown
+ working-directory: flutter_packages/packages/flutter_markdown
+ run: flutter test
diff --git a/README.md b/README.md
index 01702e8..f3281a8 100644
--- a/README.md
+++ b/README.md
@@ -31,6 +31,7 @@
| [html](pkgs/html/) | APIs for parsing and manipulating HTML content outside the browser. | [](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Ahtml) | [](https://pub.dev/packages/html) |
| [io](pkgs/io/) | Utilities for the Dart VM Runtime including support for ANSI colors, file copying, and standard exit code values. | [](https://pub.dev/packages/io) |
| [json_rpc_2](pkgs/json_rpc_2/) | Utilities to write a client or server using the JSON-RPC 2.0 spec. | [](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Ajson_rpc_2) | [](https://pub.dev/packages/json_rpc_2) |
+| [markdown](pkgs/markdown/) | A portable Markdown library written in Dart that can parse Markdown into HTML. | [](https://pub.dev/packages/markdown) |
| [mime](pkgs/mime/) | Utilities for handling media (MIME) types, including determining a type from a file extension and file contents. | [](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Amime) | [](https://pub.dev/packages/mime) |
| [oauth2](pkgs/oauth2/) | A client library for authenticating with a remote service via OAuth2 on behalf of a user, and making authorized HTTP requests with the user's OAuth2 credentials. | [](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Aoauth2) | [](https://pub.dev/packages/oauth2) |
| [package_config](pkgs/package_config/) | Support for reading and writing Dart Package Configuration files. | [](https://github.com/dart-lang/tools/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Apackage_config) | [](https://pub.dev/packages/package_config) |
diff --git a/pkgs/markdown/.gitignore b/pkgs/markdown/.gitignore
new file mode 100644
index 0000000..6ff0be3
--- /dev/null
+++ b/pkgs/markdown/.gitignore
@@ -0,0 +1,5 @@
+.dart_tool
+.packages
+.pub
+pubspec.lock
+doc/
diff --git a/pkgs/markdown/AUTHORS b/pkgs/markdown/AUTHORS
new file mode 100644
index 0000000..ca5b46b
--- /dev/null
+++ b/pkgs/markdown/AUTHORS
@@ -0,0 +1,13 @@
+# Below is a list of people and organizations that have contributed
+# to the Dart project. Names should be added to the list like so:
+#
+# Name/Organization <email address>
+
+Google Inc.
+
+David Peek <ninjascript@gmail.com>
+Daniel Schubert <daniel.schubert+github.com@gmail.com>
+Jirka Daněk <dnk@mail.muni.cz>
+Seth Westphal <westy92@gmail.com>
+Tim Maffett <timmaffett@gmail.com>
+Alex Li <alexv.525.li@gmail.com>
diff --git a/pkgs/markdown/CHANGELOG.md b/pkgs/markdown/CHANGELOG.md
new file mode 100644
index 0000000..5f9f48a
--- /dev/null
+++ b/pkgs/markdown/CHANGELOG.md
@@ -0,0 +1,409 @@
+## 7.3.0
+
+* Move to `dart-lang/tools` monorepo.
+* Fix an issue with checkbox list items separated with blank lines (#602).
+* Require package `web: '>=0.4.2 <2.0.0'`.
+* Fix several `RangeError` hazards in links (#623).
+* Export `LinkReferenceDefinitionSyntax` publicly (#626).
+
+## 7.2.2
+
+* Fix a crash parsing alert block syntax (#584).
+* Have alert block syntax support multiple paragraphs (#577).
+* Require Dart `^3.2.0`.
+
+## 7.2.1
+
+* Address a termination issue with GitHub alert syntax parsing.
+
+## 7.2.0
+
+* Require Dart `^3.1.0`.
+* Update all CommonMark specification links to 0.30.
+* Fix beginning of line detection in `AutolinkExtensionSyntax`.
+* Add a new syntax `AlertBlockSyntax` to parse GitHub Alerts.
+
+## 7.1.1
+
+* Fix delimiter row matching pattern for tables.
+* Tables are now able to interrupt other blocks.
+* Fix an obscure issue with HtmlBlockSyntax.
+
+## 7.1.0
+
+* Support for [footnotes](https://pandoc.org/MANUAL.html#footnotes).
+* Fixed bug causing infinite loop for links inside tables.
+
+## 7.0.2
+
+* Require Dart 2.19
+* Fix an issue in `HeaderWithIdSyntax`, do not generate heading IDs for headings
+ with no content.
+
+## 7.0.1
+
+* Remove RegExp lookarounds from autolink extension patterns. (Fixes issues when
+ running on Safari.)
+
+## 7.0.0
+
+* **Breaking change**: `close()` of `DelimiterSyntax` and `LinkSyntax`
+ returns multiple nodes instead of single one.
+* **Breaking change**: Remove deprecated APIs, including `TagSyntax`,
+ `indicatorForCheckedCheckBox`, and `indicatorForUncheckedCheckBox`.
+* **Breaking change**: Removed `BlockHtmlSyntax`, `BlockTagBlockHtmlSyntax`,
+ `LongBlockHtmlSyntax`, and `OtherTagBlockHtmlSyntax`.
+* **Breaking change**: Change the `line` properties of type `String` to `Line`.
+* **Breaking change**: Change the `lines` properties of type `List<String>` to
+ `List<Line>`.
+* Add a new syntax `HtmlBlockSyntax` to parse HTML blocks.
+* Add an `enableTagfilter` option to `HtmlRenderer` to eanble GFM `tagfilter`
+ extension.
+* Add a new syntax `DecodeHtmlSyntax` to decode HTML entity and numeric
+ character references.
+* Add a new syntax `SoftLineBreakSyntax` to remove the single space before the
+ line ending.
+* Add a new syntax `EscapeHtmlSyntax` to encode (`"`), (`<`), (`>`) and (`&`).
+* Add an option `caseSensitive` to `TextSyntax`.
+* Add a new public method `parse(String text)` for `Document`.
+* Add a new public method `parseLineList(List<Line> text)` for `Document`.
+* Add a new type: `Line`.
+* Add a new optional parameter `parentSyntax` for `parseLines()` of
+ `BlockParser`, which can be used when parsing nested blocks.
+* Add a new optional parameter `disabledSetextHeading` for `parseLines()` of
+ `BlockParser`, which is used to disable the `SetextHeaderSyntax`.
+* Add a new public property `previousSyntax` for `BlockParser`.
+
+## 6.0.1
+
+* Fix a crash in checkbox lists when mixing checkbox items with
+ non-checkbox items.
+
+## 6.0.0
+
+* Require Dart 2.17
+* Add support to GFM extension for GitHub task lists (aka checkboxes). These
+ are only active in the `gitHubFlavored` and `gitHubWeb` extension sets.
+* Add support for `#ff0000` color swatches.
+* Change emoji list do be derived from the GitHub API. The only two emoji that
+ visually change are `:cricket:` and `:beetle:`. There are alternate emoji
+ `:cricket_game:` and `:lady_beetle:` which can be used to access the previous
+ emoji. `update_github_emoji.dart` now pulls all emoji info directly from
+ GitHub API and as a result we have now support the entire GitHub emoji set
+ (excluding the 19 custom GitHub specific emoji which have no Unicode support).
+* **Breaking change**: The `TagSyntax` is _deprecated_.
+* Add new syntax `DelimiterSyntax`.
+* **Breaking change**: `StrikethroughSyntax` now extends `DelimiterSyntax`
+ instead of `TagSyntax`.
+* **Breaking change**: `LinkSyntax` now extends `DelimiterSyntax`
+ instead of `TagSyntax`.
+* Add two new emphasis syntaxes `EmphasisSyntax.underscore` and
+ `EmphasisSyntax.asterisk`.
+
+## 5.0.0
+
+* Breaking change: Change the type of `parseInline`'s parameter from `String?`
+ to `String`.
+* Fix table-rendering bug when table rows have trailing whitespace.
+ [#368](https://github.com/dart-lang/markdown/issues/368).
+* Do not allow reference link labels to contain left brackets. Thanks
+ @chenzhiguang.
+ [#335](https://github.com/dart-lang/markdown/issues/335).
+* Treat lines matching a code block syntax as continuations of paragraphs,
+ inside blockquotes. Thanks @chenzhiguang.
+ [#358](https://github.com/dart-lang/markdown/issues/358).
+* Add a syntax for GitLab-flavored fenced blockquotes. GitLab-flavored Markdown
+ will be evaluated into an ExtensionSet, in a future release. Thanks
+ @chenzhiguang.
+ [#359](https://github.com/dart-lang/markdown/issues/359).
+* Add `bool withDefaultInlineSyntaxes` and `bool withDefaultBlockSyntaxes`
+ parameters to `markdownToHtml` and `Document` to support the case of
+ specifying exactly the list of desired syntaxes. Thanks @chenzhiguang.
+ [#393](https://github.com/dart-lang/markdown/issues/393).
+
+## 4.0.1
+
+* Export `src/emojis.dart` in public API.
+* Update version of example page.
+* Internal: enforce lint rules found in the lints package.
+* Bump io dependency to `^1.0.0`.
+
+## 4.0.0
+
+* Stable null safety release.
+* Require the latest `args`, update the markdown executable to be opted in.
+
+## 4.0.0-nullsafety.0
+
+* Migrate package to Dart's null safety language feature, requiring Dart
+ 2.12 or higher.
+* **Breaking change:** The TagSyntax constructor no longer takes an `end`
+ parameter. TagSyntax no longer implements `onMatchEnd`. Instead, TagSyntax
+ implements a method called `close` which creates and returns a Node, if a
+ Node can be created and closed at the current position. If the TagSyntax
+ instance cannot create a Node at the current position, the method should
+ return `null`. Some TagSyntax subclasses will unconditionally create a tag in
+ `close`, while others may be unable to, such as LinkSyntax, if an inline or
+ reference link could not be resolved.
+* Improved parsing of nested links, images, and emphasis. CommonMark compliance
+ of emphasis-parsing improves to 99%, and link-parsing compliance rises to
+ 93%. Overall compliance improves to 94% and overall GitHub-flavored Markdown
+ improves to 93%.
+
+## 3.0.0
+
+* **Breaking change:** Remove `ListSyntax.removeLeadingEmptyLine`,
+ `ListSyntax.removeTrailingEmptyLines`, `TableSyntax.parseAlignments`,
+ `TableSyntax.parseRow`.
+* Allow intra-word strikethrough in GFM
+ ([#300](https://github.com/dart-lang/markdown/issues/300)).
+* **Breaking change:** Change `BlockSyntax.canEndBlock` from a getter to a
+ method accepting a BlockParser.
+
+## 2.1.8
+
+* Deprecate the _public_ methods `ListSyntax.removeLeadingEmptyLine`,
+ `ListSyntax.removeTrailingEmptyLines`, `TableSyntax.parseAlignments`,
+ `TableSyntax.parseRow`. These will be made private in a major version bump as
+ early as 3.0.0.
+
+## 2.1.7
+
+* Add dependency on the meta package
+
+## 2.1.6
+
+* Fix for custom link resolvers
+ ([#295](https://github.com/dart-lang/markdown/issues/295)).
+* Add missing HTML 5 block-level items
+ ([#294](https://github.com/dart-lang/markdown/pull/294)).
+
+## 2.1.5
+
+* Overhaul table row parsing. This does not have many consequences, except that
+ whitespace around escaped pipes is handled better.
+ ([#287](https://github.com/dart-lang/markdown/issues/287)).
+
+## 2.1.4
+
+* Correctly parse a reference link with a newline in the link reference part
+ ([#281](https://github.com/dart-lang/markdown/issues/281)).
+
+## 2.1.3
+
+* Do not encode HTML in link URLs. Also do not encode HTML in link text when
+ `encodeHtml` is false (e.g. when used in Flutter).
+
+## 2.1.2
+
+* Drop support for Dart 2.0.0 through 2.1.0.
+* Recognize Unicode ellipsis (…) and other Unicode punctuation as punctuation
+ when parsing potential emphasis.
+* Reduce time to parse a large HTML-block-free Markdown document (such as that
+ in #271) by more than half.
+* Add a new optional parameter for InlineSyntax(), `startCharacter`, where a
+ subclass can specify a single character to try to match, before matching with
+ more expensive regular expressions.
+
+## 2.1.1
+
+* Fix for encoding HTML for text string that contains `<pre>`
+ ([#263](https://github.com/dart-lang/markdown/issues/263)).
+
+## 2.1.0
+
+* Improve strict spec compliance of `>` handling by always encoding as `>`
+ – unless preceded by `/`.
+* Improve strict spec compliance for `blockquote` by always putting the closing
+ tag on a new line.
+* Improve strict spec compliance for `code` elements defined with "\`".
+* Properly encode `<`, `>`, and `"` as their respective HTML entities when
+ interpreted as text.
+* Improve inline code parsing when using multiple backticks.
+* Do not encode HTML in indented code blocks when `encodeHtml` is false (e.g.
+ when used in Flutter).
+
+## 2.0.3
+
+* Render element attributes in the order they were defined.
+ Aligns more closely with the strict spec definition.
+* Correctly render `&` within inline image titles.
+* Add 68 new GitHub emoji.
+* Escape HTML attribute for fenced code blocks, in the info string.
+
+## 2.0.2
+
+* Set max SDK version to `<3.0.0`, and adjust other dependencies.
+
+## 2.0.1
+
+* Require Dart 2.0.0-dev.
+
+## 2.0.0
+
+* **Breaking change:** The `Link` class has been renamed `LinkReference`, and
+ the `Document` field, `refLinks`, has been renamed `linkReferences`.
+* **Breaking change:** Remove the deprecated `ExtensionSet.gitHub` field.
+ Use `ExtensionSet.gitHubFlavored` instead.
+* **Breaking change:** Make all of the fields on `Document` read-only.
+* Overhaul support for emphasis (`*foo*` and `_foo_`) and strong emphasis
+ (`**foo**` and `__foo__`), dramatically improving CommonMark compliance.
+* Overhaul support for links and images, again dramatically improving CommonMark
+ compliance.
+* Improve support for tab characters, and horizontal rules.
+* Add support for GitHub Flavored Markdown's Strikethrough extension. See the
+ [GFM spec][strikethrough].
+* The above fixes raise compliance with the CommonMark specs to 93%, and
+ compliance with the GFM specs to 92%.
+* Add an `encodeHtml` parameter to `Document`, which defaults to true. When
+ false, HTML entities (such as `©` and the `<` character) will not be
+ escaped, useful when rendering Markdown in some output format other than HTML.
+* Allow the binary script to take a `--extension-set` option.
+
+ A reminder: You can [run `bin/markdown.dart` from anywhere][pub-global] via:
+
+ ```shell
+ $ pub global activate markdown
+ $ markdown
+ ```
+
+[strikethrough]: https://github.github.com/gfm/#strikethrough-extension-
+[pub-global]: https://dart.dev/tools/pub/cmd/pub-global#running-a-script-from-your-path
+
+## 1.1.1
+
+* Add support for GitHub's colon-based Emoji syntax. :tada:! This is available
+ in the `gitHubWeb` extension set.
+
+## 1.1.0
+
+* Make the constructor for ExtensionSet public, for tools like dartdoc.
+* Split the `gitHub` ExtensionSet into two sets: `gitHubFlavored`, which
+ represents the GitHub Flavored Markdown spec, and `gitHubWeb`, which
+ represents what GitHub actually renders Markdown.
+
+## 1.0.0
+
+* Fix issue where `accept` could cause an exception.
+* Remove deprecated `escapeHtml` function.
+* Fix compliance with auto-links, including support for email addresses.
+* Updated `ExtensionSet.gitHub` to more closely align with GitHub markdown.
+
+## 0.11.4
+
+* Fix bug with lazy blockquote continuations (#162)
+* Fix bug with list item continuations (#156)
+
+## 0.11.3
+
+* Deprecate `escapeHtml`. This code exists in `dart:convert`.
+
+## 0.11.2
+
+* Fix reference code links inside blockquotes.
+* Add src/util.dart to exports.
+
+## 0.11.1
+
+* Add version information:
+ * `dart bin/markdown.dart --version` now shows the package version number.
+ * The playground app now shows the version number.
+* Improve autolink parsing.
+* Add new table syntax: `TableSyntax`.
+* Add new ExtensionSet that includes the table syntax: `ExtensionSet.gitHub`.
+* For development: added `tool/travis.sh`.
+* Support multiline Setext headers.
+* Handle loose-vs-strict list items better.
+* Support ordered lists that start with a number other than 1.
+
+## 0.11.0+1
+
+* Add playground app at https://dart-lang.github.io/markdown.
+
+## 0.11.0
+
+* Parse HTML blocks more accurately, according to
+ [CommonMark](https://spec.commonmark.org/0.24/#html-blocks).
+* Support [shortcut reference
+ links](https://spec.commonmark.org/0.24/#reference-link).
+* Don't allow an indented code block to interrupt a paragraph.
+* Change definition of "loose" and "strict" lists (items wrapped in
+ paragraph tags vs not) to CommonMark's. The primary difference is that any
+ single list item can trigger the entire list to be marked as "loose", rather
+ than defining "looseness" on each specific item.
+* Fix paragraph continuations in blockquotes and list items.
+* Fix silly typing bug with `tool/common_mark_stats.dart`, which resulted in
+ a dramatic overestimate of our CommonMark compliance.
+* There are now 427/613 (69%) passing CommonMark v0.25 specs.
+
+## 0.10.1
+
+* Parse [hard line breaks](https://spec.commonmark.org/0.24/#hard-line-breaks)
+ properly (#86). Thanks @mehaase!
+* Fix processing of `[ ... ]` syntax when no resolver is specified (#92).
+* There are now 401/613 (65%) passing CommonMark v0.24 specs.
+ (_Actually: after 0f64c8f the actual number of passing tests was 352/613
+ (57%)._)
+
+## 0.10.0
+
+* BREAKING: Now following the CommonMark spec for fenced code blocks.
+ If a language (info string) is provided, it is added as a class to the `code`
+ element with a `language-` prefix.
+* BREAKING: Now following the CommonMark spec for images. Previously,
+ `` would compile too
+ `<a href="img.prg"><img src="img.prg" alt="text"></img></a>`. That same code
+ will now compile to `<img src="img.png" alt="text" />`.
+* Fix all [strong mode][] errors.
+
+[strong mode]: https://github.com/dart-lang/dev_compiler/blob/master/STRONG_MODE.md
+
+## 0.9.0
+
+* BREAKING: The text `[foo] (bar)` no longer renders as an inline link (#53).
+* BREAKING: Change list parsing to allow lists to begin immediately after a
+ preceding block element, without a blank line in between.
+* Formalize an API for Markdown extensions (#43).
+* Introduce ExtensionSets. FencedCodeBlock is considered an extension, but
+ existing usage of `markdownToHtml()` and `new Document()` will use the
+ default extension set, which is `ExtensionSet.commonMark`, which includes
+ FencedCodeBlock.
+* Inline HTML syntax support; This is also considered an extension (#18).
+* The text `[foo]()` now renders as an inline link.
+* Whitespace now allowed between a link's destination and title (#65).
+* Header identifier support in the HeaderWithIdSyntax and
+ SetextHeaderWithIdSyntax extensions.
+* Implement backslash-escaping so that Markdown syntax can be escaped, such as
+ `[foo]\(bar) ==> <p>[foo](bar)</p>`.
+* Support for hard line breaks with either `\\\n` or <code> \n</code> (#30,
+ #60).
+* New public method for BlockParser: `peek(int linesAhead)`, meant for use in
+ subclasses.
+* New public members for ListSyntax: `blocksInList` and `determineBlockItems()`,
+ meant for use in subclasses.
+* Improve public docs (better, and more of them).
+
+## 0.8.0
+
+* **Breaking:** Remove (probably unused) fields: `LinkSyntax.resolved`,
+ `InlineParser.currentSource`.
+* Switch tests to use [test][] instead of [unittest][].
+* Fix a few bugs in inline code syntax.
+* Ignore underscores inside words (#41).
+
+[test]: https://pub.dev/packages/test
+[unittest]: https://pub.dev/packages/unittest
+
+## 0.7.2
+
+* Allow resolving links that contain inline syntax (#42).
+
+## 0.7.1+3
+
+* Updated homepage.
+
+## 0.7.1+2
+
+* Formatted code.
+
+* Updated readme.
diff --git a/pkgs/markdown/LICENSE b/pkgs/markdown/LICENSE
new file mode 100644
index 0000000..c2730c9
--- /dev/null
+++ b/pkgs/markdown/LICENSE
@@ -0,0 +1,27 @@
+Copyright 2012, the Dart project authors.
+
+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 Google LLC 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.
diff --git a/pkgs/markdown/README.md b/pkgs/markdown/README.md
new file mode 100644
index 0000000..3b87484
--- /dev/null
+++ b/pkgs/markdown/README.md
@@ -0,0 +1,173 @@
+[](https://github.com/dart-lang/tools/actions/workflows/markdown.yaml)
+[](https://pub.dev/packages/markdown)
+[](https://pub.dev/packages/markdown/publisher)
+
+A portable Markdown library written in Dart. It can parse Markdown into
+HTML on both the client and server.
+
+Play with it at
+[dart-lang.github.io/markdown](https://dart-lang.github.io/markdown).
+
+### Usage
+
+```dart
+import 'package:markdown/markdown.dart';
+
+void main() {
+ print(markdownToHtml('Hello *Markdown*'));
+ //=> <p>Hello <em>Markdown</em></p>
+}
+```
+
+### Syntax extensions
+
+A few Markdown extensions, beyond what was specified in the original
+[Perl Markdown][] implementation, are supported. By default, the ones supported
+in [CommonMark] are enabled. Any individual extension can be enabled by
+specifying an Array of extension syntaxes in the `blockSyntaxes` or
+`inlineSyntaxes` argument of `markdownToHtml`.
+
+The currently supported inline extension syntaxes are:
+
+* `InlineHtmlSyntax()` - approximately CommonMark's
+ [definition][commonmark-raw-html] of "Raw HTML".
+
+The currently supported block extension syntaxes are:
+
+* `const FencedCodeBlockSyntax()` - Code blocks familiar to Pandoc and PHP
+ Markdown Extra users.
+* `const HeaderWithIdSyntax()` - ATX-style headers have generated IDs, for link
+ anchors (akin to Pandoc's [`auto_identifiers`][pandoc-auto_identifiers]).
+* `const SetextHeaderWithIdSyntax()` - Setext-style headers have generated IDs
+ for link anchors (akin to Pandoc's
+ [`auto_identifiers`][pandoc-auto_identifiers]).
+* `const TableSyntax()` - Table syntax familiar to GitHub, PHP Markdown Extra,
+ and Pandoc users.
+
+For example:
+
+```dart
+import 'package:markdown/markdown.dart';
+
+void main() {
+ print(markdownToHtml('Hello <span class="green">Markdown</span>',
+ inlineSyntaxes: [InlineHtmlSyntax()]));
+ //=> <p>Hello <span class="green">Markdown</span></p>
+}
+```
+
+### Extension sets
+
+To make extension management easy, you can also just specify an extension set.
+Both `markdownToHtml()` and `Document()` accept an `extensionSet` named
+parameter. Currently, there are four pre-defined extension sets:
+
+* `ExtensionSet.none` includes no extensions. With no extensions, Markdown
+ documents will be parsed with a default set of block and inline syntax
+ parsers that closely match how the document might be parsed by the original
+ [Perl Markdown][] implementation.
+
+* `ExtensionSet.commonMark` includes two extensions in addition to the default
+ parsers to bring the parsed output closer to the [CommonMark] specification:
+
+ * Block Syntax Parser
+ * `const FencedCodeBlockSyntax()`
+
+ * Inline Syntax Parser
+ * `InlineHtmlSyntax()`
+
+* `ExtensionSet.gitHubFlavored` includes five extensions in addition to the default
+ parsers to bring the parsed output close to the [GitHub Flavored] Markdown
+ specification:
+
+ * Block Syntax Parser
+ * `const FencedCodeBlockSyntax()`
+ * `const TableSyntax()`
+
+ * Inline Syntax Parser
+ * `InlineHtmlSyntax()`
+ * `StrikethroughSyntax()`
+ * `AutolinkExtensionSyntax()`
+
+* `ExtensionSet.gitHubWeb` includes eight extensions. The same set of parsers use
+ in the `gitHubFlavored` extension set with the addition of the block syntax parsers,
+ HeaderWithIdSyntax and SetextHeaderWithIdSyntax, which add `id` attributes to
+ headers and inline syntax parser, EmojiSyntax, for parsing GitHub style emoji
+ characters:
+
+ * Block Syntax Parser
+ * `const FencedCodeBlockSyntax()`
+ * `const HeaderWithIdSyntax()`, which adds `id` attributes to ATX-style
+ headers, for easy intra-document linking.
+ * `const SetextHeaderWithIdSyntax()`, which adds `id` attributes to
+ Setext-style headers, for easy intra-document linking.
+ * `const TableSyntax()`
+
+ * Inline Syntax Parser
+ * `InlineHtmlSyntax()`
+ * `StrikethroughSyntax()`
+ * `EmojiSyntax()`
+ * `AutolinkExtensionSyntax()`
+
+### Custom syntax extensions
+
+You can create and use your own syntaxes.
+
+```dart
+import 'package:markdown/markdown.dart';
+
+void main() {
+ var syntaxes = [TextSyntax('nyan', sub: '~=[,,_,,]:3')];
+ print(markdownToHtml('nyan', inlineSyntaxes: syntaxes));
+ //=> <p>~=[,,_,,]:3</p>
+}
+```
+
+### HTML sanitization
+
+This package offers no features in the way of HTML sanitization. Read Estevão
+Soares dos Santos's great article, ["Markdown's XSS Vulnerability (and how to
+mitigate it)"], to learn more.
+
+The authors recommend that you perform any necessary sanitization on the
+resulting HTML, for example via `dart:html`'s [NodeValidator].
+
+### CommonMark compliance
+
+This package contains a number of files in the `tool` directory for tracking
+compliance with [CommonMark].
+
+#### Updating CommonMark stats when changing the implementation
+
+ 1. Update the library and test code, making sure that tests still pass.
+ 2. Run `dart run tool/stats.dart --update-files` to update the
+ per-test results `tool/common_mark_stats.json` and the test summary
+ `tool/common_mark_stats.txt`.
+ 3. Verify that more tests now pass – or at least, no more tests fail.
+ 4. Make sure you include the updated stats files in your commit.
+
+#### Updating the CommonMark test file for a spec update
+
+ 1. Check out the [CommonMark source]. Make sure you checkout a *major* release.
+ 2. Dump the test output overwriting the existing tests file.
+
+ ```console
+ > cd /path/to/common_mark_dir
+ > python3 test/spec_tests.py --dump-tests > \
+ /path/to/markdown.dart/tool/common_mark_tests.json
+ ```
+
+ 3. Update the stats files as described above. Note any changes in the results.
+ 4. Update any references to the existing spec by search for
+ `https://spec.commonmark.org/0.30/` in the repository. (Including this one.)
+ Verify the updated links are still valid.
+ 5. Commit changes, including a corresponding note in `CHANGELOG.md`.
+
+[Perl Markdown]: https://daringfireball.net/projects/markdown/
+[CommonMark]: https://commonmark.org/
+[commonMark-raw-html]: https://spec.commonmark.org/0.30/#raw-html
+[CommonMark source]: https://github.com/commonmark/commonmark-spec
+[GitHub Flavored]: https://github.github.io/gfm/
+[pandoc-auto_identifiers]: https://pandoc.org/MANUAL.html#extension-auto_identifiers
+["Markdown's XSS Vulnerability (and how to mitigate it)"]: https://github.com/showdownjs/showdown/wiki/Markdown%27s-XSS-Vulnerability-(and-how-to-mitigate-it)
+[NodeValidator]: https://api.dart.dev/stable/dart-html/NodeValidator-class.html
diff --git a/pkgs/markdown/analysis_options.yaml b/pkgs/markdown/analysis_options.yaml
new file mode 100644
index 0000000..e7748f5
--- /dev/null
+++ b/pkgs/markdown/analysis_options.yaml
@@ -0,0 +1,36 @@
+# https://dart.dev/tools/analysis
+include: package:dart_flutter_team_lints/analysis_options.yaml
+
+analyzer:
+ language:
+ strict-casts: true
+ strict-inference: true
+ strict-raw-types: true
+
+ errors:
+ # The example app explicitly takes a String of user-generated HTML and
+ # inserts it straight into a <div> using innerHtml.
+ unsafe_html: ignore
+ # Waiting on a couple of bug fixes and new features before this should be enabled
+ comment_references: ignore
+
+linter:
+ rules:
+ # https://github.com/dart-lang/linter/issues/574
+ #- comment_references
+ - avoid_private_typedef_functions
+ - avoid_redundant_argument_values
+ - avoid_unused_constructor_parameters
+ - avoid_void_async
+ - cancel_subscriptions
+ - literal_only_boolean_expressions
+ - missing_whitespace_between_adjacent_strings
+ - no_adjacent_strings_in_list
+ - prefer_const_declarations
+ - prefer_final_locals
+ - prefer_final_in_for_each
+ - unnecessary_await_in_return
+ - unnecessary_raw_strings
+ - use_if_null_to_convert_nulls_to_bools
+ - use_raw_strings
+ - use_string_buffers
diff --git a/pkgs/markdown/benchmark/benchmark.dart b/pkgs/markdown/benchmark/benchmark.dart
new file mode 100644
index 0000000..aaf8112
--- /dev/null
+++ b/pkgs/markdown/benchmark/benchmark.dart
@@ -0,0 +1,64 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io';
+
+import 'package:markdown/markdown.dart';
+import 'package:path/path.dart' as p;
+
+const numTrials = 100;
+const runsPerTrial = 50;
+
+final source = _loadFile('input.md');
+final expected = _loadFile('output.html');
+
+void main() {
+ var best = double.infinity;
+
+ // Run the benchmark several times. This ensures the VM is warmed up and lets
+ // us see how much variance there is.
+ for (var i = 0; i <= numTrials; i++) {
+ final stopwatch = Stopwatch()..start();
+
+ // For a single benchmark, convert the source multiple times.
+ late String result;
+ for (var j = 0; j < runsPerTrial; j++) {
+ result = markdownToHtml(source);
+ }
+
+ stopwatch.stop();
+ final elapsed = stopwatch.elapsedMilliseconds / runsPerTrial;
+
+ // Keep track of the best run so far.
+ if (elapsed >= best) continue;
+ best = elapsed;
+
+ // Sanity check to make sure the output is what we expect and to make sure
+ // the VM doesn't optimize "dead" code away.
+ if (result != expected) {
+ print('Incorrect output:\n$result');
+ exitCode = 1;
+ return;
+ }
+
+ // Don't print the first run. It's always terrible since the VM hasn't
+ // warmed up yet.
+ if (i == 0) continue;
+ _printResult("Run ${'#$i'.padLeft(3)}", elapsed);
+ }
+
+ _printResult('Best ', best);
+}
+
+String _loadFile(String name) {
+ final path = p.join(p.dirname(p.fromUri(Platform.script)), name);
+ return File(path).readAsStringSync();
+}
+
+void _printResult(String label, double time) {
+ print(
+ '$label: ${time.toStringAsFixed(2).padLeft(4)}ms '
+ "${'=' * ((time * 20).toInt())}",
+ );
+}
diff --git a/pkgs/markdown/benchmark/input.md b/pkgs/markdown/benchmark/input.md
new file mode 100644
index 0000000..2dd9df5
--- /dev/null
+++ b/pkgs/markdown/benchmark/input.md
@@ -0,0 +1,421 @@
+**TODO: Add more examples to cover all of the syntax.**
+
+# Regressions
+
+Bad backtracking in the HR parser:
+
+-------------------------- | -------------------------------------------------
+
+# Real-world sample
+
+This input was taken from the test package's README to get a representative
+sample of real-world markdown:
+
+Tests are specified using the top-level [`test()`][test] function, and test
+assertions are made using [`expect()`][expect]:
+
+[test]: https://pub.dev/documentation/test_core/latest/test_core/test.html
+[expect]: https://pub.dev/documentation/test_api/latest/test_api/expect.html
+
+```dart
+import "package:test/test.dart";
+
+void main() {
+ test("String.split() splits the string on the delimiter", () {
+ var string = "foo,bar,baz";
+ expect(string.split(","), equals(["foo", "bar", "baz"]));
+ });
+
+ test("String.trim() removes surrounding whitespace", () {
+ var string = " foo ";
+ expect(string.trim(), equals("foo"));
+ });
+}
+```
+
+Tests can be grouped together using the [`group()`] function. Each group's
+description is added to the beginning of its test's descriptions.
+
+```dart
+import "package:test/test.dart";
+
+void main() {
+ group("String", () {
+ test(".split() splits the string on the delimiter", () {
+ var string = "foo,bar,baz";
+ expect(string.split(","), equals(["foo", "bar", "baz"]));
+ });
+
+ test(".trim() removes surrounding whitespace", () {
+ var string = " foo ";
+ expect(string.trim(), equals("foo"));
+ });
+ });
+
+ group("int", () {
+ test(".remainder() returns the remainder of division", () {
+ expect(11.remainder(3), equals(2));
+ });
+
+ test(".toRadixString() returns a hex string", () {
+ expect(11.toRadixString(16), equals("b"));
+ });
+ });
+}
+```
+
+Any matchers from the [`matcher`][matcher] package can be used with `expect()`
+to do complex validations:
+
+[matcher]: https://pub.dev/documentation/matcher/latest/matcher/matcher-library.html
+
+```dart
+import "package:test/test.dart";
+
+void main() {
+ test(".split() splits the string on the delimiter", () {
+ expect("foo,bar,baz", allOf([
+ contains("foo"),
+ isNot(startsWith("bar")),
+ endsWith("baz")
+ ]));
+ });
+}
+```
+
+## Running Tests
+
+A single test file can be run just using `dart run test path/to/test.dart`.
+
+Many tests can be run at a time using `dart run test path/to/dir`.
+
+It's also possible to run a test on the Dart VM only by invoking it using `dart
+path/to/test.dart`, but this doesn't load the full test runner and will be
+missing some features.
+
+The test runner considers any file that ends with `_test.dart` to be a test
+file. If you don't pass any paths, it will run all the test files in your
+`test/` directory, making it easy to test your entire application at once.
+
+By default, tests are run in the Dart VM, but you can run them in the browser as
+well by passing `dart run test -p chrome path/to/test.dart`.
+`test` will take care of starting the browser and loading the tests, and all
+the results will be reported on the command line just like for VM tests. In
+fact, you can even run tests on both platforms with a single command: `dart run
+test -p chrome,vm path/to/test.dart`.
+
+### Restricting Tests to Certain Platforms
+
+Some test files only make sense to run on particular platforms. They may use
+`dart:html` or `dart:io`, they might test Windows' particular filesystem
+behavior, or they might use a feature that's only available in Chrome. The
+[`@TestOn`][TestOn] annotation makes it easy to declare exactly which platforms
+a test file should run on. Just put it at the top of your file, before any
+`library` or `import` declarations:
+
+```dart
+@TestOn("vm")
+
+import "dart:io";
+
+import "package:test/test.dart";
+
+void main() {
+ // ...
+}
+```
+
+[TestOn]: https://pub.dev/documentation/test_api/latest/test_api/TestOn-class.html
+
+The string you pass to `@TestOn` is what's called a "platform selector", and it
+specifies exactly which platforms a test can run on. It can be as simple as the
+name of a platform, or a more complex Dart-like boolean expression involving
+these platform names.
+
+### Platform Selector Syntax
+
+Platform selectors can contain identifiers, parentheses, and operators. When
+loading a test, each identifier is set to `true` or `false` based on the current
+platform, and the test is only loaded if the platform selector returns `true`.
+The operators `||`, `&&`, `!`, and `? :` all work just like they do in Dart. The
+valid identifiers are:
+
+* `vm`: Whether the test is running on the command-line Dart VM.
+
+* `dartium`: Whether the test is running on Dartium.
+
+* `content-shell`: Whether the test is running on the headless Dartium content
+ shell.
+
+* `chrome`: Whether the test is running on Google Chrome.
+
+* `phantomjs`: Whether the test is running on
+ [PhantomJS](http://phantomjs.org/).
+
+* `firefox`: Whether the test is running on Mozilla Firefox.
+
+* `safari`: Whether the test is running on Apple Safari.
+
+* `ie`: Whether the test is running on Microsoft Internet Explorer.
+
+* `dart-vm`: Whether the test is running on the Dart VM in any context,
+ including Dartium. It's identical to `!js`.
+
+* `browser`: Whether the test is running in any browser.
+
+* `js`: Whether the test has been compiled to JS. This is identical to
+ `!dart-vm`.
+
+* `blink`: Whether the test is running in a browser that uses the Blink
+ rendering engine.
+
+* `windows`: Whether the test is running on Windows. If `vm` is false, this will
+ be `false` as well.
+
+* `mac-os`: Whether the test is running on Mac OS. If `vm` is false, this will
+ be `false` as well.
+
+* `linux`: Whether the test is running on Linux. If `vm` is false, this will be
+ `false` as well.
+
+* `android`: Whether the test is running on Android. If `vm` is false, this will
+ be `false` as well, which means that this *won't* be true if the test is
+ running on an Android browser.
+
+* `posix`: Whether the test is running on a POSIX operating system. This is
+ equivalent to `!windows`.
+
+For example, if you wanted to run a test on every browser but Chrome, you would
+write `@TestOn("browser && !chrome")`.
+
+## Asynchronous Tests
+
+Tests written with `async`/`await` will work automatically. The test runner
+won't consider the test finished until the returned `Future` completes.
+
+```dart
+import "dart:async";
+
+import "package:test/test.dart";
+
+void main() {
+ test("new Future.value() returns the value", () async {
+ var value = await new Future.value(10);
+ expect(value, equals(10));
+ });
+}
+```
+
+There are also a number of useful functions and matchers for more advanced
+asynchrony. The [`completion()`][completion] matcher can be used to test
+`Futures`; it ensures that the test doesn't finish until the `Future` completes,
+and runs a matcher against that `Future`'s value.
+
+[completion]: https://pub.dev/documentation/test_api/latest/test_api/completion.html
+
+```dart
+import "dart:async";
+
+import "package:test/test.dart";
+
+void main() {
+ test("new Future.value() returns the value", () {
+ expect(new Future.value(10), completion(equals(10)));
+ });
+}
+```
+
+The [`throwsA()`][throwsA] matcher and the various `throwsExceptionType`
+matchers work with both synchronous callbacks and asynchronous `Future`s. They
+ensure that a particular type of exception is thrown:
+
+[throwsA]: https://pub.dev/documentation/test_api/latest/test_api/throwsA.html
+
+```dart
+import "dart:async";
+
+import "package:test/test.dart";
+
+void main() {
+ test("new Future.error() throws the error", () {
+ expect(new Future.error("oh no"), throwsA(equals("oh no")));
+ expect(new Future.error(new StateError("bad state")), throwsStateError);
+ });
+}
+```
+
+The [`expectAsync()`][expectAsync] function wraps another function and has two
+jobs. First, it asserts that the wrapped function is called a certain number of
+times, and will cause the test to fail if it's called too often; second, it
+keeps the test from finishing until the function is called the requisite number
+of times.
+
+```dart
+import "dart:async";
+
+import "package:test/test.dart";
+
+void main() {
+ test("Stream.fromIterable() emits the values in the iterable", () {
+ var stream = new Stream.fromIterable([1, 2, 3]);
+
+ stream.listen(expectAsync((number) {
+ expect(number, inInclusiveRange(1, 3));
+ }, count: 3));
+ });
+}
+```
+
+[expectAsync]: https://pub.dev/documentation/test_api/latest/test_api/expectAsync.html
+
+## Running Tests with Custom HTML
+
+By default, the test runner will generate its own empty HTML file for browser
+tests. However, tests that need custom HTML can create their own files. These
+files have three requirements:
+
+* They must have the same name as the test, with `.dart` replaced by `.html`.
+
+* They must contain a `link` tag with `rel="x-dart-test"` and an `href`
+ attribute pointing to the test script.
+
+* They must contain `<script src="packages/test/dart.js"></script>`.
+
+For example, if you had a test called `custom_html_test.dart`, you might write
+the following HTML file:
+
+```html
+<!doctype html>
+<!-- custom_html_test.html -->
+<html>
+ <head>
+ <title>Custom HTML Test</title>
+ <link rel="x-dart-test" href="custom_html_test.dart">
+ <script src="packages/test/dart.js"></script>
+ </head>
+ <body>
+ // ...
+ </body>
+</html>
+```
+
+## Configuring Tests
+
+### Skipping Tests
+
+If a test, group, or entire suite isn't working yet and you just want it to stop
+complaining, you can mark it as "skipped". The test or tests won't be run, and,
+if you supply a reason why, that reason will be printed. In general, skipping
+tests indicates that they should run but is temporarily not working. If they're
+is fundamentally incompatible with a platform, [`@TestOn`/`testOn`][TestOn]
+should be used instead.
+
+[TestOn]: #restricting-tests-to-certain-platforms
+
+To skip a test suite, put a `@Skip` annotation at the top of the file:
+
+```dart
+@Skip("currently failing (see issue 1234)")
+
+import "package:test/test.dart";
+
+void main() {
+ // ...
+}
+```
+
+The string you pass should describe why the test is skipped. You don't have to
+include it, but it's a good idea to document why the test isn't running.
+
+Groups and individual tests can be skipped by passing the `skip` parameter. This
+can be either `true` or a String describing why the test is skipped. For example:
+
+```dart
+import "package:test/test.dart";
+
+void main() {
+ group("complicated algorithm tests", () {
+ // ...
+ }, skip: "the algorithm isn't quite right");
+
+ test("error-checking test", () {
+ // ...
+ }, skip: "TODO: add error-checking.");
+}
+```
+
+### Timeouts
+
+By default, tests will time out after 30 seconds of inactivity. However, this
+can be configured on a per-test, -group, or -suite basis. To change the timeout
+for a test suite, put a `@Timeout` annotation at the top of the file:
+
+```dart
+@Timeout(const Duration(seconds: 45))
+
+import "package:test/test.dart";
+
+void main() {
+ // ...
+}
+```
+
+In addition to setting an absolute timeout, you can set the timeout relative to
+the default using `@Timeout.factor`. For example, `@Timeout.factor(1.5)` will
+set the timeout to one and a half times as long as the default—45 seconds.
+
+Timeouts can be set for tests and groups using the `timeout` parameter. This
+parameter takes a `Timeout` object just like the annotation. For example:
+
+```dart
+import "package:test/test.dart";
+
+void main() {
+ group("slow tests", () {
+ // ...
+
+ test("even slower test", () {
+ // ...
+ }, timeout: new Timeout.factor(2))
+ }, timeout: new Timeout(new Duration(minutes: 1)));
+}
+```
+
+Nested timeouts apply in order from outermost to innermost. That means that
+"even slower test" will take two minutes to time out, since it multiplies the
+group's timeout by 2.
+
+### Platform-Specific Configuration
+
+Sometimes a test may need to be configured differently for different platforms.
+Windows might run your code slower than other platforms, or your DOM
+manipulation might not work right on Safari yet. For these cases, you can use
+the `@OnPlatform` annotation and the `onPlatform` named parameter to `test()`
+and `group()`. For example:
+
+```dart
+@OnPlatform(const {
+ // Give Windows some extra wiggle-room before timing out.
+ "windows": const Timeout.factor(2)
+})
+
+import "package:test/test.dart";
+
+void main() {
+ test("do a thing", () {
+ // ...
+ }, onPlatform: {
+ "safari": new Skip("Safari is currently broken (see #1234)")
+ });
+}
+```
+
+Both the annotation and the parameter take a map. The map's keys are [platform
+selectors](#platform-selector-syntax) which describe the platforms for which the
+specialized configuration applies. Its values are instances of some of the same
+annotation classes that can be used for a suite: `Skip` and `Timeout`. A value
+can also be a list of these values.
+
+If multiple platforms match, the configuration is applied in order from first to
+last, just as they would in nested groups. This means that for configuration
+like duration-based timeouts, the last matching value wins.
diff --git a/pkgs/markdown/benchmark/output.html b/pkgs/markdown/benchmark/output.html
new file mode 100644
index 0000000..200e4bd
--- /dev/null
+++ b/pkgs/markdown/benchmark/output.html
@@ -0,0 +1,360 @@
+<p><strong>TODO: Add more examples to cover all of the syntax.</strong></p>
+<h1>Regressions</h1>
+<p>Bad backtracking in the HR parser:</p>
+<p>-------------------------- | -------------------------------------------------</p>
+<h1>Real-world sample</h1>
+<p>This input was taken from the test package's README to get a representative
+sample of real-world markdown:</p>
+<p>Tests are specified using the top-level <a href="https://pub.dev/documentation/test_core/latest/test_core/test.html"><code>test()</code></a> function, and test
+assertions are made using <a href="https://pub.dev/documentation/test_api/latest/test_api/expect.html"><code>expect()</code></a>:</p>
+<pre><code class="language-dart">import "package:test/test.dart";
+
+void main() {
+ test("String.split() splits the string on the delimiter", () {
+ var string = "foo,bar,baz";
+ expect(string.split(","), equals(["foo", "bar", "baz"]));
+ });
+
+ test("String.trim() removes surrounding whitespace", () {
+ var string = " foo ";
+ expect(string.trim(), equals("foo"));
+ });
+}
+</code></pre>
+<p>Tests can be grouped together using the [<code>group()</code>] function. Each group's
+description is added to the beginning of its test's descriptions.</p>
+<pre><code class="language-dart">import "package:test/test.dart";
+
+void main() {
+ group("String", () {
+ test(".split() splits the string on the delimiter", () {
+ var string = "foo,bar,baz";
+ expect(string.split(","), equals(["foo", "bar", "baz"]));
+ });
+
+ test(".trim() removes surrounding whitespace", () {
+ var string = " foo ";
+ expect(string.trim(), equals("foo"));
+ });
+ });
+
+ group("int", () {
+ test(".remainder() returns the remainder of division", () {
+ expect(11.remainder(3), equals(2));
+ });
+
+ test(".toRadixString() returns a hex string", () {
+ expect(11.toRadixString(16), equals("b"));
+ });
+ });
+}
+</code></pre>
+<p>Any matchers from the <a href="https://pub.dev/documentation/matcher/latest/matcher/matcher-library.html"><code>matcher</code></a> package can be used with <code>expect()</code>
+to do complex validations:</p>
+<pre><code class="language-dart">import "package:test/test.dart";
+
+void main() {
+ test(".split() splits the string on the delimiter", () {
+ expect("foo,bar,baz", allOf([
+ contains("foo"),
+ isNot(startsWith("bar")),
+ endsWith("baz")
+ ]));
+ });
+}
+</code></pre>
+<h2>Running Tests</h2>
+<p>A single test file can be run just using <code>pub run test:test path/to/test.dart</code>
+(on Dart 1.10, this can be shortened to <code>pub run test path/to/test.dart</code>).</p>
+<p><img src="https://raw.githubusercontent.com/dart-lang/test/master/image/test1.gif" alt="Single file being run via pub run"" /></p>
+<p>Many tests can be run at a time using <code>pub run test:test path/to/dir</code>.</p>
+<p><img src="https://raw.githubusercontent.com/dart-lang/test/master/image/test2.gif" alt="Directory being run via "pub run"." /></p>
+<p>It's also possible to run a test on the Dart VM only by invoking it using <code>dart path/to/test.dart</code>, but this doesn't load the full test runner and will be
+missing some features.</p>
+<p>The test runner considers any file that ends with <code>_test.dart</code> to be a test
+file. If you don't pass any paths, it will run all the test files in your
+<code>test/</code> directory, making it easy to test your entire application at once.</p>
+<p>By default, tests are run in the Dart VM, but you can run them in the browser as
+well by passing <code>pub run test:test -p chrome path/to/test.dart</code>.
+<code>test</code> will take care of starting the browser and loading the tests, and all
+the results will be reported on the command line just like for VM tests. In
+fact, you can even run tests on both platforms with a single command: <code>pub run test:test -p "chrome,vm" path/to/test.dart</code>.</p>
+<h3>Restricting Tests to Certain Platforms</h3>
+<p>Some test files only make sense to run on particular platforms. They may use
+<code>dart:html</code> or <code>dart:io</code>, they might test Windows' particular filesystem
+behavior, or they might use a feature that's only available in Chrome. The
+<a href="https://pub.dev/documentation/test_api/latest/test_api/TestOn-class.html"><code>@TestOn</code></a> annotation makes it easy to declare exactly which platforms
+a test file should run on. Just put it at the top of your file, before any
+<code>library</code> or <code>import</code> declarations:</p>
+<pre><code class="language-dart">@TestOn("vm")
+
+import "dart:io";
+
+import "package:test/test.dart";
+
+void main() {
+ // ...
+}
+</code></pre>
+<p>The string you pass to <code>@TestOn</code> is what's called a "platform selector", and it
+specifies exactly which platforms a test can run on. It can be as simple as the
+name of a platform, or a more complex Dart-like boolean expression involving
+these platform names.</p>
+<h3>Platform Selector Syntax</h3>
+<p>Platform selectors can contain identifiers, parentheses, and operators. When
+loading a test, each identifier is set to <code>true</code> or <code>false</code> based on the current
+platform, and the test is only loaded if the platform selector returns <code>true</code>.
+The operators <code>||</code>, <code>&&</code>, <code>!</code>, and <code>? :</code> all work just like they do in Dart. The
+valid identifiers are:</p>
+<ul>
+<li>
+<p><code>vm</code>: Whether the test is running on the command-line Dart VM.</p>
+</li>
+<li>
+<p><code>dartium</code>: Whether the test is running on Dartium.</p>
+</li>
+<li>
+<p><code>content-shell</code>: Whether the test is running on the headless Dartium content
+shell.</p>
+</li>
+<li>
+<p><code>chrome</code>: Whether the test is running on Google Chrome.</p>
+</li>
+<li>
+<p><code>phantomjs</code>: Whether the test is running on
+<a href="http://phantomjs.org/">PhantomJS</a>.</p>
+</li>
+<li>
+<p><code>firefox</code>: Whether the test is running on Mozilla Firefox.</p>
+</li>
+<li>
+<p><code>safari</code>: Whether the test is running on Apple Safari.</p>
+</li>
+<li>
+<p><code>ie</code>: Whether the test is running on Microsoft Internet Explorer.</p>
+</li>
+<li>
+<p><code>dart-vm</code>: Whether the test is running on the Dart VM in any context,
+including Dartium. It's identical to <code>!js</code>.</p>
+</li>
+<li>
+<p><code>browser</code>: Whether the test is running in any browser.</p>
+</li>
+<li>
+<p><code>js</code>: Whether the test has been compiled to JS. This is identical to
+<code>!dart-vm</code>.</p>
+</li>
+<li>
+<p><code>blink</code>: Whether the test is running in a browser that uses the Blink
+rendering engine.</p>
+</li>
+<li>
+<p><code>windows</code>: Whether the test is running on Windows. If <code>vm</code> is false, this will
+be <code>false</code> as well.</p>
+</li>
+<li>
+<p><code>mac-os</code>: Whether the test is running on Mac OS. If <code>vm</code> is false, this will
+be <code>false</code> as well.</p>
+</li>
+<li>
+<p><code>linux</code>: Whether the test is running on Linux. If <code>vm</code> is false, this will be
+<code>false</code> as well.</p>
+</li>
+<li>
+<p><code>android</code>: Whether the test is running on Android. If <code>vm</code> is false, this will
+be <code>false</code> as well, which means that this <em>won't</em> be true if the test is
+running on an Android browser.</p>
+</li>
+<li>
+<p><code>posix</code>: Whether the test is running on a POSIX operating system. This is
+equivalent to <code>!windows</code>.</p>
+</li>
+</ul>
+<p>For example, if you wanted to run a test on every browser but Chrome, you would
+write <code>@TestOn("browser && !chrome")</code>.</p>
+<h2>Asynchronous Tests</h2>
+<p>Tests written with <code>async</code>/<code>await</code> will work automatically. The test runner
+won't consider the test finished until the returned <code>Future</code> completes.</p>
+<pre><code class="language-dart">import "dart:async";
+
+import "package:test/test.dart";
+
+void main() {
+ test("new Future.value() returns the value", () async {
+ var value = await new Future.value(10);
+ expect(value, equals(10));
+ });
+}
+</code></pre>
+<p>There are also a number of useful functions and matchers for more advanced
+asynchrony. The <a href="https://pub.dev/documentation/test_api/latest/test_api/completion.html"><code>completion()</code></a> matcher can be used to test
+<code>Futures</code>; it ensures that the test doesn't finish until the <code>Future</code> completes,
+and runs a matcher against that <code>Future</code>'s value.</p>
+<pre><code class="language-dart">import "dart:async";
+
+import "package:test/test.dart";
+
+void main() {
+ test("new Future.value() returns the value", () {
+ expect(new Future.value(10), completion(equals(10)));
+ });
+}
+</code></pre>
+<p>The <a href="https://pub.dev/documentation/test_api/latest/test_api/throwsA.html"><code>throwsA()</code></a> matcher and the various <code>throwsExceptionType</code>
+matchers work with both synchronous callbacks and asynchronous <code>Future</code>s. They
+ensure that a particular type of exception is thrown:</p>
+<pre><code class="language-dart">import "dart:async";
+
+import "package:test/test.dart";
+
+void main() {
+ test("new Future.error() throws the error", () {
+ expect(new Future.error("oh no"), throwsA(equals("oh no")));
+ expect(new Future.error(new StateError("bad state")), throwsStateError);
+ });
+}
+</code></pre>
+<p>The <a href="https://pub.dev/documentation/test_api/latest/test_api/expectAsync.html"><code>expectAsync()</code></a> function wraps another function and has two
+jobs. First, it asserts that the wrapped function is called a certain number of
+times, and will cause the test to fail if it's called too often; second, it
+keeps the test from finishing until the function is called the requisite number
+of times.</p>
+<pre><code class="language-dart">import "dart:async";
+
+import "package:test/test.dart";
+
+void main() {
+ test("Stream.fromIterable() emits the values in the iterable", () {
+ var stream = new Stream.fromIterable([1, 2, 3]);
+
+ stream.listen(expectAsync((number) {
+ expect(number, inInclusiveRange(1, 3));
+ }, count: 3));
+ });
+}
+</code></pre>
+<h2>Running Tests with Custom HTML</h2>
+<p>By default, the test runner will generate its own empty HTML file for browser
+tests. However, tests that need custom HTML can create their own files. These
+files have three requirements:</p>
+<ul>
+<li>
+<p>They must have the same name as the test, with <code>.dart</code> replaced by <code>.html</code>.</p>
+</li>
+<li>
+<p>They must contain a <code>link</code> tag with <code>rel="x-dart-test"</code> and an <code>href</code>
+attribute pointing to the test script.</p>
+</li>
+<li>
+<p>They must contain <code><script src="packages/test/dart.js"></script></code>.</p>
+</li>
+</ul>
+<p>For example, if you had a test called <code>custom_html_test.dart</code>, you might write
+the following HTML file:</p>
+<pre><code class="language-html"><!doctype html>
+<!-- custom_html_test.html -->
+<html>
+ <head>
+ <title>Custom HTML Test</title>
+ <link rel="x-dart-test" href="custom_html_test.dart">
+ <script src="packages/test/dart.js"></script>
+ </head>
+ <body>
+ // ...
+ </body>
+</html>
+</code></pre>
+<h2>Configuring Tests</h2>
+<h3>Skipping Tests</h3>
+<p>If a test, group, or entire suite isn't working yet and you just want it to stop
+complaining, you can mark it as "skipped". The test or tests won't be run, and,
+if you supply a reason why, that reason will be printed. In general, skipping
+tests indicates that they should run but is temporarily not working. If they're
+is fundamentally incompatible with a platform, <a href="https://pub.dev/documentation/test_api/latest/test_api/TestOn-class.html"><code>@TestOn</code>/<code>testOn</code></a>
+should be used instead.</p>
+<p>To skip a test suite, put a <code>@Skip</code> annotation at the top of the file:</p>
+<pre><code class="language-dart">@Skip("currently failing (see issue 1234)")
+
+import "package:test/test.dart";
+
+void main() {
+ // ...
+}
+</code></pre>
+<p>The string you pass should describe why the test is skipped. You don't have to
+include it, but it's a good idea to document why the test isn't running.</p>
+<p>Groups and individual tests can be skipped by passing the <code>skip</code> parameter. This
+can be either <code>true</code> or a String describing why the test is skipped. For example:</p>
+<pre><code class="language-dart">import "package:test/test.dart";
+
+void main() {
+ group("complicated algorithm tests", () {
+ // ...
+ }, skip: "the algorithm isn't quite right");
+
+ test("error-checking test", () {
+ // ...
+ }, skip: "TODO: add error-checking.");
+}
+</code></pre>
+<h3>Timeouts</h3>
+<p>By default, tests will time out after 30 seconds of inactivity. However, this
+can be configured on a per-test, -group, or -suite basis. To change the timeout
+for a test suite, put a <code>@Timeout</code> annotation at the top of the file:</p>
+<pre><code class="language-dart">@Timeout(const Duration(seconds: 45))
+
+import "package:test/test.dart";
+
+void main() {
+ // ...
+}
+</code></pre>
+<p>In addition to setting an absolute timeout, you can set the timeout relative to
+the default using <code>@Timeout.factor</code>. For example, <code>@Timeout.factor(1.5)</code> will
+set the timeout to one and a half times as long as the default—45 seconds.</p>
+<p>Timeouts can be set for tests and groups using the <code>timeout</code> parameter. This
+parameter takes a <code>Timeout</code> object just like the annotation. For example:</p>
+<pre><code class="language-dart">import "package:test/test.dart";
+
+void main() {
+ group("slow tests", () {
+ // ...
+
+ test("even slower test", () {
+ // ...
+ }, timeout: new Timeout.factor(2))
+ }, timeout: new Timeout(new Duration(minutes: 1)));
+}
+</code></pre>
+<p>Nested timeouts apply in order from outermost to innermost. That means that
+"even slower test" will take two minutes to time out, since it multiplies the
+group's timeout by 2.</p>
+<h3>Platform-Specific Configuration</h3>
+<p>Sometimes a test may need to be configured differently for different platforms.
+Windows might run your code slower than other platforms, or your DOM
+manipulation might not work right on Safari yet. For these cases, you can use
+the <code>@OnPlatform</code> annotation and the <code>onPlatform</code> named parameter to <code>test()</code>
+and <code>group()</code>. For example:</p>
+<pre><code class="language-dart">@OnPlatform(const {
+ // Give Windows some extra wiggle-room before timing out.
+ "windows": const Timeout.factor(2)
+})
+
+import "package:test/test.dart";
+
+void main() {
+ test("do a thing", () {
+ // ...
+ }, onPlatform: {
+ "safari": new Skip("Safari is currently broken (see #1234)")
+ });
+}
+</code></pre>
+<p>Both the annotation and the parameter take a map. The map's keys are <a href="#platform-selector-syntax">platform
+selectors</a> which describe the platforms for which the
+specialized configuration applies. Its values are instances of some of the same
+annotation classes that can be used for a suite: <code>Skip</code> and <code>Timeout</code>. A value
+can also be a list of these values.</p>
+<p>If multiple platforms match, the configuration is applied in order from first to
+last, just as they would in nested groups. This means that for configuration
+like duration-based timeouts, the last matching value wins.</p>
diff --git a/pkgs/markdown/bin/markdown.dart b/pkgs/markdown/bin/markdown.dart
new file mode 100644
index 0000000..76926c6
--- /dev/null
+++ b/pkgs/markdown/bin/markdown.dart
@@ -0,0 +1,81 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:io';
+
+import 'package:args/args.dart';
+import 'package:markdown/markdown.dart';
+
+final extensionSets = <String, ExtensionSet>{
+ 'none': ExtensionSet.none,
+ 'CommonMark': ExtensionSet.commonMark,
+ 'GitHubFlavored': ExtensionSet.gitHubFlavored,
+ 'GitHubWeb': ExtensionSet.gitHubWeb,
+};
+
+Future<void> main(List<String> args) async {
+ final parser = ArgParser()
+ ..addFlag('help', negatable: false, help: 'Print help text and exit')
+ ..addFlag('version', negatable: false, help: 'Print version and exit')
+ ..addOption(
+ 'extension-set',
+ allowed: ['none', 'CommonMark', 'GitHubFlavored', 'GitHubWeb'],
+ defaultsTo: 'CommonMark',
+ help: 'Specify a set of extensions',
+ allowedHelp: {
+ 'none': 'No extensions; similar to Markdown.pl',
+ 'CommonMark': 'Parse like CommonMark Markdown (default)',
+ 'GitHubFlavored': 'Parse like GitHub Flavored Markdown',
+ 'GitHubWeb': 'Parse like GitHub\'s Markdown-enabled web input fields',
+ },
+ );
+ final results = parser.parse(args);
+
+ if (results['help'] as bool) {
+ printUsage(parser);
+ return;
+ }
+
+ if (results['version'] as bool) {
+ print(version);
+ return;
+ }
+
+ final extensionSet = extensionSets[results['extension-set']];
+
+ if (results.rest.length > 1) {
+ printUsage(parser);
+ exitCode = 1;
+ return;
+ }
+
+ if (results.rest.length == 1) {
+ // Read argument as a file path.
+ final input = File(results.rest.first).readAsStringSync();
+ print(markdownToHtml(input, extensionSet: extensionSet));
+ return;
+ }
+
+ // Read from stdin.
+ final buffer = StringBuffer();
+ String? line;
+ while ((line = stdin.readLineSync()) != null) {
+ buffer.writeln(line);
+ }
+ print(markdownToHtml(buffer.toString(), extensionSet: extensionSet));
+}
+
+void printUsage(ArgParser parser) {
+ print('''Usage: markdown.dart [options] [file]
+
+Parse [file] as Markdown and print resulting HTML. If [file] is omitted,
+use stdin as input.
+
+By default, CommonMark Markdown will be parsed. This can be changed with
+the --extensionSet flag.
+
+${parser.usage}
+''');
+}
diff --git a/pkgs/markdown/dart_test.yaml b/pkgs/markdown/dart_test.yaml
new file mode 100644
index 0000000..588b409
--- /dev/null
+++ b/pkgs/markdown/dart_test.yaml
@@ -0,0 +1,6 @@
+tags:
+ crash_test:
+ skip: 'Only run crash_test tests manually with `dart test -P crash_test`'
+ presets:
+ crash_test:
+ skip: false # Don't skip when running in -P crash_test
diff --git a/pkgs/markdown/example/app.dart b/pkgs/markdown/example/app.dart
new file mode 100644
index 0000000..14b8f19
--- /dev/null
+++ b/pkgs/markdown/example/app.dart
@@ -0,0 +1,148 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:js_interop';
+
+import 'package:markdown/markdown.dart' as md;
+import 'package:web/web.dart';
+
+import 'highlight.dart';
+
+final markdownInput =
+ document.querySelector('#markdown') as HTMLTextAreaElement;
+final htmlDiv = document.querySelector('#html') as HTMLDivElement;
+final versionSpan = document.querySelector('.version') as HTMLSpanElement;
+
+const typing = Duration(milliseconds: 150);
+const introText = '''Markdown is the **best**!
+
+* It has lists.
+* It has [links](https://dart.dev).
+* It has...
+ ```dart
+ void sourceCode() {}
+ ```
+* ...and _so much more_...''';
+
+// Flavor support.
+final basicRadio = document.querySelector('#basic-radio') as HTMLElement;
+final commonmarkRadio =
+ document.querySelector('#commonmark-radio') as HTMLElement;
+final gfmRadio = document.querySelector('#gfm-radio') as HTMLElement;
+md.ExtensionSet? extensionSet;
+
+final extensionSets = {
+ 'basic-radio': md.ExtensionSet.none,
+ 'commonmark-radio': md.ExtensionSet.commonMark,
+ 'gfm-radio': md.ExtensionSet.gitHubWeb,
+};
+
+void main() {
+ versionSpan.text = 'v${md.version}';
+ markdownInput.onKeyUp.listen(_renderMarkdown);
+
+ final savedMarkdown = window.localStorage['markdown'];
+
+ if (savedMarkdown != null &&
+ savedMarkdown.isNotEmpty &&
+ savedMarkdown != introText) {
+ markdownInput.value = savedMarkdown;
+ markdownInput.focus();
+ _renderMarkdown();
+ } else {
+ _typeItOut(introText, 82);
+ }
+
+ // GitHub is the default extension set.
+ gfmRadio.attributes.getNamedItem('checked')?.value = '';
+ gfmRadio.querySelector('.glyph')!.text = 'radio_button_checked';
+ extensionSet = extensionSets[gfmRadio.id];
+ _renderMarkdown();
+
+ basicRadio.onClick.listen(_switchFlavor);
+ commonmarkRadio.onClick.listen(_switchFlavor);
+ gfmRadio.onClick.listen(_switchFlavor);
+}
+
+void _renderMarkdown([Event? event]) {
+ final markdown = markdownInput.value;
+
+ htmlDiv.innerHtml = md.markdownToHtml(markdown, extensionSet: extensionSet);
+
+ for (final block in htmlDiv.querySelectorAll('pre code').items) {
+ try {
+ highlightElement(block);
+ } catch (e) {
+ console.error('Error highlighting markdown:'.toJS);
+ console.error(e.toString().toJS);
+ }
+ }
+
+ if (event != null) {
+ // Not simulated typing. Store it.
+ window.localStorage['markdown'] = markdown;
+ }
+}
+
+void _typeItOut(String msg, int pos) {
+ late Timer timer;
+ markdownInput.onKeyUp.listen((_) {
+ timer.cancel();
+ });
+ void addCharacter() {
+ if (pos > msg.length) {
+ return;
+ }
+ markdownInput.value = msg.substring(0, pos);
+ markdownInput.focus();
+ _renderMarkdown();
+ pos++;
+ timer = Timer(typing, addCharacter);
+ }
+
+ timer = Timer(typing, addCharacter);
+}
+
+void _switchFlavor(Event e) {
+ final target = e.currentTarget as HTMLElement;
+ if (target.attributes.getNamedItem('checked') == null) {
+ if (basicRadio != target) {
+ basicRadio.attributes.safeRemove('checked');
+ basicRadio.querySelector('.glyph')!.text = 'radio_button_unchecked';
+ }
+ if (commonmarkRadio != target) {
+ commonmarkRadio.attributes.safeRemove('checked');
+ commonmarkRadio.querySelector('.glyph')!.text = 'radio_button_unchecked';
+ }
+ if (gfmRadio != target) {
+ gfmRadio.attributes.safeRemove('checked');
+ gfmRadio.querySelector('.glyph')!.text = 'radio_button_unchecked';
+ }
+
+ target.attributes.getNamedItem('checked')?.value = '';
+ target.querySelector('.glyph')!.text = 'radio_button_checked';
+ extensionSet = extensionSets[target.id];
+ _renderMarkdown();
+ }
+}
+
+extension on NodeList {
+ List<Node> get items => [
+ for (var i = 0; i < length; i++) item(i)!,
+ ];
+}
+
+extension on NamedNodeMap {
+ void safeRemove(String qualifiedName) {
+ if (getNamedItem(qualifiedName) != null) removeNamedItem(qualifiedName);
+ }
+}
+
+extension on HTMLDivElement {
+ // The default implementation allows `JSAny` to support trusted types. We only
+ // use `String`s, so prefer this to avoid manual conversions.
+ @JS('innerHTML')
+ external set innerHtml(String value);
+}
diff --git a/pkgs/markdown/example/favicon.png b/pkgs/markdown/example/favicon.png
new file mode 100644
index 0000000..43d2ffa
--- /dev/null
+++ b/pkgs/markdown/example/favicon.png
Binary files differ
diff --git a/pkgs/markdown/example/highlight.dart b/pkgs/markdown/example/highlight.dart
new file mode 100644
index 0000000..b54c447
--- /dev/null
+++ b/pkgs/markdown/example/highlight.dart
@@ -0,0 +1,13 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@JS('hljs')
+library;
+
+import 'dart:js_interop';
+
+import 'package:web/web.dart';
+
+@JS()
+external void highlightElement(Node block);
diff --git a/pkgs/markdown/example/index.html b/pkgs/markdown/example/index.html
new file mode 100644
index 0000000..82650a6
--- /dev/null
+++ b/pkgs/markdown/example/index.html
@@ -0,0 +1,95 @@
+<html>
+ <head>
+ <link rel="icon" sizes="64x64" href="favicon.png">
+ <link rel="stylesheet" href="style.css">
+ <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto+Mono|Roboto">
+ <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons+Extended">
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.5.1/styles/default.min.css" integrity="sha512-hasIneQUHlh06VNBe7f6ZcHmeRTLIaQWFd43YriJ0UND19bvYRauxthDg8E4eVNPm9bRUhr5JGeqH7FRFXQu5g==" crossorigin="anonymous" referrerpolicy="no-referrer" />
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github-markdown-light.min.css" integrity="sha512-zb2pp+R+czM7GAemdSUQt6jFmr3qCo6ikvBgVU6F5GvwEDR0C2sefFiPEJ9QUpmAKdD5EqDUdNRtbOYnbF/eyQ==" crossorigin="anonymous" referrerpolicy="no-referrer" />
+ <script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.5.1/highlight.min.js" integrity="sha512-yUUc0qWm2rhM7X0EFe82LNnv2moqArj5nro/w1bi05A09hRVeIZbN6jlMoyu0+4I/Bu4Ck/85JQIU82T82M28w==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
+ <script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.5.1/languages/dart.min.js" integrity="sha512-14QR6tzX5xTNeMJKXzSK+xCquDvtNEr1jM5NlKy/149BBY50Kv70qqxHtzo6zClbtc1gIG7G0CGWXuMgPIMt0g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
+ <script defer src="app.dart.js"></script>
+ <title>Dart Markdown Live Editor</title>
+ <style>
+.gfm-color_chip span {
+ display: inline-block;
+ line-height: 1;
+ margin: 0 0 2px 4px;
+ vertical-align: middle;
+ border-radius: 3px;
+ width: 0.9em;
+ height: 0.9em;
+ background: #fff;
+}
+
+code.gfm-color_chip {
+ padding: 2px 4px;
+ color: #1f1f1f;
+ background-color: #f0f0f0;
+ border-radius: 4px;
+}
+
+ul.contains-task-list, ol.contains-task-list {
+ margin-left: -1em;
+ list-style-type: none;
+}
+
+.task-list-item {
+ list-style-type: none;
+}
+ </style>
+ </head>
+ <body>
+ <div class="container">
+ <header>
+ <div class="toolbar">
+ <h2>Dart Markdown Live Editor</h2>
+ <span style="display: flex; flex: 1;"></span>
+ <span class="version"></span>
+ <a href="https://github.com/dart-lang/markdown" title="Open Source on GitHub">
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="32" height="32">
+ <path fill-rule="evenodd" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"></path>
+ </svg>
+ </a>
+ </div>
+ </header>
+ <div class="main">
+ <div class="card">
+ <div class="toolbar">
+ <h2>Markdown</h2>
+ </div>
+ <div style="padding: 8px; display: flex; height: 100%;">
+ <textarea id="markdown"></textarea>
+ </div>
+ </div>
+ <div class="card">
+ <div class="toolbar">
+ <h2>HTML</h2>
+ </div>
+ <div id="html" class="markdown-body"></div>
+ </div>
+ </div>
+ <footer>
+ <span style="margin-right: 16px;">Markdown Flavor:</span>
+ <div class="radio" id="basic-radio">
+ <i class="glyph">radio_button_unchecked</i>
+ Basic Markdown
+ </div>
+ <div class="radio" id="commonmark-radio">
+ <i class="glyph">radio_button_unchecked</i>
+ CommonMark
+ </div>
+ <div class="radio" id="gfm-radio">
+ <i class="glyph">radio_button_unchecked</i>
+ GitHub Flavored Markdown
+ </div>
+ <span style="display: flex; flex: 1;"></span>
+ <a href="https://github.com/dart-lang/markdown#extension-sets"
+ target="_blank"
+ title="More info">
+ <i class="big glyph">help</i>
+ </a>
+ </footer>
+ </div>
+ </body>
+</html>
diff --git a/pkgs/markdown/example/style.css b/pkgs/markdown/example/style.css
new file mode 100644
index 0000000..bfacfb0
--- /dev/null
+++ b/pkgs/markdown/example/style.css
@@ -0,0 +1,152 @@
+html, body {
+ background-color: rgb(250, 250, 250);
+ font-family: Roboto,"Helvetica Neue",sans-serif;
+ font-size: 16px;
+ margin: 0;
+}
+
+.container {
+ box-sizing: border-box;
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ width: 100%;
+}
+
+.main {
+ align-items: stretch;
+ box-sizing: border-box;
+ display: flex;
+ flex-direction: row;
+ height: 100%;
+ margin: 32px;
+}
+
+.version {
+ color: rgba(0, 0, 0, 0.54);
+ margin-right: 16px;
+}
+
+.card {
+ /* Styled like Material Cards. */
+ color: rgba(0, 0, 0, 0.87);
+ background-color: white;
+ border-radius: 2px;
+ box-sizing: border-box;
+ box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .2),
+ 0 1px 1px 0 rgba(0, 0, 0, .14),
+ 0 2px 1px -1px rgba(0, 0, 0, .12);
+ margin: 8px;
+
+ /* Positioned next to each other. */
+ display: flex;
+ flex: 1 1 50%;
+ flex-direction: column;
+ max-height: 100%;
+ max-width: 50%;
+ min-height: 400px;
+}
+
+.toolbar {
+ /* Styled like Material Toolbar. */
+ align-items: center;
+ background-color: #22d3c5;
+ box-sizing: border-box;
+ color: rgba(0, 0, 0, 0.87);
+ display: flex;
+ font-size: 20px;
+ line-height: 1.4;
+ margin: 0;
+ min-height: 64px;
+ padding: 0 16px;
+ position: relative;
+ width: 100%;
+}
+
+.toolbar h2 {
+ font-size: inherit;
+ font-weight: inherit;
+ margin: inherit;
+}
+
+.toolbar a:link,
+.toolbar a:visited {
+ color: rgba(0, 0, 0, 0.87);
+}
+
+.toolbar svg {
+ fill: currentColor;
+}
+
+.card .toolbar {
+ border-radius: 3px 3px 0 0;
+}
+
+.textarea-container {
+ display: flex;
+ height: 100%;
+ padding: 8px;
+}
+
+textarea {
+ border-color: rgba(0, 0, 0, 0.12);
+ border-width: 0 0 1px;
+ box-sizing: border-box;
+ color: rgba(0, 0, 0, 0.87);
+ font-family: "Roboto Mono",monospace;
+ font-size: 100%;
+ line-height: 26px;
+ overflow: auto;
+ padding: 2px 2px 1px;
+ width: 100%;
+}
+
+textarea:focus {
+ border-color: #22d3c5;
+ border-width: 0 0 2px;
+ outline: 0;
+ padding-bottom: 0;
+}
+
+#html {
+ overflow: auto;
+ padding: 8px;
+}
+
+footer {
+ box-sizing: border-box;
+ display: flex;
+ font-size: 20px;
+ height: 64px;
+ padding: 0 16px;
+}
+
+footer a:link,
+footer a:visited {
+ color: rgba(0, 0, 0, 0.87);
+}
+
+.radio {
+ cursor: pointer;
+ display: inline-block;
+ margin-right: 16px;
+}
+
+i.glyph {
+ display: inline-block;
+ font-family: 'Material Icons Extended';
+ font-size: 16px;
+ font-style: normal;
+ font-weight: normal;
+ line-height: 1;
+}
+
+.radio[checked] i.glyph {
+ color: #22d3c5;
+}
+
+i.glyph.big {
+ font-size: 32px;
+ height: 32px;
+ width: 32px;
+}
diff --git a/pkgs/markdown/lib/markdown.dart b/pkgs/markdown/lib/markdown.dart
new file mode 100644
index 0000000..9fac732
--- /dev/null
+++ b/pkgs/markdown/lib/markdown.dart
@@ -0,0 +1,94 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Parses text in a Markdown-like format building an
+/// [AST tree](https://en.wikipedia.org/wiki/Abstract_syntax_tree)
+/// that can then be rendered to HTML.
+///
+/// If you are only interested in rendering Markdown to HTML please refer
+/// to the [README](../index.html) which explains the use of [markdownToHtml].
+///
+/// The main entrypoint to the library is the [Document] which
+/// encapsulates the parsing process converting a Markdown text into
+/// a tree of [Node] (`List<Node>`).
+///
+/// The two main parsing mechanics used are:
+///
+/// - Blocks, representing top-level elements
+/// implemented via [BlockSyntax] subclasses,
+/// such as headers, paragraphs, blockquotes, and code blocks.
+/// - Inlines, representing chunks of text within a block with special meaning,
+/// implemented via [InlineSyntax] subclasses,
+/// such as links, emphasis, and inlined code.
+///
+/// Looking closely at [Document.new] a few other concepts merit a mention:
+///
+/// - [ExtensionSet] that provide configurations for common Markdown flavors
+/// - [Resolver] which aid in resolving links and images
+///
+/// If you are looking at extending the library to support custom formatting
+/// what you might want is to:
+///
+/// - Implement your own [InlineSyntax] subclasses
+/// - Implement your own [BlockSyntax] subclasses
+/// - Instruct the library to use those by:
+/// - Creating a new [ExtensionSet] from one of the existing flavors
+/// and adding your syntaxes.
+/// - Passing your syntaxes to [Document] or [markdownToHtml] as parameters.
+library;
+
+import 'src/version.dart';
+
+export 'src/ast.dart';
+export 'src/block_parser.dart';
+export 'src/block_syntaxes/alert_block_syntax.dart';
+export 'src/block_syntaxes/block_syntax.dart';
+export 'src/block_syntaxes/blockquote_syntax.dart';
+export 'src/block_syntaxes/code_block_syntax.dart';
+export 'src/block_syntaxes/dummy_block_syntax.dart';
+export 'src/block_syntaxes/empty_block_syntax.dart';
+export 'src/block_syntaxes/fenced_blockquote_syntax.dart';
+export 'src/block_syntaxes/fenced_code_block_syntax.dart';
+export 'src/block_syntaxes/footnote_def_syntax.dart';
+export 'src/block_syntaxes/header_syntax.dart';
+export 'src/block_syntaxes/header_with_id_syntax.dart';
+export 'src/block_syntaxes/horizontal_rule_syntax.dart';
+export 'src/block_syntaxes/html_block_syntax.dart';
+export 'src/block_syntaxes/link_reference_definition_syntax.dart';
+export 'src/block_syntaxes/list_syntax.dart';
+export 'src/block_syntaxes/ordered_list_syntax.dart';
+export 'src/block_syntaxes/ordered_list_with_checkbox_syntax.dart';
+export 'src/block_syntaxes/paragraph_syntax.dart';
+export 'src/block_syntaxes/setext_header_syntax.dart';
+export 'src/block_syntaxes/setext_header_with_id_syntax.dart';
+export 'src/block_syntaxes/table_syntax.dart';
+export 'src/block_syntaxes/unordered_list_syntax.dart';
+export 'src/block_syntaxes/unordered_list_with_checkbox_syntax.dart';
+export 'src/document.dart';
+export 'src/emojis.dart';
+export 'src/extension_set.dart';
+export 'src/html_renderer.dart';
+export 'src/inline_parser.dart';
+export 'src/inline_syntaxes/autolink_extension_syntax.dart';
+export 'src/inline_syntaxes/autolink_syntax.dart';
+export 'src/inline_syntaxes/code_syntax.dart';
+export 'src/inline_syntaxes/color_swatch_syntax.dart';
+export 'src/inline_syntaxes/decode_html_syntax.dart';
+export 'src/inline_syntaxes/delimiter_syntax.dart';
+export 'src/inline_syntaxes/email_autolink_syntax.dart';
+export 'src/inline_syntaxes/emoji_syntax.dart';
+export 'src/inline_syntaxes/emphasis_syntax.dart';
+export 'src/inline_syntaxes/escape_html_syntax.dart';
+export 'src/inline_syntaxes/escape_syntax.dart';
+export 'src/inline_syntaxes/image_syntax.dart';
+export 'src/inline_syntaxes/inline_html_syntax.dart';
+export 'src/inline_syntaxes/inline_syntax.dart';
+export 'src/inline_syntaxes/line_break_syntax.dart';
+export 'src/inline_syntaxes/link_syntax.dart';
+export 'src/inline_syntaxes/soft_line_break_syntax.dart';
+export 'src/inline_syntaxes/strikethrough_syntax.dart';
+export 'src/inline_syntaxes/text_syntax.dart';
+export 'src/line.dart';
+
+const version = packageVersion;
diff --git a/pkgs/markdown/lib/src/assets/case_folding.dart b/pkgs/markdown/lib/src/assets/case_folding.dart
new file mode 100644
index 0000000..09081aa
--- /dev/null
+++ b/pkgs/markdown/lib/src/assets/case_folding.dart
@@ -0,0 +1,1316 @@
+// Generated file. do not edit.
+//
+// Source: tool/case_folding.txt
+// Script: tool/update_case_folding.dart
+// ignore_for_file: prefer_single_quotes
+
+const caseFoldingMap = {
+ "A": "a",
+ "B": "b",
+ "C": "c",
+ "D": "d",
+ "E": "e",
+ "F": "f",
+ "G": "g",
+ "H": "h",
+ "I": "i",
+ "J": "j",
+ "K": "k",
+ "L": "l",
+ "M": "m",
+ "N": "n",
+ "O": "o",
+ "P": "p",
+ "Q": "q",
+ "R": "r",
+ "S": "s",
+ "T": "t",
+ "U": "u",
+ "V": "v",
+ "W": "w",
+ "X": "x",
+ "Y": "y",
+ "Z": "z",
+ "À": "à",
+ "Á": "á",
+ "Â": "â",
+ "Ã": "ã",
+ "Ä": "ä",
+ "Å": "å",
+ "Æ": "æ",
+ "Ç": "ç",
+ "È": "è",
+ "É": "é",
+ "Ê": "ê",
+ "Ë": "ë",
+ "Ì": "ì",
+ "Í": "í",
+ "Î": "î",
+ "Ï": "ï",
+ "Ð": "ð",
+ "Ñ": "ñ",
+ "Ò": "ò",
+ "Ó": "ó",
+ "Ô": "ô",
+ "Õ": "õ",
+ "Ö": "ö",
+ "Ø": "ø",
+ "Ù": "ù",
+ "Ú": "ú",
+ "Û": "û",
+ "Ü": "ü",
+ "Ý": "ý",
+ "Þ": "þ",
+ "Ā": "ā",
+ "Ă": "ă",
+ "Ą": "ą",
+ "Ć": "ć",
+ "Ĉ": "ĉ",
+ "Ċ": "ċ",
+ "Č": "č",
+ "Ď": "ď",
+ "Đ": "đ",
+ "Ē": "ē",
+ "Ĕ": "ĕ",
+ "Ė": "ė",
+ "Ę": "ę",
+ "Ě": "ě",
+ "Ĝ": "ĝ",
+ "Ğ": "ğ",
+ "Ġ": "ġ",
+ "Ģ": "ģ",
+ "Ĥ": "ĥ",
+ "Ħ": "ħ",
+ "Ĩ": "ĩ",
+ "Ī": "ī",
+ "Ĭ": "ĭ",
+ "Į": "į",
+ "İ": "i̇",
+ "Ĵ": "ĵ",
+ "Ķ": "ķ",
+ "Ĺ": "ĺ",
+ "Ļ": "ļ",
+ "Ľ": "ľ",
+ "Ŀ": "ŀ",
+ "Ł": "ł",
+ "Ń": "ń",
+ "Ņ": "ņ",
+ "Ň": "ň",
+ "Ŋ": "ŋ",
+ "Ō": "ō",
+ "Ŏ": "ŏ",
+ "Ő": "ő",
+ "Ŕ": "ŕ",
+ "Ŗ": "ŗ",
+ "Ř": "ř",
+ "Ś": "ś",
+ "Ŝ": "ŝ",
+ "Ş": "ş",
+ "Š": "š",
+ "Ţ": "ţ",
+ "Ť": "ť",
+ "Ŧ": "ŧ",
+ "Ũ": "ũ",
+ "Ū": "ū",
+ "Ŭ": "ŭ",
+ "Ů": "ů",
+ "Ű": "ű",
+ "Ų": "ų",
+ "Ŵ": "ŵ",
+ "Ŷ": "ŷ",
+ "Ÿ": "ÿ",
+ "Ź": "ź",
+ "Ż": "ż",
+ "Ž": "ž",
+ "Ɓ": "ɓ",
+ "Ƃ": "ƃ",
+ "Ƅ": "ƅ",
+ "Ɔ": "ɔ",
+ "Ƈ": "ƈ",
+ "Ɖ": "ɖ",
+ "Ɗ": "ɗ",
+ "Ƌ": "ƌ",
+ "Ǝ": "ǝ",
+ "Ə": "ə",
+ "Ɛ": "ɛ",
+ "Ƒ": "ƒ",
+ "Ɠ": "ɠ",
+ "Ɣ": "ɣ",
+ "Ɩ": "ɩ",
+ "Ɨ": "ɨ",
+ "Ƙ": "ƙ",
+ "Ɯ": "ɯ",
+ "Ɲ": "ɲ",
+ "Ɵ": "ɵ",
+ "Ơ": "ơ",
+ "Ƣ": "ƣ",
+ "Ƥ": "ƥ",
+ "Ƨ": "ƨ",
+ "Ʃ": "ʃ",
+ "Ƭ": "ƭ",
+ "Ʈ": "ʈ",
+ "Ư": "ư",
+ "Ʊ": "ʊ",
+ "Ʋ": "ʋ",
+ "Ƴ": "ƴ",
+ "Ƶ": "ƶ",
+ "Ʒ": "ʒ",
+ "Ƹ": "ƹ",
+ "Ƽ": "ƽ",
+ "DŽ": "dž",
+ "Dž": "dž",
+ "LJ": "lj",
+ "Lj": "lj",
+ "NJ": "nj",
+ "Nj": "nj",
+ "Ǎ": "ǎ",
+ "Ǐ": "ǐ",
+ "Ǒ": "ǒ",
+ "Ǔ": "ǔ",
+ "Ǖ": "ǖ",
+ "Ǘ": "ǘ",
+ "Ǚ": "ǚ",
+ "Ǜ": "ǜ",
+ "Ǟ": "ǟ",
+ "Ǡ": "ǡ",
+ "Ǣ": "ǣ",
+ "Ǥ": "ǥ",
+ "Ǧ": "ǧ",
+ "Ǩ": "ǩ",
+ "Ǫ": "ǫ",
+ "Ǭ": "ǭ",
+ "Ǯ": "ǯ",
+ "DZ": "dz",
+ "Dz": "dz",
+ "Ǵ": "ǵ",
+ "Ƕ": "ƕ",
+ "Ƿ": "ƿ",
+ "Ǹ": "ǹ",
+ "Ǻ": "ǻ",
+ "Ǽ": "ǽ",
+ "Ǿ": "ǿ",
+ "Ȁ": "ȁ",
+ "Ȃ": "ȃ",
+ "Ȅ": "ȅ",
+ "Ȇ": "ȇ",
+ "Ȉ": "ȉ",
+ "Ȋ": "ȋ",
+ "Ȍ": "ȍ",
+ "Ȏ": "ȏ",
+ "Ȑ": "ȑ",
+ "Ȓ": "ȓ",
+ "Ȕ": "ȕ",
+ "Ȗ": "ȗ",
+ "Ș": "ș",
+ "Ț": "ț",
+ "Ȝ": "ȝ",
+ "Ȟ": "ȟ",
+ "Ƞ": "ƞ",
+ "Ȣ": "ȣ",
+ "Ȥ": "ȥ",
+ "Ȧ": "ȧ",
+ "Ȩ": "ȩ",
+ "Ȫ": "ȫ",
+ "Ȭ": "ȭ",
+ "Ȯ": "ȯ",
+ "Ȱ": "ȱ",
+ "Ȳ": "ȳ",
+ "Ⱥ": "ⱥ",
+ "Ȼ": "ȼ",
+ "Ƚ": "ƚ",
+ "Ⱦ": "ⱦ",
+ "Ɂ": "ɂ",
+ "Ƀ": "ƀ",
+ "Ʉ": "ʉ",
+ "Ʌ": "ʌ",
+ "Ɇ": "ɇ",
+ "Ɉ": "ɉ",
+ "Ɋ": "ɋ",
+ "Ɍ": "ɍ",
+ "Ɏ": "ɏ",
+ "Ͱ": "ͱ",
+ "Ͳ": "ͳ",
+ "Ͷ": "ͷ",
+ "Ϳ": "ϳ",
+ "Ά": "ά",
+ "Έ": "έ",
+ "Ή": "ή",
+ "Ί": "ί",
+ "Ό": "ό",
+ "Ύ": "ύ",
+ "Ώ": "ώ",
+ "Α": "α",
+ "Β": "β",
+ "Γ": "γ",
+ "Δ": "δ",
+ "Ε": "ε",
+ "Ζ": "ζ",
+ "Η": "η",
+ "Θ": "θ",
+ "Ι": "ι",
+ "Κ": "κ",
+ "Λ": "λ",
+ "Μ": "μ",
+ "Ν": "ν",
+ "Ξ": "ξ",
+ "Ο": "ο",
+ "Π": "π",
+ "Ρ": "ρ",
+ "Σ": "σ",
+ "Τ": "τ",
+ "Υ": "υ",
+ "Φ": "φ",
+ "Χ": "χ",
+ "Ψ": "ψ",
+ "Ω": "ω",
+ "Ϊ": "ϊ",
+ "Ϋ": "ϋ",
+ "Ϣ": "ϣ",
+ "Ϥ": "ϥ",
+ "Ϧ": "ϧ",
+ "Ϩ": "ϩ",
+ "Ϫ": "ϫ",
+ "Ϭ": "ϭ",
+ "Ϯ": "ϯ",
+ "Ϸ": "ϸ",
+ "Ϻ": "ϻ",
+ "Ѐ": "ѐ",
+ "Ё": "ё",
+ "Ђ": "ђ",
+ "Ѓ": "ѓ",
+ "Є": "є",
+ "Ѕ": "ѕ",
+ "І": "і",
+ "Ї": "ї",
+ "Ј": "ј",
+ "Љ": "љ",
+ "Њ": "њ",
+ "Ћ": "ћ",
+ "Ќ": "ќ",
+ "Ѝ": "ѝ",
+ "Ў": "ў",
+ "Џ": "џ",
+ "А": "а",
+ "Б": "б",
+ "В": "в",
+ "Г": "г",
+ "Д": "д",
+ "Е": "е",
+ "Ж": "ж",
+ "З": "з",
+ "И": "и",
+ "Й": "й",
+ "К": "к",
+ "Л": "л",
+ "М": "м",
+ "Н": "н",
+ "О": "о",
+ "П": "п",
+ "Р": "р",
+ "С": "с",
+ "Т": "т",
+ "У": "у",
+ "Ф": "ф",
+ "Х": "х",
+ "Ц": "ц",
+ "Ч": "ч",
+ "Ш": "ш",
+ "Щ": "щ",
+ "Ъ": "ъ",
+ "Ы": "ы",
+ "Ь": "ь",
+ "Э": "э",
+ "Ю": "ю",
+ "Я": "я",
+ "Ѡ": "ѡ",
+ "Ѣ": "ѣ",
+ "Ѥ": "ѥ",
+ "Ѧ": "ѧ",
+ "Ѩ": "ѩ",
+ "Ѫ": "ѫ",
+ "Ѭ": "ѭ",
+ "Ѯ": "ѯ",
+ "Ѱ": "ѱ",
+ "Ѳ": "ѳ",
+ "Ѵ": "ѵ",
+ "Ѷ": "ѷ",
+ "Ѹ": "ѹ",
+ "Ѻ": "ѻ",
+ "Ѽ": "ѽ",
+ "Ѿ": "ѿ",
+ "Ҁ": "ҁ",
+ "Ҋ": "ҋ",
+ "Ҍ": "ҍ",
+ "Ҏ": "ҏ",
+ "Ґ": "ґ",
+ "Ғ": "ғ",
+ "Ҕ": "ҕ",
+ "Җ": "җ",
+ "Ҙ": "ҙ",
+ "Қ": "қ",
+ "Ҝ": "ҝ",
+ "Ҟ": "ҟ",
+ "Ҡ": "ҡ",
+ "Ң": "ң",
+ "Ҧ": "ҧ",
+ "Ҩ": "ҩ",
+ "Ҫ": "ҫ",
+ "Ҭ": "ҭ",
+ "Ү": "ү",
+ "Ұ": "ұ",
+ "Ҳ": "ҳ",
+ "Ҷ": "ҷ",
+ "Ҹ": "ҹ",
+ "Һ": "һ",
+ "Ҽ": "ҽ",
+ "Ҿ": "ҿ",
+ "Ӂ": "ӂ",
+ "Ӄ": "ӄ",
+ "Ӆ": "ӆ",
+ "Ӈ": "ӈ",
+ "Ӊ": "ӊ",
+ "Ӌ": "ӌ",
+ "Ӎ": "ӎ",
+ "Ӑ": "ӑ",
+ "Ӓ": "ӓ",
+ "Ӗ": "ӗ",
+ "Ә": "ә",
+ "Ӛ": "ӛ",
+ "Ӝ": "ӝ",
+ "Ӟ": "ӟ",
+ "Ӡ": "ӡ",
+ "Ӣ": "ӣ",
+ "Ӥ": "ӥ",
+ "Ӧ": "ӧ",
+ "Ө": "ө",
+ "Ӫ": "ӫ",
+ "Ӭ": "ӭ",
+ "Ӯ": "ӯ",
+ "Ӱ": "ӱ",
+ "Ӳ": "ӳ",
+ "Ӵ": "ӵ",
+ "Ӷ": "ӷ",
+ "Ӹ": "ӹ",
+ "Ӻ": "ӻ",
+ "Ӽ": "ӽ",
+ "Ӿ": "ӿ",
+ "Ԁ": "ԁ",
+ "Ԃ": "ԃ",
+ "Ԅ": "ԅ",
+ "Ԇ": "ԇ",
+ "Ԉ": "ԉ",
+ "Ԋ": "ԋ",
+ "Ԍ": "ԍ",
+ "Ԏ": "ԏ",
+ "Ԑ": "ԑ",
+ "Ԓ": "ԓ",
+ "Ԕ": "ԕ",
+ "Ԗ": "ԗ",
+ "Ԙ": "ԙ",
+ "Ԛ": "ԛ",
+ "Ԝ": "ԝ",
+ "Ԟ": "ԟ",
+ "Ԡ": "ԡ",
+ "Ԣ": "ԣ",
+ "Ԥ": "ԥ",
+ "Ԧ": "ԧ",
+ "Ԩ": "ԩ",
+ "Ԫ": "ԫ",
+ "Ԭ": "ԭ",
+ "Ԯ": "ԯ",
+ "Ա": "ա",
+ "Բ": "բ",
+ "Գ": "գ",
+ "Դ": "դ",
+ "Ե": "ե",
+ "Զ": "զ",
+ "Է": "է",
+ "Ը": "ը",
+ "Թ": "թ",
+ "Ժ": "ժ",
+ "Ի": "ի",
+ "Լ": "լ",
+ "Խ": "խ",
+ "Ծ": "ծ",
+ "Կ": "կ",
+ "Հ": "հ",
+ "Ձ": "ձ",
+ "Ղ": "ղ",
+ "Ճ": "ճ",
+ "Մ": "մ",
+ "Յ": "յ",
+ "Ն": "ն",
+ "Շ": "շ",
+ "Ո": "ո",
+ "Չ": "չ",
+ "Պ": "պ",
+ "Ջ": "ջ",
+ "Ռ": "ռ",
+ "Ս": "ս",
+ "Վ": "վ",
+ "Տ": "տ",
+ "Ր": "ր",
+ "Ց": "ց",
+ "Ւ": "ւ",
+ "Փ": "փ",
+ "Ք": "ք",
+ "Օ": "օ",
+ "Ֆ": "ֆ",
+ "Ⴀ": "ⴀ",
+ "Ⴁ": "ⴁ",
+ "Ⴂ": "ⴂ",
+ "Ⴃ": "ⴃ",
+ "Ⴄ": "ⴄ",
+ "Ⴅ": "ⴅ",
+ "Ⴆ": "ⴆ",
+ "Ⴇ": "ⴇ",
+ "Ⴈ": "ⴈ",
+ "Ⴉ": "ⴉ",
+ "Ⴊ": "ⴊ",
+ "Ⴋ": "ⴋ",
+ "Ⴌ": "ⴌ",
+ "Ⴍ": "ⴍ",
+ "Ⴎ": "ⴎ",
+ "Ⴏ": "ⴏ",
+ "Ⴐ": "ⴐ",
+ "Ⴑ": "ⴑ",
+ "Ⴒ": "ⴒ",
+ "Ⴓ": "ⴓ",
+ "Ⴔ": "ⴔ",
+ "Ⴕ": "ⴕ",
+ "Ⴖ": "ⴖ",
+ "Ⴗ": "ⴗ",
+ "Ⴘ": "ⴘ",
+ "Ⴙ": "ⴙ",
+ "Ⴚ": "ⴚ",
+ "Ⴛ": "ⴛ",
+ "Ⴜ": "ⴜ",
+ "Ⴝ": "ⴝ",
+ "Ⴞ": "ⴞ",
+ "Ⴟ": "ⴟ",
+ "Ⴠ": "ⴠ",
+ "Ⴡ": "ⴡ",
+ "Ⴢ": "ⴢ",
+ "Ⴣ": "ⴣ",
+ "Ⴤ": "ⴤ",
+ "Ⴥ": "ⴥ",
+ "Ⴧ": "ⴧ",
+ "Ⴭ": "ⴭ",
+ "Ა": "ა",
+ "Ბ": "ბ",
+ "Გ": "გ",
+ "Დ": "დ",
+ "Ე": "ე",
+ "Ვ": "ვ",
+ "Ზ": "ზ",
+ "Თ": "თ",
+ "Ი": "ი",
+ "Კ": "კ",
+ "Ლ": "ლ",
+ "Მ": "მ",
+ "Ნ": "ნ",
+ "Ო": "ო",
+ "Პ": "პ",
+ "Ჟ": "ჟ",
+ "Რ": "რ",
+ "Ს": "ს",
+ "Ტ": "ტ",
+ "Უ": "უ",
+ "Ფ": "ფ",
+ "Ქ": "ქ",
+ "Ღ": "ღ",
+ "Ყ": "ყ",
+ "Შ": "შ",
+ "Ჩ": "ჩ",
+ "Ც": "ც",
+ "Ძ": "ძ",
+ "Წ": "წ",
+ "Ჭ": "ჭ",
+ "Ხ": "ხ",
+ "Ჯ": "ჯ",
+ "Ჰ": "ჰ",
+ "Ჱ": "ჱ",
+ "Ჲ": "ჲ",
+ "Ჳ": "ჳ",
+ "Ჴ": "ჴ",
+ "Ჵ": "ჵ",
+ "Ჶ": "ჶ",
+ "Ჷ": "ჷ",
+ "Ჸ": "ჸ",
+ "Ჹ": "ჹ",
+ "Ჺ": "ჺ",
+ "Ჽ": "ჽ",
+ "Ჾ": "ჾ",
+ "Ჿ": "ჿ",
+ "Ḁ": "ḁ",
+ "Ḃ": "ḃ",
+ "Ḅ": "ḅ",
+ "Ḇ": "ḇ",
+ "Ḉ": "ḉ",
+ "Ḋ": "ḋ",
+ "Ḍ": "ḍ",
+ "Ḏ": "ḏ",
+ "Ḑ": "ḑ",
+ "Ḓ": "ḓ",
+ "Ḕ": "ḕ",
+ "Ḗ": "ḗ",
+ "Ḙ": "ḙ",
+ "Ḛ": "ḛ",
+ "Ḝ": "ḝ",
+ "Ḟ": "ḟ",
+ "Ḡ": "ḡ",
+ "Ḣ": "ḣ",
+ "Ḥ": "ḥ",
+ "Ḧ": "ḧ",
+ "Ḩ": "ḩ",
+ "Ḫ": "ḫ",
+ "Ḭ": "ḭ",
+ "Ḯ": "ḯ",
+ "Ḱ": "ḱ",
+ "Ḳ": "ḳ",
+ "Ḵ": "ḵ",
+ "Ḷ": "ḷ",
+ "Ḹ": "ḹ",
+ "Ḻ": "ḻ",
+ "Ḽ": "ḽ",
+ "Ḿ": "ḿ",
+ "Ṁ": "ṁ",
+ "Ṃ": "ṃ",
+ "Ṅ": "ṅ",
+ "Ṇ": "ṇ",
+ "Ṉ": "ṉ",
+ "Ṋ": "ṋ",
+ "Ṍ": "ṍ",
+ "Ṏ": "ṏ",
+ "Ṑ": "ṑ",
+ "Ṓ": "ṓ",
+ "Ṕ": "ṕ",
+ "Ṗ": "ṗ",
+ "Ṙ": "ṙ",
+ "Ṛ": "ṛ",
+ "Ṝ": "ṝ",
+ "Ṟ": "ṟ",
+ "Ṡ": "ṡ",
+ "Ṣ": "ṣ",
+ "Ṥ": "ṥ",
+ "Ṧ": "ṧ",
+ "Ṩ": "ṩ",
+ "Ṫ": "ṫ",
+ "Ṭ": "ṭ",
+ "Ṯ": "ṯ",
+ "Ṱ": "ṱ",
+ "Ṳ": "ṳ",
+ "Ṵ": "ṵ",
+ "Ṷ": "ṷ",
+ "Ṹ": "ṹ",
+ "Ṻ": "ṻ",
+ "Ṽ": "ṽ",
+ "Ṿ": "ṿ",
+ "Ẁ": "ẁ",
+ "Ẃ": "ẃ",
+ "Ẅ": "ẅ",
+ "Ẇ": "ẇ",
+ "Ẉ": "ẉ",
+ "Ẋ": "ẋ",
+ "Ẍ": "ẍ",
+ "Ẏ": "ẏ",
+ "Ẑ": "ẑ",
+ "Ẓ": "ẓ",
+ "Ẕ": "ẕ",
+ "ẞ": "ss",
+ "Ạ": "ạ",
+ "Ả": "ả",
+ "Ấ": "ấ",
+ "Ầ": "ầ",
+ "Ẩ": "ẩ",
+ "Ẫ": "ẫ",
+ "Ậ": "ậ",
+ "Ắ": "ắ",
+ "Ằ": "ằ",
+ "Ẳ": "ẳ",
+ "Ẵ": "ẵ",
+ "Ặ": "ặ",
+ "Ẹ": "ẹ",
+ "Ẻ": "ẻ",
+ "Ẽ": "ẽ",
+ "Ế": "ế",
+ "Ề": "ề",
+ "Ể": "ể",
+ "Ễ": "ễ",
+ "Ệ": "ệ",
+ "Ỉ": "ỉ",
+ "Ị": "ị",
+ "Ọ": "ọ",
+ "Ỏ": "ỏ",
+ "Ố": "ố",
+ "Ồ": "ồ",
+ "Ổ": "ổ",
+ "Ỗ": "ỗ",
+ "Ộ": "ộ",
+ "Ớ": "ớ",
+ "Ờ": "ờ",
+ "Ở": "ở",
+ "Ỡ": "ỡ",
+ "Ợ": "ợ",
+ "Ụ": "ụ",
+ "Ủ": "ủ",
+ "Ứ": "ứ",
+ "Ừ": "ừ",
+ "Ử": "ử",
+ "Ữ": "ữ",
+ "Ự": "ự",
+ "Ỳ": "ỳ",
+ "Ỵ": "ỵ",
+ "Ỷ": "ỷ",
+ "Ỹ": "ỹ",
+ "Ỻ": "ỻ",
+ "Ỽ": "ỽ",
+ "Ỿ": "ỿ",
+ "Ἀ": "ἀ",
+ "Ἁ": "ἁ",
+ "Ἂ": "ἂ",
+ "Ἃ": "ἃ",
+ "Ἄ": "ἄ",
+ "Ἅ": "ἅ",
+ "Ἆ": "ἆ",
+ "Ἇ": "ἇ",
+ "Ἐ": "ἐ",
+ "Ἑ": "ἑ",
+ "Ἒ": "ἒ",
+ "Ἓ": "ἓ",
+ "Ἔ": "ἔ",
+ "Ἕ": "ἕ",
+ "Ἠ": "ἠ",
+ "Ἡ": "ἡ",
+ "Ἢ": "ἢ",
+ "Ἣ": "ἣ",
+ "Ἤ": "ἤ",
+ "Ἥ": "ἥ",
+ "Ἦ": "ἦ",
+ "Ἧ": "ἧ",
+ "Ἰ": "ἰ",
+ "Ἱ": "ἱ",
+ "Ἲ": "ἲ",
+ "Ἳ": "ἳ",
+ "Ἴ": "ἴ",
+ "Ἵ": "ἵ",
+ "Ἶ": "ἶ",
+ "Ἷ": "ἷ",
+ "Ὀ": "ὀ",
+ "Ὁ": "ὁ",
+ "Ὂ": "ὂ",
+ "Ὃ": "ὃ",
+ "Ὄ": "ὄ",
+ "Ὅ": "ὅ",
+ "Ὑ": "ὑ",
+ "Ὓ": "ὓ",
+ "Ὕ": "ὕ",
+ "Ὗ": "ὗ",
+ "Ὠ": "ὠ",
+ "Ὡ": "ὡ",
+ "Ὢ": "ὢ",
+ "Ὣ": "ὣ",
+ "Ὤ": "ὤ",
+ "Ὥ": "ὥ",
+ "Ὦ": "ὦ",
+ "Ὧ": "ὧ",
+ "ᾈ": "ἀι",
+ "ᾉ": "ἁι",
+ "ᾊ": "ἂι",
+ "ᾋ": "ἃι",
+ "ᾌ": "ἄι",
+ "ᾍ": "ἅι",
+ "ᾎ": "ἆι",
+ "ᾏ": "ἇι",
+ "ᾘ": "ἠι",
+ "ᾙ": "ἡι",
+ "ᾚ": "ἢι",
+ "ᾛ": "ἣι",
+ "ᾜ": "ἤι",
+ "ᾝ": "ἥι",
+ "ᾞ": "ἦι",
+ "ᾟ": "ἧι",
+ "ᾨ": "ὠι",
+ "ᾩ": "ὡι",
+ "ᾪ": "ὢι",
+ "ᾫ": "ὣι",
+ "ᾬ": "ὤι",
+ "ᾭ": "ὥι",
+ "ᾮ": "ὦι",
+ "ᾯ": "ὧι",
+ "Ᾰ": "ᾰ",
+ "Ᾱ": "ᾱ",
+ "Ὰ": "ὰ",
+ "Ά": "ά",
+ "ᾼ": "αι",
+ "Ὲ": "ὲ",
+ "Έ": "έ",
+ "Ὴ": "ὴ",
+ "Ή": "ή",
+ "ῌ": "ηι",
+ "Ῐ": "ῐ",
+ "Ῑ": "ῑ",
+ "Ὶ": "ὶ",
+ "Ί": "ί",
+ "Ῠ": "ῠ",
+ "Ῡ": "ῡ",
+ "Ὺ": "ὺ",
+ "Ύ": "ύ",
+ "Ῥ": "ῥ",
+ "Ὸ": "ὸ",
+ "Ό": "ό",
+ "Ὼ": "ὼ",
+ "Ώ": "ώ",
+ "ῼ": "ωι",
+ "Ⓐ": "ⓐ",
+ "Ⓑ": "ⓑ",
+ "Ⓒ": "ⓒ",
+ "Ⓓ": "ⓓ",
+ "Ⓔ": "ⓔ",
+ "Ⓕ": "ⓕ",
+ "Ⓖ": "ⓖ",
+ "Ⓗ": "ⓗ",
+ "Ⓘ": "ⓘ",
+ "Ⓙ": "ⓙ",
+ "Ⓚ": "ⓚ",
+ "Ⓛ": "ⓛ",
+ "Ⓜ": "ⓜ",
+ "Ⓝ": "ⓝ",
+ "Ⓞ": "ⓞ",
+ "Ⓟ": "ⓟ",
+ "Ⓠ": "ⓠ",
+ "Ⓡ": "ⓡ",
+ "Ⓢ": "ⓢ",
+ "Ⓣ": "ⓣ",
+ "Ⓤ": "ⓤ",
+ "Ⓥ": "ⓥ",
+ "Ⓦ": "ⓦ",
+ "Ⓧ": "ⓧ",
+ "Ⓨ": "ⓨ",
+ "Ⓩ": "ⓩ",
+ "Ⰰ": "ⰰ",
+ "Ⰱ": "ⰱ",
+ "Ⰲ": "ⰲ",
+ "Ⰳ": "ⰳ",
+ "Ⰴ": "ⰴ",
+ "Ⰵ": "ⰵ",
+ "Ⰶ": "ⰶ",
+ "Ⰷ": "ⰷ",
+ "Ⰸ": "ⰸ",
+ "Ⰹ": "ⰹ",
+ "Ⰺ": "ⰺ",
+ "Ⰻ": "ⰻ",
+ "Ⰼ": "ⰼ",
+ "Ⰽ": "ⰽ",
+ "Ⰾ": "ⰾ",
+ "Ⰿ": "ⰿ",
+ "Ⱀ": "ⱀ",
+ "Ⱁ": "ⱁ",
+ "Ⱂ": "ⱂ",
+ "Ⱃ": "ⱃ",
+ "Ⱄ": "ⱄ",
+ "Ⱅ": "ⱅ",
+ "Ⱆ": "ⱆ",
+ "Ⱇ": "ⱇ",
+ "Ⱈ": "ⱈ",
+ "Ⱉ": "ⱉ",
+ "Ⱊ": "ⱊ",
+ "Ⱋ": "ⱋ",
+ "Ⱌ": "ⱌ",
+ "Ⱍ": "ⱍ",
+ "Ⱎ": "ⱎ",
+ "Ⱏ": "ⱏ",
+ "Ⱐ": "ⱐ",
+ "Ⱑ": "ⱑ",
+ "Ⱒ": "ⱒ",
+ "Ⱓ": "ⱓ",
+ "Ⱔ": "ⱔ",
+ "Ⱕ": "ⱕ",
+ "Ⱖ": "ⱖ",
+ "Ⱗ": "ⱗ",
+ "Ⱘ": "ⱘ",
+ "Ⱙ": "ⱙ",
+ "Ⱚ": "ⱚ",
+ "Ⱛ": "ⱛ",
+ "Ⱜ": "ⱜ",
+ "Ⱝ": "ⱝ",
+ "Ⱞ": "ⱞ",
+ "Ⱟ": "ⱟ",
+ "Ⱡ": "ⱡ",
+ "Ɫ": "ɫ",
+ "Ᵽ": "ᵽ",
+ "Ɽ": "ɽ",
+ "Ⱨ": "ⱨ",
+ "Ⱪ": "ⱪ",
+ "Ⱬ": "ⱬ",
+ "Ɑ": "ɑ",
+ "Ɱ": "ɱ",
+ "Ɐ": "ɐ",
+ "Ɒ": "ɒ",
+ "Ⱳ": "ⱳ",
+ "Ⱶ": "ⱶ",
+ "Ȿ": "ȿ",
+ "Ɀ": "ɀ",
+ "Ⲁ": "ⲁ",
+ "Ⲃ": "ⲃ",
+ "Ⲅ": "ⲅ",
+ "Ⲇ": "ⲇ",
+ "Ⲉ": "ⲉ",
+ "Ⲋ": "ⲋ",
+ "Ⲍ": "ⲍ",
+ "Ⲏ": "ⲏ",
+ "Ⲑ": "ⲑ",
+ "Ⲓ": "ⲓ",
+ "Ⲕ": "ⲕ",
+ "Ⲗ": "ⲗ",
+ "Ⲙ": "ⲙ",
+ "Ⲛ": "ⲛ",
+ "Ⲝ": "ⲝ",
+ "Ⲟ": "ⲟ",
+ "Ⲡ": "ⲡ",
+ "Ⲣ": "ⲣ",
+ "Ⲥ": "ⲥ",
+ "Ⲧ": "ⲧ",
+ "Ⲩ": "ⲩ",
+ "Ⲫ": "ⲫ",
+ "Ⲭ": "ⲭ",
+ "Ⲯ": "ⲯ",
+ "Ⲱ": "ⲱ",
+ "Ⲳ": "ⲳ",
+ "Ⲵ": "ⲵ",
+ "Ⲷ": "ⲷ",
+ "Ⲹ": "ⲹ",
+ "Ⲻ": "ⲻ",
+ "Ⲽ": "ⲽ",
+ "Ⲿ": "ⲿ",
+ "Ⳁ": "ⳁ",
+ "Ⳃ": "ⳃ",
+ "Ⳅ": "ⳅ",
+ "Ⳇ": "ⳇ",
+ "Ⳉ": "ⳉ",
+ "Ⳋ": "ⳋ",
+ "Ⳍ": "ⳍ",
+ "Ⳏ": "ⳏ",
+ "Ⳑ": "ⳑ",
+ "Ⳓ": "ⳓ",
+ "Ⳕ": "ⳕ",
+ "Ⳗ": "ⳗ",
+ "Ⳙ": "ⳙ",
+ "Ⳛ": "ⳛ",
+ "Ⳝ": "ⳝ",
+ "Ⳟ": "ⳟ",
+ "Ⳡ": "ⳡ",
+ "Ⳣ": "ⳣ",
+ "Ⳬ": "ⳬ",
+ "Ⳮ": "ⳮ",
+ "Ⳳ": "ⳳ",
+ "Ꙁ": "ꙁ",
+ "Ꙃ": "ꙃ",
+ "Ꙅ": "ꙅ",
+ "Ꙇ": "ꙇ",
+ "Ꙉ": "ꙉ",
+ "Ꙋ": "ꙋ",
+ "Ꙍ": "ꙍ",
+ "Ꙏ": "ꙏ",
+ "Ꙑ": "ꙑ",
+ "Ꙓ": "ꙓ",
+ "Ꙕ": "ꙕ",
+ "Ꙗ": "ꙗ",
+ "Ꙙ": "ꙙ",
+ "Ꙛ": "ꙛ",
+ "Ꙝ": "ꙝ",
+ "Ꙟ": "ꙟ",
+ "Ꙡ": "ꙡ",
+ "Ꙣ": "ꙣ",
+ "Ꙥ": "ꙥ",
+ "Ꙧ": "ꙧ",
+ "Ꙩ": "ꙩ",
+ "Ꙫ": "ꙫ",
+ "Ꙭ": "ꙭ",
+ "Ꚁ": "ꚁ",
+ "Ꚃ": "ꚃ",
+ "Ꚅ": "ꚅ",
+ "Ꚇ": "ꚇ",
+ "Ꚉ": "ꚉ",
+ "Ꚋ": "ꚋ",
+ "Ꚍ": "ꚍ",
+ "Ꚏ": "ꚏ",
+ "Ꚑ": "ꚑ",
+ "Ꚓ": "ꚓ",
+ "Ꚕ": "ꚕ",
+ "Ꚗ": "ꚗ",
+ "Ꚙ": "ꚙ",
+ "Ꚛ": "ꚛ",
+ "Ꜣ": "ꜣ",
+ "Ꜥ": "ꜥ",
+ "Ꜧ": "ꜧ",
+ "Ꜩ": "ꜩ",
+ "Ꜫ": "ꜫ",
+ "Ꜭ": "ꜭ",
+ "Ꜯ": "ꜯ",
+ "Ꜳ": "ꜳ",
+ "Ꜵ": "ꜵ",
+ "Ꜷ": "ꜷ",
+ "Ꜹ": "ꜹ",
+ "Ꜻ": "ꜻ",
+ "Ꜽ": "ꜽ",
+ "Ꜿ": "ꜿ",
+ "Ꝁ": "ꝁ",
+ "Ꝃ": "ꝃ",
+ "Ꝅ": "ꝅ",
+ "Ꝇ": "ꝇ",
+ "Ꝉ": "ꝉ",
+ "Ꝋ": "ꝋ",
+ "Ꝍ": "ꝍ",
+ "Ꝏ": "ꝏ",
+ "Ꝑ": "ꝑ",
+ "Ꝓ": "ꝓ",
+ "Ꝕ": "ꝕ",
+ "Ꝗ": "ꝗ",
+ "Ꝙ": "ꝙ",
+ "Ꝛ": "ꝛ",
+ "Ꝝ": "ꝝ",
+ "Ꝟ": "ꝟ",
+ "Ꝡ": "ꝡ",
+ "Ꝣ": "ꝣ",
+ "Ꝥ": "ꝥ",
+ "Ꝧ": "ꝧ",
+ "Ꝩ": "ꝩ",
+ "Ꝫ": "ꝫ",
+ "Ꝭ": "ꝭ",
+ "Ꝯ": "ꝯ",
+ "Ꝺ": "ꝺ",
+ "Ꝼ": "ꝼ",
+ "Ᵹ": "ᵹ",
+ "Ꝿ": "ꝿ",
+ "Ꞁ": "ꞁ",
+ "Ꞃ": "ꞃ",
+ "Ꞅ": "ꞅ",
+ "Ꞇ": "ꞇ",
+ "Ꞌ": "ꞌ",
+ "Ɥ": "ɥ",
+ "Ꞑ": "ꞑ",
+ "Ꞓ": "ꞓ",
+ "Ꞗ": "ꞗ",
+ "Ꞙ": "ꞙ",
+ "Ꞛ": "ꞛ",
+ "Ꞝ": "ꞝ",
+ "Ꞟ": "ꞟ",
+ "Ꞡ": "ꞡ",
+ "Ꞣ": "ꞣ",
+ "Ꞥ": "ꞥ",
+ "Ꞧ": "ꞧ",
+ "Ꞩ": "ꞩ",
+ "Ɦ": "ɦ",
+ "Ɜ": "ɜ",
+ "Ɡ": "ɡ",
+ "Ɬ": "ɬ",
+ "Ɪ": "ɪ",
+ "Ʞ": "ʞ",
+ "Ʇ": "ʇ",
+ "Ʝ": "ʝ",
+ "Ꭓ": "ꭓ",
+ "Ꞵ": "ꞵ",
+ "Ꞷ": "ꞷ",
+ "Ꞹ": "ꞹ",
+ "Ꞻ": "ꞻ",
+ "Ꞽ": "ꞽ",
+ "Ꞿ": "ꞿ",
+ "Ꟁ": "ꟁ",
+ "Ꟃ": "ꟃ",
+ "Ꞔ": "ꞔ",
+ "Ʂ": "ʂ",
+ "Ᶎ": "ᶎ",
+ "Ꟈ": "ꟈ",
+ "Ꟊ": "ꟊ",
+ "Ꟑ": "ꟑ",
+ "Ꟗ": "ꟗ",
+ "Ꟙ": "ꟙ",
+ "Ꟶ": "ꟶ",
+ "A": "a",
+ "B": "b",
+ "C": "c",
+ "D": "d",
+ "E": "e",
+ "F": "f",
+ "G": "g",
+ "H": "h",
+ "I": "i",
+ "J": "j",
+ "K": "k",
+ "L": "l",
+ "M": "m",
+ "N": "n",
+ "O": "o",
+ "P": "p",
+ "Q": "q",
+ "R": "r",
+ "S": "s",
+ "T": "t",
+ "U": "u",
+ "V": "v",
+ "W": "w",
+ "X": "x",
+ "Y": "y",
+ "Z": "z",
+ "𐐀": "𐐨",
+ "𐐁": "𐐩",
+ "𐐂": "𐐪",
+ "𐐃": "𐐫",
+ "𐐄": "𐐬",
+ "𐐅": "𐐭",
+ "𐐆": "𐐮",
+ "𐐇": "𐐯",
+ "𐐈": "𐐰",
+ "𐐉": "𐐱",
+ "𐐊": "𐐲",
+ "𐐋": "𐐳",
+ "𐐌": "𐐴",
+ "𐐍": "𐐵",
+ "𐐎": "𐐶",
+ "𐐏": "𐐷",
+ "𐐐": "𐐸",
+ "𐐑": "𐐹",
+ "𐐒": "𐐺",
+ "𐐓": "𐐻",
+ "𐐔": "𐐼",
+ "𐐕": "𐐽",
+ "𐐖": "𐐾",
+ "𐐗": "𐐿",
+ "𐐘": "𐑀",
+ "𐐙": "𐑁",
+ "𐐚": "𐑂",
+ "𐐛": "𐑃",
+ "𐐜": "𐑄",
+ "𐐝": "𐑅",
+ "𐐞": "𐑆",
+ "𐐟": "𐑇",
+ "𐐠": "𐑈",
+ "𐐡": "𐑉",
+ "𐐢": "𐑊",
+ "𐐣": "𐑋",
+ "𐐤": "𐑌",
+ "𐐥": "𐑍",
+ "𐐦": "𐑎",
+ "𐐧": "𐑏",
+ "𐒰": "𐓘",
+ "𐒱": "𐓙",
+ "𐒲": "𐓚",
+ "𐒳": "𐓛",
+ "𐒴": "𐓜",
+ "𐒵": "𐓝",
+ "𐒶": "𐓞",
+ "𐒷": "𐓟",
+ "𐒸": "𐓠",
+ "𐒹": "𐓡",
+ "𐒺": "𐓢",
+ "𐒻": "𐓣",
+ "𐒼": "𐓤",
+ "𐒽": "𐓥",
+ "𐒾": "𐓦",
+ "𐒿": "𐓧",
+ "𐓀": "𐓨",
+ "𐓁": "𐓩",
+ "𐓂": "𐓪",
+ "𐓃": "𐓫",
+ "𐓄": "𐓬",
+ "𐓅": "𐓭",
+ "𐓆": "𐓮",
+ "𐓇": "𐓯",
+ "𐓈": "𐓰",
+ "𐓉": "𐓱",
+ "𐓊": "𐓲",
+ "𐓋": "𐓳",
+ "𐓌": "𐓴",
+ "𐓍": "𐓵",
+ "𐓎": "𐓶",
+ "𐓏": "𐓷",
+ "𐓐": "𐓸",
+ "𐓑": "𐓹",
+ "𐓒": "𐓺",
+ "𐓓": "𐓻",
+ "𐕰": "𐖗",
+ "𐕱": "𐖘",
+ "𐕲": "𐖙",
+ "𐕳": "𐖚",
+ "𐕴": "𐖛",
+ "𐕵": "𐖜",
+ "𐕶": "𐖝",
+ "𐕷": "𐖞",
+ "𐕸": "𐖟",
+ "𐕹": "𐖠",
+ "𐕺": "𐖡",
+ "𐕼": "𐖣",
+ "𐕽": "𐖤",
+ "𐕾": "𐖥",
+ "𐕿": "𐖦",
+ "𐖀": "𐖧",
+ "𐖁": "𐖨",
+ "𐖂": "𐖩",
+ "𐖃": "𐖪",
+ "𐖄": "𐖫",
+ "𐖅": "𐖬",
+ "𐖆": "𐖭",
+ "𐖇": "𐖮",
+ "𐖈": "𐖯",
+ "𐖉": "𐖰",
+ "𐖊": "𐖱",
+ "𐖌": "𐖳",
+ "𐖍": "𐖴",
+ "𐖎": "𐖵",
+ "𐖏": "𐖶",
+ "𐖐": "𐖷",
+ "𐖑": "𐖸",
+ "𐖒": "𐖹",
+ "𐖔": "𐖻",
+ "𐖕": "𐖼",
+ "𐲀": "𐳀",
+ "𐲁": "𐳁",
+ "𐲂": "𐳂",
+ "𐲃": "𐳃",
+ "𐲄": "𐳄",
+ "𐲅": "𐳅",
+ "𐲆": "𐳆",
+ "𐲇": "𐳇",
+ "𐲈": "𐳈",
+ "𐲉": "𐳉",
+ "𐲊": "𐳊",
+ "𐲋": "𐳋",
+ "𐲌": "𐳌",
+ "𐲍": "𐳍",
+ "𐲎": "𐳎",
+ "𐲏": "𐳏",
+ "𐲐": "𐳐",
+ "𐲑": "𐳑",
+ "𐲒": "𐳒",
+ "𐲓": "𐳓",
+ "𐲔": "𐳔",
+ "𐲕": "𐳕",
+ "𐲖": "𐳖",
+ "𐲗": "𐳗",
+ "𐲘": "𐳘",
+ "𐲙": "𐳙",
+ "𐲚": "𐳚",
+ "𐲛": "𐳛",
+ "𐲜": "𐳜",
+ "𐲝": "𐳝",
+ "𐲞": "𐳞",
+ "𐲟": "𐳟",
+ "𐲠": "𐳠",
+ "𐲡": "𐳡",
+ "𐲢": "𐳢",
+ "𐲣": "𐳣",
+ "𐲤": "𐳤",
+ "𐲥": "𐳥",
+ "𐲦": "𐳦",
+ "𐲧": "𐳧",
+ "𐲨": "𐳨",
+ "𐲩": "𐳩",
+ "𐲪": "𐳪",
+ "𐲫": "𐳫",
+ "𐲬": "𐳬",
+ "𐲭": "𐳭",
+ "𐲮": "𐳮",
+ "𐲯": "𐳯",
+ "𐲰": "𐳰",
+ "𐲱": "𐳱",
+ "𐲲": "𐳲",
+ "𑢠": "𑣀",
+ "𑢡": "𑣁",
+ "𑢢": "𑣂",
+ "𑢣": "𑣃",
+ "𑢤": "𑣄",
+ "𑢥": "𑣅",
+ "𑢦": "𑣆",
+ "𑢧": "𑣇",
+ "𑢨": "𑣈",
+ "𑢩": "𑣉",
+ "𑢪": "𑣊",
+ "𑢫": "𑣋",
+ "𑢬": "𑣌",
+ "𑢭": "𑣍",
+ "𑢮": "𑣎",
+ "𑢯": "𑣏",
+ "𑢰": "𑣐",
+ "𑢱": "𑣑",
+ "𑢲": "𑣒",
+ "𑢳": "𑣓",
+ "𑢴": "𑣔",
+ "𑢵": "𑣕",
+ "𑢶": "𑣖",
+ "𑢷": "𑣗",
+ "𑢸": "𑣘",
+ "𑢹": "𑣙",
+ "𑢺": "𑣚",
+ "𑢻": "𑣛",
+ "𑢼": "𑣜",
+ "𑢽": "𑣝",
+ "𑢾": "𑣞",
+ "𑢿": "𑣟",
+ "𖹀": "𖹠",
+ "𖹁": "𖹡",
+ "𖹂": "𖹢",
+ "𖹃": "𖹣",
+ "𖹄": "𖹤",
+ "𖹅": "𖹥",
+ "𖹆": "𖹦",
+ "𖹇": "𖹧",
+ "𖹈": "𖹨",
+ "𖹉": "𖹩",
+ "𖹊": "𖹪",
+ "𖹋": "𖹫",
+ "𖹌": "𖹬",
+ "𖹍": "𖹭",
+ "𖹎": "𖹮",
+ "𖹏": "𖹯",
+ "𖹐": "𖹰",
+ "𖹑": "𖹱",
+ "𖹒": "𖹲",
+ "𖹓": "𖹳",
+ "𖹔": "𖹴",
+ "𖹕": "𖹵",
+ "𖹖": "𖹶",
+ "𖹗": "𖹷",
+ "𖹘": "𖹸",
+ "𖹙": "𖹹",
+ "𖹚": "𖹺",
+ "𖹛": "𖹻",
+ "𖹜": "𖹼",
+ "𖹝": "𖹽",
+ "𖹞": "𖹾",
+ "𖹟": "𖹿",
+ "𞤀": "𞤢",
+ "𞤁": "𞤣",
+ "𞤂": "𞤤",
+ "𞤃": "𞤥",
+ "𞤄": "𞤦",
+ "𞤅": "𞤧",
+ "𞤆": "𞤨",
+ "𞤇": "𞤩",
+ "𞤈": "𞤪",
+ "𞤉": "𞤫",
+ "𞤊": "𞤬",
+ "𞤋": "𞤭",
+ "𞤌": "𞤮",
+ "𞤍": "𞤯",
+ "𞤎": "𞤰",
+ "𞤏": "𞤱",
+ "𞤐": "𞤲",
+ "𞤑": "𞤳",
+ "𞤒": "𞤴",
+ "𞤓": "𞤵",
+ "𞤔": "𞤶",
+ "𞤕": "𞤷",
+ "𞤖": "𞤸",
+ "𞤗": "𞤹",
+ "𞤘": "𞤺",
+ "𞤙": "𞤻",
+ "𞤚": "𞤼",
+ "𞤛": "𞤽",
+ "𞤜": "𞤾",
+ "𞤝": "𞤿",
+ "𞤞": "𞥀",
+ "𞤟": "𞥁",
+ "𞤠": "𞥂",
+ "𞤡": "𞥃"
+};
diff --git a/pkgs/markdown/lib/src/assets/html_entities.dart b/pkgs/markdown/lib/src/assets/html_entities.dart
new file mode 100644
index 0000000..2599762
--- /dev/null
+++ b/pkgs/markdown/lib/src/assets/html_entities.dart
@@ -0,0 +1,2133 @@
+// Generated file. do not edit.
+//
+// Source: tool/entities.json
+// Script: tool/update_entities.dart
+// ignore_for_file: prefer_single_quotes
+
+const htmlEntitiesMap = {
+ "Æ": "Æ",
+ "&": "&",
+ "Á": "Á",
+ "Ă": "Ă",
+ "Â": "Â",
+ "А": "А",
+ "𝔄": "𝔄",
+ "À": "À",
+ "Α": "Α",
+ "Ā": "Ā",
+ "⩓": "⩓",
+ "Ą": "Ą",
+ "𝔸": "𝔸",
+ "⁡": "",
+ "Å": "Å",
+ "𝒜": "𝒜",
+ "≔": "≔",
+ "Ã": "Ã",
+ "Ä": "Ä",
+ "∖": "∖",
+ "⫧": "⫧",
+ "⌆": "⌆",
+ "Б": "Б",
+ "∵": "∵",
+ "ℬ": "ℬ",
+ "Β": "Β",
+ "𝔅": "𝔅",
+ "𝔹": "𝔹",
+ "˘": "˘",
+ "ℬ": "ℬ",
+ "≎": "≎",
+ "Ч": "Ч",
+ "©": "©",
+ "Ć": "Ć",
+ "⋒": "⋒",
+ "ⅅ": "ⅅ",
+ "ℭ": "ℭ",
+ "Č": "Č",
+ "Ç": "Ç",
+ "Ĉ": "Ĉ",
+ "∰": "∰",
+ "Ċ": "Ċ",
+ "¸": "¸",
+ "·": "·",
+ "ℭ": "ℭ",
+ "Χ": "Χ",
+ "⊙": "⊙",
+ "⊖": "⊖",
+ "⊕": "⊕",
+ "⊗": "⊗",
+ "∲": "∲",
+ "”": "”",
+ "’": "’",
+ "∷": "∷",
+ "⩴": "⩴",
+ "≡": "≡",
+ "∯": "∯",
+ "∮": "∮",
+ "ℂ": "ℂ",
+ "∐": "∐",
+ "∳": "∳",
+ "⨯": "⨯",
+ "𝒞": "𝒞",
+ "⋓": "⋓",
+ "≍": "≍",
+ "ⅅ": "ⅅ",
+ "⤑": "⤑",
+ "Ђ": "Ђ",
+ "Ѕ": "Ѕ",
+ "Џ": "Џ",
+ "‡": "‡",
+ "↡": "↡",
+ "⫤": "⫤",
+ "Ď": "Ď",
+ "Д": "Д",
+ "∇": "∇",
+ "Δ": "Δ",
+ "𝔇": "𝔇",
+ "´": "´",
+ "˙": "˙",
+ "˝": "˝",
+ "`": "`",
+ "˜": "˜",
+ "⋄": "⋄",
+ "ⅆ": "ⅆ",
+ "𝔻": "𝔻",
+ "¨": "¨",
+ "⃜": "⃜",
+ "≐": "≐",
+ "∯": "∯",
+ "¨": "¨",
+ "⇓": "⇓",
+ "⇐": "⇐",
+ "⇔": "⇔",
+ "⫤": "⫤",
+ "⟸": "⟸",
+ "⟺": "⟺",
+ "⟹": "⟹",
+ "⇒": "⇒",
+ "⊨": "⊨",
+ "⇑": "⇑",
+ "⇕": "⇕",
+ "∥": "∥",
+ "↓": "↓",
+ "⤓": "⤓",
+ "⇵": "⇵",
+ "̑": "̑",
+ "⥐": "⥐",
+ "⥞": "⥞",
+ "↽": "↽",
+ "⥖": "⥖",
+ "⥟": "⥟",
+ "⇁": "⇁",
+ "⥗": "⥗",
+ "⊤": "⊤",
+ "↧": "↧",
+ "⇓": "⇓",
+ "𝒟": "𝒟",
+ "Đ": "Đ",
+ "Ŋ": "Ŋ",
+ "Ð": "Ð",
+ "É": "É",
+ "Ě": "Ě",
+ "Ê": "Ê",
+ "Э": "Э",
+ "Ė": "Ė",
+ "𝔈": "𝔈",
+ "È": "È",
+ "∈": "∈",
+ "Ē": "Ē",
+ "◻": "◻",
+ "▫": "▫",
+ "Ę": "Ę",
+ "𝔼": "𝔼",
+ "Ε": "Ε",
+ "⩵": "⩵",
+ "≂": "≂",
+ "⇌": "⇌",
+ "ℰ": "ℰ",
+ "⩳": "⩳",
+ "Η": "Η",
+ "Ë": "Ë",
+ "∃": "∃",
+ "ⅇ": "ⅇ",
+ "Ф": "Ф",
+ "𝔉": "𝔉",
+ "◼": "◼",
+ "▪": "▪",
+ "𝔽": "𝔽",
+ "∀": "∀",
+ "ℱ": "ℱ",
+ "ℱ": "ℱ",
+ "Ѓ": "Ѓ",
+ ">": ">",
+ "Γ": "Γ",
+ "Ϝ": "Ϝ",
+ "Ğ": "Ğ",
+ "Ģ": "Ģ",
+ "Ĝ": "Ĝ",
+ "Г": "Г",
+ "Ġ": "Ġ",
+ "𝔊": "𝔊",
+ "⋙": "⋙",
+ "𝔾": "𝔾",
+ "≥": "≥",
+ "⋛": "⋛",
+ "≧": "≧",
+ "⪢": "⪢",
+ "≷": "≷",
+ "⩾": "⩾",
+ "≳": "≳",
+ "𝒢": "𝒢",
+ "≫": "≫",
+ "Ъ": "Ъ",
+ "ˇ": "ˇ",
+ "^": "^",
+ "Ĥ": "Ĥ",
+ "ℌ": "ℌ",
+ "ℋ": "ℋ",
+ "ℍ": "ℍ",
+ "─": "─",
+ "ℋ": "ℋ",
+ "Ħ": "Ħ",
+ "≎": "≎",
+ "≏": "≏",
+ "Е": "Е",
+ "IJ": "IJ",
+ "Ё": "Ё",
+ "Í": "Í",
+ "Î": "Î",
+ "И": "И",
+ "İ": "İ",
+ "ℑ": "ℑ",
+ "Ì": "Ì",
+ "ℑ": "ℑ",
+ "Ī": "Ī",
+ "ⅈ": "ⅈ",
+ "⇒": "⇒",
+ "∬": "∬",
+ "∫": "∫",
+ "⋂": "⋂",
+ "⁣": "",
+ "⁢": "",
+ "Į": "Į",
+ "𝕀": "𝕀",
+ "Ι": "Ι",
+ "ℐ": "ℐ",
+ "Ĩ": "Ĩ",
+ "І": "І",
+ "Ï": "Ï",
+ "Ĵ": "Ĵ",
+ "Й": "Й",
+ "𝔍": "𝔍",
+ "𝕁": "𝕁",
+ "𝒥": "𝒥",
+ "Ј": "Ј",
+ "Є": "Є",
+ "Х": "Х",
+ "Ќ": "Ќ",
+ "Κ": "Κ",
+ "Ķ": "Ķ",
+ "К": "К",
+ "𝔎": "𝔎",
+ "𝕂": "𝕂",
+ "𝒦": "𝒦",
+ "Љ": "Љ",
+ "<": "<",
+ "Ĺ": "Ĺ",
+ "Λ": "Λ",
+ "⟪": "⟪",
+ "ℒ": "ℒ",
+ "↞": "↞",
+ "Ľ": "Ľ",
+ "Ļ": "Ļ",
+ "Л": "Л",
+ "⟨": "⟨",
+ "←": "←",
+ "⇤": "⇤",
+ "⇆": "⇆",
+ "⌈": "⌈",
+ "⟦": "⟦",
+ "⥡": "⥡",
+ "⇃": "⇃",
+ "⥙": "⥙",
+ "⌊": "⌊",
+ "↔": "↔",
+ "⥎": "⥎",
+ "⊣": "⊣",
+ "↤": "↤",
+ "⥚": "⥚",
+ "⊲": "⊲",
+ "⧏": "⧏",
+ "⊴": "⊴",
+ "⥑": "⥑",
+ "⥠": "⥠",
+ "↿": "↿",
+ "⥘": "⥘",
+ "↼": "↼",
+ "⥒": "⥒",
+ "⇐": "⇐",
+ "⇔": "⇔",
+ "⋚": "⋚",
+ "≦": "≦",
+ "≶": "≶",
+ "⪡": "⪡",
+ "⩽": "⩽",
+ "≲": "≲",
+ "𝔏": "𝔏",
+ "⋘": "⋘",
+ "⇚": "⇚",
+ "Ŀ": "Ŀ",
+ "⟵": "⟵",
+ "⟷": "⟷",
+ "⟶": "⟶",
+ "⟸": "⟸",
+ "⟺": "⟺",
+ "⟹": "⟹",
+ "𝕃": "𝕃",
+ "↙": "↙",
+ "↘": "↘",
+ "ℒ": "ℒ",
+ "↰": "↰",
+ "Ł": "Ł",
+ "≪": "≪",
+ "⤅": "⤅",
+ "М": "М",
+ " ": " ",
+ "ℳ": "ℳ",
+ "𝔐": "𝔐",
+ "∓": "∓",
+ "𝕄": "𝕄",
+ "ℳ": "ℳ",
+ "Μ": "Μ",
+ "Њ": "Њ",
+ "Ń": "Ń",
+ "Ň": "Ň",
+ "Ņ": "Ņ",
+ "Н": "Н",
+ "​": "",
+ "​": "",
+ "​": "",
+ "​": "",
+ "≫": "≫",
+ "≪": "≪",
+ "
": "\n",
+ "𝔑": "𝔑",
+ "⁠": "",
+ " ": " ",
+ "ℕ": "ℕ",
+ "⫬": "⫬",
+ "≢": "≢",
+ "≭": "≭",
+ "∦": "∦",
+ "∉": "∉",
+ "≠": "≠",
+ "≂̸": "≂̸",
+ "∄": "∄",
+ "≯": "≯",
+ "≱": "≱",
+ "≧̸": "≧̸",
+ "≫̸": "≫̸",
+ "≹": "≹",
+ "⩾̸": "⩾̸",
+ "≵": "≵",
+ "≎̸": "≎̸",
+ "≏̸": "≏̸",
+ "⋪": "⋪",
+ "⧏̸": "⧏̸",
+ "⋬": "⋬",
+ "≮": "≮",
+ "≰": "≰",
+ "≸": "≸",
+ "≪̸": "≪̸",
+ "⩽̸": "⩽̸",
+ "≴": "≴",
+ "⪢̸": "⪢̸",
+ "⪡̸": "⪡̸",
+ "⊀": "⊀",
+ "⪯̸": "⪯̸",
+ "⋠": "⋠",
+ "∌": "∌",
+ "⋫": "⋫",
+ "⧐̸": "⧐̸",
+ "⋭": "⋭",
+ "⊏̸": "⊏̸",
+ "⋢": "⋢",
+ "⊐̸": "⊐̸",
+ "⋣": "⋣",
+ "⊂⃒": "⊂⃒",
+ "⊈": "⊈",
+ "⊁": "⊁",
+ "⪰̸": "⪰̸",
+ "⋡": "⋡",
+ "≿̸": "≿̸",
+ "⊃⃒": "⊃⃒",
+ "⊉": "⊉",
+ "≁": "≁",
+ "≄": "≄",
+ "≇": "≇",
+ "≉": "≉",
+ "∤": "∤",
+ "𝒩": "𝒩",
+ "Ñ": "Ñ",
+ "Ν": "Ν",
+ "Œ": "Œ",
+ "Ó": "Ó",
+ "Ô": "Ô",
+ "О": "О",
+ "Ő": "Ő",
+ "𝔒": "𝔒",
+ "Ò": "Ò",
+ "Ō": "Ō",
+ "Ω": "Ω",
+ "Ο": "Ο",
+ "𝕆": "𝕆",
+ "“": "“",
+ "‘": "‘",
+ "⩔": "⩔",
+ "𝒪": "𝒪",
+ "Ø": "Ø",
+ "Õ": "Õ",
+ "⨷": "⨷",
+ "Ö": "Ö",
+ "‾": "‾",
+ "⏞": "⏞",
+ "⎴": "⎴",
+ "⏜": "⏜",
+ "∂": "∂",
+ "П": "П",
+ "𝔓": "𝔓",
+ "Φ": "Φ",
+ "Π": "Π",
+ "±": "±",
+ "ℌ": "ℌ",
+ "ℙ": "ℙ",
+ "⪻": "⪻",
+ "≺": "≺",
+ "⪯": "⪯",
+ "≼": "≼",
+ "≾": "≾",
+ "″": "″",
+ "∏": "∏",
+ "∷": "∷",
+ "∝": "∝",
+ "𝒫": "𝒫",
+ "Ψ": "Ψ",
+ """: "\"",
+ "𝔔": "𝔔",
+ "ℚ": "ℚ",
+ "𝒬": "𝒬",
+ "⤐": "⤐",
+ "®": "®",
+ "Ŕ": "Ŕ",
+ "⟫": "⟫",
+ "↠": "↠",
+ "⤖": "⤖",
+ "Ř": "Ř",
+ "Ŗ": "Ŗ",
+ "Р": "Р",
+ "ℜ": "ℜ",
+ "∋": "∋",
+ "⇋": "⇋",
+ "⥯": "⥯",
+ "ℜ": "ℜ",
+ "Ρ": "Ρ",
+ "⟩": "⟩",
+ "→": "→",
+ "⇥": "⇥",
+ "⇄": "⇄",
+ "⌉": "⌉",
+ "⟧": "⟧",
+ "⥝": "⥝",
+ "⇂": "⇂",
+ "⥕": "⥕",
+ "⌋": "⌋",
+ "⊢": "⊢",
+ "↦": "↦",
+ "⥛": "⥛",
+ "⊳": "⊳",
+ "⧐": "⧐",
+ "⊵": "⊵",
+ "⥏": "⥏",
+ "⥜": "⥜",
+ "↾": "↾",
+ "⥔": "⥔",
+ "⇀": "⇀",
+ "⥓": "⥓",
+ "⇒": "⇒",
+ "ℝ": "ℝ",
+ "⥰": "⥰",
+ "⇛": "⇛",
+ "ℛ": "ℛ",
+ "↱": "↱",
+ "⧴": "⧴",
+ "Щ": "Щ",
+ "Ш": "Ш",
+ "Ь": "Ь",
+ "Ś": "Ś",
+ "⪼": "⪼",
+ "Š": "Š",
+ "Ş": "Ş",
+ "Ŝ": "Ŝ",
+ "С": "С",
+ "𝔖": "𝔖",
+ "↓": "↓",
+ "←": "←",
+ "→": "→",
+ "↑": "↑",
+ "Σ": "Σ",
+ "∘": "∘",
+ "𝕊": "𝕊",
+ "√": "√",
+ "□": "□",
+ "⊓": "⊓",
+ "⊏": "⊏",
+ "⊑": "⊑",
+ "⊐": "⊐",
+ "⊒": "⊒",
+ "⊔": "⊔",
+ "𝒮": "𝒮",
+ "⋆": "⋆",
+ "⋐": "⋐",
+ "⋐": "⋐",
+ "⊆": "⊆",
+ "≻": "≻",
+ "⪰": "⪰",
+ "≽": "≽",
+ "≿": "≿",
+ "∋": "∋",
+ "∑": "∑",
+ "⋑": "⋑",
+ "⊃": "⊃",
+ "⊇": "⊇",
+ "⋑": "⋑",
+ "Þ": "Þ",
+ "™": "™",
+ "Ћ": "Ћ",
+ "Ц": "Ц",
+ "	": "\t",
+ "Τ": "Τ",
+ "Ť": "Ť",
+ "Ţ": "Ţ",
+ "Т": "Т",
+ "𝔗": "𝔗",
+ "∴": "∴",
+ "Θ": "Θ",
+ "  ": " ",
+ " ": " ",
+ "∼": "∼",
+ "≃": "≃",
+ "≅": "≅",
+ "≈": "≈",
+ "𝕋": "𝕋",
+ "⃛": "⃛",
+ "𝒯": "𝒯",
+ "Ŧ": "Ŧ",
+ "Ú": "Ú",
+ "↟": "↟",
+ "⥉": "⥉",
+ "Ў": "Ў",
+ "Ŭ": "Ŭ",
+ "Û": "Û",
+ "У": "У",
+ "Ű": "Ű",
+ "𝔘": "𝔘",
+ "Ù": "Ù",
+ "Ū": "Ū",
+ "_": "_",
+ "⏟": "⏟",
+ "⎵": "⎵",
+ "⏝": "⏝",
+ "⋃": "⋃",
+ "⊎": "⊎",
+ "Ų": "Ų",
+ "𝕌": "𝕌",
+ "↑": "↑",
+ "⤒": "⤒",
+ "⇅": "⇅",
+ "↕": "↕",
+ "⥮": "⥮",
+ "⊥": "⊥",
+ "↥": "↥",
+ "⇑": "⇑",
+ "⇕": "⇕",
+ "↖": "↖",
+ "↗": "↗",
+ "ϒ": "ϒ",
+ "Υ": "Υ",
+ "Ů": "Ů",
+ "𝒰": "𝒰",
+ "Ũ": "Ũ",
+ "Ü": "Ü",
+ "⊫": "⊫",
+ "⫫": "⫫",
+ "В": "В",
+ "⊩": "⊩",
+ "⫦": "⫦",
+ "⋁": "⋁",
+ "‖": "‖",
+ "‖": "‖",
+ "∣": "∣",
+ "|": "|",
+ "❘": "❘",
+ "≀": "≀",
+ " ": " ",
+ "𝔙": "𝔙",
+ "𝕍": "𝕍",
+ "𝒱": "𝒱",
+ "⊪": "⊪",
+ "Ŵ": "Ŵ",
+ "⋀": "⋀",
+ "𝔚": "𝔚",
+ "𝕎": "𝕎",
+ "𝒲": "𝒲",
+ "𝔛": "𝔛",
+ "Ξ": "Ξ",
+ "𝕏": "𝕏",
+ "𝒳": "𝒳",
+ "Я": "Я",
+ "Ї": "Ї",
+ "Ю": "Ю",
+ "Ý": "Ý",
+ "Ŷ": "Ŷ",
+ "Ы": "Ы",
+ "𝔜": "𝔜",
+ "𝕐": "𝕐",
+ "𝒴": "𝒴",
+ "Ÿ": "Ÿ",
+ "Ж": "Ж",
+ "Ź": "Ź",
+ "Ž": "Ž",
+ "З": "З",
+ "Ż": "Ż",
+ "​": "",
+ "Ζ": "Ζ",
+ "ℨ": "ℨ",
+ "ℤ": "ℤ",
+ "𝒵": "𝒵",
+ "á": "á",
+ "ă": "ă",
+ "∾": "∾",
+ "∾̳": "∾̳",
+ "∿": "∿",
+ "â": "â",
+ "´": "´",
+ "а": "а",
+ "æ": "æ",
+ "⁡": "",
+ "𝔞": "𝔞",
+ "à": "à",
+ "ℵ": "ℵ",
+ "ℵ": "ℵ",
+ "α": "α",
+ "ā": "ā",
+ "⨿": "⨿",
+ "&": "&",
+ "∧": "∧",
+ "⩕": "⩕",
+ "⩜": "⩜",
+ "⩘": "⩘",
+ "⩚": "⩚",
+ "∠": "∠",
+ "⦤": "⦤",
+ "∠": "∠",
+ "∡": "∡",
+ "⦨": "⦨",
+ "⦩": "⦩",
+ "⦪": "⦪",
+ "⦫": "⦫",
+ "⦬": "⦬",
+ "⦭": "⦭",
+ "⦮": "⦮",
+ "⦯": "⦯",
+ "∟": "∟",
+ "⊾": "⊾",
+ "⦝": "⦝",
+ "∢": "∢",
+ "Å": "Å",
+ "⍼": "⍼",
+ "ą": "ą",
+ "𝕒": "𝕒",
+ "≈": "≈",
+ "⩰": "⩰",
+ "⩯": "⩯",
+ "≊": "≊",
+ "≋": "≋",
+ "'": "'",
+ "≈": "≈",
+ "≊": "≊",
+ "å": "å",
+ "𝒶": "𝒶",
+ "*": "*",
+ "≈": "≈",
+ "≍": "≍",
+ "ã": "ã",
+ "ä": "ä",
+ "∳": "∳",
+ "⨑": "⨑",
+ "⫭": "⫭",
+ "≌": "≌",
+ "϶": "϶",
+ "‵": "‵",
+ "∽": "∽",
+ "⋍": "⋍",
+ "⊽": "⊽",
+ "⌅": "⌅",
+ "⌅": "⌅",
+ "⎵": "⎵",
+ "⎶": "⎶",
+ "≌": "≌",
+ "б": "б",
+ "„": "„",
+ "∵": "∵",
+ "∵": "∵",
+ "⦰": "⦰",
+ "϶": "϶",
+ "ℬ": "ℬ",
+ "β": "β",
+ "ℶ": "ℶ",
+ "≬": "≬",
+ "𝔟": "𝔟",
+ "⋂": "⋂",
+ "◯": "◯",
+ "⋃": "⋃",
+ "⨀": "⨀",
+ "⨁": "⨁",
+ "⨂": "⨂",
+ "⨆": "⨆",
+ "★": "★",
+ "▽": "▽",
+ "△": "△",
+ "⨄": "⨄",
+ "⋁": "⋁",
+ "⋀": "⋀",
+ "⤍": "⤍",
+ "⧫": "⧫",
+ "▪": "▪",
+ "▴": "▴",
+ "▾": "▾",
+ "◂": "◂",
+ "▸": "▸",
+ "␣": "␣",
+ "▒": "▒",
+ "░": "░",
+ "▓": "▓",
+ "█": "█",
+ "=⃥": "=⃥",
+ "≡⃥": "≡⃥",
+ "⌐": "⌐",
+ "𝕓": "𝕓",
+ "⊥": "⊥",
+ "⊥": "⊥",
+ "⋈": "⋈",
+ "╗": "╗",
+ "╔": "╔",
+ "╖": "╖",
+ "╓": "╓",
+ "═": "═",
+ "╦": "╦",
+ "╩": "╩",
+ "╤": "╤",
+ "╧": "╧",
+ "╝": "╝",
+ "╚": "╚",
+ "╜": "╜",
+ "╙": "╙",
+ "║": "║",
+ "╬": "╬",
+ "╣": "╣",
+ "╠": "╠",
+ "╫": "╫",
+ "╢": "╢",
+ "╟": "╟",
+ "⧉": "⧉",
+ "╕": "╕",
+ "╒": "╒",
+ "┐": "┐",
+ "┌": "┌",
+ "─": "─",
+ "╥": "╥",
+ "╨": "╨",
+ "┬": "┬",
+ "┴": "┴",
+ "⊟": "⊟",
+ "⊞": "⊞",
+ "⊠": "⊠",
+ "╛": "╛",
+ "╘": "╘",
+ "┘": "┘",
+ "└": "└",
+ "│": "│",
+ "╪": "╪",
+ "╡": "╡",
+ "╞": "╞",
+ "┼": "┼",
+ "┤": "┤",
+ "├": "├",
+ "‵": "‵",
+ "˘": "˘",
+ "¦": "¦",
+ "𝒷": "𝒷",
+ "⁏": "⁏",
+ "∽": "∽",
+ "⋍": "⋍",
+ "\": r"\",
+ "⧅": "⧅",
+ "⟈": "⟈",
+ "•": "•",
+ "•": "•",
+ "≎": "≎",
+ "⪮": "⪮",
+ "≏": "≏",
+ "≏": "≏",
+ "ć": "ć",
+ "∩": "∩",
+ "⩄": "⩄",
+ "⩉": "⩉",
+ "⩋": "⩋",
+ "⩇": "⩇",
+ "⩀": "⩀",
+ "∩︀": "∩︀",
+ "⁁": "⁁",
+ "ˇ": "ˇ",
+ "⩍": "⩍",
+ "č": "č",
+ "ç": "ç",
+ "ĉ": "ĉ",
+ "⩌": "⩌",
+ "⩐": "⩐",
+ "ċ": "ċ",
+ "¸": "¸",
+ "⦲": "⦲",
+ "¢": "¢",
+ "·": "·",
+ "𝔠": "𝔠",
+ "ч": "ч",
+ "✓": "✓",
+ "✓": "✓",
+ "χ": "χ",
+ "○": "○",
+ "⧃": "⧃",
+ "ˆ": "ˆ",
+ "≗": "≗",
+ "↺": "↺",
+ "↻": "↻",
+ "®": "®",
+ "Ⓢ": "Ⓢ",
+ "⊛": "⊛",
+ "⊚": "⊚",
+ "⊝": "⊝",
+ "≗": "≗",
+ "⨐": "⨐",
+ "⫯": "⫯",
+ "⧂": "⧂",
+ "♣": "♣",
+ "♣": "♣",
+ ":": ":",
+ "≔": "≔",
+ "≔": "≔",
+ ",": ",",
+ "@": "@",
+ "∁": "∁",
+ "∘": "∘",
+ "∁": "∁",
+ "ℂ": "ℂ",
+ "≅": "≅",
+ "⩭": "⩭",
+ "∮": "∮",
+ "𝕔": "𝕔",
+ "∐": "∐",
+ "©": "©",
+ "℗": "℗",
+ "↵": "↵",
+ "✗": "✗",
+ "𝒸": "𝒸",
+ "⫏": "⫏",
+ "⫑": "⫑",
+ "⫐": "⫐",
+ "⫒": "⫒",
+ "⋯": "⋯",
+ "⤸": "⤸",
+ "⤵": "⤵",
+ "⋞": "⋞",
+ "⋟": "⋟",
+ "↶": "↶",
+ "⤽": "⤽",
+ "∪": "∪",
+ "⩈": "⩈",
+ "⩆": "⩆",
+ "⩊": "⩊",
+ "⊍": "⊍",
+ "⩅": "⩅",
+ "∪︀": "∪︀",
+ "↷": "↷",
+ "⤼": "⤼",
+ "⋞": "⋞",
+ "⋟": "⋟",
+ "⋎": "⋎",
+ "⋏": "⋏",
+ "¤": "¤",
+ "↶": "↶",
+ "↷": "↷",
+ "⋎": "⋎",
+ "⋏": "⋏",
+ "∲": "∲",
+ "∱": "∱",
+ "⌭": "⌭",
+ "⇓": "⇓",
+ "⥥": "⥥",
+ "†": "†",
+ "ℸ": "ℸ",
+ "↓": "↓",
+ "‐": "‐",
+ "⊣": "⊣",
+ "⤏": "⤏",
+ "˝": "˝",
+ "ď": "ď",
+ "д": "д",
+ "ⅆ": "ⅆ",
+ "‡": "‡",
+ "⇊": "⇊",
+ "⩷": "⩷",
+ "°": "°",
+ "δ": "δ",
+ "⦱": "⦱",
+ "⥿": "⥿",
+ "𝔡": "𝔡",
+ "⇃": "⇃",
+ "⇂": "⇂",
+ "⋄": "⋄",
+ "⋄": "⋄",
+ "♦": "♦",
+ "♦": "♦",
+ "¨": "¨",
+ "ϝ": "ϝ",
+ "⋲": "⋲",
+ "÷": "÷",
+ "÷": "÷",
+ "⋇": "⋇",
+ "⋇": "⋇",
+ "ђ": "ђ",
+ "⌞": "⌞",
+ "⌍": "⌍",
+ "$": r"$",
+ "𝕕": "𝕕",
+ "˙": "˙",
+ "≐": "≐",
+ "≑": "≑",
+ "∸": "∸",
+ "∔": "∔",
+ "⊡": "⊡",
+ "⌆": "⌆",
+ "↓": "↓",
+ "⇊": "⇊",
+ "⇃": "⇃",
+ "⇂": "⇂",
+ "⤐": "⤐",
+ "⌟": "⌟",
+ "⌌": "⌌",
+ "𝒹": "𝒹",
+ "ѕ": "ѕ",
+ "⧶": "⧶",
+ "đ": "đ",
+ "⋱": "⋱",
+ "▿": "▿",
+ "▾": "▾",
+ "⇵": "⇵",
+ "⥯": "⥯",
+ "⦦": "⦦",
+ "џ": "џ",
+ "⟿": "⟿",
+ "⩷": "⩷",
+ "≑": "≑",
+ "é": "é",
+ "⩮": "⩮",
+ "ě": "ě",
+ "≖": "≖",
+ "ê": "ê",
+ "≕": "≕",
+ "э": "э",
+ "ė": "ė",
+ "ⅇ": "ⅇ",
+ "≒": "≒",
+ "𝔢": "𝔢",
+ "⪚": "⪚",
+ "è": "è",
+ "⪖": "⪖",
+ "⪘": "⪘",
+ "⪙": "⪙",
+ "⏧": "⏧",
+ "ℓ": "ℓ",
+ "⪕": "⪕",
+ "⪗": "⪗",
+ "ē": "ē",
+ "∅": "∅",
+ "∅": "∅",
+ "∅": "∅",
+ " ": " ",
+ " ": " ",
+ " ": " ",
+ "ŋ": "ŋ",
+ " ": " ",
+ "ę": "ę",
+ "𝕖": "𝕖",
+ "⋕": "⋕",
+ "⧣": "⧣",
+ "⩱": "⩱",
+ "ε": "ε",
+ "ε": "ε",
+ "ϵ": "ϵ",
+ "≖": "≖",
+ "≕": "≕",
+ "≂": "≂",
+ "⪖": "⪖",
+ "⪕": "⪕",
+ "=": "=",
+ "≟": "≟",
+ "≡": "≡",
+ "⩸": "⩸",
+ "⧥": "⧥",
+ "≓": "≓",
+ "⥱": "⥱",
+ "ℯ": "ℯ",
+ "≐": "≐",
+ "≂": "≂",
+ "η": "η",
+ "ð": "ð",
+ "ë": "ë",
+ "€": "€",
+ "!": "!",
+ "∃": "∃",
+ "ℰ": "ℰ",
+ "ⅇ": "ⅇ",
+ "≒": "≒",
+ "ф": "ф",
+ "♀": "♀",
+ "ffi": "ffi",
+ "ff": "ff",
+ "ffl": "ffl",
+ "𝔣": "𝔣",
+ "fi": "fi",
+ "fj": "fj",
+ "♭": "♭",
+ "fl": "fl",
+ "▱": "▱",
+ "ƒ": "ƒ",
+ "𝕗": "𝕗",
+ "∀": "∀",
+ "⋔": "⋔",
+ "⫙": "⫙",
+ "⨍": "⨍",
+ "½": "½",
+ "⅓": "⅓",
+ "¼": "¼",
+ "⅕": "⅕",
+ "⅙": "⅙",
+ "⅛": "⅛",
+ "⅔": "⅔",
+ "⅖": "⅖",
+ "¾": "¾",
+ "⅗": "⅗",
+ "⅜": "⅜",
+ "⅘": "⅘",
+ "⅚": "⅚",
+ "⅝": "⅝",
+ "⅞": "⅞",
+ "⁄": "⁄",
+ "⌢": "⌢",
+ "𝒻": "𝒻",
+ "≧": "≧",
+ "⪌": "⪌",
+ "ǵ": "ǵ",
+ "γ": "γ",
+ "ϝ": "ϝ",
+ "⪆": "⪆",
+ "ğ": "ğ",
+ "ĝ": "ĝ",
+ "г": "г",
+ "ġ": "ġ",
+ "≥": "≥",
+ "⋛": "⋛",
+ "≥": "≥",
+ "≧": "≧",
+ "⩾": "⩾",
+ "⩾": "⩾",
+ "⪩": "⪩",
+ "⪀": "⪀",
+ "⪂": "⪂",
+ "⪄": "⪄",
+ "⋛︀": "⋛︀",
+ "⪔": "⪔",
+ "𝔤": "𝔤",
+ "≫": "≫",
+ "⋙": "⋙",
+ "ℷ": "ℷ",
+ "ѓ": "ѓ",
+ "≷": "≷",
+ "⪒": "⪒",
+ "⪥": "⪥",
+ "⪤": "⪤",
+ "≩": "≩",
+ "⪊": "⪊",
+ "⪊": "⪊",
+ "⪈": "⪈",
+ "⪈": "⪈",
+ "≩": "≩",
+ "⋧": "⋧",
+ "𝕘": "𝕘",
+ "`": "`",
+ "ℊ": "ℊ",
+ "≳": "≳",
+ "⪎": "⪎",
+ "⪐": "⪐",
+ ">": ">",
+ "⪧": "⪧",
+ "⩺": "⩺",
+ "⋗": "⋗",
+ "⦕": "⦕",
+ "⩼": "⩼",
+ "⪆": "⪆",
+ "⥸": "⥸",
+ "⋗": "⋗",
+ "⋛": "⋛",
+ "⪌": "⪌",
+ "≷": "≷",
+ "≳": "≳",
+ "≩︀": "≩︀",
+ "≩︀": "≩︀",
+ "⇔": "⇔",
+ " ": " ",
+ "½": "½",
+ "ℋ": "ℋ",
+ "ъ": "ъ",
+ "↔": "↔",
+ "⥈": "⥈",
+ "↭": "↭",
+ "ℏ": "ℏ",
+ "ĥ": "ĥ",
+ "♥": "♥",
+ "♥": "♥",
+ "…": "…",
+ "⊹": "⊹",
+ "𝔥": "𝔥",
+ "⤥": "⤥",
+ "⤦": "⤦",
+ "⇿": "⇿",
+ "∻": "∻",
+ "↩": "↩",
+ "↪": "↪",
+ "𝕙": "𝕙",
+ "―": "―",
+ "𝒽": "𝒽",
+ "ℏ": "ℏ",
+ "ħ": "ħ",
+ "⁃": "⁃",
+ "‐": "‐",
+ "í": "í",
+ "⁣": "",
+ "î": "î",
+ "и": "и",
+ "е": "е",
+ "¡": "¡",
+ "⇔": "⇔",
+ "𝔦": "𝔦",
+ "ì": "ì",
+ "ⅈ": "ⅈ",
+ "⨌": "⨌",
+ "∭": "∭",
+ "⧜": "⧜",
+ "℩": "℩",
+ "ij": "ij",
+ "ī": "ī",
+ "ℑ": "ℑ",
+ "ℐ": "ℐ",
+ "ℑ": "ℑ",
+ "ı": "ı",
+ "⊷": "⊷",
+ "Ƶ": "Ƶ",
+ "∈": "∈",
+ "℅": "℅",
+ "∞": "∞",
+ "⧝": "⧝",
+ "ı": "ı",
+ "∫": "∫",
+ "⊺": "⊺",
+ "ℤ": "ℤ",
+ "⊺": "⊺",
+ "⨗": "⨗",
+ "⨼": "⨼",
+ "ё": "ё",
+ "į": "į",
+ "𝕚": "𝕚",
+ "ι": "ι",
+ "⨼": "⨼",
+ "¿": "¿",
+ "𝒾": "𝒾",
+ "∈": "∈",
+ "⋹": "⋹",
+ "⋵": "⋵",
+ "⋴": "⋴",
+ "⋳": "⋳",
+ "∈": "∈",
+ "⁢": "",
+ "ĩ": "ĩ",
+ "і": "і",
+ "ï": "ï",
+ "ĵ": "ĵ",
+ "й": "й",
+ "𝔧": "𝔧",
+ "ȷ": "ȷ",
+ "𝕛": "𝕛",
+ "𝒿": "𝒿",
+ "ј": "ј",
+ "є": "є",
+ "κ": "κ",
+ "ϰ": "ϰ",
+ "ķ": "ķ",
+ "к": "к",
+ "𝔨": "𝔨",
+ "ĸ": "ĸ",
+ "х": "х",
+ "ќ": "ќ",
+ "𝕜": "𝕜",
+ "𝓀": "𝓀",
+ "⇚": "⇚",
+ "⇐": "⇐",
+ "⤛": "⤛",
+ "⤎": "⤎",
+ "≦": "≦",
+ "⪋": "⪋",
+ "⥢": "⥢",
+ "ĺ": "ĺ",
+ "⦴": "⦴",
+ "ℒ": "ℒ",
+ "λ": "λ",
+ "⟨": "⟨",
+ "⦑": "⦑",
+ "⟨": "⟨",
+ "⪅": "⪅",
+ "«": "«",
+ "←": "←",
+ "⇤": "⇤",
+ "⤟": "⤟",
+ "⤝": "⤝",
+ "↩": "↩",
+ "↫": "↫",
+ "⤹": "⤹",
+ "⥳": "⥳",
+ "↢": "↢",
+ "⪫": "⪫",
+ "⤙": "⤙",
+ "⪭": "⪭",
+ "⪭︀": "⪭︀",
+ "⤌": "⤌",
+ "❲": "❲",
+ "{": "{",
+ "[": "[",
+ "⦋": "⦋",
+ "⦏": "⦏",
+ "⦍": "⦍",
+ "ľ": "ľ",
+ "ļ": "ļ",
+ "⌈": "⌈",
+ "{": "{",
+ "л": "л",
+ "⤶": "⤶",
+ "“": "“",
+ "„": "„",
+ "⥧": "⥧",
+ "⥋": "⥋",
+ "↲": "↲",
+ "≤": "≤",
+ "←": "←",
+ "↢": "↢",
+ "↽": "↽",
+ "↼": "↼",
+ "⇇": "⇇",
+ "↔": "↔",
+ "⇆": "⇆",
+ "⇋": "⇋",
+ "↭": "↭",
+ "⋋": "⋋",
+ "⋚": "⋚",
+ "≤": "≤",
+ "≦": "≦",
+ "⩽": "⩽",
+ "⩽": "⩽",
+ "⪨": "⪨",
+ "⩿": "⩿",
+ "⪁": "⪁",
+ "⪃": "⪃",
+ "⋚︀": "⋚︀",
+ "⪓": "⪓",
+ "⪅": "⪅",
+ "⋖": "⋖",
+ "⋚": "⋚",
+ "⪋": "⪋",
+ "≶": "≶",
+ "≲": "≲",
+ "⥼": "⥼",
+ "⌊": "⌊",
+ "𝔩": "𝔩",
+ "≶": "≶",
+ "⪑": "⪑",
+ "↽": "↽",
+ "↼": "↼",
+ "⥪": "⥪",
+ "▄": "▄",
+ "љ": "љ",
+ "≪": "≪",
+ "⇇": "⇇",
+ "⌞": "⌞",
+ "⥫": "⥫",
+ "◺": "◺",
+ "ŀ": "ŀ",
+ "⎰": "⎰",
+ "⎰": "⎰",
+ "≨": "≨",
+ "⪉": "⪉",
+ "⪉": "⪉",
+ "⪇": "⪇",
+ "⪇": "⪇",
+ "≨": "≨",
+ "⋦": "⋦",
+ "⟬": "⟬",
+ "⇽": "⇽",
+ "⟦": "⟦",
+ "⟵": "⟵",
+ "⟷": "⟷",
+ "⟼": "⟼",
+ "⟶": "⟶",
+ "↫": "↫",
+ "↬": "↬",
+ "⦅": "⦅",
+ "𝕝": "𝕝",
+ "⨭": "⨭",
+ "⨴": "⨴",
+ "∗": "∗",
+ "_": "_",
+ "◊": "◊",
+ "◊": "◊",
+ "⧫": "⧫",
+ "(": "(",
+ "⦓": "⦓",
+ "⇆": "⇆",
+ "⌟": "⌟",
+ "⇋": "⇋",
+ "⥭": "⥭",
+ "‎": "",
+ "⊿": "⊿",
+ "‹": "‹",
+ "𝓁": "𝓁",
+ "↰": "↰",
+ "≲": "≲",
+ "⪍": "⪍",
+ "⪏": "⪏",
+ "[": "[",
+ "‘": "‘",
+ "‚": "‚",
+ "ł": "ł",
+ "<": "<",
+ "⪦": "⪦",
+ "⩹": "⩹",
+ "⋖": "⋖",
+ "⋋": "⋋",
+ "⋉": "⋉",
+ "⥶": "⥶",
+ "⩻": "⩻",
+ "⦖": "⦖",
+ "◃": "◃",
+ "⊴": "⊴",
+ "◂": "◂",
+ "⥊": "⥊",
+ "⥦": "⥦",
+ "≨︀": "≨︀",
+ "≨︀": "≨︀",
+ "∺": "∺",
+ "¯": "¯",
+ "♂": "♂",
+ "✠": "✠",
+ "✠": "✠",
+ "↦": "↦",
+ "↦": "↦",
+ "↧": "↧",
+ "↤": "↤",
+ "↥": "↥",
+ "▮": "▮",
+ "⨩": "⨩",
+ "м": "м",
+ "—": "—",
+ "∡": "∡",
+ "𝔪": "𝔪",
+ "℧": "℧",
+ "µ": "µ",
+ "∣": "∣",
+ "*": "*",
+ "⫰": "⫰",
+ "·": "·",
+ "−": "−",
+ "⊟": "⊟",
+ "∸": "∸",
+ "⨪": "⨪",
+ "⫛": "⫛",
+ "…": "…",
+ "∓": "∓",
+ "⊧": "⊧",
+ "𝕞": "𝕞",
+ "∓": "∓",
+ "𝓂": "𝓂",
+ "∾": "∾",
+ "μ": "μ",
+ "⊸": "⊸",
+ "⊸": "⊸",
+ "⋙̸": "⋙̸",
+ "≫⃒": "≫⃒",
+ "≫̸": "≫̸",
+ "⇍": "⇍",
+ "⇎": "⇎",
+ "⋘̸": "⋘̸",
+ "≪⃒": "≪⃒",
+ "≪̸": "≪̸",
+ "⇏": "⇏",
+ "⊯": "⊯",
+ "⊮": "⊮",
+ "∇": "∇",
+ "ń": "ń",
+ "∠⃒": "∠⃒",
+ "≉": "≉",
+ "⩰̸": "⩰̸",
+ "≋̸": "≋̸",
+ "ʼn": "ʼn",
+ "≉": "≉",
+ "♮": "♮",
+ "♮": "♮",
+ "ℕ": "ℕ",
+ " ": " ",
+ "≎̸": "≎̸",
+ "≏̸": "≏̸",
+ "⩃": "⩃",
+ "ň": "ň",
+ "ņ": "ņ",
+ "≇": "≇",
+ "⩭̸": "⩭̸",
+ "⩂": "⩂",
+ "н": "н",
+ "–": "–",
+ "≠": "≠",
+ "⇗": "⇗",
+ "⤤": "⤤",
+ "↗": "↗",
+ "↗": "↗",
+ "≐̸": "≐̸",
+ "≢": "≢",
+ "⤨": "⤨",
+ "≂̸": "≂̸",
+ "∄": "∄",
+ "∄": "∄",
+ "𝔫": "𝔫",
+ "≧̸": "≧̸",
+ "≱": "≱",
+ "≱": "≱",
+ "≧̸": "≧̸",
+ "⩾̸": "⩾̸",
+ "⩾̸": "⩾̸",
+ "≵": "≵",
+ "≯": "≯",
+ "≯": "≯",
+ "⇎": "⇎",
+ "↮": "↮",
+ "⫲": "⫲",
+ "∋": "∋",
+ "⋼": "⋼",
+ "⋺": "⋺",
+ "∋": "∋",
+ "њ": "њ",
+ "⇍": "⇍",
+ "≦̸": "≦̸",
+ "↚": "↚",
+ "‥": "‥",
+ "≰": "≰",
+ "↚": "↚",
+ "↮": "↮",
+ "≰": "≰",
+ "≦̸": "≦̸",
+ "⩽̸": "⩽̸",
+ "⩽̸": "⩽̸",
+ "≮": "≮",
+ "≴": "≴",
+ "≮": "≮",
+ "⋪": "⋪",
+ "⋬": "⋬",
+ "∤": "∤",
+ "𝕟": "𝕟",
+ "¬": "¬",
+ "∉": "∉",
+ "⋹̸": "⋹̸",
+ "⋵̸": "⋵̸",
+ "∉": "∉",
+ "⋷": "⋷",
+ "⋶": "⋶",
+ "∌": "∌",
+ "∌": "∌",
+ "⋾": "⋾",
+ "⋽": "⋽",
+ "∦": "∦",
+ "∦": "∦",
+ "⫽⃥": "⫽⃥",
+ "∂̸": "∂̸",
+ "⨔": "⨔",
+ "⊀": "⊀",
+ "⋠": "⋠",
+ "⪯̸": "⪯̸",
+ "⊀": "⊀",
+ "⪯̸": "⪯̸",
+ "⇏": "⇏",
+ "↛": "↛",
+ "⤳̸": "⤳̸",
+ "↝̸": "↝̸",
+ "↛": "↛",
+ "⋫": "⋫",
+ "⋭": "⋭",
+ "⊁": "⊁",
+ "⋡": "⋡",
+ "⪰̸": "⪰̸",
+ "𝓃": "𝓃",
+ "∤": "∤",
+ "∦": "∦",
+ "≁": "≁",
+ "≄": "≄",
+ "≄": "≄",
+ "∤": "∤",
+ "∦": "∦",
+ "⋢": "⋢",
+ "⋣": "⋣",
+ "⊄": "⊄",
+ "⫅̸": "⫅̸",
+ "⊈": "⊈",
+ "⊂⃒": "⊂⃒",
+ "⊈": "⊈",
+ "⫅̸": "⫅̸",
+ "⊁": "⊁",
+ "⪰̸": "⪰̸",
+ "⊅": "⊅",
+ "⫆̸": "⫆̸",
+ "⊉": "⊉",
+ "⊃⃒": "⊃⃒",
+ "⊉": "⊉",
+ "⫆̸": "⫆̸",
+ "≹": "≹",
+ "ñ": "ñ",
+ "≸": "≸",
+ "⋪": "⋪",
+ "⋬": "⋬",
+ "⋫": "⋫",
+ "⋭": "⋭",
+ "ν": "ν",
+ "#": "#",
+ "№": "№",
+ " ": " ",
+ "⊭": "⊭",
+ "⤄": "⤄",
+ "≍⃒": "≍⃒",
+ "⊬": "⊬",
+ "≥⃒": "≥⃒",
+ ">⃒": ">⃒",
+ "⧞": "⧞",
+ "⤂": "⤂",
+ "≤⃒": "≤⃒",
+ "<⃒": "<⃒",
+ "⊴⃒": "⊴⃒",
+ "⤃": "⤃",
+ "⊵⃒": "⊵⃒",
+ "∼⃒": "∼⃒",
+ "⇖": "⇖",
+ "⤣": "⤣",
+ "↖": "↖",
+ "↖": "↖",
+ "⤧": "⤧",
+ "Ⓢ": "Ⓢ",
+ "ó": "ó",
+ "⊛": "⊛",
+ "⊚": "⊚",
+ "ô": "ô",
+ "о": "о",
+ "⊝": "⊝",
+ "ő": "ő",
+ "⨸": "⨸",
+ "⊙": "⊙",
+ "⦼": "⦼",
+ "œ": "œ",
+ "⦿": "⦿",
+ "𝔬": "𝔬",
+ "˛": "˛",
+ "ò": "ò",
+ "⧁": "⧁",
+ "⦵": "⦵",
+ "Ω": "Ω",
+ "∮": "∮",
+ "↺": "↺",
+ "⦾": "⦾",
+ "⦻": "⦻",
+ "‾": "‾",
+ "⧀": "⧀",
+ "ō": "ō",
+ "ω": "ω",
+ "ο": "ο",
+ "⦶": "⦶",
+ "⊖": "⊖",
+ "𝕠": "𝕠",
+ "⦷": "⦷",
+ "⦹": "⦹",
+ "⊕": "⊕",
+ "∨": "∨",
+ "↻": "↻",
+ "⩝": "⩝",
+ "ℴ": "ℴ",
+ "ℴ": "ℴ",
+ "ª": "ª",
+ "º": "º",
+ "⊶": "⊶",
+ "⩖": "⩖",
+ "⩗": "⩗",
+ "⩛": "⩛",
+ "ℴ": "ℴ",
+ "ø": "ø",
+ "⊘": "⊘",
+ "õ": "õ",
+ "⊗": "⊗",
+ "⨶": "⨶",
+ "ö": "ö",
+ "⌽": "⌽",
+ "∥": "∥",
+ "¶": "¶",
+ "∥": "∥",
+ "⫳": "⫳",
+ "⫽": "⫽",
+ "∂": "∂",
+ "п": "п",
+ "%": "%",
+ ".": ".",
+ "‰": "‰",
+ "⊥": "⊥",
+ "‱": "‱",
+ "𝔭": "𝔭",
+ "φ": "φ",
+ "ϕ": "ϕ",
+ "ℳ": "ℳ",
+ "☎": "☎",
+ "π": "π",
+ "⋔": "⋔",
+ "ϖ": "ϖ",
+ "ℏ": "ℏ",
+ "ℎ": "ℎ",
+ "ℏ": "ℏ",
+ "+": "+",
+ "⨣": "⨣",
+ "⊞": "⊞",
+ "⨢": "⨢",
+ "∔": "∔",
+ "⨥": "⨥",
+ "⩲": "⩲",
+ "±": "±",
+ "⨦": "⨦",
+ "⨧": "⨧",
+ "±": "±",
+ "⨕": "⨕",
+ "𝕡": "𝕡",
+ "£": "£",
+ "≺": "≺",
+ "⪳": "⪳",
+ "⪷": "⪷",
+ "≼": "≼",
+ "⪯": "⪯",
+ "≺": "≺",
+ "⪷": "⪷",
+ "≼": "≼",
+ "⪯": "⪯",
+ "⪹": "⪹",
+ "⪵": "⪵",
+ "⋨": "⋨",
+ "≾": "≾",
+ "′": "′",
+ "ℙ": "ℙ",
+ "⪵": "⪵",
+ "⪹": "⪹",
+ "⋨": "⋨",
+ "∏": "∏",
+ "⌮": "⌮",
+ "⌒": "⌒",
+ "⌓": "⌓",
+ "∝": "∝",
+ "∝": "∝",
+ "≾": "≾",
+ "⊰": "⊰",
+ "𝓅": "𝓅",
+ "ψ": "ψ",
+ " ": " ",
+ "𝔮": "𝔮",
+ "⨌": "⨌",
+ "𝕢": "𝕢",
+ "⁗": "⁗",
+ "𝓆": "𝓆",
+ "ℍ": "ℍ",
+ "⨖": "⨖",
+ "?": "?",
+ "≟": "≟",
+ """: "\"",
+ "⇛": "⇛",
+ "⇒": "⇒",
+ "⤜": "⤜",
+ "⤏": "⤏",
+ "⥤": "⥤",
+ "∽̱": "∽̱",
+ "ŕ": "ŕ",
+ "√": "√",
+ "⦳": "⦳",
+ "⟩": "⟩",
+ "⦒": "⦒",
+ "⦥": "⦥",
+ "⟩": "⟩",
+ "»": "»",
+ "→": "→",
+ "⥵": "⥵",
+ "⇥": "⇥",
+ "⤠": "⤠",
+ "⤳": "⤳",
+ "⤞": "⤞",
+ "↪": "↪",
+ "↬": "↬",
+ "⥅": "⥅",
+ "⥴": "⥴",
+ "↣": "↣",
+ "↝": "↝",
+ "⤚": "⤚",
+ "∶": "∶",
+ "ℚ": "ℚ",
+ "⤍": "⤍",
+ "❳": "❳",
+ "}": "}",
+ "]": "]",
+ "⦌": "⦌",
+ "⦎": "⦎",
+ "⦐": "⦐",
+ "ř": "ř",
+ "ŗ": "ŗ",
+ "⌉": "⌉",
+ "}": "}",
+ "р": "р",
+ "⤷": "⤷",
+ "⥩": "⥩",
+ "”": "”",
+ "”": "”",
+ "↳": "↳",
+ "ℜ": "ℜ",
+ "ℛ": "ℛ",
+ "ℜ": "ℜ",
+ "ℝ": "ℝ",
+ "▭": "▭",
+ "®": "®",
+ "⥽": "⥽",
+ "⌋": "⌋",
+ "𝔯": "𝔯",
+ "⇁": "⇁",
+ "⇀": "⇀",
+ "⥬": "⥬",
+ "ρ": "ρ",
+ "ϱ": "ϱ",
+ "→": "→",
+ "↣": "↣",
+ "⇁": "⇁",
+ "⇀": "⇀",
+ "⇄": "⇄",
+ "⇌": "⇌",
+ "⇉": "⇉",
+ "↝": "↝",
+ "⋌": "⋌",
+ "˚": "˚",
+ "≓": "≓",
+ "⇄": "⇄",
+ "⇌": "⇌",
+ "‏": "",
+ "⎱": "⎱",
+ "⎱": "⎱",
+ "⫮": "⫮",
+ "⟭": "⟭",
+ "⇾": "⇾",
+ "⟧": "⟧",
+ "⦆": "⦆",
+ "𝕣": "𝕣",
+ "⨮": "⨮",
+ "⨵": "⨵",
+ ")": ")",
+ "⦔": "⦔",
+ "⨒": "⨒",
+ "⇉": "⇉",
+ "›": "›",
+ "𝓇": "𝓇",
+ "↱": "↱",
+ "]": "]",
+ "’": "’",
+ "’": "’",
+ "⋌": "⋌",
+ "⋊": "⋊",
+ "▹": "▹",
+ "⊵": "⊵",
+ "▸": "▸",
+ "⧎": "⧎",
+ "⥨": "⥨",
+ "℞": "℞",
+ "ś": "ś",
+ "‚": "‚",
+ "≻": "≻",
+ "⪴": "⪴",
+ "⪸": "⪸",
+ "š": "š",
+ "≽": "≽",
+ "⪰": "⪰",
+ "ş": "ş",
+ "ŝ": "ŝ",
+ "⪶": "⪶",
+ "⪺": "⪺",
+ "⋩": "⋩",
+ "⨓": "⨓",
+ "≿": "≿",
+ "с": "с",
+ "⋅": "⋅",
+ "⊡": "⊡",
+ "⩦": "⩦",
+ "⇘": "⇘",
+ "⤥": "⤥",
+ "↘": "↘",
+ "↘": "↘",
+ "§": "§",
+ ";": ";",
+ "⤩": "⤩",
+ "∖": "∖",
+ "∖": "∖",
+ "✶": "✶",
+ "𝔰": "𝔰",
+ "⌢": "⌢",
+ "♯": "♯",
+ "щ": "щ",
+ "ш": "ш",
+ "∣": "∣",
+ "∥": "∥",
+ "­": "",
+ "σ": "σ",
+ "ς": "ς",
+ "ς": "ς",
+ "∼": "∼",
+ "⩪": "⩪",
+ "≃": "≃",
+ "≃": "≃",
+ "⪞": "⪞",
+ "⪠": "⪠",
+ "⪝": "⪝",
+ "⪟": "⪟",
+ "≆": "≆",
+ "⨤": "⨤",
+ "⥲": "⥲",
+ "←": "←",
+ "∖": "∖",
+ "⨳": "⨳",
+ "⧤": "⧤",
+ "∣": "∣",
+ "⌣": "⌣",
+ "⪪": "⪪",
+ "⪬": "⪬",
+ "⪬︀": "⪬︀",
+ "ь": "ь",
+ "/": "/",
+ "⧄": "⧄",
+ "⌿": "⌿",
+ "𝕤": "𝕤",
+ "♠": "♠",
+ "♠": "♠",
+ "∥": "∥",
+ "⊓": "⊓",
+ "⊓︀": "⊓︀",
+ "⊔": "⊔",
+ "⊔︀": "⊔︀",
+ "⊏": "⊏",
+ "⊑": "⊑",
+ "⊏": "⊏",
+ "⊑": "⊑",
+ "⊐": "⊐",
+ "⊒": "⊒",
+ "⊐": "⊐",
+ "⊒": "⊒",
+ "□": "□",
+ "□": "□",
+ "▪": "▪",
+ "▪": "▪",
+ "→": "→",
+ "𝓈": "𝓈",
+ "∖": "∖",
+ "⌣": "⌣",
+ "⋆": "⋆",
+ "☆": "☆",
+ "★": "★",
+ "ϵ": "ϵ",
+ "ϕ": "ϕ",
+ "¯": "¯",
+ "⊂": "⊂",
+ "⫅": "⫅",
+ "⪽": "⪽",
+ "⊆": "⊆",
+ "⫃": "⫃",
+ "⫁": "⫁",
+ "⫋": "⫋",
+ "⊊": "⊊",
+ "⪿": "⪿",
+ "⥹": "⥹",
+ "⊂": "⊂",
+ "⊆": "⊆",
+ "⫅": "⫅",
+ "⊊": "⊊",
+ "⫋": "⫋",
+ "⫇": "⫇",
+ "⫕": "⫕",
+ "⫓": "⫓",
+ "≻": "≻",
+ "⪸": "⪸",
+ "≽": "≽",
+ "⪰": "⪰",
+ "⪺": "⪺",
+ "⪶": "⪶",
+ "⋩": "⋩",
+ "≿": "≿",
+ "∑": "∑",
+ "♪": "♪",
+ "¹": "¹",
+ "²": "²",
+ "³": "³",
+ "⊃": "⊃",
+ "⫆": "⫆",
+ "⪾": "⪾",
+ "⫘": "⫘",
+ "⊇": "⊇",
+ "⫄": "⫄",
+ "⟉": "⟉",
+ "⫗": "⫗",
+ "⥻": "⥻",
+ "⫂": "⫂",
+ "⫌": "⫌",
+ "⊋": "⊋",
+ "⫀": "⫀",
+ "⊃": "⊃",
+ "⊇": "⊇",
+ "⫆": "⫆",
+ "⊋": "⊋",
+ "⫌": "⫌",
+ "⫈": "⫈",
+ "⫔": "⫔",
+ "⫖": "⫖",
+ "⇙": "⇙",
+ "⤦": "⤦",
+ "↙": "↙",
+ "↙": "↙",
+ "⤪": "⤪",
+ "ß": "ß",
+ "⌖": "⌖",
+ "τ": "τ",
+ "⎴": "⎴",
+ "ť": "ť",
+ "ţ": "ţ",
+ "т": "т",
+ "⃛": "⃛",
+ "⌕": "⌕",
+ "𝔱": "𝔱",
+ "∴": "∴",
+ "∴": "∴",
+ "θ": "θ",
+ "ϑ": "ϑ",
+ "ϑ": "ϑ",
+ "≈": "≈",
+ "∼": "∼",
+ " ": " ",
+ "≈": "≈",
+ "∼": "∼",
+ "þ": "þ",
+ "˜": "˜",
+ "×": "×",
+ "⊠": "⊠",
+ "⨱": "⨱",
+ "⨰": "⨰",
+ "∭": "∭",
+ "⤨": "⤨",
+ "⊤": "⊤",
+ "⌶": "⌶",
+ "⫱": "⫱",
+ "𝕥": "𝕥",
+ "⫚": "⫚",
+ "⤩": "⤩",
+ "‴": "‴",
+ "™": "™",
+ "▵": "▵",
+ "▿": "▿",
+ "◃": "◃",
+ "⊴": "⊴",
+ "≜": "≜",
+ "▹": "▹",
+ "⊵": "⊵",
+ "◬": "◬",
+ "≜": "≜",
+ "⨺": "⨺",
+ "⨹": "⨹",
+ "⧍": "⧍",
+ "⨻": "⨻",
+ "⏢": "⏢",
+ "𝓉": "𝓉",
+ "ц": "ц",
+ "ћ": "ћ",
+ "ŧ": "ŧ",
+ "≬": "≬",
+ "↞": "↞",
+ "↠": "↠",
+ "⇑": "⇑",
+ "⥣": "⥣",
+ "ú": "ú",
+ "↑": "↑",
+ "ў": "ў",
+ "ŭ": "ŭ",
+ "û": "û",
+ "у": "у",
+ "⇅": "⇅",
+ "ű": "ű",
+ "⥮": "⥮",
+ "⥾": "⥾",
+ "𝔲": "𝔲",
+ "ù": "ù",
+ "↿": "↿",
+ "↾": "↾",
+ "▀": "▀",
+ "⌜": "⌜",
+ "⌜": "⌜",
+ "⌏": "⌏",
+ "◸": "◸",
+ "ū": "ū",
+ "¨": "¨",
+ "ų": "ų",
+ "𝕦": "𝕦",
+ "↑": "↑",
+ "↕": "↕",
+ "↿": "↿",
+ "↾": "↾",
+ "⊎": "⊎",
+ "υ": "υ",
+ "ϒ": "ϒ",
+ "υ": "υ",
+ "⇈": "⇈",
+ "⌝": "⌝",
+ "⌝": "⌝",
+ "⌎": "⌎",
+ "ů": "ů",
+ "◹": "◹",
+ "𝓊": "𝓊",
+ "⋰": "⋰",
+ "ũ": "ũ",
+ "▵": "▵",
+ "▴": "▴",
+ "⇈": "⇈",
+ "ü": "ü",
+ "⦧": "⦧",
+ "⇕": "⇕",
+ "⫨": "⫨",
+ "⫩": "⫩",
+ "⊨": "⊨",
+ "⦜": "⦜",
+ "ϵ": "ϵ",
+ "ϰ": "ϰ",
+ "∅": "∅",
+ "ϕ": "ϕ",
+ "ϖ": "ϖ",
+ "∝": "∝",
+ "↕": "↕",
+ "ϱ": "ϱ",
+ "ς": "ς",
+ "⊊︀": "⊊︀",
+ "⫋︀": "⫋︀",
+ "⊋︀": "⊋︀",
+ "⫌︀": "⫌︀",
+ "ϑ": "ϑ",
+ "⊲": "⊲",
+ "⊳": "⊳",
+ "в": "в",
+ "⊢": "⊢",
+ "∨": "∨",
+ "⊻": "⊻",
+ "≚": "≚",
+ "⋮": "⋮",
+ "|": "|",
+ "|": "|",
+ "𝔳": "𝔳",
+ "⊲": "⊲",
+ "⊂⃒": "⊂⃒",
+ "⊃⃒": "⊃⃒",
+ "𝕧": "𝕧",
+ "∝": "∝",
+ "⊳": "⊳",
+ "𝓋": "𝓋",
+ "⫋︀": "⫋︀",
+ "⊊︀": "⊊︀",
+ "⫌︀": "⫌︀",
+ "⊋︀": "⊋︀",
+ "⦚": "⦚",
+ "ŵ": "ŵ",
+ "⩟": "⩟",
+ "∧": "∧",
+ "≙": "≙",
+ "℘": "℘",
+ "𝔴": "𝔴",
+ "𝕨": "𝕨",
+ "℘": "℘",
+ "≀": "≀",
+ "≀": "≀",
+ "𝓌": "𝓌",
+ "⋂": "⋂",
+ "◯": "◯",
+ "⋃": "⋃",
+ "▽": "▽",
+ "𝔵": "𝔵",
+ "⟺": "⟺",
+ "⟷": "⟷",
+ "ξ": "ξ",
+ "⟸": "⟸",
+ "⟵": "⟵",
+ "⟼": "⟼",
+ "⋻": "⋻",
+ "⨀": "⨀",
+ "𝕩": "𝕩",
+ "⨁": "⨁",
+ "⨂": "⨂",
+ "⟹": "⟹",
+ "⟶": "⟶",
+ "𝓍": "𝓍",
+ "⨆": "⨆",
+ "⨄": "⨄",
+ "△": "△",
+ "⋁": "⋁",
+ "⋀": "⋀",
+ "ý": "ý",
+ "я": "я",
+ "ŷ": "ŷ",
+ "ы": "ы",
+ "¥": "¥",
+ "𝔶": "𝔶",
+ "ї": "ї",
+ "𝕪": "𝕪",
+ "𝓎": "𝓎",
+ "ю": "ю",
+ "ÿ": "ÿ",
+ "ź": "ź",
+ "ž": "ž",
+ "з": "з",
+ "ż": "ż",
+ "ℨ": "ℨ",
+ "ζ": "ζ",
+ "𝔷": "𝔷",
+ "ж": "ж",
+ "⇝": "⇝",
+ "𝕫": "𝕫",
+ "𝓏": "𝓏",
+ "‍": "",
+ "‌": ""
+};
diff --git a/pkgs/markdown/lib/src/ast.dart b/pkgs/markdown/lib/src/ast.dart
new file mode 100644
index 0000000..e5530cb
--- /dev/null
+++ b/pkgs/markdown/lib/src/ast.dart
@@ -0,0 +1,113 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+typedef Resolver = Node? Function(String name, [String? title]);
+
+/// Base class for any AST item.
+///
+/// Roughly corresponds to Node in the DOM. Will be either an Element or Text.
+abstract class Node {
+ void accept(NodeVisitor visitor);
+
+ String get textContent;
+}
+
+/// A named tag that can contain other nodes.
+class Element implements Node {
+ final String tag;
+ final List<Node>? children;
+ final Map<String, String> attributes;
+ String? generatedId;
+ String? footnoteLabel;
+
+ /// Instantiates a [tag] Element with [children].
+ Element(this.tag, this.children) : attributes = {};
+
+ /// Instantiates an empty, self-closing [tag] Element.
+ Element.empty(this.tag)
+ : children = null,
+ attributes = {};
+
+ /// Instantiates a [tag] Element with no [children].
+ Element.withTag(this.tag)
+ : children = const [],
+ attributes = {};
+
+ /// Instantiates a [tag] Element with a single Text child.
+ Element.text(this.tag, String text)
+ : children = [Text(text)],
+ attributes = {};
+
+ /// Whether this element is self-closing.
+ bool get isEmpty => children == null;
+
+ @override
+ void accept(NodeVisitor visitor) {
+ if (visitor.visitElementBefore(this)) {
+ if (children != null) {
+ for (final child in children!) {
+ child.accept(visitor);
+ }
+ }
+ visitor.visitElementAfter(this);
+ }
+ }
+
+ @override
+ String get textContent {
+ final children = this.children;
+ return children == null
+ ? ''
+ : children.map((child) => child.textContent).join();
+ }
+}
+
+/// A plain text element.
+class Text implements Node {
+ final String text;
+
+ Text(this.text);
+
+ @override
+ void accept(NodeVisitor visitor) => visitor.visitText(this);
+
+ @override
+ String get textContent => text;
+}
+
+/// Inline content that has not been parsed into inline nodes (strong, links,
+/// etc).
+///
+/// These placeholder nodes should only remain in place while the block nodes
+/// of a document are still being parsed, in order to gather all reference link
+/// definitions.
+class UnparsedContent implements Node {
+ @override
+ final String textContent;
+
+ UnparsedContent(this.textContent);
+
+ @override
+ void accept(NodeVisitor visitor) {}
+}
+
+/// Visitor pattern for the AST.
+///
+/// Renderers or other AST transformers should implement this.
+abstract class NodeVisitor {
+ /// Called when a Text node has been reached.
+ void visitText(Text text);
+
+ /// Called when an Element has been reached, before its children have been
+ /// visited.
+ ///
+ /// Returns `false` to skip its children.
+ bool visitElementBefore(Element element);
+
+ /// Called when an Element has been reached, after its children have been
+ /// visited.
+ ///
+ /// Will not be called if [visitElementBefore] returns `false`.
+ void visitElementAfter(Element element);
+}
diff --git a/pkgs/markdown/lib/src/block_parser.dart b/pkgs/markdown/lib/src/block_parser.dart
new file mode 100644
index 0000000..efe2352
--- /dev/null
+++ b/pkgs/markdown/lib/src/block_parser.dart
@@ -0,0 +1,216 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'ast.dart';
+import 'block_syntaxes/block_syntax.dart';
+import 'block_syntaxes/blockquote_syntax.dart';
+import 'block_syntaxes/code_block_syntax.dart';
+import 'block_syntaxes/dummy_block_syntax.dart';
+import 'block_syntaxes/empty_block_syntax.dart';
+import 'block_syntaxes/header_syntax.dart';
+import 'block_syntaxes/horizontal_rule_syntax.dart';
+import 'block_syntaxes/html_block_syntax.dart';
+import 'block_syntaxes/link_reference_definition_syntax.dart';
+import 'block_syntaxes/ordered_list_syntax.dart';
+import 'block_syntaxes/paragraph_syntax.dart';
+import 'block_syntaxes/setext_header_syntax.dart';
+import 'block_syntaxes/unordered_list_syntax.dart';
+import 'document.dart';
+import 'line.dart';
+
+/// Maintains the internal state needed to parse a series of lines into blocks
+/// of Markdown suitable for further inline parsing.
+class BlockParser {
+ final List<Line> lines;
+
+ /// The Markdown document this parser is parsing.
+ final Document document;
+
+ /// The enabled block syntaxes.
+ ///
+ /// To turn a series of lines into blocks, each of these will be tried in
+ /// turn. Order matters here.
+ final List<BlockSyntax> blockSyntaxes = [];
+
+ /// Index of the current line.
+ int _pos = 0;
+
+ /// Starting line of the last unconsumed content.
+ int _start = 0;
+
+ /// The lines from [_start] to [_pos] (inclusive), it works as a buffer for
+ /// some blocks, for example:
+ /// When the [ParagraphSyntax] parsing process is interrupted by the
+ /// [SetextHeaderSyntax], so this structure is not a paragraph but a setext
+ /// heading, then the [ParagraphSyntax.parse] does not have to retreat the
+ /// reading position, it only needs to return `null`, the [SetextHeaderSyntax]
+ /// will pick up the lines in [linesToConsume].
+ List<Line> get linesToConsume => lines.getRange(_start, _pos + 1).toList();
+
+ /// Whether the parser has encountered a blank line between two block-level
+ /// elements.
+ bool encounteredBlankLine = false;
+
+ /// The collection of built-in block parsers.
+ final List<BlockSyntax> standardBlockSyntaxes = [
+ const EmptyBlockSyntax(),
+ const HtmlBlockSyntax(),
+ const SetextHeaderSyntax(),
+ const HeaderSyntax(),
+ const CodeBlockSyntax(),
+ const BlockquoteSyntax(),
+ const HorizontalRuleSyntax(),
+ const UnorderedListSyntax(),
+ const OrderedListSyntax(),
+ const LinkReferenceDefinitionSyntax(),
+ const ParagraphSyntax()
+ ];
+
+ BlockParser(this.lines, this.document) {
+ blockSyntaxes.addAll(document.blockSyntaxes);
+
+ if (document.withDefaultBlockSyntaxes) {
+ blockSyntaxes.addAll(standardBlockSyntaxes);
+ } else {
+ blockSyntaxes.add(const DummyBlockSyntax());
+ }
+ }
+
+ /// Gets the current line.
+ Line get current => lines[_pos];
+
+ /// Gets the line after the current one or `null` if there is none.
+ Line? get next {
+ // Don't read past the end.
+ if (_pos >= lines.length - 1) return null;
+ return lines[_pos + 1];
+ }
+
+ /// Gets the line that is [linesAhead] lines ahead of the current one, or
+ /// `null` if there is none.
+ ///
+ /// `peek(0)` is equivalent to [current].
+ ///
+ /// `peek(1)` is equivalent to [next].
+ Line? peek(int linesAhead) {
+ if (linesAhead < 0) {
+ throw ArgumentError('Invalid linesAhead: $linesAhead; must be >= 0.');
+ }
+ // Don't read past the end.
+ if (_pos >= lines.length - linesAhead) return null;
+ return lines[_pos + linesAhead];
+ }
+
+ /// Advances the reading position by one line.
+ void advance() {
+ _pos++;
+ }
+
+ /// Retreats the reading position by one line.
+ void retreat() {
+ _pos--;
+ }
+
+ /// Retreats the reading position by [count] lines.
+ void retreatBy(int count) {
+ _pos -= count;
+ }
+
+ bool get isDone => _pos >= lines.length;
+
+ /// Gets whether or not the current line matches the given pattern.
+ bool matches(RegExp regex) {
+ if (isDone) return false;
+ return regex.hasMatch(current.content);
+ }
+
+ /// Gets whether or not the next line matches the given pattern.
+ bool matchesNext(RegExp regex) {
+ if (next == null) return false;
+ return regex.hasMatch(next!.content);
+ }
+
+ /// The parent [BlockSyntax] when it is running inside a nested syntax.
+ BlockSyntax? get parentSyntax => _parentSyntax;
+ BlockSyntax? _parentSyntax;
+
+ /// Whether the [SetextHeadingSyntax] is disabled temporarily.
+ bool get setextHeadingDisabled => _setextHeadingDisabled;
+ bool _setextHeadingDisabled = false;
+
+ /// The [BlockSyntax] which is running now.
+ /// The value is `null` until we found the first matched [BlockSyntax].
+ BlockSyntax? get currentSyntax => _currentSyntax;
+ BlockSyntax? _currentSyntax;
+
+ /// The [BlockSyntax] which is running before the [currentSyntax].
+ BlockSyntax? get previousSyntax => _previousSyntax;
+ BlockSyntax? _previousSyntax;
+
+ List<Node> parseLines({
+ BlockSyntax? parentSyntax,
+ bool disabledSetextHeading = false,
+ }) {
+ _parentSyntax = parentSyntax;
+ _setextHeadingDisabled = disabledSetextHeading;
+
+ final blocks = <Node>[];
+
+ // If the `_pos` does not change before and after `parse()`, never try to
+ // parse the line at `_pos` with the same syntax again.
+ // For example the `TableSyntax` might not advance the `_pos` in `parse`
+ // method, beause of the header row does not match the delimiter row in the
+ // number of cells, which makes a table like structure not be recognized.
+ BlockSyntax? neverMatch;
+
+ var iterationsWithoutProgress = 0;
+ while (!isDone) {
+ final positionBefore = _pos;
+ for (final syntax in blockSyntaxes) {
+ if (neverMatch == syntax) {
+ continue;
+ }
+
+ if (syntax.canParse(this)) {
+ _previousSyntax = _currentSyntax;
+ _currentSyntax = syntax;
+ final block = syntax.parse(this);
+ if (block != null) {
+ blocks.add(block);
+ }
+ neverMatch = _pos != positionBefore ? null : syntax;
+
+ if (block != null ||
+ syntax is EmptyBlockSyntax ||
+ syntax is LinkReferenceDefinitionSyntax) {
+ _start = _pos;
+ }
+
+ break;
+ }
+ }
+ // Count the number of iterations without progress.
+ // This ensures that we don't have an infinite loop. And if we have an
+ // infinite loop, it's easier to gracefully recover from an error, than
+ // it is to discover an kill an isolate that's stuck in an infinite loop.
+ // Technically, it should be perfectly safe to remove this check
+ // But as it's possible to inject custom BlockSyntax implementations and
+ // combine existing ones, it is hard to promise that no combination can't
+ // trigger an infinite loop
+ if (positionBefore == _pos) {
+ iterationsWithoutProgress++;
+ if (iterationsWithoutProgress > 2) {
+ // If this happens we throw an error to avoid having the parser
+ // running in an infinite loop. An error is easier to handle.
+ // If you see this error in production please file a bug!
+ throw AssertionError('BlockParser.parseLines is not advancing');
+ }
+ } else {
+ iterationsWithoutProgress = 0;
+ }
+ }
+
+ return blocks;
+ }
+}
diff --git a/pkgs/markdown/lib/src/block_syntaxes/alert_block_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/alert_block_syntax.dart
new file mode 100644
index 0000000..0f4f5b1
--- /dev/null
+++ b/pkgs/markdown/lib/src/block_syntaxes/alert_block_syntax.dart
@@ -0,0 +1,109 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../ast.dart';
+import '../block_parser.dart';
+import '../line.dart';
+import '../patterns.dart';
+import 'block_syntax.dart';
+import 'code_block_syntax.dart';
+import 'paragraph_syntax.dart';
+
+/// Parses GitHub Alerts blocks.
+///
+/// See also: https://docs.github.com/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#alerts
+class AlertBlockSyntax extends BlockSyntax {
+ const AlertBlockSyntax();
+
+ @override
+ RegExp get pattern => alertPattern;
+
+ @override
+ bool canParse(BlockParser parser) {
+ return alertPattern.hasMatch(parser.current.content);
+ }
+
+ /// Whether this alert ends with a lazy continuation line.
+ ///
+ /// The definition of lazy continuation lines:
+ /// https://spec.commonmark.org/0.30/#lazy-continuation-line
+ static bool _lazyContinuation = false;
+ static final _contentLineRegExp = RegExp(r'>?\s?(.*)*');
+
+ @override
+ List<Line> parseChildLines(BlockParser parser) {
+ // Grab all of the lines that form the alert, stripping off the ">".
+ final childLines = <Line>[];
+ _lazyContinuation = false;
+
+ while (!parser.isDone) {
+ final lineContent = parser.current.content.trimLeft();
+ final strippedContent = lineContent.replaceFirst(RegExp(r'^>?\s*'), '');
+ final match = strippedContent.isEmpty && !lineContent.startsWith('>')
+ ? null
+ : _contentLineRegExp.firstMatch(strippedContent);
+ if (match != null) {
+ childLines.add(Line(strippedContent));
+ parser.advance();
+ _lazyContinuation = false;
+ continue;
+ }
+
+ final lastLine = childLines.isEmpty ? Line('') : childLines.last;
+
+ // A paragraph continuation is OK. This is content that cannot be parsed
+ // as any other syntax except Paragraph, and it doesn't match the bar in
+ // a Setext header.
+ // Because indented code blocks cannot interrupt paragraphs, a line
+ // matched CodeBlockSyntax is also paragraph continuation text.
+ final otherMatched =
+ parser.blockSyntaxes.firstWhere((s) => s.canParse(parser));
+ if ((otherMatched is ParagraphSyntax &&
+ !lastLine.isBlankLine &&
+ !codeFencePattern.hasMatch(lastLine.content)) ||
+ (otherMatched is CodeBlockSyntax &&
+ !indentPattern.hasMatch(lastLine.content))) {
+ childLines.add(parser.current);
+ _lazyContinuation = true;
+ parser.advance();
+ } else {
+ break;
+ }
+ }
+
+ return childLines;
+ }
+
+ @override
+ Node parse(BlockParser parser) {
+ // Parse the alert type from the first line.
+ final type =
+ pattern.firstMatch(parser.current.content)!.group(1)!.toLowerCase();
+ parser.advance();
+ final childLines = parseChildLines(parser);
+ // Recursively parse the contents of the alert.
+ final children = BlockParser(childLines, parser.document).parseLines(
+ // The setext heading underline cannot be a lazy continuation line in a
+ // block quote.
+ // https://spec.commonmark.org/0.30/#example-93
+ disabledSetextHeading: _lazyContinuation,
+ parentSyntax: this,
+ );
+
+ // Mapping the alert title text.
+ const typeTextMap = {
+ 'note': 'Note',
+ 'tip': 'Tip',
+ 'important': 'Important',
+ 'caution': 'Caution',
+ 'warning': 'Warning',
+ };
+ final titleText = typeTextMap[type]!;
+ final titleElement = Element('p', [Text(titleText)])
+ ..attributes['class'] = 'markdown-alert-title';
+ final elementClass = 'markdown-alert markdown-alert-$type';
+ return Element('div', [titleElement, ...children])
+ ..attributes['class'] = elementClass;
+ }
+}
diff --git a/pkgs/markdown/lib/src/block_syntaxes/block_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/block_syntax.dart
new file mode 100644
index 0000000..947824a
--- /dev/null
+++ b/pkgs/markdown/lib/src/block_syntaxes/block_syntax.dart
@@ -0,0 +1,64 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../ast.dart';
+import '../block_parser.dart';
+import '../line.dart';
+
+abstract class BlockSyntax {
+ const BlockSyntax();
+
+ /// Gets the regex used to identify the beginning of this block, if any.
+ RegExp get pattern;
+
+ bool canEndBlock(BlockParser parser) => true;
+
+ bool canParse(BlockParser parser) {
+ return pattern.hasMatch(parser.current.content);
+ }
+
+ Node? parse(BlockParser parser);
+
+ List<Line?> parseChildLines(BlockParser parser) {
+ // Grab all of the lines that form the block element.
+ final childLines = <Line?>[];
+
+ while (!parser.isDone) {
+ final match = pattern.firstMatch(parser.current.content);
+ if (match == null) break;
+ childLines.add(parser.current);
+ parser.advance();
+ }
+
+ return childLines;
+ }
+
+ /// Returns the block which interrupts current syntax parsing if there is one,
+ /// otherwise returns `null`.
+ ///
+ /// Make sure to check if [parser] `isDone` is `false` first.
+ BlockSyntax? interruptedBy(BlockParser parser) {
+ for (final syntax in parser.blockSyntaxes) {
+ if (syntax.canParse(parser) && syntax.canEndBlock(parser)) {
+ return syntax;
+ }
+ }
+ return null;
+ }
+
+ /// Gets whether or not [parser]'s current line should end the previous block.
+ static bool isAtBlockEnd(BlockParser parser) {
+ if (parser.isDone) return true;
+ return parser.blockSyntaxes
+ .any((s) => s.canParse(parser) && s.canEndBlock(parser));
+ }
+
+ /// Generates a valid HTML anchor from the inner text of [element].
+ static String generateAnchorHash(Element element) =>
+ element.children!.first.textContent
+ .toLowerCase()
+ .trim()
+ .replaceAll(RegExp('[^a-z0-9 _-]'), '')
+ .replaceAll(RegExp(r'\s'), '-');
+}
diff --git a/pkgs/markdown/lib/src/block_syntaxes/blockquote_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/blockquote_syntax.dart
new file mode 100644
index 0000000..afbe23a
--- /dev/null
+++ b/pkgs/markdown/lib/src/block_syntaxes/blockquote_syntax.dart
@@ -0,0 +1,99 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../ast.dart';
+import '../block_parser.dart';
+import '../charcode.dart';
+import '../line.dart';
+import '../patterns.dart';
+import '../util.dart';
+import 'block_syntax.dart';
+import 'code_block_syntax.dart';
+import 'paragraph_syntax.dart';
+
+/// Parses email-style blockquotes: `> quote`.
+class BlockquoteSyntax extends BlockSyntax {
+ @override
+ RegExp get pattern => blockquotePattern;
+
+ const BlockquoteSyntax();
+
+ /// Whether this blockquote ends with a lazy continuation line.
+ // The definition of lazy continuation lines:
+ // https://spec.commonmark.org/0.30/#lazy-continuation-line
+ static var _lazyContinuation = false;
+ @override
+ List<Line> parseChildLines(BlockParser parser) {
+ // Grab all of the lines that form the blockquote, stripping off the ">".
+ final childLines = <Line>[];
+ _lazyContinuation = false;
+
+ while (!parser.isDone) {
+ final currentLine = parser.current;
+ final match = pattern.firstMatch(parser.current.content);
+ if (match != null) {
+ // A block quote marker consists of a `>` together with an optional
+ // following space of indentation, see
+ // https://spec.commonmark.org/0.30/#block-quote-marker.
+ final markerStart = match.match.indexOf('>');
+ int markerEnd;
+ if (currentLine.content.length > 1) {
+ var hasSpace = false;
+ // Check if there is a following space if the marker is not at the end
+ // of this line.
+ if (markerStart < currentLine.content.length - 1) {
+ final nextChar = currentLine.content.codeUnitAt(markerStart + 1);
+ hasSpace = nextChar == $tab || nextChar == $space;
+ }
+ markerEnd = markerStart + (hasSpace ? 2 : 1);
+ } else {
+ markerEnd = markerStart + 1;
+ }
+ childLines.add(Line(currentLine.content.substring(markerEnd)));
+ parser.advance();
+ _lazyContinuation = false;
+ continue;
+ }
+
+ final lastLine = childLines.last;
+
+ // A paragraph continuation is OK. This is content that cannot be parsed
+ // as any other syntax except Paragraph, and it doesn't match the bar in
+ // a Setext header.
+ // Because indented code blocks cannot interrupt paragraphs, a line
+ // matched CodeBlockSyntax is also paragraph continuation text.
+ final otherMatched =
+ parser.blockSyntaxes.firstWhere((s) => s.canParse(parser));
+ if ((otherMatched is ParagraphSyntax &&
+ !lastLine.isBlankLine &&
+ !codeFencePattern.hasMatch(lastLine.content)) ||
+ (otherMatched is CodeBlockSyntax &&
+ !indentPattern.hasMatch(lastLine.content))) {
+ childLines.add(parser.current);
+ _lazyContinuation = true;
+ parser.advance();
+ } else {
+ break;
+ }
+ }
+
+ return childLines;
+ }
+
+ @override
+ Node parse(BlockParser parser) {
+ final childLines = parseChildLines(parser);
+
+ // Recursively parse the contents of the blockquote.
+ final children = BlockParser(childLines, parser.document).parseLines(
+ // The setext heading underline cannot be a lazy continuation line in a
+ // block quote.
+ // https://spec.commonmark.org/0.30/#example-93
+ disabledSetextHeading: _lazyContinuation,
+ parentSyntax: this,
+ );
+
+ return Element('blockquote', children);
+ }
+}
diff --git a/pkgs/markdown/lib/src/block_syntaxes/code_block_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/code_block_syntax.dart
new file mode 100644
index 0000000..1d30667
--- /dev/null
+++ b/pkgs/markdown/lib/src/block_syntaxes/code_block_syntax.dart
@@ -0,0 +1,85 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../ast.dart';
+import '../block_parser.dart';
+import '../line.dart';
+import '../patterns.dart';
+import '../util.dart';
+import 'block_syntax.dart';
+
+/// Parses preformatted code blocks that are indented four spaces.
+class CodeBlockSyntax extends BlockSyntax {
+ @override
+ RegExp get pattern => indentPattern;
+
+ @override
+ bool canEndBlock(BlockParser parser) => false;
+
+ const CodeBlockSyntax();
+
+ @override
+ List<Line> parseChildLines(BlockParser parser) {
+ final childLines = <Line>[];
+
+ while (!parser.isDone) {
+ final isBlankLine = parser.current.isBlankLine;
+ if (isBlankLine && _shouldEnd(parser)) {
+ break;
+ }
+
+ if (!isBlankLine &&
+ childLines.isNotEmpty &&
+ !pattern.hasMatch(parser.current.content)) {
+ break;
+ }
+
+ childLines.add(Line(
+ parser.current.content.dedent().text,
+ tabRemaining: parser.current.tabRemaining,
+ ));
+
+ parser.advance();
+ }
+
+ return childLines;
+ }
+
+ @override
+ Node parse(BlockParser parser) {
+ final childLines = parseChildLines(parser);
+
+ // The Markdown tests expect a trailing newline.
+ childLines.add(Line(''));
+
+ var content = childLines
+ .map((e) => e.content.prependSpace(e.tabRemaining ?? 0))
+ .join('\n');
+ if (parser.document.encodeHtml) {
+ content = escapeHtml(content, escapeApos: false);
+ }
+
+ return Element('pre', [Element.text('code', content)]);
+ }
+
+ bool _shouldEnd(BlockParser parser) {
+ var i = 1;
+ while (true) {
+ final nextLine = parser.peek(i);
+ // EOF
+ if (nextLine == null) {
+ return true;
+ }
+
+ // It does not matter how many blank lines between chunks:
+ // https://spec.commonmark.org/0.30/#example-111
+ if (nextLine.isBlankLine) {
+ i++;
+ continue;
+ }
+
+ return !pattern.hasMatch(nextLine.content);
+ }
+ }
+}
diff --git a/pkgs/markdown/lib/src/block_syntaxes/dummy_block_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/dummy_block_syntax.dart
new file mode 100644
index 0000000..c08c8a8
--- /dev/null
+++ b/pkgs/markdown/lib/src/block_syntaxes/dummy_block_syntax.dart
@@ -0,0 +1,36 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../ast.dart';
+import '../block_parser.dart';
+import '../patterns.dart';
+import 'block_syntax.dart';
+
+/// Walks the parser forward through the lines does not match any [BlockSyntax].
+///
+/// Returns a [UnparsedContent] with the unmatched lines as `textContent`.
+class DummyBlockSyntax extends BlockSyntax {
+ const DummyBlockSyntax();
+
+ @override
+ RegExp get pattern => dummyPattern;
+
+ @override
+ bool canEndBlock(BlockParser parser) => false;
+
+ @override
+ bool canParse(BlockParser parser) => true;
+
+ @override
+ Node parse(BlockParser parser) {
+ final childLines = <String>[];
+
+ while (!BlockSyntax.isAtBlockEnd(parser)) {
+ childLines.add(parser.current.content);
+ parser.advance();
+ }
+
+ return UnparsedContent(childLines.join('\n'));
+ }
+}
diff --git a/pkgs/markdown/lib/src/block_syntaxes/empty_block_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/empty_block_syntax.dart
new file mode 100644
index 0000000..54cc865
--- /dev/null
+++ b/pkgs/markdown/lib/src/block_syntaxes/empty_block_syntax.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../ast.dart';
+import '../block_parser.dart';
+import '../patterns.dart';
+import 'block_syntax.dart';
+
+class EmptyBlockSyntax extends BlockSyntax {
+ @override
+ RegExp get pattern => emptyPattern;
+
+ const EmptyBlockSyntax();
+
+ @override
+ Node? parse(BlockParser parser) {
+ parser.encounteredBlankLine = true;
+ parser.advance();
+
+ // Don't actually emit anything.
+ return null;
+ }
+}
diff --git a/pkgs/markdown/lib/src/block_syntaxes/fenced_blockquote_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/fenced_blockquote_syntax.dart
new file mode 100644
index 0000000..9e18d42
--- /dev/null
+++ b/pkgs/markdown/lib/src/block_syntaxes/fenced_blockquote_syntax.dart
@@ -0,0 +1,45 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../ast.dart';
+import '../block_parser.dart';
+import '../line.dart';
+import '../patterns.dart';
+import 'block_syntax.dart';
+
+/// Parses lines fenced by `>>>` to blockquotes
+class FencedBlockquoteSyntax extends BlockSyntax {
+ const FencedBlockquoteSyntax();
+
+ @override
+ RegExp get pattern => blockquoteFencePattern;
+
+ @override
+ List<Line> parseChildLines(BlockParser parser) {
+ final childLines = <Line>[];
+ parser.advance();
+
+ while (!parser.isDone) {
+ final match = pattern.hasMatch(parser.current.content);
+ if (!match) {
+ childLines.add(parser.current);
+ parser.advance();
+ } else {
+ parser.advance();
+ break;
+ }
+ }
+
+ return childLines;
+ }
+
+ @override
+ Node? parse(BlockParser parser) {
+ final childLines = parseChildLines(parser);
+
+ // Recursively parse the contents of the blockquote.
+ final children = BlockParser(childLines, parser.document).parseLines();
+ return Element('blockquote', children);
+ }
+}
diff --git a/pkgs/markdown/lib/src/block_syntaxes/fenced_code_block_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/fenced_code_block_syntax.dart
new file mode 100644
index 0000000..cea1106
--- /dev/null
+++ b/pkgs/markdown/lib/src/block_syntaxes/fenced_code_block_syntax.dart
@@ -0,0 +1,141 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../ast.dart';
+import '../block_parser.dart';
+import '../line.dart';
+import '../patterns.dart';
+import '../util.dart';
+import 'block_syntax.dart';
+
+/// Parses preformatted code blocks between two ~~~ or ``` sequences.
+///
+/// See the CommonMark spec:
+/// https://spec.commonmark.org/0.30/#fenced-code-blocks
+class FencedCodeBlockSyntax extends BlockSyntax {
+ @override
+ RegExp get pattern => codeFencePattern;
+
+ const FencedCodeBlockSyntax();
+
+ @override
+ Node parse(BlockParser parser) {
+ final openingFence = _FenceMatch.fromMatch(pattern.firstMatch(
+ escapePunctuation(parser.current.content),
+ )!);
+
+ var text = parseChildLines(
+ parser,
+ openingFence.marker,
+ openingFence.indent,
+ ).map((e) => e.content).join('\n');
+
+ if (parser.document.encodeHtml) {
+ text = escapeHtml(text, escapeApos: false);
+ }
+ if (text.isNotEmpty) {
+ text = '$text\n';
+ }
+
+ final code = Element.text('code', text);
+ if (openingFence.hasLanguage) {
+ var language = decodeHtmlCharacters(openingFence.language);
+ if (parser.document.encodeHtml) {
+ language = escapeHtmlAttribute(language);
+ }
+ code.attributes['class'] = 'language-$language';
+ }
+
+ return Element('pre', [code]);
+ }
+
+ String _removeIndentation(String content, int length) {
+ final text = content.replaceFirst(RegExp('^\\s{0,$length}'), '');
+ return content.substring(content.length - text.length);
+ }
+
+ @override
+ List<Line> parseChildLines(
+ BlockParser parser, [
+ String openingMarker = '',
+ int indent = 0,
+ ]) {
+ final childLines = <Line>[];
+
+ parser.advance();
+
+ _FenceMatch? closingFence;
+ while (!parser.isDone) {
+ final match = pattern.firstMatch(parser.current.content);
+ closingFence = match == null ? null : _FenceMatch.fromMatch(match);
+
+ // Closing code fences cannot have info strings:
+ // https://spec.commonmark.org/0.30/#example-147
+ if (closingFence == null ||
+ !closingFence.marker.startsWith(openingMarker) ||
+ closingFence.hasInfo) {
+ childLines.add(
+ Line(_removeIndentation(parser.current.content, indent)),
+ );
+ parser.advance();
+ } else {
+ parser.advance();
+ break;
+ }
+ }
+
+ // https://spec.commonmark.org/0.30/#example-127
+ // https://spec.commonmark.org/0.30/#example-128
+ if (closingFence == null &&
+ childLines.isNotEmpty &&
+ childLines.last.isBlankLine) {
+ childLines.removeLast();
+ }
+
+ return childLines;
+ }
+}
+
+class _FenceMatch {
+ _FenceMatch._({
+ required this.indent,
+ required this.marker,
+ required this.info,
+ });
+
+ factory _FenceMatch.fromMatch(RegExpMatch match) {
+ String marker;
+ String info;
+
+ if (match.namedGroup('backtick') != null) {
+ marker = match.namedGroup('backtick')!;
+ info = match.namedGroup('backtickInfo')!;
+ } else {
+ marker = match.namedGroup('tilde')!;
+ info = match.namedGroup('tildeInfo')!;
+ }
+
+ return _FenceMatch._(
+ indent: match[1]!.length,
+ marker: marker,
+ info: info.trim(),
+ );
+ }
+
+ final int indent;
+ final String marker;
+
+ // The info-string should be trimmed,
+ // https://spec.commonmark.org/0.30/#info-string.
+ final String info;
+
+ // The first word of the info string is typically used to specify the language
+ // of the code sample,
+ // https://spec.commonmark.org/0.30/#example-143.
+ String get language => info.split(' ').first;
+
+ bool get hasInfo => info.isNotEmpty;
+
+ bool get hasLanguage => language.isNotEmpty;
+}
diff --git a/pkgs/markdown/lib/src/block_syntaxes/footnote_def_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/footnote_def_syntax.dart
new file mode 100644
index 0000000..3e59dcf
--- /dev/null
+++ b/pkgs/markdown/lib/src/block_syntaxes/footnote_def_syntax.dart
@@ -0,0 +1,82 @@
+import '../ast.dart' show Element, Node;
+import '../block_parser.dart' show BlockParser;
+import '../line.dart';
+import '../patterns.dart' show dummyPattern, emptyPattern, footnotePattern;
+import 'block_syntax.dart' show BlockSyntax;
+
+/// The spec of GFM about footnotes is [missing](https://github.com/github/cmark-gfm/issues/283#issuecomment-1378868725).
+/// For online source code of cmark-gfm, see [master@c32ef78](https://github.com/github/cmark-gfm/blob/c32ef78/src/blocks.c#L1212).
+/// A Rust implementation is also [available](https://github.com/wooorm/markdown-rs/blob/2498e31eecead798efc649502bbf5f86feaa94be/src/construct/gfm_footnote_definition.rs).
+/// Footnote definition could contain multiple line-children and children could
+/// be separated by one empty line.
+/// Its first child-line would be the remaining part of the first line after
+/// taking definition leading, combining with other child lines parsed by
+/// [parseChildLines], is fed into [BlockParser].
+class FootnoteDefSyntax extends BlockSyntax {
+ const FootnoteDefSyntax();
+
+ @override
+ RegExp get pattern => footnotePattern;
+
+ @override
+ Node? parse(BlockParser parser) {
+ final current = parser.current.content;
+ final match = pattern.firstMatch(current)!;
+ final label = match[2]!;
+ final refs = parser.document.footnoteReferences;
+ refs[label] = 0;
+
+ final id = Uri.encodeComponent(label);
+ parser.advance();
+ final lines = [
+ Line(current.substring(match[0]!.length)),
+ ...parseChildLines(parser),
+ ];
+ final children = BlockParser(lines, parser.document).parseLines();
+ return Element('li', children)
+ ..attributes['id'] = 'fn-$id'
+ ..footnoteLabel = label;
+ }
+
+ @override
+ List<Line> parseChildLines(BlockParser parser) {
+ final children = <String>[];
+ // As one empty line should not split footnote definition, use this flag.
+ var shouldBeBlock = false;
+ late final syntaxList = parser.blockSyntaxes
+ .where((s) => !_excludingPattern.contains(s.pattern));
+
+ // Every line is footnote's children util two blank lines or a block.
+ while (!parser.isDone) {
+ final line = parser.current.content;
+ if (line.trim().isEmpty) {
+ children.add(line);
+ parser.advance();
+ shouldBeBlock = true;
+ continue;
+ } else if (line.startsWith(' ')) {
+ children.add(line.substring(4));
+ parser.advance();
+ shouldBeBlock = false;
+ } else if (shouldBeBlock || _isBlock(syntaxList, line)) {
+ break;
+ } else {
+ children.add(line);
+ parser.advance();
+ }
+ }
+ return children.map(Line.new).toList(growable: false);
+ }
+
+ /// Patterns that would be used to decide if one line is a block.
+ static final _excludingPattern = {
+ emptyPattern,
+ dummyPattern,
+ };
+
+ /// Whether this line is any kind of block.
+ /// If `true`, the footnote block should end.
+ static bool _isBlock(Iterable<BlockSyntax> syntaxList, String line) {
+ return syntaxList.any((s) => s.pattern.hasMatch(line));
+ }
+}
diff --git a/pkgs/markdown/lib/src/block_syntaxes/header_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/header_syntax.dart
new file mode 100644
index 0000000..197b417
--- /dev/null
+++ b/pkgs/markdown/lib/src/block_syntaxes/header_syntax.dart
@@ -0,0 +1,47 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../ast.dart';
+import '../block_parser.dart';
+import '../patterns.dart';
+import 'block_syntax.dart';
+
+/// Parses atx-style headers: `## Header ##`.
+class HeaderSyntax extends BlockSyntax {
+ @override
+ RegExp get pattern => headerPattern;
+
+ const HeaderSyntax();
+
+ @override
+ Node parse(BlockParser parser) {
+ final match = pattern.firstMatch(parser.current.content)!;
+ final matchedText = match[0]!;
+ final openMarker = match[1]!;
+ final closeMarker = match[2];
+ final level = openMarker.length;
+ final openMarkerStart = matchedText.indexOf(openMarker);
+ final openMarkerEnd = openMarkerStart + level;
+
+ String? content;
+ if (closeMarker == null) {
+ content = parser.current.content.substring(openMarkerEnd);
+ } else {
+ final closeMarkerStart = matchedText.lastIndexOf(closeMarker);
+ content = parser.current.content.substring(
+ openMarkerEnd,
+ closeMarkerStart,
+ );
+ }
+ content = content.trim();
+
+ // https://spec.commonmark.org/0.30/#example-79
+ if (closeMarker == null && RegExp(r'^#+$').hasMatch(content)) {
+ content = null;
+ }
+
+ parser.advance();
+ return Element('h$level', [if (content != null) UnparsedContent(content)]);
+ }
+}
diff --git a/pkgs/markdown/lib/src/block_syntaxes/header_with_id_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/header_with_id_syntax.dart
new file mode 100644
index 0000000..8e2c50b
--- /dev/null
+++ b/pkgs/markdown/lib/src/block_syntaxes/header_with_id_syntax.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../ast.dart';
+import '../block_parser.dart';
+import 'block_syntax.dart';
+import 'header_syntax.dart';
+
+/// Parses atx-style headers, and adds generated IDs to the generated elements.
+class HeaderWithIdSyntax extends HeaderSyntax {
+ const HeaderWithIdSyntax();
+
+ @override
+ Node parse(BlockParser parser) {
+ final element = super.parse(parser) as Element;
+
+ if (element.children?.isNotEmpty ?? false) {
+ element.generatedId = BlockSyntax.generateAnchorHash(element);
+ }
+
+ return element;
+ }
+}
diff --git a/pkgs/markdown/lib/src/block_syntaxes/horizontal_rule_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/horizontal_rule_syntax.dart
new file mode 100644
index 0000000..12e7839
--- /dev/null
+++ b/pkgs/markdown/lib/src/block_syntaxes/horizontal_rule_syntax.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../ast.dart';
+import '../block_parser.dart';
+import '../patterns.dart';
+import 'block_syntax.dart';
+
+/// Parses horizontal rules like `---`, `_ _ _`, `* * *`, etc.
+class HorizontalRuleSyntax extends BlockSyntax {
+ @override
+ RegExp get pattern => hrPattern;
+
+ const HorizontalRuleSyntax();
+
+ @override
+ Node parse(BlockParser parser) {
+ parser.advance();
+ return Element.empty('hr');
+ }
+}
diff --git a/pkgs/markdown/lib/src/block_syntaxes/html_block_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/html_block_syntax.dart
new file mode 100644
index 0000000..c1aa85c
--- /dev/null
+++ b/pkgs/markdown/lib/src/block_syntaxes/html_block_syntax.dart
@@ -0,0 +1,99 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../ast.dart';
+import '../block_parser.dart';
+import '../line.dart';
+import '../patterns.dart';
+import 'block_syntax.dart';
+import 'list_syntax.dart';
+
+/// Parse HTML blocks.
+// There are seven kinds of HTML block defined in the CommonMark spec:
+// https://spec.commonmark.org/0.30/#html-blocks.
+// These matching conditions and HTML block types mentioned in this syntax
+// correspond to these ones in the CommonMark spec.
+class HtmlBlockSyntax extends BlockSyntax {
+ @override
+ RegExp get pattern => htmlBlockPattern;
+
+ // All types of HTML blocks except type 7 may interrupt a paragraph, see the
+ // second paragraph after https://spec.commonmark.org/0.30/#example-148 for
+ // more detail.
+ @override
+ bool canEndBlock(BlockParser parser) =>
+ pattern.firstMatch(parser.current.content)!.namedGroup('condition_7') ==
+ null;
+
+ static final _endConditions = [
+ // For condition 1, it does not need to match the start tag, see
+ // https://spec.commonmark.org/0.30/#end-condition
+ RegExp('</(?:pre|script|style|textarea)>', caseSensitive: false),
+ RegExp('-->'),
+ RegExp(r'\?>'),
+ RegExp('>'),
+ RegExp(']]>'),
+ emptyPattern,
+ emptyPattern,
+ ];
+
+ const HtmlBlockSyntax();
+
+ @override
+ List<Line> parseChildLines(BlockParser parser) {
+ final lines = <Line>[];
+
+ final match = pattern.firstMatch(parser.current.content);
+ var matchedCondition = 0;
+ for (var i = 0; i < match!.groupCount; i++) {
+ if (match.group(i + 1) != null) {
+ matchedCondition = i;
+ break;
+ }
+ }
+
+ final endCondition = _endConditions[matchedCondition];
+ if (endCondition == emptyPattern) {
+ lines.add(parser.current);
+ parser.advance();
+
+ while (!parser.isDone && !endCondition.hasMatch(parser.current.content)) {
+ lines.add(parser.current);
+ parser.advance();
+ }
+ } else {
+ while (!parser.isDone) {
+ lines.add(parser.current);
+ if (endCondition.hasMatch(parser.current.content)) {
+ break;
+ }
+ parser.advance();
+ }
+ parser.advance();
+ }
+
+ // If the current line start an HTML block again, put them together with
+ // the previous HTML block.
+ if (!parser.isDone && pattern.hasMatch(parser.current.content)) {
+ lines.addAll(parseChildLines(parser));
+ }
+
+ return lines;
+ }
+
+ @override
+ Node parse(BlockParser parser) {
+ final childLines = parseChildLines(parser);
+
+ var text = childLines.map((e) => e.content).join('\n').trimRight();
+ if (parser.previousSyntax != null || parser.parentSyntax != null) {
+ text = '\n$text';
+ if (parser.parentSyntax is ListSyntax) {
+ text = '$text\n';
+ }
+ }
+
+ return Text(text);
+ }
+}
diff --git a/pkgs/markdown/lib/src/block_syntaxes/link_reference_definition_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/link_reference_definition_syntax.dart
new file mode 100644
index 0000000..5b2b1b5
--- /dev/null
+++ b/pkgs/markdown/lib/src/block_syntaxes/link_reference_definition_syntax.dart
@@ -0,0 +1,65 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../ast.dart';
+import '../block_parser.dart';
+import '../document.dart';
+import '../line.dart';
+import '../link_parser.dart';
+import '../patterns.dart';
+import '../util.dart';
+import 'block_syntax.dart';
+
+class LinkReferenceDefinitionSyntax extends BlockSyntax {
+ @override
+ RegExp get pattern => linkReferenceDefinitionPattern;
+
+ @override
+ bool canEndBlock(BlockParser parser) => false;
+
+ const LinkReferenceDefinitionSyntax();
+
+ @override
+ Node? parse(BlockParser parser) {
+ final lines = <Line>[parser.current];
+ parser.advance();
+
+ while (!BlockSyntax.isAtBlockEnd(parser)) {
+ lines.add(parser.current);
+ parser.advance();
+ }
+
+ if (!_parseLinkReferenceDefinition(lines, parser)) {
+ parser.retreatBy(lines.length);
+ }
+
+ return null;
+ }
+
+ bool _parseLinkReferenceDefinition(List<Line> lines, BlockParser parser) {
+ final linkParser = LinkParser(lines.map((e) => e.content).join('\n'))
+ ..parseDefinition();
+
+ if (!linkParser.valid) {
+ return false;
+ }
+
+ // Retreat the parsing position back to where the link reference definition
+ // ends, so that the next syntax can continue parsing from there.
+ parser.retreatBy(linkParser.unconsumedLines);
+
+ final labelString = normalizeLinkLabel(linkParser.label!);
+
+ parser.document.linkReferences.putIfAbsent(
+ labelString,
+ () => LinkReference(
+ labelString,
+ linkParser.destination!,
+ linkParser.title,
+ ),
+ );
+
+ return true;
+ }
+}
diff --git a/pkgs/markdown/lib/src/block_syntaxes/list_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/list_syntax.dart
new file mode 100644
index 0000000..534ca3e
--- /dev/null
+++ b/pkgs/markdown/lib/src/block_syntaxes/list_syntax.dart
@@ -0,0 +1,353 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../ast.dart';
+import '../block_parser.dart';
+import '../charcode.dart';
+import '../line.dart';
+import '../patterns.dart';
+import '../text_parser.dart';
+import '../util.dart';
+import 'block_syntax.dart';
+import 'ordered_list_with_checkbox_syntax.dart';
+import 'unordered_list_with_checkbox_syntax.dart';
+
+class ListItem {
+ const ListItem(
+ this.lines, {
+ this.taskListItemState,
+ });
+
+ final List<Line> lines;
+ final TaskListItemState? taskListItemState;
+}
+
+enum TaskListItemState { checked, unchecked }
+
+/// Base class for both ordered and unordered lists.
+abstract class ListSyntax extends BlockSyntax {
+ @override
+ bool canParse(BlockParser parser) =>
+ pattern.hasMatch(parser.current.content) &&
+ !hrPattern.hasMatch(parser.current.content);
+
+ @override
+ bool canEndBlock(BlockParser parser) {
+ // An empty list cannot interrupt a paragraph. See
+ // https://spec.commonmark.org/0.30/#example-285.
+ // Ideally, [BlockSyntax.canEndBlock] should be changed to be a method
+ // which accepts a [BlockParser], but this would be a breaking change,
+ // so we're going with this temporarily.
+ final match = pattern.firstMatch(parser.current.content)!;
+
+ // Allow only lists starting with 1 to interrupt paragraphs, if it is an
+ // ordered list. See https://spec.commonmark.org/0.30/#example-304.
+ // But there should be an exception for nested ordered lists, for example:
+ // ```
+ // 1. one
+ // 2. two
+ // 3. three
+ // 4. four
+ // 5. five
+ // ```
+ if (parser.parentSyntax is! ListSyntax &&
+ match[1] != null &&
+ match[1] != '1') {
+ return false;
+ }
+
+ // An empty list item cannot interrupt a paragraph. See
+ // https://spec.commonmark.org/0.30/#example-285
+ return match[2]?.isNotEmpty ?? false;
+ }
+
+ const ListSyntax();
+
+ /// A list of patterns that can start a valid block within a list item.
+ static final blocksInList = [
+ blockquotePattern,
+ headerPattern,
+ hrPattern,
+ indentPattern,
+ listPattern,
+ ];
+
+ @override
+ Node parse(BlockParser parser) {
+ final match = pattern.firstMatch(parser.current.content);
+ final ordered = match![1] != null;
+
+ final taskListParserEnabled = this is UnorderedListWithCheckboxSyntax ||
+ this is OrderedListWithCheckboxSyntax;
+ final items = <ListItem>[];
+ var childLines = <Line>[];
+ TaskListItemState? taskListItemState;
+
+ void endItem() {
+ if (childLines.isNotEmpty) {
+ items.add(ListItem(childLines, taskListItemState: taskListItemState));
+ childLines = <Line>[];
+ }
+ }
+
+ String parseTaskListItem(String text) {
+ final pattern = RegExp(r'^ {0,3}\[([ xX])\][ \t]');
+
+ if (taskListParserEnabled && pattern.hasMatch(text)) {
+ return text.replaceFirstMapped(pattern, (match) {
+ taskListItemState = match[1] == ' '
+ ? TaskListItemState.unchecked
+ : TaskListItemState.checked;
+
+ return '';
+ });
+ } else {
+ taskListItemState = null;
+ return text;
+ }
+ }
+
+ late Match? possibleMatch;
+ bool tryMatch(RegExp pattern) {
+ possibleMatch = pattern.firstMatch(parser.current.content);
+ return possibleMatch != null;
+ }
+
+ String? listMarker;
+ int? indent;
+ // In case the first number in an ordered list is not 1, use it as the
+ // "start".
+ int? startNumber;
+
+ int? blankLines;
+
+ while (!parser.isDone) {
+ final currentIndent = parser.current.content.indentation() +
+ (parser.current.tabRemaining ?? 0);
+
+ if (parser.current.isBlankLine) {
+ childLines.add(parser.current);
+
+ if (blankLines != null) {
+ blankLines++;
+ }
+ } else if (indent != null && indent <= currentIndent) {
+ // A list item can begin with at most one blank line. See:
+ // https://spec.commonmark.org/0.30/#example-280
+ if (blankLines != null && blankLines > 1) {
+ break;
+ }
+
+ final indentedLine = parser.current.content.dedent(indent);
+
+ childLines.add(Line(
+ blankLines == null
+ ? indentedLine.text
+ : parseTaskListItem(indentedLine.text),
+ tabRemaining: indentedLine.tabRemaining,
+ ));
+ } else if (tryMatch(hrPattern)) {
+ // Horizontal rule takes precedence to a new list item.
+ break;
+ } else if (tryMatch(listPattern)) {
+ blankLines = null;
+ final match = possibleMatch!;
+ final textParser = TextParser(parser.current.content);
+ var precedingWhitespaces = textParser.moveThroughWhitespace();
+ final markerStart = textParser.pos;
+ final digits = match[1] ?? '';
+ if (digits.isNotEmpty) {
+ startNumber ??= int.parse(digits);
+ textParser.advanceBy(digits.length);
+ }
+ textParser.advance();
+
+ // See https://spec.commonmark.org/0.30/#ordered-list-marker
+ final marker = textParser.substring(
+ markerStart,
+ textParser.pos,
+ );
+
+ var isBlank = true;
+ var contentWhitespances = 0;
+ var containsTab = false;
+ int? contentBlockStart;
+
+ if (!textParser.isDone) {
+ containsTab = textParser.charAt() == $tab;
+ // Skip the first whitespace.
+ textParser.advance();
+ contentBlockStart = textParser.pos;
+ if (!textParser.isDone) {
+ contentWhitespances = textParser.moveThroughWhitespace();
+
+ if (!textParser.isDone) {
+ isBlank = false;
+ }
+ }
+ }
+
+ // Changing the bullet or ordered list delimiter starts a new list.
+ if (listMarker != null && listMarker.last() != marker.last()) {
+ break;
+ }
+
+ // End the current list item and start a new one.
+ endItem();
+
+ // Start a new list item, the last item will be ended up outside of the
+ // `while` loop.
+ listMarker = marker;
+ precedingWhitespaces += digits.length + 2;
+ if (isBlank) {
+ // See https://spec.commonmark.org/0.30/#example-278.
+ blankLines = 1;
+ indent = precedingWhitespaces;
+ } else if (contentWhitespances >= 4) {
+ // See https://spec.commonmark.org/0.30/#example-270.
+ //
+ // If the list item starts with indented code, we need to _not_ count
+ // any indentation past the required whitespace character.
+ indent = precedingWhitespaces;
+ } else {
+ indent = precedingWhitespaces + contentWhitespances;
+ }
+
+ taskListItemState = null;
+ var content = contentBlockStart != null && !isBlank
+ ? parseTaskListItem(textParser.substring(contentBlockStart))
+ : '';
+
+ if (content.isEmpty && containsTab) {
+ content = content.prependSpace(2);
+ }
+
+ childLines.add(Line(
+ content,
+ tabRemaining: containsTab ? 2 : null,
+ ));
+ } else if (BlockSyntax.isAtBlockEnd(parser)) {
+ // Done with the list.
+ break;
+ } else {
+ // If the previous item is a blank line, this means we're done with the
+ // list and are starting a new top-level paragraph.
+ if (childLines.isNotEmpty && childLines.last.isBlankLine) {
+ parser.encounteredBlankLine = true;
+ break;
+ }
+
+ // Anything else is paragraph continuation text.
+ childLines.add(parser.current);
+ }
+ parser.advance();
+ }
+
+ endItem();
+ final itemNodes = <Element>[];
+
+ items.forEach(_removeLeadingEmptyLine);
+ final anyEmptyLines = _removeTrailingEmptyLines(items);
+ var anyEmptyLinesBetweenBlocks = false;
+ var containsTaskList = false;
+ const taskListClass = 'task-list-item';
+
+ for (final item in items) {
+ Element? checkboxToInsert;
+ if (item.taskListItemState != null) {
+ containsTaskList = true;
+ checkboxToInsert = Element.withTag('input')
+ ..attributes['type'] = 'checkbox';
+ if (item.taskListItemState == TaskListItemState.checked) {
+ checkboxToInsert.attributes['checked'] = 'true';
+ }
+ }
+
+ final itemParser = BlockParser(item.lines, parser.document);
+ final children = itemParser.parseLines(parentSyntax: this);
+ final itemElement = checkboxToInsert == null
+ ? Element('li', children)
+ : (Element('li', _addCheckbox(children, checkboxToInsert))
+ ..attributes['class'] = taskListClass);
+
+ itemNodes.add(itemElement);
+ anyEmptyLinesBetweenBlocks =
+ anyEmptyLinesBetweenBlocks || itemParser.encounteredBlankLine;
+ }
+
+ // Must strip paragraph tags if the list is "tight".
+ // https://spec.commonmark.org/0.30/#lists
+ final listIsTight = !anyEmptyLines && !anyEmptyLinesBetweenBlocks;
+
+ if (listIsTight) {
+ // We must post-process the list items, converting any top-level paragraph
+ // elements to just text elements.
+ for (final item in itemNodes) {
+ final isTaskList = item.attributes['class'] == taskListClass;
+ final children = item.children;
+ if (children != null) {
+ Node? lastNode;
+ for (var i = 0; i < children.length; i++) {
+ final child = children[i];
+ if (child is Element && child.tag == 'p') {
+ final childContent = child.children!;
+ if (lastNode is Element && !isTaskList) {
+ childContent.insert(0, Text('\n'));
+ }
+
+ children
+ ..removeAt(i)
+ ..insertAll(i, childContent);
+ }
+
+ lastNode = child;
+ }
+ }
+ }
+ }
+
+ final listElement = Element(ordered ? 'ol' : 'ul', itemNodes);
+ if (ordered && startNumber != 1) {
+ listElement.attributes['start'] = '$startNumber';
+ }
+
+ if (containsTaskList) {
+ listElement.attributes['class'] = 'contains-task-list';
+ }
+ return listElement;
+ }
+
+ List<Node> _addCheckbox(List<Node> children, Element checkbox) {
+ if (children.isNotEmpty) {
+ final firstChild = children.first;
+ if (firstChild is Element && firstChild.tag == 'p') {
+ firstChild.children!.insert(0, checkbox);
+ return children;
+ }
+ }
+ return [checkbox, ...children];
+ }
+
+ void _removeLeadingEmptyLine(ListItem item) {
+ if (item.lines.isNotEmpty && item.lines.first.isBlankLine) {
+ item.lines.removeAt(0);
+ }
+ }
+
+ /// Removes any trailing empty lines and notes whether any items are separated
+ /// by such lines.
+ bool _removeTrailingEmptyLines(List<ListItem> items) {
+ var anyEmpty = false;
+ for (var i = 0; i < items.length; i++) {
+ if (items[i].lines.length == 1) continue;
+ while (items[i].lines.isNotEmpty && items[i].lines.last.isBlankLine) {
+ if (i < items.length - 1) {
+ anyEmpty = true;
+ }
+ items[i].lines.removeLast();
+ }
+ }
+ return anyEmpty;
+ }
+}
diff --git a/pkgs/markdown/lib/src/block_syntaxes/ordered_list_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/ordered_list_syntax.dart
new file mode 100644
index 0000000..53c4730
--- /dev/null
+++ b/pkgs/markdown/lib/src/block_syntaxes/ordered_list_syntax.dart
@@ -0,0 +1,14 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../patterns.dart';
+import 'list_syntax.dart';
+
+/// Parses ordered lists.
+class OrderedListSyntax extends ListSyntax {
+ @override
+ RegExp get pattern => listPattern;
+
+ const OrderedListSyntax();
+}
diff --git a/pkgs/markdown/lib/src/block_syntaxes/ordered_list_with_checkbox_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/ordered_list_with_checkbox_syntax.dart
new file mode 100644
index 0000000..8d865e8
--- /dev/null
+++ b/pkgs/markdown/lib/src/block_syntaxes/ordered_list_with_checkbox_syntax.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'ordered_list_syntax.dart';
+
+/// Parses ordered lists with checkboxes.
+class OrderedListWithCheckboxSyntax extends OrderedListSyntax {
+ const OrderedListWithCheckboxSyntax();
+}
diff --git a/pkgs/markdown/lib/src/block_syntaxes/paragraph_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/paragraph_syntax.dart
new file mode 100644
index 0000000..53d496d
--- /dev/null
+++ b/pkgs/markdown/lib/src/block_syntaxes/paragraph_syntax.dart
@@ -0,0 +1,49 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../ast.dart';
+import '../block_parser.dart';
+import '../patterns.dart';
+import 'block_syntax.dart';
+import 'setext_header_syntax.dart';
+
+/// Parses paragraphs of regular text.
+class ParagraphSyntax extends BlockSyntax {
+ @override
+ RegExp get pattern => dummyPattern;
+
+ @override
+ bool canEndBlock(BlockParser parser) => false;
+
+ const ParagraphSyntax();
+
+ @override
+ bool canParse(BlockParser parser) => true;
+
+ @override
+ Node? parse(BlockParser parser) {
+ final childLines = <String>[parser.current.content];
+
+ parser.advance();
+ var interruptedBySetextHeading = false;
+ // Eat until we hit something that ends a paragraph.
+ while (!parser.isDone) {
+ final syntax = interruptedBy(parser);
+ if (syntax != null) {
+ interruptedBySetextHeading = syntax is SetextHeaderSyntax;
+ break;
+ }
+ childLines.add(parser.current.content);
+ parser.advance();
+ }
+
+ // It is not a paragraph, but a setext heading.
+ if (interruptedBySetextHeading) {
+ return null;
+ }
+
+ final contents = UnparsedContent(childLines.join('\n').trimRight());
+ return Element('p', [contents]);
+ }
+}
diff --git a/pkgs/markdown/lib/src/block_syntaxes/setext_header_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/setext_header_syntax.dart
new file mode 100644
index 0000000..49f4eda
--- /dev/null
+++ b/pkgs/markdown/lib/src/block_syntaxes/setext_header_syntax.dart
@@ -0,0 +1,44 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../ast.dart';
+import '../block_parser.dart';
+import '../patterns.dart';
+import 'block_syntax.dart';
+import 'paragraph_syntax.dart';
+
+/// Parses setext-style headers.
+class SetextHeaderSyntax extends BlockSyntax {
+ @override
+ RegExp get pattern => setextPattern;
+
+ const SetextHeaderSyntax();
+
+ @override
+ bool canParse(BlockParser parser) {
+ final lastSyntax = parser.currentSyntax;
+ if (parser.setextHeadingDisabled || lastSyntax is! ParagraphSyntax) {
+ return false;
+ }
+ return pattern.hasMatch(parser.current.content);
+ }
+
+ @override
+ Node? parse(BlockParser parser) {
+ final lines = parser.linesToConsume;
+ if (lines.length < 2) {
+ return null;
+ }
+
+ // Remove the last line which is a marker.
+ lines.removeLast();
+
+ final marker = parser.current.content.trim();
+ final level = (marker[0] == '=') ? '1' : '2';
+ final content = lines.map((e) => e.content).join('\n').trimRight();
+
+ parser.advance();
+ return Element('h$level', [UnparsedContent(content)]);
+ }
+}
diff --git a/pkgs/markdown/lib/src/block_syntaxes/setext_header_with_id_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/setext_header_with_id_syntax.dart
new file mode 100644
index 0000000..fffe992
--- /dev/null
+++ b/pkgs/markdown/lib/src/block_syntaxes/setext_header_with_id_syntax.dart
@@ -0,0 +1,21 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../ast.dart';
+import '../block_parser.dart';
+import 'block_syntax.dart';
+import 'setext_header_syntax.dart';
+
+/// Parses setext-style headers, and adds generated IDs to the generated
+/// elements.
+class SetextHeaderWithIdSyntax extends SetextHeaderSyntax {
+ const SetextHeaderWithIdSyntax();
+
+ @override
+ Node parse(BlockParser parser) {
+ final element = super.parse(parser) as Element;
+ element.generatedId = BlockSyntax.generateAnchorHash(element);
+ return element;
+ }
+}
diff --git a/pkgs/markdown/lib/src/block_syntaxes/table_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/table_syntax.dart
new file mode 100644
index 0000000..89cbd90
--- /dev/null
+++ b/pkgs/markdown/lib/src/block_syntaxes/table_syntax.dart
@@ -0,0 +1,225 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../ast.dart';
+import '../block_parser.dart';
+import '../charcode.dart';
+import '../patterns.dart';
+import 'block_syntax.dart';
+
+/// Parses tables.
+class TableSyntax extends BlockSyntax {
+ @override
+ bool canEndBlock(BlockParser parser) => true;
+
+ @override
+ RegExp get pattern => dummyPattern;
+
+ const TableSyntax();
+
+ @override
+ bool canParse(BlockParser parser) {
+ // Note: matches *next* line, not the current one. We're looking for the
+ // bar separating the head row from the body rows.
+ return parser.matchesNext(tablePattern);
+ }
+
+ /// Parses a table into its three parts:
+ ///
+ /// * a head row of head cells (`<th>` cells)
+ /// * a divider of hyphens and pipes (not rendered)
+ /// * many body rows of body cells (`<td>` cells)
+ @override
+ Node? parse(BlockParser parser) {
+ final alignments = _parseAlignments(parser.next!.content);
+ final columnCount = alignments.length;
+ final headRow = _parseRow(parser, alignments, 'th');
+ if (headRow.children!.length != columnCount) {
+ parser.retreat();
+ return null;
+ }
+ final head = Element('thead', [headRow]);
+
+ // Advance past the divider of hyphens.
+ parser.advance();
+
+ final rows = <Element>[];
+ while (!parser.isDone && !BlockSyntax.isAtBlockEnd(parser)) {
+ final row = _parseRow(parser, alignments, 'td');
+ final children = row.children;
+ if (children != null) {
+ while (children.length < columnCount) {
+ // Insert synthetic empty cells.
+ children.add(Element('td', []));
+ }
+ while (children.length > columnCount) {
+ children.removeLast();
+ }
+ }
+ while (row.children!.length > columnCount) {
+ row.children!.removeLast();
+ }
+ rows.add(row);
+ }
+ if (rows.isEmpty) {
+ return Element('table', [head]);
+ } else {
+ final body = Element('tbody', rows);
+
+ return Element('table', [head, body]);
+ }
+ }
+
+ List<String?> _parseAlignments(String line) {
+ final columns = <String?>[];
+ // Set the value to `true` when hitting a non whitespace character other
+ // than the first pipe character.
+ var started = false;
+ var hitDash = false;
+ String? alignment;
+
+ for (var i = 0; i < line.length; i++) {
+ final char = line.codeUnitAt(i);
+ if (char == $space || char == $tab || (!started && char == $pipe)) {
+ continue;
+ }
+ started = true;
+
+ if (char == $colon) {
+ if (hitDash) {
+ alignment = alignment == 'left' ? 'center' : 'right';
+ } else {
+ alignment = 'left';
+ }
+ }
+
+ if (char == $pipe) {
+ columns.add(alignment);
+ hitDash = false;
+ alignment = null;
+ } else {
+ hitDash = true;
+ }
+ }
+
+ if (hitDash) {
+ columns.add(alignment);
+ }
+
+ return columns;
+ }
+
+ /// Parses a table row at the current line into a table row element, with
+ /// parsed table cells.
+ ///
+ /// [alignments] is used to annotate an alignment on each cell, and
+ /// [cellType] is used to declare either "td" or "th" cells.
+ Element _parseRow(
+ BlockParser parser,
+ List<String?> alignments,
+ String cellType,
+ ) {
+ final line = parser.current;
+ final cells = <String>[];
+ var index = _walkPastOpeningPipe(line.content);
+ final cellBuffer = StringBuffer();
+
+ while (true) {
+ if (index >= line.content.length) {
+ // This row ended without a trailing pipe, which is fine.
+ cells.add(cellBuffer.toString().trimRight());
+ cellBuffer.clear();
+ break;
+ }
+ final ch = line.content.codeUnitAt(index);
+ if (ch == $backslash) {
+ if (index == line.content.length - 1) {
+ // A table row ending in a backslash is not well-specified, but it
+ // looks like GitHub just allows the character as part of the text of
+ // the last cell.
+ cellBuffer.writeCharCode(ch);
+ cells.add(cellBuffer.toString().trimRight());
+ cellBuffer.clear();
+ break;
+ }
+ final escaped = line.content.codeUnitAt(index + 1);
+ if (escaped == $pipe) {
+ // GitHub Flavored Markdown has a strange bit here; the pipe is to be
+ // escaped before any other inline processing. One consequence, for
+ // example, is that "| `\|` |" should be parsed as a cell with a code
+ // element with text "|", rather than "\|". Most parsers are not
+ // compliant with this corner, but this is what is specified, and what
+ // GitHub does in practice.
+ cellBuffer.writeCharCode(escaped);
+ } else {
+ // The [InlineParser] will handle the escaping.
+ cellBuffer.writeCharCode(ch);
+ cellBuffer.writeCharCode(escaped);
+ }
+ index += 2;
+ } else if (ch == $pipe) {
+ cells.add(cellBuffer.toString().trimRight());
+ cellBuffer.clear();
+ // Walk forward past any whitespace which leads the next cell.
+ index++;
+ index = _walkPastWhitespace(line.content, index);
+ if (index >= line.content.length) {
+ // This row ended with a trailing pipe.
+ break;
+ }
+ } else {
+ cellBuffer.writeCharCode(ch);
+ index++;
+ }
+ }
+ parser.advance();
+ final row = [
+ for (final cell in cells) Element(cellType, [UnparsedContent(cell)])
+ ];
+
+ for (var i = 0; i < row.length && i < alignments.length; i++) {
+ if (alignments[i] == null) continue;
+ row[i].attributes['align'] = '${alignments[i]}';
+ }
+
+ return Element('tr', row);
+ }
+
+ /// Walks past whitespace in [line] starting at [index].
+ ///
+ /// Returns the index of the first non-whitespace character.
+ int _walkPastWhitespace(String line, int index) {
+ while (index < line.length) {
+ final ch = line.codeUnitAt(index);
+ if (ch != $space && ch != $tab) {
+ break;
+ }
+ index++;
+ }
+ return index;
+ }
+
+ /// Walks past the opening pipe (and any whitespace that surrounds it) in
+ /// [line].
+ ///
+ /// Returns the index of the first non-whitespace character after the pipe.
+ /// If no opening pipe is found, this just returns the index of the first
+ /// non-whitespace character.
+ int _walkPastOpeningPipe(String line) {
+ var index = 0;
+ while (index < line.length) {
+ final ch = line.codeUnitAt(index);
+ if (ch == $pipe) {
+ index++;
+ index = _walkPastWhitespace(line, index);
+ }
+ if (ch != $space && ch != $tab) {
+ // No leading pipe.
+ break;
+ }
+ index++;
+ }
+ return index;
+ }
+}
diff --git a/pkgs/markdown/lib/src/block_syntaxes/unordered_list_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/unordered_list_syntax.dart
new file mode 100644
index 0000000..35dd670
--- /dev/null
+++ b/pkgs/markdown/lib/src/block_syntaxes/unordered_list_syntax.dart
@@ -0,0 +1,30 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../block_parser.dart';
+import '../patterns.dart';
+import 'list_syntax.dart';
+
+/// Parses unordered lists.
+class UnorderedListSyntax extends ListSyntax {
+ @override
+ RegExp get pattern => listPattern;
+
+ @override
+ bool canParse(BlockParser parser) {
+ // Check if it matches `hrPattern`, otherwise it will produce an infinite
+ // loop if put `UnorderedListSyntax` or `UnorderedListWithCheckboxSyntax`
+ // bofore `HorizontalRuleSyntax` and parse:
+ // ```
+ // * * *
+ // ```
+ if (hrPattern.hasMatch(parser.current.content)) {
+ return false;
+ }
+
+ return pattern.hasMatch(parser.current.content);
+ }
+
+ const UnorderedListSyntax();
+}
diff --git a/pkgs/markdown/lib/src/block_syntaxes/unordered_list_with_checkbox_syntax.dart b/pkgs/markdown/lib/src/block_syntaxes/unordered_list_with_checkbox_syntax.dart
new file mode 100644
index 0000000..5f3ddf0
--- /dev/null
+++ b/pkgs/markdown/lib/src/block_syntaxes/unordered_list_with_checkbox_syntax.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'unordered_list_syntax.dart';
+
+/// Parses unordered lists with checkboxes.
+class UnorderedListWithCheckboxSyntax extends UnorderedListSyntax {
+ const UnorderedListWithCheckboxSyntax();
+}
diff --git a/pkgs/markdown/lib/src/charcode.dart b/pkgs/markdown/lib/src/charcode.dart
new file mode 100644
index 0000000..693fcc5
--- /dev/null
+++ b/pkgs/markdown/lib/src/charcode.dart
@@ -0,0 +1,123 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+/// "Horizontal Tab" control character, common name.
+const int $tab = 0x09;
+
+/// "Line feed" control character.
+const int $lf = 0x0A;
+
+/// "Vertical Tab" control character.
+const int $vt = 0x0B;
+
+/// "Form feed" control character.
+const int $ff = 0x0C;
+
+/// "Carriage return" control character.
+const int $cr = 0x0D;
+
+/// Space character.
+const int $space = 0x20;
+
+/// Character `!`.
+const int $exclamation = 0x21;
+
+/// Character `"`.
+const int $quote = 0x22;
+
+/// Character `"`.
+const int $double_quote = 0x22; // ignore: constant_identifier_names
+
+/// Character `#`.
+const int $hash = 0x23;
+
+/// Character `$`.
+const int $dollar = 0x24;
+
+/// Character `%`.
+const int $percent = 0x25;
+
+/// Character `&`.
+const int $ampersand = 0x26;
+
+/// Character `'`.
+const int $apostrophe = 0x27;
+
+/// Character `(`.
+const int $lparen = 0x28;
+
+/// Character `)`.
+const int $rparen = 0x29;
+
+/// Character `*`.
+const int $asterisk = 0x2A;
+
+/// Character `+`.
+const int $plus = 0x2B;
+
+/// Character `,`.
+const int $comma = 0x2C;
+
+/// Character `-`.
+const int $dash = 0x2D;
+
+/// Character `.`.
+const int $dot = 0x2E;
+
+/// Character `/`.
+const int $slash = 0x2F;
+
+/// Character `:`.
+const int $colon = 0x3A;
+
+/// Character `;`.
+const int $semicolon = 0x3B;
+
+/// Character `<`.
+const int $lt = 0x3C;
+
+/// Character `=`.
+const int $equal = 0x3D;
+
+/// Character `>`.
+const int $gt = 0x3E;
+
+/// Character `?`.
+const int $question = 0x3F;
+
+/// Character `@`.
+const int $at = 0x40;
+
+/// Character `[`.
+const int $lbracket = 0x5B;
+
+/// Character `\`.
+const int $backslash = 0x5C;
+
+/// Character `]`.
+const int $rbracket = 0x5D;
+
+/// Character `^`.
+const int $caret = 0x5E;
+
+/// Character `_`.
+const int $underscore = 0x5F;
+
+/// Character `` ` ``.
+const int $backquote = 0x60;
+
+/// Character `{`.
+const int $lbrace = 0x7B;
+
+/// Character `|`.
+const int $pipe = 0x7C;
+
+/// Character `|`.
+const int $bar = 0x7C;
+
+/// Character `}`.
+const int $rbrace = 0x7D;
+
+/// Character `~`.
+const int $tilde = 0x7E;
diff --git a/pkgs/markdown/lib/src/document.dart b/pkgs/markdown/lib/src/document.dart
new file mode 100644
index 0000000..f33ff33
--- /dev/null
+++ b/pkgs/markdown/lib/src/document.dart
@@ -0,0 +1,217 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'ast.dart';
+import 'block_parser.dart';
+import 'block_syntaxes/block_syntax.dart';
+import 'extension_set.dart';
+import 'inline_parser.dart';
+import 'inline_syntaxes/inline_syntax.dart';
+import 'line.dart';
+import 'util.dart';
+
+/// Maintains the context needed to parse a Markdown document.
+class Document {
+ final Map<String, LinkReference> linkReferences = {};
+
+ /// Footnote ref count, keys are case-sensitive and added by define syntax.
+ final footnoteReferences = <String, int>{};
+
+ /// Footnote labels by appearing order.
+ ///
+ /// They are case-insensitive and added by ref syntax.
+ final footnoteLabels = <String>[];
+ final Resolver? linkResolver;
+ final Resolver? imageLinkResolver;
+ final bool encodeHtml;
+
+ /// Whether to use default block syntaxes.
+ final bool withDefaultBlockSyntaxes;
+
+ /// Whether to use default inline syntaxes.
+ ///
+ /// Need to set both [withDefaultInlineSyntaxes] and [encodeHtml] to
+ /// `false` to disable all inline syntaxes including html encoding syntaxes.
+ final bool withDefaultInlineSyntaxes;
+
+ final _blockSyntaxes = <BlockSyntax>{};
+ final _inlineSyntaxes = <InlineSyntax>{};
+ final bool hasCustomInlineSyntaxes;
+
+ Iterable<BlockSyntax> get blockSyntaxes => _blockSyntaxes;
+
+ Iterable<InlineSyntax> get inlineSyntaxes => _inlineSyntaxes;
+
+ Document({
+ Iterable<BlockSyntax>? blockSyntaxes,
+ Iterable<InlineSyntax>? inlineSyntaxes,
+ ExtensionSet? extensionSet,
+ this.linkResolver,
+ this.imageLinkResolver,
+ this.encodeHtml = true,
+ this.withDefaultBlockSyntaxes = true,
+ this.withDefaultInlineSyntaxes = true,
+ }) : hasCustomInlineSyntaxes = (inlineSyntaxes?.isNotEmpty ?? false) ||
+ (extensionSet?.inlineSyntaxes.isNotEmpty ?? false) {
+ if (blockSyntaxes != null) {
+ _blockSyntaxes.addAll(blockSyntaxes);
+ }
+ if (inlineSyntaxes != null) {
+ _inlineSyntaxes.addAll(inlineSyntaxes);
+ }
+
+ if (extensionSet == null) {
+ if (withDefaultBlockSyntaxes) {
+ _blockSyntaxes.addAll(ExtensionSet.commonMark.blockSyntaxes);
+ }
+
+ if (withDefaultInlineSyntaxes) {
+ _inlineSyntaxes.addAll(ExtensionSet.commonMark.inlineSyntaxes);
+ }
+ } else {
+ _blockSyntaxes.addAll(extensionSet.blockSyntaxes);
+ _inlineSyntaxes.addAll(extensionSet.inlineSyntaxes);
+ }
+ }
+
+ /// Parses the given [lines] of Markdown to a series of AST nodes.
+ List<Node> parseLines(List<String> lines) =>
+ parseLineList(lines.map(Line.new).toList());
+
+ /// Parses the given [text] to a series of AST nodes.
+ List<Node> parse(String text) => parseLineList(text.toLines());
+
+ /// Parses the given [lines] of [Line] to a series of AST nodes.
+ List<Node> parseLineList(List<Line> lines) {
+ final nodes = BlockParser(lines, this).parseLines();
+ _parseInlineContent(nodes);
+ // Do filter after parsing inline as we need ref count.
+ return _filterFootnotes(nodes);
+ }
+
+ /// Parses the given inline Markdown [text] to a series of AST nodes.
+ List<Node> parseInline(String text) => InlineParser(text, this).parse();
+
+ void _parseInlineContent(List<Node> nodes) {
+ for (var i = 0; i < nodes.length; i++) {
+ final node = nodes[i];
+ if (node is UnparsedContent) {
+ final inlineNodes = parseInline(node.textContent);
+ nodes.removeAt(i);
+ nodes.insertAll(i, inlineNodes);
+ i += inlineNodes.length - 1;
+ } else if (node is Element && node.children != null) {
+ _parseInlineContent(node.children!);
+ }
+ }
+ }
+
+ /// Footnotes could be defined in arbitrary positions of a document, we need
+ /// to distinguish them and put them behind; and every footnote definition
+ /// may have multiple backrefs, we need to append backrefs for it.
+ List<Node> _filterFootnotes(List<Node> nodes) {
+ final footnotes = <Element>[];
+ final blocks = <Node>[];
+ for (final node in nodes) {
+ if (node is Element &&
+ node.tag == 'li' &&
+ footnoteReferences.containsKey(node.footnoteLabel)) {
+ final label = node.footnoteLabel;
+ var count = 0;
+ if (label != null && (count = footnoteReferences[label] ?? 0) > 0) {
+ footnotes.add(node);
+ final children = node.children;
+ if (children != null) {
+ _appendBackref(children, Uri.encodeComponent(label), count);
+ }
+ }
+ } else {
+ blocks.add(node);
+ }
+ }
+
+ if (footnotes.isNotEmpty) {
+ // Sort footnotes by appearing order.
+ final ordinal = {
+ for (var i = 0; i < footnoteLabels.length; i++)
+ 'fn-${footnoteLabels[i]}': i,
+ };
+ footnotes.sort((l, r) {
+ final idl = l.attributes['id']?.toLowerCase() ?? '';
+ final idr = r.attributes['id']?.toLowerCase() ?? '';
+ return (ordinal[idl] ?? 0) - (ordinal[idr] ?? 0);
+ });
+ final list = Element('ol', footnotes);
+
+ // Ignore GFM attribute: <data-footnotes>.
+ final section = Element('section', [list])
+ ..attributes['class'] = 'footnotes';
+ blocks.add(section);
+ }
+ return blocks;
+ }
+
+ /// Generate backref nodes, append them to footnote definition's last child.
+ void _appendBackref(List<Node> children, String ref, int count) {
+ final refs = [
+ for (var i = 0; i < count; i++) ...[
+ Text(' '),
+ _ElementExt.footnoteAnchor(ref, i)
+ ]
+ ];
+ if (children.isEmpty) {
+ children.addAll(refs);
+ } else {
+ final last = children.last;
+ if (last is Element) {
+ last.children?.addAll(refs);
+ } else {
+ children.last = Element('p', [last, ...refs]);
+ }
+ }
+ }
+}
+
+extension _ElementExt on Element {
+ static Element footnoteAnchor(String ref, int i) {
+ final num = '${i + 1}';
+ final suffix = i > 0 ? '-$num' : '';
+ final e = Element.empty('tag');
+ e.match;
+ return Element('a', [
+ Text('\u21a9'),
+ if (i > 0)
+ Element('sup', [Text(num)])..attributes['class'] = 'footnote-ref',
+ ])
+ // Ignore GFM's attributes:
+ // <data-footnote-backref aria-label="Back to content">.
+ ..attributes['href'] = '#fnref-$ref$suffix'
+ ..attributes['class'] = 'footnote-backref';
+ }
+
+ String get match => tag;
+}
+
+/// A [link reference
+/// definition](https://spec.commonmark.org/0.30/#link-reference-definitions).
+class LinkReference {
+ /// The [link label](https://spec.commonmark.org/0.30/#link-label).
+ ///
+ /// Temporarily, this class is also being used to represent the link data for
+ /// an inline link (the destination and title), but this should change before
+ /// the package is released.
+ final String label;
+
+ /// The [link destination](https://spec.commonmark.org/0.30/#link-destination).
+ final String destination;
+
+ /// The [link title](https://spec.commonmark.org/0.30/#link-title).
+ final String? title;
+
+ /// Construct a new [LinkReference], with all necessary fields.
+ ///
+ /// If the parsed link reference definition does not include a title, use
+ /// `null` for the [title] parameter.
+ LinkReference(this.label, this.destination, this.title);
+}
diff --git a/pkgs/markdown/lib/src/emojis.dart b/pkgs/markdown/lib/src/emojis.dart
new file mode 100644
index 0000000..cca1a28
--- /dev/null
+++ b/pkgs/markdown/lib/src/emojis.dart
@@ -0,0 +1,1904 @@
+// GENERATED FILE. DO NOT EDIT.
+//
+// This file was generated from GitHub's emoji API list endpoint:
+// https://api.github.com/emojis
+// at 2022-05-03 01:45:16.587812 by the script, tool/update_github_emojis.dart.
+
+const emojis = <String, String>{
+ '+1': '👍',
+ '-1': '👎',
+ '100': '💯',
+ '1234': '🔢',
+ '1st_place_medal': '🥇',
+ '2nd_place_medal': '🥈',
+ '3rd_place_medal': '🥉',
+ '8ball': '🎱',
+ 'a': '🅰️',
+ 'ab': '🆎',
+ 'abacus': '🧮',
+ 'abc': '🔤',
+ 'abcd': '🔡',
+ 'accept': '🉑',
+ 'accordion': '🪗',
+ 'adhesive_bandage': '🩹',
+ 'adult': '🧑',
+ 'aerial_tramway': '🚡',
+ 'afghanistan': '🇦🇫',
+ 'airplane': '✈️',
+ 'aland_islands': '🇦🇽',
+ 'alarm_clock': '⏰',
+ 'albania': '🇦🇱',
+ 'alembic': '⚗',
+ 'algeria': '🇩🇿',
+ 'alien': '👽',
+ 'ambulance': '🚑',
+ 'american_samoa': '🇦🇸',
+ 'amphora': '🏺',
+ 'anatomical_heart': '🫀',
+ 'anchor': '⚓',
+ 'andorra': '🇦🇩',
+ 'angel': '👼',
+ 'anger': '💢',
+ 'angola': '🇦🇴',
+ 'angry': '😠',
+ 'anguilla': '🇦🇮',
+ 'anguished': '😧',
+ 'ant': '🐜',
+ 'antarctica': '🇦🇶',
+ 'antigua_barbuda': '🇦🇬',
+ 'apple': '🍎',
+ 'aquarius': '♒',
+ 'argentina': '🇦🇷',
+ 'aries': '♈',
+ 'armenia': '🇦🇲',
+ 'arrow_backward': '◀️',
+ 'arrow_double_down': '⏬',
+ 'arrow_double_up': '⏫',
+ 'arrow_down': '⬇️',
+ 'arrow_down_small': '🔽',
+ 'arrow_forward': '▶️',
+ 'arrow_heading_down': '⤵️',
+ 'arrow_heading_up': '⤴️',
+ 'arrow_left': '⬅️',
+ 'arrow_lower_left': '↙️',
+ 'arrow_lower_right': '↘️',
+ 'arrow_right': '➡️',
+ 'arrow_right_hook': '↪️',
+ 'arrow_up': '⬆️',
+ 'arrow_up_down': '↕️',
+ 'arrow_up_small': '🔼',
+ 'arrow_upper_left': '↖️',
+ 'arrow_upper_right': '↗️',
+ 'arrows_clockwise': '🔃',
+ 'arrows_counterclockwise': '🔄',
+ 'art': '🎨',
+ 'articulated_lorry': '🚛',
+ 'artificial_satellite': '🛰',
+ 'artist': '🧑️🎨',
+ 'aruba': '🇦🇼',
+ 'ascension_island': '🇦️🇨',
+ 'asterisk': '*⃣',
+ 'astonished': '😲',
+ 'astronaut': '🧑️🚀',
+ 'athletic_shoe': '👟',
+ 'atm': '🏧',
+ 'atom_symbol': '⚛',
+ 'australia': '🇦🇺',
+ 'austria': '🇦🇹',
+ 'auto_rickshaw': '🛺',
+ 'avocado': '🥑',
+ 'axe': '🪓',
+ 'azerbaijan': '🇦🇿',
+ 'b': '🅱️',
+ 'baby': '👶',
+ 'baby_bottle': '🍼',
+ 'baby_chick': '🐤',
+ 'baby_symbol': '🚼',
+ 'back': '🔙',
+ 'bacon': '🥓',
+ 'badger': '🦡',
+ 'badminton': '🏸',
+ 'bagel': '🥯',
+ 'baggage_claim': '🛄',
+ 'baguette_bread': '🥖',
+ 'bahamas': '🇧🇸',
+ 'bahrain': '🇧🇭',
+ 'balance_scale': '⚖',
+ 'bald_man': '👨️🦲',
+ 'bald_woman': '👩️🦲',
+ 'ballet_shoes': '🩰',
+ 'balloon': '🎈',
+ 'ballot_box': '🗳',
+ 'ballot_box_with_check': '☑️',
+ 'bamboo': '🎍',
+ 'banana': '🍌',
+ 'bangbang': '‼️',
+ 'bangladesh': '🇧🇩',
+ 'banjo': '🪕',
+ 'bank': '🏦',
+ 'bar_chart': '📊',
+ 'barbados': '🇧🇧',
+ 'barber': '💈',
+ 'baseball': '⚾',
+ 'basket': '🧺',
+ 'basketball': '🏀',
+ 'basketball_man': '⛹',
+ 'basketball_woman': '⛹️♀️',
+ 'bat': '🦇',
+ 'bath': '🛀',
+ 'bathtub': '🛁',
+ 'battery': '🔋',
+ 'beach_umbrella': '🏖',
+ 'bear': '🐻',
+ 'bearded_person': '🧔',
+ 'beaver': '🦫',
+ 'bed': '🛏',
+ 'bee': '🐝',
+ 'beer': '🍺',
+ 'beers': '🍻',
+ 'beetle': '🪲',
+ 'beginner': '🔰',
+ 'belarus': '🇧🇾',
+ 'belgium': '🇧🇪',
+ 'belize': '🇧🇿',
+ 'bell': '🔔',
+ 'bell_pepper': '🫑',
+ 'bellhop_bell': '🛎',
+ 'benin': '🇧🇯',
+ 'bento': '🍱',
+ 'bermuda': '🇧🇲',
+ 'beverage_box': '🧃',
+ 'bhutan': '🇧🇹',
+ 'bicyclist': '🚴',
+ 'bike': '🚲',
+ 'biking_man': '🚴',
+ 'biking_woman': '🚴♀️',
+ 'bikini': '👙',
+ 'billed_cap': '🧢',
+ 'billed_hat': '🧢',
+ 'biohazard': '☣',
+ 'bird': '🐦',
+ 'birthday': '🎂',
+ 'bison': '🦬',
+ 'black_cat': '🐈️⬛',
+ 'black_circle': '⚫',
+ 'black_flag': '🏴',
+ 'black_heart': '🖤',
+ 'black_joker': '🃏',
+ 'black_large_square': '⬛',
+ 'black_medium_small_square': '◾',
+ 'black_medium_square': '◼️',
+ 'black_nib': '✒️',
+ 'black_small_square': '▪️',
+ 'black_square_button': '🔲',
+ 'blond_haired_man': '👱️♂',
+ 'blond_haired_person': '👱',
+ 'blond_haired_woman': '👱️♀',
+ 'blonde_man': '👱',
+ 'blonde_woman': '👱♀️',
+ 'blossom': '🌼',
+ 'blowfish': '🐡',
+ 'blue_book': '📘',
+ 'blue_car': '🚙',
+ 'blue_heart': '💙',
+ 'blue_square': '🟦',
+ 'blueberries': '🫐',
+ 'blush': '😊',
+ 'boar': '🐗',
+ 'boat': '⛵',
+ 'bolivia': '🇧🇴',
+ 'bomb': '💣',
+ 'bone': '🦴',
+ 'book': '📖',
+ 'bookmark': '🔖',
+ 'bookmark_tabs': '📑',
+ 'books': '📚',
+ 'boom': '💥',
+ 'boomerang': '🪃',
+ 'boot': '👢',
+ 'bosnia_herzegovina': '🇧🇦',
+ 'botswana': '🇧🇼',
+ 'bouncing_ball_man': '⛹️♂',
+ 'bouncing_ball_person': '⛹',
+ 'bouncing_ball_woman': '⛹️♀',
+ 'bouquet': '💐',
+ 'bouvet_island': '🇧️🇻',
+ 'bow': '🙇',
+ 'bow_and_arrow': '🏹',
+ 'bowing_man': '🙇',
+ 'bowing_woman': '🙇♀️',
+ 'bowl_with_spoon': '🥣',
+ 'bowling': '🎳',
+ 'boxing_glove': '🥊',
+ 'boy': '👦',
+ 'brain': '🧠',
+ 'brazil': '🇧🇷',
+ 'bread': '🍞',
+ 'breast_feeding': '🤱',
+ 'breastfeeding': '🤱',
+ 'brick': '🧱',
+ 'bricks': '🧱',
+ 'bride_with_veil': '👰',
+ 'bridge_at_night': '🌉',
+ 'briefcase': '💼',
+ 'british_indian_ocean_territory': '🇮🇴',
+ 'british_virgin_islands': '🇻🇬',
+ 'broccoli': '🥦',
+ 'broken_heart': '💔',
+ 'broom': '🧹',
+ 'brown_circle': '🟤',
+ 'brown_heart': '🤎',
+ 'brown_square': '🟫',
+ 'brunei': '🇧🇳',
+ 'bubble_tea': '🧋',
+ 'bucket': '🪣',
+ 'bug': '🐛',
+ 'building_construction': '🏗',
+ 'bulb': '💡',
+ 'bulgaria': '🇧🇬',
+ 'bullettrain_front': '🚅',
+ 'bullettrain_side': '🚄',
+ 'burkina_faso': '🇧🇫',
+ 'burrito': '🌯',
+ 'burundi': '🇧🇮',
+ 'bus': '🚌',
+ 'business_suit_levitating': '🕴',
+ 'busstop': '🚏',
+ 'bust_in_silhouette': '👤',
+ 'busts_in_silhouette': '👥',
+ 'butter': '🧈',
+ 'butterfly': '🦋',
+ 'cactus': '🌵',
+ 'cake': '🍰',
+ 'calendar': '📆',
+ 'call_me_hand': '🤙',
+ 'calling': '📲',
+ 'cambodia': '🇰🇭',
+ 'camel': '🐫',
+ 'camera': '📷',
+ 'camera_flash': '📸',
+ 'cameroon': '🇨🇲',
+ 'camping': '🏕',
+ 'canada': '🇨🇦',
+ 'canary_islands': '🇮🇨',
+ 'cancer': '♋',
+ 'candle': '🕯',
+ 'candy': '🍬',
+ 'canned_food': '🥫',
+ 'canoe': '🛶',
+ 'cape_verde': '🇨🇻',
+ 'capital_abcd': '🔠',
+ 'capricorn': '♑',
+ 'car': '🚗',
+ 'card_file_box': '🗃',
+ 'card_index': '📇',
+ 'card_index_dividers': '🗂',
+ 'caribbean_netherlands': '🇧🇶',
+ 'carousel_horse': '🎠',
+ 'carpentry_saw': '🪚',
+ 'carrot': '🥕',
+ 'cartwheeling': '🤸',
+ 'cat': '🐱',
+ 'cat2': '🐈',
+ 'cayman_islands': '🇰🇾',
+ 'cd': '💿',
+ 'central_african_republic': '🇨🇫',
+ 'ceuta_melilla': '🇪️🇦',
+ 'chad': '🇹🇩',
+ 'chains': '⛓',
+ 'chair': '🪑',
+ 'champagne': '🍾',
+ 'chart': '💹',
+ 'chart_with_downwards_trend': '📉',
+ 'chart_with_upwards_trend': '📈',
+ 'checkered_flag': '🏁',
+ 'cheese': '🧀',
+ 'cherries': '🍒',
+ 'cherry_blossom': '🌸',
+ 'chess_pawn': '♟',
+ 'chestnut': '🌰',
+ 'chicken': '🐔',
+ 'child': '🧒',
+ 'children_crossing': '🚸',
+ 'chile': '🇨🇱',
+ 'chipmunk': '🐿',
+ 'chocolate_bar': '🍫',
+ 'chopsticks': '🥢',
+ 'christmas_island': '🇨🇽',
+ 'christmas_tree': '🎄',
+ 'church': '⛪',
+ 'cinema': '🎦',
+ 'circus_tent': '🎪',
+ 'city_sunrise': '🌇',
+ 'city_sunset': '🌆',
+ 'cityscape': '🏙',
+ 'cl': '🆑',
+ 'clamp': '🗜',
+ 'clap': '👏',
+ 'clapper': '🎬',
+ 'classical_building': '🏛',
+ 'climbing': '🧗',
+ 'climbing_man': '🧗♂️',
+ 'climbing_woman': '🧗♀️',
+ 'clinking_glasses': '🥂',
+ 'clipboard': '📋',
+ 'clipperton_island': '🇨️🇵',
+ 'clock1': '🕐',
+ 'clock10': '🕙',
+ 'clock1030': '🕥',
+ 'clock11': '🕚',
+ 'clock1130': '🕦',
+ 'clock12': '🕛',
+ 'clock1230': '🕧',
+ 'clock130': '🕜',
+ 'clock2': '🕑',
+ 'clock230': '🕝',
+ 'clock3': '🕒',
+ 'clock330': '🕞',
+ 'clock4': '🕓',
+ 'clock430': '🕟',
+ 'clock5': '🕔',
+ 'clock530': '🕠',
+ 'clock6': '🕕',
+ 'clock630': '🕡',
+ 'clock7': '🕖',
+ 'clock730': '🕢',
+ 'clock8': '🕗',
+ 'clock830': '🕣',
+ 'clock9': '🕘',
+ 'clock930': '🕤',
+ 'closed_book': '📕',
+ 'closed_lock_with_key': '🔐',
+ 'closed_umbrella': '🌂',
+ 'cloud': '☁️',
+ 'cloud_with_lightning': '🌩',
+ 'cloud_with_lightning_and_rain': '⛈',
+ 'cloud_with_rain': '🌧',
+ 'cloud_with_snow': '🌨',
+ 'clown_face': '🤡',
+ 'clubs': '♣️',
+ 'cn': '🇨🇳',
+ 'coat': '🧥',
+ 'cockroach': '🪳',
+ 'cocktail': '🍸',
+ 'coconut': '🥥',
+ 'cocos_islands': '🇨🇨',
+ 'coffee': '☕',
+ 'coffin': '⚰',
+ 'coin': '🪙',
+ 'cold': '🥶',
+ 'cold_face': '🥶',
+ 'cold_sweat': '😰',
+ 'collision': '💥',
+ 'colombia': '🇨🇴',
+ 'comet': '☄',
+ 'comoros': '🇰🇲',
+ 'compass': '🧭',
+ 'computer': '💻',
+ 'computer_mouse': '🖱',
+ 'confetti_ball': '🎊',
+ 'confounded': '😖',
+ 'confused': '😕',
+ 'congo_brazzaville': '🇨🇬',
+ 'congo_kinshasa': '🇨🇩',
+ 'congratulations': '㊗️',
+ 'construction': '🚧',
+ 'construction_worker': '👷',
+ 'construction_worker_man': '👷',
+ 'construction_worker_woman': '👷♀️',
+ 'control_knobs': '🎛',
+ 'convenience_store': '🏪',
+ 'cook': '🧑️🍳',
+ 'cook_islands': '🇨🇰',
+ 'cookie': '🍪',
+ 'cool': '🆒',
+ 'cop': '👮',
+ 'copyright': '©️',
+ 'corn': '🌽',
+ 'costa_rica': '🇨🇷',
+ 'cote_divoire': '🇨🇮',
+ 'couch_and_lamp': '🛋',
+ 'couple': '👫',
+ 'couple_with_heart': '💑',
+ 'couple_with_heart_man_man': '👨❤️👨',
+ 'couple_with_heart_woman_man': '💑',
+ 'couple_with_heart_woman_woman': '👩❤️👩',
+ 'couplekiss': '💏',
+ 'couplekiss_man_man': '👨❤️💋👨',
+ 'couplekiss_man_woman': '💏',
+ 'couplekiss_woman_woman': '👩❤️💋👩',
+ 'cow': '🐮',
+ 'cow2': '🐄',
+ 'cowboy_hat_face': '🤠',
+ 'crab': '🦀',
+ 'crayon': '🖍',
+ 'credit_card': '💳',
+ 'crescent_moon': '🌙',
+ 'cricket': '🦗',
+ 'cricket_game': '🏏',
+ 'croatia': '🇭🇷',
+ 'crocodile': '🐊',
+ 'croissant': '🥐',
+ 'crossed_fingers': '🤞',
+ 'crossed_flags': '🎌',
+ 'crossed_swords': '⚔',
+ 'crown': '👑',
+ 'cry': '😢',
+ 'crying_cat_face': '😿',
+ 'crystal_ball': '🔮',
+ 'cuba': '🇨🇺',
+ 'cucumber': '🥒',
+ 'cup_with_straw': '🥤',
+ 'cupcake': '🧁',
+ 'cupid': '💘',
+ 'curacao': '🇨🇼',
+ 'curling_stone': '🥌',
+ 'curly_haired_man': '👨️🦱',
+ 'curly_haired_woman': '👩️🦱',
+ 'curly_loop': '➰',
+ 'currency_exchange': '💱',
+ 'curry': '🍛',
+ 'cursing_face': '🤬',
+ 'custard': '🍮',
+ 'customs': '🛃',
+ 'cut_of_meat': '🥩',
+ 'cyclone': '🌀',
+ 'cyprus': '🇨🇾',
+ 'czech_republic': '🇨🇿',
+ 'dagger': '🗡',
+ 'dancer': '💃',
+ 'dancers': '👯',
+ 'dancing_men': '👯♂️',
+ 'dancing_women': '👯',
+ 'dango': '🍡',
+ 'dark_sunglasses': '🕶',
+ 'dart': '🎯',
+ 'dash': '💨',
+ 'date': '📅',
+ 'de': '🇩🇪',
+ 'deaf_man': '🧏️♂',
+ 'deaf_person': '🧏',
+ 'deaf_woman': '🧏️♀',
+ 'deciduous_tree': '🌳',
+ 'deer': '🦌',
+ 'denmark': '🇩🇰',
+ 'department_store': '🏬',
+ 'derelict_house': '🏚',
+ 'desert': '🏜',
+ 'desert_island': '🏝',
+ 'desktop_computer': '🖥',
+ 'detective': '🕵',
+ 'diamond_shape_with_a_dot_inside': '💠',
+ 'diamonds': '♦️',
+ 'diego_garcia': '🇩️🇬',
+ 'disappointed': '😞',
+ 'disappointed_relieved': '😥',
+ 'disguised_face': '🥸',
+ 'diving_mask': '🤿',
+ 'diya_lamp': '🪔',
+ 'dizzy': '💫',
+ 'dizzy_face': '😵',
+ 'djibouti': '🇩🇯',
+ 'dna': '🧬',
+ 'do_not_litter': '🚯',
+ 'dodo': '🦤',
+ 'dog': '🐶',
+ 'dog2': '🐕',
+ 'dollar': '💵',
+ 'dolls': '🎎',
+ 'dolphin': '🐬',
+ 'dominica': '🇩🇲',
+ 'dominican_republic': '🇩🇴',
+ 'door': '🚪',
+ 'doughnut': '🍩',
+ 'dove': '🕊',
+ 'dragon': '🐉',
+ 'dragon_face': '🐲',
+ 'dress': '👗',
+ 'dromedary_camel': '🐪',
+ 'drooling_face': '🤤',
+ 'drop_of_blood': '🩸',
+ 'droplet': '💧',
+ 'drum': '🥁',
+ 'duck': '🦆',
+ 'dumpling': '🥟',
+ 'dvd': '📀',
+ 'e-mail': '📧',
+ 'eagle': '🦅',
+ 'ear': '👂',
+ 'ear_of_rice': '🌾',
+ 'ear_with_hearing_aid': '🦻',
+ 'earth_africa': '🌍',
+ 'earth_americas': '🌎',
+ 'earth_asia': '🌏',
+ 'ecuador': '🇪🇨',
+ 'egg': '🥚',
+ 'eggplant': '🍆',
+ 'egypt': '🇪🇬',
+ 'eight': '8️⃣',
+ 'eight_pointed_black_star': '✴️',
+ 'eight_spoked_asterisk': '✳️',
+ 'eject_button': '⏏️',
+ 'el_salvador': '🇸🇻',
+ 'electric_plug': '🔌',
+ 'elephant': '🐘',
+ 'elevator': '🛗',
+ 'elf': '🧝',
+ 'elf_man': '🧝️♂',
+ 'elf_woman': '🧝️♀',
+ 'email': '✉️',
+ 'end': '🔚',
+ 'england': '🏴',
+ 'envelope': '✉',
+ 'envelope_with_arrow': '📩',
+ 'equatorial_guinea': '🇬🇶',
+ 'eritrea': '🇪🇷',
+ 'es': '🇪🇸',
+ 'estonia': '🇪🇪',
+ 'ethiopia': '🇪🇹',
+ 'eu': '🇪🇺',
+ 'euro': '💶',
+ 'european_castle': '🏰',
+ 'european_post_office': '🏤',
+ 'european_union': '🇪️🇺',
+ 'evergreen_tree': '🌲',
+ 'exclamation': '❗',
+ 'exploding_head': '🤯',
+ 'expressionless': '😑',
+ 'eye': '👁',
+ 'eye_speech_bubble': '👁️🗨',
+ 'eyeglasses': '👓',
+ 'eyes': '👀',
+ 'face_exhaling': '😮️💨',
+ 'face_in_clouds': '😶️🌫',
+ 'face_with_head_bandage': '🤕',
+ 'face_with_spiral_eyes': '😵️💫',
+ 'face_with_thermometer': '🤒',
+ 'facepalm': '🤦',
+ 'facepunch': '👊',
+ 'factory': '🏭',
+ 'factory_worker': '🧑️🏭',
+ 'fairy': '🧚',
+ 'fairy_man': '🧚️♂',
+ 'fairy_woman': '🧚️♀',
+ 'falafel': '🧆',
+ 'falkland_islands': '🇫🇰',
+ 'fallen_leaf': '🍂',
+ 'family': '👪',
+ 'family_man_boy': '👨👦',
+ 'family_man_boy_boy': '👨👦👦',
+ 'family_man_girl': '👨👧',
+ 'family_man_girl_boy': '👨👧👦',
+ 'family_man_girl_girl': '👨👧👧',
+ 'family_man_man_boy': '👨👨👦',
+ 'family_man_man_boy_boy': '👨👨👦👦',
+ 'family_man_man_girl': '👨👨👧',
+ 'family_man_man_girl_boy': '👨👨👧👦',
+ 'family_man_man_girl_girl': '👨👨👧👧',
+ 'family_man_woman_boy': '👪',
+ 'family_man_woman_boy_boy': '👨👩👦👦',
+ 'family_man_woman_girl': '👨👩👧',
+ 'family_man_woman_girl_boy': '👨👩👧👦',
+ 'family_man_woman_girl_girl': '👨👩👧👧',
+ 'family_woman_boy': '👩👦',
+ 'family_woman_boy_boy': '👩👦👦',
+ 'family_woman_girl': '👩👧',
+ 'family_woman_girl_boy': '👩👧👦',
+ 'family_woman_girl_girl': '👩👧👧',
+ 'family_woman_woman_boy': '👩👩👦',
+ 'family_woman_woman_boy_boy': '👩👩👦👦',
+ 'family_woman_woman_girl': '👩👩👧',
+ 'family_woman_woman_girl_boy': '👩👩👧👦',
+ 'family_woman_woman_girl_girl': '👩👩👧👧',
+ 'farmer': '🧑️🌾',
+ 'faroe_islands': '🇫🇴',
+ 'fast_forward': '⏩',
+ 'fax': '📠',
+ 'fearful': '😨',
+ 'feather': '🪶',
+ 'feet': '🐾',
+ 'female_detective': '🕵️♀️',
+ 'female_sign': '♀',
+ 'ferris_wheel': '🎡',
+ 'ferry': '⛴',
+ 'field_hockey': '🏑',
+ 'fiji': '🇫🇯',
+ 'file_cabinet': '🗄',
+ 'file_folder': '📁',
+ 'film_projector': '📽',
+ 'film_strip': '🎞',
+ 'finland': '🇫🇮',
+ 'fire': '🔥',
+ 'fire_engine': '🚒',
+ 'fire_extinguisher': '🧯',
+ 'firecracker': '🧨',
+ 'firefighter': '🧑️🚒',
+ 'fireworks': '🎆',
+ 'first_quarter_moon': '🌓',
+ 'first_quarter_moon_with_face': '🌛',
+ 'fish': '🐟',
+ 'fish_cake': '🍥',
+ 'fishing_pole_and_fish': '🎣',
+ 'fist': '✊',
+ 'fist_left': '🤛',
+ 'fist_oncoming': '👊',
+ 'fist_raised': '✊',
+ 'fist_right': '🤜',
+ 'five': '5️⃣',
+ 'flags': '🎏',
+ 'flamingo': '🦩',
+ 'flashlight': '🔦',
+ 'flat_shoe': '🥿',
+ 'flatbread': '🫓',
+ 'fleur_de_lis': '⚜',
+ 'flight_arrival': '🛬',
+ 'flight_departure': '🛫',
+ 'flipper': '🐬',
+ 'floppy_disk': '💾',
+ 'flower_playing_cards': '🎴',
+ 'flushed': '😳',
+ 'fly': '🪰',
+ 'flying_disc': '🥏',
+ 'flying_saucer': '🛸',
+ 'fog': '🌫',
+ 'foggy': '🌁',
+ 'fondue': '🫕',
+ 'foot': '🦶',
+ 'football': '🏈',
+ 'footprints': '👣',
+ 'fork_and_knife': '🍴',
+ 'fortune_cookie': '🥠',
+ 'fountain': '⛲',
+ 'fountain_pen': '🖋',
+ 'four': '4️⃣',
+ 'four_leaf_clover': '🍀',
+ 'fox_face': '🦊',
+ 'fr': '🇫🇷',
+ 'framed_picture': '🖼',
+ 'free': '🆓',
+ 'french_guiana': '🇬🇫',
+ 'french_polynesia': '🇵🇫',
+ 'french_southern_territories': '🇹🇫',
+ 'fried_egg': '🍳',
+ 'fried_shrimp': '🍤',
+ 'fries': '🍟',
+ 'frog': '🐸',
+ 'frowning': '😦',
+ 'frowning_face': '☹',
+ 'frowning_man': '🙍♂️',
+ 'frowning_person': '🙍',
+ 'frowning_woman': '🙍',
+ 'fu': '🖕',
+ 'fuelpump': '⛽',
+ 'full_moon': '🌕',
+ 'full_moon_with_face': '🌝',
+ 'funeral_urn': '⚱',
+ 'gabon': '🇬🇦',
+ 'gambia': '🇬🇲',
+ 'game_die': '🎲',
+ 'garlic': '🧄',
+ 'gb': '🇬️🇧',
+ 'gear': '⚙',
+ 'gem': '💎',
+ 'gemini': '♊',
+ 'genie': '🧞',
+ 'genie_man': '🧞️♂',
+ 'genie_woman': '🧞️♀',
+ 'georgia': '🇬🇪',
+ 'ghana': '🇬🇭',
+ 'ghost': '👻',
+ 'gibraltar': '🇬🇮',
+ 'gift': '🎁',
+ 'gift_heart': '💝',
+ 'giraffe': '🦒',
+ 'girl': '👧',
+ 'globe_with_meridians': '🌐',
+ 'gloves': '🧤',
+ 'goal_net': '🥅',
+ 'goat': '🐐',
+ 'goggles': '🥽',
+ 'golf': '⛳',
+ 'golfing': '🏌',
+ 'golfing_man': '🏌',
+ 'golfing_woman': '🏌️♀️',
+ 'gorilla': '🦍',
+ 'grapes': '🍇',
+ 'grasshopper': '🦗',
+ 'greece': '🇬🇷',
+ 'green_apple': '🍏',
+ 'green_book': '📗',
+ 'green_circle': '🟢',
+ 'green_heart': '💚',
+ 'green_salad': '🥗',
+ 'green_square': '🟩',
+ 'greenland': '🇬🇱',
+ 'grenada': '🇬🇩',
+ 'grey_exclamation': '❕',
+ 'grey_question': '❔',
+ 'grimacing': '😬',
+ 'grin': '😁',
+ 'grinning': '😀',
+ 'guadeloupe': '🇬🇵',
+ 'guam': '🇬🇺',
+ 'guard': '💂',
+ 'guardsman': '💂',
+ 'guardswoman': '💂♀️',
+ 'guatemala': '🇬🇹',
+ 'guernsey': '🇬🇬',
+ 'guide_dog': '🦮',
+ 'guinea': '🇬🇳',
+ 'guinea_bissau': '🇬🇼',
+ 'guitar': '🎸',
+ 'gun': '🔫',
+ 'guyana': '🇬🇾',
+ 'haircut': '💇',
+ 'haircut_man': '💇♂️',
+ 'haircut_woman': '💇',
+ 'haiti': '🇭🇹',
+ 'hamburger': '🍔',
+ 'hammer': '🔨',
+ 'hammer_and_pick': '⚒',
+ 'hammer_and_wrench': '🛠',
+ 'hamster': '🐹',
+ 'hand': '✋',
+ 'hand_over_mouth': '🤭',
+ 'handbag': '👜',
+ 'handball_person': '🤾',
+ 'handshake': '🤝',
+ 'hankey': '💩',
+ 'hash': '#️⃣',
+ 'hatched_chick': '🐥',
+ 'hatching_chick': '🐣',
+ 'headphones': '🎧',
+ 'headstone': '🪦',
+ 'health_worker': '🧑️⚕',
+ 'hear_no_evil': '🙉',
+ 'heard_mcdonald_islands': '🇭️🇲',
+ 'heart': '❤️',
+ 'heart_decoration': '💟',
+ 'heart_eyes': '😍',
+ 'heart_eyes_cat': '😻',
+ 'heart_on_fire': '❤️🔥',
+ 'heartbeat': '💓',
+ 'heartpulse': '💗',
+ 'hearts': '♥️',
+ 'heavy_check_mark': '✔️',
+ 'heavy_division_sign': '➗',
+ 'heavy_dollar_sign': '💲',
+ 'heavy_exclamation_mark': '❗',
+ 'heavy_heart_exclamation': '❣',
+ 'heavy_minus_sign': '➖',
+ 'heavy_multiplication_x': '✖️',
+ 'heavy_plus_sign': '➕',
+ 'hedgehog': '🦔',
+ 'helicopter': '🚁',
+ 'herb': '🌿',
+ 'hibiscus': '🌺',
+ 'high_brightness': '🔆',
+ 'high_heel': '👠',
+ 'hiking_boot': '🥾',
+ 'hindu_temple': '🛕',
+ 'hippopotamus': '🦛',
+ 'hocho': '🔪',
+ 'hole': '🕳',
+ 'honduras': '🇭🇳',
+ 'honey_pot': '🍯',
+ 'honeybee': '🐝',
+ 'hong_kong': '🇭🇰',
+ 'hook': '🪝',
+ 'horse': '🐴',
+ 'horse_racing': '🏇',
+ 'hospital': '🏥',
+ 'hot': '🥵',
+ 'hot_face': '🥵',
+ 'hot_pepper': '🌶',
+ 'hotdog': '🌭',
+ 'hotel': '🏨',
+ 'hotsprings': '♨️',
+ 'hourglass': '⌛',
+ 'hourglass_flowing_sand': '⏳',
+ 'house': '🏠',
+ 'house_with_garden': '🏡',
+ 'houses': '🏘',
+ 'hugs': '🤗',
+ 'hungary': '🇭🇺',
+ 'hushed': '😯',
+ 'hut': '🛖',
+ 'ice_cream': '🍨',
+ 'ice_cube': '🧊',
+ 'ice_hockey': '🏒',
+ 'ice_skate': '⛸',
+ 'icecream': '🍦',
+ 'iceland': '🇮🇸',
+ 'id': '🆔',
+ 'ideograph_advantage': '🉐',
+ 'imp': '👿',
+ 'inbox_tray': '📥',
+ 'incoming_envelope': '📨',
+ 'india': '🇮🇳',
+ 'indonesia': '🇮🇩',
+ 'infinity': '♾',
+ 'information_desk_person': '💁',
+ 'information_source': 'ℹ️',
+ 'innocent': '😇',
+ 'interrobang': '⁉️',
+ 'iphone': '📱',
+ 'iran': '🇮🇷',
+ 'iraq': '🇮🇶',
+ 'ireland': '🇮🇪',
+ 'isle_of_man': '🇮🇲',
+ 'israel': '🇮🇱',
+ 'it': '🇮🇹',
+ 'izakaya_lantern': '🏮',
+ 'jack_o_lantern': '🎃',
+ 'jamaica': '🇯🇲',
+ 'japan': '🗾',
+ 'japanese_castle': '🏯',
+ 'japanese_goblin': '👺',
+ 'japanese_ogre': '👹',
+ 'jeans': '👖',
+ 'jersey': '🇯🇪',
+ 'jigsaw': '🧩',
+ 'jordan': '🇯🇴',
+ 'joy': '😂',
+ 'joy_cat': '😹',
+ 'joystick': '🕹',
+ 'jp': '🇯🇵',
+ 'judge': '🧑️⚖',
+ 'juggling_person': '🤹',
+ 'kaaba': '🕋',
+ 'kangaroo': '🦘',
+ 'kazakhstan': '🇰🇿',
+ 'kenya': '🇰🇪',
+ 'key': '🔑',
+ 'keyboard': '⌨',
+ 'keycap_ten': '🔟',
+ 'kick_scooter': '🛴',
+ 'kimono': '👘',
+ 'kiribati': '🇰🇮',
+ 'kiss': '💋',
+ 'kissing': '😗',
+ 'kissing_cat': '😽',
+ 'kissing_closed_eyes': '😚',
+ 'kissing_heart': '😘',
+ 'kissing_smiling_eyes': '😙',
+ 'kite': '🪁',
+ 'kiwi_fruit': '🥝',
+ 'kneeling_man': '🧎️♂',
+ 'kneeling_person': '🧎',
+ 'kneeling_woman': '🧎️♀',
+ 'knife': '🔪',
+ 'knot': '🪢',
+ 'koala': '🐨',
+ 'koko': '🈁',
+ 'kosovo': '🇽🇰',
+ 'kr': '🇰🇷',
+ 'kuwait': '🇰🇼',
+ 'kyrgyzstan': '🇰🇬',
+ 'lab_coat': '🥼',
+ 'labcoat': '🥼',
+ 'label': '🏷',
+ 'lacrosse': '🥍',
+ 'ladder': '🪜',
+ 'lady_beetle': '🐞',
+ 'lantern': '🏮',
+ 'laos': '🇱🇦',
+ 'large_blue_circle': '🔵',
+ 'large_blue_diamond': '🔷',
+ 'large_orange_diamond': '🔶',
+ 'last_quarter_moon': '🌗',
+ 'last_quarter_moon_with_face': '🌜',
+ 'latin_cross': '✝',
+ 'latvia': '🇱🇻',
+ 'laughing': '😆',
+ 'leafy_green': '🥬',
+ 'leafy_greens': '🥬',
+ 'leaves': '🍃',
+ 'lebanon': '🇱🇧',
+ 'ledger': '📒',
+ 'left_luggage': '🛅',
+ 'left_right_arrow': '↔️',
+ 'left_speech_bubble': '🗨',
+ 'leftwards_arrow_with_hook': '↩️',
+ 'leg': '🦵',
+ 'lemon': '🍋',
+ 'leo': '♌',
+ 'leopard': '🐆',
+ 'lesotho': '🇱🇸',
+ 'level_slider': '🎚',
+ 'liberia': '🇱🇷',
+ 'libra': '♎',
+ 'libya': '🇱🇾',
+ 'liechtenstein': '🇱🇮',
+ 'light_rail': '🚈',
+ 'link': '🔗',
+ 'lion': '🦁',
+ 'lips': '👄',
+ 'lipstick': '💄',
+ 'lithuania': '🇱🇹',
+ 'lizard': '🦎',
+ 'llama': '🦙',
+ 'lobster': '🦞',
+ 'lock': '🔒',
+ 'lock_with_ink_pen': '🔏',
+ 'lollipop': '🍭',
+ 'long_drum': '🪘',
+ 'loop': '➿',
+ 'lotion_bottle': '🧴',
+ 'lotus_position': '🧘',
+ 'lotus_position_man': '🧘️♂',
+ 'lotus_position_woman': '🧘️♀',
+ 'loud_sound': '🔊',
+ 'loudspeaker': '📢',
+ 'love_hotel': '🏩',
+ 'love_letter': '💌',
+ 'love_you': '🤟',
+ 'love_you_gesture': '🤟',
+ 'low_brightness': '🔅',
+ 'luggage': '🧳',
+ 'lungs': '🫁',
+ 'luxembourg': '🇱🇺',
+ 'lying_face': '🤥',
+ 'm': 'Ⓜ️',
+ 'macau': '🇲🇴',
+ 'macedonia': '🇲🇰',
+ 'madagascar': '🇲🇬',
+ 'mag': '🔍',
+ 'mag_right': '🔎',
+ 'mage': '🧙',
+ 'mage_man': '🧙️♂',
+ 'mage_woman': '🧙️♀',
+ 'magic_wand': '🪄',
+ 'magnet': '🧲',
+ 'mahjong': '🀄',
+ 'mailbox': '📫',
+ 'mailbox_closed': '📪',
+ 'mailbox_with_mail': '📬',
+ 'mailbox_with_no_mail': '📭',
+ 'malawi': '🇲🇼',
+ 'malaysia': '🇲🇾',
+ 'maldives': '🇲🇻',
+ 'male_detective': '🕵',
+ 'male_sign': '♂',
+ 'mali': '🇲🇱',
+ 'malta': '🇲🇹',
+ 'mammoth': '🦣',
+ 'man': '👨',
+ 'man_artist': '👨🎨',
+ 'man_astronaut': '👨🚀',
+ 'man_beard': '🧔️♂',
+ 'man_cartwheeling': '🤸♂️',
+ 'man_cook': '👨🍳',
+ 'man_dancing': '🕺',
+ 'man_elf': '🧝♂️',
+ 'man_facepalming': '🤦♂️',
+ 'man_factory_worker': '👨🏭',
+ 'man_fairy': '🧚♂️',
+ 'man_farmer': '👨🌾',
+ 'man_feeding_baby': '👨️🍼',
+ 'man_firefighter': '👨🚒',
+ 'man_genie': '🧞♂️',
+ 'man_health_worker': '👨⚕️',
+ 'man_in_lotus_position': '🧘♂️',
+ 'man_in_manual_wheelchair': '👨️🦽',
+ 'man_in_motorized_wheelchair': '👨️🦼',
+ 'man_in_steamy_room': '🧖♂️',
+ 'man_in_tuxedo': '🤵',
+ 'man_judge': '👨⚖️',
+ 'man_juggling': '🤹♂️',
+ 'man_mechanic': '👨🔧',
+ 'man_office_worker': '👨💼',
+ 'man_pilot': '👨✈️',
+ 'man_playing_handball': '🤾♂️',
+ 'man_playing_water_polo': '🤽♂️',
+ 'man_scientist': '👨🔬',
+ 'man_shrugging': '🤷♂️',
+ 'man_singer': '👨🎤',
+ 'man_student': '👨🎓',
+ 'man_superhero': '🦸♂️',
+ 'man_supervillain': '🦹♂️',
+ 'man_teacher': '👨🏫',
+ 'man_technologist': '👨💻',
+ 'man_vampire': '🧛♂️',
+ 'man_with_gua_pi_mao': '👲',
+ 'man_with_probing_cane': '👨️🦯',
+ 'man_with_turban': '👳',
+ 'man_with_veil': '👰️♂',
+ 'man_zombie': '🧟♂️',
+ 'mandarin': '🍊',
+ 'mango': '🥭',
+ 'mans_shoe': '👞',
+ 'mantelpiece_clock': '🕰',
+ 'manual_wheelchair': '🦽',
+ 'maple_leaf': '🍁',
+ 'marshall_islands': '🇲🇭',
+ 'martial_arts_uniform': '🥋',
+ 'martinique': '🇲🇶',
+ 'mask': '😷',
+ 'massage': '💆',
+ 'massage_man': '💆♂️',
+ 'massage_woman': '💆',
+ 'mate': '🧉',
+ 'mauritania': '🇲🇷',
+ 'mauritius': '🇲🇺',
+ 'mayotte': '🇾🇹',
+ 'meat_on_bone': '🍖',
+ 'mechanic': '🧑️🔧',
+ 'mechanical_arm': '🦾',
+ 'mechanical_leg': '🦿',
+ 'medal_military': '🎖',
+ 'medal_sports': '🏅',
+ 'medical_symbol': '⚕',
+ 'mega': '📣',
+ 'melon': '🍈',
+ 'memo': '📝',
+ 'men_wrestling': '🤼♂️',
+ 'mending_heart': '❤️🩹',
+ 'menorah': '🕎',
+ 'mens': '🚹',
+ 'mermaid': '🧜♀️',
+ 'merman': '🧜♂️',
+ 'merperson': '🧜',
+ 'metal': '🤘',
+ 'metro': '🚇',
+ 'mexico': '🇲🇽',
+ 'microbe': '🦠',
+ 'micronesia': '🇫🇲',
+ 'microphone': '🎤',
+ 'microscope': '🔬',
+ 'middle_finger': '🖕',
+ 'military_helmet': '🪖',
+ 'milk_glass': '🥛',
+ 'milky_way': '🌌',
+ 'minibus': '🚐',
+ 'minidisc': '💽',
+ 'mirror': '🪞',
+ 'mobile_phone_off': '📴',
+ 'moldova': '🇲🇩',
+ 'monaco': '🇲🇨',
+ 'money_mouth_face': '🤑',
+ 'money_with_wings': '💸',
+ 'moneybag': '💰',
+ 'mongolia': '🇲🇳',
+ 'monkey': '🐒',
+ 'monkey_face': '🐵',
+ 'monocle': '🧐',
+ 'monocle_face': '🧐',
+ 'monorail': '🚝',
+ 'montenegro': '🇲🇪',
+ 'montserrat': '🇲🇸',
+ 'moon': '🌔',
+ 'moon_cake': '🥮',
+ 'morocco': '🇲🇦',
+ 'mortar_board': '🎓',
+ 'mosque': '🕌',
+ 'mosquito': '🦟',
+ 'motor_boat': '🛥',
+ 'motor_scooter': '🛵',
+ 'motorcycle': '🏍',
+ 'motorized_wheelchair': '🦼',
+ 'motorway': '🛣',
+ 'mount_fuji': '🗻',
+ 'mountain': '⛰',
+ 'mountain_bicyclist': '🚵',
+ 'mountain_biking_man': '🚵',
+ 'mountain_biking_woman': '🚵♀️',
+ 'mountain_cableway': '🚠',
+ 'mountain_railway': '🚞',
+ 'mountain_snow': '🏔',
+ 'mouse': '🐭',
+ 'mouse2': '🐁',
+ 'mouse_trap': '🪤',
+ 'movie_camera': '🎥',
+ 'moyai': '🗿',
+ 'mozambique': '🇲🇿',
+ 'mrs_claus': '🤶',
+ 'muscle': '💪',
+ 'mushroom': '🍄',
+ 'musical_keyboard': '🎹',
+ 'musical_note': '🎵',
+ 'musical_score': '🎼',
+ 'mute': '🔇',
+ 'mx_claus': '🧑️🎄',
+ 'myanmar': '🇲🇲',
+ 'nail_care': '💅',
+ 'name_badge': '📛',
+ 'namibia': '🇳🇦',
+ 'national_park': '🏞',
+ 'nauru': '🇳🇷',
+ 'nauseated_face': '🤢',
+ 'nazar_amulet': '🧿',
+ 'necktie': '👔',
+ 'negative_squared_cross_mark': '❎',
+ 'nepal': '🇳🇵',
+ 'nerd_face': '🤓',
+ 'nesting_dolls': '🪆',
+ 'netherlands': '🇳🇱',
+ 'neutral_face': '😐',
+ 'new': '🆕',
+ 'new_caledonia': '🇳🇨',
+ 'new_moon': '🌑',
+ 'new_moon_with_face': '🌚',
+ 'new_zealand': '🇳🇿',
+ 'newspaper': '📰',
+ 'newspaper_roll': '🗞',
+ 'next_track_button': '⏭',
+ 'ng': '🆖',
+ 'ng_man': '🙅️♂',
+ 'ng_woman': '🙅️♀',
+ 'nicaragua': '🇳🇮',
+ 'niger': '🇳🇪',
+ 'nigeria': '🇳🇬',
+ 'night_with_stars': '🌃',
+ 'nine': '9️⃣',
+ 'ninja': '🥷',
+ 'niue': '🇳🇺',
+ 'no_bell': '🔕',
+ 'no_bicycles': '🚳',
+ 'no_entry': '⛔',
+ 'no_entry_sign': '🚫',
+ 'no_good': '🙅',
+ 'no_good_man': '🙅♂️',
+ 'no_good_woman': '🙅',
+ 'no_mobile_phones': '📵',
+ 'no_mouth': '😶',
+ 'no_pedestrians': '🚷',
+ 'no_smoking': '🚭',
+ 'non-potable_water': '🚱',
+ 'norfolk_island': '🇳🇫',
+ 'north_korea': '🇰🇵',
+ 'northern_mariana_islands': '🇲🇵',
+ 'norway': '🇳🇴',
+ 'nose': '👃',
+ 'notebook': '📓',
+ 'notebook_with_decorative_cover': '📔',
+ 'notes': '🎶',
+ 'nut_and_bolt': '🔩',
+ 'o': '⭕',
+ 'o2': '🅾️',
+ 'ocean': '🌊',
+ 'octopus': '🐙',
+ 'oden': '🍢',
+ 'office': '🏢',
+ 'office_worker': '🧑️💼',
+ 'oil_drum': '🛢',
+ 'ok': '🆗',
+ 'ok_hand': '👌',
+ 'ok_man': '🙆♂️',
+ 'ok_person': '🙆',
+ 'ok_woman': '🙆',
+ 'old_key': '🗝',
+ 'older_adult': '🧓',
+ 'older_man': '👴',
+ 'older_woman': '👵',
+ 'olive': '🫒',
+ 'om': '🕉',
+ 'oman': '🇴🇲',
+ 'on': '🔛',
+ 'oncoming_automobile': '🚘',
+ 'oncoming_bus': '🚍',
+ 'oncoming_police_car': '🚔',
+ 'oncoming_taxi': '🚖',
+ 'one': '1️⃣',
+ 'one_piece_swimsuit': '🩱',
+ 'onion': '🧅',
+ 'open_book': '📖',
+ 'open_file_folder': '📂',
+ 'open_hands': '👐',
+ 'open_mouth': '😮',
+ 'open_umbrella': '☂',
+ 'ophiuchus': '⛎',
+ 'orange': '🍊',
+ 'orange_book': '📙',
+ 'orange_circle': '🟠',
+ 'orange_heart': '🧡',
+ 'orange_square': '🟧',
+ 'orangutan': '🦧',
+ 'orthodox_cross': '☦',
+ 'otter': '🦦',
+ 'outbox_tray': '📤',
+ 'owl': '🦉',
+ 'ox': '🐂',
+ 'oyster': '🦪',
+ 'package': '📦',
+ 'page_facing_up': '📄',
+ 'page_with_curl': '📃',
+ 'pager': '📟',
+ 'paintbrush': '🖌',
+ 'pakistan': '🇵🇰',
+ 'palau': '🇵🇼',
+ 'palestinian_territories': '🇵🇸',
+ 'palm_tree': '🌴',
+ 'palms_up': '🤲',
+ 'palms_up_together': '🤲',
+ 'panama': '🇵🇦',
+ 'pancakes': '🥞',
+ 'panda_face': '🐼',
+ 'paperclip': '📎',
+ 'paperclips': '🖇',
+ 'papua_new_guinea': '🇵🇬',
+ 'parachute': '🪂',
+ 'paraguay': '🇵🇾',
+ 'parasol_on_ground': '⛱',
+ 'parking': '🅿️',
+ 'parrot': '🦜',
+ 'part_alternation_mark': '〽️',
+ 'partly_sunny': '⛅',
+ 'partying': '🥳',
+ 'partying_face': '🥳',
+ 'passenger_ship': '🛳',
+ 'passport_control': '🛂',
+ 'pause_button': '⏸',
+ 'paw_prints': '🐾',
+ 'peace_symbol': '☮',
+ 'peach': '🍑',
+ 'peacock': '🦚',
+ 'peanuts': '🥜',
+ 'pear': '🍐',
+ 'pen': '🖊',
+ 'pencil': '📝',
+ 'pencil2': '✏️',
+ 'penguin': '🐧',
+ 'pensive': '😔',
+ 'people_holding_hands': '🧑️🤝️🧑',
+ 'people_hugging': '🫂',
+ 'performing_arts': '🎭',
+ 'persevere': '😣',
+ 'person_bald': '🧑️🦲',
+ 'person_curly_hair': '🧑️🦱',
+ 'person_feeding_baby': '🧑️🍼',
+ 'person_fencing': '🤺',
+ 'person_in_manual_wheelchair': '🧑️🦽',
+ 'person_in_motorized_wheelchair': '🧑️🦼',
+ 'person_in_tuxedo': '🤵',
+ 'person_red_hair': '🧑️🦰',
+ 'person_white_hair': '🧑️🦳',
+ 'person_with_probing_cane': '🧑️🦯',
+ 'person_with_turban': '👳',
+ 'person_with_veil': '👰',
+ 'peru': '🇵🇪',
+ 'petri_dish': '🧫',
+ 'philippines': '🇵🇭',
+ 'phone': '☎️',
+ 'pick': '⛏',
+ 'pickup_truck': '🛻',
+ 'pie': '🥧',
+ 'pig': '🐷',
+ 'pig2': '🐖',
+ 'pig_nose': '🐽',
+ 'pill': '💊',
+ 'pilot': '🧑️✈',
+ 'pinata': '🪅',
+ 'pinched_fingers': '🤌',
+ 'pinching_hand': '🤏',
+ 'pineapple': '🍍',
+ 'ping_pong': '🏓',
+ 'pirate_flag': '🏴☠️',
+ 'pisces': '♓',
+ 'pitcairn_islands': '🇵🇳',
+ 'pizza': '🍕',
+ 'placard': '🪧',
+ 'place_of_worship': '🛐',
+ 'plate_with_cutlery': '🍽',
+ 'play_or_pause_button': '⏯',
+ 'pleading': '🥺',
+ 'pleading_face': '🥺',
+ 'plunger': '🪠',
+ 'point_down': '👇',
+ 'point_left': '👈',
+ 'point_right': '👉',
+ 'point_up': '☝',
+ 'point_up_2': '👆',
+ 'poland': '🇵🇱',
+ 'polar_bear': '🐻️❄',
+ 'police_car': '🚓',
+ 'police_officer': '👮',
+ 'policeman': '👮',
+ 'policewoman': '👮♀️',
+ 'poodle': '🐩',
+ 'poop': '💩',
+ 'popcorn': '🍿',
+ 'portugal': '🇵🇹',
+ 'post_office': '🏣',
+ 'postal_horn': '📯',
+ 'postbox': '📮',
+ 'potable_water': '🚰',
+ 'potato': '🥔',
+ 'potted_plant': '🪴',
+ 'pouch': '👝',
+ 'poultry_leg': '🍗',
+ 'pound': '💷',
+ 'pout': '😡',
+ 'pouting_cat': '😾',
+ 'pouting_face': '🙎',
+ 'pouting_man': '🙎♂️',
+ 'pouting_woman': '🙎',
+ 'pray': '🙏',
+ 'prayer_beads': '📿',
+ 'pregnant_woman': '🤰',
+ 'pretzel': '🥨',
+ 'previous_track_button': '⏮',
+ 'prince': '🤴',
+ 'princess': '👸',
+ 'printer': '🖨',
+ 'probing_cane': '🦯',
+ 'puerto_rico': '🇵🇷',
+ 'punch': '👊',
+ 'purple_circle': '🟣',
+ 'purple_heart': '💜',
+ 'purple_square': '🟪',
+ 'purse': '👛',
+ 'pushpin': '📌',
+ 'put_litter_in_its_place': '🚮',
+ 'qatar': '🇶🇦',
+ 'question': '❓',
+ 'rabbit': '🐰',
+ 'rabbit2': '🐇',
+ 'raccoon': '🦝',
+ 'racehorse': '🐎',
+ 'racing_car': '🏎',
+ 'radio': '📻',
+ 'radio_button': '🔘',
+ 'radioactive': '☢',
+ 'rage': '😡',
+ 'railway_car': '🚃',
+ 'railway_track': '🛤',
+ 'rainbow': '🌈',
+ 'rainbow_flag': '🏳️🌈',
+ 'raised_back_of_hand': '🤚',
+ 'raised_eyebrow': '🤨',
+ 'raised_hand': '✋',
+ 'raised_hand_with_fingers_splayed': '🖐',
+ 'raised_hands': '🙌',
+ 'raising_hand': '🙋',
+ 'raising_hand_man': '🙋♂️',
+ 'raising_hand_woman': '🙋',
+ 'ram': '🐏',
+ 'ramen': '🍜',
+ 'rat': '🐀',
+ 'razor': '🪒',
+ 'receipt': '🧾',
+ 'record_button': '⏺',
+ 'recycle': '♻️',
+ 'red_car': '🚗',
+ 'red_circle': '🔴',
+ 'red_envelope': '🧧',
+ 'red_haired_man': '👨️🦰',
+ 'red_haired_woman': '👩️🦰',
+ 'red_square': '🟥',
+ 'registered': '®️',
+ 'relaxed': '☺️',
+ 'relieved': '😌',
+ 'reminder_ribbon': '🎗',
+ 'repeat': '🔁',
+ 'repeat_one': '🔂',
+ 'rescue_worker_helmet': '⛑',
+ 'restroom': '🚻',
+ 'reunion': '🇷🇪',
+ 'revolving_hearts': '💞',
+ 'rewind': '⏪',
+ 'rhinoceros': '🦏',
+ 'ribbon': '🎀',
+ 'rice': '🍚',
+ 'rice_ball': '🍙',
+ 'rice_cracker': '🍘',
+ 'rice_scene': '🎑',
+ 'right_anger_bubble': '🗯',
+ 'ring': '💍',
+ 'ringed_planet': '🪐',
+ 'robot': '🤖',
+ 'rock': '🪨',
+ 'rocket': '🚀',
+ 'rofl': '🤣',
+ 'roll_eyes': '🙄',
+ 'roll_of_paper': '🧻',
+ 'roller_coaster': '🎢',
+ 'roller_skate': '🛼',
+ 'romania': '🇷🇴',
+ 'rooster': '🐓',
+ 'rose': '🌹',
+ 'rosette': '🏵',
+ 'rotating_light': '🚨',
+ 'round_pushpin': '📍',
+ 'rowboat': '🚣',
+ 'rowing_man': '🚣',
+ 'rowing_woman': '🚣♀️',
+ 'ru': '🇷🇺',
+ 'rugby_football': '🏉',
+ 'runner': '🏃',
+ 'running': '🏃',
+ 'running_man': '🏃',
+ 'running_shirt_with_sash': '🎽',
+ 'running_woman': '🏃♀️',
+ 'rwanda': '🇷🇼',
+ 'sa': '🈂️',
+ 'safety_pin': '🧷',
+ 'safety_vest': '🦺',
+ 'sagittarius': '♐',
+ 'sailboat': '⛵',
+ 'sake': '🍶',
+ 'salt': '🧂',
+ 'samoa': '🇼🇸',
+ 'san_marino': '🇸🇲',
+ 'sandal': '👡',
+ 'sandwich': '🥪',
+ 'santa': '🎅',
+ 'sao_tome_principe': '🇸🇹',
+ 'sari': '🥻',
+ 'sassy_man': '💁️♂',
+ 'sassy_woman': '💁️♀',
+ 'satellite': '📡',
+ 'satisfied': '😆',
+ 'saudi_arabia': '🇸🇦',
+ 'sauna_man': '🧖️♂',
+ 'sauna_person': '🧖',
+ 'sauna_woman': '🧖️♀',
+ 'sauropod': '🦕',
+ 'saxophone': '🎷',
+ 'scarf': '🧣',
+ 'school': '🏫',
+ 'school_satchel': '🎒',
+ 'scientist': '🧑️🔬',
+ 'scissors': '✂️',
+ 'scorpion': '🦂',
+ 'scorpius': '♏',
+ 'scotland': '🏴',
+ 'scream': '😱',
+ 'scream_cat': '🙀',
+ 'screwdriver': '🪛',
+ 'scroll': '📜',
+ 'seal': '🦭',
+ 'seat': '💺',
+ 'secret': '㊙️',
+ 'see_no_evil': '🙈',
+ 'seedling': '🌱',
+ 'selfie': '🤳',
+ 'senegal': '🇸🇳',
+ 'serbia': '🇷🇸',
+ 'service_dog': '🐕️🦺',
+ 'seven': '7️⃣',
+ 'sewing_needle': '🪡',
+ 'seychelles': '🇸🇨',
+ 'shallow_pan_of_food': '🥘',
+ 'shamrock': '☘',
+ 'shark': '🦈',
+ 'shaved_ice': '🍧',
+ 'sheep': '🐑',
+ 'shell': '🐚',
+ 'shield': '🛡',
+ 'shinto_shrine': '⛩',
+ 'ship': '🚢',
+ 'shirt': '👕',
+ 'shit': '💩',
+ 'shoe': '👞',
+ 'shopping': '🛍',
+ 'shopping_cart': '🛒',
+ 'shorts': '🩳',
+ 'shower': '🚿',
+ 'shrimp': '🦐',
+ 'shrug': '🤷',
+ 'shushing': '🤫',
+ 'shushing_face': '🤫',
+ 'sierra_leone': '🇸🇱',
+ 'signal_strength': '📶',
+ 'singapore': '🇸🇬',
+ 'singer': '🧑️🎤',
+ 'sint_maarten': '🇸🇽',
+ 'six': '6️⃣',
+ 'six_pointed_star': '🔯',
+ 'skateboard': '🛹',
+ 'ski': '🎿',
+ 'skier': '⛷',
+ 'skull': '💀',
+ 'skull_and_crossbones': '☠',
+ 'skunk': '🦨',
+ 'sled': '🛷',
+ 'sleeping': '😴',
+ 'sleeping_bed': '🛌',
+ 'sleepy': '😪',
+ 'slightly_frowning_face': '🙁',
+ 'slightly_smiling_face': '🙂',
+ 'slot_machine': '🎰',
+ 'sloth': '🦥',
+ 'slovakia': '🇸🇰',
+ 'slovenia': '🇸🇮',
+ 'small_airplane': '🛩',
+ 'small_blue_diamond': '🔹',
+ 'small_orange_diamond': '🔸',
+ 'small_red_triangle': '🔺',
+ 'small_red_triangle_down': '🔻',
+ 'smile': '😄',
+ 'smile_cat': '😸',
+ 'smiley': '😃',
+ 'smiley_cat': '😺',
+ 'smiling_face_with_tear': '🥲',
+ 'smiling_face_with_three_hearts': '🥰',
+ 'smiling_imp': '😈',
+ 'smirk': '😏',
+ 'smirk_cat': '😼',
+ 'smoking': '🚬',
+ 'snail': '🐌',
+ 'snake': '🐍',
+ 'sneezing_face': '🤧',
+ 'snowboarder': '🏂',
+ 'snowflake': '❄️',
+ 'snowman': '⛄',
+ 'snowman_with_snow': '☃',
+ 'soap': '🧼',
+ 'sob': '😭',
+ 'soccer': '⚽',
+ 'socks': '🧦',
+ 'softball': '🥎',
+ 'solomon_islands': '🇸🇧',
+ 'somalia': '🇸🇴',
+ 'soon': '🔜',
+ 'sorceress': '🧙♀️',
+ 'sos': '🆘',
+ 'sound': '🔉',
+ 'south_africa': '🇿🇦',
+ 'south_georgia_south_sandwich_islands': '🇬🇸',
+ 'south_sudan': '🇸🇸',
+ 'space_invader': '👾',
+ 'spades': '♠️',
+ 'spaghetti': '🍝',
+ 'sparkle': '❇️',
+ 'sparkler': '🎇',
+ 'sparkles': '✨',
+ 'sparkling_heart': '💖',
+ 'speak_no_evil': '🙊',
+ 'speaker': '🔈',
+ 'speaking_head': '🗣',
+ 'speech_balloon': '💬',
+ 'speedboat': '🚤',
+ 'spider': '🕷',
+ 'spider_web': '🕸',
+ 'spiral_calendar': '🗓',
+ 'spiral_notepad': '🗒',
+ 'sponge': '🧽',
+ 'spoon': '🥄',
+ 'squid': '🦑',
+ 'sri_lanka': '🇱🇰',
+ 'st_barthelemy': '🇧🇱',
+ 'st_helena': '🇸🇭',
+ 'st_kitts_nevis': '🇰🇳',
+ 'st_lucia': '🇱🇨',
+ 'st_martin': '🇲️🇫',
+ 'st_pierre_miquelon': '🇵🇲',
+ 'st_vincent_grenadines': '🇻🇨',
+ 'stadium': '🏟',
+ 'standing_man': '🧍️♂',
+ 'standing_person': '🧍',
+ 'standing_woman': '🧍️♀',
+ 'star': '⭐',
+ 'star2': '🌟',
+ 'star_and_crescent': '☪',
+ 'star_of_david': '✡',
+ 'star_struck': '🤩',
+ 'stars': '🌠',
+ 'station': '🚉',
+ 'statue_of_liberty': '🗽',
+ 'steak': '🥩',
+ 'steam_locomotive': '🚂',
+ 'stethoscope': '🩺',
+ 'stew': '🍲',
+ 'stop_button': '⏹',
+ 'stop_sign': '🛑',
+ 'stopwatch': '⏱',
+ 'straight_ruler': '📏',
+ 'strawberry': '🍓',
+ 'stuck_out_tongue': '😛',
+ 'stuck_out_tongue_closed_eyes': '😝',
+ 'stuck_out_tongue_winking_eye': '😜',
+ 'student': '🧑️🎓',
+ 'studio_microphone': '🎙',
+ 'stuffed_flatbread': '🥙',
+ 'sudan': '🇸🇩',
+ 'sun_behind_large_cloud': '🌥',
+ 'sun_behind_rain_cloud': '🌦',
+ 'sun_behind_small_cloud': '🌤',
+ 'sun_with_face': '🌞',
+ 'sunflower': '🌻',
+ 'sunglasses': '😎',
+ 'sunny': '☀️',
+ 'sunrise': '🌅',
+ 'sunrise_over_mountains': '🌄',
+ 'superhero': '🦸',
+ 'superhero_man': '🦸️♂',
+ 'superhero_woman': '🦸️♀',
+ 'supervillain': '🦹',
+ 'supervillain_man': '🦹️♂',
+ 'supervillain_woman': '🦹️♀',
+ 'surfer': '🏄',
+ 'surfing_man': '🏄',
+ 'surfing_woman': '🏄♀️',
+ 'suriname': '🇸🇷',
+ 'sushi': '🍣',
+ 'suspension_railway': '🚟',
+ 'svalbard_jan_mayen': '🇸️🇯',
+ 'swan': '🦢',
+ 'swaziland': '🇸🇿',
+ 'sweat': '😓',
+ 'sweat_drops': '💦',
+ 'sweat_smile': '😅',
+ 'sweden': '🇸🇪',
+ 'sweet_potato': '🍠',
+ 'swim_brief': '🩲',
+ 'swimmer': '🏊',
+ 'swimming_man': '🏊',
+ 'swimming_woman': '🏊♀️',
+ 'switzerland': '🇨🇭',
+ 'symbols': '🔣',
+ 'symbols_over_mouth': '🤬',
+ 'synagogue': '🕍',
+ 'syria': '🇸🇾',
+ 'syringe': '💉',
+ 't-rex': '🦖',
+ 'taco': '🌮',
+ 'tada': '🎉',
+ 'taiwan': '🇹🇼',
+ 'tajikistan': '🇹🇯',
+ 'takeout_box': '🥡',
+ 'tamale': '🫔',
+ 'tanabata_tree': '🎋',
+ 'tangerine': '🍊',
+ 'tanzania': '🇹🇿',
+ 'taurus': '♉',
+ 'taxi': '🚕',
+ 'tea': '🍵',
+ 'teacher': '🧑️🏫',
+ 'teapot': '🫖',
+ 'technologist': '🧑️💻',
+ 'teddy_bear': '🧸',
+ 'telephone': '☎️',
+ 'telephone_receiver': '📞',
+ 'telescope': '🔭',
+ 'tennis': '🎾',
+ 'tent': '⛺',
+ 'test_tube': '🧪',
+ 'thailand': '🇹🇭',
+ 'thermometer': '🌡',
+ 'thinking': '🤔',
+ 'thong_sandal': '🩴',
+ 'thought_balloon': '💭',
+ 'thread': '🧵',
+ 'three': '3️⃣',
+ 'thumbsdown': '👎',
+ 'thumbsup': '👍',
+ 'ticket': '🎫',
+ 'tickets': '🎟',
+ 'tiger': '🐯',
+ 'tiger2': '🐅',
+ 'timer_clock': '⏲',
+ 'timor_leste': '🇹🇱',
+ 'tipping_hand_man': '💁♂️',
+ 'tipping_hand_person': '💁',
+ 'tipping_hand_woman': '💁',
+ 'tired_face': '😫',
+ 'tm': '™️',
+ 'togo': '🇹🇬',
+ 'toilet': '🚽',
+ 'toilet_paper': '🧻',
+ 'tokelau': '🇹🇰',
+ 'tokyo_tower': '🗼',
+ 'tomato': '🍅',
+ 'tonga': '🇹🇴',
+ 'tongue': '👅',
+ 'toolbox': '🧰',
+ 'tooth': '🦷',
+ 'toothbrush': '🪥',
+ 'top': '🔝',
+ 'tophat': '🎩',
+ 'tornado': '🌪',
+ 'tr': '🇹🇷',
+ 'trackball': '🖲',
+ 'tractor': '🚜',
+ 'traffic_light': '🚥',
+ 'train': '🚋',
+ 'train2': '🚆',
+ 'tram': '🚊',
+ 'transgender_flag': '🏳️⚧',
+ 'transgender_symbol': '⚧',
+ 'triangular_flag_on_post': '🚩',
+ 'triangular_ruler': '📐',
+ 'trident': '🔱',
+ 'trinidad_tobago': '🇹🇹',
+ 'tristan_da_cunha': '🇹️🇦',
+ 'triumph': '😤',
+ 'trolleybus': '🚎',
+ 'trophy': '🏆',
+ 'tropical_drink': '🍹',
+ 'tropical_fish': '🐠',
+ 'truck': '🚚',
+ 'trumpet': '🎺',
+ 'tshirt': '👕',
+ 'tulip': '🌷',
+ 'tumbler_glass': '🥃',
+ 'tunisia': '🇹🇳',
+ 'turkey': '🦃',
+ 'turkmenistan': '🇹🇲',
+ 'turks_caicos_islands': '🇹🇨',
+ 'turtle': '🐢',
+ 'tuvalu': '🇹🇻',
+ 'tv': '📺',
+ 'twisted_rightwards_arrows': '🔀',
+ 'two': '2️⃣',
+ 'two_hearts': '💕',
+ 'two_men_holding_hands': '👬',
+ 'two_women_holding_hands': '👭',
+ 'u5272': '🈹',
+ 'u5408': '🈴',
+ 'u55b6': '🈺',
+ 'u6307': '🈯',
+ 'u6708': '🈷️',
+ 'u6709': '🈶',
+ 'u6e80': '🈵',
+ 'u7121': '🈚',
+ 'u7533': '🈸',
+ 'u7981': '🈲',
+ 'u7a7a': '🈳',
+ 'uganda': '🇺🇬',
+ 'uk': '🇬🇧',
+ 'ukraine': '🇺🇦',
+ 'umbrella': '☔',
+ 'unamused': '😒',
+ 'underage': '🔞',
+ 'unicorn': '🦄',
+ 'united_arab_emirates': '🇦🇪',
+ 'united_nations': '🇺🇳',
+ 'unlock': '🔓',
+ 'up': '🆙',
+ 'upside_down_face': '🙃',
+ 'uruguay': '🇺🇾',
+ 'us': '🇺🇸',
+ 'us_outlying_islands': '🇺️🇲',
+ 'us_virgin_islands': '🇻🇮',
+ 'uzbekistan': '🇺🇿',
+ 'v': '✌',
+ 'vampire': '🧛',
+ 'vampire_man': '🧛️♂',
+ 'vampire_woman': '🧛️♀',
+ 'vanuatu': '🇻🇺',
+ 'vatican_city': '🇻🇦',
+ 'venezuela': '🇻🇪',
+ 'vertical_traffic_light': '🚦',
+ 'vhs': '📼',
+ 'vibration_mode': '📳',
+ 'video_camera': '📹',
+ 'video_game': '🎮',
+ 'vietnam': '🇻🇳',
+ 'violin': '🎻',
+ 'virgo': '♍',
+ 'volcano': '🌋',
+ 'volleyball': '🏐',
+ 'vomiting': '🤮',
+ 'vomiting_face': '🤮',
+ 'vs': '🆚',
+ 'vulcan_salute': '🖖',
+ 'waffle': '🧇',
+ 'wales': '🏴',
+ 'walking': '🚶',
+ 'walking_man': '🚶',
+ 'walking_woman': '🚶♀️',
+ 'wallis_futuna': '🇼🇫',
+ 'waning_crescent_moon': '🌘',
+ 'waning_gibbous_moon': '🌖',
+ 'warning': '⚠️',
+ 'wastebasket': '🗑',
+ 'watch': '⌚',
+ 'water_buffalo': '🐃',
+ 'water_polo': '🤽',
+ 'watermelon': '🍉',
+ 'wave': '👋',
+ 'wavy_dash': '〰️',
+ 'waxing_crescent_moon': '🌒',
+ 'waxing_gibbous_moon': '🌔',
+ 'wc': '🚾',
+ 'weary': '😩',
+ 'wedding': '💒',
+ 'weight_lifting': '🏋',
+ 'weight_lifting_man': '🏋',
+ 'weight_lifting_woman': '🏋️♀️',
+ 'western_sahara': '🇪🇭',
+ 'whale': '🐳',
+ 'whale2': '🐋',
+ 'wheel_of_dharma': '☸',
+ 'wheelchair': '♿',
+ 'white_check_mark': '✅',
+ 'white_circle': '⚪',
+ 'white_flag': '🏳',
+ 'white_flower': '💮',
+ 'white_haired_man': '👨️🦳',
+ 'white_haired_woman': '👩️🦳',
+ 'white_heart': '🤍',
+ 'white_large_square': '⬜',
+ 'white_medium_small_square': '◽',
+ 'white_medium_square': '◻️',
+ 'white_small_square': '▫️',
+ 'white_square_button': '🔳',
+ 'wilted_flower': '🥀',
+ 'wind_chime': '🎐',
+ 'wind_face': '🌬',
+ 'window': '🪟',
+ 'wine_glass': '🍷',
+ 'wink': '😉',
+ 'wizard': '🧙♂️',
+ 'wolf': '🐺',
+ 'woman': '👩',
+ 'woman_artist': '👩🎨',
+ 'woman_astronaut': '👩🚀',
+ 'woman_beard': '🧔️♀',
+ 'woman_cartwheeling': '🤸♀️',
+ 'woman_cook': '👩🍳',
+ 'woman_dancing': '💃',
+ 'woman_elf': '🧝♀️',
+ 'woman_facepalming': '🤦♀️',
+ 'woman_factory_worker': '👩🏭',
+ 'woman_fairy': '🧚♀️',
+ 'woman_farmer': '👩🌾',
+ 'woman_feeding_baby': '👩️🍼',
+ 'woman_firefighter': '👩🚒',
+ 'woman_genie': '🧞♀️',
+ 'woman_health_worker': '👩⚕️',
+ 'woman_in_lotus_position': '🧘♀️',
+ 'woman_in_manual_wheelchair': '👩️🦽',
+ 'woman_in_motorized_wheelchair': '👩️🦼',
+ 'woman_in_steamy_room': '🧖♀️',
+ 'woman_in_tuxedo': '🤵️♀',
+ 'woman_judge': '👩⚖️',
+ 'woman_juggling': '🤹♀️',
+ 'woman_mechanic': '👩🔧',
+ 'woman_office_worker': '👩💼',
+ 'woman_pilot': '👩✈️',
+ 'woman_playing_handball': '🤾♀️',
+ 'woman_playing_water_polo': '🤽♀️',
+ 'woman_scientist': '👩🔬',
+ 'woman_shrugging': '🤷',
+ 'woman_singer': '👩🎤',
+ 'woman_student': '👩🎓',
+ 'woman_superhero': '🦸♀️',
+ 'woman_supervillain': '🦹♀️',
+ 'woman_teacher': '👩🏫',
+ 'woman_technologist': '👩💻',
+ 'woman_vampire': '🧛♀️',
+ 'woman_with_headscarf': '🧕',
+ 'woman_with_probing_cane': '👩️🦯',
+ 'woman_with_turban': '👳♀️',
+ 'woman_with_veil': '👰️♀',
+ 'woman_zombie': '🧟♀️',
+ 'womans_clothes': '👚',
+ 'womans_hat': '👒',
+ 'women_wrestling': '🤼♀️',
+ 'womens': '🚺',
+ 'wood': '🪵',
+ 'woozy': '🥴',
+ 'woozy_face': '🥴',
+ 'world_map': '🗺',
+ 'worm': '🪱',
+ 'worried': '😟',
+ 'wrench': '🔧',
+ 'wrestling': '🤼',
+ 'writing_hand': '✍',
+ 'x': '❌',
+ 'yarn': '🧶',
+ 'yawning_face': '🥱',
+ 'yellow_circle': '🟡',
+ 'yellow_heart': '💛',
+ 'yellow_square': '🟨',
+ 'yemen': '🇾🇪',
+ 'yen': '💴',
+ 'yin_yang': '☯',
+ 'yo_yo': '🪀',
+ 'yum': '😋',
+ 'zambia': '🇿🇲',
+ 'zany': '🤪',
+ 'zany_face': '🤪',
+ 'zap': '⚡',
+ 'zebra': '🦓',
+ 'zero': '0️⃣',
+ 'zimbabwe': '🇿🇼',
+ 'zipper_mouth_face': '🤐',
+ 'zombie': '🧟',
+ 'zombie_man': '🧟️♂',
+ 'zombie_woman': '🧟️♀',
+ 'zzz': '💤',
+};
diff --git a/pkgs/markdown/lib/src/extension_set.dart b/pkgs/markdown/lib/src/extension_set.dart
new file mode 100644
index 0000000..58a25d8
--- /dev/null
+++ b/pkgs/markdown/lib/src/extension_set.dart
@@ -0,0 +1,103 @@
+import 'block_syntaxes/alert_block_syntax.dart';
+import 'block_syntaxes/block_syntax.dart';
+import 'block_syntaxes/fenced_code_block_syntax.dart';
+import 'block_syntaxes/footnote_def_syntax.dart';
+import 'block_syntaxes/header_with_id_syntax.dart';
+import 'block_syntaxes/ordered_list_with_checkbox_syntax.dart';
+import 'block_syntaxes/setext_header_with_id_syntax.dart';
+import 'block_syntaxes/table_syntax.dart';
+import 'block_syntaxes/unordered_list_with_checkbox_syntax.dart';
+import 'inline_syntaxes/autolink_extension_syntax.dart';
+import 'inline_syntaxes/color_swatch_syntax.dart';
+import 'inline_syntaxes/emoji_syntax.dart';
+import 'inline_syntaxes/inline_html_syntax.dart';
+import 'inline_syntaxes/inline_syntax.dart';
+import 'inline_syntaxes/strikethrough_syntax.dart';
+
+/// ExtensionSets provide a simple grouping mechanism for common Markdown
+/// flavors.
+///
+/// For example, the [gitHubFlavored] set of syntax extensions allows users to
+/// output HTML from their Markdown in a similar fashion to GitHub's parsing.
+class ExtensionSet {
+ /// The [ExtensionSet.none] extension set renders Markdown similar to
+ /// [Markdown.pl].
+ ///
+ /// However, this set does not render _exactly_ the same as Markdown.pl;
+ /// rather it is more-or-less the CommonMark standard of Markdown, without
+ /// fenced code blocks, or inline HTML.
+ ///
+ /// [Markdown.pl]: http://daringfireball.net/projects/markdown/syntax
+ static final ExtensionSet none = ExtensionSet(const [], const []);
+
+ /// The [commonMark] extension set is close to compliance with [CommonMark].
+ ///
+ /// [CommonMark]: http://commonmark.org/
+ static final ExtensionSet commonMark = ExtensionSet(
+ List<BlockSyntax>.unmodifiable(
+ <BlockSyntax>[const FencedCodeBlockSyntax()],
+ ),
+ List<InlineSyntax>.unmodifiable(
+ <InlineSyntax>[InlineHtmlSyntax()],
+ ),
+ );
+
+ /// The [gitHubWeb] extension set renders Markdown similarly to GitHub.
+ ///
+ /// This is different from the [gitHubFlavored] extension set in that GitHub
+ /// actually renders HTML different from straight [GitHub flavored Markdown].
+ ///
+ /// (The only difference currently is that [gitHubWeb] renders headers with
+ /// linkable IDs.)
+ ///
+ /// [GitHub flavored Markdown]: https://github.github.com/gfm/
+ static final ExtensionSet gitHubWeb = ExtensionSet(
+ List<BlockSyntax>.unmodifiable(
+ <BlockSyntax>[
+ const FencedCodeBlockSyntax(),
+ const HeaderWithIdSyntax(),
+ const SetextHeaderWithIdSyntax(),
+ const TableSyntax(),
+ const UnorderedListWithCheckboxSyntax(),
+ const OrderedListWithCheckboxSyntax(),
+ const FootnoteDefSyntax(),
+ const AlertBlockSyntax(),
+ ],
+ ),
+ List<InlineSyntax>.unmodifiable(
+ <InlineSyntax>[
+ InlineHtmlSyntax(),
+ StrikethroughSyntax(),
+ EmojiSyntax(),
+ ColorSwatchSyntax(),
+ AutolinkExtensionSyntax()
+ ],
+ ),
+ );
+
+ /// The [gitHubFlavored] extension set is close to compliance with the
+ /// [GitHub flavored Markdown spec](https://github.github.com/gfm/).
+ static final ExtensionSet gitHubFlavored = ExtensionSet(
+ List<BlockSyntax>.unmodifiable(
+ <BlockSyntax>[
+ const FencedCodeBlockSyntax(),
+ const TableSyntax(),
+ const UnorderedListWithCheckboxSyntax(),
+ const OrderedListWithCheckboxSyntax(),
+ const FootnoteDefSyntax(),
+ ],
+ ),
+ List<InlineSyntax>.unmodifiable(
+ <InlineSyntax>[
+ InlineHtmlSyntax(),
+ StrikethroughSyntax(),
+ AutolinkExtensionSyntax()
+ ],
+ ),
+ );
+
+ final List<BlockSyntax> blockSyntaxes;
+ final List<InlineSyntax> inlineSyntaxes;
+
+ ExtensionSet(this.blockSyntaxes, this.inlineSyntaxes);
+}
diff --git a/pkgs/markdown/lib/src/html_renderer.dart b/pkgs/markdown/lib/src/html_renderer.dart
new file mode 100644
index 0000000..404d870
--- /dev/null
+++ b/pkgs/markdown/lib/src/html_renderer.dart
@@ -0,0 +1,218 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert';
+
+import 'ast.dart';
+import 'block_syntaxes/block_syntax.dart';
+import 'document.dart';
+import 'extension_set.dart';
+import 'inline_syntaxes/inline_syntax.dart';
+
+/// Converts the given string of Markdown to HTML.
+String markdownToHtml(
+ String markdown, {
+ Iterable<BlockSyntax> blockSyntaxes = const [],
+ Iterable<InlineSyntax> inlineSyntaxes = const [],
+ ExtensionSet? extensionSet,
+ Resolver? linkResolver,
+ Resolver? imageLinkResolver,
+ bool inlineOnly = false,
+ bool encodeHtml = true,
+ bool enableTagfilter = false,
+ bool withDefaultBlockSyntaxes = true,
+ bool withDefaultInlineSyntaxes = true,
+}) {
+ final document = Document(
+ blockSyntaxes: blockSyntaxes,
+ inlineSyntaxes: inlineSyntaxes,
+ extensionSet: extensionSet,
+ linkResolver: linkResolver,
+ imageLinkResolver: imageLinkResolver,
+ encodeHtml: encodeHtml,
+ withDefaultBlockSyntaxes: withDefaultBlockSyntaxes,
+ withDefaultInlineSyntaxes: withDefaultInlineSyntaxes,
+ );
+
+ if (inlineOnly) return renderToHtml(document.parseInline(markdown));
+
+ final nodes = document.parse(markdown);
+
+ return '${renderToHtml(nodes, enableTagfilter: enableTagfilter)}\n';
+}
+
+/// Renders [nodes] to HTML.
+String renderToHtml(List<Node> nodes, {bool enableTagfilter = false}) =>
+ HtmlRenderer(
+ enableTagfilter: enableTagfilter,
+ ).render(nodes);
+
+const _blockTags = [
+ 'blockquote',
+ 'h1',
+ 'h2',
+ 'h3',
+ 'h4',
+ 'h5',
+ 'h6',
+ 'hr',
+ 'li',
+ 'ol',
+ 'p',
+ 'pre',
+ 'ul',
+ 'address',
+ 'article',
+ 'aside',
+ 'details',
+ 'dd',
+ 'div',
+ 'dl',
+ 'dt',
+ 'figcaption',
+ 'figure',
+ 'footer',
+ 'header',
+ 'hgroup',
+ 'main',
+ 'nav',
+ 'section',
+ 'table',
+ 'thead',
+ 'tbody',
+ 'th',
+ 'tr',
+ 'td',
+];
+
+/// Translates a parsed AST to HTML.
+class HtmlRenderer implements NodeVisitor {
+ late StringBuffer buffer;
+ late Set<String> uniqueIds;
+
+ final _elementStack = <Element>[];
+ String? _lastVisitedTag;
+ final bool _tagfilterEnabled;
+
+ HtmlRenderer({
+ bool enableTagfilter = false,
+ }) : _tagfilterEnabled = enableTagfilter;
+
+ String render(List<Node> nodes) {
+ buffer = StringBuffer();
+ uniqueIds = <String>{};
+
+ for (final node in nodes) {
+ node.accept(this);
+ }
+
+ return buffer.toString();
+ }
+
+ @override
+ void visitText(Text text) {
+ var content = text.textContent;
+
+ if (_tagfilterEnabled) {
+ content = _filterTags(content);
+ }
+ if (const ['br', 'p', 'li'].contains(_lastVisitedTag)) {
+ final lines = LineSplitter.split(content);
+ content = content.contains('<pre>')
+ ? lines.join('\n')
+ : lines.map((line) => line.trimLeft()).join('\n');
+ if (text.textContent.endsWith('\n')) {
+ content = '$content\n';
+ }
+ }
+ buffer.write(content);
+
+ _lastVisitedTag = null;
+ }
+
+ @override
+ bool visitElementBefore(Element element) {
+ // Hackish. Separate block-level elements with newlines.
+ if (buffer.isNotEmpty && _blockTags.contains(element.tag)) {
+ buffer.writeln();
+ }
+
+ buffer.write('<${element.tag}');
+
+ for (final entry in element.attributes.entries) {
+ buffer.write(' ${entry.key}="${entry.value}"');
+ }
+
+ final generatedId = element.generatedId;
+
+ // attach header anchor ids generated from text
+ if (generatedId != null) {
+ buffer.write(' id="${uniquifyId(generatedId)}"');
+ }
+
+ _lastVisitedTag = element.tag;
+
+ if (element.isEmpty) {
+ // Empty element like <hr/>.
+ buffer.write(' />');
+
+ if (element.tag == 'br') {
+ buffer.write('\n');
+ }
+
+ return false;
+ } else {
+ _elementStack.add(element);
+ buffer.write('>');
+ return true;
+ }
+ }
+
+ @override
+ void visitElementAfter(Element element) {
+ assert(identical(_elementStack.last, element));
+
+ if (element.children != null &&
+ element.children!.isNotEmpty &&
+ _blockTags.contains(_lastVisitedTag) &&
+ _blockTags.contains(element.tag)) {
+ buffer.writeln();
+ } else if (element.tag == 'blockquote') {
+ buffer.writeln();
+ }
+ buffer.write('</${element.tag}>');
+
+ _lastVisitedTag = _elementStack.removeLast().tag;
+ }
+
+ /// Uniquifies an id generated from text.
+ String uniquifyId(String id) {
+ if (!uniqueIds.contains(id)) {
+ uniqueIds.add(id);
+ return id;
+ }
+
+ var suffix = 2;
+ var suffixedId = '$id-$suffix';
+ while (uniqueIds.contains(suffixedId)) {
+ suffixedId = '$id-${suffix++}';
+ }
+ uniqueIds.add(suffixedId);
+ return suffixedId;
+ }
+
+ /// Filters some particular tags, see:
+ /// https://github.github.com/gfm/#disallowed-raw-html-extension-
+ // As said in the specification, this process should happen when rendering
+ // HTML output, so there should not be a dedicated syntax for this extension.
+ String _filterTags(String content) => content.replaceAll(
+ RegExp(
+ '<(?=(?:'
+ 'title|textarea|style|xmp|iframe|noembed|noframes|script|plaintext'
+ ')>)',
+ caseSensitive: false,
+ multiLine: true,
+ ),
+ '<');
+}
diff --git a/pkgs/markdown/lib/src/inline_parser.dart b/pkgs/markdown/lib/src/inline_parser.dart
new file mode 100644
index 0000000..e700ecf
--- /dev/null
+++ b/pkgs/markdown/lib/src/inline_parser.dart
@@ -0,0 +1,355 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'ast.dart';
+import 'charcode.dart';
+import 'document.dart';
+import 'inline_syntaxes/autolink_syntax.dart';
+import 'inline_syntaxes/code_syntax.dart';
+import 'inline_syntaxes/decode_html_syntax.dart';
+import 'inline_syntaxes/delimiter_syntax.dart';
+import 'inline_syntaxes/email_autolink_syntax.dart';
+import 'inline_syntaxes/emphasis_syntax.dart';
+import 'inline_syntaxes/escape_html_syntax.dart';
+import 'inline_syntaxes/escape_syntax.dart';
+import 'inline_syntaxes/image_syntax.dart';
+import 'inline_syntaxes/inline_syntax.dart';
+import 'inline_syntaxes/line_break_syntax.dart';
+import 'inline_syntaxes/link_syntax.dart';
+import 'inline_syntaxes/soft_line_break_syntax.dart';
+import 'inline_syntaxes/text_syntax.dart';
+
+/// Maintains the internal state needed to parse inline span elements in
+/// Markdown.
+class InlineParser {
+ static final List<InlineSyntax> _defaultSyntaxes =
+ List<InlineSyntax>.unmodifiable(<InlineSyntax>[
+ EmailAutolinkSyntax(),
+ AutolinkSyntax(),
+ LineBreakSyntax(),
+ // Parse "**strong**" and "*emphasis*" tags.
+ EmphasisSyntax.asterisk(),
+ // Parse "__strong__" and "_emphasis_" tags.
+ EmphasisSyntax.underscore(),
+ CodeSyntax(),
+ SoftLineBreakSyntax(),
+ // We will add the LinkSyntax once we know about the specific link resolver.
+ ]);
+
+ /// The string of Markdown being parsed.
+ final String source;
+
+ /// The Markdown document this parser is parsing.
+ final Document document;
+
+ final syntaxes = <InlineSyntax>[];
+
+ /// The current read position.
+ int pos = 0;
+
+ /// Starting position of the last unconsumed text.
+ int start = 0;
+
+ /// The delimiter stack tracking possible opening delimiters and closing
+ /// delimiters for [DelimiterSyntax] nodes.
+ final _delimiterStack = <Delimiter>[];
+
+ /// The tree of parsed HTML nodes.
+ final _tree = <Node>[];
+
+ InlineParser(this.source, this.document) {
+ // User specified syntaxes are the first syntaxes to be evaluated.
+ syntaxes.addAll(document.inlineSyntaxes);
+
+ // This first RegExp matches plain text to accelerate parsing. It's written
+ // so that it does not match any prefix of any following syntaxes. Most
+ // Markdown is plain text, so it's faster to match one RegExp per 'word'
+ // rather than fail to match all the following RegExps at each non-syntax
+ // character position.
+ if (document.hasCustomInlineSyntaxes) {
+ // We should be less aggressive in blowing past "words".
+ syntaxes.add(TextSyntax(r'[A-Za-z0-9]+(?=\s)'));
+ } else {
+ syntaxes.add(TextSyntax(r'[ \tA-Za-z0-9]*[A-Za-z0-9](?=\s)'));
+ }
+
+ if (document.withDefaultInlineSyntaxes) {
+ // Custom link resolvers go after the generic text syntax.
+ syntaxes.addAll([
+ EscapeSyntax(),
+ DecodeHtmlSyntax(),
+ LinkSyntax(linkResolver: document.linkResolver),
+ ImageSyntax(linkResolver: document.imageLinkResolver)
+ ]);
+
+ syntaxes.addAll(_defaultSyntaxes);
+ }
+
+ if (encodeHtml) {
+ syntaxes.addAll([
+ EscapeHtmlSyntax(),
+ // Leave already-encoded HTML entities alone. Ensures we don't turn
+ // "&" into "&amp;"
+ TextSyntax('&[#a-zA-Z0-9]*;', startCharacter: $ampersand),
+ ]);
+ }
+ }
+
+ List<Node> parse() {
+ while (!isDone) {
+ // A right bracket (']') is special. Hitting this character triggers the
+ // "look for link or image" procedure.
+ // See https://spec.commonmark.org/0.30/#an-algorithm-for-parsing-nested-emphasis-and-links.
+ if (charAt(pos) == $rbracket) {
+ writeText();
+ _linkOrImage();
+ continue;
+ }
+
+ // See if the current text matches any defined Markdown syntax.
+ if (syntaxes.any((syntax) => syntax.tryMatch(this))) continue;
+
+ // If we got here, it's just text.
+ advanceBy(1);
+ }
+
+ // Write any trailing text content to a Text node.
+ writeText();
+ _processDelimiterRun(-1);
+ _combineAdjacentText(_tree);
+ return _tree;
+ }
+
+ /// Look back through the delimiter stack to see if we've found a link or
+ /// image.
+ ///
+ /// This is the "look for link or image" routine from the CommonMark spec:
+ /// https://spec.commonmark.org/0.30/#look-for-link-or-image.
+ void _linkOrImage() {
+ final index = _delimiterStack
+ .lastIndexWhere((d) => d.char == $lbracket || d.char == $exclamation);
+ if (index == -1) {
+ // Never found a possible open bracket. This is just a literal "]".
+ addNode(Text(']'));
+ advanceBy(1);
+ start = pos;
+ return;
+ }
+ final delimiter = _delimiterStack[index] as SimpleDelimiter;
+ if (!delimiter.isActive) {
+ _delimiterStack.removeAt(index);
+ addNode(Text(']'));
+ advanceBy(1);
+ start = pos;
+ return;
+ }
+ final syntax = delimiter.syntax;
+ if (syntax is LinkSyntax && syntaxes.any((e) => e is LinkSyntax)) {
+ final nodeIndex = _tree.lastIndexWhere((n) => n == delimiter.node);
+ final linkNodes = syntax.close(this, delimiter, null, getChildren: () {
+ _processDelimiterRun(index);
+ // All of the nodes which lie past [index] are children of this
+ // link/image.
+ final children = _tree.sublist(nodeIndex + 1, _tree.length);
+ _tree.removeRange(nodeIndex + 1, _tree.length);
+ return children;
+ });
+ if (linkNodes != null) {
+ _delimiterStack.removeAt(index);
+ if (delimiter.char == $lbracket) {
+ for (final d in _delimiterStack.sublist(0, index)) {
+ if (d.char == $lbracket) d.isActive = false;
+ }
+ }
+ _tree.replaceRange(nodeIndex, _tree.length, linkNodes);
+ advanceBy(1);
+ start = pos;
+ } else {
+ _delimiterStack.removeAt(index);
+ pos = start;
+ advanceBy(1);
+ }
+ } else {
+ throw StateError('Non-link syntax delimiter found with character '
+ '"${delimiter.char}"');
+ }
+ }
+
+ /// Rules 9 and 10.
+ bool _canFormEmphasis(Delimiter opener, Delimiter closer) {
+ if ((opener.canOpen && opener.canClose) ||
+ (closer.canOpen && closer.canClose)) {
+ return (opener.length + closer.length) % 3 != 0 ||
+ (opener.length % 3 == 0 && closer.length % 3 == 0);
+ } else {
+ return true;
+ }
+ }
+
+ /// Processes [DelimiterRun] type delimiters from [bottomIndex] and up.
+ ///
+ /// This is the same strategy as "process emphasis" routine according to the
+ /// CommonMark spec: https://spec.commonmark.org/0.30/#phase-2-inline-structure.
+ void _processDelimiterRun(int bottomIndex) {
+ var currentIndex = bottomIndex + 1;
+ // Track the lowest index where we might find an open delimiter given a
+ // closing delimiter length modulo 3.
+ // Each key in this map is an open delimiter character. Each value is a
+ // 3-element list. Each value in the list is the lowest index for the given
+ // delimiter length modulo 3 (0, 1, 2).
+ final openersBottom = <int, List<int>>{};
+ while (currentIndex < _delimiterStack.length) {
+ final closer = _delimiterStack[currentIndex];
+ if (!closer.canClose || closer is! DelimiterRun) {
+ currentIndex++;
+ continue;
+ }
+ openersBottom.putIfAbsent(closer.char, () => List.filled(3, bottomIndex));
+ final openersBottomPerCloserLength = openersBottom[closer.char]!;
+ final openerBottom = openersBottomPerCloserLength[closer.length % 3];
+ final openerIndex = _delimiterStack.lastIndexWhere(
+ (d) =>
+ d.char == closer.char && d.canOpen && _canFormEmphasis(d, closer),
+ currentIndex - 1);
+ if (openerIndex > bottomIndex && openerIndex > openerBottom) {
+ // Found an opener for [closer].
+ final opener = _delimiterStack[openerIndex];
+ if (opener is! DelimiterRun) {
+ currentIndex++;
+ continue;
+ }
+ final matchedTagIndex = opener.tags.lastIndexWhere((e) =>
+ opener.length >= e.indicatorLength &&
+ closer.length >= e.indicatorLength);
+ if (matchedTagIndex == -1) {
+ currentIndex++;
+ continue;
+ }
+ final matchedTag = opener.tags[matchedTagIndex];
+ final indicatorLength = matchedTag.indicatorLength;
+ final openerTextNode = opener.node;
+ final openerTextNodeIndex = _tree.indexOf(openerTextNode);
+ final closerTextNode = closer.node;
+ var closerTextNodeIndex = _tree.indexOf(closerTextNode);
+ final nodes = opener.syntax.close(
+ this,
+ opener,
+ closer,
+ tag: matchedTag.tag,
+ getChildren: () => _tree.sublist(
+ openerTextNodeIndex + 1,
+ closerTextNodeIndex,
+ ),
+ );
+ // Replace all of the nodes between the opener and the closer (which
+ // are now the new emphasis node's children) with the emphasis node.
+ _tree.replaceRange(
+ openerTextNodeIndex + 1,
+ closerTextNodeIndex,
+ nodes!,
+ );
+ // Slide [closerTextNodeIndex] back accordingly.
+ closerTextNodeIndex = openerTextNodeIndex + 2;
+
+ _delimiterStack.removeRange(openerIndex + 1, currentIndex);
+ // Slide [currentIndex] back accordingly.
+ currentIndex = openerIndex + 1;
+
+ // Remove delimiter characters, possibly removing nodes from the tree
+ // and Delimiters from the delimiter stack.
+ if (opener.length == indicatorLength) {
+ _tree.removeAt(openerTextNodeIndex);
+ _delimiterStack.removeAt(openerIndex);
+ // Slide [currentIndex] and [closerTextNodeIndex] back accordingly.
+ currentIndex--;
+ closerTextNodeIndex--;
+ } else {
+ final newOpenerTextNode =
+ Text(openerTextNode.text.substring(indicatorLength));
+ _tree[openerTextNodeIndex] = newOpenerTextNode;
+ opener.node = newOpenerTextNode;
+ }
+
+ if (closer.length == indicatorLength) {
+ _tree.removeAt(closerTextNodeIndex);
+ _delimiterStack.removeAt(currentIndex);
+ // [currentIndex] has just moved to point at the next delimiter;
+ // leave it.
+ } else {
+ final newCloserTextNode =
+ Text(closerTextNode.text.substring(indicatorLength));
+ _tree[closerTextNodeIndex] = newCloserTextNode;
+ closer.node = newCloserTextNode;
+ // [currentIndex] needs to be considered again; leave it.
+ }
+ } else {
+ // No opener is found.
+ openersBottomPerCloserLength[closer.length % 3] = currentIndex - 1;
+ if (!closer.canOpen) {
+ _delimiterStack.removeAt(currentIndex);
+ // This advances [currentIndex] to the next delimiter.
+ } else {
+ currentIndex++;
+ }
+ }
+ }
+
+ _delimiterStack.removeRange(bottomIndex + 1, _delimiterStack.length);
+ }
+
+ // Combine any remaining adjacent Text nodes. This is important to produce
+ // correct output across newlines, where whitespace is sometimes compressed.
+ void _combineAdjacentText(List<Node> nodes) {
+ for (var i = 0; i < nodes.length - 1; i++) {
+ final node = nodes[i];
+ if (node is Element && node.children != null) {
+ _combineAdjacentText(node.children!);
+ continue;
+ }
+ if (node is Text && nodes[i + 1] is Text) {
+ final buffer =
+ StringBuffer('${node.textContent}${nodes[i + 1].textContent}');
+ var j = i + 2;
+ while (j < nodes.length && nodes[j] is Text) {
+ buffer.write(nodes[j].textContent);
+ j++;
+ }
+ nodes[i] = Text(buffer.toString());
+ nodes.removeRange(i + 1, j);
+ }
+ }
+ }
+
+ int charAt(int index) => source.codeUnitAt(index);
+
+ void writeText() {
+ if (pos == start) {
+ return;
+ }
+ final text = source.substring(start, pos);
+ _tree.add(Text(text));
+ start = pos;
+ }
+
+ /// Add [node] to the current tree.
+ void addNode(Node node) {
+ _tree.add(node);
+ }
+
+ /// Push [delimiter] onto the stack of [Delimiter]s.
+ void pushDelimiter(Delimiter delimiter) => _delimiterStack.add(delimiter);
+
+ bool get isDone => pos == source.length;
+
+ void advanceBy(int length) {
+ pos += length;
+ }
+
+ void consume(int length) {
+ pos += length;
+ start = pos;
+ }
+
+ bool get encodeHtml => document.encodeHtml;
+}
diff --git a/pkgs/markdown/lib/src/inline_syntaxes/autolink_extension_syntax.dart b/pkgs/markdown/lib/src/inline_syntaxes/autolink_extension_syntax.dart
new file mode 100644
index 0000000..0333abb
--- /dev/null
+++ b/pkgs/markdown/lib/src/inline_syntaxes/autolink_extension_syntax.dart
@@ -0,0 +1,156 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../ast.dart';
+import '../charcode.dart';
+import '../inline_parser.dart';
+import '../util.dart';
+import 'inline_syntax.dart';
+
+/// Matches autolinks like `http://foo.com` and `foo@bar.com`.
+class AutolinkExtensionSyntax extends InlineSyntax {
+ static const _linkPattern =
+ // Autolinks can only come at the beginning of a line, after whitespace,
+ // or any of the delimiting characters *, _, ~, and (.
+ // Note: Disable this piece for now, as Safari does not support
+ // lookarounds. Consider re-enabling later.
+ // r'(?<=^|[\s*_~(>])'
+
+ // An extended url autolink will be recognised when one of the schemes
+ // http://, or https://, followed by a valid domain. See
+ // https://github.github.com/gfm/#extended-url-autolink.
+ r'(?:(?:https?|ftp):\/\/|www\.)'
+
+ // A valid domain consists of segments of alphanumeric characters,
+ // underscores (_) and hyphens (-) separated by periods (.). There must
+ // be at least one period, and no underscores may be present in the last
+ // two segments of the domain. See
+ // https://github.github.com/gfm/#valid-domain.
+ r'(?:[-_a-z0-9]+\.)*(?:[-a-z0-9]+\.[-a-z0-9]+)'
+
+ // After a valid domain, zero or more non-space non-< characters may
+ // follow.
+ r'[^\s<]*'
+
+ // Trailing punctuation (specifically, ?, !, ., ,, :, *, _, and ~) will
+ // not be considered part of the autolink, though they may be included in
+ // the interior of the link. See
+ // https://github.github.com/gfm/#extended-autolink-path-validation.
+ // Note: Do not use negative lookbehind, as Safari does not support it.
+ // '(?<![?!.,:*_~])'
+ r'[^\s<?!.,:*_~]';
+
+ // An extended email autolink, see
+ // https://github.github.com/gfm/#extended-email-autolink.
+ static const _emailPattern =
+ r'[-_.+a-z0-9]+@(?:[-_a-z0-9]+\.)+[-_a-z0-9]*[a-z0-9]';
+
+ AutolinkExtensionSyntax()
+ : super(
+ '($_linkPattern)|($_emailPattern)',
+ caseSensitive: false,
+ );
+
+ @override
+ bool tryMatch(InlineParser parser, [int? startMatchPos]) {
+ startMatchPos ??= parser.pos;
+ final startMatch = pattern.matchAsPrefix(parser.source, startMatchPos);
+ if (startMatch == null) {
+ return false;
+ }
+
+ // When it is a link and it is not at the beginning of a line, or preceded
+ // by whitespace, `*`, `_`, `~`, `(`, or `>`, it is invalid. See
+ // https://github.github.com/gfm/#autolinks-extension-.
+ if (startMatch[1] != null && parser.pos > 0) {
+ final precededBy = String.fromCharCode(parser.charAt(parser.pos - 1));
+ const validPrecedingChars = {'\n', ' ', '*', '_', '~', '(', '>'};
+ if (!validPrecedingChars.contains(precededBy)) {
+ return false;
+ }
+ }
+
+ // When it is an email link and followed by `_` or `-`, it is invalid. See
+ // https://github.github.com/gfm/#example-633
+ if (startMatch[2] != null && parser.source.length > startMatch.end) {
+ final followedBy = String.fromCharCode(parser.charAt(startMatch.end));
+ const invalidFollowingChars = {'_', '-'};
+ if (invalidFollowingChars.contains(followedBy)) {
+ return false;
+ }
+ }
+
+ parser.writeText();
+ return onMatch(parser, startMatch);
+ }
+
+ @override
+ bool onMatch(InlineParser parser, Match match) {
+ int consumeLength;
+
+ final isEmailLink = match[2] != null;
+ if (isEmailLink) {
+ consumeLength = match.match.length;
+ } else {
+ consumeLength = _getConsumeLength(match.match);
+ }
+
+ var text = match.match.substring(0, consumeLength);
+ text = parser.encodeHtml ? escapeHtml(text) : text;
+
+ var destination = text;
+ if (isEmailLink) {
+ destination = 'mailto:$destination';
+ } else if (destination[0] == 'w') {
+ // When there is no scheme specified, insert the scheme `http`.
+ destination = 'http://$destination';
+ }
+
+ final anchor = Element.text('a', text)
+ ..attributes['href'] = Uri.encodeFull(destination);
+
+ parser
+ ..addNode(anchor)
+ ..consume(consumeLength);
+
+ return true;
+ }
+
+ int _getConsumeLength(String text) {
+ var excludedLength = 0;
+
+ // When an autolink ends in `)`, see
+ // https://github.github.com/gfm/#example-625.
+ if (text.endsWith(')')) {
+ final match = RegExp(r'(\(.*)?(\)+)$').firstMatch(text)!;
+
+ if (match[1] == null) {
+ excludedLength = match[2]!.length;
+ } else {
+ var parenCount = 0;
+ for (var i = 0; i < text.length; i++) {
+ final char = text.codeUnitAt(i);
+ if (char == $lparen) {
+ parenCount++;
+ } else if (char == $rparen) {
+ parenCount--;
+ }
+ }
+ if (parenCount < 0) {
+ excludedLength = parenCount.abs();
+ }
+ }
+ }
+ // If an autolink ends in a semicolon `;`, see
+ // https://github.github.com/gfm/#example-627
+ else if (text.endsWith(';')) {
+ final match = RegExp(r'&[0-9a-z]+;$').firstMatch(text);
+ if (match != null) {
+ excludedLength = match.match.length;
+ }
+ }
+
+ return text.length - excludedLength;
+ }
+}
diff --git a/pkgs/markdown/lib/src/inline_syntaxes/autolink_syntax.dart b/pkgs/markdown/lib/src/inline_syntaxes/autolink_syntax.dart
new file mode 100644
index 0000000..073c1cc
--- /dev/null
+++ b/pkgs/markdown/lib/src/inline_syntaxes/autolink_syntax.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../ast.dart';
+import '../inline_parser.dart';
+import '../util.dart';
+import 'inline_syntax.dart';
+
+/// Matches autolinks like `<http://foo.com>`.
+class AutolinkSyntax extends InlineSyntax {
+ AutolinkSyntax() : super(r'<(([a-zA-Z][a-zA-Z\-\+\.]+):(?://)?[^\s>]*)>');
+
+ @override
+ bool onMatch(InlineParser parser, Match match) {
+ final url = match[1]!;
+ final text = parser.encodeHtml ? escapeHtml(url) : url;
+ final anchor = Element.text('a', text);
+
+ final destination = normalizeLinkDestination(url);
+ anchor.attributes['href'] =
+ parser.encodeHtml ? escapeHtml(destination) : destination;
+ parser.addNode(anchor);
+
+ return true;
+ }
+}
diff --git a/pkgs/markdown/lib/src/inline_syntaxes/code_syntax.dart b/pkgs/markdown/lib/src/inline_syntaxes/code_syntax.dart
new file mode 100644
index 0000000..35783d3
--- /dev/null
+++ b/pkgs/markdown/lib/src/inline_syntaxes/code_syntax.dart
@@ -0,0 +1,88 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../ast.dart';
+import '../charcode.dart';
+import '../inline_parser.dart';
+import '../util.dart';
+import 'inline_syntax.dart';
+
+/// Matches backtick-enclosed inline code blocks.
+class CodeSyntax extends InlineSyntax {
+ // This pattern matches:
+ //
+ // * a string of backticks (not followed by any more), followed by
+ // * a non-greedy string of anything, including newlines, ending with anything
+ // except a backtick, followed by
+ // * a string of backticks the same length as the first, not followed by any
+ // more.
+ //
+ // This conforms to the delimiters of inline code, both in Markdown.pl, and
+ // CommonMark.
+ static const _pattern = r'(`+(?!`))((?:.|\n)*?[^`])\1(?!`)';
+
+ CodeSyntax() : super(_pattern);
+
+ @override
+ bool tryMatch(InlineParser parser, [int? startMatchPos]) {
+ if (parser.pos > 0 && parser.charAt(parser.pos - 1) == $backquote) {
+ // Not really a match! We can't just sneak past one backtick to try the
+ // next character. An example of this situation would be:
+ //
+ // before ``` and `` after.
+ // ^--parser.pos
+ return false;
+ }
+
+ final match = pattern.matchAsPrefix(parser.source, parser.pos);
+ if (match == null) {
+ return false;
+ }
+ parser.writeText();
+ if (onMatch(parser, match)) parser.consume(match.match.length);
+ return true;
+ }
+
+ @override
+ bool onMatch(InlineParser parser, Match match) {
+ final markerLength = match[1]!.length;
+ final contentLength = match.match.length - markerLength * 2;
+ final contentStart = parser.pos + markerLength;
+ final contentEnd = contentStart + contentLength;
+
+ var code = parser.source.substring(contentStart, contentEnd);
+ if (_shouldStrip(code)) {
+ code = code.substring(1, code.length - 1);
+ }
+ code = code.replaceAll('\n', ' ');
+
+ if (parser.encodeHtml) {
+ code = escapeHtml(code, escapeApos: false);
+ }
+
+ parser.addNode(Element.text('code', code));
+ return true;
+ }
+
+ bool _shouldStrip(String code) {
+ // No stripping occurs if the code span contains only spaces:
+ // https://spec.commonmark.org/0.30/#example-334.
+ if (code.trim().isEmpty) {
+ return false;
+ }
+
+ // Only spaces, and not unicode whitespace in general, are stripped in this
+ // way, see https://spec.commonmark.org/0.30/#example-333.
+ final startsWithSpace = code.startsWith(' ') || code.startsWith('\n');
+ final endsWithSpace = code.endsWith(' ') || code.endsWith('\n');
+
+ // The stripping only happens if the space is on both sides of the string:
+ // https://spec.commonmark.org/0.30/#example-332.
+ if (!startsWithSpace || !endsWithSpace) {
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git a/pkgs/markdown/lib/src/inline_syntaxes/color_swatch_syntax.dart b/pkgs/markdown/lib/src/inline_syntaxes/color_swatch_syntax.dart
new file mode 100644
index 0000000..e44fdbf
--- /dev/null
+++ b/pkgs/markdown/lib/src/inline_syntaxes/color_swatch_syntax.dart
@@ -0,0 +1,79 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../ast.dart';
+import '../charcode.dart';
+import '../inline_parser.dart';
+import '../util.dart';
+import 'inline_syntax.dart';
+
+/// Matches code blocks containing a subset of CSS color syntax.
+class ColorSwatchSyntax extends InlineSyntax {
+ /// This pattern matches:
+ /// * GitHub Flavored Markup supports fewer of these options, GitLab Flavored
+ /// Markup supports all of these. Presumably GitHub will be more complete at
+ /// some point.
+ /// * CSS style '#' prefixed color hex codes in 3,4,6 or 8 digits in length.
+ /// * CSS style RGB()/RgbA()/Hsl()/HSLA() style color declarations, of any
+ /// capitalization.
+ /// EXAMPLES:
+ /// * `#f00`
+ /// * `#BA` (2 digit hex, regex will not match)
+ /// * `#F00a`
+ /// * `#F0BAD` (5 digit hex, regex will not match)
+ /// * `#FF0000`
+ /// * `#F000BAD` (7 digit hex, regex will not match)
+ /// * `#FF0000aA` (GitHub supports only this style)
+ /// * `RGB(0,255,0)`
+ /// * `rgb(0,255,0)`
+ /// * `RGB(0%,100%,0%)`
+ /// * `rgb(0%,100%,0%)`
+ /// * `RGBA(0,255,0,0.3)`
+ /// * `rgba(0,255,0,0.3)`
+ /// * `HSL(540,70%,50%)`
+ /// * `hsl(540,70%,50%)`
+ /// * `HSLA(540,70%,50%,0.3)`
+ /// * `Hsla(540,70%,50%,0.3)`
+ static const _pattern =
+ '`((#([A-Fa-f0-9]{3}|[A-Fa-f0-9]{4}|[A-Fa-f0-9]{6}|[A-Fa-f0-9]{8}))|'
+ r'([Rr][Gg][Bb][Aa]?\((\d+[%]?),(\d+[%]?),(\d+[%]?),?(\d+\.?\d+[%]?)?\))|'
+ r'([Hh][Ss][Ll][Aa]?\((\d+[%]?),(\d+[%]?),(\d+[%]?),?(\d+\.?\d+[%]?)?\)))`';
+
+ ColorSwatchSyntax() : super(_pattern);
+
+ @override
+ bool tryMatch(InlineParser parser, [int? startMatchPos]) {
+ if (parser.pos > 0 && parser.charAt(parser.pos - 1) == $backquote) {
+ // Not really a match! We can't just sneak past one backtick to try the
+ // next character. An example of this situation would be:
+ //
+ // before ``` and `` after.
+ // ^--parser.pos
+ return false;
+ }
+
+ final match = pattern.matchAsPrefix(parser.source, parser.pos);
+ if (match == null) {
+ return false;
+ }
+ parser.writeText();
+ if (onMatch(parser, match)) parser.consume(match.match.length);
+ return true;
+ }
+
+ @override
+ bool onMatch(InlineParser parser, Match match) {
+ var code = match[1]!.trim().replaceAll('\n', ' ');
+
+ if (parser.encodeHtml) code = escapeHtml(code);
+
+ parser.addNode(Element('code', [
+ Text(code),
+ Element.withTag('span')..attributes['style'] = 'background-color:$code;',
+ ])
+ ..attributes['class'] = 'gfm-color_chip');
+
+ return true;
+ }
+}
diff --git a/pkgs/markdown/lib/src/inline_syntaxes/decode_html_syntax.dart b/pkgs/markdown/lib/src/inline_syntaxes/decode_html_syntax.dart
new file mode 100644
index 0000000..1af15d5
--- /dev/null
+++ b/pkgs/markdown/lib/src/inline_syntaxes/decode_html_syntax.dart
@@ -0,0 +1,51 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../assets/html_entities.dart';
+import '../ast.dart';
+import '../charcode.dart';
+import '../inline_parser.dart';
+import '../patterns.dart';
+import '../util.dart';
+import 'inline_syntax.dart';
+
+/// Decodes numeric character references, for example decode `#` to `#`.
+// https://spec.commonmark.org/0.30/#entity-and-numeric-character-references
+class DecodeHtmlSyntax extends InlineSyntax {
+ DecodeHtmlSyntax()
+ : super(htmlCharactersPattern.pattern,
+ caseSensitive: false, startCharacter: $ampersand);
+
+ @override
+ bool tryMatch(InlineParser parser, [int? startMatchPos]) {
+ if (parser.pos > 0 && parser.charAt(parser.pos - 1) == $backquote) {
+ return false;
+ }
+
+ final match = pattern.matchAsPrefix(parser.source, parser.pos);
+ if (match == null) {
+ return false;
+ }
+
+ if (match[1] != null && htmlEntitiesMap[match.match] == null) {
+ return false;
+ }
+
+ parser.writeText();
+ if (onMatch(parser, match)) parser.consume(match.match.length);
+ return true;
+ }
+
+ @override
+ bool onMatch(InlineParser parser, Match match) {
+ var decodedText = decodeHtmlCharacterFromMatch(match);
+
+ if (parser.encodeHtml) {
+ decodedText = escapeHtml(decodedText);
+ }
+
+ parser.addNode(Text(decodedText));
+ return true;
+ }
+}
diff --git a/pkgs/markdown/lib/src/inline_syntaxes/delimiter_syntax.dart b/pkgs/markdown/lib/src/inline_syntaxes/delimiter_syntax.dart
new file mode 100644
index 0000000..f26bdc9
--- /dev/null
+++ b/pkgs/markdown/lib/src/inline_syntaxes/delimiter_syntax.dart
@@ -0,0 +1,337 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../ast.dart';
+import '../inline_parser.dart';
+import '../patterns.dart';
+import 'inline_syntax.dart';
+
+/// Matches syntax that has a pair of tags and becomes an element, like `*` for
+/// `<em>`. Allows nested tags.
+class DelimiterSyntax extends InlineSyntax {
+ /// Whether this is parsed according to the same nesting rules as [emphasis
+ /// delimiters][].
+ ///
+ /// [emphasis delimiters]: https://spec.commonmark.org/0.30/#can-open-emphasis
+ final bool requiresDelimiterRun;
+
+ /// Whether to allow intra-word delimiter runs. CommonMark emphasis and
+ /// strong emphasis does not allow this, but GitHub-Flavored Markdown allows
+ /// it on strikethrough.
+ final bool allowIntraWord;
+
+ final List<DelimiterTag>? tags;
+
+ /// Creates a new [DelimiterSyntax] which matches text on [pattern].
+ ///
+ /// The [pattern] is used to find the matching text. If [requiresDelimiterRun]
+ /// is passed, this syntax parses according to the same nesting rules as
+ /// emphasis delimiters. If [startCharacter] is passed, it is used as a
+ /// pre-matching check which is faster than matching against [pattern].
+ DelimiterSyntax(
+ super.pattern, {
+ this.requiresDelimiterRun = false,
+ super.startCharacter,
+ this.allowIntraWord = false,
+ this.tags,
+ });
+
+ @override
+ bool onMatch(InlineParser parser, Match match) {
+ final runLength = match.group(0)!.length;
+ final matchStart = parser.pos;
+ final matchEnd = parser.pos + runLength;
+ final text = Text(parser.source.substring(matchStart, matchEnd));
+ if (!requiresDelimiterRun) {
+ parser.pushDelimiter(SimpleDelimiter(
+ node: text,
+ length: runLength,
+ char: parser.source.codeUnitAt(matchStart),
+ canOpen: true,
+ canClose: false,
+ syntax: this,
+ endPos: matchEnd,
+ ));
+ parser.addNode(text);
+ return true;
+ }
+
+ final delimiterRun = DelimiterRun.tryParse(
+ parser,
+ matchStart,
+ matchEnd,
+ syntax: this,
+ node: text,
+ allowIntraWord: allowIntraWord,
+ tags: tags ?? const [],
+ );
+ if (delimiterRun != null) {
+ parser.pushDelimiter(delimiterRun);
+ parser.addNode(text);
+ return true;
+ } else {
+ parser.advanceBy(runLength);
+ return false;
+ }
+ }
+
+ /// Attempts to close this tag at the current position.
+ ///
+ /// If a tag cannot be closed at the current position (for example, if a link
+ /// reference cannot be found for a link tag's label), then `null` is
+ /// returned.
+ ///
+ /// If a tag can be closed at the current position, then this method calls
+ /// [getChildren], in which [parser] parses any nested text into child nodes.
+ /// The returned [Iterable] includes these children nodes.
+ Iterable<Node>? close(
+ InlineParser parser,
+ Delimiter opener,
+ Delimiter closer, {
+ required String tag,
+ required List<Node> Function() getChildren,
+ }) {
+ return [Element(tag, getChildren())];
+ }
+}
+
+class DelimiterTag {
+ DelimiterTag(this.tag, this.indicatorLength);
+
+ // Tag name of the HTML element.
+ final String tag;
+
+ final int indicatorLength;
+}
+
+/// A delimiter indicating the possible "open" or possible "close" of a tag for
+/// a [DelimiterSyntax].
+abstract class Delimiter {
+ /// The [Text] node representing the plain text representing this delimiter.
+ abstract Text node;
+
+ /// The type of delimiter.
+ ///
+ /// For the two-character image delimiter, `](links).
+ ///
+ /// Once we have parsed `Text [`, there is one (pending) link in the state
+ /// stack. It is, by default, active. Once we parse the next possible link,
+ /// `[more](links)`, as a real link, we must deactive the pending links (just
+ /// the one, in this case).
+ abstract bool isActive;
+
+ /// Whether this delimiter can open emphasis or strong emphasis.
+ bool get canOpen;
+
+ /// Whether this delimiter can close emphasis or strong emphasis.
+ bool get canClose;
+
+ /// The syntax which uses this delimiter to parse a tag.
+ DelimiterSyntax get syntax;
+}
+
+/// A simple delimiter implements the [Delimiter] interface with basic fields,
+/// and does not have the concept of "left-flanking" or "right-flanking".
+class SimpleDelimiter implements Delimiter {
+ @override
+ Text node;
+
+ @override
+ final int char;
+
+ @override
+ final int length;
+
+ @override
+ bool isActive;
+
+ @override
+ final bool canOpen;
+
+ @override
+ final bool canClose;
+
+ @override
+ final DelimiterSyntax syntax;
+
+ final int endPos;
+
+ SimpleDelimiter({
+ required this.node,
+ required this.char,
+ required this.length,
+ required this.canOpen,
+ required this.canClose,
+ required this.syntax,
+ required this.endPos,
+ }) : isActive = true;
+}
+
+/// An implementation of [Delimiter] which uses concepts of "left-flanking" and
+/// "right-flanking" to determine the values of [canOpen] and [canClose].
+///
+/// This is primarily used when parsing emphasis and strong emphasis, but can
+/// also be used by other extensions of [DelimiterSyntax].
+class DelimiterRun implements Delimiter {
+ /// According to
+ /// [CommonMark](https://spec.commonmark.org/0.30/#unicode-punctuation-character):
+ ///
+ /// > A punctuation character is an ASCII punctuation character or anything in
+ /// > the general Unicode categories `Pc`, `Pd`, `Pe`, `Pf`, `Pi`, `Po`, or
+ /// > `Ps`.
+ // This RegExp is inspired by
+ // https://github.com/commonmark/commonmark.js/blob/1f7d09099c20d7861a674674a5a88733f55ff729/lib/inlines.js#L39.
+ // I don't know if there is any way to simplify it or maintain it.
+ static final unicodePunctuationPattern = RegExp('['
+ '$asciiPunctuationEscaped'
+ r'\xA1\xA7\xAB\xB6\xB7\xBB\xBF\u037E\u0387\u055A-\u055F\u0589\u058A\u05BE'
+ r'\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061E'
+ r'\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E'
+ r'\u0964\u0965\u0970\u0AF0\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12\u0F14'
+ r'\u0F3A-\u0F3D\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB'
+ r'\u1360-\u1368\u1400\u166D\u166E\u169B\u169C\u16EB-\u16ED\u1735\u1736'
+ r'\u17D4-\u17D6\u17D8-\u17DA\u1800-\u180A\u1944\u1945\u1A1E\u1A1F'
+ r'\u1AA0-\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E'
+ r'\u1C7F\u1CC0-\u1CC7\u1CD3\u2010-\u2027\u2030-\u2043\u2045-\u2051'
+ r'\u2053-\u205E\u207D\u207E\u208D\u208E\u2308-\u230B\u2329\u232A'
+ r'\u2768-\u2775\u27C5\u27C6\u27E6-\u27EF\u2983-\u2998\u29D8-\u29DB\u29FC'
+ r'\u29FD\u2CF9-\u2CFC\u2CFE\u2CFF\u2D70\u2E00-\u2E2E\u2E30-\u2E42'
+ r'\u3001-\u3003\u3008-\u3011\u3014-\u301F\u3030\u303D\u30A0\u30FB\uA4FE'
+ r'\uA4FF\uA60D-\uA60F\uA673\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF'
+ r'\uA8F8-\uA8FA\uA8FC\uA92E\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF'
+ r'\uAA5C-\uAA5F\uAADE\uAADF\uAAF0\uAAF1\uABEB\uFD3E\uFD3F\uFE10-\uFE19'
+ r'\uFE30-\uFE52\uFE54-\uFE61\uFE63\uFE68\uFE6A\uFE6B\uFF01-\uFF03'
+ r'\uFF05-\uFF0A\uFF0C-\uFF0F\uFF1A\uFF1B\uFF1F\uFF20\uFF3B-\uFF3D\uFF3F'
+ r'\uFF5B\uFF5D\uFF5F-\uFF65'
+ ']');
+
+ /// Unicode whitespace.
+ // See https://spec.commonmark.org/0.30/#unicode-whitespace-character.
+ // Unicode Zs: https://www.compart.com/en/unicode/category.
+ static const unicodeWhitespace = '\u0020\u0009\u000A\u000C\u000D'
+ '\u00A0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008'
+ '\u2009\u200A\u202F\u205F\u3000';
+
+ @override
+ Text node;
+
+ @override
+ final int char;
+
+ @override
+ int get length => node.text.length;
+
+ @override
+ bool isActive;
+
+ @override
+ final DelimiterSyntax syntax;
+
+ final bool allowIntraWord;
+
+ @override
+ final bool canOpen;
+
+ @override
+ final bool canClose;
+
+ final List<DelimiterTag> tags;
+
+ DelimiterRun._({
+ required this.node,
+ required this.char,
+ required this.syntax,
+ required this.tags,
+ required bool isLeftFlanking,
+ required bool isRightFlanking,
+ required bool isPrecededByPunctuation,
+ required bool isFollowedByPunctuation,
+ required this.allowIntraWord,
+ }) : canOpen = isLeftFlanking &&
+ (!isRightFlanking || allowIntraWord || isPrecededByPunctuation),
+ canClose = isRightFlanking &&
+ (!isLeftFlanking || allowIntraWord || isFollowedByPunctuation),
+ isActive = true;
+
+ /// Tries to parse a delimiter run from [runStart] (inclusive) to [runEnd]
+ /// (exclusive).
+ static DelimiterRun? tryParse(
+ InlineParser parser,
+ int runStart,
+ int runEnd, {
+ required DelimiterSyntax syntax,
+ required List<DelimiterTag> tags,
+ required Text node,
+ bool allowIntraWord = false,
+ }) {
+ bool precededByWhitespace;
+ bool followedByWhitespace;
+ bool precededByPunctuation;
+ bool followedByPunctuation;
+
+ if (runStart == 0) {
+ precededByWhitespace = true;
+ precededByPunctuation = false;
+ } else {
+ final preceding = parser.source.substring(runStart - 1, runStart);
+ precededByWhitespace = unicodeWhitespace.contains(preceding);
+ precededByPunctuation = !precededByWhitespace &&
+ unicodePunctuationPattern.hasMatch(preceding);
+ }
+
+ if (runEnd == parser.source.length) {
+ followedByWhitespace = true;
+ followedByPunctuation = false;
+ } else {
+ final following = parser.source.substring(runEnd, runEnd + 1);
+ followedByWhitespace = unicodeWhitespace.contains(following);
+ followedByPunctuation = !followedByWhitespace &&
+ unicodePunctuationPattern.hasMatch(following);
+ }
+
+ // If it is a left-flanking delimiter run, see
+ // https://spec.commonmark.org/0.30/#left-flanking-delimiter-run.
+ final isLeftFlanking = !followedByWhitespace &&
+ (!followedByPunctuation ||
+ precededByWhitespace ||
+ precededByPunctuation);
+
+ // If it is a right-flanking delimiter run, see
+ // https://spec.commonmark.org/0.30/#right-flanking-delimiter-run.
+ final isRightFlanking = !precededByWhitespace &&
+ (!precededByPunctuation ||
+ followedByWhitespace ||
+ followedByPunctuation);
+
+ // Make sure the shorter delimiter takes precedence.
+ tags.sort((a, b) => a.indicatorLength.compareTo(b.indicatorLength));
+
+ return DelimiterRun._(
+ node: node,
+ char: parser.charAt(runStart),
+ syntax: syntax,
+ tags: tags,
+ isLeftFlanking: isLeftFlanking,
+ isRightFlanking: isRightFlanking,
+ isPrecededByPunctuation: precededByPunctuation,
+ isFollowedByPunctuation: followedByPunctuation,
+ allowIntraWord: allowIntraWord,
+ );
+ }
+
+ @override
+ String toString() => '<char: $char, length: $length, canOpen: $canOpen, '
+ 'canClose: $canClose>';
+}
diff --git a/pkgs/markdown/lib/src/inline_syntaxes/email_autolink_syntax.dart b/pkgs/markdown/lib/src/inline_syntaxes/email_autolink_syntax.dart
new file mode 100644
index 0000000..212f1a4
--- /dev/null
+++ b/pkgs/markdown/lib/src/inline_syntaxes/email_autolink_syntax.dart
@@ -0,0 +1,31 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../ast.dart';
+import '../charcode.dart';
+import '../inline_parser.dart';
+import '../util.dart';
+import 'inline_syntax.dart';
+
+/// Matches autolinks like `<foo@bar.example.com>`.
+///
+/// See <https://spec.commonmark.org/0.30/#email-address>.
+class EmailAutolinkSyntax extends InlineSyntax {
+ static const _email =
+ r'''[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}'''
+ r'''[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*''';
+
+ EmailAutolinkSyntax() : super('<($_email)>', startCharacter: $lt);
+
+ @override
+ bool onMatch(InlineParser parser, Match match) {
+ final url = match[1]!;
+ final text = parser.encodeHtml ? escapeHtml(url) : url;
+ final anchor = Element.text('a', text);
+ anchor.attributes['href'] = Uri.encodeFull('mailto:$url');
+ parser.addNode(anchor);
+
+ return true;
+ }
+}
diff --git a/pkgs/markdown/lib/src/inline_syntaxes/emoji_syntax.dart b/pkgs/markdown/lib/src/inline_syntaxes/emoji_syntax.dart
new file mode 100644
index 0000000..a068c6b
--- /dev/null
+++ b/pkgs/markdown/lib/src/inline_syntaxes/emoji_syntax.dart
@@ -0,0 +1,32 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../ast.dart';
+import '../emojis.dart';
+import '../inline_parser.dart';
+import 'inline_syntax.dart';
+
+/// Matches GitHub Markdown emoji syntax like `:smile:`.
+///
+/// There is no formal specification of GitHub's support for this colon-based
+/// emoji support, so this syntax is based on the results of Markdown-enabled
+/// text fields at github.com.
+class EmojiSyntax extends InlineSyntax {
+ // Emoji "aliases" are mostly limited to lower-case letters, numbers, and
+ // underscores, but GitHub also supports `:+1:` and `:-1:`.
+ EmojiSyntax() : super(':([a-z0-9_+-]+):');
+
+ @override
+ bool onMatch(InlineParser parser, Match match) {
+ final alias = match[1]!;
+ final emoji = emojis[alias];
+ if (emoji == null) {
+ parser.advanceBy(1);
+ return false;
+ }
+ parser.addNode(Text(emoji));
+
+ return true;
+ }
+}
diff --git a/pkgs/markdown/lib/src/inline_syntaxes/emphasis_syntax.dart b/pkgs/markdown/lib/src/inline_syntaxes/emphasis_syntax.dart
new file mode 100644
index 0000000..58f2e70
--- /dev/null
+++ b/pkgs/markdown/lib/src/inline_syntaxes/emphasis_syntax.dart
@@ -0,0 +1,29 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../charcode.dart';
+import 'delimiter_syntax.dart';
+
+class EmphasisSyntax extends DelimiterSyntax {
+ /// Parses `__strong__` and `_emphasis_`.
+ EmphasisSyntax.underscore()
+ : super(
+ '_+',
+ requiresDelimiterRun: true,
+ tags: _tags,
+ startCharacter: $underscore,
+ );
+
+ /// Parses `**strong**` and `*emphasis*`.
+ EmphasisSyntax.asterisk()
+ : super(
+ r'\*+',
+ requiresDelimiterRun: true,
+ allowIntraWord: true,
+ tags: _tags,
+ startCharacter: $asterisk,
+ );
+
+ static final _tags = [DelimiterTag('em', 1), DelimiterTag('strong', 2)];
+}
diff --git a/pkgs/markdown/lib/src/inline_syntaxes/escape_html_syntax.dart b/pkgs/markdown/lib/src/inline_syntaxes/escape_html_syntax.dart
new file mode 100644
index 0000000..565f870
--- /dev/null
+++ b/pkgs/markdown/lib/src/inline_syntaxes/escape_html_syntax.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../ast.dart';
+import '../inline_parser.dart';
+import '../util.dart';
+import 'inline_syntax.dart';
+
+/// Encodes (`"`), (`<`), (`>`) and (`&`).
+class EscapeHtmlSyntax extends InlineSyntax {
+ EscapeHtmlSyntax() : super('["<>&]');
+ @override
+ bool onMatch(InlineParser parser, Match match) {
+ final text = escapeHtml(match[0]!);
+ parser.addNode(Text(text));
+
+ return true;
+ }
+}
diff --git a/pkgs/markdown/lib/src/inline_syntaxes/escape_syntax.dart b/pkgs/markdown/lib/src/inline_syntaxes/escape_syntax.dart
new file mode 100644
index 0000000..c112d93
--- /dev/null
+++ b/pkgs/markdown/lib/src/inline_syntaxes/escape_syntax.dart
@@ -0,0 +1,34 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../ast.dart';
+import '../charcode.dart';
+import '../inline_parser.dart';
+import '../patterns.dart';
+import '../util.dart';
+import 'inline_syntax.dart';
+
+/// Escape ASCII punctuation preceded by a backslash.
+///
+/// Backslashes before other characters are treated as literal backslashes.
+// See https://spec.commonmark.org/0.30/#backslash-escapes.
+class EscapeSyntax extends InlineSyntax {
+ EscapeSyntax()
+ : super('\\\\([$asciiPunctuationEscaped])', startCharacter: $backslash);
+
+ @override
+ bool onMatch(InlineParser parser, Match match) {
+ final chars = match.match;
+
+ String text;
+ if ('&"<>'.contains(match[1]!) && parser.encodeHtml) {
+ text = escapeHtml(match[1]!);
+ } else {
+ text = chars[1];
+ }
+
+ parser.addNode(Text(text));
+ return true;
+ }
+}
diff --git a/pkgs/markdown/lib/src/inline_syntaxes/footnote_ref_syntax.dart b/pkgs/markdown/lib/src/inline_syntaxes/footnote_ref_syntax.dart
new file mode 100644
index 0000000..155fd74
--- /dev/null
+++ b/pkgs/markdown/lib/src/inline_syntaxes/footnote_ref_syntax.dart
@@ -0,0 +1,72 @@
+import '../ast.dart' show Element, Node, Text;
+import '../charcode.dart';
+import 'link_syntax.dart' show LinkContext;
+
+/// The spec of GFM about footnotes is
+/// [missing](https://github.com/github/cmark-gfm/issues/283#issuecomment-1378868725).
+/// For source code of cmark-gfm, see the `noMatch` label of the
+/// `handle_close_bracket` function in [master@c32ef78](https://github.com/github/cmark-gfm/blob/c32ef78/src/inlines.c#L1236).
+/// A Rust implementation is also [available](https://github.com/wooorm/markdown-rs/blob/2498e31eecead798efc649502bbf5f86feaa94be/src/construct/gfm_label_start_footnote.rs).
+/// Footnotes shares the same syntax with [LinkSyntax],
+/// but have a different branch of handling the close bracket.
+class FootnoteRefSyntax {
+ static String? _footnoteLabel(String key) {
+ if (key.isEmpty || key.codeUnitAt(0) != $caret) {
+ return null;
+ }
+ key = key.substring(1).trim().toLowerCase();
+ if (key.isEmpty) {
+ return null;
+ }
+ return key;
+ }
+
+ static Iterable<Node>? tryCreateFootnoteLink(
+ LinkContext context,
+ String text, {
+ bool? secondary,
+ }) {
+ secondary ??= false;
+ final parser = context.parser;
+ final key = _footnoteLabel(text);
+ final refs = parser.document.footnoteReferences;
+ // `label` is what footnoteReferences stored, it is case sensitive.
+ final label =
+ refs.keys.firstWhere((k) => k.toLowerCase() == key, orElse: () => '');
+ // `count != null` means footnote was valid.
+ var count = refs[label];
+ // And then check if footnote was matched.
+ if (key == null || count == null) {
+ return null;
+ }
+ final result = <Node>[];
+ // There are 4 cases here: ![^...], [^...], ![...][^...], [...][^...]
+ if (context.opener.char == $exclamation) {
+ result.add(Text('!'));
+ }
+ refs[label] = ++count;
+ final labels = parser.document.footnoteLabels;
+ var pos = labels.indexOf(key);
+ if (pos < 0) {
+ pos = labels.length;
+ labels.add(key);
+ }
+
+ // `children` are text segments after '[^' before ']'.
+ final children = context.getChildren();
+ if (secondary) {
+ result.add(Text('['));
+ result.addAll(children);
+ result.add(Text(']'));
+ }
+ final id = Uri.encodeComponent(label);
+ final suffix = count > 1 ? '-$count' : '';
+ final link = Element('a', [Text('${pos + 1}')])
+ // Ignore GitHub's attribute: <data-footnote-ref>.
+ ..attributes['href'] = '#fn-$id'
+ ..attributes['id'] = 'fnref-$id$suffix';
+ final sup = Element('sup', [link])..attributes['class'] = 'footnote-ref';
+ result.add(sup);
+ return result;
+ }
+}
diff --git a/pkgs/markdown/lib/src/inline_syntaxes/image_syntax.dart b/pkgs/markdown/lib/src/inline_syntaxes/image_syntax.dart
new file mode 100644
index 0000000..a8b2c35
--- /dev/null
+++ b/pkgs/markdown/lib/src/inline_syntaxes/image_syntax.dart
@@ -0,0 +1,44 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../ast.dart';
+import '../charcode.dart';
+import '../util.dart';
+import 'link_syntax.dart';
+
+/// Matches images like `` and
+/// `![alternate text][label]`.
+class ImageSyntax extends LinkSyntax {
+ ImageSyntax({super.linkResolver})
+ : super(
+ pattern: r'!\[',
+ startCharacter: $exclamation,
+ );
+
+ @override
+ Element createNode(
+ String destination,
+ String? title, {
+ required List<Node> Function() getChildren,
+ }) {
+ final element = Element.empty('img');
+ final children = getChildren();
+ element.attributes['src'] = normalizeLinkDestination(
+ escapePunctuation(destination),
+ );
+ element.attributes['alt'] = children.map((node) {
+ // See https://spec.commonmark.org/0.30/#image-description.
+ // An image description may contain links. Fetch text from the alt
+ // attribute if this nested link is an image.
+ if (node is Element && node.tag == 'img') {
+ return node.attributes['alt'];
+ }
+ return node.textContent;
+ }).join();
+ if (title != null && title.isNotEmpty) {
+ element.attributes['title'] = normalizeLinkTitle(title);
+ }
+ return element;
+ }
+}
diff --git a/pkgs/markdown/lib/src/inline_syntaxes/inline_html_syntax.dart b/pkgs/markdown/lib/src/inline_syntaxes/inline_html_syntax.dart
new file mode 100644
index 0000000..3a7ce77
--- /dev/null
+++ b/pkgs/markdown/lib/src/inline_syntaxes/inline_html_syntax.dart
@@ -0,0 +1,44 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../../markdown.dart';
+import '../charcode.dart';
+import '../patterns.dart';
+
+/// Leave inline HTML tags alone, from
+/// [CommonMark 0.30](https://spec.commonmark.org/0.30/#raw-html).
+///
+/// This is not actually a good definition (nor CommonMark's) of an HTML tag,
+/// but it is fast. It will leave text like `<a href='hi">` alone, which is
+/// incorrect.
+///
+/// TODO(srawlins): improve accuracy while ensuring performance, once
+/// Markdown benchmarking is more mature.
+class InlineHtmlSyntax extends TextSyntax {
+ static const _pattern = '(?:$namedTagDefinition)'
+ // Or
+ '|'
+
+ // HTML comment, see
+ // https://spec.commonmark.org/0.30/#html-comment.
+ '<!--(?:(?:[^-<>]+-[^-<>]+)+|[^-<>]+)-->'
+ '|'
+
+ // Processing-instruction, see
+ // https://spec.commonmark.org/0.30/#processing-instruction
+ r'<\?.*?\?>'
+ '|'
+
+ // Declaration, see
+ // https://spec.commonmark.org/0.30/#declaration.
+ '(<![a-z]+.*?>)'
+ '|'
+
+ // CDATA section, see
+ // https://spec.commonmark.org/0.30/#cdata-section.
+ r'(<!\[CDATA\[.*?]]>)';
+
+ InlineHtmlSyntax()
+ : super(_pattern, startCharacter: $lt, caseSensitive: false);
+}
diff --git a/pkgs/markdown/lib/src/inline_syntaxes/inline_syntax.dart b/pkgs/markdown/lib/src/inline_syntaxes/inline_syntax.dart
new file mode 100644
index 0000000..997d03a
--- /dev/null
+++ b/pkgs/markdown/lib/src/inline_syntaxes/inline_syntax.dart
@@ -0,0 +1,58 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../inline_parser.dart';
+import '../util.dart';
+
+/// Represents one kind of Markdown tag that can be parsed.
+abstract class InlineSyntax {
+ final RegExp pattern;
+
+ /// The first character of [pattern], to be used as an efficient first check
+ /// that this syntax matches the current parser position.
+ final int? _startCharacter;
+
+ /// Create a new [InlineSyntax] which matches text on [pattern].
+ ///
+ /// If [startCharacter] is passed, it is used as a pre-matching check which
+ /// is faster than matching against [pattern].
+ ///
+ /// If [caseSensitive] is disabled, then case is ignored when matching
+ /// the [pattern].
+ InlineSyntax(String pattern, {int? startCharacter, bool caseSensitive = true})
+ : pattern =
+ RegExp(pattern, multiLine: true, caseSensitive: caseSensitive),
+ _startCharacter = startCharacter;
+
+ /// Tries to match at the parser's current position.
+ ///
+ /// The parser's position can be overriden with [startMatchPos].
+ /// Returns whether or not the pattern successfully matched.
+ bool tryMatch(InlineParser parser, [int? startMatchPos]) {
+ startMatchPos ??= parser.pos;
+
+ // Before matching with the regular expression [pattern], which can be
+ // expensive on some platforms, check if even the first character matches
+ // this syntax.
+ if (_startCharacter != null &&
+ parser.source.codeUnitAt(startMatchPos) != _startCharacter) {
+ return false;
+ }
+
+ final startMatch = pattern.matchAsPrefix(parser.source, startMatchPos);
+ if (startMatch == null) return false;
+
+ // Write any existing plain text up to this point.
+ parser.writeText();
+
+ if (onMatch(parser, startMatch)) parser.consume(startMatch.match.length);
+ return true;
+ }
+
+ /// Processes [match], adding nodes to [parser] and possibly advancing
+ /// [parser].
+ ///
+ /// Returns whether the caller should advance [parser] by `match[0].length`.
+ bool onMatch(InlineParser parser, Match match);
+}
diff --git a/pkgs/markdown/lib/src/inline_syntaxes/line_break_syntax.dart b/pkgs/markdown/lib/src/inline_syntaxes/line_break_syntax.dart
new file mode 100644
index 0000000..0a5fb01
--- /dev/null
+++ b/pkgs/markdown/lib/src/inline_syntaxes/line_break_syntax.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../ast.dart';
+import '../inline_parser.dart';
+import 'inline_syntax.dart';
+
+/// Represents a hard line break.
+class LineBreakSyntax extends InlineSyntax {
+ LineBreakSyntax() : super(r'(?:\\| +)\n');
+
+ /// Create a void <br> element.
+ @override
+ bool onMatch(InlineParser parser, Match match) {
+ parser.addNode(Element.empty('br'));
+ return true;
+ }
+}
diff --git a/pkgs/markdown/lib/src/inline_syntaxes/link_syntax.dart b/pkgs/markdown/lib/src/inline_syntaxes/link_syntax.dart
new file mode 100644
index 0000000..bca3efb
--- /dev/null
+++ b/pkgs/markdown/lib/src/inline_syntaxes/link_syntax.dart
@@ -0,0 +1,479 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../ast.dart';
+import '../charcode.dart';
+import '../document.dart';
+import '../inline_parser.dart';
+import '../util.dart';
+import 'delimiter_syntax.dart';
+import 'footnote_ref_syntax.dart';
+
+/// A helper class holds params of link context.
+/// Footnote creation needs other info in [_tryCreateReferenceLink].
+class LinkContext {
+ final InlineParser parser;
+ final SimpleDelimiter opener;
+ final List<Node> Function() getChildren;
+
+ const LinkContext(this.parser, this.opener, this.getChildren);
+}
+
+/// Matches links like `[blah][label]` and `[blah](url)`.
+class LinkSyntax extends DelimiterSyntax {
+ static final _entirelyWhitespacePattern = RegExp(r'^\s*$');
+
+ final Resolver linkResolver;
+
+ LinkSyntax({
+ Resolver? linkResolver,
+ String pattern = r'\[',
+ int startCharacter = $lbracket,
+ }) : linkResolver = (linkResolver ?? ((String _, [String? __]) => null)),
+ super(pattern, startCharacter: startCharacter);
+
+ @override
+ Iterable<Node>? close(
+ InlineParser parser,
+ covariant SimpleDelimiter opener,
+ Delimiter? closer, {
+ String? tag,
+ required List<Node> Function() getChildren,
+ }) {
+ final context = LinkContext(parser, opener, getChildren);
+ final text = parser.source.substring(opener.endPos, parser.pos);
+ // The current character is the `]` that closed the link text. Examine the
+ // next character, to determine what type of link we might have (a '('
+ // means a possible inline link; otherwise a possible reference link).
+ if (parser.pos + 1 >= parser.source.length) {
+ // The `]` is at the end of the document, but this may still be a valid
+ // shortcut reference link.
+ return _tryCreateReferenceLink(context, text);
+ }
+
+ // Peek at the next character; don't advance, so as to avoid later stepping
+ // backward.
+ final char = parser.charAt(parser.pos + 1);
+
+ if (char == $lparen) {
+ // Maybe an inline link, like `[text](destination)`.
+ parser.advanceBy(1);
+ final leftParenIndex = parser.pos;
+ final inlineLink = _parseInlineLink(parser);
+ if (inlineLink != null) {
+ return [
+ _tryCreateInlineLink(
+ parser,
+ inlineLink,
+ getChildren: getChildren,
+ ),
+ ];
+ }
+ // At this point, we've matched `[...](`, but that `(` did not pan out to
+ // be an inline link. We must now check if `[...]` is simply a shortcut
+ // reference link.
+
+ // Reset the parser position.
+ parser.pos = leftParenIndex;
+ parser.advanceBy(-1);
+ return _tryCreateReferenceLink(context, text);
+ }
+
+ if (char == $lbracket) {
+ parser.advanceBy(1);
+ // At this point, we've matched `[...][`. Maybe a *full* reference link,
+ // like `[foo][bar]` or a *collapsed* reference link, like `[foo][]`.
+ if (parser.pos + 1 < parser.source.length &&
+ parser.charAt(parser.pos + 1) == $rbracket) {
+ // That opening `[` is not actually part of the link. Maybe a
+ // *shortcut* reference link (followed by a `[`).
+ parser.advanceBy(1);
+ return _tryCreateReferenceLink(context, text);
+ }
+ final label = _parseReferenceLinkLabel(parser);
+ if (label != null) {
+ return _tryCreateReferenceLink(context, label, secondary: true);
+ }
+ return null;
+ }
+
+ // The link text (inside `[...]`) was not followed with a opening `(` nor
+ // an opening `[`. Perhaps just a simple shortcut reference link (`[...]`).
+ return _tryCreateReferenceLink(context, text);
+ }
+
+ /// Resolve a possible reference link.
+ ///
+ /// Uses [linkReferences], [linkResolver], and [createNode] to try to
+ /// resolve [label] into a [Node]. If [label] is defined in
+ /// [linkReferences] or can be resolved by [linkResolver], returns a [Node]
+ /// that links to the resolved URL.
+ ///
+ /// Otherwise, returns `null`.
+ ///
+ /// [label] does not need to be normalized.
+ Node? _resolveReferenceLink(
+ String label,
+ Map<String, LinkReference> linkReferences, {
+ required List<Node> Function() getChildren,
+ }) {
+ final linkReference = linkReferences[normalizeLinkLabel(label)];
+ if (linkReference != null) {
+ return createNode(
+ linkReference.destination,
+ linkReference.title,
+ getChildren: getChildren,
+ );
+ } else {
+ // This link has no reference definition. But we allow users of the
+ // library to specify a custom resolver function ([linkResolver]) that
+ // may choose to handle this. Otherwise, it's just treated as plain
+ // text.
+
+ // Normally, label text does not get parsed as inline Markdown. However,
+ // for the benefit of the link resolver, we need to at least escape
+ // brackets, so that, e.g. a link resolver can receive `[\[\]]` as `[]`.
+ final resolved = linkResolver(label
+ .replaceAll(r'\\', r'\')
+ .replaceAll(r'\[', '[')
+ .replaceAll(r'\]', ']'));
+ if (resolved != null) {
+ getChildren();
+ }
+ return resolved;
+ }
+ }
+
+ /// Create the node represented by a Markdown link.
+ Node createNode(
+ String destination,
+ String? title, {
+ required List<Node> Function() getChildren,
+ }) {
+ final children = getChildren();
+ final element = Element('a', children);
+ element.attributes['href'] = normalizeLinkDestination(
+ escapePunctuation(destination),
+ );
+ if (title != null && title.isNotEmpty) {
+ element.attributes['title'] = normalizeLinkTitle(
+ escapePunctuation(title),
+ );
+ }
+ return element;
+ }
+
+ /// Tries to create a reference link node.
+ ///
+ /// Returns the nodes if it was successfully created, `null` otherwise.
+ Iterable<Node>? _tryCreateReferenceLink(
+ LinkContext context,
+ String label, {
+ bool? secondary,
+ }) {
+ final parser = context.parser;
+ final getChildren = context.getChildren;
+ final link = _resolveReferenceLink(
+ label,
+ parser.document.linkReferences,
+ getChildren: getChildren,
+ );
+ if (link != null) {
+ return [link];
+ }
+ return FootnoteRefSyntax.tryCreateFootnoteLink(
+ context,
+ label,
+ secondary: secondary,
+ );
+ }
+
+ // Tries to create an inline link node.
+ //
+ /// Returns the link if it was successfully created, `null` otherwise.
+ Node _tryCreateInlineLink(
+ InlineParser parser,
+ InlineLink link, {
+ required List<Node> Function() getChildren,
+ }) {
+ return createNode(link.destination, link.title, getChildren: getChildren);
+ }
+
+ /// Parse a reference link label at the current position.
+ ///
+ /// Specifically, [parser.pos] is expected to be pointing at the `[` which
+ /// opens the link label.
+ ///
+ /// Returns the label if it could be parsed, or `null` if not.
+ String? _parseReferenceLinkLabel(InlineParser parser) {
+ // Walk past the opening `[`.
+ parser.advanceBy(1);
+ if (parser.isDone) return null;
+
+ final buffer = StringBuffer();
+ while (true) {
+ final char = parser.charAt(parser.pos);
+ if (char == $backslash) {
+ parser.advanceBy(1);
+ if (parser.isDone) return null;
+ final next = parser.charAt(parser.pos);
+ if (next != $backslash && next != $rbracket) {
+ buffer.writeCharCode(char);
+ }
+ buffer.writeCharCode(next);
+ } else if (char == $lbracket) {
+ return null;
+ } else if (char == $rbracket) {
+ break;
+ } else {
+ buffer.writeCharCode(char);
+ }
+ parser.advanceBy(1);
+ if (parser.isDone) return null;
+ // TODO(srawlins): only check 999 characters, for performance reasons?
+ }
+
+ final label = buffer.toString();
+
+ // A link label must contain at least one non-whitespace character.
+ if (_entirelyWhitespacePattern.hasMatch(label)) return null;
+
+ return label;
+ }
+
+ /// Parse an inline [InlineLink] at the current position.
+ ///
+ /// At this point, we have parsed a link's (or image's) opening `[`, and then
+ /// a matching closing `]`, and [parser.pos] is pointing at an opening `(`.
+ /// This method will then attempt to parse a link destination wrapped in `<>`,
+ /// such as `(<http://url>)`, or a bare link destination, such as
+ /// `(http://url)`, or a link destination with a title, such as
+ /// `(http://url "title")`.
+ ///
+ /// Returns the [InlineLink] if one was parsed, or `null` if not.
+ InlineLink? _parseInlineLink(InlineParser parser) {
+ // Start walking to the character just after the opening `(`.
+ parser.advanceBy(1);
+
+ _moveThroughWhitespace(parser);
+ if (parser.isDone) return null; // EOF. Not a link.
+
+ if (parser.charAt(parser.pos) == $lt) {
+ // Maybe a `<...>`-enclosed link destination.
+ return _parseInlineBracketedLink(parser);
+ } else {
+ return _parseInlineBareDestinationLink(parser);
+ }
+ }
+
+ /// Parse an inline link with a bracketed destination (a destination wrapped
+ /// in `<...>`). The current position of the parser must be the first
+ /// character of the destination.
+ ///
+ /// Returns the link if it was successfully created, `null` otherwise.
+ InlineLink? _parseInlineBracketedLink(InlineParser parser) {
+ parser.advanceBy(1);
+ if (parser.isDone) return null;
+
+ final buffer = StringBuffer();
+ while (true) {
+ final char = parser.charAt(parser.pos);
+ if (char == $backslash) {
+ parser.advanceBy(1);
+ if (parser.isDone) return null;
+ final next = parser.charAt(parser.pos);
+ // TODO: Follow the backslash spec better here.
+ // https://spec.commonmark.org/0.30/#backslash-escapes
+ if (next != $backslash && next != $gt) {
+ buffer.writeCharCode(char);
+ }
+ buffer.writeCharCode(next);
+ } else if (char == $lf || char == $cr || char == $ff) {
+ // Not a link (no line breaks allowed within `<...>`).
+ return null;
+ } else if (char == $space) {
+ buffer.write('%20');
+ } else if (char == $gt) {
+ break;
+ } else {
+ buffer.writeCharCode(char);
+ }
+ parser.advanceBy(1);
+ if (parser.isDone) return null;
+ }
+ final destination = buffer.toString();
+
+ parser.advanceBy(1);
+ if (parser.isDone) return null;
+ final char = parser.charAt(parser.pos);
+ if (char == $space || char == $lf || char == $cr || char == $ff) {
+ final title = _parseTitle(parser);
+ if (title == null &&
+ (parser.isDone || parser.charAt(parser.pos) != $rparen)) {
+ // This looked like an inline link, until we found this $space
+ // followed by mystery characters; no longer a link.
+ return null;
+ }
+ return InlineLink(destination, title: title);
+ } else if (char == $rparen) {
+ return InlineLink(destination);
+ } else {
+ // We parsed something like `[foo](<url>X`. Not a link.
+ return null;
+ }
+ }
+
+ /// Parse an inline link with a "bare" destination (a destination _not_
+ /// wrapped in `<...>`). The current position of the parser must be the first
+ /// character of the destination.
+ ///
+ /// Returns the link if it was successfully created, `null` otherwise.
+ InlineLink? _parseInlineBareDestinationLink(InlineParser parser) {
+ // According to
+ // [CommonMark](https://spec.commonmark.org/0.30/#link-destination):
+ //
+ // > A link destination consists of [...] a nonempty sequence of
+ // > characters [...], and includes parentheses only if (a) they are
+ // > backslash-escaped or (b) they are part of a balanced pair of
+ // > unescaped parentheses.
+ //
+ // We need to count the open parens. We start with 1 for the paren that
+ // opened the destination.
+ var parenCount = 1;
+ final buffer = StringBuffer();
+
+ while (true) {
+ final char = parser.charAt(parser.pos);
+ switch (char) {
+ case $backslash:
+ parser.advanceBy(1);
+ if (parser.isDone) return null; // EOF. Not a link.
+ final next = parser.charAt(parser.pos);
+ // Parentheses may be escaped.
+ //
+ // https://spec.commonmark.org/0.30/#example-494
+ if (next != $backslash && next != $lparen && next != $rparen) {
+ buffer.writeCharCode(char);
+ }
+ buffer.writeCharCode(next);
+ break;
+
+ case $space:
+ case $lf:
+ case $cr:
+ case $ff:
+ final destination = buffer.toString();
+ final title = _parseTitle(parser);
+ if (title == null &&
+ (parser.isDone || parser.charAt(parser.pos) != $rparen)) {
+ // This looked like an inline link, until we found this $space
+ // followed by mystery characters; no longer a link.
+ return null;
+ }
+ // [_parseTitle] made sure the title was follwed by a closing `)`
+ // (but it's up to the code here to examine the balance of
+ // parentheses).
+ parenCount--;
+ if (parenCount == 0) {
+ return InlineLink(destination, title: title);
+ }
+ break;
+
+ case $lparen:
+ parenCount++;
+ buffer.writeCharCode(char);
+ break;
+
+ case $rparen:
+ parenCount--;
+ if (parenCount == 0) {
+ final destination = buffer.toString();
+ return InlineLink(destination);
+ }
+ buffer.writeCharCode(char);
+ break;
+
+ default:
+ buffer.writeCharCode(char);
+ }
+ parser.advanceBy(1);
+ if (parser.isDone) return null; // EOF. Not a link.
+ }
+ }
+
+ // Walk the parser forward through any whitespace.
+ void _moveThroughWhitespace(InlineParser parser) {
+ while (!parser.isDone) {
+ final char = parser.charAt(parser.pos);
+ if (char != $space &&
+ char != $tab &&
+ char != $lf &&
+ char != $vt &&
+ char != $cr &&
+ char != $ff) {
+ return;
+ }
+ parser.advanceBy(1);
+ }
+ }
+
+ /// Parses a link title in [parser] at it's current position. The parser's
+ /// current position should be a whitespace character that followed a link
+ /// destination.
+ ///
+ /// Returns the title if it was successfully parsed, `null` otherwise.
+ String? _parseTitle(InlineParser parser) {
+ _moveThroughWhitespace(parser);
+ if (parser.isDone) return null;
+
+ // The whitespace should be followed by a title delimiter.
+ final delimiter = parser.charAt(parser.pos);
+ if (delimiter != $apostrophe &&
+ delimiter != $quote &&
+ delimiter != $lparen) {
+ return null;
+ }
+
+ final closeDelimiter = delimiter == $lparen ? $rparen : delimiter;
+ parser.advanceBy(1);
+ if (parser.isDone) return null;
+
+ // Now we look for an un-escaped closing delimiter.
+ final buffer = StringBuffer();
+ while (true) {
+ final char = parser.charAt(parser.pos);
+ if (char == $backslash) {
+ parser.advanceBy(1);
+ if (parser.isDone) return null;
+ final next = parser.charAt(parser.pos);
+ if (next != $backslash && next != closeDelimiter) {
+ buffer.writeCharCode(char);
+ }
+ buffer.writeCharCode(next);
+ } else if (char == closeDelimiter) {
+ break;
+ } else {
+ buffer.writeCharCode(char);
+ }
+ parser.advanceBy(1);
+ if (parser.isDone) return null;
+ }
+ final title = buffer.toString();
+
+ // Advance past the closing delimiter.
+ parser.advanceBy(1);
+ if (parser.isDone) return null;
+ _moveThroughWhitespace(parser);
+ if (parser.isDone) return null;
+ if (parser.charAt(parser.pos) != $rparen) return null;
+ return title;
+ }
+}
+
+class InlineLink {
+ final String destination;
+ final String? title;
+
+ InlineLink(this.destination, {this.title});
+}
diff --git a/pkgs/markdown/lib/src/inline_syntaxes/soft_line_break_syntax.dart b/pkgs/markdown/lib/src/inline_syntaxes/soft_line_break_syntax.dart
new file mode 100644
index 0000000..c8395d5
--- /dev/null
+++ b/pkgs/markdown/lib/src/inline_syntaxes/soft_line_break_syntax.dart
@@ -0,0 +1,21 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../charcode.dart';
+import '../inline_parser.dart';
+import 'inline_syntax.dart';
+
+/// Removes the single space before the line ending.
+// https://spec.commonmark.org/0.30/#soft-line-breaks.
+// If there are more than one spaces before the line ending, it may hit the hard
+// break syntax.
+class SoftLineBreakSyntax extends InlineSyntax {
+ SoftLineBreakSyntax() : super(' \n', startCharacter: $space);
+
+ @override
+ bool onMatch(InlineParser parser, Match match) {
+ parser.consume(1);
+ return false;
+ }
+}
diff --git a/pkgs/markdown/lib/src/inline_syntaxes/strikethrough_syntax.dart b/pkgs/markdown/lib/src/inline_syntaxes/strikethrough_syntax.dart
new file mode 100644
index 0000000..ebe5e1a
--- /dev/null
+++ b/pkgs/markdown/lib/src/inline_syntaxes/strikethrough_syntax.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../charcode.dart';
+import 'delimiter_syntax.dart';
+
+/// Matches strikethrough syntax according to the GFM spec.
+class StrikethroughSyntax extends DelimiterSyntax {
+ StrikethroughSyntax()
+ : super(
+ '~+',
+ requiresDelimiterRun: true,
+ allowIntraWord: true,
+ startCharacter: $tilde,
+ tags: [DelimiterTag('del', 1), DelimiterTag('del', 2)],
+ );
+}
diff --git a/pkgs/markdown/lib/src/inline_syntaxes/text_syntax.dart b/pkgs/markdown/lib/src/inline_syntaxes/text_syntax.dart
new file mode 100644
index 0000000..b73d09d
--- /dev/null
+++ b/pkgs/markdown/lib/src/inline_syntaxes/text_syntax.dart
@@ -0,0 +1,45 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../ast.dart';
+import '../inline_parser.dart';
+import '../util.dart';
+import 'inline_syntax.dart';
+
+/// Matches stuff that should just be passed through as straight text.
+class TextSyntax extends InlineSyntax {
+ final String substitute;
+
+ /// Create a new [TextSyntax] which matches text on [pattern].
+ ///
+ /// If [sub] is passed, it is used as a simple replacement for [pattern]. If
+ /// [startCharacter] is passed, it is used as a pre-matching check which is
+ /// faster than matching against [pattern].
+ TextSyntax(
+ super.pattern, {
+ String sub = '',
+ super.startCharacter,
+ super.caseSensitive,
+ }) : substitute = sub;
+
+ /// Adds a [Text] node to [parser] and returns `true` if there is a
+ /// [substitute], as long as the preceding character (if any) is not a `/`.
+ ///
+ /// Otherwise, the parser is advanced by the length of [match] and `false` is
+ /// returned.
+ @override
+ bool onMatch(InlineParser parser, Match match) {
+ if (substitute.isEmpty ||
+ (match.start > 0 &&
+ match.input.substring(match.start - 1, match.start) == '/')) {
+ // Just use the original matched text.
+ parser.advanceBy(match.match.length);
+ return false;
+ }
+
+ // Insert the substitution.
+ parser.addNode(Text(substitute));
+ return true;
+ }
+}
diff --git a/pkgs/markdown/lib/src/legacy_emojis.dart b/pkgs/markdown/lib/src/legacy_emojis.dart
new file mode 100644
index 0000000..d608841
--- /dev/null
+++ b/pkgs/markdown/lib/src/legacy_emojis.dart
@@ -0,0 +1,1578 @@
+// GENERATED FILE. DO NOT EDIT.
+//
+// This file was generated from emojilib's emoji data file:
+// https://raw.githubusercontent.com/muan/emojilib/v2.4.0/emojis.json
+// at 2022-05-02 10:18:54.685294 by the script, tool/update_emojis.dart.
+
+const emojis = <String, String>{
+ '+1': '👍',
+ '-1': '👎',
+ '100': '💯',
+ '1234': '🔢',
+ '1st_place_medal': '🥇',
+ '2nd_place_medal': '🥈',
+ '3rd_place_medal': '🥉',
+ '8ball': '🎱',
+ 'a': '🅰️',
+ 'ab': '🆎',
+ 'abacus': '🧮',
+ 'abc': '🔤',
+ 'abcd': '🔡',
+ 'accept': '🉑',
+ 'adult': '🧑',
+ 'aerial_tramway': '🚡',
+ 'afghanistan': '🇦🇫',
+ 'airplane': '✈️',
+ 'aland_islands': '🇦🇽',
+ 'alarm_clock': '⏰',
+ 'albania': '🇦🇱',
+ 'alembic': '⚗',
+ 'algeria': '🇩🇿',
+ 'alien': '👽',
+ 'ambulance': '🚑',
+ 'american_samoa': '🇦🇸',
+ 'amphora': '🏺',
+ 'anchor': '⚓',
+ 'andorra': '🇦🇩',
+ 'angel': '👼',
+ 'anger': '💢',
+ 'angola': '🇦🇴',
+ 'angry': '😠',
+ 'anguilla': '🇦🇮',
+ 'anguished': '😧',
+ 'ant': '🐜',
+ 'antarctica': '🇦🇶',
+ 'antigua_barbuda': '🇦🇬',
+ 'apple': '🍎',
+ 'aquarius': '♒',
+ 'argentina': '🇦🇷',
+ 'aries': '♈',
+ 'armenia': '🇦🇲',
+ 'arrow_backward': '◀️',
+ 'arrow_double_down': '⏬',
+ 'arrow_double_up': '⏫',
+ 'arrow_down': '⬇️',
+ 'arrow_down_small': '🔽',
+ 'arrow_forward': '▶️',
+ 'arrow_heading_down': '⤵️',
+ 'arrow_heading_up': '⤴️',
+ 'arrow_left': '⬅️',
+ 'arrow_lower_left': '↙️',
+ 'arrow_lower_right': '↘️',
+ 'arrow_right': '➡️',
+ 'arrow_right_hook': '↪️',
+ 'arrow_up': '⬆️',
+ 'arrow_up_down': '↕️',
+ 'arrow_up_small': '🔼',
+ 'arrow_upper_left': '↖️',
+ 'arrow_upper_right': '↗️',
+ 'arrows_clockwise': '🔃',
+ 'arrows_counterclockwise': '🔄',
+ 'art': '🎨',
+ 'articulated_lorry': '🚛',
+ 'artificial_satellite': '🛰',
+ 'aruba': '🇦🇼',
+ 'asterisk': '*⃣',
+ 'astonished': '😲',
+ 'athletic_shoe': '👟',
+ 'atm': '🏧',
+ 'atom_symbol': '⚛',
+ 'australia': '🇦🇺',
+ 'austria': '🇦🇹',
+ 'avocado': '🥑',
+ 'azerbaijan': '🇦🇿',
+ 'b': '🅱️',
+ 'baby': '👶',
+ 'baby_bottle': '🍼',
+ 'baby_chick': '🐤',
+ 'baby_symbol': '🚼',
+ 'back': '🔙',
+ 'bacon': '🥓',
+ 'badger': '🦡',
+ 'badminton': '🏸',
+ 'bagel': '🥯',
+ 'baggage_claim': '🛄',
+ 'baguette_bread': '🥖',
+ 'bahamas': '🇧🇸',
+ 'bahrain': '🇧🇭',
+ 'balance_scale': '⚖',
+ 'balloon': '🎈',
+ 'ballot_box': '🗳',
+ 'ballot_box_with_check': '☑️',
+ 'bamboo': '🎍',
+ 'banana': '🍌',
+ 'bangbang': '‼️',
+ 'bangladesh': '🇧🇩',
+ 'bank': '🏦',
+ 'bar_chart': '📊',
+ 'barbados': '🇧🇧',
+ 'barber': '💈',
+ 'baseball': '⚾',
+ 'basket': '🧺',
+ 'basketball': '🏀',
+ 'basketball_man': '⛹',
+ 'basketball_woman': '⛹️♀️',
+ 'bat': '🦇',
+ 'bath': '🛀',
+ 'bathtub': '🛁',
+ 'battery': '🔋',
+ 'beach_umbrella': '🏖',
+ 'bear': '🐻',
+ 'bearded_person': '🧔',
+ 'bed': '🛏',
+ 'beer': '🍺',
+ 'beers': '🍻',
+ 'beetle': '🐞',
+ 'beginner': '🔰',
+ 'belarus': '🇧🇾',
+ 'belgium': '🇧🇪',
+ 'belize': '🇧🇿',
+ 'bell': '🔔',
+ 'bellhop_bell': '🛎',
+ 'benin': '🇧🇯',
+ 'bento': '🍱',
+ 'bermuda': '🇧🇲',
+ 'bhutan': '🇧🇹',
+ 'bike': '🚲',
+ 'biking_man': '🚴',
+ 'biking_woman': '🚴♀️',
+ 'bikini': '👙',
+ 'billed_hat': '🧢',
+ 'biohazard': '☣',
+ 'bird': '🐦',
+ 'birthday': '🎂',
+ 'black_circle': '⚫',
+ 'black_flag': '🏴',
+ 'black_heart': '🖤',
+ 'black_joker': '🃏',
+ 'black_large_square': '⬛',
+ 'black_medium_small_square': '◾',
+ 'black_medium_square': '◼️',
+ 'black_nib': '✒️',
+ 'black_small_square': '▪️',
+ 'black_square_button': '🔲',
+ 'blonde_man': '👱',
+ 'blonde_woman': '👱♀️',
+ 'blossom': '🌼',
+ 'blowfish': '🐡',
+ 'blue_book': '📘',
+ 'blue_car': '🚙',
+ 'blue_heart': '💙',
+ 'blush': '😊',
+ 'boar': '🐗',
+ 'bolivia': '🇧🇴',
+ 'bomb': '💣',
+ 'bone': '🦴',
+ 'bookmark': '🔖',
+ 'bookmark_tabs': '📑',
+ 'books': '📚',
+ 'boom': '💥',
+ 'boot': '👢',
+ 'bosnia_herzegovina': '🇧🇦',
+ 'botswana': '🇧🇼',
+ 'bouquet': '💐',
+ 'bow_and_arrow': '🏹',
+ 'bowing_man': '🙇',
+ 'bowing_woman': '🙇♀️',
+ 'bowl_with_spoon': '🥣',
+ 'bowling': '🎳',
+ 'boxing_glove': '🥊',
+ 'boy': '👦',
+ 'brain': '🧠',
+ 'brazil': '🇧🇷',
+ 'bread': '🍞',
+ 'breastfeeding': '🤱',
+ 'brick': '🧱',
+ 'bride_with_veil': '👰',
+ 'bridge_at_night': '🌉',
+ 'briefcase': '💼',
+ 'british_indian_ocean_territory': '🇮🇴',
+ 'british_virgin_islands': '🇻🇬',
+ 'broccoli': '🥦',
+ 'broken_heart': '💔',
+ 'broom': '🧹',
+ 'brunei': '🇧🇳',
+ 'bug': '🐛',
+ 'building_construction': '🏗',
+ 'bulb': '💡',
+ 'bulgaria': '🇧🇬',
+ 'bullettrain_front': '🚅',
+ 'bullettrain_side': '🚄',
+ 'burkina_faso': '🇧🇫',
+ 'burrito': '🌯',
+ 'burundi': '🇧🇮',
+ 'bus': '🚌',
+ 'business_suit_levitating': '🕴',
+ 'busstop': '🚏',
+ 'bust_in_silhouette': '👤',
+ 'busts_in_silhouette': '👥',
+ 'butterfly': '🦋',
+ 'cactus': '🌵',
+ 'cake': '🍰',
+ 'calendar': '📆',
+ 'call_me_hand': '🤙',
+ 'calling': '📲',
+ 'cambodia': '🇰🇭',
+ 'camel': '🐫',
+ 'camera': '📷',
+ 'camera_flash': '📸',
+ 'cameroon': '🇨🇲',
+ 'camping': '🏕',
+ 'canada': '🇨🇦',
+ 'canary_islands': '🇮🇨',
+ 'cancer': '♋',
+ 'candle': '🕯',
+ 'candy': '🍬',
+ 'canned_food': '🥫',
+ 'canoe': '🛶',
+ 'cape_verde': '🇨🇻',
+ 'capital_abcd': '🔠',
+ 'capricorn': '♑',
+ 'card_file_box': '🗃',
+ 'card_index': '📇',
+ 'card_index_dividers': '🗂',
+ 'caribbean_netherlands': '🇧🇶',
+ 'carousel_horse': '🎠',
+ 'carrot': '🥕',
+ 'cat': '🐱',
+ 'cat2': '🐈',
+ 'cayman_islands': '🇰🇾',
+ 'cd': '💿',
+ 'central_african_republic': '🇨🇫',
+ 'chad': '🇹🇩',
+ 'chains': '⛓',
+ 'champagne': '🍾',
+ 'chart': '💹',
+ 'chart_with_downwards_trend': '📉',
+ 'chart_with_upwards_trend': '📈',
+ 'checkered_flag': '🏁',
+ 'cheese': '🧀',
+ 'cherries': '🍒',
+ 'cherry_blossom': '🌸',
+ 'chess_pawn': '♟',
+ 'chestnut': '🌰',
+ 'chicken': '🐔',
+ 'child': '🧒',
+ 'children_crossing': '🚸',
+ 'chile': '🇨🇱',
+ 'chipmunk': '🐿',
+ 'chocolate_bar': '🍫',
+ 'chopsticks': '🥢',
+ 'christmas_island': '🇨🇽',
+ 'christmas_tree': '🎄',
+ 'church': '⛪',
+ 'cinema': '🎦',
+ 'circus_tent': '🎪',
+ 'city_sunrise': '🌇',
+ 'city_sunset': '🌆',
+ 'cityscape': '🏙',
+ 'cl': '🆑',
+ 'clamp': '🗜',
+ 'clap': '👏',
+ 'clapper': '🎬',
+ 'classical_building': '🏛',
+ 'climbing_man': '🧗♂️',
+ 'climbing_woman': '🧗♀️',
+ 'clinking_glasses': '🥂',
+ 'clipboard': '📋',
+ 'clock1': '🕐',
+ 'clock10': '🕙',
+ 'clock1030': '🕥',
+ 'clock11': '🕚',
+ 'clock1130': '🕦',
+ 'clock12': '🕛',
+ 'clock1230': '🕧',
+ 'clock130': '🕜',
+ 'clock2': '🕑',
+ 'clock230': '🕝',
+ 'clock3': '🕒',
+ 'clock330': '🕞',
+ 'clock4': '🕓',
+ 'clock430': '🕟',
+ 'clock5': '🕔',
+ 'clock530': '🕠',
+ 'clock6': '🕕',
+ 'clock630': '🕡',
+ 'clock7': '🕖',
+ 'clock730': '🕢',
+ 'clock8': '🕗',
+ 'clock830': '🕣',
+ 'clock9': '🕘',
+ 'clock930': '🕤',
+ 'closed_book': '📕',
+ 'closed_lock_with_key': '🔐',
+ 'closed_umbrella': '🌂',
+ 'cloud': '☁️',
+ 'cloud_with_lightning': '🌩',
+ 'cloud_with_lightning_and_rain': '⛈',
+ 'cloud_with_rain': '🌧',
+ 'cloud_with_snow': '🌨',
+ 'clown_face': '🤡',
+ 'clubs': '♣️',
+ 'cn': '🇨🇳',
+ 'coat': '🧥',
+ 'cocktail': '🍸',
+ 'coconut': '🥥',
+ 'cocos_islands': '🇨🇨',
+ 'coffee': '☕',
+ 'coffin': '⚰',
+ 'cold': '🥶',
+ 'cold_sweat': '😰',
+ 'colombia': '🇨🇴',
+ 'comet': '☄',
+ 'comoros': '🇰🇲',
+ 'compass': '🧭',
+ 'computer': '💻',
+ 'computer_mouse': '🖱',
+ 'confetti_ball': '🎊',
+ 'confounded': '😖',
+ 'confused': '😕',
+ 'congo_brazzaville': '🇨🇬',
+ 'congo_kinshasa': '🇨🇩',
+ 'congratulations': '㊗️',
+ 'construction': '🚧',
+ 'construction_worker_man': '👷',
+ 'construction_worker_woman': '👷♀️',
+ 'control_knobs': '🎛',
+ 'convenience_store': '🏪',
+ 'cook_islands': '🇨🇰',
+ 'cookie': '🍪',
+ 'cool': '🆒',
+ 'copyright': '©️',
+ 'corn': '🌽',
+ 'costa_rica': '🇨🇷',
+ 'cote_divoire': '🇨🇮',
+ 'couch_and_lamp': '🛋',
+ 'couple': '👫',
+ 'couple_with_heart_man_man': '👨❤️👨',
+ 'couple_with_heart_woman_man': '💑',
+ 'couple_with_heart_woman_woman': '👩❤️👩',
+ 'couplekiss_man_man': '👨❤️💋👨',
+ 'couplekiss_man_woman': '💏',
+ 'couplekiss_woman_woman': '👩❤️💋👩',
+ 'cow': '🐮',
+ 'cow2': '🐄',
+ 'cowboy_hat_face': '🤠',
+ 'crab': '🦀',
+ 'crayon': '🖍',
+ 'credit_card': '💳',
+ 'crescent_moon': '🌙',
+ 'cricket': '🏏',
+ 'croatia': '🇭🇷',
+ 'crocodile': '🐊',
+ 'croissant': '🥐',
+ 'crossed_fingers': '🤞',
+ 'crossed_flags': '🎌',
+ 'crossed_swords': '⚔',
+ 'crown': '👑',
+ 'cry': '😢',
+ 'crying_cat_face': '😿',
+ 'crystal_ball': '🔮',
+ 'cuba': '🇨🇺',
+ 'cucumber': '🥒',
+ 'cup_with_straw': '🥤',
+ 'cupcake': '🧁',
+ 'cupid': '💘',
+ 'curacao': '🇨🇼',
+ 'curling_stone': '🥌',
+ 'curly_loop': '➰',
+ 'currency_exchange': '💱',
+ 'curry': '🍛',
+ 'custard': '🍮',
+ 'customs': '🛃',
+ 'cyclone': '🌀',
+ 'cyprus': '🇨🇾',
+ 'czech_republic': '🇨🇿',
+ 'dagger': '🗡',
+ 'dancer': '💃',
+ 'dancing_men': '👯♂️',
+ 'dancing_women': '👯',
+ 'dango': '🍡',
+ 'dark_sunglasses': '🕶',
+ 'dart': '🎯',
+ 'dash': '💨',
+ 'date': '📅',
+ 'de': '🇩🇪',
+ 'deciduous_tree': '🌳',
+ 'deer': '🦌',
+ 'denmark': '🇩🇰',
+ 'department_store': '🏬',
+ 'derelict_house': '🏚',
+ 'desert': '🏜',
+ 'desert_island': '🏝',
+ 'desktop_computer': '🖥',
+ 'diamond_shape_with_a_dot_inside': '💠',
+ 'diamonds': '♦️',
+ 'disappointed': '😞',
+ 'disappointed_relieved': '😥',
+ 'dizzy': '💫',
+ 'dizzy_face': '😵',
+ 'djibouti': '🇩🇯',
+ 'dna': '🧬',
+ 'do_not_litter': '🚯',
+ 'dog': '🐶',
+ 'dog2': '🐕',
+ 'dollar': '💵',
+ 'dolls': '🎎',
+ 'dolphin': '🐬',
+ 'dominica': '🇩🇲',
+ 'dominican_republic': '🇩🇴',
+ 'door': '🚪',
+ 'doughnut': '🍩',
+ 'dove': '🕊',
+ 'dragon': '🐉',
+ 'dragon_face': '🐲',
+ 'dress': '👗',
+ 'dromedary_camel': '🐪',
+ 'drooling_face': '🤤',
+ 'droplet': '💧',
+ 'drum': '🥁',
+ 'duck': '🦆',
+ 'dumpling': '🥟',
+ 'dvd': '📀',
+ 'e-mail': '📧',
+ 'eagle': '🦅',
+ 'ear': '👂',
+ 'ear_of_rice': '🌾',
+ 'earth_africa': '🌍',
+ 'earth_americas': '🌎',
+ 'earth_asia': '🌏',
+ 'ecuador': '🇪🇨',
+ 'egg': '🥚',
+ 'eggplant': '🍆',
+ 'egypt': '🇪🇬',
+ 'eight': '8️⃣',
+ 'eight_pointed_black_star': '✴️',
+ 'eight_spoked_asterisk': '✳️',
+ 'eject_button': '⏏️',
+ 'el_salvador': '🇸🇻',
+ 'electric_plug': '🔌',
+ 'elephant': '🐘',
+ 'email': '✉️',
+ 'end': '🔚',
+ 'england': '🏴',
+ 'envelope_with_arrow': '📩',
+ 'equatorial_guinea': '🇬🇶',
+ 'eritrea': '🇪🇷',
+ 'es': '🇪🇸',
+ 'estonia': '🇪🇪',
+ 'ethiopia': '🇪🇹',
+ 'eu': '🇪🇺',
+ 'euro': '💶',
+ 'european_castle': '🏰',
+ 'european_post_office': '🏤',
+ 'evergreen_tree': '🌲',
+ 'exclamation': '❗',
+ 'exploding_head': '🤯',
+ 'expressionless': '😑',
+ 'eye': '👁',
+ 'eyeglasses': '👓',
+ 'eyes': '👀',
+ 'face_with_head_bandage': '🤕',
+ 'face_with_thermometer': '🤒',
+ 'facepunch': '👊',
+ 'factory': '🏭',
+ 'falkland_islands': '🇫🇰',
+ 'fallen_leaf': '🍂',
+ 'family_man_boy': '👨👦',
+ 'family_man_boy_boy': '👨👦👦',
+ 'family_man_girl': '👨👧',
+ 'family_man_girl_boy': '👨👧👦',
+ 'family_man_girl_girl': '👨👧👧',
+ 'family_man_man_boy': '👨👨👦',
+ 'family_man_man_boy_boy': '👨👨👦👦',
+ 'family_man_man_girl': '👨👨👧',
+ 'family_man_man_girl_boy': '👨👨👧👦',
+ 'family_man_man_girl_girl': '👨👨👧👧',
+ 'family_man_woman_boy': '👪',
+ 'family_man_woman_boy_boy': '👨👩👦👦',
+ 'family_man_woman_girl': '👨👩👧',
+ 'family_man_woman_girl_boy': '👨👩👧👦',
+ 'family_man_woman_girl_girl': '👨👩👧👧',
+ 'family_woman_boy': '👩👦',
+ 'family_woman_boy_boy': '👩👦👦',
+ 'family_woman_girl': '👩👧',
+ 'family_woman_girl_boy': '👩👧👦',
+ 'family_woman_girl_girl': '👩👧👧',
+ 'family_woman_woman_boy': '👩👩👦',
+ 'family_woman_woman_boy_boy': '👩👩👦👦',
+ 'family_woman_woman_girl': '👩👩👧',
+ 'family_woman_woman_girl_boy': '👩👩👧👦',
+ 'family_woman_woman_girl_girl': '👩👩👧👧',
+ 'faroe_islands': '🇫🇴',
+ 'fast_forward': '⏩',
+ 'fax': '📠',
+ 'fearful': '😨',
+ 'female_detective': '🕵️♀️',
+ 'ferris_wheel': '🎡',
+ 'ferry': '⛴',
+ 'field_hockey': '🏑',
+ 'fiji': '🇫🇯',
+ 'file_cabinet': '🗄',
+ 'file_folder': '📁',
+ 'film_projector': '📽',
+ 'film_strip': '🎞',
+ 'finland': '🇫🇮',
+ 'fire': '🔥',
+ 'fire_engine': '🚒',
+ 'fire_extinguisher': '🧯',
+ 'firecracker': '🧨',
+ 'fireworks': '🎆',
+ 'first_quarter_moon': '🌓',
+ 'first_quarter_moon_with_face': '🌛',
+ 'fish': '🐟',
+ 'fish_cake': '🍥',
+ 'fishing_pole_and_fish': '🎣',
+ 'fist': '✊',
+ 'fist_left': '🤛',
+ 'fist_right': '🤜',
+ 'five': '5️⃣',
+ 'flags': '🎏',
+ 'flashlight': '🔦',
+ 'flat_shoe': '🥿',
+ 'fleur_de_lis': '⚜',
+ 'flight_arrival': '🛬',
+ 'flight_departure': '🛫',
+ 'floppy_disk': '💾',
+ 'flower_playing_cards': '🎴',
+ 'flushed': '😳',
+ 'flying_disc': '🥏',
+ 'flying_saucer': '🛸',
+ 'fog': '🌫',
+ 'foggy': '🌁',
+ 'foot': '🦶',
+ 'football': '🏈',
+ 'footprints': '👣',
+ 'fork_and_knife': '🍴',
+ 'fortune_cookie': '🥠',
+ 'fountain': '⛲',
+ 'fountain_pen': '🖋',
+ 'four': '4️⃣',
+ 'four_leaf_clover': '🍀',
+ 'fox_face': '🦊',
+ 'fr': '🇫🇷',
+ 'framed_picture': '🖼',
+ 'free': '🆓',
+ 'french_guiana': '🇬🇫',
+ 'french_polynesia': '🇵🇫',
+ 'french_southern_territories': '🇹🇫',
+ 'fried_egg': '🍳',
+ 'fried_shrimp': '🍤',
+ 'fries': '🍟',
+ 'frog': '🐸',
+ 'frowning': '😦',
+ 'frowning_face': '☹',
+ 'frowning_man': '🙍♂️',
+ 'frowning_woman': '🙍',
+ 'fu': '🖕',
+ 'fuelpump': '⛽',
+ 'full_moon': '🌕',
+ 'full_moon_with_face': '🌝',
+ 'funeral_urn': '⚱',
+ 'gabon': '🇬🇦',
+ 'gambia': '🇬🇲',
+ 'game_die': '🎲',
+ 'gear': '⚙',
+ 'gem': '💎',
+ 'gemini': '♊',
+ 'georgia': '🇬🇪',
+ 'ghana': '🇬🇭',
+ 'ghost': '👻',
+ 'gibraltar': '🇬🇮',
+ 'gift': '🎁',
+ 'gift_heart': '💝',
+ 'giraffe': '🦒',
+ 'girl': '👧',
+ 'globe_with_meridians': '🌐',
+ 'gloves': '🧤',
+ 'goal_net': '🥅',
+ 'goat': '🐐',
+ 'goggles': '🥽',
+ 'golf': '⛳',
+ 'golfing_man': '🏌',
+ 'golfing_woman': '🏌️♀️',
+ 'gorilla': '🦍',
+ 'grapes': '🍇',
+ 'grasshopper': '🦗',
+ 'greece': '🇬🇷',
+ 'green_apple': '🍏',
+ 'green_book': '📗',
+ 'green_heart': '💚',
+ 'green_salad': '🥗',
+ 'greenland': '🇬🇱',
+ 'grenada': '🇬🇩',
+ 'grey_exclamation': '❕',
+ 'grey_question': '❔',
+ 'grimacing': '😬',
+ 'grin': '😁',
+ 'grinning': '😀',
+ 'guadeloupe': '🇬🇵',
+ 'guam': '🇬🇺',
+ 'guardsman': '💂',
+ 'guardswoman': '💂♀️',
+ 'guatemala': '🇬🇹',
+ 'guernsey': '🇬🇬',
+ 'guinea': '🇬🇳',
+ 'guinea_bissau': '🇬🇼',
+ 'guitar': '🎸',
+ 'gun': '🔫',
+ 'guyana': '🇬🇾',
+ 'haircut_man': '💇♂️',
+ 'haircut_woman': '💇',
+ 'haiti': '🇭🇹',
+ 'hamburger': '🍔',
+ 'hammer': '🔨',
+ 'hammer_and_pick': '⚒',
+ 'hammer_and_wrench': '🛠',
+ 'hamster': '🐹',
+ 'hand_over_mouth': '🤭',
+ 'handbag': '👜',
+ 'handshake': '🤝',
+ 'hash': '#️⃣',
+ 'hatched_chick': '🐥',
+ 'hatching_chick': '🐣',
+ 'headphones': '🎧',
+ 'hear_no_evil': '🙉',
+ 'heart': '❤️',
+ 'heart_decoration': '💟',
+ 'heart_eyes': '😍',
+ 'heart_eyes_cat': '😻',
+ 'heartbeat': '💓',
+ 'heartpulse': '💗',
+ 'hearts': '♥️',
+ 'heavy_check_mark': '✔️',
+ 'heavy_division_sign': '➗',
+ 'heavy_dollar_sign': '💲',
+ 'heavy_heart_exclamation': '❣',
+ 'heavy_minus_sign': '➖',
+ 'heavy_multiplication_x': '✖️',
+ 'heavy_plus_sign': '➕',
+ 'hedgehog': '🦔',
+ 'helicopter': '🚁',
+ 'herb': '🌿',
+ 'hibiscus': '🌺',
+ 'high_brightness': '🔆',
+ 'high_heel': '👠',
+ 'hiking_boot': '🥾',
+ 'hippopotamus': '🦛',
+ 'hocho': '🔪',
+ 'hole': '🕳',
+ 'honduras': '🇭🇳',
+ 'honey_pot': '🍯',
+ 'honeybee': '🐝',
+ 'hong_kong': '🇭🇰',
+ 'horse': '🐴',
+ 'horse_racing': '🏇',
+ 'hospital': '🏥',
+ 'hot': '🥵',
+ 'hot_pepper': '🌶',
+ 'hotdog': '🌭',
+ 'hotel': '🏨',
+ 'hotsprings': '♨️',
+ 'hourglass': '⌛',
+ 'hourglass_flowing_sand': '⏳',
+ 'house': '🏠',
+ 'house_with_garden': '🏡',
+ 'houses': '🏘',
+ 'hugs': '🤗',
+ 'hungary': '🇭🇺',
+ 'hushed': '😯',
+ 'ice_cream': '🍨',
+ 'ice_hockey': '🏒',
+ 'ice_skate': '⛸',
+ 'icecream': '🍦',
+ 'iceland': '🇮🇸',
+ 'id': '🆔',
+ 'ideograph_advantage': '🉐',
+ 'imp': '👿',
+ 'inbox_tray': '📥',
+ 'incoming_envelope': '📨',
+ 'india': '🇮🇳',
+ 'indonesia': '🇮🇩',
+ 'infinity': '♾',
+ 'information_source': 'ℹ️',
+ 'innocent': '😇',
+ 'interrobang': '⁉️',
+ 'iphone': '📱',
+ 'iran': '🇮🇷',
+ 'iraq': '🇮🇶',
+ 'ireland': '🇮🇪',
+ 'isle_of_man': '🇮🇲',
+ 'israel': '🇮🇱',
+ 'it': '🇮🇹',
+ 'izakaya_lantern': '🏮',
+ 'jack_o_lantern': '🎃',
+ 'jamaica': '🇯🇲',
+ 'japan': '🗾',
+ 'japanese_castle': '🏯',
+ 'japanese_goblin': '👺',
+ 'japanese_ogre': '👹',
+ 'jeans': '👖',
+ 'jersey': '🇯🇪',
+ 'jigsaw': '🧩',
+ 'jordan': '🇯🇴',
+ 'joy': '😂',
+ 'joy_cat': '😹',
+ 'joystick': '🕹',
+ 'jp': '🇯🇵',
+ 'kaaba': '🕋',
+ 'kangaroo': '🦘',
+ 'kazakhstan': '🇰🇿',
+ 'kenya': '🇰🇪',
+ 'key': '🔑',
+ 'keyboard': '⌨',
+ 'keycap_ten': '🔟',
+ 'kick_scooter': '🛴',
+ 'kimono': '👘',
+ 'kiribati': '🇰🇮',
+ 'kiss': '💋',
+ 'kissing': '😗',
+ 'kissing_cat': '😽',
+ 'kissing_closed_eyes': '😚',
+ 'kissing_heart': '😘',
+ 'kissing_smiling_eyes': '😙',
+ 'kiwi_fruit': '🥝',
+ 'koala': '🐨',
+ 'koko': '🈁',
+ 'kosovo': '🇽🇰',
+ 'kr': '🇰🇷',
+ 'kuwait': '🇰🇼',
+ 'kyrgyzstan': '🇰🇬',
+ 'labcoat': '🥼',
+ 'label': '🏷',
+ 'lacrosse': '🥍',
+ 'laos': '🇱🇦',
+ 'large_blue_circle': '🔵',
+ 'large_blue_diamond': '🔷',
+ 'large_orange_diamond': '🔶',
+ 'last_quarter_moon': '🌗',
+ 'last_quarter_moon_with_face': '🌜',
+ 'latin_cross': '✝',
+ 'latvia': '🇱🇻',
+ 'laughing': '😆',
+ 'leafy_greens': '🥬',
+ 'leaves': '🍃',
+ 'lebanon': '🇱🇧',
+ 'ledger': '📒',
+ 'left_luggage': '🛅',
+ 'left_right_arrow': '↔️',
+ 'left_speech_bubble': '🗨',
+ 'leftwards_arrow_with_hook': '↩️',
+ 'leg': '🦵',
+ 'lemon': '🍋',
+ 'leo': '♌',
+ 'leopard': '🐆',
+ 'lesotho': '🇱🇸',
+ 'level_slider': '🎚',
+ 'liberia': '🇱🇷',
+ 'libra': '♎',
+ 'libya': '🇱🇾',
+ 'liechtenstein': '🇱🇮',
+ 'light_rail': '🚈',
+ 'link': '🔗',
+ 'lion': '🦁',
+ 'lips': '👄',
+ 'lipstick': '💄',
+ 'lithuania': '🇱🇹',
+ 'lizard': '🦎',
+ 'llama': '🦙',
+ 'lobster': '🦞',
+ 'lock': '🔒',
+ 'lock_with_ink_pen': '🔏',
+ 'lollipop': '🍭',
+ 'loop': '➿',
+ 'lotion_bottle': '🧴',
+ 'loud_sound': '🔊',
+ 'loudspeaker': '📢',
+ 'love_hotel': '🏩',
+ 'love_letter': '💌',
+ 'love_you': '🤟',
+ 'low_brightness': '🔅',
+ 'luggage': '🧳',
+ 'luxembourg': '🇱🇺',
+ 'lying_face': '🤥',
+ 'm': 'Ⓜ️',
+ 'macau': '🇲🇴',
+ 'macedonia': '🇲🇰',
+ 'madagascar': '🇲🇬',
+ 'mag': '🔍',
+ 'mag_right': '🔎',
+ 'magnet': '🧲',
+ 'mahjong': '🀄',
+ 'mailbox': '📫',
+ 'mailbox_closed': '📪',
+ 'mailbox_with_mail': '📬',
+ 'mailbox_with_no_mail': '📭',
+ 'malawi': '🇲🇼',
+ 'malaysia': '🇲🇾',
+ 'maldives': '🇲🇻',
+ 'male_detective': '🕵',
+ 'mali': '🇲🇱',
+ 'malta': '🇲🇹',
+ 'man': '👨',
+ 'man_artist': '👨🎨',
+ 'man_astronaut': '👨🚀',
+ 'man_cartwheeling': '🤸♂️',
+ 'man_cook': '👨🍳',
+ 'man_dancing': '🕺',
+ 'man_elf': '🧝♂️',
+ 'man_facepalming': '🤦♂️',
+ 'man_factory_worker': '👨🏭',
+ 'man_fairy': '🧚♂️',
+ 'man_farmer': '👨🌾',
+ 'man_firefighter': '👨🚒',
+ 'man_genie': '🧞♂️',
+ 'man_health_worker': '👨⚕️',
+ 'man_in_lotus_position': '🧘♂️',
+ 'man_in_steamy_room': '🧖♂️',
+ 'man_in_tuxedo': '🤵',
+ 'man_judge': '👨⚖️',
+ 'man_juggling': '🤹♂️',
+ 'man_mechanic': '👨🔧',
+ 'man_office_worker': '👨💼',
+ 'man_pilot': '👨✈️',
+ 'man_playing_handball': '🤾♂️',
+ 'man_playing_water_polo': '🤽♂️',
+ 'man_scientist': '👨🔬',
+ 'man_shrugging': '🤷♂️',
+ 'man_singer': '👨🎤',
+ 'man_student': '👨🎓',
+ 'man_superhero': '🦸♂️',
+ 'man_supervillain': '🦹♂️',
+ 'man_teacher': '👨🏫',
+ 'man_technologist': '👨💻',
+ 'man_vampire': '🧛♂️',
+ 'man_with_gua_pi_mao': '👲',
+ 'man_with_turban': '👳',
+ 'man_zombie': '🧟♂️',
+ 'mango': '🥭',
+ 'mans_shoe': '👞',
+ 'mantelpiece_clock': '🕰',
+ 'maple_leaf': '🍁',
+ 'marshall_islands': '🇲🇭',
+ 'martial_arts_uniform': '🥋',
+ 'martinique': '🇲🇶',
+ 'mask': '😷',
+ 'massage_man': '💆♂️',
+ 'massage_woman': '💆',
+ 'mauritania': '🇲🇷',
+ 'mauritius': '🇲🇺',
+ 'mayotte': '🇾🇹',
+ 'meat_on_bone': '🍖',
+ 'medal_military': '🎖',
+ 'medal_sports': '🏅',
+ 'mega': '📣',
+ 'melon': '🍈',
+ 'memo': '📝',
+ 'men_wrestling': '🤼♂️',
+ 'menorah': '🕎',
+ 'mens': '🚹',
+ 'mermaid': '🧜♀️',
+ 'merman': '🧜♂️',
+ 'metal': '🤘',
+ 'metro': '🚇',
+ 'mexico': '🇲🇽',
+ 'microbe': '🦠',
+ 'micronesia': '🇫🇲',
+ 'microphone': '🎤',
+ 'microscope': '🔬',
+ 'milk_glass': '🥛',
+ 'milky_way': '🌌',
+ 'minibus': '🚐',
+ 'minidisc': '💽',
+ 'mobile_phone_off': '📴',
+ 'moldova': '🇲🇩',
+ 'monaco': '🇲🇨',
+ 'money_mouth_face': '🤑',
+ 'money_with_wings': '💸',
+ 'moneybag': '💰',
+ 'mongolia': '🇲🇳',
+ 'monkey': '🐒',
+ 'monkey_face': '🐵',
+ 'monocle': '🧐',
+ 'monorail': '🚝',
+ 'montenegro': '🇲🇪',
+ 'montserrat': '🇲🇸',
+ 'moon_cake': '🥮',
+ 'morocco': '🇲🇦',
+ 'mortar_board': '🎓',
+ 'mosque': '🕌',
+ 'mosquito': '🦟',
+ 'motor_boat': '🛥',
+ 'motor_scooter': '🛵',
+ 'motorcycle': '🏍',
+ 'motorway': '🛣',
+ 'mount_fuji': '🗻',
+ 'mountain': '⛰',
+ 'mountain_biking_man': '🚵',
+ 'mountain_biking_woman': '🚵♀️',
+ 'mountain_cableway': '🚠',
+ 'mountain_railway': '🚞',
+ 'mountain_snow': '🏔',
+ 'mouse': '🐭',
+ 'mouse2': '🐁',
+ 'movie_camera': '🎥',
+ 'moyai': '🗿',
+ 'mozambique': '🇲🇿',
+ 'mrs_claus': '🤶',
+ 'muscle': '💪',
+ 'mushroom': '🍄',
+ 'musical_keyboard': '🎹',
+ 'musical_note': '🎵',
+ 'musical_score': '🎼',
+ 'mute': '🔇',
+ 'myanmar': '🇲🇲',
+ 'nail_care': '💅',
+ 'name_badge': '📛',
+ 'namibia': '🇳🇦',
+ 'national_park': '🏞',
+ 'nauru': '🇳🇷',
+ 'nauseated_face': '🤢',
+ 'nazar_amulet': '🧿',
+ 'necktie': '👔',
+ 'negative_squared_cross_mark': '❎',
+ 'nepal': '🇳🇵',
+ 'nerd_face': '🤓',
+ 'netherlands': '🇳🇱',
+ 'neutral_face': '😐',
+ 'new': '🆕',
+ 'new_caledonia': '🇳🇨',
+ 'new_moon': '🌑',
+ 'new_moon_with_face': '🌚',
+ 'new_zealand': '🇳🇿',
+ 'newspaper': '📰',
+ 'newspaper_roll': '🗞',
+ 'next_track_button': '⏭',
+ 'ng': '🆖',
+ 'nicaragua': '🇳🇮',
+ 'niger': '🇳🇪',
+ 'nigeria': '🇳🇬',
+ 'night_with_stars': '🌃',
+ 'nine': '9️⃣',
+ 'niue': '🇳🇺',
+ 'no_bell': '🔕',
+ 'no_bicycles': '🚳',
+ 'no_entry': '⛔',
+ 'no_entry_sign': '🚫',
+ 'no_good_man': '🙅♂️',
+ 'no_good_woman': '🙅',
+ 'no_mobile_phones': '📵',
+ 'no_mouth': '😶',
+ 'no_pedestrians': '🚷',
+ 'no_smoking': '🚭',
+ 'non-potable_water': '🚱',
+ 'norfolk_island': '🇳🇫',
+ 'north_korea': '🇰🇵',
+ 'northern_mariana_islands': '🇲🇵',
+ 'norway': '🇳🇴',
+ 'nose': '👃',
+ 'notebook': '📓',
+ 'notebook_with_decorative_cover': '📔',
+ 'notes': '🎶',
+ 'nut_and_bolt': '🔩',
+ 'o': '⭕',
+ 'o2': '🅾️',
+ 'ocean': '🌊',
+ 'octopus': '🐙',
+ 'oden': '🍢',
+ 'office': '🏢',
+ 'oil_drum': '🛢',
+ 'ok': '🆗',
+ 'ok_hand': '👌',
+ 'ok_man': '🙆♂️',
+ 'ok_woman': '🙆',
+ 'old_key': '🗝',
+ 'older_adult': '🧓',
+ 'older_man': '👴',
+ 'older_woman': '👵',
+ 'om': '🕉',
+ 'oman': '🇴🇲',
+ 'on': '🔛',
+ 'oncoming_automobile': '🚘',
+ 'oncoming_bus': '🚍',
+ 'oncoming_police_car': '🚔',
+ 'oncoming_taxi': '🚖',
+ 'one': '1️⃣',
+ 'open_book': '📖',
+ 'open_file_folder': '📂',
+ 'open_hands': '👐',
+ 'open_mouth': '😮',
+ 'open_umbrella': '☂',
+ 'ophiuchus': '⛎',
+ 'orange_book': '📙',
+ 'orange_heart': '🧡',
+ 'orthodox_cross': '☦',
+ 'outbox_tray': '📤',
+ 'owl': '🦉',
+ 'ox': '🐂',
+ 'package': '📦',
+ 'page_facing_up': '📄',
+ 'page_with_curl': '📃',
+ 'pager': '📟',
+ 'paintbrush': '🖌',
+ 'pakistan': '🇵🇰',
+ 'palau': '🇵🇼',
+ 'palestinian_territories': '🇵🇸',
+ 'palm_tree': '🌴',
+ 'palms_up': '🤲',
+ 'panama': '🇵🇦',
+ 'pancakes': '🥞',
+ 'panda_face': '🐼',
+ 'paperclip': '📎',
+ 'paperclips': '🖇',
+ 'papua_new_guinea': '🇵🇬',
+ 'paraguay': '🇵🇾',
+ 'parasol_on_ground': '⛱',
+ 'parking': '🅿️',
+ 'parrot': '🦜',
+ 'part_alternation_mark': '〽️',
+ 'partly_sunny': '⛅',
+ 'partying': '🥳',
+ 'passenger_ship': '🛳',
+ 'passport_control': '🛂',
+ 'pause_button': '⏸',
+ 'paw_prints': '🐾',
+ 'peace_symbol': '☮',
+ 'peach': '🍑',
+ 'peacock': '🦚',
+ 'peanuts': '🥜',
+ 'pear': '🍐',
+ 'pen': '🖊',
+ 'pencil2': '✏️',
+ 'penguin': '🐧',
+ 'pensive': '😔',
+ 'performing_arts': '🎭',
+ 'persevere': '😣',
+ 'person_fencing': '🤺',
+ 'peru': '🇵🇪',
+ 'petri_dish': '🧫',
+ 'philippines': '🇵🇭',
+ 'phone': '☎️',
+ 'pick': '⛏',
+ 'pie': '🥧',
+ 'pig': '🐷',
+ 'pig2': '🐖',
+ 'pig_nose': '🐽',
+ 'pill': '💊',
+ 'pineapple': '🍍',
+ 'ping_pong': '🏓',
+ 'pirate_flag': '🏴☠️',
+ 'pisces': '♓',
+ 'pitcairn_islands': '🇵🇳',
+ 'pizza': '🍕',
+ 'place_of_worship': '🛐',
+ 'plate_with_cutlery': '🍽',
+ 'play_or_pause_button': '⏯',
+ 'pleading': '🥺',
+ 'point_down': '👇',
+ 'point_left': '👈',
+ 'point_right': '👉',
+ 'point_up': '☝',
+ 'point_up_2': '👆',
+ 'poland': '🇵🇱',
+ 'police_car': '🚓',
+ 'policeman': '👮',
+ 'policewoman': '👮♀️',
+ 'poodle': '🐩',
+ 'poop': '💩',
+ 'popcorn': '🍿',
+ 'portugal': '🇵🇹',
+ 'post_office': '🏣',
+ 'postal_horn': '📯',
+ 'postbox': '📮',
+ 'potable_water': '🚰',
+ 'potato': '🥔',
+ 'pouch': '👝',
+ 'poultry_leg': '🍗',
+ 'pound': '💷',
+ 'pouting_cat': '😾',
+ 'pouting_man': '🙎♂️',
+ 'pouting_woman': '🙎',
+ 'pray': '🙏',
+ 'prayer_beads': '📿',
+ 'pregnant_woman': '🤰',
+ 'pretzel': '🥨',
+ 'previous_track_button': '⏮',
+ 'prince': '🤴',
+ 'princess': '👸',
+ 'printer': '🖨',
+ 'puerto_rico': '🇵🇷',
+ 'purple_heart': '💜',
+ 'purse': '👛',
+ 'pushpin': '📌',
+ 'put_litter_in_its_place': '🚮',
+ 'qatar': '🇶🇦',
+ 'question': '❓',
+ 'rabbit': '🐰',
+ 'rabbit2': '🐇',
+ 'raccoon': '🦝',
+ 'racehorse': '🐎',
+ 'racing_car': '🏎',
+ 'radio': '📻',
+ 'radio_button': '🔘',
+ 'radioactive': '☢',
+ 'rage': '😡',
+ 'railway_car': '🚃',
+ 'railway_track': '🛤',
+ 'rainbow': '🌈',
+ 'rainbow_flag': '🏳️🌈',
+ 'raised_back_of_hand': '🤚',
+ 'raised_eyebrow': '🤨',
+ 'raised_hand': '✋',
+ 'raised_hand_with_fingers_splayed': '🖐',
+ 'raised_hands': '🙌',
+ 'raising_hand_man': '🙋♂️',
+ 'raising_hand_woman': '🙋',
+ 'ram': '🐏',
+ 'ramen': '🍜',
+ 'rat': '🐀',
+ 'receipt': '🧾',
+ 'record_button': '⏺',
+ 'recycle': '♻️',
+ 'red_car': '🚗',
+ 'red_circle': '🔴',
+ 'red_envelope': '🧧',
+ 'registered': '®️',
+ 'relaxed': '☺️',
+ 'relieved': '😌',
+ 'reminder_ribbon': '🎗',
+ 'repeat': '🔁',
+ 'repeat_one': '🔂',
+ 'rescue_worker_helmet': '⛑',
+ 'restroom': '🚻',
+ 'reunion': '🇷🇪',
+ 'revolving_hearts': '💞',
+ 'rewind': '⏪',
+ 'rhinoceros': '🦏',
+ 'ribbon': '🎀',
+ 'rice': '🍚',
+ 'rice_ball': '🍙',
+ 'rice_cracker': '🍘',
+ 'rice_scene': '🎑',
+ 'right_anger_bubble': '🗯',
+ 'ring': '💍',
+ 'robot': '🤖',
+ 'rocket': '🚀',
+ 'rofl': '🤣',
+ 'roll_eyes': '🙄',
+ 'roller_coaster': '🎢',
+ 'romania': '🇷🇴',
+ 'rooster': '🐓',
+ 'rose': '🌹',
+ 'rosette': '🏵',
+ 'rotating_light': '🚨',
+ 'round_pushpin': '📍',
+ 'rowing_man': '🚣',
+ 'rowing_woman': '🚣♀️',
+ 'ru': '🇷🇺',
+ 'rugby_football': '🏉',
+ 'running_man': '🏃',
+ 'running_shirt_with_sash': '🎽',
+ 'running_woman': '🏃♀️',
+ 'rwanda': '🇷🇼',
+ 'sa': '🈂️',
+ 'safety_pin': '🧷',
+ 'sagittarius': '♐',
+ 'sailboat': '⛵',
+ 'sake': '🍶',
+ 'salt': '🧂',
+ 'samoa': '🇼🇸',
+ 'san_marino': '🇸🇲',
+ 'sandal': '👡',
+ 'sandwich': '🥪',
+ 'santa': '🎅',
+ 'sao_tome_principe': '🇸🇹',
+ 'satellite': '📡',
+ 'saudi_arabia': '🇸🇦',
+ 'sauropod': '🦕',
+ 'saxophone': '🎷',
+ 'scarf': '🧣',
+ 'school': '🏫',
+ 'school_satchel': '🎒',
+ 'scissors': '✂️',
+ 'scorpion': '🦂',
+ 'scorpius': '♏',
+ 'scotland': '🏴',
+ 'scream': '😱',
+ 'scream_cat': '🙀',
+ 'scroll': '📜',
+ 'seat': '💺',
+ 'secret': '㊙️',
+ 'see_no_evil': '🙈',
+ 'seedling': '🌱',
+ 'selfie': '🤳',
+ 'senegal': '🇸🇳',
+ 'serbia': '🇷🇸',
+ 'seven': '7️⃣',
+ 'seychelles': '🇸🇨',
+ 'shallow_pan_of_food': '🥘',
+ 'shamrock': '☘',
+ 'shark': '🦈',
+ 'shaved_ice': '🍧',
+ 'sheep': '🐑',
+ 'shell': '🐚',
+ 'shield': '🛡',
+ 'shinto_shrine': '⛩',
+ 'ship': '🚢',
+ 'shopping': '🛍',
+ 'shopping_cart': '🛒',
+ 'shower': '🚿',
+ 'shrimp': '🦐',
+ 'shushing': '🤫',
+ 'sierra_leone': '🇸🇱',
+ 'signal_strength': '📶',
+ 'singapore': '🇸🇬',
+ 'sint_maarten': '🇸🇽',
+ 'six': '6️⃣',
+ 'six_pointed_star': '🔯',
+ 'skateboard': '🛹',
+ 'ski': '🎿',
+ 'skier': '⛷',
+ 'skull': '💀',
+ 'skull_and_crossbones': '☠',
+ 'sled': '🛷',
+ 'sleeping': '😴',
+ 'sleeping_bed': '🛌',
+ 'sleepy': '😪',
+ 'slightly_frowning_face': '🙁',
+ 'slightly_smiling_face': '🙂',
+ 'slot_machine': '🎰',
+ 'slovakia': '🇸🇰',
+ 'slovenia': '🇸🇮',
+ 'small_airplane': '🛩',
+ 'small_blue_diamond': '🔹',
+ 'small_orange_diamond': '🔸',
+ 'small_red_triangle': '🔺',
+ 'small_red_triangle_down': '🔻',
+ 'smile': '😄',
+ 'smile_cat': '😸',
+ 'smiley': '😃',
+ 'smiley_cat': '😺',
+ 'smiling_face_with_three_hearts': '🥰',
+ 'smiling_imp': '😈',
+ 'smirk': '😏',
+ 'smirk_cat': '😼',
+ 'smoking': '🚬',
+ 'snail': '🐌',
+ 'snake': '🐍',
+ 'sneezing_face': '🤧',
+ 'snowboarder': '🏂',
+ 'snowflake': '❄️',
+ 'snowman': '⛄',
+ 'snowman_with_snow': '☃',
+ 'soap': '🧼',
+ 'sob': '😭',
+ 'soccer': '⚽',
+ 'socks': '🧦',
+ 'softball': '🥎',
+ 'solomon_islands': '🇸🇧',
+ 'somalia': '🇸🇴',
+ 'soon': '🔜',
+ 'sorceress': '🧙♀️',
+ 'sos': '🆘',
+ 'sound': '🔉',
+ 'south_africa': '🇿🇦',
+ 'south_georgia_south_sandwich_islands': '🇬🇸',
+ 'south_sudan': '🇸🇸',
+ 'space_invader': '👾',
+ 'spades': '♠️',
+ 'spaghetti': '🍝',
+ 'sparkle': '❇️',
+ 'sparkler': '🎇',
+ 'sparkles': '✨',
+ 'sparkling_heart': '💖',
+ 'speak_no_evil': '🙊',
+ 'speaker': '🔈',
+ 'speaking_head': '🗣',
+ 'speech_balloon': '💬',
+ 'speedboat': '🚤',
+ 'spider': '🕷',
+ 'spider_web': '🕸',
+ 'spiral_calendar': '🗓',
+ 'spiral_notepad': '🗒',
+ 'sponge': '🧽',
+ 'spoon': '🥄',
+ 'squid': '🦑',
+ 'sri_lanka': '🇱🇰',
+ 'st_barthelemy': '🇧🇱',
+ 'st_helena': '🇸🇭',
+ 'st_kitts_nevis': '🇰🇳',
+ 'st_lucia': '🇱🇨',
+ 'st_pierre_miquelon': '🇵🇲',
+ 'st_vincent_grenadines': '🇻🇨',
+ 'stadium': '🏟',
+ 'star': '⭐',
+ 'star2': '🌟',
+ 'star_and_crescent': '☪',
+ 'star_of_david': '✡',
+ 'star_struck': '🤩',
+ 'stars': '🌠',
+ 'station': '🚉',
+ 'statue_of_liberty': '🗽',
+ 'steak': '🥩',
+ 'steam_locomotive': '🚂',
+ 'stew': '🍲',
+ 'stop_button': '⏹',
+ 'stop_sign': '🛑',
+ 'stopwatch': '⏱',
+ 'straight_ruler': '📏',
+ 'strawberry': '🍓',
+ 'stuck_out_tongue': '😛',
+ 'stuck_out_tongue_closed_eyes': '😝',
+ 'stuck_out_tongue_winking_eye': '😜',
+ 'studio_microphone': '🎙',
+ 'stuffed_flatbread': '🥙',
+ 'sudan': '🇸🇩',
+ 'sun_behind_large_cloud': '🌥',
+ 'sun_behind_rain_cloud': '🌦',
+ 'sun_behind_small_cloud': '🌤',
+ 'sun_with_face': '🌞',
+ 'sunflower': '🌻',
+ 'sunglasses': '😎',
+ 'sunny': '☀️',
+ 'sunrise': '🌅',
+ 'sunrise_over_mountains': '🌄',
+ 'surfing_man': '🏄',
+ 'surfing_woman': '🏄♀️',
+ 'suriname': '🇸🇷',
+ 'sushi': '🍣',
+ 'suspension_railway': '🚟',
+ 'swan': '🦢',
+ 'swaziland': '🇸🇿',
+ 'sweat': '😓',
+ 'sweat_drops': '💦',
+ 'sweat_smile': '😅',
+ 'sweden': '🇸🇪',
+ 'sweet_potato': '🍠',
+ 'swimming_man': '🏊',
+ 'swimming_woman': '🏊♀️',
+ 'switzerland': '🇨🇭',
+ 'symbols': '🔣',
+ 'symbols_over_mouth': '🤬',
+ 'synagogue': '🕍',
+ 'syria': '🇸🇾',
+ 'syringe': '💉',
+ 't-rex': '🦖',
+ 'taco': '🌮',
+ 'tada': '🎉',
+ 'taiwan': '🇹🇼',
+ 'tajikistan': '🇹🇯',
+ 'takeout_box': '🥡',
+ 'tanabata_tree': '🎋',
+ 'tangerine': '🍊',
+ 'tanzania': '🇹🇿',
+ 'taurus': '♉',
+ 'taxi': '🚕',
+ 'tea': '🍵',
+ 'teddy_bear': '🧸',
+ 'telephone_receiver': '📞',
+ 'telescope': '🔭',
+ 'tennis': '🎾',
+ 'tent': '⛺',
+ 'test_tube': '🧪',
+ 'thailand': '🇹🇭',
+ 'thermometer': '🌡',
+ 'thinking': '🤔',
+ 'thought_balloon': '💭',
+ 'thread': '🧵',
+ 'three': '3️⃣',
+ 'ticket': '🎫',
+ 'tickets': '🎟',
+ 'tiger': '🐯',
+ 'tiger2': '🐅',
+ 'timer_clock': '⏲',
+ 'timor_leste': '🇹🇱',
+ 'tipping_hand_man': '💁♂️',
+ 'tipping_hand_woman': '💁',
+ 'tired_face': '😫',
+ 'tm': '™️',
+ 'togo': '🇹🇬',
+ 'toilet': '🚽',
+ 'toilet_paper': '🧻',
+ 'tokelau': '🇹🇰',
+ 'tokyo_tower': '🗼',
+ 'tomato': '🍅',
+ 'tonga': '🇹🇴',
+ 'tongue': '👅',
+ 'toolbox': '🧰',
+ 'tooth': '🦷',
+ 'top': '🔝',
+ 'tophat': '🎩',
+ 'tornado': '🌪',
+ 'tr': '🇹🇷',
+ 'trackball': '🖲',
+ 'tractor': '🚜',
+ 'traffic_light': '🚥',
+ 'train': '🚋',
+ 'train2': '🚆',
+ 'tram': '🚊',
+ 'triangular_flag_on_post': '🚩',
+ 'triangular_ruler': '📐',
+ 'trident': '🔱',
+ 'trinidad_tobago': '🇹🇹',
+ 'triumph': '😤',
+ 'trolleybus': '🚎',
+ 'trophy': '🏆',
+ 'tropical_drink': '🍹',
+ 'tropical_fish': '🐠',
+ 'truck': '🚚',
+ 'trumpet': '🎺',
+ 'tshirt': '👕',
+ 'tulip': '🌷',
+ 'tumbler_glass': '🥃',
+ 'tunisia': '🇹🇳',
+ 'turkey': '🦃',
+ 'turkmenistan': '🇹🇲',
+ 'turks_caicos_islands': '🇹🇨',
+ 'turtle': '🐢',
+ 'tuvalu': '🇹🇻',
+ 'tv': '📺',
+ 'twisted_rightwards_arrows': '🔀',
+ 'two': '2️⃣',
+ 'two_hearts': '💕',
+ 'two_men_holding_hands': '👬',
+ 'two_women_holding_hands': '👭',
+ 'u5272': '🈹',
+ 'u5408': '🈴',
+ 'u55b6': '🈺',
+ 'u6307': '🈯',
+ 'u6708': '🈷️',
+ 'u6709': '🈶',
+ 'u6e80': '🈵',
+ 'u7121': '🈚',
+ 'u7533': '🈸',
+ 'u7981': '🈲',
+ 'u7a7a': '🈳',
+ 'uganda': '🇺🇬',
+ 'uk': '🇬🇧',
+ 'ukraine': '🇺🇦',
+ 'umbrella': '☔',
+ 'unamused': '😒',
+ 'underage': '🔞',
+ 'unicorn': '🦄',
+ 'united_arab_emirates': '🇦🇪',
+ 'united_nations': '🇺🇳',
+ 'unlock': '🔓',
+ 'up': '🆙',
+ 'upside_down_face': '🙃',
+ 'uruguay': '🇺🇾',
+ 'us': '🇺🇸',
+ 'us_virgin_islands': '🇻🇮',
+ 'uzbekistan': '🇺🇿',
+ 'v': '✌',
+ 'vanuatu': '🇻🇺',
+ 'vatican_city': '🇻🇦',
+ 'venezuela': '🇻🇪',
+ 'vertical_traffic_light': '🚦',
+ 'vhs': '📼',
+ 'vibration_mode': '📳',
+ 'video_camera': '📹',
+ 'video_game': '🎮',
+ 'vietnam': '🇻🇳',
+ 'violin': '🎻',
+ 'virgo': '♍',
+ 'volcano': '🌋',
+ 'volleyball': '🏐',
+ 'vomiting': '🤮',
+ 'vs': '🆚',
+ 'vulcan_salute': '🖖',
+ 'wales': '🏴',
+ 'walking_man': '🚶',
+ 'walking_woman': '🚶♀️',
+ 'wallis_futuna': '🇼🇫',
+ 'waning_crescent_moon': '🌘',
+ 'waning_gibbous_moon': '🌖',
+ 'warning': '⚠️',
+ 'wastebasket': '🗑',
+ 'watch': '⌚',
+ 'water_buffalo': '🐃',
+ 'watermelon': '🍉',
+ 'wave': '👋',
+ 'wavy_dash': '〰️',
+ 'waxing_crescent_moon': '🌒',
+ 'waxing_gibbous_moon': '🌔',
+ 'wc': '🚾',
+ 'weary': '😩',
+ 'wedding': '💒',
+ 'weight_lifting_man': '🏋',
+ 'weight_lifting_woman': '🏋️♀️',
+ 'western_sahara': '🇪🇭',
+ 'whale': '🐳',
+ 'whale2': '🐋',
+ 'wheel_of_dharma': '☸',
+ 'wheelchair': '♿',
+ 'white_check_mark': '✅',
+ 'white_circle': '⚪',
+ 'white_flag': '🏳',
+ 'white_flower': '💮',
+ 'white_large_square': '⬜',
+ 'white_medium_small_square': '◽',
+ 'white_medium_square': '◻️',
+ 'white_small_square': '▫️',
+ 'white_square_button': '🔳',
+ 'wilted_flower': '🥀',
+ 'wind_chime': '🎐',
+ 'wind_face': '🌬',
+ 'wine_glass': '🍷',
+ 'wink': '😉',
+ 'wizard': '🧙♂️',
+ 'wolf': '🐺',
+ 'woman': '👩',
+ 'woman_artist': '👩🎨',
+ 'woman_astronaut': '👩🚀',
+ 'woman_cartwheeling': '🤸♀️',
+ 'woman_cook': '👩🍳',
+ 'woman_elf': '🧝♀️',
+ 'woman_facepalming': '🤦♀️',
+ 'woman_factory_worker': '👩🏭',
+ 'woman_fairy': '🧚♀️',
+ 'woman_farmer': '👩🌾',
+ 'woman_firefighter': '👩🚒',
+ 'woman_genie': '🧞♀️',
+ 'woman_health_worker': '👩⚕️',
+ 'woman_in_lotus_position': '🧘♀️',
+ 'woman_in_steamy_room': '🧖♀️',
+ 'woman_judge': '👩⚖️',
+ 'woman_juggling': '🤹♀️',
+ 'woman_mechanic': '👩🔧',
+ 'woman_office_worker': '👩💼',
+ 'woman_pilot': '👩✈️',
+ 'woman_playing_handball': '🤾♀️',
+ 'woman_playing_water_polo': '🤽♀️',
+ 'woman_scientist': '👩🔬',
+ 'woman_shrugging': '🤷',
+ 'woman_singer': '👩🎤',
+ 'woman_student': '👩🎓',
+ 'woman_superhero': '🦸♀️',
+ 'woman_supervillain': '🦹♀️',
+ 'woman_teacher': '👩🏫',
+ 'woman_technologist': '👩💻',
+ 'woman_vampire': '🧛♀️',
+ 'woman_with_headscarf': '🧕',
+ 'woman_with_turban': '👳♀️',
+ 'woman_zombie': '🧟♀️',
+ 'womans_clothes': '👚',
+ 'womans_hat': '👒',
+ 'women_wrestling': '🤼♀️',
+ 'womens': '🚺',
+ 'woozy': '🥴',
+ 'world_map': '🗺',
+ 'worried': '😟',
+ 'wrench': '🔧',
+ 'writing_hand': '✍',
+ 'x': '❌',
+ 'yarn': '🧶',
+ 'yellow_heart': '💛',
+ 'yemen': '🇾🇪',
+ 'yen': '💴',
+ 'yin_yang': '☯',
+ 'yum': '😋',
+ 'zambia': '🇿🇲',
+ 'zany': '🤪',
+ 'zap': '⚡',
+ 'zebra': '🦓',
+ 'zero': '0️⃣',
+ 'zimbabwe': '🇿🇼',
+ 'zipper_mouth_face': '🤐',
+ 'zzz': '💤',
+};
diff --git a/pkgs/markdown/lib/src/line.dart b/pkgs/markdown/lib/src/line.dart
new file mode 100644
index 0000000..1ccd5da
--- /dev/null
+++ b/pkgs/markdown/lib/src/line.dart
@@ -0,0 +1,47 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'patterns.dart';
+
+/// A [Line] is a sequence of zero or more characters other than line feed
+/// (`U+000A`) or carriage return (`U+000D`), followed by a line ending or by
+/// the end of file.
+// See https://spec.commonmark.org/0.30/#line.
+class Line {
+ /// A sequence of zero or more characters other than the line ending.
+ final String content;
+
+ /// How many spaces of a tab that remains after part of it has been consumed.
+ // See: https://spec.commonmark.org/0.30/#example-6
+ // We cannot simply expand the `tabRemaining` to spaces, for example
+ //
+ // `>\t\tfoo`
+ //
+ // If we expand the 2 space width `tabRemaining` from blockquote block into 2
+ // spaces, so the string segment for the indented code block is:
+ //
+ // ` \tfoo`,
+ //
+ // then the output will be:
+ // ```html
+ // <pre><code>foo
+ // </code></pre>
+ // ```
+ // instead of the expected:
+ // ```html
+ // <pre><code> foo
+ // </code></pre>
+ // ```
+ final int? tabRemaining;
+
+ // A line containing no characters, or a line containing only spaces
+ // (`U+0020`) or tabs (`U+0009`), is called a blank line.
+ // https://spec.commonmark.org/0.30/#blank-line
+ final bool isBlankLine;
+
+ Line(
+ this.content, {
+ this.tabRemaining,
+ }) : isBlankLine = emptyPattern.hasMatch(content);
+}
diff --git a/pkgs/markdown/lib/src/link_parser.dart b/pkgs/markdown/lib/src/link_parser.dart
new file mode 100644
index 0000000..4db22ad
--- /dev/null
+++ b/pkgs/markdown/lib/src/link_parser.dart
@@ -0,0 +1,270 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'charcode.dart';
+import 'text_parser.dart';
+import 'util.dart';
+
+class LinkParser extends TextParser {
+ /// If there is a valid link formed.
+ bool get valid => _valid;
+ bool _valid = false;
+
+ /// Link label.
+ String? get label => _label;
+ String? _label;
+
+ /// Link destination.
+ String? get destination => _destination;
+ String? _destination;
+
+ /// Link title.
+ String? get title => _title;
+ String? _title;
+
+ LinkParser(super.source);
+
+ /// How many lines of the [source] have been consumed by link reference
+ /// definition.
+ int get unconsumedLines => _unconsumedLines;
+ int _unconsumedLines = 0;
+
+ /// Parses [source] to a link reference definition.
+ void parseDefinition() {
+ if (!parseLabel() || isDone || charAt() != $colon) {
+ return;
+ }
+
+ // Advance to the next character after the colon.
+ advance();
+ if (!_parseDestination()) {
+ return;
+ }
+
+ var precedingWhitespaces = moveThroughWhitespace();
+ if (isDone) {
+ _valid = true;
+ return;
+ }
+
+ final multiline = charAt() == $lf;
+ precedingWhitespaces += moveThroughWhitespace(multiLine: true);
+
+ // The title must be preceded by whitespaces.
+ if (precedingWhitespaces == 0 || isDone) {
+ _valid = isDone;
+ return;
+ }
+
+ final hasValidTitle = _parseTitle();
+ // For example: `[foo]: <bar> "baz` is a invalid definition, but this one is
+ // valid:
+ // ```
+ // [foo]: <bar>
+ // "baz
+ // ```
+ if (!hasValidTitle && !multiline) {
+ return;
+ }
+
+ if (hasValidTitle) {
+ moveThroughWhitespace();
+ if (!isDone && charAt() != $lf) {
+ // It is not a valid definition if the title is followed by
+ // non-whitespace characters, for example: `[foo]: <bar> "baz" hello`.
+ // See https://spec.commonmark.org/0.30/#example-209.
+ if (!multiline) {
+ return;
+ }
+ // But it is a valid link reference definition if this definition is
+ // multiline, see https://spec.commonmark.org/0.30/#example-210.
+ _title = null;
+ }
+ }
+
+ final linesUnconsumed = source.substring(pos).split('\n');
+ if (linesUnconsumed.isNotEmpty && linesUnconsumed.first.isBlank) {
+ linesUnconsumed.removeAt(0);
+ }
+ _unconsumedLines = linesUnconsumed.length;
+
+ _valid = true;
+ }
+
+ /// Parses the link label, returns `true` if there is a valid link label.
+ bool parseLabel() {
+ moveThroughWhitespace(multiLine: true);
+
+ if (length - pos < 2) {
+ return false;
+ }
+
+ if (charAt() != $lbracket) {
+ return false;
+ }
+
+ // Advance past the opening `[`.
+ advance();
+ final start = pos;
+
+ // A link label can have at most 999 characters inside the square brackets.
+ // See https://spec.commonmark.org/0.30/#link-label.
+ var maxLoop = 999;
+ while (true) {
+ if (maxLoop-- < 0) {
+ return false;
+ }
+ final char = charAt(pos);
+ if (char == $backslash) {
+ advance();
+ } else if (char == $lbracket) {
+ return false;
+ } else if (char == $rbracket) {
+ break;
+ }
+ advance();
+ if (isDone) {
+ return false;
+ }
+ }
+
+ final text = substring(start, pos);
+ if (text.isBlank) {
+ return false;
+ }
+
+ // Advance past the closing `]`.
+ advance();
+ _label = text;
+ return true;
+ }
+
+ /// Parses the link destination, returns `true` there is a valid link
+ /// destination.
+ bool _parseDestination() {
+ moveThroughWhitespace(multiLine: true);
+ if (isDone) {
+ return false;
+ }
+
+ final isValidDestination = charAt() == $lt
+ ? _parseBracketedDestination()
+ : _parseBareDestination();
+
+ return isValidDestination;
+ }
+
+ /// Parses bracketed destinations (destinations wrapped in `<...>`). The
+ /// current position of the parser must be the first character of the
+ /// destination.
+ ///
+ /// Returns `true` if there is a valid link destination.
+ bool _parseBracketedDestination() {
+ // Walk past the opening `<`.
+ advance();
+
+ final start = pos;
+ while (true) {
+ final char = charAt();
+ if (char == $backslash) {
+ advance();
+ } else if (char == $lf || char == $cr || char == $ff) {
+ return false;
+ } else if (char == $gt) {
+ break;
+ }
+ advance();
+ if (isDone) {
+ return false;
+ }
+ }
+
+ _destination = substring(start, pos);
+
+ // Advance past the closing `>`.
+ advance();
+ return true;
+ }
+
+ /// Parse "bare" destinations (destinations _not_ wrapped in `<...>`). The
+ /// current position of the parser must be the first character of the
+ /// destination.
+ ///
+ /// Returns `true` if there is a valid link destination.
+ bool _parseBareDestination() {
+ var parenCount = 0;
+ final start = pos;
+
+ while (true) {
+ final char = charAt();
+ if (char == $backslash) {
+ advance();
+ } else if (char == $space || char == $lf || char == $cr || char == $ff) {
+ break;
+ } else if (char == $lparen) {
+ parenCount++;
+ } else if (char == $rparen) {
+ parenCount--;
+ if (parenCount == 0) {
+ advance();
+ break;
+ }
+ }
+ advance();
+
+ // There is no ending delimiter, so `isDone` also means it is at the end
+ // of a link destination.
+ if (isDone) {
+ break;
+ }
+ }
+
+ _destination = substring(start, pos);
+ return true;
+ }
+
+ /// Parses the **optional** link title, returns `true` if there is a valid
+ /// link title.
+ bool _parseTitle() {
+ // See: https://spec.commonmark.org/0.30/#link-title
+ // The whitespace should be followed by a title delimiter.
+ final delimiter = charAt();
+ if (delimiter != $apostrophe &&
+ delimiter != $quote &&
+ delimiter != $lparen) {
+ return false;
+ }
+
+ final closeDelimiter = delimiter == $lparen ? $rparen : delimiter;
+ advance();
+ if (isDone) {
+ return false;
+ }
+ final start = pos;
+
+ // Looking for an un-escaped closing delimiter.
+ while (true) {
+ final char = charAt();
+ if (char == $backslash) {
+ advance();
+ } else if (char == closeDelimiter) {
+ break;
+ }
+ advance();
+ if (isDone) {
+ return false;
+ }
+ }
+
+ if (isDone) {
+ return false;
+ }
+
+ _title = substring(start, pos);
+
+ // Advance past the closing delimiter.
+ advance();
+ return true;
+ }
+}
diff --git a/pkgs/markdown/lib/src/patterns.dart b/pkgs/markdown/lib/src/patterns.dart
new file mode 100644
index 0000000..2690419
--- /dev/null
+++ b/pkgs/markdown/lib/src/patterns.dart
@@ -0,0 +1,162 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// The line contains only whitespace or is empty.
+final emptyPattern = RegExp(r'^(?:[ \t]*)$');
+
+/// A series of `=` or `-` (on the next line) define setext-style headers.
+final setextPattern = RegExp(r'^[ ]{0,3}(=+|-+)\s*$');
+
+/// Leading (and trailing) `#` define atx-style headers.
+///
+/// Starts with 1-6 unescaped `#` characters which must not be followed by a
+/// non-space character. Line may end with any number of `#` characters,.
+final headerPattern =
+ RegExp(r'^ {0,3}(#{1,6})(?:[ \x09\x0b\x0c].*?)?(?:\s(#*)\s*)?$');
+
+/// The line starts with `>` with one optional space after.
+final blockquotePattern = RegExp(r'^[ ]{0,3}>[ \t]?.*$');
+
+/// A line indented four spaces. Used for code blocks and lists.
+final indentPattern = RegExp(r'^(?: | {0,3}\t)(.*)$');
+
+/// Fenced code block.
+final codeFencePattern = RegExp(
+ '^([ ]{0,3})(?:(?<backtick>`{3,})(?<backtickInfo>[^`]*)|'
+ r'(?<tilde>~{3,})(?<tildeInfo>.*))$',
+);
+
+/// Fenced blockquotes.
+final blockquoteFencePattern = RegExp(r'^>{3}\s*$');
+
+/// Three or more hyphens, asterisks or underscores by themselves. Note that
+/// a line like `----` is valid as both HR and SETEXT. In case of a tie,
+/// SETEXT should win.
+final hrPattern = RegExp(r'^ {0,3}([-*_])[ \t]*\1[ \t]*\1(?:\1|[ \t])*$');
+
+/// **Unordered list**
+/// A line starting with one of these markers: `-`, `*`, `+`. May have up to
+/// three leading spaces before the marker and any number of spaces or tabs
+/// after.
+///
+/// **Ordered list**
+///
+/// A line starting with a number like `123.`. May have up to three leading
+/// spaces before the marker and any number of spaces or tabs after.
+final listPattern =
+ RegExp(r'^[ ]{0,3}(?:(\d{1,9})[\.)]|[*+-])(?:[ \t]+(.*))?$');
+
+/// A line of hyphens separated by at least one pipe.
+final tablePattern = RegExp(
+ r'^[ ]{0,3}\|?([ \t]*:?\-+:?[ \t]*\|[ \t]*)+([ \t]|[ \t]*:?\-+:?[ \t]*)?$');
+
+/// A line starting with `[^` and contains with `]:`, but without special chars
+/// (`\] \r\n\x00\t`) between. Same as [GFM](cmark-gfm/src/scanners.re:318).
+final footnotePattern = RegExp(r'(^[ ]{0,3})\[\^([^\] \r\n\x00\t]+)\]:[ \t]*');
+
+/// A pattern which should never be used. It just satisfies non-nullability of
+/// pattern fields.
+final dummyPattern = RegExp('');
+
+/// A [String] pattern to match a named tag like `<table>` or `</table>`.
+const namedTagDefinition =
+ // Opening tag begins.
+ '<'
+
+ // Tag name.
+ '[a-z][a-z0-9-]*'
+
+ // Attribute begins, see
+ // https://spec.commonmark.org/0.30/#attribute.
+ r'(?:\s+'
+
+ // Attribute name, see
+ // https://spec.commonmark.org/0.30/#attribute-name.
+ '[a-z_:][a-z0-9._:-]*'
+
+ //
+ '(?:'
+ // Attribute value specification, see
+ // https://spec.commonmark.org/0.30/#attribute-value-specification.
+ r'\s*=\s*'
+
+ // Attribute value, see
+ // https://spec.commonmark.org/0.30/#unquoted-attribute-value.
+ r'''(?:[^\s"'=<>`]+?|'[^']*?'|"[^"]*?")'''
+
+ // Attribute ends.
+ ')?)*'
+
+ // Opening tag ends.
+ r'\s*/?>'
+
+ // Or
+ '|'
+
+ // Closing tag, see
+ // https://spec.commonmark.org/0.30/#closing-tag.
+ r'</[a-z][a-z0-9-]*\s*>';
+
+/// A pattern to match the start of an HTML block.
+///
+/// The 7 conditions here correspond to the 7 start conditions in the Commonmark
+/// specification one by one: https://spec.commonmark.org/0.30/#html-block.
+final htmlBlockPattern = RegExp(
+ '^ {0,3}(?:'
+ '<(?<condition_1>pre|script|style|textarea)'
+ r'(?:\s|>|$)'
+ '|'
+ '(?<condition_2><!--)'
+ '|'
+ r'(?<condition_3><\?)'
+ '|'
+ '(?<condition_4><![a-z])'
+ '|'
+ r'(?<condition_5><!\[CDATA\[)'
+ '|'
+ '</?(?<condition_6>address|article|aside|base|basefont|blockquote|body|'
+ 'caption|center|col|colgroup|dd|details|dialog|dir|DIV|dl|dt|fieldset|'
+ 'figcaption|figure|footer|form|frame|frameset|h1|h2|h3|h4|h5|h6|head|'
+ 'header|hr|html|iframe|legend|li|link|main|menu|menuitem|nav|noframes|ol|'
+ 'optgroup|option|p|param|section|source|summary|table|tbody|td|tfoot|th|'
+ 'thead|title|tr|track|ul)'
+ r'(?:\s|>|/>|$)'
+ '|'
+
+ // Here we are more restrictive than the Commonmark definition (Rule #7).
+ // Otherwise some raw HTML test cases will fail, for example:
+ // https://spec.commonmark.org/0.30/#example-618.
+ // Because if a line is treated as an HTML block, it will output as a
+ // Text node directly, and the RawHtmlSyntax will not have a chance to
+ // validate if this HTML tag is legal or not.
+ '(?<condition_7>(?:$namedTagDefinition)\\s*\$))',
+ caseSensitive: false,
+);
+
+/// ASCII punctuation characters.
+// See https://spec.commonmark.org/0.30/#unicode-whitespace-character.
+const asciiPunctuationCharacters = r'''!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~''';
+
+/// ASCII punctuation characters with some characters escaped, in order to be
+// used in the RegExp character set.
+const asciiPunctuationEscaped = r'''!"#$%&'()*+,\-./:;<=>?@\[\\\]^_`{|}~''';
+
+/// A pattern to match HTML entity references and numeric character references.
+// https://spec.commonmark.org/0.30/#entity-and-numeric-character-references
+final htmlCharactersPattern = RegExp(
+ '&(?:([a-z0-9]+)|#([0-9]{1,7})|#x([a-f0-9]{1,6}));',
+ caseSensitive: false,
+);
+
+/// A line starts with `[`.
+final linkReferenceDefinitionPattern = RegExp(r'^[ ]{0,3}\[');
+
+/// Alert type patterns.
+///
+/// A alert block is similar to a blockquote, starts with `> [!TYPE]`, and only
+/// 5 types are supported (case-insensitive).
+final alertPattern = RegExp(
+ r'^\s{0,3}>\s{0,3}\\?\[!(note|tip|important|caution|warning)\\?\]\s*$',
+ caseSensitive: false,
+);
diff --git a/pkgs/markdown/lib/src/text_parser.dart b/pkgs/markdown/lib/src/text_parser.dart
new file mode 100644
index 0000000..2f696de
--- /dev/null
+++ b/pkgs/markdown/lib/src/text_parser.dart
@@ -0,0 +1,57 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+import 'charcode.dart';
+
+/// A parser to parse a segment of source text.
+class TextParser {
+ final String source;
+
+ TextParser(this.source);
+
+ /// The current read position.
+ var _position = 0;
+ int get pos => _position;
+
+ /// Whether the read position has reached the end of [source].
+ bool get isDone => _position == length;
+
+ /// The length of [source].
+ int get length => source.length;
+
+ /// Walk the parser forward through any whitespace.
+ ///
+ /// Set [multiLine] `true` to support multiline, otherwise it will stop before
+ /// the line feed [$lf].
+ int moveThroughWhitespace({bool multiLine = false}) {
+ var i = 0;
+ while (!isDone) {
+ final char = charAt();
+ if (char != $space &&
+ char != $tab &&
+ char != $vt &&
+ char != $cr &&
+ char != $ff &&
+ !(multiLine && char == $lf)) {
+ return i;
+ }
+
+ i++;
+ advance();
+ }
+ return i;
+ }
+
+ int charAt([int? position]) => source.codeUnitAt(position ?? _position);
+
+ /// Moves the read position one character ahead.
+ void advance() => advanceBy(1);
+
+ /// Moves the read position for [length] characters. [length] can be negative.
+ void advanceBy(int length) {
+ _position += length;
+ }
+
+ /// Substrings the [source] and returns a [String].
+ String substring(int start, [int? end]) => source.substring(start, end);
+}
diff --git a/pkgs/markdown/lib/src/util.dart b/pkgs/markdown/lib/src/util.dart
new file mode 100644
index 0000000..93ea1e6
--- /dev/null
+++ b/pkgs/markdown/lib/src/util.dart
@@ -0,0 +1,220 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert';
+
+import 'assets/case_folding.dart';
+import 'assets/html_entities.dart';
+import 'charcode.dart';
+import 'line.dart';
+import 'patterns.dart';
+
+/// One or more whitespace, for compressing.
+final _oneOrMoreWhitespacePattern = RegExp('[ \n\r\t]+');
+
+/// Escapes (`"`), (`<`), (`>`) and (`&`) characters.
+/// Escapes (`'`) if [escapeApos] is `true`.
+String escapeHtml(String html, {bool escapeApos = true}) =>
+ HtmlEscape(HtmlEscapeMode(
+ escapeApos: escapeApos,
+ escapeLtGt: true,
+ escapeQuot: true,
+ )).convert(html);
+
+/// Escapes (`"`), (`<`) and (`>`) characters.
+String escapeHtmlAttribute(String text) =>
+ const HtmlEscape(HtmlEscapeMode.attribute).convert(text);
+
+/// "Normalizes" a link label, according to the [CommonMark spec].
+///
+/// [CommonMark spec] https://spec.commonmark.org/0.30/#link-label
+String normalizeLinkLabel(String label) {
+ var text = label.trim().replaceAll(_oneOrMoreWhitespacePattern, ' ');
+ for (var i = 0; i < text.length; i++) {
+ final mapped = caseFoldingMap[text[i]];
+ if (mapped != null) {
+ text = text.replaceRange(i, i + 1, mapped);
+ }
+ }
+ return text;
+}
+
+/// Normalizes a link destination, including the process of HTML characters
+/// decoding and percent encoding.
+// See the description of these examples:
+// https://spec.commonmark.org/0.30/#example-501
+// https://spec.commonmark.org/0.30/#example-502
+String normalizeLinkDestination(String destination) {
+ // Split by url escaping characters
+ // Concatenate them with unmodified URL-escaping.
+ // URL-escaping should be left alone inside the destination
+ // Refer: https://spec.commonmark.org/0.30/#example-502.
+
+ final regex = RegExp('%[0-9A-Fa-f]{2}');
+
+ return destination.splitMapJoin(
+ regex,
+ onMatch: (m) => m.match,
+ onNonMatch: (e) {
+ try {
+ e = Uri.decodeFull(e);
+ } catch (_) {}
+ return Uri.encodeFull(decodeHtmlCharacters(e));
+ },
+ );
+}
+
+/// Normalizes a link title, including the process of HTML characters decoding
+/// and HTML characters escaping.
+// See the description of these examples:
+// https://spec.commonmark.org/0.30/#example-505
+// https://spec.commonmark.org/0.30/#example-506
+// https://spec.commonmark.org/0.30/#example-507
+// https://spec.commonmark.org/0.30/#example-508
+String normalizeLinkTitle(String title) =>
+ escapeHtmlAttribute(decodeHtmlCharacters(title));
+
+/// Decodes HTML entity and numeric character references, for example decode
+/// `#` to `#`.
+String decodeHtmlCharacters(String input) =>
+ input.replaceAllMapped(htmlCharactersPattern, decodeHtmlCharacterFromMatch);
+
+/// Decodes HTML entity and numeric character references from the given [match].
+String decodeHtmlCharacterFromMatch(Match match) {
+ final text = match.match;
+ final entity = match[1];
+ final decimalNumber = match[2];
+ final hexadecimalNumber = match[3];
+
+ // Entity references, see
+ // https://spec.commonmark.org/0.30/#entity-references.
+ if (entity != null) {
+ return htmlEntitiesMap[text] ?? text;
+ }
+
+ // Decimal numeric character references, see
+ // https://spec.commonmark.org/0.30/#decimal-numeric-character-references.
+ else if (decimalNumber != null) {
+ final decimalValue = int.parse(decimalNumber);
+ int hexValue;
+ if (decimalValue < 1114112 && decimalValue > 1) {
+ hexValue = int.parse(decimalValue.toRadixString(16), radix: 16);
+ } else {
+ hexValue = 0xFFFd;
+ }
+
+ return String.fromCharCode(hexValue);
+ }
+
+ // Hexadecimal numeric character references, see
+ // https://spec.commonmark.org/0.30/#hexadecimal-numeric-character-references.
+ else if (hexadecimalNumber != null) {
+ var hexValue = int.parse(hexadecimalNumber, radix: 16);
+ if (hexValue > 0x10ffff || hexValue == 0) {
+ hexValue = 0xFFFd;
+ }
+ return String.fromCharCode(hexValue);
+ }
+
+ return text;
+}
+
+extension MatchExtensions on Match {
+ /// Returns the whole match String
+ String get match => this[0]!;
+}
+
+/// Escapes the ASCII punctuation characters after backslash(`\`).
+String escapePunctuation(String input) {
+ final buffer = StringBuffer();
+
+ for (var i = 0; i < input.length; i++) {
+ if (input.codeUnitAt(i) == $backslash) {
+ final next = i + 1 < input.length ? input[i + 1] : null;
+ if (next != null && asciiPunctuationCharacters.contains(next)) {
+ i++;
+ }
+ }
+ buffer.write(input[i]);
+ }
+
+ return buffer.toString();
+}
+
+extension StringExtensions on String {
+ /// Calculates the length of indentation a `String` has.
+ ///
+ // The behavior of tabs: https://spec.commonmark.org/0.30/#tabs
+ int indentation() {
+ var length = 0;
+ for (final char in codeUnits) {
+ if (char != $space && char != $tab) {
+ break;
+ }
+ length += char == $tab ? 4 - (length % 4) : 1;
+ }
+ return length;
+ }
+
+ /// Removes up to [length] characters of leading whitespace.
+ // The way of handling tabs: https://spec.commonmark.org/0.30/#tabs
+ DedentedText dedent([int length = 4]) {
+ final whitespaceMatch = RegExp('^[ \t]{0,$length}').firstMatch(this);
+ const tabSize = 4;
+
+ int? tabRemaining;
+ var start = 0;
+ final whitespaces = whitespaceMatch?[0];
+ if (whitespaces != null) {
+ var indentLength = 0;
+ for (; start < whitespaces.length; start++) {
+ final isTab = whitespaces[start] == '\t';
+ if (isTab) {
+ indentLength += tabSize;
+ tabRemaining = 4;
+ } else {
+ indentLength += 1;
+ }
+ if (indentLength >= length) {
+ if (tabRemaining != null) {
+ tabRemaining = indentLength - length;
+ }
+ if (indentLength == length || isTab) {
+ start += 1;
+ }
+ break;
+ }
+ if (tabRemaining != null) {
+ tabRemaining = 0;
+ }
+ }
+ }
+ return DedentedText(substring(start), tabRemaining);
+ }
+
+ /// Adds [width] of spaces to the beginning of this string.
+ String prependSpace(int width) => '${" " * width}$this';
+
+ /// Whether this string contains only whitespaces.
+ bool get isBlank => trim().isEmpty;
+
+ /// Converts this string to a list of [Line].
+ List<Line> toLines() => LineSplitter.split(this).map(Line.new).toList();
+
+ /// Returns the last character.
+ String last([int n = 1]) => substring(length - n);
+}
+
+/// A class that describes a dedented text.
+class DedentedText {
+ /// The dedented text.
+ final String text;
+
+ /// How many spaces of a tab that remains after part of it has been consumed.
+ ///
+ /// `null` means we did not read a `tab`.
+ final int? tabRemaining;
+
+ DedentedText(this.text, this.tabRemaining);
+}
diff --git a/pkgs/markdown/lib/src/version.dart b/pkgs/markdown/lib/src/version.dart
new file mode 100644
index 0000000..1e5327e
--- /dev/null
+++ b/pkgs/markdown/lib/src/version.dart
@@ -0,0 +1,2 @@
+// Generated code. Do not modify.
+const packageVersion = '7.3.0';
diff --git a/pkgs/markdown/pubspec.yaml b/pkgs/markdown/pubspec.yaml
new file mode 100644
index 0000000..fadd44f
--- /dev/null
+++ b/pkgs/markdown/pubspec.yaml
@@ -0,0 +1,34 @@
+name: markdown
+version: 7.3.0
+description: >-
+ A portable Markdown library written in Dart that can parse Markdown into HTML.
+repository: https://github.com/dart-lang/tools/tree/main/pkgs/markdown
+
+topics:
+ - markdown
+
+executables:
+ markdown:
+
+environment:
+ sdk: ^3.2.0
+
+dependencies:
+ args: ^2.0.0
+ meta: ^1.3.0
+
+dev_dependencies:
+ build_runner: ^2.0.5
+ build_version: ^2.0.3
+ build_web_compilers: ^4.0.0
+ collection: ^1.15.0
+ dart_flutter_team_lints: ^3.0.0
+ html: ^0.15.0
+ http: ^1.0.0
+ io: ^1.0.0
+ path: ^1.8.0
+ pool: ^1.5.1
+ tar: ^1.0.3
+ test: ^1.16.0
+ web: '>=0.4.2 <2.0.0'
+ yaml: ^3.0.0
diff --git a/pkgs/markdown/test/blns.dart b/pkgs/markdown/test/blns.dart
new file mode 100644
index 0000000..4f06115
--- /dev/null
+++ b/pkgs/markdown/test/blns.dart
@@ -0,0 +1,526 @@
+// GENERATED FILE. DO NOT EDIT.
+//
+// This file was generated from big-list-of-naughty-strings's JSON file:
+// https://github.com/minimaxir/big-list-of-naughty-strings/raw/master/blns.json
+// at 2023-08-26 16:34:37.127975 by the script, tool/update_blns.dart.
+
+// ignore_for_file: text_direction_code_point_in_literal, use_raw_strings
+// ignore_for_file: lines_longer_than_80_chars
+
+const blns = <String>[
+ '',
+ 'undefined',
+ 'undef',
+ 'null',
+ 'NULL',
+ '(null)',
+ 'nil',
+ 'NIL',
+ 'true',
+ 'false',
+ 'True',
+ 'False',
+ 'TRUE',
+ 'FALSE',
+ 'None',
+ 'hasOwnProperty',
+ 'then',
+ '\\',
+ '\\\\',
+ '0',
+ '1',
+ '1.00',
+ '\$1.00',
+ '1/2',
+ '1E2',
+ '1E02',
+ '1E+02',
+ '-1',
+ '-1.00',
+ '-\$1.00',
+ '-1/2',
+ '-1E2',
+ '-1E02',
+ '-1E+02',
+ '1/0',
+ '0/0',
+ '-2147483648/-1',
+ '-9223372036854775808/-1',
+ '-0',
+ '-0.0',
+ '+0',
+ '+0.0',
+ '0.00',
+ '0..0',
+ '.',
+ '0.0.0',
+ '0,00',
+ '0,,0',
+ ',',
+ '0,0,0',
+ '0.0/0',
+ '1.0/0.0',
+ '0.0/0.0',
+ '1,0/0,0',
+ '0,0/0,0',
+ '--1',
+ '-',
+ '-.',
+ '-,',
+ '999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999',
+ 'NaN',
+ 'Infinity',
+ '-Infinity',
+ 'INF',
+ '1#INF',
+ '-1#IND',
+ '1#QNAN',
+ '1#SNAN',
+ '1#IND',
+ '0x0',
+ '0xffffffff',
+ '0xffffffffffffffff',
+ '0xabad1dea',
+ '123456789012345678901234567890123456789',
+ '1,000.00',
+ '1 000.00',
+ '1\'000.00',
+ '1,000,000.00',
+ '1 000 000.00',
+ '1\'000\'000.00',
+ '1.000,00',
+ '1 000,00',
+ '1\'000,00',
+ '1.000.000,00',
+ '1 000 000,00',
+ '1\'000\'000,00',
+ '01000',
+ '08',
+ '09',
+ '2.2250738585072011e-308',
+ ',./;\'[]\\-=',
+ '<>?:"{}|_+',
+ '!@#\$%^&*()`~',
+ '',
+ '',
+ '
',
+ '',
+ '',
+ '',
+ 'Ω≈ç√∫˜µ≤≥÷',
+ 'åß∂ƒ©˙∆˚¬…æ',
+ 'œ∑´®†¥¨ˆøπ“‘',
+ '¡™£¢∞§¶•ªº–≠',
+ '¸˛Ç◊ı˜Â¯˘¿',
+ 'ÅÍÎÏ˝ÓÔÒÚÆ☃',
+ 'Œ„´‰ˇÁ¨ˆØ∏”’',
+ '`⁄€‹›fifl‡°·‚—±',
+ '⅛⅜⅝⅞',
+ 'ЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя',
+ '٠١٢٣٤٥٦٧٨٩',
+ '⁰⁴⁵',
+ '₀₁₂',
+ '⁰⁴⁵₀₁₂',
+ 'ด้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็ ด้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็ ด้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็',
+ '\'',
+ '"',
+ '\'\'',
+ '""',
+ '\'"\'',
+ '"\'\'\'\'"\'"',
+ '"\'"\'"\'\'\'\'"',
+ '<foo val=“bar” />',
+ '<foo val=“bar” />',
+ '<foo val=”bar“ />',
+ '<foo val=`bar\' />',
+ '田中さんにあげて下さい',
+ 'パーティーへ行かないか',
+ '和製漢語',
+ '部落格',
+ '사회과학원 어학연구소',
+ '찦차를 타고 온 펲시맨과 쑛다리 똠방각하',
+ '社會科學院語學研究所',
+ '울란바토르',
+ '𠜎𠜱𠝹𠱓𠱸𠲖𠳏',
+ '𐐜 𐐔𐐇𐐝𐐀𐐡𐐇𐐓 𐐙𐐊𐐡𐐝𐐓/𐐝𐐇𐐗𐐊𐐤𐐔 𐐒𐐋𐐗 𐐒𐐌 𐐜 𐐡𐐀𐐖𐐇𐐤𐐓𐐝 𐐱𐑂 𐑄 𐐔𐐇𐐝𐐀𐐡𐐇𐐓 𐐏𐐆𐐅𐐤𐐆𐐚𐐊𐐡𐐝𐐆𐐓𐐆',
+ '表ポあA鷗ŒéB逍Üߪąñ丂㐀𠀀',
+ 'Ⱥ',
+ 'Ⱦ',
+ 'ヽ༼ຈل͜ຈ༽ノ ヽ༼ຈل͜ຈ༽ノ',
+ '(。◕ ∀ ◕。)',
+ '`ィ(´∀`∩',
+ '__ロ(,_,*)',
+ '・( ̄∀ ̄)・:*:',
+ '゚・✿ヾ╲(。◕‿◕。)╱✿・゚',
+ ',。・:*:・゜’( ☻ ω ☻ )。・:*:・゜’',
+ '(╯°□°)╯︵ ┻━┻)',
+ '(ノಥ益ಥ)ノ ┻━┻',
+ '┬─┬ノ( º _ ºノ)',
+ '( ͡° ͜ʖ ͡°)',
+ '¯\\_(ツ)_/¯',
+ '😍',
+ '👩🏽',
+ '👨🦰 👨🏿🦰 👨🦱 👨🏿🦱 🦹🏿♂️',
+ '👾 🙇 💁 🙅 🙆 🙋 🙎 🙍',
+ '🐵 🙈 🙉 🙊',
+ '❤️ 💔 💌 💕 💞 💓 💗 💖 💘 💝 💟 💜 💛 💚 💙',
+ '✋🏿 💪🏿 👐🏿 🙌🏿 👏🏿 🙏🏿',
+ '👨👩👦 👨👩👧👦 👨👨👦 👩👩👧 👨👦 👨👧👦 👩👦 👩👧👦',
+ '🚾 🆒 🆓 🆕 🆖 🆗 🆙 🏧',
+ '0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟',
+ '🇺🇸🇷🇺🇸 🇦🇫🇦🇲🇸',
+ '🇺🇸🇷🇺🇸🇦🇫🇦🇲',
+ '🇺🇸🇷🇺🇸🇦',
+ '123',
+ '١٢٣',
+ 'ثم نفس سقطت وبالتحديد،, جزيرتي باستخدام أن دنو. إذ هنا؟ الستار وتنصيب كان. أهّل ايطاليا، بريطانيا-فرنسا قد أخذ. سليمان، إتفاقية بين ما, يذكر الحدود أي بعد, معاملة بولندا، الإطلاق عل إيو.',
+ 'בְּרֵאשִׁית, בָּרָא אֱלֹהִים, אֵת הַשָּׁמַיִם, וְאֵת הָאָרֶץ',
+ 'הָיְתָהtestالصفحات التّحول',
+ '﷽',
+ 'ﷺ',
+ 'مُنَاقَشَةُ سُبُلِ اِسْتِخْدَامِ اللُّغَةِ فِي النُّظُمِ الْقَائِمَةِ وَفِيم يَخُصَّ التَّطْبِيقَاتُ الْحاسُوبِيَّةُ، ',
+ '᚛ᚄᚓᚐᚋᚒᚄ ᚑᚄᚂᚑᚏᚅ᚜',
+ '᚛ ᚜',
+ 'test',
+ 'test',
+ '
test
',
+ 'testtest',
+ 'test',
+ 'Ṱ̺̺̕o͞ ̷i̲̬͇̪͙n̝̗͕v̟̜̘̦͟o̶̙̰̠kè͚̮̺̪̹̱̤ ̖t̝͕̳̣̻̪͞h̼͓̲̦̳̘̲e͇̣̰̦̬͎ ̢̼̻̱̘h͚͎͙̜̣̲ͅi̦̲̣̰̤v̻͍e̺̭̳̪̰-m̢iͅn̖̺̞̲̯̰d̵̼̟͙̩̼̘̳ ̞̥̱̳̭r̛̗̘e͙p͠r̼̞̻̭̗e̺̠̣͟s̘͇̳͍̝͉e͉̥̯̞̲͚̬͜ǹ̬͎͎̟̖͇̤t͍̬̤͓̼̭͘ͅi̪̱n͠g̴͉ ͏͉ͅc̬̟h͡a̫̻̯͘o̫̟̖͍̙̝͉s̗̦̲.̨̹͈̣',
+ '̡͓̞ͅI̗̘̦͝n͇͇͙v̮̫ok̲̫̙͈i̖͙̭̹̠̞n̡̻̮̣̺g̲͈͙̭͙̬͎ ̰t͔̦h̞̲e̢̤ ͍̬̲͖f̴̘͕̣è͖ẹ̥̩l͖͔͚i͓͚̦͠n͖͍̗͓̳̮g͍ ̨o͚̪͡f̘̣̬ ̖̘͖̟͙̮c҉͔̫͖͓͇͖ͅh̵̤̣͚͔á̗̼͕ͅo̼̣̥s̱͈̺̖̦̻͢.̛̖̞̠̫̰',
+ '̗̺͖̹̯͓Ṯ̤͍̥͇͈h̲́e͏͓̼̗̙̼̣͔ ͇̜̱̠͓͍ͅN͕͠e̗̱z̘̝̜̺͙p̤̺̹͍̯͚e̠̻̠͜r̨̤͍̺̖͔̖̖d̠̟̭̬̝͟i̦͖̩͓͔̤a̠̗̬͉̙n͚͜ ̻̞̰͚ͅh̵͉i̳̞v̢͇ḙ͎͟-҉̭̩̼͔m̤̭̫i͕͇̝̦n̗͙ḍ̟ ̯̲͕͞ǫ̟̯̰̲͙̻̝f ̪̰̰̗̖̭̘͘c̦͍̲̞͍̩̙ḥ͚a̮͎̟̙͜ơ̩̹͎s̤.̝̝ ҉Z̡̖̜͖̰̣͉̜a͖̰͙̬͡l̲̫̳͍̩g̡̟̼̱͚̞̬ͅo̗͜.̟',
+ '̦H̬̤̗̤͝e͜ ̜̥̝̻͍̟́w̕h̖̯͓o̝͙̖͎̱̮ ҉̺̙̞̟͈W̷̼̭a̺̪͍į͈͕̭͙̯̜t̶̼̮s̘͙͖̕ ̠̫̠B̻͍͙͉̳ͅe̵h̵̬͇̫͙i̹͓̳̳̮͎̫̕n͟d̴̪̜̖ ̰͉̩͇͙̲͞ͅT͖̼͓̪͢h͏͓̮̻e̬̝̟ͅ ̤̹̝W͙̞̝͔͇͝ͅa͏͓͔̹̼̣l̴͔̰̤̟͔ḽ̫.͕',
+ 'Z̮̞̠͙͔ͅḀ̗̞͈̻̗Ḷ͙͎̯̹̞͓G̻O̭̗̮',
+ '˙ɐnbᴉlɐ ɐuƃɐɯ ǝɹolop ʇǝ ǝɹoqɐl ʇn ʇunpᴉpᴉɔuᴉ ɹodɯǝʇ poɯsnᴉǝ op pǝs \'ʇᴉlǝ ƃuᴉɔsᴉdᴉpɐ ɹnʇǝʇɔǝsuoɔ \'ʇǝɯɐ ʇᴉs ɹolop ɯnsdᴉ ɯǝɹo˥',
+ '00˙Ɩ\$-',
+ 'The quick brown fox jumps over the lazy dog',
+ '𝐓𝐡𝐞 𝐪𝐮𝐢𝐜𝐤 𝐛𝐫𝐨𝐰𝐧 𝐟𝐨𝐱 𝐣𝐮𝐦𝐩𝐬 𝐨𝐯𝐞𝐫 𝐭𝐡𝐞 𝐥𝐚𝐳𝐲 𝐝𝐨𝐠',
+ '𝕿𝖍𝖊 𝖖𝖚𝖎𝖈𝖐 𝖇𝖗𝖔𝖜𝖓 𝖋𝖔𝖝 𝖏𝖚𝖒𝖕𝖘 𝖔𝖛𝖊𝖗 𝖙𝖍𝖊 𝖑𝖆𝖟𝖞 𝖉𝖔𝖌',
+ '𝑻𝒉𝒆 𝒒𝒖𝒊𝒄𝒌 𝒃𝒓𝒐𝒘𝒏 𝒇𝒐𝒙 𝒋𝒖𝒎𝒑𝒔 𝒐𝒗𝒆𝒓 𝒕𝒉𝒆 𝒍𝒂𝒛𝒚 𝒅𝒐𝒈',
+ '𝓣𝓱𝓮 𝓺𝓾𝓲𝓬𝓴 𝓫𝓻𝓸𝔀𝓷 𝓯𝓸𝔁 𝓳𝓾𝓶𝓹𝓼 𝓸𝓿𝓮𝓻 𝓽𝓱𝓮 𝓵𝓪𝔃𝔂 𝓭𝓸𝓰',
+ '𝕋𝕙𝕖 𝕢𝕦𝕚𝕔𝕜 𝕓𝕣𝕠𝕨𝕟 𝕗𝕠𝕩 𝕛𝕦𝕞𝕡𝕤 𝕠𝕧𝕖𝕣 𝕥𝕙𝕖 𝕝𝕒𝕫𝕪 𝕕𝕠𝕘',
+ '𝚃𝚑𝚎 𝚚𝚞𝚒𝚌𝚔 𝚋𝚛𝚘𝚠𝚗 𝚏𝚘𝚡 𝚓𝚞𝚖𝚙𝚜 𝚘𝚟𝚎𝚛 𝚝𝚑𝚎 𝚕𝚊𝚣𝚢 𝚍𝚘𝚐',
+ '⒯⒣⒠ ⒬⒰⒤⒞⒦ ⒝⒭⒪⒲⒩ ⒡⒪⒳ ⒥⒰⒨⒫⒮ ⒪⒱⒠⒭ ⒯⒣⒠ ⒧⒜⒵⒴ ⒟⒪⒢',
+ '<script>alert(123)</script>',
+ '<script>alert('123');</script>',
+ '<img src=x onerror=alert(123) />',
+ '<svg><script>123<1>alert(123)</script>',
+ '"><script>alert(123)</script>',
+ '\'><script>alert(123)</script>',
+ '><script>alert(123)</script>',
+ '</script><script>alert(123)</script>',
+ '< / script >< script >alert(123)< / script >',
+ ' onfocus=JaVaSCript:alert(123) autofocus',
+ '" onfocus=JaVaSCript:alert(123) autofocus',
+ '\' onfocus=JaVaSCript:alert(123) autofocus',
+ '<script>alert(123)</script>',
+ '<sc<script>ript>alert(123)</sc</script>ript>',
+ '--><script>alert(123)</script>',
+ '";alert(123);t="',
+ '\';alert(123);t=\'',
+ 'JavaSCript:alert(123)',
+ ';alert(123);',
+ 'src=JaVaSCript:prompt(132)',
+ '"><script>alert(123);</script x="',
+ '\'><script>alert(123);</script x=\'',
+ '><script>alert(123);</script x=',
+ '" autofocus onkeyup="javascript:alert(123)',
+ '\' autofocus onkeyup=\'javascript:alert(123)',
+ '<script\\x20type="text/javascript">javascript:alert(1);</script>',
+ '<script\\x3Etype="text/javascript">javascript:alert(1);</script>',
+ '<script\\x0Dtype="text/javascript">javascript:alert(1);</script>',
+ '<script\\x09type="text/javascript">javascript:alert(1);</script>',
+ '<script\\x0Ctype="text/javascript">javascript:alert(1);</script>',
+ '<script\\x2Ftype="text/javascript">javascript:alert(1);</script>',
+ '<script\\x0Atype="text/javascript">javascript:alert(1);</script>',
+ '\'`"><\\x3Cscript>javascript:alert(1)</script>',
+ '\'`"><\\x00script>javascript:alert(1)</script>',
+ 'ABC<div style="x\\x3Aexpression(javascript:alert(1)">DEF',
+ 'ABC<div style="x:expression\\x5C(javascript:alert(1)">DEF',
+ 'ABC<div style="x:expression\\x00(javascript:alert(1)">DEF',
+ 'ABC<div style="x:exp\\x00ression(javascript:alert(1)">DEF',
+ 'ABC<div style="x:exp\\x5Cression(javascript:alert(1)">DEF',
+ 'ABC<div style="x:\\x0Aexpression(javascript:alert(1)">DEF',
+ 'ABC<div style="x:\\x09expression(javascript:alert(1)">DEF',
+ 'ABC<div style="x:\\xE3\\x80\\x80expression(javascript:alert(1)">DEF',
+ 'ABC<div style="x:\\xE2\\x80\\x84expression(javascript:alert(1)">DEF',
+ 'ABC<div style="x:\\xC2\\xA0expression(javascript:alert(1)">DEF',
+ 'ABC<div style="x:\\xE2\\x80\\x80expression(javascript:alert(1)">DEF',
+ 'ABC<div style="x:\\xE2\\x80\\x8Aexpression(javascript:alert(1)">DEF',
+ 'ABC<div style="x:\\x0Dexpression(javascript:alert(1)">DEF',
+ 'ABC<div style="x:\\x0Cexpression(javascript:alert(1)">DEF',
+ 'ABC<div style="x:\\xE2\\x80\\x87expression(javascript:alert(1)">DEF',
+ 'ABC<div style="x:\\xEF\\xBB\\xBFexpression(javascript:alert(1)">DEF',
+ 'ABC<div style="x:\\x20expression(javascript:alert(1)">DEF',
+ 'ABC<div style="x:\\xE2\\x80\\x88expression(javascript:alert(1)">DEF',
+ 'ABC<div style="x:\\x00expression(javascript:alert(1)">DEF',
+ 'ABC<div style="x:\\xE2\\x80\\x8Bexpression(javascript:alert(1)">DEF',
+ 'ABC<div style="x:\\xE2\\x80\\x86expression(javascript:alert(1)">DEF',
+ 'ABC<div style="x:\\xE2\\x80\\x85expression(javascript:alert(1)">DEF',
+ 'ABC<div style="x:\\xE2\\x80\\x82expression(javascript:alert(1)">DEF',
+ 'ABC<div style="x:\\x0Bexpression(javascript:alert(1)">DEF',
+ 'ABC<div style="x:\\xE2\\x80\\x81expression(javascript:alert(1)">DEF',
+ 'ABC<div style="x:\\xE2\\x80\\x83expression(javascript:alert(1)">DEF',
+ 'ABC<div style="x:\\xE2\\x80\\x89expression(javascript:alert(1)">DEF',
+ '<a href="\\x0Bjavascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\x0Fjavascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\xC2\\xA0javascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\x05javascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\xE1\\xA0\\x8Ejavascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\x18javascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\x11javascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\xE2\\x80\\x88javascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\xE2\\x80\\x89javascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\xE2\\x80\\x80javascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\x17javascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\x03javascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\x0Ejavascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\x1Ajavascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\x00javascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\x10javascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\xE2\\x80\\x82javascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\x20javascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\x13javascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\x09javascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\xE2\\x80\\x8Ajavascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\x14javascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\x19javascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\xE2\\x80\\xAFjavascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\x1Fjavascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\xE2\\x80\\x81javascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\x1Djavascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\xE2\\x80\\x87javascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\x07javascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\xE1\\x9A\\x80javascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\xE2\\x80\\x83javascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\x04javascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\x01javascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\x08javascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\xE2\\x80\\x84javascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\xE2\\x80\\x86javascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\xE3\\x80\\x80javascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\x12javascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\x0Djavascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\x0Ajavascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\x0Cjavascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\x15javascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\xE2\\x80\\xA8javascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\x16javascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\x02javascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\x1Bjavascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\x06javascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\xE2\\x80\\xA9javascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\xE2\\x80\\x85javascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\x1Ejavascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\xE2\\x81\\x9Fjavascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="\\x1Cjavascript:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="javascript\\x00:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="javascript\\x3A:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="javascript\\x09:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="javascript\\x0D:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '<a href="javascript\\x0A:javascript:alert(1)" id="fuzzelement1">test</a>',
+ '`"\'><img src=xxx:x \\x0Aonerror=javascript:alert(1)>',
+ '`"\'><img src=xxx:x \\x22onerror=javascript:alert(1)>',
+ '`"\'><img src=xxx:x \\x0Bonerror=javascript:alert(1)>',
+ '`"\'><img src=xxx:x \\x0Donerror=javascript:alert(1)>',
+ '`"\'><img src=xxx:x \\x2Fonerror=javascript:alert(1)>',
+ '`"\'><img src=xxx:x \\x09onerror=javascript:alert(1)>',
+ '`"\'><img src=xxx:x \\x0Conerror=javascript:alert(1)>',
+ '`"\'><img src=xxx:x \\x00onerror=javascript:alert(1)>',
+ '`"\'><img src=xxx:x \\x27onerror=javascript:alert(1)>',
+ '`"\'><img src=xxx:x \\x20onerror=javascript:alert(1)>',
+ '"`\'><script>\\x3Bjavascript:alert(1)</script>',
+ '"`\'><script>\\x0Djavascript:alert(1)</script>',
+ '"`\'><script>\\xEF\\xBB\\xBFjavascript:alert(1)</script>',
+ '"`\'><script>\\xE2\\x80\\x81javascript:alert(1)</script>',
+ '"`\'><script>\\xE2\\x80\\x84javascript:alert(1)</script>',
+ '"`\'><script>\\xE3\\x80\\x80javascript:alert(1)</script>',
+ '"`\'><script>\\x09javascript:alert(1)</script>',
+ '"`\'><script>\\xE2\\x80\\x89javascript:alert(1)</script>',
+ '"`\'><script>\\xE2\\x80\\x85javascript:alert(1)</script>',
+ '"`\'><script>\\xE2\\x80\\x88javascript:alert(1)</script>',
+ '"`\'><script>\\x00javascript:alert(1)</script>',
+ '"`\'><script>\\xE2\\x80\\xA8javascript:alert(1)</script>',
+ '"`\'><script>\\xE2\\x80\\x8Ajavascript:alert(1)</script>',
+ '"`\'><script>\\xE1\\x9A\\x80javascript:alert(1)</script>',
+ '"`\'><script>\\x0Cjavascript:alert(1)</script>',
+ '"`\'><script>\\x2Bjavascript:alert(1)</script>',
+ '"`\'><script>\\xF0\\x90\\x96\\x9Ajavascript:alert(1)</script>',
+ '"`\'><script>-javascript:alert(1)</script>',
+ '"`\'><script>\\x0Ajavascript:alert(1)</script>',
+ '"`\'><script>\\xE2\\x80\\xAFjavascript:alert(1)</script>',
+ '"`\'><script>\\x7Ejavascript:alert(1)</script>',
+ '"`\'><script>\\xE2\\x80\\x87javascript:alert(1)</script>',
+ '"`\'><script>\\xE2\\x81\\x9Fjavascript:alert(1)</script>',
+ '"`\'><script>\\xE2\\x80\\xA9javascript:alert(1)</script>',
+ '"`\'><script>\\xC2\\x85javascript:alert(1)</script>',
+ '"`\'><script>\\xEF\\xBF\\xAEjavascript:alert(1)</script>',
+ '"`\'><script>\\xE2\\x80\\x83javascript:alert(1)</script>',
+ '"`\'><script>\\xE2\\x80\\x8Bjavascript:alert(1)</script>',
+ '"`\'><script>\\xEF\\xBF\\xBEjavascript:alert(1)</script>',
+ '"`\'><script>\\xE2\\x80\\x80javascript:alert(1)</script>',
+ '"`\'><script>\\x21javascript:alert(1)</script>',
+ '"`\'><script>\\xE2\\x80\\x82javascript:alert(1)</script>',
+ '"`\'><script>\\xE2\\x80\\x86javascript:alert(1)</script>',
+ '"`\'><script>\\xE1\\xA0\\x8Ejavascript:alert(1)</script>',
+ '"`\'><script>\\x0Bjavascript:alert(1)</script>',
+ '"`\'><script>\\x20javascript:alert(1)</script>',
+ '"`\'><script>\\xC2\\xA0javascript:alert(1)</script>',
+ '<img \\x00src=x onerror="alert(1)">',
+ '<img \\x47src=x onerror="javascript:alert(1)">',
+ '<img \\x11src=x onerror="javascript:alert(1)">',
+ '<img \\x12src=x onerror="javascript:alert(1)">',
+ '<img\\x47src=x onerror="javascript:alert(1)">',
+ '<img\\x10src=x onerror="javascript:alert(1)">',
+ '<img\\x13src=x onerror="javascript:alert(1)">',
+ '<img\\x32src=x onerror="javascript:alert(1)">',
+ '<img\\x47src=x onerror="javascript:alert(1)">',
+ '<img\\x11src=x onerror="javascript:alert(1)">',
+ '<img \\x47src=x onerror="javascript:alert(1)">',
+ '<img \\x34src=x onerror="javascript:alert(1)">',
+ '<img \\x39src=x onerror="javascript:alert(1)">',
+ '<img \\x00src=x onerror="javascript:alert(1)">',
+ '<img src\\x09=x onerror="javascript:alert(1)">',
+ '<img src\\x10=x onerror="javascript:alert(1)">',
+ '<img src\\x13=x onerror="javascript:alert(1)">',
+ '<img src\\x32=x onerror="javascript:alert(1)">',
+ '<img src\\x12=x onerror="javascript:alert(1)">',
+ '<img src\\x11=x onerror="javascript:alert(1)">',
+ '<img src\\x00=x onerror="javascript:alert(1)">',
+ '<img src\\x47=x onerror="javascript:alert(1)">',
+ '<img src=x\\x09onerror="javascript:alert(1)">',
+ '<img src=x\\x10onerror="javascript:alert(1)">',
+ '<img src=x\\x11onerror="javascript:alert(1)">',
+ '<img src=x\\x12onerror="javascript:alert(1)">',
+ '<img src=x\\x13onerror="javascript:alert(1)">',
+ '<img[a][b][c]src[d]=x[e]onerror=[f]"alert(1)">',
+ '<img src=x onerror=\\x09"javascript:alert(1)">',
+ '<img src=x onerror=\\x10"javascript:alert(1)">',
+ '<img src=x onerror=\\x11"javascript:alert(1)">',
+ '<img src=x onerror=\\x12"javascript:alert(1)">',
+ '<img src=x onerror=\\x32"javascript:alert(1)">',
+ '<img src=x onerror=\\x00"javascript:alert(1)">',
+ '<a href=javascript:javascript:alert(1)>XXX</a>',
+ '<img src="x` `<script>javascript:alert(1)</script>"` `>',
+ '<img src onerror /" \'"= alt=javascript:alert(1)//">',
+ '<title onpropertychange=javascript:alert(1)></title><title title=>',
+ '<a href=http://foo.bar/#x=`y></a><img alt="`><img src=x:x onerror=javascript:alert(1)></a>">',
+ '<!--[if]><script>javascript:alert(1)</script -->',
+ '<!--[if<img src=x onerror=javascript:alert(1)//]> -->',
+ '<script src="/\\%(jscript)s"></script>',
+ '<script src="\\\\%(jscript)s"></script>',
+ '<IMG """><SCRIPT>alert("XSS")</SCRIPT>">',
+ '<IMG SRC=javascript:alert(String.fromCharCode(88,83,83))>',
+ '<IMG SRC=# onmouseover="alert(\'xxs\')">',
+ '<IMG SRC= onmouseover="alert(\'xxs\')">',
+ '<IMG onmouseover="alert(\'xxs\')">',
+ '<IMG SRC=javascript:alert('XSS')>',
+ '<IMG SRC=javascript:alert('XSS')>',
+ '<IMG SRC=javascript:alert('XSS')>',
+ '<IMG SRC="jav ascript:alert(\'XSS\');">',
+ '<IMG SRC="jav	ascript:alert(\'XSS\');">',
+ '<IMG SRC="jav
ascript:alert(\'XSS\');">',
+ '<IMG SRC="jav
ascript:alert(\'XSS\');">',
+ 'perl -e \'print "<IMG SRC=java\\0script:alert(\\"XSS\\")>";\' > out',
+ '<IMG SRC="  javascript:alert(\'XSS\');">',
+ '<SCRIPT/XSS SRC="http://ha.ckers.org/xss.js"></SCRIPT>',
+ '<BODY onload!#\$%&()*~+-_.,:;?@[/|\\]^`=alert("XSS")>',
+ '<SCRIPT/SRC="http://ha.ckers.org/xss.js"></SCRIPT>',
+ '<<SCRIPT>alert("XSS");//<</SCRIPT>',
+ '<SCRIPT SRC=http://ha.ckers.org/xss.js?< B >',
+ '<SCRIPT SRC=//ha.ckers.org/.j>',
+ '<IMG SRC="javascript:alert(\'XSS\')"',
+ '<iframe src=http://ha.ckers.org/scriptlet.html <',
+ '\\";alert(\'XSS\');//',
+ '<u oncopy=alert()> Copy me</u>',
+ '<i onwheel=alert(1)> Scroll over me </i>',
+ '<plaintext>',
+ 'http://a/%%30%30',
+ '</textarea><script>alert(123)</script>',
+ '1;DROP TABLE users',
+ '1\'; DROP TABLE users-- 1',
+ '\' OR 1=1 -- 1',
+ '\' OR \'1\'=\'1',
+ '\'; EXEC sp_MSForEachTable \'DROP TABLE ?\'; --',
+ ' ',
+ '%',
+ '_',
+ '-',
+ '--',
+ '--version',
+ '--help',
+ '\$USER',
+ '/dev/null; touch /tmp/blns.fail ; echo',
+ '`touch /tmp/blns.fail`',
+ '\$(touch /tmp/blns.fail)',
+ '@{[system "touch /tmp/blns.fail"]}',
+ 'eval("puts \'hello world\'")',
+ 'System("ls -al /")',
+ '`ls -al /`',
+ 'Kernel.exec("ls -al /")',
+ 'Kernel.exit(1)',
+ '%x(\'ls -al /\')',
+ '<?xml version="1.0" encoding="ISO-8859-1"?><!DOCTYPE foo [ <!ELEMENT foo ANY ><!ENTITY xxe SYSTEM "file:///etc/passwd" >]><foo>&xxe;</foo>',
+ '\$HOME',
+ '\$ENV{\'HOME\'}',
+ '%d',
+ '%s%s%s%s%s',
+ '{0}',
+ '%*.*s',
+ '%@',
+ '%n',
+ 'File:///',
+ '../../../../../../../../../../../etc/passwd%00',
+ '../../../../../../../../../../../etc/hosts',
+ '() { 0; }; touch /tmp/blns.shellshock1.fail;',
+ '() { _; } >_[\$(\$())] { touch /tmp/blns.shellshock2.fail; }',
+ '<<< %s(un=\'%s\') = %u',
+ '+++ATH0',
+ 'CON',
+ 'PRN',
+ 'AUX',
+ 'CLOCK\$',
+ 'NUL',
+ 'A:',
+ 'ZZ:',
+ 'COM1',
+ 'LPT1',
+ 'LPT2',
+ 'LPT3',
+ 'COM2',
+ 'COM3',
+ 'COM4',
+ 'DCC SEND STARTKEYLOGGER 0 0 0',
+ 'Scunthorpe General Hospital',
+ 'Penistone Community Church',
+ 'Lightwater Country Park',
+ 'Jimmy Clitheroe',
+ 'Horniman Museum',
+ 'shitake mushrooms',
+ 'RomansInSussex.co.uk',
+ 'http://www.cum.qc.ca/',
+ 'Craig Cockburn, Software Specialist',
+ 'Linda Callahan',
+ 'Dr. Herman I. Libshitz',
+ 'magna cum laude',
+ 'Super Bowl XXX',
+ 'medieval erection of parapets',
+ 'evaluate',
+ 'mocha',
+ 'expression',
+ 'Arsenal canal',
+ 'classic',
+ 'Tyson Gay',
+ 'Dick Van Dyke',
+ 'basement',
+ 'If you\'re reading this, you\'ve been in a coma for almost 20 years now. We\'re trying a new technique. We don\'t know where this message will end up in your dream, but we hope it works. Please wake up, we miss you.',
+ 'Roses are [0;31mred[0m, violets are [0;34mblue. Hope you enjoy terminal hue',
+ 'But now...[20Cfor my greatest trick...[8m',
+ 'The quick brown fox... [Beeeep]',
+ 'Powerلُلُصّبُلُلصّبُررً ॣ ॣh ॣ ॣ冗',
+ '🏳0🌈️',
+ 'జ్ఞా',
+ 'گچپژ',
+ '{% print \'x\' * 64 * 1024**3 %}',
+ '{{ "".__class__.__mro__[2].__subclasses__()[40]("/etc/passwd").read() }}',
+];
diff --git a/pkgs/markdown/test/blns_test.dart b/pkgs/markdown/test/blns_test.dart
new file mode 100644
index 0000000..69790ef
--- /dev/null
+++ b/pkgs/markdown/test/blns_test.dart
@@ -0,0 +1,39 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:markdown/markdown.dart';
+import 'package:test/test.dart';
+
+import 'blns.dart';
+
+// The BLNS tests merely test that `markdownToHtml` does not throw or hang while
+// processing "naughty string" inputs. While there are examples of multi-byte
+// characters, non-visible characters, etc., these tests should not be _relied
+// upon_ for testing multi-byte character support, etc.
+void main() {
+ test('parsing blns', () {
+ // This is more a test of update_blns.dart: we're testing that the strings
+ // were encoded half-decently, and nothing got globbed up into a big
+ // multiline string.
+ expect(blns, hasLength(515));
+ });
+
+ var index = 0;
+ for (final str in blns) {
+ test('blns string $index', () {
+ final result = markdownToHtml(str);
+ expect(result, const TypeMatcher<String>());
+ });
+ index++;
+ }
+
+ index = 0;
+ for (final str in blns) {
+ test('blns string $index w/ gitHubWeb', () {
+ final result = markdownToHtml(str, extensionSet: ExtensionSet.gitHubWeb);
+ expect(result, const TypeMatcher<String>());
+ });
+ index++;
+ }
+}
diff --git a/pkgs/markdown/test/common_mark/atx_headings.unit b/pkgs/markdown/test/common_mark/atx_headings.unit
new file mode 100644
index 0000000..1cb7e98
--- /dev/null
+++ b/pkgs/markdown/test/common_mark/atx_headings.unit
@@ -0,0 +1,112 @@
+>>> ATX headings - 62
+# foo
+## foo
+### foo
+#### foo
+##### foo
+###### foo
+<<<
+<h1>foo</h1>
+<h2>foo</h2>
+<h3>foo</h3>
+<h4>foo</h4>
+<h5>foo</h5>
+<h6>foo</h6>
+>>> ATX headings - 63
+####### foo
+<<<
+<p>####### foo</p>
+>>> ATX headings - 64
+#5 bolt
+
+#hashtag
+<<<
+<p>#5 bolt</p>
+<p>#hashtag</p>
+>>> ATX headings - 65
+\## foo
+<<<
+<p>## foo</p>
+>>> ATX headings - 66
+# foo *bar* \*baz\*
+<<<
+<h1>foo <em>bar</em> *baz*</h1>
+>>> ATX headings - 67
+# foo
+<<<
+<h1>foo</h1>
+>>> ATX headings - 68
+ ### foo
+ ## foo
+ # foo
+<<<
+<h3>foo</h3>
+<h2>foo</h2>
+<h1>foo</h1>
+>>> ATX headings - 69
+ # foo
+<<<
+<pre><code># foo
+</code></pre>
+>>> ATX headings - 70
+foo
+ # bar
+<<<
+<p>foo
+# bar</p>
+>>> ATX headings - 71
+## foo ##
+ ### bar ###
+<<<
+<h2>foo</h2>
+<h3>bar</h3>
+>>> ATX headings - 72
+# foo ##################################
+##### foo ##
+<<<
+<h1>foo</h1>
+<h5>foo</h5>
+>>> ATX headings - 73
+### foo ###
+<<<
+<h3>foo</h3>
+>>> ATX headings - 74
+### foo ### b
+<<<
+<h3>foo ### b</h3>
+>>> ATX headings - 75
+# foo#
+<<<
+<h1>foo#</h1>
+>>> ATX headings - 76
+### foo \###
+## foo #\##
+# foo \#
+<<<
+<h3>foo ###</h3>
+<h2>foo ###</h2>
+<h1>foo #</h1>
+>>> ATX headings - 77
+****
+## foo
+****
+<<<
+<hr />
+<h2>foo</h2>
+<hr />
+>>> ATX headings - 78
+Foo bar
+# baz
+Bar foo
+<<<
+<p>Foo bar</p>
+<h1>baz</h1>
+<p>Bar foo</p>
+>>> ATX headings - 79
+##
+#
+### ###
+<<<
+<h2></h2>
+<h1></h1>
+<h3></h3>
diff --git a/pkgs/markdown/test/common_mark/autolinks.unit b/pkgs/markdown/test/common_mark/autolinks.unit
new file mode 100644
index 0000000..0bb319c
--- /dev/null
+++ b/pkgs/markdown/test/common_mark/autolinks.unit
@@ -0,0 +1,76 @@
+>>> Autolinks - 594
+<http://foo.bar.baz>
+<<<
+<p><a href="http://foo.bar.baz">http://foo.bar.baz</a></p>
+>>> Autolinks - 595
+<https://foo.bar.baz/test?q=hello&id=22&boolean>
+<<<
+<p><a href="https://foo.bar.baz/test?q=hello&id=22&boolean">https://foo.bar.baz/test?q=hello&id=22&boolean</a></p>
+>>> Autolinks - 596
+<irc://foo.bar:2233/baz>
+<<<
+<p><a href="irc://foo.bar:2233/baz">irc://foo.bar:2233/baz</a></p>
+>>> Autolinks - 597
+<MAILTO:FOO@BAR.BAZ>
+<<<
+<p><a href="MAILTO:FOO@BAR.BAZ">MAILTO:FOO@BAR.BAZ</a></p>
+>>> Autolinks - 598
+<a+b+c:d>
+<<<
+<p><a href="a+b+c:d">a+b+c:d</a></p>
+>>> Autolinks - 599
+<made-up-scheme://foo,bar>
+<<<
+<p><a href="made-up-scheme://foo,bar">made-up-scheme://foo,bar</a></p>
+>>> Autolinks - 600
+<https://../>
+<<<
+<p><a href="https://../">https://../</a></p>
+>>> Autolinks - 601
+<localhost:5001/foo>
+<<<
+<p><a href="localhost:5001/foo">localhost:5001/foo</a></p>
+>>> Autolinks - 602
+<https://foo.bar/baz bim>
+<<<
+<p><https://foo.bar/baz bim></p>
+>>> Autolinks - 603
+<https://example.com/\[\>
+<<<
+<p><a href="https://example.com/%5C%5B%5C">https://example.com/\[\</a></p>
+>>> Autolinks - 604
+<foo@bar.example.com>
+<<<
+<p><a href="mailto:foo@bar.example.com">foo@bar.example.com</a></p>
+>>> Autolinks - 605
+<foo+special@Bar.baz-bar0.com>
+<<<
+<p><a href="mailto:foo+special@Bar.baz-bar0.com">foo+special@Bar.baz-bar0.com</a></p>
+>>> Autolinks - 606
+<foo\+@bar.example.com>
+<<<
+<p><foo+@bar.example.com></p>
+>>> Autolinks - 607
+<>
+<<<
+<p><></p>
+>>> Autolinks - 608
+< https://foo.bar >
+<<<
+<p>< https://foo.bar ></p>
+>>> Autolinks - 609
+<m:abc>
+<<<
+<p><m:abc></p>
+>>> Autolinks - 610
+<foo.bar.baz>
+<<<
+<p><foo.bar.baz></p>
+>>> Autolinks - 611
+https://example.com
+<<<
+<p>https://example.com</p>
+>>> Autolinks - 612
+foo@bar.example.com
+<<<
+<p>foo@bar.example.com</p>
diff --git a/pkgs/markdown/test/common_mark/backslash_escapes.unit b/pkgs/markdown/test/common_mark/backslash_escapes.unit
new file mode 100644
index 0000000..54766e4
--- /dev/null
+++ b/pkgs/markdown/test/common_mark/backslash_escapes.unit
@@ -0,0 +1,79 @@
+>>> Backslash escapes - 12
+\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\`\{\|\}\~
+<<<
+<p>!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~</p>
+>>> Backslash escapes - 13
+\ \A\a\ \3\φ\«
+<<<
+<p>\ \A\a\ \3\φ\«</p>
+>>> Backslash escapes - 14
+\*not emphasized*
+\<br/> not a tag
+\[not a link](/foo)
+\`not code`
+1\. not a list
+\* not a list
+\# not a heading
+\[foo]: /url "not a reference"
+\ö not a character entity
+<<<
+<p>*not emphasized*
+<br/> not a tag
+[not a link](/foo)
+`not code`
+1. not a list
+* not a list
+# not a heading
+[foo]: /url "not a reference"
+&ouml; not a character entity</p>
+>>> Backslash escapes - 15
+\\*emphasis*
+<<<
+<p>\<em>emphasis</em></p>
+>>> Backslash escapes - 16
+foo\
+bar
+<<<
+<p>foo<br />
+bar</p>
+>>> Backslash escapes - 17
+`` \[\` ``
+<<<
+<p><code>\[\`</code></p>
+>>> Backslash escapes - 18
+ \[\]
+<<<
+<pre><code>\[\]
+</code></pre>
+>>> Backslash escapes - 19
+~~~
+\[\]
+~~~
+<<<
+<pre><code>\[\]
+</code></pre>
+>>> Backslash escapes - 20
+<https://example.com?find=\*>
+<<<
+<p><a href="https://example.com?find=%5C*">https://example.com?find=\*</a></p>
+>>> Backslash escapes - 21
+<a href="/bar\/)">
+<<<
+<a href="/bar\/)">
+>>> Backslash escapes - 22
+[foo](/bar\* "ti\*tle")
+<<<
+<p><a href="/bar*" title="ti*tle">foo</a></p>
+>>> Backslash escapes - 23
+[foo]
+
+[foo]: /bar\* "ti\*tle"
+<<<
+<p><a href="/bar*" title="ti*tle">foo</a></p>
+>>> Backslash escapes - 24
+``` foo\+bar
+foo
+```
+<<<
+<pre><code class="language-foo+bar">foo
+</code></pre>
diff --git a/pkgs/markdown/test/common_mark/blank_lines.unit b/pkgs/markdown/test/common_mark/blank_lines.unit
new file mode 100644
index 0000000..86977bd
--- /dev/null
+++ b/pkgs/markdown/test/common_mark/blank_lines.unit
@@ -0,0 +1,12 @@
+>>> Blank lines - 227
+
+
+aaa
+
+
+# aaa
+
+
+<<<
+<p>aaa</p>
+<h1>aaa</h1>
diff --git a/pkgs/markdown/test/common_mark/block_quotes.unit b/pkgs/markdown/test/common_mark/block_quotes.unit
new file mode 100644
index 0000000..9931044
--- /dev/null
+++ b/pkgs/markdown/test/common_mark/block_quotes.unit
@@ -0,0 +1,239 @@
+>>> Block quotes - 228
+> # Foo
+> bar
+> baz
+<<<
+<blockquote>
+<h1>Foo</h1>
+<p>bar
+baz</p>
+</blockquote>
+>>> Block quotes - 229
+># Foo
+>bar
+> baz
+<<<
+<blockquote>
+<h1>Foo</h1>
+<p>bar
+baz</p>
+</blockquote>
+>>> Block quotes - 230
+ > # Foo
+ > bar
+ > baz
+<<<
+<blockquote>
+<h1>Foo</h1>
+<p>bar
+baz</p>
+</blockquote>
+>>> Block quotes - 231
+ > # Foo
+ > bar
+ > baz
+<<<
+<pre><code>> # Foo
+> bar
+> baz
+</code></pre>
+>>> Block quotes - 232
+> # Foo
+> bar
+baz
+<<<
+<blockquote>
+<h1>Foo</h1>
+<p>bar
+baz</p>
+</blockquote>
+>>> Block quotes - 233
+> bar
+baz
+> foo
+<<<
+<blockquote>
+<p>bar
+baz
+foo</p>
+</blockquote>
+>>> Block quotes - 234
+> foo
+---
+<<<
+<blockquote>
+<p>foo</p>
+</blockquote>
+<hr />
+>>> Block quotes - 235
+> - foo
+- bar
+<<<
+<blockquote>
+<ul>
+<li>foo</li>
+</ul>
+</blockquote>
+<ul>
+<li>bar</li>
+</ul>
+>>> Block quotes - 236
+> foo
+ bar
+<<<
+<blockquote>
+<pre><code>foo
+</code></pre>
+</blockquote>
+<pre><code>bar
+</code></pre>
+>>> Block quotes - 237
+> ```
+foo
+```
+<<<
+<blockquote>
+<pre><code></code></pre>
+</blockquote>
+<p>foo</p>
+<pre><code></code></pre>
+>>> Block quotes - 238
+> foo
+ - bar
+<<<
+<blockquote>
+<p>foo
+- bar</p>
+</blockquote>
+>>> Block quotes - 239
+>
+<<<
+<blockquote>
+</blockquote>
+>>> Block quotes - 240
+>
+>
+>
+<<<
+<blockquote>
+</blockquote>
+>>> Block quotes - 241
+>
+> foo
+>
+<<<
+<blockquote>
+<p>foo</p>
+</blockquote>
+>>> Block quotes - 242
+> foo
+
+> bar
+<<<
+<blockquote>
+<p>foo</p>
+</blockquote>
+<blockquote>
+<p>bar</p>
+</blockquote>
+>>> Block quotes - 243
+> foo
+> bar
+<<<
+<blockquote>
+<p>foo
+bar</p>
+</blockquote>
+>>> Block quotes - 244
+> foo
+>
+> bar
+<<<
+<blockquote>
+<p>foo</p>
+<p>bar</p>
+</blockquote>
+>>> Block quotes - 245
+foo
+> bar
+<<<
+<p>foo</p>
+<blockquote>
+<p>bar</p>
+</blockquote>
+>>> Block quotes - 246
+> aaa
+***
+> bbb
+<<<
+<blockquote>
+<p>aaa</p>
+</blockquote>
+<hr />
+<blockquote>
+<p>bbb</p>
+</blockquote>
+>>> Block quotes - 247
+> bar
+baz
+<<<
+<blockquote>
+<p>bar
+baz</p>
+</blockquote>
+>>> Block quotes - 248
+> bar
+
+baz
+<<<
+<blockquote>
+<p>bar</p>
+</blockquote>
+<p>baz</p>
+>>> Block quotes - 249
+> bar
+>
+baz
+<<<
+<blockquote>
+<p>bar</p>
+</blockquote>
+<p>baz</p>
+>>> Block quotes - 250
+> > > foo
+bar
+<<<
+<blockquote>
+<blockquote>
+<blockquote>
+<p>foo
+bar</p>
+</blockquote>
+</blockquote>
+</blockquote>
+>>> Block quotes - 251
+>>> foo
+> bar
+>>baz
+<<<
+<blockquote>
+<blockquote>
+<blockquote>
+<p>foo
+bar
+baz</p>
+</blockquote>
+</blockquote>
+</blockquote>
+>>> Block quotes - 252
+> code
+
+> not code
+<<<
+<blockquote>
+<pre><code>code
+</code></pre>
+</blockquote>
+<blockquote>
+<p>not code</p>
+</blockquote>
diff --git a/pkgs/markdown/test/common_mark/code_spans.unit b/pkgs/markdown/test/common_mark/code_spans.unit
new file mode 100644
index 0000000..5ff95dd
--- /dev/null
+++ b/pkgs/markdown/test/common_mark/code_spans.unit
@@ -0,0 +1,97 @@
+>>> Code spans - 328
+`foo`
+<<<
+<p><code>foo</code></p>
+>>> Code spans - 329
+`` foo ` bar ``
+<<<
+<p><code>foo ` bar</code></p>
+>>> Code spans - 330
+` `` `
+<<<
+<p><code>``</code></p>
+>>> Code spans - 331
+` `` `
+<<<
+<p><code> `` </code></p>
+>>> Code spans - 332
+` a`
+<<<
+<p><code> a</code></p>
+>>> Code spans - 333
+` b `
+<<<
+<p><code> b </code></p>
+>>> Code spans - 334
+` `
+` `
+<<<
+<p><code> </code>
+<code> </code></p>
+>>> Code spans - 335
+``
+foo
+bar
+baz
+``
+<<<
+<p><code>foo bar baz</code></p>
+>>> Code spans - 336
+``
+foo
+``
+<<<
+<p><code>foo </code></p>
+>>> Code spans - 337
+`foo bar
+baz`
+<<<
+<p><code>foo bar baz</code></p>
+>>> Code spans - 338
+`foo\`bar`
+<<<
+<p><code>foo\</code>bar`</p>
+>>> Code spans - 339
+``foo`bar``
+<<<
+<p><code>foo`bar</code></p>
+>>> Code spans - 340
+` foo `` bar `
+<<<
+<p><code>foo `` bar</code></p>
+>>> Code spans - 341
+*foo`*`
+<<<
+<p>*foo<code>*</code></p>
+>>> Code spans - 342
+[not a `link](/foo`)
+<<<
+<p>[not a <code>link](/foo</code>)</p>
+>>> Code spans - 343
+`<a href="`">`
+<<<
+<p><code><a href="</code>">`</p>
+>>> Code spans - 344
+<a href="`">`
+<<<
+<p><a href="`">`</p>
+>>> Code spans - 345
+`<https://foo.bar.`baz>`
+<<<
+<p><code><https://foo.bar.</code>baz>`</p>
+>>> Code spans - 346
+<https://foo.bar.`baz>`
+<<<
+<p><a href="https://foo.bar.%60baz">https://foo.bar.`baz</a>`</p>
+>>> Code spans - 347
+```foo``
+<<<
+<p>```foo``</p>
+>>> Code spans - 348
+`foo
+<<<
+<p>`foo</p>
+>>> Code spans - 349
+`foo``bar``
+<<<
+<p>`foo<code>bar</code></p>
diff --git a/pkgs/markdown/test/common_mark/emphasis_and_strong_emphasis.unit b/pkgs/markdown/test/common_mark/emphasis_and_strong_emphasis.unit
new file mode 100644
index 0000000..6c8181d
--- /dev/null
+++ b/pkgs/markdown/test/common_mark/emphasis_and_strong_emphasis.unit
@@ -0,0 +1,546 @@
+>>> Emphasis and strong emphasis - 350
+*foo bar*
+<<<
+<p><em>foo bar</em></p>
+>>> Emphasis and strong emphasis - 351
+a * foo bar*
+<<<
+<p>a * foo bar*</p>
+>>> Emphasis and strong emphasis - 352
+a*"foo"*
+<<<
+<p>a*"foo"*</p>
+>>> Emphasis and strong emphasis - 353
+* a *
+<<<
+<p>* a *</p>
+>>> Emphasis and strong emphasis - 354
+*$*alpha.
+
+*£*bravo.
+
+*€*charlie.
+<<<
+<p>*$*alpha.</p>
+<p><em>£</em>bravo.</p>
+<p><em>€</em>charlie.</p>
+>>> Emphasis and strong emphasis - 355
+foo*bar*
+<<<
+<p>foo<em>bar</em></p>
+>>> Emphasis and strong emphasis - 356
+5*6*78
+<<<
+<p>5<em>6</em>78</p>
+>>> Emphasis and strong emphasis - 357
+_foo bar_
+<<<
+<p><em>foo bar</em></p>
+>>> Emphasis and strong emphasis - 358
+_ foo bar_
+<<<
+<p>_ foo bar_</p>
+>>> Emphasis and strong emphasis - 359
+a_"foo"_
+<<<
+<p>a_"foo"_</p>
+>>> Emphasis and strong emphasis - 360
+foo_bar_
+<<<
+<p>foo_bar_</p>
+>>> Emphasis and strong emphasis - 361
+5_6_78
+<<<
+<p>5_6_78</p>
+>>> Emphasis and strong emphasis - 362
+пристаням_стремятся_
+<<<
+<p>пристаням_стремятся_</p>
+>>> Emphasis and strong emphasis - 363
+aa_"bb"_cc
+<<<
+<p>aa_"bb"_cc</p>
+>>> Emphasis and strong emphasis - 364
+foo-_(bar)_
+<<<
+<p>foo-<em>(bar)</em></p>
+>>> Emphasis and strong emphasis - 365
+_foo*
+<<<
+<p>_foo*</p>
+>>> Emphasis and strong emphasis - 366
+*foo bar *
+<<<
+<p>*foo bar *</p>
+>>> Emphasis and strong emphasis - 367
+*foo bar
+*
+<<<
+<p>*foo bar
+*</p>
+>>> Emphasis and strong emphasis - 368
+*(*foo)
+<<<
+<p>*(*foo)</p>
+>>> Emphasis and strong emphasis - 369
+*(*foo*)*
+<<<
+<p><em>(<em>foo</em>)</em></p>
+>>> Emphasis and strong emphasis - 370
+*foo*bar
+<<<
+<p><em>foo</em>bar</p>
+>>> Emphasis and strong emphasis - 371
+_foo bar _
+<<<
+<p>_foo bar _</p>
+>>> Emphasis and strong emphasis - 372
+_(_foo)
+<<<
+<p>_(_foo)</p>
+>>> Emphasis and strong emphasis - 373
+_(_foo_)_
+<<<
+<p><em>(<em>foo</em>)</em></p>
+>>> Emphasis and strong emphasis - 374
+_foo_bar
+<<<
+<p>_foo_bar</p>
+>>> Emphasis and strong emphasis - 375
+_пристаням_стремятся
+<<<
+<p>_пристаням_стремятся</p>
+>>> Emphasis and strong emphasis - 376
+_foo_bar_baz_
+<<<
+<p><em>foo_bar_baz</em></p>
+>>> Emphasis and strong emphasis - 377
+_(bar)_.
+<<<
+<p><em>(bar)</em>.</p>
+>>> Emphasis and strong emphasis - 378
+**foo bar**
+<<<
+<p><strong>foo bar</strong></p>
+>>> Emphasis and strong emphasis - 379
+** foo bar**
+<<<
+<p>** foo bar**</p>
+>>> Emphasis and strong emphasis - 380
+a**"foo"**
+<<<
+<p>a**"foo"**</p>
+>>> Emphasis and strong emphasis - 381
+foo**bar**
+<<<
+<p>foo<strong>bar</strong></p>
+>>> Emphasis and strong emphasis - 382
+__foo bar__
+<<<
+<p><strong>foo bar</strong></p>
+>>> Emphasis and strong emphasis - 383
+__ foo bar__
+<<<
+<p>__ foo bar__</p>
+>>> Emphasis and strong emphasis - 384
+__
+foo bar__
+<<<
+<p>__
+foo bar__</p>
+>>> Emphasis and strong emphasis - 385
+a__"foo"__
+<<<
+<p>a__"foo"__</p>
+>>> Emphasis and strong emphasis - 386
+foo__bar__
+<<<
+<p>foo__bar__</p>
+>>> Emphasis and strong emphasis - 387
+5__6__78
+<<<
+<p>5__6__78</p>
+>>> Emphasis and strong emphasis - 388
+пристаням__стремятся__
+<<<
+<p>пристаням__стремятся__</p>
+>>> Emphasis and strong emphasis - 389
+__foo, __bar__, baz__
+<<<
+<p><strong>foo, <strong>bar</strong>, baz</strong></p>
+>>> Emphasis and strong emphasis - 390
+foo-__(bar)__
+<<<
+<p>foo-<strong>(bar)</strong></p>
+>>> Emphasis and strong emphasis - 391
+**foo bar **
+<<<
+<p>**foo bar **</p>
+>>> Emphasis and strong emphasis - 392
+**(**foo)
+<<<
+<p>**(**foo)</p>
+>>> Emphasis and strong emphasis - 393
+*(**foo**)*
+<<<
+<p><em>(<strong>foo</strong>)</em></p>
+>>> Emphasis and strong emphasis - 394
+**Gomphocarpus (*Gomphocarpus physocarpus*, syn.
+*Asclepias physocarpa*)**
+<<<
+<p><strong>Gomphocarpus (<em>Gomphocarpus physocarpus</em>, syn.
+<em>Asclepias physocarpa</em>)</strong></p>
+>>> Emphasis and strong emphasis - 395
+**foo "*bar*" foo**
+<<<
+<p><strong>foo "<em>bar</em>" foo</strong></p>
+>>> Emphasis and strong emphasis - 396
+**foo**bar
+<<<
+<p><strong>foo</strong>bar</p>
+>>> Emphasis and strong emphasis - 397
+__foo bar __
+<<<
+<p>__foo bar __</p>
+>>> Emphasis and strong emphasis - 398
+__(__foo)
+<<<
+<p>__(__foo)</p>
+>>> Emphasis and strong emphasis - 399
+_(__foo__)_
+<<<
+<p><em>(<strong>foo</strong>)</em></p>
+>>> Emphasis and strong emphasis - 400
+__foo__bar
+<<<
+<p>__foo__bar</p>
+>>> Emphasis and strong emphasis - 401
+__пристаням__стремятся
+<<<
+<p>__пристаням__стремятся</p>
+>>> Emphasis and strong emphasis - 402
+__foo__bar__baz__
+<<<
+<p><strong>foo__bar__baz</strong></p>
+>>> Emphasis and strong emphasis - 403
+__(bar)__.
+<<<
+<p><strong>(bar)</strong>.</p>
+>>> Emphasis and strong emphasis - 404
+*foo [bar](/url)*
+<<<
+<p><em>foo <a href="/url">bar</a></em></p>
+>>> Emphasis and strong emphasis - 405
+*foo
+bar*
+<<<
+<p><em>foo
+bar</em></p>
+>>> Emphasis and strong emphasis - 406
+_foo __bar__ baz_
+<<<
+<p><em>foo <strong>bar</strong> baz</em></p>
+>>> Emphasis and strong emphasis - 407
+_foo _bar_ baz_
+<<<
+<p><em>foo <em>bar</em> baz</em></p>
+>>> Emphasis and strong emphasis - 408
+__foo_ bar_
+<<<
+<p><em><em>foo</em> bar</em></p>
+>>> Emphasis and strong emphasis - 409
+*foo *bar**
+<<<
+<p><em>foo <em>bar</em></em></p>
+>>> Emphasis and strong emphasis - 410
+*foo **bar** baz*
+<<<
+<p><em>foo <strong>bar</strong> baz</em></p>
+>>> Emphasis and strong emphasis - 411
+*foo**bar**baz*
+<<<
+<p><em>foo<strong>bar</strong>baz</em></p>
+>>> Emphasis and strong emphasis - 412
+*foo**bar*
+<<<
+<p><em>foo**bar</em></p>
+>>> Emphasis and strong emphasis - 413
+***foo** bar*
+<<<
+<p><em><strong>foo</strong> bar</em></p>
+>>> Emphasis and strong emphasis - 414
+*foo **bar***
+<<<
+<p><em>foo <strong>bar</strong></em></p>
+>>> Emphasis and strong emphasis - 415
+*foo**bar***
+<<<
+<p><em>foo<strong>bar</strong></em></p>
+>>> Emphasis and strong emphasis - 416
+foo***bar***baz
+<<<
+<p>foo<em><strong>bar</strong></em>baz</p>
+>>> Emphasis and strong emphasis - 417
+foo******bar*********baz
+<<<
+<p>foo<strong><strong><strong>bar</strong></strong></strong>***baz</p>
+>>> Emphasis and strong emphasis - 418
+*foo **bar *baz* bim** bop*
+<<<
+<p><em>foo <strong>bar <em>baz</em> bim</strong> bop</em></p>
+>>> Emphasis and strong emphasis - 419
+*foo [*bar*](/url)*
+<<<
+<p><em>foo <a href="/url"><em>bar</em></a></em></p>
+>>> Emphasis and strong emphasis - 420
+** is not an empty emphasis
+<<<
+<p>** is not an empty emphasis</p>
+>>> Emphasis and strong emphasis - 421
+**** is not an empty strong emphasis
+<<<
+<p>**** is not an empty strong emphasis</p>
+>>> Emphasis and strong emphasis - 422
+**foo [bar](/url)**
+<<<
+<p><strong>foo <a href="/url">bar</a></strong></p>
+>>> Emphasis and strong emphasis - 423
+**foo
+bar**
+<<<
+<p><strong>foo
+bar</strong></p>
+>>> Emphasis and strong emphasis - 424
+__foo _bar_ baz__
+<<<
+<p><strong>foo <em>bar</em> baz</strong></p>
+>>> Emphasis and strong emphasis - 425
+__foo __bar__ baz__
+<<<
+<p><strong>foo <strong>bar</strong> baz</strong></p>
+>>> Emphasis and strong emphasis - 426
+____foo__ bar__
+<<<
+<p><strong><strong>foo</strong> bar</strong></p>
+>>> Emphasis and strong emphasis - 427
+**foo **bar****
+<<<
+<p><strong>foo <strong>bar</strong></strong></p>
+>>> Emphasis and strong emphasis - 428
+**foo *bar* baz**
+<<<
+<p><strong>foo <em>bar</em> baz</strong></p>
+>>> Emphasis and strong emphasis - 429
+**foo*bar*baz**
+<<<
+<p><strong>foo<em>bar</em>baz</strong></p>
+>>> Emphasis and strong emphasis - 430
+***foo* bar**
+<<<
+<p><strong><em>foo</em> bar</strong></p>
+>>> Emphasis and strong emphasis - 431
+**foo *bar***
+<<<
+<p><strong>foo <em>bar</em></strong></p>
+>>> Emphasis and strong emphasis - 432
+**foo *bar **baz**
+bim* bop**
+<<<
+<p><strong>foo <em>bar <strong>baz</strong>
+bim</em> bop</strong></p>
+>>> Emphasis and strong emphasis - 433
+**foo [*bar*](/url)**
+<<<
+<p><strong>foo <a href="/url"><em>bar</em></a></strong></p>
+>>> Emphasis and strong emphasis - 434
+__ is not an empty emphasis
+<<<
+<p>__ is not an empty emphasis</p>
+>>> Emphasis and strong emphasis - 435
+____ is not an empty strong emphasis
+<<<
+<p>____ is not an empty strong emphasis</p>
+>>> Emphasis and strong emphasis - 436
+foo ***
+<<<
+<p>foo ***</p>
+>>> Emphasis and strong emphasis - 437
+foo *\**
+<<<
+<p>foo <em>*</em></p>
+>>> Emphasis and strong emphasis - 438
+foo *_*
+<<<
+<p>foo <em>_</em></p>
+>>> Emphasis and strong emphasis - 439
+foo *****
+<<<
+<p>foo *****</p>
+>>> Emphasis and strong emphasis - 440
+foo **\***
+<<<
+<p>foo <strong>*</strong></p>
+>>> Emphasis and strong emphasis - 441
+foo **_**
+<<<
+<p>foo <strong>_</strong></p>
+>>> Emphasis and strong emphasis - 442
+**foo*
+<<<
+<p>*<em>foo</em></p>
+>>> Emphasis and strong emphasis - 443
+*foo**
+<<<
+<p><em>foo</em>*</p>
+>>> Emphasis and strong emphasis - 444
+***foo**
+<<<
+<p>*<strong>foo</strong></p>
+>>> Emphasis and strong emphasis - 445
+****foo*
+<<<
+<p>***<em>foo</em></p>
+>>> Emphasis and strong emphasis - 446
+**foo***
+<<<
+<p><strong>foo</strong>*</p>
+>>> Emphasis and strong emphasis - 447
+*foo****
+<<<
+<p><em>foo</em>***</p>
+>>> Emphasis and strong emphasis - 448
+foo ___
+<<<
+<p>foo ___</p>
+>>> Emphasis and strong emphasis - 449
+foo _\__
+<<<
+<p>foo <em>_</em></p>
+>>> Emphasis and strong emphasis - 450
+foo _*_
+<<<
+<p>foo <em>*</em></p>
+>>> Emphasis and strong emphasis - 451
+foo _____
+<<<
+<p>foo _____</p>
+>>> Emphasis and strong emphasis - 452
+foo __\___
+<<<
+<p>foo <strong>_</strong></p>
+>>> Emphasis and strong emphasis - 453
+foo __*__
+<<<
+<p>foo <strong>*</strong></p>
+>>> Emphasis and strong emphasis - 454
+__foo_
+<<<
+<p>_<em>foo</em></p>
+>>> Emphasis and strong emphasis - 455
+_foo__
+<<<
+<p><em>foo</em>_</p>
+>>> Emphasis and strong emphasis - 456
+___foo__
+<<<
+<p>_<strong>foo</strong></p>
+>>> Emphasis and strong emphasis - 457
+____foo_
+<<<
+<p>___<em>foo</em></p>
+>>> Emphasis and strong emphasis - 458
+__foo___
+<<<
+<p><strong>foo</strong>_</p>
+>>> Emphasis and strong emphasis - 459
+_foo____
+<<<
+<p><em>foo</em>___</p>
+>>> Emphasis and strong emphasis - 460
+**foo**
+<<<
+<p><strong>foo</strong></p>
+>>> Emphasis and strong emphasis - 461
+*_foo_*
+<<<
+<p><em><em>foo</em></em></p>
+>>> Emphasis and strong emphasis - 462
+__foo__
+<<<
+<p><strong>foo</strong></p>
+>>> Emphasis and strong emphasis - 463
+_*foo*_
+<<<
+<p><em><em>foo</em></em></p>
+>>> Emphasis and strong emphasis - 464
+****foo****
+<<<
+<p><strong><strong>foo</strong></strong></p>
+>>> Emphasis and strong emphasis - 465
+____foo____
+<<<
+<p><strong><strong>foo</strong></strong></p>
+>>> Emphasis and strong emphasis - 466
+******foo******
+<<<
+<p><strong><strong><strong>foo</strong></strong></strong></p>
+>>> Emphasis and strong emphasis - 467
+***foo***
+<<<
+<p><em><strong>foo</strong></em></p>
+>>> Emphasis and strong emphasis - 468
+_____foo_____
+<<<
+<p><em><strong><strong>foo</strong></strong></em></p>
+>>> Emphasis and strong emphasis - 469
+*foo _bar* baz_
+<<<
+<p><em>foo _bar</em> baz_</p>
+>>> Emphasis and strong emphasis - 470
+*foo __bar *baz bim__ bam*
+<<<
+<p><em>foo <strong>bar *baz bim</strong> bam</em></p>
+>>> Emphasis and strong emphasis - 471
+**foo **bar baz**
+<<<
+<p>**foo <strong>bar baz</strong></p>
+>>> Emphasis and strong emphasis - 472
+*foo *bar baz*
+<<<
+<p>*foo <em>bar baz</em></p>
+>>> Emphasis and strong emphasis - 473
+*[bar*](/url)
+<<<
+<p>*<a href="/url">bar*</a></p>
+>>> Emphasis and strong emphasis - 474
+_foo [bar_](/url)
+<<<
+<p>_foo <a href="/url">bar_</a></p>
+>>> Emphasis and strong emphasis - 475
+*<img src="foo" title="*"/>
+<<<
+<p>*<img src="foo" title="*"/></p>
+>>> Emphasis and strong emphasis - 476
+**<a href="**">
+<<<
+<p>**<a href="**"></p>
+>>> Emphasis and strong emphasis - 477
+__<a href="__">
+<<<
+<p>__<a href="__"></p>
+>>> Emphasis and strong emphasis - 478
+*a `*`*
+<<<
+<p><em>a <code>*</code></em></p>
+>>> Emphasis and strong emphasis - 479
+_a `_`_
+<<<
+<p><em>a <code>_</code></em></p>
+>>> Emphasis and strong emphasis - 480
+**a<https://foo.bar/?q=**>
+<<<
+<p>**a<a href="https://foo.bar/?q=**">https://foo.bar/?q=**</a></p>
+>>> Emphasis and strong emphasis - 481
+__a<https://foo.bar/?q=__>
+<<<
+<p>__a<a href="https://foo.bar/?q=__">https://foo.bar/?q=__</a></p>
diff --git a/pkgs/markdown/test/common_mark/entity_and_numeric_character_references.unit b/pkgs/markdown/test/common_mark/entity_and_numeric_character_references.unit
new file mode 100644
index 0000000..2859435
--- /dev/null
+++ b/pkgs/markdown/test/common_mark/entity_and_numeric_character_references.unit
@@ -0,0 +1,93 @@
+>>> Entity and numeric character references - 25
+ & © Æ Ď
+¾ ℋ ⅆ
+∲ ≧̸
+<<<
+<p>& © Æ Ď
+¾ ℋ ⅆ
+∲ ≧̸</p>
+>>> Entity and numeric character references - 26
+# Ӓ Ϡ �
+<<<
+<p># Ӓ Ϡ �</p>
+>>> Entity and numeric character references - 27
+" ആ ಫ
+<<<
+<p>" ആ ಫ</p>
+>>> Entity and numeric character references - 28
+  &x; &#; &#x;
+�
+&#abcdef0;
+&ThisIsNotDefined; &hi?;
+<<<
+<p>&nbsp &x; &#; &#x;
+&#87654321;
+&#abcdef0;
+&ThisIsNotDefined; &hi?;</p>
+>>> Entity and numeric character references - 29
+©
+<<<
+<p>&copy</p>
+>>> Entity and numeric character references - 30
+&MadeUpEntity;
+<<<
+<p>&MadeUpEntity;</p>
+>>> Entity and numeric character references - 31
+<a href="öö.html">
+<<<
+<a href="öö.html">
+>>> Entity and numeric character references - 32
+[foo](/föö "föö")
+<<<
+<p><a href="/f%C3%B6%C3%B6" title="föö">foo</a></p>
+>>> Entity and numeric character references - 33
+[foo]
+
+[foo]: /föö "föö"
+<<<
+<p><a href="/f%C3%B6%C3%B6" title="föö">foo</a></p>
+>>> Entity and numeric character references - 34
+``` föö
+foo
+```
+<<<
+<pre><code class="language-föö">foo
+</code></pre>
+>>> Entity and numeric character references - 35
+`föö`
+<<<
+<p><code>f&ouml;&ouml;</code></p>
+>>> Entity and numeric character references - 36
+ föfö
+<<<
+<pre><code>f&ouml;f&ouml;
+</code></pre>
+>>> Entity and numeric character references - 37
+*foo*
+*foo*
+<<<
+<p>*foo*
+<em>foo</em></p>
+>>> Entity and numeric character references - 38
+* foo
+
+* foo
+<<<
+<p>* foo</p>
+<ul>
+<li>foo</li>
+</ul>
+>>> Entity and numeric character references - 39
+foo bar
+<<<
+<p>foo
+
+bar</p>
+>>> Entity and numeric character references - 40
+	foo
+<<<
+<p>foo</p>
+>>> Entity and numeric character references - 41
+[a](url "tit")
+<<<
+<p>[a](url "tit")</p>
diff --git a/pkgs/markdown/test/common_mark/fenced_code_blocks.unit b/pkgs/markdown/test/common_mark/fenced_code_blocks.unit
new file mode 100644
index 0000000..06dec58
--- /dev/null
+++ b/pkgs/markdown/test/common_mark/fenced_code_blocks.unit
@@ -0,0 +1,245 @@
+>>> Fenced code blocks - 119
+```
+<
+ >
+```
+<<<
+<pre><code><
+ >
+</code></pre>
+>>> Fenced code blocks - 120
+~~~
+<
+ >
+~~~
+<<<
+<pre><code><
+ >
+</code></pre>
+>>> Fenced code blocks - 121
+``
+foo
+``
+<<<
+<p><code>foo</code></p>
+>>> Fenced code blocks - 122
+```
+aaa
+~~~
+```
+<<<
+<pre><code>aaa
+~~~
+</code></pre>
+>>> Fenced code blocks - 123
+~~~
+aaa
+```
+~~~
+<<<
+<pre><code>aaa
+```
+</code></pre>
+>>> Fenced code blocks - 124
+````
+aaa
+```
+``````
+<<<
+<pre><code>aaa
+```
+</code></pre>
+>>> Fenced code blocks - 125
+~~~~
+aaa
+~~~
+~~~~
+<<<
+<pre><code>aaa
+~~~
+</code></pre>
+>>> Fenced code blocks - 126
+```
+<<<
+<pre><code></code></pre>
+>>> Fenced code blocks - 127
+`````
+
+```
+aaa
+<<<
+<pre><code>
+```
+aaa
+</code></pre>
+>>> Fenced code blocks - 128
+> ```
+> aaa
+
+bbb
+<<<
+<blockquote>
+<pre><code>aaa
+</code></pre>
+</blockquote>
+<p>bbb</p>
+>>> Fenced code blocks - 129
+```
+
+
+```
+<<<
+<pre><code>
+
+</code></pre>
+>>> Fenced code blocks - 130
+```
+```
+<<<
+<pre><code></code></pre>
+>>> Fenced code blocks - 131
+ ```
+ aaa
+aaa
+```
+<<<
+<pre><code>aaa
+aaa
+</code></pre>
+>>> Fenced code blocks - 132
+ ```
+aaa
+ aaa
+aaa
+ ```
+<<<
+<pre><code>aaa
+aaa
+aaa
+</code></pre>
+>>> Fenced code blocks - 133
+ ```
+ aaa
+ aaa
+ aaa
+ ```
+<<<
+<pre><code>aaa
+ aaa
+aaa
+</code></pre>
+>>> Fenced code blocks - 134
+ ```
+ aaa
+ ```
+<<<
+<pre><code>```
+aaa
+```
+</code></pre>
+>>> Fenced code blocks - 135
+```
+aaa
+ ```
+<<<
+<pre><code>aaa
+</code></pre>
+>>> Fenced code blocks - 136
+ ```
+aaa
+ ```
+<<<
+<pre><code>aaa
+</code></pre>
+>>> Fenced code blocks - 137
+```
+aaa
+ ```
+<<<
+<pre><code>aaa
+ ```
+</code></pre>
+>>> Fenced code blocks - 138
+``` ```
+aaa
+<<<
+<p><code> </code>
+aaa</p>
+>>> Fenced code blocks - 139
+~~~~~~
+aaa
+~~~ ~~
+<<<
+<pre><code>aaa
+~~~ ~~
+</code></pre>
+>>> Fenced code blocks - 140
+foo
+```
+bar
+```
+baz
+<<<
+<p>foo</p>
+<pre><code>bar
+</code></pre>
+<p>baz</p>
+>>> Fenced code blocks - 141
+foo
+---
+~~~
+bar
+~~~
+# baz
+<<<
+<h2>foo</h2>
+<pre><code>bar
+</code></pre>
+<h1>baz</h1>
+>>> Fenced code blocks - 142
+```ruby
+def foo(x)
+ return 3
+end
+```
+<<<
+<pre><code class="language-ruby">def foo(x)
+ return 3
+end
+</code></pre>
+>>> Fenced code blocks - 143
+~~~~ ruby startline=3 $%@#$
+def foo(x)
+ return 3
+end
+~~~~~~~
+<<<
+<pre><code class="language-ruby">def foo(x)
+ return 3
+end
+</code></pre>
+>>> Fenced code blocks - 144
+````;
+````
+<<<
+<pre><code class="language-;"></code></pre>
+>>> Fenced code blocks - 145
+``` aa ```
+foo
+<<<
+<p><code>aa</code>
+foo</p>
+>>> Fenced code blocks - 146
+~~~ aa ``` ~~~
+foo
+~~~
+<<<
+<pre><code class="language-aa">foo
+</code></pre>
+>>> Fenced code blocks - 147
+```
+``` aaa
+```
+<<<
+<pre><code>``` aaa
+</code></pre>
diff --git a/pkgs/markdown/test/common_mark/hard_line_breaks.unit b/pkgs/markdown/test/common_mark/hard_line_breaks.unit
new file mode 100644
index 0000000..8a3f0be
--- /dev/null
+++ b/pkgs/markdown/test/common_mark/hard_line_breaks.unit
@@ -0,0 +1,80 @@
+>>> Hard line breaks - 633
+foo
+baz
+<<<
+<p>foo<br />
+baz</p>
+>>> Hard line breaks - 634
+foo\
+baz
+<<<
+<p>foo<br />
+baz</p>
+>>> Hard line breaks - 635
+foo
+baz
+<<<
+<p>foo<br />
+baz</p>
+>>> Hard line breaks - 636
+foo
+ bar
+<<<
+<p>foo<br />
+bar</p>
+>>> Hard line breaks - 637
+foo\
+ bar
+<<<
+<p>foo<br />
+bar</p>
+>>> Hard line breaks - 638
+*foo
+bar*
+<<<
+<p><em>foo<br />
+bar</em></p>
+>>> Hard line breaks - 639
+*foo\
+bar*
+<<<
+<p><em>foo<br />
+bar</em></p>
+>>> Hard line breaks - 640
+`code
+span`
+<<<
+<p><code>code span</code></p>
+>>> Hard line breaks - 641
+`code\
+span`
+<<<
+<p><code>code\ span</code></p>
+>>> Hard line breaks - 642
+<a href="foo
+bar">
+<<<
+<p><a href="foo
+bar"></p>
+>>> Hard line breaks - 643
+<a href="foo\
+bar">
+<<<
+<p><a href="foo\
+bar"></p>
+>>> Hard line breaks - 644
+foo\
+<<<
+<p>foo\</p>
+>>> Hard line breaks - 645
+foo
+<<<
+<p>foo</p>
+>>> Hard line breaks - 646
+### foo\
+<<<
+<h3>foo\</h3>
+>>> Hard line breaks - 647
+### foo
+<<<
+<h3>foo</h3>
diff --git a/pkgs/markdown/test/common_mark/html_blocks.unit b/pkgs/markdown/test/common_mark/html_blocks.unit
new file mode 100644
index 0000000..3a01cd0
--- /dev/null
+++ b/pkgs/markdown/test/common_mark/html_blocks.unit
@@ -0,0 +1,449 @@
+>>> HTML blocks - 148
+<table><tr><td>
+<pre>
+**Hello**,
+
+_world_.
+</pre>
+</td></tr></table>
+<<<
+<table><tr><td>
+<pre>
+**Hello**,
+<p><em>world</em>.
+</pre></p>
+</td></tr></table>
+>>> HTML blocks - 149
+<table>
+ <tr>
+ <td>
+ hi
+ </td>
+ </tr>
+</table>
+
+okay.
+<<<
+<table>
+ <tr>
+ <td>
+ hi
+ </td>
+ </tr>
+</table>
+<p>okay.</p>
+>>> HTML blocks - 150
+ <div>
+ *hello*
+ <foo><a>
+<<<
+ <div>
+ *hello*
+ <foo><a>
+>>> HTML blocks - 151
+</div>
+*foo*
+<<<
+</div>
+*foo*
+>>> HTML blocks - 152
+<DIV CLASS="foo">
+
+*Markdown*
+
+</DIV>
+<<<
+<DIV CLASS="foo">
+<p><em>Markdown</em></p>
+</DIV>
+>>> HTML blocks - 153
+<div id="foo"
+ class="bar">
+</div>
+<<<
+<div id="foo"
+ class="bar">
+</div>
+>>> HTML blocks - 154
+<div id="foo" class="bar
+ baz">
+</div>
+<<<
+<div id="foo" class="bar
+ baz">
+</div>
+>>> HTML blocks - 155
+<div>
+*foo*
+
+*bar*
+<<<
+<div>
+*foo*
+<p><em>bar</em></p>
+>>> HTML blocks - 156
+<div id="foo"
+*hi*
+<<<
+<div id="foo"
+*hi*
+>>> HTML blocks - 157
+<div class
+foo
+<<<
+<div class
+foo
+>>> HTML blocks - 158
+<div *???-&&&-<---
+*foo*
+<<<
+<div *???-&&&-<---
+*foo*
+>>> HTML blocks - 159
+<div><a href="bar">*foo*</a></div>
+<<<
+<div><a href="bar">*foo*</a></div>
+>>> HTML blocks - 160
+<table><tr><td>
+foo
+</td></tr></table>
+<<<
+<table><tr><td>
+foo
+</td></tr></table>
+>>> HTML blocks - 161
+<div></div>
+``` c
+int x = 33;
+```
+<<<
+<div></div>
+``` c
+int x = 33;
+```
+>>> HTML blocks - 162
+<a href="foo">
+*bar*
+</a>
+<<<
+<a href="foo">
+*bar*
+</a>
+>>> HTML blocks - 163
+<Warning>
+*bar*
+</Warning>
+<<<
+<Warning>
+*bar*
+</Warning>
+>>> HTML blocks - 164
+<i class="foo">
+*bar*
+</i>
+<<<
+<i class="foo">
+*bar*
+</i>
+>>> HTML blocks - 165
+</ins>
+*bar*
+<<<
+</ins>
+*bar*
+>>> HTML blocks - 166
+<del>
+*foo*
+</del>
+<<<
+<del>
+*foo*
+</del>
+>>> HTML blocks - 167
+<del>
+
+*foo*
+
+</del>
+<<<
+<del>
+<p><em>foo</em></p>
+</del>
+>>> HTML blocks - 168
+<del>*foo*</del>
+<<<
+<p><del><em>foo</em></del></p>
+>>> HTML blocks - 169
+<pre language="haskell"><code>
+import Text.HTML.TagSoup
+
+main :: IO ()
+main = print $ parseTags tags
+</code></pre>
+okay
+<<<
+<pre language="haskell"><code>
+import Text.HTML.TagSoup
+
+main :: IO ()
+main = print $ parseTags tags
+</code></pre>
+<p>okay</p>
+>>> HTML blocks - 170
+<script type="text/javascript">
+// JavaScript example
+
+document.getElementById("demo").innerHTML = "Hello JavaScript!";
+</script>
+okay
+<<<
+<script type="text/javascript">
+// JavaScript example
+
+document.getElementById("demo").innerHTML = "Hello JavaScript!";
+</script>
+<p>okay</p>
+>>> HTML blocks - 171
+<textarea>
+
+*foo*
+
+_bar_
+
+</textarea>
+<<<
+<textarea>
+
+*foo*
+
+_bar_
+
+</textarea>
+>>> HTML blocks - 172
+<style
+ type="text/css">
+h1 {color:red;}
+
+p {color:blue;}
+</style>
+okay
+<<<
+<style
+ type="text/css">
+h1 {color:red;}
+
+p {color:blue;}
+</style>
+<p>okay</p>
+>>> HTML blocks - 173
+<style
+ type="text/css">
+
+foo
+<<<
+<style
+ type="text/css">
+
+foo
+>>> HTML blocks - 174
+> <div>
+> foo
+
+bar
+<<<
+<blockquote>
+<div>
+foo
+</blockquote>
+<p>bar</p>
+>>> HTML blocks - 175
+- <div>
+- foo
+<<<
+<ul>
+<li>
+<div>
+</li>
+<li>foo</li>
+</ul>
+>>> HTML blocks - 176
+<style>p{color:red;}</style>
+*foo*
+<<<
+<style>p{color:red;}</style>
+<p><em>foo</em></p>
+>>> HTML blocks - 177
+<!-- foo -->*bar*
+*baz*
+<<<
+<!-- foo -->*bar*
+<p><em>baz</em></p>
+>>> HTML blocks - 178
+<script>
+foo
+</script>1. *bar*
+<<<
+<script>
+foo
+</script>1. *bar*
+>>> HTML blocks - 179
+<!-- Foo
+
+bar
+ baz -->
+okay
+<<<
+<!-- Foo
+
+bar
+ baz -->
+<p>okay</p>
+>>> HTML blocks - 180
+<?php
+
+ echo '>';
+
+?>
+okay
+<<<
+<?php
+
+ echo '>';
+
+?>
+<p>okay</p>
+>>> HTML blocks - 181
+<!DOCTYPE html>
+<<<
+<!DOCTYPE html>
+>>> HTML blocks - 182
+<![CDATA[
+function matchwo(a,b)
+{
+ if (a < b && a < 0) then {
+ return 1;
+
+ } else {
+
+ return 0;
+ }
+}
+]]>
+okay
+<<<
+<![CDATA[
+function matchwo(a,b)
+{
+ if (a < b && a < 0) then {
+ return 1;
+
+ } else {
+
+ return 0;
+ }
+}
+]]>
+<p>okay</p>
+>>> HTML blocks - 183
+ <!-- foo -->
+
+ <!-- foo -->
+<<<
+ <!-- foo -->
+<pre><code><!-- foo -->
+</code></pre>
+>>> HTML blocks - 184
+ <div>
+
+ <div>
+<<<
+ <div>
+<pre><code><div>
+</code></pre>
+>>> HTML blocks - 185
+Foo
+<div>
+bar
+</div>
+<<<
+<p>Foo</p>
+<div>
+bar
+</div>
+>>> HTML blocks - 186
+<div>
+bar
+</div>
+*foo*
+<<<
+<div>
+bar
+</div>
+*foo*
+>>> HTML blocks - 187
+Foo
+<a href="bar">
+baz
+<<<
+<p>Foo
+<a href="bar">
+baz</p>
+>>> HTML blocks - 188
+<div>
+
+*Emphasized* text.
+
+</div>
+<<<
+<div>
+<p><em>Emphasized</em> text.</p>
+</div>
+>>> HTML blocks - 189
+<div>
+*Emphasized* text.
+</div>
+<<<
+<div>
+*Emphasized* text.
+</div>
+>>> HTML blocks - 190
+<table>
+
+<tr>
+
+<td>
+Hi
+</td>
+
+</tr>
+
+</table>
+<<<
+<table>
+<tr>
+<td>
+Hi
+</td>
+</tr>
+</table>
+>>> HTML blocks - 191
+<table>
+
+ <tr>
+
+ <td>
+ Hi
+ </td>
+
+ </tr>
+
+</table>
+<<<
+<table>
+ <tr>
+<pre><code><td>
+ Hi
+</td>
+</code></pre>
+ </tr>
+</table>
diff --git a/pkgs/markdown/test/common_mark/images.unit b/pkgs/markdown/test/common_mark/images.unit
new file mode 100644
index 0000000..ae42aa2
--- /dev/null
+++ b/pkgs/markdown/test/common_mark/images.unit
@@ -0,0 +1,121 @@
+>>> Images - 572
+
+<<<
+<p><img src="/url" alt="foo" title="title" /></p>
+>>> Images - 573
+![foo *bar*]
+
+[foo *bar*]: train.jpg "train & tracks"
+<<<
+<p><img src="train.jpg" alt="foo bar" title="train & tracks" /></p>
+>>> Images - 574
+](/url2)
+<<<
+<p><img src="/url2" alt="foo bar" /></p>
+>>> Images - 575
+](/url2)
+<<<
+<p><img src="/url2" alt="foo bar" /></p>
+>>> Images - 576
+![foo *bar*][]
+
+[foo *bar*]: train.jpg "train & tracks"
+<<<
+<p><img src="train.jpg" alt="foo bar" title="train & tracks" /></p>
+>>> Images - 577
+![foo *bar*][foobar]
+
+[FOOBAR]: train.jpg "train & tracks"
+<<<
+<p><img src="train.jpg" alt="foo bar" title="train & tracks" /></p>
+>>> Images - 578
+
+<<<
+<p><img src="train.jpg" alt="foo" /></p>
+>>> Images - 579
+My 
+<<<
+<p>My <img src="/path/to/train.jpg" alt="foo bar" title="title" /></p>
+>>> Images - 580
+
+<<<
+<p><img src="url" alt="foo" /></p>
+>>> Images - 581
+
+<<<
+<p><img src="/url" alt="" /></p>
+>>> Images - 582
+![foo][bar]
+
+[bar]: /url
+<<<
+<p><img src="/url" alt="foo" /></p>
+>>> Images - 583
+![foo][bar]
+
+[BAR]: /url
+<<<
+<p><img src="/url" alt="foo" /></p>
+>>> Images - 584
+![foo][]
+
+[foo]: /url "title"
+<<<
+<p><img src="/url" alt="foo" title="title" /></p>
+>>> Images - 585
+![*foo* bar][]
+
+[*foo* bar]: /url "title"
+<<<
+<p><img src="/url" alt="foo bar" title="title" /></p>
+>>> Images - 586
+![Foo][]
+
+[foo]: /url "title"
+<<<
+<p><img src="/url" alt="Foo" title="title" /></p>
+>>> Images - 587
+![foo]
+[]
+
+[foo]: /url "title"
+<<<
+<p><img src="/url" alt="foo" title="title" />
+[]</p>
+>>> Images - 588
+![foo]
+
+[foo]: /url "title"
+<<<
+<p><img src="/url" alt="foo" title="title" /></p>
+>>> Images - 589
+![*foo* bar]
+
+[*foo* bar]: /url "title"
+<<<
+<p><img src="/url" alt="foo bar" title="title" /></p>
+>>> Images - 590
+![[foo]]
+
+[[foo]]: /url "title"
+<<<
+<p>![[foo]]</p>
+<p>[[foo]]: /url "title"</p>
+>>> Images - 591
+![Foo]
+
+[foo]: /url "title"
+<<<
+<p><img src="/url" alt="Foo" title="title" /></p>
+>>> Images - 592
+!\[foo]
+
+[foo]: /url "title"
+<<<
+<p>![foo]</p>
+>>> Images - 593
+\![foo]
+
+[foo]: /url "title"
+<<<
+<p>!<a href="/url" title="title">foo</a></p>
diff --git a/pkgs/markdown/test/common_mark/indented_code_blocks.unit b/pkgs/markdown/test/common_mark/indented_code_blocks.unit
new file mode 100644
index 0000000..ce142fe
--- /dev/null
+++ b/pkgs/markdown/test/common_mark/indented_code_blocks.unit
@@ -0,0 +1,118 @@
+>>> Indented code blocks - 107
+ a simple
+ indented code block
+<<<
+<pre><code>a simple
+ indented code block
+</code></pre>
+>>> Indented code blocks - 108
+ - foo
+
+ bar
+<<<
+<ul>
+<li>
+<p>foo</p>
+<p>bar</p>
+</li>
+</ul>
+>>> Indented code blocks - 109
+1. foo
+
+ - bar
+<<<
+<ol>
+<li>
+<p>foo</p>
+<ul>
+<li>bar</li>
+</ul>
+</li>
+</ol>
+>>> Indented code blocks - 110
+ <a/>
+ *hi*
+
+ - one
+<<<
+<pre><code><a/>
+*hi*
+
+- one
+</code></pre>
+>>> Indented code blocks - 111
+ chunk1
+
+ chunk2
+
+
+
+ chunk3
+<<<
+<pre><code>chunk1
+
+chunk2
+
+
+
+chunk3
+</code></pre>
+>>> Indented code blocks - 112
+ chunk1
+
+ chunk2
+<<<
+<pre><code>chunk1
+
+ chunk2
+</code></pre>
+>>> Indented code blocks - 113
+Foo
+ bar
+
+<<<
+<p>Foo
+bar</p>
+>>> Indented code blocks - 114
+ foo
+bar
+<<<
+<pre><code>foo
+</code></pre>
+<p>bar</p>
+>>> Indented code blocks - 115
+# Heading
+ foo
+Heading
+------
+ foo
+----
+<<<
+<h1>Heading</h1>
+<pre><code>foo
+</code></pre>
+<h2>Heading</h2>
+<pre><code>foo
+</code></pre>
+<hr />
+>>> Indented code blocks - 116
+ foo
+ bar
+<<<
+<pre><code> foo
+bar
+</code></pre>
+>>> Indented code blocks - 117
+
+
+ foo
+
+
+<<<
+<pre><code>foo
+</code></pre>
+>>> Indented code blocks - 118
+ foo
+<<<
+<pre><code>foo
+</code></pre>
diff --git a/pkgs/markdown/test/common_mark/inlines.unit b/pkgs/markdown/test/common_mark/inlines.unit
new file mode 100644
index 0000000..3d2eebe
--- /dev/null
+++ b/pkgs/markdown/test/common_mark/inlines.unit
@@ -0,0 +1,4 @@
+>>> Inlines - 327
+`hi`lo`
+<<<
+<p><code>hi</code>lo`</p>
diff --git a/pkgs/markdown/test/common_mark/link_reference_definitions.unit b/pkgs/markdown/test/common_mark/link_reference_definitions.unit
new file mode 100644
index 0000000..0677259
--- /dev/null
+++ b/pkgs/markdown/test/common_mark/link_reference_definitions.unit
@@ -0,0 +1,202 @@
+>>> Link reference definitions - 192
+[foo]: /url "title"
+
+[foo]
+<<<
+<p><a href="/url" title="title">foo</a></p>
+>>> Link reference definitions - 193
+ [foo]:
+ /url
+ 'the title'
+
+[foo]
+<<<
+<p><a href="/url" title="the title">foo</a></p>
+>>> Link reference definitions - 194
+[Foo*bar\]]:my_(url) 'title (with parens)'
+
+[Foo*bar\]]
+<<<
+<p><a href="my_(url)" title="title (with parens)">Foo*bar]</a></p>
+>>> Link reference definitions - 195
+[Foo bar]:
+<my url>
+'title'
+
+[Foo bar]
+<<<
+<p><a href="my%20url" title="title">Foo bar</a></p>
+>>> Link reference definitions - 196
+[foo]: /url '
+title
+line1
+line2
+'
+
+[foo]
+<<<
+<p><a href="/url" title="
+title
+line1
+line2
+">foo</a></p>
+>>> Link reference definitions - 197
+[foo]: /url 'title
+
+with blank line'
+
+[foo]
+<<<
+<p>[foo]: /url 'title</p>
+<p>with blank line'</p>
+<p>[foo]</p>
+>>> Link reference definitions - 198
+[foo]:
+/url
+
+[foo]
+<<<
+<p><a href="/url">foo</a></p>
+>>> Link reference definitions - 199
+[foo]:
+
+[foo]
+<<<
+<p>[foo]:</p>
+<p>[foo]</p>
+>>> Link reference definitions - 200
+[foo]: <>
+
+[foo]
+<<<
+<p><a href="">foo</a></p>
+>>> Link reference definitions - 201
+[foo]: <bar>(baz)
+
+[foo]
+<<<
+<p>[foo]: <bar>(baz)</p>
+<p>[foo]</p>
+>>> Link reference definitions - 202
+[foo]: /url\bar\*baz "foo\"bar\baz"
+
+[foo]
+<<<
+<p><a href="/url%5Cbar*baz" title="foo"bar\baz">foo</a></p>
+>>> Link reference definitions - 203
+[foo]
+
+[foo]: url
+<<<
+<p><a href="url">foo</a></p>
+>>> Link reference definitions - 204
+[foo]
+
+[foo]: first
+[foo]: second
+<<<
+<p><a href="first">foo</a></p>
+>>> Link reference definitions - 205
+[FOO]: /url
+
+[Foo]
+<<<
+<p><a href="/url">Foo</a></p>
+>>> Link reference definitions - 206
+[ΑΓΩ]: /φου
+
+[αγω]
+<<<
+<p><a href="/%CF%86%CE%BF%CF%85">αγω</a></p>
+>>> Link reference definitions - 207
+[foo]: /url
+<<<
+
+>>> Link reference definitions - 208
+[
+foo
+]: /url
+bar
+<<<
+<p>bar</p>
+>>> Link reference definitions - 209
+[foo]: /url "title" ok
+<<<
+<p>[foo]: /url "title" ok</p>
+>>> Link reference definitions - 210
+[foo]: /url
+"title" ok
+<<<
+<p>"title" ok</p>
+>>> Link reference definitions - 211
+ [foo]: /url "title"
+
+[foo]
+<<<
+<pre><code>[foo]: /url "title"
+</code></pre>
+<p>[foo]</p>
+>>> Link reference definitions - 212
+```
+[foo]: /url
+```
+
+[foo]
+<<<
+<pre><code>[foo]: /url
+</code></pre>
+<p>[foo]</p>
+>>> Link reference definitions - 213
+Foo
+[bar]: /baz
+
+[bar]
+<<<
+<p>Foo
+[bar]: /baz</p>
+<p>[bar]</p>
+>>> Link reference definitions - 214
+# [Foo]
+[foo]: /url
+> bar
+<<<
+<h1><a href="/url">Foo</a></h1>
+<blockquote>
+<p>bar</p>
+</blockquote>
+>>> Link reference definitions - 215
+[foo]: /url
+bar
+===
+[foo]
+<<<
+<h1>bar</h1>
+<p><a href="/url">foo</a></p>
+>>> Link reference definitions - 216
+[foo]: /url
+===
+[foo]
+<<<
+<p>===
+<a href="/url">foo</a></p>
+>>> Link reference definitions - 217
+[foo]: /foo-url "foo"
+[bar]: /bar-url
+ "bar"
+[baz]: /baz-url
+
+[foo],
+[bar],
+[baz]
+<<<
+<p><a href="/foo-url" title="foo">foo</a>,
+<a href="/bar-url" title="bar">bar</a>,
+<a href="/baz-url">baz</a></p>
+>>> Link reference definitions - 218
+[foo]
+
+> [foo]: /url
+<<<
+<p><a href="/url">foo</a></p>
+<blockquote>
+</blockquote>
diff --git a/pkgs/markdown/test/common_mark/links.unit b/pkgs/markdown/test/common_mark/links.unit
new file mode 100644
index 0000000..ab399f5
--- /dev/null
+++ b/pkgs/markdown/test/common_mark/links.unit
@@ -0,0 +1,488 @@
+>>> Links - 482
+[link](/uri "title")
+<<<
+<p><a href="/uri" title="title">link</a></p>
+>>> Links - 483
+[link](/uri)
+<<<
+<p><a href="/uri">link</a></p>
+>>> Links - 484
+[](./target.md)
+<<<
+<p><a href="./target.md"></a></p>
+>>> Links - 485
+[link]()
+<<<
+<p><a href="">link</a></p>
+>>> Links - 486
+[link](<>)
+<<<
+<p><a href="">link</a></p>
+>>> Links - 487
+[]()
+<<<
+<p><a href=""></a></p>
+>>> Links - 488
+[link](/my uri)
+<<<
+<p>[link](/my uri)</p>
+>>> Links - 489
+[link](</my uri>)
+<<<
+<p><a href="/my%20uri">link</a></p>
+>>> Links - 490
+[link](foo
+bar)
+<<<
+<p>[link](foo
+bar)</p>
+>>> Links - 491
+[link](<foo
+bar>)
+<<<
+<p>[link](<foo
+bar>)</p>
+>>> Links - 492
+[a](<b)c>)
+<<<
+<p><a href="b)c">a</a></p>
+>>> Links - 493
+[link](<foo\>)
+<<<
+<p>[link](<foo>)</p>
+>>> Links - 494
+[a](<b)c
+[a](<b)c>
+[a](<b>c)
+<<<
+<p>[a](<b)c
+[a](<b)c>
+[a](<b>c)</p>
+>>> Links - 495
+[link](\(foo\))
+<<<
+<p><a href="(foo)">link</a></p>
+>>> Links - 496
+[link](foo(and(bar)))
+<<<
+<p><a href="foo(and(bar))">link</a></p>
+>>> Links - 497
+[link](foo(and(bar))
+<<<
+<p>[link](foo(and(bar))</p>
+>>> Links - 498
+[link](foo\(and\(bar\))
+<<<
+<p><a href="foo(and(bar)">link</a></p>
+>>> Links - 499
+[link](<foo(and(bar)>)
+<<<
+<p><a href="foo(and(bar)">link</a></p>
+>>> Links - 500
+[link](foo\)\:)
+<<<
+<p><a href="foo):">link</a></p>
+>>> Links - 501
+[link](#fragment)
+
+[link](https://example.com#fragment)
+
+[link](https://example.com?foo=3#frag)
+<<<
+<p><a href="#fragment">link</a></p>
+<p><a href="https://example.com#fragment">link</a></p>
+<p><a href="https://example.com?foo=3#frag">link</a></p>
+>>> Links - 502
+[link](foo\bar)
+<<<
+<p><a href="foo%5Cbar">link</a></p>
+>>> Links - 503
+[link](foo%20bä)
+<<<
+<p><a href="foo%20b%C3%A4">link</a></p>
+>>> Links - 504
+[link]("title")
+<<<
+<p><a href="%22title%22">link</a></p>
+>>> Links - 505
+[link](/url "title")
+[link](/url 'title')
+[link](/url (title))
+<<<
+<p><a href="/url" title="title">link</a>
+<a href="/url" title="title">link</a>
+<a href="/url" title="title">link</a></p>
+>>> Links - 506
+[link](/url "title \""")
+<<<
+<p><a href="/url" title="title """>link</a></p>
+>>> Links - 507
+[link](/url "title")
+<<<
+<p><a href="/url%C2%A0%22title%22">link</a></p>
+>>> Links - 508
+[link](/url "title "and" title")
+<<<
+<p>[link](/url "title "and" title")</p>
+>>> Links - 509
+[link](/url 'title "and" title')
+<<<
+<p><a href="/url" title="title "and" title">link</a></p>
+>>> Links - 510
+[link]( /uri
+ "title" )
+<<<
+<p><a href="/uri" title="title">link</a></p>
+>>> Links - 511
+[link] (/uri)
+<<<
+<p>[link] (/uri)</p>
+>>> Links - 512
+[link [foo [bar]]](/uri)
+<<<
+<p><a href="/uri">link [foo [bar]]</a></p>
+>>> Links - 513
+[link] bar](/uri)
+<<<
+<p>[link] bar](/uri)</p>
+>>> Links - 514
+[link [bar](/uri)
+<<<
+<p>[link <a href="/uri">bar</a></p>
+>>> Links - 515
+[link \[bar](/uri)
+<<<
+<p><a href="/uri">link [bar</a></p>
+>>> Links - 516
+[link *foo **bar** `#`*](/uri)
+<<<
+<p><a href="/uri">link <em>foo <strong>bar</strong> <code>#</code></em></a></p>
+>>> Links - 517
+[](/uri)
+<<<
+<p><a href="/uri"><img src="moon.jpg" alt="moon" /></a></p>
+>>> Links - 518
+[foo [bar](/uri)](/uri)
+<<<
+<p>[foo <a href="/uri">bar</a>](/uri)</p>
+>>> Links - 519
+[foo *[bar [baz](/uri)](/uri)*](/uri)
+<<<
+<p>[foo <em>[bar <a href="/uri">baz</a>](/uri)</em>](/uri)</p>
+>>> Links - 520
+](uri2)](uri3)
+<<<
+<p><img src="uri3" alt="[foo](uri2)" /></p>
+>>> Links - 521
+*[foo*](/uri)
+<<<
+<p>*<a href="/uri">foo*</a></p>
+>>> Links - 522
+[foo *bar](baz*)
+<<<
+<p><a href="baz*">foo *bar</a></p>
+>>> Links - 523
+*foo [bar* baz]
+<<<
+<p><em>foo [bar</em> baz]</p>
+>>> Links - 524
+[foo <bar attr="](baz)">
+<<<
+<p>[foo <bar attr="](baz)"></p>
+>>> Links - 525
+[foo`](/uri)`
+<<<
+<p>[foo<code>](/uri)</code></p>
+>>> Links - 526
+[foo<https://example.com/?search=](uri)>
+<<<
+<p>[foo<a href="https://example.com/?search=%5D(uri)">https://example.com/?search=](uri)</a></p>
+>>> Links - 527
+[foo][bar]
+
+[bar]: /url "title"
+<<<
+<p><a href="/url" title="title">foo</a></p>
+>>> Links - 528
+[link [foo [bar]]][ref]
+
+[ref]: /uri
+<<<
+<p><a href="/uri">link [foo [bar]]</a></p>
+>>> Links - 529
+[link \[bar][ref]
+
+[ref]: /uri
+<<<
+<p><a href="/uri">link [bar</a></p>
+>>> Links - 530
+[link *foo **bar** `#`*][ref]
+
+[ref]: /uri
+<<<
+<p><a href="/uri">link <em>foo <strong>bar</strong> <code>#</code></em></a></p>
+>>> Links - 531
+[][ref]
+
+[ref]: /uri
+<<<
+<p><a href="/uri"><img src="moon.jpg" alt="moon" /></a></p>
+>>> Links - 532
+[foo [bar](/uri)][ref]
+
+[ref]: /uri
+<<<
+<p>[foo <a href="/uri">bar</a>]<a href="/uri">ref</a></p>
+>>> Links - 533
+[foo *bar [baz][ref]*][ref]
+
+[ref]: /uri
+<<<
+<p>[foo <em>bar <a href="/uri">baz</a></em>]<a href="/uri">ref</a></p>
+>>> Links - 534
+*[foo*][ref]
+
+[ref]: /uri
+<<<
+<p>*<a href="/uri">foo*</a></p>
+>>> Links - 535
+[foo *bar][ref]*
+
+[ref]: /uri
+<<<
+<p><a href="/uri">foo *bar</a>*</p>
+>>> Links - 536
+[foo <bar attr="][ref]">
+
+[ref]: /uri
+<<<
+<p>[foo <bar attr="][ref]"></p>
+>>> Links - 537
+[foo`][ref]`
+
+[ref]: /uri
+<<<
+<p>[foo<code>][ref]</code></p>
+>>> Links - 538
+[foo<https://example.com/?search=][ref]>
+
+[ref]: /uri
+<<<
+<p>[foo<a href="https://example.com/?search=%5D%5Bref%5D">https://example.com/?search=][ref]</a></p>
+>>> Links - 539
+[foo][BaR]
+
+[bar]: /url "title"
+<<<
+<p><a href="/url" title="title">foo</a></p>
+>>> Links - 540
+[ẞ]
+
+[SS]: /url
+<<<
+<p><a href="/url">ẞ</a></p>
+>>> Links - 541
+[Foo
+ bar]: /url
+
+[Baz][Foo bar]
+<<<
+<p><a href="/url">Baz</a></p>
+>>> Links - 542
+[foo] [bar]
+
+[bar]: /url "title"
+<<<
+<p>[foo] <a href="/url" title="title">bar</a></p>
+>>> Links - 543
+[foo]
+[bar]
+
+[bar]: /url "title"
+<<<
+<p>[foo]
+<a href="/url" title="title">bar</a></p>
+>>> Links - 544
+[foo]: /url1
+
+[foo]: /url2
+
+[bar][foo]
+<<<
+<p><a href="/url1">bar</a></p>
+>>> Links - 545
+[bar][foo\!]
+
+[foo!]: /url
+<<<
+<p>[bar][foo!]</p>
+>>> Links - 546
+[foo][ref[]
+
+[ref[]: /uri
+<<<
+<p>[foo][ref[]</p>
+<p>[ref[]: /uri</p>
+>>> Links - 547
+[foo][ref[bar]]
+
+[ref[bar]]: /uri
+<<<
+<p>[foo][ref[bar]]</p>
+<p>[ref[bar]]: /uri</p>
+>>> Links - 548
+[[[foo]]]
+
+[[[foo]]]: /url
+<<<
+<p>[[[foo]]]</p>
+<p>[[[foo]]]: /url</p>
+>>> Links - 549
+[foo][ref\[]
+
+[ref\[]: /uri
+<<<
+<p><a href="/uri">foo</a></p>
+>>> Links - 550
+[bar\\]: /uri
+
+[bar\\]
+<<<
+<p><a href="/uri">bar\</a></p>
+>>> Links - 551
+[]
+
+[]: /uri
+<<<
+<p>[]</p>
+<p>[]: /uri</p>
+>>> Links - 552
+[
+ ]
+
+[
+ ]: /uri
+<<<
+<p>[
+]</p>
+<p>[
+]: /uri</p>
+>>> Links - 553
+[foo][]
+
+[foo]: /url "title"
+<<<
+<p><a href="/url" title="title">foo</a></p>
+>>> Links - 554
+[*foo* bar][]
+
+[*foo* bar]: /url "title"
+<<<
+<p><a href="/url" title="title"><em>foo</em> bar</a></p>
+>>> Links - 555
+[Foo][]
+
+[foo]: /url "title"
+<<<
+<p><a href="/url" title="title">Foo</a></p>
+>>> Links - 556
+[foo]
+[]
+
+[foo]: /url "title"
+<<<
+<p><a href="/url" title="title">foo</a>
+[]</p>
+>>> Links - 557
+[foo]
+
+[foo]: /url "title"
+<<<
+<p><a href="/url" title="title">foo</a></p>
+>>> Links - 558
+[*foo* bar]
+
+[*foo* bar]: /url "title"
+<<<
+<p><a href="/url" title="title"><em>foo</em> bar</a></p>
+>>> Links - 559
+[[*foo* bar]]
+
+[*foo* bar]: /url "title"
+<<<
+<p>[<a href="/url" title="title"><em>foo</em> bar</a>]</p>
+>>> Links - 560
+[[bar [foo]
+
+[foo]: /url
+<<<
+<p>[[bar <a href="/url">foo</a></p>
+>>> Links - 561
+[Foo]
+
+[foo]: /url "title"
+<<<
+<p><a href="/url" title="title">Foo</a></p>
+>>> Links - 562
+[foo] bar
+
+[foo]: /url
+<<<
+<p><a href="/url">foo</a> bar</p>
+>>> Links - 563
+\[foo]
+
+[foo]: /url "title"
+<<<
+<p>[foo]</p>
+>>> Links - 564
+[foo*]: /url
+
+*[foo*]
+<<<
+<p>*<a href="/url">foo*</a></p>
+>>> Links - 565
+[foo][bar]
+
+[foo]: /url1
+[bar]: /url2
+<<<
+<p><a href="/url2">foo</a></p>
+>>> Links - 566
+[foo][]
+
+[foo]: /url1
+<<<
+<p><a href="/url1">foo</a></p>
+>>> Links - 567
+[foo]()
+
+[foo]: /url1
+<<<
+<p><a href="">foo</a></p>
+>>> Links - 568
+[foo](not a link)
+
+[foo]: /url1
+<<<
+<p><a href="/url1">foo</a>(not a link)</p>
+>>> Links - 569
+[foo][bar][baz]
+
+[baz]: /url
+<<<
+<p>[foo]<a href="/url">bar</a></p>
+>>> Links - 570
+[foo][bar][baz]
+
+[baz]: /url1
+[bar]: /url2
+<<<
+<p><a href="/url2">foo</a><a href="/url1">baz</a></p>
+>>> Links - 571
+[foo][bar][baz]
+
+[baz]: /url1
+[foo]: /url2
+<<<
+<p>[foo]<a href="/url1">bar</a></p>
diff --git a/pkgs/markdown/test/common_mark/list_items.unit b/pkgs/markdown/test/common_mark/list_items.unit
new file mode 100644
index 0000000..46162a9
--- /dev/null
+++ b/pkgs/markdown/test/common_mark/list_items.unit
@@ -0,0 +1,586 @@
+>>> List items - 253
+A paragraph
+with two lines.
+
+ indented code
+
+> A block quote.
+<<<
+<p>A paragraph
+with two lines.</p>
+<pre><code>indented code
+</code></pre>
+<blockquote>
+<p>A block quote.</p>
+</blockquote>
+>>> List items - 254
+1. A paragraph
+ with two lines.
+
+ indented code
+
+ > A block quote.
+<<<
+<ol>
+<li>
+<p>A paragraph
+with two lines.</p>
+<pre><code>indented code
+</code></pre>
+<blockquote>
+<p>A block quote.</p>
+</blockquote>
+</li>
+</ol>
+>>> List items - 255
+- one
+
+ two
+<<<
+<ul>
+<li>one</li>
+</ul>
+<p>two</p>
+>>> List items - 256
+- one
+
+ two
+<<<
+<ul>
+<li>
+<p>one</p>
+<p>two</p>
+</li>
+</ul>
+>>> List items - 257
+ - one
+
+ two
+<<<
+<ul>
+<li>one</li>
+</ul>
+<pre><code> two
+</code></pre>
+>>> List items - 258
+ - one
+
+ two
+<<<
+<ul>
+<li>
+<p>one</p>
+<p>two</p>
+</li>
+</ul>
+>>> List items - 259
+ > > 1. one
+>>
+>> two
+<<<
+<blockquote>
+<blockquote>
+<ol>
+<li>
+<p>one</p>
+<p>two</p>
+</li>
+</ol>
+</blockquote>
+</blockquote>
+>>> List items - 260
+>>- one
+>>
+ > > two
+<<<
+<blockquote>
+<blockquote>
+<ul>
+<li>one</li>
+</ul>
+<p>two</p>
+</blockquote>
+</blockquote>
+>>> List items - 261
+-one
+
+2.two
+<<<
+<p>-one</p>
+<p>2.two</p>
+>>> List items - 262
+- foo
+
+
+ bar
+<<<
+<ul>
+<li>
+<p>foo</p>
+<p>bar</p>
+</li>
+</ul>
+>>> List items - 263
+1. foo
+
+ ```
+ bar
+ ```
+
+ baz
+
+ > bam
+<<<
+<ol>
+<li>
+<p>foo</p>
+<pre><code>bar
+</code></pre>
+<p>baz</p>
+<blockquote>
+<p>bam</p>
+</blockquote>
+</li>
+</ol>
+>>> List items - 264
+- Foo
+
+ bar
+
+
+ baz
+<<<
+<ul>
+<li>
+<p>Foo</p>
+<pre><code>bar
+
+
+baz
+</code></pre>
+</li>
+</ul>
+>>> List items - 265
+123456789. ok
+<<<
+<ol start="123456789">
+<li>ok</li>
+</ol>
+>>> List items - 266
+1234567890. not ok
+<<<
+<p>1234567890. not ok</p>
+>>> List items - 267
+0. ok
+<<<
+<ol start="0">
+<li>ok</li>
+</ol>
+>>> List items - 268
+003. ok
+<<<
+<ol start="3">
+<li>ok</li>
+</ol>
+>>> List items - 269
+-1. not ok
+<<<
+<p>-1. not ok</p>
+>>> List items - 270
+- foo
+
+ bar
+<<<
+<ul>
+<li>
+<p>foo</p>
+<pre><code>bar
+</code></pre>
+</li>
+</ul>
+>>> List items - 271
+ 10. foo
+
+ bar
+<<<
+<ol start="10">
+<li>
+<p>foo</p>
+<pre><code>bar
+</code></pre>
+</li>
+</ol>
+>>> List items - 272
+ indented code
+
+paragraph
+
+ more code
+<<<
+<pre><code>indented code
+</code></pre>
+<p>paragraph</p>
+<pre><code>more code
+</code></pre>
+>>> List items - 273
+1. indented code
+
+ paragraph
+
+ more code
+<<<
+<ol>
+<li>
+<pre><code>indented code
+</code></pre>
+<p>paragraph</p>
+<pre><code>more code
+</code></pre>
+</li>
+</ol>
+>>> List items - 274
+1. indented code
+
+ paragraph
+
+ more code
+<<<
+<ol>
+<li>
+<pre><code> indented code
+</code></pre>
+<p>paragraph</p>
+<pre><code>more code
+</code></pre>
+</li>
+</ol>
+>>> List items - 275
+ foo
+
+bar
+<<<
+<p>foo</p>
+<p>bar</p>
+>>> List items - 276
+- foo
+
+ bar
+<<<
+<ul>
+<li>foo</li>
+</ul>
+<p>bar</p>
+>>> List items - 277
+- foo
+
+ bar
+<<<
+<ul>
+<li>
+<p>foo</p>
+<p>bar</p>
+</li>
+</ul>
+>>> List items - 278
+-
+ foo
+-
+ ```
+ bar
+ ```
+-
+ baz
+<<<
+<ul>
+<li>foo</li>
+<li>
+<pre><code>bar
+</code></pre>
+</li>
+<li>
+<pre><code>baz
+</code></pre>
+</li>
+</ul>
+>>> List items - 279
+-
+ foo
+<<<
+<ul>
+<li>foo</li>
+</ul>
+>>> List items - 280
+-
+
+ foo
+<<<
+<ul>
+<li></li>
+</ul>
+<p>foo</p>
+>>> List items - 281
+- foo
+-
+- bar
+<<<
+<ul>
+<li>foo</li>
+<li></li>
+<li>bar</li>
+</ul>
+>>> List items - 282
+- foo
+-
+- bar
+<<<
+<ul>
+<li>foo</li>
+<li></li>
+<li>bar</li>
+</ul>
+>>> List items - 283
+1. foo
+2.
+3. bar
+<<<
+<ol>
+<li>foo</li>
+<li></li>
+<li>bar</li>
+</ol>
+>>> List items - 284
+*
+<<<
+<ul>
+<li></li>
+</ul>
+>>> List items - 285
+foo
+*
+
+foo
+1.
+<<<
+<p>foo
+*</p>
+<p>foo
+1.</p>
+>>> List items - 286
+ 1. A paragraph
+ with two lines.
+
+ indented code
+
+ > A block quote.
+<<<
+<ol>
+<li>
+<p>A paragraph
+with two lines.</p>
+<pre><code>indented code
+</code></pre>
+<blockquote>
+<p>A block quote.</p>
+</blockquote>
+</li>
+</ol>
+>>> List items - 287
+ 1. A paragraph
+ with two lines.
+
+ indented code
+
+ > A block quote.
+<<<
+<ol>
+<li>
+<p>A paragraph
+with two lines.</p>
+<pre><code>indented code
+</code></pre>
+<blockquote>
+<p>A block quote.</p>
+</blockquote>
+</li>
+</ol>
+>>> List items - 288
+ 1. A paragraph
+ with two lines.
+
+ indented code
+
+ > A block quote.
+<<<
+<ol>
+<li>
+<p>A paragraph
+with two lines.</p>
+<pre><code>indented code
+</code></pre>
+<blockquote>
+<p>A block quote.</p>
+</blockquote>
+</li>
+</ol>
+>>> List items - 289
+ 1. A paragraph
+ with two lines.
+
+ indented code
+
+ > A block quote.
+<<<
+<pre><code>1. A paragraph
+ with two lines.
+
+ indented code
+
+ > A block quote.
+</code></pre>
+>>> List items - 290
+ 1. A paragraph
+with two lines.
+
+ indented code
+
+ > A block quote.
+<<<
+<ol>
+<li>
+<p>A paragraph
+with two lines.</p>
+<pre><code>indented code
+</code></pre>
+<blockquote>
+<p>A block quote.</p>
+</blockquote>
+</li>
+</ol>
+>>> List items - 291
+ 1. A paragraph
+ with two lines.
+<<<
+<ol>
+<li>A paragraph
+with two lines.</li>
+</ol>
+>>> List items - 292
+> 1. > Blockquote
+continued here.
+<<<
+<blockquote>
+<ol>
+<li>
+<blockquote>
+<p>Blockquote
+continued here.</p>
+</blockquote>
+</li>
+</ol>
+</blockquote>
+>>> List items - 293
+> 1. > Blockquote
+> continued here.
+<<<
+<blockquote>
+<ol>
+<li>
+<blockquote>
+<p>Blockquote
+continued here.</p>
+</blockquote>
+</li>
+</ol>
+</blockquote>
+>>> List items - 294
+- foo
+ - bar
+ - baz
+ - boo
+<<<
+<ul>
+<li>foo
+<ul>
+<li>bar
+<ul>
+<li>baz
+<ul>
+<li>boo</li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+>>> List items - 295
+- foo
+ - bar
+ - baz
+ - boo
+<<<
+<ul>
+<li>foo</li>
+<li>bar</li>
+<li>baz</li>
+<li>boo</li>
+</ul>
+>>> List items - 296
+10) foo
+ - bar
+<<<
+<ol start="10">
+<li>foo
+<ul>
+<li>bar</li>
+</ul>
+</li>
+</ol>
+>>> List items - 297
+10) foo
+ - bar
+<<<
+<ol start="10">
+<li>foo</li>
+</ol>
+<ul>
+<li>bar</li>
+</ul>
+>>> List items - 298
+- - foo
+<<<
+<ul>
+<li>
+<ul>
+<li>foo</li>
+</ul>
+</li>
+</ul>
+>>> List items - 299
+1. - 2. foo
+<<<
+<ol>
+<li>
+<ul>
+<li>
+<ol start="2">
+<li>foo</li>
+</ol>
+</li>
+</ul>
+</li>
+</ol>
+>>> List items - 300
+- # Foo
+- Bar
+ ---
+ baz
+<<<
+<ul>
+<li>
+<h1>Foo</h1>
+</li>
+<li>
+<h2>Bar</h2>
+baz</li>
+</ul>
diff --git a/pkgs/markdown/test/common_mark/lists.unit b/pkgs/markdown/test/common_mark/lists.unit
new file mode 100644
index 0000000..fce59fe
--- /dev/null
+++ b/pkgs/markdown/test/common_mark/lists.unit
@@ -0,0 +1,406 @@
+>>> Lists - 301
+- foo
+- bar
++ baz
+<<<
+<ul>
+<li>foo</li>
+<li>bar</li>
+</ul>
+<ul>
+<li>baz</li>
+</ul>
+>>> Lists - 302
+1. foo
+2. bar
+3) baz
+<<<
+<ol>
+<li>foo</li>
+<li>bar</li>
+</ol>
+<ol start="3">
+<li>baz</li>
+</ol>
+>>> Lists - 303
+Foo
+- bar
+- baz
+<<<
+<p>Foo</p>
+<ul>
+<li>bar</li>
+<li>baz</li>
+</ul>
+>>> Lists - 304
+The number of windows in my house is
+14. The number of doors is 6.
+<<<
+<p>The number of windows in my house is
+14. The number of doors is 6.</p>
+>>> Lists - 305
+The number of windows in my house is
+1. The number of doors is 6.
+<<<
+<p>The number of windows in my house is</p>
+<ol>
+<li>The number of doors is 6.</li>
+</ol>
+>>> Lists - 306
+- foo
+
+- bar
+
+
+- baz
+<<<
+<ul>
+<li>
+<p>foo</p>
+</li>
+<li>
+<p>bar</p>
+</li>
+<li>
+<p>baz</p>
+</li>
+</ul>
+>>> Lists - 307
+- foo
+ - bar
+ - baz
+
+
+ bim
+<<<
+<ul>
+<li>foo
+<ul>
+<li>bar
+<ul>
+<li>
+<p>baz</p>
+<p>bim</p>
+</li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+>>> Lists - 308
+- foo
+- bar
+
+<!-- -->
+
+- baz
+- bim
+<<<
+<ul>
+<li>foo</li>
+<li>bar</li>
+</ul>
+<!-- -->
+<ul>
+<li>baz</li>
+<li>bim</li>
+</ul>
+>>> Lists - 309
+- foo
+
+ notcode
+
+- foo
+
+<!-- -->
+
+ code
+<<<
+<ul>
+<li>
+<p>foo</p>
+<p>notcode</p>
+</li>
+<li>
+<p>foo</p>
+</li>
+</ul>
+<!-- -->
+<pre><code>code
+</code></pre>
+>>> Lists - 310
+- a
+ - b
+ - c
+ - d
+ - e
+ - f
+- g
+<<<
+<ul>
+<li>a</li>
+<li>b</li>
+<li>c</li>
+<li>d</li>
+<li>e</li>
+<li>f</li>
+<li>g</li>
+</ul>
+>>> Lists - 311
+1. a
+
+ 2. b
+
+ 3. c
+<<<
+<ol>
+<li>
+<p>a</p>
+</li>
+<li>
+<p>b</p>
+</li>
+<li>
+<p>c</p>
+</li>
+</ol>
+>>> Lists - 312
+- a
+ - b
+ - c
+ - d
+ - e
+<<<
+<ul>
+<li>a</li>
+<li>b</li>
+<li>c</li>
+<li>d
+- e</li>
+</ul>
+>>> Lists - 313
+1. a
+
+ 2. b
+
+ 3. c
+<<<
+<ol>
+<li>
+<p>a</p>
+</li>
+<li>
+<p>b</p>
+</li>
+</ol>
+<pre><code>3. c
+</code></pre>
+>>> Lists - 314
+- a
+- b
+
+- c
+<<<
+<ul>
+<li>
+<p>a</p>
+</li>
+<li>
+<p>b</p>
+</li>
+<li>
+<p>c</p>
+</li>
+</ul>
+>>> Lists - 315
+* a
+*
+
+* c
+<<<
+<ul>
+<li>
+<p>a</p>
+</li>
+<li></li>
+<li>
+<p>c</p>
+</li>
+</ul>
+>>> Lists - 316
+- a
+- b
+
+ c
+- d
+<<<
+<ul>
+<li>
+<p>a</p>
+</li>
+<li>
+<p>b</p>
+<p>c</p>
+</li>
+<li>
+<p>d</p>
+</li>
+</ul>
+>>> Lists - 317
+- a
+- b
+
+ [ref]: /url
+- d
+<<<
+<ul>
+<li>
+<p>a</p>
+</li>
+<li>
+<p>b</p>
+</li>
+<li>
+<p>d</p>
+</li>
+</ul>
+>>> Lists - 318
+- a
+- ```
+ b
+
+
+ ```
+- c
+<<<
+<ul>
+<li>a</li>
+<li>
+<pre><code>b
+
+
+</code></pre>
+</li>
+<li>c</li>
+</ul>
+>>> Lists - 319
+- a
+ - b
+
+ c
+- d
+<<<
+<ul>
+<li>a
+<ul>
+<li>
+<p>b</p>
+<p>c</p>
+</li>
+</ul>
+</li>
+<li>d</li>
+</ul>
+>>> Lists - 320
+* a
+ > b
+ >
+* c
+<<<
+<ul>
+<li>a
+<blockquote>
+<p>b</p>
+</blockquote>
+</li>
+<li>c</li>
+</ul>
+>>> Lists - 321
+- a
+ > b
+ ```
+ c
+ ```
+- d
+<<<
+<ul>
+<li>a
+<blockquote>
+<p>b</p>
+</blockquote>
+<pre><code>c
+</code></pre>
+</li>
+<li>d</li>
+</ul>
+>>> Lists - 322
+- a
+<<<
+<ul>
+<li>a</li>
+</ul>
+>>> Lists - 323
+- a
+ - b
+<<<
+<ul>
+<li>a
+<ul>
+<li>b</li>
+</ul>
+</li>
+</ul>
+>>> Lists - 324
+1. ```
+ foo
+ ```
+
+ bar
+<<<
+<ol>
+<li>
+<pre><code>foo
+</code></pre>
+<p>bar</p>
+</li>
+</ol>
+>>> Lists - 325
+* foo
+ * bar
+
+ baz
+<<<
+<ul>
+<li>
+<p>foo</p>
+<ul>
+<li>bar</li>
+</ul>
+<p>baz</p>
+</li>
+</ul>
+>>> Lists - 326
+- a
+ - b
+ - c
+
+- d
+ - e
+ - f
+<<<
+<ul>
+<li>
+<p>a</p>
+<ul>
+<li>b</li>
+<li>c</li>
+</ul>
+</li>
+<li>
+<p>d</p>
+<ul>
+<li>e</li>
+<li>f</li>
+</ul>
+</li>
+</ul>
diff --git a/pkgs/markdown/test/common_mark/paragraphs.unit b/pkgs/markdown/test/common_mark/paragraphs.unit
new file mode 100644
index 0000000..a03f4a1
--- /dev/null
+++ b/pkgs/markdown/test/common_mark/paragraphs.unit
@@ -0,0 +1,59 @@
+>>> Paragraphs - 219
+aaa
+
+bbb
+<<<
+<p>aaa</p>
+<p>bbb</p>
+>>> Paragraphs - 220
+aaa
+bbb
+
+ccc
+ddd
+<<<
+<p>aaa
+bbb</p>
+<p>ccc
+ddd</p>
+>>> Paragraphs - 221
+aaa
+
+
+bbb
+<<<
+<p>aaa</p>
+<p>bbb</p>
+>>> Paragraphs - 222
+ aaa
+ bbb
+<<<
+<p>aaa
+bbb</p>
+>>> Paragraphs - 223
+aaa
+ bbb
+ ccc
+<<<
+<p>aaa
+bbb
+ccc</p>
+>>> Paragraphs - 224
+ aaa
+bbb
+<<<
+<p>aaa
+bbb</p>
+>>> Paragraphs - 225
+ aaa
+bbb
+<<<
+<pre><code>aaa
+</code></pre>
+<p>bbb</p>
+>>> Paragraphs - 226
+aaa
+bbb
+<<<
+<p>aaa<br />
+bbb</p>
diff --git a/pkgs/markdown/test/common_mark/precedence.unit b/pkgs/markdown/test/common_mark/precedence.unit
new file mode 100644
index 0000000..4359ce9
--- /dev/null
+++ b/pkgs/markdown/test/common_mark/precedence.unit
@@ -0,0 +1,8 @@
+>>> Precedence - 42
+- `one
+- two`
+<<<
+<ul>
+<li>`one</li>
+<li>two`</li>
+</ul>
diff --git a/pkgs/markdown/test/common_mark/raw_html.unit b/pkgs/markdown/test/common_mark/raw_html.unit
new file mode 100644
index 0000000..329f96a
--- /dev/null
+++ b/pkgs/markdown/test/common_mark/raw_html.unit
@@ -0,0 +1,95 @@
+>>> Raw HTML - 613
+<a><bab><c2c>
+<<<
+<p><a><bab><c2c></p>
+>>> Raw HTML - 614
+<a/><b2/>
+<<<
+<p><a/><b2/></p>
+>>> Raw HTML - 615
+<a /><b2
+data="foo" >
+<<<
+<p><a /><b2
+data="foo" ></p>
+>>> Raw HTML - 616
+<a foo="bar" bam = 'baz <em>"</em>'
+_boolean zoop:33=zoop:33 />
+<<<
+<p><a foo="bar" bam = 'baz <em>"</em>'
+_boolean zoop:33=zoop:33 /></p>
+>>> Raw HTML - 617
+Foo <responsive-image src="foo.jpg" />
+<<<
+<p>Foo <responsive-image src="foo.jpg" /></p>
+>>> Raw HTML - 618
+<33> <__>
+<<<
+<p><33> <__></p>
+>>> Raw HTML - 619
+<a h*#ref="hi">
+<<<
+<p><a h*#ref="hi"></p>
+>>> Raw HTML - 620
+<a href="hi'> <a href=hi'>
+<<<
+<p><a href="hi'> <a href=hi'></p>
+>>> Raw HTML - 621
+< a><
+foo><bar/ >
+<foo bar=baz
+bim!bop />
+<<<
+<p>< a><
+foo><bar/ >
+<foo bar=baz
+bim!bop /></p>
+>>> Raw HTML - 622
+<a href='bar'title=title>
+<<<
+<p><a href='bar'title=title></p>
+>>> Raw HTML - 623
+</a></foo >
+<<<
+<p></a></foo ></p>
+>>> Raw HTML - 624
+</a href="foo">
+<<<
+<p></a href="foo"></p>
+>>> Raw HTML - 625
+foo <!-- this is a --
+comment - with hyphens -->
+<<<
+<p>foo <!-- this is a --
+comment - with hyphens --></p>
+>>> Raw HTML - 626
+foo <!--> foo -->
+
+foo <!---> foo -->
+<<<
+<p>foo <!--> foo --></p>
+<p>foo <!---> foo --></p>
+>>> Raw HTML - 627
+foo <?php echo $a; ?>
+<<<
+<p>foo <?php echo $a; ?></p>
+>>> Raw HTML - 628
+foo <!ELEMENT br EMPTY>
+<<<
+<p>foo <!ELEMENT br EMPTY></p>
+>>> Raw HTML - 629
+foo <![CDATA[>&<]]>
+<<<
+<p>foo <![CDATA[>&<]]></p>
+>>> Raw HTML - 630
+foo <a href="ö">
+<<<
+<p>foo <a href="ö"></p>
+>>> Raw HTML - 631
+foo <a href="\*">
+<<<
+<p>foo <a href="\*"></p>
+>>> Raw HTML - 632
+<a href="\"">
+<<<
+<p><a href="""></p>
diff --git a/pkgs/markdown/test/common_mark/setext_headings.unit b/pkgs/markdown/test/common_mark/setext_headings.unit
new file mode 100644
index 0000000..702c72c
--- /dev/null
+++ b/pkgs/markdown/test/common_mark/setext_headings.unit
@@ -0,0 +1,229 @@
+>>> Setext headings - 80
+Foo *bar*
+=========
+
+Foo *bar*
+---------
+<<<
+<h1>Foo <em>bar</em></h1>
+<h2>Foo <em>bar</em></h2>
+>>> Setext headings - 81
+Foo *bar
+baz*
+====
+<<<
+<h1>Foo <em>bar
+baz</em></h1>
+>>> Setext headings - 82
+ Foo *bar
+baz*
+====
+<<<
+<h1> Foo <em>bar
+baz</em></h1>
+>>> Setext headings - 83
+Foo
+-------------------------
+
+Foo
+=
+<<<
+<h2>Foo</h2>
+<h1>Foo</h1>
+>>> Setext headings - 84
+ Foo
+---
+
+ Foo
+-----
+
+ Foo
+ ===
+<<<
+<h2> Foo</h2>
+<h2> Foo</h2>
+<h1> Foo</h1>
+>>> Setext headings - 85
+ Foo
+ ---
+
+ Foo
+---
+<<<
+<pre><code>Foo
+---
+
+Foo
+</code></pre>
+<hr />
+>>> Setext headings - 86
+Foo
+ ----
+<<<
+<h2>Foo</h2>
+>>> Setext headings - 87
+Foo
+ ---
+<<<
+<p>Foo
+---</p>
+>>> Setext headings - 88
+Foo
+= =
+
+Foo
+--- -
+<<<
+<p>Foo
+= =</p>
+<p>Foo</p>
+<hr />
+>>> Setext headings - 89
+Foo
+-----
+<<<
+<h2>Foo</h2>
+>>> Setext headings - 90
+Foo\
+----
+<<<
+<h2>Foo\</h2>
+>>> Setext headings - 91
+`Foo
+----
+`
+
+<a title="a lot
+---
+of dashes"/>
+<<<
+<h2>`Foo</h2>
+<p>`</p>
+<h2><a title="a lot</h2>
+<p>of dashes"/></p>
+>>> Setext headings - 92
+> Foo
+---
+<<<
+<blockquote>
+<p>Foo</p>
+</blockquote>
+<hr />
+>>> Setext headings - 93
+> foo
+bar
+===
+<<<
+<blockquote>
+<p>foo
+bar
+===</p>
+</blockquote>
+>>> Setext headings - 94
+- Foo
+---
+<<<
+<ul>
+<li>Foo</li>
+</ul>
+<hr />
+>>> Setext headings - 95
+Foo
+Bar
+---
+<<<
+<h2>Foo
+Bar</h2>
+>>> Setext headings - 96
+---
+Foo
+---
+Bar
+---
+Baz
+<<<
+<hr />
+<h2>Foo</h2>
+<h2>Bar</h2>
+<p>Baz</p>
+>>> Setext headings - 97
+
+====
+<<<
+<p>====</p>
+>>> Setext headings - 98
+---
+---
+<<<
+<hr />
+<hr />
+>>> Setext headings - 99
+- foo
+-----
+<<<
+<ul>
+<li>foo</li>
+</ul>
+<hr />
+>>> Setext headings - 100
+ foo
+---
+<<<
+<pre><code>foo
+</code></pre>
+<hr />
+>>> Setext headings - 101
+> foo
+-----
+<<<
+<blockquote>
+<p>foo</p>
+</blockquote>
+<hr />
+>>> Setext headings - 102
+\> foo
+------
+<<<
+<h2>> foo</h2>
+>>> Setext headings - 103
+Foo
+
+bar
+---
+baz
+<<<
+<p>Foo</p>
+<h2>bar</h2>
+<p>baz</p>
+>>> Setext headings - 104
+Foo
+bar
+
+---
+
+baz
+<<<
+<p>Foo
+bar</p>
+<hr />
+<p>baz</p>
+>>> Setext headings - 105
+Foo
+bar
+* * *
+baz
+<<<
+<p>Foo
+bar</p>
+<hr />
+<p>baz</p>
+>>> Setext headings - 106
+Foo
+bar
+\---
+baz
+<<<
+<p>Foo
+bar
+---
+baz</p>
diff --git a/pkgs/markdown/test/common_mark/soft_line_breaks.unit b/pkgs/markdown/test/common_mark/soft_line_breaks.unit
new file mode 100644
index 0000000..88e82f2
--- /dev/null
+++ b/pkgs/markdown/test/common_mark/soft_line_breaks.unit
@@ -0,0 +1,12 @@
+>>> Soft line breaks - 648
+foo
+baz
+<<<
+<p>foo
+baz</p>
+>>> Soft line breaks - 649
+foo
+ baz
+<<<
+<p>foo
+baz</p>
diff --git a/pkgs/markdown/test/common_mark/tabs.unit b/pkgs/markdown/test/common_mark/tabs.unit
new file mode 100644
index 0000000..1239481
--- /dev/null
+++ b/pkgs/markdown/test/common_mark/tabs.unit
@@ -0,0 +1,87 @@
+>>> Tabs - 1
+ foo baz bim
+<<<
+<pre><code>foo baz bim
+</code></pre>
+>>> Tabs - 2
+ foo baz bim
+<<<
+<pre><code>foo baz bim
+</code></pre>
+>>> Tabs - 3
+ a a
+ ὐ a
+<<<
+<pre><code>a a
+ὐ a
+</code></pre>
+>>> Tabs - 4
+ - foo
+
+ bar
+<<<
+<ul>
+<li>
+<p>foo</p>
+<p>bar</p>
+</li>
+</ul>
+>>> Tabs - 5
+- foo
+
+ bar
+<<<
+<ul>
+<li>
+<p>foo</p>
+<pre><code> bar
+</code></pre>
+</li>
+</ul>
+>>> Tabs - 6
+> foo
+<<<
+<blockquote>
+<pre><code>foo
+</code></pre>
+</blockquote>
+>>> Tabs - 7
+- foo
+<<<
+<ul>
+<li>
+<pre><code> foo
+</code></pre>
+</li>
+</ul>
+>>> Tabs - 8
+ foo
+ bar
+<<<
+<pre><code>foo
+bar
+</code></pre>
+>>> Tabs - 9
+ - foo
+ - bar
+ - baz
+<<<
+<ul>
+<li>foo
+<ul>
+<li>bar
+<ul>
+<li>baz</li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+>>> Tabs - 10
+# Foo
+<<<
+<h1>Foo</h1>
+>>> Tabs - 11
+* * *
+<<<
+<hr />
diff --git a/pkgs/markdown/test/common_mark/textual_content.unit b/pkgs/markdown/test/common_mark/textual_content.unit
new file mode 100644
index 0000000..0069e0f
--- /dev/null
+++ b/pkgs/markdown/test/common_mark/textual_content.unit
@@ -0,0 +1,12 @@
+>>> Textual content - 650
+hello $.;'there
+<<<
+<p>hello $.;'there</p>
+>>> Textual content - 651
+Foo χρῆν
+<<<
+<p>Foo χρῆν</p>
+>>> Textual content - 652
+Multiple spaces
+<<<
+<p>Multiple spaces</p>
diff --git a/pkgs/markdown/test/common_mark/thematic_breaks.unit b/pkgs/markdown/test/common_mark/thematic_breaks.unit
new file mode 100644
index 0000000..b4d490f
--- /dev/null
+++ b/pkgs/markdown/test/common_mark/thematic_breaks.unit
@@ -0,0 +1,126 @@
+>>> Thematic breaks - 43
+***
+---
+___
+<<<
+<hr />
+<hr />
+<hr />
+>>> Thematic breaks - 44
++++
+<<<
+<p>+++</p>
+>>> Thematic breaks - 45
+===
+<<<
+<p>===</p>
+>>> Thematic breaks - 46
+--
+**
+__
+<<<
+<p>--
+**
+__</p>
+>>> Thematic breaks - 47
+ ***
+ ***
+ ***
+<<<
+<hr />
+<hr />
+<hr />
+>>> Thematic breaks - 48
+ ***
+<<<
+<pre><code>***
+</code></pre>
+>>> Thematic breaks - 49
+Foo
+ ***
+<<<
+<p>Foo
+***</p>
+>>> Thematic breaks - 50
+_____________________________________
+<<<
+<hr />
+>>> Thematic breaks - 51
+ - - -
+<<<
+<hr />
+>>> Thematic breaks - 52
+ ** * ** * ** * **
+<<<
+<hr />
+>>> Thematic breaks - 53
+- - - -
+<<<
+<hr />
+>>> Thematic breaks - 54
+- - - -
+<<<
+<hr />
+>>> Thematic breaks - 55
+_ _ _ _ a
+
+a------
+
+---a---
+<<<
+<p>_ _ _ _ a</p>
+<p>a------</p>
+<p>---a---</p>
+>>> Thematic breaks - 56
+ *-*
+<<<
+<p><em>-</em></p>
+>>> Thematic breaks - 57
+- foo
+***
+- bar
+<<<
+<ul>
+<li>foo</li>
+</ul>
+<hr />
+<ul>
+<li>bar</li>
+</ul>
+>>> Thematic breaks - 58
+Foo
+***
+bar
+<<<
+<p>Foo</p>
+<hr />
+<p>bar</p>
+>>> Thematic breaks - 59
+Foo
+---
+bar
+<<<
+<h2>Foo</h2>
+<p>bar</p>
+>>> Thematic breaks - 60
+* Foo
+* * *
+* Bar
+<<<
+<ul>
+<li>Foo</li>
+</ul>
+<hr />
+<ul>
+<li>Bar</li>
+</ul>
+>>> Thematic breaks - 61
+- Foo
+- * * *
+<<<
+<ul>
+<li>Foo</li>
+<li>
+<hr />
+</li>
+</ul>
diff --git a/pkgs/markdown/test/crash_test.dart b/pkgs/markdown/test/crash_test.dart
new file mode 100644
index 0000000..a6f427d
--- /dev/null
+++ b/pkgs/markdown/test/crash_test.dart
@@ -0,0 +1,226 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert';
+import 'dart:io';
+import 'dart:isolate';
+
+import 'package:http/http.dart' as http;
+import 'package:http/retry.dart' as http;
+import 'package:markdown/markdown.dart';
+import 'package:pool/pool.dart';
+import 'package:tar/tar.dart';
+import 'package:test/test.dart';
+
+// ignore_for_file: avoid_dynamic_calls
+
+const extensions = [
+ '.md',
+ '.mkd',
+ '.mdwn',
+ '.mdown',
+ '.mdtxt',
+ '.mdtext',
+ '.markdown',
+ 'README',
+ 'CHANGELOG',
+];
+
+void main() async {
+ // This test is a really dumb and very slow crash-test.
+ // It downloads the latest package version for each package on pub.dev
+ // and tries to parse all `*.md` files in the package, counting the number
+ // of times where the parser throws.
+ //
+ // Needless to say, this test is very slow and running it eats a lot of CPU.
+ // But it's a fairly good way to try a lot of real-world markdown text to see
+ // if any of the poorly formatted markdown causes the parser to crash.
+ test(
+ 'crash test',
+ () async {
+ final started = DateTime.now();
+ var lastStatus = DateTime(0);
+ void status(String Function() message) {
+ if (DateTime.now().difference(lastStatus) >
+ const Duration(seconds: 30)) {
+ lastStatus = DateTime.now();
+ print(message());
+ }
+ }
+
+ final c = http.RetryClient(http.Client());
+ Future<dynamic> getJson(String url) async {
+ final u = Uri.tryParse(url);
+ if (u == null) {
+ return null;
+ }
+ try {
+ final data = await c.read(u);
+ try {
+ return jsonDecode(data);
+ } on FormatException {
+ return null;
+ }
+ } on http.ClientException {
+ return null;
+ } on IOException {
+ return null;
+ }
+ }
+
+ final packages =
+ ((await getJson('https://pub.dev/api/package-names'))['packages']
+ as List)
+ .cast<String>();
+ //.take(3).toList(); // useful when testing
+ print('## Found ${packages.length} packages to scan');
+
+ var count = 0;
+ final pool = Pool(50);
+ final packageVersions = <PackageVersion>[];
+ await Future.wait(packages.map((package) async {
+ await pool.withResource(() async {
+ final response = await getJson(
+ 'https://pub.dev/api/packages/$package',
+ );
+ final entry = response['latest'] as Map?;
+ if (entry != null) {
+ packageVersions.add(PackageVersion(
+ package: package,
+ version: entry['version'] as String,
+ archiveUrl: entry['archive_url'] as String,
+ ));
+ }
+ count++;
+ status(
+ () => 'Listed versions for $count / ${packages.length} packages',
+ );
+ });
+ }));
+
+ print('## Found ${packageVersions.length} package versions to scan');
+
+ count = 0;
+ final errors = <String>[];
+ var skipped = 0;
+ await Future.wait(packageVersions.map((pv) async {
+ await pool.withResource(() async {
+ final archiveUrl = Uri.tryParse(pv.archiveUrl);
+ if (archiveUrl == null) {
+ skipped++;
+ return;
+ }
+ late List<int> archive;
+ try {
+ archive = await c.readBytes(archiveUrl);
+ } on http.ClientException {
+ skipped++;
+ return;
+ } on IOException {
+ skipped++;
+ return;
+ }
+
+ final result = await _findMarkdownIssues(
+ pv.package,
+ pv.version,
+ archive,
+ );
+
+ // If tar decoding fails.
+ if (result == null) {
+ skipped++;
+ return;
+ }
+
+ errors.addAll(result);
+ result.forEach(print);
+ });
+ count++;
+ status(() =>
+ 'Scanned $count / ${packageVersions.length} (skipped $skipped),'
+ ' found ${errors.length} issues');
+ }));
+
+ await pool.close();
+ c.close();
+
+ print('## Finished scanning');
+ print('Scanned ${packageVersions.length} package versions in '
+ '${DateTime.now().difference(started)}');
+
+ if (errors.isNotEmpty) {
+ print('Found issues:');
+ errors.forEach(print);
+ fail('Found ${errors.length} cases where markdownToHtml threw!');
+ }
+ },
+ timeout: const Timeout(Duration(hours: 5)),
+ tags: 'crash_test', // skipped by default, see: dart_test.yaml
+ );
+}
+
+class PackageVersion {
+ final String package;
+ final String version;
+ final String archiveUrl;
+
+ PackageVersion({
+ required this.package,
+ required this.version,
+ required this.archiveUrl,
+ });
+}
+
+/// Scans [gzippedArchive] for markdown files and tries to parse them all.
+///
+/// Creates a list of issues that arose when parsing markdown files. The
+/// [package] and [version] strings are used to construct nice issues.
+/// An issue string may be multi-line, but should be printable.
+///
+/// Returns a list of issues, or `null` if decoding and parsing [gzippedArchive]
+/// failed.
+Future<List<String>?> _findMarkdownIssues(
+ String package,
+ String version,
+ List<int> gzippedArchive,
+) async {
+ return Isolate.run<List<String>?>(() async {
+ try {
+ final archive = gzip.decode(gzippedArchive);
+ final issues = <String>[];
+ await TarReader.forEach(Stream.value(archive), (entry) async {
+ if (extensions.any((ext) => entry.name.endsWith(ext))) {
+ late String contents;
+ try {
+ final bytes = await http.ByteStream(entry.contents).toBytes();
+ contents = utf8.decode(bytes);
+ } on FormatException {
+ return; // ignore invalid utf8
+ }
+ final start = DateTime.now();
+ try {
+ markdownToHtml(
+ contents,
+ extensionSet: ExtensionSet.gitHubWeb,
+ );
+ } catch (err, st) {
+ issues.add(
+ 'package:$package-$version/${entry.name}, throws: $err\n$st');
+ }
+ final time = DateTime.now().difference(start);
+ if (time.inSeconds > 30) {
+ issues.add(
+ 'package:$package-$version/${entry.name} took $time to process');
+ }
+ }
+ });
+ return issues;
+ } on FormatException {
+ return null;
+ }
+ }).timeout(const Duration(minutes: 2), onTimeout: () {
+ return ['package:$package-$version failed to be processed in 2 minutes'];
+ });
+}
diff --git a/pkgs/markdown/test/document_test.dart b/pkgs/markdown/test/document_test.dart
new file mode 100644
index 0000000..3e30697
--- /dev/null
+++ b/pkgs/markdown/test/document_test.dart
@@ -0,0 +1,125 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:markdown/markdown.dart';
+import 'package:markdown/src/util.dart';
+import 'package:test/test.dart';
+
+void main() {
+ group('Document', () {
+ test('encodeHtml prevents less than and ampersand escaping', () {
+ final document = Document(encodeHtml: false);
+ final result = document.parseInline('< &');
+ expect(result, hasLength(1));
+ expect(
+ result[0],
+ const TypeMatcher<Text>().having((e) => e.text, 'text', equals('< &')),
+ );
+ });
+
+ group('with encodeHtml enabled', () {
+ final document = Document();
+
+ test('encodes HTML in an inline code snippet', () {
+ final result =
+ document.parseInline('``<p>Hello <em>Markdown</em></p>``');
+ final codeSnippet = result.single as Element;
+ expect(
+ codeSnippet.textContent,
+ equals('<p>Hello <em>Markdown</em></p>'),
+ );
+ });
+
+ test('encodes HTML in a fenced code block', () {
+ final lines = '```\n<p>Hello <em>Markdown</em></p>\n```\n'.toLines();
+ final result = document.parseLineList(lines);
+ final codeBlock = result.single as Element;
+ expect(
+ codeBlock.textContent,
+ equals('<p>Hello <em>Markdown</em></p>\n'),
+ );
+ });
+
+ test('encodes HTML in an indented code block', () {
+ final lines = ' <p>Hello <em>Markdown</em></p>\n'.toLines();
+ final result = document.parseLineList(lines);
+ final codeBlock = result.single as Element;
+ expect(
+ codeBlock.textContent,
+ equals('<p>Hello <em>Markdown</em></p>\n'),
+ );
+ });
+
+ test('encodeHtml spaces are preserved in text', () {
+ // Example to get a <p> tag rendered before a text node.
+ const contents = 'Sample\n\n<pre>\n A\n B\n</pre>';
+ final document = Document();
+ final nodes = BlockParser(contents.toLines(), document).parseLines();
+ final result = HtmlRenderer().render(nodes);
+ expect(result, '<p>\n</p>\n<pre>\n A\n B\n</pre>');
+ });
+
+ test('encode double quotes, greater than, and less than when escaped',
+ () {
+ const contents = r'\>\"\< Hello';
+ final document = Document();
+ final nodes = document.parseInline(contents);
+ expect(nodes, hasLength(1));
+ expect(
+ nodes.single,
+ const TypeMatcher<Text>().having(
+ (e) => e.text,
+ 'text',
+ '>"< Hello',
+ ),
+ );
+ });
+ });
+
+ group('with encodeHtml disabled', () {
+ final document = Document(encodeHtml: false);
+
+ test('leaves HTML alone, in a code snippet', () {
+ final result =
+ document.parseInline('```<p>Hello <em>Markdown</em></p>```');
+ final codeSnippet = result.single as Element;
+ expect(
+ codeSnippet.textContent,
+ equals('<p>Hello <em>Markdown</em></p>'),
+ );
+ });
+
+ test('leaves HTML alone, in a fenced code block', () {
+ final lines = '```\n<p>Hello <em>Markdown</em></p>\n```\n'.toLines();
+ final result = document.parseLineList(lines);
+ final codeBlock = result.single as Element;
+ expect(
+ codeBlock.textContent,
+ equals('<p>Hello <em>Markdown</em></p>\n'),
+ );
+ });
+
+ test('leaves HTML alone, in an indented code block', () {
+ final lines = ' <p>Hello <em>Markdown</em></p>\n'.toLines();
+ final result = document.parseLineList(lines);
+ final codeBlock = result.single as Element;
+ expect(
+ codeBlock.textContent,
+ equals('<p>Hello <em>Markdown</em></p>\n'),
+ );
+ });
+
+ test('leave double quotes, greater than, and less than when escaped', () {
+ const contents = r'\>\"\< Hello';
+ final document = Document(encodeHtml: false);
+ final nodes = document.parseInline(contents);
+ expect(nodes, hasLength(1));
+ expect(
+ nodes.single,
+ const TypeMatcher<Text>().having((e) => e.text, 'text', '>"< Hello'),
+ );
+ });
+ });
+ });
+}
diff --git a/pkgs/markdown/test/extensions/alert_extension.unit b/pkgs/markdown/test/extensions/alert_extension.unit
new file mode 100644
index 0000000..9a21f18
--- /dev/null
+++ b/pkgs/markdown/test/extensions/alert_extension.unit
@@ -0,0 +1,162 @@
+>>> type note
+> [!NoTe]
+> Test note alert.
+<<<
+<div class="markdown-alert markdown-alert-note">
+<p class="markdown-alert-title">Note</p>
+<p>Test note alert.</p>
+</div>
+>>> type tip
+> [!TiP]
+> Test tip alert.
+<<<
+<div class="markdown-alert markdown-alert-tip">
+<p class="markdown-alert-title">Tip</p>
+<p>Test tip alert.</p>
+</div>
+>>> type important
+> [!ImpoRtanT]
+> Test important alert.
+<<<
+<div class="markdown-alert markdown-alert-important">
+<p class="markdown-alert-title">Important</p>
+<p>Test important alert.</p>
+</div>
+>>> type warning
+> [!WarNinG]
+> Test warning alert.
+<<<
+<div class="markdown-alert markdown-alert-warning">
+<p class="markdown-alert-title">Warning</p>
+<p>Test warning alert.</p>
+</div>
+>>> type caution
+> [!CauTioN]
+> Test caution alert.
+<<<
+<div class="markdown-alert markdown-alert-caution">
+<p class="markdown-alert-title">Caution</p>
+<p>Test caution alert.</p>
+</div>
+>>> invalid type
+> [!foo]
+> Test foo alert.
+<<<
+<blockquote>
+<p>[!foo]
+Test foo alert.</p>
+</blockquote>
+>>> contents can both contain/not contain starting quote
+> [!NOTE]
+Test note alert.
+>Test note alert x2.
+<<<
+<div class="markdown-alert markdown-alert-note">
+<p class="markdown-alert-title">Note</p>
+<p>Test note alert.
+Test note alert x2.</p>
+</div>
+>>> spaces everywhere
+ > [!NOTE]
+> Test note alert.
+ > Test note alert x2.
+<<<
+<div class="markdown-alert markdown-alert-note">
+<p class="markdown-alert-title">Note</p>
+<p>Test note alert.
+Test note alert x2.</p>
+</div>
+>>> title has 3 more spaces then fallback to blockquote
+> [!NOTE]
+> Test blockquote.
+<<<
+<blockquote>
+<p>[!NOTE]
+Test blockquote.</p>
+</blockquote>
+>>> nested blockquote
+> [!NOTE]
+>> Test nested blockquote.
+<<<
+<div class="markdown-alert markdown-alert-note">
+<p class="markdown-alert-title">Note</p>
+<blockquote>
+<p>Test nested blockquote.</p>
+</blockquote>
+</div>
+>>> escape brackets
+> \[!note\]
+> Test escape brackets.
+<<<
+<div class="markdown-alert markdown-alert-note">
+<p class="markdown-alert-title">Note</p>
+<p>Test escape brackets.</p>
+</div>
+>>> terminates properly
+> [!note]
+> A sample note.
+
+Additional markdown text.
+<<<
+<div class="markdown-alert markdown-alert-note">
+<p class="markdown-alert-title">Note</p>
+<p>A sample note.</p>
+</div>
+<p>Additional markdown text.</p>
+>>> supports multiple quoted lines
+> [!note]
+> A sample note
+> with two lines.
+
+Additional markdown text.
+<<<
+<div class="markdown-alert markdown-alert-note">
+<p class="markdown-alert-title">Note</p>
+<p>A sample note
+with two lines.</p>
+</div>
+<p>Additional markdown text.</p>
+>>> supports multiple lines
+> [!note]
+> A sample note
+ with two lines.
+
+Additional markdown text.
+<<<
+<div class="markdown-alert markdown-alert-note">
+<p class="markdown-alert-title">Note</p>
+<p>A sample note
+with two lines.</p>
+</div>
+<p>Additional markdown text.</p>
+>>> supports continuation lines
+> [!note]
+> A sample note
+with two lines.
+
+Additional markdown text.
+<<<
+<div class="markdown-alert markdown-alert-note">
+<p class="markdown-alert-title">Note</p>
+<p>A sample note
+with two lines.</p>
+</div>
+<p>Additional markdown text.</p>
+>>> crash repro #584.1
+> [!Warning]
+>
+> Some extensions won't work on dynamic types.
+<<<
+<div class="markdown-alert markdown-alert-warning">
+<p class="markdown-alert-title">Warning</p>
+<p>Some extensions won't work on dynamic types.</p>
+</div>
+>>> crash repro #584.2
+> [!NOTE]
+>
+> if you receive the following error:
+<<<
+<div class="markdown-alert markdown-alert-note">
+<p class="markdown-alert-title">Note</p>
+<p>if you receive the following error:</p>
+</div>
diff --git a/pkgs/markdown/test/extensions/autolink_extension.unit b/pkgs/markdown/test/extensions/autolink_extension.unit
new file mode 100644
index 0000000..4a07fdc
--- /dev/null
+++ b/pkgs/markdown/test/extensions/autolink_extension.unit
@@ -0,0 +1,10 @@
+>>> not a link
+mhttp://www.foo.com
+<<<
+<p>mhttp://www.foo.com</p>
+>>> following a newline
+m
+http://www.foo.com
+<<<
+<p>m
+<a href="http://www.foo.com">http://www.foo.com</a></p>
\ No newline at end of file
diff --git a/pkgs/markdown/test/extensions/emojis.unit b/pkgs/markdown/test/extensions/emojis.unit
new file mode 100644
index 0000000..00197e5
--- /dev/null
+++ b/pkgs/markdown/test/extensions/emojis.unit
@@ -0,0 +1,42 @@
+>>> within a paragraph
+I love to :smile:.
+
+<<<
+<p>I love to 😄.</p>
+>>> within other inline syntax
+I *love to :smile:*
+<<<
+<p>I <em>love to 😄</em></p>
+>>> within blockquote
+> I love to :smile:.
+<<<
+<blockquote>
+<p>I love to 😄.</p>
+</blockquote>
+>>> within code block
+ I love to :smile:
+<<<
+<pre><code>I love to :smile:
+</code></pre>
+>>> within a link
+I love [to :smile:](http://www.google.com).
+<<<
+<p>I love <a href="http://www.google.com">to 😄</a>.</p>
+>>> within a reference link
+I love [to :smile:][].
+
+[to :smile:]: http://www.google.com
+<<<
+<p>I love <a href="http://www.google.com">to 😄</a>.</p>
+>>> within inline code
+I love to `:smile:`.
+<<<
+<p>I love to <code>:smile:</code>.</p>
+>>> with multiple code points
+Yay :australia:
+<<<
+<p>Yay 🇦🇺</p>
+>>> leaves unknown emojis alone
+I love :smiles:.
+<<<
+<p>I love :smiles:.</p>
diff --git a/pkgs/markdown/test/extensions/fenced_blockquotes.unit b/pkgs/markdown/test/extensions/fenced_blockquotes.unit
new file mode 100644
index 0000000..8124ad4
--- /dev/null
+++ b/pkgs/markdown/test/extensions/fenced_blockquotes.unit
@@ -0,0 +1,70 @@
+>>> simple block quote
+>>>
+# Foo
+bar
+baz
+>>>
+
+<<<
+<blockquote>
+<h1>Foo</h1>
+<p>bar
+baz</p>
+</blockquote>
+>>> has blank lines
+>>>
+
+foo
+
+
+
+
+bar
+
+
+>>>
+
+<<<
+<blockquote>
+<p>foo</p>
+<p>bar</p>
+</blockquote>
+>>> with nested block quote
+>>>
+foo
+> bar
+>>>
+
+<<<
+<blockquote>
+<p>foo</p>
+<blockquote>
+<p>bar</p>
+</blockquote>
+</blockquote>
+>>> with nested indented clode block
+>>>
+ foo
+ bar
+>>>
+
+<<<
+<blockquote>
+<pre><code>foo
+bar
+</code></pre>
+</blockquote>
+>>> with nested fenced clode block
+>>>
+```
+foo
+bar
+```
+>>>
+
+<<<
+<blockquote>
+<pre><code>foo
+bar
+</code></pre>
+</blockquote>
\ No newline at end of file
diff --git a/pkgs/markdown/test/extensions/fenced_code_blocks.unit b/pkgs/markdown/test/extensions/fenced_code_blocks.unit
new file mode 100644
index 0000000..596f49a
--- /dev/null
+++ b/pkgs/markdown/test/extensions/fenced_code_blocks.unit
@@ -0,0 +1,52 @@
+>>> without an optional language identifier
+```
+code
+```
+
+<<<
+<pre><code>code
+</code></pre>
+>>> with an optional language identifier
+```dart
+code
+```
+
+<<<
+<pre><code class="language-dart">code
+</code></pre>
+>>> escape HTML characters
+```
+<&>
+```
+
+<<<
+<pre><code><&>
+</code></pre>
+>>> Pandoc style without language identifier
+~~~~~
+code
+~~~~~
+
+<<<
+<pre><code>code
+</code></pre>
+>>> Pandoc style with language identifier
+~~~~~dart
+code
+~~~~~
+
+<<<
+<pre><code class="language-dart">code
+</code></pre>
+>>> Pandoc style with inner tildes row
+~~~~~
+~~~
+code
+~~~
+~~~~~
+
+<<<
+<pre><code>~~~
+code
+~~~
+</code></pre>
diff --git a/pkgs/markdown/test/extensions/footnote_block.unit b/pkgs/markdown/test/extensions/footnote_block.unit
new file mode 100644
index 0000000..ae730bf
--- /dev/null
+++ b/pkgs/markdown/test/extensions/footnote_block.unit
@@ -0,0 +1,288 @@
+>>> footnote reference in footnote definition
+
+Footnote 1 link[^first].
+
+[^first]: footnote reference in footnote definition[^first]
+
+<<<
+<p>Footnote 1 link<sup class="footnote-ref"><a href="#fn-first" id="fnref-first">1</a></sup>.</p>
+<section class="footnotes">
+<ol>
+<li id="fn-first">
+<p>footnote reference in footnote definition<sup class="footnote-ref"><a href="#fn-first" id="fnref-first-2">1</a></sup> <a href="#fnref-first" class="footnote-backref">↩</a> <a href="#fnref-first-2" class="footnote-backref">↩<sup class="footnote-ref">2</sup></a></p>
+</li>
+</ol>
+</section>
+>>> footnote reference cases
+[^fifth]: ending with another ']' and different order
+
+Footnote 1 link[^first].
+
+Footnote 2 link[^きゃくちゅう脚注].
+
+Footnote 3 link[^p1 p2].
+
+Footnote 4 link![^forth].
+
+Footnote 5 link![^fifth]].
+
+Footnote 6 link![^ sixth ].
+
+Footnote 7 link[^きゃくちゅう脚注].
+
+[^first]: Here is the footnote definition
+
+[^きゃくちゅう脚注]: unicode label and duplicated reference.
+
+[^p1 p2]: p1 p2
+
+[^ForTh]: start with '[' and with upper case
+
+[^sixth]: label-start-with-blank
+<<<
+<p>Footnote 1 link<sup class="footnote-ref"><a href="#fn-first" id="fnref-first">1</a></sup>.</p>
+<p>Footnote 2 link<sup class="footnote-ref"><a href="#fn-%E3%81%8D%E3%82%83%E3%81%8F%E3%81%A1%E3%82%85%E3%81%86%E8%84%9A%E6%B3%A8" id="fnref-%E3%81%8D%E3%82%83%E3%81%8F%E3%81%A1%E3%82%85%E3%81%86%E8%84%9A%E6%B3%A8">2</a></sup>.</p>
+<p>Footnote 3 link[^p1 p2].</p>
+<p>Footnote 4 link!<sup class="footnote-ref"><a href="#fn-ForTh" id="fnref-ForTh">3</a></sup>.</p>
+<p>Footnote 5 link!<sup class="footnote-ref"><a href="#fn-fifth" id="fnref-fifth">4</a></sup>].</p>
+<p>Footnote 6 link!<sup class="footnote-ref"><a href="#fn-sixth" id="fnref-sixth">5</a></sup>.</p>
+<p>Footnote 7 link<sup class="footnote-ref"><a href="#fn-%E3%81%8D%E3%82%83%E3%81%8F%E3%81%A1%E3%82%85%E3%81%86%E8%84%9A%E6%B3%A8" id="fnref-%E3%81%8D%E3%82%83%E3%81%8F%E3%81%A1%E3%82%85%E3%81%86%E8%84%9A%E6%B3%A8-2">2</a></sup>.</p>
+<p>[^p1 p2]: p1 p2</p>
+<section class="footnotes">
+<ol>
+<li id="fn-first">
+<p>Here is the footnote definition <a href="#fnref-first" class="footnote-backref">↩</a></p>
+</li>
+<li id="fn-%E3%81%8D%E3%82%83%E3%81%8F%E3%81%A1%E3%82%85%E3%81%86%E8%84%9A%E6%B3%A8">
+<p>unicode label and duplicated reference. <a href="#fnref-%E3%81%8D%E3%82%83%E3%81%8F%E3%81%A1%E3%82%85%E3%81%86%E8%84%9A%E6%B3%A8" class="footnote-backref">↩</a> <a href="#fnref-%E3%81%8D%E3%82%83%E3%81%8F%E3%81%A1%E3%82%85%E3%81%86%E8%84%9A%E6%B3%A8-2" class="footnote-backref">↩<sup class="footnote-ref">2</sup></a></p>
+</li>
+<li id="fn-ForTh">
+<p>start with '[' and with upper case <a href="#fnref-ForTh" class="footnote-backref">↩</a></p>
+</li>
+<li id="fn-fifth">
+<p>ending with another ']' and different order <a href="#fnref-fifth" class="footnote-backref">↩</a></p>
+</li>
+<li id="fn-sixth">
+<p>label-start-with-blank <a href="#fnref-sixth" class="footnote-backref">↩</a></p>
+</li>
+</ol>
+</section>
+>>> footnote labels with special chars
+empty label[^] and blank label[^ ]
+
+some[^-] strange[^^] but[^\[] labels[^\[\]]
+
+[^]:
+[^ ]:
+
+[^-]: valid1
+
+[^^]:valid2
+
+[^\[]: valid3
+
+[^\[\]]: this-is-link-not-footnote
+<<<
+<p>empty label[^] and blank label[^ ]</p>
+<p>some<sup class="footnote-ref"><a href="#fn--" id="fnref--">1</a></sup> strange<sup class="footnote-ref"><a href="#fn-%5E" id="fnref-%5E">2</a></sup> but<sup class="footnote-ref"><a href="#fn-%5C%5B" id="fnref-%5C%5B">3</a></sup> labels<a href="this-is-link-not-footnote">^[]</a></p>
+<p>[^]:
+[^ ]:</p>
+<section class="footnotes">
+<ol>
+<li id="fn--">
+<p>valid1 <a href="#fnref--" class="footnote-backref">↩</a></p>
+</li>
+<li id="fn-%5E">
+<p>valid2 <a href="#fnref-%5E" class="footnote-backref">↩</a></p>
+</li>
+<li id="fn-%5C%5B">
+<p>valid3 <a href="#fnref-%5C%5B" class="footnote-backref">↩</a></p>
+</li>
+</ol>
+</section>
+>>> footnote with paragraph
+test footnote[^first].
+
+[^first]: Footnote **can have markup**
+
+ and multiple paragraphs.
+
+"Smartypants, double quotes" and 'single quotes'
+<<<
+<p>test footnote<sup class="footnote-ref"><a href="#fn-first" id="fnref-first">1</a></sup>.</p>
+<p>"Smartypants, double quotes" and 'single quotes'</p>
+<section class="footnotes">
+<ol>
+<li id="fn-first">
+<p>Footnote <strong>can have markup</strong></p>
+<p>and multiple paragraphs. <a href="#fnref-first" class="footnote-backref">↩</a></p>
+</li>
+</ol>
+</section>
+>>> footnote adjacent paragraph
+Here is a footnote reference,[^1]
+[^1]: Here is the footnote.
+ Subsequent paragraphs
+<<<
+<p>Here is a footnote reference,<sup class="footnote-ref"><a href="#fn-1" id="fnref-1">1</a></sup></p>
+<section class="footnotes">
+<ol>
+<li id="fn-1">
+<p>Here is the footnote.
+Subsequent paragraphs <a href="#fnref-1" class="footnote-backref">↩</a></p>
+</li>
+</ol>
+</section>
+>>> footnote without ref
+Here is a footnote reference
+[^1]: Here is the footnote.
+<<<
+<p>Here is a footnote reference</p>
+>>> footnote example from github
+Here is a simple footnote[^1].
+
+A footnote can also have multiple lines[^2].
+
+You can also use words, to fit your writing style more closely[^note].
+
+[^1]: My reference.
+[^2]: Every new line should be prefixed with 2 spaces.
+ This allows you to have a footnote with multiple lines.
+[^note]:
+ Named footnotes will still render with numbers instead of the text but allow easier identification and linking.
+ This footnote also has been made with a different syntax using 4 spaces for new lines.
+<<<
+<p>Here is a simple footnote<sup class="footnote-ref"><a href="#fn-1" id="fnref-1">1</a></sup>.</p>
+<p>A footnote can also have multiple lines<sup class="footnote-ref"><a href="#fn-2" id="fnref-2">2</a></sup>.</p>
+<p>You can also use words, to fit your writing style more closely<sup class="footnote-ref"><a href="#fn-note" id="fnref-note">3</a></sup>.</p>
+<section class="footnotes">
+<ol>
+<li id="fn-1">
+<p>My reference. <a href="#fnref-1" class="footnote-backref">↩</a></p>
+</li>
+<li id="fn-2">
+<p>Every new line should be prefixed with 2 spaces.
+This allows you to have a footnote with multiple lines. <a href="#fnref-2" class="footnote-backref">↩</a></p>
+</li>
+<li id="fn-note">
+<p>Named footnotes will still render with numbers instead of the text but allow easier identification and linking.
+This footnote also has been made with a different syntax using 4 spaces for new lines. <a href="#fnref-note" class="footnote-backref">↩</a></p>
+</li>
+</ol>
+</section>
+>>> ![^ **image**] without definition should be formatted: unlike github
+![^ **image**]
+<<<
+<p>![^ <strong>image</strong>]</p>
+>>> ![^ **image**] with definition should be image: unlike github
+![^ **image**]
+
+[^ **image**]: valid-link
+<<<
+<p><img src="valid-link" alt="^ image" /></p>
+>>> ![^ **image**] with definition should be plain html: unlike github
+![^ **image**]
+
+[^ **image**]: invalid link
+<<<
+<p>![^ <strong>image</strong>]</p>
+<p>[^ <strong>image</strong>]: invalid link</p>
+>>> ![ ^**image**] without definition should be formatted
+![ ^**image**]
+<<<
+<p>![ ^<strong>image</strong>]</p>
+>>> ![^ ^**image**] without definition should be formatted: unlike github
+![^ ^**image**]
+<<<
+<p>![^ ^<strong>image</strong>]</p>
+>>> ![^ ^**image**] with definition should be image: unlike github
+![^ ^**image**]
+
+[^ ^**image**]: valid-link
+<<<
+<p><img src="valid-link" alt="^ ^image" /></p>
+>>> [^ **label**] without definition should be formatted: unlike github
+[^ **label**]
+<<<
+<p>[^ <strong>label</strong>]</p>
+>>> [adc][^**link**] without definition should be formatted: unlike github
+[adc][^**link**]
+<<<
+<p>[adc][^<strong>link</strong>]</p>
+>>> [adc][^**link**] with definition should be footnotes:
+[adc][^**link**]
+
+[^**link**]: valid-link
+<<<
+<p>[adc]<sup class="footnote-ref"><a href="#fn-**link**" id="fnref-**link**">1</a></sup></p>
+<section class="footnotes">
+<ol>
+<li id="fn-**link**">
+<p>valid-link <a href="#fnref-**link**" class="footnote-backref">↩</a></p>
+</li>
+</ol>
+</section>
+>>> \[^good] should be text
+\[^good]
+
+[^good]: good
+<<<
+<p>[^good]</p>
+>>>[^ nice] should be link
+[^ nice]
+
+[^ nice ]: good
+<<<
+<p><a href="good">^ nice</a></p>
+>>>[^ nice ] should be text
+[^ nice ]
+
+[^nice ]: good
+<<<
+<p>[^ nice ]</p>
+>>> [^\]] with definition should be link
+[^\]]
+
+[^\]]: good
+<<<
+<p><a href="good">^]</a></p>
+>>> [^a-\nb] with definition should be paragraph
+[^a-
+b]
+
+[^a-
+b]: good
+<<<
+<p><a href="good">^a-
+b</a></p>
+>>> [^a] with error definition should be text
+[^a]
+
+[^a\]: good
+<<<
+<p>[^a]</p>
+>>> [^a] with double definition contain '\]' should be text
+[^a]
+
+[^a\]:]: definition contain '\]'
+<<<
+<p>[^a]</p>
+>>> [^a] with double definition trailing should be footnote
+[^a]
+
+[^a]:]: good
+<<<
+<p><sup class="footnote-ref"><a href="#fn-a" id="fnref-a">1</a></sup></p>
+<section class="footnotes">
+<ol>
+<li id="fn-a">
+<p>]: good <a href="#fnref-a" class="footnote-backref">↩</a></p>
+</li>
+</ol>
+</section>
+>>> complete image link with definition would be image: unlike github
+
+
+[^image]: image footnote
+<<<
+<p><img src="example.png" alt="^image" /></p>
diff --git a/pkgs/markdown/test/extensions/headers_with_ids.unit b/pkgs/markdown/test/extensions/headers_with_ids.unit
new file mode 100644
index 0000000..7bad75c
--- /dev/null
+++ b/pkgs/markdown/test/extensions/headers_with_ids.unit
@@ -0,0 +1,41 @@
+>>> simple header
+# header
+
+<<<
+<h1 id="header">header</h1>
+>>> header that starts with garbage
+## 2. header again
+
+<<<
+<h2 id="2-header-again">2. header again</h2>
+>>> header with inline syntaxes
+### headers **rock** `etc.`
+
+<<<
+<h3 id="headers-rock-etc">headers <strong>rock</strong> <code>etc.</code></h3>
+>>> non-unique headers
+# header
+
+## header
+
+<<<
+<h1 id="header">header</h1>
+<h2 id="header-2">header</h2>
+>>> header starts with inline syntax
+# *headers* etc.
+<<<
+<h1 id="headers-etc"><em>headers</em> etc.</h1>
+>>> numbers-only headers (like a changelog)
+# 1.2.34
+
+## 1.23.4
+
+## 1.2.3+4
+<<<
+<h1 id="1234">1.2.34</h1>
+<h2 id="1234-2">1.23.4</h2>
+<h2 id="1234-3">1.2.3+4</h2>
+>>> no id
+# #
+<<<
+<h1></h1>
diff --git a/pkgs/markdown/test/extensions/inline_html.unit b/pkgs/markdown/test/extensions/inline_html.unit
new file mode 100644
index 0000000..1540118
--- /dev/null
+++ b/pkgs/markdown/test/extensions/inline_html.unit
@@ -0,0 +1,17 @@
+>>> within a paragraph
+Within a <em class="x">paragraph</EM>.
+
+<<<
+<p>Within a <em class="x">paragraph</EM>.</p>
+>>> not HTML
+Obviously, 3 < 5 and 7 > 2.
+Not HTML: <3>, <_a>, <>
+
+<<<
+<p>Obviously, 3 < 5 and 7 > 2.
+Not HTML: <3>, <_a>, <></p>
+>>> "markdown" within a tag is not parsed
+Text <a href="_foo_">And "_foo_"</a>.
+
+<<<
+<p>Text <a href="_foo_">And "<em>foo</em>"</a>.</p>
diff --git a/pkgs/markdown/test/extensions/ordered_list_with_checkboxes.unit b/pkgs/markdown/test/extensions/ordered_list_with_checkboxes.unit
new file mode 100644
index 0000000..8503e56
--- /dev/null
+++ b/pkgs/markdown/test/extensions/ordered_list_with_checkboxes.unit
@@ -0,0 +1,79 @@
+>>> checkbox with space
+1. [ ] one
+2. [ ] two
+<<<
+<ol class="contains-task-list">
+<li class="task-list-item"><input type="checkbox"></input>one</li>
+<li class="task-list-item"><input type="checkbox"></input>two</li>
+</ol>
+>>> empty checkbox
+1. [] one
+2. [] two
+<<<
+<ol>
+<li>[] one</li>
+<li>[] two</li>
+</ol>
+>>> checkbox with x
+1. [x] one
+2. [x] two
+<<<
+<ol class="contains-task-list">
+<li class="task-list-item"><input type="checkbox" checked="true"></input>one</li>
+<li class="task-list-item"><input type="checkbox" checked="true"></input>two</li>
+</ol>
+>>> checkbox with X
+1. [X] one
+2. [X] two
+<<<
+<ol class="contains-task-list">
+<li class="task-list-item"><input type="checkbox" checked="true"></input>one</li>
+<li class="task-list-item"><input type="checkbox" checked="true"></input>two</li>
+</ol>
+>>> mixed checkboxes
+1. [ ] one
+2. [] two
+3. [x] three
+4. [X] four
+5. five
+<<<
+<ol class="contains-task-list">
+<li class="task-list-item"><input type="checkbox"></input>one</li>
+<li>[] two</li>
+<li class="task-list-item"><input type="checkbox" checked="true"></input>three</li>
+<li class="task-list-item"><input type="checkbox" checked="true"></input>four</li>
+<li>five</li>
+</ol>
+>>> mixed leading spaces
+1. [ ] zero
+2. [ ] one
+3. [ ] two
+4. [ ] three
+5. [ ] four
+<<<
+<ol class="contains-task-list">
+<li class="task-list-item"><input type="checkbox"></input>zero</li>
+<li class="task-list-item"><input type="checkbox"></input>one</li>
+<li class="task-list-item"><input type="checkbox"></input>two</li>
+<li class="task-list-item"><input type="checkbox"></input>three</li>
+<li>
+<pre><code>[ ] four
+</code></pre>
+</li>
+</ol>
+>>> checkbox with empty content
+1. [ ] one
+2.
+3.
+4. four
+5. [ ] five
+6.
+<<<
+<ol class="contains-task-list">
+<li class="task-list-item"><input type="checkbox"></input>one</li>
+<li></li>
+<li></li>
+<li>four</li>
+<li class="task-list-item"><input type="checkbox"></input>five</li>
+<li></li>
+</ol>
\ No newline at end of file
diff --git a/pkgs/markdown/test/extensions/setext_headers_with_ids.unit b/pkgs/markdown/test/extensions/setext_headers_with_ids.unit
new file mode 100644
index 0000000..b8ef022
--- /dev/null
+++ b/pkgs/markdown/test/extensions/setext_headers_with_ids.unit
@@ -0,0 +1,18 @@
+>>> h1
+text
+===
+
+<<<
+<h1 id="text">text</h1>
+>>> h2
+text
+---
+
+<<<
+<h2 id="text">text</h2>
+>>> header with inline syntax
+header *emphasised*
+===
+
+<<<
+<h1 id="header-emphasised">header <em>emphasised</em></h1>
diff --git a/pkgs/markdown/test/extensions/strikethrough.unit b/pkgs/markdown/test/extensions/strikethrough.unit
new file mode 100644
index 0000000..5222d91
--- /dev/null
+++ b/pkgs/markdown/test/extensions/strikethrough.unit
@@ -0,0 +1,24 @@
+>>> Missing leading whitespace
+word pas~~t~~ word
+<<<
+<p>word pas<del>t</del> word</p>
+>>> Missing trailing whitespace
+word ~~p~~ast word
+<<<
+<p>word <del>p</del>ast word</p>
+>>> Middle of word
+word p~~as~~t word
+<<<
+<p>word p<del>as</del>t word</p>
+>>> Whitespace after opening
+word~~ past~~ word
+<<<
+<p>word~~ past~~ word</p>
+>>> Whitespace before closing
+word ~~past ~~word
+<<<
+<p>word ~~past ~~word</p>
+>>> mixed with emphasis and order changes
+**~~first~~** ~~**second**~~
+<<<
+<p><strong><del>first</del></strong> <del><strong>second</strong></del></p>
diff --git a/pkgs/markdown/test/extensions/tables.unit b/pkgs/markdown/test/extensions/tables.unit
new file mode 100644
index 0000000..c7a8cae
--- /dev/null
+++ b/pkgs/markdown/test/extensions/tables.unit
@@ -0,0 +1,378 @@
+>>> basic table
+head | cells
+-----|------
+body | cells
+
+<<<
+<table>
+<thead>
+<tr>
+<th>head</th>
+<th>cells</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>body</td>
+<td>cells</td>
+</tr>
+</tbody>
+</table>
+>>> multiple rows
+head | cells
+-----|------
+body | cells
+more | cells
+
+<<<
+<table>
+<thead>
+<tr>
+<th>head</th>
+<th>cells</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>body</td>
+<td>cells</td>
+</tr>
+<tr>
+<td>more</td>
+<td>cells</td>
+</tr>
+</tbody>
+</table>
+>>> rows wrapped in pipes
+| head | cells |
+|------|-------|
+| body | cells |
+
+<<<
+<table>
+<thead>
+<tr>
+<th>head</th>
+<th>cells</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>body</td>
+<td>cells</td>
+</tr>
+</tbody>
+</table>
+>>> rows wrapped in pipes, whitespace alignment row
+| head | cells |
+| -- | --- |
+| body | cells |
+
+<<<
+<table>
+<thead>
+<tr>
+<th>head</th>
+<th>cells</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>body</td>
+<td>cells</td>
+</tr>
+</tbody>
+</table>
+>>> rows wrapped in pipes, tabs in whitespace
+| head | cells |
+| -- | --- |
+| body | cells |
+
+<<<
+<table>
+<thead>
+<tr>
+<th>head</th>
+<th>cells</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>body</td>
+<td>cells</td>
+</tr>
+</tbody>
+</table>
+>>> cells with inline syntax
+head `code` | _cells_
+------------|--------
+*text* | <span>text</span>
+<<<
+<table>
+<thead>
+<tr>
+<th>head <code>code</code></th>
+<th><em>cells</em></th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td><em>text</em></td>
+<td><span>text</span></td>
+</tr>
+</tbody>
+</table>
+>>> cells are parsed before inline syntax
+header | _foo | bar_
+-------|------------|---
+text | text
+<<<
+<table>
+<thead>
+<tr>
+<th>header</th>
+<th>_foo</th>
+<th>bar_</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>text</td>
+<td>text</td>
+<td></td>
+</tr>
+</tbody>
+</table>
+>>> cells contain reference links
+header | header
+-------|--------
+text | [link][here]
+
+[here]: http://url
+<<<
+<table>
+<thead>
+<tr>
+<th>header</th>
+<th>header</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>text</td>
+<td><a href="http://url">link</a></td>
+</tr>
+</tbody>
+</table>
+>>> one column tables
+head
+-----|
+body
+<<<
+<table>
+<thead>
+<tr>
+<th>head</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>body</td>
+</tr>
+</tbody>
+</table>
+>>> varying cells per row
+head | foo | bar
+-----|-----|-----
+body
+row with | two cells
+<<<
+<table>
+<thead>
+<tr>
+<th>head</th>
+<th>foo</th>
+<th>bar</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>body</td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td>row with</td>
+<td>two cells</td>
+<td></td>
+</tr>
+</tbody>
+</table>
+>>> left, center, and right alignment
+head | cells | here
+:----|:-----:|----:
+body | cells | here
+too | many | cells | here
+
+<<<
+<table>
+<thead>
+<tr>
+<th align="left">head</th>
+<th align="center">cells</th>
+<th align="right">here</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td align="left">body</td>
+<td align="center">cells</td>
+<td align="right">here</td>
+</tr>
+<tr>
+<td align="left">too</td>
+<td align="center">many</td>
+<td align="right">cells</td>
+</tr>
+</tbody>
+</table>
+>>> left, center, and right alignment, with whitespace
+head | cells | here
+ :-- | :---: | ---:
+body | cells | here
+too | many | cells | here
+
+<<<
+<table>
+<thead>
+<tr>
+<th align="left">head</th>
+<th align="center">cells</th>
+<th align="right">here</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td align="left">body</td>
+<td align="center">cells</td>
+<td align="right">here</td>
+</tr>
+<tr>
+<td align="left">too</td>
+<td align="center">many</td>
+<td align="right">cells</td>
+</tr>
+</tbody>
+</table>
+>>> escape pipe
+| Name | Character |
+| --- | --- |
+| Backtick | ` |
+| Pipe | \| |
+
+<<<
+<table>
+<thead>
+<tr>
+<th>Name</th>
+<th>Character</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>Backtick</td>
+<td>`</td>
+</tr>
+<tr>
+<td>Pipe</td>
+<td>|</td>
+</tr>
+</tbody>
+</table>
+>>> escape pipe, preserve trailing whitespace
+| Name | Character |
+| --- | --- |
+| Pipe | \| abcdef |
+
+<<<
+<table>
+<thead>
+<tr>
+<th>Name</th>
+<th>Character</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>Pipe</td>
+<td>| abcdef</td>
+</tr>
+</tbody>
+</table>
+>>> trailing whitespace after final pipe
+| Name | Character |
+| --- | --- |
+| Pipe | abcdef |
+<<<
+<table>
+<thead>
+<tr>
+<th>Name</th>
+<th>Character</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>Pipe</td>
+<td>abcdef</td>
+</tr>
+</tbody>
+</table>
+>>> issue #531
+| A | [B](url) | C |
+|---|---|
+| a | b | c |
+<<<
+<p>| A | <a href="url">B</a> | C |
+|---|---|
+| a | b | c |</p>
+>>> trailing whitespace after delimiter row
+| Name | Value |
+| --- | --- |
+| Foo | bar |
+<<<
+<table>
+<thead>
+<tr>
+<th>Name</th>
+<th>Value</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>Foo</td>
+<td>bar</td>
+</tr>
+</tbody>
+</table>
+>>> can interrupt a paragraph
+paragraph
+foo | bar
+--- | ---
+baz | bim
+<<<
+<p>paragraph</p>
+<table>
+<thead>
+<tr>
+<th>foo</th>
+<th>bar</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>baz</td>
+<td>bim</td>
+</tr>
+</tbody>
+</table>
diff --git a/pkgs/markdown/test/extensions/unordered_list_with_checkboxes.unit b/pkgs/markdown/test/extensions/unordered_list_with_checkboxes.unit
new file mode 100644
index 0000000..f33161e
--- /dev/null
+++ b/pkgs/markdown/test/extensions/unordered_list_with_checkboxes.unit
@@ -0,0 +1,83 @@
+>>> checkbox with space
+* [ ] one
+* [ ] two
+<<<
+<ul class="contains-task-list">
+<li class="task-list-item"><input type="checkbox"></input>one</li>
+<li class="task-list-item"><input type="checkbox"></input>two</li>
+</ul>
+>>> empty checkbox
+* [] one
+* [] two
+<<<
+<ul>
+<li>[] one</li>
+<li>[] two</li>
+</ul>
+>>> checkbox with x
+* [x] one
+* [x] two
+<<<
+<ul class="contains-task-list">
+<li class="task-list-item"><input type="checkbox" checked="true"></input>one</li>
+<li class="task-list-item"><input type="checkbox" checked="true"></input>two</li>
+</ul>
+>>> checkbox with X
+* [X] one
+* [X] two
+<<<
+<ul class="contains-task-list">
+<li class="task-list-item"><input type="checkbox" checked="true"></input>one</li>
+<li class="task-list-item"><input type="checkbox" checked="true"></input>two</li>
+</ul>
+>>> mixed checkboxes
+* [ ] one
+* [] two
+* [x] three
+* [X] four
+* five
+<<<
+<ul class="contains-task-list">
+<li class="task-list-item"><input type="checkbox"></input>one</li>
+<li>[] two</li>
+<li class="task-list-item"><input type="checkbox" checked="true"></input>three</li>
+<li class="task-list-item"><input type="checkbox" checked="true"></input>four</li>
+<li>five</li>
+</ul>
+>>> mixed leading spaces
+*[ ] zero
+* [ ] one
+* [ ] two
+* [ ] three
+* [ ] four
+* [ ] five
+<<<
+<p>*[ ] zero</p>
+<ul class="contains-task-list">
+<li class="task-list-item"><input type="checkbox"></input>one</li>
+<li class="task-list-item"><input type="checkbox"></input>two</li>
+<li class="task-list-item"><input type="checkbox"></input>three</li>
+<li class="task-list-item"><input type="checkbox"></input>four</li>
+<li>
+<pre><code>[ ] five
+</code></pre>
+</li>
+</ul>
+>>> checkbox list separated with blank lines
+- [ ] A
+
+- [ ] B
+
+- [ ]
+<<<
+<ul class="contains-task-list">
+<li class="task-list-item">
+<p><input type="checkbox"></input>A</p>
+</li>
+<li class="task-list-item">
+<p><input type="checkbox"></input>B</p>
+</li>
+<li>
+<p>[ ]</p>
+</li>
+</ul>
\ No newline at end of file
diff --git a/pkgs/markdown/test/gfm/atx_headings.unit b/pkgs/markdown/test/gfm/atx_headings.unit
new file mode 100644
index 0000000..5a60cf4
--- /dev/null
+++ b/pkgs/markdown/test/gfm/atx_headings.unit
@@ -0,0 +1,112 @@
+>>> ATX headings - 32
+# foo
+## foo
+### foo
+#### foo
+##### foo
+###### foo
+<<<
+<h1>foo</h1>
+<h2>foo</h2>
+<h3>foo</h3>
+<h4>foo</h4>
+<h5>foo</h5>
+<h6>foo</h6>
+>>> ATX headings - 33
+####### foo
+<<<
+<p>####### foo</p>
+>>> ATX headings - 34
+#5 bolt
+
+#hashtag
+<<<
+<p>#5 bolt</p>
+<p>#hashtag</p>
+>>> ATX headings - 35
+\## foo
+<<<
+<p>## foo</p>
+>>> ATX headings - 36
+# foo *bar* \*baz\*
+<<<
+<h1>foo <em>bar</em> *baz*</h1>
+>>> ATX headings - 37
+# foo
+<<<
+<h1>foo</h1>
+>>> ATX headings - 38
+ ### foo
+ ## foo
+ # foo
+<<<
+<h3>foo</h3>
+<h2>foo</h2>
+<h1>foo</h1>
+>>> ATX headings - 39
+ # foo
+<<<
+<pre><code># foo
+</code></pre>
+>>> ATX headings - 40
+foo
+ # bar
+<<<
+<p>foo
+# bar</p>
+>>> ATX headings - 41
+## foo ##
+ ### bar ###
+<<<
+<h2>foo</h2>
+<h3>bar</h3>
+>>> ATX headings - 42
+# foo ##################################
+##### foo ##
+<<<
+<h1>foo</h1>
+<h5>foo</h5>
+>>> ATX headings - 43
+### foo ###
+<<<
+<h3>foo</h3>
+>>> ATX headings - 44
+### foo ### b
+<<<
+<h3>foo ### b</h3>
+>>> ATX headings - 45
+# foo#
+<<<
+<h1>foo#</h1>
+>>> ATX headings - 46
+### foo \###
+## foo #\##
+# foo \#
+<<<
+<h3>foo ###</h3>
+<h2>foo ###</h2>
+<h1>foo #</h1>
+>>> ATX headings - 47
+****
+## foo
+****
+<<<
+<hr />
+<h2>foo</h2>
+<hr />
+>>> ATX headings - 48
+Foo bar
+# baz
+Bar foo
+<<<
+<p>Foo bar</p>
+<h1>baz</h1>
+<p>Bar foo</p>
+>>> ATX headings - 49
+##
+#
+### ###
+<<<
+<h2></h2>
+<h1></h1>
+<h3></h3>
diff --git a/pkgs/markdown/test/gfm/autolinks.unit b/pkgs/markdown/test/gfm/autolinks.unit
new file mode 100644
index 0000000..6df5296
--- /dev/null
+++ b/pkgs/markdown/test/gfm/autolinks.unit
@@ -0,0 +1,76 @@
+>>> Autolinks - 602
+<http://foo.bar.baz>
+<<<
+<p><a href="http://foo.bar.baz">http://foo.bar.baz</a></p>
+>>> Autolinks - 603
+<http://foo.bar.baz/test?q=hello&id=22&boolean>
+<<<
+<p><a href="http://foo.bar.baz/test?q=hello&id=22&boolean">http://foo.bar.baz/test?q=hello&id=22&boolean</a></p>
+>>> Autolinks - 604
+<irc://foo.bar:2233/baz>
+<<<
+<p><a href="irc://foo.bar:2233/baz">irc://foo.bar:2233/baz</a></p>
+>>> Autolinks - 605
+<MAILTO:FOO@BAR.BAZ>
+<<<
+<p><a href="MAILTO:FOO@BAR.BAZ">MAILTO:FOO@BAR.BAZ</a></p>
+>>> Autolinks - 606
+<a+b+c:d>
+<<<
+<p><a href="a+b+c:d">a+b+c:d</a></p>
+>>> Autolinks - 607
+<made-up-scheme://foo,bar>
+<<<
+<p><a href="made-up-scheme://foo,bar">made-up-scheme://foo,bar</a></p>
+>>> Autolinks - 608
+<http://../>
+<<<
+<p><a href="http://../">http://../</a></p>
+>>> Autolinks - 609
+<localhost:5001/foo>
+<<<
+<p><a href="localhost:5001/foo">localhost:5001/foo</a></p>
+>>> Autolinks - 610
+<http://foo.bar/baz bim>
+<<<
+<p><http://foo.bar/baz bim></p>
+>>> Autolinks - 611
+<http://example.com/\[\>
+<<<
+<p><a href="http://example.com/%5C%5B%5C">http://example.com/\[\</a></p>
+>>> Autolinks - 612
+<foo@bar.example.com>
+<<<
+<p><a href="mailto:foo@bar.example.com">foo@bar.example.com</a></p>
+>>> Autolinks - 613
+<foo+special@Bar.baz-bar0.com>
+<<<
+<p><a href="mailto:foo+special@Bar.baz-bar0.com">foo+special@Bar.baz-bar0.com</a></p>
+>>> Autolinks - 614
+<foo\+@bar.example.com>
+<<<
+<p><foo+@bar.example.com></p>
+>>> Autolinks - 615
+<>
+<<<
+<p><></p>
+>>> Autolinks - 616
+< http://foo.bar >
+<<<
+<p>< http://foo.bar ></p>
+>>> Autolinks - 617
+<m:abc>
+<<<
+<p><m:abc></p>
+>>> Autolinks - 618
+<foo.bar.baz>
+<<<
+<p><foo.bar.baz></p>
+>>> Autolinks - 619
+http://example.com
+<<<
+<p>http://example.com</p>
+>>> Autolinks - 620
+foo@bar.example.com
+<<<
+<p>foo@bar.example.com</p>
diff --git a/pkgs/markdown/test/gfm/autolinks_extension.unit b/pkgs/markdown/test/gfm/autolinks_extension.unit
new file mode 100644
index 0000000..ff69a53
--- /dev/null
+++ b/pkgs/markdown/test/gfm/autolinks_extension.unit
@@ -0,0 +1,74 @@
+>>> Autolinks (extension) - 621
+www.commonmark.org
+<<<
+<p><a href="http://www.commonmark.org">www.commonmark.org</a></p>
+>>> Autolinks (extension) - 622
+Visit www.commonmark.org/help for more information.
+<<<
+<p>Visit <a href="http://www.commonmark.org/help">www.commonmark.org/help</a> for more information.</p>
+>>> Autolinks (extension) - 623
+Visit www.commonmark.org.
+
+Visit www.commonmark.org/a.b.
+<<<
+<p>Visit <a href="http://www.commonmark.org">www.commonmark.org</a>.</p>
+<p>Visit <a href="http://www.commonmark.org/a.b">www.commonmark.org/a.b</a>.</p>
+>>> Autolinks (extension) - 624
+www.google.com/search?q=Markup+(business)
+
+www.google.com/search?q=Markup+(business)))
+
+(www.google.com/search?q=Markup+(business))
+
+(www.google.com/search?q=Markup+(business)
+<<<
+<p><a href="http://www.google.com/search?q=Markup+(business)">www.google.com/search?q=Markup+(business)</a></p>
+<p><a href="http://www.google.com/search?q=Markup+(business)">www.google.com/search?q=Markup+(business)</a>))</p>
+<p>(<a href="http://www.google.com/search?q=Markup+(business)">www.google.com/search?q=Markup+(business)</a>)</p>
+<p>(<a href="http://www.google.com/search?q=Markup+(business)">www.google.com/search?q=Markup+(business)</a></p>
+>>> Autolinks (extension) - 625
+www.google.com/search?q=(business))+ok
+<<<
+<p><a href="http://www.google.com/search?q=(business))+ok">www.google.com/search?q=(business))+ok</a></p>
+>>> Autolinks (extension) - 626
+www.google.com/search?q=commonmark&hl=en
+
+www.google.com/search?q=commonmark&hl;
+<<<
+<p><a href="http://www.google.com/search?q=commonmark&hl=en">www.google.com/search?q=commonmark&hl=en</a></p>
+<p><a href="http://www.google.com/search?q=commonmark">www.google.com/search?q=commonmark</a>&hl;</p>
+>>> Autolinks (extension) - 627
+www.commonmark.org/he<lp
+<<<
+<p><a href="http://www.commonmark.org/he">www.commonmark.org/he</a><lp</p>
+>>> Autolinks (extension) - 628
+http://commonmark.org
+
+(Visit https://encrypted.google.com/search?q=Markup+(business))
+
+Anonymous FTP is available at ftp://foo.bar.baz.
+<<<
+<p><a href="http://commonmark.org">http://commonmark.org</a></p>
+<p>(Visit <a href="https://encrypted.google.com/search?q=Markup+(business)">https://encrypted.google.com/search?q=Markup+(business)</a>)</p>
+<p>Anonymous FTP is available at <a href="ftp://foo.bar.baz">ftp://foo.bar.baz</a>.</p>
+>>> Autolinks (extension) - 629
+foo@bar.baz
+<<<
+<p><a href="mailto:foo@bar.baz">foo@bar.baz</a></p>
+>>> Autolinks (extension) - 630
+hello@mail+xyz.example isn't valid, but hello+xyz@mail.example is.
+<<<
+<p>hello@mail+xyz.example isn't valid, but <a href="mailto:hello+xyz@mail.example">hello+xyz@mail.example</a> is.</p>
+>>> Autolinks (extension) - 631
+a.b-c_d@a.b
+
+a.b-c_d@a.b.
+
+a.b-c_d@a.b-
+
+a.b-c_d@a.b_
+<<<
+<p><a href="mailto:a.b-c_d@a.b">a.b-c_d@a.b</a></p>
+<p><a href="mailto:a.b-c_d@a.b">a.b-c_d@a.b</a>.</p>
+<p>a.b-c_d@a.b-</p>
+<p>a.b-c_d@a.b_</p>
diff --git a/pkgs/markdown/test/gfm/backslash_escapes.unit b/pkgs/markdown/test/gfm/backslash_escapes.unit
new file mode 100644
index 0000000..0e9074a
--- /dev/null
+++ b/pkgs/markdown/test/gfm/backslash_escapes.unit
@@ -0,0 +1,79 @@
+>>> Backslash escapes - 308
+\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\`\{\|\}\~
+<<<
+<p>!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~</p>
+>>> Backslash escapes - 309
+\ \A\a\ \3\φ\«
+<<<
+<p>\ \A\a\ \3\φ\«</p>
+>>> Backslash escapes - 310
+\*not emphasized*
+\<br/> not a tag
+\[not a link](/foo)
+\`not code`
+1\. not a list
+\* not a list
+\# not a heading
+\[foo]: /url "not a reference"
+\ö not a character entity
+<<<
+<p>*not emphasized*
+<br/> not a tag
+[not a link](/foo)
+`not code`
+1. not a list
+* not a list
+# not a heading
+[foo]: /url "not a reference"
+&ouml; not a character entity</p>
+>>> Backslash escapes - 311
+\\*emphasis*
+<<<
+<p>\<em>emphasis</em></p>
+>>> Backslash escapes - 312
+foo\
+bar
+<<<
+<p>foo<br />
+bar</p>
+>>> Backslash escapes - 313
+`` \[\` ``
+<<<
+<p><code>\[\`</code></p>
+>>> Backslash escapes - 314
+ \[\]
+<<<
+<pre><code>\[\]
+</code></pre>
+>>> Backslash escapes - 315
+~~~
+\[\]
+~~~
+<<<
+<pre><code>\[\]
+</code></pre>
+>>> Backslash escapes - 316
+<http://example.com?find=\*>
+<<<
+<p><a href="http://example.com?find=%5C*">http://example.com?find=\*</a></p>
+>>> Backslash escapes - 317
+<a href="/bar\/)">
+<<<
+<a href="/bar\/)">
+>>> Backslash escapes - 318
+[foo](/bar\* "ti\*tle")
+<<<
+<p><a href="/bar*" title="ti*tle">foo</a></p>
+>>> Backslash escapes - 319
+[foo]
+
+[foo]: /bar\* "ti\*tle"
+<<<
+<p><a href="/bar*" title="ti*tle">foo</a></p>
+>>> Backslash escapes - 320
+``` foo\+bar
+foo
+```
+<<<
+<pre><code class="language-foo+bar">foo
+</code></pre>
diff --git a/pkgs/markdown/test/gfm/blank_lines.unit b/pkgs/markdown/test/gfm/blank_lines.unit
new file mode 100644
index 0000000..be24ab7
--- /dev/null
+++ b/pkgs/markdown/test/gfm/blank_lines.unit
@@ -0,0 +1,12 @@
+>>> Blank lines - 197
+
+
+aaa
+
+
+# aaa
+
+
+<<<
+<p>aaa</p>
+<h1>aaa</h1>
diff --git a/pkgs/markdown/test/gfm/block_quotes.unit b/pkgs/markdown/test/gfm/block_quotes.unit
new file mode 100644
index 0000000..50d8757
--- /dev/null
+++ b/pkgs/markdown/test/gfm/block_quotes.unit
@@ -0,0 +1,239 @@
+>>> Block quotes - 206
+> # Foo
+> bar
+> baz
+<<<
+<blockquote>
+<h1>Foo</h1>
+<p>bar
+baz</p>
+</blockquote>
+>>> Block quotes - 207
+># Foo
+>bar
+> baz
+<<<
+<blockquote>
+<h1>Foo</h1>
+<p>bar
+baz</p>
+</blockquote>
+>>> Block quotes - 208
+ > # Foo
+ > bar
+ > baz
+<<<
+<blockquote>
+<h1>Foo</h1>
+<p>bar
+baz</p>
+</blockquote>
+>>> Block quotes - 209
+ > # Foo
+ > bar
+ > baz
+<<<
+<pre><code>> # Foo
+> bar
+> baz
+</code></pre>
+>>> Block quotes - 210
+> # Foo
+> bar
+baz
+<<<
+<blockquote>
+<h1>Foo</h1>
+<p>bar
+baz</p>
+</blockquote>
+>>> Block quotes - 211
+> bar
+baz
+> foo
+<<<
+<blockquote>
+<p>bar
+baz
+foo</p>
+</blockquote>
+>>> Block quotes - 212
+> foo
+---
+<<<
+<blockquote>
+<p>foo</p>
+</blockquote>
+<hr />
+>>> Block quotes - 213
+> - foo
+- bar
+<<<
+<blockquote>
+<ul>
+<li>foo</li>
+</ul>
+</blockquote>
+<ul>
+<li>bar</li>
+</ul>
+>>> Block quotes - 214
+> foo
+ bar
+<<<
+<blockquote>
+<pre><code>foo
+</code></pre>
+</blockquote>
+<pre><code>bar
+</code></pre>
+>>> Block quotes - 215
+> ```
+foo
+```
+<<<
+<blockquote>
+<pre><code></code></pre>
+</blockquote>
+<p>foo</p>
+<pre><code></code></pre>
+>>> Block quotes - 216
+> foo
+ - bar
+<<<
+<blockquote>
+<p>foo
+- bar</p>
+</blockquote>
+>>> Block quotes - 217
+>
+<<<
+<blockquote>
+</blockquote>
+>>> Block quotes - 218
+>
+>
+>
+<<<
+<blockquote>
+</blockquote>
+>>> Block quotes - 219
+>
+> foo
+>
+<<<
+<blockquote>
+<p>foo</p>
+</blockquote>
+>>> Block quotes - 220
+> foo
+
+> bar
+<<<
+<blockquote>
+<p>foo</p>
+</blockquote>
+<blockquote>
+<p>bar</p>
+</blockquote>
+>>> Block quotes - 221
+> foo
+> bar
+<<<
+<blockquote>
+<p>foo
+bar</p>
+</blockquote>
+>>> Block quotes - 222
+> foo
+>
+> bar
+<<<
+<blockquote>
+<p>foo</p>
+<p>bar</p>
+</blockquote>
+>>> Block quotes - 223
+foo
+> bar
+<<<
+<p>foo</p>
+<blockquote>
+<p>bar</p>
+</blockquote>
+>>> Block quotes - 224
+> aaa
+***
+> bbb
+<<<
+<blockquote>
+<p>aaa</p>
+</blockquote>
+<hr />
+<blockquote>
+<p>bbb</p>
+</blockquote>
+>>> Block quotes - 225
+> bar
+baz
+<<<
+<blockquote>
+<p>bar
+baz</p>
+</blockquote>
+>>> Block quotes - 226
+> bar
+
+baz
+<<<
+<blockquote>
+<p>bar</p>
+</blockquote>
+<p>baz</p>
+>>> Block quotes - 227
+> bar
+>
+baz
+<<<
+<blockquote>
+<p>bar</p>
+</blockquote>
+<p>baz</p>
+>>> Block quotes - 228
+> > > foo
+bar
+<<<
+<blockquote>
+<blockquote>
+<blockquote>
+<p>foo
+bar</p>
+</blockquote>
+</blockquote>
+</blockquote>
+>>> Block quotes - 229
+>>> foo
+> bar
+>>baz
+<<<
+<blockquote>
+<blockquote>
+<blockquote>
+<p>foo
+bar
+baz</p>
+</blockquote>
+</blockquote>
+</blockquote>
+>>> Block quotes - 230
+> code
+
+> not code
+<<<
+<blockquote>
+<pre><code>code
+</code></pre>
+</blockquote>
+<blockquote>
+<p>not code</p>
+</blockquote>
diff --git a/pkgs/markdown/test/gfm/code_spans.unit b/pkgs/markdown/test/gfm/code_spans.unit
new file mode 100644
index 0000000..68a4b3a
--- /dev/null
+++ b/pkgs/markdown/test/gfm/code_spans.unit
@@ -0,0 +1,97 @@
+>>> Code spans - 338
+`foo`
+<<<
+<p><code>foo</code></p>
+>>> Code spans - 339
+`` foo ` bar ``
+<<<
+<p><code>foo ` bar</code></p>
+>>> Code spans - 340
+` `` `
+<<<
+<p><code>``</code></p>
+>>> Code spans - 341
+` `` `
+<<<
+<p><code> `` </code></p>
+>>> Code spans - 342
+` a`
+<<<
+<p><code> a</code></p>
+>>> Code spans - 343
+` b `
+<<<
+<p><code> b </code></p>
+>>> Code spans - 344
+` `
+` `
+<<<
+<p><code> </code>
+<code> </code></p>
+>>> Code spans - 345
+``
+foo
+bar
+baz
+``
+<<<
+<p><code>foo bar baz</code></p>
+>>> Code spans - 346
+``
+foo
+``
+<<<
+<p><code>foo </code></p>
+>>> Code spans - 347
+`foo bar
+baz`
+<<<
+<p><code>foo bar baz</code></p>
+>>> Code spans - 348
+`foo\`bar`
+<<<
+<p><code>foo\</code>bar`</p>
+>>> Code spans - 349
+``foo`bar``
+<<<
+<p><code>foo`bar</code></p>
+>>> Code spans - 350
+` foo `` bar `
+<<<
+<p><code>foo `` bar</code></p>
+>>> Code spans - 351
+*foo`*`
+<<<
+<p>*foo<code>*</code></p>
+>>> Code spans - 352
+[not a `link](/foo`)
+<<<
+<p>[not a <code>link](/foo</code>)</p>
+>>> Code spans - 353
+`<a href="`">`
+<<<
+<p><code><a href="</code>">`</p>
+>>> Code spans - 354
+<a href="`">`
+<<<
+<p><a href="`">`</p>
+>>> Code spans - 355
+`<http://foo.bar.`baz>`
+<<<
+<p><code><http://foo.bar.</code>baz>`</p>
+>>> Code spans - 356
+<http://foo.bar.`baz>`
+<<<
+<p><a href="http://foo.bar.%60baz">http://foo.bar.`baz</a>`</p>
+>>> Code spans - 357
+```foo``
+<<<
+<p>```foo``</p>
+>>> Code spans - 358
+`foo
+<<<
+<p>`foo</p>
+>>> Code spans - 359
+`foo``bar``
+<<<
+<p>`foo<code>bar</code></p>
diff --git a/pkgs/markdown/test/gfm/disallowed_raw_html_extension.unit b/pkgs/markdown/test/gfm/disallowed_raw_html_extension.unit
new file mode 100644
index 0000000..34cc396
--- /dev/null
+++ b/pkgs/markdown/test/gfm/disallowed_raw_html_extension.unit
@@ -0,0 +1,11 @@
+>>> Disallowed Raw HTML (extension) - 652
+<strong> <title> <style> <em>
+
+<blockquote>
+ <xmp> is disallowed. <XMP> is also disallowed.
+</blockquote>
+<<<
+<p><strong> <title> <style> <em></p>
+<blockquote>
+<xmp> is disallowed. <XMP> is also disallowed.
+</blockquote>
diff --git a/pkgs/markdown/test/gfm/emphasis_and_strong_emphasis.unit b/pkgs/markdown/test/gfm/emphasis_and_strong_emphasis.unit
new file mode 100644
index 0000000..b6e8155
--- /dev/null
+++ b/pkgs/markdown/test/gfm/emphasis_and_strong_emphasis.unit
@@ -0,0 +1,536 @@
+>>> Emphasis and strong emphasis - 360
+*foo bar*
+<<<
+<p><em>foo bar</em></p>
+>>> Emphasis and strong emphasis - 361
+a * foo bar*
+<<<
+<p>a * foo bar*</p>
+>>> Emphasis and strong emphasis - 362
+a*"foo"*
+<<<
+<p>a*"foo"*</p>
+>>> Emphasis and strong emphasis - 363
+* a *
+<<<
+<p>* a *</p>
+>>> Emphasis and strong emphasis - 364
+foo*bar*
+<<<
+<p>foo<em>bar</em></p>
+>>> Emphasis and strong emphasis - 365
+5*6*78
+<<<
+<p>5<em>6</em>78</p>
+>>> Emphasis and strong emphasis - 366
+_foo bar_
+<<<
+<p><em>foo bar</em></p>
+>>> Emphasis and strong emphasis - 367
+_ foo bar_
+<<<
+<p>_ foo bar_</p>
+>>> Emphasis and strong emphasis - 368
+a_"foo"_
+<<<
+<p>a_"foo"_</p>
+>>> Emphasis and strong emphasis - 369
+foo_bar_
+<<<
+<p>foo_bar_</p>
+>>> Emphasis and strong emphasis - 370
+5_6_78
+<<<
+<p>5_6_78</p>
+>>> Emphasis and strong emphasis - 371
+пристаням_стремятся_
+<<<
+<p>пристаням_стремятся_</p>
+>>> Emphasis and strong emphasis - 372
+aa_"bb"_cc
+<<<
+<p>aa_"bb"_cc</p>
+>>> Emphasis and strong emphasis - 373
+foo-_(bar)_
+<<<
+<p>foo-<em>(bar)</em></p>
+>>> Emphasis and strong emphasis - 374
+_foo*
+<<<
+<p>_foo*</p>
+>>> Emphasis and strong emphasis - 375
+*foo bar *
+<<<
+<p>*foo bar *</p>
+>>> Emphasis and strong emphasis - 376
+*foo bar
+*
+<<<
+<p>*foo bar
+*</p>
+>>> Emphasis and strong emphasis - 377
+*(*foo)
+<<<
+<p>*(*foo)</p>
+>>> Emphasis and strong emphasis - 378
+*(*foo*)*
+<<<
+<p><em>(<em>foo</em>)</em></p>
+>>> Emphasis and strong emphasis - 379
+*foo*bar
+<<<
+<p><em>foo</em>bar</p>
+>>> Emphasis and strong emphasis - 380
+_foo bar _
+<<<
+<p>_foo bar _</p>
+>>> Emphasis and strong emphasis - 381
+_(_foo)
+<<<
+<p>_(_foo)</p>
+>>> Emphasis and strong emphasis - 382
+_(_foo_)_
+<<<
+<p><em>(<em>foo</em>)</em></p>
+>>> Emphasis and strong emphasis - 383
+_foo_bar
+<<<
+<p>_foo_bar</p>
+>>> Emphasis and strong emphasis - 384
+_пристаням_стремятся
+<<<
+<p>_пристаням_стремятся</p>
+>>> Emphasis and strong emphasis - 385
+_foo_bar_baz_
+<<<
+<p><em>foo_bar_baz</em></p>
+>>> Emphasis and strong emphasis - 386
+_(bar)_.
+<<<
+<p><em>(bar)</em>.</p>
+>>> Emphasis and strong emphasis - 387
+**foo bar**
+<<<
+<p><strong>foo bar</strong></p>
+>>> Emphasis and strong emphasis - 388
+** foo bar**
+<<<
+<p>** foo bar**</p>
+>>> Emphasis and strong emphasis - 389
+a**"foo"**
+<<<
+<p>a**"foo"**</p>
+>>> Emphasis and strong emphasis - 390
+foo**bar**
+<<<
+<p>foo<strong>bar</strong></p>
+>>> Emphasis and strong emphasis - 391
+__foo bar__
+<<<
+<p><strong>foo bar</strong></p>
+>>> Emphasis and strong emphasis - 392
+__ foo bar__
+<<<
+<p>__ foo bar__</p>
+>>> Emphasis and strong emphasis - 393
+__
+foo bar__
+<<<
+<p>__
+foo bar__</p>
+>>> Emphasis and strong emphasis - 394
+a__"foo"__
+<<<
+<p>a__"foo"__</p>
+>>> Emphasis and strong emphasis - 395
+foo__bar__
+<<<
+<p>foo__bar__</p>
+>>> Emphasis and strong emphasis - 396
+5__6__78
+<<<
+<p>5__6__78</p>
+>>> Emphasis and strong emphasis - 397
+пристаням__стремятся__
+<<<
+<p>пристаням__стремятся__</p>
+>>> Emphasis and strong emphasis - 398
+__foo, __bar__, baz__
+<<<
+<p><strong>foo, <strong>bar</strong>, baz</strong></p>
+>>> Emphasis and strong emphasis - 399
+foo-__(bar)__
+<<<
+<p>foo-<strong>(bar)</strong></p>
+>>> Emphasis and strong emphasis - 400
+**foo bar **
+<<<
+<p>**foo bar **</p>
+>>> Emphasis and strong emphasis - 401
+**(**foo)
+<<<
+<p>**(**foo)</p>
+>>> Emphasis and strong emphasis - 402
+*(**foo**)*
+<<<
+<p><em>(<strong>foo</strong>)</em></p>
+>>> Emphasis and strong emphasis - 403
+**Gomphocarpus (*Gomphocarpus physocarpus*, syn.
+*Asclepias physocarpa*)**
+<<<
+<p><strong>Gomphocarpus (<em>Gomphocarpus physocarpus</em>, syn.
+<em>Asclepias physocarpa</em>)</strong></p>
+>>> Emphasis and strong emphasis - 404
+**foo "*bar*" foo**
+<<<
+<p><strong>foo "<em>bar</em>" foo</strong></p>
+>>> Emphasis and strong emphasis - 405
+**foo**bar
+<<<
+<p><strong>foo</strong>bar</p>
+>>> Emphasis and strong emphasis - 406
+__foo bar __
+<<<
+<p>__foo bar __</p>
+>>> Emphasis and strong emphasis - 407
+__(__foo)
+<<<
+<p>__(__foo)</p>
+>>> Emphasis and strong emphasis - 408
+_(__foo__)_
+<<<
+<p><em>(<strong>foo</strong>)</em></p>
+>>> Emphasis and strong emphasis - 409
+__foo__bar
+<<<
+<p>__foo__bar</p>
+>>> Emphasis and strong emphasis - 410
+__пристаням__стремятся
+<<<
+<p>__пристаням__стремятся</p>
+>>> Emphasis and strong emphasis - 411
+__foo__bar__baz__
+<<<
+<p><strong>foo__bar__baz</strong></p>
+>>> Emphasis and strong emphasis - 412
+__(bar)__.
+<<<
+<p><strong>(bar)</strong>.</p>
+>>> Emphasis and strong emphasis - 413
+*foo [bar](/url)*
+<<<
+<p><em>foo <a href="/url">bar</a></em></p>
+>>> Emphasis and strong emphasis - 414
+*foo
+bar*
+<<<
+<p><em>foo
+bar</em></p>
+>>> Emphasis and strong emphasis - 415
+_foo __bar__ baz_
+<<<
+<p><em>foo <strong>bar</strong> baz</em></p>
+>>> Emphasis and strong emphasis - 416
+_foo _bar_ baz_
+<<<
+<p><em>foo <em>bar</em> baz</em></p>
+>>> Emphasis and strong emphasis - 417
+__foo_ bar_
+<<<
+<p><em><em>foo</em> bar</em></p>
+>>> Emphasis and strong emphasis - 418
+*foo *bar**
+<<<
+<p><em>foo <em>bar</em></em></p>
+>>> Emphasis and strong emphasis - 419
+*foo **bar** baz*
+<<<
+<p><em>foo <strong>bar</strong> baz</em></p>
+>>> Emphasis and strong emphasis - 420
+*foo**bar**baz*
+<<<
+<p><em>foo<strong>bar</strong>baz</em></p>
+>>> Emphasis and strong emphasis - 421
+*foo**bar*
+<<<
+<p><em>foo**bar</em></p>
+>>> Emphasis and strong emphasis - 422
+***foo** bar*
+<<<
+<p><em><strong>foo</strong> bar</em></p>
+>>> Emphasis and strong emphasis - 423
+*foo **bar***
+<<<
+<p><em>foo <strong>bar</strong></em></p>
+>>> Emphasis and strong emphasis - 424
+*foo**bar***
+<<<
+<p><em>foo<strong>bar</strong></em></p>
+>>> Emphasis and strong emphasis - 425
+foo***bar***baz
+<<<
+<p>foo<em><strong>bar</strong></em>baz</p>
+>>> Emphasis and strong emphasis - 426
+foo******bar*********baz
+<<<
+<p>foo<strong><strong><strong>bar</strong></strong></strong>***baz</p>
+>>> Emphasis and strong emphasis - 427
+*foo **bar *baz* bim** bop*
+<<<
+<p><em>foo <strong>bar <em>baz</em> bim</strong> bop</em></p>
+>>> Emphasis and strong emphasis - 428
+*foo [*bar*](/url)*
+<<<
+<p><em>foo <a href="/url"><em>bar</em></a></em></p>
+>>> Emphasis and strong emphasis - 429
+** is not an empty emphasis
+<<<
+<p>** is not an empty emphasis</p>
+>>> Emphasis and strong emphasis - 430
+**** is not an empty strong emphasis
+<<<
+<p>**** is not an empty strong emphasis</p>
+>>> Emphasis and strong emphasis - 431
+**foo [bar](/url)**
+<<<
+<p><strong>foo <a href="/url">bar</a></strong></p>
+>>> Emphasis and strong emphasis - 432
+**foo
+bar**
+<<<
+<p><strong>foo
+bar</strong></p>
+>>> Emphasis and strong emphasis - 433
+__foo _bar_ baz__
+<<<
+<p><strong>foo <em>bar</em> baz</strong></p>
+>>> Emphasis and strong emphasis - 434
+__foo __bar__ baz__
+<<<
+<p><strong>foo <strong>bar</strong> baz</strong></p>
+>>> Emphasis and strong emphasis - 435
+____foo__ bar__
+<<<
+<p><strong><strong>foo</strong> bar</strong></p>
+>>> Emphasis and strong emphasis - 436
+**foo **bar****
+<<<
+<p><strong>foo <strong>bar</strong></strong></p>
+>>> Emphasis and strong emphasis - 437
+**foo *bar* baz**
+<<<
+<p><strong>foo <em>bar</em> baz</strong></p>
+>>> Emphasis and strong emphasis - 438
+**foo*bar*baz**
+<<<
+<p><strong>foo<em>bar</em>baz</strong></p>
+>>> Emphasis and strong emphasis - 439
+***foo* bar**
+<<<
+<p><strong><em>foo</em> bar</strong></p>
+>>> Emphasis and strong emphasis - 440
+**foo *bar***
+<<<
+<p><strong>foo <em>bar</em></strong></p>
+>>> Emphasis and strong emphasis - 441
+**foo *bar **baz**
+bim* bop**
+<<<
+<p><strong>foo <em>bar <strong>baz</strong>
+bim</em> bop</strong></p>
+>>> Emphasis and strong emphasis - 442
+**foo [*bar*](/url)**
+<<<
+<p><strong>foo <a href="/url"><em>bar</em></a></strong></p>
+>>> Emphasis and strong emphasis - 443
+__ is not an empty emphasis
+<<<
+<p>__ is not an empty emphasis</p>
+>>> Emphasis and strong emphasis - 444
+____ is not an empty strong emphasis
+<<<
+<p>____ is not an empty strong emphasis</p>
+>>> Emphasis and strong emphasis - 445
+foo ***
+<<<
+<p>foo ***</p>
+>>> Emphasis and strong emphasis - 446
+foo *\**
+<<<
+<p>foo <em>*</em></p>
+>>> Emphasis and strong emphasis - 447
+foo *_*
+<<<
+<p>foo <em>_</em></p>
+>>> Emphasis and strong emphasis - 448
+foo *****
+<<<
+<p>foo *****</p>
+>>> Emphasis and strong emphasis - 449
+foo **\***
+<<<
+<p>foo <strong>*</strong></p>
+>>> Emphasis and strong emphasis - 450
+foo **_**
+<<<
+<p>foo <strong>_</strong></p>
+>>> Emphasis and strong emphasis - 451
+**foo*
+<<<
+<p>*<em>foo</em></p>
+>>> Emphasis and strong emphasis - 452
+*foo**
+<<<
+<p><em>foo</em>*</p>
+>>> Emphasis and strong emphasis - 453
+***foo**
+<<<
+<p>*<strong>foo</strong></p>
+>>> Emphasis and strong emphasis - 454
+****foo*
+<<<
+<p>***<em>foo</em></p>
+>>> Emphasis and strong emphasis - 455
+**foo***
+<<<
+<p><strong>foo</strong>*</p>
+>>> Emphasis and strong emphasis - 456
+*foo****
+<<<
+<p><em>foo</em>***</p>
+>>> Emphasis and strong emphasis - 457
+foo ___
+<<<
+<p>foo ___</p>
+>>> Emphasis and strong emphasis - 458
+foo _\__
+<<<
+<p>foo <em>_</em></p>
+>>> Emphasis and strong emphasis - 459
+foo _*_
+<<<
+<p>foo <em>*</em></p>
+>>> Emphasis and strong emphasis - 460
+foo _____
+<<<
+<p>foo _____</p>
+>>> Emphasis and strong emphasis - 461
+foo __\___
+<<<
+<p>foo <strong>_</strong></p>
+>>> Emphasis and strong emphasis - 462
+foo __*__
+<<<
+<p>foo <strong>*</strong></p>
+>>> Emphasis and strong emphasis - 463
+__foo_
+<<<
+<p>_<em>foo</em></p>
+>>> Emphasis and strong emphasis - 464
+_foo__
+<<<
+<p><em>foo</em>_</p>
+>>> Emphasis and strong emphasis - 465
+___foo__
+<<<
+<p>_<strong>foo</strong></p>
+>>> Emphasis and strong emphasis - 466
+____foo_
+<<<
+<p>___<em>foo</em></p>
+>>> Emphasis and strong emphasis - 467
+__foo___
+<<<
+<p><strong>foo</strong>_</p>
+>>> Emphasis and strong emphasis - 468
+_foo____
+<<<
+<p><em>foo</em>___</p>
+>>> Emphasis and strong emphasis - 469
+**foo**
+<<<
+<p><strong>foo</strong></p>
+>>> Emphasis and strong emphasis - 470
+*_foo_*
+<<<
+<p><em><em>foo</em></em></p>
+>>> Emphasis and strong emphasis - 471
+__foo__
+<<<
+<p><strong>foo</strong></p>
+>>> Emphasis and strong emphasis - 472
+_*foo*_
+<<<
+<p><em><em>foo</em></em></p>
+>>> Emphasis and strong emphasis - 473
+****foo****
+<<<
+<p><strong><strong>foo</strong></strong></p>
+>>> Emphasis and strong emphasis - 474
+____foo____
+<<<
+<p><strong><strong>foo</strong></strong></p>
+>>> Emphasis and strong emphasis - 475
+******foo******
+<<<
+<p><strong><strong><strong>foo</strong></strong></strong></p>
+>>> Emphasis and strong emphasis - 476
+***foo***
+<<<
+<p><em><strong>foo</strong></em></p>
+>>> Emphasis and strong emphasis - 477
+_____foo_____
+<<<
+<p><em><strong><strong>foo</strong></strong></em></p>
+>>> Emphasis and strong emphasis - 478
+*foo _bar* baz_
+<<<
+<p><em>foo _bar</em> baz_</p>
+>>> Emphasis and strong emphasis - 479
+*foo __bar *baz bim__ bam*
+<<<
+<p><em>foo <strong>bar *baz bim</strong> bam</em></p>
+>>> Emphasis and strong emphasis - 480
+**foo **bar baz**
+<<<
+<p>**foo <strong>bar baz</strong></p>
+>>> Emphasis and strong emphasis - 481
+*foo *bar baz*
+<<<
+<p>*foo <em>bar baz</em></p>
+>>> Emphasis and strong emphasis - 482
+*[bar*](/url)
+<<<
+<p>*<a href="/url">bar*</a></p>
+>>> Emphasis and strong emphasis - 483
+_foo [bar_](/url)
+<<<
+<p>_foo <a href="/url">bar_</a></p>
+>>> Emphasis and strong emphasis - 484
+*<img src="foo" title="*"/>
+<<<
+<p>*<img src="foo" title="*"/></p>
+>>> Emphasis and strong emphasis - 485
+**<a href="**">
+<<<
+<p>**<a href="**"></p>
+>>> Emphasis and strong emphasis - 486
+__<a href="__">
+<<<
+<p>__<a href="__"></p>
+>>> Emphasis and strong emphasis - 487
+*a `*`*
+<<<
+<p><em>a <code>*</code></em></p>
+>>> Emphasis and strong emphasis - 488
+_a `_`_
+<<<
+<p><em>a <code>_</code></em></p>
+>>> Emphasis and strong emphasis - 489
+**a<http://foo.bar/?q=**>
+<<<
+<p>**a<a href="http://foo.bar/?q=**">http://foo.bar/?q=**</a></p>
+>>> Emphasis and strong emphasis - 490
+__a<http://foo.bar/?q=__>
+<<<
+<p>__a<a href="http://foo.bar/?q=__">http://foo.bar/?q=__</a></p>
diff --git a/pkgs/markdown/test/gfm/entity_and_numeric_character_references.unit b/pkgs/markdown/test/gfm/entity_and_numeric_character_references.unit
new file mode 100644
index 0000000..2a6248e
--- /dev/null
+++ b/pkgs/markdown/test/gfm/entity_and_numeric_character_references.unit
@@ -0,0 +1,93 @@
+>>> Entity and numeric character references - 321
+ & © Æ Ď
+¾ ℋ ⅆ
+∲ ≧̸
+<<<
+<p>& © Æ Ď
+¾ ℋ ⅆ
+∲ ≧̸</p>
+>>> Entity and numeric character references - 322
+# Ӓ Ϡ �
+<<<
+<p># Ӓ Ϡ �</p>
+>>> Entity and numeric character references - 323
+" ആ ಫ
+<<<
+<p>" ആ ಫ</p>
+>>> Entity and numeric character references - 324
+  &x; &#; &#x;
+�
+&#abcdef0;
+&ThisIsNotDefined; &hi?;
+<<<
+<p>&nbsp &x; &#; &#x;
+&#987654321;
+&#abcdef0;
+&ThisIsNotDefined; &hi?;</p>
+>>> Entity and numeric character references - 325
+©
+<<<
+<p>&copy</p>
+>>> Entity and numeric character references - 326
+&MadeUpEntity;
+<<<
+<p>&MadeUpEntity;</p>
+>>> Entity and numeric character references - 327
+<a href="öö.html">
+<<<
+<a href="öö.html">
+>>> Entity and numeric character references - 328
+[foo](/föö "föö")
+<<<
+<p><a href="/f%C3%B6%C3%B6" title="föö">foo</a></p>
+>>> Entity and numeric character references - 329
+[foo]
+
+[foo]: /föö "föö"
+<<<
+<p><a href="/f%C3%B6%C3%B6" title="föö">foo</a></p>
+>>> Entity and numeric character references - 330
+``` föö
+foo
+```
+<<<
+<pre><code class="language-föö">foo
+</code></pre>
+>>> Entity and numeric character references - 331
+`föö`
+<<<
+<p><code>f&ouml;&ouml;</code></p>
+>>> Entity and numeric character references - 332
+ föfö
+<<<
+<pre><code>f&ouml;f&ouml;
+</code></pre>
+>>> Entity and numeric character references - 333
+*foo*
+*foo*
+<<<
+<p>*foo*
+<em>foo</em></p>
+>>> Entity and numeric character references - 334
+* foo
+
+* foo
+<<<
+<p>* foo</p>
+<ul>
+<li>foo</li>
+</ul>
+>>> Entity and numeric character references - 335
+foo bar
+<<<
+<p>foo
+
+bar</p>
+>>> Entity and numeric character references - 336
+	foo
+<<<
+<p>foo</p>
+>>> Entity and numeric character references - 337
+[a](url "tit")
+<<<
+<p>[a](url "tit")</p>
diff --git a/pkgs/markdown/test/gfm/fenced_code_blocks.unit b/pkgs/markdown/test/gfm/fenced_code_blocks.unit
new file mode 100644
index 0000000..f6fa843
--- /dev/null
+++ b/pkgs/markdown/test/gfm/fenced_code_blocks.unit
@@ -0,0 +1,245 @@
+>>> Fenced code blocks - 89
+```
+<
+ >
+```
+<<<
+<pre><code><
+ >
+</code></pre>
+>>> Fenced code blocks - 90
+~~~
+<
+ >
+~~~
+<<<
+<pre><code><
+ >
+</code></pre>
+>>> Fenced code blocks - 91
+``
+foo
+``
+<<<
+<p><code>foo</code></p>
+>>> Fenced code blocks - 92
+```
+aaa
+~~~
+```
+<<<
+<pre><code>aaa
+~~~
+</code></pre>
+>>> Fenced code blocks - 93
+~~~
+aaa
+```
+~~~
+<<<
+<pre><code>aaa
+```
+</code></pre>
+>>> Fenced code blocks - 94
+````
+aaa
+```
+``````
+<<<
+<pre><code>aaa
+```
+</code></pre>
+>>> Fenced code blocks - 95
+~~~~
+aaa
+~~~
+~~~~
+<<<
+<pre><code>aaa
+~~~
+</code></pre>
+>>> Fenced code blocks - 96
+```
+<<<
+<pre><code></code></pre>
+>>> Fenced code blocks - 97
+`````
+
+```
+aaa
+<<<
+<pre><code>
+```
+aaa
+</code></pre>
+>>> Fenced code blocks - 98
+> ```
+> aaa
+
+bbb
+<<<
+<blockquote>
+<pre><code>aaa
+</code></pre>
+</blockquote>
+<p>bbb</p>
+>>> Fenced code blocks - 99
+```
+
+
+```
+<<<
+<pre><code>
+
+</code></pre>
+>>> Fenced code blocks - 100
+```
+```
+<<<
+<pre><code></code></pre>
+>>> Fenced code blocks - 101
+ ```
+ aaa
+aaa
+```
+<<<
+<pre><code>aaa
+aaa
+</code></pre>
+>>> Fenced code blocks - 102
+ ```
+aaa
+ aaa
+aaa
+ ```
+<<<
+<pre><code>aaa
+aaa
+aaa
+</code></pre>
+>>> Fenced code blocks - 103
+ ```
+ aaa
+ aaa
+ aaa
+ ```
+<<<
+<pre><code>aaa
+ aaa
+aaa
+</code></pre>
+>>> Fenced code blocks - 104
+ ```
+ aaa
+ ```
+<<<
+<pre><code>```
+aaa
+```
+</code></pre>
+>>> Fenced code blocks - 105
+```
+aaa
+ ```
+<<<
+<pre><code>aaa
+</code></pre>
+>>> Fenced code blocks - 106
+ ```
+aaa
+ ```
+<<<
+<pre><code>aaa
+</code></pre>
+>>> Fenced code blocks - 107
+```
+aaa
+ ```
+<<<
+<pre><code>aaa
+ ```
+</code></pre>
+>>> Fenced code blocks - 108
+``` ```
+aaa
+<<<
+<p><code> </code>
+aaa</p>
+>>> Fenced code blocks - 109
+~~~~~~
+aaa
+~~~ ~~
+<<<
+<pre><code>aaa
+~~~ ~~
+</code></pre>
+>>> Fenced code blocks - 110
+foo
+```
+bar
+```
+baz
+<<<
+<p>foo</p>
+<pre><code>bar
+</code></pre>
+<p>baz</p>
+>>> Fenced code blocks - 111
+foo
+---
+~~~
+bar
+~~~
+# baz
+<<<
+<h2>foo</h2>
+<pre><code>bar
+</code></pre>
+<h1>baz</h1>
+>>> Fenced code blocks - 112
+```ruby
+def foo(x)
+ return 3
+end
+```
+<<<
+<pre><code class="language-ruby">def foo(x)
+ return 3
+end
+</code></pre>
+>>> Fenced code blocks - 113
+~~~~ ruby startline=3 $%@#$
+def foo(x)
+ return 3
+end
+~~~~~~~
+<<<
+<pre><code class="language-ruby">def foo(x)
+ return 3
+end
+</code></pre>
+>>> Fenced code blocks - 114
+````;
+````
+<<<
+<pre><code class="language-;"></code></pre>
+>>> Fenced code blocks - 115
+``` aa ```
+foo
+<<<
+<p><code>aa</code>
+foo</p>
+>>> Fenced code blocks - 116
+~~~ aa ``` ~~~
+foo
+~~~
+<<<
+<pre><code class="language-aa">foo
+</code></pre>
+>>> Fenced code blocks - 117
+```
+``` aaa
+```
+<<<
+<pre><code>``` aaa
+</code></pre>
diff --git a/pkgs/markdown/test/gfm/hard_line_breaks.unit b/pkgs/markdown/test/gfm/hard_line_breaks.unit
new file mode 100644
index 0000000..e8aa5c0
--- /dev/null
+++ b/pkgs/markdown/test/gfm/hard_line_breaks.unit
@@ -0,0 +1,80 @@
+>>> Hard line breaks - 653
+foo
+baz
+<<<
+<p>foo<br />
+baz</p>
+>>> Hard line breaks - 654
+foo\
+baz
+<<<
+<p>foo<br />
+baz</p>
+>>> Hard line breaks - 655
+foo
+baz
+<<<
+<p>foo<br />
+baz</p>
+>>> Hard line breaks - 656
+foo
+ bar
+<<<
+<p>foo<br />
+bar</p>
+>>> Hard line breaks - 657
+foo\
+ bar
+<<<
+<p>foo<br />
+bar</p>
+>>> Hard line breaks - 658
+*foo
+bar*
+<<<
+<p><em>foo<br />
+bar</em></p>
+>>> Hard line breaks - 659
+*foo\
+bar*
+<<<
+<p><em>foo<br />
+bar</em></p>
+>>> Hard line breaks - 660
+`code
+span`
+<<<
+<p><code>code span</code></p>
+>>> Hard line breaks - 661
+`code\
+span`
+<<<
+<p><code>code\ span</code></p>
+>>> Hard line breaks - 662
+<a href="foo
+bar">
+<<<
+<p><a href="foo
+bar"></p>
+>>> Hard line breaks - 663
+<a href="foo\
+bar">
+<<<
+<p><a href="foo\
+bar"></p>
+>>> Hard line breaks - 664
+foo\
+<<<
+<p>foo\</p>
+>>> Hard line breaks - 665
+foo
+<<<
+<p>foo</p>
+>>> Hard line breaks - 666
+### foo\
+<<<
+<h3>foo\</h3>
+>>> Hard line breaks - 667
+### foo
+<<<
+<h3>foo</h3>
diff --git a/pkgs/markdown/test/gfm/html_blocks.unit b/pkgs/markdown/test/gfm/html_blocks.unit
new file mode 100644
index 0000000..1af6420
--- /dev/null
+++ b/pkgs/markdown/test/gfm/html_blocks.unit
@@ -0,0 +1,433 @@
+>>> HTML blocks - 118
+<table><tr><td>
+<pre>
+**Hello**,
+
+_world_.
+</pre>
+</td></tr></table>
+<<<
+<table><tr><td>
+<pre>
+**Hello**,
+<p><em>world</em>.
+</pre></p>
+</td></tr></table>
+>>> HTML blocks - 119
+<table>
+ <tr>
+ <td>
+ hi
+ </td>
+ </tr>
+</table>
+
+okay.
+<<<
+<table>
+ <tr>
+ <td>
+ hi
+ </td>
+ </tr>
+</table>
+<p>okay.</p>
+>>> HTML blocks - 120
+ <div>
+ *hello*
+ <foo><a>
+<<<
+ <div>
+ *hello*
+ <foo><a>
+>>> HTML blocks - 121
+</div>
+*foo*
+<<<
+</div>
+*foo*
+>>> HTML blocks - 122
+<DIV CLASS="foo">
+
+*Markdown*
+
+</DIV>
+<<<
+<DIV CLASS="foo">
+<p><em>Markdown</em></p>
+</DIV>
+>>> HTML blocks - 123
+<div id="foo"
+ class="bar">
+</div>
+<<<
+<div id="foo"
+ class="bar">
+</div>
+>>> HTML blocks - 124
+<div id="foo" class="bar
+ baz">
+</div>
+<<<
+<div id="foo" class="bar
+ baz">
+</div>
+>>> HTML blocks - 125
+<div>
+*foo*
+
+*bar*
+<<<
+<div>
+*foo*
+<p><em>bar</em></p>
+>>> HTML blocks - 126
+<div id="foo"
+*hi*
+<<<
+<div id="foo"
+*hi*
+>>> HTML blocks - 127
+<div class
+foo
+<<<
+<div class
+foo
+>>> HTML blocks - 128
+<div *???-&&&-<---
+*foo*
+<<<
+<div *???-&&&-<---
+*foo*
+>>> HTML blocks - 129
+<div><a href="bar">*foo*</a></div>
+<<<
+<div><a href="bar">*foo*</a></div>
+>>> HTML blocks - 130
+<table><tr><td>
+foo
+</td></tr></table>
+<<<
+<table><tr><td>
+foo
+</td></tr></table>
+>>> HTML blocks - 131
+<div></div>
+``` c
+int x = 33;
+```
+<<<
+<div></div>
+``` c
+int x = 33;
+```
+>>> HTML blocks - 132
+<a href="foo">
+*bar*
+</a>
+<<<
+<a href="foo">
+*bar*
+</a>
+>>> HTML blocks - 133
+<Warning>
+*bar*
+</Warning>
+<<<
+<Warning>
+*bar*
+</Warning>
+>>> HTML blocks - 134
+<i class="foo">
+*bar*
+</i>
+<<<
+<i class="foo">
+*bar*
+</i>
+>>> HTML blocks - 135
+</ins>
+*bar*
+<<<
+</ins>
+*bar*
+>>> HTML blocks - 136
+<del>
+*foo*
+</del>
+<<<
+<del>
+*foo*
+</del>
+>>> HTML blocks - 137
+<del>
+
+*foo*
+
+</del>
+<<<
+<del>
+<p><em>foo</em></p>
+</del>
+>>> HTML blocks - 138
+<del>*foo*</del>
+<<<
+<p><del><em>foo</em></del></p>
+>>> HTML blocks - 139
+<pre language="haskell"><code>
+import Text.HTML.TagSoup
+
+main :: IO ()
+main = print $ parseTags tags
+</code></pre>
+okay
+<<<
+<pre language="haskell"><code>
+import Text.HTML.TagSoup
+
+main :: IO ()
+main = print $ parseTags tags
+</code></pre>
+<p>okay</p>
+>>> HTML blocks - 140
+<script type="text/javascript">
+// JavaScript example
+
+document.getElementById("demo").innerHTML = "Hello JavaScript!";
+</script>
+okay
+<<<
+<script type="text/javascript">
+// JavaScript example
+
+document.getElementById("demo").innerHTML = "Hello JavaScript!";
+</script>
+<p>okay</p>
+>>> HTML blocks - 141
+<style
+ type="text/css">
+h1 {color:red;}
+
+p {color:blue;}
+</style>
+okay
+<<<
+<style
+ type="text/css">
+h1 {color:red;}
+
+p {color:blue;}
+</style>
+<p>okay</p>
+>>> HTML blocks - 142
+<style
+ type="text/css">
+
+foo
+<<<
+<style
+ type="text/css">
+
+foo
+>>> HTML blocks - 143
+> <div>
+> foo
+
+bar
+<<<
+<blockquote>
+<div>
+foo
+</blockquote>
+<p>bar</p>
+>>> HTML blocks - 144
+- <div>
+- foo
+<<<
+<ul>
+<li>
+<div>
+</li>
+<li>foo</li>
+</ul>
+>>> HTML blocks - 145
+<style>p{color:red;}</style>
+*foo*
+<<<
+<style>p{color:red;}</style>
+<p><em>foo</em></p>
+>>> HTML blocks - 146
+<!-- foo -->*bar*
+*baz*
+<<<
+<!-- foo -->*bar*
+<p><em>baz</em></p>
+>>> HTML blocks - 147
+<script>
+foo
+</script>1. *bar*
+<<<
+<script>
+foo
+</script>1. *bar*
+>>> HTML blocks - 148
+<!-- Foo
+
+bar
+ baz -->
+okay
+<<<
+<!-- Foo
+
+bar
+ baz -->
+<p>okay</p>
+>>> HTML blocks - 149
+<?php
+
+ echo '>';
+
+?>
+okay
+<<<
+<?php
+
+ echo '>';
+
+?>
+<p>okay</p>
+>>> HTML blocks - 150
+<!DOCTYPE html>
+<<<
+<!DOCTYPE html>
+>>> HTML blocks - 151
+<![CDATA[
+function matchwo(a,b)
+{
+ if (a < b && a < 0) then {
+ return 1;
+
+ } else {
+
+ return 0;
+ }
+}
+]]>
+okay
+<<<
+<![CDATA[
+function matchwo(a,b)
+{
+ if (a < b && a < 0) then {
+ return 1;
+
+ } else {
+
+ return 0;
+ }
+}
+]]>
+<p>okay</p>
+>>> HTML blocks - 152
+ <!-- foo -->
+
+ <!-- foo -->
+<<<
+ <!-- foo -->
+<pre><code><!-- foo -->
+</code></pre>
+>>> HTML blocks - 153
+ <div>
+
+ <div>
+<<<
+ <div>
+<pre><code><div>
+</code></pre>
+>>> HTML blocks - 154
+Foo
+<div>
+bar
+</div>
+<<<
+<p>Foo</p>
+<div>
+bar
+</div>
+>>> HTML blocks - 155
+<div>
+bar
+</div>
+*foo*
+<<<
+<div>
+bar
+</div>
+*foo*
+>>> HTML blocks - 156
+Foo
+<a href="bar">
+baz
+<<<
+<p>Foo
+<a href="bar">
+baz</p>
+>>> HTML blocks - 157
+<div>
+
+*Emphasized* text.
+
+</div>
+<<<
+<div>
+<p><em>Emphasized</em> text.</p>
+</div>
+>>> HTML blocks - 158
+<div>
+*Emphasized* text.
+</div>
+<<<
+<div>
+*Emphasized* text.
+</div>
+>>> HTML blocks - 159
+<table>
+
+<tr>
+
+<td>
+Hi
+</td>
+
+</tr>
+
+</table>
+<<<
+<table>
+<tr>
+<td>
+Hi
+</td>
+</tr>
+</table>
+>>> HTML blocks - 160
+<table>
+
+ <tr>
+
+ <td>
+ Hi
+ </td>
+
+ </tr>
+
+</table>
+<<<
+<table>
+ <tr>
+<pre><code><td>
+ Hi
+</td>
+</code></pre>
+ </tr>
+</table>
diff --git a/pkgs/markdown/test/gfm/images.unit b/pkgs/markdown/test/gfm/images.unit
new file mode 100644
index 0000000..106e1a2
--- /dev/null
+++ b/pkgs/markdown/test/gfm/images.unit
@@ -0,0 +1,121 @@
+>>> Images - 580
+
+<<<
+<p><img src="/url" alt="foo" title="title" /></p>
+>>> Images - 581
+![foo *bar*]
+
+[foo *bar*]: train.jpg "train & tracks"
+<<<
+<p><img src="train.jpg" alt="foo bar" title="train & tracks" /></p>
+>>> Images - 582
+](/url2)
+<<<
+<p><img src="/url2" alt="foo bar" /></p>
+>>> Images - 583
+](/url2)
+<<<
+<p><img src="/url2" alt="foo bar" /></p>
+>>> Images - 584
+![foo *bar*][]
+
+[foo *bar*]: train.jpg "train & tracks"
+<<<
+<p><img src="train.jpg" alt="foo bar" title="train & tracks" /></p>
+>>> Images - 585
+![foo *bar*][foobar]
+
+[FOOBAR]: train.jpg "train & tracks"
+<<<
+<p><img src="train.jpg" alt="foo bar" title="train & tracks" /></p>
+>>> Images - 586
+
+<<<
+<p><img src="train.jpg" alt="foo" /></p>
+>>> Images - 587
+My 
+<<<
+<p>My <img src="/path/to/train.jpg" alt="foo bar" title="title" /></p>
+>>> Images - 588
+
+<<<
+<p><img src="url" alt="foo" /></p>
+>>> Images - 589
+
+<<<
+<p><img src="/url" alt="" /></p>
+>>> Images - 590
+![foo][bar]
+
+[bar]: /url
+<<<
+<p><img src="/url" alt="foo" /></p>
+>>> Images - 591
+![foo][bar]
+
+[BAR]: /url
+<<<
+<p><img src="/url" alt="foo" /></p>
+>>> Images - 592
+![foo][]
+
+[foo]: /url "title"
+<<<
+<p><img src="/url" alt="foo" title="title" /></p>
+>>> Images - 593
+![*foo* bar][]
+
+[*foo* bar]: /url "title"
+<<<
+<p><img src="/url" alt="foo bar" title="title" /></p>
+>>> Images - 594
+![Foo][]
+
+[foo]: /url "title"
+<<<
+<p><img src="/url" alt="Foo" title="title" /></p>
+>>> Images - 595
+![foo]
+[]
+
+[foo]: /url "title"
+<<<
+<p><img src="/url" alt="foo" title="title" />
+[]</p>
+>>> Images - 596
+![foo]
+
+[foo]: /url "title"
+<<<
+<p><img src="/url" alt="foo" title="title" /></p>
+>>> Images - 597
+![*foo* bar]
+
+[*foo* bar]: /url "title"
+<<<
+<p><img src="/url" alt="foo bar" title="title" /></p>
+>>> Images - 598
+![[foo]]
+
+[[foo]]: /url "title"
+<<<
+<p>![[foo]]</p>
+<p>[[foo]]: /url "title"</p>
+>>> Images - 599
+![Foo]
+
+[foo]: /url "title"
+<<<
+<p><img src="/url" alt="Foo" title="title" /></p>
+>>> Images - 600
+!\[foo]
+
+[foo]: /url "title"
+<<<
+<p>![foo]</p>
+>>> Images - 601
+\![foo]
+
+[foo]: /url "title"
+<<<
+<p>!<a href="/url" title="title">foo</a></p>
diff --git a/pkgs/markdown/test/gfm/indented_code_blocks.unit b/pkgs/markdown/test/gfm/indented_code_blocks.unit
new file mode 100644
index 0000000..68fc6d1
--- /dev/null
+++ b/pkgs/markdown/test/gfm/indented_code_blocks.unit
@@ -0,0 +1,118 @@
+>>> Indented code blocks - 77
+ a simple
+ indented code block
+<<<
+<pre><code>a simple
+ indented code block
+</code></pre>
+>>> Indented code blocks - 78
+ - foo
+
+ bar
+<<<
+<ul>
+<li>
+<p>foo</p>
+<p>bar</p>
+</li>
+</ul>
+>>> Indented code blocks - 79
+1. foo
+
+ - bar
+<<<
+<ol>
+<li>
+<p>foo</p>
+<ul>
+<li>bar</li>
+</ul>
+</li>
+</ol>
+>>> Indented code blocks - 80
+ <a/>
+ *hi*
+
+ - one
+<<<
+<pre><code><a/>
+*hi*
+
+- one
+</code></pre>
+>>> Indented code blocks - 81
+ chunk1
+
+ chunk2
+
+
+
+ chunk3
+<<<
+<pre><code>chunk1
+
+chunk2
+
+
+
+chunk3
+</code></pre>
+>>> Indented code blocks - 82
+ chunk1
+
+ chunk2
+<<<
+<pre><code>chunk1
+
+ chunk2
+</code></pre>
+>>> Indented code blocks - 83
+Foo
+ bar
+
+<<<
+<p>Foo
+bar</p>
+>>> Indented code blocks - 84
+ foo
+bar
+<<<
+<pre><code>foo
+</code></pre>
+<p>bar</p>
+>>> Indented code blocks - 85
+# Heading
+ foo
+Heading
+------
+ foo
+----
+<<<
+<h1>Heading</h1>
+<pre><code>foo
+</code></pre>
+<h2>Heading</h2>
+<pre><code>foo
+</code></pre>
+<hr />
+>>> Indented code blocks - 86
+ foo
+ bar
+<<<
+<pre><code> foo
+bar
+</code></pre>
+>>> Indented code blocks - 87
+
+
+ foo
+
+
+<<<
+<pre><code>foo
+</code></pre>
+>>> Indented code blocks - 88
+ foo
+<<<
+<pre><code>foo
+</code></pre>
diff --git a/pkgs/markdown/test/gfm/inlines.unit b/pkgs/markdown/test/gfm/inlines.unit
new file mode 100644
index 0000000..9e19a33
--- /dev/null
+++ b/pkgs/markdown/test/gfm/inlines.unit
@@ -0,0 +1,4 @@
+>>> Inlines - 307
+`hi`lo`
+<<<
+<p><code>hi</code>lo`</p>
diff --git a/pkgs/markdown/test/gfm/link_reference_definitions.unit b/pkgs/markdown/test/gfm/link_reference_definitions.unit
new file mode 100644
index 0000000..b09236f
--- /dev/null
+++ b/pkgs/markdown/test/gfm/link_reference_definitions.unit
@@ -0,0 +1,206 @@
+>>> Link reference definitions - 161
+[foo]: /url "title"
+
+[foo]
+<<<
+<p><a href="/url" title="title">foo</a></p>
+>>> Link reference definitions - 162
+ [foo]:
+ /url
+ 'the title'
+
+[foo]
+<<<
+<p><a href="/url" title="the title">foo</a></p>
+>>> Link reference definitions - 163
+[Foo*bar\]]:my_(url) 'title (with parens)'
+
+[Foo*bar\]]
+<<<
+<p><a href="my_(url)" title="title (with parens)">Foo*bar]</a></p>
+>>> Link reference definitions - 164
+[Foo bar]:
+<my url>
+'title'
+
+[Foo bar]
+<<<
+<p><a href="my%20url" title="title">Foo bar</a></p>
+>>> Link reference definitions - 165
+[foo]: /url '
+title
+line1
+line2
+'
+
+[foo]
+<<<
+<p><a href="/url" title="
+title
+line1
+line2
+">foo</a></p>
+>>> Link reference definitions - 166
+[foo]: /url 'title
+
+with blank line'
+
+[foo]
+<<<
+<p>[foo]: /url 'title</p>
+<p>with blank line'</p>
+<p>[foo]</p>
+>>> Link reference definitions - 167
+[foo]:
+/url
+
+[foo]
+<<<
+<p><a href="/url">foo</a></p>
+>>> Link reference definitions - 168
+[foo]:
+
+[foo]
+<<<
+<p>[foo]:</p>
+<p>[foo]</p>
+>>> Link reference definitions - 169
+[foo]: <>
+
+[foo]
+<<<
+<p><a href="">foo</a></p>
+>>> Link reference definitions - 170
+[foo]: <bar>(baz)
+
+[foo]
+<<<
+<p>[foo]: <bar>(baz)</p>
+<p>[foo]</p>
+>>> Link reference definitions - 171
+[foo]: /url\bar\*baz "foo\"bar\baz"
+
+[foo]
+<<<
+<p><a href="/url%5Cbar*baz" title="foo"bar\baz">foo</a></p>
+>>> Link reference definitions - 172
+[foo]
+
+[foo]: url
+<<<
+<p><a href="url">foo</a></p>
+>>> Link reference definitions - 173
+[foo]
+
+[foo]: first
+[foo]: second
+<<<
+<p><a href="first">foo</a></p>
+>>> Link reference definitions - 174
+[FOO]: /url
+
+[Foo]
+<<<
+<p><a href="/url">Foo</a></p>
+>>> Link reference definitions - 175
+[ΑΓΩ]: /φου
+
+[αγω]
+<<<
+<p><a href="/%CF%86%CE%BF%CF%85">αγω</a></p>
+>>> Link reference definitions - 176
+[foo]: /url
+<<<
+
+>>> Link reference definitions - 177
+[
+foo
+]: /url
+bar
+<<<
+<p>bar</p>
+>>> Link reference definitions - 178
+[foo]: /url "title" ok
+<<<
+<p>[foo]: /url "title" ok</p>
+>>> Link reference definitions - 179
+[foo]: /url
+"title" ok
+<<<
+<p>"title" ok</p>
+>>> Link reference definitions - 180
+ [foo]: /url "title"
+
+[foo]
+<<<
+<pre><code>[foo]: /url "title"
+</code></pre>
+<p>[foo]</p>
+>>> Link reference definitions - 181
+```
+[foo]: /url
+```
+
+[foo]
+<<<
+<pre><code>[foo]: /url
+</code></pre>
+<p>[foo]</p>
+>>> Link reference definitions - 182
+Foo
+[bar]: /baz
+
+[bar]
+<<<
+<p>Foo
+[bar]: /baz</p>
+<p>[bar]</p>
+>>> Link reference definitions - 183
+# [Foo]
+[foo]: /url
+> bar
+<<<
+<h1><a href="/url">Foo</a></h1>
+<blockquote>
+<p>bar</p>
+</blockquote>
+>>> Link reference definitions - 184
+[foo]: /url
+bar
+===
+[foo]
+<<<
+<h1>bar</h1>
+<p><a href="/url">foo</a></p>
+>>> Link reference definitions - 185
+[foo]: /url
+===
+[foo]
+<<<
+<p>===
+<a href="/url">foo</a></p>
+>>> Link reference definitions - 186
+[foo]: /foo-url "foo"
+[bar]: /bar-url
+ "bar"
+[baz]: /baz-url
+
+[foo],
+[bar],
+[baz]
+<<<
+<p><a href="/foo-url" title="foo">foo</a>,
+<a href="/bar-url" title="bar">bar</a>,
+<a href="/baz-url">baz</a></p>
+>>> Link reference definitions - 187
+[foo]
+
+> [foo]: /url
+<<<
+<p><a href="/url">foo</a></p>
+<blockquote>
+</blockquote>
+>>> Link reference definitions - 188
+[foo]: /url
+<<<
+
diff --git a/pkgs/markdown/test/gfm/links.unit b/pkgs/markdown/test/gfm/links.unit
new file mode 100644
index 0000000..7288c79
--- /dev/null
+++ b/pkgs/markdown/test/gfm/links.unit
@@ -0,0 +1,476 @@
+>>> Links - 493
+[link](/uri "title")
+<<<
+<p><a href="/uri" title="title">link</a></p>
+>>> Links - 494
+[link](/uri)
+<<<
+<p><a href="/uri">link</a></p>
+>>> Links - 495
+[link]()
+<<<
+<p><a href="">link</a></p>
+>>> Links - 496
+[link](<>)
+<<<
+<p><a href="">link</a></p>
+>>> Links - 497
+[link](/my uri)
+<<<
+<p>[link](/my uri)</p>
+>>> Links - 498
+[link](</my uri>)
+<<<
+<p><a href="/my%20uri">link</a></p>
+>>> Links - 499
+[link](foo
+bar)
+<<<
+<p>[link](foo
+bar)</p>
+>>> Links - 500
+[link](<foo
+bar>)
+<<<
+<p>[link](<foo
+bar>)</p>
+>>> Links - 501
+[a](<b)c>)
+<<<
+<p><a href="b)c">a</a></p>
+>>> Links - 502
+[link](<foo\>)
+<<<
+<p>[link](<foo>)</p>
+>>> Links - 503
+[a](<b)c
+[a](<b)c>
+[a](<b>c)
+<<<
+<p>[a](<b)c
+[a](<b)c>
+[a](<b>c)</p>
+>>> Links - 504
+[link](\(foo\))
+<<<
+<p><a href="(foo)">link</a></p>
+>>> Links - 505
+[link](foo(and(bar)))
+<<<
+<p><a href="foo(and(bar))">link</a></p>
+>>> Links - 506
+[link](foo\(and\(bar\))
+<<<
+<p><a href="foo(and(bar)">link</a></p>
+>>> Links - 507
+[link](<foo(and(bar)>)
+<<<
+<p><a href="foo(and(bar)">link</a></p>
+>>> Links - 508
+[link](foo\)\:)
+<<<
+<p><a href="foo):">link</a></p>
+>>> Links - 509
+[link](#fragment)
+
+[link](http://example.com#fragment)
+
+[link](http://example.com?foo=3#frag)
+<<<
+<p><a href="#fragment">link</a></p>
+<p><a href="http://example.com#fragment">link</a></p>
+<p><a href="http://example.com?foo=3#frag">link</a></p>
+>>> Links - 510
+[link](foo\bar)
+<<<
+<p><a href="foo%5Cbar">link</a></p>
+>>> Links - 511
+[link](foo%20bä)
+<<<
+<p><a href="foo%20b%C3%A4">link</a></p>
+>>> Links - 512
+[link]("title")
+<<<
+<p><a href="%22title%22">link</a></p>
+>>> Links - 513
+[link](/url "title")
+[link](/url 'title')
+[link](/url (title))
+<<<
+<p><a href="/url" title="title">link</a>
+<a href="/url" title="title">link</a>
+<a href="/url" title="title">link</a></p>
+>>> Links - 514
+[link](/url "title \""")
+<<<
+<p><a href="/url" title="title """>link</a></p>
+>>> Links - 515
+[link](/url "title")
+<<<
+<p><a href="/url%C2%A0%22title%22">link</a></p>
+>>> Links - 516
+[link](/url "title "and" title")
+<<<
+<p>[link](/url "title "and" title")</p>
+>>> Links - 517
+[link](/url 'title "and" title')
+<<<
+<p><a href="/url" title="title "and" title">link</a></p>
+>>> Links - 518
+[link]( /uri
+ "title" )
+<<<
+<p><a href="/uri" title="title">link</a></p>
+>>> Links - 519
+[link] (/uri)
+<<<
+<p>[link] (/uri)</p>
+>>> Links - 520
+[link [foo [bar]]](/uri)
+<<<
+<p><a href="/uri">link [foo [bar]]</a></p>
+>>> Links - 521
+[link] bar](/uri)
+<<<
+<p>[link] bar](/uri)</p>
+>>> Links - 522
+[link [bar](/uri)
+<<<
+<p>[link <a href="/uri">bar</a></p>
+>>> Links - 523
+[link \[bar](/uri)
+<<<
+<p><a href="/uri">link [bar</a></p>
+>>> Links - 524
+[link *foo **bar** `#`*](/uri)
+<<<
+<p><a href="/uri">link <em>foo <strong>bar</strong> <code>#</code></em></a></p>
+>>> Links - 525
+[](/uri)
+<<<
+<p><a href="/uri"><img src="moon.jpg" alt="moon" /></a></p>
+>>> Links - 526
+[foo [bar](/uri)](/uri)
+<<<
+<p>[foo <a href="/uri">bar</a>](/uri)</p>
+>>> Links - 527
+[foo *[bar [baz](/uri)](/uri)*](/uri)
+<<<
+<p>[foo <em>[bar <a href="/uri">baz</a>](/uri)</em>](/uri)</p>
+>>> Links - 528
+](uri2)](uri3)
+<<<
+<p><img src="uri3" alt="[foo](uri2)" /></p>
+>>> Links - 529
+*[foo*](/uri)
+<<<
+<p>*<a href="/uri">foo*</a></p>
+>>> Links - 530
+[foo *bar](baz*)
+<<<
+<p><a href="baz*">foo *bar</a></p>
+>>> Links - 531
+*foo [bar* baz]
+<<<
+<p><em>foo [bar</em> baz]</p>
+>>> Links - 532
+[foo <bar attr="](baz)">
+<<<
+<p>[foo <bar attr="](baz)"></p>
+>>> Links - 533
+[foo`](/uri)`
+<<<
+<p>[foo<code>](/uri)</code></p>
+>>> Links - 534
+[foo<http://example.com/?search=](uri)>
+<<<
+<p>[foo<a href="http://example.com/?search=%5D(uri)">http://example.com/?search=](uri)</a></p>
+>>> Links - 535
+[foo][bar]
+
+[bar]: /url "title"
+<<<
+<p><a href="/url" title="title">foo</a></p>
+>>> Links - 536
+[link [foo [bar]]][ref]
+
+[ref]: /uri
+<<<
+<p><a href="/uri">link [foo [bar]]</a></p>
+>>> Links - 537
+[link \[bar][ref]
+
+[ref]: /uri
+<<<
+<p><a href="/uri">link [bar</a></p>
+>>> Links - 538
+[link *foo **bar** `#`*][ref]
+
+[ref]: /uri
+<<<
+<p><a href="/uri">link <em>foo <strong>bar</strong> <code>#</code></em></a></p>
+>>> Links - 539
+[][ref]
+
+[ref]: /uri
+<<<
+<p><a href="/uri"><img src="moon.jpg" alt="moon" /></a></p>
+>>> Links - 540
+[foo [bar](/uri)][ref]
+
+[ref]: /uri
+<<<
+<p>[foo <a href="/uri">bar</a>]<a href="/uri">ref</a></p>
+>>> Links - 541
+[foo *bar [baz][ref]*][ref]
+
+[ref]: /uri
+<<<
+<p>[foo <em>bar <a href="/uri">baz</a></em>]<a href="/uri">ref</a></p>
+>>> Links - 542
+*[foo*][ref]
+
+[ref]: /uri
+<<<
+<p>*<a href="/uri">foo*</a></p>
+>>> Links - 543
+[foo *bar][ref]
+
+[ref]: /uri
+<<<
+<p><a href="/uri">foo *bar</a></p>
+>>> Links - 544
+[foo <bar attr="][ref]">
+
+[ref]: /uri
+<<<
+<p>[foo <bar attr="][ref]"></p>
+>>> Links - 545
+[foo`][ref]`
+
+[ref]: /uri
+<<<
+<p>[foo<code>][ref]</code></p>
+>>> Links - 546
+[foo<http://example.com/?search=][ref]>
+
+[ref]: /uri
+<<<
+<p>[foo<a href="http://example.com/?search=%5D%5Bref%5D">http://example.com/?search=][ref]</a></p>
+>>> Links - 547
+[foo][BaR]
+
+[bar]: /url "title"
+<<<
+<p><a href="/url" title="title">foo</a></p>
+>>> Links - 548
+[Толпой][Толпой] is a Russian word.
+
+[ТОЛПОЙ]: /url
+<<<
+<p><a href="/url">Толпой</a> is a Russian word.</p>
+>>> Links - 549
+[Foo
+ bar]: /url
+
+[Baz][Foo bar]
+<<<
+<p><a href="/url">Baz</a></p>
+>>> Links - 550
+[foo] [bar]
+
+[bar]: /url "title"
+<<<
+<p>[foo] <a href="/url" title="title">bar</a></p>
+>>> Links - 551
+[foo]
+[bar]
+
+[bar]: /url "title"
+<<<
+<p>[foo]
+<a href="/url" title="title">bar</a></p>
+>>> Links - 552
+[foo]: /url1
+
+[foo]: /url2
+
+[bar][foo]
+<<<
+<p><a href="/url1">bar</a></p>
+>>> Links - 553
+[bar][foo\!]
+
+[foo!]: /url
+<<<
+<p>[bar][foo!]</p>
+>>> Links - 554
+[foo][ref[]
+
+[ref[]: /uri
+<<<
+<p>[foo][ref[]</p>
+<p>[ref[]: /uri</p>
+>>> Links - 555
+[foo][ref[bar]]
+
+[ref[bar]]: /uri
+<<<
+<p>[foo][ref[bar]]</p>
+<p>[ref[bar]]: /uri</p>
+>>> Links - 556
+[[[foo]]]
+
+[[[foo]]]: /url
+<<<
+<p>[[[foo]]]</p>
+<p>[[[foo]]]: /url</p>
+>>> Links - 557
+[foo][ref\[]
+
+[ref\[]: /uri
+<<<
+<p><a href="/uri">foo</a></p>
+>>> Links - 558
+[bar\\]: /uri
+
+[bar\\]
+<<<
+<p><a href="/uri">bar\</a></p>
+>>> Links - 559
+[]
+
+[]: /uri
+<<<
+<p>[]</p>
+<p>[]: /uri</p>
+>>> Links - 560
+[
+ ]
+
+[
+ ]: /uri
+<<<
+<p>[
+]</p>
+<p>[
+]: /uri</p>
+>>> Links - 561
+[foo][]
+
+[foo]: /url "title"
+<<<
+<p><a href="/url" title="title">foo</a></p>
+>>> Links - 562
+[*foo* bar][]
+
+[*foo* bar]: /url "title"
+<<<
+<p><a href="/url" title="title"><em>foo</em> bar</a></p>
+>>> Links - 563
+[Foo][]
+
+[foo]: /url "title"
+<<<
+<p><a href="/url" title="title">Foo</a></p>
+>>> Links - 564
+[foo]
+[]
+
+[foo]: /url "title"
+<<<
+<p><a href="/url" title="title">foo</a>
+[]</p>
+>>> Links - 565
+[foo]
+
+[foo]: /url "title"
+<<<
+<p><a href="/url" title="title">foo</a></p>
+>>> Links - 566
+[*foo* bar]
+
+[*foo* bar]: /url "title"
+<<<
+<p><a href="/url" title="title"><em>foo</em> bar</a></p>
+>>> Links - 567
+[[*foo* bar]]
+
+[*foo* bar]: /url "title"
+<<<
+<p>[<a href="/url" title="title"><em>foo</em> bar</a>]</p>
+>>> Links - 568
+[[bar [foo]
+
+[foo]: /url
+<<<
+<p>[[bar <a href="/url">foo</a></p>
+>>> Links - 569
+[Foo]
+
+[foo]: /url "title"
+<<<
+<p><a href="/url" title="title">Foo</a></p>
+>>> Links - 570
+[foo] bar
+
+[foo]: /url
+<<<
+<p><a href="/url">foo</a> bar</p>
+>>> Links - 571
+\[foo]
+
+[foo]: /url "title"
+<<<
+<p>[foo]</p>
+>>> Links - 572
+[foo*]: /url
+
+*[foo*]
+<<<
+<p>*<a href="/url">foo*</a></p>
+>>> Links - 573
+[foo][bar]
+
+[foo]: /url1
+[bar]: /url2
+<<<
+<p><a href="/url2">foo</a></p>
+>>> Links - 574
+[foo][]
+
+[foo]: /url1
+<<<
+<p><a href="/url1">foo</a></p>
+>>> Links - 575
+[foo]()
+
+[foo]: /url1
+<<<
+<p><a href="">foo</a></p>
+>>> Links - 576
+[foo](not a link)
+
+[foo]: /url1
+<<<
+<p><a href="/url1">foo</a>(not a link)</p>
+>>> Links - 577
+[foo][bar][baz]
+
+[baz]: /url
+<<<
+<p>[foo]<a href="/url">bar</a></p>
+>>> Links - 578
+[foo][bar][baz]
+
+[baz]: /url1
+[bar]: /url2
+<<<
+<p><a href="/url2">foo</a><a href="/url1">baz</a></p>
+>>> Links - 579
+[foo][bar][baz]
+
+[baz]: /url1
+[foo]: /url2
+<<<
+<p>[foo]<a href="/url1">bar</a></p>
diff --git a/pkgs/markdown/test/gfm/list_items.unit b/pkgs/markdown/test/gfm/list_items.unit
new file mode 100644
index 0000000..3954af8
--- /dev/null
+++ b/pkgs/markdown/test/gfm/list_items.unit
@@ -0,0 +1,586 @@
+>>> List items - 231
+A paragraph
+with two lines.
+
+ indented code
+
+> A block quote.
+<<<
+<p>A paragraph
+with two lines.</p>
+<pre><code>indented code
+</code></pre>
+<blockquote>
+<p>A block quote.</p>
+</blockquote>
+>>> List items - 232
+1. A paragraph
+ with two lines.
+
+ indented code
+
+ > A block quote.
+<<<
+<ol>
+<li>
+<p>A paragraph
+with two lines.</p>
+<pre><code>indented code
+</code></pre>
+<blockquote>
+<p>A block quote.</p>
+</blockquote>
+</li>
+</ol>
+>>> List items - 233
+- one
+
+ two
+<<<
+<ul>
+<li>one</li>
+</ul>
+<p>two</p>
+>>> List items - 234
+- one
+
+ two
+<<<
+<ul>
+<li>
+<p>one</p>
+<p>two</p>
+</li>
+</ul>
+>>> List items - 235
+ - one
+
+ two
+<<<
+<ul>
+<li>one</li>
+</ul>
+<pre><code> two
+</code></pre>
+>>> List items - 236
+ - one
+
+ two
+<<<
+<ul>
+<li>
+<p>one</p>
+<p>two</p>
+</li>
+</ul>
+>>> List items - 237
+ > > 1. one
+>>
+>> two
+<<<
+<blockquote>
+<blockquote>
+<ol>
+<li>
+<p>one</p>
+<p>two</p>
+</li>
+</ol>
+</blockquote>
+</blockquote>
+>>> List items - 238
+>>- one
+>>
+ > > two
+<<<
+<blockquote>
+<blockquote>
+<ul>
+<li>one</li>
+</ul>
+<p>two</p>
+</blockquote>
+</blockquote>
+>>> List items - 239
+-one
+
+2.two
+<<<
+<p>-one</p>
+<p>2.two</p>
+>>> List items - 240
+- foo
+
+
+ bar
+<<<
+<ul>
+<li>
+<p>foo</p>
+<p>bar</p>
+</li>
+</ul>
+>>> List items - 241
+1. foo
+
+ ```
+ bar
+ ```
+
+ baz
+
+ > bam
+<<<
+<ol>
+<li>
+<p>foo</p>
+<pre><code>bar
+</code></pre>
+<p>baz</p>
+<blockquote>
+<p>bam</p>
+</blockquote>
+</li>
+</ol>
+>>> List items - 242
+- Foo
+
+ bar
+
+
+ baz
+<<<
+<ul>
+<li>
+<p>Foo</p>
+<pre><code>bar
+
+
+baz
+</code></pre>
+</li>
+</ul>
+>>> List items - 243
+123456789. ok
+<<<
+<ol start="123456789">
+<li>ok</li>
+</ol>
+>>> List items - 244
+1234567890. not ok
+<<<
+<p>1234567890. not ok</p>
+>>> List items - 245
+0. ok
+<<<
+<ol start="0">
+<li>ok</li>
+</ol>
+>>> List items - 246
+003. ok
+<<<
+<ol start="3">
+<li>ok</li>
+</ol>
+>>> List items - 247
+-1. not ok
+<<<
+<p>-1. not ok</p>
+>>> List items - 248
+- foo
+
+ bar
+<<<
+<ul>
+<li>
+<p>foo</p>
+<pre><code>bar
+</code></pre>
+</li>
+</ul>
+>>> List items - 249
+ 10. foo
+
+ bar
+<<<
+<ol start="10">
+<li>
+<p>foo</p>
+<pre><code>bar
+</code></pre>
+</li>
+</ol>
+>>> List items - 250
+ indented code
+
+paragraph
+
+ more code
+<<<
+<pre><code>indented code
+</code></pre>
+<p>paragraph</p>
+<pre><code>more code
+</code></pre>
+>>> List items - 251
+1. indented code
+
+ paragraph
+
+ more code
+<<<
+<ol>
+<li>
+<pre><code>indented code
+</code></pre>
+<p>paragraph</p>
+<pre><code>more code
+</code></pre>
+</li>
+</ol>
+>>> List items - 252
+1. indented code
+
+ paragraph
+
+ more code
+<<<
+<ol>
+<li>
+<pre><code> indented code
+</code></pre>
+<p>paragraph</p>
+<pre><code>more code
+</code></pre>
+</li>
+</ol>
+>>> List items - 253
+ foo
+
+bar
+<<<
+<p>foo</p>
+<p>bar</p>
+>>> List items - 254
+- foo
+
+ bar
+<<<
+<ul>
+<li>foo</li>
+</ul>
+<p>bar</p>
+>>> List items - 255
+- foo
+
+ bar
+<<<
+<ul>
+<li>
+<p>foo</p>
+<p>bar</p>
+</li>
+</ul>
+>>> List items - 256
+-
+ foo
+-
+ ```
+ bar
+ ```
+-
+ baz
+<<<
+<ul>
+<li>foo</li>
+<li>
+<pre><code>bar
+</code></pre>
+</li>
+<li>
+<pre><code>baz
+</code></pre>
+</li>
+</ul>
+>>> List items - 257
+-
+ foo
+<<<
+<ul>
+<li>foo</li>
+</ul>
+>>> List items - 258
+-
+
+ foo
+<<<
+<ul>
+<li></li>
+</ul>
+<p>foo</p>
+>>> List items - 259
+- foo
+-
+- bar
+<<<
+<ul>
+<li>foo</li>
+<li></li>
+<li>bar</li>
+</ul>
+>>> List items - 260
+- foo
+-
+- bar
+<<<
+<ul>
+<li>foo</li>
+<li></li>
+<li>bar</li>
+</ul>
+>>> List items - 261
+1. foo
+2.
+3. bar
+<<<
+<ol>
+<li>foo</li>
+<li></li>
+<li>bar</li>
+</ol>
+>>> List items - 262
+*
+<<<
+<ul>
+<li></li>
+</ul>
+>>> List items - 263
+foo
+*
+
+foo
+1.
+<<<
+<p>foo
+*</p>
+<p>foo
+1.</p>
+>>> List items - 264
+ 1. A paragraph
+ with two lines.
+
+ indented code
+
+ > A block quote.
+<<<
+<ol>
+<li>
+<p>A paragraph
+with two lines.</p>
+<pre><code>indented code
+</code></pre>
+<blockquote>
+<p>A block quote.</p>
+</blockquote>
+</li>
+</ol>
+>>> List items - 265
+ 1. A paragraph
+ with two lines.
+
+ indented code
+
+ > A block quote.
+<<<
+<ol>
+<li>
+<p>A paragraph
+with two lines.</p>
+<pre><code>indented code
+</code></pre>
+<blockquote>
+<p>A block quote.</p>
+</blockquote>
+</li>
+</ol>
+>>> List items - 266
+ 1. A paragraph
+ with two lines.
+
+ indented code
+
+ > A block quote.
+<<<
+<ol>
+<li>
+<p>A paragraph
+with two lines.</p>
+<pre><code>indented code
+</code></pre>
+<blockquote>
+<p>A block quote.</p>
+</blockquote>
+</li>
+</ol>
+>>> List items - 267
+ 1. A paragraph
+ with two lines.
+
+ indented code
+
+ > A block quote.
+<<<
+<pre><code>1. A paragraph
+ with two lines.
+
+ indented code
+
+ > A block quote.
+</code></pre>
+>>> List items - 268
+ 1. A paragraph
+with two lines.
+
+ indented code
+
+ > A block quote.
+<<<
+<ol>
+<li>
+<p>A paragraph
+with two lines.</p>
+<pre><code>indented code
+</code></pre>
+<blockquote>
+<p>A block quote.</p>
+</blockquote>
+</li>
+</ol>
+>>> List items - 269
+ 1. A paragraph
+ with two lines.
+<<<
+<ol>
+<li>A paragraph
+with two lines.</li>
+</ol>
+>>> List items - 270
+> 1. > Blockquote
+continued here.
+<<<
+<blockquote>
+<ol>
+<li>
+<blockquote>
+<p>Blockquote
+continued here.</p>
+</blockquote>
+</li>
+</ol>
+</blockquote>
+>>> List items - 271
+> 1. > Blockquote
+> continued here.
+<<<
+<blockquote>
+<ol>
+<li>
+<blockquote>
+<p>Blockquote
+continued here.</p>
+</blockquote>
+</li>
+</ol>
+</blockquote>
+>>> List items - 272
+- foo
+ - bar
+ - baz
+ - boo
+<<<
+<ul>
+<li>foo
+<ul>
+<li>bar
+<ul>
+<li>baz
+<ul>
+<li>boo</li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+>>> List items - 273
+- foo
+ - bar
+ - baz
+ - boo
+<<<
+<ul>
+<li>foo</li>
+<li>bar</li>
+<li>baz</li>
+<li>boo</li>
+</ul>
+>>> List items - 274
+10) foo
+ - bar
+<<<
+<ol start="10">
+<li>foo
+<ul>
+<li>bar</li>
+</ul>
+</li>
+</ol>
+>>> List items - 275
+10) foo
+ - bar
+<<<
+<ol start="10">
+<li>foo</li>
+</ol>
+<ul>
+<li>bar</li>
+</ul>
+>>> List items - 276
+- - foo
+<<<
+<ul>
+<li>
+<ul>
+<li>foo</li>
+</ul>
+</li>
+</ul>
+>>> List items - 277
+1. - 2. foo
+<<<
+<ol>
+<li>
+<ul>
+<li>
+<ol start="2">
+<li>foo</li>
+</ol>
+</li>
+</ul>
+</li>
+</ol>
+>>> List items - 278
+- # Foo
+- Bar
+ ---
+ baz
+<<<
+<ul>
+<li>
+<h1>Foo</h1>
+</li>
+<li>
+<h2>Bar</h2>
+baz</li>
+</ul>
diff --git a/pkgs/markdown/test/gfm/lists.unit b/pkgs/markdown/test/gfm/lists.unit
new file mode 100644
index 0000000..e5802db
--- /dev/null
+++ b/pkgs/markdown/test/gfm/lists.unit
@@ -0,0 +1,406 @@
+>>> Lists - 281
+- foo
+- bar
++ baz
+<<<
+<ul>
+<li>foo</li>
+<li>bar</li>
+</ul>
+<ul>
+<li>baz</li>
+</ul>
+>>> Lists - 282
+1. foo
+2. bar
+3) baz
+<<<
+<ol>
+<li>foo</li>
+<li>bar</li>
+</ol>
+<ol start="3">
+<li>baz</li>
+</ol>
+>>> Lists - 283
+Foo
+- bar
+- baz
+<<<
+<p>Foo</p>
+<ul>
+<li>bar</li>
+<li>baz</li>
+</ul>
+>>> Lists - 284
+The number of windows in my house is
+14. The number of doors is 6.
+<<<
+<p>The number of windows in my house is
+14. The number of doors is 6.</p>
+>>> Lists - 285
+The number of windows in my house is
+1. The number of doors is 6.
+<<<
+<p>The number of windows in my house is</p>
+<ol>
+<li>The number of doors is 6.</li>
+</ol>
+>>> Lists - 286
+- foo
+
+- bar
+
+
+- baz
+<<<
+<ul>
+<li>
+<p>foo</p>
+</li>
+<li>
+<p>bar</p>
+</li>
+<li>
+<p>baz</p>
+</li>
+</ul>
+>>> Lists - 287
+- foo
+ - bar
+ - baz
+
+
+ bim
+<<<
+<ul>
+<li>foo
+<ul>
+<li>bar
+<ul>
+<li>
+<p>baz</p>
+<p>bim</p>
+</li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+>>> Lists - 288
+- foo
+- bar
+
+<!-- -->
+
+- baz
+- bim
+<<<
+<ul>
+<li>foo</li>
+<li>bar</li>
+</ul>
+<!-- -->
+<ul>
+<li>baz</li>
+<li>bim</li>
+</ul>
+>>> Lists - 289
+- foo
+
+ notcode
+
+- foo
+
+<!-- -->
+
+ code
+<<<
+<ul>
+<li>
+<p>foo</p>
+<p>notcode</p>
+</li>
+<li>
+<p>foo</p>
+</li>
+</ul>
+<!-- -->
+<pre><code>code
+</code></pre>
+>>> Lists - 290
+- a
+ - b
+ - c
+ - d
+ - e
+ - f
+- g
+<<<
+<ul>
+<li>a</li>
+<li>b</li>
+<li>c</li>
+<li>d</li>
+<li>e</li>
+<li>f</li>
+<li>g</li>
+</ul>
+>>> Lists - 291
+1. a
+
+ 2. b
+
+ 3. c
+<<<
+<ol>
+<li>
+<p>a</p>
+</li>
+<li>
+<p>b</p>
+</li>
+<li>
+<p>c</p>
+</li>
+</ol>
+>>> Lists - 292
+- a
+ - b
+ - c
+ - d
+ - e
+<<<
+<ul>
+<li>a</li>
+<li>b</li>
+<li>c</li>
+<li>d
+- e</li>
+</ul>
+>>> Lists - 293
+1. a
+
+ 2. b
+
+ 3. c
+<<<
+<ol>
+<li>
+<p>a</p>
+</li>
+<li>
+<p>b</p>
+</li>
+</ol>
+<pre><code>3. c
+</code></pre>
+>>> Lists - 294
+- a
+- b
+
+- c
+<<<
+<ul>
+<li>
+<p>a</p>
+</li>
+<li>
+<p>b</p>
+</li>
+<li>
+<p>c</p>
+</li>
+</ul>
+>>> Lists - 295
+* a
+*
+
+* c
+<<<
+<ul>
+<li>
+<p>a</p>
+</li>
+<li></li>
+<li>
+<p>c</p>
+</li>
+</ul>
+>>> Lists - 296
+- a
+- b
+
+ c
+- d
+<<<
+<ul>
+<li>
+<p>a</p>
+</li>
+<li>
+<p>b</p>
+<p>c</p>
+</li>
+<li>
+<p>d</p>
+</li>
+</ul>
+>>> Lists - 297
+- a
+- b
+
+ [ref]: /url
+- d
+<<<
+<ul>
+<li>
+<p>a</p>
+</li>
+<li>
+<p>b</p>
+</li>
+<li>
+<p>d</p>
+</li>
+</ul>
+>>> Lists - 298
+- a
+- ```
+ b
+
+
+ ```
+- c
+<<<
+<ul>
+<li>a</li>
+<li>
+<pre><code>b
+
+
+</code></pre>
+</li>
+<li>c</li>
+</ul>
+>>> Lists - 299
+- a
+ - b
+
+ c
+- d
+<<<
+<ul>
+<li>a
+<ul>
+<li>
+<p>b</p>
+<p>c</p>
+</li>
+</ul>
+</li>
+<li>d</li>
+</ul>
+>>> Lists - 300
+* a
+ > b
+ >
+* c
+<<<
+<ul>
+<li>a
+<blockquote>
+<p>b</p>
+</blockquote>
+</li>
+<li>c</li>
+</ul>
+>>> Lists - 301
+- a
+ > b
+ ```
+ c
+ ```
+- d
+<<<
+<ul>
+<li>a
+<blockquote>
+<p>b</p>
+</blockquote>
+<pre><code>c
+</code></pre>
+</li>
+<li>d</li>
+</ul>
+>>> Lists - 302
+- a
+<<<
+<ul>
+<li>a</li>
+</ul>
+>>> Lists - 303
+- a
+ - b
+<<<
+<ul>
+<li>a
+<ul>
+<li>b</li>
+</ul>
+</li>
+</ul>
+>>> Lists - 304
+1. ```
+ foo
+ ```
+
+ bar
+<<<
+<ol>
+<li>
+<pre><code>foo
+</code></pre>
+<p>bar</p>
+</li>
+</ol>
+>>> Lists - 305
+* foo
+ * bar
+
+ baz
+<<<
+<ul>
+<li>
+<p>foo</p>
+<ul>
+<li>bar</li>
+</ul>
+<p>baz</p>
+</li>
+</ul>
+>>> Lists - 306
+- a
+ - b
+ - c
+
+- d
+ - e
+ - f
+<<<
+<ul>
+<li>
+<p>a</p>
+<ul>
+<li>b</li>
+<li>c</li>
+</ul>
+</li>
+<li>
+<p>d</p>
+<ul>
+<li>e</li>
+<li>f</li>
+</ul>
+</li>
+</ul>
diff --git a/pkgs/markdown/test/gfm/paragraphs.unit b/pkgs/markdown/test/gfm/paragraphs.unit
new file mode 100644
index 0000000..a6fc2b1
--- /dev/null
+++ b/pkgs/markdown/test/gfm/paragraphs.unit
@@ -0,0 +1,59 @@
+>>> Paragraphs - 189
+aaa
+
+bbb
+<<<
+<p>aaa</p>
+<p>bbb</p>
+>>> Paragraphs - 190
+aaa
+bbb
+
+ccc
+ddd
+<<<
+<p>aaa
+bbb</p>
+<p>ccc
+ddd</p>
+>>> Paragraphs - 191
+aaa
+
+
+bbb
+<<<
+<p>aaa</p>
+<p>bbb</p>
+>>> Paragraphs - 192
+ aaa
+ bbb
+<<<
+<p>aaa
+bbb</p>
+>>> Paragraphs - 193
+aaa
+ bbb
+ ccc
+<<<
+<p>aaa
+bbb
+ccc</p>
+>>> Paragraphs - 194
+ aaa
+bbb
+<<<
+<p>aaa
+bbb</p>
+>>> Paragraphs - 195
+ aaa
+bbb
+<<<
+<pre><code>aaa
+</code></pre>
+<p>bbb</p>
+>>> Paragraphs - 196
+aaa
+bbb
+<<<
+<p>aaa<br />
+bbb</p>
diff --git a/pkgs/markdown/test/gfm/precedence.unit b/pkgs/markdown/test/gfm/precedence.unit
new file mode 100644
index 0000000..793a094
--- /dev/null
+++ b/pkgs/markdown/test/gfm/precedence.unit
@@ -0,0 +1,8 @@
+>>> Precedence - 12
+- `one
+- two`
+<<<
+<ul>
+<li>`one</li>
+<li>two`</li>
+</ul>
diff --git a/pkgs/markdown/test/gfm/raw_html.unit b/pkgs/markdown/test/gfm/raw_html.unit
new file mode 100644
index 0000000..b408353
--- /dev/null
+++ b/pkgs/markdown/test/gfm/raw_html.unit
@@ -0,0 +1,95 @@
+>>> Raw HTML - 632
+<a><bab><c2c>
+<<<
+<p><a><bab><c2c></p>
+>>> Raw HTML - 633
+<a/><b2/>
+<<<
+<p><a/><b2/></p>
+>>> Raw HTML - 634
+<a /><b2
+data="foo" >
+<<<
+<p><a /><b2
+data="foo" ></p>
+>>> Raw HTML - 635
+<a foo="bar" bam = 'baz <em>"</em>'
+_boolean zoop:33=zoop:33 />
+<<<
+<p><a foo="bar" bam = 'baz <em>"</em>'
+_boolean zoop:33=zoop:33 /></p>
+>>> Raw HTML - 636
+Foo <responsive-image src="foo.jpg" />
+<<<
+<p>Foo <responsive-image src="foo.jpg" /></p>
+>>> Raw HTML - 637
+<33> <__>
+<<<
+<p><33> <__></p>
+>>> Raw HTML - 638
+<a h*#ref="hi">
+<<<
+<p><a h*#ref="hi"></p>
+>>> Raw HTML - 639
+<a href="hi'> <a href=hi'>
+<<<
+<p><a href="hi'> <a href=hi'></p>
+>>> Raw HTML - 640
+< a><
+foo><bar/ >
+<foo bar=baz
+bim!bop />
+<<<
+<p>< a><
+foo><bar/ >
+<foo bar=baz
+bim!bop /></p>
+>>> Raw HTML - 641
+<a href='bar'title=title>
+<<<
+<p><a href='bar'title=title></p>
+>>> Raw HTML - 642
+</a></foo >
+<<<
+<p></a></foo ></p>
+>>> Raw HTML - 643
+</a href="foo">
+<<<
+<p></a href="foo"></p>
+>>> Raw HTML - 644
+foo <!-- this is a --
+comment - with hyphens -->
+<<<
+<p>foo <!-- this is a --
+comment - with hyphens --></p>
+>>> Raw HTML - 645
+foo <!--> foo -->
+
+foo <!---> foo -->
+<<<
+<p>foo <!--> foo --></p>
+<p>foo <!---> foo --></p>
+>>> Raw HTML - 646
+foo <?php echo $a; ?>
+<<<
+<p>foo <?php echo $a; ?></p>
+>>> Raw HTML - 647
+foo <!ELEMENT br EMPTY>
+<<<
+<p>foo <!ELEMENT br EMPTY></p>
+>>> Raw HTML - 648
+foo <![CDATA[>&<]]>
+<<<
+<p>foo <![CDATA[>&<]]></p>
+>>> Raw HTML - 649
+foo <a href="ö">
+<<<
+<p>foo <a href="ö"></p>
+>>> Raw HTML - 650
+foo <a href="\*">
+<<<
+<p>foo <a href="\*"></p>
+>>> Raw HTML - 651
+<a href="\"">
+<<<
+<p><a href="""></p>
diff --git a/pkgs/markdown/test/gfm/setext_headings.unit b/pkgs/markdown/test/gfm/setext_headings.unit
new file mode 100644
index 0000000..725a175
--- /dev/null
+++ b/pkgs/markdown/test/gfm/setext_headings.unit
@@ -0,0 +1,229 @@
+>>> Setext headings - 50
+Foo *bar*
+=========
+
+Foo *bar*
+---------
+<<<
+<h1>Foo <em>bar</em></h1>
+<h2>Foo <em>bar</em></h2>
+>>> Setext headings - 51
+Foo *bar
+baz*
+====
+<<<
+<h1>Foo <em>bar
+baz</em></h1>
+>>> Setext headings - 52
+ Foo *bar
+baz*
+====
+<<<
+<h1> Foo <em>bar
+baz</em></h1>
+>>> Setext headings - 53
+Foo
+-------------------------
+
+Foo
+=
+<<<
+<h2>Foo</h2>
+<h1>Foo</h1>
+>>> Setext headings - 54
+ Foo
+---
+
+ Foo
+-----
+
+ Foo
+ ===
+<<<
+<h2> Foo</h2>
+<h2> Foo</h2>
+<h1> Foo</h1>
+>>> Setext headings - 55
+ Foo
+ ---
+
+ Foo
+---
+<<<
+<pre><code>Foo
+---
+
+Foo
+</code></pre>
+<hr />
+>>> Setext headings - 56
+Foo
+ ----
+<<<
+<h2>Foo</h2>
+>>> Setext headings - 57
+Foo
+ ---
+<<<
+<p>Foo
+---</p>
+>>> Setext headings - 58
+Foo
+= =
+
+Foo
+--- -
+<<<
+<p>Foo
+= =</p>
+<p>Foo</p>
+<hr />
+>>> Setext headings - 59
+Foo
+-----
+<<<
+<h2>Foo</h2>
+>>> Setext headings - 60
+Foo\
+----
+<<<
+<h2>Foo\</h2>
+>>> Setext headings - 61
+`Foo
+----
+`
+
+<a title="a lot
+---
+of dashes"/>
+<<<
+<h2>`Foo</h2>
+<p>`</p>
+<h2><a title="a lot</h2>
+<p>of dashes"/></p>
+>>> Setext headings - 62
+> Foo
+---
+<<<
+<blockquote>
+<p>Foo</p>
+</blockquote>
+<hr />
+>>> Setext headings - 63
+> foo
+bar
+===
+<<<
+<blockquote>
+<p>foo
+bar
+===</p>
+</blockquote>
+>>> Setext headings - 64
+- Foo
+---
+<<<
+<ul>
+<li>Foo</li>
+</ul>
+<hr />
+>>> Setext headings - 65
+Foo
+Bar
+---
+<<<
+<h2>Foo
+Bar</h2>
+>>> Setext headings - 66
+---
+Foo
+---
+Bar
+---
+Baz
+<<<
+<hr />
+<h2>Foo</h2>
+<h2>Bar</h2>
+<p>Baz</p>
+>>> Setext headings - 67
+
+====
+<<<
+<p>====</p>
+>>> Setext headings - 68
+---
+---
+<<<
+<hr />
+<hr />
+>>> Setext headings - 69
+- foo
+-----
+<<<
+<ul>
+<li>foo</li>
+</ul>
+<hr />
+>>> Setext headings - 70
+ foo
+---
+<<<
+<pre><code>foo
+</code></pre>
+<hr />
+>>> Setext headings - 71
+> foo
+-----
+<<<
+<blockquote>
+<p>foo</p>
+</blockquote>
+<hr />
+>>> Setext headings - 72
+\> foo
+------
+<<<
+<h2>> foo</h2>
+>>> Setext headings - 73
+Foo
+
+bar
+---
+baz
+<<<
+<p>Foo</p>
+<h2>bar</h2>
+<p>baz</p>
+>>> Setext headings - 74
+Foo
+bar
+
+---
+
+baz
+<<<
+<p>Foo
+bar</p>
+<hr />
+<p>baz</p>
+>>> Setext headings - 75
+Foo
+bar
+* * *
+baz
+<<<
+<p>Foo
+bar</p>
+<hr />
+<p>baz</p>
+>>> Setext headings - 76
+Foo
+bar
+\---
+baz
+<<<
+<p>Foo
+bar
+---
+baz</p>
diff --git a/pkgs/markdown/test/gfm/soft_line_breaks.unit b/pkgs/markdown/test/gfm/soft_line_breaks.unit
new file mode 100644
index 0000000..2186b00
--- /dev/null
+++ b/pkgs/markdown/test/gfm/soft_line_breaks.unit
@@ -0,0 +1,12 @@
+>>> Soft line breaks - 668
+foo
+baz
+<<<
+<p>foo
+baz</p>
+>>> Soft line breaks - 669
+foo
+ baz
+<<<
+<p>foo
+baz</p>
diff --git a/pkgs/markdown/test/gfm/strikethrough_extension.unit b/pkgs/markdown/test/gfm/strikethrough_extension.unit
new file mode 100644
index 0000000..0d6f75f
--- /dev/null
+++ b/pkgs/markdown/test/gfm/strikethrough_extension.unit
@@ -0,0 +1,19 @@
+>>> Strikethrough (extension) - 491
+~~Hi~~ Hello, world!
+<<<
+<p><del>Hi</del> Hello, world!</p>
+>>> Strikethrough (extension) - 492
+This ~~has a
+
+new paragraph~~.
+<<<
+<p>This ~~has a</p>
+<p>new paragraph~~.</p>
+>>> single tilde
+~Hi~ there.
+<<<
+<p><del>Hi</del> there.</p>
+>>> single tilde with double tilde
+~Hi~~ there.
+<<<
+<p><del>Hi</del>~ there.</p>
diff --git a/pkgs/markdown/test/gfm/tables_extension.unit b/pkgs/markdown/test/gfm/tables_extension.unit
new file mode 100644
index 0000000..625fca8
--- /dev/null
+++ b/pkgs/markdown/test/gfm/tables_extension.unit
@@ -0,0 +1,153 @@
+>>> Tables (extension) - 198
+| foo | bar |
+| --- | --- |
+| baz | bim |
+<<<
+<table>
+<thead>
+<tr>
+<th>foo</th>
+<th>bar</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>baz</td>
+<td>bim</td>
+</tr>
+</tbody>
+</table>
+>>> Tables (extension) - 199
+| abc | defghi |
+:-: | -----------:
+bar | baz
+<<<
+<table>
+<thead>
+<tr>
+<th align="center">abc</th>
+<th align="right">defghi</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td align="center">bar</td>
+<td align="right">baz</td>
+</tr>
+</tbody>
+</table>
+>>> Tables (extension) - 200
+| f\|oo |
+| ------ |
+| b `\|` az |
+| b **\|** im |
+<<<
+<table>
+<thead>
+<tr>
+<th>f|oo</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>b <code>|</code> az</td>
+</tr>
+<tr>
+<td>b <strong>|</strong> im</td>
+</tr>
+</tbody>
+</table>
+>>> Tables (extension) - 201
+| abc | def |
+| --- | --- |
+| bar | baz |
+> bar
+<<<
+<table>
+<thead>
+<tr>
+<th>abc</th>
+<th>def</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>bar</td>
+<td>baz</td>
+</tr>
+</tbody>
+</table>
+<blockquote>
+<p>bar</p>
+</blockquote>
+>>> Tables (extension) - 202
+| abc | def |
+| --- | --- |
+| bar | baz |
+bar
+
+bar
+<<<
+<table>
+<thead>
+<tr>
+<th>abc</th>
+<th>def</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>bar</td>
+<td>baz</td>
+</tr>
+<tr>
+<td>bar</td>
+<td></td>
+</tr>
+</tbody>
+</table>
+<p>bar</p>
+>>> Tables (extension) - 203
+| abc | def |
+| --- |
+| bar |
+<<<
+<p>| abc | def |
+| --- |
+| bar |</p>
+>>> Tables (extension) - 204
+| abc | def |
+| --- | --- |
+| bar |
+| bar | baz | boo |
+<<<
+<table>
+<thead>
+<tr>
+<th>abc</th>
+<th>def</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>bar</td>
+<td></td>
+</tr>
+<tr>
+<td>bar</td>
+<td>baz</td>
+</tr>
+</tbody>
+</table>
+>>> Tables (extension) - 205
+| abc | def |
+| --- | --- |
+<<<
+<table>
+<thead>
+<tr>
+<th>abc</th>
+<th>def</th>
+</tr>
+</thead>
+</table>
diff --git a/pkgs/markdown/test/gfm/tabs.unit b/pkgs/markdown/test/gfm/tabs.unit
new file mode 100644
index 0000000..1239481
--- /dev/null
+++ b/pkgs/markdown/test/gfm/tabs.unit
@@ -0,0 +1,87 @@
+>>> Tabs - 1
+ foo baz bim
+<<<
+<pre><code>foo baz bim
+</code></pre>
+>>> Tabs - 2
+ foo baz bim
+<<<
+<pre><code>foo baz bim
+</code></pre>
+>>> Tabs - 3
+ a a
+ ὐ a
+<<<
+<pre><code>a a
+ὐ a
+</code></pre>
+>>> Tabs - 4
+ - foo
+
+ bar
+<<<
+<ul>
+<li>
+<p>foo</p>
+<p>bar</p>
+</li>
+</ul>
+>>> Tabs - 5
+- foo
+
+ bar
+<<<
+<ul>
+<li>
+<p>foo</p>
+<pre><code> bar
+</code></pre>
+</li>
+</ul>
+>>> Tabs - 6
+> foo
+<<<
+<blockquote>
+<pre><code>foo
+</code></pre>
+</blockquote>
+>>> Tabs - 7
+- foo
+<<<
+<ul>
+<li>
+<pre><code> foo
+</code></pre>
+</li>
+</ul>
+>>> Tabs - 8
+ foo
+ bar
+<<<
+<pre><code>foo
+bar
+</code></pre>
+>>> Tabs - 9
+ - foo
+ - bar
+ - baz
+<<<
+<ul>
+<li>foo
+<ul>
+<li>bar
+<ul>
+<li>baz</li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+>>> Tabs - 10
+# Foo
+<<<
+<h1>Foo</h1>
+>>> Tabs - 11
+* * *
+<<<
+<hr />
diff --git a/pkgs/markdown/test/gfm/textual_content.unit b/pkgs/markdown/test/gfm/textual_content.unit
new file mode 100644
index 0000000..7a1b02c
--- /dev/null
+++ b/pkgs/markdown/test/gfm/textual_content.unit
@@ -0,0 +1,12 @@
+>>> Textual content - 670
+hello $.;'there
+<<<
+<p>hello $.;'there</p>
+>>> Textual content - 671
+Foo χρῆν
+<<<
+<p>Foo χρῆν</p>
+>>> Textual content - 672
+Multiple spaces
+<<<
+<p>Multiple spaces</p>
diff --git a/pkgs/markdown/test/gfm/thematic_breaks.unit b/pkgs/markdown/test/gfm/thematic_breaks.unit
new file mode 100644
index 0000000..85206c8
--- /dev/null
+++ b/pkgs/markdown/test/gfm/thematic_breaks.unit
@@ -0,0 +1,126 @@
+>>> Thematic breaks - 13
+***
+---
+___
+<<<
+<hr />
+<hr />
+<hr />
+>>> Thematic breaks - 14
++++
+<<<
+<p>+++</p>
+>>> Thematic breaks - 15
+===
+<<<
+<p>===</p>
+>>> Thematic breaks - 16
+--
+**
+__
+<<<
+<p>--
+**
+__</p>
+>>> Thematic breaks - 17
+ ***
+ ***
+ ***
+<<<
+<hr />
+<hr />
+<hr />
+>>> Thematic breaks - 18
+ ***
+<<<
+<pre><code>***
+</code></pre>
+>>> Thematic breaks - 19
+Foo
+ ***
+<<<
+<p>Foo
+***</p>
+>>> Thematic breaks - 20
+_____________________________________
+<<<
+<hr />
+>>> Thematic breaks - 21
+ - - -
+<<<
+<hr />
+>>> Thematic breaks - 22
+ ** * ** * ** * **
+<<<
+<hr />
+>>> Thematic breaks - 23
+- - - -
+<<<
+<hr />
+>>> Thematic breaks - 24
+- - - -
+<<<
+<hr />
+>>> Thematic breaks - 25
+_ _ _ _ a
+
+a------
+
+---a---
+<<<
+<p>_ _ _ _ a</p>
+<p>a------</p>
+<p>---a---</p>
+>>> Thematic breaks - 26
+ *-*
+<<<
+<p><em>-</em></p>
+>>> Thematic breaks - 27
+- foo
+***
+- bar
+<<<
+<ul>
+<li>foo</li>
+</ul>
+<hr />
+<ul>
+<li>bar</li>
+</ul>
+>>> Thematic breaks - 28
+Foo
+***
+bar
+<<<
+<p>Foo</p>
+<hr />
+<p>bar</p>
+>>> Thematic breaks - 29
+Foo
+---
+bar
+<<<
+<h2>Foo</h2>
+<p>bar</p>
+>>> Thematic breaks - 30
+* Foo
+* * *
+* Bar
+<<<
+<ul>
+<li>Foo</li>
+</ul>
+<hr />
+<ul>
+<li>Bar</li>
+</ul>
+>>> Thematic breaks - 31
+- Foo
+- * * *
+<<<
+<ul>
+<li>Foo</li>
+<li>
+<hr />
+</li>
+</ul>
diff --git a/pkgs/markdown/test/html_renderer_test.dart b/pkgs/markdown/test/html_renderer_test.dart
new file mode 100644
index 0000000..77c33d3
--- /dev/null
+++ b/pkgs/markdown/test/html_renderer_test.dart
@@ -0,0 +1,114 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:markdown/markdown.dart';
+import 'package:test/test.dart';
+
+void main() {
+ group('markdownToHtml', () {
+ const text = '# Hello **Markdown<em>!</em>**\n***';
+
+ test('with no syntaxes', () {
+ final result = markdownToHtml(
+ text,
+ withDefaultBlockSyntaxes: false,
+ withDefaultInlineSyntaxes: false,
+ encodeHtml: false,
+ );
+ expect(result, equals('# Hello **Markdown<em>!</em>**\n***\n'));
+ });
+
+ test('with no default syntaxes but with custom syntaxes', () {
+ final result = markdownToHtml(
+ text,
+ withDefaultBlockSyntaxes: false,
+ withDefaultInlineSyntaxes: false,
+ encodeHtml: false,
+ blockSyntaxes: [const HorizontalRuleSyntax()],
+ inlineSyntaxes: [
+ EmphasisSyntax.asterisk(),
+ ],
+ );
+
+ expect(
+ result,
+ equals('# Hello <strong>Markdown<em>!</em></strong>\n<hr />\n'),
+ );
+ });
+
+ test('with only default block syntaxes', () {
+ final result = markdownToHtml(
+ text,
+ withDefaultInlineSyntaxes: false,
+ encodeHtml: false,
+ );
+
+ expect(
+ result,
+ equals('<h1>Hello **Markdown<em>!</em>**</h1>\n<hr />\n'),
+ );
+ });
+
+ test('with only default inline syntaxes', () {
+ final result = markdownToHtml(
+ text,
+ withDefaultBlockSyntaxes: false,
+ encodeHtml: false,
+ );
+
+ expect(
+ result,
+ equals('# Hello <strong>Markdown<em>!</em></strong>\n***\n'),
+ );
+ });
+
+ test('with no default syntaxes but with encodeHtml enabled', () {
+ final result = markdownToHtml(
+ text,
+ withDefaultBlockSyntaxes: false,
+ withDefaultInlineSyntaxes: false,
+ );
+
+ expect(
+ result,
+ equals('# Hello **Markdown<em>!</em>**\n***\n'),
+ );
+ });
+ });
+
+ group('test InlineSyntax caseSensitive parameter', () {
+ const text = 'one BREAK two';
+
+ test('with caseSensitive enabled', () {
+ final result = markdownToHtml(
+ text,
+ inlineOnly: true,
+ inlineSyntaxes: [_BreakSyntax(true)],
+ );
+
+ expect(result, equals('one BREAK two'));
+ });
+
+ test('with caseSensitive disabled', () {
+ final result = markdownToHtml(
+ text,
+ inlineOnly: true,
+ inlineSyntaxes: [_BreakSyntax(false)],
+ );
+
+ expect(result, equals('one <break /> two'));
+ });
+ });
+}
+
+class _BreakSyntax extends InlineSyntax {
+ _BreakSyntax(bool caseSensitive)
+ : super('break', caseSensitive: caseSensitive);
+
+ @override
+ bool onMatch(InlineParser parser, Match match) {
+ parser.addNode(Element.empty('break'));
+ return true;
+ }
+}
diff --git a/pkgs/markdown/test/markdown_test.dart b/pkgs/markdown/test/markdown_test.dart
new file mode 100644
index 0000000..feb2d77
--- /dev/null
+++ b/pkgs/markdown/test/markdown_test.dart
@@ -0,0 +1,306 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@TestOn('vm')
+library;
+
+import 'package:markdown/markdown.dart';
+import 'package:test/test.dart';
+
+import 'util.dart';
+
+void main() async {
+ testDirectory('original');
+
+ // Block syntax extensions.
+ testFile(
+ 'extensions/fenced_blockquotes.unit',
+ blockSyntaxes: [const FencedBlockquoteSyntax()],
+ );
+ testFile(
+ 'extensions/fenced_code_blocks.unit',
+ blockSyntaxes: [const FencedCodeBlockSyntax()],
+ );
+ testFile(
+ 'extensions/headers_with_ids.unit',
+ blockSyntaxes: [const HeaderWithIdSyntax()],
+ );
+ testFile(
+ 'extensions/ordered_list_with_checkboxes.unit',
+ blockSyntaxes: [const OrderedListWithCheckboxSyntax()],
+ );
+ testFile(
+ 'extensions/setext_headers_with_ids.unit',
+ blockSyntaxes: [const SetextHeaderWithIdSyntax()],
+ );
+ testFile(
+ 'extensions/tables.unit',
+ blockSyntaxes: [const TableSyntax()],
+ );
+ testFile(
+ 'extensions/unordered_list_with_checkboxes.unit',
+ blockSyntaxes: [const UnorderedListWithCheckboxSyntax()],
+ );
+ testFile(
+ 'extensions/alert_extension.unit',
+ blockSyntaxes: [const AlertBlockSyntax()],
+ );
+
+ // Inline syntax extensions
+ testFile(
+ 'extensions/autolink_extension.unit',
+ inlineSyntaxes: [AutolinkExtensionSyntax()],
+ );
+
+ testFile(
+ 'extensions/emojis.unit',
+ inlineSyntaxes: [EmojiSyntax()],
+ );
+ testFile(
+ 'extensions/inline_html.unit',
+ inlineSyntaxes: [InlineHtmlSyntax()],
+ );
+ testFile(
+ 'extensions/strikethrough.unit',
+ inlineSyntaxes: [StrikethroughSyntax()],
+ );
+ testFile(
+ 'extensions/footnote_block.unit',
+ blockSyntaxes: [const FootnoteDefSyntax()],
+ );
+
+ testDirectory('common_mark');
+ testDirectory('gfm');
+
+ group('Corner cases', () {
+ validateCore('Incorrect Links', '''
+5 Ethernet ([Music](
+''', '''
+<p>5 Ethernet ([Music](</p>
+''');
+
+ validateCore('Incorrect Links - Issue #623 - 1 - Bracketed link 1', '''
+[](<
+''', '''
+<p>[](<</p>
+''');
+
+ validateCore('Incorrect Links - Issue #623 - 2 - Bracketed link 2', '''
+[](<>
+''', '''
+<p>[](<></p>
+''');
+
+ validateCore('Incorrect Links - Issue #623 - 3 - Bracketed link 3', r'''
+[](<\
+''', r'''
+<p>[](<\</p>
+''');
+
+ validateCore('Incorrect Links - Issue #623 - 4 - Link title 1', '''
+[](www.example.com "
+''', '''
+<p>[](www.example.com "</p>
+''');
+
+ validateCore('Incorrect Links - Issue #623 - 5 - Link title 2', r'''
+[](www.example.com "\
+''', r'''
+<p>[](www.example.com "\</p>
+''');
+
+ validateCore('Incorrect Links - Issue #623 - 6 - Reference link label', r'''
+[][\
+''', r'''
+<p>[][\</p>
+''');
+
+ validateCore('Escaping code block language', '''
+```"/><a/href="url">arbitrary_html</a>
+```
+''', '''
+<pre><code class="language-"/><a/href="url">arbitrary_html</a>"></code></pre>
+''');
+
+ validateCore('Unicode ellipsis as punctuation', '''
+"Connecting dot **A** to **B.**…"
+''', '''
+<p>"Connecting dot <strong>A</strong> to <strong>B.</strong>…"</p>
+''');
+ });
+
+ group('Resolver', () {
+ Node? nyanResolver(String text, [_]) =>
+ text.isEmpty ? null : Text('~=[,,_${text}_,,]:3');
+ validateCore(
+ 'simple link resolver',
+ '''
+resolve [this] thing
+''',
+ '''
+<p>resolve ~=[,,_this_,,]:3 thing</p>
+''',
+ linkResolver: nyanResolver);
+
+ validateCore(
+ 'simple image resolver',
+ '''
+resolve ![this] thing
+''',
+ '''
+<p>resolve ~=[,,_this_,,]:3 thing</p>
+''',
+ imageLinkResolver: nyanResolver);
+
+ validateCore(
+ 'can resolve link containing inline tags',
+ '''
+resolve [*star* _underline_] thing
+''',
+ '''
+<p>resolve ~=[,,_*star* _underline__,,]:3 thing</p>
+''',
+ linkResolver: nyanResolver);
+
+ validateCore(
+ 'link resolver uses un-normalized link label',
+ '''
+resolve [TH IS] thing
+''',
+ '''
+<p>resolve ~=[,,_TH IS_,,]:3 thing</p>
+''',
+ linkResolver: nyanResolver);
+
+ validateCore(
+ 'can resolve escaped brackets',
+ r'''
+resolve [\[\]] thing
+''',
+ '''
+<p>resolve ~=[,,_[]_,,]:3 thing</p>
+''',
+ linkResolver: nyanResolver);
+
+ validateCore(
+ 'can choose to _not_ resolve something, like an empty link',
+ '''
+resolve [[]] thing
+''',
+ '''
+<p>resolve ~=[,,_[]_,,]:3 thing</p>
+''',
+ linkResolver: nyanResolver);
+ });
+
+ group('Custom inline syntax', () {
+ final nyanSyntax = <InlineSyntax>[TextSyntax('nyan', sub: '~=[,,_,,]:3')];
+ validateCore(
+ 'simple inline syntax',
+ '''
+nyan''',
+ '''<p>~=[,,_,,]:3</p>
+''',
+ inlineSyntaxes: nyanSyntax);
+
+ validateCore(
+ 'dart custom links',
+ 'links [are<foo>] awesome',
+ '<p>links <a>are<foo></a> awesome</p>\n',
+ linkResolver: (String text, [String? _]) => Element.text(
+ 'a',
+ text.replaceAll('<', '<'),
+ ),
+ );
+
+ // TODO(amouravski): need more tests here for custom syntaxes, as some
+ // things are not quite working properly. The regexps are sometime a little
+ // too greedy, I think.
+ });
+
+ group('Inline only', () {
+ validateCore(
+ 'simple line',
+ '''
+ This would normally create a paragraph.
+ ''',
+ '''
+ This would normally create a paragraph.
+ ''',
+ inlineOnly: true);
+ validateCore(
+ 'strong and em',
+ '''
+ This would _normally_ create a **paragraph**.
+ ''',
+ '''
+ This would <em>normally</em> create a <strong>paragraph</strong>.
+ ''',
+ inlineOnly: true);
+ validateCore(
+ 'link',
+ '''
+ This [link](http://www.example.com/) will work normally.
+ ''',
+ '''
+ This <a href="http://www.example.com/">link</a> will work normally.
+ ''',
+ inlineOnly: true);
+ validateCore(
+ 'references do not work',
+ '''
+ [This][] shouldn't work, though.
+ ''',
+ '''
+ [This][] shouldn't work, though.
+ ''',
+ inlineOnly: true);
+ validateCore(
+ 'less than and ampersand are escaped',
+ '''
+ < &
+ ''',
+ '''
+ < &
+ ''',
+ inlineOnly: true);
+ validateCore(
+ 'keeps newlines',
+ '''
+ This paragraph
+ continues after a newline.
+ ''',
+ '''
+ This paragraph
+ continues after a newline.
+ ''',
+ inlineOnly: true);
+ validateCore(
+ 'ignores block-level markdown syntax',
+ '''
+ 1. This will not be an <ol>.
+ ''',
+ '''
+ 1. This will not be an <ol>.
+ ''',
+ inlineOnly: true);
+ });
+
+ group('ExtensionSet', () {
+ test(
+ '3 asterisks separated with spaces horizontal rule while it is '
+ 'gitHubFlavored',
+ () {
+ // Because `gitHubFlavored` will put `UnorderedListWithCheckboxSyntax`
+ // before `HorizontalRuleSyntax`, the `* * *` will be parsed into an
+ // empty unordered list if `ListSyntax` does not skip the horizontal
+ // rule structure.
+ expect(
+ markdownToHtml('* * *', extensionSet: ExtensionSet.gitHubFlavored),
+ '<hr />\n',
+ );
+ },
+ );
+ });
+}
diff --git a/pkgs/markdown/test/original/autolinks.unit b/pkgs/markdown/test/original/autolinks.unit
new file mode 100644
index 0000000..d3658e8
--- /dev/null
+++ b/pkgs/markdown/test/original/autolinks.unit
@@ -0,0 +1,10 @@
+>>> basic link
+before <http://foo.com/> after
+
+<<<
+<p>before <a href="http://foo.com/">http://foo.com/</a> after</p>
+>>> handles ampersand in url
+<http://foo.com/?a=1&b=2>
+
+<<<
+<p><a href="http://foo.com/?a=1&b=2">http://foo.com/?a=1&b=2</a></p>
diff --git a/pkgs/markdown/test/original/backslash_escapes.unit b/pkgs/markdown/test/original/backslash_escapes.unit
new file mode 100644
index 0000000..e3446f3
--- /dev/null
+++ b/pkgs/markdown/test/original/backslash_escapes.unit
@@ -0,0 +1,38 @@
+>>> Escaped punctuation is indeed escaped.
+Punctuations like \! and \" and \# and \$ and \% and \& and \' and \( and \)
+and \* and \+ and \, and \- and \. and \/ and \: and \; and \< and \= and \>
+and \? and \@ and \[ and \\ and \] and \^ and \_ and \` and \{ and \| and \}
+and \~.
+
+<<<
+<p>Punctuations like ! and " and # and $ and % and & and ' and ( and )
+and * and + and , and - and . and / and : and ; and < and = and >
+and ? and @ and [ and \ and ] and ^ and _ and ` and { and | and }
+and ~.</p>
+>>> Inline code blocks can be escaped.
+Not \`code`.
+
+<<<
+<p>Not `code`.</p>
+>>> Emphasis can be escaped.
+\*Both* \_kinds_.
+
+<<<
+<p>*Both* _kinds_.</p>
+>>> Links can be escaped.
+Escaped brackets: \[foo](bar), and parens: [foo]\(bar).
+
+<<<
+<p>Escaped brackets: [foo](bar), and parens: [foo](bar).</p>
+>>> Reference links can be escaped.
+Front: \[foo][bar] and back: [foo]\[bar].
+
+<<<
+<p>Front: [foo][bar] and back: [foo][bar].</p>
+>>> Images can be escaped.
+Escapes the bang: \,
+and escapes the image: !\[img](img.png).
+
+<<<
+<p>Escapes the bang: !<a href="img.png">img</a>,
+and escapes the image: .</p>
diff --git a/pkgs/markdown/test/original/block_level_html.unit b/pkgs/markdown/test/original/block_level_html.unit
new file mode 100644
index 0000000..ce40760
--- /dev/null
+++ b/pkgs/markdown/test/original/block_level_html.unit
@@ -0,0 +1,38 @@
+>>> single line
+<table></table>
+
+<<<
+<table></table>
+>>> multi-line
+<table>
+ blah
+</table>
+
+<<<
+<table>
+ blah
+</table>
+>>> blank line ends block
+<table>
+ blah
+</table>
+
+para
+
+<<<
+<table>
+ blah
+</table>
+<p>para</p>
+>>> HTML can be bogus
+<bogus>
+blah
+</weird>
+
+para
+
+<<<
+<bogus>
+blah
+</weird>
+<p>para</p>
diff --git a/pkgs/markdown/test/original/block_quotes.unit b/pkgs/markdown/test/original/block_quotes.unit
new file mode 100644
index 0000000..548bc1a
--- /dev/null
+++ b/pkgs/markdown/test/original/block_quotes.unit
@@ -0,0 +1,54 @@
+>>> single line
+> blah
+
+<<<
+<blockquote>
+<p>blah</p>
+</blockquote>
+>>> with two paragraphs
+> first
+>
+> second
+
+<<<
+<blockquote>
+<p>first</p>
+<p>second</p>
+</blockquote>
+>>> nested
+> one
+>> two
+> > > three
+
+<<<
+<blockquote>
+<p>one</p>
+<blockquote>
+<p>two</p>
+<blockquote>
+<p>three</p>
+</blockquote>
+</blockquote>
+</blockquote>
+>>> qoute with lazy continuation
+> quote
+text
+<<<
+<blockquote>
+<p>quote
+text</p>
+</blockquote>
+>>> quote turns what might be an h2 into an hr
+> quote
+---
+
+<<<
+<blockquote>
+<p>quote</p>
+</blockquote>
+<hr />
+>>> issue #495
+ >
+<<<
+<blockquote>
+</blockquote>
diff --git a/pkgs/markdown/test/original/code_blocks.unit b/pkgs/markdown/test/original/code_blocks.unit
new file mode 100644
index 0000000..330a90f
--- /dev/null
+++ b/pkgs/markdown/test/original/code_blocks.unit
@@ -0,0 +1,65 @@
+>>> single line
+ code
+
+<<<
+<pre><code>code
+</code></pre>
+>>> include leading whitespace after indentation
+ zero
+ one
+ two
+ three
+
+<<<
+<pre><code>zero
+ one
+ two
+ three
+</code></pre>
+>>> code blocks separated by newlines form one block
+ zero
+ one
+
+ two
+
+ three
+
+<<<
+<pre><code>zero
+one
+
+two
+
+three
+</code></pre>
+>>> code blocks separated by two newlines form multiple blocks
+ zero
+ one
+
+
+ two
+
+
+ three
+
+<<<
+<pre><code>zero
+one
+
+
+two
+
+
+three
+</code></pre>
+>>> escape HTML characters
+ <&>
+
+<<<
+<pre><code><&>
+</code></pre>
+>>> issue #497
+ 'foo'
+<<<
+<pre><code>'foo'
+</code></pre>
diff --git a/pkgs/markdown/test/original/emphasis_and_strong.unit b/pkgs/markdown/test/original/emphasis_and_strong.unit
new file mode 100644
index 0000000..13a6dd2
--- /dev/null
+++ b/pkgs/markdown/test/original/emphasis_and_strong.unit
@@ -0,0 +1,83 @@
+>>> single asterisks
+before *em* after
+
+<<<
+<p>before <em>em</em> after</p>
+>>> single underscores
+before _em_ after
+
+<<<
+<p>before <em>em</em> after</p>
+>>> double asterisks
+before **strong** after
+
+<<<
+<p>before <strong>strong</strong> after</p>
+>>> double underscores
+before __strong__ after
+
+<<<
+<p>before <strong>strong</strong> after</p>
+>>> unmatched asterisk
+before *after
+
+<<<
+<p>before *after</p>
+>>> unmatched underscore
+before _after
+
+<<<
+<p>before _after</p>
+>>> multiple spans in one text
+a *one* b _two_ c
+
+<<<
+<p>a <em>one</em> b <em>two</em> c</p>
+>>> multi-line
+before *first
+second* after
+
+<<<
+<p>before <em>first
+second</em> after</p>
+>>> not processed when surrounded by spaces
+a * b * c _ d _ e
+
+<<<
+<p>a * b * c _ d _ e</p>
+>>> strong then emphasis
+**strong***em*
+
+<<<
+<p><strong>strong</strong><em>em</em></p>
+>>> emphasis then strong
+*em***strong**
+
+<<<
+<p><em>em</em><strong>strong</strong></p>
+>>> emphasis inside strong
+**strong *em***
+
+<<<
+<p><strong>strong <em>em</em></strong></p>
+>>> mismatched in nested
+*a _b* c_
+
+<<<
+<p><em>a _b</em> c_</p>
+>>> in the middle of a word
+a_b_c a__b__c a*b*c a**b**c
+<<<
+<p>a_b_c a__b__c a<em>b</em>c a<strong>b</strong>c</p>
+>>> prefixing a word
+_a_b __a__b *a*b **a**b
+<<<
+<p>_a_b __a__b <em>a</em>b <strong>a</strong>b</p>
+>>> suffixing a word
+a_b_ a__b__ a*b* a**b**
+<<<
+<p>a_b_ a__b__ a<em>b</em> a<strong>b</strong></p>
+>>> spanning words
+_a_b c_d_ __a__b c__d__ *a*b c*d* **a**b c**d**
+<<<
+<p><em>a_b c_d</em> <strong>a__b c__d</strong> <em>a</em>b c<em>d</em> <strong>a</strong>b c<strong>d</strong></p>
diff --git a/pkgs/markdown/test/original/fenced_code_block.unit b/pkgs/markdown/test/original/fenced_code_block.unit
new file mode 100644
index 0000000..779e747
--- /dev/null
+++ b/pkgs/markdown/test/original/fenced_code_block.unit
@@ -0,0 +1,7 @@
+>>> issue #497
+```
+'foo'
+```
+<<<
+<pre><code>'foo'
+</code></pre>
diff --git a/pkgs/markdown/test/original/hard_line_breaks.unit b/pkgs/markdown/test/original/hard_line_breaks.unit
new file mode 100644
index 0000000..c8d1626
--- /dev/null
+++ b/pkgs/markdown/test/original/hard_line_breaks.unit
@@ -0,0 +1,40 @@
+>>> hard line break in a paragraph, using backslash
+First line.\
+Second line.
+
+<<<
+<p>First line.<br />
+Second line.</p>
+>>> within emphasis, using backslash
+*Emphasised\
+text.*
+
+<<<
+<p><em>Emphasised<br />
+text.</em></p>
+>>> no escape within code, using backslash
+`Some\
+code`.
+
+<<<
+<p><code>Some\ code</code>.</p>
+>>> hard line break in a paragraph, using trailing spaces
+First line.
+Second line.
+
+<<<
+<p>First line.
+Second line.</p>
+>>> within emphasis, using trailing spaces
+*Emphasised
+text.*
+
+<<<
+<p><em>Emphasised
+text.</em></p>
+>>> no escape within code, using trailing spaces
+`Some
+code`.
+
+<<<
+<p><code>Some code</code>.</p>
diff --git a/pkgs/markdown/test/original/headers.unit b/pkgs/markdown/test/original/headers.unit
new file mode 100644
index 0000000..928da8b
--- /dev/null
+++ b/pkgs/markdown/test/original/headers.unit
@@ -0,0 +1,35 @@
+>>> h1
+# header
+
+<<<
+<h1>header</h1>
+>>> h2
+## header
+
+<<<
+<h2>header</h2>
+>>> h3
+### header
+
+<<<
+<h3>header</h3>
+>>> h4
+#### header
+
+<<<
+<h4>header</h4>
+>>> h5
+##### header
+
+<<<
+<h5>header</h5>
+>>> h6
+###### header
+
+<<<
+<h6>header</h6>
+>>> trailing "#" are removed
+# header ######
+
+<<<
+<h1>header</h1>
diff --git a/pkgs/markdown/test/original/horizontal_rules.unit b/pkgs/markdown/test/original/horizontal_rules.unit
new file mode 100644
index 0000000..36642e9
--- /dev/null
+++ b/pkgs/markdown/test/original/horizontal_rules.unit
@@ -0,0 +1,20 @@
+>>> from dashes
+---
+
+<<<
+<hr />
+>>> from asterisks
+***
+
+<<<
+<hr />
+>>> from underscores
+___
+
+<<<
+<hr />
+>>> can include up to two spaces
+_ _ _
+
+<<<
+<hr />
diff --git a/pkgs/markdown/test/original/html_block.unit b/pkgs/markdown/test/original/html_block.unit
new file mode 100644
index 0000000..f6b9216
--- /dev/null
+++ b/pkgs/markdown/test/original/html_block.unit
@@ -0,0 +1,11 @@
+>>> issue https://github.com/dart-lang/markdown/issues/547
+<?code-excerpt ?>
+```xml
+<q>
+</q>
+```
+<<<
+<?code-excerpt ?>
+<pre><code class="language-xml"><q>
+</q>
+</code></pre>
\ No newline at end of file
diff --git a/pkgs/markdown/test/original/html_encoding.unit b/pkgs/markdown/test/original/html_encoding.unit
new file mode 100644
index 0000000..dab9043
--- /dev/null
+++ b/pkgs/markdown/test/original/html_encoding.unit
@@ -0,0 +1,15 @@
+>>> less than and ampersand are escaped
+< &
+
+<<<
+<p>< &</p>
+>>> greater than is escaped
+not you >
+
+<<<
+<p>not you ></p>
+>>> existing entities are untouched
+&
+
+<<<
+<p>&</p>
diff --git a/pkgs/markdown/test/original/inline_code.unit b/pkgs/markdown/test/original/inline_code.unit
new file mode 100644
index 0000000..7315931
--- /dev/null
+++ b/pkgs/markdown/test/original/inline_code.unit
@@ -0,0 +1,87 @@
+>>> simple case
+before `source` after
+
+<<<
+<p>before <code>source</code> after</p>
+>>> single characters
+before `x` and `_` after
+
+<<<
+<p>before <code>x</code> and <code>_</code> after</p>
+>>> unmatched backtick
+before ` after
+
+<<<
+<p>before ` after</p>
+>>> multiple spans in one text
+a `one` b `two` c
+
+<<<
+<p>a <code>one</code> b <code>two</code> c</p>
+>>> multi-line
+before `first
+second` after
+
+<<<
+<p>before <code>first second</code> after</p>
+>>> simple double backticks
+before ``source`` after
+
+<<<
+<p>before <code>source</code> after</p>
+>>> even more backticks
+before ````source with ``` and```` after
+
+<<<
+<p>before <code>source with ``` and</code> after</p>
+>>> double backticks
+before ``can `contain` backticks`` after
+
+<<<
+<p>before <code>can `contain` backticks</code> after</p>
+>>> double backticks with spaces
+before `` `tick` `` after
+
+<<<
+<p>before <code>`tick`</code> after</p>
+>>> multiline single backticks with spaces
+before `in tick
+another` after
+
+<<<
+<p>before <code>in tick another</code> after</p>
+>>> multiline double backticks with spaces
+before ``in `tick`
+another`` after
+
+<<<
+<p>before <code>in `tick` another</code> after</p>
+>>> ignore markup inside code
+before `*b* _c_` after
+
+<<<
+<p>before <code>*b* _c_</code> after</p>
+>>> escape HTML characters
+`<&>`
+
+<<<
+<p><code><&></code></p>
+>>> escape HTML tags
+'*' `<em>`
+
+<<<
+<p>'*' <code><em></code></p>
+>>> leave unmatched backticks when first are too long
+before ``` tick `` after
+
+<<<
+<p>before ``` tick `` after</p>
+>>> leave unmatched backticks when first are too short
+before `` tick ``` after
+
+<<<
+<p>before `` tick ``` after</p>
+>>> issue #497
+`'foo'`
+<<<
+<p><code>'foo'</code></p>
diff --git a/pkgs/markdown/test/original/inline_images.unit b/pkgs/markdown/test/original/inline_images.unit
new file mode 100644
index 0000000..c8180ce
--- /dev/null
+++ b/pkgs/markdown/test/original/inline_images.unit
@@ -0,0 +1,29 @@
+>>> image
+
+
+<<<
+<p><img src="http://foo.com/foo.png" alt="" /></p>
+>>> alternate text
+
+
+<<<
+<p><img src="http://foo.com/foo.png" alt="alternate text" /></p>
+>>> title
+
+
+<<<
+<p><img src="http://foo.com/foo.png" alt="" title="optional title" /></p>
+>>> invalid alt text
+
+
+<<<
+<p><img src="http://foo.com/foo.png" alt="alt" /></p>
+>>> XSS
+)
+
+<<<
+<p><img src="%22onerror=%22alert('XSS')" alt="Uh oh..." /></p>
+>>> URL-escaping should be left alone inside the destination
+
+<<<
+<p><img src="https://example/foo%2Fvar" alt="" /></p>
\ No newline at end of file
diff --git a/pkgs/markdown/test/original/inline_links.unit b/pkgs/markdown/test/original/inline_links.unit
new file mode 100644
index 0000000..0a40407
--- /dev/null
+++ b/pkgs/markdown/test/original/inline_links.unit
@@ -0,0 +1,87 @@
+>>> double quotes for title
+links [are](http://foo.com "woo") awesome
+
+<<<
+<p>links <a href="http://foo.com" title="woo">are</a> awesome</p>
+>>> no title
+links [are](http://foo.com) awesome
+
+<<<
+<p>links <a href="http://foo.com">are</a> awesome</p>
+>>> can style link contents
+links [*are*](http://foo.com) awesome
+
+<<<
+<p>links <a href="http://foo.com"><em>are</em></a> awesome</p>
+>>> image inside link
+links [](http://foo.com) awesome
+
+<<<
+<p>links <a href="http://foo.com"><img src="/are.png" alt="" /></a> awesome</p>
+>>> image with alt inside link
+links [](http://foo.com) awesome
+
+<<<
+<p>links <a href="http://foo.com"><img src="/are.png" alt="my alt" /></a> awesome</p>
+>>> image with title inside link
+links [](http://foo.com) awesome
+
+<<<
+<p>links <a href="http://foo.com"><img src="/are.png" alt="" title="my title" /></a> awesome</p>
+>>> no URL
+links [are]() awesome
+
+<<<
+<p>links <a href="">are</a> awesome</p>
+>>> URL wrapped in angle brackets
+links [are](<http://example.com>) awesome
+
+<<<
+<p>links <a href="http://example.com">are</a> awesome</p>
+>>> URL wrapped in angle brackets with a title; https://github.com/commonmark/CommonMark/issues/521
+links [are](<http://example.com> "title") awesome
+
+<<<
+<p>links <a href="http://example.com" title="title">are</a> awesome</p>
+>>> multi-line link
+links [are
+awesome](<http://example.com>).
+
+<<<
+<p>links <a href="http://example.com">are
+awesome</a>.</p>
+>>> multi-line link with a title
+links [are](http://foo.com
+"woo") awesome
+
+<<<
+<p>links <a href="http://foo.com" title="woo">are</a> awesome</p>
+>>> not a real link
+links [are] (http://foo.com) awesome
+
+<<<
+<p>links [are] (http://foo.com) awesome</p>
+>>> resolver link without a resolver
+links [are *awesome*]
+
+<<<
+<p>links [are <em>awesome</em>]</p>
+>>> links with escaped parens
+[a](\(yes-a-link)
+[a](\(yes-a-link\))
+[a](\\(not-a-link\))
+[a](\\(yes-a-link\)))
+<<<
+<p><a href="(yes-a-link">a</a>
+<a href="(yes-a-link)">a</a>
+[a](\(not-a-link))
+<a href="(yes-a-link))">a</a></p>
+>>> links with unbalanced parentheses
+[foo](link(1.png) (what?)
+<<<
+<p>[foo](link(1.png) (what?)</p>
+>>> not an inline link: the title's ending quote is escaped
+links [are](<http://example.com> "title\") awesome
+
+<<<
+<p>links [are](<a href="http://example.com">http://example.com</a> "title") awesome</p>
\ No newline at end of file
diff --git a/pkgs/markdown/test/original/ordered_lists.unit b/pkgs/markdown/test/original/ordered_lists.unit
new file mode 100644
index 0000000..8156889
--- /dev/null
+++ b/pkgs/markdown/test/original/ordered_lists.unit
@@ -0,0 +1,49 @@
+>>> ordered list with multiple items
+1. one
+2. two
+10. ten
+<<<
+<ol>
+<li>one</li>
+<li>two</li>
+<li>ten</li>
+</ol>
+>>> ordered list with almost nested item
+1. one
+45. two
+ 12345. three
+
+<<<
+<ol>
+<li>one</li>
+<li>two</li>
+<li>three</li>
+</ol>
+>>> nested ordered lists
+1. one
+2. two
+ 3. three
+ 4. four
+5. five
+<<<
+<ol>
+<li>one</li>
+<li>two
+<ol start="3">
+<li>three</li>
+<li>four</li>
+</ol>
+</li>
+<li>five</li>
+</ol>
+>>> new list markers start new lists
+1. a
+* b
+
+<<<
+<ol>
+<li>a</li>
+</ol>
+<ul>
+<li>b</li>
+</ul>
diff --git a/pkgs/markdown/test/original/paragraphs.unit b/pkgs/markdown/test/original/paragraphs.unit
new file mode 100644
index 0000000..a20a556
--- /dev/null
+++ b/pkgs/markdown/test/original/paragraphs.unit
@@ -0,0 +1,55 @@
+>>> consecutive lines form a single paragraph
+This is the first line.
+This is the second line.
+
+<<<
+<p>This is the first line.
+This is the second line.</p>
+>>> are terminated by a header
+para
+# header
+
+<<<
+<p>para</p>
+<h1>header</h1>
+>>> are terminated by a hr
+para
+___
+
+<<<
+<p>para</p>
+<hr />
+>>> are terminated by an unordered list
+para
+* list
+
+<<<
+<p>para</p>
+<ul>
+<li>list</li>
+</ul>
+>>> are terminated by an ordered list
+para
+1. list
+
+<<<
+<p>para</p>
+<ol>
+<li>list</li>
+</ol>
+>>> take account of windows line endings
+line1
+
+line2
+
+
+<<<
+<p>line1</p>
+<p>line2</p>
+>>> cannot be terminated by indented code blocks
+para
+ not code
+
+<<<
+<p>para
+not code</p>
diff --git a/pkgs/markdown/test/original/reference_images.unit b/pkgs/markdown/test/original/reference_images.unit
new file mode 100644
index 0000000..b098d24
--- /dev/null
+++ b/pkgs/markdown/test/original/reference_images.unit
@@ -0,0 +1,34 @@
+>>> image
+![][foo]
+
+[foo]: http://foo.com/foo.png
+
+<<<
+<p><img src="http://foo.com/foo.png" alt="" /></p>
+>>> alternate text
+![alternate text][foo]
+
+[foo]: http://foo.com/foo.png
+
+<<<
+<p><img src="http://foo.com/foo.png" alt="alternate text" /></p>
+>>> title
+![][foo]
+
+[foo]: http://foo.com/foo.png "optional title"
+
+<<<
+<p><img src="http://foo.com/foo.png" alt="" title="optional title" /></p>
+>>> invalid alt text
+![`alt`][foo]
+
+[foo]: http://foo.com/foo.png "optional title"
+
+<<<
+<p><img src="http://foo.com/foo.png" alt="alt" title="optional title" /></p>
+>>> shortcut reference image
+![foo]
+
+[foo]: http://foo.com/foo.png
+<<<
+<p><img src="http://foo.com/foo.png" alt="foo" /></p>
diff --git a/pkgs/markdown/test/original/reference_links.unit b/pkgs/markdown/test/original/reference_links.unit
new file mode 100644
index 0000000..bc3e336
--- /dev/null
+++ b/pkgs/markdown/test/original/reference_links.unit
@@ -0,0 +1,100 @@
+>>> double quotes for title
+links [are][a] awesome
+
+[a]: http://foo.com "woo"
+
+<<<
+<p>links <a href="http://foo.com" title="woo">are</a> awesome</p>
+>>> single quoted title
+links [are][a] awesome
+
+[a]: http://foo.com 'woo'
+
+<<<
+<p>links <a href="http://foo.com" title="woo">are</a> awesome</p>
+>>> parentheses for title
+links [are][a] awesome
+
+[a]: http://foo.com (woo)
+
+<<<
+<p>links <a href="http://foo.com" title="woo">are</a> awesome</p>
+>>> no title
+links [are][a] awesome
+
+[a]: http://foo.com
+
+<<<
+<p>links <a href="http://foo.com">are</a> awesome</p>
+>>> unknown link becomes plaintext
+[not] [known]
+
+<<<
+<p>[not] [known]</p>
+>>> can style link contents
+links [*are*][a] awesome
+
+[a]: http://foo.com
+
+<<<
+<p>links <a href="http://foo.com"><em>are</em></a> awesome</p>
+>>> inline styles after a bad link are processed
+[bad] `code`
+
+<<<
+<p>[bad] <code>code</code></p>
+>>> empty reference uses text from link
+links [are][] awesome
+
+[are]: http://foo.com
+
+<<<
+<p>links <a href="http://foo.com">are</a> awesome</p>
+>>> references are case-insensitive
+links [ARE][] awesome
+
+[are]: http://foo.com
+
+<<<
+<p>links <a href="http://foo.com">ARE</a> awesome</p>
+>>> shortcut reference links
+links [are] awesome
+
+[are]: http://foo.com
+<<<
+<p>links <a href="http://foo.com">are</a> awesome</p>
+>>> reference definitions can span lines
+links [are] [awesome]
+
+[are]:
+http://foo.com
+[awesome]:
+http://bar.com
+"Long
+Title"
+<<<
+<p>links <a href="http://foo.com">are</a> <a href="http://bar.com" title="Long
+Title">awesome</a></p>
+>>> references can be defined in blocks
+> links [are] awesome
+>
+> [are]: http://foo.com
+<<<
+<blockquote>
+<p>links <a href="http://foo.com">are</a> awesome</p>
+</blockquote>
+>>> reference link regression for github.com/dart-lang/markdown/issues/176
+[![Coverage Status][coverage_status]][coverage_page]
+
+[coverage_page]:https://coveralls.io/github/yeradis/stay_points.dart?branch=master
+[coverage_status]: https://coveralls.io/repos/github/yeradis/stay_points.dart/badge.svg?branch=master
+<<<
+<p><a href="https://coveralls.io/github/yeradis/stay_points.dart?branch=master"><img src="https://coveralls.io/repos/github/yeradis/stay_points.dart/badge.svg?branch=master" alt="Coverage Status" /></a></p>
+>>> compressed reference link label is normalized
+Text [foo
+bar][].
+
+[foo bar]: http://bar.com
+<<<
+<p>Text <a href="http://bar.com">foo
+bar</a>.</p>
diff --git a/pkgs/markdown/test/original/setext_headers.unit b/pkgs/markdown/test/original/setext_headers.unit
new file mode 100644
index 0000000..f094801
--- /dev/null
+++ b/pkgs/markdown/test/original/setext_headers.unit
@@ -0,0 +1,32 @@
+>>> h1
+text
+===
+
+<<<
+<h1>text</h1>
+>>> h2
+text
+---
+
+<<<
+<h2>text</h2>
+>>> h1 bar on first line becomes text
+===
+
+<<<
+<p>===</p>
+>>> h2 bar on first line becomes list
+-
+
+<<<
+<ul>
+<li></li>
+</ul>
+>>> can be multiline
+header
+on two lines
+==
+
+<<<
+<h1>header
+on two lines</h1>
diff --git a/pkgs/markdown/test/original/strong.unit b/pkgs/markdown/test/original/strong.unit
new file mode 100644
index 0000000..e558424
--- /dev/null
+++ b/pkgs/markdown/test/original/strong.unit
@@ -0,0 +1,32 @@
+>>> using asterisks
+before **strong** after
+
+<<<
+<p>before <strong>strong</strong> after</p>
+>>> using underscores
+before __strong__ after
+
+<<<
+<p>before <strong>strong</strong> after</p>
+>>> unmatched asterisks
+before ** after
+
+<<<
+<p>before ** after</p>
+>>> unmatched underscores
+before __ after
+
+<<<
+<p>before __ after</p>
+>>> multiple spans in one text
+a **one** b __two__ c
+
+<<<
+<p>a <strong>one</strong> b <strong>two</strong> c</p>
+>>> multi-line
+before **first
+second** after
+
+<<<
+<p>before <strong>first
+second</strong> after</p>
diff --git a/pkgs/markdown/test/original/unordered_lists.unit b/pkgs/markdown/test/original/unordered_lists.unit
new file mode 100644
index 0000000..6017775
--- /dev/null
+++ b/pkgs/markdown/test/original/unordered_lists.unit
@@ -0,0 +1,151 @@
+>>> asterisk, plus and hyphen
+* star
+- dash
++ plus
+
+<<<
+<ul>
+<li>star</li>
+</ul>
+<ul>
+<li>dash</li>
+</ul>
+<ul>
+<li>plus</li>
+</ul>
+>>> new markers begin new lists
+* a
+1. b
+
+<<<
+<ul>
+<li>a</li>
+</ul>
+<ol>
+<li>b</li>
+</ol>
+>>> allow a tab after the marker
+* a
+1. b
+
+<<<
+<ul>
+<li>a</li>
+</ul>
+<ol>
+<li>b</li>
+</ol>
+>>> wrap items in paragraphs if blank lines separate
+* one
+
+* two
+
+<<<
+<ul>
+<li>
+<p>one</p>
+</li>
+<li>
+<p>two</p>
+</li>
+</ul>
+>>> force paragraph on item before and after blank lines
+* one
+* two
+
+* three
+
+<<<
+<ul>
+<li>
+<p>one</p>
+</li>
+<li>
+<p>two</p>
+</li>
+<li>
+<p>three</p>
+</li>
+</ul>
+>>> do not force paragraph if item is already block
+* > quote
+
+* # header
+
+<<<
+<ul>
+<li>
+<blockquote>
+<p>quote</p>
+</blockquote>
+</li>
+<li>
+<h1>header</h1>
+</li>
+</ul>
+>>> can contain multiple paragraphs
+* one
+
+ two
+
+* three
+
+<<<
+<ul>
+<li>
+<p>one</p>
+<p>two</p>
+</li>
+<li>
+<p>three</p>
+</li>
+</ul>
+>>> can span newlines
+* one
+ two
+* three
+
+<<<
+<ul>
+<li>one
+two</li>
+<li>three</li>
+</ul>
+>>> can nest lists
+* one
+ * nested one
+ * nested two
+
+* two
+
+<<<
+<ul>
+<li>
+<p>one</p>
+<ul>
+<li>nested one</li>
+<li>nested two</li>
+</ul>
+</li>
+<li>
+<p>two</p>
+</li>
+</ul>
+>>> list item allows lazy continuations
+- list
+item
+
+<<<
+<ul>
+<li>list
+item</li>
+</ul>
+>>> list item turns what might be an h2 into nothing
+- list
+---
+
+<<<
+<ul>
+<li>list</li>
+</ul>
+<hr />
diff --git a/pkgs/markdown/test/util.dart b/pkgs/markdown/test/util.dart
new file mode 100644
index 0000000..3d7dc6a
--- /dev/null
+++ b/pkgs/markdown/test/util.dart
@@ -0,0 +1,124 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:io/ansi.dart' as ansi;
+import 'package:markdown/markdown.dart';
+import 'package:path/path.dart' as p;
+import 'package:test/test.dart';
+
+import '../tool/expected_output.dart';
+
+/// Runs tests defined in "*.unit" files inside directory [name].
+void testDirectory(String name, {ExtensionSet? extensionSet}) {
+ for (final dataCase in dataCasesUnder(testDirectory: name)) {
+ final description =
+ '${dataCase.directory}/${dataCase.file}.unit ${dataCase.description}';
+
+ final inlineSyntaxes = <InlineSyntax>[];
+ final blockSyntaxes = <BlockSyntax>[];
+ var enableTagfilter = false;
+
+ if (dataCase.file.endsWith('_extension')) {
+ final extension = dataCase.file.substring(
+ 0,
+ dataCase.file.lastIndexOf('_extension'),
+ );
+ switch (extension) {
+ case 'autolinks':
+ inlineSyntaxes.add(AutolinkExtensionSyntax());
+ break;
+ case 'strikethrough':
+ inlineSyntaxes.add(StrikethroughSyntax());
+ break;
+ case 'tables':
+ blockSyntaxes.add(const TableSyntax());
+ break;
+ case 'disallowed_raw_html':
+ enableTagfilter = true;
+ break;
+ default:
+ throw UnimplementedError('Unimplemented extension "$extension"');
+ }
+ }
+
+ validateCore(
+ description,
+ dataCase.input,
+ dataCase.expectedOutput,
+ extensionSet: extensionSet,
+ inlineSyntaxes: inlineSyntaxes,
+ blockSyntaxes: blockSyntaxes,
+ enableTagfilter: enableTagfilter,
+ );
+ }
+}
+
+void testFile(
+ String file, {
+ Iterable<BlockSyntax> blockSyntaxes = const [],
+ Iterable<InlineSyntax> inlineSyntaxes = const [],
+}) {
+ for (final dataCase
+ in dataCasesInFile(path: p.join(p.current, 'test', file))) {
+ final description =
+ '${dataCase.directory}/${dataCase.file}.unit ${dataCase.description}';
+ validateCore(
+ description,
+ dataCase.input,
+ dataCase.expectedOutput,
+ blockSyntaxes: blockSyntaxes,
+ inlineSyntaxes: inlineSyntaxes,
+ );
+ }
+}
+
+void validateCore(
+ String description,
+ String markdown,
+ String html, {
+ Iterable<BlockSyntax> blockSyntaxes = const [],
+ Iterable<InlineSyntax> inlineSyntaxes = const [],
+ ExtensionSet? extensionSet,
+ Resolver? linkResolver,
+ Resolver? imageLinkResolver,
+ bool inlineOnly = false,
+ bool enableTagfilter = false,
+}) {
+ test(description, () {
+ final result = markdownToHtml(
+ markdown,
+ blockSyntaxes: blockSyntaxes,
+ inlineSyntaxes: inlineSyntaxes,
+ extensionSet: extensionSet,
+ linkResolver: linkResolver,
+ imageLinkResolver: imageLinkResolver,
+ inlineOnly: inlineOnly,
+ enableTagfilter: enableTagfilter,
+ );
+
+ markdownPrintOnFailure(markdown, html, result);
+
+ expect(result, html);
+ });
+}
+
+String whitespaceColor(String input) => input
+ .replaceAll(' ', ansi.lightBlue.wrap('·')!)
+ .replaceAll('\t', ansi.backgroundDarkGray.wrap('\t')!);
+
+void markdownPrintOnFailure(String markdown, String expected, String actual) {
+ printOnFailure("""
+INPUT:
+'''r
+${whitespaceColor(markdown)}'''
+
+EXPECTED:
+'''r
+${whitespaceColor(expected)}'''
+
+GOT:
+'''r
+${whitespaceColor(actual)}'''
+""");
+}
diff --git a/pkgs/markdown/test/util_test.dart b/pkgs/markdown/test/util_test.dart
new file mode 100644
index 0000000..5a2108a
--- /dev/null
+++ b/pkgs/markdown/test/util_test.dart
@@ -0,0 +1,86 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:markdown/markdown.dart';
+import 'package:markdown/src/util.dart';
+import 'package:test/test.dart';
+
+void main() {
+ group('String.toLines()', () {
+ test('a single line without a line ending', () {
+ const text = 'Foo';
+ final lines = text.toLines();
+
+ expect(lines.map((e) => e.toMap()), [
+ {
+ 'content': 'Foo',
+ 'isBlankLine': false,
+ }
+ ]);
+ });
+
+ test('a single line with a line ending', () {
+ const text = 'Foo\n';
+ final lines = text.toLines();
+
+ expect(lines.map((e) => e.toMap()), [
+ {
+ 'content': 'Foo',
+ 'isBlankLine': false,
+ },
+ ]);
+ });
+
+ test('multiple lines with a blank line in between', () {
+ const text = 'Foo\r\n\nBar';
+ final lines = text.toLines();
+
+ expect(lines.map((e) => e.toMap()), [
+ {
+ 'content': 'Foo',
+ 'isBlankLine': false,
+ },
+ {
+ 'content': '',
+ 'isBlankLine': true,
+ },
+ {
+ 'content': 'Bar',
+ 'isBlankLine': false,
+ }
+ ]);
+ });
+ });
+
+ group('String.indentation()', () {
+ test('only spaces', () {
+ expect(' '.indentation(), 3);
+ expect(' '.indentation(), 4);
+ expect(' '.indentation(), 5);
+ });
+
+ test('spaces and tabs', () {
+ expect('\t '.indentation(), 6);
+ expect(' \t '.indentation(), 5);
+ expect(' \t'.indentation(), 4);
+ expect('\t\t '.indentation(), 10);
+ expect(' \t\t '.indentation(), 9);
+ expect(' \t\t'.indentation(), 8);
+ });
+
+ test('spaces, tabs and non whitespace characters', () {
+ expect('\t foo'.indentation(), 6);
+ expect(' \t foo'.indentation(), 5);
+ expect(' \tfoo'.indentation(), 4);
+ });
+ });
+}
+
+extension on Line {
+ Map<String, dynamic> toMap() => {
+ 'content': content,
+ 'isBlankLine': isBlankLine,
+ if (tabRemaining != null) 'tabRemaining': tabRemaining,
+ };
+}
diff --git a/pkgs/markdown/test/version_test.dart b/pkgs/markdown/test/version_test.dart
new file mode 100644
index 0000000..93fedcb
--- /dev/null
+++ b/pkgs/markdown/test/version_test.dart
@@ -0,0 +1,41 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@TestOn('vm')
+library;
+
+import 'dart:io';
+
+import 'package:path/path.dart' as p;
+import 'package:test/test.dart';
+import 'package:yaml/yaml.dart';
+
+void main() {
+ test('check versions', () async {
+ final binary = p.join(p.current, 'bin', 'markdown.dart');
+ final dartBin = Platform.executable;
+ final result = Process.runSync(dartBin, [binary, '--version']);
+ expect(
+ result.exitCode,
+ 0,
+ reason: 'Exit code expected: 0; actual: ${result.exitCode}\n\n'
+ 'stdout: ${result.stdout}\n\n'
+ 'stderr: ${result.stderr}',
+ );
+
+ final binVersion = (result.stdout as String).trim();
+
+ final pubspecFile = p.join(p.current, 'pubspec.yaml');
+
+ final pubspecContent =
+ loadYaml(File(pubspecFile).readAsStringSync()) as YamlMap;
+
+ expect(
+ binVersion,
+ pubspecContent['version'],
+ reason: 'The version reported by bin/markdown.dart should match the '
+ 'version in pubspec. Run `dart run build_runner build` to update.',
+ );
+ });
+}
diff --git a/pkgs/markdown/tool/README.md b/pkgs/markdown/tool/README.md
new file mode 100644
index 0000000..ff2f749
--- /dev/null
+++ b/pkgs/markdown/tool/README.md
@@ -0,0 +1,48 @@
+# Developer Tools
+
+This directory contains tools for developers of the Dart markdown package.
+
+## dartdoc_compare.dart
+
+When you make a change to the package that might have subtle consequences on
+how Markdown is parsed, it would be really great to see how your output compares
+to the previous output, on a large collection of Markdown.
+
+One such collection is the Dartdoc comments of any Dart package, which [dartdoc]
+translates into HTML, with the help of this markdown package. You can use the
+`dartdoc_compare.dart` script to compare what changes your code will make to
+dartdoc's output. Here's how it works:
+
+1. Clone the [dartdoc git repository].
+2. Get a copy of some Dart code that you would like to use for the comparison.
+3. Run the `dartdoc_compare.dart` script like so:
+
+ ```
+ $ dart tool/dartdoc_compare.dart \
+ --dartdoc-dir=<dartdoc repo> \
+ --before=<git SHA of "previous" code> \
+ <directory of dart code for comparison>
+ ```
+
+4. The tool will then walk through the following steps:
+
+ 1. cd into the dartdoc directory, change `pubspec.yaml` to depend on your
+ "before" version of markdown, and run `pub get`.
+ 2. cd into the directory of dart code, and run `pub get`.
+ 3. Run dartdoc.
+ 4. cd back into the dartdoc directory, change `pubspec.yaml` to depend on
+ your "after" version of markdown (defaults to HEAD), and run `pub get`.
+ 5. Repeat steps 2 and 3.
+ 6. Diff the output of steps 3 and 5, and show you how to diff it yourself.
+
+[dartdoc]: https://pub.dev/packages/dartdoc
+[dartdoc git repository]: https://github.com/dart-lang/dartdoc
+
+## stats.dart
+
+In an effort to make this package CommonMark-compliant, we have a script that
+runs the package through the CommonMark specs. To see help:
+
+```bash
+$ dart tool/stats.dart --help
+```
diff --git a/pkgs/markdown/tool/case_folding.txt b/pkgs/markdown/tool/case_folding.txt
new file mode 100644
index 0000000..932ace2
--- /dev/null
+++ b/pkgs/markdown/tool/case_folding.txt
@@ -0,0 +1,1624 @@
+# CaseFolding-14.0.0.txt
+# Date: 2021-03-08, 19:35:41 GMT
+# © 2021 Unicode®, Inc.
+# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
+# For terms of use, see http://www.unicode.org/terms_of_use.html
+#
+# Unicode Character Database
+# For documentation, see http://www.unicode.org/reports/tr44/
+#
+# Case Folding Properties
+#
+# This file is a supplement to the UnicodeData file.
+# It provides a case folding mapping generated from the Unicode Character Database.
+# If all characters are mapped according to the full mapping below, then
+# case differences (according to UnicodeData.txt and SpecialCasing.txt)
+# are eliminated.
+#
+# The data supports both implementations that require simple case foldings
+# (where string lengths don't change), and implementations that allow full case folding
+# (where string lengths may grow). Note that where they can be supported, the
+# full case foldings are superior: for example, they allow "MASSE" and "Maße" to match.
+#
+# All code points not listed in this file map to themselves.
+#
+# NOTE: case folding does not preserve normalization formats!
+#
+# For information on case folding, including how to have case folding
+# preserve normalization formats, see Section 3.13 Default Case Algorithms in
+# The Unicode Standard.
+#
+# ================================================================================
+# Format
+# ================================================================================
+# The entries in this file are in the following machine-readable format:
+#
+# <code>; <status>; <mapping>; # <name>
+#
+# The status field is:
+# C: common case folding, common mappings shared by both simple and full mappings.
+# F: full case folding, mappings that cause strings to grow in length. Multiple characters are separated by spaces.
+# S: simple case folding, mappings to single characters where different from F.
+# T: special case for uppercase I and dotted uppercase I
+# - For non-Turkic languages, this mapping is normally not used.
+# - For Turkic languages (tr, az), this mapping can be used instead of the normal mapping for these characters.
+# Note that the Turkic mappings do not maintain canonical equivalence without additional processing.
+# See the discussions of case mapping in the Unicode Standard for more information.
+#
+# Usage:
+# A. To do a simple case folding, use the mappings with status C + S.
+# B. To do a full case folding, use the mappings with status C + F.
+#
+# The mappings with status T can be used or omitted depending on the desired case-folding
+# behavior. (The default option is to exclude them.)
+#
+# =================================================================
+
+# Property: Case_Folding
+
+# All code points not explicitly listed for Case_Folding
+# have the value C for the status field, and the code point itself for the mapping field.
+
+# =================================================================
+0041; C; 0061; # LATIN CAPITAL LETTER A
+0042; C; 0062; # LATIN CAPITAL LETTER B
+0043; C; 0063; # LATIN CAPITAL LETTER C
+0044; C; 0064; # LATIN CAPITAL LETTER D
+0045; C; 0065; # LATIN CAPITAL LETTER E
+0046; C; 0066; # LATIN CAPITAL LETTER F
+0047; C; 0067; # LATIN CAPITAL LETTER G
+0048; C; 0068; # LATIN CAPITAL LETTER H
+0049; C; 0069; # LATIN CAPITAL LETTER I
+0049; T; 0131; # LATIN CAPITAL LETTER I
+004A; C; 006A; # LATIN CAPITAL LETTER J
+004B; C; 006B; # LATIN CAPITAL LETTER K
+004C; C; 006C; # LATIN CAPITAL LETTER L
+004D; C; 006D; # LATIN CAPITAL LETTER M
+004E; C; 006E; # LATIN CAPITAL LETTER N
+004F; C; 006F; # LATIN CAPITAL LETTER O
+0050; C; 0070; # LATIN CAPITAL LETTER P
+0051; C; 0071; # LATIN CAPITAL LETTER Q
+0052; C; 0072; # LATIN CAPITAL LETTER R
+0053; C; 0073; # LATIN CAPITAL LETTER S
+0054; C; 0074; # LATIN CAPITAL LETTER T
+0055; C; 0075; # LATIN CAPITAL LETTER U
+0056; C; 0076; # LATIN CAPITAL LETTER V
+0057; C; 0077; # LATIN CAPITAL LETTER W
+0058; C; 0078; # LATIN CAPITAL LETTER X
+0059; C; 0079; # LATIN CAPITAL LETTER Y
+005A; C; 007A; # LATIN CAPITAL LETTER Z
+00B5; C; 03BC; # MICRO SIGN
+00C0; C; 00E0; # LATIN CAPITAL LETTER A WITH GRAVE
+00C1; C; 00E1; # LATIN CAPITAL LETTER A WITH ACUTE
+00C2; C; 00E2; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX
+00C3; C; 00E3; # LATIN CAPITAL LETTER A WITH TILDE
+00C4; C; 00E4; # LATIN CAPITAL LETTER A WITH DIAERESIS
+00C5; C; 00E5; # LATIN CAPITAL LETTER A WITH RING ABOVE
+00C6; C; 00E6; # LATIN CAPITAL LETTER AE
+00C7; C; 00E7; # LATIN CAPITAL LETTER C WITH CEDILLA
+00C8; C; 00E8; # LATIN CAPITAL LETTER E WITH GRAVE
+00C9; C; 00E9; # LATIN CAPITAL LETTER E WITH ACUTE
+00CA; C; 00EA; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX
+00CB; C; 00EB; # LATIN CAPITAL LETTER E WITH DIAERESIS
+00CC; C; 00EC; # LATIN CAPITAL LETTER I WITH GRAVE
+00CD; C; 00ED; # LATIN CAPITAL LETTER I WITH ACUTE
+00CE; C; 00EE; # LATIN CAPITAL LETTER I WITH CIRCUMFLEX
+00CF; C; 00EF; # LATIN CAPITAL LETTER I WITH DIAERESIS
+00D0; C; 00F0; # LATIN CAPITAL LETTER ETH
+00D1; C; 00F1; # LATIN CAPITAL LETTER N WITH TILDE
+00D2; C; 00F2; # LATIN CAPITAL LETTER O WITH GRAVE
+00D3; C; 00F3; # LATIN CAPITAL LETTER O WITH ACUTE
+00D4; C; 00F4; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX
+00D5; C; 00F5; # LATIN CAPITAL LETTER O WITH TILDE
+00D6; C; 00F6; # LATIN CAPITAL LETTER O WITH DIAERESIS
+00D8; C; 00F8; # LATIN CAPITAL LETTER O WITH STROKE
+00D9; C; 00F9; # LATIN CAPITAL LETTER U WITH GRAVE
+00DA; C; 00FA; # LATIN CAPITAL LETTER U WITH ACUTE
+00DB; C; 00FB; # LATIN CAPITAL LETTER U WITH CIRCUMFLEX
+00DC; C; 00FC; # LATIN CAPITAL LETTER U WITH DIAERESIS
+00DD; C; 00FD; # LATIN CAPITAL LETTER Y WITH ACUTE
+00DE; C; 00FE; # LATIN CAPITAL LETTER THORN
+00DF; F; 0073 0073; # LATIN SMALL LETTER SHARP S
+0100; C; 0101; # LATIN CAPITAL LETTER A WITH MACRON
+0102; C; 0103; # LATIN CAPITAL LETTER A WITH BREVE
+0104; C; 0105; # LATIN CAPITAL LETTER A WITH OGONEK
+0106; C; 0107; # LATIN CAPITAL LETTER C WITH ACUTE
+0108; C; 0109; # LATIN CAPITAL LETTER C WITH CIRCUMFLEX
+010A; C; 010B; # LATIN CAPITAL LETTER C WITH DOT ABOVE
+010C; C; 010D; # LATIN CAPITAL LETTER C WITH CARON
+010E; C; 010F; # LATIN CAPITAL LETTER D WITH CARON
+0110; C; 0111; # LATIN CAPITAL LETTER D WITH STROKE
+0112; C; 0113; # LATIN CAPITAL LETTER E WITH MACRON
+0114; C; 0115; # LATIN CAPITAL LETTER E WITH BREVE
+0116; C; 0117; # LATIN CAPITAL LETTER E WITH DOT ABOVE
+0118; C; 0119; # LATIN CAPITAL LETTER E WITH OGONEK
+011A; C; 011B; # LATIN CAPITAL LETTER E WITH CARON
+011C; C; 011D; # LATIN CAPITAL LETTER G WITH CIRCUMFLEX
+011E; C; 011F; # LATIN CAPITAL LETTER G WITH BREVE
+0120; C; 0121; # LATIN CAPITAL LETTER G WITH DOT ABOVE
+0122; C; 0123; # LATIN CAPITAL LETTER G WITH CEDILLA
+0124; C; 0125; # LATIN CAPITAL LETTER H WITH CIRCUMFLEX
+0126; C; 0127; # LATIN CAPITAL LETTER H WITH STROKE
+0128; C; 0129; # LATIN CAPITAL LETTER I WITH TILDE
+012A; C; 012B; # LATIN CAPITAL LETTER I WITH MACRON
+012C; C; 012D; # LATIN CAPITAL LETTER I WITH BREVE
+012E; C; 012F; # LATIN CAPITAL LETTER I WITH OGONEK
+0130; F; 0069 0307; # LATIN CAPITAL LETTER I WITH DOT ABOVE
+0130; T; 0069; # LATIN CAPITAL LETTER I WITH DOT ABOVE
+0132; C; 0133; # LATIN CAPITAL LIGATURE IJ
+0134; C; 0135; # LATIN CAPITAL LETTER J WITH CIRCUMFLEX
+0136; C; 0137; # LATIN CAPITAL LETTER K WITH CEDILLA
+0139; C; 013A; # LATIN CAPITAL LETTER L WITH ACUTE
+013B; C; 013C; # LATIN CAPITAL LETTER L WITH CEDILLA
+013D; C; 013E; # LATIN CAPITAL LETTER L WITH CARON
+013F; C; 0140; # LATIN CAPITAL LETTER L WITH MIDDLE DOT
+0141; C; 0142; # LATIN CAPITAL LETTER L WITH STROKE
+0143; C; 0144; # LATIN CAPITAL LETTER N WITH ACUTE
+0145; C; 0146; # LATIN CAPITAL LETTER N WITH CEDILLA
+0147; C; 0148; # LATIN CAPITAL LETTER N WITH CARON
+0149; F; 02BC 006E; # LATIN SMALL LETTER N PRECEDED BY APOSTROPHE
+014A; C; 014B; # LATIN CAPITAL LETTER ENG
+014C; C; 014D; # LATIN CAPITAL LETTER O WITH MACRON
+014E; C; 014F; # LATIN CAPITAL LETTER O WITH BREVE
+0150; C; 0151; # LATIN CAPITAL LETTER O WITH DOUBLE ACUTE
+0152; C; 0153; # LATIN CAPITAL LIGATURE OE
+0154; C; 0155; # LATIN CAPITAL LETTER R WITH ACUTE
+0156; C; 0157; # LATIN CAPITAL LETTER R WITH CEDILLA
+0158; C; 0159; # LATIN CAPITAL LETTER R WITH CARON
+015A; C; 015B; # LATIN CAPITAL LETTER S WITH ACUTE
+015C; C; 015D; # LATIN CAPITAL LETTER S WITH CIRCUMFLEX
+015E; C; 015F; # LATIN CAPITAL LETTER S WITH CEDILLA
+0160; C; 0161; # LATIN CAPITAL LETTER S WITH CARON
+0162; C; 0163; # LATIN CAPITAL LETTER T WITH CEDILLA
+0164; C; 0165; # LATIN CAPITAL LETTER T WITH CARON
+0166; C; 0167; # LATIN CAPITAL LETTER T WITH STROKE
+0168; C; 0169; # LATIN CAPITAL LETTER U WITH TILDE
+016A; C; 016B; # LATIN CAPITAL LETTER U WITH MACRON
+016C; C; 016D; # LATIN CAPITAL LETTER U WITH BREVE
+016E; C; 016F; # LATIN CAPITAL LETTER U WITH RING ABOVE
+0170; C; 0171; # LATIN CAPITAL LETTER U WITH DOUBLE ACUTE
+0172; C; 0173; # LATIN CAPITAL LETTER U WITH OGONEK
+0174; C; 0175; # LATIN CAPITAL LETTER W WITH CIRCUMFLEX
+0176; C; 0177; # LATIN CAPITAL LETTER Y WITH CIRCUMFLEX
+0178; C; 00FF; # LATIN CAPITAL LETTER Y WITH DIAERESIS
+0179; C; 017A; # LATIN CAPITAL LETTER Z WITH ACUTE
+017B; C; 017C; # LATIN CAPITAL LETTER Z WITH DOT ABOVE
+017D; C; 017E; # LATIN CAPITAL LETTER Z WITH CARON
+017F; C; 0073; # LATIN SMALL LETTER LONG S
+0181; C; 0253; # LATIN CAPITAL LETTER B WITH HOOK
+0182; C; 0183; # LATIN CAPITAL LETTER B WITH TOPBAR
+0184; C; 0185; # LATIN CAPITAL LETTER TONE SIX
+0186; C; 0254; # LATIN CAPITAL LETTER OPEN O
+0187; C; 0188; # LATIN CAPITAL LETTER C WITH HOOK
+0189; C; 0256; # LATIN CAPITAL LETTER AFRICAN D
+018A; C; 0257; # LATIN CAPITAL LETTER D WITH HOOK
+018B; C; 018C; # LATIN CAPITAL LETTER D WITH TOPBAR
+018E; C; 01DD; # LATIN CAPITAL LETTER REVERSED E
+018F; C; 0259; # LATIN CAPITAL LETTER SCHWA
+0190; C; 025B; # LATIN CAPITAL LETTER OPEN E
+0191; C; 0192; # LATIN CAPITAL LETTER F WITH HOOK
+0193; C; 0260; # LATIN CAPITAL LETTER G WITH HOOK
+0194; C; 0263; # LATIN CAPITAL LETTER GAMMA
+0196; C; 0269; # LATIN CAPITAL LETTER IOTA
+0197; C; 0268; # LATIN CAPITAL LETTER I WITH STROKE
+0198; C; 0199; # LATIN CAPITAL LETTER K WITH HOOK
+019C; C; 026F; # LATIN CAPITAL LETTER TURNED M
+019D; C; 0272; # LATIN CAPITAL LETTER N WITH LEFT HOOK
+019F; C; 0275; # LATIN CAPITAL LETTER O WITH MIDDLE TILDE
+01A0; C; 01A1; # LATIN CAPITAL LETTER O WITH HORN
+01A2; C; 01A3; # LATIN CAPITAL LETTER OI
+01A4; C; 01A5; # LATIN CAPITAL LETTER P WITH HOOK
+01A6; C; 0280; # LATIN LETTER YR
+01A7; C; 01A8; # LATIN CAPITAL LETTER TONE TWO
+01A9; C; 0283; # LATIN CAPITAL LETTER ESH
+01AC; C; 01AD; # LATIN CAPITAL LETTER T WITH HOOK
+01AE; C; 0288; # LATIN CAPITAL LETTER T WITH RETROFLEX HOOK
+01AF; C; 01B0; # LATIN CAPITAL LETTER U WITH HORN
+01B1; C; 028A; # LATIN CAPITAL LETTER UPSILON
+01B2; C; 028B; # LATIN CAPITAL LETTER V WITH HOOK
+01B3; C; 01B4; # LATIN CAPITAL LETTER Y WITH HOOK
+01B5; C; 01B6; # LATIN CAPITAL LETTER Z WITH STROKE
+01B7; C; 0292; # LATIN CAPITAL LETTER EZH
+01B8; C; 01B9; # LATIN CAPITAL LETTER EZH REVERSED
+01BC; C; 01BD; # LATIN CAPITAL LETTER TONE FIVE
+01C4; C; 01C6; # LATIN CAPITAL LETTER DZ WITH CARON
+01C5; C; 01C6; # LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON
+01C7; C; 01C9; # LATIN CAPITAL LETTER LJ
+01C8; C; 01C9; # LATIN CAPITAL LETTER L WITH SMALL LETTER J
+01CA; C; 01CC; # LATIN CAPITAL LETTER NJ
+01CB; C; 01CC; # LATIN CAPITAL LETTER N WITH SMALL LETTER J
+01CD; C; 01CE; # LATIN CAPITAL LETTER A WITH CARON
+01CF; C; 01D0; # LATIN CAPITAL LETTER I WITH CARON
+01D1; C; 01D2; # LATIN CAPITAL LETTER O WITH CARON
+01D3; C; 01D4; # LATIN CAPITAL LETTER U WITH CARON
+01D5; C; 01D6; # LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON
+01D7; C; 01D8; # LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE
+01D9; C; 01DA; # LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON
+01DB; C; 01DC; # LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE
+01DE; C; 01DF; # LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON
+01E0; C; 01E1; # LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON
+01E2; C; 01E3; # LATIN CAPITAL LETTER AE WITH MACRON
+01E4; C; 01E5; # LATIN CAPITAL LETTER G WITH STROKE
+01E6; C; 01E7; # LATIN CAPITAL LETTER G WITH CARON
+01E8; C; 01E9; # LATIN CAPITAL LETTER K WITH CARON
+01EA; C; 01EB; # LATIN CAPITAL LETTER O WITH OGONEK
+01EC; C; 01ED; # LATIN CAPITAL LETTER O WITH OGONEK AND MACRON
+01EE; C; 01EF; # LATIN CAPITAL LETTER EZH WITH CARON
+01F0; F; 006A 030C; # LATIN SMALL LETTER J WITH CARON
+01F1; C; 01F3; # LATIN CAPITAL LETTER DZ
+01F2; C; 01F3; # LATIN CAPITAL LETTER D WITH SMALL LETTER Z
+01F4; C; 01F5; # LATIN CAPITAL LETTER G WITH ACUTE
+01F6; C; 0195; # LATIN CAPITAL LETTER HWAIR
+01F7; C; 01BF; # LATIN CAPITAL LETTER WYNN
+01F8; C; 01F9; # LATIN CAPITAL LETTER N WITH GRAVE
+01FA; C; 01FB; # LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE
+01FC; C; 01FD; # LATIN CAPITAL LETTER AE WITH ACUTE
+01FE; C; 01FF; # LATIN CAPITAL LETTER O WITH STROKE AND ACUTE
+0200; C; 0201; # LATIN CAPITAL LETTER A WITH DOUBLE GRAVE
+0202; C; 0203; # LATIN CAPITAL LETTER A WITH INVERTED BREVE
+0204; C; 0205; # LATIN CAPITAL LETTER E WITH DOUBLE GRAVE
+0206; C; 0207; # LATIN CAPITAL LETTER E WITH INVERTED BREVE
+0208; C; 0209; # LATIN CAPITAL LETTER I WITH DOUBLE GRAVE
+020A; C; 020B; # LATIN CAPITAL LETTER I WITH INVERTED BREVE
+020C; C; 020D; # LATIN CAPITAL LETTER O WITH DOUBLE GRAVE
+020E; C; 020F; # LATIN CAPITAL LETTER O WITH INVERTED BREVE
+0210; C; 0211; # LATIN CAPITAL LETTER R WITH DOUBLE GRAVE
+0212; C; 0213; # LATIN CAPITAL LETTER R WITH INVERTED BREVE
+0214; C; 0215; # LATIN CAPITAL LETTER U WITH DOUBLE GRAVE
+0216; C; 0217; # LATIN CAPITAL LETTER U WITH INVERTED BREVE
+0218; C; 0219; # LATIN CAPITAL LETTER S WITH COMMA BELOW
+021A; C; 021B; # LATIN CAPITAL LETTER T WITH COMMA BELOW
+021C; C; 021D; # LATIN CAPITAL LETTER YOGH
+021E; C; 021F; # LATIN CAPITAL LETTER H WITH CARON
+0220; C; 019E; # LATIN CAPITAL LETTER N WITH LONG RIGHT LEG
+0222; C; 0223; # LATIN CAPITAL LETTER OU
+0224; C; 0225; # LATIN CAPITAL LETTER Z WITH HOOK
+0226; C; 0227; # LATIN CAPITAL LETTER A WITH DOT ABOVE
+0228; C; 0229; # LATIN CAPITAL LETTER E WITH CEDILLA
+022A; C; 022B; # LATIN CAPITAL LETTER O WITH DIAERESIS AND MACRON
+022C; C; 022D; # LATIN CAPITAL LETTER O WITH TILDE AND MACRON
+022E; C; 022F; # LATIN CAPITAL LETTER O WITH DOT ABOVE
+0230; C; 0231; # LATIN CAPITAL LETTER O WITH DOT ABOVE AND MACRON
+0232; C; 0233; # LATIN CAPITAL LETTER Y WITH MACRON
+023A; C; 2C65; # LATIN CAPITAL LETTER A WITH STROKE
+023B; C; 023C; # LATIN CAPITAL LETTER C WITH STROKE
+023D; C; 019A; # LATIN CAPITAL LETTER L WITH BAR
+023E; C; 2C66; # LATIN CAPITAL LETTER T WITH DIAGONAL STROKE
+0241; C; 0242; # LATIN CAPITAL LETTER GLOTTAL STOP
+0243; C; 0180; # LATIN CAPITAL LETTER B WITH STROKE
+0244; C; 0289; # LATIN CAPITAL LETTER U BAR
+0245; C; 028C; # LATIN CAPITAL LETTER TURNED V
+0246; C; 0247; # LATIN CAPITAL LETTER E WITH STROKE
+0248; C; 0249; # LATIN CAPITAL LETTER J WITH STROKE
+024A; C; 024B; # LATIN CAPITAL LETTER SMALL Q WITH HOOK TAIL
+024C; C; 024D; # LATIN CAPITAL LETTER R WITH STROKE
+024E; C; 024F; # LATIN CAPITAL LETTER Y WITH STROKE
+0345; C; 03B9; # COMBINING GREEK YPOGEGRAMMENI
+0370; C; 0371; # GREEK CAPITAL LETTER HETA
+0372; C; 0373; # GREEK CAPITAL LETTER ARCHAIC SAMPI
+0376; C; 0377; # GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA
+037F; C; 03F3; # GREEK CAPITAL LETTER YOT
+0386; C; 03AC; # GREEK CAPITAL LETTER ALPHA WITH TONOS
+0388; C; 03AD; # GREEK CAPITAL LETTER EPSILON WITH TONOS
+0389; C; 03AE; # GREEK CAPITAL LETTER ETA WITH TONOS
+038A; C; 03AF; # GREEK CAPITAL LETTER IOTA WITH TONOS
+038C; C; 03CC; # GREEK CAPITAL LETTER OMICRON WITH TONOS
+038E; C; 03CD; # GREEK CAPITAL LETTER UPSILON WITH TONOS
+038F; C; 03CE; # GREEK CAPITAL LETTER OMEGA WITH TONOS
+0390; F; 03B9 0308 0301; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS
+0391; C; 03B1; # GREEK CAPITAL LETTER ALPHA
+0392; C; 03B2; # GREEK CAPITAL LETTER BETA
+0393; C; 03B3; # GREEK CAPITAL LETTER GAMMA
+0394; C; 03B4; # GREEK CAPITAL LETTER DELTA
+0395; C; 03B5; # GREEK CAPITAL LETTER EPSILON
+0396; C; 03B6; # GREEK CAPITAL LETTER ZETA
+0397; C; 03B7; # GREEK CAPITAL LETTER ETA
+0398; C; 03B8; # GREEK CAPITAL LETTER THETA
+0399; C; 03B9; # GREEK CAPITAL LETTER IOTA
+039A; C; 03BA; # GREEK CAPITAL LETTER KAPPA
+039B; C; 03BB; # GREEK CAPITAL LETTER LAMDA
+039C; C; 03BC; # GREEK CAPITAL LETTER MU
+039D; C; 03BD; # GREEK CAPITAL LETTER NU
+039E; C; 03BE; # GREEK CAPITAL LETTER XI
+039F; C; 03BF; # GREEK CAPITAL LETTER OMICRON
+03A0; C; 03C0; # GREEK CAPITAL LETTER PI
+03A1; C; 03C1; # GREEK CAPITAL LETTER RHO
+03A3; C; 03C3; # GREEK CAPITAL LETTER SIGMA
+03A4; C; 03C4; # GREEK CAPITAL LETTER TAU
+03A5; C; 03C5; # GREEK CAPITAL LETTER UPSILON
+03A6; C; 03C6; # GREEK CAPITAL LETTER PHI
+03A7; C; 03C7; # GREEK CAPITAL LETTER CHI
+03A8; C; 03C8; # GREEK CAPITAL LETTER PSI
+03A9; C; 03C9; # GREEK CAPITAL LETTER OMEGA
+03AA; C; 03CA; # GREEK CAPITAL LETTER IOTA WITH DIALYTIKA
+03AB; C; 03CB; # GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA
+03B0; F; 03C5 0308 0301; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS
+03C2; C; 03C3; # GREEK SMALL LETTER FINAL SIGMA
+03CF; C; 03D7; # GREEK CAPITAL KAI SYMBOL
+03D0; C; 03B2; # GREEK BETA SYMBOL
+03D1; C; 03B8; # GREEK THETA SYMBOL
+03D5; C; 03C6; # GREEK PHI SYMBOL
+03D6; C; 03C0; # GREEK PI SYMBOL
+03D8; C; 03D9; # GREEK LETTER ARCHAIC KOPPA
+03DA; C; 03DB; # GREEK LETTER STIGMA
+03DC; C; 03DD; # GREEK LETTER DIGAMMA
+03DE; C; 03DF; # GREEK LETTER KOPPA
+03E0; C; 03E1; # GREEK LETTER SAMPI
+03E2; C; 03E3; # COPTIC CAPITAL LETTER SHEI
+03E4; C; 03E5; # COPTIC CAPITAL LETTER FEI
+03E6; C; 03E7; # COPTIC CAPITAL LETTER KHEI
+03E8; C; 03E9; # COPTIC CAPITAL LETTER HORI
+03EA; C; 03EB; # COPTIC CAPITAL LETTER GANGIA
+03EC; C; 03ED; # COPTIC CAPITAL LETTER SHIMA
+03EE; C; 03EF; # COPTIC CAPITAL LETTER DEI
+03F0; C; 03BA; # GREEK KAPPA SYMBOL
+03F1; C; 03C1; # GREEK RHO SYMBOL
+03F4; C; 03B8; # GREEK CAPITAL THETA SYMBOL
+03F5; C; 03B5; # GREEK LUNATE EPSILON SYMBOL
+03F7; C; 03F8; # GREEK CAPITAL LETTER SHO
+03F9; C; 03F2; # GREEK CAPITAL LUNATE SIGMA SYMBOL
+03FA; C; 03FB; # GREEK CAPITAL LETTER SAN
+03FD; C; 037B; # GREEK CAPITAL REVERSED LUNATE SIGMA SYMBOL
+03FE; C; 037C; # GREEK CAPITAL DOTTED LUNATE SIGMA SYMBOL
+03FF; C; 037D; # GREEK CAPITAL REVERSED DOTTED LUNATE SIGMA SYMBOL
+0400; C; 0450; # CYRILLIC CAPITAL LETTER IE WITH GRAVE
+0401; C; 0451; # CYRILLIC CAPITAL LETTER IO
+0402; C; 0452; # CYRILLIC CAPITAL LETTER DJE
+0403; C; 0453; # CYRILLIC CAPITAL LETTER GJE
+0404; C; 0454; # CYRILLIC CAPITAL LETTER UKRAINIAN IE
+0405; C; 0455; # CYRILLIC CAPITAL LETTER DZE
+0406; C; 0456; # CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I
+0407; C; 0457; # CYRILLIC CAPITAL LETTER YI
+0408; C; 0458; # CYRILLIC CAPITAL LETTER JE
+0409; C; 0459; # CYRILLIC CAPITAL LETTER LJE
+040A; C; 045A; # CYRILLIC CAPITAL LETTER NJE
+040B; C; 045B; # CYRILLIC CAPITAL LETTER TSHE
+040C; C; 045C; # CYRILLIC CAPITAL LETTER KJE
+040D; C; 045D; # CYRILLIC CAPITAL LETTER I WITH GRAVE
+040E; C; 045E; # CYRILLIC CAPITAL LETTER SHORT U
+040F; C; 045F; # CYRILLIC CAPITAL LETTER DZHE
+0410; C; 0430; # CYRILLIC CAPITAL LETTER A
+0411; C; 0431; # CYRILLIC CAPITAL LETTER BE
+0412; C; 0432; # CYRILLIC CAPITAL LETTER VE
+0413; C; 0433; # CYRILLIC CAPITAL LETTER GHE
+0414; C; 0434; # CYRILLIC CAPITAL LETTER DE
+0415; C; 0435; # CYRILLIC CAPITAL LETTER IE
+0416; C; 0436; # CYRILLIC CAPITAL LETTER ZHE
+0417; C; 0437; # CYRILLIC CAPITAL LETTER ZE
+0418; C; 0438; # CYRILLIC CAPITAL LETTER I
+0419; C; 0439; # CYRILLIC CAPITAL LETTER SHORT I
+041A; C; 043A; # CYRILLIC CAPITAL LETTER KA
+041B; C; 043B; # CYRILLIC CAPITAL LETTER EL
+041C; C; 043C; # CYRILLIC CAPITAL LETTER EM
+041D; C; 043D; # CYRILLIC CAPITAL LETTER EN
+041E; C; 043E; # CYRILLIC CAPITAL LETTER O
+041F; C; 043F; # CYRILLIC CAPITAL LETTER PE
+0420; C; 0440; # CYRILLIC CAPITAL LETTER ER
+0421; C; 0441; # CYRILLIC CAPITAL LETTER ES
+0422; C; 0442; # CYRILLIC CAPITAL LETTER TE
+0423; C; 0443; # CYRILLIC CAPITAL LETTER U
+0424; C; 0444; # CYRILLIC CAPITAL LETTER EF
+0425; C; 0445; # CYRILLIC CAPITAL LETTER HA
+0426; C; 0446; # CYRILLIC CAPITAL LETTER TSE
+0427; C; 0447; # CYRILLIC CAPITAL LETTER CHE
+0428; C; 0448; # CYRILLIC CAPITAL LETTER SHA
+0429; C; 0449; # CYRILLIC CAPITAL LETTER SHCHA
+042A; C; 044A; # CYRILLIC CAPITAL LETTER HARD SIGN
+042B; C; 044B; # CYRILLIC CAPITAL LETTER YERU
+042C; C; 044C; # CYRILLIC CAPITAL LETTER SOFT SIGN
+042D; C; 044D; # CYRILLIC CAPITAL LETTER E
+042E; C; 044E; # CYRILLIC CAPITAL LETTER YU
+042F; C; 044F; # CYRILLIC CAPITAL LETTER YA
+0460; C; 0461; # CYRILLIC CAPITAL LETTER OMEGA
+0462; C; 0463; # CYRILLIC CAPITAL LETTER YAT
+0464; C; 0465; # CYRILLIC CAPITAL LETTER IOTIFIED E
+0466; C; 0467; # CYRILLIC CAPITAL LETTER LITTLE YUS
+0468; C; 0469; # CYRILLIC CAPITAL LETTER IOTIFIED LITTLE YUS
+046A; C; 046B; # CYRILLIC CAPITAL LETTER BIG YUS
+046C; C; 046D; # CYRILLIC CAPITAL LETTER IOTIFIED BIG YUS
+046E; C; 046F; # CYRILLIC CAPITAL LETTER KSI
+0470; C; 0471; # CYRILLIC CAPITAL LETTER PSI
+0472; C; 0473; # CYRILLIC CAPITAL LETTER FITA
+0474; C; 0475; # CYRILLIC CAPITAL LETTER IZHITSA
+0476; C; 0477; # CYRILLIC CAPITAL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT
+0478; C; 0479; # CYRILLIC CAPITAL LETTER UK
+047A; C; 047B; # CYRILLIC CAPITAL LETTER ROUND OMEGA
+047C; C; 047D; # CYRILLIC CAPITAL LETTER OMEGA WITH TITLO
+047E; C; 047F; # CYRILLIC CAPITAL LETTER OT
+0480; C; 0481; # CYRILLIC CAPITAL LETTER KOPPA
+048A; C; 048B; # CYRILLIC CAPITAL LETTER SHORT I WITH TAIL
+048C; C; 048D; # CYRILLIC CAPITAL LETTER SEMISOFT SIGN
+048E; C; 048F; # CYRILLIC CAPITAL LETTER ER WITH TICK
+0490; C; 0491; # CYRILLIC CAPITAL LETTER GHE WITH UPTURN
+0492; C; 0493; # CYRILLIC CAPITAL LETTER GHE WITH STROKE
+0494; C; 0495; # CYRILLIC CAPITAL LETTER GHE WITH MIDDLE HOOK
+0496; C; 0497; # CYRILLIC CAPITAL LETTER ZHE WITH DESCENDER
+0498; C; 0499; # CYRILLIC CAPITAL LETTER ZE WITH DESCENDER
+049A; C; 049B; # CYRILLIC CAPITAL LETTER KA WITH DESCENDER
+049C; C; 049D; # CYRILLIC CAPITAL LETTER KA WITH VERTICAL STROKE
+049E; C; 049F; # CYRILLIC CAPITAL LETTER KA WITH STROKE
+04A0; C; 04A1; # CYRILLIC CAPITAL LETTER BASHKIR KA
+04A2; C; 04A3; # CYRILLIC CAPITAL LETTER EN WITH DESCENDER
+04A4; C; 04A5; # CYRILLIC CAPITAL LIGATURE EN GHE
+04A6; C; 04A7; # CYRILLIC CAPITAL LETTER PE WITH MIDDLE HOOK
+04A8; C; 04A9; # CYRILLIC CAPITAL LETTER ABKHASIAN HA
+04AA; C; 04AB; # CYRILLIC CAPITAL LETTER ES WITH DESCENDER
+04AC; C; 04AD; # CYRILLIC CAPITAL LETTER TE WITH DESCENDER
+04AE; C; 04AF; # CYRILLIC CAPITAL LETTER STRAIGHT U
+04B0; C; 04B1; # CYRILLIC CAPITAL LETTER STRAIGHT U WITH STROKE
+04B2; C; 04B3; # CYRILLIC CAPITAL LETTER HA WITH DESCENDER
+04B4; C; 04B5; # CYRILLIC CAPITAL LIGATURE TE TSE
+04B6; C; 04B7; # CYRILLIC CAPITAL LETTER CHE WITH DESCENDER
+04B8; C; 04B9; # CYRILLIC CAPITAL LETTER CHE WITH VERTICAL STROKE
+04BA; C; 04BB; # CYRILLIC CAPITAL LETTER SHHA
+04BC; C; 04BD; # CYRILLIC CAPITAL LETTER ABKHASIAN CHE
+04BE; C; 04BF; # CYRILLIC CAPITAL LETTER ABKHASIAN CHE WITH DESCENDER
+04C0; C; 04CF; # CYRILLIC LETTER PALOCHKA
+04C1; C; 04C2; # CYRILLIC CAPITAL LETTER ZHE WITH BREVE
+04C3; C; 04C4; # CYRILLIC CAPITAL LETTER KA WITH HOOK
+04C5; C; 04C6; # CYRILLIC CAPITAL LETTER EL WITH TAIL
+04C7; C; 04C8; # CYRILLIC CAPITAL LETTER EN WITH HOOK
+04C9; C; 04CA; # CYRILLIC CAPITAL LETTER EN WITH TAIL
+04CB; C; 04CC; # CYRILLIC CAPITAL LETTER KHAKASSIAN CHE
+04CD; C; 04CE; # CYRILLIC CAPITAL LETTER EM WITH TAIL
+04D0; C; 04D1; # CYRILLIC CAPITAL LETTER A WITH BREVE
+04D2; C; 04D3; # CYRILLIC CAPITAL LETTER A WITH DIAERESIS
+04D4; C; 04D5; # CYRILLIC CAPITAL LIGATURE A IE
+04D6; C; 04D7; # CYRILLIC CAPITAL LETTER IE WITH BREVE
+04D8; C; 04D9; # CYRILLIC CAPITAL LETTER SCHWA
+04DA; C; 04DB; # CYRILLIC CAPITAL LETTER SCHWA WITH DIAERESIS
+04DC; C; 04DD; # CYRILLIC CAPITAL LETTER ZHE WITH DIAERESIS
+04DE; C; 04DF; # CYRILLIC CAPITAL LETTER ZE WITH DIAERESIS
+04E0; C; 04E1; # CYRILLIC CAPITAL LETTER ABKHASIAN DZE
+04E2; C; 04E3; # CYRILLIC CAPITAL LETTER I WITH MACRON
+04E4; C; 04E5; # CYRILLIC CAPITAL LETTER I WITH DIAERESIS
+04E6; C; 04E7; # CYRILLIC CAPITAL LETTER O WITH DIAERESIS
+04E8; C; 04E9; # CYRILLIC CAPITAL LETTER BARRED O
+04EA; C; 04EB; # CYRILLIC CAPITAL LETTER BARRED O WITH DIAERESIS
+04EC; C; 04ED; # CYRILLIC CAPITAL LETTER E WITH DIAERESIS
+04EE; C; 04EF; # CYRILLIC CAPITAL LETTER U WITH MACRON
+04F0; C; 04F1; # CYRILLIC CAPITAL LETTER U WITH DIAERESIS
+04F2; C; 04F3; # CYRILLIC CAPITAL LETTER U WITH DOUBLE ACUTE
+04F4; C; 04F5; # CYRILLIC CAPITAL LETTER CHE WITH DIAERESIS
+04F6; C; 04F7; # CYRILLIC CAPITAL LETTER GHE WITH DESCENDER
+04F8; C; 04F9; # CYRILLIC CAPITAL LETTER YERU WITH DIAERESIS
+04FA; C; 04FB; # CYRILLIC CAPITAL LETTER GHE WITH STROKE AND HOOK
+04FC; C; 04FD; # CYRILLIC CAPITAL LETTER HA WITH HOOK
+04FE; C; 04FF; # CYRILLIC CAPITAL LETTER HA WITH STROKE
+0500; C; 0501; # CYRILLIC CAPITAL LETTER KOMI DE
+0502; C; 0503; # CYRILLIC CAPITAL LETTER KOMI DJE
+0504; C; 0505; # CYRILLIC CAPITAL LETTER KOMI ZJE
+0506; C; 0507; # CYRILLIC CAPITAL LETTER KOMI DZJE
+0508; C; 0509; # CYRILLIC CAPITAL LETTER KOMI LJE
+050A; C; 050B; # CYRILLIC CAPITAL LETTER KOMI NJE
+050C; C; 050D; # CYRILLIC CAPITAL LETTER KOMI SJE
+050E; C; 050F; # CYRILLIC CAPITAL LETTER KOMI TJE
+0510; C; 0511; # CYRILLIC CAPITAL LETTER REVERSED ZE
+0512; C; 0513; # CYRILLIC CAPITAL LETTER EL WITH HOOK
+0514; C; 0515; # CYRILLIC CAPITAL LETTER LHA
+0516; C; 0517; # CYRILLIC CAPITAL LETTER RHA
+0518; C; 0519; # CYRILLIC CAPITAL LETTER YAE
+051A; C; 051B; # CYRILLIC CAPITAL LETTER QA
+051C; C; 051D; # CYRILLIC CAPITAL LETTER WE
+051E; C; 051F; # CYRILLIC CAPITAL LETTER ALEUT KA
+0520; C; 0521; # CYRILLIC CAPITAL LETTER EL WITH MIDDLE HOOK
+0522; C; 0523; # CYRILLIC CAPITAL LETTER EN WITH MIDDLE HOOK
+0524; C; 0525; # CYRILLIC CAPITAL LETTER PE WITH DESCENDER
+0526; C; 0527; # CYRILLIC CAPITAL LETTER SHHA WITH DESCENDER
+0528; C; 0529; # CYRILLIC CAPITAL LETTER EN WITH LEFT HOOK
+052A; C; 052B; # CYRILLIC CAPITAL LETTER DZZHE
+052C; C; 052D; # CYRILLIC CAPITAL LETTER DCHE
+052E; C; 052F; # CYRILLIC CAPITAL LETTER EL WITH DESCENDER
+0531; C; 0561; # ARMENIAN CAPITAL LETTER AYB
+0532; C; 0562; # ARMENIAN CAPITAL LETTER BEN
+0533; C; 0563; # ARMENIAN CAPITAL LETTER GIM
+0534; C; 0564; # ARMENIAN CAPITAL LETTER DA
+0535; C; 0565; # ARMENIAN CAPITAL LETTER ECH
+0536; C; 0566; # ARMENIAN CAPITAL LETTER ZA
+0537; C; 0567; # ARMENIAN CAPITAL LETTER EH
+0538; C; 0568; # ARMENIAN CAPITAL LETTER ET
+0539; C; 0569; # ARMENIAN CAPITAL LETTER TO
+053A; C; 056A; # ARMENIAN CAPITAL LETTER ZHE
+053B; C; 056B; # ARMENIAN CAPITAL LETTER INI
+053C; C; 056C; # ARMENIAN CAPITAL LETTER LIWN
+053D; C; 056D; # ARMENIAN CAPITAL LETTER XEH
+053E; C; 056E; # ARMENIAN CAPITAL LETTER CA
+053F; C; 056F; # ARMENIAN CAPITAL LETTER KEN
+0540; C; 0570; # ARMENIAN CAPITAL LETTER HO
+0541; C; 0571; # ARMENIAN CAPITAL LETTER JA
+0542; C; 0572; # ARMENIAN CAPITAL LETTER GHAD
+0543; C; 0573; # ARMENIAN CAPITAL LETTER CHEH
+0544; C; 0574; # ARMENIAN CAPITAL LETTER MEN
+0545; C; 0575; # ARMENIAN CAPITAL LETTER YI
+0546; C; 0576; # ARMENIAN CAPITAL LETTER NOW
+0547; C; 0577; # ARMENIAN CAPITAL LETTER SHA
+0548; C; 0578; # ARMENIAN CAPITAL LETTER VO
+0549; C; 0579; # ARMENIAN CAPITAL LETTER CHA
+054A; C; 057A; # ARMENIAN CAPITAL LETTER PEH
+054B; C; 057B; # ARMENIAN CAPITAL LETTER JHEH
+054C; C; 057C; # ARMENIAN CAPITAL LETTER RA
+054D; C; 057D; # ARMENIAN CAPITAL LETTER SEH
+054E; C; 057E; # ARMENIAN CAPITAL LETTER VEW
+054F; C; 057F; # ARMENIAN CAPITAL LETTER TIWN
+0550; C; 0580; # ARMENIAN CAPITAL LETTER REH
+0551; C; 0581; # ARMENIAN CAPITAL LETTER CO
+0552; C; 0582; # ARMENIAN CAPITAL LETTER YIWN
+0553; C; 0583; # ARMENIAN CAPITAL LETTER PIWR
+0554; C; 0584; # ARMENIAN CAPITAL LETTER KEH
+0555; C; 0585; # ARMENIAN CAPITAL LETTER OH
+0556; C; 0586; # ARMENIAN CAPITAL LETTER FEH
+0587; F; 0565 0582; # ARMENIAN SMALL LIGATURE ECH YIWN
+10A0; C; 2D00; # GEORGIAN CAPITAL LETTER AN
+10A1; C; 2D01; # GEORGIAN CAPITAL LETTER BAN
+10A2; C; 2D02; # GEORGIAN CAPITAL LETTER GAN
+10A3; C; 2D03; # GEORGIAN CAPITAL LETTER DON
+10A4; C; 2D04; # GEORGIAN CAPITAL LETTER EN
+10A5; C; 2D05; # GEORGIAN CAPITAL LETTER VIN
+10A6; C; 2D06; # GEORGIAN CAPITAL LETTER ZEN
+10A7; C; 2D07; # GEORGIAN CAPITAL LETTER TAN
+10A8; C; 2D08; # GEORGIAN CAPITAL LETTER IN
+10A9; C; 2D09; # GEORGIAN CAPITAL LETTER KAN
+10AA; C; 2D0A; # GEORGIAN CAPITAL LETTER LAS
+10AB; C; 2D0B; # GEORGIAN CAPITAL LETTER MAN
+10AC; C; 2D0C; # GEORGIAN CAPITAL LETTER NAR
+10AD; C; 2D0D; # GEORGIAN CAPITAL LETTER ON
+10AE; C; 2D0E; # GEORGIAN CAPITAL LETTER PAR
+10AF; C; 2D0F; # GEORGIAN CAPITAL LETTER ZHAR
+10B0; C; 2D10; # GEORGIAN CAPITAL LETTER RAE
+10B1; C; 2D11; # GEORGIAN CAPITAL LETTER SAN
+10B2; C; 2D12; # GEORGIAN CAPITAL LETTER TAR
+10B3; C; 2D13; # GEORGIAN CAPITAL LETTER UN
+10B4; C; 2D14; # GEORGIAN CAPITAL LETTER PHAR
+10B5; C; 2D15; # GEORGIAN CAPITAL LETTER KHAR
+10B6; C; 2D16; # GEORGIAN CAPITAL LETTER GHAN
+10B7; C; 2D17; # GEORGIAN CAPITAL LETTER QAR
+10B8; C; 2D18; # GEORGIAN CAPITAL LETTER SHIN
+10B9; C; 2D19; # GEORGIAN CAPITAL LETTER CHIN
+10BA; C; 2D1A; # GEORGIAN CAPITAL LETTER CAN
+10BB; C; 2D1B; # GEORGIAN CAPITAL LETTER JIL
+10BC; C; 2D1C; # GEORGIAN CAPITAL LETTER CIL
+10BD; C; 2D1D; # GEORGIAN CAPITAL LETTER CHAR
+10BE; C; 2D1E; # GEORGIAN CAPITAL LETTER XAN
+10BF; C; 2D1F; # GEORGIAN CAPITAL LETTER JHAN
+10C0; C; 2D20; # GEORGIAN CAPITAL LETTER HAE
+10C1; C; 2D21; # GEORGIAN CAPITAL LETTER HE
+10C2; C; 2D22; # GEORGIAN CAPITAL LETTER HIE
+10C3; C; 2D23; # GEORGIAN CAPITAL LETTER WE
+10C4; C; 2D24; # GEORGIAN CAPITAL LETTER HAR
+10C5; C; 2D25; # GEORGIAN CAPITAL LETTER HOE
+10C7; C; 2D27; # GEORGIAN CAPITAL LETTER YN
+10CD; C; 2D2D; # GEORGIAN CAPITAL LETTER AEN
+13F8; C; 13F0; # CHEROKEE SMALL LETTER YE
+13F9; C; 13F1; # CHEROKEE SMALL LETTER YI
+13FA; C; 13F2; # CHEROKEE SMALL LETTER YO
+13FB; C; 13F3; # CHEROKEE SMALL LETTER YU
+13FC; C; 13F4; # CHEROKEE SMALL LETTER YV
+13FD; C; 13F5; # CHEROKEE SMALL LETTER MV
+1C80; C; 0432; # CYRILLIC SMALL LETTER ROUNDED VE
+1C81; C; 0434; # CYRILLIC SMALL LETTER LONG-LEGGED DE
+1C82; C; 043E; # CYRILLIC SMALL LETTER NARROW O
+1C83; C; 0441; # CYRILLIC SMALL LETTER WIDE ES
+1C84; C; 0442; # CYRILLIC SMALL LETTER TALL TE
+1C85; C; 0442; # CYRILLIC SMALL LETTER THREE-LEGGED TE
+1C86; C; 044A; # CYRILLIC SMALL LETTER TALL HARD SIGN
+1C87; C; 0463; # CYRILLIC SMALL LETTER TALL YAT
+1C88; C; A64B; # CYRILLIC SMALL LETTER UNBLENDED UK
+1C90; C; 10D0; # GEORGIAN MTAVRULI CAPITAL LETTER AN
+1C91; C; 10D1; # GEORGIAN MTAVRULI CAPITAL LETTER BAN
+1C92; C; 10D2; # GEORGIAN MTAVRULI CAPITAL LETTER GAN
+1C93; C; 10D3; # GEORGIAN MTAVRULI CAPITAL LETTER DON
+1C94; C; 10D4; # GEORGIAN MTAVRULI CAPITAL LETTER EN
+1C95; C; 10D5; # GEORGIAN MTAVRULI CAPITAL LETTER VIN
+1C96; C; 10D6; # GEORGIAN MTAVRULI CAPITAL LETTER ZEN
+1C97; C; 10D7; # GEORGIAN MTAVRULI CAPITAL LETTER TAN
+1C98; C; 10D8; # GEORGIAN MTAVRULI CAPITAL LETTER IN
+1C99; C; 10D9; # GEORGIAN MTAVRULI CAPITAL LETTER KAN
+1C9A; C; 10DA; # GEORGIAN MTAVRULI CAPITAL LETTER LAS
+1C9B; C; 10DB; # GEORGIAN MTAVRULI CAPITAL LETTER MAN
+1C9C; C; 10DC; # GEORGIAN MTAVRULI CAPITAL LETTER NAR
+1C9D; C; 10DD; # GEORGIAN MTAVRULI CAPITAL LETTER ON
+1C9E; C; 10DE; # GEORGIAN MTAVRULI CAPITAL LETTER PAR
+1C9F; C; 10DF; # GEORGIAN MTAVRULI CAPITAL LETTER ZHAR
+1CA0; C; 10E0; # GEORGIAN MTAVRULI CAPITAL LETTER RAE
+1CA1; C; 10E1; # GEORGIAN MTAVRULI CAPITAL LETTER SAN
+1CA2; C; 10E2; # GEORGIAN MTAVRULI CAPITAL LETTER TAR
+1CA3; C; 10E3; # GEORGIAN MTAVRULI CAPITAL LETTER UN
+1CA4; C; 10E4; # GEORGIAN MTAVRULI CAPITAL LETTER PHAR
+1CA5; C; 10E5; # GEORGIAN MTAVRULI CAPITAL LETTER KHAR
+1CA6; C; 10E6; # GEORGIAN MTAVRULI CAPITAL LETTER GHAN
+1CA7; C; 10E7; # GEORGIAN MTAVRULI CAPITAL LETTER QAR
+1CA8; C; 10E8; # GEORGIAN MTAVRULI CAPITAL LETTER SHIN
+1CA9; C; 10E9; # GEORGIAN MTAVRULI CAPITAL LETTER CHIN
+1CAA; C; 10EA; # GEORGIAN MTAVRULI CAPITAL LETTER CAN
+1CAB; C; 10EB; # GEORGIAN MTAVRULI CAPITAL LETTER JIL
+1CAC; C; 10EC; # GEORGIAN MTAVRULI CAPITAL LETTER CIL
+1CAD; C; 10ED; # GEORGIAN MTAVRULI CAPITAL LETTER CHAR
+1CAE; C; 10EE; # GEORGIAN MTAVRULI CAPITAL LETTER XAN
+1CAF; C; 10EF; # GEORGIAN MTAVRULI CAPITAL LETTER JHAN
+1CB0; C; 10F0; # GEORGIAN MTAVRULI CAPITAL LETTER HAE
+1CB1; C; 10F1; # GEORGIAN MTAVRULI CAPITAL LETTER HE
+1CB2; C; 10F2; # GEORGIAN MTAVRULI CAPITAL LETTER HIE
+1CB3; C; 10F3; # GEORGIAN MTAVRULI CAPITAL LETTER WE
+1CB4; C; 10F4; # GEORGIAN MTAVRULI CAPITAL LETTER HAR
+1CB5; C; 10F5; # GEORGIAN MTAVRULI CAPITAL LETTER HOE
+1CB6; C; 10F6; # GEORGIAN MTAVRULI CAPITAL LETTER FI
+1CB7; C; 10F7; # GEORGIAN MTAVRULI CAPITAL LETTER YN
+1CB8; C; 10F8; # GEORGIAN MTAVRULI CAPITAL LETTER ELIFI
+1CB9; C; 10F9; # GEORGIAN MTAVRULI CAPITAL LETTER TURNED GAN
+1CBA; C; 10FA; # GEORGIAN MTAVRULI CAPITAL LETTER AIN
+1CBD; C; 10FD; # GEORGIAN MTAVRULI CAPITAL LETTER AEN
+1CBE; C; 10FE; # GEORGIAN MTAVRULI CAPITAL LETTER HARD SIGN
+1CBF; C; 10FF; # GEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGN
+1E00; C; 1E01; # LATIN CAPITAL LETTER A WITH RING BELOW
+1E02; C; 1E03; # LATIN CAPITAL LETTER B WITH DOT ABOVE
+1E04; C; 1E05; # LATIN CAPITAL LETTER B WITH DOT BELOW
+1E06; C; 1E07; # LATIN CAPITAL LETTER B WITH LINE BELOW
+1E08; C; 1E09; # LATIN CAPITAL LETTER C WITH CEDILLA AND ACUTE
+1E0A; C; 1E0B; # LATIN CAPITAL LETTER D WITH DOT ABOVE
+1E0C; C; 1E0D; # LATIN CAPITAL LETTER D WITH DOT BELOW
+1E0E; C; 1E0F; # LATIN CAPITAL LETTER D WITH LINE BELOW
+1E10; C; 1E11; # LATIN CAPITAL LETTER D WITH CEDILLA
+1E12; C; 1E13; # LATIN CAPITAL LETTER D WITH CIRCUMFLEX BELOW
+1E14; C; 1E15; # LATIN CAPITAL LETTER E WITH MACRON AND GRAVE
+1E16; C; 1E17; # LATIN CAPITAL LETTER E WITH MACRON AND ACUTE
+1E18; C; 1E19; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX BELOW
+1E1A; C; 1E1B; # LATIN CAPITAL LETTER E WITH TILDE BELOW
+1E1C; C; 1E1D; # LATIN CAPITAL LETTER E WITH CEDILLA AND BREVE
+1E1E; C; 1E1F; # LATIN CAPITAL LETTER F WITH DOT ABOVE
+1E20; C; 1E21; # LATIN CAPITAL LETTER G WITH MACRON
+1E22; C; 1E23; # LATIN CAPITAL LETTER H WITH DOT ABOVE
+1E24; C; 1E25; # LATIN CAPITAL LETTER H WITH DOT BELOW
+1E26; C; 1E27; # LATIN CAPITAL LETTER H WITH DIAERESIS
+1E28; C; 1E29; # LATIN CAPITAL LETTER H WITH CEDILLA
+1E2A; C; 1E2B; # LATIN CAPITAL LETTER H WITH BREVE BELOW
+1E2C; C; 1E2D; # LATIN CAPITAL LETTER I WITH TILDE BELOW
+1E2E; C; 1E2F; # LATIN CAPITAL LETTER I WITH DIAERESIS AND ACUTE
+1E30; C; 1E31; # LATIN CAPITAL LETTER K WITH ACUTE
+1E32; C; 1E33; # LATIN CAPITAL LETTER K WITH DOT BELOW
+1E34; C; 1E35; # LATIN CAPITAL LETTER K WITH LINE BELOW
+1E36; C; 1E37; # LATIN CAPITAL LETTER L WITH DOT BELOW
+1E38; C; 1E39; # LATIN CAPITAL LETTER L WITH DOT BELOW AND MACRON
+1E3A; C; 1E3B; # LATIN CAPITAL LETTER L WITH LINE BELOW
+1E3C; C; 1E3D; # LATIN CAPITAL LETTER L WITH CIRCUMFLEX BELOW
+1E3E; C; 1E3F; # LATIN CAPITAL LETTER M WITH ACUTE
+1E40; C; 1E41; # LATIN CAPITAL LETTER M WITH DOT ABOVE
+1E42; C; 1E43; # LATIN CAPITAL LETTER M WITH DOT BELOW
+1E44; C; 1E45; # LATIN CAPITAL LETTER N WITH DOT ABOVE
+1E46; C; 1E47; # LATIN CAPITAL LETTER N WITH DOT BELOW
+1E48; C; 1E49; # LATIN CAPITAL LETTER N WITH LINE BELOW
+1E4A; C; 1E4B; # LATIN CAPITAL LETTER N WITH CIRCUMFLEX BELOW
+1E4C; C; 1E4D; # LATIN CAPITAL LETTER O WITH TILDE AND ACUTE
+1E4E; C; 1E4F; # LATIN CAPITAL LETTER O WITH TILDE AND DIAERESIS
+1E50; C; 1E51; # LATIN CAPITAL LETTER O WITH MACRON AND GRAVE
+1E52; C; 1E53; # LATIN CAPITAL LETTER O WITH MACRON AND ACUTE
+1E54; C; 1E55; # LATIN CAPITAL LETTER P WITH ACUTE
+1E56; C; 1E57; # LATIN CAPITAL LETTER P WITH DOT ABOVE
+1E58; C; 1E59; # LATIN CAPITAL LETTER R WITH DOT ABOVE
+1E5A; C; 1E5B; # LATIN CAPITAL LETTER R WITH DOT BELOW
+1E5C; C; 1E5D; # LATIN CAPITAL LETTER R WITH DOT BELOW AND MACRON
+1E5E; C; 1E5F; # LATIN CAPITAL LETTER R WITH LINE BELOW
+1E60; C; 1E61; # LATIN CAPITAL LETTER S WITH DOT ABOVE
+1E62; C; 1E63; # LATIN CAPITAL LETTER S WITH DOT BELOW
+1E64; C; 1E65; # LATIN CAPITAL LETTER S WITH ACUTE AND DOT ABOVE
+1E66; C; 1E67; # LATIN CAPITAL LETTER S WITH CARON AND DOT ABOVE
+1E68; C; 1E69; # LATIN CAPITAL LETTER S WITH DOT BELOW AND DOT ABOVE
+1E6A; C; 1E6B; # LATIN CAPITAL LETTER T WITH DOT ABOVE
+1E6C; C; 1E6D; # LATIN CAPITAL LETTER T WITH DOT BELOW
+1E6E; C; 1E6F; # LATIN CAPITAL LETTER T WITH LINE BELOW
+1E70; C; 1E71; # LATIN CAPITAL LETTER T WITH CIRCUMFLEX BELOW
+1E72; C; 1E73; # LATIN CAPITAL LETTER U WITH DIAERESIS BELOW
+1E74; C; 1E75; # LATIN CAPITAL LETTER U WITH TILDE BELOW
+1E76; C; 1E77; # LATIN CAPITAL LETTER U WITH CIRCUMFLEX BELOW
+1E78; C; 1E79; # LATIN CAPITAL LETTER U WITH TILDE AND ACUTE
+1E7A; C; 1E7B; # LATIN CAPITAL LETTER U WITH MACRON AND DIAERESIS
+1E7C; C; 1E7D; # LATIN CAPITAL LETTER V WITH TILDE
+1E7E; C; 1E7F; # LATIN CAPITAL LETTER V WITH DOT BELOW
+1E80; C; 1E81; # LATIN CAPITAL LETTER W WITH GRAVE
+1E82; C; 1E83; # LATIN CAPITAL LETTER W WITH ACUTE
+1E84; C; 1E85; # LATIN CAPITAL LETTER W WITH DIAERESIS
+1E86; C; 1E87; # LATIN CAPITAL LETTER W WITH DOT ABOVE
+1E88; C; 1E89; # LATIN CAPITAL LETTER W WITH DOT BELOW
+1E8A; C; 1E8B; # LATIN CAPITAL LETTER X WITH DOT ABOVE
+1E8C; C; 1E8D; # LATIN CAPITAL LETTER X WITH DIAERESIS
+1E8E; C; 1E8F; # LATIN CAPITAL LETTER Y WITH DOT ABOVE
+1E90; C; 1E91; # LATIN CAPITAL LETTER Z WITH CIRCUMFLEX
+1E92; C; 1E93; # LATIN CAPITAL LETTER Z WITH DOT BELOW
+1E94; C; 1E95; # LATIN CAPITAL LETTER Z WITH LINE BELOW
+1E96; F; 0068 0331; # LATIN SMALL LETTER H WITH LINE BELOW
+1E97; F; 0074 0308; # LATIN SMALL LETTER T WITH DIAERESIS
+1E98; F; 0077 030A; # LATIN SMALL LETTER W WITH RING ABOVE
+1E99; F; 0079 030A; # LATIN SMALL LETTER Y WITH RING ABOVE
+1E9A; F; 0061 02BE; # LATIN SMALL LETTER A WITH RIGHT HALF RING
+1E9B; C; 1E61; # LATIN SMALL LETTER LONG S WITH DOT ABOVE
+1E9E; F; 0073 0073; # LATIN CAPITAL LETTER SHARP S
+1E9E; S; 00DF; # LATIN CAPITAL LETTER SHARP S
+1EA0; C; 1EA1; # LATIN CAPITAL LETTER A WITH DOT BELOW
+1EA2; C; 1EA3; # LATIN CAPITAL LETTER A WITH HOOK ABOVE
+1EA4; C; 1EA5; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE
+1EA6; C; 1EA7; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE
+1EA8; C; 1EA9; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE
+1EAA; C; 1EAB; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE
+1EAC; C; 1EAD; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW
+1EAE; C; 1EAF; # LATIN CAPITAL LETTER A WITH BREVE AND ACUTE
+1EB0; C; 1EB1; # LATIN CAPITAL LETTER A WITH BREVE AND GRAVE
+1EB2; C; 1EB3; # LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE
+1EB4; C; 1EB5; # LATIN CAPITAL LETTER A WITH BREVE AND TILDE
+1EB6; C; 1EB7; # LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW
+1EB8; C; 1EB9; # LATIN CAPITAL LETTER E WITH DOT BELOW
+1EBA; C; 1EBB; # LATIN CAPITAL LETTER E WITH HOOK ABOVE
+1EBC; C; 1EBD; # LATIN CAPITAL LETTER E WITH TILDE
+1EBE; C; 1EBF; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE
+1EC0; C; 1EC1; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE
+1EC2; C; 1EC3; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE
+1EC4; C; 1EC5; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE
+1EC6; C; 1EC7; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW
+1EC8; C; 1EC9; # LATIN CAPITAL LETTER I WITH HOOK ABOVE
+1ECA; C; 1ECB; # LATIN CAPITAL LETTER I WITH DOT BELOW
+1ECC; C; 1ECD; # LATIN CAPITAL LETTER O WITH DOT BELOW
+1ECE; C; 1ECF; # LATIN CAPITAL LETTER O WITH HOOK ABOVE
+1ED0; C; 1ED1; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE
+1ED2; C; 1ED3; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE
+1ED4; C; 1ED5; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE
+1ED6; C; 1ED7; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE
+1ED8; C; 1ED9; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW
+1EDA; C; 1EDB; # LATIN CAPITAL LETTER O WITH HORN AND ACUTE
+1EDC; C; 1EDD; # LATIN CAPITAL LETTER O WITH HORN AND GRAVE
+1EDE; C; 1EDF; # LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE
+1EE0; C; 1EE1; # LATIN CAPITAL LETTER O WITH HORN AND TILDE
+1EE2; C; 1EE3; # LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW
+1EE4; C; 1EE5; # LATIN CAPITAL LETTER U WITH DOT BELOW
+1EE6; C; 1EE7; # LATIN CAPITAL LETTER U WITH HOOK ABOVE
+1EE8; C; 1EE9; # LATIN CAPITAL LETTER U WITH HORN AND ACUTE
+1EEA; C; 1EEB; # LATIN CAPITAL LETTER U WITH HORN AND GRAVE
+1EEC; C; 1EED; # LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE
+1EEE; C; 1EEF; # LATIN CAPITAL LETTER U WITH HORN AND TILDE
+1EF0; C; 1EF1; # LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW
+1EF2; C; 1EF3; # LATIN CAPITAL LETTER Y WITH GRAVE
+1EF4; C; 1EF5; # LATIN CAPITAL LETTER Y WITH DOT BELOW
+1EF6; C; 1EF7; # LATIN CAPITAL LETTER Y WITH HOOK ABOVE
+1EF8; C; 1EF9; # LATIN CAPITAL LETTER Y WITH TILDE
+1EFA; C; 1EFB; # LATIN CAPITAL LETTER MIDDLE-WELSH LL
+1EFC; C; 1EFD; # LATIN CAPITAL LETTER MIDDLE-WELSH V
+1EFE; C; 1EFF; # LATIN CAPITAL LETTER Y WITH LOOP
+1F08; C; 1F00; # GREEK CAPITAL LETTER ALPHA WITH PSILI
+1F09; C; 1F01; # GREEK CAPITAL LETTER ALPHA WITH DASIA
+1F0A; C; 1F02; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA
+1F0B; C; 1F03; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA
+1F0C; C; 1F04; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA
+1F0D; C; 1F05; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA
+1F0E; C; 1F06; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI
+1F0F; C; 1F07; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI
+1F18; C; 1F10; # GREEK CAPITAL LETTER EPSILON WITH PSILI
+1F19; C; 1F11; # GREEK CAPITAL LETTER EPSILON WITH DASIA
+1F1A; C; 1F12; # GREEK CAPITAL LETTER EPSILON WITH PSILI AND VARIA
+1F1B; C; 1F13; # GREEK CAPITAL LETTER EPSILON WITH DASIA AND VARIA
+1F1C; C; 1F14; # GREEK CAPITAL LETTER EPSILON WITH PSILI AND OXIA
+1F1D; C; 1F15; # GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA
+1F28; C; 1F20; # GREEK CAPITAL LETTER ETA WITH PSILI
+1F29; C; 1F21; # GREEK CAPITAL LETTER ETA WITH DASIA
+1F2A; C; 1F22; # GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA
+1F2B; C; 1F23; # GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA
+1F2C; C; 1F24; # GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA
+1F2D; C; 1F25; # GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA
+1F2E; C; 1F26; # GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI
+1F2F; C; 1F27; # GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI
+1F38; C; 1F30; # GREEK CAPITAL LETTER IOTA WITH PSILI
+1F39; C; 1F31; # GREEK CAPITAL LETTER IOTA WITH DASIA
+1F3A; C; 1F32; # GREEK CAPITAL LETTER IOTA WITH PSILI AND VARIA
+1F3B; C; 1F33; # GREEK CAPITAL LETTER IOTA WITH DASIA AND VARIA
+1F3C; C; 1F34; # GREEK CAPITAL LETTER IOTA WITH PSILI AND OXIA
+1F3D; C; 1F35; # GREEK CAPITAL LETTER IOTA WITH DASIA AND OXIA
+1F3E; C; 1F36; # GREEK CAPITAL LETTER IOTA WITH PSILI AND PERISPOMENI
+1F3F; C; 1F37; # GREEK CAPITAL LETTER IOTA WITH DASIA AND PERISPOMENI
+1F48; C; 1F40; # GREEK CAPITAL LETTER OMICRON WITH PSILI
+1F49; C; 1F41; # GREEK CAPITAL LETTER OMICRON WITH DASIA
+1F4A; C; 1F42; # GREEK CAPITAL LETTER OMICRON WITH PSILI AND VARIA
+1F4B; C; 1F43; # GREEK CAPITAL LETTER OMICRON WITH DASIA AND VARIA
+1F4C; C; 1F44; # GREEK CAPITAL LETTER OMICRON WITH PSILI AND OXIA
+1F4D; C; 1F45; # GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA
+1F50; F; 03C5 0313; # GREEK SMALL LETTER UPSILON WITH PSILI
+1F52; F; 03C5 0313 0300; # GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA
+1F54; F; 03C5 0313 0301; # GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA
+1F56; F; 03C5 0313 0342; # GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI
+1F59; C; 1F51; # GREEK CAPITAL LETTER UPSILON WITH DASIA
+1F5B; C; 1F53; # GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA
+1F5D; C; 1F55; # GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA
+1F5F; C; 1F57; # GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI
+1F68; C; 1F60; # GREEK CAPITAL LETTER OMEGA WITH PSILI
+1F69; C; 1F61; # GREEK CAPITAL LETTER OMEGA WITH DASIA
+1F6A; C; 1F62; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA
+1F6B; C; 1F63; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA
+1F6C; C; 1F64; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA
+1F6D; C; 1F65; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA
+1F6E; C; 1F66; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI
+1F6F; C; 1F67; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI
+1F80; F; 1F00 03B9; # GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI
+1F81; F; 1F01 03B9; # GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI
+1F82; F; 1F02 03B9; # GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI
+1F83; F; 1F03 03B9; # GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI
+1F84; F; 1F04 03B9; # GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI
+1F85; F; 1F05 03B9; # GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI
+1F86; F; 1F06 03B9; # GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI
+1F87; F; 1F07 03B9; # GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI
+1F88; F; 1F00 03B9; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI
+1F88; S; 1F80; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI
+1F89; F; 1F01 03B9; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI
+1F89; S; 1F81; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI
+1F8A; F; 1F02 03B9; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI
+1F8A; S; 1F82; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI
+1F8B; F; 1F03 03B9; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI
+1F8B; S; 1F83; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI
+1F8C; F; 1F04 03B9; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI
+1F8C; S; 1F84; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI
+1F8D; F; 1F05 03B9; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI
+1F8D; S; 1F85; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI
+1F8E; F; 1F06 03B9; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI
+1F8E; S; 1F86; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI
+1F8F; F; 1F07 03B9; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI
+1F8F; S; 1F87; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI
+1F90; F; 1F20 03B9; # GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI
+1F91; F; 1F21 03B9; # GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI
+1F92; F; 1F22 03B9; # GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI
+1F93; F; 1F23 03B9; # GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI
+1F94; F; 1F24 03B9; # GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI
+1F95; F; 1F25 03B9; # GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI
+1F96; F; 1F26 03B9; # GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI
+1F97; F; 1F27 03B9; # GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI
+1F98; F; 1F20 03B9; # GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI
+1F98; S; 1F90; # GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI
+1F99; F; 1F21 03B9; # GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI
+1F99; S; 1F91; # GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI
+1F9A; F; 1F22 03B9; # GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI
+1F9A; S; 1F92; # GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI
+1F9B; F; 1F23 03B9; # GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI
+1F9B; S; 1F93; # GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI
+1F9C; F; 1F24 03B9; # GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI
+1F9C; S; 1F94; # GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI
+1F9D; F; 1F25 03B9; # GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI
+1F9D; S; 1F95; # GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI
+1F9E; F; 1F26 03B9; # GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI
+1F9E; S; 1F96; # GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI
+1F9F; F; 1F27 03B9; # GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI
+1F9F; S; 1F97; # GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI
+1FA0; F; 1F60 03B9; # GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI
+1FA1; F; 1F61 03B9; # GREEK SMALL LETTER OMEGA WITH DASIA AND YPOGEGRAMMENI
+1FA2; F; 1F62 03B9; # GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRAMMENI
+1FA3; F; 1F63 03B9; # GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA AND YPOGEGRAMMENI
+1FA4; F; 1F64 03B9; # GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA AND YPOGEGRAMMENI
+1FA5; F; 1F65 03B9; # GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA AND YPOGEGRAMMENI
+1FA6; F; 1F66 03B9; # GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI
+1FA7; F; 1F67 03B9; # GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI
+1FA8; F; 1F60 03B9; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI
+1FA8; S; 1FA0; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI
+1FA9; F; 1F61 03B9; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI
+1FA9; S; 1FA1; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI
+1FAA; F; 1F62 03B9; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI
+1FAA; S; 1FA2; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI
+1FAB; F; 1F63 03B9; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI
+1FAB; S; 1FA3; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI
+1FAC; F; 1F64 03B9; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI
+1FAC; S; 1FA4; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI
+1FAD; F; 1F65 03B9; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI
+1FAD; S; 1FA5; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI
+1FAE; F; 1F66 03B9; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI
+1FAE; S; 1FA6; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI
+1FAF; F; 1F67 03B9; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI
+1FAF; S; 1FA7; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI
+1FB2; F; 1F70 03B9; # GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI
+1FB3; F; 03B1 03B9; # GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI
+1FB4; F; 03AC 03B9; # GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI
+1FB6; F; 03B1 0342; # GREEK SMALL LETTER ALPHA WITH PERISPOMENI
+1FB7; F; 03B1 0342 03B9; # GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI
+1FB8; C; 1FB0; # GREEK CAPITAL LETTER ALPHA WITH VRACHY
+1FB9; C; 1FB1; # GREEK CAPITAL LETTER ALPHA WITH MACRON
+1FBA; C; 1F70; # GREEK CAPITAL LETTER ALPHA WITH VARIA
+1FBB; C; 1F71; # GREEK CAPITAL LETTER ALPHA WITH OXIA
+1FBC; F; 03B1 03B9; # GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI
+1FBC; S; 1FB3; # GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI
+1FBE; C; 03B9; # GREEK PROSGEGRAMMENI
+1FC2; F; 1F74 03B9; # GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI
+1FC3; F; 03B7 03B9; # GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI
+1FC4; F; 03AE 03B9; # GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI
+1FC6; F; 03B7 0342; # GREEK SMALL LETTER ETA WITH PERISPOMENI
+1FC7; F; 03B7 0342 03B9; # GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI
+1FC8; C; 1F72; # GREEK CAPITAL LETTER EPSILON WITH VARIA
+1FC9; C; 1F73; # GREEK CAPITAL LETTER EPSILON WITH OXIA
+1FCA; C; 1F74; # GREEK CAPITAL LETTER ETA WITH VARIA
+1FCB; C; 1F75; # GREEK CAPITAL LETTER ETA WITH OXIA
+1FCC; F; 03B7 03B9; # GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI
+1FCC; S; 1FC3; # GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI
+1FD2; F; 03B9 0308 0300; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA
+1FD3; F; 03B9 0308 0301; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA
+1FD6; F; 03B9 0342; # GREEK SMALL LETTER IOTA WITH PERISPOMENI
+1FD7; F; 03B9 0308 0342; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI
+1FD8; C; 1FD0; # GREEK CAPITAL LETTER IOTA WITH VRACHY
+1FD9; C; 1FD1; # GREEK CAPITAL LETTER IOTA WITH MACRON
+1FDA; C; 1F76; # GREEK CAPITAL LETTER IOTA WITH VARIA
+1FDB; C; 1F77; # GREEK CAPITAL LETTER IOTA WITH OXIA
+1FE2; F; 03C5 0308 0300; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA
+1FE3; F; 03C5 0308 0301; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA
+1FE4; F; 03C1 0313; # GREEK SMALL LETTER RHO WITH PSILI
+1FE6; F; 03C5 0342; # GREEK SMALL LETTER UPSILON WITH PERISPOMENI
+1FE7; F; 03C5 0308 0342; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI
+1FE8; C; 1FE0; # GREEK CAPITAL LETTER UPSILON WITH VRACHY
+1FE9; C; 1FE1; # GREEK CAPITAL LETTER UPSILON WITH MACRON
+1FEA; C; 1F7A; # GREEK CAPITAL LETTER UPSILON WITH VARIA
+1FEB; C; 1F7B; # GREEK CAPITAL LETTER UPSILON WITH OXIA
+1FEC; C; 1FE5; # GREEK CAPITAL LETTER RHO WITH DASIA
+1FF2; F; 1F7C 03B9; # GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI
+1FF3; F; 03C9 03B9; # GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI
+1FF4; F; 03CE 03B9; # GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI
+1FF6; F; 03C9 0342; # GREEK SMALL LETTER OMEGA WITH PERISPOMENI
+1FF7; F; 03C9 0342 03B9; # GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI
+1FF8; C; 1F78; # GREEK CAPITAL LETTER OMICRON WITH VARIA
+1FF9; C; 1F79; # GREEK CAPITAL LETTER OMICRON WITH OXIA
+1FFA; C; 1F7C; # GREEK CAPITAL LETTER OMEGA WITH VARIA
+1FFB; C; 1F7D; # GREEK CAPITAL LETTER OMEGA WITH OXIA
+1FFC; F; 03C9 03B9; # GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI
+1FFC; S; 1FF3; # GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI
+2126; C; 03C9; # OHM SIGN
+212A; C; 006B; # KELVIN SIGN
+212B; C; 00E5; # ANGSTROM SIGN
+2132; C; 214E; # TURNED CAPITAL F
+2160; C; 2170; # ROMAN NUMERAL ONE
+2161; C; 2171; # ROMAN NUMERAL TWO
+2162; C; 2172; # ROMAN NUMERAL THREE
+2163; C; 2173; # ROMAN NUMERAL FOUR
+2164; C; 2174; # ROMAN NUMERAL FIVE
+2165; C; 2175; # ROMAN NUMERAL SIX
+2166; C; 2176; # ROMAN NUMERAL SEVEN
+2167; C; 2177; # ROMAN NUMERAL EIGHT
+2168; C; 2178; # ROMAN NUMERAL NINE
+2169; C; 2179; # ROMAN NUMERAL TEN
+216A; C; 217A; # ROMAN NUMERAL ELEVEN
+216B; C; 217B; # ROMAN NUMERAL TWELVE
+216C; C; 217C; # ROMAN NUMERAL FIFTY
+216D; C; 217D; # ROMAN NUMERAL ONE HUNDRED
+216E; C; 217E; # ROMAN NUMERAL FIVE HUNDRED
+216F; C; 217F; # ROMAN NUMERAL ONE THOUSAND
+2183; C; 2184; # ROMAN NUMERAL REVERSED ONE HUNDRED
+24B6; C; 24D0; # CIRCLED LATIN CAPITAL LETTER A
+24B7; C; 24D1; # CIRCLED LATIN CAPITAL LETTER B
+24B8; C; 24D2; # CIRCLED LATIN CAPITAL LETTER C
+24B9; C; 24D3; # CIRCLED LATIN CAPITAL LETTER D
+24BA; C; 24D4; # CIRCLED LATIN CAPITAL LETTER E
+24BB; C; 24D5; # CIRCLED LATIN CAPITAL LETTER F
+24BC; C; 24D6; # CIRCLED LATIN CAPITAL LETTER G
+24BD; C; 24D7; # CIRCLED LATIN CAPITAL LETTER H
+24BE; C; 24D8; # CIRCLED LATIN CAPITAL LETTER I
+24BF; C; 24D9; # CIRCLED LATIN CAPITAL LETTER J
+24C0; C; 24DA; # CIRCLED LATIN CAPITAL LETTER K
+24C1; C; 24DB; # CIRCLED LATIN CAPITAL LETTER L
+24C2; C; 24DC; # CIRCLED LATIN CAPITAL LETTER M
+24C3; C; 24DD; # CIRCLED LATIN CAPITAL LETTER N
+24C4; C; 24DE; # CIRCLED LATIN CAPITAL LETTER O
+24C5; C; 24DF; # CIRCLED LATIN CAPITAL LETTER P
+24C6; C; 24E0; # CIRCLED LATIN CAPITAL LETTER Q
+24C7; C; 24E1; # CIRCLED LATIN CAPITAL LETTER R
+24C8; C; 24E2; # CIRCLED LATIN CAPITAL LETTER S
+24C9; C; 24E3; # CIRCLED LATIN CAPITAL LETTER T
+24CA; C; 24E4; # CIRCLED LATIN CAPITAL LETTER U
+24CB; C; 24E5; # CIRCLED LATIN CAPITAL LETTER V
+24CC; C; 24E6; # CIRCLED LATIN CAPITAL LETTER W
+24CD; C; 24E7; # CIRCLED LATIN CAPITAL LETTER X
+24CE; C; 24E8; # CIRCLED LATIN CAPITAL LETTER Y
+24CF; C; 24E9; # CIRCLED LATIN CAPITAL LETTER Z
+2C00; C; 2C30; # GLAGOLITIC CAPITAL LETTER AZU
+2C01; C; 2C31; # GLAGOLITIC CAPITAL LETTER BUKY
+2C02; C; 2C32; # GLAGOLITIC CAPITAL LETTER VEDE
+2C03; C; 2C33; # GLAGOLITIC CAPITAL LETTER GLAGOLI
+2C04; C; 2C34; # GLAGOLITIC CAPITAL LETTER DOBRO
+2C05; C; 2C35; # GLAGOLITIC CAPITAL LETTER YESTU
+2C06; C; 2C36; # GLAGOLITIC CAPITAL LETTER ZHIVETE
+2C07; C; 2C37; # GLAGOLITIC CAPITAL LETTER DZELO
+2C08; C; 2C38; # GLAGOLITIC CAPITAL LETTER ZEMLJA
+2C09; C; 2C39; # GLAGOLITIC CAPITAL LETTER IZHE
+2C0A; C; 2C3A; # GLAGOLITIC CAPITAL LETTER INITIAL IZHE
+2C0B; C; 2C3B; # GLAGOLITIC CAPITAL LETTER I
+2C0C; C; 2C3C; # GLAGOLITIC CAPITAL LETTER DJERVI
+2C0D; C; 2C3D; # GLAGOLITIC CAPITAL LETTER KAKO
+2C0E; C; 2C3E; # GLAGOLITIC CAPITAL LETTER LJUDIJE
+2C0F; C; 2C3F; # GLAGOLITIC CAPITAL LETTER MYSLITE
+2C10; C; 2C40; # GLAGOLITIC CAPITAL LETTER NASHI
+2C11; C; 2C41; # GLAGOLITIC CAPITAL LETTER ONU
+2C12; C; 2C42; # GLAGOLITIC CAPITAL LETTER POKOJI
+2C13; C; 2C43; # GLAGOLITIC CAPITAL LETTER RITSI
+2C14; C; 2C44; # GLAGOLITIC CAPITAL LETTER SLOVO
+2C15; C; 2C45; # GLAGOLITIC CAPITAL LETTER TVRIDO
+2C16; C; 2C46; # GLAGOLITIC CAPITAL LETTER UKU
+2C17; C; 2C47; # GLAGOLITIC CAPITAL LETTER FRITU
+2C18; C; 2C48; # GLAGOLITIC CAPITAL LETTER HERU
+2C19; C; 2C49; # GLAGOLITIC CAPITAL LETTER OTU
+2C1A; C; 2C4A; # GLAGOLITIC CAPITAL LETTER PE
+2C1B; C; 2C4B; # GLAGOLITIC CAPITAL LETTER SHTA
+2C1C; C; 2C4C; # GLAGOLITIC CAPITAL LETTER TSI
+2C1D; C; 2C4D; # GLAGOLITIC CAPITAL LETTER CHRIVI
+2C1E; C; 2C4E; # GLAGOLITIC CAPITAL LETTER SHA
+2C1F; C; 2C4F; # GLAGOLITIC CAPITAL LETTER YERU
+2C20; C; 2C50; # GLAGOLITIC CAPITAL LETTER YERI
+2C21; C; 2C51; # GLAGOLITIC CAPITAL LETTER YATI
+2C22; C; 2C52; # GLAGOLITIC CAPITAL LETTER SPIDERY HA
+2C23; C; 2C53; # GLAGOLITIC CAPITAL LETTER YU
+2C24; C; 2C54; # GLAGOLITIC CAPITAL LETTER SMALL YUS
+2C25; C; 2C55; # GLAGOLITIC CAPITAL LETTER SMALL YUS WITH TAIL
+2C26; C; 2C56; # GLAGOLITIC CAPITAL LETTER YO
+2C27; C; 2C57; # GLAGOLITIC CAPITAL LETTER IOTATED SMALL YUS
+2C28; C; 2C58; # GLAGOLITIC CAPITAL LETTER BIG YUS
+2C29; C; 2C59; # GLAGOLITIC CAPITAL LETTER IOTATED BIG YUS
+2C2A; C; 2C5A; # GLAGOLITIC CAPITAL LETTER FITA
+2C2B; C; 2C5B; # GLAGOLITIC CAPITAL LETTER IZHITSA
+2C2C; C; 2C5C; # GLAGOLITIC CAPITAL LETTER SHTAPIC
+2C2D; C; 2C5D; # GLAGOLITIC CAPITAL LETTER TROKUTASTI A
+2C2E; C; 2C5E; # GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE
+2C2F; C; 2C5F; # GLAGOLITIC CAPITAL LETTER CAUDATE CHRIVI
+2C60; C; 2C61; # LATIN CAPITAL LETTER L WITH DOUBLE BAR
+2C62; C; 026B; # LATIN CAPITAL LETTER L WITH MIDDLE TILDE
+2C63; C; 1D7D; # LATIN CAPITAL LETTER P WITH STROKE
+2C64; C; 027D; # LATIN CAPITAL LETTER R WITH TAIL
+2C67; C; 2C68; # LATIN CAPITAL LETTER H WITH DESCENDER
+2C69; C; 2C6A; # LATIN CAPITAL LETTER K WITH DESCENDER
+2C6B; C; 2C6C; # LATIN CAPITAL LETTER Z WITH DESCENDER
+2C6D; C; 0251; # LATIN CAPITAL LETTER ALPHA
+2C6E; C; 0271; # LATIN CAPITAL LETTER M WITH HOOK
+2C6F; C; 0250; # LATIN CAPITAL LETTER TURNED A
+2C70; C; 0252; # LATIN CAPITAL LETTER TURNED ALPHA
+2C72; C; 2C73; # LATIN CAPITAL LETTER W WITH HOOK
+2C75; C; 2C76; # LATIN CAPITAL LETTER HALF H
+2C7E; C; 023F; # LATIN CAPITAL LETTER S WITH SWASH TAIL
+2C7F; C; 0240; # LATIN CAPITAL LETTER Z WITH SWASH TAIL
+2C80; C; 2C81; # COPTIC CAPITAL LETTER ALFA
+2C82; C; 2C83; # COPTIC CAPITAL LETTER VIDA
+2C84; C; 2C85; # COPTIC CAPITAL LETTER GAMMA
+2C86; C; 2C87; # COPTIC CAPITAL LETTER DALDA
+2C88; C; 2C89; # COPTIC CAPITAL LETTER EIE
+2C8A; C; 2C8B; # COPTIC CAPITAL LETTER SOU
+2C8C; C; 2C8D; # COPTIC CAPITAL LETTER ZATA
+2C8E; C; 2C8F; # COPTIC CAPITAL LETTER HATE
+2C90; C; 2C91; # COPTIC CAPITAL LETTER THETHE
+2C92; C; 2C93; # COPTIC CAPITAL LETTER IAUDA
+2C94; C; 2C95; # COPTIC CAPITAL LETTER KAPA
+2C96; C; 2C97; # COPTIC CAPITAL LETTER LAULA
+2C98; C; 2C99; # COPTIC CAPITAL LETTER MI
+2C9A; C; 2C9B; # COPTIC CAPITAL LETTER NI
+2C9C; C; 2C9D; # COPTIC CAPITAL LETTER KSI
+2C9E; C; 2C9F; # COPTIC CAPITAL LETTER O
+2CA0; C; 2CA1; # COPTIC CAPITAL LETTER PI
+2CA2; C; 2CA3; # COPTIC CAPITAL LETTER RO
+2CA4; C; 2CA5; # COPTIC CAPITAL LETTER SIMA
+2CA6; C; 2CA7; # COPTIC CAPITAL LETTER TAU
+2CA8; C; 2CA9; # COPTIC CAPITAL LETTER UA
+2CAA; C; 2CAB; # COPTIC CAPITAL LETTER FI
+2CAC; C; 2CAD; # COPTIC CAPITAL LETTER KHI
+2CAE; C; 2CAF; # COPTIC CAPITAL LETTER PSI
+2CB0; C; 2CB1; # COPTIC CAPITAL LETTER OOU
+2CB2; C; 2CB3; # COPTIC CAPITAL LETTER DIALECT-P ALEF
+2CB4; C; 2CB5; # COPTIC CAPITAL LETTER OLD COPTIC AIN
+2CB6; C; 2CB7; # COPTIC CAPITAL LETTER CRYPTOGRAMMIC EIE
+2CB8; C; 2CB9; # COPTIC CAPITAL LETTER DIALECT-P KAPA
+2CBA; C; 2CBB; # COPTIC CAPITAL LETTER DIALECT-P NI
+2CBC; C; 2CBD; # COPTIC CAPITAL LETTER CRYPTOGRAMMIC NI
+2CBE; C; 2CBF; # COPTIC CAPITAL LETTER OLD COPTIC OOU
+2CC0; C; 2CC1; # COPTIC CAPITAL LETTER SAMPI
+2CC2; C; 2CC3; # COPTIC CAPITAL LETTER CROSSED SHEI
+2CC4; C; 2CC5; # COPTIC CAPITAL LETTER OLD COPTIC SHEI
+2CC6; C; 2CC7; # COPTIC CAPITAL LETTER OLD COPTIC ESH
+2CC8; C; 2CC9; # COPTIC CAPITAL LETTER AKHMIMIC KHEI
+2CCA; C; 2CCB; # COPTIC CAPITAL LETTER DIALECT-P HORI
+2CCC; C; 2CCD; # COPTIC CAPITAL LETTER OLD COPTIC HORI
+2CCE; C; 2CCF; # COPTIC CAPITAL LETTER OLD COPTIC HA
+2CD0; C; 2CD1; # COPTIC CAPITAL LETTER L-SHAPED HA
+2CD2; C; 2CD3; # COPTIC CAPITAL LETTER OLD COPTIC HEI
+2CD4; C; 2CD5; # COPTIC CAPITAL LETTER OLD COPTIC HAT
+2CD6; C; 2CD7; # COPTIC CAPITAL LETTER OLD COPTIC GANGIA
+2CD8; C; 2CD9; # COPTIC CAPITAL LETTER OLD COPTIC DJA
+2CDA; C; 2CDB; # COPTIC CAPITAL LETTER OLD COPTIC SHIMA
+2CDC; C; 2CDD; # COPTIC CAPITAL LETTER OLD NUBIAN SHIMA
+2CDE; C; 2CDF; # COPTIC CAPITAL LETTER OLD NUBIAN NGI
+2CE0; C; 2CE1; # COPTIC CAPITAL LETTER OLD NUBIAN NYI
+2CE2; C; 2CE3; # COPTIC CAPITAL LETTER OLD NUBIAN WAU
+2CEB; C; 2CEC; # COPTIC CAPITAL LETTER CRYPTOGRAMMIC SHEI
+2CED; C; 2CEE; # COPTIC CAPITAL LETTER CRYPTOGRAMMIC GANGIA
+2CF2; C; 2CF3; # COPTIC CAPITAL LETTER BOHAIRIC KHEI
+A640; C; A641; # CYRILLIC CAPITAL LETTER ZEMLYA
+A642; C; A643; # CYRILLIC CAPITAL LETTER DZELO
+A644; C; A645; # CYRILLIC CAPITAL LETTER REVERSED DZE
+A646; C; A647; # CYRILLIC CAPITAL LETTER IOTA
+A648; C; A649; # CYRILLIC CAPITAL LETTER DJERV
+A64A; C; A64B; # CYRILLIC CAPITAL LETTER MONOGRAPH UK
+A64C; C; A64D; # CYRILLIC CAPITAL LETTER BROAD OMEGA
+A64E; C; A64F; # CYRILLIC CAPITAL LETTER NEUTRAL YER
+A650; C; A651; # CYRILLIC CAPITAL LETTER YERU WITH BACK YER
+A652; C; A653; # CYRILLIC CAPITAL LETTER IOTIFIED YAT
+A654; C; A655; # CYRILLIC CAPITAL LETTER REVERSED YU
+A656; C; A657; # CYRILLIC CAPITAL LETTER IOTIFIED A
+A658; C; A659; # CYRILLIC CAPITAL LETTER CLOSED LITTLE YUS
+A65A; C; A65B; # CYRILLIC CAPITAL LETTER BLENDED YUS
+A65C; C; A65D; # CYRILLIC CAPITAL LETTER IOTIFIED CLOSED LITTLE YUS
+A65E; C; A65F; # CYRILLIC CAPITAL LETTER YN
+A660; C; A661; # CYRILLIC CAPITAL LETTER REVERSED TSE
+A662; C; A663; # CYRILLIC CAPITAL LETTER SOFT DE
+A664; C; A665; # CYRILLIC CAPITAL LETTER SOFT EL
+A666; C; A667; # CYRILLIC CAPITAL LETTER SOFT EM
+A668; C; A669; # CYRILLIC CAPITAL LETTER MONOCULAR O
+A66A; C; A66B; # CYRILLIC CAPITAL LETTER BINOCULAR O
+A66C; C; A66D; # CYRILLIC CAPITAL LETTER DOUBLE MONOCULAR O
+A680; C; A681; # CYRILLIC CAPITAL LETTER DWE
+A682; C; A683; # CYRILLIC CAPITAL LETTER DZWE
+A684; C; A685; # CYRILLIC CAPITAL LETTER ZHWE
+A686; C; A687; # CYRILLIC CAPITAL LETTER CCHE
+A688; C; A689; # CYRILLIC CAPITAL LETTER DZZE
+A68A; C; A68B; # CYRILLIC CAPITAL LETTER TE WITH MIDDLE HOOK
+A68C; C; A68D; # CYRILLIC CAPITAL LETTER TWE
+A68E; C; A68F; # CYRILLIC CAPITAL LETTER TSWE
+A690; C; A691; # CYRILLIC CAPITAL LETTER TSSE
+A692; C; A693; # CYRILLIC CAPITAL LETTER TCHE
+A694; C; A695; # CYRILLIC CAPITAL LETTER HWE
+A696; C; A697; # CYRILLIC CAPITAL LETTER SHWE
+A698; C; A699; # CYRILLIC CAPITAL LETTER DOUBLE O
+A69A; C; A69B; # CYRILLIC CAPITAL LETTER CROSSED O
+A722; C; A723; # LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF
+A724; C; A725; # LATIN CAPITAL LETTER EGYPTOLOGICAL AIN
+A726; C; A727; # LATIN CAPITAL LETTER HENG
+A728; C; A729; # LATIN CAPITAL LETTER TZ
+A72A; C; A72B; # LATIN CAPITAL LETTER TRESILLO
+A72C; C; A72D; # LATIN CAPITAL LETTER CUATRILLO
+A72E; C; A72F; # LATIN CAPITAL LETTER CUATRILLO WITH COMMA
+A732; C; A733; # LATIN CAPITAL LETTER AA
+A734; C; A735; # LATIN CAPITAL LETTER AO
+A736; C; A737; # LATIN CAPITAL LETTER AU
+A738; C; A739; # LATIN CAPITAL LETTER AV
+A73A; C; A73B; # LATIN CAPITAL LETTER AV WITH HORIZONTAL BAR
+A73C; C; A73D; # LATIN CAPITAL LETTER AY
+A73E; C; A73F; # LATIN CAPITAL LETTER REVERSED C WITH DOT
+A740; C; A741; # LATIN CAPITAL LETTER K WITH STROKE
+A742; C; A743; # LATIN CAPITAL LETTER K WITH DIAGONAL STROKE
+A744; C; A745; # LATIN CAPITAL LETTER K WITH STROKE AND DIAGONAL STROKE
+A746; C; A747; # LATIN CAPITAL LETTER BROKEN L
+A748; C; A749; # LATIN CAPITAL LETTER L WITH HIGH STROKE
+A74A; C; A74B; # LATIN CAPITAL LETTER O WITH LONG STROKE OVERLAY
+A74C; C; A74D; # LATIN CAPITAL LETTER O WITH LOOP
+A74E; C; A74F; # LATIN CAPITAL LETTER OO
+A750; C; A751; # LATIN CAPITAL LETTER P WITH STROKE THROUGH DESCENDER
+A752; C; A753; # LATIN CAPITAL LETTER P WITH FLOURISH
+A754; C; A755; # LATIN CAPITAL LETTER P WITH SQUIRREL TAIL
+A756; C; A757; # LATIN CAPITAL LETTER Q WITH STROKE THROUGH DESCENDER
+A758; C; A759; # LATIN CAPITAL LETTER Q WITH DIAGONAL STROKE
+A75A; C; A75B; # LATIN CAPITAL LETTER R ROTUNDA
+A75C; C; A75D; # LATIN CAPITAL LETTER RUM ROTUNDA
+A75E; C; A75F; # LATIN CAPITAL LETTER V WITH DIAGONAL STROKE
+A760; C; A761; # LATIN CAPITAL LETTER VY
+A762; C; A763; # LATIN CAPITAL LETTER VISIGOTHIC Z
+A764; C; A765; # LATIN CAPITAL LETTER THORN WITH STROKE
+A766; C; A767; # LATIN CAPITAL LETTER THORN WITH STROKE THROUGH DESCENDER
+A768; C; A769; # LATIN CAPITAL LETTER VEND
+A76A; C; A76B; # LATIN CAPITAL LETTER ET
+A76C; C; A76D; # LATIN CAPITAL LETTER IS
+A76E; C; A76F; # LATIN CAPITAL LETTER CON
+A779; C; A77A; # LATIN CAPITAL LETTER INSULAR D
+A77B; C; A77C; # LATIN CAPITAL LETTER INSULAR F
+A77D; C; 1D79; # LATIN CAPITAL LETTER INSULAR G
+A77E; C; A77F; # LATIN CAPITAL LETTER TURNED INSULAR G
+A780; C; A781; # LATIN CAPITAL LETTER TURNED L
+A782; C; A783; # LATIN CAPITAL LETTER INSULAR R
+A784; C; A785; # LATIN CAPITAL LETTER INSULAR S
+A786; C; A787; # LATIN CAPITAL LETTER INSULAR T
+A78B; C; A78C; # LATIN CAPITAL LETTER SALTILLO
+A78D; C; 0265; # LATIN CAPITAL LETTER TURNED H
+A790; C; A791; # LATIN CAPITAL LETTER N WITH DESCENDER
+A792; C; A793; # LATIN CAPITAL LETTER C WITH BAR
+A796; C; A797; # LATIN CAPITAL LETTER B WITH FLOURISH
+A798; C; A799; # LATIN CAPITAL LETTER F WITH STROKE
+A79A; C; A79B; # LATIN CAPITAL LETTER VOLAPUK AE
+A79C; C; A79D; # LATIN CAPITAL LETTER VOLAPUK OE
+A79E; C; A79F; # LATIN CAPITAL LETTER VOLAPUK UE
+A7A0; C; A7A1; # LATIN CAPITAL LETTER G WITH OBLIQUE STROKE
+A7A2; C; A7A3; # LATIN CAPITAL LETTER K WITH OBLIQUE STROKE
+A7A4; C; A7A5; # LATIN CAPITAL LETTER N WITH OBLIQUE STROKE
+A7A6; C; A7A7; # LATIN CAPITAL LETTER R WITH OBLIQUE STROKE
+A7A8; C; A7A9; # LATIN CAPITAL LETTER S WITH OBLIQUE STROKE
+A7AA; C; 0266; # LATIN CAPITAL LETTER H WITH HOOK
+A7AB; C; 025C; # LATIN CAPITAL LETTER REVERSED OPEN E
+A7AC; C; 0261; # LATIN CAPITAL LETTER SCRIPT G
+A7AD; C; 026C; # LATIN CAPITAL LETTER L WITH BELT
+A7AE; C; 026A; # LATIN CAPITAL LETTER SMALL CAPITAL I
+A7B0; C; 029E; # LATIN CAPITAL LETTER TURNED K
+A7B1; C; 0287; # LATIN CAPITAL LETTER TURNED T
+A7B2; C; 029D; # LATIN CAPITAL LETTER J WITH CROSSED-TAIL
+A7B3; C; AB53; # LATIN CAPITAL LETTER CHI
+A7B4; C; A7B5; # LATIN CAPITAL LETTER BETA
+A7B6; C; A7B7; # LATIN CAPITAL LETTER OMEGA
+A7B8; C; A7B9; # LATIN CAPITAL LETTER U WITH STROKE
+A7BA; C; A7BB; # LATIN CAPITAL LETTER GLOTTAL A
+A7BC; C; A7BD; # LATIN CAPITAL LETTER GLOTTAL I
+A7BE; C; A7BF; # LATIN CAPITAL LETTER GLOTTAL U
+A7C0; C; A7C1; # LATIN CAPITAL LETTER OLD POLISH O
+A7C2; C; A7C3; # LATIN CAPITAL LETTER ANGLICANA W
+A7C4; C; A794; # LATIN CAPITAL LETTER C WITH PALATAL HOOK
+A7C5; C; 0282; # LATIN CAPITAL LETTER S WITH HOOK
+A7C6; C; 1D8E; # LATIN CAPITAL LETTER Z WITH PALATAL HOOK
+A7C7; C; A7C8; # LATIN CAPITAL LETTER D WITH SHORT STROKE OVERLAY
+A7C9; C; A7CA; # LATIN CAPITAL LETTER S WITH SHORT STROKE OVERLAY
+A7D0; C; A7D1; # LATIN CAPITAL LETTER CLOSED INSULAR G
+A7D6; C; A7D7; # LATIN CAPITAL LETTER MIDDLE SCOTS S
+A7D8; C; A7D9; # LATIN CAPITAL LETTER SIGMOID S
+A7F5; C; A7F6; # LATIN CAPITAL LETTER REVERSED HALF H
+AB70; C; 13A0; # CHEROKEE SMALL LETTER A
+AB71; C; 13A1; # CHEROKEE SMALL LETTER E
+AB72; C; 13A2; # CHEROKEE SMALL LETTER I
+AB73; C; 13A3; # CHEROKEE SMALL LETTER O
+AB74; C; 13A4; # CHEROKEE SMALL LETTER U
+AB75; C; 13A5; # CHEROKEE SMALL LETTER V
+AB76; C; 13A6; # CHEROKEE SMALL LETTER GA
+AB77; C; 13A7; # CHEROKEE SMALL LETTER KA
+AB78; C; 13A8; # CHEROKEE SMALL LETTER GE
+AB79; C; 13A9; # CHEROKEE SMALL LETTER GI
+AB7A; C; 13AA; # CHEROKEE SMALL LETTER GO
+AB7B; C; 13AB; # CHEROKEE SMALL LETTER GU
+AB7C; C; 13AC; # CHEROKEE SMALL LETTER GV
+AB7D; C; 13AD; # CHEROKEE SMALL LETTER HA
+AB7E; C; 13AE; # CHEROKEE SMALL LETTER HE
+AB7F; C; 13AF; # CHEROKEE SMALL LETTER HI
+AB80; C; 13B0; # CHEROKEE SMALL LETTER HO
+AB81; C; 13B1; # CHEROKEE SMALL LETTER HU
+AB82; C; 13B2; # CHEROKEE SMALL LETTER HV
+AB83; C; 13B3; # CHEROKEE SMALL LETTER LA
+AB84; C; 13B4; # CHEROKEE SMALL LETTER LE
+AB85; C; 13B5; # CHEROKEE SMALL LETTER LI
+AB86; C; 13B6; # CHEROKEE SMALL LETTER LO
+AB87; C; 13B7; # CHEROKEE SMALL LETTER LU
+AB88; C; 13B8; # CHEROKEE SMALL LETTER LV
+AB89; C; 13B9; # CHEROKEE SMALL LETTER MA
+AB8A; C; 13BA; # CHEROKEE SMALL LETTER ME
+AB8B; C; 13BB; # CHEROKEE SMALL LETTER MI
+AB8C; C; 13BC; # CHEROKEE SMALL LETTER MO
+AB8D; C; 13BD; # CHEROKEE SMALL LETTER MU
+AB8E; C; 13BE; # CHEROKEE SMALL LETTER NA
+AB8F; C; 13BF; # CHEROKEE SMALL LETTER HNA
+AB90; C; 13C0; # CHEROKEE SMALL LETTER NAH
+AB91; C; 13C1; # CHEROKEE SMALL LETTER NE
+AB92; C; 13C2; # CHEROKEE SMALL LETTER NI
+AB93; C; 13C3; # CHEROKEE SMALL LETTER NO
+AB94; C; 13C4; # CHEROKEE SMALL LETTER NU
+AB95; C; 13C5; # CHEROKEE SMALL LETTER NV
+AB96; C; 13C6; # CHEROKEE SMALL LETTER QUA
+AB97; C; 13C7; # CHEROKEE SMALL LETTER QUE
+AB98; C; 13C8; # CHEROKEE SMALL LETTER QUI
+AB99; C; 13C9; # CHEROKEE SMALL LETTER QUO
+AB9A; C; 13CA; # CHEROKEE SMALL LETTER QUU
+AB9B; C; 13CB; # CHEROKEE SMALL LETTER QUV
+AB9C; C; 13CC; # CHEROKEE SMALL LETTER SA
+AB9D; C; 13CD; # CHEROKEE SMALL LETTER S
+AB9E; C; 13CE; # CHEROKEE SMALL LETTER SE
+AB9F; C; 13CF; # CHEROKEE SMALL LETTER SI
+ABA0; C; 13D0; # CHEROKEE SMALL LETTER SO
+ABA1; C; 13D1; # CHEROKEE SMALL LETTER SU
+ABA2; C; 13D2; # CHEROKEE SMALL LETTER SV
+ABA3; C; 13D3; # CHEROKEE SMALL LETTER DA
+ABA4; C; 13D4; # CHEROKEE SMALL LETTER TA
+ABA5; C; 13D5; # CHEROKEE SMALL LETTER DE
+ABA6; C; 13D6; # CHEROKEE SMALL LETTER TE
+ABA7; C; 13D7; # CHEROKEE SMALL LETTER DI
+ABA8; C; 13D8; # CHEROKEE SMALL LETTER TI
+ABA9; C; 13D9; # CHEROKEE SMALL LETTER DO
+ABAA; C; 13DA; # CHEROKEE SMALL LETTER DU
+ABAB; C; 13DB; # CHEROKEE SMALL LETTER DV
+ABAC; C; 13DC; # CHEROKEE SMALL LETTER DLA
+ABAD; C; 13DD; # CHEROKEE SMALL LETTER TLA
+ABAE; C; 13DE; # CHEROKEE SMALL LETTER TLE
+ABAF; C; 13DF; # CHEROKEE SMALL LETTER TLI
+ABB0; C; 13E0; # CHEROKEE SMALL LETTER TLO
+ABB1; C; 13E1; # CHEROKEE SMALL LETTER TLU
+ABB2; C; 13E2; # CHEROKEE SMALL LETTER TLV
+ABB3; C; 13E3; # CHEROKEE SMALL LETTER TSA
+ABB4; C; 13E4; # CHEROKEE SMALL LETTER TSE
+ABB5; C; 13E5; # CHEROKEE SMALL LETTER TSI
+ABB6; C; 13E6; # CHEROKEE SMALL LETTER TSO
+ABB7; C; 13E7; # CHEROKEE SMALL LETTER TSU
+ABB8; C; 13E8; # CHEROKEE SMALL LETTER TSV
+ABB9; C; 13E9; # CHEROKEE SMALL LETTER WA
+ABBA; C; 13EA; # CHEROKEE SMALL LETTER WE
+ABBB; C; 13EB; # CHEROKEE SMALL LETTER WI
+ABBC; C; 13EC; # CHEROKEE SMALL LETTER WO
+ABBD; C; 13ED; # CHEROKEE SMALL LETTER WU
+ABBE; C; 13EE; # CHEROKEE SMALL LETTER WV
+ABBF; C; 13EF; # CHEROKEE SMALL LETTER YA
+FB00; F; 0066 0066; # LATIN SMALL LIGATURE FF
+FB01; F; 0066 0069; # LATIN SMALL LIGATURE FI
+FB02; F; 0066 006C; # LATIN SMALL LIGATURE FL
+FB03; F; 0066 0066 0069; # LATIN SMALL LIGATURE FFI
+FB04; F; 0066 0066 006C; # LATIN SMALL LIGATURE FFL
+FB05; F; 0073 0074; # LATIN SMALL LIGATURE LONG S T
+FB06; F; 0073 0074; # LATIN SMALL LIGATURE ST
+FB13; F; 0574 0576; # ARMENIAN SMALL LIGATURE MEN NOW
+FB14; F; 0574 0565; # ARMENIAN SMALL LIGATURE MEN ECH
+FB15; F; 0574 056B; # ARMENIAN SMALL LIGATURE MEN INI
+FB16; F; 057E 0576; # ARMENIAN SMALL LIGATURE VEW NOW
+FB17; F; 0574 056D; # ARMENIAN SMALL LIGATURE MEN XEH
+FF21; C; FF41; # FULLWIDTH LATIN CAPITAL LETTER A
+FF22; C; FF42; # FULLWIDTH LATIN CAPITAL LETTER B
+FF23; C; FF43; # FULLWIDTH LATIN CAPITAL LETTER C
+FF24; C; FF44; # FULLWIDTH LATIN CAPITAL LETTER D
+FF25; C; FF45; # FULLWIDTH LATIN CAPITAL LETTER E
+FF26; C; FF46; # FULLWIDTH LATIN CAPITAL LETTER F
+FF27; C; FF47; # FULLWIDTH LATIN CAPITAL LETTER G
+FF28; C; FF48; # FULLWIDTH LATIN CAPITAL LETTER H
+FF29; C; FF49; # FULLWIDTH LATIN CAPITAL LETTER I
+FF2A; C; FF4A; # FULLWIDTH LATIN CAPITAL LETTER J
+FF2B; C; FF4B; # FULLWIDTH LATIN CAPITAL LETTER K
+FF2C; C; FF4C; # FULLWIDTH LATIN CAPITAL LETTER L
+FF2D; C; FF4D; # FULLWIDTH LATIN CAPITAL LETTER M
+FF2E; C; FF4E; # FULLWIDTH LATIN CAPITAL LETTER N
+FF2F; C; FF4F; # FULLWIDTH LATIN CAPITAL LETTER O
+FF30; C; FF50; # FULLWIDTH LATIN CAPITAL LETTER P
+FF31; C; FF51; # FULLWIDTH LATIN CAPITAL LETTER Q
+FF32; C; FF52; # FULLWIDTH LATIN CAPITAL LETTER R
+FF33; C; FF53; # FULLWIDTH LATIN CAPITAL LETTER S
+FF34; C; FF54; # FULLWIDTH LATIN CAPITAL LETTER T
+FF35; C; FF55; # FULLWIDTH LATIN CAPITAL LETTER U
+FF36; C; FF56; # FULLWIDTH LATIN CAPITAL LETTER V
+FF37; C; FF57; # FULLWIDTH LATIN CAPITAL LETTER W
+FF38; C; FF58; # FULLWIDTH LATIN CAPITAL LETTER X
+FF39; C; FF59; # FULLWIDTH LATIN CAPITAL LETTER Y
+FF3A; C; FF5A; # FULLWIDTH LATIN CAPITAL LETTER Z
+10400; C; 10428; # DESERET CAPITAL LETTER LONG I
+10401; C; 10429; # DESERET CAPITAL LETTER LONG E
+10402; C; 1042A; # DESERET CAPITAL LETTER LONG A
+10403; C; 1042B; # DESERET CAPITAL LETTER LONG AH
+10404; C; 1042C; # DESERET CAPITAL LETTER LONG O
+10405; C; 1042D; # DESERET CAPITAL LETTER LONG OO
+10406; C; 1042E; # DESERET CAPITAL LETTER SHORT I
+10407; C; 1042F; # DESERET CAPITAL LETTER SHORT E
+10408; C; 10430; # DESERET CAPITAL LETTER SHORT A
+10409; C; 10431; # DESERET CAPITAL LETTER SHORT AH
+1040A; C; 10432; # DESERET CAPITAL LETTER SHORT O
+1040B; C; 10433; # DESERET CAPITAL LETTER SHORT OO
+1040C; C; 10434; # DESERET CAPITAL LETTER AY
+1040D; C; 10435; # DESERET CAPITAL LETTER OW
+1040E; C; 10436; # DESERET CAPITAL LETTER WU
+1040F; C; 10437; # DESERET CAPITAL LETTER YEE
+10410; C; 10438; # DESERET CAPITAL LETTER H
+10411; C; 10439; # DESERET CAPITAL LETTER PEE
+10412; C; 1043A; # DESERET CAPITAL LETTER BEE
+10413; C; 1043B; # DESERET CAPITAL LETTER TEE
+10414; C; 1043C; # DESERET CAPITAL LETTER DEE
+10415; C; 1043D; # DESERET CAPITAL LETTER CHEE
+10416; C; 1043E; # DESERET CAPITAL LETTER JEE
+10417; C; 1043F; # DESERET CAPITAL LETTER KAY
+10418; C; 10440; # DESERET CAPITAL LETTER GAY
+10419; C; 10441; # DESERET CAPITAL LETTER EF
+1041A; C; 10442; # DESERET CAPITAL LETTER VEE
+1041B; C; 10443; # DESERET CAPITAL LETTER ETH
+1041C; C; 10444; # DESERET CAPITAL LETTER THEE
+1041D; C; 10445; # DESERET CAPITAL LETTER ES
+1041E; C; 10446; # DESERET CAPITAL LETTER ZEE
+1041F; C; 10447; # DESERET CAPITAL LETTER ESH
+10420; C; 10448; # DESERET CAPITAL LETTER ZHEE
+10421; C; 10449; # DESERET CAPITAL LETTER ER
+10422; C; 1044A; # DESERET CAPITAL LETTER EL
+10423; C; 1044B; # DESERET CAPITAL LETTER EM
+10424; C; 1044C; # DESERET CAPITAL LETTER EN
+10425; C; 1044D; # DESERET CAPITAL LETTER ENG
+10426; C; 1044E; # DESERET CAPITAL LETTER OI
+10427; C; 1044F; # DESERET CAPITAL LETTER EW
+104B0; C; 104D8; # OSAGE CAPITAL LETTER A
+104B1; C; 104D9; # OSAGE CAPITAL LETTER AI
+104B2; C; 104DA; # OSAGE CAPITAL LETTER AIN
+104B3; C; 104DB; # OSAGE CAPITAL LETTER AH
+104B4; C; 104DC; # OSAGE CAPITAL LETTER BRA
+104B5; C; 104DD; # OSAGE CAPITAL LETTER CHA
+104B6; C; 104DE; # OSAGE CAPITAL LETTER EHCHA
+104B7; C; 104DF; # OSAGE CAPITAL LETTER E
+104B8; C; 104E0; # OSAGE CAPITAL LETTER EIN
+104B9; C; 104E1; # OSAGE CAPITAL LETTER HA
+104BA; C; 104E2; # OSAGE CAPITAL LETTER HYA
+104BB; C; 104E3; # OSAGE CAPITAL LETTER I
+104BC; C; 104E4; # OSAGE CAPITAL LETTER KA
+104BD; C; 104E5; # OSAGE CAPITAL LETTER EHKA
+104BE; C; 104E6; # OSAGE CAPITAL LETTER KYA
+104BF; C; 104E7; # OSAGE CAPITAL LETTER LA
+104C0; C; 104E8; # OSAGE CAPITAL LETTER MA
+104C1; C; 104E9; # OSAGE CAPITAL LETTER NA
+104C2; C; 104EA; # OSAGE CAPITAL LETTER O
+104C3; C; 104EB; # OSAGE CAPITAL LETTER OIN
+104C4; C; 104EC; # OSAGE CAPITAL LETTER PA
+104C5; C; 104ED; # OSAGE CAPITAL LETTER EHPA
+104C6; C; 104EE; # OSAGE CAPITAL LETTER SA
+104C7; C; 104EF; # OSAGE CAPITAL LETTER SHA
+104C8; C; 104F0; # OSAGE CAPITAL LETTER TA
+104C9; C; 104F1; # OSAGE CAPITAL LETTER EHTA
+104CA; C; 104F2; # OSAGE CAPITAL LETTER TSA
+104CB; C; 104F3; # OSAGE CAPITAL LETTER EHTSA
+104CC; C; 104F4; # OSAGE CAPITAL LETTER TSHA
+104CD; C; 104F5; # OSAGE CAPITAL LETTER DHA
+104CE; C; 104F6; # OSAGE CAPITAL LETTER U
+104CF; C; 104F7; # OSAGE CAPITAL LETTER WA
+104D0; C; 104F8; # OSAGE CAPITAL LETTER KHA
+104D1; C; 104F9; # OSAGE CAPITAL LETTER GHA
+104D2; C; 104FA; # OSAGE CAPITAL LETTER ZA
+104D3; C; 104FB; # OSAGE CAPITAL LETTER ZHA
+10570; C; 10597; # VITHKUQI CAPITAL LETTER A
+10571; C; 10598; # VITHKUQI CAPITAL LETTER BBE
+10572; C; 10599; # VITHKUQI CAPITAL LETTER BE
+10573; C; 1059A; # VITHKUQI CAPITAL LETTER CE
+10574; C; 1059B; # VITHKUQI CAPITAL LETTER CHE
+10575; C; 1059C; # VITHKUQI CAPITAL LETTER DE
+10576; C; 1059D; # VITHKUQI CAPITAL LETTER DHE
+10577; C; 1059E; # VITHKUQI CAPITAL LETTER EI
+10578; C; 1059F; # VITHKUQI CAPITAL LETTER E
+10579; C; 105A0; # VITHKUQI CAPITAL LETTER FE
+1057A; C; 105A1; # VITHKUQI CAPITAL LETTER GA
+1057C; C; 105A3; # VITHKUQI CAPITAL LETTER HA
+1057D; C; 105A4; # VITHKUQI CAPITAL LETTER HHA
+1057E; C; 105A5; # VITHKUQI CAPITAL LETTER I
+1057F; C; 105A6; # VITHKUQI CAPITAL LETTER IJE
+10580; C; 105A7; # VITHKUQI CAPITAL LETTER JE
+10581; C; 105A8; # VITHKUQI CAPITAL LETTER KA
+10582; C; 105A9; # VITHKUQI CAPITAL LETTER LA
+10583; C; 105AA; # VITHKUQI CAPITAL LETTER LLA
+10584; C; 105AB; # VITHKUQI CAPITAL LETTER ME
+10585; C; 105AC; # VITHKUQI CAPITAL LETTER NE
+10586; C; 105AD; # VITHKUQI CAPITAL LETTER NJE
+10587; C; 105AE; # VITHKUQI CAPITAL LETTER O
+10588; C; 105AF; # VITHKUQI CAPITAL LETTER PE
+10589; C; 105B0; # VITHKUQI CAPITAL LETTER QA
+1058A; C; 105B1; # VITHKUQI CAPITAL LETTER RE
+1058C; C; 105B3; # VITHKUQI CAPITAL LETTER SE
+1058D; C; 105B4; # VITHKUQI CAPITAL LETTER SHE
+1058E; C; 105B5; # VITHKUQI CAPITAL LETTER TE
+1058F; C; 105B6; # VITHKUQI CAPITAL LETTER THE
+10590; C; 105B7; # VITHKUQI CAPITAL LETTER U
+10591; C; 105B8; # VITHKUQI CAPITAL LETTER VE
+10592; C; 105B9; # VITHKUQI CAPITAL LETTER XE
+10594; C; 105BB; # VITHKUQI CAPITAL LETTER Y
+10595; C; 105BC; # VITHKUQI CAPITAL LETTER ZE
+10C80; C; 10CC0; # OLD HUNGARIAN CAPITAL LETTER A
+10C81; C; 10CC1; # OLD HUNGARIAN CAPITAL LETTER AA
+10C82; C; 10CC2; # OLD HUNGARIAN CAPITAL LETTER EB
+10C83; C; 10CC3; # OLD HUNGARIAN CAPITAL LETTER AMB
+10C84; C; 10CC4; # OLD HUNGARIAN CAPITAL LETTER EC
+10C85; C; 10CC5; # OLD HUNGARIAN CAPITAL LETTER ENC
+10C86; C; 10CC6; # OLD HUNGARIAN CAPITAL LETTER ECS
+10C87; C; 10CC7; # OLD HUNGARIAN CAPITAL LETTER ED
+10C88; C; 10CC8; # OLD HUNGARIAN CAPITAL LETTER AND
+10C89; C; 10CC9; # OLD HUNGARIAN CAPITAL LETTER E
+10C8A; C; 10CCA; # OLD HUNGARIAN CAPITAL LETTER CLOSE E
+10C8B; C; 10CCB; # OLD HUNGARIAN CAPITAL LETTER EE
+10C8C; C; 10CCC; # OLD HUNGARIAN CAPITAL LETTER EF
+10C8D; C; 10CCD; # OLD HUNGARIAN CAPITAL LETTER EG
+10C8E; C; 10CCE; # OLD HUNGARIAN CAPITAL LETTER EGY
+10C8F; C; 10CCF; # OLD HUNGARIAN CAPITAL LETTER EH
+10C90; C; 10CD0; # OLD HUNGARIAN CAPITAL LETTER I
+10C91; C; 10CD1; # OLD HUNGARIAN CAPITAL LETTER II
+10C92; C; 10CD2; # OLD HUNGARIAN CAPITAL LETTER EJ
+10C93; C; 10CD3; # OLD HUNGARIAN CAPITAL LETTER EK
+10C94; C; 10CD4; # OLD HUNGARIAN CAPITAL LETTER AK
+10C95; C; 10CD5; # OLD HUNGARIAN CAPITAL LETTER UNK
+10C96; C; 10CD6; # OLD HUNGARIAN CAPITAL LETTER EL
+10C97; C; 10CD7; # OLD HUNGARIAN CAPITAL LETTER ELY
+10C98; C; 10CD8; # OLD HUNGARIAN CAPITAL LETTER EM
+10C99; C; 10CD9; # OLD HUNGARIAN CAPITAL LETTER EN
+10C9A; C; 10CDA; # OLD HUNGARIAN CAPITAL LETTER ENY
+10C9B; C; 10CDB; # OLD HUNGARIAN CAPITAL LETTER O
+10C9C; C; 10CDC; # OLD HUNGARIAN CAPITAL LETTER OO
+10C9D; C; 10CDD; # OLD HUNGARIAN CAPITAL LETTER NIKOLSBURG OE
+10C9E; C; 10CDE; # OLD HUNGARIAN CAPITAL LETTER RUDIMENTA OE
+10C9F; C; 10CDF; # OLD HUNGARIAN CAPITAL LETTER OEE
+10CA0; C; 10CE0; # OLD HUNGARIAN CAPITAL LETTER EP
+10CA1; C; 10CE1; # OLD HUNGARIAN CAPITAL LETTER EMP
+10CA2; C; 10CE2; # OLD HUNGARIAN CAPITAL LETTER ER
+10CA3; C; 10CE3; # OLD HUNGARIAN CAPITAL LETTER SHORT ER
+10CA4; C; 10CE4; # OLD HUNGARIAN CAPITAL LETTER ES
+10CA5; C; 10CE5; # OLD HUNGARIAN CAPITAL LETTER ESZ
+10CA6; C; 10CE6; # OLD HUNGARIAN CAPITAL LETTER ET
+10CA7; C; 10CE7; # OLD HUNGARIAN CAPITAL LETTER ENT
+10CA8; C; 10CE8; # OLD HUNGARIAN CAPITAL LETTER ETY
+10CA9; C; 10CE9; # OLD HUNGARIAN CAPITAL LETTER ECH
+10CAA; C; 10CEA; # OLD HUNGARIAN CAPITAL LETTER U
+10CAB; C; 10CEB; # OLD HUNGARIAN CAPITAL LETTER UU
+10CAC; C; 10CEC; # OLD HUNGARIAN CAPITAL LETTER NIKOLSBURG UE
+10CAD; C; 10CED; # OLD HUNGARIAN CAPITAL LETTER RUDIMENTA UE
+10CAE; C; 10CEE; # OLD HUNGARIAN CAPITAL LETTER EV
+10CAF; C; 10CEF; # OLD HUNGARIAN CAPITAL LETTER EZ
+10CB0; C; 10CF0; # OLD HUNGARIAN CAPITAL LETTER EZS
+10CB1; C; 10CF1; # OLD HUNGARIAN CAPITAL LETTER ENT-SHAPED SIGN
+10CB2; C; 10CF2; # OLD HUNGARIAN CAPITAL LETTER US
+118A0; C; 118C0; # WARANG CITI CAPITAL LETTER NGAA
+118A1; C; 118C1; # WARANG CITI CAPITAL LETTER A
+118A2; C; 118C2; # WARANG CITI CAPITAL LETTER WI
+118A3; C; 118C3; # WARANG CITI CAPITAL LETTER YU
+118A4; C; 118C4; # WARANG CITI CAPITAL LETTER YA
+118A5; C; 118C5; # WARANG CITI CAPITAL LETTER YO
+118A6; C; 118C6; # WARANG CITI CAPITAL LETTER II
+118A7; C; 118C7; # WARANG CITI CAPITAL LETTER UU
+118A8; C; 118C8; # WARANG CITI CAPITAL LETTER E
+118A9; C; 118C9; # WARANG CITI CAPITAL LETTER O
+118AA; C; 118CA; # WARANG CITI CAPITAL LETTER ANG
+118AB; C; 118CB; # WARANG CITI CAPITAL LETTER GA
+118AC; C; 118CC; # WARANG CITI CAPITAL LETTER KO
+118AD; C; 118CD; # WARANG CITI CAPITAL LETTER ENY
+118AE; C; 118CE; # WARANG CITI CAPITAL LETTER YUJ
+118AF; C; 118CF; # WARANG CITI CAPITAL LETTER UC
+118B0; C; 118D0; # WARANG CITI CAPITAL LETTER ENN
+118B1; C; 118D1; # WARANG CITI CAPITAL LETTER ODD
+118B2; C; 118D2; # WARANG CITI CAPITAL LETTER TTE
+118B3; C; 118D3; # WARANG CITI CAPITAL LETTER NUNG
+118B4; C; 118D4; # WARANG CITI CAPITAL LETTER DA
+118B5; C; 118D5; # WARANG CITI CAPITAL LETTER AT
+118B6; C; 118D6; # WARANG CITI CAPITAL LETTER AM
+118B7; C; 118D7; # WARANG CITI CAPITAL LETTER BU
+118B8; C; 118D8; # WARANG CITI CAPITAL LETTER PU
+118B9; C; 118D9; # WARANG CITI CAPITAL LETTER HIYO
+118BA; C; 118DA; # WARANG CITI CAPITAL LETTER HOLO
+118BB; C; 118DB; # WARANG CITI CAPITAL LETTER HORR
+118BC; C; 118DC; # WARANG CITI CAPITAL LETTER HAR
+118BD; C; 118DD; # WARANG CITI CAPITAL LETTER SSUU
+118BE; C; 118DE; # WARANG CITI CAPITAL LETTER SII
+118BF; C; 118DF; # WARANG CITI CAPITAL LETTER VIYO
+16E40; C; 16E60; # MEDEFAIDRIN CAPITAL LETTER M
+16E41; C; 16E61; # MEDEFAIDRIN CAPITAL LETTER S
+16E42; C; 16E62; # MEDEFAIDRIN CAPITAL LETTER V
+16E43; C; 16E63; # MEDEFAIDRIN CAPITAL LETTER W
+16E44; C; 16E64; # MEDEFAIDRIN CAPITAL LETTER ATIU
+16E45; C; 16E65; # MEDEFAIDRIN CAPITAL LETTER Z
+16E46; C; 16E66; # MEDEFAIDRIN CAPITAL LETTER KP
+16E47; C; 16E67; # MEDEFAIDRIN CAPITAL LETTER P
+16E48; C; 16E68; # MEDEFAIDRIN CAPITAL LETTER T
+16E49; C; 16E69; # MEDEFAIDRIN CAPITAL LETTER G
+16E4A; C; 16E6A; # MEDEFAIDRIN CAPITAL LETTER F
+16E4B; C; 16E6B; # MEDEFAIDRIN CAPITAL LETTER I
+16E4C; C; 16E6C; # MEDEFAIDRIN CAPITAL LETTER K
+16E4D; C; 16E6D; # MEDEFAIDRIN CAPITAL LETTER A
+16E4E; C; 16E6E; # MEDEFAIDRIN CAPITAL LETTER J
+16E4F; C; 16E6F; # MEDEFAIDRIN CAPITAL LETTER E
+16E50; C; 16E70; # MEDEFAIDRIN CAPITAL LETTER B
+16E51; C; 16E71; # MEDEFAIDRIN CAPITAL LETTER C
+16E52; C; 16E72; # MEDEFAIDRIN CAPITAL LETTER U
+16E53; C; 16E73; # MEDEFAIDRIN CAPITAL LETTER YU
+16E54; C; 16E74; # MEDEFAIDRIN CAPITAL LETTER L
+16E55; C; 16E75; # MEDEFAIDRIN CAPITAL LETTER Q
+16E56; C; 16E76; # MEDEFAIDRIN CAPITAL LETTER HP
+16E57; C; 16E77; # MEDEFAIDRIN CAPITAL LETTER NY
+16E58; C; 16E78; # MEDEFAIDRIN CAPITAL LETTER X
+16E59; C; 16E79; # MEDEFAIDRIN CAPITAL LETTER D
+16E5A; C; 16E7A; # MEDEFAIDRIN CAPITAL LETTER OE
+16E5B; C; 16E7B; # MEDEFAIDRIN CAPITAL LETTER N
+16E5C; C; 16E7C; # MEDEFAIDRIN CAPITAL LETTER R
+16E5D; C; 16E7D; # MEDEFAIDRIN CAPITAL LETTER O
+16E5E; C; 16E7E; # MEDEFAIDRIN CAPITAL LETTER AI
+16E5F; C; 16E7F; # MEDEFAIDRIN CAPITAL LETTER Y
+1E900; C; 1E922; # ADLAM CAPITAL LETTER ALIF
+1E901; C; 1E923; # ADLAM CAPITAL LETTER DAALI
+1E902; C; 1E924; # ADLAM CAPITAL LETTER LAAM
+1E903; C; 1E925; # ADLAM CAPITAL LETTER MIIM
+1E904; C; 1E926; # ADLAM CAPITAL LETTER BA
+1E905; C; 1E927; # ADLAM CAPITAL LETTER SINNYIIYHE
+1E906; C; 1E928; # ADLAM CAPITAL LETTER PE
+1E907; C; 1E929; # ADLAM CAPITAL LETTER BHE
+1E908; C; 1E92A; # ADLAM CAPITAL LETTER RA
+1E909; C; 1E92B; # ADLAM CAPITAL LETTER E
+1E90A; C; 1E92C; # ADLAM CAPITAL LETTER FA
+1E90B; C; 1E92D; # ADLAM CAPITAL LETTER I
+1E90C; C; 1E92E; # ADLAM CAPITAL LETTER O
+1E90D; C; 1E92F; # ADLAM CAPITAL LETTER DHA
+1E90E; C; 1E930; # ADLAM CAPITAL LETTER YHE
+1E90F; C; 1E931; # ADLAM CAPITAL LETTER WAW
+1E910; C; 1E932; # ADLAM CAPITAL LETTER NUN
+1E911; C; 1E933; # ADLAM CAPITAL LETTER KAF
+1E912; C; 1E934; # ADLAM CAPITAL LETTER YA
+1E913; C; 1E935; # ADLAM CAPITAL LETTER U
+1E914; C; 1E936; # ADLAM CAPITAL LETTER JIIM
+1E915; C; 1E937; # ADLAM CAPITAL LETTER CHI
+1E916; C; 1E938; # ADLAM CAPITAL LETTER HA
+1E917; C; 1E939; # ADLAM CAPITAL LETTER QAAF
+1E918; C; 1E93A; # ADLAM CAPITAL LETTER GA
+1E919; C; 1E93B; # ADLAM CAPITAL LETTER NYA
+1E91A; C; 1E93C; # ADLAM CAPITAL LETTER TU
+1E91B; C; 1E93D; # ADLAM CAPITAL LETTER NHA
+1E91C; C; 1E93E; # ADLAM CAPITAL LETTER VA
+1E91D; C; 1E93F; # ADLAM CAPITAL LETTER KHA
+1E91E; C; 1E940; # ADLAM CAPITAL LETTER GBE
+1E91F; C; 1E941; # ADLAM CAPITAL LETTER ZAL
+1E920; C; 1E942; # ADLAM CAPITAL LETTER KPO
+1E921; C; 1E943; # ADLAM CAPITAL LETTER SHA
+#
+# EOF
diff --git a/pkgs/markdown/tool/common_mark_stats.json b/pkgs/markdown/tool/common_mark_stats.json
new file mode 100644
index 0000000..2e0ba8f
--- /dev/null
+++ b/pkgs/markdown/tool/common_mark_stats.json
@@ -0,0 +1,706 @@
+{
+ "ATX headings": {
+ "62": "strict",
+ "63": "strict",
+ "64": "strict",
+ "65": "strict",
+ "66": "strict",
+ "67": "strict",
+ "68": "strict",
+ "69": "strict",
+ "70": "strict",
+ "71": "strict",
+ "72": "strict",
+ "73": "strict",
+ "74": "strict",
+ "75": "strict",
+ "76": "strict",
+ "77": "strict",
+ "78": "strict",
+ "79": "strict"
+ },
+ "Autolinks": {
+ "594": "strict",
+ "595": "strict",
+ "596": "strict",
+ "597": "strict",
+ "598": "strict",
+ "599": "strict",
+ "600": "strict",
+ "601": "strict",
+ "602": "strict",
+ "603": "strict",
+ "604": "strict",
+ "605": "strict",
+ "606": "strict",
+ "607": "strict",
+ "608": "strict",
+ "609": "strict",
+ "610": "strict",
+ "611": "strict",
+ "612": "strict"
+ },
+ "Backslash escapes": {
+ "12": "strict",
+ "13": "strict",
+ "14": "strict",
+ "15": "strict",
+ "16": "strict",
+ "17": "strict",
+ "18": "strict",
+ "19": "strict",
+ "20": "strict",
+ "21": "strict",
+ "22": "strict",
+ "23": "strict",
+ "24": "strict"
+ },
+ "Blank lines": {
+ "227": "strict"
+ },
+ "Block quotes": {
+ "228": "strict",
+ "229": "strict",
+ "230": "strict",
+ "231": "strict",
+ "232": "strict",
+ "233": "strict",
+ "234": "strict",
+ "235": "strict",
+ "236": "strict",
+ "237": "strict",
+ "238": "strict",
+ "239": "strict",
+ "240": "strict",
+ "241": "strict",
+ "242": "strict",
+ "243": "strict",
+ "244": "strict",
+ "245": "strict",
+ "246": "strict",
+ "247": "strict",
+ "248": "strict",
+ "249": "strict",
+ "250": "strict",
+ "251": "strict",
+ "252": "strict"
+ },
+ "Code spans": {
+ "328": "strict",
+ "329": "strict",
+ "330": "strict",
+ "331": "strict",
+ "332": "strict",
+ "333": "strict",
+ "334": "strict",
+ "335": "strict",
+ "336": "strict",
+ "337": "strict",
+ "338": "strict",
+ "339": "strict",
+ "340": "strict",
+ "341": "strict",
+ "342": "strict",
+ "343": "strict",
+ "344": "strict",
+ "345": "strict",
+ "346": "strict",
+ "347": "strict",
+ "348": "strict",
+ "349": "strict"
+ },
+ "Emphasis and strong emphasis": {
+ "350": "strict",
+ "351": "strict",
+ "352": "strict",
+ "353": "strict",
+ "354": "fail",
+ "355": "strict",
+ "356": "strict",
+ "357": "strict",
+ "358": "strict",
+ "359": "strict",
+ "360": "strict",
+ "361": "strict",
+ "362": "strict",
+ "363": "strict",
+ "364": "strict",
+ "365": "strict",
+ "366": "strict",
+ "367": "strict",
+ "368": "strict",
+ "369": "strict",
+ "370": "strict",
+ "371": "strict",
+ "372": "strict",
+ "373": "strict",
+ "374": "strict",
+ "375": "strict",
+ "376": "strict",
+ "377": "strict",
+ "378": "strict",
+ "379": "strict",
+ "380": "strict",
+ "381": "strict",
+ "382": "strict",
+ "383": "strict",
+ "384": "strict",
+ "385": "strict",
+ "386": "strict",
+ "387": "strict",
+ "388": "strict",
+ "389": "strict",
+ "390": "strict",
+ "391": "strict",
+ "392": "strict",
+ "393": "strict",
+ "394": "strict",
+ "395": "strict",
+ "396": "strict",
+ "397": "strict",
+ "398": "strict",
+ "399": "strict",
+ "400": "strict",
+ "401": "strict",
+ "402": "strict",
+ "403": "strict",
+ "404": "strict",
+ "405": "strict",
+ "406": "strict",
+ "407": "strict",
+ "408": "strict",
+ "409": "strict",
+ "410": "strict",
+ "411": "strict",
+ "412": "strict",
+ "413": "strict",
+ "414": "strict",
+ "415": "strict",
+ "416": "strict",
+ "417": "strict",
+ "418": "strict",
+ "419": "strict",
+ "420": "strict",
+ "421": "strict",
+ "422": "strict",
+ "423": "strict",
+ "424": "strict",
+ "425": "strict",
+ "426": "strict",
+ "427": "strict",
+ "428": "strict",
+ "429": "strict",
+ "430": "strict",
+ "431": "strict",
+ "432": "strict",
+ "433": "strict",
+ "434": "strict",
+ "435": "strict",
+ "436": "strict",
+ "437": "strict",
+ "438": "strict",
+ "439": "strict",
+ "440": "strict",
+ "441": "strict",
+ "442": "strict",
+ "443": "strict",
+ "444": "strict",
+ "445": "strict",
+ "446": "strict",
+ "447": "strict",
+ "448": "strict",
+ "449": "strict",
+ "450": "strict",
+ "451": "strict",
+ "452": "strict",
+ "453": "strict",
+ "454": "strict",
+ "455": "strict",
+ "456": "strict",
+ "457": "strict",
+ "458": "strict",
+ "459": "strict",
+ "460": "strict",
+ "461": "strict",
+ "462": "strict",
+ "463": "strict",
+ "464": "strict",
+ "465": "strict",
+ "466": "strict",
+ "467": "strict",
+ "468": "strict",
+ "469": "strict",
+ "470": "strict",
+ "471": "strict",
+ "472": "strict",
+ "473": "strict",
+ "474": "strict",
+ "475": "strict",
+ "476": "strict",
+ "477": "strict",
+ "478": "strict",
+ "479": "strict",
+ "480": "strict",
+ "481": "strict"
+ },
+ "Entity and numeric character references": {
+ "25": "loose",
+ "26": "strict",
+ "27": "strict",
+ "28": "strict",
+ "29": "strict",
+ "30": "strict",
+ "31": "strict",
+ "32": "strict",
+ "33": "strict",
+ "34": "strict",
+ "35": "strict",
+ "36": "strict",
+ "37": "strict",
+ "38": "strict",
+ "39": "strict",
+ "40": "loose",
+ "41": "strict"
+ },
+ "Fenced code blocks": {
+ "119": "strict",
+ "120": "strict",
+ "121": "strict",
+ "122": "strict",
+ "123": "strict",
+ "124": "strict",
+ "125": "strict",
+ "126": "strict",
+ "127": "strict",
+ "128": "strict",
+ "129": "strict",
+ "130": "strict",
+ "131": "strict",
+ "132": "strict",
+ "133": "strict",
+ "134": "strict",
+ "135": "strict",
+ "136": "strict",
+ "137": "strict",
+ "138": "strict",
+ "139": "strict",
+ "140": "strict",
+ "141": "strict",
+ "142": "strict",
+ "143": "strict",
+ "144": "strict",
+ "145": "strict",
+ "146": "strict",
+ "147": "strict"
+ },
+ "Hard line breaks": {
+ "633": "strict",
+ "634": "strict",
+ "635": "strict",
+ "636": "strict",
+ "637": "strict",
+ "638": "strict",
+ "639": "strict",
+ "640": "strict",
+ "641": "strict",
+ "642": "strict",
+ "643": "strict",
+ "644": "strict",
+ "645": "strict",
+ "646": "strict",
+ "647": "strict"
+ },
+ "HTML blocks": {
+ "148": "strict",
+ "149": "strict",
+ "150": "strict",
+ "151": "strict",
+ "152": "strict",
+ "153": "strict",
+ "154": "strict",
+ "155": "strict",
+ "156": "strict",
+ "157": "strict",
+ "158": "strict",
+ "159": "strict",
+ "160": "strict",
+ "161": "strict",
+ "162": "strict",
+ "163": "strict",
+ "164": "strict",
+ "165": "strict",
+ "166": "strict",
+ "167": "strict",
+ "168": "strict",
+ "169": "strict",
+ "170": "strict",
+ "171": "strict",
+ "172": "strict",
+ "173": "strict",
+ "174": "strict",
+ "175": "strict",
+ "176": "strict",
+ "177": "strict",
+ "178": "strict",
+ "179": "strict",
+ "180": "strict",
+ "181": "strict",
+ "182": "strict",
+ "183": "strict",
+ "184": "strict",
+ "185": "strict",
+ "186": "strict",
+ "187": "strict",
+ "188": "strict",
+ "189": "strict",
+ "190": "strict",
+ "191": "strict"
+ },
+ "Images": {
+ "572": "strict",
+ "573": "strict",
+ "574": "strict",
+ "575": "strict",
+ "576": "strict",
+ "577": "strict",
+ "578": "strict",
+ "579": "strict",
+ "580": "strict",
+ "581": "strict",
+ "582": "strict",
+ "583": "strict",
+ "584": "strict",
+ "585": "strict",
+ "586": "strict",
+ "587": "strict",
+ "588": "strict",
+ "589": "strict",
+ "590": "strict",
+ "591": "strict",
+ "592": "strict",
+ "593": "strict"
+ },
+ "Indented code blocks": {
+ "107": "strict",
+ "108": "strict",
+ "109": "strict",
+ "110": "strict",
+ "111": "strict",
+ "112": "strict",
+ "113": "strict",
+ "114": "strict",
+ "115": "strict",
+ "116": "strict",
+ "117": "strict",
+ "118": "strict"
+ },
+ "Inlines": {
+ "327": "strict"
+ },
+ "Link reference definitions": {
+ "192": "strict",
+ "193": "strict",
+ "194": "strict",
+ "195": "strict",
+ "196": "strict",
+ "197": "strict",
+ "198": "strict",
+ "199": "strict",
+ "200": "strict",
+ "201": "strict",
+ "202": "strict",
+ "203": "strict",
+ "204": "strict",
+ "205": "strict",
+ "206": "strict",
+ "207": "loose",
+ "208": "strict",
+ "209": "strict",
+ "210": "strict",
+ "211": "strict",
+ "212": "strict",
+ "213": "strict",
+ "214": "strict",
+ "215": "strict",
+ "216": "strict",
+ "217": "strict",
+ "218": "strict"
+ },
+ "Links": {
+ "482": "strict",
+ "483": "strict",
+ "484": "strict",
+ "485": "strict",
+ "486": "strict",
+ "487": "strict",
+ "488": "strict",
+ "489": "strict",
+ "490": "strict",
+ "491": "strict",
+ "492": "strict",
+ "493": "strict",
+ "494": "strict",
+ "495": "strict",
+ "496": "strict",
+ "497": "strict",
+ "498": "strict",
+ "499": "strict",
+ "500": "strict",
+ "501": "strict",
+ "502": "strict",
+ "503": "strict",
+ "504": "strict",
+ "505": "strict",
+ "506": "strict",
+ "507": "strict",
+ "508": "strict",
+ "509": "strict",
+ "510": "strict",
+ "511": "strict",
+ "512": "strict",
+ "513": "strict",
+ "514": "strict",
+ "515": "strict",
+ "516": "strict",
+ "517": "strict",
+ "518": "strict",
+ "519": "strict",
+ "520": "strict",
+ "521": "strict",
+ "522": "strict",
+ "523": "strict",
+ "524": "strict",
+ "525": "strict",
+ "526": "strict",
+ "527": "strict",
+ "528": "strict",
+ "529": "strict",
+ "530": "strict",
+ "531": "strict",
+ "532": "strict",
+ "533": "strict",
+ "534": "strict",
+ "535": "strict",
+ "536": "strict",
+ "537": "strict",
+ "538": "strict",
+ "539": "strict",
+ "540": "strict",
+ "541": "strict",
+ "542": "strict",
+ "543": "strict",
+ "544": "strict",
+ "545": "strict",
+ "546": "strict",
+ "547": "strict",
+ "548": "strict",
+ "549": "strict",
+ "550": "strict",
+ "551": "strict",
+ "552": "strict",
+ "553": "strict",
+ "554": "strict",
+ "555": "strict",
+ "556": "strict",
+ "557": "strict",
+ "558": "strict",
+ "559": "strict",
+ "560": "strict",
+ "561": "strict",
+ "562": "strict",
+ "563": "strict",
+ "564": "strict",
+ "565": "strict",
+ "566": "strict",
+ "567": "strict",
+ "568": "strict",
+ "569": "strict",
+ "570": "strict",
+ "571": "strict"
+ },
+ "List items": {
+ "253": "strict",
+ "254": "strict",
+ "255": "strict",
+ "256": "strict",
+ "257": "strict",
+ "258": "strict",
+ "259": "strict",
+ "260": "strict",
+ "261": "strict",
+ "262": "strict",
+ "263": "strict",
+ "264": "strict",
+ "265": "strict",
+ "266": "strict",
+ "267": "strict",
+ "268": "strict",
+ "269": "strict",
+ "270": "strict",
+ "271": "strict",
+ "272": "strict",
+ "273": "strict",
+ "274": "strict",
+ "275": "strict",
+ "276": "strict",
+ "277": "strict",
+ "278": "strict",
+ "279": "strict",
+ "280": "strict",
+ "281": "strict",
+ "282": "strict",
+ "283": "strict",
+ "284": "strict",
+ "285": "strict",
+ "286": "strict",
+ "287": "strict",
+ "288": "strict",
+ "289": "strict",
+ "290": "strict",
+ "291": "strict",
+ "292": "strict",
+ "293": "strict",
+ "294": "strict",
+ "295": "strict",
+ "296": "strict",
+ "297": "strict",
+ "298": "strict",
+ "299": "strict",
+ "300": "strict"
+ },
+ "Lists": {
+ "301": "strict",
+ "302": "strict",
+ "303": "strict",
+ "304": "strict",
+ "305": "strict",
+ "306": "strict",
+ "307": "strict",
+ "308": "strict",
+ "309": "strict",
+ "310": "strict",
+ "311": "strict",
+ "312": "strict",
+ "313": "strict",
+ "314": "strict",
+ "315": "strict",
+ "316": "strict",
+ "317": "strict",
+ "318": "strict",
+ "319": "strict",
+ "320": "strict",
+ "321": "strict",
+ "322": "strict",
+ "323": "strict",
+ "324": "strict",
+ "325": "strict",
+ "326": "strict"
+ },
+ "Paragraphs": {
+ "219": "strict",
+ "220": "strict",
+ "221": "strict",
+ "222": "strict",
+ "223": "strict",
+ "224": "strict",
+ "225": "strict",
+ "226": "strict"
+ },
+ "Precedence": {
+ "42": "strict"
+ },
+ "Raw HTML": {
+ "613": "strict",
+ "614": "strict",
+ "615": "strict",
+ "616": "strict",
+ "617": "strict",
+ "618": "strict",
+ "619": "strict",
+ "620": "strict",
+ "621": "strict",
+ "622": "strict",
+ "623": "strict",
+ "624": "strict",
+ "625": "loose",
+ "626": "loose",
+ "627": "strict",
+ "628": "strict",
+ "629": "strict",
+ "630": "strict",
+ "631": "strict",
+ "632": "strict"
+ },
+ "Setext headings": {
+ "80": "strict",
+ "81": "strict",
+ "82": "loose",
+ "83": "strict",
+ "84": "loose",
+ "85": "strict",
+ "86": "strict",
+ "87": "strict",
+ "88": "strict",
+ "89": "strict",
+ "90": "strict",
+ "91": "strict",
+ "92": "strict",
+ "93": "strict",
+ "94": "strict",
+ "95": "strict",
+ "96": "strict",
+ "97": "strict",
+ "98": "strict",
+ "99": "strict",
+ "100": "strict",
+ "101": "strict",
+ "102": "strict",
+ "103": "strict",
+ "104": "strict",
+ "105": "strict",
+ "106": "strict"
+ },
+ "Soft line breaks": {
+ "648": "strict",
+ "649": "strict"
+ },
+ "Tabs": {
+ "1": "strict",
+ "2": "strict",
+ "3": "strict",
+ "4": "strict",
+ "5": "strict",
+ "6": "loose",
+ "7": "strict",
+ "8": "strict",
+ "9": "strict",
+ "10": "strict",
+ "11": "strict"
+ },
+ "Textual content": {
+ "650": "strict",
+ "651": "strict",
+ "652": "strict"
+ },
+ "Thematic breaks": {
+ "43": "strict",
+ "44": "strict",
+ "45": "strict",
+ "46": "strict",
+ "47": "strict",
+ "48": "strict",
+ "49": "strict",
+ "50": "strict",
+ "51": "strict",
+ "52": "strict",
+ "53": "strict",
+ "54": "strict",
+ "55": "strict",
+ "56": "strict",
+ "57": "strict",
+ "58": "strict",
+ "59": "strict",
+ "60": "strict",
+ "61": "strict"
+ }
+}
diff --git a/pkgs/markdown/tool/common_mark_stats.txt b/pkgs/markdown/tool/common_mark_stats.txt
new file mode 100644
index 0000000..db3b891
--- /dev/null
+++ b/pkgs/markdown/tool/common_mark_stats.txt
@@ -0,0 +1,28 @@
+ 18 of 18 – 100.0% ATX headings
+ 19 of 19 – 100.0% Autolinks
+ 13 of 13 – 100.0% Backslash escapes
+ 1 of 1 – 100.0% Blank lines
+ 25 of 25 – 100.0% Block quotes
+ 22 of 22 – 100.0% Code spans
+ 131 of 132 – 99.2% Emphasis and strong emphasis
+ 17 of 17 – 100.0% Entity and numeric character references
+ 29 of 29 – 100.0% Fenced code blocks
+ 15 of 15 – 100.0% Hard line breaks
+ 44 of 44 – 100.0% HTML blocks
+ 22 of 22 – 100.0% Images
+ 12 of 12 – 100.0% Indented code blocks
+ 1 of 1 – 100.0% Inlines
+ 27 of 27 – 100.0% Link reference definitions
+ 90 of 90 – 100.0% Links
+ 48 of 48 – 100.0% List items
+ 26 of 26 – 100.0% Lists
+ 8 of 8 – 100.0% Paragraphs
+ 1 of 1 – 100.0% Precedence
+ 20 of 20 – 100.0% Raw HTML
+ 27 of 27 – 100.0% Setext headings
+ 2 of 2 – 100.0% Soft line breaks
+ 11 of 11 – 100.0% Tabs
+ 3 of 3 – 100.0% Textual content
+ 19 of 19 – 100.0% Thematic breaks
+ 651 of 652 – 99.8% TOTAL
+ 643 of 651 – 98.8% TOTAL Strict
diff --git a/pkgs/markdown/tool/common_mark_tests.json b/pkgs/markdown/tool/common_mark_tests.json
new file mode 100644
index 0000000..1f89e66
--- /dev/null
+++ b/pkgs/markdown/tool/common_mark_tests.json
@@ -0,0 +1,5218 @@
+[
+ {
+ "markdown": "\tfoo\tbaz\t\tbim\n",
+ "html": "<pre><code>foo\tbaz\t\tbim\n</code></pre>\n",
+ "example": 1,
+ "start_line": 355,
+ "end_line": 360,
+ "section": "Tabs"
+ },
+ {
+ "markdown": " \tfoo\tbaz\t\tbim\n",
+ "html": "<pre><code>foo\tbaz\t\tbim\n</code></pre>\n",
+ "example": 2,
+ "start_line": 362,
+ "end_line": 367,
+ "section": "Tabs"
+ },
+ {
+ "markdown": " a\ta\n ὐ\ta\n",
+ "html": "<pre><code>a\ta\nὐ\ta\n</code></pre>\n",
+ "example": 3,
+ "start_line": 369,
+ "end_line": 376,
+ "section": "Tabs"
+ },
+ {
+ "markdown": " - foo\n\n\tbar\n",
+ "html": "<ul>\n<li>\n<p>foo</p>\n<p>bar</p>\n</li>\n</ul>\n",
+ "example": 4,
+ "start_line": 382,
+ "end_line": 393,
+ "section": "Tabs"
+ },
+ {
+ "markdown": "- foo\n\n\t\tbar\n",
+ "html": "<ul>\n<li>\n<p>foo</p>\n<pre><code> bar\n</code></pre>\n</li>\n</ul>\n",
+ "example": 5,
+ "start_line": 395,
+ "end_line": 407,
+ "section": "Tabs"
+ },
+ {
+ "markdown": ">\t\tfoo\n",
+ "html": "<blockquote>\n<pre><code> foo\n</code></pre>\n</blockquote>\n",
+ "example": 6,
+ "start_line": 418,
+ "end_line": 425,
+ "section": "Tabs"
+ },
+ {
+ "markdown": "-\t\tfoo\n",
+ "html": "<ul>\n<li>\n<pre><code> foo\n</code></pre>\n</li>\n</ul>\n",
+ "example": 7,
+ "start_line": 427,
+ "end_line": 436,
+ "section": "Tabs"
+ },
+ {
+ "markdown": " foo\n\tbar\n",
+ "html": "<pre><code>foo\nbar\n</code></pre>\n",
+ "example": 8,
+ "start_line": 439,
+ "end_line": 446,
+ "section": "Tabs"
+ },
+ {
+ "markdown": " - foo\n - bar\n\t - baz\n",
+ "html": "<ul>\n<li>foo\n<ul>\n<li>bar\n<ul>\n<li>baz</li>\n</ul>\n</li>\n</ul>\n</li>\n</ul>\n",
+ "example": 9,
+ "start_line": 448,
+ "end_line": 464,
+ "section": "Tabs"
+ },
+ {
+ "markdown": "#\tFoo\n",
+ "html": "<h1>Foo</h1>\n",
+ "example": 10,
+ "start_line": 466,
+ "end_line": 470,
+ "section": "Tabs"
+ },
+ {
+ "markdown": "*\t*\t*\t\n",
+ "html": "<hr />\n",
+ "example": 11,
+ "start_line": 472,
+ "end_line": 476,
+ "section": "Tabs"
+ },
+ {
+ "markdown": "\\!\\\"\\#\\$\\%\\&\\'\\(\\)\\*\\+\\,\\-\\.\\/\\:\\;\\<\\=\\>\\?\\@\\[\\\\\\]\\^\\_\\`\\{\\|\\}\\~\n",
+ "html": "<p>!"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~</p>\n",
+ "example": 12,
+ "start_line": 489,
+ "end_line": 493,
+ "section": "Backslash escapes"
+ },
+ {
+ "markdown": "\\\t\\A\\a\\ \\3\\φ\\«\n",
+ "html": "<p>\\\t\\A\\a\\ \\3\\φ\\«</p>\n",
+ "example": 13,
+ "start_line": 499,
+ "end_line": 503,
+ "section": "Backslash escapes"
+ },
+ {
+ "markdown": "\\*not emphasized*\n\\<br/> not a tag\n\\[not a link](/foo)\n\\`not code`\n1\\. not a list\n\\* not a list\n\\# not a heading\n\\[foo]: /url \"not a reference\"\n\\ö not a character entity\n",
+ "html": "<p>*not emphasized*\n<br/> not a tag\n[not a link](/foo)\n`not code`\n1. not a list\n* not a list\n# not a heading\n[foo]: /url "not a reference"\n&ouml; not a character entity</p>\n",
+ "example": 14,
+ "start_line": 509,
+ "end_line": 529,
+ "section": "Backslash escapes"
+ },
+ {
+ "markdown": "\\\\*emphasis*\n",
+ "html": "<p>\\<em>emphasis</em></p>\n",
+ "example": 15,
+ "start_line": 534,
+ "end_line": 538,
+ "section": "Backslash escapes"
+ },
+ {
+ "markdown": "foo\\\nbar\n",
+ "html": "<p>foo<br />\nbar</p>\n",
+ "example": 16,
+ "start_line": 543,
+ "end_line": 549,
+ "section": "Backslash escapes"
+ },
+ {
+ "markdown": "`` \\[\\` ``\n",
+ "html": "<p><code>\\[\\`</code></p>\n",
+ "example": 17,
+ "start_line": 555,
+ "end_line": 559,
+ "section": "Backslash escapes"
+ },
+ {
+ "markdown": " \\[\\]\n",
+ "html": "<pre><code>\\[\\]\n</code></pre>\n",
+ "example": 18,
+ "start_line": 562,
+ "end_line": 567,
+ "section": "Backslash escapes"
+ },
+ {
+ "markdown": "~~~\n\\[\\]\n~~~\n",
+ "html": "<pre><code>\\[\\]\n</code></pre>\n",
+ "example": 19,
+ "start_line": 570,
+ "end_line": 577,
+ "section": "Backslash escapes"
+ },
+ {
+ "markdown": "<https://example.com?find=\\*>\n",
+ "html": "<p><a href=\"https://example.com?find=%5C*\">https://example.com?find=\\*</a></p>\n",
+ "example": 20,
+ "start_line": 580,
+ "end_line": 584,
+ "section": "Backslash escapes"
+ },
+ {
+ "markdown": "<a href=\"/bar\\/)\">\n",
+ "html": "<a href=\"/bar\\/)\">\n",
+ "example": 21,
+ "start_line": 587,
+ "end_line": 591,
+ "section": "Backslash escapes"
+ },
+ {
+ "markdown": "[foo](/bar\\* \"ti\\*tle\")\n",
+ "html": "<p><a href=\"/bar*\" title=\"ti*tle\">foo</a></p>\n",
+ "example": 22,
+ "start_line": 597,
+ "end_line": 601,
+ "section": "Backslash escapes"
+ },
+ {
+ "markdown": "[foo]\n\n[foo]: /bar\\* \"ti\\*tle\"\n",
+ "html": "<p><a href=\"/bar*\" title=\"ti*tle\">foo</a></p>\n",
+ "example": 23,
+ "start_line": 604,
+ "end_line": 610,
+ "section": "Backslash escapes"
+ },
+ {
+ "markdown": "``` foo\\+bar\nfoo\n```\n",
+ "html": "<pre><code class=\"language-foo+bar\">foo\n</code></pre>\n",
+ "example": 24,
+ "start_line": 613,
+ "end_line": 620,
+ "section": "Backslash escapes"
+ },
+ {
+ "markdown": " & © Æ Ď\n¾ ℋ ⅆ\n∲ ≧̸\n",
+ "html": "<p> & © Æ Ď\n¾ ℋ ⅆ\n∲ ≧̸</p>\n",
+ "example": 25,
+ "start_line": 649,
+ "end_line": 657,
+ "section": "Entity and numeric character references"
+ },
+ {
+ "markdown": "# Ӓ Ϡ �\n",
+ "html": "<p># Ӓ Ϡ �</p>\n",
+ "example": 26,
+ "start_line": 668,
+ "end_line": 672,
+ "section": "Entity and numeric character references"
+ },
+ {
+ "markdown": "" ആ ಫ\n",
+ "html": "<p>" ആ ಫ</p>\n",
+ "example": 27,
+ "start_line": 681,
+ "end_line": 685,
+ "section": "Entity and numeric character references"
+ },
+ {
+ "markdown": "  &x; &#; &#x;\n�\n&#abcdef0;\n&ThisIsNotDefined; &hi?;\n",
+ "html": "<p>&nbsp &x; &#; &#x;\n&#87654321;\n&#abcdef0;\n&ThisIsNotDefined; &hi?;</p>\n",
+ "example": 28,
+ "start_line": 690,
+ "end_line": 700,
+ "section": "Entity and numeric character references"
+ },
+ {
+ "markdown": "©\n",
+ "html": "<p>&copy</p>\n",
+ "example": 29,
+ "start_line": 707,
+ "end_line": 711,
+ "section": "Entity and numeric character references"
+ },
+ {
+ "markdown": "&MadeUpEntity;\n",
+ "html": "<p>&MadeUpEntity;</p>\n",
+ "example": 30,
+ "start_line": 717,
+ "end_line": 721,
+ "section": "Entity and numeric character references"
+ },
+ {
+ "markdown": "<a href=\"öö.html\">\n",
+ "html": "<a href=\"öö.html\">\n",
+ "example": 31,
+ "start_line": 728,
+ "end_line": 732,
+ "section": "Entity and numeric character references"
+ },
+ {
+ "markdown": "[foo](/föö \"föö\")\n",
+ "html": "<p><a href=\"/f%C3%B6%C3%B6\" title=\"föö\">foo</a></p>\n",
+ "example": 32,
+ "start_line": 735,
+ "end_line": 739,
+ "section": "Entity and numeric character references"
+ },
+ {
+ "markdown": "[foo]\n\n[foo]: /föö \"föö\"\n",
+ "html": "<p><a href=\"/f%C3%B6%C3%B6\" title=\"föö\">foo</a></p>\n",
+ "example": 33,
+ "start_line": 742,
+ "end_line": 748,
+ "section": "Entity and numeric character references"
+ },
+ {
+ "markdown": "``` föö\nfoo\n```\n",
+ "html": "<pre><code class=\"language-föö\">foo\n</code></pre>\n",
+ "example": 34,
+ "start_line": 751,
+ "end_line": 758,
+ "section": "Entity and numeric character references"
+ },
+ {
+ "markdown": "`föö`\n",
+ "html": "<p><code>f&ouml;&ouml;</code></p>\n",
+ "example": 35,
+ "start_line": 764,
+ "end_line": 768,
+ "section": "Entity and numeric character references"
+ },
+ {
+ "markdown": " föfö\n",
+ "html": "<pre><code>f&ouml;f&ouml;\n</code></pre>\n",
+ "example": 36,
+ "start_line": 771,
+ "end_line": 776,
+ "section": "Entity and numeric character references"
+ },
+ {
+ "markdown": "*foo*\n*foo*\n",
+ "html": "<p>*foo*\n<em>foo</em></p>\n",
+ "example": 37,
+ "start_line": 783,
+ "end_line": 789,
+ "section": "Entity and numeric character references"
+ },
+ {
+ "markdown": "* foo\n\n* foo\n",
+ "html": "<p>* foo</p>\n<ul>\n<li>foo</li>\n</ul>\n",
+ "example": 38,
+ "start_line": 791,
+ "end_line": 800,
+ "section": "Entity and numeric character references"
+ },
+ {
+ "markdown": "foo bar\n",
+ "html": "<p>foo\n\nbar</p>\n",
+ "example": 39,
+ "start_line": 802,
+ "end_line": 808,
+ "section": "Entity and numeric character references"
+ },
+ {
+ "markdown": "	foo\n",
+ "html": "<p>\tfoo</p>\n",
+ "example": 40,
+ "start_line": 810,
+ "end_line": 814,
+ "section": "Entity and numeric character references"
+ },
+ {
+ "markdown": "[a](url "tit")\n",
+ "html": "<p>[a](url "tit")</p>\n",
+ "example": 41,
+ "start_line": 817,
+ "end_line": 821,
+ "section": "Entity and numeric character references"
+ },
+ {
+ "markdown": "- `one\n- two`\n",
+ "html": "<ul>\n<li>`one</li>\n<li>two`</li>\n</ul>\n",
+ "example": 42,
+ "start_line": 840,
+ "end_line": 848,
+ "section": "Precedence"
+ },
+ {
+ "markdown": "***\n---\n___\n",
+ "html": "<hr />\n<hr />\n<hr />\n",
+ "example": 43,
+ "start_line": 879,
+ "end_line": 887,
+ "section": "Thematic breaks"
+ },
+ {
+ "markdown": "+++\n",
+ "html": "<p>+++</p>\n",
+ "example": 44,
+ "start_line": 892,
+ "end_line": 896,
+ "section": "Thematic breaks"
+ },
+ {
+ "markdown": "===\n",
+ "html": "<p>===</p>\n",
+ "example": 45,
+ "start_line": 899,
+ "end_line": 903,
+ "section": "Thematic breaks"
+ },
+ {
+ "markdown": "--\n**\n__\n",
+ "html": "<p>--\n**\n__</p>\n",
+ "example": 46,
+ "start_line": 908,
+ "end_line": 916,
+ "section": "Thematic breaks"
+ },
+ {
+ "markdown": " ***\n ***\n ***\n",
+ "html": "<hr />\n<hr />\n<hr />\n",
+ "example": 47,
+ "start_line": 921,
+ "end_line": 929,
+ "section": "Thematic breaks"
+ },
+ {
+ "markdown": " ***\n",
+ "html": "<pre><code>***\n</code></pre>\n",
+ "example": 48,
+ "start_line": 934,
+ "end_line": 939,
+ "section": "Thematic breaks"
+ },
+ {
+ "markdown": "Foo\n ***\n",
+ "html": "<p>Foo\n***</p>\n",
+ "example": 49,
+ "start_line": 942,
+ "end_line": 948,
+ "section": "Thematic breaks"
+ },
+ {
+ "markdown": "_____________________________________\n",
+ "html": "<hr />\n",
+ "example": 50,
+ "start_line": 953,
+ "end_line": 957,
+ "section": "Thematic breaks"
+ },
+ {
+ "markdown": " - - -\n",
+ "html": "<hr />\n",
+ "example": 51,
+ "start_line": 962,
+ "end_line": 966,
+ "section": "Thematic breaks"
+ },
+ {
+ "markdown": " ** * ** * ** * **\n",
+ "html": "<hr />\n",
+ "example": 52,
+ "start_line": 969,
+ "end_line": 973,
+ "section": "Thematic breaks"
+ },
+ {
+ "markdown": "- - - -\n",
+ "html": "<hr />\n",
+ "example": 53,
+ "start_line": 976,
+ "end_line": 980,
+ "section": "Thematic breaks"
+ },
+ {
+ "markdown": "- - - - \n",
+ "html": "<hr />\n",
+ "example": 54,
+ "start_line": 985,
+ "end_line": 989,
+ "section": "Thematic breaks"
+ },
+ {
+ "markdown": "_ _ _ _ a\n\na------\n\n---a---\n",
+ "html": "<p>_ _ _ _ a</p>\n<p>a------</p>\n<p>---a---</p>\n",
+ "example": 55,
+ "start_line": 994,
+ "end_line": 1004,
+ "section": "Thematic breaks"
+ },
+ {
+ "markdown": " *-*\n",
+ "html": "<p><em>-</em></p>\n",
+ "example": 56,
+ "start_line": 1010,
+ "end_line": 1014,
+ "section": "Thematic breaks"
+ },
+ {
+ "markdown": "- foo\n***\n- bar\n",
+ "html": "<ul>\n<li>foo</li>\n</ul>\n<hr />\n<ul>\n<li>bar</li>\n</ul>\n",
+ "example": 57,
+ "start_line": 1019,
+ "end_line": 1031,
+ "section": "Thematic breaks"
+ },
+ {
+ "markdown": "Foo\n***\nbar\n",
+ "html": "<p>Foo</p>\n<hr />\n<p>bar</p>\n",
+ "example": 58,
+ "start_line": 1036,
+ "end_line": 1044,
+ "section": "Thematic breaks"
+ },
+ {
+ "markdown": "Foo\n---\nbar\n",
+ "html": "<h2>Foo</h2>\n<p>bar</p>\n",
+ "example": 59,
+ "start_line": 1053,
+ "end_line": 1060,
+ "section": "Thematic breaks"
+ },
+ {
+ "markdown": "* Foo\n* * *\n* Bar\n",
+ "html": "<ul>\n<li>Foo</li>\n</ul>\n<hr />\n<ul>\n<li>Bar</li>\n</ul>\n",
+ "example": 60,
+ "start_line": 1066,
+ "end_line": 1078,
+ "section": "Thematic breaks"
+ },
+ {
+ "markdown": "- Foo\n- * * *\n",
+ "html": "<ul>\n<li>Foo</li>\n<li>\n<hr />\n</li>\n</ul>\n",
+ "example": 61,
+ "start_line": 1083,
+ "end_line": 1093,
+ "section": "Thematic breaks"
+ },
+ {
+ "markdown": "# foo\n## foo\n### foo\n#### foo\n##### foo\n###### foo\n",
+ "html": "<h1>foo</h1>\n<h2>foo</h2>\n<h3>foo</h3>\n<h4>foo</h4>\n<h5>foo</h5>\n<h6>foo</h6>\n",
+ "example": 62,
+ "start_line": 1112,
+ "end_line": 1126,
+ "section": "ATX headings"
+ },
+ {
+ "markdown": "####### foo\n",
+ "html": "<p>####### foo</p>\n",
+ "example": 63,
+ "start_line": 1131,
+ "end_line": 1135,
+ "section": "ATX headings"
+ },
+ {
+ "markdown": "#5 bolt\n\n#hashtag\n",
+ "html": "<p>#5 bolt</p>\n<p>#hashtag</p>\n",
+ "example": 64,
+ "start_line": 1146,
+ "end_line": 1153,
+ "section": "ATX headings"
+ },
+ {
+ "markdown": "\\## foo\n",
+ "html": "<p>## foo</p>\n",
+ "example": 65,
+ "start_line": 1158,
+ "end_line": 1162,
+ "section": "ATX headings"
+ },
+ {
+ "markdown": "# foo *bar* \\*baz\\*\n",
+ "html": "<h1>foo <em>bar</em> *baz*</h1>\n",
+ "example": 66,
+ "start_line": 1167,
+ "end_line": 1171,
+ "section": "ATX headings"
+ },
+ {
+ "markdown": "# foo \n",
+ "html": "<h1>foo</h1>\n",
+ "example": 67,
+ "start_line": 1176,
+ "end_line": 1180,
+ "section": "ATX headings"
+ },
+ {
+ "markdown": " ### foo\n ## foo\n # foo\n",
+ "html": "<h3>foo</h3>\n<h2>foo</h2>\n<h1>foo</h1>\n",
+ "example": 68,
+ "start_line": 1185,
+ "end_line": 1193,
+ "section": "ATX headings"
+ },
+ {
+ "markdown": " # foo\n",
+ "html": "<pre><code># foo\n</code></pre>\n",
+ "example": 69,
+ "start_line": 1198,
+ "end_line": 1203,
+ "section": "ATX headings"
+ },
+ {
+ "markdown": "foo\n # bar\n",
+ "html": "<p>foo\n# bar</p>\n",
+ "example": 70,
+ "start_line": 1206,
+ "end_line": 1212,
+ "section": "ATX headings"
+ },
+ {
+ "markdown": "## foo ##\n ### bar ###\n",
+ "html": "<h2>foo</h2>\n<h3>bar</h3>\n",
+ "example": 71,
+ "start_line": 1217,
+ "end_line": 1223,
+ "section": "ATX headings"
+ },
+ {
+ "markdown": "# foo ##################################\n##### foo ##\n",
+ "html": "<h1>foo</h1>\n<h5>foo</h5>\n",
+ "example": 72,
+ "start_line": 1228,
+ "end_line": 1234,
+ "section": "ATX headings"
+ },
+ {
+ "markdown": "### foo ### \n",
+ "html": "<h3>foo</h3>\n",
+ "example": 73,
+ "start_line": 1239,
+ "end_line": 1243,
+ "section": "ATX headings"
+ },
+ {
+ "markdown": "### foo ### b\n",
+ "html": "<h3>foo ### b</h3>\n",
+ "example": 74,
+ "start_line": 1250,
+ "end_line": 1254,
+ "section": "ATX headings"
+ },
+ {
+ "markdown": "# foo#\n",
+ "html": "<h1>foo#</h1>\n",
+ "example": 75,
+ "start_line": 1259,
+ "end_line": 1263,
+ "section": "ATX headings"
+ },
+ {
+ "markdown": "### foo \\###\n## foo #\\##\n# foo \\#\n",
+ "html": "<h3>foo ###</h3>\n<h2>foo ###</h2>\n<h1>foo #</h1>\n",
+ "example": 76,
+ "start_line": 1269,
+ "end_line": 1277,
+ "section": "ATX headings"
+ },
+ {
+ "markdown": "****\n## foo\n****\n",
+ "html": "<hr />\n<h2>foo</h2>\n<hr />\n",
+ "example": 77,
+ "start_line": 1283,
+ "end_line": 1291,
+ "section": "ATX headings"
+ },
+ {
+ "markdown": "Foo bar\n# baz\nBar foo\n",
+ "html": "<p>Foo bar</p>\n<h1>baz</h1>\n<p>Bar foo</p>\n",
+ "example": 78,
+ "start_line": 1294,
+ "end_line": 1302,
+ "section": "ATX headings"
+ },
+ {
+ "markdown": "## \n#\n### ###\n",
+ "html": "<h2></h2>\n<h1></h1>\n<h3></h3>\n",
+ "example": 79,
+ "start_line": 1307,
+ "end_line": 1315,
+ "section": "ATX headings"
+ },
+ {
+ "markdown": "Foo *bar*\n=========\n\nFoo *bar*\n---------\n",
+ "html": "<h1>Foo <em>bar</em></h1>\n<h2>Foo <em>bar</em></h2>\n",
+ "example": 80,
+ "start_line": 1347,
+ "end_line": 1356,
+ "section": "Setext headings"
+ },
+ {
+ "markdown": "Foo *bar\nbaz*\n====\n",
+ "html": "<h1>Foo <em>bar\nbaz</em></h1>\n",
+ "example": 81,
+ "start_line": 1361,
+ "end_line": 1368,
+ "section": "Setext headings"
+ },
+ {
+ "markdown": " Foo *bar\nbaz*\t\n====\n",
+ "html": "<h1>Foo <em>bar\nbaz</em></h1>\n",
+ "example": 82,
+ "start_line": 1375,
+ "end_line": 1382,
+ "section": "Setext headings"
+ },
+ {
+ "markdown": "Foo\n-------------------------\n\nFoo\n=\n",
+ "html": "<h2>Foo</h2>\n<h1>Foo</h1>\n",
+ "example": 83,
+ "start_line": 1387,
+ "end_line": 1396,
+ "section": "Setext headings"
+ },
+ {
+ "markdown": " Foo\n---\n\n Foo\n-----\n\n Foo\n ===\n",
+ "html": "<h2>Foo</h2>\n<h2>Foo</h2>\n<h1>Foo</h1>\n",
+ "example": 84,
+ "start_line": 1402,
+ "end_line": 1415,
+ "section": "Setext headings"
+ },
+ {
+ "markdown": " Foo\n ---\n\n Foo\n---\n",
+ "html": "<pre><code>Foo\n---\n\nFoo\n</code></pre>\n<hr />\n",
+ "example": 85,
+ "start_line": 1420,
+ "end_line": 1433,
+ "section": "Setext headings"
+ },
+ {
+ "markdown": "Foo\n ---- \n",
+ "html": "<h2>Foo</h2>\n",
+ "example": 86,
+ "start_line": 1439,
+ "end_line": 1444,
+ "section": "Setext headings"
+ },
+ {
+ "markdown": "Foo\n ---\n",
+ "html": "<p>Foo\n---</p>\n",
+ "example": 87,
+ "start_line": 1449,
+ "end_line": 1455,
+ "section": "Setext headings"
+ },
+ {
+ "markdown": "Foo\n= =\n\nFoo\n--- -\n",
+ "html": "<p>Foo\n= =</p>\n<p>Foo</p>\n<hr />\n",
+ "example": 88,
+ "start_line": 1460,
+ "end_line": 1471,
+ "section": "Setext headings"
+ },
+ {
+ "markdown": "Foo \n-----\n",
+ "html": "<h2>Foo</h2>\n",
+ "example": 89,
+ "start_line": 1476,
+ "end_line": 1481,
+ "section": "Setext headings"
+ },
+ {
+ "markdown": "Foo\\\n----\n",
+ "html": "<h2>Foo\\</h2>\n",
+ "example": 90,
+ "start_line": 1486,
+ "end_line": 1491,
+ "section": "Setext headings"
+ },
+ {
+ "markdown": "`Foo\n----\n`\n\n<a title=\"a lot\n---\nof dashes\"/>\n",
+ "html": "<h2>`Foo</h2>\n<p>`</p>\n<h2><a title="a lot</h2>\n<p>of dashes"/></p>\n",
+ "example": 91,
+ "start_line": 1497,
+ "end_line": 1510,
+ "section": "Setext headings"
+ },
+ {
+ "markdown": "> Foo\n---\n",
+ "html": "<blockquote>\n<p>Foo</p>\n</blockquote>\n<hr />\n",
+ "example": 92,
+ "start_line": 1516,
+ "end_line": 1524,
+ "section": "Setext headings"
+ },
+ {
+ "markdown": "> foo\nbar\n===\n",
+ "html": "<blockquote>\n<p>foo\nbar\n===</p>\n</blockquote>\n",
+ "example": 93,
+ "start_line": 1527,
+ "end_line": 1537,
+ "section": "Setext headings"
+ },
+ {
+ "markdown": "- Foo\n---\n",
+ "html": "<ul>\n<li>Foo</li>\n</ul>\n<hr />\n",
+ "example": 94,
+ "start_line": 1540,
+ "end_line": 1548,
+ "section": "Setext headings"
+ },
+ {
+ "markdown": "Foo\nBar\n---\n",
+ "html": "<h2>Foo\nBar</h2>\n",
+ "example": 95,
+ "start_line": 1555,
+ "end_line": 1562,
+ "section": "Setext headings"
+ },
+ {
+ "markdown": "---\nFoo\n---\nBar\n---\nBaz\n",
+ "html": "<hr />\n<h2>Foo</h2>\n<h2>Bar</h2>\n<p>Baz</p>\n",
+ "example": 96,
+ "start_line": 1568,
+ "end_line": 1580,
+ "section": "Setext headings"
+ },
+ {
+ "markdown": "\n====\n",
+ "html": "<p>====</p>\n",
+ "example": 97,
+ "start_line": 1585,
+ "end_line": 1590,
+ "section": "Setext headings"
+ },
+ {
+ "markdown": "---\n---\n",
+ "html": "<hr />\n<hr />\n",
+ "example": 98,
+ "start_line": 1597,
+ "end_line": 1603,
+ "section": "Setext headings"
+ },
+ {
+ "markdown": "- foo\n-----\n",
+ "html": "<ul>\n<li>foo</li>\n</ul>\n<hr />\n",
+ "example": 99,
+ "start_line": 1606,
+ "end_line": 1614,
+ "section": "Setext headings"
+ },
+ {
+ "markdown": " foo\n---\n",
+ "html": "<pre><code>foo\n</code></pre>\n<hr />\n",
+ "example": 100,
+ "start_line": 1617,
+ "end_line": 1624,
+ "section": "Setext headings"
+ },
+ {
+ "markdown": "> foo\n-----\n",
+ "html": "<blockquote>\n<p>foo</p>\n</blockquote>\n<hr />\n",
+ "example": 101,
+ "start_line": 1627,
+ "end_line": 1635,
+ "section": "Setext headings"
+ },
+ {
+ "markdown": "\\> foo\n------\n",
+ "html": "<h2>> foo</h2>\n",
+ "example": 102,
+ "start_line": 1641,
+ "end_line": 1646,
+ "section": "Setext headings"
+ },
+ {
+ "markdown": "Foo\n\nbar\n---\nbaz\n",
+ "html": "<p>Foo</p>\n<h2>bar</h2>\n<p>baz</p>\n",
+ "example": 103,
+ "start_line": 1672,
+ "end_line": 1682,
+ "section": "Setext headings"
+ },
+ {
+ "markdown": "Foo\nbar\n\n---\n\nbaz\n",
+ "html": "<p>Foo\nbar</p>\n<hr />\n<p>baz</p>\n",
+ "example": 104,
+ "start_line": 1688,
+ "end_line": 1700,
+ "section": "Setext headings"
+ },
+ {
+ "markdown": "Foo\nbar\n* * *\nbaz\n",
+ "html": "<p>Foo\nbar</p>\n<hr />\n<p>baz</p>\n",
+ "example": 105,
+ "start_line": 1706,
+ "end_line": 1716,
+ "section": "Setext headings"
+ },
+ {
+ "markdown": "Foo\nbar\n\\---\nbaz\n",
+ "html": "<p>Foo\nbar\n---\nbaz</p>\n",
+ "example": 106,
+ "start_line": 1721,
+ "end_line": 1731,
+ "section": "Setext headings"
+ },
+ {
+ "markdown": " a simple\n indented code block\n",
+ "html": "<pre><code>a simple\n indented code block\n</code></pre>\n",
+ "example": 107,
+ "start_line": 1749,
+ "end_line": 1756,
+ "section": "Indented code blocks"
+ },
+ {
+ "markdown": " - foo\n\n bar\n",
+ "html": "<ul>\n<li>\n<p>foo</p>\n<p>bar</p>\n</li>\n</ul>\n",
+ "example": 108,
+ "start_line": 1763,
+ "end_line": 1774,
+ "section": "Indented code blocks"
+ },
+ {
+ "markdown": "1. foo\n\n - bar\n",
+ "html": "<ol>\n<li>\n<p>foo</p>\n<ul>\n<li>bar</li>\n</ul>\n</li>\n</ol>\n",
+ "example": 109,
+ "start_line": 1777,
+ "end_line": 1790,
+ "section": "Indented code blocks"
+ },
+ {
+ "markdown": " <a/>\n *hi*\n\n - one\n",
+ "html": "<pre><code><a/>\n*hi*\n\n- one\n</code></pre>\n",
+ "example": 110,
+ "start_line": 1797,
+ "end_line": 1808,
+ "section": "Indented code blocks"
+ },
+ {
+ "markdown": " chunk1\n\n chunk2\n \n \n \n chunk3\n",
+ "html": "<pre><code>chunk1\n\nchunk2\n\n\n\nchunk3\n</code></pre>\n",
+ "example": 111,
+ "start_line": 1813,
+ "end_line": 1830,
+ "section": "Indented code blocks"
+ },
+ {
+ "markdown": " chunk1\n \n chunk2\n",
+ "html": "<pre><code>chunk1\n \n chunk2\n</code></pre>\n",
+ "example": 112,
+ "start_line": 1836,
+ "end_line": 1845,
+ "section": "Indented code blocks"
+ },
+ {
+ "markdown": "Foo\n bar\n\n",
+ "html": "<p>Foo\nbar</p>\n",
+ "example": 113,
+ "start_line": 1851,
+ "end_line": 1858,
+ "section": "Indented code blocks"
+ },
+ {
+ "markdown": " foo\nbar\n",
+ "html": "<pre><code>foo\n</code></pre>\n<p>bar</p>\n",
+ "example": 114,
+ "start_line": 1865,
+ "end_line": 1872,
+ "section": "Indented code blocks"
+ },
+ {
+ "markdown": "# Heading\n foo\nHeading\n------\n foo\n----\n",
+ "html": "<h1>Heading</h1>\n<pre><code>foo\n</code></pre>\n<h2>Heading</h2>\n<pre><code>foo\n</code></pre>\n<hr />\n",
+ "example": 115,
+ "start_line": 1878,
+ "end_line": 1893,
+ "section": "Indented code blocks"
+ },
+ {
+ "markdown": " foo\n bar\n",
+ "html": "<pre><code> foo\nbar\n</code></pre>\n",
+ "example": 116,
+ "start_line": 1898,
+ "end_line": 1905,
+ "section": "Indented code blocks"
+ },
+ {
+ "markdown": "\n \n foo\n \n\n",
+ "html": "<pre><code>foo\n</code></pre>\n",
+ "example": 117,
+ "start_line": 1911,
+ "end_line": 1920,
+ "section": "Indented code blocks"
+ },
+ {
+ "markdown": " foo \n",
+ "html": "<pre><code>foo \n</code></pre>\n",
+ "example": 118,
+ "start_line": 1925,
+ "end_line": 1930,
+ "section": "Indented code blocks"
+ },
+ {
+ "markdown": "```\n<\n >\n```\n",
+ "html": "<pre><code><\n >\n</code></pre>\n",
+ "example": 119,
+ "start_line": 1980,
+ "end_line": 1989,
+ "section": "Fenced code blocks"
+ },
+ {
+ "markdown": "~~~\n<\n >\n~~~\n",
+ "html": "<pre><code><\n >\n</code></pre>\n",
+ "example": 120,
+ "start_line": 1994,
+ "end_line": 2003,
+ "section": "Fenced code blocks"
+ },
+ {
+ "markdown": "``\nfoo\n``\n",
+ "html": "<p><code>foo</code></p>\n",
+ "example": 121,
+ "start_line": 2007,
+ "end_line": 2013,
+ "section": "Fenced code blocks"
+ },
+ {
+ "markdown": "```\naaa\n~~~\n```\n",
+ "html": "<pre><code>aaa\n~~~\n</code></pre>\n",
+ "example": 122,
+ "start_line": 2018,
+ "end_line": 2027,
+ "section": "Fenced code blocks"
+ },
+ {
+ "markdown": "~~~\naaa\n```\n~~~\n",
+ "html": "<pre><code>aaa\n```\n</code></pre>\n",
+ "example": 123,
+ "start_line": 2030,
+ "end_line": 2039,
+ "section": "Fenced code blocks"
+ },
+ {
+ "markdown": "````\naaa\n```\n``````\n",
+ "html": "<pre><code>aaa\n```\n</code></pre>\n",
+ "example": 124,
+ "start_line": 2044,
+ "end_line": 2053,
+ "section": "Fenced code blocks"
+ },
+ {
+ "markdown": "~~~~\naaa\n~~~\n~~~~\n",
+ "html": "<pre><code>aaa\n~~~\n</code></pre>\n",
+ "example": 125,
+ "start_line": 2056,
+ "end_line": 2065,
+ "section": "Fenced code blocks"
+ },
+ {
+ "markdown": "```\n",
+ "html": "<pre><code></code></pre>\n",
+ "example": 126,
+ "start_line": 2071,
+ "end_line": 2075,
+ "section": "Fenced code blocks"
+ },
+ {
+ "markdown": "`````\n\n```\naaa\n",
+ "html": "<pre><code>\n```\naaa\n</code></pre>\n",
+ "example": 127,
+ "start_line": 2078,
+ "end_line": 2088,
+ "section": "Fenced code blocks"
+ },
+ {
+ "markdown": "> ```\n> aaa\n\nbbb\n",
+ "html": "<blockquote>\n<pre><code>aaa\n</code></pre>\n</blockquote>\n<p>bbb</p>\n",
+ "example": 128,
+ "start_line": 2091,
+ "end_line": 2102,
+ "section": "Fenced code blocks"
+ },
+ {
+ "markdown": "```\n\n \n```\n",
+ "html": "<pre><code>\n \n</code></pre>\n",
+ "example": 129,
+ "start_line": 2107,
+ "end_line": 2116,
+ "section": "Fenced code blocks"
+ },
+ {
+ "markdown": "```\n```\n",
+ "html": "<pre><code></code></pre>\n",
+ "example": 130,
+ "start_line": 2121,
+ "end_line": 2126,
+ "section": "Fenced code blocks"
+ },
+ {
+ "markdown": " ```\n aaa\naaa\n```\n",
+ "html": "<pre><code>aaa\naaa\n</code></pre>\n",
+ "example": 131,
+ "start_line": 2133,
+ "end_line": 2142,
+ "section": "Fenced code blocks"
+ },
+ {
+ "markdown": " ```\naaa\n aaa\naaa\n ```\n",
+ "html": "<pre><code>aaa\naaa\naaa\n</code></pre>\n",
+ "example": 132,
+ "start_line": 2145,
+ "end_line": 2156,
+ "section": "Fenced code blocks"
+ },
+ {
+ "markdown": " ```\n aaa\n aaa\n aaa\n ```\n",
+ "html": "<pre><code>aaa\n aaa\naaa\n</code></pre>\n",
+ "example": 133,
+ "start_line": 2159,
+ "end_line": 2170,
+ "section": "Fenced code blocks"
+ },
+ {
+ "markdown": " ```\n aaa\n ```\n",
+ "html": "<pre><code>```\naaa\n```\n</code></pre>\n",
+ "example": 134,
+ "start_line": 2175,
+ "end_line": 2184,
+ "section": "Fenced code blocks"
+ },
+ {
+ "markdown": "```\naaa\n ```\n",
+ "html": "<pre><code>aaa\n</code></pre>\n",
+ "example": 135,
+ "start_line": 2190,
+ "end_line": 2197,
+ "section": "Fenced code blocks"
+ },
+ {
+ "markdown": " ```\naaa\n ```\n",
+ "html": "<pre><code>aaa\n</code></pre>\n",
+ "example": 136,
+ "start_line": 2200,
+ "end_line": 2207,
+ "section": "Fenced code blocks"
+ },
+ {
+ "markdown": "```\naaa\n ```\n",
+ "html": "<pre><code>aaa\n ```\n</code></pre>\n",
+ "example": 137,
+ "start_line": 2212,
+ "end_line": 2220,
+ "section": "Fenced code blocks"
+ },
+ {
+ "markdown": "``` ```\naaa\n",
+ "html": "<p><code> </code>\naaa</p>\n",
+ "example": 138,
+ "start_line": 2226,
+ "end_line": 2232,
+ "section": "Fenced code blocks"
+ },
+ {
+ "markdown": "~~~~~~\naaa\n~~~ ~~\n",
+ "html": "<pre><code>aaa\n~~~ ~~\n</code></pre>\n",
+ "example": 139,
+ "start_line": 2235,
+ "end_line": 2243,
+ "section": "Fenced code blocks"
+ },
+ {
+ "markdown": "foo\n```\nbar\n```\nbaz\n",
+ "html": "<p>foo</p>\n<pre><code>bar\n</code></pre>\n<p>baz</p>\n",
+ "example": 140,
+ "start_line": 2249,
+ "end_line": 2260,
+ "section": "Fenced code blocks"
+ },
+ {
+ "markdown": "foo\n---\n~~~\nbar\n~~~\n# baz\n",
+ "html": "<h2>foo</h2>\n<pre><code>bar\n</code></pre>\n<h1>baz</h1>\n",
+ "example": 141,
+ "start_line": 2266,
+ "end_line": 2278,
+ "section": "Fenced code blocks"
+ },
+ {
+ "markdown": "```ruby\ndef foo(x)\n return 3\nend\n```\n",
+ "html": "<pre><code class=\"language-ruby\">def foo(x)\n return 3\nend\n</code></pre>\n",
+ "example": 142,
+ "start_line": 2288,
+ "end_line": 2299,
+ "section": "Fenced code blocks"
+ },
+ {
+ "markdown": "~~~~ ruby startline=3 $%@#$\ndef foo(x)\n return 3\nend\n~~~~~~~\n",
+ "html": "<pre><code class=\"language-ruby\">def foo(x)\n return 3\nend\n</code></pre>\n",
+ "example": 143,
+ "start_line": 2302,
+ "end_line": 2313,
+ "section": "Fenced code blocks"
+ },
+ {
+ "markdown": "````;\n````\n",
+ "html": "<pre><code class=\"language-;\"></code></pre>\n",
+ "example": 144,
+ "start_line": 2316,
+ "end_line": 2321,
+ "section": "Fenced code blocks"
+ },
+ {
+ "markdown": "``` aa ```\nfoo\n",
+ "html": "<p><code>aa</code>\nfoo</p>\n",
+ "example": 145,
+ "start_line": 2326,
+ "end_line": 2332,
+ "section": "Fenced code blocks"
+ },
+ {
+ "markdown": "~~~ aa ``` ~~~\nfoo\n~~~\n",
+ "html": "<pre><code class=\"language-aa\">foo\n</code></pre>\n",
+ "example": 146,
+ "start_line": 2337,
+ "end_line": 2344,
+ "section": "Fenced code blocks"
+ },
+ {
+ "markdown": "```\n``` aaa\n```\n",
+ "html": "<pre><code>``` aaa\n</code></pre>\n",
+ "example": 147,
+ "start_line": 2349,
+ "end_line": 2356,
+ "section": "Fenced code blocks"
+ },
+ {
+ "markdown": "<table><tr><td>\n<pre>\n**Hello**,\n\n_world_.\n</pre>\n</td></tr></table>\n",
+ "html": "<table><tr><td>\n<pre>\n**Hello**,\n<p><em>world</em>.\n</pre></p>\n</td></tr></table>\n",
+ "example": 148,
+ "start_line": 2428,
+ "end_line": 2443,
+ "section": "HTML blocks"
+ },
+ {
+ "markdown": "<table>\n <tr>\n <td>\n hi\n </td>\n </tr>\n</table>\n\nokay.\n",
+ "html": "<table>\n <tr>\n <td>\n hi\n </td>\n </tr>\n</table>\n<p>okay.</p>\n",
+ "example": 149,
+ "start_line": 2457,
+ "end_line": 2476,
+ "section": "HTML blocks"
+ },
+ {
+ "markdown": " <div>\n *hello*\n <foo><a>\n",
+ "html": " <div>\n *hello*\n <foo><a>\n",
+ "example": 150,
+ "start_line": 2479,
+ "end_line": 2487,
+ "section": "HTML blocks"
+ },
+ {
+ "markdown": "</div>\n*foo*\n",
+ "html": "</div>\n*foo*\n",
+ "example": 151,
+ "start_line": 2492,
+ "end_line": 2498,
+ "section": "HTML blocks"
+ },
+ {
+ "markdown": "<DIV CLASS=\"foo\">\n\n*Markdown*\n\n</DIV>\n",
+ "html": "<DIV CLASS=\"foo\">\n<p><em>Markdown</em></p>\n</DIV>\n",
+ "example": 152,
+ "start_line": 2503,
+ "end_line": 2513,
+ "section": "HTML blocks"
+ },
+ {
+ "markdown": "<div id=\"foo\"\n class=\"bar\">\n</div>\n",
+ "html": "<div id=\"foo\"\n class=\"bar\">\n</div>\n",
+ "example": 153,
+ "start_line": 2519,
+ "end_line": 2527,
+ "section": "HTML blocks"
+ },
+ {
+ "markdown": "<div id=\"foo\" class=\"bar\n baz\">\n</div>\n",
+ "html": "<div id=\"foo\" class=\"bar\n baz\">\n</div>\n",
+ "example": 154,
+ "start_line": 2530,
+ "end_line": 2538,
+ "section": "HTML blocks"
+ },
+ {
+ "markdown": "<div>\n*foo*\n\n*bar*\n",
+ "html": "<div>\n*foo*\n<p><em>bar</em></p>\n",
+ "example": 155,
+ "start_line": 2542,
+ "end_line": 2551,
+ "section": "HTML blocks"
+ },
+ {
+ "markdown": "<div id=\"foo\"\n*hi*\n",
+ "html": "<div id=\"foo\"\n*hi*\n",
+ "example": 156,
+ "start_line": 2558,
+ "end_line": 2564,
+ "section": "HTML blocks"
+ },
+ {
+ "markdown": "<div class\nfoo\n",
+ "html": "<div class\nfoo\n",
+ "example": 157,
+ "start_line": 2567,
+ "end_line": 2573,
+ "section": "HTML blocks"
+ },
+ {
+ "markdown": "<div *???-&&&-<---\n*foo*\n",
+ "html": "<div *???-&&&-<---\n*foo*\n",
+ "example": 158,
+ "start_line": 2579,
+ "end_line": 2585,
+ "section": "HTML blocks"
+ },
+ {
+ "markdown": "<div><a href=\"bar\">*foo*</a></div>\n",
+ "html": "<div><a href=\"bar\">*foo*</a></div>\n",
+ "example": 159,
+ "start_line": 2591,
+ "end_line": 2595,
+ "section": "HTML blocks"
+ },
+ {
+ "markdown": "<table><tr><td>\nfoo\n</td></tr></table>\n",
+ "html": "<table><tr><td>\nfoo\n</td></tr></table>\n",
+ "example": 160,
+ "start_line": 2598,
+ "end_line": 2606,
+ "section": "HTML blocks"
+ },
+ {
+ "markdown": "<div></div>\n``` c\nint x = 33;\n```\n",
+ "html": "<div></div>\n``` c\nint x = 33;\n```\n",
+ "example": 161,
+ "start_line": 2615,
+ "end_line": 2625,
+ "section": "HTML blocks"
+ },
+ {
+ "markdown": "<a href=\"foo\">\n*bar*\n</a>\n",
+ "html": "<a href=\"foo\">\n*bar*\n</a>\n",
+ "example": 162,
+ "start_line": 2632,
+ "end_line": 2640,
+ "section": "HTML blocks"
+ },
+ {
+ "markdown": "<Warning>\n*bar*\n</Warning>\n",
+ "html": "<Warning>\n*bar*\n</Warning>\n",
+ "example": 163,
+ "start_line": 2645,
+ "end_line": 2653,
+ "section": "HTML blocks"
+ },
+ {
+ "markdown": "<i class=\"foo\">\n*bar*\n</i>\n",
+ "html": "<i class=\"foo\">\n*bar*\n</i>\n",
+ "example": 164,
+ "start_line": 2656,
+ "end_line": 2664,
+ "section": "HTML blocks"
+ },
+ {
+ "markdown": "</ins>\n*bar*\n",
+ "html": "</ins>\n*bar*\n",
+ "example": 165,
+ "start_line": 2667,
+ "end_line": 2673,
+ "section": "HTML blocks"
+ },
+ {
+ "markdown": "<del>\n*foo*\n</del>\n",
+ "html": "<del>\n*foo*\n</del>\n",
+ "example": 166,
+ "start_line": 2682,
+ "end_line": 2690,
+ "section": "HTML blocks"
+ },
+ {
+ "markdown": "<del>\n\n*foo*\n\n</del>\n",
+ "html": "<del>\n<p><em>foo</em></p>\n</del>\n",
+ "example": 167,
+ "start_line": 2697,
+ "end_line": 2707,
+ "section": "HTML blocks"
+ },
+ {
+ "markdown": "<del>*foo*</del>\n",
+ "html": "<p><del><em>foo</em></del></p>\n",
+ "example": 168,
+ "start_line": 2715,
+ "end_line": 2719,
+ "section": "HTML blocks"
+ },
+ {
+ "markdown": "<pre language=\"haskell\"><code>\nimport Text.HTML.TagSoup\n\nmain :: IO ()\nmain = print $ parseTags tags\n</code></pre>\nokay\n",
+ "html": "<pre language=\"haskell\"><code>\nimport Text.HTML.TagSoup\n\nmain :: IO ()\nmain = print $ parseTags tags\n</code></pre>\n<p>okay</p>\n",
+ "example": 169,
+ "start_line": 2731,
+ "end_line": 2747,
+ "section": "HTML blocks"
+ },
+ {
+ "markdown": "<script type=\"text/javascript\">\n// JavaScript example\n\ndocument.getElementById(\"demo\").innerHTML = \"Hello JavaScript!\";\n</script>\nokay\n",
+ "html": "<script type=\"text/javascript\">\n// JavaScript example\n\ndocument.getElementById(\"demo\").innerHTML = \"Hello JavaScript!\";\n</script>\n<p>okay</p>\n",
+ "example": 170,
+ "start_line": 2752,
+ "end_line": 2766,
+ "section": "HTML blocks"
+ },
+ {
+ "markdown": "<textarea>\n\n*foo*\n\n_bar_\n\n</textarea>\n",
+ "html": "<textarea>\n\n*foo*\n\n_bar_\n\n</textarea>\n",
+ "example": 171,
+ "start_line": 2771,
+ "end_line": 2787,
+ "section": "HTML blocks"
+ },
+ {
+ "markdown": "<style\n type=\"text/css\">\nh1 {color:red;}\n\np {color:blue;}\n</style>\nokay\n",
+ "html": "<style\n type=\"text/css\">\nh1 {color:red;}\n\np {color:blue;}\n</style>\n<p>okay</p>\n",
+ "example": 172,
+ "start_line": 2791,
+ "end_line": 2807,
+ "section": "HTML blocks"
+ },
+ {
+ "markdown": "<style\n type=\"text/css\">\n\nfoo\n",
+ "html": "<style\n type=\"text/css\">\n\nfoo\n",
+ "example": 173,
+ "start_line": 2814,
+ "end_line": 2824,
+ "section": "HTML blocks"
+ },
+ {
+ "markdown": "> <div>\n> foo\n\nbar\n",
+ "html": "<blockquote>\n<div>\nfoo\n</blockquote>\n<p>bar</p>\n",
+ "example": 174,
+ "start_line": 2827,
+ "end_line": 2838,
+ "section": "HTML blocks"
+ },
+ {
+ "markdown": "- <div>\n- foo\n",
+ "html": "<ul>\n<li>\n<div>\n</li>\n<li>foo</li>\n</ul>\n",
+ "example": 175,
+ "start_line": 2841,
+ "end_line": 2851,
+ "section": "HTML blocks"
+ },
+ {
+ "markdown": "<style>p{color:red;}</style>\n*foo*\n",
+ "html": "<style>p{color:red;}</style>\n<p><em>foo</em></p>\n",
+ "example": 176,
+ "start_line": 2856,
+ "end_line": 2862,
+ "section": "HTML blocks"
+ },
+ {
+ "markdown": "<!-- foo -->*bar*\n*baz*\n",
+ "html": "<!-- foo -->*bar*\n<p><em>baz</em></p>\n",
+ "example": 177,
+ "start_line": 2865,
+ "end_line": 2871,
+ "section": "HTML blocks"
+ },
+ {
+ "markdown": "<script>\nfoo\n</script>1. *bar*\n",
+ "html": "<script>\nfoo\n</script>1. *bar*\n",
+ "example": 178,
+ "start_line": 2877,
+ "end_line": 2885,
+ "section": "HTML blocks"
+ },
+ {
+ "markdown": "<!-- Foo\n\nbar\n baz -->\nokay\n",
+ "html": "<!-- Foo\n\nbar\n baz -->\n<p>okay</p>\n",
+ "example": 179,
+ "start_line": 2890,
+ "end_line": 2902,
+ "section": "HTML blocks"
+ },
+ {
+ "markdown": "<?php\n\n echo '>';\n\n?>\nokay\n",
+ "html": "<?php\n\n echo '>';\n\n?>\n<p>okay</p>\n",
+ "example": 180,
+ "start_line": 2908,
+ "end_line": 2922,
+ "section": "HTML blocks"
+ },
+ {
+ "markdown": "<!DOCTYPE html>\n",
+ "html": "<!DOCTYPE html>\n",
+ "example": 181,
+ "start_line": 2927,
+ "end_line": 2931,
+ "section": "HTML blocks"
+ },
+ {
+ "markdown": "<![CDATA[\nfunction matchwo(a,b)\n{\n if (a < b && a < 0) then {\n return 1;\n\n } else {\n\n return 0;\n }\n}\n]]>\nokay\n",
+ "html": "<![CDATA[\nfunction matchwo(a,b)\n{\n if (a < b && a < 0) then {\n return 1;\n\n } else {\n\n return 0;\n }\n}\n]]>\n<p>okay</p>\n",
+ "example": 182,
+ "start_line": 2936,
+ "end_line": 2964,
+ "section": "HTML blocks"
+ },
+ {
+ "markdown": " <!-- foo -->\n\n <!-- foo -->\n",
+ "html": " <!-- foo -->\n<pre><code><!-- foo -->\n</code></pre>\n",
+ "example": 183,
+ "start_line": 2970,
+ "end_line": 2978,
+ "section": "HTML blocks"
+ },
+ {
+ "markdown": " <div>\n\n <div>\n",
+ "html": " <div>\n<pre><code><div>\n</code></pre>\n",
+ "example": 184,
+ "start_line": 2981,
+ "end_line": 2989,
+ "section": "HTML blocks"
+ },
+ {
+ "markdown": "Foo\n<div>\nbar\n</div>\n",
+ "html": "<p>Foo</p>\n<div>\nbar\n</div>\n",
+ "example": 185,
+ "start_line": 2995,
+ "end_line": 3005,
+ "section": "HTML blocks"
+ },
+ {
+ "markdown": "<div>\nbar\n</div>\n*foo*\n",
+ "html": "<div>\nbar\n</div>\n*foo*\n",
+ "example": 186,
+ "start_line": 3012,
+ "end_line": 3022,
+ "section": "HTML blocks"
+ },
+ {
+ "markdown": "Foo\n<a href=\"bar\">\nbaz\n",
+ "html": "<p>Foo\n<a href=\"bar\">\nbaz</p>\n",
+ "example": 187,
+ "start_line": 3027,
+ "end_line": 3035,
+ "section": "HTML blocks"
+ },
+ {
+ "markdown": "<div>\n\n*Emphasized* text.\n\n</div>\n",
+ "html": "<div>\n<p><em>Emphasized</em> text.</p>\n</div>\n",
+ "example": 188,
+ "start_line": 3068,
+ "end_line": 3078,
+ "section": "HTML blocks"
+ },
+ {
+ "markdown": "<div>\n*Emphasized* text.\n</div>\n",
+ "html": "<div>\n*Emphasized* text.\n</div>\n",
+ "example": 189,
+ "start_line": 3081,
+ "end_line": 3089,
+ "section": "HTML blocks"
+ },
+ {
+ "markdown": "<table>\n\n<tr>\n\n<td>\nHi\n</td>\n\n</tr>\n\n</table>\n",
+ "html": "<table>\n<tr>\n<td>\nHi\n</td>\n</tr>\n</table>\n",
+ "example": 190,
+ "start_line": 3103,
+ "end_line": 3123,
+ "section": "HTML blocks"
+ },
+ {
+ "markdown": "<table>\n\n <tr>\n\n <td>\n Hi\n </td>\n\n </tr>\n\n</table>\n",
+ "html": "<table>\n <tr>\n<pre><code><td>\n Hi\n</td>\n</code></pre>\n </tr>\n</table>\n",
+ "example": 191,
+ "start_line": 3130,
+ "end_line": 3151,
+ "section": "HTML blocks"
+ },
+ {
+ "markdown": "[foo]: /url \"title\"\n\n[foo]\n",
+ "html": "<p><a href=\"/url\" title=\"title\">foo</a></p>\n",
+ "example": 192,
+ "start_line": 3179,
+ "end_line": 3185,
+ "section": "Link reference definitions"
+ },
+ {
+ "markdown": " [foo]: \n /url \n 'the title' \n\n[foo]\n",
+ "html": "<p><a href=\"/url\" title=\"the title\">foo</a></p>\n",
+ "example": 193,
+ "start_line": 3188,
+ "end_line": 3196,
+ "section": "Link reference definitions"
+ },
+ {
+ "markdown": "[Foo*bar\\]]:my_(url) 'title (with parens)'\n\n[Foo*bar\\]]\n",
+ "html": "<p><a href=\"my_(url)\" title=\"title (with parens)\">Foo*bar]</a></p>\n",
+ "example": 194,
+ "start_line": 3199,
+ "end_line": 3205,
+ "section": "Link reference definitions"
+ },
+ {
+ "markdown": "[Foo bar]:\n<my url>\n'title'\n\n[Foo bar]\n",
+ "html": "<p><a href=\"my%20url\" title=\"title\">Foo bar</a></p>\n",
+ "example": 195,
+ "start_line": 3208,
+ "end_line": 3216,
+ "section": "Link reference definitions"
+ },
+ {
+ "markdown": "[foo]: /url '\ntitle\nline1\nline2\n'\n\n[foo]\n",
+ "html": "<p><a href=\"/url\" title=\"\ntitle\nline1\nline2\n\">foo</a></p>\n",
+ "example": 196,
+ "start_line": 3221,
+ "end_line": 3235,
+ "section": "Link reference definitions"
+ },
+ {
+ "markdown": "[foo]: /url 'title\n\nwith blank line'\n\n[foo]\n",
+ "html": "<p>[foo]: /url 'title</p>\n<p>with blank line'</p>\n<p>[foo]</p>\n",
+ "example": 197,
+ "start_line": 3240,
+ "end_line": 3250,
+ "section": "Link reference definitions"
+ },
+ {
+ "markdown": "[foo]:\n/url\n\n[foo]\n",
+ "html": "<p><a href=\"/url\">foo</a></p>\n",
+ "example": 198,
+ "start_line": 3255,
+ "end_line": 3262,
+ "section": "Link reference definitions"
+ },
+ {
+ "markdown": "[foo]:\n\n[foo]\n",
+ "html": "<p>[foo]:</p>\n<p>[foo]</p>\n",
+ "example": 199,
+ "start_line": 3267,
+ "end_line": 3274,
+ "section": "Link reference definitions"
+ },
+ {
+ "markdown": "[foo]: <>\n\n[foo]\n",
+ "html": "<p><a href=\"\">foo</a></p>\n",
+ "example": 200,
+ "start_line": 3279,
+ "end_line": 3285,
+ "section": "Link reference definitions"
+ },
+ {
+ "markdown": "[foo]: <bar>(baz)\n\n[foo]\n",
+ "html": "<p>[foo]: <bar>(baz)</p>\n<p>[foo]</p>\n",
+ "example": 201,
+ "start_line": 3290,
+ "end_line": 3297,
+ "section": "Link reference definitions"
+ },
+ {
+ "markdown": "[foo]: /url\\bar\\*baz \"foo\\\"bar\\baz\"\n\n[foo]\n",
+ "html": "<p><a href=\"/url%5Cbar*baz\" title=\"foo"bar\\baz\">foo</a></p>\n",
+ "example": 202,
+ "start_line": 3303,
+ "end_line": 3309,
+ "section": "Link reference definitions"
+ },
+ {
+ "markdown": "[foo]\n\n[foo]: url\n",
+ "html": "<p><a href=\"url\">foo</a></p>\n",
+ "example": 203,
+ "start_line": 3314,
+ "end_line": 3320,
+ "section": "Link reference definitions"
+ },
+ {
+ "markdown": "[foo]\n\n[foo]: first\n[foo]: second\n",
+ "html": "<p><a href=\"first\">foo</a></p>\n",
+ "example": 204,
+ "start_line": 3326,
+ "end_line": 3333,
+ "section": "Link reference definitions"
+ },
+ {
+ "markdown": "[FOO]: /url\n\n[Foo]\n",
+ "html": "<p><a href=\"/url\">Foo</a></p>\n",
+ "example": 205,
+ "start_line": 3339,
+ "end_line": 3345,
+ "section": "Link reference definitions"
+ },
+ {
+ "markdown": "[ΑΓΩ]: /φου\n\n[αγω]\n",
+ "html": "<p><a href=\"/%CF%86%CE%BF%CF%85\">αγω</a></p>\n",
+ "example": 206,
+ "start_line": 3348,
+ "end_line": 3354,
+ "section": "Link reference definitions"
+ },
+ {
+ "markdown": "[foo]: /url\n",
+ "html": "",
+ "example": 207,
+ "start_line": 3363,
+ "end_line": 3366,
+ "section": "Link reference definitions"
+ },
+ {
+ "markdown": "[\nfoo\n]: /url\nbar\n",
+ "html": "<p>bar</p>\n",
+ "example": 208,
+ "start_line": 3371,
+ "end_line": 3378,
+ "section": "Link reference definitions"
+ },
+ {
+ "markdown": "[foo]: /url \"title\" ok\n",
+ "html": "<p>[foo]: /url "title" ok</p>\n",
+ "example": 209,
+ "start_line": 3384,
+ "end_line": 3388,
+ "section": "Link reference definitions"
+ },
+ {
+ "markdown": "[foo]: /url\n\"title\" ok\n",
+ "html": "<p>"title" ok</p>\n",
+ "example": 210,
+ "start_line": 3393,
+ "end_line": 3398,
+ "section": "Link reference definitions"
+ },
+ {
+ "markdown": " [foo]: /url \"title\"\n\n[foo]\n",
+ "html": "<pre><code>[foo]: /url "title"\n</code></pre>\n<p>[foo]</p>\n",
+ "example": 211,
+ "start_line": 3404,
+ "end_line": 3412,
+ "section": "Link reference definitions"
+ },
+ {
+ "markdown": "```\n[foo]: /url\n```\n\n[foo]\n",
+ "html": "<pre><code>[foo]: /url\n</code></pre>\n<p>[foo]</p>\n",
+ "example": 212,
+ "start_line": 3418,
+ "end_line": 3428,
+ "section": "Link reference definitions"
+ },
+ {
+ "markdown": "Foo\n[bar]: /baz\n\n[bar]\n",
+ "html": "<p>Foo\n[bar]: /baz</p>\n<p>[bar]</p>\n",
+ "example": 213,
+ "start_line": 3433,
+ "end_line": 3442,
+ "section": "Link reference definitions"
+ },
+ {
+ "markdown": "# [Foo]\n[foo]: /url\n> bar\n",
+ "html": "<h1><a href=\"/url\">Foo</a></h1>\n<blockquote>\n<p>bar</p>\n</blockquote>\n",
+ "example": 214,
+ "start_line": 3448,
+ "end_line": 3457,
+ "section": "Link reference definitions"
+ },
+ {
+ "markdown": "[foo]: /url\nbar\n===\n[foo]\n",
+ "html": "<h1>bar</h1>\n<p><a href=\"/url\">foo</a></p>\n",
+ "example": 215,
+ "start_line": 3459,
+ "end_line": 3467,
+ "section": "Link reference definitions"
+ },
+ {
+ "markdown": "[foo]: /url\n===\n[foo]\n",
+ "html": "<p>===\n<a href=\"/url\">foo</a></p>\n",
+ "example": 216,
+ "start_line": 3469,
+ "end_line": 3476,
+ "section": "Link reference definitions"
+ },
+ {
+ "markdown": "[foo]: /foo-url \"foo\"\n[bar]: /bar-url\n \"bar\"\n[baz]: /baz-url\n\n[foo],\n[bar],\n[baz]\n",
+ "html": "<p><a href=\"/foo-url\" title=\"foo\">foo</a>,\n<a href=\"/bar-url\" title=\"bar\">bar</a>,\n<a href=\"/baz-url\">baz</a></p>\n",
+ "example": 217,
+ "start_line": 3482,
+ "end_line": 3495,
+ "section": "Link reference definitions"
+ },
+ {
+ "markdown": "[foo]\n\n> [foo]: /url\n",
+ "html": "<p><a href=\"/url\">foo</a></p>\n<blockquote>\n</blockquote>\n",
+ "example": 218,
+ "start_line": 3503,
+ "end_line": 3511,
+ "section": "Link reference definitions"
+ },
+ {
+ "markdown": "aaa\n\nbbb\n",
+ "html": "<p>aaa</p>\n<p>bbb</p>\n",
+ "example": 219,
+ "start_line": 3525,
+ "end_line": 3532,
+ "section": "Paragraphs"
+ },
+ {
+ "markdown": "aaa\nbbb\n\nccc\nddd\n",
+ "html": "<p>aaa\nbbb</p>\n<p>ccc\nddd</p>\n",
+ "example": 220,
+ "start_line": 3537,
+ "end_line": 3548,
+ "section": "Paragraphs"
+ },
+ {
+ "markdown": "aaa\n\n\nbbb\n",
+ "html": "<p>aaa</p>\n<p>bbb</p>\n",
+ "example": 221,
+ "start_line": 3553,
+ "end_line": 3561,
+ "section": "Paragraphs"
+ },
+ {
+ "markdown": " aaa\n bbb\n",
+ "html": "<p>aaa\nbbb</p>\n",
+ "example": 222,
+ "start_line": 3566,
+ "end_line": 3572,
+ "section": "Paragraphs"
+ },
+ {
+ "markdown": "aaa\n bbb\n ccc\n",
+ "html": "<p>aaa\nbbb\nccc</p>\n",
+ "example": 223,
+ "start_line": 3578,
+ "end_line": 3586,
+ "section": "Paragraphs"
+ },
+ {
+ "markdown": " aaa\nbbb\n",
+ "html": "<p>aaa\nbbb</p>\n",
+ "example": 224,
+ "start_line": 3592,
+ "end_line": 3598,
+ "section": "Paragraphs"
+ },
+ {
+ "markdown": " aaa\nbbb\n",
+ "html": "<pre><code>aaa\n</code></pre>\n<p>bbb</p>\n",
+ "example": 225,
+ "start_line": 3601,
+ "end_line": 3608,
+ "section": "Paragraphs"
+ },
+ {
+ "markdown": "aaa \nbbb \n",
+ "html": "<p>aaa<br />\nbbb</p>\n",
+ "example": 226,
+ "start_line": 3615,
+ "end_line": 3621,
+ "section": "Paragraphs"
+ },
+ {
+ "markdown": " \n\naaa\n \n\n# aaa\n\n \n",
+ "html": "<p>aaa</p>\n<h1>aaa</h1>\n",
+ "example": 227,
+ "start_line": 3632,
+ "end_line": 3644,
+ "section": "Blank lines"
+ },
+ {
+ "markdown": "> # Foo\n> bar\n> baz\n",
+ "html": "<blockquote>\n<h1>Foo</h1>\n<p>bar\nbaz</p>\n</blockquote>\n",
+ "example": 228,
+ "start_line": 3700,
+ "end_line": 3710,
+ "section": "Block quotes"
+ },
+ {
+ "markdown": "># Foo\n>bar\n> baz\n",
+ "html": "<blockquote>\n<h1>Foo</h1>\n<p>bar\nbaz</p>\n</blockquote>\n",
+ "example": 229,
+ "start_line": 3715,
+ "end_line": 3725,
+ "section": "Block quotes"
+ },
+ {
+ "markdown": " > # Foo\n > bar\n > baz\n",
+ "html": "<blockquote>\n<h1>Foo</h1>\n<p>bar\nbaz</p>\n</blockquote>\n",
+ "example": 230,
+ "start_line": 3730,
+ "end_line": 3740,
+ "section": "Block quotes"
+ },
+ {
+ "markdown": " > # Foo\n > bar\n > baz\n",
+ "html": "<pre><code>> # Foo\n> bar\n> baz\n</code></pre>\n",
+ "example": 231,
+ "start_line": 3745,
+ "end_line": 3754,
+ "section": "Block quotes"
+ },
+ {
+ "markdown": "> # Foo\n> bar\nbaz\n",
+ "html": "<blockquote>\n<h1>Foo</h1>\n<p>bar\nbaz</p>\n</blockquote>\n",
+ "example": 232,
+ "start_line": 3760,
+ "end_line": 3770,
+ "section": "Block quotes"
+ },
+ {
+ "markdown": "> bar\nbaz\n> foo\n",
+ "html": "<blockquote>\n<p>bar\nbaz\nfoo</p>\n</blockquote>\n",
+ "example": 233,
+ "start_line": 3776,
+ "end_line": 3786,
+ "section": "Block quotes"
+ },
+ {
+ "markdown": "> foo\n---\n",
+ "html": "<blockquote>\n<p>foo</p>\n</blockquote>\n<hr />\n",
+ "example": 234,
+ "start_line": 3800,
+ "end_line": 3808,
+ "section": "Block quotes"
+ },
+ {
+ "markdown": "> - foo\n- bar\n",
+ "html": "<blockquote>\n<ul>\n<li>foo</li>\n</ul>\n</blockquote>\n<ul>\n<li>bar</li>\n</ul>\n",
+ "example": 235,
+ "start_line": 3820,
+ "end_line": 3832,
+ "section": "Block quotes"
+ },
+ {
+ "markdown": "> foo\n bar\n",
+ "html": "<blockquote>\n<pre><code>foo\n</code></pre>\n</blockquote>\n<pre><code>bar\n</code></pre>\n",
+ "example": 236,
+ "start_line": 3838,
+ "end_line": 3848,
+ "section": "Block quotes"
+ },
+ {
+ "markdown": "> ```\nfoo\n```\n",
+ "html": "<blockquote>\n<pre><code></code></pre>\n</blockquote>\n<p>foo</p>\n<pre><code></code></pre>\n",
+ "example": 237,
+ "start_line": 3851,
+ "end_line": 3861,
+ "section": "Block quotes"
+ },
+ {
+ "markdown": "> foo\n - bar\n",
+ "html": "<blockquote>\n<p>foo\n- bar</p>\n</blockquote>\n",
+ "example": 238,
+ "start_line": 3867,
+ "end_line": 3875,
+ "section": "Block quotes"
+ },
+ {
+ "markdown": ">\n",
+ "html": "<blockquote>\n</blockquote>\n",
+ "example": 239,
+ "start_line": 3891,
+ "end_line": 3896,
+ "section": "Block quotes"
+ },
+ {
+ "markdown": ">\n> \n> \n",
+ "html": "<blockquote>\n</blockquote>\n",
+ "example": 240,
+ "start_line": 3899,
+ "end_line": 3906,
+ "section": "Block quotes"
+ },
+ {
+ "markdown": ">\n> foo\n> \n",
+ "html": "<blockquote>\n<p>foo</p>\n</blockquote>\n",
+ "example": 241,
+ "start_line": 3911,
+ "end_line": 3919,
+ "section": "Block quotes"
+ },
+ {
+ "markdown": "> foo\n\n> bar\n",
+ "html": "<blockquote>\n<p>foo</p>\n</blockquote>\n<blockquote>\n<p>bar</p>\n</blockquote>\n",
+ "example": 242,
+ "start_line": 3924,
+ "end_line": 3935,
+ "section": "Block quotes"
+ },
+ {
+ "markdown": "> foo\n> bar\n",
+ "html": "<blockquote>\n<p>foo\nbar</p>\n</blockquote>\n",
+ "example": 243,
+ "start_line": 3946,
+ "end_line": 3954,
+ "section": "Block quotes"
+ },
+ {
+ "markdown": "> foo\n>\n> bar\n",
+ "html": "<blockquote>\n<p>foo</p>\n<p>bar</p>\n</blockquote>\n",
+ "example": 244,
+ "start_line": 3959,
+ "end_line": 3968,
+ "section": "Block quotes"
+ },
+ {
+ "markdown": "foo\n> bar\n",
+ "html": "<p>foo</p>\n<blockquote>\n<p>bar</p>\n</blockquote>\n",
+ "example": 245,
+ "start_line": 3973,
+ "end_line": 3981,
+ "section": "Block quotes"
+ },
+ {
+ "markdown": "> aaa\n***\n> bbb\n",
+ "html": "<blockquote>\n<p>aaa</p>\n</blockquote>\n<hr />\n<blockquote>\n<p>bbb</p>\n</blockquote>\n",
+ "example": 246,
+ "start_line": 3987,
+ "end_line": 3999,
+ "section": "Block quotes"
+ },
+ {
+ "markdown": "> bar\nbaz\n",
+ "html": "<blockquote>\n<p>bar\nbaz</p>\n</blockquote>\n",
+ "example": 247,
+ "start_line": 4005,
+ "end_line": 4013,
+ "section": "Block quotes"
+ },
+ {
+ "markdown": "> bar\n\nbaz\n",
+ "html": "<blockquote>\n<p>bar</p>\n</blockquote>\n<p>baz</p>\n",
+ "example": 248,
+ "start_line": 4016,
+ "end_line": 4025,
+ "section": "Block quotes"
+ },
+ {
+ "markdown": "> bar\n>\nbaz\n",
+ "html": "<blockquote>\n<p>bar</p>\n</blockquote>\n<p>baz</p>\n",
+ "example": 249,
+ "start_line": 4028,
+ "end_line": 4037,
+ "section": "Block quotes"
+ },
+ {
+ "markdown": "> > > foo\nbar\n",
+ "html": "<blockquote>\n<blockquote>\n<blockquote>\n<p>foo\nbar</p>\n</blockquote>\n</blockquote>\n</blockquote>\n",
+ "example": 250,
+ "start_line": 4044,
+ "end_line": 4056,
+ "section": "Block quotes"
+ },
+ {
+ "markdown": ">>> foo\n> bar\n>>baz\n",
+ "html": "<blockquote>\n<blockquote>\n<blockquote>\n<p>foo\nbar\nbaz</p>\n</blockquote>\n</blockquote>\n</blockquote>\n",
+ "example": 251,
+ "start_line": 4059,
+ "end_line": 4073,
+ "section": "Block quotes"
+ },
+ {
+ "markdown": "> code\n\n> not code\n",
+ "html": "<blockquote>\n<pre><code>code\n</code></pre>\n</blockquote>\n<blockquote>\n<p>not code</p>\n</blockquote>\n",
+ "example": 252,
+ "start_line": 4081,
+ "end_line": 4093,
+ "section": "Block quotes"
+ },
+ {
+ "markdown": "A paragraph\nwith two lines.\n\n indented code\n\n> A block quote.\n",
+ "html": "<p>A paragraph\nwith two lines.</p>\n<pre><code>indented code\n</code></pre>\n<blockquote>\n<p>A block quote.</p>\n</blockquote>\n",
+ "example": 253,
+ "start_line": 4135,
+ "end_line": 4150,
+ "section": "List items"
+ },
+ {
+ "markdown": "1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.\n",
+ "html": "<ol>\n<li>\n<p>A paragraph\nwith two lines.</p>\n<pre><code>indented code\n</code></pre>\n<blockquote>\n<p>A block quote.</p>\n</blockquote>\n</li>\n</ol>\n",
+ "example": 254,
+ "start_line": 4157,
+ "end_line": 4176,
+ "section": "List items"
+ },
+ {
+ "markdown": "- one\n\n two\n",
+ "html": "<ul>\n<li>one</li>\n</ul>\n<p>two</p>\n",
+ "example": 255,
+ "start_line": 4190,
+ "end_line": 4199,
+ "section": "List items"
+ },
+ {
+ "markdown": "- one\n\n two\n",
+ "html": "<ul>\n<li>\n<p>one</p>\n<p>two</p>\n</li>\n</ul>\n",
+ "example": 256,
+ "start_line": 4202,
+ "end_line": 4213,
+ "section": "List items"
+ },
+ {
+ "markdown": " - one\n\n two\n",
+ "html": "<ul>\n<li>one</li>\n</ul>\n<pre><code> two\n</code></pre>\n",
+ "example": 257,
+ "start_line": 4216,
+ "end_line": 4226,
+ "section": "List items"
+ },
+ {
+ "markdown": " - one\n\n two\n",
+ "html": "<ul>\n<li>\n<p>one</p>\n<p>two</p>\n</li>\n</ul>\n",
+ "example": 258,
+ "start_line": 4229,
+ "end_line": 4240,
+ "section": "List items"
+ },
+ {
+ "markdown": " > > 1. one\n>>\n>> two\n",
+ "html": "<blockquote>\n<blockquote>\n<ol>\n<li>\n<p>one</p>\n<p>two</p>\n</li>\n</ol>\n</blockquote>\n</blockquote>\n",
+ "example": 259,
+ "start_line": 4251,
+ "end_line": 4266,
+ "section": "List items"
+ },
+ {
+ "markdown": ">>- one\n>>\n > > two\n",
+ "html": "<blockquote>\n<blockquote>\n<ul>\n<li>one</li>\n</ul>\n<p>two</p>\n</blockquote>\n</blockquote>\n",
+ "example": 260,
+ "start_line": 4278,
+ "end_line": 4291,
+ "section": "List items"
+ },
+ {
+ "markdown": "-one\n\n2.two\n",
+ "html": "<p>-one</p>\n<p>2.two</p>\n",
+ "example": 261,
+ "start_line": 4297,
+ "end_line": 4304,
+ "section": "List items"
+ },
+ {
+ "markdown": "- foo\n\n\n bar\n",
+ "html": "<ul>\n<li>\n<p>foo</p>\n<p>bar</p>\n</li>\n</ul>\n",
+ "example": 262,
+ "start_line": 4310,
+ "end_line": 4322,
+ "section": "List items"
+ },
+ {
+ "markdown": "1. foo\n\n ```\n bar\n ```\n\n baz\n\n > bam\n",
+ "html": "<ol>\n<li>\n<p>foo</p>\n<pre><code>bar\n</code></pre>\n<p>baz</p>\n<blockquote>\n<p>bam</p>\n</blockquote>\n</li>\n</ol>\n",
+ "example": 263,
+ "start_line": 4327,
+ "end_line": 4349,
+ "section": "List items"
+ },
+ {
+ "markdown": "- Foo\n\n bar\n\n\n baz\n",
+ "html": "<ul>\n<li>\n<p>Foo</p>\n<pre><code>bar\n\n\nbaz\n</code></pre>\n</li>\n</ul>\n",
+ "example": 264,
+ "start_line": 4355,
+ "end_line": 4373,
+ "section": "List items"
+ },
+ {
+ "markdown": "123456789. ok\n",
+ "html": "<ol start=\"123456789\">\n<li>ok</li>\n</ol>\n",
+ "example": 265,
+ "start_line": 4377,
+ "end_line": 4383,
+ "section": "List items"
+ },
+ {
+ "markdown": "1234567890. not ok\n",
+ "html": "<p>1234567890. not ok</p>\n",
+ "example": 266,
+ "start_line": 4386,
+ "end_line": 4390,
+ "section": "List items"
+ },
+ {
+ "markdown": "0. ok\n",
+ "html": "<ol start=\"0\">\n<li>ok</li>\n</ol>\n",
+ "example": 267,
+ "start_line": 4395,
+ "end_line": 4401,
+ "section": "List items"
+ },
+ {
+ "markdown": "003. ok\n",
+ "html": "<ol start=\"3\">\n<li>ok</li>\n</ol>\n",
+ "example": 268,
+ "start_line": 4404,
+ "end_line": 4410,
+ "section": "List items"
+ },
+ {
+ "markdown": "-1. not ok\n",
+ "html": "<p>-1. not ok</p>\n",
+ "example": 269,
+ "start_line": 4415,
+ "end_line": 4419,
+ "section": "List items"
+ },
+ {
+ "markdown": "- foo\n\n bar\n",
+ "html": "<ul>\n<li>\n<p>foo</p>\n<pre><code>bar\n</code></pre>\n</li>\n</ul>\n",
+ "example": 270,
+ "start_line": 4438,
+ "end_line": 4450,
+ "section": "List items"
+ },
+ {
+ "markdown": " 10. foo\n\n bar\n",
+ "html": "<ol start=\"10\">\n<li>\n<p>foo</p>\n<pre><code>bar\n</code></pre>\n</li>\n</ol>\n",
+ "example": 271,
+ "start_line": 4455,
+ "end_line": 4467,
+ "section": "List items"
+ },
+ {
+ "markdown": " indented code\n\nparagraph\n\n more code\n",
+ "html": "<pre><code>indented code\n</code></pre>\n<p>paragraph</p>\n<pre><code>more code\n</code></pre>\n",
+ "example": 272,
+ "start_line": 4474,
+ "end_line": 4486,
+ "section": "List items"
+ },
+ {
+ "markdown": "1. indented code\n\n paragraph\n\n more code\n",
+ "html": "<ol>\n<li>\n<pre><code>indented code\n</code></pre>\n<p>paragraph</p>\n<pre><code>more code\n</code></pre>\n</li>\n</ol>\n",
+ "example": 273,
+ "start_line": 4489,
+ "end_line": 4505,
+ "section": "List items"
+ },
+ {
+ "markdown": "1. indented code\n\n paragraph\n\n more code\n",
+ "html": "<ol>\n<li>\n<pre><code> indented code\n</code></pre>\n<p>paragraph</p>\n<pre><code>more code\n</code></pre>\n</li>\n</ol>\n",
+ "example": 274,
+ "start_line": 4511,
+ "end_line": 4527,
+ "section": "List items"
+ },
+ {
+ "markdown": " foo\n\nbar\n",
+ "html": "<p>foo</p>\n<p>bar</p>\n",
+ "example": 275,
+ "start_line": 4538,
+ "end_line": 4545,
+ "section": "List items"
+ },
+ {
+ "markdown": "- foo\n\n bar\n",
+ "html": "<ul>\n<li>foo</li>\n</ul>\n<p>bar</p>\n",
+ "example": 276,
+ "start_line": 4548,
+ "end_line": 4557,
+ "section": "List items"
+ },
+ {
+ "markdown": "- foo\n\n bar\n",
+ "html": "<ul>\n<li>\n<p>foo</p>\n<p>bar</p>\n</li>\n</ul>\n",
+ "example": 277,
+ "start_line": 4565,
+ "end_line": 4576,
+ "section": "List items"
+ },
+ {
+ "markdown": "-\n foo\n-\n ```\n bar\n ```\n-\n baz\n",
+ "html": "<ul>\n<li>foo</li>\n<li>\n<pre><code>bar\n</code></pre>\n</li>\n<li>\n<pre><code>baz\n</code></pre>\n</li>\n</ul>\n",
+ "example": 278,
+ "start_line": 4592,
+ "end_line": 4613,
+ "section": "List items"
+ },
+ {
+ "markdown": "- \n foo\n",
+ "html": "<ul>\n<li>foo</li>\n</ul>\n",
+ "example": 279,
+ "start_line": 4618,
+ "end_line": 4625,
+ "section": "List items"
+ },
+ {
+ "markdown": "-\n\n foo\n",
+ "html": "<ul>\n<li></li>\n</ul>\n<p>foo</p>\n",
+ "example": 280,
+ "start_line": 4632,
+ "end_line": 4641,
+ "section": "List items"
+ },
+ {
+ "markdown": "- foo\n-\n- bar\n",
+ "html": "<ul>\n<li>foo</li>\n<li></li>\n<li>bar</li>\n</ul>\n",
+ "example": 281,
+ "start_line": 4646,
+ "end_line": 4656,
+ "section": "List items"
+ },
+ {
+ "markdown": "- foo\n- \n- bar\n",
+ "html": "<ul>\n<li>foo</li>\n<li></li>\n<li>bar</li>\n</ul>\n",
+ "example": 282,
+ "start_line": 4661,
+ "end_line": 4671,
+ "section": "List items"
+ },
+ {
+ "markdown": "1. foo\n2.\n3. bar\n",
+ "html": "<ol>\n<li>foo</li>\n<li></li>\n<li>bar</li>\n</ol>\n",
+ "example": 283,
+ "start_line": 4676,
+ "end_line": 4686,
+ "section": "List items"
+ },
+ {
+ "markdown": "*\n",
+ "html": "<ul>\n<li></li>\n</ul>\n",
+ "example": 284,
+ "start_line": 4691,
+ "end_line": 4697,
+ "section": "List items"
+ },
+ {
+ "markdown": "foo\n*\n\nfoo\n1.\n",
+ "html": "<p>foo\n*</p>\n<p>foo\n1.</p>\n",
+ "example": 285,
+ "start_line": 4701,
+ "end_line": 4712,
+ "section": "List items"
+ },
+ {
+ "markdown": " 1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.\n",
+ "html": "<ol>\n<li>\n<p>A paragraph\nwith two lines.</p>\n<pre><code>indented code\n</code></pre>\n<blockquote>\n<p>A block quote.</p>\n</blockquote>\n</li>\n</ol>\n",
+ "example": 286,
+ "start_line": 4723,
+ "end_line": 4742,
+ "section": "List items"
+ },
+ {
+ "markdown": " 1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.\n",
+ "html": "<ol>\n<li>\n<p>A paragraph\nwith two lines.</p>\n<pre><code>indented code\n</code></pre>\n<blockquote>\n<p>A block quote.</p>\n</blockquote>\n</li>\n</ol>\n",
+ "example": 287,
+ "start_line": 4747,
+ "end_line": 4766,
+ "section": "List items"
+ },
+ {
+ "markdown": " 1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.\n",
+ "html": "<ol>\n<li>\n<p>A paragraph\nwith two lines.</p>\n<pre><code>indented code\n</code></pre>\n<blockquote>\n<p>A block quote.</p>\n</blockquote>\n</li>\n</ol>\n",
+ "example": 288,
+ "start_line": 4771,
+ "end_line": 4790,
+ "section": "List items"
+ },
+ {
+ "markdown": " 1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.\n",
+ "html": "<pre><code>1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.\n</code></pre>\n",
+ "example": 289,
+ "start_line": 4795,
+ "end_line": 4810,
+ "section": "List items"
+ },
+ {
+ "markdown": " 1. A paragraph\nwith two lines.\n\n indented code\n\n > A block quote.\n",
+ "html": "<ol>\n<li>\n<p>A paragraph\nwith two lines.</p>\n<pre><code>indented code\n</code></pre>\n<blockquote>\n<p>A block quote.</p>\n</blockquote>\n</li>\n</ol>\n",
+ "example": 290,
+ "start_line": 4825,
+ "end_line": 4844,
+ "section": "List items"
+ },
+ {
+ "markdown": " 1. A paragraph\n with two lines.\n",
+ "html": "<ol>\n<li>A paragraph\nwith two lines.</li>\n</ol>\n",
+ "example": 291,
+ "start_line": 4849,
+ "end_line": 4857,
+ "section": "List items"
+ },
+ {
+ "markdown": "> 1. > Blockquote\ncontinued here.\n",
+ "html": "<blockquote>\n<ol>\n<li>\n<blockquote>\n<p>Blockquote\ncontinued here.</p>\n</blockquote>\n</li>\n</ol>\n</blockquote>\n",
+ "example": 292,
+ "start_line": 4862,
+ "end_line": 4876,
+ "section": "List items"
+ },
+ {
+ "markdown": "> 1. > Blockquote\n> continued here.\n",
+ "html": "<blockquote>\n<ol>\n<li>\n<blockquote>\n<p>Blockquote\ncontinued here.</p>\n</blockquote>\n</li>\n</ol>\n</blockquote>\n",
+ "example": 293,
+ "start_line": 4879,
+ "end_line": 4893,
+ "section": "List items"
+ },
+ {
+ "markdown": "- foo\n - bar\n - baz\n - boo\n",
+ "html": "<ul>\n<li>foo\n<ul>\n<li>bar\n<ul>\n<li>baz\n<ul>\n<li>boo</li>\n</ul>\n</li>\n</ul>\n</li>\n</ul>\n</li>\n</ul>\n",
+ "example": 294,
+ "start_line": 4907,
+ "end_line": 4928,
+ "section": "List items"
+ },
+ {
+ "markdown": "- foo\n - bar\n - baz\n - boo\n",
+ "html": "<ul>\n<li>foo</li>\n<li>bar</li>\n<li>baz</li>\n<li>boo</li>\n</ul>\n",
+ "example": 295,
+ "start_line": 4933,
+ "end_line": 4945,
+ "section": "List items"
+ },
+ {
+ "markdown": "10) foo\n - bar\n",
+ "html": "<ol start=\"10\">\n<li>foo\n<ul>\n<li>bar</li>\n</ul>\n</li>\n</ol>\n",
+ "example": 296,
+ "start_line": 4950,
+ "end_line": 4961,
+ "section": "List items"
+ },
+ {
+ "markdown": "10) foo\n - bar\n",
+ "html": "<ol start=\"10\">\n<li>foo</li>\n</ol>\n<ul>\n<li>bar</li>\n</ul>\n",
+ "example": 297,
+ "start_line": 4966,
+ "end_line": 4976,
+ "section": "List items"
+ },
+ {
+ "markdown": "- - foo\n",
+ "html": "<ul>\n<li>\n<ul>\n<li>foo</li>\n</ul>\n</li>\n</ul>\n",
+ "example": 298,
+ "start_line": 4981,
+ "end_line": 4991,
+ "section": "List items"
+ },
+ {
+ "markdown": "1. - 2. foo\n",
+ "html": "<ol>\n<li>\n<ul>\n<li>\n<ol start=\"2\">\n<li>foo</li>\n</ol>\n</li>\n</ul>\n</li>\n</ol>\n",
+ "example": 299,
+ "start_line": 4994,
+ "end_line": 5008,
+ "section": "List items"
+ },
+ {
+ "markdown": "- # Foo\n- Bar\n ---\n baz\n",
+ "html": "<ul>\n<li>\n<h1>Foo</h1>\n</li>\n<li>\n<h2>Bar</h2>\nbaz</li>\n</ul>\n",
+ "example": 300,
+ "start_line": 5013,
+ "end_line": 5027,
+ "section": "List items"
+ },
+ {
+ "markdown": "- foo\n- bar\n+ baz\n",
+ "html": "<ul>\n<li>foo</li>\n<li>bar</li>\n</ul>\n<ul>\n<li>baz</li>\n</ul>\n",
+ "example": 301,
+ "start_line": 5249,
+ "end_line": 5261,
+ "section": "Lists"
+ },
+ {
+ "markdown": "1. foo\n2. bar\n3) baz\n",
+ "html": "<ol>\n<li>foo</li>\n<li>bar</li>\n</ol>\n<ol start=\"3\">\n<li>baz</li>\n</ol>\n",
+ "example": 302,
+ "start_line": 5264,
+ "end_line": 5276,
+ "section": "Lists"
+ },
+ {
+ "markdown": "Foo\n- bar\n- baz\n",
+ "html": "<p>Foo</p>\n<ul>\n<li>bar</li>\n<li>baz</li>\n</ul>\n",
+ "example": 303,
+ "start_line": 5283,
+ "end_line": 5293,
+ "section": "Lists"
+ },
+ {
+ "markdown": "The number of windows in my house is\n14. The number of doors is 6.\n",
+ "html": "<p>The number of windows in my house is\n14. The number of doors is 6.</p>\n",
+ "example": 304,
+ "start_line": 5360,
+ "end_line": 5366,
+ "section": "Lists"
+ },
+ {
+ "markdown": "The number of windows in my house is\n1. The number of doors is 6.\n",
+ "html": "<p>The number of windows in my house is</p>\n<ol>\n<li>The number of doors is 6.</li>\n</ol>\n",
+ "example": 305,
+ "start_line": 5370,
+ "end_line": 5378,
+ "section": "Lists"
+ },
+ {
+ "markdown": "- foo\n\n- bar\n\n\n- baz\n",
+ "html": "<ul>\n<li>\n<p>foo</p>\n</li>\n<li>\n<p>bar</p>\n</li>\n<li>\n<p>baz</p>\n</li>\n</ul>\n",
+ "example": 306,
+ "start_line": 5384,
+ "end_line": 5403,
+ "section": "Lists"
+ },
+ {
+ "markdown": "- foo\n - bar\n - baz\n\n\n bim\n",
+ "html": "<ul>\n<li>foo\n<ul>\n<li>bar\n<ul>\n<li>\n<p>baz</p>\n<p>bim</p>\n</li>\n</ul>\n</li>\n</ul>\n</li>\n</ul>\n",
+ "example": 307,
+ "start_line": 5405,
+ "end_line": 5427,
+ "section": "Lists"
+ },
+ {
+ "markdown": "- foo\n- bar\n\n<!-- -->\n\n- baz\n- bim\n",
+ "html": "<ul>\n<li>foo</li>\n<li>bar</li>\n</ul>\n<!-- -->\n<ul>\n<li>baz</li>\n<li>bim</li>\n</ul>\n",
+ "example": 308,
+ "start_line": 5435,
+ "end_line": 5453,
+ "section": "Lists"
+ },
+ {
+ "markdown": "- foo\n\n notcode\n\n- foo\n\n<!-- -->\n\n code\n",
+ "html": "<ul>\n<li>\n<p>foo</p>\n<p>notcode</p>\n</li>\n<li>\n<p>foo</p>\n</li>\n</ul>\n<!-- -->\n<pre><code>code\n</code></pre>\n",
+ "example": 309,
+ "start_line": 5456,
+ "end_line": 5479,
+ "section": "Lists"
+ },
+ {
+ "markdown": "- a\n - b\n - c\n - d\n - e\n - f\n- g\n",
+ "html": "<ul>\n<li>a</li>\n<li>b</li>\n<li>c</li>\n<li>d</li>\n<li>e</li>\n<li>f</li>\n<li>g</li>\n</ul>\n",
+ "example": 310,
+ "start_line": 5487,
+ "end_line": 5505,
+ "section": "Lists"
+ },
+ {
+ "markdown": "1. a\n\n 2. b\n\n 3. c\n",
+ "html": "<ol>\n<li>\n<p>a</p>\n</li>\n<li>\n<p>b</p>\n</li>\n<li>\n<p>c</p>\n</li>\n</ol>\n",
+ "example": 311,
+ "start_line": 5508,
+ "end_line": 5526,
+ "section": "Lists"
+ },
+ {
+ "markdown": "- a\n - b\n - c\n - d\n - e\n",
+ "html": "<ul>\n<li>a</li>\n<li>b</li>\n<li>c</li>\n<li>d\n- e</li>\n</ul>\n",
+ "example": 312,
+ "start_line": 5532,
+ "end_line": 5546,
+ "section": "Lists"
+ },
+ {
+ "markdown": "1. a\n\n 2. b\n\n 3. c\n",
+ "html": "<ol>\n<li>\n<p>a</p>\n</li>\n<li>\n<p>b</p>\n</li>\n</ol>\n<pre><code>3. c\n</code></pre>\n",
+ "example": 313,
+ "start_line": 5552,
+ "end_line": 5569,
+ "section": "Lists"
+ },
+ {
+ "markdown": "- a\n- b\n\n- c\n",
+ "html": "<ul>\n<li>\n<p>a</p>\n</li>\n<li>\n<p>b</p>\n</li>\n<li>\n<p>c</p>\n</li>\n</ul>\n",
+ "example": 314,
+ "start_line": 5575,
+ "end_line": 5592,
+ "section": "Lists"
+ },
+ {
+ "markdown": "* a\n*\n\n* c\n",
+ "html": "<ul>\n<li>\n<p>a</p>\n</li>\n<li></li>\n<li>\n<p>c</p>\n</li>\n</ul>\n",
+ "example": 315,
+ "start_line": 5597,
+ "end_line": 5612,
+ "section": "Lists"
+ },
+ {
+ "markdown": "- a\n- b\n\n c\n- d\n",
+ "html": "<ul>\n<li>\n<p>a</p>\n</li>\n<li>\n<p>b</p>\n<p>c</p>\n</li>\n<li>\n<p>d</p>\n</li>\n</ul>\n",
+ "example": 316,
+ "start_line": 5619,
+ "end_line": 5638,
+ "section": "Lists"
+ },
+ {
+ "markdown": "- a\n- b\n\n [ref]: /url\n- d\n",
+ "html": "<ul>\n<li>\n<p>a</p>\n</li>\n<li>\n<p>b</p>\n</li>\n<li>\n<p>d</p>\n</li>\n</ul>\n",
+ "example": 317,
+ "start_line": 5641,
+ "end_line": 5659,
+ "section": "Lists"
+ },
+ {
+ "markdown": "- a\n- ```\n b\n\n\n ```\n- c\n",
+ "html": "<ul>\n<li>a</li>\n<li>\n<pre><code>b\n\n\n</code></pre>\n</li>\n<li>c</li>\n</ul>\n",
+ "example": 318,
+ "start_line": 5664,
+ "end_line": 5683,
+ "section": "Lists"
+ },
+ {
+ "markdown": "- a\n - b\n\n c\n- d\n",
+ "html": "<ul>\n<li>a\n<ul>\n<li>\n<p>b</p>\n<p>c</p>\n</li>\n</ul>\n</li>\n<li>d</li>\n</ul>\n",
+ "example": 319,
+ "start_line": 5690,
+ "end_line": 5708,
+ "section": "Lists"
+ },
+ {
+ "markdown": "* a\n > b\n >\n* c\n",
+ "html": "<ul>\n<li>a\n<blockquote>\n<p>b</p>\n</blockquote>\n</li>\n<li>c</li>\n</ul>\n",
+ "example": 320,
+ "start_line": 5714,
+ "end_line": 5728,
+ "section": "Lists"
+ },
+ {
+ "markdown": "- a\n > b\n ```\n c\n ```\n- d\n",
+ "html": "<ul>\n<li>a\n<blockquote>\n<p>b</p>\n</blockquote>\n<pre><code>c\n</code></pre>\n</li>\n<li>d</li>\n</ul>\n",
+ "example": 321,
+ "start_line": 5734,
+ "end_line": 5752,
+ "section": "Lists"
+ },
+ {
+ "markdown": "- a\n",
+ "html": "<ul>\n<li>a</li>\n</ul>\n",
+ "example": 322,
+ "start_line": 5757,
+ "end_line": 5763,
+ "section": "Lists"
+ },
+ {
+ "markdown": "- a\n - b\n",
+ "html": "<ul>\n<li>a\n<ul>\n<li>b</li>\n</ul>\n</li>\n</ul>\n",
+ "example": 323,
+ "start_line": 5766,
+ "end_line": 5777,
+ "section": "Lists"
+ },
+ {
+ "markdown": "1. ```\n foo\n ```\n\n bar\n",
+ "html": "<ol>\n<li>\n<pre><code>foo\n</code></pre>\n<p>bar</p>\n</li>\n</ol>\n",
+ "example": 324,
+ "start_line": 5783,
+ "end_line": 5797,
+ "section": "Lists"
+ },
+ {
+ "markdown": "* foo\n * bar\n\n baz\n",
+ "html": "<ul>\n<li>\n<p>foo</p>\n<ul>\n<li>bar</li>\n</ul>\n<p>baz</p>\n</li>\n</ul>\n",
+ "example": 325,
+ "start_line": 5802,
+ "end_line": 5817,
+ "section": "Lists"
+ },
+ {
+ "markdown": "- a\n - b\n - c\n\n- d\n - e\n - f\n",
+ "html": "<ul>\n<li>\n<p>a</p>\n<ul>\n<li>b</li>\n<li>c</li>\n</ul>\n</li>\n<li>\n<p>d</p>\n<ul>\n<li>e</li>\n<li>f</li>\n</ul>\n</li>\n</ul>\n",
+ "example": 326,
+ "start_line": 5820,
+ "end_line": 5845,
+ "section": "Lists"
+ },
+ {
+ "markdown": "`hi`lo`\n",
+ "html": "<p><code>hi</code>lo`</p>\n",
+ "example": 327,
+ "start_line": 5854,
+ "end_line": 5858,
+ "section": "Inlines"
+ },
+ {
+ "markdown": "`foo`\n",
+ "html": "<p><code>foo</code></p>\n",
+ "example": 328,
+ "start_line": 5886,
+ "end_line": 5890,
+ "section": "Code spans"
+ },
+ {
+ "markdown": "`` foo ` bar ``\n",
+ "html": "<p><code>foo ` bar</code></p>\n",
+ "example": 329,
+ "start_line": 5897,
+ "end_line": 5901,
+ "section": "Code spans"
+ },
+ {
+ "markdown": "` `` `\n",
+ "html": "<p><code>``</code></p>\n",
+ "example": 330,
+ "start_line": 5907,
+ "end_line": 5911,
+ "section": "Code spans"
+ },
+ {
+ "markdown": "` `` `\n",
+ "html": "<p><code> `` </code></p>\n",
+ "example": 331,
+ "start_line": 5915,
+ "end_line": 5919,
+ "section": "Code spans"
+ },
+ {
+ "markdown": "` a`\n",
+ "html": "<p><code> a</code></p>\n",
+ "example": 332,
+ "start_line": 5924,
+ "end_line": 5928,
+ "section": "Code spans"
+ },
+ {
+ "markdown": "` b `\n",
+ "html": "<p><code> b </code></p>\n",
+ "example": 333,
+ "start_line": 5933,
+ "end_line": 5937,
+ "section": "Code spans"
+ },
+ {
+ "markdown": "` `\n` `\n",
+ "html": "<p><code> </code>\n<code> </code></p>\n",
+ "example": 334,
+ "start_line": 5941,
+ "end_line": 5947,
+ "section": "Code spans"
+ },
+ {
+ "markdown": "``\nfoo\nbar \nbaz\n``\n",
+ "html": "<p><code>foo bar baz</code></p>\n",
+ "example": 335,
+ "start_line": 5952,
+ "end_line": 5960,
+ "section": "Code spans"
+ },
+ {
+ "markdown": "``\nfoo \n``\n",
+ "html": "<p><code>foo </code></p>\n",
+ "example": 336,
+ "start_line": 5962,
+ "end_line": 5968,
+ "section": "Code spans"
+ },
+ {
+ "markdown": "`foo bar \nbaz`\n",
+ "html": "<p><code>foo bar baz</code></p>\n",
+ "example": 337,
+ "start_line": 5973,
+ "end_line": 5978,
+ "section": "Code spans"
+ },
+ {
+ "markdown": "`foo\\`bar`\n",
+ "html": "<p><code>foo\\</code>bar`</p>\n",
+ "example": 338,
+ "start_line": 5990,
+ "end_line": 5994,
+ "section": "Code spans"
+ },
+ {
+ "markdown": "``foo`bar``\n",
+ "html": "<p><code>foo`bar</code></p>\n",
+ "example": 339,
+ "start_line": 6001,
+ "end_line": 6005,
+ "section": "Code spans"
+ },
+ {
+ "markdown": "` foo `` bar `\n",
+ "html": "<p><code>foo `` bar</code></p>\n",
+ "example": 340,
+ "start_line": 6007,
+ "end_line": 6011,
+ "section": "Code spans"
+ },
+ {
+ "markdown": "*foo`*`\n",
+ "html": "<p>*foo<code>*</code></p>\n",
+ "example": 341,
+ "start_line": 6019,
+ "end_line": 6023,
+ "section": "Code spans"
+ },
+ {
+ "markdown": "[not a `link](/foo`)\n",
+ "html": "<p>[not a <code>link](/foo</code>)</p>\n",
+ "example": 342,
+ "start_line": 6028,
+ "end_line": 6032,
+ "section": "Code spans"
+ },
+ {
+ "markdown": "`<a href=\"`\">`\n",
+ "html": "<p><code><a href="</code>">`</p>\n",
+ "example": 343,
+ "start_line": 6038,
+ "end_line": 6042,
+ "section": "Code spans"
+ },
+ {
+ "markdown": "<a href=\"`\">`\n",
+ "html": "<p><a href=\"`\">`</p>\n",
+ "example": 344,
+ "start_line": 6047,
+ "end_line": 6051,
+ "section": "Code spans"
+ },
+ {
+ "markdown": "`<https://foo.bar.`baz>`\n",
+ "html": "<p><code><https://foo.bar.</code>baz>`</p>\n",
+ "example": 345,
+ "start_line": 6056,
+ "end_line": 6060,
+ "section": "Code spans"
+ },
+ {
+ "markdown": "<https://foo.bar.`baz>`\n",
+ "html": "<p><a href=\"https://foo.bar.%60baz\">https://foo.bar.`baz</a>`</p>\n",
+ "example": 346,
+ "start_line": 6065,
+ "end_line": 6069,
+ "section": "Code spans"
+ },
+ {
+ "markdown": "```foo``\n",
+ "html": "<p>```foo``</p>\n",
+ "example": 347,
+ "start_line": 6075,
+ "end_line": 6079,
+ "section": "Code spans"
+ },
+ {
+ "markdown": "`foo\n",
+ "html": "<p>`foo</p>\n",
+ "example": 348,
+ "start_line": 6082,
+ "end_line": 6086,
+ "section": "Code spans"
+ },
+ {
+ "markdown": "`foo``bar``\n",
+ "html": "<p>`foo<code>bar</code></p>\n",
+ "example": 349,
+ "start_line": 6091,
+ "end_line": 6095,
+ "section": "Code spans"
+ },
+ {
+ "markdown": "*foo bar*\n",
+ "html": "<p><em>foo bar</em></p>\n",
+ "example": 350,
+ "start_line": 6308,
+ "end_line": 6312,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "a * foo bar*\n",
+ "html": "<p>a * foo bar*</p>\n",
+ "example": 351,
+ "start_line": 6318,
+ "end_line": 6322,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "a*\"foo\"*\n",
+ "html": "<p>a*"foo"*</p>\n",
+ "example": 352,
+ "start_line": 6329,
+ "end_line": 6333,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "* a *\n",
+ "html": "<p>* a *</p>\n",
+ "example": 353,
+ "start_line": 6338,
+ "end_line": 6342,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "*$*alpha.\n\n*£*bravo.\n\n*€*charlie.\n",
+ "html": "<p>*$*alpha.</p>\n<p>*£*bravo.</p>\n<p>*€*charlie.</p>\n",
+ "example": 354,
+ "start_line": 6347,
+ "end_line": 6357,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "foo*bar*\n",
+ "html": "<p>foo<em>bar</em></p>\n",
+ "example": 355,
+ "start_line": 6362,
+ "end_line": 6366,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "5*6*78\n",
+ "html": "<p>5<em>6</em>78</p>\n",
+ "example": 356,
+ "start_line": 6369,
+ "end_line": 6373,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "_foo bar_\n",
+ "html": "<p><em>foo bar</em></p>\n",
+ "example": 357,
+ "start_line": 6378,
+ "end_line": 6382,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "_ foo bar_\n",
+ "html": "<p>_ foo bar_</p>\n",
+ "example": 358,
+ "start_line": 6388,
+ "end_line": 6392,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "a_\"foo\"_\n",
+ "html": "<p>a_"foo"_</p>\n",
+ "example": 359,
+ "start_line": 6398,
+ "end_line": 6402,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "foo_bar_\n",
+ "html": "<p>foo_bar_</p>\n",
+ "example": 360,
+ "start_line": 6407,
+ "end_line": 6411,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "5_6_78\n",
+ "html": "<p>5_6_78</p>\n",
+ "example": 361,
+ "start_line": 6414,
+ "end_line": 6418,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "пристаням_стремятся_\n",
+ "html": "<p>пристаням_стремятся_</p>\n",
+ "example": 362,
+ "start_line": 6421,
+ "end_line": 6425,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "aa_\"bb\"_cc\n",
+ "html": "<p>aa_"bb"_cc</p>\n",
+ "example": 363,
+ "start_line": 6431,
+ "end_line": 6435,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "foo-_(bar)_\n",
+ "html": "<p>foo-<em>(bar)</em></p>\n",
+ "example": 364,
+ "start_line": 6442,
+ "end_line": 6446,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "_foo*\n",
+ "html": "<p>_foo*</p>\n",
+ "example": 365,
+ "start_line": 6454,
+ "end_line": 6458,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "*foo bar *\n",
+ "html": "<p>*foo bar *</p>\n",
+ "example": 366,
+ "start_line": 6464,
+ "end_line": 6468,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "*foo bar\n*\n",
+ "html": "<p>*foo bar\n*</p>\n",
+ "example": 367,
+ "start_line": 6473,
+ "end_line": 6479,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "*(*foo)\n",
+ "html": "<p>*(*foo)</p>\n",
+ "example": 368,
+ "start_line": 6486,
+ "end_line": 6490,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "*(*foo*)*\n",
+ "html": "<p><em>(<em>foo</em>)</em></p>\n",
+ "example": 369,
+ "start_line": 6496,
+ "end_line": 6500,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "*foo*bar\n",
+ "html": "<p><em>foo</em>bar</p>\n",
+ "example": 370,
+ "start_line": 6505,
+ "end_line": 6509,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "_foo bar _\n",
+ "html": "<p>_foo bar _</p>\n",
+ "example": 371,
+ "start_line": 6518,
+ "end_line": 6522,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "_(_foo)\n",
+ "html": "<p>_(_foo)</p>\n",
+ "example": 372,
+ "start_line": 6528,
+ "end_line": 6532,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "_(_foo_)_\n",
+ "html": "<p><em>(<em>foo</em>)</em></p>\n",
+ "example": 373,
+ "start_line": 6537,
+ "end_line": 6541,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "_foo_bar\n",
+ "html": "<p>_foo_bar</p>\n",
+ "example": 374,
+ "start_line": 6546,
+ "end_line": 6550,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "_пристаням_стремятся\n",
+ "html": "<p>_пристаням_стремятся</p>\n",
+ "example": 375,
+ "start_line": 6553,
+ "end_line": 6557,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "_foo_bar_baz_\n",
+ "html": "<p><em>foo_bar_baz</em></p>\n",
+ "example": 376,
+ "start_line": 6560,
+ "end_line": 6564,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "_(bar)_.\n",
+ "html": "<p><em>(bar)</em>.</p>\n",
+ "example": 377,
+ "start_line": 6571,
+ "end_line": 6575,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "**foo bar**\n",
+ "html": "<p><strong>foo bar</strong></p>\n",
+ "example": 378,
+ "start_line": 6580,
+ "end_line": 6584,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "** foo bar**\n",
+ "html": "<p>** foo bar**</p>\n",
+ "example": 379,
+ "start_line": 6590,
+ "end_line": 6594,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "a**\"foo\"**\n",
+ "html": "<p>a**"foo"**</p>\n",
+ "example": 380,
+ "start_line": 6601,
+ "end_line": 6605,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "foo**bar**\n",
+ "html": "<p>foo<strong>bar</strong></p>\n",
+ "example": 381,
+ "start_line": 6610,
+ "end_line": 6614,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "__foo bar__\n",
+ "html": "<p><strong>foo bar</strong></p>\n",
+ "example": 382,
+ "start_line": 6619,
+ "end_line": 6623,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "__ foo bar__\n",
+ "html": "<p>__ foo bar__</p>\n",
+ "example": 383,
+ "start_line": 6629,
+ "end_line": 6633,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "__\nfoo bar__\n",
+ "html": "<p>__\nfoo bar__</p>\n",
+ "example": 384,
+ "start_line": 6637,
+ "end_line": 6643,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "a__\"foo\"__\n",
+ "html": "<p>a__"foo"__</p>\n",
+ "example": 385,
+ "start_line": 6649,
+ "end_line": 6653,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "foo__bar__\n",
+ "html": "<p>foo__bar__</p>\n",
+ "example": 386,
+ "start_line": 6658,
+ "end_line": 6662,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "5__6__78\n",
+ "html": "<p>5__6__78</p>\n",
+ "example": 387,
+ "start_line": 6665,
+ "end_line": 6669,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "пристаням__стремятся__\n",
+ "html": "<p>пристаням__стремятся__</p>\n",
+ "example": 388,
+ "start_line": 6672,
+ "end_line": 6676,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "__foo, __bar__, baz__\n",
+ "html": "<p><strong>foo, <strong>bar</strong>, baz</strong></p>\n",
+ "example": 389,
+ "start_line": 6679,
+ "end_line": 6683,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "foo-__(bar)__\n",
+ "html": "<p>foo-<strong>(bar)</strong></p>\n",
+ "example": 390,
+ "start_line": 6690,
+ "end_line": 6694,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "**foo bar **\n",
+ "html": "<p>**foo bar **</p>\n",
+ "example": 391,
+ "start_line": 6703,
+ "end_line": 6707,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "**(**foo)\n",
+ "html": "<p>**(**foo)</p>\n",
+ "example": 392,
+ "start_line": 6716,
+ "end_line": 6720,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "*(**foo**)*\n",
+ "html": "<p><em>(<strong>foo</strong>)</em></p>\n",
+ "example": 393,
+ "start_line": 6726,
+ "end_line": 6730,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "**Gomphocarpus (*Gomphocarpus physocarpus*, syn.\n*Asclepias physocarpa*)**\n",
+ "html": "<p><strong>Gomphocarpus (<em>Gomphocarpus physocarpus</em>, syn.\n<em>Asclepias physocarpa</em>)</strong></p>\n",
+ "example": 394,
+ "start_line": 6733,
+ "end_line": 6739,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "**foo \"*bar*\" foo**\n",
+ "html": "<p><strong>foo "<em>bar</em>" foo</strong></p>\n",
+ "example": 395,
+ "start_line": 6742,
+ "end_line": 6746,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "**foo**bar\n",
+ "html": "<p><strong>foo</strong>bar</p>\n",
+ "example": 396,
+ "start_line": 6751,
+ "end_line": 6755,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "__foo bar __\n",
+ "html": "<p>__foo bar __</p>\n",
+ "example": 397,
+ "start_line": 6763,
+ "end_line": 6767,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "__(__foo)\n",
+ "html": "<p>__(__foo)</p>\n",
+ "example": 398,
+ "start_line": 6773,
+ "end_line": 6777,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "_(__foo__)_\n",
+ "html": "<p><em>(<strong>foo</strong>)</em></p>\n",
+ "example": 399,
+ "start_line": 6783,
+ "end_line": 6787,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "__foo__bar\n",
+ "html": "<p>__foo__bar</p>\n",
+ "example": 400,
+ "start_line": 6792,
+ "end_line": 6796,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "__пристаням__стремятся\n",
+ "html": "<p>__пристаням__стремятся</p>\n",
+ "example": 401,
+ "start_line": 6799,
+ "end_line": 6803,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "__foo__bar__baz__\n",
+ "html": "<p><strong>foo__bar__baz</strong></p>\n",
+ "example": 402,
+ "start_line": 6806,
+ "end_line": 6810,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "__(bar)__.\n",
+ "html": "<p><strong>(bar)</strong>.</p>\n",
+ "example": 403,
+ "start_line": 6817,
+ "end_line": 6821,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "*foo [bar](/url)*\n",
+ "html": "<p><em>foo <a href=\"/url\">bar</a></em></p>\n",
+ "example": 404,
+ "start_line": 6829,
+ "end_line": 6833,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "*foo\nbar*\n",
+ "html": "<p><em>foo\nbar</em></p>\n",
+ "example": 405,
+ "start_line": 6836,
+ "end_line": 6842,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "_foo __bar__ baz_\n",
+ "html": "<p><em>foo <strong>bar</strong> baz</em></p>\n",
+ "example": 406,
+ "start_line": 6848,
+ "end_line": 6852,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "_foo _bar_ baz_\n",
+ "html": "<p><em>foo <em>bar</em> baz</em></p>\n",
+ "example": 407,
+ "start_line": 6855,
+ "end_line": 6859,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "__foo_ bar_\n",
+ "html": "<p><em><em>foo</em> bar</em></p>\n",
+ "example": 408,
+ "start_line": 6862,
+ "end_line": 6866,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "*foo *bar**\n",
+ "html": "<p><em>foo <em>bar</em></em></p>\n",
+ "example": 409,
+ "start_line": 6869,
+ "end_line": 6873,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "*foo **bar** baz*\n",
+ "html": "<p><em>foo <strong>bar</strong> baz</em></p>\n",
+ "example": 410,
+ "start_line": 6876,
+ "end_line": 6880,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "*foo**bar**baz*\n",
+ "html": "<p><em>foo<strong>bar</strong>baz</em></p>\n",
+ "example": 411,
+ "start_line": 6882,
+ "end_line": 6886,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "*foo**bar*\n",
+ "html": "<p><em>foo**bar</em></p>\n",
+ "example": 412,
+ "start_line": 6906,
+ "end_line": 6910,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "***foo** bar*\n",
+ "html": "<p><em><strong>foo</strong> bar</em></p>\n",
+ "example": 413,
+ "start_line": 6919,
+ "end_line": 6923,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "*foo **bar***\n",
+ "html": "<p><em>foo <strong>bar</strong></em></p>\n",
+ "example": 414,
+ "start_line": 6926,
+ "end_line": 6930,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "*foo**bar***\n",
+ "html": "<p><em>foo<strong>bar</strong></em></p>\n",
+ "example": 415,
+ "start_line": 6933,
+ "end_line": 6937,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "foo***bar***baz\n",
+ "html": "<p>foo<em><strong>bar</strong></em>baz</p>\n",
+ "example": 416,
+ "start_line": 6944,
+ "end_line": 6948,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "foo******bar*********baz\n",
+ "html": "<p>foo<strong><strong><strong>bar</strong></strong></strong>***baz</p>\n",
+ "example": 417,
+ "start_line": 6950,
+ "end_line": 6954,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "*foo **bar *baz* bim** bop*\n",
+ "html": "<p><em>foo <strong>bar <em>baz</em> bim</strong> bop</em></p>\n",
+ "example": 418,
+ "start_line": 6959,
+ "end_line": 6963,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "*foo [*bar*](/url)*\n",
+ "html": "<p><em>foo <a href=\"/url\"><em>bar</em></a></em></p>\n",
+ "example": 419,
+ "start_line": 6966,
+ "end_line": 6970,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "** is not an empty emphasis\n",
+ "html": "<p>** is not an empty emphasis</p>\n",
+ "example": 420,
+ "start_line": 6975,
+ "end_line": 6979,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "**** is not an empty strong emphasis\n",
+ "html": "<p>**** is not an empty strong emphasis</p>\n",
+ "example": 421,
+ "start_line": 6982,
+ "end_line": 6986,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "**foo [bar](/url)**\n",
+ "html": "<p><strong>foo <a href=\"/url\">bar</a></strong></p>\n",
+ "example": 422,
+ "start_line": 6995,
+ "end_line": 6999,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "**foo\nbar**\n",
+ "html": "<p><strong>foo\nbar</strong></p>\n",
+ "example": 423,
+ "start_line": 7002,
+ "end_line": 7008,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "__foo _bar_ baz__\n",
+ "html": "<p><strong>foo <em>bar</em> baz</strong></p>\n",
+ "example": 424,
+ "start_line": 7014,
+ "end_line": 7018,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "__foo __bar__ baz__\n",
+ "html": "<p><strong>foo <strong>bar</strong> baz</strong></p>\n",
+ "example": 425,
+ "start_line": 7021,
+ "end_line": 7025,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "____foo__ bar__\n",
+ "html": "<p><strong><strong>foo</strong> bar</strong></p>\n",
+ "example": 426,
+ "start_line": 7028,
+ "end_line": 7032,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "**foo **bar****\n",
+ "html": "<p><strong>foo <strong>bar</strong></strong></p>\n",
+ "example": 427,
+ "start_line": 7035,
+ "end_line": 7039,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "**foo *bar* baz**\n",
+ "html": "<p><strong>foo <em>bar</em> baz</strong></p>\n",
+ "example": 428,
+ "start_line": 7042,
+ "end_line": 7046,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "**foo*bar*baz**\n",
+ "html": "<p><strong>foo<em>bar</em>baz</strong></p>\n",
+ "example": 429,
+ "start_line": 7049,
+ "end_line": 7053,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "***foo* bar**\n",
+ "html": "<p><strong><em>foo</em> bar</strong></p>\n",
+ "example": 430,
+ "start_line": 7056,
+ "end_line": 7060,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "**foo *bar***\n",
+ "html": "<p><strong>foo <em>bar</em></strong></p>\n",
+ "example": 431,
+ "start_line": 7063,
+ "end_line": 7067,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "**foo *bar **baz**\nbim* bop**\n",
+ "html": "<p><strong>foo <em>bar <strong>baz</strong>\nbim</em> bop</strong></p>\n",
+ "example": 432,
+ "start_line": 7072,
+ "end_line": 7078,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "**foo [*bar*](/url)**\n",
+ "html": "<p><strong>foo <a href=\"/url\"><em>bar</em></a></strong></p>\n",
+ "example": 433,
+ "start_line": 7081,
+ "end_line": 7085,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "__ is not an empty emphasis\n",
+ "html": "<p>__ is not an empty emphasis</p>\n",
+ "example": 434,
+ "start_line": 7090,
+ "end_line": 7094,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "____ is not an empty strong emphasis\n",
+ "html": "<p>____ is not an empty strong emphasis</p>\n",
+ "example": 435,
+ "start_line": 7097,
+ "end_line": 7101,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "foo ***\n",
+ "html": "<p>foo ***</p>\n",
+ "example": 436,
+ "start_line": 7107,
+ "end_line": 7111,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "foo *\\**\n",
+ "html": "<p>foo <em>*</em></p>\n",
+ "example": 437,
+ "start_line": 7114,
+ "end_line": 7118,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "foo *_*\n",
+ "html": "<p>foo <em>_</em></p>\n",
+ "example": 438,
+ "start_line": 7121,
+ "end_line": 7125,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "foo *****\n",
+ "html": "<p>foo *****</p>\n",
+ "example": 439,
+ "start_line": 7128,
+ "end_line": 7132,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "foo **\\***\n",
+ "html": "<p>foo <strong>*</strong></p>\n",
+ "example": 440,
+ "start_line": 7135,
+ "end_line": 7139,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "foo **_**\n",
+ "html": "<p>foo <strong>_</strong></p>\n",
+ "example": 441,
+ "start_line": 7142,
+ "end_line": 7146,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "**foo*\n",
+ "html": "<p>*<em>foo</em></p>\n",
+ "example": 442,
+ "start_line": 7153,
+ "end_line": 7157,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "*foo**\n",
+ "html": "<p><em>foo</em>*</p>\n",
+ "example": 443,
+ "start_line": 7160,
+ "end_line": 7164,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "***foo**\n",
+ "html": "<p>*<strong>foo</strong></p>\n",
+ "example": 444,
+ "start_line": 7167,
+ "end_line": 7171,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "****foo*\n",
+ "html": "<p>***<em>foo</em></p>\n",
+ "example": 445,
+ "start_line": 7174,
+ "end_line": 7178,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "**foo***\n",
+ "html": "<p><strong>foo</strong>*</p>\n",
+ "example": 446,
+ "start_line": 7181,
+ "end_line": 7185,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "*foo****\n",
+ "html": "<p><em>foo</em>***</p>\n",
+ "example": 447,
+ "start_line": 7188,
+ "end_line": 7192,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "foo ___\n",
+ "html": "<p>foo ___</p>\n",
+ "example": 448,
+ "start_line": 7198,
+ "end_line": 7202,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "foo _\\__\n",
+ "html": "<p>foo <em>_</em></p>\n",
+ "example": 449,
+ "start_line": 7205,
+ "end_line": 7209,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "foo _*_\n",
+ "html": "<p>foo <em>*</em></p>\n",
+ "example": 450,
+ "start_line": 7212,
+ "end_line": 7216,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "foo _____\n",
+ "html": "<p>foo _____</p>\n",
+ "example": 451,
+ "start_line": 7219,
+ "end_line": 7223,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "foo __\\___\n",
+ "html": "<p>foo <strong>_</strong></p>\n",
+ "example": 452,
+ "start_line": 7226,
+ "end_line": 7230,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "foo __*__\n",
+ "html": "<p>foo <strong>*</strong></p>\n",
+ "example": 453,
+ "start_line": 7233,
+ "end_line": 7237,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "__foo_\n",
+ "html": "<p>_<em>foo</em></p>\n",
+ "example": 454,
+ "start_line": 7240,
+ "end_line": 7244,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "_foo__\n",
+ "html": "<p><em>foo</em>_</p>\n",
+ "example": 455,
+ "start_line": 7251,
+ "end_line": 7255,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "___foo__\n",
+ "html": "<p>_<strong>foo</strong></p>\n",
+ "example": 456,
+ "start_line": 7258,
+ "end_line": 7262,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "____foo_\n",
+ "html": "<p>___<em>foo</em></p>\n",
+ "example": 457,
+ "start_line": 7265,
+ "end_line": 7269,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "__foo___\n",
+ "html": "<p><strong>foo</strong>_</p>\n",
+ "example": 458,
+ "start_line": 7272,
+ "end_line": 7276,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "_foo____\n",
+ "html": "<p><em>foo</em>___</p>\n",
+ "example": 459,
+ "start_line": 7279,
+ "end_line": 7283,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "**foo**\n",
+ "html": "<p><strong>foo</strong></p>\n",
+ "example": 460,
+ "start_line": 7289,
+ "end_line": 7293,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "*_foo_*\n",
+ "html": "<p><em><em>foo</em></em></p>\n",
+ "example": 461,
+ "start_line": 7296,
+ "end_line": 7300,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "__foo__\n",
+ "html": "<p><strong>foo</strong></p>\n",
+ "example": 462,
+ "start_line": 7303,
+ "end_line": 7307,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "_*foo*_\n",
+ "html": "<p><em><em>foo</em></em></p>\n",
+ "example": 463,
+ "start_line": 7310,
+ "end_line": 7314,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "****foo****\n",
+ "html": "<p><strong><strong>foo</strong></strong></p>\n",
+ "example": 464,
+ "start_line": 7320,
+ "end_line": 7324,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "____foo____\n",
+ "html": "<p><strong><strong>foo</strong></strong></p>\n",
+ "example": 465,
+ "start_line": 7327,
+ "end_line": 7331,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "******foo******\n",
+ "html": "<p><strong><strong><strong>foo</strong></strong></strong></p>\n",
+ "example": 466,
+ "start_line": 7338,
+ "end_line": 7342,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "***foo***\n",
+ "html": "<p><em><strong>foo</strong></em></p>\n",
+ "example": 467,
+ "start_line": 7347,
+ "end_line": 7351,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "_____foo_____\n",
+ "html": "<p><em><strong><strong>foo</strong></strong></em></p>\n",
+ "example": 468,
+ "start_line": 7354,
+ "end_line": 7358,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "*foo _bar* baz_\n",
+ "html": "<p><em>foo _bar</em> baz_</p>\n",
+ "example": 469,
+ "start_line": 7363,
+ "end_line": 7367,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "*foo __bar *baz bim__ bam*\n",
+ "html": "<p><em>foo <strong>bar *baz bim</strong> bam</em></p>\n",
+ "example": 470,
+ "start_line": 7370,
+ "end_line": 7374,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "**foo **bar baz**\n",
+ "html": "<p>**foo <strong>bar baz</strong></p>\n",
+ "example": 471,
+ "start_line": 7379,
+ "end_line": 7383,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "*foo *bar baz*\n",
+ "html": "<p>*foo <em>bar baz</em></p>\n",
+ "example": 472,
+ "start_line": 7386,
+ "end_line": 7390,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "*[bar*](/url)\n",
+ "html": "<p>*<a href=\"/url\">bar*</a></p>\n",
+ "example": 473,
+ "start_line": 7395,
+ "end_line": 7399,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "_foo [bar_](/url)\n",
+ "html": "<p>_foo <a href=\"/url\">bar_</a></p>\n",
+ "example": 474,
+ "start_line": 7402,
+ "end_line": 7406,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "*<img src=\"foo\" title=\"*\"/>\n",
+ "html": "<p>*<img src=\"foo\" title=\"*\"/></p>\n",
+ "example": 475,
+ "start_line": 7409,
+ "end_line": 7413,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "**<a href=\"**\">\n",
+ "html": "<p>**<a href=\"**\"></p>\n",
+ "example": 476,
+ "start_line": 7416,
+ "end_line": 7420,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "__<a href=\"__\">\n",
+ "html": "<p>__<a href=\"__\"></p>\n",
+ "example": 477,
+ "start_line": 7423,
+ "end_line": 7427,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "*a `*`*\n",
+ "html": "<p><em>a <code>*</code></em></p>\n",
+ "example": 478,
+ "start_line": 7430,
+ "end_line": 7434,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "_a `_`_\n",
+ "html": "<p><em>a <code>_</code></em></p>\n",
+ "example": 479,
+ "start_line": 7437,
+ "end_line": 7441,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "**a<https://foo.bar/?q=**>\n",
+ "html": "<p>**a<a href=\"https://foo.bar/?q=**\">https://foo.bar/?q=**</a></p>\n",
+ "example": 480,
+ "start_line": 7444,
+ "end_line": 7448,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "__a<https://foo.bar/?q=__>\n",
+ "html": "<p>__a<a href=\"https://foo.bar/?q=__\">https://foo.bar/?q=__</a></p>\n",
+ "example": 481,
+ "start_line": 7451,
+ "end_line": 7455,
+ "section": "Emphasis and strong emphasis"
+ },
+ {
+ "markdown": "[link](/uri \"title\")\n",
+ "html": "<p><a href=\"/uri\" title=\"title\">link</a></p>\n",
+ "example": 482,
+ "start_line": 7539,
+ "end_line": 7543,
+ "section": "Links"
+ },
+ {
+ "markdown": "[link](/uri)\n",
+ "html": "<p><a href=\"/uri\">link</a></p>\n",
+ "example": 483,
+ "start_line": 7549,
+ "end_line": 7553,
+ "section": "Links"
+ },
+ {
+ "markdown": "[](./target.md)\n",
+ "html": "<p><a href=\"./target.md\"></a></p>\n",
+ "example": 484,
+ "start_line": 7555,
+ "end_line": 7559,
+ "section": "Links"
+ },
+ {
+ "markdown": "[link]()\n",
+ "html": "<p><a href=\"\">link</a></p>\n",
+ "example": 485,
+ "start_line": 7562,
+ "end_line": 7566,
+ "section": "Links"
+ },
+ {
+ "markdown": "[link](<>)\n",
+ "html": "<p><a href=\"\">link</a></p>\n",
+ "example": 486,
+ "start_line": 7569,
+ "end_line": 7573,
+ "section": "Links"
+ },
+ {
+ "markdown": "[]()\n",
+ "html": "<p><a href=\"\"></a></p>\n",
+ "example": 487,
+ "start_line": 7576,
+ "end_line": 7580,
+ "section": "Links"
+ },
+ {
+ "markdown": "[link](/my uri)\n",
+ "html": "<p>[link](/my uri)</p>\n",
+ "example": 488,
+ "start_line": 7585,
+ "end_line": 7589,
+ "section": "Links"
+ },
+ {
+ "markdown": "[link](</my uri>)\n",
+ "html": "<p><a href=\"/my%20uri\">link</a></p>\n",
+ "example": 489,
+ "start_line": 7591,
+ "end_line": 7595,
+ "section": "Links"
+ },
+ {
+ "markdown": "[link](foo\nbar)\n",
+ "html": "<p>[link](foo\nbar)</p>\n",
+ "example": 490,
+ "start_line": 7600,
+ "end_line": 7606,
+ "section": "Links"
+ },
+ {
+ "markdown": "[link](<foo\nbar>)\n",
+ "html": "<p>[link](<foo\nbar>)</p>\n",
+ "example": 491,
+ "start_line": 7608,
+ "end_line": 7614,
+ "section": "Links"
+ },
+ {
+ "markdown": "[a](<b)c>)\n",
+ "html": "<p><a href=\"b)c\">a</a></p>\n",
+ "example": 492,
+ "start_line": 7619,
+ "end_line": 7623,
+ "section": "Links"
+ },
+ {
+ "markdown": "[link](<foo\\>)\n",
+ "html": "<p>[link](<foo>)</p>\n",
+ "example": 493,
+ "start_line": 7627,
+ "end_line": 7631,
+ "section": "Links"
+ },
+ {
+ "markdown": "[a](<b)c\n[a](<b)c>\n[a](<b>c)\n",
+ "html": "<p>[a](<b)c\n[a](<b)c>\n[a](<b>c)</p>\n",
+ "example": 494,
+ "start_line": 7636,
+ "end_line": 7644,
+ "section": "Links"
+ },
+ {
+ "markdown": "[link](\\(foo\\))\n",
+ "html": "<p><a href=\"(foo)\">link</a></p>\n",
+ "example": 495,
+ "start_line": 7648,
+ "end_line": 7652,
+ "section": "Links"
+ },
+ {
+ "markdown": "[link](foo(and(bar)))\n",
+ "html": "<p><a href=\"foo(and(bar))\">link</a></p>\n",
+ "example": 496,
+ "start_line": 7657,
+ "end_line": 7661,
+ "section": "Links"
+ },
+ {
+ "markdown": "[link](foo(and(bar))\n",
+ "html": "<p>[link](foo(and(bar))</p>\n",
+ "example": 497,
+ "start_line": 7666,
+ "end_line": 7670,
+ "section": "Links"
+ },
+ {
+ "markdown": "[link](foo\\(and\\(bar\\))\n",
+ "html": "<p><a href=\"foo(and(bar)\">link</a></p>\n",
+ "example": 498,
+ "start_line": 7673,
+ "end_line": 7677,
+ "section": "Links"
+ },
+ {
+ "markdown": "[link](<foo(and(bar)>)\n",
+ "html": "<p><a href=\"foo(and(bar)\">link</a></p>\n",
+ "example": 499,
+ "start_line": 7680,
+ "end_line": 7684,
+ "section": "Links"
+ },
+ {
+ "markdown": "[link](foo\\)\\:)\n",
+ "html": "<p><a href=\"foo):\">link</a></p>\n",
+ "example": 500,
+ "start_line": 7690,
+ "end_line": 7694,
+ "section": "Links"
+ },
+ {
+ "markdown": "[link](#fragment)\n\n[link](https://example.com#fragment)\n\n[link](https://example.com?foo=3#frag)\n",
+ "html": "<p><a href=\"#fragment\">link</a></p>\n<p><a href=\"https://example.com#fragment\">link</a></p>\n<p><a href=\"https://example.com?foo=3#frag\">link</a></p>\n",
+ "example": 501,
+ "start_line": 7699,
+ "end_line": 7709,
+ "section": "Links"
+ },
+ {
+ "markdown": "[link](foo\\bar)\n",
+ "html": "<p><a href=\"foo%5Cbar\">link</a></p>\n",
+ "example": 502,
+ "start_line": 7715,
+ "end_line": 7719,
+ "section": "Links"
+ },
+ {
+ "markdown": "[link](foo%20bä)\n",
+ "html": "<p><a href=\"foo%20b%C3%A4\">link</a></p>\n",
+ "example": 503,
+ "start_line": 7731,
+ "end_line": 7735,
+ "section": "Links"
+ },
+ {
+ "markdown": "[link](\"title\")\n",
+ "html": "<p><a href=\"%22title%22\">link</a></p>\n",
+ "example": 504,
+ "start_line": 7742,
+ "end_line": 7746,
+ "section": "Links"
+ },
+ {
+ "markdown": "[link](/url \"title\")\n[link](/url 'title')\n[link](/url (title))\n",
+ "html": "<p><a href=\"/url\" title=\"title\">link</a>\n<a href=\"/url\" title=\"title\">link</a>\n<a href=\"/url\" title=\"title\">link</a></p>\n",
+ "example": 505,
+ "start_line": 7751,
+ "end_line": 7759,
+ "section": "Links"
+ },
+ {
+ "markdown": "[link](/url \"title \\\""\")\n",
+ "html": "<p><a href=\"/url\" title=\"title ""\">link</a></p>\n",
+ "example": 506,
+ "start_line": 7765,
+ "end_line": 7769,
+ "section": "Links"
+ },
+ {
+ "markdown": "[link](/url \"title\")\n",
+ "html": "<p><a href=\"/url%C2%A0%22title%22\">link</a></p>\n",
+ "example": 507,
+ "start_line": 7776,
+ "end_line": 7780,
+ "section": "Links"
+ },
+ {
+ "markdown": "[link](/url \"title \"and\" title\")\n",
+ "html": "<p>[link](/url "title "and" title")</p>\n",
+ "example": 508,
+ "start_line": 7785,
+ "end_line": 7789,
+ "section": "Links"
+ },
+ {
+ "markdown": "[link](/url 'title \"and\" title')\n",
+ "html": "<p><a href=\"/url\" title=\"title "and" title\">link</a></p>\n",
+ "example": 509,
+ "start_line": 7794,
+ "end_line": 7798,
+ "section": "Links"
+ },
+ {
+ "markdown": "[link]( /uri\n \"title\" )\n",
+ "html": "<p><a href=\"/uri\" title=\"title\">link</a></p>\n",
+ "example": 510,
+ "start_line": 7819,
+ "end_line": 7824,
+ "section": "Links"
+ },
+ {
+ "markdown": "[link] (/uri)\n",
+ "html": "<p>[link] (/uri)</p>\n",
+ "example": 511,
+ "start_line": 7830,
+ "end_line": 7834,
+ "section": "Links"
+ },
+ {
+ "markdown": "[link [foo [bar]]](/uri)\n",
+ "html": "<p><a href=\"/uri\">link [foo [bar]]</a></p>\n",
+ "example": 512,
+ "start_line": 7840,
+ "end_line": 7844,
+ "section": "Links"
+ },
+ {
+ "markdown": "[link] bar](/uri)\n",
+ "html": "<p>[link] bar](/uri)</p>\n",
+ "example": 513,
+ "start_line": 7847,
+ "end_line": 7851,
+ "section": "Links"
+ },
+ {
+ "markdown": "[link [bar](/uri)\n",
+ "html": "<p>[link <a href=\"/uri\">bar</a></p>\n",
+ "example": 514,
+ "start_line": 7854,
+ "end_line": 7858,
+ "section": "Links"
+ },
+ {
+ "markdown": "[link \\[bar](/uri)\n",
+ "html": "<p><a href=\"/uri\">link [bar</a></p>\n",
+ "example": 515,
+ "start_line": 7861,
+ "end_line": 7865,
+ "section": "Links"
+ },
+ {
+ "markdown": "[link *foo **bar** `#`*](/uri)\n",
+ "html": "<p><a href=\"/uri\">link <em>foo <strong>bar</strong> <code>#</code></em></a></p>\n",
+ "example": 516,
+ "start_line": 7870,
+ "end_line": 7874,
+ "section": "Links"
+ },
+ {
+ "markdown": "[](/uri)\n",
+ "html": "<p><a href=\"/uri\"><img src=\"moon.jpg\" alt=\"moon\" /></a></p>\n",
+ "example": 517,
+ "start_line": 7877,
+ "end_line": 7881,
+ "section": "Links"
+ },
+ {
+ "markdown": "[foo [bar](/uri)](/uri)\n",
+ "html": "<p>[foo <a href=\"/uri\">bar</a>](/uri)</p>\n",
+ "example": 518,
+ "start_line": 7886,
+ "end_line": 7890,
+ "section": "Links"
+ },
+ {
+ "markdown": "[foo *[bar [baz](/uri)](/uri)*](/uri)\n",
+ "html": "<p>[foo <em>[bar <a href=\"/uri\">baz</a>](/uri)</em>](/uri)</p>\n",
+ "example": 519,
+ "start_line": 7893,
+ "end_line": 7897,
+ "section": "Links"
+ },
+ {
+ "markdown": "](uri2)](uri3)\n",
+ "html": "<p><img src=\"uri3\" alt=\"[foo](uri2)\" /></p>\n",
+ "example": 520,
+ "start_line": 7900,
+ "end_line": 7904,
+ "section": "Links"
+ },
+ {
+ "markdown": "*[foo*](/uri)\n",
+ "html": "<p>*<a href=\"/uri\">foo*</a></p>\n",
+ "example": 521,
+ "start_line": 7910,
+ "end_line": 7914,
+ "section": "Links"
+ },
+ {
+ "markdown": "[foo *bar](baz*)\n",
+ "html": "<p><a href=\"baz*\">foo *bar</a></p>\n",
+ "example": 522,
+ "start_line": 7917,
+ "end_line": 7921,
+ "section": "Links"
+ },
+ {
+ "markdown": "*foo [bar* baz]\n",
+ "html": "<p><em>foo [bar</em> baz]</p>\n",
+ "example": 523,
+ "start_line": 7927,
+ "end_line": 7931,
+ "section": "Links"
+ },
+ {
+ "markdown": "[foo <bar attr=\"](baz)\">\n",
+ "html": "<p>[foo <bar attr=\"](baz)\"></p>\n",
+ "example": 524,
+ "start_line": 7937,
+ "end_line": 7941,
+ "section": "Links"
+ },
+ {
+ "markdown": "[foo`](/uri)`\n",
+ "html": "<p>[foo<code>](/uri)</code></p>\n",
+ "example": 525,
+ "start_line": 7944,
+ "end_line": 7948,
+ "section": "Links"
+ },
+ {
+ "markdown": "[foo<https://example.com/?search=](uri)>\n",
+ "html": "<p>[foo<a href=\"https://example.com/?search=%5D(uri)\">https://example.com/?search=](uri)</a></p>\n",
+ "example": 526,
+ "start_line": 7951,
+ "end_line": 7955,
+ "section": "Links"
+ },
+ {
+ "markdown": "[foo][bar]\n\n[bar]: /url \"title\"\n",
+ "html": "<p><a href=\"/url\" title=\"title\">foo</a></p>\n",
+ "example": 527,
+ "start_line": 7989,
+ "end_line": 7995,
+ "section": "Links"
+ },
+ {
+ "markdown": "[link [foo [bar]]][ref]\n\n[ref]: /uri\n",
+ "html": "<p><a href=\"/uri\">link [foo [bar]]</a></p>\n",
+ "example": 528,
+ "start_line": 8004,
+ "end_line": 8010,
+ "section": "Links"
+ },
+ {
+ "markdown": "[link \\[bar][ref]\n\n[ref]: /uri\n",
+ "html": "<p><a href=\"/uri\">link [bar</a></p>\n",
+ "example": 529,
+ "start_line": 8013,
+ "end_line": 8019,
+ "section": "Links"
+ },
+ {
+ "markdown": "[link *foo **bar** `#`*][ref]\n\n[ref]: /uri\n",
+ "html": "<p><a href=\"/uri\">link <em>foo <strong>bar</strong> <code>#</code></em></a></p>\n",
+ "example": 530,
+ "start_line": 8024,
+ "end_line": 8030,
+ "section": "Links"
+ },
+ {
+ "markdown": "[][ref]\n\n[ref]: /uri\n",
+ "html": "<p><a href=\"/uri\"><img src=\"moon.jpg\" alt=\"moon\" /></a></p>\n",
+ "example": 531,
+ "start_line": 8033,
+ "end_line": 8039,
+ "section": "Links"
+ },
+ {
+ "markdown": "[foo [bar](/uri)][ref]\n\n[ref]: /uri\n",
+ "html": "<p>[foo <a href=\"/uri\">bar</a>]<a href=\"/uri\">ref</a></p>\n",
+ "example": 532,
+ "start_line": 8044,
+ "end_line": 8050,
+ "section": "Links"
+ },
+ {
+ "markdown": "[foo *bar [baz][ref]*][ref]\n\n[ref]: /uri\n",
+ "html": "<p>[foo <em>bar <a href=\"/uri\">baz</a></em>]<a href=\"/uri\">ref</a></p>\n",
+ "example": 533,
+ "start_line": 8053,
+ "end_line": 8059,
+ "section": "Links"
+ },
+ {
+ "markdown": "*[foo*][ref]\n\n[ref]: /uri\n",
+ "html": "<p>*<a href=\"/uri\">foo*</a></p>\n",
+ "example": 534,
+ "start_line": 8068,
+ "end_line": 8074,
+ "section": "Links"
+ },
+ {
+ "markdown": "[foo *bar][ref]*\n\n[ref]: /uri\n",
+ "html": "<p><a href=\"/uri\">foo *bar</a>*</p>\n",
+ "example": 535,
+ "start_line": 8077,
+ "end_line": 8083,
+ "section": "Links"
+ },
+ {
+ "markdown": "[foo <bar attr=\"][ref]\">\n\n[ref]: /uri\n",
+ "html": "<p>[foo <bar attr=\"][ref]\"></p>\n",
+ "example": 536,
+ "start_line": 8089,
+ "end_line": 8095,
+ "section": "Links"
+ },
+ {
+ "markdown": "[foo`][ref]`\n\n[ref]: /uri\n",
+ "html": "<p>[foo<code>][ref]</code></p>\n",
+ "example": 537,
+ "start_line": 8098,
+ "end_line": 8104,
+ "section": "Links"
+ },
+ {
+ "markdown": "[foo<https://example.com/?search=][ref]>\n\n[ref]: /uri\n",
+ "html": "<p>[foo<a href=\"https://example.com/?search=%5D%5Bref%5D\">https://example.com/?search=][ref]</a></p>\n",
+ "example": 538,
+ "start_line": 8107,
+ "end_line": 8113,
+ "section": "Links"
+ },
+ {
+ "markdown": "[foo][BaR]\n\n[bar]: /url \"title\"\n",
+ "html": "<p><a href=\"/url\" title=\"title\">foo</a></p>\n",
+ "example": 539,
+ "start_line": 8118,
+ "end_line": 8124,
+ "section": "Links"
+ },
+ {
+ "markdown": "[ẞ]\n\n[SS]: /url\n",
+ "html": "<p><a href=\"/url\">ẞ</a></p>\n",
+ "example": 540,
+ "start_line": 8129,
+ "end_line": 8135,
+ "section": "Links"
+ },
+ {
+ "markdown": "[Foo\n bar]: /url\n\n[Baz][Foo bar]\n",
+ "html": "<p><a href=\"/url\">Baz</a></p>\n",
+ "example": 541,
+ "start_line": 8141,
+ "end_line": 8148,
+ "section": "Links"
+ },
+ {
+ "markdown": "[foo] [bar]\n\n[bar]: /url \"title\"\n",
+ "html": "<p>[foo] <a href=\"/url\" title=\"title\">bar</a></p>\n",
+ "example": 542,
+ "start_line": 8154,
+ "end_line": 8160,
+ "section": "Links"
+ },
+ {
+ "markdown": "[foo]\n[bar]\n\n[bar]: /url \"title\"\n",
+ "html": "<p>[foo]\n<a href=\"/url\" title=\"title\">bar</a></p>\n",
+ "example": 543,
+ "start_line": 8163,
+ "end_line": 8171,
+ "section": "Links"
+ },
+ {
+ "markdown": "[foo]: /url1\n\n[foo]: /url2\n\n[bar][foo]\n",
+ "html": "<p><a href=\"/url1\">bar</a></p>\n",
+ "example": 544,
+ "start_line": 8204,
+ "end_line": 8212,
+ "section": "Links"
+ },
+ {
+ "markdown": "[bar][foo\\!]\n\n[foo!]: /url\n",
+ "html": "<p>[bar][foo!]</p>\n",
+ "example": 545,
+ "start_line": 8219,
+ "end_line": 8225,
+ "section": "Links"
+ },
+ {
+ "markdown": "[foo][ref[]\n\n[ref[]: /uri\n",
+ "html": "<p>[foo][ref[]</p>\n<p>[ref[]: /uri</p>\n",
+ "example": 546,
+ "start_line": 8231,
+ "end_line": 8238,
+ "section": "Links"
+ },
+ {
+ "markdown": "[foo][ref[bar]]\n\n[ref[bar]]: /uri\n",
+ "html": "<p>[foo][ref[bar]]</p>\n<p>[ref[bar]]: /uri</p>\n",
+ "example": 547,
+ "start_line": 8241,
+ "end_line": 8248,
+ "section": "Links"
+ },
+ {
+ "markdown": "[[[foo]]]\n\n[[[foo]]]: /url\n",
+ "html": "<p>[[[foo]]]</p>\n<p>[[[foo]]]: /url</p>\n",
+ "example": 548,
+ "start_line": 8251,
+ "end_line": 8258,
+ "section": "Links"
+ },
+ {
+ "markdown": "[foo][ref\\[]\n\n[ref\\[]: /uri\n",
+ "html": "<p><a href=\"/uri\">foo</a></p>\n",
+ "example": 549,
+ "start_line": 8261,
+ "end_line": 8267,
+ "section": "Links"
+ },
+ {
+ "markdown": "[bar\\\\]: /uri\n\n[bar\\\\]\n",
+ "html": "<p><a href=\"/uri\">bar\\</a></p>\n",
+ "example": 550,
+ "start_line": 8272,
+ "end_line": 8278,
+ "section": "Links"
+ },
+ {
+ "markdown": "[]\n\n[]: /uri\n",
+ "html": "<p>[]</p>\n<p>[]: /uri</p>\n",
+ "example": 551,
+ "start_line": 8284,
+ "end_line": 8291,
+ "section": "Links"
+ },
+ {
+ "markdown": "[\n ]\n\n[\n ]: /uri\n",
+ "html": "<p>[\n]</p>\n<p>[\n]: /uri</p>\n",
+ "example": 552,
+ "start_line": 8294,
+ "end_line": 8305,
+ "section": "Links"
+ },
+ {
+ "markdown": "[foo][]\n\n[foo]: /url \"title\"\n",
+ "html": "<p><a href=\"/url\" title=\"title\">foo</a></p>\n",
+ "example": 553,
+ "start_line": 8317,
+ "end_line": 8323,
+ "section": "Links"
+ },
+ {
+ "markdown": "[*foo* bar][]\n\n[*foo* bar]: /url \"title\"\n",
+ "html": "<p><a href=\"/url\" title=\"title\"><em>foo</em> bar</a></p>\n",
+ "example": 554,
+ "start_line": 8326,
+ "end_line": 8332,
+ "section": "Links"
+ },
+ {
+ "markdown": "[Foo][]\n\n[foo]: /url \"title\"\n",
+ "html": "<p><a href=\"/url\" title=\"title\">Foo</a></p>\n",
+ "example": 555,
+ "start_line": 8337,
+ "end_line": 8343,
+ "section": "Links"
+ },
+ {
+ "markdown": "[foo] \n[]\n\n[foo]: /url \"title\"\n",
+ "html": "<p><a href=\"/url\" title=\"title\">foo</a>\n[]</p>\n",
+ "example": 556,
+ "start_line": 8350,
+ "end_line": 8358,
+ "section": "Links"
+ },
+ {
+ "markdown": "[foo]\n\n[foo]: /url \"title\"\n",
+ "html": "<p><a href=\"/url\" title=\"title\">foo</a></p>\n",
+ "example": 557,
+ "start_line": 8370,
+ "end_line": 8376,
+ "section": "Links"
+ },
+ {
+ "markdown": "[*foo* bar]\n\n[*foo* bar]: /url \"title\"\n",
+ "html": "<p><a href=\"/url\" title=\"title\"><em>foo</em> bar</a></p>\n",
+ "example": 558,
+ "start_line": 8379,
+ "end_line": 8385,
+ "section": "Links"
+ },
+ {
+ "markdown": "[[*foo* bar]]\n\n[*foo* bar]: /url \"title\"\n",
+ "html": "<p>[<a href=\"/url\" title=\"title\"><em>foo</em> bar</a>]</p>\n",
+ "example": 559,
+ "start_line": 8388,
+ "end_line": 8394,
+ "section": "Links"
+ },
+ {
+ "markdown": "[[bar [foo]\n\n[foo]: /url\n",
+ "html": "<p>[[bar <a href=\"/url\">foo</a></p>\n",
+ "example": 560,
+ "start_line": 8397,
+ "end_line": 8403,
+ "section": "Links"
+ },
+ {
+ "markdown": "[Foo]\n\n[foo]: /url \"title\"\n",
+ "html": "<p><a href=\"/url\" title=\"title\">Foo</a></p>\n",
+ "example": 561,
+ "start_line": 8408,
+ "end_line": 8414,
+ "section": "Links"
+ },
+ {
+ "markdown": "[foo] bar\n\n[foo]: /url\n",
+ "html": "<p><a href=\"/url\">foo</a> bar</p>\n",
+ "example": 562,
+ "start_line": 8419,
+ "end_line": 8425,
+ "section": "Links"
+ },
+ {
+ "markdown": "\\[foo]\n\n[foo]: /url \"title\"\n",
+ "html": "<p>[foo]</p>\n",
+ "example": 563,
+ "start_line": 8431,
+ "end_line": 8437,
+ "section": "Links"
+ },
+ {
+ "markdown": "[foo*]: /url\n\n*[foo*]\n",
+ "html": "<p>*<a href=\"/url\">foo*</a></p>\n",
+ "example": 564,
+ "start_line": 8443,
+ "end_line": 8449,
+ "section": "Links"
+ },
+ {
+ "markdown": "[foo][bar]\n\n[foo]: /url1\n[bar]: /url2\n",
+ "html": "<p><a href=\"/url2\">foo</a></p>\n",
+ "example": 565,
+ "start_line": 8455,
+ "end_line": 8462,
+ "section": "Links"
+ },
+ {
+ "markdown": "[foo][]\n\n[foo]: /url1\n",
+ "html": "<p><a href=\"/url1\">foo</a></p>\n",
+ "example": 566,
+ "start_line": 8464,
+ "end_line": 8470,
+ "section": "Links"
+ },
+ {
+ "markdown": "[foo]()\n\n[foo]: /url1\n",
+ "html": "<p><a href=\"\">foo</a></p>\n",
+ "example": 567,
+ "start_line": 8474,
+ "end_line": 8480,
+ "section": "Links"
+ },
+ {
+ "markdown": "[foo](not a link)\n\n[foo]: /url1\n",
+ "html": "<p><a href=\"/url1\">foo</a>(not a link)</p>\n",
+ "example": 568,
+ "start_line": 8482,
+ "end_line": 8488,
+ "section": "Links"
+ },
+ {
+ "markdown": "[foo][bar][baz]\n\n[baz]: /url\n",
+ "html": "<p>[foo]<a href=\"/url\">bar</a></p>\n",
+ "example": 569,
+ "start_line": 8493,
+ "end_line": 8499,
+ "section": "Links"
+ },
+ {
+ "markdown": "[foo][bar][baz]\n\n[baz]: /url1\n[bar]: /url2\n",
+ "html": "<p><a href=\"/url2\">foo</a><a href=\"/url1\">baz</a></p>\n",
+ "example": 570,
+ "start_line": 8505,
+ "end_line": 8512,
+ "section": "Links"
+ },
+ {
+ "markdown": "[foo][bar][baz]\n\n[baz]: /url1\n[foo]: /url2\n",
+ "html": "<p>[foo]<a href=\"/url1\">bar</a></p>\n",
+ "example": 571,
+ "start_line": 8518,
+ "end_line": 8525,
+ "section": "Links"
+ },
+ {
+ "markdown": "\n",
+ "html": "<p><img src=\"/url\" alt=\"foo\" title=\"title\" /></p>\n",
+ "example": 572,
+ "start_line": 8541,
+ "end_line": 8545,
+ "section": "Images"
+ },
+ {
+ "markdown": "![foo *bar*]\n\n[foo *bar*]: train.jpg \"train & tracks\"\n",
+ "html": "<p><img src=\"train.jpg\" alt=\"foo bar\" title=\"train & tracks\" /></p>\n",
+ "example": 573,
+ "start_line": 8548,
+ "end_line": 8554,
+ "section": "Images"
+ },
+ {
+ "markdown": "](/url2)\n",
+ "html": "<p><img src=\"/url2\" alt=\"foo bar\" /></p>\n",
+ "example": 574,
+ "start_line": 8557,
+ "end_line": 8561,
+ "section": "Images"
+ },
+ {
+ "markdown": "](/url2)\n",
+ "html": "<p><img src=\"/url2\" alt=\"foo bar\" /></p>\n",
+ "example": 575,
+ "start_line": 8564,
+ "end_line": 8568,
+ "section": "Images"
+ },
+ {
+ "markdown": "![foo *bar*][]\n\n[foo *bar*]: train.jpg \"train & tracks\"\n",
+ "html": "<p><img src=\"train.jpg\" alt=\"foo bar\" title=\"train & tracks\" /></p>\n",
+ "example": 576,
+ "start_line": 8578,
+ "end_line": 8584,
+ "section": "Images"
+ },
+ {
+ "markdown": "![foo *bar*][foobar]\n\n[FOOBAR]: train.jpg \"train & tracks\"\n",
+ "html": "<p><img src=\"train.jpg\" alt=\"foo bar\" title=\"train & tracks\" /></p>\n",
+ "example": 577,
+ "start_line": 8587,
+ "end_line": 8593,
+ "section": "Images"
+ },
+ {
+ "markdown": "\n",
+ "html": "<p><img src=\"train.jpg\" alt=\"foo\" /></p>\n",
+ "example": 578,
+ "start_line": 8596,
+ "end_line": 8600,
+ "section": "Images"
+ },
+ {
+ "markdown": "My \n",
+ "html": "<p>My <img src=\"/path/to/train.jpg\" alt=\"foo bar\" title=\"title\" /></p>\n",
+ "example": 579,
+ "start_line": 8603,
+ "end_line": 8607,
+ "section": "Images"
+ },
+ {
+ "markdown": "\n",
+ "html": "<p><img src=\"url\" alt=\"foo\" /></p>\n",
+ "example": 580,
+ "start_line": 8610,
+ "end_line": 8614,
+ "section": "Images"
+ },
+ {
+ "markdown": "\n",
+ "html": "<p><img src=\"/url\" alt=\"\" /></p>\n",
+ "example": 581,
+ "start_line": 8617,
+ "end_line": 8621,
+ "section": "Images"
+ },
+ {
+ "markdown": "![foo][bar]\n\n[bar]: /url\n",
+ "html": "<p><img src=\"/url\" alt=\"foo\" /></p>\n",
+ "example": 582,
+ "start_line": 8626,
+ "end_line": 8632,
+ "section": "Images"
+ },
+ {
+ "markdown": "![foo][bar]\n\n[BAR]: /url\n",
+ "html": "<p><img src=\"/url\" alt=\"foo\" /></p>\n",
+ "example": 583,
+ "start_line": 8635,
+ "end_line": 8641,
+ "section": "Images"
+ },
+ {
+ "markdown": "![foo][]\n\n[foo]: /url \"title\"\n",
+ "html": "<p><img src=\"/url\" alt=\"foo\" title=\"title\" /></p>\n",
+ "example": 584,
+ "start_line": 8646,
+ "end_line": 8652,
+ "section": "Images"
+ },
+ {
+ "markdown": "![*foo* bar][]\n\n[*foo* bar]: /url \"title\"\n",
+ "html": "<p><img src=\"/url\" alt=\"foo bar\" title=\"title\" /></p>\n",
+ "example": 585,
+ "start_line": 8655,
+ "end_line": 8661,
+ "section": "Images"
+ },
+ {
+ "markdown": "![Foo][]\n\n[foo]: /url \"title\"\n",
+ "html": "<p><img src=\"/url\" alt=\"Foo\" title=\"title\" /></p>\n",
+ "example": 586,
+ "start_line": 8666,
+ "end_line": 8672,
+ "section": "Images"
+ },
+ {
+ "markdown": "![foo] \n[]\n\n[foo]: /url \"title\"\n",
+ "html": "<p><img src=\"/url\" alt=\"foo\" title=\"title\" />\n[]</p>\n",
+ "example": 587,
+ "start_line": 8678,
+ "end_line": 8686,
+ "section": "Images"
+ },
+ {
+ "markdown": "![foo]\n\n[foo]: /url \"title\"\n",
+ "html": "<p><img src=\"/url\" alt=\"foo\" title=\"title\" /></p>\n",
+ "example": 588,
+ "start_line": 8691,
+ "end_line": 8697,
+ "section": "Images"
+ },
+ {
+ "markdown": "![*foo* bar]\n\n[*foo* bar]: /url \"title\"\n",
+ "html": "<p><img src=\"/url\" alt=\"foo bar\" title=\"title\" /></p>\n",
+ "example": 589,
+ "start_line": 8700,
+ "end_line": 8706,
+ "section": "Images"
+ },
+ {
+ "markdown": "![[foo]]\n\n[[foo]]: /url \"title\"\n",
+ "html": "<p>![[foo]]</p>\n<p>[[foo]]: /url "title"</p>\n",
+ "example": 590,
+ "start_line": 8711,
+ "end_line": 8718,
+ "section": "Images"
+ },
+ {
+ "markdown": "![Foo]\n\n[foo]: /url \"title\"\n",
+ "html": "<p><img src=\"/url\" alt=\"Foo\" title=\"title\" /></p>\n",
+ "example": 591,
+ "start_line": 8723,
+ "end_line": 8729,
+ "section": "Images"
+ },
+ {
+ "markdown": "!\\[foo]\n\n[foo]: /url \"title\"\n",
+ "html": "<p>![foo]</p>\n",
+ "example": 592,
+ "start_line": 8735,
+ "end_line": 8741,
+ "section": "Images"
+ },
+ {
+ "markdown": "\\![foo]\n\n[foo]: /url \"title\"\n",
+ "html": "<p>!<a href=\"/url\" title=\"title\">foo</a></p>\n",
+ "example": 593,
+ "start_line": 8747,
+ "end_line": 8753,
+ "section": "Images"
+ },
+ {
+ "markdown": "<http://foo.bar.baz>\n",
+ "html": "<p><a href=\"http://foo.bar.baz\">http://foo.bar.baz</a></p>\n",
+ "example": 594,
+ "start_line": 8780,
+ "end_line": 8784,
+ "section": "Autolinks"
+ },
+ {
+ "markdown": "<https://foo.bar.baz/test?q=hello&id=22&boolean>\n",
+ "html": "<p><a href=\"https://foo.bar.baz/test?q=hello&id=22&boolean\">https://foo.bar.baz/test?q=hello&id=22&boolean</a></p>\n",
+ "example": 595,
+ "start_line": 8787,
+ "end_line": 8791,
+ "section": "Autolinks"
+ },
+ {
+ "markdown": "<irc://foo.bar:2233/baz>\n",
+ "html": "<p><a href=\"irc://foo.bar:2233/baz\">irc://foo.bar:2233/baz</a></p>\n",
+ "example": 596,
+ "start_line": 8794,
+ "end_line": 8798,
+ "section": "Autolinks"
+ },
+ {
+ "markdown": "<MAILTO:FOO@BAR.BAZ>\n",
+ "html": "<p><a href=\"MAILTO:FOO@BAR.BAZ\">MAILTO:FOO@BAR.BAZ</a></p>\n",
+ "example": 597,
+ "start_line": 8803,
+ "end_line": 8807,
+ "section": "Autolinks"
+ },
+ {
+ "markdown": "<a+b+c:d>\n",
+ "html": "<p><a href=\"a+b+c:d\">a+b+c:d</a></p>\n",
+ "example": 598,
+ "start_line": 8815,
+ "end_line": 8819,
+ "section": "Autolinks"
+ },
+ {
+ "markdown": "<made-up-scheme://foo,bar>\n",
+ "html": "<p><a href=\"made-up-scheme://foo,bar\">made-up-scheme://foo,bar</a></p>\n",
+ "example": 599,
+ "start_line": 8822,
+ "end_line": 8826,
+ "section": "Autolinks"
+ },
+ {
+ "markdown": "<https://../>\n",
+ "html": "<p><a href=\"https://../\">https://../</a></p>\n",
+ "example": 600,
+ "start_line": 8829,
+ "end_line": 8833,
+ "section": "Autolinks"
+ },
+ {
+ "markdown": "<localhost:5001/foo>\n",
+ "html": "<p><a href=\"localhost:5001/foo\">localhost:5001/foo</a></p>\n",
+ "example": 601,
+ "start_line": 8836,
+ "end_line": 8840,
+ "section": "Autolinks"
+ },
+ {
+ "markdown": "<https://foo.bar/baz bim>\n",
+ "html": "<p><https://foo.bar/baz bim></p>\n",
+ "example": 602,
+ "start_line": 8845,
+ "end_line": 8849,
+ "section": "Autolinks"
+ },
+ {
+ "markdown": "<https://example.com/\\[\\>\n",
+ "html": "<p><a href=\"https://example.com/%5C%5B%5C\">https://example.com/\\[\\</a></p>\n",
+ "example": 603,
+ "start_line": 8854,
+ "end_line": 8858,
+ "section": "Autolinks"
+ },
+ {
+ "markdown": "<foo@bar.example.com>\n",
+ "html": "<p><a href=\"mailto:foo@bar.example.com\">foo@bar.example.com</a></p>\n",
+ "example": 604,
+ "start_line": 8876,
+ "end_line": 8880,
+ "section": "Autolinks"
+ },
+ {
+ "markdown": "<foo+special@Bar.baz-bar0.com>\n",
+ "html": "<p><a href=\"mailto:foo+special@Bar.baz-bar0.com\">foo+special@Bar.baz-bar0.com</a></p>\n",
+ "example": 605,
+ "start_line": 8883,
+ "end_line": 8887,
+ "section": "Autolinks"
+ },
+ {
+ "markdown": "<foo\\+@bar.example.com>\n",
+ "html": "<p><foo+@bar.example.com></p>\n",
+ "example": 606,
+ "start_line": 8892,
+ "end_line": 8896,
+ "section": "Autolinks"
+ },
+ {
+ "markdown": "<>\n",
+ "html": "<p><></p>\n",
+ "example": 607,
+ "start_line": 8901,
+ "end_line": 8905,
+ "section": "Autolinks"
+ },
+ {
+ "markdown": "< https://foo.bar >\n",
+ "html": "<p>< https://foo.bar ></p>\n",
+ "example": 608,
+ "start_line": 8908,
+ "end_line": 8912,
+ "section": "Autolinks"
+ },
+ {
+ "markdown": "<m:abc>\n",
+ "html": "<p><m:abc></p>\n",
+ "example": 609,
+ "start_line": 8915,
+ "end_line": 8919,
+ "section": "Autolinks"
+ },
+ {
+ "markdown": "<foo.bar.baz>\n",
+ "html": "<p><foo.bar.baz></p>\n",
+ "example": 610,
+ "start_line": 8922,
+ "end_line": 8926,
+ "section": "Autolinks"
+ },
+ {
+ "markdown": "https://example.com\n",
+ "html": "<p>https://example.com</p>\n",
+ "example": 611,
+ "start_line": 8929,
+ "end_line": 8933,
+ "section": "Autolinks"
+ },
+ {
+ "markdown": "foo@bar.example.com\n",
+ "html": "<p>foo@bar.example.com</p>\n",
+ "example": 612,
+ "start_line": 8936,
+ "end_line": 8940,
+ "section": "Autolinks"
+ },
+ {
+ "markdown": "<a><bab><c2c>\n",
+ "html": "<p><a><bab><c2c></p>\n",
+ "example": 613,
+ "start_line": 9016,
+ "end_line": 9020,
+ "section": "Raw HTML"
+ },
+ {
+ "markdown": "<a/><b2/>\n",
+ "html": "<p><a/><b2/></p>\n",
+ "example": 614,
+ "start_line": 9025,
+ "end_line": 9029,
+ "section": "Raw HTML"
+ },
+ {
+ "markdown": "<a /><b2\ndata=\"foo\" >\n",
+ "html": "<p><a /><b2\ndata=\"foo\" ></p>\n",
+ "example": 615,
+ "start_line": 9034,
+ "end_line": 9040,
+ "section": "Raw HTML"
+ },
+ {
+ "markdown": "<a foo=\"bar\" bam = 'baz <em>\"</em>'\n_boolean zoop:33=zoop:33 />\n",
+ "html": "<p><a foo=\"bar\" bam = 'baz <em>\"</em>'\n_boolean zoop:33=zoop:33 /></p>\n",
+ "example": 616,
+ "start_line": 9045,
+ "end_line": 9051,
+ "section": "Raw HTML"
+ },
+ {
+ "markdown": "Foo <responsive-image src=\"foo.jpg\" />\n",
+ "html": "<p>Foo <responsive-image src=\"foo.jpg\" /></p>\n",
+ "example": 617,
+ "start_line": 9056,
+ "end_line": 9060,
+ "section": "Raw HTML"
+ },
+ {
+ "markdown": "<33> <__>\n",
+ "html": "<p><33> <__></p>\n",
+ "example": 618,
+ "start_line": 9065,
+ "end_line": 9069,
+ "section": "Raw HTML"
+ },
+ {
+ "markdown": "<a h*#ref=\"hi\">\n",
+ "html": "<p><a h*#ref="hi"></p>\n",
+ "example": 619,
+ "start_line": 9074,
+ "end_line": 9078,
+ "section": "Raw HTML"
+ },
+ {
+ "markdown": "<a href=\"hi'> <a href=hi'>\n",
+ "html": "<p><a href="hi'> <a href=hi'></p>\n",
+ "example": 620,
+ "start_line": 9083,
+ "end_line": 9087,
+ "section": "Raw HTML"
+ },
+ {
+ "markdown": "< a><\nfoo><bar/ >\n<foo bar=baz\nbim!bop />\n",
+ "html": "<p>< a><\nfoo><bar/ >\n<foo bar=baz\nbim!bop /></p>\n",
+ "example": 621,
+ "start_line": 9092,
+ "end_line": 9102,
+ "section": "Raw HTML"
+ },
+ {
+ "markdown": "<a href='bar'title=title>\n",
+ "html": "<p><a href='bar'title=title></p>\n",
+ "example": 622,
+ "start_line": 9107,
+ "end_line": 9111,
+ "section": "Raw HTML"
+ },
+ {
+ "markdown": "</a></foo >\n",
+ "html": "<p></a></foo ></p>\n",
+ "example": 623,
+ "start_line": 9116,
+ "end_line": 9120,
+ "section": "Raw HTML"
+ },
+ {
+ "markdown": "</a href=\"foo\">\n",
+ "html": "<p></a href="foo"></p>\n",
+ "example": 624,
+ "start_line": 9125,
+ "end_line": 9129,
+ "section": "Raw HTML"
+ },
+ {
+ "markdown": "foo <!-- this is a --\ncomment - with hyphens -->\n",
+ "html": "<p>foo <!-- this is a --\ncomment - with hyphens --></p>\n",
+ "example": 625,
+ "start_line": 9134,
+ "end_line": 9140,
+ "section": "Raw HTML"
+ },
+ {
+ "markdown": "foo <!--> foo -->\n\nfoo <!---> foo -->\n",
+ "html": "<p>foo <!--> foo --></p>\n<p>foo <!---> foo --></p>\n",
+ "example": 626,
+ "start_line": 9142,
+ "end_line": 9149,
+ "section": "Raw HTML"
+ },
+ {
+ "markdown": "foo <?php echo $a; ?>\n",
+ "html": "<p>foo <?php echo $a; ?></p>\n",
+ "example": 627,
+ "start_line": 9154,
+ "end_line": 9158,
+ "section": "Raw HTML"
+ },
+ {
+ "markdown": "foo <!ELEMENT br EMPTY>\n",
+ "html": "<p>foo <!ELEMENT br EMPTY></p>\n",
+ "example": 628,
+ "start_line": 9163,
+ "end_line": 9167,
+ "section": "Raw HTML"
+ },
+ {
+ "markdown": "foo <![CDATA[>&<]]>\n",
+ "html": "<p>foo <![CDATA[>&<]]></p>\n",
+ "example": 629,
+ "start_line": 9172,
+ "end_line": 9176,
+ "section": "Raw HTML"
+ },
+ {
+ "markdown": "foo <a href=\"ö\">\n",
+ "html": "<p>foo <a href=\"ö\"></p>\n",
+ "example": 630,
+ "start_line": 9182,
+ "end_line": 9186,
+ "section": "Raw HTML"
+ },
+ {
+ "markdown": "foo <a href=\"\\*\">\n",
+ "html": "<p>foo <a href=\"\\*\"></p>\n",
+ "example": 631,
+ "start_line": 9191,
+ "end_line": 9195,
+ "section": "Raw HTML"
+ },
+ {
+ "markdown": "<a href=\"\\\"\">\n",
+ "html": "<p><a href="""></p>\n",
+ "example": 632,
+ "start_line": 9198,
+ "end_line": 9202,
+ "section": "Raw HTML"
+ },
+ {
+ "markdown": "foo \nbaz\n",
+ "html": "<p>foo<br />\nbaz</p>\n",
+ "example": 633,
+ "start_line": 9212,
+ "end_line": 9218,
+ "section": "Hard line breaks"
+ },
+ {
+ "markdown": "foo\\\nbaz\n",
+ "html": "<p>foo<br />\nbaz</p>\n",
+ "example": 634,
+ "start_line": 9224,
+ "end_line": 9230,
+ "section": "Hard line breaks"
+ },
+ {
+ "markdown": "foo \nbaz\n",
+ "html": "<p>foo<br />\nbaz</p>\n",
+ "example": 635,
+ "start_line": 9235,
+ "end_line": 9241,
+ "section": "Hard line breaks"
+ },
+ {
+ "markdown": "foo \n bar\n",
+ "html": "<p>foo<br />\nbar</p>\n",
+ "example": 636,
+ "start_line": 9246,
+ "end_line": 9252,
+ "section": "Hard line breaks"
+ },
+ {
+ "markdown": "foo\\\n bar\n",
+ "html": "<p>foo<br />\nbar</p>\n",
+ "example": 637,
+ "start_line": 9255,
+ "end_line": 9261,
+ "section": "Hard line breaks"
+ },
+ {
+ "markdown": "*foo \nbar*\n",
+ "html": "<p><em>foo<br />\nbar</em></p>\n",
+ "example": 638,
+ "start_line": 9267,
+ "end_line": 9273,
+ "section": "Hard line breaks"
+ },
+ {
+ "markdown": "*foo\\\nbar*\n",
+ "html": "<p><em>foo<br />\nbar</em></p>\n",
+ "example": 639,
+ "start_line": 9276,
+ "end_line": 9282,
+ "section": "Hard line breaks"
+ },
+ {
+ "markdown": "`code \nspan`\n",
+ "html": "<p><code>code span</code></p>\n",
+ "example": 640,
+ "start_line": 9287,
+ "end_line": 9292,
+ "section": "Hard line breaks"
+ },
+ {
+ "markdown": "`code\\\nspan`\n",
+ "html": "<p><code>code\\ span</code></p>\n",
+ "example": 641,
+ "start_line": 9295,
+ "end_line": 9300,
+ "section": "Hard line breaks"
+ },
+ {
+ "markdown": "<a href=\"foo \nbar\">\n",
+ "html": "<p><a href=\"foo \nbar\"></p>\n",
+ "example": 642,
+ "start_line": 9305,
+ "end_line": 9311,
+ "section": "Hard line breaks"
+ },
+ {
+ "markdown": "<a href=\"foo\\\nbar\">\n",
+ "html": "<p><a href=\"foo\\\nbar\"></p>\n",
+ "example": 643,
+ "start_line": 9314,
+ "end_line": 9320,
+ "section": "Hard line breaks"
+ },
+ {
+ "markdown": "foo\\\n",
+ "html": "<p>foo\\</p>\n",
+ "example": 644,
+ "start_line": 9327,
+ "end_line": 9331,
+ "section": "Hard line breaks"
+ },
+ {
+ "markdown": "foo \n",
+ "html": "<p>foo</p>\n",
+ "example": 645,
+ "start_line": 9334,
+ "end_line": 9338,
+ "section": "Hard line breaks"
+ },
+ {
+ "markdown": "### foo\\\n",
+ "html": "<h3>foo\\</h3>\n",
+ "example": 646,
+ "start_line": 9341,
+ "end_line": 9345,
+ "section": "Hard line breaks"
+ },
+ {
+ "markdown": "### foo \n",
+ "html": "<h3>foo</h3>\n",
+ "example": 647,
+ "start_line": 9348,
+ "end_line": 9352,
+ "section": "Hard line breaks"
+ },
+ {
+ "markdown": "foo\nbaz\n",
+ "html": "<p>foo\nbaz</p>\n",
+ "example": 648,
+ "start_line": 9363,
+ "end_line": 9369,
+ "section": "Soft line breaks"
+ },
+ {
+ "markdown": "foo \n baz\n",
+ "html": "<p>foo\nbaz</p>\n",
+ "example": 649,
+ "start_line": 9375,
+ "end_line": 9381,
+ "section": "Soft line breaks"
+ },
+ {
+ "markdown": "hello $.;'there\n",
+ "html": "<p>hello $.;'there</p>\n",
+ "example": 650,
+ "start_line": 9395,
+ "end_line": 9399,
+ "section": "Textual content"
+ },
+ {
+ "markdown": "Foo χρῆν\n",
+ "html": "<p>Foo χρῆν</p>\n",
+ "example": 651,
+ "start_line": 9402,
+ "end_line": 9406,
+ "section": "Textual content"
+ },
+ {
+ "markdown": "Multiple spaces\n",
+ "html": "<p>Multiple spaces</p>\n",
+ "example": 652,
+ "start_line": 9411,
+ "end_line": 9415,
+ "section": "Textual content"
+ }
+]
\ No newline at end of file
diff --git a/pkgs/markdown/tool/dartdoc_compare.dart b/pkgs/markdown/tool/dartdoc_compare.dart
new file mode 100644
index 0000000..e6100ee
--- /dev/null
+++ b/pkgs/markdown/tool/dartdoc_compare.dart
@@ -0,0 +1,189 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert' show jsonDecode, jsonEncode;
+import 'dart:io' show Directory, File, Platform, Process, exitCode;
+
+import 'package:args/args.dart' show ArgParser;
+import 'package:path/path.dart' show absolute;
+import 'package:yaml/yaml.dart' show loadYaml;
+
+const _dartdocDir = 'dartdoc-dir';
+const _markdownBefore = 'before';
+const _markdownAfter = 'after';
+const _sdk = 'sdk';
+const _help = 'help';
+
+void main(List<String> arguments) {
+ final parser = ArgParser()
+ ..addSeparator('Usage: dartdoc-compare.dart [OPTIONS] <dart-package>')
+ ..addOption(_dartdocDir, help: 'Directory of the dartdoc package')
+ ..addOption(_markdownBefore, help: "Markdown package 'before' ref")
+ ..addOption(
+ _markdownAfter,
+ defaultsTo: 'HEAD',
+ help: "Markdown package 'after' ref (or 'local')",
+ )
+ ..addFlag(
+ _sdk,
+ negatable: false,
+ help: 'Is the package the SDK?',
+ )
+ ..addFlag(_help, abbr: 'h', hide: true);
+
+ final options = parser.parse(arguments);
+ if (options[_help] as bool) {
+ print(parser.usage);
+ exitCode = 0;
+ return;
+ }
+ if (options[_dartdocDir] == null || options[_markdownBefore] == null) {
+ print(
+ 'Invalid arguments: Options --$_dartdocDir and --$_markdownBefore '
+ 'must be specified',
+ );
+ print(parser.usage);
+ exitCode = 1;
+ return;
+ }
+ final comparer = DartdocCompare(
+ options[_dartdocDir] as String,
+ options[_markdownBefore] as String,
+ options[_markdownAfter] as String,
+ absolute(options[_dartdocDir] as String, 'bin/dartdoc.dart'),
+ absolute(options[_dartdocDir] as String, 'pubspec.yaml'),
+ options[_sdk] as bool,
+ );
+
+ String? path;
+ if (comparer.sdk) {
+ if (options.rest.isNotEmpty) {
+ path = options.rest.single;
+ }
+ } else {
+ path = options.rest.single;
+ }
+
+ if (comparer.compare(path)) {
+ exitCode = 0;
+ } else {
+ exitCode = 1;
+ }
+}
+
+class DartdocCompare {
+ final String dartdocDir;
+ final String markdownBefore;
+ final String markdownAfter;
+ final String dartdocBin;
+ final String dartdocPubspecPath;
+ final bool sdk;
+ final String markdownPath = File(Platform.script.path).parent.parent.path;
+
+ DartdocCompare(
+ this.dartdocDir,
+ this.markdownBefore,
+ this.markdownAfter,
+ this.dartdocBin,
+ this.dartdocPubspecPath,
+ this.sdk,
+ );
+
+ bool compare(String? package) {
+ // Generate docs with Markdown "Before".
+ final outBefore = _runDartdoc(markdownBefore, package);
+
+ // Generate docs with Markdown "After".
+ final outAfter = _runDartdoc(markdownAfter, package);
+
+ // Compare outputs
+ final diffOptions = ['-r', '-B', outBefore, outAfter];
+ final result = Process.runSync('diff', diffOptions, runInShell: true);
+ final nlines = '\n'.allMatches(result.stdout as String).length;
+ print('Diff lines: $nlines');
+ print('diff ${diffOptions.join(" ")}');
+ return result.exitCode == 0;
+ }
+
+ String _runDartdoc(String markdownRef, String? path) {
+ print('==========================================================');
+ print('Running dartdoc for $markdownRef...');
+ print('==========================================================');
+ _doInPath(dartdocDir, () {
+ final returnCode = _updateDartdocPubspec(markdownRef);
+ if (returnCode != 0) {
+ throw Exception("Could not update dartdoc's pubspec!");
+ }
+ });
+ return _doInPath(path, () {
+ if (!sdk) {
+ _system('pub', ['upgrade']);
+ }
+ final out = Directory.systemTemp
+ .createTempSync('dartdoc-compare-${markdownRef}__');
+ const cmd = 'dart';
+ final args = [dartdocBin, '--output=${out.path}'];
+
+ if (sdk) {
+ args.add('--sdk-docs');
+ }
+
+ print('Command: $cmd ${args.join(' ')}');
+ final startTime = DateTime.now();
+ _system(cmd, args);
+ final endTime = DateTime.now();
+ final duration = endTime.difference(startTime).inSeconds;
+ print('dartdoc generation for $markdownRef took $duration seconds.');
+ print('');
+
+ return out.path;
+ });
+ }
+
+ int _updateDartdocPubspec(String markdownRef) {
+ var dartdocPubspec =
+ loadYaml(File(dartdocPubspecPath).readAsStringSync()) as Map;
+ // make modifiable copy
+ dartdocPubspec = jsonDecode(jsonEncode(dartdocPubspec)) as Map;
+
+ final dependencies = dartdocPubspec['dependencies'] as Map;
+
+ if (markdownRef == 'local') {
+ dependencies['markdown'] = {
+ 'path': markdownPath,
+ };
+ } else {
+ dependencies['markdown'] = {
+ 'git': {
+ 'url': 'git://github.com/dart-lang/markdown.git',
+ 'ref': markdownRef
+ }
+ };
+ }
+
+ File(dartdocPubspecPath).writeAsStringSync(jsonEncode(dartdocPubspec));
+ return _system('pub', ['upgrade']);
+ }
+}
+
+int _system(String cmd, List<String> args) {
+ final result = Process.runSync(cmd, args);
+ print(result.stdout);
+ print(result.stderr);
+ return result.exitCode;
+}
+
+T _doInPath<T>(String? path, T Function() f) {
+ if (path == null) {
+ return f();
+ }
+
+ final former = Directory.current.path;
+ Directory.current = path;
+ try {
+ return f();
+ } finally {
+ Directory.current = former;
+ }
+}
diff --git a/pkgs/markdown/tool/entities.json b/pkgs/markdown/tool/entities.json
new file mode 100644
index 0000000..557170b
--- /dev/null
+++ b/pkgs/markdown/tool/entities.json
@@ -0,0 +1,2233 @@
+{
+ "Æ": { "codepoints": [198], "characters": "\u00C6" },
+ "Æ": { "codepoints": [198], "characters": "\u00C6" },
+ "&": { "codepoints": [38], "characters": "\u0026" },
+ "&": { "codepoints": [38], "characters": "\u0026" },
+ "Á": { "codepoints": [193], "characters": "\u00C1" },
+ "Á": { "codepoints": [193], "characters": "\u00C1" },
+ "Ă": { "codepoints": [258], "characters": "\u0102" },
+ "Â": { "codepoints": [194], "characters": "\u00C2" },
+ "Â": { "codepoints": [194], "characters": "\u00C2" },
+ "А": { "codepoints": [1040], "characters": "\u0410" },
+ "𝔄": { "codepoints": [120068], "characters": "\uD835\uDD04" },
+ "À": { "codepoints": [192], "characters": "\u00C0" },
+ "À": { "codepoints": [192], "characters": "\u00C0" },
+ "Α": { "codepoints": [913], "characters": "\u0391" },
+ "Ā": { "codepoints": [256], "characters": "\u0100" },
+ "⩓": { "codepoints": [10835], "characters": "\u2A53" },
+ "Ą": { "codepoints": [260], "characters": "\u0104" },
+ "𝔸": { "codepoints": [120120], "characters": "\uD835\uDD38" },
+ "⁡": { "codepoints": [8289], "characters": "\u2061" },
+ "Å": { "codepoints": [197], "characters": "\u00C5" },
+ "Å": { "codepoints": [197], "characters": "\u00C5" },
+ "𝒜": { "codepoints": [119964], "characters": "\uD835\uDC9C" },
+ "≔": { "codepoints": [8788], "characters": "\u2254" },
+ "Ã": { "codepoints": [195], "characters": "\u00C3" },
+ "Ã": { "codepoints": [195], "characters": "\u00C3" },
+ "Ä": { "codepoints": [196], "characters": "\u00C4" },
+ "Ä": { "codepoints": [196], "characters": "\u00C4" },
+ "∖": { "codepoints": [8726], "characters": "\u2216" },
+ "⫧": { "codepoints": [10983], "characters": "\u2AE7" },
+ "⌆": { "codepoints": [8966], "characters": "\u2306" },
+ "Б": { "codepoints": [1041], "characters": "\u0411" },
+ "∵": { "codepoints": [8757], "characters": "\u2235" },
+ "ℬ": { "codepoints": [8492], "characters": "\u212C" },
+ "Β": { "codepoints": [914], "characters": "\u0392" },
+ "𝔅": { "codepoints": [120069], "characters": "\uD835\uDD05" },
+ "𝔹": { "codepoints": [120121], "characters": "\uD835\uDD39" },
+ "˘": { "codepoints": [728], "characters": "\u02D8" },
+ "ℬ": { "codepoints": [8492], "characters": "\u212C" },
+ "≎": { "codepoints": [8782], "characters": "\u224E" },
+ "Ч": { "codepoints": [1063], "characters": "\u0427" },
+ "©": { "codepoints": [169], "characters": "\u00A9" },
+ "©": { "codepoints": [169], "characters": "\u00A9" },
+ "Ć": { "codepoints": [262], "characters": "\u0106" },
+ "⋒": { "codepoints": [8914], "characters": "\u22D2" },
+ "ⅅ": { "codepoints": [8517], "characters": "\u2145" },
+ "ℭ": { "codepoints": [8493], "characters": "\u212D" },
+ "Č": { "codepoints": [268], "characters": "\u010C" },
+ "Ç": { "codepoints": [199], "characters": "\u00C7" },
+ "Ç": { "codepoints": [199], "characters": "\u00C7" },
+ "Ĉ": { "codepoints": [264], "characters": "\u0108" },
+ "∰": { "codepoints": [8752], "characters": "\u2230" },
+ "Ċ": { "codepoints": [266], "characters": "\u010A" },
+ "¸": { "codepoints": [184], "characters": "\u00B8" },
+ "·": { "codepoints": [183], "characters": "\u00B7" },
+ "ℭ": { "codepoints": [8493], "characters": "\u212D" },
+ "Χ": { "codepoints": [935], "characters": "\u03A7" },
+ "⊙": { "codepoints": [8857], "characters": "\u2299" },
+ "⊖": { "codepoints": [8854], "characters": "\u2296" },
+ "⊕": { "codepoints": [8853], "characters": "\u2295" },
+ "⊗": { "codepoints": [8855], "characters": "\u2297" },
+ "∲": { "codepoints": [8754], "characters": "\u2232" },
+ "”": { "codepoints": [8221], "characters": "\u201D" },
+ "’": { "codepoints": [8217], "characters": "\u2019" },
+ "∷": { "codepoints": [8759], "characters": "\u2237" },
+ "⩴": { "codepoints": [10868], "characters": "\u2A74" },
+ "≡": { "codepoints": [8801], "characters": "\u2261" },
+ "∯": { "codepoints": [8751], "characters": "\u222F" },
+ "∮": { "codepoints": [8750], "characters": "\u222E" },
+ "ℂ": { "codepoints": [8450], "characters": "\u2102" },
+ "∐": { "codepoints": [8720], "characters": "\u2210" },
+ "∳": { "codepoints": [8755], "characters": "\u2233" },
+ "⨯": { "codepoints": [10799], "characters": "\u2A2F" },
+ "𝒞": { "codepoints": [119966], "characters": "\uD835\uDC9E" },
+ "⋓": { "codepoints": [8915], "characters": "\u22D3" },
+ "≍": { "codepoints": [8781], "characters": "\u224D" },
+ "ⅅ": { "codepoints": [8517], "characters": "\u2145" },
+ "⤑": { "codepoints": [10513], "characters": "\u2911" },
+ "Ђ": { "codepoints": [1026], "characters": "\u0402" },
+ "Ѕ": { "codepoints": [1029], "characters": "\u0405" },
+ "Џ": { "codepoints": [1039], "characters": "\u040F" },
+ "‡": { "codepoints": [8225], "characters": "\u2021" },
+ "↡": { "codepoints": [8609], "characters": "\u21A1" },
+ "⫤": { "codepoints": [10980], "characters": "\u2AE4" },
+ "Ď": { "codepoints": [270], "characters": "\u010E" },
+ "Д": { "codepoints": [1044], "characters": "\u0414" },
+ "∇": { "codepoints": [8711], "characters": "\u2207" },
+ "Δ": { "codepoints": [916], "characters": "\u0394" },
+ "𝔇": { "codepoints": [120071], "characters": "\uD835\uDD07" },
+ "´": { "codepoints": [180], "characters": "\u00B4" },
+ "˙": { "codepoints": [729], "characters": "\u02D9" },
+ "˝": { "codepoints": [733], "characters": "\u02DD" },
+ "`": { "codepoints": [96], "characters": "\u0060" },
+ "˜": { "codepoints": [732], "characters": "\u02DC" },
+ "⋄": { "codepoints": [8900], "characters": "\u22C4" },
+ "ⅆ": { "codepoints": [8518], "characters": "\u2146" },
+ "𝔻": { "codepoints": [120123], "characters": "\uD835\uDD3B" },
+ "¨": { "codepoints": [168], "characters": "\u00A8" },
+ "⃜": { "codepoints": [8412], "characters": "\u20DC" },
+ "≐": { "codepoints": [8784], "characters": "\u2250" },
+ "∯": { "codepoints": [8751], "characters": "\u222F" },
+ "¨": { "codepoints": [168], "characters": "\u00A8" },
+ "⇓": { "codepoints": [8659], "characters": "\u21D3" },
+ "⇐": { "codepoints": [8656], "characters": "\u21D0" },
+ "⇔": { "codepoints": [8660], "characters": "\u21D4" },
+ "⫤": { "codepoints": [10980], "characters": "\u2AE4" },
+ "⟸": { "codepoints": [10232], "characters": "\u27F8" },
+ "⟺": { "codepoints": [10234], "characters": "\u27FA" },
+ "⟹": { "codepoints": [10233], "characters": "\u27F9" },
+ "⇒": { "codepoints": [8658], "characters": "\u21D2" },
+ "⊨": { "codepoints": [8872], "characters": "\u22A8" },
+ "⇑": { "codepoints": [8657], "characters": "\u21D1" },
+ "⇕": { "codepoints": [8661], "characters": "\u21D5" },
+ "∥": { "codepoints": [8741], "characters": "\u2225" },
+ "↓": { "codepoints": [8595], "characters": "\u2193" },
+ "⤓": { "codepoints": [10515], "characters": "\u2913" },
+ "⇵": { "codepoints": [8693], "characters": "\u21F5" },
+ "̑": { "codepoints": [785], "characters": "\u0311" },
+ "⥐": { "codepoints": [10576], "characters": "\u2950" },
+ "⥞": { "codepoints": [10590], "characters": "\u295E" },
+ "↽": { "codepoints": [8637], "characters": "\u21BD" },
+ "⥖": { "codepoints": [10582], "characters": "\u2956" },
+ "⥟": { "codepoints": [10591], "characters": "\u295F" },
+ "⇁": { "codepoints": [8641], "characters": "\u21C1" },
+ "⥗": { "codepoints": [10583], "characters": "\u2957" },
+ "⊤": { "codepoints": [8868], "characters": "\u22A4" },
+ "↧": { "codepoints": [8615], "characters": "\u21A7" },
+ "⇓": { "codepoints": [8659], "characters": "\u21D3" },
+ "𝒟": { "codepoints": [119967], "characters": "\uD835\uDC9F" },
+ "Đ": { "codepoints": [272], "characters": "\u0110" },
+ "Ŋ": { "codepoints": [330], "characters": "\u014A" },
+ "Ð": { "codepoints": [208], "characters": "\u00D0" },
+ "Ð": { "codepoints": [208], "characters": "\u00D0" },
+ "É": { "codepoints": [201], "characters": "\u00C9" },
+ "É": { "codepoints": [201], "characters": "\u00C9" },
+ "Ě": { "codepoints": [282], "characters": "\u011A" },
+ "Ê": { "codepoints": [202], "characters": "\u00CA" },
+ "Ê": { "codepoints": [202], "characters": "\u00CA" },
+ "Э": { "codepoints": [1069], "characters": "\u042D" },
+ "Ė": { "codepoints": [278], "characters": "\u0116" },
+ "𝔈": { "codepoints": [120072], "characters": "\uD835\uDD08" },
+ "È": { "codepoints": [200], "characters": "\u00C8" },
+ "È": { "codepoints": [200], "characters": "\u00C8" },
+ "∈": { "codepoints": [8712], "characters": "\u2208" },
+ "Ē": { "codepoints": [274], "characters": "\u0112" },
+ "◻": { "codepoints": [9723], "characters": "\u25FB" },
+ "▫": { "codepoints": [9643], "characters": "\u25AB" },
+ "Ę": { "codepoints": [280], "characters": "\u0118" },
+ "𝔼": { "codepoints": [120124], "characters": "\uD835\uDD3C" },
+ "Ε": { "codepoints": [917], "characters": "\u0395" },
+ "⩵": { "codepoints": [10869], "characters": "\u2A75" },
+ "≂": { "codepoints": [8770], "characters": "\u2242" },
+ "⇌": { "codepoints": [8652], "characters": "\u21CC" },
+ "ℰ": { "codepoints": [8496], "characters": "\u2130" },
+ "⩳": { "codepoints": [10867], "characters": "\u2A73" },
+ "Η": { "codepoints": [919], "characters": "\u0397" },
+ "Ë": { "codepoints": [203], "characters": "\u00CB" },
+ "Ë": { "codepoints": [203], "characters": "\u00CB" },
+ "∃": { "codepoints": [8707], "characters": "\u2203" },
+ "ⅇ": { "codepoints": [8519], "characters": "\u2147" },
+ "Ф": { "codepoints": [1060], "characters": "\u0424" },
+ "𝔉": { "codepoints": [120073], "characters": "\uD835\uDD09" },
+ "◼": { "codepoints": [9724], "characters": "\u25FC" },
+ "▪": { "codepoints": [9642], "characters": "\u25AA" },
+ "𝔽": { "codepoints": [120125], "characters": "\uD835\uDD3D" },
+ "∀": { "codepoints": [8704], "characters": "\u2200" },
+ "ℱ": { "codepoints": [8497], "characters": "\u2131" },
+ "ℱ": { "codepoints": [8497], "characters": "\u2131" },
+ "Ѓ": { "codepoints": [1027], "characters": "\u0403" },
+ ">": { "codepoints": [62], "characters": "\u003E" },
+ ">": { "codepoints": [62], "characters": "\u003E" },
+ "Γ": { "codepoints": [915], "characters": "\u0393" },
+ "Ϝ": { "codepoints": [988], "characters": "\u03DC" },
+ "Ğ": { "codepoints": [286], "characters": "\u011E" },
+ "Ģ": { "codepoints": [290], "characters": "\u0122" },
+ "Ĝ": { "codepoints": [284], "characters": "\u011C" },
+ "Г": { "codepoints": [1043], "characters": "\u0413" },
+ "Ġ": { "codepoints": [288], "characters": "\u0120" },
+ "𝔊": { "codepoints": [120074], "characters": "\uD835\uDD0A" },
+ "⋙": { "codepoints": [8921], "characters": "\u22D9" },
+ "𝔾": { "codepoints": [120126], "characters": "\uD835\uDD3E" },
+ "≥": { "codepoints": [8805], "characters": "\u2265" },
+ "⋛": { "codepoints": [8923], "characters": "\u22DB" },
+ "≧": { "codepoints": [8807], "characters": "\u2267" },
+ "⪢": { "codepoints": [10914], "characters": "\u2AA2" },
+ "≷": { "codepoints": [8823], "characters": "\u2277" },
+ "⩾": { "codepoints": [10878], "characters": "\u2A7E" },
+ "≳": { "codepoints": [8819], "characters": "\u2273" },
+ "𝒢": { "codepoints": [119970], "characters": "\uD835\uDCA2" },
+ "≫": { "codepoints": [8811], "characters": "\u226B" },
+ "Ъ": { "codepoints": [1066], "characters": "\u042A" },
+ "ˇ": { "codepoints": [711], "characters": "\u02C7" },
+ "^": { "codepoints": [94], "characters": "\u005E" },
+ "Ĥ": { "codepoints": [292], "characters": "\u0124" },
+ "ℌ": { "codepoints": [8460], "characters": "\u210C" },
+ "ℋ": { "codepoints": [8459], "characters": "\u210B" },
+ "ℍ": { "codepoints": [8461], "characters": "\u210D" },
+ "─": { "codepoints": [9472], "characters": "\u2500" },
+ "ℋ": { "codepoints": [8459], "characters": "\u210B" },
+ "Ħ": { "codepoints": [294], "characters": "\u0126" },
+ "≎": { "codepoints": [8782], "characters": "\u224E" },
+ "≏": { "codepoints": [8783], "characters": "\u224F" },
+ "Е": { "codepoints": [1045], "characters": "\u0415" },
+ "IJ": { "codepoints": [306], "characters": "\u0132" },
+ "Ё": { "codepoints": [1025], "characters": "\u0401" },
+ "Í": { "codepoints": [205], "characters": "\u00CD" },
+ "Í": { "codepoints": [205], "characters": "\u00CD" },
+ "Î": { "codepoints": [206], "characters": "\u00CE" },
+ "Î": { "codepoints": [206], "characters": "\u00CE" },
+ "И": { "codepoints": [1048], "characters": "\u0418" },
+ "İ": { "codepoints": [304], "characters": "\u0130" },
+ "ℑ": { "codepoints": [8465], "characters": "\u2111" },
+ "Ì": { "codepoints": [204], "characters": "\u00CC" },
+ "Ì": { "codepoints": [204], "characters": "\u00CC" },
+ "ℑ": { "codepoints": [8465], "characters": "\u2111" },
+ "Ī": { "codepoints": [298], "characters": "\u012A" },
+ "ⅈ": { "codepoints": [8520], "characters": "\u2148" },
+ "⇒": { "codepoints": [8658], "characters": "\u21D2" },
+ "∬": { "codepoints": [8748], "characters": "\u222C" },
+ "∫": { "codepoints": [8747], "characters": "\u222B" },
+ "⋂": { "codepoints": [8898], "characters": "\u22C2" },
+ "⁣": { "codepoints": [8291], "characters": "\u2063" },
+ "⁢": { "codepoints": [8290], "characters": "\u2062" },
+ "Į": { "codepoints": [302], "characters": "\u012E" },
+ "𝕀": { "codepoints": [120128], "characters": "\uD835\uDD40" },
+ "Ι": { "codepoints": [921], "characters": "\u0399" },
+ "ℐ": { "codepoints": [8464], "characters": "\u2110" },
+ "Ĩ": { "codepoints": [296], "characters": "\u0128" },
+ "І": { "codepoints": [1030], "characters": "\u0406" },
+ "Ï": { "codepoints": [207], "characters": "\u00CF" },
+ "Ï": { "codepoints": [207], "characters": "\u00CF" },
+ "Ĵ": { "codepoints": [308], "characters": "\u0134" },
+ "Й": { "codepoints": [1049], "characters": "\u0419" },
+ "𝔍": { "codepoints": [120077], "characters": "\uD835\uDD0D" },
+ "𝕁": { "codepoints": [120129], "characters": "\uD835\uDD41" },
+ "𝒥": { "codepoints": [119973], "characters": "\uD835\uDCA5" },
+ "Ј": { "codepoints": [1032], "characters": "\u0408" },
+ "Є": { "codepoints": [1028], "characters": "\u0404" },
+ "Х": { "codepoints": [1061], "characters": "\u0425" },
+ "Ќ": { "codepoints": [1036], "characters": "\u040C" },
+ "Κ": { "codepoints": [922], "characters": "\u039A" },
+ "Ķ": { "codepoints": [310], "characters": "\u0136" },
+ "К": { "codepoints": [1050], "characters": "\u041A" },
+ "𝔎": { "codepoints": [120078], "characters": "\uD835\uDD0E" },
+ "𝕂": { "codepoints": [120130], "characters": "\uD835\uDD42" },
+ "𝒦": { "codepoints": [119974], "characters": "\uD835\uDCA6" },
+ "Љ": { "codepoints": [1033], "characters": "\u0409" },
+ "<": { "codepoints": [60], "characters": "\u003C" },
+ "<": { "codepoints": [60], "characters": "\u003C" },
+ "Ĺ": { "codepoints": [313], "characters": "\u0139" },
+ "Λ": { "codepoints": [923], "characters": "\u039B" },
+ "⟪": { "codepoints": [10218], "characters": "\u27EA" },
+ "ℒ": { "codepoints": [8466], "characters": "\u2112" },
+ "↞": { "codepoints": [8606], "characters": "\u219E" },
+ "Ľ": { "codepoints": [317], "characters": "\u013D" },
+ "Ļ": { "codepoints": [315], "characters": "\u013B" },
+ "Л": { "codepoints": [1051], "characters": "\u041B" },
+ "⟨": { "codepoints": [10216], "characters": "\u27E8" },
+ "←": { "codepoints": [8592], "characters": "\u2190" },
+ "⇤": { "codepoints": [8676], "characters": "\u21E4" },
+ "⇆": { "codepoints": [8646], "characters": "\u21C6" },
+ "⌈": { "codepoints": [8968], "characters": "\u2308" },
+ "⟦": { "codepoints": [10214], "characters": "\u27E6" },
+ "⥡": { "codepoints": [10593], "characters": "\u2961" },
+ "⇃": { "codepoints": [8643], "characters": "\u21C3" },
+ "⥙": { "codepoints": [10585], "characters": "\u2959" },
+ "⌊": { "codepoints": [8970], "characters": "\u230A" },
+ "↔": { "codepoints": [8596], "characters": "\u2194" },
+ "⥎": { "codepoints": [10574], "characters": "\u294E" },
+ "⊣": { "codepoints": [8867], "characters": "\u22A3" },
+ "↤": { "codepoints": [8612], "characters": "\u21A4" },
+ "⥚": { "codepoints": [10586], "characters": "\u295A" },
+ "⊲": { "codepoints": [8882], "characters": "\u22B2" },
+ "⧏": { "codepoints": [10703], "characters": "\u29CF" },
+ "⊴": { "codepoints": [8884], "characters": "\u22B4" },
+ "⥑": { "codepoints": [10577], "characters": "\u2951" },
+ "⥠": { "codepoints": [10592], "characters": "\u2960" },
+ "↿": { "codepoints": [8639], "characters": "\u21BF" },
+ "⥘": { "codepoints": [10584], "characters": "\u2958" },
+ "↼": { "codepoints": [8636], "characters": "\u21BC" },
+ "⥒": { "codepoints": [10578], "characters": "\u2952" },
+ "⇐": { "codepoints": [8656], "characters": "\u21D0" },
+ "⇔": { "codepoints": [8660], "characters": "\u21D4" },
+ "⋚": { "codepoints": [8922], "characters": "\u22DA" },
+ "≦": { "codepoints": [8806], "characters": "\u2266" },
+ "≶": { "codepoints": [8822], "characters": "\u2276" },
+ "⪡": { "codepoints": [10913], "characters": "\u2AA1" },
+ "⩽": { "codepoints": [10877], "characters": "\u2A7D" },
+ "≲": { "codepoints": [8818], "characters": "\u2272" },
+ "𝔏": { "codepoints": [120079], "characters": "\uD835\uDD0F" },
+ "⋘": { "codepoints": [8920], "characters": "\u22D8" },
+ "⇚": { "codepoints": [8666], "characters": "\u21DA" },
+ "Ŀ": { "codepoints": [319], "characters": "\u013F" },
+ "⟵": { "codepoints": [10229], "characters": "\u27F5" },
+ "⟷": { "codepoints": [10231], "characters": "\u27F7" },
+ "⟶": { "codepoints": [10230], "characters": "\u27F6" },
+ "⟸": { "codepoints": [10232], "characters": "\u27F8" },
+ "⟺": { "codepoints": [10234], "characters": "\u27FA" },
+ "⟹": { "codepoints": [10233], "characters": "\u27F9" },
+ "𝕃": { "codepoints": [120131], "characters": "\uD835\uDD43" },
+ "↙": { "codepoints": [8601], "characters": "\u2199" },
+ "↘": { "codepoints": [8600], "characters": "\u2198" },
+ "ℒ": { "codepoints": [8466], "characters": "\u2112" },
+ "↰": { "codepoints": [8624], "characters": "\u21B0" },
+ "Ł": { "codepoints": [321], "characters": "\u0141" },
+ "≪": { "codepoints": [8810], "characters": "\u226A" },
+ "⤅": { "codepoints": [10501], "characters": "\u2905" },
+ "М": { "codepoints": [1052], "characters": "\u041C" },
+ " ": { "codepoints": [8287], "characters": "\u205F" },
+ "ℳ": { "codepoints": [8499], "characters": "\u2133" },
+ "𝔐": { "codepoints": [120080], "characters": "\uD835\uDD10" },
+ "∓": { "codepoints": [8723], "characters": "\u2213" },
+ "𝕄": { "codepoints": [120132], "characters": "\uD835\uDD44" },
+ "ℳ": { "codepoints": [8499], "characters": "\u2133" },
+ "Μ": { "codepoints": [924], "characters": "\u039C" },
+ "Њ": { "codepoints": [1034], "characters": "\u040A" },
+ "Ń": { "codepoints": [323], "characters": "\u0143" },
+ "Ň": { "codepoints": [327], "characters": "\u0147" },
+ "Ņ": { "codepoints": [325], "characters": "\u0145" },
+ "Н": { "codepoints": [1053], "characters": "\u041D" },
+ "​": { "codepoints": [8203], "characters": "\u200B" },
+ "​": { "codepoints": [8203], "characters": "\u200B" },
+ "​": { "codepoints": [8203], "characters": "\u200B" },
+ "​": { "codepoints": [8203], "characters": "\u200B" },
+ "≫": { "codepoints": [8811], "characters": "\u226B" },
+ "≪": { "codepoints": [8810], "characters": "\u226A" },
+ "
": { "codepoints": [10], "characters": "\u000A" },
+ "𝔑": { "codepoints": [120081], "characters": "\uD835\uDD11" },
+ "⁠": { "codepoints": [8288], "characters": "\u2060" },
+ " ": { "codepoints": [160], "characters": "\u00A0" },
+ "ℕ": { "codepoints": [8469], "characters": "\u2115" },
+ "⫬": { "codepoints": [10988], "characters": "\u2AEC" },
+ "≢": { "codepoints": [8802], "characters": "\u2262" },
+ "≭": { "codepoints": [8813], "characters": "\u226D" },
+ "∦": { "codepoints": [8742], "characters": "\u2226" },
+ "∉": { "codepoints": [8713], "characters": "\u2209" },
+ "≠": { "codepoints": [8800], "characters": "\u2260" },
+ "≂̸": { "codepoints": [8770, 824], "characters": "\u2242\u0338" },
+ "∄": { "codepoints": [8708], "characters": "\u2204" },
+ "≯": { "codepoints": [8815], "characters": "\u226F" },
+ "≱": { "codepoints": [8817], "characters": "\u2271" },
+ "≧̸": { "codepoints": [8807, 824], "characters": "\u2267\u0338" },
+ "≫̸": { "codepoints": [8811, 824], "characters": "\u226B\u0338" },
+ "≹": { "codepoints": [8825], "characters": "\u2279" },
+ "⩾̸": { "codepoints": [10878, 824], "characters": "\u2A7E\u0338" },
+ "≵": { "codepoints": [8821], "characters": "\u2275" },
+ "≎̸": { "codepoints": [8782, 824], "characters": "\u224E\u0338" },
+ "≏̸": { "codepoints": [8783, 824], "characters": "\u224F\u0338" },
+ "⋪": { "codepoints": [8938], "characters": "\u22EA" },
+ "⧏̸": { "codepoints": [10703, 824], "characters": "\u29CF\u0338" },
+ "⋬": { "codepoints": [8940], "characters": "\u22EC" },
+ "≮": { "codepoints": [8814], "characters": "\u226E" },
+ "≰": { "codepoints": [8816], "characters": "\u2270" },
+ "≸": { "codepoints": [8824], "characters": "\u2278" },
+ "≪̸": { "codepoints": [8810, 824], "characters": "\u226A\u0338" },
+ "⩽̸": { "codepoints": [10877, 824], "characters": "\u2A7D\u0338" },
+ "≴": { "codepoints": [8820], "characters": "\u2274" },
+ "⪢̸": { "codepoints": [10914, 824], "characters": "\u2AA2\u0338" },
+ "⪡̸": { "codepoints": [10913, 824], "characters": "\u2AA1\u0338" },
+ "⊀": { "codepoints": [8832], "characters": "\u2280" },
+ "⪯̸": { "codepoints": [10927, 824], "characters": "\u2AAF\u0338" },
+ "⋠": { "codepoints": [8928], "characters": "\u22E0" },
+ "∌": { "codepoints": [8716], "characters": "\u220C" },
+ "⋫": { "codepoints": [8939], "characters": "\u22EB" },
+ "⧐̸": { "codepoints": [10704, 824], "characters": "\u29D0\u0338" },
+ "⋭": { "codepoints": [8941], "characters": "\u22ED" },
+ "⊏̸": { "codepoints": [8847, 824], "characters": "\u228F\u0338" },
+ "⋢": { "codepoints": [8930], "characters": "\u22E2" },
+ "⊐̸": { "codepoints": [8848, 824], "characters": "\u2290\u0338" },
+ "⋣": { "codepoints": [8931], "characters": "\u22E3" },
+ "⊂⃒": { "codepoints": [8834, 8402], "characters": "\u2282\u20D2" },
+ "⊈": { "codepoints": [8840], "characters": "\u2288" },
+ "⊁": { "codepoints": [8833], "characters": "\u2281" },
+ "⪰̸": { "codepoints": [10928, 824], "characters": "\u2AB0\u0338" },
+ "⋡": { "codepoints": [8929], "characters": "\u22E1" },
+ "≿̸": { "codepoints": [8831, 824], "characters": "\u227F\u0338" },
+ "⊃⃒": { "codepoints": [8835, 8402], "characters": "\u2283\u20D2" },
+ "⊉": { "codepoints": [8841], "characters": "\u2289" },
+ "≁": { "codepoints": [8769], "characters": "\u2241" },
+ "≄": { "codepoints": [8772], "characters": "\u2244" },
+ "≇": { "codepoints": [8775], "characters": "\u2247" },
+ "≉": { "codepoints": [8777], "characters": "\u2249" },
+ "∤": { "codepoints": [8740], "characters": "\u2224" },
+ "𝒩": { "codepoints": [119977], "characters": "\uD835\uDCA9" },
+ "Ñ": { "codepoints": [209], "characters": "\u00D1" },
+ "Ñ": { "codepoints": [209], "characters": "\u00D1" },
+ "Ν": { "codepoints": [925], "characters": "\u039D" },
+ "Œ": { "codepoints": [338], "characters": "\u0152" },
+ "Ó": { "codepoints": [211], "characters": "\u00D3" },
+ "Ó": { "codepoints": [211], "characters": "\u00D3" },
+ "Ô": { "codepoints": [212], "characters": "\u00D4" },
+ "Ô": { "codepoints": [212], "characters": "\u00D4" },
+ "О": { "codepoints": [1054], "characters": "\u041E" },
+ "Ő": { "codepoints": [336], "characters": "\u0150" },
+ "𝔒": { "codepoints": [120082], "characters": "\uD835\uDD12" },
+ "Ò": { "codepoints": [210], "characters": "\u00D2" },
+ "Ò": { "codepoints": [210], "characters": "\u00D2" },
+ "Ō": { "codepoints": [332], "characters": "\u014C" },
+ "Ω": { "codepoints": [937], "characters": "\u03A9" },
+ "Ο": { "codepoints": [927], "characters": "\u039F" },
+ "𝕆": { "codepoints": [120134], "characters": "\uD835\uDD46" },
+ "“": { "codepoints": [8220], "characters": "\u201C" },
+ "‘": { "codepoints": [8216], "characters": "\u2018" },
+ "⩔": { "codepoints": [10836], "characters": "\u2A54" },
+ "𝒪": { "codepoints": [119978], "characters": "\uD835\uDCAA" },
+ "Ø": { "codepoints": [216], "characters": "\u00D8" },
+ "Ø": { "codepoints": [216], "characters": "\u00D8" },
+ "Õ": { "codepoints": [213], "characters": "\u00D5" },
+ "Õ": { "codepoints": [213], "characters": "\u00D5" },
+ "⨷": { "codepoints": [10807], "characters": "\u2A37" },
+ "Ö": { "codepoints": [214], "characters": "\u00D6" },
+ "Ö": { "codepoints": [214], "characters": "\u00D6" },
+ "‾": { "codepoints": [8254], "characters": "\u203E" },
+ "⏞": { "codepoints": [9182], "characters": "\u23DE" },
+ "⎴": { "codepoints": [9140], "characters": "\u23B4" },
+ "⏜": { "codepoints": [9180], "characters": "\u23DC" },
+ "∂": { "codepoints": [8706], "characters": "\u2202" },
+ "П": { "codepoints": [1055], "characters": "\u041F" },
+ "𝔓": { "codepoints": [120083], "characters": "\uD835\uDD13" },
+ "Φ": { "codepoints": [934], "characters": "\u03A6" },
+ "Π": { "codepoints": [928], "characters": "\u03A0" },
+ "±": { "codepoints": [177], "characters": "\u00B1" },
+ "ℌ": { "codepoints": [8460], "characters": "\u210C" },
+ "ℙ": { "codepoints": [8473], "characters": "\u2119" },
+ "⪻": { "codepoints": [10939], "characters": "\u2ABB" },
+ "≺": { "codepoints": [8826], "characters": "\u227A" },
+ "⪯": { "codepoints": [10927], "characters": "\u2AAF" },
+ "≼": { "codepoints": [8828], "characters": "\u227C" },
+ "≾": { "codepoints": [8830], "characters": "\u227E" },
+ "″": { "codepoints": [8243], "characters": "\u2033" },
+ "∏": { "codepoints": [8719], "characters": "\u220F" },
+ "∷": { "codepoints": [8759], "characters": "\u2237" },
+ "∝": { "codepoints": [8733], "characters": "\u221D" },
+ "𝒫": { "codepoints": [119979], "characters": "\uD835\uDCAB" },
+ "Ψ": { "codepoints": [936], "characters": "\u03A8" },
+ """: { "codepoints": [34], "characters": "\u0022" },
+ """: { "codepoints": [34], "characters": "\u0022" },
+ "𝔔": { "codepoints": [120084], "characters": "\uD835\uDD14" },
+ "ℚ": { "codepoints": [8474], "characters": "\u211A" },
+ "𝒬": { "codepoints": [119980], "characters": "\uD835\uDCAC" },
+ "⤐": { "codepoints": [10512], "characters": "\u2910" },
+ "®": { "codepoints": [174], "characters": "\u00AE" },
+ "®": { "codepoints": [174], "characters": "\u00AE" },
+ "Ŕ": { "codepoints": [340], "characters": "\u0154" },
+ "⟫": { "codepoints": [10219], "characters": "\u27EB" },
+ "↠": { "codepoints": [8608], "characters": "\u21A0" },
+ "⤖": { "codepoints": [10518], "characters": "\u2916" },
+ "Ř": { "codepoints": [344], "characters": "\u0158" },
+ "Ŗ": { "codepoints": [342], "characters": "\u0156" },
+ "Р": { "codepoints": [1056], "characters": "\u0420" },
+ "ℜ": { "codepoints": [8476], "characters": "\u211C" },
+ "∋": { "codepoints": [8715], "characters": "\u220B" },
+ "⇋": { "codepoints": [8651], "characters": "\u21CB" },
+ "⥯": { "codepoints": [10607], "characters": "\u296F" },
+ "ℜ": { "codepoints": [8476], "characters": "\u211C" },
+ "Ρ": { "codepoints": [929], "characters": "\u03A1" },
+ "⟩": { "codepoints": [10217], "characters": "\u27E9" },
+ "→": { "codepoints": [8594], "characters": "\u2192" },
+ "⇥": { "codepoints": [8677], "characters": "\u21E5" },
+ "⇄": { "codepoints": [8644], "characters": "\u21C4" },
+ "⌉": { "codepoints": [8969], "characters": "\u2309" },
+ "⟧": { "codepoints": [10215], "characters": "\u27E7" },
+ "⥝": { "codepoints": [10589], "characters": "\u295D" },
+ "⇂": { "codepoints": [8642], "characters": "\u21C2" },
+ "⥕": { "codepoints": [10581], "characters": "\u2955" },
+ "⌋": { "codepoints": [8971], "characters": "\u230B" },
+ "⊢": { "codepoints": [8866], "characters": "\u22A2" },
+ "↦": { "codepoints": [8614], "characters": "\u21A6" },
+ "⥛": { "codepoints": [10587], "characters": "\u295B" },
+ "⊳": { "codepoints": [8883], "characters": "\u22B3" },
+ "⧐": { "codepoints": [10704], "characters": "\u29D0" },
+ "⊵": { "codepoints": [8885], "characters": "\u22B5" },
+ "⥏": { "codepoints": [10575], "characters": "\u294F" },
+ "⥜": { "codepoints": [10588], "characters": "\u295C" },
+ "↾": { "codepoints": [8638], "characters": "\u21BE" },
+ "⥔": { "codepoints": [10580], "characters": "\u2954" },
+ "⇀": { "codepoints": [8640], "characters": "\u21C0" },
+ "⥓": { "codepoints": [10579], "characters": "\u2953" },
+ "⇒": { "codepoints": [8658], "characters": "\u21D2" },
+ "ℝ": { "codepoints": [8477], "characters": "\u211D" },
+ "⥰": { "codepoints": [10608], "characters": "\u2970" },
+ "⇛": { "codepoints": [8667], "characters": "\u21DB" },
+ "ℛ": { "codepoints": [8475], "characters": "\u211B" },
+ "↱": { "codepoints": [8625], "characters": "\u21B1" },
+ "⧴": { "codepoints": [10740], "characters": "\u29F4" },
+ "Щ": { "codepoints": [1065], "characters": "\u0429" },
+ "Ш": { "codepoints": [1064], "characters": "\u0428" },
+ "Ь": { "codepoints": [1068], "characters": "\u042C" },
+ "Ś": { "codepoints": [346], "characters": "\u015A" },
+ "⪼": { "codepoints": [10940], "characters": "\u2ABC" },
+ "Š": { "codepoints": [352], "characters": "\u0160" },
+ "Ş": { "codepoints": [350], "characters": "\u015E" },
+ "Ŝ": { "codepoints": [348], "characters": "\u015C" },
+ "С": { "codepoints": [1057], "characters": "\u0421" },
+ "𝔖": { "codepoints": [120086], "characters": "\uD835\uDD16" },
+ "↓": { "codepoints": [8595], "characters": "\u2193" },
+ "←": { "codepoints": [8592], "characters": "\u2190" },
+ "→": { "codepoints": [8594], "characters": "\u2192" },
+ "↑": { "codepoints": [8593], "characters": "\u2191" },
+ "Σ": { "codepoints": [931], "characters": "\u03A3" },
+ "∘": { "codepoints": [8728], "characters": "\u2218" },
+ "𝕊": { "codepoints": [120138], "characters": "\uD835\uDD4A" },
+ "√": { "codepoints": [8730], "characters": "\u221A" },
+ "□": { "codepoints": [9633], "characters": "\u25A1" },
+ "⊓": { "codepoints": [8851], "characters": "\u2293" },
+ "⊏": { "codepoints": [8847], "characters": "\u228F" },
+ "⊑": { "codepoints": [8849], "characters": "\u2291" },
+ "⊐": { "codepoints": [8848], "characters": "\u2290" },
+ "⊒": { "codepoints": [8850], "characters": "\u2292" },
+ "⊔": { "codepoints": [8852], "characters": "\u2294" },
+ "𝒮": { "codepoints": [119982], "characters": "\uD835\uDCAE" },
+ "⋆": { "codepoints": [8902], "characters": "\u22C6" },
+ "⋐": { "codepoints": [8912], "characters": "\u22D0" },
+ "⋐": { "codepoints": [8912], "characters": "\u22D0" },
+ "⊆": { "codepoints": [8838], "characters": "\u2286" },
+ "≻": { "codepoints": [8827], "characters": "\u227B" },
+ "⪰": { "codepoints": [10928], "characters": "\u2AB0" },
+ "≽": { "codepoints": [8829], "characters": "\u227D" },
+ "≿": { "codepoints": [8831], "characters": "\u227F" },
+ "∋": { "codepoints": [8715], "characters": "\u220B" },
+ "∑": { "codepoints": [8721], "characters": "\u2211" },
+ "⋑": { "codepoints": [8913], "characters": "\u22D1" },
+ "⊃": { "codepoints": [8835], "characters": "\u2283" },
+ "⊇": { "codepoints": [8839], "characters": "\u2287" },
+ "⋑": { "codepoints": [8913], "characters": "\u22D1" },
+ "Þ": { "codepoints": [222], "characters": "\u00DE" },
+ "Þ": { "codepoints": [222], "characters": "\u00DE" },
+ "™": { "codepoints": [8482], "characters": "\u2122" },
+ "Ћ": { "codepoints": [1035], "characters": "\u040B" },
+ "Ц": { "codepoints": [1062], "characters": "\u0426" },
+ "	": { "codepoints": [9], "characters": "\u0009" },
+ "Τ": { "codepoints": [932], "characters": "\u03A4" },
+ "Ť": { "codepoints": [356], "characters": "\u0164" },
+ "Ţ": { "codepoints": [354], "characters": "\u0162" },
+ "Т": { "codepoints": [1058], "characters": "\u0422" },
+ "𝔗": { "codepoints": [120087], "characters": "\uD835\uDD17" },
+ "∴": { "codepoints": [8756], "characters": "\u2234" },
+ "Θ": { "codepoints": [920], "characters": "\u0398" },
+ "  ": { "codepoints": [8287, 8202], "characters": "\u205F\u200A" },
+ " ": { "codepoints": [8201], "characters": "\u2009" },
+ "∼": { "codepoints": [8764], "characters": "\u223C" },
+ "≃": { "codepoints": [8771], "characters": "\u2243" },
+ "≅": { "codepoints": [8773], "characters": "\u2245" },
+ "≈": { "codepoints": [8776], "characters": "\u2248" },
+ "𝕋": { "codepoints": [120139], "characters": "\uD835\uDD4B" },
+ "⃛": { "codepoints": [8411], "characters": "\u20DB" },
+ "𝒯": { "codepoints": [119983], "characters": "\uD835\uDCAF" },
+ "Ŧ": { "codepoints": [358], "characters": "\u0166" },
+ "Ú": { "codepoints": [218], "characters": "\u00DA" },
+ "Ú": { "codepoints": [218], "characters": "\u00DA" },
+ "↟": { "codepoints": [8607], "characters": "\u219F" },
+ "⥉": { "codepoints": [10569], "characters": "\u2949" },
+ "Ў": { "codepoints": [1038], "characters": "\u040E" },
+ "Ŭ": { "codepoints": [364], "characters": "\u016C" },
+ "Û": { "codepoints": [219], "characters": "\u00DB" },
+ "Û": { "codepoints": [219], "characters": "\u00DB" },
+ "У": { "codepoints": [1059], "characters": "\u0423" },
+ "Ű": { "codepoints": [368], "characters": "\u0170" },
+ "𝔘": { "codepoints": [120088], "characters": "\uD835\uDD18" },
+ "Ù": { "codepoints": [217], "characters": "\u00D9" },
+ "Ù": { "codepoints": [217], "characters": "\u00D9" },
+ "Ū": { "codepoints": [362], "characters": "\u016A" },
+ "_": { "codepoints": [95], "characters": "\u005F" },
+ "⏟": { "codepoints": [9183], "characters": "\u23DF" },
+ "⎵": { "codepoints": [9141], "characters": "\u23B5" },
+ "⏝": { "codepoints": [9181], "characters": "\u23DD" },
+ "⋃": { "codepoints": [8899], "characters": "\u22C3" },
+ "⊎": { "codepoints": [8846], "characters": "\u228E" },
+ "Ų": { "codepoints": [370], "characters": "\u0172" },
+ "𝕌": { "codepoints": [120140], "characters": "\uD835\uDD4C" },
+ "↑": { "codepoints": [8593], "characters": "\u2191" },
+ "⤒": { "codepoints": [10514], "characters": "\u2912" },
+ "⇅": { "codepoints": [8645], "characters": "\u21C5" },
+ "↕": { "codepoints": [8597], "characters": "\u2195" },
+ "⥮": { "codepoints": [10606], "characters": "\u296E" },
+ "⊥": { "codepoints": [8869], "characters": "\u22A5" },
+ "↥": { "codepoints": [8613], "characters": "\u21A5" },
+ "⇑": { "codepoints": [8657], "characters": "\u21D1" },
+ "⇕": { "codepoints": [8661], "characters": "\u21D5" },
+ "↖": { "codepoints": [8598], "characters": "\u2196" },
+ "↗": { "codepoints": [8599], "characters": "\u2197" },
+ "ϒ": { "codepoints": [978], "characters": "\u03D2" },
+ "Υ": { "codepoints": [933], "characters": "\u03A5" },
+ "Ů": { "codepoints": [366], "characters": "\u016E" },
+ "𝒰": { "codepoints": [119984], "characters": "\uD835\uDCB0" },
+ "Ũ": { "codepoints": [360], "characters": "\u0168" },
+ "Ü": { "codepoints": [220], "characters": "\u00DC" },
+ "Ü": { "codepoints": [220], "characters": "\u00DC" },
+ "⊫": { "codepoints": [8875], "characters": "\u22AB" },
+ "⫫": { "codepoints": [10987], "characters": "\u2AEB" },
+ "В": { "codepoints": [1042], "characters": "\u0412" },
+ "⊩": { "codepoints": [8873], "characters": "\u22A9" },
+ "⫦": { "codepoints": [10982], "characters": "\u2AE6" },
+ "⋁": { "codepoints": [8897], "characters": "\u22C1" },
+ "‖": { "codepoints": [8214], "characters": "\u2016" },
+ "‖": { "codepoints": [8214], "characters": "\u2016" },
+ "∣": { "codepoints": [8739], "characters": "\u2223" },
+ "|": { "codepoints": [124], "characters": "\u007C" },
+ "❘": { "codepoints": [10072], "characters": "\u2758" },
+ "≀": { "codepoints": [8768], "characters": "\u2240" },
+ " ": { "codepoints": [8202], "characters": "\u200A" },
+ "𝔙": { "codepoints": [120089], "characters": "\uD835\uDD19" },
+ "𝕍": { "codepoints": [120141], "characters": "\uD835\uDD4D" },
+ "𝒱": { "codepoints": [119985], "characters": "\uD835\uDCB1" },
+ "⊪": { "codepoints": [8874], "characters": "\u22AA" },
+ "Ŵ": { "codepoints": [372], "characters": "\u0174" },
+ "⋀": { "codepoints": [8896], "characters": "\u22C0" },
+ "𝔚": { "codepoints": [120090], "characters": "\uD835\uDD1A" },
+ "𝕎": { "codepoints": [120142], "characters": "\uD835\uDD4E" },
+ "𝒲": { "codepoints": [119986], "characters": "\uD835\uDCB2" },
+ "𝔛": { "codepoints": [120091], "characters": "\uD835\uDD1B" },
+ "Ξ": { "codepoints": [926], "characters": "\u039E" },
+ "𝕏": { "codepoints": [120143], "characters": "\uD835\uDD4F" },
+ "𝒳": { "codepoints": [119987], "characters": "\uD835\uDCB3" },
+ "Я": { "codepoints": [1071], "characters": "\u042F" },
+ "Ї": { "codepoints": [1031], "characters": "\u0407" },
+ "Ю": { "codepoints": [1070], "characters": "\u042E" },
+ "Ý": { "codepoints": [221], "characters": "\u00DD" },
+ "Ý": { "codepoints": [221], "characters": "\u00DD" },
+ "Ŷ": { "codepoints": [374], "characters": "\u0176" },
+ "Ы": { "codepoints": [1067], "characters": "\u042B" },
+ "𝔜": { "codepoints": [120092], "characters": "\uD835\uDD1C" },
+ "𝕐": { "codepoints": [120144], "characters": "\uD835\uDD50" },
+ "𝒴": { "codepoints": [119988], "characters": "\uD835\uDCB4" },
+ "Ÿ": { "codepoints": [376], "characters": "\u0178" },
+ "Ж": { "codepoints": [1046], "characters": "\u0416" },
+ "Ź": { "codepoints": [377], "characters": "\u0179" },
+ "Ž": { "codepoints": [381], "characters": "\u017D" },
+ "З": { "codepoints": [1047], "characters": "\u0417" },
+ "Ż": { "codepoints": [379], "characters": "\u017B" },
+ "​": { "codepoints": [8203], "characters": "\u200B" },
+ "Ζ": { "codepoints": [918], "characters": "\u0396" },
+ "ℨ": { "codepoints": [8488], "characters": "\u2128" },
+ "ℤ": { "codepoints": [8484], "characters": "\u2124" },
+ "𝒵": { "codepoints": [119989], "characters": "\uD835\uDCB5" },
+ "á": { "codepoints": [225], "characters": "\u00E1" },
+ "á": { "codepoints": [225], "characters": "\u00E1" },
+ "ă": { "codepoints": [259], "characters": "\u0103" },
+ "∾": { "codepoints": [8766], "characters": "\u223E" },
+ "∾̳": { "codepoints": [8766, 819], "characters": "\u223E\u0333" },
+ "∿": { "codepoints": [8767], "characters": "\u223F" },
+ "â": { "codepoints": [226], "characters": "\u00E2" },
+ "â": { "codepoints": [226], "characters": "\u00E2" },
+ "´": { "codepoints": [180], "characters": "\u00B4" },
+ "´": { "codepoints": [180], "characters": "\u00B4" },
+ "а": { "codepoints": [1072], "characters": "\u0430" },
+ "æ": { "codepoints": [230], "characters": "\u00E6" },
+ "æ": { "codepoints": [230], "characters": "\u00E6" },
+ "⁡": { "codepoints": [8289], "characters": "\u2061" },
+ "𝔞": { "codepoints": [120094], "characters": "\uD835\uDD1E" },
+ "à": { "codepoints": [224], "characters": "\u00E0" },
+ "à": { "codepoints": [224], "characters": "\u00E0" },
+ "ℵ": { "codepoints": [8501], "characters": "\u2135" },
+ "ℵ": { "codepoints": [8501], "characters": "\u2135" },
+ "α": { "codepoints": [945], "characters": "\u03B1" },
+ "ā": { "codepoints": [257], "characters": "\u0101" },
+ "⨿": { "codepoints": [10815], "characters": "\u2A3F" },
+ "&": { "codepoints": [38], "characters": "\u0026" },
+ "&": { "codepoints": [38], "characters": "\u0026" },
+ "∧": { "codepoints": [8743], "characters": "\u2227" },
+ "⩕": { "codepoints": [10837], "characters": "\u2A55" },
+ "⩜": { "codepoints": [10844], "characters": "\u2A5C" },
+ "⩘": { "codepoints": [10840], "characters": "\u2A58" },
+ "⩚": { "codepoints": [10842], "characters": "\u2A5A" },
+ "∠": { "codepoints": [8736], "characters": "\u2220" },
+ "⦤": { "codepoints": [10660], "characters": "\u29A4" },
+ "∠": { "codepoints": [8736], "characters": "\u2220" },
+ "∡": { "codepoints": [8737], "characters": "\u2221" },
+ "⦨": { "codepoints": [10664], "characters": "\u29A8" },
+ "⦩": { "codepoints": [10665], "characters": "\u29A9" },
+ "⦪": { "codepoints": [10666], "characters": "\u29AA" },
+ "⦫": { "codepoints": [10667], "characters": "\u29AB" },
+ "⦬": { "codepoints": [10668], "characters": "\u29AC" },
+ "⦭": { "codepoints": [10669], "characters": "\u29AD" },
+ "⦮": { "codepoints": [10670], "characters": "\u29AE" },
+ "⦯": { "codepoints": [10671], "characters": "\u29AF" },
+ "∟": { "codepoints": [8735], "characters": "\u221F" },
+ "⊾": { "codepoints": [8894], "characters": "\u22BE" },
+ "⦝": { "codepoints": [10653], "characters": "\u299D" },
+ "∢": { "codepoints": [8738], "characters": "\u2222" },
+ "Å": { "codepoints": [197], "characters": "\u00C5" },
+ "⍼": { "codepoints": [9084], "characters": "\u237C" },
+ "ą": { "codepoints": [261], "characters": "\u0105" },
+ "𝕒": { "codepoints": [120146], "characters": "\uD835\uDD52" },
+ "≈": { "codepoints": [8776], "characters": "\u2248" },
+ "⩰": { "codepoints": [10864], "characters": "\u2A70" },
+ "⩯": { "codepoints": [10863], "characters": "\u2A6F" },
+ "≊": { "codepoints": [8778], "characters": "\u224A" },
+ "≋": { "codepoints": [8779], "characters": "\u224B" },
+ "'": { "codepoints": [39], "characters": "\u0027" },
+ "≈": { "codepoints": [8776], "characters": "\u2248" },
+ "≊": { "codepoints": [8778], "characters": "\u224A" },
+ "å": { "codepoints": [229], "characters": "\u00E5" },
+ "å": { "codepoints": [229], "characters": "\u00E5" },
+ "𝒶": { "codepoints": [119990], "characters": "\uD835\uDCB6" },
+ "*": { "codepoints": [42], "characters": "\u002A" },
+ "≈": { "codepoints": [8776], "characters": "\u2248" },
+ "≍": { "codepoints": [8781], "characters": "\u224D" },
+ "ã": { "codepoints": [227], "characters": "\u00E3" },
+ "ã": { "codepoints": [227], "characters": "\u00E3" },
+ "ä": { "codepoints": [228], "characters": "\u00E4" },
+ "ä": { "codepoints": [228], "characters": "\u00E4" },
+ "∳": { "codepoints": [8755], "characters": "\u2233" },
+ "⨑": { "codepoints": [10769], "characters": "\u2A11" },
+ "⫭": { "codepoints": [10989], "characters": "\u2AED" },
+ "≌": { "codepoints": [8780], "characters": "\u224C" },
+ "϶": { "codepoints": [1014], "characters": "\u03F6" },
+ "‵": { "codepoints": [8245], "characters": "\u2035" },
+ "∽": { "codepoints": [8765], "characters": "\u223D" },
+ "⋍": { "codepoints": [8909], "characters": "\u22CD" },
+ "⊽": { "codepoints": [8893], "characters": "\u22BD" },
+ "⌅": { "codepoints": [8965], "characters": "\u2305" },
+ "⌅": { "codepoints": [8965], "characters": "\u2305" },
+ "⎵": { "codepoints": [9141], "characters": "\u23B5" },
+ "⎶": { "codepoints": [9142], "characters": "\u23B6" },
+ "≌": { "codepoints": [8780], "characters": "\u224C" },
+ "б": { "codepoints": [1073], "characters": "\u0431" },
+ "„": { "codepoints": [8222], "characters": "\u201E" },
+ "∵": { "codepoints": [8757], "characters": "\u2235" },
+ "∵": { "codepoints": [8757], "characters": "\u2235" },
+ "⦰": { "codepoints": [10672], "characters": "\u29B0" },
+ "϶": { "codepoints": [1014], "characters": "\u03F6" },
+ "ℬ": { "codepoints": [8492], "characters": "\u212C" },
+ "β": { "codepoints": [946], "characters": "\u03B2" },
+ "ℶ": { "codepoints": [8502], "characters": "\u2136" },
+ "≬": { "codepoints": [8812], "characters": "\u226C" },
+ "𝔟": { "codepoints": [120095], "characters": "\uD835\uDD1F" },
+ "⋂": { "codepoints": [8898], "characters": "\u22C2" },
+ "◯": { "codepoints": [9711], "characters": "\u25EF" },
+ "⋃": { "codepoints": [8899], "characters": "\u22C3" },
+ "⨀": { "codepoints": [10752], "characters": "\u2A00" },
+ "⨁": { "codepoints": [10753], "characters": "\u2A01" },
+ "⨂": { "codepoints": [10754], "characters": "\u2A02" },
+ "⨆": { "codepoints": [10758], "characters": "\u2A06" },
+ "★": { "codepoints": [9733], "characters": "\u2605" },
+ "▽": { "codepoints": [9661], "characters": "\u25BD" },
+ "△": { "codepoints": [9651], "characters": "\u25B3" },
+ "⨄": { "codepoints": [10756], "characters": "\u2A04" },
+ "⋁": { "codepoints": [8897], "characters": "\u22C1" },
+ "⋀": { "codepoints": [8896], "characters": "\u22C0" },
+ "⤍": { "codepoints": [10509], "characters": "\u290D" },
+ "⧫": { "codepoints": [10731], "characters": "\u29EB" },
+ "▪": { "codepoints": [9642], "characters": "\u25AA" },
+ "▴": { "codepoints": [9652], "characters": "\u25B4" },
+ "▾": { "codepoints": [9662], "characters": "\u25BE" },
+ "◂": { "codepoints": [9666], "characters": "\u25C2" },
+ "▸": { "codepoints": [9656], "characters": "\u25B8" },
+ "␣": { "codepoints": [9251], "characters": "\u2423" },
+ "▒": { "codepoints": [9618], "characters": "\u2592" },
+ "░": { "codepoints": [9617], "characters": "\u2591" },
+ "▓": { "codepoints": [9619], "characters": "\u2593" },
+ "█": { "codepoints": [9608], "characters": "\u2588" },
+ "=⃥": { "codepoints": [61, 8421], "characters": "\u003D\u20E5" },
+ "≡⃥": { "codepoints": [8801, 8421], "characters": "\u2261\u20E5" },
+ "⌐": { "codepoints": [8976], "characters": "\u2310" },
+ "𝕓": { "codepoints": [120147], "characters": "\uD835\uDD53" },
+ "⊥": { "codepoints": [8869], "characters": "\u22A5" },
+ "⊥": { "codepoints": [8869], "characters": "\u22A5" },
+ "⋈": { "codepoints": [8904], "characters": "\u22C8" },
+ "╗": { "codepoints": [9559], "characters": "\u2557" },
+ "╔": { "codepoints": [9556], "characters": "\u2554" },
+ "╖": { "codepoints": [9558], "characters": "\u2556" },
+ "╓": { "codepoints": [9555], "characters": "\u2553" },
+ "═": { "codepoints": [9552], "characters": "\u2550" },
+ "╦": { "codepoints": [9574], "characters": "\u2566" },
+ "╩": { "codepoints": [9577], "characters": "\u2569" },
+ "╤": { "codepoints": [9572], "characters": "\u2564" },
+ "╧": { "codepoints": [9575], "characters": "\u2567" },
+ "╝": { "codepoints": [9565], "characters": "\u255D" },
+ "╚": { "codepoints": [9562], "characters": "\u255A" },
+ "╜": { "codepoints": [9564], "characters": "\u255C" },
+ "╙": { "codepoints": [9561], "characters": "\u2559" },
+ "║": { "codepoints": [9553], "characters": "\u2551" },
+ "╬": { "codepoints": [9580], "characters": "\u256C" },
+ "╣": { "codepoints": [9571], "characters": "\u2563" },
+ "╠": { "codepoints": [9568], "characters": "\u2560" },
+ "╫": { "codepoints": [9579], "characters": "\u256B" },
+ "╢": { "codepoints": [9570], "characters": "\u2562" },
+ "╟": { "codepoints": [9567], "characters": "\u255F" },
+ "⧉": { "codepoints": [10697], "characters": "\u29C9" },
+ "╕": { "codepoints": [9557], "characters": "\u2555" },
+ "╒": { "codepoints": [9554], "characters": "\u2552" },
+ "┐": { "codepoints": [9488], "characters": "\u2510" },
+ "┌": { "codepoints": [9484], "characters": "\u250C" },
+ "─": { "codepoints": [9472], "characters": "\u2500" },
+ "╥": { "codepoints": [9573], "characters": "\u2565" },
+ "╨": { "codepoints": [9576], "characters": "\u2568" },
+ "┬": { "codepoints": [9516], "characters": "\u252C" },
+ "┴": { "codepoints": [9524], "characters": "\u2534" },
+ "⊟": { "codepoints": [8863], "characters": "\u229F" },
+ "⊞": { "codepoints": [8862], "characters": "\u229E" },
+ "⊠": { "codepoints": [8864], "characters": "\u22A0" },
+ "╛": { "codepoints": [9563], "characters": "\u255B" },
+ "╘": { "codepoints": [9560], "characters": "\u2558" },
+ "┘": { "codepoints": [9496], "characters": "\u2518" },
+ "└": { "codepoints": [9492], "characters": "\u2514" },
+ "│": { "codepoints": [9474], "characters": "\u2502" },
+ "╪": { "codepoints": [9578], "characters": "\u256A" },
+ "╡": { "codepoints": [9569], "characters": "\u2561" },
+ "╞": { "codepoints": [9566], "characters": "\u255E" },
+ "┼": { "codepoints": [9532], "characters": "\u253C" },
+ "┤": { "codepoints": [9508], "characters": "\u2524" },
+ "├": { "codepoints": [9500], "characters": "\u251C" },
+ "‵": { "codepoints": [8245], "characters": "\u2035" },
+ "˘": { "codepoints": [728], "characters": "\u02D8" },
+ "¦": { "codepoints": [166], "characters": "\u00A6" },
+ "¦": { "codepoints": [166], "characters": "\u00A6" },
+ "𝒷": { "codepoints": [119991], "characters": "\uD835\uDCB7" },
+ "⁏": { "codepoints": [8271], "characters": "\u204F" },
+ "∽": { "codepoints": [8765], "characters": "\u223D" },
+ "⋍": { "codepoints": [8909], "characters": "\u22CD" },
+ "\": { "codepoints": [92], "characters": "\u005C" },
+ "⧅": { "codepoints": [10693], "characters": "\u29C5" },
+ "⟈": { "codepoints": [10184], "characters": "\u27C8" },
+ "•": { "codepoints": [8226], "characters": "\u2022" },
+ "•": { "codepoints": [8226], "characters": "\u2022" },
+ "≎": { "codepoints": [8782], "characters": "\u224E" },
+ "⪮": { "codepoints": [10926], "characters": "\u2AAE" },
+ "≏": { "codepoints": [8783], "characters": "\u224F" },
+ "≏": { "codepoints": [8783], "characters": "\u224F" },
+ "ć": { "codepoints": [263], "characters": "\u0107" },
+ "∩": { "codepoints": [8745], "characters": "\u2229" },
+ "⩄": { "codepoints": [10820], "characters": "\u2A44" },
+ "⩉": { "codepoints": [10825], "characters": "\u2A49" },
+ "⩋": { "codepoints": [10827], "characters": "\u2A4B" },
+ "⩇": { "codepoints": [10823], "characters": "\u2A47" },
+ "⩀": { "codepoints": [10816], "characters": "\u2A40" },
+ "∩︀": { "codepoints": [8745, 65024], "characters": "\u2229\uFE00" },
+ "⁁": { "codepoints": [8257], "characters": "\u2041" },
+ "ˇ": { "codepoints": [711], "characters": "\u02C7" },
+ "⩍": { "codepoints": [10829], "characters": "\u2A4D" },
+ "č": { "codepoints": [269], "characters": "\u010D" },
+ "ç": { "codepoints": [231], "characters": "\u00E7" },
+ "ç": { "codepoints": [231], "characters": "\u00E7" },
+ "ĉ": { "codepoints": [265], "characters": "\u0109" },
+ "⩌": { "codepoints": [10828], "characters": "\u2A4C" },
+ "⩐": { "codepoints": [10832], "characters": "\u2A50" },
+ "ċ": { "codepoints": [267], "characters": "\u010B" },
+ "¸": { "codepoints": [184], "characters": "\u00B8" },
+ "¸": { "codepoints": [184], "characters": "\u00B8" },
+ "⦲": { "codepoints": [10674], "characters": "\u29B2" },
+ "¢": { "codepoints": [162], "characters": "\u00A2" },
+ "¢": { "codepoints": [162], "characters": "\u00A2" },
+ "·": { "codepoints": [183], "characters": "\u00B7" },
+ "𝔠": { "codepoints": [120096], "characters": "\uD835\uDD20" },
+ "ч": { "codepoints": [1095], "characters": "\u0447" },
+ "✓": { "codepoints": [10003], "characters": "\u2713" },
+ "✓": { "codepoints": [10003], "characters": "\u2713" },
+ "χ": { "codepoints": [967], "characters": "\u03C7" },
+ "○": { "codepoints": [9675], "characters": "\u25CB" },
+ "⧃": { "codepoints": [10691], "characters": "\u29C3" },
+ "ˆ": { "codepoints": [710], "characters": "\u02C6" },
+ "≗": { "codepoints": [8791], "characters": "\u2257" },
+ "↺": { "codepoints": [8634], "characters": "\u21BA" },
+ "↻": { "codepoints": [8635], "characters": "\u21BB" },
+ "®": { "codepoints": [174], "characters": "\u00AE" },
+ "Ⓢ": { "codepoints": [9416], "characters": "\u24C8" },
+ "⊛": { "codepoints": [8859], "characters": "\u229B" },
+ "⊚": { "codepoints": [8858], "characters": "\u229A" },
+ "⊝": { "codepoints": [8861], "characters": "\u229D" },
+ "≗": { "codepoints": [8791], "characters": "\u2257" },
+ "⨐": { "codepoints": [10768], "characters": "\u2A10" },
+ "⫯": { "codepoints": [10991], "characters": "\u2AEF" },
+ "⧂": { "codepoints": [10690], "characters": "\u29C2" },
+ "♣": { "codepoints": [9827], "characters": "\u2663" },
+ "♣": { "codepoints": [9827], "characters": "\u2663" },
+ ":": { "codepoints": [58], "characters": "\u003A" },
+ "≔": { "codepoints": [8788], "characters": "\u2254" },
+ "≔": { "codepoints": [8788], "characters": "\u2254" },
+ ",": { "codepoints": [44], "characters": "\u002C" },
+ "@": { "codepoints": [64], "characters": "\u0040" },
+ "∁": { "codepoints": [8705], "characters": "\u2201" },
+ "∘": { "codepoints": [8728], "characters": "\u2218" },
+ "∁": { "codepoints": [8705], "characters": "\u2201" },
+ "ℂ": { "codepoints": [8450], "characters": "\u2102" },
+ "≅": { "codepoints": [8773], "characters": "\u2245" },
+ "⩭": { "codepoints": [10861], "characters": "\u2A6D" },
+ "∮": { "codepoints": [8750], "characters": "\u222E" },
+ "𝕔": { "codepoints": [120148], "characters": "\uD835\uDD54" },
+ "∐": { "codepoints": [8720], "characters": "\u2210" },
+ "©": { "codepoints": [169], "characters": "\u00A9" },
+ "©": { "codepoints": [169], "characters": "\u00A9" },
+ "℗": { "codepoints": [8471], "characters": "\u2117" },
+ "↵": { "codepoints": [8629], "characters": "\u21B5" },
+ "✗": { "codepoints": [10007], "characters": "\u2717" },
+ "𝒸": { "codepoints": [119992], "characters": "\uD835\uDCB8" },
+ "⫏": { "codepoints": [10959], "characters": "\u2ACF" },
+ "⫑": { "codepoints": [10961], "characters": "\u2AD1" },
+ "⫐": { "codepoints": [10960], "characters": "\u2AD0" },
+ "⫒": { "codepoints": [10962], "characters": "\u2AD2" },
+ "⋯": { "codepoints": [8943], "characters": "\u22EF" },
+ "⤸": { "codepoints": [10552], "characters": "\u2938" },
+ "⤵": { "codepoints": [10549], "characters": "\u2935" },
+ "⋞": { "codepoints": [8926], "characters": "\u22DE" },
+ "⋟": { "codepoints": [8927], "characters": "\u22DF" },
+ "↶": { "codepoints": [8630], "characters": "\u21B6" },
+ "⤽": { "codepoints": [10557], "characters": "\u293D" },
+ "∪": { "codepoints": [8746], "characters": "\u222A" },
+ "⩈": { "codepoints": [10824], "characters": "\u2A48" },
+ "⩆": { "codepoints": [10822], "characters": "\u2A46" },
+ "⩊": { "codepoints": [10826], "characters": "\u2A4A" },
+ "⊍": { "codepoints": [8845], "characters": "\u228D" },
+ "⩅": { "codepoints": [10821], "characters": "\u2A45" },
+ "∪︀": { "codepoints": [8746, 65024], "characters": "\u222A\uFE00" },
+ "↷": { "codepoints": [8631], "characters": "\u21B7" },
+ "⤼": { "codepoints": [10556], "characters": "\u293C" },
+ "⋞": { "codepoints": [8926], "characters": "\u22DE" },
+ "⋟": { "codepoints": [8927], "characters": "\u22DF" },
+ "⋎": { "codepoints": [8910], "characters": "\u22CE" },
+ "⋏": { "codepoints": [8911], "characters": "\u22CF" },
+ "¤": { "codepoints": [164], "characters": "\u00A4" },
+ "¤": { "codepoints": [164], "characters": "\u00A4" },
+ "↶": { "codepoints": [8630], "characters": "\u21B6" },
+ "↷": { "codepoints": [8631], "characters": "\u21B7" },
+ "⋎": { "codepoints": [8910], "characters": "\u22CE" },
+ "⋏": { "codepoints": [8911], "characters": "\u22CF" },
+ "∲": { "codepoints": [8754], "characters": "\u2232" },
+ "∱": { "codepoints": [8753], "characters": "\u2231" },
+ "⌭": { "codepoints": [9005], "characters": "\u232D" },
+ "⇓": { "codepoints": [8659], "characters": "\u21D3" },
+ "⥥": { "codepoints": [10597], "characters": "\u2965" },
+ "†": { "codepoints": [8224], "characters": "\u2020" },
+ "ℸ": { "codepoints": [8504], "characters": "\u2138" },
+ "↓": { "codepoints": [8595], "characters": "\u2193" },
+ "‐": { "codepoints": [8208], "characters": "\u2010" },
+ "⊣": { "codepoints": [8867], "characters": "\u22A3" },
+ "⤏": { "codepoints": [10511], "characters": "\u290F" },
+ "˝": { "codepoints": [733], "characters": "\u02DD" },
+ "ď": { "codepoints": [271], "characters": "\u010F" },
+ "д": { "codepoints": [1076], "characters": "\u0434" },
+ "ⅆ": { "codepoints": [8518], "characters": "\u2146" },
+ "‡": { "codepoints": [8225], "characters": "\u2021" },
+ "⇊": { "codepoints": [8650], "characters": "\u21CA" },
+ "⩷": { "codepoints": [10871], "characters": "\u2A77" },
+ "°": { "codepoints": [176], "characters": "\u00B0" },
+ "°": { "codepoints": [176], "characters": "\u00B0" },
+ "δ": { "codepoints": [948], "characters": "\u03B4" },
+ "⦱": { "codepoints": [10673], "characters": "\u29B1" },
+ "⥿": { "codepoints": [10623], "characters": "\u297F" },
+ "𝔡": { "codepoints": [120097], "characters": "\uD835\uDD21" },
+ "⇃": { "codepoints": [8643], "characters": "\u21C3" },
+ "⇂": { "codepoints": [8642], "characters": "\u21C2" },
+ "⋄": { "codepoints": [8900], "characters": "\u22C4" },
+ "⋄": { "codepoints": [8900], "characters": "\u22C4" },
+ "♦": { "codepoints": [9830], "characters": "\u2666" },
+ "♦": { "codepoints": [9830], "characters": "\u2666" },
+ "¨": { "codepoints": [168], "characters": "\u00A8" },
+ "ϝ": { "codepoints": [989], "characters": "\u03DD" },
+ "⋲": { "codepoints": [8946], "characters": "\u22F2" },
+ "÷": { "codepoints": [247], "characters": "\u00F7" },
+ "÷": { "codepoints": [247], "characters": "\u00F7" },
+ "÷": { "codepoints": [247], "characters": "\u00F7" },
+ "⋇": { "codepoints": [8903], "characters": "\u22C7" },
+ "⋇": { "codepoints": [8903], "characters": "\u22C7" },
+ "ђ": { "codepoints": [1106], "characters": "\u0452" },
+ "⌞": { "codepoints": [8990], "characters": "\u231E" },
+ "⌍": { "codepoints": [8973], "characters": "\u230D" },
+ "$": { "codepoints": [36], "characters": "\u0024" },
+ "𝕕": { "codepoints": [120149], "characters": "\uD835\uDD55" },
+ "˙": { "codepoints": [729], "characters": "\u02D9" },
+ "≐": { "codepoints": [8784], "characters": "\u2250" },
+ "≑": { "codepoints": [8785], "characters": "\u2251" },
+ "∸": { "codepoints": [8760], "characters": "\u2238" },
+ "∔": { "codepoints": [8724], "characters": "\u2214" },
+ "⊡": { "codepoints": [8865], "characters": "\u22A1" },
+ "⌆": { "codepoints": [8966], "characters": "\u2306" },
+ "↓": { "codepoints": [8595], "characters": "\u2193" },
+ "⇊": { "codepoints": [8650], "characters": "\u21CA" },
+ "⇃": { "codepoints": [8643], "characters": "\u21C3" },
+ "⇂": { "codepoints": [8642], "characters": "\u21C2" },
+ "⤐": { "codepoints": [10512], "characters": "\u2910" },
+ "⌟": { "codepoints": [8991], "characters": "\u231F" },
+ "⌌": { "codepoints": [8972], "characters": "\u230C" },
+ "𝒹": { "codepoints": [119993], "characters": "\uD835\uDCB9" },
+ "ѕ": { "codepoints": [1109], "characters": "\u0455" },
+ "⧶": { "codepoints": [10742], "characters": "\u29F6" },
+ "đ": { "codepoints": [273], "characters": "\u0111" },
+ "⋱": { "codepoints": [8945], "characters": "\u22F1" },
+ "▿": { "codepoints": [9663], "characters": "\u25BF" },
+ "▾": { "codepoints": [9662], "characters": "\u25BE" },
+ "⇵": { "codepoints": [8693], "characters": "\u21F5" },
+ "⥯": { "codepoints": [10607], "characters": "\u296F" },
+ "⦦": { "codepoints": [10662], "characters": "\u29A6" },
+ "џ": { "codepoints": [1119], "characters": "\u045F" },
+ "⟿": { "codepoints": [10239], "characters": "\u27FF" },
+ "⩷": { "codepoints": [10871], "characters": "\u2A77" },
+ "≑": { "codepoints": [8785], "characters": "\u2251" },
+ "é": { "codepoints": [233], "characters": "\u00E9" },
+ "é": { "codepoints": [233], "characters": "\u00E9" },
+ "⩮": { "codepoints": [10862], "characters": "\u2A6E" },
+ "ě": { "codepoints": [283], "characters": "\u011B" },
+ "≖": { "codepoints": [8790], "characters": "\u2256" },
+ "ê": { "codepoints": [234], "characters": "\u00EA" },
+ "ê": { "codepoints": [234], "characters": "\u00EA" },
+ "≕": { "codepoints": [8789], "characters": "\u2255" },
+ "э": { "codepoints": [1101], "characters": "\u044D" },
+ "ė": { "codepoints": [279], "characters": "\u0117" },
+ "ⅇ": { "codepoints": [8519], "characters": "\u2147" },
+ "≒": { "codepoints": [8786], "characters": "\u2252" },
+ "𝔢": { "codepoints": [120098], "characters": "\uD835\uDD22" },
+ "⪚": { "codepoints": [10906], "characters": "\u2A9A" },
+ "è": { "codepoints": [232], "characters": "\u00E8" },
+ "è": { "codepoints": [232], "characters": "\u00E8" },
+ "⪖": { "codepoints": [10902], "characters": "\u2A96" },
+ "⪘": { "codepoints": [10904], "characters": "\u2A98" },
+ "⪙": { "codepoints": [10905], "characters": "\u2A99" },
+ "⏧": { "codepoints": [9191], "characters": "\u23E7" },
+ "ℓ": { "codepoints": [8467], "characters": "\u2113" },
+ "⪕": { "codepoints": [10901], "characters": "\u2A95" },
+ "⪗": { "codepoints": [10903], "characters": "\u2A97" },
+ "ē": { "codepoints": [275], "characters": "\u0113" },
+ "∅": { "codepoints": [8709], "characters": "\u2205" },
+ "∅": { "codepoints": [8709], "characters": "\u2205" },
+ "∅": { "codepoints": [8709], "characters": "\u2205" },
+ " ": { "codepoints": [8196], "characters": "\u2004" },
+ " ": { "codepoints": [8197], "characters": "\u2005" },
+ " ": { "codepoints": [8195], "characters": "\u2003" },
+ "ŋ": { "codepoints": [331], "characters": "\u014B" },
+ " ": { "codepoints": [8194], "characters": "\u2002" },
+ "ę": { "codepoints": [281], "characters": "\u0119" },
+ "𝕖": { "codepoints": [120150], "characters": "\uD835\uDD56" },
+ "⋕": { "codepoints": [8917], "characters": "\u22D5" },
+ "⧣": { "codepoints": [10723], "characters": "\u29E3" },
+ "⩱": { "codepoints": [10865], "characters": "\u2A71" },
+ "ε": { "codepoints": [949], "characters": "\u03B5" },
+ "ε": { "codepoints": [949], "characters": "\u03B5" },
+ "ϵ": { "codepoints": [1013], "characters": "\u03F5" },
+ "≖": { "codepoints": [8790], "characters": "\u2256" },
+ "≕": { "codepoints": [8789], "characters": "\u2255" },
+ "≂": { "codepoints": [8770], "characters": "\u2242" },
+ "⪖": { "codepoints": [10902], "characters": "\u2A96" },
+ "⪕": { "codepoints": [10901], "characters": "\u2A95" },
+ "=": { "codepoints": [61], "characters": "\u003D" },
+ "≟": { "codepoints": [8799], "characters": "\u225F" },
+ "≡": { "codepoints": [8801], "characters": "\u2261" },
+ "⩸": { "codepoints": [10872], "characters": "\u2A78" },
+ "⧥": { "codepoints": [10725], "characters": "\u29E5" },
+ "≓": { "codepoints": [8787], "characters": "\u2253" },
+ "⥱": { "codepoints": [10609], "characters": "\u2971" },
+ "ℯ": { "codepoints": [8495], "characters": "\u212F" },
+ "≐": { "codepoints": [8784], "characters": "\u2250" },
+ "≂": { "codepoints": [8770], "characters": "\u2242" },
+ "η": { "codepoints": [951], "characters": "\u03B7" },
+ "ð": { "codepoints": [240], "characters": "\u00F0" },
+ "ð": { "codepoints": [240], "characters": "\u00F0" },
+ "ë": { "codepoints": [235], "characters": "\u00EB" },
+ "ë": { "codepoints": [235], "characters": "\u00EB" },
+ "€": { "codepoints": [8364], "characters": "\u20AC" },
+ "!": { "codepoints": [33], "characters": "\u0021" },
+ "∃": { "codepoints": [8707], "characters": "\u2203" },
+ "ℰ": { "codepoints": [8496], "characters": "\u2130" },
+ "ⅇ": { "codepoints": [8519], "characters": "\u2147" },
+ "≒": { "codepoints": [8786], "characters": "\u2252" },
+ "ф": { "codepoints": [1092], "characters": "\u0444" },
+ "♀": { "codepoints": [9792], "characters": "\u2640" },
+ "ffi": { "codepoints": [64259], "characters": "\uFB03" },
+ "ff": { "codepoints": [64256], "characters": "\uFB00" },
+ "ffl": { "codepoints": [64260], "characters": "\uFB04" },
+ "𝔣": { "codepoints": [120099], "characters": "\uD835\uDD23" },
+ "fi": { "codepoints": [64257], "characters": "\uFB01" },
+ "fj": { "codepoints": [102, 106], "characters": "\u0066\u006A" },
+ "♭": { "codepoints": [9837], "characters": "\u266D" },
+ "fl": { "codepoints": [64258], "characters": "\uFB02" },
+ "▱": { "codepoints": [9649], "characters": "\u25B1" },
+ "ƒ": { "codepoints": [402], "characters": "\u0192" },
+ "𝕗": { "codepoints": [120151], "characters": "\uD835\uDD57" },
+ "∀": { "codepoints": [8704], "characters": "\u2200" },
+ "⋔": { "codepoints": [8916], "characters": "\u22D4" },
+ "⫙": { "codepoints": [10969], "characters": "\u2AD9" },
+ "⨍": { "codepoints": [10765], "characters": "\u2A0D" },
+ "½": { "codepoints": [189], "characters": "\u00BD" },
+ "½": { "codepoints": [189], "characters": "\u00BD" },
+ "⅓": { "codepoints": [8531], "characters": "\u2153" },
+ "¼": { "codepoints": [188], "characters": "\u00BC" },
+ "¼": { "codepoints": [188], "characters": "\u00BC" },
+ "⅕": { "codepoints": [8533], "characters": "\u2155" },
+ "⅙": { "codepoints": [8537], "characters": "\u2159" },
+ "⅛": { "codepoints": [8539], "characters": "\u215B" },
+ "⅔": { "codepoints": [8532], "characters": "\u2154" },
+ "⅖": { "codepoints": [8534], "characters": "\u2156" },
+ "¾": { "codepoints": [190], "characters": "\u00BE" },
+ "¾": { "codepoints": [190], "characters": "\u00BE" },
+ "⅗": { "codepoints": [8535], "characters": "\u2157" },
+ "⅜": { "codepoints": [8540], "characters": "\u215C" },
+ "⅘": { "codepoints": [8536], "characters": "\u2158" },
+ "⅚": { "codepoints": [8538], "characters": "\u215A" },
+ "⅝": { "codepoints": [8541], "characters": "\u215D" },
+ "⅞": { "codepoints": [8542], "characters": "\u215E" },
+ "⁄": { "codepoints": [8260], "characters": "\u2044" },
+ "⌢": { "codepoints": [8994], "characters": "\u2322" },
+ "𝒻": { "codepoints": [119995], "characters": "\uD835\uDCBB" },
+ "≧": { "codepoints": [8807], "characters": "\u2267" },
+ "⪌": { "codepoints": [10892], "characters": "\u2A8C" },
+ "ǵ": { "codepoints": [501], "characters": "\u01F5" },
+ "γ": { "codepoints": [947], "characters": "\u03B3" },
+ "ϝ": { "codepoints": [989], "characters": "\u03DD" },
+ "⪆": { "codepoints": [10886], "characters": "\u2A86" },
+ "ğ": { "codepoints": [287], "characters": "\u011F" },
+ "ĝ": { "codepoints": [285], "characters": "\u011D" },
+ "г": { "codepoints": [1075], "characters": "\u0433" },
+ "ġ": { "codepoints": [289], "characters": "\u0121" },
+ "≥": { "codepoints": [8805], "characters": "\u2265" },
+ "⋛": { "codepoints": [8923], "characters": "\u22DB" },
+ "≥": { "codepoints": [8805], "characters": "\u2265" },
+ "≧": { "codepoints": [8807], "characters": "\u2267" },
+ "⩾": { "codepoints": [10878], "characters": "\u2A7E" },
+ "⩾": { "codepoints": [10878], "characters": "\u2A7E" },
+ "⪩": { "codepoints": [10921], "characters": "\u2AA9" },
+ "⪀": { "codepoints": [10880], "characters": "\u2A80" },
+ "⪂": { "codepoints": [10882], "characters": "\u2A82" },
+ "⪄": { "codepoints": [10884], "characters": "\u2A84" },
+ "⋛︀": { "codepoints": [8923, 65024], "characters": "\u22DB\uFE00" },
+ "⪔": { "codepoints": [10900], "characters": "\u2A94" },
+ "𝔤": { "codepoints": [120100], "characters": "\uD835\uDD24" },
+ "≫": { "codepoints": [8811], "characters": "\u226B" },
+ "⋙": { "codepoints": [8921], "characters": "\u22D9" },
+ "ℷ": { "codepoints": [8503], "characters": "\u2137" },
+ "ѓ": { "codepoints": [1107], "characters": "\u0453" },
+ "≷": { "codepoints": [8823], "characters": "\u2277" },
+ "⪒": { "codepoints": [10898], "characters": "\u2A92" },
+ "⪥": { "codepoints": [10917], "characters": "\u2AA5" },
+ "⪤": { "codepoints": [10916], "characters": "\u2AA4" },
+ "≩": { "codepoints": [8809], "characters": "\u2269" },
+ "⪊": { "codepoints": [10890], "characters": "\u2A8A" },
+ "⪊": { "codepoints": [10890], "characters": "\u2A8A" },
+ "⪈": { "codepoints": [10888], "characters": "\u2A88" },
+ "⪈": { "codepoints": [10888], "characters": "\u2A88" },
+ "≩": { "codepoints": [8809], "characters": "\u2269" },
+ "⋧": { "codepoints": [8935], "characters": "\u22E7" },
+ "𝕘": { "codepoints": [120152], "characters": "\uD835\uDD58" },
+ "`": { "codepoints": [96], "characters": "\u0060" },
+ "ℊ": { "codepoints": [8458], "characters": "\u210A" },
+ "≳": { "codepoints": [8819], "characters": "\u2273" },
+ "⪎": { "codepoints": [10894], "characters": "\u2A8E" },
+ "⪐": { "codepoints": [10896], "characters": "\u2A90" },
+ ">": { "codepoints": [62], "characters": "\u003E" },
+ ">": { "codepoints": [62], "characters": "\u003E" },
+ "⪧": { "codepoints": [10919], "characters": "\u2AA7" },
+ "⩺": { "codepoints": [10874], "characters": "\u2A7A" },
+ "⋗": { "codepoints": [8919], "characters": "\u22D7" },
+ "⦕": { "codepoints": [10645], "characters": "\u2995" },
+ "⩼": { "codepoints": [10876], "characters": "\u2A7C" },
+ "⪆": { "codepoints": [10886], "characters": "\u2A86" },
+ "⥸": { "codepoints": [10616], "characters": "\u2978" },
+ "⋗": { "codepoints": [8919], "characters": "\u22D7" },
+ "⋛": { "codepoints": [8923], "characters": "\u22DB" },
+ "⪌": { "codepoints": [10892], "characters": "\u2A8C" },
+ "≷": { "codepoints": [8823], "characters": "\u2277" },
+ "≳": { "codepoints": [8819], "characters": "\u2273" },
+ "≩︀": { "codepoints": [8809, 65024], "characters": "\u2269\uFE00" },
+ "≩︀": { "codepoints": [8809, 65024], "characters": "\u2269\uFE00" },
+ "⇔": { "codepoints": [8660], "characters": "\u21D4" },
+ " ": { "codepoints": [8202], "characters": "\u200A" },
+ "½": { "codepoints": [189], "characters": "\u00BD" },
+ "ℋ": { "codepoints": [8459], "characters": "\u210B" },
+ "ъ": { "codepoints": [1098], "characters": "\u044A" },
+ "↔": { "codepoints": [8596], "characters": "\u2194" },
+ "⥈": { "codepoints": [10568], "characters": "\u2948" },
+ "↭": { "codepoints": [8621], "characters": "\u21AD" },
+ "ℏ": { "codepoints": [8463], "characters": "\u210F" },
+ "ĥ": { "codepoints": [293], "characters": "\u0125" },
+ "♥": { "codepoints": [9829], "characters": "\u2665" },
+ "♥": { "codepoints": [9829], "characters": "\u2665" },
+ "…": { "codepoints": [8230], "characters": "\u2026" },
+ "⊹": { "codepoints": [8889], "characters": "\u22B9" },
+ "𝔥": { "codepoints": [120101], "characters": "\uD835\uDD25" },
+ "⤥": { "codepoints": [10533], "characters": "\u2925" },
+ "⤦": { "codepoints": [10534], "characters": "\u2926" },
+ "⇿": { "codepoints": [8703], "characters": "\u21FF" },
+ "∻": { "codepoints": [8763], "characters": "\u223B" },
+ "↩": { "codepoints": [8617], "characters": "\u21A9" },
+ "↪": { "codepoints": [8618], "characters": "\u21AA" },
+ "𝕙": { "codepoints": [120153], "characters": "\uD835\uDD59" },
+ "―": { "codepoints": [8213], "characters": "\u2015" },
+ "𝒽": { "codepoints": [119997], "characters": "\uD835\uDCBD" },
+ "ℏ": { "codepoints": [8463], "characters": "\u210F" },
+ "ħ": { "codepoints": [295], "characters": "\u0127" },
+ "⁃": { "codepoints": [8259], "characters": "\u2043" },
+ "‐": { "codepoints": [8208], "characters": "\u2010" },
+ "í": { "codepoints": [237], "characters": "\u00ED" },
+ "í": { "codepoints": [237], "characters": "\u00ED" },
+ "⁣": { "codepoints": [8291], "characters": "\u2063" },
+ "î": { "codepoints": [238], "characters": "\u00EE" },
+ "î": { "codepoints": [238], "characters": "\u00EE" },
+ "и": { "codepoints": [1080], "characters": "\u0438" },
+ "е": { "codepoints": [1077], "characters": "\u0435" },
+ "¡": { "codepoints": [161], "characters": "\u00A1" },
+ "¡": { "codepoints": [161], "characters": "\u00A1" },
+ "⇔": { "codepoints": [8660], "characters": "\u21D4" },
+ "𝔦": { "codepoints": [120102], "characters": "\uD835\uDD26" },
+ "ì": { "codepoints": [236], "characters": "\u00EC" },
+ "ì": { "codepoints": [236], "characters": "\u00EC" },
+ "ⅈ": { "codepoints": [8520], "characters": "\u2148" },
+ "⨌": { "codepoints": [10764], "characters": "\u2A0C" },
+ "∭": { "codepoints": [8749], "characters": "\u222D" },
+ "⧜": { "codepoints": [10716], "characters": "\u29DC" },
+ "℩": { "codepoints": [8489], "characters": "\u2129" },
+ "ij": { "codepoints": [307], "characters": "\u0133" },
+ "ī": { "codepoints": [299], "characters": "\u012B" },
+ "ℑ": { "codepoints": [8465], "characters": "\u2111" },
+ "ℐ": { "codepoints": [8464], "characters": "\u2110" },
+ "ℑ": { "codepoints": [8465], "characters": "\u2111" },
+ "ı": { "codepoints": [305], "characters": "\u0131" },
+ "⊷": { "codepoints": [8887], "characters": "\u22B7" },
+ "Ƶ": { "codepoints": [437], "characters": "\u01B5" },
+ "∈": { "codepoints": [8712], "characters": "\u2208" },
+ "℅": { "codepoints": [8453], "characters": "\u2105" },
+ "∞": { "codepoints": [8734], "characters": "\u221E" },
+ "⧝": { "codepoints": [10717], "characters": "\u29DD" },
+ "ı": { "codepoints": [305], "characters": "\u0131" },
+ "∫": { "codepoints": [8747], "characters": "\u222B" },
+ "⊺": { "codepoints": [8890], "characters": "\u22BA" },
+ "ℤ": { "codepoints": [8484], "characters": "\u2124" },
+ "⊺": { "codepoints": [8890], "characters": "\u22BA" },
+ "⨗": { "codepoints": [10775], "characters": "\u2A17" },
+ "⨼": { "codepoints": [10812], "characters": "\u2A3C" },
+ "ё": { "codepoints": [1105], "characters": "\u0451" },
+ "į": { "codepoints": [303], "characters": "\u012F" },
+ "𝕚": { "codepoints": [120154], "characters": "\uD835\uDD5A" },
+ "ι": { "codepoints": [953], "characters": "\u03B9" },
+ "⨼": { "codepoints": [10812], "characters": "\u2A3C" },
+ "¿": { "codepoints": [191], "characters": "\u00BF" },
+ "¿": { "codepoints": [191], "characters": "\u00BF" },
+ "𝒾": { "codepoints": [119998], "characters": "\uD835\uDCBE" },
+ "∈": { "codepoints": [8712], "characters": "\u2208" },
+ "⋹": { "codepoints": [8953], "characters": "\u22F9" },
+ "⋵": { "codepoints": [8949], "characters": "\u22F5" },
+ "⋴": { "codepoints": [8948], "characters": "\u22F4" },
+ "⋳": { "codepoints": [8947], "characters": "\u22F3" },
+ "∈": { "codepoints": [8712], "characters": "\u2208" },
+ "⁢": { "codepoints": [8290], "characters": "\u2062" },
+ "ĩ": { "codepoints": [297], "characters": "\u0129" },
+ "і": { "codepoints": [1110], "characters": "\u0456" },
+ "ï": { "codepoints": [239], "characters": "\u00EF" },
+ "ï": { "codepoints": [239], "characters": "\u00EF" },
+ "ĵ": { "codepoints": [309], "characters": "\u0135" },
+ "й": { "codepoints": [1081], "characters": "\u0439" },
+ "𝔧": { "codepoints": [120103], "characters": "\uD835\uDD27" },
+ "ȷ": { "codepoints": [567], "characters": "\u0237" },
+ "𝕛": { "codepoints": [120155], "characters": "\uD835\uDD5B" },
+ "𝒿": { "codepoints": [119999], "characters": "\uD835\uDCBF" },
+ "ј": { "codepoints": [1112], "characters": "\u0458" },
+ "є": { "codepoints": [1108], "characters": "\u0454" },
+ "κ": { "codepoints": [954], "characters": "\u03BA" },
+ "ϰ": { "codepoints": [1008], "characters": "\u03F0" },
+ "ķ": { "codepoints": [311], "characters": "\u0137" },
+ "к": { "codepoints": [1082], "characters": "\u043A" },
+ "𝔨": { "codepoints": [120104], "characters": "\uD835\uDD28" },
+ "ĸ": { "codepoints": [312], "characters": "\u0138" },
+ "х": { "codepoints": [1093], "characters": "\u0445" },
+ "ќ": { "codepoints": [1116], "characters": "\u045C" },
+ "𝕜": { "codepoints": [120156], "characters": "\uD835\uDD5C" },
+ "𝓀": { "codepoints": [120000], "characters": "\uD835\uDCC0" },
+ "⇚": { "codepoints": [8666], "characters": "\u21DA" },
+ "⇐": { "codepoints": [8656], "characters": "\u21D0" },
+ "⤛": { "codepoints": [10523], "characters": "\u291B" },
+ "⤎": { "codepoints": [10510], "characters": "\u290E" },
+ "≦": { "codepoints": [8806], "characters": "\u2266" },
+ "⪋": { "codepoints": [10891], "characters": "\u2A8B" },
+ "⥢": { "codepoints": [10594], "characters": "\u2962" },
+ "ĺ": { "codepoints": [314], "characters": "\u013A" },
+ "⦴": { "codepoints": [10676], "characters": "\u29B4" },
+ "ℒ": { "codepoints": [8466], "characters": "\u2112" },
+ "λ": { "codepoints": [955], "characters": "\u03BB" },
+ "⟨": { "codepoints": [10216], "characters": "\u27E8" },
+ "⦑": { "codepoints": [10641], "characters": "\u2991" },
+ "⟨": { "codepoints": [10216], "characters": "\u27E8" },
+ "⪅": { "codepoints": [10885], "characters": "\u2A85" },
+ "«": { "codepoints": [171], "characters": "\u00AB" },
+ "«": { "codepoints": [171], "characters": "\u00AB" },
+ "←": { "codepoints": [8592], "characters": "\u2190" },
+ "⇤": { "codepoints": [8676], "characters": "\u21E4" },
+ "⤟": { "codepoints": [10527], "characters": "\u291F" },
+ "⤝": { "codepoints": [10525], "characters": "\u291D" },
+ "↩": { "codepoints": [8617], "characters": "\u21A9" },
+ "↫": { "codepoints": [8619], "characters": "\u21AB" },
+ "⤹": { "codepoints": [10553], "characters": "\u2939" },
+ "⥳": { "codepoints": [10611], "characters": "\u2973" },
+ "↢": { "codepoints": [8610], "characters": "\u21A2" },
+ "⪫": { "codepoints": [10923], "characters": "\u2AAB" },
+ "⤙": { "codepoints": [10521], "characters": "\u2919" },
+ "⪭": { "codepoints": [10925], "characters": "\u2AAD" },
+ "⪭︀": { "codepoints": [10925, 65024], "characters": "\u2AAD\uFE00" },
+ "⤌": { "codepoints": [10508], "characters": "\u290C" },
+ "❲": { "codepoints": [10098], "characters": "\u2772" },
+ "{": { "codepoints": [123], "characters": "\u007B" },
+ "[": { "codepoints": [91], "characters": "\u005B" },
+ "⦋": { "codepoints": [10635], "characters": "\u298B" },
+ "⦏": { "codepoints": [10639], "characters": "\u298F" },
+ "⦍": { "codepoints": [10637], "characters": "\u298D" },
+ "ľ": { "codepoints": [318], "characters": "\u013E" },
+ "ļ": { "codepoints": [316], "characters": "\u013C" },
+ "⌈": { "codepoints": [8968], "characters": "\u2308" },
+ "{": { "codepoints": [123], "characters": "\u007B" },
+ "л": { "codepoints": [1083], "characters": "\u043B" },
+ "⤶": { "codepoints": [10550], "characters": "\u2936" },
+ "“": { "codepoints": [8220], "characters": "\u201C" },
+ "„": { "codepoints": [8222], "characters": "\u201E" },
+ "⥧": { "codepoints": [10599], "characters": "\u2967" },
+ "⥋": { "codepoints": [10571], "characters": "\u294B" },
+ "↲": { "codepoints": [8626], "characters": "\u21B2" },
+ "≤": { "codepoints": [8804], "characters": "\u2264" },
+ "←": { "codepoints": [8592], "characters": "\u2190" },
+ "↢": { "codepoints": [8610], "characters": "\u21A2" },
+ "↽": { "codepoints": [8637], "characters": "\u21BD" },
+ "↼": { "codepoints": [8636], "characters": "\u21BC" },
+ "⇇": { "codepoints": [8647], "characters": "\u21C7" },
+ "↔": { "codepoints": [8596], "characters": "\u2194" },
+ "⇆": { "codepoints": [8646], "characters": "\u21C6" },
+ "⇋": { "codepoints": [8651], "characters": "\u21CB" },
+ "↭": { "codepoints": [8621], "characters": "\u21AD" },
+ "⋋": { "codepoints": [8907], "characters": "\u22CB" },
+ "⋚": { "codepoints": [8922], "characters": "\u22DA" },
+ "≤": { "codepoints": [8804], "characters": "\u2264" },
+ "≦": { "codepoints": [8806], "characters": "\u2266" },
+ "⩽": { "codepoints": [10877], "characters": "\u2A7D" },
+ "⩽": { "codepoints": [10877], "characters": "\u2A7D" },
+ "⪨": { "codepoints": [10920], "characters": "\u2AA8" },
+ "⩿": { "codepoints": [10879], "characters": "\u2A7F" },
+ "⪁": { "codepoints": [10881], "characters": "\u2A81" },
+ "⪃": { "codepoints": [10883], "characters": "\u2A83" },
+ "⋚︀": { "codepoints": [8922, 65024], "characters": "\u22DA\uFE00" },
+ "⪓": { "codepoints": [10899], "characters": "\u2A93" },
+ "⪅": { "codepoints": [10885], "characters": "\u2A85" },
+ "⋖": { "codepoints": [8918], "characters": "\u22D6" },
+ "⋚": { "codepoints": [8922], "characters": "\u22DA" },
+ "⪋": { "codepoints": [10891], "characters": "\u2A8B" },
+ "≶": { "codepoints": [8822], "characters": "\u2276" },
+ "≲": { "codepoints": [8818], "characters": "\u2272" },
+ "⥼": { "codepoints": [10620], "characters": "\u297C" },
+ "⌊": { "codepoints": [8970], "characters": "\u230A" },
+ "𝔩": { "codepoints": [120105], "characters": "\uD835\uDD29" },
+ "≶": { "codepoints": [8822], "characters": "\u2276" },
+ "⪑": { "codepoints": [10897], "characters": "\u2A91" },
+ "↽": { "codepoints": [8637], "characters": "\u21BD" },
+ "↼": { "codepoints": [8636], "characters": "\u21BC" },
+ "⥪": { "codepoints": [10602], "characters": "\u296A" },
+ "▄": { "codepoints": [9604], "characters": "\u2584" },
+ "љ": { "codepoints": [1113], "characters": "\u0459" },
+ "≪": { "codepoints": [8810], "characters": "\u226A" },
+ "⇇": { "codepoints": [8647], "characters": "\u21C7" },
+ "⌞": { "codepoints": [8990], "characters": "\u231E" },
+ "⥫": { "codepoints": [10603], "characters": "\u296B" },
+ "◺": { "codepoints": [9722], "characters": "\u25FA" },
+ "ŀ": { "codepoints": [320], "characters": "\u0140" },
+ "⎰": { "codepoints": [9136], "characters": "\u23B0" },
+ "⎰": { "codepoints": [9136], "characters": "\u23B0" },
+ "≨": { "codepoints": [8808], "characters": "\u2268" },
+ "⪉": { "codepoints": [10889], "characters": "\u2A89" },
+ "⪉": { "codepoints": [10889], "characters": "\u2A89" },
+ "⪇": { "codepoints": [10887], "characters": "\u2A87" },
+ "⪇": { "codepoints": [10887], "characters": "\u2A87" },
+ "≨": { "codepoints": [8808], "characters": "\u2268" },
+ "⋦": { "codepoints": [8934], "characters": "\u22E6" },
+ "⟬": { "codepoints": [10220], "characters": "\u27EC" },
+ "⇽": { "codepoints": [8701], "characters": "\u21FD" },
+ "⟦": { "codepoints": [10214], "characters": "\u27E6" },
+ "⟵": { "codepoints": [10229], "characters": "\u27F5" },
+ "⟷": { "codepoints": [10231], "characters": "\u27F7" },
+ "⟼": { "codepoints": [10236], "characters": "\u27FC" },
+ "⟶": { "codepoints": [10230], "characters": "\u27F6" },
+ "↫": { "codepoints": [8619], "characters": "\u21AB" },
+ "↬": { "codepoints": [8620], "characters": "\u21AC" },
+ "⦅": { "codepoints": [10629], "characters": "\u2985" },
+ "𝕝": { "codepoints": [120157], "characters": "\uD835\uDD5D" },
+ "⨭": { "codepoints": [10797], "characters": "\u2A2D" },
+ "⨴": { "codepoints": [10804], "characters": "\u2A34" },
+ "∗": { "codepoints": [8727], "characters": "\u2217" },
+ "_": { "codepoints": [95], "characters": "\u005F" },
+ "◊": { "codepoints": [9674], "characters": "\u25CA" },
+ "◊": { "codepoints": [9674], "characters": "\u25CA" },
+ "⧫": { "codepoints": [10731], "characters": "\u29EB" },
+ "(": { "codepoints": [40], "characters": "\u0028" },
+ "⦓": { "codepoints": [10643], "characters": "\u2993" },
+ "⇆": { "codepoints": [8646], "characters": "\u21C6" },
+ "⌟": { "codepoints": [8991], "characters": "\u231F" },
+ "⇋": { "codepoints": [8651], "characters": "\u21CB" },
+ "⥭": { "codepoints": [10605], "characters": "\u296D" },
+ "‎": { "codepoints": [8206], "characters": "\u200E" },
+ "⊿": { "codepoints": [8895], "characters": "\u22BF" },
+ "‹": { "codepoints": [8249], "characters": "\u2039" },
+ "𝓁": { "codepoints": [120001], "characters": "\uD835\uDCC1" },
+ "↰": { "codepoints": [8624], "characters": "\u21B0" },
+ "≲": { "codepoints": [8818], "characters": "\u2272" },
+ "⪍": { "codepoints": [10893], "characters": "\u2A8D" },
+ "⪏": { "codepoints": [10895], "characters": "\u2A8F" },
+ "[": { "codepoints": [91], "characters": "\u005B" },
+ "‘": { "codepoints": [8216], "characters": "\u2018" },
+ "‚": { "codepoints": [8218], "characters": "\u201A" },
+ "ł": { "codepoints": [322], "characters": "\u0142" },
+ "<": { "codepoints": [60], "characters": "\u003C" },
+ "<": { "codepoints": [60], "characters": "\u003C" },
+ "⪦": { "codepoints": [10918], "characters": "\u2AA6" },
+ "⩹": { "codepoints": [10873], "characters": "\u2A79" },
+ "⋖": { "codepoints": [8918], "characters": "\u22D6" },
+ "⋋": { "codepoints": [8907], "characters": "\u22CB" },
+ "⋉": { "codepoints": [8905], "characters": "\u22C9" },
+ "⥶": { "codepoints": [10614], "characters": "\u2976" },
+ "⩻": { "codepoints": [10875], "characters": "\u2A7B" },
+ "⦖": { "codepoints": [10646], "characters": "\u2996" },
+ "◃": { "codepoints": [9667], "characters": "\u25C3" },
+ "⊴": { "codepoints": [8884], "characters": "\u22B4" },
+ "◂": { "codepoints": [9666], "characters": "\u25C2" },
+ "⥊": { "codepoints": [10570], "characters": "\u294A" },
+ "⥦": { "codepoints": [10598], "characters": "\u2966" },
+ "≨︀": { "codepoints": [8808, 65024], "characters": "\u2268\uFE00" },
+ "≨︀": { "codepoints": [8808, 65024], "characters": "\u2268\uFE00" },
+ "∺": { "codepoints": [8762], "characters": "\u223A" },
+ "¯": { "codepoints": [175], "characters": "\u00AF" },
+ "¯": { "codepoints": [175], "characters": "\u00AF" },
+ "♂": { "codepoints": [9794], "characters": "\u2642" },
+ "✠": { "codepoints": [10016], "characters": "\u2720" },
+ "✠": { "codepoints": [10016], "characters": "\u2720" },
+ "↦": { "codepoints": [8614], "characters": "\u21A6" },
+ "↦": { "codepoints": [8614], "characters": "\u21A6" },
+ "↧": { "codepoints": [8615], "characters": "\u21A7" },
+ "↤": { "codepoints": [8612], "characters": "\u21A4" },
+ "↥": { "codepoints": [8613], "characters": "\u21A5" },
+ "▮": { "codepoints": [9646], "characters": "\u25AE" },
+ "⨩": { "codepoints": [10793], "characters": "\u2A29" },
+ "м": { "codepoints": [1084], "characters": "\u043C" },
+ "—": { "codepoints": [8212], "characters": "\u2014" },
+ "∡": { "codepoints": [8737], "characters": "\u2221" },
+ "𝔪": { "codepoints": [120106], "characters": "\uD835\uDD2A" },
+ "℧": { "codepoints": [8487], "characters": "\u2127" },
+ "µ": { "codepoints": [181], "characters": "\u00B5" },
+ "µ": { "codepoints": [181], "characters": "\u00B5" },
+ "∣": { "codepoints": [8739], "characters": "\u2223" },
+ "*": { "codepoints": [42], "characters": "\u002A" },
+ "⫰": { "codepoints": [10992], "characters": "\u2AF0" },
+ "·": { "codepoints": [183], "characters": "\u00B7" },
+ "·": { "codepoints": [183], "characters": "\u00B7" },
+ "−": { "codepoints": [8722], "characters": "\u2212" },
+ "⊟": { "codepoints": [8863], "characters": "\u229F" },
+ "∸": { "codepoints": [8760], "characters": "\u2238" },
+ "⨪": { "codepoints": [10794], "characters": "\u2A2A" },
+ "⫛": { "codepoints": [10971], "characters": "\u2ADB" },
+ "…": { "codepoints": [8230], "characters": "\u2026" },
+ "∓": { "codepoints": [8723], "characters": "\u2213" },
+ "⊧": { "codepoints": [8871], "characters": "\u22A7" },
+ "𝕞": { "codepoints": [120158], "characters": "\uD835\uDD5E" },
+ "∓": { "codepoints": [8723], "characters": "\u2213" },
+ "𝓂": { "codepoints": [120002], "characters": "\uD835\uDCC2" },
+ "∾": { "codepoints": [8766], "characters": "\u223E" },
+ "μ": { "codepoints": [956], "characters": "\u03BC" },
+ "⊸": { "codepoints": [8888], "characters": "\u22B8" },
+ "⊸": { "codepoints": [8888], "characters": "\u22B8" },
+ "⋙̸": { "codepoints": [8921, 824], "characters": "\u22D9\u0338" },
+ "≫⃒": { "codepoints": [8811, 8402], "characters": "\u226B\u20D2" },
+ "≫̸": { "codepoints": [8811, 824], "characters": "\u226B\u0338" },
+ "⇍": { "codepoints": [8653], "characters": "\u21CD" },
+ "⇎": { "codepoints": [8654], "characters": "\u21CE" },
+ "⋘̸": { "codepoints": [8920, 824], "characters": "\u22D8\u0338" },
+ "≪⃒": { "codepoints": [8810, 8402], "characters": "\u226A\u20D2" },
+ "≪̸": { "codepoints": [8810, 824], "characters": "\u226A\u0338" },
+ "⇏": { "codepoints": [8655], "characters": "\u21CF" },
+ "⊯": { "codepoints": [8879], "characters": "\u22AF" },
+ "⊮": { "codepoints": [8878], "characters": "\u22AE" },
+ "∇": { "codepoints": [8711], "characters": "\u2207" },
+ "ń": { "codepoints": [324], "characters": "\u0144" },
+ "∠⃒": { "codepoints": [8736, 8402], "characters": "\u2220\u20D2" },
+ "≉": { "codepoints": [8777], "characters": "\u2249" },
+ "⩰̸": { "codepoints": [10864, 824], "characters": "\u2A70\u0338" },
+ "≋̸": { "codepoints": [8779, 824], "characters": "\u224B\u0338" },
+ "ʼn": { "codepoints": [329], "characters": "\u0149" },
+ "≉": { "codepoints": [8777], "characters": "\u2249" },
+ "♮": { "codepoints": [9838], "characters": "\u266E" },
+ "♮": { "codepoints": [9838], "characters": "\u266E" },
+ "ℕ": { "codepoints": [8469], "characters": "\u2115" },
+ " ": { "codepoints": [160], "characters": "\u00A0" },
+ " ": { "codepoints": [160], "characters": "\u00A0" },
+ "≎̸": { "codepoints": [8782, 824], "characters": "\u224E\u0338" },
+ "≏̸": { "codepoints": [8783, 824], "characters": "\u224F\u0338" },
+ "⩃": { "codepoints": [10819], "characters": "\u2A43" },
+ "ň": { "codepoints": [328], "characters": "\u0148" },
+ "ņ": { "codepoints": [326], "characters": "\u0146" },
+ "≇": { "codepoints": [8775], "characters": "\u2247" },
+ "⩭̸": { "codepoints": [10861, 824], "characters": "\u2A6D\u0338" },
+ "⩂": { "codepoints": [10818], "characters": "\u2A42" },
+ "н": { "codepoints": [1085], "characters": "\u043D" },
+ "–": { "codepoints": [8211], "characters": "\u2013" },
+ "≠": { "codepoints": [8800], "characters": "\u2260" },
+ "⇗": { "codepoints": [8663], "characters": "\u21D7" },
+ "⤤": { "codepoints": [10532], "characters": "\u2924" },
+ "↗": { "codepoints": [8599], "characters": "\u2197" },
+ "↗": { "codepoints": [8599], "characters": "\u2197" },
+ "≐̸": { "codepoints": [8784, 824], "characters": "\u2250\u0338" },
+ "≢": { "codepoints": [8802], "characters": "\u2262" },
+ "⤨": { "codepoints": [10536], "characters": "\u2928" },
+ "≂̸": { "codepoints": [8770, 824], "characters": "\u2242\u0338" },
+ "∄": { "codepoints": [8708], "characters": "\u2204" },
+ "∄": { "codepoints": [8708], "characters": "\u2204" },
+ "𝔫": { "codepoints": [120107], "characters": "\uD835\uDD2B" },
+ "≧̸": { "codepoints": [8807, 824], "characters": "\u2267\u0338" },
+ "≱": { "codepoints": [8817], "characters": "\u2271" },
+ "≱": { "codepoints": [8817], "characters": "\u2271" },
+ "≧̸": { "codepoints": [8807, 824], "characters": "\u2267\u0338" },
+ "⩾̸": { "codepoints": [10878, 824], "characters": "\u2A7E\u0338" },
+ "⩾̸": { "codepoints": [10878, 824], "characters": "\u2A7E\u0338" },
+ "≵": { "codepoints": [8821], "characters": "\u2275" },
+ "≯": { "codepoints": [8815], "characters": "\u226F" },
+ "≯": { "codepoints": [8815], "characters": "\u226F" },
+ "⇎": { "codepoints": [8654], "characters": "\u21CE" },
+ "↮": { "codepoints": [8622], "characters": "\u21AE" },
+ "⫲": { "codepoints": [10994], "characters": "\u2AF2" },
+ "∋": { "codepoints": [8715], "characters": "\u220B" },
+ "⋼": { "codepoints": [8956], "characters": "\u22FC" },
+ "⋺": { "codepoints": [8954], "characters": "\u22FA" },
+ "∋": { "codepoints": [8715], "characters": "\u220B" },
+ "њ": { "codepoints": [1114], "characters": "\u045A" },
+ "⇍": { "codepoints": [8653], "characters": "\u21CD" },
+ "≦̸": { "codepoints": [8806, 824], "characters": "\u2266\u0338" },
+ "↚": { "codepoints": [8602], "characters": "\u219A" },
+ "‥": { "codepoints": [8229], "characters": "\u2025" },
+ "≰": { "codepoints": [8816], "characters": "\u2270" },
+ "↚": { "codepoints": [8602], "characters": "\u219A" },
+ "↮": { "codepoints": [8622], "characters": "\u21AE" },
+ "≰": { "codepoints": [8816], "characters": "\u2270" },
+ "≦̸": { "codepoints": [8806, 824], "characters": "\u2266\u0338" },
+ "⩽̸": { "codepoints": [10877, 824], "characters": "\u2A7D\u0338" },
+ "⩽̸": { "codepoints": [10877, 824], "characters": "\u2A7D\u0338" },
+ "≮": { "codepoints": [8814], "characters": "\u226E" },
+ "≴": { "codepoints": [8820], "characters": "\u2274" },
+ "≮": { "codepoints": [8814], "characters": "\u226E" },
+ "⋪": { "codepoints": [8938], "characters": "\u22EA" },
+ "⋬": { "codepoints": [8940], "characters": "\u22EC" },
+ "∤": { "codepoints": [8740], "characters": "\u2224" },
+ "𝕟": { "codepoints": [120159], "characters": "\uD835\uDD5F" },
+ "¬": { "codepoints": [172], "characters": "\u00AC" },
+ "¬": { "codepoints": [172], "characters": "\u00AC" },
+ "∉": { "codepoints": [8713], "characters": "\u2209" },
+ "⋹̸": { "codepoints": [8953, 824], "characters": "\u22F9\u0338" },
+ "⋵̸": { "codepoints": [8949, 824], "characters": "\u22F5\u0338" },
+ "∉": { "codepoints": [8713], "characters": "\u2209" },
+ "⋷": { "codepoints": [8951], "characters": "\u22F7" },
+ "⋶": { "codepoints": [8950], "characters": "\u22F6" },
+ "∌": { "codepoints": [8716], "characters": "\u220C" },
+ "∌": { "codepoints": [8716], "characters": "\u220C" },
+ "⋾": { "codepoints": [8958], "characters": "\u22FE" },
+ "⋽": { "codepoints": [8957], "characters": "\u22FD" },
+ "∦": { "codepoints": [8742], "characters": "\u2226" },
+ "∦": { "codepoints": [8742], "characters": "\u2226" },
+ "⫽⃥": { "codepoints": [11005, 8421], "characters": "\u2AFD\u20E5" },
+ "∂̸": { "codepoints": [8706, 824], "characters": "\u2202\u0338" },
+ "⨔": { "codepoints": [10772], "characters": "\u2A14" },
+ "⊀": { "codepoints": [8832], "characters": "\u2280" },
+ "⋠": { "codepoints": [8928], "characters": "\u22E0" },
+ "⪯̸": { "codepoints": [10927, 824], "characters": "\u2AAF\u0338" },
+ "⊀": { "codepoints": [8832], "characters": "\u2280" },
+ "⪯̸": { "codepoints": [10927, 824], "characters": "\u2AAF\u0338" },
+ "⇏": { "codepoints": [8655], "characters": "\u21CF" },
+ "↛": { "codepoints": [8603], "characters": "\u219B" },
+ "⤳̸": { "codepoints": [10547, 824], "characters": "\u2933\u0338" },
+ "↝̸": { "codepoints": [8605, 824], "characters": "\u219D\u0338" },
+ "↛": { "codepoints": [8603], "characters": "\u219B" },
+ "⋫": { "codepoints": [8939], "characters": "\u22EB" },
+ "⋭": { "codepoints": [8941], "characters": "\u22ED" },
+ "⊁": { "codepoints": [8833], "characters": "\u2281" },
+ "⋡": { "codepoints": [8929], "characters": "\u22E1" },
+ "⪰̸": { "codepoints": [10928, 824], "characters": "\u2AB0\u0338" },
+ "𝓃": { "codepoints": [120003], "characters": "\uD835\uDCC3" },
+ "∤": { "codepoints": [8740], "characters": "\u2224" },
+ "∦": { "codepoints": [8742], "characters": "\u2226" },
+ "≁": { "codepoints": [8769], "characters": "\u2241" },
+ "≄": { "codepoints": [8772], "characters": "\u2244" },
+ "≄": { "codepoints": [8772], "characters": "\u2244" },
+ "∤": { "codepoints": [8740], "characters": "\u2224" },
+ "∦": { "codepoints": [8742], "characters": "\u2226" },
+ "⋢": { "codepoints": [8930], "characters": "\u22E2" },
+ "⋣": { "codepoints": [8931], "characters": "\u22E3" },
+ "⊄": { "codepoints": [8836], "characters": "\u2284" },
+ "⫅̸": { "codepoints": [10949, 824], "characters": "\u2AC5\u0338" },
+ "⊈": { "codepoints": [8840], "characters": "\u2288" },
+ "⊂⃒": { "codepoints": [8834, 8402], "characters": "\u2282\u20D2" },
+ "⊈": { "codepoints": [8840], "characters": "\u2288" },
+ "⫅̸": { "codepoints": [10949, 824], "characters": "\u2AC5\u0338" },
+ "⊁": { "codepoints": [8833], "characters": "\u2281" },
+ "⪰̸": { "codepoints": [10928, 824], "characters": "\u2AB0\u0338" },
+ "⊅": { "codepoints": [8837], "characters": "\u2285" },
+ "⫆̸": { "codepoints": [10950, 824], "characters": "\u2AC6\u0338" },
+ "⊉": { "codepoints": [8841], "characters": "\u2289" },
+ "⊃⃒": { "codepoints": [8835, 8402], "characters": "\u2283\u20D2" },
+ "⊉": { "codepoints": [8841], "characters": "\u2289" },
+ "⫆̸": { "codepoints": [10950, 824], "characters": "\u2AC6\u0338" },
+ "≹": { "codepoints": [8825], "characters": "\u2279" },
+ "ñ": { "codepoints": [241], "characters": "\u00F1" },
+ "ñ": { "codepoints": [241], "characters": "\u00F1" },
+ "≸": { "codepoints": [8824], "characters": "\u2278" },
+ "⋪": { "codepoints": [8938], "characters": "\u22EA" },
+ "⋬": { "codepoints": [8940], "characters": "\u22EC" },
+ "⋫": { "codepoints": [8939], "characters": "\u22EB" },
+ "⋭": { "codepoints": [8941], "characters": "\u22ED" },
+ "ν": { "codepoints": [957], "characters": "\u03BD" },
+ "#": { "codepoints": [35], "characters": "\u0023" },
+ "№": { "codepoints": [8470], "characters": "\u2116" },
+ " ": { "codepoints": [8199], "characters": "\u2007" },
+ "⊭": { "codepoints": [8877], "characters": "\u22AD" },
+ "⤄": { "codepoints": [10500], "characters": "\u2904" },
+ "≍⃒": { "codepoints": [8781, 8402], "characters": "\u224D\u20D2" },
+ "⊬": { "codepoints": [8876], "characters": "\u22AC" },
+ "≥⃒": { "codepoints": [8805, 8402], "characters": "\u2265\u20D2" },
+ ">⃒": { "codepoints": [62, 8402], "characters": "\u003E\u20D2" },
+ "⧞": { "codepoints": [10718], "characters": "\u29DE" },
+ "⤂": { "codepoints": [10498], "characters": "\u2902" },
+ "≤⃒": { "codepoints": [8804, 8402], "characters": "\u2264\u20D2" },
+ "<⃒": { "codepoints": [60, 8402], "characters": "\u003C\u20D2" },
+ "⊴⃒": { "codepoints": [8884, 8402], "characters": "\u22B4\u20D2" },
+ "⤃": { "codepoints": [10499], "characters": "\u2903" },
+ "⊵⃒": { "codepoints": [8885, 8402], "characters": "\u22B5\u20D2" },
+ "∼⃒": { "codepoints": [8764, 8402], "characters": "\u223C\u20D2" },
+ "⇖": { "codepoints": [8662], "characters": "\u21D6" },
+ "⤣": { "codepoints": [10531], "characters": "\u2923" },
+ "↖": { "codepoints": [8598], "characters": "\u2196" },
+ "↖": { "codepoints": [8598], "characters": "\u2196" },
+ "⤧": { "codepoints": [10535], "characters": "\u2927" },
+ "Ⓢ": { "codepoints": [9416], "characters": "\u24C8" },
+ "ó": { "codepoints": [243], "characters": "\u00F3" },
+ "ó": { "codepoints": [243], "characters": "\u00F3" },
+ "⊛": { "codepoints": [8859], "characters": "\u229B" },
+ "⊚": { "codepoints": [8858], "characters": "\u229A" },
+ "ô": { "codepoints": [244], "characters": "\u00F4" },
+ "ô": { "codepoints": [244], "characters": "\u00F4" },
+ "о": { "codepoints": [1086], "characters": "\u043E" },
+ "⊝": { "codepoints": [8861], "characters": "\u229D" },
+ "ő": { "codepoints": [337], "characters": "\u0151" },
+ "⨸": { "codepoints": [10808], "characters": "\u2A38" },
+ "⊙": { "codepoints": [8857], "characters": "\u2299" },
+ "⦼": { "codepoints": [10684], "characters": "\u29BC" },
+ "œ": { "codepoints": [339], "characters": "\u0153" },
+ "⦿": { "codepoints": [10687], "characters": "\u29BF" },
+ "𝔬": { "codepoints": [120108], "characters": "\uD835\uDD2C" },
+ "˛": { "codepoints": [731], "characters": "\u02DB" },
+ "ò": { "codepoints": [242], "characters": "\u00F2" },
+ "ò": { "codepoints": [242], "characters": "\u00F2" },
+ "⧁": { "codepoints": [10689], "characters": "\u29C1" },
+ "⦵": { "codepoints": [10677], "characters": "\u29B5" },
+ "Ω": { "codepoints": [937], "characters": "\u03A9" },
+ "∮": { "codepoints": [8750], "characters": "\u222E" },
+ "↺": { "codepoints": [8634], "characters": "\u21BA" },
+ "⦾": { "codepoints": [10686], "characters": "\u29BE" },
+ "⦻": { "codepoints": [10683], "characters": "\u29BB" },
+ "‾": { "codepoints": [8254], "characters": "\u203E" },
+ "⧀": { "codepoints": [10688], "characters": "\u29C0" },
+ "ō": { "codepoints": [333], "characters": "\u014D" },
+ "ω": { "codepoints": [969], "characters": "\u03C9" },
+ "ο": { "codepoints": [959], "characters": "\u03BF" },
+ "⦶": { "codepoints": [10678], "characters": "\u29B6" },
+ "⊖": { "codepoints": [8854], "characters": "\u2296" },
+ "𝕠": { "codepoints": [120160], "characters": "\uD835\uDD60" },
+ "⦷": { "codepoints": [10679], "characters": "\u29B7" },
+ "⦹": { "codepoints": [10681], "characters": "\u29B9" },
+ "⊕": { "codepoints": [8853], "characters": "\u2295" },
+ "∨": { "codepoints": [8744], "characters": "\u2228" },
+ "↻": { "codepoints": [8635], "characters": "\u21BB" },
+ "⩝": { "codepoints": [10845], "characters": "\u2A5D" },
+ "ℴ": { "codepoints": [8500], "characters": "\u2134" },
+ "ℴ": { "codepoints": [8500], "characters": "\u2134" },
+ "ª": { "codepoints": [170], "characters": "\u00AA" },
+ "ª": { "codepoints": [170], "characters": "\u00AA" },
+ "º": { "codepoints": [186], "characters": "\u00BA" },
+ "º": { "codepoints": [186], "characters": "\u00BA" },
+ "⊶": { "codepoints": [8886], "characters": "\u22B6" },
+ "⩖": { "codepoints": [10838], "characters": "\u2A56" },
+ "⩗": { "codepoints": [10839], "characters": "\u2A57" },
+ "⩛": { "codepoints": [10843], "characters": "\u2A5B" },
+ "ℴ": { "codepoints": [8500], "characters": "\u2134" },
+ "ø": { "codepoints": [248], "characters": "\u00F8" },
+ "ø": { "codepoints": [248], "characters": "\u00F8" },
+ "⊘": { "codepoints": [8856], "characters": "\u2298" },
+ "õ": { "codepoints": [245], "characters": "\u00F5" },
+ "õ": { "codepoints": [245], "characters": "\u00F5" },
+ "⊗": { "codepoints": [8855], "characters": "\u2297" },
+ "⨶": { "codepoints": [10806], "characters": "\u2A36" },
+ "ö": { "codepoints": [246], "characters": "\u00F6" },
+ "ö": { "codepoints": [246], "characters": "\u00F6" },
+ "⌽": { "codepoints": [9021], "characters": "\u233D" },
+ "∥": { "codepoints": [8741], "characters": "\u2225" },
+ "¶": { "codepoints": [182], "characters": "\u00B6" },
+ "¶": { "codepoints": [182], "characters": "\u00B6" },
+ "∥": { "codepoints": [8741], "characters": "\u2225" },
+ "⫳": { "codepoints": [10995], "characters": "\u2AF3" },
+ "⫽": { "codepoints": [11005], "characters": "\u2AFD" },
+ "∂": { "codepoints": [8706], "characters": "\u2202" },
+ "п": { "codepoints": [1087], "characters": "\u043F" },
+ "%": { "codepoints": [37], "characters": "\u0025" },
+ ".": { "codepoints": [46], "characters": "\u002E" },
+ "‰": { "codepoints": [8240], "characters": "\u2030" },
+ "⊥": { "codepoints": [8869], "characters": "\u22A5" },
+ "‱": { "codepoints": [8241], "characters": "\u2031" },
+ "𝔭": { "codepoints": [120109], "characters": "\uD835\uDD2D" },
+ "φ": { "codepoints": [966], "characters": "\u03C6" },
+ "ϕ": { "codepoints": [981], "characters": "\u03D5" },
+ "ℳ": { "codepoints": [8499], "characters": "\u2133" },
+ "☎": { "codepoints": [9742], "characters": "\u260E" },
+ "π": { "codepoints": [960], "characters": "\u03C0" },
+ "⋔": { "codepoints": [8916], "characters": "\u22D4" },
+ "ϖ": { "codepoints": [982], "characters": "\u03D6" },
+ "ℏ": { "codepoints": [8463], "characters": "\u210F" },
+ "ℎ": { "codepoints": [8462], "characters": "\u210E" },
+ "ℏ": { "codepoints": [8463], "characters": "\u210F" },
+ "+": { "codepoints": [43], "characters": "\u002B" },
+ "⨣": { "codepoints": [10787], "characters": "\u2A23" },
+ "⊞": { "codepoints": [8862], "characters": "\u229E" },
+ "⨢": { "codepoints": [10786], "characters": "\u2A22" },
+ "∔": { "codepoints": [8724], "characters": "\u2214" },
+ "⨥": { "codepoints": [10789], "characters": "\u2A25" },
+ "⩲": { "codepoints": [10866], "characters": "\u2A72" },
+ "±": { "codepoints": [177], "characters": "\u00B1" },
+ "±": { "codepoints": [177], "characters": "\u00B1" },
+ "⨦": { "codepoints": [10790], "characters": "\u2A26" },
+ "⨧": { "codepoints": [10791], "characters": "\u2A27" },
+ "±": { "codepoints": [177], "characters": "\u00B1" },
+ "⨕": { "codepoints": [10773], "characters": "\u2A15" },
+ "𝕡": { "codepoints": [120161], "characters": "\uD835\uDD61" },
+ "£": { "codepoints": [163], "characters": "\u00A3" },
+ "£": { "codepoints": [163], "characters": "\u00A3" },
+ "≺": { "codepoints": [8826], "characters": "\u227A" },
+ "⪳": { "codepoints": [10931], "characters": "\u2AB3" },
+ "⪷": { "codepoints": [10935], "characters": "\u2AB7" },
+ "≼": { "codepoints": [8828], "characters": "\u227C" },
+ "⪯": { "codepoints": [10927], "characters": "\u2AAF" },
+ "≺": { "codepoints": [8826], "characters": "\u227A" },
+ "⪷": { "codepoints": [10935], "characters": "\u2AB7" },
+ "≼": { "codepoints": [8828], "characters": "\u227C" },
+ "⪯": { "codepoints": [10927], "characters": "\u2AAF" },
+ "⪹": { "codepoints": [10937], "characters": "\u2AB9" },
+ "⪵": { "codepoints": [10933], "characters": "\u2AB5" },
+ "⋨": { "codepoints": [8936], "characters": "\u22E8" },
+ "≾": { "codepoints": [8830], "characters": "\u227E" },
+ "′": { "codepoints": [8242], "characters": "\u2032" },
+ "ℙ": { "codepoints": [8473], "characters": "\u2119" },
+ "⪵": { "codepoints": [10933], "characters": "\u2AB5" },
+ "⪹": { "codepoints": [10937], "characters": "\u2AB9" },
+ "⋨": { "codepoints": [8936], "characters": "\u22E8" },
+ "∏": { "codepoints": [8719], "characters": "\u220F" },
+ "⌮": { "codepoints": [9006], "characters": "\u232E" },
+ "⌒": { "codepoints": [8978], "characters": "\u2312" },
+ "⌓": { "codepoints": [8979], "characters": "\u2313" },
+ "∝": { "codepoints": [8733], "characters": "\u221D" },
+ "∝": { "codepoints": [8733], "characters": "\u221D" },
+ "≾": { "codepoints": [8830], "characters": "\u227E" },
+ "⊰": { "codepoints": [8880], "characters": "\u22B0" },
+ "𝓅": { "codepoints": [120005], "characters": "\uD835\uDCC5" },
+ "ψ": { "codepoints": [968], "characters": "\u03C8" },
+ " ": { "codepoints": [8200], "characters": "\u2008" },
+ "𝔮": { "codepoints": [120110], "characters": "\uD835\uDD2E" },
+ "⨌": { "codepoints": [10764], "characters": "\u2A0C" },
+ "𝕢": { "codepoints": [120162], "characters": "\uD835\uDD62" },
+ "⁗": { "codepoints": [8279], "characters": "\u2057" },
+ "𝓆": { "codepoints": [120006], "characters": "\uD835\uDCC6" },
+ "ℍ": { "codepoints": [8461], "characters": "\u210D" },
+ "⨖": { "codepoints": [10774], "characters": "\u2A16" },
+ "?": { "codepoints": [63], "characters": "\u003F" },
+ "≟": { "codepoints": [8799], "characters": "\u225F" },
+ """: { "codepoints": [34], "characters": "\u0022" },
+ """: { "codepoints": [34], "characters": "\u0022" },
+ "⇛": { "codepoints": [8667], "characters": "\u21DB" },
+ "⇒": { "codepoints": [8658], "characters": "\u21D2" },
+ "⤜": { "codepoints": [10524], "characters": "\u291C" },
+ "⤏": { "codepoints": [10511], "characters": "\u290F" },
+ "⥤": { "codepoints": [10596], "characters": "\u2964" },
+ "∽̱": { "codepoints": [8765, 817], "characters": "\u223D\u0331" },
+ "ŕ": { "codepoints": [341], "characters": "\u0155" },
+ "√": { "codepoints": [8730], "characters": "\u221A" },
+ "⦳": { "codepoints": [10675], "characters": "\u29B3" },
+ "⟩": { "codepoints": [10217], "characters": "\u27E9" },
+ "⦒": { "codepoints": [10642], "characters": "\u2992" },
+ "⦥": { "codepoints": [10661], "characters": "\u29A5" },
+ "⟩": { "codepoints": [10217], "characters": "\u27E9" },
+ "»": { "codepoints": [187], "characters": "\u00BB" },
+ "»": { "codepoints": [187], "characters": "\u00BB" },
+ "→": { "codepoints": [8594], "characters": "\u2192" },
+ "⥵": { "codepoints": [10613], "characters": "\u2975" },
+ "⇥": { "codepoints": [8677], "characters": "\u21E5" },
+ "⤠": { "codepoints": [10528], "characters": "\u2920" },
+ "⤳": { "codepoints": [10547], "characters": "\u2933" },
+ "⤞": { "codepoints": [10526], "characters": "\u291E" },
+ "↪": { "codepoints": [8618], "characters": "\u21AA" },
+ "↬": { "codepoints": [8620], "characters": "\u21AC" },
+ "⥅": { "codepoints": [10565], "characters": "\u2945" },
+ "⥴": { "codepoints": [10612], "characters": "\u2974" },
+ "↣": { "codepoints": [8611], "characters": "\u21A3" },
+ "↝": { "codepoints": [8605], "characters": "\u219D" },
+ "⤚": { "codepoints": [10522], "characters": "\u291A" },
+ "∶": { "codepoints": [8758], "characters": "\u2236" },
+ "ℚ": { "codepoints": [8474], "characters": "\u211A" },
+ "⤍": { "codepoints": [10509], "characters": "\u290D" },
+ "❳": { "codepoints": [10099], "characters": "\u2773" },
+ "}": { "codepoints": [125], "characters": "\u007D" },
+ "]": { "codepoints": [93], "characters": "\u005D" },
+ "⦌": { "codepoints": [10636], "characters": "\u298C" },
+ "⦎": { "codepoints": [10638], "characters": "\u298E" },
+ "⦐": { "codepoints": [10640], "characters": "\u2990" },
+ "ř": { "codepoints": [345], "characters": "\u0159" },
+ "ŗ": { "codepoints": [343], "characters": "\u0157" },
+ "⌉": { "codepoints": [8969], "characters": "\u2309" },
+ "}": { "codepoints": [125], "characters": "\u007D" },
+ "р": { "codepoints": [1088], "characters": "\u0440" },
+ "⤷": { "codepoints": [10551], "characters": "\u2937" },
+ "⥩": { "codepoints": [10601], "characters": "\u2969" },
+ "”": { "codepoints": [8221], "characters": "\u201D" },
+ "”": { "codepoints": [8221], "characters": "\u201D" },
+ "↳": { "codepoints": [8627], "characters": "\u21B3" },
+ "ℜ": { "codepoints": [8476], "characters": "\u211C" },
+ "ℛ": { "codepoints": [8475], "characters": "\u211B" },
+ "ℜ": { "codepoints": [8476], "characters": "\u211C" },
+ "ℝ": { "codepoints": [8477], "characters": "\u211D" },
+ "▭": { "codepoints": [9645], "characters": "\u25AD" },
+ "®": { "codepoints": [174], "characters": "\u00AE" },
+ "®": { "codepoints": [174], "characters": "\u00AE" },
+ "⥽": { "codepoints": [10621], "characters": "\u297D" },
+ "⌋": { "codepoints": [8971], "characters": "\u230B" },
+ "𝔯": { "codepoints": [120111], "characters": "\uD835\uDD2F" },
+ "⇁": { "codepoints": [8641], "characters": "\u21C1" },
+ "⇀": { "codepoints": [8640], "characters": "\u21C0" },
+ "⥬": { "codepoints": [10604], "characters": "\u296C" },
+ "ρ": { "codepoints": [961], "characters": "\u03C1" },
+ "ϱ": { "codepoints": [1009], "characters": "\u03F1" },
+ "→": { "codepoints": [8594], "characters": "\u2192" },
+ "↣": { "codepoints": [8611], "characters": "\u21A3" },
+ "⇁": { "codepoints": [8641], "characters": "\u21C1" },
+ "⇀": { "codepoints": [8640], "characters": "\u21C0" },
+ "⇄": { "codepoints": [8644], "characters": "\u21C4" },
+ "⇌": { "codepoints": [8652], "characters": "\u21CC" },
+ "⇉": { "codepoints": [8649], "characters": "\u21C9" },
+ "↝": { "codepoints": [8605], "characters": "\u219D" },
+ "⋌": { "codepoints": [8908], "characters": "\u22CC" },
+ "˚": { "codepoints": [730], "characters": "\u02DA" },
+ "≓": { "codepoints": [8787], "characters": "\u2253" },
+ "⇄": { "codepoints": [8644], "characters": "\u21C4" },
+ "⇌": { "codepoints": [8652], "characters": "\u21CC" },
+ "‏": { "codepoints": [8207], "characters": "\u200F" },
+ "⎱": { "codepoints": [9137], "characters": "\u23B1" },
+ "⎱": { "codepoints": [9137], "characters": "\u23B1" },
+ "⫮": { "codepoints": [10990], "characters": "\u2AEE" },
+ "⟭": { "codepoints": [10221], "characters": "\u27ED" },
+ "⇾": { "codepoints": [8702], "characters": "\u21FE" },
+ "⟧": { "codepoints": [10215], "characters": "\u27E7" },
+ "⦆": { "codepoints": [10630], "characters": "\u2986" },
+ "𝕣": { "codepoints": [120163], "characters": "\uD835\uDD63" },
+ "⨮": { "codepoints": [10798], "characters": "\u2A2E" },
+ "⨵": { "codepoints": [10805], "characters": "\u2A35" },
+ ")": { "codepoints": [41], "characters": "\u0029" },
+ "⦔": { "codepoints": [10644], "characters": "\u2994" },
+ "⨒": { "codepoints": [10770], "characters": "\u2A12" },
+ "⇉": { "codepoints": [8649], "characters": "\u21C9" },
+ "›": { "codepoints": [8250], "characters": "\u203A" },
+ "𝓇": { "codepoints": [120007], "characters": "\uD835\uDCC7" },
+ "↱": { "codepoints": [8625], "characters": "\u21B1" },
+ "]": { "codepoints": [93], "characters": "\u005D" },
+ "’": { "codepoints": [8217], "characters": "\u2019" },
+ "’": { "codepoints": [8217], "characters": "\u2019" },
+ "⋌": { "codepoints": [8908], "characters": "\u22CC" },
+ "⋊": { "codepoints": [8906], "characters": "\u22CA" },
+ "▹": { "codepoints": [9657], "characters": "\u25B9" },
+ "⊵": { "codepoints": [8885], "characters": "\u22B5" },
+ "▸": { "codepoints": [9656], "characters": "\u25B8" },
+ "⧎": { "codepoints": [10702], "characters": "\u29CE" },
+ "⥨": { "codepoints": [10600], "characters": "\u2968" },
+ "℞": { "codepoints": [8478], "characters": "\u211E" },
+ "ś": { "codepoints": [347], "characters": "\u015B" },
+ "‚": { "codepoints": [8218], "characters": "\u201A" },
+ "≻": { "codepoints": [8827], "characters": "\u227B" },
+ "⪴": { "codepoints": [10932], "characters": "\u2AB4" },
+ "⪸": { "codepoints": [10936], "characters": "\u2AB8" },
+ "š": { "codepoints": [353], "characters": "\u0161" },
+ "≽": { "codepoints": [8829], "characters": "\u227D" },
+ "⪰": { "codepoints": [10928], "characters": "\u2AB0" },
+ "ş": { "codepoints": [351], "characters": "\u015F" },
+ "ŝ": { "codepoints": [349], "characters": "\u015D" },
+ "⪶": { "codepoints": [10934], "characters": "\u2AB6" },
+ "⪺": { "codepoints": [10938], "characters": "\u2ABA" },
+ "⋩": { "codepoints": [8937], "characters": "\u22E9" },
+ "⨓": { "codepoints": [10771], "characters": "\u2A13" },
+ "≿": { "codepoints": [8831], "characters": "\u227F" },
+ "с": { "codepoints": [1089], "characters": "\u0441" },
+ "⋅": { "codepoints": [8901], "characters": "\u22C5" },
+ "⊡": { "codepoints": [8865], "characters": "\u22A1" },
+ "⩦": { "codepoints": [10854], "characters": "\u2A66" },
+ "⇘": { "codepoints": [8664], "characters": "\u21D8" },
+ "⤥": { "codepoints": [10533], "characters": "\u2925" },
+ "↘": { "codepoints": [8600], "characters": "\u2198" },
+ "↘": { "codepoints": [8600], "characters": "\u2198" },
+ "§": { "codepoints": [167], "characters": "\u00A7" },
+ "§": { "codepoints": [167], "characters": "\u00A7" },
+ ";": { "codepoints": [59], "characters": "\u003B" },
+ "⤩": { "codepoints": [10537], "characters": "\u2929" },
+ "∖": { "codepoints": [8726], "characters": "\u2216" },
+ "∖": { "codepoints": [8726], "characters": "\u2216" },
+ "✶": { "codepoints": [10038], "characters": "\u2736" },
+ "𝔰": { "codepoints": [120112], "characters": "\uD835\uDD30" },
+ "⌢": { "codepoints": [8994], "characters": "\u2322" },
+ "♯": { "codepoints": [9839], "characters": "\u266F" },
+ "щ": { "codepoints": [1097], "characters": "\u0449" },
+ "ш": { "codepoints": [1096], "characters": "\u0448" },
+ "∣": { "codepoints": [8739], "characters": "\u2223" },
+ "∥": { "codepoints": [8741], "characters": "\u2225" },
+ "­": { "codepoints": [173], "characters": "\u00AD" },
+ "­": { "codepoints": [173], "characters": "\u00AD" },
+ "σ": { "codepoints": [963], "characters": "\u03C3" },
+ "ς": { "codepoints": [962], "characters": "\u03C2" },
+ "ς": { "codepoints": [962], "characters": "\u03C2" },
+ "∼": { "codepoints": [8764], "characters": "\u223C" },
+ "⩪": { "codepoints": [10858], "characters": "\u2A6A" },
+ "≃": { "codepoints": [8771], "characters": "\u2243" },
+ "≃": { "codepoints": [8771], "characters": "\u2243" },
+ "⪞": { "codepoints": [10910], "characters": "\u2A9E" },
+ "⪠": { "codepoints": [10912], "characters": "\u2AA0" },
+ "⪝": { "codepoints": [10909], "characters": "\u2A9D" },
+ "⪟": { "codepoints": [10911], "characters": "\u2A9F" },
+ "≆": { "codepoints": [8774], "characters": "\u2246" },
+ "⨤": { "codepoints": [10788], "characters": "\u2A24" },
+ "⥲": { "codepoints": [10610], "characters": "\u2972" },
+ "←": { "codepoints": [8592], "characters": "\u2190" },
+ "∖": { "codepoints": [8726], "characters": "\u2216" },
+ "⨳": { "codepoints": [10803], "characters": "\u2A33" },
+ "⧤": { "codepoints": [10724], "characters": "\u29E4" },
+ "∣": { "codepoints": [8739], "characters": "\u2223" },
+ "⌣": { "codepoints": [8995], "characters": "\u2323" },
+ "⪪": { "codepoints": [10922], "characters": "\u2AAA" },
+ "⪬": { "codepoints": [10924], "characters": "\u2AAC" },
+ "⪬︀": { "codepoints": [10924, 65024], "characters": "\u2AAC\uFE00" },
+ "ь": { "codepoints": [1100], "characters": "\u044C" },
+ "/": { "codepoints": [47], "characters": "\u002F" },
+ "⧄": { "codepoints": [10692], "characters": "\u29C4" },
+ "⌿": { "codepoints": [9023], "characters": "\u233F" },
+ "𝕤": { "codepoints": [120164], "characters": "\uD835\uDD64" },
+ "♠": { "codepoints": [9824], "characters": "\u2660" },
+ "♠": { "codepoints": [9824], "characters": "\u2660" },
+ "∥": { "codepoints": [8741], "characters": "\u2225" },
+ "⊓": { "codepoints": [8851], "characters": "\u2293" },
+ "⊓︀": { "codepoints": [8851, 65024], "characters": "\u2293\uFE00" },
+ "⊔": { "codepoints": [8852], "characters": "\u2294" },
+ "⊔︀": { "codepoints": [8852, 65024], "characters": "\u2294\uFE00" },
+ "⊏": { "codepoints": [8847], "characters": "\u228F" },
+ "⊑": { "codepoints": [8849], "characters": "\u2291" },
+ "⊏": { "codepoints": [8847], "characters": "\u228F" },
+ "⊑": { "codepoints": [8849], "characters": "\u2291" },
+ "⊐": { "codepoints": [8848], "characters": "\u2290" },
+ "⊒": { "codepoints": [8850], "characters": "\u2292" },
+ "⊐": { "codepoints": [8848], "characters": "\u2290" },
+ "⊒": { "codepoints": [8850], "characters": "\u2292" },
+ "□": { "codepoints": [9633], "characters": "\u25A1" },
+ "□": { "codepoints": [9633], "characters": "\u25A1" },
+ "▪": { "codepoints": [9642], "characters": "\u25AA" },
+ "▪": { "codepoints": [9642], "characters": "\u25AA" },
+ "→": { "codepoints": [8594], "characters": "\u2192" },
+ "𝓈": { "codepoints": [120008], "characters": "\uD835\uDCC8" },
+ "∖": { "codepoints": [8726], "characters": "\u2216" },
+ "⌣": { "codepoints": [8995], "characters": "\u2323" },
+ "⋆": { "codepoints": [8902], "characters": "\u22C6" },
+ "☆": { "codepoints": [9734], "characters": "\u2606" },
+ "★": { "codepoints": [9733], "characters": "\u2605" },
+ "ϵ": { "codepoints": [1013], "characters": "\u03F5" },
+ "ϕ": { "codepoints": [981], "characters": "\u03D5" },
+ "¯": { "codepoints": [175], "characters": "\u00AF" },
+ "⊂": { "codepoints": [8834], "characters": "\u2282" },
+ "⫅": { "codepoints": [10949], "characters": "\u2AC5" },
+ "⪽": { "codepoints": [10941], "characters": "\u2ABD" },
+ "⊆": { "codepoints": [8838], "characters": "\u2286" },
+ "⫃": { "codepoints": [10947], "characters": "\u2AC3" },
+ "⫁": { "codepoints": [10945], "characters": "\u2AC1" },
+ "⫋": { "codepoints": [10955], "characters": "\u2ACB" },
+ "⊊": { "codepoints": [8842], "characters": "\u228A" },
+ "⪿": { "codepoints": [10943], "characters": "\u2ABF" },
+ "⥹": { "codepoints": [10617], "characters": "\u2979" },
+ "⊂": { "codepoints": [8834], "characters": "\u2282" },
+ "⊆": { "codepoints": [8838], "characters": "\u2286" },
+ "⫅": { "codepoints": [10949], "characters": "\u2AC5" },
+ "⊊": { "codepoints": [8842], "characters": "\u228A" },
+ "⫋": { "codepoints": [10955], "characters": "\u2ACB" },
+ "⫇": { "codepoints": [10951], "characters": "\u2AC7" },
+ "⫕": { "codepoints": [10965], "characters": "\u2AD5" },
+ "⫓": { "codepoints": [10963], "characters": "\u2AD3" },
+ "≻": { "codepoints": [8827], "characters": "\u227B" },
+ "⪸": { "codepoints": [10936], "characters": "\u2AB8" },
+ "≽": { "codepoints": [8829], "characters": "\u227D" },
+ "⪰": { "codepoints": [10928], "characters": "\u2AB0" },
+ "⪺": { "codepoints": [10938], "characters": "\u2ABA" },
+ "⪶": { "codepoints": [10934], "characters": "\u2AB6" },
+ "⋩": { "codepoints": [8937], "characters": "\u22E9" },
+ "≿": { "codepoints": [8831], "characters": "\u227F" },
+ "∑": { "codepoints": [8721], "characters": "\u2211" },
+ "♪": { "codepoints": [9834], "characters": "\u266A" },
+ "¹": { "codepoints": [185], "characters": "\u00B9" },
+ "¹": { "codepoints": [185], "characters": "\u00B9" },
+ "²": { "codepoints": [178], "characters": "\u00B2" },
+ "²": { "codepoints": [178], "characters": "\u00B2" },
+ "³": { "codepoints": [179], "characters": "\u00B3" },
+ "³": { "codepoints": [179], "characters": "\u00B3" },
+ "⊃": { "codepoints": [8835], "characters": "\u2283" },
+ "⫆": { "codepoints": [10950], "characters": "\u2AC6" },
+ "⪾": { "codepoints": [10942], "characters": "\u2ABE" },
+ "⫘": { "codepoints": [10968], "characters": "\u2AD8" },
+ "⊇": { "codepoints": [8839], "characters": "\u2287" },
+ "⫄": { "codepoints": [10948], "characters": "\u2AC4" },
+ "⟉": { "codepoints": [10185], "characters": "\u27C9" },
+ "⫗": { "codepoints": [10967], "characters": "\u2AD7" },
+ "⥻": { "codepoints": [10619], "characters": "\u297B" },
+ "⫂": { "codepoints": [10946], "characters": "\u2AC2" },
+ "⫌": { "codepoints": [10956], "characters": "\u2ACC" },
+ "⊋": { "codepoints": [8843], "characters": "\u228B" },
+ "⫀": { "codepoints": [10944], "characters": "\u2AC0" },
+ "⊃": { "codepoints": [8835], "characters": "\u2283" },
+ "⊇": { "codepoints": [8839], "characters": "\u2287" },
+ "⫆": { "codepoints": [10950], "characters": "\u2AC6" },
+ "⊋": { "codepoints": [8843], "characters": "\u228B" },
+ "⫌": { "codepoints": [10956], "characters": "\u2ACC" },
+ "⫈": { "codepoints": [10952], "characters": "\u2AC8" },
+ "⫔": { "codepoints": [10964], "characters": "\u2AD4" },
+ "⫖": { "codepoints": [10966], "characters": "\u2AD6" },
+ "⇙": { "codepoints": [8665], "characters": "\u21D9" },
+ "⤦": { "codepoints": [10534], "characters": "\u2926" },
+ "↙": { "codepoints": [8601], "characters": "\u2199" },
+ "↙": { "codepoints": [8601], "characters": "\u2199" },
+ "⤪": { "codepoints": [10538], "characters": "\u292A" },
+ "ß": { "codepoints": [223], "characters": "\u00DF" },
+ "ß": { "codepoints": [223], "characters": "\u00DF" },
+ "⌖": { "codepoints": [8982], "characters": "\u2316" },
+ "τ": { "codepoints": [964], "characters": "\u03C4" },
+ "⎴": { "codepoints": [9140], "characters": "\u23B4" },
+ "ť": { "codepoints": [357], "characters": "\u0165" },
+ "ţ": { "codepoints": [355], "characters": "\u0163" },
+ "т": { "codepoints": [1090], "characters": "\u0442" },
+ "⃛": { "codepoints": [8411], "characters": "\u20DB" },
+ "⌕": { "codepoints": [8981], "characters": "\u2315" },
+ "𝔱": { "codepoints": [120113], "characters": "\uD835\uDD31" },
+ "∴": { "codepoints": [8756], "characters": "\u2234" },
+ "∴": { "codepoints": [8756], "characters": "\u2234" },
+ "θ": { "codepoints": [952], "characters": "\u03B8" },
+ "ϑ": { "codepoints": [977], "characters": "\u03D1" },
+ "ϑ": { "codepoints": [977], "characters": "\u03D1" },
+ "≈": { "codepoints": [8776], "characters": "\u2248" },
+ "∼": { "codepoints": [8764], "characters": "\u223C" },
+ " ": { "codepoints": [8201], "characters": "\u2009" },
+ "≈": { "codepoints": [8776], "characters": "\u2248" },
+ "∼": { "codepoints": [8764], "characters": "\u223C" },
+ "þ": { "codepoints": [254], "characters": "\u00FE" },
+ "þ": { "codepoints": [254], "characters": "\u00FE" },
+ "˜": { "codepoints": [732], "characters": "\u02DC" },
+ "×": { "codepoints": [215], "characters": "\u00D7" },
+ "×": { "codepoints": [215], "characters": "\u00D7" },
+ "⊠": { "codepoints": [8864], "characters": "\u22A0" },
+ "⨱": { "codepoints": [10801], "characters": "\u2A31" },
+ "⨰": { "codepoints": [10800], "characters": "\u2A30" },
+ "∭": { "codepoints": [8749], "characters": "\u222D" },
+ "⤨": { "codepoints": [10536], "characters": "\u2928" },
+ "⊤": { "codepoints": [8868], "characters": "\u22A4" },
+ "⌶": { "codepoints": [9014], "characters": "\u2336" },
+ "⫱": { "codepoints": [10993], "characters": "\u2AF1" },
+ "𝕥": { "codepoints": [120165], "characters": "\uD835\uDD65" },
+ "⫚": { "codepoints": [10970], "characters": "\u2ADA" },
+ "⤩": { "codepoints": [10537], "characters": "\u2929" },
+ "‴": { "codepoints": [8244], "characters": "\u2034" },
+ "™": { "codepoints": [8482], "characters": "\u2122" },
+ "▵": { "codepoints": [9653], "characters": "\u25B5" },
+ "▿": { "codepoints": [9663], "characters": "\u25BF" },
+ "◃": { "codepoints": [9667], "characters": "\u25C3" },
+ "⊴": { "codepoints": [8884], "characters": "\u22B4" },
+ "≜": { "codepoints": [8796], "characters": "\u225C" },
+ "▹": { "codepoints": [9657], "characters": "\u25B9" },
+ "⊵": { "codepoints": [8885], "characters": "\u22B5" },
+ "◬": { "codepoints": [9708], "characters": "\u25EC" },
+ "≜": { "codepoints": [8796], "characters": "\u225C" },
+ "⨺": { "codepoints": [10810], "characters": "\u2A3A" },
+ "⨹": { "codepoints": [10809], "characters": "\u2A39" },
+ "⧍": { "codepoints": [10701], "characters": "\u29CD" },
+ "⨻": { "codepoints": [10811], "characters": "\u2A3B" },
+ "⏢": { "codepoints": [9186], "characters": "\u23E2" },
+ "𝓉": { "codepoints": [120009], "characters": "\uD835\uDCC9" },
+ "ц": { "codepoints": [1094], "characters": "\u0446" },
+ "ћ": { "codepoints": [1115], "characters": "\u045B" },
+ "ŧ": { "codepoints": [359], "characters": "\u0167" },
+ "≬": { "codepoints": [8812], "characters": "\u226C" },
+ "↞": { "codepoints": [8606], "characters": "\u219E" },
+ "↠": { "codepoints": [8608], "characters": "\u21A0" },
+ "⇑": { "codepoints": [8657], "characters": "\u21D1" },
+ "⥣": { "codepoints": [10595], "characters": "\u2963" },
+ "ú": { "codepoints": [250], "characters": "\u00FA" },
+ "ú": { "codepoints": [250], "characters": "\u00FA" },
+ "↑": { "codepoints": [8593], "characters": "\u2191" },
+ "ў": { "codepoints": [1118], "characters": "\u045E" },
+ "ŭ": { "codepoints": [365], "characters": "\u016D" },
+ "û": { "codepoints": [251], "characters": "\u00FB" },
+ "û": { "codepoints": [251], "characters": "\u00FB" },
+ "у": { "codepoints": [1091], "characters": "\u0443" },
+ "⇅": { "codepoints": [8645], "characters": "\u21C5" },
+ "ű": { "codepoints": [369], "characters": "\u0171" },
+ "⥮": { "codepoints": [10606], "characters": "\u296E" },
+ "⥾": { "codepoints": [10622], "characters": "\u297E" },
+ "𝔲": { "codepoints": [120114], "characters": "\uD835\uDD32" },
+ "ù": { "codepoints": [249], "characters": "\u00F9" },
+ "ù": { "codepoints": [249], "characters": "\u00F9" },
+ "↿": { "codepoints": [8639], "characters": "\u21BF" },
+ "↾": { "codepoints": [8638], "characters": "\u21BE" },
+ "▀": { "codepoints": [9600], "characters": "\u2580" },
+ "⌜": { "codepoints": [8988], "characters": "\u231C" },
+ "⌜": { "codepoints": [8988], "characters": "\u231C" },
+ "⌏": { "codepoints": [8975], "characters": "\u230F" },
+ "◸": { "codepoints": [9720], "characters": "\u25F8" },
+ "ū": { "codepoints": [363], "characters": "\u016B" },
+ "¨": { "codepoints": [168], "characters": "\u00A8" },
+ "¨": { "codepoints": [168], "characters": "\u00A8" },
+ "ų": { "codepoints": [371], "characters": "\u0173" },
+ "𝕦": { "codepoints": [120166], "characters": "\uD835\uDD66" },
+ "↑": { "codepoints": [8593], "characters": "\u2191" },
+ "↕": { "codepoints": [8597], "characters": "\u2195" },
+ "↿": { "codepoints": [8639], "characters": "\u21BF" },
+ "↾": { "codepoints": [8638], "characters": "\u21BE" },
+ "⊎": { "codepoints": [8846], "characters": "\u228E" },
+ "υ": { "codepoints": [965], "characters": "\u03C5" },
+ "ϒ": { "codepoints": [978], "characters": "\u03D2" },
+ "υ": { "codepoints": [965], "characters": "\u03C5" },
+ "⇈": { "codepoints": [8648], "characters": "\u21C8" },
+ "⌝": { "codepoints": [8989], "characters": "\u231D" },
+ "⌝": { "codepoints": [8989], "characters": "\u231D" },
+ "⌎": { "codepoints": [8974], "characters": "\u230E" },
+ "ů": { "codepoints": [367], "characters": "\u016F" },
+ "◹": { "codepoints": [9721], "characters": "\u25F9" },
+ "𝓊": { "codepoints": [120010], "characters": "\uD835\uDCCA" },
+ "⋰": { "codepoints": [8944], "characters": "\u22F0" },
+ "ũ": { "codepoints": [361], "characters": "\u0169" },
+ "▵": { "codepoints": [9653], "characters": "\u25B5" },
+ "▴": { "codepoints": [9652], "characters": "\u25B4" },
+ "⇈": { "codepoints": [8648], "characters": "\u21C8" },
+ "ü": { "codepoints": [252], "characters": "\u00FC" },
+ "ü": { "codepoints": [252], "characters": "\u00FC" },
+ "⦧": { "codepoints": [10663], "characters": "\u29A7" },
+ "⇕": { "codepoints": [8661], "characters": "\u21D5" },
+ "⫨": { "codepoints": [10984], "characters": "\u2AE8" },
+ "⫩": { "codepoints": [10985], "characters": "\u2AE9" },
+ "⊨": { "codepoints": [8872], "characters": "\u22A8" },
+ "⦜": { "codepoints": [10652], "characters": "\u299C" },
+ "ϵ": { "codepoints": [1013], "characters": "\u03F5" },
+ "ϰ": { "codepoints": [1008], "characters": "\u03F0" },
+ "∅": { "codepoints": [8709], "characters": "\u2205" },
+ "ϕ": { "codepoints": [981], "characters": "\u03D5" },
+ "ϖ": { "codepoints": [982], "characters": "\u03D6" },
+ "∝": { "codepoints": [8733], "characters": "\u221D" },
+ "↕": { "codepoints": [8597], "characters": "\u2195" },
+ "ϱ": { "codepoints": [1009], "characters": "\u03F1" },
+ "ς": { "codepoints": [962], "characters": "\u03C2" },
+ "⊊︀": { "codepoints": [8842, 65024], "characters": "\u228A\uFE00" },
+ "⫋︀": { "codepoints": [10955, 65024], "characters": "\u2ACB\uFE00" },
+ "⊋︀": { "codepoints": [8843, 65024], "characters": "\u228B\uFE00" },
+ "⫌︀": { "codepoints": [10956, 65024], "characters": "\u2ACC\uFE00" },
+ "ϑ": { "codepoints": [977], "characters": "\u03D1" },
+ "⊲": { "codepoints": [8882], "characters": "\u22B2" },
+ "⊳": { "codepoints": [8883], "characters": "\u22B3" },
+ "в": { "codepoints": [1074], "characters": "\u0432" },
+ "⊢": { "codepoints": [8866], "characters": "\u22A2" },
+ "∨": { "codepoints": [8744], "characters": "\u2228" },
+ "⊻": { "codepoints": [8891], "characters": "\u22BB" },
+ "≚": { "codepoints": [8794], "characters": "\u225A" },
+ "⋮": { "codepoints": [8942], "characters": "\u22EE" },
+ "|": { "codepoints": [124], "characters": "\u007C" },
+ "|": { "codepoints": [124], "characters": "\u007C" },
+ "𝔳": { "codepoints": [120115], "characters": "\uD835\uDD33" },
+ "⊲": { "codepoints": [8882], "characters": "\u22B2" },
+ "⊂⃒": { "codepoints": [8834, 8402], "characters": "\u2282\u20D2" },
+ "⊃⃒": { "codepoints": [8835, 8402], "characters": "\u2283\u20D2" },
+ "𝕧": { "codepoints": [120167], "characters": "\uD835\uDD67" },
+ "∝": { "codepoints": [8733], "characters": "\u221D" },
+ "⊳": { "codepoints": [8883], "characters": "\u22B3" },
+ "𝓋": { "codepoints": [120011], "characters": "\uD835\uDCCB" },
+ "⫋︀": { "codepoints": [10955, 65024], "characters": "\u2ACB\uFE00" },
+ "⊊︀": { "codepoints": [8842, 65024], "characters": "\u228A\uFE00" },
+ "⫌︀": { "codepoints": [10956, 65024], "characters": "\u2ACC\uFE00" },
+ "⊋︀": { "codepoints": [8843, 65024], "characters": "\u228B\uFE00" },
+ "⦚": { "codepoints": [10650], "characters": "\u299A" },
+ "ŵ": { "codepoints": [373], "characters": "\u0175" },
+ "⩟": { "codepoints": [10847], "characters": "\u2A5F" },
+ "∧": { "codepoints": [8743], "characters": "\u2227" },
+ "≙": { "codepoints": [8793], "characters": "\u2259" },
+ "℘": { "codepoints": [8472], "characters": "\u2118" },
+ "𝔴": { "codepoints": [120116], "characters": "\uD835\uDD34" },
+ "𝕨": { "codepoints": [120168], "characters": "\uD835\uDD68" },
+ "℘": { "codepoints": [8472], "characters": "\u2118" },
+ "≀": { "codepoints": [8768], "characters": "\u2240" },
+ "≀": { "codepoints": [8768], "characters": "\u2240" },
+ "𝓌": { "codepoints": [120012], "characters": "\uD835\uDCCC" },
+ "⋂": { "codepoints": [8898], "characters": "\u22C2" },
+ "◯": { "codepoints": [9711], "characters": "\u25EF" },
+ "⋃": { "codepoints": [8899], "characters": "\u22C3" },
+ "▽": { "codepoints": [9661], "characters": "\u25BD" },
+ "𝔵": { "codepoints": [120117], "characters": "\uD835\uDD35" },
+ "⟺": { "codepoints": [10234], "characters": "\u27FA" },
+ "⟷": { "codepoints": [10231], "characters": "\u27F7" },
+ "ξ": { "codepoints": [958], "characters": "\u03BE" },
+ "⟸": { "codepoints": [10232], "characters": "\u27F8" },
+ "⟵": { "codepoints": [10229], "characters": "\u27F5" },
+ "⟼": { "codepoints": [10236], "characters": "\u27FC" },
+ "⋻": { "codepoints": [8955], "characters": "\u22FB" },
+ "⨀": { "codepoints": [10752], "characters": "\u2A00" },
+ "𝕩": { "codepoints": [120169], "characters": "\uD835\uDD69" },
+ "⨁": { "codepoints": [10753], "characters": "\u2A01" },
+ "⨂": { "codepoints": [10754], "characters": "\u2A02" },
+ "⟹": { "codepoints": [10233], "characters": "\u27F9" },
+ "⟶": { "codepoints": [10230], "characters": "\u27F6" },
+ "𝓍": { "codepoints": [120013], "characters": "\uD835\uDCCD" },
+ "⨆": { "codepoints": [10758], "characters": "\u2A06" },
+ "⨄": { "codepoints": [10756], "characters": "\u2A04" },
+ "△": { "codepoints": [9651], "characters": "\u25B3" },
+ "⋁": { "codepoints": [8897], "characters": "\u22C1" },
+ "⋀": { "codepoints": [8896], "characters": "\u22C0" },
+ "ý": { "codepoints": [253], "characters": "\u00FD" },
+ "ý": { "codepoints": [253], "characters": "\u00FD" },
+ "я": { "codepoints": [1103], "characters": "\u044F" },
+ "ŷ": { "codepoints": [375], "characters": "\u0177" },
+ "ы": { "codepoints": [1099], "characters": "\u044B" },
+ "¥": { "codepoints": [165], "characters": "\u00A5" },
+ "¥": { "codepoints": [165], "characters": "\u00A5" },
+ "𝔶": { "codepoints": [120118], "characters": "\uD835\uDD36" },
+ "ї": { "codepoints": [1111], "characters": "\u0457" },
+ "𝕪": { "codepoints": [120170], "characters": "\uD835\uDD6A" },
+ "𝓎": { "codepoints": [120014], "characters": "\uD835\uDCCE" },
+ "ю": { "codepoints": [1102], "characters": "\u044E" },
+ "ÿ": { "codepoints": [255], "characters": "\u00FF" },
+ "ÿ": { "codepoints": [255], "characters": "\u00FF" },
+ "ź": { "codepoints": [378], "characters": "\u017A" },
+ "ž": { "codepoints": [382], "characters": "\u017E" },
+ "з": { "codepoints": [1079], "characters": "\u0437" },
+ "ż": { "codepoints": [380], "characters": "\u017C" },
+ "ℨ": { "codepoints": [8488], "characters": "\u2128" },
+ "ζ": { "codepoints": [950], "characters": "\u03B6" },
+ "𝔷": { "codepoints": [120119], "characters": "\uD835\uDD37" },
+ "ж": { "codepoints": [1078], "characters": "\u0436" },
+ "⇝": { "codepoints": [8669], "characters": "\u21DD" },
+ "𝕫": { "codepoints": [120171], "characters": "\uD835\uDD6B" },
+ "𝓏": { "codepoints": [120015], "characters": "\uD835\uDCCF" },
+ "‍": { "codepoints": [8205], "characters": "\u200D" },
+ "‌": { "codepoints": [8204], "characters": "\u200C" }
+}
diff --git a/pkgs/markdown/tool/expected_output.dart b/pkgs/markdown/tool/expected_output.dart
new file mode 100644
index 0000000..aa7bab3
--- /dev/null
+++ b/pkgs/markdown/tool/expected_output.dart
@@ -0,0 +1,159 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io';
+
+import 'package:path/path.dart' as p;
+
+/// Parse and yield data cases (each a [DataCase]) from [path].
+Iterable<DataCase> dataCasesInFile({
+ required String path,
+ String? baseDir,
+}) sync* {
+ final file = p.basename(path).replaceFirst(RegExp(r'\..+$'), '');
+ baseDir ??= p.relative(p.dirname(path), from: p.dirname(p.dirname(path)));
+
+ // Explicitly create a File, in case the entry is a Link.
+ final lines = File(path).readAsLinesSync();
+
+ final frontMatter = StringBuffer();
+
+ var i = 0;
+
+ while (!lines[i].startsWith('>>>')) {
+ frontMatter.write('${lines[i++]}\n');
+ }
+
+ while (i < lines.length) {
+ var description = lines[i++].replaceFirst(RegExp(r'>>>\s*'), '').trim();
+ final skip = description.startsWith('skip:');
+ if (description == '') {
+ description = 'line ${i + 1}';
+ } else {
+ description = 'line ${i + 1}: $description';
+ }
+
+ final input = StringBuffer();
+ while (!lines[i].startsWith('<<<')) {
+ input.writeln(lines[i++]);
+ }
+
+ final expectedOutput = StringBuffer();
+ while (++i < lines.length && !lines[i].startsWith('>>>')) {
+ expectedOutput.writeln(lines[i]);
+ }
+
+ final dataCase = DataCase(
+ directory: baseDir,
+ file: file,
+ front_matter: frontMatter.toString(),
+ description: description,
+ skip: skip,
+ input: input.toString(),
+ expectedOutput: expectedOutput.toString(),
+ );
+ yield dataCase;
+ }
+}
+
+/// Parse and return data cases (each a [DataCase]) from [directory].
+///
+/// By default, only read data cases from files with a `.unit` extension. Data
+/// cases are read from files located immediately in [directory], or
+/// recursively, according to [recursive].
+Iterable<DataCase> _dataCases({
+ required String directory,
+ String extension = 'unit',
+ bool recursive = true,
+}) {
+ final entries =
+ Directory(directory).listSync(recursive: recursive, followLinks: false);
+ final results = <DataCase>[];
+ for (final entry in entries) {
+ if (!entry.path.endsWith(extension)) {
+ continue;
+ }
+
+ final relativeDir =
+ p.relative(p.dirname(entry.path), from: p.dirname(directory));
+
+ results.addAll(dataCasesInFile(path: entry.path, baseDir: relativeDir));
+ }
+
+ // The API makes no guarantees on order. This is just here for stability in
+ // tests.
+ results.sort((a, b) {
+ final compare = a.directory.compareTo(b.directory);
+ if (compare != 0) return compare;
+
+ return a.file.compareTo(b.file);
+ });
+ return results;
+}
+
+/// Parse and yield data cases (each a [DataCase]) from [testDirectory].
+///
+/// By default, only read data cases from files with a `.unit` extension. Data
+/// cases are read from files located immediately in [testDirectory], or
+/// recursively, according to [recursive].
+///
+/// The typical use case of this method is to declare a library at the top of a
+/// Dart test file, then reference the symbol with a pound sign. Example:
+///
+/// ```dart
+/// library my_package.test.this_test;
+///
+/// import 'package:expected_output/expected_output.dart';
+/// import 'package:test/test.dart';
+///
+/// void main() {
+/// for (final dataCase
+/// in dataCasesUnder(library: #my_package.test.this_test)) {
+/// // ...
+/// }
+/// }
+/// ```
+Iterable<DataCase> dataCasesUnder({
+ required String testDirectory,
+ String extension = 'unit',
+ bool recursive = true,
+}) sync* {
+ final directory = p.join(p.current, 'test', testDirectory);
+ for (final dataCase in _dataCases(
+ directory: directory,
+ extension: extension,
+ recursive: recursive,
+ )) {
+ yield dataCase;
+ }
+}
+
+/// All of the data pertaining to a particular test case, namely the [input] and
+/// [expectedOutput].
+class DataCase {
+ final String directory;
+ final String file;
+
+ // ignore: non_constant_identifier_names
+ final String front_matter;
+ final String description;
+ final bool skip;
+ final String input;
+ final String expectedOutput;
+
+ DataCase({
+ this.directory = '',
+ this.file = '',
+ // ignore: non_constant_identifier_names
+ this.front_matter = '',
+ this.description = '',
+ this.skip = false,
+ required this.input,
+ required this.expectedOutput,
+ });
+
+ /// A good standard description for `test()`, derived from the data directory,
+ /// the particular data file, and the test case description.
+ String get testDescription => [directory, file, description].join(' ');
+}
diff --git a/pkgs/markdown/tool/gfm_stats.json b/pkgs/markdown/tool/gfm_stats.json
new file mode 100644
index 0000000..93c0cab
--- /dev/null
+++ b/pkgs/markdown/tool/gfm_stats.json
@@ -0,0 +1,732 @@
+{
+ "ATX headings": {
+ "32": "strict",
+ "33": "strict",
+ "34": "strict",
+ "35": "strict",
+ "36": "strict",
+ "37": "strict",
+ "38": "strict",
+ "39": "strict",
+ "40": "strict",
+ "41": "strict",
+ "42": "strict",
+ "43": "strict",
+ "44": "strict",
+ "45": "strict",
+ "46": "strict",
+ "47": "strict",
+ "48": "strict",
+ "49": "strict"
+ },
+ "Autolinks": {
+ "602": "strict",
+ "603": "strict",
+ "604": "strict",
+ "605": "strict",
+ "606": "strict",
+ "607": "strict",
+ "608": "strict",
+ "609": "strict",
+ "610": "strict",
+ "611": "strict",
+ "612": "strict",
+ "613": "strict",
+ "614": "strict",
+ "615": "strict",
+ "616": "strict",
+ "617": "strict",
+ "618": "strict",
+ "619": "strict",
+ "620": "strict"
+ },
+ "Autolinks (extension)": {
+ "621": "strict",
+ "622": "strict",
+ "623": "strict",
+ "624": "strict",
+ "625": "strict",
+ "626": "strict",
+ "627": "strict",
+ "628": "strict",
+ "629": "strict",
+ "630": "strict",
+ "631": "strict"
+ },
+ "Backslash escapes": {
+ "308": "strict",
+ "309": "strict",
+ "310": "strict",
+ "311": "strict",
+ "312": "strict",
+ "313": "strict",
+ "314": "strict",
+ "315": "strict",
+ "316": "strict",
+ "317": "strict",
+ "318": "strict",
+ "319": "strict",
+ "320": "strict"
+ },
+ "Blank lines": {
+ "197": "strict"
+ },
+ "Block quotes": {
+ "206": "strict",
+ "207": "strict",
+ "208": "strict",
+ "209": "strict",
+ "210": "strict",
+ "211": "strict",
+ "212": "strict",
+ "213": "strict",
+ "214": "strict",
+ "215": "strict",
+ "216": "strict",
+ "217": "strict",
+ "218": "strict",
+ "219": "strict",
+ "220": "strict",
+ "221": "strict",
+ "222": "strict",
+ "223": "strict",
+ "224": "strict",
+ "225": "strict",
+ "226": "strict",
+ "227": "strict",
+ "228": "strict",
+ "229": "strict",
+ "230": "strict"
+ },
+ "Code spans": {
+ "338": "strict",
+ "339": "strict",
+ "340": "strict",
+ "341": "strict",
+ "342": "strict",
+ "343": "strict",
+ "344": "strict",
+ "345": "strict",
+ "346": "strict",
+ "347": "strict",
+ "348": "strict",
+ "349": "strict",
+ "350": "strict",
+ "351": "strict",
+ "352": "strict",
+ "353": "strict",
+ "354": "strict",
+ "355": "strict",
+ "356": "strict",
+ "357": "strict",
+ "358": "strict",
+ "359": "strict"
+ },
+ "Disallowed Raw HTML (extension)": {
+ "652": "loose"
+ },
+ "Emphasis and strong emphasis": {
+ "360": "strict",
+ "361": "strict",
+ "362": "strict",
+ "363": "strict",
+ "364": "strict",
+ "365": "strict",
+ "366": "strict",
+ "367": "strict",
+ "368": "strict",
+ "369": "strict",
+ "370": "strict",
+ "371": "strict",
+ "372": "strict",
+ "373": "strict",
+ "374": "strict",
+ "375": "strict",
+ "376": "strict",
+ "377": "strict",
+ "378": "strict",
+ "379": "strict",
+ "380": "strict",
+ "381": "strict",
+ "382": "strict",
+ "383": "strict",
+ "384": "strict",
+ "385": "strict",
+ "386": "strict",
+ "387": "strict",
+ "388": "strict",
+ "389": "strict",
+ "390": "strict",
+ "391": "strict",
+ "392": "strict",
+ "393": "strict",
+ "394": "strict",
+ "395": "strict",
+ "396": "strict",
+ "397": "strict",
+ "398": "strict",
+ "399": "strict",
+ "400": "strict",
+ "401": "strict",
+ "402": "strict",
+ "403": "strict",
+ "404": "strict",
+ "405": "strict",
+ "406": "strict",
+ "407": "strict",
+ "408": "strict",
+ "409": "strict",
+ "410": "strict",
+ "411": "strict",
+ "412": "strict",
+ "413": "strict",
+ "414": "strict",
+ "415": "strict",
+ "416": "strict",
+ "417": "strict",
+ "418": "strict",
+ "419": "strict",
+ "420": "strict",
+ "421": "strict",
+ "422": "strict",
+ "423": "strict",
+ "424": "strict",
+ "425": "strict",
+ "426": "strict",
+ "427": "strict",
+ "428": "strict",
+ "429": "strict",
+ "430": "strict",
+ "431": "strict",
+ "432": "strict",
+ "433": "strict",
+ "434": "strict",
+ "435": "strict",
+ "436": "strict",
+ "437": "strict",
+ "438": "strict",
+ "439": "strict",
+ "440": "strict",
+ "441": "strict",
+ "442": "strict",
+ "443": "strict",
+ "444": "strict",
+ "445": "strict",
+ "446": "strict",
+ "447": "strict",
+ "448": "strict",
+ "449": "strict",
+ "450": "strict",
+ "451": "strict",
+ "452": "strict",
+ "453": "strict",
+ "454": "strict",
+ "455": "strict",
+ "456": "strict",
+ "457": "strict",
+ "458": "strict",
+ "459": "strict",
+ "460": "strict",
+ "461": "strict",
+ "462": "strict",
+ "463": "strict",
+ "464": "strict",
+ "465": "strict",
+ "466": "strict",
+ "467": "strict",
+ "468": "strict",
+ "469": "strict",
+ "470": "strict",
+ "471": "strict",
+ "472": "strict",
+ "473": "strict",
+ "474": "strict",
+ "475": "strict",
+ "476": "strict",
+ "477": "strict",
+ "478": "strict",
+ "479": "strict",
+ "480": "strict",
+ "481": "strict",
+ "482": "strict",
+ "483": "strict",
+ "484": "strict",
+ "485": "strict",
+ "486": "strict",
+ "487": "strict",
+ "488": "strict",
+ "489": "strict",
+ "490": "strict"
+ },
+ "Entity and numeric character references": {
+ "321": "loose",
+ "322": "strict",
+ "323": "strict",
+ "324": "strict",
+ "325": "strict",
+ "326": "strict",
+ "327": "strict",
+ "328": "strict",
+ "329": "strict",
+ "330": "strict",
+ "331": "strict",
+ "332": "strict",
+ "333": "strict",
+ "334": "strict",
+ "335": "strict",
+ "336": "loose",
+ "337": "strict"
+ },
+ "Fenced code blocks": {
+ "89": "strict",
+ "90": "strict",
+ "91": "strict",
+ "92": "strict",
+ "93": "strict",
+ "94": "strict",
+ "95": "strict",
+ "96": "strict",
+ "97": "strict",
+ "98": "strict",
+ "99": "strict",
+ "100": "strict",
+ "101": "strict",
+ "102": "strict",
+ "103": "strict",
+ "104": "strict",
+ "105": "strict",
+ "106": "strict",
+ "107": "strict",
+ "108": "strict",
+ "109": "strict",
+ "110": "strict",
+ "111": "strict",
+ "112": "strict",
+ "113": "strict",
+ "114": "strict",
+ "115": "strict",
+ "116": "strict",
+ "117": "strict"
+ },
+ "Hard line breaks": {
+ "653": "strict",
+ "654": "strict",
+ "655": "strict",
+ "656": "strict",
+ "657": "strict",
+ "658": "strict",
+ "659": "strict",
+ "660": "strict",
+ "661": "strict",
+ "662": "strict",
+ "663": "strict",
+ "664": "strict",
+ "665": "strict",
+ "666": "strict",
+ "667": "strict"
+ },
+ "HTML blocks": {
+ "118": "strict",
+ "119": "strict",
+ "120": "strict",
+ "121": "strict",
+ "122": "strict",
+ "123": "strict",
+ "124": "strict",
+ "125": "strict",
+ "126": "strict",
+ "127": "strict",
+ "128": "strict",
+ "129": "strict",
+ "130": "strict",
+ "131": "strict",
+ "132": "strict",
+ "133": "strict",
+ "134": "strict",
+ "135": "strict",
+ "136": "strict",
+ "137": "strict",
+ "138": "strict",
+ "139": "strict",
+ "140": "strict",
+ "141": "strict",
+ "142": "strict",
+ "143": "strict",
+ "144": "strict",
+ "145": "strict",
+ "146": "strict",
+ "147": "strict",
+ "148": "strict",
+ "149": "strict",
+ "150": "strict",
+ "151": "strict",
+ "152": "strict",
+ "153": "strict",
+ "154": "strict",
+ "155": "strict",
+ "156": "strict",
+ "157": "strict",
+ "158": "strict",
+ "159": "strict",
+ "160": "strict"
+ },
+ "Images": {
+ "580": "strict",
+ "581": "strict",
+ "582": "strict",
+ "583": "strict",
+ "584": "strict",
+ "585": "strict",
+ "586": "strict",
+ "587": "strict",
+ "588": "strict",
+ "589": "strict",
+ "590": "strict",
+ "591": "strict",
+ "592": "strict",
+ "593": "strict",
+ "594": "strict",
+ "595": "strict",
+ "596": "strict",
+ "597": "strict",
+ "598": "strict",
+ "599": "strict",
+ "600": "strict",
+ "601": "strict"
+ },
+ "Indented code blocks": {
+ "77": "strict",
+ "78": "strict",
+ "79": "strict",
+ "80": "strict",
+ "81": "strict",
+ "82": "strict",
+ "83": "strict",
+ "84": "strict",
+ "85": "strict",
+ "86": "strict",
+ "87": "strict",
+ "88": "strict"
+ },
+ "Inlines": {
+ "307": "strict"
+ },
+ "Link reference definitions": {
+ "161": "strict",
+ "162": "strict",
+ "163": "strict",
+ "164": "strict",
+ "165": "strict",
+ "166": "strict",
+ "167": "strict",
+ "168": "strict",
+ "169": "strict",
+ "170": "strict",
+ "171": "strict",
+ "172": "strict",
+ "173": "strict",
+ "174": "strict",
+ "175": "strict",
+ "176": "loose",
+ "177": "strict",
+ "178": "strict",
+ "179": "strict",
+ "180": "strict",
+ "181": "strict",
+ "182": "strict",
+ "183": "strict",
+ "184": "strict",
+ "185": "strict",
+ "186": "strict",
+ "187": "strict",
+ "188": "loose"
+ },
+ "Links": {
+ "493": "strict",
+ "494": "strict",
+ "495": "strict",
+ "496": "strict",
+ "497": "strict",
+ "498": "strict",
+ "499": "strict",
+ "500": "strict",
+ "501": "strict",
+ "502": "strict",
+ "503": "strict",
+ "504": "strict",
+ "505": "strict",
+ "506": "strict",
+ "507": "strict",
+ "508": "strict",
+ "509": "strict",
+ "510": "strict",
+ "511": "strict",
+ "512": "strict",
+ "513": "strict",
+ "514": "strict",
+ "515": "strict",
+ "516": "strict",
+ "517": "strict",
+ "518": "strict",
+ "519": "strict",
+ "520": "strict",
+ "521": "strict",
+ "522": "strict",
+ "523": "strict",
+ "524": "strict",
+ "525": "strict",
+ "526": "strict",
+ "527": "strict",
+ "528": "strict",
+ "529": "strict",
+ "530": "strict",
+ "531": "strict",
+ "532": "strict",
+ "533": "strict",
+ "534": "strict",
+ "535": "strict",
+ "536": "strict",
+ "537": "strict",
+ "538": "strict",
+ "539": "strict",
+ "540": "strict",
+ "541": "strict",
+ "542": "strict",
+ "543": "strict",
+ "544": "strict",
+ "545": "strict",
+ "546": "strict",
+ "547": "strict",
+ "548": "strict",
+ "549": "strict",
+ "550": "strict",
+ "551": "strict",
+ "552": "strict",
+ "553": "strict",
+ "554": "strict",
+ "555": "strict",
+ "556": "strict",
+ "557": "strict",
+ "558": "strict",
+ "559": "strict",
+ "560": "strict",
+ "561": "strict",
+ "562": "strict",
+ "563": "strict",
+ "564": "strict",
+ "565": "strict",
+ "566": "strict",
+ "567": "strict",
+ "568": "strict",
+ "569": "strict",
+ "570": "strict",
+ "571": "strict",
+ "572": "strict",
+ "573": "strict",
+ "574": "strict",
+ "575": "strict",
+ "576": "strict",
+ "577": "strict",
+ "578": "strict",
+ "579": "strict"
+ },
+ "List items": {
+ "231": "strict",
+ "232": "strict",
+ "233": "strict",
+ "234": "strict",
+ "235": "strict",
+ "236": "strict",
+ "237": "strict",
+ "238": "strict",
+ "239": "strict",
+ "240": "strict",
+ "241": "strict",
+ "242": "strict",
+ "243": "strict",
+ "244": "strict",
+ "245": "strict",
+ "246": "strict",
+ "247": "strict",
+ "248": "strict",
+ "249": "strict",
+ "250": "strict",
+ "251": "strict",
+ "252": "strict",
+ "253": "strict",
+ "254": "strict",
+ "255": "strict",
+ "256": "strict",
+ "257": "strict",
+ "258": "strict",
+ "259": "strict",
+ "260": "strict",
+ "261": "strict",
+ "262": "strict",
+ "263": "strict",
+ "264": "strict",
+ "265": "strict",
+ "266": "strict",
+ "267": "strict",
+ "268": "strict",
+ "269": "strict",
+ "270": "strict",
+ "271": "strict",
+ "272": "strict",
+ "273": "strict",
+ "274": "strict",
+ "275": "strict",
+ "276": "strict",
+ "277": "strict",
+ "278": "strict"
+ },
+ "Lists": {
+ "281": "strict",
+ "282": "strict",
+ "283": "strict",
+ "284": "strict",
+ "285": "strict",
+ "286": "strict",
+ "287": "strict",
+ "288": "strict",
+ "289": "strict",
+ "290": "strict",
+ "291": "strict",
+ "292": "strict",
+ "293": "strict",
+ "294": "strict",
+ "295": "strict",
+ "296": "strict",
+ "297": "strict",
+ "298": "strict",
+ "299": "strict",
+ "300": "strict",
+ "301": "strict",
+ "302": "strict",
+ "303": "strict",
+ "304": "strict",
+ "305": "strict",
+ "306": "strict"
+ },
+ "Paragraphs": {
+ "189": "strict",
+ "190": "strict",
+ "191": "strict",
+ "192": "strict",
+ "193": "strict",
+ "194": "strict",
+ "195": "strict",
+ "196": "strict"
+ },
+ "Precedence": {
+ "12": "strict"
+ },
+ "Raw HTML": {
+ "632": "strict",
+ "633": "strict",
+ "634": "strict",
+ "635": "strict",
+ "636": "strict",
+ "637": "strict",
+ "638": "strict",
+ "639": "strict",
+ "640": "strict",
+ "641": "strict",
+ "642": "strict",
+ "643": "strict",
+ "644": "loose",
+ "645": "loose",
+ "646": "strict",
+ "647": "strict",
+ "648": "strict",
+ "649": "strict",
+ "650": "strict",
+ "651": "strict"
+ },
+ "Setext headings": {
+ "50": "strict",
+ "51": "strict",
+ "52": "loose",
+ "53": "strict",
+ "54": "loose",
+ "55": "strict",
+ "56": "strict",
+ "57": "strict",
+ "58": "strict",
+ "59": "strict",
+ "60": "strict",
+ "61": "strict",
+ "62": "strict",
+ "63": "strict",
+ "64": "strict",
+ "65": "strict",
+ "66": "strict",
+ "67": "strict",
+ "68": "strict",
+ "69": "strict",
+ "70": "strict",
+ "71": "strict",
+ "72": "strict",
+ "73": "strict",
+ "74": "strict",
+ "75": "strict",
+ "76": "strict"
+ },
+ "Soft line breaks": {
+ "668": "strict",
+ "669": "strict"
+ },
+ "Strikethrough (extension)": {
+ "491": "strict",
+ "492": "strict"
+ },
+ "Tables (extension)": {
+ "198": "strict",
+ "199": "strict",
+ "200": "strict",
+ "201": "strict",
+ "202": "strict",
+ "203": "strict",
+ "204": "strict",
+ "205": "strict"
+ },
+ "Tabs": {
+ "1": "strict",
+ "2": "strict",
+ "3": "strict",
+ "4": "strict",
+ "5": "strict",
+ "6": "loose",
+ "7": "strict",
+ "8": "strict",
+ "9": "strict",
+ "10": "strict",
+ "11": "strict"
+ },
+ "Textual content": {
+ "670": "strict",
+ "671": "strict",
+ "672": "strict"
+ },
+ "Thematic breaks": {
+ "13": "strict",
+ "14": "strict",
+ "15": "strict",
+ "16": "strict",
+ "17": "strict",
+ "18": "strict",
+ "19": "strict",
+ "20": "strict",
+ "21": "strict",
+ "22": "strict",
+ "23": "strict",
+ "24": "strict",
+ "25": "strict",
+ "26": "strict",
+ "27": "strict",
+ "28": "strict",
+ "29": "strict",
+ "30": "strict",
+ "31": "strict"
+ }
+}
diff --git a/pkgs/markdown/tool/gfm_stats.txt b/pkgs/markdown/tool/gfm_stats.txt
new file mode 100644
index 0000000..06e240b
--- /dev/null
+++ b/pkgs/markdown/tool/gfm_stats.txt
@@ -0,0 +1,32 @@
+ 18 of 18 – 100.0% ATX headings
+ 19 of 19 – 100.0% Autolinks
+ 11 of 11 – 100.0% Autolinks (extension)
+ 13 of 13 – 100.0% Backslash escapes
+ 1 of 1 – 100.0% Blank lines
+ 25 of 25 – 100.0% Block quotes
+ 22 of 22 – 100.0% Code spans
+ 1 of 1 – 100.0% Disallowed Raw HTML (extension)
+ 131 of 131 – 100.0% Emphasis and strong emphasis
+ 17 of 17 – 100.0% Entity and numeric character references
+ 29 of 29 – 100.0% Fenced code blocks
+ 15 of 15 – 100.0% Hard line breaks
+ 43 of 43 – 100.0% HTML blocks
+ 22 of 22 – 100.0% Images
+ 12 of 12 – 100.0% Indented code blocks
+ 1 of 1 – 100.0% Inlines
+ 28 of 28 – 100.0% Link reference definitions
+ 87 of 87 – 100.0% Links
+ 48 of 48 – 100.0% List items
+ 26 of 26 – 100.0% Lists
+ 8 of 8 – 100.0% Paragraphs
+ 1 of 1 – 100.0% Precedence
+ 20 of 20 – 100.0% Raw HTML
+ 27 of 27 – 100.0% Setext headings
+ 2 of 2 – 100.0% Soft line breaks
+ 2 of 2 – 100.0% Strikethrough (extension)
+ 8 of 8 – 100.0% Tables (extension)
+ 11 of 11 – 100.0% Tabs
+ 3 of 3 – 100.0% Textual content
+ 19 of 19 – 100.0% Thematic breaks
+ 670 of 670 – 100.0% TOTAL
+ 660 of 670 – 98.5% TOTAL Strict
diff --git a/pkgs/markdown/tool/gfm_tests.json b/pkgs/markdown/tool/gfm_tests.json
new file mode 100644
index 0000000..e5e849c
--- /dev/null
+++ b/pkgs/markdown/tool/gfm_tests.json
@@ -0,0 +1,6076 @@
+[
+ {
+ "markdown": "\tfoo\tbaz\t\tbim\n",
+ "html": "<pre><code>foo\tbaz\t\tbim\n</code></pre>\n",
+ "example": 1,
+ "start_line": 368,
+ "end_line": 373,
+ "section": "Tabs",
+ "extensions": []
+ },
+ {
+ "markdown": " \tfoo\tbaz\t\tbim\n",
+ "html": "<pre><code>foo\tbaz\t\tbim\n</code></pre>\n",
+ "example": 2,
+ "start_line": 375,
+ "end_line": 380,
+ "section": "Tabs",
+ "extensions": []
+ },
+ {
+ "markdown": " a\ta\n \u1f50\ta\n",
+ "html": "<pre><code>a\ta\n\u1f50\ta\n</code></pre>\n",
+ "example": 3,
+ "start_line": 382,
+ "end_line": 389,
+ "section": "Tabs",
+ "extensions": []
+ },
+ {
+ "markdown": " - foo\n\n\tbar\n",
+ "html": "<ul>\n<li>\n<p>foo</p>\n<p>bar</p>\n</li>\n</ul>\n",
+ "example": 4,
+ "start_line": 395,
+ "end_line": 406,
+ "section": "Tabs",
+ "extensions": []
+ },
+ {
+ "markdown": "- foo\n\n\t\tbar\n",
+ "html": "<ul>\n<li>\n<p>foo</p>\n<pre><code> bar\n</code></pre>\n</li>\n</ul>\n",
+ "example": 5,
+ "start_line": 408,
+ "end_line": 420,
+ "section": "Tabs",
+ "extensions": []
+ },
+ {
+ "markdown": ">\t\tfoo\n",
+ "html": "<blockquote>\n<pre><code> foo\n</code></pre>\n</blockquote>\n",
+ "example": 6,
+ "start_line": 431,
+ "end_line": 438,
+ "section": "Tabs",
+ "extensions": []
+ },
+ {
+ "markdown": "-\t\tfoo\n",
+ "html": "<ul>\n<li>\n<pre><code> foo\n</code></pre>\n</li>\n</ul>\n",
+ "example": 7,
+ "start_line": 440,
+ "end_line": 449,
+ "section": "Tabs",
+ "extensions": []
+ },
+ {
+ "markdown": " foo\n\tbar\n",
+ "html": "<pre><code>foo\nbar\n</code></pre>\n",
+ "example": 8,
+ "start_line": 452,
+ "end_line": 459,
+ "section": "Tabs",
+ "extensions": []
+ },
+ {
+ "markdown": " - foo\n - bar\n\t - baz\n",
+ "html": "<ul>\n<li>foo\n<ul>\n<li>bar\n<ul>\n<li>baz</li>\n</ul>\n</li>\n</ul>\n</li>\n</ul>\n",
+ "example": 9,
+ "start_line": 461,
+ "end_line": 477,
+ "section": "Tabs",
+ "extensions": []
+ },
+ {
+ "markdown": "#\tFoo\n",
+ "html": "<h1>Foo</h1>\n",
+ "example": 10,
+ "start_line": 479,
+ "end_line": 483,
+ "section": "Tabs",
+ "extensions": []
+ },
+ {
+ "markdown": "*\t*\t*\t\n",
+ "html": "<hr />\n",
+ "example": 11,
+ "start_line": 485,
+ "end_line": 489,
+ "section": "Tabs",
+ "extensions": []
+ },
+ {
+ "markdown": "- `one\n- two`\n",
+ "html": "<ul>\n<li>`one</li>\n<li>two`</li>\n</ul>\n",
+ "example": 12,
+ "start_line": 512,
+ "end_line": 520,
+ "section": "Precedence",
+ "extensions": []
+ },
+ {
+ "markdown": "***\n---\n___\n",
+ "html": "<hr />\n<hr />\n<hr />\n",
+ "example": 13,
+ "start_line": 551,
+ "end_line": 559,
+ "section": "Thematic breaks",
+ "extensions": []
+ },
+ {
+ "markdown": "+++\n",
+ "html": "<p>+++</p>\n",
+ "example": 14,
+ "start_line": 564,
+ "end_line": 568,
+ "section": "Thematic breaks",
+ "extensions": []
+ },
+ {
+ "markdown": "===\n",
+ "html": "<p>===</p>\n",
+ "example": 15,
+ "start_line": 571,
+ "end_line": 575,
+ "section": "Thematic breaks",
+ "extensions": []
+ },
+ {
+ "markdown": "--\n**\n__\n",
+ "html": "<p>--\n**\n__</p>\n",
+ "example": 16,
+ "start_line": 580,
+ "end_line": 588,
+ "section": "Thematic breaks",
+ "extensions": []
+ },
+ {
+ "markdown": " ***\n ***\n ***\n",
+ "html": "<hr />\n<hr />\n<hr />\n",
+ "example": 17,
+ "start_line": 593,
+ "end_line": 601,
+ "section": "Thematic breaks",
+ "extensions": []
+ },
+ {
+ "markdown": " ***\n",
+ "html": "<pre><code>***\n</code></pre>\n",
+ "example": 18,
+ "start_line": 606,
+ "end_line": 611,
+ "section": "Thematic breaks",
+ "extensions": []
+ },
+ {
+ "markdown": "Foo\n ***\n",
+ "html": "<p>Foo\n***</p>\n",
+ "example": 19,
+ "start_line": 614,
+ "end_line": 620,
+ "section": "Thematic breaks",
+ "extensions": []
+ },
+ {
+ "markdown": "_____________________________________\n",
+ "html": "<hr />\n",
+ "example": 20,
+ "start_line": 625,
+ "end_line": 629,
+ "section": "Thematic breaks",
+ "extensions": []
+ },
+ {
+ "markdown": " - - -\n",
+ "html": "<hr />\n",
+ "example": 21,
+ "start_line": 634,
+ "end_line": 638,
+ "section": "Thematic breaks",
+ "extensions": []
+ },
+ {
+ "markdown": " ** * ** * ** * **\n",
+ "html": "<hr />\n",
+ "example": 22,
+ "start_line": 641,
+ "end_line": 645,
+ "section": "Thematic breaks",
+ "extensions": []
+ },
+ {
+ "markdown": "- - - -\n",
+ "html": "<hr />\n",
+ "example": 23,
+ "start_line": 648,
+ "end_line": 652,
+ "section": "Thematic breaks",
+ "extensions": []
+ },
+ {
+ "markdown": "- - - - \n",
+ "html": "<hr />\n",
+ "example": 24,
+ "start_line": 657,
+ "end_line": 661,
+ "section": "Thematic breaks",
+ "extensions": []
+ },
+ {
+ "markdown": "_ _ _ _ a\n\na------\n\n---a---\n",
+ "html": "<p>_ _ _ _ a</p>\n<p>a------</p>\n<p>---a---</p>\n",
+ "example": 25,
+ "start_line": 666,
+ "end_line": 676,
+ "section": "Thematic breaks",
+ "extensions": []
+ },
+ {
+ "markdown": " *-*\n",
+ "html": "<p><em>-</em></p>\n",
+ "example": 26,
+ "start_line": 682,
+ "end_line": 686,
+ "section": "Thematic breaks",
+ "extensions": []
+ },
+ {
+ "markdown": "- foo\n***\n- bar\n",
+ "html": "<ul>\n<li>foo</li>\n</ul>\n<hr />\n<ul>\n<li>bar</li>\n</ul>\n",
+ "example": 27,
+ "start_line": 691,
+ "end_line": 703,
+ "section": "Thematic breaks",
+ "extensions": []
+ },
+ {
+ "markdown": "Foo\n***\nbar\n",
+ "html": "<p>Foo</p>\n<hr />\n<p>bar</p>\n",
+ "example": 28,
+ "start_line": 708,
+ "end_line": 716,
+ "section": "Thematic breaks",
+ "extensions": []
+ },
+ {
+ "markdown": "Foo\n---\nbar\n",
+ "html": "<h2>Foo</h2>\n<p>bar</p>\n",
+ "example": 29,
+ "start_line": 725,
+ "end_line": 732,
+ "section": "Thematic breaks",
+ "extensions": []
+ },
+ {
+ "markdown": "* Foo\n* * *\n* Bar\n",
+ "html": "<ul>\n<li>Foo</li>\n</ul>\n<hr />\n<ul>\n<li>Bar</li>\n</ul>\n",
+ "example": 30,
+ "start_line": 738,
+ "end_line": 750,
+ "section": "Thematic breaks",
+ "extensions": []
+ },
+ {
+ "markdown": "- Foo\n- * * *\n",
+ "html": "<ul>\n<li>Foo</li>\n<li>\n<hr />\n</li>\n</ul>\n",
+ "example": 31,
+ "start_line": 755,
+ "end_line": 765,
+ "section": "Thematic breaks",
+ "extensions": []
+ },
+ {
+ "markdown": "# foo\n## foo\n### foo\n#### foo\n##### foo\n###### foo\n",
+ "html": "<h1>foo</h1>\n<h2>foo</h2>\n<h3>foo</h3>\n<h4>foo</h4>\n<h5>foo</h5>\n<h6>foo</h6>\n",
+ "example": 32,
+ "start_line": 784,
+ "end_line": 798,
+ "section": "ATX headings",
+ "extensions": []
+ },
+ {
+ "markdown": "####### foo\n",
+ "html": "<p>####### foo</p>\n",
+ "example": 33,
+ "start_line": 803,
+ "end_line": 807,
+ "section": "ATX headings",
+ "extensions": []
+ },
+ {
+ "markdown": "#5 bolt\n\n#hashtag\n",
+ "html": "<p>#5 bolt</p>\n<p>#hashtag</p>\n",
+ "example": 34,
+ "start_line": 818,
+ "end_line": 825,
+ "section": "ATX headings",
+ "extensions": []
+ },
+ {
+ "markdown": "\\## foo\n",
+ "html": "<p>## foo</p>\n",
+ "example": 35,
+ "start_line": 830,
+ "end_line": 834,
+ "section": "ATX headings",
+ "extensions": []
+ },
+ {
+ "markdown": "# foo *bar* \\*baz\\*\n",
+ "html": "<h1>foo <em>bar</em> *baz*</h1>\n",
+ "example": 36,
+ "start_line": 839,
+ "end_line": 843,
+ "section": "ATX headings",
+ "extensions": []
+ },
+ {
+ "markdown": "# foo \n",
+ "html": "<h1>foo</h1>\n",
+ "example": 37,
+ "start_line": 848,
+ "end_line": 852,
+ "section": "ATX headings",
+ "extensions": []
+ },
+ {
+ "markdown": " ### foo\n ## foo\n # foo\n",
+ "html": "<h3>foo</h3>\n<h2>foo</h2>\n<h1>foo</h1>\n",
+ "example": 38,
+ "start_line": 857,
+ "end_line": 865,
+ "section": "ATX headings",
+ "extensions": []
+ },
+ {
+ "markdown": " # foo\n",
+ "html": "<pre><code># foo\n</code></pre>\n",
+ "example": 39,
+ "start_line": 870,
+ "end_line": 875,
+ "section": "ATX headings",
+ "extensions": []
+ },
+ {
+ "markdown": "foo\n # bar\n",
+ "html": "<p>foo\n# bar</p>\n",
+ "example": 40,
+ "start_line": 878,
+ "end_line": 884,
+ "section": "ATX headings",
+ "extensions": []
+ },
+ {
+ "markdown": "## foo ##\n ### bar ###\n",
+ "html": "<h2>foo</h2>\n<h3>bar</h3>\n",
+ "example": 41,
+ "start_line": 889,
+ "end_line": 895,
+ "section": "ATX headings",
+ "extensions": []
+ },
+ {
+ "markdown": "# foo ##################################\n##### foo ##\n",
+ "html": "<h1>foo</h1>\n<h5>foo</h5>\n",
+ "example": 42,
+ "start_line": 900,
+ "end_line": 906,
+ "section": "ATX headings",
+ "extensions": []
+ },
+ {
+ "markdown": "### foo ### \n",
+ "html": "<h3>foo</h3>\n",
+ "example": 43,
+ "start_line": 911,
+ "end_line": 915,
+ "section": "ATX headings",
+ "extensions": []
+ },
+ {
+ "markdown": "### foo ### b\n",
+ "html": "<h3>foo ### b</h3>\n",
+ "example": 44,
+ "start_line": 922,
+ "end_line": 926,
+ "section": "ATX headings",
+ "extensions": []
+ },
+ {
+ "markdown": "# foo#\n",
+ "html": "<h1>foo#</h1>\n",
+ "example": 45,
+ "start_line": 931,
+ "end_line": 935,
+ "section": "ATX headings",
+ "extensions": []
+ },
+ {
+ "markdown": "### foo \\###\n## foo #\\##\n# foo \\#\n",
+ "html": "<h3>foo ###</h3>\n<h2>foo ###</h2>\n<h1>foo #</h1>\n",
+ "example": 46,
+ "start_line": 941,
+ "end_line": 949,
+ "section": "ATX headings",
+ "extensions": []
+ },
+ {
+ "markdown": "****\n## foo\n****\n",
+ "html": "<hr />\n<h2>foo</h2>\n<hr />\n",
+ "example": 47,
+ "start_line": 955,
+ "end_line": 963,
+ "section": "ATX headings",
+ "extensions": []
+ },
+ {
+ "markdown": "Foo bar\n# baz\nBar foo\n",
+ "html": "<p>Foo bar</p>\n<h1>baz</h1>\n<p>Bar foo</p>\n",
+ "example": 48,
+ "start_line": 966,
+ "end_line": 974,
+ "section": "ATX headings",
+ "extensions": []
+ },
+ {
+ "markdown": "## \n#\n### ###\n",
+ "html": "<h2></h2>\n<h1></h1>\n<h3></h3>\n",
+ "example": 49,
+ "start_line": 979,
+ "end_line": 987,
+ "section": "ATX headings",
+ "extensions": []
+ },
+ {
+ "markdown": "Foo *bar*\n=========\n\nFoo *bar*\n---------\n",
+ "html": "<h1>Foo <em>bar</em></h1>\n<h2>Foo <em>bar</em></h2>\n",
+ "example": 50,
+ "start_line": 1019,
+ "end_line": 1028,
+ "section": "Setext headings",
+ "extensions": []
+ },
+ {
+ "markdown": "Foo *bar\nbaz*\n====\n",
+ "html": "<h1>Foo <em>bar\nbaz</em></h1>\n",
+ "example": 51,
+ "start_line": 1033,
+ "end_line": 1040,
+ "section": "Setext headings",
+ "extensions": []
+ },
+ {
+ "markdown": " Foo *bar\nbaz*\t\n====\n",
+ "html": "<h1>Foo <em>bar\nbaz</em></h1>\n",
+ "example": 52,
+ "start_line": 1047,
+ "end_line": 1054,
+ "section": "Setext headings",
+ "extensions": []
+ },
+ {
+ "markdown": "Foo\n-------------------------\n\nFoo\n=\n",
+ "html": "<h2>Foo</h2>\n<h1>Foo</h1>\n",
+ "example": 53,
+ "start_line": 1059,
+ "end_line": 1068,
+ "section": "Setext headings",
+ "extensions": []
+ },
+ {
+ "markdown": " Foo\n---\n\n Foo\n-----\n\n Foo\n ===\n",
+ "html": "<h2>Foo</h2>\n<h2>Foo</h2>\n<h1>Foo</h1>\n",
+ "example": 54,
+ "start_line": 1074,
+ "end_line": 1087,
+ "section": "Setext headings",
+ "extensions": []
+ },
+ {
+ "markdown": " Foo\n ---\n\n Foo\n---\n",
+ "html": "<pre><code>Foo\n---\n\nFoo\n</code></pre>\n<hr />\n",
+ "example": 55,
+ "start_line": 1092,
+ "end_line": 1105,
+ "section": "Setext headings",
+ "extensions": []
+ },
+ {
+ "markdown": "Foo\n ---- \n",
+ "html": "<h2>Foo</h2>\n",
+ "example": 56,
+ "start_line": 1111,
+ "end_line": 1116,
+ "section": "Setext headings",
+ "extensions": []
+ },
+ {
+ "markdown": "Foo\n ---\n",
+ "html": "<p>Foo\n---</p>\n",
+ "example": 57,
+ "start_line": 1121,
+ "end_line": 1127,
+ "section": "Setext headings",
+ "extensions": []
+ },
+ {
+ "markdown": "Foo\n= =\n\nFoo\n--- -\n",
+ "html": "<p>Foo\n= =</p>\n<p>Foo</p>\n<hr />\n",
+ "example": 58,
+ "start_line": 1132,
+ "end_line": 1143,
+ "section": "Setext headings",
+ "extensions": []
+ },
+ {
+ "markdown": "Foo \n-----\n",
+ "html": "<h2>Foo</h2>\n",
+ "example": 59,
+ "start_line": 1148,
+ "end_line": 1153,
+ "section": "Setext headings",
+ "extensions": []
+ },
+ {
+ "markdown": "Foo\\\n----\n",
+ "html": "<h2>Foo\\</h2>\n",
+ "example": 60,
+ "start_line": 1158,
+ "end_line": 1163,
+ "section": "Setext headings",
+ "extensions": []
+ },
+ {
+ "markdown": "`Foo\n----\n`\n\n<a title=\"a lot\n---\nof dashes\"/>\n",
+ "html": "<h2>`Foo</h2>\n<p>`</p>\n<h2><a title="a lot</h2>\n<p>of dashes"/></p>\n",
+ "example": 61,
+ "start_line": 1169,
+ "end_line": 1182,
+ "section": "Setext headings",
+ "extensions": []
+ },
+ {
+ "markdown": "> Foo\n---\n",
+ "html": "<blockquote>\n<p>Foo</p>\n</blockquote>\n<hr />\n",
+ "example": 62,
+ "start_line": 1188,
+ "end_line": 1196,
+ "section": "Setext headings",
+ "extensions": []
+ },
+ {
+ "markdown": "> foo\nbar\n===\n",
+ "html": "<blockquote>\n<p>foo\nbar\n===</p>\n</blockquote>\n",
+ "example": 63,
+ "start_line": 1199,
+ "end_line": 1209,
+ "section": "Setext headings",
+ "extensions": []
+ },
+ {
+ "markdown": "- Foo\n---\n",
+ "html": "<ul>\n<li>Foo</li>\n</ul>\n<hr />\n",
+ "example": 64,
+ "start_line": 1212,
+ "end_line": 1220,
+ "section": "Setext headings",
+ "extensions": []
+ },
+ {
+ "markdown": "Foo\nBar\n---\n",
+ "html": "<h2>Foo\nBar</h2>\n",
+ "example": 65,
+ "start_line": 1227,
+ "end_line": 1234,
+ "section": "Setext headings",
+ "extensions": []
+ },
+ {
+ "markdown": "---\nFoo\n---\nBar\n---\nBaz\n",
+ "html": "<hr />\n<h2>Foo</h2>\n<h2>Bar</h2>\n<p>Baz</p>\n",
+ "example": 66,
+ "start_line": 1240,
+ "end_line": 1252,
+ "section": "Setext headings",
+ "extensions": []
+ },
+ {
+ "markdown": "\n====\n",
+ "html": "<p>====</p>\n",
+ "example": 67,
+ "start_line": 1257,
+ "end_line": 1262,
+ "section": "Setext headings",
+ "extensions": []
+ },
+ {
+ "markdown": "---\n---\n",
+ "html": "<hr />\n<hr />\n",
+ "example": 68,
+ "start_line": 1269,
+ "end_line": 1275,
+ "section": "Setext headings",
+ "extensions": []
+ },
+ {
+ "markdown": "- foo\n-----\n",
+ "html": "<ul>\n<li>foo</li>\n</ul>\n<hr />\n",
+ "example": 69,
+ "start_line": 1278,
+ "end_line": 1286,
+ "section": "Setext headings",
+ "extensions": []
+ },
+ {
+ "markdown": " foo\n---\n",
+ "html": "<pre><code>foo\n</code></pre>\n<hr />\n",
+ "example": 70,
+ "start_line": 1289,
+ "end_line": 1296,
+ "section": "Setext headings",
+ "extensions": []
+ },
+ {
+ "markdown": "> foo\n-----\n",
+ "html": "<blockquote>\n<p>foo</p>\n</blockquote>\n<hr />\n",
+ "example": 71,
+ "start_line": 1299,
+ "end_line": 1307,
+ "section": "Setext headings",
+ "extensions": []
+ },
+ {
+ "markdown": "\\> foo\n------\n",
+ "html": "<h2>> foo</h2>\n",
+ "example": 72,
+ "start_line": 1313,
+ "end_line": 1318,
+ "section": "Setext headings",
+ "extensions": []
+ },
+ {
+ "markdown": "Foo\n\nbar\n---\nbaz\n",
+ "html": "<p>Foo</p>\n<h2>bar</h2>\n<p>baz</p>\n",
+ "example": 73,
+ "start_line": 1344,
+ "end_line": 1354,
+ "section": "Setext headings",
+ "extensions": []
+ },
+ {
+ "markdown": "Foo\nbar\n\n---\n\nbaz\n",
+ "html": "<p>Foo\nbar</p>\n<hr />\n<p>baz</p>\n",
+ "example": 74,
+ "start_line": 1360,
+ "end_line": 1372,
+ "section": "Setext headings",
+ "extensions": []
+ },
+ {
+ "markdown": "Foo\nbar\n* * *\nbaz\n",
+ "html": "<p>Foo\nbar</p>\n<hr />\n<p>baz</p>\n",
+ "example": 75,
+ "start_line": 1378,
+ "end_line": 1388,
+ "section": "Setext headings",
+ "extensions": []
+ },
+ {
+ "markdown": "Foo\nbar\n\\---\nbaz\n",
+ "html": "<p>Foo\nbar\n---\nbaz</p>\n",
+ "example": 76,
+ "start_line": 1393,
+ "end_line": 1403,
+ "section": "Setext headings",
+ "extensions": []
+ },
+ {
+ "markdown": " a simple\n indented code block\n",
+ "html": "<pre><code>a simple\n indented code block\n</code></pre>\n",
+ "example": 77,
+ "start_line": 1421,
+ "end_line": 1428,
+ "section": "Indented code blocks",
+ "extensions": []
+ },
+ {
+ "markdown": " - foo\n\n bar\n",
+ "html": "<ul>\n<li>\n<p>foo</p>\n<p>bar</p>\n</li>\n</ul>\n",
+ "example": 78,
+ "start_line": 1435,
+ "end_line": 1446,
+ "section": "Indented code blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "1. foo\n\n - bar\n",
+ "html": "<ol>\n<li>\n<p>foo</p>\n<ul>\n<li>bar</li>\n</ul>\n</li>\n</ol>\n",
+ "example": 79,
+ "start_line": 1449,
+ "end_line": 1462,
+ "section": "Indented code blocks",
+ "extensions": []
+ },
+ {
+ "markdown": " <a/>\n *hi*\n\n - one\n",
+ "html": "<pre><code><a/>\n*hi*\n\n- one\n</code></pre>\n",
+ "example": 80,
+ "start_line": 1469,
+ "end_line": 1480,
+ "section": "Indented code blocks",
+ "extensions": []
+ },
+ {
+ "markdown": " chunk1\n\n chunk2\n \n \n \n chunk3\n",
+ "html": "<pre><code>chunk1\n\nchunk2\n\n\n\nchunk3\n</code></pre>\n",
+ "example": 81,
+ "start_line": 1485,
+ "end_line": 1502,
+ "section": "Indented code blocks",
+ "extensions": []
+ },
+ {
+ "markdown": " chunk1\n \n chunk2\n",
+ "html": "<pre><code>chunk1\n \n chunk2\n</code></pre>\n",
+ "example": 82,
+ "start_line": 1508,
+ "end_line": 1517,
+ "section": "Indented code blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "Foo\n bar\n\n",
+ "html": "<p>Foo\nbar</p>\n",
+ "example": 83,
+ "start_line": 1523,
+ "end_line": 1530,
+ "section": "Indented code blocks",
+ "extensions": []
+ },
+ {
+ "markdown": " foo\nbar\n",
+ "html": "<pre><code>foo\n</code></pre>\n<p>bar</p>\n",
+ "example": 84,
+ "start_line": 1537,
+ "end_line": 1544,
+ "section": "Indented code blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "# Heading\n foo\nHeading\n------\n foo\n----\n",
+ "html": "<h1>Heading</h1>\n<pre><code>foo\n</code></pre>\n<h2>Heading</h2>\n<pre><code>foo\n</code></pre>\n<hr />\n",
+ "example": 85,
+ "start_line": 1550,
+ "end_line": 1565,
+ "section": "Indented code blocks",
+ "extensions": []
+ },
+ {
+ "markdown": " foo\n bar\n",
+ "html": "<pre><code> foo\nbar\n</code></pre>\n",
+ "example": 86,
+ "start_line": 1570,
+ "end_line": 1577,
+ "section": "Indented code blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "\n \n foo\n \n\n",
+ "html": "<pre><code>foo\n</code></pre>\n",
+ "example": 87,
+ "start_line": 1583,
+ "end_line": 1592,
+ "section": "Indented code blocks",
+ "extensions": []
+ },
+ {
+ "markdown": " foo \n",
+ "html": "<pre><code>foo \n</code></pre>\n",
+ "example": 88,
+ "start_line": 1597,
+ "end_line": 1602,
+ "section": "Indented code blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "```\n<\n >\n```\n",
+ "html": "<pre><code><\n >\n</code></pre>\n",
+ "example": 89,
+ "start_line": 1652,
+ "end_line": 1661,
+ "section": "Fenced code blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "~~~\n<\n >\n~~~\n",
+ "html": "<pre><code><\n >\n</code></pre>\n",
+ "example": 90,
+ "start_line": 1666,
+ "end_line": 1675,
+ "section": "Fenced code blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "``\nfoo\n``\n",
+ "html": "<p><code>foo</code></p>\n",
+ "example": 91,
+ "start_line": 1679,
+ "end_line": 1685,
+ "section": "Fenced code blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "```\naaa\n~~~\n```\n",
+ "html": "<pre><code>aaa\n~~~\n</code></pre>\n",
+ "example": 92,
+ "start_line": 1690,
+ "end_line": 1699,
+ "section": "Fenced code blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "~~~\naaa\n```\n~~~\n",
+ "html": "<pre><code>aaa\n```\n</code></pre>\n",
+ "example": 93,
+ "start_line": 1702,
+ "end_line": 1711,
+ "section": "Fenced code blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "````\naaa\n```\n``````\n",
+ "html": "<pre><code>aaa\n```\n</code></pre>\n",
+ "example": 94,
+ "start_line": 1716,
+ "end_line": 1725,
+ "section": "Fenced code blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "~~~~\naaa\n~~~\n~~~~\n",
+ "html": "<pre><code>aaa\n~~~\n</code></pre>\n",
+ "example": 95,
+ "start_line": 1728,
+ "end_line": 1737,
+ "section": "Fenced code blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "```\n",
+ "html": "<pre><code></code></pre>\n",
+ "example": 96,
+ "start_line": 1743,
+ "end_line": 1747,
+ "section": "Fenced code blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "`````\n\n```\naaa\n",
+ "html": "<pre><code>\n```\naaa\n</code></pre>\n",
+ "example": 97,
+ "start_line": 1750,
+ "end_line": 1760,
+ "section": "Fenced code blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "> ```\n> aaa\n\nbbb\n",
+ "html": "<blockquote>\n<pre><code>aaa\n</code></pre>\n</blockquote>\n<p>bbb</p>\n",
+ "example": 98,
+ "start_line": 1763,
+ "end_line": 1774,
+ "section": "Fenced code blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "```\n\n \n```\n",
+ "html": "<pre><code>\n \n</code></pre>\n",
+ "example": 99,
+ "start_line": 1779,
+ "end_line": 1788,
+ "section": "Fenced code blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "```\n```\n",
+ "html": "<pre><code></code></pre>\n",
+ "example": 100,
+ "start_line": 1793,
+ "end_line": 1798,
+ "section": "Fenced code blocks",
+ "extensions": []
+ },
+ {
+ "markdown": " ```\n aaa\naaa\n```\n",
+ "html": "<pre><code>aaa\naaa\n</code></pre>\n",
+ "example": 101,
+ "start_line": 1805,
+ "end_line": 1814,
+ "section": "Fenced code blocks",
+ "extensions": []
+ },
+ {
+ "markdown": " ```\naaa\n aaa\naaa\n ```\n",
+ "html": "<pre><code>aaa\naaa\naaa\n</code></pre>\n",
+ "example": 102,
+ "start_line": 1817,
+ "end_line": 1828,
+ "section": "Fenced code blocks",
+ "extensions": []
+ },
+ {
+ "markdown": " ```\n aaa\n aaa\n aaa\n ```\n",
+ "html": "<pre><code>aaa\n aaa\naaa\n</code></pre>\n",
+ "example": 103,
+ "start_line": 1831,
+ "end_line": 1842,
+ "section": "Fenced code blocks",
+ "extensions": []
+ },
+ {
+ "markdown": " ```\n aaa\n ```\n",
+ "html": "<pre><code>```\naaa\n```\n</code></pre>\n",
+ "example": 104,
+ "start_line": 1847,
+ "end_line": 1856,
+ "section": "Fenced code blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "```\naaa\n ```\n",
+ "html": "<pre><code>aaa\n</code></pre>\n",
+ "example": 105,
+ "start_line": 1862,
+ "end_line": 1869,
+ "section": "Fenced code blocks",
+ "extensions": []
+ },
+ {
+ "markdown": " ```\naaa\n ```\n",
+ "html": "<pre><code>aaa\n</code></pre>\n",
+ "example": 106,
+ "start_line": 1872,
+ "end_line": 1879,
+ "section": "Fenced code blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "```\naaa\n ```\n",
+ "html": "<pre><code>aaa\n ```\n</code></pre>\n",
+ "example": 107,
+ "start_line": 1884,
+ "end_line": 1892,
+ "section": "Fenced code blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "``` ```\naaa\n",
+ "html": "<p><code> </code>\naaa</p>\n",
+ "example": 108,
+ "start_line": 1898,
+ "end_line": 1904,
+ "section": "Fenced code blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "~~~~~~\naaa\n~~~ ~~\n",
+ "html": "<pre><code>aaa\n~~~ ~~\n</code></pre>\n",
+ "example": 109,
+ "start_line": 1907,
+ "end_line": 1915,
+ "section": "Fenced code blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "foo\n```\nbar\n```\nbaz\n",
+ "html": "<p>foo</p>\n<pre><code>bar\n</code></pre>\n<p>baz</p>\n",
+ "example": 110,
+ "start_line": 1921,
+ "end_line": 1932,
+ "section": "Fenced code blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "foo\n---\n~~~\nbar\n~~~\n# baz\n",
+ "html": "<h2>foo</h2>\n<pre><code>bar\n</code></pre>\n<h1>baz</h1>\n",
+ "example": 111,
+ "start_line": 1938,
+ "end_line": 1950,
+ "section": "Fenced code blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "```ruby\ndef foo(x)\n return 3\nend\n```\n",
+ "html": "<pre><code class=\"language-ruby\">def foo(x)\n return 3\nend\n</code></pre>\n",
+ "example": 112,
+ "start_line": 1960,
+ "end_line": 1971,
+ "section": "Fenced code blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "~~~~ ruby startline=3 $%@#$\ndef foo(x)\n return 3\nend\n~~~~~~~\n",
+ "html": "<pre><code class=\"language-ruby\">def foo(x)\n return 3\nend\n</code></pre>\n",
+ "example": 113,
+ "start_line": 1974,
+ "end_line": 1985,
+ "section": "Fenced code blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "````;\n````\n",
+ "html": "<pre><code class=\"language-;\"></code></pre>\n",
+ "example": 114,
+ "start_line": 1988,
+ "end_line": 1993,
+ "section": "Fenced code blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "``` aa ```\nfoo\n",
+ "html": "<p><code>aa</code>\nfoo</p>\n",
+ "example": 115,
+ "start_line": 1998,
+ "end_line": 2004,
+ "section": "Fenced code blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "~~~ aa ``` ~~~\nfoo\n~~~\n",
+ "html": "<pre><code class=\"language-aa\">foo\n</code></pre>\n",
+ "example": 116,
+ "start_line": 2009,
+ "end_line": 2016,
+ "section": "Fenced code blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "```\n``` aaa\n```\n",
+ "html": "<pre><code>``` aaa\n</code></pre>\n",
+ "example": 117,
+ "start_line": 2021,
+ "end_line": 2028,
+ "section": "Fenced code blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "<table><tr><td>\n<pre>\n**Hello**,\n\n_world_.\n</pre>\n</td></tr></table>\n",
+ "html": "<table><tr><td>\n<pre>\n**Hello**,\n<p><em>world</em>.\n</pre></p>\n</td></tr></table>\n",
+ "example": 118,
+ "start_line": 2100,
+ "end_line": 2115,
+ "section": "HTML blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "<table>\n <tr>\n <td>\n hi\n </td>\n </tr>\n</table>\n\nokay.\n",
+ "html": "<table>\n <tr>\n <td>\n hi\n </td>\n </tr>\n</table>\n<p>okay.</p>\n",
+ "example": 119,
+ "start_line": 2129,
+ "end_line": 2148,
+ "section": "HTML blocks",
+ "extensions": []
+ },
+ {
+ "markdown": " <div>\n *hello*\n <foo><a>\n",
+ "html": " <div>\n *hello*\n <foo><a>\n",
+ "example": 120,
+ "start_line": 2151,
+ "end_line": 2159,
+ "section": "HTML blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "</div>\n*foo*\n",
+ "html": "</div>\n*foo*\n",
+ "example": 121,
+ "start_line": 2164,
+ "end_line": 2170,
+ "section": "HTML blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "<DIV CLASS=\"foo\">\n\n*Markdown*\n\n</DIV>\n",
+ "html": "<DIV CLASS=\"foo\">\n<p><em>Markdown</em></p>\n</DIV>\n",
+ "example": 122,
+ "start_line": 2175,
+ "end_line": 2185,
+ "section": "HTML blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "<div id=\"foo\"\n class=\"bar\">\n</div>\n",
+ "html": "<div id=\"foo\"\n class=\"bar\">\n</div>\n",
+ "example": 123,
+ "start_line": 2191,
+ "end_line": 2199,
+ "section": "HTML blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "<div id=\"foo\" class=\"bar\n baz\">\n</div>\n",
+ "html": "<div id=\"foo\" class=\"bar\n baz\">\n</div>\n",
+ "example": 124,
+ "start_line": 2202,
+ "end_line": 2210,
+ "section": "HTML blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "<div>\n*foo*\n\n*bar*\n",
+ "html": "<div>\n*foo*\n<p><em>bar</em></p>\n",
+ "example": 125,
+ "start_line": 2214,
+ "end_line": 2223,
+ "section": "HTML blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "<div id=\"foo\"\n*hi*\n",
+ "html": "<div id=\"foo\"\n*hi*\n",
+ "example": 126,
+ "start_line": 2230,
+ "end_line": 2236,
+ "section": "HTML blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "<div class\nfoo\n",
+ "html": "<div class\nfoo\n",
+ "example": 127,
+ "start_line": 2239,
+ "end_line": 2245,
+ "section": "HTML blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "<div *???-&&&-<---\n*foo*\n",
+ "html": "<div *???-&&&-<---\n*foo*\n",
+ "example": 128,
+ "start_line": 2251,
+ "end_line": 2257,
+ "section": "HTML blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "<div><a href=\"bar\">*foo*</a></div>\n",
+ "html": "<div><a href=\"bar\">*foo*</a></div>\n",
+ "example": 129,
+ "start_line": 2263,
+ "end_line": 2267,
+ "section": "HTML blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "<table><tr><td>\nfoo\n</td></tr></table>\n",
+ "html": "<table><tr><td>\nfoo\n</td></tr></table>\n",
+ "example": 130,
+ "start_line": 2270,
+ "end_line": 2278,
+ "section": "HTML blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "<div></div>\n``` c\nint x = 33;\n```\n",
+ "html": "<div></div>\n``` c\nint x = 33;\n```\n",
+ "example": 131,
+ "start_line": 2287,
+ "end_line": 2297,
+ "section": "HTML blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "<a href=\"foo\">\n*bar*\n</a>\n",
+ "html": "<a href=\"foo\">\n*bar*\n</a>\n",
+ "example": 132,
+ "start_line": 2304,
+ "end_line": 2312,
+ "section": "HTML blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "<Warning>\n*bar*\n</Warning>\n",
+ "html": "<Warning>\n*bar*\n</Warning>\n",
+ "example": 133,
+ "start_line": 2317,
+ "end_line": 2325,
+ "section": "HTML blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "<i class=\"foo\">\n*bar*\n</i>\n",
+ "html": "<i class=\"foo\">\n*bar*\n</i>\n",
+ "example": 134,
+ "start_line": 2328,
+ "end_line": 2336,
+ "section": "HTML blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "</ins>\n*bar*\n",
+ "html": "</ins>\n*bar*\n",
+ "example": 135,
+ "start_line": 2339,
+ "end_line": 2345,
+ "section": "HTML blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "<del>\n*foo*\n</del>\n",
+ "html": "<del>\n*foo*\n</del>\n",
+ "example": 136,
+ "start_line": 2354,
+ "end_line": 2362,
+ "section": "HTML blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "<del>\n\n*foo*\n\n</del>\n",
+ "html": "<del>\n<p><em>foo</em></p>\n</del>\n",
+ "example": 137,
+ "start_line": 2369,
+ "end_line": 2379,
+ "section": "HTML blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "<del>*foo*</del>\n",
+ "html": "<p><del><em>foo</em></del></p>\n",
+ "example": 138,
+ "start_line": 2387,
+ "end_line": 2391,
+ "section": "HTML blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "<pre language=\"haskell\"><code>\nimport Text.HTML.TagSoup\n\nmain :: IO ()\nmain = print $ parseTags tags\n</code></pre>\nokay\n",
+ "html": "<pre language=\"haskell\"><code>\nimport Text.HTML.TagSoup\n\nmain :: IO ()\nmain = print $ parseTags tags\n</code></pre>\n<p>okay</p>\n",
+ "example": 139,
+ "start_line": 2403,
+ "end_line": 2419,
+ "section": "HTML blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "<script type=\"text/javascript\">\n// JavaScript example\n\ndocument.getElementById(\"demo\").innerHTML = \"Hello JavaScript!\";\n</script>\nokay\n",
+ "html": "<script type=\"text/javascript\">\n// JavaScript example\n\ndocument.getElementById(\"demo\").innerHTML = \"Hello JavaScript!\";\n</script>\n<p>okay</p>\n",
+ "example": 140,
+ "start_line": 2424,
+ "end_line": 2438,
+ "section": "HTML blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "<style\n type=\"text/css\">\nh1 {color:red;}\n\np {color:blue;}\n</style>\nokay\n",
+ "html": "<style\n type=\"text/css\">\nh1 {color:red;}\n\np {color:blue;}\n</style>\n<p>okay</p>\n",
+ "example": 141,
+ "start_line": 2443,
+ "end_line": 2459,
+ "section": "HTML blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "<style\n type=\"text/css\">\n\nfoo\n",
+ "html": "<style\n type=\"text/css\">\n\nfoo\n",
+ "example": 142,
+ "start_line": 2466,
+ "end_line": 2476,
+ "section": "HTML blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "> <div>\n> foo\n\nbar\n",
+ "html": "<blockquote>\n<div>\nfoo\n</blockquote>\n<p>bar</p>\n",
+ "example": 143,
+ "start_line": 2479,
+ "end_line": 2490,
+ "section": "HTML blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "- <div>\n- foo\n",
+ "html": "<ul>\n<li>\n<div>\n</li>\n<li>foo</li>\n</ul>\n",
+ "example": 144,
+ "start_line": 2493,
+ "end_line": 2503,
+ "section": "HTML blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "<style>p{color:red;}</style>\n*foo*\n",
+ "html": "<style>p{color:red;}</style>\n<p><em>foo</em></p>\n",
+ "example": 145,
+ "start_line": 2508,
+ "end_line": 2514,
+ "section": "HTML blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "<!-- foo -->*bar*\n*baz*\n",
+ "html": "<!-- foo -->*bar*\n<p><em>baz</em></p>\n",
+ "example": 146,
+ "start_line": 2517,
+ "end_line": 2523,
+ "section": "HTML blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "<script>\nfoo\n</script>1. *bar*\n",
+ "html": "<script>\nfoo\n</script>1. *bar*\n",
+ "example": 147,
+ "start_line": 2529,
+ "end_line": 2537,
+ "section": "HTML blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "<!-- Foo\n\nbar\n baz -->\nokay\n",
+ "html": "<!-- Foo\n\nbar\n baz -->\n<p>okay</p>\n",
+ "example": 148,
+ "start_line": 2542,
+ "end_line": 2554,
+ "section": "HTML blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "<?php\n\n echo '>';\n\n?>\nokay\n",
+ "html": "<?php\n\n echo '>';\n\n?>\n<p>okay</p>\n",
+ "example": 149,
+ "start_line": 2560,
+ "end_line": 2574,
+ "section": "HTML blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "<!DOCTYPE html>\n",
+ "html": "<!DOCTYPE html>\n",
+ "example": 150,
+ "start_line": 2579,
+ "end_line": 2583,
+ "section": "HTML blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "<![CDATA[\nfunction matchwo(a,b)\n{\n if (a < b && a < 0) then {\n return 1;\n\n } else {\n\n return 0;\n }\n}\n]]>\nokay\n",
+ "html": "<![CDATA[\nfunction matchwo(a,b)\n{\n if (a < b && a < 0) then {\n return 1;\n\n } else {\n\n return 0;\n }\n}\n]]>\n<p>okay</p>\n",
+ "example": 151,
+ "start_line": 2588,
+ "end_line": 2616,
+ "section": "HTML blocks",
+ "extensions": []
+ },
+ {
+ "markdown": " <!-- foo -->\n\n <!-- foo -->\n",
+ "html": " <!-- foo -->\n<pre><code><!-- foo -->\n</code></pre>\n",
+ "example": 152,
+ "start_line": 2621,
+ "end_line": 2629,
+ "section": "HTML blocks",
+ "extensions": []
+ },
+ {
+ "markdown": " <div>\n\n <div>\n",
+ "html": " <div>\n<pre><code><div>\n</code></pre>\n",
+ "example": 153,
+ "start_line": 2632,
+ "end_line": 2640,
+ "section": "HTML blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "Foo\n<div>\nbar\n</div>\n",
+ "html": "<p>Foo</p>\n<div>\nbar\n</div>\n",
+ "example": 154,
+ "start_line": 2646,
+ "end_line": 2656,
+ "section": "HTML blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "<div>\nbar\n</div>\n*foo*\n",
+ "html": "<div>\nbar\n</div>\n*foo*\n",
+ "example": 155,
+ "start_line": 2663,
+ "end_line": 2673,
+ "section": "HTML blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "Foo\n<a href=\"bar\">\nbaz\n",
+ "html": "<p>Foo\n<a href=\"bar\">\nbaz</p>\n",
+ "example": 156,
+ "start_line": 2678,
+ "end_line": 2686,
+ "section": "HTML blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "<div>\n\n*Emphasized* text.\n\n</div>\n",
+ "html": "<div>\n<p><em>Emphasized</em> text.</p>\n</div>\n",
+ "example": 157,
+ "start_line": 2719,
+ "end_line": 2729,
+ "section": "HTML blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "<div>\n*Emphasized* text.\n</div>\n",
+ "html": "<div>\n*Emphasized* text.\n</div>\n",
+ "example": 158,
+ "start_line": 2732,
+ "end_line": 2740,
+ "section": "HTML blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "<table>\n\n<tr>\n\n<td>\nHi\n</td>\n\n</tr>\n\n</table>\n",
+ "html": "<table>\n<tr>\n<td>\nHi\n</td>\n</tr>\n</table>\n",
+ "example": 159,
+ "start_line": 2754,
+ "end_line": 2774,
+ "section": "HTML blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "<table>\n\n <tr>\n\n <td>\n Hi\n </td>\n\n </tr>\n\n</table>\n",
+ "html": "<table>\n <tr>\n<pre><code><td>\n Hi\n</td>\n</code></pre>\n </tr>\n</table>\n",
+ "example": 160,
+ "start_line": 2781,
+ "end_line": 2802,
+ "section": "HTML blocks",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo]: /url \"title\"\n\n[foo]\n",
+ "html": "<p><a href=\"/url\" title=\"title\">foo</a></p>\n",
+ "example": 161,
+ "start_line": 2829,
+ "end_line": 2835,
+ "section": "Link reference definitions",
+ "extensions": []
+ },
+ {
+ "markdown": " [foo]: \n /url \n 'the title' \n\n[foo]\n",
+ "html": "<p><a href=\"/url\" title=\"the title\">foo</a></p>\n",
+ "example": 162,
+ "start_line": 2838,
+ "end_line": 2846,
+ "section": "Link reference definitions",
+ "extensions": []
+ },
+ {
+ "markdown": "[Foo*bar\\]]:my_(url) 'title (with parens)'\n\n[Foo*bar\\]]\n",
+ "html": "<p><a href=\"my_(url)\" title=\"title (with parens)\">Foo*bar]</a></p>\n",
+ "example": 163,
+ "start_line": 2849,
+ "end_line": 2855,
+ "section": "Link reference definitions",
+ "extensions": []
+ },
+ {
+ "markdown": "[Foo bar]:\n<my url>\n'title'\n\n[Foo bar]\n",
+ "html": "<p><a href=\"my%20url\" title=\"title\">Foo bar</a></p>\n",
+ "example": 164,
+ "start_line": 2858,
+ "end_line": 2866,
+ "section": "Link reference definitions",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo]: /url '\ntitle\nline1\nline2\n'\n\n[foo]\n",
+ "html": "<p><a href=\"/url\" title=\"\ntitle\nline1\nline2\n\">foo</a></p>\n",
+ "example": 165,
+ "start_line": 2871,
+ "end_line": 2885,
+ "section": "Link reference definitions",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo]: /url 'title\n\nwith blank line'\n\n[foo]\n",
+ "html": "<p>[foo]: /url 'title</p>\n<p>with blank line'</p>\n<p>[foo]</p>\n",
+ "example": 166,
+ "start_line": 2890,
+ "end_line": 2900,
+ "section": "Link reference definitions",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo]:\n/url\n\n[foo]\n",
+ "html": "<p><a href=\"/url\">foo</a></p>\n",
+ "example": 167,
+ "start_line": 2905,
+ "end_line": 2912,
+ "section": "Link reference definitions",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo]:\n\n[foo]\n",
+ "html": "<p>[foo]:</p>\n<p>[foo]</p>\n",
+ "example": 168,
+ "start_line": 2917,
+ "end_line": 2924,
+ "section": "Link reference definitions",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo]: <>\n\n[foo]\n",
+ "html": "<p><a href=\"\">foo</a></p>\n",
+ "example": 169,
+ "start_line": 2929,
+ "end_line": 2935,
+ "section": "Link reference definitions",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo]: <bar>(baz)\n\n[foo]\n",
+ "html": "<p>[foo]: <bar>(baz)</p>\n<p>[foo]</p>\n",
+ "example": 170,
+ "start_line": 2940,
+ "end_line": 2947,
+ "section": "Link reference definitions",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo]: /url\\bar\\*baz \"foo\\\"bar\\baz\"\n\n[foo]\n",
+ "html": "<p><a href=\"/url%5Cbar*baz\" title=\"foo"bar\\baz\">foo</a></p>\n",
+ "example": 171,
+ "start_line": 2953,
+ "end_line": 2959,
+ "section": "Link reference definitions",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo]\n\n[foo]: url\n",
+ "html": "<p><a href=\"url\">foo</a></p>\n",
+ "example": 172,
+ "start_line": 2964,
+ "end_line": 2970,
+ "section": "Link reference definitions",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo]\n\n[foo]: first\n[foo]: second\n",
+ "html": "<p><a href=\"first\">foo</a></p>\n",
+ "example": 173,
+ "start_line": 2976,
+ "end_line": 2983,
+ "section": "Link reference definitions",
+ "extensions": []
+ },
+ {
+ "markdown": "[FOO]: /url\n\n[Foo]\n",
+ "html": "<p><a href=\"/url\">Foo</a></p>\n",
+ "example": 174,
+ "start_line": 2989,
+ "end_line": 2995,
+ "section": "Link reference definitions",
+ "extensions": []
+ },
+ {
+ "markdown": "[\u0391\u0393\u03a9]: /\u03c6\u03bf\u03c5\n\n[\u03b1\u03b3\u03c9]\n",
+ "html": "<p><a href=\"/%CF%86%CE%BF%CF%85\">\u03b1\u03b3\u03c9</a></p>\n",
+ "example": 175,
+ "start_line": 2998,
+ "end_line": 3004,
+ "section": "Link reference definitions",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo]: /url\n",
+ "html": "",
+ "example": 176,
+ "start_line": 3010,
+ "end_line": 3013,
+ "section": "Link reference definitions",
+ "extensions": []
+ },
+ {
+ "markdown": "[\nfoo\n]: /url\nbar\n",
+ "html": "<p>bar</p>\n",
+ "example": 177,
+ "start_line": 3018,
+ "end_line": 3025,
+ "section": "Link reference definitions",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo]: /url \"title\" ok\n",
+ "html": "<p>[foo]: /url "title" ok</p>\n",
+ "example": 178,
+ "start_line": 3031,
+ "end_line": 3035,
+ "section": "Link reference definitions",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo]: /url\n\"title\" ok\n",
+ "html": "<p>"title" ok</p>\n",
+ "example": 179,
+ "start_line": 3040,
+ "end_line": 3045,
+ "section": "Link reference definitions",
+ "extensions": []
+ },
+ {
+ "markdown": " [foo]: /url \"title\"\n\n[foo]\n",
+ "html": "<pre><code>[foo]: /url "title"\n</code></pre>\n<p>[foo]</p>\n",
+ "example": 180,
+ "start_line": 3051,
+ "end_line": 3059,
+ "section": "Link reference definitions",
+ "extensions": []
+ },
+ {
+ "markdown": "```\n[foo]: /url\n```\n\n[foo]\n",
+ "html": "<pre><code>[foo]: /url\n</code></pre>\n<p>[foo]</p>\n",
+ "example": 181,
+ "start_line": 3065,
+ "end_line": 3075,
+ "section": "Link reference definitions",
+ "extensions": []
+ },
+ {
+ "markdown": "Foo\n[bar]: /baz\n\n[bar]\n",
+ "html": "<p>Foo\n[bar]: /baz</p>\n<p>[bar]</p>\n",
+ "example": 182,
+ "start_line": 3080,
+ "end_line": 3089,
+ "section": "Link reference definitions",
+ "extensions": []
+ },
+ {
+ "markdown": "# [Foo]\n[foo]: /url\n> bar\n",
+ "html": "<h1><a href=\"/url\">Foo</a></h1>\n<blockquote>\n<p>bar</p>\n</blockquote>\n",
+ "example": 183,
+ "start_line": 3095,
+ "end_line": 3104,
+ "section": "Link reference definitions",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo]: /url\nbar\n===\n[foo]\n",
+ "html": "<h1>bar</h1>\n<p><a href=\"/url\">foo</a></p>\n",
+ "example": 184,
+ "start_line": 3106,
+ "end_line": 3114,
+ "section": "Link reference definitions",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo]: /url\n===\n[foo]\n",
+ "html": "<p>===\n<a href=\"/url\">foo</a></p>\n",
+ "example": 185,
+ "start_line": 3116,
+ "end_line": 3123,
+ "section": "Link reference definitions",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo]: /foo-url \"foo\"\n[bar]: /bar-url\n \"bar\"\n[baz]: /baz-url\n\n[foo],\n[bar],\n[baz]\n",
+ "html": "<p><a href=\"/foo-url\" title=\"foo\">foo</a>,\n<a href=\"/bar-url\" title=\"bar\">bar</a>,\n<a href=\"/baz-url\">baz</a></p>\n",
+ "example": 186,
+ "start_line": 3129,
+ "end_line": 3142,
+ "section": "Link reference definitions",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo]\n\n> [foo]: /url\n",
+ "html": "<p><a href=\"/url\">foo</a></p>\n<blockquote>\n</blockquote>\n",
+ "example": 187,
+ "start_line": 3150,
+ "end_line": 3158,
+ "section": "Link reference definitions",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo]: /url\n",
+ "html": "",
+ "example": 188,
+ "start_line": 3167,
+ "end_line": 3170,
+ "section": "Link reference definitions",
+ "extensions": []
+ },
+ {
+ "markdown": "aaa\n\nbbb\n",
+ "html": "<p>aaa</p>\n<p>bbb</p>\n",
+ "example": 189,
+ "start_line": 3184,
+ "end_line": 3191,
+ "section": "Paragraphs",
+ "extensions": []
+ },
+ {
+ "markdown": "aaa\nbbb\n\nccc\nddd\n",
+ "html": "<p>aaa\nbbb</p>\n<p>ccc\nddd</p>\n",
+ "example": 190,
+ "start_line": 3196,
+ "end_line": 3207,
+ "section": "Paragraphs",
+ "extensions": []
+ },
+ {
+ "markdown": "aaa\n\n\nbbb\n",
+ "html": "<p>aaa</p>\n<p>bbb</p>\n",
+ "example": 191,
+ "start_line": 3212,
+ "end_line": 3220,
+ "section": "Paragraphs",
+ "extensions": []
+ },
+ {
+ "markdown": " aaa\n bbb\n",
+ "html": "<p>aaa\nbbb</p>\n",
+ "example": 192,
+ "start_line": 3225,
+ "end_line": 3231,
+ "section": "Paragraphs",
+ "extensions": []
+ },
+ {
+ "markdown": "aaa\n bbb\n ccc\n",
+ "html": "<p>aaa\nbbb\nccc</p>\n",
+ "example": 193,
+ "start_line": 3237,
+ "end_line": 3245,
+ "section": "Paragraphs",
+ "extensions": []
+ },
+ {
+ "markdown": " aaa\nbbb\n",
+ "html": "<p>aaa\nbbb</p>\n",
+ "example": 194,
+ "start_line": 3251,
+ "end_line": 3257,
+ "section": "Paragraphs",
+ "extensions": []
+ },
+ {
+ "markdown": " aaa\nbbb\n",
+ "html": "<pre><code>aaa\n</code></pre>\n<p>bbb</p>\n",
+ "example": 195,
+ "start_line": 3260,
+ "end_line": 3267,
+ "section": "Paragraphs",
+ "extensions": []
+ },
+ {
+ "markdown": "aaa \nbbb \n",
+ "html": "<p>aaa<br />\nbbb</p>\n",
+ "example": 196,
+ "start_line": 3274,
+ "end_line": 3280,
+ "section": "Paragraphs",
+ "extensions": []
+ },
+ {
+ "markdown": " \n\naaa\n \n\n# aaa\n\n \n",
+ "html": "<p>aaa</p>\n<h1>aaa</h1>\n",
+ "example": 197,
+ "start_line": 3291,
+ "end_line": 3303,
+ "section": "Blank lines",
+ "extensions": []
+ },
+ {
+ "markdown": "| foo | bar |\n| --- | --- |\n| baz | bim |\n",
+ "html": "<table>\n<thead>\n<tr>\n<th>foo</th>\n<th>bar</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>baz</td>\n<td>bim</td>\n</tr>\n</tbody>\n</table>\n",
+ "example": 198,
+ "start_line": 3326,
+ "end_line": 3345,
+ "section": "Tables (extension)",
+ "extensions": [
+ "table"
+ ]
+ },
+ {
+ "markdown": "| abc | defghi |\n:-: | -----------:\nbar | baz\n",
+ "html": "<table>\n<thead>\n<tr>\n<th align=\"center\">abc</th>\n<th align=\"right\">defghi</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td align=\"center\">bar</td>\n<td align=\"right\">baz</td>\n</tr>\n</tbody>\n</table>\n",
+ "example": 199,
+ "start_line": 3350,
+ "end_line": 3369,
+ "section": "Tables (extension)",
+ "extensions": [
+ "table"
+ ]
+ },
+ {
+ "markdown": "| f\\|oo |\n| ------ |\n| b `\\|` az |\n| b **\\|** im |\n",
+ "html": "<table>\n<thead>\n<tr>\n<th>f|oo</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>b <code>|</code> az</td>\n</tr>\n<tr>\n<td>b <strong>|</strong> im</td>\n</tr>\n</tbody>\n</table>\n",
+ "example": 200,
+ "start_line": 3374,
+ "end_line": 3395,
+ "section": "Tables (extension)",
+ "extensions": [
+ "table"
+ ]
+ },
+ {
+ "markdown": "| abc | def |\n| --- | --- |\n| bar | baz |\n> bar\n",
+ "html": "<table>\n<thead>\n<tr>\n<th>abc</th>\n<th>def</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>bar</td>\n<td>baz</td>\n</tr>\n</tbody>\n</table>\n<blockquote>\n<p>bar</p>\n</blockquote>\n",
+ "example": 201,
+ "start_line": 3400,
+ "end_line": 3423,
+ "section": "Tables (extension)",
+ "extensions": [
+ "table"
+ ]
+ },
+ {
+ "markdown": "| abc | def |\n| --- | --- |\n| bar | baz |\nbar\n\nbar\n",
+ "html": "<table>\n<thead>\n<tr>\n<th>abc</th>\n<th>def</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>bar</td>\n<td>baz</td>\n</tr>\n<tr>\n<td>bar</td>\n<td></td>\n</tr>\n</tbody>\n</table>\n<p>bar</p>\n",
+ "example": 202,
+ "start_line": 3425,
+ "end_line": 3452,
+ "section": "Tables (extension)",
+ "extensions": [
+ "table"
+ ]
+ },
+ {
+ "markdown": "| abc | def |\n| --- |\n| bar |\n",
+ "html": "<p>| abc | def |\n| --- |\n| bar |</p>\n",
+ "example": 203,
+ "start_line": 3457,
+ "end_line": 3465,
+ "section": "Tables (extension)",
+ "extensions": [
+ "table"
+ ]
+ },
+ {
+ "markdown": "| abc | def |\n| --- | --- |\n| bar |\n| bar | baz | boo |\n",
+ "html": "<table>\n<thead>\n<tr>\n<th>abc</th>\n<th>def</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>bar</td>\n<td></td>\n</tr>\n<tr>\n<td>bar</td>\n<td>baz</td>\n</tr>\n</tbody>\n</table>\n",
+ "example": 204,
+ "start_line": 3471,
+ "end_line": 3495,
+ "section": "Tables (extension)",
+ "extensions": [
+ "table"
+ ]
+ },
+ {
+ "markdown": "| abc | def |\n| --- | --- |\n",
+ "html": "<table>\n<thead>\n<tr>\n<th>abc</th>\n<th>def</th>\n</tr>\n</thead>\n</table>\n",
+ "example": 205,
+ "start_line": 3499,
+ "end_line": 3511,
+ "section": "Tables (extension)",
+ "extensions": [
+ "table"
+ ]
+ },
+ {
+ "markdown": "> # Foo\n> bar\n> baz\n",
+ "html": "<blockquote>\n<h1>Foo</h1>\n<p>bar\nbaz</p>\n</blockquote>\n",
+ "example": 206,
+ "start_line": 3565,
+ "end_line": 3575,
+ "section": "Block quotes",
+ "extensions": []
+ },
+ {
+ "markdown": "># Foo\n>bar\n> baz\n",
+ "html": "<blockquote>\n<h1>Foo</h1>\n<p>bar\nbaz</p>\n</blockquote>\n",
+ "example": 207,
+ "start_line": 3580,
+ "end_line": 3590,
+ "section": "Block quotes",
+ "extensions": []
+ },
+ {
+ "markdown": " > # Foo\n > bar\n > baz\n",
+ "html": "<blockquote>\n<h1>Foo</h1>\n<p>bar\nbaz</p>\n</blockquote>\n",
+ "example": 208,
+ "start_line": 3595,
+ "end_line": 3605,
+ "section": "Block quotes",
+ "extensions": []
+ },
+ {
+ "markdown": " > # Foo\n > bar\n > baz\n",
+ "html": "<pre><code>> # Foo\n> bar\n> baz\n</code></pre>\n",
+ "example": 209,
+ "start_line": 3610,
+ "end_line": 3619,
+ "section": "Block quotes",
+ "extensions": []
+ },
+ {
+ "markdown": "> # Foo\n> bar\nbaz\n",
+ "html": "<blockquote>\n<h1>Foo</h1>\n<p>bar\nbaz</p>\n</blockquote>\n",
+ "example": 210,
+ "start_line": 3625,
+ "end_line": 3635,
+ "section": "Block quotes",
+ "extensions": []
+ },
+ {
+ "markdown": "> bar\nbaz\n> foo\n",
+ "html": "<blockquote>\n<p>bar\nbaz\nfoo</p>\n</blockquote>\n",
+ "example": 211,
+ "start_line": 3641,
+ "end_line": 3651,
+ "section": "Block quotes",
+ "extensions": []
+ },
+ {
+ "markdown": "> foo\n---\n",
+ "html": "<blockquote>\n<p>foo</p>\n</blockquote>\n<hr />\n",
+ "example": 212,
+ "start_line": 3665,
+ "end_line": 3673,
+ "section": "Block quotes",
+ "extensions": []
+ },
+ {
+ "markdown": "> - foo\n- bar\n",
+ "html": "<blockquote>\n<ul>\n<li>foo</li>\n</ul>\n</blockquote>\n<ul>\n<li>bar</li>\n</ul>\n",
+ "example": 213,
+ "start_line": 3685,
+ "end_line": 3697,
+ "section": "Block quotes",
+ "extensions": []
+ },
+ {
+ "markdown": "> foo\n bar\n",
+ "html": "<blockquote>\n<pre><code>foo\n</code></pre>\n</blockquote>\n<pre><code>bar\n</code></pre>\n",
+ "example": 214,
+ "start_line": 3703,
+ "end_line": 3713,
+ "section": "Block quotes",
+ "extensions": []
+ },
+ {
+ "markdown": "> ```\nfoo\n```\n",
+ "html": "<blockquote>\n<pre><code></code></pre>\n</blockquote>\n<p>foo</p>\n<pre><code></code></pre>\n",
+ "example": 215,
+ "start_line": 3716,
+ "end_line": 3726,
+ "section": "Block quotes",
+ "extensions": []
+ },
+ {
+ "markdown": "> foo\n - bar\n",
+ "html": "<blockquote>\n<p>foo\n- bar</p>\n</blockquote>\n",
+ "example": 216,
+ "start_line": 3732,
+ "end_line": 3740,
+ "section": "Block quotes",
+ "extensions": []
+ },
+ {
+ "markdown": ">\n",
+ "html": "<blockquote>\n</blockquote>\n",
+ "example": 217,
+ "start_line": 3756,
+ "end_line": 3761,
+ "section": "Block quotes",
+ "extensions": []
+ },
+ {
+ "markdown": ">\n> \n> \n",
+ "html": "<blockquote>\n</blockquote>\n",
+ "example": 218,
+ "start_line": 3764,
+ "end_line": 3771,
+ "section": "Block quotes",
+ "extensions": []
+ },
+ {
+ "markdown": ">\n> foo\n> \n",
+ "html": "<blockquote>\n<p>foo</p>\n</blockquote>\n",
+ "example": 219,
+ "start_line": 3776,
+ "end_line": 3784,
+ "section": "Block quotes",
+ "extensions": []
+ },
+ {
+ "markdown": "> foo\n\n> bar\n",
+ "html": "<blockquote>\n<p>foo</p>\n</blockquote>\n<blockquote>\n<p>bar</p>\n</blockquote>\n",
+ "example": 220,
+ "start_line": 3789,
+ "end_line": 3800,
+ "section": "Block quotes",
+ "extensions": []
+ },
+ {
+ "markdown": "> foo\n> bar\n",
+ "html": "<blockquote>\n<p>foo\nbar</p>\n</blockquote>\n",
+ "example": 221,
+ "start_line": 3811,
+ "end_line": 3819,
+ "section": "Block quotes",
+ "extensions": []
+ },
+ {
+ "markdown": "> foo\n>\n> bar\n",
+ "html": "<blockquote>\n<p>foo</p>\n<p>bar</p>\n</blockquote>\n",
+ "example": 222,
+ "start_line": 3824,
+ "end_line": 3833,
+ "section": "Block quotes",
+ "extensions": []
+ },
+ {
+ "markdown": "foo\n> bar\n",
+ "html": "<p>foo</p>\n<blockquote>\n<p>bar</p>\n</blockquote>\n",
+ "example": 223,
+ "start_line": 3838,
+ "end_line": 3846,
+ "section": "Block quotes",
+ "extensions": []
+ },
+ {
+ "markdown": "> aaa\n***\n> bbb\n",
+ "html": "<blockquote>\n<p>aaa</p>\n</blockquote>\n<hr />\n<blockquote>\n<p>bbb</p>\n</blockquote>\n",
+ "example": 224,
+ "start_line": 3852,
+ "end_line": 3864,
+ "section": "Block quotes",
+ "extensions": []
+ },
+ {
+ "markdown": "> bar\nbaz\n",
+ "html": "<blockquote>\n<p>bar\nbaz</p>\n</blockquote>\n",
+ "example": 225,
+ "start_line": 3870,
+ "end_line": 3878,
+ "section": "Block quotes",
+ "extensions": []
+ },
+ {
+ "markdown": "> bar\n\nbaz\n",
+ "html": "<blockquote>\n<p>bar</p>\n</blockquote>\n<p>baz</p>\n",
+ "example": 226,
+ "start_line": 3881,
+ "end_line": 3890,
+ "section": "Block quotes",
+ "extensions": []
+ },
+ {
+ "markdown": "> bar\n>\nbaz\n",
+ "html": "<blockquote>\n<p>bar</p>\n</blockquote>\n<p>baz</p>\n",
+ "example": 227,
+ "start_line": 3893,
+ "end_line": 3902,
+ "section": "Block quotes",
+ "extensions": []
+ },
+ {
+ "markdown": "> > > foo\nbar\n",
+ "html": "<blockquote>\n<blockquote>\n<blockquote>\n<p>foo\nbar</p>\n</blockquote>\n</blockquote>\n</blockquote>\n",
+ "example": 228,
+ "start_line": 3909,
+ "end_line": 3921,
+ "section": "Block quotes",
+ "extensions": []
+ },
+ {
+ "markdown": ">>> foo\n> bar\n>>baz\n",
+ "html": "<blockquote>\n<blockquote>\n<blockquote>\n<p>foo\nbar\nbaz</p>\n</blockquote>\n</blockquote>\n</blockquote>\n",
+ "example": 229,
+ "start_line": 3924,
+ "end_line": 3938,
+ "section": "Block quotes",
+ "extensions": []
+ },
+ {
+ "markdown": "> code\n\n> not code\n",
+ "html": "<blockquote>\n<pre><code>code\n</code></pre>\n</blockquote>\n<blockquote>\n<p>not code</p>\n</blockquote>\n",
+ "example": 230,
+ "start_line": 3946,
+ "end_line": 3958,
+ "section": "Block quotes",
+ "extensions": []
+ },
+ {
+ "markdown": "A paragraph\nwith two lines.\n\n indented code\n\n> A block quote.\n",
+ "html": "<p>A paragraph\nwith two lines.</p>\n<pre><code>indented code\n</code></pre>\n<blockquote>\n<p>A block quote.</p>\n</blockquote>\n",
+ "example": 231,
+ "start_line": 4000,
+ "end_line": 4015,
+ "section": "List items",
+ "extensions": []
+ },
+ {
+ "markdown": "1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.\n",
+ "html": "<ol>\n<li>\n<p>A paragraph\nwith two lines.</p>\n<pre><code>indented code\n</code></pre>\n<blockquote>\n<p>A block quote.</p>\n</blockquote>\n</li>\n</ol>\n",
+ "example": 232,
+ "start_line": 4022,
+ "end_line": 4041,
+ "section": "List items",
+ "extensions": []
+ },
+ {
+ "markdown": "- one\n\n two\n",
+ "html": "<ul>\n<li>one</li>\n</ul>\n<p>two</p>\n",
+ "example": 233,
+ "start_line": 4055,
+ "end_line": 4064,
+ "section": "List items",
+ "extensions": []
+ },
+ {
+ "markdown": "- one\n\n two\n",
+ "html": "<ul>\n<li>\n<p>one</p>\n<p>two</p>\n</li>\n</ul>\n",
+ "example": 234,
+ "start_line": 4067,
+ "end_line": 4078,
+ "section": "List items",
+ "extensions": []
+ },
+ {
+ "markdown": " - one\n\n two\n",
+ "html": "<ul>\n<li>one</li>\n</ul>\n<pre><code> two\n</code></pre>\n",
+ "example": 235,
+ "start_line": 4081,
+ "end_line": 4091,
+ "section": "List items",
+ "extensions": []
+ },
+ {
+ "markdown": " - one\n\n two\n",
+ "html": "<ul>\n<li>\n<p>one</p>\n<p>two</p>\n</li>\n</ul>\n",
+ "example": 236,
+ "start_line": 4094,
+ "end_line": 4105,
+ "section": "List items",
+ "extensions": []
+ },
+ {
+ "markdown": " > > 1. one\n>>\n>> two\n",
+ "html": "<blockquote>\n<blockquote>\n<ol>\n<li>\n<p>one</p>\n<p>two</p>\n</li>\n</ol>\n</blockquote>\n</blockquote>\n",
+ "example": 237,
+ "start_line": 4116,
+ "end_line": 4131,
+ "section": "List items",
+ "extensions": []
+ },
+ {
+ "markdown": ">>- one\n>>\n > > two\n",
+ "html": "<blockquote>\n<blockquote>\n<ul>\n<li>one</li>\n</ul>\n<p>two</p>\n</blockquote>\n</blockquote>\n",
+ "example": 238,
+ "start_line": 4143,
+ "end_line": 4156,
+ "section": "List items",
+ "extensions": []
+ },
+ {
+ "markdown": "-one\n\n2.two\n",
+ "html": "<p>-one</p>\n<p>2.two</p>\n",
+ "example": 239,
+ "start_line": 4162,
+ "end_line": 4169,
+ "section": "List items",
+ "extensions": []
+ },
+ {
+ "markdown": "- foo\n\n\n bar\n",
+ "html": "<ul>\n<li>\n<p>foo</p>\n<p>bar</p>\n</li>\n</ul>\n",
+ "example": 240,
+ "start_line": 4175,
+ "end_line": 4187,
+ "section": "List items",
+ "extensions": []
+ },
+ {
+ "markdown": "1. foo\n\n ```\n bar\n ```\n\n baz\n\n > bam\n",
+ "html": "<ol>\n<li>\n<p>foo</p>\n<pre><code>bar\n</code></pre>\n<p>baz</p>\n<blockquote>\n<p>bam</p>\n</blockquote>\n</li>\n</ol>\n",
+ "example": 241,
+ "start_line": 4192,
+ "end_line": 4214,
+ "section": "List items",
+ "extensions": []
+ },
+ {
+ "markdown": "- Foo\n\n bar\n\n\n baz\n",
+ "html": "<ul>\n<li>\n<p>Foo</p>\n<pre><code>bar\n\n\nbaz\n</code></pre>\n</li>\n</ul>\n",
+ "example": 242,
+ "start_line": 4220,
+ "end_line": 4238,
+ "section": "List items",
+ "extensions": []
+ },
+ {
+ "markdown": "123456789. ok\n",
+ "html": "<ol start=\"123456789\">\n<li>ok</li>\n</ol>\n",
+ "example": 243,
+ "start_line": 4242,
+ "end_line": 4248,
+ "section": "List items",
+ "extensions": []
+ },
+ {
+ "markdown": "1234567890. not ok\n",
+ "html": "<p>1234567890. not ok</p>\n",
+ "example": 244,
+ "start_line": 4251,
+ "end_line": 4255,
+ "section": "List items",
+ "extensions": []
+ },
+ {
+ "markdown": "0. ok\n",
+ "html": "<ol start=\"0\">\n<li>ok</li>\n</ol>\n",
+ "example": 245,
+ "start_line": 4260,
+ "end_line": 4266,
+ "section": "List items",
+ "extensions": []
+ },
+ {
+ "markdown": "003. ok\n",
+ "html": "<ol start=\"3\">\n<li>ok</li>\n</ol>\n",
+ "example": 246,
+ "start_line": 4269,
+ "end_line": 4275,
+ "section": "List items",
+ "extensions": []
+ },
+ {
+ "markdown": "-1. not ok\n",
+ "html": "<p>-1. not ok</p>\n",
+ "example": 247,
+ "start_line": 4280,
+ "end_line": 4284,
+ "section": "List items",
+ "extensions": []
+ },
+ {
+ "markdown": "- foo\n\n bar\n",
+ "html": "<ul>\n<li>\n<p>foo</p>\n<pre><code>bar\n</code></pre>\n</li>\n</ul>\n",
+ "example": 248,
+ "start_line": 4303,
+ "end_line": 4315,
+ "section": "List items",
+ "extensions": []
+ },
+ {
+ "markdown": " 10. foo\n\n bar\n",
+ "html": "<ol start=\"10\">\n<li>\n<p>foo</p>\n<pre><code>bar\n</code></pre>\n</li>\n</ol>\n",
+ "example": 249,
+ "start_line": 4320,
+ "end_line": 4332,
+ "section": "List items",
+ "extensions": []
+ },
+ {
+ "markdown": " indented code\n\nparagraph\n\n more code\n",
+ "html": "<pre><code>indented code\n</code></pre>\n<p>paragraph</p>\n<pre><code>more code\n</code></pre>\n",
+ "example": 250,
+ "start_line": 4339,
+ "end_line": 4351,
+ "section": "List items",
+ "extensions": []
+ },
+ {
+ "markdown": "1. indented code\n\n paragraph\n\n more code\n",
+ "html": "<ol>\n<li>\n<pre><code>indented code\n</code></pre>\n<p>paragraph</p>\n<pre><code>more code\n</code></pre>\n</li>\n</ol>\n",
+ "example": 251,
+ "start_line": 4354,
+ "end_line": 4370,
+ "section": "List items",
+ "extensions": []
+ },
+ {
+ "markdown": "1. indented code\n\n paragraph\n\n more code\n",
+ "html": "<ol>\n<li>\n<pre><code> indented code\n</code></pre>\n<p>paragraph</p>\n<pre><code>more code\n</code></pre>\n</li>\n</ol>\n",
+ "example": 252,
+ "start_line": 4376,
+ "end_line": 4392,
+ "section": "List items",
+ "extensions": []
+ },
+ {
+ "markdown": " foo\n\nbar\n",
+ "html": "<p>foo</p>\n<p>bar</p>\n",
+ "example": 253,
+ "start_line": 4403,
+ "end_line": 4410,
+ "section": "List items",
+ "extensions": []
+ },
+ {
+ "markdown": "- foo\n\n bar\n",
+ "html": "<ul>\n<li>foo</li>\n</ul>\n<p>bar</p>\n",
+ "example": 254,
+ "start_line": 4413,
+ "end_line": 4422,
+ "section": "List items",
+ "extensions": []
+ },
+ {
+ "markdown": "- foo\n\n bar\n",
+ "html": "<ul>\n<li>\n<p>foo</p>\n<p>bar</p>\n</li>\n</ul>\n",
+ "example": 255,
+ "start_line": 4430,
+ "end_line": 4441,
+ "section": "List items",
+ "extensions": []
+ },
+ {
+ "markdown": "-\n foo\n-\n ```\n bar\n ```\n-\n baz\n",
+ "html": "<ul>\n<li>foo</li>\n<li>\n<pre><code>bar\n</code></pre>\n</li>\n<li>\n<pre><code>baz\n</code></pre>\n</li>\n</ul>\n",
+ "example": 256,
+ "start_line": 4458,
+ "end_line": 4479,
+ "section": "List items",
+ "extensions": []
+ },
+ {
+ "markdown": "- \n foo\n",
+ "html": "<ul>\n<li>foo</li>\n</ul>\n",
+ "example": 257,
+ "start_line": 4484,
+ "end_line": 4491,
+ "section": "List items",
+ "extensions": []
+ },
+ {
+ "markdown": "-\n\n foo\n",
+ "html": "<ul>\n<li></li>\n</ul>\n<p>foo</p>\n",
+ "example": 258,
+ "start_line": 4498,
+ "end_line": 4507,
+ "section": "List items",
+ "extensions": []
+ },
+ {
+ "markdown": "- foo\n-\n- bar\n",
+ "html": "<ul>\n<li>foo</li>\n<li></li>\n<li>bar</li>\n</ul>\n",
+ "example": 259,
+ "start_line": 4512,
+ "end_line": 4522,
+ "section": "List items",
+ "extensions": []
+ },
+ {
+ "markdown": "- foo\n- \n- bar\n",
+ "html": "<ul>\n<li>foo</li>\n<li></li>\n<li>bar</li>\n</ul>\n",
+ "example": 260,
+ "start_line": 4527,
+ "end_line": 4537,
+ "section": "List items",
+ "extensions": []
+ },
+ {
+ "markdown": "1. foo\n2.\n3. bar\n",
+ "html": "<ol>\n<li>foo</li>\n<li></li>\n<li>bar</li>\n</ol>\n",
+ "example": 261,
+ "start_line": 4542,
+ "end_line": 4552,
+ "section": "List items",
+ "extensions": []
+ },
+ {
+ "markdown": "*\n",
+ "html": "<ul>\n<li></li>\n</ul>\n",
+ "example": 262,
+ "start_line": 4557,
+ "end_line": 4563,
+ "section": "List items",
+ "extensions": []
+ },
+ {
+ "markdown": "foo\n*\n\nfoo\n1.\n",
+ "html": "<p>foo\n*</p>\n<p>foo\n1.</p>\n",
+ "example": 263,
+ "start_line": 4567,
+ "end_line": 4578,
+ "section": "List items",
+ "extensions": []
+ },
+ {
+ "markdown": " 1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.\n",
+ "html": "<ol>\n<li>\n<p>A paragraph\nwith two lines.</p>\n<pre><code>indented code\n</code></pre>\n<blockquote>\n<p>A block quote.</p>\n</blockquote>\n</li>\n</ol>\n",
+ "example": 264,
+ "start_line": 4589,
+ "end_line": 4608,
+ "section": "List items",
+ "extensions": []
+ },
+ {
+ "markdown": " 1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.\n",
+ "html": "<ol>\n<li>\n<p>A paragraph\nwith two lines.</p>\n<pre><code>indented code\n</code></pre>\n<blockquote>\n<p>A block quote.</p>\n</blockquote>\n</li>\n</ol>\n",
+ "example": 265,
+ "start_line": 4613,
+ "end_line": 4632,
+ "section": "List items",
+ "extensions": []
+ },
+ {
+ "markdown": " 1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.\n",
+ "html": "<ol>\n<li>\n<p>A paragraph\nwith two lines.</p>\n<pre><code>indented code\n</code></pre>\n<blockquote>\n<p>A block quote.</p>\n</blockquote>\n</li>\n</ol>\n",
+ "example": 266,
+ "start_line": 4637,
+ "end_line": 4656,
+ "section": "List items",
+ "extensions": []
+ },
+ {
+ "markdown": " 1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.\n",
+ "html": "<pre><code>1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.\n</code></pre>\n",
+ "example": 267,
+ "start_line": 4661,
+ "end_line": 4676,
+ "section": "List items",
+ "extensions": []
+ },
+ {
+ "markdown": " 1. A paragraph\nwith two lines.\n\n indented code\n\n > A block quote.\n",
+ "html": "<ol>\n<li>\n<p>A paragraph\nwith two lines.</p>\n<pre><code>indented code\n</code></pre>\n<blockquote>\n<p>A block quote.</p>\n</blockquote>\n</li>\n</ol>\n",
+ "example": 268,
+ "start_line": 4691,
+ "end_line": 4710,
+ "section": "List items",
+ "extensions": []
+ },
+ {
+ "markdown": " 1. A paragraph\n with two lines.\n",
+ "html": "<ol>\n<li>A paragraph\nwith two lines.</li>\n</ol>\n",
+ "example": 269,
+ "start_line": 4715,
+ "end_line": 4723,
+ "section": "List items",
+ "extensions": []
+ },
+ {
+ "markdown": "> 1. > Blockquote\ncontinued here.\n",
+ "html": "<blockquote>\n<ol>\n<li>\n<blockquote>\n<p>Blockquote\ncontinued here.</p>\n</blockquote>\n</li>\n</ol>\n</blockquote>\n",
+ "example": 270,
+ "start_line": 4728,
+ "end_line": 4742,
+ "section": "List items",
+ "extensions": []
+ },
+ {
+ "markdown": "> 1. > Blockquote\n> continued here.\n",
+ "html": "<blockquote>\n<ol>\n<li>\n<blockquote>\n<p>Blockquote\ncontinued here.</p>\n</blockquote>\n</li>\n</ol>\n</blockquote>\n",
+ "example": 271,
+ "start_line": 4745,
+ "end_line": 4759,
+ "section": "List items",
+ "extensions": []
+ },
+ {
+ "markdown": "- foo\n - bar\n - baz\n - boo\n",
+ "html": "<ul>\n<li>foo\n<ul>\n<li>bar\n<ul>\n<li>baz\n<ul>\n<li>boo</li>\n</ul>\n</li>\n</ul>\n</li>\n</ul>\n</li>\n</ul>\n",
+ "example": 272,
+ "start_line": 4773,
+ "end_line": 4794,
+ "section": "List items",
+ "extensions": []
+ },
+ {
+ "markdown": "- foo\n - bar\n - baz\n - boo\n",
+ "html": "<ul>\n<li>foo</li>\n<li>bar</li>\n<li>baz</li>\n<li>boo</li>\n</ul>\n",
+ "example": 273,
+ "start_line": 4799,
+ "end_line": 4811,
+ "section": "List items",
+ "extensions": []
+ },
+ {
+ "markdown": "10) foo\n - bar\n",
+ "html": "<ol start=\"10\">\n<li>foo\n<ul>\n<li>bar</li>\n</ul>\n</li>\n</ol>\n",
+ "example": 274,
+ "start_line": 4816,
+ "end_line": 4827,
+ "section": "List items",
+ "extensions": []
+ },
+ {
+ "markdown": "10) foo\n - bar\n",
+ "html": "<ol start=\"10\">\n<li>foo</li>\n</ol>\n<ul>\n<li>bar</li>\n</ul>\n",
+ "example": 275,
+ "start_line": 4832,
+ "end_line": 4842,
+ "section": "List items",
+ "extensions": []
+ },
+ {
+ "markdown": "- - foo\n",
+ "html": "<ul>\n<li>\n<ul>\n<li>foo</li>\n</ul>\n</li>\n</ul>\n",
+ "example": 276,
+ "start_line": 4847,
+ "end_line": 4857,
+ "section": "List items",
+ "extensions": []
+ },
+ {
+ "markdown": "1. - 2. foo\n",
+ "html": "<ol>\n<li>\n<ul>\n<li>\n<ol start=\"2\">\n<li>foo</li>\n</ol>\n</li>\n</ul>\n</li>\n</ol>\n",
+ "example": 277,
+ "start_line": 4860,
+ "end_line": 4874,
+ "section": "List items",
+ "extensions": []
+ },
+ {
+ "markdown": "- # Foo\n- Bar\n ---\n baz\n",
+ "html": "<ul>\n<li>\n<h1>Foo</h1>\n</li>\n<li>\n<h2>Bar</h2>\nbaz</li>\n</ul>\n",
+ "example": 278,
+ "start_line": 4879,
+ "end_line": 4893,
+ "section": "List items",
+ "extensions": []
+ },
+ {
+ "markdown": "- foo\n- bar\n+ baz\n",
+ "html": "<ul>\n<li>foo</li>\n<li>bar</li>\n</ul>\n<ul>\n<li>baz</li>\n</ul>\n",
+ "example": 281,
+ "start_line": 5172,
+ "end_line": 5184,
+ "section": "Lists",
+ "extensions": []
+ },
+ {
+ "markdown": "1. foo\n2. bar\n3) baz\n",
+ "html": "<ol>\n<li>foo</li>\n<li>bar</li>\n</ol>\n<ol start=\"3\">\n<li>baz</li>\n</ol>\n",
+ "example": 282,
+ "start_line": 5187,
+ "end_line": 5199,
+ "section": "Lists",
+ "extensions": []
+ },
+ {
+ "markdown": "Foo\n- bar\n- baz\n",
+ "html": "<p>Foo</p>\n<ul>\n<li>bar</li>\n<li>baz</li>\n</ul>\n",
+ "example": 283,
+ "start_line": 5206,
+ "end_line": 5216,
+ "section": "Lists",
+ "extensions": []
+ },
+ {
+ "markdown": "The number of windows in my house is\n14. The number of doors is 6.\n",
+ "html": "<p>The number of windows in my house is\n14. The number of doors is 6.</p>\n",
+ "example": 284,
+ "start_line": 5283,
+ "end_line": 5289,
+ "section": "Lists",
+ "extensions": []
+ },
+ {
+ "markdown": "The number of windows in my house is\n1. The number of doors is 6.\n",
+ "html": "<p>The number of windows in my house is</p>\n<ol>\n<li>The number of doors is 6.</li>\n</ol>\n",
+ "example": 285,
+ "start_line": 5293,
+ "end_line": 5301,
+ "section": "Lists",
+ "extensions": []
+ },
+ {
+ "markdown": "- foo\n\n- bar\n\n\n- baz\n",
+ "html": "<ul>\n<li>\n<p>foo</p>\n</li>\n<li>\n<p>bar</p>\n</li>\n<li>\n<p>baz</p>\n</li>\n</ul>\n",
+ "example": 286,
+ "start_line": 5307,
+ "end_line": 5326,
+ "section": "Lists",
+ "extensions": []
+ },
+ {
+ "markdown": "- foo\n - bar\n - baz\n\n\n bim\n",
+ "html": "<ul>\n<li>foo\n<ul>\n<li>bar\n<ul>\n<li>\n<p>baz</p>\n<p>bim</p>\n</li>\n</ul>\n</li>\n</ul>\n</li>\n</ul>\n",
+ "example": 287,
+ "start_line": 5328,
+ "end_line": 5350,
+ "section": "Lists",
+ "extensions": []
+ },
+ {
+ "markdown": "- foo\n- bar\n\n<!-- -->\n\n- baz\n- bim\n",
+ "html": "<ul>\n<li>foo</li>\n<li>bar</li>\n</ul>\n<!-- -->\n<ul>\n<li>baz</li>\n<li>bim</li>\n</ul>\n",
+ "example": 288,
+ "start_line": 5358,
+ "end_line": 5376,
+ "section": "Lists",
+ "extensions": []
+ },
+ {
+ "markdown": "- foo\n\n notcode\n\n- foo\n\n<!-- -->\n\n code\n",
+ "html": "<ul>\n<li>\n<p>foo</p>\n<p>notcode</p>\n</li>\n<li>\n<p>foo</p>\n</li>\n</ul>\n<!-- -->\n<pre><code>code\n</code></pre>\n",
+ "example": 289,
+ "start_line": 5379,
+ "end_line": 5402,
+ "section": "Lists",
+ "extensions": []
+ },
+ {
+ "markdown": "- a\n - b\n - c\n - d\n - e\n - f\n- g\n",
+ "html": "<ul>\n<li>a</li>\n<li>b</li>\n<li>c</li>\n<li>d</li>\n<li>e</li>\n<li>f</li>\n<li>g</li>\n</ul>\n",
+ "example": 290,
+ "start_line": 5410,
+ "end_line": 5428,
+ "section": "Lists",
+ "extensions": []
+ },
+ {
+ "markdown": "1. a\n\n 2. b\n\n 3. c\n",
+ "html": "<ol>\n<li>\n<p>a</p>\n</li>\n<li>\n<p>b</p>\n</li>\n<li>\n<p>c</p>\n</li>\n</ol>\n",
+ "example": 291,
+ "start_line": 5431,
+ "end_line": 5449,
+ "section": "Lists",
+ "extensions": []
+ },
+ {
+ "markdown": "- a\n - b\n - c\n - d\n - e\n",
+ "html": "<ul>\n<li>a</li>\n<li>b</li>\n<li>c</li>\n<li>d\n- e</li>\n</ul>\n",
+ "example": 292,
+ "start_line": 5455,
+ "end_line": 5469,
+ "section": "Lists",
+ "extensions": []
+ },
+ {
+ "markdown": "1. a\n\n 2. b\n\n 3. c\n",
+ "html": "<ol>\n<li>\n<p>a</p>\n</li>\n<li>\n<p>b</p>\n</li>\n</ol>\n<pre><code>3. c\n</code></pre>\n",
+ "example": 293,
+ "start_line": 5475,
+ "end_line": 5492,
+ "section": "Lists",
+ "extensions": []
+ },
+ {
+ "markdown": "- a\n- b\n\n- c\n",
+ "html": "<ul>\n<li>\n<p>a</p>\n</li>\n<li>\n<p>b</p>\n</li>\n<li>\n<p>c</p>\n</li>\n</ul>\n",
+ "example": 294,
+ "start_line": 5498,
+ "end_line": 5515,
+ "section": "Lists",
+ "extensions": []
+ },
+ {
+ "markdown": "* a\n*\n\n* c\n",
+ "html": "<ul>\n<li>\n<p>a</p>\n</li>\n<li></li>\n<li>\n<p>c</p>\n</li>\n</ul>\n",
+ "example": 295,
+ "start_line": 5520,
+ "end_line": 5535,
+ "section": "Lists",
+ "extensions": []
+ },
+ {
+ "markdown": "- a\n- b\n\n c\n- d\n",
+ "html": "<ul>\n<li>\n<p>a</p>\n</li>\n<li>\n<p>b</p>\n<p>c</p>\n</li>\n<li>\n<p>d</p>\n</li>\n</ul>\n",
+ "example": 296,
+ "start_line": 5542,
+ "end_line": 5561,
+ "section": "Lists",
+ "extensions": []
+ },
+ {
+ "markdown": "- a\n- b\n\n [ref]: /url\n- d\n",
+ "html": "<ul>\n<li>\n<p>a</p>\n</li>\n<li>\n<p>b</p>\n</li>\n<li>\n<p>d</p>\n</li>\n</ul>\n",
+ "example": 297,
+ "start_line": 5564,
+ "end_line": 5582,
+ "section": "Lists",
+ "extensions": []
+ },
+ {
+ "markdown": "- a\n- ```\n b\n\n\n ```\n- c\n",
+ "html": "<ul>\n<li>a</li>\n<li>\n<pre><code>b\n\n\n</code></pre>\n</li>\n<li>c</li>\n</ul>\n",
+ "example": 298,
+ "start_line": 5587,
+ "end_line": 5606,
+ "section": "Lists",
+ "extensions": []
+ },
+ {
+ "markdown": "- a\n - b\n\n c\n- d\n",
+ "html": "<ul>\n<li>a\n<ul>\n<li>\n<p>b</p>\n<p>c</p>\n</li>\n</ul>\n</li>\n<li>d</li>\n</ul>\n",
+ "example": 299,
+ "start_line": 5613,
+ "end_line": 5631,
+ "section": "Lists",
+ "extensions": []
+ },
+ {
+ "markdown": "* a\n > b\n >\n* c\n",
+ "html": "<ul>\n<li>a\n<blockquote>\n<p>b</p>\n</blockquote>\n</li>\n<li>c</li>\n</ul>\n",
+ "example": 300,
+ "start_line": 5637,
+ "end_line": 5651,
+ "section": "Lists",
+ "extensions": []
+ },
+ {
+ "markdown": "- a\n > b\n ```\n c\n ```\n- d\n",
+ "html": "<ul>\n<li>a\n<blockquote>\n<p>b</p>\n</blockquote>\n<pre><code>c\n</code></pre>\n</li>\n<li>d</li>\n</ul>\n",
+ "example": 301,
+ "start_line": 5657,
+ "end_line": 5675,
+ "section": "Lists",
+ "extensions": []
+ },
+ {
+ "markdown": "- a\n",
+ "html": "<ul>\n<li>a</li>\n</ul>\n",
+ "example": 302,
+ "start_line": 5680,
+ "end_line": 5686,
+ "section": "Lists",
+ "extensions": []
+ },
+ {
+ "markdown": "- a\n - b\n",
+ "html": "<ul>\n<li>a\n<ul>\n<li>b</li>\n</ul>\n</li>\n</ul>\n",
+ "example": 303,
+ "start_line": 5689,
+ "end_line": 5700,
+ "section": "Lists",
+ "extensions": []
+ },
+ {
+ "markdown": "1. ```\n foo\n ```\n\n bar\n",
+ "html": "<ol>\n<li>\n<pre><code>foo\n</code></pre>\n<p>bar</p>\n</li>\n</ol>\n",
+ "example": 304,
+ "start_line": 5706,
+ "end_line": 5720,
+ "section": "Lists",
+ "extensions": []
+ },
+ {
+ "markdown": "* foo\n * bar\n\n baz\n",
+ "html": "<ul>\n<li>\n<p>foo</p>\n<ul>\n<li>bar</li>\n</ul>\n<p>baz</p>\n</li>\n</ul>\n",
+ "example": 305,
+ "start_line": 5725,
+ "end_line": 5740,
+ "section": "Lists",
+ "extensions": []
+ },
+ {
+ "markdown": "- a\n - b\n - c\n\n- d\n - e\n - f\n",
+ "html": "<ul>\n<li>\n<p>a</p>\n<ul>\n<li>b</li>\n<li>c</li>\n</ul>\n</li>\n<li>\n<p>d</p>\n<ul>\n<li>e</li>\n<li>f</li>\n</ul>\n</li>\n</ul>\n",
+ "example": 306,
+ "start_line": 5743,
+ "end_line": 5768,
+ "section": "Lists",
+ "extensions": []
+ },
+ {
+ "markdown": "`hi`lo`\n",
+ "html": "<p><code>hi</code>lo`</p>\n",
+ "example": 307,
+ "start_line": 5777,
+ "end_line": 5781,
+ "section": "Inlines",
+ "extensions": []
+ },
+ {
+ "markdown": "\\!\\\"\\#\\$\\%\\&\\'\\(\\)\\*\\+\\,\\-\\.\\/\\:\\;\\<\\=\\>\\?\\@\\[\\\\\\]\\^\\_\\`\\{\\|\\}\\~\n",
+ "html": "<p>!"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~</p>\n",
+ "example": 308,
+ "start_line": 5791,
+ "end_line": 5795,
+ "section": "Backslash escapes",
+ "extensions": []
+ },
+ {
+ "markdown": "\\\t\\A\\a\\ \\3\\\u03c6\\\u00ab\n",
+ "html": "<p>\\\t\\A\\a\\ \\3\\\u03c6\\\u00ab</p>\n",
+ "example": 309,
+ "start_line": 5801,
+ "end_line": 5805,
+ "section": "Backslash escapes",
+ "extensions": []
+ },
+ {
+ "markdown": "\\*not emphasized*\n\\<br/> not a tag\n\\[not a link](/foo)\n\\`not code`\n1\\. not a list\n\\* not a list\n\\# not a heading\n\\[foo]: /url \"not a reference\"\n\\ö not a character entity\n",
+ "html": "<p>*not emphasized*\n<br/> not a tag\n[not a link](/foo)\n`not code`\n1. not a list\n* not a list\n# not a heading\n[foo]: /url "not a reference"\n&ouml; not a character entity</p>\n",
+ "example": 310,
+ "start_line": 5811,
+ "end_line": 5831,
+ "section": "Backslash escapes",
+ "extensions": []
+ },
+ {
+ "markdown": "\\\\*emphasis*\n",
+ "html": "<p>\\<em>emphasis</em></p>\n",
+ "example": 311,
+ "start_line": 5836,
+ "end_line": 5840,
+ "section": "Backslash escapes",
+ "extensions": []
+ },
+ {
+ "markdown": "foo\\\nbar\n",
+ "html": "<p>foo<br />\nbar</p>\n",
+ "example": 312,
+ "start_line": 5845,
+ "end_line": 5851,
+ "section": "Backslash escapes",
+ "extensions": []
+ },
+ {
+ "markdown": "`` \\[\\` ``\n",
+ "html": "<p><code>\\[\\`</code></p>\n",
+ "example": 313,
+ "start_line": 5857,
+ "end_line": 5861,
+ "section": "Backslash escapes",
+ "extensions": []
+ },
+ {
+ "markdown": " \\[\\]\n",
+ "html": "<pre><code>\\[\\]\n</code></pre>\n",
+ "example": 314,
+ "start_line": 5864,
+ "end_line": 5869,
+ "section": "Backslash escapes",
+ "extensions": []
+ },
+ {
+ "markdown": "~~~\n\\[\\]\n~~~\n",
+ "html": "<pre><code>\\[\\]\n</code></pre>\n",
+ "example": 315,
+ "start_line": 5872,
+ "end_line": 5879,
+ "section": "Backslash escapes",
+ "extensions": []
+ },
+ {
+ "markdown": "<http://example.com?find=\\*>\n",
+ "html": "<p><a href=\"http://example.com?find=%5C*\">http://example.com?find=\\*</a></p>\n",
+ "example": 316,
+ "start_line": 5882,
+ "end_line": 5886,
+ "section": "Backslash escapes",
+ "extensions": []
+ },
+ {
+ "markdown": "<a href=\"/bar\\/)\">\n",
+ "html": "<a href=\"/bar\\/)\">\n",
+ "example": 317,
+ "start_line": 5889,
+ "end_line": 5893,
+ "section": "Backslash escapes",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo](/bar\\* \"ti\\*tle\")\n",
+ "html": "<p><a href=\"/bar*\" title=\"ti*tle\">foo</a></p>\n",
+ "example": 318,
+ "start_line": 5899,
+ "end_line": 5903,
+ "section": "Backslash escapes",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo]\n\n[foo]: /bar\\* \"ti\\*tle\"\n",
+ "html": "<p><a href=\"/bar*\" title=\"ti*tle\">foo</a></p>\n",
+ "example": 319,
+ "start_line": 5906,
+ "end_line": 5912,
+ "section": "Backslash escapes",
+ "extensions": []
+ },
+ {
+ "markdown": "``` foo\\+bar\nfoo\n```\n",
+ "html": "<pre><code class=\"language-foo+bar\">foo\n</code></pre>\n",
+ "example": 320,
+ "start_line": 5915,
+ "end_line": 5922,
+ "section": "Backslash escapes",
+ "extensions": []
+ },
+ {
+ "markdown": " & © Æ Ď\n¾ ℋ ⅆ\n∲ ≧̸\n",
+ "html": "<p>\u00a0 & \u00a9 \u00c6 \u010e\n\u00be \u210b \u2146\n\u2232 \u2267\u0338</p>\n",
+ "example": 321,
+ "start_line": 5952,
+ "end_line": 5960,
+ "section": "Entity and numeric character references",
+ "extensions": []
+ },
+ {
+ "markdown": "# Ӓ Ϡ �\n",
+ "html": "<p># \u04d2 \u03e0 \ufffd</p>\n",
+ "example": 322,
+ "start_line": 5971,
+ "end_line": 5975,
+ "section": "Entity and numeric character references",
+ "extensions": []
+ },
+ {
+ "markdown": "" ആ ಫ\n",
+ "html": "<p>" \u0d06 \u0cab</p>\n",
+ "example": 323,
+ "start_line": 5984,
+ "end_line": 5988,
+ "section": "Entity and numeric character references",
+ "extensions": []
+ },
+ {
+ "markdown": "  &x; &#; &#x;\n�\n&#abcdef0;\n&ThisIsNotDefined; &hi?;\n",
+ "html": "<p>&nbsp &x; &#; &#x;\n&#987654321;\n&#abcdef0;\n&ThisIsNotDefined; &hi?;</p>\n",
+ "example": 324,
+ "start_line": 5993,
+ "end_line": 6003,
+ "section": "Entity and numeric character references",
+ "extensions": []
+ },
+ {
+ "markdown": "©\n",
+ "html": "<p>&copy</p>\n",
+ "example": 325,
+ "start_line": 6010,
+ "end_line": 6014,
+ "section": "Entity and numeric character references",
+ "extensions": []
+ },
+ {
+ "markdown": "&MadeUpEntity;\n",
+ "html": "<p>&MadeUpEntity;</p>\n",
+ "example": 326,
+ "start_line": 6020,
+ "end_line": 6024,
+ "section": "Entity and numeric character references",
+ "extensions": []
+ },
+ {
+ "markdown": "<a href=\"öö.html\">\n",
+ "html": "<a href=\"öö.html\">\n",
+ "example": 327,
+ "start_line": 6031,
+ "end_line": 6035,
+ "section": "Entity and numeric character references",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo](/föö \"föö\")\n",
+ "html": "<p><a href=\"/f%C3%B6%C3%B6\" title=\"f\u00f6\u00f6\">foo</a></p>\n",
+ "example": 328,
+ "start_line": 6038,
+ "end_line": 6042,
+ "section": "Entity and numeric character references",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo]\n\n[foo]: /föö \"föö\"\n",
+ "html": "<p><a href=\"/f%C3%B6%C3%B6\" title=\"f\u00f6\u00f6\">foo</a></p>\n",
+ "example": 329,
+ "start_line": 6045,
+ "end_line": 6051,
+ "section": "Entity and numeric character references",
+ "extensions": []
+ },
+ {
+ "markdown": "``` föö\nfoo\n```\n",
+ "html": "<pre><code class=\"language-f\u00f6\u00f6\">foo\n</code></pre>\n",
+ "example": 330,
+ "start_line": 6054,
+ "end_line": 6061,
+ "section": "Entity and numeric character references",
+ "extensions": []
+ },
+ {
+ "markdown": "`föö`\n",
+ "html": "<p><code>f&ouml;&ouml;</code></p>\n",
+ "example": 331,
+ "start_line": 6067,
+ "end_line": 6071,
+ "section": "Entity and numeric character references",
+ "extensions": []
+ },
+ {
+ "markdown": " föfö\n",
+ "html": "<pre><code>f&ouml;f&ouml;\n</code></pre>\n",
+ "example": 332,
+ "start_line": 6074,
+ "end_line": 6079,
+ "section": "Entity and numeric character references",
+ "extensions": []
+ },
+ {
+ "markdown": "*foo*\n*foo*\n",
+ "html": "<p>*foo*\n<em>foo</em></p>\n",
+ "example": 333,
+ "start_line": 6086,
+ "end_line": 6092,
+ "section": "Entity and numeric character references",
+ "extensions": []
+ },
+ {
+ "markdown": "* foo\n\n* foo\n",
+ "html": "<p>* foo</p>\n<ul>\n<li>foo</li>\n</ul>\n",
+ "example": 334,
+ "start_line": 6094,
+ "end_line": 6103,
+ "section": "Entity and numeric character references",
+ "extensions": []
+ },
+ {
+ "markdown": "foo bar\n",
+ "html": "<p>foo\n\nbar</p>\n",
+ "example": 335,
+ "start_line": 6105,
+ "end_line": 6111,
+ "section": "Entity and numeric character references",
+ "extensions": []
+ },
+ {
+ "markdown": "	foo\n",
+ "html": "<p>\tfoo</p>\n",
+ "example": 336,
+ "start_line": 6113,
+ "end_line": 6117,
+ "section": "Entity and numeric character references",
+ "extensions": []
+ },
+ {
+ "markdown": "[a](url "tit")\n",
+ "html": "<p>[a](url "tit")</p>\n",
+ "example": 337,
+ "start_line": 6120,
+ "end_line": 6124,
+ "section": "Entity and numeric character references",
+ "extensions": []
+ },
+ {
+ "markdown": "`foo`\n",
+ "html": "<p><code>foo</code></p>\n",
+ "example": 338,
+ "start_line": 6148,
+ "end_line": 6152,
+ "section": "Code spans",
+ "extensions": []
+ },
+ {
+ "markdown": "`` foo ` bar ``\n",
+ "html": "<p><code>foo ` bar</code></p>\n",
+ "example": 339,
+ "start_line": 6159,
+ "end_line": 6163,
+ "section": "Code spans",
+ "extensions": []
+ },
+ {
+ "markdown": "` `` `\n",
+ "html": "<p><code>``</code></p>\n",
+ "example": 340,
+ "start_line": 6169,
+ "end_line": 6173,
+ "section": "Code spans",
+ "extensions": []
+ },
+ {
+ "markdown": "` `` `\n",
+ "html": "<p><code> `` </code></p>\n",
+ "example": 341,
+ "start_line": 6177,
+ "end_line": 6181,
+ "section": "Code spans",
+ "extensions": []
+ },
+ {
+ "markdown": "` a`\n",
+ "html": "<p><code> a</code></p>\n",
+ "example": 342,
+ "start_line": 6186,
+ "end_line": 6190,
+ "section": "Code spans",
+ "extensions": []
+ },
+ {
+ "markdown": "`\u00a0b\u00a0`\n",
+ "html": "<p><code>\u00a0b\u00a0</code></p>\n",
+ "example": 343,
+ "start_line": 6195,
+ "end_line": 6199,
+ "section": "Code spans",
+ "extensions": []
+ },
+ {
+ "markdown": "`\u00a0`\n` `\n",
+ "html": "<p><code>\u00a0</code>\n<code> </code></p>\n",
+ "example": 344,
+ "start_line": 6203,
+ "end_line": 6209,
+ "section": "Code spans",
+ "extensions": []
+ },
+ {
+ "markdown": "``\nfoo\nbar \nbaz\n``\n",
+ "html": "<p><code>foo bar baz</code></p>\n",
+ "example": 345,
+ "start_line": 6214,
+ "end_line": 6222,
+ "section": "Code spans",
+ "extensions": []
+ },
+ {
+ "markdown": "``\nfoo \n``\n",
+ "html": "<p><code>foo </code></p>\n",
+ "example": 346,
+ "start_line": 6224,
+ "end_line": 6230,
+ "section": "Code spans",
+ "extensions": []
+ },
+ {
+ "markdown": "`foo bar \nbaz`\n",
+ "html": "<p><code>foo bar baz</code></p>\n",
+ "example": 347,
+ "start_line": 6235,
+ "end_line": 6240,
+ "section": "Code spans",
+ "extensions": []
+ },
+ {
+ "markdown": "`foo\\`bar`\n",
+ "html": "<p><code>foo\\</code>bar`</p>\n",
+ "example": 348,
+ "start_line": 6252,
+ "end_line": 6256,
+ "section": "Code spans",
+ "extensions": []
+ },
+ {
+ "markdown": "``foo`bar``\n",
+ "html": "<p><code>foo`bar</code></p>\n",
+ "example": 349,
+ "start_line": 6263,
+ "end_line": 6267,
+ "section": "Code spans",
+ "extensions": []
+ },
+ {
+ "markdown": "` foo `` bar `\n",
+ "html": "<p><code>foo `` bar</code></p>\n",
+ "example": 350,
+ "start_line": 6269,
+ "end_line": 6273,
+ "section": "Code spans",
+ "extensions": []
+ },
+ {
+ "markdown": "*foo`*`\n",
+ "html": "<p>*foo<code>*</code></p>\n",
+ "example": 351,
+ "start_line": 6281,
+ "end_line": 6285,
+ "section": "Code spans",
+ "extensions": []
+ },
+ {
+ "markdown": "[not a `link](/foo`)\n",
+ "html": "<p>[not a <code>link](/foo</code>)</p>\n",
+ "example": 352,
+ "start_line": 6290,
+ "end_line": 6294,
+ "section": "Code spans",
+ "extensions": []
+ },
+ {
+ "markdown": "`<a href=\"`\">`\n",
+ "html": "<p><code><a href="</code>">`</p>\n",
+ "example": 353,
+ "start_line": 6300,
+ "end_line": 6304,
+ "section": "Code spans",
+ "extensions": []
+ },
+ {
+ "markdown": "<a href=\"`\">`\n",
+ "html": "<p><a href=\"`\">`</p>\n",
+ "example": 354,
+ "start_line": 6309,
+ "end_line": 6313,
+ "section": "Code spans",
+ "extensions": []
+ },
+ {
+ "markdown": "`<http://foo.bar.`baz>`\n",
+ "html": "<p><code><http://foo.bar.</code>baz>`</p>\n",
+ "example": 355,
+ "start_line": 6318,
+ "end_line": 6322,
+ "section": "Code spans",
+ "extensions": []
+ },
+ {
+ "markdown": "<http://foo.bar.`baz>`\n",
+ "html": "<p><a href=\"http://foo.bar.%60baz\">http://foo.bar.`baz</a>`</p>\n",
+ "example": 356,
+ "start_line": 6327,
+ "end_line": 6331,
+ "section": "Code spans",
+ "extensions": []
+ },
+ {
+ "markdown": "```foo``\n",
+ "html": "<p>```foo``</p>\n",
+ "example": 357,
+ "start_line": 6337,
+ "end_line": 6341,
+ "section": "Code spans",
+ "extensions": []
+ },
+ {
+ "markdown": "`foo\n",
+ "html": "<p>`foo</p>\n",
+ "example": 358,
+ "start_line": 6344,
+ "end_line": 6348,
+ "section": "Code spans",
+ "extensions": []
+ },
+ {
+ "markdown": "`foo``bar``\n",
+ "html": "<p>`foo<code>bar</code></p>\n",
+ "example": 359,
+ "start_line": 6353,
+ "end_line": 6357,
+ "section": "Code spans",
+ "extensions": []
+ },
+ {
+ "markdown": "*foo bar*\n",
+ "html": "<p><em>foo bar</em></p>\n",
+ "example": 360,
+ "start_line": 6570,
+ "end_line": 6574,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "a * foo bar*\n",
+ "html": "<p>a * foo bar*</p>\n",
+ "example": 361,
+ "start_line": 6580,
+ "end_line": 6584,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "a*\"foo\"*\n",
+ "html": "<p>a*"foo"*</p>\n",
+ "example": 362,
+ "start_line": 6591,
+ "end_line": 6595,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "*\u00a0a\u00a0*\n",
+ "html": "<p>*\u00a0a\u00a0*</p>\n",
+ "example": 363,
+ "start_line": 6600,
+ "end_line": 6604,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "foo*bar*\n",
+ "html": "<p>foo<em>bar</em></p>\n",
+ "example": 364,
+ "start_line": 6609,
+ "end_line": 6613,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "5*6*78\n",
+ "html": "<p>5<em>6</em>78</p>\n",
+ "example": 365,
+ "start_line": 6616,
+ "end_line": 6620,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "_foo bar_\n",
+ "html": "<p><em>foo bar</em></p>\n",
+ "example": 366,
+ "start_line": 6625,
+ "end_line": 6629,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "_ foo bar_\n",
+ "html": "<p>_ foo bar_</p>\n",
+ "example": 367,
+ "start_line": 6635,
+ "end_line": 6639,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "a_\"foo\"_\n",
+ "html": "<p>a_"foo"_</p>\n",
+ "example": 368,
+ "start_line": 6645,
+ "end_line": 6649,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "foo_bar_\n",
+ "html": "<p>foo_bar_</p>\n",
+ "example": 369,
+ "start_line": 6654,
+ "end_line": 6658,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "5_6_78\n",
+ "html": "<p>5_6_78</p>\n",
+ "example": 370,
+ "start_line": 6661,
+ "end_line": 6665,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "\u043f\u0440\u0438\u0441\u0442\u0430\u043d\u044f\u043c_\u0441\u0442\u0440\u0435\u043c\u044f\u0442\u0441\u044f_\n",
+ "html": "<p>\u043f\u0440\u0438\u0441\u0442\u0430\u043d\u044f\u043c_\u0441\u0442\u0440\u0435\u043c\u044f\u0442\u0441\u044f_</p>\n",
+ "example": 371,
+ "start_line": 6668,
+ "end_line": 6672,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "aa_\"bb\"_cc\n",
+ "html": "<p>aa_"bb"_cc</p>\n",
+ "example": 372,
+ "start_line": 6678,
+ "end_line": 6682,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "foo-_(bar)_\n",
+ "html": "<p>foo-<em>(bar)</em></p>\n",
+ "example": 373,
+ "start_line": 6689,
+ "end_line": 6693,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "_foo*\n",
+ "html": "<p>_foo*</p>\n",
+ "example": 374,
+ "start_line": 6701,
+ "end_line": 6705,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "*foo bar *\n",
+ "html": "<p>*foo bar *</p>\n",
+ "example": 375,
+ "start_line": 6711,
+ "end_line": 6715,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "*foo bar\n*\n",
+ "html": "<p>*foo bar\n*</p>\n",
+ "example": 376,
+ "start_line": 6720,
+ "end_line": 6726,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "*(*foo)\n",
+ "html": "<p>*(*foo)</p>\n",
+ "example": 377,
+ "start_line": 6733,
+ "end_line": 6737,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "*(*foo*)*\n",
+ "html": "<p><em>(<em>foo</em>)</em></p>\n",
+ "example": 378,
+ "start_line": 6743,
+ "end_line": 6747,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "*foo*bar\n",
+ "html": "<p><em>foo</em>bar</p>\n",
+ "example": 379,
+ "start_line": 6752,
+ "end_line": 6756,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "_foo bar _\n",
+ "html": "<p>_foo bar _</p>\n",
+ "example": 380,
+ "start_line": 6765,
+ "end_line": 6769,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "_(_foo)\n",
+ "html": "<p>_(_foo)</p>\n",
+ "example": 381,
+ "start_line": 6775,
+ "end_line": 6779,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "_(_foo_)_\n",
+ "html": "<p><em>(<em>foo</em>)</em></p>\n",
+ "example": 382,
+ "start_line": 6784,
+ "end_line": 6788,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "_foo_bar\n",
+ "html": "<p>_foo_bar</p>\n",
+ "example": 383,
+ "start_line": 6793,
+ "end_line": 6797,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "_\u043f\u0440\u0438\u0441\u0442\u0430\u043d\u044f\u043c_\u0441\u0442\u0440\u0435\u043c\u044f\u0442\u0441\u044f\n",
+ "html": "<p>_\u043f\u0440\u0438\u0441\u0442\u0430\u043d\u044f\u043c_\u0441\u0442\u0440\u0435\u043c\u044f\u0442\u0441\u044f</p>\n",
+ "example": 384,
+ "start_line": 6800,
+ "end_line": 6804,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "_foo_bar_baz_\n",
+ "html": "<p><em>foo_bar_baz</em></p>\n",
+ "example": 385,
+ "start_line": 6807,
+ "end_line": 6811,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "_(bar)_.\n",
+ "html": "<p><em>(bar)</em>.</p>\n",
+ "example": 386,
+ "start_line": 6818,
+ "end_line": 6822,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "**foo bar**\n",
+ "html": "<p><strong>foo bar</strong></p>\n",
+ "example": 387,
+ "start_line": 6827,
+ "end_line": 6831,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "** foo bar**\n",
+ "html": "<p>** foo bar**</p>\n",
+ "example": 388,
+ "start_line": 6837,
+ "end_line": 6841,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "a**\"foo\"**\n",
+ "html": "<p>a**"foo"**</p>\n",
+ "example": 389,
+ "start_line": 6848,
+ "end_line": 6852,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "foo**bar**\n",
+ "html": "<p>foo<strong>bar</strong></p>\n",
+ "example": 390,
+ "start_line": 6857,
+ "end_line": 6861,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "__foo bar__\n",
+ "html": "<p><strong>foo bar</strong></p>\n",
+ "example": 391,
+ "start_line": 6866,
+ "end_line": 6870,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "__ foo bar__\n",
+ "html": "<p>__ foo bar__</p>\n",
+ "example": 392,
+ "start_line": 6876,
+ "end_line": 6880,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "__\nfoo bar__\n",
+ "html": "<p>__\nfoo bar__</p>\n",
+ "example": 393,
+ "start_line": 6884,
+ "end_line": 6890,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "a__\"foo\"__\n",
+ "html": "<p>a__"foo"__</p>\n",
+ "example": 394,
+ "start_line": 6896,
+ "end_line": 6900,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "foo__bar__\n",
+ "html": "<p>foo__bar__</p>\n",
+ "example": 395,
+ "start_line": 6905,
+ "end_line": 6909,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "5__6__78\n",
+ "html": "<p>5__6__78</p>\n",
+ "example": 396,
+ "start_line": 6912,
+ "end_line": 6916,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "\u043f\u0440\u0438\u0441\u0442\u0430\u043d\u044f\u043c__\u0441\u0442\u0440\u0435\u043c\u044f\u0442\u0441\u044f__\n",
+ "html": "<p>\u043f\u0440\u0438\u0441\u0442\u0430\u043d\u044f\u043c__\u0441\u0442\u0440\u0435\u043c\u044f\u0442\u0441\u044f__</p>\n",
+ "example": 397,
+ "start_line": 6919,
+ "end_line": 6923,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "__foo, __bar__, baz__\n",
+ "html": "<p><strong>foo, <strong>bar</strong>, baz</strong></p>\n",
+ "example": 398,
+ "start_line": 6926,
+ "end_line": 6930,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "foo-__(bar)__\n",
+ "html": "<p>foo-<strong>(bar)</strong></p>\n",
+ "example": 399,
+ "start_line": 6937,
+ "end_line": 6941,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "**foo bar **\n",
+ "html": "<p>**foo bar **</p>\n",
+ "example": 400,
+ "start_line": 6950,
+ "end_line": 6954,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "**(**foo)\n",
+ "html": "<p>**(**foo)</p>\n",
+ "example": 401,
+ "start_line": 6963,
+ "end_line": 6967,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "*(**foo**)*\n",
+ "html": "<p><em>(<strong>foo</strong>)</em></p>\n",
+ "example": 402,
+ "start_line": 6973,
+ "end_line": 6977,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "**Gomphocarpus (*Gomphocarpus physocarpus*, syn.\n*Asclepias physocarpa*)**\n",
+ "html": "<p><strong>Gomphocarpus (<em>Gomphocarpus physocarpus</em>, syn.\n<em>Asclepias physocarpa</em>)</strong></p>\n",
+ "example": 403,
+ "start_line": 6980,
+ "end_line": 6986,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "**foo \"*bar*\" foo**\n",
+ "html": "<p><strong>foo "<em>bar</em>" foo</strong></p>\n",
+ "example": 404,
+ "start_line": 6989,
+ "end_line": 6993,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "**foo**bar\n",
+ "html": "<p><strong>foo</strong>bar</p>\n",
+ "example": 405,
+ "start_line": 6998,
+ "end_line": 7002,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "__foo bar __\n",
+ "html": "<p>__foo bar __</p>\n",
+ "example": 406,
+ "start_line": 7010,
+ "end_line": 7014,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "__(__foo)\n",
+ "html": "<p>__(__foo)</p>\n",
+ "example": 407,
+ "start_line": 7020,
+ "end_line": 7024,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "_(__foo__)_\n",
+ "html": "<p><em>(<strong>foo</strong>)</em></p>\n",
+ "example": 408,
+ "start_line": 7030,
+ "end_line": 7034,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "__foo__bar\n",
+ "html": "<p>__foo__bar</p>\n",
+ "example": 409,
+ "start_line": 7039,
+ "end_line": 7043,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "__\u043f\u0440\u0438\u0441\u0442\u0430\u043d\u044f\u043c__\u0441\u0442\u0440\u0435\u043c\u044f\u0442\u0441\u044f\n",
+ "html": "<p>__\u043f\u0440\u0438\u0441\u0442\u0430\u043d\u044f\u043c__\u0441\u0442\u0440\u0435\u043c\u044f\u0442\u0441\u044f</p>\n",
+ "example": 410,
+ "start_line": 7046,
+ "end_line": 7050,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "__foo__bar__baz__\n",
+ "html": "<p><strong>foo__bar__baz</strong></p>\n",
+ "example": 411,
+ "start_line": 7053,
+ "end_line": 7057,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "__(bar)__.\n",
+ "html": "<p><strong>(bar)</strong>.</p>\n",
+ "example": 412,
+ "start_line": 7064,
+ "end_line": 7068,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "*foo [bar](/url)*\n",
+ "html": "<p><em>foo <a href=\"/url\">bar</a></em></p>\n",
+ "example": 413,
+ "start_line": 7076,
+ "end_line": 7080,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "*foo\nbar*\n",
+ "html": "<p><em>foo\nbar</em></p>\n",
+ "example": 414,
+ "start_line": 7083,
+ "end_line": 7089,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "_foo __bar__ baz_\n",
+ "html": "<p><em>foo <strong>bar</strong> baz</em></p>\n",
+ "example": 415,
+ "start_line": 7095,
+ "end_line": 7099,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "_foo _bar_ baz_\n",
+ "html": "<p><em>foo <em>bar</em> baz</em></p>\n",
+ "example": 416,
+ "start_line": 7102,
+ "end_line": 7106,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "__foo_ bar_\n",
+ "html": "<p><em><em>foo</em> bar</em></p>\n",
+ "example": 417,
+ "start_line": 7109,
+ "end_line": 7113,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "*foo *bar**\n",
+ "html": "<p><em>foo <em>bar</em></em></p>\n",
+ "example": 418,
+ "start_line": 7116,
+ "end_line": 7120,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "*foo **bar** baz*\n",
+ "html": "<p><em>foo <strong>bar</strong> baz</em></p>\n",
+ "example": 419,
+ "start_line": 7123,
+ "end_line": 7127,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "*foo**bar**baz*\n",
+ "html": "<p><em>foo<strong>bar</strong>baz</em></p>\n",
+ "example": 420,
+ "start_line": 7129,
+ "end_line": 7133,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "*foo**bar*\n",
+ "html": "<p><em>foo**bar</em></p>\n",
+ "example": 421,
+ "start_line": 7153,
+ "end_line": 7157,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "***foo** bar*\n",
+ "html": "<p><em><strong>foo</strong> bar</em></p>\n",
+ "example": 422,
+ "start_line": 7166,
+ "end_line": 7170,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "*foo **bar***\n",
+ "html": "<p><em>foo <strong>bar</strong></em></p>\n",
+ "example": 423,
+ "start_line": 7173,
+ "end_line": 7177,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "*foo**bar***\n",
+ "html": "<p><em>foo<strong>bar</strong></em></p>\n",
+ "example": 424,
+ "start_line": 7180,
+ "end_line": 7184,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "foo***bar***baz\n",
+ "html": "<p>foo<em><strong>bar</strong></em>baz</p>\n",
+ "example": 425,
+ "start_line": 7191,
+ "end_line": 7195,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "foo******bar*********baz\n",
+ "html": "<p>foo<strong><strong><strong>bar</strong></strong></strong>***baz</p>\n",
+ "example": 426,
+ "start_line": 7197,
+ "end_line": 7201,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "*foo **bar *baz* bim** bop*\n",
+ "html": "<p><em>foo <strong>bar <em>baz</em> bim</strong> bop</em></p>\n",
+ "example": 427,
+ "start_line": 7206,
+ "end_line": 7210,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "*foo [*bar*](/url)*\n",
+ "html": "<p><em>foo <a href=\"/url\"><em>bar</em></a></em></p>\n",
+ "example": 428,
+ "start_line": 7213,
+ "end_line": 7217,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "** is not an empty emphasis\n",
+ "html": "<p>** is not an empty emphasis</p>\n",
+ "example": 429,
+ "start_line": 7222,
+ "end_line": 7226,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "**** is not an empty strong emphasis\n",
+ "html": "<p>**** is not an empty strong emphasis</p>\n",
+ "example": 430,
+ "start_line": 7229,
+ "end_line": 7233,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "**foo [bar](/url)**\n",
+ "html": "<p><strong>foo <a href=\"/url\">bar</a></strong></p>\n",
+ "example": 431,
+ "start_line": 7242,
+ "end_line": 7246,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "**foo\nbar**\n",
+ "html": "<p><strong>foo\nbar</strong></p>\n",
+ "example": 432,
+ "start_line": 7249,
+ "end_line": 7255,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "__foo _bar_ baz__\n",
+ "html": "<p><strong>foo <em>bar</em> baz</strong></p>\n",
+ "example": 433,
+ "start_line": 7261,
+ "end_line": 7265,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "__foo __bar__ baz__\n",
+ "html": "<p><strong>foo <strong>bar</strong> baz</strong></p>\n",
+ "example": 434,
+ "start_line": 7268,
+ "end_line": 7272,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "____foo__ bar__\n",
+ "html": "<p><strong><strong>foo</strong> bar</strong></p>\n",
+ "example": 435,
+ "start_line": 7275,
+ "end_line": 7279,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "**foo **bar****\n",
+ "html": "<p><strong>foo <strong>bar</strong></strong></p>\n",
+ "example": 436,
+ "start_line": 7282,
+ "end_line": 7286,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "**foo *bar* baz**\n",
+ "html": "<p><strong>foo <em>bar</em> baz</strong></p>\n",
+ "example": 437,
+ "start_line": 7289,
+ "end_line": 7293,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "**foo*bar*baz**\n",
+ "html": "<p><strong>foo<em>bar</em>baz</strong></p>\n",
+ "example": 438,
+ "start_line": 7296,
+ "end_line": 7300,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "***foo* bar**\n",
+ "html": "<p><strong><em>foo</em> bar</strong></p>\n",
+ "example": 439,
+ "start_line": 7303,
+ "end_line": 7307,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "**foo *bar***\n",
+ "html": "<p><strong>foo <em>bar</em></strong></p>\n",
+ "example": 440,
+ "start_line": 7310,
+ "end_line": 7314,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "**foo *bar **baz**\nbim* bop**\n",
+ "html": "<p><strong>foo <em>bar <strong>baz</strong>\nbim</em> bop</strong></p>\n",
+ "example": 441,
+ "start_line": 7319,
+ "end_line": 7325,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "**foo [*bar*](/url)**\n",
+ "html": "<p><strong>foo <a href=\"/url\"><em>bar</em></a></strong></p>\n",
+ "example": 442,
+ "start_line": 7328,
+ "end_line": 7332,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "__ is not an empty emphasis\n",
+ "html": "<p>__ is not an empty emphasis</p>\n",
+ "example": 443,
+ "start_line": 7337,
+ "end_line": 7341,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "____ is not an empty strong emphasis\n",
+ "html": "<p>____ is not an empty strong emphasis</p>\n",
+ "example": 444,
+ "start_line": 7344,
+ "end_line": 7348,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "foo ***\n",
+ "html": "<p>foo ***</p>\n",
+ "example": 445,
+ "start_line": 7354,
+ "end_line": 7358,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "foo *\\**\n",
+ "html": "<p>foo <em>*</em></p>\n",
+ "example": 446,
+ "start_line": 7361,
+ "end_line": 7365,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "foo *_*\n",
+ "html": "<p>foo <em>_</em></p>\n",
+ "example": 447,
+ "start_line": 7368,
+ "end_line": 7372,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "foo *****\n",
+ "html": "<p>foo *****</p>\n",
+ "example": 448,
+ "start_line": 7375,
+ "end_line": 7379,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "foo **\\***\n",
+ "html": "<p>foo <strong>*</strong></p>\n",
+ "example": 449,
+ "start_line": 7382,
+ "end_line": 7386,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "foo **_**\n",
+ "html": "<p>foo <strong>_</strong></p>\n",
+ "example": 450,
+ "start_line": 7389,
+ "end_line": 7393,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "**foo*\n",
+ "html": "<p>*<em>foo</em></p>\n",
+ "example": 451,
+ "start_line": 7400,
+ "end_line": 7404,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "*foo**\n",
+ "html": "<p><em>foo</em>*</p>\n",
+ "example": 452,
+ "start_line": 7407,
+ "end_line": 7411,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "***foo**\n",
+ "html": "<p>*<strong>foo</strong></p>\n",
+ "example": 453,
+ "start_line": 7414,
+ "end_line": 7418,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "****foo*\n",
+ "html": "<p>***<em>foo</em></p>\n",
+ "example": 454,
+ "start_line": 7421,
+ "end_line": 7425,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "**foo***\n",
+ "html": "<p><strong>foo</strong>*</p>\n",
+ "example": 455,
+ "start_line": 7428,
+ "end_line": 7432,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "*foo****\n",
+ "html": "<p><em>foo</em>***</p>\n",
+ "example": 456,
+ "start_line": 7435,
+ "end_line": 7439,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "foo ___\n",
+ "html": "<p>foo ___</p>\n",
+ "example": 457,
+ "start_line": 7445,
+ "end_line": 7449,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "foo _\\__\n",
+ "html": "<p>foo <em>_</em></p>\n",
+ "example": 458,
+ "start_line": 7452,
+ "end_line": 7456,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "foo _*_\n",
+ "html": "<p>foo <em>*</em></p>\n",
+ "example": 459,
+ "start_line": 7459,
+ "end_line": 7463,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "foo _____\n",
+ "html": "<p>foo _____</p>\n",
+ "example": 460,
+ "start_line": 7466,
+ "end_line": 7470,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "foo __\\___\n",
+ "html": "<p>foo <strong>_</strong></p>\n",
+ "example": 461,
+ "start_line": 7473,
+ "end_line": 7477,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "foo __*__\n",
+ "html": "<p>foo <strong>*</strong></p>\n",
+ "example": 462,
+ "start_line": 7480,
+ "end_line": 7484,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "__foo_\n",
+ "html": "<p>_<em>foo</em></p>\n",
+ "example": 463,
+ "start_line": 7487,
+ "end_line": 7491,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "_foo__\n",
+ "html": "<p><em>foo</em>_</p>\n",
+ "example": 464,
+ "start_line": 7498,
+ "end_line": 7502,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "___foo__\n",
+ "html": "<p>_<strong>foo</strong></p>\n",
+ "example": 465,
+ "start_line": 7505,
+ "end_line": 7509,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "____foo_\n",
+ "html": "<p>___<em>foo</em></p>\n",
+ "example": 466,
+ "start_line": 7512,
+ "end_line": 7516,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "__foo___\n",
+ "html": "<p><strong>foo</strong>_</p>\n",
+ "example": 467,
+ "start_line": 7519,
+ "end_line": 7523,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "_foo____\n",
+ "html": "<p><em>foo</em>___</p>\n",
+ "example": 468,
+ "start_line": 7526,
+ "end_line": 7530,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "**foo**\n",
+ "html": "<p><strong>foo</strong></p>\n",
+ "example": 469,
+ "start_line": 7536,
+ "end_line": 7540,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "*_foo_*\n",
+ "html": "<p><em><em>foo</em></em></p>\n",
+ "example": 470,
+ "start_line": 7543,
+ "end_line": 7547,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "__foo__\n",
+ "html": "<p><strong>foo</strong></p>\n",
+ "example": 471,
+ "start_line": 7550,
+ "end_line": 7554,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "_*foo*_\n",
+ "html": "<p><em><em>foo</em></em></p>\n",
+ "example": 472,
+ "start_line": 7557,
+ "end_line": 7561,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "****foo****\n",
+ "html": "<p><strong><strong>foo</strong></strong></p>\n",
+ "example": 473,
+ "start_line": 7567,
+ "end_line": 7571,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "____foo____\n",
+ "html": "<p><strong><strong>foo</strong></strong></p>\n",
+ "example": 474,
+ "start_line": 7574,
+ "end_line": 7578,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "******foo******\n",
+ "html": "<p><strong><strong><strong>foo</strong></strong></strong></p>\n",
+ "example": 475,
+ "start_line": 7585,
+ "end_line": 7589,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "***foo***\n",
+ "html": "<p><em><strong>foo</strong></em></p>\n",
+ "example": 476,
+ "start_line": 7594,
+ "end_line": 7598,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "_____foo_____\n",
+ "html": "<p><em><strong><strong>foo</strong></strong></em></p>\n",
+ "example": 477,
+ "start_line": 7601,
+ "end_line": 7605,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "*foo _bar* baz_\n",
+ "html": "<p><em>foo _bar</em> baz_</p>\n",
+ "example": 478,
+ "start_line": 7610,
+ "end_line": 7614,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "*foo __bar *baz bim__ bam*\n",
+ "html": "<p><em>foo <strong>bar *baz bim</strong> bam</em></p>\n",
+ "example": 479,
+ "start_line": 7617,
+ "end_line": 7621,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "**foo **bar baz**\n",
+ "html": "<p>**foo <strong>bar baz</strong></p>\n",
+ "example": 480,
+ "start_line": 7626,
+ "end_line": 7630,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "*foo *bar baz*\n",
+ "html": "<p>*foo <em>bar baz</em></p>\n",
+ "example": 481,
+ "start_line": 7633,
+ "end_line": 7637,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "*[bar*](/url)\n",
+ "html": "<p>*<a href=\"/url\">bar*</a></p>\n",
+ "example": 482,
+ "start_line": 7642,
+ "end_line": 7646,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "_foo [bar_](/url)\n",
+ "html": "<p>_foo <a href=\"/url\">bar_</a></p>\n",
+ "example": 483,
+ "start_line": 7649,
+ "end_line": 7653,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "*<img src=\"foo\" title=\"*\"/>\n",
+ "html": "<p>*<img src=\"foo\" title=\"*\"/></p>\n",
+ "example": 484,
+ "start_line": 7656,
+ "end_line": 7660,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "**<a href=\"**\">\n",
+ "html": "<p>**<a href=\"**\"></p>\n",
+ "example": 485,
+ "start_line": 7663,
+ "end_line": 7667,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "__<a href=\"__\">\n",
+ "html": "<p>__<a href=\"__\"></p>\n",
+ "example": 486,
+ "start_line": 7670,
+ "end_line": 7674,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "*a `*`*\n",
+ "html": "<p><em>a <code>*</code></em></p>\n",
+ "example": 487,
+ "start_line": 7677,
+ "end_line": 7681,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "_a `_`_\n",
+ "html": "<p><em>a <code>_</code></em></p>\n",
+ "example": 488,
+ "start_line": 7684,
+ "end_line": 7688,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "**a<http://foo.bar/?q=**>\n",
+ "html": "<p>**a<a href=\"http://foo.bar/?q=**\">http://foo.bar/?q=**</a></p>\n",
+ "example": 489,
+ "start_line": 7691,
+ "end_line": 7695,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "__a<http://foo.bar/?q=__>\n",
+ "html": "<p>__a<a href=\"http://foo.bar/?q=__\">http://foo.bar/?q=__</a></p>\n",
+ "example": 490,
+ "start_line": 7698,
+ "end_line": 7702,
+ "section": "Emphasis and strong emphasis",
+ "extensions": []
+ },
+ {
+ "markdown": "~~Hi~~ Hello, world!\n",
+ "html": "<p><del>Hi</del> Hello, world!</p>\n",
+ "example": 491,
+ "start_line": 7714,
+ "end_line": 7718,
+ "section": "Strikethrough (extension)",
+ "extensions": [
+ "strikethrough"
+ ]
+ },
+ {
+ "markdown": "This ~~has a\n\nnew paragraph~~.\n",
+ "html": "<p>This ~~has a</p>\n<p>new paragraph~~.</p>\n",
+ "example": 492,
+ "start_line": 7723,
+ "end_line": 7730,
+ "section": "Strikethrough (extension)",
+ "extensions": [
+ "strikethrough"
+ ]
+ },
+ {
+ "markdown": "[link](/uri \"title\")\n",
+ "html": "<p><a href=\"/uri\" title=\"title\">link</a></p>\n",
+ "example": 493,
+ "start_line": 7809,
+ "end_line": 7813,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[link](/uri)\n",
+ "html": "<p><a href=\"/uri\">link</a></p>\n",
+ "example": 494,
+ "start_line": 7818,
+ "end_line": 7822,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[link]()\n",
+ "html": "<p><a href=\"\">link</a></p>\n",
+ "example": 495,
+ "start_line": 7827,
+ "end_line": 7831,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[link](<>)\n",
+ "html": "<p><a href=\"\">link</a></p>\n",
+ "example": 496,
+ "start_line": 7834,
+ "end_line": 7838,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[link](/my uri)\n",
+ "html": "<p>[link](/my uri)</p>\n",
+ "example": 497,
+ "start_line": 7843,
+ "end_line": 7847,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[link](</my uri>)\n",
+ "html": "<p><a href=\"/my%20uri\">link</a></p>\n",
+ "example": 498,
+ "start_line": 7849,
+ "end_line": 7853,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[link](foo\nbar)\n",
+ "html": "<p>[link](foo\nbar)</p>\n",
+ "example": 499,
+ "start_line": 7858,
+ "end_line": 7864,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[link](<foo\nbar>)\n",
+ "html": "<p>[link](<foo\nbar>)</p>\n",
+ "example": 500,
+ "start_line": 7866,
+ "end_line": 7872,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[a](<b)c>)\n",
+ "html": "<p><a href=\"b)c\">a</a></p>\n",
+ "example": 501,
+ "start_line": 7877,
+ "end_line": 7881,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[link](<foo\\>)\n",
+ "html": "<p>[link](<foo>)</p>\n",
+ "example": 502,
+ "start_line": 7885,
+ "end_line": 7889,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[a](<b)c\n[a](<b)c>\n[a](<b>c)\n",
+ "html": "<p>[a](<b)c\n[a](<b)c>\n[a](<b>c)</p>\n",
+ "example": 503,
+ "start_line": 7894,
+ "end_line": 7902,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[link](\\(foo\\))\n",
+ "html": "<p><a href=\"(foo)\">link</a></p>\n",
+ "example": 504,
+ "start_line": 7906,
+ "end_line": 7910,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[link](foo(and(bar)))\n",
+ "html": "<p><a href=\"foo(and(bar))\">link</a></p>\n",
+ "example": 505,
+ "start_line": 7915,
+ "end_line": 7919,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[link](foo\\(and\\(bar\\))\n",
+ "html": "<p><a href=\"foo(and(bar)\">link</a></p>\n",
+ "example": 506,
+ "start_line": 7924,
+ "end_line": 7928,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[link](<foo(and(bar)>)\n",
+ "html": "<p><a href=\"foo(and(bar)\">link</a></p>\n",
+ "example": 507,
+ "start_line": 7931,
+ "end_line": 7935,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[link](foo\\)\\:)\n",
+ "html": "<p><a href=\"foo):\">link</a></p>\n",
+ "example": 508,
+ "start_line": 7941,
+ "end_line": 7945,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[link](#fragment)\n\n[link](http://example.com#fragment)\n\n[link](http://example.com?foo=3#frag)\n",
+ "html": "<p><a href=\"#fragment\">link</a></p>\n<p><a href=\"http://example.com#fragment\">link</a></p>\n<p><a href=\"http://example.com?foo=3#frag\">link</a></p>\n",
+ "example": 509,
+ "start_line": 7950,
+ "end_line": 7960,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[link](foo\\bar)\n",
+ "html": "<p><a href=\"foo%5Cbar\">link</a></p>\n",
+ "example": 510,
+ "start_line": 7966,
+ "end_line": 7970,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[link](foo%20bä)\n",
+ "html": "<p><a href=\"foo%20b%C3%A4\">link</a></p>\n",
+ "example": 511,
+ "start_line": 7982,
+ "end_line": 7986,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[link](\"title\")\n",
+ "html": "<p><a href=\"%22title%22\">link</a></p>\n",
+ "example": 512,
+ "start_line": 7993,
+ "end_line": 7997,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[link](/url \"title\")\n[link](/url 'title')\n[link](/url (title))\n",
+ "html": "<p><a href=\"/url\" title=\"title\">link</a>\n<a href=\"/url\" title=\"title\">link</a>\n<a href=\"/url\" title=\"title\">link</a></p>\n",
+ "example": 513,
+ "start_line": 8002,
+ "end_line": 8010,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[link](/url \"title \\\""\")\n",
+ "html": "<p><a href=\"/url\" title=\"title ""\">link</a></p>\n",
+ "example": 514,
+ "start_line": 8016,
+ "end_line": 8020,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[link](/url\u00a0\"title\")\n",
+ "html": "<p><a href=\"/url%C2%A0%22title%22\">link</a></p>\n",
+ "example": 515,
+ "start_line": 8026,
+ "end_line": 8030,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[link](/url \"title \"and\" title\")\n",
+ "html": "<p>[link](/url "title "and" title")</p>\n",
+ "example": 516,
+ "start_line": 8035,
+ "end_line": 8039,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[link](/url 'title \"and\" title')\n",
+ "html": "<p><a href=\"/url\" title=\"title "and" title\">link</a></p>\n",
+ "example": 517,
+ "start_line": 8044,
+ "end_line": 8048,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[link]( /uri\n \"title\" )\n",
+ "html": "<p><a href=\"/uri\" title=\"title\">link</a></p>\n",
+ "example": 518,
+ "start_line": 8068,
+ "end_line": 8073,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[link] (/uri)\n",
+ "html": "<p>[link] (/uri)</p>\n",
+ "example": 519,
+ "start_line": 8079,
+ "end_line": 8083,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[link [foo [bar]]](/uri)\n",
+ "html": "<p><a href=\"/uri\">link [foo [bar]]</a></p>\n",
+ "example": 520,
+ "start_line": 8089,
+ "end_line": 8093,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[link] bar](/uri)\n",
+ "html": "<p>[link] bar](/uri)</p>\n",
+ "example": 521,
+ "start_line": 8096,
+ "end_line": 8100,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[link [bar](/uri)\n",
+ "html": "<p>[link <a href=\"/uri\">bar</a></p>\n",
+ "example": 522,
+ "start_line": 8103,
+ "end_line": 8107,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[link \\[bar](/uri)\n",
+ "html": "<p><a href=\"/uri\">link [bar</a></p>\n",
+ "example": 523,
+ "start_line": 8110,
+ "end_line": 8114,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[link *foo **bar** `#`*](/uri)\n",
+ "html": "<p><a href=\"/uri\">link <em>foo <strong>bar</strong> <code>#</code></em></a></p>\n",
+ "example": 524,
+ "start_line": 8119,
+ "end_line": 8123,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[](/uri)\n",
+ "html": "<p><a href=\"/uri\"><img src=\"moon.jpg\" alt=\"moon\" /></a></p>\n",
+ "example": 525,
+ "start_line": 8126,
+ "end_line": 8130,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo [bar](/uri)](/uri)\n",
+ "html": "<p>[foo <a href=\"/uri\">bar</a>](/uri)</p>\n",
+ "example": 526,
+ "start_line": 8135,
+ "end_line": 8139,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo *[bar [baz](/uri)](/uri)*](/uri)\n",
+ "html": "<p>[foo <em>[bar <a href=\"/uri\">baz</a>](/uri)</em>](/uri)</p>\n",
+ "example": 527,
+ "start_line": 8142,
+ "end_line": 8146,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "](uri2)](uri3)\n",
+ "html": "<p><img src=\"uri3\" alt=\"[foo](uri2)\" /></p>\n",
+ "example": 528,
+ "start_line": 8149,
+ "end_line": 8153,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "*[foo*](/uri)\n",
+ "html": "<p>*<a href=\"/uri\">foo*</a></p>\n",
+ "example": 529,
+ "start_line": 8159,
+ "end_line": 8163,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo *bar](baz*)\n",
+ "html": "<p><a href=\"baz*\">foo *bar</a></p>\n",
+ "example": 530,
+ "start_line": 8166,
+ "end_line": 8170,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "*foo [bar* baz]\n",
+ "html": "<p><em>foo [bar</em> baz]</p>\n",
+ "example": 531,
+ "start_line": 8176,
+ "end_line": 8180,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo <bar attr=\"](baz)\">\n",
+ "html": "<p>[foo <bar attr=\"](baz)\"></p>\n",
+ "example": 532,
+ "start_line": 8186,
+ "end_line": 8190,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo`](/uri)`\n",
+ "html": "<p>[foo<code>](/uri)</code></p>\n",
+ "example": 533,
+ "start_line": 8193,
+ "end_line": 8197,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo<http://example.com/?search=](uri)>\n",
+ "html": "<p>[foo<a href=\"http://example.com/?search=%5D(uri)\">http://example.com/?search=](uri)</a></p>\n",
+ "example": 534,
+ "start_line": 8200,
+ "end_line": 8204,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo][bar]\n\n[bar]: /url \"title\"\n",
+ "html": "<p><a href=\"/url\" title=\"title\">foo</a></p>\n",
+ "example": 535,
+ "start_line": 8238,
+ "end_line": 8244,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[link [foo [bar]]][ref]\n\n[ref]: /uri\n",
+ "html": "<p><a href=\"/uri\">link [foo [bar]]</a></p>\n",
+ "example": 536,
+ "start_line": 8253,
+ "end_line": 8259,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[link \\[bar][ref]\n\n[ref]: /uri\n",
+ "html": "<p><a href=\"/uri\">link [bar</a></p>\n",
+ "example": 537,
+ "start_line": 8262,
+ "end_line": 8268,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[link *foo **bar** `#`*][ref]\n\n[ref]: /uri\n",
+ "html": "<p><a href=\"/uri\">link <em>foo <strong>bar</strong> <code>#</code></em></a></p>\n",
+ "example": 538,
+ "start_line": 8273,
+ "end_line": 8279,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[][ref]\n\n[ref]: /uri\n",
+ "html": "<p><a href=\"/uri\"><img src=\"moon.jpg\" alt=\"moon\" /></a></p>\n",
+ "example": 539,
+ "start_line": 8282,
+ "end_line": 8288,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo [bar](/uri)][ref]\n\n[ref]: /uri\n",
+ "html": "<p>[foo <a href=\"/uri\">bar</a>]<a href=\"/uri\">ref</a></p>\n",
+ "example": 540,
+ "start_line": 8293,
+ "end_line": 8299,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo *bar [baz][ref]*][ref]\n\n[ref]: /uri\n",
+ "html": "<p>[foo <em>bar <a href=\"/uri\">baz</a></em>]<a href=\"/uri\">ref</a></p>\n",
+ "example": 541,
+ "start_line": 8302,
+ "end_line": 8308,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "*[foo*][ref]\n\n[ref]: /uri\n",
+ "html": "<p>*<a href=\"/uri\">foo*</a></p>\n",
+ "example": 542,
+ "start_line": 8317,
+ "end_line": 8323,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo *bar][ref]\n\n[ref]: /uri\n",
+ "html": "<p><a href=\"/uri\">foo *bar</a></p>\n",
+ "example": 543,
+ "start_line": 8326,
+ "end_line": 8332,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo <bar attr=\"][ref]\">\n\n[ref]: /uri\n",
+ "html": "<p>[foo <bar attr=\"][ref]\"></p>\n",
+ "example": 544,
+ "start_line": 8338,
+ "end_line": 8344,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo`][ref]`\n\n[ref]: /uri\n",
+ "html": "<p>[foo<code>][ref]</code></p>\n",
+ "example": 545,
+ "start_line": 8347,
+ "end_line": 8353,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo<http://example.com/?search=][ref]>\n\n[ref]: /uri\n",
+ "html": "<p>[foo<a href=\"http://example.com/?search=%5D%5Bref%5D\">http://example.com/?search=][ref]</a></p>\n",
+ "example": 546,
+ "start_line": 8356,
+ "end_line": 8362,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo][BaR]\n\n[bar]: /url \"title\"\n",
+ "html": "<p><a href=\"/url\" title=\"title\">foo</a></p>\n",
+ "example": 547,
+ "start_line": 8367,
+ "end_line": 8373,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[\u0422\u043e\u043b\u043f\u043e\u0439][\u0422\u043e\u043b\u043f\u043e\u0439] is a Russian word.\n\n[\u0422\u041e\u041b\u041f\u041e\u0419]: /url\n",
+ "html": "<p><a href=\"/url\">\u0422\u043e\u043b\u043f\u043e\u0439</a> is a Russian word.</p>\n",
+ "example": 548,
+ "start_line": 8378,
+ "end_line": 8384,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[Foo\n bar]: /url\n\n[Baz][Foo bar]\n",
+ "html": "<p><a href=\"/url\">Baz</a></p>\n",
+ "example": 549,
+ "start_line": 8390,
+ "end_line": 8397,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo] [bar]\n\n[bar]: /url \"title\"\n",
+ "html": "<p>[foo] <a href=\"/url\" title=\"title\">bar</a></p>\n",
+ "example": 550,
+ "start_line": 8403,
+ "end_line": 8409,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo]\n[bar]\n\n[bar]: /url \"title\"\n",
+ "html": "<p>[foo]\n<a href=\"/url\" title=\"title\">bar</a></p>\n",
+ "example": 551,
+ "start_line": 8412,
+ "end_line": 8420,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo]: /url1\n\n[foo]: /url2\n\n[bar][foo]\n",
+ "html": "<p><a href=\"/url1\">bar</a></p>\n",
+ "example": 552,
+ "start_line": 8453,
+ "end_line": 8461,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[bar][foo\\!]\n\n[foo!]: /url\n",
+ "html": "<p>[bar][foo!]</p>\n",
+ "example": 553,
+ "start_line": 8468,
+ "end_line": 8474,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo][ref[]\n\n[ref[]: /uri\n",
+ "html": "<p>[foo][ref[]</p>\n<p>[ref[]: /uri</p>\n",
+ "example": 554,
+ "start_line": 8480,
+ "end_line": 8487,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo][ref[bar]]\n\n[ref[bar]]: /uri\n",
+ "html": "<p>[foo][ref[bar]]</p>\n<p>[ref[bar]]: /uri</p>\n",
+ "example": 555,
+ "start_line": 8490,
+ "end_line": 8497,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[[[foo]]]\n\n[[[foo]]]: /url\n",
+ "html": "<p>[[[foo]]]</p>\n<p>[[[foo]]]: /url</p>\n",
+ "example": 556,
+ "start_line": 8500,
+ "end_line": 8507,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo][ref\\[]\n\n[ref\\[]: /uri\n",
+ "html": "<p><a href=\"/uri\">foo</a></p>\n",
+ "example": 557,
+ "start_line": 8510,
+ "end_line": 8516,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[bar\\\\]: /uri\n\n[bar\\\\]\n",
+ "html": "<p><a href=\"/uri\">bar\\</a></p>\n",
+ "example": 558,
+ "start_line": 8521,
+ "end_line": 8527,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[]\n\n[]: /uri\n",
+ "html": "<p>[]</p>\n<p>[]: /uri</p>\n",
+ "example": 559,
+ "start_line": 8532,
+ "end_line": 8539,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[\n ]\n\n[\n ]: /uri\n",
+ "html": "<p>[\n]</p>\n<p>[\n]: /uri</p>\n",
+ "example": 560,
+ "start_line": 8542,
+ "end_line": 8553,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo][]\n\n[foo]: /url \"title\"\n",
+ "html": "<p><a href=\"/url\" title=\"title\">foo</a></p>\n",
+ "example": 561,
+ "start_line": 8565,
+ "end_line": 8571,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[*foo* bar][]\n\n[*foo* bar]: /url \"title\"\n",
+ "html": "<p><a href=\"/url\" title=\"title\"><em>foo</em> bar</a></p>\n",
+ "example": 562,
+ "start_line": 8574,
+ "end_line": 8580,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[Foo][]\n\n[foo]: /url \"title\"\n",
+ "html": "<p><a href=\"/url\" title=\"title\">Foo</a></p>\n",
+ "example": 563,
+ "start_line": 8585,
+ "end_line": 8591,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo] \n[]\n\n[foo]: /url \"title\"\n",
+ "html": "<p><a href=\"/url\" title=\"title\">foo</a>\n[]</p>\n",
+ "example": 564,
+ "start_line": 8598,
+ "end_line": 8606,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo]\n\n[foo]: /url \"title\"\n",
+ "html": "<p><a href=\"/url\" title=\"title\">foo</a></p>\n",
+ "example": 565,
+ "start_line": 8618,
+ "end_line": 8624,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[*foo* bar]\n\n[*foo* bar]: /url \"title\"\n",
+ "html": "<p><a href=\"/url\" title=\"title\"><em>foo</em> bar</a></p>\n",
+ "example": 566,
+ "start_line": 8627,
+ "end_line": 8633,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[[*foo* bar]]\n\n[*foo* bar]: /url \"title\"\n",
+ "html": "<p>[<a href=\"/url\" title=\"title\"><em>foo</em> bar</a>]</p>\n",
+ "example": 567,
+ "start_line": 8636,
+ "end_line": 8642,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[[bar [foo]\n\n[foo]: /url\n",
+ "html": "<p>[[bar <a href=\"/url\">foo</a></p>\n",
+ "example": 568,
+ "start_line": 8645,
+ "end_line": 8651,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[Foo]\n\n[foo]: /url \"title\"\n",
+ "html": "<p><a href=\"/url\" title=\"title\">Foo</a></p>\n",
+ "example": 569,
+ "start_line": 8656,
+ "end_line": 8662,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo] bar\n\n[foo]: /url\n",
+ "html": "<p><a href=\"/url\">foo</a> bar</p>\n",
+ "example": 570,
+ "start_line": 8667,
+ "end_line": 8673,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "\\[foo]\n\n[foo]: /url \"title\"\n",
+ "html": "<p>[foo]</p>\n",
+ "example": 571,
+ "start_line": 8679,
+ "end_line": 8685,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo*]: /url\n\n*[foo*]\n",
+ "html": "<p>*<a href=\"/url\">foo*</a></p>\n",
+ "example": 572,
+ "start_line": 8691,
+ "end_line": 8697,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo][bar]\n\n[foo]: /url1\n[bar]: /url2\n",
+ "html": "<p><a href=\"/url2\">foo</a></p>\n",
+ "example": 573,
+ "start_line": 8703,
+ "end_line": 8710,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo][]\n\n[foo]: /url1\n",
+ "html": "<p><a href=\"/url1\">foo</a></p>\n",
+ "example": 574,
+ "start_line": 8712,
+ "end_line": 8718,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo]()\n\n[foo]: /url1\n",
+ "html": "<p><a href=\"\">foo</a></p>\n",
+ "example": 575,
+ "start_line": 8722,
+ "end_line": 8728,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo](not a link)\n\n[foo]: /url1\n",
+ "html": "<p><a href=\"/url1\">foo</a>(not a link)</p>\n",
+ "example": 576,
+ "start_line": 8730,
+ "end_line": 8736,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo][bar][baz]\n\n[baz]: /url\n",
+ "html": "<p>[foo]<a href=\"/url\">bar</a></p>\n",
+ "example": 577,
+ "start_line": 8741,
+ "end_line": 8747,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo][bar][baz]\n\n[baz]: /url1\n[bar]: /url2\n",
+ "html": "<p><a href=\"/url2\">foo</a><a href=\"/url1\">baz</a></p>\n",
+ "example": 578,
+ "start_line": 8753,
+ "end_line": 8760,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "[foo][bar][baz]\n\n[baz]: /url1\n[foo]: /url2\n",
+ "html": "<p>[foo]<a href=\"/url1\">bar</a></p>\n",
+ "example": 579,
+ "start_line": 8766,
+ "end_line": 8773,
+ "section": "Links",
+ "extensions": []
+ },
+ {
+ "markdown": "\n",
+ "html": "<p><img src=\"/url\" alt=\"foo\" title=\"title\" /></p>\n",
+ "example": 580,
+ "start_line": 8789,
+ "end_line": 8793,
+ "section": "Images",
+ "extensions": []
+ },
+ {
+ "markdown": "![foo *bar*]\n\n[foo *bar*]: train.jpg \"train & tracks\"\n",
+ "html": "<p><img src=\"train.jpg\" alt=\"foo bar\" title=\"train & tracks\" /></p>\n",
+ "example": 581,
+ "start_line": 8796,
+ "end_line": 8802,
+ "section": "Images",
+ "extensions": []
+ },
+ {
+ "markdown": "](/url2)\n",
+ "html": "<p><img src=\"/url2\" alt=\"foo bar\" /></p>\n",
+ "example": 582,
+ "start_line": 8805,
+ "end_line": 8809,
+ "section": "Images",
+ "extensions": []
+ },
+ {
+ "markdown": "](/url2)\n",
+ "html": "<p><img src=\"/url2\" alt=\"foo bar\" /></p>\n",
+ "example": 583,
+ "start_line": 8812,
+ "end_line": 8816,
+ "section": "Images",
+ "extensions": []
+ },
+ {
+ "markdown": "![foo *bar*][]\n\n[foo *bar*]: train.jpg \"train & tracks\"\n",
+ "html": "<p><img src=\"train.jpg\" alt=\"foo bar\" title=\"train & tracks\" /></p>\n",
+ "example": 584,
+ "start_line": 8826,
+ "end_line": 8832,
+ "section": "Images",
+ "extensions": []
+ },
+ {
+ "markdown": "![foo *bar*][foobar]\n\n[FOOBAR]: train.jpg \"train & tracks\"\n",
+ "html": "<p><img src=\"train.jpg\" alt=\"foo bar\" title=\"train & tracks\" /></p>\n",
+ "example": 585,
+ "start_line": 8835,
+ "end_line": 8841,
+ "section": "Images",
+ "extensions": []
+ },
+ {
+ "markdown": "\n",
+ "html": "<p><img src=\"train.jpg\" alt=\"foo\" /></p>\n",
+ "example": 586,
+ "start_line": 8844,
+ "end_line": 8848,
+ "section": "Images",
+ "extensions": []
+ },
+ {
+ "markdown": "My \n",
+ "html": "<p>My <img src=\"/path/to/train.jpg\" alt=\"foo bar\" title=\"title\" /></p>\n",
+ "example": 587,
+ "start_line": 8851,
+ "end_line": 8855,
+ "section": "Images",
+ "extensions": []
+ },
+ {
+ "markdown": "\n",
+ "html": "<p><img src=\"url\" alt=\"foo\" /></p>\n",
+ "example": 588,
+ "start_line": 8858,
+ "end_line": 8862,
+ "section": "Images",
+ "extensions": []
+ },
+ {
+ "markdown": "\n",
+ "html": "<p><img src=\"/url\" alt=\"\" /></p>\n",
+ "example": 589,
+ "start_line": 8865,
+ "end_line": 8869,
+ "section": "Images",
+ "extensions": []
+ },
+ {
+ "markdown": "![foo][bar]\n\n[bar]: /url\n",
+ "html": "<p><img src=\"/url\" alt=\"foo\" /></p>\n",
+ "example": 590,
+ "start_line": 8874,
+ "end_line": 8880,
+ "section": "Images",
+ "extensions": []
+ },
+ {
+ "markdown": "![foo][bar]\n\n[BAR]: /url\n",
+ "html": "<p><img src=\"/url\" alt=\"foo\" /></p>\n",
+ "example": 591,
+ "start_line": 8883,
+ "end_line": 8889,
+ "section": "Images",
+ "extensions": []
+ },
+ {
+ "markdown": "![foo][]\n\n[foo]: /url \"title\"\n",
+ "html": "<p><img src=\"/url\" alt=\"foo\" title=\"title\" /></p>\n",
+ "example": 592,
+ "start_line": 8894,
+ "end_line": 8900,
+ "section": "Images",
+ "extensions": []
+ },
+ {
+ "markdown": "![*foo* bar][]\n\n[*foo* bar]: /url \"title\"\n",
+ "html": "<p><img src=\"/url\" alt=\"foo bar\" title=\"title\" /></p>\n",
+ "example": 593,
+ "start_line": 8903,
+ "end_line": 8909,
+ "section": "Images",
+ "extensions": []
+ },
+ {
+ "markdown": "![Foo][]\n\n[foo]: /url \"title\"\n",
+ "html": "<p><img src=\"/url\" alt=\"Foo\" title=\"title\" /></p>\n",
+ "example": 594,
+ "start_line": 8914,
+ "end_line": 8920,
+ "section": "Images",
+ "extensions": []
+ },
+ {
+ "markdown": "![foo] \n[]\n\n[foo]: /url \"title\"\n",
+ "html": "<p><img src=\"/url\" alt=\"foo\" title=\"title\" />\n[]</p>\n",
+ "example": 595,
+ "start_line": 8926,
+ "end_line": 8934,
+ "section": "Images",
+ "extensions": []
+ },
+ {
+ "markdown": "![foo]\n\n[foo]: /url \"title\"\n",
+ "html": "<p><img src=\"/url\" alt=\"foo\" title=\"title\" /></p>\n",
+ "example": 596,
+ "start_line": 8939,
+ "end_line": 8945,
+ "section": "Images",
+ "extensions": []
+ },
+ {
+ "markdown": "![*foo* bar]\n\n[*foo* bar]: /url \"title\"\n",
+ "html": "<p><img src=\"/url\" alt=\"foo bar\" title=\"title\" /></p>\n",
+ "example": 597,
+ "start_line": 8948,
+ "end_line": 8954,
+ "section": "Images",
+ "extensions": []
+ },
+ {
+ "markdown": "![[foo]]\n\n[[foo]]: /url \"title\"\n",
+ "html": "<p>![[foo]]</p>\n<p>[[foo]]: /url "title"</p>\n",
+ "example": 598,
+ "start_line": 8959,
+ "end_line": 8966,
+ "section": "Images",
+ "extensions": []
+ },
+ {
+ "markdown": "![Foo]\n\n[foo]: /url \"title\"\n",
+ "html": "<p><img src=\"/url\" alt=\"Foo\" title=\"title\" /></p>\n",
+ "example": 599,
+ "start_line": 8971,
+ "end_line": 8977,
+ "section": "Images",
+ "extensions": []
+ },
+ {
+ "markdown": "!\\[foo]\n\n[foo]: /url \"title\"\n",
+ "html": "<p>![foo]</p>\n",
+ "example": 600,
+ "start_line": 8983,
+ "end_line": 8989,
+ "section": "Images",
+ "extensions": []
+ },
+ {
+ "markdown": "\\![foo]\n\n[foo]: /url \"title\"\n",
+ "html": "<p>!<a href=\"/url\" title=\"title\">foo</a></p>\n",
+ "example": 601,
+ "start_line": 8995,
+ "end_line": 9001,
+ "section": "Images",
+ "extensions": []
+ },
+ {
+ "markdown": "<http://foo.bar.baz>\n",
+ "html": "<p><a href=\"http://foo.bar.baz\">http://foo.bar.baz</a></p>\n",
+ "example": 602,
+ "start_line": 9028,
+ "end_line": 9032,
+ "section": "Autolinks",
+ "extensions": []
+ },
+ {
+ "markdown": "<http://foo.bar.baz/test?q=hello&id=22&boolean>\n",
+ "html": "<p><a href=\"http://foo.bar.baz/test?q=hello&id=22&boolean\">http://foo.bar.baz/test?q=hello&id=22&boolean</a></p>\n",
+ "example": 603,
+ "start_line": 9035,
+ "end_line": 9039,
+ "section": "Autolinks",
+ "extensions": []
+ },
+ {
+ "markdown": "<irc://foo.bar:2233/baz>\n",
+ "html": "<p><a href=\"irc://foo.bar:2233/baz\">irc://foo.bar:2233/baz</a></p>\n",
+ "example": 604,
+ "start_line": 9042,
+ "end_line": 9046,
+ "section": "Autolinks",
+ "extensions": []
+ },
+ {
+ "markdown": "<MAILTO:FOO@BAR.BAZ>\n",
+ "html": "<p><a href=\"MAILTO:FOO@BAR.BAZ\">MAILTO:FOO@BAR.BAZ</a></p>\n",
+ "example": 605,
+ "start_line": 9051,
+ "end_line": 9055,
+ "section": "Autolinks",
+ "extensions": []
+ },
+ {
+ "markdown": "<a+b+c:d>\n",
+ "html": "<p><a href=\"a+b+c:d\">a+b+c:d</a></p>\n",
+ "example": 606,
+ "start_line": 9063,
+ "end_line": 9067,
+ "section": "Autolinks",
+ "extensions": []
+ },
+ {
+ "markdown": "<made-up-scheme://foo,bar>\n",
+ "html": "<p><a href=\"made-up-scheme://foo,bar\">made-up-scheme://foo,bar</a></p>\n",
+ "example": 607,
+ "start_line": 9070,
+ "end_line": 9074,
+ "section": "Autolinks",
+ "extensions": []
+ },
+ {
+ "markdown": "<http://../>\n",
+ "html": "<p><a href=\"http://../\">http://../</a></p>\n",
+ "example": 608,
+ "start_line": 9077,
+ "end_line": 9081,
+ "section": "Autolinks",
+ "extensions": []
+ },
+ {
+ "markdown": "<localhost:5001/foo>\n",
+ "html": "<p><a href=\"localhost:5001/foo\">localhost:5001/foo</a></p>\n",
+ "example": 609,
+ "start_line": 9084,
+ "end_line": 9088,
+ "section": "Autolinks",
+ "extensions": []
+ },
+ {
+ "markdown": "<http://foo.bar/baz bim>\n",
+ "html": "<p><http://foo.bar/baz bim></p>\n",
+ "example": 610,
+ "start_line": 9093,
+ "end_line": 9097,
+ "section": "Autolinks",
+ "extensions": []
+ },
+ {
+ "markdown": "<http://example.com/\\[\\>\n",
+ "html": "<p><a href=\"http://example.com/%5C%5B%5C\">http://example.com/\\[\\</a></p>\n",
+ "example": 611,
+ "start_line": 9102,
+ "end_line": 9106,
+ "section": "Autolinks",
+ "extensions": []
+ },
+ {
+ "markdown": "<foo@bar.example.com>\n",
+ "html": "<p><a href=\"mailto:foo@bar.example.com\">foo@bar.example.com</a></p>\n",
+ "example": 612,
+ "start_line": 9124,
+ "end_line": 9128,
+ "section": "Autolinks",
+ "extensions": []
+ },
+ {
+ "markdown": "<foo+special@Bar.baz-bar0.com>\n",
+ "html": "<p><a href=\"mailto:foo+special@Bar.baz-bar0.com\">foo+special@Bar.baz-bar0.com</a></p>\n",
+ "example": 613,
+ "start_line": 9131,
+ "end_line": 9135,
+ "section": "Autolinks",
+ "extensions": []
+ },
+ {
+ "markdown": "<foo\\+@bar.example.com>\n",
+ "html": "<p><foo+@bar.example.com></p>\n",
+ "example": 614,
+ "start_line": 9140,
+ "end_line": 9144,
+ "section": "Autolinks",
+ "extensions": []
+ },
+ {
+ "markdown": "<>\n",
+ "html": "<p><></p>\n",
+ "example": 615,
+ "start_line": 9149,
+ "end_line": 9153,
+ "section": "Autolinks",
+ "extensions": []
+ },
+ {
+ "markdown": "< http://foo.bar >\n",
+ "html": "<p>< http://foo.bar ></p>\n",
+ "example": 616,
+ "start_line": 9156,
+ "end_line": 9160,
+ "section": "Autolinks",
+ "extensions": []
+ },
+ {
+ "markdown": "<m:abc>\n",
+ "html": "<p><m:abc></p>\n",
+ "example": 617,
+ "start_line": 9163,
+ "end_line": 9167,
+ "section": "Autolinks",
+ "extensions": []
+ },
+ {
+ "markdown": "<foo.bar.baz>\n",
+ "html": "<p><foo.bar.baz></p>\n",
+ "example": 618,
+ "start_line": 9170,
+ "end_line": 9174,
+ "section": "Autolinks",
+ "extensions": []
+ },
+ {
+ "markdown": "http://example.com\n",
+ "html": "<p>http://example.com</p>\n",
+ "example": 619,
+ "start_line": 9177,
+ "end_line": 9181,
+ "section": "Autolinks",
+ "extensions": []
+ },
+ {
+ "markdown": "foo@bar.example.com\n",
+ "html": "<p>foo@bar.example.com</p>\n",
+ "example": 620,
+ "start_line": 9184,
+ "end_line": 9188,
+ "section": "Autolinks",
+ "extensions": []
+ },
+ {
+ "markdown": "www.commonmark.org\n",
+ "html": "<p><a href=\"http://www.commonmark.org\">www.commonmark.org</a></p>\n",
+ "example": 621,
+ "start_line": 9213,
+ "end_line": 9217,
+ "section": "Autolinks (extension)",
+ "extensions": [
+ "autolink"
+ ]
+ },
+ {
+ "markdown": "Visit www.commonmark.org/help for more information.\n",
+ "html": "<p>Visit <a href=\"http://www.commonmark.org/help\">www.commonmark.org/help</a> for more information.</p>\n",
+ "example": 622,
+ "start_line": 9221,
+ "end_line": 9225,
+ "section": "Autolinks (extension)",
+ "extensions": [
+ "autolink"
+ ]
+ },
+ {
+ "markdown": "Visit www.commonmark.org.\n\nVisit www.commonmark.org/a.b.\n",
+ "html": "<p>Visit <a href=\"http://www.commonmark.org\">www.commonmark.org</a>.</p>\n<p>Visit <a href=\"http://www.commonmark.org/a.b\">www.commonmark.org/a.b</a>.</p>\n",
+ "example": 623,
+ "start_line": 9233,
+ "end_line": 9240,
+ "section": "Autolinks (extension)",
+ "extensions": [
+ "autolink"
+ ]
+ },
+ {
+ "markdown": "www.google.com/search?q=Markup+(business)\n\nwww.google.com/search?q=Markup+(business)))\n\n(www.google.com/search?q=Markup+(business))\n\n(www.google.com/search?q=Markup+(business)\n",
+ "html": "<p><a href=\"http://www.google.com/search?q=Markup+(business)\">www.google.com/search?q=Markup+(business)</a></p>\n<p><a href=\"http://www.google.com/search?q=Markup+(business)\">www.google.com/search?q=Markup+(business)</a>))</p>\n<p>(<a href=\"http://www.google.com/search?q=Markup+(business)\">www.google.com/search?q=Markup+(business)</a>)</p>\n<p>(<a href=\"http://www.google.com/search?q=Markup+(business)\">www.google.com/search?q=Markup+(business)</a></p>\n",
+ "example": 624,
+ "start_line": 9247,
+ "end_line": 9260,
+ "section": "Autolinks (extension)",
+ "extensions": [
+ "autolink"
+ ]
+ },
+ {
+ "markdown": "www.google.com/search?q=(business))+ok\n",
+ "html": "<p><a href=\"http://www.google.com/search?q=(business))+ok\">www.google.com/search?q=(business))+ok</a></p>\n",
+ "example": 625,
+ "start_line": 9266,
+ "end_line": 9270,
+ "section": "Autolinks (extension)",
+ "extensions": [
+ "autolink"
+ ]
+ },
+ {
+ "markdown": "www.google.com/search?q=commonmark&hl=en\n\nwww.google.com/search?q=commonmark&hl;\n",
+ "html": "<p><a href=\"http://www.google.com/search?q=commonmark&hl=en\">www.google.com/search?q=commonmark&hl=en</a></p>\n<p><a href=\"http://www.google.com/search?q=commonmark\">www.google.com/search?q=commonmark</a>&hl;</p>\n",
+ "example": 626,
+ "start_line": 9277,
+ "end_line": 9284,
+ "section": "Autolinks (extension)",
+ "extensions": [
+ "autolink"
+ ]
+ },
+ {
+ "markdown": "www.commonmark.org/he<lp\n",
+ "html": "<p><a href=\"http://www.commonmark.org/he\">www.commonmark.org/he</a><lp</p>\n",
+ "example": 627,
+ "start_line": 9288,
+ "end_line": 9292,
+ "section": "Autolinks (extension)",
+ "extensions": [
+ "autolink"
+ ]
+ },
+ {
+ "markdown": "http://commonmark.org\n\n(Visit https://encrypted.google.com/search?q=Markup+(business))\n\nAnonymous FTP is available at ftp://foo.bar.baz.\n",
+ "html": "<p><a href=\"http://commonmark.org\">http://commonmark.org</a></p>\n<p>(Visit <a href=\"https://encrypted.google.com/search?q=Markup+(business)\">https://encrypted.google.com/search?q=Markup+(business)</a>)</p>\n<p>Anonymous FTP is available at <a href=\"ftp://foo.bar.baz\">ftp://foo.bar.baz</a>.</p>\n",
+ "example": 628,
+ "start_line": 9299,
+ "end_line": 9309,
+ "section": "Autolinks (extension)",
+ "extensions": [
+ "autolink"
+ ]
+ },
+ {
+ "markdown": "foo@bar.baz\n",
+ "html": "<p><a href=\"mailto:foo@bar.baz\">foo@bar.baz</a></p>\n",
+ "example": 629,
+ "start_line": 9325,
+ "end_line": 9329,
+ "section": "Autolinks (extension)",
+ "extensions": [
+ "autolink"
+ ]
+ },
+ {
+ "markdown": "hello@mail+xyz.example isn't valid, but hello+xyz@mail.example is.\n",
+ "html": "<p>hello@mail+xyz.example isn't valid, but <a href=\"mailto:hello+xyz@mail.example\">hello+xyz@mail.example</a> is.</p>\n",
+ "example": 630,
+ "start_line": 9333,
+ "end_line": 9337,
+ "section": "Autolinks (extension)",
+ "extensions": [
+ "autolink"
+ ]
+ },
+ {
+ "markdown": "a.b-c_d@a.b\n\na.b-c_d@a.b.\n\na.b-c_d@a.b-\n\na.b-c_d@a.b_\n",
+ "html": "<p><a href=\"mailto:a.b-c_d@a.b\">a.b-c_d@a.b</a></p>\n<p><a href=\"mailto:a.b-c_d@a.b\">a.b-c_d@a.b</a>.</p>\n<p>a.b-c_d@a.b-</p>\n<p>a.b-c_d@a.b_</p>\n",
+ "example": 631,
+ "start_line": 9343,
+ "end_line": 9356,
+ "section": "Autolinks (extension)",
+ "extensions": [
+ "autolink"
+ ]
+ },
+ {
+ "markdown": "<a><bab><c2c>\n",
+ "html": "<p><a><bab><c2c></p>\n",
+ "example": 632,
+ "start_line": 9434,
+ "end_line": 9438,
+ "section": "Raw HTML",
+ "extensions": []
+ },
+ {
+ "markdown": "<a/><b2/>\n",
+ "html": "<p><a/><b2/></p>\n",
+ "example": 633,
+ "start_line": 9443,
+ "end_line": 9447,
+ "section": "Raw HTML",
+ "extensions": []
+ },
+ {
+ "markdown": "<a /><b2\ndata=\"foo\" >\n",
+ "html": "<p><a /><b2\ndata=\"foo\" ></p>\n",
+ "example": 634,
+ "start_line": 9452,
+ "end_line": 9458,
+ "section": "Raw HTML",
+ "extensions": []
+ },
+ {
+ "markdown": "<a foo=\"bar\" bam = 'baz <em>\"</em>'\n_boolean zoop:33=zoop:33 />\n",
+ "html": "<p><a foo=\"bar\" bam = 'baz <em>\"</em>'\n_boolean zoop:33=zoop:33 /></p>\n",
+ "example": 635,
+ "start_line": 9463,
+ "end_line": 9469,
+ "section": "Raw HTML",
+ "extensions": []
+ },
+ {
+ "markdown": "Foo <responsive-image src=\"foo.jpg\" />\n",
+ "html": "<p>Foo <responsive-image src=\"foo.jpg\" /></p>\n",
+ "example": 636,
+ "start_line": 9474,
+ "end_line": 9478,
+ "section": "Raw HTML",
+ "extensions": []
+ },
+ {
+ "markdown": "<33> <__>\n",
+ "html": "<p><33> <__></p>\n",
+ "example": 637,
+ "start_line": 9483,
+ "end_line": 9487,
+ "section": "Raw HTML",
+ "extensions": []
+ },
+ {
+ "markdown": "<a h*#ref=\"hi\">\n",
+ "html": "<p><a h*#ref="hi"></p>\n",
+ "example": 638,
+ "start_line": 9492,
+ "end_line": 9496,
+ "section": "Raw HTML",
+ "extensions": []
+ },
+ {
+ "markdown": "<a href=\"hi'> <a href=hi'>\n",
+ "html": "<p><a href="hi'> <a href=hi'></p>\n",
+ "example": 639,
+ "start_line": 9501,
+ "end_line": 9505,
+ "section": "Raw HTML",
+ "extensions": []
+ },
+ {
+ "markdown": "< a><\nfoo><bar/ >\n<foo bar=baz\nbim!bop />\n",
+ "html": "<p>< a><\nfoo><bar/ >\n<foo bar=baz\nbim!bop /></p>\n",
+ "example": 640,
+ "start_line": 9510,
+ "end_line": 9520,
+ "section": "Raw HTML",
+ "extensions": []
+ },
+ {
+ "markdown": "<a href='bar'title=title>\n",
+ "html": "<p><a href='bar'title=title></p>\n",
+ "example": 641,
+ "start_line": 9525,
+ "end_line": 9529,
+ "section": "Raw HTML",
+ "extensions": []
+ },
+ {
+ "markdown": "</a></foo >\n",
+ "html": "<p></a></foo ></p>\n",
+ "example": 642,
+ "start_line": 9534,
+ "end_line": 9538,
+ "section": "Raw HTML",
+ "extensions": []
+ },
+ {
+ "markdown": "</a href=\"foo\">\n",
+ "html": "<p></a href="foo"></p>\n",
+ "example": 643,
+ "start_line": 9543,
+ "end_line": 9547,
+ "section": "Raw HTML",
+ "extensions": []
+ },
+ {
+ "markdown": "foo <!-- this is a --\ncomment - with hyphens -->\n",
+ "html": "<p>foo <!-- this is a --\ncomment - with hyphens --></p>\n",
+ "example": 644,
+ "start_line": 9552,
+ "end_line": 9558,
+ "section": "Raw HTML",
+ "extensions": []
+ },
+ {
+ "markdown": "foo <!--> foo -->\n\nfoo <!---> foo -->\n",
+ "html": "<p>foo <!--> foo --></p>\n<p>foo <!---> foo --></p>\n",
+ "example": 645,
+ "start_line": 9560,
+ "end_line": 9567,
+ "section": "Raw HTML",
+ "extensions": []
+ },
+ {
+ "markdown": "foo <?php echo $a; ?>\n",
+ "html": "<p>foo <?php echo $a; ?></p>\n",
+ "example": 646,
+ "start_line": 9572,
+ "end_line": 9576,
+ "section": "Raw HTML",
+ "extensions": []
+ },
+ {
+ "markdown": "foo <!ELEMENT br EMPTY>\n",
+ "html": "<p>foo <!ELEMENT br EMPTY></p>\n",
+ "example": 647,
+ "start_line": 9581,
+ "end_line": 9585,
+ "section": "Raw HTML",
+ "extensions": []
+ },
+ {
+ "markdown": "foo <![CDATA[>&<]]>\n",
+ "html": "<p>foo <![CDATA[>&<]]></p>\n",
+ "example": 648,
+ "start_line": 9590,
+ "end_line": 9594,
+ "section": "Raw HTML",
+ "extensions": []
+ },
+ {
+ "markdown": "foo <a href=\"ö\">\n",
+ "html": "<p>foo <a href=\"ö\"></p>\n",
+ "example": 649,
+ "start_line": 9600,
+ "end_line": 9604,
+ "section": "Raw HTML",
+ "extensions": []
+ },
+ {
+ "markdown": "foo <a href=\"\\*\">\n",
+ "html": "<p>foo <a href=\"\\*\"></p>\n",
+ "example": 650,
+ "start_line": 9609,
+ "end_line": 9613,
+ "section": "Raw HTML",
+ "extensions": []
+ },
+ {
+ "markdown": "<a href=\"\\\"\">\n",
+ "html": "<p><a href="""></p>\n",
+ "example": 651,
+ "start_line": 9616,
+ "end_line": 9620,
+ "section": "Raw HTML",
+ "extensions": []
+ },
+ {
+ "markdown": "<strong> <title> <style> <em>\n\n<blockquote>\n <xmp> is disallowed. <XMP> is also disallowed.\n</blockquote>\n",
+ "html": "<p><strong> <title> <style> <em></p>\n<blockquote>\n <xmp> is disallowed. <XMP> is also disallowed.\n</blockquote>\n",
+ "example": 652,
+ "start_line": 9647,
+ "end_line": 9658,
+ "section": "Disallowed Raw HTML (extension)",
+ "extensions": [
+ "tagfilter"
+ ]
+ },
+ {
+ "markdown": "foo \nbaz\n",
+ "html": "<p>foo<br />\nbaz</p>\n",
+ "example": 653,
+ "start_line": 9669,
+ "end_line": 9675,
+ "section": "Hard line breaks",
+ "extensions": []
+ },
+ {
+ "markdown": "foo\\\nbaz\n",
+ "html": "<p>foo<br />\nbaz</p>\n",
+ "example": 654,
+ "start_line": 9681,
+ "end_line": 9687,
+ "section": "Hard line breaks",
+ "extensions": []
+ },
+ {
+ "markdown": "foo \nbaz\n",
+ "html": "<p>foo<br />\nbaz</p>\n",
+ "example": 655,
+ "start_line": 9692,
+ "end_line": 9698,
+ "section": "Hard line breaks",
+ "extensions": []
+ },
+ {
+ "markdown": "foo \n bar\n",
+ "html": "<p>foo<br />\nbar</p>\n",
+ "example": 656,
+ "start_line": 9703,
+ "end_line": 9709,
+ "section": "Hard line breaks",
+ "extensions": []
+ },
+ {
+ "markdown": "foo\\\n bar\n",
+ "html": "<p>foo<br />\nbar</p>\n",
+ "example": 657,
+ "start_line": 9712,
+ "end_line": 9718,
+ "section": "Hard line breaks",
+ "extensions": []
+ },
+ {
+ "markdown": "*foo \nbar*\n",
+ "html": "<p><em>foo<br />\nbar</em></p>\n",
+ "example": 658,
+ "start_line": 9724,
+ "end_line": 9730,
+ "section": "Hard line breaks",
+ "extensions": []
+ },
+ {
+ "markdown": "*foo\\\nbar*\n",
+ "html": "<p><em>foo<br />\nbar</em></p>\n",
+ "example": 659,
+ "start_line": 9733,
+ "end_line": 9739,
+ "section": "Hard line breaks",
+ "extensions": []
+ },
+ {
+ "markdown": "`code \nspan`\n",
+ "html": "<p><code>code span</code></p>\n",
+ "example": 660,
+ "start_line": 9744,
+ "end_line": 9749,
+ "section": "Hard line breaks",
+ "extensions": []
+ },
+ {
+ "markdown": "`code\\\nspan`\n",
+ "html": "<p><code>code\\ span</code></p>\n",
+ "example": 661,
+ "start_line": 9752,
+ "end_line": 9757,
+ "section": "Hard line breaks",
+ "extensions": []
+ },
+ {
+ "markdown": "<a href=\"foo \nbar\">\n",
+ "html": "<p><a href=\"foo \nbar\"></p>\n",
+ "example": 662,
+ "start_line": 9762,
+ "end_line": 9768,
+ "section": "Hard line breaks",
+ "extensions": []
+ },
+ {
+ "markdown": "<a href=\"foo\\\nbar\">\n",
+ "html": "<p><a href=\"foo\\\nbar\"></p>\n",
+ "example": 663,
+ "start_line": 9771,
+ "end_line": 9777,
+ "section": "Hard line breaks",
+ "extensions": []
+ },
+ {
+ "markdown": "foo\\\n",
+ "html": "<p>foo\\</p>\n",
+ "example": 664,
+ "start_line": 9784,
+ "end_line": 9788,
+ "section": "Hard line breaks",
+ "extensions": []
+ },
+ {
+ "markdown": "foo \n",
+ "html": "<p>foo</p>\n",
+ "example": 665,
+ "start_line": 9791,
+ "end_line": 9795,
+ "section": "Hard line breaks",
+ "extensions": []
+ },
+ {
+ "markdown": "### foo\\\n",
+ "html": "<h3>foo\\</h3>\n",
+ "example": 666,
+ "start_line": 9798,
+ "end_line": 9802,
+ "section": "Hard line breaks",
+ "extensions": []
+ },
+ {
+ "markdown": "### foo \n",
+ "html": "<h3>foo</h3>\n",
+ "example": 667,
+ "start_line": 9805,
+ "end_line": 9809,
+ "section": "Hard line breaks",
+ "extensions": []
+ },
+ {
+ "markdown": "foo\nbaz\n",
+ "html": "<p>foo\nbaz</p>\n",
+ "example": 668,
+ "start_line": 9820,
+ "end_line": 9826,
+ "section": "Soft line breaks",
+ "extensions": []
+ },
+ {
+ "markdown": "foo \n baz\n",
+ "html": "<p>foo\nbaz</p>\n",
+ "example": 669,
+ "start_line": 9832,
+ "end_line": 9838,
+ "section": "Soft line breaks",
+ "extensions": []
+ },
+ {
+ "markdown": "hello $.;'there\n",
+ "html": "<p>hello $.;'there</p>\n",
+ "example": 670,
+ "start_line": 9852,
+ "end_line": 9856,
+ "section": "Textual content",
+ "extensions": []
+ },
+ {
+ "markdown": "Foo \u03c7\u03c1\u1fc6\u03bd\n",
+ "html": "<p>Foo \u03c7\u03c1\u1fc6\u03bd</p>\n",
+ "example": 671,
+ "start_line": 9859,
+ "end_line": 9863,
+ "section": "Textual content",
+ "extensions": []
+ },
+ {
+ "markdown": "Multiple spaces\n",
+ "html": "<p>Multiple spaces</p>\n",
+ "example": 672,
+ "start_line": 9868,
+ "end_line": 9872,
+ "section": "Textual content",
+ "extensions": []
+ }
+]
\ No newline at end of file
diff --git a/pkgs/markdown/tool/stats.dart b/pkgs/markdown/tool/stats.dart
new file mode 100644
index 0000000..67b1d39
--- /dev/null
+++ b/pkgs/markdown/tool/stats.dart
@@ -0,0 +1,266 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:collection';
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:args/args.dart';
+import 'package:collection/collection.dart';
+import 'package:path/path.dart' as p;
+
+import '../tool/expected_output.dart';
+import 'stats_lib.dart';
+
+final _configs = List<Config>.unmodifiable([
+ Config.commonMarkConfig,
+ Config.gfmConfig,
+]);
+
+Future<void> main(List<String> args) async {
+ final parser = ArgParser()
+ ..addOption(
+ 'section',
+ help: 'Restrict tests to one section, provided after the option.',
+ )
+ ..addFlag(
+ 'raw',
+ help: 'raw JSON format',
+ negatable: false,
+ )
+ ..addFlag(
+ 'update-files',
+ help: 'Update stats files in $toolDir',
+ negatable: false,
+ )
+ ..addFlag(
+ 'verbose',
+ help: 'Print details for failures and errors.',
+ negatable: false,
+ )
+ ..addFlag(
+ 'verbose-loose',
+ help: 'Print details for "loose" matches.',
+ negatable: false,
+ )
+ ..addOption('flavor', allowed: _configs.map((c) => c.prefix))
+ ..addFlag('help', negatable: false);
+
+ ArgResults options;
+
+ try {
+ options = parser.parse(args);
+ } on FormatException catch (e) {
+ stderr.writeln(e);
+ print(parser.usage);
+ exitCode = 64; // unix standard improper usage
+ return;
+ }
+
+ if (options['help'] as bool) {
+ print(parser.usage);
+ return;
+ }
+
+ final specifiedSection = options['section'] as String?;
+ final raw = options['raw'] as bool;
+ final verbose = options['verbose'] as bool;
+ final verboseLooseMatch = options['verbose-loose'] as bool;
+ final updateFiles = options['update-files'] as bool;
+
+ if (updateFiles && (raw || verbose || (specifiedSection != null))) {
+ stderr.writeln('The `update-files` flag must be used by itself');
+ print(parser.usage);
+ exitCode = 64; // unix standard improper usage
+ return;
+ }
+
+ var testPrefix = options['flavor'] as String?;
+ if (!updateFiles) {
+ testPrefix = _configs.first.prefix;
+ }
+
+ final testPrefixes =
+ testPrefix == null ? _configs.map((c) => c.prefix) : <String>[testPrefix];
+
+ for (final testPrefix in testPrefixes) {
+ await _processConfig(
+ testPrefix,
+ raw,
+ updateFiles,
+ verbose,
+ specifiedSection,
+ verboseLooseMatch,
+ );
+ }
+}
+
+final _sectionNameReplace = RegExp(r'[ \)\(]+');
+
+String _unitOutput(Iterable<DataCase> cases) => cases.map((dataCase) => '''
+>>> ${dataCase.front_matter}
+${dataCase.input}<<<
+${dataCase.expectedOutput}''').join();
+
+/// Set this to `true` and rerun `--update-files` to ease finding easy strict
+/// fixes.
+const _improveStrict = false;
+
+Future<void> _processConfig(
+ String testPrefix,
+ bool raw,
+ bool updateFiles,
+ bool verbose,
+ String? specifiedSection,
+ bool verboseLooseMatch,
+) async {
+ final config = _configs.singleWhere((c) => c.prefix == testPrefix);
+
+ final sections = loadCommonMarkSections(testPrefix);
+
+ final scores = SplayTreeMap<String, SplayTreeMap<int, CompareLevel>>(
+ compareAsciiLowerCaseNatural);
+
+ for (final entry in sections.entries) {
+ if (specifiedSection != null && entry.key != specifiedSection) {
+ continue;
+ }
+
+ final units = <DataCase>[];
+
+ for (final e in entry.value) {
+ final result = compareResult(
+ config,
+ e,
+ verboseFail: verbose,
+ verboseLooseMatch: verboseLooseMatch,
+ extensions: e.extensions,
+ );
+
+ units.add(DataCase(
+ front_matter: result.testCase.toString(),
+ input: result.testCase.markdown,
+ expectedOutput:
+ (_improveStrict && result.compareLevel == CompareLevel.loose)
+ ? result.testCase.html
+ : result.result!,
+ ));
+
+ final nestedMap = scores.putIfAbsent(
+ entry.key,
+ SplayTreeMap<int, CompareLevel>.new,
+ );
+ nestedMap[e.example] = result.compareLevel;
+ }
+
+ if (updateFiles && units.isNotEmpty) {
+ var fileName =
+ entry.key.toLowerCase().replaceAll(_sectionNameReplace, '_');
+ while (fileName.endsWith('_')) {
+ fileName = fileName.substring(0, fileName.length - 1);
+ }
+ fileName = '$fileName.unit';
+ File(p.join('test', testPrefix, fileName))
+ ..createSync(recursive: true)
+ ..writeAsStringSync(_unitOutput(units));
+ }
+ }
+
+ if (raw || updateFiles) {
+ await _printRaw(testPrefix, scores, updateFiles);
+ }
+
+ if (!raw || updateFiles) {
+ await _printFriendly(testPrefix, scores, updateFiles);
+ }
+}
+
+Object? _convert(Object? obj) {
+ if (obj is CompareLevel) {
+ return obj.name;
+ }
+ if (obj is Map) {
+ return obj
+ .map<String, Object?>((key, value) => MapEntry(key.toString(), value));
+ }
+ return obj;
+}
+
+Future<void> _printRaw(
+ String testPrefix,
+ Map<String, Map<int, CompareLevel>> scores,
+ bool updateFiles,
+) async {
+ IOSink sink;
+ if (updateFiles) {
+ final file = getStatsFile(testPrefix);
+ print('Updating ${file.path}');
+ sink = file.openWrite();
+ } else {
+ sink = stdout;
+ }
+
+ const encoder = JsonEncoder.withIndent(' ', _convert);
+ try {
+ sink.writeln(encoder.convert(scores));
+ // ignore: avoid_catching_errors
+ } on JsonUnsupportedObjectError catch (e) {
+ stderr.writeln(e.cause);
+ stderr.writeln(e.unsupportedObject.runtimeType);
+ rethrow;
+ }
+
+ await sink.flush();
+ await sink.close();
+}
+
+String _pct(int value, int total, String section) =>
+ '${value.toString().padLeft(4)} '
+ 'of ${total.toString().padLeft(4)} '
+ '– ${(100 * value / total).toStringAsFixed(1).padLeft(5)}% $section';
+
+Future<void> _printFriendly(
+ String testPrefix,
+ SplayTreeMap<String, SplayTreeMap<int, CompareLevel>> scores,
+ bool updateFiles,
+) async {
+ var totalValid = 0;
+ var totalStrict = 0;
+ var totalExamples = 0;
+
+ IOSink sink;
+ if (updateFiles) {
+ final path = p.join(toolDir, '${testPrefix}_stats.txt');
+ print('Updating $path');
+ final file = File(path);
+ sink = file.openWrite();
+ } else {
+ sink = stdout;
+ }
+
+ scores.forEach((section, Map<int, CompareLevel> map) {
+ final total = map.values.length;
+ totalExamples += total;
+
+ final sectionStrictCount =
+ map.values.where((val) => val == CompareLevel.strict).length;
+
+ final sectionLooseCount =
+ map.values.where((val) => val == CompareLevel.loose).length;
+
+ final sectionValidCount = sectionStrictCount + sectionLooseCount;
+
+ totalStrict += sectionStrictCount;
+ totalValid += sectionValidCount;
+
+ sink.writeln(_pct(sectionValidCount, total, section));
+ });
+
+ sink.writeln(_pct(totalValid, totalExamples, 'TOTAL'));
+ sink.writeln(_pct(totalStrict, totalValid, 'TOTAL Strict'));
+
+ await sink.flush();
+ await sink.close();
+}
diff --git a/pkgs/markdown/tool/stats_lib.dart b/pkgs/markdown/tool/stats_lib.dart
new file mode 100644
index 0000000..5ff6321
--- /dev/null
+++ b/pkgs/markdown/tool/stats_lib.dart
@@ -0,0 +1,276 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert';
+import 'dart:io';
+import 'dart:mirrors';
+
+import 'package:html/dom.dart' show Element;
+import 'package:html/parser.dart' show parseFragment;
+import 'package:markdown/markdown.dart'
+ show
+ AutolinkExtensionSyntax,
+ BlockSyntax,
+ InlineSyntax,
+ StrikethroughSyntax,
+ TableSyntax,
+ markdownToHtml;
+import 'package:path/path.dart' as p;
+
+import '../test/util.dart';
+
+// Locate the "tool" directory. Use mirrors so that this works with the test
+// package, which loads this suite into an isolate.
+String get toolDir {
+ final path = (reflect(loadCommonMarkSections) as ClosureMirror)
+ .function
+ .location!
+ .sourceUri
+ .path;
+
+ return p.dirname(path);
+}
+
+File getStatsFile(String prefix) =>
+ File(p.join(toolDir, '${prefix}_stats.json'));
+
+Map<String, List<CommonMarkTestCase>> loadCommonMarkSections(
+ String testPrefix) {
+ final testFile = File(p.join(toolDir, '${testPrefix}_tests.json'));
+ final testsJson = testFile.readAsStringSync();
+
+ final testArray = jsonDecode(testsJson) as List;
+
+ final sections = <String, List<CommonMarkTestCase>>{};
+
+ for (final exampleMap in testArray) {
+ final exampleTest =
+ CommonMarkTestCase.fromJson(exampleMap as Map<String, dynamic>);
+
+ final sectionList =
+ sections.putIfAbsent(exampleTest.section, () => <CommonMarkTestCase>[]);
+
+ sectionList.add(exampleTest);
+ }
+
+ return sections;
+}
+
+class Config {
+ static final Config commonMarkConfig = Config._(
+ 'common_mark',
+ 'https://spec.commonmark.org/0.30/',
+ );
+ static final Config gfmConfig = Config._(
+ 'gfm',
+ 'https://github.github.com/gfm/',
+ );
+
+ final String prefix;
+ final String baseUrl;
+
+ Config._(this.prefix, this.baseUrl);
+}
+
+class CommonMarkTestCase {
+ final String markdown;
+ final String section;
+ final int example;
+ final String html;
+ final int startLine;
+ final int endLine;
+ final Set<String> extensions;
+
+ CommonMarkTestCase(
+ this.example,
+ this.section,
+ this.startLine,
+ this.endLine,
+ this.markdown,
+ this.html,
+ this.extensions,
+ );
+
+ factory CommonMarkTestCase.fromJson(Map<String, dynamic> json) {
+ return CommonMarkTestCase(
+ json['example'] as int,
+ json['section'] as String /*!*/,
+ json['start_line'] as int,
+ json['end_line'] as int,
+ json['markdown'] as String /*!*/,
+ json['html'] as String,
+ json['extensions'] == null
+ ? const {}
+ : Set.from(json['extensions'] as List),
+ );
+ }
+
+ @override
+ String toString() => '$section - $example';
+}
+
+enum CompareLevel { strict, loose, fail, error }
+
+class CompareResult {
+ final CompareLevel compareLevel;
+ final CommonMarkTestCase testCase;
+ final String? result;
+
+ CompareResult(this.testCase, this.result, this.compareLevel);
+}
+
+CompareResult compareResult(
+ Config config,
+ CommonMarkTestCase testCase, {
+ bool throwOnError = false,
+ bool verboseFail = false,
+ bool verboseLooseMatch = false,
+ Set<String> extensions = const {},
+}) {
+ var enabletagfilter = false;
+
+ String output;
+ final inlineSyntaxes = <InlineSyntax>[];
+ final blockSyntaxes = <BlockSyntax>[];
+
+ for (final extension in extensions) {
+ switch (extension) {
+ case 'autolink':
+ inlineSyntaxes.add(AutolinkExtensionSyntax());
+ break;
+ case 'strikethrough':
+ inlineSyntaxes.add(StrikethroughSyntax());
+ break;
+ case 'table':
+ blockSyntaxes.add(const TableSyntax());
+ break;
+ case 'tagfilter':
+ enabletagfilter = true;
+ break;
+ default:
+ throw UnimplementedError('Unimplemented extension "$extension"');
+ }
+ }
+
+ try {
+ output = markdownToHtml(
+ testCase.markdown,
+ inlineSyntaxes: inlineSyntaxes,
+ blockSyntaxes: blockSyntaxes,
+ enableTagfilter: enabletagfilter,
+ );
+ } catch (err, stackTrace) {
+ if (throwOnError) {
+ rethrow;
+ }
+ if (verboseFail) {
+ _printVerboseFailure(
+ config.baseUrl,
+ 'ERROR',
+ testCase,
+ 'Thrown: $err\n$stackTrace',
+ );
+ }
+
+ return CompareResult(testCase, null, CompareLevel.error);
+ }
+
+ if (testCase.html == output) {
+ return CompareResult(testCase, output, CompareLevel.strict);
+ }
+
+ final expectedParsed = parseFragment(testCase.html);
+ final actual = parseFragment(output);
+
+ final looseMatch = _compareHtml(expectedParsed.children, actual.children);
+
+ if (!looseMatch && verboseFail) {
+ _printVerboseFailure(config.baseUrl, 'FAIL', testCase, output);
+ }
+
+ if (looseMatch && verboseLooseMatch) {
+ _printVerboseFailure(config.baseUrl, 'LOOSE', testCase, output);
+ }
+
+ return CompareResult(
+ testCase,
+ output,
+ looseMatch ? CompareLevel.loose : CompareLevel.fail,
+ );
+}
+
+String _indent(String s) =>
+ s.splitMapJoin('\n', onNonMatch: (n) => ' ${whitespaceColor(n)}');
+
+void _printVerboseFailure(
+ String baseUrl,
+ String message,
+ CommonMarkTestCase testCase,
+ String actual,
+) {
+ print('$message: $baseUrl#example-${testCase.example} '
+ '@ ${testCase.section}');
+ print('input:');
+ print(_indent(testCase.markdown));
+ print('expected:');
+ print(_indent(testCase.html));
+ print('actual:');
+ print(_indent(actual));
+ print('-----------------------');
+}
+
+/// Compare two DOM trees for equality.
+bool _compareHtml(
+ List<Element> expectedElements,
+ List<Element> actualElements,
+) {
+ if (expectedElements.length != actualElements.length) {
+ return false;
+ }
+
+ for (var childNum = 0; childNum < expectedElements.length; childNum++) {
+ final expected = expectedElements[childNum];
+ final actual = actualElements[childNum];
+
+ if (expected.runtimeType != actual.runtimeType) {
+ return false;
+ }
+
+ if (expected.localName != actual.localName) {
+ return false;
+ }
+
+ if (expected.attributes.length != actual.attributes.length) {
+ return false;
+ }
+
+ final expectedAttrKeys = expected.attributes.keys.toList();
+ expectedAttrKeys.sort();
+
+ final actualAttrKeys = actual.attributes.keys.toList();
+ actualAttrKeys.sort();
+
+ for (var attrNum = 0; attrNum < actualAttrKeys.length; attrNum++) {
+ final expectedAttrKey = expectedAttrKeys[attrNum];
+ final actualAttrKey = actualAttrKeys[attrNum];
+
+ if (expectedAttrKey != actualAttrKey) {
+ return false;
+ }
+
+ if (expected.attributes[expectedAttrKey] !=
+ actual.attributes[actualAttrKey]) {
+ return false;
+ }
+ }
+
+ final childrenEqual = _compareHtml(expected.children, actual.children);
+
+ if (!childrenEqual) {
+ return false;
+ }
+ }
+
+ return true;
+}
diff --git a/pkgs/markdown/tool/update-gh-pages.sh b/pkgs/markdown/tool/update-gh-pages.sh
new file mode 100755
index 0000000..97762ad
--- /dev/null
+++ b/pkgs/markdown/tool/update-gh-pages.sh
@@ -0,0 +1,13 @@
+# Echo every command being run.
+set +x
+
+# Fail fast if a command fails.
+set -e
+
+dart pub global activate peanut
+
+peanut -d example
+
+echo Now push updated gh-pages branch with:
+echo
+echo ' git push origin --set-upstream gh-pages'
diff --git a/pkgs/markdown/tool/update_blns.dart b/pkgs/markdown/tool/update_blns.dart
new file mode 100644
index 0000000..fbdabca
--- /dev/null
+++ b/pkgs/markdown/tool/update_blns.dart
@@ -0,0 +1,33 @@
+import 'dart:async';
+import 'dart:io';
+
+import 'update_shared.dart';
+
+const _blnsJsonRawUrl =
+ 'https://github.com/minimaxir/big-list-of-naughty-strings/raw/master/blns.json';
+const _blnsFilePath = 'test/blns.dart';
+
+Future<void> main() async {
+ final json = (await downloadJson(_blnsJsonRawUrl) as List).cast<String>();
+ final blnsContent = StringBuffer('''
+// GENERATED FILE. DO NOT EDIT.
+//
+// This file was generated from big-list-of-naughty-strings's JSON file:
+// $_blnsJsonRawUrl
+// at ${DateTime.now()} by the script, tool/update_blns.dart.
+
+// ignore_for_file: text_direction_code_point_in_literal, use_raw_strings
+// ignore_for_file: lines_longer_than_80_chars
+
+''');
+ blnsContent.writeln('const blns = <String>[');
+ for (final str in json) {
+ final escaped = str
+ .replaceAll(r'\', r'\\')
+ .replaceAll("'", r"\'")
+ .replaceAll(r'$', r'\$');
+ blnsContent.writeln(" '$escaped',");
+ }
+ blnsContent.writeln('];');
+ File(_blnsFilePath).writeAsStringSync(blnsContent.toString());
+}
diff --git a/pkgs/markdown/tool/update_case_folding.dart b/pkgs/markdown/tool/update_case_folding.dart
new file mode 100644
index 0000000..e53f70b
--- /dev/null
+++ b/pkgs/markdown/tool/update_case_folding.dart
@@ -0,0 +1,51 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:path/path.dart' as p;
+
+// Generates and updates unicode case folding map.
+// Here only extract status C + F capital letters.
+void main() {
+ // Downloaded from http://www.unicode.org/Public/14.0.0/ucd/CaseFolding.txt
+ final file = File('${p.current}/tool/case_folding.txt');
+
+ final result = <String, String>{};
+
+ for (final line in file.readAsLinesSync()) {
+ if (line.startsWith('#') ||
+ line.trim().isEmpty ||
+ !line.contains('CAPITAL LETTER')) {
+ continue;
+ }
+
+ final content = line.substring(0, line.indexOf('#'));
+ final match =
+ RegExp(r'([0-9A-F]{1,6});\s+[CF];\s+(.+);').firstMatch(content);
+ if (match == null) {
+ continue;
+ }
+
+ final key = String.fromCharCode(int.parse(match[1]!, radix: 16));
+ final value = match[2]!.split(RegExp('[ ]+')).map((e) {
+ return String.fromCharCode(int.parse(e, radix: 16));
+ }).join();
+ result[key] = value;
+ }
+
+ final outputPath = '${p.current}/lib/src/assets/case_folding.dart';
+ final stringMap = const JsonEncoder.withIndent(' ').convert(result);
+ final output = '''
+// Generated file. do not edit.
+//
+// Source: tool/case_folding.txt
+// Script: tool/update_case_folding.dart
+// ignore_for_file: prefer_single_quotes
+
+const caseFoldingMap = $stringMap;
+''';
+ File(outputPath).writeAsStringSync(output);
+}
diff --git a/pkgs/markdown/tool/update_emojis.dart b/pkgs/markdown/tool/update_emojis.dart
new file mode 100644
index 0000000..0b2b8a9
--- /dev/null
+++ b/pkgs/markdown/tool/update_emojis.dart
@@ -0,0 +1,56 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:io';
+
+import 'update_shared.dart';
+
+// update_github_emojis.dart now generates the emoji list using the GitHub API
+// to retrieve the emoji list. It uses this emoji source as a source to keep
+// binary compatibility with the Unicode sequences for each emoji found here.
+const _emojisJsonRawUrl =
+ 'https://raw.githubusercontent.com/muan/emojilib/v2.4.0/emojis.json';
+const _emojisFilePath = 'lib/src/legacy_emojis.dart';
+
+Future<void> main() async {
+ final json =
+ (await downloadJson(_emojisJsonRawUrl) as Map<String, dynamic>).map(
+ (String alias, dynamic info) =>
+ MapEntry(alias, info as Map<String, dynamic>),
+ );
+ final emojisContent = StringBuffer('''
+// GENERATED FILE. DO NOT EDIT.
+//
+// This file was generated from emojilib's emoji data file:
+// $_emojisJsonRawUrl
+// at ${DateTime.now()} by the script, tool/update_emojis.dart.
+
+''');
+ emojisContent.writeln('const emojis = <String, String>{');
+ var emojiCount = 0;
+ final ignored = <String>[];
+ // Dump in sorted order now to facilitate comparison with new GitHub emoji.
+ final sortedKeys = json.keys.toList()..sort();
+ for (final alias in sortedKeys) {
+ final info = json[alias] as Map<String, dynamic>;
+ if (info['char'] != null) {
+ emojisContent.writeln(" '$alias': '${info['char']}',");
+ emojiCount++;
+ } else {
+ ignored.add(alias);
+ }
+ }
+ emojisContent.writeln('};');
+ File(_emojisFilePath).writeAsStringSync(emojisContent.toString());
+ print(
+ 'WARNING: This updates only the LEGACY emoji - to update the active '
+ 'emoji recognized by the markdown package, '
+ 'execute `update_github_emojis.dart`.',
+ );
+ print(
+ 'Wrote data to $_emojisFilePath for $emojiCount emoji, '
+ 'ignoring ${ignored.length}: ${ignored.join(', ')}.',
+ );
+}
diff --git a/pkgs/markdown/tool/update_entities.dart b/pkgs/markdown/tool/update_entities.dart
new file mode 100644
index 0000000..2d114bd
--- /dev/null
+++ b/pkgs/markdown/tool/update_entities.dart
@@ -0,0 +1,39 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert';
+import 'dart:io';
+import 'package:path/path.dart' as p;
+
+/// Generates and updates HTML entities.
+void main() {
+ // Original file: https://html.spec.whatwg.org/entities.json
+ final file = File('${p.current}/tool/entities.json');
+ final json = file.readAsStringSync();
+ final map = Map<String, Map<String, dynamic>>.from(jsonDecode(json) as Map);
+
+ final result = <String, String>{};
+ for (final name in map.keys) {
+ if (name.endsWith(';')) {
+ final value = map[name]!['characters'] as String;
+ result[name] = value;
+ }
+ }
+
+ final outputPath = '${p.current}/lib/src/assets/html_entities.dart';
+ final stringMap = const JsonEncoder.withIndent(' ')
+ .convert(result)
+ .replaceAll(r'"$"', r'r"$"')
+ .replaceAll(r'"\\"', r'r"\"');
+ final output = '''
+// Generated file. do not edit.
+//
+// Source: tool/entities.json
+// Script: tool/update_entities.dart
+// ignore_for_file: prefer_single_quotes
+
+const htmlEntitiesMap = $stringMap;
+''';
+ File(outputPath).writeAsStringSync(output);
+}
diff --git a/pkgs/markdown/tool/update_github_emojis.dart b/pkgs/markdown/tool/update_github_emojis.dart
new file mode 100644
index 0000000..fb07ac5
--- /dev/null
+++ b/pkgs/markdown/tool/update_github_emojis.dart
@@ -0,0 +1,348 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:io';
+
+import 'package:args/args.dart';
+import 'package:markdown/src/legacy_emojis.dart' as legacy;
+
+import 'update_shared.dart';
+
+/// Regular expression to parse unicode from GitHub emoji API output filenames.
+RegExp gitHubEmojiUnicodeFromFilenamePattern =
+ RegExp(r'.*unicode\/([A-Fa-f0-9\-]+)\.png');
+
+/// URL for GitHub's emoji API. We reconcile with our legacy emoji so that
+/// we don't change or break anything.
+/// There are essentially only TWO (2) emoji that change and the
+/// legacy emoji is still available with an alternate name.
+/// The 'beetle' emoji changes from `🐞` to `🪲`,
+/// legacy available as 'lady_beetle'.
+/// The 'cricket' emoji changes from `🏏` to `🦗`,
+/// legacy available as 'cricket_game'.
+/// (if the -g flag us used to force using the GitHub Unicode sequences for the
+/// emoji then additionally the 'email' emoji changes from '✉️' to '📧').
+const _emojisJsonRawUrl = 'https://api.github.com/emojis';
+const _emojisFilePath = 'lib/src/emojis.dart';
+
+/// Reference to emoji map within legacy_emojis.dart
+const legacyEmojis = legacy.emojis;
+
+/// AUTO GENERATED by `reconcile_emojis.dart` - this only needed to be done ONCE
+/// during the reconciliation process with the legacy emoji.
+/// This array is ONLY USED when the --useGitHubUnicodes option is used to
+/// minimize the visual differences in the output emoji.
+const legacyEmojisUsedVariationModifier = {
+ '263a',
+ '2600',
+ '2601',
+ '2744',
+ '2708',
+ '260e',
+ '2702',
+ '2712',
+ '270f',
+ '2764',
+ 'd83c-de37',
+ '2734',
+ '3299',
+ '3297',
+ 'd83c-dd70',
+ 'd83c-dd71',
+ 'd83c-dd7e',
+ '2668',
+ '203c',
+ '2049',
+ '303d',
+ '26a0',
+ '267b',
+ '2747',
+ '2733',
+ '24c2',
+ 'd83c-de02',
+ 'd83c-dd7f',
+ '23cf',
+ '25b6',
+ '25c0',
+ '27a1',
+ '2b05',
+ '2b06',
+ '2b07',
+ '2197',
+ '2198',
+ '2199',
+ '2196',
+ '2195',
+ '2194',
+ '21aa',
+ '21a9',
+ '2934',
+ '2935',
+ '2139',
+ '3030',
+ '2714',
+ '2716',
+ '00a9',
+ '00ae',
+ '2122',
+ '2611',
+ '25aa',
+ '25ab',
+ '25fc',
+ '25fb',
+ '2660',
+ '2663',
+ '2665',
+ '2666',
+};
+
+/// Special replacement character '�'
+const errorSpecialReplacement = '\u{FFFD}';
+
+const useOfGitHubUnicodeSequencesWarning = '''
+IMPORTANT NOTE: The use of the --useGitHubUnicodes switch will force using
+GitHub Unicode sequences.
+This option is essentially here only for completeness, not for
+release use.
+The slight visual differences of some emoji might also be another
+reason using --useGitHubUnicodes should be considered a *Breaking Change*.
+
+Some test will fail because of the different Unicode sequences
+and the emojis.unit file would need to be updated to contain the new
+expected GitHub versions of the Unicode sequences of the emoji in order
+for the tests to pass.
+''';
+
+/// The GitHub API URL will return a JSON map of all emoji in the form of
+/// `{ 'shortcode':'emojifilename' ... }`.
+/// The filenames are simply a list of all of the hex string of the
+/// *essential* Unicode codepoints representing the emoji.
+/// These sequences exclude the Unicode join zero width (0x200D) and
+/// variation select (0xFE0F) modifiers. (We will need to add these in to
+/// build our actually Unicode strings representing the emoji).
+/// Multiple Unicode codepoints are separated by '-'.
+/// Examples filenames (single and double code point examples):
+/// - "https://github.githubassets.com/images/icons/emoji/unicode/1f643.png?v8"
+/// - "https://github.githubassets.com/images/icons/emoji/unicode/1f1fa-1f1fe.png?v8"
+/// - "https://github.githubassets.com/images/icons/emoji/unicode/1f469-1f469-1f467-1f466.png?v8"
+/// NOTE: Some filenames will be GitHub 'custom' emoji that have
+/// no Unicode equivalent and these will not have hex codepoints,
+/// only the GitHub custom name.
+/// We will ignore these (there are only a 19 and they are mostly pixel art
+/// from the old Doom game).
+/// Example GitHub custom emoji filename:
+/// - "https://github.githubassets.com/images/icons/emoji/godmode.png?v8",
+String parseGitHubFilenameIntoUnicodeString(String emojiFilename) {
+ const variationSelector = 0xFE0F;
+ const zeroWidthJoiner = 0x200D;
+
+ try {
+ final rawHexList = gitHubEmojiUnicodeFromFilenamePattern
+ .firstMatch(emojiFilename)
+ ?.group(1);
+ if (rawHexList == null) {
+ // This is a GitHub custom emoji and it is represented by a PNG image only
+ // and there is no equivalent Unicode. We have to ignore.
+ return '';
+ }
+ var legacyUsedVariationCode = false;
+ if (legacyEmojisUsedVariationModifier.contains(rawHexList)) {
+ legacyUsedVariationCode = true;
+ }
+ final rawCodePointsHex = rawHexList
+ .split('-')
+ .map((hexstr) => int.parse(hexstr, radix: 16))
+ .toList();
+ final codePointsHex = <int>[];
+
+ if (legacyUsedVariationCode) {
+ // Just add single variation selector.
+ codePointsHex.addAll(rawCodePointsHex);
+ codePointsHex.add(variationSelector);
+ } else {
+ // Now insert the join zero width and
+ // variation select modifying Unicode chars.
+ for (var i = 0; i < rawCodePointsHex.length; i++) {
+ final codePointAtIndex = rawCodePointsHex[i];
+ codePointsHex.add(codePointAtIndex);
+ if (i < (rawCodePointsHex.length - 1)) {
+ codePointsHex.add(variationSelector);
+ // # and 0-9 don't use Zero Width Joiner.
+ if (codePointAtIndex == 0x23 ||
+ (codePointAtIndex >= 0x30 && codePointAtIndex <= 0x39)) {
+ // Don't add Zero Width Joiner.
+ } else {
+ codePointsHex.add(zeroWidthJoiner);
+ }
+ }
+ }
+ }
+ return String.fromCharCodes(codePointsHex);
+ } catch (e) {
+ print(
+ 'Invalid/Non-Conformant emoji filename encountered "$emojiFilename"!');
+ return errorSpecialReplacement;
+ }
+}
+
+Future<void> main(List<String> args) async {
+ final parser = ArgParser()
+ ..addFlag('help',
+ abbr: 'h', negatable: false, help: 'Print help text and exit.')
+ ..addFlag('useGitHubUnicodes',
+ abbr: 'g',
+ negatable: false,
+ help: 'Use the GitHub Unicode sequences instead of legacy sequences.')
+ ..addFlag('visualizeDifferentUnicodes',
+ abbr: 'v',
+ negatable: false,
+ help: 'Visualize any Unicode sequence differences.')
+ ..addOption('dumpMarkdownShortCodes',
+ abbr: 's',
+ defaultsTo: 'missing',
+ allowed: ['plain', 'tooltip'],
+ allowedHelp: {
+ 'plain': 'just shortcode',
+ 'tooltip':
+ '(shortcode with a link to provide emoji name in tooltips)',
+ },
+ help: 'Outputs all emoji shortcodes to stdout which can be used '
+ 'in markdown to show and tests all emoji.');
+ late final ArgResults results;
+
+ try {
+ results = parser.parse(args);
+ } catch (e) {
+ print(e);
+ printUsage(parser);
+ return;
+ }
+
+ if (results['help'] as bool) {
+ printUsage(parser);
+ return;
+ }
+
+ var totalEmojiWithDifferentUnicodeSequences = 0;
+ final useLegacyUnicodeSequences = !(results['useGitHubUnicodes'] as bool);
+ final visualizeUnicodeDiffs = results['visualizeDifferentUnicodes'] as bool;
+
+ final shortCodes =
+ (results['dumpMarkdownShortCodes'] as String).toLowerCase();
+ final dumpMarkdownShortCodes = shortCodes == 'plain';
+ final dumpMarkdownToolTipShortCodes = shortCodes == 'tooltip';
+
+ if (!useLegacyUnicodeSequences) {
+ // Issue warning of the implications of using
+ // full GitHub emoji Unicode sequences.
+ print(useOfGitHubUnicodeSequencesWarning);
+ }
+ if (visualizeUnicodeDiffs) {
+ print(
+ 'The following emoji have different Unicode sequences '
+ 'from those of legacy versions:',
+ );
+ }
+ final shortcodeToEmoji =
+ (await downloadJson(_emojisJsonRawUrl) as Map<String, dynamic>).map(
+ (String alias, dynamic filename) => MapEntry(
+ alias,
+ parseGitHubFilenameIntoUnicodeString(filename as String),
+ ),
+ );
+
+ // Now before we proceed we need to 'mix in' any legacy emoji alias shortcodes
+ // that are missing from the GitHub emoji list.
+ legacyEmojis.forEach((String shortCodeAlias, String emojiUnicode) {
+ if (!shortcodeToEmoji.containsKey(shortCodeAlias)) {
+ shortcodeToEmoji[shortCodeAlias] = emojiUnicode;
+ }
+ });
+
+ final emojisContent = StringBuffer('''
+// GENERATED FILE. DO NOT EDIT.
+//
+// This file was generated from GitHub's emoji API list endpoint:
+// $_emojisJsonRawUrl
+// at ${DateTime.now()} by the script, tool/update_github_emojis.dart.
+
+''');
+ emojisContent.writeln('const emojis = <String, String>{');
+ var emojiCount = 0;
+ final ignored = <String>[];
+ final errored = <String>[];
+ // Dump in sorted order now to facilitate comparison with new GitHub emoji.
+ final sortedKeys = shortcodeToEmoji.keys.toList()..sort();
+ for (final shortCodeAlias in sortedKeys) {
+ var emojiUnicode = shortcodeToEmoji[shortCodeAlias]!;
+ if (useLegacyUnicodeSequences &&
+ legacyEmojis.containsKey(shortCodeAlias) &&
+ shortCodeAlias != 'cricket' &&
+ shortCodeAlias != 'beetle') {
+ emojiUnicode = legacyEmojis[
+ shortCodeAlias]!; // Use legacy Unicode string if available.
+ }
+ if (legacyEmojis.containsKey(shortCodeAlias) &&
+ emojiUnicode != legacyEmojis[shortCodeAlias]) {
+ totalEmojiWithDifferentUnicodeSequences++;
+ if (visualizeUnicodeDiffs) {
+ print(
+ '$emojiUnicode was ${legacyEmojis[shortCodeAlias]} '
+ ':$shortCodeAlias:',
+ );
+ }
+ }
+ if (emojiUnicode != errorSpecialReplacement && emojiUnicode.isNotEmpty) {
+ emojisContent.writeln(" '$shortCodeAlias': '$emojiUnicode',");
+ if (dumpMarkdownShortCodes) {
+ print(':$shortCodeAlias:');
+ } else if (dumpMarkdownToolTipShortCodes) {
+ print('[:$shortCodeAlias:](## ":$shortCodeAlias: emoji")');
+ }
+ emojiCount++;
+ } else {
+ if (emojiUnicode == errorSpecialReplacement) {
+ errored.add(shortCodeAlias);
+ } else {
+ ignored.add(shortCodeAlias);
+ }
+ }
+ }
+ emojisContent.writeln('};');
+ File(_emojisFilePath).writeAsStringSync(emojisContent.toString());
+
+ if (dumpMarkdownShortCodes) {
+ // We are outputing the markdown to stdout, and presumably it
+ // is being captured, so we exit now to exclude the summary
+ // report from being included in the emoji markdown we have
+ // been outputing.
+ return;
+ }
+
+ print('''Wrote data to $_emojisFilePath for $emojiCount emoji,
+$totalEmojiWithDifferentUnicodeSequences emoji's Unicode sequences differ from legacy versions${!visualizeUnicodeDiffs ? " (run with -v flag to visualize)" : ""},
+ignoring ${ignored.length}: ${ignored.join(', ')},
+errored: ${errored.length} ${errored.join(', ')}.''');
+}
+
+void printUsage(ArgParser parser) {
+ print('''Usage: update_emojis.dart [--useGitHubUnicodes | -l]
+
+By default, the legacy Unicode sequences are used (for
+maximum visual compatability with the legacy emoji).
+The --useGitHubUnicodes flag can be used so that the
+Unicode sequences from GitHub are used for emoji's that
+existed within the legacy set. This will result in very slight visual
+differences for some emoji, but it will result in many more
+binary differences when comparing legacy_emoji.dart to emoji.dart.
+$useOfGitHubUnicodeSequencesWarning
+
+The --visualizeDifferentUnicodes flag can be used to visually
+verify that any different Unicode sequences produce the same
+emoji.
+
+${parser.usage}
+''');
+}
diff --git a/pkgs/markdown/tool/update_shared.dart b/pkgs/markdown/tool/update_shared.dart
new file mode 100644
index 0000000..6992cd5
--- /dev/null
+++ b/pkgs/markdown/tool/update_shared.dart
@@ -0,0 +1,21 @@
+// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert';
+import 'dart:io';
+
+Future<Object?> downloadJson(String uri) async {
+ final client = HttpClient();
+ try {
+ final request = await client.getUrl(Uri.parse(uri));
+ final response = await request.close();
+
+ return response
+ .transform(utf8.decoder)
+ .transform(const JsonDecoder())
+ .single;
+ } finally {
+ client.close();
+ }
+}