summaryrefslogtreecommitdiff
path: root/cmark
diff options
context:
space:
mode:
authorMehmet Samet Duman <yongdohyun@projecttick.org>2026-04-02 18:41:54 +0300
committerMehmet Samet Duman <yongdohyun@projecttick.org>2026-04-02 18:41:54 +0300
commit3d2121f5d6555744ce5aa502088fc2b34dc26d38 (patch)
tree53f42c08746171878b57f5b6ffe1eb841da9d45d /cmark
parent6bf7c5ce92ff6237c0b17c332873805018812b40 (diff)
parent64efa3b3b3d35f2ffb604b57a8a9c89047cb420b (diff)
downloadProject-Tick-3d2121f5d6555744ce5aa502088fc2b34dc26d38.tar.gz
Project-Tick-3d2121f5d6555744ce5aa502088fc2b34dc26d38.zip
Add 'cmark/' from commit '64efa3b3b3d35f2ffb604b57a8a9c89047cb420b'
git-subtree-dir: cmark git-subtree-mainline: 6bf7c5ce92ff6237c0b17c332873805018812b40 git-subtree-split: 64efa3b3b3d35f2ffb604b57a8a9c89047cb420b
Diffstat (limited to 'cmark')
-rw-r--r--cmark/.editorconfig21
-rw-r--r--cmark/.gitattributes2
-rw-r--r--cmark/.github/FUNDING.yml1
-rw-r--r--cmark/.github/dependabot.yml7
-rw-r--r--cmark/.github/workflows/ci.yml145
-rw-r--r--cmark/.github/workflows/fuzz.yml23
-rw-r--r--cmark/.gitignore39
-rw-r--r--cmark/CMakeLists.txt128
-rw-r--r--cmark/COPYING170
-rw-r--r--cmark/Makefile214
-rw-r--r--cmark/Makefile.nmake28
-rw-r--r--cmark/README.md190
-rw-r--r--cmark/api_test/CMakeLists.txt16
-rw-r--r--cmark/api_test/cplusplus.cpp15
-rw-r--r--cmark/api_test/cplusplus.h16
-rw-r--r--cmark/api_test/harness.c83
-rw-r--r--cmark/api_test/harness.h35
-rw-r--r--cmark/api_test/main.c1194
-rw-r--r--cmark/bench/samples/block-bq-flat.md16
-rw-r--r--cmark/bench/samples/block-bq-nested.md13
-rw-r--r--cmark/bench/samples/block-code.md11
-rw-r--r--cmark/bench/samples/block-fences.md14
-rw-r--r--cmark/bench/samples/block-heading.md9
-rw-r--r--cmark/bench/samples/block-hr.md10
-rw-r--r--cmark/bench/samples/block-html.md32
-rw-r--r--cmark/bench/samples/block-lheading.md8
-rw-r--r--cmark/bench/samples/block-list-flat.md67
-rw-r--r--cmark/bench/samples/block-list-nested.md36
-rw-r--r--cmark/bench/samples/block-ref-flat.md15
-rw-r--r--cmark/bench/samples/block-ref-nested.md17
-rw-r--r--cmark/bench/samples/inline-autolink.md14
-rw-r--r--cmark/bench/samples/inline-backticks.md3
-rw-r--r--cmark/bench/samples/inline-em-flat.md5
-rw-r--r--cmark/bench/samples/inline-em-nested.md5
-rw-r--r--cmark/bench/samples/inline-em-worst.md5
-rw-r--r--cmark/bench/samples/inline-entity.md11
-rw-r--r--cmark/bench/samples/inline-escape.md15
-rw-r--r--cmark/bench/samples/inline-html.md44
-rw-r--r--cmark/bench/samples/inline-links-flat.md23
-rw-r--r--cmark/bench/samples/inline-links-nested.md13
-rw-r--r--cmark/bench/samples/inline-newlines.md24
-rw-r--r--cmark/bench/samples/lorem1.md13
-rw-r--r--cmark/bench/samples/rawtabs.md18
-rw-r--r--cmark/bench/statistics.py595
-rw-r--r--cmark/bench/stats.py19
-rw-r--r--cmark/benchmarks.md23
-rw-r--r--cmark/changelog.txt1552
-rw-r--r--cmark/cmake/modules/FindAsan.cmake74
-rw-r--r--cmark/data/CaseFolding.txt1682
-rw-r--r--cmark/fuzz/CMakeLists.txt3
-rw-r--r--cmark/fuzz/afl_test_cases/test.md36
-rw-r--r--cmark/fuzz/cmark-fuzz.c75
-rw-r--r--cmark/fuzz/dictionary49
-rw-r--r--cmark/man/CMakeLists.txt4
-rw-r--r--cmark/man/make_man_page.py137
-rw-r--r--cmark/man/man1/cmark.173
-rw-r--r--cmark/man/man3/cmark.3906
-rw-r--r--cmark/nmake.bat1
-rw-r--r--cmark/shell.nix12
-rw-r--r--cmark/src/CMakeLists.txt100
-rw-r--r--cmark/src/blocks.c1345
-rw-r--r--cmark/src/buffer.c209
-rw-r--r--cmark/src/buffer.h74
-rw-r--r--cmark/src/case_fold.inc722
-rw-r--r--cmark/src/chunk.h69
-rw-r--r--cmark/src/cmark.c48
-rw-r--r--cmark/src/cmark.h704
-rw-r--r--cmark/src/cmarkConfig.cmake.in4
-rw-r--r--cmark/src/cmark_ctype.c38
-rw-r--r--cmark/src/cmark_ctype.h24
-rw-r--r--cmark/src/cmark_version.h.in7
-rw-r--r--cmark/src/commonmark.c473
-rw-r--r--cmark/src/entities.inc2054
-rw-r--r--cmark/src/houdini.h41
-rw-r--r--cmark/src/houdini_href_e.c111
-rw-r--r--cmark/src/houdini_html_e.c73
-rw-r--r--cmark/src/houdini_html_u.c174
-rw-r--r--cmark/src/html.c345
-rw-r--r--cmark/src/inlines.c1503
-rw-r--r--cmark/src/inlines.h24
-rw-r--r--cmark/src/iterator.c122
-rw-r--r--cmark/src/iterator.h26
-rw-r--r--cmark/src/latex.c456
-rw-r--r--cmark/src/libcmark.pc.in10
-rw-r--r--cmark/src/main.c213
-rw-r--r--cmark/src/man.c281
-rw-r--r--cmark/src/node.c888
-rw-r--r--cmark/src/node.h93
-rw-r--r--cmark/src/parser.h42
-rw-r--r--cmark/src/references.c171
-rw-r--r--cmark/src/references.h43
-rw-r--r--cmark/src/render.c195
-rw-r--r--cmark/src/render.h57
-rw-r--r--cmark/src/scanners.c9415
-rw-r--r--cmark/src/scanners.h59
-rw-r--r--cmark/src/scanners.re330
-rw-r--r--cmark/src/utf8.c428
-rw-r--r--cmark/src/utf8.h24
-rw-r--r--cmark/src/xml.c229
-rwxr-xr-xcmark/test/CMakeLists.txt62
-rw-r--r--cmark/test/cmark.py88
-rw-r--r--cmark/test/entity_tests.py67
-rw-r--r--cmark/test/normalize.py194
-rw-r--r--cmark/test/pathological_tests.py202
-rw-r--r--cmark/test/regression.txt284
-rw-r--r--cmark/test/roundtrip_tests.py46
-rw-r--r--cmark/test/smart_punct.txt177
-rw-r--r--cmark/test/spec.txt9756
-rwxr-xr-xcmark/test/spec_tests.py158
-rw-r--r--cmark/toolchain-mingw32.cmake17
-rw-r--r--cmark/tools/appveyor-build.bat13
-rw-r--r--cmark/tools/make_case_fold_inc.py96
-rw-r--r--cmark/tools/make_entities_inc.py72
-rw-r--r--cmark/tools/xml2md.xsl319
-rw-r--r--cmark/why-cmark-and-not-x.md104
-rw-r--r--cmark/wrappers/wrapper.php26
-rwxr-xr-xcmark/wrappers/wrapper.py43
-rwxr-xr-xcmark/wrappers/wrapper.rb27
-rw-r--r--cmark/wrappers/wrapper.rkt210
119 files changed, 41194 insertions, 0 deletions
diff --git a/cmark/.editorconfig b/cmark/.editorconfig
new file mode 100644
index 0000000000..9223a323ec
--- /dev/null
+++ b/cmark/.editorconfig
@@ -0,0 +1,21 @@
+# editorconfig.org
+
+root = true
+
+[*]
+end_of_line = lf
+charset = utf-8
+insert_final_newline = true
+
+[*.{c,h}]
+trim_trailing_whitespace = true
+indent_style = space
+indent_size = 2
+
+[Makefile]
+trim_trailing_whitespace = true
+indent_style = tab
+indent_size = 8
+
+[Makefile.nmake]
+end_of_line = crlf
diff --git a/cmark/.gitattributes b/cmark/.gitattributes
new file mode 100644
index 0000000000..92008d5b2e
--- /dev/null
+++ b/cmark/.gitattributes
@@ -0,0 +1,2 @@
+* text=auto eol=lf
+Makefile.nmake eol=crlf
diff --git a/cmark/.github/FUNDING.yml b/cmark/.github/FUNDING.yml
new file mode 100644
index 0000000000..726f8b0371
--- /dev/null
+++ b/cmark/.github/FUNDING.yml
@@ -0,0 +1 @@
+github: [jgm]
diff --git a/cmark/.github/dependabot.yml b/cmark/.github/dependabot.yml
new file mode 100644
index 0000000000..81bae9acd6
--- /dev/null
+++ b/cmark/.github/dependabot.yml
@@ -0,0 +1,7 @@
+version: 2
+
+updates:
+ - package-ecosystem: "github-actions"
+ directory: "/"
+ schedule:
+ interval: "daily"
diff --git a/cmark/.github/workflows/ci.yml b/cmark/.github/workflows/ci.yml
new file mode 100644
index 0000000000..09ee0d6c3c
--- /dev/null
+++ b/cmark/.github/workflows/ci.yml
@@ -0,0 +1,145 @@
+name: CI tests
+
+on:
+ push:
+ branches-ignore:
+ - 'dependabot/**'
+ pull_request:
+ workflow_dispatch:
+
+jobs:
+
+ linter:
+
+ runs-on: ubuntu-latest
+
+ steps:
+
+ - uses: actions/checkout@v6
+ - name: Install clang-tidy
+ run: |
+ sudo apt-get install -y clang-tidy
+ - name: lint with clang-tidy
+ run: |
+ make lint
+ env:
+ CC: clang
+ CXX: clang++
+
+ posix:
+
+ strategy:
+ fail-fast: false
+ matrix:
+ os: [linux, macos]
+ cc: [clang, gcc]
+ build_type: [shared, static]
+ sanitizers: ['', ASan]
+
+ include:
+ # Translate human readable labels
+ - os: 'linux'
+ image: 'ubuntu-latest'
+ - os: 'macos'
+ image: 'macos-latest'
+ - cc: 'clang'
+ cxx: 'clang++'
+ - cc: 'gcc'
+ cxx: 'g++'
+ - build_type: 'shared'
+ cmake_shared: 'YES'
+ - build_type: 'static'
+ cmake_shared: 'NO'
+ - sanitizers: 'ASan'
+ san_cflags: '-fsanitize=address,undefined -fno-sanitize-recover=all'
+
+ # When building shared libraries, they will be loaded
+ # dynamically from Python when testing. This means that
+ # we have to use a preloaded shared libasan.
+ - sanitizers: 'ASan'
+ os: 'linux'
+ cc: 'gcc'
+ build_type: 'shared'
+ test_env: 'LD_PRELOAD=$(gcc -print-file-name=libasan.so)'
+ - sanitizers: 'ASan'
+ os: 'linux'
+ cc: 'clang'
+ build_type: 'shared'
+ # clang defaults to -static-libsasn
+ asan_cflags: '-shared-libasan'
+ test_env: 'LD_PRELOAD=$(clang -print-file-name=libclang_rt.asan-x86_64.so)'
+
+ # We have to disable LeakSanitizer in shared library builds
+ # because we get false positives from Python.
+ - sanitizers: 'ASan'
+ build_type: 'shared'
+ asan_opts: 'detect_leaks=0'
+
+ # The static build can run with LeakSanitizer.
+ # gcc defaults to -shared-libasan and needs -static-libasan
+ - sanitizers: 'ASan'
+ cc: 'gcc'
+ build_type: 'static'
+ asan_cflags: '-static-libasan'
+
+ exclude:
+ # gcc is just an alias for clang on macOS
+ - os: 'macos'
+ cc: 'gcc'
+ # Shared libasan doesn't work with macOS system Python.
+ - os: 'macos'
+ sanitizers: 'ASan'
+ build_type: 'shared'
+
+ runs-on: ${{ matrix.image }}
+
+ env:
+ ASAN_OPTIONS: ${{ matrix.asan_opts }}
+ CC: ${{ matrix.cc }}
+ CXX: ${{ matrix.cxx }}
+ CFLAGS: '${{ matrix.san_cflags }} ${{ matrix.asan_cflags }}'
+ CXXFLAGS: '${{ matrix.san_cflags }} ${{ matrix.asan_cflags }}'
+
+ steps:
+ - uses: actions/checkout@v6
+ - name: Build and test
+ run: |
+ cmake \
+ -DBUILD_SHARED_LIBS=${{ matrix.cmake_shared }} \
+ -DCMAKE_BUILD_TYPE=Debug \
+ -S . -B build
+ cmake --build build
+ ${{ matrix.test_env }} ctest --test-dir build --output-on-failure
+
+ windows:
+
+ runs-on: windows-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ build_type: [shared, static]
+ include:
+ - build_type: 'shared'
+ cmake_shared: 'YES'
+ - build_type: 'static'
+ cmake_shared: 'NO'
+
+ steps:
+ - uses: actions/checkout@v6
+ - uses: ilammy/msvc-dev-cmd@v1
+ - name: Build and test
+ run: |
+ cmake ^
+ -DBUILD_SHARED_LIBS=${{ matrix.cmake_shared }} ^
+ -DCMAKE_BUILD_TYPE=Debug ^
+ -S . -B build
+ cmake --build build
+ ctest --test-dir build -C Debug --output-on-failure
+ shell: cmd
+ - name: Upload artifact
+ if: ${{ matrix.build_type == 'static' }}
+ uses: actions/upload-artifact@v7
+ with:
+ name: cmark windows ${{ matrix.build_type }}
+ path: build/src/Debug/cmark.exe
+ if-no-files-found: error
diff --git a/cmark/.github/workflows/fuzz.yml b/cmark/.github/workflows/fuzz.yml
new file mode 100644
index 0000000000..bbe45ee288
--- /dev/null
+++ b/cmark/.github/workflows/fuzz.yml
@@ -0,0 +1,23 @@
+name: CIFuzz
+on: [pull_request]
+jobs:
+ Fuzzing:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Build Fuzzers
+ uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
+ with:
+ oss-fuzz-project-name: 'cmark'
+ dry-run: false
+ - name: Run Fuzzers
+ uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
+ with:
+ oss-fuzz-project-name: 'cmark'
+ fuzz-seconds: 600
+ dry-run: false
+ - name: Upload Crash
+ uses: actions/upload-artifact@v7
+ if: failure()
+ with:
+ name: artifacts
+ path: ./out/artifacts
diff --git a/cmark/.gitignore b/cmark/.gitignore
new file mode 100644
index 0000000000..438340a7ff
--- /dev/null
+++ b/cmark/.gitignore
@@ -0,0 +1,39 @@
+# Object files
+*.o
+*.ko
+*.obj
+*.elf
+
+# Libraries
+*.lib
+*.a
+
+# Shared objects (inc. Windows DLLs)
+*.dll
+*.so
+*.so.*
+*.dylib
+
+# Executables
+*.exe
+*.out
+*.app
+*.i*86
+*.x86_64
+*.hex
+*.pyc
+
+*~
+*.bak
+*.sw?
+*.diff
+*#
+*.zip
+bstrlib.txt
+build
+cmark.dSYM/*
+cmark
+
+# Visual Studio CMake support
+/.vs/
+/out/
diff --git a/cmark/CMakeLists.txt b/cmark/CMakeLists.txt
new file mode 100644
index 0000000000..813f632f71
--- /dev/null
+++ b/cmark/CMakeLists.txt
@@ -0,0 +1,128 @@
+cmake_minimum_required(VERSION 3.14)
+
+project(cmark
+ LANGUAGES C CXX
+ VERSION 0.31.2)
+
+set(CMAKE_C_STANDARD 99)
+set(CMAKE_C_STANDARD_REQUIRED YES)
+set(CMAKE_C_EXTENSIONS NO)
+
+if(CMAKE_BUILD_TYPE STREQUAL Asan)
+ list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/modules)
+ include(FindAsan)
+endif()
+
+# Include module for functions
+# - 'write_basic_package_version_file'
+# - 'configure_package_config_file'
+include(CMakePackageConfigHelpers)
+include(CTest)
+include(GenerateExportHeader)
+include(GNUInstallDirs)
+
+if(NOT MSVC OR CMAKE_HOST_SYSTEM_NAME STREQUAL Windows)
+ set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS ON)
+ include(InstallRequiredSystemLibraries)
+endif()
+
+if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}")
+ message(FATAL_ERROR "Do not build in-source.\nPlease remove CMakeCache.txt and the CMakeFiles/ directory.\nThen: mkdir build ; cd build ; cmake .. ; make")
+endif()
+
+# Backwards Compatibility
+# TODO: remove this once there has been a period to enable people to migrate
+set(_CMARK_BUILD_SHARED_LIBS_DEFAULT NO)
+if(DEFINED CMARK_SHARED)
+ message(AUTHOR_WARNING [=[
+'CMARK_SHARED' has been replaced with the standard 'BUILD_SHARED_LIBS' to control the library type.
+]=])
+ set(_CMARK_BUILD_SHARED_LIBS_DEFAULT ${CMARK_SHARED})
+endif()
+if(DEFINED CMARK_STATIC)
+ message(AUTHOR_WARNING [=[
+'CMARK_STATIC' has been replaced with the standard 'BUILD_SHARED_LIBS' to control the library type.
+]=])
+ if(NOT CMARK_STATIC)
+ set(_CMARK_BUILD_SHARED_LIBS_DEFAULT YES)
+ else()
+ set(_CMARK_BUILD_SHARED_LIBS_DEFAULT NO)
+ endif()
+endif()
+
+option(CMARK_LIB_FUZZER "Build libFuzzer fuzzing harness" OFF)
+option(BUILD_SHARED_LIBS "Build the CMark library as shared"
+ ${_CMARK_BUILD_SHARED_LIBS_DEFAULT})
+
+# -fvisibility=hidden
+set(CMAKE_C_VISIBILITY_PRESET hidden)
+set(CMAKE_VISIBILITY_INLINES_HIDDEN 1)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+if (DEFINED CMAKE_INSTALL_RPATH)
+ set(Base_rpath "${CMAKE_INSTALL_RPATH}")
+else()
+ if(BUILD_SHARED_LIBS)
+ set(p "${CMAKE_INSTALL_FULL_LIBDIR}")
+ list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${p}" i)
+ if("${i}" STREQUAL "-1")
+ set(Base_rpath "${p}")
+ endif()
+ endif()
+endif()
+
+# Append non-standard external dependency directories, if any.
+set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
+
+# Check integrity of node structure when compiled as debug
+add_compile_options($<$<CONFIG:Debug>:-DCMARK_DEBUG_NODES>)
+
+# In order to maintain compatibility with older platforms which may not have a
+# recent version of CMake (i.e. are running CMake <3.3), we cannot simply use
+# the `add_compile_options` with a generator expression. This uses the
+# `target_compile_options` with `PRIVATE` to add the flags only to the targets
+# so that CMark may be used in projects with non-C languages.
+function(cmark_add_compile_options target)
+ if(MSVC)
+ target_compile_definitions(${target} PRIVATE _CRT_SECURE_NO_WARNINGS)
+ else()
+ target_compile_options(${target} PRIVATE
+ -Wall -Wextra -pedantic
+ $<$<COMPILE_LANGUAGE:C>:-Wstrict-prototypes>)
+ endif()
+ if(CMAKE_BUILD_TYPE STREQUAL Profile)
+ target_compile_options(${target} PRIVATE -pg)
+ endif()
+ if(CMAKE_BUILD_TYPE STREQUAL Ubsan)
+ target_compile_options(${target} PRIVATE -fsanitize=undefined)
+ endif()
+ if(CMARK_LIB_FUZZER)
+ if(target MATCHES fuzz)
+ target_compile_options(${target} PRIVATE -fsanitize=fuzzer)
+ target_link_options(${target} PRIVATE -fsanitize=fuzzer)
+ else()
+ target_compile_options(${target} PRIVATE -fsanitize=fuzzer-no-link)
+ target_link_options(${target} PRIVATE -fsanitize=fuzzer-no-link)
+ endif()
+ endif()
+endfunction()
+
+add_subdirectory(src)
+# TODO(compnerd) should this be enabled for MinGW, which sets CMAKE_SYSTEM_NAME
+# to Windows, but defines `MINGW`.
+if(NOT CMAKE_SYSTEM_NAME STREQUAL Windows)
+ add_subdirectory(man)
+endif()
+if(BUILD_TESTING)
+ add_subdirectory(api_test)
+ add_subdirectory(test testdir)
+endif()
+if(CMARK_LIB_FUZZER)
+ add_subdirectory(fuzz)
+endif()
+
+if(NOT CMAKE_BUILD_TYPE)
+ set(CMAKE_BUILD_TYPE "Release" CACHE STRING
+ "Choose the type of build, options are: Debug Profile Release Asan Ubsan." FORCE)
+endif(NOT CMAKE_BUILD_TYPE)
diff --git a/cmark/COPYING b/cmark/COPYING
new file mode 100644
index 0000000000..db88a81b3e
--- /dev/null
+++ b/cmark/COPYING
@@ -0,0 +1,170 @@
+Copyright (c) 2014, John MacFarlane
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+
+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.
+
+-----
+
+houdini.h, houdini_href_e.c, houdini_html_e.c, houdini_html_u.c
+
+derive from https://github.com/vmg/houdini (with some modifications)
+
+Copyright (C) 2012 Vicent Martí
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+-----
+
+buffer.h, buffer.c, chunk.h
+
+are derived from code (C) 2012 Github, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+-----
+
+utf8.c and utf8.c
+
+are derived from utf8proc
+(<http://www.public-software-group.org/utf8proc>),
+(C) 2009 Public Software Group e. V., Berlin, Germany.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+-----
+
+The normalization code in normalize.py was derived from the
+markdowntest project, Copyright 2013 Karl Dubost:
+
+The MIT License (MIT)
+
+Copyright (c) 2013 Karl Dubost
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+-----
+
+The CommonMark spec (test/spec.txt) is
+
+Copyright (C) 2014-15 John MacFarlane
+
+Released under the Creative Commons CC-BY-SA 4.0 license:
+<http://creativecommons.org/licenses/by-sa/4.0/>.
+
+-----
+
+The test software in test/ is
+
+Copyright (c) 2014, John MacFarlane
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+
+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/cmark/Makefile b/cmark/Makefile
new file mode 100644
index 0000000000..609bbfa560
--- /dev/null
+++ b/cmark/Makefile
@@ -0,0 +1,214 @@
+SRCDIR=src
+DATADIR=data
+BUILDDIR?=build
+GENERATOR?=Unix Makefiles
+MINGW_BUILDDIR?=build-mingw
+MINGW_INSTALLDIR?=windows
+SPEC=test/spec.txt
+SITE=_site
+SPECVERSION=$(shell perl -ne 'print $$1 if /^version: *([0-9.]+)/' $(SPEC))
+FUZZCHARS?=2000000 # for fuzztest
+BENCHDIR=bench
+BENCHSAMPLES=$(wildcard $(BENCHDIR)/samples/*.md)
+BENCHFILE=$(BENCHDIR)/benchinput.md
+ALLTESTS=alltests.md
+NUMRUNS?=10
+CMARK=$(BUILDDIR)/src/cmark
+CMARK_FUZZ=$(BUILDDIR)/src/cmark-fuzz
+PROG?=$(CMARK)
+VERSION?=$(SPECVERSION)
+RELEASE?=cmark-$(VERSION)
+INSTALL_PREFIX?=/usr/local
+CLANG_CHECK?=clang-check
+CLANG_FORMAT=clang-format -style llvm -sort-includes=0 -i
+AFL_PATH?=/usr/local/bin
+
+.PHONY: all cmake_build leakcheck clean fuzztest test debug ubsan asan mingw archive newbench bench format update-spec afl libFuzzer lint
+
+all: cmake_build man/man3/cmark.3
+
+$(CMARK): cmake_build
+
+cmake_build: $(BUILDDIR)
+ cmake --build $(BUILDDIR)
+ @echo "Binaries can be found in $(BUILDDIR)/src"
+
+$(BUILDDIR):
+ @cmake --version > /dev/null || (echo "You need cmake to build this program: http://www.cmake.org/download/" && exit 1)
+ cmake \
+ -S . -B $(BUILDDIR) -G "$(GENERATOR)" \
+ -DCMAKE_BUILD_TYPE=$(BUILD_TYPE) \
+ -DCMAKE_INSTALL_PREFIX=$(INSTALL_PREFIX) \
+ -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
+ -DBUILD_SHARED_LIBS=YES
+
+install: $(BUILDDIR)
+ cmake --install $(BUILDDIR)
+
+uninstall: $(BUILDDIR)/install_manifest.txt
+ xargs rm < $<
+
+debug:
+ cmake \
+ -S . -B $(BUILDDIR) -G "$(GENERATOR)" \
+ -DCMAKE_BUILD_TYPE=Debug \
+ -DBUILD_SHARED_LIBS=YES
+ cmake --build $(BUILDDIR)
+
+ubsan:
+ cmake \
+ -S . -B $(BUILDDIR) -G "$(GENERATOR)" \
+ -DCMAKE_BUILD_TYPE=Ubsan
+ cmake --build $(BUILDDIR)
+
+asan:
+ cmake \
+ -S . -B $(BUILDDIR) -G "$(GENERATOR)" \
+ -DCMAKE_BUILD_TYPE=Asan
+ cmake --build $(BUILDDIR)
+
+prof:
+ cmake \
+ -S . -B $(BUILDDIR) -G "$(GENERATOR)" \
+ -DCMAKE_BUILD_TYPE=Profile
+ cmake --build $(BUILDDIR)
+
+afl:
+ @[ -n "$(AFL_PATH)" ] || { echo '$$AFL_PATH not set'; false; }
+ cmake \
+ -S . -B $(BUILDDIR) -G "$(GENERATOR)" \
+ -DBUILD_TESTING=NO \
+ -DCMAKE_C_COMPILER=$(AFL_PATH)/afl-clang
+ cmake --build $(BUILDDIR)
+ $(AFL_PATH)/afl-fuzz \
+ -i fuzz/afl_test_cases \
+ -o fuzz/afl_results \
+ -x fuzz/dictionary \
+ -t 100 \
+ $(CMARK) $(CMARK_OPTS)
+
+libFuzzer:
+ cmake \
+ -S . -B $(BUILDDIR) -G "$(GENERATOR)" \
+ -DCMAKE_C_COMPILER=clang \
+ -DCMAKE_CXX_COMPILER=clang++ \
+ -DCMAKE_BUILD_TYPE=Asan \
+ -DCMARK_LIB_FUZZER=ON
+ cmake --build $(BUILDDIR)
+ mkdir -p fuzz/corpus
+ $(BUILDDIR)/fuzz/cmark-fuzz \
+ -dict=fuzz/dictionary \
+ -max_len=1000 \
+ -timeout=1 \
+ fuzz/corpus
+
+lint: $(BUILDDIR)
+ errs=0 ; \
+ for f in `ls src/*.[ch] | grep -v "scanners.c"` ; \
+ do echo $$f ; clang-tidy -header-filter='^build/.*' -p=build -warnings-as-errors='*' $$f || errs=1 ; done ; \
+ exit $$errs
+
+mingw:
+ cmake \
+ -S . -B $(MINGW_BUILDDIR) -G "$(GENERATOR)" \
+ -DCMAKE_TOOLCHAIN_FILE=toolchain-mingw32.cmake \
+ -DCMAKE_INSTALL_PREFIX=$(MINGW_INSTALLDIR)
+ cmake --build $(MINGW_BUILDDIR)
+ cmake --install $(MINGW_BUILDDIR)
+
+man/man3/cmark.3: src/cmark.h | $(CMARK)
+ python3 man/make_man_page.py $< > $@ \
+
+archive:
+ git archive --prefix=$(RELEASE)/ -o $(RELEASE).tar.gz HEAD
+ git archive --prefix=$(RELEASE)/ -o $(RELEASE).zip HEAD
+
+clean:
+ rm -rf $(BUILDDIR) $(MINGW_BUILDDIR) $(MINGW_INSTALLDIR)
+
+# We include case_fold.inc in the repository, so this shouldn't
+# normally need to be generated.
+$(SRCDIR)/case_fold.inc: $(DATADIR)/CaseFolding.txt
+ python3 tools/make_case_fold_inc.py < $< > $@
+
+# We include scanners.c in the repository, so this shouldn't
+# normally need to be generated.
+$(SRCDIR)/scanners.c: $(SRCDIR)/scanners.re
+ @case "$$(re2c -v)" in \
+ *\ 0.13.*|*\ 0.14|*\ 0.14.1) \
+ echo "re2c >= 0.14.2 is required"; \
+ false; \
+ ;; \
+ esac
+ re2c -W -Werror --case-insensitive -b -i --no-generation-date \
+ -o $@ $<
+ $(CLANG_FORMAT) $@
+
+# We include entities.inc in the repository, so normally this
+# doesn't need to be regenerated:
+$(SRCDIR)/entities.inc: tools/make_entities_inc.py
+ python3 $< > $@
+
+update-spec:
+ curl 'https://raw.githubusercontent.com/jgm/CommonMark/master/spec.txt'\
+ > $(SPEC)
+
+test: cmake_build
+ ctest --test-dir $(BUILDDIR) --output-on-failure || (cat $(BUILDDIR)/Testing/Temporary/LastTest.log && exit 1)
+
+$(ALLTESTS):
+ python3 test/spec_tests.py --spec $(SPEC) --dump-tests | python3 -c 'import json; import sys; tests = json.loads(sys.stdin.read()); print("\n".join([test["markdown"] for test in tests]))' > $@
+
+leakcheck: $(ALLTESTS)
+ for format in html man xml latex commonmark; do \
+ for opts in "" "--smart"; do \
+ echo "cmark -t $$format $$opts" ; \
+ valgrind -q --leak-check=full --dsymutil=yes --error-exitcode=1 $(PROG) -t $$format $$opts $(ALLTESTS) >/dev/null || exit 1;\
+ done; \
+ done;
+
+fuzztest:
+ { for i in `seq 1 10`; do \
+ cat /dev/urandom | head -c $(FUZZCHARS) | iconv -f latin1 -t utf-8 | tee fuzz-$$i.txt | \
+ /usr/bin/env time -p $(PROG) >/dev/null && rm fuzz-$$i.txt ; \
+ done } 2>&1 | grep 'user\|abnormally'
+
+progit:
+ git clone https://github.com/progit/progit.git
+
+$(BENCHFILE): progit
+ echo "" > $@
+ for lang in ar az be ca cs de en eo es es-ni fa fi fr hi hu id it ja ko mk nl no-nb pl pt-br ro ru sr th tr uk vi zh zh-tw; do \
+ cat progit/$$lang/*/*.markdown >> $@; \
+ done
+
+# for more accurate results, run with
+# sudo renice -10 $$; make bench
+bench: $(BENCHFILE)
+ { for x in `seq 1 $(NUMRUNS)` ; do \
+ /usr/bin/env time -p $(PROG) </dev/null >/dev/null ; \
+ /usr/bin/env time -p $(PROG) $< >/dev/null ; \
+ done \
+ } 2>&1 | grep 'real' | awk '{print $$2}' | python3 'bench/stats.py'
+
+newbench:
+ for f in $(BENCHSAMPLES) ; do \
+ printf "%26s " `basename $$f` ; \
+ { for x in `seq 1 $(NUMRUNS)` ; do \
+ /usr/bin/env time -p $(PROG) </dev/null >/dev/null ; \
+ for x in `seq 1 200` ; do cat $$f ; done | \
+ /usr/bin/env time -p $(PROG) > /dev/null; \
+ done \
+ } 2>&1 | grep 'real' | awk '{print $$2}' | \
+ python3 'bench/stats.py'; done
+
+format:
+ $(CLANG_FORMAT) src/*.c src/*.h api_test/*.c api_test/*.h
+
+operf: $(CMARK)
+ operf $< < $(BENCHFILE) > /dev/null
+
+distclean: clean
+ -rm -rf *.dSYM
+ -rm -f README.html
+ -rm -rf $(BENCHFILE) $(ALLTESTS) progit
diff --git a/cmark/Makefile.nmake b/cmark/Makefile.nmake
new file mode 100644
index 0000000000..47d166563f
--- /dev/null
+++ b/cmark/Makefile.nmake
@@ -0,0 +1,28 @@
+SRCDIR=src
+DATADIR=data
+BUILDDIR=build
+INSTALLDIR=windows
+PROG=$(BUILDDIR)\src\cmark.exe
+GENERATOR=NMake Makefiles
+
+all: $(BUILDDIR)/CMakeFiles
+ cmake --build $(BUILDDIR)
+
+$(BUILDDIR)/CMakeFiles:
+ cmake \
+ -S . -B $(BUILDDIR) -G "$(GENERATOR)" \
+ -D CMAKE_BUILD_TYPE=$(BUILD_TYPE) \
+ -D CMAKE_INSTALL_PREFIX=$(INSTALLDIR)
+
+install: all
+ cmake --install $(BUILDDIR)
+
+clean:
+ -rmdir /s /q $(BUILDDIR) $(MINGW_INSTALLDIR) 2> nul
+
+test: all
+ ctest --test-dir $(BUILDDIR) --output-on-failure
+
+distclean: clean
+ del /q src\scanners.c 2> nul
+ del /q spec.md spec.html 2> nul
diff --git a/cmark/README.md b/cmark/README.md
new file mode 100644
index 0000000000..99d02bd619
--- /dev/null
+++ b/cmark/README.md
@@ -0,0 +1,190 @@
+cmark
+=====
+
+[![CI
+tests](https://github.com/commonmark/cmark/workflows/CI%20tests/badge.svg)](https://github.com/commonmark/cmark/actions)
+
+`cmark` is the C reference implementation of [CommonMark], a
+rationalized version of Markdown syntax with a [spec][the spec].
+(For the JavaScript reference implementation, see
+[commonmark.js].)
+
+It provides a shared library (`libcmark`) with functions for parsing
+CommonMark documents to an abstract syntax tree (AST), manipulating
+the AST, and rendering the document to HTML, groff man, LaTeX,
+CommonMark, or an XML representation of the AST. It also provides a
+command-line program (`cmark`) for parsing and rendering CommonMark
+documents.
+
+Advantages of this library:
+
+- **Portable.** The library and program are written in standard
+ C99 and have no external dependencies. They have been tested with
+ MSVC, gcc, tcc, and clang.
+
+- **Fast.** cmark can render a Markdown version of *War and Peace* in
+ the blink of an eye (127 milliseconds on a ten year old laptop,
+ vs. 100-400 milliseconds for an eye blink). In our [benchmarks],
+ cmark is 10,000 times faster than the original `Markdown.pl`, and
+ on par with the very fastest available Markdown processors.
+
+- **Accurate.** The library passes all CommonMark conformance tests.
+
+- **Standardized.** The library can be expected to parse CommonMark
+ the same way as any other conforming parser. So, for example,
+ you can use `commonmark.js` on the client to preview content that
+ will be rendered on the server using `cmark`.
+
+- **Robust.** The library has been extensively fuzz-tested using
+ [american fuzzy lop]. The test suite includes pathological cases
+ that bring many other Markdown parsers to a crawl (for example,
+ thousands-deep nested bracketed text or block quotes).
+
+- **Flexible.** CommonMark input is parsed to an AST which can be
+ manipulated programmatically prior to rendering.
+
+- **Multiple renderers.** Output in HTML, groff man, LaTeX, CommonMark,
+ and a custom XML format is supported. And it is easy to write new
+ renderers to support other formats.
+
+- **Free.** BSD2-licensed.
+
+It is easy to use `libcmark` in python, lua, ruby, and other dynamic
+languages: see the `wrappers/` subdirectory for some simple examples.
+
+There are also libraries that wrap `libcmark` for
+[Go](https://github.com/rhinoman/go-commonmark),
+[Haskell](https://hackage.haskell.org/package/cmark),
+[Ruby](https://github.com/gjtorikian/commonmarker),
+[Lua](https://github.com/jgm/cmark-lua),
+[Perl](https://metacpan.org/release/CommonMark),
+[Python](https://pypi.org/project/umarkdown/),
+[R](https://cran.r-project.org/package=commonmark),
+[Scala](https://github.com/sparsetech/cmark-scala) and
+[PHP](https://www.php.net/manual/en/book.cmark.php).
+
+Installing
+----------
+
+Building the C program (`cmark`) and shared library (`libcmark`)
+requires [cmake]. If you modify `scanners.re`, then you will also
+need [re2c] \(>= 0.14.2\), which is used to generate `scanners.c` from
+`scanners.re`. We have included a pre-generated `scanners.c` in
+the repository to reduce build dependencies.
+
+If you have GNU make, you can simply `make`, `make test`, and `make
+install`. This calls [cmake] to create a `Makefile` in the `build`
+directory, then uses that `Makefile` to create the executable and
+library. The binaries can be found in `build/src`. The default
+installation prefix is `/usr/local`. To change the installation
+prefix, pass the `INSTALL_PREFIX` variable if you run `make` for the
+first time: `make INSTALL_PREFIX=path`.
+
+For a more portable method, you can use [cmake] manually. [cmake] knows
+how to create build environments for many build systems. For example,
+on FreeBSD:
+
+ cmake -S . -B build # optionally: -DCMAKE_INSTALL_PREFIX=path
+ cmake --build build # executable will be created as build/src/cmark
+ ctest --test-dir build
+ cmake --install build
+
+Or, to create Xcode project files on OSX:
+
+ cmake -S . -B build -G Xcode
+ open build/cmark.xcodeproj
+
+The GNU Makefile also provides a few other targets for developers.
+To run a benchmark:
+
+ make bench
+
+For more detailed benchmarks:
+
+ make newbench
+
+To run a test for memory leaks using `valgrind`:
+
+ make leakcheck
+
+To reformat source code using `clang-format`:
+
+ make format
+
+To run a "fuzz test" against ten long randomly generated inputs:
+
+ make fuzztest
+
+To do a more systematic fuzz test with [american fuzzy lop]:
+
+ AFL_PATH=/path/to/afl_directory make afl
+
+Fuzzing with [libFuzzer] is also supported. The fuzzer can be run with:
+
+ make libFuzzer
+
+To make a release tarball and zip archive:
+
+ make archive
+
+Installing (Windows)
+--------------------
+
+To compile with MSVC and NMAKE:
+
+ nmake /f Makefile.nmake
+
+You can cross-compile a Windows binary and dll on linux if you have the
+`mingw32` compiler:
+
+ make mingw
+
+The binaries will be in `build-mingw/windows/bin`.
+
+Usage
+-----
+
+Instructions for the use of the command line program and library can
+be found in the man pages in the `man` subdirectory.
+
+Security
+--------
+
+By default, the library will scrub raw HTML and potentially
+dangerous links (`javascript:`, `vbscript:`, `data:`, `file:`).
+
+To allow these, use the option `CMARK_OPT_UNSAFE` (or
+`--unsafe`) with the command line program. If doing so, we
+recommend you use a HTML sanitizer specific to your needs to
+protect against [XSS
+attacks](http://en.wikipedia.org/wiki/Cross-site_scripting).
+
+Contributing
+------------
+
+There is a [forum for discussing
+CommonMark](http://talk.commonmark.org); you should use it instead of
+github issues for questions and possibly open-ended discussions.
+Use the [github issue tracker](http://github.com/commonmark/CommonMark/issues)
+only for simple, clear, actionable issues.
+
+Authors
+-------
+
+John MacFarlane wrote the original library and program.
+The block parsing algorithm was worked out together with David
+Greenspan. Vicent Marti optimized the C implementation for
+performance, increasing its speed tenfold. Kārlis Gaņģis helped
+work out a better parsing algorithm for links and emphasis,
+eliminating several worst-case performance issues.
+Nick Wellnhofer contributed many improvements, including
+most of the C library's API and its test harness.
+
+[benchmarks]: benchmarks.md
+[the spec]: http://spec.commonmark.org
+[CommonMark]: http://commonmark.org
+[cmake]: http://www.cmake.org/download/
+[re2c]: http://re2c.org
+[commonmark.js]: https://github.com/commonmark/commonmark.js
+[american fuzzy lop]: http://lcamtuf.coredump.cx/afl/
+[libFuzzer]: http://llvm.org/docs/LibFuzzer.html
diff --git a/cmark/api_test/CMakeLists.txt b/cmark/api_test/CMakeLists.txt
new file mode 100644
index 0000000000..533c2c6d88
--- /dev/null
+++ b/cmark/api_test/CMakeLists.txt
@@ -0,0 +1,16 @@
+add_executable(api_test
+ cplusplus.cpp
+ harness.c
+ harness.h
+ main.c
+)
+cmark_add_compile_options(api_test)
+target_link_libraries(api_test PRIVATE
+ cmark)
+
+add_test(NAME api_test COMMAND api_test)
+if(WIN32)
+ set_tests_properties(api_test PROPERTIES
+ ENVIRONMENT "PATH=$<TARGET_FILE_DIR:cmark>$<SEMICOLON>$ENV{PATH}")
+endif()
+
diff --git a/cmark/api_test/cplusplus.cpp b/cmark/api_test/cplusplus.cpp
new file mode 100644
index 0000000000..5e8f722a3b
--- /dev/null
+++ b/cmark/api_test/cplusplus.cpp
@@ -0,0 +1,15 @@
+#include <cstdlib>
+
+#include "cmark.h"
+#include "cplusplus.h"
+#include "harness.h"
+
+void
+test_cplusplus(test_batch_runner *runner)
+{
+ static const char md[] = "paragraph\n";
+ char *html = cmark_markdown_to_html(md, sizeof(md) - 1, CMARK_OPT_DEFAULT);
+ STR_EQ(runner, html, "<p>paragraph</p>\n", "libcmark works with C++");
+ free(html);
+}
+
diff --git a/cmark/api_test/cplusplus.h b/cmark/api_test/cplusplus.h
new file mode 100644
index 0000000000..1f3dd15213
--- /dev/null
+++ b/cmark/api_test/cplusplus.h
@@ -0,0 +1,16 @@
+#ifndef CMARK_API_TEST_CPLUSPLUS_H
+#define CMARK_API_TEST_CPLUSPLUS_H
+
+#include "harness.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void test_cplusplus(test_batch_runner *runner);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/cmark/api_test/harness.c b/cmark/api_test/harness.c
new file mode 100644
index 0000000000..d27e7caff1
--- /dev/null
+++ b/cmark/api_test/harness.c
@@ -0,0 +1,83 @@
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "harness.h"
+
+test_batch_runner *test_batch_runner_new(void) {
+ return (test_batch_runner *)calloc(1, sizeof(test_batch_runner));
+}
+
+static void test_result(test_batch_runner *runner, int cond, const char *msg,
+ va_list ap) {
+ ++runner->test_num;
+
+ if (cond) {
+ ++runner->num_passed;
+ } else {
+ fprintf(stderr, "FAILED test %d: ", runner->test_num);
+ vfprintf(stderr, msg, ap);
+ fprintf(stderr, "\n");
+ ++runner->num_failed;
+ }
+}
+
+void SKIP(test_batch_runner *runner, int num_tests) {
+ runner->test_num += num_tests;
+ runner->num_skipped += num_tests;
+}
+
+void OK(test_batch_runner *runner, int cond, const char *msg, ...) {
+ va_list ap;
+ va_start(ap, msg);
+ test_result(runner, cond, msg, ap);
+ va_end(ap);
+}
+
+void INT_EQ(test_batch_runner *runner, int got, int expected, const char *msg,
+ ...) {
+ int cond = got == expected;
+
+ va_list ap;
+ va_start(ap, msg);
+ test_result(runner, cond, msg, ap);
+ va_end(ap);
+
+ if (!cond) {
+ fprintf(stderr, " Got: %d\n", got);
+ fprintf(stderr, " Expected: %d\n", expected);
+ }
+}
+
+void STR_EQ(test_batch_runner *runner, const char *got, const char *expected,
+ const char *msg, ...) {
+ int cond = strcmp(got, expected) == 0;
+
+ va_list ap;
+ va_start(ap, msg);
+ test_result(runner, cond, msg, ap);
+ va_end(ap);
+
+ if (!cond) {
+ fprintf(stderr, " Got: \"%s\"\n", got);
+ fprintf(stderr, " Expected: \"%s\"\n", expected);
+ }
+}
+
+int test_ok(test_batch_runner *runner) { return runner->num_failed == 0; }
+
+void test_print_summary(test_batch_runner *runner) {
+ int num_passed = runner->num_passed;
+ int num_skipped = runner->num_skipped;
+ int num_failed = runner->num_failed;
+
+ fprintf(stderr, "%d tests passed, %d failed, %d skipped\n", num_passed,
+ num_failed, num_skipped);
+
+ if (test_ok(runner)) {
+ fprintf(stderr, "PASS\n");
+ } else {
+ fprintf(stderr, "FAIL\n");
+ }
+}
diff --git a/cmark/api_test/harness.h b/cmark/api_test/harness.h
new file mode 100644
index 0000000000..f352f07f53
--- /dev/null
+++ b/cmark/api_test/harness.h
@@ -0,0 +1,35 @@
+#ifndef CMARK_API_TEST_HARNESS_H
+#define CMARK_API_TEST_HARNESS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+ int test_num;
+ int num_passed;
+ int num_failed;
+ int num_skipped;
+} test_batch_runner;
+
+test_batch_runner *test_batch_runner_new(void);
+
+void SKIP(test_batch_runner *runner, int num_tests);
+
+void OK(test_batch_runner *runner, int cond, const char *msg, ...);
+
+void INT_EQ(test_batch_runner *runner, int got, int expected, const char *msg,
+ ...);
+
+void STR_EQ(test_batch_runner *runner, const char *got, const char *expected,
+ const char *msg, ...);
+
+int test_ok(test_batch_runner *runner);
+
+void test_print_summary(test_batch_runner *runner);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/cmark/api_test/main.c b/cmark/api_test/main.c
new file mode 100644
index 0000000000..6ec25c453b
--- /dev/null
+++ b/cmark/api_test/main.c
@@ -0,0 +1,1194 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define CMARK_NO_SHORT_NAMES
+#include "cmark.h"
+#include "node.h"
+
+#include "harness.h"
+#include "cplusplus.h"
+
+#define UTF8_REPL "\xEF\xBF\xBD"
+
+static const cmark_node_type node_types[] = {
+ CMARK_NODE_DOCUMENT, CMARK_NODE_BLOCK_QUOTE, CMARK_NODE_LIST,
+ CMARK_NODE_ITEM, CMARK_NODE_CODE_BLOCK, CMARK_NODE_HTML_BLOCK,
+ CMARK_NODE_PARAGRAPH, CMARK_NODE_HEADING, CMARK_NODE_THEMATIC_BREAK,
+ CMARK_NODE_TEXT, CMARK_NODE_SOFTBREAK, CMARK_NODE_LINEBREAK,
+ CMARK_NODE_CODE, CMARK_NODE_HTML_INLINE, CMARK_NODE_EMPH,
+ CMARK_NODE_STRONG, CMARK_NODE_LINK, CMARK_NODE_IMAGE};
+static const int num_node_types = sizeof(node_types) / sizeof(*node_types);
+
+static void test_md_to_html(test_batch_runner *runner, const char *markdown,
+ const char *expected_html, const char *msg);
+
+static void test_content(test_batch_runner *runner, cmark_node_type type,
+ int allowed_content);
+
+static void test_char(test_batch_runner *runner, int valid, const char *utf8,
+ const char *msg);
+
+static void test_incomplete_char(test_batch_runner *runner, const char *utf8,
+ const char *msg);
+
+static void test_continuation_byte(test_batch_runner *runner, const char *utf8);
+
+static void version(test_batch_runner *runner) {
+ INT_EQ(runner, cmark_version(), CMARK_VERSION, "cmark_version");
+ STR_EQ(runner, cmark_version_string(), CMARK_VERSION_STRING,
+ "cmark_version_string");
+}
+
+static void constructor(test_batch_runner *runner) {
+ for (int i = 0; i < num_node_types; ++i) {
+ cmark_node_type type = node_types[i];
+ cmark_node *node = cmark_node_new(type);
+ OK(runner, node != NULL, "new type %d", type);
+ INT_EQ(runner, cmark_node_get_type(node), type, "get_type %d", type);
+
+ switch (node->type) {
+ case CMARK_NODE_HEADING:
+ INT_EQ(runner, cmark_node_get_heading_level(node), 1,
+ "default heading level is 1");
+ node->as.heading.level = 1;
+ break;
+
+ case CMARK_NODE_LIST:
+ INT_EQ(runner, cmark_node_get_list_type(node), CMARK_BULLET_LIST,
+ "default is list type is bullet");
+ INT_EQ(runner, cmark_node_get_list_delim(node), CMARK_NO_DELIM,
+ "default is list delim is NO_DELIM");
+ INT_EQ(runner, cmark_node_get_list_start(node), 0,
+ "default is list start is 0");
+ INT_EQ(runner, cmark_node_get_list_tight(node), 0,
+ "default is list is loose");
+ break;
+
+ default:
+ break;
+ }
+
+ cmark_node_free(node);
+ }
+}
+
+static void classifiers(test_batch_runner *runner) {
+ cmark_node *node = cmark_node_new(CMARK_NODE_BLOCK_QUOTE);
+ OK(runner, cmark_node_is_block(node), "is block CMARK_NODE_BLOCK_QUOTE");
+ OK(runner, !cmark_node_is_inline(node), "is not inline CMARK_NODE_BLOCK_QUOTE");
+ OK(runner, !cmark_node_is_leaf(node), "is not leaf CMARK_NODE_BLOCK_QUOTE");
+ cmark_node_free(node);
+ node = cmark_node_new(CMARK_NODE_EMPH);
+ OK(runner, !cmark_node_is_block(node), "is not block CMARK_NODE_EMPH");
+ OK(runner, cmark_node_is_inline(node), "is inline CMARK_NODE_EMPH");
+ OK(runner, !cmark_node_is_leaf(node), "is not leaf CMARK_NODE_EMPH");
+ cmark_node_free(node);
+ node = cmark_node_new(CMARK_NODE_THEMATIC_BREAK);
+ OK(runner, cmark_node_is_block(node), "is block CMARK_NODE_THEMATIC_BREAK");
+ OK(runner, !cmark_node_is_inline(node), "is not inline CMARK_NODE_THEMATIC_BREAK");
+ OK(runner, cmark_node_is_leaf(node), "is leaf CMARK_NODE_THEMATIC_BREAK");
+ cmark_node_free(node);
+}
+
+static void accessors(test_batch_runner *runner) {
+ static const char markdown[] = "## Header\n"
+ "\n"
+ "* Item 1\n"
+ "* Item 2\n"
+ "\n"
+ "2. Item 1\n"
+ "\n"
+ "3. Item 2\n"
+ "\n"
+ "``` lang\n"
+ "fenced\n"
+ "```\n"
+ " code\n"
+ "\n"
+ "<div>html</div>\n"
+ "\n"
+ "[link](url 'title')\n";
+
+ cmark_node *doc =
+ cmark_parse_document(markdown, sizeof(markdown) - 1, CMARK_OPT_DEFAULT);
+
+ // Getters
+
+ cmark_node *heading = cmark_node_first_child(doc);
+ INT_EQ(runner, cmark_node_get_heading_level(heading), 2, "get_heading_level");
+
+ cmark_node *bullet_list = cmark_node_next(heading);
+ INT_EQ(runner, cmark_node_get_list_type(bullet_list), CMARK_BULLET_LIST,
+ "get_list_type bullet");
+ INT_EQ(runner, cmark_node_get_list_tight(bullet_list), 1,
+ "get_list_tight tight");
+
+ cmark_node *ordered_list = cmark_node_next(bullet_list);
+ INT_EQ(runner, cmark_node_get_list_type(ordered_list), CMARK_ORDERED_LIST,
+ "get_list_type ordered");
+ INT_EQ(runner, cmark_node_get_list_delim(ordered_list), CMARK_PERIOD_DELIM,
+ "get_list_delim ordered");
+ INT_EQ(runner, cmark_node_get_list_start(ordered_list), 2, "get_list_start");
+ INT_EQ(runner, cmark_node_get_list_tight(ordered_list), 0,
+ "get_list_tight loose");
+
+ cmark_node *fenced = cmark_node_next(ordered_list);
+ STR_EQ(runner, cmark_node_get_literal(fenced), "fenced\n",
+ "get_literal fenced code");
+ STR_EQ(runner, cmark_node_get_fence_info(fenced), "lang", "get_fence_info");
+
+ cmark_node *code = cmark_node_next(fenced);
+ STR_EQ(runner, cmark_node_get_literal(code), "code\n",
+ "get_literal indented code");
+
+ cmark_node *html = cmark_node_next(code);
+ STR_EQ(runner, cmark_node_get_literal(html), "<div>html</div>\n",
+ "get_literal html");
+
+ cmark_node *paragraph = cmark_node_next(html);
+ INT_EQ(runner, cmark_node_get_start_line(paragraph), 17, "get_start_line");
+ INT_EQ(runner, cmark_node_get_start_column(paragraph), 1, "get_start_column");
+ INT_EQ(runner, cmark_node_get_end_line(paragraph), 17, "get_end_line");
+
+ cmark_node *link = cmark_node_first_child(paragraph);
+ STR_EQ(runner, cmark_node_get_url(link), "url", "get_url");
+ STR_EQ(runner, cmark_node_get_title(link), "title", "get_title");
+
+ cmark_node *string = cmark_node_first_child(link);
+ STR_EQ(runner, cmark_node_get_literal(string), "link", "get_literal string");
+
+ // Setters
+
+ OK(runner, cmark_node_set_heading_level(heading, 3), "set_heading_level");
+
+ OK(runner, cmark_node_set_list_type(bullet_list, CMARK_ORDERED_LIST),
+ "set_list_type ordered");
+ OK(runner, cmark_node_set_list_delim(bullet_list, CMARK_PAREN_DELIM),
+ "set_list_delim paren");
+ OK(runner, cmark_node_set_list_start(bullet_list, 3), "set_list_start");
+ OK(runner, cmark_node_set_list_tight(bullet_list, 0), "set_list_tight loose");
+
+ OK(runner, cmark_node_set_list_type(ordered_list, CMARK_BULLET_LIST),
+ "set_list_type bullet");
+ OK(runner, cmark_node_set_list_tight(ordered_list, 1),
+ "set_list_tight tight");
+
+ OK(runner, cmark_node_set_literal(code, "CODE\n"),
+ "set_literal indented code");
+
+ OK(runner, cmark_node_set_literal(fenced, "FENCED\n"),
+ "set_literal fenced code");
+ OK(runner, cmark_node_set_fence_info(fenced, "LANG"), "set_fence_info");
+
+ OK(runner, cmark_node_set_literal(html, "<div>HTML</div>\n"),
+ "set_literal html");
+
+ OK(runner, cmark_node_set_url(link, "URL"), "set_url");
+ OK(runner, cmark_node_set_title(link, "TITLE"), "set_title");
+
+ OK(runner, cmark_node_set_literal(string, "prefix-LINK"),
+ "set_literal string");
+
+ // Set literal to suffix of itself (issue #139).
+ const char *literal = cmark_node_get_literal(string);
+ OK(runner, cmark_node_set_literal(string, literal + sizeof("prefix")),
+ "set_literal suffix");
+
+ char *rendered_html = cmark_render_html(doc,
+ CMARK_OPT_DEFAULT | CMARK_OPT_UNSAFE);
+ static const char expected_html[] =
+ "<h3>Header</h3>\n"
+ "<ol start=\"3\">\n"
+ "<li>\n"
+ "<p>Item 1</p>\n"
+ "</li>\n"
+ "<li>\n"
+ "<p>Item 2</p>\n"
+ "</li>\n"
+ "</ol>\n"
+ "<ul>\n"
+ "<li>Item 1</li>\n"
+ "<li>Item 2</li>\n"
+ "</ul>\n"
+ "<pre><code class=\"language-LANG\">FENCED\n"
+ "</code></pre>\n"
+ "<pre><code>CODE\n"
+ "</code></pre>\n"
+ "<div>HTML</div>\n"
+ "<p><a href=\"URL\" title=\"TITLE\">LINK</a></p>\n";
+ STR_EQ(runner, rendered_html, expected_html, "setters work");
+ free(rendered_html);
+
+ // Getter errors
+
+ INT_EQ(runner, cmark_node_get_heading_level(bullet_list), 0,
+ "get_heading_level error");
+ INT_EQ(runner, cmark_node_get_list_type(heading), CMARK_NO_LIST,
+ "get_list_type error");
+ INT_EQ(runner, cmark_node_get_list_start(code), 0, "get_list_start error");
+ INT_EQ(runner, cmark_node_get_list_tight(fenced), 0, "get_list_tight error");
+ OK(runner, cmark_node_get_literal(ordered_list) == NULL, "get_literal error");
+ OK(runner, cmark_node_get_fence_info(paragraph) == NULL,
+ "get_fence_info error");
+ OK(runner, cmark_node_get_url(html) == NULL, "get_url error");
+ OK(runner, cmark_node_get_title(heading) == NULL, "get_title error");
+
+ // Setter errors
+
+ OK(runner, !cmark_node_set_heading_level(bullet_list, 3),
+ "set_heading_level error");
+ OK(runner, !cmark_node_set_list_type(heading, CMARK_ORDERED_LIST),
+ "set_list_type error");
+ OK(runner, !cmark_node_set_list_start(code, 3), "set_list_start error");
+ OK(runner, !cmark_node_set_list_tight(fenced, 0), "set_list_tight error");
+ OK(runner, !cmark_node_set_literal(ordered_list, "content\n"),
+ "set_literal error");
+ OK(runner, !cmark_node_set_fence_info(paragraph, "lang"),
+ "set_fence_info error");
+ OK(runner, !cmark_node_set_url(html, "url"), "set_url error");
+ OK(runner, !cmark_node_set_title(heading, "title"), "set_title error");
+
+ OK(runner, !cmark_node_set_heading_level(heading, 0),
+ "set_heading_level too small");
+ OK(runner, !cmark_node_set_heading_level(heading, 7),
+ "set_heading_level too large");
+ OK(runner, !cmark_node_set_list_type(bullet_list, CMARK_NO_LIST),
+ "set_list_type invalid");
+ OK(runner, !cmark_node_set_list_start(bullet_list, -1),
+ "set_list_start negative");
+
+ cmark_node_free(doc);
+}
+
+static void free_parent(test_batch_runner *runner) {
+ static const char markdown[] = "text\n";
+
+ cmark_node *doc =
+ cmark_parse_document(markdown, sizeof(markdown) - 1, CMARK_OPT_DEFAULT);
+
+ cmark_node *para = cmark_node_first_child(doc);
+ cmark_node *text = cmark_node_first_child(para);
+ cmark_node_unlink(text);
+ cmark_node_free(doc);
+ STR_EQ(runner, cmark_node_get_literal(text), "text",
+ "inline content after freeing parent block");
+ cmark_node_free(text);
+}
+
+static void node_check(test_batch_runner *runner) {
+ // Construct an incomplete tree.
+ cmark_node *doc = cmark_node_new(CMARK_NODE_DOCUMENT);
+ cmark_node *p1 = cmark_node_new(CMARK_NODE_PARAGRAPH);
+ cmark_node *p2 = cmark_node_new(CMARK_NODE_PARAGRAPH);
+ doc->first_child = p1;
+ p1->next = p2;
+
+ INT_EQ(runner, cmark_node_check(doc, NULL), 4, "node_check works");
+ INT_EQ(runner, cmark_node_check(doc, NULL), 0, "node_check fixes tree");
+
+ cmark_node_free(doc);
+}
+
+static void iterator(test_batch_runner *runner) {
+ cmark_node *doc = cmark_parse_document("> a *b*\n\nc", 10, CMARK_OPT_DEFAULT);
+ int parnodes = 0;
+ cmark_event_type ev_type;
+ cmark_iter *iter = cmark_iter_new(doc);
+ cmark_node *cur;
+
+ while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
+ cur = cmark_iter_get_node(iter);
+ if (cur->type == CMARK_NODE_PARAGRAPH && ev_type == CMARK_EVENT_ENTER) {
+ parnodes += 1;
+ }
+ }
+ INT_EQ(runner, parnodes, 2, "iterate correctly counts paragraphs");
+
+ cmark_iter_free(iter);
+ cmark_node_free(doc);
+}
+
+static void iterator_delete(test_batch_runner *runner) {
+ static const char md[] = "a *b* c\n"
+ "\n"
+ "* item1\n"
+ "* item2\n"
+ "\n"
+ "a `b` c\n"
+ "\n"
+ "* item1\n"
+ "* item2\n";
+ cmark_node *doc = cmark_parse_document(md, sizeof(md) - 1, CMARK_OPT_DEFAULT);
+ cmark_iter *iter = cmark_iter_new(doc);
+ cmark_event_type ev_type;
+
+ while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
+ cmark_node *node = cmark_iter_get_node(iter);
+ // Delete list, emph, and code nodes.
+ if ((ev_type == CMARK_EVENT_EXIT && node->type == CMARK_NODE_LIST) ||
+ (ev_type == CMARK_EVENT_EXIT && node->type == CMARK_NODE_EMPH) ||
+ (ev_type == CMARK_EVENT_ENTER && node->type == CMARK_NODE_CODE)) {
+ cmark_node_free(node);
+ }
+ }
+
+ char *html = cmark_render_html(doc, CMARK_OPT_DEFAULT);
+ static const char expected[] = "<p>a c</p>\n"
+ "<p>a c</p>\n";
+ STR_EQ(runner, html, expected, "iterate and delete nodes");
+
+ cmark_mem *allocator = cmark_get_default_mem_allocator();
+
+ allocator->free(html);
+ cmark_iter_free(iter);
+ cmark_node_free(doc);
+}
+
+static void create_tree(test_batch_runner *runner) {
+ char *html;
+ cmark_node *doc = cmark_node_new(CMARK_NODE_DOCUMENT);
+
+ cmark_node *p = cmark_node_new(CMARK_NODE_PARAGRAPH);
+ OK(runner, !cmark_node_insert_before(doc, p), "insert before root fails");
+ OK(runner, !cmark_node_insert_after(doc, p), "insert after root fails");
+ OK(runner, cmark_node_append_child(doc, p), "append1");
+ INT_EQ(runner, cmark_node_check(doc, NULL), 0, "append1 consistent");
+ OK(runner, cmark_node_parent(p) == doc, "node_parent");
+
+ cmark_node *emph = cmark_node_new(CMARK_NODE_EMPH);
+ OK(runner, cmark_node_prepend_child(p, emph), "prepend1");
+ INT_EQ(runner, cmark_node_check(doc, NULL), 0, "prepend1 consistent");
+
+ cmark_node *str1 = cmark_node_new(CMARK_NODE_TEXT);
+ cmark_node_set_literal(str1, "Hello, ");
+ OK(runner, cmark_node_prepend_child(p, str1), "prepend2");
+ INT_EQ(runner, cmark_node_check(doc, NULL), 0, "prepend2 consistent");
+
+ cmark_node *str3 = cmark_node_new(CMARK_NODE_TEXT);
+ cmark_node_set_literal(str3, "!");
+ OK(runner, cmark_node_append_child(p, str3), "append2");
+ INT_EQ(runner, cmark_node_check(doc, NULL), 0, "append2 consistent");
+
+ cmark_node *str2 = cmark_node_new(CMARK_NODE_TEXT);
+ cmark_node_set_literal(str2, "world");
+ OK(runner, cmark_node_append_child(emph, str2), "append3");
+ INT_EQ(runner, cmark_node_check(doc, NULL), 0, "append3 consistent");
+
+ html = cmark_render_html(doc, CMARK_OPT_DEFAULT);
+ STR_EQ(runner, html, "<p>Hello, <em>world</em>!</p>\n", "render_html");
+ free(html);
+
+ OK(runner, cmark_node_insert_before(str1, str3), "ins before1");
+ INT_EQ(runner, cmark_node_check(doc, NULL), 0, "ins before1 consistent");
+ // 31e
+ OK(runner, cmark_node_first_child(p) == str3, "ins before1 works");
+
+ OK(runner, cmark_node_insert_before(str1, emph), "ins before2");
+ INT_EQ(runner, cmark_node_check(doc, NULL), 0, "ins before2 consistent");
+ // 3e1
+ OK(runner, cmark_node_last_child(p) == str1, "ins before2 works");
+
+ OK(runner, cmark_node_insert_after(str1, str3), "ins after1");
+ INT_EQ(runner, cmark_node_check(doc, NULL), 0, "ins after1 consistent");
+ // e13
+ OK(runner, cmark_node_next(str1) == str3, "ins after1 works");
+
+ OK(runner, cmark_node_insert_after(str1, emph), "ins after2");
+ INT_EQ(runner, cmark_node_check(doc, NULL), 0, "ins after2 consistent");
+ // 1e3
+ OK(runner, cmark_node_previous(emph) == str1, "ins after2 works");
+
+ cmark_node *str4 = cmark_node_new(CMARK_NODE_TEXT);
+ cmark_node_set_literal(str4, "brzz");
+ OK(runner, cmark_node_replace(str1, str4), "replace");
+ // The replaced node is not freed
+ cmark_node_free(str1);
+
+ INT_EQ(runner, cmark_node_check(doc, NULL), 0, "replace consistent");
+ OK(runner, cmark_node_previous(emph) == str4, "replace works");
+ INT_EQ(runner, cmark_node_replace(p, str4), 0, "replace str for p fails");
+
+ cmark_node_unlink(emph);
+
+ html = cmark_render_html(doc, CMARK_OPT_DEFAULT);
+ STR_EQ(runner, html, "<p>brzz!</p>\n", "render_html after shuffling");
+ free(html);
+
+ cmark_node_free(doc);
+ cmark_node_free(emph);
+}
+
+static void custom_nodes(test_batch_runner *runner) {
+ char *html;
+ char *man;
+ cmark_node *doc = cmark_node_new(CMARK_NODE_DOCUMENT);
+ cmark_node *p = cmark_node_new(CMARK_NODE_PARAGRAPH);
+ cmark_node_append_child(doc, p);
+ cmark_node *ci = cmark_node_new(CMARK_NODE_CUSTOM_INLINE);
+ cmark_node *str1 = cmark_node_new(CMARK_NODE_TEXT);
+ cmark_node_set_literal(str1, "Hello");
+ OK(runner, cmark_node_append_child(ci, str1), "append1");
+ OK(runner, cmark_node_set_on_enter(ci, "<ON ENTER|"), "set_on_enter");
+ OK(runner, cmark_node_set_on_exit(ci, "|ON EXIT>"), "set_on_exit");
+ STR_EQ(runner, cmark_node_get_on_enter(ci), "<ON ENTER|", "get_on_enter");
+ STR_EQ(runner, cmark_node_get_on_exit(ci), "|ON EXIT>", "get_on_exit");
+ cmark_node_append_child(p, ci);
+ cmark_node *cb = cmark_node_new(CMARK_NODE_CUSTOM_BLOCK);
+ cmark_node_set_on_enter(cb, "<on enter|");
+ // leave on_exit unset
+ STR_EQ(runner, cmark_node_get_on_exit(cb), "", "get_on_exit (empty)");
+ cmark_node_append_child(doc, cb);
+
+ html = cmark_render_html(doc, CMARK_OPT_DEFAULT);
+ STR_EQ(runner, html, "<p><ON ENTER|Hello|ON EXIT></p>\n<on enter|\n",
+ "render_html");
+ free(html);
+
+ man = cmark_render_man(doc, CMARK_OPT_DEFAULT, 0);
+ STR_EQ(runner, man, ".PP\n<ON ENTER|Hello|ON EXIT>\n<on enter|\n",
+ "render_man");
+ free(man);
+
+ cmark_node_free(doc);
+}
+
+void hierarchy(test_batch_runner *runner) {
+ cmark_node *bquote1 = cmark_node_new(CMARK_NODE_BLOCK_QUOTE);
+ cmark_node *bquote2 = cmark_node_new(CMARK_NODE_BLOCK_QUOTE);
+ cmark_node *bquote3 = cmark_node_new(CMARK_NODE_BLOCK_QUOTE);
+
+ OK(runner, cmark_node_append_child(bquote1, bquote2), "append bquote2");
+ OK(runner, cmark_node_append_child(bquote2, bquote3), "append bquote3");
+ OK(runner, !cmark_node_append_child(bquote3, bquote3),
+ "adding a node as child of itself fails");
+ OK(runner, !cmark_node_append_child(bquote3, bquote1),
+ "adding a parent as child fails");
+
+ cmark_node_free(bquote1);
+
+ int max_node_type = CMARK_NODE_LAST_BLOCK > CMARK_NODE_LAST_INLINE
+ ? CMARK_NODE_LAST_BLOCK
+ : CMARK_NODE_LAST_INLINE;
+ OK(runner, max_node_type < 32, "all node types < 32");
+
+ int list_item_flag = 1 << CMARK_NODE_ITEM;
+ int top_level_blocks =
+ (1 << CMARK_NODE_BLOCK_QUOTE) | (1 << CMARK_NODE_LIST) |
+ (1 << CMARK_NODE_CODE_BLOCK) | (1 << CMARK_NODE_HTML_BLOCK) |
+ (1 << CMARK_NODE_PARAGRAPH) | (1 << CMARK_NODE_HEADING) |
+ (1 << CMARK_NODE_THEMATIC_BREAK);
+ int all_inlines = (1 << CMARK_NODE_TEXT) | (1 << CMARK_NODE_SOFTBREAK) |
+ (1 << CMARK_NODE_LINEBREAK) | (1 << CMARK_NODE_CODE) |
+ (1 << CMARK_NODE_HTML_INLINE) | (1 << CMARK_NODE_EMPH) |
+ (1 << CMARK_NODE_STRONG) | (1 << CMARK_NODE_LINK) |
+ (1 << CMARK_NODE_IMAGE);
+
+ test_content(runner, CMARK_NODE_DOCUMENT, top_level_blocks);
+ test_content(runner, CMARK_NODE_BLOCK_QUOTE, top_level_blocks);
+ test_content(runner, CMARK_NODE_LIST, list_item_flag);
+ test_content(runner, CMARK_NODE_ITEM, top_level_blocks);
+ test_content(runner, CMARK_NODE_CODE_BLOCK, 0);
+ test_content(runner, CMARK_NODE_HTML_BLOCK, 0);
+ test_content(runner, CMARK_NODE_PARAGRAPH, all_inlines);
+ test_content(runner, CMARK_NODE_HEADING, all_inlines);
+ test_content(runner, CMARK_NODE_THEMATIC_BREAK, 0);
+ test_content(runner, CMARK_NODE_TEXT, 0);
+ test_content(runner, CMARK_NODE_SOFTBREAK, 0);
+ test_content(runner, CMARK_NODE_LINEBREAK, 0);
+ test_content(runner, CMARK_NODE_CODE, 0);
+ test_content(runner, CMARK_NODE_HTML_INLINE, 0);
+ test_content(runner, CMARK_NODE_EMPH, all_inlines);
+ test_content(runner, CMARK_NODE_STRONG, all_inlines);
+ test_content(runner, CMARK_NODE_LINK, all_inlines);
+ test_content(runner, CMARK_NODE_IMAGE, all_inlines);
+}
+
+static void test_content(test_batch_runner *runner, cmark_node_type type,
+ int allowed_content) {
+ cmark_node *node = cmark_node_new(type);
+
+ for (int i = 0; i < num_node_types; ++i) {
+ cmark_node_type child_type = node_types[i];
+ cmark_node *child = cmark_node_new(child_type);
+
+ int got = cmark_node_append_child(node, child);
+ int expected = (allowed_content >> child_type) & 1;
+
+ INT_EQ(runner, got, expected, "add %d as child of %d", child_type, type);
+
+ cmark_node_free(child);
+ }
+
+ cmark_node_free(node);
+}
+
+static void parser(test_batch_runner *runner) {
+ test_md_to_html(runner, "No newline", "<p>No newline</p>\n",
+ "document without trailing newline");
+}
+
+static void render_html(test_batch_runner *runner) {
+ char *html;
+
+ static const char markdown[] = "foo *bar*\n"
+ "\n"
+ "paragraph 2\n";
+ cmark_node *doc =
+ cmark_parse_document(markdown, sizeof(markdown) - 1, CMARK_OPT_DEFAULT);
+
+ cmark_node *paragraph = cmark_node_first_child(doc);
+ html = cmark_render_html(paragraph, CMARK_OPT_DEFAULT);
+ STR_EQ(runner, html, "<p>foo <em>bar</em></p>\n", "render single paragraph");
+ free(html);
+
+ cmark_node *string = cmark_node_first_child(paragraph);
+ html = cmark_render_html(string, CMARK_OPT_DEFAULT);
+ STR_EQ(runner, html, "foo ", "render single inline");
+ free(html);
+
+ cmark_node *emph = cmark_node_next(string);
+ html = cmark_render_html(emph, CMARK_OPT_DEFAULT);
+ STR_EQ(runner, html, "<em>bar</em>", "render inline with children");
+ free(html);
+
+ cmark_node_free(doc);
+}
+
+static void render_xml(test_batch_runner *runner) {
+ char *xml;
+
+ static const char markdown[] = "foo *bar*\n"
+ "\n"
+ "control -\x0C-\n"
+ "fffe -\xEF\xBF\xBE-\n"
+ "ffff -\xEF\xBF\xBF-\n"
+ "escape <>&\"\n"
+ "\n"
+ "```\ncode\n```\n";
+ cmark_node *doc =
+ cmark_parse_document(markdown, sizeof(markdown) - 1, CMARK_OPT_DEFAULT);
+
+ xml = cmark_render_xml(doc, CMARK_OPT_DEFAULT);
+ STR_EQ(runner, xml, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<!DOCTYPE document SYSTEM \"CommonMark.dtd\">\n"
+ "<document xmlns=\"http://commonmark.org/xml/1.0\">\n"
+ " <paragraph>\n"
+ " <text xml:space=\"preserve\">foo </text>\n"
+ " <emph>\n"
+ " <text xml:space=\"preserve\">bar</text>\n"
+ " </emph>\n"
+ " </paragraph>\n"
+ " <paragraph>\n"
+ " <text xml:space=\"preserve\">control -" UTF8_REPL "-</text>\n"
+ " <softbreak />\n"
+ " <text xml:space=\"preserve\">fffe -" UTF8_REPL "-</text>\n"
+ " <softbreak />\n"
+ " <text xml:space=\"preserve\">ffff -" UTF8_REPL "-</text>\n"
+ " <softbreak />\n"
+ " <text xml:space=\"preserve\">escape &lt;&gt;&amp;&quot;</text>\n"
+ " </paragraph>\n"
+ " <code_block xml:space=\"preserve\">code\n"
+ "</code_block>\n"
+ "</document>\n",
+ "render document");
+ free(xml);
+ cmark_node *paragraph = cmark_node_first_child(doc);
+ xml = cmark_render_xml(paragraph, CMARK_OPT_DEFAULT | CMARK_OPT_SOURCEPOS);
+ STR_EQ(runner, xml, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<!DOCTYPE document SYSTEM \"CommonMark.dtd\">\n"
+ "<paragraph sourcepos=\"1:1-1:9\">\n"
+ " <text sourcepos=\"1:1-1:4\" xml:space=\"preserve\">foo </text>\n"
+ " <emph sourcepos=\"1:5-1:9\">\n"
+ " <text sourcepos=\"1:6-1:8\" xml:space=\"preserve\">bar</text>\n"
+ " </emph>\n"
+ "</paragraph>\n",
+ "render first paragraph with source pos");
+ free(xml);
+ cmark_node_free(doc);
+}
+
+static void render_man(test_batch_runner *runner) {
+ char *man;
+
+ static const char markdown[] = "foo *bar*\n"
+ "\n"
+ "- Lorem ipsum dolor sit amet,\n"
+ " consectetur adipiscing elit,\n"
+ "- sed do eiusmod tempor incididunt\n"
+ " ut labore et dolore magna aliqua.\n";
+ cmark_node *doc =
+ cmark_parse_document(markdown, sizeof(markdown) - 1, CMARK_OPT_DEFAULT);
+
+ man = cmark_render_man(doc, CMARK_OPT_DEFAULT, 20);
+ STR_EQ(runner, man, ".PP\n"
+ "foo \\f[I]bar\\f[]\n"
+ ".IP \\[bu] 2\n"
+ "Lorem ipsum dolor\n"
+ "sit amet,\n"
+ "consectetur\n"
+ "adipiscing elit,\n"
+ ".IP \\[bu] 2\n"
+ "sed do eiusmod\n"
+ "tempor incididunt ut\n"
+ "labore et dolore\n"
+ "magna aliqua.\n",
+ "render document with wrapping");
+ free(man);
+ man = cmark_render_man(doc, CMARK_OPT_DEFAULT, 0);
+ STR_EQ(runner, man, ".PP\n"
+ "foo \\f[I]bar\\f[]\n"
+ ".IP \\[bu] 2\n"
+ "Lorem ipsum dolor sit amet,\n"
+ "consectetur adipiscing elit,\n"
+ ".IP \\[bu] 2\n"
+ "sed do eiusmod tempor incididunt\n"
+ "ut labore et dolore magna aliqua.\n",
+ "render document without wrapping");
+ free(man);
+ cmark_node_free(doc);
+}
+
+static void render_latex(test_batch_runner *runner) {
+ char *latex;
+
+ static const char markdown[] = "foo *bar* $%\n"
+ "\n"
+ "- Lorem ipsum dolor sit amet,\n"
+ " consectetur adipiscing elit,\n"
+ "- sed do eiusmod tempor incididunt\n"
+ " ut labore et dolore magna aliqua.\n";
+ cmark_node *doc =
+ cmark_parse_document(markdown, sizeof(markdown) - 1, CMARK_OPT_DEFAULT);
+
+ latex = cmark_render_latex(doc, CMARK_OPT_DEFAULT, 20);
+ STR_EQ(runner, latex, "foo \\emph{bar} \\$\\%\n"
+ "\n"
+ "\\begin{itemize}\n"
+ "\\item Lorem ipsum\n"
+ "dolor sit amet,\n"
+ "consectetur\n"
+ "adipiscing elit,\n"
+ "\n"
+ "\\item sed do eiusmod\n"
+ "tempor incididunt ut\n"
+ "labore et dolore\n"
+ "magna aliqua.\n"
+ "\n"
+ "\\end{itemize}\n",
+ "render document with wrapping");
+ free(latex);
+ latex = cmark_render_latex(doc, CMARK_OPT_DEFAULT, 0);
+ STR_EQ(runner, latex, "foo \\emph{bar} \\$\\%\n"
+ "\n"
+ "\\begin{itemize}\n"
+ "\\item Lorem ipsum dolor sit amet,\n"
+ "consectetur adipiscing elit,\n"
+ "\n"
+ "\\item sed do eiusmod tempor incididunt\n"
+ "ut labore et dolore magna aliqua.\n"
+ "\n"
+ "\\end{itemize}\n",
+ "render document without wrapping");
+ free(latex);
+ cmark_node_free(doc);
+}
+
+static void render_commonmark(test_batch_runner *runner) {
+ char *commonmark;
+
+ static const char markdown[] = "> \\- foo *bar* \\*bar\\*\n"
+ "\n"
+ "- Lorem ipsum dolor sit amet,\n"
+ " consectetur adipiscing elit,\n"
+ "- sed do eiusmod tempor incididunt\n"
+ " ut labore et dolore magna aliqua.\n";
+ cmark_node *doc =
+ cmark_parse_document(markdown, sizeof(markdown) - 1, CMARK_OPT_DEFAULT);
+
+ commonmark = cmark_render_commonmark(doc, CMARK_OPT_DEFAULT, 26);
+ STR_EQ(runner, commonmark, "> \\- foo *bar* \\*bar\\*\n"
+ "\n"
+ " - Lorem ipsum dolor sit\n"
+ " amet, consectetur\n"
+ " adipiscing elit,\n"
+ " - sed do eiusmod tempor\n"
+ " incididunt ut labore\n"
+ " et dolore magna\n"
+ " aliqua.\n",
+ "render document with wrapping");
+ free(commonmark);
+ commonmark = cmark_render_commonmark(doc, CMARK_OPT_DEFAULT, 0);
+ STR_EQ(runner, commonmark, "> \\- foo *bar* \\*bar\\*\n"
+ "\n"
+ " - Lorem ipsum dolor sit amet,\n"
+ " consectetur adipiscing elit,\n"
+ " - sed do eiusmod tempor incididunt\n"
+ " ut labore et dolore magna aliqua.\n",
+ "render document without wrapping");
+ free(commonmark);
+
+ cmark_node *text = cmark_node_new(CMARK_NODE_TEXT);
+ cmark_node_set_literal(text, "Hi");
+ commonmark = cmark_render_commonmark(text, CMARK_OPT_DEFAULT, 0);
+ STR_EQ(runner, commonmark, "Hi", "render single inline node");
+ free(commonmark);
+
+ cmark_node_free(text);
+ cmark_node_free(doc);
+}
+
+static void utf8(test_batch_runner *runner) {
+ // Ranges
+ test_char(runner, 1, "\x01", "valid utf8 01");
+ test_char(runner, 1, "\x7F", "valid utf8 7F");
+ test_char(runner, 0, "\x80", "invalid utf8 80");
+ test_char(runner, 0, "\xBF", "invalid utf8 BF");
+ test_char(runner, 0, "\xC0\x80", "invalid utf8 C080");
+ test_char(runner, 0, "\xC1\xBF", "invalid utf8 C1BF");
+ test_char(runner, 1, "\xC2\x80", "valid utf8 C280");
+ test_char(runner, 1, "\xDF\xBF", "valid utf8 DFBF");
+ test_char(runner, 0, "\xE0\x80\x80", "invalid utf8 E08080");
+ test_char(runner, 0, "\xE0\x9F\xBF", "invalid utf8 E09FBF");
+ test_char(runner, 1, "\xE0\xA0\x80", "valid utf8 E0A080");
+ test_char(runner, 1, "\xED\x9F\xBF", "valid utf8 ED9FBF");
+ test_char(runner, 0, "\xED\xA0\x80", "invalid utf8 EDA080");
+ test_char(runner, 0, "\xED\xBF\xBF", "invalid utf8 EDBFBF");
+ test_char(runner, 0, "\xF0\x80\x80\x80", "invalid utf8 F0808080");
+ test_char(runner, 0, "\xF0\x8F\xBF\xBF", "invalid utf8 F08FBFBF");
+ test_char(runner, 1, "\xF0\x90\x80\x80", "valid utf8 F0908080");
+ test_char(runner, 1, "\xF4\x8F\xBF\xBF", "valid utf8 F48FBFBF");
+ test_char(runner, 0, "\xF4\x90\x80\x80", "invalid utf8 F4908080");
+ test_char(runner, 0, "\xF7\xBF\xBF\xBF", "invalid utf8 F7BFBFBF");
+ test_char(runner, 0, "\xF8", "invalid utf8 F8");
+ test_char(runner, 0, "\xFF", "invalid utf8 FF");
+
+ // Incomplete byte sequences at end of input
+ test_incomplete_char(runner, "\xE0\xA0", "invalid utf8 E0A0");
+ test_incomplete_char(runner, "\xF0\x90\x80", "invalid utf8 F09080");
+
+ // Invalid continuation bytes
+ test_continuation_byte(runner, "\xC2\x80");
+ test_continuation_byte(runner, "\xE0\xA0\x80");
+ test_continuation_byte(runner, "\xF0\x90\x80\x80");
+
+ // Test string containing null character
+ static const char string_with_null[] = "((((\0))))";
+ char *html = cmark_markdown_to_html(
+ string_with_null, sizeof(string_with_null) - 1, CMARK_OPT_DEFAULT);
+ STR_EQ(runner, html, "<p>((((" UTF8_REPL "))))</p>\n", "utf8 with U+0000");
+ free(html);
+
+ // Test NUL followed by newline
+ static const char string_with_nul_lf[] = "```\n\0\n```\n";
+ html = cmark_markdown_to_html(
+ string_with_nul_lf, sizeof(string_with_nul_lf) - 1, CMARK_OPT_DEFAULT);
+ STR_EQ(runner, html, "<pre><code>\xef\xbf\xbd\n</code></pre>\n",
+ "utf8 with \\0\\n");
+ free(html);
+}
+
+static void test_char(test_batch_runner *runner, int valid, const char *utf8,
+ const char *msg) {
+ char buf[20];
+ sprintf(buf, "((((%s))))", utf8);
+
+ if (valid) {
+ char expected[30];
+ sprintf(expected, "<p>((((%s))))</p>\n", utf8);
+ test_md_to_html(runner, buf, expected, msg);
+ } else {
+ test_md_to_html(runner, buf, "<p>((((" UTF8_REPL "))))</p>\n", msg);
+ }
+}
+
+static void test_incomplete_char(test_batch_runner *runner, const char *utf8,
+ const char *msg) {
+ char buf[20];
+ sprintf(buf, "----%s", utf8);
+ test_md_to_html(runner, buf, "<p>----" UTF8_REPL "</p>\n", msg);
+}
+
+static void test_continuation_byte(test_batch_runner *runner,
+ const char *utf8) {
+ size_t len = strlen(utf8);
+
+ for (size_t pos = 1; pos < len; ++pos) {
+ char buf[20];
+ sprintf(buf, "((((%s))))", utf8);
+ buf[4 + pos] = '\x20';
+
+ char expected[50];
+ strcpy(expected, "<p>((((" UTF8_REPL "\x20");
+ for (size_t i = pos + 1; i < len; ++i) {
+ strcat(expected, UTF8_REPL);
+ }
+ strcat(expected, "))))</p>\n");
+
+ char *html =
+ cmark_markdown_to_html(buf, strlen(buf), CMARK_OPT_VALIDATE_UTF8);
+ STR_EQ(runner, html, expected, "invalid utf8 continuation byte %d/%d", pos,
+ len);
+ free(html);
+ }
+}
+
+static void line_endings(test_batch_runner *runner) {
+ // Test list with different line endings
+ static const char list_with_endings[] = "- a\n- b\r\n- c\r- d";
+ char *html = cmark_markdown_to_html(
+ list_with_endings, sizeof(list_with_endings) - 1, CMARK_OPT_DEFAULT);
+ STR_EQ(runner, html,
+ "<ul>\n<li>a</li>\n<li>b</li>\n<li>c</li>\n<li>d</li>\n</ul>\n",
+ "list with different line endings");
+ free(html);
+
+ static const char crlf_lines[] = "line\r\nline\r\n";
+ html = cmark_markdown_to_html(crlf_lines, sizeof(crlf_lines) - 1,
+ CMARK_OPT_DEFAULT | CMARK_OPT_HARDBREAKS);
+ STR_EQ(runner, html, "<p>line<br />\nline</p>\n",
+ "crlf endings with CMARK_OPT_HARDBREAKS");
+ free(html);
+ html = cmark_markdown_to_html(crlf_lines, sizeof(crlf_lines) - 1,
+ CMARK_OPT_DEFAULT | CMARK_OPT_NOBREAKS);
+ STR_EQ(runner, html, "<p>line line</p>\n",
+ "crlf endings with CMARK_OPT_NOBREAKS");
+ free(html);
+
+ static const char no_line_ending[] = "```\nline\n```";
+ html = cmark_markdown_to_html(no_line_ending, sizeof(no_line_ending) - 1,
+ CMARK_OPT_DEFAULT);
+ STR_EQ(runner, html, "<pre><code>line\n</code></pre>\n",
+ "fenced code block with no final newline");
+ free(html);
+}
+
+static void numeric_entities(test_batch_runner *runner) {
+ test_md_to_html(runner, "&#0;", "<p>" UTF8_REPL "</p>\n",
+ "Invalid numeric entity 0");
+ test_md_to_html(runner, "&#55295;", "<p>\xED\x9F\xBF</p>\n",
+ "Valid numeric entity 0xD7FF");
+ test_md_to_html(runner, "&#xD800;", "<p>" UTF8_REPL "</p>\n",
+ "Invalid numeric entity 0xD800");
+ test_md_to_html(runner, "&#xDFFF;", "<p>" UTF8_REPL "</p>\n",
+ "Invalid numeric entity 0xDFFF");
+ test_md_to_html(runner, "&#57344;", "<p>\xEE\x80\x80</p>\n",
+ "Valid numeric entity 0xE000");
+ test_md_to_html(runner, "&#x10FFFF;", "<p>\xF4\x8F\xBF\xBF</p>\n",
+ "Valid numeric entity 0x10FFFF");
+ test_md_to_html(runner, "&#x110000;", "<p>" UTF8_REPL "</p>\n",
+ "Invalid numeric entity 0x110000");
+ test_md_to_html(runner, "&#x80000000;", "<p>&amp;#x80000000;</p>\n",
+ "Invalid numeric entity 0x80000000");
+ test_md_to_html(runner, "&#xFFFFFFFF;", "<p>&amp;#xFFFFFFFF;</p>\n",
+ "Invalid numeric entity 0xFFFFFFFF");
+ test_md_to_html(runner, "&#99999999;", "<p>&amp;#99999999;</p>\n",
+ "Invalid numeric entity 99999999");
+
+ test_md_to_html(runner, "&#;", "<p>&amp;#;</p>\n",
+ "Min decimal entity length");
+ test_md_to_html(runner, "&#x;", "<p>&amp;#x;</p>\n",
+ "Min hexadecimal entity length");
+ test_md_to_html(runner, "&#999999999;", "<p>&amp;#999999999;</p>\n",
+ "Max decimal entity length");
+ test_md_to_html(runner, "&#x000000041;", "<p>&amp;#x000000041;</p>\n",
+ "Max hexadecimal entity length");
+}
+
+static void test_safe(test_batch_runner *runner) {
+ // Test safe mode
+ static const char raw_html[] = "<div>\nhi\n</div>\n\n<a>hi</"
+ "a>\n[link](JAVAscript:alert('hi'))\n![image]("
+ "file:my.js)\n";
+ char *html = cmark_markdown_to_html(raw_html, sizeof(raw_html) - 1,
+ CMARK_OPT_DEFAULT);
+ STR_EQ(runner, html, "<!-- raw HTML omitted -->\n<p><!-- raw HTML omitted "
+ "-->hi<!-- raw HTML omitted -->\n<a "
+ "href=\"\">link</a>\n<img src=\"\" alt=\"image\" "
+ "/></p>\n",
+ "input with raw HTML and dangerous links");
+ free(html);
+}
+
+static void test_md_to_html(test_batch_runner *runner, const char *markdown,
+ const char *expected_html, const char *msg) {
+ char *html = cmark_markdown_to_html(markdown, strlen(markdown),
+ CMARK_OPT_VALIDATE_UTF8);
+ STR_EQ(runner, html, expected_html, msg);
+ free(html);
+}
+
+static void test_feed_across_line_ending(test_batch_runner *runner) {
+ // See #117
+ cmark_parser *parser = cmark_parser_new(CMARK_OPT_DEFAULT);
+ cmark_parser_feed(parser, "line1\r", 6);
+ cmark_parser_feed(parser, "\nline2\r\n", 8);
+ cmark_node *document = cmark_parser_finish(parser);
+ OK(runner, document->first_child->next == NULL, "document has one paragraph");
+ cmark_parser_free(parser);
+ cmark_node_free(document);
+}
+
+static void sub_document(test_batch_runner *runner) {
+ cmark_node *doc = cmark_node_new(CMARK_NODE_DOCUMENT);
+ cmark_node *list = cmark_node_new(CMARK_NODE_LIST);
+ OK(runner, cmark_node_append_child(doc, list), "list");
+
+ {
+ cmark_node *item = cmark_node_new(CMARK_NODE_ITEM);
+ OK(runner, cmark_node_append_child(list, item), "append_0");
+ static const char markdown[] =
+ "Hello &ldquo; <http://www.google.com>\n";
+ cmark_parser *parser = cmark_parser_new_with_mem_into_root(
+ CMARK_OPT_DEFAULT,
+ cmark_get_default_mem_allocator(),
+ item);
+ cmark_parser_feed(parser, markdown, sizeof(markdown) - 1);
+ OK(runner, cmark_parser_finish(parser) != NULL, "parser_finish_0");
+ cmark_parser_free(parser);
+ }
+
+ {
+ cmark_node *item = cmark_node_new(CMARK_NODE_ITEM);
+ OK(runner, cmark_node_append_child(list, item), "append_0");
+ static const char markdown[] =
+ "Bye &ldquo; <http://www.geocities.com>\n";
+ cmark_parser *parser = cmark_parser_new_with_mem_into_root(
+ CMARK_OPT_DEFAULT,
+ cmark_get_default_mem_allocator(),
+ item);
+ cmark_parser_feed(parser, markdown, sizeof(markdown) - 1);
+ OK(runner, cmark_parser_finish(parser) != NULL, "parser_finish_0");
+ cmark_parser_free(parser);
+ }
+
+ char *xml = cmark_render_xml(doc, CMARK_OPT_DEFAULT);
+ STR_EQ(runner, xml, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<!DOCTYPE document SYSTEM \"CommonMark.dtd\">\n"
+ "<document xmlns=\"http://commonmark.org/xml/1.0\">\n"
+ " <list type=\"bullet\" tight=\"false\">\n"
+ " <item>\n"
+ " <paragraph>\n"
+ " <text xml:space=\"preserve\">Hello “ </text>\n"
+ " <link destination=\"http://www.google.com\">\n"
+ " <text xml:space=\"preserve\">http://www.google.com</text>\n"
+ " </link>\n"
+ " </paragraph>\n"
+ " </item>\n"
+ " <item>\n"
+ " <paragraph>\n"
+ " <text xml:space=\"preserve\">Bye “ </text>\n"
+ " <link destination=\"http://www.geocities.com\">\n"
+ " <text xml:space=\"preserve\">http://www.geocities.com</text>\n"
+ " </link>\n"
+ " </paragraph>\n"
+ " </item>\n"
+ " </list>\n"
+ "</document>\n",
+ "nested document XML is as expected");
+ free(xml);
+
+ char *cmark = cmark_render_commonmark(doc, CMARK_OPT_DEFAULT, 0);
+ STR_EQ(runner, cmark, " - Hello “ <http://www.google.com>\n"
+ "\n"
+ " - Bye “ <http://www.geocities.com>\n",
+ "nested document CommonMark is as expected");
+ free(cmark);
+
+ cmark_node_free(doc);
+}
+
+static void source_pos(test_batch_runner *runner) {
+ static const char markdown[] =
+ "# Hi **there*.\n"
+ "\n"
+ "Hello &ldquo; <http://www.google.com>\n"
+ "there `hi` -- [okay](www.google.com (ok)).\n"
+ "\n"
+ "> 1. Okay.\n"
+ "> Sure.\n"
+ ">\n"
+ "> 2. Yes, okay.\n"
+ "> ![ok](hi \"yes\")\n";
+
+ cmark_node *doc = cmark_parse_document(markdown, sizeof(markdown) - 1, CMARK_OPT_DEFAULT);
+ char *xml = cmark_render_xml(doc, CMARK_OPT_DEFAULT | CMARK_OPT_SOURCEPOS);
+ STR_EQ(runner, xml, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<!DOCTYPE document SYSTEM \"CommonMark.dtd\">\n"
+ "<document sourcepos=\"1:1-10:20\" xmlns=\"http://commonmark.org/xml/1.0\">\n"
+ " <heading sourcepos=\"1:1-1:14\" level=\"1\">\n"
+ " <text sourcepos=\"1:3-1:6\" xml:space=\"preserve\">Hi *</text>\n"
+ " <emph sourcepos=\"1:7-1:13\">\n"
+ " <text sourcepos=\"1:8-1:12\" xml:space=\"preserve\">there</text>\n"
+ " </emph>\n"
+ " <text sourcepos=\"1:14-1:14\" xml:space=\"preserve\">.</text>\n"
+ " </heading>\n"
+ " <paragraph sourcepos=\"3:1-4:42\">\n"
+ " <text sourcepos=\"3:1-3:14\" xml:space=\"preserve\">Hello “ </text>\n"
+ " <link sourcepos=\"3:15-3:37\" destination=\"http://www.google.com\">\n"
+ " <text sourcepos=\"3:16-3:36\" xml:space=\"preserve\">http://www.google.com</text>\n"
+ " </link>\n"
+ " <softbreak />\n"
+ " <text sourcepos=\"4:1-4:6\" xml:space=\"preserve\">there </text>\n"
+ " <code sourcepos=\"4:8-4:9\" xml:space=\"preserve\">hi</code>\n"
+ " <text sourcepos=\"4:11-4:14\" xml:space=\"preserve\"> -- </text>\n"
+ " <link sourcepos=\"4:15-4:41\" destination=\"www.google.com\" title=\"ok\">\n"
+ " <text sourcepos=\"4:16-4:19\" xml:space=\"preserve\">okay</text>\n"
+ " </link>\n"
+ " <text sourcepos=\"4:42-4:42\" xml:space=\"preserve\">.</text>\n"
+ " </paragraph>\n"
+ " <block_quote sourcepos=\"6:1-10:20\">\n"
+ " <list sourcepos=\"6:3-10:20\" type=\"ordered\" start=\"1\" delimiter=\"period\" tight=\"false\">\n"
+ " <item sourcepos=\"6:3-8:1\">\n"
+ " <paragraph sourcepos=\"6:6-7:10\">\n"
+ " <text sourcepos=\"6:6-6:10\" xml:space=\"preserve\">Okay.</text>\n"
+ " <softbreak />\n"
+ " <text sourcepos=\"7:6-7:10\" xml:space=\"preserve\">Sure.</text>\n"
+ " </paragraph>\n"
+ " </item>\n"
+ " <item sourcepos=\"9:3-10:20\">\n"
+ " <paragraph sourcepos=\"9:6-10:20\">\n"
+ " <text sourcepos=\"9:6-9:15\" xml:space=\"preserve\">Yes, okay.</text>\n"
+ " <softbreak />\n"
+ " <image sourcepos=\"10:6-10:20\" destination=\"hi\" title=\"yes\">\n"
+ " <text sourcepos=\"10:8-10:9\" xml:space=\"preserve\">ok</text>\n"
+ " </image>\n"
+ " </paragraph>\n"
+ " </item>\n"
+ " </list>\n"
+ " </block_quote>\n"
+ "</document>\n",
+ "sourcepos are as expected");
+ free(xml);
+ cmark_node_free(doc);
+}
+
+static void source_pos_inlines(test_batch_runner *runner) {
+ {
+ static const char markdown[] =
+ "*first*\n"
+ "second\n";
+
+ cmark_node *doc = cmark_parse_document(markdown, sizeof(markdown) - 1, CMARK_OPT_DEFAULT);
+ char *xml = cmark_render_xml(doc, CMARK_OPT_DEFAULT | CMARK_OPT_SOURCEPOS);
+ STR_EQ(runner, xml, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<!DOCTYPE document SYSTEM \"CommonMark.dtd\">\n"
+ "<document sourcepos=\"1:1-2:6\" xmlns=\"http://commonmark.org/xml/1.0\">\n"
+ " <paragraph sourcepos=\"1:1-2:6\">\n"
+ " <emph sourcepos=\"1:1-1:7\">\n"
+ " <text sourcepos=\"1:2-1:6\" xml:space=\"preserve\">first</text>\n"
+ " </emph>\n"
+ " <softbreak />\n"
+ " <text sourcepos=\"2:1-2:6\" xml:space=\"preserve\">second</text>\n"
+ " </paragraph>\n"
+ "</document>\n",
+ "sourcepos are as expected");
+ free(xml);
+ cmark_node_free(doc);
+ }
+ {
+ static const char markdown[] =
+ "*first\n"
+ "second*\n";
+
+ cmark_node *doc = cmark_parse_document(markdown, sizeof(markdown) - 1, CMARK_OPT_DEFAULT);
+ char *xml = cmark_render_xml(doc, CMARK_OPT_DEFAULT | CMARK_OPT_SOURCEPOS);
+ STR_EQ(runner, xml, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<!DOCTYPE document SYSTEM \"CommonMark.dtd\">\n"
+ "<document sourcepos=\"1:1-2:7\" xmlns=\"http://commonmark.org/xml/1.0\">\n"
+ " <paragraph sourcepos=\"1:1-2:7\">\n"
+ " <emph sourcepos=\"1:1-2:7\">\n"
+ " <text sourcepos=\"1:2-1:6\" xml:space=\"preserve\">first</text>\n"
+ " <softbreak />\n"
+ " <text sourcepos=\"2:1-2:6\" xml:space=\"preserve\">second</text>\n"
+ " </emph>\n"
+ " </paragraph>\n"
+ "</document>\n",
+ "sourcepos are as expected");
+ free(xml);
+ cmark_node_free(doc);
+ }
+ {
+ static const char markdown[] =
+ "` It is one backtick\n"
+ "`` They are two backticks\n";
+
+ cmark_node *doc = cmark_parse_document(markdown, sizeof(markdown) - 1, CMARK_OPT_DEFAULT);
+ char *xml = cmark_render_xml(doc, CMARK_OPT_DEFAULT | CMARK_OPT_SOURCEPOS);
+ STR_EQ(runner, xml, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<!DOCTYPE document SYSTEM \"CommonMark.dtd\">\n"
+ "<document sourcepos=\"1:1-2:25\" xmlns=\"http://commonmark.org/xml/1.0\">\n"
+ " <paragraph sourcepos=\"1:1-2:25\">\n"
+ " <text sourcepos=\"1:1-1:20\" xml:space=\"preserve\">` It is one backtick</text>\n"
+ " <softbreak />\n"
+ " <text sourcepos=\"2:1-2:25\" xml:space=\"preserve\">`` They are two backticks</text>\n"
+ " </paragraph>\n"
+ "</document>\n",
+ "sourcepos are as expected");
+ free(xml);
+ cmark_node_free(doc);
+ }
+}
+
+static void ref_source_pos(test_batch_runner *runner) {
+ static const char markdown[] =
+ "Let's try [reference] links.\n"
+ "\n"
+ "[reference]: https://github.com (GitHub)\n";
+
+ cmark_node *doc = cmark_parse_document(markdown, sizeof(markdown) - 1, CMARK_OPT_DEFAULT);
+ char *xml = cmark_render_xml(doc, CMARK_OPT_DEFAULT | CMARK_OPT_SOURCEPOS);
+ STR_EQ(runner, xml, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<!DOCTYPE document SYSTEM \"CommonMark.dtd\">\n"
+ "<document sourcepos=\"1:1-3:40\" xmlns=\"http://commonmark.org/xml/1.0\">\n"
+ " <paragraph sourcepos=\"1:1-1:28\">\n"
+ " <text sourcepos=\"1:1-1:10\" xml:space=\"preserve\">Let's try </text>\n"
+ " <link sourcepos=\"1:11-1:21\" destination=\"https://github.com\" title=\"GitHub\">\n"
+ " <text sourcepos=\"1:12-1:20\" xml:space=\"preserve\">reference</text>\n"
+ " </link>\n"
+ " <text sourcepos=\"1:22-1:28\" xml:space=\"preserve\"> links.</text>\n"
+ " </paragraph>\n"
+ "</document>\n",
+ "sourcepos are as expected");
+ free(xml);
+ cmark_node_free(doc);
+}
+
+int main(void) {
+ int retval;
+ test_batch_runner *runner = test_batch_runner_new();
+
+ version(runner);
+ constructor(runner);
+ classifiers(runner);
+ accessors(runner);
+ free_parent(runner);
+ node_check(runner);
+ iterator(runner);
+ iterator_delete(runner);
+ create_tree(runner);
+ custom_nodes(runner);
+ hierarchy(runner);
+ parser(runner);
+ render_html(runner);
+ render_xml(runner);
+ render_man(runner);
+ render_latex(runner);
+ render_commonmark(runner);
+ utf8(runner);
+ line_endings(runner);
+ numeric_entities(runner);
+ test_cplusplus(runner);
+ test_safe(runner);
+ test_feed_across_line_ending(runner);
+ sub_document(runner);
+ source_pos(runner);
+ source_pos_inlines(runner);
+ ref_source_pos(runner);
+
+ test_print_summary(runner);
+ retval = test_ok(runner) ? 0 : 1;
+ free(runner);
+
+ return retval;
+}
diff --git a/cmark/bench/samples/block-bq-flat.md b/cmark/bench/samples/block-bq-flat.md
new file mode 100644
index 0000000000..33e382afc3
--- /dev/null
+++ b/cmark/bench/samples/block-bq-flat.md
@@ -0,0 +1,16 @@
+> the simple example of a blockquote
+> the simple example of a blockquote
+> the simple example of a blockquote
+> the simple example of a blockquote
+... continuation
+... continuation
+... continuation
+... continuation
+
+empty blockquote:
+
+>
+>
+>
+>
+
diff --git a/cmark/bench/samples/block-bq-nested.md b/cmark/bench/samples/block-bq-nested.md
new file mode 100644
index 0000000000..7ddcffa400
--- /dev/null
+++ b/cmark/bench/samples/block-bq-nested.md
@@ -0,0 +1,13 @@
+>>>>>> deeply nested blockquote
+>>>>> deeply nested blockquote
+>>>> deeply nested blockquote
+>>> deeply nested blockquote
+>> deeply nested blockquote
+> deeply nested blockquote
+
+> deeply nested blockquote
+>> deeply nested blockquote
+>>> deeply nested blockquote
+>>>> deeply nested blockquote
+>>>>> deeply nested blockquote
+>>>>>> deeply nested blockquote
diff --git a/cmark/bench/samples/block-code.md b/cmark/bench/samples/block-code.md
new file mode 100644
index 0000000000..2b1554f427
--- /dev/null
+++ b/cmark/bench/samples/block-code.md
@@ -0,0 +1,11 @@
+
+ an
+ example
+
+ of
+
+
+
+ a code
+ block
+
diff --git a/cmark/bench/samples/block-fences.md b/cmark/bench/samples/block-fences.md
new file mode 100644
index 0000000000..5fe8b3c340
--- /dev/null
+++ b/cmark/bench/samples/block-fences.md
@@ -0,0 +1,14 @@
+
+``````````text
+an
+example
+```
+of
+
+
+a fenced
+```
+code
+block
+``````````
+
diff --git a/cmark/bench/samples/block-heading.md b/cmark/bench/samples/block-heading.md
new file mode 100644
index 0000000000..fd98558797
--- /dev/null
+++ b/cmark/bench/samples/block-heading.md
@@ -0,0 +1,9 @@
+# heading
+### heading
+##### heading
+
+# heading #
+### heading ###
+##### heading \#\#\#\#\######
+
+############ not a heading
diff --git a/cmark/bench/samples/block-hr.md b/cmark/bench/samples/block-hr.md
new file mode 100644
index 0000000000..e1bad6f4dd
--- /dev/null
+++ b/cmark/bench/samples/block-hr.md
@@ -0,0 +1,10 @@
+
+ * * * * *
+
+ - - - - -
+
+ ________
+
+
+ ************************* text
+
diff --git a/cmark/bench/samples/block-html.md b/cmark/bench/samples/block-html.md
new file mode 100644
index 0000000000..ff7f8fa6a0
--- /dev/null
+++ b/cmark/bench/samples/block-html.md
@@ -0,0 +1,32 @@
+<div class="this is an html block">
+
+blah blah
+
+</div>
+
+<table>
+ <tr>
+ <td>
+ **test**
+ </td>
+ </tr>
+</table>
+
+<table>
+
+ <tr>
+
+ <td>
+
+ test
+
+ </td>
+
+ </tr>
+
+</table>
+
+<![CDATA[
+ [[[[[[[[[[[... *cdata section - this should not be parsed* ...]]]]]]]]]]]
+]]>
+
diff --git a/cmark/bench/samples/block-lheading.md b/cmark/bench/samples/block-lheading.md
new file mode 100644
index 0000000000..e5c0d99d4f
--- /dev/null
+++ b/cmark/bench/samples/block-lheading.md
@@ -0,0 +1,8 @@
+heading
+---
+
+heading
+===================================
+
+not a heading
+----------------------------------- text
diff --git a/cmark/bench/samples/block-list-flat.md b/cmark/bench/samples/block-list-flat.md
new file mode 100644
index 0000000000..14149dbf33
--- /dev/null
+++ b/cmark/bench/samples/block-list-flat.md
@@ -0,0 +1,67 @@
+ - tidy
+ - bullet
+ - list
+
+
+ - loose
+
+ - bullet
+
+ - list
+
+
+ 0. ordered
+ 1. list
+ 2. example
+
+
+ -
+ -
+ -
+ -
+
+
+ 1.
+ 2.
+ 3.
+
+
+ - an example
+of a list item
+ with a continuation
+
+ this part is inside the list
+
+ this part is just a paragraph
+
+
+ 1. test
+ - test
+ 1. test
+ - test
+
+
+111111111111111111111111111111111111111111. is this a valid bullet?
+
+ - _________________________
+
+ - this
+ - is
+
+ a
+
+ long
+ - loose
+ - list
+
+ - with
+ - some
+
+ tidy
+
+ - list
+ - items
+ - in
+
+ - between
+ - _________________________
diff --git a/cmark/bench/samples/block-list-nested.md b/cmark/bench/samples/block-list-nested.md
new file mode 100644
index 0000000000..d30aed3b88
--- /dev/null
+++ b/cmark/bench/samples/block-list-nested.md
@@ -0,0 +1,36 @@
+
+ - this
+ - is
+ - a
+ - deeply
+ - nested
+ - bullet
+ - list
+
+
+ 1. this
+ 2. is
+ 3. a
+ 4. deeply
+ 5. nested
+ 6. unordered
+ 7. list
+
+
+ - 1
+ - 2
+ - 3
+ - 4
+ - 5
+ - 6
+ - 7
+ - 6
+ - 5
+ - 4
+ - 3
+ - 2
+ - 1
+
+
+ - - - - - - - - - deeply-nested one-element item
+
diff --git a/cmark/bench/samples/block-ref-flat.md b/cmark/bench/samples/block-ref-flat.md
new file mode 100644
index 0000000000..c83dccb6f1
--- /dev/null
+++ b/cmark/bench/samples/block-ref-flat.md
@@ -0,0 +1,15 @@
+[1] [2] [3] [1] [2] [3]
+
+[looooooooooooooooooooooooooooooooooooooooooooooooooong label]
+
+ [1]: <http://something.example.com/foo/bar>
+ [2]: http://something.example.com/foo/bar 'test'
+ [3]:
+ http://foo/bar
+ [ looooooooooooooooooooooooooooooooooooooooooooooooooong label ]:
+ 111
+ 'test'
+ [[[[[[[[[[[[[[[[[[[[ this should not slow down anything ]]]]]]]]]]]]]]]]]]]]: q
+ (as long as it is not referenced anywhere)
+
+ [[[[[[[[[[[[[[[[[[[[]: this is not a valid reference
diff --git a/cmark/bench/samples/block-ref-nested.md b/cmark/bench/samples/block-ref-nested.md
new file mode 100644
index 0000000000..1e10a8c213
--- /dev/null
+++ b/cmark/bench/samples/block-ref-nested.md
@@ -0,0 +1,17 @@
+[[[[[[[foo]]]]]]]
+
+[[[[[[[foo]]]]]]]: bar
+[[[[[[foo]]]]]]: bar
+[[[[[foo]]]]]: bar
+[[[[foo]]]]: bar
+[[[foo]]]: bar
+[[foo]]: bar
+[foo]: bar
+
+[*[*[*[*[foo]*]*]*]*]
+
+[*[*[*[*[foo]*]*]*]*]: bar
+[*[*[*[foo]*]*]*]: bar
+[*[*[foo]*]*]: bar
+[*[foo]*]: bar
+[foo]: bar
diff --git a/cmark/bench/samples/inline-autolink.md b/cmark/bench/samples/inline-autolink.md
new file mode 100644
index 0000000000..0f71482d6b
--- /dev/null
+++ b/cmark/bench/samples/inline-autolink.md
@@ -0,0 +1,14 @@
+closed (valid) autolinks:
+
+ <ftp://1.2.3.4:21/path/foo>
+ <http://foo.bar.baz?q=hello&id=22&boolean>
+ <http://veeeeeeeeeeeeeeeeeeery.loooooooooooooooooooooooooooooooong.autolink/>
+ <teeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeest@gmail.com>
+
+these are not autolinks:
+
+ <ftp://1.2.3.4:21/path/foo
+ <http://foo.bar.baz?q=hello&id=22&boolean
+ <http://veeeeeeeeeeeeeeeeeeery.loooooooooooooooooooooooooooooooong.autolink
+ <teeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeest@gmail.com
+ < http://foo.bar.baz?q=hello&id=22&boolean >
diff --git a/cmark/bench/samples/inline-backticks.md b/cmark/bench/samples/inline-backticks.md
new file mode 100644
index 0000000000..a6ec6e1fb0
--- /dev/null
+++ b/cmark/bench/samples/inline-backticks.md
@@ -0,0 +1,3 @@
+`lots`of`backticks`
+
+``i``wonder``how``this``will``be``parsed``
diff --git a/cmark/bench/samples/inline-em-flat.md b/cmark/bench/samples/inline-em-flat.md
new file mode 100644
index 0000000000..b7668a54ee
--- /dev/null
+++ b/cmark/bench/samples/inline-em-flat.md
@@ -0,0 +1,5 @@
+*this* *is* *your* *basic* *boring* *emphasis*
+
+_this_ _is_ _your_ _basic_ _boring_ _emphasis_
+
+**this** **is** **your** **basic** **boring** **emphasis**
diff --git a/cmark/bench/samples/inline-em-nested.md b/cmark/bench/samples/inline-em-nested.md
new file mode 100644
index 0000000000..6bb0a0d3bd
--- /dev/null
+++ b/cmark/bench/samples/inline-em-nested.md
@@ -0,0 +1,5 @@
+*this *is *a *bunch* of* nested* emphases*
+
+__this __is __a __bunch__ of__ nested__ emphases__
+
+***this ***is ***a ***bunch*** of*** nested*** emphases***
diff --git a/cmark/bench/samples/inline-em-worst.md b/cmark/bench/samples/inline-em-worst.md
new file mode 100644
index 0000000000..b6d21da984
--- /dev/null
+++ b/cmark/bench/samples/inline-em-worst.md
@@ -0,0 +1,5 @@
+*this *is *a *worst *case *for *em *backtracking
+
+__this __is __a __worst __case __for __em __backtracking
+
+***this ***is ***a ***worst ***case ***for ***em ***backtracking
diff --git a/cmark/bench/samples/inline-entity.md b/cmark/bench/samples/inline-entity.md
new file mode 100644
index 0000000000..da095edbf2
--- /dev/null
+++ b/cmark/bench/samples/inline-entity.md
@@ -0,0 +1,11 @@
+entities:
+
+&nbsp; &amp; &copy; &AElig; &Dcaron; &frac34; &HilbertSpace; &DifferentialD; &ClockwiseContourIntegral;
+
+&#35; &#1234; &#992; &#98765432;
+
+non-entities:
+
+&18900987654321234567890; &1234567890098765432123456789009876543212345678987654;
+
+&qwertyuioppoiuytrewqwer; &oiuytrewqwertyuioiuytrewqwertyuioytrewqwertyuiiuytri;
diff --git a/cmark/bench/samples/inline-escape.md b/cmark/bench/samples/inline-escape.md
new file mode 100644
index 0000000000..4e1bb396be
--- /dev/null
+++ b/cmark/bench/samples/inline-escape.md
@@ -0,0 +1,15 @@
+
+\t\e\s\t\i\n\g \e\s\c\a\p\e \s\e\q\u\e\n\c\e\s
+
+\!\\\"\#\$\%\&\'\(\)\*\+\,\.\/\:\;\<\=\>\?
+
+\@ \[ \] \^ \_ \` \{ \| \} \~ \- \'
+
+\
+\\
+\\\
+\\\\
+\\\\\
+
+\<this\> \<is\> \<not\> \<html\>
+
diff --git a/cmark/bench/samples/inline-html.md b/cmark/bench/samples/inline-html.md
new file mode 100644
index 0000000000..f6e63419e8
--- /dev/null
+++ b/cmark/bench/samples/inline-html.md
@@ -0,0 +1,44 @@
+Taking commonmark tests from the spec for benchmarking here:
+
+<a><bab><c2c>
+
+<a/><b2/>
+
+<a /><b2
+data="foo" >
+
+<a foo="bar" bam = 'baz <em>"</em>'
+_boolean zoop:33=zoop:33 />
+
+<33> <__>
+
+<a h*#ref="hi">
+
+<a href="hi'> <a href=hi'>
+
+< a><
+foo><bar/ >
+
+<a href='bar'title=title>
+
+</a>
+</foo >
+
+</a href="foo">
+
+foo <!-- this is a
+comment - with hyphen -->
+
+foo <!-- not a comment -- two hyphens -->
+
+foo <?php echo $a; ?>
+
+foo <!ELEMENT br EMPTY>
+
+foo <![CDATA[>&<]]>
+
+<a href="&ouml;">
+
+<a href="\*">
+
+<a href="\"">
diff --git a/cmark/bench/samples/inline-links-flat.md b/cmark/bench/samples/inline-links-flat.md
new file mode 100644
index 0000000000..5117db8794
--- /dev/null
+++ b/cmark/bench/samples/inline-links-flat.md
@@ -0,0 +1,23 @@
+Valid links:
+
+ [this is a link]()
+ [this is a link](<http://something.example.com/foo/bar>)
+ [this is a link](http://something.example.com/foo/bar 'test')
+ ![this is an image]()
+ ![this is an image](<http://something.example.com/foo/bar>)
+ ![this is an image](http://something.example.com/foo/bar 'test')
+
+ [escape test](<\>\>\>\>\>\>\>\>\>\>\>\>\>\>> '\'\'\'\'\'\'\'\'\'\'\'\'\'\'')
+ [escape test \]\]\]\]\]\]\]\]\]\]\]\]\]\]\]\]](\)\)\)\)\)\)\)\)\)\)\)\)\)\))
+
+Invalid links:
+
+ [this is not a link
+
+ [this is not a link](
+
+ [this is not a link](http://something.example.com/foo/bar 'test'
+
+ [this is not a link](((((((((((((((((((((((((((((((((((((((((((((((
+
+ [this is not a link]((((((((((()))))))))) (((((((((()))))))))))
diff --git a/cmark/bench/samples/inline-links-nested.md b/cmark/bench/samples/inline-links-nested.md
new file mode 100644
index 0000000000..4e7dc8579e
--- /dev/null
+++ b/cmark/bench/samples/inline-links-nested.md
@@ -0,0 +1,13 @@
+Valid links:
+
+[[[[[[[[](test)](test)](test)](test)](test)](test)](test)]
+
+[ [[[[[[[[[[[[[[[[[[ [](test) ]]]]]]]]]]]]]]]]]] ](test)
+
+Invalid links:
+
+[[[[[[[[[
+
+[ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [
+
+![![![![![![![![![![![![![![![![![![![![![![![![![![![![![![![![![![![![![![
diff --git a/cmark/bench/samples/inline-newlines.md b/cmark/bench/samples/inline-newlines.md
new file mode 100644
index 0000000000..068a807d91
--- /dev/null
+++ b/cmark/bench/samples/inline-newlines.md
@@ -0,0 +1,24 @@
+
+this\
+should\
+be\
+separated\
+by\
+newlines
+
+this
+should
+be
+separated
+by
+newlines
+too
+
+this
+should
+not
+be
+separated
+by
+newlines
+
diff --git a/cmark/bench/samples/lorem1.md b/cmark/bench/samples/lorem1.md
new file mode 100644
index 0000000000..eccb898b66
--- /dev/null
+++ b/cmark/bench/samples/lorem1.md
@@ -0,0 +1,13 @@
+Lorem ipsum dolor sit amet, __consectetur__ adipiscing elit. Cras imperdiet nec erat ac condimentum. Nulla vel rutrum ligula. Sed hendrerit interdum orci a posuere. Vivamus ut velit aliquet, mollis purus eget, iaculis nisl. Proin posuere malesuada ante. Proin auctor orci eros, ac molestie lorem dictum nec. Vestibulum sit amet erat est. Morbi luctus sed elit ac luctus. Proin blandit, enim vitae egestas posuere, neque elit ultricies dui, vel mattis nibh enim ac lorem. Maecenas molestie nisl sit amet velit dictum lobortis. Aliquam erat volutpat.
+
+Vivamus sagittis, diam in [vehicula](https://github.com/markdown-it/markdown-it) lobortis, sapien arcu mattis erat, vel aliquet sem urna et risus. Ut feugiat sapien vitae mi elementum laoreet. Suspendisse potenti. Aliquam erat nisl, aliquam pretium libero aliquet, sagittis eleifend nunc. In hac habitasse platea dictumst. Integer turpis augue, tincidunt dignissim mauris id, rhoncus dapibus purus. Maecenas et enim odio. Nullam massa metus, varius quis vehicula sed, pharetra mollis erat. In quis viverra velit. Vivamus placerat, est nec hendrerit varius, enim dui hendrerit magna, ut pulvinar nibh lorem vel lacus. Mauris a orci iaculis, hendrerit eros sed, gravida leo. In dictum mauris vel augue varius, ac ullamcorper nisl ornare. In eu posuere velit, ac fermentum arcu. Interdum et malesuada fames ac ante ipsum primis in faucibus. Nullam sed malesuada leo, at interdum elit.
+
+Nullam ut tincidunt nunc. [Pellentesque][1] metus lacus, commodo eget justo ut, rutrum varius nunc. Sed non rhoncus risus. Morbi sodales gravida pulvinar. Duis malesuada, odio volutpat elementum vulputate, massa magna scelerisque ante, et accumsan tellus nunc in sem. Donec mattis arcu et velit aliquet, non sagittis justo vestibulum. Suspendisse volutpat felis lectus, nec consequat ipsum mattis id. Donec dapibus vehicula facilisis. In tincidunt mi nisi, nec faucibus tortor euismod nec. Suspendisse ante ligula, aliquet vitae libero eu, vulputate dapibus libero. Sed bibendum, sapien at posuere interdum, libero est sollicitudin magna, ac gravida tellus purus eu ipsum. Proin ut quam arcu.
+
+Suspendisse potenti. Donec ante velit, ornare at augue quis, tristique laoreet sem. Etiam in ipsum elit. Nullam cursus dolor sit amet nulla feugiat tristique. Phasellus ac tellus tincidunt, imperdiet purus eget, ullamcorper ipsum. Cras eu tincidunt sem. Nullam sed dapibus magna. Lorem ipsum dolor sit amet, consectetur adipiscing elit. In id venenatis tortor. In consectetur sollicitudin pharetra. Etiam convallis nisi nunc, et aliquam turpis viverra sit amet. Maecenas faucibus sodales tortor. Suspendisse lobortis mi eu leo viverra volutpat. Pellentesque velit ante, vehicula sodales congue ut, elementum a urna. Cras tempor, ipsum eget luctus rhoncus, arcu ligula fermentum urna, vulputate pharetra enim enim non libero.
+
+Proin diam quam, elementum in eleifend id, elementum et metus. Cras in justo consequat justo semper ultrices. Sed dignissim lectus a ante mollis, nec vulputate ante molestie. Proin in porta nunc. Etiam pulvinar turpis sed velit porttitor, vel adipiscing velit fringilla. Cras ac tellus vitae purus pharetra tincidunt. Sed cursus aliquet aliquet. Cras eleifend commodo malesuada. In turpis turpis, ullamcorper ut tincidunt a, ullamcorper a nunc. Etiam luctus tellus ac dapibus gravida. Ut nec lacus laoreet neque ullamcorper volutpat.
+
+Nunc et leo erat. Aenean mattis ultrices lorem, eget adipiscing dolor ultricies eu. In hac habitasse platea dictumst. Vivamus cursus feugiat sapien quis aliquam. Mauris quam libero, porta vel volutpat ut, blandit a purus. Vivamus vestibulum dui vel tortor molestie, sit amet feugiat sem commodo. Nulla facilisi. Sed molestie arcu eget tellus vestibulum tristique.
+
+[1]: https://github.com/markdown-it
diff --git a/cmark/bench/samples/rawtabs.md b/cmark/bench/samples/rawtabs.md
new file mode 100644
index 0000000000..dc989ea75e
--- /dev/null
+++ b/cmark/bench/samples/rawtabs.md
@@ -0,0 +1,18 @@
+
+this is a test for tab expansion, be careful not to replace them with spaces
+
+1 4444
+22 333
+333 22
+4444 1
+
+
+ tab-indented line
+ space-indented line
+ tab-indented line
+
+
+a lot of spaces in between here
+
+a lot of tabs in between here
+
diff --git a/cmark/bench/statistics.py b/cmark/bench/statistics.py
new file mode 100644
index 0000000000..25a26d4aa7
--- /dev/null
+++ b/cmark/bench/statistics.py
@@ -0,0 +1,595 @@
+## Module statistics.py
+##
+## Copyright (c) 2013 Steven D'Aprano <steve+python@pearwood.info>.
+##
+## Licensed under the Apache License, Version 2.0 (the "License");
+## you may not use this file except in compliance with the License.
+## You may obtain a copy of the License at
+##
+## http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing, software
+## distributed under the License is distributed on an "AS IS" BASIS,
+## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+## See the License for the specific language governing permissions and
+## limitations under the License.
+
+
+"""
+Basic statistics module.
+
+This module provides functions for calculating statistics of data, including
+averages, variance, and standard deviation.
+
+Calculating averages
+--------------------
+
+================== =============================================
+Function Description
+================== =============================================
+mean Arithmetic mean (average) of data.
+median Median (middle value) of data.
+median_low Low median of data.
+median_high High median of data.
+median_grouped Median, or 50th percentile, of grouped data.
+mode Mode (most common value) of data.
+================== =============================================
+
+Calculate the arithmetic mean ("the average") of data:
+
+>>> mean([-1.0, 2.5, 3.25, 5.75])
+2.625
+
+
+Calculate the standard median of discrete data:
+
+>>> median([2, 3, 4, 5])
+3.5
+
+
+Calculate the median, or 50th percentile, of data grouped into class intervals
+centred on the data values provided. E.g. if your data points are rounded to
+the nearest whole number:
+
+>>> median_grouped([2, 2, 3, 3, 3, 4]) #doctest: +ELLIPSIS
+2.8333333333...
+
+This should be interpreted in this way: you have two data points in the class
+interval 1.5-2.5, three data points in the class interval 2.5-3.5, and one in
+the class interval 3.5-4.5. The median of these data points is 2.8333...
+
+
+Calculating variability or spread
+---------------------------------
+
+================== =============================================
+Function Description
+================== =============================================
+pvariance Population variance of data.
+variance Sample variance of data.
+pstdev Population standard deviation of data.
+stdev Sample standard deviation of data.
+================== =============================================
+
+Calculate the standard deviation of sample data:
+
+>>> stdev([2.5, 3.25, 5.5, 11.25, 11.75]) #doctest: +ELLIPSIS
+4.38961843444...
+
+If you have previously calculated the mean, you can pass it as the optional
+second argument to the four "spread" functions to avoid recalculating it:
+
+>>> data = [1, 2, 2, 4, 4, 4, 5, 6]
+>>> mu = mean(data)
+>>> pvariance(data, mu)
+2.5
+
+
+Exceptions
+----------
+
+A single exception is defined: StatisticsError is a subclass of ValueError.
+
+"""
+
+__all__ = [ 'StatisticsError',
+ 'pstdev', 'pvariance', 'stdev', 'variance',
+ 'median', 'median_low', 'median_high', 'median_grouped',
+ 'mean', 'mode',
+ ]
+
+
+import collections
+import math
+
+from fractions import Fraction
+from decimal import Decimal
+
+
+# === Exceptions ===
+
+class StatisticsError(ValueError):
+ pass
+
+
+# === Private utilities ===
+
+def _sum(data, start=0):
+ """_sum(data [, start]) -> value
+
+ Return a high-precision sum of the given numeric data. If optional
+ argument ``start`` is given, it is added to the total. If ``data`` is
+ empty, ``start`` (defaulting to 0) is returned.
+
+
+ Examples
+ --------
+
+ >>> _sum([3, 2.25, 4.5, -0.5, 1.0], 0.75)
+ 11.0
+
+ Some sources of round-off error will be avoided:
+
+ >>> _sum([1e50, 1, -1e50] * 1000) # Built-in sum returns zero.
+ 1000.0
+
+ Fractions and Decimals are also supported:
+
+ >>> from fractions import Fraction as F
+ >>> _sum([F(2, 3), F(7, 5), F(1, 4), F(5, 6)])
+ Fraction(63, 20)
+
+ >>> from decimal import Decimal as D
+ >>> data = [D("0.1375"), D("0.2108"), D("0.3061"), D("0.0419")]
+ >>> _sum(data)
+ Decimal('0.6963')
+
+ Mixed types are currently treated as an error, except that int is
+ allowed.
+ """
+ # We fail as soon as we reach a value that is not an int or the type of
+ # the first value which is not an int. E.g. _sum([int, int, float, int])
+ # is okay, but sum([int, int, float, Fraction]) is not.
+ allowed_types = set([int, type(start)])
+ n, d = _exact_ratio(start)
+ partials = {d: n} # map {denominator: sum of numerators}
+ # Micro-optimizations.
+ exact_ratio = _exact_ratio
+ partials_get = partials.get
+ # Add numerators for each denominator.
+ for x in data:
+ _check_type(type(x), allowed_types)
+ n, d = exact_ratio(x)
+ partials[d] = partials_get(d, 0) + n
+ # Find the expected result type. If allowed_types has only one item, it
+ # will be int; if it has two, use the one which isn't int.
+ assert len(allowed_types) in (1, 2)
+ if len(allowed_types) == 1:
+ assert allowed_types.pop() is int
+ T = int
+ else:
+ T = (allowed_types - set([int])).pop()
+ if None in partials:
+ assert issubclass(T, (float, Decimal))
+ assert not math.isfinite(partials[None])
+ return T(partials[None])
+ total = Fraction()
+ for d, n in sorted(partials.items()):
+ total += Fraction(n, d)
+ if issubclass(T, int):
+ assert total.denominator == 1
+ return T(total.numerator)
+ if issubclass(T, Decimal):
+ return T(total.numerator)/total.denominator
+ return T(total)
+
+
+def _check_type(T, allowed):
+ if T not in allowed:
+ if len(allowed) == 1:
+ allowed.add(T)
+ else:
+ types = ', '.join([t.__name__ for t in allowed] + [T.__name__])
+ raise TypeError("unsupported mixed types: %s" % types)
+
+
+def _exact_ratio(x):
+ """Convert Real number x exactly to (numerator, denominator) pair.
+
+ >>> _exact_ratio(0.25)
+ (1, 4)
+
+ x is expected to be an int, Fraction, Decimal or float.
+ """
+ try:
+ try:
+ # int, Fraction
+ return (x.numerator, x.denominator)
+ except AttributeError:
+ # float
+ try:
+ return x.as_integer_ratio()
+ except AttributeError:
+ # Decimal
+ try:
+ return _decimal_to_ratio(x)
+ except AttributeError:
+ msg = "can't convert type '{}' to numerator/denominator"
+ raise TypeError(msg.format(type(x).__name__)) from None
+ except (OverflowError, ValueError):
+ # INF or NAN
+ if __debug__:
+ # Decimal signalling NANs cannot be converted to float :-(
+ if isinstance(x, Decimal):
+ assert not x.is_finite()
+ else:
+ assert not math.isfinite(x)
+ return (x, None)
+
+
+# FIXME This is faster than Fraction.from_decimal, but still too slow.
+def _decimal_to_ratio(d):
+ """Convert Decimal d to exact integer ratio (numerator, denominator).
+
+ >>> from decimal import Decimal
+ >>> _decimal_to_ratio(Decimal("2.6"))
+ (26, 10)
+
+ """
+ sign, digits, exp = d.as_tuple()
+ if exp in ('F', 'n', 'N'): # INF, NAN, sNAN
+ assert not d.is_finite()
+ raise ValueError
+ num = 0
+ for digit in digits:
+ num = num*10 + digit
+ if exp < 0:
+ den = 10**-exp
+ else:
+ num *= 10**exp
+ den = 1
+ if sign:
+ num = -num
+ return (num, den)
+
+
+def _counts(data):
+ # Generate a table of sorted (value, frequency) pairs.
+ table = collections.Counter(iter(data)).most_common()
+ if not table:
+ return table
+ # Extract the values with the highest frequency.
+ maxfreq = table[0][1]
+ for i in range(1, len(table)):
+ if table[i][1] != maxfreq:
+ table = table[:i]
+ break
+ return table
+
+
+# === Measures of central tendency (averages) ===
+
+def mean(data):
+ """Return the sample arithmetic mean of data.
+
+ >>> mean([1, 2, 3, 4, 4])
+ 2.8
+
+ >>> from fractions import Fraction as F
+ >>> mean([F(3, 7), F(1, 21), F(5, 3), F(1, 3)])
+ Fraction(13, 21)
+
+ >>> from decimal import Decimal as D
+ >>> mean([D("0.5"), D("0.75"), D("0.625"), D("0.375")])
+ Decimal('0.5625')
+
+ If ``data`` is empty, StatisticsError will be raised.
+ """
+ if iter(data) is data:
+ data = list(data)
+ n = len(data)
+ if n < 1:
+ raise StatisticsError('mean requires at least one data point')
+ return _sum(data)/n
+
+
+# FIXME: investigate ways to calculate medians without sorting? Quickselect?
+def median(data):
+ """Return the median (middle value) of numeric data.
+
+ When the number of data points is odd, return the middle data point.
+ When the number of data points is even, the median is interpolated by
+ taking the average of the two middle values:
+
+ >>> median([1, 3, 5])
+ 3
+ >>> median([1, 3, 5, 7])
+ 4.0
+
+ """
+ data = sorted(data)
+ n = len(data)
+ if n == 0:
+ raise StatisticsError("no median for empty data")
+ if n%2 == 1:
+ return data[n//2]
+ else:
+ i = n//2
+ return (data[i - 1] + data[i])/2
+
+
+def median_low(data):
+ """Return the low median of numeric data.
+
+ When the number of data points is odd, the middle value is returned.
+ When it is even, the smaller of the two middle values is returned.
+
+ >>> median_low([1, 3, 5])
+ 3
+ >>> median_low([1, 3, 5, 7])
+ 3
+
+ """
+ data = sorted(data)
+ n = len(data)
+ if n == 0:
+ raise StatisticsError("no median for empty data")
+ if n%2 == 1:
+ return data[n//2]
+ else:
+ return data[n//2 - 1]
+
+
+def median_high(data):
+ """Return the high median of data.
+
+ When the number of data points is odd, the middle value is returned.
+ When it is even, the larger of the two middle values is returned.
+
+ >>> median_high([1, 3, 5])
+ 3
+ >>> median_high([1, 3, 5, 7])
+ 5
+
+ """
+ data = sorted(data)
+ n = len(data)
+ if n == 0:
+ raise StatisticsError("no median for empty data")
+ return data[n//2]
+
+
+def median_grouped(data, interval=1):
+ """"Return the 50th percentile (median) of grouped continuous data.
+
+ >>> median_grouped([1, 2, 2, 3, 4, 4, 4, 4, 4, 5])
+ 3.7
+ >>> median_grouped([52, 52, 53, 54])
+ 52.5
+
+ This calculates the median as the 50th percentile, and should be
+ used when your data is continuous and grouped. In the above example,
+ the values 1, 2, 3, etc. actually represent the midpoint of classes
+ 0.5-1.5, 1.5-2.5, 2.5-3.5, etc. The middle value falls somewhere in
+ class 3.5-4.5, and interpolation is used to estimate it.
+
+ Optional argument ``interval`` represents the class interval, and
+ defaults to 1. Changing the class interval naturally will change the
+ interpolated 50th percentile value:
+
+ >>> median_grouped([1, 3, 3, 5, 7], interval=1)
+ 3.25
+ >>> median_grouped([1, 3, 3, 5, 7], interval=2)
+ 3.5
+
+ This function does not check whether the data points are at least
+ ``interval`` apart.
+ """
+ data = sorted(data)
+ n = len(data)
+ if n == 0:
+ raise StatisticsError("no median for empty data")
+ elif n == 1:
+ return data[0]
+ # Find the value at the midpoint. Remember this corresponds to the
+ # centre of the class interval.
+ x = data[n//2]
+ for obj in (x, interval):
+ if isinstance(obj, (str, bytes)):
+ raise TypeError('expected number but got %r' % obj)
+ try:
+ L = x - interval/2 # The lower limit of the median interval.
+ except TypeError:
+ # Mixed type. For now we just coerce to float.
+ L = float(x) - float(interval)/2
+ cf = data.index(x) # Number of values below the median interval.
+ # FIXME The following line could be more efficient for big lists.
+ f = data.count(x) # Number of data points in the median interval.
+ return L + interval*(n/2 - cf)/f
+
+
+def mode(data):
+ """Return the most common data point from discrete or nominal data.
+
+ ``mode`` assumes discrete data, and returns a single value. This is the
+ standard treatment of the mode as commonly taught in schools:
+
+ >>> mode([1, 1, 2, 3, 3, 3, 3, 4])
+ 3
+
+ This also works with nominal (non-numeric) data:
+
+ >>> mode(["red", "blue", "blue", "red", "green", "red", "red"])
+ 'red'
+
+ If there is not exactly one most common value, ``mode`` will raise
+ StatisticsError.
+ """
+ # Generate a table of sorted (value, frequency) pairs.
+ table = _counts(data)
+ if len(table) == 1:
+ return table[0][0]
+ elif table:
+ raise StatisticsError(
+ 'no unique mode; found %d equally common values' % len(table)
+ )
+ else:
+ raise StatisticsError('no mode for empty data')
+
+
+# === Measures of spread ===
+
+# See http://mathworld.wolfram.com/Variance.html
+# http://mathworld.wolfram.com/SampleVariance.html
+# http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
+#
+# Under no circumstances use the so-called "computational formula for
+# variance", as that is only suitable for hand calculations with a small
+# amount of low-precision data. It has terrible numeric properties.
+#
+# See a comparison of three computational methods here:
+# http://www.johndcook.com/blog/2008/09/26/comparing-three-methods-of-computing-standard-deviation/
+
+def _ss(data, c=None):
+ """Return sum of square deviations of sequence data.
+
+ If ``c`` is None, the mean is calculated in one pass, and the deviations
+ from the mean are calculated in a second pass. Otherwise, deviations are
+ calculated from ``c`` as given. Use the second case with care, as it can
+ lead to garbage results.
+ """
+ if c is None:
+ c = mean(data)
+ ss = _sum((x-c)**2 for x in data)
+ # The following sum should mathematically equal zero, but due to rounding
+ # error may not.
+ ss -= _sum((x-c) for x in data)**2/len(data)
+ assert not ss < 0, 'negative sum of square deviations: %f' % ss
+ return ss
+
+
+def variance(data, xbar=None):
+ """Return the sample variance of data.
+
+ data should be an iterable of Real-valued numbers, with at least two
+ values. The optional argument xbar, if given, should be the mean of
+ the data. If it is missing or None, the mean is automatically calculated.
+
+ Use this function when your data is a sample from a population. To
+ calculate the variance from the entire population, see ``pvariance``.
+
+ Examples:
+
+ >>> data = [2.75, 1.75, 1.25, 0.25, 0.5, 1.25, 3.5]
+ >>> variance(data)
+ 1.3720238095238095
+
+ If you have already calculated the mean of your data, you can pass it as
+ the optional second argument ``xbar`` to avoid recalculating it:
+
+ >>> m = mean(data)
+ >>> variance(data, m)
+ 1.3720238095238095
+
+ This function does not check that ``xbar`` is actually the mean of
+ ``data``. Giving arbitrary values for ``xbar`` may lead to invalid or
+ impossible results.
+
+ Decimals and Fractions are supported:
+
+ >>> from decimal import Decimal as D
+ >>> variance([D("27.5"), D("30.25"), D("30.25"), D("34.5"), D("41.75")])
+ Decimal('31.01875')
+
+ >>> from fractions import Fraction as F
+ >>> variance([F(1, 6), F(1, 2), F(5, 3)])
+ Fraction(67, 108)
+
+ """
+ if iter(data) is data:
+ data = list(data)
+ n = len(data)
+ if n < 2:
+ raise StatisticsError('variance requires at least two data points')
+ ss = _ss(data, xbar)
+ return ss/(n-1)
+
+
+def pvariance(data, mu=None):
+ """Return the population variance of ``data``.
+
+ data should be an iterable of Real-valued numbers, with at least one
+ value. The optional argument mu, if given, should be the mean of
+ the data. If it is missing or None, the mean is automatically calculated.
+
+ Use this function to calculate the variance from the entire population.
+ To estimate the variance from a sample, the ``variance`` function is
+ usually a better choice.
+
+ Examples:
+
+ >>> data = [0.0, 0.25, 0.25, 1.25, 1.5, 1.75, 2.75, 3.25]
+ >>> pvariance(data)
+ 1.25
+
+ If you have already calculated the mean of the data, you can pass it as
+ the optional second argument to avoid recalculating it:
+
+ >>> mu = mean(data)
+ >>> pvariance(data, mu)
+ 1.25
+
+ This function does not check that ``mu`` is actually the mean of ``data``.
+ Giving arbitrary values for ``mu`` may lead to invalid or impossible
+ results.
+
+ Decimals and Fractions are supported:
+
+ >>> from decimal import Decimal as D
+ >>> pvariance([D("27.5"), D("30.25"), D("30.25"), D("34.5"), D("41.75")])
+ Decimal('24.815')
+
+ >>> from fractions import Fraction as F
+ >>> pvariance([F(1, 4), F(5, 4), F(1, 2)])
+ Fraction(13, 72)
+
+ """
+ if iter(data) is data:
+ data = list(data)
+ n = len(data)
+ if n < 1:
+ raise StatisticsError('pvariance requires at least one data point')
+ ss = _ss(data, mu)
+ return ss/n
+
+
+def stdev(data, xbar=None):
+ """Return the square root of the sample variance.
+
+ See ``variance`` for arguments and other details.
+
+ >>> stdev([1.5, 2.5, 2.5, 2.75, 3.25, 4.75])
+ 1.0810874155219827
+
+ """
+ var = variance(data, xbar)
+ try:
+ return var.sqrt()
+ except AttributeError:
+ return math.sqrt(var)
+
+
+def pstdev(data, mu=None):
+ """Return the square root of the population variance.
+
+ See ``pvariance`` for arguments and other details.
+
+ >>> pstdev([1.5, 2.5, 2.5, 2.75, 3.25, 4.75])
+ 0.986893273527251
+
+ """
+ var = pvariance(data, mu)
+ try:
+ return var.sqrt()
+ except AttributeError:
+ return math.sqrt(var)
diff --git a/cmark/bench/stats.py b/cmark/bench/stats.py
new file mode 100644
index 0000000000..c244b419f6
--- /dev/null
+++ b/cmark/bench/stats.py
@@ -0,0 +1,19 @@
+#!/usr/bin/env python3
+
+import sys
+import statistics
+
+def pairs(l, n):
+ return zip(*[l[i::n] for i in range(n)])
+
+# data comes in pairs:
+# n - time for running the program with no input
+# m - time for running it with the benchmark input
+# we measure (m - n)
+
+values = [ float(y) - float(x) for (x,y) in pairs(sys.stdin.readlines(),2)]
+
+print("mean = %.4f, median = %.4f, stdev = %.4f" %
+ (statistics.mean(values), statistics.median(values),
+ statistics.stdev(values)))
+
diff --git a/cmark/benchmarks.md b/cmark/benchmarks.md
new file mode 100644
index 0000000000..bb5e28ec0b
--- /dev/null
+++ b/cmark/benchmarks.md
@@ -0,0 +1,23 @@
+# Benchmarks
+
+Here are some benchmarks, run on a 2.3GHz 8-core i9 macbook pro.
+The input text is a 1106 KB Markdown file built by concatenating
+the Markdown sources of all the localizations of the first edition
+of [*Pro Git*](https://github.com/progit/progit/tree/master/en) by
+Scott Chacon.
+
+|Implementation | Time (sec)|
+|-------------------|-----------:|
+| **commonmark.js** | 0.59 |
+| **cmark** | 0.12 |
+| **md4c** | 0.04 |
+
+To run these benchmarks, use `make bench PROG=/path/to/program`.
+
+`time` is used to measure execution speed. The reported
+time is the *difference* between the time to run the program
+with the benchmark input and the time to run it with no input.
+(This procedure ensures that implementations in dynamic languages are
+not penalized by startup time.) A median of ten runs is taken. The
+process is reniced to a high priority so that the system doesn't
+interrupt runs.
diff --git a/cmark/changelog.txt b/cmark/changelog.txt
new file mode 100644
index 0000000000..3cb825bd9e
--- /dev/null
+++ b/cmark/changelog.txt
@@ -0,0 +1,1552 @@
+[0.31.2]
+
+ * Export `cmark_node_is_inline`, `cmark_node_is_block`,
+ `cmark_node_is_leaf` [non-breaking API change].
+
+ * Don't append a newline character when rendering inline nodes
+ (Samuel Williams).
+
+ * Fix inline source positions (#551, Nick Wellnhofer).
+ Account for partially removed delimiter chars.
+
+ * Commonmark renderer: fix bug with empty item at end of list (#583).
+
+ * Fix email autolink rendering in latex (#595).
+
+ * CMake: Remove handling CMP0063 (Christophh Grüninger).
+ Required CMake is 3.7 which automatically sets CMP0063 to NEW.
+
+ * Makefile: Don't depend on $(SPEC) (Nick Wellnhofer).
+ The spec file is always present.
+
+ * Makefile: Clean up cmake invocations (Nick Wellnhofer).
+ Use cmake command to build and install instead of invoking make. Also
+ use -G option consistently. This allows to use other generators like
+ Ninja: `make GENERATOR=Ninja`.
+
+ * Fix python warnings about regexp escape sequences
+ (Azamat H. Hackimov).
+
+ * Update cmake_minimum_required to 3.14 (Azamat H. Hackimov).
+
+ * Update to Unicode 17.0 (Dmitry Atamanov).
+
+ * README: Make cmake instructions more portable and simple
+ (Nick Wellnhofer). Don't assume that make is used. Don't
+ change directories.
+
+ * Replace link to unmaintained Python bindings (Ofek Lev).
+
+[0.31.1]
+
+ * Flag root node as open in `cmark_parser_new_with_mem_into_root` (#532).
+
+ * Remove `source`, add `search` to list of block tags
+ (a spec 0.31 change we forgot in last release).
+
+ * Accept lowercase inline HTML declarations (Michael Howell).
+
+ * Remove unused functions (Nick Wellnhofer).
+
+ * utf8:
+
+ + Fix encoding of U+FFFE and U+FFFF (#548, Nick Wellnhofer).
+ + Rework case folding (Nick Wellnhofer). Using a table and binary
+ search instead of a generated switch statement significantly
+ reduces the size of the compiled code.
+
+ * houdini:
+
+ + Rename `houdini_escape_html0` -> `houdini_escape_html` (#536).
+ + Rework HTML entity table (Nick Wellnhofer).
+ The new layout saves about 20 KB and removes 50 KB of relocation
+ entries from the shared library, also speeding up loading.
+
+ * cmake:
+
+ + Tell cmake to set `rpath` so the installed `cmark` can find
+ `libcmark.so` (Michael Witten).
+ + Remove unnecessary enabling of target property: MACOSX_RPATH
+ (Michael Witten).
+ + Fix build type checks (Nick Wellnhofer). Make the libFuzzer
+ target use the Asan build type again.
+
+ * Makefile:
+
+ + Fix `libFuzzer` target (Nick Wellnhofer).
+ + Use `ctest` and `--output-on-failure` in `test` target.
+ + `make debug` should build a shared library (Nick Wellnhofer).
+ The full test suite is only available to a shared library build.
+
+ * wrappers:
+
+ + Fix memory leak in Ruby wrapper (Nick Wellnhofer).
+ Free the string returned from `cmark_markdown_to_html`.
+ Fix `cmark_markdown_to_html` argument types.
+ + Fix memory leak in Python wrapper (Nick Wellnhofer).
+ Free the string returned from cmark_markdown_to_html.
+ Fix cmark_markdown_to_html argument types.
+ + Convert to and from UTF-8 under Python 2.
+ + Add PHP wraper (Vinicius Dias).
+
+ * ci:
+
+ + Test with ASan and rework CI matrix (Nick Wellnhofer).
+ + Remove the valgrind leakcheck test. This should be covered now
+ by testing with LeakSanitizer on static builds, including tests
+ like spectest_executable. The full test suite is only available
+ to shared library builds which have to run without leak checks
+ for now.
+ + Separate cflags from cc (Nick Wellnhofer).
+ + Make CMake matrix options work (Nick Wellnhofer).
+ CMAKE_OPTIONS had no effect, leading to the shared library not being
+ tested. Invoke cmake directly, so we don't have to deal with the mess
+ in Makefile.
+ + Do debug build so that assertions will run (#532).
+ + Use `-gdwarf-4` with clang for compatibility with valgrind (#532).
+
+ * test:
+
+ + Fix memory leaks in cmark.py (Nick Wellnhofer).
+ Free results of libcmark API function calls.
+ + Fix memory leaks in api_test (Nick Wellnhofer).
+ + Simplify test execution environment handling (Saleem Abdulrasool).
+ Use generator expressions to compute the new path and avoid
+ translations. This reduces complexity in the build and allows for a
+ different build layout.
+
+ * fuzz: Test more parser entry points (Nick Wellnhofer).
+
+ * Remove superfluous definitions from scanners.re.
+
+ * re2c: Disable UTF-8 (Nick Wellnhofer). The regexes don't require UTF-8
+ features and work in ASCII mode as well. Disabling UTF-8 reduces the
+ size of the code generated by re2c.
+
+[0.31.0]
+
+ * Update to 0.31.2 spec.txt.
+
+ * Treat unicode Symbols like Punctuation, as per the 0.31 spec.
+
+ * Add a new function to `utf8.h`:
+ `int cmark_utf8proc_is_punctuation_or_symbol(int32_t uc)`.
+ The old `cmark_utf8proc_is_punctuation` has been kept for
+ now, but it is no longer used.
+
+ * Add new exported function `cmark_parser_new_with_mem_into_root`
+ (API change) (John Ericson).
+
+ * Avoid repeated `language-` in info string (commonmark/commonmark.js#277).
+
+ * Fix quadratic behavior in `S_insert_emph` (Nick Wellnhofer).
+ Fixes part of GHSA-66g8-4hjf-77xh.
+
+ * Fix quadratic behavior in `check_open_blocks` (Nick Wellnhofer).
+ Fixes part of GHSA-66g8-4hjf-77xh.
+
+ * Track underscore bottom separately mod 3, like asterisk (Michael
+ Howell). This was already implemented correctly for asterisks,
+ but not for underscore.
+
+ * Use `fwrite` instead of `printf` to print results in main (#523).
+ This avoids a massive slowdown in MSYS2.
+
+ * commonmark writer: less aggressive escaping for `!` (#131).
+
+ * Update libFuzzer build (Nick Wellnhofer):
+
+ + Move fuzzing files into their own directory.
+ + Use libFuzzer the modern way by compiling and linking with
+ `-fsanitize=fuzzer(-no-link)` without requiring `LIB_FUZZER_PATH`.
+ + Update the `libFuzzer` rule in Makefile and the README.md.
+
+ * CMake build changes (Saleem Abdulrasool).
+
+ + Inline multiple variables in CMake, following CMake recommendations.
+ + Simplify the version computation.
+ + Remove the `CMARK_STATIC` and `CMARK_SHARED` options as one of the two
+ must be enabled always as the cmark executable depends on the library.
+ Instead of having a custom flag to discern between the
+ library type, use the native CMake option `BUILD_SHARED_LIBS`,
+ allowing the user to control which library to build. This matches
+ CMake recommendations to only build a single copy of the library.
+ + Introduce an author warning for the use of `CMARK_SHARED` and
+ `CMARK_STATIC` to redirect the author of the dependent package to
+ `BUILD_SHARED_LIBS`.
+ + Permit incremental linking on Windows. Although incremental linking
+ does introduce padding in the binary for incremental links, that
+ should not matter for release mode builds in theory as `/OPT:REF`
+ and `/OPT:ICF` will trigger full links, which is the default in
+ release mode.
+ + Hoist the CMake module inclusion to the top level.
+ + Minor tweaks for speeding up the configure phase.
+ Restructure the file layout to place the custom modules into the
+ `cmake/modules` directory that is the common layout for CMake based
+ projects.
+ + Squelch C4232 warnings on MSVC builds.
+ + Remove check for `__builtin_expect`. Use `__has_builtin` to check
+ at compile time if the feature is supported.
+ This macro is supported by both clang and GCC (as of 10).
+ In the case that the compiler in use is not new enough, we still
+ provide the fallback so that the code will compile but without the
+ additional hints for the branch probability. `config.h` has been
+ removed from the code base as it is no longer needed.
+ + Remove `/TP` usage on MSVC and replace `CMARK_INLINE` with `inline`.
+ These were workarounds for pre-VS2015 compilers, which are no longer
+ supported.
+ + Hoist the C visibility settings to top level
+ + Clean up C4267 warnings on MSVC builds.
+ + Remove some compiler compatibility checks that are no longer
+ needed because VS 2013 is no longer supported (#498).
+ + Adjust the policy to silence warnings on MSVC builds
+ CMake 3.15+ remove `/W3` from the language flags under MSVC with
+ CMP0092. Set the policy to new to avoid the D9025 warning.
+ + Reflow some text to match CMake documentation style
+ + Use generator expression for path computation.
+ + Use CMake to propagate `CMARK_STATIC_DEFINE`.
+ + Clean up an obsoleted variable (NFC).
+ + Hoist the policy settings. Policy settings may impact how
+ `project` functions. They should be set immediately after
+ `cmake_minimum_required` (which implicitly sets policies).
+ Use the `POLICY` check to see if a policy is defined rather
+ than using a version check.
+ + Replace `CMARK_TESTS` with CMake sanctioned `BUILD_TESTING`.
+ + Correct typo and adjust command invocation. Use the proper
+ generator expression for the python interpreter and adjust
+ a typo in the component name.
+ + Add an upgrade path for newer CMake.
+ CMake 3.12 deprecated `FindPythonInterp`, and with CMake 3.27, were
+ obsoleted with CMP0148. Add a version check and switch to the new
+ behaviour to allow building with newer releases.
+
+ * Fix regex syntax warnings in `pathological_tests.py` (Nick Wellnhofer).
+
+ * `test/cmark.py`: avoid star imports (Jakub Wilk).
+
+ * `spec_tests.py`: Add option to generate fuzz corpus (Nick Wellnhofer).
+ Add an option `--fuzz-corpus` that writes the test cases to separate
+ files including the options header, so they can be used as seed corpus
+ for fuzz testing.
+
+ * Fix some cmark.3 man rendering issues so we can do a clean regen
+ (John Ericson).
+
+ * Update Windows compilation instructions (Pomax, #525).
+
+[0.30.3]
+
+ * Fix quadratic complexity bug with repeated `![[]()`.
+ Resolves CVE-2023-22486. Add new pathological test. (John MacFarlane)
+
+ * Allow declarations with no space, as per spec (#456, John MacFarlane).
+
+ * Set `enumi*` counter correctly in LaTeX output (#451, John MacFarlane).
+
+ * Allow `<!DOCTYPE` to be case-insensitive. (This conforms to the
+ existing spec.) (John MacFarlane)
+
+ * Fixed HTML comment scanning. Need to handle this case: `<!--> and -->`.
+ Since the scanner finds the longest match, we had to
+ move some of the logic outside of the scanner. (John MacFarlane)
+
+ * Fix quadratic parsing issue with repeated `<!--` (this was not
+ introduced by the previous fix, and not in a released version of cmark).
+ Resolves CVE-2023-22484. Add new pathological test. (John MacFarlane)
+
+ * Update HTML comment scanner to accord with commonmark/commonmark-spec#713
+ (John MacFarlane).
+
+ * Pathological tests: half the number of repetitions, and the timeout.
+ This reduces the time needed for the pathological tests.
+ (John MacFarlane)
+
+ * Shrink `struct cmark_node` (#446). The `internal_offset` member is
+ only used for headings and can be moved to `struct cmark_heading`.
+ This reduces the size of `struct cmark_node` from 112 to 104 bytes on
+ 64-bit systems. (Nick Wellnhofer)
+
+ * Add `-Wstrict-prototypes` and fix offending functions. (Nick
+ Wellnhofer, Dan Cîrnaț)
+
+ * Fix quadratic behavior involving `get_containing_block` (#431).
+ Instead of searching for the containing block, update the tight list
+ status when entering a child of a list item or exiting a list.
+ (Nick Wellnhofer)
+
+ * Fix `pathological_tests.py` (Nick Wellnhofer):
+ - Use a multiprocessing.Queue to actually get results from spawned
+ tests processes.
+ - Fix the `allowed_failures` test.
+ - Truncate actual output when printed.
+ - Prepare for testing pathological behavior of the Commonmark renderer.
+
+ * Fix source position bug with backticks (kyle).
+
+[0.30.2]
+
+ * Fix parsing of emphasis before links (#424, Nick Wellnhofer).
+ Fixes a regression introduced with commit ed0a4bf.
+
+ * Update to Unicode 14.0 (data-man).
+
+ * Add `~` to safe href character set (#394, frogtile).
+
+ * Update CMakeLists.txt (Saleem Abdulrasool). Bump the minimum required
+ CMake to 3.7. Imperatively define output name for static library.
+
+ * Fix install paths in libcmark.pc (Sebastián Mancilla).
+ `CMAKE_INSTALL_<dir>` can be relative or absolute path, so it is wrong to
+ prefix CMAKE_INSTALL_PREFIX because if CMAKE_INSTALL_<dir> is set to an
+ absolute path it will result in a malformed path with two absolute paths
+ joined together. Instead, use `CMAKE_INSTALL_FULL_<dir>` from
+ GNUInstallDirs.
+
+[0.30.1]
+
+ * Properly indent block-level contents of list items in man (#258).
+ This handles nested lists as well as items with multiple paragraphs.
+ The change requires addition of a new field block_number_in_list_item
+ to cmark_renderer, but this does not change the public API.
+ * Fix quadratic behavior when parsing emphasis (#389, Nick
+ Wellnhofer). Delimiters can be deleted, so store delimiter positions
+ instead of pointers in `openers_bottom`. Besides causing undefined
+ behavior when reading a dangling pointer, this could also result
+ in quadratic behavior when parsing emphasis.
+ * Fix quadratic behavior when parsing smart quotes (#388, Nick Wellnhofer).
+ Remove matching smart quote delimiters. Otherwise, the same opener
+ could be found over and over, preventing the `openers_bottom`
+ optimization from kicking in and leading to quadratic behavior when
+ processing lots of quotes.
+ * Modify CMake configuration so that the project can be built with
+ older versions of CMake (#384, Saleem Abdulrasool). (In 0.30.0,
+ some features were used that require CMake >= 3.3.) The cost of this
+ backwards compatibility is that developers must now explicitly invoke
+ `cmark_add_compile_options` when a new compilation target is added.
+ * Remove a comma at the end of an enumerator list, which was flagged
+ by clang as a C++11 extension.
+ * make_man_page.py: use absolute path with CDLL. This avoids the error
+ "file system relative paths not allowed in hardened programs."
+ * Include cmark version in cmark(3) man page (instead of LOCAL).
+
+[0.30.0]
+
+ * Use official 0.30 spec.txt.
+ * Add `cmark_get_default_mem_allocator()` (#330). API change: this
+ adds a new exported function in cmark.h.
+ * Fix #383. An optimization we used for emphasis parsing was
+ too aggressive, causing us to miss some emphasis that was legal
+ according to the spec. We fix this by indexing the `openers_bottom`
+ table not just by the type of delimiter and the length of the
+ closing delimiter mod 3, but by whether the closing delimiter
+ can also be an opener. (The algorithm for determining emphasis
+ matching depends on all these factors.) Add regression test.
+ * Fix quadratic behavior with inline HTML (#299, Nick Wellnhofer).
+ Repeated starting sequences like `<?`, `<!DECL ` or `<![CDATA[` could
+ lead to quadratic behavior if no matching ending sequence was found.
+ Separate the inline HTML scanners. Remember if scanning the whole input
+ for a specific ending sequence failed and skip subsequent scans.
+ * Speed up hierarchy check in tree manipulation API (Nick Wellnhofer).
+ Skip hierarchy check in the common case that the inserted child has
+ no children.
+ * Fix quadratic behavior when parsing inlines (#373, Nick Wellnhofer).
+ The inline parsing code would call `cmark_node_append_child` to append
+ nodes. This public function has a sanity check which is linear in the
+ depth of the tree. Repeated calls could show quadratic behavior in
+ degenerate trees. Use a special function to append nodes without this
+ check. (Issue found by OSS-Fuzz.)
+ * Replace invalid characters in XML output (#365, Nick wellnhofer).
+ Control characters, U+FFFE and U+FFFF aren't allowed in XML 1.0, so
+ replace them with U+FFFD (replacement character). This doesn't solve
+ the problem how to roundtrip these characters, but at least we don't
+ produce invalid XML.
+ * Avoid quadratic output growth with reference links (#354, Nick Wellnhofer).
+ Keep track of the number bytes added through expansion of reference
+ links and limit the total to the size of the input document. Always
+ allow a minimum of 100KB. Unfortunately, cmark has no error handling,
+ so all we can do is to stop expanding reference links without returning
+ an error. This should never be an issue in practice though. The 100KB
+ minimum alone should cover all real-world cases.
+ * Fix issue with type-7 HTML blocks interrupting paragraphs
+ (see commonmark/commonmark.js#213).
+ * Treat `textarea` like `script`, `style`, `pre` (type 1 HTML block),
+ in accordance with spec change.
+ * Define whitespace per spec (Asherah Conor).
+ * Add `MAX_INDENT` for xml (#355). Otherwise we can get quadratic
+ increase in size with deeply nested structures.
+ * Fix handling of empty strings when creating XML/HTML output
+ (Steffen Kieß).
+ * Commonmark renderer: always use fences for code (#317).
+ This solves problems with adjacent code blocks being merged.
+ * Improve rendering of commonmark code spans with spaces (#316).
+ * Cleaner approach to max digits for numeric entities.
+ This modifies unescaping in `houdini_html_u.c` rather than
+ the entity handling in `inlines.c`. Unlike the other,
+ this approach works also in e.g. link titles.
+ * Fix entity parser (and api test) to respect length limit on
+ numeric entities.
+ * Don't allow link destinations with unbalanced unescaped parentheses.
+ See commonmark/commonmark.js#177.
+ * `print_usage()`: Minor grammar fix, swap two words (#305, Øyvind A. Holm).
+ * Don't call `memcpy` with `NULL` as first parameter.
+ This is illegal according to the C standard, sec. 7.1.4.
+ See <https://www.imperialviolet.org/2016/06/26/nonnull.html>.
+ * Add needed include in `blocks.c`.
+ * Fix unnecessary variable assignment.
+ * Skip UTF-8 BOM if present at beginning of buffer (#334).
+ * Fix URL check in `is_autolink` (Nick Wellnhofer). In a recent commit,
+ the check was changed to `strcmp`, but we really have to use `strncmp`.
+ * Fix null pointer deref in `is_autolink` (Nick Wellnhofer).
+ Introduced by a recent commit. Found by OSS-Fuzz.
+ * Rearrange struct cmark_node (Nick Wellnhofer). Introduce multi-purpose
+ data/len members in struct cmark_node. This is mainly used to store
+ literal text for inlines, code and HTML blocks.
+ Move the content strbuf for blocks from `cmark_node` to `cmark_parser`.
+ When finalizing nodes that allow inlines (paragraphs and headings),
+ detach the strbuf and store the block content in the node's data/len
+ members. Free the block content after processing inlines.
+ Reduces size of struct `cmark_node` by 8 bytes.
+ * Improve packing of `struct cmark_list` (Nick Wellnhofer).
+ * Use C string instead of chunk in a number of contexts (Nick Wellnhofer,
+ #309). The node struct never references memory of other nodes now.
+ Node accessors don't have to check for delayed creation of C strings,
+ so parsing and iterating all literals using the public API should
+ actually be faster than before. These changes also reduce the size
+ of `struct cmark_node`.
+ * Add casts for MSVC10 (from kivikakk in cmark-cfm).
+ * commonmark renderer: better escaping in smart mode. When
+ `CMARK_OPT_SMART` is enabled, we escape literal `-`, `.`, and quote
+ characters when needed to avoid their being "smartified."
+ * Add options field to `cmark_renderer`.
+ * commonmark.c - use `size_t` instead of `int`.
+ * Include `string.h` in `cmark-fuzz.c`.
+ * Fix #220 (hash collisions for references) (Vicent Marti via cmark-gfm).
+ Reimplemented reference storage as follows:
+ 1. New references are always inserted at the end of a linked list. This
+ is an O(1) operation, and does not check whether an existing (duplicate)
+ reference with the same label already exists in the document.
+ 2. Upon the first call to `cmark_reference_lookup` (when it is expected
+ that no further references will be added to the reference map), the
+ linked list of references is written into a fixed-size array.
+ 3. The fixed size array can then be efficiently sorted in-place in O(n
+ log n). This operation only happens once. We perform this sort in a
+ _stable_ manner to ensure that the earliest link reference in the
+ document always has preference, as the spec dictates. To accomplish
+ this, every reference is tagged with a generation number when initially
+ inserted in the linked list.
+ 4. The sorted array is then compacted in O(n). Since it was sorted in a
+ stable way, the first reference for each label is preserved and the
+ duplicates are removed, matching the spec.
+ 5. We can now simply perform a binary search for the current
+ `cmark_reference_lookup` query in O(log n). Any further lookup calls
+ will also be O(log n), since the sorted references table only needs to
+ be generated once.
+ The resulting implementation is notably simple (as it uses standard
+ library builtins `qsort` and `bsearch`), whilst performing better than
+ the fixed size hash table in documents that have a high number of
+ references and never becoming pathological regardless of the input.
+ * Comment out unused function `cmark_strbuf_cstr` in `buffer.h`.
+ * Re-add `--safe` command-line option as a no-op (#344), for backwards
+ compatibility.
+ * Update to Unicode 13.0
+ * Generate and install cmake-config file (Reinhold Gschweicher).
+ Add full cmake support. The project can either be used with
+ `add_subdirectory` or be installed into the system (or some other
+ directory) and be found with `find_package(cmark)`. In both cases the
+ cmake target `cmark::cmark` and/or `cmark::cmark_static` is all that
+ is needed to be linked. Previously the `cmarkConfig.cmake` file
+ was generated, but not installed. As additional bonus of generation
+ by cmake we get a generated `cmake-config-version.cmake` file for
+ `find_package()` to search for the same major version.
+ The generated config file is position independent, allowing the
+ installed directory to be copied or moved and still work.
+ The following four files are generated and installed:
+ `lib/cmake/cmark/cmark-config.cmake`,
+ `lib/cmake/cmark/cmark-config-version.cmake`,
+ `lib/cmake/cmark/cmark-targets.cmake`,
+ `lib/cmake/cmark/cmark-targets-release.cmake`.
+ * Adjust the MinGW paths for MinGW64 (Daniil Baturin).
+ * Fix CMake generator expression checking for MSVC (Nick Wellnhofer).
+ * Fix `-Wconst-qual` warning (Saleem Abdulrasool). This enables building
+ with `/Zc:strictString` with MSVC as well.
+ * Improve and modernize cmake build (Saleem Abdulrasool).
+ + Build: add exports targets for build tree usage (#307).
+ + Uuse target properties for include paths.
+ + Remove the unnecessary execute permission on CMakeLists.txt.
+ + Reduce property computation in CMake.
+ + Use `CMAKE_INCLUDE_CURRENT_DIRECTORY`.
+ + Improve man page installation.
+ + Only include `GNUInstallDirs` once.
+ + Replace `add_compile_definitions` with `add_compile_options`
+ since the former was introduced in 3.12 (#321).
+ + Cleanup CMake (#319).
+ + Inline a variable.
+ + Use `LINKER_LANGUAGE` property for C++ runtime.
+ + Use CMake to control C standard.
+ + Use the correct variable.
+ + Loosen the compiler check
+ + Hoist shared flags to top-level CMakeLists
+ + Remove duplicated flags.
+ + Use `add_compile_options` rather than modify `CMAKE_C_FLAGS`.
+ + Hoist sanitizer flags to global state.
+ + Hoist `-fvisibilty` flags to top-level.
+ + Hoist the debug flag handling.
+ + Hoist the profile flag handling.
+ + Remove incorrect variable handling.
+ + Remove unused CMake includes.
+ * Remove "-rdynamic" flag for static builds (#300, Eric Pruitt).
+ * Fixed installation on other than Ubuntu GNU/Linux distributions
+ (Vitaly Zaitsev).
+ * Link executable with static or shared library (Nick Wellnhofer).
+ If `CMARK_STATIC` is on (default), link the executable with the static
+ library. This produces exactly the same result as compiling the library
+ sources again and linking with the object files.
+ If `CMARK_STATIC` is off, link the executable with the shared library.
+ This wasn't supported before and should be the preferred way to
+ package cmark on Linux distros.
+ Building only a shared library and a statically linked executable
+ isn't supported anymore but this doesn't seem useful.
+ * Reintroduce version check for MSVC /TP flag (Nick Wellnhofer).
+ The flag is only required for old MSVC versions.
+ * normalize.py: use `html.escape` instead of `cgi.escape` (#313).
+ * Fix pathological_tests.py on Windows (Nick Wellnhofer).
+ When using multiprocessing on Windows, the main program must be
+ guarded with a `__name__` check.
+ * Remove useless `__name__` check in test scripts (Nick Wellnhofer).
+ * Add CIFuzz (Leo Neat).
+ * cmark.1 - Document --unsafe instead of --safe (#332).
+ * cmark.1: remove docs for `--normalize` which no longer exists (#332).
+ * Add lint target to Makefile.
+ * Add uninstall target to Makefile.
+ * Update benchmarks (#338).
+ * Fix typo in documentation (Tim Gates).
+ * Increase timeout for pathological tests to avoid CI failure.
+ * Update the Racket wrapper with the safe -> unsafe flag change (Eli
+ Barzilay).
+
+[0.29.0]
+
+ * Update spec to 0.29.
+ * Make rendering safe by default (#239, #273).
+ Adds `CMARK_OPT_UNSAFE` and make `CMARK_OPT_SAFE` a no-op (for API
+ compatibility). The new default behavior is to suppress raw HTML and
+ potentially dangerous links. The `CMARK_OPT_UNSAFE` option has to be set
+ explicitly to prevent this.
+ **NOTE:** This change will require modifications in bindings for cmark
+ and in most libraries and programs that use cmark.
+ Borrows heavily from @kivikakk's patch in github/cmark-gfm#123.
+ * Add sourcepos info for inlines (Yuki Izumi).
+ * Disallow more than 32 nested balanced parens in a link (Yuki Izumi).
+ * Resolve link references before creating setext header.
+ A setext header line after a link reference should not
+ create a header, according to the spec.
+ * commonmark renderer: improve escaping.
+ URL-escape special characters when escape mode is URL, and not otherwise.
+ Entity-escape control characters (< 0x20) in non-literal escape modes.
+ * render: only emit actual newline when escape mode is LITERAL.
+ For markdown content, e.g., in other contexts we want some
+ kind of escaping, not a literal newline.
+ * Update code span normalization to conform with spec change.
+ * Allow empty `<>` link destination in reference link.
+ * Remove leftover includes of `memory.h` (#290).
+ * A link destination can't start with `<` unless it is
+ an angle-bracket link that also ends with `>` (#289).
+ (If your URL really starts with `<`, URL-escape it.)
+ * Allow internal delimiter runs to match if both have lengths that are
+ multiples of 3. See commonmark/commonmark#528.
+ * Include `references.h` in `parser.h` (#287).
+ * Fix `[link](<foo\>)`.
+ * Use hand-rolled scanner for thematic break (see #284).
+ Keep track of the last position where a thematic break
+ failed to match on a line, to avoid rescanning unnecessarily.
+ * Rename `ends_with_blank_line` with `S_` prefix.
+ * Add `CMARK_NODE__LAST_LINE_CHECKED` flag (#284).
+ Use this to avoid unnecessary recursion in `ends_with_blank_line`.
+ * In `ends_with_blank_line`, call `S_set_last_line_blank`
+ to avoid unnecessary repetition (#284). Once we settle whether a list
+ item ends in a blank line, we don't need to revisit this in considering
+ parent list items.
+ * Disallow unescaped `(` in parenthesized link title.
+ * Copy line/col info straight from opener/closer (Ashe Connor).
+ We can't rely on anything in `subj` since it's been modified while parsing
+ the subject and could represent line info from a future line. This is
+ simple and works.
+ * `render.c`: reset `last_breakable` after cr. Fixes jgm/pandoc#5033.
+ * Fix a typo in `houdini_href_e.c` (Felix Yan).
+ * commonmark writer: use `~~~` fences if info string contains backtick.
+ This is needed for round-trip tests.
+ * Update scanners for new info string rules.
+ * Add XSLT stylesheet to convert cmark XML back to Commonmark
+ (Nick Wellnhofer, #264). Initial version of an XSLT stylesheet that
+ converts the XML format produced by `cmark -t xml` back to Commonmark.
+ * Check for whitespace before reference title (#263).
+ * Bump CMake to version 3 (Jonathan Müller).
+ * Build: Remove deprecated call to `add_compiler_export_flags()`
+ (Jonathan Müller). It is deprecated in CMake 3.0, the replacement is to
+ set the `CXX_VISIBILITY_PRESET` (or in our case `C_VISIBILITY_PRESET`) and
+ `VISIBILITY_INLINES_HIDDEN` properties of the target. We're already
+ setting them by setting the CMake variables anyway, so the call can be
+ removed.
+ * Build: only attempt to install MSVC system libraries on Windows
+ (Saleem Abdulrasool). Newer versions of CMake attempt to query the system
+ for information about the VS 2017 installation. Unfortunately, this query
+ fails on non-Windows systems when cross-compiling:
+ `cmake_host_system_information does not recognize <key> VS_15_DIR`.
+ CMake will not find these system libraries on non-Windows hosts anyways,
+ and we were silencing the warnings, so simply omit the installation when
+ cross-compiling to Windows.
+ * Simplify code normalization, in line with spec change.
+ * Implement code span spec changes. These affect both parsing and writing
+ commonmark.
+ * Add link parsing corner cases to regressions (Ashe Connor).
+ * Add `xml:space="preserve"` in XML output when appropriate
+ (Nguyễn Thái Ngọc Duy).
+ (For text, code, code_block, html_inline and html_block tags.)
+ * Removed meta from list of block tags. Added regression test.
+ See commonmark/CommonMark#527.
+ * `entity_tests.py` - omit noisy success output.
+ * `pathological_tests.py`: make tests run faster.
+ Commented out the (already ignored) "many references" test, which
+ times out. Reduced the iterations for a couple other tests.
+ * `pathological_tests.py`: added test for deeply nested lists.
+ * Optimize `S_find_first_nonspace`. We were needlessly redoing things we'd
+ already done. Now we skip the work if the first nonspace is greater than
+ the current offset. This fixes pathological slowdown with deeply nested
+ lists (#255). For N = 3000, the time goes from over 17s to about 0.7s.
+ Thanks to Martin Mitas for diagnosing the problem.
+ * Allow spaces in link destination delimited with pointy brackets.
+ * Adjust max length of decimal/numeric entities.
+ See commonmark/CommonMark#487.
+ * Fix inline raw HTML parsing.
+ This fixes a recently added failing spec test case. Previously spaces
+ were being allowed in unquoted attribute values; no we forbid them.
+ * Don't allow list markers to be indented >= 4 spaces.
+ See commonmark/CommonMark#497.
+ * Check for empty buffer when rendering (Phil Turnbull).
+ For empty documents, `->size` is zero so
+ `renderer.buffer->ptr[renderer.buffer->size - 1]` will cause an
+ out-of-bounds read. Empty buffers always point to the global
+ `cmark_strbuf__initbuf` buffer so we read `cmark_strbuf__initbuf[-1]`.
+ * Also run API tests with `CMARK_SHARED=OFF` (Nick Wellnhofer).
+ * Rename roundtrip and entity tests (Nick Wellnhofer).
+ Rename the tests to reflect that they use the library, not the
+ executable.
+ * Generate export header for static-only build (#247, Nick Wellnhofer).
+ * Fuzz width parameter too (Phil Turnbull). Allow the `width` parameter to
+ be generated too so we get better fuzz-coverage.
+ * Don't discard empty fuzz test-cases (Phil Turnbull). We currently discard
+ fuzz test-cases that are empty but empty inputs are valid markdown. This
+ improves the fuzzing coverage slightly.
+ * Fixed exit code for pathological tests.
+ * Add allowed failures to `pathological_tests.py`.
+ This allows us to include tests that we don't yet know how to pass.
+ * Add timeout to `pathological_tests.py`.
+ Tests must complete in 8 seconds or are errors.
+ * Add more pathological tests (Martin Mitas).
+ These tests target the issues #214, #218, #220.
+ * Use pledge(2) on OpenBSD (Ashe Connor).
+ * Update the Racket wrapper (Eli Barzilay).
+ * Makefile: For afl target, don't build tests.
+
+[0.28.3]
+
+ * Include GNUInstallDirs in src/CMakeLists.txt (Nick Wellnhofer, #240).
+ This fixes build problems on some cmake versions (#241).
+
+[0.28.2]
+
+ * Fixed regression in install dest for static library (#238).
+ Due to a mistake, 0.28.1 installed libcmark.a into include/.
+
+[0.28.1]
+
+ * `--smart`: open quote can never occur right after `]` or `)` (#227).
+ * Fix quadratic behavior in `finalize` (Vicent Marti).
+ * Don't use `CMAKE_INSTALL_LIBDIR` to create `libcmark.pc` (#236).
+ This wasn't getting set in processing `libcmark.pc.in`, and we
+ were getting the wrong entry in `libcmark.pc`.
+ The new approach sets an internal `libdir` variable to
+ `lib${LIB_SUFFIX}`. This variable is used both to set the
+ install destination and in the libcmark.pc.in template.
+ * Update README.md, replace `make astyle` with `make format`
+ (Nguyễn Thái Ngọc Duy).
+
+[0.28.0]
+
+ * Update spec.
+ * Use unsigned integer when shifting (Phil Turnbull).
+ Avoids a UBSAN warning which can be triggered when handling a
+ long sequence of backticks.
+ * Avoid memcpy'ing NULL pointers (Phil Turnbull).
+ Avoids a UBSAN warning when link title is empty string.
+ The length of the memcpy is zero so the NULL pointer is not
+ dereferenced but it is still undefined behaviour.
+ * DeMorgan simplification of some tests in emphasis parser.
+ This also brings the code into closer alignment with the wording
+ of the spec (see jgm/CommonMark#467).
+ * Fixed undefined shift in commonmark writer (#211).
+ Found by google/oss-fuzz:
+ <https://oss-fuzz.com/v2/testcase-detail/4686992824598528>.
+ * latex writer: fix memory overflow (#210).
+ We got an array overflow in enumerated lists nested more than
+ 10 deep with start number =/= 1.
+ This commit also ensures that we don't try to set `enum_` counters
+ that aren't defined by LaTeX (generally up to enumv).
+ Found by google/oss-fuzz:
+ <https://oss-fuzz.com/v2/testcase-detail/5546760854306816>.
+ * Check for NULL pointer in get_link_type (Phil Turnbull).
+ `echo '[](xx:)' | ./build/src/cmark -t latex` gave a
+ segfault.
+ * Move fuzzing dictionary into single file (Phil Turnbull).
+ This allows AFL and libFuzzer to use the same dictionary
+ * Reset bytes after UTF8 proc (Yuki Izumi, #206).
+ * Don't scan past an EOL (Yuki Izumi).
+ The existing negated character classes (`[^…]`) are careful to
+ always include` \x00` in the characters excluded, but these `.`
+ catch-alls can scan right past the terminating NUL placed
+ at the end of the buffer by `_scan_at`. As such, buffer
+ overruns can occur. Also, don't scan past a newline in HTML
+ block end scanners.
+ * Document cases where `get_` functions return `NULL` (#155).
+ E.g. `cmark_node_get_url` on a non-link or image.
+ * Properly handle backslashes in link destinations (#192).
+ Only ascii punctuation characters are escapable, per the spec.
+ * Fixed `cmark_node_get_list_start` to return 0 for bullet lists,
+ as documented (#202).
+ * Use `CMARK_NO_DELIM` for bullet lists (#201).
+ * Fixed code for freeing delimiter stack (#189).
+ * Removed abort outside of conditional (typo).
+ * Removed coercion in error message when aborting from buffer.
+ * Print message to stderr when we abort due to memory demands (#188).
+ * `libcmark.pc`: use `CMAKE_INSTALL_LIBDIR` (#185, Jens Petersen).
+ Needed for multilib distros like Fedora.
+ * Fixed buffer overflow error in `S_parser_feed` (#184).
+ The overflow could occur in the following condition:
+ the buffer ends with `\r` and the next memory address
+ contains `\n`.
+ * Update emphasis parsing for spec change.
+ Strong now goes inside Emph rather than the reverse,
+ when both scopes are possible. The code is much simpler.
+ This also avoids a spec inconsistency that cmark had previously:
+ `***hi***` became Strong (Emph "hi")) but
+ `***hi****` became Emph (Strong "hi")) "*"
+ * Fixes for the LaTeX renderer (#182, Doeme)
+ + Don't double-output the link in latex-rendering.
+ + Prevent ligatures in dashes sensibly when rendering latex.
+ `\-` is a hyphenation, so it doesn't get displayed at all.
+ * Added a test for NULL when freeing `subj->last_delim`.
+ * Cleaned up setting of lower bounds for openers.
+ We now use a much smaller array.
+ * Fix #178, quadratic parsing bug. Add pathological test.
+ * Slight improvement of clarity of logic in emph matching.
+ * Fix "multiple of 3" determination in emph/strong parsing.
+ We need to store the length of the original delimiter run,
+ instead of using the length of the remaining delimiters
+ after some have been subtracted. Test case:
+ `a***b* c*`. Thanks to Raph Levin for reporting.
+ * Correctly initialize chunk in S_process_line (Nick Wellnhofer, #170).
+ The `alloc` member wasn't initialized. This also allows to add an
+ assertion in `chunk_rtrim` which doesn't work for alloced chunks.
+ * Added 'make newbench'.
+ * `scanners.c` generated with re2c 0.16 (68K smaller!).
+ * `scanners.re` - fixed warnings; use `*` for fallback.
+ * Fixed some warnings in `scanners.re`.
+ * Update CaseFolding to latest (Kevin Wojniak, #168).
+ * Allow balanced nested parens in link destinations (Yuki Izumi, #166)
+ * Allocate enough bytes for backticks array.
+ * Inlines: Ensure that the delimiter stack is freed in subject.
+ * Fixed pathological cases with backtick code spans:
+
+ - Removed recursion in scan_to_closing_backticks
+ - Added an array of pointers to potential backtick closers
+ to subject
+ - This array is used to avoid traversing the subject again
+ when we've already seen all the potential backtick closers.
+ - Added a max bound of 1000 for backtick code span delimiters.
+ - This helps with pathological cases like:
+
+ x
+ x `
+ x ``
+ x ```
+ x ````
+ ...
+
+ - Added pathological test case.
+
+ Thanks to Martin Mitáš for identifying the problem and for
+ discussion of solutions.
+ * Remove redundant cmake_minimum_required (#163, @kainjow).
+ * Make shared and static libraries optional (Azamat H. Hackimov).
+ Now you can enable/disable compilation and installation targets for
+ shared and static libraries via `-DCMARK_SHARED=ON/OFF` and
+ `-DCMARK_STATIC=ON/OFF`.
+ * Added support for built-in `${LIB_SUFFIX}` feature (Azamat H.
+ Hackimov). Replaced `${LIB_INSTALL_DIR}` option with built-in
+ `${LIB_SUFFIX}` for installing for 32/64-bit systems. Normally,
+ CMake will set `${LIB_SUFFIX}` automatically for required enviroment.
+ If you have any issues with it, you can override this option with
+ `-DLIB_SUFFIX=64` or `-DLIB_SUFFIX=""` during configuration.
+ * Add Makefile target and harness to fuzz with libFuzzer (Phil Turnbull).
+ This can be run locally with `make libFuzzer` but the harness will be
+ integrated into oss-fuzz for large-scale fuzzing.
+ * Advertise `--validate-utf8` in usage information
+ (Nguyễn Thái Ngọc Duy).
+ * Makefile: use warnings with re2c.
+ * README: Add link to Python wrapper, prettify languages list
+ (Pavlo Kapyshin).
+ * README: Add link to cmark-scala (Tim Nieradzik, #196)
+
+[0.27.1]
+
+ * Set policy for CMP0063 to avoid a warning (#162).
+ Put set_policy under cmake version test.
+ Otherwise we get errors in older versions of cmake.
+ * Use VERSION_GREATER to clean up cmake version test.
+ * Improve afl target. Use afl-clang by default. Set default for path.
+
+[0.27.0]
+
+ * Update spec to 0.27.
+ * Fix warnings building with MSVC on Windows (#165, Hugh Bellamy).
+ * Fix `CMAKE_C_VISIBILITY_PRESET` for cmake versions greater than 1.8
+ (e.g. 3.6.2) (#162, Hugh Bellamy). This lets us build swift-cmark
+ on Windows, using clang-cl.
+ * Fix for non-matching entities (#161, Yuki Izumi).
+ * Modified `print_delimiters` (commented out) so it compiles again.
+ * `make format`: don't change order of includes.
+ * Changed logic for null/eol checks (#160).
+ + only check once for "not at end of line"
+ + check for null before we check for newline characters (the
+ previous patch would fail for NULL + CR)
+ * Fix by not advancing past both `\0` and `\n` (Yuki Izumi).
+ * Add test for NUL-LF sequence (Yuki Izumi).
+ * Fix memory leak in list parsing (Yuki Izumi).
+ * Use `cmark_mem` to free where used to alloc (Yuki Izumi).
+ * Allow a shortcut link before a `(` (jgm/CommonMark#427).
+ * Allow tabs after setext header line (jgm/commonmark.js#109).
+ * Don't let URI schemes start with spaces.
+ * Fixed h2..h6 HTML blocks (jgm/CommonMark#430). Added regression test.
+ * Autolink scheme can contain digits (Gábor Csárdi).
+ * Fix nullary function declarations in cmark.h (Nick Wellnhofer).
+ Fixes strict prototypes warnings.
+ * COPYING: Update file name and remove duplicate section and
+ (Peter Eisentraut).
+ * Fix typo (Pavlo Kapyshin).
+
+[0.26.1]
+
+ * Removed unnecessary typedef that caused build failure on
+ some platforms.
+ * Use `$(MAKE)` in Makefile instead of hardcoded `make` (#146,
+ Tobias Kortkamp).
+
+[0.26.0]
+
+ * Implement spec changes for list items:
+ - Empty list items cannot interrupt paragraphs.
+ - Ordered lists cannot interrupt paragraphs unless
+ they start with 1.
+ - Removed "two blank lines break out of a list" feature.
+ * Fix sourcepos for blockquotes (#142).
+ * Fix sourcepos for atx headers (#141).
+ * Fix ATX headers and thematic breaks to allow tabs as well as spaces.
+ * Fix `chunk_set_cstr` with suffix of current string (#139,
+ Nick Wellnhofer). It's possible that `cmark_chunk_set_cstr` is called
+ with a substring (suffix) of the current string. Delay freeing of the
+ chunk content to handle this case correctly.
+ * Export targets on installation (Jonathan Müller).
+ This allows using them in other cmake projects.
+ * Fix cmake warning about CMP0048 (Jonathan Müller).
+ * commonmark renderer: Ensure we don't have a blank line
+ before a code block when it's the first thing in a list
+ item.
+ * Change parsing of strong/emph in response to spec changes.
+ `process_emphasis` now gets better results in corner cases.
+ The change is this: when considering matches between an interior
+ delimiter run (one that can open and can close) and another delimiter
+ run, we require that the sum of the lengths of the two delimiter
+ runs mod 3 is not 0.
+ * Ported Robin Stocker's changes to link parsing in jgm/commonmark#101.
+ This uses a separate stack for brackets, instead of putting them on the
+ delimiter stack. This avoids the need for looking through the delimiter
+ stack for the next bracket.
+ * `cmark_reference_lookup`: Return NULL if reference is null string.
+ * Fix character type detection in `commonmark.c` (Nick Wellnhofer).
+ Fixes test failures on Windows and undefined behavior.
+ - Implement `cmark_isalpha`.
+ - Check for ASCII character before implicit cast to char.
+ - Use internal ctype functions in `commonmark.c`.
+ * Better documentation of memory-freeing responsibilities.
+ in `cmark.h` and its man page (#124).
+ * Use library functions to insert nodes in emphasis/link processing.
+ Previously we did this manually, which introduces many
+ places where errors can creep in.
+ * Correctly handle list marker followed only by spaces.
+ Previously when a list marker was followed only by spaces,
+ cmark expected the following content to be indented by
+ the same number of spaces. But in this case we should
+ treat the line just like a blank line and set list padding
+ accordingly.
+ * Fixed a number of issues relating to line wrapping.
+ - Extend `CMARK_OPT_NOBREAKS` to all renderers and add `--nobreaks`.
+ - Do not autowrap, regardless of width parameter, if
+ `CMARK_OPT_NOBREAKS` is set.
+ - Fixed `CMARK_OPT_HARDBREAKS` for LaTeX and man renderers.
+ - Ensure that no auto-wrapping occurs if
+ `CMARK_OPT_NOBREAKS` is enabled, or if output is CommonMark and
+ `CMARK_OPT_HARDBREAKS` is enabled.
+ * Set stdin to binary mode on Windows (Nick Wellnhofer, #113).
+ This fixes EOLs when reading from stdin.
+ * Add library option to render softbreaks as spaces (Pavlo
+ Kapyshin). Note that the `NOBREAKS` option is HTML-only
+ * renderer: `no_linebreaks` instead of `no_wrap`.
+ We generally want this option to prohibit any breaking
+ in things like headers (not just wraps, but softbreaks).
+ * Coerce `realurllen` to `int`. This is an alternate solution for pull
+ request #132, which introduced a new warning on the comparison
+ (Benedict Cohen).
+ * Remove unused variable `link_text` (Mathiew Duponchelle).
+ * Improved safety checks in buffer (Vicent Marti).
+ * Add new interface allowing specification of custom memory allocator
+ for nodes (Vicent Marti). Added `cmark_node_new_with_mem`,
+ `cmark_parser_new_with_mem`, `cmark_mem` to API.
+ * Reduce storage size for nodes by using bit flags instead of
+ separate booleans (Vicent Marti).
+ * config: Add `SSIZE_T` compat for Win32 (Vicent Marti).
+ * cmake: Global handler for OOM situations (Vicent Marti).
+ * Add tests for memory exhaustion (Vicent Marti).
+ * Document in man page and public header that one should use the same
+ memory allocator for every node in a tree.
+ * Fix ctypes in Python FFI calls (Nick Wellnhofer). This didn't cause
+ problems so far because all types are 32-bit on 32-bit systems and
+ arguments are passed in registers on x86-64. The wrong types could cause
+ crashes on other platforms, though.
+ * Remove spurious failures in roundtrip tests. In the commonmark writer we
+ separate lists, and lists and indented code, using a dummy HTML comment.
+ So in evaluating the round-trip tests, we now strip out
+ these comments. We also normalize HTML to avoid issues
+ having to do with line breaks.
+ * Add 2016 to copyright (Kevin Burke).
+ * Added `to_commonmark` in `test/cmark.py` (for round-trip tests).
+ * `spec_test.py` - parameterize `do_test` with converter.
+ * `spec_tests.py`: exit code is now sum of failures and errors.
+ This ensures that a failing exit code will be given when
+ there are errors, not just with failures.
+ * Fixed round trip tests. Previously they actually ran
+ `cmark` instead of the round-trip version, since there was a bug in
+ setting the ROUNDTRIP variable (#131).
+ * Added new `roundtrip_tests.py`. This replaces the old use of simple shell
+ scripts. It is much faster, and more flexible. (We will be able
+ to do custom normalization and skip certain tests.)
+ * Fix tests under MinGW (Nick Wellnhofer).
+ * Fix leak in `api_test` (Mathieu Duponchelle).
+ * Makefile: have leakcheck stop on first error instead of going through
+ all the formats and options and probably getting the same output.
+ * Add regression tests (Nick Wellnhofer).
+
+[0.25.2]
+
+ * Open files in binary mode (#113, Nick Wellnhofer). Now that cmark
+ supports different line endings, files must be openend in binary mode
+ on Windows.
+ * Reset `partially_consumed_tab` on every new line (#114, Nick Wellnhofer).
+ * Handle buffer split across a CRLF line ending (#117). Adds an internal
+ field to the parser struct to keep track of `last_buffer_ended_with_cr`.
+ Added test.
+
+[0.25.1]
+
+ * Release with no code changes. cmark version was mistakenly set to
+ 0.25.1 in the 0.25.0 release (#112), so this release just
+ ensures that this will cause no confusion later.
+
+[0.25.0]
+
+ * Fixed tabs in indentation (#101). This patch fixes S_advance_offset
+ so that it doesn't gobble a tab character when advancing less than the
+ width of a tab.
+ * Added partially_consumed_tab to parser. This keeps track of when we
+ have gotten partway through a tab when consuming initial indentation.
+ * Simplified add_line (only need parser parameter).
+ * Properly handle partially consumed tab. E.g. in
+
+ - foo
+
+ <TAB><TAB>bar
+
+ we should consume two spaces from the second tab, including two spaces
+ in the code block.
+ * Properly handle tabs with blockquotes and fenced blocks.
+ * Fixed handling of tabs in lists.
+ * Clarified logic in S_advance_offset.
+ * Use an assertion to check for in-range html_block_type.
+ It's a programming error if the type is out of range.
+ * Refactored S_processLines to make the logic easier to
+ understand, and added documentation (Mathieu Duponchelle).
+ * Removed unnecessary check for empty string_content.
+ * Factored out contains_inlines.
+ * Moved the cmake minimum version to top line of CMakeLists.txt
+ (tinysun212).
+ * Fix ctype(3) usage on NetBSD (Kamil Rytarowski). We need to cast value
+ passed to isspace(3) to unsigned char to explicitly prevent possibly
+ undefined behavior.
+ * Compile in plain C mode with MSVC 12.0 or newer (Nick Wellnhofer).
+ Under MSVC, we used to compile in C++ mode to get some C99 features
+ like mixing declarations and code. With newer MSVC versions, it's
+ possible to build in plain C mode.
+ * Switched from "inline" to "CMARK_INLINE" (Nick Wellnhofer).
+ Newer MSVC versions support enough of C99 to be able to compile cmark
+ in plain C mode. Only the "inline" keyword is still unsupported.
+ We have to use "__inline" instead.
+ * Added include guards to config.h
+ * config.h.in - added compatibility snprintf, vsnprintf for MSVC.
+ * Replaced sprintf with snprintf (Marco Benelli).
+ * config.h: include stdio.h for _vscprintf etc.
+ * Include starg.h when needed in config.h.
+ * Removed an unnecessary C99-ism in buffer.c. This helps compiling on
+ systems like luarocks that don't have all the cmake configuration
+ goodness (thanks to carlmartus).
+ * Don't use variable length arrays (Nick Wellnhofer).
+ They're not supported by MSVC.
+ * Test with multiple MSVC versions under Appveyor (Nick Wellnhofer).
+ * Fix installation dir of man-pages on NetBSD (Kamil Rytarowski).
+ * Fixed typo in cmark.h comments (Chris Eidhof).
+ * Clarify in man page that cmark_node_free frees a node's children too.
+ * Fixed documentation of --width in man page.
+ * Require re2c >= 1.14.2 (#102).
+ * Generated scanners.c with more recent re2c.
+
+[0.24.1]
+
+ * Commonmark renderer:
+ + Use HTML comment, not two blank lines, to separate a list
+ item from a following code block or list. This makes the
+ output more portable, since the "two blank lines" rule is
+ unique to CommonMark. Also, it allows us to break out of
+ a sublist without breaking out of all levels of nesting.
+ + `is_autolink` - handle case where link has no children,
+ which previously caused a segfault.
+ + Use 4-space indent for bullet lists, for increased portability.
+ + Use 2-space + newline for line break for increased portability (#90).
+ + Improved punctuation escaping. Previously all `)` and
+ `.` characters after digits were escaped; now they are
+ only escaped if they are genuinely in a position where
+ they'd cause a list item. This is achieved by changes in
+ `render.c`: (a) `renderer->begin_content` is only set to
+ false after a string of digits at the beginning of the
+ line, and (b) we never break a line before a digit.
+ Also, `begin_content` is properly initialized to true.
+ * Handle NULL root in `consolidate_text_nodes`.
+
+[0.24.0]
+
+ * [API change] Added `cmark_node_replace(oldnode, newnode)`.
+ * Updated spec.txt to 0.24.
+ * Fixed edge case with escaped parens in link destination (#97).
+ This was also checked against the #82 case with asan.
+ * Removed unnecessary check for `fenced` in `cmark_render_html`.
+ It's sufficient to check that the info string is empty.
+ Indeed, those who use the API may well create a code block
+ with an info string without explicitly setting `fenced`.
+ * Updated format of `test/smart_punct.txt`.
+ * Updated `test/spec.txt`, `test/smart_punct.txt`, and
+ `spec_tests.py` to new format.
+ * Fixed `get_containing_block` logic in `src/commonmark.c`.
+ This did not allow for the possibility that a node might have no
+ containing block, causing the commonmark renderer to segfault if
+ passed an inline node with no block parent.
+ * Fixed string representations of `CUSTOM_BLOCK`,
+ `CUSTOM_INLINE`. The old versions `raw_inline` and
+ `raw_block` were being used, and this led to incorrect xml output.
+ * Use default opts in python sample wrapper.
+ * Allow multiline setext header content, as per spec.
+ * Don't allow spaces in link destinations, even with pointy brackets.
+ Conforms to latest change in spec.
+ * Updated `scheme` scanner according to spec change. We no longer use
+ a whitelist of valid schemes.
+ * Allow any kind of nodes as children of `CUSTOM_BLOCK` (#96).
+ * `cmark.h`: moved typedefs for iterator into iterator section.
+ This just moves some code around so it makes more sense
+ to read, and in the man page.
+ * Fixed `make_man_page.py` so it includes typedefs again.
+
+[0.23.0]
+
+ * [API change] Added `CUSTOM_BLOCK` and `CUSTOM_INLINE` node types.
+ They are never generated by the parser, and do not correspond
+ to CommonMark elements. They are designed to be inserted by
+ filters that postprocess the AST. For example, a filter might
+ convert specially marked code blocks to svg diagrams in HTML
+ and tikz diagrams in LaTeX, passing these through to the renderer
+ as a `CUSTOM_BLOCK`. These nodes can have children, but they
+ also have literal text to be printed by the renderer "on enter"
+ and "on exit." Added `cmark_node_get_on_enter`,
+ `cmark_node_set_on_enter`, `cmark_node_get_on_exit`,
+ `cmark_node_set_on_exit` to API.
+ * [API change] Rename `NODE_HTML` -> `NODE_HTML_BLOCK`,
+ `NODE_INLINE_HTML` -> `NODE_HTML_INLINE`. Define aliases
+ so the old names still work, for backwards compatibility.
+ * [API change] Rename `CMARK_NODE_HEADER` -> `CMARK_NODE_HEADING`.
+ Note that for backwards compatibility, we have defined aliases:
+ `CMARK_NODE_HEADER` = `CMARK_NODE_HEADING`,
+ `cmark_node_get_header_level` = `cmark_node_get_heading_level`, and
+ `cmark_node_set_header_level` = `cmark_node_set_heading_level`.
+ * [API change] Rename `CMARK_NODE_HRULE` -> `CMARK_NODE_THEMATIC_BREAK`.
+ Defined the former as the latter for backwards compatibility.
+ * Don't allow space between link text and link label in a reference link
+ (spec change).
+ * Separate parsing and rendering opts in `cmark.h` (#88).
+ This change also changes some of these constants' numerical values,
+ but nothing should change in the API if you use the constants
+ themselves. It should now be clear in the man page which
+ options affect parsing and which affect rendering.
+ * xml renderer - Added xmlns attribute to document node (jgm/CommonMark#87).
+ * Commonmark renderer: ensure html blocks surrounded by blanks.
+ Otherwise we get failures of roundtrip tests.
+ * Commonmark renderer: ensure that literal characters get escaped
+ when they're at the beginning of a block, e.g. `> \- foo`.
+ * LaTeX renderer - better handling of internal links.
+ Now we render `[foo](#bar)` as `\protect\hyperlink{bar}{foo}`.
+ * Check for NULL pointer in _scan_at (#81).
+ * `Makefile.nmake`: be more robust when cmake is missing. Previously,
+ when cmake was missing, the build dir would be created anyway, and
+ subsequent attempts (even with cmake) would fail, because cmake would
+ not be run. Depending on `build/CMakeFiles` is more robust -- this won't
+ be created unless cmake is run. Partially addresses #85.
+ * Fixed DOCTYPE in xml output.
+ * commonmark.c: fix `size_t` to `int`. This fixes an MSVC warning
+ "conversion from 'size_t' to 'int', possible loss of data" (Kevin Wojniak).
+ * Correct string length in `cmark_parse_document` example (Lee Jeffery).
+ * Fix non-ASCII end-of-line character check (andyuhnak).
+ * Fix "declaration shadows a local variable" (Kevin Wojniak).
+ * Install static library (jgm/CommonMark#381).
+ * Fix warnings about dropping const qualifier (Kevin Wojniak).
+ * Use full (unabbreviated) versions of constants (`CMARK_...`).
+ * Removed outdated targets from Makefile.
+ * Removed need for sudo in `make bench`.
+ * Improved benchmark. Use longer test, since `time` has limited resolution.
+ * Removed `bench.h` and timing calls in `main.c`.
+ * Updated API docs; getters return empty strings if not set
+ rather than NULL, as previously documented.
+ * Added api_tests for custom nodes.
+ * Made roundtrip test part of the test suite run by cmake.
+ * Regenerate `scanners.c` using re2c 0.15.3.
+ * Adjusted scanner for link url. This fixes a heap buffer overflow (#82).
+ * Added version number (1.0) to XML namespace. We don't guarantee
+ stability in this until 1.0 is actually released, however.
+ * Removed obsolete `TIMER` macro.
+ * Make `LIB_INSTALL_DIR` configurable (Mathieu Bridon, #79).
+ * Removed out-of-date luajit wrapper.
+ * Use `input`, not `parser->curline` to determine last line length.
+ * Small optimizations in `_scan_at`.
+ * Replaced hard-coded 4 with `TAB_STOP`.
+ * Have `make format` reformat api tests as well.
+ * Added api tests for man, latex, commonmark, and xml renderers (#51).
+ * render.c: added `begin_content` field. This is like `begin_line` except
+ that it doesn't trigger production of the prefix. So it can be set
+ after an initial prefix (say `> `) is printed by the renderer, and
+ consulted in determining whether to escape content that has a special
+ meaning at the beginning of a line. Used in the commonmark renderer.
+ * Python 3.5 compatibility: don't require HTMLParseError (Zhiming Wang).
+ HTMLParseError was removed in Python 3.5. Since it could never be thrown
+ in Python 3.5+, we simply define a placeholder when HTMLParseError
+ cannot be imported.
+ * Set `convert_charrefs=False` in `normalize.py` (#83). This defeats the
+ new default as of python 3.5, and allows the script to work with python
+ 3.5.
+
+[0.22.0]
+
+ * Removed `pre` from blocktags scanner. `pre` is handled separately
+ in rule 1 and needn't be handled in rule 6.
+ * Added `iframe` to list of blocktags, as per spec change.
+ * Fixed bug with `HRULE` after blank line. This previously caused cmark
+ to break out of a list, thinking it had two consecutive blanks.
+ * Check for empty string before trying to look at line ending.
+ * Make sure every line fed to `S_process_line` ends with `\n` (#72).
+ So `S_process_line` sees only unix style line endings. Ultimately we
+ probably want a better solution, allowing the line ending style of
+ the input file to be preserved. This solution forces output with newlines.
+ * Improved `cmark_strbuf_normalize_whitespace` (#73). Now all characters
+ that satisfy `cmark_isspace` are recognized as whitespace. Previously
+ `\r` and `\t` (and others) weren't included.
+ * Treat line ending with EOF as ending with newline (#71).
+ * Fixed `--hardbreaks` with `\r\n` line breaks (#68).
+ * Disallow list item starting with multiple blank lines (jgm/CommonMark#332).
+ * Allow tabs before closing `#`s in ATX header
+ * Removed `cmark_strbuf_printf` and `cmark_strbuf_vprintf`.
+ These are no longer needed, and cause complications for MSVC.
+ Also removed `HAVE_VA_COPY` and `HAVE_C99_SNPRINTF` feature tests.
+ * Added option to disable tests (Kevin Wojniak).
+ * Added `CMARK_INLINE` macro.
+ * Removed need to disable MSVC warnings 4267, 4244, 4800
+ (Kevin Wojniak).
+ * Fixed MSVC inline errors when cmark is included in sources that
+ don't have the same set of disabled warnings (Kevin Wojniak).
+ * Fix `FileNotFoundError` errors on tests when cmark is built from
+ another project via `add_subdirectory()` (Kevin Wojniak).
+ * Prefix `utf8proc` functions to avoid conflict with existing library
+ (Kevin Wojniak).
+ * Avoid name clash between Windows `.pdb` files (Nick Wellnhofer).
+ * Improved `smart_punct.txt` (see jgm/commonmark.js#61).
+ * Set `POSITION_INDEPENDENT_CODE` `ON` for static library (see #39).
+ * `make bench`: allow overriding `BENCHFILE`. Previously if you did
+ this, it would clopper `BENCHFILE` with the default bench file.
+ * `make bench`: Use -10 priority with renice.
+ * Improved `make_autolink`. Ensures that title is chunk with empty
+ string rather than NULL, as with other links.
+ * Added `clang-check` target.
+ * Travis: split `roundtrip_test` and `leakcheck` (OGINO Masanori).
+ * Use clang-format, llvm style, for formatting. Reformatted all source files.
+ Added `format` target to Makefile. Removed `astyle` target.
+ Updated `.editorconfig`.
+
+[0.21.0]
+
+ * Updated to version 0.21 of spec.
+ * Added latex renderer (#31). New exported function in API:
+ `cmark_render_latex`. New source file: `src/latex.hs`.
+ * Updates for new HTML block spec. Removed old `html_block_tag` scanner.
+ Added new `html_block_start` and `html_block_start_7`, as well
+ as `html_block_end_n` for n = 1-5. Rewrote block parser for new HTML
+ block spec.
+ * We no longer preprocess tabs to spaces before parsing.
+ Instead, we keep track of both the byte offset and
+ the (virtual) column as we parse block starts.
+ This allows us to handle tabs without converting
+ to spaces first. Tabs are left as tabs in the output, as
+ per the revised spec.
+ * Removed utf8 validation by default. We now replace null characters
+ in the line splitting code.
+ * Added `CMARK_OPT_VALIDATE_UTF8` option and command-line option
+ `--validate-utf8`. This option causes cmark to check for valid
+ UTF-8, replacing invalid sequences with the replacement
+ character, U+FFFD. Previously this was done by default in
+ connection with tab expansion, but we no longer do it by
+ default with the new tab treatment. (Many applications will
+ know that the input is valid UTF-8, so validation will not
+ be necessary.)
+ * Added `CMARK_OPT_SAFE` option and `--safe` command-line flag.
+ + Added `CMARK_OPT_SAFE`. This option disables rendering of raw HTML
+ and potentially dangerous links.
+ + Added `--safe` option in command-line program.
+ + Updated `cmark.3` man page.
+ + Added `scan_dangerous_url` to scanners.
+ + In HTML, suppress rendering of raw HTML and potentially dangerous
+ links if `CMARK_OPT_SAFE`. Dangerous URLs are those that begin
+ with `javascript:`, `vbscript:`, `file:`, or `data:` (except for
+ `image/png`, `image/gif`, `image/jpeg`, or `image/webp` mime types).
+ + Added `api_test` for `OPT_CMARK_SAFE`.
+ + Rewrote `README.md` on security.
+ * Limit ordered list start to 9 digits, per spec.
+ * Added width parameter to `render_man` (API change).
+ * Extracted common renderer code from latex, man, and commonmark
+ renderers into a separate module, `renderer.[ch]` (#63). To write a
+ renderer now, you only need to write a character escaping function
+ and a node rendering function. You pass these to `cmark_render`
+ and it handles all the plumbing (including line wrapping) for you.
+ So far this is an internal module, but we might consider adding
+ it to the API in the future.
+ * commonmark writer: correctly handle email autolinks.
+ * commonmark writer: escape `!`.
+ * Fixed soft breaks in commonmark renderer.
+ * Fixed scanner for link url. re2c returns the longest match, so we
+ were getting bad results with `[link](foo\(and\(bar\)\))`
+ which it would parse as containing a bare `\` followed by
+ an in-parens chunk ending with the final paren.
+ * Allow non-initial hyphens in html tag names. This allows for
+ custom tags, see jgm/CommonMark#239.
+ * Updated `test/smart_punct.txt`.
+ * Implemented new treatment of hyphens with `--smart`, converting
+ sequences of hyphens to sequences of em and en dashes that contain no
+ hyphens.
+ * HTML renderer: properly split info on first space char (see
+ jgm/commonmark.js#54).
+ * Changed version variables to functions (#60, Andrius Bentkus).
+ This is easier to access using ffi, since some languages, like C#
+ like to use only function interfaces for accessing library
+ functionality.
+ * `process_emphasis`: Fixed setting lower bound to potential openers.
+ Renamed `potential_openers` -> `openers_bottom`.
+ Renamed `start_delim` -> `stack_bottom`.
+ * Added case for #59 to `pathological_test.py`.
+ * Fixed emphasis/link parsing bug (#59).
+ * Fixed off-by-one error in line splitting routine.
+ This caused certain NULLs not to be replaced.
+ * Don't rtrim in `subject_from_buffer`. This gives bad results in
+ parsing reference links, where we might have trailing blanks
+ (`finalize` removes the bytes parsed as a reference definition;
+ before this change, some blank bytes might remain on the line).
+ + Added `column` and `first_nonspace_column` fields to `parser`.
+ + Added utility function to advance the offset, computing
+ the virtual column too. Note that we don't need to deal with
+ UTF-8 here at all. Only ASCII occurs in block starts.
+ + Significant performance improvement due to the fact that
+ we're not doing UTF-8 validation.
+ * Fixed entity lookup table. The old one had many errors.
+ The new one is derived from the list in the npm entities package.
+ Since the sequences can now be longer (multi-code-point), we
+ have bumped the length limit from 4 to 8, which also affects
+ `houdini_html_u.c`. An example of the kind of error that was fixed:
+ `&ngE;` should be rendered as "≧̸" (U+02267 U+00338), but it was
+ being rendered as "≧" (which is the same as `&gE;`).
+ * Replace gperf-based entity lookup with binary tree lookup.
+ The primary advantage is a big reduction in the size of
+ the compiled library and executable (> 100K).
+ There should be no measurable performance difference in
+ normal documents. I detected only a slight performance
+ hit in a file containing 1,000,000 entities.
+ + Removed `src/html_unescape.gperf` and `src/html_unescape.h`.
+ + Added `src/entities.h` (generated by `tools/make_entities_h.py`).
+ + Added binary tree lookup functions to `houdini_html_u.c`, and
+ use the data in `src/entities.h`.
+ * Renamed `entities.h` -> `entities.inc`, and
+ `tools/make_entities_h.py` -> `tools/make_entitis_inc.py`.
+ * Fixed cases like
+ ```
+ [ref]: url
+ "title" ok
+ ```
+ Here we should parse the first line as a reference.
+ * `inlines.c`: Added utility functions to skip spaces and line endings.
+ * Fixed backslashes in link destinations that are not part of escapes
+ (jgm/commonmark#45).
+ * `process_line`: Removed "add newline if line doesn't have one."
+ This isn't actually needed.
+ * Small logic fixes and a simplification in `process_emphasis`.
+ * Added more pathological tests:
+ + Many link closers with no openers.
+ + Many link openers with no closers.
+ + Many emph openers with no closers.
+ + Many closers with no openers.
+ + `"*a_ " * 20000`.
+ * Fixed `process_emphasis` to handle new pathological cases.
+ Now we have an array of pointers (`potential_openers`),
+ keyed to the delim char. When we've failed to match a potential opener
+ prior to point X in the delimiter stack, we reset `potential_openers`
+ for that opener type to X, and thus avoid having to look again through
+ all the openers we've already rejected.
+ * `process_inlines`: remove closers from delim stack when possible.
+ When they have no matching openers and cannot be openers themselves,
+ we can safely remove them. This helps with a performance case:
+ `"a_ " * 20000` (jgm/commonmark.js#43).
+ * Roll utf8proc_charlen into utf8proc_valid (Nick Wellnhofer).
+ Speeds up "make bench" by another percent.
+ * `spec_tests.py`: allow `→` for tab in HTML examples.
+ * `normalize.py`: don't collapse whitespace in pre contexts.
+ * Use utf-8 aware re2c.
+ * Makefile afl target: removed `-m none`, added `CMARK_OPTS`.
+ * README: added `make afl` instructions.
+ * Limit generated generated `cmark.3` to 72 character line width.
+ * Travis: switched to containerized build system.
+ * Removed `debug.h`. (It uses GNU extensions, and we don't need it anyway.)
+ * Removed sundown from benchmarks, because the reading was anomalous.
+ sundown had an arbitrary 16MB limit on buffers, and the benchmark
+ input exceeded that. So who knows what we were actually testing?
+ Added hoedown, sundown's successor, which is a better comparison.
+
+[0.20.0]
+
+ * Fixed bug in list item parsing when items indented >= 4 spaces (#52).
+ * Don't allow link labels with no non-whitespace characters
+ (jgm/CommonMark#322).
+ * Fixed multiple issues with numeric entities (#33, Nick Wellnhofer).
+ * Support CR and CRLF line endings (Ben Trask).
+ * Added test for different line endings to `api_test`.
+ * Allow NULL value in string setters (Nick Wellnhofer). (NULL
+ produces a 0-length string value.) Internally, URL and
+ title are now stored as `cmark_chunk` rather than `char *`.
+ * Fixed memory leak in `cmark_consolidate_text_nodes` (#32).
+ * Fixed `is_autolink` in the CommonMark renderer (#50). Previously *any*
+ link with an absolute URL was treated as an autolink.
+ * Cope with broken `snprintf` on Windows (Nick Wellnhofer). On Windows,
+ `snprintf` returns -1 if the output was truncated. Fall back to
+ Windows-specific `_scprintf`.
+ * Switched length parameter on `cmark_markdown_to_html`,
+ `cmark_parser_feed`, and `cmark_parse_document` from `int`
+ to `size_t` (#53, Nick Wellnhofer).
+ * Use a custom type `bufsize_t` for all string sizes and indices.
+ This allows to switch to 64-bit string buffers by changing a single
+ typedef and a macro definition (Nick Wellnhofer).
+ * Hardened the `strbuf` code, checking for integer overflows and
+ adding range checks (Nick Wellnhofer).
+ * Removed unused function `cmark_strbuf_attach` (Nick Wellnhofer).
+ * Fixed all implicit 64-bit to 32-bit conversions that
+ `-Wshorten-64-to-32` warns about (Nick Wellnhofer).
+ * Added helper function `cmark_strbuf_safe_strlen` that converts
+ from `size_t` to `bufsize_t` and throws an error in case of
+ an overflow (Nick Wellnhofer).
+ * Abort on `strbuf` out of memory errors (Nick Wellnhofer).
+ Previously such errors were not being trapped. This involves
+ some internal changes to the `buffer` library that do not affect
+ the API.
+ * Factored out `S_find_first_nonspace` in `S_proces_line`.
+ Added fields `offset`, `first_nonspace`, `indent`, and `blank`
+ to `cmark_parser` struct. This just removes some repetition.
+ * Added Racket Racket (5.3+) wrapper (Eli Barzilay).
+ * Removed `-pg` from Debug build flags (#47).
+ * Added Ubsan build target, to check for undefined behavior.
+ * Improved `make leakcheck`. We now return an error status if anything
+ in the loop fails. We now check `--smart` and `--normalize` options.
+ * Removed `wrapper3.py`, made `wrapper.py` work with python 2 and 3.
+ Also improved the wrapper to work with Windows, and to use smart
+ punctuation (as an example).
+ * In `wrapper.rb`, added argument for options.
+ * Revised luajit wrapper.
+ * Added build status badges to README.md.
+ * Added links to go, perl, ruby, R, and Haskell bindings to README.md.
+
+[0.19.0]
+
+ * Fixed `_` emphasis parsing to conform to spec (jgm/CommonMark#317).
+ * Updated `spec.txt`.
+ * Compile static library with `-DCMARK_STATIC_DEFINE` (Nick Wellnhofer).
+ * Suppress warnings about Windows runtime library files (Nick Wellnhofer).
+ Visual Studio Express editions do not include the redistributable files.
+ Set `CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS` to suppress warnings.
+ * Added appyeyor: Windows continuous integration (`appveyor.yml`).
+ * Use `os.path.join` in `test/cmark.py` for proper cross-platform paths.
+ * Fixed `Makefile.nmake`.
+ * Improved `make afl`: added `test/afl_dictionary`, increased timeout
+ for hangs.
+ * Improved README with a description of the library's strengths.
+ * Pass-through Unicode non-characters (Nick Wellnhofer).
+ Despite their name, Unicode non-characters are valid code points. They
+ should be passed through by a library like libcmark.
+ * Check return status of `utf8proc_iterate` (#27).
+
+[0.18.3]
+
+ * Include patch level in soname (Nick Wellnhofer). Minor version is
+ tied to spec version, so this allows breaking the ABI between spec
+ releases.
+ * Install compiler-provided system runtime libraries (Changjiang Yang).
+ * Use `strbuf_printf` instead of `snprintf`. `snprintf` is not
+ available on some platforms (Visual Studio 2013 and earlier).
+ * Fixed memory access bug: "invalid read of size 1" on input `[link](<>)`.
+
+[0.18.2]
+
+ * Added commonmark renderer: `cmark_render_commonmark`. In addition
+ to options, this takes a `width` parameter. A value of 0 disables
+ wrapping; a positive value wraps the document to the specified
+ width. Note that width is automatically set to 0 if the
+ `CMARK_OPT_HARDBREAKS` option is set.
+ * The `cmark` executable now allows `-t commonmark` for output as
+ CommonMark. A `--width` option has been added to specify wrapping
+ width.
+ * Added `roundtrip_test` Makefile target. This runs all the spec
+ through the commonmark renderer, and then through the commonmark
+ parser, and compares normalized HTML to the test. All tests pass
+ with the current parser and renderer, giving us some confidence that
+ the commonmark renderer is sufficiently robust. Eventually this
+ should be pythonized and put in the cmake test routine.
+ * Removed an unnecessary check in `blocks.c`. By the time we check
+ for a list start, we've already checked for a horizontal rule, so
+ we don't need to repeat that check here. Thanks to Robin Stocker for
+ pointing out a similar redundancy in commonmark.js.
+ * Fixed bug in `cmark_strbuf_unescape` (`buffer.c`). The old function
+ gave incorrect results on input like `\\*`, since the next backslash
+ would be treated as escaping the `*` instead of being escaped itself.
+ * `scanners.re`: added `_scan_scheme`, `scan_scheme`, used in the
+ commonmark renderer.
+ * Check for `CMAKE_C_COMPILER` (not `CC_COMPILER`) when setting C flags.
+ * Update code examples in documentation, adding new parser option
+ argument, and using `CMARK_OPT_DEFAULT` (Nick Wellnhofer).
+ * Added options parameter to `cmark_markdown_to_html`.
+ * Removed obsolete reference to `CMARK_NODE_LINK_LABEL`.
+ * `make leakcheck` now checks all output formats.
+ * `test/cmark.py`: set default options for `markdown_to_html`.
+ * Warn about buggy re2c versions (Nick Wellnhofer).
+
+[0.18.1]
+
+ * Build static version of library in default build (#11).
+ * `cmark.h`: Add missing argument to `cmark_parser_new` (#12).
+
+[0.18]
+
+ * Switch to 2-clause BSD license, with agreement of contributors.
+ * Added Profile build type, `make prof` target.
+ * Fixed autolink scanner to conform to the spec. Backslash escapes
+ not allowed in autolinks.
+ * Don't rely on strnlen being available (Nick Wellnhofer).
+ * Updated scanners for new whitespace definition.
+ * Added `CMARK_OPT_SMART` and `--smart` option, `smart.c`, `smart.h`.
+ * Added test for `--smart` option.
+ * Fixed segfault with --normalize (closes #7).
+ * Moved normalization step from XML renderer to `cmark_parser_finish`.
+ * Added options parameter to `cmark_parse_document`, `cmark_parse_file`.
+ * Fixed man renderer's escaping for unicode characters.
+ * Don't require python3 to make `cmark.3` man page.
+ * Use ASCII escapes for punctuation characters for portability.
+ * Made `options` an int rather than a long, for consistency.
+ * Packed `cmark_node` struct to fit into 128 bytes.
+ This gives a small performance boost and lowers memory usage.
+ * Repacked `delimiter` struct to avoid hole.
+ * Fixed use-after-free bug, which arose when a paragraph containing
+ only reference links and blank space was finalized (#9).
+ Avoid using `parser->current` in the loop that creates new
+ blocks, since `finalize` in `add_child` may have removed
+ the current parser (if it contains only reference definitions).
+ This isn't a great solution; in the long run we need to rewrite
+ to make the logic clearer and to make it harder to make
+ mistakes like this one.
+ * Added 'Asan' build type. `make asan` will link against ASan; the
+ resulting executable will do checks for memory access issues.
+ Thanks @JordanMilne for the suggestion.
+ * Add Makefile target to fuzz with AFL (Nick Wellnhofer)
+ The variable `$AFL_PATH` must point to the directory containing the AFL
+ binaries. It can be set as an environment variable or passed to make on
+ the command line.
+
+[0.17]
+
+ * Stripped out all JavaScript related code and documentation, moving
+ it to a separate repository (<https://github.com/jgm/commonmark.js>).
+ * Improved Makefile targets, so that `cmake` is run again only when
+ necessary (Nick Wellnhofer).
+ * Added `INSTALL_PREFIX` to the Makefile, allowing installation to a
+ location other than `/usr/local` without invoking `cmake`
+ manually (Nick Wellnhofer).
+ * `make test` now guarantees that the project will
+ be rebuilt before tests are run (Nick Wellnhofer).
+ * Prohibited overriding of some Makefile variables (Nick Wellnhofer).
+ * Provide version number and string, both as macros
+ (`CMARK_VERSION`, `CMARK_VERSION_STRING`) and as symbols
+ (`cmark_version`, `cmark_version_string`) (Nick Wellnhofer). All of
+ these come from `cmark_version.h`, which is constructed from a
+ template `cmark_version.h.in` and data in `CMakeLists.txt`.
+ * Avoid calling `free` on null pointer.
+ * Added an accessor for an iterator's root node (`cmark_iter_get_root`).
+ * Added user data field for nodes (Nick Wellnhofer). This is
+ intended mainly for use in bindings for dynamic languages, where
+ it could store a pointer to a target language object (#287). But
+ it can be used for anything.
+ * Man renderer: properly escape multiline strings.
+ * Added assertion to raise error if finalize is called on a closed block.
+ * Implemented the new spec rule for emphasis and strong emphasis with `_`.
+ * Moved the check for fence-close with the other checks for end-of-block.
+ * Fixed a bug with loose list detection with items containings
+ fenced code blocks (#285).
+ * Removed recursive algorithm in `ends_with_blank_line` (#286).
+ * Minor code reformatting: renamed parameters.
+
+[0.16]
+
+ * Added xml renderer (XML representation of the CommonMark AST,
+ which is described in `CommonMark.dtd`).
+ * Reduced size of gperf entity table (Nick Wellnhofer).
+ * Reworked iterators to allow deletion of nodes during iteration
+ (Nick Wellnhofer).
+ * Optimized `S_is_leaf`.
+ * Added `cmark_iter_reset` to iterator API.
+ * Added `cmark_consolidate_text_nodes` to API to combine adjacent
+ text nodes.
+ * Added `CMARK_OPT_NORMALIZE` to options (this combines adjacent
+ text nodes).
+ * Added `--normalize` option to command-line program.
+ * Improved regex for HTML comments in inline parsing.
+ * Python is no longer required for a basic build from the
+ repository.
diff --git a/cmark/cmake/modules/FindAsan.cmake b/cmark/cmake/modules/FindAsan.cmake
new file mode 100644
index 0000000000..064b5b6b39
--- /dev/null
+++ b/cmark/cmake/modules/FindAsan.cmake
@@ -0,0 +1,74 @@
+#
+# The MIT License (MIT)
+#
+# Copyright (c) 2013 Matthew Arsenault
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# This module tests if address sanitizer is supported by the compiler,
+# and creates a ASan build type (i.e. set CMAKE_BUILD_TYPE=ASan to use
+# it). This sets the following variables:
+#
+# CMAKE_C_FLAGS_ASAN - Flags to use for C with asan
+# CMAKE_CXX_FLAGS_ASAN - Flags to use for C++ with asan
+# HAVE_ADDRESS_SANITIZER - True or false if the ASan build type is available
+
+include(CheckCCompilerFlag)
+
+# Set -Werror to catch "argument unused during compilation" warnings
+set(CMAKE_REQUIRED_FLAGS "-Werror -faddress-sanitizer") # Also needs to be a link flag for test to pass
+check_c_compiler_flag("-faddress-sanitizer" HAVE_FLAG_ADDRESS_SANITIZER)
+
+set(CMAKE_REQUIRED_FLAGS "-Werror -fsanitize=address") # Also needs to be a link flag for test to pass
+check_c_compiler_flag("-fsanitize=address" HAVE_FLAG_SANITIZE_ADDRESS)
+
+unset(CMAKE_REQUIRED_FLAGS)
+
+if(HAVE_FLAG_SANITIZE_ADDRESS)
+ # Clang 3.2+ use this version
+ set(ADDRESS_SANITIZER_FLAG "-fsanitize=address")
+elseif(HAVE_FLAG_ADDRESS_SANITIZER)
+ # Older deprecated flag for ASan
+ set(ADDRESS_SANITIZER_FLAG "-faddress-sanitizer")
+endif()
+
+if(NOT ADDRESS_SANITIZER_FLAG)
+ return()
+else(NOT ADDRESS_SANITIZER_FLAG)
+ set(HAVE_ADDRESS_SANITIZER FALSE)
+endif()
+
+set(HAVE_ADDRESS_SANITIZER TRUE)
+
+set(CMAKE_C_FLAGS_ASAN "-O1 -g ${ADDRESS_SANITIZER_FLAG} -fno-omit-frame-pointer -fno-optimize-sibling-calls"
+ CACHE STRING "Flags used by the C compiler during ASan builds."
+ FORCE)
+set(CMAKE_CXX_FLAGS_ASAN "-O1 -g ${ADDRESS_SANITIZER_FLAG} -fno-omit-frame-pointer -fno-optimize-sibling-calls"
+ CACHE STRING "Flags used by the C++ compiler during ASan builds."
+ FORCE)
+set(CMAKE_EXE_LINKER_FLAGS_ASAN "${ADDRESS_SANITIZER_FLAG}"
+ CACHE STRING "Flags used for linking binaries during ASan builds."
+ FORCE)
+set(CMAKE_SHARED_LINKER_FLAGS_ASAN "${ADDRESS_SANITIZER_FLAG}"
+ CACHE STRING "Flags used by the shared libraries linker during ASan builds."
+ FORCE)
+mark_as_advanced(CMAKE_C_FLAGS_ASAN
+ CMAKE_CXX_FLAGS_ASAN
+ CMAKE_EXE_LINKER_FLAGS_ASAN
+ CMAKE_SHARED_LINKER_FLAGS_ASAN)
diff --git a/cmark/data/CaseFolding.txt b/cmark/data/CaseFolding.txt
new file mode 100644
index 0000000000..a0b0f07fd6
--- /dev/null
+++ b/cmark/data/CaseFolding.txt
@@ -0,0 +1,1682 @@
+# CaseFolding-17.0.0.txt
+# Date: 2025-07-30, 23:54:36 GMT
+# © 2025 Unicode®, Inc.
+# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
+# For terms of use and license, see https://www.unicode.org/terms_of_use.html
+#
+# Unicode Character Database
+# For documentation, see https://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 "FUSS" and "Fuß" 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 the
+# "Conformance" / "Default Case Algorithms" section of the core specification.
+#
+# ================================================================================
+# 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
+1C89; C; 1C8A; # CYRILLIC CAPITAL LETTER TJE
+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
+1FD3; S; 0390; # 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
+1FE3; S; 03B0; # 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
+A7CB; C; 0264; # LATIN CAPITAL LETTER RAMS HORN
+A7CC; C; A7CD; # LATIN CAPITAL LETTER S WITH DIAGONAL STROKE
+A7CE; C; A7CF; # LATIN CAPITAL LETTER PHARYNGEAL VOICED FRICATIVE
+A7D0; C; A7D1; # LATIN CAPITAL LETTER CLOSED INSULAR G
+A7D2; C; A7D3; # LATIN CAPITAL LETTER DOUBLE THORN
+A7D4; C; A7D5; # LATIN CAPITAL LETTER DOUBLE WYNN
+A7D6; C; A7D7; # LATIN CAPITAL LETTER MIDDLE SCOTS S
+A7D8; C; A7D9; # LATIN CAPITAL LETTER SIGMOID S
+A7DA; C; A7DB; # LATIN CAPITAL LETTER LAMBDA
+A7DC; C; 019B; # LATIN CAPITAL LETTER LAMBDA WITH STROKE
+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
+FB05; S; FB06; # 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
+10D50; C; 10D70; # GARAY CAPITAL LETTER A
+10D51; C; 10D71; # GARAY CAPITAL LETTER CA
+10D52; C; 10D72; # GARAY CAPITAL LETTER MA
+10D53; C; 10D73; # GARAY CAPITAL LETTER KA
+10D54; C; 10D74; # GARAY CAPITAL LETTER BA
+10D55; C; 10D75; # GARAY CAPITAL LETTER JA
+10D56; C; 10D76; # GARAY CAPITAL LETTER SA
+10D57; C; 10D77; # GARAY CAPITAL LETTER WA
+10D58; C; 10D78; # GARAY CAPITAL LETTER LA
+10D59; C; 10D79; # GARAY CAPITAL LETTER GA
+10D5A; C; 10D7A; # GARAY CAPITAL LETTER DA
+10D5B; C; 10D7B; # GARAY CAPITAL LETTER XA
+10D5C; C; 10D7C; # GARAY CAPITAL LETTER YA
+10D5D; C; 10D7D; # GARAY CAPITAL LETTER TA
+10D5E; C; 10D7E; # GARAY CAPITAL LETTER RA
+10D5F; C; 10D7F; # GARAY CAPITAL LETTER NYA
+10D60; C; 10D80; # GARAY CAPITAL LETTER FA
+10D61; C; 10D81; # GARAY CAPITAL LETTER NA
+10D62; C; 10D82; # GARAY CAPITAL LETTER PA
+10D63; C; 10D83; # GARAY CAPITAL LETTER HA
+10D64; C; 10D84; # GARAY CAPITAL LETTER OLD KA
+10D65; C; 10D85; # GARAY CAPITAL LETTER OLD NA
+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
+16EA0; C; 16EBB; # BERIA ERFE CAPITAL LETTER ARKAB
+16EA1; C; 16EBC; # BERIA ERFE CAPITAL LETTER BASIGNA
+16EA2; C; 16EBD; # BERIA ERFE CAPITAL LETTER DARBAI
+16EA3; C; 16EBE; # BERIA ERFE CAPITAL LETTER EH
+16EA4; C; 16EBF; # BERIA ERFE CAPITAL LETTER FITKO
+16EA5; C; 16EC0; # BERIA ERFE CAPITAL LETTER GOWAY
+16EA6; C; 16EC1; # BERIA ERFE CAPITAL LETTER HIRDEABO
+16EA7; C; 16EC2; # BERIA ERFE CAPITAL LETTER I
+16EA8; C; 16EC3; # BERIA ERFE CAPITAL LETTER DJAI
+16EA9; C; 16EC4; # BERIA ERFE CAPITAL LETTER KOBO
+16EAA; C; 16EC5; # BERIA ERFE CAPITAL LETTER LAKKO
+16EAB; C; 16EC6; # BERIA ERFE CAPITAL LETTER MERI
+16EAC; C; 16EC7; # BERIA ERFE CAPITAL LETTER NINI
+16EAD; C; 16EC8; # BERIA ERFE CAPITAL LETTER GNA
+16EAE; C; 16EC9; # BERIA ERFE CAPITAL LETTER NGAY
+16EAF; C; 16ECA; # BERIA ERFE CAPITAL LETTER OI
+16EB0; C; 16ECB; # BERIA ERFE CAPITAL LETTER PI
+16EB1; C; 16ECC; # BERIA ERFE CAPITAL LETTER ERIGO
+16EB2; C; 16ECD; # BERIA ERFE CAPITAL LETTER ERIGO TAMURA
+16EB3; C; 16ECE; # BERIA ERFE CAPITAL LETTER SERI
+16EB4; C; 16ECF; # BERIA ERFE CAPITAL LETTER SHEP
+16EB5; C; 16ED0; # BERIA ERFE CAPITAL LETTER TATASOUE
+16EB6; C; 16ED1; # BERIA ERFE CAPITAL LETTER UI
+16EB7; C; 16ED2; # BERIA ERFE CAPITAL LETTER WASSE
+16EB8; C; 16ED3; # BERIA ERFE CAPITAL LETTER AY
+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/cmark/fuzz/CMakeLists.txt b/cmark/fuzz/CMakeLists.txt
new file mode 100644
index 0000000000..8ffecef4e0
--- /dev/null
+++ b/cmark/fuzz/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_executable(cmark-fuzz cmark-fuzz.c)
+cmark_add_compile_options(cmark-fuzz)
+target_link_libraries(cmark-fuzz cmark)
diff --git a/cmark/fuzz/afl_test_cases/test.md b/cmark/fuzz/afl_test_cases/test.md
new file mode 100644
index 0000000000..27eee009c7
--- /dev/null
+++ b/cmark/fuzz/afl_test_cases/test.md
@@ -0,0 +1,36 @@
+# H1
+
+H2
+--
+
+t ☺
+*b* **em** `c`
+&ge;\&\
+\_e\_
+
+4) I1
+
+5) I2
+ > [l](/u "t")
+ >
+ > - [f]
+ > - ![a](/u "t")
+ >
+ >> <ftp://hh>
+ >> <u@hh>
+
+~~~ l☺
+cb
+~~~
+
+ c1
+ c2
+
+***
+
+<div>
+<b>x</b>
+</div>
+
+[f]: /u "t"
+
diff --git a/cmark/fuzz/cmark-fuzz.c b/cmark/fuzz/cmark-fuzz.c
new file mode 100644
index 0000000000..74e72013e2
--- /dev/null
+++ b/cmark/fuzz/cmark-fuzz.c
@@ -0,0 +1,75 @@
+/* for fmemopen */
+#define _POSIX_C_SOURCE 200809L
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "cmark.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ struct __attribute__((packed)) {
+ int options;
+ int width;
+ } fuzz_config;
+
+ if (size >= sizeof(fuzz_config)) {
+ /* The beginning of `data` is treated as fuzzer configuration */
+ memcpy(&fuzz_config, data, sizeof(fuzz_config));
+ int options = fuzz_config.options;
+
+ /* Mask off valid option bits */
+ options &= (CMARK_OPT_SOURCEPOS | CMARK_OPT_HARDBREAKS | CMARK_OPT_UNSAFE | CMARK_OPT_NOBREAKS | CMARK_OPT_NORMALIZE | CMARK_OPT_VALIDATE_UTF8 | CMARK_OPT_SMART);
+
+ /* Remainder of input is the markdown */
+ const char *markdown = (const char *)(data + sizeof(fuzz_config));
+ size_t markdown_size = size - sizeof(fuzz_config);
+ cmark_node *doc = NULL;
+
+ /* Use upper bits of options to select parsing mode */
+ switch (((unsigned) fuzz_config.options >> 30) & 3) {
+ case 0:
+ doc = cmark_parse_document(markdown, markdown_size, options);
+ break;
+
+ case 1:
+ if (markdown_size > 0) {
+ FILE *file = fmemopen((void *) markdown, markdown_size, "r");
+ doc = cmark_parse_file(file, options);
+ fclose(file);
+ }
+ break;
+
+ case 2: {
+ size_t block_max = 20;
+ cmark_parser *parser = cmark_parser_new(options);
+
+ while (markdown_size > 0) {
+ size_t block_size = markdown_size > block_max ? block_max : markdown_size;
+ cmark_parser_feed(parser, markdown, block_size);
+ markdown += block_size;
+ markdown_size -= block_size;
+ }
+
+ doc = cmark_parser_finish(parser);
+ cmark_parser_free(parser);
+ break;
+ }
+
+ case 3:
+ free(cmark_markdown_to_html(markdown, markdown_size, options));
+ break;
+ }
+
+ if (doc != NULL) {
+ free(cmark_render_commonmark(doc, options, fuzz_config.width));
+ free(cmark_render_html(doc, options));
+ free(cmark_render_latex(doc, options, fuzz_config.width));
+ free(cmark_render_man(doc, options, fuzz_config.width));
+ free(cmark_render_xml(doc, options));
+
+ cmark_node_free(doc);
+ }
+ }
+ return 0;
+}
diff --git a/cmark/fuzz/dictionary b/cmark/fuzz/dictionary
new file mode 100644
index 0000000000..b06783c94e
--- /dev/null
+++ b/cmark/fuzz/dictionary
@@ -0,0 +1,49 @@
+asterisk="*"
+attr_generic=" a=\"1\""
+attr_href=" href=\"1\""
+attr_xml_lang=" xml:lang=\"1\""
+attr_xmlns=" xmlns=\"1\""
+backslash="\\"
+backtick="`"
+colon=":"
+dashes="---"
+double_quote="\""
+entity_builtin="&lt;"
+entity_decimal="&#1;"
+entity_external="&a;"
+entity_hex="&#x1;"
+equals="==="
+exclamation="!"
+greater_than=">"
+hash="#"
+hyphen="-"
+indent=" "
+left_bracket="["
+left_paren="("
+less_than="<"
+plus="+"
+right_bracket="]"
+right_paren=")"
+single_quote="'"
+string_any="ANY"
+string_brackets="[]"
+string_cdata="CDATA"
+string_dashes="--"
+string_empty_dblquotes="\"\""
+string_empty_quotes="''"
+string_idrefs="IDREFS"
+string_parentheses="()"
+string_pcdata="#PCDATA"
+tag_cdata="<![CDATA["
+tag_close="</a>"
+tag_doctype="<!DOCTYPE"
+tag_element="<!ELEMENT"
+tag_entity="<!ENTITY"
+tag_notation="<!NOTATION"
+tag_open="<a>"
+tag_open_close="<a />"
+tag_open_exclamation="<!"
+tag_open_q="<?"
+tag_sq2_close="]]>"
+tag_xml_q="<?xml?>"
+underscore="_"
diff --git a/cmark/man/CMakeLists.txt b/cmark/man/CMakeLists.txt
new file mode 100644
index 0000000000..8ed54487d9
--- /dev/null
+++ b/cmark/man/CMakeLists.txt
@@ -0,0 +1,4 @@
+install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/man1/cmark.1
+ DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
+install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/man3/cmark.3
+ DESTINATION ${CMAKE_INSTALL_MANDIR}/man3)
diff --git a/cmark/man/make_man_page.py b/cmark/man/make_man_page.py
new file mode 100644
index 0000000000..2115411bce
--- /dev/null
+++ b/cmark/man/make_man_page.py
@@ -0,0 +1,137 @@
+#!/usr/bin/env python
+
+# Creates a man page from a C file.
+
+# Comments beginning with `/**` are treated as Groff man, except that
+# 'this' is converted to \fIthis\f[], and ''this'' to \fBthis\f[].
+
+# Non-blank lines immediately following a man page comment are treated
+# as function signatures or examples and parsed into .Ft, .Fo, .Fa, .Fc. The
+# immediately preceding man documentation chunk is printed after the example
+# as a comment on it.
+
+# That's about it!
+
+import sys, re, os, platform
+from datetime import date
+from ctypes import CDLL, c_char_p, c_long, c_void_p
+
+sysname = platform.system()
+
+curdir = os.getcwd()
+
+if sysname == 'Darwin':
+ cmark = CDLL(curdir + "/build/src/libcmark.dylib")
+else:
+ cmark = CDLL(curdir + "/build/src/libcmark.so")
+
+parse_document = cmark.cmark_parse_document
+parse_document.restype = c_void_p
+parse_document.argtypes = [c_char_p, c_long]
+
+render_man = cmark.cmark_render_man
+render_man.restype = c_char_p
+render_man.argtypes = [c_void_p, c_long, c_long]
+
+cmark_version_string = cmark.cmark_version_string
+cmark_version_string.restype = c_char_p
+cmark_version_string.argtypes = []
+
+def md2man(text):
+ if sys.version_info >= (3,0):
+ textbytes = text.encode('utf-8')
+ textlen = len(textbytes)
+ return render_man(parse_document(textbytes, textlen), 0, 72).decode('utf-8')
+ else:
+ textbytes = text
+ textlen = len(text)
+ return render_man(parse_document(textbytes, textlen), 0, 72)
+
+comment_start_re = re.compile(r'^\/\*\* ?')
+comment_delim_re = re.compile(r'^[/ ]\** ?')
+comment_end_re = re.compile(r'^ \**\/')
+function_re = re.compile(r'^ *(?:CMARK_EXPORT\s+)?(?P<type>(?:const\s+)?\w+(?:\s*[*])?)\s*(?P<name>\w+)\s*\((?P<args>[^)]*)\)')
+blank_re = re.compile(r'^\s*$')
+macro_re = re.compile(r'CMARK_EXPORT *')
+typedef_start_re = re.compile(r'typedef.*{$')
+typedef_end_re = re.compile(r'}')
+single_quote_re = re.compile(r"(?<!\w)'([^']+)'(?!\w)")
+double_quote_re = re.compile(r"(?<!\w)''([^']+)''(?!\w)")
+
+def handle_quotes(s):
+ return re.sub(double_quote_re, r'**\g<1>**', re.sub(single_quote_re, r'*\g<1>*', s))
+
+typedef = False
+mdlines = []
+chunk = []
+sig = []
+
+if len(sys.argv) > 1:
+ sourcefile = sys.argv[1]
+else:
+ print("Usage: make_man_page.py sourcefile")
+ exit(1)
+
+with open(sourcefile, 'r') as cmarkh:
+ state = 'default'
+ for line in cmarkh:
+ # state transition
+ oldstate = state
+ if comment_start_re.match(line):
+ state = 'man'
+ elif comment_end_re.match(line) and state == 'man':
+ continue
+ elif comment_delim_re.match(line) and state == 'man':
+ state = 'man'
+ elif not typedef and blank_re.match(line):
+ state = 'default'
+ elif typedef and typedef_end_re.match(line):
+ typedef = False
+ elif typedef_start_re.match(line):
+ typedef = True
+ state = 'signature'
+ elif state == 'man':
+ state = 'signature'
+
+ # handle line
+ if state == 'man':
+ chunk.append(handle_quotes(re.sub(comment_delim_re, '', line)))
+ elif state == 'signature':
+ ln = re.sub(macro_re, '', line)
+ if typedef or not re.match(blank_re, ln):
+ sig.append(ln)
+ elif oldstate == 'signature' and state != 'signature':
+ if len(mdlines) > 0 and mdlines[-1] != '\n':
+ mdlines.append('\n')
+ rawsig = ''.join(sig)
+ m = function_re.match(rawsig)
+ mdlines.append('.PP\n')
+ if m:
+ mdlines.append('\\fI' + m.group('type') + '\\f[]' + ' ')
+ mdlines.append('\\fB' + m.group('name') + '\\f[]' + '(')
+ first = True
+ for argument in re.split(',', m.group('args')):
+ if not first:
+ mdlines.append(', ')
+ first = False
+ mdlines.append('\\fI' + argument.strip() + '\\f[]')
+ mdlines.append(')\n')
+ else:
+ mdlines.append('.nf\n\\fC\n.RS 0n\n')
+ mdlines += sig
+ mdlines.append('.RE\n\\f[]\n.fi\n')
+ if len(mdlines) > 0 and mdlines[-1] != '\n':
+ mdlines.append('\n')
+ mdlines += md2man(''.join(chunk))
+ mdlines.append('\n')
+ chunk = []
+ sig = []
+ elif oldstate == 'man' and state != 'signature':
+ if len(mdlines) > 0 and mdlines[-1] != '\n':
+ mdlines.append('\n')
+ mdlines += md2man(''.join(chunk)) # add man chunk
+ chunk = []
+ mdlines.append('\n')
+
+sys.stdout.write('.TH ' + os.path.basename(sourcefile).replace('.h','') + ' 3 "' + date.today().strftime('%B %d, %Y') + '" "cmark ' + cmark_version_string().decode('utf-8') + '" "Library Functions Manual"\n')
+sys.stdout.write(''.join(mdlines))
diff --git a/cmark/man/man1/cmark.1 b/cmark/man/man1/cmark.1
new file mode 100644
index 0000000000..00b9251590
--- /dev/null
+++ b/cmark/man/man1/cmark.1
@@ -0,0 +1,73 @@
+.TH "cmark" "1" "February 11, 2020" "LOCAL" "General Commands Manual"
+.SH "NAME"
+\fBcmark\fR
+\- convert CommonMark formatted text to HTML
+.SH "SYNOPSIS"
+.HP 6n
+\fBcmark\fR
+[options]
+file*
+.SH "DESCRIPTION"
+\fBcmark\fR
+converts Markdown formatted plain text to either HTML, groff man,
+CommonMark XML, LaTeX, or CommonMark, using the conventions
+described in the CommonMark spec. It reads input from \fIstdin\fR
+or the specified files (concatenating their contents) and writes
+output to \fIstdout\fR.
+.SH "OPTIONS"
+.TP 12n
+.B \-\-to, \-t \f[I]FORMAT\f[]
+Specify output format (\f[C]html\f[], \f[C]man\f[], \f[C]xml\f[],
+\f[C]latex\f[], \f[C]commonmark\f[]).
+.TP 12n
+.B \-\-width \f[I]WIDTH\f[]
+Specify a column width to which to wrap the output. For no wrapping, use
+the value 0 (the default). This option currently only affects the
+commonmark, latex, and man renderers.
+.TP 12n
+.B \-\-hardbreaks
+Render soft breaks (newlines inside paragraphs in the CommonMark source)
+as hard line breaks in the target format. If this option is specified,
+hard wrapping is disabled for CommonMark output, regardless of the value
+given with \-\-width.
+.TP 12n
+.B \-\-nobreaks
+Render soft breaks as spaces. If this option is specified,
+hard wrapping is disabled for all output formats, regardless of the value
+given with \-\-width.
+.TP 12n
+.B \-\-sourcepos
+Include source position attribute.
+.TP 12n
+.B \-\-validate-utf8
+Validate UTF-8, replacing illegal sequences with U+FFFD.
+.TP 12n
+.B \-\-smart
+Use smart punctuation. Straight double and single quotes will
+be rendered as curly quotes, depending on their position.
+\f[C]\-\-\f[] will be rendered as an en-dash.
+\f[C]\-\-\-\f[] will be rendered as an em-dash.
+\f[C]...\f[] will be rendered as ellipses.
+.TP 12n
+.B \-\-safe
+Omit raw HTML and potentially dangerous URLs (default).
+Raw HTML is replaced by a placeholder comment
+and potentially dangerous URLs are replaced by empty strings.
+Potentially dangerous URLs are those that begin with `javascript:`,
+`vbscript:`, `file:`, or `data:` (except for `image/png`,
+`image/gif`, `image/jpeg`, or `image/webp` mime types).
+.TP 12n
+.B \-\-unsafe
+Render raw HTML or potentially dangerous URLs, overriding
+the default (\-\-safe) behavior.
+.TP 12n
+.B \-\-help
+Print usage information.
+.TP 12n
+.B \-\-version
+Print version.
+.SH "AUTHORS"
+John MacFarlane, Vicent Marti, Kārlis Gaņģis, Nick Wellnhofer.
+.SH "SEE ALSO"
+.PP
+CommonMark spec: \f[C]https://spec.commonmark.org\f[].
diff --git a/cmark/man/man3/cmark.3 b/cmark/man/man3/cmark.3
new file mode 100644
index 0000000000..e454a510ad
--- /dev/null
+++ b/cmark/man/man3/cmark.3
@@ -0,0 +1,906 @@
+.TH cmark 3 "September 05, 2024" "cmark 0.31.1" "Library Functions Manual"
+.SH
+NAME
+.PP
+\f[B]cmark\f[] \- CommonMark parsing, manipulating, and rendering
+
+.SH
+DESCRIPTION
+.SS
+Simple Interface
+
+.PP
+\fIchar *\f[] \fBcmark_markdown_to_html\f[](\fIconst char *text\f[], \fIsize_t len\f[], \fIint options\f[])
+
+.PP
+Convert \f[I]text\f[] (assumed to be a UTF\-8 encoded string with length
+\f[I]len\f[]) from CommonMark Markdown to HTML, returning a
+null\-terminated, UTF\-8\-encoded string. It is the caller's
+responsibility to free the returned buffer.
+
+.SS
+Node Structure
+
+.PP
+.nf
+\fC
+.RS 0n
+typedef enum {
+ /* Error status */
+ CMARK_NODE_NONE,
+
+ /* Block */
+ CMARK_NODE_DOCUMENT,
+ CMARK_NODE_BLOCK_QUOTE,
+ CMARK_NODE_LIST,
+ CMARK_NODE_ITEM,
+ CMARK_NODE_CODE_BLOCK,
+ CMARK_NODE_HTML_BLOCK,
+ CMARK_NODE_CUSTOM_BLOCK,
+ CMARK_NODE_PARAGRAPH,
+ CMARK_NODE_HEADING,
+ CMARK_NODE_THEMATIC_BREAK,
+
+ CMARK_NODE_FIRST_BLOCK = CMARK_NODE_DOCUMENT,
+ CMARK_NODE_LAST_BLOCK = CMARK_NODE_THEMATIC_BREAK,
+
+ /* Inline */
+ CMARK_NODE_TEXT,
+ CMARK_NODE_SOFTBREAK,
+ CMARK_NODE_LINEBREAK,
+ CMARK_NODE_CODE,
+ CMARK_NODE_HTML_INLINE,
+ CMARK_NODE_CUSTOM_INLINE,
+ CMARK_NODE_EMPH,
+ CMARK_NODE_STRONG,
+ CMARK_NODE_LINK,
+ CMARK_NODE_IMAGE,
+
+ CMARK_NODE_FIRST_INLINE = CMARK_NODE_TEXT,
+ CMARK_NODE_LAST_INLINE = CMARK_NODE_IMAGE
+} cmark_node_type;
+.RE
+\f[]
+.fi
+
+
+
+.PP
+.nf
+\fC
+.RS 0n
+typedef enum {
+ CMARK_NO_LIST,
+ CMARK_BULLET_LIST,
+ CMARK_ORDERED_LIST
+} cmark_list_type;
+.RE
+\f[]
+.fi
+
+
+
+.PP
+.nf
+\fC
+.RS 0n
+typedef enum {
+ CMARK_NO_DELIM,
+ CMARK_PERIOD_DELIM,
+ CMARK_PAREN_DELIM
+} cmark_delim_type;
+.RE
+\f[]
+.fi
+
+
+
+.SS
+Custom memory allocator support
+
+.PP
+.nf
+\fC
+.RS 0n
+typedef struct cmark_mem {
+ void *(*calloc)(size_t, size_t);
+ void *(*realloc)(void *, size_t);
+ void (*free)(void *);
+} cmark_mem;
+.RE
+\f[]
+.fi
+
+.PP
+Defines the memory allocation functions to be used by CMark when parsing
+and allocating a document tree
+
+.PP
+\fIcmark_mem *\f[] \fBcmark_get_default_mem_allocator\f[](\fIvoid\f[])
+
+.PP
+Returns a pointer to the default memory allocator.
+
+.SS
+Classifying nodes
+
+.PP
+\fIbool\f[] \fBcmark_node_is_block\f[](\fIcmark_node *node\f[])
+
+.PP
+Returns true if the node is a block node. */
+
+.PP
+\fIbool\f[] \fBcmark_node_is_inline\f[](\fIcmark_node *node\f[])
+
+.PP
+Returns true if the node is an inline node. */
+
+.PP
+\fIbool\f[] \fBcmark_node_is_leaf\f[](\fIcmark_node *node\f[])
+
+.PP
+Returns true if the node is a leaf node (a node that cannot contain
+children). */
+
+.SS
+Creating and Destroying Nodes
+
+.PP
+\fIcmark_node *\f[] \fBcmark_node_new\f[](\fIcmark_node_type type\f[])
+
+.PP
+Creates a new node of type \f[I]type\f[]. Note that the node may have
+other required properties, which it is the caller's responsibility to
+assign.
+
+.PP
+\fIcmark_node *\f[] \fBcmark_node_new_with_mem\f[](\fIcmark_node_type type\f[], \fIcmark_mem *mem\f[])
+
+.PP
+Same as \f[C]cmark_node_new\f[], but explicitly listing the memory
+allocator used to allocate the node. Note: be sure to use the same
+allocator for every node in a tree, or bad things can happen.
+
+.PP
+\fIvoid\f[] \fBcmark_node_free\f[](\fIcmark_node *node\f[])
+
+.PP
+Frees the memory allocated for a node and any children.
+
+.SS
+Tree Traversal
+
+.PP
+\fIcmark_node *\f[] \fBcmark_node_next\f[](\fIcmark_node *node\f[])
+
+.PP
+Returns the next node in the sequence after \f[I]node\f[], or NULL if
+there is none.
+
+.PP
+\fIcmark_node *\f[] \fBcmark_node_previous\f[](\fIcmark_node *node\f[])
+
+.PP
+Returns the previous node in the sequence after \f[I]node\f[], or NULL
+if there is none.
+
+.PP
+\fIcmark_node *\f[] \fBcmark_node_parent\f[](\fIcmark_node *node\f[])
+
+.PP
+Returns the parent of \f[I]node\f[], or NULL if there is none.
+
+.PP
+\fIcmark_node *\f[] \fBcmark_node_first_child\f[](\fIcmark_node *node\f[])
+
+.PP
+Returns the first child of \f[I]node\f[], or NULL if \f[I]node\f[] has
+no children.
+
+.PP
+\fIcmark_node *\f[] \fBcmark_node_last_child\f[](\fIcmark_node *node\f[])
+
+.PP
+Returns the last child of \f[I]node\f[], or NULL if \f[I]node\f[] has no
+children.
+
+.SS
+Iterator
+.PP
+An iterator will walk through a tree of nodes, starting from a root
+node, returning one node at a time, together with information about
+whether the node is being entered or exited. The iterator will first
+descend to a child node, if there is one. When there is no child, the
+iterator will go to the next sibling. When there is no next sibling, the
+iterator will return to the parent (but with a \f[I]cmark_event_type\f[]
+of \f[C]CMARK_EVENT_EXIT\f[]). The iterator will return
+\f[C]CMARK_EVENT_DONE\f[] when it reaches the root node again. One
+natural application is an HTML renderer, where an \f[C]ENTER\f[] event
+outputs an open tag and an \f[C]EXIT\f[] event outputs a close tag. An
+iterator might also be used to transform an AST in some systematic way,
+for example, turning all level\-3 headings into regular paragraphs.
+.IP
+.nf
+\f[C]
+void
+usage_example(cmark_node *root) {
+ cmark_event_type ev_type;
+ cmark_iter *iter = cmark_iter_new(root);
+
+ while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
+ cmark_node *cur = cmark_iter_get_node(iter);
+ // Do something with `cur` and `ev_type`
+ }
+
+ cmark_iter_free(iter);
+}
+\f[]
+.fi
+.PP
+Iterators will never return \f[C]EXIT\f[] events for leaf nodes, which
+are nodes of type:
+.IP \[bu] 2
+CMARK_NODE_HTML_BLOCK
+.IP \[bu] 2
+CMARK_NODE_THEMATIC_BREAK
+.IP \[bu] 2
+CMARK_NODE_CODE_BLOCK
+.IP \[bu] 2
+CMARK_NODE_TEXT
+.IP \[bu] 2
+CMARK_NODE_SOFTBREAK
+.IP \[bu] 2
+CMARK_NODE_LINEBREAK
+.IP \[bu] 2
+CMARK_NODE_CODE
+.IP \[bu] 2
+CMARK_NODE_HTML_INLINE
+.PP
+Nodes must only be modified after an \f[C]EXIT\f[] event, or an
+\f[C]ENTER\f[] event for leaf nodes.
+
+.PP
+.nf
+\fC
+.RS 0n
+typedef enum {
+ CMARK_EVENT_NONE,
+ CMARK_EVENT_DONE,
+ CMARK_EVENT_ENTER,
+ CMARK_EVENT_EXIT
+} cmark_event_type;
+.RE
+\f[]
+.fi
+
+
+
+.PP
+\fIcmark_iter *\f[] \fBcmark_iter_new\f[](\fIcmark_node *root\f[])
+
+.PP
+Creates a new iterator starting at \f[I]root\f[]. The current node and
+event type are undefined until \f[I]cmark_iter_next\f[] is called for
+the first time. The memory allocated for the iterator should be released
+using \f[I]cmark_iter_free\f[] when it is no longer needed.
+
+.PP
+\fIvoid\f[] \fBcmark_iter_free\f[](\fIcmark_iter *iter\f[])
+
+.PP
+Frees the memory allocated for an iterator.
+
+.PP
+\fIcmark_event_type\f[] \fBcmark_iter_next\f[](\fIcmark_iter *iter\f[])
+
+.PP
+Advances to the next node and returns the event type
+(\f[C]CMARK_EVENT_ENTER\f[], \f[C]CMARK_EVENT_EXIT\f[] or
+\f[C]CMARK_EVENT_DONE\f[]).
+
+.PP
+\fIcmark_node *\f[] \fBcmark_iter_get_node\f[](\fIcmark_iter *iter\f[])
+
+.PP
+Returns the current node.
+
+.PP
+\fIcmark_event_type\f[] \fBcmark_iter_get_event_type\f[](\fIcmark_iter *iter\f[])
+
+.PP
+Returns the current event type.
+
+.PP
+\fIcmark_node *\f[] \fBcmark_iter_get_root\f[](\fIcmark_iter *iter\f[])
+
+.PP
+Returns the root node.
+
+.PP
+\fIvoid\f[] \fBcmark_iter_reset\f[](\fIcmark_iter *iter\f[], \fIcmark_node *current\f[], \fIcmark_event_type event_type\f[])
+
+.PP
+Resets the iterator so that the current node is \f[I]current\f[] and the
+event type is \f[I]event_type\f[]. The new current node must be a
+descendant of the root node or the root node itself.
+
+.SS
+Accessors
+
+.PP
+\fIvoid *\f[] \fBcmark_node_get_user_data\f[](\fIcmark_node *node\f[])
+
+.PP
+Returns the user data of \f[I]node\f[].
+
+.PP
+\fIint\f[] \fBcmark_node_set_user_data\f[](\fIcmark_node *node\f[], \fIvoid *user_data\f[])
+
+.PP
+Sets arbitrary user data for \f[I]node\f[]. Returns 1 on success, 0 on
+failure.
+
+.PP
+\fIcmark_node_type\f[] \fBcmark_node_get_type\f[](\fIcmark_node *node\f[])
+
+.PP
+Returns the type of \f[I]node\f[], or \f[C]CMARK_NODE_NONE\f[] on error.
+
+.PP
+\fIconst char *\f[] \fBcmark_node_get_type_string\f[](\fIcmark_node *node\f[])
+
+.PP
+Like \f[I]cmark_node_get_type\f[], but returns a string representation
+of the type, or \f[C]"<unknown>"\f[].
+
+.PP
+\fIconst char *\f[] \fBcmark_node_get_literal\f[](\fIcmark_node *node\f[])
+
+.PP
+Returns the string contents of \f[I]node\f[], or an empty string if none
+is set. Returns NULL if called on a node that does not have string
+content.
+
+.PP
+\fIint\f[] \fBcmark_node_set_literal\f[](\fIcmark_node *node\f[], \fIconst char *content\f[])
+
+.PP
+Sets the string contents of \f[I]node\f[]. Returns 1 on success, 0 on
+failure.
+
+.PP
+\fIint\f[] \fBcmark_node_get_heading_level\f[](\fIcmark_node *node\f[])
+
+.PP
+Returns the heading level of \f[I]node\f[], or 0 if \f[I]node\f[] is not
+a heading.
+
+.PP
+\fIint\f[] \fBcmark_node_set_heading_level\f[](\fIcmark_node *node\f[], \fIint level\f[])
+
+.PP
+Sets the heading level of \f[I]node\f[], returning 1 on success and 0 on
+error.
+
+.PP
+\fIcmark_list_type\f[] \fBcmark_node_get_list_type\f[](\fIcmark_node *node\f[])
+
+.PP
+Returns the list type of \f[I]node\f[], or \f[C]CMARK_NO_LIST\f[] if
+\f[I]node\f[] is not a list.
+
+.PP
+\fIint\f[] \fBcmark_node_set_list_type\f[](\fIcmark_node *node\f[], \fIcmark_list_type type\f[])
+
+.PP
+Sets the list type of \f[I]node\f[], returning 1 on success and 0 on
+error.
+
+.PP
+\fIcmark_delim_type\f[] \fBcmark_node_get_list_delim\f[](\fIcmark_node *node\f[])
+
+.PP
+Returns the list delimiter type of \f[I]node\f[], or
+\f[C]CMARK_NO_DELIM\f[] if \f[I]node\f[] is not a list.
+
+.PP
+\fIint\f[] \fBcmark_node_set_list_delim\f[](\fIcmark_node *node\f[], \fIcmark_delim_type delim\f[])
+
+.PP
+Sets the list delimiter type of \f[I]node\f[], returning 1 on success
+and 0 on error.
+
+.PP
+\fIint\f[] \fBcmark_node_get_list_start\f[](\fIcmark_node *node\f[])
+
+.PP
+Returns starting number of \f[I]node\f[], if it is an ordered list,
+otherwise 0.
+
+.PP
+\fIint\f[] \fBcmark_node_set_list_start\f[](\fIcmark_node *node\f[], \fIint start\f[])
+
+.PP
+Sets starting number of \f[I]node\f[], if it is an ordered list.
+Returns 1 on success, 0 on failure.
+
+.PP
+\fIint\f[] \fBcmark_node_get_list_tight\f[](\fIcmark_node *node\f[])
+
+.PP
+Returns 1 if \f[I]node\f[] is a tight list, 0 otherwise.
+
+.PP
+\fIint\f[] \fBcmark_node_set_list_tight\f[](\fIcmark_node *node\f[], \fIint tight\f[])
+
+.PP
+Sets the "tightness" of a list. Returns 1 on success, 0 on failure.
+
+.PP
+\fIconst char *\f[] \fBcmark_node_get_fence_info\f[](\fIcmark_node *node\f[])
+
+.PP
+Returns the info string from a fenced code block.
+
+.PP
+\fIint\f[] \fBcmark_node_set_fence_info\f[](\fIcmark_node *node\f[], \fIconst char *info\f[])
+
+.PP
+Sets the info string in a fenced code block, returning 1 on success
+and 0 on failure.
+
+.PP
+\fIconst char *\f[] \fBcmark_node_get_url\f[](\fIcmark_node *node\f[])
+
+.PP
+Returns the URL of a link or image \f[I]node\f[], or an empty string if
+no URL is set. Returns NULL if called on a node that is not a link or
+image.
+
+.PP
+\fIint\f[] \fBcmark_node_set_url\f[](\fIcmark_node *node\f[], \fIconst char *url\f[])
+
+.PP
+Sets the URL of a link or image \f[I]node\f[]. Returns 1 on success, 0
+on failure.
+
+.PP
+\fIconst char *\f[] \fBcmark_node_get_title\f[](\fIcmark_node *node\f[])
+
+.PP
+Returns the title of a link or image \f[I]node\f[], or an empty string
+if no title is set. Returns NULL if called on a node that is not a link
+or image.
+
+.PP
+\fIint\f[] \fBcmark_node_set_title\f[](\fIcmark_node *node\f[], \fIconst char *title\f[])
+
+.PP
+Sets the title of a link or image \f[I]node\f[]. Returns 1 on success, 0
+on failure.
+
+.PP
+\fIconst char *\f[] \fBcmark_node_get_on_enter\f[](\fIcmark_node *node\f[])
+
+.PP
+Returns the literal "on enter" text for a custom \f[I]node\f[], or an
+empty string if no on_enter is set. Returns NULL if called on a
+non\-custom node.
+
+.PP
+\fIint\f[] \fBcmark_node_set_on_enter\f[](\fIcmark_node *node\f[], \fIconst char *on_enter\f[])
+
+.PP
+Sets the literal text to render "on enter" for a custom \f[I]node\f[].
+Any children of the node will be rendered after this text. Returns 1 on
+success 0 on failure.
+
+.PP
+\fIconst char *\f[] \fBcmark_node_get_on_exit\f[](\fIcmark_node *node\f[])
+
+.PP
+Returns the literal "on exit" text for a custom \f[I]node\f[], or an
+empty string if no on_exit is set. Returns NULL if called on a
+non\-custom node.
+
+.PP
+\fIint\f[] \fBcmark_node_set_on_exit\f[](\fIcmark_node *node\f[], \fIconst char *on_exit\f[])
+
+.PP
+Sets the literal text to render "on exit" for a custom \f[I]node\f[].
+Any children of the node will be rendered before this text. Returns 1 on
+success 0 on failure.
+
+.PP
+\fIint\f[] \fBcmark_node_get_start_line\f[](\fIcmark_node *node\f[])
+
+.PP
+Returns the line on which \f[I]node\f[] begins.
+
+.PP
+\fIint\f[] \fBcmark_node_get_start_column\f[](\fIcmark_node *node\f[])
+
+.PP
+Returns the column at which \f[I]node\f[] begins.
+
+.PP
+\fIint\f[] \fBcmark_node_get_end_line\f[](\fIcmark_node *node\f[])
+
+.PP
+Returns the line on which \f[I]node\f[] ends.
+
+.PP
+\fIint\f[] \fBcmark_node_get_end_column\f[](\fIcmark_node *node\f[])
+
+.PP
+Returns the column at which \f[I]node\f[] ends.
+
+.SS
+Tree Manipulation
+
+.PP
+\fIvoid\f[] \fBcmark_node_unlink\f[](\fIcmark_node *node\f[])
+
+.PP
+Unlinks a \f[I]node\f[], removing it from the tree, but not freeing its
+memory. (Use \f[I]cmark_node_free\f[] for that.)
+
+.PP
+\fIint\f[] \fBcmark_node_insert_before\f[](\fIcmark_node *node\f[], \fIcmark_node *sibling\f[])
+
+.PP
+Inserts \f[I]sibling\f[] before \f[I]node\f[]. Returns 1 on success, 0
+on failure.
+
+.PP
+\fIint\f[] \fBcmark_node_insert_after\f[](\fIcmark_node *node\f[], \fIcmark_node *sibling\f[])
+
+.PP
+Inserts \f[I]sibling\f[] after \f[I]node\f[]. Returns 1 on success, 0 on
+failure.
+
+.PP
+\fIint\f[] \fBcmark_node_replace\f[](\fIcmark_node *oldnode\f[], \fIcmark_node *newnode\f[])
+
+.PP
+Replaces \f[I]oldnode\f[] with \f[I]newnode\f[] and unlinks
+\f[I]oldnode\f[] (but does not free its memory). Returns 1 on success, 0
+on failure.
+
+.PP
+\fIint\f[] \fBcmark_node_prepend_child\f[](\fIcmark_node *node\f[], \fIcmark_node *child\f[])
+
+.PP
+Adds \f[I]child\f[] to the beginning of the children of \f[I]node\f[].
+Returns 1 on success, 0 on failure.
+
+.PP
+\fIint\f[] \fBcmark_node_append_child\f[](\fIcmark_node *node\f[], \fIcmark_node *child\f[])
+
+.PP
+Adds \f[I]child\f[] to the end of the children of \f[I]node\f[].
+Returns 1 on success, 0 on failure.
+
+.PP
+\fIvoid\f[] \fBcmark_consolidate_text_nodes\f[](\fIcmark_node *root\f[])
+
+.PP
+Consolidates adjacent text nodes.
+
+.SS
+Parsing
+.PP
+Simple interface:
+.IP
+.nf
+\f[C]
+cmark_node *document = cmark_parse_document("Hello *world*", 13,
+ CMARK_OPT_DEFAULT);
+\f[]
+.fi
+.PP
+Streaming interface:
+.IP
+.nf
+\f[C]
+cmark_parser *parser = cmark_parser_new(CMARK_OPT_DEFAULT);
+FILE *fp = fopen("myfile.md", "rb");
+while ((bytes = fread(buffer, 1, sizeof(buffer), fp)) > 0) {
+ cmark_parser_feed(parser, buffer, bytes);
+ if (bytes < sizeof(buffer)) {
+ break;
+ }
+}
+document = cmark_parser_finish(parser);
+cmark_parser_free(parser);
+\f[]
+.fi
+
+.PP
+\fIcmark_parser *\f[] \fBcmark_parser_new\f[](\fIint options\f[])
+
+.PP
+Creates a new parser object.
+
+.PP
+\fIcmark_parser *\f[] \fBcmark_parser_new_with_mem\f[](\fIint options\f[], \fIcmark_mem *mem\f[])
+
+.PP
+Creates a new parser object with the given memory allocator
+.PP
+A generalization of \f[C]cmark_parser_new\f[]:
+.IP
+.nf
+\f[C]
+cmark_parser_new(options)
+\f[]
+.fi
+.PP
+is the same as:
+.IP
+.nf
+\f[C]
+cmark_parser_new_with_mem(options, cmark_get_default_mem_allocator())
+\f[]
+.fi
+
+.PP
+\fIcmark_parser *\f[] \fBcmark_parser_new_with_mem_into_root\f[](\fIint options\f[], \fIcmark_mem *mem\f[], \fIcmark_node *root\f[])
+
+.PP
+Creates a new parser object with the given node to use as the root node
+of the parsed AST.
+.PP
+When parsing, children are always appended, not prepended; that means if
+\f[C]root\f[] already has children, the newly\-parsed children will
+appear after the given children.
+.PP
+A generalization of \f[C]cmark_parser_new_with_mem\f[]:
+.IP
+.nf
+\f[C]
+cmark_parser_new_with_mem(options, mem)
+\f[]
+.fi
+.PP
+is approximately the same as:
+.IP
+.nf
+\f[C]
+cmark_parser_new_with_mem_into_root(options, mem, cmark_node_new(CMARK_NODE_DOCUMENT))
+\f[]
+.fi
+.PP
+This is useful for creating a single document out of multiple parsed
+document fragments.
+
+.PP
+\fIvoid\f[] \fBcmark_parser_free\f[](\fIcmark_parser *parser\f[])
+
+.PP
+Frees memory allocated for a parser object.
+
+.PP
+\fIvoid\f[] \fBcmark_parser_feed\f[](\fIcmark_parser *parser\f[], \fIconst char *buffer\f[], \fIsize_t len\f[])
+
+.PP
+Feeds a string of length \f[I]len\f[] to \f[I]parser\f[].
+
+.PP
+\fIcmark_node *\f[] \fBcmark_parser_finish\f[](\fIcmark_parser *parser\f[])
+
+.PP
+Finish parsing and return a pointer to a tree of nodes.
+
+.PP
+\fIcmark_node *\f[] \fBcmark_parse_document\f[](\fIconst char *buffer\f[], \fIsize_t len\f[], \fIint options\f[])
+
+.PP
+Parse a CommonMark document in \f[I]buffer\f[] of length \f[I]len\f[].
+Returns a pointer to a tree of nodes. The memory allocated for the node
+tree should be released using \f[I]cmark_node_free\f[] when it is no
+longer needed.
+
+.PP
+\fIcmark_node *\f[] \fBcmark_parse_file\f[](\fIFILE *f\f[], \fIint options\f[])
+
+.PP
+Parse a CommonMark document in file \f[I]f\f[], returning a pointer to a
+tree of nodes. The memory allocated for the node tree should be released
+using \f[I]cmark_node_free\f[] when it is no longer needed.
+
+.SS
+Rendering
+
+.PP
+\fIchar *\f[] \fBcmark_render_xml\f[](\fIcmark_node *root\f[], \fIint options\f[])
+
+.PP
+Render a \f[I]node\f[] tree as XML. It is the caller's responsibility to
+free the returned buffer.
+
+.PP
+\fIchar *\f[] \fBcmark_render_html\f[](\fIcmark_node *root\f[], \fIint options\f[])
+
+.PP
+Render a \f[I]node\f[] tree as an HTML fragment. It is up to the user to
+add an appropriate header and footer. It is the caller's responsibility
+to free the returned buffer.
+
+.PP
+\fIchar *\f[] \fBcmark_render_man\f[](\fIcmark_node *root\f[], \fIint options\f[], \fIint width\f[])
+
+.PP
+Render a \f[I]node\f[] tree as a groff man page, without the header. It
+is the caller's responsibility to free the returned buffer.
+
+.PP
+\fIchar *\f[] \fBcmark_render_commonmark\f[](\fIcmark_node *root\f[], \fIint options\f[], \fIint width\f[])
+
+.PP
+Render a \f[I]node\f[] tree as a commonmark document. It is the caller's
+responsibility to free the returned buffer.
+
+.PP
+\fIchar *\f[] \fBcmark_render_latex\f[](\fIcmark_node *root\f[], \fIint options\f[], \fIint width\f[])
+
+.PP
+Render a \f[I]node\f[] tree as a LaTeX document. It is the caller's
+responsibility to free the returned buffer.
+
+.SS
+Options
+
+.PP
+.nf
+\fC
+.RS 0n
+#define CMARK_OPT_DEFAULT 0
+.RE
+\f[]
+.fi
+
+.PP
+Default options.
+
+.SS
+Options affecting rendering
+
+.PP
+.nf
+\fC
+.RS 0n
+#define CMARK_OPT_SOURCEPOS (1 << 1)
+.RE
+\f[]
+.fi
+
+.PP
+Include a \f[C]data\-sourcepos\f[] attribute on all block elements.
+
+.PP
+.nf
+\fC
+.RS 0n
+#define CMARK_OPT_HARDBREAKS (1 << 2)
+.RE
+\f[]
+.fi
+
+.PP
+Render \f[C]softbreak\f[] elements as hard line breaks.
+
+.PP
+.nf
+\fC
+.RS 0n
+#define CMARK_OPT_SAFE (1 << 3)
+.RE
+\f[]
+.fi
+
+.PP
+\f[C]CMARK_OPT_SAFE\f[] is defined here for API compatibility, but it no
+longer has any effect. "Safe" mode is now the default: set
+\f[C]CMARK_OPT_UNSAFE\f[] to disable it.
+
+.PP
+.nf
+\fC
+.RS 0n
+#define CMARK_OPT_UNSAFE (1 << 17)
+.RE
+\f[]
+.fi
+
+.PP
+Render raw HTML and unsafe links (\f[C]javascript:\f[],
+\f[C]vbscript:\f[], \f[C]file:\f[], and \f[C]data:\f[], except for
+\f[C]image/png\f[], \f[C]image/gif\f[], \f[C]image/jpeg\f[], or
+\f[C]image/webp\f[] mime types). By default, raw HTML is replaced by a
+placeholder HTML comment. Unsafe links are replaced by empty strings.
+
+.PP
+.nf
+\fC
+.RS 0n
+#define CMARK_OPT_NOBREAKS (1 << 4)
+.RE
+\f[]
+.fi
+
+.PP
+Render \f[C]softbreak\f[] elements as spaces.
+
+.SS
+Options affecting parsing
+
+.PP
+.nf
+\fC
+.RS 0n
+#define CMARK_OPT_NORMALIZE (1 << 8)
+.RE
+\f[]
+.fi
+
+.PP
+Legacy option (no effect).
+
+.PP
+.nf
+\fC
+.RS 0n
+#define CMARK_OPT_VALIDATE_UTF8 (1 << 9)
+.RE
+\f[]
+.fi
+
+.PP
+Validate UTF\-8 in the input before parsing, replacing illegal sequences
+with the replacement character U+FFFD.
+
+.PP
+.nf
+\fC
+.RS 0n
+#define CMARK_OPT_SMART (1 << 10)
+.RE
+\f[]
+.fi
+
+.PP
+Convert straight quotes to curly, \f[C]\-\-\-\f[] to em dashes,
+\f[C]\-\-\f[] to en dashes.
+
+.SS
+Version information
+
+.PP
+\fIint\f[] \fBcmark_version\f[](\fIvoid\f[])
+
+.PP
+The library version as integer for runtime checks. Also available as
+macro CMARK_VERSION for compile time checks.
+.IP \[bu] 2
+Bits 16\-23 contain the major version.
+.IP \[bu] 2
+Bits 8\-15 contain the minor version.
+.IP \[bu] 2
+Bits 0\-7 contain the patchlevel.
+.PP
+In hexadecimal format, the number 0x010203 represents version 1.2.3.
+
+.PP
+\fIconst char *\f[] \fBcmark_version_string\f[](\fIvoid\f[])
+
+.PP
+The library version string for runtime checks. Also available as macro
+CMARK_VERSION_STRING for compile time checks.
+
+.SH
+AUTHORS
+.PP
+John MacFarlane, Vicent Marti, Kārlis Gaņģis, Nick Wellnhofer.
+
diff --git a/cmark/nmake.bat b/cmark/nmake.bat
new file mode 100644
index 0000000000..cd4045326c
--- /dev/null
+++ b/cmark/nmake.bat
@@ -0,0 +1 @@
+@nmake.exe /nologo /f Makefile.nmake %*
diff --git a/cmark/shell.nix b/cmark/shell.nix
new file mode 100644
index 0000000000..3e96dfb112
--- /dev/null
+++ b/cmark/shell.nix
@@ -0,0 +1,12 @@
+with (import <nixpkgs> {});
+mkShell {
+ buildInputs = [
+ clangStdenv
+ cmake
+ gdb
+ python3
+ perl
+ re2c
+ curl
+ ];
+}
diff --git a/cmark/src/CMakeLists.txt b/cmark/src/CMakeLists.txt
new file mode 100644
index 0000000000..523b2cb82b
--- /dev/null
+++ b/cmark/src/CMakeLists.txt
@@ -0,0 +1,100 @@
+
+configure_file(cmark_version.h.in
+ ${CMAKE_CURRENT_BINARY_DIR}/cmark_version.h)
+configure_file(libcmark.pc.in
+ ${CMAKE_CURRENT_BINARY_DIR}/libcmark.pc
+ @ONLY)
+
+add_library(cmark
+ blocks.c
+ buffer.c
+ cmark.c
+ cmark_ctype.c
+ commonmark.c
+ houdini_href_e.c
+ houdini_html_e.c
+ houdini_html_u.c
+ html.c
+ inlines.c
+ iterator.c
+ latex.c
+ man.c
+ node.c
+ references.c
+ render.c
+ scanners.c
+ scanners.re
+ utf8.c
+ xml.c)
+cmark_add_compile_options(cmark)
+set_target_properties(cmark PROPERTIES
+ OUTPUT_NAME "cmark"
+ # Avoid name clash between PROGRAM and LIBRARY pdb files.
+ PDB_NAME libcmark
+ POSITION_INDEPENDENT_CODE YES
+ # Include minor version and patch level in soname for now.
+ SOVERSION ${PROJECT_VERSION}
+ VERSION ${PROJECT_VERSION})
+if(NOT BUILD_SHARED_LIBS)
+ target_compile_definitions(cmark PUBLIC
+ CMARK_STATIC_DEFINE)
+endif()
+target_include_directories(cmark INTERFACE
+ $<INSTALL_INTERFACE:include>
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>)
+
+generate_export_header(cmark
+ BASE_NAME ${PROJECT_NAME})
+
+# FIXME(compnerd) this should be removed, but exists solely to allow a migration
+# path for OSS Fuzz.
+add_custom_target(cmark_static DEPENDS cmark)
+
+add_executable(cmark_exe
+ main.c)
+cmark_add_compile_options(cmark_exe)
+set_target_properties(cmark_exe PROPERTIES
+ OUTPUT_NAME "cmark"
+ INSTALL_RPATH "${Base_rpath}")
+target_link_libraries(cmark_exe PRIVATE
+ cmark)
+
+install(TARGETS cmark_exe cmark
+ EXPORT cmark-targets
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ )
+
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libcmark.pc
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
+
+install(FILES
+ cmark.h
+ ${CMAKE_CURRENT_BINARY_DIR}/cmark_export.h
+ ${CMAKE_CURRENT_BINARY_DIR}/cmark_version.h
+ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
+ )
+
+# generate cmark-config.cmake and cmark-config-version.cmake files
+configure_package_config_file(
+ "cmarkConfig.cmake.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/generated/cmark-config.cmake"
+ INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/cmark")
+write_basic_package_version_file(
+ "${CMAKE_CURRENT_BINARY_DIR}/generated/cmark-config-version.cmake"
+ VERSION ${PROJECT_VERSION}
+ COMPATIBILITY SameMajorVersion)
+# install config and version file
+install(
+ FILES "${CMAKE_CURRENT_BINARY_DIR}/generated/cmark-config.cmake"
+ "${CMAKE_CURRENT_BINARY_DIR}/generated/cmark-config-version.cmake"
+ DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/cmark"
+)
+# install targets file
+install(
+ EXPORT "cmark-targets"
+ NAMESPACE "cmark::"
+ DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/cmark"
+)
diff --git a/cmark/src/blocks.c b/cmark/src/blocks.c
new file mode 100644
index 0000000000..292e563bb6
--- /dev/null
+++ b/cmark/src/blocks.c
@@ -0,0 +1,1345 @@
+/**
+ * Block parsing implementation.
+ *
+ * For a high-level overview of the block parsing process,
+ * see http://spec.commonmark.org/0.24/#phase-1-block-structure
+ */
+
+#include <assert.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "cmark_ctype.h"
+#include "parser.h"
+#include "cmark.h"
+#include "node.h"
+#include "references.h"
+#include "utf8.h"
+#include "scanners.h"
+#include "inlines.h"
+#include "houdini.h"
+#include "buffer.h"
+#include "chunk.h"
+
+#define CODE_INDENT 4
+#define TAB_STOP 4
+
+#ifndef MIN
+#define MIN(x, y) ((x < y) ? x : y)
+#endif
+
+#define peek_at(i, n) (i)->data[n]
+
+static bool S_last_line_blank(const cmark_node *node) {
+ return (node->flags & CMARK_NODE__LAST_LINE_BLANK) != 0;
+}
+
+static bool S_last_line_checked(const cmark_node *node) {
+ return (node->flags & CMARK_NODE__LAST_LINE_CHECKED) != 0;
+}
+
+static inline cmark_node_type S_type(const cmark_node *node) {
+ return (cmark_node_type)node->type;
+}
+
+static void S_set_last_line_blank(cmark_node *node, bool is_blank) {
+ if (is_blank)
+ node->flags |= CMARK_NODE__LAST_LINE_BLANK;
+ else
+ node->flags &= ~CMARK_NODE__LAST_LINE_BLANK;
+}
+
+static void S_set_last_line_checked(cmark_node *node) {
+ node->flags |= CMARK_NODE__LAST_LINE_CHECKED;
+}
+
+static inline bool S_is_line_end_char(char c) {
+ return (c == '\n' || c == '\r');
+}
+
+static inline bool S_is_space_or_tab(char c) {
+ return (c == ' ' || c == '\t');
+}
+
+static void S_parser_feed(cmark_parser *parser, const unsigned char *buffer,
+ size_t len, bool eof);
+
+static void S_process_line(cmark_parser *parser, const unsigned char *buffer,
+ bufsize_t bytes);
+
+static cmark_node *make_block(cmark_mem *mem, cmark_node_type tag,
+ int start_line, int start_column) {
+ cmark_node *e;
+
+ e = (cmark_node *)mem->calloc(1, sizeof(*e));
+ e->mem = mem;
+ e->type = (uint16_t)tag;
+ e->flags = CMARK_NODE__OPEN;
+ e->start_line = start_line;
+ e->start_column = start_column;
+ e->end_line = start_line;
+
+ return e;
+}
+
+// Create a root document node.
+static cmark_node *make_document(cmark_mem *mem) {
+ cmark_node *e = make_block(mem, CMARK_NODE_DOCUMENT, 1, 1);
+ return e;
+}
+
+cmark_parser *cmark_parser_new_with_mem_into_root(int options, cmark_mem *mem, cmark_node *root) {
+ cmark_parser *parser = (cmark_parser *)mem->calloc(1, sizeof(cmark_parser));
+ parser->mem = mem;
+
+ cmark_strbuf_init(mem, &parser->curline, 256);
+ cmark_strbuf_init(mem, &parser->linebuf, 0);
+ cmark_strbuf_init(mem, &parser->content, 0);
+
+ root->flags = CMARK_NODE__OPEN;
+
+ parser->refmap = cmark_reference_map_new(mem);
+ parser->root = root;
+ parser->current = root;
+ parser->line_number = 0;
+ parser->offset = 0;
+ parser->column = 0;
+ parser->first_nonspace = 0;
+ parser->first_nonspace_column = 0;
+ parser->thematic_break_kill_pos = 0;
+ parser->indent = 0;
+ parser->blank = false;
+ parser->partially_consumed_tab = false;
+ parser->last_line_length = 0;
+ parser->options = options;
+ parser->last_buffer_ended_with_cr = false;
+
+ return parser;
+}
+
+cmark_parser *cmark_parser_new_with_mem(int options, cmark_mem *mem) {
+ cmark_node *document = make_document(mem);
+ return cmark_parser_new_with_mem_into_root(options, mem, document);
+}
+
+cmark_parser *cmark_parser_new(int options) {
+ extern cmark_mem DEFAULT_MEM_ALLOCATOR;
+ return cmark_parser_new_with_mem(options, &DEFAULT_MEM_ALLOCATOR);
+}
+
+void cmark_parser_free(cmark_parser *parser) {
+ cmark_mem *mem = parser->mem;
+ cmark_strbuf_free(&parser->curline);
+ cmark_strbuf_free(&parser->linebuf);
+ cmark_reference_map_free(parser->refmap);
+ mem->free(parser);
+}
+
+static cmark_node *finalize(cmark_parser *parser, cmark_node *b);
+
+// Returns true if line has only space characters, else false.
+static bool is_blank(cmark_strbuf *s, bufsize_t offset) {
+ while (offset < s->size) {
+ switch (s->ptr[offset]) {
+ case '\r':
+ case '\n':
+ return true;
+ case ' ':
+ offset++;
+ break;
+ case '\t':
+ offset++;
+ break;
+ default:
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static inline bool can_contain(cmark_node_type parent_type,
+ cmark_node_type child_type) {
+ return (parent_type == CMARK_NODE_DOCUMENT ||
+ parent_type == CMARK_NODE_BLOCK_QUOTE ||
+ parent_type == CMARK_NODE_ITEM ||
+ (parent_type == CMARK_NODE_LIST && child_type == CMARK_NODE_ITEM));
+}
+
+static inline bool accepts_lines(cmark_node_type block_type) {
+ return (block_type == CMARK_NODE_PARAGRAPH ||
+ block_type == CMARK_NODE_HEADING ||
+ block_type == CMARK_NODE_CODE_BLOCK);
+}
+
+static inline bool contains_inlines(cmark_node_type block_type) {
+ return (block_type == CMARK_NODE_PARAGRAPH ||
+ block_type == CMARK_NODE_HEADING);
+}
+
+static void add_line(cmark_chunk *ch, cmark_parser *parser) {
+ int chars_to_tab;
+ int i;
+ if (parser->partially_consumed_tab) {
+ parser->offset += 1; // skip over tab
+ // add space characters:
+ chars_to_tab = TAB_STOP - (parser->column % TAB_STOP);
+ for (i = 0; i < chars_to_tab; i++) {
+ cmark_strbuf_putc(&parser->content, ' ');
+ }
+ }
+ cmark_strbuf_put(&parser->content, ch->data + parser->offset,
+ ch->len - parser->offset);
+}
+
+static void remove_trailing_blank_lines(cmark_strbuf *ln) {
+ bufsize_t i;
+ unsigned char c;
+
+ for (i = ln->size - 1; i >= 0; --i) {
+ c = ln->ptr[i];
+
+ if (c != ' ' && c != '\t' && !S_is_line_end_char(c))
+ break;
+ }
+
+ if (i < 0) {
+ cmark_strbuf_clear(ln);
+ return;
+ }
+
+ for (; i < ln->size; ++i) {
+ c = ln->ptr[i];
+
+ if (!S_is_line_end_char(c))
+ continue;
+
+ cmark_strbuf_truncate(ln, i);
+ break;
+ }
+}
+
+// Check to see if a node ends with a blank line, descending
+// if needed into lists and sublists.
+static bool S_ends_with_blank_line(cmark_node *node) {
+ if (S_last_line_checked(node)) {
+ return(S_last_line_blank(node));
+ } else if ((S_type(node) == CMARK_NODE_LIST ||
+ S_type(node) == CMARK_NODE_ITEM) && node->last_child) {
+ S_set_last_line_checked(node);
+ return(S_ends_with_blank_line(node->last_child));
+ } else {
+ S_set_last_line_checked(node);
+ return (S_last_line_blank(node));
+ }
+}
+
+// returns true if content remains after link defs are resolved.
+static bool resolve_reference_link_definitions(cmark_parser *parser) {
+ bufsize_t pos;
+ cmark_strbuf *node_content = &parser->content;
+ cmark_chunk chunk = {node_content->ptr, node_content->size};
+ while (chunk.len && chunk.data[0] == '[' &&
+ (pos = cmark_parse_reference_inline(parser->mem, &chunk,
+ parser->refmap))) {
+
+ chunk.data += pos;
+ chunk.len -= pos;
+ }
+ cmark_strbuf_drop(node_content, (node_content->size - chunk.len));
+ return !is_blank(node_content, 0);
+}
+
+static cmark_node *finalize(cmark_parser *parser, cmark_node *b) {
+ bufsize_t pos;
+ cmark_node *item;
+ cmark_node *subitem;
+ cmark_node *parent;
+ bool has_content;
+
+ parent = b->parent;
+ assert(b->flags &
+ CMARK_NODE__OPEN); // shouldn't call finalize on closed blocks
+ b->flags &= ~CMARK_NODE__OPEN;
+
+ if (parser->curline.size == 0) {
+ // end of input - line number has not been incremented
+ b->end_line = parser->line_number;
+ b->end_column = parser->last_line_length;
+ } else if (S_type(b) == CMARK_NODE_DOCUMENT ||
+ (S_type(b) == CMARK_NODE_CODE_BLOCK && b->as.code.fenced) ||
+ (S_type(b) == CMARK_NODE_HEADING && b->as.heading.setext)) {
+ b->end_line = parser->line_number;
+ b->end_column = parser->curline.size;
+ if (b->end_column && parser->curline.ptr[b->end_column - 1] == '\n')
+ b->end_column -= 1;
+ if (b->end_column && parser->curline.ptr[b->end_column - 1] == '\r')
+ b->end_column -= 1;
+ } else {
+ b->end_line = parser->line_number - 1;
+ b->end_column = parser->last_line_length;
+ }
+
+ cmark_strbuf *node_content = &parser->content;
+
+ switch (S_type(b)) {
+ case CMARK_NODE_PARAGRAPH:
+ {
+ has_content = resolve_reference_link_definitions(parser);
+ if (!has_content) {
+ // remove blank node (former reference def)
+ cmark_node_free(b);
+ } else {
+ b->len = node_content->size;
+ b->data = cmark_strbuf_detach(node_content);
+ }
+ break;
+ }
+
+ case CMARK_NODE_CODE_BLOCK:
+ if (!b->as.code.fenced) { // indented code
+ remove_trailing_blank_lines(node_content);
+ cmark_strbuf_putc(node_content, '\n');
+ } else {
+ // first line of contents becomes info
+ for (pos = 0; pos < node_content->size; ++pos) {
+ if (S_is_line_end_char(node_content->ptr[pos]))
+ break;
+ }
+ assert(pos < node_content->size);
+
+ if (pos == 0) {
+ b->as.code.info = NULL;
+ } else {
+ cmark_strbuf tmp = CMARK_BUF_INIT(parser->mem);
+ houdini_unescape_html_f(&tmp, node_content->ptr, pos);
+ cmark_strbuf_trim(&tmp);
+ cmark_strbuf_unescape(&tmp);
+ b->as.code.info = cmark_strbuf_detach(&tmp);
+ }
+
+ if (node_content->ptr[pos] == '\r')
+ pos += 1;
+ if (node_content->ptr[pos] == '\n')
+ pos += 1;
+ cmark_strbuf_drop(node_content, pos);
+ }
+ b->len = node_content->size;
+ b->data = cmark_strbuf_detach(node_content);
+ break;
+
+ case CMARK_NODE_HEADING:
+ case CMARK_NODE_HTML_BLOCK:
+ b->len = node_content->size;
+ b->data = cmark_strbuf_detach(node_content);
+ break;
+
+ case CMARK_NODE_LIST: // determine tight/loose status
+ b->as.list.tight = true; // tight by default
+ item = b->first_child;
+
+ while (item) {
+ // check for non-final non-empty list item ending with blank line:
+ if (S_last_line_blank(item) && item->next) {
+ b->as.list.tight = false;
+ break;
+ }
+ // recurse into children of list item, to see if there are
+ // spaces between them:
+ subitem = item->first_child;
+ while (subitem) {
+ if ((item->next || subitem->next) &&
+ S_ends_with_blank_line(subitem)) {
+ b->as.list.tight = false;
+ break;
+ }
+ subitem = subitem->next;
+ }
+ if (!(b->as.list.tight)) {
+ break;
+ }
+ item = item->next;
+ }
+
+ break;
+
+ default:
+ break;
+ }
+
+ return parent;
+}
+
+// Add a node as child of another. Return pointer to child.
+static cmark_node *add_child(cmark_parser *parser, cmark_node *parent,
+ cmark_node_type block_type, int start_column) {
+ assert(parent);
+
+ // if 'parent' isn't the kind of node that can accept this child,
+ // then back up til we hit a node that can.
+ while (!can_contain(S_type(parent), block_type)) {
+ parent = finalize(parser, parent);
+ }
+
+ cmark_node *child =
+ make_block(parser->mem, block_type, parser->line_number, start_column);
+ child->parent = parent;
+
+ if (parent->last_child) {
+ parent->last_child->next = child;
+ child->prev = parent->last_child;
+ } else {
+ parent->first_child = child;
+ child->prev = NULL;
+ }
+ parent->last_child = child;
+ return child;
+}
+
+// Walk through node and all children, recursively, parsing
+// string content into inline content where appropriate.
+static void process_inlines(cmark_mem *mem, cmark_node *root,
+ cmark_reference_map *refmap, int options) {
+ cmark_iter *iter = cmark_iter_new(root);
+ cmark_node *cur;
+ cmark_event_type ev_type;
+
+ while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
+ cur = cmark_iter_get_node(iter);
+ if (ev_type == CMARK_EVENT_ENTER) {
+ if (contains_inlines(S_type(cur))) {
+ cmark_parse_inlines(mem, cur, refmap, options);
+ mem->free(cur->data);
+ cur->data = NULL;
+ cur->len = 0;
+ }
+ }
+ }
+
+ cmark_iter_free(iter);
+}
+
+// Attempts to parse a list item marker (bullet or enumerated).
+// On success, returns length of the marker, and populates
+// data with the details. On failure, returns 0.
+static bufsize_t parse_list_marker(cmark_mem *mem, cmark_chunk *input,
+ bufsize_t pos, bool interrupts_paragraph,
+ cmark_list **dataptr) {
+ unsigned char c;
+ bufsize_t startpos;
+ cmark_list *data;
+ bufsize_t i;
+
+ startpos = pos;
+ c = peek_at(input, pos);
+
+ if (c == '*' || c == '-' || c == '+') {
+ pos++;
+ if (!cmark_isspace(peek_at(input, pos))) {
+ return 0;
+ }
+
+ if (interrupts_paragraph) {
+ i = pos;
+ // require non-blank content after list marker:
+ while (S_is_space_or_tab(peek_at(input, i))) {
+ i++;
+ }
+ if (peek_at(input, i) == '\n') {
+ return 0;
+ }
+ }
+
+ data = (cmark_list *)mem->calloc(1, sizeof(*data));
+ data->marker_offset = 0; // will be adjusted later
+ data->list_type = CMARK_BULLET_LIST;
+ data->bullet_char = c;
+ data->start = 0;
+ data->delimiter = CMARK_NO_DELIM;
+ data->tight = false;
+ } else if (cmark_isdigit(c)) {
+ int start = 0;
+ int digits = 0;
+
+ do {
+ start = (10 * start) + (peek_at(input, pos) - '0');
+ pos++;
+ digits++;
+ // We limit to 9 digits to avoid overflow,
+ // assuming max int is 2^31 - 1
+ // This also seems to be the limit for 'start' in some browsers.
+ } while (digits < 9 && cmark_isdigit(peek_at(input, pos)));
+
+ if (interrupts_paragraph && start != 1) {
+ return 0;
+ }
+ c = peek_at(input, pos);
+ if (c == '.' || c == ')') {
+ pos++;
+ if (!cmark_isspace(peek_at(input, pos))) {
+ return 0;
+ }
+ if (interrupts_paragraph) {
+ // require non-blank content after list marker:
+ i = pos;
+ while (S_is_space_or_tab(peek_at(input, i))) {
+ i++;
+ }
+ if (S_is_line_end_char(peek_at(input, i))) {
+ return 0;
+ }
+ }
+
+ data = (cmark_list *)mem->calloc(1, sizeof(*data));
+ data->marker_offset = 0; // will be adjusted later
+ data->list_type = CMARK_ORDERED_LIST;
+ data->bullet_char = 0;
+ data->start = start;
+ data->delimiter = (c == '.' ? CMARK_PERIOD_DELIM : CMARK_PAREN_DELIM);
+ data->tight = false;
+ } else {
+ return 0;
+ }
+ } else {
+ return 0;
+ }
+
+ *dataptr = data;
+ return (pos - startpos);
+}
+
+// Return 1 if list item belongs in list, else 0.
+static int lists_match(cmark_list *list_data, cmark_list *item_data) {
+ return (list_data->list_type == item_data->list_type &&
+ list_data->delimiter == item_data->delimiter &&
+ // list_data->marker_offset == item_data.marker_offset &&
+ list_data->bullet_char == item_data->bullet_char);
+}
+
+static cmark_node *finalize_document(cmark_parser *parser) {
+ while (parser->current != parser->root) {
+ parser->current = finalize(parser, parser->current);
+ }
+
+ finalize(parser, parser->root);
+
+ // Limit total size of extra content created from reference links to
+ // document size to avoid superlinear growth. Always allow 100KB.
+ if (parser->total_size > 100000)
+ parser->refmap->max_ref_size = parser->total_size;
+ else
+ parser->refmap->max_ref_size = 100000;
+
+ process_inlines(parser->mem, parser->root, parser->refmap, parser->options);
+
+ cmark_strbuf_free(&parser->content);
+
+ return parser->root;
+}
+
+cmark_node *cmark_parse_file(FILE *f, int options) {
+ unsigned char buffer[4096];
+ cmark_parser *parser = cmark_parser_new(options);
+ size_t bytes;
+ cmark_node *document;
+
+ while ((bytes = fread(buffer, 1, sizeof(buffer), f)) > 0) {
+ bool eof = bytes < sizeof(buffer);
+ S_parser_feed(parser, buffer, bytes, eof);
+ if (eof) {
+ break;
+ }
+ }
+
+ document = cmark_parser_finish(parser);
+ cmark_parser_free(parser);
+ return document;
+}
+
+cmark_node *cmark_parse_document(const char *buffer, size_t len, int options) {
+ cmark_parser *parser = cmark_parser_new(options);
+ cmark_node *document;
+
+ S_parser_feed(parser, (const unsigned char *)buffer, len, true);
+
+ document = cmark_parser_finish(parser);
+ cmark_parser_free(parser);
+ return document;
+}
+
+void cmark_parser_feed(cmark_parser *parser, const char *buffer, size_t len) {
+ S_parser_feed(parser, (const unsigned char *)buffer, len, false);
+}
+
+static void S_parser_feed(cmark_parser *parser, const unsigned char *buffer,
+ size_t len, bool eof) {
+ const unsigned char *end = buffer + len;
+ static const uint8_t repl[] = {239, 191, 189};
+
+ if (len > UINT_MAX - parser->total_size)
+ parser->total_size = UINT_MAX;
+ else
+ parser->total_size += (int)len;
+
+ // Skip UTF-8 BOM if present; see #334
+ if (parser->line_number == 0 && parser->column == 0 && len >= 3 &&
+ *buffer == 0xEF && *(buffer + 1) == 0xBB &&
+ *(buffer + 2) == 0xBF) {
+ buffer += 3;
+ } else if (parser->last_buffer_ended_with_cr && *buffer == '\n') {
+ // skip NL if last buffer ended with CR ; see #117
+ buffer++;
+ }
+
+ parser->last_buffer_ended_with_cr = false;
+ while (buffer < end) {
+ const unsigned char *eol;
+ bufsize_t chunk_len;
+ bool process = false;
+ for (eol = buffer; eol < end; ++eol) {
+ if (S_is_line_end_char(*eol)) {
+ process = true;
+ break;
+ }
+ if (*eol == '\0' && eol < end) {
+ break;
+ }
+ }
+ if (eol >= end && eof) {
+ process = true;
+ }
+
+ chunk_len = (eol - buffer);
+ if (process) {
+ if (parser->linebuf.size > 0) {
+ cmark_strbuf_put(&parser->linebuf, buffer, chunk_len);
+ S_process_line(parser, parser->linebuf.ptr, parser->linebuf.size);
+ cmark_strbuf_clear(&parser->linebuf);
+ } else {
+ S_process_line(parser, buffer, chunk_len);
+ }
+ } else {
+ if (eol < end && *eol == '\0') {
+ // omit NULL byte
+ cmark_strbuf_put(&parser->linebuf, buffer, chunk_len);
+ // add replacement character
+ cmark_strbuf_put(&parser->linebuf, repl, 3);
+ } else {
+ cmark_strbuf_put(&parser->linebuf, buffer, chunk_len);
+ }
+ }
+
+ buffer += chunk_len;
+ if (buffer < end) {
+ if (*buffer == '\0') {
+ // skip over NULL
+ buffer++;
+ } else {
+ // skip over line ending characters
+ if (*buffer == '\r') {
+ buffer++;
+ if (buffer == end)
+ parser->last_buffer_ended_with_cr = true;
+ }
+ if (buffer < end && *buffer == '\n')
+ buffer++;
+ }
+ }
+ }
+}
+
+static void chop_trailing_hashtags(cmark_chunk *ch) {
+ bufsize_t n, orig_n;
+
+ cmark_chunk_rtrim(ch);
+ orig_n = n = ch->len - 1;
+
+ // if string ends in space followed by #s, remove these:
+ while (n >= 0 && peek_at(ch, n) == '#')
+ n--;
+
+ // Check for a space before the final #s:
+ if (n != orig_n && n >= 0 && S_is_space_or_tab(peek_at(ch, n))) {
+ ch->len = n;
+ cmark_chunk_rtrim(ch);
+ }
+}
+
+// Check for thematic break. On failure, return 0 and update
+// thematic_break_kill_pos with the index at which the
+// parse fails. On success, return length of match.
+// "...three or more hyphens, asterisks,
+// or underscores on a line by themselves. If you wish, you may use
+// spaces between the hyphens or asterisks."
+static int S_scan_thematic_break(cmark_parser *parser, cmark_chunk *input,
+ bufsize_t offset) {
+ bufsize_t i;
+ char c;
+ char nextc = '\0';
+ int count;
+ i = offset;
+ c = peek_at(input, i);
+ if (!(c == '*' || c == '_' || c == '-')) {
+ parser->thematic_break_kill_pos = i;
+ return 0;
+ }
+ count = 1;
+ while ((nextc = peek_at(input, ++i))) {
+ if (nextc == c) {
+ count++;
+ } else if (nextc != ' ' && nextc != '\t') {
+ break;
+ }
+ }
+ if (count >= 3 && (nextc == '\r' || nextc == '\n')) {
+ return (i - offset) + 1;
+ } else {
+ parser->thematic_break_kill_pos = i;
+ return 0;
+ }
+}
+
+// Find first nonspace character from current offset, setting
+// parser->first_nonspace, parser->first_nonspace_column,
+// parser->indent, and parser->blank. Does not advance parser->offset.
+static void S_find_first_nonspace(cmark_parser *parser, cmark_chunk *input) {
+ char c;
+ int chars_to_tab = TAB_STOP - (parser->column % TAB_STOP);
+
+ if (parser->first_nonspace <= parser->offset) {
+ parser->first_nonspace = parser->offset;
+ parser->first_nonspace_column = parser->column;
+ while ((c = peek_at(input, parser->first_nonspace))) {
+ if (c == ' ') {
+ parser->first_nonspace += 1;
+ parser->first_nonspace_column += 1;
+ chars_to_tab = chars_to_tab - 1;
+ if (chars_to_tab == 0) {
+ chars_to_tab = TAB_STOP;
+ }
+ } else if (c == '\t') {
+ parser->first_nonspace += 1;
+ parser->first_nonspace_column += chars_to_tab;
+ chars_to_tab = TAB_STOP;
+ } else {
+ break;
+ }
+ }
+ }
+
+ parser->indent = parser->first_nonspace_column - parser->column;
+ parser->blank = S_is_line_end_char(peek_at(input, parser->first_nonspace));
+}
+
+// Advance parser->offset and parser->column. parser->offset is the
+// byte position in input; parser->column is a virtual column number
+// that takes into account tabs. (Multibyte characters are not taken
+// into account, because the Markdown line prefixes we are interested in
+// analyzing are entirely ASCII.) The count parameter indicates
+// how far to advance the offset. If columns is true, then count
+// indicates a number of columns; otherwise, a number of bytes.
+// If advancing a certain number of columns partially consumes
+// a tab character, parser->partially_consumed_tab is set to true.
+static void S_advance_offset(cmark_parser *parser, cmark_chunk *input,
+ bufsize_t count, bool columns) {
+ char c;
+ int chars_to_tab;
+ int chars_to_advance;
+ while (count > 0 && (c = peek_at(input, parser->offset))) {
+ if (c == '\t') {
+ chars_to_tab = TAB_STOP - (parser->column % TAB_STOP);
+ if (columns) {
+ parser->partially_consumed_tab = chars_to_tab > count;
+ chars_to_advance = MIN(count, chars_to_tab);
+ parser->column += chars_to_advance;
+ parser->offset += (parser->partially_consumed_tab ? 0 : 1);
+ count -= chars_to_advance;
+ } else {
+ parser->partially_consumed_tab = false;
+ parser->column += chars_to_tab;
+ parser->offset += 1;
+ count -= 1;
+ }
+ } else {
+ parser->partially_consumed_tab = false;
+ parser->offset += 1;
+ parser->column += 1; // assume ascii; block starts are ascii
+ count -= 1;
+ }
+ }
+}
+
+static bool S_last_child_is_open(cmark_node *container) {
+ return container->last_child &&
+ (container->last_child->flags & CMARK_NODE__OPEN);
+}
+
+static bool parse_block_quote_prefix(cmark_parser *parser, cmark_chunk *input) {
+ bool res = false;
+ bufsize_t matched = 0;
+
+ matched =
+ parser->indent <= 3 && peek_at(input, parser->first_nonspace) == '>';
+ if (matched) {
+
+ S_advance_offset(parser, input, parser->indent + 1, true);
+
+ if (S_is_space_or_tab(peek_at(input, parser->offset))) {
+ S_advance_offset(parser, input, 1, true);
+ }
+
+ res = true;
+ }
+ return res;
+}
+
+static bool parse_node_item_prefix(cmark_parser *parser, cmark_chunk *input,
+ cmark_node *container) {
+ bool res = false;
+
+ if (parser->indent >=
+ container->as.list.marker_offset + container->as.list.padding) {
+ S_advance_offset(parser, input, container->as.list.marker_offset +
+ container->as.list.padding,
+ true);
+ res = true;
+ } else if (parser->blank && container->first_child != NULL) {
+ // if container->first_child is NULL, then the opening line
+ // of the list item was blank after the list marker; in this
+ // case, we are done with the list item.
+ S_advance_offset(parser, input, parser->first_nonspace - parser->offset,
+ false);
+ res = true;
+ }
+ return res;
+}
+
+static bool parse_code_block_prefix(cmark_parser *parser, cmark_chunk *input,
+ cmark_node *container,
+ bool *should_continue) {
+ bool res = false;
+
+ if (!container->as.code.fenced) { // indented
+ if (parser->indent >= CODE_INDENT) {
+ S_advance_offset(parser, input, CODE_INDENT, true);
+ res = true;
+ } else if (parser->blank) {
+ S_advance_offset(parser, input, parser->first_nonspace - parser->offset,
+ false);
+ res = true;
+ }
+ } else { // fenced
+ bufsize_t matched = 0;
+
+ if (parser->indent <= 3 && (peek_at(input, parser->first_nonspace) ==
+ container->as.code.fence_char)) {
+ matched = scan_close_code_fence(input, parser->first_nonspace);
+ }
+
+ if (matched >= container->as.code.fence_length) {
+ // closing fence - and since we're at
+ // the end of a line, we can stop processing it:
+ *should_continue = false;
+ S_advance_offset(parser, input, matched, false);
+ parser->current = finalize(parser, container);
+ } else {
+ // skip opt. spaces of fence parser->offset
+ int i = container->as.code.fence_offset;
+
+ while (i > 0 && S_is_space_or_tab(peek_at(input, parser->offset))) {
+ S_advance_offset(parser, input, 1, true);
+ i--;
+ }
+ res = true;
+ }
+ }
+
+ return res;
+}
+
+static bool parse_html_block_prefix(cmark_parser *parser,
+ cmark_node *container) {
+ bool res = false;
+ int html_block_type = container->as.html_block_type;
+
+ assert(html_block_type >= 1 && html_block_type <= 7);
+ switch (html_block_type) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ // these types of blocks can accept blanks
+ res = true;
+ break;
+ case 6:
+ case 7:
+ res = !parser->blank;
+ break;
+ }
+
+ return res;
+}
+
+/**
+ * For each containing node, try to parse the associated line start.
+ *
+ * Will not close unmatched blocks, as we may have a lazy continuation
+ * line -> http://spec.commonmark.org/0.24/#lazy-continuation-line
+ *
+ * Returns: The last matching node, or NULL
+ */
+static cmark_node *check_open_blocks(cmark_parser *parser, cmark_chunk *input,
+ bool *all_matched) {
+ bool should_continue = true;
+ *all_matched = false;
+ cmark_node *container = parser->root;
+ cmark_node_type cont_type;
+
+ while (S_last_child_is_open(container)) {
+ container = container->last_child;
+ cont_type = S_type(container);
+
+ S_find_first_nonspace(parser, input);
+
+ switch (cont_type) {
+ case CMARK_NODE_BLOCK_QUOTE:
+ if (!parse_block_quote_prefix(parser, input))
+ goto done;
+ break;
+ case CMARK_NODE_LIST:
+ // Avoid quadratic behavior caused by iterating deeply nested lists
+ // for each blank line.
+ if (parser->blank) {
+ if (container->flags & CMARK_NODE__LIST_LAST_LINE_BLANK &&
+ parser->indent == 0) {
+ // Abort early if we encounter multiple blank lines. Returning
+ // NULL will cause S_process_line to skip the calls to
+ // open_new_blocks and add_text_to_container. open_new_blocks
+ // is a no-op for blank lines. add_text_to_container closes
+ // remaining open nodes, but since we have a second blank
+ // line, all open nodes have already been closed when the
+ // first blank line was processed. Certain block types accept
+ // empty lines as content, so add them here.
+ if (parser->current->type == CMARK_NODE_CODE_BLOCK ||
+ parser->current->type == CMARK_NODE_HTML_BLOCK) {
+ add_line(input, parser);
+ }
+ return NULL;
+ }
+ container->flags |= CMARK_NODE__LIST_LAST_LINE_BLANK;
+ } else {
+ container->flags &= ~CMARK_NODE__LIST_LAST_LINE_BLANK;
+ }
+ break;
+ case CMARK_NODE_ITEM:
+ if (!parse_node_item_prefix(parser, input, container))
+ goto done;
+ break;
+ case CMARK_NODE_CODE_BLOCK:
+ if (!parse_code_block_prefix(parser, input, container, &should_continue))
+ goto done;
+ break;
+ case CMARK_NODE_HEADING:
+ // a heading can never contain more than one line
+ goto done;
+ case CMARK_NODE_HTML_BLOCK:
+ if (!parse_html_block_prefix(parser, container))
+ goto done;
+ break;
+ case CMARK_NODE_PARAGRAPH:
+ if (parser->blank)
+ goto done;
+ break;
+ default:
+ break;
+ }
+ }
+
+ *all_matched = true;
+
+done:
+ if (!*all_matched) {
+ container = container->parent; // back up to last matching node
+ }
+
+ if (!should_continue) {
+ container = NULL;
+ }
+
+ return container;
+}
+
+static void open_new_blocks(cmark_parser *parser, cmark_node **container,
+ cmark_chunk *input, bool all_matched) {
+ bool indented;
+ cmark_list *data = NULL;
+ bool maybe_lazy = S_type(parser->current) == CMARK_NODE_PARAGRAPH;
+ cmark_node_type cont_type = S_type(*container);
+ bufsize_t matched = 0;
+ int lev = 0;
+ bool save_partially_consumed_tab;
+ bool has_content;
+ int save_offset;
+ int save_column;
+
+ while (cont_type != CMARK_NODE_CODE_BLOCK &&
+ cont_type != CMARK_NODE_HTML_BLOCK) {
+
+ S_find_first_nonspace(parser, input);
+ indented = parser->indent >= CODE_INDENT;
+
+ if (!indented && peek_at(input, parser->first_nonspace) == '>') {
+
+ bufsize_t blockquote_startpos = parser->first_nonspace;
+
+ S_advance_offset(parser, input,
+ parser->first_nonspace + 1 - parser->offset, false);
+ // optional following character
+ if (S_is_space_or_tab(peek_at(input, parser->offset))) {
+ S_advance_offset(parser, input, 1, true);
+ }
+ *container = add_child(parser, *container, CMARK_NODE_BLOCK_QUOTE,
+ blockquote_startpos + 1);
+
+ } else if (!indented && (matched = scan_atx_heading_start(
+ input, parser->first_nonspace))) {
+ bufsize_t hashpos;
+ int level = 0;
+ bufsize_t heading_startpos = parser->first_nonspace;
+
+ S_advance_offset(parser, input,
+ parser->first_nonspace + matched - parser->offset,
+ false);
+ *container = add_child(parser, *container, CMARK_NODE_HEADING,
+ heading_startpos + 1);
+
+ hashpos = cmark_chunk_strchr(input, '#', parser->first_nonspace);
+
+ while (peek_at(input, hashpos) == '#') {
+ level++;
+ hashpos++;
+ }
+
+ (*container)->as.heading.level = level;
+ (*container)->as.heading.setext = false;
+ (*container)->as.heading.internal_offset = matched;
+
+ } else if (!indented && (matched = scan_open_code_fence(
+ input, parser->first_nonspace))) {
+ *container = add_child(parser, *container, CMARK_NODE_CODE_BLOCK,
+ parser->first_nonspace + 1);
+ (*container)->as.code.fenced = true;
+ (*container)->as.code.fence_char = peek_at(input, parser->first_nonspace);
+ (*container)->as.code.fence_length = (matched > 255) ? 255 : matched;
+ (*container)->as.code.fence_offset =
+ (int8_t)(parser->first_nonspace - parser->offset);
+ (*container)->as.code.info = NULL;
+ S_advance_offset(parser, input,
+ parser->first_nonspace + matched - parser->offset,
+ false);
+
+ } else if (!indented && ((matched = scan_html_block_start(
+ input, parser->first_nonspace)) ||
+ (cont_type != CMARK_NODE_PARAGRAPH &&
+ !maybe_lazy &&
+ (matched = scan_html_block_start_7(
+ input, parser->first_nonspace))))) {
+ *container = add_child(parser, *container, CMARK_NODE_HTML_BLOCK,
+ parser->first_nonspace + 1);
+ (*container)->as.html_block_type = matched;
+ // note, we don't adjust parser->offset because the tag is part of the
+ // text
+ } else if (!indented && cont_type == CMARK_NODE_PARAGRAPH &&
+ (lev =
+ scan_setext_heading_line(input, parser->first_nonspace))) {
+ // finalize paragraph, resolving reference links
+ has_content = resolve_reference_link_definitions(parser);
+
+ if (has_content) {
+
+ (*container)->type = (uint16_t)CMARK_NODE_HEADING;
+ (*container)->as.heading.level = lev;
+ (*container)->as.heading.setext = true;
+ S_advance_offset(parser, input, input->len - 1 - parser->offset, false);
+ }
+ } else if (!indented &&
+ !(cont_type == CMARK_NODE_PARAGRAPH && !all_matched) &&
+ (parser->thematic_break_kill_pos <= parser->first_nonspace) &&
+ S_scan_thematic_break(parser, input, parser->first_nonspace)) {
+ // it's only now that we know the line is not part of a setext heading:
+ *container = add_child(parser, *container, CMARK_NODE_THEMATIC_BREAK,
+ parser->first_nonspace + 1);
+ S_advance_offset(parser, input, input->len - 1 - parser->offset, false);
+ } else if ((!indented || cont_type == CMARK_NODE_LIST) &&
+ parser->indent < 4 &&
+ (matched = parse_list_marker(
+ parser->mem, input, parser->first_nonspace,
+ (*container)->type == CMARK_NODE_PARAGRAPH, &data))) {
+
+ // Note that we can have new list items starting with >= 4
+ // spaces indent, as long as the list container is still open.
+ int i = 0;
+
+ // compute padding:
+ S_advance_offset(parser, input,
+ parser->first_nonspace + matched - parser->offset,
+ false);
+
+ save_partially_consumed_tab = parser->partially_consumed_tab;
+ save_offset = parser->offset;
+ save_column = parser->column;
+
+ while (parser->column - save_column <= 5 &&
+ S_is_space_or_tab(peek_at(input, parser->offset))) {
+ S_advance_offset(parser, input, 1, true);
+ }
+
+ i = parser->column - save_column;
+ if (i >= 5 || i < 1 ||
+ // only spaces after list marker:
+ S_is_line_end_char(peek_at(input, parser->offset))) {
+ data->padding = matched + 1;
+ parser->offset = save_offset;
+ parser->column = save_column;
+ parser->partially_consumed_tab = save_partially_consumed_tab;
+ if (i > 0) {
+ S_advance_offset(parser, input, 1, true);
+ }
+ } else {
+ data->padding = matched + i;
+ }
+
+ // check container; if it's a list, see if this list item
+ // can continue the list; otherwise, create a list container.
+
+ data->marker_offset = parser->indent;
+
+ if (cont_type != CMARK_NODE_LIST ||
+ !lists_match(&((*container)->as.list), data)) {
+ *container = add_child(parser, *container, CMARK_NODE_LIST,
+ parser->first_nonspace + 1);
+
+ memcpy(&((*container)->as.list), data, sizeof(*data));
+ }
+
+ // add the list item
+ *container = add_child(parser, *container, CMARK_NODE_ITEM,
+ parser->first_nonspace + 1);
+ /* TODO: static */
+ memcpy(&((*container)->as.list), data, sizeof(*data));
+ parser->mem->free(data);
+ } else if (indented && !maybe_lazy && !parser->blank) {
+ S_advance_offset(parser, input, CODE_INDENT, true);
+ *container = add_child(parser, *container, CMARK_NODE_CODE_BLOCK,
+ parser->offset + 1);
+ (*container)->as.code.fenced = false;
+ (*container)->as.code.fence_char = 0;
+ (*container)->as.code.fence_length = 0;
+ (*container)->as.code.fence_offset = 0;
+ (*container)->as.code.info = NULL;
+
+ } else {
+ break;
+ }
+
+ if (accepts_lines(S_type(*container))) {
+ // if it's a line container, it can't contain other containers
+ break;
+ }
+
+ cont_type = S_type(*container);
+ maybe_lazy = false;
+ }
+}
+
+static void add_text_to_container(cmark_parser *parser, cmark_node *container,
+ cmark_node *last_matched_container,
+ cmark_chunk *input) {
+ cmark_node *tmp;
+ // what remains at parser->offset is a text line. add the text to the
+ // appropriate container.
+
+ S_find_first_nonspace(parser, input);
+
+ if (parser->blank && container->last_child)
+ S_set_last_line_blank(container->last_child, true);
+
+ // block quote lines are never blank as they start with >
+ // and we don't count blanks in fenced code for purposes of tight/loose
+ // lists or breaking out of lists. we also don't set last_line_blank
+ // on an empty list item.
+ const cmark_node_type ctype = S_type(container);
+ const bool last_line_blank =
+ (parser->blank && ctype != CMARK_NODE_BLOCK_QUOTE &&
+ ctype != CMARK_NODE_HEADING && ctype != CMARK_NODE_THEMATIC_BREAK &&
+ !(ctype == CMARK_NODE_CODE_BLOCK && container->as.code.fenced) &&
+ !(ctype == CMARK_NODE_ITEM && container->first_child == NULL &&
+ container->start_line == parser->line_number));
+
+ S_set_last_line_blank(container, last_line_blank);
+
+ tmp = container;
+ while (tmp->parent) {
+ S_set_last_line_blank(tmp->parent, false);
+ tmp = tmp->parent;
+ }
+
+ // If the last line processed belonged to a paragraph node,
+ // and we didn't match all of the line prefixes for the open containers,
+ // and we didn't start any new containers,
+ // and the line isn't blank,
+ // then treat this as a "lazy continuation line" and add it to
+ // the open paragraph.
+ if (parser->current != last_matched_container &&
+ container == last_matched_container && !parser->blank &&
+ S_type(parser->current) == CMARK_NODE_PARAGRAPH) {
+ add_line(input, parser);
+ } else { // not a lazy continuation
+ // Finalize any blocks that were not matched and set cur to container:
+ while (parser->current != last_matched_container) {
+ parser->current = finalize(parser, parser->current);
+ assert(parser->current != NULL);
+ }
+
+ if (S_type(container) == CMARK_NODE_CODE_BLOCK) {
+ add_line(input, parser);
+ } else if (S_type(container) == CMARK_NODE_HTML_BLOCK) {
+ add_line(input, parser);
+
+ int matches_end_condition;
+ switch (container->as.html_block_type) {
+ case 1:
+ // </script>, </style>, </textarea>, </pre>
+ matches_end_condition =
+ scan_html_block_end_1(input, parser->first_nonspace);
+ break;
+ case 2:
+ // -->
+ matches_end_condition =
+ scan_html_block_end_2(input, parser->first_nonspace);
+ break;
+ case 3:
+ // ?>
+ matches_end_condition =
+ scan_html_block_end_3(input, parser->first_nonspace);
+ break;
+ case 4:
+ // >
+ matches_end_condition =
+ scan_html_block_end_4(input, parser->first_nonspace);
+ break;
+ case 5:
+ // ]]>
+ matches_end_condition =
+ scan_html_block_end_5(input, parser->first_nonspace);
+ break;
+ default:
+ matches_end_condition = 0;
+ break;
+ }
+
+ if (matches_end_condition) {
+ container = finalize(parser, container);
+ assert(parser->current != NULL);
+ }
+ } else if (parser->blank) {
+ // ??? do nothing
+ } else if (accepts_lines(S_type(container))) {
+ if (S_type(container) == CMARK_NODE_HEADING &&
+ container->as.heading.setext == false) {
+ chop_trailing_hashtags(input);
+ }
+ S_advance_offset(parser, input, parser->first_nonspace - parser->offset,
+ false);
+ add_line(input, parser);
+ } else {
+ // create paragraph container for line
+ container = add_child(parser, container, CMARK_NODE_PARAGRAPH,
+ parser->first_nonspace + 1);
+ S_advance_offset(parser, input, parser->first_nonspace - parser->offset,
+ false);
+ add_line(input, parser);
+ }
+
+ parser->current = container;
+ }
+}
+
+/* See http://spec.commonmark.org/0.24/#phase-1-block-structure */
+static void S_process_line(cmark_parser *parser, const unsigned char *buffer,
+ bufsize_t bytes) {
+ cmark_node *last_matched_container;
+ bool all_matched = true;
+ cmark_node *container;
+ cmark_chunk input;
+
+ if (parser->options & CMARK_OPT_VALIDATE_UTF8)
+ cmark_utf8proc_check(&parser->curline, buffer, bytes);
+ else
+ cmark_strbuf_put(&parser->curline, buffer, bytes);
+
+ bytes = parser->curline.size;
+
+ // ensure line ends with a newline:
+ if (bytes == 0 || !S_is_line_end_char(parser->curline.ptr[bytes - 1]))
+ cmark_strbuf_putc(&parser->curline, '\n');
+
+ parser->offset = 0;
+ parser->column = 0;
+ parser->first_nonspace = 0;
+ parser->first_nonspace_column = 0;
+ parser->thematic_break_kill_pos = 0;
+ parser->indent = 0;
+ parser->blank = false;
+ parser->partially_consumed_tab = false;
+
+ input.data = parser->curline.ptr;
+ input.len = parser->curline.size;
+
+ parser->line_number++;
+
+ last_matched_container = check_open_blocks(parser, &input, &all_matched);
+
+ if (!last_matched_container)
+ goto finished;
+
+ container = last_matched_container;
+
+ open_new_blocks(parser, &container, &input, all_matched);
+
+ add_text_to_container(parser, container, last_matched_container, &input);
+
+finished:
+ parser->last_line_length = input.len;
+ if (parser->last_line_length &&
+ input.data[parser->last_line_length - 1] == '\n')
+ parser->last_line_length -= 1;
+ if (parser->last_line_length &&
+ input.data[parser->last_line_length - 1] == '\r')
+ parser->last_line_length -= 1;
+
+ cmark_strbuf_clear(&parser->curline);
+}
+
+cmark_node *cmark_parser_finish(cmark_parser *parser) {
+ if (parser->linebuf.size) {
+ S_process_line(parser, parser->linebuf.ptr, parser->linebuf.size);
+ cmark_strbuf_clear(&parser->linebuf);
+ }
+
+ finalize_document(parser);
+
+ cmark_consolidate_text_nodes(parser->root);
+
+ cmark_strbuf_free(&parser->curline);
+
+#if CMARK_DEBUG_NODES
+ if (cmark_node_check(parser->root, stderr)) {
+ abort();
+ }
+#endif
+ return parser->root;
+}
diff --git a/cmark/src/buffer.c b/cmark/src/buffer.c
new file mode 100644
index 0000000000..f3159948ce
--- /dev/null
+++ b/cmark/src/buffer.c
@@ -0,0 +1,209 @@
+#include <assert.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "cmark_ctype.h"
+#include "buffer.h"
+
+/* Used as default value for cmark_strbuf->ptr so that people can always
+ * assume ptr is non-NULL and zero terminated even for new cmark_strbufs.
+ */
+unsigned char cmark_strbuf__initbuf[1];
+
+#ifndef MIN
+#define MIN(x, y) ((x < y) ? x : y)
+#endif
+
+void cmark_strbuf_init(cmark_mem *mem, cmark_strbuf *buf,
+ bufsize_t initial_size) {
+ buf->mem = mem;
+ buf->asize = 0;
+ buf->size = 0;
+ buf->ptr = cmark_strbuf__initbuf;
+
+ if (initial_size > 0)
+ cmark_strbuf_grow(buf, initial_size);
+}
+
+static inline void S_strbuf_grow_by(cmark_strbuf *buf, bufsize_t add) {
+ cmark_strbuf_grow(buf, buf->size + add);
+}
+
+void cmark_strbuf_grow(cmark_strbuf *buf, bufsize_t target_size) {
+ assert(target_size > 0);
+
+ if (target_size < buf->asize)
+ return;
+
+ if (target_size > (bufsize_t)(INT32_MAX / 2)) {
+ fprintf(stderr,
+ "[cmark] cmark_strbuf_grow requests buffer with size > %d, aborting\n",
+ (INT32_MAX / 2));
+ abort();
+ }
+
+ /* Oversize the buffer by 50% to guarantee amortized linear time
+ * complexity on append operations. */
+ bufsize_t new_size = target_size + target_size / 2;
+ new_size += 1;
+ new_size = (new_size + 7) & ~7;
+
+ buf->ptr = (unsigned char *)buf->mem->realloc(buf->asize ? buf->ptr : NULL,
+ new_size);
+ buf->asize = new_size;
+}
+
+void cmark_strbuf_free(cmark_strbuf *buf) {
+ if (!buf)
+ return;
+
+ if (buf->ptr != cmark_strbuf__initbuf)
+ buf->mem->free(buf->ptr);
+
+ cmark_strbuf_init(buf->mem, buf, 0);
+}
+
+void cmark_strbuf_clear(cmark_strbuf *buf) {
+ buf->size = 0;
+
+ if (buf->asize > 0)
+ buf->ptr[0] = '\0';
+}
+
+void cmark_strbuf_set(cmark_strbuf *buf, const unsigned char *data,
+ bufsize_t len) {
+ if (len <= 0 || data == NULL) {
+ cmark_strbuf_clear(buf);
+ } else {
+ if (data != buf->ptr) {
+ if (len >= buf->asize)
+ cmark_strbuf_grow(buf, len);
+ memmove(buf->ptr, data, len);
+ }
+ buf->size = len;
+ buf->ptr[buf->size] = '\0';
+ }
+}
+
+void cmark_strbuf_putc(cmark_strbuf *buf, int c) {
+ S_strbuf_grow_by(buf, 1);
+ buf->ptr[buf->size++] = (unsigned char)(c & 0xFF);
+ buf->ptr[buf->size] = '\0';
+}
+
+void cmark_strbuf_put(cmark_strbuf *buf, const unsigned char *data,
+ bufsize_t len) {
+ if (len <= 0)
+ return;
+
+ S_strbuf_grow_by(buf, len);
+ memmove(buf->ptr + buf->size, data, len);
+ buf->size += len;
+ buf->ptr[buf->size] = '\0';
+}
+
+void cmark_strbuf_puts(cmark_strbuf *buf, const char *string) {
+ cmark_strbuf_put(buf, (const unsigned char *)string, (bufsize_t)strlen(string));
+}
+
+unsigned char *cmark_strbuf_detach(cmark_strbuf *buf) {
+ unsigned char *data = buf->ptr;
+
+ if (buf->asize == 0) {
+ /* return an empty string */
+ return (unsigned char *)buf->mem->calloc(1, 1);
+ }
+
+ cmark_strbuf_init(buf->mem, buf, 0);
+ return data;
+}
+
+void cmark_strbuf_truncate(cmark_strbuf *buf, bufsize_t len) {
+ if (len < 0)
+ len = 0;
+
+ if (len < buf->size) {
+ buf->size = len;
+ buf->ptr[buf->size] = '\0';
+ }
+}
+
+void cmark_strbuf_drop(cmark_strbuf *buf, bufsize_t n) {
+ if (n > 0) {
+ if (n > buf->size)
+ n = buf->size;
+ buf->size = buf->size - n;
+ if (buf->size)
+ memmove(buf->ptr, buf->ptr + n, buf->size);
+
+ buf->ptr[buf->size] = '\0';
+ }
+}
+
+void cmark_strbuf_rtrim(cmark_strbuf *buf) {
+ if (!buf->size)
+ return;
+
+ while (buf->size > 0) {
+ if (!cmark_isspace(buf->ptr[buf->size - 1]))
+ break;
+
+ buf->size--;
+ }
+
+ buf->ptr[buf->size] = '\0';
+}
+
+void cmark_strbuf_trim(cmark_strbuf *buf) {
+ bufsize_t i = 0;
+
+ if (!buf->size)
+ return;
+
+ while (i < buf->size && cmark_isspace(buf->ptr[i]))
+ i++;
+
+ cmark_strbuf_drop(buf, i);
+
+ cmark_strbuf_rtrim(buf);
+}
+
+// Destructively modify string, collapsing consecutive
+// space and newline characters into a single space.
+void cmark_strbuf_normalize_whitespace(cmark_strbuf *s) {
+ bool last_char_was_space = false;
+ bufsize_t r, w;
+
+ for (r = 0, w = 0; r < s->size; ++r) {
+ if (cmark_isspace(s->ptr[r])) {
+ if (!last_char_was_space) {
+ s->ptr[w++] = ' ';
+ last_char_was_space = true;
+ }
+ } else {
+ s->ptr[w++] = s->ptr[r];
+ last_char_was_space = false;
+ }
+ }
+
+ cmark_strbuf_truncate(s, w);
+}
+
+// Destructively unescape a string: remove backslashes before punctuation chars.
+void cmark_strbuf_unescape(cmark_strbuf *buf) {
+ bufsize_t r, w;
+
+ for (r = 0, w = 0; r < buf->size; ++r) {
+ if (buf->ptr[r] == '\\' && cmark_ispunct(buf->ptr[r + 1]))
+ r++;
+
+ buf->ptr[w++] = buf->ptr[r];
+ }
+
+ cmark_strbuf_truncate(buf, w);
+}
diff --git a/cmark/src/buffer.h b/cmark/src/buffer.h
new file mode 100644
index 0000000000..e6a085724c
--- /dev/null
+++ b/cmark/src/buffer.h
@@ -0,0 +1,74 @@
+#ifndef CMARK_BUFFER_H
+#define CMARK_BUFFER_H
+
+#include <limits.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "cmark.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef int32_t bufsize_t;
+
+typedef struct {
+ cmark_mem *mem;
+ unsigned char *ptr;
+ bufsize_t asize, size;
+} cmark_strbuf;
+
+extern unsigned char cmark_strbuf__initbuf[];
+
+#define CMARK_BUF_INIT(mem) \
+ { mem, cmark_strbuf__initbuf, 0, 0 }
+
+/**
+ * Initialize a cmark_strbuf structure.
+ *
+ * For the cases where CMARK_BUF_INIT cannot be used to do static
+ * initialization.
+ */
+void cmark_strbuf_init(cmark_mem *mem, cmark_strbuf *buf,
+ bufsize_t initial_size);
+
+/**
+ * Grow the buffer to hold at least `target_size` bytes.
+ */
+void cmark_strbuf_grow(cmark_strbuf *buf, bufsize_t target_size);
+
+void cmark_strbuf_free(cmark_strbuf *buf);
+
+unsigned char *cmark_strbuf_detach(cmark_strbuf *buf);
+
+/*
+static inline const char *cmark_strbuf_cstr(const cmark_strbuf *buf) {
+ return (char *)buf->ptr;
+}
+*/
+
+#define cmark_strbuf_at(buf, n) ((buf)->ptr[n])
+
+void cmark_strbuf_set(cmark_strbuf *buf, const unsigned char *data,
+ bufsize_t len);
+void cmark_strbuf_putc(cmark_strbuf *buf, int c);
+void cmark_strbuf_put(cmark_strbuf *buf, const unsigned char *data,
+ bufsize_t len);
+void cmark_strbuf_puts(cmark_strbuf *buf, const char *string);
+void cmark_strbuf_clear(cmark_strbuf *buf);
+
+void cmark_strbuf_drop(cmark_strbuf *buf, bufsize_t n);
+void cmark_strbuf_truncate(cmark_strbuf *buf, bufsize_t len);
+void cmark_strbuf_rtrim(cmark_strbuf *buf);
+void cmark_strbuf_trim(cmark_strbuf *buf);
+void cmark_strbuf_normalize_whitespace(cmark_strbuf *s);
+void cmark_strbuf_unescape(cmark_strbuf *s);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/cmark/src/case_fold.inc b/cmark/src/case_fold.inc
new file mode 100644
index 0000000000..b309d3e24f
--- /dev/null
+++ b/cmark/src/case_fold.inc
@@ -0,0 +1,722 @@
+// Generated by tools/make_case_fold_inc.py
+
+#define CF_MAX (1 << 17)
+#define CF_TABLE_SIZE 1559
+#define CF_CODE_POINT(x) ((x) & 0x1FFFF)
+#define CF_REPL_IDX(x) ((((x) >> 17) & 0xFFF) * 2)
+#define CF_REPL_SIZE(x) ((x) >> 29)
+
+static const uint32_t cf_table[1559] = {
+ 0x400000B5, 0x400200C0, 0x400400C1, 0x400600C2, 0x400800C3, 0x400A00C4,
+ 0x400C00C5, 0x400E00C6, 0x401000C7, 0x401200C8, 0x401400C9, 0x401600CA,
+ 0x401800CB, 0x401A00CC, 0x401C00CD, 0x401E00CE, 0x402000CF, 0x402200D0,
+ 0x402400D1, 0x402600D2, 0x402800D3, 0x402A00D4, 0x402C00D5, 0x402E00D6,
+ 0x403000D8, 0x403200D9, 0x403400DA, 0x403600DB, 0x403800DC, 0x403A00DD,
+ 0x403C00DE, 0x403E00DF, 0x40400100, 0x40420102, 0x40440104, 0x40460106,
+ 0x40480108, 0x404A010A, 0x404C010C, 0x404E010E, 0x40500110, 0x40520112,
+ 0x40540114, 0x40560116, 0x40580118, 0x405A011A, 0x405C011C, 0x405E011E,
+ 0x40600120, 0x40620122, 0x40640124, 0x40660126, 0x40680128, 0x406A012A,
+ 0x406C012C, 0x406E012E, 0x60700130, 0x40740132, 0x40760134, 0x40780136,
+ 0x407A0139, 0x407C013B, 0x407E013D, 0x4080013F, 0x40820141, 0x40840143,
+ 0x40860145, 0x40880147, 0x608A0149, 0x408E014A, 0x4090014C, 0x4092014E,
+ 0x40940150, 0x40960152, 0x40980154, 0x409A0156, 0x409C0158, 0x409E015A,
+ 0x40A0015C, 0x40A2015E, 0x40A40160, 0x40A60162, 0x40A80164, 0x40AA0166,
+ 0x40AC0168, 0x40AE016A, 0x40B0016C, 0x40B2016E, 0x40B40170, 0x40B60172,
+ 0x40B80174, 0x40BA0176, 0x40BC0178, 0x40BE0179, 0x40C0017B, 0x40C2017D,
+ 0x20C4017F, 0x40C60181, 0x40C80182, 0x40CA0184, 0x40CC0186, 0x40CE0187,
+ 0x40D00189, 0x40D2018A, 0x40D4018B, 0x40D6018E, 0x40D8018F, 0x40DA0190,
+ 0x40DC0191, 0x40DE0193, 0x40E00194, 0x40E20196, 0x40E40197, 0x40E60198,
+ 0x40E8019C, 0x40EA019D, 0x40EC019F, 0x40EE01A0, 0x40F001A2, 0x40F201A4,
+ 0x40F401A6, 0x40F601A7, 0x40F801A9, 0x40FA01AC, 0x40FC01AE, 0x40FE01AF,
+ 0x410001B1, 0x410201B2, 0x410401B3, 0x410601B5, 0x410801B7, 0x410A01B8,
+ 0x410C01BC, 0x410E01C4, 0x411001C5, 0x411201C7, 0x411401C8, 0x411601CA,
+ 0x411801CB, 0x411A01CD, 0x411C01CF, 0x411E01D1, 0x412001D3, 0x412201D5,
+ 0x412401D7, 0x412601D9, 0x412801DB, 0x412A01DE, 0x412C01E0, 0x412E01E2,
+ 0x413001E4, 0x413201E6, 0x413401E8, 0x413601EA, 0x413801EC, 0x413A01EE,
+ 0x613C01F0, 0x414001F1, 0x414201F2, 0x414401F4, 0x414601F6, 0x414801F7,
+ 0x414A01F8, 0x414C01FA, 0x414E01FC, 0x415001FE, 0x41520200, 0x41540202,
+ 0x41560204, 0x41580206, 0x415A0208, 0x415C020A, 0x415E020C, 0x4160020E,
+ 0x41620210, 0x41640212, 0x41660214, 0x41680216, 0x416A0218, 0x416C021A,
+ 0x416E021C, 0x4170021E, 0x41720220, 0x41740222, 0x41760224, 0x41780226,
+ 0x417A0228, 0x417C022A, 0x417E022C, 0x4180022E, 0x41820230, 0x41840232,
+ 0x6186023A, 0x418A023B, 0x418C023D, 0x618E023E, 0x41920241, 0x41940243,
+ 0x41960244, 0x41980245, 0x419A0246, 0x419C0248, 0x419E024A, 0x41A0024C,
+ 0x41A2024E, 0x41A40345, 0x41A60370, 0x41A80372, 0x41AA0376, 0x41AC037F,
+ 0x41AE0386, 0x41B00388, 0x41B20389, 0x41B4038A, 0x41B6038C, 0x41B8038E,
+ 0x41BA038F, 0xC1BC0390, 0x41C20391, 0x41C40392, 0x41C60393, 0x41C80394,
+ 0x41CA0395, 0x41CC0396, 0x41CE0397, 0x41D00398, 0x41D20399, 0x41D4039A,
+ 0x41D6039B, 0x41D8039C, 0x41DA039D, 0x41DC039E, 0x41DE039F, 0x41E003A0,
+ 0x41E203A1, 0x41E403A3, 0x41E603A4, 0x41E803A5, 0x41EA03A6, 0x41EC03A7,
+ 0x41EE03A8, 0x41F003A9, 0x41F203AA, 0x41F403AB, 0xC1F603B0, 0x41FC03C2,
+ 0x41FE03CF, 0x420003D0, 0x420203D1, 0x420403D5, 0x420603D6, 0x420803D8,
+ 0x420A03DA, 0x420C03DC, 0x420E03DE, 0x421003E0, 0x421203E2, 0x421403E4,
+ 0x421603E6, 0x421803E8, 0x421A03EA, 0x421C03EC, 0x421E03EE, 0x422003F0,
+ 0x422203F1, 0x422403F4, 0x422603F5, 0x422803F7, 0x422A03F9, 0x422C03FA,
+ 0x422E03FD, 0x423003FE, 0x423203FF, 0x42340400, 0x42360401, 0x42380402,
+ 0x423A0403, 0x423C0404, 0x423E0405, 0x42400406, 0x42420407, 0x42440408,
+ 0x42460409, 0x4248040A, 0x424A040B, 0x424C040C, 0x424E040D, 0x4250040E,
+ 0x4252040F, 0x42540410, 0x42560411, 0x42580412, 0x425A0413, 0x425C0414,
+ 0x425E0415, 0x42600416, 0x42620417, 0x42640418, 0x42660419, 0x4268041A,
+ 0x426A041B, 0x426C041C, 0x426E041D, 0x4270041E, 0x4272041F, 0x42740420,
+ 0x42760421, 0x42780422, 0x427A0423, 0x427C0424, 0x427E0425, 0x42800426,
+ 0x42820427, 0x42840428, 0x42860429, 0x4288042A, 0x428A042B, 0x428C042C,
+ 0x428E042D, 0x4290042E, 0x4292042F, 0x42940460, 0x42960462, 0x42980464,
+ 0x429A0466, 0x429C0468, 0x429E046A, 0x42A0046C, 0x42A2046E, 0x42A40470,
+ 0x42A60472, 0x42A80474, 0x42AA0476, 0x42AC0478, 0x42AE047A, 0x42B0047C,
+ 0x42B2047E, 0x42B40480, 0x42B6048A, 0x42B8048C, 0x42BA048E, 0x42BC0490,
+ 0x42BE0492, 0x42C00494, 0x42C20496, 0x42C40498, 0x42C6049A, 0x42C8049C,
+ 0x42CA049E, 0x42CC04A0, 0x42CE04A2, 0x42D004A4, 0x42D204A6, 0x42D404A8,
+ 0x42D604AA, 0x42D804AC, 0x42DA04AE, 0x42DC04B0, 0x42DE04B2, 0x42E004B4,
+ 0x42E204B6, 0x42E404B8, 0x42E604BA, 0x42E804BC, 0x42EA04BE, 0x42EC04C0,
+ 0x42EE04C1, 0x42F004C3, 0x42F204C5, 0x42F404C7, 0x42F604C9, 0x42F804CB,
+ 0x42FA04CD, 0x42FC04D0, 0x42FE04D2, 0x430004D4, 0x430204D6, 0x430404D8,
+ 0x430604DA, 0x430804DC, 0x430A04DE, 0x430C04E0, 0x430E04E2, 0x431004E4,
+ 0x431204E6, 0x431404E8, 0x431604EA, 0x431804EC, 0x431A04EE, 0x431C04F0,
+ 0x431E04F2, 0x432004F4, 0x432204F6, 0x432404F8, 0x432604FA, 0x432804FC,
+ 0x432A04FE, 0x432C0500, 0x432E0502, 0x43300504, 0x43320506, 0x43340508,
+ 0x4336050A, 0x4338050C, 0x433A050E, 0x433C0510, 0x433E0512, 0x43400514,
+ 0x43420516, 0x43440518, 0x4346051A, 0x4348051C, 0x434A051E, 0x434C0520,
+ 0x434E0522, 0x43500524, 0x43520526, 0x43540528, 0x4356052A, 0x4358052C,
+ 0x435A052E, 0x435C0531, 0x435E0532, 0x43600533, 0x43620534, 0x43640535,
+ 0x43660536, 0x43680537, 0x436A0538, 0x436C0539, 0x436E053A, 0x4370053B,
+ 0x4372053C, 0x4374053D, 0x4376053E, 0x4378053F, 0x437A0540, 0x437C0541,
+ 0x437E0542, 0x43800543, 0x43820544, 0x43840545, 0x43860546, 0x43880547,
+ 0x438A0548, 0x438C0549, 0x438E054A, 0x4390054B, 0x4392054C, 0x4394054D,
+ 0x4396054E, 0x4398054F, 0x439A0550, 0x439C0551, 0x439E0552, 0x43A00553,
+ 0x43A20554, 0x43A40555, 0x43A60556, 0x83A80587, 0x63AC10A0, 0x63B010A1,
+ 0x63B410A2, 0x63B810A3, 0x63BC10A4, 0x63C010A5, 0x63C410A6, 0x63C810A7,
+ 0x63CC10A8, 0x63D010A9, 0x63D410AA, 0x63D810AB, 0x63DC10AC, 0x63E010AD,
+ 0x63E410AE, 0x63E810AF, 0x63EC10B0, 0x63F010B1, 0x63F410B2, 0x63F810B3,
+ 0x63FC10B4, 0x640010B5, 0x640410B6, 0x640810B7, 0x640C10B8, 0x641010B9,
+ 0x641410BA, 0x641810BB, 0x641C10BC, 0x642010BD, 0x642410BE, 0x642810BF,
+ 0x642C10C0, 0x643010C1, 0x643410C2, 0x643810C3, 0x643C10C4, 0x644010C5,
+ 0x644410C7, 0x644810CD, 0x644C13F8, 0x645013F9, 0x645413FA, 0x645813FB,
+ 0x645C13FC, 0x646013FD, 0x44641C80, 0x44661C81, 0x44681C82, 0x446A1C83,
+ 0x446C1C84, 0x446E1C85, 0x44701C86, 0x44721C87, 0x64741C88, 0x64781C89,
+ 0x647C1C90, 0x64801C91, 0x64841C92, 0x64881C93, 0x648C1C94, 0x64901C95,
+ 0x64941C96, 0x64981C97, 0x649C1C98, 0x64A01C99, 0x64A41C9A, 0x64A81C9B,
+ 0x64AC1C9C, 0x64B01C9D, 0x64B41C9E, 0x64B81C9F, 0x64BC1CA0, 0x64C01CA1,
+ 0x64C41CA2, 0x64C81CA3, 0x64CC1CA4, 0x64D01CA5, 0x64D41CA6, 0x64D81CA7,
+ 0x64DC1CA8, 0x64E01CA9, 0x64E41CAA, 0x64E81CAB, 0x64EC1CAC, 0x64F01CAD,
+ 0x64F41CAE, 0x64F81CAF, 0x64FC1CB0, 0x65001CB1, 0x65041CB2, 0x65081CB3,
+ 0x650C1CB4, 0x65101CB5, 0x65141CB6, 0x65181CB7, 0x651C1CB8, 0x65201CB9,
+ 0x65241CBA, 0x65281CBD, 0x652C1CBE, 0x65301CBF, 0x65341E00, 0x65381E02,
+ 0x653C1E04, 0x65401E06, 0x65441E08, 0x65481E0A, 0x654C1E0C, 0x65501E0E,
+ 0x65541E10, 0x65581E12, 0x655C1E14, 0x65601E16, 0x65641E18, 0x65681E1A,
+ 0x656C1E1C, 0x65701E1E, 0x65741E20, 0x65781E22, 0x657C1E24, 0x65801E26,
+ 0x65841E28, 0x65881E2A, 0x658C1E2C, 0x65901E2E, 0x65941E30, 0x65981E32,
+ 0x659C1E34, 0x65A01E36, 0x65A41E38, 0x65A81E3A, 0x65AC1E3C, 0x65B01E3E,
+ 0x65B41E40, 0x65B81E42, 0x65BC1E44, 0x65C01E46, 0x65C41E48, 0x65C81E4A,
+ 0x65CC1E4C, 0x65D01E4E, 0x65D41E50, 0x65D81E52, 0x65DC1E54, 0x65E01E56,
+ 0x65E41E58, 0x65E81E5A, 0x65EC1E5C, 0x65F01E5E, 0x65F41E60, 0x65F81E62,
+ 0x65FC1E64, 0x66001E66, 0x66041E68, 0x66081E6A, 0x660C1E6C, 0x66101E6E,
+ 0x66141E70, 0x66181E72, 0x661C1E74, 0x66201E76, 0x66241E78, 0x66281E7A,
+ 0x662C1E7C, 0x66301E7E, 0x66341E80, 0x66381E82, 0x663C1E84, 0x66401E86,
+ 0x66441E88, 0x66481E8A, 0x664C1E8C, 0x66501E8E, 0x66541E90, 0x66581E92,
+ 0x665C1E94, 0x66601E96, 0x66641E97, 0x66681E98, 0x666C1E99, 0x66701E9A,
+ 0x66741E9B, 0x46781E9E, 0x667A1EA0, 0x667E1EA2, 0x66821EA4, 0x66861EA6,
+ 0x668A1EA8, 0x668E1EAA, 0x66921EAC, 0x66961EAE, 0x669A1EB0, 0x669E1EB2,
+ 0x66A21EB4, 0x66A61EB6, 0x66AA1EB8, 0x66AE1EBA, 0x66B21EBC, 0x66B61EBE,
+ 0x66BA1EC0, 0x66BE1EC2, 0x66C21EC4, 0x66C61EC6, 0x66CA1EC8, 0x66CE1ECA,
+ 0x66D21ECC, 0x66D61ECE, 0x66DA1ED0, 0x66DE1ED2, 0x66E21ED4, 0x66E61ED6,
+ 0x66EA1ED8, 0x66EE1EDA, 0x66F21EDC, 0x66F61EDE, 0x66FA1EE0, 0x66FE1EE2,
+ 0x67021EE4, 0x67061EE6, 0x670A1EE8, 0x670E1EEA, 0x67121EEC, 0x67161EEE,
+ 0x671A1EF0, 0x671E1EF2, 0x67221EF4, 0x67261EF6, 0x672A1EF8, 0x672E1EFA,
+ 0x67321EFC, 0x67361EFE, 0x673A1F08, 0x673E1F09, 0x67421F0A, 0x67461F0B,
+ 0x674A1F0C, 0x674E1F0D, 0x67521F0E, 0x67561F0F, 0x675A1F18, 0x675E1F19,
+ 0x67621F1A, 0x67661F1B, 0x676A1F1C, 0x676E1F1D, 0x67721F28, 0x67761F29,
+ 0x677A1F2A, 0x677E1F2B, 0x67821F2C, 0x67861F2D, 0x678A1F2E, 0x678E1F2F,
+ 0x67921F38, 0x67961F39, 0x679A1F3A, 0x679E1F3B, 0x67A21F3C, 0x67A61F3D,
+ 0x67AA1F3E, 0x67AE1F3F, 0x67B21F48, 0x67B61F49, 0x67BA1F4A, 0x67BE1F4B,
+ 0x67C21F4C, 0x67C61F4D, 0x87CA1F50, 0xC7CE1F52, 0xC7D41F54, 0xC7DA1F56,
+ 0x67E01F59, 0x67E41F5B, 0x67E81F5D, 0x67EC1F5F, 0x67F01F68, 0x67F41F69,
+ 0x67F81F6A, 0x67FC1F6B, 0x68001F6C, 0x68041F6D, 0x68081F6E, 0x680C1F6F,
+ 0xA8101F80, 0xA8161F81, 0xA81C1F82, 0xA8221F83, 0xA8281F84, 0xA82E1F85,
+ 0xA8341F86, 0xA83A1F87, 0xA8401F88, 0xA8461F89, 0xA84C1F8A, 0xA8521F8B,
+ 0xA8581F8C, 0xA85E1F8D, 0xA8641F8E, 0xA86A1F8F, 0xA8701F90, 0xA8761F91,
+ 0xA87C1F92, 0xA8821F93, 0xA8881F94, 0xA88E1F95, 0xA8941F96, 0xA89A1F97,
+ 0xA8A01F98, 0xA8A61F99, 0xA8AC1F9A, 0xA8B21F9B, 0xA8B81F9C, 0xA8BE1F9D,
+ 0xA8C41F9E, 0xA8CA1F9F, 0xA8D01FA0, 0xA8D61FA1, 0xA8DC1FA2, 0xA8E21FA3,
+ 0xA8E81FA4, 0xA8EE1FA5, 0xA8F41FA6, 0xA8FA1FA7, 0xA9001FA8, 0xA9061FA9,
+ 0xA90C1FAA, 0xA9121FAB, 0xA9181FAC, 0xA91E1FAD, 0xA9241FAE, 0xA92A1FAF,
+ 0xA9301FB2, 0x89361FB3, 0x893A1FB4, 0x893E1FB6, 0xC9421FB7, 0x69481FB8,
+ 0x694C1FB9, 0x69501FBA, 0x69541FBB, 0x89581FBC, 0x495C1FBE, 0xA95E1FC2,
+ 0x89641FC3, 0x89681FC4, 0x896C1FC6, 0xC9701FC7, 0x69761FC8, 0x697A1FC9,
+ 0x697E1FCA, 0x69821FCB, 0x89861FCC, 0xC98A1FD2, 0xC9901FD3, 0x89961FD6,
+ 0xC99A1FD7, 0x69A01FD8, 0x69A41FD9, 0x69A81FDA, 0x69AC1FDB, 0xC9B01FE2,
+ 0xC9B61FE3, 0x89BC1FE4, 0x89C01FE6, 0xC9C41FE7, 0x69CA1FE8, 0x69CE1FE9,
+ 0x69D21FEA, 0x69D61FEB, 0x69DA1FEC, 0xA9DE1FF2, 0x89E41FF3, 0x89E81FF4,
+ 0x89EC1FF6, 0xC9F01FF7, 0x69F61FF8, 0x69FA1FF9, 0x69FE1FFA, 0x6A021FFB,
+ 0x8A061FFC, 0x4A0A2126, 0x2A0C212A, 0x4A0E212B, 0x6A102132, 0x6A142160,
+ 0x6A182161, 0x6A1C2162, 0x6A202163, 0x6A242164, 0x6A282165, 0x6A2C2166,
+ 0x6A302167, 0x6A342168, 0x6A382169, 0x6A3C216A, 0x6A40216B, 0x6A44216C,
+ 0x6A48216D, 0x6A4C216E, 0x6A50216F, 0x6A542183, 0x6A5824B6, 0x6A5C24B7,
+ 0x6A6024B8, 0x6A6424B9, 0x6A6824BA, 0x6A6C24BB, 0x6A7024BC, 0x6A7424BD,
+ 0x6A7824BE, 0x6A7C24BF, 0x6A8024C0, 0x6A8424C1, 0x6A8824C2, 0x6A8C24C3,
+ 0x6A9024C4, 0x6A9424C5, 0x6A9824C6, 0x6A9C24C7, 0x6AA024C8, 0x6AA424C9,
+ 0x6AA824CA, 0x6AAC24CB, 0x6AB024CC, 0x6AB424CD, 0x6AB824CE, 0x6ABC24CF,
+ 0x6AC02C00, 0x6AC42C01, 0x6AC82C02, 0x6ACC2C03, 0x6AD02C04, 0x6AD42C05,
+ 0x6AD82C06, 0x6ADC2C07, 0x6AE02C08, 0x6AE42C09, 0x6AE82C0A, 0x6AEC2C0B,
+ 0x6AF02C0C, 0x6AF42C0D, 0x6AF82C0E, 0x6AFC2C0F, 0x6B002C10, 0x6B042C11,
+ 0x6B082C12, 0x6B0C2C13, 0x6B102C14, 0x6B142C15, 0x6B182C16, 0x6B1C2C17,
+ 0x6B202C18, 0x6B242C19, 0x6B282C1A, 0x6B2C2C1B, 0x6B302C1C, 0x6B342C1D,
+ 0x6B382C1E, 0x6B3C2C1F, 0x6B402C20, 0x6B442C21, 0x6B482C22, 0x6B4C2C23,
+ 0x6B502C24, 0x6B542C25, 0x6B582C26, 0x6B5C2C27, 0x6B602C28, 0x6B642C29,
+ 0x6B682C2A, 0x6B6C2C2B, 0x6B702C2C, 0x6B742C2D, 0x6B782C2E, 0x6B7C2C2F,
+ 0x6B802C60, 0x4B842C62, 0x6B862C63, 0x4B8A2C64, 0x6B8C2C67, 0x6B902C69,
+ 0x6B942C6B, 0x4B982C6D, 0x4B9A2C6E, 0x4B9C2C6F, 0x4B9E2C70, 0x6BA02C72,
+ 0x6BA42C75, 0x4BA82C7E, 0x4BAA2C7F, 0x6BAC2C80, 0x6BB02C82, 0x6BB42C84,
+ 0x6BB82C86, 0x6BBC2C88, 0x6BC02C8A, 0x6BC42C8C, 0x6BC82C8E, 0x6BCC2C90,
+ 0x6BD02C92, 0x6BD42C94, 0x6BD82C96, 0x6BDC2C98, 0x6BE02C9A, 0x6BE42C9C,
+ 0x6BE82C9E, 0x6BEC2CA0, 0x6BF02CA2, 0x6BF42CA4, 0x6BF82CA6, 0x6BFC2CA8,
+ 0x6C002CAA, 0x6C042CAC, 0x6C082CAE, 0x6C0C2CB0, 0x6C102CB2, 0x6C142CB4,
+ 0x6C182CB6, 0x6C1C2CB8, 0x6C202CBA, 0x6C242CBC, 0x6C282CBE, 0x6C2C2CC0,
+ 0x6C302CC2, 0x6C342CC4, 0x6C382CC6, 0x6C3C2CC8, 0x6C402CCA, 0x6C442CCC,
+ 0x6C482CCE, 0x6C4C2CD0, 0x6C502CD2, 0x6C542CD4, 0x6C582CD6, 0x6C5C2CD8,
+ 0x6C602CDA, 0x6C642CDC, 0x6C682CDE, 0x6C6C2CE0, 0x6C702CE2, 0x6C742CEB,
+ 0x6C782CED, 0x6C7C2CF2, 0x6C80A640, 0x6C84A642, 0x6C88A644, 0x6C8CA646,
+ 0x6C90A648, 0x6C94A64A, 0x6C98A64C, 0x6C9CA64E, 0x6CA0A650, 0x6CA4A652,
+ 0x6CA8A654, 0x6CACA656, 0x6CB0A658, 0x6CB4A65A, 0x6CB8A65C, 0x6CBCA65E,
+ 0x6CC0A660, 0x6CC4A662, 0x6CC8A664, 0x6CCCA666, 0x6CD0A668, 0x6CD4A66A,
+ 0x6CD8A66C, 0x6CDCA680, 0x6CE0A682, 0x6CE4A684, 0x6CE8A686, 0x6CECA688,
+ 0x6CF0A68A, 0x6CF4A68C, 0x6CF8A68E, 0x6CFCA690, 0x6D00A692, 0x6D04A694,
+ 0x6D08A696, 0x6D0CA698, 0x6D10A69A, 0x6D14A722, 0x6D18A724, 0x6D1CA726,
+ 0x6D20A728, 0x6D24A72A, 0x6D28A72C, 0x6D2CA72E, 0x6D30A732, 0x6D34A734,
+ 0x6D38A736, 0x6D3CA738, 0x6D40A73A, 0x6D44A73C, 0x6D48A73E, 0x6D4CA740,
+ 0x6D50A742, 0x6D54A744, 0x6D58A746, 0x6D5CA748, 0x6D60A74A, 0x6D64A74C,
+ 0x6D68A74E, 0x6D6CA750, 0x6D70A752, 0x6D74A754, 0x6D78A756, 0x6D7CA758,
+ 0x6D80A75A, 0x6D84A75C, 0x6D88A75E, 0x6D8CA760, 0x6D90A762, 0x6D94A764,
+ 0x6D98A766, 0x6D9CA768, 0x6DA0A76A, 0x6DA4A76C, 0x6DA8A76E, 0x6DACA779,
+ 0x6DB0A77B, 0x6DB4A77D, 0x6DB8A77E, 0x6DBCA780, 0x6DC0A782, 0x6DC4A784,
+ 0x6DC8A786, 0x6DCCA78B, 0x4DD0A78D, 0x6DD2A790, 0x6DD6A792, 0x6DDAA796,
+ 0x6DDEA798, 0x6DE2A79A, 0x6DE6A79C, 0x6DEAA79E, 0x6DEEA7A0, 0x6DF2A7A2,
+ 0x6DF6A7A4, 0x6DFAA7A6, 0x6DFEA7A8, 0x4E02A7AA, 0x4E04A7AB, 0x4E06A7AC,
+ 0x4E08A7AD, 0x4E0AA7AE, 0x4E0CA7B0, 0x4E0EA7B1, 0x4E10A7B2, 0x6E12A7B3,
+ 0x6E16A7B4, 0x6E1AA7B6, 0x6E1EA7B8, 0x6E22A7BA, 0x6E26A7BC, 0x6E2AA7BE,
+ 0x6E2EA7C0, 0x6E32A7C2, 0x6E36A7C4, 0x4E3AA7C5, 0x6E3CA7C6, 0x6E40A7C7,
+ 0x6E44A7C9, 0x4E48A7CB, 0x6E4AA7CC, 0x6E4EA7CE, 0x6E52A7D0, 0x6E56A7D2,
+ 0x6E5AA7D4, 0x6E5EA7D6, 0x6E62A7D8, 0x6E66A7DA, 0x4E6AA7DC, 0x6E6CA7F5,
+ 0x6E70AB70, 0x6E74AB71, 0x6E78AB72, 0x6E7CAB73, 0x6E80AB74, 0x6E84AB75,
+ 0x6E88AB76, 0x6E8CAB77, 0x6E90AB78, 0x6E94AB79, 0x6E98AB7A, 0x6E9CAB7B,
+ 0x6EA0AB7C, 0x6EA4AB7D, 0x6EA8AB7E, 0x6EACAB7F, 0x6EB0AB80, 0x6EB4AB81,
+ 0x6EB8AB82, 0x6EBCAB83, 0x6EC0AB84, 0x6EC4AB85, 0x6EC8AB86, 0x6ECCAB87,
+ 0x6ED0AB88, 0x6ED4AB89, 0x6ED8AB8A, 0x6EDCAB8B, 0x6EE0AB8C, 0x6EE4AB8D,
+ 0x6EE8AB8E, 0x6EECAB8F, 0x6EF0AB90, 0x6EF4AB91, 0x6EF8AB92, 0x6EFCAB93,
+ 0x6F00AB94, 0x6F04AB95, 0x6F08AB96, 0x6F0CAB97, 0x6F10AB98, 0x6F14AB99,
+ 0x6F18AB9A, 0x6F1CAB9B, 0x6F20AB9C, 0x6F24AB9D, 0x6F28AB9E, 0x6F2CAB9F,
+ 0x6F30ABA0, 0x6F34ABA1, 0x6F38ABA2, 0x6F3CABA3, 0x6F40ABA4, 0x6F44ABA5,
+ 0x6F48ABA6, 0x6F4CABA7, 0x6F50ABA8, 0x6F54ABA9, 0x6F58ABAA, 0x6F5CABAB,
+ 0x6F60ABAC, 0x6F64ABAD, 0x6F68ABAE, 0x6F6CABAF, 0x6F70ABB0, 0x6F74ABB1,
+ 0x6F78ABB2, 0x6F7CABB3, 0x6F80ABB4, 0x6F84ABB5, 0x6F88ABB6, 0x6F8CABB7,
+ 0x6F90ABB8, 0x6F94ABB9, 0x6F98ABBA, 0x6F9CABBB, 0x6FA0ABBC, 0x6FA4ABBD,
+ 0x6FA8ABBE, 0x6FACABBF, 0x4FB0FB00, 0x4FB2FB01, 0x4FB4FB02, 0x6FB6FB03,
+ 0x6FBAFB04, 0x4FBEFB05, 0x4FC0FB06, 0x8FC2FB13, 0x8FC6FB14, 0x8FCAFB15,
+ 0x8FCEFB16, 0x8FD2FB17, 0x6FD6FF21, 0x6FDAFF22, 0x6FDEFF23, 0x6FE2FF24,
+ 0x6FE6FF25, 0x6FEAFF26, 0x6FEEFF27, 0x6FF2FF28, 0x6FF6FF29, 0x6FFAFF2A,
+ 0x6FFEFF2B, 0x7002FF2C, 0x7006FF2D, 0x700AFF2E, 0x700EFF2F, 0x7012FF30,
+ 0x7016FF31, 0x701AFF32, 0x701EFF33, 0x7022FF34, 0x7026FF35, 0x702AFF36,
+ 0x702EFF37, 0x7032FF38, 0x7036FF39, 0x703AFF3A, 0x903F0400, 0x90430401,
+ 0x90470402, 0x904B0403, 0x904F0404, 0x90530405, 0x90570406, 0x905B0407,
+ 0x905F0408, 0x90630409, 0x9067040A, 0x906B040B, 0x906F040C, 0x9073040D,
+ 0x9077040E, 0x907B040F, 0x907F0410, 0x90830411, 0x90870412, 0x908B0413,
+ 0x908F0414, 0x90930415, 0x90970416, 0x909B0417, 0x909F0418, 0x90A30419,
+ 0x90A7041A, 0x90AB041B, 0x90AF041C, 0x90B3041D, 0x90B7041E, 0x90BB041F,
+ 0x90BF0420, 0x90C30421, 0x90C70422, 0x90CB0423, 0x90CF0424, 0x90D30425,
+ 0x90D70426, 0x90DB0427, 0x90DF04B0, 0x90E304B1, 0x90E704B2, 0x90EB04B3,
+ 0x90EF04B4, 0x90F304B5, 0x90F704B6, 0x90FB04B7, 0x90FF04B8, 0x910304B9,
+ 0x910704BA, 0x910B04BB, 0x910F04BC, 0x911304BD, 0x911704BE, 0x911B04BF,
+ 0x911F04C0, 0x912304C1, 0x912704C2, 0x912B04C3, 0x912F04C4, 0x913304C5,
+ 0x913704C6, 0x913B04C7, 0x913F04C8, 0x914304C9, 0x914704CA, 0x914B04CB,
+ 0x914F04CC, 0x915304CD, 0x915704CE, 0x915B04CF, 0x915F04D0, 0x916304D1,
+ 0x916704D2, 0x916B04D3, 0x916F0570, 0x91730571, 0x91770572, 0x917B0573,
+ 0x917F0574, 0x91830575, 0x91870576, 0x918B0577, 0x918F0578, 0x91930579,
+ 0x9197057A, 0x919B057C, 0x919F057D, 0x91A3057E, 0x91A7057F, 0x91AB0580,
+ 0x91AF0581, 0x91B30582, 0x91B70583, 0x91BB0584, 0x91BF0585, 0x91C30586,
+ 0x91C70587, 0x91CB0588, 0x91CF0589, 0x91D3058A, 0x91D7058C, 0x91DB058D,
+ 0x91DF058E, 0x91E3058F, 0x91E70590, 0x91EB0591, 0x91EF0592, 0x91F30594,
+ 0x91F70595, 0x91FB0C80, 0x91FF0C81, 0x92030C82, 0x92070C83, 0x920B0C84,
+ 0x920F0C85, 0x92130C86, 0x92170C87, 0x921B0C88, 0x921F0C89, 0x92230C8A,
+ 0x92270C8B, 0x922B0C8C, 0x922F0C8D, 0x92330C8E, 0x92370C8F, 0x923B0C90,
+ 0x923F0C91, 0x92430C92, 0x92470C93, 0x924B0C94, 0x924F0C95, 0x92530C96,
+ 0x92570C97, 0x925B0C98, 0x925F0C99, 0x92630C9A, 0x92670C9B, 0x926B0C9C,
+ 0x926F0C9D, 0x92730C9E, 0x92770C9F, 0x927B0CA0, 0x927F0CA1, 0x92830CA2,
+ 0x92870CA3, 0x928B0CA4, 0x928F0CA5, 0x92930CA6, 0x92970CA7, 0x929B0CA8,
+ 0x929F0CA9, 0x92A30CAA, 0x92A70CAB, 0x92AB0CAC, 0x92AF0CAD, 0x92B30CAE,
+ 0x92B70CAF, 0x92BB0CB0, 0x92BF0CB1, 0x92C30CB2, 0x92C70D50, 0x92CB0D51,
+ 0x92CF0D52, 0x92D30D53, 0x92D70D54, 0x92DB0D55, 0x92DF0D56, 0x92E30D57,
+ 0x92E70D58, 0x92EB0D59, 0x92EF0D5A, 0x92F30D5B, 0x92F70D5C, 0x92FB0D5D,
+ 0x92FF0D5E, 0x93030D5F, 0x93070D60, 0x930B0D61, 0x930F0D62, 0x93130D63,
+ 0x93170D64, 0x931B0D65, 0x931F18A0, 0x932318A1, 0x932718A2, 0x932B18A3,
+ 0x932F18A4, 0x933318A5, 0x933718A6, 0x933B18A7, 0x933F18A8, 0x934318A9,
+ 0x934718AA, 0x934B18AB, 0x934F18AC, 0x935318AD, 0x935718AE, 0x935B18AF,
+ 0x935F18B0, 0x936318B1, 0x936718B2, 0x936B18B3, 0x936F18B4, 0x937318B5,
+ 0x937718B6, 0x937B18B7, 0x937F18B8, 0x938318B9, 0x938718BA, 0x938B18BB,
+ 0x938F18BC, 0x939318BD, 0x939718BE, 0x939B18BF, 0x939F6E40, 0x93A36E41,
+ 0x93A76E42, 0x93AB6E43, 0x93AF6E44, 0x93B36E45, 0x93B76E46, 0x93BB6E47,
+ 0x93BF6E48, 0x93C36E49, 0x93C76E4A, 0x93CB6E4B, 0x93CF6E4C, 0x93D36E4D,
+ 0x93D76E4E, 0x93DB6E4F, 0x93DF6E50, 0x93E36E51, 0x93E76E52, 0x93EB6E53,
+ 0x93EF6E54, 0x93F36E55, 0x93F76E56, 0x93FB6E57, 0x93FF6E58, 0x94036E59,
+ 0x94076E5A, 0x940B6E5B, 0x940F6E5C, 0x94136E5D, 0x94176E5E, 0x941B6E5F,
+ 0x941F6EA0, 0x94236EA1, 0x94276EA2, 0x942B6EA3, 0x942F6EA4, 0x94336EA5,
+ 0x94376EA6, 0x943B6EA7, 0x943F6EA8, 0x94436EA9, 0x94476EAA, 0x944B6EAB,
+ 0x944F6EAC, 0x94536EAD, 0x94576EAE, 0x945B6EAF, 0x945F6EB0, 0x94636EB1,
+ 0x94676EB2, 0x946B6EB3, 0x946F6EB4, 0x94736EB5, 0x94776EB6, 0x947B6EB7,
+ 0x947F6EB8, 0x9483E900, 0x9487E901, 0x948BE902, 0x948FE903, 0x9493E904,
+ 0x9497E905, 0x949BE906, 0x949FE907, 0x94A3E908, 0x94A7E909, 0x94ABE90A,
+ 0x94AFE90B, 0x94B3E90C, 0x94B7E90D, 0x94BBE90E, 0x94BFE90F, 0x94C3E910,
+ 0x94C7E911, 0x94CBE912, 0x94CFE913, 0x94D3E914, 0x94D7E915, 0x94DBE916,
+ 0x94DFE917, 0x94E3E918, 0x94E7E919, 0x94EBE91A, 0x94EFE91B, 0x94F3E91C,
+ 0x94F7E91D, 0x94FBE91E, 0x94FFE91F, 0x9503E920, 0x9507E921
+};
+
+static const unsigned char cf_repl[5386] = {
+ 0xCE, 0xBC, 0xC3, 0xA0, 0xC3, 0xA1, 0xC3, 0xA2, 0xC3, 0xA3, 0xC3, 0xA4,
+ 0xC3, 0xA5, 0xC3, 0xA6, 0xC3, 0xA7, 0xC3, 0xA8, 0xC3, 0xA9, 0xC3, 0xAA,
+ 0xC3, 0xAB, 0xC3, 0xAC, 0xC3, 0xAD, 0xC3, 0xAE, 0xC3, 0xAF, 0xC3, 0xB0,
+ 0xC3, 0xB1, 0xC3, 0xB2, 0xC3, 0xB3, 0xC3, 0xB4, 0xC3, 0xB5, 0xC3, 0xB6,
+ 0xC3, 0xB8, 0xC3, 0xB9, 0xC3, 0xBA, 0xC3, 0xBB, 0xC3, 0xBC, 0xC3, 0xBD,
+ 0xC3, 0xBE, 0x73, 0x73, 0xC4, 0x81, 0xC4, 0x83, 0xC4, 0x85, 0xC4, 0x87,
+ 0xC4, 0x89, 0xC4, 0x8B, 0xC4, 0x8D, 0xC4, 0x8F, 0xC4, 0x91, 0xC4, 0x93,
+ 0xC4, 0x95, 0xC4, 0x97, 0xC4, 0x99, 0xC4, 0x9B, 0xC4, 0x9D, 0xC4, 0x9F,
+ 0xC4, 0xA1, 0xC4, 0xA3, 0xC4, 0xA5, 0xC4, 0xA7, 0xC4, 0xA9, 0xC4, 0xAB,
+ 0xC4, 0xAD, 0xC4, 0xAF, 0x69, 0xCC, 0x87, 0x00, 0xC4, 0xB3, 0xC4, 0xB5,
+ 0xC4, 0xB7, 0xC4, 0xBA, 0xC4, 0xBC, 0xC4, 0xBE, 0xC5, 0x80, 0xC5, 0x82,
+ 0xC5, 0x84, 0xC5, 0x86, 0xC5, 0x88, 0xCA, 0xBC, 0x6E, 0x00, 0xC5, 0x8B,
+ 0xC5, 0x8D, 0xC5, 0x8F, 0xC5, 0x91, 0xC5, 0x93, 0xC5, 0x95, 0xC5, 0x97,
+ 0xC5, 0x99, 0xC5, 0x9B, 0xC5, 0x9D, 0xC5, 0x9F, 0xC5, 0xA1, 0xC5, 0xA3,
+ 0xC5, 0xA5, 0xC5, 0xA7, 0xC5, 0xA9, 0xC5, 0xAB, 0xC5, 0xAD, 0xC5, 0xAF,
+ 0xC5, 0xB1, 0xC5, 0xB3, 0xC5, 0xB5, 0xC5, 0xB7, 0xC3, 0xBF, 0xC5, 0xBA,
+ 0xC5, 0xBC, 0xC5, 0xBE, 0x73, 0x00, 0xC9, 0x93, 0xC6, 0x83, 0xC6, 0x85,
+ 0xC9, 0x94, 0xC6, 0x88, 0xC9, 0x96, 0xC9, 0x97, 0xC6, 0x8C, 0xC7, 0x9D,
+ 0xC9, 0x99, 0xC9, 0x9B, 0xC6, 0x92, 0xC9, 0xA0, 0xC9, 0xA3, 0xC9, 0xA9,
+ 0xC9, 0xA8, 0xC6, 0x99, 0xC9, 0xAF, 0xC9, 0xB2, 0xC9, 0xB5, 0xC6, 0xA1,
+ 0xC6, 0xA3, 0xC6, 0xA5, 0xCA, 0x80, 0xC6, 0xA8, 0xCA, 0x83, 0xC6, 0xAD,
+ 0xCA, 0x88, 0xC6, 0xB0, 0xCA, 0x8A, 0xCA, 0x8B, 0xC6, 0xB4, 0xC6, 0xB6,
+ 0xCA, 0x92, 0xC6, 0xB9, 0xC6, 0xBD, 0xC7, 0x86, 0xC7, 0x86, 0xC7, 0x89,
+ 0xC7, 0x89, 0xC7, 0x8C, 0xC7, 0x8C, 0xC7, 0x8E, 0xC7, 0x90, 0xC7, 0x92,
+ 0xC7, 0x94, 0xC7, 0x96, 0xC7, 0x98, 0xC7, 0x9A, 0xC7, 0x9C, 0xC7, 0x9F,
+ 0xC7, 0xA1, 0xC7, 0xA3, 0xC7, 0xA5, 0xC7, 0xA7, 0xC7, 0xA9, 0xC7, 0xAB,
+ 0xC7, 0xAD, 0xC7, 0xAF, 0x6A, 0xCC, 0x8C, 0x00, 0xC7, 0xB3, 0xC7, 0xB3,
+ 0xC7, 0xB5, 0xC6, 0x95, 0xC6, 0xBF, 0xC7, 0xB9, 0xC7, 0xBB, 0xC7, 0xBD,
+ 0xC7, 0xBF, 0xC8, 0x81, 0xC8, 0x83, 0xC8, 0x85, 0xC8, 0x87, 0xC8, 0x89,
+ 0xC8, 0x8B, 0xC8, 0x8D, 0xC8, 0x8F, 0xC8, 0x91, 0xC8, 0x93, 0xC8, 0x95,
+ 0xC8, 0x97, 0xC8, 0x99, 0xC8, 0x9B, 0xC8, 0x9D, 0xC8, 0x9F, 0xC6, 0x9E,
+ 0xC8, 0xA3, 0xC8, 0xA5, 0xC8, 0xA7, 0xC8, 0xA9, 0xC8, 0xAB, 0xC8, 0xAD,
+ 0xC8, 0xAF, 0xC8, 0xB1, 0xC8, 0xB3, 0xE2, 0xB1, 0xA5, 0x00, 0xC8, 0xBC,
+ 0xC6, 0x9A, 0xE2, 0xB1, 0xA6, 0x00, 0xC9, 0x82, 0xC6, 0x80, 0xCA, 0x89,
+ 0xCA, 0x8C, 0xC9, 0x87, 0xC9, 0x89, 0xC9, 0x8B, 0xC9, 0x8D, 0xC9, 0x8F,
+ 0xCE, 0xB9, 0xCD, 0xB1, 0xCD, 0xB3, 0xCD, 0xB7, 0xCF, 0xB3, 0xCE, 0xAC,
+ 0xCE, 0xAD, 0xCE, 0xAE, 0xCE, 0xAF, 0xCF, 0x8C, 0xCF, 0x8D, 0xCF, 0x8E,
+ 0xCE, 0xB9, 0xCC, 0x88, 0xCC, 0x81, 0xCE, 0xB1, 0xCE, 0xB2, 0xCE, 0xB3,
+ 0xCE, 0xB4, 0xCE, 0xB5, 0xCE, 0xB6, 0xCE, 0xB7, 0xCE, 0xB8, 0xCE, 0xB9,
+ 0xCE, 0xBA, 0xCE, 0xBB, 0xCE, 0xBC, 0xCE, 0xBD, 0xCE, 0xBE, 0xCE, 0xBF,
+ 0xCF, 0x80, 0xCF, 0x81, 0xCF, 0x83, 0xCF, 0x84, 0xCF, 0x85, 0xCF, 0x86,
+ 0xCF, 0x87, 0xCF, 0x88, 0xCF, 0x89, 0xCF, 0x8A, 0xCF, 0x8B, 0xCF, 0x85,
+ 0xCC, 0x88, 0xCC, 0x81, 0xCF, 0x83, 0xCF, 0x97, 0xCE, 0xB2, 0xCE, 0xB8,
+ 0xCF, 0x86, 0xCF, 0x80, 0xCF, 0x99, 0xCF, 0x9B, 0xCF, 0x9D, 0xCF, 0x9F,
+ 0xCF, 0xA1, 0xCF, 0xA3, 0xCF, 0xA5, 0xCF, 0xA7, 0xCF, 0xA9, 0xCF, 0xAB,
+ 0xCF, 0xAD, 0xCF, 0xAF, 0xCE, 0xBA, 0xCF, 0x81, 0xCE, 0xB8, 0xCE, 0xB5,
+ 0xCF, 0xB8, 0xCF, 0xB2, 0xCF, 0xBB, 0xCD, 0xBB, 0xCD, 0xBC, 0xCD, 0xBD,
+ 0xD1, 0x90, 0xD1, 0x91, 0xD1, 0x92, 0xD1, 0x93, 0xD1, 0x94, 0xD1, 0x95,
+ 0xD1, 0x96, 0xD1, 0x97, 0xD1, 0x98, 0xD1, 0x99, 0xD1, 0x9A, 0xD1, 0x9B,
+ 0xD1, 0x9C, 0xD1, 0x9D, 0xD1, 0x9E, 0xD1, 0x9F, 0xD0, 0xB0, 0xD0, 0xB1,
+ 0xD0, 0xB2, 0xD0, 0xB3, 0xD0, 0xB4, 0xD0, 0xB5, 0xD0, 0xB6, 0xD0, 0xB7,
+ 0xD0, 0xB8, 0xD0, 0xB9, 0xD0, 0xBA, 0xD0, 0xBB, 0xD0, 0xBC, 0xD0, 0xBD,
+ 0xD0, 0xBE, 0xD0, 0xBF, 0xD1, 0x80, 0xD1, 0x81, 0xD1, 0x82, 0xD1, 0x83,
+ 0xD1, 0x84, 0xD1, 0x85, 0xD1, 0x86, 0xD1, 0x87, 0xD1, 0x88, 0xD1, 0x89,
+ 0xD1, 0x8A, 0xD1, 0x8B, 0xD1, 0x8C, 0xD1, 0x8D, 0xD1, 0x8E, 0xD1, 0x8F,
+ 0xD1, 0xA1, 0xD1, 0xA3, 0xD1, 0xA5, 0xD1, 0xA7, 0xD1, 0xA9, 0xD1, 0xAB,
+ 0xD1, 0xAD, 0xD1, 0xAF, 0xD1, 0xB1, 0xD1, 0xB3, 0xD1, 0xB5, 0xD1, 0xB7,
+ 0xD1, 0xB9, 0xD1, 0xBB, 0xD1, 0xBD, 0xD1, 0xBF, 0xD2, 0x81, 0xD2, 0x8B,
+ 0xD2, 0x8D, 0xD2, 0x8F, 0xD2, 0x91, 0xD2, 0x93, 0xD2, 0x95, 0xD2, 0x97,
+ 0xD2, 0x99, 0xD2, 0x9B, 0xD2, 0x9D, 0xD2, 0x9F, 0xD2, 0xA1, 0xD2, 0xA3,
+ 0xD2, 0xA5, 0xD2, 0xA7, 0xD2, 0xA9, 0xD2, 0xAB, 0xD2, 0xAD, 0xD2, 0xAF,
+ 0xD2, 0xB1, 0xD2, 0xB3, 0xD2, 0xB5, 0xD2, 0xB7, 0xD2, 0xB9, 0xD2, 0xBB,
+ 0xD2, 0xBD, 0xD2, 0xBF, 0xD3, 0x8F, 0xD3, 0x82, 0xD3, 0x84, 0xD3, 0x86,
+ 0xD3, 0x88, 0xD3, 0x8A, 0xD3, 0x8C, 0xD3, 0x8E, 0xD3, 0x91, 0xD3, 0x93,
+ 0xD3, 0x95, 0xD3, 0x97, 0xD3, 0x99, 0xD3, 0x9B, 0xD3, 0x9D, 0xD3, 0x9F,
+ 0xD3, 0xA1, 0xD3, 0xA3, 0xD3, 0xA5, 0xD3, 0xA7, 0xD3, 0xA9, 0xD3, 0xAB,
+ 0xD3, 0xAD, 0xD3, 0xAF, 0xD3, 0xB1, 0xD3, 0xB3, 0xD3, 0xB5, 0xD3, 0xB7,
+ 0xD3, 0xB9, 0xD3, 0xBB, 0xD3, 0xBD, 0xD3, 0xBF, 0xD4, 0x81, 0xD4, 0x83,
+ 0xD4, 0x85, 0xD4, 0x87, 0xD4, 0x89, 0xD4, 0x8B, 0xD4, 0x8D, 0xD4, 0x8F,
+ 0xD4, 0x91, 0xD4, 0x93, 0xD4, 0x95, 0xD4, 0x97, 0xD4, 0x99, 0xD4, 0x9B,
+ 0xD4, 0x9D, 0xD4, 0x9F, 0xD4, 0xA1, 0xD4, 0xA3, 0xD4, 0xA5, 0xD4, 0xA7,
+ 0xD4, 0xA9, 0xD4, 0xAB, 0xD4, 0xAD, 0xD4, 0xAF, 0xD5, 0xA1, 0xD5, 0xA2,
+ 0xD5, 0xA3, 0xD5, 0xA4, 0xD5, 0xA5, 0xD5, 0xA6, 0xD5, 0xA7, 0xD5, 0xA8,
+ 0xD5, 0xA9, 0xD5, 0xAA, 0xD5, 0xAB, 0xD5, 0xAC, 0xD5, 0xAD, 0xD5, 0xAE,
+ 0xD5, 0xAF, 0xD5, 0xB0, 0xD5, 0xB1, 0xD5, 0xB2, 0xD5, 0xB3, 0xD5, 0xB4,
+ 0xD5, 0xB5, 0xD5, 0xB6, 0xD5, 0xB7, 0xD5, 0xB8, 0xD5, 0xB9, 0xD5, 0xBA,
+ 0xD5, 0xBB, 0xD5, 0xBC, 0xD5, 0xBD, 0xD5, 0xBE, 0xD5, 0xBF, 0xD6, 0x80,
+ 0xD6, 0x81, 0xD6, 0x82, 0xD6, 0x83, 0xD6, 0x84, 0xD6, 0x85, 0xD6, 0x86,
+ 0xD5, 0xA5, 0xD6, 0x82, 0xE2, 0xB4, 0x80, 0x00, 0xE2, 0xB4, 0x81, 0x00,
+ 0xE2, 0xB4, 0x82, 0x00, 0xE2, 0xB4, 0x83, 0x00, 0xE2, 0xB4, 0x84, 0x00,
+ 0xE2, 0xB4, 0x85, 0x00, 0xE2, 0xB4, 0x86, 0x00, 0xE2, 0xB4, 0x87, 0x00,
+ 0xE2, 0xB4, 0x88, 0x00, 0xE2, 0xB4, 0x89, 0x00, 0xE2, 0xB4, 0x8A, 0x00,
+ 0xE2, 0xB4, 0x8B, 0x00, 0xE2, 0xB4, 0x8C, 0x00, 0xE2, 0xB4, 0x8D, 0x00,
+ 0xE2, 0xB4, 0x8E, 0x00, 0xE2, 0xB4, 0x8F, 0x00, 0xE2, 0xB4, 0x90, 0x00,
+ 0xE2, 0xB4, 0x91, 0x00, 0xE2, 0xB4, 0x92, 0x00, 0xE2, 0xB4, 0x93, 0x00,
+ 0xE2, 0xB4, 0x94, 0x00, 0xE2, 0xB4, 0x95, 0x00, 0xE2, 0xB4, 0x96, 0x00,
+ 0xE2, 0xB4, 0x97, 0x00, 0xE2, 0xB4, 0x98, 0x00, 0xE2, 0xB4, 0x99, 0x00,
+ 0xE2, 0xB4, 0x9A, 0x00, 0xE2, 0xB4, 0x9B, 0x00, 0xE2, 0xB4, 0x9C, 0x00,
+ 0xE2, 0xB4, 0x9D, 0x00, 0xE2, 0xB4, 0x9E, 0x00, 0xE2, 0xB4, 0x9F, 0x00,
+ 0xE2, 0xB4, 0xA0, 0x00, 0xE2, 0xB4, 0xA1, 0x00, 0xE2, 0xB4, 0xA2, 0x00,
+ 0xE2, 0xB4, 0xA3, 0x00, 0xE2, 0xB4, 0xA4, 0x00, 0xE2, 0xB4, 0xA5, 0x00,
+ 0xE2, 0xB4, 0xA7, 0x00, 0xE2, 0xB4, 0xAD, 0x00, 0xE1, 0x8F, 0xB0, 0x00,
+ 0xE1, 0x8F, 0xB1, 0x00, 0xE1, 0x8F, 0xB2, 0x00, 0xE1, 0x8F, 0xB3, 0x00,
+ 0xE1, 0x8F, 0xB4, 0x00, 0xE1, 0x8F, 0xB5, 0x00, 0xD0, 0xB2, 0xD0, 0xB4,
+ 0xD0, 0xBE, 0xD1, 0x81, 0xD1, 0x82, 0xD1, 0x82, 0xD1, 0x8A, 0xD1, 0xA3,
+ 0xEA, 0x99, 0x8B, 0x00, 0xE1, 0xB2, 0x8A, 0x00, 0xE1, 0x83, 0x90, 0x00,
+ 0xE1, 0x83, 0x91, 0x00, 0xE1, 0x83, 0x92, 0x00, 0xE1, 0x83, 0x93, 0x00,
+ 0xE1, 0x83, 0x94, 0x00, 0xE1, 0x83, 0x95, 0x00, 0xE1, 0x83, 0x96, 0x00,
+ 0xE1, 0x83, 0x97, 0x00, 0xE1, 0x83, 0x98, 0x00, 0xE1, 0x83, 0x99, 0x00,
+ 0xE1, 0x83, 0x9A, 0x00, 0xE1, 0x83, 0x9B, 0x00, 0xE1, 0x83, 0x9C, 0x00,
+ 0xE1, 0x83, 0x9D, 0x00, 0xE1, 0x83, 0x9E, 0x00, 0xE1, 0x83, 0x9F, 0x00,
+ 0xE1, 0x83, 0xA0, 0x00, 0xE1, 0x83, 0xA1, 0x00, 0xE1, 0x83, 0xA2, 0x00,
+ 0xE1, 0x83, 0xA3, 0x00, 0xE1, 0x83, 0xA4, 0x00, 0xE1, 0x83, 0xA5, 0x00,
+ 0xE1, 0x83, 0xA6, 0x00, 0xE1, 0x83, 0xA7, 0x00, 0xE1, 0x83, 0xA8, 0x00,
+ 0xE1, 0x83, 0xA9, 0x00, 0xE1, 0x83, 0xAA, 0x00, 0xE1, 0x83, 0xAB, 0x00,
+ 0xE1, 0x83, 0xAC, 0x00, 0xE1, 0x83, 0xAD, 0x00, 0xE1, 0x83, 0xAE, 0x00,
+ 0xE1, 0x83, 0xAF, 0x00, 0xE1, 0x83, 0xB0, 0x00, 0xE1, 0x83, 0xB1, 0x00,
+ 0xE1, 0x83, 0xB2, 0x00, 0xE1, 0x83, 0xB3, 0x00, 0xE1, 0x83, 0xB4, 0x00,
+ 0xE1, 0x83, 0xB5, 0x00, 0xE1, 0x83, 0xB6, 0x00, 0xE1, 0x83, 0xB7, 0x00,
+ 0xE1, 0x83, 0xB8, 0x00, 0xE1, 0x83, 0xB9, 0x00, 0xE1, 0x83, 0xBA, 0x00,
+ 0xE1, 0x83, 0xBD, 0x00, 0xE1, 0x83, 0xBE, 0x00, 0xE1, 0x83, 0xBF, 0x00,
+ 0xE1, 0xB8, 0x81, 0x00, 0xE1, 0xB8, 0x83, 0x00, 0xE1, 0xB8, 0x85, 0x00,
+ 0xE1, 0xB8, 0x87, 0x00, 0xE1, 0xB8, 0x89, 0x00, 0xE1, 0xB8, 0x8B, 0x00,
+ 0xE1, 0xB8, 0x8D, 0x00, 0xE1, 0xB8, 0x8F, 0x00, 0xE1, 0xB8, 0x91, 0x00,
+ 0xE1, 0xB8, 0x93, 0x00, 0xE1, 0xB8, 0x95, 0x00, 0xE1, 0xB8, 0x97, 0x00,
+ 0xE1, 0xB8, 0x99, 0x00, 0xE1, 0xB8, 0x9B, 0x00, 0xE1, 0xB8, 0x9D, 0x00,
+ 0xE1, 0xB8, 0x9F, 0x00, 0xE1, 0xB8, 0xA1, 0x00, 0xE1, 0xB8, 0xA3, 0x00,
+ 0xE1, 0xB8, 0xA5, 0x00, 0xE1, 0xB8, 0xA7, 0x00, 0xE1, 0xB8, 0xA9, 0x00,
+ 0xE1, 0xB8, 0xAB, 0x00, 0xE1, 0xB8, 0xAD, 0x00, 0xE1, 0xB8, 0xAF, 0x00,
+ 0xE1, 0xB8, 0xB1, 0x00, 0xE1, 0xB8, 0xB3, 0x00, 0xE1, 0xB8, 0xB5, 0x00,
+ 0xE1, 0xB8, 0xB7, 0x00, 0xE1, 0xB8, 0xB9, 0x00, 0xE1, 0xB8, 0xBB, 0x00,
+ 0xE1, 0xB8, 0xBD, 0x00, 0xE1, 0xB8, 0xBF, 0x00, 0xE1, 0xB9, 0x81, 0x00,
+ 0xE1, 0xB9, 0x83, 0x00, 0xE1, 0xB9, 0x85, 0x00, 0xE1, 0xB9, 0x87, 0x00,
+ 0xE1, 0xB9, 0x89, 0x00, 0xE1, 0xB9, 0x8B, 0x00, 0xE1, 0xB9, 0x8D, 0x00,
+ 0xE1, 0xB9, 0x8F, 0x00, 0xE1, 0xB9, 0x91, 0x00, 0xE1, 0xB9, 0x93, 0x00,
+ 0xE1, 0xB9, 0x95, 0x00, 0xE1, 0xB9, 0x97, 0x00, 0xE1, 0xB9, 0x99, 0x00,
+ 0xE1, 0xB9, 0x9B, 0x00, 0xE1, 0xB9, 0x9D, 0x00, 0xE1, 0xB9, 0x9F, 0x00,
+ 0xE1, 0xB9, 0xA1, 0x00, 0xE1, 0xB9, 0xA3, 0x00, 0xE1, 0xB9, 0xA5, 0x00,
+ 0xE1, 0xB9, 0xA7, 0x00, 0xE1, 0xB9, 0xA9, 0x00, 0xE1, 0xB9, 0xAB, 0x00,
+ 0xE1, 0xB9, 0xAD, 0x00, 0xE1, 0xB9, 0xAF, 0x00, 0xE1, 0xB9, 0xB1, 0x00,
+ 0xE1, 0xB9, 0xB3, 0x00, 0xE1, 0xB9, 0xB5, 0x00, 0xE1, 0xB9, 0xB7, 0x00,
+ 0xE1, 0xB9, 0xB9, 0x00, 0xE1, 0xB9, 0xBB, 0x00, 0xE1, 0xB9, 0xBD, 0x00,
+ 0xE1, 0xB9, 0xBF, 0x00, 0xE1, 0xBA, 0x81, 0x00, 0xE1, 0xBA, 0x83, 0x00,
+ 0xE1, 0xBA, 0x85, 0x00, 0xE1, 0xBA, 0x87, 0x00, 0xE1, 0xBA, 0x89, 0x00,
+ 0xE1, 0xBA, 0x8B, 0x00, 0xE1, 0xBA, 0x8D, 0x00, 0xE1, 0xBA, 0x8F, 0x00,
+ 0xE1, 0xBA, 0x91, 0x00, 0xE1, 0xBA, 0x93, 0x00, 0xE1, 0xBA, 0x95, 0x00,
+ 0x68, 0xCC, 0xB1, 0x00, 0x74, 0xCC, 0x88, 0x00, 0x77, 0xCC, 0x8A, 0x00,
+ 0x79, 0xCC, 0x8A, 0x00, 0x61, 0xCA, 0xBE, 0x00, 0xE1, 0xB9, 0xA1, 0x00,
+ 0x73, 0x73, 0xE1, 0xBA, 0xA1, 0x00, 0xE1, 0xBA, 0xA3, 0x00, 0xE1, 0xBA,
+ 0xA5, 0x00, 0xE1, 0xBA, 0xA7, 0x00, 0xE1, 0xBA, 0xA9, 0x00, 0xE1, 0xBA,
+ 0xAB, 0x00, 0xE1, 0xBA, 0xAD, 0x00, 0xE1, 0xBA, 0xAF, 0x00, 0xE1, 0xBA,
+ 0xB1, 0x00, 0xE1, 0xBA, 0xB3, 0x00, 0xE1, 0xBA, 0xB5, 0x00, 0xE1, 0xBA,
+ 0xB7, 0x00, 0xE1, 0xBA, 0xB9, 0x00, 0xE1, 0xBA, 0xBB, 0x00, 0xE1, 0xBA,
+ 0xBD, 0x00, 0xE1, 0xBA, 0xBF, 0x00, 0xE1, 0xBB, 0x81, 0x00, 0xE1, 0xBB,
+ 0x83, 0x00, 0xE1, 0xBB, 0x85, 0x00, 0xE1, 0xBB, 0x87, 0x00, 0xE1, 0xBB,
+ 0x89, 0x00, 0xE1, 0xBB, 0x8B, 0x00, 0xE1, 0xBB, 0x8D, 0x00, 0xE1, 0xBB,
+ 0x8F, 0x00, 0xE1, 0xBB, 0x91, 0x00, 0xE1, 0xBB, 0x93, 0x00, 0xE1, 0xBB,
+ 0x95, 0x00, 0xE1, 0xBB, 0x97, 0x00, 0xE1, 0xBB, 0x99, 0x00, 0xE1, 0xBB,
+ 0x9B, 0x00, 0xE1, 0xBB, 0x9D, 0x00, 0xE1, 0xBB, 0x9F, 0x00, 0xE1, 0xBB,
+ 0xA1, 0x00, 0xE1, 0xBB, 0xA3, 0x00, 0xE1, 0xBB, 0xA5, 0x00, 0xE1, 0xBB,
+ 0xA7, 0x00, 0xE1, 0xBB, 0xA9, 0x00, 0xE1, 0xBB, 0xAB, 0x00, 0xE1, 0xBB,
+ 0xAD, 0x00, 0xE1, 0xBB, 0xAF, 0x00, 0xE1, 0xBB, 0xB1, 0x00, 0xE1, 0xBB,
+ 0xB3, 0x00, 0xE1, 0xBB, 0xB5, 0x00, 0xE1, 0xBB, 0xB7, 0x00, 0xE1, 0xBB,
+ 0xB9, 0x00, 0xE1, 0xBB, 0xBB, 0x00, 0xE1, 0xBB, 0xBD, 0x00, 0xE1, 0xBB,
+ 0xBF, 0x00, 0xE1, 0xBC, 0x80, 0x00, 0xE1, 0xBC, 0x81, 0x00, 0xE1, 0xBC,
+ 0x82, 0x00, 0xE1, 0xBC, 0x83, 0x00, 0xE1, 0xBC, 0x84, 0x00, 0xE1, 0xBC,
+ 0x85, 0x00, 0xE1, 0xBC, 0x86, 0x00, 0xE1, 0xBC, 0x87, 0x00, 0xE1, 0xBC,
+ 0x90, 0x00, 0xE1, 0xBC, 0x91, 0x00, 0xE1, 0xBC, 0x92, 0x00, 0xE1, 0xBC,
+ 0x93, 0x00, 0xE1, 0xBC, 0x94, 0x00, 0xE1, 0xBC, 0x95, 0x00, 0xE1, 0xBC,
+ 0xA0, 0x00, 0xE1, 0xBC, 0xA1, 0x00, 0xE1, 0xBC, 0xA2, 0x00, 0xE1, 0xBC,
+ 0xA3, 0x00, 0xE1, 0xBC, 0xA4, 0x00, 0xE1, 0xBC, 0xA5, 0x00, 0xE1, 0xBC,
+ 0xA6, 0x00, 0xE1, 0xBC, 0xA7, 0x00, 0xE1, 0xBC, 0xB0, 0x00, 0xE1, 0xBC,
+ 0xB1, 0x00, 0xE1, 0xBC, 0xB2, 0x00, 0xE1, 0xBC, 0xB3, 0x00, 0xE1, 0xBC,
+ 0xB4, 0x00, 0xE1, 0xBC, 0xB5, 0x00, 0xE1, 0xBC, 0xB6, 0x00, 0xE1, 0xBC,
+ 0xB7, 0x00, 0xE1, 0xBD, 0x80, 0x00, 0xE1, 0xBD, 0x81, 0x00, 0xE1, 0xBD,
+ 0x82, 0x00, 0xE1, 0xBD, 0x83, 0x00, 0xE1, 0xBD, 0x84, 0x00, 0xE1, 0xBD,
+ 0x85, 0x00, 0xCF, 0x85, 0xCC, 0x93, 0xCF, 0x85, 0xCC, 0x93, 0xCC, 0x80,
+ 0xCF, 0x85, 0xCC, 0x93, 0xCC, 0x81, 0xCF, 0x85, 0xCC, 0x93, 0xCD, 0x82,
+ 0xE1, 0xBD, 0x91, 0x00, 0xE1, 0xBD, 0x93, 0x00, 0xE1, 0xBD, 0x95, 0x00,
+ 0xE1, 0xBD, 0x97, 0x00, 0xE1, 0xBD, 0xA0, 0x00, 0xE1, 0xBD, 0xA1, 0x00,
+ 0xE1, 0xBD, 0xA2, 0x00, 0xE1, 0xBD, 0xA3, 0x00, 0xE1, 0xBD, 0xA4, 0x00,
+ 0xE1, 0xBD, 0xA5, 0x00, 0xE1, 0xBD, 0xA6, 0x00, 0xE1, 0xBD, 0xA7, 0x00,
+ 0xE1, 0xBC, 0x80, 0xCE, 0xB9, 0x00, 0xE1, 0xBC, 0x81, 0xCE, 0xB9, 0x00,
+ 0xE1, 0xBC, 0x82, 0xCE, 0xB9, 0x00, 0xE1, 0xBC, 0x83, 0xCE, 0xB9, 0x00,
+ 0xE1, 0xBC, 0x84, 0xCE, 0xB9, 0x00, 0xE1, 0xBC, 0x85, 0xCE, 0xB9, 0x00,
+ 0xE1, 0xBC, 0x86, 0xCE, 0xB9, 0x00, 0xE1, 0xBC, 0x87, 0xCE, 0xB9, 0x00,
+ 0xE1, 0xBC, 0x80, 0xCE, 0xB9, 0x00, 0xE1, 0xBC, 0x81, 0xCE, 0xB9, 0x00,
+ 0xE1, 0xBC, 0x82, 0xCE, 0xB9, 0x00, 0xE1, 0xBC, 0x83, 0xCE, 0xB9, 0x00,
+ 0xE1, 0xBC, 0x84, 0xCE, 0xB9, 0x00, 0xE1, 0xBC, 0x85, 0xCE, 0xB9, 0x00,
+ 0xE1, 0xBC, 0x86, 0xCE, 0xB9, 0x00, 0xE1, 0xBC, 0x87, 0xCE, 0xB9, 0x00,
+ 0xE1, 0xBC, 0xA0, 0xCE, 0xB9, 0x00, 0xE1, 0xBC, 0xA1, 0xCE, 0xB9, 0x00,
+ 0xE1, 0xBC, 0xA2, 0xCE, 0xB9, 0x00, 0xE1, 0xBC, 0xA3, 0xCE, 0xB9, 0x00,
+ 0xE1, 0xBC, 0xA4, 0xCE, 0xB9, 0x00, 0xE1, 0xBC, 0xA5, 0xCE, 0xB9, 0x00,
+ 0xE1, 0xBC, 0xA6, 0xCE, 0xB9, 0x00, 0xE1, 0xBC, 0xA7, 0xCE, 0xB9, 0x00,
+ 0xE1, 0xBC, 0xA0, 0xCE, 0xB9, 0x00, 0xE1, 0xBC, 0xA1, 0xCE, 0xB9, 0x00,
+ 0xE1, 0xBC, 0xA2, 0xCE, 0xB9, 0x00, 0xE1, 0xBC, 0xA3, 0xCE, 0xB9, 0x00,
+ 0xE1, 0xBC, 0xA4, 0xCE, 0xB9, 0x00, 0xE1, 0xBC, 0xA5, 0xCE, 0xB9, 0x00,
+ 0xE1, 0xBC, 0xA6, 0xCE, 0xB9, 0x00, 0xE1, 0xBC, 0xA7, 0xCE, 0xB9, 0x00,
+ 0xE1, 0xBD, 0xA0, 0xCE, 0xB9, 0x00, 0xE1, 0xBD, 0xA1, 0xCE, 0xB9, 0x00,
+ 0xE1, 0xBD, 0xA2, 0xCE, 0xB9, 0x00, 0xE1, 0xBD, 0xA3, 0xCE, 0xB9, 0x00,
+ 0xE1, 0xBD, 0xA4, 0xCE, 0xB9, 0x00, 0xE1, 0xBD, 0xA5, 0xCE, 0xB9, 0x00,
+ 0xE1, 0xBD, 0xA6, 0xCE, 0xB9, 0x00, 0xE1, 0xBD, 0xA7, 0xCE, 0xB9, 0x00,
+ 0xE1, 0xBD, 0xA0, 0xCE, 0xB9, 0x00, 0xE1, 0xBD, 0xA1, 0xCE, 0xB9, 0x00,
+ 0xE1, 0xBD, 0xA2, 0xCE, 0xB9, 0x00, 0xE1, 0xBD, 0xA3, 0xCE, 0xB9, 0x00,
+ 0xE1, 0xBD, 0xA4, 0xCE, 0xB9, 0x00, 0xE1, 0xBD, 0xA5, 0xCE, 0xB9, 0x00,
+ 0xE1, 0xBD, 0xA6, 0xCE, 0xB9, 0x00, 0xE1, 0xBD, 0xA7, 0xCE, 0xB9, 0x00,
+ 0xE1, 0xBD, 0xB0, 0xCE, 0xB9, 0x00, 0xCE, 0xB1, 0xCE, 0xB9, 0xCE, 0xAC,
+ 0xCE, 0xB9, 0xCE, 0xB1, 0xCD, 0x82, 0xCE, 0xB1, 0xCD, 0x82, 0xCE, 0xB9,
+ 0xE1, 0xBE, 0xB0, 0x00, 0xE1, 0xBE, 0xB1, 0x00, 0xE1, 0xBD, 0xB0, 0x00,
+ 0xE1, 0xBD, 0xB1, 0x00, 0xCE, 0xB1, 0xCE, 0xB9, 0xCE, 0xB9, 0xE1, 0xBD,
+ 0xB4, 0xCE, 0xB9, 0x00, 0xCE, 0xB7, 0xCE, 0xB9, 0xCE, 0xAE, 0xCE, 0xB9,
+ 0xCE, 0xB7, 0xCD, 0x82, 0xCE, 0xB7, 0xCD, 0x82, 0xCE, 0xB9, 0xE1, 0xBD,
+ 0xB2, 0x00, 0xE1, 0xBD, 0xB3, 0x00, 0xE1, 0xBD, 0xB4, 0x00, 0xE1, 0xBD,
+ 0xB5, 0x00, 0xCE, 0xB7, 0xCE, 0xB9, 0xCE, 0xB9, 0xCC, 0x88, 0xCC, 0x80,
+ 0xCE, 0xB9, 0xCC, 0x88, 0xCC, 0x81, 0xCE, 0xB9, 0xCD, 0x82, 0xCE, 0xB9,
+ 0xCC, 0x88, 0xCD, 0x82, 0xE1, 0xBF, 0x90, 0x00, 0xE1, 0xBF, 0x91, 0x00,
+ 0xE1, 0xBD, 0xB6, 0x00, 0xE1, 0xBD, 0xB7, 0x00, 0xCF, 0x85, 0xCC, 0x88,
+ 0xCC, 0x80, 0xCF, 0x85, 0xCC, 0x88, 0xCC, 0x81, 0xCF, 0x81, 0xCC, 0x93,
+ 0xCF, 0x85, 0xCD, 0x82, 0xCF, 0x85, 0xCC, 0x88, 0xCD, 0x82, 0xE1, 0xBF,
+ 0xA0, 0x00, 0xE1, 0xBF, 0xA1, 0x00, 0xE1, 0xBD, 0xBA, 0x00, 0xE1, 0xBD,
+ 0xBB, 0x00, 0xE1, 0xBF, 0xA5, 0x00, 0xE1, 0xBD, 0xBC, 0xCE, 0xB9, 0x00,
+ 0xCF, 0x89, 0xCE, 0xB9, 0xCF, 0x8E, 0xCE, 0xB9, 0xCF, 0x89, 0xCD, 0x82,
+ 0xCF, 0x89, 0xCD, 0x82, 0xCE, 0xB9, 0xE1, 0xBD, 0xB8, 0x00, 0xE1, 0xBD,
+ 0xB9, 0x00, 0xE1, 0xBD, 0xBC, 0x00, 0xE1, 0xBD, 0xBD, 0x00, 0xCF, 0x89,
+ 0xCE, 0xB9, 0xCF, 0x89, 0x6B, 0x00, 0xC3, 0xA5, 0xE2, 0x85, 0x8E, 0x00,
+ 0xE2, 0x85, 0xB0, 0x00, 0xE2, 0x85, 0xB1, 0x00, 0xE2, 0x85, 0xB2, 0x00,
+ 0xE2, 0x85, 0xB3, 0x00, 0xE2, 0x85, 0xB4, 0x00, 0xE2, 0x85, 0xB5, 0x00,
+ 0xE2, 0x85, 0xB6, 0x00, 0xE2, 0x85, 0xB7, 0x00, 0xE2, 0x85, 0xB8, 0x00,
+ 0xE2, 0x85, 0xB9, 0x00, 0xE2, 0x85, 0xBA, 0x00, 0xE2, 0x85, 0xBB, 0x00,
+ 0xE2, 0x85, 0xBC, 0x00, 0xE2, 0x85, 0xBD, 0x00, 0xE2, 0x85, 0xBE, 0x00,
+ 0xE2, 0x85, 0xBF, 0x00, 0xE2, 0x86, 0x84, 0x00, 0xE2, 0x93, 0x90, 0x00,
+ 0xE2, 0x93, 0x91, 0x00, 0xE2, 0x93, 0x92, 0x00, 0xE2, 0x93, 0x93, 0x00,
+ 0xE2, 0x93, 0x94, 0x00, 0xE2, 0x93, 0x95, 0x00, 0xE2, 0x93, 0x96, 0x00,
+ 0xE2, 0x93, 0x97, 0x00, 0xE2, 0x93, 0x98, 0x00, 0xE2, 0x93, 0x99, 0x00,
+ 0xE2, 0x93, 0x9A, 0x00, 0xE2, 0x93, 0x9B, 0x00, 0xE2, 0x93, 0x9C, 0x00,
+ 0xE2, 0x93, 0x9D, 0x00, 0xE2, 0x93, 0x9E, 0x00, 0xE2, 0x93, 0x9F, 0x00,
+ 0xE2, 0x93, 0xA0, 0x00, 0xE2, 0x93, 0xA1, 0x00, 0xE2, 0x93, 0xA2, 0x00,
+ 0xE2, 0x93, 0xA3, 0x00, 0xE2, 0x93, 0xA4, 0x00, 0xE2, 0x93, 0xA5, 0x00,
+ 0xE2, 0x93, 0xA6, 0x00, 0xE2, 0x93, 0xA7, 0x00, 0xE2, 0x93, 0xA8, 0x00,
+ 0xE2, 0x93, 0xA9, 0x00, 0xE2, 0xB0, 0xB0, 0x00, 0xE2, 0xB0, 0xB1, 0x00,
+ 0xE2, 0xB0, 0xB2, 0x00, 0xE2, 0xB0, 0xB3, 0x00, 0xE2, 0xB0, 0xB4, 0x00,
+ 0xE2, 0xB0, 0xB5, 0x00, 0xE2, 0xB0, 0xB6, 0x00, 0xE2, 0xB0, 0xB7, 0x00,
+ 0xE2, 0xB0, 0xB8, 0x00, 0xE2, 0xB0, 0xB9, 0x00, 0xE2, 0xB0, 0xBA, 0x00,
+ 0xE2, 0xB0, 0xBB, 0x00, 0xE2, 0xB0, 0xBC, 0x00, 0xE2, 0xB0, 0xBD, 0x00,
+ 0xE2, 0xB0, 0xBE, 0x00, 0xE2, 0xB0, 0xBF, 0x00, 0xE2, 0xB1, 0x80, 0x00,
+ 0xE2, 0xB1, 0x81, 0x00, 0xE2, 0xB1, 0x82, 0x00, 0xE2, 0xB1, 0x83, 0x00,
+ 0xE2, 0xB1, 0x84, 0x00, 0xE2, 0xB1, 0x85, 0x00, 0xE2, 0xB1, 0x86, 0x00,
+ 0xE2, 0xB1, 0x87, 0x00, 0xE2, 0xB1, 0x88, 0x00, 0xE2, 0xB1, 0x89, 0x00,
+ 0xE2, 0xB1, 0x8A, 0x00, 0xE2, 0xB1, 0x8B, 0x00, 0xE2, 0xB1, 0x8C, 0x00,
+ 0xE2, 0xB1, 0x8D, 0x00, 0xE2, 0xB1, 0x8E, 0x00, 0xE2, 0xB1, 0x8F, 0x00,
+ 0xE2, 0xB1, 0x90, 0x00, 0xE2, 0xB1, 0x91, 0x00, 0xE2, 0xB1, 0x92, 0x00,
+ 0xE2, 0xB1, 0x93, 0x00, 0xE2, 0xB1, 0x94, 0x00, 0xE2, 0xB1, 0x95, 0x00,
+ 0xE2, 0xB1, 0x96, 0x00, 0xE2, 0xB1, 0x97, 0x00, 0xE2, 0xB1, 0x98, 0x00,
+ 0xE2, 0xB1, 0x99, 0x00, 0xE2, 0xB1, 0x9A, 0x00, 0xE2, 0xB1, 0x9B, 0x00,
+ 0xE2, 0xB1, 0x9C, 0x00, 0xE2, 0xB1, 0x9D, 0x00, 0xE2, 0xB1, 0x9E, 0x00,
+ 0xE2, 0xB1, 0x9F, 0x00, 0xE2, 0xB1, 0xA1, 0x00, 0xC9, 0xAB, 0xE1, 0xB5,
+ 0xBD, 0x00, 0xC9, 0xBD, 0xE2, 0xB1, 0xA8, 0x00, 0xE2, 0xB1, 0xAA, 0x00,
+ 0xE2, 0xB1, 0xAC, 0x00, 0xC9, 0x91, 0xC9, 0xB1, 0xC9, 0x90, 0xC9, 0x92,
+ 0xE2, 0xB1, 0xB3, 0x00, 0xE2, 0xB1, 0xB6, 0x00, 0xC8, 0xBF, 0xC9, 0x80,
+ 0xE2, 0xB2, 0x81, 0x00, 0xE2, 0xB2, 0x83, 0x00, 0xE2, 0xB2, 0x85, 0x00,
+ 0xE2, 0xB2, 0x87, 0x00, 0xE2, 0xB2, 0x89, 0x00, 0xE2, 0xB2, 0x8B, 0x00,
+ 0xE2, 0xB2, 0x8D, 0x00, 0xE2, 0xB2, 0x8F, 0x00, 0xE2, 0xB2, 0x91, 0x00,
+ 0xE2, 0xB2, 0x93, 0x00, 0xE2, 0xB2, 0x95, 0x00, 0xE2, 0xB2, 0x97, 0x00,
+ 0xE2, 0xB2, 0x99, 0x00, 0xE2, 0xB2, 0x9B, 0x00, 0xE2, 0xB2, 0x9D, 0x00,
+ 0xE2, 0xB2, 0x9F, 0x00, 0xE2, 0xB2, 0xA1, 0x00, 0xE2, 0xB2, 0xA3, 0x00,
+ 0xE2, 0xB2, 0xA5, 0x00, 0xE2, 0xB2, 0xA7, 0x00, 0xE2, 0xB2, 0xA9, 0x00,
+ 0xE2, 0xB2, 0xAB, 0x00, 0xE2, 0xB2, 0xAD, 0x00, 0xE2, 0xB2, 0xAF, 0x00,
+ 0xE2, 0xB2, 0xB1, 0x00, 0xE2, 0xB2, 0xB3, 0x00, 0xE2, 0xB2, 0xB5, 0x00,
+ 0xE2, 0xB2, 0xB7, 0x00, 0xE2, 0xB2, 0xB9, 0x00, 0xE2, 0xB2, 0xBB, 0x00,
+ 0xE2, 0xB2, 0xBD, 0x00, 0xE2, 0xB2, 0xBF, 0x00, 0xE2, 0xB3, 0x81, 0x00,
+ 0xE2, 0xB3, 0x83, 0x00, 0xE2, 0xB3, 0x85, 0x00, 0xE2, 0xB3, 0x87, 0x00,
+ 0xE2, 0xB3, 0x89, 0x00, 0xE2, 0xB3, 0x8B, 0x00, 0xE2, 0xB3, 0x8D, 0x00,
+ 0xE2, 0xB3, 0x8F, 0x00, 0xE2, 0xB3, 0x91, 0x00, 0xE2, 0xB3, 0x93, 0x00,
+ 0xE2, 0xB3, 0x95, 0x00, 0xE2, 0xB3, 0x97, 0x00, 0xE2, 0xB3, 0x99, 0x00,
+ 0xE2, 0xB3, 0x9B, 0x00, 0xE2, 0xB3, 0x9D, 0x00, 0xE2, 0xB3, 0x9F, 0x00,
+ 0xE2, 0xB3, 0xA1, 0x00, 0xE2, 0xB3, 0xA3, 0x00, 0xE2, 0xB3, 0xAC, 0x00,
+ 0xE2, 0xB3, 0xAE, 0x00, 0xE2, 0xB3, 0xB3, 0x00, 0xEA, 0x99, 0x81, 0x00,
+ 0xEA, 0x99, 0x83, 0x00, 0xEA, 0x99, 0x85, 0x00, 0xEA, 0x99, 0x87, 0x00,
+ 0xEA, 0x99, 0x89, 0x00, 0xEA, 0x99, 0x8B, 0x00, 0xEA, 0x99, 0x8D, 0x00,
+ 0xEA, 0x99, 0x8F, 0x00, 0xEA, 0x99, 0x91, 0x00, 0xEA, 0x99, 0x93, 0x00,
+ 0xEA, 0x99, 0x95, 0x00, 0xEA, 0x99, 0x97, 0x00, 0xEA, 0x99, 0x99, 0x00,
+ 0xEA, 0x99, 0x9B, 0x00, 0xEA, 0x99, 0x9D, 0x00, 0xEA, 0x99, 0x9F, 0x00,
+ 0xEA, 0x99, 0xA1, 0x00, 0xEA, 0x99, 0xA3, 0x00, 0xEA, 0x99, 0xA5, 0x00,
+ 0xEA, 0x99, 0xA7, 0x00, 0xEA, 0x99, 0xA9, 0x00, 0xEA, 0x99, 0xAB, 0x00,
+ 0xEA, 0x99, 0xAD, 0x00, 0xEA, 0x9A, 0x81, 0x00, 0xEA, 0x9A, 0x83, 0x00,
+ 0xEA, 0x9A, 0x85, 0x00, 0xEA, 0x9A, 0x87, 0x00, 0xEA, 0x9A, 0x89, 0x00,
+ 0xEA, 0x9A, 0x8B, 0x00, 0xEA, 0x9A, 0x8D, 0x00, 0xEA, 0x9A, 0x8F, 0x00,
+ 0xEA, 0x9A, 0x91, 0x00, 0xEA, 0x9A, 0x93, 0x00, 0xEA, 0x9A, 0x95, 0x00,
+ 0xEA, 0x9A, 0x97, 0x00, 0xEA, 0x9A, 0x99, 0x00, 0xEA, 0x9A, 0x9B, 0x00,
+ 0xEA, 0x9C, 0xA3, 0x00, 0xEA, 0x9C, 0xA5, 0x00, 0xEA, 0x9C, 0xA7, 0x00,
+ 0xEA, 0x9C, 0xA9, 0x00, 0xEA, 0x9C, 0xAB, 0x00, 0xEA, 0x9C, 0xAD, 0x00,
+ 0xEA, 0x9C, 0xAF, 0x00, 0xEA, 0x9C, 0xB3, 0x00, 0xEA, 0x9C, 0xB5, 0x00,
+ 0xEA, 0x9C, 0xB7, 0x00, 0xEA, 0x9C, 0xB9, 0x00, 0xEA, 0x9C, 0xBB, 0x00,
+ 0xEA, 0x9C, 0xBD, 0x00, 0xEA, 0x9C, 0xBF, 0x00, 0xEA, 0x9D, 0x81, 0x00,
+ 0xEA, 0x9D, 0x83, 0x00, 0xEA, 0x9D, 0x85, 0x00, 0xEA, 0x9D, 0x87, 0x00,
+ 0xEA, 0x9D, 0x89, 0x00, 0xEA, 0x9D, 0x8B, 0x00, 0xEA, 0x9D, 0x8D, 0x00,
+ 0xEA, 0x9D, 0x8F, 0x00, 0xEA, 0x9D, 0x91, 0x00, 0xEA, 0x9D, 0x93, 0x00,
+ 0xEA, 0x9D, 0x95, 0x00, 0xEA, 0x9D, 0x97, 0x00, 0xEA, 0x9D, 0x99, 0x00,
+ 0xEA, 0x9D, 0x9B, 0x00, 0xEA, 0x9D, 0x9D, 0x00, 0xEA, 0x9D, 0x9F, 0x00,
+ 0xEA, 0x9D, 0xA1, 0x00, 0xEA, 0x9D, 0xA3, 0x00, 0xEA, 0x9D, 0xA5, 0x00,
+ 0xEA, 0x9D, 0xA7, 0x00, 0xEA, 0x9D, 0xA9, 0x00, 0xEA, 0x9D, 0xAB, 0x00,
+ 0xEA, 0x9D, 0xAD, 0x00, 0xEA, 0x9D, 0xAF, 0x00, 0xEA, 0x9D, 0xBA, 0x00,
+ 0xEA, 0x9D, 0xBC, 0x00, 0xE1, 0xB5, 0xB9, 0x00, 0xEA, 0x9D, 0xBF, 0x00,
+ 0xEA, 0x9E, 0x81, 0x00, 0xEA, 0x9E, 0x83, 0x00, 0xEA, 0x9E, 0x85, 0x00,
+ 0xEA, 0x9E, 0x87, 0x00, 0xEA, 0x9E, 0x8C, 0x00, 0xC9, 0xA5, 0xEA, 0x9E,
+ 0x91, 0x00, 0xEA, 0x9E, 0x93, 0x00, 0xEA, 0x9E, 0x97, 0x00, 0xEA, 0x9E,
+ 0x99, 0x00, 0xEA, 0x9E, 0x9B, 0x00, 0xEA, 0x9E, 0x9D, 0x00, 0xEA, 0x9E,
+ 0x9F, 0x00, 0xEA, 0x9E, 0xA1, 0x00, 0xEA, 0x9E, 0xA3, 0x00, 0xEA, 0x9E,
+ 0xA5, 0x00, 0xEA, 0x9E, 0xA7, 0x00, 0xEA, 0x9E, 0xA9, 0x00, 0xC9, 0xA6,
+ 0xC9, 0x9C, 0xC9, 0xA1, 0xC9, 0xAC, 0xC9, 0xAA, 0xCA, 0x9E, 0xCA, 0x87,
+ 0xCA, 0x9D, 0xEA, 0xAD, 0x93, 0x00, 0xEA, 0x9E, 0xB5, 0x00, 0xEA, 0x9E,
+ 0xB7, 0x00, 0xEA, 0x9E, 0xB9, 0x00, 0xEA, 0x9E, 0xBB, 0x00, 0xEA, 0x9E,
+ 0xBD, 0x00, 0xEA, 0x9E, 0xBF, 0x00, 0xEA, 0x9F, 0x81, 0x00, 0xEA, 0x9F,
+ 0x83, 0x00, 0xEA, 0x9E, 0x94, 0x00, 0xCA, 0x82, 0xE1, 0xB6, 0x8E, 0x00,
+ 0xEA, 0x9F, 0x88, 0x00, 0xEA, 0x9F, 0x8A, 0x00, 0xC9, 0xA4, 0xEA, 0x9F,
+ 0x8D, 0x00, 0xEA, 0x9F, 0x8F, 0x00, 0xEA, 0x9F, 0x91, 0x00, 0xEA, 0x9F,
+ 0x93, 0x00, 0xEA, 0x9F, 0x95, 0x00, 0xEA, 0x9F, 0x97, 0x00, 0xEA, 0x9F,
+ 0x99, 0x00, 0xEA, 0x9F, 0x9B, 0x00, 0xC6, 0x9B, 0xEA, 0x9F, 0xB6, 0x00,
+ 0xE1, 0x8E, 0xA0, 0x00, 0xE1, 0x8E, 0xA1, 0x00, 0xE1, 0x8E, 0xA2, 0x00,
+ 0xE1, 0x8E, 0xA3, 0x00, 0xE1, 0x8E, 0xA4, 0x00, 0xE1, 0x8E, 0xA5, 0x00,
+ 0xE1, 0x8E, 0xA6, 0x00, 0xE1, 0x8E, 0xA7, 0x00, 0xE1, 0x8E, 0xA8, 0x00,
+ 0xE1, 0x8E, 0xA9, 0x00, 0xE1, 0x8E, 0xAA, 0x00, 0xE1, 0x8E, 0xAB, 0x00,
+ 0xE1, 0x8E, 0xAC, 0x00, 0xE1, 0x8E, 0xAD, 0x00, 0xE1, 0x8E, 0xAE, 0x00,
+ 0xE1, 0x8E, 0xAF, 0x00, 0xE1, 0x8E, 0xB0, 0x00, 0xE1, 0x8E, 0xB1, 0x00,
+ 0xE1, 0x8E, 0xB2, 0x00, 0xE1, 0x8E, 0xB3, 0x00, 0xE1, 0x8E, 0xB4, 0x00,
+ 0xE1, 0x8E, 0xB5, 0x00, 0xE1, 0x8E, 0xB6, 0x00, 0xE1, 0x8E, 0xB7, 0x00,
+ 0xE1, 0x8E, 0xB8, 0x00, 0xE1, 0x8E, 0xB9, 0x00, 0xE1, 0x8E, 0xBA, 0x00,
+ 0xE1, 0x8E, 0xBB, 0x00, 0xE1, 0x8E, 0xBC, 0x00, 0xE1, 0x8E, 0xBD, 0x00,
+ 0xE1, 0x8E, 0xBE, 0x00, 0xE1, 0x8E, 0xBF, 0x00, 0xE1, 0x8F, 0x80, 0x00,
+ 0xE1, 0x8F, 0x81, 0x00, 0xE1, 0x8F, 0x82, 0x00, 0xE1, 0x8F, 0x83, 0x00,
+ 0xE1, 0x8F, 0x84, 0x00, 0xE1, 0x8F, 0x85, 0x00, 0xE1, 0x8F, 0x86, 0x00,
+ 0xE1, 0x8F, 0x87, 0x00, 0xE1, 0x8F, 0x88, 0x00, 0xE1, 0x8F, 0x89, 0x00,
+ 0xE1, 0x8F, 0x8A, 0x00, 0xE1, 0x8F, 0x8B, 0x00, 0xE1, 0x8F, 0x8C, 0x00,
+ 0xE1, 0x8F, 0x8D, 0x00, 0xE1, 0x8F, 0x8E, 0x00, 0xE1, 0x8F, 0x8F, 0x00,
+ 0xE1, 0x8F, 0x90, 0x00, 0xE1, 0x8F, 0x91, 0x00, 0xE1, 0x8F, 0x92, 0x00,
+ 0xE1, 0x8F, 0x93, 0x00, 0xE1, 0x8F, 0x94, 0x00, 0xE1, 0x8F, 0x95, 0x00,
+ 0xE1, 0x8F, 0x96, 0x00, 0xE1, 0x8F, 0x97, 0x00, 0xE1, 0x8F, 0x98, 0x00,
+ 0xE1, 0x8F, 0x99, 0x00, 0xE1, 0x8F, 0x9A, 0x00, 0xE1, 0x8F, 0x9B, 0x00,
+ 0xE1, 0x8F, 0x9C, 0x00, 0xE1, 0x8F, 0x9D, 0x00, 0xE1, 0x8F, 0x9E, 0x00,
+ 0xE1, 0x8F, 0x9F, 0x00, 0xE1, 0x8F, 0xA0, 0x00, 0xE1, 0x8F, 0xA1, 0x00,
+ 0xE1, 0x8F, 0xA2, 0x00, 0xE1, 0x8F, 0xA3, 0x00, 0xE1, 0x8F, 0xA4, 0x00,
+ 0xE1, 0x8F, 0xA5, 0x00, 0xE1, 0x8F, 0xA6, 0x00, 0xE1, 0x8F, 0xA7, 0x00,
+ 0xE1, 0x8F, 0xA8, 0x00, 0xE1, 0x8F, 0xA9, 0x00, 0xE1, 0x8F, 0xAA, 0x00,
+ 0xE1, 0x8F, 0xAB, 0x00, 0xE1, 0x8F, 0xAC, 0x00, 0xE1, 0x8F, 0xAD, 0x00,
+ 0xE1, 0x8F, 0xAE, 0x00, 0xE1, 0x8F, 0xAF, 0x00, 0x66, 0x66, 0x66, 0x69,
+ 0x66, 0x6C, 0x66, 0x66, 0x69, 0x00, 0x66, 0x66, 0x6C, 0x00, 0x73, 0x74,
+ 0x73, 0x74, 0xD5, 0xB4, 0xD5, 0xB6, 0xD5, 0xB4, 0xD5, 0xA5, 0xD5, 0xB4,
+ 0xD5, 0xAB, 0xD5, 0xBE, 0xD5, 0xB6, 0xD5, 0xB4, 0xD5, 0xAD, 0xEF, 0xBD,
+ 0x81, 0x00, 0xEF, 0xBD, 0x82, 0x00, 0xEF, 0xBD, 0x83, 0x00, 0xEF, 0xBD,
+ 0x84, 0x00, 0xEF, 0xBD, 0x85, 0x00, 0xEF, 0xBD, 0x86, 0x00, 0xEF, 0xBD,
+ 0x87, 0x00, 0xEF, 0xBD, 0x88, 0x00, 0xEF, 0xBD, 0x89, 0x00, 0xEF, 0xBD,
+ 0x8A, 0x00, 0xEF, 0xBD, 0x8B, 0x00, 0xEF, 0xBD, 0x8C, 0x00, 0xEF, 0xBD,
+ 0x8D, 0x00, 0xEF, 0xBD, 0x8E, 0x00, 0xEF, 0xBD, 0x8F, 0x00, 0xEF, 0xBD,
+ 0x90, 0x00, 0xEF, 0xBD, 0x91, 0x00, 0xEF, 0xBD, 0x92, 0x00, 0xEF, 0xBD,
+ 0x93, 0x00, 0xEF, 0xBD, 0x94, 0x00, 0xEF, 0xBD, 0x95, 0x00, 0xEF, 0xBD,
+ 0x96, 0x00, 0xEF, 0xBD, 0x97, 0x00, 0xEF, 0xBD, 0x98, 0x00, 0xEF, 0xBD,
+ 0x99, 0x00, 0xEF, 0xBD, 0x9A, 0x00, 0xF0, 0x90, 0x90, 0xA8, 0xF0, 0x90,
+ 0x90, 0xA9, 0xF0, 0x90, 0x90, 0xAA, 0xF0, 0x90, 0x90, 0xAB, 0xF0, 0x90,
+ 0x90, 0xAC, 0xF0, 0x90, 0x90, 0xAD, 0xF0, 0x90, 0x90, 0xAE, 0xF0, 0x90,
+ 0x90, 0xAF, 0xF0, 0x90, 0x90, 0xB0, 0xF0, 0x90, 0x90, 0xB1, 0xF0, 0x90,
+ 0x90, 0xB2, 0xF0, 0x90, 0x90, 0xB3, 0xF0, 0x90, 0x90, 0xB4, 0xF0, 0x90,
+ 0x90, 0xB5, 0xF0, 0x90, 0x90, 0xB6, 0xF0, 0x90, 0x90, 0xB7, 0xF0, 0x90,
+ 0x90, 0xB8, 0xF0, 0x90, 0x90, 0xB9, 0xF0, 0x90, 0x90, 0xBA, 0xF0, 0x90,
+ 0x90, 0xBB, 0xF0, 0x90, 0x90, 0xBC, 0xF0, 0x90, 0x90, 0xBD, 0xF0, 0x90,
+ 0x90, 0xBE, 0xF0, 0x90, 0x90, 0xBF, 0xF0, 0x90, 0x91, 0x80, 0xF0, 0x90,
+ 0x91, 0x81, 0xF0, 0x90, 0x91, 0x82, 0xF0, 0x90, 0x91, 0x83, 0xF0, 0x90,
+ 0x91, 0x84, 0xF0, 0x90, 0x91, 0x85, 0xF0, 0x90, 0x91, 0x86, 0xF0, 0x90,
+ 0x91, 0x87, 0xF0, 0x90, 0x91, 0x88, 0xF0, 0x90, 0x91, 0x89, 0xF0, 0x90,
+ 0x91, 0x8A, 0xF0, 0x90, 0x91, 0x8B, 0xF0, 0x90, 0x91, 0x8C, 0xF0, 0x90,
+ 0x91, 0x8D, 0xF0, 0x90, 0x91, 0x8E, 0xF0, 0x90, 0x91, 0x8F, 0xF0, 0x90,
+ 0x93, 0x98, 0xF0, 0x90, 0x93, 0x99, 0xF0, 0x90, 0x93, 0x9A, 0xF0, 0x90,
+ 0x93, 0x9B, 0xF0, 0x90, 0x93, 0x9C, 0xF0, 0x90, 0x93, 0x9D, 0xF0, 0x90,
+ 0x93, 0x9E, 0xF0, 0x90, 0x93, 0x9F, 0xF0, 0x90, 0x93, 0xA0, 0xF0, 0x90,
+ 0x93, 0xA1, 0xF0, 0x90, 0x93, 0xA2, 0xF0, 0x90, 0x93, 0xA3, 0xF0, 0x90,
+ 0x93, 0xA4, 0xF0, 0x90, 0x93, 0xA5, 0xF0, 0x90, 0x93, 0xA6, 0xF0, 0x90,
+ 0x93, 0xA7, 0xF0, 0x90, 0x93, 0xA8, 0xF0, 0x90, 0x93, 0xA9, 0xF0, 0x90,
+ 0x93, 0xAA, 0xF0, 0x90, 0x93, 0xAB, 0xF0, 0x90, 0x93, 0xAC, 0xF0, 0x90,
+ 0x93, 0xAD, 0xF0, 0x90, 0x93, 0xAE, 0xF0, 0x90, 0x93, 0xAF, 0xF0, 0x90,
+ 0x93, 0xB0, 0xF0, 0x90, 0x93, 0xB1, 0xF0, 0x90, 0x93, 0xB2, 0xF0, 0x90,
+ 0x93, 0xB3, 0xF0, 0x90, 0x93, 0xB4, 0xF0, 0x90, 0x93, 0xB5, 0xF0, 0x90,
+ 0x93, 0xB6, 0xF0, 0x90, 0x93, 0xB7, 0xF0, 0x90, 0x93, 0xB8, 0xF0, 0x90,
+ 0x93, 0xB9, 0xF0, 0x90, 0x93, 0xBA, 0xF0, 0x90, 0x93, 0xBB, 0xF0, 0x90,
+ 0x96, 0x97, 0xF0, 0x90, 0x96, 0x98, 0xF0, 0x90, 0x96, 0x99, 0xF0, 0x90,
+ 0x96, 0x9A, 0xF0, 0x90, 0x96, 0x9B, 0xF0, 0x90, 0x96, 0x9C, 0xF0, 0x90,
+ 0x96, 0x9D, 0xF0, 0x90, 0x96, 0x9E, 0xF0, 0x90, 0x96, 0x9F, 0xF0, 0x90,
+ 0x96, 0xA0, 0xF0, 0x90, 0x96, 0xA1, 0xF0, 0x90, 0x96, 0xA3, 0xF0, 0x90,
+ 0x96, 0xA4, 0xF0, 0x90, 0x96, 0xA5, 0xF0, 0x90, 0x96, 0xA6, 0xF0, 0x90,
+ 0x96, 0xA7, 0xF0, 0x90, 0x96, 0xA8, 0xF0, 0x90, 0x96, 0xA9, 0xF0, 0x90,
+ 0x96, 0xAA, 0xF0, 0x90, 0x96, 0xAB, 0xF0, 0x90, 0x96, 0xAC, 0xF0, 0x90,
+ 0x96, 0xAD, 0xF0, 0x90, 0x96, 0xAE, 0xF0, 0x90, 0x96, 0xAF, 0xF0, 0x90,
+ 0x96, 0xB0, 0xF0, 0x90, 0x96, 0xB1, 0xF0, 0x90, 0x96, 0xB3, 0xF0, 0x90,
+ 0x96, 0xB4, 0xF0, 0x90, 0x96, 0xB5, 0xF0, 0x90, 0x96, 0xB6, 0xF0, 0x90,
+ 0x96, 0xB7, 0xF0, 0x90, 0x96, 0xB8, 0xF0, 0x90, 0x96, 0xB9, 0xF0, 0x90,
+ 0x96, 0xBB, 0xF0, 0x90, 0x96, 0xBC, 0xF0, 0x90, 0xB3, 0x80, 0xF0, 0x90,
+ 0xB3, 0x81, 0xF0, 0x90, 0xB3, 0x82, 0xF0, 0x90, 0xB3, 0x83, 0xF0, 0x90,
+ 0xB3, 0x84, 0xF0, 0x90, 0xB3, 0x85, 0xF0, 0x90, 0xB3, 0x86, 0xF0, 0x90,
+ 0xB3, 0x87, 0xF0, 0x90, 0xB3, 0x88, 0xF0, 0x90, 0xB3, 0x89, 0xF0, 0x90,
+ 0xB3, 0x8A, 0xF0, 0x90, 0xB3, 0x8B, 0xF0, 0x90, 0xB3, 0x8C, 0xF0, 0x90,
+ 0xB3, 0x8D, 0xF0, 0x90, 0xB3, 0x8E, 0xF0, 0x90, 0xB3, 0x8F, 0xF0, 0x90,
+ 0xB3, 0x90, 0xF0, 0x90, 0xB3, 0x91, 0xF0, 0x90, 0xB3, 0x92, 0xF0, 0x90,
+ 0xB3, 0x93, 0xF0, 0x90, 0xB3, 0x94, 0xF0, 0x90, 0xB3, 0x95, 0xF0, 0x90,
+ 0xB3, 0x96, 0xF0, 0x90, 0xB3, 0x97, 0xF0, 0x90, 0xB3, 0x98, 0xF0, 0x90,
+ 0xB3, 0x99, 0xF0, 0x90, 0xB3, 0x9A, 0xF0, 0x90, 0xB3, 0x9B, 0xF0, 0x90,
+ 0xB3, 0x9C, 0xF0, 0x90, 0xB3, 0x9D, 0xF0, 0x90, 0xB3, 0x9E, 0xF0, 0x90,
+ 0xB3, 0x9F, 0xF0, 0x90, 0xB3, 0xA0, 0xF0, 0x90, 0xB3, 0xA1, 0xF0, 0x90,
+ 0xB3, 0xA2, 0xF0, 0x90, 0xB3, 0xA3, 0xF0, 0x90, 0xB3, 0xA4, 0xF0, 0x90,
+ 0xB3, 0xA5, 0xF0, 0x90, 0xB3, 0xA6, 0xF0, 0x90, 0xB3, 0xA7, 0xF0, 0x90,
+ 0xB3, 0xA8, 0xF0, 0x90, 0xB3, 0xA9, 0xF0, 0x90, 0xB3, 0xAA, 0xF0, 0x90,
+ 0xB3, 0xAB, 0xF0, 0x90, 0xB3, 0xAC, 0xF0, 0x90, 0xB3, 0xAD, 0xF0, 0x90,
+ 0xB3, 0xAE, 0xF0, 0x90, 0xB3, 0xAF, 0xF0, 0x90, 0xB3, 0xB0, 0xF0, 0x90,
+ 0xB3, 0xB1, 0xF0, 0x90, 0xB3, 0xB2, 0xF0, 0x90, 0xB5, 0xB0, 0xF0, 0x90,
+ 0xB5, 0xB1, 0xF0, 0x90, 0xB5, 0xB2, 0xF0, 0x90, 0xB5, 0xB3, 0xF0, 0x90,
+ 0xB5, 0xB4, 0xF0, 0x90, 0xB5, 0xB5, 0xF0, 0x90, 0xB5, 0xB6, 0xF0, 0x90,
+ 0xB5, 0xB7, 0xF0, 0x90, 0xB5, 0xB8, 0xF0, 0x90, 0xB5, 0xB9, 0xF0, 0x90,
+ 0xB5, 0xBA, 0xF0, 0x90, 0xB5, 0xBB, 0xF0, 0x90, 0xB5, 0xBC, 0xF0, 0x90,
+ 0xB5, 0xBD, 0xF0, 0x90, 0xB5, 0xBE, 0xF0, 0x90, 0xB5, 0xBF, 0xF0, 0x90,
+ 0xB6, 0x80, 0xF0, 0x90, 0xB6, 0x81, 0xF0, 0x90, 0xB6, 0x82, 0xF0, 0x90,
+ 0xB6, 0x83, 0xF0, 0x90, 0xB6, 0x84, 0xF0, 0x90, 0xB6, 0x85, 0xF0, 0x91,
+ 0xA3, 0x80, 0xF0, 0x91, 0xA3, 0x81, 0xF0, 0x91, 0xA3, 0x82, 0xF0, 0x91,
+ 0xA3, 0x83, 0xF0, 0x91, 0xA3, 0x84, 0xF0, 0x91, 0xA3, 0x85, 0xF0, 0x91,
+ 0xA3, 0x86, 0xF0, 0x91, 0xA3, 0x87, 0xF0, 0x91, 0xA3, 0x88, 0xF0, 0x91,
+ 0xA3, 0x89, 0xF0, 0x91, 0xA3, 0x8A, 0xF0, 0x91, 0xA3, 0x8B, 0xF0, 0x91,
+ 0xA3, 0x8C, 0xF0, 0x91, 0xA3, 0x8D, 0xF0, 0x91, 0xA3, 0x8E, 0xF0, 0x91,
+ 0xA3, 0x8F, 0xF0, 0x91, 0xA3, 0x90, 0xF0, 0x91, 0xA3, 0x91, 0xF0, 0x91,
+ 0xA3, 0x92, 0xF0, 0x91, 0xA3, 0x93, 0xF0, 0x91, 0xA3, 0x94, 0xF0, 0x91,
+ 0xA3, 0x95, 0xF0, 0x91, 0xA3, 0x96, 0xF0, 0x91, 0xA3, 0x97, 0xF0, 0x91,
+ 0xA3, 0x98, 0xF0, 0x91, 0xA3, 0x99, 0xF0, 0x91, 0xA3, 0x9A, 0xF0, 0x91,
+ 0xA3, 0x9B, 0xF0, 0x91, 0xA3, 0x9C, 0xF0, 0x91, 0xA3, 0x9D, 0xF0, 0x91,
+ 0xA3, 0x9E, 0xF0, 0x91, 0xA3, 0x9F, 0xF0, 0x96, 0xB9, 0xA0, 0xF0, 0x96,
+ 0xB9, 0xA1, 0xF0, 0x96, 0xB9, 0xA2, 0xF0, 0x96, 0xB9, 0xA3, 0xF0, 0x96,
+ 0xB9, 0xA4, 0xF0, 0x96, 0xB9, 0xA5, 0xF0, 0x96, 0xB9, 0xA6, 0xF0, 0x96,
+ 0xB9, 0xA7, 0xF0, 0x96, 0xB9, 0xA8, 0xF0, 0x96, 0xB9, 0xA9, 0xF0, 0x96,
+ 0xB9, 0xAA, 0xF0, 0x96, 0xB9, 0xAB, 0xF0, 0x96, 0xB9, 0xAC, 0xF0, 0x96,
+ 0xB9, 0xAD, 0xF0, 0x96, 0xB9, 0xAE, 0xF0, 0x96, 0xB9, 0xAF, 0xF0, 0x96,
+ 0xB9, 0xB0, 0xF0, 0x96, 0xB9, 0xB1, 0xF0, 0x96, 0xB9, 0xB2, 0xF0, 0x96,
+ 0xB9, 0xB3, 0xF0, 0x96, 0xB9, 0xB4, 0xF0, 0x96, 0xB9, 0xB5, 0xF0, 0x96,
+ 0xB9, 0xB6, 0xF0, 0x96, 0xB9, 0xB7, 0xF0, 0x96, 0xB9, 0xB8, 0xF0, 0x96,
+ 0xB9, 0xB9, 0xF0, 0x96, 0xB9, 0xBA, 0xF0, 0x96, 0xB9, 0xBB, 0xF0, 0x96,
+ 0xB9, 0xBC, 0xF0, 0x96, 0xB9, 0xBD, 0xF0, 0x96, 0xB9, 0xBE, 0xF0, 0x96,
+ 0xB9, 0xBF, 0xF0, 0x96, 0xBA, 0xBB, 0xF0, 0x96, 0xBA, 0xBC, 0xF0, 0x96,
+ 0xBA, 0xBD, 0xF0, 0x96, 0xBA, 0xBE, 0xF0, 0x96, 0xBA, 0xBF, 0xF0, 0x96,
+ 0xBB, 0x80, 0xF0, 0x96, 0xBB, 0x81, 0xF0, 0x96, 0xBB, 0x82, 0xF0, 0x96,
+ 0xBB, 0x83, 0xF0, 0x96, 0xBB, 0x84, 0xF0, 0x96, 0xBB, 0x85, 0xF0, 0x96,
+ 0xBB, 0x86, 0xF0, 0x96, 0xBB, 0x87, 0xF0, 0x96, 0xBB, 0x88, 0xF0, 0x96,
+ 0xBB, 0x89, 0xF0, 0x96, 0xBB, 0x8A, 0xF0, 0x96, 0xBB, 0x8B, 0xF0, 0x96,
+ 0xBB, 0x8C, 0xF0, 0x96, 0xBB, 0x8D, 0xF0, 0x96, 0xBB, 0x8E, 0xF0, 0x96,
+ 0xBB, 0x8F, 0xF0, 0x96, 0xBB, 0x90, 0xF0, 0x96, 0xBB, 0x91, 0xF0, 0x96,
+ 0xBB, 0x92, 0xF0, 0x96, 0xBB, 0x93, 0xF0, 0x9E, 0xA4, 0xA2, 0xF0, 0x9E,
+ 0xA4, 0xA3, 0xF0, 0x9E, 0xA4, 0xA4, 0xF0, 0x9E, 0xA4, 0xA5, 0xF0, 0x9E,
+ 0xA4, 0xA6, 0xF0, 0x9E, 0xA4, 0xA7, 0xF0, 0x9E, 0xA4, 0xA8, 0xF0, 0x9E,
+ 0xA4, 0xA9, 0xF0, 0x9E, 0xA4, 0xAA, 0xF0, 0x9E, 0xA4, 0xAB, 0xF0, 0x9E,
+ 0xA4, 0xAC, 0xF0, 0x9E, 0xA4, 0xAD, 0xF0, 0x9E, 0xA4, 0xAE, 0xF0, 0x9E,
+ 0xA4, 0xAF, 0xF0, 0x9E, 0xA4, 0xB0, 0xF0, 0x9E, 0xA4, 0xB1, 0xF0, 0x9E,
+ 0xA4, 0xB2, 0xF0, 0x9E, 0xA4, 0xB3, 0xF0, 0x9E, 0xA4, 0xB4, 0xF0, 0x9E,
+ 0xA4, 0xB5, 0xF0, 0x9E, 0xA4, 0xB6, 0xF0, 0x9E, 0xA4, 0xB7, 0xF0, 0x9E,
+ 0xA4, 0xB8, 0xF0, 0x9E, 0xA4, 0xB9, 0xF0, 0x9E, 0xA4, 0xBA, 0xF0, 0x9E,
+ 0xA4, 0xBB, 0xF0, 0x9E, 0xA4, 0xBC, 0xF0, 0x9E, 0xA4, 0xBD, 0xF0, 0x9E,
+ 0xA4, 0xBE, 0xF0, 0x9E, 0xA4, 0xBF, 0xF0, 0x9E, 0xA5, 0x80, 0xF0, 0x9E,
+ 0xA5, 0x81, 0xF0, 0x9E, 0xA5, 0x82, 0xF0, 0x9E, 0xA5, 0x83
+};
diff --git a/cmark/src/chunk.h b/cmark/src/chunk.h
new file mode 100644
index 0000000000..54c28f8b82
--- /dev/null
+++ b/cmark/src/chunk.h
@@ -0,0 +1,69 @@
+#ifndef CMARK_CHUNK_H
+#define CMARK_CHUNK_H
+
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "cmark.h"
+#include "buffer.h"
+#include "cmark_ctype.h"
+
+#define CMARK_CHUNK_EMPTY \
+ { NULL, 0 }
+
+typedef struct {
+ const unsigned char *data;
+ bufsize_t len;
+} cmark_chunk;
+
+// NOLINTNEXTLINE(clang-diagnostic-unused-function)
+static inline void cmark_chunk_free(cmark_chunk *c) {
+ c->data = NULL;
+ c->len = 0;
+}
+
+static inline void cmark_chunk_ltrim(cmark_chunk *c) {
+ while (c->len && cmark_isspace(c->data[0])) {
+ c->data++;
+ c->len--;
+ }
+}
+
+static inline void cmark_chunk_rtrim(cmark_chunk *c) {
+ while (c->len > 0) {
+ if (!cmark_isspace(c->data[c->len - 1]))
+ break;
+
+ c->len--;
+ }
+}
+
+// NOLINTNEXTLINE(clang-diagnostic-unused-function)
+static inline void cmark_chunk_trim(cmark_chunk *c) {
+ cmark_chunk_ltrim(c);
+ cmark_chunk_rtrim(c);
+}
+
+// NOLINTNEXTLINE(clang-diagnostic-unused-function)
+static inline bufsize_t cmark_chunk_strchr(cmark_chunk *ch, int c,
+ bufsize_t offset) {
+ const unsigned char *p =
+ (unsigned char *)memchr(ch->data + offset, c, ch->len - offset);
+ return p ? (bufsize_t)(p - ch->data) : ch->len;
+}
+
+// NOLINTNEXTLINE(clang-diagnostic-unused-function)
+static inline cmark_chunk cmark_chunk_literal(const char *data) {
+ bufsize_t len = data ? (bufsize_t)strlen(data) : 0;
+ cmark_chunk c = {(unsigned char *)data, len};
+ return c;
+}
+
+// NOLINTNEXTLINE(clang-diagnostic-unused-function)
+static inline cmark_chunk cmark_chunk_dup(const cmark_chunk *ch, bufsize_t pos,
+ bufsize_t len) {
+ cmark_chunk c = {ch->data + pos, len};
+ return c;
+}
+
+#endif
diff --git a/cmark/src/cmark.c b/cmark/src/cmark.c
new file mode 100644
index 0000000000..60aedbc6f1
--- /dev/null
+++ b/cmark/src/cmark.c
@@ -0,0 +1,48 @@
+#include <stdlib.h>
+#include <assert.h>
+#include <stdio.h>
+#include "node.h"
+#include "houdini.h"
+#include "cmark.h"
+#include "buffer.h"
+
+int cmark_version(void) { return CMARK_VERSION; }
+
+const char *cmark_version_string(void) { return CMARK_VERSION_STRING; }
+
+static void *xcalloc(size_t nmem, size_t size) {
+ void *ptr = calloc(nmem, size);
+ if (!ptr) {
+ fprintf(stderr, "[cmark] calloc returned null pointer, aborting\n");
+ abort();
+ }
+ return ptr;
+}
+
+static void *xrealloc(void *ptr, size_t size) {
+ void *new_ptr = realloc(ptr, size);
+ if (!new_ptr) {
+ fprintf(stderr, "[cmark] realloc returned null pointer, aborting\n");
+ abort();
+ }
+ return new_ptr;
+}
+
+cmark_mem DEFAULT_MEM_ALLOCATOR = {xcalloc, xrealloc, free};
+
+cmark_mem *cmark_get_default_mem_allocator(void) {
+ return &DEFAULT_MEM_ALLOCATOR;
+}
+
+
+char *cmark_markdown_to_html(const char *text, size_t len, int options) {
+ cmark_node *doc;
+ char *result;
+
+ doc = cmark_parse_document(text, len, options);
+
+ result = cmark_render_html(doc, options);
+ cmark_node_free(doc);
+
+ return result;
+}
diff --git a/cmark/src/cmark.h b/cmark/src/cmark.h
new file mode 100644
index 0000000000..6626b06273
--- /dev/null
+++ b/cmark/src/cmark.h
@@ -0,0 +1,704 @@
+#ifndef CMARK_H
+#define CMARK_H
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <cmark_export.h>
+#include <cmark_version.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** # NAME
+ *
+ * **cmark** - CommonMark parsing, manipulating, and rendering
+ */
+
+/** # DESCRIPTION
+ *
+ * ## Simple Interface
+ */
+
+/** Convert 'text' (assumed to be a UTF-8 encoded string with length
+ * 'len') from CommonMark Markdown to HTML, returning a null-terminated,
+ * UTF-8-encoded string. It is the caller's responsibility
+ * to free the returned buffer.
+ */
+CMARK_EXPORT
+char *cmark_markdown_to_html(const char *text, size_t len, int options);
+
+/** ## Node Structure
+ */
+
+typedef enum {
+ /* Error status */
+ CMARK_NODE_NONE,
+
+ /* Block */
+ CMARK_NODE_DOCUMENT,
+ CMARK_NODE_BLOCK_QUOTE,
+ CMARK_NODE_LIST,
+ CMARK_NODE_ITEM,
+ CMARK_NODE_CODE_BLOCK,
+ CMARK_NODE_HTML_BLOCK,
+ CMARK_NODE_CUSTOM_BLOCK,
+ CMARK_NODE_PARAGRAPH,
+ CMARK_NODE_HEADING,
+ CMARK_NODE_THEMATIC_BREAK,
+
+ CMARK_NODE_FIRST_BLOCK = CMARK_NODE_DOCUMENT,
+ CMARK_NODE_LAST_BLOCK = CMARK_NODE_THEMATIC_BREAK,
+
+ /* Inline */
+ CMARK_NODE_TEXT,
+ CMARK_NODE_SOFTBREAK,
+ CMARK_NODE_LINEBREAK,
+ CMARK_NODE_CODE,
+ CMARK_NODE_HTML_INLINE,
+ CMARK_NODE_CUSTOM_INLINE,
+ CMARK_NODE_EMPH,
+ CMARK_NODE_STRONG,
+ CMARK_NODE_LINK,
+ CMARK_NODE_IMAGE,
+
+ CMARK_NODE_FIRST_INLINE = CMARK_NODE_TEXT,
+ CMARK_NODE_LAST_INLINE = CMARK_NODE_IMAGE
+} cmark_node_type;
+
+/* For backwards compatibility: */
+#define CMARK_NODE_HEADER CMARK_NODE_HEADING
+#define CMARK_NODE_HRULE CMARK_NODE_THEMATIC_BREAK
+#define CMARK_NODE_HTML CMARK_NODE_HTML_BLOCK
+#define CMARK_NODE_INLINE_HTML CMARK_NODE_HTML_INLINE
+
+typedef enum {
+ CMARK_NO_LIST,
+ CMARK_BULLET_LIST,
+ CMARK_ORDERED_LIST
+} cmark_list_type;
+
+typedef enum {
+ CMARK_NO_DELIM,
+ CMARK_PERIOD_DELIM,
+ CMARK_PAREN_DELIM
+} cmark_delim_type;
+
+typedef struct cmark_node cmark_node;
+typedef struct cmark_parser cmark_parser;
+typedef struct cmark_iter cmark_iter;
+
+/**
+ * ## Custom memory allocator support
+ */
+
+/** Defines the memory allocation functions to be used by CMark
+ * when parsing and allocating a document tree
+ */
+typedef struct cmark_mem {
+ void *(*calloc)(size_t, size_t);
+ void *(*realloc)(void *, size_t);
+ void (*free)(void *);
+} cmark_mem;
+
+/** Returns a pointer to the default memory allocator.
+ */
+CMARK_EXPORT cmark_mem *cmark_get_default_mem_allocator(void);
+
+/**
+ * ## Classifying nodes
+ */
+
+/** Returns true if the node is a block node.
+ */
+CMARK_EXPORT bool cmark_node_is_block(cmark_node *node);
+
+/** Returns true if the node is an inline node.
+ */
+CMARK_EXPORT bool cmark_node_is_inline(cmark_node *node);
+
+/** Returns true if the node is a leaf node (a node that cannot
+ contain children).
+ */
+CMARK_EXPORT bool cmark_node_is_leaf(cmark_node *node);
+
+/**
+ * ## Creating and Destroying Nodes
+ */
+
+/** Creates a new node of type 'type'. Note that the node may have
+ * other required properties, which it is the caller's responsibility
+ * to assign.
+ */
+CMARK_EXPORT cmark_node *cmark_node_new(cmark_node_type type);
+
+/** Same as `cmark_node_new`, but explicitly listing the memory
+ * allocator used to allocate the node. Note: be sure to use the same
+ * allocator for every node in a tree, or bad things can happen.
+ */
+CMARK_EXPORT cmark_node *cmark_node_new_with_mem(cmark_node_type type,
+ cmark_mem *mem);
+
+/** Frees the memory allocated for a node and any children.
+ */
+CMARK_EXPORT void cmark_node_free(cmark_node *node);
+
+/**
+ * ## Tree Traversal
+ */
+
+/** Returns the next node in the sequence after 'node', or NULL if
+ * there is none.
+ */
+CMARK_EXPORT cmark_node *cmark_node_next(cmark_node *node);
+
+/** Returns the previous node in the sequence after 'node', or NULL if
+ * there is none.
+ */
+CMARK_EXPORT cmark_node *cmark_node_previous(cmark_node *node);
+
+/** Returns the parent of 'node', or NULL if there is none.
+ */
+CMARK_EXPORT cmark_node *cmark_node_parent(cmark_node *node);
+
+/** Returns the first child of 'node', or NULL if 'node' has no children.
+ */
+CMARK_EXPORT cmark_node *cmark_node_first_child(cmark_node *node);
+
+/** Returns the last child of 'node', or NULL if 'node' has no children.
+ */
+CMARK_EXPORT cmark_node *cmark_node_last_child(cmark_node *node);
+
+/**
+ * ## Iterator
+ *
+ * An iterator will walk through a tree of nodes, starting from a root
+ * node, returning one node at a time, together with information about
+ * whether the node is being entered or exited. The iterator will
+ * first descend to a child node, if there is one. When there is no
+ * child, the iterator will go to the next sibling. When there is no
+ * next sibling, the iterator will return to the parent (but with
+ * a 'cmark_event_type' of `CMARK_EVENT_EXIT`). The iterator will
+ * return `CMARK_EVENT_DONE` when it reaches the root node again.
+ * One natural application is an HTML renderer, where an `ENTER` event
+ * outputs an open tag and an `EXIT` event outputs a close tag.
+ * An iterator might also be used to transform an AST in some systematic
+ * way, for example, turning all level-3 headings into regular paragraphs.
+ *
+ * void
+ * usage_example(cmark_node *root) {
+ * cmark_event_type ev_type;
+ * cmark_iter *iter = cmark_iter_new(root);
+ *
+ * while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
+ * cmark_node *cur = cmark_iter_get_node(iter);
+ * // Do something with `cur` and `ev_type`
+ * }
+ *
+ * cmark_iter_free(iter);
+ * }
+ *
+ * Iterators will never return `EXIT` events for leaf nodes, which are nodes
+ * of type:
+ *
+ * * CMARK_NODE_HTML_BLOCK
+ * * CMARK_NODE_THEMATIC_BREAK
+ * * CMARK_NODE_CODE_BLOCK
+ * * CMARK_NODE_TEXT
+ * * CMARK_NODE_SOFTBREAK
+ * * CMARK_NODE_LINEBREAK
+ * * CMARK_NODE_CODE
+ * * CMARK_NODE_HTML_INLINE
+ *
+ * Nodes must only be modified after an `EXIT` event, or an `ENTER` event for
+ * leaf nodes.
+ */
+
+typedef enum {
+ CMARK_EVENT_NONE,
+ CMARK_EVENT_DONE,
+ CMARK_EVENT_ENTER,
+ CMARK_EVENT_EXIT
+} cmark_event_type;
+
+/** Creates a new iterator starting at 'root'. The current node and event
+ * type are undefined until 'cmark_iter_next' is called for the first time.
+ * The memory allocated for the iterator should be released using
+ * 'cmark_iter_free' when it is no longer needed.
+ */
+CMARK_EXPORT
+cmark_iter *cmark_iter_new(cmark_node *root);
+
+/** Frees the memory allocated for an iterator.
+ */
+CMARK_EXPORT
+void cmark_iter_free(cmark_iter *iter);
+
+/** Advances to the next node and returns the event type (`CMARK_EVENT_ENTER`,
+ * `CMARK_EVENT_EXIT` or `CMARK_EVENT_DONE`).
+ */
+CMARK_EXPORT
+cmark_event_type cmark_iter_next(cmark_iter *iter);
+
+/** Returns the current node.
+ */
+CMARK_EXPORT
+cmark_node *cmark_iter_get_node(cmark_iter *iter);
+
+/** Returns the current event type.
+ */
+CMARK_EXPORT
+cmark_event_type cmark_iter_get_event_type(cmark_iter *iter);
+
+/** Returns the root node.
+ */
+CMARK_EXPORT
+cmark_node *cmark_iter_get_root(cmark_iter *iter);
+
+/** Resets the iterator so that the current node is 'current' and
+ * the event type is 'event_type'. The new current node must be a
+ * descendant of the root node or the root node itself.
+ */
+CMARK_EXPORT
+void cmark_iter_reset(cmark_iter *iter, cmark_node *current,
+ cmark_event_type event_type);
+
+/**
+ * ## Accessors
+ */
+
+/** Returns the user data of 'node'.
+ */
+CMARK_EXPORT void *cmark_node_get_user_data(cmark_node *node);
+
+/** Sets arbitrary user data for 'node'. Returns 1 on success,
+ * 0 on failure.
+ */
+CMARK_EXPORT int cmark_node_set_user_data(cmark_node *node, void *user_data);
+
+/** Returns the type of 'node', or `CMARK_NODE_NONE` on error.
+ */
+CMARK_EXPORT cmark_node_type cmark_node_get_type(cmark_node *node);
+
+/** Like 'cmark_node_get_type', but returns a string representation
+ of the type, or `"<unknown>"`.
+ */
+CMARK_EXPORT
+const char *cmark_node_get_type_string(cmark_node *node);
+
+/** Returns the string contents of 'node', or an empty
+ string if none is set. Returns NULL if called on a
+ node that does not have string content.
+ */
+CMARK_EXPORT const char *cmark_node_get_literal(cmark_node *node);
+
+/** Sets the string contents of 'node'. Returns 1 on success,
+ * 0 on failure.
+ */
+CMARK_EXPORT int cmark_node_set_literal(cmark_node *node, const char *content);
+
+/** Returns the heading level of 'node', or 0 if 'node' is not a heading.
+ */
+CMARK_EXPORT int cmark_node_get_heading_level(cmark_node *node);
+
+/* For backwards compatibility */
+#define cmark_node_get_header_level cmark_node_get_heading_level
+#define cmark_node_set_header_level cmark_node_set_heading_level
+
+/** Sets the heading level of 'node', returning 1 on success and 0 on error.
+ */
+CMARK_EXPORT int cmark_node_set_heading_level(cmark_node *node, int level);
+
+/** Returns the list type of 'node', or `CMARK_NO_LIST` if 'node'
+ * is not a list.
+ */
+CMARK_EXPORT cmark_list_type cmark_node_get_list_type(cmark_node *node);
+
+/** Sets the list type of 'node', returning 1 on success and 0 on error.
+ */
+CMARK_EXPORT int cmark_node_set_list_type(cmark_node *node,
+ cmark_list_type type);
+
+/** Returns the list delimiter type of 'node', or `CMARK_NO_DELIM` if 'node'
+ * is not a list.
+ */
+CMARK_EXPORT cmark_delim_type cmark_node_get_list_delim(cmark_node *node);
+
+/** Sets the list delimiter type of 'node', returning 1 on success and 0
+ * on error.
+ */
+CMARK_EXPORT int cmark_node_set_list_delim(cmark_node *node,
+ cmark_delim_type delim);
+
+/** Returns starting number of 'node', if it is an ordered list, otherwise 0.
+ */
+CMARK_EXPORT int cmark_node_get_list_start(cmark_node *node);
+
+/** Sets starting number of 'node', if it is an ordered list. Returns 1
+ * on success, 0 on failure.
+ */
+CMARK_EXPORT int cmark_node_set_list_start(cmark_node *node, int start);
+
+/** Returns 1 if 'node' is a tight list, 0 otherwise.
+ */
+CMARK_EXPORT int cmark_node_get_list_tight(cmark_node *node);
+
+/** Sets the "tightness" of a list. Returns 1 on success, 0 on failure.
+ */
+CMARK_EXPORT int cmark_node_set_list_tight(cmark_node *node, int tight);
+
+/** Returns the info string from a fenced code block.
+ */
+CMARK_EXPORT const char *cmark_node_get_fence_info(cmark_node *node);
+
+/** Sets the info string in a fenced code block, returning 1 on
+ * success and 0 on failure.
+ */
+CMARK_EXPORT int cmark_node_set_fence_info(cmark_node *node, const char *info);
+
+/** Returns the URL of a link or image 'node', or an empty string
+ if no URL is set. Returns NULL if called on a node that is
+ not a link or image.
+ */
+CMARK_EXPORT const char *cmark_node_get_url(cmark_node *node);
+
+/** Sets the URL of a link or image 'node'. Returns 1 on success,
+ * 0 on failure.
+ */
+CMARK_EXPORT int cmark_node_set_url(cmark_node *node, const char *url);
+
+/** Returns the title of a link or image 'node', or an empty
+ string if no title is set. Returns NULL if called on a node
+ that is not a link or image.
+ */
+CMARK_EXPORT const char *cmark_node_get_title(cmark_node *node);
+
+/** Sets the title of a link or image 'node'. Returns 1 on success,
+ * 0 on failure.
+ */
+CMARK_EXPORT int cmark_node_set_title(cmark_node *node, const char *title);
+
+/** Returns the literal "on enter" text for a custom 'node', or
+ an empty string if no on_enter is set. Returns NULL if called
+ on a non-custom node.
+ */
+CMARK_EXPORT const char *cmark_node_get_on_enter(cmark_node *node);
+
+/** Sets the literal text to render "on enter" for a custom 'node'.
+ Any children of the node will be rendered after this text.
+ Returns 1 on success 0 on failure.
+ */
+CMARK_EXPORT int cmark_node_set_on_enter(cmark_node *node,
+ const char *on_enter);
+
+/** Returns the literal "on exit" text for a custom 'node', or
+ an empty string if no on_exit is set. Returns NULL if
+ called on a non-custom node.
+ */
+CMARK_EXPORT const char *cmark_node_get_on_exit(cmark_node *node);
+
+/** Sets the literal text to render "on exit" for a custom 'node'.
+ Any children of the node will be rendered before this text.
+ Returns 1 on success 0 on failure.
+ */
+CMARK_EXPORT int cmark_node_set_on_exit(cmark_node *node, const char *on_exit);
+
+/** Returns the line on which 'node' begins.
+ */
+CMARK_EXPORT int cmark_node_get_start_line(cmark_node *node);
+
+/** Returns the column at which 'node' begins.
+ */
+CMARK_EXPORT int cmark_node_get_start_column(cmark_node *node);
+
+/** Returns the line on which 'node' ends.
+ */
+CMARK_EXPORT int cmark_node_get_end_line(cmark_node *node);
+
+/** Returns the column at which 'node' ends.
+ */
+CMARK_EXPORT int cmark_node_get_end_column(cmark_node *node);
+
+/**
+ * ## Tree Manipulation
+ */
+
+/** Unlinks a 'node', removing it from the tree, but not freeing its
+ * memory. (Use 'cmark_node_free' for that.)
+ */
+CMARK_EXPORT void cmark_node_unlink(cmark_node *node);
+
+/** Inserts 'sibling' before 'node'. Returns 1 on success, 0 on failure.
+ */
+CMARK_EXPORT int cmark_node_insert_before(cmark_node *node,
+ cmark_node *sibling);
+
+/** Inserts 'sibling' after 'node'. Returns 1 on success, 0 on failure.
+ */
+CMARK_EXPORT int cmark_node_insert_after(cmark_node *node, cmark_node *sibling);
+
+/** Replaces 'oldnode' with 'newnode' and unlinks 'oldnode' (but does
+ * not free its memory).
+ * Returns 1 on success, 0 on failure.
+ */
+CMARK_EXPORT int cmark_node_replace(cmark_node *oldnode, cmark_node *newnode);
+
+/** Adds 'child' to the beginning of the children of 'node'.
+ * Returns 1 on success, 0 on failure.
+ */
+CMARK_EXPORT int cmark_node_prepend_child(cmark_node *node, cmark_node *child);
+
+/** Adds 'child' to the end of the children of 'node'.
+ * Returns 1 on success, 0 on failure.
+ */
+CMARK_EXPORT int cmark_node_append_child(cmark_node *node, cmark_node *child);
+
+/** Consolidates adjacent text nodes.
+ */
+CMARK_EXPORT void cmark_consolidate_text_nodes(cmark_node *root);
+
+/**
+ * ## Parsing
+ *
+ * Simple interface:
+ *
+ * cmark_node *document = cmark_parse_document("Hello *world*", 13,
+ * CMARK_OPT_DEFAULT);
+ *
+ * Streaming interface:
+ *
+ * cmark_parser *parser = cmark_parser_new(CMARK_OPT_DEFAULT);
+ * FILE *fp = fopen("myfile.md", "rb");
+ * while ((bytes = fread(buffer, 1, sizeof(buffer), fp)) > 0) {
+ * cmark_parser_feed(parser, buffer, bytes);
+ * if (bytes < sizeof(buffer)) {
+ * break;
+ * }
+ * }
+ * document = cmark_parser_finish(parser);
+ * cmark_parser_free(parser);
+ */
+
+/** Creates a new parser object.
+ */
+CMARK_EXPORT
+cmark_parser *cmark_parser_new(int options);
+
+/** Creates a new parser object with the given memory allocator
+ *
+ * A generalization of `cmark_parser_new`:
+ * ```c
+ * cmark_parser_new(options)
+ * ```
+ * is the same as:
+ * ```c
+ * cmark_parser_new_with_mem(options, cmark_get_default_mem_allocator())
+ * ```
+ */
+CMARK_EXPORT
+cmark_parser *cmark_parser_new_with_mem(int options, cmark_mem *mem);
+
+/** Creates a new parser object with the given node to use as the root
+ * node of the parsed AST.
+ *
+ * When parsing, children are always appended, not prepended; that means
+ * if `root` already has children, the newly-parsed children will appear
+ * after the given children.
+ *
+ * A generalization of `cmark_parser_new_with_mem`:
+ * ```c
+ * cmark_parser_new_with_mem(options, mem)
+ * ```
+ * is approximately the same as:
+ * ```c
+ * cmark_parser_new_with_mem_into_root(options, mem, cmark_node_new(CMARK_NODE_DOCUMENT))
+ * ```
+ *
+ * This is useful for creating a single document out of multiple parsed
+ * document fragments.
+ */
+CMARK_EXPORT
+cmark_parser *cmark_parser_new_with_mem_into_root(
+ int options, cmark_mem *mem, cmark_node *root);
+
+/** Frees memory allocated for a parser object.
+ */
+CMARK_EXPORT
+void cmark_parser_free(cmark_parser *parser);
+
+/** Feeds a string of length 'len' to 'parser'.
+ */
+CMARK_EXPORT
+void cmark_parser_feed(cmark_parser *parser, const char *buffer, size_t len);
+
+/** Finish parsing and return a pointer to a tree of nodes.
+ */
+CMARK_EXPORT
+cmark_node *cmark_parser_finish(cmark_parser *parser);
+
+/** Parse a CommonMark document in 'buffer' of length 'len'.
+ * Returns a pointer to a tree of nodes. The memory allocated for
+ * the node tree should be released using 'cmark_node_free'
+ * when it is no longer needed.
+ */
+CMARK_EXPORT
+cmark_node *cmark_parse_document(const char *buffer, size_t len, int options);
+
+/** Parse a CommonMark document in file 'f', returning a pointer to
+ * a tree of nodes. The memory allocated for the node tree should be
+ * released using 'cmark_node_free' when it is no longer needed.
+ */
+CMARK_EXPORT
+cmark_node *cmark_parse_file(FILE *f, int options);
+
+/**
+ * ## Rendering
+ */
+
+/** Render a 'node' tree as XML. It is the caller's responsibility
+ * to free the returned buffer.
+ */
+CMARK_EXPORT
+char *cmark_render_xml(cmark_node *root, int options);
+
+/** Render a 'node' tree as an HTML fragment. It is up to the user
+ * to add an appropriate header and footer. It is the caller's
+ * responsibility to free the returned buffer.
+ */
+CMARK_EXPORT
+char *cmark_render_html(cmark_node *root, int options);
+
+/** Render a 'node' tree as a groff man page, without the header.
+ * It is the caller's responsibility to free the returned buffer.
+ */
+CMARK_EXPORT
+char *cmark_render_man(cmark_node *root, int options, int width);
+
+/** Render a 'node' tree as a commonmark document.
+ * It is the caller's responsibility to free the returned buffer.
+ */
+CMARK_EXPORT
+char *cmark_render_commonmark(cmark_node *root, int options, int width);
+
+/** Render a 'node' tree as a LaTeX document.
+ * It is the caller's responsibility to free the returned buffer.
+ */
+CMARK_EXPORT
+char *cmark_render_latex(cmark_node *root, int options, int width);
+
+/**
+ * ## Options
+ */
+
+/** Default options.
+ */
+#define CMARK_OPT_DEFAULT 0
+
+/**
+ * ### Options affecting rendering
+ */
+
+/** Include a `data-sourcepos` attribute on all block elements.
+ */
+#define CMARK_OPT_SOURCEPOS (1 << 1)
+
+/** Render `softbreak` elements as hard line breaks.
+ */
+#define CMARK_OPT_HARDBREAKS (1 << 2)
+
+/** `CMARK_OPT_SAFE` is defined here for API compatibility,
+ but it no longer has any effect. "Safe" mode is now the default:
+ set `CMARK_OPT_UNSAFE` to disable it.
+ */
+#define CMARK_OPT_SAFE (1 << 3)
+
+/** Render raw HTML and unsafe links (`javascript:`, `vbscript:`,
+ * `file:`, and `data:`, except for `image/png`, `image/gif`,
+ * `image/jpeg`, or `image/webp` mime types). By default,
+ * raw HTML is replaced by a placeholder HTML comment. Unsafe
+ * links are replaced by empty strings.
+ */
+#define CMARK_OPT_UNSAFE (1 << 17)
+
+/** Render `softbreak` elements as spaces.
+ */
+#define CMARK_OPT_NOBREAKS (1 << 4)
+
+/**
+ * ### Options affecting parsing
+ */
+
+/** Legacy option (no effect).
+ */
+#define CMARK_OPT_NORMALIZE (1 << 8)
+
+/** Validate UTF-8 in the input before parsing, replacing illegal
+ * sequences with the replacement character U+FFFD.
+ */
+#define CMARK_OPT_VALIDATE_UTF8 (1 << 9)
+
+/** Convert straight quotes to curly, `---` to em dashes, `--` to en dashes.
+ */
+#define CMARK_OPT_SMART (1 << 10)
+
+/**
+ * ## Version information
+ */
+
+/** The library version as integer for runtime checks. Also available as
+ * macro CMARK_VERSION for compile time checks.
+ *
+ * * Bits 16-23 contain the major version.
+ * * Bits 8-15 contain the minor version.
+ * * Bits 0-7 contain the patchlevel.
+ *
+ * In hexadecimal format, the number 0x010203 represents version 1.2.3.
+ */
+CMARK_EXPORT
+int cmark_version(void);
+
+/** The library version string for runtime checks. Also available as
+ * macro CMARK_VERSION_STRING for compile time checks.
+ */
+CMARK_EXPORT
+const char *cmark_version_string(void);
+
+/** # AUTHORS
+ *
+ * John MacFarlane, Vicent Marti, Kārlis Gaņģis, Nick Wellnhofer.
+ */
+
+#ifndef CMARK_NO_SHORT_NAMES
+#define NODE_DOCUMENT CMARK_NODE_DOCUMENT
+#define NODE_BLOCK_QUOTE CMARK_NODE_BLOCK_QUOTE
+#define NODE_LIST CMARK_NODE_LIST
+#define NODE_ITEM CMARK_NODE_ITEM
+#define NODE_CODE_BLOCK CMARK_NODE_CODE_BLOCK
+#define NODE_HTML_BLOCK CMARK_NODE_HTML_BLOCK
+#define NODE_CUSTOM_BLOCK CMARK_NODE_CUSTOM_BLOCK
+#define NODE_PARAGRAPH CMARK_NODE_PARAGRAPH
+#define NODE_HEADING CMARK_NODE_HEADING
+#define NODE_HEADER CMARK_NODE_HEADER
+#define NODE_THEMATIC_BREAK CMARK_NODE_THEMATIC_BREAK
+#define NODE_HRULE CMARK_NODE_HRULE
+#define NODE_TEXT CMARK_NODE_TEXT
+#define NODE_SOFTBREAK CMARK_NODE_SOFTBREAK
+#define NODE_LINEBREAK CMARK_NODE_LINEBREAK
+#define NODE_CODE CMARK_NODE_CODE
+#define NODE_HTML_INLINE CMARK_NODE_HTML_INLINE
+#define NODE_CUSTOM_INLINE CMARK_NODE_CUSTOM_INLINE
+#define NODE_EMPH CMARK_NODE_EMPH
+#define NODE_STRONG CMARK_NODE_STRONG
+#define NODE_LINK CMARK_NODE_LINK
+#define NODE_IMAGE CMARK_NODE_IMAGE
+#define BULLET_LIST CMARK_BULLET_LIST
+#define ORDERED_LIST CMARK_ORDERED_LIST
+#define PERIOD_DELIM CMARK_PERIOD_DELIM
+#define PAREN_DELIM CMARK_PAREN_DELIM
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/cmark/src/cmarkConfig.cmake.in b/cmark/src/cmarkConfig.cmake.in
new file mode 100644
index 0000000000..3d865ff3f5
--- /dev/null
+++ b/cmark/src/cmarkConfig.cmake.in
@@ -0,0 +1,4 @@
+@PACKAGE_INIT@
+
+include("${CMAKE_CURRENT_LIST_DIR}/cmark-targets.cmake")
+check_required_components("cmark")
diff --git a/cmark/src/cmark_ctype.c b/cmark/src/cmark_ctype.c
new file mode 100644
index 0000000000..6280f0a424
--- /dev/null
+++ b/cmark/src/cmark_ctype.c
@@ -0,0 +1,38 @@
+#include <stdint.h>
+
+#include "cmark_ctype.h"
+
+/** 1 = space, 2 = punct, 3 = digit, 4 = alpha, 0 = other
+ */
+static const uint8_t cmark_ctype_class[256] = {
+ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
+ /* 0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
+ /* 1 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 2 */ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ /* 3 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2,
+ /* 4 */ 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ /* 5 */ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2,
+ /* 6 */ 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ /* 7 */ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 0,
+ /* 8 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 9 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* a */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* b */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* c */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* d */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* e */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* f */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+/**
+ * Returns 1 if c is a "whitespace" character as defined by the spec.
+ */
+int cmark_isspace(char c) { return cmark_ctype_class[(uint8_t)c] == 1; }
+
+/**
+ * Returns 1 if c is an ascii punctuation character.
+ */
+int cmark_ispunct(char c) { return cmark_ctype_class[(uint8_t)c] == 2; }
+
+int cmark_isdigit(char c) { return cmark_ctype_class[(uint8_t)c] == 3; }
+
+int cmark_isalpha(char c) { return cmark_ctype_class[(uint8_t)c] == 4; }
diff --git a/cmark/src/cmark_ctype.h b/cmark/src/cmark_ctype.h
new file mode 100644
index 0000000000..3ed63defda
--- /dev/null
+++ b/cmark/src/cmark_ctype.h
@@ -0,0 +1,24 @@
+#ifndef CMARK_CMARK_CTYPE_H
+#define CMARK_CMARK_CTYPE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Locale-independent versions of functions from ctype.h.
+ * We want cmark to behave the same no matter what the system locale.
+ */
+
+int cmark_isspace(char c);
+
+int cmark_ispunct(char c);
+
+int cmark_isdigit(char c);
+
+int cmark_isalpha(char c);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/cmark/src/cmark_version.h.in b/cmark/src/cmark_version.h.in
new file mode 100644
index 0000000000..41de3ac675
--- /dev/null
+++ b/cmark/src/cmark_version.h.in
@@ -0,0 +1,7 @@
+#ifndef CMARK_VERSION_H
+#define CMARK_VERSION_H
+
+#define CMARK_VERSION ((@PROJECT_VERSION_MAJOR@ << 16) | (@PROJECT_VERSION_MINOR@ << 8) | @PROJECT_VERSION_PATCH@)
+#define CMARK_VERSION_STRING "@PROJECT_VERSION_MAJOR@.@PROJECT_VERSION_MINOR@.@PROJECT_VERSION_PATCH@"
+
+#endif
diff --git a/cmark/src/commonmark.c b/cmark/src/commonmark.c
new file mode 100644
index 0000000000..ad805a630e
--- /dev/null
+++ b/cmark/src/commonmark.c
@@ -0,0 +1,473 @@
+#include <assert.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "cmark.h"
+#include "node.h"
+#include "buffer.h"
+#include "utf8.h"
+#include "scanners.h"
+#include "render.h"
+
+#define OUT(s, wrap, escaping) renderer->out(renderer, s, wrap, escaping)
+#define LIT(s) renderer->out(renderer, s, false, LITERAL)
+#define CR() renderer->cr(renderer)
+#define BLANKLINE() renderer->blankline(renderer)
+#define ENCODED_SIZE 20
+#define LISTMARKER_SIZE 20
+
+// Functions to convert cmark_nodes to commonmark strings.
+
+static inline void outc(cmark_renderer *renderer, cmark_escaping escape,
+ int32_t c, unsigned char nextc) {
+ bool needs_escaping = false;
+ bool follows_digit =
+ renderer->buffer->size > 0 &&
+ cmark_isdigit(renderer->buffer->ptr[renderer->buffer->size - 1]);
+ char encoded[ENCODED_SIZE];
+ int options = renderer->options;
+
+ needs_escaping =
+ c < 0x80 && escape != LITERAL &&
+ ((escape == NORMAL &&
+ (c < 0x20 ||
+ c == '*' || c == '_' || c == '[' || c == ']' || c == '#' || c == '<' ||
+ c == '>' || c == '\\' || c == '`' ||
+ (c == '!' && (!nextc || nextc == '[')) ||
+ (c == '&' && cmark_isalpha(nextc)) || (c == '!' && nextc == '[') ||
+ ((CMARK_OPT_SMART & options) &&
+ ((c == '-' && nextc == '-') ||
+ (c == '.' && nextc == '.') ||
+ c == '"' || c == '\'')) ||
+ (renderer->begin_content && (c == '-' || c == '+' || c == '=') &&
+ // begin_content doesn't get set to false til we've passed digits
+ // at the beginning of line, so...
+ !follows_digit) ||
+ (renderer->begin_content && (c == '.' || c == ')') && follows_digit &&
+ (nextc == 0 || cmark_isspace(nextc))))) ||
+ (escape == URL &&
+ (c == '`' || c == '<' || c == '>' || cmark_isspace(c) || c == '\\' ||
+ c == ')' || c == '(')) ||
+ (escape == TITLE &&
+ (c == '`' || c == '<' || c == '>' || c == '"' || c == '\\')));
+
+ if (needs_escaping) {
+ if (escape == URL && cmark_isspace(c)) {
+ // use percent encoding for spaces
+ snprintf(encoded, ENCODED_SIZE, "%%%2X", c);
+ cmark_strbuf_puts(renderer->buffer, encoded);
+ renderer->column += 3;
+ } else if (cmark_ispunct(c)) {
+ cmark_render_ascii(renderer, "\\");
+ cmark_render_code_point(renderer, c);
+ } else { // render as entity
+ snprintf(encoded, ENCODED_SIZE, "&#%d;", c);
+ cmark_strbuf_puts(renderer->buffer, encoded);
+ renderer->column += (int)strlen(encoded);
+ }
+ } else {
+ cmark_render_code_point(renderer, c);
+ }
+}
+
+static int longest_backtick_sequence(const char *code) {
+ int longest = 0;
+ int current = 0;
+ size_t i = 0;
+ size_t code_len = strlen(code);
+ while (i <= code_len) {
+ if (code[i] == '`') {
+ current++;
+ } else {
+ if (current > longest) {
+ longest = current;
+ }
+ current = 0;
+ }
+ i++;
+ }
+ return longest;
+}
+
+static int shortest_unused_backtick_sequence(const char *code) {
+ // note: if the shortest sequence is >= 32, this returns 32
+ // so as not to overflow the bit array.
+ uint32_t used = 1;
+ int current = 0;
+ size_t i = 0;
+ size_t code_len = strlen(code);
+ while (i <= code_len) {
+ if (code[i] == '`') {
+ current++;
+ } else {
+ if (current > 0 && current < 32) {
+ used |= (1U << current);
+ }
+ current = 0;
+ }
+ i++;
+ }
+ // return number of first bit that is 0:
+ i = 0;
+ while (i < 32 && used & 1) {
+ used = used >> 1;
+ i++;
+ }
+ return (int)i;
+}
+
+static bool is_autolink(cmark_node *node) {
+ const unsigned char *title;
+ const unsigned char *url;
+ cmark_node *link_text;
+
+ if (node->type != CMARK_NODE_LINK) {
+ return false;
+ }
+
+ url = node->as.link.url;
+ if (url == NULL || _scan_scheme(url) == 0) {
+ return false;
+ }
+
+ title = node->as.link.title;
+ // if it has a title, we can't treat it as an autolink:
+ if (title && title[0]) {
+ return false;
+ }
+
+ link_text = node->first_child;
+ if (link_text == NULL) {
+ return false;
+ }
+ cmark_consolidate_text_nodes(link_text);
+ if (strncmp((const char *)url, "mailto:", 7) == 0) {
+ url += 7;
+ }
+ return link_text->data != NULL &&
+ strcmp((const char *)url, (char *)link_text->data) == 0;
+}
+
+static int S_render_node(cmark_renderer *renderer, cmark_node *node,
+ cmark_event_type ev_type, int options) {
+ cmark_node *tmp;
+ int list_number;
+ cmark_delim_type list_delim;
+ size_t numticks;
+ bool extra_spaces;
+ size_t i;
+ bool entering = (ev_type == CMARK_EVENT_ENTER);
+ const char *info, *code, *title;
+ char fencechar[2] = {'\0', '\0'};
+ size_t code_len;
+ char listmarker[LISTMARKER_SIZE];
+ const char *emph_delim;
+ bool first_in_list_item;
+ bufsize_t marker_width;
+ bool has_nonspace;
+ bool allow_wrap = renderer->width > 0 && !(CMARK_OPT_NOBREAKS & options) &&
+ !(CMARK_OPT_HARDBREAKS & options);
+
+ // Don't adjust tight list status til we've started the list.
+ // Otherwise we lose the blank line between a paragraph and
+ // a following list.
+ if (entering) {
+ if (node->parent && node->parent->type == CMARK_NODE_ITEM) {
+ renderer->in_tight_list_item = node->parent->parent->as.list.tight;
+ }
+ } else {
+ if (node->type == CMARK_NODE_LIST) {
+ renderer->in_tight_list_item =
+ node->parent &&
+ node->parent->type == CMARK_NODE_ITEM &&
+ node->parent->parent->as.list.tight;
+ }
+ }
+
+ switch (node->type) {
+ case CMARK_NODE_DOCUMENT:
+ break;
+
+ case CMARK_NODE_BLOCK_QUOTE:
+ if (entering) {
+ LIT("> ");
+ renderer->begin_content = true;
+ cmark_strbuf_puts(renderer->prefix, "> ");
+ } else {
+ cmark_strbuf_truncate(renderer->prefix, renderer->prefix->size - 2);
+ BLANKLINE();
+ }
+ break;
+
+ case CMARK_NODE_LIST:
+ if (!entering && node->next && (node->next->type == CMARK_NODE_LIST)) {
+ // this ensures that a following indented code block or list will be
+ // inteprereted correctly.
+ CR();
+ LIT("<!-- end list -->");
+ BLANKLINE();
+ }
+ break;
+
+ case CMARK_NODE_ITEM:
+ if (cmark_node_get_list_type(node->parent) == CMARK_BULLET_LIST) {
+ marker_width = 4;
+ } else {
+ list_number = cmark_node_get_list_start(node->parent);
+ list_delim = cmark_node_get_list_delim(node->parent);
+ tmp = node;
+ while (tmp->prev) {
+ tmp = tmp->prev;
+ list_number += 1;
+ }
+ // we ensure a width of at least 4 so
+ // we get nice transition from single digits
+ // to double
+ snprintf(listmarker, LISTMARKER_SIZE, "%d%s%s", list_number,
+ list_delim == CMARK_PAREN_DELIM ? ")" : ".",
+ list_number < 10 ? " " : " ");
+ marker_width = (bufsize_t)strlen(listmarker);
+ }
+ if (entering) {
+ if (cmark_node_get_list_type(node->parent) == CMARK_BULLET_LIST) {
+ LIT(" - ");
+ renderer->begin_content = true;
+ } else {
+ LIT(listmarker);
+ renderer->begin_content = true;
+ }
+ if (node->first_child == NULL) {
+ BLANKLINE();
+ } else {
+ for (i = marker_width; i--;) {
+ cmark_strbuf_putc(renderer->prefix, ' ');
+ }
+ }
+ } else {
+ cmark_strbuf_truncate(renderer->prefix,
+ renderer->prefix->size - marker_width);
+ CR();
+ }
+ break;
+
+ case CMARK_NODE_HEADING:
+ if (entering) {
+ for (i = cmark_node_get_heading_level(node); i > 0; i--) {
+ LIT("#");
+ }
+ LIT(" ");
+ renderer->begin_content = true;
+ renderer->no_linebreaks = true;
+ } else {
+ renderer->no_linebreaks = false;
+ BLANKLINE();
+ }
+ break;
+
+ case CMARK_NODE_CODE_BLOCK:
+
+ first_in_list_item = node->prev == NULL && node->parent &&
+ node->parent->type == CMARK_NODE_ITEM;
+
+ if (!first_in_list_item) {
+ BLANKLINE();
+ }
+ info = cmark_node_get_fence_info(node);
+ fencechar[0] = strchr(info, '`') == NULL ? '`' : '~';
+ code = cmark_node_get_literal(node);
+
+ numticks = longest_backtick_sequence(code) + 1;
+ if (numticks < 3) {
+ numticks = 3;
+ }
+ for (i = 0; i < numticks; i++) {
+ LIT(fencechar);
+ }
+ LIT(" ");
+ OUT(info, false, LITERAL);
+ CR();
+ OUT(cmark_node_get_literal(node), false, LITERAL);
+ CR();
+ for (i = 0; i < numticks; i++) {
+ LIT(fencechar);
+ }
+
+ BLANKLINE();
+ break;
+
+ case CMARK_NODE_HTML_BLOCK:
+ BLANKLINE();
+ OUT(cmark_node_get_literal(node), false, LITERAL);
+ BLANKLINE();
+ break;
+
+ case CMARK_NODE_CUSTOM_BLOCK:
+ BLANKLINE();
+ OUT(entering ? cmark_node_get_on_enter(node) : cmark_node_get_on_exit(node),
+ false, LITERAL);
+ BLANKLINE();
+ break;
+
+ case CMARK_NODE_THEMATIC_BREAK:
+ BLANKLINE();
+ LIT("-----");
+ BLANKLINE();
+ break;
+
+ case CMARK_NODE_PARAGRAPH:
+ if (!entering) {
+ BLANKLINE();
+ }
+ break;
+
+ case CMARK_NODE_TEXT:
+ OUT(cmark_node_get_literal(node), allow_wrap, NORMAL);
+ break;
+
+ case CMARK_NODE_LINEBREAK:
+ if (!(CMARK_OPT_HARDBREAKS & options)) {
+ LIT(" ");
+ }
+ CR();
+ break;
+
+ case CMARK_NODE_SOFTBREAK:
+ if (CMARK_OPT_HARDBREAKS & options) {
+ LIT(" ");
+ CR();
+ } else if (!renderer->no_linebreaks && renderer->width == 0 &&
+ !(CMARK_OPT_HARDBREAKS & options) &&
+ !(CMARK_OPT_NOBREAKS & options)) {
+ CR();
+ } else {
+ OUT(" ", allow_wrap, LITERAL);
+ }
+ break;
+
+ case CMARK_NODE_CODE:
+ code = cmark_node_get_literal(node);
+ code_len = strlen(code);
+ numticks = shortest_unused_backtick_sequence(code);
+ has_nonspace = false;
+ for (i=0; i < code_len; i++) {
+ if (code[i] != ' ') {
+ has_nonspace = true;
+ break;
+ }
+ }
+ extra_spaces = code_len == 0 ||
+ code[0] == '`' || code[code_len - 1] == '`' ||
+ (has_nonspace && code[0] == ' ' && code[code_len - 1] == ' ');
+ for (i = 0; i < numticks; i++) {
+ LIT("`");
+ }
+ if (extra_spaces) {
+ LIT(" ");
+ }
+ OUT(cmark_node_get_literal(node), allow_wrap, LITERAL);
+ if (extra_spaces) {
+ LIT(" ");
+ }
+ for (i = 0; i < numticks; i++) {
+ LIT("`");
+ }
+ break;
+
+ case CMARK_NODE_HTML_INLINE:
+ OUT(cmark_node_get_literal(node), false, LITERAL);
+ break;
+
+ case CMARK_NODE_CUSTOM_INLINE:
+ OUT(entering ? cmark_node_get_on_enter(node) : cmark_node_get_on_exit(node),
+ false, LITERAL);
+ break;
+
+ case CMARK_NODE_STRONG:
+ if (entering) {
+ LIT("**");
+ } else {
+ LIT("**");
+ }
+ break;
+
+ case CMARK_NODE_EMPH:
+ // If we have EMPH(EMPH(x)), we need to use *_x_*
+ // because **x** is STRONG(x):
+ if (node->parent && node->parent->type == CMARK_NODE_EMPH &&
+ node->next == NULL && node->prev == NULL) {
+ emph_delim = "_";
+ } else {
+ emph_delim = "*";
+ }
+ if (entering) {
+ LIT(emph_delim);
+ } else {
+ LIT(emph_delim);
+ }
+ break;
+
+ case CMARK_NODE_LINK:
+ if (is_autolink(node)) {
+ if (entering) {
+ LIT("<");
+ if (strncmp(cmark_node_get_url(node), "mailto:", 7) == 0) {
+ LIT((const char *)cmark_node_get_url(node) + 7);
+ } else {
+ LIT((const char *)cmark_node_get_url(node));
+ }
+ LIT(">");
+ // return signal to skip contents of node...
+ return 0;
+ }
+ } else {
+ if (entering) {
+ LIT("[");
+ } else {
+ LIT("](");
+ OUT(cmark_node_get_url(node), false, URL);
+ title = cmark_node_get_title(node);
+ if (strlen(title) > 0) {
+ LIT(" \"");
+ OUT(title, false, TITLE);
+ LIT("\"");
+ }
+ LIT(")");
+ }
+ }
+ break;
+
+ case CMARK_NODE_IMAGE:
+ if (entering) {
+ LIT("![");
+ } else {
+ LIT("](");
+ OUT(cmark_node_get_url(node), false, URL);
+ title = cmark_node_get_title(node);
+ if (strlen(title) > 0) {
+ OUT(" \"", allow_wrap, LITERAL);
+ OUT(title, false, TITLE);
+ LIT("\"");
+ }
+ LIT(")");
+ }
+ break;
+
+ default:
+ assert(false);
+ break;
+ }
+
+ return 1;
+}
+
+char *cmark_render_commonmark(cmark_node *root, int options, int width) {
+ if (options & CMARK_OPT_HARDBREAKS) {
+ // disable breaking on width, since it has
+ // a different meaning with OPT_HARDBREAKS
+ width = 0;
+ }
+ return cmark_render(root, options, width, outc, S_render_node);
+}
diff --git a/cmark/src/entities.inc b/cmark/src/entities.inc
new file mode 100644
index 0000000000..e80d9aa9a4
--- /dev/null
+++ b/cmark/src/entities.inc
@@ -0,0 +1,2054 @@
+/* Autogenerated by tools/make_headers_inc.py */
+
+#define ENT_MIN_LENGTH 2
+#define ENT_MAX_LENGTH 32
+#define ENT_TABLE_SIZE 2125
+#define ENT_TEXT_IDX(x) ((x) & 0x7FFF)
+#define ENT_NAME_SIZE(x) (((x) >> 15) & 0x1F)
+#define ENT_REPL_SIZE(x) ((x) >> 20)
+
+static const uint32_t cmark_entities[2125] = {
+ 0x228000, 0x118007, 0x23000B, 0x230013, 0x22801B, 0x218022,
+ 0x418027, 0x23002E, 0x228036, 0x22803D, 0x318044, 0x22804A,
+ 0x420051, 0x368059, 0x228069, 0x420070, 0x330078, 0x230081,
+ 0x220089, 0x34808F, 0x32009B, 0x3300A2, 0x2180AB, 0x3380B0,
+ 0x3500BA, 0x2200C7, 0x4180CD, 0x4200D4, 0x2280DC, 0x3200E3,
+ 0x3300EA, 0x2200F3, 0x2200F9, 0x2300FF, 0x318107, 0x3A010D,
+ 0x338124, 0x23012E, 0x230136, 0x22813E, 0x338145, 0x22014F,
+ 0x238155, 0x24815E, 0x318169, 0x21816F, 0x348174, 0x358180,
+ 0x35018E, 0x35819B, 0x3C01A9, 0x3A81C4, 0x3781DC, 0x3281EE,
+ 0x3301F6, 0x3481FF, 0x33020B, 0x378214, 0x320226, 0x34822D,
+ 0x3F8239, 0x32825B, 0x420263, 0x31826B, 0x330271, 0x31027A,
+ 0x34027F, 0x22028A, 0x220290, 0x220296, 0x33029C, 0x3202A5,
+ 0x3282AC, 0x2302B4, 0x2182BC, 0x3182C1, 0x2282C7, 0x4182CE,
+ 0x2802D5, 0x2702E7, 0x2B02F7, 0x18030F, 0x280320, 0x338332,
+ 0x36833C, 0x42034C, 0x218354, 0x330359, 0x340362, 0x3A836D,
+ 0x248385, 0x378390, 0x3783A2, 0x3A03B4, 0x3683CB, 0x3983DB,
+ 0x3C03F1, 0x3A040C, 0x380423, 0x370436, 0x368447, 0x388457,
+ 0x38846B, 0x34847F, 0x36048B, 0x38049A, 0x2484AD, 0x3984B8,
+ 0x3884CE, 0x3704E2, 0x3884F3, 0x390507, 0x37851C, 0x39052E,
+ 0x338543, 0x36054D, 0x34855C, 0x420568, 0x230570, 0x218578,
+ 0x21857D, 0x230582, 0x23058A, 0x228592, 0x218599, 0x22059E,
+ 0x4185A4, 0x2305AB, 0x3385B3, 0x2285BD, 0x3805C4, 0x3A05D7,
+ 0x2285EE, 0x4205F5, 0x2385FD, 0x328606, 0x35060E, 0x35861B,
+ 0x320629, 0x320630, 0x218637, 0x22063C, 0x330642, 0x36064B,
+ 0x21865A, 0x41865F, 0x388666, 0x3A867A, 0x420692, 0x33069A,
+ 0x3506A3, 0x3206B0, 0x2206B7, 0x1106BD, 0x2286C0, 0x2306C7,
+ 0x2306CF, 0x2306D7, 0x2286DF, 0x2186E6, 0x2206EB, 0x4186F1,
+ 0x3106F8, 0x4206FD, 0x360705, 0x380714, 0x380727, 0x37073A,
+ 0x35874B, 0x388759, 0x36076D, 0x42077C, 0x310784, 0x230789,
+ 0x228791, 0x118798, 0x22879C, 0x3187A3, 0x3607A9, 0x3207B8,
+ 0x3707BF, 0x3207D0, 0x2307D7, 0x3607DF, 0x3487EE, 0x2207FA,
+ 0x228800, 0x220807, 0x23080D, 0x228815, 0x21881C, 0x220821,
+ 0x318827, 0x23082D, 0x310835, 0x22883A, 0x350841, 0x33884E,
+ 0x318858, 0x34085E, 0x360869, 0x370878, 0x370889, 0x22889A,
+ 0x4208A1, 0x2208A9, 0x3208AF, 0x2308B6, 0x2288BE, 0x2208C5,
+ 0x2288CB, 0x2188D2, 0x4188D7, 0x4208DE, 0x4208E6, 0x2308EE,
+ 0x2288F6, 0x2208FD, 0x220903, 0x228909, 0x230910, 0x218918,
+ 0x41891D, 0x420924, 0x42092C, 0x220934, 0x11093A, 0x23093D,
+ 0x230945, 0x32094D, 0x350954, 0x320961, 0x230968, 0x230970,
+ 0x218978, 0x38097D, 0x348990, 0x36099C, 0x3989AB, 0x3589C1,
+ 0x3889CF, 0x3889E3, 0x3709F7, 0x388A08, 0x348A1C, 0x370A28,
+ 0x378A39, 0x338A4B, 0x360A55, 0x368A64, 0x360A74, 0x378A83,
+ 0x388A95, 0x380AA9, 0x378ABC, 0x360ACE, 0x378ADD, 0x350AEF,
+ 0x368AFC, 0x348B0C, 0x370B18, 0x380B29, 0x368B3C, 0x358B4C,
+ 0x340B5A, 0x370B65, 0x348B76, 0x418B82, 0x310B89, 0x350B8E,
+ 0x230B9B, 0x368BA3, 0x390BB3, 0x370BC8, 0x368BD9, 0x390BE9,
+ 0x370BFE, 0x420C0F, 0x370C17, 0x378C28, 0x320C3A, 0x318C41,
+ 0x230C47, 0x310C4F, 0x318C54, 0x218C5A, 0x358C5F, 0x348C6D,
+ 0x418C79, 0x348C80, 0x420C8C, 0x320C94, 0x210C9B, 0x220C9F,
+ 0x230CA5, 0x230CAD, 0x230CB5, 0x218CBD, 0x398CC2, 0x390CD8,
+ 0x388CED, 0x3A8D01, 0x3A0D19, 0x370D30, 0x138D41, 0x418D49,
+ 0x338D50, 0x280D5A, 0x320D6C, 0x318D73, 0x360D79, 0x348D88,
+ 0x3A0D94, 0x350DAB, 0x340DB8, 0x568DC3, 0x348DD5, 0x350DE1,
+ 0x378DEE, 0x598E00, 0x588E18, 0x370E2E, 0x5A0E3F, 0x378E58,
+ 0x578E6A, 0x560E7E, 0x378E8F, 0x590EA1, 0x3A0EB8, 0x338ECF,
+ 0x360ED9, 0x370EE8, 0x558EF9, 0x588F09, 0x360F1F, 0x5B8F2E,
+ 0x588F4A, 0x358F60, 0x580F6E, 0x3A8F83, 0x388F9B, 0x380FAF,
+ 0x598FC2, 0x3A8FDA, 0x578FF2, 0x3A1006, 0x58901D, 0x3B1033,
+ 0x64904C, 0x37105B, 0x35906C, 0x58107A, 0x3A908F, 0x5810A7,
+ 0x6590BC, 0x3810CD, 0x3410E0, 0x3690EB, 0x3890FB, 0x36910F,
+ 0x37111F, 0x421130, 0x231138, 0x211140, 0x229144, 0x23114B,
+ 0x229153, 0x21915A, 0x23115F, 0x419167, 0x23116E, 0x229176,
+ 0x22917D, 0x239184, 0x42118D, 0x3A1195, 0x3711AC, 0x3111BD,
+ 0x4211C2, 0x2311CA, 0x2311D2, 0x3311DA, 0x2211E3, 0x3391E9,
+ 0x3491F3, 0x3591FF, 0x37920D, 0x34121F, 0x21922A, 0x41922F,
+ 0x219236, 0x21123B, 0x24923F, 0x36924A, 0x32125A, 0x311261,
+ 0x341266, 0x369271, 0x391281, 0x369296, 0x3292A6, 0x3392AE,
+ 0x3512B8, 0x3612C5, 0x4212D4, 0x2192DC, 0x1212E1, 0x4192E6,
+ 0x3212ED, 0x4212F4, 0x3292FC, 0x219304, 0x231309, 0x321311,
+ 0x321318, 0x33131F, 0x231328, 0x231330, 0x219338, 0x31133D,
+ 0x371342, 0x391353, 0x3A1368, 0x31937F, 0x219385, 0x38938A,
+ 0x35139E, 0x3693AB, 0x3993BB, 0x3613D1, 0x3913E0, 0x3913F5,
+ 0x37940A, 0x39141C, 0x351431, 0x34143E, 0x369449, 0x371459,
+ 0x36946A, 0x38147A, 0x39148D, 0x3894A2, 0x3814B6, 0x3694C9,
+ 0x3814D9, 0x3594EC, 0x3714FA, 0x35150B, 0x321518, 0x36151F,
+ 0x35952E, 0x32153C, 0x319543, 0x359549, 0x231557, 0x22155F,
+ 0x231565, 0x23156D, 0x311575, 0x23157A, 0x231582, 0x22958A,
+ 0x219591, 0x419596, 0x37159D, 0x3715AE, 0x3795BF, 0x3615D1,
+ 0x2295E0, 0x3595E7, 0x4215F5, 0x3215FD, 0x331604, 0x39160D,
+ 0x361622, 0x389631, 0x371645, 0x399656, 0x35966C, 0x42167A,
+ 0x321682, 0x319689, 0x33168F, 0x359698, 0x3416A6, 0x3696B1,
+ 0x3916C1, 0x3696D6, 0x3416E6, 0x3196F1, 0x3196F7, 0x3416FD,
+ 0x369708, 0x331718, 0x229721, 0x329728, 0x229730, 0x221737,
+ 0x11973D, 0x219741, 0x231746, 0x23174E, 0x219756, 0x41975B,
+ 0x349762, 0x22976E, 0x651775, 0x349785, 0x329791, 0x351799,
+ 0x3717A6, 0x3517B7, 0x4217C4, 0x3497CC, 0x4217D8, 0x2317E0,
+ 0x2317E8, 0x3217F0, 0x3417F7, 0x229802, 0x231809, 0x229811,
+ 0x219818, 0x23181D, 0x419825, 0x23182C, 0x229834, 0x14183B,
+ 0x351844, 0x361851, 0x381860, 0x329873, 0x34987B, 0x229887,
+ 0x42188E, 0x339896, 0x3518A0, 0x3818AD, 0x3598C0, 0x3698CE,
+ 0x3298DE, 0x3518E6, 0x3398F3, 0x3598FD, 0x37190B, 0x37991C,
+ 0x22192E, 0x239934, 0x22993D, 0x421944, 0x23194C, 0x221954,
+ 0x32995A, 0x321962, 0x219969, 0x32996E, 0x331976, 0x31997F,
+ 0x331985, 0x32198E, 0x359995, 0x1619A3, 0x3899B0, 0x3699C4,
+ 0x3699D4, 0x4199E4, 0x4219EB, 0x4219F3, 0x3319FB, 0x229A04,
+ 0x329A0B, 0x419A13, 0x421A1A, 0x421A22, 0x419A2A, 0x211A31,
+ 0x421A35, 0x421A3D, 0x221A45, 0x221A4B, 0x221A51, 0x231A57,
+ 0x229A5F, 0x219A66, 0x419A6B, 0x421A72, 0x421A7A, 0x221A82,
+ 0x221A88, 0x231A8E, 0x231A96, 0x219A9E, 0x221AA3, 0x371AA9,
+ 0x221ABA, 0x319AC0, 0x321AC6, 0x421ACD, 0x231AD5, 0x231ADD,
+ 0x311AE5, 0x519AEA, 0x319AF2, 0x229AF8, 0x229AFF, 0x219B06,
+ 0x229B0B, 0x311B12, 0x419B17, 0x231B1E, 0x339B26, 0x329B30,
+ 0x229B38, 0x229B3F, 0x329B46, 0x119B4E, 0x319B52, 0x331B58,
+ 0x321B61, 0x341B68, 0x321B73, 0x319B7A, 0x321B80, 0x329B87,
+ 0x331B8F, 0x341B98, 0x341BA3, 0x341BAE, 0x341BB9, 0x341BC4,
+ 0x341BCF, 0x341BDA, 0x341BE5, 0x329BF0, 0x339BF8, 0x341C02,
+ 0x331C0D, 0x229C16, 0x339C1D, 0x229C27, 0x421C2E, 0x311C36,
+ 0x319C3B, 0x331C41, 0x319C4A, 0x321C50, 0x121C57, 0x331C5C,
+ 0x341C65, 0x229C70, 0x421C77, 0x119C7F, 0x329C83, 0x339C8B,
+ 0x231C95, 0x221C9D, 0x341CA3, 0x329CAE, 0x321CB6, 0x341CBD,
+ 0x259CC8, 0x349CD5, 0x339CE1, 0x349CEB, 0x331CF7, 0x331D00,
+ 0x341D09, 0x321D14, 0x341D1B, 0x329D26, 0x219D2E, 0x329D33,
+ 0x331D3B, 0x339D44, 0x339D4E, 0x229D58, 0x331D5F, 0x221D68,
+ 0x321D6E, 0x339D75, 0x419D7F, 0x331D86, 0x339D8F, 0x331D99,
+ 0x339DA2, 0x341DAC, 0x349DB7, 0x341DC3, 0x339DCE, 0x379DD8,
+ 0x369DEA, 0x341DFA, 0x331E05, 0x341E0E, 0x331E19, 0x361E22,
+ 0x359E31, 0x369E3F, 0x389E4F, 0x389E63, 0x391E77, 0x329E8C,
+ 0x329E94, 0x329E9C, 0x329EA4, 0x329EAC, 0x419EB4, 0x639EBB,
+ 0x321EC8, 0x421ECF, 0x319ED7, 0x331EDD, 0x331EE6, 0x329EEF,
+ 0x329EF7, 0x329EFF, 0x329F07, 0x321F0F, 0x329F16, 0x329F1E,
+ 0x329F26, 0x329F2E, 0x329F36, 0x329F3E, 0x329F46, 0x329F4E,
+ 0x321F56, 0x329F5D, 0x329F65, 0x329F6D, 0x329F75, 0x329F7D,
+ 0x329F85, 0x331F8D, 0x329F96, 0x329F9E, 0x329FA6, 0x329FAE,
+ 0x321FB6, 0x329FBD, 0x329FC5, 0x329FCD, 0x329FD5, 0x341FDD,
+ 0x339FE8, 0x341FF2, 0x329FFD, 0x32A005, 0x32A00D, 0x32A015,
+ 0x32201D, 0x32A024, 0x32A02C, 0x32A034, 0x32A03C, 0x32A044,
+ 0x32A04C, 0x332054, 0x22A05D, 0x232064, 0x42206C, 0x32A074,
+ 0x32207C, 0x32A083, 0x12208B, 0x32A090, 0x342098, 0x3220A3,
+ 0x3320AA, 0x3220B3, 0x32A0BA, 0x32A0C2, 0x3320CA, 0x2320D3,
+ 0x31A0DB, 0x3320E1, 0x3420EA, 0x3320F5, 0x3320FE, 0x332107,
+ 0x622110, 0x32A11A, 0x22A122, 0x32A129, 0x232131, 0x232139,
+ 0x22A141, 0x32A148, 0x33A150, 0x22215A, 0x22A160, 0x33A167,
+ 0x222171, 0x24A177, 0x41A182, 0x222189, 0x32A18F, 0x34A197,
+ 0x21A1A3, 0x31A1A8, 0x3221AE, 0x2221B5, 0x3321BB, 0x37A1C4,
+ 0x3821D6, 0x2421E9, 0x3421F3, 0x3521FE, 0x35A20B, 0x35A219,
+ 0x322227, 0x34222E, 0x332239, 0x33A242, 0x32A24C, 0x342254,
+ 0x12A25F, 0x332265, 0x33A26E, 0x12A278, 0x13227E, 0x322285,
+ 0x33228C, 0x352295, 0x34A2A2, 0x3222AE, 0x33A2B5, 0x3322BF,
+ 0x4222C8, 0x3322D0, 0x2222D9, 0x3322DF, 0x32A2E8, 0x32A2F0,
+ 0x4222F8, 0x322300, 0x32A307, 0x32230F, 0x32A316, 0x32A31E,
+ 0x33A326, 0x33A330, 0x32A33A, 0x32A342, 0x33234A, 0x33A353,
+ 0x31A35D, 0x342363, 0x33236E, 0x332377, 0x332380, 0x32A389,
+ 0x622391, 0x33239B, 0x33A3A4, 0x35A3AE, 0x35A3BC, 0x3423CA,
+ 0x3523D5, 0x2323E2, 0x3723EA, 0x37A3FB, 0x32A40D, 0x32A415,
+ 0x34241D, 0x32A428, 0x332430, 0x322439, 0x322440, 0x332447,
+ 0x332450, 0x322459, 0x322460, 0x32A467, 0x33A46F, 0x22A479,
+ 0x232480, 0x21A488, 0x31248D, 0x33A492, 0x32A49C, 0x33A4A4,
+ 0x21A4AE, 0x22A4B3, 0x33A4BA, 0x3324C4, 0x41A4CD, 0x32A4D4,
+ 0x32A4DC, 0x3224E4, 0x33A4EB, 0x35A4F5, 0x32A503, 0x21A50B,
+ 0x23A510, 0x32A519, 0x21A521, 0x232526, 0x36A52E, 0x33253E,
+ 0x222547, 0x33254D, 0x332556, 0x13255F, 0x422566, 0x21A56E,
+ 0x32A573, 0x34257B, 0x342586, 0x33A591, 0x34A59B, 0x3725A7,
+ 0x34A5B8, 0x3725C4, 0x37A5D5, 0x3825E7, 0x3425FA, 0x332605,
+ 0x33260E, 0x422617, 0x22261F, 0x322625, 0x23262C, 0x32A634,
+ 0x32263C, 0x32A643, 0x32A64B, 0x32A653, 0x33A65B, 0x222665,
+ 0x34266B, 0x32A676, 0x32267E, 0x232685, 0x33268D, 0x232696,
+ 0x32269E, 0x22A6A5, 0x3326AC, 0x21A6B5, 0x2226BA, 0x3126C0,
+ 0x32A6C5, 0x41A6CD, 0x3126D4, 0x2326D9, 0x31A6E1, 0x3326E7,
+ 0x3126F0, 0x3426F5, 0x31A700, 0x31A706, 0x33270C, 0x22A715,
+ 0x32A71C, 0x342724, 0x33272F, 0x322738, 0x33273F, 0x332748,
+ 0x21A751, 0x322756, 0x22A75D, 0x422764, 0x32276C, 0x332773,
+ 0x32A77C, 0x222784, 0x23A78A, 0x22A793, 0x33279A, 0x33A7A3,
+ 0x32A7AD, 0x3527B5, 0x35A7C2, 0x1327D0, 0x3327D7, 0x32A7E0,
+ 0x33A7E8, 0x3427F2, 0x32A7FD, 0x32A805, 0x32280D, 0x32A814,
+ 0x32281C, 0x21A823, 0x21A828, 0x22282D, 0x322833, 0x12283A,
+ 0x32A83F, 0x35A847, 0x362855, 0x36A864, 0x21A874, 0x332879,
+ 0x332882, 0x32A88B, 0x332893, 0x41A89C, 0x32A8A3, 0x22A8AB,
+ 0x3228B2, 0x32A8B9, 0x32A8C1, 0x2228C9, 0x4228CF, 0x3328D7,
+ 0x3228E0, 0x32A8E7, 0x3428EF, 0x2328FA, 0x332902, 0x23290B,
+ 0x332913, 0x33291C, 0x332925, 0x33292E, 0x332937, 0x232940,
+ 0x332948, 0x332951, 0x33295A, 0x332963, 0x33296C, 0x332975,
+ 0x32A97E, 0x32A986, 0x42298E, 0x312996, 0x31A99B, 0x2329A1,
+ 0x22A9A9, 0x2329B0, 0x31A9B8, 0x2329BE, 0x22A9C6, 0x21A9CD,
+ 0x2229D2, 0x3129D8, 0x31A9DD, 0x31A9E3, 0x3229E9, 0x3429F0,
+ 0x31A9FB, 0x32AA01, 0x332A09, 0x33AA12, 0x342A1C, 0x622A27,
+ 0x332A31, 0x41AA3A, 0x312A41, 0x31AA46, 0x32AA4C, 0x222A54,
+ 0x312A5A, 0x31AA5F, 0x31AA65, 0x31AA6B, 0x31AA71, 0x322A77,
+ 0x342A7E, 0x31AA89, 0x322A8F, 0x32AA96, 0x32AA9E, 0x422AA6,
+ 0x12AAAE, 0x322AB4, 0x322ABB, 0x32AAC2, 0x32AACA, 0x112AD2,
+ 0x322AD5, 0x32AADC, 0x32AAE4, 0x332AEC, 0x33AAF5, 0x34AAFF,
+ 0x332B0B, 0x332B14, 0x34AB1D, 0x352B29, 0x33AB36, 0x332B40,
+ 0x64AB49, 0x622B58, 0x322B62, 0x332B69, 0x222B72, 0x332B78,
+ 0x232B81, 0x322B89, 0x33AB90, 0x32AB9A, 0x322BA2, 0x22ABA9,
+ 0x332BB0, 0x34ABB9, 0x332BC5, 0x332BCE, 0x41ABD7, 0x342BDE,
+ 0x342BE9, 0x32ABF4, 0x332BFC, 0x36AC05, 0x372C15, 0x422C26,
+ 0x332C2E, 0x422C37, 0x332C3F, 0x232C48, 0x332C50, 0x332C59,
+ 0x232C62, 0x312C6A, 0x22AC6F, 0x21AC76, 0x222C7B, 0x22AC81,
+ 0x31AC88, 0x41AC8E, 0x232C95, 0x312C9D, 0x332CA2, 0x32ACAB,
+ 0x332CB3, 0x32ACBC, 0x22ACC4, 0x22ACCB, 0x32ACD2, 0x342CDA,
+ 0x342CE5, 0x22ACF0, 0x322CF7, 0x22ACFE, 0x312D05, 0x332D0A,
+ 0x32AD13, 0x342D1B, 0x232D26, 0x31AD2E, 0x332D34, 0x342D3D,
+ 0x342D48, 0x342D53, 0x33AD5E, 0x222D68, 0x22AD6E, 0x422D75,
+ 0x222D7D, 0x32AD83, 0x232D8B, 0x422D93, 0x322D9B, 0x32ADA2,
+ 0x33ADAA, 0x32ADB4, 0x332DBC, 0x32ADC5, 0x312DCD, 0x232DD2,
+ 0x22ADDA, 0x222DE1, 0x22ADE7, 0x21ADEE, 0x41ADF3, 0x22ADFA,
+ 0x422E01, 0x422E09, 0x232E11, 0x22AE19, 0x22AE20, 0x232E27,
+ 0x232E2F, 0x21AE37, 0x41AE3C, 0x232E43, 0x222E4B, 0x222E51,
+ 0x422E57, 0x422E5F, 0x32AE67, 0x322E6F, 0x332E76, 0x32AE7F,
+ 0x312E87, 0x31AE8C, 0x322E92, 0x232E99, 0x342EA1, 0x332EAC,
+ 0x232EB5, 0x322EBD, 0x32AEC4, 0x332ECC, 0x31AED5, 0x22AEDB,
+ 0x322EE2, 0x32AEE9, 0x33AEF1, 0x332EFB, 0x332F04, 0x332F0D,
+ 0x332F16, 0x33AF1F, 0x332F29, 0x31AF32, 0x332F38, 0x322F41,
+ 0x62AF48, 0x32AF53, 0x32AF5B, 0x132F63, 0x132F6A, 0x32AF71,
+ 0x33AF79, 0x33AF83, 0x232F8D, 0x232F95, 0x32AF9D, 0x122FA5,
+ 0x21AFAA, 0x322FAF, 0x32AFB6, 0x332FBE, 0x33AFC7, 0x342FD1,
+ 0x322FDC, 0x312FE3, 0x34AFE8, 0x36AFF4, 0x37B004, 0x36B016,
+ 0x373026, 0x373037, 0x37B048, 0x38B05A, 0x39B06E, 0x373084,
+ 0x31B095, 0x31B09B, 0x3230A1, 0x3430A8, 0x31B0B3, 0x32B0B9,
+ 0x3330C1, 0x33B0CA, 0x3430D4, 0x6230DF, 0x3330E9, 0x3530F2,
+ 0x33B0FF, 0x34B109, 0x353115, 0x33B122, 0x33B12C, 0x333136,
+ 0x33313F, 0x41B148, 0x31314F, 0x31B154, 0x32B15A, 0x32B162,
+ 0x33316A, 0x32B173, 0x22317B, 0x313181, 0x32B186, 0x34318E,
+ 0x333199, 0x32B1A2, 0x2331AA, 0x3331B2, 0x3531BB, 0x31B1C8,
+ 0x3231CE, 0x3431D5, 0x31B1E0, 0x3231E6, 0x32B1ED, 0x32B1F5,
+ 0x32B1FD, 0x32B205, 0x32B20D, 0x36B215, 0x393225, 0x35323A,
+ 0x373247, 0x36B258, 0x373268, 0x32B279, 0x423281, 0x333289,
+ 0x33B292, 0x33329C, 0x1332A5, 0x31B2AC, 0x33B2B2, 0x3232BC,
+ 0x1232C3, 0x3332C8, 0x32B2D1, 0x3432D9, 0x32B2E4, 0x3332EC,
+ 0x31B2F5, 0x32B2FB, 0x333303, 0x42330C, 0x31B314, 0x32331A,
+ 0x32B321, 0x32B329, 0x123331, 0x32B336, 0x33333E, 0x233347,
+ 0x11334F, 0x323352, 0x32B359, 0x32B361, 0x333369, 0x333372,
+ 0x33337B, 0x33B384, 0x33338E, 0x323397, 0x32B39E, 0x32B3A6,
+ 0x3433AE, 0x33B3B9, 0x64B3C3, 0x6233D2, 0x32B3DC, 0x2233E4,
+ 0x3233EA, 0x3233F1, 0x33B3F8, 0x31B402, 0x333408, 0x353411,
+ 0x35341E, 0x34342B, 0x333436, 0x33343F, 0x21B448, 0x32B44D,
+ 0x36B455, 0x41B465, 0x31B46C, 0x22B472, 0x31B479, 0x13347F,
+ 0x333486, 0x23348F, 0x32B497, 0x33349F, 0x3334A8, 0x33B4B1,
+ 0x3234BB, 0x3234C2, 0x3334C9, 0x3334D2, 0x4234DB, 0x3134E3,
+ 0x4234E8, 0x3334F0, 0x2134F9, 0x3434FD, 0x32B508, 0x51B510,
+ 0x61B518, 0x523521, 0x35352A, 0x37B537, 0x51B549, 0x61B551,
+ 0x52355A, 0x35B563, 0x333571, 0x33357A, 0x32B583, 0x23358B,
+ 0x623593, 0x31B59D, 0x5235A3, 0x52B5AC, 0x22B5B6, 0x33B5BD,
+ 0x32B5C7, 0x33B5CF, 0x3435D9, 0x2235E4, 0x52B5EA, 0x5335F4,
+ 0x3235FF, 0x233606, 0x23360E, 0x32B616, 0x54361E, 0x32362B,
+ 0x21B632, 0x32B637, 0x31363F, 0x32B644, 0x33364C, 0x32B655,
+ 0x33B65D, 0x52B667, 0x333671, 0x33367A, 0x52B683, 0x33368D,
+ 0x33B696, 0x41B6A0, 0x51B6A7, 0x31B6AF, 0x3236B5, 0x52B6BC,
+ 0x54B6C6, 0x5236D4, 0x32B6DD, 0x31B6E5, 0x3236EB, 0x32B6F2,
+ 0x32B6FA, 0x32B702, 0x31370A, 0x31B70F, 0x323715, 0x31B71C,
+ 0x223722, 0x32B728, 0x51B730, 0x32B738, 0x323740, 0x31B747,
+ 0x35374D, 0x37B75A, 0x32376C, 0x52B773, 0x54B77D, 0x52378B,
+ 0x32B794, 0x32B79C, 0x31B7A4, 0x32B7AA, 0x3337B2, 0x3237BB,
+ 0x4237C2, 0x21B7CA, 0x32B7CF, 0x5337D7, 0x5437E2, 0x33B7EF,
+ 0x33B7F9, 0x33B803, 0x32B80D, 0x33B815, 0x33B81F, 0x33B829,
+ 0x323833, 0x34B83A, 0x633846, 0x52B852, 0x33B85C, 0x31B866,
+ 0x33386C, 0x523875, 0x32B87E, 0x53B886, 0x32B892, 0x32B89A,
+ 0x5338A2, 0x5338AD, 0x35B8B8, 0x32B8C6, 0x3338CE, 0x31B8D7,
+ 0x3338DD, 0x5238E6, 0x4238EF, 0x34B8F7, 0x373903, 0x323914,
+ 0x32B91B, 0x333923, 0x32B92C, 0x32B934, 0x33B93C, 0x33B946,
+ 0x323950, 0x52B957, 0x32B961, 0x63B969, 0x34B976, 0x553982,
+ 0x32B991, 0x53B999, 0x3239A5, 0x52B9AC, 0x32B9B6, 0x63B9BE,
+ 0x34B9CB, 0x5539D7, 0x3239E6, 0x2339ED, 0x3239F5, 0x36B9FC,
+ 0x37BA0C, 0x373A1E, 0x383A2F, 0x213A42, 0x11BA46, 0x333A4A,
+ 0x32BA53, 0x333A5B, 0x333A64, 0x623A6D, 0x333A77, 0x623A80,
+ 0x423A8A, 0x33BA92, 0x333A9C, 0x623AA5, 0x423AAF, 0x63BAB7,
+ 0x333AC4, 0x63BACD, 0x62BADA, 0x32BAE5, 0x333AED, 0x32BAF6,
+ 0x33BAFE, 0x333B08, 0x313B11, 0x233B16, 0x323B1E, 0x323B25,
+ 0x22BB2C, 0x21BB33, 0x32BB38, 0x233B40, 0x323B48, 0x323B4F,
+ 0x333B56, 0x22BB5F, 0x32BB66, 0x41BB6E, 0x223B75, 0x233B7B,
+ 0x31BB83, 0x32BB89, 0x21BB91, 0x323B96, 0x32BB9D, 0x32BBA5,
+ 0x33BBAD, 0x32BBB7, 0x31BBBF, 0x22BBC5, 0x22BBCC, 0x23BBD3,
+ 0x323BDC, 0x333BE3, 0x423BEC, 0x323BF4, 0x32BBFB, 0x32BC03,
+ 0x313C0B, 0x32BC10, 0x31BC18, 0x32BC1E, 0x33BC26, 0x223C30,
+ 0x223C36, 0x333C3C, 0x323C45, 0x33BC4C, 0x31BC56, 0x323C5C,
+ 0x233C63, 0x323C6B, 0x233C72, 0x333C7A, 0x343C83, 0x223C8E,
+ 0x32BC94, 0x31BC9C, 0x223CA2, 0x343CA8, 0x333CB3, 0x32BCBC,
+ 0x323CC4, 0x21BCCB, 0x133CD0, 0x133CD7, 0x333CDE, 0x323CE7,
+ 0x33BCEE, 0x41BCF8, 0x21BCFF, 0x223D04, 0x333D0A, 0x32BD13,
+ 0x213D1B, 0x34BD1F, 0x21BD2B, 0x333D30, 0x33BD39, 0x333D43,
+ 0x123D4C, 0x343D51, 0x32BD5C, 0x33BD64, 0x333D6E, 0x333D77,
+ 0x32BD80, 0x233D88, 0x33BD90, 0x33BD9A, 0x213DA4, 0x343DA8,
+ 0x423DB3, 0x22BDBB, 0x313DC2, 0x31BDC7, 0x323DCD, 0x32BDD4,
+ 0x31BDDC, 0x323DE2, 0x353DE9, 0x35BDF6, 0x333E04, 0x35BE0D,
+ 0x343E1B, 0x343E26, 0x33BE31, 0x32BE3B, 0x333E43, 0x323E4C,
+ 0x32BE53, 0x333E5B, 0x323E64, 0x343E6B, 0x343E76, 0x343E81,
+ 0x323E8C, 0x333E93, 0x32BE9C, 0x333EA4, 0x423EAD, 0x21BEB5,
+ 0x333EBA, 0x41BEC3, 0x323ECA, 0x423ED1, 0x333ED9, 0x423EE2,
+ 0x35BEEA, 0x33BEF8, 0x12BF02, 0x33BF08, 0x123F12, 0x32BF17,
+ 0x323F1F, 0x333F26, 0x32BF2F, 0x323F37, 0x523F3E, 0x233F47,
+ 0x32BF4F, 0x343F57, 0x323F62, 0x32BF69, 0x32BF71, 0x333F79,
+ 0x22BF82, 0x323F89, 0x333F90, 0x32BF99, 0x33BFA1, 0x32BFAB,
+ 0x333FB3, 0x333FBC, 0x333FC5, 0x333FCE, 0x33BFD7, 0x333FE1,
+ 0x32BFEA, 0x333FF2, 0x32BFFB, 0x34C003, 0x32C00F, 0x32C017,
+ 0x13401F, 0x134026, 0x32C02D, 0x33C035, 0x33C03F, 0x234049,
+ 0x234051, 0x32C059, 0x124061, 0x21C066, 0x32406B, 0x33C072,
+ 0x32C07C, 0x334084, 0x32408D, 0x324094, 0x33C09B, 0x3440A5,
+ 0x32C0B0, 0x3240B8, 0x21C0BF, 0x3340C4, 0x3340CD, 0x41C0D6,
+ 0x32C0DD, 0x32C0E5, 0x3340ED, 0x21C0F6, 0x2240FB, 0x354101,
+ 0x37410E, 0x38411F, 0x374132, 0x37C143, 0x38C155, 0x384169,
+ 0x37C17C, 0x37C18E, 0x2241A0, 0x3641A6, 0x32C1B5, 0x32C1BD,
+ 0x31C1C5, 0x3341CB, 0x3541D4, 0x32C1E1, 0x32C1E9, 0x32C1F1,
+ 0x32C1F9, 0x32C201, 0x424209, 0x334211, 0x33C21A, 0x124224,
+ 0x334229, 0x344232, 0x32C23D, 0x334245, 0x42424E, 0x31C256,
+ 0x12425C, 0x32C261, 0x334269, 0x334272, 0x33427B, 0x324284,
+ 0x32C28B, 0x32C293, 0x34429B, 0x33C2A6, 0x3142B0, 0x2342B5,
+ 0x32C2BD, 0x3142C5, 0x31C2CA, 0x3242D0, 0x2342D7, 0x32C2DF,
+ 0x31C2E7, 0x2342ED, 0x22C2F5, 0x3242FC, 0x32C303, 0x33430B,
+ 0x344314, 0x32C31F, 0x21C327, 0x32432C, 0x32C333, 0x32C33B,
+ 0x32C343, 0x33434B, 0x32C354, 0x33C35C, 0x224366, 0x12436C,
+ 0x334371, 0x34437A, 0x32C385, 0x32438D, 0x41C394, 0x33439B,
+ 0x32C3A4, 0x2343AC, 0x2243B4, 0x3443BA, 0x36C3C5, 0x21C3D5,
+ 0x22C3DA, 0x2343E1, 0x2343E9, 0x31C3F1, 0x3343F7, 0x324400,
+ 0x32C407, 0x32440F, 0x32C416, 0x32441E, 0x32C425, 0x32C42D,
+ 0x33C435, 0x33C43F, 0x32C449, 0x36C451, 0x334461, 0x34446A,
+ 0x324475, 0x32C47C, 0x31C484, 0x32448A, 0x62C491, 0x23449C,
+ 0x11C4A4, 0x3244A8, 0x3344AF, 0x4244B8, 0x3344C0, 0x34C4C9,
+ 0x3244D5, 0x32C4DC, 0x6344E4, 0x32C4F0, 0x6344F8, 0x32C504,
+ 0x33450C, 0x344515, 0x354520, 0x32C52D, 0x334535, 0x34453E,
+ 0x354549, 0x31C556, 0x33455C, 0x334565, 0x32456E, 0x32C575,
+ 0x42457D, 0x334585, 0x33458E, 0x334597, 0x3245A0, 0x32C5A7,
+ 0x27C5AF, 0x25C5C0, 0x22C5CD, 0x31C5D4, 0x3245DA, 0x3345E1,
+ 0x3245EA, 0x33C5F1, 0x33C5FB, 0x32C605, 0x32C60D, 0x33C615,
+ 0x33C61F, 0x334629, 0x344632, 0x34C63D, 0x34C649, 0x354655,
+ 0x334662, 0x33466B, 0x334674, 0x32467D, 0x354684, 0x35C691,
+ 0x33469F, 0x35C6A8, 0x3446B6, 0x3446C1, 0x33C6CC, 0x31C6D6,
+ 0x3246DC, 0x31C6E3, 0x2246E9, 0x2246EF, 0x2246F5, 0x3246FB,
+ 0x334702, 0x33C70B, 0x324715, 0x33C71C, 0x33C726, 0x33C730,
+ 0x33C73A, 0x33C744, 0x32C74E, 0x32C756, 0x33C75E, 0x334768,
+ 0x344771, 0x34C77C, 0x34C788, 0x354794, 0x3347A1, 0x3347AA,
+ 0x3347B3, 0x32C7BC, 0x3347C4, 0x32C7CD, 0x33C7D5, 0x3347DF,
+ 0x22C7E8, 0x3347EF, 0x21C7F8, 0x3247FD, 0x234804, 0x23480C,
+ 0x21C814, 0x324819, 0x334820, 0x41C829, 0x334830, 0x34C839,
+ 0x22C845, 0x24484C, 0x234856, 0x35C85E, 0x34486C, 0x334877,
+ 0x32C880, 0x334888, 0x22C891, 0x22C898, 0x22C89F, 0x3348A6,
+ 0x3448AF, 0x3348BA, 0x3248C3, 0x3248CA, 0x31C8D1, 0x3348D7,
+ 0x3348E0, 0x4248E9, 0x33C8F1, 0x3248FB, 0x334902, 0x32C90B,
+ 0x344913, 0x36491E, 0x36492D, 0x37493C, 0x34C94D, 0x36C959,
+ 0x37C969, 0x33497B, 0x324984, 0x34498B, 0x33C996, 0x32C9A0,
+ 0x33C9A8, 0x3449B2, 0x4249BD, 0x2249C5, 0x22C9CB, 0x2349D2,
+ 0x32C9DA, 0x3849E2, 0x38C9F5, 0x324A09, 0x324A10, 0x234A17,
+ 0x324A1F, 0x22CA26, 0x234A2D, 0x22CA35, 0x21CA3C, 0x32CA41,
+ 0x234A49, 0x32CA51, 0x334A59, 0x41CA62, 0x234A69, 0x32CA71,
+ 0x32CA79, 0x32CA81, 0x334A89, 0x344A92, 0x334A9D, 0x32CAA6,
+ 0x22CAAE, 0x21CAB5, 0x22CABA, 0x424AC1, 0x33CAC9, 0x35CAD3,
+ 0x36CAE1, 0x374AF1, 0x32CB02, 0x224B0A, 0x22CB10, 0x23CB17,
+ 0x354B20, 0x334B2D, 0x344B36, 0x334B41, 0x22CB4A, 0x32CB51,
+ 0x424B59, 0x32CB61, 0x234B69, 0x324B71, 0x32CB78, 0x32CB80,
+ 0x224B88, 0x33CB8E, 0x324B98, 0x324B9F, 0x32CBA6, 0x32CBAE,
+ 0x334BB6, 0x254BBF, 0x244BCB, 0x354BD5, 0x234BE2, 0x22CBEA,
+ 0x34CBF1, 0x324BFD, 0x234C04, 0x244C0C, 0x664C16, 0x66CC28,
+ 0x664C3B, 0x66CC4D, 0x244C60, 0x37CC6A, 0x384C7C, 0x21CC8F,
+ 0x32CC94, 0x31CC9C, 0x334CA2, 0x32CCAB, 0x334CB3, 0x134CBC,
+ 0x124CC3, 0x41CCC8, 0x32CCCF, 0x62CCD7, 0x62CCE2, 0x424CED,
+ 0x32CCF5, 0x32CCFD, 0x424D05, 0x634D0D, 0x634D19, 0x634D25,
+ 0x634D31, 0x33CD3D, 0x22CD47, 0x334D4E, 0x32CD57, 0x334D5F,
+ 0x334D68, 0x41CD71, 0x424D78, 0x314D80, 0x314D85, 0x334D8A,
+ 0x424D93, 0x324D9B, 0x32CDA2, 0x324DAA, 0x32CDB1, 0x41CDB9,
+ 0x32CDC0, 0x32CDC8, 0x214DD0, 0x32CDD4, 0x32CDDC, 0x324DE4,
+ 0x324DEB, 0x32CDF2, 0x424DFA, 0x334E02, 0x334E0B, 0x32CE14,
+ 0x32CE1C, 0x424E24, 0x334E2C, 0x334E35, 0x32CE3E, 0x324E46,
+ 0x334E4D, 0x234E56, 0x224E5E, 0x22CE64, 0x21CE6B, 0x21CE70,
+ 0x41CE75, 0x224E7C, 0x424E82, 0x424E8A, 0x224E92, 0x224E98,
+ 0x234E9E, 0x234EA6, 0x21CEAE, 0x224EB3, 0x334EB9, 0x224EC2,
+ 0x41CEC8, 0x224ECF, 0x33CED5, 0x424EDF, 0x424EE7, 0x31CEEF,
+ 0x324EF5
+};
+
+static const unsigned char cmark_entity_text[20220] = {
+ 0x41, 0x45, 0x6C, 0x69, 0x67, 0xC3, 0x86, 0x41, 0x4D, 0x50, 0x26, 0x41,
+ 0x61, 0x63, 0x75, 0x74, 0x65, 0xC3, 0x81, 0x41, 0x62, 0x72, 0x65, 0x76,
+ 0x65, 0xC4, 0x82, 0x41, 0x63, 0x69, 0x72, 0x63, 0xC3, 0x82, 0x41, 0x63,
+ 0x79, 0xD0, 0x90, 0x41, 0x66, 0x72, 0xF0, 0x9D, 0x94, 0x84, 0x41, 0x67,
+ 0x72, 0x61, 0x76, 0x65, 0xC3, 0x80, 0x41, 0x6C, 0x70, 0x68, 0x61, 0xCE,
+ 0x91, 0x41, 0x6D, 0x61, 0x63, 0x72, 0xC4, 0x80, 0x41, 0x6E, 0x64, 0xE2,
+ 0xA9, 0x93, 0x41, 0x6F, 0x67, 0x6F, 0x6E, 0xC4, 0x84, 0x41, 0x6F, 0x70,
+ 0x66, 0xF0, 0x9D, 0x94, 0xB8, 0x41, 0x70, 0x70, 0x6C, 0x79, 0x46, 0x75,
+ 0x6E, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0xE2, 0x81, 0xA1, 0x41, 0x72, 0x69,
+ 0x6E, 0x67, 0xC3, 0x85, 0x41, 0x73, 0x63, 0x72, 0xF0, 0x9D, 0x92, 0x9C,
+ 0x41, 0x73, 0x73, 0x69, 0x67, 0x6E, 0xE2, 0x89, 0x94, 0x41, 0x74, 0x69,
+ 0x6C, 0x64, 0x65, 0xC3, 0x83, 0x41, 0x75, 0x6D, 0x6C, 0xC3, 0x84, 0x42,
+ 0x61, 0x63, 0x6B, 0x73, 0x6C, 0x61, 0x73, 0x68, 0xE2, 0x88, 0x96, 0x42,
+ 0x61, 0x72, 0x76, 0xE2, 0xAB, 0xA7, 0x42, 0x61, 0x72, 0x77, 0x65, 0x64,
+ 0xE2, 0x8C, 0x86, 0x42, 0x63, 0x79, 0xD0, 0x91, 0x42, 0x65, 0x63, 0x61,
+ 0x75, 0x73, 0x65, 0xE2, 0x88, 0xB5, 0x42, 0x65, 0x72, 0x6E, 0x6F, 0x75,
+ 0x6C, 0x6C, 0x69, 0x73, 0xE2, 0x84, 0xAC, 0x42, 0x65, 0x74, 0x61, 0xCE,
+ 0x92, 0x42, 0x66, 0x72, 0xF0, 0x9D, 0x94, 0x85, 0x42, 0x6F, 0x70, 0x66,
+ 0xF0, 0x9D, 0x94, 0xB9, 0x42, 0x72, 0x65, 0x76, 0x65, 0xCB, 0x98, 0x42,
+ 0x73, 0x63, 0x72, 0xE2, 0x84, 0xAC, 0x42, 0x75, 0x6D, 0x70, 0x65, 0x71,
+ 0xE2, 0x89, 0x8E, 0x43, 0x48, 0x63, 0x79, 0xD0, 0xA7, 0x43, 0x4F, 0x50,
+ 0x59, 0xC2, 0xA9, 0x43, 0x61, 0x63, 0x75, 0x74, 0x65, 0xC4, 0x86, 0x43,
+ 0x61, 0x70, 0xE2, 0x8B, 0x92, 0x43, 0x61, 0x70, 0x69, 0x74, 0x61, 0x6C,
+ 0x44, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, 0x6E, 0x74, 0x69, 0x61, 0x6C,
+ 0x44, 0xE2, 0x85, 0x85, 0x43, 0x61, 0x79, 0x6C, 0x65, 0x79, 0x73, 0xE2,
+ 0x84, 0xAD, 0x43, 0x63, 0x61, 0x72, 0x6F, 0x6E, 0xC4, 0x8C, 0x43, 0x63,
+ 0x65, 0x64, 0x69, 0x6C, 0xC3, 0x87, 0x43, 0x63, 0x69, 0x72, 0x63, 0xC4,
+ 0x88, 0x43, 0x63, 0x6F, 0x6E, 0x69, 0x6E, 0x74, 0xE2, 0x88, 0xB0, 0x43,
+ 0x64, 0x6F, 0x74, 0xC4, 0x8A, 0x43, 0x65, 0x64, 0x69, 0x6C, 0x6C, 0x61,
+ 0xC2, 0xB8, 0x43, 0x65, 0x6E, 0x74, 0x65, 0x72, 0x44, 0x6F, 0x74, 0xC2,
+ 0xB7, 0x43, 0x66, 0x72, 0xE2, 0x84, 0xAD, 0x43, 0x68, 0x69, 0xCE, 0xA7,
+ 0x43, 0x69, 0x72, 0x63, 0x6C, 0x65, 0x44, 0x6F, 0x74, 0xE2, 0x8A, 0x99,
+ 0x43, 0x69, 0x72, 0x63, 0x6C, 0x65, 0x4D, 0x69, 0x6E, 0x75, 0x73, 0xE2,
+ 0x8A, 0x96, 0x43, 0x69, 0x72, 0x63, 0x6C, 0x65, 0x50, 0x6C, 0x75, 0x73,
+ 0xE2, 0x8A, 0x95, 0x43, 0x69, 0x72, 0x63, 0x6C, 0x65, 0x54, 0x69, 0x6D,
+ 0x65, 0x73, 0xE2, 0x8A, 0x97, 0x43, 0x6C, 0x6F, 0x63, 0x6B, 0x77, 0x69,
+ 0x73, 0x65, 0x43, 0x6F, 0x6E, 0x74, 0x6F, 0x75, 0x72, 0x49, 0x6E, 0x74,
+ 0x65, 0x67, 0x72, 0x61, 0x6C, 0xE2, 0x88, 0xB2, 0x43, 0x6C, 0x6F, 0x73,
+ 0x65, 0x43, 0x75, 0x72, 0x6C, 0x79, 0x44, 0x6F, 0x75, 0x62, 0x6C, 0x65,
+ 0x51, 0x75, 0x6F, 0x74, 0x65, 0xE2, 0x80, 0x9D, 0x43, 0x6C, 0x6F, 0x73,
+ 0x65, 0x43, 0x75, 0x72, 0x6C, 0x79, 0x51, 0x75, 0x6F, 0x74, 0x65, 0xE2,
+ 0x80, 0x99, 0x43, 0x6F, 0x6C, 0x6F, 0x6E, 0xE2, 0x88, 0xB7, 0x43, 0x6F,
+ 0x6C, 0x6F, 0x6E, 0x65, 0xE2, 0xA9, 0xB4, 0x43, 0x6F, 0x6E, 0x67, 0x72,
+ 0x75, 0x65, 0x6E, 0x74, 0xE2, 0x89, 0xA1, 0x43, 0x6F, 0x6E, 0x69, 0x6E,
+ 0x74, 0xE2, 0x88, 0xAF, 0x43, 0x6F, 0x6E, 0x74, 0x6F, 0x75, 0x72, 0x49,
+ 0x6E, 0x74, 0x65, 0x67, 0x72, 0x61, 0x6C, 0xE2, 0x88, 0xAE, 0x43, 0x6F,
+ 0x70, 0x66, 0xE2, 0x84, 0x82, 0x43, 0x6F, 0x70, 0x72, 0x6F, 0x64, 0x75,
+ 0x63, 0x74, 0xE2, 0x88, 0x90, 0x43, 0x6F, 0x75, 0x6E, 0x74, 0x65, 0x72,
+ 0x43, 0x6C, 0x6F, 0x63, 0x6B, 0x77, 0x69, 0x73, 0x65, 0x43, 0x6F, 0x6E,
+ 0x74, 0x6F, 0x75, 0x72, 0x49, 0x6E, 0x74, 0x65, 0x67, 0x72, 0x61, 0x6C,
+ 0xE2, 0x88, 0xB3, 0x43, 0x72, 0x6F, 0x73, 0x73, 0xE2, 0xA8, 0xAF, 0x43,
+ 0x73, 0x63, 0x72, 0xF0, 0x9D, 0x92, 0x9E, 0x43, 0x75, 0x70, 0xE2, 0x8B,
+ 0x93, 0x43, 0x75, 0x70, 0x43, 0x61, 0x70, 0xE2, 0x89, 0x8D, 0x44, 0x44,
+ 0xE2, 0x85, 0x85, 0x44, 0x44, 0x6F, 0x74, 0x72, 0x61, 0x68, 0x64, 0xE2,
+ 0xA4, 0x91, 0x44, 0x4A, 0x63, 0x79, 0xD0, 0x82, 0x44, 0x53, 0x63, 0x79,
+ 0xD0, 0x85, 0x44, 0x5A, 0x63, 0x79, 0xD0, 0x8F, 0x44, 0x61, 0x67, 0x67,
+ 0x65, 0x72, 0xE2, 0x80, 0xA1, 0x44, 0x61, 0x72, 0x72, 0xE2, 0x86, 0xA1,
+ 0x44, 0x61, 0x73, 0x68, 0x76, 0xE2, 0xAB, 0xA4, 0x44, 0x63, 0x61, 0x72,
+ 0x6F, 0x6E, 0xC4, 0x8E, 0x44, 0x63, 0x79, 0xD0, 0x94, 0x44, 0x65, 0x6C,
+ 0xE2, 0x88, 0x87, 0x44, 0x65, 0x6C, 0x74, 0x61, 0xCE, 0x94, 0x44, 0x66,
+ 0x72, 0xF0, 0x9D, 0x94, 0x87, 0x44, 0x69, 0x61, 0x63, 0x72, 0x69, 0x74,
+ 0x69, 0x63, 0x61, 0x6C, 0x41, 0x63, 0x75, 0x74, 0x65, 0xC2, 0xB4, 0x44,
+ 0x69, 0x61, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6C, 0x44, 0x6F,
+ 0x74, 0xCB, 0x99, 0x44, 0x69, 0x61, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63,
+ 0x61, 0x6C, 0x44, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x41, 0x63, 0x75, 0x74,
+ 0x65, 0xCB, 0x9D, 0x44, 0x69, 0x61, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63,
+ 0x61, 0x6C, 0x47, 0x72, 0x61, 0x76, 0x65, 0x60, 0x44, 0x69, 0x61, 0x63,
+ 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6C, 0x54, 0x69, 0x6C, 0x64, 0x65,
+ 0xCB, 0x9C, 0x44, 0x69, 0x61, 0x6D, 0x6F, 0x6E, 0x64, 0xE2, 0x8B, 0x84,
+ 0x44, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, 0x6E, 0x74, 0x69, 0x61, 0x6C,
+ 0x44, 0xE2, 0x85, 0x86, 0x44, 0x6F, 0x70, 0x66, 0xF0, 0x9D, 0x94, 0xBB,
+ 0x44, 0x6F, 0x74, 0xC2, 0xA8, 0x44, 0x6F, 0x74, 0x44, 0x6F, 0x74, 0xE2,
+ 0x83, 0x9C, 0x44, 0x6F, 0x74, 0x45, 0x71, 0x75, 0x61, 0x6C, 0xE2, 0x89,
+ 0x90, 0x44, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x43, 0x6F, 0x6E, 0x74, 0x6F,
+ 0x75, 0x72, 0x49, 0x6E, 0x74, 0x65, 0x67, 0x72, 0x61, 0x6C, 0xE2, 0x88,
+ 0xAF, 0x44, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x44, 0x6F, 0x74, 0xC2, 0xA8,
+ 0x44, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x44, 0x6F, 0x77, 0x6E, 0x41, 0x72,
+ 0x72, 0x6F, 0x77, 0xE2, 0x87, 0x93, 0x44, 0x6F, 0x75, 0x62, 0x6C, 0x65,
+ 0x4C, 0x65, 0x66, 0x74, 0x41, 0x72, 0x72, 0x6F, 0x77, 0xE2, 0x87, 0x90,
+ 0x44, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x4C, 0x65, 0x66, 0x74, 0x52, 0x69,
+ 0x67, 0x68, 0x74, 0x41, 0x72, 0x72, 0x6F, 0x77, 0xE2, 0x87, 0x94, 0x44,
+ 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x4C, 0x65, 0x66, 0x74, 0x54, 0x65, 0x65,
+ 0xE2, 0xAB, 0xA4, 0x44, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x4C, 0x6F, 0x6E,
+ 0x67, 0x4C, 0x65, 0x66, 0x74, 0x41, 0x72, 0x72, 0x6F, 0x77, 0xE2, 0x9F,
+ 0xB8, 0x44, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x4C, 0x6F, 0x6E, 0x67, 0x4C,
+ 0x65, 0x66, 0x74, 0x52, 0x69, 0x67, 0x68, 0x74, 0x41, 0x72, 0x72, 0x6F,
+ 0x77, 0xE2, 0x9F, 0xBA, 0x44, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x4C, 0x6F,
+ 0x6E, 0x67, 0x52, 0x69, 0x67, 0x68, 0x74, 0x41, 0x72, 0x72, 0x6F, 0x77,
+ 0xE2, 0x9F, 0xB9, 0x44, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x52, 0x69, 0x67,
+ 0x68, 0x74, 0x41, 0x72, 0x72, 0x6F, 0x77, 0xE2, 0x87, 0x92, 0x44, 0x6F,
+ 0x75, 0x62, 0x6C, 0x65, 0x52, 0x69, 0x67, 0x68, 0x74, 0x54, 0x65, 0x65,
+ 0xE2, 0x8A, 0xA8, 0x44, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x55, 0x70, 0x41,
+ 0x72, 0x72, 0x6F, 0x77, 0xE2, 0x87, 0x91, 0x44, 0x6F, 0x75, 0x62, 0x6C,
+ 0x65, 0x55, 0x70, 0x44, 0x6F, 0x77, 0x6E, 0x41, 0x72, 0x72, 0x6F, 0x77,
+ 0xE2, 0x87, 0x95, 0x44, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x56, 0x65, 0x72,
+ 0x74, 0x69, 0x63, 0x61, 0x6C, 0x42, 0x61, 0x72, 0xE2, 0x88, 0xA5, 0x44,
+ 0x6F, 0x77, 0x6E, 0x41, 0x72, 0x72, 0x6F, 0x77, 0xE2, 0x86, 0x93, 0x44,
+ 0x6F, 0x77, 0x6E, 0x41, 0x72, 0x72, 0x6F, 0x77, 0x42, 0x61, 0x72, 0xE2,
+ 0xA4, 0x93, 0x44, 0x6F, 0x77, 0x6E, 0x41, 0x72, 0x72, 0x6F, 0x77, 0x55,
+ 0x70, 0x41, 0x72, 0x72, 0x6F, 0x77, 0xE2, 0x87, 0xB5, 0x44, 0x6F, 0x77,
+ 0x6E, 0x42, 0x72, 0x65, 0x76, 0x65, 0xCC, 0x91, 0x44, 0x6F, 0x77, 0x6E,
+ 0x4C, 0x65, 0x66, 0x74, 0x52, 0x69, 0x67, 0x68, 0x74, 0x56, 0x65, 0x63,
+ 0x74, 0x6F, 0x72, 0xE2, 0xA5, 0x90, 0x44, 0x6F, 0x77, 0x6E, 0x4C, 0x65,
+ 0x66, 0x74, 0x54, 0x65, 0x65, 0x56, 0x65, 0x63, 0x74, 0x6F, 0x72, 0xE2,
+ 0xA5, 0x9E, 0x44, 0x6F, 0x77, 0x6E, 0x4C, 0x65, 0x66, 0x74, 0x56, 0x65,
+ 0x63, 0x74, 0x6F, 0x72, 0xE2, 0x86, 0xBD, 0x44, 0x6F, 0x77, 0x6E, 0x4C,
+ 0x65, 0x66, 0x74, 0x56, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x42, 0x61, 0x72,
+ 0xE2, 0xA5, 0x96, 0x44, 0x6F, 0x77, 0x6E, 0x52, 0x69, 0x67, 0x68, 0x74,
+ 0x54, 0x65, 0x65, 0x56, 0x65, 0x63, 0x74, 0x6F, 0x72, 0xE2, 0xA5, 0x9F,
+ 0x44, 0x6F, 0x77, 0x6E, 0x52, 0x69, 0x67, 0x68, 0x74, 0x56, 0x65, 0x63,
+ 0x74, 0x6F, 0x72, 0xE2, 0x87, 0x81, 0x44, 0x6F, 0x77, 0x6E, 0x52, 0x69,
+ 0x67, 0x68, 0x74, 0x56, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x42, 0x61, 0x72,
+ 0xE2, 0xA5, 0x97, 0x44, 0x6F, 0x77, 0x6E, 0x54, 0x65, 0x65, 0xE2, 0x8A,
+ 0xA4, 0x44, 0x6F, 0x77, 0x6E, 0x54, 0x65, 0x65, 0x41, 0x72, 0x72, 0x6F,
+ 0x77, 0xE2, 0x86, 0xA7, 0x44, 0x6F, 0x77, 0x6E, 0x61, 0x72, 0x72, 0x6F,
+ 0x77, 0xE2, 0x87, 0x93, 0x44, 0x73, 0x63, 0x72, 0xF0, 0x9D, 0x92, 0x9F,
+ 0x44, 0x73, 0x74, 0x72, 0x6F, 0x6B, 0xC4, 0x90, 0x45, 0x4E, 0x47, 0xC5,
+ 0x8A, 0x45, 0x54, 0x48, 0xC3, 0x90, 0x45, 0x61, 0x63, 0x75, 0x74, 0x65,
+ 0xC3, 0x89, 0x45, 0x63, 0x61, 0x72, 0x6F, 0x6E, 0xC4, 0x9A, 0x45, 0x63,
+ 0x69, 0x72, 0x63, 0xC3, 0x8A, 0x45, 0x63, 0x79, 0xD0, 0xAD, 0x45, 0x64,
+ 0x6F, 0x74, 0xC4, 0x96, 0x45, 0x66, 0x72, 0xF0, 0x9D, 0x94, 0x88, 0x45,
+ 0x67, 0x72, 0x61, 0x76, 0x65, 0xC3, 0x88, 0x45, 0x6C, 0x65, 0x6D, 0x65,
+ 0x6E, 0x74, 0xE2, 0x88, 0x88, 0x45, 0x6D, 0x61, 0x63, 0x72, 0xC4, 0x92,
+ 0x45, 0x6D, 0x70, 0x74, 0x79, 0x53, 0x6D, 0x61, 0x6C, 0x6C, 0x53, 0x71,
+ 0x75, 0x61, 0x72, 0x65, 0xE2, 0x97, 0xBB, 0x45, 0x6D, 0x70, 0x74, 0x79,
+ 0x56, 0x65, 0x72, 0x79, 0x53, 0x6D, 0x61, 0x6C, 0x6C, 0x53, 0x71, 0x75,
+ 0x61, 0x72, 0x65, 0xE2, 0x96, 0xAB, 0x45, 0x6F, 0x67, 0x6F, 0x6E, 0xC4,
+ 0x98, 0x45, 0x6F, 0x70, 0x66, 0xF0, 0x9D, 0x94, 0xBC, 0x45, 0x70, 0x73,
+ 0x69, 0x6C, 0x6F, 0x6E, 0xCE, 0x95, 0x45, 0x71, 0x75, 0x61, 0x6C, 0xE2,
+ 0xA9, 0xB5, 0x45, 0x71, 0x75, 0x61, 0x6C, 0x54, 0x69, 0x6C, 0x64, 0x65,
+ 0xE2, 0x89, 0x82, 0x45, 0x71, 0x75, 0x69, 0x6C, 0x69, 0x62, 0x72, 0x69,
+ 0x75, 0x6D, 0xE2, 0x87, 0x8C, 0x45, 0x73, 0x63, 0x72, 0xE2, 0x84, 0xB0,
+ 0x45, 0x73, 0x69, 0x6D, 0xE2, 0xA9, 0xB3, 0x45, 0x74, 0x61, 0xCE, 0x97,
+ 0x45, 0x75, 0x6D, 0x6C, 0xC3, 0x8B, 0x45, 0x78, 0x69, 0x73, 0x74, 0x73,
+ 0xE2, 0x88, 0x83, 0x45, 0x78, 0x70, 0x6F, 0x6E, 0x65, 0x6E, 0x74, 0x69,
+ 0x61, 0x6C, 0x45, 0xE2, 0x85, 0x87, 0x46, 0x63, 0x79, 0xD0, 0xA4, 0x46,
+ 0x66, 0x72, 0xF0, 0x9D, 0x94, 0x89, 0x46, 0x69, 0x6C, 0x6C, 0x65, 0x64,
+ 0x53, 0x6D, 0x61, 0x6C, 0x6C, 0x53, 0x71, 0x75, 0x61, 0x72, 0x65, 0xE2,
+ 0x97, 0xBC, 0x46, 0x69, 0x6C, 0x6C, 0x65, 0x64, 0x56, 0x65, 0x72, 0x79,
+ 0x53, 0x6D, 0x61, 0x6C, 0x6C, 0x53, 0x71, 0x75, 0x61, 0x72, 0x65, 0xE2,
+ 0x96, 0xAA, 0x46, 0x6F, 0x70, 0x66, 0xF0, 0x9D, 0x94, 0xBD, 0x46, 0x6F,
+ 0x72, 0x41, 0x6C, 0x6C, 0xE2, 0x88, 0x80, 0x46, 0x6F, 0x75, 0x72, 0x69,
+ 0x65, 0x72, 0x74, 0x72, 0x66, 0xE2, 0x84, 0xB1, 0x46, 0x73, 0x63, 0x72,
+ 0xE2, 0x84, 0xB1, 0x47, 0x4A, 0x63, 0x79, 0xD0, 0x83, 0x47, 0x54, 0x3E,
+ 0x47, 0x61, 0x6D, 0x6D, 0x61, 0xCE, 0x93, 0x47, 0x61, 0x6D, 0x6D, 0x61,
+ 0x64, 0xCF, 0x9C, 0x47, 0x62, 0x72, 0x65, 0x76, 0x65, 0xC4, 0x9E, 0x47,
+ 0x63, 0x65, 0x64, 0x69, 0x6C, 0xC4, 0xA2, 0x47, 0x63, 0x69, 0x72, 0x63,
+ 0xC4, 0x9C, 0x47, 0x63, 0x79, 0xD0, 0x93, 0x47, 0x64, 0x6F, 0x74, 0xC4,
+ 0xA0, 0x47, 0x66, 0x72, 0xF0, 0x9D, 0x94, 0x8A, 0x47, 0x67, 0xE2, 0x8B,
+ 0x99, 0x47, 0x6F, 0x70, 0x66, 0xF0, 0x9D, 0x94, 0xBE, 0x47, 0x72, 0x65,
+ 0x61, 0x74, 0x65, 0x72, 0x45, 0x71, 0x75, 0x61, 0x6C, 0xE2, 0x89, 0xA5,
+ 0x47, 0x72, 0x65, 0x61, 0x74, 0x65, 0x72, 0x45, 0x71, 0x75, 0x61, 0x6C,
+ 0x4C, 0x65, 0x73, 0x73, 0xE2, 0x8B, 0x9B, 0x47, 0x72, 0x65, 0x61, 0x74,
+ 0x65, 0x72, 0x46, 0x75, 0x6C, 0x6C, 0x45, 0x71, 0x75, 0x61, 0x6C, 0xE2,
+ 0x89, 0xA7, 0x47, 0x72, 0x65, 0x61, 0x74, 0x65, 0x72, 0x47, 0x72, 0x65,
+ 0x61, 0x74, 0x65, 0x72, 0xE2, 0xAA, 0xA2, 0x47, 0x72, 0x65, 0x61, 0x74,
+ 0x65, 0x72, 0x4C, 0x65, 0x73, 0x73, 0xE2, 0x89, 0xB7, 0x47, 0x72, 0x65,
+ 0x61, 0x74, 0x65, 0x72, 0x53, 0x6C, 0x61, 0x6E, 0x74, 0x45, 0x71, 0x75,
+ 0x61, 0x6C, 0xE2, 0xA9, 0xBE, 0x47, 0x72, 0x65, 0x61, 0x74, 0x65, 0x72,
+ 0x54, 0x69, 0x6C, 0x64, 0x65, 0xE2, 0x89, 0xB3, 0x47, 0x73, 0x63, 0x72,
+ 0xF0, 0x9D, 0x92, 0xA2, 0x47, 0x74, 0xE2, 0x89, 0xAB, 0x48, 0x41, 0x52,
+ 0x44, 0x63, 0x79, 0xD0, 0xAA, 0x48, 0x61, 0x63, 0x65, 0x6B, 0xCB, 0x87,
+ 0x48, 0x61, 0x74, 0x5E, 0x48, 0x63, 0x69, 0x72, 0x63, 0xC4, 0xA4, 0x48,
+ 0x66, 0x72, 0xE2, 0x84, 0x8C, 0x48, 0x69, 0x6C, 0x62, 0x65, 0x72, 0x74,
+ 0x53, 0x70, 0x61, 0x63, 0x65, 0xE2, 0x84, 0x8B, 0x48, 0x6F, 0x70, 0x66,
+ 0xE2, 0x84, 0x8D, 0x48, 0x6F, 0x72, 0x69, 0x7A, 0x6F, 0x6E, 0x74, 0x61,
+ 0x6C, 0x4C, 0x69, 0x6E, 0x65, 0xE2, 0x94, 0x80, 0x48, 0x73, 0x63, 0x72,
+ 0xE2, 0x84, 0x8B, 0x48, 0x73, 0x74, 0x72, 0x6F, 0x6B, 0xC4, 0xA6, 0x48,
+ 0x75, 0x6D, 0x70, 0x44, 0x6F, 0x77, 0x6E, 0x48, 0x75, 0x6D, 0x70, 0xE2,
+ 0x89, 0x8E, 0x48, 0x75, 0x6D, 0x70, 0x45, 0x71, 0x75, 0x61, 0x6C, 0xE2,
+ 0x89, 0x8F, 0x49, 0x45, 0x63, 0x79, 0xD0, 0x95, 0x49, 0x4A, 0x6C, 0x69,
+ 0x67, 0xC4, 0xB2, 0x49, 0x4F, 0x63, 0x79, 0xD0, 0x81, 0x49, 0x61, 0x63,
+ 0x75, 0x74, 0x65, 0xC3, 0x8D, 0x49, 0x63, 0x69, 0x72, 0x63, 0xC3, 0x8E,
+ 0x49, 0x63, 0x79, 0xD0, 0x98, 0x49, 0x64, 0x6F, 0x74, 0xC4, 0xB0, 0x49,
+ 0x66, 0x72, 0xE2, 0x84, 0x91, 0x49, 0x67, 0x72, 0x61, 0x76, 0x65, 0xC3,
+ 0x8C, 0x49, 0x6D, 0xE2, 0x84, 0x91, 0x49, 0x6D, 0x61, 0x63, 0x72, 0xC4,
+ 0xAA, 0x49, 0x6D, 0x61, 0x67, 0x69, 0x6E, 0x61, 0x72, 0x79, 0x49, 0xE2,
+ 0x85, 0x88, 0x49, 0x6D, 0x70, 0x6C, 0x69, 0x65, 0x73, 0xE2, 0x87, 0x92,
+ 0x49, 0x6E, 0x74, 0xE2, 0x88, 0xAC, 0x49, 0x6E, 0x74, 0x65, 0x67, 0x72,
+ 0x61, 0x6C, 0xE2, 0x88, 0xAB, 0x49, 0x6E, 0x74, 0x65, 0x72, 0x73, 0x65,
+ 0x63, 0x74, 0x69, 0x6F, 0x6E, 0xE2, 0x8B, 0x82, 0x49, 0x6E, 0x76, 0x69,
+ 0x73, 0x69, 0x62, 0x6C, 0x65, 0x43, 0x6F, 0x6D, 0x6D, 0x61, 0xE2, 0x81,
+ 0xA3, 0x49, 0x6E, 0x76, 0x69, 0x73, 0x69, 0x62, 0x6C, 0x65, 0x54, 0x69,
+ 0x6D, 0x65, 0x73, 0xE2, 0x81, 0xA2, 0x49, 0x6F, 0x67, 0x6F, 0x6E, 0xC4,
+ 0xAE, 0x49, 0x6F, 0x70, 0x66, 0xF0, 0x9D, 0x95, 0x80, 0x49, 0x6F, 0x74,
+ 0x61, 0xCE, 0x99, 0x49, 0x73, 0x63, 0x72, 0xE2, 0x84, 0x90, 0x49, 0x74,
+ 0x69, 0x6C, 0x64, 0x65, 0xC4, 0xA8, 0x49, 0x75, 0x6B, 0x63, 0x79, 0xD0,
+ 0x86, 0x49, 0x75, 0x6D, 0x6C, 0xC3, 0x8F, 0x4A, 0x63, 0x69, 0x72, 0x63,
+ 0xC4, 0xB4, 0x4A, 0x63, 0x79, 0xD0, 0x99, 0x4A, 0x66, 0x72, 0xF0, 0x9D,
+ 0x94, 0x8D, 0x4A, 0x6F, 0x70, 0x66, 0xF0, 0x9D, 0x95, 0x81, 0x4A, 0x73,
+ 0x63, 0x72, 0xF0, 0x9D, 0x92, 0xA5, 0x4A, 0x73, 0x65, 0x72, 0x63, 0x79,
+ 0xD0, 0x88, 0x4A, 0x75, 0x6B, 0x63, 0x79, 0xD0, 0x84, 0x4B, 0x48, 0x63,
+ 0x79, 0xD0, 0xA5, 0x4B, 0x4A, 0x63, 0x79, 0xD0, 0x8C, 0x4B, 0x61, 0x70,
+ 0x70, 0x61, 0xCE, 0x9A, 0x4B, 0x63, 0x65, 0x64, 0x69, 0x6C, 0xC4, 0xB6,
+ 0x4B, 0x63, 0x79, 0xD0, 0x9A, 0x4B, 0x66, 0x72, 0xF0, 0x9D, 0x94, 0x8E,
+ 0x4B, 0x6F, 0x70, 0x66, 0xF0, 0x9D, 0x95, 0x82, 0x4B, 0x73, 0x63, 0x72,
+ 0xF0, 0x9D, 0x92, 0xA6, 0x4C, 0x4A, 0x63, 0x79, 0xD0, 0x89, 0x4C, 0x54,
+ 0x3C, 0x4C, 0x61, 0x63, 0x75, 0x74, 0x65, 0xC4, 0xB9, 0x4C, 0x61, 0x6D,
+ 0x62, 0x64, 0x61, 0xCE, 0x9B, 0x4C, 0x61, 0x6E, 0x67, 0xE2, 0x9F, 0xAA,
+ 0x4C, 0x61, 0x70, 0x6C, 0x61, 0x63, 0x65, 0x74, 0x72, 0x66, 0xE2, 0x84,
+ 0x92, 0x4C, 0x61, 0x72, 0x72, 0xE2, 0x86, 0x9E, 0x4C, 0x63, 0x61, 0x72,
+ 0x6F, 0x6E, 0xC4, 0xBD, 0x4C, 0x63, 0x65, 0x64, 0x69, 0x6C, 0xC4, 0xBB,
+ 0x4C, 0x63, 0x79, 0xD0, 0x9B, 0x4C, 0x65, 0x66, 0x74, 0x41, 0x6E, 0x67,
+ 0x6C, 0x65, 0x42, 0x72, 0x61, 0x63, 0x6B, 0x65, 0x74, 0xE2, 0x9F, 0xA8,
+ 0x4C, 0x65, 0x66, 0x74, 0x41, 0x72, 0x72, 0x6F, 0x77, 0xE2, 0x86, 0x90,
+ 0x4C, 0x65, 0x66, 0x74, 0x41, 0x72, 0x72, 0x6F, 0x77, 0x42, 0x61, 0x72,
+ 0xE2, 0x87, 0xA4, 0x4C, 0x65, 0x66, 0x74, 0x41, 0x72, 0x72, 0x6F, 0x77,
+ 0x52, 0x69, 0x67, 0x68, 0x74, 0x41, 0x72, 0x72, 0x6F, 0x77, 0xE2, 0x87,
+ 0x86, 0x4C, 0x65, 0x66, 0x74, 0x43, 0x65, 0x69, 0x6C, 0x69, 0x6E, 0x67,
+ 0xE2, 0x8C, 0x88, 0x4C, 0x65, 0x66, 0x74, 0x44, 0x6F, 0x75, 0x62, 0x6C,
+ 0x65, 0x42, 0x72, 0x61, 0x63, 0x6B, 0x65, 0x74, 0xE2, 0x9F, 0xA6, 0x4C,
+ 0x65, 0x66, 0x74, 0x44, 0x6F, 0x77, 0x6E, 0x54, 0x65, 0x65, 0x56, 0x65,
+ 0x63, 0x74, 0x6F, 0x72, 0xE2, 0xA5, 0xA1, 0x4C, 0x65, 0x66, 0x74, 0x44,
+ 0x6F, 0x77, 0x6E, 0x56, 0x65, 0x63, 0x74, 0x6F, 0x72, 0xE2, 0x87, 0x83,
+ 0x4C, 0x65, 0x66, 0x74, 0x44, 0x6F, 0x77, 0x6E, 0x56, 0x65, 0x63, 0x74,
+ 0x6F, 0x72, 0x42, 0x61, 0x72, 0xE2, 0xA5, 0x99, 0x4C, 0x65, 0x66, 0x74,
+ 0x46, 0x6C, 0x6F, 0x6F, 0x72, 0xE2, 0x8C, 0x8A, 0x4C, 0x65, 0x66, 0x74,
+ 0x52, 0x69, 0x67, 0x68, 0x74, 0x41, 0x72, 0x72, 0x6F, 0x77, 0xE2, 0x86,
+ 0x94, 0x4C, 0x65, 0x66, 0x74, 0x52, 0x69, 0x67, 0x68, 0x74, 0x56, 0x65,
+ 0x63, 0x74, 0x6F, 0x72, 0xE2, 0xA5, 0x8E, 0x4C, 0x65, 0x66, 0x74, 0x54,
+ 0x65, 0x65, 0xE2, 0x8A, 0xA3, 0x4C, 0x65, 0x66, 0x74, 0x54, 0x65, 0x65,
+ 0x41, 0x72, 0x72, 0x6F, 0x77, 0xE2, 0x86, 0xA4, 0x4C, 0x65, 0x66, 0x74,
+ 0x54, 0x65, 0x65, 0x56, 0x65, 0x63, 0x74, 0x6F, 0x72, 0xE2, 0xA5, 0x9A,
+ 0x4C, 0x65, 0x66, 0x74, 0x54, 0x72, 0x69, 0x61, 0x6E, 0x67, 0x6C, 0x65,
+ 0xE2, 0x8A, 0xB2, 0x4C, 0x65, 0x66, 0x74, 0x54, 0x72, 0x69, 0x61, 0x6E,
+ 0x67, 0x6C, 0x65, 0x42, 0x61, 0x72, 0xE2, 0xA7, 0x8F, 0x4C, 0x65, 0x66,
+ 0x74, 0x54, 0x72, 0x69, 0x61, 0x6E, 0x67, 0x6C, 0x65, 0x45, 0x71, 0x75,
+ 0x61, 0x6C, 0xE2, 0x8A, 0xB4, 0x4C, 0x65, 0x66, 0x74, 0x55, 0x70, 0x44,
+ 0x6F, 0x77, 0x6E, 0x56, 0x65, 0x63, 0x74, 0x6F, 0x72, 0xE2, 0xA5, 0x91,
+ 0x4C, 0x65, 0x66, 0x74, 0x55, 0x70, 0x54, 0x65, 0x65, 0x56, 0x65, 0x63,
+ 0x74, 0x6F, 0x72, 0xE2, 0xA5, 0xA0, 0x4C, 0x65, 0x66, 0x74, 0x55, 0x70,
+ 0x56, 0x65, 0x63, 0x74, 0x6F, 0x72, 0xE2, 0x86, 0xBF, 0x4C, 0x65, 0x66,
+ 0x74, 0x55, 0x70, 0x56, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x42, 0x61, 0x72,
+ 0xE2, 0xA5, 0x98, 0x4C, 0x65, 0x66, 0x74, 0x56, 0x65, 0x63, 0x74, 0x6F,
+ 0x72, 0xE2, 0x86, 0xBC, 0x4C, 0x65, 0x66, 0x74, 0x56, 0x65, 0x63, 0x74,
+ 0x6F, 0x72, 0x42, 0x61, 0x72, 0xE2, 0xA5, 0x92, 0x4C, 0x65, 0x66, 0x74,
+ 0x61, 0x72, 0x72, 0x6F, 0x77, 0xE2, 0x87, 0x90, 0x4C, 0x65, 0x66, 0x74,
+ 0x72, 0x69, 0x67, 0x68, 0x74, 0x61, 0x72, 0x72, 0x6F, 0x77, 0xE2, 0x87,
+ 0x94, 0x4C, 0x65, 0x73, 0x73, 0x45, 0x71, 0x75, 0x61, 0x6C, 0x47, 0x72,
+ 0x65, 0x61, 0x74, 0x65, 0x72, 0xE2, 0x8B, 0x9A, 0x4C, 0x65, 0x73, 0x73,
+ 0x46, 0x75, 0x6C, 0x6C, 0x45, 0x71, 0x75, 0x61, 0x6C, 0xE2, 0x89, 0xA6,
+ 0x4C, 0x65, 0x73, 0x73, 0x47, 0x72, 0x65, 0x61, 0x74, 0x65, 0x72, 0xE2,
+ 0x89, 0xB6, 0x4C, 0x65, 0x73, 0x73, 0x4C, 0x65, 0x73, 0x73, 0xE2, 0xAA,
+ 0xA1, 0x4C, 0x65, 0x73, 0x73, 0x53, 0x6C, 0x61, 0x6E, 0x74, 0x45, 0x71,
+ 0x75, 0x61, 0x6C, 0xE2, 0xA9, 0xBD, 0x4C, 0x65, 0x73, 0x73, 0x54, 0x69,
+ 0x6C, 0x64, 0x65, 0xE2, 0x89, 0xB2, 0x4C, 0x66, 0x72, 0xF0, 0x9D, 0x94,
+ 0x8F, 0x4C, 0x6C, 0xE2, 0x8B, 0x98, 0x4C, 0x6C, 0x65, 0x66, 0x74, 0x61,
+ 0x72, 0x72, 0x6F, 0x77, 0xE2, 0x87, 0x9A, 0x4C, 0x6D, 0x69, 0x64, 0x6F,
+ 0x74, 0xC4, 0xBF, 0x4C, 0x6F, 0x6E, 0x67, 0x4C, 0x65, 0x66, 0x74, 0x41,
+ 0x72, 0x72, 0x6F, 0x77, 0xE2, 0x9F, 0xB5, 0x4C, 0x6F, 0x6E, 0x67, 0x4C,
+ 0x65, 0x66, 0x74, 0x52, 0x69, 0x67, 0x68, 0x74, 0x41, 0x72, 0x72, 0x6F,
+ 0x77, 0xE2, 0x9F, 0xB7, 0x4C, 0x6F, 0x6E, 0x67, 0x52, 0x69, 0x67, 0x68,
+ 0x74, 0x41, 0x72, 0x72, 0x6F, 0x77, 0xE2, 0x9F, 0xB6, 0x4C, 0x6F, 0x6E,
+ 0x67, 0x6C, 0x65, 0x66, 0x74, 0x61, 0x72, 0x72, 0x6F, 0x77, 0xE2, 0x9F,
+ 0xB8, 0x4C, 0x6F, 0x6E, 0x67, 0x6C, 0x65, 0x66, 0x74, 0x72, 0x69, 0x67,
+ 0x68, 0x74, 0x61, 0x72, 0x72, 0x6F, 0x77, 0xE2, 0x9F, 0xBA, 0x4C, 0x6F,
+ 0x6E, 0x67, 0x72, 0x69, 0x67, 0x68, 0x74, 0x61, 0x72, 0x72, 0x6F, 0x77,
+ 0xE2, 0x9F, 0xB9, 0x4C, 0x6F, 0x70, 0x66, 0xF0, 0x9D, 0x95, 0x83, 0x4C,
+ 0x6F, 0x77, 0x65, 0x72, 0x4C, 0x65, 0x66, 0x74, 0x41, 0x72, 0x72, 0x6F,
+ 0x77, 0xE2, 0x86, 0x99, 0x4C, 0x6F, 0x77, 0x65, 0x72, 0x52, 0x69, 0x67,
+ 0x68, 0x74, 0x41, 0x72, 0x72, 0x6F, 0x77, 0xE2, 0x86, 0x98, 0x4C, 0x73,
+ 0x63, 0x72, 0xE2, 0x84, 0x92, 0x4C, 0x73, 0x68, 0xE2, 0x86, 0xB0, 0x4C,
+ 0x73, 0x74, 0x72, 0x6F, 0x6B, 0xC5, 0x81, 0x4C, 0x74, 0xE2, 0x89, 0xAA,
+ 0x4D, 0x61, 0x70, 0xE2, 0xA4, 0x85, 0x4D, 0x63, 0x79, 0xD0, 0x9C, 0x4D,
+ 0x65, 0x64, 0x69, 0x75, 0x6D, 0x53, 0x70, 0x61, 0x63, 0x65, 0xE2, 0x81,
+ 0x9F, 0x4D, 0x65, 0x6C, 0x6C, 0x69, 0x6E, 0x74, 0x72, 0x66, 0xE2, 0x84,
+ 0xB3, 0x4D, 0x66, 0x72, 0xF0, 0x9D, 0x94, 0x90, 0x4D, 0x69, 0x6E, 0x75,
+ 0x73, 0x50, 0x6C, 0x75, 0x73, 0xE2, 0x88, 0x93, 0x4D, 0x6F, 0x70, 0x66,
+ 0xF0, 0x9D, 0x95, 0x84, 0x4D, 0x73, 0x63, 0x72, 0xE2, 0x84, 0xB3, 0x4D,
+ 0x75, 0xCE, 0x9C, 0x4E, 0x4A, 0x63, 0x79, 0xD0, 0x8A, 0x4E, 0x61, 0x63,
+ 0x75, 0x74, 0x65, 0xC5, 0x83, 0x4E, 0x63, 0x61, 0x72, 0x6F, 0x6E, 0xC5,
+ 0x87, 0x4E, 0x63, 0x65, 0x64, 0x69, 0x6C, 0xC5, 0x85, 0x4E, 0x63, 0x79,
+ 0xD0, 0x9D, 0x4E, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x4D, 0x65,
+ 0x64, 0x69, 0x75, 0x6D, 0x53, 0x70, 0x61, 0x63, 0x65, 0xE2, 0x80, 0x8B,
+ 0x4E, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x54, 0x68, 0x69, 0x63,
+ 0x6B, 0x53, 0x70, 0x61, 0x63, 0x65, 0xE2, 0x80, 0x8B, 0x4E, 0x65, 0x67,
+ 0x61, 0x74, 0x69, 0x76, 0x65, 0x54, 0x68, 0x69, 0x6E, 0x53, 0x70, 0x61,
+ 0x63, 0x65, 0xE2, 0x80, 0x8B, 0x4E, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76,
+ 0x65, 0x56, 0x65, 0x72, 0x79, 0x54, 0x68, 0x69, 0x6E, 0x53, 0x70, 0x61,
+ 0x63, 0x65, 0xE2, 0x80, 0x8B, 0x4E, 0x65, 0x73, 0x74, 0x65, 0x64, 0x47,
+ 0x72, 0x65, 0x61, 0x74, 0x65, 0x72, 0x47, 0x72, 0x65, 0x61, 0x74, 0x65,
+ 0x72, 0xE2, 0x89, 0xAB, 0x4E, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4C, 0x65,
+ 0x73, 0x73, 0x4C, 0x65, 0x73, 0x73, 0xE2, 0x89, 0xAA, 0x4E, 0x65, 0x77,
+ 0x4C, 0x69, 0x6E, 0x65, 0x0A, 0x4E, 0x66, 0x72, 0xF0, 0x9D, 0x94, 0x91,
+ 0x4E, 0x6F, 0x42, 0x72, 0x65, 0x61, 0x6B, 0xE2, 0x81, 0xA0, 0x4E, 0x6F,
+ 0x6E, 0x42, 0x72, 0x65, 0x61, 0x6B, 0x69, 0x6E, 0x67, 0x53, 0x70, 0x61,
+ 0x63, 0x65, 0xC2, 0xA0, 0x4E, 0x6F, 0x70, 0x66, 0xE2, 0x84, 0x95, 0x4E,
+ 0x6F, 0x74, 0xE2, 0xAB, 0xAC, 0x4E, 0x6F, 0x74, 0x43, 0x6F, 0x6E, 0x67,
+ 0x72, 0x75, 0x65, 0x6E, 0x74, 0xE2, 0x89, 0xA2, 0x4E, 0x6F, 0x74, 0x43,
+ 0x75, 0x70, 0x43, 0x61, 0x70, 0xE2, 0x89, 0xAD, 0x4E, 0x6F, 0x74, 0x44,
+ 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x56, 0x65, 0x72, 0x74, 0x69, 0x63, 0x61,
+ 0x6C, 0x42, 0x61, 0x72, 0xE2, 0x88, 0xA6, 0x4E, 0x6F, 0x74, 0x45, 0x6C,
+ 0x65, 0x6D, 0x65, 0x6E, 0x74, 0xE2, 0x88, 0x89, 0x4E, 0x6F, 0x74, 0x45,
+ 0x71, 0x75, 0x61, 0x6C, 0xE2, 0x89, 0xA0, 0x4E, 0x6F, 0x74, 0x45, 0x71,
+ 0x75, 0x61, 0x6C, 0x54, 0x69, 0x6C, 0x64, 0x65, 0xE2, 0x89, 0x82, 0xCC,
+ 0xB8, 0x4E, 0x6F, 0x74, 0x45, 0x78, 0x69, 0x73, 0x74, 0x73, 0xE2, 0x88,
+ 0x84, 0x4E, 0x6F, 0x74, 0x47, 0x72, 0x65, 0x61, 0x74, 0x65, 0x72, 0xE2,
+ 0x89, 0xAF, 0x4E, 0x6F, 0x74, 0x47, 0x72, 0x65, 0x61, 0x74, 0x65, 0x72,
+ 0x45, 0x71, 0x75, 0x61, 0x6C, 0xE2, 0x89, 0xB1, 0x4E, 0x6F, 0x74, 0x47,
+ 0x72, 0x65, 0x61, 0x74, 0x65, 0x72, 0x46, 0x75, 0x6C, 0x6C, 0x45, 0x71,
+ 0x75, 0x61, 0x6C, 0xE2, 0x89, 0xA7, 0xCC, 0xB8, 0x4E, 0x6F, 0x74, 0x47,
+ 0x72, 0x65, 0x61, 0x74, 0x65, 0x72, 0x47, 0x72, 0x65, 0x61, 0x74, 0x65,
+ 0x72, 0xE2, 0x89, 0xAB, 0xCC, 0xB8, 0x4E, 0x6F, 0x74, 0x47, 0x72, 0x65,
+ 0x61, 0x74, 0x65, 0x72, 0x4C, 0x65, 0x73, 0x73, 0xE2, 0x89, 0xB9, 0x4E,
+ 0x6F, 0x74, 0x47, 0x72, 0x65, 0x61, 0x74, 0x65, 0x72, 0x53, 0x6C, 0x61,
+ 0x6E, 0x74, 0x45, 0x71, 0x75, 0x61, 0x6C, 0xE2, 0xA9, 0xBE, 0xCC, 0xB8,
+ 0x4E, 0x6F, 0x74, 0x47, 0x72, 0x65, 0x61, 0x74, 0x65, 0x72, 0x54, 0x69,
+ 0x6C, 0x64, 0x65, 0xE2, 0x89, 0xB5, 0x4E, 0x6F, 0x74, 0x48, 0x75, 0x6D,
+ 0x70, 0x44, 0x6F, 0x77, 0x6E, 0x48, 0x75, 0x6D, 0x70, 0xE2, 0x89, 0x8E,
+ 0xCC, 0xB8, 0x4E, 0x6F, 0x74, 0x48, 0x75, 0x6D, 0x70, 0x45, 0x71, 0x75,
+ 0x61, 0x6C, 0xE2, 0x89, 0x8F, 0xCC, 0xB8, 0x4E, 0x6F, 0x74, 0x4C, 0x65,
+ 0x66, 0x74, 0x54, 0x72, 0x69, 0x61, 0x6E, 0x67, 0x6C, 0x65, 0xE2, 0x8B,
+ 0xAA, 0x4E, 0x6F, 0x74, 0x4C, 0x65, 0x66, 0x74, 0x54, 0x72, 0x69, 0x61,
+ 0x6E, 0x67, 0x6C, 0x65, 0x42, 0x61, 0x72, 0xE2, 0xA7, 0x8F, 0xCC, 0xB8,
+ 0x4E, 0x6F, 0x74, 0x4C, 0x65, 0x66, 0x74, 0x54, 0x72, 0x69, 0x61, 0x6E,
+ 0x67, 0x6C, 0x65, 0x45, 0x71, 0x75, 0x61, 0x6C, 0xE2, 0x8B, 0xAC, 0x4E,
+ 0x6F, 0x74, 0x4C, 0x65, 0x73, 0x73, 0xE2, 0x89, 0xAE, 0x4E, 0x6F, 0x74,
+ 0x4C, 0x65, 0x73, 0x73, 0x45, 0x71, 0x75, 0x61, 0x6C, 0xE2, 0x89, 0xB0,
+ 0x4E, 0x6F, 0x74, 0x4C, 0x65, 0x73, 0x73, 0x47, 0x72, 0x65, 0x61, 0x74,
+ 0x65, 0x72, 0xE2, 0x89, 0xB8, 0x4E, 0x6F, 0x74, 0x4C, 0x65, 0x73, 0x73,
+ 0x4C, 0x65, 0x73, 0x73, 0xE2, 0x89, 0xAA, 0xCC, 0xB8, 0x4E, 0x6F, 0x74,
+ 0x4C, 0x65, 0x73, 0x73, 0x53, 0x6C, 0x61, 0x6E, 0x74, 0x45, 0x71, 0x75,
+ 0x61, 0x6C, 0xE2, 0xA9, 0xBD, 0xCC, 0xB8, 0x4E, 0x6F, 0x74, 0x4C, 0x65,
+ 0x73, 0x73, 0x54, 0x69, 0x6C, 0x64, 0x65, 0xE2, 0x89, 0xB4, 0x4E, 0x6F,
+ 0x74, 0x4E, 0x65, 0x73, 0x74, 0x65, 0x64, 0x47, 0x72, 0x65, 0x61, 0x74,
+ 0x65, 0x72, 0x47, 0x72, 0x65, 0x61, 0x74, 0x65, 0x72, 0xE2, 0xAA, 0xA2,
+ 0xCC, 0xB8, 0x4E, 0x6F, 0x74, 0x4E, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4C,
+ 0x65, 0x73, 0x73, 0x4C, 0x65, 0x73, 0x73, 0xE2, 0xAA, 0xA1, 0xCC, 0xB8,
+ 0x4E, 0x6F, 0x74, 0x50, 0x72, 0x65, 0x63, 0x65, 0x64, 0x65, 0x73, 0xE2,
+ 0x8A, 0x80, 0x4E, 0x6F, 0x74, 0x50, 0x72, 0x65, 0x63, 0x65, 0x64, 0x65,
+ 0x73, 0x45, 0x71, 0x75, 0x61, 0x6C, 0xE2, 0xAA, 0xAF, 0xCC, 0xB8, 0x4E,
+ 0x6F, 0x74, 0x50, 0x72, 0x65, 0x63, 0x65, 0x64, 0x65, 0x73, 0x53, 0x6C,
+ 0x61, 0x6E, 0x74, 0x45, 0x71, 0x75, 0x61, 0x6C, 0xE2, 0x8B, 0xA0, 0x4E,
+ 0x6F, 0x74, 0x52, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x45, 0x6C, 0x65,
+ 0x6D, 0x65, 0x6E, 0x74, 0xE2, 0x88, 0x8C, 0x4E, 0x6F, 0x74, 0x52, 0x69,
+ 0x67, 0x68, 0x74, 0x54, 0x72, 0x69, 0x61, 0x6E, 0x67, 0x6C, 0x65, 0xE2,
+ 0x8B, 0xAB, 0x4E, 0x6F, 0x74, 0x52, 0x69, 0x67, 0x68, 0x74, 0x54, 0x72,
+ 0x69, 0x61, 0x6E, 0x67, 0x6C, 0x65, 0x42, 0x61, 0x72, 0xE2, 0xA7, 0x90,
+ 0xCC, 0xB8, 0x4E, 0x6F, 0x74, 0x52, 0x69, 0x67, 0x68, 0x74, 0x54, 0x72,
+ 0x69, 0x61, 0x6E, 0x67, 0x6C, 0x65, 0x45, 0x71, 0x75, 0x61, 0x6C, 0xE2,
+ 0x8B, 0xAD, 0x4E, 0x6F, 0x74, 0x53, 0x71, 0x75, 0x61, 0x72, 0x65, 0x53,
+ 0x75, 0x62, 0x73, 0x65, 0x74, 0xE2, 0x8A, 0x8F, 0xCC, 0xB8, 0x4E, 0x6F,
+ 0x74, 0x53, 0x71, 0x75, 0x61, 0x72, 0x65, 0x53, 0x75, 0x62, 0x73, 0x65,
+ 0x74, 0x45, 0x71, 0x75, 0x61, 0x6C, 0xE2, 0x8B, 0xA2, 0x4E, 0x6F, 0x74,
+ 0x53, 0x71, 0x75, 0x61, 0x72, 0x65, 0x53, 0x75, 0x70, 0x65, 0x72, 0x73,
+ 0x65, 0x74, 0xE2, 0x8A, 0x90, 0xCC, 0xB8, 0x4E, 0x6F, 0x74, 0x53, 0x71,
+ 0x75, 0x61, 0x72, 0x65, 0x53, 0x75, 0x70, 0x65, 0x72, 0x73, 0x65, 0x74,
+ 0x45, 0x71, 0x75, 0x61, 0x6C, 0xE2, 0x8B, 0xA3, 0x4E, 0x6F, 0x74, 0x53,
+ 0x75, 0x62, 0x73, 0x65, 0x74, 0xE2, 0x8A, 0x82, 0xE2, 0x83, 0x92, 0x4E,
+ 0x6F, 0x74, 0x53, 0x75, 0x62, 0x73, 0x65, 0x74, 0x45, 0x71, 0x75, 0x61,
+ 0x6C, 0xE2, 0x8A, 0x88, 0x4E, 0x6F, 0x74, 0x53, 0x75, 0x63, 0x63, 0x65,
+ 0x65, 0x64, 0x73, 0xE2, 0x8A, 0x81, 0x4E, 0x6F, 0x74, 0x53, 0x75, 0x63,
+ 0x63, 0x65, 0x65, 0x64, 0x73, 0x45, 0x71, 0x75, 0x61, 0x6C, 0xE2, 0xAA,
+ 0xB0, 0xCC, 0xB8, 0x4E, 0x6F, 0x74, 0x53, 0x75, 0x63, 0x63, 0x65, 0x65,
+ 0x64, 0x73, 0x53, 0x6C, 0x61, 0x6E, 0x74, 0x45, 0x71, 0x75, 0x61, 0x6C,
+ 0xE2, 0x8B, 0xA1, 0x4E, 0x6F, 0x74, 0x53, 0x75, 0x63, 0x63, 0x65, 0x65,
+ 0x64, 0x73, 0x54, 0x69, 0x6C, 0x64, 0x65, 0xE2, 0x89, 0xBF, 0xCC, 0xB8,
+ 0x4E, 0x6F, 0x74, 0x53, 0x75, 0x70, 0x65, 0x72, 0x73, 0x65, 0x74, 0xE2,
+ 0x8A, 0x83, 0xE2, 0x83, 0x92, 0x4E, 0x6F, 0x74, 0x53, 0x75, 0x70, 0x65,
+ 0x72, 0x73, 0x65, 0x74, 0x45, 0x71, 0x75, 0x61, 0x6C, 0xE2, 0x8A, 0x89,
+ 0x4E, 0x6F, 0x74, 0x54, 0x69, 0x6C, 0x64, 0x65, 0xE2, 0x89, 0x81, 0x4E,
+ 0x6F, 0x74, 0x54, 0x69, 0x6C, 0x64, 0x65, 0x45, 0x71, 0x75, 0x61, 0x6C,
+ 0xE2, 0x89, 0x84, 0x4E, 0x6F, 0x74, 0x54, 0x69, 0x6C, 0x64, 0x65, 0x46,
+ 0x75, 0x6C, 0x6C, 0x45, 0x71, 0x75, 0x61, 0x6C, 0xE2, 0x89, 0x87, 0x4E,
+ 0x6F, 0x74, 0x54, 0x69, 0x6C, 0x64, 0x65, 0x54, 0x69, 0x6C, 0x64, 0x65,
+ 0xE2, 0x89, 0x89, 0x4E, 0x6F, 0x74, 0x56, 0x65, 0x72, 0x74, 0x69, 0x63,
+ 0x61, 0x6C, 0x42, 0x61, 0x72, 0xE2, 0x88, 0xA4, 0x4E, 0x73, 0x63, 0x72,
+ 0xF0, 0x9D, 0x92, 0xA9, 0x4E, 0x74, 0x69, 0x6C, 0x64, 0x65, 0xC3, 0x91,
+ 0x4E, 0x75, 0xCE, 0x9D, 0x4F, 0x45, 0x6C, 0x69, 0x67, 0xC5, 0x92, 0x4F,
+ 0x61, 0x63, 0x75, 0x74, 0x65, 0xC3, 0x93, 0x4F, 0x63, 0x69, 0x72, 0x63,
+ 0xC3, 0x94, 0x4F, 0x63, 0x79, 0xD0, 0x9E, 0x4F, 0x64, 0x62, 0x6C, 0x61,
+ 0x63, 0xC5, 0x90, 0x4F, 0x66, 0x72, 0xF0, 0x9D, 0x94, 0x92, 0x4F, 0x67,
+ 0x72, 0x61, 0x76, 0x65, 0xC3, 0x92, 0x4F, 0x6D, 0x61, 0x63, 0x72, 0xC5,
+ 0x8C, 0x4F, 0x6D, 0x65, 0x67, 0x61, 0xCE, 0xA9, 0x4F, 0x6D, 0x69, 0x63,
+ 0x72, 0x6F, 0x6E, 0xCE, 0x9F, 0x4F, 0x6F, 0x70, 0x66, 0xF0, 0x9D, 0x95,
+ 0x86, 0x4F, 0x70, 0x65, 0x6E, 0x43, 0x75, 0x72, 0x6C, 0x79, 0x44, 0x6F,
+ 0x75, 0x62, 0x6C, 0x65, 0x51, 0x75, 0x6F, 0x74, 0x65, 0xE2, 0x80, 0x9C,
+ 0x4F, 0x70, 0x65, 0x6E, 0x43, 0x75, 0x72, 0x6C, 0x79, 0x51, 0x75, 0x6F,
+ 0x74, 0x65, 0xE2, 0x80, 0x98, 0x4F, 0x72, 0xE2, 0xA9, 0x94, 0x4F, 0x73,
+ 0x63, 0x72, 0xF0, 0x9D, 0x92, 0xAA, 0x4F, 0x73, 0x6C, 0x61, 0x73, 0x68,
+ 0xC3, 0x98, 0x4F, 0x74, 0x69, 0x6C, 0x64, 0x65, 0xC3, 0x95, 0x4F, 0x74,
+ 0x69, 0x6D, 0x65, 0x73, 0xE2, 0xA8, 0xB7, 0x4F, 0x75, 0x6D, 0x6C, 0xC3,
+ 0x96, 0x4F, 0x76, 0x65, 0x72, 0x42, 0x61, 0x72, 0xE2, 0x80, 0xBE, 0x4F,
+ 0x76, 0x65, 0x72, 0x42, 0x72, 0x61, 0x63, 0x65, 0xE2, 0x8F, 0x9E, 0x4F,
+ 0x76, 0x65, 0x72, 0x42, 0x72, 0x61, 0x63, 0x6B, 0x65, 0x74, 0xE2, 0x8E,
+ 0xB4, 0x4F, 0x76, 0x65, 0x72, 0x50, 0x61, 0x72, 0x65, 0x6E, 0x74, 0x68,
+ 0x65, 0x73, 0x69, 0x73, 0xE2, 0x8F, 0x9C, 0x50, 0x61, 0x72, 0x74, 0x69,
+ 0x61, 0x6C, 0x44, 0xE2, 0x88, 0x82, 0x50, 0x63, 0x79, 0xD0, 0x9F, 0x50,
+ 0x66, 0x72, 0xF0, 0x9D, 0x94, 0x93, 0x50, 0x68, 0x69, 0xCE, 0xA6, 0x50,
+ 0x69, 0xCE, 0xA0, 0x50, 0x6C, 0x75, 0x73, 0x4D, 0x69, 0x6E, 0x75, 0x73,
+ 0xC2, 0xB1, 0x50, 0x6F, 0x69, 0x6E, 0x63, 0x61, 0x72, 0x65, 0x70, 0x6C,
+ 0x61, 0x6E, 0x65, 0xE2, 0x84, 0x8C, 0x50, 0x6F, 0x70, 0x66, 0xE2, 0x84,
+ 0x99, 0x50, 0x72, 0xE2, 0xAA, 0xBB, 0x50, 0x72, 0x65, 0x63, 0x65, 0x64,
+ 0x65, 0x73, 0xE2, 0x89, 0xBA, 0x50, 0x72, 0x65, 0x63, 0x65, 0x64, 0x65,
+ 0x73, 0x45, 0x71, 0x75, 0x61, 0x6C, 0xE2, 0xAA, 0xAF, 0x50, 0x72, 0x65,
+ 0x63, 0x65, 0x64, 0x65, 0x73, 0x53, 0x6C, 0x61, 0x6E, 0x74, 0x45, 0x71,
+ 0x75, 0x61, 0x6C, 0xE2, 0x89, 0xBC, 0x50, 0x72, 0x65, 0x63, 0x65, 0x64,
+ 0x65, 0x73, 0x54, 0x69, 0x6C, 0x64, 0x65, 0xE2, 0x89, 0xBE, 0x50, 0x72,
+ 0x69, 0x6D, 0x65, 0xE2, 0x80, 0xB3, 0x50, 0x72, 0x6F, 0x64, 0x75, 0x63,
+ 0x74, 0xE2, 0x88, 0x8F, 0x50, 0x72, 0x6F, 0x70, 0x6F, 0x72, 0x74, 0x69,
+ 0x6F, 0x6E, 0xE2, 0x88, 0xB7, 0x50, 0x72, 0x6F, 0x70, 0x6F, 0x72, 0x74,
+ 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0xE2, 0x88, 0x9D, 0x50, 0x73, 0x63, 0x72,
+ 0xF0, 0x9D, 0x92, 0xAB, 0x50, 0x73, 0x69, 0xCE, 0xA8, 0x51, 0x55, 0x4F,
+ 0x54, 0x22, 0x51, 0x66, 0x72, 0xF0, 0x9D, 0x94, 0x94, 0x51, 0x6F, 0x70,
+ 0x66, 0xE2, 0x84, 0x9A, 0x51, 0x73, 0x63, 0x72, 0xF0, 0x9D, 0x92, 0xAC,
+ 0x52, 0x42, 0x61, 0x72, 0x72, 0xE2, 0xA4, 0x90, 0x52, 0x45, 0x47, 0xC2,
+ 0xAE, 0x52, 0x61, 0x63, 0x75, 0x74, 0x65, 0xC5, 0x94, 0x52, 0x61, 0x6E,
+ 0x67, 0xE2, 0x9F, 0xAB, 0x52, 0x61, 0x72, 0x72, 0xE2, 0x86, 0xA0, 0x52,
+ 0x61, 0x72, 0x72, 0x74, 0x6C, 0xE2, 0xA4, 0x96, 0x52, 0x63, 0x61, 0x72,
+ 0x6F, 0x6E, 0xC5, 0x98, 0x52, 0x63, 0x65, 0x64, 0x69, 0x6C, 0xC5, 0x96,
+ 0x52, 0x63, 0x79, 0xD0, 0xA0, 0x52, 0x65, 0xE2, 0x84, 0x9C, 0x52, 0x65,
+ 0x76, 0x65, 0x72, 0x73, 0x65, 0x45, 0x6C, 0x65, 0x6D, 0x65, 0x6E, 0x74,
+ 0xE2, 0x88, 0x8B, 0x52, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x45, 0x71,
+ 0x75, 0x69, 0x6C, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6D, 0xE2, 0x87, 0x8B,
+ 0x52, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x55, 0x70, 0x45, 0x71, 0x75,
+ 0x69, 0x6C, 0x69, 0x62, 0x72, 0x69, 0x75, 0x6D, 0xE2, 0xA5, 0xAF, 0x52,
+ 0x66, 0x72, 0xE2, 0x84, 0x9C, 0x52, 0x68, 0x6F, 0xCE, 0xA1, 0x52, 0x69,
+ 0x67, 0x68, 0x74, 0x41, 0x6E, 0x67, 0x6C, 0x65, 0x42, 0x72, 0x61, 0x63,
+ 0x6B, 0x65, 0x74, 0xE2, 0x9F, 0xA9, 0x52, 0x69, 0x67, 0x68, 0x74, 0x41,
+ 0x72, 0x72, 0x6F, 0x77, 0xE2, 0x86, 0x92, 0x52, 0x69, 0x67, 0x68, 0x74,
+ 0x41, 0x72, 0x72, 0x6F, 0x77, 0x42, 0x61, 0x72, 0xE2, 0x87, 0xA5, 0x52,
+ 0x69, 0x67, 0x68, 0x74, 0x41, 0x72, 0x72, 0x6F, 0x77, 0x4C, 0x65, 0x66,
+ 0x74, 0x41, 0x72, 0x72, 0x6F, 0x77, 0xE2, 0x87, 0x84, 0x52, 0x69, 0x67,
+ 0x68, 0x74, 0x43, 0x65, 0x69, 0x6C, 0x69, 0x6E, 0x67, 0xE2, 0x8C, 0x89,
+ 0x52, 0x69, 0x67, 0x68, 0x74, 0x44, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x42,
+ 0x72, 0x61, 0x63, 0x6B, 0x65, 0x74, 0xE2, 0x9F, 0xA7, 0x52, 0x69, 0x67,
+ 0x68, 0x74, 0x44, 0x6F, 0x77, 0x6E, 0x54, 0x65, 0x65, 0x56, 0x65, 0x63,
+ 0x74, 0x6F, 0x72, 0xE2, 0xA5, 0x9D, 0x52, 0x69, 0x67, 0x68, 0x74, 0x44,
+ 0x6F, 0x77, 0x6E, 0x56, 0x65, 0x63, 0x74, 0x6F, 0x72, 0xE2, 0x87, 0x82,
+ 0x52, 0x69, 0x67, 0x68, 0x74, 0x44, 0x6F, 0x77, 0x6E, 0x56, 0x65, 0x63,
+ 0x74, 0x6F, 0x72, 0x42, 0x61, 0x72, 0xE2, 0xA5, 0x95, 0x52, 0x69, 0x67,
+ 0x68, 0x74, 0x46, 0x6C, 0x6F, 0x6F, 0x72, 0xE2, 0x8C, 0x8B, 0x52, 0x69,
+ 0x67, 0x68, 0x74, 0x54, 0x65, 0x65, 0xE2, 0x8A, 0xA2, 0x52, 0x69, 0x67,
+ 0x68, 0x74, 0x54, 0x65, 0x65, 0x41, 0x72, 0x72, 0x6F, 0x77, 0xE2, 0x86,
+ 0xA6, 0x52, 0x69, 0x67, 0x68, 0x74, 0x54, 0x65, 0x65, 0x56, 0x65, 0x63,
+ 0x74, 0x6F, 0x72, 0xE2, 0xA5, 0x9B, 0x52, 0x69, 0x67, 0x68, 0x74, 0x54,
+ 0x72, 0x69, 0x61, 0x6E, 0x67, 0x6C, 0x65, 0xE2, 0x8A, 0xB3, 0x52, 0x69,
+ 0x67, 0x68, 0x74, 0x54, 0x72, 0x69, 0x61, 0x6E, 0x67, 0x6C, 0x65, 0x42,
+ 0x61, 0x72, 0xE2, 0xA7, 0x90, 0x52, 0x69, 0x67, 0x68, 0x74, 0x54, 0x72,
+ 0x69, 0x61, 0x6E, 0x67, 0x6C, 0x65, 0x45, 0x71, 0x75, 0x61, 0x6C, 0xE2,
+ 0x8A, 0xB5, 0x52, 0x69, 0x67, 0x68, 0x74, 0x55, 0x70, 0x44, 0x6F, 0x77,
+ 0x6E, 0x56, 0x65, 0x63, 0x74, 0x6F, 0x72, 0xE2, 0xA5, 0x8F, 0x52, 0x69,
+ 0x67, 0x68, 0x74, 0x55, 0x70, 0x54, 0x65, 0x65, 0x56, 0x65, 0x63, 0x74,
+ 0x6F, 0x72, 0xE2, 0xA5, 0x9C, 0x52, 0x69, 0x67, 0x68, 0x74, 0x55, 0x70,
+ 0x56, 0x65, 0x63, 0x74, 0x6F, 0x72, 0xE2, 0x86, 0xBE, 0x52, 0x69, 0x67,
+ 0x68, 0x74, 0x55, 0x70, 0x56, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x42, 0x61,
+ 0x72, 0xE2, 0xA5, 0x94, 0x52, 0x69, 0x67, 0x68, 0x74, 0x56, 0x65, 0x63,
+ 0x74, 0x6F, 0x72, 0xE2, 0x87, 0x80, 0x52, 0x69, 0x67, 0x68, 0x74, 0x56,
+ 0x65, 0x63, 0x74, 0x6F, 0x72, 0x42, 0x61, 0x72, 0xE2, 0xA5, 0x93, 0x52,
+ 0x69, 0x67, 0x68, 0x74, 0x61, 0x72, 0x72, 0x6F, 0x77, 0xE2, 0x87, 0x92,
+ 0x52, 0x6F, 0x70, 0x66, 0xE2, 0x84, 0x9D, 0x52, 0x6F, 0x75, 0x6E, 0x64,
+ 0x49, 0x6D, 0x70, 0x6C, 0x69, 0x65, 0x73, 0xE2, 0xA5, 0xB0, 0x52, 0x72,
+ 0x69, 0x67, 0x68, 0x74, 0x61, 0x72, 0x72, 0x6F, 0x77, 0xE2, 0x87, 0x9B,
+ 0x52, 0x73, 0x63, 0x72, 0xE2, 0x84, 0x9B, 0x52, 0x73, 0x68, 0xE2, 0x86,
+ 0xB1, 0x52, 0x75, 0x6C, 0x65, 0x44, 0x65, 0x6C, 0x61, 0x79, 0x65, 0x64,
+ 0xE2, 0xA7, 0xB4, 0x53, 0x48, 0x43, 0x48, 0x63, 0x79, 0xD0, 0xA9, 0x53,
+ 0x48, 0x63, 0x79, 0xD0, 0xA8, 0x53, 0x4F, 0x46, 0x54, 0x63, 0x79, 0xD0,
+ 0xAC, 0x53, 0x61, 0x63, 0x75, 0x74, 0x65, 0xC5, 0x9A, 0x53, 0x63, 0xE2,
+ 0xAA, 0xBC, 0x53, 0x63, 0x61, 0x72, 0x6F, 0x6E, 0xC5, 0xA0, 0x53, 0x63,
+ 0x65, 0x64, 0x69, 0x6C, 0xC5, 0x9E, 0x53, 0x63, 0x69, 0x72, 0x63, 0xC5,
+ 0x9C, 0x53, 0x63, 0x79, 0xD0, 0xA1, 0x53, 0x66, 0x72, 0xF0, 0x9D, 0x94,
+ 0x96, 0x53, 0x68, 0x6F, 0x72, 0x74, 0x44, 0x6F, 0x77, 0x6E, 0x41, 0x72,
+ 0x72, 0x6F, 0x77, 0xE2, 0x86, 0x93, 0x53, 0x68, 0x6F, 0x72, 0x74, 0x4C,
+ 0x65, 0x66, 0x74, 0x41, 0x72, 0x72, 0x6F, 0x77, 0xE2, 0x86, 0x90, 0x53,
+ 0x68, 0x6F, 0x72, 0x74, 0x52, 0x69, 0x67, 0x68, 0x74, 0x41, 0x72, 0x72,
+ 0x6F, 0x77, 0xE2, 0x86, 0x92, 0x53, 0x68, 0x6F, 0x72, 0x74, 0x55, 0x70,
+ 0x41, 0x72, 0x72, 0x6F, 0x77, 0xE2, 0x86, 0x91, 0x53, 0x69, 0x67, 0x6D,
+ 0x61, 0xCE, 0xA3, 0x53, 0x6D, 0x61, 0x6C, 0x6C, 0x43, 0x69, 0x72, 0x63,
+ 0x6C, 0x65, 0xE2, 0x88, 0x98, 0x53, 0x6F, 0x70, 0x66, 0xF0, 0x9D, 0x95,
+ 0x8A, 0x53, 0x71, 0x72, 0x74, 0xE2, 0x88, 0x9A, 0x53, 0x71, 0x75, 0x61,
+ 0x72, 0x65, 0xE2, 0x96, 0xA1, 0x53, 0x71, 0x75, 0x61, 0x72, 0x65, 0x49,
+ 0x6E, 0x74, 0x65, 0x72, 0x73, 0x65, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0xE2,
+ 0x8A, 0x93, 0x53, 0x71, 0x75, 0x61, 0x72, 0x65, 0x53, 0x75, 0x62, 0x73,
+ 0x65, 0x74, 0xE2, 0x8A, 0x8F, 0x53, 0x71, 0x75, 0x61, 0x72, 0x65, 0x53,
+ 0x75, 0x62, 0x73, 0x65, 0x74, 0x45, 0x71, 0x75, 0x61, 0x6C, 0xE2, 0x8A,
+ 0x91, 0x53, 0x71, 0x75, 0x61, 0x72, 0x65, 0x53, 0x75, 0x70, 0x65, 0x72,
+ 0x73, 0x65, 0x74, 0xE2, 0x8A, 0x90, 0x53, 0x71, 0x75, 0x61, 0x72, 0x65,
+ 0x53, 0x75, 0x70, 0x65, 0x72, 0x73, 0x65, 0x74, 0x45, 0x71, 0x75, 0x61,
+ 0x6C, 0xE2, 0x8A, 0x92, 0x53, 0x71, 0x75, 0x61, 0x72, 0x65, 0x55, 0x6E,
+ 0x69, 0x6F, 0x6E, 0xE2, 0x8A, 0x94, 0x53, 0x73, 0x63, 0x72, 0xF0, 0x9D,
+ 0x92, 0xAE, 0x53, 0x74, 0x61, 0x72, 0xE2, 0x8B, 0x86, 0x53, 0x75, 0x62,
+ 0xE2, 0x8B, 0x90, 0x53, 0x75, 0x62, 0x73, 0x65, 0x74, 0xE2, 0x8B, 0x90,
+ 0x53, 0x75, 0x62, 0x73, 0x65, 0x74, 0x45, 0x71, 0x75, 0x61, 0x6C, 0xE2,
+ 0x8A, 0x86, 0x53, 0x75, 0x63, 0x63, 0x65, 0x65, 0x64, 0x73, 0xE2, 0x89,
+ 0xBB, 0x53, 0x75, 0x63, 0x63, 0x65, 0x65, 0x64, 0x73, 0x45, 0x71, 0x75,
+ 0x61, 0x6C, 0xE2, 0xAA, 0xB0, 0x53, 0x75, 0x63, 0x63, 0x65, 0x65, 0x64,
+ 0x73, 0x53, 0x6C, 0x61, 0x6E, 0x74, 0x45, 0x71, 0x75, 0x61, 0x6C, 0xE2,
+ 0x89, 0xBD, 0x53, 0x75, 0x63, 0x63, 0x65, 0x65, 0x64, 0x73, 0x54, 0x69,
+ 0x6C, 0x64, 0x65, 0xE2, 0x89, 0xBF, 0x53, 0x75, 0x63, 0x68, 0x54, 0x68,
+ 0x61, 0x74, 0xE2, 0x88, 0x8B, 0x53, 0x75, 0x6D, 0xE2, 0x88, 0x91, 0x53,
+ 0x75, 0x70, 0xE2, 0x8B, 0x91, 0x53, 0x75, 0x70, 0x65, 0x72, 0x73, 0x65,
+ 0x74, 0xE2, 0x8A, 0x83, 0x53, 0x75, 0x70, 0x65, 0x72, 0x73, 0x65, 0x74,
+ 0x45, 0x71, 0x75, 0x61, 0x6C, 0xE2, 0x8A, 0x87, 0x53, 0x75, 0x70, 0x73,
+ 0x65, 0x74, 0xE2, 0x8B, 0x91, 0x54, 0x48, 0x4F, 0x52, 0x4E, 0xC3, 0x9E,
+ 0x54, 0x52, 0x41, 0x44, 0x45, 0xE2, 0x84, 0xA2, 0x54, 0x53, 0x48, 0x63,
+ 0x79, 0xD0, 0x8B, 0x54, 0x53, 0x63, 0x79, 0xD0, 0xA6, 0x54, 0x61, 0x62,
+ 0x09, 0x54, 0x61, 0x75, 0xCE, 0xA4, 0x54, 0x63, 0x61, 0x72, 0x6F, 0x6E,
+ 0xC5, 0xA4, 0x54, 0x63, 0x65, 0x64, 0x69, 0x6C, 0xC5, 0xA2, 0x54, 0x63,
+ 0x79, 0xD0, 0xA2, 0x54, 0x66, 0x72, 0xF0, 0x9D, 0x94, 0x97, 0x54, 0x68,
+ 0x65, 0x72, 0x65, 0x66, 0x6F, 0x72, 0x65, 0xE2, 0x88, 0xB4, 0x54, 0x68,
+ 0x65, 0x74, 0x61, 0xCE, 0x98, 0x54, 0x68, 0x69, 0x63, 0x6B, 0x53, 0x70,
+ 0x61, 0x63, 0x65, 0xE2, 0x81, 0x9F, 0xE2, 0x80, 0x8A, 0x54, 0x68, 0x69,
+ 0x6E, 0x53, 0x70, 0x61, 0x63, 0x65, 0xE2, 0x80, 0x89, 0x54, 0x69, 0x6C,
+ 0x64, 0x65, 0xE2, 0x88, 0xBC, 0x54, 0x69, 0x6C, 0x64, 0x65, 0x45, 0x71,
+ 0x75, 0x61, 0x6C, 0xE2, 0x89, 0x83, 0x54, 0x69, 0x6C, 0x64, 0x65, 0x46,
+ 0x75, 0x6C, 0x6C, 0x45, 0x71, 0x75, 0x61, 0x6C, 0xE2, 0x89, 0x85, 0x54,
+ 0x69, 0x6C, 0x64, 0x65, 0x54, 0x69, 0x6C, 0x64, 0x65, 0xE2, 0x89, 0x88,
+ 0x54, 0x6F, 0x70, 0x66, 0xF0, 0x9D, 0x95, 0x8B, 0x54, 0x72, 0x69, 0x70,
+ 0x6C, 0x65, 0x44, 0x6F, 0x74, 0xE2, 0x83, 0x9B, 0x54, 0x73, 0x63, 0x72,
+ 0xF0, 0x9D, 0x92, 0xAF, 0x54, 0x73, 0x74, 0x72, 0x6F, 0x6B, 0xC5, 0xA6,
+ 0x55, 0x61, 0x63, 0x75, 0x74, 0x65, 0xC3, 0x9A, 0x55, 0x61, 0x72, 0x72,
+ 0xE2, 0x86, 0x9F, 0x55, 0x61, 0x72, 0x72, 0x6F, 0x63, 0x69, 0x72, 0xE2,
+ 0xA5, 0x89, 0x55, 0x62, 0x72, 0x63, 0x79, 0xD0, 0x8E, 0x55, 0x62, 0x72,
+ 0x65, 0x76, 0x65, 0xC5, 0xAC, 0x55, 0x63, 0x69, 0x72, 0x63, 0xC3, 0x9B,
+ 0x55, 0x63, 0x79, 0xD0, 0xA3, 0x55, 0x64, 0x62, 0x6C, 0x61, 0x63, 0xC5,
+ 0xB0, 0x55, 0x66, 0x72, 0xF0, 0x9D, 0x94, 0x98, 0x55, 0x67, 0x72, 0x61,
+ 0x76, 0x65, 0xC3, 0x99, 0x55, 0x6D, 0x61, 0x63, 0x72, 0xC5, 0xAA, 0x55,
+ 0x6E, 0x64, 0x65, 0x72, 0x42, 0x61, 0x72, 0x5F, 0x55, 0x6E, 0x64, 0x65,
+ 0x72, 0x42, 0x72, 0x61, 0x63, 0x65, 0xE2, 0x8F, 0x9F, 0x55, 0x6E, 0x64,
+ 0x65, 0x72, 0x42, 0x72, 0x61, 0x63, 0x6B, 0x65, 0x74, 0xE2, 0x8E, 0xB5,
+ 0x55, 0x6E, 0x64, 0x65, 0x72, 0x50, 0x61, 0x72, 0x65, 0x6E, 0x74, 0x68,
+ 0x65, 0x73, 0x69, 0x73, 0xE2, 0x8F, 0x9D, 0x55, 0x6E, 0x69, 0x6F, 0x6E,
+ 0xE2, 0x8B, 0x83, 0x55, 0x6E, 0x69, 0x6F, 0x6E, 0x50, 0x6C, 0x75, 0x73,
+ 0xE2, 0x8A, 0x8E, 0x55, 0x6F, 0x67, 0x6F, 0x6E, 0xC5, 0xB2, 0x55, 0x6F,
+ 0x70, 0x66, 0xF0, 0x9D, 0x95, 0x8C, 0x55, 0x70, 0x41, 0x72, 0x72, 0x6F,
+ 0x77, 0xE2, 0x86, 0x91, 0x55, 0x70, 0x41, 0x72, 0x72, 0x6F, 0x77, 0x42,
+ 0x61, 0x72, 0xE2, 0xA4, 0x92, 0x55, 0x70, 0x41, 0x72, 0x72, 0x6F, 0x77,
+ 0x44, 0x6F, 0x77, 0x6E, 0x41, 0x72, 0x72, 0x6F, 0x77, 0xE2, 0x87, 0x85,
+ 0x55, 0x70, 0x44, 0x6F, 0x77, 0x6E, 0x41, 0x72, 0x72, 0x6F, 0x77, 0xE2,
+ 0x86, 0x95, 0x55, 0x70, 0x45, 0x71, 0x75, 0x69, 0x6C, 0x69, 0x62, 0x72,
+ 0x69, 0x75, 0x6D, 0xE2, 0xA5, 0xAE, 0x55, 0x70, 0x54, 0x65, 0x65, 0xE2,
+ 0x8A, 0xA5, 0x55, 0x70, 0x54, 0x65, 0x65, 0x41, 0x72, 0x72, 0x6F, 0x77,
+ 0xE2, 0x86, 0xA5, 0x55, 0x70, 0x61, 0x72, 0x72, 0x6F, 0x77, 0xE2, 0x87,
+ 0x91, 0x55, 0x70, 0x64, 0x6F, 0x77, 0x6E, 0x61, 0x72, 0x72, 0x6F, 0x77,
+ 0xE2, 0x87, 0x95, 0x55, 0x70, 0x70, 0x65, 0x72, 0x4C, 0x65, 0x66, 0x74,
+ 0x41, 0x72, 0x72, 0x6F, 0x77, 0xE2, 0x86, 0x96, 0x55, 0x70, 0x70, 0x65,
+ 0x72, 0x52, 0x69, 0x67, 0x68, 0x74, 0x41, 0x72, 0x72, 0x6F, 0x77, 0xE2,
+ 0x86, 0x97, 0x55, 0x70, 0x73, 0x69, 0xCF, 0x92, 0x55, 0x70, 0x73, 0x69,
+ 0x6C, 0x6F, 0x6E, 0xCE, 0xA5, 0x55, 0x72, 0x69, 0x6E, 0x67, 0xC5, 0xAE,
+ 0x55, 0x73, 0x63, 0x72, 0xF0, 0x9D, 0x92, 0xB0, 0x55, 0x74, 0x69, 0x6C,
+ 0x64, 0x65, 0xC5, 0xA8, 0x55, 0x75, 0x6D, 0x6C, 0xC3, 0x9C, 0x56, 0x44,
+ 0x61, 0x73, 0x68, 0xE2, 0x8A, 0xAB, 0x56, 0x62, 0x61, 0x72, 0xE2, 0xAB,
+ 0xAB, 0x56, 0x63, 0x79, 0xD0, 0x92, 0x56, 0x64, 0x61, 0x73, 0x68, 0xE2,
+ 0x8A, 0xA9, 0x56, 0x64, 0x61, 0x73, 0x68, 0x6C, 0xE2, 0xAB, 0xA6, 0x56,
+ 0x65, 0x65, 0xE2, 0x8B, 0x81, 0x56, 0x65, 0x72, 0x62, 0x61, 0x72, 0xE2,
+ 0x80, 0x96, 0x56, 0x65, 0x72, 0x74, 0xE2, 0x80, 0x96, 0x56, 0x65, 0x72,
+ 0x74, 0x69, 0x63, 0x61, 0x6C, 0x42, 0x61, 0x72, 0xE2, 0x88, 0xA3, 0x56,
+ 0x65, 0x72, 0x74, 0x69, 0x63, 0x61, 0x6C, 0x4C, 0x69, 0x6E, 0x65, 0x7C,
+ 0x56, 0x65, 0x72, 0x74, 0x69, 0x63, 0x61, 0x6C, 0x53, 0x65, 0x70, 0x61,
+ 0x72, 0x61, 0x74, 0x6F, 0x72, 0xE2, 0x9D, 0x98, 0x56, 0x65, 0x72, 0x74,
+ 0x69, 0x63, 0x61, 0x6C, 0x54, 0x69, 0x6C, 0x64, 0x65, 0xE2, 0x89, 0x80,
+ 0x56, 0x65, 0x72, 0x79, 0x54, 0x68, 0x69, 0x6E, 0x53, 0x70, 0x61, 0x63,
+ 0x65, 0xE2, 0x80, 0x8A, 0x56, 0x66, 0x72, 0xF0, 0x9D, 0x94, 0x99, 0x56,
+ 0x6F, 0x70, 0x66, 0xF0, 0x9D, 0x95, 0x8D, 0x56, 0x73, 0x63, 0x72, 0xF0,
+ 0x9D, 0x92, 0xB1, 0x56, 0x76, 0x64, 0x61, 0x73, 0x68, 0xE2, 0x8A, 0xAA,
+ 0x57, 0x63, 0x69, 0x72, 0x63, 0xC5, 0xB4, 0x57, 0x65, 0x64, 0x67, 0x65,
+ 0xE2, 0x8B, 0x80, 0x57, 0x66, 0x72, 0xF0, 0x9D, 0x94, 0x9A, 0x57, 0x6F,
+ 0x70, 0x66, 0xF0, 0x9D, 0x95, 0x8E, 0x57, 0x73, 0x63, 0x72, 0xF0, 0x9D,
+ 0x92, 0xB2, 0x58, 0x66, 0x72, 0xF0, 0x9D, 0x94, 0x9B, 0x58, 0x69, 0xCE,
+ 0x9E, 0x58, 0x6F, 0x70, 0x66, 0xF0, 0x9D, 0x95, 0x8F, 0x58, 0x73, 0x63,
+ 0x72, 0xF0, 0x9D, 0x92, 0xB3, 0x59, 0x41, 0x63, 0x79, 0xD0, 0xAF, 0x59,
+ 0x49, 0x63, 0x79, 0xD0, 0x87, 0x59, 0x55, 0x63, 0x79, 0xD0, 0xAE, 0x59,
+ 0x61, 0x63, 0x75, 0x74, 0x65, 0xC3, 0x9D, 0x59, 0x63, 0x69, 0x72, 0x63,
+ 0xC5, 0xB6, 0x59, 0x63, 0x79, 0xD0, 0xAB, 0x59, 0x66, 0x72, 0xF0, 0x9D,
+ 0x94, 0x9C, 0x59, 0x6F, 0x70, 0x66, 0xF0, 0x9D, 0x95, 0x90, 0x59, 0x73,
+ 0x63, 0x72, 0xF0, 0x9D, 0x92, 0xB4, 0x59, 0x75, 0x6D, 0x6C, 0xC5, 0xB8,
+ 0x5A, 0x48, 0x63, 0x79, 0xD0, 0x96, 0x5A, 0x61, 0x63, 0x75, 0x74, 0x65,
+ 0xC5, 0xB9, 0x5A, 0x63, 0x61, 0x72, 0x6F, 0x6E, 0xC5, 0xBD, 0x5A, 0x63,
+ 0x79, 0xD0, 0x97, 0x5A, 0x64, 0x6F, 0x74, 0xC5, 0xBB, 0x5A, 0x65, 0x72,
+ 0x6F, 0x57, 0x69, 0x64, 0x74, 0x68, 0x53, 0x70, 0x61, 0x63, 0x65, 0xE2,
+ 0x80, 0x8B, 0x5A, 0x65, 0x74, 0x61, 0xCE, 0x96, 0x5A, 0x66, 0x72, 0xE2,
+ 0x84, 0xA8, 0x5A, 0x6F, 0x70, 0x66, 0xE2, 0x84, 0xA4, 0x5A, 0x73, 0x63,
+ 0x72, 0xF0, 0x9D, 0x92, 0xB5, 0x61, 0x61, 0x63, 0x75, 0x74, 0x65, 0xC3,
+ 0xA1, 0x61, 0x62, 0x72, 0x65, 0x76, 0x65, 0xC4, 0x83, 0x61, 0x63, 0xE2,
+ 0x88, 0xBE, 0x61, 0x63, 0x45, 0xE2, 0x88, 0xBE, 0xCC, 0xB3, 0x61, 0x63,
+ 0x64, 0xE2, 0x88, 0xBF, 0x61, 0x63, 0x69, 0x72, 0x63, 0xC3, 0xA2, 0x61,
+ 0x63, 0x75, 0x74, 0x65, 0xC2, 0xB4, 0x61, 0x63, 0x79, 0xD0, 0xB0, 0x61,
+ 0x65, 0x6C, 0x69, 0x67, 0xC3, 0xA6, 0x61, 0x66, 0xE2, 0x81, 0xA1, 0x61,
+ 0x66, 0x72, 0xF0, 0x9D, 0x94, 0x9E, 0x61, 0x67, 0x72, 0x61, 0x76, 0x65,
+ 0xC3, 0xA0, 0x61, 0x6C, 0x65, 0x66, 0x73, 0x79, 0x6D, 0xE2, 0x84, 0xB5,
+ 0x61, 0x6C, 0x65, 0x70, 0x68, 0xE2, 0x84, 0xB5, 0x61, 0x6C, 0x70, 0x68,
+ 0x61, 0xCE, 0xB1, 0x61, 0x6D, 0x61, 0x63, 0x72, 0xC4, 0x81, 0x61, 0x6D,
+ 0x61, 0x6C, 0x67, 0xE2, 0xA8, 0xBF, 0x61, 0x6D, 0x70, 0x26, 0x61, 0x6E,
+ 0x64, 0xE2, 0x88, 0xA7, 0x61, 0x6E, 0x64, 0x61, 0x6E, 0x64, 0xE2, 0xA9,
+ 0x95, 0x61, 0x6E, 0x64, 0x64, 0xE2, 0xA9, 0x9C, 0x61, 0x6E, 0x64, 0x73,
+ 0x6C, 0x6F, 0x70, 0x65, 0xE2, 0xA9, 0x98, 0x61, 0x6E, 0x64, 0x76, 0xE2,
+ 0xA9, 0x9A, 0x61, 0x6E, 0x67, 0xE2, 0x88, 0xA0, 0x61, 0x6E, 0x67, 0x65,
+ 0xE2, 0xA6, 0xA4, 0x61, 0x6E, 0x67, 0x6C, 0x65, 0xE2, 0x88, 0xA0, 0x61,
+ 0x6E, 0x67, 0x6D, 0x73, 0x64, 0xE2, 0x88, 0xA1, 0x61, 0x6E, 0x67, 0x6D,
+ 0x73, 0x64, 0x61, 0x61, 0xE2, 0xA6, 0xA8, 0x61, 0x6E, 0x67, 0x6D, 0x73,
+ 0x64, 0x61, 0x62, 0xE2, 0xA6, 0xA9, 0x61, 0x6E, 0x67, 0x6D, 0x73, 0x64,
+ 0x61, 0x63, 0xE2, 0xA6, 0xAA, 0x61, 0x6E, 0x67, 0x6D, 0x73, 0x64, 0x61,
+ 0x64, 0xE2, 0xA6, 0xAB, 0x61, 0x6E, 0x67, 0x6D, 0x73, 0x64, 0x61, 0x65,
+ 0xE2, 0xA6, 0xAC, 0x61, 0x6E, 0x67, 0x6D, 0x73, 0x64, 0x61, 0x66, 0xE2,
+ 0xA6, 0xAD, 0x61, 0x6E, 0x67, 0x6D, 0x73, 0x64, 0x61, 0x67, 0xE2, 0xA6,
+ 0xAE, 0x61, 0x6E, 0x67, 0x6D, 0x73, 0x64, 0x61, 0x68, 0xE2, 0xA6, 0xAF,
+ 0x61, 0x6E, 0x67, 0x72, 0x74, 0xE2, 0x88, 0x9F, 0x61, 0x6E, 0x67, 0x72,
+ 0x74, 0x76, 0x62, 0xE2, 0x8A, 0xBE, 0x61, 0x6E, 0x67, 0x72, 0x74, 0x76,
+ 0x62, 0x64, 0xE2, 0xA6, 0x9D, 0x61, 0x6E, 0x67, 0x73, 0x70, 0x68, 0xE2,
+ 0x88, 0xA2, 0x61, 0x6E, 0x67, 0x73, 0x74, 0xC3, 0x85, 0x61, 0x6E, 0x67,
+ 0x7A, 0x61, 0x72, 0x72, 0xE2, 0x8D, 0xBC, 0x61, 0x6F, 0x67, 0x6F, 0x6E,
+ 0xC4, 0x85, 0x61, 0x6F, 0x70, 0x66, 0xF0, 0x9D, 0x95, 0x92, 0x61, 0x70,
+ 0xE2, 0x89, 0x88, 0x61, 0x70, 0x45, 0xE2, 0xA9, 0xB0, 0x61, 0x70, 0x61,
+ 0x63, 0x69, 0x72, 0xE2, 0xA9, 0xAF, 0x61, 0x70, 0x65, 0xE2, 0x89, 0x8A,
+ 0x61, 0x70, 0x69, 0x64, 0xE2, 0x89, 0x8B, 0x61, 0x70, 0x6F, 0x73, 0x27,
+ 0x61, 0x70, 0x70, 0x72, 0x6F, 0x78, 0xE2, 0x89, 0x88, 0x61, 0x70, 0x70,
+ 0x72, 0x6F, 0x78, 0x65, 0x71, 0xE2, 0x89, 0x8A, 0x61, 0x72, 0x69, 0x6E,
+ 0x67, 0xC3, 0xA5, 0x61, 0x73, 0x63, 0x72, 0xF0, 0x9D, 0x92, 0xB6, 0x61,
+ 0x73, 0x74, 0x2A, 0x61, 0x73, 0x79, 0x6D, 0x70, 0xE2, 0x89, 0x88, 0x61,
+ 0x73, 0x79, 0x6D, 0x70, 0x65, 0x71, 0xE2, 0x89, 0x8D, 0x61, 0x74, 0x69,
+ 0x6C, 0x64, 0x65, 0xC3, 0xA3, 0x61, 0x75, 0x6D, 0x6C, 0xC3, 0xA4, 0x61,
+ 0x77, 0x63, 0x6F, 0x6E, 0x69, 0x6E, 0x74, 0xE2, 0x88, 0xB3, 0x61, 0x77,
+ 0x69, 0x6E, 0x74, 0xE2, 0xA8, 0x91, 0x62, 0x4E, 0x6F, 0x74, 0xE2, 0xAB,
+ 0xAD, 0x62, 0x61, 0x63, 0x6B, 0x63, 0x6F, 0x6E, 0x67, 0xE2, 0x89, 0x8C,
+ 0x62, 0x61, 0x63, 0x6B, 0x65, 0x70, 0x73, 0x69, 0x6C, 0x6F, 0x6E, 0xCF,
+ 0xB6, 0x62, 0x61, 0x63, 0x6B, 0x70, 0x72, 0x69, 0x6D, 0x65, 0xE2, 0x80,
+ 0xB5, 0x62, 0x61, 0x63, 0x6B, 0x73, 0x69, 0x6D, 0xE2, 0x88, 0xBD, 0x62,
+ 0x61, 0x63, 0x6B, 0x73, 0x69, 0x6D, 0x65, 0x71, 0xE2, 0x8B, 0x8D, 0x62,
+ 0x61, 0x72, 0x76, 0x65, 0x65, 0xE2, 0x8A, 0xBD, 0x62, 0x61, 0x72, 0x77,
+ 0x65, 0x64, 0xE2, 0x8C, 0x85, 0x62, 0x61, 0x72, 0x77, 0x65, 0x64, 0x67,
+ 0x65, 0xE2, 0x8C, 0x85, 0x62, 0x62, 0x72, 0x6B, 0xE2, 0x8E, 0xB5, 0x62,
+ 0x62, 0x72, 0x6B, 0x74, 0x62, 0x72, 0x6B, 0xE2, 0x8E, 0xB6, 0x62, 0x63,
+ 0x6F, 0x6E, 0x67, 0xE2, 0x89, 0x8C, 0x62, 0x63, 0x79, 0xD0, 0xB1, 0x62,
+ 0x64, 0x71, 0x75, 0x6F, 0xE2, 0x80, 0x9E, 0x62, 0x65, 0x63, 0x61, 0x75,
+ 0x73, 0xE2, 0x88, 0xB5, 0x62, 0x65, 0x63, 0x61, 0x75, 0x73, 0x65, 0xE2,
+ 0x88, 0xB5, 0x62, 0x65, 0x6D, 0x70, 0x74, 0x79, 0x76, 0xE2, 0xA6, 0xB0,
+ 0x62, 0x65, 0x70, 0x73, 0x69, 0xCF, 0xB6, 0x62, 0x65, 0x72, 0x6E, 0x6F,
+ 0x75, 0xE2, 0x84, 0xAC, 0x62, 0x65, 0x74, 0x61, 0xCE, 0xB2, 0x62, 0x65,
+ 0x74, 0x68, 0xE2, 0x84, 0xB6, 0x62, 0x65, 0x74, 0x77, 0x65, 0x65, 0x6E,
+ 0xE2, 0x89, 0xAC, 0x62, 0x66, 0x72, 0xF0, 0x9D, 0x94, 0x9F, 0x62, 0x69,
+ 0x67, 0x63, 0x61, 0x70, 0xE2, 0x8B, 0x82, 0x62, 0x69, 0x67, 0x63, 0x69,
+ 0x72, 0x63, 0xE2, 0x97, 0xAF, 0x62, 0x69, 0x67, 0x63, 0x75, 0x70, 0xE2,
+ 0x8B, 0x83, 0x62, 0x69, 0x67, 0x6F, 0x64, 0x6F, 0x74, 0xE2, 0xA8, 0x80,
+ 0x62, 0x69, 0x67, 0x6F, 0x70, 0x6C, 0x75, 0x73, 0xE2, 0xA8, 0x81, 0x62,
+ 0x69, 0x67, 0x6F, 0x74, 0x69, 0x6D, 0x65, 0x73, 0xE2, 0xA8, 0x82, 0x62,
+ 0x69, 0x67, 0x73, 0x71, 0x63, 0x75, 0x70, 0xE2, 0xA8, 0x86, 0x62, 0x69,
+ 0x67, 0x73, 0x74, 0x61, 0x72, 0xE2, 0x98, 0x85, 0x62, 0x69, 0x67, 0x74,
+ 0x72, 0x69, 0x61, 0x6E, 0x67, 0x6C, 0x65, 0x64, 0x6F, 0x77, 0x6E, 0xE2,
+ 0x96, 0xBD, 0x62, 0x69, 0x67, 0x74, 0x72, 0x69, 0x61, 0x6E, 0x67, 0x6C,
+ 0x65, 0x75, 0x70, 0xE2, 0x96, 0xB3, 0x62, 0x69, 0x67, 0x75, 0x70, 0x6C,
+ 0x75, 0x73, 0xE2, 0xA8, 0x84, 0x62, 0x69, 0x67, 0x76, 0x65, 0x65, 0xE2,
+ 0x8B, 0x81, 0x62, 0x69, 0x67, 0x77, 0x65, 0x64, 0x67, 0x65, 0xE2, 0x8B,
+ 0x80, 0x62, 0x6B, 0x61, 0x72, 0x6F, 0x77, 0xE2, 0xA4, 0x8D, 0x62, 0x6C,
+ 0x61, 0x63, 0x6B, 0x6C, 0x6F, 0x7A, 0x65, 0x6E, 0x67, 0x65, 0xE2, 0xA7,
+ 0xAB, 0x62, 0x6C, 0x61, 0x63, 0x6B, 0x73, 0x71, 0x75, 0x61, 0x72, 0x65,
+ 0xE2, 0x96, 0xAA, 0x62, 0x6C, 0x61, 0x63, 0x6B, 0x74, 0x72, 0x69, 0x61,
+ 0x6E, 0x67, 0x6C, 0x65, 0xE2, 0x96, 0xB4, 0x62, 0x6C, 0x61, 0x63, 0x6B,
+ 0x74, 0x72, 0x69, 0x61, 0x6E, 0x67, 0x6C, 0x65, 0x64, 0x6F, 0x77, 0x6E,
+ 0xE2, 0x96, 0xBE, 0x62, 0x6C, 0x61, 0x63, 0x6B, 0x74, 0x72, 0x69, 0x61,
+ 0x6E, 0x67, 0x6C, 0x65, 0x6C, 0x65, 0x66, 0x74, 0xE2, 0x97, 0x82, 0x62,
+ 0x6C, 0x61, 0x63, 0x6B, 0x74, 0x72, 0x69, 0x61, 0x6E, 0x67, 0x6C, 0x65,
+ 0x72, 0x69, 0x67, 0x68, 0x74, 0xE2, 0x96, 0xB8, 0x62, 0x6C, 0x61, 0x6E,
+ 0x6B, 0xE2, 0x90, 0xA3, 0x62, 0x6C, 0x6B, 0x31, 0x32, 0xE2, 0x96, 0x92,
+ 0x62, 0x6C, 0x6B, 0x31, 0x34, 0xE2, 0x96, 0x91, 0x62, 0x6C, 0x6B, 0x33,
+ 0x34, 0xE2, 0x96, 0x93, 0x62, 0x6C, 0x6F, 0x63, 0x6B, 0xE2, 0x96, 0x88,
+ 0x62, 0x6E, 0x65, 0x3D, 0xE2, 0x83, 0xA5, 0x62, 0x6E, 0x65, 0x71, 0x75,
+ 0x69, 0x76, 0xE2, 0x89, 0xA1, 0xE2, 0x83, 0xA5, 0x62, 0x6E, 0x6F, 0x74,
+ 0xE2, 0x8C, 0x90, 0x62, 0x6F, 0x70, 0x66, 0xF0, 0x9D, 0x95, 0x93, 0x62,
+ 0x6F, 0x74, 0xE2, 0x8A, 0xA5, 0x62, 0x6F, 0x74, 0x74, 0x6F, 0x6D, 0xE2,
+ 0x8A, 0xA5, 0x62, 0x6F, 0x77, 0x74, 0x69, 0x65, 0xE2, 0x8B, 0x88, 0x62,
+ 0x6F, 0x78, 0x44, 0x4C, 0xE2, 0x95, 0x97, 0x62, 0x6F, 0x78, 0x44, 0x52,
+ 0xE2, 0x95, 0x94, 0x62, 0x6F, 0x78, 0x44, 0x6C, 0xE2, 0x95, 0x96, 0x62,
+ 0x6F, 0x78, 0x44, 0x72, 0xE2, 0x95, 0x93, 0x62, 0x6F, 0x78, 0x48, 0xE2,
+ 0x95, 0x90, 0x62, 0x6F, 0x78, 0x48, 0x44, 0xE2, 0x95, 0xA6, 0x62, 0x6F,
+ 0x78, 0x48, 0x55, 0xE2, 0x95, 0xA9, 0x62, 0x6F, 0x78, 0x48, 0x64, 0xE2,
+ 0x95, 0xA4, 0x62, 0x6F, 0x78, 0x48, 0x75, 0xE2, 0x95, 0xA7, 0x62, 0x6F,
+ 0x78, 0x55, 0x4C, 0xE2, 0x95, 0x9D, 0x62, 0x6F, 0x78, 0x55, 0x52, 0xE2,
+ 0x95, 0x9A, 0x62, 0x6F, 0x78, 0x55, 0x6C, 0xE2, 0x95, 0x9C, 0x62, 0x6F,
+ 0x78, 0x55, 0x72, 0xE2, 0x95, 0x99, 0x62, 0x6F, 0x78, 0x56, 0xE2, 0x95,
+ 0x91, 0x62, 0x6F, 0x78, 0x56, 0x48, 0xE2, 0x95, 0xAC, 0x62, 0x6F, 0x78,
+ 0x56, 0x4C, 0xE2, 0x95, 0xA3, 0x62, 0x6F, 0x78, 0x56, 0x52, 0xE2, 0x95,
+ 0xA0, 0x62, 0x6F, 0x78, 0x56, 0x68, 0xE2, 0x95, 0xAB, 0x62, 0x6F, 0x78,
+ 0x56, 0x6C, 0xE2, 0x95, 0xA2, 0x62, 0x6F, 0x78, 0x56, 0x72, 0xE2, 0x95,
+ 0x9F, 0x62, 0x6F, 0x78, 0x62, 0x6F, 0x78, 0xE2, 0xA7, 0x89, 0x62, 0x6F,
+ 0x78, 0x64, 0x4C, 0xE2, 0x95, 0x95, 0x62, 0x6F, 0x78, 0x64, 0x52, 0xE2,
+ 0x95, 0x92, 0x62, 0x6F, 0x78, 0x64, 0x6C, 0xE2, 0x94, 0x90, 0x62, 0x6F,
+ 0x78, 0x64, 0x72, 0xE2, 0x94, 0x8C, 0x62, 0x6F, 0x78, 0x68, 0xE2, 0x94,
+ 0x80, 0x62, 0x6F, 0x78, 0x68, 0x44, 0xE2, 0x95, 0xA5, 0x62, 0x6F, 0x78,
+ 0x68, 0x55, 0xE2, 0x95, 0xA8, 0x62, 0x6F, 0x78, 0x68, 0x64, 0xE2, 0x94,
+ 0xAC, 0x62, 0x6F, 0x78, 0x68, 0x75, 0xE2, 0x94, 0xB4, 0x62, 0x6F, 0x78,
+ 0x6D, 0x69, 0x6E, 0x75, 0x73, 0xE2, 0x8A, 0x9F, 0x62, 0x6F, 0x78, 0x70,
+ 0x6C, 0x75, 0x73, 0xE2, 0x8A, 0x9E, 0x62, 0x6F, 0x78, 0x74, 0x69, 0x6D,
+ 0x65, 0x73, 0xE2, 0x8A, 0xA0, 0x62, 0x6F, 0x78, 0x75, 0x4C, 0xE2, 0x95,
+ 0x9B, 0x62, 0x6F, 0x78, 0x75, 0x52, 0xE2, 0x95, 0x98, 0x62, 0x6F, 0x78,
+ 0x75, 0x6C, 0xE2, 0x94, 0x98, 0x62, 0x6F, 0x78, 0x75, 0x72, 0xE2, 0x94,
+ 0x94, 0x62, 0x6F, 0x78, 0x76, 0xE2, 0x94, 0x82, 0x62, 0x6F, 0x78, 0x76,
+ 0x48, 0xE2, 0x95, 0xAA, 0x62, 0x6F, 0x78, 0x76, 0x4C, 0xE2, 0x95, 0xA1,
+ 0x62, 0x6F, 0x78, 0x76, 0x52, 0xE2, 0x95, 0x9E, 0x62, 0x6F, 0x78, 0x76,
+ 0x68, 0xE2, 0x94, 0xBC, 0x62, 0x6F, 0x78, 0x76, 0x6C, 0xE2, 0x94, 0xA4,
+ 0x62, 0x6F, 0x78, 0x76, 0x72, 0xE2, 0x94, 0x9C, 0x62, 0x70, 0x72, 0x69,
+ 0x6D, 0x65, 0xE2, 0x80, 0xB5, 0x62, 0x72, 0x65, 0x76, 0x65, 0xCB, 0x98,
+ 0x62, 0x72, 0x76, 0x62, 0x61, 0x72, 0xC2, 0xA6, 0x62, 0x73, 0x63, 0x72,
+ 0xF0, 0x9D, 0x92, 0xB7, 0x62, 0x73, 0x65, 0x6D, 0x69, 0xE2, 0x81, 0x8F,
+ 0x62, 0x73, 0x69, 0x6D, 0xE2, 0x88, 0xBD, 0x62, 0x73, 0x69, 0x6D, 0x65,
+ 0xE2, 0x8B, 0x8D, 0x62, 0x73, 0x6F, 0x6C, 0x5C, 0x62, 0x73, 0x6F, 0x6C,
+ 0x62, 0xE2, 0xA7, 0x85, 0x62, 0x73, 0x6F, 0x6C, 0x68, 0x73, 0x75, 0x62,
+ 0xE2, 0x9F, 0x88, 0x62, 0x75, 0x6C, 0x6C, 0xE2, 0x80, 0xA2, 0x62, 0x75,
+ 0x6C, 0x6C, 0x65, 0x74, 0xE2, 0x80, 0xA2, 0x62, 0x75, 0x6D, 0x70, 0xE2,
+ 0x89, 0x8E, 0x62, 0x75, 0x6D, 0x70, 0x45, 0xE2, 0xAA, 0xAE, 0x62, 0x75,
+ 0x6D, 0x70, 0x65, 0xE2, 0x89, 0x8F, 0x62, 0x75, 0x6D, 0x70, 0x65, 0x71,
+ 0xE2, 0x89, 0x8F, 0x63, 0x61, 0x63, 0x75, 0x74, 0x65, 0xC4, 0x87, 0x63,
+ 0x61, 0x70, 0xE2, 0x88, 0xA9, 0x63, 0x61, 0x70, 0x61, 0x6E, 0x64, 0xE2,
+ 0xA9, 0x84, 0x63, 0x61, 0x70, 0x62, 0x72, 0x63, 0x75, 0x70, 0xE2, 0xA9,
+ 0x89, 0x63, 0x61, 0x70, 0x63, 0x61, 0x70, 0xE2, 0xA9, 0x8B, 0x63, 0x61,
+ 0x70, 0x63, 0x75, 0x70, 0xE2, 0xA9, 0x87, 0x63, 0x61, 0x70, 0x64, 0x6F,
+ 0x74, 0xE2, 0xA9, 0x80, 0x63, 0x61, 0x70, 0x73, 0xE2, 0x88, 0xA9, 0xEF,
+ 0xB8, 0x80, 0x63, 0x61, 0x72, 0x65, 0x74, 0xE2, 0x81, 0x81, 0x63, 0x61,
+ 0x72, 0x6F, 0x6E, 0xCB, 0x87, 0x63, 0x63, 0x61, 0x70, 0x73, 0xE2, 0xA9,
+ 0x8D, 0x63, 0x63, 0x61, 0x72, 0x6F, 0x6E, 0xC4, 0x8D, 0x63, 0x63, 0x65,
+ 0x64, 0x69, 0x6C, 0xC3, 0xA7, 0x63, 0x63, 0x69, 0x72, 0x63, 0xC4, 0x89,
+ 0x63, 0x63, 0x75, 0x70, 0x73, 0xE2, 0xA9, 0x8C, 0x63, 0x63, 0x75, 0x70,
+ 0x73, 0x73, 0x6D, 0xE2, 0xA9, 0x90, 0x63, 0x64, 0x6F, 0x74, 0xC4, 0x8B,
+ 0x63, 0x65, 0x64, 0x69, 0x6C, 0xC2, 0xB8, 0x63, 0x65, 0x6D, 0x70, 0x74,
+ 0x79, 0x76, 0xE2, 0xA6, 0xB2, 0x63, 0x65, 0x6E, 0x74, 0xC2, 0xA2, 0x63,
+ 0x65, 0x6E, 0x74, 0x65, 0x72, 0x64, 0x6F, 0x74, 0xC2, 0xB7, 0x63, 0x66,
+ 0x72, 0xF0, 0x9D, 0x94, 0xA0, 0x63, 0x68, 0x63, 0x79, 0xD1, 0x87, 0x63,
+ 0x68, 0x65, 0x63, 0x6B, 0xE2, 0x9C, 0x93, 0x63, 0x68, 0x65, 0x63, 0x6B,
+ 0x6D, 0x61, 0x72, 0x6B, 0xE2, 0x9C, 0x93, 0x63, 0x68, 0x69, 0xCF, 0x87,
+ 0x63, 0x69, 0x72, 0xE2, 0x97, 0x8B, 0x63, 0x69, 0x72, 0x45, 0xE2, 0xA7,
+ 0x83, 0x63, 0x69, 0x72, 0x63, 0xCB, 0x86, 0x63, 0x69, 0x72, 0x63, 0x65,
+ 0x71, 0xE2, 0x89, 0x97, 0x63, 0x69, 0x72, 0x63, 0x6C, 0x65, 0x61, 0x72,
+ 0x72, 0x6F, 0x77, 0x6C, 0x65, 0x66, 0x74, 0xE2, 0x86, 0xBA, 0x63, 0x69,
+ 0x72, 0x63, 0x6C, 0x65, 0x61, 0x72, 0x72, 0x6F, 0x77, 0x72, 0x69, 0x67,
+ 0x68, 0x74, 0xE2, 0x86, 0xBB, 0x63, 0x69, 0x72, 0x63, 0x6C, 0x65, 0x64,
+ 0x52, 0xC2, 0xAE, 0x63, 0x69, 0x72, 0x63, 0x6C, 0x65, 0x64, 0x53, 0xE2,
+ 0x93, 0x88, 0x63, 0x69, 0x72, 0x63, 0x6C, 0x65, 0x64, 0x61, 0x73, 0x74,
+ 0xE2, 0x8A, 0x9B, 0x63, 0x69, 0x72, 0x63, 0x6C, 0x65, 0x64, 0x63, 0x69,
+ 0x72, 0x63, 0xE2, 0x8A, 0x9A, 0x63, 0x69, 0x72, 0x63, 0x6C, 0x65, 0x64,
+ 0x64, 0x61, 0x73, 0x68, 0xE2, 0x8A, 0x9D, 0x63, 0x69, 0x72, 0x65, 0xE2,
+ 0x89, 0x97, 0x63, 0x69, 0x72, 0x66, 0x6E, 0x69, 0x6E, 0x74, 0xE2, 0xA8,
+ 0x90, 0x63, 0x69, 0x72, 0x6D, 0x69, 0x64, 0xE2, 0xAB, 0xAF, 0x63, 0x69,
+ 0x72, 0x73, 0x63, 0x69, 0x72, 0xE2, 0xA7, 0x82, 0x63, 0x6C, 0x75, 0x62,
+ 0x73, 0xE2, 0x99, 0xA3, 0x63, 0x6C, 0x75, 0x62, 0x73, 0x75, 0x69, 0x74,
+ 0xE2, 0x99, 0xA3, 0x63, 0x6F, 0x6C, 0x6F, 0x6E, 0x3A, 0x63, 0x6F, 0x6C,
+ 0x6F, 0x6E, 0x65, 0xE2, 0x89, 0x94, 0x63, 0x6F, 0x6C, 0x6F, 0x6E, 0x65,
+ 0x71, 0xE2, 0x89, 0x94, 0x63, 0x6F, 0x6D, 0x6D, 0x61, 0x2C, 0x63, 0x6F,
+ 0x6D, 0x6D, 0x61, 0x74, 0x40, 0x63, 0x6F, 0x6D, 0x70, 0xE2, 0x88, 0x81,
+ 0x63, 0x6F, 0x6D, 0x70, 0x66, 0x6E, 0xE2, 0x88, 0x98, 0x63, 0x6F, 0x6D,
+ 0x70, 0x6C, 0x65, 0x6D, 0x65, 0x6E, 0x74, 0xE2, 0x88, 0x81, 0x63, 0x6F,
+ 0x6D, 0x70, 0x6C, 0x65, 0x78, 0x65, 0x73, 0xE2, 0x84, 0x82, 0x63, 0x6F,
+ 0x6E, 0x67, 0xE2, 0x89, 0x85, 0x63, 0x6F, 0x6E, 0x67, 0x64, 0x6F, 0x74,
+ 0xE2, 0xA9, 0xAD, 0x63, 0x6F, 0x6E, 0x69, 0x6E, 0x74, 0xE2, 0x88, 0xAE,
+ 0x63, 0x6F, 0x70, 0x66, 0xF0, 0x9D, 0x95, 0x94, 0x63, 0x6F, 0x70, 0x72,
+ 0x6F, 0x64, 0xE2, 0x88, 0x90, 0x63, 0x6F, 0x70, 0x79, 0xC2, 0xA9, 0x63,
+ 0x6F, 0x70, 0x79, 0x73, 0x72, 0xE2, 0x84, 0x97, 0x63, 0x72, 0x61, 0x72,
+ 0x72, 0xE2, 0x86, 0xB5, 0x63, 0x72, 0x6F, 0x73, 0x73, 0xE2, 0x9C, 0x97,
+ 0x63, 0x73, 0x63, 0x72, 0xF0, 0x9D, 0x92, 0xB8, 0x63, 0x73, 0x75, 0x62,
+ 0xE2, 0xAB, 0x8F, 0x63, 0x73, 0x75, 0x62, 0x65, 0xE2, 0xAB, 0x91, 0x63,
+ 0x73, 0x75, 0x70, 0xE2, 0xAB, 0x90, 0x63, 0x73, 0x75, 0x70, 0x65, 0xE2,
+ 0xAB, 0x92, 0x63, 0x74, 0x64, 0x6F, 0x74, 0xE2, 0x8B, 0xAF, 0x63, 0x75,
+ 0x64, 0x61, 0x72, 0x72, 0x6C, 0xE2, 0xA4, 0xB8, 0x63, 0x75, 0x64, 0x61,
+ 0x72, 0x72, 0x72, 0xE2, 0xA4, 0xB5, 0x63, 0x75, 0x65, 0x70, 0x72, 0xE2,
+ 0x8B, 0x9E, 0x63, 0x75, 0x65, 0x73, 0x63, 0xE2, 0x8B, 0x9F, 0x63, 0x75,
+ 0x6C, 0x61, 0x72, 0x72, 0xE2, 0x86, 0xB6, 0x63, 0x75, 0x6C, 0x61, 0x72,
+ 0x72, 0x70, 0xE2, 0xA4, 0xBD, 0x63, 0x75, 0x70, 0xE2, 0x88, 0xAA, 0x63,
+ 0x75, 0x70, 0x62, 0x72, 0x63, 0x61, 0x70, 0xE2, 0xA9, 0x88, 0x63, 0x75,
+ 0x70, 0x63, 0x61, 0x70, 0xE2, 0xA9, 0x86, 0x63, 0x75, 0x70, 0x63, 0x75,
+ 0x70, 0xE2, 0xA9, 0x8A, 0x63, 0x75, 0x70, 0x64, 0x6F, 0x74, 0xE2, 0x8A,
+ 0x8D, 0x63, 0x75, 0x70, 0x6F, 0x72, 0xE2, 0xA9, 0x85, 0x63, 0x75, 0x70,
+ 0x73, 0xE2, 0x88, 0xAA, 0xEF, 0xB8, 0x80, 0x63, 0x75, 0x72, 0x61, 0x72,
+ 0x72, 0xE2, 0x86, 0xB7, 0x63, 0x75, 0x72, 0x61, 0x72, 0x72, 0x6D, 0xE2,
+ 0xA4, 0xBC, 0x63, 0x75, 0x72, 0x6C, 0x79, 0x65, 0x71, 0x70, 0x72, 0x65,
+ 0x63, 0xE2, 0x8B, 0x9E, 0x63, 0x75, 0x72, 0x6C, 0x79, 0x65, 0x71, 0x73,
+ 0x75, 0x63, 0x63, 0xE2, 0x8B, 0x9F, 0x63, 0x75, 0x72, 0x6C, 0x79, 0x76,
+ 0x65, 0x65, 0xE2, 0x8B, 0x8E, 0x63, 0x75, 0x72, 0x6C, 0x79, 0x77, 0x65,
+ 0x64, 0x67, 0x65, 0xE2, 0x8B, 0x8F, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6E,
+ 0xC2, 0xA4, 0x63, 0x75, 0x72, 0x76, 0x65, 0x61, 0x72, 0x72, 0x6F, 0x77,
+ 0x6C, 0x65, 0x66, 0x74, 0xE2, 0x86, 0xB6, 0x63, 0x75, 0x72, 0x76, 0x65,
+ 0x61, 0x72, 0x72, 0x6F, 0x77, 0x72, 0x69, 0x67, 0x68, 0x74, 0xE2, 0x86,
+ 0xB7, 0x63, 0x75, 0x76, 0x65, 0x65, 0xE2, 0x8B, 0x8E, 0x63, 0x75, 0x77,
+ 0x65, 0x64, 0xE2, 0x8B, 0x8F, 0x63, 0x77, 0x63, 0x6F, 0x6E, 0x69, 0x6E,
+ 0x74, 0xE2, 0x88, 0xB2, 0x63, 0x77, 0x69, 0x6E, 0x74, 0xE2, 0x88, 0xB1,
+ 0x63, 0x79, 0x6C, 0x63, 0x74, 0x79, 0xE2, 0x8C, 0xAD, 0x64, 0x41, 0x72,
+ 0x72, 0xE2, 0x87, 0x93, 0x64, 0x48, 0x61, 0x72, 0xE2, 0xA5, 0xA5, 0x64,
+ 0x61, 0x67, 0x67, 0x65, 0x72, 0xE2, 0x80, 0xA0, 0x64, 0x61, 0x6C, 0x65,
+ 0x74, 0x68, 0xE2, 0x84, 0xB8, 0x64, 0x61, 0x72, 0x72, 0xE2, 0x86, 0x93,
+ 0x64, 0x61, 0x73, 0x68, 0xE2, 0x80, 0x90, 0x64, 0x61, 0x73, 0x68, 0x76,
+ 0xE2, 0x8A, 0xA3, 0x64, 0x62, 0x6B, 0x61, 0x72, 0x6F, 0x77, 0xE2, 0xA4,
+ 0x8F, 0x64, 0x62, 0x6C, 0x61, 0x63, 0xCB, 0x9D, 0x64, 0x63, 0x61, 0x72,
+ 0x6F, 0x6E, 0xC4, 0x8F, 0x64, 0x63, 0x79, 0xD0, 0xB4, 0x64, 0x64, 0xE2,
+ 0x85, 0x86, 0x64, 0x64, 0x61, 0x67, 0x67, 0x65, 0x72, 0xE2, 0x80, 0xA1,
+ 0x64, 0x64, 0x61, 0x72, 0x72, 0xE2, 0x87, 0x8A, 0x64, 0x64, 0x6F, 0x74,
+ 0x73, 0x65, 0x71, 0xE2, 0xA9, 0xB7, 0x64, 0x65, 0x67, 0xC2, 0xB0, 0x64,
+ 0x65, 0x6C, 0x74, 0x61, 0xCE, 0xB4, 0x64, 0x65, 0x6D, 0x70, 0x74, 0x79,
+ 0x76, 0xE2, 0xA6, 0xB1, 0x64, 0x66, 0x69, 0x73, 0x68, 0x74, 0xE2, 0xA5,
+ 0xBF, 0x64, 0x66, 0x72, 0xF0, 0x9D, 0x94, 0xA1, 0x64, 0x68, 0x61, 0x72,
+ 0x6C, 0xE2, 0x87, 0x83, 0x64, 0x68, 0x61, 0x72, 0x72, 0xE2, 0x87, 0x82,
+ 0x64, 0x69, 0x61, 0x6D, 0xE2, 0x8B, 0x84, 0x64, 0x69, 0x61, 0x6D, 0x6F,
+ 0x6E, 0x64, 0xE2, 0x8B, 0x84, 0x64, 0x69, 0x61, 0x6D, 0x6F, 0x6E, 0x64,
+ 0x73, 0x75, 0x69, 0x74, 0xE2, 0x99, 0xA6, 0x64, 0x69, 0x61, 0x6D, 0x73,
+ 0xE2, 0x99, 0xA6, 0x64, 0x69, 0x65, 0xC2, 0xA8, 0x64, 0x69, 0x67, 0x61,
+ 0x6D, 0x6D, 0x61, 0xCF, 0x9D, 0x64, 0x69, 0x73, 0x69, 0x6E, 0xE2, 0x8B,
+ 0xB2, 0x64, 0x69, 0x76, 0xC3, 0xB7, 0x64, 0x69, 0x76, 0x69, 0x64, 0x65,
+ 0xC3, 0xB7, 0x64, 0x69, 0x76, 0x69, 0x64, 0x65, 0x6F, 0x6E, 0x74, 0x69,
+ 0x6D, 0x65, 0x73, 0xE2, 0x8B, 0x87, 0x64, 0x69, 0x76, 0x6F, 0x6E, 0x78,
+ 0xE2, 0x8B, 0x87, 0x64, 0x6A, 0x63, 0x79, 0xD1, 0x92, 0x64, 0x6C, 0x63,
+ 0x6F, 0x72, 0x6E, 0xE2, 0x8C, 0x9E, 0x64, 0x6C, 0x63, 0x72, 0x6F, 0x70,
+ 0xE2, 0x8C, 0x8D, 0x64, 0x6F, 0x6C, 0x6C, 0x61, 0x72, 0x24, 0x64, 0x6F,
+ 0x70, 0x66, 0xF0, 0x9D, 0x95, 0x95, 0x64, 0x6F, 0x74, 0xCB, 0x99, 0x64,
+ 0x6F, 0x74, 0x65, 0x71, 0xE2, 0x89, 0x90, 0x64, 0x6F, 0x74, 0x65, 0x71,
+ 0x64, 0x6F, 0x74, 0xE2, 0x89, 0x91, 0x64, 0x6F, 0x74, 0x6D, 0x69, 0x6E,
+ 0x75, 0x73, 0xE2, 0x88, 0xB8, 0x64, 0x6F, 0x74, 0x70, 0x6C, 0x75, 0x73,
+ 0xE2, 0x88, 0x94, 0x64, 0x6F, 0x74, 0x73, 0x71, 0x75, 0x61, 0x72, 0x65,
+ 0xE2, 0x8A, 0xA1, 0x64, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x62, 0x61, 0x72,
+ 0x77, 0x65, 0x64, 0x67, 0x65, 0xE2, 0x8C, 0x86, 0x64, 0x6F, 0x77, 0x6E,
+ 0x61, 0x72, 0x72, 0x6F, 0x77, 0xE2, 0x86, 0x93, 0x64, 0x6F, 0x77, 0x6E,
+ 0x64, 0x6F, 0x77, 0x6E, 0x61, 0x72, 0x72, 0x6F, 0x77, 0x73, 0xE2, 0x87,
+ 0x8A, 0x64, 0x6F, 0x77, 0x6E, 0x68, 0x61, 0x72, 0x70, 0x6F, 0x6F, 0x6E,
+ 0x6C, 0x65, 0x66, 0x74, 0xE2, 0x87, 0x83, 0x64, 0x6F, 0x77, 0x6E, 0x68,
+ 0x61, 0x72, 0x70, 0x6F, 0x6F, 0x6E, 0x72, 0x69, 0x67, 0x68, 0x74, 0xE2,
+ 0x87, 0x82, 0x64, 0x72, 0x62, 0x6B, 0x61, 0x72, 0x6F, 0x77, 0xE2, 0xA4,
+ 0x90, 0x64, 0x72, 0x63, 0x6F, 0x72, 0x6E, 0xE2, 0x8C, 0x9F, 0x64, 0x72,
+ 0x63, 0x72, 0x6F, 0x70, 0xE2, 0x8C, 0x8C, 0x64, 0x73, 0x63, 0x72, 0xF0,
+ 0x9D, 0x92, 0xB9, 0x64, 0x73, 0x63, 0x79, 0xD1, 0x95, 0x64, 0x73, 0x6F,
+ 0x6C, 0xE2, 0xA7, 0xB6, 0x64, 0x73, 0x74, 0x72, 0x6F, 0x6B, 0xC4, 0x91,
+ 0x64, 0x74, 0x64, 0x6F, 0x74, 0xE2, 0x8B, 0xB1, 0x64, 0x74, 0x72, 0x69,
+ 0xE2, 0x96, 0xBF, 0x64, 0x74, 0x72, 0x69, 0x66, 0xE2, 0x96, 0xBE, 0x64,
+ 0x75, 0x61, 0x72, 0x72, 0xE2, 0x87, 0xB5, 0x64, 0x75, 0x68, 0x61, 0x72,
+ 0xE2, 0xA5, 0xAF, 0x64, 0x77, 0x61, 0x6E, 0x67, 0x6C, 0x65, 0xE2, 0xA6,
+ 0xA6, 0x64, 0x7A, 0x63, 0x79, 0xD1, 0x9F, 0x64, 0x7A, 0x69, 0x67, 0x72,
+ 0x61, 0x72, 0x72, 0xE2, 0x9F, 0xBF, 0x65, 0x44, 0x44, 0x6F, 0x74, 0xE2,
+ 0xA9, 0xB7, 0x65, 0x44, 0x6F, 0x74, 0xE2, 0x89, 0x91, 0x65, 0x61, 0x63,
+ 0x75, 0x74, 0x65, 0xC3, 0xA9, 0x65, 0x61, 0x73, 0x74, 0x65, 0x72, 0xE2,
+ 0xA9, 0xAE, 0x65, 0x63, 0x61, 0x72, 0x6F, 0x6E, 0xC4, 0x9B, 0x65, 0x63,
+ 0x69, 0x72, 0xE2, 0x89, 0x96, 0x65, 0x63, 0x69, 0x72, 0x63, 0xC3, 0xAA,
+ 0x65, 0x63, 0x6F, 0x6C, 0x6F, 0x6E, 0xE2, 0x89, 0x95, 0x65, 0x63, 0x79,
+ 0xD1, 0x8D, 0x65, 0x64, 0x6F, 0x74, 0xC4, 0x97, 0x65, 0x65, 0xE2, 0x85,
+ 0x87, 0x65, 0x66, 0x44, 0x6F, 0x74, 0xE2, 0x89, 0x92, 0x65, 0x66, 0x72,
+ 0xF0, 0x9D, 0x94, 0xA2, 0x65, 0x67, 0xE2, 0xAA, 0x9A, 0x65, 0x67, 0x72,
+ 0x61, 0x76, 0x65, 0xC3, 0xA8, 0x65, 0x67, 0x73, 0xE2, 0xAA, 0x96, 0x65,
+ 0x67, 0x73, 0x64, 0x6F, 0x74, 0xE2, 0xAA, 0x98, 0x65, 0x6C, 0xE2, 0xAA,
+ 0x99, 0x65, 0x6C, 0x69, 0x6E, 0x74, 0x65, 0x72, 0x73, 0xE2, 0x8F, 0xA7,
+ 0x65, 0x6C, 0x6C, 0xE2, 0x84, 0x93, 0x65, 0x6C, 0x73, 0xE2, 0xAA, 0x95,
+ 0x65, 0x6C, 0x73, 0x64, 0x6F, 0x74, 0xE2, 0xAA, 0x97, 0x65, 0x6D, 0x61,
+ 0x63, 0x72, 0xC4, 0x93, 0x65, 0x6D, 0x70, 0x74, 0x79, 0xE2, 0x88, 0x85,
+ 0x65, 0x6D, 0x70, 0x74, 0x79, 0x73, 0x65, 0x74, 0xE2, 0x88, 0x85, 0x65,
+ 0x6D, 0x70, 0x74, 0x79, 0x76, 0xE2, 0x88, 0x85, 0x65, 0x6D, 0x73, 0x70,
+ 0xE2, 0x80, 0x83, 0x65, 0x6D, 0x73, 0x70, 0x31, 0x33, 0xE2, 0x80, 0x84,
+ 0x65, 0x6D, 0x73, 0x70, 0x31, 0x34, 0xE2, 0x80, 0x85, 0x65, 0x6E, 0x67,
+ 0xC5, 0x8B, 0x65, 0x6E, 0x73, 0x70, 0xE2, 0x80, 0x82, 0x65, 0x6F, 0x67,
+ 0x6F, 0x6E, 0xC4, 0x99, 0x65, 0x6F, 0x70, 0x66, 0xF0, 0x9D, 0x95, 0x96,
+ 0x65, 0x70, 0x61, 0x72, 0xE2, 0x8B, 0x95, 0x65, 0x70, 0x61, 0x72, 0x73,
+ 0x6C, 0xE2, 0xA7, 0xA3, 0x65, 0x70, 0x6C, 0x75, 0x73, 0xE2, 0xA9, 0xB1,
+ 0x65, 0x70, 0x73, 0x69, 0xCE, 0xB5, 0x65, 0x70, 0x73, 0x69, 0x6C, 0x6F,
+ 0x6E, 0xCE, 0xB5, 0x65, 0x70, 0x73, 0x69, 0x76, 0xCF, 0xB5, 0x65, 0x71,
+ 0x63, 0x69, 0x72, 0x63, 0xE2, 0x89, 0x96, 0x65, 0x71, 0x63, 0x6F, 0x6C,
+ 0x6F, 0x6E, 0xE2, 0x89, 0x95, 0x65, 0x71, 0x73, 0x69, 0x6D, 0xE2, 0x89,
+ 0x82, 0x65, 0x71, 0x73, 0x6C, 0x61, 0x6E, 0x74, 0x67, 0x74, 0x72, 0xE2,
+ 0xAA, 0x96, 0x65, 0x71, 0x73, 0x6C, 0x61, 0x6E, 0x74, 0x6C, 0x65, 0x73,
+ 0x73, 0xE2, 0xAA, 0x95, 0x65, 0x71, 0x75, 0x61, 0x6C, 0x73, 0x3D, 0x65,
+ 0x71, 0x75, 0x65, 0x73, 0x74, 0xE2, 0x89, 0x9F, 0x65, 0x71, 0x75, 0x69,
+ 0x76, 0xE2, 0x89, 0xA1, 0x65, 0x71, 0x75, 0x69, 0x76, 0x44, 0x44, 0xE2,
+ 0xA9, 0xB8, 0x65, 0x71, 0x76, 0x70, 0x61, 0x72, 0x73, 0x6C, 0xE2, 0xA7,
+ 0xA5, 0x65, 0x72, 0x44, 0x6F, 0x74, 0xE2, 0x89, 0x93, 0x65, 0x72, 0x61,
+ 0x72, 0x72, 0xE2, 0xA5, 0xB1, 0x65, 0x73, 0x63, 0x72, 0xE2, 0x84, 0xAF,
+ 0x65, 0x73, 0x64, 0x6F, 0x74, 0xE2, 0x89, 0x90, 0x65, 0x73, 0x69, 0x6D,
+ 0xE2, 0x89, 0x82, 0x65, 0x74, 0x61, 0xCE, 0xB7, 0x65, 0x74, 0x68, 0xC3,
+ 0xB0, 0x65, 0x75, 0x6D, 0x6C, 0xC3, 0xAB, 0x65, 0x75, 0x72, 0x6F, 0xE2,
+ 0x82, 0xAC, 0x65, 0x78, 0x63, 0x6C, 0x21, 0x65, 0x78, 0x69, 0x73, 0x74,
+ 0xE2, 0x88, 0x83, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x61, 0x74, 0x69,
+ 0x6F, 0x6E, 0xE2, 0x84, 0xB0, 0x65, 0x78, 0x70, 0x6F, 0x6E, 0x65, 0x6E,
+ 0x74, 0x69, 0x61, 0x6C, 0x65, 0xE2, 0x85, 0x87, 0x66, 0x61, 0x6C, 0x6C,
+ 0x69, 0x6E, 0x67, 0x64, 0x6F, 0x74, 0x73, 0x65, 0x71, 0xE2, 0x89, 0x92,
+ 0x66, 0x63, 0x79, 0xD1, 0x84, 0x66, 0x65, 0x6D, 0x61, 0x6C, 0x65, 0xE2,
+ 0x99, 0x80, 0x66, 0x66, 0x69, 0x6C, 0x69, 0x67, 0xEF, 0xAC, 0x83, 0x66,
+ 0x66, 0x6C, 0x69, 0x67, 0xEF, 0xAC, 0x80, 0x66, 0x66, 0x6C, 0x6C, 0x69,
+ 0x67, 0xEF, 0xAC, 0x84, 0x66, 0x66, 0x72, 0xF0, 0x9D, 0x94, 0xA3, 0x66,
+ 0x69, 0x6C, 0x69, 0x67, 0xEF, 0xAC, 0x81, 0x66, 0x6A, 0x6C, 0x69, 0x67,
+ 0x66, 0x6A, 0x66, 0x6C, 0x61, 0x74, 0xE2, 0x99, 0xAD, 0x66, 0x6C, 0x6C,
+ 0x69, 0x67, 0xEF, 0xAC, 0x82, 0x66, 0x6C, 0x74, 0x6E, 0x73, 0xE2, 0x96,
+ 0xB1, 0x66, 0x6E, 0x6F, 0x66, 0xC6, 0x92, 0x66, 0x6F, 0x70, 0x66, 0xF0,
+ 0x9D, 0x95, 0x97, 0x66, 0x6F, 0x72, 0x61, 0x6C, 0x6C, 0xE2, 0x88, 0x80,
+ 0x66, 0x6F, 0x72, 0x6B, 0xE2, 0x8B, 0x94, 0x66, 0x6F, 0x72, 0x6B, 0x76,
+ 0xE2, 0xAB, 0x99, 0x66, 0x70, 0x61, 0x72, 0x74, 0x69, 0x6E, 0x74, 0xE2,
+ 0xA8, 0x8D, 0x66, 0x72, 0x61, 0x63, 0x31, 0x32, 0xC2, 0xBD, 0x66, 0x72,
+ 0x61, 0x63, 0x31, 0x33, 0xE2, 0x85, 0x93, 0x66, 0x72, 0x61, 0x63, 0x31,
+ 0x34, 0xC2, 0xBC, 0x66, 0x72, 0x61, 0x63, 0x31, 0x35, 0xE2, 0x85, 0x95,
+ 0x66, 0x72, 0x61, 0x63, 0x31, 0x36, 0xE2, 0x85, 0x99, 0x66, 0x72, 0x61,
+ 0x63, 0x31, 0x38, 0xE2, 0x85, 0x9B, 0x66, 0x72, 0x61, 0x63, 0x32, 0x33,
+ 0xE2, 0x85, 0x94, 0x66, 0x72, 0x61, 0x63, 0x32, 0x35, 0xE2, 0x85, 0x96,
+ 0x66, 0x72, 0x61, 0x63, 0x33, 0x34, 0xC2, 0xBE, 0x66, 0x72, 0x61, 0x63,
+ 0x33, 0x35, 0xE2, 0x85, 0x97, 0x66, 0x72, 0x61, 0x63, 0x33, 0x38, 0xE2,
+ 0x85, 0x9C, 0x66, 0x72, 0x61, 0x63, 0x34, 0x35, 0xE2, 0x85, 0x98, 0x66,
+ 0x72, 0x61, 0x63, 0x35, 0x36, 0xE2, 0x85, 0x9A, 0x66, 0x72, 0x61, 0x63,
+ 0x35, 0x38, 0xE2, 0x85, 0x9D, 0x66, 0x72, 0x61, 0x63, 0x37, 0x38, 0xE2,
+ 0x85, 0x9E, 0x66, 0x72, 0x61, 0x73, 0x6C, 0xE2, 0x81, 0x84, 0x66, 0x72,
+ 0x6F, 0x77, 0x6E, 0xE2, 0x8C, 0xA2, 0x66, 0x73, 0x63, 0x72, 0xF0, 0x9D,
+ 0x92, 0xBB, 0x67, 0x45, 0xE2, 0x89, 0xA7, 0x67, 0x45, 0x6C, 0xE2, 0xAA,
+ 0x8C, 0x67, 0x61, 0x63, 0x75, 0x74, 0x65, 0xC7, 0xB5, 0x67, 0x61, 0x6D,
+ 0x6D, 0x61, 0xCE, 0xB3, 0x67, 0x61, 0x6D, 0x6D, 0x61, 0x64, 0xCF, 0x9D,
+ 0x67, 0x61, 0x70, 0xE2, 0xAA, 0x86, 0x67, 0x62, 0x72, 0x65, 0x76, 0x65,
+ 0xC4, 0x9F, 0x67, 0x63, 0x69, 0x72, 0x63, 0xC4, 0x9D, 0x67, 0x63, 0x79,
+ 0xD0, 0xB3, 0x67, 0x64, 0x6F, 0x74, 0xC4, 0xA1, 0x67, 0x65, 0xE2, 0x89,
+ 0xA5, 0x67, 0x65, 0x6C, 0xE2, 0x8B, 0x9B, 0x67, 0x65, 0x71, 0xE2, 0x89,
+ 0xA5, 0x67, 0x65, 0x71, 0x71, 0xE2, 0x89, 0xA7, 0x67, 0x65, 0x71, 0x73,
+ 0x6C, 0x61, 0x6E, 0x74, 0xE2, 0xA9, 0xBE, 0x67, 0x65, 0x73, 0xE2, 0xA9,
+ 0xBE, 0x67, 0x65, 0x73, 0x63, 0x63, 0xE2, 0xAA, 0xA9, 0x67, 0x65, 0x73,
+ 0x64, 0x6F, 0x74, 0xE2, 0xAA, 0x80, 0x67, 0x65, 0x73, 0x64, 0x6F, 0x74,
+ 0x6F, 0xE2, 0xAA, 0x82, 0x67, 0x65, 0x73, 0x64, 0x6F, 0x74, 0x6F, 0x6C,
+ 0xE2, 0xAA, 0x84, 0x67, 0x65, 0x73, 0x6C, 0xE2, 0x8B, 0x9B, 0xEF, 0xB8,
+ 0x80, 0x67, 0x65, 0x73, 0x6C, 0x65, 0x73, 0xE2, 0xAA, 0x94, 0x67, 0x66,
+ 0x72, 0xF0, 0x9D, 0x94, 0xA4, 0x67, 0x67, 0xE2, 0x89, 0xAB, 0x67, 0x67,
+ 0x67, 0xE2, 0x8B, 0x99, 0x67, 0x69, 0x6D, 0x65, 0x6C, 0xE2, 0x84, 0xB7,
+ 0x67, 0x6A, 0x63, 0x79, 0xD1, 0x93, 0x67, 0x6C, 0xE2, 0x89, 0xB7, 0x67,
+ 0x6C, 0x45, 0xE2, 0xAA, 0x92, 0x67, 0x6C, 0x61, 0xE2, 0xAA, 0xA5, 0x67,
+ 0x6C, 0x6A, 0xE2, 0xAA, 0xA4, 0x67, 0x6E, 0x45, 0xE2, 0x89, 0xA9, 0x67,
+ 0x6E, 0x61, 0x70, 0xE2, 0xAA, 0x8A, 0x67, 0x6E, 0x61, 0x70, 0x70, 0x72,
+ 0x6F, 0x78, 0xE2, 0xAA, 0x8A, 0x67, 0x6E, 0x65, 0xE2, 0xAA, 0x88, 0x67,
+ 0x6E, 0x65, 0x71, 0xE2, 0xAA, 0x88, 0x67, 0x6E, 0x65, 0x71, 0x71, 0xE2,
+ 0x89, 0xA9, 0x67, 0x6E, 0x73, 0x69, 0x6D, 0xE2, 0x8B, 0xA7, 0x67, 0x6F,
+ 0x70, 0x66, 0xF0, 0x9D, 0x95, 0x98, 0x67, 0x72, 0x61, 0x76, 0x65, 0x60,
+ 0x67, 0x73, 0x63, 0x72, 0xE2, 0x84, 0x8A, 0x67, 0x73, 0x69, 0x6D, 0xE2,
+ 0x89, 0xB3, 0x67, 0x73, 0x69, 0x6D, 0x65, 0xE2, 0xAA, 0x8E, 0x67, 0x73,
+ 0x69, 0x6D, 0x6C, 0xE2, 0xAA, 0x90, 0x67, 0x74, 0x3E, 0x67, 0x74, 0x63,
+ 0x63, 0xE2, 0xAA, 0xA7, 0x67, 0x74, 0x63, 0x69, 0x72, 0xE2, 0xA9, 0xBA,
+ 0x67, 0x74, 0x64, 0x6F, 0x74, 0xE2, 0x8B, 0x97, 0x67, 0x74, 0x6C, 0x50,
+ 0x61, 0x72, 0xE2, 0xA6, 0x95, 0x67, 0x74, 0x71, 0x75, 0x65, 0x73, 0x74,
+ 0xE2, 0xA9, 0xBC, 0x67, 0x74, 0x72, 0x61, 0x70, 0x70, 0x72, 0x6F, 0x78,
+ 0xE2, 0xAA, 0x86, 0x67, 0x74, 0x72, 0x61, 0x72, 0x72, 0xE2, 0xA5, 0xB8,
+ 0x67, 0x74, 0x72, 0x64, 0x6F, 0x74, 0xE2, 0x8B, 0x97, 0x67, 0x74, 0x72,
+ 0x65, 0x71, 0x6C, 0x65, 0x73, 0x73, 0xE2, 0x8B, 0x9B, 0x67, 0x74, 0x72,
+ 0x65, 0x71, 0x71, 0x6C, 0x65, 0x73, 0x73, 0xE2, 0xAA, 0x8C, 0x67, 0x74,
+ 0x72, 0x6C, 0x65, 0x73, 0x73, 0xE2, 0x89, 0xB7, 0x67, 0x74, 0x72, 0x73,
+ 0x69, 0x6D, 0xE2, 0x89, 0xB3, 0x67, 0x76, 0x65, 0x72, 0x74, 0x6E, 0x65,
+ 0x71, 0x71, 0xE2, 0x89, 0xA9, 0xEF, 0xB8, 0x80, 0x67, 0x76, 0x6E, 0x45,
+ 0xE2, 0x89, 0xA9, 0xEF, 0xB8, 0x80, 0x68, 0x41, 0x72, 0x72, 0xE2, 0x87,
+ 0x94, 0x68, 0x61, 0x69, 0x72, 0x73, 0x70, 0xE2, 0x80, 0x8A, 0x68, 0x61,
+ 0x6C, 0x66, 0xC2, 0xBD, 0x68, 0x61, 0x6D, 0x69, 0x6C, 0x74, 0xE2, 0x84,
+ 0x8B, 0x68, 0x61, 0x72, 0x64, 0x63, 0x79, 0xD1, 0x8A, 0x68, 0x61, 0x72,
+ 0x72, 0xE2, 0x86, 0x94, 0x68, 0x61, 0x72, 0x72, 0x63, 0x69, 0x72, 0xE2,
+ 0xA5, 0x88, 0x68, 0x61, 0x72, 0x72, 0x77, 0xE2, 0x86, 0xAD, 0x68, 0x62,
+ 0x61, 0x72, 0xE2, 0x84, 0x8F, 0x68, 0x63, 0x69, 0x72, 0x63, 0xC4, 0xA5,
+ 0x68, 0x65, 0x61, 0x72, 0x74, 0x73, 0xE2, 0x99, 0xA5, 0x68, 0x65, 0x61,
+ 0x72, 0x74, 0x73, 0x75, 0x69, 0x74, 0xE2, 0x99, 0xA5, 0x68, 0x65, 0x6C,
+ 0x6C, 0x69, 0x70, 0xE2, 0x80, 0xA6, 0x68, 0x65, 0x72, 0x63, 0x6F, 0x6E,
+ 0xE2, 0x8A, 0xB9, 0x68, 0x66, 0x72, 0xF0, 0x9D, 0x94, 0xA5, 0x68, 0x6B,
+ 0x73, 0x65, 0x61, 0x72, 0x6F, 0x77, 0xE2, 0xA4, 0xA5, 0x68, 0x6B, 0x73,
+ 0x77, 0x61, 0x72, 0x6F, 0x77, 0xE2, 0xA4, 0xA6, 0x68, 0x6F, 0x61, 0x72,
+ 0x72, 0xE2, 0x87, 0xBF, 0x68, 0x6F, 0x6D, 0x74, 0x68, 0x74, 0xE2, 0x88,
+ 0xBB, 0x68, 0x6F, 0x6F, 0x6B, 0x6C, 0x65, 0x66, 0x74, 0x61, 0x72, 0x72,
+ 0x6F, 0x77, 0xE2, 0x86, 0xA9, 0x68, 0x6F, 0x6F, 0x6B, 0x72, 0x69, 0x67,
+ 0x68, 0x74, 0x61, 0x72, 0x72, 0x6F, 0x77, 0xE2, 0x86, 0xAA, 0x68, 0x6F,
+ 0x70, 0x66, 0xF0, 0x9D, 0x95, 0x99, 0x68, 0x6F, 0x72, 0x62, 0x61, 0x72,
+ 0xE2, 0x80, 0x95, 0x68, 0x73, 0x63, 0x72, 0xF0, 0x9D, 0x92, 0xBD, 0x68,
+ 0x73, 0x6C, 0x61, 0x73, 0x68, 0xE2, 0x84, 0x8F, 0x68, 0x73, 0x74, 0x72,
+ 0x6F, 0x6B, 0xC4, 0xA7, 0x68, 0x79, 0x62, 0x75, 0x6C, 0x6C, 0xE2, 0x81,
+ 0x83, 0x68, 0x79, 0x70, 0x68, 0x65, 0x6E, 0xE2, 0x80, 0x90, 0x69, 0x61,
+ 0x63, 0x75, 0x74, 0x65, 0xC3, 0xAD, 0x69, 0x63, 0xE2, 0x81, 0xA3, 0x69,
+ 0x63, 0x69, 0x72, 0x63, 0xC3, 0xAE, 0x69, 0x63, 0x79, 0xD0, 0xB8, 0x69,
+ 0x65, 0x63, 0x79, 0xD0, 0xB5, 0x69, 0x65, 0x78, 0x63, 0x6C, 0xC2, 0xA1,
+ 0x69, 0x66, 0x66, 0xE2, 0x87, 0x94, 0x69, 0x66, 0x72, 0xF0, 0x9D, 0x94,
+ 0xA6, 0x69, 0x67, 0x72, 0x61, 0x76, 0x65, 0xC3, 0xAC, 0x69, 0x69, 0xE2,
+ 0x85, 0x88, 0x69, 0x69, 0x69, 0x69, 0x6E, 0x74, 0xE2, 0xA8, 0x8C, 0x69,
+ 0x69, 0x69, 0x6E, 0x74, 0xE2, 0x88, 0xAD, 0x69, 0x69, 0x6E, 0x66, 0x69,
+ 0x6E, 0xE2, 0xA7, 0x9C, 0x69, 0x69, 0x6F, 0x74, 0x61, 0xE2, 0x84, 0xA9,
+ 0x69, 0x6A, 0x6C, 0x69, 0x67, 0xC4, 0xB3, 0x69, 0x6D, 0x61, 0x63, 0x72,
+ 0xC4, 0xAB, 0x69, 0x6D, 0x61, 0x67, 0x65, 0xE2, 0x84, 0x91, 0x69, 0x6D,
+ 0x61, 0x67, 0x6C, 0x69, 0x6E, 0x65, 0xE2, 0x84, 0x90, 0x69, 0x6D, 0x61,
+ 0x67, 0x70, 0x61, 0x72, 0x74, 0xE2, 0x84, 0x91, 0x69, 0x6D, 0x61, 0x74,
+ 0x68, 0xC4, 0xB1, 0x69, 0x6D, 0x6F, 0x66, 0xE2, 0x8A, 0xB7, 0x69, 0x6D,
+ 0x70, 0x65, 0x64, 0xC6, 0xB5, 0x69, 0x6E, 0xE2, 0x88, 0x88, 0x69, 0x6E,
+ 0x63, 0x61, 0x72, 0x65, 0xE2, 0x84, 0x85, 0x69, 0x6E, 0x66, 0x69, 0x6E,
+ 0xE2, 0x88, 0x9E, 0x69, 0x6E, 0x66, 0x69, 0x6E, 0x74, 0x69, 0x65, 0xE2,
+ 0xA7, 0x9D, 0x69, 0x6E, 0x6F, 0x64, 0x6F, 0x74, 0xC4, 0xB1, 0x69, 0x6E,
+ 0x74, 0xE2, 0x88, 0xAB, 0x69, 0x6E, 0x74, 0x63, 0x61, 0x6C, 0xE2, 0x8A,
+ 0xBA, 0x69, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0x73, 0xE2, 0x84, 0xA4,
+ 0x69, 0x6E, 0x74, 0x65, 0x72, 0x63, 0x61, 0x6C, 0xE2, 0x8A, 0xBA, 0x69,
+ 0x6E, 0x74, 0x6C, 0x61, 0x72, 0x68, 0x6B, 0xE2, 0xA8, 0x97, 0x69, 0x6E,
+ 0x74, 0x70, 0x72, 0x6F, 0x64, 0xE2, 0xA8, 0xBC, 0x69, 0x6F, 0x63, 0x79,
+ 0xD1, 0x91, 0x69, 0x6F, 0x67, 0x6F, 0x6E, 0xC4, 0xAF, 0x69, 0x6F, 0x70,
+ 0x66, 0xF0, 0x9D, 0x95, 0x9A, 0x69, 0x6F, 0x74, 0x61, 0xCE, 0xB9, 0x69,
+ 0x70, 0x72, 0x6F, 0x64, 0xE2, 0xA8, 0xBC, 0x69, 0x71, 0x75, 0x65, 0x73,
+ 0x74, 0xC2, 0xBF, 0x69, 0x73, 0x63, 0x72, 0xF0, 0x9D, 0x92, 0xBE, 0x69,
+ 0x73, 0x69, 0x6E, 0xE2, 0x88, 0x88, 0x69, 0x73, 0x69, 0x6E, 0x45, 0xE2,
+ 0x8B, 0xB9, 0x69, 0x73, 0x69, 0x6E, 0x64, 0x6F, 0x74, 0xE2, 0x8B, 0xB5,
+ 0x69, 0x73, 0x69, 0x6E, 0x73, 0xE2, 0x8B, 0xB4, 0x69, 0x73, 0x69, 0x6E,
+ 0x73, 0x76, 0xE2, 0x8B, 0xB3, 0x69, 0x73, 0x69, 0x6E, 0x76, 0xE2, 0x88,
+ 0x88, 0x69, 0x74, 0xE2, 0x81, 0xA2, 0x69, 0x74, 0x69, 0x6C, 0x64, 0x65,
+ 0xC4, 0xA9, 0x69, 0x75, 0x6B, 0x63, 0x79, 0xD1, 0x96, 0x69, 0x75, 0x6D,
+ 0x6C, 0xC3, 0xAF, 0x6A, 0x63, 0x69, 0x72, 0x63, 0xC4, 0xB5, 0x6A, 0x63,
+ 0x79, 0xD0, 0xB9, 0x6A, 0x66, 0x72, 0xF0, 0x9D, 0x94, 0xA7, 0x6A, 0x6D,
+ 0x61, 0x74, 0x68, 0xC8, 0xB7, 0x6A, 0x6F, 0x70, 0x66, 0xF0, 0x9D, 0x95,
+ 0x9B, 0x6A, 0x73, 0x63, 0x72, 0xF0, 0x9D, 0x92, 0xBF, 0x6A, 0x73, 0x65,
+ 0x72, 0x63, 0x79, 0xD1, 0x98, 0x6A, 0x75, 0x6B, 0x63, 0x79, 0xD1, 0x94,
+ 0x6B, 0x61, 0x70, 0x70, 0x61, 0xCE, 0xBA, 0x6B, 0x61, 0x70, 0x70, 0x61,
+ 0x76, 0xCF, 0xB0, 0x6B, 0x63, 0x65, 0x64, 0x69, 0x6C, 0xC4, 0xB7, 0x6B,
+ 0x63, 0x79, 0xD0, 0xBA, 0x6B, 0x66, 0x72, 0xF0, 0x9D, 0x94, 0xA8, 0x6B,
+ 0x67, 0x72, 0x65, 0x65, 0x6E, 0xC4, 0xB8, 0x6B, 0x68, 0x63, 0x79, 0xD1,
+ 0x85, 0x6B, 0x6A, 0x63, 0x79, 0xD1, 0x9C, 0x6B, 0x6F, 0x70, 0x66, 0xF0,
+ 0x9D, 0x95, 0x9C, 0x6B, 0x73, 0x63, 0x72, 0xF0, 0x9D, 0x93, 0x80, 0x6C,
+ 0x41, 0x61, 0x72, 0x72, 0xE2, 0x87, 0x9A, 0x6C, 0x41, 0x72, 0x72, 0xE2,
+ 0x87, 0x90, 0x6C, 0x41, 0x74, 0x61, 0x69, 0x6C, 0xE2, 0xA4, 0x9B, 0x6C,
+ 0x42, 0x61, 0x72, 0x72, 0xE2, 0xA4, 0x8E, 0x6C, 0x45, 0xE2, 0x89, 0xA6,
+ 0x6C, 0x45, 0x67, 0xE2, 0xAA, 0x8B, 0x6C, 0x48, 0x61, 0x72, 0xE2, 0xA5,
+ 0xA2, 0x6C, 0x61, 0x63, 0x75, 0x74, 0x65, 0xC4, 0xBA, 0x6C, 0x61, 0x65,
+ 0x6D, 0x70, 0x74, 0x79, 0x76, 0xE2, 0xA6, 0xB4, 0x6C, 0x61, 0x67, 0x72,
+ 0x61, 0x6E, 0xE2, 0x84, 0x92, 0x6C, 0x61, 0x6D, 0x62, 0x64, 0x61, 0xCE,
+ 0xBB, 0x6C, 0x61, 0x6E, 0x67, 0xE2, 0x9F, 0xA8, 0x6C, 0x61, 0x6E, 0x67,
+ 0x64, 0xE2, 0xA6, 0x91, 0x6C, 0x61, 0x6E, 0x67, 0x6C, 0x65, 0xE2, 0x9F,
+ 0xA8, 0x6C, 0x61, 0x70, 0xE2, 0xAA, 0x85, 0x6C, 0x61, 0x71, 0x75, 0x6F,
+ 0xC2, 0xAB, 0x6C, 0x61, 0x72, 0x72, 0xE2, 0x86, 0x90, 0x6C, 0x61, 0x72,
+ 0x72, 0x62, 0xE2, 0x87, 0xA4, 0x6C, 0x61, 0x72, 0x72, 0x62, 0x66, 0x73,
+ 0xE2, 0xA4, 0x9F, 0x6C, 0x61, 0x72, 0x72, 0x66, 0x73, 0xE2, 0xA4, 0x9D,
+ 0x6C, 0x61, 0x72, 0x72, 0x68, 0x6B, 0xE2, 0x86, 0xA9, 0x6C, 0x61, 0x72,
+ 0x72, 0x6C, 0x70, 0xE2, 0x86, 0xAB, 0x6C, 0x61, 0x72, 0x72, 0x70, 0x6C,
+ 0xE2, 0xA4, 0xB9, 0x6C, 0x61, 0x72, 0x72, 0x73, 0x69, 0x6D, 0xE2, 0xA5,
+ 0xB3, 0x6C, 0x61, 0x72, 0x72, 0x74, 0x6C, 0xE2, 0x86, 0xA2, 0x6C, 0x61,
+ 0x74, 0xE2, 0xAA, 0xAB, 0x6C, 0x61, 0x74, 0x61, 0x69, 0x6C, 0xE2, 0xA4,
+ 0x99, 0x6C, 0x61, 0x74, 0x65, 0xE2, 0xAA, 0xAD, 0x6C, 0x61, 0x74, 0x65,
+ 0x73, 0xE2, 0xAA, 0xAD, 0xEF, 0xB8, 0x80, 0x6C, 0x62, 0x61, 0x72, 0x72,
+ 0xE2, 0xA4, 0x8C, 0x6C, 0x62, 0x62, 0x72, 0x6B, 0xE2, 0x9D, 0xB2, 0x6C,
+ 0x62, 0x72, 0x61, 0x63, 0x65, 0x7B, 0x6C, 0x62, 0x72, 0x61, 0x63, 0x6B,
+ 0x5B, 0x6C, 0x62, 0x72, 0x6B, 0x65, 0xE2, 0xA6, 0x8B, 0x6C, 0x62, 0x72,
+ 0x6B, 0x73, 0x6C, 0x64, 0xE2, 0xA6, 0x8F, 0x6C, 0x62, 0x72, 0x6B, 0x73,
+ 0x6C, 0x75, 0xE2, 0xA6, 0x8D, 0x6C, 0x63, 0x61, 0x72, 0x6F, 0x6E, 0xC4,
+ 0xBE, 0x6C, 0x63, 0x65, 0x64, 0x69, 0x6C, 0xC4, 0xBC, 0x6C, 0x63, 0x65,
+ 0x69, 0x6C, 0xE2, 0x8C, 0x88, 0x6C, 0x63, 0x75, 0x62, 0x7B, 0x6C, 0x63,
+ 0x79, 0xD0, 0xBB, 0x6C, 0x64, 0x63, 0x61, 0xE2, 0xA4, 0xB6, 0x6C, 0x64,
+ 0x71, 0x75, 0x6F, 0xE2, 0x80, 0x9C, 0x6C, 0x64, 0x71, 0x75, 0x6F, 0x72,
+ 0xE2, 0x80, 0x9E, 0x6C, 0x64, 0x72, 0x64, 0x68, 0x61, 0x72, 0xE2, 0xA5,
+ 0xA7, 0x6C, 0x64, 0x72, 0x75, 0x73, 0x68, 0x61, 0x72, 0xE2, 0xA5, 0x8B,
+ 0x6C, 0x64, 0x73, 0x68, 0xE2, 0x86, 0xB2, 0x6C, 0x65, 0xE2, 0x89, 0xA4,
+ 0x6C, 0x65, 0x66, 0x74, 0x61, 0x72, 0x72, 0x6F, 0x77, 0xE2, 0x86, 0x90,
+ 0x6C, 0x65, 0x66, 0x74, 0x61, 0x72, 0x72, 0x6F, 0x77, 0x74, 0x61, 0x69,
+ 0x6C, 0xE2, 0x86, 0xA2, 0x6C, 0x65, 0x66, 0x74, 0x68, 0x61, 0x72, 0x70,
+ 0x6F, 0x6F, 0x6E, 0x64, 0x6F, 0x77, 0x6E, 0xE2, 0x86, 0xBD, 0x6C, 0x65,
+ 0x66, 0x74, 0x68, 0x61, 0x72, 0x70, 0x6F, 0x6F, 0x6E, 0x75, 0x70, 0xE2,
+ 0x86, 0xBC, 0x6C, 0x65, 0x66, 0x74, 0x6C, 0x65, 0x66, 0x74, 0x61, 0x72,
+ 0x72, 0x6F, 0x77, 0x73, 0xE2, 0x87, 0x87, 0x6C, 0x65, 0x66, 0x74, 0x72,
+ 0x69, 0x67, 0x68, 0x74, 0x61, 0x72, 0x72, 0x6F, 0x77, 0xE2, 0x86, 0x94,
+ 0x6C, 0x65, 0x66, 0x74, 0x72, 0x69, 0x67, 0x68, 0x74, 0x61, 0x72, 0x72,
+ 0x6F, 0x77, 0x73, 0xE2, 0x87, 0x86, 0x6C, 0x65, 0x66, 0x74, 0x72, 0x69,
+ 0x67, 0x68, 0x74, 0x68, 0x61, 0x72, 0x70, 0x6F, 0x6F, 0x6E, 0x73, 0xE2,
+ 0x87, 0x8B, 0x6C, 0x65, 0x66, 0x74, 0x72, 0x69, 0x67, 0x68, 0x74, 0x73,
+ 0x71, 0x75, 0x69, 0x67, 0x61, 0x72, 0x72, 0x6F, 0x77, 0xE2, 0x86, 0xAD,
+ 0x6C, 0x65, 0x66, 0x74, 0x74, 0x68, 0x72, 0x65, 0x65, 0x74, 0x69, 0x6D,
+ 0x65, 0x73, 0xE2, 0x8B, 0x8B, 0x6C, 0x65, 0x67, 0xE2, 0x8B, 0x9A, 0x6C,
+ 0x65, 0x71, 0xE2, 0x89, 0xA4, 0x6C, 0x65, 0x71, 0x71, 0xE2, 0x89, 0xA6,
+ 0x6C, 0x65, 0x71, 0x73, 0x6C, 0x61, 0x6E, 0x74, 0xE2, 0xA9, 0xBD, 0x6C,
+ 0x65, 0x73, 0xE2, 0xA9, 0xBD, 0x6C, 0x65, 0x73, 0x63, 0x63, 0xE2, 0xAA,
+ 0xA8, 0x6C, 0x65, 0x73, 0x64, 0x6F, 0x74, 0xE2, 0xA9, 0xBF, 0x6C, 0x65,
+ 0x73, 0x64, 0x6F, 0x74, 0x6F, 0xE2, 0xAA, 0x81, 0x6C, 0x65, 0x73, 0x64,
+ 0x6F, 0x74, 0x6F, 0x72, 0xE2, 0xAA, 0x83, 0x6C, 0x65, 0x73, 0x67, 0xE2,
+ 0x8B, 0x9A, 0xEF, 0xB8, 0x80, 0x6C, 0x65, 0x73, 0x67, 0x65, 0x73, 0xE2,
+ 0xAA, 0x93, 0x6C, 0x65, 0x73, 0x73, 0x61, 0x70, 0x70, 0x72, 0x6F, 0x78,
+ 0xE2, 0xAA, 0x85, 0x6C, 0x65, 0x73, 0x73, 0x64, 0x6F, 0x74, 0xE2, 0x8B,
+ 0x96, 0x6C, 0x65, 0x73, 0x73, 0x65, 0x71, 0x67, 0x74, 0x72, 0xE2, 0x8B,
+ 0x9A, 0x6C, 0x65, 0x73, 0x73, 0x65, 0x71, 0x71, 0x67, 0x74, 0x72, 0xE2,
+ 0xAA, 0x8B, 0x6C, 0x65, 0x73, 0x73, 0x67, 0x74, 0x72, 0xE2, 0x89, 0xB6,
+ 0x6C, 0x65, 0x73, 0x73, 0x73, 0x69, 0x6D, 0xE2, 0x89, 0xB2, 0x6C, 0x66,
+ 0x69, 0x73, 0x68, 0x74, 0xE2, 0xA5, 0xBC, 0x6C, 0x66, 0x6C, 0x6F, 0x6F,
+ 0x72, 0xE2, 0x8C, 0x8A, 0x6C, 0x66, 0x72, 0xF0, 0x9D, 0x94, 0xA9, 0x6C,
+ 0x67, 0xE2, 0x89, 0xB6, 0x6C, 0x67, 0x45, 0xE2, 0xAA, 0x91, 0x6C, 0x68,
+ 0x61, 0x72, 0x64, 0xE2, 0x86, 0xBD, 0x6C, 0x68, 0x61, 0x72, 0x75, 0xE2,
+ 0x86, 0xBC, 0x6C, 0x68, 0x61, 0x72, 0x75, 0x6C, 0xE2, 0xA5, 0xAA, 0x6C,
+ 0x68, 0x62, 0x6C, 0x6B, 0xE2, 0x96, 0x84, 0x6C, 0x6A, 0x63, 0x79, 0xD1,
+ 0x99, 0x6C, 0x6C, 0xE2, 0x89, 0xAA, 0x6C, 0x6C, 0x61, 0x72, 0x72, 0xE2,
+ 0x87, 0x87, 0x6C, 0x6C, 0x63, 0x6F, 0x72, 0x6E, 0x65, 0x72, 0xE2, 0x8C,
+ 0x9E, 0x6C, 0x6C, 0x68, 0x61, 0x72, 0x64, 0xE2, 0xA5, 0xAB, 0x6C, 0x6C,
+ 0x74, 0x72, 0x69, 0xE2, 0x97, 0xBA, 0x6C, 0x6D, 0x69, 0x64, 0x6F, 0x74,
+ 0xC5, 0x80, 0x6C, 0x6D, 0x6F, 0x75, 0x73, 0x74, 0xE2, 0x8E, 0xB0, 0x6C,
+ 0x6D, 0x6F, 0x75, 0x73, 0x74, 0x61, 0x63, 0x68, 0x65, 0xE2, 0x8E, 0xB0,
+ 0x6C, 0x6E, 0x45, 0xE2, 0x89, 0xA8, 0x6C, 0x6E, 0x61, 0x70, 0xE2, 0xAA,
+ 0x89, 0x6C, 0x6E, 0x61, 0x70, 0x70, 0x72, 0x6F, 0x78, 0xE2, 0xAA, 0x89,
+ 0x6C, 0x6E, 0x65, 0xE2, 0xAA, 0x87, 0x6C, 0x6E, 0x65, 0x71, 0xE2, 0xAA,
+ 0x87, 0x6C, 0x6E, 0x65, 0x71, 0x71, 0xE2, 0x89, 0xA8, 0x6C, 0x6E, 0x73,
+ 0x69, 0x6D, 0xE2, 0x8B, 0xA6, 0x6C, 0x6F, 0x61, 0x6E, 0x67, 0xE2, 0x9F,
+ 0xAC, 0x6C, 0x6F, 0x61, 0x72, 0x72, 0xE2, 0x87, 0xBD, 0x6C, 0x6F, 0x62,
+ 0x72, 0x6B, 0xE2, 0x9F, 0xA6, 0x6C, 0x6F, 0x6E, 0x67, 0x6C, 0x65, 0x66,
+ 0x74, 0x61, 0x72, 0x72, 0x6F, 0x77, 0xE2, 0x9F, 0xB5, 0x6C, 0x6F, 0x6E,
+ 0x67, 0x6C, 0x65, 0x66, 0x74, 0x72, 0x69, 0x67, 0x68, 0x74, 0x61, 0x72,
+ 0x72, 0x6F, 0x77, 0xE2, 0x9F, 0xB7, 0x6C, 0x6F, 0x6E, 0x67, 0x6D, 0x61,
+ 0x70, 0x73, 0x74, 0x6F, 0xE2, 0x9F, 0xBC, 0x6C, 0x6F, 0x6E, 0x67, 0x72,
+ 0x69, 0x67, 0x68, 0x74, 0x61, 0x72, 0x72, 0x6F, 0x77, 0xE2, 0x9F, 0xB6,
+ 0x6C, 0x6F, 0x6F, 0x70, 0x61, 0x72, 0x72, 0x6F, 0x77, 0x6C, 0x65, 0x66,
+ 0x74, 0xE2, 0x86, 0xAB, 0x6C, 0x6F, 0x6F, 0x70, 0x61, 0x72, 0x72, 0x6F,
+ 0x77, 0x72, 0x69, 0x67, 0x68, 0x74, 0xE2, 0x86, 0xAC, 0x6C, 0x6F, 0x70,
+ 0x61, 0x72, 0xE2, 0xA6, 0x85, 0x6C, 0x6F, 0x70, 0x66, 0xF0, 0x9D, 0x95,
+ 0x9D, 0x6C, 0x6F, 0x70, 0x6C, 0x75, 0x73, 0xE2, 0xA8, 0xAD, 0x6C, 0x6F,
+ 0x74, 0x69, 0x6D, 0x65, 0x73, 0xE2, 0xA8, 0xB4, 0x6C, 0x6F, 0x77, 0x61,
+ 0x73, 0x74, 0xE2, 0x88, 0x97, 0x6C, 0x6F, 0x77, 0x62, 0x61, 0x72, 0x5F,
+ 0x6C, 0x6F, 0x7A, 0xE2, 0x97, 0x8A, 0x6C, 0x6F, 0x7A, 0x65, 0x6E, 0x67,
+ 0x65, 0xE2, 0x97, 0x8A, 0x6C, 0x6F, 0x7A, 0x66, 0xE2, 0xA7, 0xAB, 0x6C,
+ 0x70, 0x61, 0x72, 0x28, 0x6C, 0x70, 0x61, 0x72, 0x6C, 0x74, 0xE2, 0xA6,
+ 0x93, 0x6C, 0x72, 0x61, 0x72, 0x72, 0xE2, 0x87, 0x86, 0x6C, 0x72, 0x63,
+ 0x6F, 0x72, 0x6E, 0x65, 0x72, 0xE2, 0x8C, 0x9F, 0x6C, 0x72, 0x68, 0x61,
+ 0x72, 0xE2, 0x87, 0x8B, 0x6C, 0x72, 0x68, 0x61, 0x72, 0x64, 0xE2, 0xA5,
+ 0xAD, 0x6C, 0x72, 0x6D, 0xE2, 0x80, 0x8E, 0x6C, 0x72, 0x74, 0x72, 0x69,
+ 0xE2, 0x8A, 0xBF, 0x6C, 0x73, 0x61, 0x71, 0x75, 0x6F, 0xE2, 0x80, 0xB9,
+ 0x6C, 0x73, 0x63, 0x72, 0xF0, 0x9D, 0x93, 0x81, 0x6C, 0x73, 0x68, 0xE2,
+ 0x86, 0xB0, 0x6C, 0x73, 0x69, 0x6D, 0xE2, 0x89, 0xB2, 0x6C, 0x73, 0x69,
+ 0x6D, 0x65, 0xE2, 0xAA, 0x8D, 0x6C, 0x73, 0x69, 0x6D, 0x67, 0xE2, 0xAA,
+ 0x8F, 0x6C, 0x73, 0x71, 0x62, 0x5B, 0x6C, 0x73, 0x71, 0x75, 0x6F, 0xE2,
+ 0x80, 0x98, 0x6C, 0x73, 0x71, 0x75, 0x6F, 0x72, 0xE2, 0x80, 0x9A, 0x6C,
+ 0x73, 0x74, 0x72, 0x6F, 0x6B, 0xC5, 0x82, 0x6C, 0x74, 0x3C, 0x6C, 0x74,
+ 0x63, 0x63, 0xE2, 0xAA, 0xA6, 0x6C, 0x74, 0x63, 0x69, 0x72, 0xE2, 0xA9,
+ 0xB9, 0x6C, 0x74, 0x64, 0x6F, 0x74, 0xE2, 0x8B, 0x96, 0x6C, 0x74, 0x68,
+ 0x72, 0x65, 0x65, 0xE2, 0x8B, 0x8B, 0x6C, 0x74, 0x69, 0x6D, 0x65, 0x73,
+ 0xE2, 0x8B, 0x89, 0x6C, 0x74, 0x6C, 0x61, 0x72, 0x72, 0xE2, 0xA5, 0xB6,
+ 0x6C, 0x74, 0x71, 0x75, 0x65, 0x73, 0x74, 0xE2, 0xA9, 0xBB, 0x6C, 0x74,
+ 0x72, 0x50, 0x61, 0x72, 0xE2, 0xA6, 0x96, 0x6C, 0x74, 0x72, 0x69, 0xE2,
+ 0x97, 0x83, 0x6C, 0x74, 0x72, 0x69, 0x65, 0xE2, 0x8A, 0xB4, 0x6C, 0x74,
+ 0x72, 0x69, 0x66, 0xE2, 0x97, 0x82, 0x6C, 0x75, 0x72, 0x64, 0x73, 0x68,
+ 0x61, 0x72, 0xE2, 0xA5, 0x8A, 0x6C, 0x75, 0x72, 0x75, 0x68, 0x61, 0x72,
+ 0xE2, 0xA5, 0xA6, 0x6C, 0x76, 0x65, 0x72, 0x74, 0x6E, 0x65, 0x71, 0x71,
+ 0xE2, 0x89, 0xA8, 0xEF, 0xB8, 0x80, 0x6C, 0x76, 0x6E, 0x45, 0xE2, 0x89,
+ 0xA8, 0xEF, 0xB8, 0x80, 0x6D, 0x44, 0x44, 0x6F, 0x74, 0xE2, 0x88, 0xBA,
+ 0x6D, 0x61, 0x63, 0x72, 0xC2, 0xAF, 0x6D, 0x61, 0x6C, 0x65, 0xE2, 0x99,
+ 0x82, 0x6D, 0x61, 0x6C, 0x74, 0xE2, 0x9C, 0xA0, 0x6D, 0x61, 0x6C, 0x74,
+ 0x65, 0x73, 0x65, 0xE2, 0x9C, 0xA0, 0x6D, 0x61, 0x70, 0xE2, 0x86, 0xA6,
+ 0x6D, 0x61, 0x70, 0x73, 0x74, 0x6F, 0xE2, 0x86, 0xA6, 0x6D, 0x61, 0x70,
+ 0x73, 0x74, 0x6F, 0x64, 0x6F, 0x77, 0x6E, 0xE2, 0x86, 0xA7, 0x6D, 0x61,
+ 0x70, 0x73, 0x74, 0x6F, 0x6C, 0x65, 0x66, 0x74, 0xE2, 0x86, 0xA4, 0x6D,
+ 0x61, 0x70, 0x73, 0x74, 0x6F, 0x75, 0x70, 0xE2, 0x86, 0xA5, 0x6D, 0x61,
+ 0x72, 0x6B, 0x65, 0x72, 0xE2, 0x96, 0xAE, 0x6D, 0x63, 0x6F, 0x6D, 0x6D,
+ 0x61, 0xE2, 0xA8, 0xA9, 0x6D, 0x63, 0x79, 0xD0, 0xBC, 0x6D, 0x64, 0x61,
+ 0x73, 0x68, 0xE2, 0x80, 0x94, 0x6D, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65,
+ 0x64, 0x61, 0x6E, 0x67, 0x6C, 0x65, 0xE2, 0x88, 0xA1, 0x6D, 0x66, 0x72,
+ 0xF0, 0x9D, 0x94, 0xAA, 0x6D, 0x68, 0x6F, 0xE2, 0x84, 0xA7, 0x6D, 0x69,
+ 0x63, 0x72, 0x6F, 0xC2, 0xB5, 0x6D, 0x69, 0x64, 0xE2, 0x88, 0xA3, 0x6D,
+ 0x69, 0x64, 0x61, 0x73, 0x74, 0x2A, 0x6D, 0x69, 0x64, 0x63, 0x69, 0x72,
+ 0xE2, 0xAB, 0xB0, 0x6D, 0x69, 0x64, 0x64, 0x6F, 0x74, 0xC2, 0xB7, 0x6D,
+ 0x69, 0x6E, 0x75, 0x73, 0xE2, 0x88, 0x92, 0x6D, 0x69, 0x6E, 0x75, 0x73,
+ 0x62, 0xE2, 0x8A, 0x9F, 0x6D, 0x69, 0x6E, 0x75, 0x73, 0x64, 0xE2, 0x88,
+ 0xB8, 0x6D, 0x69, 0x6E, 0x75, 0x73, 0x64, 0x75, 0xE2, 0xA8, 0xAA, 0x6D,
+ 0x6C, 0x63, 0x70, 0xE2, 0xAB, 0x9B, 0x6D, 0x6C, 0x64, 0x72, 0xE2, 0x80,
+ 0xA6, 0x6D, 0x6E, 0x70, 0x6C, 0x75, 0x73, 0xE2, 0x88, 0x93, 0x6D, 0x6F,
+ 0x64, 0x65, 0x6C, 0x73, 0xE2, 0x8A, 0xA7, 0x6D, 0x6F, 0x70, 0x66, 0xF0,
+ 0x9D, 0x95, 0x9E, 0x6D, 0x70, 0xE2, 0x88, 0x93, 0x6D, 0x73, 0x63, 0x72,
+ 0xF0, 0x9D, 0x93, 0x82, 0x6D, 0x73, 0x74, 0x70, 0x6F, 0x73, 0xE2, 0x88,
+ 0xBE, 0x6D, 0x75, 0xCE, 0xBC, 0x6D, 0x75, 0x6C, 0x74, 0x69, 0x6D, 0x61,
+ 0x70, 0xE2, 0x8A, 0xB8, 0x6D, 0x75, 0x6D, 0x61, 0x70, 0xE2, 0x8A, 0xB8,
+ 0x6E, 0x47, 0x67, 0xE2, 0x8B, 0x99, 0xCC, 0xB8, 0x6E, 0x47, 0x74, 0xE2,
+ 0x89, 0xAB, 0xE2, 0x83, 0x92, 0x6E, 0x47, 0x74, 0x76, 0xE2, 0x89, 0xAB,
+ 0xCC, 0xB8, 0x6E, 0x4C, 0x65, 0x66, 0x74, 0x61, 0x72, 0x72, 0x6F, 0x77,
+ 0xE2, 0x87, 0x8D, 0x6E, 0x4C, 0x65, 0x66, 0x74, 0x72, 0x69, 0x67, 0x68,
+ 0x74, 0x61, 0x72, 0x72, 0x6F, 0x77, 0xE2, 0x87, 0x8E, 0x6E, 0x4C, 0x6C,
+ 0xE2, 0x8B, 0x98, 0xCC, 0xB8, 0x6E, 0x4C, 0x74, 0xE2, 0x89, 0xAA, 0xE2,
+ 0x83, 0x92, 0x6E, 0x4C, 0x74, 0x76, 0xE2, 0x89, 0xAA, 0xCC, 0xB8, 0x6E,
+ 0x52, 0x69, 0x67, 0x68, 0x74, 0x61, 0x72, 0x72, 0x6F, 0x77, 0xE2, 0x87,
+ 0x8F, 0x6E, 0x56, 0x44, 0x61, 0x73, 0x68, 0xE2, 0x8A, 0xAF, 0x6E, 0x56,
+ 0x64, 0x61, 0x73, 0x68, 0xE2, 0x8A, 0xAE, 0x6E, 0x61, 0x62, 0x6C, 0x61,
+ 0xE2, 0x88, 0x87, 0x6E, 0x61, 0x63, 0x75, 0x74, 0x65, 0xC5, 0x84, 0x6E,
+ 0x61, 0x6E, 0x67, 0xE2, 0x88, 0xA0, 0xE2, 0x83, 0x92, 0x6E, 0x61, 0x70,
+ 0xE2, 0x89, 0x89, 0x6E, 0x61, 0x70, 0x45, 0xE2, 0xA9, 0xB0, 0xCC, 0xB8,
+ 0x6E, 0x61, 0x70, 0x69, 0x64, 0xE2, 0x89, 0x8B, 0xCC, 0xB8, 0x6E, 0x61,
+ 0x70, 0x6F, 0x73, 0xC5, 0x89, 0x6E, 0x61, 0x70, 0x70, 0x72, 0x6F, 0x78,
+ 0xE2, 0x89, 0x89, 0x6E, 0x61, 0x74, 0x75, 0x72, 0xE2, 0x99, 0xAE, 0x6E,
+ 0x61, 0x74, 0x75, 0x72, 0x61, 0x6C, 0xE2, 0x99, 0xAE, 0x6E, 0x61, 0x74,
+ 0x75, 0x72, 0x61, 0x6C, 0x73, 0xE2, 0x84, 0x95, 0x6E, 0x62, 0x73, 0x70,
+ 0xC2, 0xA0, 0x6E, 0x62, 0x75, 0x6D, 0x70, 0xE2, 0x89, 0x8E, 0xCC, 0xB8,
+ 0x6E, 0x62, 0x75, 0x6D, 0x70, 0x65, 0xE2, 0x89, 0x8F, 0xCC, 0xB8, 0x6E,
+ 0x63, 0x61, 0x70, 0xE2, 0xA9, 0x83, 0x6E, 0x63, 0x61, 0x72, 0x6F, 0x6E,
+ 0xC5, 0x88, 0x6E, 0x63, 0x65, 0x64, 0x69, 0x6C, 0xC5, 0x86, 0x6E, 0x63,
+ 0x6F, 0x6E, 0x67, 0xE2, 0x89, 0x87, 0x6E, 0x63, 0x6F, 0x6E, 0x67, 0x64,
+ 0x6F, 0x74, 0xE2, 0xA9, 0xAD, 0xCC, 0xB8, 0x6E, 0x63, 0x75, 0x70, 0xE2,
+ 0xA9, 0x82, 0x6E, 0x63, 0x79, 0xD0, 0xBD, 0x6E, 0x64, 0x61, 0x73, 0x68,
+ 0xE2, 0x80, 0x93, 0x6E, 0x65, 0xE2, 0x89, 0xA0, 0x6E, 0x65, 0x41, 0x72,
+ 0x72, 0xE2, 0x87, 0x97, 0x6E, 0x65, 0x61, 0x72, 0x68, 0x6B, 0xE2, 0xA4,
+ 0xA4, 0x6E, 0x65, 0x61, 0x72, 0x72, 0xE2, 0x86, 0x97, 0x6E, 0x65, 0x61,
+ 0x72, 0x72, 0x6F, 0x77, 0xE2, 0x86, 0x97, 0x6E, 0x65, 0x64, 0x6F, 0x74,
+ 0xE2, 0x89, 0x90, 0xCC, 0xB8, 0x6E, 0x65, 0x71, 0x75, 0x69, 0x76, 0xE2,
+ 0x89, 0xA2, 0x6E, 0x65, 0x73, 0x65, 0x61, 0x72, 0xE2, 0xA4, 0xA8, 0x6E,
+ 0x65, 0x73, 0x69, 0x6D, 0xE2, 0x89, 0x82, 0xCC, 0xB8, 0x6E, 0x65, 0x78,
+ 0x69, 0x73, 0x74, 0xE2, 0x88, 0x84, 0x6E, 0x65, 0x78, 0x69, 0x73, 0x74,
+ 0x73, 0xE2, 0x88, 0x84, 0x6E, 0x66, 0x72, 0xF0, 0x9D, 0x94, 0xAB, 0x6E,
+ 0x67, 0x45, 0xE2, 0x89, 0xA7, 0xCC, 0xB8, 0x6E, 0x67, 0x65, 0xE2, 0x89,
+ 0xB1, 0x6E, 0x67, 0x65, 0x71, 0xE2, 0x89, 0xB1, 0x6E, 0x67, 0x65, 0x71,
+ 0x71, 0xE2, 0x89, 0xA7, 0xCC, 0xB8, 0x6E, 0x67, 0x65, 0x71, 0x73, 0x6C,
+ 0x61, 0x6E, 0x74, 0xE2, 0xA9, 0xBE, 0xCC, 0xB8, 0x6E, 0x67, 0x65, 0x73,
+ 0xE2, 0xA9, 0xBE, 0xCC, 0xB8, 0x6E, 0x67, 0x73, 0x69, 0x6D, 0xE2, 0x89,
+ 0xB5, 0x6E, 0x67, 0x74, 0xE2, 0x89, 0xAF, 0x6E, 0x67, 0x74, 0x72, 0xE2,
+ 0x89, 0xAF, 0x6E, 0x68, 0x41, 0x72, 0x72, 0xE2, 0x87, 0x8E, 0x6E, 0x68,
+ 0x61, 0x72, 0x72, 0xE2, 0x86, 0xAE, 0x6E, 0x68, 0x70, 0x61, 0x72, 0xE2,
+ 0xAB, 0xB2, 0x6E, 0x69, 0xE2, 0x88, 0x8B, 0x6E, 0x69, 0x73, 0xE2, 0x8B,
+ 0xBC, 0x6E, 0x69, 0x73, 0x64, 0xE2, 0x8B, 0xBA, 0x6E, 0x69, 0x76, 0xE2,
+ 0x88, 0x8B, 0x6E, 0x6A, 0x63, 0x79, 0xD1, 0x9A, 0x6E, 0x6C, 0x41, 0x72,
+ 0x72, 0xE2, 0x87, 0x8D, 0x6E, 0x6C, 0x45, 0xE2, 0x89, 0xA6, 0xCC, 0xB8,
+ 0x6E, 0x6C, 0x61, 0x72, 0x72, 0xE2, 0x86, 0x9A, 0x6E, 0x6C, 0x64, 0x72,
+ 0xE2, 0x80, 0xA5, 0x6E, 0x6C, 0x65, 0xE2, 0x89, 0xB0, 0x6E, 0x6C, 0x65,
+ 0x66, 0x74, 0x61, 0x72, 0x72, 0x6F, 0x77, 0xE2, 0x86, 0x9A, 0x6E, 0x6C,
+ 0x65, 0x66, 0x74, 0x72, 0x69, 0x67, 0x68, 0x74, 0x61, 0x72, 0x72, 0x6F,
+ 0x77, 0xE2, 0x86, 0xAE, 0x6E, 0x6C, 0x65, 0x71, 0xE2, 0x89, 0xB0, 0x6E,
+ 0x6C, 0x65, 0x71, 0x71, 0xE2, 0x89, 0xA6, 0xCC, 0xB8, 0x6E, 0x6C, 0x65,
+ 0x71, 0x73, 0x6C, 0x61, 0x6E, 0x74, 0xE2, 0xA9, 0xBD, 0xCC, 0xB8, 0x6E,
+ 0x6C, 0x65, 0x73, 0xE2, 0xA9, 0xBD, 0xCC, 0xB8, 0x6E, 0x6C, 0x65, 0x73,
+ 0x73, 0xE2, 0x89, 0xAE, 0x6E, 0x6C, 0x73, 0x69, 0x6D, 0xE2, 0x89, 0xB4,
+ 0x6E, 0x6C, 0x74, 0xE2, 0x89, 0xAE, 0x6E, 0x6C, 0x74, 0x72, 0x69, 0xE2,
+ 0x8B, 0xAA, 0x6E, 0x6C, 0x74, 0x72, 0x69, 0x65, 0xE2, 0x8B, 0xAC, 0x6E,
+ 0x6D, 0x69, 0x64, 0xE2, 0x88, 0xA4, 0x6E, 0x6F, 0x70, 0x66, 0xF0, 0x9D,
+ 0x95, 0x9F, 0x6E, 0x6F, 0x74, 0xC2, 0xAC, 0x6E, 0x6F, 0x74, 0x69, 0x6E,
+ 0xE2, 0x88, 0x89, 0x6E, 0x6F, 0x74, 0x69, 0x6E, 0x45, 0xE2, 0x8B, 0xB9,
+ 0xCC, 0xB8, 0x6E, 0x6F, 0x74, 0x69, 0x6E, 0x64, 0x6F, 0x74, 0xE2, 0x8B,
+ 0xB5, 0xCC, 0xB8, 0x6E, 0x6F, 0x74, 0x69, 0x6E, 0x76, 0x61, 0xE2, 0x88,
+ 0x89, 0x6E, 0x6F, 0x74, 0x69, 0x6E, 0x76, 0x62, 0xE2, 0x8B, 0xB7, 0x6E,
+ 0x6F, 0x74, 0x69, 0x6E, 0x76, 0x63, 0xE2, 0x8B, 0xB6, 0x6E, 0x6F, 0x74,
+ 0x6E, 0x69, 0xE2, 0x88, 0x8C, 0x6E, 0x6F, 0x74, 0x6E, 0x69, 0x76, 0x61,
+ 0xE2, 0x88, 0x8C, 0x6E, 0x6F, 0x74, 0x6E, 0x69, 0x76, 0x62, 0xE2, 0x8B,
+ 0xBE, 0x6E, 0x6F, 0x74, 0x6E, 0x69, 0x76, 0x63, 0xE2, 0x8B, 0xBD, 0x6E,
+ 0x70, 0x61, 0x72, 0xE2, 0x88, 0xA6, 0x6E, 0x70, 0x61, 0x72, 0x61, 0x6C,
+ 0x6C, 0x65, 0x6C, 0xE2, 0x88, 0xA6, 0x6E, 0x70, 0x61, 0x72, 0x73, 0x6C,
+ 0xE2, 0xAB, 0xBD, 0xE2, 0x83, 0xA5, 0x6E, 0x70, 0x61, 0x72, 0x74, 0xE2,
+ 0x88, 0x82, 0xCC, 0xB8, 0x6E, 0x70, 0x6F, 0x6C, 0x69, 0x6E, 0x74, 0xE2,
+ 0xA8, 0x94, 0x6E, 0x70, 0x72, 0xE2, 0x8A, 0x80, 0x6E, 0x70, 0x72, 0x63,
+ 0x75, 0x65, 0xE2, 0x8B, 0xA0, 0x6E, 0x70, 0x72, 0x65, 0xE2, 0xAA, 0xAF,
+ 0xCC, 0xB8, 0x6E, 0x70, 0x72, 0x65, 0x63, 0xE2, 0x8A, 0x80, 0x6E, 0x70,
+ 0x72, 0x65, 0x63, 0x65, 0x71, 0xE2, 0xAA, 0xAF, 0xCC, 0xB8, 0x6E, 0x72,
+ 0x41, 0x72, 0x72, 0xE2, 0x87, 0x8F, 0x6E, 0x72, 0x61, 0x72, 0x72, 0xE2,
+ 0x86, 0x9B, 0x6E, 0x72, 0x61, 0x72, 0x72, 0x63, 0xE2, 0xA4, 0xB3, 0xCC,
+ 0xB8, 0x6E, 0x72, 0x61, 0x72, 0x72, 0x77, 0xE2, 0x86, 0x9D, 0xCC, 0xB8,
+ 0x6E, 0x72, 0x69, 0x67, 0x68, 0x74, 0x61, 0x72, 0x72, 0x6F, 0x77, 0xE2,
+ 0x86, 0x9B, 0x6E, 0x72, 0x74, 0x72, 0x69, 0xE2, 0x8B, 0xAB, 0x6E, 0x72,
+ 0x74, 0x72, 0x69, 0x65, 0xE2, 0x8B, 0xAD, 0x6E, 0x73, 0x63, 0xE2, 0x8A,
+ 0x81, 0x6E, 0x73, 0x63, 0x63, 0x75, 0x65, 0xE2, 0x8B, 0xA1, 0x6E, 0x73,
+ 0x63, 0x65, 0xE2, 0xAA, 0xB0, 0xCC, 0xB8, 0x6E, 0x73, 0x63, 0x72, 0xF0,
+ 0x9D, 0x93, 0x83, 0x6E, 0x73, 0x68, 0x6F, 0x72, 0x74, 0x6D, 0x69, 0x64,
+ 0xE2, 0x88, 0xA4, 0x6E, 0x73, 0x68, 0x6F, 0x72, 0x74, 0x70, 0x61, 0x72,
+ 0x61, 0x6C, 0x6C, 0x65, 0x6C, 0xE2, 0x88, 0xA6, 0x6E, 0x73, 0x69, 0x6D,
+ 0xE2, 0x89, 0x81, 0x6E, 0x73, 0x69, 0x6D, 0x65, 0xE2, 0x89, 0x84, 0x6E,
+ 0x73, 0x69, 0x6D, 0x65, 0x71, 0xE2, 0x89, 0x84, 0x6E, 0x73, 0x6D, 0x69,
+ 0x64, 0xE2, 0x88, 0xA4, 0x6E, 0x73, 0x70, 0x61, 0x72, 0xE2, 0x88, 0xA6,
+ 0x6E, 0x73, 0x71, 0x73, 0x75, 0x62, 0x65, 0xE2, 0x8B, 0xA2, 0x6E, 0x73,
+ 0x71, 0x73, 0x75, 0x70, 0x65, 0xE2, 0x8B, 0xA3, 0x6E, 0x73, 0x75, 0x62,
+ 0xE2, 0x8A, 0x84, 0x6E, 0x73, 0x75, 0x62, 0x45, 0xE2, 0xAB, 0x85, 0xCC,
+ 0xB8, 0x6E, 0x73, 0x75, 0x62, 0x65, 0xE2, 0x8A, 0x88, 0x6E, 0x73, 0x75,
+ 0x62, 0x73, 0x65, 0x74, 0xE2, 0x8A, 0x82, 0xE2, 0x83, 0x92, 0x6E, 0x73,
+ 0x75, 0x62, 0x73, 0x65, 0x74, 0x65, 0x71, 0xE2, 0x8A, 0x88, 0x6E, 0x73,
+ 0x75, 0x62, 0x73, 0x65, 0x74, 0x65, 0x71, 0x71, 0xE2, 0xAB, 0x85, 0xCC,
+ 0xB8, 0x6E, 0x73, 0x75, 0x63, 0x63, 0xE2, 0x8A, 0x81, 0x6E, 0x73, 0x75,
+ 0x63, 0x63, 0x65, 0x71, 0xE2, 0xAA, 0xB0, 0xCC, 0xB8, 0x6E, 0x73, 0x75,
+ 0x70, 0xE2, 0x8A, 0x85, 0x6E, 0x73, 0x75, 0x70, 0x45, 0xE2, 0xAB, 0x86,
+ 0xCC, 0xB8, 0x6E, 0x73, 0x75, 0x70, 0x65, 0xE2, 0x8A, 0x89, 0x6E, 0x73,
+ 0x75, 0x70, 0x73, 0x65, 0x74, 0xE2, 0x8A, 0x83, 0xE2, 0x83, 0x92, 0x6E,
+ 0x73, 0x75, 0x70, 0x73, 0x65, 0x74, 0x65, 0x71, 0xE2, 0x8A, 0x89, 0x6E,
+ 0x73, 0x75, 0x70, 0x73, 0x65, 0x74, 0x65, 0x71, 0x71, 0xE2, 0xAB, 0x86,
+ 0xCC, 0xB8, 0x6E, 0x74, 0x67, 0x6C, 0xE2, 0x89, 0xB9, 0x6E, 0x74, 0x69,
+ 0x6C, 0x64, 0x65, 0xC3, 0xB1, 0x6E, 0x74, 0x6C, 0x67, 0xE2, 0x89, 0xB8,
+ 0x6E, 0x74, 0x72, 0x69, 0x61, 0x6E, 0x67, 0x6C, 0x65, 0x6C, 0x65, 0x66,
+ 0x74, 0xE2, 0x8B, 0xAA, 0x6E, 0x74, 0x72, 0x69, 0x61, 0x6E, 0x67, 0x6C,
+ 0x65, 0x6C, 0x65, 0x66, 0x74, 0x65, 0x71, 0xE2, 0x8B, 0xAC, 0x6E, 0x74,
+ 0x72, 0x69, 0x61, 0x6E, 0x67, 0x6C, 0x65, 0x72, 0x69, 0x67, 0x68, 0x74,
+ 0xE2, 0x8B, 0xAB, 0x6E, 0x74, 0x72, 0x69, 0x61, 0x6E, 0x67, 0x6C, 0x65,
+ 0x72, 0x69, 0x67, 0x68, 0x74, 0x65, 0x71, 0xE2, 0x8B, 0xAD, 0x6E, 0x75,
+ 0xCE, 0xBD, 0x6E, 0x75, 0x6D, 0x23, 0x6E, 0x75, 0x6D, 0x65, 0x72, 0x6F,
+ 0xE2, 0x84, 0x96, 0x6E, 0x75, 0x6D, 0x73, 0x70, 0xE2, 0x80, 0x87, 0x6E,
+ 0x76, 0x44, 0x61, 0x73, 0x68, 0xE2, 0x8A, 0xAD, 0x6E, 0x76, 0x48, 0x61,
+ 0x72, 0x72, 0xE2, 0xA4, 0x84, 0x6E, 0x76, 0x61, 0x70, 0xE2, 0x89, 0x8D,
+ 0xE2, 0x83, 0x92, 0x6E, 0x76, 0x64, 0x61, 0x73, 0x68, 0xE2, 0x8A, 0xAC,
+ 0x6E, 0x76, 0x67, 0x65, 0xE2, 0x89, 0xA5, 0xE2, 0x83, 0x92, 0x6E, 0x76,
+ 0x67, 0x74, 0x3E, 0xE2, 0x83, 0x92, 0x6E, 0x76, 0x69, 0x6E, 0x66, 0x69,
+ 0x6E, 0xE2, 0xA7, 0x9E, 0x6E, 0x76, 0x6C, 0x41, 0x72, 0x72, 0xE2, 0xA4,
+ 0x82, 0x6E, 0x76, 0x6C, 0x65, 0xE2, 0x89, 0xA4, 0xE2, 0x83, 0x92, 0x6E,
+ 0x76, 0x6C, 0x74, 0x3C, 0xE2, 0x83, 0x92, 0x6E, 0x76, 0x6C, 0x74, 0x72,
+ 0x69, 0x65, 0xE2, 0x8A, 0xB4, 0xE2, 0x83, 0x92, 0x6E, 0x76, 0x72, 0x41,
+ 0x72, 0x72, 0xE2, 0xA4, 0x83, 0x6E, 0x76, 0x72, 0x74, 0x72, 0x69, 0x65,
+ 0xE2, 0x8A, 0xB5, 0xE2, 0x83, 0x92, 0x6E, 0x76, 0x73, 0x69, 0x6D, 0xE2,
+ 0x88, 0xBC, 0xE2, 0x83, 0x92, 0x6E, 0x77, 0x41, 0x72, 0x72, 0xE2, 0x87,
+ 0x96, 0x6E, 0x77, 0x61, 0x72, 0x68, 0x6B, 0xE2, 0xA4, 0xA3, 0x6E, 0x77,
+ 0x61, 0x72, 0x72, 0xE2, 0x86, 0x96, 0x6E, 0x77, 0x61, 0x72, 0x72, 0x6F,
+ 0x77, 0xE2, 0x86, 0x96, 0x6E, 0x77, 0x6E, 0x65, 0x61, 0x72, 0xE2, 0xA4,
+ 0xA7, 0x6F, 0x53, 0xE2, 0x93, 0x88, 0x6F, 0x61, 0x63, 0x75, 0x74, 0x65,
+ 0xC3, 0xB3, 0x6F, 0x61, 0x73, 0x74, 0xE2, 0x8A, 0x9B, 0x6F, 0x63, 0x69,
+ 0x72, 0xE2, 0x8A, 0x9A, 0x6F, 0x63, 0x69, 0x72, 0x63, 0xC3, 0xB4, 0x6F,
+ 0x63, 0x79, 0xD0, 0xBE, 0x6F, 0x64, 0x61, 0x73, 0x68, 0xE2, 0x8A, 0x9D,
+ 0x6F, 0x64, 0x62, 0x6C, 0x61, 0x63, 0xC5, 0x91, 0x6F, 0x64, 0x69, 0x76,
+ 0xE2, 0xA8, 0xB8, 0x6F, 0x64, 0x6F, 0x74, 0xE2, 0x8A, 0x99, 0x6F, 0x64,
+ 0x73, 0x6F, 0x6C, 0x64, 0xE2, 0xA6, 0xBC, 0x6F, 0x65, 0x6C, 0x69, 0x67,
+ 0xC5, 0x93, 0x6F, 0x66, 0x63, 0x69, 0x72, 0xE2, 0xA6, 0xBF, 0x6F, 0x66,
+ 0x72, 0xF0, 0x9D, 0x94, 0xAC, 0x6F, 0x67, 0x6F, 0x6E, 0xCB, 0x9B, 0x6F,
+ 0x67, 0x72, 0x61, 0x76, 0x65, 0xC3, 0xB2, 0x6F, 0x67, 0x74, 0xE2, 0xA7,
+ 0x81, 0x6F, 0x68, 0x62, 0x61, 0x72, 0xE2, 0xA6, 0xB5, 0x6F, 0x68, 0x6D,
+ 0xCE, 0xA9, 0x6F, 0x69, 0x6E, 0x74, 0xE2, 0x88, 0xAE, 0x6F, 0x6C, 0x61,
+ 0x72, 0x72, 0xE2, 0x86, 0xBA, 0x6F, 0x6C, 0x63, 0x69, 0x72, 0xE2, 0xA6,
+ 0xBE, 0x6F, 0x6C, 0x63, 0x72, 0x6F, 0x73, 0x73, 0xE2, 0xA6, 0xBB, 0x6F,
+ 0x6C, 0x69, 0x6E, 0x65, 0xE2, 0x80, 0xBE, 0x6F, 0x6C, 0x74, 0xE2, 0xA7,
+ 0x80, 0x6F, 0x6D, 0x61, 0x63, 0x72, 0xC5, 0x8D, 0x6F, 0x6D, 0x65, 0x67,
+ 0x61, 0xCF, 0x89, 0x6F, 0x6D, 0x69, 0x63, 0x72, 0x6F, 0x6E, 0xCE, 0xBF,
+ 0x6F, 0x6D, 0x69, 0x64, 0xE2, 0xA6, 0xB6, 0x6F, 0x6D, 0x69, 0x6E, 0x75,
+ 0x73, 0xE2, 0x8A, 0x96, 0x6F, 0x6F, 0x70, 0x66, 0xF0, 0x9D, 0x95, 0xA0,
+ 0x6F, 0x70, 0x61, 0x72, 0xE2, 0xA6, 0xB7, 0x6F, 0x70, 0x65, 0x72, 0x70,
+ 0xE2, 0xA6, 0xB9, 0x6F, 0x70, 0x6C, 0x75, 0x73, 0xE2, 0x8A, 0x95, 0x6F,
+ 0x72, 0xE2, 0x88, 0xA8, 0x6F, 0x72, 0x61, 0x72, 0x72, 0xE2, 0x86, 0xBB,
+ 0x6F, 0x72, 0x64, 0xE2, 0xA9, 0x9D, 0x6F, 0x72, 0x64, 0x65, 0x72, 0xE2,
+ 0x84, 0xB4, 0x6F, 0x72, 0x64, 0x65, 0x72, 0x6F, 0x66, 0xE2, 0x84, 0xB4,
+ 0x6F, 0x72, 0x64, 0x66, 0xC2, 0xAA, 0x6F, 0x72, 0x64, 0x6D, 0xC2, 0xBA,
+ 0x6F, 0x72, 0x69, 0x67, 0x6F, 0x66, 0xE2, 0x8A, 0xB6, 0x6F, 0x72, 0x6F,
+ 0x72, 0xE2, 0xA9, 0x96, 0x6F, 0x72, 0x73, 0x6C, 0x6F, 0x70, 0x65, 0xE2,
+ 0xA9, 0x97, 0x6F, 0x72, 0x76, 0xE2, 0xA9, 0x9B, 0x6F, 0x73, 0x63, 0x72,
+ 0xE2, 0x84, 0xB4, 0x6F, 0x73, 0x6C, 0x61, 0x73, 0x68, 0xC3, 0xB8, 0x6F,
+ 0x73, 0x6F, 0x6C, 0xE2, 0x8A, 0x98, 0x6F, 0x74, 0x69, 0x6C, 0x64, 0x65,
+ 0xC3, 0xB5, 0x6F, 0x74, 0x69, 0x6D, 0x65, 0x73, 0xE2, 0x8A, 0x97, 0x6F,
+ 0x74, 0x69, 0x6D, 0x65, 0x73, 0x61, 0x73, 0xE2, 0xA8, 0xB6, 0x6F, 0x75,
+ 0x6D, 0x6C, 0xC3, 0xB6, 0x6F, 0x76, 0x62, 0x61, 0x72, 0xE2, 0x8C, 0xBD,
+ 0x70, 0x61, 0x72, 0xE2, 0x88, 0xA5, 0x70, 0x61, 0x72, 0x61, 0xC2, 0xB6,
+ 0x70, 0x61, 0x72, 0x61, 0x6C, 0x6C, 0x65, 0x6C, 0xE2, 0x88, 0xA5, 0x70,
+ 0x61, 0x72, 0x73, 0x69, 0x6D, 0xE2, 0xAB, 0xB3, 0x70, 0x61, 0x72, 0x73,
+ 0x6C, 0xE2, 0xAB, 0xBD, 0x70, 0x61, 0x72, 0x74, 0xE2, 0x88, 0x82, 0x70,
+ 0x63, 0x79, 0xD0, 0xBF, 0x70, 0x65, 0x72, 0x63, 0x6E, 0x74, 0x25, 0x70,
+ 0x65, 0x72, 0x69, 0x6F, 0x64, 0x2E, 0x70, 0x65, 0x72, 0x6D, 0x69, 0x6C,
+ 0xE2, 0x80, 0xB0, 0x70, 0x65, 0x72, 0x70, 0xE2, 0x8A, 0xA5, 0x70, 0x65,
+ 0x72, 0x74, 0x65, 0x6E, 0x6B, 0xE2, 0x80, 0xB1, 0x70, 0x66, 0x72, 0xF0,
+ 0x9D, 0x94, 0xAD, 0x70, 0x68, 0x69, 0xCF, 0x86, 0x70, 0x68, 0x69, 0x76,
+ 0xCF, 0x95, 0x70, 0x68, 0x6D, 0x6D, 0x61, 0x74, 0xE2, 0x84, 0xB3, 0x70,
+ 0x68, 0x6F, 0x6E, 0x65, 0xE2, 0x98, 0x8E, 0x70, 0x69, 0xCF, 0x80, 0x70,
+ 0x69, 0x74, 0x63, 0x68, 0x66, 0x6F, 0x72, 0x6B, 0xE2, 0x8B, 0x94, 0x70,
+ 0x69, 0x76, 0xCF, 0x96, 0x70, 0x6C, 0x61, 0x6E, 0x63, 0x6B, 0xE2, 0x84,
+ 0x8F, 0x70, 0x6C, 0x61, 0x6E, 0x63, 0x6B, 0x68, 0xE2, 0x84, 0x8E, 0x70,
+ 0x6C, 0x61, 0x6E, 0x6B, 0x76, 0xE2, 0x84, 0x8F, 0x70, 0x6C, 0x75, 0x73,
+ 0x2B, 0x70, 0x6C, 0x75, 0x73, 0x61, 0x63, 0x69, 0x72, 0xE2, 0xA8, 0xA3,
+ 0x70, 0x6C, 0x75, 0x73, 0x62, 0xE2, 0x8A, 0x9E, 0x70, 0x6C, 0x75, 0x73,
+ 0x63, 0x69, 0x72, 0xE2, 0xA8, 0xA2, 0x70, 0x6C, 0x75, 0x73, 0x64, 0x6F,
+ 0xE2, 0x88, 0x94, 0x70, 0x6C, 0x75, 0x73, 0x64, 0x75, 0xE2, 0xA8, 0xA5,
+ 0x70, 0x6C, 0x75, 0x73, 0x65, 0xE2, 0xA9, 0xB2, 0x70, 0x6C, 0x75, 0x73,
+ 0x6D, 0x6E, 0xC2, 0xB1, 0x70, 0x6C, 0x75, 0x73, 0x73, 0x69, 0x6D, 0xE2,
+ 0xA8, 0xA6, 0x70, 0x6C, 0x75, 0x73, 0x74, 0x77, 0x6F, 0xE2, 0xA8, 0xA7,
+ 0x70, 0x6D, 0xC2, 0xB1, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x69, 0x6E, 0x74,
+ 0xE2, 0xA8, 0x95, 0x70, 0x6F, 0x70, 0x66, 0xF0, 0x9D, 0x95, 0xA1, 0x70,
+ 0x6F, 0x75, 0x6E, 0x64, 0xC2, 0xA3, 0x70, 0x72, 0xE2, 0x89, 0xBA, 0x70,
+ 0x72, 0x45, 0xE2, 0xAA, 0xB3, 0x70, 0x72, 0x61, 0x70, 0xE2, 0xAA, 0xB7,
+ 0x70, 0x72, 0x63, 0x75, 0x65, 0xE2, 0x89, 0xBC, 0x70, 0x72, 0x65, 0xE2,
+ 0xAA, 0xAF, 0x70, 0x72, 0x65, 0x63, 0xE2, 0x89, 0xBA, 0x70, 0x72, 0x65,
+ 0x63, 0x61, 0x70, 0x70, 0x72, 0x6F, 0x78, 0xE2, 0xAA, 0xB7, 0x70, 0x72,
+ 0x65, 0x63, 0x63, 0x75, 0x72, 0x6C, 0x79, 0x65, 0x71, 0xE2, 0x89, 0xBC,
+ 0x70, 0x72, 0x65, 0x63, 0x65, 0x71, 0xE2, 0xAA, 0xAF, 0x70, 0x72, 0x65,
+ 0x63, 0x6E, 0x61, 0x70, 0x70, 0x72, 0x6F, 0x78, 0xE2, 0xAA, 0xB9, 0x70,
+ 0x72, 0x65, 0x63, 0x6E, 0x65, 0x71, 0x71, 0xE2, 0xAA, 0xB5, 0x70, 0x72,
+ 0x65, 0x63, 0x6E, 0x73, 0x69, 0x6D, 0xE2, 0x8B, 0xA8, 0x70, 0x72, 0x65,
+ 0x63, 0x73, 0x69, 0x6D, 0xE2, 0x89, 0xBE, 0x70, 0x72, 0x69, 0x6D, 0x65,
+ 0xE2, 0x80, 0xB2, 0x70, 0x72, 0x69, 0x6D, 0x65, 0x73, 0xE2, 0x84, 0x99,
+ 0x70, 0x72, 0x6E, 0x45, 0xE2, 0xAA, 0xB5, 0x70, 0x72, 0x6E, 0x61, 0x70,
+ 0xE2, 0xAA, 0xB9, 0x70, 0x72, 0x6E, 0x73, 0x69, 0x6D, 0xE2, 0x8B, 0xA8,
+ 0x70, 0x72, 0x6F, 0x64, 0xE2, 0x88, 0x8F, 0x70, 0x72, 0x6F, 0x66, 0x61,
+ 0x6C, 0x61, 0x72, 0xE2, 0x8C, 0xAE, 0x70, 0x72, 0x6F, 0x66, 0x6C, 0x69,
+ 0x6E, 0x65, 0xE2, 0x8C, 0x92, 0x70, 0x72, 0x6F, 0x66, 0x73, 0x75, 0x72,
+ 0x66, 0xE2, 0x8C, 0x93, 0x70, 0x72, 0x6F, 0x70, 0xE2, 0x88, 0x9D, 0x70,
+ 0x72, 0x6F, 0x70, 0x74, 0x6F, 0xE2, 0x88, 0x9D, 0x70, 0x72, 0x73, 0x69,
+ 0x6D, 0xE2, 0x89, 0xBE, 0x70, 0x72, 0x75, 0x72, 0x65, 0x6C, 0xE2, 0x8A,
+ 0xB0, 0x70, 0x73, 0x63, 0x72, 0xF0, 0x9D, 0x93, 0x85, 0x70, 0x73, 0x69,
+ 0xCF, 0x88, 0x70, 0x75, 0x6E, 0x63, 0x73, 0x70, 0xE2, 0x80, 0x88, 0x71,
+ 0x66, 0x72, 0xF0, 0x9D, 0x94, 0xAE, 0x71, 0x69, 0x6E, 0x74, 0xE2, 0xA8,
+ 0x8C, 0x71, 0x6F, 0x70, 0x66, 0xF0, 0x9D, 0x95, 0xA2, 0x71, 0x70, 0x72,
+ 0x69, 0x6D, 0x65, 0xE2, 0x81, 0x97, 0x71, 0x73, 0x63, 0x72, 0xF0, 0x9D,
+ 0x93, 0x86, 0x71, 0x75, 0x61, 0x74, 0x65, 0x72, 0x6E, 0x69, 0x6F, 0x6E,
+ 0x73, 0xE2, 0x84, 0x8D, 0x71, 0x75, 0x61, 0x74, 0x69, 0x6E, 0x74, 0xE2,
+ 0xA8, 0x96, 0x71, 0x75, 0x65, 0x73, 0x74, 0x3F, 0x71, 0x75, 0x65, 0x73,
+ 0x74, 0x65, 0x71, 0xE2, 0x89, 0x9F, 0x71, 0x75, 0x6F, 0x74, 0x22, 0x72,
+ 0x41, 0x61, 0x72, 0x72, 0xE2, 0x87, 0x9B, 0x72, 0x41, 0x72, 0x72, 0xE2,
+ 0x87, 0x92, 0x72, 0x41, 0x74, 0x61, 0x69, 0x6C, 0xE2, 0xA4, 0x9C, 0x72,
+ 0x42, 0x61, 0x72, 0x72, 0xE2, 0xA4, 0x8F, 0x72, 0x48, 0x61, 0x72, 0xE2,
+ 0xA5, 0xA4, 0x72, 0x61, 0x63, 0x65, 0xE2, 0x88, 0xBD, 0xCC, 0xB1, 0x72,
+ 0x61, 0x63, 0x75, 0x74, 0x65, 0xC5, 0x95, 0x72, 0x61, 0x64, 0x69, 0x63,
+ 0xE2, 0x88, 0x9A, 0x72, 0x61, 0x65, 0x6D, 0x70, 0x74, 0x79, 0x76, 0xE2,
+ 0xA6, 0xB3, 0x72, 0x61, 0x6E, 0x67, 0xE2, 0x9F, 0xA9, 0x72, 0x61, 0x6E,
+ 0x67, 0x64, 0xE2, 0xA6, 0x92, 0x72, 0x61, 0x6E, 0x67, 0x65, 0xE2, 0xA6,
+ 0xA5, 0x72, 0x61, 0x6E, 0x67, 0x6C, 0x65, 0xE2, 0x9F, 0xA9, 0x72, 0x61,
+ 0x71, 0x75, 0x6F, 0xC2, 0xBB, 0x72, 0x61, 0x72, 0x72, 0xE2, 0x86, 0x92,
+ 0x72, 0x61, 0x72, 0x72, 0x61, 0x70, 0xE2, 0xA5, 0xB5, 0x72, 0x61, 0x72,
+ 0x72, 0x62, 0xE2, 0x87, 0xA5, 0x72, 0x61, 0x72, 0x72, 0x62, 0x66, 0x73,
+ 0xE2, 0xA4, 0xA0, 0x72, 0x61, 0x72, 0x72, 0x63, 0xE2, 0xA4, 0xB3, 0x72,
+ 0x61, 0x72, 0x72, 0x66, 0x73, 0xE2, 0xA4, 0x9E, 0x72, 0x61, 0x72, 0x72,
+ 0x68, 0x6B, 0xE2, 0x86, 0xAA, 0x72, 0x61, 0x72, 0x72, 0x6C, 0x70, 0xE2,
+ 0x86, 0xAC, 0x72, 0x61, 0x72, 0x72, 0x70, 0x6C, 0xE2, 0xA5, 0x85, 0x72,
+ 0x61, 0x72, 0x72, 0x73, 0x69, 0x6D, 0xE2, 0xA5, 0xB4, 0x72, 0x61, 0x72,
+ 0x72, 0x74, 0x6C, 0xE2, 0x86, 0xA3, 0x72, 0x61, 0x72, 0x72, 0x77, 0xE2,
+ 0x86, 0x9D, 0x72, 0x61, 0x74, 0x61, 0x69, 0x6C, 0xE2, 0xA4, 0x9A, 0x72,
+ 0x61, 0x74, 0x69, 0x6F, 0xE2, 0x88, 0xB6, 0x72, 0x61, 0x74, 0x69, 0x6F,
+ 0x6E, 0x61, 0x6C, 0x73, 0xE2, 0x84, 0x9A, 0x72, 0x62, 0x61, 0x72, 0x72,
+ 0xE2, 0xA4, 0x8D, 0x72, 0x62, 0x62, 0x72, 0x6B, 0xE2, 0x9D, 0xB3, 0x72,
+ 0x62, 0x72, 0x61, 0x63, 0x65, 0x7D, 0x72, 0x62, 0x72, 0x61, 0x63, 0x6B,
+ 0x5D, 0x72, 0x62, 0x72, 0x6B, 0x65, 0xE2, 0xA6, 0x8C, 0x72, 0x62, 0x72,
+ 0x6B, 0x73, 0x6C, 0x64, 0xE2, 0xA6, 0x8E, 0x72, 0x62, 0x72, 0x6B, 0x73,
+ 0x6C, 0x75, 0xE2, 0xA6, 0x90, 0x72, 0x63, 0x61, 0x72, 0x6F, 0x6E, 0xC5,
+ 0x99, 0x72, 0x63, 0x65, 0x64, 0x69, 0x6C, 0xC5, 0x97, 0x72, 0x63, 0x65,
+ 0x69, 0x6C, 0xE2, 0x8C, 0x89, 0x72, 0x63, 0x75, 0x62, 0x7D, 0x72, 0x63,
+ 0x79, 0xD1, 0x80, 0x72, 0x64, 0x63, 0x61, 0xE2, 0xA4, 0xB7, 0x72, 0x64,
+ 0x6C, 0x64, 0x68, 0x61, 0x72, 0xE2, 0xA5, 0xA9, 0x72, 0x64, 0x71, 0x75,
+ 0x6F, 0xE2, 0x80, 0x9D, 0x72, 0x64, 0x71, 0x75, 0x6F, 0x72, 0xE2, 0x80,
+ 0x9D, 0x72, 0x64, 0x73, 0x68, 0xE2, 0x86, 0xB3, 0x72, 0x65, 0x61, 0x6C,
+ 0xE2, 0x84, 0x9C, 0x72, 0x65, 0x61, 0x6C, 0x69, 0x6E, 0x65, 0xE2, 0x84,
+ 0x9B, 0x72, 0x65, 0x61, 0x6C, 0x70, 0x61, 0x72, 0x74, 0xE2, 0x84, 0x9C,
+ 0x72, 0x65, 0x61, 0x6C, 0x73, 0xE2, 0x84, 0x9D, 0x72, 0x65, 0x63, 0x74,
+ 0xE2, 0x96, 0xAD, 0x72, 0x65, 0x67, 0xC2, 0xAE, 0x72, 0x66, 0x69, 0x73,
+ 0x68, 0x74, 0xE2, 0xA5, 0xBD, 0x72, 0x66, 0x6C, 0x6F, 0x6F, 0x72, 0xE2,
+ 0x8C, 0x8B, 0x72, 0x66, 0x72, 0xF0, 0x9D, 0x94, 0xAF, 0x72, 0x68, 0x61,
+ 0x72, 0x64, 0xE2, 0x87, 0x81, 0x72, 0x68, 0x61, 0x72, 0x75, 0xE2, 0x87,
+ 0x80, 0x72, 0x68, 0x61, 0x72, 0x75, 0x6C, 0xE2, 0xA5, 0xAC, 0x72, 0x68,
+ 0x6F, 0xCF, 0x81, 0x72, 0x68, 0x6F, 0x76, 0xCF, 0xB1, 0x72, 0x69, 0x67,
+ 0x68, 0x74, 0x61, 0x72, 0x72, 0x6F, 0x77, 0xE2, 0x86, 0x92, 0x72, 0x69,
+ 0x67, 0x68, 0x74, 0x61, 0x72, 0x72, 0x6F, 0x77, 0x74, 0x61, 0x69, 0x6C,
+ 0xE2, 0x86, 0xA3, 0x72, 0x69, 0x67, 0x68, 0x74, 0x68, 0x61, 0x72, 0x70,
+ 0x6F, 0x6F, 0x6E, 0x64, 0x6F, 0x77, 0x6E, 0xE2, 0x87, 0x81, 0x72, 0x69,
+ 0x67, 0x68, 0x74, 0x68, 0x61, 0x72, 0x70, 0x6F, 0x6F, 0x6E, 0x75, 0x70,
+ 0xE2, 0x87, 0x80, 0x72, 0x69, 0x67, 0x68, 0x74, 0x6C, 0x65, 0x66, 0x74,
+ 0x61, 0x72, 0x72, 0x6F, 0x77, 0x73, 0xE2, 0x87, 0x84, 0x72, 0x69, 0x67,
+ 0x68, 0x74, 0x6C, 0x65, 0x66, 0x74, 0x68, 0x61, 0x72, 0x70, 0x6F, 0x6F,
+ 0x6E, 0x73, 0xE2, 0x87, 0x8C, 0x72, 0x69, 0x67, 0x68, 0x74, 0x72, 0x69,
+ 0x67, 0x68, 0x74, 0x61, 0x72, 0x72, 0x6F, 0x77, 0x73, 0xE2, 0x87, 0x89,
+ 0x72, 0x69, 0x67, 0x68, 0x74, 0x73, 0x71, 0x75, 0x69, 0x67, 0x61, 0x72,
+ 0x72, 0x6F, 0x77, 0xE2, 0x86, 0x9D, 0x72, 0x69, 0x67, 0x68, 0x74, 0x74,
+ 0x68, 0x72, 0x65, 0x65, 0x74, 0x69, 0x6D, 0x65, 0x73, 0xE2, 0x8B, 0x8C,
+ 0x72, 0x69, 0x6E, 0x67, 0xCB, 0x9A, 0x72, 0x69, 0x73, 0x69, 0x6E, 0x67,
+ 0x64, 0x6F, 0x74, 0x73, 0x65, 0x71, 0xE2, 0x89, 0x93, 0x72, 0x6C, 0x61,
+ 0x72, 0x72, 0xE2, 0x87, 0x84, 0x72, 0x6C, 0x68, 0x61, 0x72, 0xE2, 0x87,
+ 0x8C, 0x72, 0x6C, 0x6D, 0xE2, 0x80, 0x8F, 0x72, 0x6D, 0x6F, 0x75, 0x73,
+ 0x74, 0xE2, 0x8E, 0xB1, 0x72, 0x6D, 0x6F, 0x75, 0x73, 0x74, 0x61, 0x63,
+ 0x68, 0x65, 0xE2, 0x8E, 0xB1, 0x72, 0x6E, 0x6D, 0x69, 0x64, 0xE2, 0xAB,
+ 0xAE, 0x72, 0x6F, 0x61, 0x6E, 0x67, 0xE2, 0x9F, 0xAD, 0x72, 0x6F, 0x61,
+ 0x72, 0x72, 0xE2, 0x87, 0xBE, 0x72, 0x6F, 0x62, 0x72, 0x6B, 0xE2, 0x9F,
+ 0xA7, 0x72, 0x6F, 0x70, 0x61, 0x72, 0xE2, 0xA6, 0x86, 0x72, 0x6F, 0x70,
+ 0x66, 0xF0, 0x9D, 0x95, 0xA3, 0x72, 0x6F, 0x70, 0x6C, 0x75, 0x73, 0xE2,
+ 0xA8, 0xAE, 0x72, 0x6F, 0x74, 0x69, 0x6D, 0x65, 0x73, 0xE2, 0xA8, 0xB5,
+ 0x72, 0x70, 0x61, 0x72, 0x29, 0x72, 0x70, 0x61, 0x72, 0x67, 0x74, 0xE2,
+ 0xA6, 0x94, 0x72, 0x70, 0x70, 0x6F, 0x6C, 0x69, 0x6E, 0x74, 0xE2, 0xA8,
+ 0x92, 0x72, 0x72, 0x61, 0x72, 0x72, 0xE2, 0x87, 0x89, 0x72, 0x73, 0x61,
+ 0x71, 0x75, 0x6F, 0xE2, 0x80, 0xBA, 0x72, 0x73, 0x63, 0x72, 0xF0, 0x9D,
+ 0x93, 0x87, 0x72, 0x73, 0x68, 0xE2, 0x86, 0xB1, 0x72, 0x73, 0x71, 0x62,
+ 0x5D, 0x72, 0x73, 0x71, 0x75, 0x6F, 0xE2, 0x80, 0x99, 0x72, 0x73, 0x71,
+ 0x75, 0x6F, 0x72, 0xE2, 0x80, 0x99, 0x72, 0x74, 0x68, 0x72, 0x65, 0x65,
+ 0xE2, 0x8B, 0x8C, 0x72, 0x74, 0x69, 0x6D, 0x65, 0x73, 0xE2, 0x8B, 0x8A,
+ 0x72, 0x74, 0x72, 0x69, 0xE2, 0x96, 0xB9, 0x72, 0x74, 0x72, 0x69, 0x65,
+ 0xE2, 0x8A, 0xB5, 0x72, 0x74, 0x72, 0x69, 0x66, 0xE2, 0x96, 0xB8, 0x72,
+ 0x74, 0x72, 0x69, 0x6C, 0x74, 0x72, 0x69, 0xE2, 0xA7, 0x8E, 0x72, 0x75,
+ 0x6C, 0x75, 0x68, 0x61, 0x72, 0xE2, 0xA5, 0xA8, 0x72, 0x78, 0xE2, 0x84,
+ 0x9E, 0x73, 0x61, 0x63, 0x75, 0x74, 0x65, 0xC5, 0x9B, 0x73, 0x62, 0x71,
+ 0x75, 0x6F, 0xE2, 0x80, 0x9A, 0x73, 0x63, 0xE2, 0x89, 0xBB, 0x73, 0x63,
+ 0x45, 0xE2, 0xAA, 0xB4, 0x73, 0x63, 0x61, 0x70, 0xE2, 0xAA, 0xB8, 0x73,
+ 0x63, 0x61, 0x72, 0x6F, 0x6E, 0xC5, 0xA1, 0x73, 0x63, 0x63, 0x75, 0x65,
+ 0xE2, 0x89, 0xBD, 0x73, 0x63, 0x65, 0xE2, 0xAA, 0xB0, 0x73, 0x63, 0x65,
+ 0x64, 0x69, 0x6C, 0xC5, 0x9F, 0x73, 0x63, 0x69, 0x72, 0x63, 0xC5, 0x9D,
+ 0x73, 0x63, 0x6E, 0x45, 0xE2, 0xAA, 0xB6, 0x73, 0x63, 0x6E, 0x61, 0x70,
+ 0xE2, 0xAA, 0xBA, 0x73, 0x63, 0x6E, 0x73, 0x69, 0x6D, 0xE2, 0x8B, 0xA9,
+ 0x73, 0x63, 0x70, 0x6F, 0x6C, 0x69, 0x6E, 0x74, 0xE2, 0xA8, 0x93, 0x73,
+ 0x63, 0x73, 0x69, 0x6D, 0xE2, 0x89, 0xBF, 0x73, 0x63, 0x79, 0xD1, 0x81,
+ 0x73, 0x64, 0x6F, 0x74, 0xE2, 0x8B, 0x85, 0x73, 0x64, 0x6F, 0x74, 0x62,
+ 0xE2, 0x8A, 0xA1, 0x73, 0x64, 0x6F, 0x74, 0x65, 0xE2, 0xA9, 0xA6, 0x73,
+ 0x65, 0x41, 0x72, 0x72, 0xE2, 0x87, 0x98, 0x73, 0x65, 0x61, 0x72, 0x68,
+ 0x6B, 0xE2, 0xA4, 0xA5, 0x73, 0x65, 0x61, 0x72, 0x72, 0xE2, 0x86, 0x98,
+ 0x73, 0x65, 0x61, 0x72, 0x72, 0x6F, 0x77, 0xE2, 0x86, 0x98, 0x73, 0x65,
+ 0x63, 0x74, 0xC2, 0xA7, 0x73, 0x65, 0x6D, 0x69, 0x3B, 0x73, 0x65, 0x73,
+ 0x77, 0x61, 0x72, 0xE2, 0xA4, 0xA9, 0x73, 0x65, 0x74, 0x6D, 0x69, 0x6E,
+ 0x75, 0x73, 0xE2, 0x88, 0x96, 0x73, 0x65, 0x74, 0x6D, 0x6E, 0xE2, 0x88,
+ 0x96, 0x73, 0x65, 0x78, 0x74, 0xE2, 0x9C, 0xB6, 0x73, 0x66, 0x72, 0xF0,
+ 0x9D, 0x94, 0xB0, 0x73, 0x66, 0x72, 0x6F, 0x77, 0x6E, 0xE2, 0x8C, 0xA2,
+ 0x73, 0x68, 0x61, 0x72, 0x70, 0xE2, 0x99, 0xAF, 0x73, 0x68, 0x63, 0x68,
+ 0x63, 0x79, 0xD1, 0x89, 0x73, 0x68, 0x63, 0x79, 0xD1, 0x88, 0x73, 0x68,
+ 0x6F, 0x72, 0x74, 0x6D, 0x69, 0x64, 0xE2, 0x88, 0xA3, 0x73, 0x68, 0x6F,
+ 0x72, 0x74, 0x70, 0x61, 0x72, 0x61, 0x6C, 0x6C, 0x65, 0x6C, 0xE2, 0x88,
+ 0xA5, 0x73, 0x68, 0x79, 0xC2, 0xAD, 0x73, 0x69, 0x67, 0x6D, 0x61, 0xCF,
+ 0x83, 0x73, 0x69, 0x67, 0x6D, 0x61, 0x66, 0xCF, 0x82, 0x73, 0x69, 0x67,
+ 0x6D, 0x61, 0x76, 0xCF, 0x82, 0x73, 0x69, 0x6D, 0xE2, 0x88, 0xBC, 0x73,
+ 0x69, 0x6D, 0x64, 0x6F, 0x74, 0xE2, 0xA9, 0xAA, 0x73, 0x69, 0x6D, 0x65,
+ 0xE2, 0x89, 0x83, 0x73, 0x69, 0x6D, 0x65, 0x71, 0xE2, 0x89, 0x83, 0x73,
+ 0x69, 0x6D, 0x67, 0xE2, 0xAA, 0x9E, 0x73, 0x69, 0x6D, 0x67, 0x45, 0xE2,
+ 0xAA, 0xA0, 0x73, 0x69, 0x6D, 0x6C, 0xE2, 0xAA, 0x9D, 0x73, 0x69, 0x6D,
+ 0x6C, 0x45, 0xE2, 0xAA, 0x9F, 0x73, 0x69, 0x6D, 0x6E, 0x65, 0xE2, 0x89,
+ 0x86, 0x73, 0x69, 0x6D, 0x70, 0x6C, 0x75, 0x73, 0xE2, 0xA8, 0xA4, 0x73,
+ 0x69, 0x6D, 0x72, 0x61, 0x72, 0x72, 0xE2, 0xA5, 0xB2, 0x73, 0x6C, 0x61,
+ 0x72, 0x72, 0xE2, 0x86, 0x90, 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x73, 0x65,
+ 0x74, 0x6D, 0x69, 0x6E, 0x75, 0x73, 0xE2, 0x88, 0x96, 0x73, 0x6D, 0x61,
+ 0x73, 0x68, 0x70, 0xE2, 0xA8, 0xB3, 0x73, 0x6D, 0x65, 0x70, 0x61, 0x72,
+ 0x73, 0x6C, 0xE2, 0xA7, 0xA4, 0x73, 0x6D, 0x69, 0x64, 0xE2, 0x88, 0xA3,
+ 0x73, 0x6D, 0x69, 0x6C, 0x65, 0xE2, 0x8C, 0xA3, 0x73, 0x6D, 0x74, 0xE2,
+ 0xAA, 0xAA, 0x73, 0x6D, 0x74, 0x65, 0xE2, 0xAA, 0xAC, 0x73, 0x6D, 0x74,
+ 0x65, 0x73, 0xE2, 0xAA, 0xAC, 0xEF, 0xB8, 0x80, 0x73, 0x6F, 0x66, 0x74,
+ 0x63, 0x79, 0xD1, 0x8C, 0x73, 0x6F, 0x6C, 0x2F, 0x73, 0x6F, 0x6C, 0x62,
+ 0xE2, 0xA7, 0x84, 0x73, 0x6F, 0x6C, 0x62, 0x61, 0x72, 0xE2, 0x8C, 0xBF,
+ 0x73, 0x6F, 0x70, 0x66, 0xF0, 0x9D, 0x95, 0xA4, 0x73, 0x70, 0x61, 0x64,
+ 0x65, 0x73, 0xE2, 0x99, 0xA0, 0x73, 0x70, 0x61, 0x64, 0x65, 0x73, 0x75,
+ 0x69, 0x74, 0xE2, 0x99, 0xA0, 0x73, 0x70, 0x61, 0x72, 0xE2, 0x88, 0xA5,
+ 0x73, 0x71, 0x63, 0x61, 0x70, 0xE2, 0x8A, 0x93, 0x73, 0x71, 0x63, 0x61,
+ 0x70, 0x73, 0xE2, 0x8A, 0x93, 0xEF, 0xB8, 0x80, 0x73, 0x71, 0x63, 0x75,
+ 0x70, 0xE2, 0x8A, 0x94, 0x73, 0x71, 0x63, 0x75, 0x70, 0x73, 0xE2, 0x8A,
+ 0x94, 0xEF, 0xB8, 0x80, 0x73, 0x71, 0x73, 0x75, 0x62, 0xE2, 0x8A, 0x8F,
+ 0x73, 0x71, 0x73, 0x75, 0x62, 0x65, 0xE2, 0x8A, 0x91, 0x73, 0x71, 0x73,
+ 0x75, 0x62, 0x73, 0x65, 0x74, 0xE2, 0x8A, 0x8F, 0x73, 0x71, 0x73, 0x75,
+ 0x62, 0x73, 0x65, 0x74, 0x65, 0x71, 0xE2, 0x8A, 0x91, 0x73, 0x71, 0x73,
+ 0x75, 0x70, 0xE2, 0x8A, 0x90, 0x73, 0x71, 0x73, 0x75, 0x70, 0x65, 0xE2,
+ 0x8A, 0x92, 0x73, 0x71, 0x73, 0x75, 0x70, 0x73, 0x65, 0x74, 0xE2, 0x8A,
+ 0x90, 0x73, 0x71, 0x73, 0x75, 0x70, 0x73, 0x65, 0x74, 0x65, 0x71, 0xE2,
+ 0x8A, 0x92, 0x73, 0x71, 0x75, 0xE2, 0x96, 0xA1, 0x73, 0x71, 0x75, 0x61,
+ 0x72, 0x65, 0xE2, 0x96, 0xA1, 0x73, 0x71, 0x75, 0x61, 0x72, 0x66, 0xE2,
+ 0x96, 0xAA, 0x73, 0x71, 0x75, 0x66, 0xE2, 0x96, 0xAA, 0x73, 0x72, 0x61,
+ 0x72, 0x72, 0xE2, 0x86, 0x92, 0x73, 0x73, 0x63, 0x72, 0xF0, 0x9D, 0x93,
+ 0x88, 0x73, 0x73, 0x65, 0x74, 0x6D, 0x6E, 0xE2, 0x88, 0x96, 0x73, 0x73,
+ 0x6D, 0x69, 0x6C, 0x65, 0xE2, 0x8C, 0xA3, 0x73, 0x73, 0x74, 0x61, 0x72,
+ 0x66, 0xE2, 0x8B, 0x86, 0x73, 0x74, 0x61, 0x72, 0xE2, 0x98, 0x86, 0x73,
+ 0x74, 0x61, 0x72, 0x66, 0xE2, 0x98, 0x85, 0x73, 0x74, 0x72, 0x61, 0x69,
+ 0x67, 0x68, 0x74, 0x65, 0x70, 0x73, 0x69, 0x6C, 0x6F, 0x6E, 0xCF, 0xB5,
+ 0x73, 0x74, 0x72, 0x61, 0x69, 0x67, 0x68, 0x74, 0x70, 0x68, 0x69, 0xCF,
+ 0x95, 0x73, 0x74, 0x72, 0x6E, 0x73, 0xC2, 0xAF, 0x73, 0x75, 0x62, 0xE2,
+ 0x8A, 0x82, 0x73, 0x75, 0x62, 0x45, 0xE2, 0xAB, 0x85, 0x73, 0x75, 0x62,
+ 0x64, 0x6F, 0x74, 0xE2, 0xAA, 0xBD, 0x73, 0x75, 0x62, 0x65, 0xE2, 0x8A,
+ 0x86, 0x73, 0x75, 0x62, 0x65, 0x64, 0x6F, 0x74, 0xE2, 0xAB, 0x83, 0x73,
+ 0x75, 0x62, 0x6D, 0x75, 0x6C, 0x74, 0xE2, 0xAB, 0x81, 0x73, 0x75, 0x62,
+ 0x6E, 0x45, 0xE2, 0xAB, 0x8B, 0x73, 0x75, 0x62, 0x6E, 0x65, 0xE2, 0x8A,
+ 0x8A, 0x73, 0x75, 0x62, 0x70, 0x6C, 0x75, 0x73, 0xE2, 0xAA, 0xBF, 0x73,
+ 0x75, 0x62, 0x72, 0x61, 0x72, 0x72, 0xE2, 0xA5, 0xB9, 0x73, 0x75, 0x62,
+ 0x73, 0x65, 0x74, 0xE2, 0x8A, 0x82, 0x73, 0x75, 0x62, 0x73, 0x65, 0x74,
+ 0x65, 0x71, 0xE2, 0x8A, 0x86, 0x73, 0x75, 0x62, 0x73, 0x65, 0x74, 0x65,
+ 0x71, 0x71, 0xE2, 0xAB, 0x85, 0x73, 0x75, 0x62, 0x73, 0x65, 0x74, 0x6E,
+ 0x65, 0x71, 0xE2, 0x8A, 0x8A, 0x73, 0x75, 0x62, 0x73, 0x65, 0x74, 0x6E,
+ 0x65, 0x71, 0x71, 0xE2, 0xAB, 0x8B, 0x73, 0x75, 0x62, 0x73, 0x69, 0x6D,
+ 0xE2, 0xAB, 0x87, 0x73, 0x75, 0x62, 0x73, 0x75, 0x62, 0xE2, 0xAB, 0x95,
+ 0x73, 0x75, 0x62, 0x73, 0x75, 0x70, 0xE2, 0xAB, 0x93, 0x73, 0x75, 0x63,
+ 0x63, 0xE2, 0x89, 0xBB, 0x73, 0x75, 0x63, 0x63, 0x61, 0x70, 0x70, 0x72,
+ 0x6F, 0x78, 0xE2, 0xAA, 0xB8, 0x73, 0x75, 0x63, 0x63, 0x63, 0x75, 0x72,
+ 0x6C, 0x79, 0x65, 0x71, 0xE2, 0x89, 0xBD, 0x73, 0x75, 0x63, 0x63, 0x65,
+ 0x71, 0xE2, 0xAA, 0xB0, 0x73, 0x75, 0x63, 0x63, 0x6E, 0x61, 0x70, 0x70,
+ 0x72, 0x6F, 0x78, 0xE2, 0xAA, 0xBA, 0x73, 0x75, 0x63, 0x63, 0x6E, 0x65,
+ 0x71, 0x71, 0xE2, 0xAA, 0xB6, 0x73, 0x75, 0x63, 0x63, 0x6E, 0x73, 0x69,
+ 0x6D, 0xE2, 0x8B, 0xA9, 0x73, 0x75, 0x63, 0x63, 0x73, 0x69, 0x6D, 0xE2,
+ 0x89, 0xBF, 0x73, 0x75, 0x6D, 0xE2, 0x88, 0x91, 0x73, 0x75, 0x6E, 0x67,
+ 0xE2, 0x99, 0xAA, 0x73, 0x75, 0x70, 0xE2, 0x8A, 0x83, 0x73, 0x75, 0x70,
+ 0x31, 0xC2, 0xB9, 0x73, 0x75, 0x70, 0x32, 0xC2, 0xB2, 0x73, 0x75, 0x70,
+ 0x33, 0xC2, 0xB3, 0x73, 0x75, 0x70, 0x45, 0xE2, 0xAB, 0x86, 0x73, 0x75,
+ 0x70, 0x64, 0x6F, 0x74, 0xE2, 0xAA, 0xBE, 0x73, 0x75, 0x70, 0x64, 0x73,
+ 0x75, 0x62, 0xE2, 0xAB, 0x98, 0x73, 0x75, 0x70, 0x65, 0xE2, 0x8A, 0x87,
+ 0x73, 0x75, 0x70, 0x65, 0x64, 0x6F, 0x74, 0xE2, 0xAB, 0x84, 0x73, 0x75,
+ 0x70, 0x68, 0x73, 0x6F, 0x6C, 0xE2, 0x9F, 0x89, 0x73, 0x75, 0x70, 0x68,
+ 0x73, 0x75, 0x62, 0xE2, 0xAB, 0x97, 0x73, 0x75, 0x70, 0x6C, 0x61, 0x72,
+ 0x72, 0xE2, 0xA5, 0xBB, 0x73, 0x75, 0x70, 0x6D, 0x75, 0x6C, 0x74, 0xE2,
+ 0xAB, 0x82, 0x73, 0x75, 0x70, 0x6E, 0x45, 0xE2, 0xAB, 0x8C, 0x73, 0x75,
+ 0x70, 0x6E, 0x65, 0xE2, 0x8A, 0x8B, 0x73, 0x75, 0x70, 0x70, 0x6C, 0x75,
+ 0x73, 0xE2, 0xAB, 0x80, 0x73, 0x75, 0x70, 0x73, 0x65, 0x74, 0xE2, 0x8A,
+ 0x83, 0x73, 0x75, 0x70, 0x73, 0x65, 0x74, 0x65, 0x71, 0xE2, 0x8A, 0x87,
+ 0x73, 0x75, 0x70, 0x73, 0x65, 0x74, 0x65, 0x71, 0x71, 0xE2, 0xAB, 0x86,
+ 0x73, 0x75, 0x70, 0x73, 0x65, 0x74, 0x6E, 0x65, 0x71, 0xE2, 0x8A, 0x8B,
+ 0x73, 0x75, 0x70, 0x73, 0x65, 0x74, 0x6E, 0x65, 0x71, 0x71, 0xE2, 0xAB,
+ 0x8C, 0x73, 0x75, 0x70, 0x73, 0x69, 0x6D, 0xE2, 0xAB, 0x88, 0x73, 0x75,
+ 0x70, 0x73, 0x75, 0x62, 0xE2, 0xAB, 0x94, 0x73, 0x75, 0x70, 0x73, 0x75,
+ 0x70, 0xE2, 0xAB, 0x96, 0x73, 0x77, 0x41, 0x72, 0x72, 0xE2, 0x87, 0x99,
+ 0x73, 0x77, 0x61, 0x72, 0x68, 0x6B, 0xE2, 0xA4, 0xA6, 0x73, 0x77, 0x61,
+ 0x72, 0x72, 0xE2, 0x86, 0x99, 0x73, 0x77, 0x61, 0x72, 0x72, 0x6F, 0x77,
+ 0xE2, 0x86, 0x99, 0x73, 0x77, 0x6E, 0x77, 0x61, 0x72, 0xE2, 0xA4, 0xAA,
+ 0x73, 0x7A, 0x6C, 0x69, 0x67, 0xC3, 0x9F, 0x74, 0x61, 0x72, 0x67, 0x65,
+ 0x74, 0xE2, 0x8C, 0x96, 0x74, 0x61, 0x75, 0xCF, 0x84, 0x74, 0x62, 0x72,
+ 0x6B, 0xE2, 0x8E, 0xB4, 0x74, 0x63, 0x61, 0x72, 0x6F, 0x6E, 0xC5, 0xA5,
+ 0x74, 0x63, 0x65, 0x64, 0x69, 0x6C, 0xC5, 0xA3, 0x74, 0x63, 0x79, 0xD1,
+ 0x82, 0x74, 0x64, 0x6F, 0x74, 0xE2, 0x83, 0x9B, 0x74, 0x65, 0x6C, 0x72,
+ 0x65, 0x63, 0xE2, 0x8C, 0x95, 0x74, 0x66, 0x72, 0xF0, 0x9D, 0x94, 0xB1,
+ 0x74, 0x68, 0x65, 0x72, 0x65, 0x34, 0xE2, 0x88, 0xB4, 0x74, 0x68, 0x65,
+ 0x72, 0x65, 0x66, 0x6F, 0x72, 0x65, 0xE2, 0x88, 0xB4, 0x74, 0x68, 0x65,
+ 0x74, 0x61, 0xCE, 0xB8, 0x74, 0x68, 0x65, 0x74, 0x61, 0x73, 0x79, 0x6D,
+ 0xCF, 0x91, 0x74, 0x68, 0x65, 0x74, 0x61, 0x76, 0xCF, 0x91, 0x74, 0x68,
+ 0x69, 0x63, 0x6B, 0x61, 0x70, 0x70, 0x72, 0x6F, 0x78, 0xE2, 0x89, 0x88,
+ 0x74, 0x68, 0x69, 0x63, 0x6B, 0x73, 0x69, 0x6D, 0xE2, 0x88, 0xBC, 0x74,
+ 0x68, 0x69, 0x6E, 0x73, 0x70, 0xE2, 0x80, 0x89, 0x74, 0x68, 0x6B, 0x61,
+ 0x70, 0xE2, 0x89, 0x88, 0x74, 0x68, 0x6B, 0x73, 0x69, 0x6D, 0xE2, 0x88,
+ 0xBC, 0x74, 0x68, 0x6F, 0x72, 0x6E, 0xC3, 0xBE, 0x74, 0x69, 0x6C, 0x64,
+ 0x65, 0xCB, 0x9C, 0x74, 0x69, 0x6D, 0x65, 0x73, 0xC3, 0x97, 0x74, 0x69,
+ 0x6D, 0x65, 0x73, 0x62, 0xE2, 0x8A, 0xA0, 0x74, 0x69, 0x6D, 0x65, 0x73,
+ 0x62, 0x61, 0x72, 0xE2, 0xA8, 0xB1, 0x74, 0x69, 0x6D, 0x65, 0x73, 0x64,
+ 0xE2, 0xA8, 0xB0, 0x74, 0x69, 0x6E, 0x74, 0xE2, 0x88, 0xAD, 0x74, 0x6F,
+ 0x65, 0x61, 0xE2, 0xA4, 0xA8, 0x74, 0x6F, 0x70, 0xE2, 0x8A, 0xA4, 0x74,
+ 0x6F, 0x70, 0x62, 0x6F, 0x74, 0xE2, 0x8C, 0xB6, 0x74, 0x6F, 0x70, 0x63,
+ 0x69, 0x72, 0xE2, 0xAB, 0xB1, 0x74, 0x6F, 0x70, 0x66, 0xF0, 0x9D, 0x95,
+ 0xA5, 0x74, 0x6F, 0x70, 0x66, 0x6F, 0x72, 0x6B, 0xE2, 0xAB, 0x9A, 0x74,
+ 0x6F, 0x73, 0x61, 0xE2, 0xA4, 0xA9, 0x74, 0x70, 0x72, 0x69, 0x6D, 0x65,
+ 0xE2, 0x80, 0xB4, 0x74, 0x72, 0x61, 0x64, 0x65, 0xE2, 0x84, 0xA2, 0x74,
+ 0x72, 0x69, 0x61, 0x6E, 0x67, 0x6C, 0x65, 0xE2, 0x96, 0xB5, 0x74, 0x72,
+ 0x69, 0x61, 0x6E, 0x67, 0x6C, 0x65, 0x64, 0x6F, 0x77, 0x6E, 0xE2, 0x96,
+ 0xBF, 0x74, 0x72, 0x69, 0x61, 0x6E, 0x67, 0x6C, 0x65, 0x6C, 0x65, 0x66,
+ 0x74, 0xE2, 0x97, 0x83, 0x74, 0x72, 0x69, 0x61, 0x6E, 0x67, 0x6C, 0x65,
+ 0x6C, 0x65, 0x66, 0x74, 0x65, 0x71, 0xE2, 0x8A, 0xB4, 0x74, 0x72, 0x69,
+ 0x61, 0x6E, 0x67, 0x6C, 0x65, 0x71, 0xE2, 0x89, 0x9C, 0x74, 0x72, 0x69,
+ 0x61, 0x6E, 0x67, 0x6C, 0x65, 0x72, 0x69, 0x67, 0x68, 0x74, 0xE2, 0x96,
+ 0xB9, 0x74, 0x72, 0x69, 0x61, 0x6E, 0x67, 0x6C, 0x65, 0x72, 0x69, 0x67,
+ 0x68, 0x74, 0x65, 0x71, 0xE2, 0x8A, 0xB5, 0x74, 0x72, 0x69, 0x64, 0x6F,
+ 0x74, 0xE2, 0x97, 0xAC, 0x74, 0x72, 0x69, 0x65, 0xE2, 0x89, 0x9C, 0x74,
+ 0x72, 0x69, 0x6D, 0x69, 0x6E, 0x75, 0x73, 0xE2, 0xA8, 0xBA, 0x74, 0x72,
+ 0x69, 0x70, 0x6C, 0x75, 0x73, 0xE2, 0xA8, 0xB9, 0x74, 0x72, 0x69, 0x73,
+ 0x62, 0xE2, 0xA7, 0x8D, 0x74, 0x72, 0x69, 0x74, 0x69, 0x6D, 0x65, 0xE2,
+ 0xA8, 0xBB, 0x74, 0x72, 0x70, 0x65, 0x7A, 0x69, 0x75, 0x6D, 0xE2, 0x8F,
+ 0xA2, 0x74, 0x73, 0x63, 0x72, 0xF0, 0x9D, 0x93, 0x89, 0x74, 0x73, 0x63,
+ 0x79, 0xD1, 0x86, 0x74, 0x73, 0x68, 0x63, 0x79, 0xD1, 0x9B, 0x74, 0x73,
+ 0x74, 0x72, 0x6F, 0x6B, 0xC5, 0xA7, 0x74, 0x77, 0x69, 0x78, 0x74, 0xE2,
+ 0x89, 0xAC, 0x74, 0x77, 0x6F, 0x68, 0x65, 0x61, 0x64, 0x6C, 0x65, 0x66,
+ 0x74, 0x61, 0x72, 0x72, 0x6F, 0x77, 0xE2, 0x86, 0x9E, 0x74, 0x77, 0x6F,
+ 0x68, 0x65, 0x61, 0x64, 0x72, 0x69, 0x67, 0x68, 0x74, 0x61, 0x72, 0x72,
+ 0x6F, 0x77, 0xE2, 0x86, 0xA0, 0x75, 0x41, 0x72, 0x72, 0xE2, 0x87, 0x91,
+ 0x75, 0x48, 0x61, 0x72, 0xE2, 0xA5, 0xA3, 0x75, 0x61, 0x63, 0x75, 0x74,
+ 0x65, 0xC3, 0xBA, 0x75, 0x61, 0x72, 0x72, 0xE2, 0x86, 0x91, 0x75, 0x62,
+ 0x72, 0x63, 0x79, 0xD1, 0x9E, 0x75, 0x62, 0x72, 0x65, 0x76, 0x65, 0xC5,
+ 0xAD, 0x75, 0x63, 0x69, 0x72, 0x63, 0xC3, 0xBB, 0x75, 0x63, 0x79, 0xD1,
+ 0x83, 0x75, 0x64, 0x61, 0x72, 0x72, 0xE2, 0x87, 0x85, 0x75, 0x64, 0x62,
+ 0x6C, 0x61, 0x63, 0xC5, 0xB1, 0x75, 0x64, 0x68, 0x61, 0x72, 0xE2, 0xA5,
+ 0xAE, 0x75, 0x66, 0x69, 0x73, 0x68, 0x74, 0xE2, 0xA5, 0xBE, 0x75, 0x66,
+ 0x72, 0xF0, 0x9D, 0x94, 0xB2, 0x75, 0x67, 0x72, 0x61, 0x76, 0x65, 0xC3,
+ 0xB9, 0x75, 0x68, 0x61, 0x72, 0x6C, 0xE2, 0x86, 0xBF, 0x75, 0x68, 0x61,
+ 0x72, 0x72, 0xE2, 0x86, 0xBE, 0x75, 0x68, 0x62, 0x6C, 0x6B, 0xE2, 0x96,
+ 0x80, 0x75, 0x6C, 0x63, 0x6F, 0x72, 0x6E, 0xE2, 0x8C, 0x9C, 0x75, 0x6C,
+ 0x63, 0x6F, 0x72, 0x6E, 0x65, 0x72, 0xE2, 0x8C, 0x9C, 0x75, 0x6C, 0x63,
+ 0x72, 0x6F, 0x70, 0xE2, 0x8C, 0x8F, 0x75, 0x6C, 0x74, 0x72, 0x69, 0xE2,
+ 0x97, 0xB8, 0x75, 0x6D, 0x61, 0x63, 0x72, 0xC5, 0xAB, 0x75, 0x6D, 0x6C,
+ 0xC2, 0xA8, 0x75, 0x6F, 0x67, 0x6F, 0x6E, 0xC5, 0xB3, 0x75, 0x6F, 0x70,
+ 0x66, 0xF0, 0x9D, 0x95, 0xA6, 0x75, 0x70, 0x61, 0x72, 0x72, 0x6F, 0x77,
+ 0xE2, 0x86, 0x91, 0x75, 0x70, 0x64, 0x6F, 0x77, 0x6E, 0x61, 0x72, 0x72,
+ 0x6F, 0x77, 0xE2, 0x86, 0x95, 0x75, 0x70, 0x68, 0x61, 0x72, 0x70, 0x6F,
+ 0x6F, 0x6E, 0x6C, 0x65, 0x66, 0x74, 0xE2, 0x86, 0xBF, 0x75, 0x70, 0x68,
+ 0x61, 0x72, 0x70, 0x6F, 0x6F, 0x6E, 0x72, 0x69, 0x67, 0x68, 0x74, 0xE2,
+ 0x86, 0xBE, 0x75, 0x70, 0x6C, 0x75, 0x73, 0xE2, 0x8A, 0x8E, 0x75, 0x70,
+ 0x73, 0x69, 0xCF, 0x85, 0x75, 0x70, 0x73, 0x69, 0x68, 0xCF, 0x92, 0x75,
+ 0x70, 0x73, 0x69, 0x6C, 0x6F, 0x6E, 0xCF, 0x85, 0x75, 0x70, 0x75, 0x70,
+ 0x61, 0x72, 0x72, 0x6F, 0x77, 0x73, 0xE2, 0x87, 0x88, 0x75, 0x72, 0x63,
+ 0x6F, 0x72, 0x6E, 0xE2, 0x8C, 0x9D, 0x75, 0x72, 0x63, 0x6F, 0x72, 0x6E,
+ 0x65, 0x72, 0xE2, 0x8C, 0x9D, 0x75, 0x72, 0x63, 0x72, 0x6F, 0x70, 0xE2,
+ 0x8C, 0x8E, 0x75, 0x72, 0x69, 0x6E, 0x67, 0xC5, 0xAF, 0x75, 0x72, 0x74,
+ 0x72, 0x69, 0xE2, 0x97, 0xB9, 0x75, 0x73, 0x63, 0x72, 0xF0, 0x9D, 0x93,
+ 0x8A, 0x75, 0x74, 0x64, 0x6F, 0x74, 0xE2, 0x8B, 0xB0, 0x75, 0x74, 0x69,
+ 0x6C, 0x64, 0x65, 0xC5, 0xA9, 0x75, 0x74, 0x72, 0x69, 0xE2, 0x96, 0xB5,
+ 0x75, 0x74, 0x72, 0x69, 0x66, 0xE2, 0x96, 0xB4, 0x75, 0x75, 0x61, 0x72,
+ 0x72, 0xE2, 0x87, 0x88, 0x75, 0x75, 0x6D, 0x6C, 0xC3, 0xBC, 0x75, 0x77,
+ 0x61, 0x6E, 0x67, 0x6C, 0x65, 0xE2, 0xA6, 0xA7, 0x76, 0x41, 0x72, 0x72,
+ 0xE2, 0x87, 0x95, 0x76, 0x42, 0x61, 0x72, 0xE2, 0xAB, 0xA8, 0x76, 0x42,
+ 0x61, 0x72, 0x76, 0xE2, 0xAB, 0xA9, 0x76, 0x44, 0x61, 0x73, 0x68, 0xE2,
+ 0x8A, 0xA8, 0x76, 0x61, 0x6E, 0x67, 0x72, 0x74, 0xE2, 0xA6, 0x9C, 0x76,
+ 0x61, 0x72, 0x65, 0x70, 0x73, 0x69, 0x6C, 0x6F, 0x6E, 0xCF, 0xB5, 0x76,
+ 0x61, 0x72, 0x6B, 0x61, 0x70, 0x70, 0x61, 0xCF, 0xB0, 0x76, 0x61, 0x72,
+ 0x6E, 0x6F, 0x74, 0x68, 0x69, 0x6E, 0x67, 0xE2, 0x88, 0x85, 0x76, 0x61,
+ 0x72, 0x70, 0x68, 0x69, 0xCF, 0x95, 0x76, 0x61, 0x72, 0x70, 0x69, 0xCF,
+ 0x96, 0x76, 0x61, 0x72, 0x70, 0x72, 0x6F, 0x70, 0x74, 0x6F, 0xE2, 0x88,
+ 0x9D, 0x76, 0x61, 0x72, 0x72, 0xE2, 0x86, 0x95, 0x76, 0x61, 0x72, 0x72,
+ 0x68, 0x6F, 0xCF, 0xB1, 0x76, 0x61, 0x72, 0x73, 0x69, 0x67, 0x6D, 0x61,
+ 0xCF, 0x82, 0x76, 0x61, 0x72, 0x73, 0x75, 0x62, 0x73, 0x65, 0x74, 0x6E,
+ 0x65, 0x71, 0xE2, 0x8A, 0x8A, 0xEF, 0xB8, 0x80, 0x76, 0x61, 0x72, 0x73,
+ 0x75, 0x62, 0x73, 0x65, 0x74, 0x6E, 0x65, 0x71, 0x71, 0xE2, 0xAB, 0x8B,
+ 0xEF, 0xB8, 0x80, 0x76, 0x61, 0x72, 0x73, 0x75, 0x70, 0x73, 0x65, 0x74,
+ 0x6E, 0x65, 0x71, 0xE2, 0x8A, 0x8B, 0xEF, 0xB8, 0x80, 0x76, 0x61, 0x72,
+ 0x73, 0x75, 0x70, 0x73, 0x65, 0x74, 0x6E, 0x65, 0x71, 0x71, 0xE2, 0xAB,
+ 0x8C, 0xEF, 0xB8, 0x80, 0x76, 0x61, 0x72, 0x74, 0x68, 0x65, 0x74, 0x61,
+ 0xCF, 0x91, 0x76, 0x61, 0x72, 0x74, 0x72, 0x69, 0x61, 0x6E, 0x67, 0x6C,
+ 0x65, 0x6C, 0x65, 0x66, 0x74, 0xE2, 0x8A, 0xB2, 0x76, 0x61, 0x72, 0x74,
+ 0x72, 0x69, 0x61, 0x6E, 0x67, 0x6C, 0x65, 0x72, 0x69, 0x67, 0x68, 0x74,
+ 0xE2, 0x8A, 0xB3, 0x76, 0x63, 0x79, 0xD0, 0xB2, 0x76, 0x64, 0x61, 0x73,
+ 0x68, 0xE2, 0x8A, 0xA2, 0x76, 0x65, 0x65, 0xE2, 0x88, 0xA8, 0x76, 0x65,
+ 0x65, 0x62, 0x61, 0x72, 0xE2, 0x8A, 0xBB, 0x76, 0x65, 0x65, 0x65, 0x71,
+ 0xE2, 0x89, 0x9A, 0x76, 0x65, 0x6C, 0x6C, 0x69, 0x70, 0xE2, 0x8B, 0xAE,
+ 0x76, 0x65, 0x72, 0x62, 0x61, 0x72, 0x7C, 0x76, 0x65, 0x72, 0x74, 0x7C,
+ 0x76, 0x66, 0x72, 0xF0, 0x9D, 0x94, 0xB3, 0x76, 0x6C, 0x74, 0x72, 0x69,
+ 0xE2, 0x8A, 0xB2, 0x76, 0x6E, 0x73, 0x75, 0x62, 0xE2, 0x8A, 0x82, 0xE2,
+ 0x83, 0x92, 0x76, 0x6E, 0x73, 0x75, 0x70, 0xE2, 0x8A, 0x83, 0xE2, 0x83,
+ 0x92, 0x76, 0x6F, 0x70, 0x66, 0xF0, 0x9D, 0x95, 0xA7, 0x76, 0x70, 0x72,
+ 0x6F, 0x70, 0xE2, 0x88, 0x9D, 0x76, 0x72, 0x74, 0x72, 0x69, 0xE2, 0x8A,
+ 0xB3, 0x76, 0x73, 0x63, 0x72, 0xF0, 0x9D, 0x93, 0x8B, 0x76, 0x73, 0x75,
+ 0x62, 0x6E, 0x45, 0xE2, 0xAB, 0x8B, 0xEF, 0xB8, 0x80, 0x76, 0x73, 0x75,
+ 0x62, 0x6E, 0x65, 0xE2, 0x8A, 0x8A, 0xEF, 0xB8, 0x80, 0x76, 0x73, 0x75,
+ 0x70, 0x6E, 0x45, 0xE2, 0xAB, 0x8C, 0xEF, 0xB8, 0x80, 0x76, 0x73, 0x75,
+ 0x70, 0x6E, 0x65, 0xE2, 0x8A, 0x8B, 0xEF, 0xB8, 0x80, 0x76, 0x7A, 0x69,
+ 0x67, 0x7A, 0x61, 0x67, 0xE2, 0xA6, 0x9A, 0x77, 0x63, 0x69, 0x72, 0x63,
+ 0xC5, 0xB5, 0x77, 0x65, 0x64, 0x62, 0x61, 0x72, 0xE2, 0xA9, 0x9F, 0x77,
+ 0x65, 0x64, 0x67, 0x65, 0xE2, 0x88, 0xA7, 0x77, 0x65, 0x64, 0x67, 0x65,
+ 0x71, 0xE2, 0x89, 0x99, 0x77, 0x65, 0x69, 0x65, 0x72, 0x70, 0xE2, 0x84,
+ 0x98, 0x77, 0x66, 0x72, 0xF0, 0x9D, 0x94, 0xB4, 0x77, 0x6F, 0x70, 0x66,
+ 0xF0, 0x9D, 0x95, 0xA8, 0x77, 0x70, 0xE2, 0x84, 0x98, 0x77, 0x72, 0xE2,
+ 0x89, 0x80, 0x77, 0x72, 0x65, 0x61, 0x74, 0x68, 0xE2, 0x89, 0x80, 0x77,
+ 0x73, 0x63, 0x72, 0xF0, 0x9D, 0x93, 0x8C, 0x78, 0x63, 0x61, 0x70, 0xE2,
+ 0x8B, 0x82, 0x78, 0x63, 0x69, 0x72, 0x63, 0xE2, 0x97, 0xAF, 0x78, 0x63,
+ 0x75, 0x70, 0xE2, 0x8B, 0x83, 0x78, 0x64, 0x74, 0x72, 0x69, 0xE2, 0x96,
+ 0xBD, 0x78, 0x66, 0x72, 0xF0, 0x9D, 0x94, 0xB5, 0x78, 0x68, 0x41, 0x72,
+ 0x72, 0xE2, 0x9F, 0xBA, 0x78, 0x68, 0x61, 0x72, 0x72, 0xE2, 0x9F, 0xB7,
+ 0x78, 0x69, 0xCE, 0xBE, 0x78, 0x6C, 0x41, 0x72, 0x72, 0xE2, 0x9F, 0xB8,
+ 0x78, 0x6C, 0x61, 0x72, 0x72, 0xE2, 0x9F, 0xB5, 0x78, 0x6D, 0x61, 0x70,
+ 0xE2, 0x9F, 0xBC, 0x78, 0x6E, 0x69, 0x73, 0xE2, 0x8B, 0xBB, 0x78, 0x6F,
+ 0x64, 0x6F, 0x74, 0xE2, 0xA8, 0x80, 0x78, 0x6F, 0x70, 0x66, 0xF0, 0x9D,
+ 0x95, 0xA9, 0x78, 0x6F, 0x70, 0x6C, 0x75, 0x73, 0xE2, 0xA8, 0x81, 0x78,
+ 0x6F, 0x74, 0x69, 0x6D, 0x65, 0xE2, 0xA8, 0x82, 0x78, 0x72, 0x41, 0x72,
+ 0x72, 0xE2, 0x9F, 0xB9, 0x78, 0x72, 0x61, 0x72, 0x72, 0xE2, 0x9F, 0xB6,
+ 0x78, 0x73, 0x63, 0x72, 0xF0, 0x9D, 0x93, 0x8D, 0x78, 0x73, 0x71, 0x63,
+ 0x75, 0x70, 0xE2, 0xA8, 0x86, 0x78, 0x75, 0x70, 0x6C, 0x75, 0x73, 0xE2,
+ 0xA8, 0x84, 0x78, 0x75, 0x74, 0x72, 0x69, 0xE2, 0x96, 0xB3, 0x78, 0x76,
+ 0x65, 0x65, 0xE2, 0x8B, 0x81, 0x78, 0x77, 0x65, 0x64, 0x67, 0x65, 0xE2,
+ 0x8B, 0x80, 0x79, 0x61, 0x63, 0x75, 0x74, 0x65, 0xC3, 0xBD, 0x79, 0x61,
+ 0x63, 0x79, 0xD1, 0x8F, 0x79, 0x63, 0x69, 0x72, 0x63, 0xC5, 0xB7, 0x79,
+ 0x63, 0x79, 0xD1, 0x8B, 0x79, 0x65, 0x6E, 0xC2, 0xA5, 0x79, 0x66, 0x72,
+ 0xF0, 0x9D, 0x94, 0xB6, 0x79, 0x69, 0x63, 0x79, 0xD1, 0x97, 0x79, 0x6F,
+ 0x70, 0x66, 0xF0, 0x9D, 0x95, 0xAA, 0x79, 0x73, 0x63, 0x72, 0xF0, 0x9D,
+ 0x93, 0x8E, 0x79, 0x75, 0x63, 0x79, 0xD1, 0x8E, 0x79, 0x75, 0x6D, 0x6C,
+ 0xC3, 0xBF, 0x7A, 0x61, 0x63, 0x75, 0x74, 0x65, 0xC5, 0xBA, 0x7A, 0x63,
+ 0x61, 0x72, 0x6F, 0x6E, 0xC5, 0xBE, 0x7A, 0x63, 0x79, 0xD0, 0xB7, 0x7A,
+ 0x64, 0x6F, 0x74, 0xC5, 0xBC, 0x7A, 0x65, 0x65, 0x74, 0x72, 0x66, 0xE2,
+ 0x84, 0xA8, 0x7A, 0x65, 0x74, 0x61, 0xCE, 0xB6, 0x7A, 0x66, 0x72, 0xF0,
+ 0x9D, 0x94, 0xB7, 0x7A, 0x68, 0x63, 0x79, 0xD0, 0xB6, 0x7A, 0x69, 0x67,
+ 0x72, 0x61, 0x72, 0x72, 0xE2, 0x87, 0x9D, 0x7A, 0x6F, 0x70, 0x66, 0xF0,
+ 0x9D, 0x95, 0xAB, 0x7A, 0x73, 0x63, 0x72, 0xF0, 0x9D, 0x93, 0x8F, 0x7A,
+ 0x77, 0x6A, 0xE2, 0x80, 0x8D, 0x7A, 0x77, 0x6E, 0x6A, 0xE2, 0x80, 0x8C
+};
diff --git a/cmark/src/houdini.h b/cmark/src/houdini.h
new file mode 100644
index 0000000000..69d4fec95c
--- /dev/null
+++ b/cmark/src/houdini.h
@@ -0,0 +1,41 @@
+#ifndef CMARK_HOUDINI_H
+#define CMARK_HOUDINI_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+#include "buffer.h"
+
+#ifdef HOUDINI_USE_LOCALE
+#define _isxdigit(c) isxdigit(c)
+#define _isdigit(c) isdigit(c)
+#else
+/*
+ * Helper _isdigit methods -- do not trust the current locale
+ * */
+#define _isxdigit(c) (strchr("0123456789ABCDEFabcdef", (c)) != NULL)
+#define _isdigit(c) ((c) >= '0' && (c) <= '9')
+#endif
+
+#define HOUDINI_ESCAPED_SIZE(x) (((x)*12) / 10)
+#define HOUDINI_UNESCAPED_SIZE(x) (x)
+
+bufsize_t houdini_unescape_ent(cmark_strbuf *ob, const uint8_t *src,
+ bufsize_t size);
+int houdini_escape_html(cmark_strbuf *ob, const uint8_t *src,
+ bufsize_t size, int secure);
+int houdini_unescape_html(cmark_strbuf *ob, const uint8_t *src,
+ bufsize_t size);
+void houdini_unescape_html_f(cmark_strbuf *ob, const uint8_t *src,
+ bufsize_t size);
+int houdini_escape_href(cmark_strbuf *ob, const uint8_t *src,
+ bufsize_t size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/cmark/src/houdini_href_e.c b/cmark/src/houdini_href_e.c
new file mode 100644
index 0000000000..38f2a58264
--- /dev/null
+++ b/cmark/src/houdini_href_e.c
@@ -0,0 +1,111 @@
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "houdini.h"
+
+#if !defined(__has_builtin)
+# define __has_builtin(b) 0
+#endif
+
+#if !__has_builtin(__builtin_expect)
+# define __builtin_expect(e, v) (e)
+#endif
+
+#define likely(e) __builtin_expect((e), 1)
+#define unlikely(e) __builtin_expect((e), 0)
+
+/*
+ * The following characters will not be escaped:
+ *
+ * -_.+!*'(),%#@?=;:/,+&$~ alphanum
+ *
+ * Note that this character set is the addition of:
+ *
+ * - The characters which are safe to be in an URL
+ * - The characters which are *not* safe to be in
+ * an URL because they are RESERVED characters.
+ *
+ * We assume (lazily) that any RESERVED char that
+ * appears inside an URL is actually meant to
+ * have its native function (i.e. as an URL
+ * component/separator) and hence needs no escaping.
+ *
+ * There are two exceptions: the characters & (amp)
+ * and ' (single quote) do not appear in the table.
+ * They are meant to appear in the URL as components,
+ * yet they require special HTML-entity escaping
+ * to generate valid HTML markup.
+ *
+ * All other characters will be escaped to %XX.
+ *
+ */
+static const char HREF_SAFE[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+int houdini_escape_href(cmark_strbuf *ob, const uint8_t *src, bufsize_t size) {
+ static const uint8_t hex_chars[] = "0123456789ABCDEF";
+ bufsize_t i = 0, org;
+ uint8_t hex_str[3];
+
+ hex_str[0] = '%';
+
+ while (i < size) {
+ org = i;
+ while (i < size && HREF_SAFE[src[i]] != 0)
+ i++;
+
+ if (likely(i > org))
+ cmark_strbuf_put(ob, src + org, i - org);
+
+ /* escaping */
+ if (i >= size)
+ break;
+
+ switch (src[i]) {
+ /* amp appears all the time in URLs, but needs
+ * HTML-entity escaping to be inside an href */
+ case '&':
+ cmark_strbuf_puts(ob, "&amp;");
+ break;
+
+ /* the single quote is a valid URL character
+ * according to the standard; it needs HTML
+ * entity escaping too */
+ case '\'':
+ cmark_strbuf_puts(ob, "&#x27;");
+ break;
+
+/* the space can be escaped to %20 or a plus
+ * sign. we're going with the generic escape
+ * for now. the plus thing is more commonly seen
+ * when building GET strings */
+#if 0
+ case ' ':
+ cmark_strbuf_putc(ob, '+');
+ break;
+#endif
+
+ /* every other character goes with a %XX escaping */
+ default:
+ hex_str[1] = hex_chars[(src[i] >> 4) & 0xF];
+ hex_str[2] = hex_chars[src[i] & 0xF];
+ cmark_strbuf_put(ob, hex_str, 3);
+ }
+
+ i++;
+ }
+
+ return 1;
+}
diff --git a/cmark/src/houdini_html_e.c b/cmark/src/houdini_html_e.c
new file mode 100644
index 0000000000..111bc1374f
--- /dev/null
+++ b/cmark/src/houdini_html_e.c
@@ -0,0 +1,73 @@
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "houdini.h"
+
+#if !defined(__has_builtin)
+# define __has_builtin(b) 0
+#endif
+
+#if !__has_builtin(__builtin_expect)
+# define __builtin_expect(e, v) (e)
+#endif
+
+#define likely(e) __builtin_expect((e), 1)
+#define unlikely(e) __builtin_expect((e), 0)
+
+/**
+ * According to the OWASP rules:
+ *
+ * & --> &amp;
+ * < --> &lt;
+ * > --> &gt;
+ * " --> &quot;
+ * ' --> &#x27; &apos; is not recommended
+ * / --> &#x2F; forward slash is included as it helps end an HTML entity
+ *
+ */
+static const char HTML_ESCAPE_TABLE[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 3, 0, 0, 0, 0, 0, 0, 0, 4,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+static const char *HTML_ESCAPES[] = {"", "&quot;", "&amp;", "&#39;",
+ "&#47;", "&lt;", "&gt;"};
+
+int houdini_escape_html(cmark_strbuf *ob, const uint8_t *src, bufsize_t size,
+ int secure) {
+ bufsize_t i = 0, org, esc = 0;
+
+ while (i < size) {
+ org = i;
+ while (i < size && (esc = HTML_ESCAPE_TABLE[src[i]]) == 0)
+ i++;
+
+ if (i > org)
+ cmark_strbuf_put(ob, src + org, i - org);
+
+ /* escaping */
+ if (unlikely(i >= size))
+ break;
+
+ /* The forward slash is only escaped in secure mode */
+ if ((src[i] == '/' || src[i] == '\'') && !secure) {
+ cmark_strbuf_putc(ob, src[i]);
+ } else {
+ cmark_strbuf_puts(ob, HTML_ESCAPES[esc]);
+ }
+
+ i++;
+ }
+
+ return 1;
+}
diff --git a/cmark/src/houdini_html_u.c b/cmark/src/houdini_html_u.c
new file mode 100644
index 0000000000..07ac34a412
--- /dev/null
+++ b/cmark/src/houdini_html_u.c
@@ -0,0 +1,174 @@
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "buffer.h"
+#include "houdini.h"
+#include "utf8.h"
+#include "entities.inc"
+
+#if !defined(__has_builtin)
+# define __has_builtin(b) 0
+#endif
+
+#if !__has_builtin(__builtin_expect)
+# define __builtin_expect(e, v) (e)
+#endif
+
+#define likely(e) __builtin_expect((e), 1)
+#define unlikely(e) __builtin_expect((e), 0)
+
+/* Binary tree lookup code for entities added by JGM */
+
+static const unsigned char *S_lookup(int i, int low, int hi,
+ const unsigned char *s, int len,
+ bufsize_t *size_out) {
+ int j;
+ uint32_t value = cmark_entities[i];
+ const unsigned char *ent_name = cmark_entity_text + ENT_TEXT_IDX(value);
+ int ent_len = ENT_NAME_SIZE(value);
+ int min_len = len < ent_len ? len : ent_len;
+ int cmp =
+ strncmp((const char *)s, (const char *)ent_name, min_len);
+ if (cmp == 0)
+ cmp = len - ent_len;
+ if (cmp == 0) {
+ *size_out = ENT_REPL_SIZE(value);
+ return ent_name + ent_len;
+ } else if (cmp <= 0 && i > low) {
+ j = i - ((i - low) / 2);
+ if (j == i)
+ j -= 1;
+ return S_lookup(j, low, i - 1, s, len, size_out);
+ } else if (cmp > 0 && i < hi) {
+ j = i + ((hi - i) / 2);
+ if (j == i)
+ j += 1;
+ return S_lookup(j, i + 1, hi, s, len, size_out);
+ } else {
+ return NULL;
+ }
+}
+
+static const unsigned char *S_lookup_entity(const unsigned char *s, int len,
+ bufsize_t *size_out) {
+ return S_lookup(ENT_TABLE_SIZE / 2, 0, ENT_TABLE_SIZE - 1, s, len, size_out);
+}
+
+bufsize_t houdini_unescape_ent(cmark_strbuf *ob, const uint8_t *src,
+ bufsize_t size) {
+ bufsize_t i = 0;
+
+ if (size >= 3 && src[0] == '#') {
+ int codepoint = 0;
+ int num_digits = 0;
+ int max_digits = 7;
+
+ if (_isdigit(src[1])) {
+ for (i = 1; i < size && _isdigit(src[i]); ++i) {
+ codepoint = (codepoint * 10) + (src[i] - '0');
+
+ if (codepoint >= 0x110000) {
+ // Keep counting digits but
+ // avoid integer overflow.
+ codepoint = 0x110000;
+ }
+ }
+
+ num_digits = i - 1;
+ max_digits = 7;
+ }
+
+ else if (src[1] == 'x' || src[1] == 'X') {
+ for (i = 2; i < size && _isxdigit(src[i]); ++i) {
+ codepoint = (codepoint * 16) + ((src[i] | 32) % 39 - 9);
+
+ if (codepoint >= 0x110000) {
+ // Keep counting digits but
+ // avoid integer overflow.
+ codepoint = 0x110000;
+ }
+ }
+
+ num_digits = i - 2;
+ max_digits = 6;
+ }
+
+ if (num_digits >= 1 && num_digits <= max_digits &&
+ i < size && src[i] == ';') {
+ if (codepoint == 0 || (codepoint >= 0xD800 && codepoint < 0xE000) ||
+ codepoint >= 0x110000) {
+ codepoint = 0xFFFD;
+ }
+ cmark_utf8proc_encode_char(codepoint, ob);
+ return i + 1;
+ }
+ }
+
+ else {
+ if (size > ENT_MAX_LENGTH)
+ size = ENT_MAX_LENGTH;
+
+ for (i = ENT_MIN_LENGTH; i < size; ++i) {
+ if (src[i] == ' ')
+ break;
+
+ if (src[i] == ';') {
+ bufsize_t size;
+ const unsigned char *entity = S_lookup_entity(src, i, &size);
+
+ if (entity != NULL) {
+ cmark_strbuf_put(ob, entity, size);
+ return i + 1;
+ }
+
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+int houdini_unescape_html(cmark_strbuf *ob, const uint8_t *src,
+ bufsize_t size) {
+ bufsize_t i = 0, org, ent;
+
+ while (i < size) {
+ org = i;
+ while (i < size && src[i] != '&')
+ i++;
+
+ if (likely(i > org)) {
+ if (unlikely(org == 0)) {
+ if (i >= size)
+ return 0;
+
+ cmark_strbuf_grow(ob, HOUDINI_UNESCAPED_SIZE(size));
+ }
+
+ cmark_strbuf_put(ob, src + org, i - org);
+ }
+
+ /* escaping */
+ if (i >= size)
+ break;
+
+ i++;
+
+ ent = houdini_unescape_ent(ob, src + i, size - i);
+ i += ent;
+
+ /* not really an entity */
+ if (ent == 0)
+ cmark_strbuf_putc(ob, '&');
+ }
+
+ return 1;
+}
+
+void houdini_unescape_html_f(cmark_strbuf *ob, const uint8_t *src,
+ bufsize_t size) {
+ if (!houdini_unescape_html(ob, src, size))
+ cmark_strbuf_put(ob, src, size);
+}
diff --git a/cmark/src/html.c b/cmark/src/html.c
new file mode 100644
index 0000000000..5c14fa6f89
--- /dev/null
+++ b/cmark/src/html.c
@@ -0,0 +1,345 @@
+#include <assert.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "cmark_ctype.h"
+#include "cmark.h"
+#include "node.h"
+#include "buffer.h"
+#include "houdini.h"
+#include "scanners.h"
+
+#define BUFFER_SIZE 100
+
+// Functions to convert cmark_nodes to HTML strings.
+
+static void escape_html(cmark_strbuf *dest, const unsigned char *source,
+ bufsize_t length) {
+ houdini_escape_html(dest, source, length, 0);
+}
+
+static inline void cr(cmark_strbuf *html) {
+ if (html->size && html->ptr[html->size - 1] != '\n')
+ cmark_strbuf_putc(html, '\n');
+}
+
+struct render_state {
+ cmark_strbuf *html;
+ cmark_node *plain;
+};
+
+static void S_render_sourcepos(cmark_node *node, cmark_strbuf *html,
+ int options) {
+ char buffer[BUFFER_SIZE];
+ if (CMARK_OPT_SOURCEPOS & options) {
+ snprintf(buffer, BUFFER_SIZE, " data-sourcepos=\"%d:%d-%d:%d\"",
+ cmark_node_get_start_line(node), cmark_node_get_start_column(node),
+ cmark_node_get_end_line(node), cmark_node_get_end_column(node));
+ cmark_strbuf_puts(html, buffer);
+ }
+}
+
+static int S_render_node(cmark_node *node, cmark_event_type ev_type,
+ struct render_state *state, int options) {
+ cmark_node *parent;
+ cmark_node *grandparent;
+ cmark_strbuf *html = state->html;
+ char start_heading[] = "<h0";
+ char end_heading[] = "</h0";
+ bool tight;
+ char buffer[BUFFER_SIZE];
+
+ bool entering = (ev_type == CMARK_EVENT_ENTER);
+
+ if (state->plain == node) { // back at original node
+ state->plain = NULL;
+ }
+
+ if (state->plain != NULL) {
+ switch (node->type) {
+ case CMARK_NODE_TEXT:
+ case CMARK_NODE_CODE:
+ case CMARK_NODE_HTML_INLINE:
+ escape_html(html, node->data, node->len);
+ break;
+
+ case CMARK_NODE_LINEBREAK:
+ case CMARK_NODE_SOFTBREAK:
+ cmark_strbuf_putc(html, ' ');
+ break;
+
+ default:
+ break;
+ }
+ return 1;
+ }
+
+ switch (node->type) {
+ case CMARK_NODE_DOCUMENT:
+ break;
+
+ case CMARK_NODE_BLOCK_QUOTE:
+ if (entering) {
+ cr(html);
+ cmark_strbuf_puts(html, "<blockquote");
+ S_render_sourcepos(node, html, options);
+ cmark_strbuf_puts(html, ">\n");
+ } else {
+ cr(html);
+ cmark_strbuf_puts(html, "</blockquote>\n");
+ }
+ break;
+
+ case CMARK_NODE_LIST: {
+ cmark_list_type list_type = (cmark_list_type)node->as.list.list_type;
+ int start = node->as.list.start;
+
+ if (entering) {
+ cr(html);
+ if (list_type == CMARK_BULLET_LIST) {
+ cmark_strbuf_puts(html, "<ul");
+ S_render_sourcepos(node, html, options);
+ cmark_strbuf_puts(html, ">\n");
+ } else if (start == 1) {
+ cmark_strbuf_puts(html, "<ol");
+ S_render_sourcepos(node, html, options);
+ cmark_strbuf_puts(html, ">\n");
+ } else {
+ snprintf(buffer, BUFFER_SIZE, "<ol start=\"%d\"", start);
+ cmark_strbuf_puts(html, buffer);
+ S_render_sourcepos(node, html, options);
+ cmark_strbuf_puts(html, ">\n");
+ }
+ } else {
+ cmark_strbuf_puts(html,
+ list_type == CMARK_BULLET_LIST ? "</ul>\n" : "</ol>\n");
+ }
+ break;
+ }
+
+ case CMARK_NODE_ITEM:
+ if (entering) {
+ cr(html);
+ cmark_strbuf_puts(html, "<li");
+ S_render_sourcepos(node, html, options);
+ cmark_strbuf_putc(html, '>');
+ } else {
+ cmark_strbuf_puts(html, "</li>\n");
+ }
+ break;
+
+ case CMARK_NODE_HEADING:
+ if (entering) {
+ cr(html);
+ start_heading[2] = (char)('0' + node->as.heading.level);
+ cmark_strbuf_puts(html, start_heading);
+ S_render_sourcepos(node, html, options);
+ cmark_strbuf_putc(html, '>');
+ } else {
+ end_heading[3] = (char)('0' + node->as.heading.level);
+ cmark_strbuf_puts(html, end_heading);
+ cmark_strbuf_puts(html, ">\n");
+ }
+ break;
+
+ case CMARK_NODE_CODE_BLOCK:
+ cr(html);
+
+ if (node->as.code.info == NULL || node->as.code.info[0] == 0) {
+ cmark_strbuf_puts(html, "<pre");
+ S_render_sourcepos(node, html, options);
+ cmark_strbuf_puts(html, "><code>");
+ } else {
+ bufsize_t first_tag = 0;
+ while (node->as.code.info[first_tag] &&
+ !cmark_isspace(node->as.code.info[first_tag])) {
+ first_tag += 1;
+ }
+
+ cmark_strbuf_puts(html, "<pre");
+ S_render_sourcepos(node, html, options);
+ cmark_strbuf_puts(html, "><code class=\"");
+ if (strncmp((char *)node->as.code.info, "language-", 9) != 0) {
+ cmark_strbuf_puts(html, "language-");
+ }
+ escape_html(html, node->as.code.info, first_tag);
+ cmark_strbuf_puts(html, "\">");
+ }
+
+ escape_html(html, node->data, node->len);
+ cmark_strbuf_puts(html, "</code></pre>\n");
+ break;
+
+ case CMARK_NODE_HTML_BLOCK:
+ cr(html);
+ if (!(options & CMARK_OPT_UNSAFE)) {
+ cmark_strbuf_puts(html, "<!-- raw HTML omitted -->");
+ } else {
+ cmark_strbuf_put(html, node->data, node->len);
+ }
+ cr(html);
+ break;
+
+ case CMARK_NODE_CUSTOM_BLOCK: {
+ unsigned char *block = entering ? node->as.custom.on_enter :
+ node->as.custom.on_exit;
+ cr(html);
+ if (block) {
+ cmark_strbuf_puts(html, (char *)block);
+ }
+ cr(html);
+ break;
+ }
+
+ case CMARK_NODE_THEMATIC_BREAK:
+ cr(html);
+ cmark_strbuf_puts(html, "<hr");
+ S_render_sourcepos(node, html, options);
+ cmark_strbuf_puts(html, " />\n");
+ break;
+
+ case CMARK_NODE_PARAGRAPH:
+ parent = cmark_node_parent(node);
+ grandparent = cmark_node_parent(parent);
+ if (grandparent != NULL && grandparent->type == CMARK_NODE_LIST) {
+ tight = grandparent->as.list.tight;
+ } else {
+ tight = false;
+ }
+ if (!tight) {
+ if (entering) {
+ cr(html);
+ cmark_strbuf_puts(html, "<p");
+ S_render_sourcepos(node, html, options);
+ cmark_strbuf_putc(html, '>');
+ } else {
+ cmark_strbuf_puts(html, "</p>\n");
+ }
+ }
+ break;
+
+ case CMARK_NODE_TEXT:
+ escape_html(html, node->data, node->len);
+ break;
+
+ case CMARK_NODE_LINEBREAK:
+ cmark_strbuf_puts(html, "<br />\n");
+ break;
+
+ case CMARK_NODE_SOFTBREAK:
+ if (options & CMARK_OPT_HARDBREAKS) {
+ cmark_strbuf_puts(html, "<br />\n");
+ } else if (options & CMARK_OPT_NOBREAKS) {
+ cmark_strbuf_putc(html, ' ');
+ } else {
+ cmark_strbuf_putc(html, '\n');
+ }
+ break;
+
+ case CMARK_NODE_CODE:
+ cmark_strbuf_puts(html, "<code>");
+ escape_html(html, node->data, node->len);
+ cmark_strbuf_puts(html, "</code>");
+ break;
+
+ case CMARK_NODE_HTML_INLINE:
+ if (!(options & CMARK_OPT_UNSAFE)) {
+ cmark_strbuf_puts(html, "<!-- raw HTML omitted -->");
+ } else {
+ cmark_strbuf_put(html, node->data, node->len);
+ }
+ break;
+
+ case CMARK_NODE_CUSTOM_INLINE: {
+ unsigned char *block = entering ? node->as.custom.on_enter :
+ node->as.custom.on_exit;
+ if (block) {
+ cmark_strbuf_puts(html, (char *)block);
+ }
+ break;
+ }
+
+ case CMARK_NODE_STRONG:
+ if (entering) {
+ cmark_strbuf_puts(html, "<strong>");
+ } else {
+ cmark_strbuf_puts(html, "</strong>");
+ }
+ break;
+
+ case CMARK_NODE_EMPH:
+ if (entering) {
+ cmark_strbuf_puts(html, "<em>");
+ } else {
+ cmark_strbuf_puts(html, "</em>");
+ }
+ break;
+
+ case CMARK_NODE_LINK:
+ if (entering) {
+ cmark_strbuf_puts(html, "<a href=\"");
+ if (node->as.link.url && ((options & CMARK_OPT_UNSAFE) ||
+ !(_scan_dangerous_url(node->as.link.url)))) {
+ houdini_escape_href(html, node->as.link.url,
+ (bufsize_t)strlen((char *)node->as.link.url));
+ }
+ if (node->as.link.title) {
+ cmark_strbuf_puts(html, "\" title=\"");
+ escape_html(html, node->as.link.title,
+ (bufsize_t)strlen((char *)node->as.link.title));
+ }
+ cmark_strbuf_puts(html, "\">");
+ } else {
+ cmark_strbuf_puts(html, "</a>");
+ }
+ break;
+
+ case CMARK_NODE_IMAGE:
+ if (entering) {
+ cmark_strbuf_puts(html, "<img src=\"");
+ if (node->as.link.url && ((options & CMARK_OPT_UNSAFE) ||
+ !(_scan_dangerous_url(node->as.link.url)))) {
+ houdini_escape_href(html, node->as.link.url,
+ (bufsize_t)strlen((char *)node->as.link.url));
+ }
+ cmark_strbuf_puts(html, "\" alt=\"");
+ state->plain = node;
+ } else {
+ if (node->as.link.title) {
+ cmark_strbuf_puts(html, "\" title=\"");
+ escape_html(html, node->as.link.title,
+ (bufsize_t)strlen((char *)node->as.link.title));
+ }
+
+ cmark_strbuf_puts(html, "\" />");
+ }
+ break;
+
+ default:
+ assert(false);
+ break;
+ }
+
+ // cmark_strbuf_putc(html, 'x');
+ return 1;
+}
+
+char *cmark_render_html(cmark_node *root, int options) {
+ char *result;
+ cmark_strbuf html = CMARK_BUF_INIT(root->mem);
+ cmark_event_type ev_type;
+ cmark_node *cur;
+ struct render_state state = {&html, NULL};
+ cmark_iter *iter = cmark_iter_new(root);
+
+ while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
+ cur = cmark_iter_get_node(iter);
+ S_render_node(cur, ev_type, &state, options);
+ }
+ result = (char *)cmark_strbuf_detach(&html);
+
+ cmark_iter_free(iter);
+ return result;
+}
diff --git a/cmark/src/inlines.c b/cmark/src/inlines.c
new file mode 100644
index 0000000000..ab82ca74e2
--- /dev/null
+++ b/cmark/src/inlines.c
@@ -0,0 +1,1503 @@
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "cmark_ctype.h"
+#include "node.h"
+#include "parser.h"
+#include "references.h"
+#include "cmark.h"
+#include "houdini.h"
+#include "utf8.h"
+#include "scanners.h"
+#include "inlines.h"
+
+static const char *EMDASH = "\xE2\x80\x94";
+static const char *ENDASH = "\xE2\x80\x93";
+static const char *ELLIPSES = "\xE2\x80\xA6";
+static const char *LEFTDOUBLEQUOTE = "\xE2\x80\x9C";
+static const char *RIGHTDOUBLEQUOTE = "\xE2\x80\x9D";
+static const char *LEFTSINGLEQUOTE = "\xE2\x80\x98";
+static const char *RIGHTSINGLEQUOTE = "\xE2\x80\x99";
+
+// Macros for creating various kinds of simple.
+#define make_linebreak(mem) make_simple(mem, CMARK_NODE_LINEBREAK)
+#define make_softbreak(mem) make_simple(mem, CMARK_NODE_SOFTBREAK)
+#define make_emph(mem) make_simple(mem, CMARK_NODE_EMPH)
+#define make_strong(mem) make_simple(mem, CMARK_NODE_STRONG)
+
+#define MAXBACKTICKS 1000
+
+typedef struct delimiter {
+ struct delimiter *previous;
+ struct delimiter *next;
+ cmark_node *inl_text;
+ bufsize_t position;
+ bufsize_t length;
+ unsigned char delim_char;
+ bool can_open;
+ bool can_close;
+} delimiter;
+
+typedef struct bracket {
+ struct bracket *previous;
+ cmark_node *inl_text;
+ bufsize_t position;
+ bool image;
+ bool active;
+ bool bracket_after;
+} bracket;
+
+#define FLAG_SKIP_HTML_CDATA (1u << 0)
+#define FLAG_SKIP_HTML_DECLARATION (1u << 1)
+#define FLAG_SKIP_HTML_PI (1u << 2)
+#define FLAG_SKIP_HTML_COMMENT (1u << 3)
+
+typedef struct {
+ cmark_mem *mem;
+ cmark_chunk input;
+ unsigned flags;
+ int line;
+ bufsize_t pos;
+ int block_offset;
+ int column_offset;
+ cmark_reference_map *refmap;
+ delimiter *last_delim;
+ bracket *last_bracket;
+ bufsize_t backticks[MAXBACKTICKS + 1];
+ bool scanned_for_backticks;
+ bool no_link_openers;
+} subject;
+
+static inline bool S_is_line_end_char(char c) {
+ return (c == '\n' || c == '\r');
+}
+
+static delimiter *S_insert_emph(subject *subj, delimiter *opener,
+ delimiter *closer);
+
+static int parse_inline(subject *subj, cmark_node *parent, int options);
+
+static void subject_from_buf(cmark_mem *mem, int line_number, int block_offset, subject *e,
+ cmark_chunk *chunk, cmark_reference_map *refmap);
+static bufsize_t subject_find_special_char(subject *subj, int options);
+
+// Create an inline with a literal string value.
+static inline cmark_node *make_literal(subject *subj, cmark_node_type t,
+ int start_column, int end_column) {
+ cmark_node *e = (cmark_node *)subj->mem->calloc(1, sizeof(*e));
+ e->mem = subj->mem;
+ e->type = (uint16_t)t;
+ e->start_line = e->end_line = subj->line;
+ // columns are 1 based.
+ e->start_column = start_column + 1 + subj->column_offset + subj->block_offset;
+ e->end_column = end_column + 1 + subj->column_offset + subj->block_offset;
+ return e;
+}
+
+// Create an inline with no value.
+static inline cmark_node *make_simple(cmark_mem *mem, cmark_node_type t) {
+ cmark_node *e = (cmark_node *)mem->calloc(1, sizeof(*e));
+ e->mem = mem;
+ e->type = t;
+ return e;
+}
+
+static cmark_node *make_str(subject *subj, int sc, int ec, cmark_chunk s) {
+ cmark_node *e = make_literal(subj, CMARK_NODE_TEXT, sc, ec);
+ e->data = (unsigned char *)subj->mem->realloc(NULL, s.len + 1);
+ if (s.data != NULL) {
+ memcpy(e->data, s.data, s.len);
+ }
+ e->data[s.len] = 0;
+ e->len = s.len;
+ return e;
+}
+
+static cmark_node *make_str_from_buf(subject *subj, int sc, int ec,
+ cmark_strbuf *buf) {
+ cmark_node *e = make_literal(subj, CMARK_NODE_TEXT, sc, ec);
+ e->len = buf->size;
+ e->data = cmark_strbuf_detach(buf);
+ return e;
+}
+
+// Like make_str, but parses entities.
+static cmark_node *make_str_with_entities(subject *subj,
+ int start_column, int end_column,
+ cmark_chunk *content) {
+ cmark_strbuf unescaped = CMARK_BUF_INIT(subj->mem);
+
+ if (houdini_unescape_html(&unescaped, content->data, content->len)) {
+ return make_str_from_buf(subj, start_column, end_column, &unescaped);
+ } else {
+ return make_str(subj, start_column, end_column, *content);
+ }
+}
+
+// Like cmark_node_append_child but without costly sanity checks.
+// Assumes that child was newly created.
+static void append_child(cmark_node *node, cmark_node *child) {
+ cmark_node *old_last_child = node->last_child;
+
+ child->next = NULL;
+ child->prev = old_last_child;
+ child->parent = node;
+ node->last_child = child;
+
+ if (old_last_child) {
+ old_last_child->next = child;
+ } else {
+ // Also set first_child if node previously had no children.
+ node->first_child = child;
+ }
+}
+
+// Duplicate a chunk by creating a copy of the buffer not by reusing the
+// buffer like cmark_chunk_dup does.
+static unsigned char *cmark_strdup(cmark_mem *mem, unsigned char *src) {
+ if (src == NULL) {
+ return NULL;
+ }
+ size_t len = strlen((char *)src);
+ unsigned char *data = (unsigned char *)mem->realloc(NULL, len + 1);
+ memcpy(data, src, len + 1);
+ return data;
+}
+
+static unsigned char *cmark_clean_autolink(cmark_mem *mem, cmark_chunk *url,
+ int is_email) {
+ cmark_strbuf buf = CMARK_BUF_INIT(mem);
+
+ cmark_chunk_trim(url);
+
+ if (is_email)
+ cmark_strbuf_puts(&buf, "mailto:");
+
+ houdini_unescape_html_f(&buf, url->data, url->len);
+ return cmark_strbuf_detach(&buf);
+}
+
+static inline cmark_node *make_autolink(subject *subj, int start_column,
+ int end_column, cmark_chunk url,
+ int is_email) {
+ cmark_node *link = make_simple(subj->mem, CMARK_NODE_LINK);
+ link->as.link.url = cmark_clean_autolink(subj->mem, &url, is_email);
+ link->as.link.title = NULL;
+ link->start_line = link->end_line = subj->line;
+ link->start_column = start_column + 1;
+ link->end_column = end_column + 1;
+ append_child(link, make_str_with_entities(subj, start_column + 1, end_column - 1, &url));
+ return link;
+}
+
+static void subject_from_buf(cmark_mem *mem, int line_number, int block_offset, subject *e,
+ cmark_chunk *chunk, cmark_reference_map *refmap) {
+ int i;
+ e->mem = mem;
+ e->input = *chunk;
+ e->flags = 0;
+ e->line = line_number;
+ e->pos = 0;
+ e->block_offset = block_offset;
+ e->column_offset = 0;
+ e->refmap = refmap;
+ e->last_delim = NULL;
+ e->last_bracket = NULL;
+ for (i = 0; i <= MAXBACKTICKS; i++) {
+ e->backticks[i] = 0;
+ }
+ e->scanned_for_backticks = false;
+ e->no_link_openers = true;
+}
+
+static inline int isbacktick(int c) { return (c == '`'); }
+
+static inline unsigned char peek_char(subject *subj) {
+ // NULL bytes should have been stripped out by now. If they're
+ // present, it's a programming error:
+ assert(!(subj->pos < subj->input.len && subj->input.data[subj->pos] == 0));
+ return (subj->pos < subj->input.len) ? subj->input.data[subj->pos] : 0;
+}
+
+static inline unsigned char peek_at(subject *subj, bufsize_t pos) {
+ return subj->input.data[pos];
+}
+
+// Return true if there are more characters in the subject.
+static inline int is_eof(subject *subj) {
+ return (subj->pos >= subj->input.len);
+}
+
+// Advance the subject. Doesn't check for eof.
+#define advance(subj) (subj)->pos += 1
+
+static inline bool skip_spaces(subject *subj) {
+ bool skipped = false;
+ while (peek_char(subj) == ' ' || peek_char(subj) == '\t') {
+ advance(subj);
+ skipped = true;
+ }
+ return skipped;
+}
+
+static inline bool skip_line_end(subject *subj) {
+ bool seen_line_end_char = false;
+ if (peek_char(subj) == '\r') {
+ advance(subj);
+ seen_line_end_char = true;
+ }
+ if (peek_char(subj) == '\n') {
+ advance(subj);
+ seen_line_end_char = true;
+ }
+ return seen_line_end_char || is_eof(subj);
+}
+
+// Take characters while a predicate holds, and return a string.
+static inline cmark_chunk take_while(subject *subj, int (*f)(int)) {
+ unsigned char c;
+ bufsize_t startpos = subj->pos;
+ bufsize_t len = 0;
+
+ while ((c = peek_char(subj)) && (*f)(c)) {
+ advance(subj);
+ len++;
+ }
+
+ return cmark_chunk_dup(&subj->input, startpos, len);
+}
+
+// Return the number of newlines in a given span of text in a subject. If
+// the number is greater than zero, also return the number of characters
+// between the last newline and the end of the span in `since_newline`.
+static int count_newlines(subject *subj, bufsize_t from, bufsize_t len, int *since_newline) {
+ int nls = 0;
+ int since_nl = 0;
+
+ while (len--) {
+ if (subj->input.data[from++] == '\n') {
+ ++nls;
+ since_nl = 0;
+ } else {
+ ++since_nl;
+ }
+ }
+
+ if (!nls)
+ return 0;
+
+ *since_newline = since_nl;
+ return nls;
+}
+
+// Adjust `node`'s `end_line`, `end_column`, and `subj`'s `line` and
+// `column_offset` according to the number of newlines in a just-matched span
+// of text in `subj`.
+static void adjust_subj_node_newlines(subject *subj, cmark_node *node, int matchlen, int extra, int options) {
+ if (!(options & CMARK_OPT_SOURCEPOS)) {
+ return;
+ }
+
+ int since_newline;
+ int newlines = count_newlines(subj, subj->pos - matchlen - extra, matchlen, &since_newline);
+ if (newlines) {
+ subj->line += newlines;
+ node->end_line += newlines;
+ node->end_column = since_newline;
+ subj->column_offset = -subj->pos + since_newline + extra;
+ }
+}
+
+// Try to process a backtick code span that began with a
+// span of ticks of length openticklength length (already
+// parsed). Return 0 if you don't find matching closing
+// backticks, otherwise return the position in the subject
+// after the closing backticks.
+static bufsize_t scan_to_closing_backticks(subject *subj,
+ bufsize_t openticklength) {
+
+ bool found = false;
+ if (openticklength > MAXBACKTICKS) {
+ // we limit backtick string length because of the array subj->backticks:
+ return 0;
+ }
+ if (subj->scanned_for_backticks &&
+ subj->backticks[openticklength] <= subj->pos) {
+ // return if we already know there's no closer
+ return 0;
+ }
+ while (!found) {
+ // read non backticks
+ unsigned char c;
+ while ((c = peek_char(subj)) && c != '`') {
+ advance(subj);
+ }
+ if (is_eof(subj)) {
+ break;
+ }
+ bufsize_t numticks = 0;
+ while (peek_char(subj) == '`') {
+ advance(subj);
+ numticks++;
+ }
+ // store position of ender
+ if (numticks <= MAXBACKTICKS) {
+ subj->backticks[numticks] = subj->pos - numticks;
+ }
+ if (numticks == openticklength) {
+ return (subj->pos);
+ }
+ }
+ // got through whole input without finding closer
+ subj->scanned_for_backticks = true;
+ return 0;
+}
+
+// Destructively modify string, converting newlines to
+// spaces, then removing a single leading + trailing space,
+// unless the code span consists entirely of space characters.
+static void S_normalize_code(cmark_strbuf *s) {
+ bufsize_t r, w;
+ bool contains_nonspace = false;
+
+ for (r = 0, w = 0; r < s->size; ++r) {
+ switch (s->ptr[r]) {
+ case '\r':
+ if (s->ptr[r + 1] != '\n') {
+ s->ptr[w++] = ' ';
+ }
+ break;
+ case '\n':
+ s->ptr[w++] = ' ';
+ break;
+ default:
+ s->ptr[w++] = s->ptr[r];
+ }
+ if (s->ptr[r] != ' ') {
+ contains_nonspace = true;
+ }
+ }
+
+ // begins and ends with space?
+ if (contains_nonspace &&
+ s->ptr[0] == ' ' && s->ptr[w - 1] == ' ') {
+ cmark_strbuf_drop(s, 1);
+ cmark_strbuf_truncate(s, w - 2);
+ } else {
+ cmark_strbuf_truncate(s, w);
+ }
+
+}
+
+
+// Parse backtick code section or raw backticks, return an inline.
+// Assumes that the subject has a backtick at the current position.
+static cmark_node *handle_backticks(subject *subj, int options) {
+ bufsize_t initpos = subj->pos;
+ cmark_chunk openticks = take_while(subj, isbacktick);
+ bufsize_t startpos = subj->pos;
+ bufsize_t endpos = scan_to_closing_backticks(subj, openticks.len);
+
+ if (endpos == 0) { // not found
+ subj->pos = startpos; // rewind
+ return make_str(subj, initpos, initpos + openticks.len - 1, openticks);
+ } else {
+ cmark_strbuf buf = CMARK_BUF_INIT(subj->mem);
+
+ cmark_strbuf_set(&buf, subj->input.data + startpos,
+ endpos - startpos - openticks.len);
+ S_normalize_code(&buf);
+
+ cmark_node *node = make_literal(subj, CMARK_NODE_CODE, startpos,
+ endpos - openticks.len - 1);
+ node->len = buf.size;
+ node->data = cmark_strbuf_detach(&buf);
+ adjust_subj_node_newlines(subj, node, endpos - startpos, openticks.len, options);
+ return node;
+ }
+}
+
+
+// Scan ***, **, or * and return number scanned, or 0.
+// Advances position.
+static int scan_delims(subject *subj, unsigned char c, bool *can_open,
+ bool *can_close) {
+ int numdelims = 0;
+ bufsize_t before_char_pos;
+ int32_t after_char = 0;
+ int32_t before_char = 0;
+ int len;
+ bool left_flanking, right_flanking;
+
+ if (subj->pos == 0) {
+ before_char = 10;
+ } else {
+ before_char_pos = subj->pos - 1;
+ // walk back to the beginning of the UTF_8 sequence:
+ while (peek_at(subj, before_char_pos) >> 6 == 2 && before_char_pos > 0) {
+ before_char_pos -= 1;
+ }
+ len = cmark_utf8proc_iterate(subj->input.data + before_char_pos,
+ subj->pos - before_char_pos, &before_char);
+ if (len == -1) {
+ before_char = 10;
+ }
+ }
+
+ if (c == '\'' || c == '"') {
+ numdelims++;
+ advance(subj); // limit to 1 delim for quotes
+ } else {
+ while (peek_char(subj) == c) {
+ numdelims++;
+ advance(subj);
+ }
+ }
+
+ len = cmark_utf8proc_iterate(subj->input.data + subj->pos,
+ subj->input.len - subj->pos, &after_char);
+ if (len == -1) {
+ after_char = 10;
+ }
+ left_flanking = numdelims > 0 && !cmark_utf8proc_is_space(after_char) &&
+ (!cmark_utf8proc_is_punctuation_or_symbol(after_char) ||
+ cmark_utf8proc_is_space(before_char) ||
+ cmark_utf8proc_is_punctuation_or_symbol(before_char));
+ right_flanking = numdelims > 0 && !cmark_utf8proc_is_space(before_char) &&
+ (!cmark_utf8proc_is_punctuation_or_symbol(before_char) ||
+ cmark_utf8proc_is_space(after_char) ||
+ cmark_utf8proc_is_punctuation_or_symbol(after_char));
+ if (c == '_') {
+ *can_open = left_flanking &&
+ (!right_flanking ||
+ cmark_utf8proc_is_punctuation_or_symbol(before_char));
+ *can_close = right_flanking &&
+ (!left_flanking ||
+ cmark_utf8proc_is_punctuation_or_symbol(after_char));
+ } else if (c == '\'' || c == '"') {
+ *can_open = left_flanking &&
+ (!right_flanking || before_char == '(' || before_char == '[') &&
+ before_char != ']' && before_char != ')';
+ *can_close = right_flanking;
+ } else {
+ *can_open = left_flanking;
+ *can_close = right_flanking;
+ }
+ return numdelims;
+}
+
+/*
+static void print_delimiters(subject *subj)
+{
+ delimiter *delim;
+ delim = subj->last_delim;
+ while (delim != NULL) {
+ printf("Item at stack pos %p: %d %d %d next(%p) prev(%p)\n",
+ (void*)delim, delim->delim_char,
+ delim->can_open, delim->can_close,
+ (void*)delim->next, (void*)delim->previous);
+ delim = delim->previous;
+ }
+}
+*/
+
+static void remove_delimiter(subject *subj, delimiter *delim) {
+ if (delim == NULL)
+ return;
+ if (delim->next == NULL) {
+ // end of list:
+ assert(delim == subj->last_delim);
+ subj->last_delim = delim->previous;
+ } else {
+ delim->next->previous = delim->previous;
+ }
+ if (delim->previous != NULL) {
+ delim->previous->next = delim->next;
+ }
+ subj->mem->free(delim);
+}
+
+static void pop_bracket(subject *subj) {
+ bracket *b;
+ if (subj->last_bracket == NULL)
+ return;
+ b = subj->last_bracket;
+ subj->last_bracket = subj->last_bracket->previous;
+ subj->mem->free(b);
+}
+
+static void push_delimiter(subject *subj, unsigned char c, bool can_open,
+ bool can_close, cmark_node *inl_text) {
+ delimiter *delim = (delimiter *)subj->mem->calloc(1, sizeof(delimiter));
+ delim->delim_char = c;
+ delim->can_open = can_open;
+ delim->can_close = can_close;
+ delim->inl_text = inl_text;
+ delim->position = subj->pos;
+ delim->length = inl_text->len;
+ delim->previous = subj->last_delim;
+ delim->next = NULL;
+ if (delim->previous != NULL) {
+ delim->previous->next = delim;
+ }
+ subj->last_delim = delim;
+}
+
+static void push_bracket(subject *subj, bool image, cmark_node *inl_text) {
+ bracket *b = (bracket *)subj->mem->calloc(1, sizeof(bracket));
+ if (subj->last_bracket != NULL) {
+ subj->last_bracket->bracket_after = true;
+ }
+ b->image = image;
+ b->active = true;
+ b->inl_text = inl_text;
+ b->previous = subj->last_bracket;
+ b->position = subj->pos;
+ b->bracket_after = false;
+ subj->last_bracket = b;
+ if (!image) {
+ subj->no_link_openers = false;
+ }
+}
+
+// Assumes the subject has a c at the current position.
+static cmark_node *handle_delim(subject *subj, unsigned char c, bool smart) {
+ bufsize_t numdelims;
+ cmark_node *inl_text;
+ bool can_open, can_close;
+ cmark_chunk contents;
+
+ numdelims = scan_delims(subj, c, &can_open, &can_close);
+
+ if (c == '\'' && smart) {
+ contents = cmark_chunk_literal(RIGHTSINGLEQUOTE);
+ } else if (c == '"' && smart) {
+ contents =
+ cmark_chunk_literal(can_close ? RIGHTDOUBLEQUOTE : LEFTDOUBLEQUOTE);
+ } else {
+ contents = cmark_chunk_dup(&subj->input, subj->pos - numdelims, numdelims);
+ }
+
+ inl_text = make_str(subj, subj->pos - numdelims, subj->pos - 1, contents);
+
+ if ((can_open || can_close) && (!(c == '\'' || c == '"') || smart)) {
+ push_delimiter(subj, c, can_open, can_close, inl_text);
+ }
+
+ return inl_text;
+}
+
+// Assumes we have a hyphen at the current position.
+static cmark_node *handle_hyphen(subject *subj, bool smart) {
+ int startpos = subj->pos;
+
+ advance(subj);
+
+ if (!smart || peek_char(subj) != '-') {
+ return make_str(subj, subj->pos - 1, subj->pos - 1, cmark_chunk_literal("-"));
+ }
+
+ while (smart && peek_char(subj) == '-') {
+ advance(subj);
+ }
+
+ int numhyphens = subj->pos - startpos;
+ int en_count = 0;
+ int em_count = 0;
+ int i;
+ cmark_strbuf buf = CMARK_BUF_INIT(subj->mem);
+
+ if (numhyphens % 3 == 0) { // if divisible by 3, use all em dashes
+ em_count = numhyphens / 3;
+ } else if (numhyphens % 2 == 0) { // if divisible by 2, use all en dashes
+ en_count = numhyphens / 2;
+ } else if (numhyphens % 3 == 2) { // use one en dash at end
+ en_count = 1;
+ em_count = (numhyphens - 2) / 3;
+ } else { // use two en dashes at the end
+ en_count = 2;
+ em_count = (numhyphens - 4) / 3;
+ }
+
+ for (i = em_count; i > 0; i--) {
+ cmark_strbuf_puts(&buf, EMDASH);
+ }
+
+ for (i = en_count; i > 0; i--) {
+ cmark_strbuf_puts(&buf, ENDASH);
+ }
+
+ return make_str_from_buf(subj, startpos, subj->pos - 1, &buf);
+}
+
+// Assumes we have a period at the current position.
+static cmark_node *handle_period(subject *subj, bool smart) {
+ advance(subj);
+ if (smart && peek_char(subj) == '.') {
+ advance(subj);
+ if (peek_char(subj) == '.') {
+ advance(subj);
+ return make_str(subj, subj->pos - 3, subj->pos - 1, cmark_chunk_literal(ELLIPSES));
+ } else {
+ return make_str(subj, subj->pos - 2, subj->pos - 1, cmark_chunk_literal(".."));
+ }
+ } else {
+ return make_str(subj, subj->pos - 1, subj->pos - 1, cmark_chunk_literal("."));
+ }
+}
+
+static void process_emphasis(subject *subj, bufsize_t stack_bottom) {
+ delimiter *candidate;
+ delimiter *closer = NULL;
+ delimiter *opener;
+ delimiter *old_closer;
+ bool opener_found;
+ int openers_bottom_index = 0;
+ bufsize_t openers_bottom[15] = {stack_bottom, stack_bottom, stack_bottom,
+ stack_bottom, stack_bottom, stack_bottom,
+ stack_bottom, stack_bottom, stack_bottom,
+ stack_bottom, stack_bottom, stack_bottom,
+ stack_bottom, stack_bottom, stack_bottom};
+
+ // move back to first relevant delim.
+ candidate = subj->last_delim;
+ while (candidate != NULL && candidate->position >= stack_bottom) {
+ closer = candidate;
+ candidate = candidate->previous;
+ }
+
+ // now move forward, looking for closers, and handling each
+ while (closer != NULL) {
+ if (closer->can_close) {
+ switch (closer->delim_char) {
+ case '"':
+ openers_bottom_index = 0;
+ break;
+ case '\'':
+ openers_bottom_index = 1;
+ break;
+ case '_':
+ openers_bottom_index = 2 +
+ (closer->can_open ? 3 : 0) + (closer->length % 3);
+ break;
+ case '*':
+ openers_bottom_index = 8 +
+ (closer->can_open ? 3 : 0) + (closer->length % 3);
+ break;
+ default:
+ assert(false);
+ }
+
+ // Now look backwards for first matching opener:
+ opener = closer->previous;
+ opener_found = false;
+ while (opener != NULL &&
+ opener->position >= openers_bottom[openers_bottom_index]) {
+ if (opener->can_open && opener->delim_char == closer->delim_char) {
+ // interior closer of size 2 can't match opener of size 1
+ // or of size 1 can't match 2
+ if (!(closer->can_open || opener->can_close) ||
+ closer->length % 3 == 0 ||
+ (opener->length + closer->length) % 3 != 0) {
+ opener_found = true;
+ break;
+ }
+ }
+ opener = opener->previous;
+ }
+ old_closer = closer;
+ if (closer->delim_char == '*' || closer->delim_char == '_') {
+ if (opener_found) {
+ closer = S_insert_emph(subj, opener, closer);
+ } else {
+ closer = closer->next;
+ }
+ } else if (closer->delim_char == '\'' || closer->delim_char == '"') {
+ if (closer->delim_char == '\'') {
+ cmark_node_set_literal(closer->inl_text, RIGHTSINGLEQUOTE);
+ } else {
+ cmark_node_set_literal(closer->inl_text, RIGHTDOUBLEQUOTE);
+ }
+ closer = closer->next;
+ if (opener_found) {
+ if (old_closer->delim_char == '\'') {
+ cmark_node_set_literal(opener->inl_text, LEFTSINGLEQUOTE);
+ } else {
+ cmark_node_set_literal(opener->inl_text, LEFTDOUBLEQUOTE);
+ }
+ remove_delimiter(subj, opener);
+ remove_delimiter(subj, old_closer);
+ }
+ }
+ if (!opener_found) {
+ // set lower bound for future searches for openers
+ openers_bottom[openers_bottom_index] = old_closer->position;
+ if (!old_closer->can_open) {
+ // we can remove a closer that can't be an
+ // opener, once we've seen there's no
+ // matching opener:
+ remove_delimiter(subj, old_closer);
+ }
+ }
+ } else {
+ closer = closer->next;
+ }
+ }
+ // free all delimiters in list until stack_bottom:
+ while (subj->last_delim != NULL &&
+ subj->last_delim->position >= stack_bottom) {
+ remove_delimiter(subj, subj->last_delim);
+ }
+}
+
+static delimiter *S_insert_emph(subject *subj, delimiter *opener,
+ delimiter *closer) {
+ delimiter *delim, *tmp_delim;
+ bufsize_t use_delims;
+ cmark_node *opener_inl = opener->inl_text;
+ cmark_node *closer_inl = closer->inl_text;
+ bufsize_t opener_num_chars = opener_inl->len;
+ bufsize_t closer_num_chars = closer_inl->len;
+ cmark_node *tmp, *tmpnext, *emph;
+
+ // calculate the actual number of characters used from this closer
+ use_delims = (closer_num_chars >= 2 && opener_num_chars >= 2) ? 2 : 1;
+
+ // remove used characters from associated inlines.
+ opener_num_chars -= use_delims;
+ closer_num_chars -= use_delims;
+ opener_inl->len = opener_num_chars;
+ opener_inl->data[opener_num_chars] = 0;
+ opener_inl->end_column -= use_delims;
+ closer_inl->len = closer_num_chars;
+ closer_inl->data[closer_num_chars] = 0;
+ closer_inl->start_column += use_delims;
+
+ // free delimiters between opener and closer
+ delim = closer->previous;
+ while (delim != NULL && delim != opener) {
+ tmp_delim = delim->previous;
+ remove_delimiter(subj, delim);
+ delim = tmp_delim;
+ }
+
+ // create new emph or strong, and splice it in to our inlines
+ // between the opener and closer
+ emph = use_delims == 1 ? make_emph(subj->mem) : make_strong(subj->mem);
+
+ tmp = opener_inl->next;
+ if (tmp && tmp != closer_inl) {
+ emph->first_child = tmp;
+ tmp->prev = NULL;
+
+ while (tmp && tmp != closer_inl) {
+ tmpnext = tmp->next;
+ tmp->parent = emph;
+ if (tmpnext == closer_inl) {
+ emph->last_child = tmp;
+ tmp->next = NULL;
+ }
+ tmp = tmpnext;
+ }
+ }
+
+ opener_inl->next = emph;
+ closer_inl->prev = emph;
+ emph->prev = opener_inl;
+ emph->next = closer_inl;
+ emph->parent = opener_inl->parent;
+
+ emph->start_line = opener_inl->start_line;
+ emph->end_line = closer_inl->end_line;
+ emph->start_column = opener_inl->start_column + opener_inl->len;
+ emph->end_column = closer_inl->end_column - closer_inl->len;
+
+ // if opener has 0 characters, remove it and its associated inline
+ if (opener_num_chars == 0) {
+ cmark_node_free(opener_inl);
+ remove_delimiter(subj, opener);
+ }
+
+ // if closer has 0 characters, remove it and its associated inline
+ if (closer_num_chars == 0) {
+ // remove empty closer inline
+ cmark_node_free(closer_inl);
+ // remove closer from list
+ tmp_delim = closer->next;
+ remove_delimiter(subj, closer);
+ closer = tmp_delim;
+ }
+
+ return closer;
+}
+
+// Parse backslash-escape or just a backslash, returning an inline.
+static cmark_node *handle_backslash(subject *subj) {
+ advance(subj);
+ unsigned char nextchar = peek_char(subj);
+ if (cmark_ispunct(
+ nextchar)) { // only ascii symbols and newline can be escaped
+ advance(subj);
+ return make_str(subj, subj->pos - 2, subj->pos - 1, cmark_chunk_dup(&subj->input, subj->pos - 1, 1));
+ } else if (!is_eof(subj) && skip_line_end(subj)) {
+ return make_linebreak(subj->mem);
+ } else {
+ return make_str(subj, subj->pos - 1, subj->pos - 1, cmark_chunk_literal("\\"));
+ }
+}
+
+// Parse an entity or a regular "&" string.
+// Assumes the subject has an '&' character at the current position.
+static cmark_node *handle_entity(subject *subj) {
+ cmark_strbuf ent = CMARK_BUF_INIT(subj->mem);
+ bufsize_t len;
+
+ advance(subj);
+
+ len = houdini_unescape_ent(&ent, subj->input.data + subj->pos,
+ subj->input.len - subj->pos);
+
+ if (len <= 0)
+ return make_str(subj, subj->pos - 1, subj->pos - 1, cmark_chunk_literal("&"));
+
+ subj->pos += len;
+ return make_str_from_buf(subj, subj->pos - 1 - len, subj->pos - 1, &ent);
+}
+
+// Clean a URL: remove surrounding whitespace, and remove \ that escape
+// punctuation.
+unsigned char *cmark_clean_url(cmark_mem *mem, cmark_chunk *url) {
+ cmark_strbuf buf = CMARK_BUF_INIT(mem);
+
+ cmark_chunk_trim(url);
+
+ houdini_unescape_html_f(&buf, url->data, url->len);
+
+ cmark_strbuf_unescape(&buf);
+ return cmark_strbuf_detach(&buf);
+}
+
+unsigned char *cmark_clean_title(cmark_mem *mem, cmark_chunk *title) {
+ cmark_strbuf buf = CMARK_BUF_INIT(mem);
+ unsigned char first, last;
+
+ if (title->len == 0) {
+ return NULL;
+ }
+
+ first = title->data[0];
+ last = title->data[title->len - 1];
+
+ // remove surrounding quotes if any:
+ if ((first == '\'' && last == '\'') || (first == '(' && last == ')') ||
+ (first == '"' && last == '"')) {
+ houdini_unescape_html_f(&buf, title->data + 1, title->len - 2);
+ } else {
+ houdini_unescape_html_f(&buf, title->data, title->len);
+ }
+
+ cmark_strbuf_unescape(&buf);
+ return cmark_strbuf_detach(&buf);
+}
+
+// Parse an autolink or HTML tag.
+// Assumes the subject has a '<' character at the current position.
+static cmark_node *handle_pointy_brace(subject *subj, int options) {
+ bufsize_t matchlen = 0;
+ cmark_chunk contents;
+
+ advance(subj); // advance past first <
+
+ // first try to match a URL autolink
+ matchlen = scan_autolink_uri(&subj->input, subj->pos);
+ if (matchlen > 0) {
+ contents = cmark_chunk_dup(&subj->input, subj->pos, matchlen - 1);
+ subj->pos += matchlen;
+
+ return make_autolink(subj, subj->pos - 1 - matchlen, subj->pos - 1, contents, 0);
+ }
+
+ // next try to match an email autolink
+ matchlen = scan_autolink_email(&subj->input, subj->pos);
+ if (matchlen > 0) {
+ contents = cmark_chunk_dup(&subj->input, subj->pos, matchlen - 1);
+ subj->pos += matchlen;
+
+ return make_autolink(subj, subj->pos - 1 - matchlen, subj->pos - 1, contents, 1);
+ }
+
+ // finally, try to match an html tag
+ if (subj->pos + 2 <= subj->input.len) {
+ int c = subj->input.data[subj->pos];
+ if (c == '!' && (subj->flags & FLAG_SKIP_HTML_COMMENT) == 0) {
+ c = subj->input.data[subj->pos+1];
+ if (c == '-' && subj->input.data[subj->pos+2] == '-') {
+ if (subj->input.data[subj->pos+3] == '>') {
+ matchlen = 4;
+ } else if (subj->input.data[subj->pos+3] == '-' &&
+ subj->input.data[subj->pos+4] == '>') {
+ matchlen = 5;
+ } else {
+ matchlen = scan_html_comment(&subj->input, subj->pos + 1);
+ if (matchlen > 0) {
+ matchlen += 1; // prefix "<"
+ } else { // no match through end of input: set a flag so
+ // we don't reparse looking for -->:
+ subj->flags |= FLAG_SKIP_HTML_COMMENT;
+ }
+ }
+ } else if (c == '[') {
+ if ((subj->flags & FLAG_SKIP_HTML_CDATA) == 0) {
+ matchlen = scan_html_cdata(&subj->input, subj->pos + 2);
+ if (matchlen > 0) {
+ // The regex doesn't require the final "]]>". But if we're not at
+ // the end of input, it must come after the match. Otherwise,
+ // disable subsequent scans to avoid quadratic behavior.
+ matchlen += 5; // prefix "![", suffix "]]>"
+ if (subj->pos + matchlen > subj->input.len) {
+ subj->flags |= FLAG_SKIP_HTML_CDATA;
+ matchlen = 0;
+ }
+ }
+ }
+ } else if ((subj->flags & FLAG_SKIP_HTML_DECLARATION) == 0) {
+ matchlen = scan_html_declaration(&subj->input, subj->pos + 1);
+ if (matchlen > 0) {
+ matchlen += 2; // prefix "!", suffix ">"
+ if (subj->pos + matchlen > subj->input.len) {
+ subj->flags |= FLAG_SKIP_HTML_DECLARATION;
+ matchlen = 0;
+ }
+ }
+ }
+ } else if (c == '?') {
+ if ((subj->flags & FLAG_SKIP_HTML_PI) == 0) {
+ // Note that we allow an empty match.
+ matchlen = scan_html_pi(&subj->input, subj->pos + 1);
+ matchlen += 3; // prefix "?", suffix "?>"
+ if (subj->pos + matchlen > subj->input.len) {
+ subj->flags |= FLAG_SKIP_HTML_PI;
+ matchlen = 0;
+ }
+ }
+ } else {
+ matchlen = scan_html_tag(&subj->input, subj->pos);
+ }
+ }
+ if (matchlen > 0) {
+ const unsigned char *src = subj->input.data + subj->pos - 1;
+ bufsize_t len = matchlen + 1;
+ subj->pos += matchlen;
+ cmark_node *node = make_literal(subj, CMARK_NODE_HTML_INLINE,
+ subj->pos - matchlen - 1, subj->pos - 1);
+ node->data = (unsigned char *)subj->mem->realloc(NULL, len + 1);
+ memcpy(node->data, src, len);
+ node->data[len] = 0;
+ node->len = len;
+ adjust_subj_node_newlines(subj, node, matchlen, 1, options);
+ return node;
+ }
+
+ // if nothing matches, just return the opening <:
+ return make_str(subj, subj->pos - 1, subj->pos - 1, cmark_chunk_literal("<"));
+}
+
+// Parse a link label. Returns 1 if successful.
+// Note: unescaped brackets are not allowed in labels.
+// The label begins with `[` and ends with the first `]` character
+// encountered. Backticks in labels do not start code spans.
+static int link_label(subject *subj, cmark_chunk *raw_label) {
+ bufsize_t startpos = subj->pos;
+ int length = 0;
+ unsigned char c;
+
+ // advance past [
+ if (peek_char(subj) == '[') {
+ advance(subj);
+ } else {
+ return 0;
+ }
+
+ while ((c = peek_char(subj)) && c != '[' && c != ']') {
+ if (c == '\\') {
+ advance(subj);
+ length++;
+ if (cmark_ispunct(peek_char(subj))) {
+ advance(subj);
+ length++;
+ }
+ } else {
+ advance(subj);
+ length++;
+ }
+ if (length > MAX_LINK_LABEL_LENGTH) {
+ goto noMatch;
+ }
+ }
+
+ if (c == ']') { // match found
+ *raw_label =
+ cmark_chunk_dup(&subj->input, startpos + 1, subj->pos - (startpos + 1));
+ cmark_chunk_trim(raw_label);
+ advance(subj); // advance past ]
+ return 1;
+ }
+
+noMatch:
+ subj->pos = startpos; // rewind
+ return 0;
+}
+
+static bufsize_t manual_scan_link_url_2(cmark_chunk *input, bufsize_t offset,
+ cmark_chunk *output) {
+ bufsize_t i = offset;
+ size_t nb_p = 0;
+
+ while (i < input->len) {
+ if (input->data[i] == '\\' &&
+ i + 1 < input-> len &&
+ cmark_ispunct(input->data[i+1]))
+ i += 2;
+ else if (input->data[i] == '(') {
+ ++nb_p;
+ ++i;
+ if (nb_p > 32)
+ return -1;
+ } else if (input->data[i] == ')') {
+ if (nb_p == 0)
+ break;
+ --nb_p;
+ ++i;
+ } else if (cmark_isspace(input->data[i])) {
+ if (i == offset) {
+ return -1;
+ }
+ break;
+ } else {
+ ++i;
+ }
+ }
+
+ if (i >= input->len || nb_p != 0)
+ return -1;
+
+ {
+ cmark_chunk result = {input->data + offset, i - offset};
+ *output = result;
+ }
+ return i - offset;
+}
+
+static bufsize_t manual_scan_link_url(cmark_chunk *input, bufsize_t offset,
+ cmark_chunk *output) {
+ bufsize_t i = offset;
+
+ if (i < input->len && input->data[i] == '<') {
+ ++i;
+ while (i < input->len) {
+ if (input->data[i] == '>') {
+ ++i;
+ break;
+ } else if (input->data[i] == '\\')
+ i += 2;
+ else if (input->data[i] == '\n' || input->data[i] == '<')
+ return -1;
+ else
+ ++i;
+ }
+ } else {
+ return manual_scan_link_url_2(input, offset, output);
+ }
+
+ if (i >= input->len)
+ return -1;
+
+ {
+ cmark_chunk result = {input->data + offset + 1, i - 2 - offset};
+ *output = result;
+ }
+ return i - offset;
+}
+
+// Return a link, an image, or a literal close bracket.
+static cmark_node *handle_close_bracket(subject *subj) {
+ bufsize_t initial_pos, after_link_text_pos;
+ bufsize_t endurl, starttitle, endtitle, endall;
+ bufsize_t sps, n;
+ cmark_reference *ref = NULL;
+ cmark_chunk url_chunk, title_chunk;
+ unsigned char *url, *title;
+ bracket *opener;
+ cmark_node *inl;
+ cmark_chunk raw_label;
+ int found_label;
+ cmark_node *tmp, *tmpnext;
+ bool is_image;
+
+ advance(subj); // advance past ]
+ initial_pos = subj->pos;
+
+ // get last [ or ![
+ opener = subj->last_bracket;
+
+ if (opener == NULL) {
+ return make_str(subj, subj->pos - 1, subj->pos - 1, cmark_chunk_literal("]"));
+ }
+
+ // If we got here, we matched a potential link/image text.
+ // Now we check to see if it's a link/image.
+ is_image = opener->image;
+
+ if (!is_image && subj->no_link_openers) {
+ // take delimiter off stack
+ pop_bracket(subj);
+ return make_str(subj, subj->pos - 1, subj->pos - 1, cmark_chunk_literal("]"));
+ }
+
+ after_link_text_pos = subj->pos;
+
+ // First, look for an inline link.
+ if (peek_char(subj) == '(' &&
+ ((sps = scan_spacechars(&subj->input, subj->pos + 1)) > -1) &&
+ ((n = manual_scan_link_url(&subj->input, subj->pos + 1 + sps,
+ &url_chunk)) > -1)) {
+
+ // try to parse an explicit link:
+ endurl = subj->pos + 1 + sps + n;
+ starttitle = endurl + scan_spacechars(&subj->input, endurl);
+
+ // ensure there are spaces btw url and title
+ endtitle = (starttitle == endurl)
+ ? starttitle
+ : starttitle + scan_link_title(&subj->input, starttitle);
+
+ endall = endtitle + scan_spacechars(&subj->input, endtitle);
+
+ if (peek_at(subj, endall) == ')') {
+ subj->pos = endall + 1;
+
+ title_chunk =
+ cmark_chunk_dup(&subj->input, starttitle, endtitle - starttitle);
+ url = cmark_clean_url(subj->mem, &url_chunk);
+ title = cmark_clean_title(subj->mem, &title_chunk);
+ cmark_chunk_free(&url_chunk);
+ cmark_chunk_free(&title_chunk);
+ goto match;
+
+ } else {
+ // it could still be a shortcut reference link
+ subj->pos = after_link_text_pos;
+ }
+ }
+
+ // Next, look for a following [link label] that matches in refmap.
+ // skip spaces
+ raw_label = cmark_chunk_literal("");
+ found_label = link_label(subj, &raw_label);
+ if (!found_label) {
+ // If we have a shortcut reference link, back up
+ // to before the spaces we skipped.
+ subj->pos = initial_pos;
+ }
+
+ if ((!found_label || raw_label.len == 0) && !opener->bracket_after) {
+ cmark_chunk_free(&raw_label);
+ raw_label = cmark_chunk_dup(&subj->input, opener->position,
+ initial_pos - opener->position - 1);
+ found_label = true;
+ }
+
+ if (found_label) {
+ ref = cmark_reference_lookup(subj->refmap, &raw_label);
+ cmark_chunk_free(&raw_label);
+ }
+
+ if (ref != NULL) { // found
+ url = cmark_strdup(subj->mem, ref->url);
+ title = cmark_strdup(subj->mem, ref->title);
+ goto match;
+ } else {
+ goto noMatch;
+ }
+
+noMatch:
+ // If we fall through to here, it means we didn't match a link:
+ pop_bracket(subj); // remove this opener from delimiter list
+ subj->pos = initial_pos;
+ return make_str(subj, subj->pos - 1, subj->pos - 1, cmark_chunk_literal("]"));
+
+match:
+ inl = make_simple(subj->mem, is_image ? CMARK_NODE_IMAGE : CMARK_NODE_LINK);
+ inl->as.link.url = url;
+ inl->as.link.title = title;
+ inl->start_line = inl->end_line = subj->line;
+ inl->start_column = opener->inl_text->start_column;
+ inl->end_column = subj->pos + subj->column_offset + subj->block_offset;
+ cmark_node_insert_before(opener->inl_text, inl);
+ // Add link text:
+ tmp = opener->inl_text->next;
+ while (tmp) {
+ tmpnext = tmp->next;
+ cmark_node_unlink(tmp);
+ append_child(inl, tmp);
+ tmp = tmpnext;
+ }
+
+ // Free the bracket [:
+ cmark_node_free(opener->inl_text);
+
+ process_emphasis(subj, opener->position);
+ pop_bracket(subj);
+
+ // Now, if we have a link, we also want to deactivate links until
+ // we get a new opener. (This code can be removed if we decide to allow links
+ // inside links.)
+ if (!is_image) {
+ subj->no_link_openers = true;
+ }
+
+ return NULL;
+}
+
+// Parse a hard or soft linebreak, returning an inline.
+// Assumes the subject has a cr or newline at the current position.
+static cmark_node *handle_newline(subject *subj) {
+ bufsize_t nlpos = subj->pos;
+ // skip over cr, crlf, or lf:
+ if (peek_at(subj, subj->pos) == '\r') {
+ advance(subj);
+ }
+ if (peek_at(subj, subj->pos) == '\n') {
+ advance(subj);
+ }
+ ++subj->line;
+ subj->column_offset = -subj->pos;
+ // skip spaces at beginning of line
+ skip_spaces(subj);
+ if (nlpos > 1 && peek_at(subj, nlpos - 1) == ' ' &&
+ peek_at(subj, nlpos - 2) == ' ') {
+ return make_linebreak(subj->mem);
+ } else {
+ return make_softbreak(subj->mem);
+ }
+}
+
+static bufsize_t subject_find_special_char(subject *subj, int options) {
+ // "\r\n\\`&_*[]<!"
+ static const int8_t SPECIAL_CHARS[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+ // " ' . -
+ static const char SMART_PUNCT_CHARS[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ };
+
+ bufsize_t n = subj->pos + 1;
+
+ while (n < subj->input.len) {
+ if (SPECIAL_CHARS[subj->input.data[n]])
+ return n;
+ if (options & CMARK_OPT_SMART && SMART_PUNCT_CHARS[subj->input.data[n]])
+ return n;
+ n++;
+ }
+
+ return subj->input.len;
+}
+
+// Parse an inline, advancing subject, and add it as a child of parent.
+// Return 0 if no inline can be parsed, 1 otherwise.
+static int parse_inline(subject *subj, cmark_node *parent, int options) {
+ cmark_node *new_inl = NULL;
+ cmark_chunk contents;
+ unsigned char c;
+ bufsize_t startpos, endpos;
+ c = peek_char(subj);
+ if (c == 0) {
+ return 0;
+ }
+ switch (c) {
+ case '\r':
+ case '\n':
+ new_inl = handle_newline(subj);
+ break;
+ case '`':
+ new_inl = handle_backticks(subj, options);
+ break;
+ case '\\':
+ new_inl = handle_backslash(subj);
+ break;
+ case '&':
+ new_inl = handle_entity(subj);
+ break;
+ case '<':
+ new_inl = handle_pointy_brace(subj, options);
+ break;
+ case '*':
+ case '_':
+ case '\'':
+ case '"':
+ new_inl = handle_delim(subj, c, (options & CMARK_OPT_SMART) != 0);
+ break;
+ case '-':
+ new_inl = handle_hyphen(subj, (options & CMARK_OPT_SMART) != 0);
+ break;
+ case '.':
+ new_inl = handle_period(subj, (options & CMARK_OPT_SMART) != 0);
+ break;
+ case '[':
+ advance(subj);
+ new_inl = make_str(subj, subj->pos - 1, subj->pos - 1, cmark_chunk_literal("["));
+ push_bracket(subj, false, new_inl);
+ break;
+ case ']':
+ new_inl = handle_close_bracket(subj);
+ break;
+ case '!':
+ advance(subj);
+ if (peek_char(subj) == '[') {
+ advance(subj);
+ new_inl = make_str(subj, subj->pos - 2, subj->pos - 1, cmark_chunk_literal("!["));
+ push_bracket(subj, true, new_inl);
+ } else {
+ new_inl = make_str(subj, subj->pos - 1, subj->pos - 1, cmark_chunk_literal("!"));
+ }
+ break;
+ default:
+ endpos = subject_find_special_char(subj, options);
+ contents = cmark_chunk_dup(&subj->input, subj->pos, endpos - subj->pos);
+ startpos = subj->pos;
+ subj->pos = endpos;
+
+ // if we're at a newline, strip trailing spaces.
+ if (S_is_line_end_char(peek_char(subj))) {
+ cmark_chunk_rtrim(&contents);
+ }
+
+ new_inl = make_str(subj, startpos, endpos - 1, contents);
+ }
+ if (new_inl != NULL) {
+ append_child(parent, new_inl);
+ }
+
+ return 1;
+}
+
+// Parse inlines from parent's string_content, adding as children of parent.
+void cmark_parse_inlines(cmark_mem *mem, cmark_node *parent,
+ cmark_reference_map *refmap, int options) {
+ int internal_offset = parent->type == CMARK_NODE_HEADING ?
+ parent->as.heading.internal_offset : 0;
+ subject subj;
+ cmark_chunk content = {parent->data, parent->len};
+ subject_from_buf(mem, parent->start_line, parent->start_column - 1 + internal_offset, &subj, &content, refmap);
+ cmark_chunk_rtrim(&subj.input);
+
+ while (!is_eof(&subj) && parse_inline(&subj, parent, options))
+ ;
+
+ process_emphasis(&subj, 0);
+ // free bracket and delim stack
+ while (subj.last_delim) {
+ remove_delimiter(&subj, subj.last_delim);
+ }
+ while (subj.last_bracket) {
+ pop_bracket(&subj);
+ }
+}
+
+// Parse zero or more space characters, including at most one newline.
+static void spnl(subject *subj) {
+ skip_spaces(subj);
+ if (skip_line_end(subj)) {
+ skip_spaces(subj);
+ }
+}
+
+// Parse reference. Assumes string begins with '[' character.
+// Modify refmap if a reference is encountered.
+// Return 0 if no reference found, otherwise position of subject
+// after reference is parsed.
+bufsize_t cmark_parse_reference_inline(cmark_mem *mem, cmark_chunk *input,
+ cmark_reference_map *refmap) {
+ subject subj;
+
+ cmark_chunk lab;
+ cmark_chunk url;
+ cmark_chunk title;
+
+ bufsize_t matchlen = 0;
+ bufsize_t beforetitle;
+
+ subject_from_buf(mem, -1, 0, &subj, input, NULL);
+
+ // parse label:
+ if (!link_label(&subj, &lab) || lab.len == 0)
+ return 0;
+
+ // colon:
+ if (peek_char(&subj) == ':') {
+ advance(&subj);
+ } else {
+ return 0;
+ }
+
+ // parse link url:
+ spnl(&subj);
+ if ((matchlen = manual_scan_link_url(&subj.input, subj.pos, &url)) > -1) {
+ subj.pos += matchlen;
+ } else {
+ return 0;
+ }
+
+ // parse optional link_title
+ beforetitle = subj.pos;
+ spnl(&subj);
+ matchlen = subj.pos == beforetitle ? 0 : scan_link_title(&subj.input, subj.pos);
+ if (matchlen) {
+ title = cmark_chunk_dup(&subj.input, subj.pos, matchlen);
+ subj.pos += matchlen;
+ } else {
+ subj.pos = beforetitle;
+ title = cmark_chunk_literal("");
+ }
+
+ // parse final spaces and newline:
+ skip_spaces(&subj);
+ if (!skip_line_end(&subj)) {
+ if (matchlen) { // try rewinding before title
+ subj.pos = beforetitle;
+ skip_spaces(&subj);
+ if (!skip_line_end(&subj)) {
+ return 0;
+ }
+ } else {
+ return 0;
+ }
+ }
+ // insert reference into refmap
+ cmark_reference_create(refmap, &lab, &url, &title);
+ return subj.pos;
+}
diff --git a/cmark/src/inlines.h b/cmark/src/inlines.h
new file mode 100644
index 0000000000..800ed0c68f
--- /dev/null
+++ b/cmark/src/inlines.h
@@ -0,0 +1,24 @@
+#ifndef CMARK_INLINES_H
+#define CMARK_INLINES_H
+
+#include "chunk.h"
+#include "references.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+unsigned char *cmark_clean_url(cmark_mem *mem, cmark_chunk *url);
+unsigned char *cmark_clean_title(cmark_mem *mem, cmark_chunk *title);
+
+void cmark_parse_inlines(cmark_mem *mem, cmark_node *parent,
+ cmark_reference_map *refmap, int options);
+
+bufsize_t cmark_parse_reference_inline(cmark_mem *mem, cmark_chunk *input,
+ cmark_reference_map *refmap);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/cmark/src/iterator.c b/cmark/src/iterator.c
new file mode 100644
index 0000000000..cc428285ea
--- /dev/null
+++ b/cmark/src/iterator.c
@@ -0,0 +1,122 @@
+#include <assert.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include "node.h"
+#include "cmark.h"
+#include "iterator.h"
+
+static const int S_leaf_mask =
+ (1 << CMARK_NODE_HTML_BLOCK) | (1 << CMARK_NODE_THEMATIC_BREAK) |
+ (1 << CMARK_NODE_CODE_BLOCK) | (1 << CMARK_NODE_TEXT) |
+ (1 << CMARK_NODE_SOFTBREAK) | (1 << CMARK_NODE_LINEBREAK) |
+ (1 << CMARK_NODE_CODE) | (1 << CMARK_NODE_HTML_INLINE);
+
+cmark_iter *cmark_iter_new(cmark_node *root) {
+ if (root == NULL) {
+ return NULL;
+ }
+ cmark_mem *mem = root->mem;
+ cmark_iter *iter = (cmark_iter *)mem->calloc(1, sizeof(cmark_iter));
+ iter->mem = mem;
+ iter->root = root;
+ iter->cur.ev_type = CMARK_EVENT_NONE;
+ iter->cur.node = NULL;
+ iter->next.ev_type = CMARK_EVENT_ENTER;
+ iter->next.node = root;
+ return iter;
+}
+
+void cmark_iter_free(cmark_iter *iter) { iter->mem->free(iter); }
+
+static bool S_is_leaf(cmark_node *node) {
+ return ((1 << node->type) & S_leaf_mask) != 0;
+}
+
+cmark_event_type cmark_iter_next(cmark_iter *iter) {
+ cmark_event_type ev_type = iter->next.ev_type;
+ cmark_node *node = iter->next.node;
+
+ iter->cur.ev_type = ev_type;
+ iter->cur.node = node;
+
+ if (ev_type == CMARK_EVENT_DONE) {
+ return ev_type;
+ }
+
+ /* roll forward to next item, setting both fields */
+ if (ev_type == CMARK_EVENT_ENTER && !S_is_leaf(node)) {
+ if (node->first_child == NULL) {
+ /* stay on this node but exit */
+ iter->next.ev_type = CMARK_EVENT_EXIT;
+ } else {
+ iter->next.ev_type = CMARK_EVENT_ENTER;
+ iter->next.node = node->first_child;
+ }
+ } else if (node == iter->root) {
+ /* don't move past root */
+ iter->next.ev_type = CMARK_EVENT_DONE;
+ iter->next.node = NULL;
+ } else if (node->next) {
+ iter->next.ev_type = CMARK_EVENT_ENTER;
+ iter->next.node = node->next;
+ } else if (node->parent) {
+ iter->next.ev_type = CMARK_EVENT_EXIT;
+ iter->next.node = node->parent;
+ } else {
+ assert(false);
+ iter->next.ev_type = CMARK_EVENT_DONE;
+ iter->next.node = NULL;
+ }
+
+ return ev_type;
+}
+
+void cmark_iter_reset(cmark_iter *iter, cmark_node *current,
+ cmark_event_type event_type) {
+ iter->next.ev_type = event_type;
+ iter->next.node = current;
+ cmark_iter_next(iter);
+}
+
+cmark_node *cmark_iter_get_node(cmark_iter *iter) { return iter->cur.node; }
+
+cmark_event_type cmark_iter_get_event_type(cmark_iter *iter) {
+ return iter->cur.ev_type;
+}
+
+cmark_node *cmark_iter_get_root(cmark_iter *iter) { return iter->root; }
+
+void cmark_consolidate_text_nodes(cmark_node *root) {
+ if (root == NULL) {
+ return;
+ }
+ cmark_iter *iter = cmark_iter_new(root);
+ cmark_strbuf buf = CMARK_BUF_INIT(iter->mem);
+ cmark_event_type ev_type;
+ cmark_node *cur, *tmp, *next;
+
+ while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
+ cur = cmark_iter_get_node(iter);
+ if (ev_type == CMARK_EVENT_ENTER && cur->type == CMARK_NODE_TEXT &&
+ cur->next && cur->next->type == CMARK_NODE_TEXT) {
+ cmark_strbuf_clear(&buf);
+ cmark_strbuf_put(&buf, cur->data, cur->len);
+ tmp = cur->next;
+ while (tmp && tmp->type == CMARK_NODE_TEXT) {
+ cmark_iter_next(iter); // advance pointer
+ cmark_strbuf_put(&buf, tmp->data, tmp->len);
+ cur->end_column = tmp->end_column;
+ next = tmp->next;
+ cmark_node_free(tmp);
+ tmp = next;
+ }
+ iter->mem->free(cur->data);
+ cur->len = buf.size;
+ cur->data = cmark_strbuf_detach(&buf);
+ }
+ }
+
+ cmark_strbuf_free(&buf);
+ cmark_iter_free(iter);
+}
diff --git a/cmark/src/iterator.h b/cmark/src/iterator.h
new file mode 100644
index 0000000000..30ce76f519
--- /dev/null
+++ b/cmark/src/iterator.h
@@ -0,0 +1,26 @@
+#ifndef CMARK_ITERATOR_H
+#define CMARK_ITERATOR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "cmark.h"
+
+typedef struct {
+ cmark_event_type ev_type;
+ cmark_node *node;
+} cmark_iter_state;
+
+struct cmark_iter {
+ cmark_mem *mem;
+ cmark_node *root;
+ cmark_iter_state cur;
+ cmark_iter_state next;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/cmark/src/latex.c b/cmark/src/latex.c
new file mode 100644
index 0000000000..386c14ff58
--- /dev/null
+++ b/cmark/src/latex.c
@@ -0,0 +1,456 @@
+#include <assert.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "cmark.h"
+#include "node.h"
+#include "buffer.h"
+#include "utf8.h"
+#include "scanners.h"
+#include "render.h"
+
+#define OUT(s, wrap, escaping) renderer->out(renderer, s, wrap, escaping)
+#define LIT(s) renderer->out(renderer, s, false, LITERAL)
+#define CR() renderer->cr(renderer)
+#define BLANKLINE() renderer->blankline(renderer)
+#define LIST_NUMBER_STRING_SIZE 20
+
+static inline void outc(cmark_renderer *renderer, cmark_escaping escape,
+ int32_t c, unsigned char nextc) {
+ if (escape == LITERAL) {
+ cmark_render_code_point(renderer, c);
+ return;
+ }
+
+ switch (c) {
+ case 123: // '{'
+ case 125: // '}'
+ case 35: // '#'
+ case 37: // '%'
+ case 38: // '&'
+ cmark_render_ascii(renderer, "\\");
+ cmark_render_code_point(renderer, c);
+ break;
+ case 36: // '$'
+ case 95: // '_'
+ if (escape == NORMAL) {
+ cmark_render_ascii(renderer, "\\");
+ }
+ cmark_render_code_point(renderer, c);
+ break;
+ case 45: // '-'
+ if (nextc == 45) { // prevent ligature
+ cmark_render_ascii(renderer, "-{}");
+ } else {
+ cmark_render_ascii(renderer, "-");
+ }
+ break;
+ case 126: // '~'
+ if (escape == NORMAL) {
+ cmark_render_ascii(renderer, "\\textasciitilde{}");
+ } else {
+ cmark_render_code_point(renderer, c);
+ }
+ break;
+ case 94: // '^'
+ cmark_render_ascii(renderer, "\\^{}");
+ break;
+ case 92: // '\\'
+ if (escape == URL) {
+ // / acts as path sep even on windows:
+ cmark_render_ascii(renderer, "/");
+ } else {
+ cmark_render_ascii(renderer, "\\textbackslash{}");
+ }
+ break;
+ case 124: // '|'
+ cmark_render_ascii(renderer, "\\textbar{}");
+ break;
+ case 60: // '<'
+ cmark_render_ascii(renderer, "\\textless{}");
+ break;
+ case 62: // '>'
+ cmark_render_ascii(renderer, "\\textgreater{}");
+ break;
+ case 91: // '['
+ case 93: // ']'
+ cmark_render_ascii(renderer, "{");
+ cmark_render_code_point(renderer, c);
+ cmark_render_ascii(renderer, "}");
+ break;
+ case 34: // '"'
+ cmark_render_ascii(renderer, "\\textquotedbl{}");
+ // requires \usepackage[T1]{fontenc}
+ break;
+ case 39: // '\''
+ cmark_render_ascii(renderer, "\\textquotesingle{}");
+ // requires \usepackage{textcomp}
+ break;
+ case 160: // nbsp
+ cmark_render_ascii(renderer, "~");
+ break;
+ case 8230: // hellip
+ cmark_render_ascii(renderer, "\\ldots{}");
+ break;
+ case 8216: // lsquo
+ if (escape == NORMAL) {
+ cmark_render_ascii(renderer, "`");
+ } else {
+ cmark_render_code_point(renderer, c);
+ }
+ break;
+ case 8217: // rsquo
+ if (escape == NORMAL) {
+ cmark_render_ascii(renderer, "\'");
+ } else {
+ cmark_render_code_point(renderer, c);
+ }
+ break;
+ case 8220: // ldquo
+ if (escape == NORMAL) {
+ cmark_render_ascii(renderer, "``");
+ } else {
+ cmark_render_code_point(renderer, c);
+ }
+ break;
+ case 8221: // rdquo
+ if (escape == NORMAL) {
+ cmark_render_ascii(renderer, "''");
+ } else {
+ cmark_render_code_point(renderer, c);
+ }
+ break;
+ case 8212: // emdash
+ if (escape == NORMAL) {
+ cmark_render_ascii(renderer, "---");
+ } else {
+ cmark_render_code_point(renderer, c);
+ }
+ break;
+ case 8211: // endash
+ if (escape == NORMAL) {
+ cmark_render_ascii(renderer, "--");
+ } else {
+ cmark_render_code_point(renderer, c);
+ }
+ break;
+ default:
+ cmark_render_code_point(renderer, c);
+ }
+}
+
+typedef enum {
+ NO_LINK,
+ URL_AUTOLINK,
+ EMAIL_AUTOLINK,
+ NORMAL_LINK,
+ INTERNAL_LINK
+} link_type;
+
+static link_type get_link_type(cmark_node *node) {
+ size_t title_len, url_len;
+ cmark_node *link_text;
+ char *realurl;
+ int realurllen;
+ bool isemail = false;
+
+ if (node->type != CMARK_NODE_LINK) {
+ return NO_LINK;
+ }
+
+ const char *url = cmark_node_get_url(node);
+ cmark_chunk url_chunk = cmark_chunk_literal(url);
+
+ if (url && *url == '#') {
+ return INTERNAL_LINK;
+ }
+
+ url_len = strlen(url);
+ if (url_len == 0 || scan_scheme(&url_chunk, 0) == 0) {
+ return NO_LINK;
+ }
+
+ const char *title = cmark_node_get_title(node);
+ title_len = strlen(title);
+ // if it has a title, we can't treat it as an autolink:
+ if (title_len == 0) {
+
+ link_text = node->first_child;
+ cmark_consolidate_text_nodes(link_text);
+
+ if (!link_text)
+ return NO_LINK;
+
+ realurl = (char *)url;
+ realurllen = (int)url_len;
+ if (strncmp(realurl, "mailto:", 7) == 0) {
+ realurl += 7;
+ realurllen -= 7;
+ isemail = true;
+ }
+ if (realurllen == link_text->len &&
+ strncmp(realurl, (char *)link_text->data,
+ link_text->len) == 0) {
+ if (isemail) {
+ return EMAIL_AUTOLINK;
+ } else {
+ return URL_AUTOLINK;
+ }
+ }
+ }
+
+ return NORMAL_LINK;
+}
+
+static int S_get_enumlevel(cmark_node *node) {
+ int enumlevel = 0;
+ cmark_node *tmp = node;
+ while (tmp) {
+ if (tmp->type == CMARK_NODE_LIST &&
+ cmark_node_get_list_type(node) == CMARK_ORDERED_LIST) {
+ enumlevel++;
+ }
+ tmp = tmp->parent;
+ }
+ return enumlevel;
+}
+
+static int S_render_node(cmark_renderer *renderer, cmark_node *node,
+ cmark_event_type ev_type, int options) {
+ int list_number;
+ int enumlevel;
+ char list_number_string[LIST_NUMBER_STRING_SIZE];
+ bool entering = (ev_type == CMARK_EVENT_ENTER);
+ cmark_list_type list_type;
+ bool allow_wrap = renderer->width > 0 && !(CMARK_OPT_NOBREAKS & options);
+
+ // avoid warning about unused parameter:
+ (void)(options);
+
+ switch (node->type) {
+ case CMARK_NODE_DOCUMENT:
+ break;
+
+ case CMARK_NODE_BLOCK_QUOTE:
+ if (entering) {
+ LIT("\\begin{quote}");
+ CR();
+ } else {
+ LIT("\\end{quote}");
+ BLANKLINE();
+ }
+ break;
+
+ case CMARK_NODE_LIST:
+ list_type = cmark_node_get_list_type(node);
+ if (entering) {
+ LIT("\\begin{");
+ LIT(list_type == CMARK_ORDERED_LIST ? "enumerate" : "itemize");
+ LIT("}");
+ CR();
+ list_number = cmark_node_get_list_start(node);
+ if (list_number > 1) {
+ enumlevel = S_get_enumlevel(node);
+ // latex normally supports only five levels
+ if (enumlevel >= 1 && enumlevel <= 5) {
+ snprintf(list_number_string, LIST_NUMBER_STRING_SIZE, "%d",
+ list_number - 1); // the next item will increment this
+ LIT("\\setcounter{enum");
+ switch (enumlevel) {
+ case 1: LIT("i"); break;
+ case 2: LIT("ii"); break;
+ case 3: LIT("iii"); break;
+ case 4: LIT("iv"); break;
+ case 5: LIT("v"); break;
+ default: LIT("i"); break;
+ }
+ LIT("}{");
+ OUT(list_number_string, false, NORMAL);
+ LIT("}");
+ }
+ CR();
+ }
+ } else {
+ LIT("\\end{");
+ LIT(list_type == CMARK_ORDERED_LIST ? "enumerate" : "itemize");
+ LIT("}");
+ BLANKLINE();
+ }
+ break;
+
+ case CMARK_NODE_ITEM:
+ if (entering) {
+ LIT("\\item ");
+ } else {
+ CR();
+ }
+ break;
+
+ case CMARK_NODE_HEADING:
+ if (entering) {
+ switch (cmark_node_get_heading_level(node)) {
+ case 1:
+ LIT("\\section");
+ break;
+ case 2:
+ LIT("\\subsection");
+ break;
+ case 3:
+ LIT("\\subsubsection");
+ break;
+ case 4:
+ LIT("\\paragraph");
+ break;
+ case 5:
+ LIT("\\subparagraph");
+ break;
+ }
+ LIT("{");
+ } else {
+ LIT("}");
+ BLANKLINE();
+ }
+ break;
+
+ case CMARK_NODE_CODE_BLOCK:
+ CR();
+ LIT("\\begin{verbatim}");
+ CR();
+ OUT(cmark_node_get_literal(node), false, LITERAL);
+ CR();
+ LIT("\\end{verbatim}");
+ BLANKLINE();
+ break;
+
+ case CMARK_NODE_HTML_BLOCK:
+ break;
+
+ case CMARK_NODE_CUSTOM_BLOCK:
+ CR();
+ OUT(entering ? cmark_node_get_on_enter(node) : cmark_node_get_on_exit(node),
+ false, LITERAL);
+ CR();
+ break;
+
+ case CMARK_NODE_THEMATIC_BREAK:
+ BLANKLINE();
+ LIT("\\begin{center}\\rule{0.5\\linewidth}{\\linethickness}\\end{center}");
+ BLANKLINE();
+ break;
+
+ case CMARK_NODE_PARAGRAPH:
+ if (!entering) {
+ BLANKLINE();
+ }
+ break;
+
+ case CMARK_NODE_TEXT:
+ OUT(cmark_node_get_literal(node), allow_wrap, NORMAL);
+ break;
+
+ case CMARK_NODE_LINEBREAK:
+ LIT("\\\\");
+ CR();
+ break;
+
+ case CMARK_NODE_SOFTBREAK:
+ if (options & CMARK_OPT_HARDBREAKS) {
+ LIT("\\\\");
+ CR();
+ } else if (renderer->width == 0 && !(CMARK_OPT_NOBREAKS & options)) {
+ CR();
+ } else {
+ OUT(" ", allow_wrap, NORMAL);
+ }
+ break;
+
+ case CMARK_NODE_CODE:
+ LIT("\\texttt{");
+ OUT(cmark_node_get_literal(node), false, NORMAL);
+ LIT("}");
+ break;
+
+ case CMARK_NODE_HTML_INLINE:
+ break;
+
+ case CMARK_NODE_CUSTOM_INLINE:
+ OUT(entering ? cmark_node_get_on_enter(node) : cmark_node_get_on_exit(node),
+ false, LITERAL);
+ break;
+
+ case CMARK_NODE_STRONG:
+ if (entering) {
+ LIT("\\textbf{");
+ } else {
+ LIT("}");
+ }
+ break;
+
+ case CMARK_NODE_EMPH:
+ if (entering) {
+ LIT("\\emph{");
+ } else {
+ LIT("}");
+ }
+ break;
+
+ case CMARK_NODE_LINK:
+ if (entering) {
+ const char *url = cmark_node_get_url(node);
+ // requires \usepackage{hyperref}
+ switch (get_link_type(node)) {
+ case URL_AUTOLINK:
+ LIT("\\url{");
+ OUT(url, false, URL);
+ LIT("}");
+ return 0; // Don't process further nodes to avoid double-rendering artefacts
+ case EMAIL_AUTOLINK:
+ LIT("\\href{");
+ OUT(url, false, URL);
+ LIT("}{\\nolinkurl{");
+ break;
+ case NORMAL_LINK:
+ LIT("\\href{");
+ OUT(url, false, URL);
+ LIT("}{");
+ break;
+ case INTERNAL_LINK:
+ LIT("\\protect\\hyperlink{");
+ OUT(url + 1, false, URL);
+ LIT("}{");
+ break;
+ case NO_LINK:
+ LIT("{"); // error?
+ }
+ } else {
+ if (get_link_type(node) == EMAIL_AUTOLINK) {
+ LIT("}"); // Close up \nolinkurl argument
+ }
+ LIT("}");
+ }
+
+ break;
+
+ case CMARK_NODE_IMAGE:
+ if (entering) {
+ LIT("\\protect\\includegraphics{");
+ // requires \include{graphicx}
+ OUT(cmark_node_get_url(node), false, URL);
+ LIT("}");
+ return 0;
+ }
+ break;
+
+ default:
+ assert(false);
+ break;
+ }
+
+ return 1;
+}
+
+char *cmark_render_latex(cmark_node *root, int options, int width) {
+ return cmark_render(root, options, width, outc, S_render_node);
+}
diff --git a/cmark/src/libcmark.pc.in b/cmark/src/libcmark.pc.in
new file mode 100644
index 0000000000..e259898a91
--- /dev/null
+++ b/cmark/src/libcmark.pc.in
@@ -0,0 +1,10 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+exec_prefix=@CMAKE_INSTALL_PREFIX@
+libdir=@CMAKE_INSTALL_FULL_LIBDIR@
+includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
+
+Name: libcmark
+Description: CommonMark parsing, rendering, and manipulation
+Version: @PROJECT_VERSION@
+Libs: -L${libdir} -lcmark
+Cflags: -I${includedir}
diff --git a/cmark/src/main.c b/cmark/src/main.c
new file mode 100644
index 0000000000..9a43cceda7
--- /dev/null
+++ b/cmark/src/main.c
@@ -0,0 +1,213 @@
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "cmark.h"
+#include "node.h"
+
+#if defined(__OpenBSD__)
+# include <sys/param.h>
+# if OpenBSD >= 201605
+# define USE_PLEDGE
+# include <unistd.h>
+# endif
+#endif
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+#include <io.h>
+#include <fcntl.h>
+#endif
+
+typedef enum {
+ FORMAT_NONE,
+ FORMAT_HTML,
+ FORMAT_XML,
+ FORMAT_MAN,
+ FORMAT_COMMONMARK,
+ FORMAT_LATEX
+} writer_format;
+
+void print_usage(void) {
+ printf("Usage: cmark [FILE*]\n");
+ printf("Options:\n");
+ printf(" --to, -t FORMAT Specify output format (html, xml, man, "
+ "commonmark, latex)\n");
+ printf(" --width WIDTH Specify wrap width (default 0 = nowrap)\n");
+ printf(" --sourcepos Include source position attribute\n");
+ printf(" --hardbreaks Treat newlines as hard line breaks\n");
+ printf(" --nobreaks Render soft line breaks as spaces\n");
+ printf(" --safe Omit raw HTML and dangerous URLs\n");
+ printf(" --unsafe Render raw HTML and dangerous URLs\n");
+ printf(" --smart Use smart punctuation\n");
+ printf(" --validate-utf8 Replace invalid UTF-8 sequences with U+FFFD\n");
+ printf(" --help, -h Print usage information\n");
+ printf(" --version Print version\n");
+}
+
+static void print_document(cmark_node *document, writer_format writer,
+ int options, int width) {
+ char *result;
+
+ switch (writer) {
+ case FORMAT_HTML:
+ result = cmark_render_html(document, options);
+ break;
+ case FORMAT_XML:
+ result = cmark_render_xml(document, options);
+ break;
+ case FORMAT_MAN:
+ result = cmark_render_man(document, options, width);
+ break;
+ case FORMAT_COMMONMARK:
+ result = cmark_render_commonmark(document, options, width);
+ break;
+ case FORMAT_LATEX:
+ result = cmark_render_latex(document, options, width);
+ break;
+ default:
+ fprintf(stderr, "Unknown format %d\n", writer);
+ exit(1);
+ }
+ fwrite(result, strlen(result), 1, stdout);
+ document->mem->free(result);
+}
+
+int main(int argc, char *argv[]) {
+ int i, numfps = 0;
+ int *files;
+ char buffer[4096];
+ cmark_parser *parser;
+ size_t bytes;
+ cmark_node *document;
+ int width = 0;
+ char *unparsed;
+ writer_format writer = FORMAT_HTML;
+ int options = CMARK_OPT_DEFAULT;
+
+#ifdef USE_PLEDGE
+ if (pledge("stdio rpath", NULL) != 0) {
+ perror("pledge");
+ return 1;
+ }
+#endif
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ _setmode(_fileno(stdin), _O_BINARY);
+ _setmode(_fileno(stdout), _O_BINARY);
+#endif
+
+ files = (int *)calloc(argc, sizeof(*files));
+
+ for (i = 1; i < argc; i++) {
+ if (strcmp(argv[i], "--version") == 0) {
+ printf("cmark %s", CMARK_VERSION_STRING);
+ printf(" - CommonMark converter\n(C) 2014-2016 John MacFarlane\n");
+ exit(0);
+ } else if (strcmp(argv[i], "--sourcepos") == 0) {
+ options |= CMARK_OPT_SOURCEPOS;
+ } else if (strcmp(argv[i], "--hardbreaks") == 0) {
+ options |= CMARK_OPT_HARDBREAKS;
+ } else if (strcmp(argv[i], "--nobreaks") == 0) {
+ options |= CMARK_OPT_NOBREAKS;
+ } else if (strcmp(argv[i], "--smart") == 0) {
+ options |= CMARK_OPT_SMART;
+ } else if (strcmp(argv[i], "--safe") == 0) {
+ options |= CMARK_OPT_SAFE;
+ } else if (strcmp(argv[i], "--unsafe") == 0) {
+ options |= CMARK_OPT_UNSAFE;
+ } else if (strcmp(argv[i], "--validate-utf8") == 0) {
+ options |= CMARK_OPT_VALIDATE_UTF8;
+ } else if ((strcmp(argv[i], "--help") == 0) ||
+ (strcmp(argv[i], "-h") == 0)) {
+ print_usage();
+ exit(0);
+ } else if (strcmp(argv[i], "--width") == 0) {
+ i += 1;
+ if (i < argc) {
+ width = (int)strtol(argv[i], &unparsed, 10);
+ if (unparsed && strlen(unparsed) > 0) {
+ fprintf(stderr, "failed parsing width '%s' at '%s'\n", argv[i],
+ unparsed);
+ exit(1);
+ }
+ } else {
+ fprintf(stderr, "--width requires an argument\n");
+ exit(1);
+ }
+ } else if ((strcmp(argv[i], "-t") == 0) || (strcmp(argv[i], "--to") == 0)) {
+ i += 1;
+ if (i < argc) {
+ if (strcmp(argv[i], "man") == 0) {
+ writer = FORMAT_MAN;
+ } else if (strcmp(argv[i], "html") == 0) {
+ writer = FORMAT_HTML;
+ } else if (strcmp(argv[i], "xml") == 0) {
+ writer = FORMAT_XML;
+ } else if (strcmp(argv[i], "commonmark") == 0) {
+ writer = FORMAT_COMMONMARK;
+ } else if (strcmp(argv[i], "latex") == 0) {
+ writer = FORMAT_LATEX;
+ } else {
+ fprintf(stderr, "Unknown format %s\n", argv[i]);
+ exit(1);
+ }
+ } else {
+ fprintf(stderr, "No argument provided for %s\n", argv[i - 1]);
+ exit(1);
+ }
+ } else if (*argv[i] == '-') {
+ print_usage();
+ exit(1);
+ } else { // treat as file argument
+ files[numfps++] = i;
+ }
+ }
+
+ parser = cmark_parser_new(options);
+ for (i = 0; i < numfps; i++) {
+ FILE *fp = fopen(argv[files[i]], "rb");
+ if (fp == NULL) {
+ fprintf(stderr, "Error opening file %s: %s\n", argv[files[i]],
+ strerror(errno));
+ exit(1);
+ }
+
+ while ((bytes = fread(buffer, 1, sizeof(buffer), fp)) > 0) {
+ cmark_parser_feed(parser, buffer, bytes);
+ if (bytes < sizeof(buffer)) {
+ break;
+ }
+ }
+
+ fclose(fp);
+ }
+
+ if (numfps == 0) {
+
+ while ((bytes = fread(buffer, 1, sizeof(buffer), stdin)) > 0) {
+ cmark_parser_feed(parser, buffer, bytes);
+ if (bytes < sizeof(buffer)) {
+ break;
+ }
+ }
+ }
+
+#ifdef USE_PLEDGE
+ if (pledge("stdio", NULL) != 0) {
+ perror("pledge");
+ return 1;
+ }
+#endif
+
+ document = cmark_parser_finish(parser);
+ cmark_parser_free(parser);
+
+ print_document(document, writer, options, width);
+
+ cmark_node_free(document);
+
+ free(files);
+
+ return 0;
+}
diff --git a/cmark/src/man.c b/cmark/src/man.c
new file mode 100644
index 0000000000..02dfb7cb39
--- /dev/null
+++ b/cmark/src/man.c
@@ -0,0 +1,281 @@
+#include <assert.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "cmark.h"
+#include "node.h"
+#include "buffer.h"
+#include "utf8.h"
+#include "render.h"
+
+#define OUT(s, wrap, escaping) renderer->out(renderer, s, wrap, escaping)
+#define LIT(s) renderer->out(renderer, s, false, LITERAL)
+#define CR() renderer->cr(renderer)
+#define BLANKLINE() renderer->blankline(renderer)
+#define LIST_NUMBER_SIZE 20
+
+// Functions to convert cmark_nodes to groff man strings.
+static void S_outc(cmark_renderer *renderer, cmark_escaping escape, int32_t c,
+ unsigned char nextc) {
+ (void)(nextc);
+
+ if (escape == LITERAL) {
+ cmark_render_code_point(renderer, c);
+ return;
+ }
+
+ switch (c) {
+ case 46:
+ if (renderer->begin_line) {
+ cmark_render_ascii(renderer, "\\&.");
+ } else {
+ cmark_render_code_point(renderer, c);
+ }
+ break;
+ case 39:
+ if (renderer->begin_line) {
+ cmark_render_ascii(renderer, "\\&'");
+ } else {
+ cmark_render_code_point(renderer, c);
+ }
+ break;
+ case 45:
+ cmark_render_ascii(renderer, "\\-");
+ break;
+ case 92:
+ cmark_render_ascii(renderer, "\\e");
+ break;
+ case 8216: // left single quote
+ cmark_render_ascii(renderer, "\\[oq]");
+ break;
+ case 8217: // right single quote
+ cmark_render_ascii(renderer, "\\[cq]");
+ break;
+ case 8220: // left double quote
+ cmark_render_ascii(renderer, "\\[lq]");
+ break;
+ case 8221: // right double quote
+ cmark_render_ascii(renderer, "\\[rq]");
+ break;
+ case 8212: // em dash
+ cmark_render_ascii(renderer, "\\[em]");
+ break;
+ case 8211: // en dash
+ cmark_render_ascii(renderer, "\\[en]");
+ break;
+ default:
+ cmark_render_code_point(renderer, c);
+ }
+}
+
+static int S_render_node(cmark_renderer *renderer, cmark_node *node,
+ cmark_event_type ev_type, int options) {
+ cmark_node *tmp;
+ int list_number;
+ bool entering = (ev_type == CMARK_EVENT_ENTER);
+ bool allow_wrap = renderer->width > 0 && !(CMARK_OPT_NOBREAKS & options);
+ struct block_number *new_block_number;
+ cmark_mem *allocator = cmark_get_default_mem_allocator();
+
+ // avoid unused parameter error:
+ (void)(options);
+
+ // indent inside nested lists
+ if (renderer->block_number_in_list_item &&
+ node->type < CMARK_NODE_FIRST_INLINE) {
+ if (entering) {
+ renderer->block_number_in_list_item->number += 1;
+ if (renderer->block_number_in_list_item->number == 2) {
+ CR();
+ LIT(".RS"); // indent
+ CR();
+ }
+ }
+ }
+
+ switch (node->type) {
+ case CMARK_NODE_DOCUMENT:
+ break;
+
+ case CMARK_NODE_BLOCK_QUOTE:
+ if (entering) {
+ CR();
+ LIT(".RS");
+ CR();
+ } else {
+ CR();
+ LIT(".RE");
+ CR();
+ }
+ break;
+
+ case CMARK_NODE_LIST:
+ break;
+
+ case CMARK_NODE_ITEM:
+ if (entering) {
+ new_block_number = allocator->calloc(1, sizeof(struct block_number));
+ new_block_number->number = 0;
+ new_block_number->parent = renderer->block_number_in_list_item;
+ renderer->block_number_in_list_item = new_block_number;
+ CR();
+ LIT(".IP ");
+ if (cmark_node_get_list_type(node->parent) == CMARK_BULLET_LIST) {
+ LIT("\\[bu] 2");
+ } else {
+ list_number = cmark_node_get_list_start(node->parent);
+ tmp = node;
+ while (tmp->prev) {
+ tmp = tmp->prev;
+ list_number += 1;
+ }
+ char list_number_s[LIST_NUMBER_SIZE];
+ snprintf(list_number_s, LIST_NUMBER_SIZE, "\"%d.\" 4", list_number);
+ LIT(list_number_s);
+ }
+ CR();
+ } else {
+ if (renderer->block_number_in_list_item) {
+ if (renderer->block_number_in_list_item->number >= 2) {
+ CR();
+ LIT(".RE"); // de-indent
+ }
+ new_block_number = renderer->block_number_in_list_item;
+ renderer->block_number_in_list_item =
+ renderer->block_number_in_list_item->parent;
+ allocator->free(new_block_number);
+ }
+ CR();
+ }
+ break;
+
+ case CMARK_NODE_HEADING:
+ if (entering) {
+ CR();
+ LIT(cmark_node_get_heading_level(node) == 1 ? ".SH" : ".SS");
+ CR();
+ } else {
+ CR();
+ }
+ break;
+
+ case CMARK_NODE_CODE_BLOCK:
+ CR();
+ LIT(".IP\n.nf\n\\f[C]\n");
+ OUT(cmark_node_get_literal(node), false, NORMAL);
+ CR();
+ LIT("\\f[]\n.fi");
+ CR();
+ break;
+
+ case CMARK_NODE_HTML_BLOCK:
+ break;
+
+ case CMARK_NODE_CUSTOM_BLOCK:
+ CR();
+ OUT(entering ? cmark_node_get_on_enter(node) : cmark_node_get_on_exit(node),
+ false, LITERAL);
+ CR();
+ break;
+
+ case CMARK_NODE_THEMATIC_BREAK:
+ CR();
+ LIT(".PP\n * * * * *");
+ CR();
+ break;
+
+ case CMARK_NODE_PARAGRAPH:
+ if (entering) {
+ // no blank line if first paragraph in list:
+ if (node->parent && node->parent->type == CMARK_NODE_ITEM &&
+ node->prev == NULL) {
+ // no blank line or .PP
+ } else {
+ CR();
+ LIT(".PP");
+ CR();
+ }
+ } else {
+ CR();
+ }
+ break;
+
+ case CMARK_NODE_TEXT:
+ OUT(cmark_node_get_literal(node), allow_wrap, NORMAL);
+ break;
+
+ case CMARK_NODE_LINEBREAK:
+ LIT(".PD 0\n.P\n.PD");
+ CR();
+ break;
+
+ case CMARK_NODE_SOFTBREAK:
+ if (options & CMARK_OPT_HARDBREAKS) {
+ LIT(".PD 0\n.P\n.PD");
+ CR();
+ } else if (renderer->width == 0 && !(CMARK_OPT_NOBREAKS & options)) {
+ CR();
+ } else {
+ OUT(" ", allow_wrap, LITERAL);
+ }
+ break;
+
+ case CMARK_NODE_CODE:
+ LIT("\\f[C]");
+ OUT(cmark_node_get_literal(node), allow_wrap, NORMAL);
+ LIT("\\f[]");
+ break;
+
+ case CMARK_NODE_HTML_INLINE:
+ break;
+
+ case CMARK_NODE_CUSTOM_INLINE:
+ OUT(entering ? cmark_node_get_on_enter(node) : cmark_node_get_on_exit(node),
+ false, LITERAL);
+ break;
+
+ case CMARK_NODE_STRONG:
+ if (entering) {
+ LIT("\\f[B]");
+ } else {
+ LIT("\\f[]");
+ }
+ break;
+
+ case CMARK_NODE_EMPH:
+ if (entering) {
+ LIT("\\f[I]");
+ } else {
+ LIT("\\f[]");
+ }
+ break;
+
+ case CMARK_NODE_LINK:
+ if (!entering) {
+ LIT(" (");
+ OUT(cmark_node_get_url(node), allow_wrap, URL);
+ LIT(")");
+ }
+ break;
+
+ case CMARK_NODE_IMAGE:
+ if (entering) {
+ LIT("[IMAGE: ");
+ } else {
+ LIT("]");
+ }
+ break;
+
+ default:
+ assert(false);
+ break;
+ }
+
+ return 1;
+}
+
+char *cmark_render_man(cmark_node *root, int options, int width) {
+ return cmark_render(root, options, width, S_outc, S_render_node);
+}
diff --git a/cmark/src/node.c b/cmark/src/node.c
new file mode 100644
index 0000000000..c1492545e4
--- /dev/null
+++ b/cmark/src/node.c
@@ -0,0 +1,888 @@
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "node.h"
+
+static void S_node_unlink(cmark_node *node);
+
+bool cmark_node_is_block(cmark_node *node) {
+ if (node == NULL) {
+ return false;
+ }
+ return node->type >= CMARK_NODE_FIRST_BLOCK &&
+ node->type <= CMARK_NODE_LAST_BLOCK;
+}
+
+bool cmark_node_is_inline(cmark_node *node) {
+ if (node == NULL) {
+ return false;
+ }
+ return node->type >= CMARK_NODE_FIRST_INLINE &&
+ node->type <= CMARK_NODE_LAST_INLINE;
+}
+
+bool cmark_node_is_leaf(cmark_node *node) {
+ if (node == NULL) {
+ return false;
+ }
+ switch (node->type) {
+ case CMARK_NODE_THEMATIC_BREAK: return true;
+ case CMARK_NODE_CODE_BLOCK : return true;
+ case CMARK_NODE_TEXT : return true;
+ case CMARK_NODE_SOFTBREAK : return true;
+ case CMARK_NODE_LINEBREAK : return true;
+ case CMARK_NODE_CODE : return true;
+ case CMARK_NODE_HTML_INLINE: return true;
+ }
+ return false;
+}
+
+static bool S_can_contain(cmark_node *node, cmark_node *child) {
+ if (node == NULL || child == NULL || node == child) {
+ return false;
+ }
+
+ // Verify that child is not an ancestor of node.
+ if (child->first_child != NULL) {
+ cmark_node *cur = node->parent;
+
+ while (cur != NULL) {
+ if (cur == child) {
+ return false;
+ }
+ cur = cur->parent;
+ }
+ }
+
+ if (child->type == CMARK_NODE_DOCUMENT) {
+ return false;
+ }
+
+ switch (node->type) {
+ case CMARK_NODE_DOCUMENT:
+ case CMARK_NODE_BLOCK_QUOTE:
+ case CMARK_NODE_ITEM:
+ return cmark_node_is_block(child) && child->type != CMARK_NODE_ITEM;
+
+ case CMARK_NODE_LIST:
+ return child->type == CMARK_NODE_ITEM;
+
+ case CMARK_NODE_CUSTOM_BLOCK:
+ return true;
+
+ case CMARK_NODE_PARAGRAPH:
+ case CMARK_NODE_HEADING:
+ case CMARK_NODE_EMPH:
+ case CMARK_NODE_STRONG:
+ case CMARK_NODE_LINK:
+ case CMARK_NODE_IMAGE:
+ case CMARK_NODE_CUSTOM_INLINE:
+ return cmark_node_is_inline(child);
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+cmark_node *cmark_node_new_with_mem(cmark_node_type type, cmark_mem *mem) {
+ cmark_node *node = (cmark_node *)mem->calloc(1, sizeof(*node));
+ node->mem = mem;
+ node->type = (uint16_t)type;
+
+ switch (node->type) {
+ case CMARK_NODE_HEADING:
+ node->as.heading.level = 1;
+ break;
+
+ case CMARK_NODE_LIST: {
+ cmark_list *list = &node->as.list;
+ list->list_type = CMARK_BULLET_LIST;
+ list->start = 0;
+ list->tight = false;
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ return node;
+}
+
+cmark_node *cmark_node_new(cmark_node_type type) {
+ extern cmark_mem DEFAULT_MEM_ALLOCATOR;
+ return cmark_node_new_with_mem(type, &DEFAULT_MEM_ALLOCATOR);
+}
+
+// Free a cmark_node list and any children.
+static void S_free_nodes(cmark_node *e) {
+ cmark_mem *mem = e->mem;
+ cmark_node *next;
+ while (e != NULL) {
+ switch (e->type) {
+ case CMARK_NODE_CODE_BLOCK:
+ mem->free(e->data);
+ mem->free(e->as.code.info);
+ break;
+ case CMARK_NODE_TEXT:
+ case CMARK_NODE_HTML_INLINE:
+ case CMARK_NODE_CODE:
+ case CMARK_NODE_HTML_BLOCK:
+ mem->free(e->data);
+ break;
+ case CMARK_NODE_LINK:
+ case CMARK_NODE_IMAGE:
+ mem->free(e->as.link.url);
+ mem->free(e->as.link.title);
+ break;
+ case CMARK_NODE_CUSTOM_BLOCK:
+ case CMARK_NODE_CUSTOM_INLINE:
+ mem->free(e->as.custom.on_enter);
+ mem->free(e->as.custom.on_exit);
+ break;
+ default:
+ break;
+ }
+ if (e->last_child) {
+ // Splice children into list
+ e->last_child->next = e->next;
+ e->next = e->first_child;
+ }
+ next = e->next;
+ mem->free(e);
+ e = next;
+ }
+}
+
+void cmark_node_free(cmark_node *node) {
+ S_node_unlink(node);
+ node->next = NULL;
+ S_free_nodes(node);
+}
+
+cmark_node_type cmark_node_get_type(cmark_node *node) {
+ if (node == NULL) {
+ return CMARK_NODE_NONE;
+ } else {
+ return (cmark_node_type)node->type;
+ }
+}
+
+const char *cmark_node_get_type_string(cmark_node *node) {
+ if (node == NULL) {
+ return "NONE";
+ }
+
+ switch (node->type) {
+ case CMARK_NODE_NONE:
+ return "none";
+ case CMARK_NODE_DOCUMENT:
+ return "document";
+ case CMARK_NODE_BLOCK_QUOTE:
+ return "block_quote";
+ case CMARK_NODE_LIST:
+ return "list";
+ case CMARK_NODE_ITEM:
+ return "item";
+ case CMARK_NODE_CODE_BLOCK:
+ return "code_block";
+ case CMARK_NODE_HTML_BLOCK:
+ return "html_block";
+ case CMARK_NODE_CUSTOM_BLOCK:
+ return "custom_block";
+ case CMARK_NODE_PARAGRAPH:
+ return "paragraph";
+ case CMARK_NODE_HEADING:
+ return "heading";
+ case CMARK_NODE_THEMATIC_BREAK:
+ return "thematic_break";
+ case CMARK_NODE_TEXT:
+ return "text";
+ case CMARK_NODE_SOFTBREAK:
+ return "softbreak";
+ case CMARK_NODE_LINEBREAK:
+ return "linebreak";
+ case CMARK_NODE_CODE:
+ return "code";
+ case CMARK_NODE_HTML_INLINE:
+ return "html_inline";
+ case CMARK_NODE_CUSTOM_INLINE:
+ return "custom_inline";
+ case CMARK_NODE_EMPH:
+ return "emph";
+ case CMARK_NODE_STRONG:
+ return "strong";
+ case CMARK_NODE_LINK:
+ return "link";
+ case CMARK_NODE_IMAGE:
+ return "image";
+ }
+
+ return "<unknown>";
+}
+
+cmark_node *cmark_node_next(cmark_node *node) {
+ if (node == NULL) {
+ return NULL;
+ } else {
+ return node->next;
+ }
+}
+
+cmark_node *cmark_node_previous(cmark_node *node) {
+ if (node == NULL) {
+ return NULL;
+ } else {
+ return node->prev;
+ }
+}
+
+cmark_node *cmark_node_parent(cmark_node *node) {
+ if (node == NULL) {
+ return NULL;
+ } else {
+ return node->parent;
+ }
+}
+
+cmark_node *cmark_node_first_child(cmark_node *node) {
+ if (node == NULL) {
+ return NULL;
+ } else {
+ return node->first_child;
+ }
+}
+
+cmark_node *cmark_node_last_child(cmark_node *node) {
+ if (node == NULL) {
+ return NULL;
+ } else {
+ return node->last_child;
+ }
+}
+
+static bufsize_t cmark_set_cstr(cmark_mem *mem, unsigned char **dst,
+ const char *src) {
+ unsigned char *old = *dst;
+ bufsize_t len;
+
+ if (src && src[0]) {
+ len = (bufsize_t)strlen(src);
+ *dst = (unsigned char *)mem->realloc(NULL, len + 1);
+ memcpy(*dst, src, len + 1);
+ } else {
+ len = 0;
+ *dst = NULL;
+ }
+ if (old) {
+ mem->free(old);
+ }
+
+ return len;
+}
+
+void *cmark_node_get_user_data(cmark_node *node) {
+ if (node == NULL) {
+ return NULL;
+ } else {
+ return node->user_data;
+ }
+}
+
+int cmark_node_set_user_data(cmark_node *node, void *user_data) {
+ if (node == NULL) {
+ return 0;
+ }
+ node->user_data = user_data;
+ return 1;
+}
+
+const char *cmark_node_get_literal(cmark_node *node) {
+ if (node == NULL) {
+ return NULL;
+ }
+
+ switch (node->type) {
+ case CMARK_NODE_HTML_BLOCK:
+ case CMARK_NODE_TEXT:
+ case CMARK_NODE_HTML_INLINE:
+ case CMARK_NODE_CODE:
+ case CMARK_NODE_CODE_BLOCK:
+ return node->data ? (char *)node->data : "";
+
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+int cmark_node_set_literal(cmark_node *node, const char *content) {
+ if (node == NULL) {
+ return 0;
+ }
+
+ switch (node->type) {
+ case CMARK_NODE_HTML_BLOCK:
+ case CMARK_NODE_TEXT:
+ case CMARK_NODE_HTML_INLINE:
+ case CMARK_NODE_CODE:
+ case CMARK_NODE_CODE_BLOCK:
+ node->len = cmark_set_cstr(node->mem, &node->data, content);
+ return 1;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+int cmark_node_get_heading_level(cmark_node *node) {
+ if (node == NULL) {
+ return 0;
+ }
+
+ switch (node->type) {
+ case CMARK_NODE_HEADING:
+ return node->as.heading.level;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+int cmark_node_set_heading_level(cmark_node *node, int level) {
+ if (node == NULL || level < 1 || level > 6) {
+ return 0;
+ }
+
+ switch (node->type) {
+ case CMARK_NODE_HEADING:
+ node->as.heading.level = level;
+ return 1;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+cmark_list_type cmark_node_get_list_type(cmark_node *node) {
+ if (node == NULL) {
+ return CMARK_NO_LIST;
+ }
+
+ if (node->type == CMARK_NODE_LIST) {
+ return (cmark_list_type)node->as.list.list_type;
+ } else {
+ return CMARK_NO_LIST;
+ }
+}
+
+int cmark_node_set_list_type(cmark_node *node, cmark_list_type type) {
+ if (!(type == CMARK_BULLET_LIST || type == CMARK_ORDERED_LIST)) {
+ return 0;
+ }
+
+ if (node == NULL) {
+ return 0;
+ }
+
+ if (node->type == CMARK_NODE_LIST) {
+ node->as.list.list_type = (unsigned char)type;
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+cmark_delim_type cmark_node_get_list_delim(cmark_node *node) {
+ if (node == NULL) {
+ return CMARK_NO_DELIM;
+ }
+
+ if (node->type == CMARK_NODE_LIST) {
+ return (cmark_delim_type)node->as.list.delimiter;
+ } else {
+ return CMARK_NO_DELIM;
+ }
+}
+
+int cmark_node_set_list_delim(cmark_node *node, cmark_delim_type delim) {
+ if (!(delim == CMARK_PERIOD_DELIM || delim == CMARK_PAREN_DELIM)) {
+ return 0;
+ }
+
+ if (node == NULL) {
+ return 0;
+ }
+
+ if (node->type == CMARK_NODE_LIST) {
+ node->as.list.delimiter = (unsigned char)delim;
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+int cmark_node_get_list_start(cmark_node *node) {
+ if (node == NULL) {
+ return 0;
+ }
+
+ if (node->type == CMARK_NODE_LIST) {
+ return node->as.list.start;
+ } else {
+ return 0;
+ }
+}
+
+int cmark_node_set_list_start(cmark_node *node, int start) {
+ if (node == NULL || start < 0) {
+ return 0;
+ }
+
+ if (node->type == CMARK_NODE_LIST) {
+ node->as.list.start = start;
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+int cmark_node_get_list_tight(cmark_node *node) {
+ if (node == NULL) {
+ return 0;
+ }
+
+ if (node->type == CMARK_NODE_LIST) {
+ return node->as.list.tight;
+ } else {
+ return 0;
+ }
+}
+
+int cmark_node_set_list_tight(cmark_node *node, int tight) {
+ if (node == NULL) {
+ return 0;
+ }
+
+ if (node->type == CMARK_NODE_LIST) {
+ node->as.list.tight = tight == 1;
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+const char *cmark_node_get_fence_info(cmark_node *node) {
+ if (node == NULL) {
+ return NULL;
+ }
+
+ if (node->type == CMARK_NODE_CODE_BLOCK) {
+ return node->as.code.info ? (char *)node->as.code.info : "";
+ } else {
+ return NULL;
+ }
+}
+
+int cmark_node_set_fence_info(cmark_node *node, const char *info) {
+ if (node == NULL) {
+ return 0;
+ }
+
+ if (node->type == CMARK_NODE_CODE_BLOCK) {
+ cmark_set_cstr(node->mem, &node->as.code.info, info);
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+const char *cmark_node_get_url(cmark_node *node) {
+ if (node == NULL) {
+ return NULL;
+ }
+
+ switch (node->type) {
+ case CMARK_NODE_LINK:
+ case CMARK_NODE_IMAGE:
+ return node->as.link.url ? (char *)node->as.link.url : "";
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+int cmark_node_set_url(cmark_node *node, const char *url) {
+ if (node == NULL) {
+ return 0;
+ }
+
+ switch (node->type) {
+ case CMARK_NODE_LINK:
+ case CMARK_NODE_IMAGE:
+ cmark_set_cstr(node->mem, &node->as.link.url, url);
+ return 1;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+const char *cmark_node_get_title(cmark_node *node) {
+ if (node == NULL) {
+ return NULL;
+ }
+
+ switch (node->type) {
+ case CMARK_NODE_LINK:
+ case CMARK_NODE_IMAGE:
+ return node->as.link.title ? (char *)node->as.link.title : "";
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+int cmark_node_set_title(cmark_node *node, const char *title) {
+ if (node == NULL) {
+ return 0;
+ }
+
+ switch (node->type) {
+ case CMARK_NODE_LINK:
+ case CMARK_NODE_IMAGE:
+ cmark_set_cstr(node->mem, &node->as.link.title, title);
+ return 1;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+const char *cmark_node_get_on_enter(cmark_node *node) {
+ if (node == NULL) {
+ return NULL;
+ }
+
+ switch (node->type) {
+ case CMARK_NODE_CUSTOM_INLINE:
+ case CMARK_NODE_CUSTOM_BLOCK:
+ return node->as.custom.on_enter ? (char *)node->as.custom.on_enter : "";
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+int cmark_node_set_on_enter(cmark_node *node, const char *on_enter) {
+ if (node == NULL) {
+ return 0;
+ }
+
+ switch (node->type) {
+ case CMARK_NODE_CUSTOM_INLINE:
+ case CMARK_NODE_CUSTOM_BLOCK:
+ cmark_set_cstr(node->mem, &node->as.custom.on_enter, on_enter);
+ return 1;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+const char *cmark_node_get_on_exit(cmark_node *node) {
+ if (node == NULL) {
+ return NULL;
+ }
+
+ switch (node->type) {
+ case CMARK_NODE_CUSTOM_INLINE:
+ case CMARK_NODE_CUSTOM_BLOCK:
+ return node->as.custom.on_exit ? (char *)node->as.custom.on_exit : "";
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+int cmark_node_set_on_exit(cmark_node *node, const char *on_exit) {
+ if (node == NULL) {
+ return 0;
+ }
+
+ switch (node->type) {
+ case CMARK_NODE_CUSTOM_INLINE:
+ case CMARK_NODE_CUSTOM_BLOCK:
+ cmark_set_cstr(node->mem, &node->as.custom.on_exit, on_exit);
+ return 1;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+int cmark_node_get_start_line(cmark_node *node) {
+ if (node == NULL) {
+ return 0;
+ }
+ return node->start_line;
+}
+
+int cmark_node_get_start_column(cmark_node *node) {
+ if (node == NULL) {
+ return 0;
+ }
+ return node->start_column;
+}
+
+int cmark_node_get_end_line(cmark_node *node) {
+ if (node == NULL) {
+ return 0;
+ }
+ return node->end_line;
+}
+
+int cmark_node_get_end_column(cmark_node *node) {
+ if (node == NULL) {
+ return 0;
+ }
+ return node->end_column;
+}
+
+// Unlink a node without adjusting its next, prev, and parent pointers.
+static void S_node_unlink(cmark_node *node) {
+ if (node == NULL) {
+ return;
+ }
+
+ if (node->prev) {
+ node->prev->next = node->next;
+ }
+ if (node->next) {
+ node->next->prev = node->prev;
+ }
+
+ // Adjust first_child and last_child of parent.
+ cmark_node *parent = node->parent;
+ if (parent) {
+ if (parent->first_child == node) {
+ parent->first_child = node->next;
+ }
+ if (parent->last_child == node) {
+ parent->last_child = node->prev;
+ }
+ }
+}
+
+void cmark_node_unlink(cmark_node *node) {
+ S_node_unlink(node);
+
+ node->next = NULL;
+ node->prev = NULL;
+ node->parent = NULL;
+}
+
+int cmark_node_insert_before(cmark_node *node, cmark_node *sibling) {
+ if (node == NULL || sibling == NULL) {
+ return 0;
+ }
+
+ if (!node->parent || !S_can_contain(node->parent, sibling)) {
+ return 0;
+ }
+
+ S_node_unlink(sibling);
+
+ cmark_node *old_prev = node->prev;
+
+ // Insert 'sibling' between 'old_prev' and 'node'.
+ if (old_prev) {
+ old_prev->next = sibling;
+ }
+ sibling->prev = old_prev;
+ sibling->next = node;
+ node->prev = sibling;
+
+ // Set new parent.
+ cmark_node *parent = node->parent;
+ sibling->parent = parent;
+
+ // Adjust first_child of parent if inserted as first child.
+ if (parent && !old_prev) {
+ parent->first_child = sibling;
+ }
+
+ return 1;
+}
+
+int cmark_node_insert_after(cmark_node *node, cmark_node *sibling) {
+ if (node == NULL || sibling == NULL) {
+ return 0;
+ }
+
+ if (!node->parent || !S_can_contain(node->parent, sibling)) {
+ return 0;
+ }
+
+ S_node_unlink(sibling);
+
+ cmark_node *old_next = node->next;
+
+ // Insert 'sibling' between 'node' and 'old_next'.
+ if (old_next) {
+ old_next->prev = sibling;
+ }
+ sibling->next = old_next;
+ sibling->prev = node;
+ node->next = sibling;
+
+ // Set new parent.
+ cmark_node *parent = node->parent;
+ sibling->parent = parent;
+
+ // Adjust last_child of parent if inserted as last child.
+ if (parent && !old_next) {
+ parent->last_child = sibling;
+ }
+
+ return 1;
+}
+
+int cmark_node_replace(cmark_node *oldnode, cmark_node *newnode) {
+ if (!cmark_node_insert_before(oldnode, newnode)) {
+ return 0;
+ }
+ cmark_node_unlink(oldnode);
+ return 1;
+}
+
+int cmark_node_prepend_child(cmark_node *node, cmark_node *child) {
+ if (!S_can_contain(node, child)) {
+ return 0;
+ }
+
+ S_node_unlink(child);
+
+ cmark_node *old_first_child = node->first_child;
+
+ child->next = old_first_child;
+ child->prev = NULL;
+ child->parent = node;
+ node->first_child = child;
+
+ if (old_first_child) {
+ old_first_child->prev = child;
+ } else {
+ // Also set last_child if node previously had no children.
+ node->last_child = child;
+ }
+
+ return 1;
+}
+
+int cmark_node_append_child(cmark_node *node, cmark_node *child) {
+ if (!S_can_contain(node, child)) {
+ return 0;
+ }
+
+ S_node_unlink(child);
+
+ cmark_node *old_last_child = node->last_child;
+
+ child->next = NULL;
+ child->prev = old_last_child;
+ child->parent = node;
+ node->last_child = child;
+
+ if (old_last_child) {
+ old_last_child->next = child;
+ } else {
+ // Also set first_child if node previously had no children.
+ node->first_child = child;
+ }
+
+ return 1;
+}
+
+static void S_print_error(FILE *out, cmark_node *node, const char *elem) {
+ if (out == NULL) {
+ return;
+ }
+ fprintf(out, "Invalid '%s' in node type %s at %d:%d\n", elem,
+ cmark_node_get_type_string(node), node->start_line,
+ node->start_column);
+}
+
+int cmark_node_check(cmark_node *node, FILE *out) {
+ cmark_node *cur;
+ int errors = 0;
+
+ if (!node) {
+ return 0;
+ }
+
+ cur = node;
+ for (;;) {
+ if (cur->first_child) {
+ if (cur->first_child->prev != NULL) {
+ S_print_error(out, cur->first_child, "prev");
+ cur->first_child->prev = NULL;
+ ++errors;
+ }
+ if (cur->first_child->parent != cur) {
+ S_print_error(out, cur->first_child, "parent");
+ cur->first_child->parent = cur;
+ ++errors;
+ }
+ cur = cur->first_child;
+ continue;
+ }
+
+ next_sibling:
+ if (cur == node) {
+ break;
+ }
+ if (cur->next) {
+ if (cur->next->prev != cur) {
+ S_print_error(out, cur->next, "prev");
+ cur->next->prev = cur;
+ ++errors;
+ }
+ if (cur->next->parent != cur->parent) {
+ S_print_error(out, cur->next, "parent");
+ cur->next->parent = cur->parent;
+ ++errors;
+ }
+ cur = cur->next;
+ continue;
+ }
+
+ if (cur->parent->last_child != cur) {
+ S_print_error(out, cur->parent, "last_child");
+ cur->parent->last_child = cur;
+ ++errors;
+ }
+ cur = cur->parent;
+ goto next_sibling;
+ }
+
+ return errors;
+}
diff --git a/cmark/src/node.h b/cmark/src/node.h
new file mode 100644
index 0000000000..3d9ddcf54b
--- /dev/null
+++ b/cmark/src/node.h
@@ -0,0 +1,93 @@
+#ifndef CMARK_NODE_H
+#define CMARK_NODE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include "cmark.h"
+#include "buffer.h"
+
+typedef struct {
+ int marker_offset;
+ int padding;
+ int start;
+ unsigned char list_type;
+ unsigned char delimiter;
+ unsigned char bullet_char;
+ bool tight;
+} cmark_list;
+
+typedef struct {
+ unsigned char *info;
+ uint8_t fence_length;
+ uint8_t fence_offset;
+ unsigned char fence_char;
+ int8_t fenced;
+} cmark_code;
+
+typedef struct {
+ int internal_offset;
+ int8_t level;
+ bool setext;
+} cmark_heading;
+
+typedef struct {
+ unsigned char *url;
+ unsigned char *title;
+} cmark_link;
+
+typedef struct {
+ unsigned char *on_enter;
+ unsigned char *on_exit;
+} cmark_custom;
+
+enum cmark_node__internal_flags {
+ CMARK_NODE__OPEN = (1 << 0),
+ CMARK_NODE__LAST_LINE_BLANK = (1 << 1),
+ CMARK_NODE__LAST_LINE_CHECKED = (1 << 2),
+ CMARK_NODE__LIST_LAST_LINE_BLANK = (1 << 3),
+};
+
+struct cmark_node {
+ cmark_mem *mem;
+
+ struct cmark_node *next;
+ struct cmark_node *prev;
+ struct cmark_node *parent;
+ struct cmark_node *first_child;
+ struct cmark_node *last_child;
+
+ void *user_data;
+
+ unsigned char *data;
+ bufsize_t len;
+
+ int start_line;
+ int start_column;
+ int end_line;
+ int end_column;
+ uint16_t type;
+ uint16_t flags;
+
+ union {
+ cmark_list list;
+ cmark_code code;
+ cmark_heading heading;
+ cmark_link link;
+ cmark_custom custom;
+ int html_block_type;
+ } as;
+};
+
+CMARK_EXPORT int cmark_node_check(cmark_node *node, FILE *out);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/cmark/src/parser.h b/cmark/src/parser.h
new file mode 100644
index 0000000000..f546ace11b
--- /dev/null
+++ b/cmark/src/parser.h
@@ -0,0 +1,42 @@
+#ifndef CMARK_AST_H
+#define CMARK_AST_H
+
+#include <stdio.h>
+#include "references.h"
+#include "node.h"
+#include "buffer.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MAX_LINK_LABEL_LENGTH 1000
+
+struct cmark_parser {
+ struct cmark_mem *mem;
+ struct cmark_reference_map *refmap;
+ struct cmark_node *root;
+ struct cmark_node *current;
+ int line_number;
+ bufsize_t offset;
+ bufsize_t column;
+ bufsize_t first_nonspace;
+ bufsize_t first_nonspace_column;
+ bufsize_t thematic_break_kill_pos;
+ int indent;
+ bool blank;
+ bool partially_consumed_tab;
+ cmark_strbuf curline;
+ bufsize_t last_line_length;
+ cmark_strbuf linebuf;
+ cmark_strbuf content;
+ int options;
+ bool last_buffer_ended_with_cr;
+ unsigned int total_size;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/cmark/src/references.c b/cmark/src/references.c
new file mode 100644
index 0000000000..96d793b708
--- /dev/null
+++ b/cmark/src/references.c
@@ -0,0 +1,171 @@
+#include "cmark.h"
+#include "utf8.h"
+#include "parser.h"
+#include "references.h"
+#include "inlines.h"
+#include "chunk.h"
+
+static void reference_free(cmark_reference_map *map, cmark_reference *ref) {
+ cmark_mem *mem = map->mem;
+ if (ref != NULL) {
+ mem->free(ref->label);
+ mem->free(ref->url);
+ mem->free(ref->title);
+ mem->free(ref);
+ }
+}
+
+// normalize reference: collapse internal whitespace to single space,
+// remove leading/trailing whitespace, case fold
+// Return NULL if the reference name is actually empty (i.e. composed
+// solely from whitespace)
+static unsigned char *normalize_reference(cmark_mem *mem, cmark_chunk *ref) {
+ cmark_strbuf normalized = CMARK_BUF_INIT(mem);
+ unsigned char *result;
+
+ if (ref == NULL)
+ return NULL;
+
+ if (ref->len == 0)
+ return NULL;
+
+ cmark_utf8proc_case_fold(&normalized, ref->data, ref->len);
+ cmark_strbuf_trim(&normalized);
+ cmark_strbuf_normalize_whitespace(&normalized);
+
+ result = cmark_strbuf_detach(&normalized);
+ assert(result);
+
+ if (result[0] == '\0') {
+ mem->free(result);
+ return NULL;
+ }
+
+ return result;
+}
+
+void cmark_reference_create(cmark_reference_map *map, cmark_chunk *label,
+ cmark_chunk *url, cmark_chunk *title) {
+ cmark_reference *ref;
+ unsigned char *reflabel = normalize_reference(map->mem, label);
+
+ /* empty reference name, or composed from only whitespace */
+ if (reflabel == NULL)
+ return;
+
+ assert(map->sorted == NULL);
+
+ ref = (cmark_reference *)map->mem->calloc(1, sizeof(*ref));
+ ref->label = reflabel;
+ ref->url = cmark_clean_url(map->mem, url);
+ ref->title = cmark_clean_title(map->mem, title);
+ ref->age = map->size;
+ ref->next = map->refs;
+
+ if (ref->url != NULL)
+ ref->size += (int)strlen((char*)ref->url);
+ if (ref->title != NULL)
+ ref->size += (int)strlen((char*)ref->title);
+
+ map->refs = ref;
+ map->size++;
+}
+
+static int
+labelcmp(const unsigned char *a, const unsigned char *b) {
+ return strcmp((const char *)a, (const char *)b);
+}
+
+static int
+refcmp(const void *p1, const void *p2) {
+ cmark_reference *r1 = *(cmark_reference **)p1;
+ cmark_reference *r2 = *(cmark_reference **)p2;
+ int res = labelcmp(r1->label, r2->label);
+ return res ? res : ((int)r1->age - (int)r2->age);
+}
+
+static int
+refsearch(const void *label, const void *p2) {
+ cmark_reference *ref = *(cmark_reference **)p2;
+ return labelcmp((const unsigned char *)label, ref->label);
+}
+
+static void sort_references(cmark_reference_map *map) {
+ unsigned int i = 0, last = 0, size = map->size;
+ cmark_reference *r = map->refs, **sorted = NULL;
+
+ sorted = (cmark_reference **)map->mem->calloc(size, sizeof(cmark_reference *));
+ while (r) {
+ sorted[i++] = r;
+ r = r->next;
+ }
+
+ qsort(sorted, size, sizeof(cmark_reference *), refcmp);
+
+ for (i = 1; i < size; i++) {
+ if (labelcmp(sorted[i]->label, sorted[last]->label) != 0)
+ sorted[++last] = sorted[i];
+ }
+ map->sorted = sorted;
+ map->size = last + 1;
+}
+
+// Returns reference if refmap contains a reference with matching
+// label, otherwise NULL.
+cmark_reference *cmark_reference_lookup(cmark_reference_map *map,
+ cmark_chunk *label) {
+ cmark_reference **ref = NULL;
+ cmark_reference *r = NULL;
+ unsigned char *norm;
+
+ if (label->len < 1 || label->len > MAX_LINK_LABEL_LENGTH)
+ return NULL;
+
+ if (map == NULL || !map->size)
+ return NULL;
+
+ norm = normalize_reference(map->mem, label);
+ if (norm == NULL)
+ return NULL;
+
+ if (!map->sorted)
+ sort_references(map);
+
+ ref = (cmark_reference **)bsearch(norm, map->sorted, map->size, sizeof(cmark_reference *),
+ refsearch);
+ map->mem->free(norm);
+
+ if (ref != NULL) {
+ r = ref[0];
+ /* Check for expansion limit */
+ if (map->max_ref_size && r->size > map->max_ref_size - map->ref_size)
+ return NULL;
+ map->ref_size += r->size;
+ }
+
+ return r;
+}
+
+void cmark_reference_map_free(cmark_reference_map *map) {
+ cmark_reference *ref;
+
+ if (map == NULL)
+ return;
+
+ ref = map->refs;
+ while (ref) {
+ cmark_reference *next = ref->next;
+ reference_free(map, ref);
+ ref = next;
+ }
+
+ map->mem->free(map->sorted);
+ map->mem->free(map);
+}
+
+cmark_reference_map *cmark_reference_map_new(cmark_mem *mem) {
+ cmark_reference_map *map =
+ (cmark_reference_map *)mem->calloc(1, sizeof(cmark_reference_map));
+ map->mem = mem;
+ return map;
+}
diff --git a/cmark/src/references.h b/cmark/src/references.h
new file mode 100644
index 0000000000..27f15de2a4
--- /dev/null
+++ b/cmark/src/references.h
@@ -0,0 +1,43 @@
+#ifndef CMARK_REFERENCES_H
+#define CMARK_REFERENCES_H
+
+#include "chunk.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct cmark_reference {
+ struct cmark_reference *next;
+ unsigned char *label;
+ unsigned char *url;
+ unsigned char *title;
+ unsigned int age;
+ unsigned int size;
+};
+
+typedef struct cmark_reference cmark_reference;
+
+struct cmark_reference_map {
+ cmark_mem *mem;
+ cmark_reference *refs;
+ cmark_reference **sorted;
+ unsigned int size;
+ unsigned int ref_size;
+ unsigned int max_ref_size;
+};
+
+typedef struct cmark_reference_map cmark_reference_map;
+
+cmark_reference_map *cmark_reference_map_new(cmark_mem *mem);
+void cmark_reference_map_free(cmark_reference_map *map);
+cmark_reference *cmark_reference_lookup(cmark_reference_map *map,
+ cmark_chunk *label);
+void cmark_reference_create(cmark_reference_map *map, cmark_chunk *label,
+ cmark_chunk *url, cmark_chunk *title);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/cmark/src/render.c b/cmark/src/render.c
new file mode 100644
index 0000000000..0404deba15
--- /dev/null
+++ b/cmark/src/render.c
@@ -0,0 +1,195 @@
+#include <stdlib.h>
+#include "buffer.h"
+#include "cmark.h"
+#include "utf8.h"
+#include "render.h"
+#include "node.h"
+#include "cmark_ctype.h"
+
+static inline void S_cr(cmark_renderer *renderer) {
+ if (renderer->need_cr < 1) {
+ renderer->need_cr = 1;
+ }
+}
+
+static inline void S_blankline(cmark_renderer *renderer) {
+ if (renderer->need_cr < 2) {
+ renderer->need_cr = 2;
+ }
+}
+
+static void S_out(cmark_renderer *renderer, const char *source, bool wrap,
+ cmark_escaping escape) {
+ int length = (int)strlen(source);
+ unsigned char nextc;
+ int32_t c;
+ int i = 0;
+ int last_nonspace;
+ int len;
+ int k = renderer->buffer->size - 1;
+
+ wrap = wrap && !renderer->no_linebreaks;
+
+ if (renderer->in_tight_list_item && renderer->need_cr > 1) {
+ renderer->need_cr = 1;
+ }
+ while (renderer->need_cr) {
+ if (k < 0 || renderer->buffer->ptr[k] == '\n') {
+ k -= 1;
+ } else {
+ cmark_strbuf_putc(renderer->buffer, '\n');
+ if (renderer->need_cr > 1) {
+ cmark_strbuf_put(renderer->buffer, renderer->prefix->ptr,
+ renderer->prefix->size);
+ }
+ }
+ renderer->column = 0;
+ renderer->last_breakable = 0;
+ renderer->begin_line = true;
+ renderer->begin_content = true;
+ renderer->need_cr -= 1;
+ }
+
+ while (i < length) {
+ if (renderer->begin_line) {
+ cmark_strbuf_put(renderer->buffer, renderer->prefix->ptr,
+ renderer->prefix->size);
+ // note: this assumes prefix is ascii:
+ renderer->column = renderer->prefix->size;
+ }
+
+ len = cmark_utf8proc_iterate((const uint8_t *)source + i, length - i, &c);
+ if (len == -1) { // error condition
+ return; // return without rendering rest of string
+ }
+ nextc = source[i + len];
+ if (c == 32 && wrap) {
+ if (!renderer->begin_line) {
+ last_nonspace = renderer->buffer->size;
+ cmark_strbuf_putc(renderer->buffer, ' ');
+ renderer->column += 1;
+ renderer->begin_line = false;
+ renderer->begin_content = false;
+ // skip following spaces
+ while (source[i + 1] == ' ') {
+ i++;
+ }
+ // We don't allow breaks that make a digit the first character
+ // because this causes problems with commonmark output.
+ if (!cmark_isdigit(source[i + 1])) {
+ renderer->last_breakable = last_nonspace;
+ }
+ }
+
+ } else if (escape == LITERAL) {
+ if (c == 10) {
+ cmark_strbuf_putc(renderer->buffer, '\n');
+ renderer->column = 0;
+ renderer->begin_line = true;
+ renderer->begin_content = true;
+ renderer->last_breakable = 0;
+ } else {
+ cmark_render_code_point(renderer, c);
+ renderer->begin_line = false;
+ // we don't set 'begin_content' to false til we've
+ // finished parsing a digit. Reason: in commonmark
+ // we need to escape a potential list marker after
+ // a digit:
+ renderer->begin_content =
+ renderer->begin_content && cmark_isdigit(c) == 1;
+ }
+ } else {
+ (renderer->outc)(renderer, escape, c, nextc);
+ renderer->begin_line = false;
+ renderer->begin_content =
+ renderer->begin_content && cmark_isdigit(c) == 1;
+ }
+
+ // If adding the character went beyond width, look for an
+ // earlier place where the line could be broken:
+ if (renderer->width > 0 && renderer->column > renderer->width &&
+ !renderer->begin_line && renderer->last_breakable > 0) {
+
+ // copy from last_breakable to remainder
+ unsigned char *src = renderer->buffer->ptr +
+ renderer->last_breakable + 1;
+ bufsize_t remainder_len = renderer->buffer->size -
+ renderer->last_breakable - 1;
+ unsigned char *remainder =
+ (unsigned char *)renderer->mem->realloc(NULL, remainder_len);
+ memcpy(remainder, src, remainder_len);
+ // truncate at last_breakable
+ cmark_strbuf_truncate(renderer->buffer, renderer->last_breakable);
+ // add newline, prefix, and remainder
+ cmark_strbuf_putc(renderer->buffer, '\n');
+ cmark_strbuf_put(renderer->buffer, renderer->prefix->ptr,
+ renderer->prefix->size);
+ cmark_strbuf_put(renderer->buffer, remainder, remainder_len);
+ renderer->column = renderer->prefix->size + remainder_len;
+ renderer->mem->free(remainder);
+ renderer->last_breakable = 0;
+ renderer->begin_line = false;
+ renderer->begin_content = false;
+ }
+
+ i += len;
+ }
+}
+
+// Assumes no newlines, assumes ascii content:
+void cmark_render_ascii(cmark_renderer *renderer, const char *s) {
+ int origsize = renderer->buffer->size;
+ cmark_strbuf_puts(renderer->buffer, s);
+ renderer->column += renderer->buffer->size - origsize;
+}
+
+void cmark_render_code_point(cmark_renderer *renderer, uint32_t c) {
+ cmark_utf8proc_encode_char(c, renderer->buffer);
+ renderer->column += 1;
+}
+
+char *cmark_render(cmark_node *root, int options, int width,
+ void (*outc)(cmark_renderer *, cmark_escaping, int32_t,
+ unsigned char),
+ int (*render_node)(cmark_renderer *renderer,
+ cmark_node *node,
+ cmark_event_type ev_type, int options)) {
+ cmark_mem *mem = root->mem;
+ cmark_strbuf pref = CMARK_BUF_INIT(mem);
+ cmark_strbuf buf = CMARK_BUF_INIT(mem);
+ cmark_node *cur;
+ cmark_event_type ev_type;
+ char *result;
+ cmark_iter *iter = cmark_iter_new(root);
+
+ cmark_renderer renderer = {options,
+ mem, &buf, &pref, 0, width,
+ 0, 0, true, true, false,
+ false, NULL,
+ outc, S_cr, S_blankline, S_out};
+
+ while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
+ cur = cmark_iter_get_node(iter);
+ if (!render_node(&renderer, cur, ev_type, options)) {
+ // a false value causes us to skip processing
+ // the node's contents. this is used for
+ // autolinks.
+ cmark_iter_reset(iter, cur, CMARK_EVENT_EXIT);
+ }
+ }
+
+ // If the root node is a block type (i.e. not inline), ensure there's a final newline:
+ if (cmark_node_is_block(root)) {
+ if (renderer.buffer->size == 0 || renderer.buffer->ptr[renderer.buffer->size - 1] != '\n') {
+ cmark_strbuf_putc(renderer.buffer, '\n');
+ }
+ }
+
+ result = (char *)cmark_strbuf_detach(renderer.buffer);
+
+ cmark_iter_free(iter);
+ cmark_strbuf_free(renderer.prefix);
+ cmark_strbuf_free(renderer.buffer);
+
+ return result;
+}
diff --git a/cmark/src/render.h b/cmark/src/render.h
new file mode 100644
index 0000000000..6f71acbd4e
--- /dev/null
+++ b/cmark/src/render.h
@@ -0,0 +1,57 @@
+#ifndef CMARK_RENDER_H
+#define CMARK_RENDER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include "buffer.h"
+
+typedef enum { LITERAL, NORMAL, TITLE, URL } cmark_escaping;
+
+struct block_number {
+ int number;
+ struct block_number *parent;
+};
+
+struct cmark_renderer {
+ int options;
+ cmark_mem *mem;
+ cmark_strbuf *buffer;
+ cmark_strbuf *prefix;
+ int column;
+ int width;
+ int need_cr;
+ bufsize_t last_breakable;
+ bool begin_line;
+ bool begin_content;
+ bool no_linebreaks;
+ bool in_tight_list_item;
+ struct block_number *block_number_in_list_item;
+ void (*outc)(struct cmark_renderer *, cmark_escaping, int32_t, unsigned char);
+ void (*cr)(struct cmark_renderer *);
+ void (*blankline)(struct cmark_renderer *);
+ void (*out)(struct cmark_renderer *, const char *, bool, cmark_escaping);
+};
+
+typedef struct cmark_renderer cmark_renderer;
+
+void cmark_render_ascii(cmark_renderer *renderer, const char *s);
+
+void cmark_render_code_point(cmark_renderer *renderer, uint32_t c);
+
+char *cmark_render(cmark_node *root, int options, int width,
+ void (*outc)(cmark_renderer *, cmark_escaping, int32_t,
+ unsigned char),
+ int (*render_node)(cmark_renderer *renderer,
+ cmark_node *node,
+ cmark_event_type ev_type, int options));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/cmark/src/scanners.c b/cmark/src/scanners.c
new file mode 100644
index 0000000000..7338c75b76
--- /dev/null
+++ b/cmark/src/scanners.c
@@ -0,0 +1,9415 @@
+/* Generated by re2c 3.0 */
+#include <stdlib.h>
+#include "chunk.h"
+#include "scanners.h"
+
+bufsize_t _scan_at(bufsize_t (*scanner)(const unsigned char *), cmark_chunk *c,
+ bufsize_t offset) {
+ bufsize_t res;
+ unsigned char *ptr = (unsigned char *)c->data;
+
+ if (ptr == NULL || offset > c->len) {
+ return 0;
+ } else {
+ unsigned char lim = ptr[c->len];
+
+ ptr[c->len] = '\0';
+ res = scanner(ptr + offset);
+ ptr[c->len] = lim;
+ }
+
+ return res;
+}
+
+// Try to match a scheme including colon.
+bufsize_t _scan_scheme(const unsigned char *p) {
+ const unsigned char *marker = NULL;
+ const unsigned char *start = p;
+
+ {
+ unsigned char yych;
+ yych = *p;
+ if (yych <= '@')
+ goto yy1;
+ if (yych <= 'Z')
+ goto yy3;
+ if (yych <= '`')
+ goto yy1;
+ if (yych <= 'z')
+ goto yy3;
+ yy1:
+ ++p;
+ yy2 : { return 0; }
+ yy3:
+ yych = *(marker = ++p);
+ if (yych <= '/') {
+ if (yych <= '+') {
+ if (yych <= '*')
+ goto yy2;
+ } else {
+ if (yych <= ',')
+ goto yy2;
+ if (yych >= '/')
+ goto yy2;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '9')
+ goto yy4;
+ if (yych <= '@')
+ goto yy2;
+ } else {
+ if (yych <= '`')
+ goto yy2;
+ if (yych >= '{')
+ goto yy2;
+ }
+ }
+ yy4:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych == '+')
+ goto yy6;
+ } else {
+ if (yych != '/')
+ goto yy6;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy7;
+ if (yych >= 'A')
+ goto yy6;
+ } else {
+ if (yych <= '`')
+ goto yy5;
+ if (yych <= 'z')
+ goto yy6;
+ }
+ }
+ yy5:
+ p = marker;
+ goto yy2;
+ yy6:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych == '+')
+ goto yy8;
+ goto yy5;
+ } else {
+ if (yych == '/')
+ goto yy5;
+ goto yy8;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy7;
+ if (yych <= '@')
+ goto yy5;
+ goto yy8;
+ } else {
+ if (yych <= '`')
+ goto yy5;
+ if (yych <= 'z')
+ goto yy8;
+ goto yy5;
+ }
+ }
+ yy7:
+ ++p;
+ { return (bufsize_t)(p - start); }
+ yy8:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy5;
+ } else {
+ if (yych == '/')
+ goto yy5;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy7;
+ if (yych <= '@')
+ goto yy5;
+ } else {
+ if (yych <= '`')
+ goto yy5;
+ if (yych >= '{')
+ goto yy5;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy5;
+ } else {
+ if (yych == '/')
+ goto yy5;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy7;
+ if (yych <= '@')
+ goto yy5;
+ } else {
+ if (yych <= '`')
+ goto yy5;
+ if (yych >= '{')
+ goto yy5;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy5;
+ } else {
+ if (yych == '/')
+ goto yy5;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy7;
+ if (yych <= '@')
+ goto yy5;
+ } else {
+ if (yych <= '`')
+ goto yy5;
+ if (yych >= '{')
+ goto yy5;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy5;
+ } else {
+ if (yych == '/')
+ goto yy5;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy7;
+ if (yych <= '@')
+ goto yy5;
+ } else {
+ if (yych <= '`')
+ goto yy5;
+ if (yych >= '{')
+ goto yy5;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy5;
+ } else {
+ if (yych == '/')
+ goto yy5;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy7;
+ if (yych <= '@')
+ goto yy5;
+ } else {
+ if (yych <= '`')
+ goto yy5;
+ if (yych >= '{')
+ goto yy5;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy5;
+ } else {
+ if (yych == '/')
+ goto yy5;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy7;
+ if (yych <= '@')
+ goto yy5;
+ } else {
+ if (yych <= '`')
+ goto yy5;
+ if (yych >= '{')
+ goto yy5;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy5;
+ } else {
+ if (yych == '/')
+ goto yy5;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy7;
+ if (yych <= '@')
+ goto yy5;
+ } else {
+ if (yych <= '`')
+ goto yy5;
+ if (yych >= '{')
+ goto yy5;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy5;
+ } else {
+ if (yych == '/')
+ goto yy5;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy7;
+ if (yych <= '@')
+ goto yy5;
+ } else {
+ if (yych <= '`')
+ goto yy5;
+ if (yych >= '{')
+ goto yy5;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy5;
+ } else {
+ if (yych == '/')
+ goto yy5;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy7;
+ if (yych <= '@')
+ goto yy5;
+ } else {
+ if (yych <= '`')
+ goto yy5;
+ if (yych >= '{')
+ goto yy5;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy5;
+ } else {
+ if (yych == '/')
+ goto yy5;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy7;
+ if (yych <= '@')
+ goto yy5;
+ } else {
+ if (yych <= '`')
+ goto yy5;
+ if (yych >= '{')
+ goto yy5;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy5;
+ } else {
+ if (yych == '/')
+ goto yy5;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy7;
+ if (yych <= '@')
+ goto yy5;
+ } else {
+ if (yych <= '`')
+ goto yy5;
+ if (yych >= '{')
+ goto yy5;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy5;
+ } else {
+ if (yych == '/')
+ goto yy5;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy7;
+ if (yych <= '@')
+ goto yy5;
+ } else {
+ if (yych <= '`')
+ goto yy5;
+ if (yych >= '{')
+ goto yy5;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy5;
+ } else {
+ if (yych == '/')
+ goto yy5;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy7;
+ if (yych <= '@')
+ goto yy5;
+ } else {
+ if (yych <= '`')
+ goto yy5;
+ if (yych >= '{')
+ goto yy5;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy5;
+ } else {
+ if (yych == '/')
+ goto yy5;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy7;
+ if (yych <= '@')
+ goto yy5;
+ } else {
+ if (yych <= '`')
+ goto yy5;
+ if (yych >= '{')
+ goto yy5;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy5;
+ } else {
+ if (yych == '/')
+ goto yy5;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy7;
+ if (yych <= '@')
+ goto yy5;
+ } else {
+ if (yych <= '`')
+ goto yy5;
+ if (yych >= '{')
+ goto yy5;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy5;
+ } else {
+ if (yych == '/')
+ goto yy5;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy7;
+ if (yych <= '@')
+ goto yy5;
+ } else {
+ if (yych <= '`')
+ goto yy5;
+ if (yych >= '{')
+ goto yy5;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy5;
+ } else {
+ if (yych == '/')
+ goto yy5;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy7;
+ if (yych <= '@')
+ goto yy5;
+ } else {
+ if (yych <= '`')
+ goto yy5;
+ if (yych >= '{')
+ goto yy5;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy5;
+ } else {
+ if (yych == '/')
+ goto yy5;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy7;
+ if (yych <= '@')
+ goto yy5;
+ } else {
+ if (yych <= '`')
+ goto yy5;
+ if (yych >= '{')
+ goto yy5;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy5;
+ } else {
+ if (yych == '/')
+ goto yy5;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy7;
+ if (yych <= '@')
+ goto yy5;
+ } else {
+ if (yych <= '`')
+ goto yy5;
+ if (yych >= '{')
+ goto yy5;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy5;
+ } else {
+ if (yych == '/')
+ goto yy5;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy7;
+ if (yych <= '@')
+ goto yy5;
+ } else {
+ if (yych <= '`')
+ goto yy5;
+ if (yych >= '{')
+ goto yy5;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy5;
+ } else {
+ if (yych == '/')
+ goto yy5;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy7;
+ if (yych <= '@')
+ goto yy5;
+ } else {
+ if (yych <= '`')
+ goto yy5;
+ if (yych >= '{')
+ goto yy5;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy5;
+ } else {
+ if (yych == '/')
+ goto yy5;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy7;
+ if (yych <= '@')
+ goto yy5;
+ } else {
+ if (yych <= '`')
+ goto yy5;
+ if (yych >= '{')
+ goto yy5;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy5;
+ } else {
+ if (yych == '/')
+ goto yy5;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy7;
+ if (yych <= '@')
+ goto yy5;
+ } else {
+ if (yych <= '`')
+ goto yy5;
+ if (yych >= '{')
+ goto yy5;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy5;
+ } else {
+ if (yych == '/')
+ goto yy5;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy7;
+ if (yych <= '@')
+ goto yy5;
+ } else {
+ if (yych <= '`')
+ goto yy5;
+ if (yych >= '{')
+ goto yy5;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy5;
+ } else {
+ if (yych == '/')
+ goto yy5;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy7;
+ if (yych <= '@')
+ goto yy5;
+ } else {
+ if (yych <= '`')
+ goto yy5;
+ if (yych >= '{')
+ goto yy5;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy5;
+ } else {
+ if (yych == '/')
+ goto yy5;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy7;
+ if (yych <= '@')
+ goto yy5;
+ } else {
+ if (yych <= '`')
+ goto yy5;
+ if (yych >= '{')
+ goto yy5;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy5;
+ } else {
+ if (yych == '/')
+ goto yy5;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy7;
+ if (yych <= '@')
+ goto yy5;
+ } else {
+ if (yych <= '`')
+ goto yy5;
+ if (yych >= '{')
+ goto yy5;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy5;
+ } else {
+ if (yych == '/')
+ goto yy5;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy7;
+ if (yych <= '@')
+ goto yy5;
+ } else {
+ if (yych <= '`')
+ goto yy5;
+ if (yych >= '{')
+ goto yy5;
+ }
+ }
+ yych = *++p;
+ if (yych == ':')
+ goto yy7;
+ goto yy5;
+ }
+}
+
+// Try to match URI autolink after first <, returning number of chars matched.
+bufsize_t _scan_autolink_uri(const unsigned char *p) {
+ const unsigned char *marker = NULL;
+ const unsigned char *start = p;
+
+ {
+ unsigned char yych;
+ static const unsigned char yybm[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 0, 128, 0, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128,
+ };
+ yych = *p;
+ if (yych <= '@')
+ goto yy10;
+ if (yych <= 'Z')
+ goto yy12;
+ if (yych <= '`')
+ goto yy10;
+ if (yych <= 'z')
+ goto yy12;
+ yy10:
+ ++p;
+ yy11 : { return 0; }
+ yy12:
+ yych = *(marker = ++p);
+ if (yych <= '/') {
+ if (yych <= '+') {
+ if (yych <= '*')
+ goto yy11;
+ } else {
+ if (yych <= ',')
+ goto yy11;
+ if (yych >= '/')
+ goto yy11;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '9')
+ goto yy13;
+ if (yych <= '@')
+ goto yy11;
+ } else {
+ if (yych <= '`')
+ goto yy11;
+ if (yych >= '{')
+ goto yy11;
+ }
+ }
+ yy13:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych == '+')
+ goto yy15;
+ } else {
+ if (yych != '/')
+ goto yy15;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy16;
+ if (yych >= 'A')
+ goto yy15;
+ } else {
+ if (yych <= '`')
+ goto yy14;
+ if (yych <= 'z')
+ goto yy15;
+ }
+ }
+ yy14:
+ p = marker;
+ goto yy11;
+ yy15:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych == '+')
+ goto yy17;
+ goto yy14;
+ } else {
+ if (yych == '/')
+ goto yy14;
+ goto yy17;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy16;
+ if (yych <= '@')
+ goto yy14;
+ goto yy17;
+ } else {
+ if (yych <= '`')
+ goto yy14;
+ if (yych <= 'z')
+ goto yy17;
+ goto yy14;
+ }
+ }
+ yy16:
+ yych = *++p;
+ if (yybm[0 + yych] & 128) {
+ goto yy16;
+ }
+ if (yych <= '<')
+ goto yy14;
+ goto yy18;
+ yy17:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych == '+')
+ goto yy19;
+ goto yy14;
+ } else {
+ if (yych == '/')
+ goto yy14;
+ goto yy19;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy16;
+ if (yych <= '@')
+ goto yy14;
+ goto yy19;
+ } else {
+ if (yych <= '`')
+ goto yy14;
+ if (yych <= 'z')
+ goto yy19;
+ goto yy14;
+ }
+ }
+ yy18:
+ ++p;
+ { return (bufsize_t)(p - start); }
+ yy19:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy14;
+ } else {
+ if (yych == '/')
+ goto yy14;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy16;
+ if (yych <= '@')
+ goto yy14;
+ } else {
+ if (yych <= '`')
+ goto yy14;
+ if (yych >= '{')
+ goto yy14;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy14;
+ } else {
+ if (yych == '/')
+ goto yy14;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy16;
+ if (yych <= '@')
+ goto yy14;
+ } else {
+ if (yych <= '`')
+ goto yy14;
+ if (yych >= '{')
+ goto yy14;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy14;
+ } else {
+ if (yych == '/')
+ goto yy14;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy16;
+ if (yych <= '@')
+ goto yy14;
+ } else {
+ if (yych <= '`')
+ goto yy14;
+ if (yych >= '{')
+ goto yy14;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy14;
+ } else {
+ if (yych == '/')
+ goto yy14;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy16;
+ if (yych <= '@')
+ goto yy14;
+ } else {
+ if (yych <= '`')
+ goto yy14;
+ if (yych >= '{')
+ goto yy14;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy14;
+ } else {
+ if (yych == '/')
+ goto yy14;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy16;
+ if (yych <= '@')
+ goto yy14;
+ } else {
+ if (yych <= '`')
+ goto yy14;
+ if (yych >= '{')
+ goto yy14;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy14;
+ } else {
+ if (yych == '/')
+ goto yy14;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy16;
+ if (yych <= '@')
+ goto yy14;
+ } else {
+ if (yych <= '`')
+ goto yy14;
+ if (yych >= '{')
+ goto yy14;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy14;
+ } else {
+ if (yych == '/')
+ goto yy14;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy16;
+ if (yych <= '@')
+ goto yy14;
+ } else {
+ if (yych <= '`')
+ goto yy14;
+ if (yych >= '{')
+ goto yy14;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy14;
+ } else {
+ if (yych == '/')
+ goto yy14;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy16;
+ if (yych <= '@')
+ goto yy14;
+ } else {
+ if (yych <= '`')
+ goto yy14;
+ if (yych >= '{')
+ goto yy14;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy14;
+ } else {
+ if (yych == '/')
+ goto yy14;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy16;
+ if (yych <= '@')
+ goto yy14;
+ } else {
+ if (yych <= '`')
+ goto yy14;
+ if (yych >= '{')
+ goto yy14;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy14;
+ } else {
+ if (yych == '/')
+ goto yy14;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy16;
+ if (yych <= '@')
+ goto yy14;
+ } else {
+ if (yych <= '`')
+ goto yy14;
+ if (yych >= '{')
+ goto yy14;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy14;
+ } else {
+ if (yych == '/')
+ goto yy14;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy16;
+ if (yych <= '@')
+ goto yy14;
+ } else {
+ if (yych <= '`')
+ goto yy14;
+ if (yych >= '{')
+ goto yy14;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy14;
+ } else {
+ if (yych == '/')
+ goto yy14;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy16;
+ if (yych <= '@')
+ goto yy14;
+ } else {
+ if (yych <= '`')
+ goto yy14;
+ if (yych >= '{')
+ goto yy14;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy14;
+ } else {
+ if (yych == '/')
+ goto yy14;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy16;
+ if (yych <= '@')
+ goto yy14;
+ } else {
+ if (yych <= '`')
+ goto yy14;
+ if (yych >= '{')
+ goto yy14;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy14;
+ } else {
+ if (yych == '/')
+ goto yy14;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy16;
+ if (yych <= '@')
+ goto yy14;
+ } else {
+ if (yych <= '`')
+ goto yy14;
+ if (yych >= '{')
+ goto yy14;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy14;
+ } else {
+ if (yych == '/')
+ goto yy14;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy16;
+ if (yych <= '@')
+ goto yy14;
+ } else {
+ if (yych <= '`')
+ goto yy14;
+ if (yych >= '{')
+ goto yy14;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy14;
+ } else {
+ if (yych == '/')
+ goto yy14;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy16;
+ if (yych <= '@')
+ goto yy14;
+ } else {
+ if (yych <= '`')
+ goto yy14;
+ if (yych >= '{')
+ goto yy14;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy14;
+ } else {
+ if (yych == '/')
+ goto yy14;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy16;
+ if (yych <= '@')
+ goto yy14;
+ } else {
+ if (yych <= '`')
+ goto yy14;
+ if (yych >= '{')
+ goto yy14;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy14;
+ } else {
+ if (yych == '/')
+ goto yy14;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy16;
+ if (yych <= '@')
+ goto yy14;
+ } else {
+ if (yych <= '`')
+ goto yy14;
+ if (yych >= '{')
+ goto yy14;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy14;
+ } else {
+ if (yych == '/')
+ goto yy14;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy16;
+ if (yych <= '@')
+ goto yy14;
+ } else {
+ if (yych <= '`')
+ goto yy14;
+ if (yych >= '{')
+ goto yy14;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy14;
+ } else {
+ if (yych == '/')
+ goto yy14;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy16;
+ if (yych <= '@')
+ goto yy14;
+ } else {
+ if (yych <= '`')
+ goto yy14;
+ if (yych >= '{')
+ goto yy14;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy14;
+ } else {
+ if (yych == '/')
+ goto yy14;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy16;
+ if (yych <= '@')
+ goto yy14;
+ } else {
+ if (yych <= '`')
+ goto yy14;
+ if (yych >= '{')
+ goto yy14;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy14;
+ } else {
+ if (yych == '/')
+ goto yy14;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy16;
+ if (yych <= '@')
+ goto yy14;
+ } else {
+ if (yych <= '`')
+ goto yy14;
+ if (yych >= '{')
+ goto yy14;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy14;
+ } else {
+ if (yych == '/')
+ goto yy14;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy16;
+ if (yych <= '@')
+ goto yy14;
+ } else {
+ if (yych <= '`')
+ goto yy14;
+ if (yych >= '{')
+ goto yy14;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy14;
+ } else {
+ if (yych == '/')
+ goto yy14;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy16;
+ if (yych <= '@')
+ goto yy14;
+ } else {
+ if (yych <= '`')
+ goto yy14;
+ if (yych >= '{')
+ goto yy14;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy14;
+ } else {
+ if (yych == '/')
+ goto yy14;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy16;
+ if (yych <= '@')
+ goto yy14;
+ } else {
+ if (yych <= '`')
+ goto yy14;
+ if (yych >= '{')
+ goto yy14;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy14;
+ } else {
+ if (yych == '/')
+ goto yy14;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy16;
+ if (yych <= '@')
+ goto yy14;
+ } else {
+ if (yych <= '`')
+ goto yy14;
+ if (yych >= '{')
+ goto yy14;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych <= ',') {
+ if (yych != '+')
+ goto yy14;
+ } else {
+ if (yych == '/')
+ goto yy14;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= ':')
+ goto yy16;
+ if (yych <= '@')
+ goto yy14;
+ } else {
+ if (yych <= '`')
+ goto yy14;
+ if (yych >= '{')
+ goto yy14;
+ }
+ }
+ yych = *++p;
+ if (yych == ':')
+ goto yy16;
+ goto yy14;
+ }
+}
+
+// Try to match email autolink after first <, returning num of chars matched.
+bufsize_t _scan_autolink_email(const unsigned char *p) {
+ const unsigned char *marker = NULL;
+ const unsigned char *start = p;
+
+ {
+ unsigned char yych;
+ static const unsigned char yybm[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 128, 0, 128, 128, 128, 128, 128, 0, 0,
+ 128, 128, 0, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 0, 0, 0, 128, 0, 128, 0, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 0, 0, 0, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ };
+ yych = *p;
+ if (yych <= '9') {
+ if (yych <= '\'') {
+ if (yych == '!')
+ goto yy23;
+ if (yych >= '#')
+ goto yy23;
+ } else {
+ if (yych <= ')')
+ goto yy21;
+ if (yych != ',')
+ goto yy23;
+ }
+ } else {
+ if (yych <= '?') {
+ if (yych == '=')
+ goto yy23;
+ if (yych >= '?')
+ goto yy23;
+ } else {
+ if (yych <= 'Z') {
+ if (yych >= 'A')
+ goto yy23;
+ } else {
+ if (yych <= ']')
+ goto yy21;
+ if (yych <= '~')
+ goto yy23;
+ }
+ }
+ }
+ yy21:
+ ++p;
+ yy22 : { return 0; }
+ yy23:
+ yych = *(marker = ++p);
+ if (yych <= ',') {
+ if (yych <= '"') {
+ if (yych == '!')
+ goto yy25;
+ goto yy22;
+ } else {
+ if (yych <= '\'')
+ goto yy25;
+ if (yych <= ')')
+ goto yy22;
+ if (yych <= '+')
+ goto yy25;
+ goto yy22;
+ }
+ } else {
+ if (yych <= '>') {
+ if (yych <= '9')
+ goto yy25;
+ if (yych == '=')
+ goto yy25;
+ goto yy22;
+ } else {
+ if (yych <= 'Z')
+ goto yy25;
+ if (yych <= ']')
+ goto yy22;
+ if (yych <= '~')
+ goto yy25;
+ goto yy22;
+ }
+ }
+ yy24:
+ yych = *++p;
+ yy25:
+ if (yybm[0 + yych] & 128) {
+ goto yy24;
+ }
+ if (yych <= '>')
+ goto yy26;
+ if (yych <= '@')
+ goto yy27;
+ yy26:
+ p = marker;
+ goto yy22;
+ yy27:
+ yych = *++p;
+ if (yych <= '@') {
+ if (yych <= '/')
+ goto yy26;
+ if (yych >= ':')
+ goto yy26;
+ } else {
+ if (yych <= 'Z')
+ goto yy28;
+ if (yych <= '`')
+ goto yy26;
+ if (yych >= '{')
+ goto yy26;
+ }
+ yy28:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy29;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy29;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy29;
+ goto yy26;
+ }
+ }
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy31;
+ if (yych <= '/')
+ goto yy26;
+ goto yy32;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy32;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy32;
+ goto yy26;
+ }
+ }
+ yy29:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych <= '-')
+ goto yy31;
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy32;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy32;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy32;
+ goto yy26;
+ }
+ }
+ yy30:
+ ++p;
+ { return (bufsize_t)(p - start); }
+ yy31:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy33;
+ if (yych <= '/')
+ goto yy26;
+ goto yy34;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy34;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy34;
+ goto yy26;
+ }
+ }
+ yy32:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy34;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy34;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy34;
+ goto yy26;
+ }
+ }
+ yy33:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy35;
+ if (yych <= '/')
+ goto yy26;
+ goto yy36;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy36;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy36;
+ goto yy26;
+ }
+ }
+ yy34:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy36;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy36;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy36;
+ goto yy26;
+ }
+ }
+ yy35:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy37;
+ if (yych <= '/')
+ goto yy26;
+ goto yy38;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy38;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy38;
+ goto yy26;
+ }
+ }
+ yy36:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy38;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy38;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy38;
+ goto yy26;
+ }
+ }
+ yy37:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy39;
+ if (yych <= '/')
+ goto yy26;
+ goto yy40;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy40;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy40;
+ goto yy26;
+ }
+ }
+ yy38:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy40;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy40;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy40;
+ goto yy26;
+ }
+ }
+ yy39:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy41;
+ if (yych <= '/')
+ goto yy26;
+ goto yy42;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy42;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy42;
+ goto yy26;
+ }
+ }
+ yy40:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy42;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy42;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy42;
+ goto yy26;
+ }
+ }
+ yy41:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy43;
+ if (yych <= '/')
+ goto yy26;
+ goto yy44;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy44;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy44;
+ goto yy26;
+ }
+ }
+ yy42:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy44;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy44;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy44;
+ goto yy26;
+ }
+ }
+ yy43:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy45;
+ if (yych <= '/')
+ goto yy26;
+ goto yy46;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy46;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy46;
+ goto yy26;
+ }
+ }
+ yy44:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy46;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy46;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy46;
+ goto yy26;
+ }
+ }
+ yy45:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy47;
+ if (yych <= '/')
+ goto yy26;
+ goto yy48;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy48;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy48;
+ goto yy26;
+ }
+ }
+ yy46:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy48;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy48;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy48;
+ goto yy26;
+ }
+ }
+ yy47:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy49;
+ if (yych <= '/')
+ goto yy26;
+ goto yy50;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy50;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy50;
+ goto yy26;
+ }
+ }
+ yy48:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy50;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy50;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy50;
+ goto yy26;
+ }
+ }
+ yy49:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy51;
+ if (yych <= '/')
+ goto yy26;
+ goto yy52;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy52;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy52;
+ goto yy26;
+ }
+ }
+ yy50:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy52;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy52;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy52;
+ goto yy26;
+ }
+ }
+ yy51:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy53;
+ if (yych <= '/')
+ goto yy26;
+ goto yy54;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy54;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy54;
+ goto yy26;
+ }
+ }
+ yy52:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy54;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy54;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy54;
+ goto yy26;
+ }
+ }
+ yy53:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy55;
+ if (yych <= '/')
+ goto yy26;
+ goto yy56;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy56;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy56;
+ goto yy26;
+ }
+ }
+ yy54:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy56;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy56;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy56;
+ goto yy26;
+ }
+ }
+ yy55:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy57;
+ if (yych <= '/')
+ goto yy26;
+ goto yy58;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy58;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy58;
+ goto yy26;
+ }
+ }
+ yy56:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy58;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy58;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy58;
+ goto yy26;
+ }
+ }
+ yy57:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy59;
+ if (yych <= '/')
+ goto yy26;
+ goto yy60;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy60;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy60;
+ goto yy26;
+ }
+ }
+ yy58:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy60;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy60;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy60;
+ goto yy26;
+ }
+ }
+ yy59:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy61;
+ if (yych <= '/')
+ goto yy26;
+ goto yy62;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy62;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy62;
+ goto yy26;
+ }
+ }
+ yy60:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy62;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy62;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy62;
+ goto yy26;
+ }
+ }
+ yy61:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy63;
+ if (yych <= '/')
+ goto yy26;
+ goto yy64;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy64;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy64;
+ goto yy26;
+ }
+ }
+ yy62:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy64;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy64;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy64;
+ goto yy26;
+ }
+ }
+ yy63:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy65;
+ if (yych <= '/')
+ goto yy26;
+ goto yy66;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy66;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy66;
+ goto yy26;
+ }
+ }
+ yy64:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy66;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy66;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy66;
+ goto yy26;
+ }
+ }
+ yy65:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy67;
+ if (yych <= '/')
+ goto yy26;
+ goto yy68;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy68;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy68;
+ goto yy26;
+ }
+ }
+ yy66:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy68;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy68;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy68;
+ goto yy26;
+ }
+ }
+ yy67:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy69;
+ if (yych <= '/')
+ goto yy26;
+ goto yy70;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy70;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy70;
+ goto yy26;
+ }
+ }
+ yy68:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy70;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy70;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy70;
+ goto yy26;
+ }
+ }
+ yy69:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy71;
+ if (yych <= '/')
+ goto yy26;
+ goto yy72;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy72;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy72;
+ goto yy26;
+ }
+ }
+ yy70:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy72;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy72;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy72;
+ goto yy26;
+ }
+ }
+ yy71:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy73;
+ if (yych <= '/')
+ goto yy26;
+ goto yy74;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy74;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy74;
+ goto yy26;
+ }
+ }
+ yy72:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy74;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy74;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy74;
+ goto yy26;
+ }
+ }
+ yy73:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy75;
+ if (yych <= '/')
+ goto yy26;
+ goto yy76;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy76;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy76;
+ goto yy26;
+ }
+ }
+ yy74:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy76;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy76;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy76;
+ goto yy26;
+ }
+ }
+ yy75:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy77;
+ if (yych <= '/')
+ goto yy26;
+ goto yy78;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy78;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy78;
+ goto yy26;
+ }
+ }
+ yy76:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy78;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy78;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy78;
+ goto yy26;
+ }
+ }
+ yy77:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy79;
+ if (yych <= '/')
+ goto yy26;
+ goto yy80;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy80;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy80;
+ goto yy26;
+ }
+ }
+ yy78:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy80;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy80;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy80;
+ goto yy26;
+ }
+ }
+ yy79:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy81;
+ if (yych <= '/')
+ goto yy26;
+ goto yy82;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy82;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy82;
+ goto yy26;
+ }
+ }
+ yy80:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy82;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy82;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy82;
+ goto yy26;
+ }
+ }
+ yy81:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy83;
+ if (yych <= '/')
+ goto yy26;
+ goto yy84;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy84;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy84;
+ goto yy26;
+ }
+ }
+ yy82:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy84;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy84;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy84;
+ goto yy26;
+ }
+ }
+ yy83:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy85;
+ if (yych <= '/')
+ goto yy26;
+ goto yy86;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy86;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy86;
+ goto yy26;
+ }
+ }
+ yy84:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy86;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy86;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy86;
+ goto yy26;
+ }
+ }
+ yy85:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy87;
+ if (yych <= '/')
+ goto yy26;
+ goto yy88;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy88;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy88;
+ goto yy26;
+ }
+ }
+ yy86:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy88;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy88;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy88;
+ goto yy26;
+ }
+ }
+ yy87:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy89;
+ if (yych <= '/')
+ goto yy26;
+ goto yy90;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy90;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy90;
+ goto yy26;
+ }
+ }
+ yy88:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy90;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy90;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy90;
+ goto yy26;
+ }
+ }
+ yy89:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy91;
+ if (yych <= '/')
+ goto yy26;
+ goto yy92;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy92;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy92;
+ goto yy26;
+ }
+ }
+ yy90:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy92;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy92;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy92;
+ goto yy26;
+ }
+ }
+ yy91:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy93;
+ if (yych <= '/')
+ goto yy26;
+ goto yy94;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy94;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy94;
+ goto yy26;
+ }
+ }
+ yy92:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy94;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy94;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy94;
+ goto yy26;
+ }
+ }
+ yy93:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy95;
+ if (yych <= '/')
+ goto yy26;
+ goto yy96;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy96;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy96;
+ goto yy26;
+ }
+ }
+ yy94:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy96;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy96;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy96;
+ goto yy26;
+ }
+ }
+ yy95:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy97;
+ if (yych <= '/')
+ goto yy26;
+ goto yy98;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy98;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy98;
+ goto yy26;
+ }
+ }
+ yy96:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy98;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy98;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy98;
+ goto yy26;
+ }
+ }
+ yy97:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy99;
+ if (yych <= '/')
+ goto yy26;
+ goto yy100;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy100;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy100;
+ goto yy26;
+ }
+ }
+ yy98:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy100;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy100;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy100;
+ goto yy26;
+ }
+ }
+ yy99:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy101;
+ if (yych <= '/')
+ goto yy26;
+ goto yy102;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy102;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy102;
+ goto yy26;
+ }
+ }
+ yy100:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy102;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy102;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy102;
+ goto yy26;
+ }
+ }
+ yy101:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy103;
+ if (yych <= '/')
+ goto yy26;
+ goto yy104;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy104;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy104;
+ goto yy26;
+ }
+ }
+ yy102:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy104;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy104;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy104;
+ goto yy26;
+ }
+ }
+ yy103:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy105;
+ if (yych <= '/')
+ goto yy26;
+ goto yy106;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy106;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy106;
+ goto yy26;
+ }
+ }
+ yy104:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy106;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy106;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy106;
+ goto yy26;
+ }
+ }
+ yy105:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy107;
+ if (yych <= '/')
+ goto yy26;
+ goto yy108;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy108;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy108;
+ goto yy26;
+ }
+ }
+ yy106:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy108;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy108;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy108;
+ goto yy26;
+ }
+ }
+ yy107:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy109;
+ if (yych <= '/')
+ goto yy26;
+ goto yy110;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy110;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy110;
+ goto yy26;
+ }
+ }
+ yy108:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy110;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy110;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy110;
+ goto yy26;
+ }
+ }
+ yy109:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy111;
+ if (yych <= '/')
+ goto yy26;
+ goto yy112;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy112;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy112;
+ goto yy26;
+ }
+ }
+ yy110:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy112;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy112;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy112;
+ goto yy26;
+ }
+ }
+ yy111:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy113;
+ if (yych <= '/')
+ goto yy26;
+ goto yy114;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy114;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy114;
+ goto yy26;
+ }
+ }
+ yy112:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy114;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy114;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy114;
+ goto yy26;
+ }
+ }
+ yy113:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy115;
+ if (yych <= '/')
+ goto yy26;
+ goto yy116;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy116;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy116;
+ goto yy26;
+ }
+ }
+ yy114:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy116;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy116;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy116;
+ goto yy26;
+ }
+ }
+ yy115:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy117;
+ if (yych <= '/')
+ goto yy26;
+ goto yy118;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy118;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy118;
+ goto yy26;
+ }
+ }
+ yy116:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy118;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy118;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy118;
+ goto yy26;
+ }
+ }
+ yy117:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy119;
+ if (yych <= '/')
+ goto yy26;
+ goto yy120;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy120;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy120;
+ goto yy26;
+ }
+ }
+ yy118:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy120;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy120;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy120;
+ goto yy26;
+ }
+ }
+ yy119:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy121;
+ if (yych <= '/')
+ goto yy26;
+ goto yy122;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy122;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy122;
+ goto yy26;
+ }
+ }
+ yy120:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy122;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy122;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy122;
+ goto yy26;
+ }
+ }
+ yy121:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy123;
+ if (yych <= '/')
+ goto yy26;
+ goto yy124;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy124;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy124;
+ goto yy26;
+ }
+ }
+ yy122:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy124;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy124;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy124;
+ goto yy26;
+ }
+ }
+ yy123:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy125;
+ if (yych <= '/')
+ goto yy26;
+ goto yy126;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy126;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy126;
+ goto yy26;
+ }
+ }
+ yy124:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy126;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy126;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy126;
+ goto yy26;
+ }
+ }
+ yy125:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy127;
+ if (yych <= '/')
+ goto yy26;
+ goto yy128;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy128;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy128;
+ goto yy26;
+ }
+ }
+ yy126:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy128;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy128;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy128;
+ goto yy26;
+ }
+ }
+ yy127:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy129;
+ if (yych <= '/')
+ goto yy26;
+ goto yy130;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy130;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy130;
+ goto yy26;
+ }
+ }
+ yy128:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy130;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy130;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy130;
+ goto yy26;
+ }
+ }
+ yy129:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy131;
+ if (yych <= '/')
+ goto yy26;
+ goto yy132;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy132;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy132;
+ goto yy26;
+ }
+ }
+ yy130:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy132;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy132;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy132;
+ goto yy26;
+ }
+ }
+ yy131:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy133;
+ if (yych <= '/')
+ goto yy26;
+ goto yy134;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy134;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy134;
+ goto yy26;
+ }
+ }
+ yy132:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy134;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy134;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy134;
+ goto yy26;
+ }
+ }
+ yy133:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy135;
+ if (yych <= '/')
+ goto yy26;
+ goto yy136;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy136;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy136;
+ goto yy26;
+ }
+ }
+ yy134:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy136;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy136;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy136;
+ goto yy26;
+ }
+ }
+ yy135:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy137;
+ if (yych <= '/')
+ goto yy26;
+ goto yy138;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy138;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy138;
+ goto yy26;
+ }
+ }
+ yy136:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy138;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy138;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy138;
+ goto yy26;
+ }
+ }
+ yy137:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy139;
+ if (yych <= '/')
+ goto yy26;
+ goto yy140;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy140;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy140;
+ goto yy26;
+ }
+ }
+ yy138:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy140;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy140;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy140;
+ goto yy26;
+ }
+ }
+ yy139:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy141;
+ if (yych <= '/')
+ goto yy26;
+ goto yy142;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy142;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy142;
+ goto yy26;
+ }
+ }
+ yy140:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy142;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy142;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy142;
+ goto yy26;
+ }
+ }
+ yy141:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy143;
+ if (yych <= '/')
+ goto yy26;
+ goto yy144;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy144;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy144;
+ goto yy26;
+ }
+ }
+ yy142:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy144;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy144;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy144;
+ goto yy26;
+ }
+ }
+ yy143:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy145;
+ if (yych <= '/')
+ goto yy26;
+ goto yy146;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy146;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy146;
+ goto yy26;
+ }
+ }
+ yy144:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy146;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy146;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy146;
+ goto yy26;
+ }
+ }
+ yy145:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy147;
+ if (yych <= '/')
+ goto yy26;
+ goto yy148;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy148;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy148;
+ goto yy26;
+ }
+ }
+ yy146:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy148;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy148;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy148;
+ goto yy26;
+ }
+ }
+ yy147:
+ yych = *++p;
+ if (yych <= '9') {
+ if (yych == '-')
+ goto yy149;
+ if (yych <= '/')
+ goto yy26;
+ goto yy150;
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '@')
+ goto yy26;
+ goto yy150;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy150;
+ goto yy26;
+ }
+ }
+ yy148:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= ',')
+ goto yy26;
+ if (yych >= '.')
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy150;
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ goto yy150;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy150;
+ goto yy26;
+ }
+ }
+ yy149:
+ yych = *++p;
+ if (yych <= '@') {
+ if (yych <= '/')
+ goto yy26;
+ if (yych <= '9')
+ goto yy151;
+ goto yy26;
+ } else {
+ if (yych <= 'Z')
+ goto yy151;
+ if (yych <= '`')
+ goto yy26;
+ if (yych <= 'z')
+ goto yy151;
+ goto yy26;
+ }
+ yy150:
+ yych = *++p;
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych <= '-')
+ goto yy26;
+ goto yy27;
+ } else {
+ if (yych <= '/')
+ goto yy26;
+ if (yych >= ':')
+ goto yy26;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy30;
+ if (yych <= '@')
+ goto yy26;
+ } else {
+ if (yych <= '`')
+ goto yy26;
+ if (yych >= '{')
+ goto yy26;
+ }
+ }
+ yy151:
+ yych = *++p;
+ if (yych == '.')
+ goto yy27;
+ if (yych == '>')
+ goto yy30;
+ goto yy26;
+ }
+}
+
+// Try to match an HTML tag after first <, returning num of chars matched.
+bufsize_t _scan_html_tag(const unsigned char *p) {
+ const unsigned char *marker = NULL;
+ const unsigned char *start = p;
+
+ {
+ unsigned char yych;
+ static const unsigned char yybm[] = {
+ 0, 224, 224, 224, 224, 224, 224, 224, 224, 200, 200, 200, 200, 200,
+ 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224,
+ 224, 224, 224, 224, 200, 224, 128, 224, 224, 224, 224, 64, 224, 224,
+ 224, 224, 224, 244, 240, 224, 244, 244, 244, 244, 244, 244, 244, 244,
+ 244, 244, 240, 224, 192, 192, 192, 224, 224, 244, 244, 244, 244, 244,
+ 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244,
+ 244, 244, 244, 244, 244, 244, 244, 224, 224, 224, 224, 240, 192, 244,
+ 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244,
+ 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 224, 224, 224,
+ 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224,
+ 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224,
+ 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224,
+ 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224,
+ 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224,
+ 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224,
+ 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224,
+ 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224,
+ 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224,
+ 224, 224, 224, 224,
+ };
+ yych = *p;
+ if (yych <= '@') {
+ if (yych == '/')
+ goto yy155;
+ } else {
+ if (yych <= 'Z')
+ goto yy156;
+ if (yych <= '`')
+ goto yy153;
+ if (yych <= 'z')
+ goto yy156;
+ }
+ yy153:
+ ++p;
+ yy154 : { return 0; }
+ yy155:
+ yych = *(marker = ++p);
+ if (yych <= '@')
+ goto yy154;
+ if (yych <= 'Z')
+ goto yy157;
+ if (yych <= '`')
+ goto yy154;
+ if (yych <= 'z')
+ goto yy157;
+ goto yy154;
+ yy156:
+ yych = *(marker = ++p);
+ if (yych <= '.') {
+ if (yych <= 0x1F) {
+ if (yych <= 0x08)
+ goto yy154;
+ if (yych <= '\r')
+ goto yy161;
+ goto yy154;
+ } else {
+ if (yych <= ' ')
+ goto yy161;
+ if (yych == '-')
+ goto yy161;
+ goto yy154;
+ }
+ } else {
+ if (yych <= '@') {
+ if (yych <= '9')
+ goto yy161;
+ if (yych == '>')
+ goto yy161;
+ goto yy154;
+ } else {
+ if (yych <= 'Z')
+ goto yy161;
+ if (yych <= '`')
+ goto yy154;
+ if (yych <= 'z')
+ goto yy161;
+ goto yy154;
+ }
+ }
+ yy157:
+ yych = *++p;
+ if (yybm[0 + yych] & 4) {
+ goto yy157;
+ }
+ if (yych <= 0x1F) {
+ if (yych <= 0x08)
+ goto yy158;
+ if (yych <= '\r')
+ goto yy164;
+ } else {
+ if (yych <= ' ')
+ goto yy164;
+ if (yych == '>')
+ goto yy163;
+ }
+ yy158:
+ p = marker;
+ goto yy154;
+ yy159:
+ yych = *++p;
+ if (yybm[0 + yych] & 8) {
+ goto yy159;
+ }
+ if (yych <= '>') {
+ if (yych <= '9') {
+ if (yych == '/')
+ goto yy162;
+ goto yy158;
+ } else {
+ if (yych <= ':')
+ goto yy165;
+ if (yych <= '=')
+ goto yy158;
+ goto yy163;
+ }
+ } else {
+ if (yych <= '^') {
+ if (yych <= '@')
+ goto yy158;
+ if (yych <= 'Z')
+ goto yy165;
+ goto yy158;
+ } else {
+ if (yych == '`')
+ goto yy158;
+ if (yych <= 'z')
+ goto yy165;
+ goto yy158;
+ }
+ }
+ yy160:
+ yych = *++p;
+ yy161:
+ if (yybm[0 + yych] & 8) {
+ goto yy159;
+ }
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych == '-')
+ goto yy160;
+ goto yy158;
+ } else {
+ if (yych <= '/')
+ goto yy162;
+ if (yych <= '9')
+ goto yy160;
+ goto yy158;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy163;
+ if (yych <= '@')
+ goto yy158;
+ goto yy160;
+ } else {
+ if (yych <= '`')
+ goto yy158;
+ if (yych <= 'z')
+ goto yy160;
+ goto yy158;
+ }
+ }
+ yy162:
+ yych = *++p;
+ if (yych != '>')
+ goto yy158;
+ yy163:
+ ++p;
+ { return (bufsize_t)(p - start); }
+ yy164:
+ yych = *++p;
+ if (yych <= 0x1F) {
+ if (yych <= 0x08)
+ goto yy158;
+ if (yych <= '\r')
+ goto yy164;
+ goto yy158;
+ } else {
+ if (yych <= ' ')
+ goto yy164;
+ if (yych == '>')
+ goto yy163;
+ goto yy158;
+ }
+ yy165:
+ yych = *++p;
+ if (yybm[0 + yych] & 16) {
+ goto yy165;
+ }
+ if (yych <= ',') {
+ if (yych <= '\r') {
+ if (yych <= 0x08)
+ goto yy158;
+ } else {
+ if (yych != ' ')
+ goto yy158;
+ }
+ } else {
+ if (yych <= '<') {
+ if (yych <= '/')
+ goto yy162;
+ goto yy158;
+ } else {
+ if (yych <= '=')
+ goto yy167;
+ if (yych <= '>')
+ goto yy163;
+ goto yy158;
+ }
+ }
+ yy166:
+ yych = *++p;
+ if (yych <= '<') {
+ if (yych <= ' ') {
+ if (yych <= 0x08)
+ goto yy158;
+ if (yych <= '\r')
+ goto yy166;
+ if (yych <= 0x1F)
+ goto yy158;
+ goto yy166;
+ } else {
+ if (yych <= '/') {
+ if (yych <= '.')
+ goto yy158;
+ goto yy162;
+ } else {
+ if (yych == ':')
+ goto yy165;
+ goto yy158;
+ }
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '=')
+ goto yy167;
+ if (yych <= '>')
+ goto yy163;
+ if (yych <= '@')
+ goto yy158;
+ goto yy165;
+ } else {
+ if (yych <= '_') {
+ if (yych <= '^')
+ goto yy158;
+ goto yy165;
+ } else {
+ if (yych <= '`')
+ goto yy158;
+ if (yych <= 'z')
+ goto yy165;
+ goto yy158;
+ }
+ }
+ }
+ yy167:
+ yych = *++p;
+ if (yybm[0 + yych] & 32) {
+ goto yy168;
+ }
+ if (yych <= 0x00)
+ goto yy158;
+ if (yych <= ' ')
+ goto yy167;
+ if (yych <= '"')
+ goto yy169;
+ if (yych <= '\'')
+ goto yy170;
+ goto yy158;
+ yy168:
+ yych = *++p;
+ if (yybm[0 + yych] & 32) {
+ goto yy168;
+ }
+ if (yych <= 0x00)
+ goto yy158;
+ if (yych <= ' ')
+ goto yy159;
+ if (yych == '>')
+ goto yy163;
+ goto yy158;
+ yy169:
+ yych = *++p;
+ if (yybm[0 + yych] & 64) {
+ goto yy169;
+ }
+ if (yych <= 0x00)
+ goto yy158;
+ goto yy171;
+ yy170:
+ yych = *++p;
+ if (yybm[0 + yych] & 128) {
+ goto yy170;
+ }
+ if (yych <= 0x00)
+ goto yy158;
+ yy171:
+ yych = *++p;
+ if (yybm[0 + yych] & 8) {
+ goto yy159;
+ }
+ if (yych == '/')
+ goto yy162;
+ if (yych == '>')
+ goto yy163;
+ goto yy158;
+ }
+}
+
+bufsize_t _scan_html_comment(const unsigned char *p) {
+ const unsigned char *marker = NULL;
+ const unsigned char *start = p;
+
+ {
+ unsigned char yych;
+ static const unsigned char yybm[] = {
+ 0, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 0, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128,
+ };
+ yych = *p;
+ if (yych == '-')
+ goto yy174;
+ ++p;
+ yy173 : { return 0; }
+ yy174:
+ yych = *(marker = ++p);
+ if (yych != '-')
+ goto yy173;
+ yy175:
+ yych = *++p;
+ if (yybm[0 + yych] & 128) {
+ goto yy175;
+ }
+ if (yych >= 0x01)
+ goto yy177;
+ yy176:
+ p = marker;
+ goto yy173;
+ yy177:
+ yych = *++p;
+ if (yybm[0 + yych] & 128) {
+ goto yy175;
+ }
+ if (yych <= 0x00)
+ goto yy176;
+ yych = *++p;
+ if (yych <= 0x00)
+ goto yy176;
+ if (yych != '>')
+ goto yy175;
+ ++p;
+ { return (bufsize_t)(p - start); }
+ }
+}
+
+bufsize_t _scan_html_pi(const unsigned char *p) {
+ const unsigned char *marker = NULL;
+ const unsigned char *start = p;
+
+ {
+ unsigned char yych;
+ static const unsigned char yybm[] = {
+ 0, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 0, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128,
+ };
+ yych = *p;
+ if (yybm[0 + yych] & 128) {
+ goto yy180;
+ }
+ if (yych >= 0x01)
+ goto yy182;
+ ++p;
+ yy179 : { return 0; }
+ yy180:
+ yych = *(marker = ++p);
+ if (yybm[0 + yych] & 128) {
+ goto yy180;
+ }
+ if (yych >= 0x01)
+ goto yy183;
+ yy181 : { return (bufsize_t)(p - start); }
+ yy182:
+ yych = *++p;
+ if (yych <= 0x00)
+ goto yy179;
+ if (yych == '>')
+ goto yy179;
+ goto yy180;
+ yy183:
+ yych = *++p;
+ if (yych <= 0x00)
+ goto yy184;
+ if (yych != '>')
+ goto yy180;
+ yy184:
+ p = marker;
+ goto yy181;
+ }
+}
+
+bufsize_t _scan_html_declaration(const unsigned char *p) {
+ const unsigned char *marker = NULL;
+ const unsigned char *start = p;
+ (void)marker;
+
+ {
+ unsigned char yych;
+ static const unsigned char yybm[] = {
+ 0, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 0, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128,
+ };
+ yych = *p;
+ if (yych <= '@')
+ goto yy186;
+ if (yych <= 'Z')
+ goto yy187;
+ if (yych <= '`')
+ goto yy186;
+ if (yych <= 'z')
+ goto yy187;
+ yy186:
+ ++p;
+ { return 0; }
+ yy187:
+ yych = *++p;
+ if (yybm[0 + yych] & 128) {
+ goto yy187;
+ }
+ { return (bufsize_t)(p - start); }
+ }
+}
+
+bufsize_t _scan_html_cdata(const unsigned char *p) {
+ const unsigned char *marker = NULL;
+ const unsigned char *start = p;
+
+ {
+ unsigned char yych;
+ unsigned int yyaccept = 0;
+ static const unsigned char yybm[] = {
+ 0, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 0, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128,
+ };
+ yych = *p;
+ if (yych == 'C')
+ goto yy190;
+ if (yych == 'c')
+ goto yy190;
+ ++p;
+ yy189 : { return 0; }
+ yy190:
+ yyaccept = 0;
+ yych = *(marker = ++p);
+ if (yych == 'D')
+ goto yy191;
+ if (yych != 'd')
+ goto yy189;
+ yy191:
+ yych = *++p;
+ if (yych == 'A')
+ goto yy193;
+ if (yych == 'a')
+ goto yy193;
+ yy192:
+ p = marker;
+ if (yyaccept == 0) {
+ goto yy189;
+ } else {
+ goto yy197;
+ }
+ yy193:
+ yych = *++p;
+ if (yych == 'T')
+ goto yy194;
+ if (yych != 't')
+ goto yy192;
+ yy194:
+ yych = *++p;
+ if (yych == 'A')
+ goto yy195;
+ if (yych != 'a')
+ goto yy192;
+ yy195:
+ yych = *++p;
+ if (yych != '[')
+ goto yy192;
+ yy196:
+ yyaccept = 1;
+ yych = *(marker = ++p);
+ if (yybm[0 + yych] & 128) {
+ goto yy196;
+ }
+ if (yych >= 0x01)
+ goto yy198;
+ yy197 : { return (bufsize_t)(p - start); }
+ yy198:
+ yych = *++p;
+ if (yybm[0 + yych] & 128) {
+ goto yy196;
+ }
+ if (yych <= 0x00)
+ goto yy192;
+ yych = *++p;
+ if (yych <= 0x00)
+ goto yy192;
+ if (yych == '>')
+ goto yy192;
+ goto yy196;
+ }
+}
+
+// Try to match an HTML block tag start line, returning
+// an integer code for the type of block (1-6, matching the spec).
+// #7 is handled by a separate function, below.
+bufsize_t _scan_html_block_start(const unsigned char *p) {
+ const unsigned char *marker = NULL;
+
+ {
+ unsigned char yych;
+ yych = *p;
+ if (yych == '<')
+ goto yy201;
+ ++p;
+ yy200 : { return 0; }
+ yy201:
+ yych = *(marker = ++p);
+ switch (yych) {
+ case '!':
+ goto yy202;
+ case '/':
+ goto yy204;
+ case '?':
+ goto yy205;
+ case 'A':
+ case 'a':
+ goto yy206;
+ case 'B':
+ case 'b':
+ goto yy207;
+ case 'C':
+ case 'c':
+ goto yy208;
+ case 'D':
+ case 'd':
+ goto yy209;
+ case 'F':
+ case 'f':
+ goto yy210;
+ case 'H':
+ case 'h':
+ goto yy211;
+ case 'I':
+ case 'i':
+ goto yy212;
+ case 'L':
+ case 'l':
+ goto yy213;
+ case 'M':
+ case 'm':
+ goto yy214;
+ case 'N':
+ case 'n':
+ goto yy215;
+ case 'O':
+ case 'o':
+ goto yy216;
+ case 'P':
+ case 'p':
+ goto yy217;
+ case 'S':
+ case 's':
+ goto yy218;
+ case 'T':
+ case 't':
+ goto yy219;
+ case 'U':
+ case 'u':
+ goto yy220;
+ default:
+ goto yy200;
+ }
+ yy202:
+ yych = *++p;
+ if (yych <= 'Z') {
+ if (yych == '-')
+ goto yy221;
+ if (yych >= 'A')
+ goto yy222;
+ } else {
+ if (yych <= '[')
+ goto yy223;
+ if (yych <= '`')
+ goto yy203;
+ if (yych <= 'z')
+ goto yy222;
+ }
+ yy203:
+ p = marker;
+ goto yy200;
+ yy204:
+ yych = *++p;
+ switch (yych) {
+ case 'A':
+ case 'a':
+ goto yy206;
+ case 'B':
+ case 'b':
+ goto yy207;
+ case 'C':
+ case 'c':
+ goto yy208;
+ case 'D':
+ case 'd':
+ goto yy209;
+ case 'F':
+ case 'f':
+ goto yy210;
+ case 'H':
+ case 'h':
+ goto yy211;
+ case 'I':
+ case 'i':
+ goto yy212;
+ case 'L':
+ case 'l':
+ goto yy213;
+ case 'M':
+ case 'm':
+ goto yy214;
+ case 'N':
+ case 'n':
+ goto yy215;
+ case 'O':
+ case 'o':
+ goto yy216;
+ case 'P':
+ case 'p':
+ goto yy224;
+ case 'S':
+ case 's':
+ goto yy225;
+ case 'T':
+ case 't':
+ goto yy226;
+ case 'U':
+ case 'u':
+ goto yy220;
+ default:
+ goto yy203;
+ }
+ yy205:
+ ++p;
+ { return 3; }
+ yy206:
+ yych = *++p;
+ if (yych <= 'S') {
+ if (yych <= 'D') {
+ if (yych <= 'C')
+ goto yy203;
+ goto yy227;
+ } else {
+ if (yych <= 'Q')
+ goto yy203;
+ if (yych <= 'R')
+ goto yy228;
+ goto yy229;
+ }
+ } else {
+ if (yych <= 'q') {
+ if (yych == 'd')
+ goto yy227;
+ goto yy203;
+ } else {
+ if (yych <= 'r')
+ goto yy228;
+ if (yych <= 's')
+ goto yy229;
+ goto yy203;
+ }
+ }
+ yy207:
+ yych = *++p;
+ if (yych <= 'O') {
+ if (yych <= 'K') {
+ if (yych == 'A')
+ goto yy230;
+ goto yy203;
+ } else {
+ if (yych <= 'L')
+ goto yy231;
+ if (yych <= 'N')
+ goto yy203;
+ goto yy232;
+ }
+ } else {
+ if (yych <= 'k') {
+ if (yych == 'a')
+ goto yy230;
+ goto yy203;
+ } else {
+ if (yych <= 'l')
+ goto yy231;
+ if (yych == 'o')
+ goto yy232;
+ goto yy203;
+ }
+ }
+ yy208:
+ yych = *++p;
+ if (yych <= 'O') {
+ if (yych <= 'D') {
+ if (yych == 'A')
+ goto yy233;
+ goto yy203;
+ } else {
+ if (yych <= 'E')
+ goto yy234;
+ if (yych <= 'N')
+ goto yy203;
+ goto yy235;
+ }
+ } else {
+ if (yych <= 'd') {
+ if (yych == 'a')
+ goto yy233;
+ goto yy203;
+ } else {
+ if (yych <= 'e')
+ goto yy234;
+ if (yych == 'o')
+ goto yy235;
+ goto yy203;
+ }
+ }
+ yy209:
+ yych = *++p;
+ switch (yych) {
+ case 'D':
+ case 'L':
+ case 'T':
+ case 'd':
+ case 'l':
+ case 't':
+ goto yy236;
+ case 'E':
+ case 'e':
+ goto yy237;
+ case 'I':
+ case 'i':
+ goto yy238;
+ default:
+ goto yy203;
+ }
+ yy210:
+ yych = *++p;
+ if (yych <= 'R') {
+ if (yych <= 'N') {
+ if (yych == 'I')
+ goto yy239;
+ goto yy203;
+ } else {
+ if (yych <= 'O')
+ goto yy240;
+ if (yych <= 'Q')
+ goto yy203;
+ goto yy241;
+ }
+ } else {
+ if (yych <= 'n') {
+ if (yych == 'i')
+ goto yy239;
+ goto yy203;
+ } else {
+ if (yych <= 'o')
+ goto yy240;
+ if (yych == 'r')
+ goto yy241;
+ goto yy203;
+ }
+ }
+ yy211:
+ yych = *++p;
+ if (yych <= 'S') {
+ if (yych <= 'D') {
+ if (yych <= '0')
+ goto yy203;
+ if (yych <= '6')
+ goto yy236;
+ goto yy203;
+ } else {
+ if (yych <= 'E')
+ goto yy242;
+ if (yych == 'R')
+ goto yy236;
+ goto yy203;
+ }
+ } else {
+ if (yych <= 'q') {
+ if (yych <= 'T')
+ goto yy243;
+ if (yych == 'e')
+ goto yy242;
+ goto yy203;
+ } else {
+ if (yych <= 'r')
+ goto yy236;
+ if (yych == 't')
+ goto yy243;
+ goto yy203;
+ }
+ }
+ yy212:
+ yych = *++p;
+ if (yych == 'F')
+ goto yy244;
+ if (yych == 'f')
+ goto yy244;
+ goto yy203;
+ yy213:
+ yych = *++p;
+ if (yych <= 'I') {
+ if (yych == 'E')
+ goto yy245;
+ if (yych <= 'H')
+ goto yy203;
+ goto yy246;
+ } else {
+ if (yych <= 'e') {
+ if (yych <= 'd')
+ goto yy203;
+ goto yy245;
+ } else {
+ if (yych == 'i')
+ goto yy246;
+ goto yy203;
+ }
+ }
+ yy214:
+ yych = *++p;
+ if (yych <= 'E') {
+ if (yych == 'A')
+ goto yy247;
+ if (yych <= 'D')
+ goto yy203;
+ goto yy248;
+ } else {
+ if (yych <= 'a') {
+ if (yych <= '`')
+ goto yy203;
+ goto yy247;
+ } else {
+ if (yych == 'e')
+ goto yy248;
+ goto yy203;
+ }
+ }
+ yy215:
+ yych = *++p;
+ if (yych <= 'O') {
+ if (yych == 'A')
+ goto yy249;
+ if (yych <= 'N')
+ goto yy203;
+ goto yy250;
+ } else {
+ if (yych <= 'a') {
+ if (yych <= '`')
+ goto yy203;
+ goto yy249;
+ } else {
+ if (yych == 'o')
+ goto yy250;
+ goto yy203;
+ }
+ }
+ yy216:
+ yych = *++p;
+ if (yych <= 'P') {
+ if (yych == 'L')
+ goto yy236;
+ if (yych <= 'O')
+ goto yy203;
+ goto yy251;
+ } else {
+ if (yych <= 'l') {
+ if (yych <= 'k')
+ goto yy203;
+ goto yy236;
+ } else {
+ if (yych == 'p')
+ goto yy251;
+ goto yy203;
+ }
+ }
+ yy217:
+ yych = *++p;
+ if (yych <= '>') {
+ if (yych <= ' ') {
+ if (yych <= 0x08)
+ goto yy203;
+ if (yych <= '\r')
+ goto yy252;
+ if (yych <= 0x1F)
+ goto yy203;
+ goto yy252;
+ } else {
+ if (yych == '/')
+ goto yy253;
+ if (yych <= '=')
+ goto yy203;
+ goto yy252;
+ }
+ } else {
+ if (yych <= 'R') {
+ if (yych == 'A')
+ goto yy254;
+ if (yych <= 'Q')
+ goto yy203;
+ goto yy255;
+ } else {
+ if (yych <= 'a') {
+ if (yych <= '`')
+ goto yy203;
+ goto yy254;
+ } else {
+ if (yych == 'r')
+ goto yy255;
+ goto yy203;
+ }
+ }
+ }
+ yy218:
+ yych = *++p;
+ if (yych <= 'U') {
+ if (yych <= 'D') {
+ if (yych == 'C')
+ goto yy256;
+ goto yy203;
+ } else {
+ if (yych <= 'E')
+ goto yy257;
+ if (yych <= 'S')
+ goto yy203;
+ if (yych <= 'T')
+ goto yy258;
+ goto yy259;
+ }
+ } else {
+ if (yych <= 'e') {
+ if (yych == 'c')
+ goto yy256;
+ if (yych <= 'd')
+ goto yy203;
+ goto yy257;
+ } else {
+ if (yych <= 's')
+ goto yy203;
+ if (yych <= 't')
+ goto yy258;
+ if (yych <= 'u')
+ goto yy259;
+ goto yy203;
+ }
+ }
+ yy219:
+ yych = *++p;
+ switch (yych) {
+ case 'A':
+ case 'a':
+ goto yy260;
+ case 'B':
+ case 'b':
+ goto yy261;
+ case 'D':
+ case 'd':
+ goto yy236;
+ case 'E':
+ case 'e':
+ goto yy262;
+ case 'F':
+ case 'f':
+ goto yy263;
+ case 'H':
+ case 'h':
+ goto yy264;
+ case 'I':
+ case 'i':
+ goto yy265;
+ case 'R':
+ case 'r':
+ goto yy266;
+ default:
+ goto yy203;
+ }
+ yy220:
+ yych = *++p;
+ if (yych == 'L')
+ goto yy236;
+ if (yych == 'l')
+ goto yy236;
+ goto yy203;
+ yy221:
+ yych = *++p;
+ if (yych == '-')
+ goto yy267;
+ goto yy203;
+ yy222:
+ ++p;
+ { return 4; }
+ yy223:
+ yych = *++p;
+ if (yych == 'C')
+ goto yy268;
+ if (yych == 'c')
+ goto yy268;
+ goto yy203;
+ yy224:
+ yych = *++p;
+ if (yych <= '/') {
+ if (yych <= 0x1F) {
+ if (yych <= 0x08)
+ goto yy203;
+ if (yych <= '\r')
+ goto yy252;
+ goto yy203;
+ } else {
+ if (yych <= ' ')
+ goto yy252;
+ if (yych <= '.')
+ goto yy203;
+ goto yy253;
+ }
+ } else {
+ if (yych <= '@') {
+ if (yych == '>')
+ goto yy252;
+ goto yy203;
+ } else {
+ if (yych <= 'A')
+ goto yy254;
+ if (yych == 'a')
+ goto yy254;
+ goto yy203;
+ }
+ }
+ yy225:
+ yych = *++p;
+ if (yych <= 'U') {
+ if (yych == 'E')
+ goto yy257;
+ if (yych <= 'T')
+ goto yy203;
+ goto yy259;
+ } else {
+ if (yych <= 'e') {
+ if (yych <= 'd')
+ goto yy203;
+ goto yy257;
+ } else {
+ if (yych == 'u')
+ goto yy259;
+ goto yy203;
+ }
+ }
+ yy226:
+ yych = *++p;
+ switch (yych) {
+ case 'A':
+ case 'a':
+ goto yy260;
+ case 'B':
+ case 'b':
+ goto yy261;
+ case 'D':
+ case 'd':
+ goto yy236;
+ case 'F':
+ case 'f':
+ goto yy263;
+ case 'H':
+ case 'h':
+ goto yy264;
+ case 'I':
+ case 'i':
+ goto yy265;
+ case 'R':
+ case 'r':
+ goto yy266;
+ default:
+ goto yy203;
+ }
+ yy227:
+ yych = *++p;
+ if (yych == 'D')
+ goto yy269;
+ if (yych == 'd')
+ goto yy269;
+ goto yy203;
+ yy228:
+ yych = *++p;
+ if (yych == 'T')
+ goto yy270;
+ if (yych == 't')
+ goto yy270;
+ goto yy203;
+ yy229:
+ yych = *++p;
+ if (yych == 'I')
+ goto yy271;
+ if (yych == 'i')
+ goto yy271;
+ goto yy203;
+ yy230:
+ yych = *++p;
+ if (yych == 'S')
+ goto yy272;
+ if (yych == 's')
+ goto yy272;
+ goto yy203;
+ yy231:
+ yych = *++p;
+ if (yych == 'O')
+ goto yy273;
+ if (yych == 'o')
+ goto yy273;
+ goto yy203;
+ yy232:
+ yych = *++p;
+ if (yych == 'D')
+ goto yy274;
+ if (yych == 'd')
+ goto yy274;
+ goto yy203;
+ yy233:
+ yych = *++p;
+ if (yych == 'P')
+ goto yy275;
+ if (yych == 'p')
+ goto yy275;
+ goto yy203;
+ yy234:
+ yych = *++p;
+ if (yych == 'N')
+ goto yy276;
+ if (yych == 'n')
+ goto yy276;
+ goto yy203;
+ yy235:
+ yych = *++p;
+ if (yych == 'L')
+ goto yy277;
+ if (yych == 'l')
+ goto yy277;
+ goto yy203;
+ yy236:
+ yych = *++p;
+ if (yych <= ' ') {
+ if (yych <= 0x08)
+ goto yy203;
+ if (yych <= '\r')
+ goto yy252;
+ if (yych <= 0x1F)
+ goto yy203;
+ goto yy252;
+ } else {
+ if (yych <= '/') {
+ if (yych <= '.')
+ goto yy203;
+ goto yy253;
+ } else {
+ if (yych == '>')
+ goto yy252;
+ goto yy203;
+ }
+ }
+ yy237:
+ yych = *++p;
+ if (yych == 'T')
+ goto yy278;
+ if (yych == 't')
+ goto yy278;
+ goto yy203;
+ yy238:
+ yych = *++p;
+ if (yych <= 'V') {
+ if (yych <= 'Q') {
+ if (yych == 'A')
+ goto yy279;
+ goto yy203;
+ } else {
+ if (yych <= 'R')
+ goto yy236;
+ if (yych <= 'U')
+ goto yy203;
+ goto yy236;
+ }
+ } else {
+ if (yych <= 'q') {
+ if (yych == 'a')
+ goto yy279;
+ goto yy203;
+ } else {
+ if (yych <= 'r')
+ goto yy236;
+ if (yych == 'v')
+ goto yy236;
+ goto yy203;
+ }
+ }
+ yy239:
+ yych = *++p;
+ if (yych <= 'G') {
+ if (yych == 'E')
+ goto yy280;
+ if (yych <= 'F')
+ goto yy203;
+ goto yy281;
+ } else {
+ if (yych <= 'e') {
+ if (yych <= 'd')
+ goto yy203;
+ goto yy280;
+ } else {
+ if (yych == 'g')
+ goto yy281;
+ goto yy203;
+ }
+ }
+ yy240:
+ yych = *++p;
+ if (yych <= 'R') {
+ if (yych == 'O')
+ goto yy276;
+ if (yych <= 'Q')
+ goto yy203;
+ goto yy282;
+ } else {
+ if (yych <= 'o') {
+ if (yych <= 'n')
+ goto yy203;
+ goto yy276;
+ } else {
+ if (yych == 'r')
+ goto yy282;
+ goto yy203;
+ }
+ }
+ yy241:
+ yych = *++p;
+ if (yych == 'A')
+ goto yy283;
+ if (yych == 'a')
+ goto yy283;
+ goto yy203;
+ yy242:
+ yych = *++p;
+ if (yych == 'A')
+ goto yy284;
+ if (yych == 'a')
+ goto yy284;
+ goto yy203;
+ yy243:
+ yych = *++p;
+ if (yych == 'M')
+ goto yy220;
+ if (yych == 'm')
+ goto yy220;
+ goto yy203;
+ yy244:
+ yych = *++p;
+ if (yych == 'R')
+ goto yy285;
+ if (yych == 'r')
+ goto yy285;
+ goto yy203;
+ yy245:
+ yych = *++p;
+ if (yych == 'G')
+ goto yy286;
+ if (yych == 'g')
+ goto yy286;
+ goto yy203;
+ yy246:
+ yych = *++p;
+ if (yych <= '/') {
+ if (yych <= 0x1F) {
+ if (yych <= 0x08)
+ goto yy203;
+ if (yych <= '\r')
+ goto yy252;
+ goto yy203;
+ } else {
+ if (yych <= ' ')
+ goto yy252;
+ if (yych <= '.')
+ goto yy203;
+ goto yy253;
+ }
+ } else {
+ if (yych <= 'M') {
+ if (yych == '>')
+ goto yy252;
+ goto yy203;
+ } else {
+ if (yych <= 'N')
+ goto yy287;
+ if (yych == 'n')
+ goto yy287;
+ goto yy203;
+ }
+ }
+ yy247:
+ yych = *++p;
+ if (yych == 'I')
+ goto yy288;
+ if (yych == 'i')
+ goto yy288;
+ goto yy203;
+ yy248:
+ yych = *++p;
+ if (yych == 'N')
+ goto yy289;
+ if (yych == 'n')
+ goto yy289;
+ goto yy203;
+ yy249:
+ yych = *++p;
+ if (yych == 'V')
+ goto yy236;
+ if (yych == 'v')
+ goto yy236;
+ goto yy203;
+ yy250:
+ yych = *++p;
+ if (yych == 'F')
+ goto yy290;
+ if (yych == 'f')
+ goto yy290;
+ goto yy203;
+ yy251:
+ yych = *++p;
+ if (yych == 'T')
+ goto yy291;
+ if (yych == 't')
+ goto yy291;
+ goto yy203;
+ yy252:
+ ++p;
+ { return 6; }
+ yy253:
+ yych = *++p;
+ if (yych == '>')
+ goto yy252;
+ goto yy203;
+ yy254:
+ yych = *++p;
+ if (yych == 'R')
+ goto yy292;
+ if (yych == 'r')
+ goto yy292;
+ goto yy203;
+ yy255:
+ yych = *++p;
+ if (yych == 'E')
+ goto yy293;
+ if (yych == 'e')
+ goto yy293;
+ goto yy203;
+ yy256:
+ yych = *++p;
+ if (yych == 'R')
+ goto yy294;
+ if (yych == 'r')
+ goto yy294;
+ goto yy203;
+ yy257:
+ yych = *++p;
+ if (yych <= 'C') {
+ if (yych == 'A')
+ goto yy295;
+ if (yych <= 'B')
+ goto yy203;
+ goto yy275;
+ } else {
+ if (yych <= 'a') {
+ if (yych <= '`')
+ goto yy203;
+ goto yy295;
+ } else {
+ if (yych == 'c')
+ goto yy275;
+ goto yy203;
+ }
+ }
+ yy258:
+ yych = *++p;
+ if (yych == 'Y')
+ goto yy296;
+ if (yych == 'y')
+ goto yy296;
+ goto yy203;
+ yy259:
+ yych = *++p;
+ if (yych == 'M')
+ goto yy297;
+ if (yych == 'm')
+ goto yy297;
+ goto yy203;
+ yy260:
+ yych = *++p;
+ if (yych == 'B')
+ goto yy298;
+ if (yych == 'b')
+ goto yy298;
+ goto yy203;
+ yy261:
+ yych = *++p;
+ if (yych == 'O')
+ goto yy232;
+ if (yych == 'o')
+ goto yy232;
+ goto yy203;
+ yy262:
+ yych = *++p;
+ if (yych == 'X')
+ goto yy299;
+ if (yych == 'x')
+ goto yy299;
+ goto yy203;
+ yy263:
+ yych = *++p;
+ if (yych == 'O')
+ goto yy300;
+ if (yych == 'o')
+ goto yy300;
+ goto yy203;
+ yy264:
+ yych = *++p;
+ if (yych <= '/') {
+ if (yych <= 0x1F) {
+ if (yych <= 0x08)
+ goto yy203;
+ if (yych <= '\r')
+ goto yy252;
+ goto yy203;
+ } else {
+ if (yych <= ' ')
+ goto yy252;
+ if (yych <= '.')
+ goto yy203;
+ goto yy253;
+ }
+ } else {
+ if (yych <= 'D') {
+ if (yych == '>')
+ goto yy252;
+ goto yy203;
+ } else {
+ if (yych <= 'E')
+ goto yy301;
+ if (yych == 'e')
+ goto yy301;
+ goto yy203;
+ }
+ }
+ yy265:
+ yych = *++p;
+ if (yych == 'T')
+ goto yy298;
+ if (yych == 't')
+ goto yy298;
+ goto yy203;
+ yy266:
+ yych = *++p;
+ if (yych <= '/') {
+ if (yych <= 0x1F) {
+ if (yych <= 0x08)
+ goto yy203;
+ if (yych <= '\r')
+ goto yy252;
+ goto yy203;
+ } else {
+ if (yych <= ' ')
+ goto yy252;
+ if (yych <= '.')
+ goto yy203;
+ goto yy253;
+ }
+ } else {
+ if (yych <= '@') {
+ if (yych == '>')
+ goto yy252;
+ goto yy203;
+ } else {
+ if (yych <= 'A')
+ goto yy302;
+ if (yych == 'a')
+ goto yy302;
+ goto yy203;
+ }
+ }
+ yy267:
+ ++p;
+ { return 2; }
+ yy268:
+ yych = *++p;
+ if (yych == 'D')
+ goto yy303;
+ if (yych == 'd')
+ goto yy303;
+ goto yy203;
+ yy269:
+ yych = *++p;
+ if (yych == 'R')
+ goto yy304;
+ if (yych == 'r')
+ goto yy304;
+ goto yy203;
+ yy270:
+ yych = *++p;
+ if (yych == 'I')
+ goto yy305;
+ if (yych == 'i')
+ goto yy305;
+ goto yy203;
+ yy271:
+ yych = *++p;
+ if (yych == 'D')
+ goto yy306;
+ if (yych == 'd')
+ goto yy306;
+ goto yy203;
+ yy272:
+ yych = *++p;
+ if (yych == 'E')
+ goto yy307;
+ if (yych == 'e')
+ goto yy307;
+ goto yy203;
+ yy273:
+ yych = *++p;
+ if (yych == 'C')
+ goto yy308;
+ if (yych == 'c')
+ goto yy308;
+ goto yy203;
+ yy274:
+ yych = *++p;
+ if (yych == 'Y')
+ goto yy236;
+ if (yych == 'y')
+ goto yy236;
+ goto yy203;
+ yy275:
+ yych = *++p;
+ if (yych == 'T')
+ goto yy309;
+ if (yych == 't')
+ goto yy309;
+ goto yy203;
+ yy276:
+ yych = *++p;
+ if (yych == 'T')
+ goto yy310;
+ if (yych == 't')
+ goto yy310;
+ goto yy203;
+ yy277:
+ yych = *++p;
+ if (yych <= '/') {
+ if (yych <= 0x1F) {
+ if (yych <= 0x08)
+ goto yy203;
+ if (yych <= '\r')
+ goto yy252;
+ goto yy203;
+ } else {
+ if (yych <= ' ')
+ goto yy252;
+ if (yych <= '.')
+ goto yy203;
+ goto yy253;
+ }
+ } else {
+ if (yych <= 'F') {
+ if (yych == '>')
+ goto yy252;
+ goto yy203;
+ } else {
+ if (yych <= 'G')
+ goto yy311;
+ if (yych == 'g')
+ goto yy311;
+ goto yy203;
+ }
+ }
+ yy278:
+ yych = *++p;
+ if (yych == 'A')
+ goto yy312;
+ if (yych == 'a')
+ goto yy312;
+ goto yy203;
+ yy279:
+ yych = *++p;
+ if (yych == 'L')
+ goto yy313;
+ if (yych == 'l')
+ goto yy313;
+ goto yy203;
+ yy280:
+ yych = *++p;
+ if (yych == 'L')
+ goto yy314;
+ if (yych == 'l')
+ goto yy314;
+ goto yy203;
+ yy281:
+ yych = *++p;
+ if (yych <= 'U') {
+ if (yych == 'C')
+ goto yy315;
+ if (yych <= 'T')
+ goto yy203;
+ goto yy316;
+ } else {
+ if (yych <= 'c') {
+ if (yych <= 'b')
+ goto yy203;
+ goto yy315;
+ } else {
+ if (yych == 'u')
+ goto yy316;
+ goto yy203;
+ }
+ }
+ yy282:
+ yych = *++p;
+ if (yych == 'M')
+ goto yy236;
+ if (yych == 'm')
+ goto yy236;
+ goto yy203;
+ yy283:
+ yych = *++p;
+ if (yych == 'M')
+ goto yy317;
+ if (yych == 'm')
+ goto yy317;
+ goto yy203;
+ yy284:
+ yych = *++p;
+ if (yych == 'D')
+ goto yy318;
+ if (yych == 'd')
+ goto yy318;
+ goto yy203;
+ yy285:
+ yych = *++p;
+ if (yych == 'A')
+ goto yy319;
+ if (yych == 'a')
+ goto yy319;
+ goto yy203;
+ yy286:
+ yych = *++p;
+ if (yych == 'E')
+ goto yy320;
+ if (yych == 'e')
+ goto yy320;
+ goto yy203;
+ yy287:
+ yych = *++p;
+ if (yych == 'K')
+ goto yy236;
+ if (yych == 'k')
+ goto yy236;
+ goto yy203;
+ yy288:
+ yych = *++p;
+ if (yych == 'N')
+ goto yy236;
+ if (yych == 'n')
+ goto yy236;
+ goto yy203;
+ yy289:
+ yych = *++p;
+ if (yych == 'U')
+ goto yy321;
+ if (yych == 'u')
+ goto yy321;
+ goto yy203;
+ yy290:
+ yych = *++p;
+ if (yych == 'R')
+ goto yy322;
+ if (yych == 'r')
+ goto yy322;
+ goto yy203;
+ yy291:
+ yych = *++p;
+ if (yych <= 'I') {
+ if (yych == 'G')
+ goto yy311;
+ if (yych <= 'H')
+ goto yy203;
+ goto yy323;
+ } else {
+ if (yych <= 'g') {
+ if (yych <= 'f')
+ goto yy203;
+ goto yy311;
+ } else {
+ if (yych == 'i')
+ goto yy323;
+ goto yy203;
+ }
+ }
+ yy292:
+ yych = *++p;
+ if (yych == 'A')
+ goto yy282;
+ if (yych == 'a')
+ goto yy282;
+ goto yy203;
+ yy293:
+ yych = *++p;
+ if (yych <= 0x1F) {
+ if (yych <= 0x08)
+ goto yy203;
+ if (yych <= '\r')
+ goto yy324;
+ goto yy203;
+ } else {
+ if (yych <= ' ')
+ goto yy324;
+ if (yych == '>')
+ goto yy324;
+ goto yy203;
+ }
+ yy294:
+ yych = *++p;
+ if (yych == 'I')
+ goto yy325;
+ if (yych == 'i')
+ goto yy325;
+ goto yy203;
+ yy295:
+ yych = *++p;
+ if (yych == 'R')
+ goto yy326;
+ if (yych == 'r')
+ goto yy326;
+ goto yy203;
+ yy296:
+ yych = *++p;
+ if (yych == 'L')
+ goto yy255;
+ if (yych == 'l')
+ goto yy255;
+ goto yy203;
+ yy297:
+ yych = *++p;
+ if (yych == 'M')
+ goto yy327;
+ if (yych == 'm')
+ goto yy327;
+ goto yy203;
+ yy298:
+ yych = *++p;
+ if (yych == 'L')
+ goto yy306;
+ if (yych == 'l')
+ goto yy306;
+ goto yy203;
+ yy299:
+ yych = *++p;
+ if (yych == 'T')
+ goto yy328;
+ if (yych == 't')
+ goto yy328;
+ goto yy203;
+ yy300:
+ yych = *++p;
+ if (yych == 'O')
+ goto yy329;
+ if (yych == 'o')
+ goto yy329;
+ goto yy203;
+ yy301:
+ yych = *++p;
+ if (yych == 'A')
+ goto yy330;
+ if (yych == 'a')
+ goto yy330;
+ goto yy203;
+ yy302:
+ yych = *++p;
+ if (yych == 'C')
+ goto yy287;
+ if (yych == 'c')
+ goto yy287;
+ goto yy203;
+ yy303:
+ yych = *++p;
+ if (yych == 'A')
+ goto yy331;
+ if (yych == 'a')
+ goto yy331;
+ goto yy203;
+ yy304:
+ yych = *++p;
+ if (yych == 'E')
+ goto yy332;
+ if (yych == 'e')
+ goto yy332;
+ goto yy203;
+ yy305:
+ yych = *++p;
+ if (yych == 'C')
+ goto yy298;
+ if (yych == 'c')
+ goto yy298;
+ goto yy203;
+ yy306:
+ yych = *++p;
+ if (yych == 'E')
+ goto yy236;
+ if (yych == 'e')
+ goto yy236;
+ goto yy203;
+ yy307:
+ yych = *++p;
+ if (yych <= '/') {
+ if (yych <= 0x1F) {
+ if (yych <= 0x08)
+ goto yy203;
+ if (yych <= '\r')
+ goto yy252;
+ goto yy203;
+ } else {
+ if (yych <= ' ')
+ goto yy252;
+ if (yych <= '.')
+ goto yy203;
+ goto yy253;
+ }
+ } else {
+ if (yych <= 'E') {
+ if (yych == '>')
+ goto yy252;
+ goto yy203;
+ } else {
+ if (yych <= 'F')
+ goto yy333;
+ if (yych == 'f')
+ goto yy333;
+ goto yy203;
+ }
+ }
+ yy308:
+ yych = *++p;
+ if (yych == 'K')
+ goto yy334;
+ if (yych == 'k')
+ goto yy334;
+ goto yy203;
+ yy309:
+ yych = *++p;
+ if (yych == 'I')
+ goto yy323;
+ if (yych == 'i')
+ goto yy323;
+ goto yy203;
+ yy310:
+ yych = *++p;
+ if (yych == 'E')
+ goto yy335;
+ if (yych == 'e')
+ goto yy335;
+ goto yy203;
+ yy311:
+ yych = *++p;
+ if (yych == 'R')
+ goto yy336;
+ if (yych == 'r')
+ goto yy336;
+ goto yy203;
+ yy312:
+ yych = *++p;
+ if (yych == 'I')
+ goto yy337;
+ if (yych == 'i')
+ goto yy337;
+ goto yy203;
+ yy313:
+ yych = *++p;
+ if (yych == 'O')
+ goto yy338;
+ if (yych == 'o')
+ goto yy338;
+ goto yy203;
+ yy314:
+ yych = *++p;
+ if (yych == 'D')
+ goto yy339;
+ if (yych == 'd')
+ goto yy339;
+ goto yy203;
+ yy315:
+ yych = *++p;
+ if (yych == 'A')
+ goto yy233;
+ if (yych == 'a')
+ goto yy233;
+ goto yy203;
+ yy316:
+ yych = *++p;
+ if (yych == 'R')
+ goto yy306;
+ if (yych == 'r')
+ goto yy306;
+ goto yy203;
+ yy317:
+ yych = *++p;
+ if (yych == 'E')
+ goto yy340;
+ if (yych == 'e')
+ goto yy340;
+ goto yy203;
+ yy318:
+ yych = *++p;
+ if (yych <= '/') {
+ if (yych <= 0x1F) {
+ if (yych <= 0x08)
+ goto yy203;
+ if (yych <= '\r')
+ goto yy252;
+ goto yy203;
+ } else {
+ if (yych <= ' ')
+ goto yy252;
+ if (yych <= '.')
+ goto yy203;
+ goto yy253;
+ }
+ } else {
+ if (yych <= 'D') {
+ if (yych == '>')
+ goto yy252;
+ goto yy203;
+ } else {
+ if (yych <= 'E')
+ goto yy335;
+ if (yych == 'e')
+ goto yy335;
+ goto yy203;
+ }
+ }
+ yy319:
+ yych = *++p;
+ if (yych == 'M')
+ goto yy306;
+ if (yych == 'm')
+ goto yy306;
+ goto yy203;
+ yy320:
+ yych = *++p;
+ if (yych == 'N')
+ goto yy330;
+ if (yych == 'n')
+ goto yy330;
+ goto yy203;
+ yy321:
+ yych = *++p;
+ if (yych <= '/') {
+ if (yych <= 0x1F) {
+ if (yych <= 0x08)
+ goto yy203;
+ if (yych <= '\r')
+ goto yy252;
+ goto yy203;
+ } else {
+ if (yych <= ' ')
+ goto yy252;
+ if (yych <= '.')
+ goto yy203;
+ goto yy253;
+ }
+ } else {
+ if (yych <= 'H') {
+ if (yych == '>')
+ goto yy252;
+ goto yy203;
+ } else {
+ if (yych <= 'I')
+ goto yy341;
+ if (yych == 'i')
+ goto yy341;
+ goto yy203;
+ }
+ }
+ yy322:
+ yych = *++p;
+ if (yych == 'A')
+ goto yy342;
+ if (yych == 'a')
+ goto yy342;
+ goto yy203;
+ yy323:
+ yych = *++p;
+ if (yych == 'O')
+ goto yy288;
+ if (yych == 'o')
+ goto yy288;
+ goto yy203;
+ yy324:
+ ++p;
+ { return 1; }
+ yy325:
+ yych = *++p;
+ if (yych == 'P')
+ goto yy343;
+ if (yych == 'p')
+ goto yy343;
+ goto yy203;
+ yy326:
+ yych = *++p;
+ if (yych == 'C')
+ goto yy344;
+ if (yych == 'c')
+ goto yy344;
+ goto yy203;
+ yy327:
+ yych = *++p;
+ if (yych == 'A')
+ goto yy345;
+ if (yych == 'a')
+ goto yy345;
+ goto yy203;
+ yy328:
+ yych = *++p;
+ if (yych == 'A')
+ goto yy346;
+ if (yych == 'a')
+ goto yy346;
+ goto yy203;
+ yy329:
+ yych = *++p;
+ if (yych == 'T')
+ goto yy236;
+ if (yych == 't')
+ goto yy236;
+ goto yy203;
+ yy330:
+ yych = *++p;
+ if (yych == 'D')
+ goto yy236;
+ if (yych == 'd')
+ goto yy236;
+ goto yy203;
+ yy331:
+ yych = *++p;
+ if (yych == 'T')
+ goto yy347;
+ if (yych == 't')
+ goto yy347;
+ goto yy203;
+ yy332:
+ yych = *++p;
+ if (yych == 'S')
+ goto yy348;
+ if (yych == 's')
+ goto yy348;
+ goto yy203;
+ yy333:
+ yych = *++p;
+ if (yych == 'O')
+ goto yy349;
+ if (yych == 'o')
+ goto yy349;
+ goto yy203;
+ yy334:
+ yych = *++p;
+ if (yych == 'Q')
+ goto yy350;
+ if (yych == 'q')
+ goto yy350;
+ goto yy203;
+ yy335:
+ yych = *++p;
+ if (yych == 'R')
+ goto yy236;
+ if (yych == 'r')
+ goto yy236;
+ goto yy203;
+ yy336:
+ yych = *++p;
+ if (yych == 'O')
+ goto yy351;
+ if (yych == 'o')
+ goto yy351;
+ goto yy203;
+ yy337:
+ yych = *++p;
+ if (yych == 'L')
+ goto yy348;
+ if (yych == 'l')
+ goto yy348;
+ goto yy203;
+ yy338:
+ yych = *++p;
+ if (yych == 'G')
+ goto yy236;
+ if (yych == 'g')
+ goto yy236;
+ goto yy203;
+ yy339:
+ yych = *++p;
+ if (yych == 'S')
+ goto yy352;
+ if (yych == 's')
+ goto yy352;
+ goto yy203;
+ yy340:
+ yych = *++p;
+ if (yych <= '/') {
+ if (yych <= 0x1F) {
+ if (yych <= 0x08)
+ goto yy203;
+ if (yych <= '\r')
+ goto yy252;
+ goto yy203;
+ } else {
+ if (yych <= ' ')
+ goto yy252;
+ if (yych <= '.')
+ goto yy203;
+ goto yy253;
+ }
+ } else {
+ if (yych <= 'R') {
+ if (yych == '>')
+ goto yy252;
+ goto yy203;
+ } else {
+ if (yych <= 'S')
+ goto yy352;
+ if (yych == 's')
+ goto yy352;
+ goto yy203;
+ }
+ }
+ yy341:
+ yych = *++p;
+ if (yych == 'T')
+ goto yy353;
+ if (yych == 't')
+ goto yy353;
+ goto yy203;
+ yy342:
+ yych = *++p;
+ if (yych == 'M')
+ goto yy354;
+ if (yych == 'm')
+ goto yy354;
+ goto yy203;
+ yy343:
+ yych = *++p;
+ if (yych == 'T')
+ goto yy293;
+ if (yych == 't')
+ goto yy293;
+ goto yy203;
+ yy344:
+ yych = *++p;
+ if (yych == 'H')
+ goto yy236;
+ if (yych == 'h')
+ goto yy236;
+ goto yy203;
+ yy345:
+ yych = *++p;
+ if (yych == 'R')
+ goto yy274;
+ if (yych == 'r')
+ goto yy274;
+ goto yy203;
+ yy346:
+ yych = *++p;
+ if (yych == 'R')
+ goto yy355;
+ if (yych == 'r')
+ goto yy355;
+ goto yy203;
+ yy347:
+ yych = *++p;
+ if (yych == 'A')
+ goto yy356;
+ if (yych == 'a')
+ goto yy356;
+ goto yy203;
+ yy348:
+ yych = *++p;
+ if (yych == 'S')
+ goto yy236;
+ if (yych == 's')
+ goto yy236;
+ goto yy203;
+ yy349:
+ yych = *++p;
+ if (yych == 'N')
+ goto yy329;
+ if (yych == 'n')
+ goto yy329;
+ goto yy203;
+ yy350:
+ yych = *++p;
+ if (yych == 'U')
+ goto yy357;
+ if (yych == 'u')
+ goto yy357;
+ goto yy203;
+ yy351:
+ yych = *++p;
+ if (yych == 'U')
+ goto yy358;
+ if (yych == 'u')
+ goto yy358;
+ goto yy203;
+ yy352:
+ yych = *++p;
+ if (yych == 'E')
+ goto yy329;
+ if (yych == 'e')
+ goto yy329;
+ goto yy203;
+ yy353:
+ yych = *++p;
+ if (yych == 'E')
+ goto yy282;
+ if (yych == 'e')
+ goto yy282;
+ goto yy203;
+ yy354:
+ yych = *++p;
+ if (yych == 'E')
+ goto yy348;
+ if (yych == 'e')
+ goto yy348;
+ goto yy203;
+ yy355:
+ yych = *++p;
+ if (yych == 'E')
+ goto yy359;
+ if (yych == 'e')
+ goto yy359;
+ goto yy203;
+ yy356:
+ yych = *++p;
+ if (yych == '[')
+ goto yy360;
+ goto yy203;
+ yy357:
+ yych = *++p;
+ if (yych == 'O')
+ goto yy361;
+ if (yych == 'o')
+ goto yy361;
+ goto yy203;
+ yy358:
+ yych = *++p;
+ if (yych == 'P')
+ goto yy236;
+ if (yych == 'p')
+ goto yy236;
+ goto yy203;
+ yy359:
+ yych = *++p;
+ if (yych == 'A')
+ goto yy293;
+ if (yych == 'a')
+ goto yy293;
+ goto yy203;
+ yy360:
+ ++p;
+ { return 5; }
+ yy361:
+ yych = *++p;
+ if (yych == 'T')
+ goto yy306;
+ if (yych == 't')
+ goto yy306;
+ goto yy203;
+ }
+}
+
+// Try to match an HTML block tag start line of type 7, returning
+// 7 if successful, 0 if not.
+bufsize_t _scan_html_block_start_7(const unsigned char *p) {
+ const unsigned char *marker = NULL;
+
+ {
+ unsigned char yych;
+ unsigned int yyaccept = 0;
+ static const unsigned char yybm[] = {
+ 0, 224, 224, 224, 224, 224, 224, 224, 224, 198, 210, 194, 198, 194,
+ 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224,
+ 224, 224, 224, 224, 198, 224, 128, 224, 224, 224, 224, 64, 224, 224,
+ 224, 224, 224, 233, 232, 224, 233, 233, 233, 233, 233, 233, 233, 233,
+ 233, 233, 232, 224, 192, 192, 192, 224, 224, 233, 233, 233, 233, 233,
+ 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233,
+ 233, 233, 233, 233, 233, 233, 233, 224, 224, 224, 224, 232, 192, 233,
+ 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233,
+ 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 224, 224, 224,
+ 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224,
+ 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224,
+ 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224,
+ 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224,
+ 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224,
+ 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224,
+ 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224,
+ 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224,
+ 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224,
+ 224, 224, 224, 224,
+ };
+ yych = *p;
+ if (yych == '<')
+ goto yy364;
+ ++p;
+ yy363 : { return 0; }
+ yy364:
+ yyaccept = 0;
+ yych = *(marker = ++p);
+ if (yych <= '@') {
+ if (yych != '/')
+ goto yy363;
+ } else {
+ if (yych <= 'Z')
+ goto yy366;
+ if (yych <= '`')
+ goto yy363;
+ if (yych <= 'z')
+ goto yy366;
+ goto yy363;
+ }
+ yych = *++p;
+ if (yych <= '@')
+ goto yy365;
+ if (yych <= 'Z')
+ goto yy367;
+ if (yych <= '`')
+ goto yy365;
+ if (yych <= 'z')
+ goto yy367;
+ yy365:
+ p = marker;
+ if (yyaccept == 0) {
+ goto yy363;
+ } else {
+ goto yy374;
+ }
+ yy366:
+ yych = *++p;
+ if (yybm[0 + yych] & 2) {
+ goto yy368;
+ }
+ if (yych <= '=') {
+ if (yych <= '.') {
+ if (yych == '-')
+ goto yy366;
+ goto yy365;
+ } else {
+ if (yych <= '/')
+ goto yy369;
+ if (yych <= '9')
+ goto yy366;
+ goto yy365;
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '>')
+ goto yy370;
+ if (yych <= '@')
+ goto yy365;
+ goto yy366;
+ } else {
+ if (yych <= '`')
+ goto yy365;
+ if (yych <= 'z')
+ goto yy366;
+ goto yy365;
+ }
+ }
+ yy367:
+ yych = *++p;
+ if (yych <= '/') {
+ if (yych <= 0x1F) {
+ if (yych <= 0x08)
+ goto yy365;
+ if (yych <= '\r')
+ goto yy371;
+ goto yy365;
+ } else {
+ if (yych <= ' ')
+ goto yy371;
+ if (yych == '-')
+ goto yy367;
+ goto yy365;
+ }
+ } else {
+ if (yych <= '@') {
+ if (yych <= '9')
+ goto yy367;
+ if (yych == '>')
+ goto yy370;
+ goto yy365;
+ } else {
+ if (yych <= 'Z')
+ goto yy367;
+ if (yych <= '`')
+ goto yy365;
+ if (yych <= 'z')
+ goto yy367;
+ goto yy365;
+ }
+ }
+ yy368:
+ yych = *++p;
+ if (yybm[0 + yych] & 2) {
+ goto yy368;
+ }
+ if (yych <= '>') {
+ if (yych <= '9') {
+ if (yych != '/')
+ goto yy365;
+ } else {
+ if (yych <= ':')
+ goto yy372;
+ if (yych <= '=')
+ goto yy365;
+ goto yy370;
+ }
+ } else {
+ if (yych <= '^') {
+ if (yych <= '@')
+ goto yy365;
+ if (yych <= 'Z')
+ goto yy372;
+ goto yy365;
+ } else {
+ if (yych == '`')
+ goto yy365;
+ if (yych <= 'z')
+ goto yy372;
+ goto yy365;
+ }
+ }
+ yy369:
+ yych = *++p;
+ if (yych != '>')
+ goto yy365;
+ yy370:
+ yych = *++p;
+ if (yybm[0 + yych] & 4) {
+ goto yy370;
+ }
+ if (yych <= 0x08)
+ goto yy365;
+ if (yych <= '\n')
+ goto yy373;
+ if (yych <= '\v')
+ goto yy365;
+ if (yych <= '\r')
+ goto yy375;
+ goto yy365;
+ yy371:
+ yych = *++p;
+ if (yych <= 0x1F) {
+ if (yych <= 0x08)
+ goto yy365;
+ if (yych <= '\r')
+ goto yy371;
+ goto yy365;
+ } else {
+ if (yych <= ' ')
+ goto yy371;
+ if (yych == '>')
+ goto yy370;
+ goto yy365;
+ }
+ yy372:
+ yych = *++p;
+ if (yybm[0 + yych] & 8) {
+ goto yy372;
+ }
+ if (yych <= ',') {
+ if (yych <= '\r') {
+ if (yych <= 0x08)
+ goto yy365;
+ goto yy376;
+ } else {
+ if (yych == ' ')
+ goto yy376;
+ goto yy365;
+ }
+ } else {
+ if (yych <= '<') {
+ if (yych <= '/')
+ goto yy369;
+ goto yy365;
+ } else {
+ if (yych <= '=')
+ goto yy377;
+ if (yych <= '>')
+ goto yy370;
+ goto yy365;
+ }
+ }
+ yy373:
+ yyaccept = 1;
+ yych = *(marker = ++p);
+ if (yybm[0 + yych] & 4) {
+ goto yy370;
+ }
+ if (yych <= 0x08)
+ goto yy374;
+ if (yych <= '\n')
+ goto yy373;
+ if (yych <= '\v')
+ goto yy374;
+ if (yych <= '\r')
+ goto yy375;
+ yy374 : { return 7; }
+ yy375:
+ ++p;
+ goto yy374;
+ yy376:
+ yych = *++p;
+ if (yych <= '<') {
+ if (yych <= ' ') {
+ if (yych <= 0x08)
+ goto yy365;
+ if (yych <= '\r')
+ goto yy376;
+ if (yych <= 0x1F)
+ goto yy365;
+ goto yy376;
+ } else {
+ if (yych <= '/') {
+ if (yych <= '.')
+ goto yy365;
+ goto yy369;
+ } else {
+ if (yych == ':')
+ goto yy372;
+ goto yy365;
+ }
+ }
+ } else {
+ if (yych <= 'Z') {
+ if (yych <= '=')
+ goto yy377;
+ if (yych <= '>')
+ goto yy370;
+ if (yych <= '@')
+ goto yy365;
+ goto yy372;
+ } else {
+ if (yych <= '_') {
+ if (yych <= '^')
+ goto yy365;
+ goto yy372;
+ } else {
+ if (yych <= '`')
+ goto yy365;
+ if (yych <= 'z')
+ goto yy372;
+ goto yy365;
+ }
+ }
+ }
+ yy377:
+ yych = *++p;
+ if (yybm[0 + yych] & 32) {
+ goto yy378;
+ }
+ if (yych <= 0x00)
+ goto yy365;
+ if (yych <= ' ')
+ goto yy377;
+ if (yych <= '"')
+ goto yy379;
+ if (yych <= '\'')
+ goto yy380;
+ goto yy365;
+ yy378:
+ yych = *++p;
+ if (yybm[0 + yych] & 32) {
+ goto yy378;
+ }
+ if (yych <= 0x00)
+ goto yy365;
+ if (yych <= ' ')
+ goto yy368;
+ if (yych == '>')
+ goto yy370;
+ goto yy365;
+ yy379:
+ yych = *++p;
+ if (yybm[0 + yych] & 64) {
+ goto yy379;
+ }
+ if (yych <= 0x00)
+ goto yy365;
+ goto yy381;
+ yy380:
+ yych = *++p;
+ if (yybm[0 + yych] & 128) {
+ goto yy380;
+ }
+ if (yych <= 0x00)
+ goto yy365;
+ yy381:
+ yych = *++p;
+ if (yybm[0 + yych] & 2) {
+ goto yy368;
+ }
+ if (yych == '/')
+ goto yy369;
+ if (yych == '>')
+ goto yy370;
+ goto yy365;
+ }
+}
+
+// Try to match an HTML block end line of type 1
+bufsize_t _scan_html_block_end_1(const unsigned char *p) {
+ const unsigned char *marker = NULL;
+ const unsigned char *start = p;
+
+ {
+ unsigned char yych;
+ unsigned int yyaccept = 0;
+ static const unsigned char yybm[] = {
+ 0, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 128, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64,
+ };
+ yych = *p;
+ if (yych <= '\n') {
+ if (yych <= 0x00)
+ goto yy383;
+ if (yych <= '\t')
+ goto yy385;
+ } else {
+ if (yych == '<')
+ goto yy386;
+ goto yy385;
+ }
+ yy383:
+ ++p;
+ yy384 : { return 0; }
+ yy385:
+ yyaccept = 0;
+ yych = *(marker = ++p);
+ if (yych <= 0x00)
+ goto yy384;
+ if (yych == '\n')
+ goto yy384;
+ goto yy388;
+ yy386:
+ yyaccept = 0;
+ yych = *(marker = ++p);
+ if (yych <= '\n') {
+ if (yych <= 0x00)
+ goto yy384;
+ if (yych <= '\t')
+ goto yy388;
+ goto yy384;
+ } else {
+ if (yych == '/')
+ goto yy391;
+ goto yy388;
+ }
+ yy387:
+ yych = *++p;
+ yy388:
+ if (yybm[0 + yych] & 64) {
+ goto yy387;
+ }
+ if (yych >= '\v')
+ goto yy390;
+ yy389:
+ p = marker;
+ if (yyaccept == 0) {
+ goto yy384;
+ } else {
+ goto yy404;
+ }
+ yy390:
+ yych = *++p;
+ if (yybm[0 + yych] & 128) {
+ goto yy390;
+ }
+ if (yych <= '\n') {
+ if (yych <= 0x00)
+ goto yy389;
+ if (yych <= '\t')
+ goto yy387;
+ goto yy389;
+ } else {
+ if (yych != '/')
+ goto yy387;
+ }
+ yy391:
+ yych = *++p;
+ if (yybm[0 + yych] & 128) {
+ goto yy390;
+ }
+ if (yych <= 'S') {
+ if (yych <= '\n') {
+ if (yych <= 0x00)
+ goto yy389;
+ if (yych <= '\t')
+ goto yy387;
+ goto yy389;
+ } else {
+ if (yych == 'P')
+ goto yy392;
+ if (yych <= 'R')
+ goto yy387;
+ goto yy393;
+ }
+ } else {
+ if (yych <= 'p') {
+ if (yych <= 'T')
+ goto yy394;
+ if (yych <= 'o')
+ goto yy387;
+ } else {
+ if (yych <= 'r')
+ goto yy387;
+ if (yych <= 's')
+ goto yy393;
+ if (yych <= 't')
+ goto yy394;
+ goto yy387;
+ }
+ }
+ yy392:
+ yych = *++p;
+ if (yybm[0 + yych] & 128) {
+ goto yy390;
+ }
+ if (yych <= 'Q') {
+ if (yych <= 0x00)
+ goto yy389;
+ if (yych == '\n')
+ goto yy389;
+ goto yy387;
+ } else {
+ if (yych <= 'R')
+ goto yy395;
+ if (yych == 'r')
+ goto yy395;
+ goto yy387;
+ }
+ yy393:
+ yych = *++p;
+ if (yybm[0 + yych] & 128) {
+ goto yy390;
+ }
+ if (yych <= 'S') {
+ if (yych <= '\n') {
+ if (yych <= 0x00)
+ goto yy389;
+ if (yych <= '\t')
+ goto yy387;
+ goto yy389;
+ } else {
+ if (yych == 'C')
+ goto yy396;
+ goto yy387;
+ }
+ } else {
+ if (yych <= 'c') {
+ if (yych <= 'T')
+ goto yy397;
+ if (yych <= 'b')
+ goto yy387;
+ goto yy396;
+ } else {
+ if (yych == 't')
+ goto yy397;
+ goto yy387;
+ }
+ }
+ yy394:
+ yych = *++p;
+ if (yybm[0 + yych] & 128) {
+ goto yy390;
+ }
+ if (yych <= 'D') {
+ if (yych <= 0x00)
+ goto yy389;
+ if (yych == '\n')
+ goto yy389;
+ goto yy387;
+ } else {
+ if (yych <= 'E')
+ goto yy398;
+ if (yych == 'e')
+ goto yy398;
+ goto yy387;
+ }
+ yy395:
+ yych = *++p;
+ if (yybm[0 + yych] & 128) {
+ goto yy390;
+ }
+ if (yych <= 'D') {
+ if (yych <= 0x00)
+ goto yy389;
+ if (yych == '\n')
+ goto yy389;
+ goto yy387;
+ } else {
+ if (yych <= 'E')
+ goto yy399;
+ if (yych == 'e')
+ goto yy399;
+ goto yy387;
+ }
+ yy396:
+ yych = *++p;
+ if (yybm[0 + yych] & 128) {
+ goto yy390;
+ }
+ if (yych <= 'Q') {
+ if (yych <= 0x00)
+ goto yy389;
+ if (yych == '\n')
+ goto yy389;
+ goto yy387;
+ } else {
+ if (yych <= 'R')
+ goto yy400;
+ if (yych == 'r')
+ goto yy400;
+ goto yy387;
+ }
+ yy397:
+ yych = *++p;
+ if (yybm[0 + yych] & 128) {
+ goto yy390;
+ }
+ if (yych <= 'X') {
+ if (yych <= 0x00)
+ goto yy389;
+ if (yych == '\n')
+ goto yy389;
+ goto yy387;
+ } else {
+ if (yych <= 'Y')
+ goto yy401;
+ if (yych == 'y')
+ goto yy401;
+ goto yy387;
+ }
+ yy398:
+ yych = *++p;
+ if (yybm[0 + yych] & 128) {
+ goto yy390;
+ }
+ if (yych <= 'W') {
+ if (yych <= 0x00)
+ goto yy389;
+ if (yych == '\n')
+ goto yy389;
+ goto yy387;
+ } else {
+ if (yych <= 'X')
+ goto yy402;
+ if (yych == 'x')
+ goto yy402;
+ goto yy387;
+ }
+ yy399:
+ yych = *++p;
+ if (yybm[0 + yych] & 128) {
+ goto yy390;
+ }
+ if (yych <= '\n') {
+ if (yych <= 0x00)
+ goto yy389;
+ if (yych <= '\t')
+ goto yy387;
+ goto yy389;
+ } else {
+ if (yych == '>')
+ goto yy403;
+ goto yy387;
+ }
+ yy400:
+ yych = *++p;
+ if (yybm[0 + yych] & 128) {
+ goto yy390;
+ }
+ if (yych <= 'H') {
+ if (yych <= 0x00)
+ goto yy389;
+ if (yych == '\n')
+ goto yy389;
+ goto yy387;
+ } else {
+ if (yych <= 'I')
+ goto yy405;
+ if (yych == 'i')
+ goto yy405;
+ goto yy387;
+ }
+ yy401:
+ yych = *++p;
+ if (yybm[0 + yych] & 128) {
+ goto yy390;
+ }
+ if (yych <= 'K') {
+ if (yych <= 0x00)
+ goto yy389;
+ if (yych == '\n')
+ goto yy389;
+ goto yy387;
+ } else {
+ if (yych <= 'L')
+ goto yy395;
+ if (yych == 'l')
+ goto yy395;
+ goto yy387;
+ }
+ yy402:
+ yych = *++p;
+ if (yybm[0 + yych] & 128) {
+ goto yy390;
+ }
+ if (yych <= 'S') {
+ if (yych <= 0x00)
+ goto yy389;
+ if (yych == '\n')
+ goto yy389;
+ goto yy387;
+ } else {
+ if (yych <= 'T')
+ goto yy406;
+ if (yych == 't')
+ goto yy406;
+ goto yy387;
+ }
+ yy403:
+ yyaccept = 1;
+ yych = *(marker = ++p);
+ if (yybm[0 + yych] & 64) {
+ goto yy387;
+ }
+ if (yych >= '\v')
+ goto yy390;
+ yy404 : { return (bufsize_t)(p - start); }
+ yy405:
+ yych = *++p;
+ if (yybm[0 + yych] & 128) {
+ goto yy390;
+ }
+ if (yych <= 'O') {
+ if (yych <= 0x00)
+ goto yy389;
+ if (yych == '\n')
+ goto yy389;
+ goto yy387;
+ } else {
+ if (yych <= 'P')
+ goto yy407;
+ if (yych == 'p')
+ goto yy407;
+ goto yy387;
+ }
+ yy406:
+ yych = *++p;
+ if (yybm[0 + yych] & 128) {
+ goto yy390;
+ }
+ if (yych <= '@') {
+ if (yych <= 0x00)
+ goto yy389;
+ if (yych == '\n')
+ goto yy389;
+ goto yy387;
+ } else {
+ if (yych <= 'A')
+ goto yy408;
+ if (yych == 'a')
+ goto yy408;
+ goto yy387;
+ }
+ yy407:
+ yych = *++p;
+ if (yybm[0 + yych] & 128) {
+ goto yy390;
+ }
+ if (yych <= 'S') {
+ if (yych <= 0x00)
+ goto yy389;
+ if (yych == '\n')
+ goto yy389;
+ goto yy387;
+ } else {
+ if (yych <= 'T')
+ goto yy399;
+ if (yych == 't')
+ goto yy399;
+ goto yy387;
+ }
+ yy408:
+ yych = *++p;
+ if (yybm[0 + yych] & 128) {
+ goto yy390;
+ }
+ if (yych <= 'Q') {
+ if (yych <= 0x00)
+ goto yy389;
+ if (yych == '\n')
+ goto yy389;
+ goto yy387;
+ } else {
+ if (yych <= 'R')
+ goto yy409;
+ if (yych != 'r')
+ goto yy387;
+ }
+ yy409:
+ yych = *++p;
+ if (yybm[0 + yych] & 128) {
+ goto yy390;
+ }
+ if (yych <= 'D') {
+ if (yych <= 0x00)
+ goto yy389;
+ if (yych == '\n')
+ goto yy389;
+ goto yy387;
+ } else {
+ if (yych <= 'E')
+ goto yy410;
+ if (yych != 'e')
+ goto yy387;
+ }
+ yy410:
+ yych = *++p;
+ if (yybm[0 + yych] & 128) {
+ goto yy390;
+ }
+ if (yych <= '@') {
+ if (yych <= 0x00)
+ goto yy389;
+ if (yych == '\n')
+ goto yy389;
+ goto yy387;
+ } else {
+ if (yych <= 'A')
+ goto yy399;
+ if (yych == 'a')
+ goto yy399;
+ goto yy387;
+ }
+ }
+}
+
+// Try to match an HTML block end line of type 2
+bufsize_t _scan_html_block_end_2(const unsigned char *p) {
+ const unsigned char *marker = NULL;
+ const unsigned char *start = p;
+
+ {
+ unsigned char yych;
+ unsigned int yyaccept = 0;
+ static const unsigned char yybm[] = {
+ 0, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 128, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64,
+ };
+ yych = *p;
+ if (yych <= '\n') {
+ if (yych <= 0x00)
+ goto yy412;
+ if (yych <= '\t')
+ goto yy414;
+ } else {
+ if (yych == '-')
+ goto yy415;
+ goto yy414;
+ }
+ yy412:
+ ++p;
+ yy413 : { return 0; }
+ yy414:
+ yyaccept = 0;
+ yych = *(marker = ++p);
+ if (yych <= 0x00)
+ goto yy413;
+ if (yych == '\n')
+ goto yy413;
+ goto yy417;
+ yy415:
+ yyaccept = 0;
+ yych = *(marker = ++p);
+ if (yybm[0 + yych] & 64) {
+ goto yy416;
+ }
+ if (yych <= '\n')
+ goto yy413;
+ goto yy420;
+ yy416:
+ yych = *++p;
+ yy417:
+ if (yybm[0 + yych] & 64) {
+ goto yy416;
+ }
+ if (yych >= '\v')
+ goto yy419;
+ yy418:
+ p = marker;
+ if (yyaccept == 0) {
+ goto yy413;
+ } else {
+ goto yy421;
+ }
+ yy419:
+ yych = *++p;
+ if (yybm[0 + yych] & 64) {
+ goto yy416;
+ }
+ if (yych <= '\n')
+ goto yy418;
+ yy420:
+ yych = *++p;
+ if (yybm[0 + yych] & 128) {
+ goto yy420;
+ }
+ if (yych <= '\n') {
+ if (yych <= 0x00)
+ goto yy418;
+ if (yych <= '\t')
+ goto yy416;
+ goto yy418;
+ } else {
+ if (yych != '>')
+ goto yy416;
+ }
+ yyaccept = 1;
+ yych = *(marker = ++p);
+ if (yybm[0 + yych] & 64) {
+ goto yy416;
+ }
+ if (yych >= '\v')
+ goto yy419;
+ yy421 : { return (bufsize_t)(p - start); }
+ }
+}
+
+// Try to match an HTML block end line of type 3
+bufsize_t _scan_html_block_end_3(const unsigned char *p) {
+ const unsigned char *marker = NULL;
+ const unsigned char *start = p;
+
+ {
+ unsigned char yych;
+ unsigned int yyaccept = 0;
+ static const unsigned char yybm[] = {
+ 0, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 128, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64,
+ };
+ yych = *p;
+ if (yych <= '\n') {
+ if (yych <= 0x00)
+ goto yy423;
+ if (yych <= '\t')
+ goto yy425;
+ } else {
+ if (yych == '?')
+ goto yy426;
+ goto yy425;
+ }
+ yy423:
+ ++p;
+ yy424 : { return 0; }
+ yy425:
+ yyaccept = 0;
+ yych = *(marker = ++p);
+ if (yych <= 0x00)
+ goto yy424;
+ if (yych == '\n')
+ goto yy424;
+ goto yy428;
+ yy426:
+ yyaccept = 0;
+ yych = *(marker = ++p);
+ if (yych <= '\n') {
+ if (yych <= 0x00)
+ goto yy424;
+ if (yych <= '\t')
+ goto yy428;
+ goto yy424;
+ } else {
+ if (yych == '>')
+ goto yy431;
+ goto yy428;
+ }
+ yy427:
+ yych = *++p;
+ yy428:
+ if (yybm[0 + yych] & 64) {
+ goto yy427;
+ }
+ if (yych >= '\v')
+ goto yy430;
+ yy429:
+ p = marker;
+ if (yyaccept == 0) {
+ goto yy424;
+ } else {
+ goto yy432;
+ }
+ yy430:
+ yych = *++p;
+ if (yybm[0 + yych] & 128) {
+ goto yy430;
+ }
+ if (yych <= '\n') {
+ if (yych <= 0x00)
+ goto yy429;
+ if (yych <= '\t')
+ goto yy427;
+ goto yy429;
+ } else {
+ if (yych != '>')
+ goto yy427;
+ }
+ yy431:
+ yyaccept = 1;
+ yych = *(marker = ++p);
+ if (yybm[0 + yych] & 64) {
+ goto yy427;
+ }
+ if (yych >= '\v')
+ goto yy430;
+ yy432 : { return (bufsize_t)(p - start); }
+ }
+}
+
+// Try to match an HTML block end line of type 4
+bufsize_t _scan_html_block_end_4(const unsigned char *p) {
+ const unsigned char *marker = NULL;
+ const unsigned char *start = p;
+
+ {
+ unsigned char yych;
+ unsigned int yyaccept = 0;
+ static const unsigned char yybm[] = {
+ 0, 128, 128, 128, 128, 128, 128, 128, 128, 128, 0, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 64, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128,
+ };
+ yych = *p;
+ if (yybm[0 + yych] & 64) {
+ goto yy437;
+ }
+ if (yych <= 0x00)
+ goto yy434;
+ if (yych != '\n')
+ goto yy436;
+ yy434:
+ ++p;
+ yy435 : { return 0; }
+ yy436:
+ yyaccept = 0;
+ yych = *(marker = ++p);
+ if (yych <= 0x00)
+ goto yy435;
+ if (yych == '\n')
+ goto yy435;
+ goto yy440;
+ yy437:
+ yyaccept = 1;
+ yych = *(marker = ++p);
+ if (yybm[0 + yych] & 128) {
+ goto yy439;
+ }
+ if (yych >= '\v')
+ goto yy437;
+ yy438 : { return (bufsize_t)(p - start); }
+ yy439:
+ yych = *++p;
+ yy440:
+ if (yybm[0 + yych] & 128) {
+ goto yy439;
+ }
+ if (yych >= '\v')
+ goto yy437;
+ p = marker;
+ if (yyaccept == 0) {
+ goto yy435;
+ } else {
+ goto yy438;
+ }
+ }
+}
+
+// Try to match an HTML block end line of type 5
+bufsize_t _scan_html_block_end_5(const unsigned char *p) {
+ const unsigned char *marker = NULL;
+ const unsigned char *start = p;
+
+ {
+ unsigned char yych;
+ unsigned int yyaccept = 0;
+ static const unsigned char yybm[] = {
+ 0, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 128, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64,
+ };
+ yych = *p;
+ if (yych <= '\n') {
+ if (yych <= 0x00)
+ goto yy442;
+ if (yych <= '\t')
+ goto yy444;
+ } else {
+ if (yych == ']')
+ goto yy445;
+ goto yy444;
+ }
+ yy442:
+ ++p;
+ yy443 : { return 0; }
+ yy444:
+ yyaccept = 0;
+ yych = *(marker = ++p);
+ if (yych <= 0x00)
+ goto yy443;
+ if (yych == '\n')
+ goto yy443;
+ goto yy447;
+ yy445:
+ yyaccept = 0;
+ yych = *(marker = ++p);
+ if (yybm[0 + yych] & 64) {
+ goto yy446;
+ }
+ if (yych <= '\n')
+ goto yy443;
+ goto yy450;
+ yy446:
+ yych = *++p;
+ yy447:
+ if (yybm[0 + yych] & 64) {
+ goto yy446;
+ }
+ if (yych >= '\v')
+ goto yy449;
+ yy448:
+ p = marker;
+ if (yyaccept == 0) {
+ goto yy443;
+ } else {
+ goto yy451;
+ }
+ yy449:
+ yych = *++p;
+ if (yybm[0 + yych] & 64) {
+ goto yy446;
+ }
+ if (yych <= '\n')
+ goto yy448;
+ yy450:
+ yych = *++p;
+ if (yybm[0 + yych] & 128) {
+ goto yy450;
+ }
+ if (yych <= '\n') {
+ if (yych <= 0x00)
+ goto yy448;
+ if (yych <= '\t')
+ goto yy446;
+ goto yy448;
+ } else {
+ if (yych != '>')
+ goto yy446;
+ }
+ yyaccept = 1;
+ yych = *(marker = ++p);
+ if (yybm[0 + yych] & 64) {
+ goto yy446;
+ }
+ if (yych >= '\v')
+ goto yy449;
+ yy451 : { return (bufsize_t)(p - start); }
+ }
+}
+
+// Try to match a link title (in single quotes, in double quotes, or
+// in parentheses), returning number of chars matched. Allow one
+// level of internal nesting (quotes within quotes).
+bufsize_t _scan_link_title(const unsigned char *p) {
+ const unsigned char *marker = NULL;
+ const unsigned char *start = p;
+
+ {
+ unsigned char yych;
+ unsigned int yyaccept = 0;
+ static const unsigned char yybm[] = {
+ 0, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208,
+ 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208,
+ 208, 208, 208, 208, 208, 208, 192, 208, 208, 208, 208, 144, 80, 80,
+ 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208,
+ 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208,
+ 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208,
+ 208, 208, 208, 208, 208, 208, 208, 208, 32, 208, 208, 208, 208, 208,
+ 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208,
+ 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208,
+ 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208,
+ 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208,
+ 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208,
+ 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208,
+ 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208,
+ 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208,
+ 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208,
+ 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208,
+ 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208,
+ 208, 208, 208, 208,
+ };
+ yych = *p;
+ if (yych <= '&') {
+ if (yych == '"')
+ goto yy454;
+ } else {
+ if (yych <= '\'')
+ goto yy455;
+ if (yych <= '(')
+ goto yy456;
+ }
+ ++p;
+ yy453 : { return 0; }
+ yy454:
+ yyaccept = 0;
+ yych = *(marker = ++p);
+ if (yych <= 0x00)
+ goto yy453;
+ goto yy458;
+ yy455:
+ yyaccept = 0;
+ yych = *(marker = ++p);
+ if (yych <= 0x00)
+ goto yy453;
+ goto yy464;
+ yy456:
+ yyaccept = 0;
+ yych = *(marker = ++p);
+ if (yych <= 0x00)
+ goto yy453;
+ if (yych == '(')
+ goto yy453;
+ goto yy469;
+ yy457:
+ yych = *++p;
+ yy458:
+ if (yybm[0 + yych] & 16) {
+ goto yy457;
+ }
+ if (yych <= 0x00)
+ goto yy459;
+ if (yych <= '"')
+ goto yy460;
+ goto yy462;
+ yy459:
+ p = marker;
+ if (yyaccept <= 1) {
+ if (yyaccept == 0) {
+ goto yy453;
+ } else {
+ goto yy461;
+ }
+ } else {
+ if (yyaccept == 2) {
+ goto yy466;
+ } else {
+ goto yy471;
+ }
+ }
+ yy460:
+ ++p;
+ yy461 : { return (bufsize_t)(p - start); }
+ yy462:
+ yych = *++p;
+ if (yybm[0 + yych] & 16) {
+ goto yy457;
+ }
+ if (yych <= 0x00)
+ goto yy459;
+ if (yych <= '"')
+ goto yy473;
+ goto yy462;
+ yy463:
+ yych = *++p;
+ yy464:
+ if (yybm[0 + yych] & 64) {
+ goto yy463;
+ }
+ if (yych <= 0x00)
+ goto yy459;
+ if (yych >= '(')
+ goto yy467;
+ yy465:
+ ++p;
+ yy466 : { return (bufsize_t)(p - start); }
+ yy467:
+ yych = *++p;
+ if (yybm[0 + yych] & 64) {
+ goto yy463;
+ }
+ if (yych <= 0x00)
+ goto yy459;
+ if (yych <= '\'')
+ goto yy474;
+ goto yy467;
+ yy468:
+ yych = *++p;
+ yy469:
+ if (yybm[0 + yych] & 128) {
+ goto yy468;
+ }
+ if (yych <= '(')
+ goto yy459;
+ if (yych >= '*')
+ goto yy472;
+ yy470:
+ ++p;
+ yy471 : { return (bufsize_t)(p - start); }
+ yy472:
+ yych = *++p;
+ if (yych <= ')') {
+ if (yych <= 0x00)
+ goto yy459;
+ if (yych <= '(')
+ goto yy468;
+ goto yy475;
+ } else {
+ if (yych == '\\')
+ goto yy472;
+ goto yy468;
+ }
+ yy473:
+ yyaccept = 1;
+ yych = *(marker = ++p);
+ if (yybm[0 + yych] & 16) {
+ goto yy457;
+ }
+ if (yych <= 0x00)
+ goto yy461;
+ if (yych <= '"')
+ goto yy460;
+ goto yy462;
+ yy474:
+ yyaccept = 2;
+ yych = *(marker = ++p);
+ if (yybm[0 + yych] & 64) {
+ goto yy463;
+ }
+ if (yych <= 0x00)
+ goto yy466;
+ if (yych <= '\'')
+ goto yy465;
+ goto yy467;
+ yy475:
+ yyaccept = 3;
+ yych = *(marker = ++p);
+ if (yybm[0 + yych] & 128) {
+ goto yy468;
+ }
+ if (yych <= '(')
+ goto yy471;
+ if (yych <= ')')
+ goto yy470;
+ goto yy472;
+ }
+}
+
+// Match space characters, including newlines.
+bufsize_t _scan_spacechars(const unsigned char *p) {
+ const unsigned char *start = p;
+
+ {
+ unsigned char yych;
+ static const unsigned char yybm[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ };
+ yych = *p;
+ if (yybm[0 + yych] & 128) {
+ goto yy477;
+ }
+ ++p;
+ { return 0; }
+ yy477:
+ yych = *++p;
+ if (yybm[0 + yych] & 128) {
+ goto yy477;
+ }
+ { return (bufsize_t)(p - start); }
+ }
+}
+
+// Match ATX heading start.
+bufsize_t _scan_atx_heading_start(const unsigned char *p) {
+ const unsigned char *marker = NULL;
+ const unsigned char *start = p;
+
+ {
+ unsigned char yych;
+ static const unsigned char yybm[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ };
+ yych = *p;
+ if (yych == '#')
+ goto yy480;
+ ++p;
+ yy479 : { return 0; }
+ yy480:
+ yych = *(marker = ++p);
+ if (yybm[0 + yych] & 128) {
+ goto yy481;
+ }
+ if (yych <= '\f') {
+ if (yych <= 0x08)
+ goto yy479;
+ if (yych <= '\n')
+ goto yy483;
+ goto yy479;
+ } else {
+ if (yych <= '\r')
+ goto yy483;
+ if (yych == '#')
+ goto yy484;
+ goto yy479;
+ }
+ yy481:
+ yych = *++p;
+ if (yybm[0 + yych] & 128) {
+ goto yy481;
+ }
+ yy482 : { return (bufsize_t)(p - start); }
+ yy483:
+ ++p;
+ goto yy482;
+ yy484:
+ yych = *++p;
+ if (yybm[0 + yych] & 128) {
+ goto yy481;
+ }
+ if (yych <= '\f') {
+ if (yych <= 0x08)
+ goto yy485;
+ if (yych <= '\n')
+ goto yy483;
+ } else {
+ if (yych <= '\r')
+ goto yy483;
+ if (yych == '#')
+ goto yy486;
+ }
+ yy485:
+ p = marker;
+ goto yy479;
+ yy486:
+ yych = *++p;
+ if (yybm[0 + yych] & 128) {
+ goto yy481;
+ }
+ if (yych <= '\f') {
+ if (yych <= 0x08)
+ goto yy485;
+ if (yych <= '\n')
+ goto yy483;
+ goto yy485;
+ } else {
+ if (yych <= '\r')
+ goto yy483;
+ if (yych != '#')
+ goto yy485;
+ }
+ yych = *++p;
+ if (yybm[0 + yych] & 128) {
+ goto yy481;
+ }
+ if (yych <= '\f') {
+ if (yych <= 0x08)
+ goto yy485;
+ if (yych <= '\n')
+ goto yy483;
+ goto yy485;
+ } else {
+ if (yych <= '\r')
+ goto yy483;
+ if (yych != '#')
+ goto yy485;
+ }
+ yych = *++p;
+ if (yybm[0 + yych] & 128) {
+ goto yy481;
+ }
+ if (yych <= '\f') {
+ if (yych <= 0x08)
+ goto yy485;
+ if (yych <= '\n')
+ goto yy483;
+ goto yy485;
+ } else {
+ if (yych <= '\r')
+ goto yy483;
+ if (yych != '#')
+ goto yy485;
+ }
+ yych = *++p;
+ if (yybm[0 + yych] & 128) {
+ goto yy481;
+ }
+ if (yych <= 0x08)
+ goto yy485;
+ if (yych <= '\n')
+ goto yy483;
+ if (yych == '\r')
+ goto yy483;
+ goto yy485;
+ }
+}
+
+// Match setext heading line. Return 1 for level-1 heading,
+// 2 for level-2, 0 for no match.
+bufsize_t _scan_setext_heading_line(const unsigned char *p) {
+ const unsigned char *marker = NULL;
+
+ {
+ unsigned char yych;
+ static const unsigned char yybm[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ };
+ yych = *p;
+ if (yych == '-')
+ goto yy489;
+ if (yych == '=')
+ goto yy490;
+ ++p;
+ yy488 : { return 0; }
+ yy489:
+ yych = *(marker = ++p);
+ if (yybm[0 + yych] & 64) {
+ goto yy495;
+ }
+ if (yych <= '\f') {
+ if (yych <= 0x08)
+ goto yy488;
+ if (yych <= '\n')
+ goto yy492;
+ goto yy488;
+ } else {
+ if (yych <= '\r')
+ goto yy492;
+ if (yych == ' ')
+ goto yy492;
+ goto yy488;
+ }
+ yy490:
+ yych = *(marker = ++p);
+ if (yybm[0 + yych] & 128) {
+ goto yy499;
+ }
+ if (yych <= '\f') {
+ if (yych <= 0x08)
+ goto yy488;
+ if (yych <= '\n')
+ goto yy497;
+ goto yy488;
+ } else {
+ if (yych <= '\r')
+ goto yy497;
+ if (yych == ' ')
+ goto yy497;
+ goto yy488;
+ }
+ yy491:
+ yych = *++p;
+ yy492:
+ if (yybm[0 + yych] & 32) {
+ goto yy491;
+ }
+ if (yych <= 0x08)
+ goto yy493;
+ if (yych <= '\n')
+ goto yy494;
+ if (yych == '\r')
+ goto yy494;
+ yy493:
+ p = marker;
+ goto yy488;
+ yy494:
+ ++p;
+ { return 2; }
+ yy495:
+ yych = *++p;
+ if (yybm[0 + yych] & 32) {
+ goto yy491;
+ }
+ if (yych <= '\f') {
+ if (yych <= 0x08)
+ goto yy493;
+ if (yych <= '\n')
+ goto yy494;
+ goto yy493;
+ } else {
+ if (yych <= '\r')
+ goto yy494;
+ if (yych == '-')
+ goto yy495;
+ goto yy493;
+ }
+ yy496:
+ yych = *++p;
+ yy497:
+ if (yych <= '\f') {
+ if (yych <= 0x08)
+ goto yy493;
+ if (yych <= '\t')
+ goto yy496;
+ if (yych >= '\v')
+ goto yy493;
+ } else {
+ if (yych <= '\r')
+ goto yy498;
+ if (yych == ' ')
+ goto yy496;
+ goto yy493;
+ }
+ yy498:
+ ++p;
+ { return 1; }
+ yy499:
+ yych = *++p;
+ if (yybm[0 + yych] & 128) {
+ goto yy499;
+ }
+ if (yych <= '\f') {
+ if (yych <= 0x08)
+ goto yy493;
+ if (yych <= '\t')
+ goto yy496;
+ if (yych <= '\n')
+ goto yy498;
+ goto yy493;
+ } else {
+ if (yych <= '\r')
+ goto yy498;
+ if (yych == ' ')
+ goto yy496;
+ goto yy493;
+ }
+ }
+}
+
+// Scan an opening code fence.
+bufsize_t _scan_open_code_fence(const unsigned char *p) {
+ const unsigned char *marker = NULL;
+ const unsigned char *start = p;
+
+ {
+ unsigned char yych;
+ static const unsigned char yybm[] = {
+ 0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, 192, 192, 0,
+ 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
+ 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
+ 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
+ 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
+ 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
+ 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 144, 192,
+ 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
+ 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
+ 224, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
+ 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
+ 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
+ 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
+ 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
+ 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
+ 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
+ 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
+ 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
+ 192, 192, 192, 192,
+ };
+ yych = *p;
+ if (yych == '`')
+ goto yy502;
+ if (yych == '~')
+ goto yy503;
+ ++p;
+ yy501 : { return 0; }
+ yy502:
+ yych = *(marker = ++p);
+ if (yych == '`')
+ goto yy504;
+ goto yy501;
+ yy503:
+ yych = *(marker = ++p);
+ if (yych == '~')
+ goto yy506;
+ goto yy501;
+ yy504:
+ yych = *++p;
+ if (yybm[0 + yych] & 16) {
+ goto yy507;
+ }
+ yy505:
+ p = marker;
+ goto yy501;
+ yy506:
+ yych = *++p;
+ if (yybm[0 + yych] & 32) {
+ goto yy508;
+ }
+ goto yy505;
+ yy507:
+ yych = *++p;
+ if (yybm[0 + yych] & 16) {
+ goto yy507;
+ }
+ if (yych <= '\n') {
+ if (yych <= 0x00)
+ goto yy505;
+ if (yych <= '\t') {
+ marker = p;
+ goto yy509;
+ }
+ marker = p;
+ goto yy510;
+ } else {
+ if (yych == '\r') {
+ marker = p;
+ goto yy510;
+ }
+ marker = p;
+ goto yy509;
+ }
+ yy508:
+ yych = *++p;
+ if (yybm[0 + yych] & 32) {
+ goto yy508;
+ }
+ if (yych <= '\n') {
+ if (yych <= 0x00)
+ goto yy505;
+ if (yych <= '\t') {
+ marker = p;
+ goto yy511;
+ }
+ marker = p;
+ goto yy512;
+ } else {
+ if (yych == '\r') {
+ marker = p;
+ goto yy512;
+ }
+ marker = p;
+ goto yy511;
+ }
+ yy509:
+ yych = *++p;
+ if (yybm[0 + yych] & 64) {
+ goto yy509;
+ }
+ if (yych <= 0x00)
+ goto yy505;
+ if (yych >= 0x0E)
+ goto yy505;
+ yy510:
+ ++p;
+ p = marker;
+ { return (bufsize_t)(p - start); }
+ yy511:
+ yych = *++p;
+ if (yybm[0 + yych] & 128) {
+ goto yy511;
+ }
+ if (yych <= 0x00)
+ goto yy505;
+ yy512:
+ ++p;
+ p = marker;
+ { return (bufsize_t)(p - start); }
+ }
+}
+
+// Scan a closing code fence with length at least len.
+bufsize_t _scan_close_code_fence(const unsigned char *p) {
+ const unsigned char *marker = NULL;
+ const unsigned char *start = p;
+
+ {
+ unsigned char yych;
+ static const unsigned char yybm[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ };
+ yych = *p;
+ if (yych == '`')
+ goto yy515;
+ if (yych == '~')
+ goto yy516;
+ ++p;
+ yy514 : { return 0; }
+ yy515:
+ yych = *(marker = ++p);
+ if (yych == '`')
+ goto yy517;
+ goto yy514;
+ yy516:
+ yych = *(marker = ++p);
+ if (yych == '~')
+ goto yy519;
+ goto yy514;
+ yy517:
+ yych = *++p;
+ if (yybm[0 + yych] & 32) {
+ goto yy520;
+ }
+ yy518:
+ p = marker;
+ goto yy514;
+ yy519:
+ yych = *++p;
+ if (yybm[0 + yych] & 64) {
+ goto yy521;
+ }
+ goto yy518;
+ yy520:
+ yych = *++p;
+ if (yybm[0 + yych] & 32) {
+ goto yy520;
+ }
+ if (yych <= '\f') {
+ if (yych <= 0x08)
+ goto yy518;
+ if (yych <= '\t') {
+ marker = p;
+ goto yy522;
+ }
+ if (yych <= '\n') {
+ marker = p;
+ goto yy523;
+ }
+ goto yy518;
+ } else {
+ if (yych <= '\r') {
+ marker = p;
+ goto yy523;
+ }
+ if (yych == ' ') {
+ marker = p;
+ goto yy522;
+ }
+ goto yy518;
+ }
+ yy521:
+ yych = *++p;
+ if (yybm[0 + yych] & 64) {
+ goto yy521;
+ }
+ if (yych <= '\f') {
+ if (yych <= 0x08)
+ goto yy518;
+ if (yych <= '\t') {
+ marker = p;
+ goto yy524;
+ }
+ if (yych <= '\n') {
+ marker = p;
+ goto yy525;
+ }
+ goto yy518;
+ } else {
+ if (yych <= '\r') {
+ marker = p;
+ goto yy525;
+ }
+ if (yych == ' ') {
+ marker = p;
+ goto yy524;
+ }
+ goto yy518;
+ }
+ yy522:
+ yych = *++p;
+ if (yybm[0 + yych] & 128) {
+ goto yy522;
+ }
+ if (yych <= 0x08)
+ goto yy518;
+ if (yych <= '\n')
+ goto yy523;
+ if (yych != '\r')
+ goto yy518;
+ yy523:
+ ++p;
+ p = marker;
+ { return (bufsize_t)(p - start); }
+ yy524:
+ yych = *++p;
+ if (yych <= '\f') {
+ if (yych <= 0x08)
+ goto yy518;
+ if (yych <= '\t')
+ goto yy524;
+ if (yych >= '\v')
+ goto yy518;
+ } else {
+ if (yych <= '\r')
+ goto yy525;
+ if (yych == ' ')
+ goto yy524;
+ goto yy518;
+ }
+ yy525:
+ ++p;
+ p = marker;
+ { return (bufsize_t)(p - start); }
+ }
+}
+
+// Returns positive value if a URL begins in a way that is potentially
+// dangerous, with javascript:, vbscript:, file:, or data:, otherwise 0.
+bufsize_t _scan_dangerous_url(const unsigned char *p) {
+ const unsigned char *marker = NULL;
+ const unsigned char *start = p;
+
+ {
+ unsigned char yych;
+ unsigned int yyaccept = 0;
+ yych = *p;
+ if (yych <= 'V') {
+ if (yych <= 'F') {
+ if (yych == 'D')
+ goto yy528;
+ if (yych >= 'F')
+ goto yy529;
+ } else {
+ if (yych == 'J')
+ goto yy530;
+ if (yych >= 'V')
+ goto yy531;
+ }
+ } else {
+ if (yych <= 'f') {
+ if (yych == 'd')
+ goto yy528;
+ if (yych >= 'f')
+ goto yy529;
+ } else {
+ if (yych <= 'j') {
+ if (yych >= 'j')
+ goto yy530;
+ } else {
+ if (yych == 'v')
+ goto yy531;
+ }
+ }
+ }
+ ++p;
+ yy527 : { return 0; }
+ yy528:
+ yyaccept = 0;
+ yych = *(marker = ++p);
+ if (yych == 'A')
+ goto yy532;
+ if (yych == 'a')
+ goto yy532;
+ goto yy527;
+ yy529:
+ yyaccept = 0;
+ yych = *(marker = ++p);
+ if (yych == 'I')
+ goto yy534;
+ if (yych == 'i')
+ goto yy534;
+ goto yy527;
+ yy530:
+ yyaccept = 0;
+ yych = *(marker = ++p);
+ if (yych == 'A')
+ goto yy535;
+ if (yych == 'a')
+ goto yy535;
+ goto yy527;
+ yy531:
+ yyaccept = 0;
+ yych = *(marker = ++p);
+ if (yych == 'B')
+ goto yy536;
+ if (yych == 'b')
+ goto yy536;
+ goto yy527;
+ yy532:
+ yych = *++p;
+ if (yych == 'T')
+ goto yy537;
+ if (yych == 't')
+ goto yy537;
+ yy533:
+ p = marker;
+ if (yyaccept == 0) {
+ goto yy527;
+ } else {
+ goto yy545;
+ }
+ yy534:
+ yych = *++p;
+ if (yych == 'L')
+ goto yy538;
+ if (yych == 'l')
+ goto yy538;
+ goto yy533;
+ yy535:
+ yych = *++p;
+ if (yych == 'V')
+ goto yy539;
+ if (yych == 'v')
+ goto yy539;
+ goto yy533;
+ yy536:
+ yych = *++p;
+ if (yych == 'S')
+ goto yy540;
+ if (yych == 's')
+ goto yy540;
+ goto yy533;
+ yy537:
+ yych = *++p;
+ if (yych == 'A')
+ goto yy541;
+ if (yych == 'a')
+ goto yy541;
+ goto yy533;
+ yy538:
+ yych = *++p;
+ if (yych == 'E')
+ goto yy542;
+ if (yych == 'e')
+ goto yy542;
+ goto yy533;
+ yy539:
+ yych = *++p;
+ if (yych == 'A')
+ goto yy536;
+ if (yych == 'a')
+ goto yy536;
+ goto yy533;
+ yy540:
+ yych = *++p;
+ if (yych == 'C')
+ goto yy543;
+ if (yych == 'c')
+ goto yy543;
+ goto yy533;
+ yy541:
+ yych = *++p;
+ if (yych == ':')
+ goto yy544;
+ goto yy533;
+ yy542:
+ yych = *++p;
+ if (yych == ':')
+ goto yy546;
+ goto yy533;
+ yy543:
+ yych = *++p;
+ if (yych == 'R')
+ goto yy547;
+ if (yych == 'r')
+ goto yy547;
+ goto yy533;
+ yy544:
+ yyaccept = 1;
+ yych = *(marker = ++p);
+ if (yych == 'I')
+ goto yy548;
+ if (yych == 'i')
+ goto yy548;
+ yy545 : { return (bufsize_t)(p - start); }
+ yy546:
+ ++p;
+ goto yy545;
+ yy547:
+ yych = *++p;
+ if (yych == 'I')
+ goto yy549;
+ if (yych == 'i')
+ goto yy549;
+ goto yy533;
+ yy548:
+ yych = *++p;
+ if (yych == 'M')
+ goto yy550;
+ if (yych == 'm')
+ goto yy550;
+ goto yy533;
+ yy549:
+ yych = *++p;
+ if (yych == 'P')
+ goto yy551;
+ if (yych == 'p')
+ goto yy551;
+ goto yy533;
+ yy550:
+ yych = *++p;
+ if (yych == 'A')
+ goto yy552;
+ if (yych == 'a')
+ goto yy552;
+ goto yy533;
+ yy551:
+ yych = *++p;
+ if (yych == 'T')
+ goto yy542;
+ if (yych == 't')
+ goto yy542;
+ goto yy533;
+ yy552:
+ yych = *++p;
+ if (yych == 'G')
+ goto yy553;
+ if (yych != 'g')
+ goto yy533;
+ yy553:
+ yych = *++p;
+ if (yych == 'E')
+ goto yy554;
+ if (yych != 'e')
+ goto yy533;
+ yy554:
+ yych = *++p;
+ if (yych != '/')
+ goto yy533;
+ yych = *++p;
+ if (yych <= 'W') {
+ if (yych <= 'J') {
+ if (yych == 'G')
+ goto yy555;
+ if (yych <= 'I')
+ goto yy533;
+ goto yy556;
+ } else {
+ if (yych == 'P')
+ goto yy557;
+ if (yych <= 'V')
+ goto yy533;
+ goto yy558;
+ }
+ } else {
+ if (yych <= 'j') {
+ if (yych == 'g')
+ goto yy555;
+ if (yych <= 'i')
+ goto yy533;
+ goto yy556;
+ } else {
+ if (yych <= 'p') {
+ if (yych <= 'o')
+ goto yy533;
+ goto yy557;
+ } else {
+ if (yych == 'w')
+ goto yy558;
+ goto yy533;
+ }
+ }
+ }
+ yy555:
+ yych = *++p;
+ if (yych == 'I')
+ goto yy559;
+ if (yych == 'i')
+ goto yy559;
+ goto yy533;
+ yy556:
+ yych = *++p;
+ if (yych == 'P')
+ goto yy560;
+ if (yych == 'p')
+ goto yy560;
+ goto yy533;
+ yy557:
+ yych = *++p;
+ if (yych == 'N')
+ goto yy561;
+ if (yych == 'n')
+ goto yy561;
+ goto yy533;
+ yy558:
+ yych = *++p;
+ if (yych == 'E')
+ goto yy562;
+ if (yych == 'e')
+ goto yy562;
+ goto yy533;
+ yy559:
+ yych = *++p;
+ if (yych == 'F')
+ goto yy563;
+ if (yych == 'f')
+ goto yy563;
+ goto yy533;
+ yy560:
+ yych = *++p;
+ if (yych == 'E')
+ goto yy561;
+ if (yych != 'e')
+ goto yy533;
+ yy561:
+ yych = *++p;
+ if (yych == 'G')
+ goto yy563;
+ if (yych == 'g')
+ goto yy563;
+ goto yy533;
+ yy562:
+ yych = *++p;
+ if (yych == 'B')
+ goto yy564;
+ if (yych == 'b')
+ goto yy564;
+ goto yy533;
+ yy563:
+ ++p;
+ { return 0; }
+ yy564:
+ yych = *++p;
+ if (yych == 'P')
+ goto yy563;
+ if (yych == 'p')
+ goto yy563;
+ goto yy533;
+ }
+}
diff --git a/cmark/src/scanners.h b/cmark/src/scanners.h
new file mode 100644
index 0000000000..27f927342a
--- /dev/null
+++ b/cmark/src/scanners.h
@@ -0,0 +1,59 @@
+#include "cmark.h"
+#include "chunk.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+bufsize_t _scan_at(bufsize_t (*scanner)(const unsigned char *), cmark_chunk *c,
+ bufsize_t offset);
+bufsize_t _scan_scheme(const unsigned char *p);
+bufsize_t _scan_autolink_uri(const unsigned char *p);
+bufsize_t _scan_autolink_email(const unsigned char *p);
+bufsize_t _scan_html_tag(const unsigned char *p);
+bufsize_t _scan_html_comment(const unsigned char *p);
+bufsize_t _scan_html_pi(const unsigned char *p);
+bufsize_t _scan_html_declaration(const unsigned char *p);
+bufsize_t _scan_html_cdata(const unsigned char *p);
+bufsize_t _scan_html_block_start(const unsigned char *p);
+bufsize_t _scan_html_block_start_7(const unsigned char *p);
+bufsize_t _scan_html_block_end_1(const unsigned char *p);
+bufsize_t _scan_html_block_end_2(const unsigned char *p);
+bufsize_t _scan_html_block_end_3(const unsigned char *p);
+bufsize_t _scan_html_block_end_4(const unsigned char *p);
+bufsize_t _scan_html_block_end_5(const unsigned char *p);
+bufsize_t _scan_link_title(const unsigned char *p);
+bufsize_t _scan_spacechars(const unsigned char *p);
+bufsize_t _scan_atx_heading_start(const unsigned char *p);
+bufsize_t _scan_setext_heading_line(const unsigned char *p);
+bufsize_t _scan_open_code_fence(const unsigned char *p);
+bufsize_t _scan_close_code_fence(const unsigned char *p);
+bufsize_t _scan_dangerous_url(const unsigned char *p);
+
+#define scan_scheme(c, n) _scan_at(&_scan_scheme, c, n)
+#define scan_autolink_uri(c, n) _scan_at(&_scan_autolink_uri, c, n)
+#define scan_autolink_email(c, n) _scan_at(&_scan_autolink_email, c, n)
+#define scan_html_tag(c, n) _scan_at(&_scan_html_tag, c, n)
+#define scan_html_comment(c, n) _scan_at(&_scan_html_comment, c, n)
+#define scan_html_pi(c, n) _scan_at(&_scan_html_pi, c, n)
+#define scan_html_declaration(c, n) _scan_at(&_scan_html_declaration, c, n)
+#define scan_html_cdata(c, n) _scan_at(&_scan_html_cdata, c, n)
+#define scan_html_block_start(c, n) _scan_at(&_scan_html_block_start, c, n)
+#define scan_html_block_start_7(c, n) _scan_at(&_scan_html_block_start_7, c, n)
+#define scan_html_block_end_1(c, n) _scan_at(&_scan_html_block_end_1, c, n)
+#define scan_html_block_end_2(c, n) _scan_at(&_scan_html_block_end_2, c, n)
+#define scan_html_block_end_3(c, n) _scan_at(&_scan_html_block_end_3, c, n)
+#define scan_html_block_end_4(c, n) _scan_at(&_scan_html_block_end_4, c, n)
+#define scan_html_block_end_5(c, n) _scan_at(&_scan_html_block_end_5, c, n)
+#define scan_link_title(c, n) _scan_at(&_scan_link_title, c, n)
+#define scan_spacechars(c, n) _scan_at(&_scan_spacechars, c, n)
+#define scan_atx_heading_start(c, n) _scan_at(&_scan_atx_heading_start, c, n)
+#define scan_setext_heading_line(c, n) \
+ _scan_at(&_scan_setext_heading_line, c, n)
+#define scan_open_code_fence(c, n) _scan_at(&_scan_open_code_fence, c, n)
+#define scan_close_code_fence(c, n) _scan_at(&_scan_close_code_fence, c, n)
+#define scan_dangerous_url(c, n) _scan_at(&_scan_dangerous_url, c, n)
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/cmark/src/scanners.re b/cmark/src/scanners.re
new file mode 100644
index 0000000000..16238b7745
--- /dev/null
+++ b/cmark/src/scanners.re
@@ -0,0 +1,330 @@
+#include <stdlib.h>
+#include "chunk.h"
+#include "scanners.h"
+
+bufsize_t _scan_at(bufsize_t (*scanner)(const unsigned char *), cmark_chunk *c, bufsize_t offset)
+{
+ bufsize_t res;
+ unsigned char *ptr = (unsigned char *)c->data;
+
+ if (ptr == NULL || offset > c->len) {
+ return 0;
+ } else {
+ unsigned char lim = ptr[c->len];
+
+ ptr[c->len] = '\0';
+ res = scanner(ptr + offset);
+ ptr[c->len] = lim;
+ }
+
+ return res;
+}
+
+/*!re2c
+ re2c:define:YYCTYPE = "unsigned char";
+ re2c:define:YYCURSOR = p;
+ re2c:define:YYMARKER = marker;
+ re2c:define:YYCTXMARKER = marker;
+ re2c:yyfill:enable = 0;
+
+ spacechar = [ \t\v\f\r\n];
+
+ reg_char = [^\\()\x00-\x20];
+
+ escaped_char = [\\][!"#$%&'()*+,./:;<=>?@[\\\]^_`{|}~-];
+
+ tagname = [A-Za-z][A-Za-z0-9-]*;
+
+ blocktagname = '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'|'search'|'title'|'summary'|'table'|'tbody'|'td'|'tfoot'|'th'|'thead'|'title'|'tr'|'track'|'ul';
+
+ attributename = [a-zA-Z_:][a-zA-Z0-9:._-]*;
+
+ unquotedvalue = [^ \t\r\n\v\f"'=<>`\x00]+;
+ singlequotedvalue = ['][^'\x00]*['];
+ doublequotedvalue = ["][^"\x00]*["];
+
+ attributevalue = unquotedvalue | singlequotedvalue | doublequotedvalue;
+
+ attributevaluespec = spacechar* [=] spacechar* attributevalue;
+
+ attribute = spacechar+ attributename attributevaluespec?;
+
+ opentag = tagname attribute* spacechar* [/]? [>];
+ closetag = [/] tagname spacechar* [>];
+
+ htmlcomment = "--" ([^\x00-]+ | "-" [^\x00-] | "--" [^\x00>])* "-->";
+
+ processinginstruction = ([^?>\x00]+ | [?][^>\x00] | [>])+;
+
+ declaration = [A-Za-z]+ [^>\x00]*;
+
+ cdata = "CDATA[" ([^\]\x00]+ | "]" [^\]\x00] | "]]" [^>\x00])*;
+
+ htmltag = opentag | closetag;
+
+ in_parens_nosp = [(] (reg_char|escaped_char|[\\])* [)];
+
+ in_double_quotes = ["] (escaped_char|[^"\x00])* ["];
+ in_single_quotes = ['] (escaped_char|[^'\x00])* ['];
+ in_parens = [(] (escaped_char|[^)\x00])* [)];
+
+ scheme = [A-Za-z][A-Za-z0-9.+-]{1,31};
+*/
+
+// Try to match a scheme including colon.
+bufsize_t _scan_scheme(const unsigned char *p)
+{
+ const unsigned char *marker = NULL;
+ const unsigned char *start = p;
+/*!re2c
+ scheme [:] { return (bufsize_t)(p - start); }
+ * { return 0; }
+*/
+}
+
+// Try to match URI autolink after first <, returning number of chars matched.
+bufsize_t _scan_autolink_uri(const unsigned char *p)
+{
+ const unsigned char *marker = NULL;
+ const unsigned char *start = p;
+/*!re2c
+ scheme [:][^\x00-\x20<>]*[>] { return (bufsize_t)(p - start); }
+ * { return 0; }
+*/
+}
+
+// Try to match email autolink after first <, returning num of chars matched.
+bufsize_t _scan_autolink_email(const unsigned char *p)
+{
+ const unsigned char *marker = NULL;
+ const unsigned char *start = p;
+/*!re2c
+ [a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+
+ [@]
+ [a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?
+ ([.][a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*
+ [>] { return (bufsize_t)(p - start); }
+ * { return 0; }
+*/
+}
+
+// Try to match an HTML tag after first <, returning num of chars matched.
+bufsize_t _scan_html_tag(const unsigned char *p)
+{
+ const unsigned char *marker = NULL;
+ const unsigned char *start = p;
+/*!re2c
+ htmltag { return (bufsize_t)(p - start); }
+ * { return 0; }
+*/
+}
+
+bufsize_t _scan_html_comment(const unsigned char *p)
+{
+ const unsigned char *marker = NULL;
+ const unsigned char *start = p;
+/*!re2c
+ htmlcomment { return (bufsize_t)(p - start); }
+ * { return 0; }
+*/
+}
+
+bufsize_t _scan_html_pi(const unsigned char *p)
+{
+ const unsigned char *marker = NULL;
+ const unsigned char *start = p;
+/*!re2c
+ processinginstruction { return (bufsize_t)(p - start); }
+ * { return 0; }
+*/
+}
+
+bufsize_t _scan_html_declaration(const unsigned char *p)
+{
+ const unsigned char *marker = NULL;
+ const unsigned char *start = p;
+ (void) marker;
+/*!re2c
+ declaration { return (bufsize_t)(p - start); }
+ * { return 0; }
+*/
+}
+
+bufsize_t _scan_html_cdata(const unsigned char *p)
+{
+ const unsigned char *marker = NULL;
+ const unsigned char *start = p;
+/*!re2c
+ cdata { return (bufsize_t)(p - start); }
+ * { return 0; }
+*/
+}
+
+// Try to match an HTML block tag start line, returning
+// an integer code for the type of block (1-6, matching the spec).
+// #7 is handled by a separate function, below.
+bufsize_t _scan_html_block_start(const unsigned char *p)
+{
+ const unsigned char *marker = NULL;
+/*!re2c
+ [<] ('script'|'pre'|'textarea'|'style') (spacechar | [>]) { return 1; }
+ '<!--' { return 2; }
+ '<?' { return 3; }
+ '<!' [A-Za-z] { return 4; }
+ '<![CDATA[' { return 5; }
+ [<] [/]? blocktagname (spacechar | [/]? [>]) { return 6; }
+ * { return 0; }
+*/
+}
+
+// Try to match an HTML block tag start line of type 7, returning
+// 7 if successful, 0 if not.
+bufsize_t _scan_html_block_start_7(const unsigned char *p)
+{
+ const unsigned char *marker = NULL;
+/*!re2c
+ [<] (opentag | closetag) [\t\n\f ]* [\r\n] { return 7; }
+ * { return 0; }
+*/
+}
+
+// Try to match an HTML block end line of type 1
+bufsize_t _scan_html_block_end_1(const unsigned char *p)
+{
+ const unsigned char *marker = NULL;
+ const unsigned char *start = p;
+/*!re2c
+ [^\n\x00]* [<] [/] ('script'|'pre'|'textarea'|'style') [>] { return (bufsize_t)(p - start); }
+ * { return 0; }
+*/
+}
+
+// Try to match an HTML block end line of type 2
+bufsize_t _scan_html_block_end_2(const unsigned char *p)
+{
+ const unsigned char *marker = NULL;
+ const unsigned char *start = p;
+/*!re2c
+ [^\n\x00]* '-->' { return (bufsize_t)(p - start); }
+ * { return 0; }
+*/
+}
+
+// Try to match an HTML block end line of type 3
+bufsize_t _scan_html_block_end_3(const unsigned char *p)
+{
+ const unsigned char *marker = NULL;
+ const unsigned char *start = p;
+/*!re2c
+ [^\n\x00]* '?>' { return (bufsize_t)(p - start); }
+ * { return 0; }
+*/
+}
+
+// Try to match an HTML block end line of type 4
+bufsize_t _scan_html_block_end_4(const unsigned char *p)
+{
+ const unsigned char *marker = NULL;
+ const unsigned char *start = p;
+/*!re2c
+ [^\n\x00]* '>' { return (bufsize_t)(p - start); }
+ * { return 0; }
+*/
+}
+
+// Try to match an HTML block end line of type 5
+bufsize_t _scan_html_block_end_5(const unsigned char *p)
+{
+ const unsigned char *marker = NULL;
+ const unsigned char *start = p;
+/*!re2c
+ [^\n\x00]* ']]>' { return (bufsize_t)(p - start); }
+ * { return 0; }
+*/
+}
+
+// Try to match a link title (in single quotes, in double quotes, or
+// in parentheses), returning number of chars matched. Allow one
+// level of internal nesting (quotes within quotes).
+bufsize_t _scan_link_title(const unsigned char *p)
+{
+ const unsigned char *marker = NULL;
+ const unsigned char *start = p;
+/*!re2c
+ ["] (escaped_char|[^"\x00])* ["] { return (bufsize_t)(p - start); }
+ ['] (escaped_char|[^'\x00])* ['] { return (bufsize_t)(p - start); }
+ [(] (escaped_char|[^()\x00])* [)] { return (bufsize_t)(p - start); }
+ * { return 0; }
+*/
+}
+
+// Match space characters, including newlines.
+bufsize_t _scan_spacechars(const unsigned char *p)
+{
+ const unsigned char *start = p; \
+/*!re2c
+ [ \t\v\f\r\n]+ { return (bufsize_t)(p - start); }
+ * { return 0; }
+*/
+}
+
+// Match ATX heading start.
+bufsize_t _scan_atx_heading_start(const unsigned char *p)
+{
+ const unsigned char *marker = NULL;
+ const unsigned char *start = p;
+/*!re2c
+ [#]{1,6} ([ \t]+|[\r\n]) { return (bufsize_t)(p - start); }
+ * { return 0; }
+*/
+}
+
+// Match setext heading line. Return 1 for level-1 heading,
+// 2 for level-2, 0 for no match.
+bufsize_t _scan_setext_heading_line(const unsigned char *p)
+{
+ const unsigned char *marker = NULL;
+/*!re2c
+ [=]+ [ \t]* [\r\n] { return 1; }
+ [-]+ [ \t]* [\r\n] { return 2; }
+ * { return 0; }
+*/
+}
+
+// Scan an opening code fence.
+bufsize_t _scan_open_code_fence(const unsigned char *p)
+{
+ const unsigned char *marker = NULL;
+ const unsigned char *start = p;
+/*!re2c
+ [`]{3,} / [^`\r\n\x00]*[\r\n] { return (bufsize_t)(p - start); }
+ [~]{3,} / [^\r\n\x00]*[\r\n] { return (bufsize_t)(p - start); }
+ * { return 0; }
+*/
+}
+
+// Scan a closing code fence with length at least len.
+bufsize_t _scan_close_code_fence(const unsigned char *p)
+{
+ const unsigned char *marker = NULL;
+ const unsigned char *start = p;
+/*!re2c
+ [`]{3,} / [ \t]*[\r\n] { return (bufsize_t)(p - start); }
+ [~]{3,} / [ \t]*[\r\n] { return (bufsize_t)(p - start); }
+ * { return 0; }
+*/
+}
+
+// Returns positive value if a URL begins in a way that is potentially
+// dangerous, with javascript:, vbscript:, file:, or data:, otherwise 0.
+bufsize_t _scan_dangerous_url(const unsigned char *p)
+{
+ const unsigned char *marker = NULL;
+ const unsigned char *start = p;
+/*!re2c
+ 'data:image/' ('png'|'gif'|'jpeg'|'webp') { return 0; }
+ 'javascript:' | 'vbscript:' | 'file:' | 'data:' { return (bufsize_t)(p - start); }
+ * { return 0; }
+*/
+}
+
diff --git a/cmark/src/utf8.c b/cmark/src/utf8.c
new file mode 100644
index 0000000000..48697c77d7
--- /dev/null
+++ b/cmark/src/utf8.c
@@ -0,0 +1,428 @@
+#include <stdlib.h>
+#include <stdint.h>
+#include <assert.h>
+
+#include "cmark_ctype.h"
+#include "utf8.h"
+
+static const int8_t utf8proc_utf8class[256] = {
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0};
+
+static void encode_unknown(cmark_strbuf *buf) {
+ static const uint8_t repl[] = {239, 191, 189};
+ cmark_strbuf_put(buf, repl, 3);
+}
+
+static int utf8proc_charlen(const uint8_t *str, bufsize_t str_len) {
+ int length, i;
+
+ if (!str_len)
+ return 0;
+
+ length = utf8proc_utf8class[str[0]];
+
+ if (!length)
+ return -1;
+
+ if (str_len >= 0 && (bufsize_t)length > str_len)
+ return -str_len;
+
+ for (i = 1; i < length; i++) {
+ if ((str[i] & 0xC0) != 0x80)
+ return -i;
+ }
+
+ return length;
+}
+
+// Validate a single UTF-8 character according to RFC 3629.
+static int utf8proc_valid(const uint8_t *str, bufsize_t str_len) {
+ int length = utf8proc_utf8class[str[0]];
+
+ if (!length)
+ return -1;
+
+ if ((bufsize_t)length > str_len)
+ return -str_len;
+
+ switch (length) {
+ case 2:
+ if ((str[1] & 0xC0) != 0x80)
+ return -1;
+ if (str[0] < 0xC2) {
+ // Overlong
+ return -length;
+ }
+ break;
+
+ case 3:
+ if ((str[1] & 0xC0) != 0x80)
+ return -1;
+ if ((str[2] & 0xC0) != 0x80)
+ return -2;
+ if (str[0] == 0xE0) {
+ if (str[1] < 0xA0) {
+ // Overlong
+ return -length;
+ }
+ } else if (str[0] == 0xED) {
+ if (str[1] >= 0xA0) {
+ // Surrogate
+ return -length;
+ }
+ }
+ break;
+
+ case 4:
+ if ((str[1] & 0xC0) != 0x80)
+ return -1;
+ if ((str[2] & 0xC0) != 0x80)
+ return -2;
+ if ((str[3] & 0xC0) != 0x80)
+ return -3;
+ if (str[0] == 0xF0) {
+ if (str[1] < 0x90) {
+ // Overlong
+ return -length;
+ }
+ } else if (str[0] >= 0xF4) {
+ if (str[0] > 0xF4 || str[1] >= 0x90) {
+ // Above 0x10FFFF
+ return -length;
+ }
+ }
+ break;
+ }
+
+ return length;
+}
+
+void cmark_utf8proc_check(cmark_strbuf *ob, const uint8_t *line,
+ bufsize_t size) {
+ bufsize_t i = 0;
+
+ while (i < size) {
+ bufsize_t org = i;
+ int charlen = 0;
+
+ while (i < size) {
+ if (line[i] < 0x80 && line[i] != 0) {
+ i++;
+ } else if (line[i] >= 0x80) {
+ charlen = utf8proc_valid(line + i, size - i);
+ if (charlen < 0) {
+ charlen = -charlen;
+ break;
+ }
+ i += charlen;
+ } else if (line[i] == 0) {
+ // ASCII NUL is technically valid but rejected
+ // for security reasons.
+ charlen = 1;
+ break;
+ }
+ }
+
+ if (i > org) {
+ cmark_strbuf_put(ob, line + org, i - org);
+ }
+
+ if (i >= size) {
+ break;
+ } else {
+ // Invalid UTF-8
+ encode_unknown(ob);
+ i += charlen;
+ }
+ }
+}
+
+int cmark_utf8proc_iterate(const uint8_t *str, bufsize_t str_len,
+ int32_t *dst) {
+ int length;
+ int32_t uc = -1;
+
+ *dst = -1;
+ length = utf8proc_charlen(str, str_len);
+ if (length < 0)
+ return -1;
+
+ switch (length) {
+ case 1:
+ uc = str[0];
+ break;
+ case 2:
+ uc = ((str[0] & 0x1F) << 6) + (str[1] & 0x3F);
+ if (uc < 0x80)
+ uc = -1;
+ break;
+ case 3:
+ uc = ((str[0] & 0x0F) << 12) + ((str[1] & 0x3F) << 6) + (str[2] & 0x3F);
+ if (uc < 0x800 || (uc >= 0xD800 && uc < 0xE000))
+ uc = -1;
+ break;
+ case 4:
+ uc = ((str[0] & 0x07) << 18) + ((str[1] & 0x3F) << 12) +
+ ((str[2] & 0x3F) << 6) + (str[3] & 0x3F);
+ if (uc < 0x10000 || uc >= 0x110000)
+ uc = -1;
+ break;
+ }
+
+ if (uc < 0)
+ return -1;
+
+ *dst = uc;
+ return length;
+}
+
+void cmark_utf8proc_encode_char(int32_t uc, cmark_strbuf *buf) {
+ uint8_t dst[4];
+ bufsize_t len = 0;
+
+ assert(uc >= 0);
+
+ if (uc < 0x80) {
+ dst[0] = (uint8_t)(uc);
+ len = 1;
+ } else if (uc < 0x800) {
+ dst[0] = (uint8_t)(0xC0 + (uc >> 6));
+ dst[1] = 0x80 + (uc & 0x3F);
+ len = 2;
+ } else if (uc < 0x10000) {
+ dst[0] = (uint8_t)(0xE0 + (uc >> 12));
+ dst[1] = 0x80 + ((uc >> 6) & 0x3F);
+ dst[2] = 0x80 + (uc & 0x3F);
+ len = 3;
+ } else if (uc < 0x110000) {
+ dst[0] = (uint8_t)(0xF0 + (uc >> 18));
+ dst[1] = 0x80 + ((uc >> 12) & 0x3F);
+ dst[2] = 0x80 + ((uc >> 6) & 0x3F);
+ dst[3] = 0x80 + (uc & 0x3F);
+ len = 4;
+ } else {
+ encode_unknown(buf);
+ return;
+ }
+
+ cmark_strbuf_put(buf, dst, len);
+}
+
+#include "case_fold.inc"
+
+int cf_compare(const void *v1, const void *v2) {
+ uint32_t entry1 = *(uint32_t *) v1;
+ uint32_t entry2 = *(uint32_t *) v2;
+
+ return (int32_t) CF_CODE_POINT(entry1) - (int32_t) CF_CODE_POINT(entry2);
+}
+
+void cmark_utf8proc_case_fold(cmark_strbuf *dest, const uint8_t *str,
+ bufsize_t len) {
+ int32_t c;
+
+ while (len > 0) {
+ bufsize_t char_len = cmark_utf8proc_iterate(str, len, &c);
+
+ if (char_len == 1) {
+ if (c >= 'A' && c <= 'Z')
+ c += 'a' - 'A';
+ cmark_strbuf_putc(dest, c);
+ } else if (c >= CF_MAX) {
+ cmark_strbuf_put(dest, str, char_len);
+ } else if (char_len >= 0) {
+ uint32_t key = c;
+ uint32_t *entry = bsearch(&key, cf_table,
+ CF_TABLE_SIZE, sizeof(uint32_t),
+ cf_compare);
+ if (entry == NULL) {
+ cmark_strbuf_put(dest, str, char_len);
+ } else {
+ cmark_strbuf_put(dest, cf_repl + CF_REPL_IDX(*entry),
+ CF_REPL_SIZE(*entry));
+ }
+ } else {
+ encode_unknown(dest);
+ char_len = -char_len;
+ }
+
+ str += char_len;
+ len -= char_len;
+ }
+}
+
+// matches anything in the Zs class, plus LF, CR, TAB, FF.
+int cmark_utf8proc_is_space(int32_t uc) {
+ return (uc == 9 || uc == 10 || uc == 12 || uc == 13 || uc == 32 ||
+ uc == 160 || uc == 5760 || (uc >= 8192 && uc <= 8202) || uc == 8239 ||
+ uc == 8287 || uc == 12288);
+}
+
+// matches anything in the P or S classes.
+int cmark_utf8proc_is_punctuation_or_symbol(int32_t uc) {
+ if (uc < 128) {
+ return cmark_ispunct((char)uc);
+ } else {
+ return (
+ uc > 128 &&
+ ((uc >= 161 && uc <= 169) || (uc >= 171 && uc <= 172) ||
+ (uc >= 174 && uc <= 177) || (uc == 180) || (uc >= 182 && uc <= 184) ||
+ (uc == 187) || (uc == 191) || (uc == 215) || (uc == 247) ||
+ (uc >= 706 && uc <= 709) || (uc >= 722 && uc <= 735) ||
+ (uc >= 741 && uc <= 747) || (uc == 749) || (uc >= 751 && uc <= 767) ||
+ (uc == 885) || (uc == 894) || (uc >= 900 && uc <= 901) ||
+ (uc == 903) || (uc == 1014) || (uc == 1154) ||
+ (uc >= 1370 && uc <= 1375) || (uc >= 1417 && uc <= 1418) ||
+ (uc >= 1421 && uc <= 1423) || (uc == 1470) || (uc == 1472) ||
+ (uc == 1475) || (uc == 1478) || (uc >= 1523 && uc <= 1524) ||
+ (uc >= 1542 && uc <= 1551) || (uc == 1563) ||
+ (uc >= 1565 && uc <= 1567) || (uc >= 1642 && uc <= 1645) ||
+ (uc == 1748) || (uc == 1758) || (uc == 1769) ||
+ (uc >= 1789 && uc <= 1790) || (uc >= 1792 && uc <= 1805) ||
+ (uc >= 2038 && uc <= 2041) || (uc >= 2046 && uc <= 2047) ||
+ (uc >= 2096 && uc <= 2110) || (uc == 2142) || (uc == 2184) ||
+ (uc >= 2404 && uc <= 2405) || (uc == 2416) ||
+ (uc >= 2546 && uc <= 2547) || (uc >= 2554 && uc <= 2555) ||
+ (uc == 2557) || (uc == 2678) || (uc >= 2800 && uc <= 2801) ||
+ (uc == 2928) || (uc >= 3059 && uc <= 3066) || (uc == 3191) ||
+ (uc == 3199) || (uc == 3204) || (uc == 3407) || (uc == 3449) ||
+ (uc == 3572) || (uc == 3647) || (uc == 3663) ||
+ (uc >= 3674 && uc <= 3675) || (uc >= 3841 && uc <= 3863) ||
+ (uc >= 3866 && uc <= 3871) || (uc == 3892) || (uc == 3894) ||
+ (uc == 3896) || (uc >= 3898 && uc <= 3901) || (uc == 3973) ||
+ (uc >= 4030 && uc <= 4037) || (uc >= 4039 && uc <= 4044) ||
+ (uc >= 4046 && uc <= 4058) || (uc >= 4170 && uc <= 4175) ||
+ (uc >= 4254 && uc <= 4255) || (uc == 4347) ||
+ (uc >= 4960 && uc <= 4968) || (uc >= 5008 && uc <= 5017) ||
+ (uc == 5120) || (uc >= 5741 && uc <= 5742) ||
+ (uc >= 5787 && uc <= 5788) || (uc >= 5867 && uc <= 5869) ||
+ (uc >= 5941 && uc <= 5942) || (uc >= 6100 && uc <= 6102) ||
+ (uc >= 6104 && uc <= 6107) || (uc >= 6144 && uc <= 6154) ||
+ (uc == 6464) || (uc >= 6468 && uc <= 6469) ||
+ (uc >= 6622 && uc <= 6655) || (uc >= 6686 && uc <= 6687) ||
+ (uc >= 6816 && uc <= 6822) || (uc >= 6824 && uc <= 6829) ||
+ (uc >= 7002 && uc <= 7018) || (uc >= 7028 && uc <= 7038) ||
+ (uc >= 7164 && uc <= 7167) || (uc >= 7227 && uc <= 7231) ||
+ (uc >= 7294 && uc <= 7295) || (uc >= 7360 && uc <= 7367) ||
+ (uc == 7379) || (uc == 8125) || (uc >= 8127 && uc <= 8129) ||
+ (uc >= 8141 && uc <= 8143) || (uc >= 8157 && uc <= 8159) ||
+ (uc >= 8173 && uc <= 8175) || (uc >= 8189 && uc <= 8190) ||
+ (uc >= 8208 && uc <= 8231) || (uc >= 8240 && uc <= 8286) ||
+ (uc >= 8314 && uc <= 8318) || (uc >= 8330 && uc <= 8334) ||
+ (uc >= 8352 && uc <= 8384) || (uc >= 8448 && uc <= 8449) ||
+ (uc >= 8451 && uc <= 8454) || (uc >= 8456 && uc <= 8457) ||
+ (uc == 8468) || (uc >= 8470 && uc <= 8472) ||
+ (uc >= 8478 && uc <= 8483) || (uc == 8485) || (uc == 8487) ||
+ (uc == 8489) || (uc == 8494) || (uc >= 8506 && uc <= 8507) ||
+ (uc >= 8512 && uc <= 8516) || (uc >= 8522 && uc <= 8525) ||
+ (uc == 8527) || (uc >= 8586 && uc <= 8587) ||
+ (uc >= 8592 && uc <= 9254) || (uc >= 9280 && uc <= 9290) ||
+ (uc >= 9372 && uc <= 9449) || (uc >= 9472 && uc <= 10101) ||
+ (uc >= 10132 && uc <= 11123) || (uc >= 11126 && uc <= 11157) ||
+ (uc >= 11159 && uc <= 11263) || (uc >= 11493 && uc <= 11498) ||
+ (uc >= 11513 && uc <= 11516) || (uc >= 11518 && uc <= 11519) ||
+ (uc == 11632) || (uc >= 11776 && uc <= 11822) ||
+ (uc >= 11824 && uc <= 11869) || (uc >= 11904 && uc <= 11929) ||
+ (uc >= 11931 && uc <= 12019) || (uc >= 12032 && uc <= 12245) ||
+ (uc >= 12272 && uc <= 12283) || (uc >= 12289 && uc <= 12292) ||
+ (uc >= 12296 && uc <= 12320) || (uc == 12336) ||
+ (uc >= 12342 && uc <= 12343) || (uc >= 12349 && uc <= 12351) ||
+ (uc >= 12443 && uc <= 12444) || (uc == 12448) || (uc == 12539) ||
+ (uc >= 12688 && uc <= 12689) || (uc >= 12694 && uc <= 12703) ||
+ (uc >= 12736 && uc <= 12771) || (uc >= 12800 && uc <= 12830) ||
+ (uc >= 12842 && uc <= 12871) || (uc == 12880) ||
+ (uc >= 12896 && uc <= 12927) || (uc >= 12938 && uc <= 12976) ||
+ (uc >= 12992 && uc <= 13311) || (uc >= 19904 && uc <= 19967) ||
+ (uc >= 42128 && uc <= 42182) || (uc >= 42238 && uc <= 42239) ||
+ (uc >= 42509 && uc <= 42511) || (uc == 42611) || (uc == 42622) ||
+ (uc >= 42738 && uc <= 42743) || (uc >= 42752 && uc <= 42774) ||
+ (uc >= 42784 && uc <= 42785) || (uc >= 42889 && uc <= 42890) ||
+ (uc >= 43048 && uc <= 43051) || (uc >= 43062 && uc <= 43065) ||
+ (uc >= 43124 && uc <= 43127) || (uc >= 43214 && uc <= 43215) ||
+ (uc >= 43256 && uc <= 43258) || (uc == 43260) ||
+ (uc >= 43310 && uc <= 43311) || (uc == 43359) ||
+ (uc >= 43457 && uc <= 43469) || (uc >= 43486 && uc <= 43487) ||
+ (uc >= 43612 && uc <= 43615) || (uc >= 43639 && uc <= 43641) ||
+ (uc >= 43742 && uc <= 43743) || (uc >= 43760 && uc <= 43761) ||
+ (uc == 43867) || (uc >= 43882 && uc <= 43883) || (uc == 44011) ||
+ (uc == 64297) || (uc >= 64434 && uc <= 64450) ||
+ (uc >= 64830 && uc <= 64847) || (uc == 64975) ||
+ (uc >= 65020 && uc <= 65023) || (uc >= 65040 && uc <= 65049) ||
+ (uc >= 65072 && uc <= 65106) || (uc >= 65108 && uc <= 65126) ||
+ (uc >= 65128 && uc <= 65131) || (uc >= 65281 && uc <= 65295) ||
+ (uc >= 65306 && uc <= 65312) || (uc >= 65339 && uc <= 65344) ||
+ (uc >= 65371 && uc <= 65381) || (uc >= 65504 && uc <= 65510) ||
+ (uc >= 65512 && uc <= 65518) || (uc >= 65532 && uc <= 65533) ||
+ (uc >= 65792 && uc <= 65794) || (uc >= 65847 && uc <= 65855) ||
+ (uc >= 65913 && uc <= 65929) || (uc >= 65932 && uc <= 65934) ||
+ (uc >= 65936 && uc <= 65948) || (uc == 65952) ||
+ (uc >= 66000 && uc <= 66044) || (uc == 66463) || (uc == 66512) ||
+ (uc == 66927) || (uc == 67671) || (uc >= 67703 && uc <= 67704) ||
+ (uc == 67871) || (uc == 67903) || (uc >= 68176 && uc <= 68184) ||
+ (uc == 68223) || (uc == 68296) || (uc >= 68336 && uc <= 68342) ||
+ (uc >= 68409 && uc <= 68415) || (uc >= 68505 && uc <= 68508) ||
+ (uc == 69293) || (uc >= 69461 && uc <= 69465) ||
+ (uc >= 69510 && uc <= 69513) || (uc >= 69703 && uc <= 69709) ||
+ (uc >= 69819 && uc <= 69820) || (uc >= 69822 && uc <= 69825) ||
+ (uc >= 69952 && uc <= 69955) || (uc >= 70004 && uc <= 70005) ||
+ (uc >= 70085 && uc <= 70088) || (uc == 70093) || (uc == 70107) ||
+ (uc >= 70109 && uc <= 70111) || (uc >= 70200 && uc <= 70205) ||
+ (uc == 70313) || (uc >= 70731 && uc <= 70735) ||
+ (uc >= 70746 && uc <= 70747) || (uc == 70749) || (uc == 70854) ||
+ (uc >= 71105 && uc <= 71127) || (uc >= 71233 && uc <= 71235) ||
+ (uc >= 71264 && uc <= 71276) || (uc == 71353) ||
+ (uc >= 71484 && uc <= 71487) || (uc == 71739) ||
+ (uc >= 72004 && uc <= 72006) || (uc == 72162) ||
+ (uc >= 72255 && uc <= 72262) || (uc >= 72346 && uc <= 72348) ||
+ (uc >= 72350 && uc <= 72354) || (uc >= 72448 && uc <= 72457) ||
+ (uc >= 72769 && uc <= 72773) || (uc >= 72816 && uc <= 72817) ||
+ (uc >= 73463 && uc <= 73464) || (uc >= 73539 && uc <= 73551) ||
+ (uc >= 73685 && uc <= 73713) || (uc == 73727) ||
+ (uc >= 74864 && uc <= 74868) || (uc >= 77809 && uc <= 77810) ||
+ (uc >= 92782 && uc <= 92783) || (uc == 92917) ||
+ (uc >= 92983 && uc <= 92991) || (uc >= 92996 && uc <= 92997) ||
+ (uc >= 93847 && uc <= 93850) || (uc == 94178) || (uc == 113820) ||
+ (uc == 113823) || (uc >= 118608 && uc <= 118723) ||
+ (uc >= 118784 && uc <= 119029) || (uc >= 119040 && uc <= 119078) ||
+ (uc >= 119081 && uc <= 119140) || (uc >= 119146 && uc <= 119148) ||
+ (uc >= 119171 && uc <= 119172) || (uc >= 119180 && uc <= 119209) ||
+ (uc >= 119214 && uc <= 119274) || (uc >= 119296 && uc <= 119361) ||
+ (uc == 119365) || (uc >= 119552 && uc <= 119638) || (uc == 120513) ||
+ (uc == 120539) || (uc == 120571) || (uc == 120597) || (uc == 120629) ||
+ (uc == 120655) || (uc == 120687) || (uc == 120713) || (uc == 120745) ||
+ (uc == 120771) || (uc >= 120832 && uc <= 121343) ||
+ (uc >= 121399 && uc <= 121402) || (uc >= 121453 && uc <= 121460) ||
+ (uc >= 121462 && uc <= 121475) || (uc >= 121477 && uc <= 121483) ||
+ (uc == 123215) || (uc == 123647) || (uc >= 125278 && uc <= 125279) ||
+ (uc == 126124) || (uc == 126128) || (uc == 126254) ||
+ (uc >= 126704 && uc <= 126705) || (uc >= 126976 && uc <= 127019) ||
+ (uc >= 127024 && uc <= 127123) || (uc >= 127136 && uc <= 127150) ||
+ (uc >= 127153 && uc <= 127167) || (uc >= 127169 && uc <= 127183) ||
+ (uc >= 127185 && uc <= 127221) || (uc >= 127245 && uc <= 127405) ||
+ (uc >= 127462 && uc <= 127490) || (uc >= 127504 && uc <= 127547) ||
+ (uc >= 127552 && uc <= 127560) || (uc >= 127568 && uc <= 127569) ||
+ (uc >= 127584 && uc <= 127589) || (uc >= 127744 && uc <= 128727) ||
+ (uc >= 128732 && uc <= 128748) || (uc >= 128752 && uc <= 128764) ||
+ (uc >= 128768 && uc <= 128886) || (uc >= 128891 && uc <= 128985) ||
+ (uc >= 128992 && uc <= 129003) || (uc == 129008) ||
+ (uc >= 129024 && uc <= 129035) || (uc >= 129040 && uc <= 129095) ||
+ (uc >= 129104 && uc <= 129113) || (uc >= 129120 && uc <= 129159) ||
+ (uc >= 129168 && uc <= 129197) || (uc >= 129200 && uc <= 129201) ||
+ (uc >= 129280 && uc <= 129619) || (uc >= 129632 && uc <= 129645) ||
+ (uc >= 129648 && uc <= 129660) || (uc >= 129664 && uc <= 129672) ||
+ (uc >= 129680 && uc <= 129725) || (uc >= 129727 && uc <= 129733) ||
+ (uc >= 129742 && uc <= 129755) || (uc >= 129760 && uc <= 129768) ||
+ (uc >= 129776 && uc <= 129784) || (uc >= 129792 && uc <= 129938) ||
+ (uc >= 129940 && uc <= 129994)));
+ }
+}
diff --git a/cmark/src/utf8.h b/cmark/src/utf8.h
new file mode 100644
index 0000000000..4b84c19c8d
--- /dev/null
+++ b/cmark/src/utf8.h
@@ -0,0 +1,24 @@
+#ifndef CMARK_UTF8_H
+#define CMARK_UTF8_H
+
+#include <stdint.h>
+#include "buffer.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void cmark_utf8proc_case_fold(cmark_strbuf *dest, const uint8_t *str,
+ bufsize_t len);
+void cmark_utf8proc_encode_char(int32_t uc, cmark_strbuf *buf);
+int cmark_utf8proc_iterate(const uint8_t *str, bufsize_t str_len, int32_t *dst);
+void cmark_utf8proc_check(cmark_strbuf *dest, const uint8_t *line,
+ bufsize_t size);
+int cmark_utf8proc_is_space(int32_t uc);
+int cmark_utf8proc_is_punctuation_or_symbol(int32_t uc);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/cmark/src/xml.c b/cmark/src/xml.c
new file mode 100644
index 0000000000..2ca2de82ce
--- /dev/null
+++ b/cmark/src/xml.c
@@ -0,0 +1,229 @@
+#include <assert.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "cmark.h"
+#include "node.h"
+#include "buffer.h"
+
+#define BUFFER_SIZE 100
+#define MAX_INDENT 40
+
+// Functions to convert cmark_nodes to XML strings.
+
+// C0 control characters, U+FFFE and U+FFF aren't allowed in XML.
+static const char XML_ESCAPE_TABLE[256] = {
+ /* 0x00 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1,
+ /* 0x10 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ /* 0x20 */ 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 5, 0,
+ /* 0x40 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x50 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x60 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x70 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x80 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x90 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xA0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xB0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9,
+ /* 0xC0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xD0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xE0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0xF0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+// U+FFFD Replacement Character encoded in UTF-8
+#define UTF8_REPL "\xEF\xBF\xBD"
+
+static const char *XML_ESCAPES[] = {
+ "", UTF8_REPL, "&quot;", "&amp;", "&lt;", "&gt;"
+};
+
+static void escape_xml(cmark_strbuf *ob, const unsigned char *src,
+ bufsize_t size) {
+ bufsize_t i = 0, org, esc = 0;
+
+ while (i < size) {
+ org = i;
+ while (i < size && (esc = XML_ESCAPE_TABLE[src[i]]) == 0)
+ i++;
+
+ if (i > org)
+ cmark_strbuf_put(ob, src + org, i - org);
+
+ if (i >= size)
+ break;
+
+ if (esc == 9) {
+ // To replace U+FFFE and U+FFFF with U+FFFD, only the last byte has to
+ // be changed.
+ // We know that src[i] is 0xBE or 0xBF.
+ if (i >= 2 && src[i-2] == 0xEF && src[i-1] == 0xBF) {
+ cmark_strbuf_putc(ob, 0xBD);
+ } else {
+ cmark_strbuf_putc(ob, src[i]);
+ }
+ } else {
+ cmark_strbuf_puts(ob, XML_ESCAPES[esc]);
+ }
+
+ i++;
+ }
+}
+
+static void escape_xml_str(cmark_strbuf *dest, const unsigned char *source) {
+ if (source)
+ escape_xml(dest, source, (bufsize_t)strlen((char *)source));
+}
+
+struct render_state {
+ cmark_strbuf *xml;
+ int indent;
+};
+
+static inline void indent(struct render_state *state) {
+ int i;
+ for (i = 0; i < state->indent && i < MAX_INDENT; i++) {
+ cmark_strbuf_putc(state->xml, ' ');
+ }
+}
+
+static int S_render_node(cmark_node *node, cmark_event_type ev_type,
+ struct render_state *state, int options) {
+ cmark_strbuf *xml = state->xml;
+ bool literal = false;
+ cmark_delim_type delim;
+ bool entering = (ev_type == CMARK_EVENT_ENTER);
+ char buffer[BUFFER_SIZE];
+
+ if (entering) {
+ indent(state);
+ cmark_strbuf_putc(xml, '<');
+ cmark_strbuf_puts(xml, cmark_node_get_type_string(node));
+
+ if (options & CMARK_OPT_SOURCEPOS && node->start_line != 0) {
+ snprintf(buffer, BUFFER_SIZE, " sourcepos=\"%d:%d-%d:%d\"",
+ node->start_line, node->start_column, node->end_line,
+ node->end_column);
+ cmark_strbuf_puts(xml, buffer);
+ }
+
+ literal = false;
+
+ switch (node->type) {
+ case CMARK_NODE_DOCUMENT:
+ cmark_strbuf_puts(xml, " xmlns=\"http://commonmark.org/xml/1.0\"");
+ break;
+ case CMARK_NODE_TEXT:
+ case CMARK_NODE_CODE:
+ case CMARK_NODE_HTML_BLOCK:
+ case CMARK_NODE_HTML_INLINE:
+ cmark_strbuf_puts(xml, " xml:space=\"preserve\">");
+ escape_xml(xml, node->data, node->len);
+ cmark_strbuf_puts(xml, "</");
+ cmark_strbuf_puts(xml, cmark_node_get_type_string(node));
+ literal = true;
+ break;
+ case CMARK_NODE_LIST:
+ switch (cmark_node_get_list_type(node)) {
+ case CMARK_ORDERED_LIST:
+ cmark_strbuf_puts(xml, " type=\"ordered\"");
+ snprintf(buffer, BUFFER_SIZE, " start=\"%d\"",
+ cmark_node_get_list_start(node));
+ cmark_strbuf_puts(xml, buffer);
+ delim = cmark_node_get_list_delim(node);
+ if (delim == CMARK_PAREN_DELIM) {
+ cmark_strbuf_puts(xml, " delimiter=\"paren\"");
+ } else if (delim == CMARK_PERIOD_DELIM) {
+ cmark_strbuf_puts(xml, " delimiter=\"period\"");
+ }
+ break;
+ case CMARK_BULLET_LIST:
+ cmark_strbuf_puts(xml, " type=\"bullet\"");
+ break;
+ default:
+ break;
+ }
+ snprintf(buffer, BUFFER_SIZE, " tight=\"%s\"",
+ (cmark_node_get_list_tight(node) ? "true" : "false"));
+ cmark_strbuf_puts(xml, buffer);
+ break;
+ case CMARK_NODE_HEADING:
+ snprintf(buffer, BUFFER_SIZE, " level=\"%d\"", node->as.heading.level);
+ cmark_strbuf_puts(xml, buffer);
+ break;
+ case CMARK_NODE_CODE_BLOCK:
+ if (node->as.code.info) {
+ cmark_strbuf_puts(xml, " info=\"");
+ escape_xml_str(xml, node->as.code.info);
+ cmark_strbuf_putc(xml, '"');
+ }
+ cmark_strbuf_puts(xml, " xml:space=\"preserve\">");
+ escape_xml(xml, node->data, node->len);
+ cmark_strbuf_puts(xml, "</");
+ cmark_strbuf_puts(xml, cmark_node_get_type_string(node));
+ literal = true;
+ break;
+ case CMARK_NODE_CUSTOM_BLOCK:
+ case CMARK_NODE_CUSTOM_INLINE:
+ cmark_strbuf_puts(xml, " on_enter=\"");
+ escape_xml_str(xml, node->as.custom.on_enter);
+ cmark_strbuf_putc(xml, '"');
+ cmark_strbuf_puts(xml, " on_exit=\"");
+ escape_xml_str(xml, node->as.custom.on_exit);
+ cmark_strbuf_putc(xml, '"');
+ break;
+ case CMARK_NODE_LINK:
+ case CMARK_NODE_IMAGE:
+ cmark_strbuf_puts(xml, " destination=\"");
+ escape_xml_str(xml, node->as.link.url);
+ cmark_strbuf_putc(xml, '"');
+ if (node->as.link.title) {
+ cmark_strbuf_puts(xml, " title=\"");
+ escape_xml_str(xml, node->as.link.title);
+ cmark_strbuf_putc(xml, '"');
+ }
+ break;
+ default:
+ break;
+ }
+ if (node->first_child) {
+ state->indent += 2;
+ } else if (!literal) {
+ cmark_strbuf_puts(xml, " /");
+ }
+ cmark_strbuf_puts(xml, ">\n");
+
+ } else if (node->first_child) {
+ state->indent -= 2;
+ indent(state);
+ cmark_strbuf_puts(xml, "</");
+ cmark_strbuf_puts(xml, cmark_node_get_type_string(node));
+ cmark_strbuf_puts(xml, ">\n");
+ }
+
+ return 1;
+}
+
+char *cmark_render_xml(cmark_node *root, int options) {
+ char *result;
+ cmark_strbuf xml = CMARK_BUF_INIT(root->mem);
+ cmark_event_type ev_type;
+ cmark_node *cur;
+ struct render_state state = {&xml, 0};
+
+ cmark_iter *iter = cmark_iter_new(root);
+
+ cmark_strbuf_puts(state.xml, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+ cmark_strbuf_puts(state.xml,
+ "<!DOCTYPE document SYSTEM \"CommonMark.dtd\">\n");
+ while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
+ cur = cmark_iter_get_node(iter);
+ S_render_node(cur, ev_type, &state, options);
+ }
+ result = (char *)cmark_strbuf_detach(&xml);
+
+ cmark_iter_free(iter);
+ return result;
+}
diff --git a/cmark/test/CMakeLists.txt b/cmark/test/CMakeLists.txt
new file mode 100755
index 0000000000..f13ddae55a
--- /dev/null
+++ b/cmark/test/CMakeLists.txt
@@ -0,0 +1,62 @@
+# To get verbose output: cmake --build build --target "test" -- ARGS='-V'
+
+# By default, we run the spec tests only if python3 is available.
+# To require the spec tests, compile with -DSPEC_TESTS=1
+
+if(SPEC_TESTS)
+ set(PYTHON_REQUIRED REQUIRED)
+else()
+ set(PYTHON_REQUIRED)
+endif()
+
+find_package(Python3 ${PYTHON_REQUIRED} COMPONENTS Interpreter)
+
+IF (Python3_Interpreter_FOUND)
+
+ add_test(NAME html_normalization
+ COMMAND "$<TARGET_FILE:Python3::Interpreter>" -m doctest "${CMAKE_CURRENT_SOURCE_DIR}/normalize.py")
+
+ if(BUILD_SHARED_LIBS)
+ add_test(NAME spectest_library
+ COMMAND "$<TARGET_FILE:Python3::Interpreter>" "${CMAKE_CURRENT_SOURCE_DIR}/spec_tests.py"
+ --no-normalize
+ --spec "${CMAKE_CURRENT_SOURCE_DIR}/spec.txt"
+ --library-dir "$<TARGET_FILE_DIR:cmark>")
+
+ add_test(NAME pathological_tests_library
+ COMMAND "$<TARGET_FILE:Python3::Interpreter>" "${CMAKE_CURRENT_SOURCE_DIR}/pathological_tests.py"
+ --library-dir "$<TARGET_FILE_DIR:cmark>")
+
+ add_test(NAME roundtriptest_library
+ COMMAND "$<TARGET_FILE:Python3::Interpreter>" "${CMAKE_CURRENT_SOURCE_DIR}/roundtrip_tests.py"
+ --spec "${CMAKE_CURRENT_SOURCE_DIR}/spec.txt"
+ --library-dir "$<TARGET_FILE_DIR:cmark>")
+
+ add_test(NAME entity_library
+ COMMAND "$<TARGET_FILE:Python3::Interpreter>" "${CMAKE_CURRENT_SOURCE_DIR}/entity_tests.py"
+ --library-dir "$<TARGET_FILE_DIR:cmark>")
+ endif()
+
+ add_test(NAME spectest_executable
+ COMMAND "$<TARGET_FILE:Python3::Interpreter>" "${CMAKE_CURRENT_SOURCE_DIR}/spec_tests.py"
+ --no-normalize
+ --spec "${CMAKE_CURRENT_SOURCE_DIR}/spec.txt"
+ --program "$<TARGET_FILE:cmark_exe>")
+
+ add_test(NAME smartpuncttest_executable
+ COMMAND "$<TARGET_FILE:Python3::Interpreter>" "${CMAKE_CURRENT_SOURCE_DIR}/spec_tests.py"
+ --no-normalize
+ --spec "${CMAKE_CURRENT_SOURCE_DIR}/smart_punct.txt"
+ --program "$<TARGET_FILE:cmark_exe> --smart")
+
+ add_test(NAME regressiontest_executable
+ COMMAND "$<TARGET_FILE:Python3::Interpreter>" "${CMAKE_CURRENT_SOURCE_DIR}/spec_tests.py"
+ --no-normalize
+ --spec "${CMAKE_CURRENT_SOURCE_DIR}/regression.txt"
+ --program "$<TARGET_FILE:cmark_exe>")
+
+ELSE(Python3_Interpreter_FOUND)
+
+ message(WARNING "A Python 3 Interpreter is required to run the spec tests")
+
+ENDIF(Python3_Interpreter_FOUND)
diff --git a/cmark/test/cmark.py b/cmark/test/cmark.py
new file mode 100644
index 0000000000..f9200f3460
--- /dev/null
+++ b/cmark/test/cmark.py
@@ -0,0 +1,88 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+from ctypes import *
+from subprocess import Popen, PIPE
+import platform
+import os
+
+class cmark_mem(Structure):
+ _fields_ = [("calloc", c_void_p),
+ ("realloc", c_void_p),
+ ("free", CFUNCTYPE(None, c_void_p))]
+
+def pipe_through_prog(prog, text):
+ p1 = Popen(prog.split(), stdout=PIPE, stdin=PIPE, stderr=PIPE)
+ [result, err] = p1.communicate(input=text.encode('utf-8'))
+ return [p1.returncode, result.decode('utf-8'), err]
+
+def to_html(lib, text):
+ get_alloc = lib.cmark_get_default_mem_allocator
+ get_alloc.restype = POINTER(cmark_mem)
+ free_func = get_alloc().contents.free
+
+ markdown = lib.cmark_markdown_to_html
+ markdown.restype = POINTER(c_char)
+ markdown.argtypes = [c_char_p, c_size_t, c_int]
+
+ textbytes = text.encode('utf-8')
+ textlen = len(textbytes)
+ # 1 << 17 == CMARK_OPT_UNSAFE
+ cstring = markdown(textbytes, textlen, 1 << 17)
+ result = string_at(cstring).decode('utf-8')
+ free_func(cstring)
+
+ return [0, result, '']
+
+def to_commonmark(lib, text):
+ get_alloc = lib.cmark_get_default_mem_allocator
+ get_alloc.restype = POINTER(cmark_mem)
+ free_func = get_alloc().contents.free
+
+ parse_document = lib.cmark_parse_document
+ parse_document.restype = c_void_p
+ parse_document.argtypes = [c_char_p, c_size_t, c_int]
+
+ render_commonmark = lib.cmark_render_commonmark
+ render_commonmark.restype = POINTER(c_char)
+ render_commonmark.argtypes = [c_void_p, c_int, c_int]
+
+ free_node = lib.cmark_node_free
+ free_node.argtypes = [c_void_p]
+
+ textbytes = text.encode('utf-8')
+ textlen = len(textbytes)
+ node = parse_document(textbytes, textlen, 0)
+ cstring = render_commonmark(node, 0, 0)
+ result = string_at(cstring).decode('utf-8')
+ free_func(cstring)
+ free_node(node)
+
+ return [0, result, '']
+
+class CMark:
+ def __init__(self, prog=None, library_dir=None):
+ self.prog = prog
+ if prog:
+ prog += ' --unsafe'
+ self.to_html = lambda x: pipe_through_prog(prog, x)
+ self.to_commonmark = lambda x: pipe_through_prog(prog + ' -t commonmark', x)
+ else:
+ sysname = platform.system()
+ if sysname == 'Darwin':
+ libnames = [ "libcmark.dylib" ]
+ elif sysname == 'Windows':
+ libnames = [ "cmark.dll", "libcmark.dll" ]
+ else:
+ libnames = [ "libcmark.so" ]
+ if not library_dir:
+ library_dir = os.path.join("build", "src")
+ for libname in libnames:
+ candidate = os.path.join(library_dir, libname)
+ if os.path.isfile(candidate):
+ libpath = candidate
+ break
+ cmark = CDLL(libpath)
+ self.to_html = lambda x: to_html(cmark, x)
+ self.to_commonmark = lambda x: to_commonmark(cmark, x)
+
diff --git a/cmark/test/entity_tests.py b/cmark/test/entity_tests.py
new file mode 100644
index 0000000000..27b70e690a
--- /dev/null
+++ b/cmark/test/entity_tests.py
@@ -0,0 +1,67 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+import re
+import os
+import argparse
+import sys
+import platform
+import html
+from cmark import CMark
+
+def get_entities():
+ regex = r'^{\(unsigned char\*\)"([^"]+)", \{([^}]+)\}'
+ with open(os.path.join(os.path.dirname(__file__), '..', 'src', 'entities.inc')) as f:
+ code = f.read()
+ entities = []
+ for entity, utf8 in re.findall(regex, code, re.MULTILINE):
+ utf8 = bytes(map(int, utf8.split(", ")[:-1])).decode('utf-8')
+ entities.append((entity, utf8))
+ return entities
+
+parser = argparse.ArgumentParser(description='Run cmark tests.')
+parser.add_argument('--program', dest='program', nargs='?', default=None,
+ help='program to test')
+parser.add_argument('--library-dir', dest='library_dir', nargs='?',
+ default=None, help='directory containing dynamic library')
+args = parser.parse_args(sys.argv[1:])
+
+cmark = CMark(prog=args.program, library_dir=args.library_dir)
+
+entities = get_entities()
+
+passed = 0
+errored = 0
+failed = 0
+
+exceptions = {
+ 'quot': '&quot;',
+ 'QUOT': '&quot;',
+
+ # These are broken, but I'm not too worried about them.
+ 'nvlt': '&lt;⃒',
+ 'nvgt': '&gt;⃒',
+}
+
+print("Testing entities:")
+for entity, utf8 in entities:
+ [rc, actual, err] = cmark.to_html("&{};".format(entity))
+ check = exceptions.get(entity, utf8)
+
+ if rc != 0:
+ errored += 1
+ print(entity, '[ERRORED (return code {})]'.format(rc))
+ print(err)
+ elif check in actual:
+ # print(entity, '[PASSED]') # omit noisy success output
+ passed += 1
+ else:
+ print(entity, '[FAILED]')
+ print(repr(actual))
+ failed += 1
+
+print("{} passed, {} failed, {} errored".format(passed, failed, errored))
+if failed == 0 and errored == 0:
+ exit(0)
+else:
+ exit(1)
diff --git a/cmark/test/normalize.py b/cmark/test/normalize.py
new file mode 100644
index 0000000000..9e5b406c9d
--- /dev/null
+++ b/cmark/test/normalize.py
@@ -0,0 +1,194 @@
+# -*- coding: utf-8 -*-
+from html.parser import HTMLParser
+import urllib
+
+try:
+ from html.parser import HTMLParseError
+except ImportError:
+ # HTMLParseError was removed in Python 3.5. It could never be
+ # thrown, so we define a placeholder instead.
+ class HTMLParseError(Exception):
+ pass
+
+from html.entities import name2codepoint
+import sys
+import re
+import html
+
+# Normalization code, adapted from
+# https://github.com/karlcow/markdown-testsuite/
+significant_attrs = ["alt", "href", "src", "title"]
+whitespace_re = re.compile(r"\s+")
+class MyHTMLParser(HTMLParser):
+ def __init__(self):
+ HTMLParser.__init__(self)
+ self.convert_charrefs = False
+ self.last = "starttag"
+ self.in_pre = False
+ self.output = ""
+ self.last_tag = ""
+ def handle_data(self, data):
+ after_tag = self.last == "endtag" or self.last == "starttag"
+ after_block_tag = after_tag and self.is_block_tag(self.last_tag)
+ if after_tag and self.last_tag == "br":
+ data = data.lstrip('\n')
+ if not self.in_pre:
+ data = whitespace_re.sub(' ', data)
+ if after_block_tag and not self.in_pre:
+ if self.last == "starttag":
+ data = data.lstrip()
+ elif self.last == "endtag":
+ data = data.strip()
+ self.output += data
+ self.last = "data"
+ def handle_endtag(self, tag):
+ if tag == "pre":
+ self.in_pre = False
+ elif self.is_block_tag(tag):
+ self.output = self.output.rstrip()
+ self.output += "</" + tag + ">"
+ self.last_tag = tag
+ self.last = "endtag"
+ def handle_starttag(self, tag, attrs):
+ if tag == "pre":
+ self.in_pre = True
+ if self.is_block_tag(tag):
+ self.output = self.output.rstrip()
+ self.output += "<" + tag
+ # For now we don't strip out 'extra' attributes, because of
+ # raw HTML test cases.
+ # attrs = filter(lambda attr: attr[0] in significant_attrs, attrs)
+ if attrs:
+ attrs.sort()
+ for (k,v) in attrs:
+ self.output += " " + k
+ if v in ['href','src']:
+ self.output += ("=" + '"' +
+ urllib.quote(urllib.unquote(v), safe='/') + '"')
+ elif v != None:
+ self.output += ("=" + '"' + html.escape(v,quote=True) + '"')
+ self.output += ">"
+ self.last_tag = tag
+ self.last = "starttag"
+ def handle_startendtag(self, tag, attrs):
+ """Ignore closing tag for self-closing """
+ self.handle_starttag(tag, attrs)
+ self.last_tag = tag
+ self.last = "endtag"
+ def handle_comment(self, data):
+ self.output += '<!--' + data + '-->'
+ self.last = "comment"
+ def handle_decl(self, data):
+ self.output += '<!' + data + '>'
+ self.last = "decl"
+ def unknown_decl(self, data):
+ self.output += '<!' + data + '>'
+ self.last = "decl"
+ def handle_pi(self,data):
+ self.output += '<?' + data + '>'
+ self.last = "pi"
+ def handle_entityref(self, name):
+ try:
+ c = chr(name2codepoint[name])
+ except KeyError:
+ c = None
+ self.output_char(c, '&' + name + ';')
+ self.last = "ref"
+ def handle_charref(self, name):
+ try:
+ if name.startswith("x"):
+ c = chr(int(name[1:], 16))
+ else:
+ c = chr(int(name))
+ except ValueError:
+ c = None
+ self.output_char(c, '&' + name + ';')
+ self.last = "ref"
+ # Helpers.
+ def output_char(self, c, fallback):
+ if c == '<':
+ self.output += "&lt;"
+ elif c == '>':
+ self.output += "&gt;"
+ elif c == '&':
+ self.output += "&amp;"
+ elif c == '"':
+ self.output += "&quot;"
+ elif c == None:
+ self.output += fallback
+ else:
+ self.output += c
+
+ def is_block_tag(self,tag):
+ return (tag in ['article', 'header', 'aside', 'hgroup', 'blockquote',
+ 'hr', 'iframe', 'body', 'li', 'map', 'button', 'object', 'canvas',
+ 'ol', 'caption', 'output', 'col', 'p', 'colgroup', 'pre', 'dd',
+ 'progress', 'div', 'section', 'dl', 'table', 'td', 'dt',
+ 'tbody', 'embed', 'textarea', 'fieldset', 'tfoot', 'figcaption',
+ 'th', 'figure', 'thead', 'footer', 'tr', 'form', 'ul',
+ 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'video', 'script', 'style'])
+
+def normalize_html(html):
+ r"""
+ Return normalized form of HTML which ignores insignificant output
+ differences:
+
+ Multiple inner whitespaces are collapsed to a single space (except
+ in pre tags):
+
+ >>> normalize_html("<p>a \t b</p>")
+ '<p>a b</p>'
+
+ >>> normalize_html("<p>a \t\nb</p>")
+ '<p>a b</p>'
+
+ * Whitespace surrounding block-level tags is removed.
+
+ >>> normalize_html("<p>a b</p>")
+ '<p>a b</p>'
+
+ >>> normalize_html(" <p>a b</p>")
+ '<p>a b</p>'
+
+ >>> normalize_html("<p>a b</p> ")
+ '<p>a b</p>'
+
+ >>> normalize_html("\n\t<p>\n\t\ta b\t\t</p>\n\t")
+ '<p>a b</p>'
+
+ >>> normalize_html("<i>a b</i> ")
+ '<i>a b</i> '
+
+ * Self-closing tags are converted to open tags.
+
+ >>> normalize_html("<br />")
+ '<br>'
+
+ * Attributes are sorted and lowercased.
+
+ >>> normalize_html('<a title="bar" HREF="foo">x</a>')
+ '<a href="foo" title="bar">x</a>'
+
+ * References are converted to unicode, except that '<', '>', '&', and
+ '"' are rendered using entities.
+
+ >>> normalize_html("&forall;&amp;&gt;&lt;&quot;")
+ '\u2200&amp;&gt;&lt;&quot;'
+
+ """
+ html_chunk_re = re.compile(r"(\<!\[CDATA\[.*?\]\]\>|\<[^>]*\>|[^<]+)")
+ try:
+ parser = MyHTMLParser()
+ # We work around HTMLParser's limitations parsing CDATA
+ # by breaking the input into chunks and passing CDATA chunks
+ # through verbatim.
+ for chunk in re.finditer(html_chunk_re, html):
+ if chunk.group(0)[:8] == "<![CDATA":
+ parser.output += chunk.group(0)
+ else:
+ parser.feed(chunk.group(0))
+ parser.close()
+ return parser.output
+ except HTMLParseError as e:
+ sys.stderr.write("Normalization error: " + e.msg + "\n")
+ return html # on error, return unnormalized HTML
diff --git a/cmark/test/pathological_tests.py b/cmark/test/pathological_tests.py
new file mode 100644
index 0000000000..42c0e79e6d
--- /dev/null
+++ b/cmark/test/pathological_tests.py
@@ -0,0 +1,202 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+import argparse
+import itertools
+import multiprocessing
+import re
+import sys
+import queue
+from cmark import CMark
+
+def hash_collisions():
+ REFMAP_SIZE = 16
+ COUNT = 25000
+
+ def badhash(ref):
+ h = 0
+ for c in ref:
+ a = (h << 6) & 0xFFFFFFFF
+ b = (h << 16) & 0xFFFFFFFF
+ h = ord(c) + a + b - h
+ h = h & 0xFFFFFFFF
+
+ return (h % REFMAP_SIZE) == 0
+
+ keys = ("x%d" % i for i in itertools.count())
+ collisions = itertools.islice((k for k in keys if badhash(k)), COUNT)
+ bad_key = next(collisions)
+
+ document = ''.join("[%s]: /url\n\n[%s]\n\n" % (key, bad_key) for key in collisions)
+
+ return document, re.compile(r"(<p>\[%s]</p>\n){%d}" % (bad_key, COUNT-1))
+
+
+# list of pairs consisting of input and a regex that must match the output.
+pathological = {
+ # note - some pythons have limit of 65535 for {num-matches} in re.
+ "nested strong emph":
+ (("*a **a " * 32500) + "b" + (" a** a*" * 32500),
+ re.compile("(<em>a <strong>a ){32500}b( a</strong> a</em>){32500}")),
+ "many emph closers with no openers":
+ (("a_ " * 32500),
+ re.compile("(a[_] ){32499}a_")),
+ "many emph openers with no closers":
+ (("_a " * 32500),
+ re.compile("(_a ){32499}_a")),
+ "many link closers with no openers":
+ (("a]" * 32500),
+ re.compile("(a\\]){32500}")),
+ "many link openers with no closers":
+ (("[a" * 32500),
+ re.compile("(\\[a){32500}")),
+ "mismatched openers and closers":
+ (("*a_ " * 25000),
+ re.compile("([*]a[_] ){24999}[*]a_")),
+ "issue #389":
+ (("*a " * 20000 + "_a*_ " * 20000),
+ re.compile("(<em>a ){20000}(_a<\\/em>_ ?){20000}")),
+ "openers and closers multiple of 3":
+ (("a**b" + ("c* " * 25000)),
+ re.compile("a[*][*]b(c[*] ){24999}c[*]")),
+ "link openers and emph closers":
+ (("[ a_" * 25000),
+ re.compile("(\\[ a_){25000}")),
+ "pattern [ (]( repeated":
+ (("[ (](" * 40000),
+ re.compile("(\\[ \\(\\]\\(){40000}")),
+ "pattern ![[]() repeated":
+ ("![[]()" * 160000,
+ re.compile("(!\\[<a href=\"\"></a>){160000}")),
+ "hard link/emph case":
+ ("**x [a*b**c*](d)",
+ re.compile("\\*\\*x <a href=\"d\">a<em>b\\*\\*c</em></a>")),
+ "nested brackets":
+ (("[" * 25000) + "a" + ("]" * 25000),
+ re.compile("\\[{25000}a\\]{25000}")),
+ "nested block quotes":
+ ((("> " * 25000) + "a"),
+ re.compile("(<blockquote>\n){25000}")),
+ "deeply nested lists":
+ ("".join(map(lambda x: (" " * x + "* a\n"), range(0,500))),
+ re.compile("<ul>\n(<li>a\n<ul>\n){499}<li>a</li>\n</ul>\n(</li>\n</ul>\n){499}")),
+ "U+0000 in input":
+ ("abc\u0000de\u0000",
+ re.compile("abc\ufffd?de\ufffd?")),
+ "backticks":
+ ("".join(map(lambda x: ("e" + "`" * x), range(1,2500))),
+ re.compile("^<p>[e`]*</p>\n$")),
+ "unclosed links A":
+ ("[a](<b" * 30000,
+ re.compile(r"(\[a]\(&lt;b){30000}")),
+ "unclosed links B":
+ ("[a](b" * 30000,
+ re.compile(r"(\[a]\(b){30000}")),
+ "unclosed <!--":
+ ("</" + "<!--" * 300000,
+ re.compile("\\&lt;\\/(\\&lt;!--){300000}")),
+ "empty lines in deeply nested lists":
+ ("- " * 30000 + "x" + "\n" * 30000,
+ re.compile(r"^(<\w+>\n?)+x(</\w+>\n)+$")),
+ "empty lines in deeply nested lists in blockquote":
+ ("> " + "- " * 30000 + "x\n" + ">\n" * 30000,
+ re.compile(r"^(<\w+>\n?)+x(</\w+>\n)+$")),
+ "emph in deep blockquote":
+ (">" * 100000 + "a*" * 100000,
+ re.compile(r"^(<\w+>\n)+<p>.*</p>\n(</\w+>\n)+$")),
+ "reference collisions": hash_collisions()
+# "many references":
+# ("".join(map(lambda x: ("[" + str(x) + "]: u\n"), range(1,5000 * 16))) + "[0] " * 5000,
+# re.compile("(\\[0\\] ){4999}"))
+ }
+
+pathological_cmark = {
+ "nested inlines":
+ ("*" * 20000 + "a" + "*" * 20000,
+ re.compile("^\\*+a\\*+$")),
+ }
+
+whitespace_re = re.compile('/s+/')
+
+def run_pathological(q, inp, prog, lib_dir):
+ cmark = CMark(prog=prog, library_dir=lib_dir)
+ q.put(cmark.to_html(inp))
+
+def run_pathological_cmark(q, inp, prog, lib_dir):
+ cmark = CMark(prog=prog, library_dir=lib_dir)
+ q.put(cmark.to_commonmark(inp))
+
+def run_tests(args):
+ allowed_failures = {"many references": True}
+ TIMEOUT = 5
+
+ q = multiprocessing.Queue()
+ passed = []
+ errored = []
+ failed = []
+ ignored = []
+
+ print("Testing pathological cases:")
+ for description in (*pathological, *pathological_cmark):
+ if description in pathological:
+ (inp, regex) = pathological[description]
+ p = multiprocessing.Process(
+ target=run_pathological,
+ args=(q, inp, args.program, args.library_dir)
+ )
+ else:
+ (inp, regex) = pathological_cmark[description]
+ p = multiprocessing.Process(
+ target=run_pathological_cmark,
+ args=(q, inp, args.program, args.library_dir)
+ )
+ p.start()
+ try:
+ # wait TIMEOUT seconds or until it finishes
+ rc, actual, err = q.get(True, TIMEOUT)
+ p.join()
+ if rc != 0:
+ print(description, '[ERRORED (return code %d)]' %rc)
+ print(err)
+ if description in allowed_failures:
+ ignored.append(description)
+ else:
+ errored.append(description)
+ elif regex.search(actual):
+ print(description, '[PASSED]')
+ passed.append(description)
+ else:
+ print(description, '[FAILED]')
+ print(repr(actual[:60]))
+ if description in allowed_failures:
+ ignored.append(description)
+ else:
+ failed.append(description)
+ except queue.Empty:
+ p.terminate()
+ p.join()
+ print(description, '[TIMEOUT]')
+ if description in allowed_failures:
+ ignored.append(description)
+ else:
+ errored.append(description)
+
+ print("%d passed, %d failed, %d errored" %
+ (len(passed), len(failed), len(errored)))
+ if ignored:
+ print("Ignoring these allowed failures:")
+ for x in ignored:
+ print(x)
+ if failed or errored:
+ exit(1)
+ else:
+ exit(0)
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(description='Run cmark tests.')
+ parser.add_argument('--program', dest='program', nargs='?', default=None,
+ help='program to test')
+ parser.add_argument('--library-dir', dest='library_dir', nargs='?',
+ default=None, help='directory containing dynamic library')
+ args = parser.parse_args(sys.argv[1:])
+ run_tests(args)
diff --git a/cmark/test/regression.txt b/cmark/test/regression.txt
new file mode 100644
index 0000000000..dce35fee8c
--- /dev/null
+++ b/cmark/test/regression.txt
@@ -0,0 +1,284 @@
+### Regression tests
+
+Issue #113: EOL character weirdness on Windows
+(Important: first line ends with CR + CR + LF)
+
+```````````````````````````````` example
+line1
+line2
+.
+<p>line1</p>
+<p>line2</p>
+````````````````````````````````
+
+Issue #114: cmark skipping first character in line
+(Important: the blank lines around "Repeatedly" contain a tab.)
+
+```````````````````````````````` example
+By taking it apart
+
+- alternative solutions
+→
+Repeatedly solving
+→
+- how techniques
+.
+<p>By taking it apart</p>
+<ul>
+<li>alternative solutions</li>
+</ul>
+<p>Repeatedly solving</p>
+<ul>
+<li>how techniques</li>
+</ul>
+````````````````````````````````
+
+Issue jgm/CommonMark#430: h2..h6 not recognized as block tags.
+
+```````````````````````````````` example
+<h1>lorem</h1>
+
+<h2>lorem</h2>
+
+<h3>lorem</h3>
+
+<h4>lorem</h4>
+
+<h5>lorem</h5>
+
+<h6>lorem</h6>
+.
+<h1>lorem</h1>
+<h2>lorem</h2>
+<h3>lorem</h3>
+<h4>lorem</h4>
+<h5>lorem</h5>
+<h6>lorem</h6>
+````````````````````````````````
+
+Issue jgm/commonmark.js#109 - tabs after setext header line
+
+
+```````````````````````````````` example
+hi
+--→
+.
+<h2>hi</h2>
+````````````````````````````````
+
+Issue #177 - incorrect emphasis parsing
+
+```````````````````````````````` example
+a***b* c*
+.
+<p>a*<em><em>b</em> c</em></p>
+````````````````````````````````
+
+Issue #193 - unescaped left angle brackets in link destination
+
+```````````````````````````````` example
+[a]
+
+[a]: <te<st>
+.
+<p>[a]</p>
+<p>[a]: &lt;te<st></p>
+````````````````````````````````
+
+Issue #192 - escaped spaces in link destination
+
+
+```````````````````````````````` example
+[a](te\ st)
+.
+<p>[a](te\ st)</p>
+````````````````````````````````
+
+Issue #527 - meta tags in inline contexts
+
+```````````````````````````````` example
+City:
+<span itemprop="contentLocation" itemscope itemtype="https://schema.org/City">
+ <meta itemprop="name" content="Springfield">
+</span>
+.
+<p>City:
+<span itemprop="contentLocation" itemscope itemtype="https://schema.org/City">
+<meta itemprop="name" content="Springfield">
+</span></p>
+````````````````````````````````
+
+Issue #530 - link parsing corner cases
+
+```````````````````````````````` example
+[a](\ b)
+
+[a](<<b)
+
+[a](<b
+)
+.
+<p>[a](\ b)</p>
+<p>[a](&lt;&lt;b)</p>
+<p>[a](&lt;b
+)</p>
+````````````````````````````````
+
+Issue commonmark#526 - unescaped ( in link title
+
+```````````````````````````````` example
+[link](url ((title))
+.
+<p>[link](url ((title))</p>
+````````````````````````````````
+
+Issue commonamrk#517 - script, pre, style close tag without
+opener.
+
+```````````````````````````````` example
+</script>
+
+</pre>
+
+</style>
+.
+</script>
+</pre>
+</style>
+````````````````````````````````
+
+Issue #289.
+
+```````````````````````````````` example
+[a](<b) c>
+.
+<p>[a](&lt;b) c&gt;</p>
+````````````````````````````````
+
+Issue #334 - UTF-8 BOM
+
+```````````````````````````````` example
+# Hi
+.
+<h1>Hi</h1>
+````````````````````````````````
+
+Issue commonmark.js#213 - type 7 blocks can't interrupt
+paragraph
+
+```````````````````````````````` example
+- <script>
+- some text
+some other text
+</script>
+.
+<ul>
+<li>
+<script>
+</li>
+<li>some text
+some other text
+</script></li>
+</ul>
+````````````````````````````````
+
+Issue #383 - emphasis parsing.
+
+```````````````````````````````` example
+*****Hello*world****
+.
+<p>**<em><strong>Hello<em>world</em></strong></em></p>
+````````````````````````````````
+
+Issue #424 - emphasis before links
+
+```````````````````````````````` example
+*text* [link](#section)
+.
+<p><em>text</em> <a href="#section">link</a></p>
+````````````````````````````````
+
+`<!doctype` is case-insensitive
+```````````````````````````````` example
+<!docType html>
+.
+<!docType html>
+````````````````````````````````
+
+Declarations don't need spaces, according to the spec
+```````````````````````````````` example
+x <!A>
+.
+<p>x <!A></p>
+````````````````````````````````
+
+An underscore that is not part of a delimiter should not prevent another
+pair of underscores from forming part of their own.
+```````````````````````````````` example
+__!_!__
+
+__!x!__
+
+**!*!**
+
+---
+
+_*__*_*
+
+_*xx*_*
+
+_*__-_-
+
+_*xx-_-
+.
+<p><strong>!_!</strong></p>
+<p><strong>!x!</strong></p>
+<p><strong>!*!</strong></p>
+<hr />
+<p><em><em>__</em></em>*</p>
+<p><em><em>xx</em></em>*</p>
+<p><em>*__-</em>-</p>
+<p><em>*xx-</em>-</p>
+````````````````````````````````
+
+commonmark.js #277:
+```````````````````````````````` example
+```language-r
+x <- 1
+```
+
+```r
+x <- 1
+```
+.
+<pre><code class="language-r">x &lt;- 1
+</code></pre>
+<pre><code class="language-r">x &lt;- 1
+</code></pre>
+````````````````````````````````
+
+https://github.com/commonmark/commonmark.js/issues/283
+```````````````````````````````` example
+x<!x>
+
+x<!>
+.
+<p>x<!x></p>
+<p>x&lt;!&gt;</p>
+````````````````````````````````
+
+Case fold test
+```````````````````````````````` example
+[link][µÓĐĹŠƆƦǏǶȜɆΓΨϪЇЛЯҎҶӞԆԮՄႠႴᏸᲕᲩᲿḦṎṶẚỂỪἙἿὭᾑᾥᾼῢΩↃⓉⰍⰡⱩⲔⲼⳫꙢꜢꝌꝽꞪꟇꭾꮒꮦꮺCW𐐐𐐤𐓀𐕰𐖅𐲅𐲙𐲭𑢮𖹂𖹖𞤊𞤞]
+
+[μóđĺšɔʀǐƕȝɇγψϫїляҏҷӟԇԯմⴀⴔᏰვჩჿḧṏṷaʾểừἑἷὥἡιὥιαιῢωↄⓣⰽⱑⱪⲕⲽⳬꙣꜣꝍᵹɦꟈᎮᏂᏖᏪcw𐐸𐑌𐓨𐖗𐖬𐳅𐳙𐳭𑣎𖹢𖹶𞤬𞥀]: /url
+.
+<p><a href="/url">link</a></p>
+````````````````````````````````
+
+https://github.com/commonmark/cmark/issues/548
+```````````````````````````````` example
+(&#xFFFE;&#xFFFF;)
+.
+<p>(￾￿)</p>
+````````````````````````````````
diff --git a/cmark/test/roundtrip_tests.py b/cmark/test/roundtrip_tests.py
new file mode 100644
index 0000000000..13444b1412
--- /dev/null
+++ b/cmark/test/roundtrip_tests.py
@@ -0,0 +1,46 @@
+import re
+import sys
+from spec_tests import get_tests, do_test
+from cmark import CMark
+import argparse
+
+parser = argparse.ArgumentParser(description='Run cmark roundtrip tests.')
+parser.add_argument('-p', '--program', dest='program', nargs='?', default=None,
+ help='program to test')
+parser.add_argument('-s', '--spec', dest='spec', nargs='?', default='spec.txt',
+ help='path to spec')
+parser.add_argument('-P', '--pattern', dest='pattern', nargs='?',
+ default=None, help='limit to sections matching regex pattern')
+parser.add_argument('--library-dir', dest='library_dir', nargs='?',
+ default=None, help='directory containing dynamic library')
+parser.add_argument('--no-normalize', dest='normalize',
+ action='store_const', const=False, default=True,
+ help='do not normalize HTML')
+parser.add_argument('-n', '--number', type=int, default=None,
+ help='only consider the test with the given number')
+args = parser.parse_args(sys.argv[1:])
+
+spec = sys.argv[1]
+
+def converter(md):
+ cmark = CMark(prog=args.program, library_dir=args.library_dir)
+ [ec, result, err] = cmark.to_commonmark(md)
+ if ec == 0:
+ [ec, html, err] = cmark.to_html(result)
+ if ec == 0:
+ # In the commonmark writer we insert dummy HTML
+ # comments between lists, and between lists and code
+ # blocks. Strip these out, since the spec uses
+ # two blank lines instead:
+ return [ec, re.sub('<!-- end list -->\n', '', html), '']
+ else:
+ return [ec, html, err]
+ else:
+ return [ec, result, err]
+
+tests = get_tests(args.spec)
+result_counts = {'pass': 0, 'fail': 0, 'error': 0, 'skip': 0}
+for test in tests:
+ do_test(converter, test, args.normalize, result_counts)
+
+exit(result_counts['fail'] + result_counts['error'])
diff --git a/cmark/test/smart_punct.txt b/cmark/test/smart_punct.txt
new file mode 100644
index 0000000000..fd55e6227b
--- /dev/null
+++ b/cmark/test/smart_punct.txt
@@ -0,0 +1,177 @@
+## Smart punctuation
+
+Open quotes are matched with closed quotes.
+The same method is used for matching openers and closers
+as is used in emphasis parsing:
+
+```````````````````````````````` example
+"Hello," said the spider.
+"'Shelob' is my name."
+.
+<p>“Hello,” said the spider.
+“‘Shelob’ is my name.”</p>
+````````````````````````````````
+
+```````````````````````````````` example
+'A', 'B', and 'C' are letters.
+.
+<p>‘A’, ‘B’, and ‘C’ are letters.</p>
+````````````````````````````````
+
+```````````````````````````````` example
+'Oak,' 'elm,' and 'beech' are names of trees.
+So is 'pine.'
+.
+<p>‘Oak,’ ‘elm,’ and ‘beech’ are names of trees.
+So is ‘pine.’</p>
+````````````````````````````````
+
+```````````````````````````````` example
+'He said, "I want to go."'
+.
+<p>‘He said, “I want to go.”’</p>
+````````````````````````````````
+
+A single quote that isn't an open quote matched
+with a close quote will be treated as an
+apostrophe:
+
+```````````````````````````````` example
+Were you alive in the 70's?
+.
+<p>Were you alive in the 70’s?</p>
+````````````````````````````````
+
+```````````````````````````````` example
+Here is some quoted '`code`' and a "[quoted link](url)".
+.
+<p>Here is some quoted ‘<code>code</code>’ and a “<a href="url">quoted link</a>”.</p>
+````````````````````````````````
+
+Here the first `'` is treated as an apostrophe, not
+an open quote, because the final single quote is matched
+by the single quote before `jolly`:
+
+```````````````````````````````` example
+'tis the season to be 'jolly'
+.
+<p>’tis the season to be ‘jolly’</p>
+````````````````````````````````
+
+Multiple apostrophes should not be marked as open/closing quotes.
+
+```````````````````````````````` example
+'We'll use Jane's boat and John's truck,' Jenna said.
+.
+<p>‘We’ll use Jane’s boat and John’s truck,’ Jenna said.</p>
+````````````````````````````````
+
+An unmatched double quote will be interpreted as a
+left double quote, to facilitate this style:
+
+```````````````````````````````` example
+"A paragraph with no closing quote.
+
+"Second paragraph by same speaker, in fiction."
+.
+<p>“A paragraph with no closing quote.</p>
+<p>“Second paragraph by same speaker, in fiction.”</p>
+````````````````````````````````
+
+A quote following a `]` or `)` character cannot
+be an open quote:
+
+```````````````````````````````` example
+[a]'s b'
+.
+<p>[a]’s b’</p>
+````````````````````````````````
+
+Quotes that are escaped come out as literal straight
+quotes:
+
+```````````````````````````````` example
+\"This is not smart.\"
+This isn\'t either.
+5\'8\"
+.
+<p>&quot;This is not smart.&quot;
+This isn't either.
+5'8&quot;</p>
+````````````````````````````````
+
+Two hyphens form an en-dash, three an em-dash.
+
+```````````````````````````````` example
+Some dashes: em---em
+en--en
+em --- em
+en -- en
+2--3
+.
+<p>Some dashes: em—em
+en–en
+em — em
+en – en
+2–3</p>
+````````````````````````````````
+
+A sequence of more than three hyphens is
+parsed as a sequence of em and/or en dashes,
+with no hyphens. If possible, a homogeneous
+sequence of dashes is used (so, 10 hyphens
+= 5 en dashes, and 9 hyphens = 3 em dashes).
+When a heterogeneous sequence must be used,
+the em dashes come first, followed by the en
+dashes, and as few en dashes as possible are
+used (so, 7 hyphens = 2 em dashes an 1 en
+dash).
+
+```````````````````````````````` example
+one-
+two--
+three---
+four----
+five-----
+six------
+seven-------
+eight--------
+nine---------
+thirteen-------------.
+.
+<p>one-
+two–
+three—
+four––
+five—–
+six——
+seven—––
+eight––––
+nine———
+thirteen———––.</p>
+````````````````````````````````
+
+Hyphens can be escaped:
+
+```````````````````````````````` example
+Escaped hyphens: \-- \-\-\-.
+.
+<p>Escaped hyphens: -- ---.</p>
+````````````````````````````````
+
+Three periods form an ellipsis:
+
+```````````````````````````````` example
+Ellipses...and...and....
+.
+<p>Ellipses…and…and….</p>
+````````````````````````````````
+
+Periods can be escaped if ellipsis-formation
+is not wanted:
+
+```````````````````````````````` example
+No ellipses\.\.\.
+.
+<p>No ellipses...</p>
+````````````````````````````````
diff --git a/cmark/test/spec.txt b/cmark/test/spec.txt
new file mode 100644
index 0000000000..f1fab281e9
--- /dev/null
+++ b/cmark/test/spec.txt
@@ -0,0 +1,9756 @@
+---
+title: CommonMark Spec
+author: John MacFarlane
+version: '0.31.2'
+date: '2024-01-28'
+license: '[CC-BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)'
+...
+
+# Introduction
+
+## What is Markdown?
+
+Markdown is a plain text format for writing structured documents,
+based on conventions for indicating formatting in email
+and usenet posts. It was developed by John Gruber (with
+help from Aaron Swartz) and released in 2004 in the form of a
+[syntax description](https://daringfireball.net/projects/markdown/syntax)
+and a Perl script (`Markdown.pl`) for converting Markdown to
+HTML. In the next decade, dozens of implementations were
+developed in many languages. Some extended the original
+Markdown syntax with conventions for footnotes, tables, and
+other document elements. Some allowed Markdown documents to be
+rendered in formats other than HTML. Websites like Reddit,
+StackOverflow, and GitHub had millions of people using Markdown.
+And Markdown started to be used beyond the web, to author books,
+articles, slide shows, letters, and lecture notes.
+
+What distinguishes Markdown from many other lightweight markup
+syntaxes, which are often easier to write, is its readability.
+As Gruber writes:
+
+> The overriding design goal for Markdown's formatting syntax is
+> to make it as readable as possible. The idea is that a
+> Markdown-formatted document should be publishable as-is, as
+> plain text, without looking like it's been marked up with tags
+> or formatting instructions.
+> (<https://daringfireball.net/projects/markdown/>)
+
+The point can be illustrated by comparing a sample of
+[AsciiDoc](https://asciidoc.org/) with
+an equivalent sample of Markdown. Here is a sample of
+AsciiDoc from the AsciiDoc manual:
+
+```
+1. List item one.
++
+List item one continued with a second paragraph followed by an
+Indented block.
++
+.................
+$ ls *.sh
+$ mv *.sh ~/tmp
+.................
++
+List item continued with a third paragraph.
+
+2. List item two continued with an open block.
++
+--
+This paragraph is part of the preceding list item.
+
+a. This list is nested and does not require explicit item
+continuation.
++
+This paragraph is part of the preceding list item.
+
+b. List item b.
+
+This paragraph belongs to item two of the outer list.
+--
+```
+
+And here is the equivalent in Markdown:
+```
+1. List item one.
+
+ List item one continued with a second paragraph followed by an
+ Indented block.
+
+ $ ls *.sh
+ $ mv *.sh ~/tmp
+
+ List item continued with a third paragraph.
+
+2. List item two continued with an open block.
+
+ This paragraph is part of the preceding list item.
+
+ 1. This list is nested and does not require explicit item continuation.
+
+ This paragraph is part of the preceding list item.
+
+ 2. List item b.
+
+ This paragraph belongs to item two of the outer list.
+```
+
+The AsciiDoc version is, arguably, easier to write. You don't need
+to worry about indentation. But the Markdown version is much easier
+to read. The nesting of list items is apparent to the eye in the
+source, not just in the processed document.
+
+## Why is a spec needed?
+
+John Gruber's [canonical description of Markdown's
+syntax](https://daringfireball.net/projects/markdown/syntax)
+does not specify the syntax unambiguously. Here are some examples of
+questions it does not answer:
+
+1. How much indentation is needed for a sublist? The spec says that
+ continuation paragraphs need to be indented four spaces, but is
+ not fully explicit about sublists. It is natural to think that
+ they, too, must be indented four spaces, but `Markdown.pl` does
+ not require that. This is hardly a "corner case," and divergences
+ between implementations on this issue often lead to surprises for
+ users in real documents. (See [this comment by John
+ Gruber](https://web.archive.org/web/20170611172104/http://article.gmane.org/gmane.text.markdown.general/1997).)
+
+2. Is a blank line needed before a block quote or heading?
+ Most implementations do not require the blank line. However,
+ this can lead to unexpected results in hard-wrapped text, and
+ also to ambiguities in parsing (note that some implementations
+ put the heading inside the blockquote, while others do not).
+ (John Gruber has also spoken [in favor of requiring the blank
+ lines](https://web.archive.org/web/20170611172104/http://article.gmane.org/gmane.text.markdown.general/2146).)
+
+3. Is a blank line needed before an indented code block?
+ (`Markdown.pl` requires it, but this is not mentioned in the
+ documentation, and some implementations do not require it.)
+
+ ``` markdown
+ paragraph
+ code?
+ ```
+
+4. What is the exact rule for determining when list items get
+ wrapped in `<p>` tags? Can a list be partially "loose" and partially
+ "tight"? What should we do with a list like this?
+
+ ``` markdown
+ 1. one
+
+ 2. two
+ 3. three
+ ```
+
+ Or this?
+
+ ``` markdown
+ 1. one
+ - a
+
+ - b
+ 2. two
+ ```
+
+ (There are some relevant comments by John Gruber
+ [here](https://web.archive.org/web/20170611172104/http://article.gmane.org/gmane.text.markdown.general/2554).)
+
+5. Can list markers be indented? Can ordered list markers be right-aligned?
+
+ ``` markdown
+ 8. item 1
+ 9. item 2
+ 10. item 2a
+ ```
+
+6. Is this one list with a thematic break in its second item,
+ or two lists separated by a thematic break?
+
+ ``` markdown
+ * a
+ * * * * *
+ * b
+ ```
+
+7. When list markers change from numbers to bullets, do we have
+ two lists or one? (The Markdown syntax description suggests two,
+ but the perl scripts and many other implementations produce one.)
+
+ ``` markdown
+ 1. fee
+ 2. fie
+ - foe
+ - fum
+ ```
+
+8. What are the precedence rules for the markers of inline structure?
+ For example, is the following a valid link, or does the code span
+ take precedence ?
+
+ ``` markdown
+ [a backtick (`)](/url) and [another backtick (`)](/url).
+ ```
+
+9. What are the precedence rules for markers of emphasis and strong
+ emphasis? For example, how should the following be parsed?
+
+ ``` markdown
+ *foo *bar* baz*
+ ```
+
+10. What are the precedence rules between block-level and inline-level
+ structure? For example, how should the following be parsed?
+
+ ``` markdown
+ - `a long code span can contain a hyphen like this
+ - and it can screw things up`
+ ```
+
+11. Can list items include section headings? (`Markdown.pl` does not
+ allow this, but does allow blockquotes to include headings.)
+
+ ``` markdown
+ - # Heading
+ ```
+
+12. Can list items be empty?
+
+ ``` markdown
+ * a
+ *
+ * b
+ ```
+
+13. Can link references be defined inside block quotes or list items?
+
+ ``` markdown
+ > Blockquote [foo].
+ >
+ > [foo]: /url
+ ```
+
+14. If there are multiple definitions for the same reference, which takes
+ precedence?
+
+ ``` markdown
+ [foo]: /url1
+ [foo]: /url2
+
+ [foo][]
+ ```
+
+In the absence of a spec, early implementers consulted `Markdown.pl`
+to resolve these ambiguities. But `Markdown.pl` was quite buggy, and
+gave manifestly bad results in many cases, so it was not a
+satisfactory replacement for a spec.
+
+Because there is no unambiguous spec, implementations have diverged
+considerably. As a result, users are often surprised to find that
+a document that renders one way on one system (say, a GitHub wiki)
+renders differently on another (say, converting to docbook using
+pandoc). To make matters worse, because nothing in Markdown counts
+as a "syntax error," the divergence often isn't discovered right away.
+
+## About this document
+
+This document attempts to specify Markdown syntax unambiguously.
+It contains many examples with side-by-side Markdown and
+HTML. These are intended to double as conformance tests. An
+accompanying script `spec_tests.py` can be used to run the tests
+against any Markdown program:
+
+ python test/spec_tests.py --spec spec.txt --program PROGRAM
+
+Since this document describes how Markdown is to be parsed into
+an abstract syntax tree, it would have made sense to use an abstract
+representation of the syntax tree instead of HTML. But HTML is capable
+of representing the structural distinctions we need to make, and the
+choice of HTML for the tests makes it possible to run the tests against
+an implementation without writing an abstract syntax tree renderer.
+
+Note that not every feature of the HTML samples is mandated by
+the spec. For example, the spec says what counts as a link
+destination, but it doesn't mandate that non-ASCII characters in
+the URL be percent-encoded. To use the automatic tests,
+implementers will need to provide a renderer that conforms to
+the expectations of the spec examples (percent-encoding
+non-ASCII characters in URLs). But a conforming implementation
+can use a different renderer and may choose not to
+percent-encode non-ASCII characters in URLs.
+
+This document is generated from a text file, `spec.txt`, written
+in Markdown with a small extension for the side-by-side tests.
+The script `tools/makespec.py` can be used to convert `spec.txt` into
+HTML or CommonMark (which can then be converted into other formats).
+
+In the examples, the `→` character is used to represent tabs.
+
+# Preliminaries
+
+## Characters and lines
+
+Any sequence of [characters] is a valid CommonMark
+document.
+
+A [character](@) is a Unicode code point. Although some
+code points (for example, combining accents) do not correspond to
+characters in an intuitive sense, all code points count as characters
+for purposes of this spec.
+
+This spec does not specify an encoding; it thinks of lines as composed
+of [characters] rather than bytes. A conforming parser may be limited
+to a certain encoding.
+
+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.
+
+A [line ending](@) is a line feed (`U+000A`), a carriage return
+(`U+000D`) not followed by a line feed, or a carriage return and a
+following line feed.
+
+A line containing no characters, or a line containing only spaces
+(`U+0020`) or tabs (`U+0009`), is called a [blank line](@).
+
+The following definitions of character classes will be used in this spec:
+
+A [Unicode whitespace character](@) is a character in the Unicode `Zs` general
+category, or a tab (`U+0009`), line feed (`U+000A`), form feed (`U+000C`), or
+carriage return (`U+000D`).
+
+[Unicode whitespace](@) is a sequence of one or more
+[Unicode whitespace characters].
+
+A [tab](@) is `U+0009`.
+
+A [space](@) is `U+0020`.
+
+An [ASCII control character](@) is a character between `U+0000–1F` (both
+including) or `U+007F`.
+
+An [ASCII punctuation character](@)
+is `!`, `"`, `#`, `$`, `%`, `&`, `'`, `(`, `)`,
+`*`, `+`, `,`, `-`, `.`, `/` (U+0021–2F),
+`:`, `;`, `<`, `=`, `>`, `?`, `@` (U+003A–0040),
+`[`, `\`, `]`, `^`, `_`, `` ` `` (U+005B–0060),
+`{`, `|`, `}`, or `~` (U+007B–007E).
+
+A [Unicode punctuation character](@) is a character in the Unicode `P`
+(puncuation) or `S` (symbol) general categories.
+
+## Tabs
+
+Tabs in lines are not expanded to [spaces]. However,
+in contexts where spaces help to define block structure,
+tabs behave as if they were replaced by spaces with a tab stop
+of 4 characters.
+
+Thus, for example, a tab can be used instead of four spaces
+in an indented code block. (Note, however, that internal
+tabs are passed through as literal tabs, not expanded to
+spaces.)
+
+```````````````````````````````` example
+→foo→baz→→bim
+.
+<pre><code>foo→baz→→bim
+</code></pre>
+````````````````````````````````
+
+```````````````````````````````` example
+ →foo→baz→→bim
+.
+<pre><code>foo→baz→→bim
+</code></pre>
+````````````````````````````````
+
+```````````````````````````````` example
+ a→a
+ ὐ→a
+.
+<pre><code>a→a
+ὐ→a
+</code></pre>
+````````````````````````````````
+
+In the following example, a continuation paragraph of a list
+item is indented with a tab; this has exactly the same effect
+as indentation with four spaces would:
+
+```````````````````````````````` example
+ - foo
+
+→bar
+.
+<ul>
+<li>
+<p>foo</p>
+<p>bar</p>
+</li>
+</ul>
+````````````````````````````````
+
+```````````````````````````````` example
+- foo
+
+→→bar
+.
+<ul>
+<li>
+<p>foo</p>
+<pre><code> bar
+</code></pre>
+</li>
+</ul>
+````````````````````````````````
+
+Normally the `>` that begins a block quote may be followed
+optionally by a space, which is not considered part of the
+content. In the following case `>` is followed by a tab,
+which is treated as if it were expanded into three spaces.
+Since one of these spaces is considered part of the
+delimiter, `foo` is considered to be indented six spaces
+inside the block quote context, so we get an indented
+code block starting with two spaces.
+
+```````````````````````````````` example
+>→→foo
+.
+<blockquote>
+<pre><code> foo
+</code></pre>
+</blockquote>
+````````````````````````````````
+
+```````````````````````````````` example
+-→→foo
+.
+<ul>
+<li>
+<pre><code> foo
+</code></pre>
+</li>
+</ul>
+````````````````````````````````
+
+
+```````````````````````````````` example
+ foo
+→bar
+.
+<pre><code>foo
+bar
+</code></pre>
+````````````````````````````````
+
+```````````````````````````````` example
+ - foo
+ - bar
+→ - baz
+.
+<ul>
+<li>foo
+<ul>
+<li>bar
+<ul>
+<li>baz</li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+````````````````````````````````
+
+```````````````````````````````` example
+#→Foo
+.
+<h1>Foo</h1>
+````````````````````````````````
+
+```````````````````````````````` example
+*→*→*→
+.
+<hr />
+````````````````````````````````
+
+
+## Insecure characters
+
+For security reasons, the Unicode character `U+0000` must be replaced
+with the REPLACEMENT CHARACTER (`U+FFFD`).
+
+
+## Backslash escapes
+
+Any ASCII punctuation character may be backslash-escaped:
+
+```````````````````````````````` example
+\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\`\{\|\}\~
+.
+<p>!&quot;#$%&amp;'()*+,-./:;&lt;=&gt;?@[\]^_`{|}~</p>
+````````````````````````````````
+
+
+Backslashes before other characters are treated as literal
+backslashes:
+
+```````````````````````````````` example
+\→\A\a\ \3\φ\«
+.
+<p>\→\A\a\ \3\φ\«</p>
+````````````````````````````````
+
+
+Escaped characters are treated as regular characters and do
+not have their usual Markdown meanings:
+
+```````````````````````````````` example
+\*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>*not emphasized*
+&lt;br/&gt; not a tag
+[not a link](/foo)
+`not code`
+1. not a list
+* not a list
+# not a heading
+[foo]: /url &quot;not a reference&quot;
+&amp;ouml; not a character entity</p>
+````````````````````````````````
+
+
+If a backslash is itself escaped, the following character is not:
+
+```````````````````````````````` example
+\\*emphasis*
+.
+<p>\<em>emphasis</em></p>
+````````````````````````````````
+
+
+A backslash at the end of the line is a [hard line break]:
+
+```````````````````````````````` example
+foo\
+bar
+.
+<p>foo<br />
+bar</p>
+````````````````````````````````
+
+
+Backslash escapes do not work in code blocks, code spans, autolinks, or
+raw HTML:
+
+```````````````````````````````` example
+`` \[\` ``
+.
+<p><code>\[\`</code></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+ \[\]
+.
+<pre><code>\[\]
+</code></pre>
+````````````````````````````````
+
+
+```````````````````````````````` example
+~~~
+\[\]
+~~~
+.
+<pre><code>\[\]
+</code></pre>
+````````````````````````````````
+
+
+```````````````````````````````` example
+<https://example.com?find=\*>
+.
+<p><a href="https://example.com?find=%5C*">https://example.com?find=\*</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+<a href="/bar\/)">
+.
+<a href="/bar\/)">
+````````````````````````````````
+
+
+But they work in all other contexts, including URLs and link titles,
+link references, and [info strings] in [fenced code blocks]:
+
+```````````````````````````````` example
+[foo](/bar\* "ti\*tle")
+.
+<p><a href="/bar*" title="ti*tle">foo</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[foo]
+
+[foo]: /bar\* "ti\*tle"
+.
+<p><a href="/bar*" title="ti*tle">foo</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+``` foo\+bar
+foo
+```
+.
+<pre><code class="language-foo+bar">foo
+</code></pre>
+````````````````````````````````
+
+
+## Entity and numeric character references
+
+Valid HTML entity references and numeric character references
+can be used in place of the corresponding Unicode character,
+with the following exceptions:
+
+- Entity and character references are not recognized in code
+ blocks and code spans.
+
+- Entity and character references cannot stand in place of
+ special characters that define structural elements in
+ CommonMark. For example, although `&#42;` can be used
+ in place of a literal `*` character, `&#42;` cannot replace
+ `*` in emphasis delimiters, bullet list markers, or thematic
+ breaks.
+
+Conforming CommonMark parsers need not store information about
+whether a particular character was represented in the source
+using a Unicode character or an entity reference.
+
+[Entity references](@) consist of `&` + any of the valid
+HTML5 entity names + `;`. The
+document <https://html.spec.whatwg.org/entities.json>
+is used as an authoritative source for the valid entity
+references and their corresponding code points.
+
+```````````````````````````````` example
+&nbsp; &amp; &copy; &AElig; &Dcaron;
+&frac34; &HilbertSpace; &DifferentialD;
+&ClockwiseContourIntegral; &ngE;
+.
+<p>  &amp; © Æ Ď
+¾ ℋ ⅆ
+∲ ≧̸</p>
+````````````````````````````````
+
+
+[Decimal numeric character
+references](@)
+consist of `&#` + a string of 1--7 arabic digits + `;`. A
+numeric character reference is parsed as the corresponding
+Unicode character. Invalid Unicode code points will be replaced by
+the REPLACEMENT CHARACTER (`U+FFFD`). For security reasons,
+the code point `U+0000` will also be replaced by `U+FFFD`.
+
+```````````````````````````````` example
+&#35; &#1234; &#992; &#0;
+.
+<p># Ӓ Ϡ �</p>
+````````````````````````````````
+
+
+[Hexadecimal numeric character
+references](@) consist of `&#` +
+either `X` or `x` + a string of 1-6 hexadecimal digits + `;`.
+They too are parsed as the corresponding Unicode character (this
+time specified with a hexadecimal numeral instead of decimal).
+
+```````````````````````````````` example
+&#X22; &#XD06; &#xcab;
+.
+<p>&quot; ആ ಫ</p>
+````````````````````````````````
+
+
+Here are some nonentities:
+
+```````````````````````````````` example
+&nbsp &x; &#; &#x;
+&#87654321;
+&#abcdef0;
+&ThisIsNotDefined; &hi?;
+.
+<p>&amp;nbsp &amp;x; &amp;#; &amp;#x;
+&amp;#87654321;
+&amp;#abcdef0;
+&amp;ThisIsNotDefined; &amp;hi?;</p>
+````````````````````````````````
+
+
+Although HTML5 does accept some entity references
+without a trailing semicolon (such as `&copy`), these are not
+recognized here, because it makes the grammar too ambiguous:
+
+```````````````````````````````` example
+&copy
+.
+<p>&amp;copy</p>
+````````````````````````````````
+
+
+Strings that are not on the list of HTML5 named entities are not
+recognized as entity references either:
+
+```````````````````````````````` example
+&MadeUpEntity;
+.
+<p>&amp;MadeUpEntity;</p>
+````````````````````````````````
+
+
+Entity and numeric character references are recognized in any
+context besides code spans or code blocks, including
+URLs, [link titles], and [fenced code block][] [info strings]:
+
+```````````````````````````````` example
+<a href="&ouml;&ouml;.html">
+.
+<a href="&ouml;&ouml;.html">
+````````````````````````````````
+
+
+```````````````````````````````` example
+[foo](/f&ouml;&ouml; "f&ouml;&ouml;")
+.
+<p><a href="/f%C3%B6%C3%B6" title="föö">foo</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[foo]
+
+[foo]: /f&ouml;&ouml; "f&ouml;&ouml;"
+.
+<p><a href="/f%C3%B6%C3%B6" title="föö">foo</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+``` f&ouml;&ouml;
+foo
+```
+.
+<pre><code class="language-föö">foo
+</code></pre>
+````````````````````````````````
+
+
+Entity and numeric character references are treated as literal
+text in code spans and code blocks:
+
+```````````````````````````````` example
+`f&ouml;&ouml;`
+.
+<p><code>f&amp;ouml;&amp;ouml;</code></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+ f&ouml;f&ouml;
+.
+<pre><code>f&amp;ouml;f&amp;ouml;
+</code></pre>
+````````````````````````````````
+
+
+Entity and numeric character references cannot be used
+in place of symbols indicating structure in CommonMark
+documents.
+
+```````````````````````````````` example
+&#42;foo&#42;
+*foo*
+.
+<p>*foo*
+<em>foo</em></p>
+````````````````````````````````
+
+```````````````````````````````` example
+&#42; foo
+
+* foo
+.
+<p>* foo</p>
+<ul>
+<li>foo</li>
+</ul>
+````````````````````````````````
+
+```````````````````````````````` example
+foo&#10;&#10;bar
+.
+<p>foo
+
+bar</p>
+````````````````````````````````
+
+```````````````````````````````` example
+&#9;foo
+.
+<p>→foo</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[a](url &quot;tit&quot;)
+.
+<p>[a](url &quot;tit&quot;)</p>
+````````````````````````````````
+
+
+
+# Blocks and inlines
+
+We can think of a document as a sequence of
+[blocks](@)---structural elements like paragraphs, block
+quotations, lists, headings, rules, and code blocks. Some blocks (like
+block quotes and list items) contain other blocks; others (like
+headings and paragraphs) contain [inline](@) content---text,
+links, emphasized text, images, code spans, and so on.
+
+## Precedence
+
+Indicators of block structure always take precedence over indicators
+of inline structure. So, for example, the following is a list with
+two items, not a list with one item containing a code span:
+
+```````````````````````````````` example
+- `one
+- two`
+.
+<ul>
+<li>`one</li>
+<li>two`</li>
+</ul>
+````````````````````````````````
+
+
+This means that parsing can proceed in two steps: first, the block
+structure of the document can be discerned; second, text lines inside
+paragraphs, headings, and other block constructs can be parsed for inline
+structure. The second step requires information about link reference
+definitions that will be available only at the end of the first
+step. Note that the first step requires processing lines in sequence,
+but the second can be parallelized, since the inline parsing of
+one block element does not affect the inline parsing of any other.
+
+## Container blocks and leaf blocks
+
+We can divide blocks into two types:
+[container blocks](#container-blocks),
+which can contain other blocks, and [leaf blocks](#leaf-blocks),
+which cannot.
+
+# Leaf blocks
+
+This section describes the different kinds of leaf block that make up a
+Markdown document.
+
+## Thematic breaks
+
+A line consisting of optionally up to three spaces of indentation, followed by a
+sequence of three or more matching `-`, `_`, or `*` characters, each followed
+optionally by any number of spaces or tabs, forms a
+[thematic break](@).
+
+```````````````````````````````` example
+***
+---
+___
+.
+<hr />
+<hr />
+<hr />
+````````````````````````````````
+
+
+Wrong characters:
+
+```````````````````````````````` example
++++
+.
+<p>+++</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+===
+.
+<p>===</p>
+````````````````````````````````
+
+
+Not enough characters:
+
+```````````````````````````````` example
+--
+**
+__
+.
+<p>--
+**
+__</p>
+````````````````````````````````
+
+
+Up to three spaces of indentation are allowed:
+
+```````````````````````````````` example
+ ***
+ ***
+ ***
+.
+<hr />
+<hr />
+<hr />
+````````````````````````````````
+
+
+Four spaces of indentation is too many:
+
+```````````````````````````````` example
+ ***
+.
+<pre><code>***
+</code></pre>
+````````````````````````````````
+
+
+```````````````````````````````` example
+Foo
+ ***
+.
+<p>Foo
+***</p>
+````````````````````````````````
+
+
+More than three characters may be used:
+
+```````````````````````````````` example
+_____________________________________
+.
+<hr />
+````````````````````````````````
+
+
+Spaces and tabs are allowed between the characters:
+
+```````````````````````````````` example
+ - - -
+.
+<hr />
+````````````````````````````````
+
+
+```````````````````````````````` example
+ ** * ** * ** * **
+.
+<hr />
+````````````````````````````````
+
+
+```````````````````````````````` example
+- - - -
+.
+<hr />
+````````````````````````````````
+
+
+Spaces and tabs are allowed at the end:
+
+```````````````````````````````` example
+- - - -
+.
+<hr />
+````````````````````````````````
+
+
+However, no other characters may occur in the line:
+
+```````````````````````````````` example
+_ _ _ _ a
+
+a------
+
+---a---
+.
+<p>_ _ _ _ a</p>
+<p>a------</p>
+<p>---a---</p>
+````````````````````````````````
+
+
+It is required that all of the characters other than spaces or tabs be the same.
+So, this is not a thematic break:
+
+```````````````````````````````` example
+ *-*
+.
+<p><em>-</em></p>
+````````````````````````````````
+
+
+Thematic breaks do not need blank lines before or after:
+
+```````````````````````````````` example
+- foo
+***
+- bar
+.
+<ul>
+<li>foo</li>
+</ul>
+<hr />
+<ul>
+<li>bar</li>
+</ul>
+````````````````````````````````
+
+
+Thematic breaks can interrupt a paragraph:
+
+```````````````````````````````` example
+Foo
+***
+bar
+.
+<p>Foo</p>
+<hr />
+<p>bar</p>
+````````````````````````````````
+
+
+If a line of dashes that meets the above conditions for being a
+thematic break could also be interpreted as the underline of a [setext
+heading], the interpretation as a
+[setext heading] takes precedence. Thus, for example,
+this is a setext heading, not a paragraph followed by a thematic break:
+
+```````````````````````````````` example
+Foo
+---
+bar
+.
+<h2>Foo</h2>
+<p>bar</p>
+````````````````````````````````
+
+
+When both a thematic break and a list item are possible
+interpretations of a line, the thematic break takes precedence:
+
+```````````````````````````````` example
+* Foo
+* * *
+* Bar
+.
+<ul>
+<li>Foo</li>
+</ul>
+<hr />
+<ul>
+<li>Bar</li>
+</ul>
+````````````````````````````````
+
+
+If you want a thematic break in a list item, use a different bullet:
+
+```````````````````````````````` example
+- Foo
+- * * *
+.
+<ul>
+<li>Foo</li>
+<li>
+<hr />
+</li>
+</ul>
+````````````````````````````````
+
+
+## ATX headings
+
+An [ATX heading](@)
+consists of a string of characters, parsed as inline content, between an
+opening sequence of 1--6 unescaped `#` characters and an optional
+closing sequence of any number of unescaped `#` characters.
+The opening sequence of `#` characters must be followed by spaces or tabs, or
+by the end of line. The optional closing sequence of `#`s must be preceded by
+spaces or tabs and may be followed by spaces or tabs only. The opening
+`#` character may be preceded by up to three spaces of indentation. The raw
+contents of the heading are stripped of leading and trailing space or tabs
+before being parsed as inline content. The heading level is equal to the number
+of `#` characters in the opening sequence.
+
+Simple headings:
+
+```````````````````````````````` example
+# foo
+## foo
+### foo
+#### foo
+##### foo
+###### foo
+.
+<h1>foo</h1>
+<h2>foo</h2>
+<h3>foo</h3>
+<h4>foo</h4>
+<h5>foo</h5>
+<h6>foo</h6>
+````````````````````````````````
+
+
+More than six `#` characters is not a heading:
+
+```````````````````````````````` example
+####### foo
+.
+<p>####### foo</p>
+````````````````````````````````
+
+
+At least one space or tab is required between the `#` characters and the
+heading's contents, unless the heading is empty. Note that many
+implementations currently do not require the space. However, the
+space was required by the
+[original ATX implementation](http://www.aaronsw.com/2002/atx/atx.py),
+and it helps prevent things like the following from being parsed as
+headings:
+
+```````````````````````````````` example
+#5 bolt
+
+#hashtag
+.
+<p>#5 bolt</p>
+<p>#hashtag</p>
+````````````````````````````````
+
+
+This is not a heading, because the first `#` is escaped:
+
+```````````````````````````````` example
+\## foo
+.
+<p>## foo</p>
+````````````````````````````````
+
+
+Contents are parsed as inlines:
+
+```````````````````````````````` example
+# foo *bar* \*baz\*
+.
+<h1>foo <em>bar</em> *baz*</h1>
+````````````````````````````````
+
+
+Leading and trailing spaces or tabs are ignored in parsing inline content:
+
+```````````````````````````````` example
+# foo
+.
+<h1>foo</h1>
+````````````````````````````````
+
+
+Up to three spaces of indentation are allowed:
+
+```````````````````````````````` example
+ ### foo
+ ## foo
+ # foo
+.
+<h3>foo</h3>
+<h2>foo</h2>
+<h1>foo</h1>
+````````````````````````````````
+
+
+Four spaces of indentation is too many:
+
+```````````````````````````````` example
+ # foo
+.
+<pre><code># foo
+</code></pre>
+````````````````````````````````
+
+
+```````````````````````````````` example
+foo
+ # bar
+.
+<p>foo
+# bar</p>
+````````````````````````````````
+
+
+A closing sequence of `#` characters is optional:
+
+```````````````````````````````` example
+## foo ##
+ ### bar ###
+.
+<h2>foo</h2>
+<h3>bar</h3>
+````````````````````````````````
+
+
+It need not be the same length as the opening sequence:
+
+```````````````````````````````` example
+# foo ##################################
+##### foo ##
+.
+<h1>foo</h1>
+<h5>foo</h5>
+````````````````````````````````
+
+
+Spaces or tabs are allowed after the closing sequence:
+
+```````````````````````````````` example
+### foo ###
+.
+<h3>foo</h3>
+````````````````````````````````
+
+
+A sequence of `#` characters with anything but spaces or tabs following it
+is not a closing sequence, but counts as part of the contents of the
+heading:
+
+```````````````````````````````` example
+### foo ### b
+.
+<h3>foo ### b</h3>
+````````````````````````````````
+
+
+The closing sequence must be preceded by a space or tab:
+
+```````````````````````````````` example
+# foo#
+.
+<h1>foo#</h1>
+````````````````````````````````
+
+
+Backslash-escaped `#` characters do not count as part
+of the closing sequence:
+
+```````````````````````````````` example
+### foo \###
+## foo #\##
+# foo \#
+.
+<h3>foo ###</h3>
+<h2>foo ###</h2>
+<h1>foo #</h1>
+````````````````````````````````
+
+
+ATX headings need not be separated from surrounding content by blank
+lines, and they can interrupt paragraphs:
+
+```````````````````````````````` example
+****
+## foo
+****
+.
+<hr />
+<h2>foo</h2>
+<hr />
+````````````````````````````````
+
+
+```````````````````````````````` example
+Foo bar
+# baz
+Bar foo
+.
+<p>Foo bar</p>
+<h1>baz</h1>
+<p>Bar foo</p>
+````````````````````````````````
+
+
+ATX headings can be empty:
+
+```````````````````````````````` example
+##
+#
+### ###
+.
+<h2></h2>
+<h1></h1>
+<h3></h3>
+````````````````````````````````
+
+
+## Setext headings
+
+A [setext heading](@) consists of one or more
+lines of text, not interrupted by a blank line, of which the first line does not
+have more than 3 spaces of indentation, followed by
+a [setext heading underline]. The lines of text must be such
+that, were they not followed by the setext heading underline,
+they would be interpreted as a paragraph: they cannot be
+interpretable as a [code fence], [ATX heading][ATX headings],
+[block quote][block quotes], [thematic break][thematic breaks],
+[list item][list items], or [HTML block][HTML blocks].
+
+A [setext heading underline](@) is a sequence of
+`=` characters or a sequence of `-` characters, with no more than 3
+spaces of indentation and any number of trailing spaces or tabs.
+
+The heading is a level 1 heading if `=` characters are used in
+the [setext heading underline], and a level 2 heading if `-`
+characters are used. The contents of the heading are the result
+of parsing the preceding lines of text as CommonMark inline
+content.
+
+In general, a setext heading need not be preceded or followed by a
+blank line. However, it cannot interrupt a paragraph, so when a
+setext heading comes after a paragraph, a blank line is needed between
+them.
+
+Simple examples:
+
+```````````````````````````````` example
+Foo *bar*
+=========
+
+Foo *bar*
+---------
+.
+<h1>Foo <em>bar</em></h1>
+<h2>Foo <em>bar</em></h2>
+````````````````````````````````
+
+
+The content of the header may span more than one line:
+
+```````````````````````````````` example
+Foo *bar
+baz*
+====
+.
+<h1>Foo <em>bar
+baz</em></h1>
+````````````````````````````````
+
+The contents are the result of parsing the headings's raw
+content as inlines. The heading's raw content is formed by
+concatenating the lines and removing initial and final
+spaces or tabs.
+
+```````````````````````````````` example
+ Foo *bar
+baz*→
+====
+.
+<h1>Foo <em>bar
+baz</em></h1>
+````````````````````````````````
+
+
+The underlining can be any length:
+
+```````````````````````````````` example
+Foo
+-------------------------
+
+Foo
+=
+.
+<h2>Foo</h2>
+<h1>Foo</h1>
+````````````````````````````````
+
+
+The heading content can be preceded by up to three spaces of indentation, and
+need not line up with the underlining:
+
+```````````````````````````````` example
+ Foo
+---
+
+ Foo
+-----
+
+ Foo
+ ===
+.
+<h2>Foo</h2>
+<h2>Foo</h2>
+<h1>Foo</h1>
+````````````````````````````````
+
+
+Four spaces of indentation is too many:
+
+```````````````````````````````` example
+ Foo
+ ---
+
+ Foo
+---
+.
+<pre><code>Foo
+---
+
+Foo
+</code></pre>
+<hr />
+````````````````````````````````
+
+
+The setext heading underline can be preceded by up to three spaces of
+indentation, and may have trailing spaces or tabs:
+
+```````````````````````````````` example
+Foo
+ ----
+.
+<h2>Foo</h2>
+````````````````````````````````
+
+
+Four spaces of indentation is too many:
+
+```````````````````````````````` example
+Foo
+ ---
+.
+<p>Foo
+---</p>
+````````````````````````````````
+
+
+The setext heading underline cannot contain internal spaces or tabs:
+
+```````````````````````````````` example
+Foo
+= =
+
+Foo
+--- -
+.
+<p>Foo
+= =</p>
+<p>Foo</p>
+<hr />
+````````````````````````````````
+
+
+Trailing spaces or tabs in the content line do not cause a hard line break:
+
+```````````````````````````````` example
+Foo
+-----
+.
+<h2>Foo</h2>
+````````````````````````````````
+
+
+Nor does a backslash at the end:
+
+```````````````````````````````` example
+Foo\
+----
+.
+<h2>Foo\</h2>
+````````````````````````````````
+
+
+Since indicators of block structure take precedence over
+indicators of inline structure, the following are setext headings:
+
+```````````````````````````````` example
+`Foo
+----
+`
+
+<a title="a lot
+---
+of dashes"/>
+.
+<h2>`Foo</h2>
+<p>`</p>
+<h2>&lt;a title=&quot;a lot</h2>
+<p>of dashes&quot;/&gt;</p>
+````````````````````````````````
+
+
+The setext heading underline cannot be a [lazy continuation
+line] in a list item or block quote:
+
+```````````````````````````````` example
+> Foo
+---
+.
+<blockquote>
+<p>Foo</p>
+</blockquote>
+<hr />
+````````````````````````````````
+
+
+```````````````````````````````` example
+> foo
+bar
+===
+.
+<blockquote>
+<p>foo
+bar
+===</p>
+</blockquote>
+````````````````````````````````
+
+
+```````````````````````````````` example
+- Foo
+---
+.
+<ul>
+<li>Foo</li>
+</ul>
+<hr />
+````````````````````````````````
+
+
+A blank line is needed between a paragraph and a following
+setext heading, since otherwise the paragraph becomes part
+of the heading's content:
+
+```````````````````````````````` example
+Foo
+Bar
+---
+.
+<h2>Foo
+Bar</h2>
+````````````````````````````````
+
+
+But in general a blank line is not required before or after
+setext headings:
+
+```````````````````````````````` example
+---
+Foo
+---
+Bar
+---
+Baz
+.
+<hr />
+<h2>Foo</h2>
+<h2>Bar</h2>
+<p>Baz</p>
+````````````````````````````````
+
+
+Setext headings cannot be empty:
+
+```````````````````````````````` example
+
+====
+.
+<p>====</p>
+````````````````````````````````
+
+
+Setext heading text lines must not be interpretable as block
+constructs other than paragraphs. So, the line of dashes
+in these examples gets interpreted as a thematic break:
+
+```````````````````````````````` example
+---
+---
+.
+<hr />
+<hr />
+````````````````````````````````
+
+
+```````````````````````````````` example
+- foo
+-----
+.
+<ul>
+<li>foo</li>
+</ul>
+<hr />
+````````````````````````````````
+
+
+```````````````````````````````` example
+ foo
+---
+.
+<pre><code>foo
+</code></pre>
+<hr />
+````````````````````````````````
+
+
+```````````````````````````````` example
+> foo
+-----
+.
+<blockquote>
+<p>foo</p>
+</blockquote>
+<hr />
+````````````````````````````````
+
+
+If you want a heading with `> foo` as its literal text, you can
+use backslash escapes:
+
+```````````````````````````````` example
+\> foo
+------
+.
+<h2>&gt; foo</h2>
+````````````````````````````````
+
+
+**Compatibility note:** Most existing Markdown implementations
+do not allow the text of setext headings to span multiple lines.
+But there is no consensus about how to interpret
+
+``` markdown
+Foo
+bar
+---
+baz
+```
+
+One can find four different interpretations:
+
+1. paragraph "Foo", heading "bar", paragraph "baz"
+2. paragraph "Foo bar", thematic break, paragraph "baz"
+3. paragraph "Foo bar --- baz"
+4. heading "Foo bar", paragraph "baz"
+
+We find interpretation 4 most natural, and interpretation 4
+increases the expressive power of CommonMark, by allowing
+multiline headings. Authors who want interpretation 1 can
+put a blank line after the first paragraph:
+
+```````````````````````````````` example
+Foo
+
+bar
+---
+baz
+.
+<p>Foo</p>
+<h2>bar</h2>
+<p>baz</p>
+````````````````````````````````
+
+
+Authors who want interpretation 2 can put blank lines around
+the thematic break,
+
+```````````````````````````````` example
+Foo
+bar
+
+---
+
+baz
+.
+<p>Foo
+bar</p>
+<hr />
+<p>baz</p>
+````````````````````````````````
+
+
+or use a thematic break that cannot count as a [setext heading
+underline], such as
+
+```````````````````````````````` example
+Foo
+bar
+* * *
+baz
+.
+<p>Foo
+bar</p>
+<hr />
+<p>baz</p>
+````````````````````````````````
+
+
+Authors who want interpretation 3 can use backslash escapes:
+
+```````````````````````````````` example
+Foo
+bar
+\---
+baz
+.
+<p>Foo
+bar
+---
+baz</p>
+````````````````````````````````
+
+
+## Indented code blocks
+
+An [indented code block](@) is composed of one or more
+[indented chunks] separated by blank lines.
+An [indented chunk](@) is a sequence of non-blank lines,
+each preceded by four or more spaces of indentation. The contents of the code
+block are the literal contents of the lines, including trailing
+[line endings], minus four spaces of indentation.
+An indented code block has no [info string].
+
+An indented code block cannot interrupt a paragraph, so there must be
+a blank line between a paragraph and a following indented code block.
+(A blank line is not needed, however, between a code block and a following
+paragraph.)
+
+```````````````````````````````` example
+ a simple
+ indented code block
+.
+<pre><code>a simple
+ indented code block
+</code></pre>
+````````````````````````````````
+
+
+If there is any ambiguity between an interpretation of indentation
+as a code block and as indicating that material belongs to a [list
+item][list items], the list item interpretation takes precedence:
+
+```````````````````````````````` example
+ - foo
+
+ bar
+.
+<ul>
+<li>
+<p>foo</p>
+<p>bar</p>
+</li>
+</ul>
+````````````````````````````````
+
+
+```````````````````````````````` example
+1. foo
+
+ - bar
+.
+<ol>
+<li>
+<p>foo</p>
+<ul>
+<li>bar</li>
+</ul>
+</li>
+</ol>
+````````````````````````````````
+
+
+
+The contents of a code block are literal text, and do not get parsed
+as Markdown:
+
+```````````````````````````````` example
+ <a/>
+ *hi*
+
+ - one
+.
+<pre><code>&lt;a/&gt;
+*hi*
+
+- one
+</code></pre>
+````````````````````````````````
+
+
+Here we have three chunks separated by blank lines:
+
+```````````````````````````````` example
+ chunk1
+
+ chunk2
+
+
+
+ chunk3
+.
+<pre><code>chunk1
+
+chunk2
+
+
+
+chunk3
+</code></pre>
+````````````````````````````````
+
+
+Any initial spaces or tabs beyond four spaces of indentation will be included in
+the content, even in interior blank lines:
+
+```````````````````````````````` example
+ chunk1
+
+ chunk2
+.
+<pre><code>chunk1
+
+ chunk2
+</code></pre>
+````````````````````````````````
+
+
+An indented code block cannot interrupt a paragraph. (This
+allows hanging indents and the like.)
+
+```````````````````````````````` example
+Foo
+ bar
+
+.
+<p>Foo
+bar</p>
+````````````````````````````````
+
+
+However, any non-blank line with fewer than four spaces of indentation ends
+the code block immediately. So a paragraph may occur immediately
+after indented code:
+
+```````````````````````````````` example
+ foo
+bar
+.
+<pre><code>foo
+</code></pre>
+<p>bar</p>
+````````````````````````````````
+
+
+And indented code can occur immediately before and after other kinds of
+blocks:
+
+```````````````````````````````` example
+# Heading
+ foo
+Heading
+------
+ foo
+----
+.
+<h1>Heading</h1>
+<pre><code>foo
+</code></pre>
+<h2>Heading</h2>
+<pre><code>foo
+</code></pre>
+<hr />
+````````````````````````````````
+
+
+The first line can be preceded by more than four spaces of indentation:
+
+```````````````````````````````` example
+ foo
+ bar
+.
+<pre><code> foo
+bar
+</code></pre>
+````````````````````````````````
+
+
+Blank lines preceding or following an indented code block
+are not included in it:
+
+```````````````````````````````` example
+
+
+ foo
+
+
+.
+<pre><code>foo
+</code></pre>
+````````````````````````````````
+
+
+Trailing spaces or tabs are included in the code block's content:
+
+```````````````````````````````` example
+ foo
+.
+<pre><code>foo
+</code></pre>
+````````````````````````````````
+
+
+
+## Fenced code blocks
+
+A [code fence](@) is a sequence
+of at least three consecutive backtick characters (`` ` ``) or
+tildes (`~`). (Tildes and backticks cannot be mixed.)
+A [fenced code block](@)
+begins with a code fence, preceded by up to three spaces of indentation.
+
+The line with the opening code fence may optionally contain some text
+following the code fence; this is trimmed of leading and trailing
+spaces or tabs and called the [info string](@). If the [info string] comes
+after a backtick fence, it may not contain any backtick
+characters. (The reason for this restriction is that otherwise
+some inline code would be incorrectly interpreted as the
+beginning of a fenced code block.)
+
+The content of the code block consists of all subsequent lines, until
+a closing [code fence] of the same type as the code block
+began with (backticks or tildes), and with at least as many backticks
+or tildes as the opening code fence. If the leading code fence is
+preceded by N spaces of indentation, then up to N spaces of indentation are
+removed from each line of the content (if present). (If a content line is not
+indented, it is preserved unchanged. If it is indented N spaces or less, all
+of the indentation is removed.)
+
+The closing code fence may be preceded by up to three spaces of indentation, and
+may be followed only by spaces or tabs, which are ignored. If the end of the
+containing block (or document) is reached and no closing code fence
+has been found, the code block contains all of the lines after the
+opening code fence until the end of the containing block (or
+document). (An alternative spec would require backtracking in the
+event that a closing code fence is not found. But this makes parsing
+much less efficient, and there seems to be no real downside to the
+behavior described here.)
+
+A fenced code block may interrupt a paragraph, and does not require
+a blank line either before or after.
+
+The content of a code fence is treated as literal text, not parsed
+as inlines. The first word of the [info string] is typically used to
+specify the language of the code sample, and rendered in the `class`
+attribute of the `code` tag. However, this spec does not mandate any
+particular treatment of the [info string].
+
+Here is a simple example with backticks:
+
+```````````````````````````````` example
+```
+<
+ >
+```
+.
+<pre><code>&lt;
+ &gt;
+</code></pre>
+````````````````````````````````
+
+
+With tildes:
+
+```````````````````````````````` example
+~~~
+<
+ >
+~~~
+.
+<pre><code>&lt;
+ &gt;
+</code></pre>
+````````````````````````````````
+
+Fewer than three backticks is not enough:
+
+```````````````````````````````` example
+``
+foo
+``
+.
+<p><code>foo</code></p>
+````````````````````````````````
+
+The closing code fence must use the same character as the opening
+fence:
+
+```````````````````````````````` example
+```
+aaa
+~~~
+```
+.
+<pre><code>aaa
+~~~
+</code></pre>
+````````````````````````````````
+
+
+```````````````````````````````` example
+~~~
+aaa
+```
+~~~
+.
+<pre><code>aaa
+```
+</code></pre>
+````````````````````````````````
+
+
+The closing code fence must be at least as long as the opening fence:
+
+```````````````````````````````` example
+````
+aaa
+```
+``````
+.
+<pre><code>aaa
+```
+</code></pre>
+````````````````````````````````
+
+
+```````````````````````````````` example
+~~~~
+aaa
+~~~
+~~~~
+.
+<pre><code>aaa
+~~~
+</code></pre>
+````````````````````````````````
+
+
+Unclosed code blocks are closed by the end of the document
+(or the enclosing [block quote][block quotes] or [list item][list items]):
+
+```````````````````````````````` example
+```
+.
+<pre><code></code></pre>
+````````````````````````````````
+
+
+```````````````````````````````` example
+`````
+
+```
+aaa
+.
+<pre><code>
+```
+aaa
+</code></pre>
+````````````````````````````````
+
+
+```````````````````````````````` example
+> ```
+> aaa
+
+bbb
+.
+<blockquote>
+<pre><code>aaa
+</code></pre>
+</blockquote>
+<p>bbb</p>
+````````````````````````````````
+
+
+A code block can have all empty lines as its content:
+
+```````````````````````````````` example
+```
+
+
+```
+.
+<pre><code>
+
+</code></pre>
+````````````````````````````````
+
+
+A code block can be empty:
+
+```````````````````````````````` example
+```
+```
+.
+<pre><code></code></pre>
+````````````````````````````````
+
+
+Fences can be indented. If the opening fence is indented,
+content lines will have equivalent opening indentation removed,
+if present:
+
+```````````````````````````````` example
+ ```
+ aaa
+aaa
+```
+.
+<pre><code>aaa
+aaa
+</code></pre>
+````````````````````````````````
+
+
+```````````````````````````````` example
+ ```
+aaa
+ aaa
+aaa
+ ```
+.
+<pre><code>aaa
+aaa
+aaa
+</code></pre>
+````````````````````````````````
+
+
+```````````````````````````````` example
+ ```
+ aaa
+ aaa
+ aaa
+ ```
+.
+<pre><code>aaa
+ aaa
+aaa
+</code></pre>
+````````````````````````````````
+
+
+Four spaces of indentation is too many:
+
+```````````````````````````````` example
+ ```
+ aaa
+ ```
+.
+<pre><code>```
+aaa
+```
+</code></pre>
+````````````````````````````````
+
+
+Closing fences may be preceded by up to three spaces of indentation, and their
+indentation need not match that of the opening fence:
+
+```````````````````````````````` example
+```
+aaa
+ ```
+.
+<pre><code>aaa
+</code></pre>
+````````````````````````````````
+
+
+```````````````````````````````` example
+ ```
+aaa
+ ```
+.
+<pre><code>aaa
+</code></pre>
+````````````````````````````````
+
+
+This is not a closing fence, because it is indented 4 spaces:
+
+```````````````````````````````` example
+```
+aaa
+ ```
+.
+<pre><code>aaa
+ ```
+</code></pre>
+````````````````````````````````
+
+
+
+Code fences (opening and closing) cannot contain internal spaces or tabs:
+
+```````````````````````````````` example
+``` ```
+aaa
+.
+<p><code> </code>
+aaa</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+~~~~~~
+aaa
+~~~ ~~
+.
+<pre><code>aaa
+~~~ ~~
+</code></pre>
+````````````````````````````````
+
+
+Fenced code blocks can interrupt paragraphs, and can be followed
+directly by paragraphs, without a blank line between:
+
+```````````````````````````````` example
+foo
+```
+bar
+```
+baz
+.
+<p>foo</p>
+<pre><code>bar
+</code></pre>
+<p>baz</p>
+````````````````````````````````
+
+
+Other blocks can also occur before and after fenced code blocks
+without an intervening blank line:
+
+```````````````````````````````` example
+foo
+---
+~~~
+bar
+~~~
+# baz
+.
+<h2>foo</h2>
+<pre><code>bar
+</code></pre>
+<h1>baz</h1>
+````````````````````````````````
+
+
+An [info string] can be provided after the opening code fence.
+Although this spec doesn't mandate any particular treatment of
+the info string, the first word is typically used to specify
+the language of the code block. In HTML output, the language is
+normally indicated by adding a class to the `code` element consisting
+of `language-` followed by the language name.
+
+```````````````````````````````` example
+```ruby
+def foo(x)
+ return 3
+end
+```
+.
+<pre><code class="language-ruby">def foo(x)
+ return 3
+end
+</code></pre>
+````````````````````````````````
+
+
+```````````````````````````````` example
+~~~~ ruby startline=3 $%@#$
+def foo(x)
+ return 3
+end
+~~~~~~~
+.
+<pre><code class="language-ruby">def foo(x)
+ return 3
+end
+</code></pre>
+````````````````````````````````
+
+
+```````````````````````````````` example
+````;
+````
+.
+<pre><code class="language-;"></code></pre>
+````````````````````````````````
+
+
+[Info strings] for backtick code blocks cannot contain backticks:
+
+```````````````````````````````` example
+``` aa ```
+foo
+.
+<p><code>aa</code>
+foo</p>
+````````````````````````````````
+
+
+[Info strings] for tilde code blocks can contain backticks and tildes:
+
+```````````````````````````````` example
+~~~ aa ``` ~~~
+foo
+~~~
+.
+<pre><code class="language-aa">foo
+</code></pre>
+````````````````````````````````
+
+
+Closing code fences cannot have [info strings]:
+
+```````````````````````````````` example
+```
+``` aaa
+```
+.
+<pre><code>``` aaa
+</code></pre>
+````````````````````````````````
+
+
+
+## HTML blocks
+
+An [HTML block](@) is a group of lines that is treated
+as raw HTML (and will not be escaped in HTML output).
+
+There are seven kinds of [HTML block], which can be defined by their
+start and end conditions. The block begins with a line that meets a
+[start condition](@) (after up to three optional spaces of indentation).
+It ends with the first subsequent line that meets a matching
+[end condition](@), or the last line of the document, or the last line of
+the [container block](#container-blocks) containing the current HTML
+block, if no line is encountered that meets the [end condition]. If
+the first line meets both the [start condition] and the [end
+condition], the block will contain just that line.
+
+1. **Start condition:** line begins with the string `<pre`,
+`<script`, `<style`, or `<textarea` (case-insensitive), followed by a space,
+a tab, the string `>`, or the end of the line.\
+**End condition:** line contains an end tag
+`</pre>`, `</script>`, `</style>`, or `</textarea>` (case-insensitive; it
+need not match the start tag).
+
+2. **Start condition:** line begins with the string `<!--`.\
+**End condition:** line contains the string `-->`.
+
+3. **Start condition:** line begins with the string `<?`.\
+**End condition:** line contains the string `?>`.
+
+4. **Start condition:** line begins with the string `<!`
+followed by an ASCII letter.\
+**End condition:** line contains the character `>`.
+
+5. **Start condition:** line begins with the string
+`<![CDATA[`.\
+**End condition:** line contains the string `]]>`.
+
+6. **Start condition:** line begins with the string `<` or `</`
+followed by one of the strings (case-insensitive) `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`,
+`search`, `section`, `summary`, `table`, `tbody`, `td`,
+`tfoot`, `th`, `thead`, `title`, `tr`, `track`, `ul`, followed
+by a space, a tab, the end of the line, the string `>`, or
+the string `/>`.\
+**End condition:** line is followed by a [blank line].
+
+7. **Start condition:** line begins with a complete [open tag]
+(with any [tag name] other than `pre`, `script`,
+`style`, or `textarea`) or a complete [closing tag],
+followed by zero or more spaces and tabs, followed by the end of the line.\
+**End condition:** line is followed by a [blank line].
+
+HTML blocks continue until they are closed by their appropriate
+[end condition], or the last line of the document or other [container
+block](#container-blocks). This means any HTML **within an HTML
+block** that might otherwise be recognised as a start condition will
+be ignored by the parser and passed through as-is, without changing
+the parser's state.
+
+For instance, `<pre>` within an HTML block started by `<table>` will not affect
+the parser state; as the HTML block was started in by start condition 6, it
+will end at any blank line. This can be surprising:
+
+```````````````````````````````` example
+<table><tr><td>
+<pre>
+**Hello**,
+
+_world_.
+</pre>
+</td></tr></table>
+.
+<table><tr><td>
+<pre>
+**Hello**,
+<p><em>world</em>.
+</pre></p>
+</td></tr></table>
+````````````````````````````````
+
+In this case, the HTML block is terminated by the blank line — the `**Hello**`
+text remains verbatim — and regular parsing resumes, with a paragraph,
+emphasised `world` and inline and block HTML following.
+
+All types of [HTML blocks] except type 7 may interrupt
+a paragraph. Blocks of type 7 may not interrupt a paragraph.
+(This restriction is intended to prevent unwanted interpretation
+of long tags inside a wrapped paragraph as starting HTML blocks.)
+
+Some simple examples follow. Here are some basic HTML blocks
+of type 6:
+
+```````````````````````````````` example
+<table>
+ <tr>
+ <td>
+ hi
+ </td>
+ </tr>
+</table>
+
+okay.
+.
+<table>
+ <tr>
+ <td>
+ hi
+ </td>
+ </tr>
+</table>
+<p>okay.</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+ <div>
+ *hello*
+ <foo><a>
+.
+ <div>
+ *hello*
+ <foo><a>
+````````````````````````````````
+
+
+A block can also start with a closing tag:
+
+```````````````````````````````` example
+</div>
+*foo*
+.
+</div>
+*foo*
+````````````````````````````````
+
+
+Here we have two HTML blocks with a Markdown paragraph between them:
+
+```````````````````````````````` example
+<DIV CLASS="foo">
+
+*Markdown*
+
+</DIV>
+.
+<DIV CLASS="foo">
+<p><em>Markdown</em></p>
+</DIV>
+````````````````````````````````
+
+
+The tag on the first line can be partial, as long
+as it is split where there would be whitespace:
+
+```````````````````````````````` example
+<div id="foo"
+ class="bar">
+</div>
+.
+<div id="foo"
+ class="bar">
+</div>
+````````````````````````````````
+
+
+```````````````````````````````` example
+<div id="foo" class="bar
+ baz">
+</div>
+.
+<div id="foo" class="bar
+ baz">
+</div>
+````````````````````````````````
+
+
+An open tag need not be closed:
+```````````````````````````````` example
+<div>
+*foo*
+
+*bar*
+.
+<div>
+*foo*
+<p><em>bar</em></p>
+````````````````````````````````
+
+
+
+A partial tag need not even be completed (garbage
+in, garbage out):
+
+```````````````````````````````` example
+<div id="foo"
+*hi*
+.
+<div id="foo"
+*hi*
+````````````````````````````````
+
+
+```````````````````````````````` example
+<div class
+foo
+.
+<div class
+foo
+````````````````````````````````
+
+
+The initial tag doesn't even need to be a valid
+tag, as long as it starts like one:
+
+```````````````````````````````` example
+<div *???-&&&-<---
+*foo*
+.
+<div *???-&&&-<---
+*foo*
+````````````````````````````````
+
+
+In type 6 blocks, the initial tag need not be on a line by
+itself:
+
+```````````````````````````````` example
+<div><a href="bar">*foo*</a></div>
+.
+<div><a href="bar">*foo*</a></div>
+````````````````````````````````
+
+
+```````````````````````````````` example
+<table><tr><td>
+foo
+</td></tr></table>
+.
+<table><tr><td>
+foo
+</td></tr></table>
+````````````````````````````````
+
+
+Everything until the next blank line or end of document
+gets included in the HTML block. So, in the following
+example, what looks like a Markdown code block
+is actually part of the HTML block, which continues until a blank
+line or the end of the document is reached:
+
+```````````````````````````````` example
+<div></div>
+``` c
+int x = 33;
+```
+.
+<div></div>
+``` c
+int x = 33;
+```
+````````````````````````````````
+
+
+To start an [HTML block] with a tag that is *not* in the
+list of block-level tags in (6), you must put the tag by
+itself on the first line (and it must be complete):
+
+```````````````````````````````` example
+<a href="foo">
+*bar*
+</a>
+.
+<a href="foo">
+*bar*
+</a>
+````````````````````````````````
+
+
+In type 7 blocks, the [tag name] can be anything:
+
+```````````````````````````````` example
+<Warning>
+*bar*
+</Warning>
+.
+<Warning>
+*bar*
+</Warning>
+````````````````````````````````
+
+
+```````````````````````````````` example
+<i class="foo">
+*bar*
+</i>
+.
+<i class="foo">
+*bar*
+</i>
+````````````````````````````````
+
+
+```````````````````````````````` example
+</ins>
+*bar*
+.
+</ins>
+*bar*
+````````````````````````````````
+
+
+These rules are designed to allow us to work with tags that
+can function as either block-level or inline-level tags.
+The `<del>` tag is a nice example. We can surround content with
+`<del>` tags in three different ways. In this case, we get a raw
+HTML block, because the `<del>` tag is on a line by itself:
+
+```````````````````````````````` example
+<del>
+*foo*
+</del>
+.
+<del>
+*foo*
+</del>
+````````````````````````````````
+
+
+In this case, we get a raw HTML block that just includes
+the `<del>` tag (because it ends with the following blank
+line). So the contents get interpreted as CommonMark:
+
+```````````````````````````````` example
+<del>
+
+*foo*
+
+</del>
+.
+<del>
+<p><em>foo</em></p>
+</del>
+````````````````````````````````
+
+
+Finally, in this case, the `<del>` tags are interpreted
+as [raw HTML] *inside* the CommonMark paragraph. (Because
+the tag is not on a line by itself, we get inline HTML
+rather than an [HTML block].)
+
+```````````````````````````````` example
+<del>*foo*</del>
+.
+<p><del><em>foo</em></del></p>
+````````````````````````````````
+
+
+HTML tags designed to contain literal content
+(`pre`, `script`, `style`, `textarea`), comments, processing instructions,
+and declarations are treated somewhat differently.
+Instead of ending at the first blank line, these blocks
+end at the first line containing a corresponding end tag.
+As a result, these blocks can contain blank lines:
+
+A pre tag (type 1):
+
+```````````````````````````````` example
+<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>
+````````````````````````````````
+
+
+A script tag (type 1):
+
+```````````````````````````````` example
+<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>
+````````````````````````````````
+
+
+A textarea tag (type 1):
+
+```````````````````````````````` example
+<textarea>
+
+*foo*
+
+_bar_
+
+</textarea>
+.
+<textarea>
+
+*foo*
+
+_bar_
+
+</textarea>
+````````````````````````````````
+
+A style tag (type 1):
+
+```````````````````````````````` example
+<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>
+````````````````````````````````
+
+
+If there is no matching end tag, the block will end at the
+end of the document (or the enclosing [block quote][block quotes]
+or [list item][list items]):
+
+```````````````````````````````` example
+<style
+ type="text/css">
+
+foo
+.
+<style
+ type="text/css">
+
+foo
+````````````````````````````````
+
+
+```````````````````````````````` example
+> <div>
+> foo
+
+bar
+.
+<blockquote>
+<div>
+foo
+</blockquote>
+<p>bar</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+- <div>
+- foo
+.
+<ul>
+<li>
+<div>
+</li>
+<li>foo</li>
+</ul>
+````````````````````````````````
+
+
+The end tag can occur on the same line as the start tag:
+
+```````````````````````````````` example
+<style>p{color:red;}</style>
+*foo*
+.
+<style>p{color:red;}</style>
+<p><em>foo</em></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+<!-- foo -->*bar*
+*baz*
+.
+<!-- foo -->*bar*
+<p><em>baz</em></p>
+````````````````````````````````
+
+
+Note that anything on the last line after the
+end tag will be included in the [HTML block]:
+
+```````````````````````````````` example
+<script>
+foo
+</script>1. *bar*
+.
+<script>
+foo
+</script>1. *bar*
+````````````````````````````````
+
+
+A comment (type 2):
+
+```````````````````````````````` example
+<!-- Foo
+
+bar
+ baz -->
+okay
+.
+<!-- Foo
+
+bar
+ baz -->
+<p>okay</p>
+````````````````````````````````
+
+
+
+A processing instruction (type 3):
+
+```````````````````````````````` example
+<?php
+
+ echo '>';
+
+?>
+okay
+.
+<?php
+
+ echo '>';
+
+?>
+<p>okay</p>
+````````````````````````````````
+
+
+A declaration (type 4):
+
+```````````````````````````````` example
+<!DOCTYPE html>
+.
+<!DOCTYPE html>
+````````````````````````````````
+
+
+CDATA (type 5):
+
+```````````````````````````````` example
+<![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>
+````````````````````````````````
+
+
+The opening tag can be preceded by up to three spaces of indentation, but not
+four:
+
+```````````````````````````````` example
+ <!-- foo -->
+
+ <!-- foo -->
+.
+ <!-- foo -->
+<pre><code>&lt;!-- foo --&gt;
+</code></pre>
+````````````````````````````````
+
+
+```````````````````````````````` example
+ <div>
+
+ <div>
+.
+ <div>
+<pre><code>&lt;div&gt;
+</code></pre>
+````````````````````````````````
+
+
+An HTML block of types 1--6 can interrupt a paragraph, and need not be
+preceded by a blank line.
+
+```````````````````````````````` example
+Foo
+<div>
+bar
+</div>
+.
+<p>Foo</p>
+<div>
+bar
+</div>
+````````````````````````````````
+
+
+However, a following blank line is needed, except at the end of
+a document, and except for blocks of types 1--5, [above][HTML
+block]:
+
+```````````````````````````````` example
+<div>
+bar
+</div>
+*foo*
+.
+<div>
+bar
+</div>
+*foo*
+````````````````````````````````
+
+
+HTML blocks of type 7 cannot interrupt a paragraph:
+
+```````````````````````````````` example
+Foo
+<a href="bar">
+baz
+.
+<p>Foo
+<a href="bar">
+baz</p>
+````````````````````````````````
+
+
+This rule differs from John Gruber's original Markdown syntax
+specification, which says:
+
+> The only restrictions are that block-level HTML elements —
+> e.g. `<div>`, `<table>`, `<pre>`, `<p>`, etc. — must be separated from
+> surrounding content by blank lines, and the start and end tags of the
+> block should not be indented with spaces or tabs.
+
+In some ways Gruber's rule is more restrictive than the one given
+here:
+
+- It requires that an HTML block be preceded by a blank line.
+- It does not allow the start tag to be indented.
+- It requires a matching end tag, which it also does not allow to
+ be indented.
+
+Most Markdown implementations (including some of Gruber's own) do not
+respect all of these restrictions.
+
+There is one respect, however, in which Gruber's rule is more liberal
+than the one given here, since it allows blank lines to occur inside
+an HTML block. There are two reasons for disallowing them here.
+First, it removes the need to parse balanced tags, which is
+expensive and can require backtracking from the end of the document
+if no matching end tag is found. Second, it provides a very simple
+and flexible way of including Markdown content inside HTML tags:
+simply separate the Markdown from the HTML using blank lines:
+
+Compare:
+
+```````````````````````````````` example
+<div>
+
+*Emphasized* text.
+
+</div>
+.
+<div>
+<p><em>Emphasized</em> text.</p>
+</div>
+````````````````````````````````
+
+
+```````````````````````````````` example
+<div>
+*Emphasized* text.
+</div>
+.
+<div>
+*Emphasized* text.
+</div>
+````````````````````````````````
+
+
+Some Markdown implementations have adopted a convention of
+interpreting content inside tags as text if the open tag has
+the attribute `markdown=1`. The rule given above seems a simpler and
+more elegant way of achieving the same expressive power, which is also
+much simpler to parse.
+
+The main potential drawback is that one can no longer paste HTML
+blocks into Markdown documents with 100% reliability. However,
+*in most cases* this will work fine, because the blank lines in
+HTML are usually followed by HTML block tags. For example:
+
+```````````````````````````````` example
+<table>
+
+<tr>
+
+<td>
+Hi
+</td>
+
+</tr>
+
+</table>
+.
+<table>
+<tr>
+<td>
+Hi
+</td>
+</tr>
+</table>
+````````````````````````````````
+
+
+There are problems, however, if the inner tags are indented
+*and* separated by spaces, as then they will be interpreted as
+an indented code block:
+
+```````````````````````````````` example
+<table>
+
+ <tr>
+
+ <td>
+ Hi
+ </td>
+
+ </tr>
+
+</table>
+.
+<table>
+ <tr>
+<pre><code>&lt;td&gt;
+ Hi
+&lt;/td&gt;
+</code></pre>
+ </tr>
+</table>
+````````````````````````````````
+
+
+Fortunately, blank lines are usually not necessary and can be
+deleted. The exception is inside `<pre>` tags, but as described
+[above][HTML blocks], raw HTML blocks starting with `<pre>`
+*can* contain blank lines.
+
+## Link reference definitions
+
+A [link reference definition](@)
+consists of a [link label], optionally preceded by up to three spaces of
+indentation, followed
+by a colon (`:`), optional spaces or tabs (including up to one
+[line ending]), a [link destination],
+optional spaces or tabs (including up to one
+[line ending]), and an optional [link
+title], which if it is present must be separated
+from the [link destination] by spaces or tabs.
+No further character may occur.
+
+A [link reference definition]
+does not correspond to a structural element of a document. Instead, it
+defines a label which can be used in [reference links]
+and reference-style [images] elsewhere in the document. [Link
+reference definitions] can come either before or after the links that use
+them.
+
+```````````````````````````````` example
+[foo]: /url "title"
+
+[foo]
+.
+<p><a href="/url" title="title">foo</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+ [foo]:
+ /url
+ 'the title'
+
+[foo]
+.
+<p><a href="/url" title="the title">foo</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[Foo*bar\]]:my_(url) 'title (with parens)'
+
+[Foo*bar\]]
+.
+<p><a href="my_(url)" title="title (with parens)">Foo*bar]</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[Foo bar]:
+<my url>
+'title'
+
+[Foo bar]
+.
+<p><a href="my%20url" title="title">Foo bar</a></p>
+````````````````````````````````
+
+
+The title may extend over multiple lines:
+
+```````````````````````````````` example
+[foo]: /url '
+title
+line1
+line2
+'
+
+[foo]
+.
+<p><a href="/url" title="
+title
+line1
+line2
+">foo</a></p>
+````````````````````````````````
+
+
+However, it may not contain a [blank line]:
+
+```````````````````````````````` example
+[foo]: /url 'title
+
+with blank line'
+
+[foo]
+.
+<p>[foo]: /url 'title</p>
+<p>with blank line'</p>
+<p>[foo]</p>
+````````````````````````````````
+
+
+The title may be omitted:
+
+```````````````````````````````` example
+[foo]:
+/url
+
+[foo]
+.
+<p><a href="/url">foo</a></p>
+````````````````````````````````
+
+
+The link destination may not be omitted:
+
+```````````````````````````````` example
+[foo]:
+
+[foo]
+.
+<p>[foo]:</p>
+<p>[foo]</p>
+````````````````````````````````
+
+ However, an empty link destination may be specified using
+ angle brackets:
+
+```````````````````````````````` example
+[foo]: <>
+
+[foo]
+.
+<p><a href="">foo</a></p>
+````````````````````````````````
+
+The title must be separated from the link destination by
+spaces or tabs:
+
+```````````````````````````````` example
+[foo]: <bar>(baz)
+
+[foo]
+.
+<p>[foo]: <bar>(baz)</p>
+<p>[foo]</p>
+````````````````````````````````
+
+
+Both title and destination can contain backslash escapes
+and literal backslashes:
+
+```````````````````````````````` example
+[foo]: /url\bar\*baz "foo\"bar\baz"
+
+[foo]
+.
+<p><a href="/url%5Cbar*baz" title="foo&quot;bar\baz">foo</a></p>
+````````````````````````````````
+
+
+A link can come before its corresponding definition:
+
+```````````````````````````````` example
+[foo]
+
+[foo]: url
+.
+<p><a href="url">foo</a></p>
+````````````````````````````````
+
+
+If there are several matching definitions, the first one takes
+precedence:
+
+```````````````````````````````` example
+[foo]
+
+[foo]: first
+[foo]: second
+.
+<p><a href="first">foo</a></p>
+````````````````````````````````
+
+
+As noted in the section on [Links], matching of labels is
+case-insensitive (see [matches]).
+
+```````````````````````````````` example
+[FOO]: /url
+
+[Foo]
+.
+<p><a href="/url">Foo</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[ΑΓΩ]: /φου
+
+[αγω]
+.
+<p><a href="/%CF%86%CE%BF%CF%85">αγω</a></p>
+````````````````````````````````
+
+
+Whether something is a [link reference definition] is
+independent of whether the link reference it defines is
+used in the document. Thus, for example, the following
+document contains just a link reference definition, and
+no visible content:
+
+```````````````````````````````` example
+[foo]: /url
+.
+````````````````````````````````
+
+
+Here is another one:
+
+```````````````````````````````` example
+[
+foo
+]: /url
+bar
+.
+<p>bar</p>
+````````````````````````````````
+
+
+This is not a link reference definition, because there are
+characters other than spaces or tabs after the title:
+
+```````````````````````````````` example
+[foo]: /url "title" ok
+.
+<p>[foo]: /url &quot;title&quot; ok</p>
+````````````````````````````````
+
+
+This is a link reference definition, but it has no title:
+
+```````````````````````````````` example
+[foo]: /url
+"title" ok
+.
+<p>&quot;title&quot; ok</p>
+````````````````````````````````
+
+
+This is not a link reference definition, because it is indented
+four spaces:
+
+```````````````````````````````` example
+ [foo]: /url "title"
+
+[foo]
+.
+<pre><code>[foo]: /url &quot;title&quot;
+</code></pre>
+<p>[foo]</p>
+````````````````````````````````
+
+
+This is not a link reference definition, because it occurs inside
+a code block:
+
+```````````````````````````````` example
+```
+[foo]: /url
+```
+
+[foo]
+.
+<pre><code>[foo]: /url
+</code></pre>
+<p>[foo]</p>
+````````````````````````````````
+
+
+A [link reference definition] cannot interrupt a paragraph.
+
+```````````````````````````````` example
+Foo
+[bar]: /baz
+
+[bar]
+.
+<p>Foo
+[bar]: /baz</p>
+<p>[bar]</p>
+````````````````````````````````
+
+
+However, it can directly follow other block elements, such as headings
+and thematic breaks, and it need not be followed by a blank line.
+
+```````````````````````````````` example
+# [Foo]
+[foo]: /url
+> bar
+.
+<h1><a href="/url">Foo</a></h1>
+<blockquote>
+<p>bar</p>
+</blockquote>
+````````````````````````````````
+
+```````````````````````````````` example
+[foo]: /url
+bar
+===
+[foo]
+.
+<h1>bar</h1>
+<p><a href="/url">foo</a></p>
+````````````````````````````````
+
+```````````````````````````````` example
+[foo]: /url
+===
+[foo]
+.
+<p>===
+<a href="/url">foo</a></p>
+````````````````````````````````
+
+
+Several [link reference definitions]
+can occur one after another, without intervening blank lines.
+
+```````````````````````````````` example
+[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] can occur
+inside block containers, like lists and block quotations. They
+affect the entire document, not just the container in which they
+are defined:
+
+```````````````````````````````` example
+[foo]
+
+> [foo]: /url
+.
+<p><a href="/url">foo</a></p>
+<blockquote>
+</blockquote>
+````````````````````````````````
+
+
+## Paragraphs
+
+A sequence of non-blank lines that cannot be interpreted as other
+kinds of blocks forms a [paragraph](@).
+The contents of the paragraph are the result of parsing the
+paragraph's raw content as inlines. The paragraph's raw content
+is formed by concatenating the lines and removing initial and final
+spaces or tabs.
+
+A simple example with two paragraphs:
+
+```````````````````````````````` example
+aaa
+
+bbb
+.
+<p>aaa</p>
+<p>bbb</p>
+````````````````````````````````
+
+
+Paragraphs can contain multiple lines, but no blank lines:
+
+```````````````````````````````` example
+aaa
+bbb
+
+ccc
+ddd
+.
+<p>aaa
+bbb</p>
+<p>ccc
+ddd</p>
+````````````````````````````````
+
+
+Multiple blank lines between paragraphs have no effect:
+
+```````````````````````````````` example
+aaa
+
+
+bbb
+.
+<p>aaa</p>
+<p>bbb</p>
+````````````````````````````````
+
+
+Leading spaces or tabs are skipped:
+
+```````````````````````````````` example
+ aaa
+ bbb
+.
+<p>aaa
+bbb</p>
+````````````````````````````````
+
+
+Lines after the first may be indented any amount, since indented
+code blocks cannot interrupt paragraphs.
+
+```````````````````````````````` example
+aaa
+ bbb
+ ccc
+.
+<p>aaa
+bbb
+ccc</p>
+````````````````````````````````
+
+
+However, the first line may be preceded by up to three spaces of indentation.
+Four spaces of indentation is too many:
+
+```````````````````````````````` example
+ aaa
+bbb
+.
+<p>aaa
+bbb</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+ aaa
+bbb
+.
+<pre><code>aaa
+</code></pre>
+<p>bbb</p>
+````````````````````````````````
+
+
+Final spaces or tabs are stripped before inline parsing, so a paragraph
+that ends with two or more spaces will not end with a [hard line
+break]:
+
+```````````````````````````````` example
+aaa
+bbb
+.
+<p>aaa<br />
+bbb</p>
+````````````````````````````````
+
+
+## Blank lines
+
+[Blank lines] between block-level elements are ignored,
+except for the role they play in determining whether a [list]
+is [tight] or [loose].
+
+Blank lines at the beginning and end of the document are also ignored.
+
+```````````````````````````````` example
+
+
+aaa
+
+
+# aaa
+
+
+.
+<p>aaa</p>
+<h1>aaa</h1>
+````````````````````````````````
+
+
+
+# Container blocks
+
+A [container block](#container-blocks) is a block that has other
+blocks as its contents. There are two basic kinds of container blocks:
+[block quotes] and [list items].
+[Lists] are meta-containers for [list items].
+
+We define the syntax for container blocks recursively. The general
+form of the definition is:
+
+> If X is a sequence of blocks, then the result of
+> transforming X in such-and-such a way is a container of type Y
+> with these blocks as its content.
+
+So, we explain what counts as a block quote or list item by explaining
+how these can be *generated* from their contents. This should suffice
+to define the syntax, although it does not give a recipe for *parsing*
+these constructions. (A recipe is provided below in the section entitled
+[A parsing strategy](#appendix-a-parsing-strategy).)
+
+## Block quotes
+
+A [block quote marker](@),
+optionally preceded by up to three spaces of indentation,
+consists of (a) the character `>` together with a following space of
+indentation, or (b) a single character `>` not followed by a space of
+indentation.
+
+The following rules define [block quotes]:
+
+1. **Basic case.** If a string of lines *Ls* constitute a sequence
+ of blocks *Bs*, then the result of prepending a [block quote
+ marker] to the beginning of each line in *Ls*
+ is a [block quote](#block-quotes) containing *Bs*.
+
+2. **Laziness.** If a string of lines *Ls* constitute a [block
+ quote](#block-quotes) with contents *Bs*, then the result of deleting
+ the initial [block quote marker] from one or
+ more lines in which the next character other than a space or tab after the
+ [block quote marker] is [paragraph continuation
+ text] is a block quote with *Bs* as its content.
+ [Paragraph continuation text](@) is text
+ that will be parsed as part of the content of a paragraph, but does
+ not occur at the beginning of the paragraph.
+
+3. **Consecutiveness.** A document cannot contain two [block
+ quotes] in a row unless there is a [blank line] between them.
+
+Nothing else counts as a [block quote](#block-quotes).
+
+Here is a simple example:
+
+```````````````````````````````` example
+> # Foo
+> bar
+> baz
+.
+<blockquote>
+<h1>Foo</h1>
+<p>bar
+baz</p>
+</blockquote>
+````````````````````````````````
+
+
+The space or tab after the `>` characters can be omitted:
+
+```````````````````````````````` example
+># Foo
+>bar
+> baz
+.
+<blockquote>
+<h1>Foo</h1>
+<p>bar
+baz</p>
+</blockquote>
+````````````````````````````````
+
+
+The `>` characters can be preceded by up to three spaces of indentation:
+
+```````````````````````````````` example
+ > # Foo
+ > bar
+ > baz
+.
+<blockquote>
+<h1>Foo</h1>
+<p>bar
+baz</p>
+</blockquote>
+````````````````````````````````
+
+
+Four spaces of indentation is too many:
+
+```````````````````````````````` example
+ > # Foo
+ > bar
+ > baz
+.
+<pre><code>&gt; # Foo
+&gt; bar
+&gt; baz
+</code></pre>
+````````````````````````````````
+
+
+The Laziness clause allows us to omit the `>` before
+[paragraph continuation text]:
+
+```````````````````````````````` example
+> # Foo
+> bar
+baz
+.
+<blockquote>
+<h1>Foo</h1>
+<p>bar
+baz</p>
+</blockquote>
+````````````````````````````````
+
+
+A block quote can contain some lazy and some non-lazy
+continuation lines:
+
+```````````````````````````````` example
+> bar
+baz
+> foo
+.
+<blockquote>
+<p>bar
+baz
+foo</p>
+</blockquote>
+````````````````````````````````
+
+
+Laziness only applies to lines that would have been continuations of
+paragraphs had they been prepended with [block quote markers].
+For example, the `> ` cannot be omitted in the second line of
+
+``` markdown
+> foo
+> ---
+```
+
+without changing the meaning:
+
+```````````````````````````````` example
+> foo
+---
+.
+<blockquote>
+<p>foo</p>
+</blockquote>
+<hr />
+````````````````````````````````
+
+
+Similarly, if we omit the `> ` in the second line of
+
+``` markdown
+> - foo
+> - bar
+```
+
+then the block quote ends after the first line:
+
+```````````````````````````````` example
+> - foo
+- bar
+.
+<blockquote>
+<ul>
+<li>foo</li>
+</ul>
+</blockquote>
+<ul>
+<li>bar</li>
+</ul>
+````````````````````````````````
+
+
+For the same reason, we can't omit the `> ` in front of
+subsequent lines of an indented or fenced code block:
+
+```````````````````````````````` example
+> foo
+ bar
+.
+<blockquote>
+<pre><code>foo
+</code></pre>
+</blockquote>
+<pre><code>bar
+</code></pre>
+````````````````````````````````
+
+
+```````````````````````````````` example
+> ```
+foo
+```
+.
+<blockquote>
+<pre><code></code></pre>
+</blockquote>
+<p>foo</p>
+<pre><code></code></pre>
+````````````````````````````````
+
+
+Note that in the following case, we have a [lazy
+continuation line]:
+
+```````````````````````````````` example
+> foo
+ - bar
+.
+<blockquote>
+<p>foo
+- bar</p>
+</blockquote>
+````````````````````````````````
+
+
+To see why, note that in
+
+```markdown
+> foo
+> - bar
+```
+
+the `- bar` is indented too far to start a list, and can't
+be an indented code block because indented code blocks cannot
+interrupt paragraphs, so it is [paragraph continuation text].
+
+A block quote can be empty:
+
+```````````````````````````````` example
+>
+.
+<blockquote>
+</blockquote>
+````````````````````````````````
+
+
+```````````````````````````````` example
+>
+>
+>
+.
+<blockquote>
+</blockquote>
+````````````````````````````````
+
+
+A block quote can have initial or final blank lines:
+
+```````````````````````````````` example
+>
+> foo
+>
+.
+<blockquote>
+<p>foo</p>
+</blockquote>
+````````````````````````````````
+
+
+A blank line always separates block quotes:
+
+```````````````````````````````` example
+> foo
+
+> bar
+.
+<blockquote>
+<p>foo</p>
+</blockquote>
+<blockquote>
+<p>bar</p>
+</blockquote>
+````````````````````````````````
+
+
+(Most current Markdown implementations, including John Gruber's
+original `Markdown.pl`, will parse this example as a single block quote
+with two paragraphs. But it seems better to allow the author to decide
+whether two block quotes or one are wanted.)
+
+Consecutiveness means that if we put these block quotes together,
+we get a single block quote:
+
+```````````````````````````````` example
+> foo
+> bar
+.
+<blockquote>
+<p>foo
+bar</p>
+</blockquote>
+````````````````````````````````
+
+
+To get a block quote with two paragraphs, use:
+
+```````````````````````````````` example
+> foo
+>
+> bar
+.
+<blockquote>
+<p>foo</p>
+<p>bar</p>
+</blockquote>
+````````````````````````````````
+
+
+Block quotes can interrupt paragraphs:
+
+```````````````````````````````` example
+foo
+> bar
+.
+<p>foo</p>
+<blockquote>
+<p>bar</p>
+</blockquote>
+````````````````````````````````
+
+
+In general, blank lines are not needed before or after block
+quotes:
+
+```````````````````````````````` example
+> aaa
+***
+> bbb
+.
+<blockquote>
+<p>aaa</p>
+</blockquote>
+<hr />
+<blockquote>
+<p>bbb</p>
+</blockquote>
+````````````````````````````````
+
+
+However, because of laziness, a blank line is needed between
+a block quote and a following paragraph:
+
+```````````````````````````````` example
+> bar
+baz
+.
+<blockquote>
+<p>bar
+baz</p>
+</blockquote>
+````````````````````````````````
+
+
+```````````````````````````````` example
+> bar
+
+baz
+.
+<blockquote>
+<p>bar</p>
+</blockquote>
+<p>baz</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+> bar
+>
+baz
+.
+<blockquote>
+<p>bar</p>
+</blockquote>
+<p>baz</p>
+````````````````````````````````
+
+
+It is a consequence of the Laziness rule that any number
+of initial `>`s may be omitted on a continuation line of a
+nested block quote:
+
+```````````````````````````````` example
+> > > foo
+bar
+.
+<blockquote>
+<blockquote>
+<blockquote>
+<p>foo
+bar</p>
+</blockquote>
+</blockquote>
+</blockquote>
+````````````````````````````````
+
+
+```````````````````````````````` example
+>>> foo
+> bar
+>>baz
+.
+<blockquote>
+<blockquote>
+<blockquote>
+<p>foo
+bar
+baz</p>
+</blockquote>
+</blockquote>
+</blockquote>
+````````````````````````````````
+
+
+When including an indented code block in a block quote,
+remember that the [block quote marker] includes
+both the `>` and a following space of indentation. So *five spaces* are needed
+after the `>`:
+
+```````````````````````````````` example
+> code
+
+> not code
+.
+<blockquote>
+<pre><code>code
+</code></pre>
+</blockquote>
+<blockquote>
+<p>not code</p>
+</blockquote>
+````````````````````````````````
+
+
+
+## List items
+
+A [list marker](@) is a
+[bullet list marker] or an [ordered list marker].
+
+A [bullet list marker](@)
+is a `-`, `+`, or `*` character.
+
+An [ordered list marker](@)
+is a sequence of 1--9 arabic digits (`0-9`), followed by either a
+`.` character or a `)` character. (The reason for the length
+limit is that with 10 digits we start seeing integer overflows
+in some browsers.)
+
+The following rules define [list items]:
+
+1. **Basic case.** If a sequence of lines *Ls* constitute a sequence of
+ blocks *Bs* starting with a character other than a space or tab, and *M* is
+ a list marker of width *W* followed by 1 ≤ *N* ≤ 4 spaces of indentation,
+ then the result of prepending *M* and the following spaces to the first line
+ of *Ls*, and indenting subsequent lines of *Ls* by *W + N* spaces, is a
+ list item with *Bs* as its contents. The type of the list item
+ (bullet or ordered) is determined by the type of its list marker.
+ If the list item is ordered, then it is also assigned a start
+ number, based on the ordered list marker.
+
+ Exceptions:
+
+ 1. When the first list item in a [list] interrupts
+ a paragraph---that is, when it starts on a line that would
+ otherwise count as [paragraph continuation text]---then (a)
+ the lines *Ls* must not begin with a blank line, and (b) if
+ the list item is ordered, the start number must be 1.
+ 2. If any line is a [thematic break][thematic breaks] then
+ that line is not a list item.
+
+For example, let *Ls* be the lines
+
+```````````````````````````````` example
+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>
+````````````````````````````````
+
+
+And let *M* be the marker `1.`, and *N* = 2. Then rule #1 says
+that the following is an ordered list item with start number 1,
+and the same contents as *Ls*:
+
+```````````````````````````````` example
+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>
+````````````````````````````````
+
+
+The most important thing to notice is that the position of
+the text after the list marker determines how much indentation
+is needed in subsequent blocks in the list item. If the list
+marker takes up two spaces of indentation, and there are three spaces between
+the list marker and the next character other than a space or tab, then blocks
+must be indented five spaces in order to fall under the list
+item.
+
+Here are some examples showing how far content must be indented to be
+put under the list item:
+
+```````````````````````````````` example
+- one
+
+ two
+.
+<ul>
+<li>one</li>
+</ul>
+<p>two</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+- one
+
+ two
+.
+<ul>
+<li>
+<p>one</p>
+<p>two</p>
+</li>
+</ul>
+````````````````````````````````
+
+
+```````````````````````````````` example
+ - one
+
+ two
+.
+<ul>
+<li>one</li>
+</ul>
+<pre><code> two
+</code></pre>
+````````````````````````````````
+
+
+```````````````````````````````` example
+ - one
+
+ two
+.
+<ul>
+<li>
+<p>one</p>
+<p>two</p>
+</li>
+</ul>
+````````````````````````````````
+
+
+It is tempting to think of this in terms of columns: the continuation
+blocks must be indented at least to the column of the first character other than
+a space or tab after the list marker. However, that is not quite right.
+The spaces of indentation after the list marker determine how much relative
+indentation is needed. Which column this indentation reaches will depend on
+how the list item is embedded in other constructions, as shown by
+this example:
+
+```````````````````````````````` example
+ > > 1. one
+>>
+>> two
+.
+<blockquote>
+<blockquote>
+<ol>
+<li>
+<p>one</p>
+<p>two</p>
+</li>
+</ol>
+</blockquote>
+</blockquote>
+````````````````````````````````
+
+
+Here `two` occurs in the same column as the list marker `1.`,
+but is actually contained in the list item, because there is
+sufficient indentation after the last containing blockquote marker.
+
+The converse is also possible. In the following example, the word `two`
+occurs far to the right of the initial text of the list item, `one`, but
+it is not considered part of the list item, because it is not indented
+far enough past the blockquote marker:
+
+```````````````````````````````` example
+>>- one
+>>
+ > > two
+.
+<blockquote>
+<blockquote>
+<ul>
+<li>one</li>
+</ul>
+<p>two</p>
+</blockquote>
+</blockquote>
+````````````````````````````````
+
+
+Note that at least one space or tab is needed between the list marker and
+any following content, so these are not list items:
+
+```````````````````````````````` example
+-one
+
+2.two
+.
+<p>-one</p>
+<p>2.two</p>
+````````````````````````````````
+
+
+A list item may contain blocks that are separated by more than
+one blank line.
+
+```````````````````````````````` example
+- foo
+
+
+ bar
+.
+<ul>
+<li>
+<p>foo</p>
+<p>bar</p>
+</li>
+</ul>
+````````````````````````````````
+
+
+A list item may contain any kind of block:
+
+```````````````````````````````` example
+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>
+````````````````````````````````
+
+
+A list item that contains an indented code block will preserve
+empty lines within the code block verbatim.
+
+```````````````````````````````` example
+- Foo
+
+ bar
+
+
+ baz
+.
+<ul>
+<li>
+<p>Foo</p>
+<pre><code>bar
+
+
+baz
+</code></pre>
+</li>
+</ul>
+````````````````````````````````
+
+Note that ordered list start numbers must be nine digits or less:
+
+```````````````````````````````` example
+123456789. ok
+.
+<ol start="123456789">
+<li>ok</li>
+</ol>
+````````````````````````````````
+
+
+```````````````````````````````` example
+1234567890. not ok
+.
+<p>1234567890. not ok</p>
+````````````````````````````````
+
+
+A start number may begin with 0s:
+
+```````````````````````````````` example
+0. ok
+.
+<ol start="0">
+<li>ok</li>
+</ol>
+````````````````````````````````
+
+
+```````````````````````````````` example
+003. ok
+.
+<ol start="3">
+<li>ok</li>
+</ol>
+````````````````````````````````
+
+
+A start number may not be negative:
+
+```````````````````````````````` example
+-1. not ok
+.
+<p>-1. not ok</p>
+````````````````````````````````
+
+
+
+2. **Item starting with indented code.** If a sequence of lines *Ls*
+ constitute a sequence of blocks *Bs* starting with an indented code
+ block, and *M* is a list marker of width *W* followed by
+ one space of indentation, then the result of prepending *M* and the
+ following space to the first line of *Ls*, and indenting subsequent lines
+ of *Ls* by *W + 1* spaces, is a list item with *Bs* as its contents.
+ If a line is empty, then it need not be indented. The type of the
+ list item (bullet or ordered) is determined by the type of its list
+ marker. If the list item is ordered, then it is also assigned a
+ start number, based on the ordered list marker.
+
+An indented code block will have to be preceded by four spaces of indentation
+beyond the edge of the region where text will be included in the list item.
+In the following case that is 6 spaces:
+
+```````````````````````````````` example
+- foo
+
+ bar
+.
+<ul>
+<li>
+<p>foo</p>
+<pre><code>bar
+</code></pre>
+</li>
+</ul>
+````````````````````````````````
+
+
+And in this case it is 11 spaces:
+
+```````````````````````````````` example
+ 10. foo
+
+ bar
+.
+<ol start="10">
+<li>
+<p>foo</p>
+<pre><code>bar
+</code></pre>
+</li>
+</ol>
+````````````````````````````````
+
+
+If the *first* block in the list item is an indented code block,
+then by rule #2, the contents must be preceded by *one* space of indentation
+after the list marker:
+
+```````````````````````````````` example
+ indented code
+
+paragraph
+
+ more code
+.
+<pre><code>indented code
+</code></pre>
+<p>paragraph</p>
+<pre><code>more code
+</code></pre>
+````````````````````````````````
+
+
+```````````````````````````````` example
+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>
+````````````````````````````````
+
+
+Note that an additional space of indentation is interpreted as space
+inside the code block:
+
+```````````````````````````````` example
+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>
+````````````````````````````````
+
+
+Note that rules #1 and #2 only apply to two cases: (a) cases
+in which the lines to be included in a list item begin with a
+character other than a space or tab, and (b) cases in which
+they begin with an indented code
+block. In a case like the following, where the first block begins with
+three spaces of indentation, the rules do not allow us to form a list item by
+indenting the whole thing and prepending a list marker:
+
+```````````````````````````````` example
+ foo
+
+bar
+.
+<p>foo</p>
+<p>bar</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+- foo
+
+ bar
+.
+<ul>
+<li>foo</li>
+</ul>
+<p>bar</p>
+````````````````````````````````
+
+
+This is not a significant restriction, because when a block is preceded by up to
+three spaces of indentation, the indentation can always be removed without
+a change in interpretation, allowing rule #1 to be applied. So, in
+the above case:
+
+```````````````````````````````` example
+- foo
+
+ bar
+.
+<ul>
+<li>
+<p>foo</p>
+<p>bar</p>
+</li>
+</ul>
+````````````````````````````````
+
+
+3. **Item starting with a blank line.** If a sequence of lines *Ls*
+ starting with a single [blank line] constitute a (possibly empty)
+ sequence of blocks *Bs*, and *M* is a list marker of width *W*,
+ then the result of prepending *M* to the first line of *Ls*, and
+ preceding subsequent lines of *Ls* by *W + 1* spaces of indentation, is a
+ list item with *Bs* as its contents.
+ If a line is empty, then it need not be indented. The type of the
+ list item (bullet or ordered) is determined by the type of its list
+ marker. If the list item is ordered, then it is also assigned a
+ start number, based on the ordered list marker.
+
+Here are some list items that start with a blank line but are not empty:
+
+```````````````````````````````` example
+-
+ foo
+-
+ ```
+ bar
+ ```
+-
+ baz
+.
+<ul>
+<li>foo</li>
+<li>
+<pre><code>bar
+</code></pre>
+</li>
+<li>
+<pre><code>baz
+</code></pre>
+</li>
+</ul>
+````````````````````````````````
+
+When the list item starts with a blank line, the number of spaces
+following the list marker doesn't change the required indentation:
+
+```````````````````````````````` example
+-
+ foo
+.
+<ul>
+<li>foo</li>
+</ul>
+````````````````````````````````
+
+
+A list item can begin with at most one blank line.
+In the following example, `foo` is not part of the list
+item:
+
+```````````````````````````````` example
+-
+
+ foo
+.
+<ul>
+<li></li>
+</ul>
+<p>foo</p>
+````````````````````````````````
+
+
+Here is an empty bullet list item:
+
+```````````````````````````````` example
+- foo
+-
+- bar
+.
+<ul>
+<li>foo</li>
+<li></li>
+<li>bar</li>
+</ul>
+````````````````````````````````
+
+
+It does not matter whether there are spaces or tabs following the [list marker]:
+
+```````````````````````````````` example
+- foo
+-
+- bar
+.
+<ul>
+<li>foo</li>
+<li></li>
+<li>bar</li>
+</ul>
+````````````````````````````````
+
+
+Here is an empty ordered list item:
+
+```````````````````````````````` example
+1. foo
+2.
+3. bar
+.
+<ol>
+<li>foo</li>
+<li></li>
+<li>bar</li>
+</ol>
+````````````````````````````````
+
+
+A list may start or end with an empty list item:
+
+```````````````````````````````` example
+*
+.
+<ul>
+<li></li>
+</ul>
+````````````````````````````````
+
+However, an empty list item cannot interrupt a paragraph:
+
+```````````````````````````````` example
+foo
+*
+
+foo
+1.
+.
+<p>foo
+*</p>
+<p>foo
+1.</p>
+````````````````````````````````
+
+
+4. **Indentation.** If a sequence of lines *Ls* constitutes a list item
+ according to rule #1, #2, or #3, then the result of preceding each line
+ of *Ls* by up to three spaces of indentation (the same for each line) also
+ constitutes a list item with the same contents and attributes. If a line is
+ empty, then it need not be indented.
+
+Indented one space:
+
+```````````````````````````````` example
+ 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>
+````````````````````````````````
+
+
+Indented two spaces:
+
+```````````````````````````````` example
+ 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>
+````````````````````````````````
+
+
+Indented three spaces:
+
+```````````````````````````````` example
+ 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>
+````````````````````````````````
+
+
+Four spaces indent gives a code block:
+
+```````````````````````````````` example
+ 1. A paragraph
+ with two lines.
+
+ indented code
+
+ > A block quote.
+.
+<pre><code>1. A paragraph
+ with two lines.
+
+ indented code
+
+ &gt; A block quote.
+</code></pre>
+````````````````````````````````
+
+
+
+5. **Laziness.** If a string of lines *Ls* constitute a [list
+ item](#list-items) with contents *Bs*, then the result of deleting
+ some or all of the indentation from one or more lines in which the
+ next character other than a space or tab after the indentation is
+ [paragraph continuation text] is a
+ list item with the same contents and attributes. The unindented
+ lines are called
+ [lazy continuation line](@)s.
+
+Here is an example with [lazy continuation lines]:
+
+```````````````````````````````` example
+ 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>
+````````````````````````````````
+
+
+Indentation can be partially deleted:
+
+```````````````````````````````` example
+ 1. A paragraph
+ with two lines.
+.
+<ol>
+<li>A paragraph
+with two lines.</li>
+</ol>
+````````````````````````````````
+
+
+These examples show how laziness can work in nested structures:
+
+```````````````````````````````` example
+> 1. > Blockquote
+continued here.
+.
+<blockquote>
+<ol>
+<li>
+<blockquote>
+<p>Blockquote
+continued here.</p>
+</blockquote>
+</li>
+</ol>
+</blockquote>
+````````````````````````````````
+
+
+```````````````````````````````` example
+> 1. > Blockquote
+> continued here.
+.
+<blockquote>
+<ol>
+<li>
+<blockquote>
+<p>Blockquote
+continued here.</p>
+</blockquote>
+</li>
+</ol>
+</blockquote>
+````````````````````````````````
+
+
+
+6. **That's all.** Nothing that is not counted as a list item by rules
+ #1--5 counts as a [list item](#list-items).
+
+The rules for sublists follow from the general rules
+[above][List items]. A sublist must be indented the same number
+of spaces of indentation a paragraph would need to be in order to be included
+in the list item.
+
+So, in this case we need two spaces indent:
+
+```````````````````````````````` example
+- foo
+ - bar
+ - baz
+ - boo
+.
+<ul>
+<li>foo
+<ul>
+<li>bar
+<ul>
+<li>baz
+<ul>
+<li>boo</li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+````````````````````````````````
+
+
+One is not enough:
+
+```````````````````````````````` example
+- foo
+ - bar
+ - baz
+ - boo
+.
+<ul>
+<li>foo</li>
+<li>bar</li>
+<li>baz</li>
+<li>boo</li>
+</ul>
+````````````````````````````````
+
+
+Here we need four, because the list marker is wider:
+
+```````````````````````````````` example
+10) foo
+ - bar
+.
+<ol start="10">
+<li>foo
+<ul>
+<li>bar</li>
+</ul>
+</li>
+</ol>
+````````````````````````````````
+
+
+Three is not enough:
+
+```````````````````````````````` example
+10) foo
+ - bar
+.
+<ol start="10">
+<li>foo</li>
+</ol>
+<ul>
+<li>bar</li>
+</ul>
+````````````````````````````````
+
+
+A list may be the first block in a list item:
+
+```````````````````````````````` example
+- - foo
+.
+<ul>
+<li>
+<ul>
+<li>foo</li>
+</ul>
+</li>
+</ul>
+````````````````````````````````
+
+
+```````````````````````````````` example
+1. - 2. foo
+.
+<ol>
+<li>
+<ul>
+<li>
+<ol start="2">
+<li>foo</li>
+</ol>
+</li>
+</ul>
+</li>
+</ol>
+````````````````````````````````
+
+
+A list item can contain a heading:
+
+```````````````````````````````` example
+- # Foo
+- Bar
+ ---
+ baz
+.
+<ul>
+<li>
+<h1>Foo</h1>
+</li>
+<li>
+<h2>Bar</h2>
+baz</li>
+</ul>
+````````````````````````````````
+
+
+### Motivation
+
+John Gruber's Markdown spec says the following about list items:
+
+1. "List markers typically start at the left margin, but may be indented
+ by up to three spaces. List markers must be followed by one or more
+ spaces or a tab."
+
+2. "To make lists look nice, you can wrap items with hanging indents....
+ But if you don't want to, you don't have to."
+
+3. "List items may consist of multiple paragraphs. Each subsequent
+ paragraph in a list item must be indented by either 4 spaces or one
+ tab."
+
+4. "It looks nice if you indent every line of the subsequent paragraphs,
+ but here again, Markdown will allow you to be lazy."
+
+5. "To put a blockquote within a list item, the blockquote's `>`
+ delimiters need to be indented."
+
+6. "To put a code block within a list item, the code block needs to be
+ indented twice — 8 spaces or two tabs."
+
+These rules specify that a paragraph under a list item must be indented
+four spaces (presumably, from the left margin, rather than the start of
+the list marker, but this is not said), and that code under a list item
+must be indented eight spaces instead of the usual four. They also say
+that a block quote must be indented, but not by how much; however, the
+example given has four spaces indentation. Although nothing is said
+about other kinds of block-level content, it is certainly reasonable to
+infer that *all* block elements under a list item, including other
+lists, must be indented four spaces. This principle has been called the
+*four-space rule*.
+
+The four-space rule is clear and principled, and if the reference
+implementation `Markdown.pl` had followed it, it probably would have
+become the standard. However, `Markdown.pl` allowed paragraphs and
+sublists to start with only two spaces indentation, at least on the
+outer level. Worse, its behavior was inconsistent: a sublist of an
+outer-level list needed two spaces indentation, but a sublist of this
+sublist needed three spaces. It is not surprising, then, that different
+implementations of Markdown have developed very different rules for
+determining what comes under a list item. (Pandoc and python-Markdown,
+for example, stuck with Gruber's syntax description and the four-space
+rule, while discount, redcarpet, marked, PHP Markdown, and others
+followed `Markdown.pl`'s behavior more closely.)
+
+Unfortunately, given the divergences between implementations, there
+is no way to give a spec for list items that will be guaranteed not
+to break any existing documents. However, the spec given here should
+correctly handle lists formatted with either the four-space rule or
+the more forgiving `Markdown.pl` behavior, provided they are laid out
+in a way that is natural for a human to read.
+
+The strategy here is to let the width and indentation of the list marker
+determine the indentation necessary for blocks to fall under the list
+item, rather than having a fixed and arbitrary number. The writer can
+think of the body of the list item as a unit which gets indented to the
+right enough to fit the list marker (and any indentation on the list
+marker). (The laziness rule, #5, then allows continuation lines to be
+unindented if needed.)
+
+This rule is superior, we claim, to any rule requiring a fixed level of
+indentation from the margin. The four-space rule is clear but
+unnatural. It is quite unintuitive that
+
+``` markdown
+- foo
+
+ bar
+
+ - baz
+```
+
+should be parsed as two lists with an intervening paragraph,
+
+``` html
+<ul>
+<li>foo</li>
+</ul>
+<p>bar</p>
+<ul>
+<li>baz</li>
+</ul>
+```
+
+as the four-space rule demands, rather than a single list,
+
+``` html
+<ul>
+<li>
+<p>foo</p>
+<p>bar</p>
+<ul>
+<li>baz</li>
+</ul>
+</li>
+</ul>
+```
+
+The choice of four spaces is arbitrary. It can be learned, but it is
+not likely to be guessed, and it trips up beginners regularly.
+
+Would it help to adopt a two-space rule? The problem is that such
+a rule, together with the rule allowing up to three spaces of indentation for
+the initial list marker, allows text that is indented *less than* the
+original list marker to be included in the list item. For example,
+`Markdown.pl` parses
+
+``` markdown
+ - one
+
+ two
+```
+
+as a single list item, with `two` a continuation paragraph:
+
+``` html
+<ul>
+<li>
+<p>one</p>
+<p>two</p>
+</li>
+</ul>
+```
+
+and similarly
+
+``` markdown
+> - one
+>
+> two
+```
+
+as
+
+``` html
+<blockquote>
+<ul>
+<li>
+<p>one</p>
+<p>two</p>
+</li>
+</ul>
+</blockquote>
+```
+
+This is extremely unintuitive.
+
+Rather than requiring a fixed indent from the margin, we could require
+a fixed indent (say, two spaces, or even one space) from the list marker (which
+may itself be indented). This proposal would remove the last anomaly
+discussed. Unlike the spec presented above, it would count the following
+as a list item with a subparagraph, even though the paragraph `bar`
+is not indented as far as the first paragraph `foo`:
+
+``` markdown
+ 10. foo
+
+ bar
+```
+
+Arguably this text does read like a list item with `bar` as a subparagraph,
+which may count in favor of the proposal. However, on this proposal indented
+code would have to be indented six spaces after the list marker. And this
+would break a lot of existing Markdown, which has the pattern:
+
+``` markdown
+1. foo
+
+ indented code
+```
+
+where the code is indented eight spaces. The spec above, by contrast, will
+parse this text as expected, since the code block's indentation is measured
+from the beginning of `foo`.
+
+The one case that needs special treatment is a list item that *starts*
+with indented code. How much indentation is required in that case, since
+we don't have a "first paragraph" to measure from? Rule #2 simply stipulates
+that in such cases, we require one space indentation from the list marker
+(and then the normal four spaces for the indented code). This will match the
+four-space rule in cases where the list marker plus its initial indentation
+takes four spaces (a common case), but diverge in other cases.
+
+## Lists
+
+A [list](@) is a sequence of one or more
+list items [of the same type]. The list items
+may be separated by any number of blank lines.
+
+Two list items are [of the same type](@)
+if they begin with a [list marker] of the same type.
+Two list markers are of the
+same type if (a) they are bullet list markers using the same character
+(`-`, `+`, or `*`) or (b) they are ordered list numbers with the same
+delimiter (either `.` or `)`).
+
+A list is an [ordered list](@)
+if its constituent list items begin with
+[ordered list markers], and a
+[bullet list](@) if its constituent list
+items begin with [bullet list markers].
+
+The [start number](@)
+of an [ordered list] is determined by the list number of
+its initial list item. The numbers of subsequent list items are
+disregarded.
+
+A list is [loose](@) if any of its constituent
+list items are separated by blank lines, or if any of its constituent
+list items directly contain two block-level elements with a blank line
+between them. Otherwise a list is [tight](@).
+(The difference in HTML output is that paragraphs in a loose list are
+wrapped in `<p>` tags, while paragraphs in a tight list are not.)
+
+Changing the bullet or ordered list delimiter starts a new list:
+
+```````````````````````````````` example
+- foo
+- bar
++ baz
+.
+<ul>
+<li>foo</li>
+<li>bar</li>
+</ul>
+<ul>
+<li>baz</li>
+</ul>
+````````````````````````````````
+
+
+```````````````````````````````` example
+1. foo
+2. bar
+3) baz
+.
+<ol>
+<li>foo</li>
+<li>bar</li>
+</ol>
+<ol start="3">
+<li>baz</li>
+</ol>
+````````````````````````````````
+
+
+In CommonMark, a list can interrupt a paragraph. That is,
+no blank line is needed to separate a paragraph from a following
+list:
+
+```````````````````````````````` example
+Foo
+- bar
+- baz
+.
+<p>Foo</p>
+<ul>
+<li>bar</li>
+<li>baz</li>
+</ul>
+````````````````````````````````
+
+`Markdown.pl` does not allow this, through fear of triggering a list
+via a numeral in a hard-wrapped line:
+
+``` markdown
+The number of windows in my house is
+14. The number of doors is 6.
+```
+
+Oddly, though, `Markdown.pl` *does* allow a blockquote to
+interrupt a paragraph, even though the same considerations might
+apply.
+
+In CommonMark, we do allow lists to interrupt paragraphs, for
+two reasons. First, it is natural and not uncommon for people
+to start lists without blank lines:
+
+``` markdown
+I need to buy
+- new shoes
+- a coat
+- a plane ticket
+```
+
+Second, we are attracted to a
+
+> [principle of uniformity](@):
+> if a chunk of text has a certain
+> meaning, it will continue to have the same meaning when put into a
+> container block (such as a list item or blockquote).
+
+(Indeed, the spec for [list items] and [block quotes] presupposes
+this principle.) This principle implies that if
+
+``` markdown
+ * I need to buy
+ - new shoes
+ - a coat
+ - a plane ticket
+```
+
+is a list item containing a paragraph followed by a nested sublist,
+as all Markdown implementations agree it is (though the paragraph
+may be rendered without `<p>` tags, since the list is "tight"),
+then
+
+``` markdown
+I need to buy
+- new shoes
+- a coat
+- a plane ticket
+```
+
+by itself should be a paragraph followed by a nested sublist.
+
+Since it is well established Markdown practice to allow lists to
+interrupt paragraphs inside list items, the [principle of
+uniformity] requires us to allow this outside list items as
+well. ([reStructuredText](https://docutils.sourceforge.net/rst.html)
+takes a different approach, requiring blank lines before lists
+even inside other list items.)
+
+In order to solve the problem of unwanted lists in paragraphs with
+hard-wrapped numerals, we allow only lists starting with `1` to
+interrupt paragraphs. Thus,
+
+```````````````````````````````` example
+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>
+````````````````````````````````
+
+We may still get an unintended result in cases like
+
+```````````````````````````````` example
+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>
+````````````````````````````````
+
+but this rule should prevent most spurious list captures.
+
+There can be any number of blank lines between items:
+
+```````````````````````````````` example
+- foo
+
+- bar
+
+
+- baz
+.
+<ul>
+<li>
+<p>foo</p>
+</li>
+<li>
+<p>bar</p>
+</li>
+<li>
+<p>baz</p>
+</li>
+</ul>
+````````````````````````````````
+
+```````````````````````````````` example
+- foo
+ - bar
+ - baz
+
+
+ bim
+.
+<ul>
+<li>foo
+<ul>
+<li>bar
+<ul>
+<li>
+<p>baz</p>
+<p>bim</p>
+</li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+````````````````````````````````
+
+
+To separate consecutive lists of the same type, or to separate a
+list from an indented code block that would otherwise be parsed
+as a subparagraph of the final list item, you can insert a blank HTML
+comment:
+
+```````````````````````````````` example
+- foo
+- bar
+
+<!-- -->
+
+- baz
+- bim
+.
+<ul>
+<li>foo</li>
+<li>bar</li>
+</ul>
+<!-- -->
+<ul>
+<li>baz</li>
+<li>bim</li>
+</ul>
+````````````````````````````````
+
+
+```````````````````````````````` example
+- foo
+
+ notcode
+
+- foo
+
+<!-- -->
+
+ code
+.
+<ul>
+<li>
+<p>foo</p>
+<p>notcode</p>
+</li>
+<li>
+<p>foo</p>
+</li>
+</ul>
+<!-- -->
+<pre><code>code
+</code></pre>
+````````````````````````````````
+
+
+List items need not be indented to the same level. The following
+list items will be treated as items at the same list level,
+since none is indented enough to belong to the previous list
+item:
+
+```````````````````````````````` example
+- 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>
+````````````````````````````````
+
+
+```````````````````````````````` example
+1. a
+
+ 2. b
+
+ 3. c
+.
+<ol>
+<li>
+<p>a</p>
+</li>
+<li>
+<p>b</p>
+</li>
+<li>
+<p>c</p>
+</li>
+</ol>
+````````````````````````````````
+
+Note, however, that list items may not be preceded by more than
+three spaces of indentation. Here `- e` is treated as a paragraph continuation
+line, because it is indented more than three spaces:
+
+```````````````````````````````` example
+- a
+ - b
+ - c
+ - d
+ - e
+.
+<ul>
+<li>a</li>
+<li>b</li>
+<li>c</li>
+<li>d
+- e</li>
+</ul>
+````````````````````````````````
+
+And here, `3. c` is treated as in indented code block,
+because it is indented four spaces and preceded by a
+blank line.
+
+```````````````````````````````` example
+1. a
+
+ 2. b
+
+ 3. c
+.
+<ol>
+<li>
+<p>a</p>
+</li>
+<li>
+<p>b</p>
+</li>
+</ol>
+<pre><code>3. c
+</code></pre>
+````````````````````````````````
+
+
+This is a loose list, because there is a blank line between
+two of the list items:
+
+```````````````````````````````` example
+- a
+- b
+
+- c
+.
+<ul>
+<li>
+<p>a</p>
+</li>
+<li>
+<p>b</p>
+</li>
+<li>
+<p>c</p>
+</li>
+</ul>
+````````````````````````````````
+
+
+So is this, with a empty second item:
+
+```````````````````````````````` example
+* a
+*
+
+* c
+.
+<ul>
+<li>
+<p>a</p>
+</li>
+<li></li>
+<li>
+<p>c</p>
+</li>
+</ul>
+````````````````````````````````
+
+
+These are loose lists, even though there are no blank lines between the items,
+because one of the items directly contains two block-level elements
+with a blank line between them:
+
+```````````````````````````````` example
+- a
+- b
+
+ c
+- d
+.
+<ul>
+<li>
+<p>a</p>
+</li>
+<li>
+<p>b</p>
+<p>c</p>
+</li>
+<li>
+<p>d</p>
+</li>
+</ul>
+````````````````````````````````
+
+
+```````````````````````````````` example
+- a
+- b
+
+ [ref]: /url
+- d
+.
+<ul>
+<li>
+<p>a</p>
+</li>
+<li>
+<p>b</p>
+</li>
+<li>
+<p>d</p>
+</li>
+</ul>
+````````````````````````````````
+
+
+This is a tight list, because the blank lines are in a code block:
+
+```````````````````````````````` example
+- a
+- ```
+ b
+
+
+ ```
+- c
+.
+<ul>
+<li>a</li>
+<li>
+<pre><code>b
+
+
+</code></pre>
+</li>
+<li>c</li>
+</ul>
+````````````````````````````````
+
+
+This is a tight list, because the blank line is between two
+paragraphs of a sublist. So the sublist is loose while
+the outer list is tight:
+
+```````````````````````````````` example
+- a
+ - b
+
+ c
+- d
+.
+<ul>
+<li>a
+<ul>
+<li>
+<p>b</p>
+<p>c</p>
+</li>
+</ul>
+</li>
+<li>d</li>
+</ul>
+````````````````````````````````
+
+
+This is a tight list, because the blank line is inside the
+block quote:
+
+```````````````````````````````` example
+* a
+ > b
+ >
+* c
+.
+<ul>
+<li>a
+<blockquote>
+<p>b</p>
+</blockquote>
+</li>
+<li>c</li>
+</ul>
+````````````````````````````````
+
+
+This list is tight, because the consecutive block elements
+are not separated by blank lines:
+
+```````````````````````````````` example
+- a
+ > b
+ ```
+ c
+ ```
+- d
+.
+<ul>
+<li>a
+<blockquote>
+<p>b</p>
+</blockquote>
+<pre><code>c
+</code></pre>
+</li>
+<li>d</li>
+</ul>
+````````````````````````````````
+
+
+A single-paragraph list is tight:
+
+```````````````````````````````` example
+- a
+.
+<ul>
+<li>a</li>
+</ul>
+````````````````````````````````
+
+
+```````````````````````````````` example
+- a
+ - b
+.
+<ul>
+<li>a
+<ul>
+<li>b</li>
+</ul>
+</li>
+</ul>
+````````````````````````````````
+
+
+This list is loose, because of the blank line between the
+two block elements in the list item:
+
+```````````````````````````````` example
+1. ```
+ foo
+ ```
+
+ bar
+.
+<ol>
+<li>
+<pre><code>foo
+</code></pre>
+<p>bar</p>
+</li>
+</ol>
+````````````````````````````````
+
+
+Here the outer list is loose, the inner list tight:
+
+```````````````````````````````` example
+* foo
+ * bar
+
+ baz
+.
+<ul>
+<li>
+<p>foo</p>
+<ul>
+<li>bar</li>
+</ul>
+<p>baz</p>
+</li>
+</ul>
+````````````````````````````````
+
+
+```````````````````````````````` example
+- 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>
+````````````````````````````````
+
+
+# Inlines
+
+Inlines are parsed sequentially from the beginning of the character
+stream to the end (left to right, in left-to-right languages).
+Thus, for example, in
+
+```````````````````````````````` example
+`hi`lo`
+.
+<p><code>hi</code>lo`</p>
+````````````````````````````````
+
+`hi` is parsed as code, leaving the backtick at the end as a literal
+backtick.
+
+
+
+## Code spans
+
+A [backtick string](@)
+is a string of one or more backtick characters (`` ` ``) that is neither
+preceded nor followed by a backtick.
+
+A [code span](@) begins with a backtick string and ends with
+a backtick string of equal length. The contents of the code span are
+the characters between these two backtick strings, normalized in the
+following ways:
+
+- First, [line endings] are converted to [spaces].
+- If the resulting string both begins *and* ends with a [space]
+ character, but does not consist entirely of [space]
+ characters, a single [space] character is removed from the
+ front and back. This allows you to include code that begins
+ or ends with backtick characters, which must be separated by
+ whitespace from the opening or closing backtick strings.
+
+This is a simple code span:
+
+```````````````````````````````` example
+`foo`
+.
+<p><code>foo</code></p>
+````````````````````````````````
+
+
+Here two backticks are used, because the code contains a backtick.
+This example also illustrates stripping of a single leading and
+trailing space:
+
+```````````````````````````````` example
+`` foo ` bar ``
+.
+<p><code>foo ` bar</code></p>
+````````````````````````````````
+
+
+This example shows the motivation for stripping leading and trailing
+spaces:
+
+```````````````````````````````` example
+` `` `
+.
+<p><code>``</code></p>
+````````````````````````````````
+
+Note that only *one* space is stripped:
+
+```````````````````````````````` example
+` `` `
+.
+<p><code> `` </code></p>
+````````````````````````````````
+
+The stripping only happens if the space is on both
+sides of the string:
+
+```````````````````````````````` example
+` a`
+.
+<p><code> a</code></p>
+````````````````````````````````
+
+Only [spaces], and not [unicode whitespace] in general, are
+stripped in this way:
+
+```````````````````````````````` example
+` b `
+.
+<p><code> b </code></p>
+````````````````````````````````
+
+No stripping occurs if the code span contains only spaces:
+
+```````````````````````````````` example
+` `
+` `
+.
+<p><code> </code>
+<code> </code></p>
+````````````````````````````````
+
+
+[Line endings] are treated like spaces:
+
+```````````````````````````````` example
+``
+foo
+bar
+baz
+``
+.
+<p><code>foo bar baz</code></p>
+````````````````````````````````
+
+```````````````````````````````` example
+``
+foo
+``
+.
+<p><code>foo </code></p>
+````````````````````````````````
+
+
+Interior spaces are not collapsed:
+
+```````````````````````````````` example
+`foo bar
+baz`
+.
+<p><code>foo bar baz</code></p>
+````````````````````````````````
+
+Note that browsers will typically collapse consecutive spaces
+when rendering `<code>` elements, so it is recommended that
+the following CSS be used:
+
+ code{white-space: pre-wrap;}
+
+
+Note that backslash escapes do not work in code spans. All backslashes
+are treated literally:
+
+```````````````````````````````` example
+`foo\`bar`
+.
+<p><code>foo\</code>bar`</p>
+````````````````````````````````
+
+
+Backslash escapes are never needed, because one can always choose a
+string of *n* backtick characters as delimiters, where the code does
+not contain any strings of exactly *n* backtick characters.
+
+```````````````````````````````` example
+``foo`bar``
+.
+<p><code>foo`bar</code></p>
+````````````````````````````````
+
+```````````````````````````````` example
+` foo `` bar `
+.
+<p><code>foo `` bar</code></p>
+````````````````````````````````
+
+
+Code span backticks have higher precedence than any other inline
+constructs except HTML tags and autolinks. Thus, for example, this is
+not parsed as emphasized text, since the second `*` is part of a code
+span:
+
+```````````````````````````````` example
+*foo`*`
+.
+<p>*foo<code>*</code></p>
+````````````````````````````````
+
+
+And this is not parsed as a link:
+
+```````````````````````````````` example
+[not a `link](/foo`)
+.
+<p>[not a <code>link](/foo</code>)</p>
+````````````````````````````````
+
+
+Code spans, HTML tags, and autolinks have the same precedence.
+Thus, this is code:
+
+```````````````````````````````` example
+`<a href="`">`
+.
+<p><code>&lt;a href=&quot;</code>&quot;&gt;`</p>
+````````````````````````````````
+
+
+But this is an HTML tag:
+
+```````````````````````````````` example
+<a href="`">`
+.
+<p><a href="`">`</p>
+````````````````````````````````
+
+
+And this is code:
+
+```````````````````````````````` example
+`<https://foo.bar.`baz>`
+.
+<p><code>&lt;https://foo.bar.</code>baz&gt;`</p>
+````````````````````````````````
+
+
+But this is an autolink:
+
+```````````````````````````````` example
+<https://foo.bar.`baz>`
+.
+<p><a href="https://foo.bar.%60baz">https://foo.bar.`baz</a>`</p>
+````````````````````````````````
+
+
+When a backtick string is not closed by a matching backtick string,
+we just have literal backticks:
+
+```````````````````````````````` example
+```foo``
+.
+<p>```foo``</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+`foo
+.
+<p>`foo</p>
+````````````````````````````````
+
+The following case also illustrates the need for opening and
+closing backtick strings to be equal in length:
+
+```````````````````````````````` example
+`foo``bar``
+.
+<p>`foo<code>bar</code></p>
+````````````````````````````````
+
+
+## Emphasis and strong emphasis
+
+John Gruber's original [Markdown syntax
+description](https://daringfireball.net/projects/markdown/syntax#em) says:
+
+> Markdown treats asterisks (`*`) and underscores (`_`) as indicators of
+> emphasis. Text wrapped with one `*` or `_` will be wrapped with an HTML
+> `<em>` tag; double `*`'s or `_`'s will be wrapped with an HTML `<strong>`
+> tag.
+
+This is enough for most users, but these rules leave much undecided,
+especially when it comes to nested emphasis. The original
+`Markdown.pl` test suite makes it clear that triple `***` and
+`___` delimiters can be used for strong emphasis, and most
+implementations have also allowed the following patterns:
+
+``` markdown
+***strong emph***
+***strong** in emph*
+***emph* in strong**
+**in strong *emph***
+*in emph **strong***
+```
+
+The following patterns are less widely supported, but the intent
+is clear and they are useful (especially in contexts like bibliography
+entries):
+
+``` markdown
+*emph *with emph* in it*
+**strong **with strong** in it**
+```
+
+Many implementations have also restricted intraword emphasis to
+the `*` forms, to avoid unwanted emphasis in words containing
+internal underscores. (It is best practice to put these in code
+spans, but users often do not.)
+
+``` markdown
+internal emphasis: foo*bar*baz
+no emphasis: foo_bar_baz
+```
+
+The rules given below capture all of these patterns, while allowing
+for efficient parsing strategies that do not backtrack.
+
+First, some definitions. A [delimiter run](@) is either
+a sequence of one or more `*` characters that is not preceded or
+followed by a non-backslash-escaped `*` character, or a sequence
+of one or more `_` characters that is not preceded or followed by
+a non-backslash-escaped `_` character.
+
+A [left-flanking delimiter run](@) is
+a [delimiter run] that is (1) not followed by [Unicode whitespace],
+and either (2a) not followed by a [Unicode punctuation character], or
+(2b) followed by a [Unicode punctuation character] and
+preceded by [Unicode whitespace] or a [Unicode punctuation character].
+For purposes of this definition, the beginning and the end of
+the line count as Unicode whitespace.
+
+A [right-flanking delimiter run](@) is
+a [delimiter run] that is (1) not preceded by [Unicode whitespace],
+and either (2a) not preceded by a [Unicode punctuation character], or
+(2b) preceded by a [Unicode punctuation character] and
+followed by [Unicode whitespace] or a [Unicode punctuation character].
+For purposes of this definition, the beginning and the end of
+the line count as Unicode whitespace.
+
+Here are some examples of delimiter runs.
+
+ - left-flanking but not right-flanking:
+
+ ```
+ ***abc
+ _abc
+ **"abc"
+ _"abc"
+ ```
+
+ - right-flanking but not left-flanking:
+
+ ```
+ abc***
+ abc_
+ "abc"**
+ "abc"_
+ ```
+
+ - Both left and right-flanking:
+
+ ```
+ abc***def
+ "abc"_"def"
+ ```
+
+ - Neither left nor right-flanking:
+
+ ```
+ abc *** def
+ a _ b
+ ```
+
+(The idea of distinguishing left-flanking and right-flanking
+delimiter runs based on the character before and the character
+after comes from Roopesh Chander's
+[vfmd](https://web.archive.org/web/20220608143320/http://www.vfmd.org/vfmd-spec/specification/#procedure-for-identifying-emphasis-tags).
+vfmd uses the terminology "emphasis indicator string" instead of "delimiter
+run," and its rules for distinguishing left- and right-flanking runs
+are a bit more complex than the ones given here.)
+
+The following rules define emphasis and strong emphasis:
+
+1. A single `*` character [can open emphasis](@)
+ iff (if and only if) it is part of a [left-flanking delimiter run].
+
+2. A single `_` character [can open emphasis] iff
+ it is part of a [left-flanking delimiter run]
+ and either (a) not part of a [right-flanking delimiter run]
+ or (b) part of a [right-flanking delimiter run]
+ preceded by a [Unicode punctuation character].
+
+3. A single `*` character [can close emphasis](@)
+ iff it is part of a [right-flanking delimiter run].
+
+4. A single `_` character [can close emphasis] iff
+ it is part of a [right-flanking delimiter run]
+ and either (a) not part of a [left-flanking delimiter run]
+ or (b) part of a [left-flanking delimiter run]
+ followed by a [Unicode punctuation character].
+
+5. A double `**` [can open strong emphasis](@)
+ iff it is part of a [left-flanking delimiter run].
+
+6. A double `__` [can open strong emphasis] iff
+ it is part of a [left-flanking delimiter run]
+ and either (a) not part of a [right-flanking delimiter run]
+ or (b) part of a [right-flanking delimiter run]
+ preceded by a [Unicode punctuation character].
+
+7. A double `**` [can close strong emphasis](@)
+ iff it is part of a [right-flanking delimiter run].
+
+8. A double `__` [can close strong emphasis] iff
+ it is part of a [right-flanking delimiter run]
+ and either (a) not part of a [left-flanking delimiter run]
+ or (b) part of a [left-flanking delimiter run]
+ followed by a [Unicode punctuation character].
+
+9. Emphasis begins with a delimiter that [can open emphasis] and ends
+ with a delimiter that [can close emphasis], and that uses the same
+ character (`_` or `*`) as the opening delimiter. The
+ opening and closing delimiters must belong to separate
+ [delimiter runs]. If one of the delimiters can both
+ open and close emphasis, then the sum of the lengths of the
+ delimiter runs containing the opening and closing delimiters
+ must not be a multiple of 3 unless both lengths are
+ multiples of 3.
+
+10. Strong emphasis begins with a delimiter that
+ [can open strong emphasis] and ends with a delimiter that
+ [can close strong emphasis], and that uses the same character
+ (`_` or `*`) as the opening delimiter. The
+ opening and closing delimiters must belong to separate
+ [delimiter runs]. If one of the delimiters can both open
+ and close strong emphasis, then the sum of the lengths of
+ the delimiter runs containing the opening and closing
+ delimiters must not be a multiple of 3 unless both lengths
+ are multiples of 3.
+
+11. A literal `*` character cannot occur at the beginning or end of
+ `*`-delimited emphasis or `**`-delimited strong emphasis, unless it
+ is backslash-escaped.
+
+12. A literal `_` character cannot occur at the beginning or end of
+ `_`-delimited emphasis or `__`-delimited strong emphasis, unless it
+ is backslash-escaped.
+
+Where rules 1--12 above are compatible with multiple parsings,
+the following principles resolve ambiguity:
+
+13. The number of nestings should be minimized. Thus, for example,
+ an interpretation `<strong>...</strong>` is always preferred to
+ `<em><em>...</em></em>`.
+
+14. An interpretation `<em><strong>...</strong></em>` is always
+ preferred to `<strong><em>...</em></strong>`.
+
+15. When two potential emphasis or strong emphasis spans overlap,
+ so that the second begins before the first ends and ends after
+ the first ends, the first takes precedence. Thus, for example,
+ `*foo _bar* baz_` is parsed as `<em>foo _bar</em> baz_` rather
+ than `*foo <em>bar* baz</em>`.
+
+16. When there are two potential emphasis or strong emphasis spans
+ with the same closing delimiter, the shorter one (the one that
+ opens later) takes precedence. Thus, for example,
+ `**foo **bar baz**` is parsed as `**foo <strong>bar baz</strong>`
+ rather than `<strong>foo **bar baz</strong>`.
+
+17. Inline code spans, links, images, and HTML tags group more tightly
+ than emphasis. So, when there is a choice between an interpretation
+ that contains one of these elements and one that does not, the
+ former always wins. Thus, for example, `*[foo*](bar)` is
+ parsed as `*<a href="bar">foo*</a>` rather than as
+ `<em>[foo</em>](bar)`.
+
+These rules can be illustrated through a series of examples.
+
+Rule 1:
+
+```````````````````````````````` example
+*foo bar*
+.
+<p><em>foo bar</em></p>
+````````````````````````````````
+
+
+This is not emphasis, because the opening `*` is followed by
+whitespace, and hence not part of a [left-flanking delimiter run]:
+
+```````````````````````````````` example
+a * foo bar*
+.
+<p>a * foo bar*</p>
+````````````````````````````````
+
+
+This is not emphasis, because the opening `*` is preceded
+by an alphanumeric and followed by punctuation, and hence
+not part of a [left-flanking delimiter run]:
+
+```````````````````````````````` example
+a*"foo"*
+.
+<p>a*&quot;foo&quot;*</p>
+````````````````````````````````
+
+
+Unicode nonbreaking spaces count as whitespace, too:
+
+```````````````````````````````` example
+* a *
+.
+<p>* a *</p>
+````````````````````````````````
+
+
+Unicode symbols count as punctuation, too:
+
+```````````````````````````````` example
+*$*alpha.
+
+*£*bravo.
+
+*€*charlie.
+.
+<p>*$*alpha.</p>
+<p>*£*bravo.</p>
+<p>*€*charlie.</p>
+````````````````````````````````
+
+
+Intraword emphasis with `*` is permitted:
+
+```````````````````````````````` example
+foo*bar*
+.
+<p>foo<em>bar</em></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+5*6*78
+.
+<p>5<em>6</em>78</p>
+````````````````````````````````
+
+
+Rule 2:
+
+```````````````````````````````` example
+_foo bar_
+.
+<p><em>foo bar</em></p>
+````````````````````````````````
+
+
+This is not emphasis, because the opening `_` is followed by
+whitespace:
+
+```````````````````````````````` example
+_ foo bar_
+.
+<p>_ foo bar_</p>
+````````````````````````````````
+
+
+This is not emphasis, because the opening `_` is preceded
+by an alphanumeric and followed by punctuation:
+
+```````````````````````````````` example
+a_"foo"_
+.
+<p>a_&quot;foo&quot;_</p>
+````````````````````````````````
+
+
+Emphasis with `_` is not allowed inside words:
+
+```````````````````````````````` example
+foo_bar_
+.
+<p>foo_bar_</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+5_6_78
+.
+<p>5_6_78</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+пристаням_стремятся_
+.
+<p>пристаням_стремятся_</p>
+````````````````````````````````
+
+
+Here `_` does not generate emphasis, because the first delimiter run
+is right-flanking and the second left-flanking:
+
+```````````````````````````````` example
+aa_"bb"_cc
+.
+<p>aa_&quot;bb&quot;_cc</p>
+````````````````````````````````
+
+
+This is emphasis, even though the opening delimiter is
+both left- and right-flanking, because it is preceded by
+punctuation:
+
+```````````````````````````````` example
+foo-_(bar)_
+.
+<p>foo-<em>(bar)</em></p>
+````````````````````````````````
+
+
+Rule 3:
+
+This is not emphasis, because the closing delimiter does
+not match the opening delimiter:
+
+```````````````````````````````` example
+_foo*
+.
+<p>_foo*</p>
+````````````````````````````````
+
+
+This is not emphasis, because the closing `*` is preceded by
+whitespace:
+
+```````````````````````````````` example
+*foo bar *
+.
+<p>*foo bar *</p>
+````````````````````````````````
+
+
+A line ending also counts as whitespace:
+
+```````````````````````````````` example
+*foo bar
+*
+.
+<p>*foo bar
+*</p>
+````````````````````````````````
+
+
+This is not emphasis, because the second `*` is
+preceded by punctuation and followed by an alphanumeric
+(hence it is not part of a [right-flanking delimiter run]:
+
+```````````````````````````````` example
+*(*foo)
+.
+<p>*(*foo)</p>
+````````````````````````````````
+
+
+The point of this restriction is more easily appreciated
+with this example:
+
+```````````````````````````````` example
+*(*foo*)*
+.
+<p><em>(<em>foo</em>)</em></p>
+````````````````````````````````
+
+
+Intraword emphasis with `*` is allowed:
+
+```````````````````````````````` example
+*foo*bar
+.
+<p><em>foo</em>bar</p>
+````````````````````````````````
+
+
+
+Rule 4:
+
+This is not emphasis, because the closing `_` is preceded by
+whitespace:
+
+```````````````````````````````` example
+_foo bar _
+.
+<p>_foo bar _</p>
+````````````````````````````````
+
+
+This is not emphasis, because the second `_` is
+preceded by punctuation and followed by an alphanumeric:
+
+```````````````````````````````` example
+_(_foo)
+.
+<p>_(_foo)</p>
+````````````````````````````````
+
+
+This is emphasis within emphasis:
+
+```````````````````````````````` example
+_(_foo_)_
+.
+<p><em>(<em>foo</em>)</em></p>
+````````````````````````````````
+
+
+Intraword emphasis is disallowed for `_`:
+
+```````````````````````````````` example
+_foo_bar
+.
+<p>_foo_bar</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+_пристаням_стремятся
+.
+<p>_пристаням_стремятся</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+_foo_bar_baz_
+.
+<p><em>foo_bar_baz</em></p>
+````````````````````````````````
+
+
+This is emphasis, even though the closing delimiter is
+both left- and right-flanking, because it is followed by
+punctuation:
+
+```````````````````````````````` example
+_(bar)_.
+.
+<p><em>(bar)</em>.</p>
+````````````````````````````````
+
+
+Rule 5:
+
+```````````````````````````````` example
+**foo bar**
+.
+<p><strong>foo bar</strong></p>
+````````````````````````````````
+
+
+This is not strong emphasis, because the opening delimiter is
+followed by whitespace:
+
+```````````````````````````````` example
+** foo bar**
+.
+<p>** foo bar**</p>
+````````````````````````````````
+
+
+This is not strong emphasis, because the opening `**` is preceded
+by an alphanumeric and followed by punctuation, and hence
+not part of a [left-flanking delimiter run]:
+
+```````````````````````````````` example
+a**"foo"**
+.
+<p>a**&quot;foo&quot;**</p>
+````````````````````````````````
+
+
+Intraword strong emphasis with `**` is permitted:
+
+```````````````````````````````` example
+foo**bar**
+.
+<p>foo<strong>bar</strong></p>
+````````````````````````````````
+
+
+Rule 6:
+
+```````````````````````````````` example
+__foo bar__
+.
+<p><strong>foo bar</strong></p>
+````````````````````````````````
+
+
+This is not strong emphasis, because the opening delimiter is
+followed by whitespace:
+
+```````````````````````````````` example
+__ foo bar__
+.
+<p>__ foo bar__</p>
+````````````````````````````````
+
+
+A line ending counts as whitespace:
+```````````````````````````````` example
+__
+foo bar__
+.
+<p>__
+foo bar__</p>
+````````````````````````````````
+
+
+This is not strong emphasis, because the opening `__` is preceded
+by an alphanumeric and followed by punctuation:
+
+```````````````````````````````` example
+a__"foo"__
+.
+<p>a__&quot;foo&quot;__</p>
+````````````````````````````````
+
+
+Intraword strong emphasis is forbidden with `__`:
+
+```````````````````````````````` example
+foo__bar__
+.
+<p>foo__bar__</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+5__6__78
+.
+<p>5__6__78</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+пристаням__стремятся__
+.
+<p>пристаням__стремятся__</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+__foo, __bar__, baz__
+.
+<p><strong>foo, <strong>bar</strong>, baz</strong></p>
+````````````````````````````````
+
+
+This is strong emphasis, even though the opening delimiter is
+both left- and right-flanking, because it is preceded by
+punctuation:
+
+```````````````````````````````` example
+foo-__(bar)__
+.
+<p>foo-<strong>(bar)</strong></p>
+````````````````````````````````
+
+
+
+Rule 7:
+
+This is not strong emphasis, because the closing delimiter is preceded
+by whitespace:
+
+```````````````````````````````` example
+**foo bar **
+.
+<p>**foo bar **</p>
+````````````````````````````````
+
+
+(Nor can it be interpreted as an emphasized `*foo bar *`, because of
+Rule 11.)
+
+This is not strong emphasis, because the second `**` is
+preceded by punctuation and followed by an alphanumeric:
+
+```````````````````````````````` example
+**(**foo)
+.
+<p>**(**foo)</p>
+````````````````````````````````
+
+
+The point of this restriction is more easily appreciated
+with these examples:
+
+```````````````````````````````` example
+*(**foo**)*
+.
+<p><em>(<strong>foo</strong>)</em></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+**Gomphocarpus (*Gomphocarpus physocarpus*, syn.
+*Asclepias physocarpa*)**
+.
+<p><strong>Gomphocarpus (<em>Gomphocarpus physocarpus</em>, syn.
+<em>Asclepias physocarpa</em>)</strong></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+**foo "*bar*" foo**
+.
+<p><strong>foo &quot;<em>bar</em>&quot; foo</strong></p>
+````````````````````````````````
+
+
+Intraword emphasis:
+
+```````````````````````````````` example
+**foo**bar
+.
+<p><strong>foo</strong>bar</p>
+````````````````````````````````
+
+
+Rule 8:
+
+This is not strong emphasis, because the closing delimiter is
+preceded by whitespace:
+
+```````````````````````````````` example
+__foo bar __
+.
+<p>__foo bar __</p>
+````````````````````````````````
+
+
+This is not strong emphasis, because the second `__` is
+preceded by punctuation and followed by an alphanumeric:
+
+```````````````````````````````` example
+__(__foo)
+.
+<p>__(__foo)</p>
+````````````````````````````````
+
+
+The point of this restriction is more easily appreciated
+with this example:
+
+```````````````````````````````` example
+_(__foo__)_
+.
+<p><em>(<strong>foo</strong>)</em></p>
+````````````````````````````````
+
+
+Intraword strong emphasis is forbidden with `__`:
+
+```````````````````````````````` example
+__foo__bar
+.
+<p>__foo__bar</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+__пристаням__стремятся
+.
+<p>__пристаням__стремятся</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+__foo__bar__baz__
+.
+<p><strong>foo__bar__baz</strong></p>
+````````````````````````````````
+
+
+This is strong emphasis, even though the closing delimiter is
+both left- and right-flanking, because it is followed by
+punctuation:
+
+```````````````````````````````` example
+__(bar)__.
+.
+<p><strong>(bar)</strong>.</p>
+````````````````````````````````
+
+
+Rule 9:
+
+Any nonempty sequence of inline elements can be the contents of an
+emphasized span.
+
+```````````````````````````````` example
+*foo [bar](/url)*
+.
+<p><em>foo <a href="/url">bar</a></em></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+*foo
+bar*
+.
+<p><em>foo
+bar</em></p>
+````````````````````````````````
+
+
+In particular, emphasis and strong emphasis can be nested
+inside emphasis:
+
+```````````````````````````````` example
+_foo __bar__ baz_
+.
+<p><em>foo <strong>bar</strong> baz</em></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+_foo _bar_ baz_
+.
+<p><em>foo <em>bar</em> baz</em></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+__foo_ bar_
+.
+<p><em><em>foo</em> bar</em></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+*foo *bar**
+.
+<p><em>foo <em>bar</em></em></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+*foo **bar** baz*
+.
+<p><em>foo <strong>bar</strong> baz</em></p>
+````````````````````````````````
+
+```````````````````````````````` example
+*foo**bar**baz*
+.
+<p><em>foo<strong>bar</strong>baz</em></p>
+````````````````````````````````
+
+Note that in the preceding case, the interpretation
+
+``` markdown
+<p><em>foo</em><em>bar<em></em>baz</em></p>
+```
+
+
+is precluded by the condition that a delimiter that
+can both open and close (like the `*` after `foo`)
+cannot form emphasis if the sum of the lengths of
+the delimiter runs containing the opening and
+closing delimiters is a multiple of 3 unless
+both lengths are multiples of 3.
+
+
+For the same reason, we don't get two consecutive
+emphasis sections in this example:
+
+```````````````````````````````` example
+*foo**bar*
+.
+<p><em>foo**bar</em></p>
+````````````````````````````````
+
+
+The same condition ensures that the following
+cases are all strong emphasis nested inside
+emphasis, even when the interior whitespace is
+omitted:
+
+
+```````````````````````````````` example
+***foo** bar*
+.
+<p><em><strong>foo</strong> bar</em></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+*foo **bar***
+.
+<p><em>foo <strong>bar</strong></em></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+*foo**bar***
+.
+<p><em>foo<strong>bar</strong></em></p>
+````````````````````````````````
+
+
+When the lengths of the interior closing and opening
+delimiter runs are *both* multiples of 3, though,
+they can match to create emphasis:
+
+```````````````````````````````` example
+foo***bar***baz
+.
+<p>foo<em><strong>bar</strong></em>baz</p>
+````````````````````````````````
+
+```````````````````````````````` example
+foo******bar*********baz
+.
+<p>foo<strong><strong><strong>bar</strong></strong></strong>***baz</p>
+````````````````````````````````
+
+
+Indefinite levels of nesting are possible:
+
+```````````````````````````````` example
+*foo **bar *baz* bim** bop*
+.
+<p><em>foo <strong>bar <em>baz</em> bim</strong> bop</em></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+*foo [*bar*](/url)*
+.
+<p><em>foo <a href="/url"><em>bar</em></a></em></p>
+````````````````````````````````
+
+
+There can be no empty emphasis or strong emphasis:
+
+```````````````````````````````` example
+** is not an empty emphasis
+.
+<p>** is not an empty emphasis</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+**** is not an empty strong emphasis
+.
+<p>**** is not an empty strong emphasis</p>
+````````````````````````````````
+
+
+
+Rule 10:
+
+Any nonempty sequence of inline elements can be the contents of an
+strongly emphasized span.
+
+```````````````````````````````` example
+**foo [bar](/url)**
+.
+<p><strong>foo <a href="/url">bar</a></strong></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+**foo
+bar**
+.
+<p><strong>foo
+bar</strong></p>
+````````````````````````````````
+
+
+In particular, emphasis and strong emphasis can be nested
+inside strong emphasis:
+
+```````````````````````````````` example
+__foo _bar_ baz__
+.
+<p><strong>foo <em>bar</em> baz</strong></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+__foo __bar__ baz__
+.
+<p><strong>foo <strong>bar</strong> baz</strong></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+____foo__ bar__
+.
+<p><strong><strong>foo</strong> bar</strong></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+**foo **bar****
+.
+<p><strong>foo <strong>bar</strong></strong></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+**foo *bar* baz**
+.
+<p><strong>foo <em>bar</em> baz</strong></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+**foo*bar*baz**
+.
+<p><strong>foo<em>bar</em>baz</strong></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+***foo* bar**
+.
+<p><strong><em>foo</em> bar</strong></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+**foo *bar***
+.
+<p><strong>foo <em>bar</em></strong></p>
+````````````````````````````````
+
+
+Indefinite levels of nesting are possible:
+
+```````````````````````````````` example
+**foo *bar **baz**
+bim* bop**
+.
+<p><strong>foo <em>bar <strong>baz</strong>
+bim</em> bop</strong></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+**foo [*bar*](/url)**
+.
+<p><strong>foo <a href="/url"><em>bar</em></a></strong></p>
+````````````````````````````````
+
+
+There can be no empty emphasis or strong emphasis:
+
+```````````````````````````````` example
+__ is not an empty emphasis
+.
+<p>__ is not an empty emphasis</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+____ is not an empty strong emphasis
+.
+<p>____ is not an empty strong emphasis</p>
+````````````````````````````````
+
+
+
+Rule 11:
+
+```````````````````````````````` example
+foo ***
+.
+<p>foo ***</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+foo *\**
+.
+<p>foo <em>*</em></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+foo *_*
+.
+<p>foo <em>_</em></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+foo *****
+.
+<p>foo *****</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+foo **\***
+.
+<p>foo <strong>*</strong></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+foo **_**
+.
+<p>foo <strong>_</strong></p>
+````````````````````````````````
+
+
+Note that when delimiters do not match evenly, Rule 11 determines
+that the excess literal `*` characters will appear outside of the
+emphasis, rather than inside it:
+
+```````````````````````````````` example
+**foo*
+.
+<p>*<em>foo</em></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+*foo**
+.
+<p><em>foo</em>*</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+***foo**
+.
+<p>*<strong>foo</strong></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+****foo*
+.
+<p>***<em>foo</em></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+**foo***
+.
+<p><strong>foo</strong>*</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+*foo****
+.
+<p><em>foo</em>***</p>
+````````````````````````````````
+
+
+
+Rule 12:
+
+```````````````````````````````` example
+foo ___
+.
+<p>foo ___</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+foo _\__
+.
+<p>foo <em>_</em></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+foo _*_
+.
+<p>foo <em>*</em></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+foo _____
+.
+<p>foo _____</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+foo __\___
+.
+<p>foo <strong>_</strong></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+foo __*__
+.
+<p>foo <strong>*</strong></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+__foo_
+.
+<p>_<em>foo</em></p>
+````````````````````````````````
+
+
+Note that when delimiters do not match evenly, Rule 12 determines
+that the excess literal `_` characters will appear outside of the
+emphasis, rather than inside it:
+
+```````````````````````````````` example
+_foo__
+.
+<p><em>foo</em>_</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+___foo__
+.
+<p>_<strong>foo</strong></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+____foo_
+.
+<p>___<em>foo</em></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+__foo___
+.
+<p><strong>foo</strong>_</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+_foo____
+.
+<p><em>foo</em>___</p>
+````````````````````````````````
+
+
+Rule 13 implies that if you want emphasis nested directly inside
+emphasis, you must use different delimiters:
+
+```````````````````````````````` example
+**foo**
+.
+<p><strong>foo</strong></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+*_foo_*
+.
+<p><em><em>foo</em></em></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+__foo__
+.
+<p><strong>foo</strong></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+_*foo*_
+.
+<p><em><em>foo</em></em></p>
+````````````````````````````````
+
+
+However, strong emphasis within strong emphasis is possible without
+switching delimiters:
+
+```````````````````````````````` example
+****foo****
+.
+<p><strong><strong>foo</strong></strong></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+____foo____
+.
+<p><strong><strong>foo</strong></strong></p>
+````````````````````````````````
+
+
+
+Rule 13 can be applied to arbitrarily long sequences of
+delimiters:
+
+```````````````````````````````` example
+******foo******
+.
+<p><strong><strong><strong>foo</strong></strong></strong></p>
+````````````````````````````````
+
+
+Rule 14:
+
+```````````````````````````````` example
+***foo***
+.
+<p><em><strong>foo</strong></em></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+_____foo_____
+.
+<p><em><strong><strong>foo</strong></strong></em></p>
+````````````````````````````````
+
+
+Rule 15:
+
+```````````````````````````````` example
+*foo _bar* baz_
+.
+<p><em>foo _bar</em> baz_</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+*foo __bar *baz bim__ bam*
+.
+<p><em>foo <strong>bar *baz bim</strong> bam</em></p>
+````````````````````````````````
+
+
+Rule 16:
+
+```````````````````````````````` example
+**foo **bar baz**
+.
+<p>**foo <strong>bar baz</strong></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+*foo *bar baz*
+.
+<p>*foo <em>bar baz</em></p>
+````````````````````````````````
+
+
+Rule 17:
+
+```````````````````````````````` example
+*[bar*](/url)
+.
+<p>*<a href="/url">bar*</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+_foo [bar_](/url)
+.
+<p>_foo <a href="/url">bar_</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+*<img src="foo" title="*"/>
+.
+<p>*<img src="foo" title="*"/></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+**<a href="**">
+.
+<p>**<a href="**"></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+__<a href="__">
+.
+<p>__<a href="__"></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+*a `*`*
+.
+<p><em>a <code>*</code></em></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+_a `_`_
+.
+<p><em>a <code>_</code></em></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+**a<https://foo.bar/?q=**>
+.
+<p>**a<a href="https://foo.bar/?q=**">https://foo.bar/?q=**</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+__a<https://foo.bar/?q=__>
+.
+<p>__a<a href="https://foo.bar/?q=__">https://foo.bar/?q=__</a></p>
+````````````````````````````````
+
+
+
+## Links
+
+A link contains [link text] (the visible text), a [link destination]
+(the URI that is the link destination), and optionally a [link title].
+There are two basic kinds of links in Markdown. In [inline links] the
+destination and title are given immediately after the link text. In
+[reference links] the destination and title are defined elsewhere in
+the document.
+
+A [link text](@) consists of a sequence of zero or more
+inline elements enclosed by square brackets (`[` and `]`). The
+following rules apply:
+
+- Links may not contain other links, at any level of nesting. If
+ multiple otherwise valid link definitions appear nested inside each
+ other, the inner-most definition is used.
+
+- Brackets are allowed in the [link text] only if (a) they
+ are backslash-escaped or (b) they appear as a matched pair of brackets,
+ with an open bracket `[`, a sequence of zero or more inlines, and
+ a close bracket `]`.
+
+- Backtick [code spans], [autolinks], and raw [HTML tags] bind more tightly
+ than the brackets in link text. Thus, for example,
+ `` [foo`]` `` could not be a link text, since the second `]`
+ is part of a code span.
+
+- The brackets in link text bind more tightly than markers for
+ [emphasis and strong emphasis]. Thus, for example, `*[foo*](url)` is a link.
+
+A [link destination](@) consists of either
+
+- a sequence of zero or more characters between an opening `<` and a
+ closing `>` that contains no line endings or unescaped
+ `<` or `>` characters, or
+
+- a nonempty sequence of characters that does not start with `<`,
+ does not include [ASCII control characters][ASCII control character]
+ or [space] character, and includes parentheses only if (a) they are
+ backslash-escaped or (b) they are part of a balanced pair of
+ unescaped parentheses.
+ (Implementations may impose limits on parentheses nesting to
+ avoid performance issues, but at least three levels of nesting
+ should be supported.)
+
+A [link title](@) consists of either
+
+- a sequence of zero or more characters between straight double-quote
+ characters (`"`), including a `"` character only if it is
+ backslash-escaped, or
+
+- a sequence of zero or more characters between straight single-quote
+ characters (`'`), including a `'` character only if it is
+ backslash-escaped, or
+
+- a sequence of zero or more characters between matching parentheses
+ (`(...)`), including a `(` or `)` character only if it is
+ backslash-escaped.
+
+Although [link titles] may span multiple lines, they may not contain
+a [blank line].
+
+An [inline link](@) consists of a [link text] followed immediately
+by a left parenthesis `(`, an optional [link destination], an optional
+[link title], and a right parenthesis `)`.
+These four components may be separated by spaces, tabs, and up to one line
+ending.
+If both [link destination] and [link title] are present, they *must* be
+separated by spaces, tabs, and up to one line ending.
+
+The link's text consists of the inlines contained
+in the [link text] (excluding the enclosing square brackets).
+The link's URI consists of the link destination, excluding enclosing
+`<...>` if present, with backslash-escapes in effect as described
+above. The link's title consists of the link title, excluding its
+enclosing delimiters, with backslash-escapes in effect as described
+above.
+
+Here is a simple inline link:
+
+```````````````````````````````` example
+[link](/uri "title")
+.
+<p><a href="/uri" title="title">link</a></p>
+````````````````````````````````
+
+
+The title, the link text and even
+the destination may be omitted:
+
+```````````````````````````````` example
+[link](/uri)
+.
+<p><a href="/uri">link</a></p>
+````````````````````````````````
+
+```````````````````````````````` example
+[](./target.md)
+.
+<p><a href="./target.md"></a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[link]()
+.
+<p><a href="">link</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[link](<>)
+.
+<p><a href="">link</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[]()
+.
+<p><a href=""></a></p>
+````````````````````````````````
+
+The destination can only contain spaces if it is
+enclosed in pointy brackets:
+
+```````````````````````````````` example
+[link](/my uri)
+.
+<p>[link](/my uri)</p>
+````````````````````````````````
+
+```````````````````````````````` example
+[link](</my uri>)
+.
+<p><a href="/my%20uri">link</a></p>
+````````````````````````````````
+
+The destination cannot contain line endings,
+even if enclosed in pointy brackets:
+
+```````````````````````````````` example
+[link](foo
+bar)
+.
+<p>[link](foo
+bar)</p>
+````````````````````````````````
+
+```````````````````````````````` example
+[link](<foo
+bar>)
+.
+<p>[link](<foo
+bar>)</p>
+````````````````````````````````
+
+The destination can contain `)` if it is enclosed
+in pointy brackets:
+
+```````````````````````````````` example
+[a](<b)c>)
+.
+<p><a href="b)c">a</a></p>
+````````````````````````````````
+
+Pointy brackets that enclose links must be unescaped:
+
+```````````````````````````````` example
+[link](<foo\>)
+.
+<p>[link](&lt;foo&gt;)</p>
+````````````````````````````````
+
+These are not links, because the opening pointy bracket
+is not matched properly:
+
+```````````````````````````````` example
+[a](<b)c
+[a](<b)c>
+[a](<b>c)
+.
+<p>[a](&lt;b)c
+[a](&lt;b)c&gt;
+[a](<b>c)</p>
+````````````````````````````````
+
+Parentheses inside the link destination may be escaped:
+
+```````````````````````````````` example
+[link](\(foo\))
+.
+<p><a href="(foo)">link</a></p>
+````````````````````````````````
+
+Any number of parentheses are allowed without escaping, as long as they are
+balanced:
+
+```````````````````````````````` example
+[link](foo(and(bar)))
+.
+<p><a href="foo(and(bar))">link</a></p>
+````````````````````````````````
+
+However, if you have unbalanced parentheses, you need to escape or use the
+`<...>` form:
+
+```````````````````````````````` example
+[link](foo(and(bar))
+.
+<p>[link](foo(and(bar))</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[link](foo\(and\(bar\))
+.
+<p><a href="foo(and(bar)">link</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[link](<foo(and(bar)>)
+.
+<p><a href="foo(and(bar)">link</a></p>
+````````````````````````````````
+
+
+Parentheses and other symbols can also be escaped, as usual
+in Markdown:
+
+```````````````````````````````` example
+[link](foo\)\:)
+.
+<p><a href="foo):">link</a></p>
+````````````````````````````````
+
+
+A link can contain fragment identifiers and queries:
+
+```````````````````````````````` example
+[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>
+````````````````````````````````
+
+
+Note that a backslash before a non-escapable character is
+just a backslash:
+
+```````````````````````````````` example
+[link](foo\bar)
+.
+<p><a href="foo%5Cbar">link</a></p>
+````````````````````````````````
+
+
+URL-escaping should be left alone inside the destination, as all
+URL-escaped characters are also valid URL characters. Entity and
+numerical character references in the destination will be parsed
+into the corresponding Unicode code points, as usual. These may
+be optionally URL-escaped when written as HTML, but this spec
+does not enforce any particular policy for rendering URLs in
+HTML or other formats. Renderers may make different decisions
+about how to escape or normalize URLs in the output.
+
+```````````````````````````````` example
+[link](foo%20b&auml;)
+.
+<p><a href="foo%20b%C3%A4">link</a></p>
+````````````````````````````````
+
+
+Note that, because titles can often be parsed as destinations,
+if you try to omit the destination and keep the title, you'll
+get unexpected results:
+
+```````````````````````````````` example
+[link]("title")
+.
+<p><a href="%22title%22">link</a></p>
+````````````````````````````````
+
+
+Titles may be in single quotes, double quotes, or parentheses:
+
+```````````````````````````````` example
+[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>
+````````````````````````````````
+
+
+Backslash escapes and entity and numeric character references
+may be used in titles:
+
+```````````````````````````````` example
+[link](/url "title \"&quot;")
+.
+<p><a href="/url" title="title &quot;&quot;">link</a></p>
+````````````````````````````````
+
+
+Titles must be separated from the link using spaces, tabs, and up to one line
+ending.
+Other [Unicode whitespace] like non-breaking space doesn't work.
+
+```````````````````````````````` example
+[link](/url "title")
+.
+<p><a href="/url%C2%A0%22title%22">link</a></p>
+````````````````````````````````
+
+
+Nested balanced quotes are not allowed without escaping:
+
+```````````````````````````````` example
+[link](/url "title "and" title")
+.
+<p>[link](/url &quot;title &quot;and&quot; title&quot;)</p>
+````````````````````````````````
+
+
+But it is easy to work around this by using a different quote type:
+
+```````````````````````````````` example
+[link](/url 'title "and" title')
+.
+<p><a href="/url" title="title &quot;and&quot; title">link</a></p>
+````````````````````````````````
+
+
+(Note: `Markdown.pl` did allow double quotes inside a double-quoted
+title, and its test suite included a test demonstrating this.
+But it is hard to see a good rationale for the extra complexity this
+brings, since there are already many ways---backslash escaping,
+entity and numeric character references, or using a different
+quote type for the enclosing title---to write titles containing
+double quotes. `Markdown.pl`'s handling of titles has a number
+of other strange features. For example, it allows single-quoted
+titles in inline links, but not reference links. And, in
+reference links but not inline links, it allows a title to begin
+with `"` and end with `)`. `Markdown.pl` 1.0.1 even allows
+titles with no closing quotation mark, though 1.0.2b8 does not.
+It seems preferable to adopt a simple, rational rule that works
+the same way in inline links and link reference definitions.)
+
+Spaces, tabs, and up to one line ending is allowed around the destination and
+title:
+
+```````````````````````````````` example
+[link]( /uri
+ "title" )
+.
+<p><a href="/uri" title="title">link</a></p>
+````````````````````````````````
+
+
+But it is not allowed between the link text and the
+following parenthesis:
+
+```````````````````````````````` example
+[link] (/uri)
+.
+<p>[link] (/uri)</p>
+````````````````````````````````
+
+
+The link text may contain balanced brackets, but not unbalanced ones,
+unless they are escaped:
+
+```````````````````````````````` example
+[link [foo [bar]]](/uri)
+.
+<p><a href="/uri">link [foo [bar]]</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[link] bar](/uri)
+.
+<p>[link] bar](/uri)</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[link [bar](/uri)
+.
+<p>[link <a href="/uri">bar</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[link \[bar](/uri)
+.
+<p><a href="/uri">link [bar</a></p>
+````````````````````````````````
+
+
+The link text may contain inline content:
+
+```````````````````````````````` example
+[link *foo **bar** `#`*](/uri)
+.
+<p><a href="/uri">link <em>foo <strong>bar</strong> <code>#</code></em></a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[![moon](moon.jpg)](/uri)
+.
+<p><a href="/uri"><img src="moon.jpg" alt="moon" /></a></p>
+````````````````````````````````
+
+
+However, links may not contain other links, at any level of nesting.
+
+```````````````````````````````` example
+[foo [bar](/uri)](/uri)
+.
+<p>[foo <a href="/uri">bar</a>](/uri)</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[foo *[bar [baz](/uri)](/uri)*](/uri)
+.
+<p>[foo <em>[bar <a href="/uri">baz</a>](/uri)</em>](/uri)</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+![[[foo](uri1)](uri2)](uri3)
+.
+<p><img src="uri3" alt="[foo](uri2)" /></p>
+````````````````````````````````
+
+
+These cases illustrate the precedence of link text grouping over
+emphasis grouping:
+
+```````````````````````````````` example
+*[foo*](/uri)
+.
+<p>*<a href="/uri">foo*</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[foo *bar](baz*)
+.
+<p><a href="baz*">foo *bar</a></p>
+````````````````````````````````
+
+
+Note that brackets that *aren't* part of links do not take
+precedence:
+
+```````````````````````````````` example
+*foo [bar* baz]
+.
+<p><em>foo [bar</em> baz]</p>
+````````````````````````````````
+
+
+These cases illustrate the precedence of HTML tags, code spans,
+and autolinks over link grouping:
+
+```````````````````````````````` example
+[foo <bar attr="](baz)">
+.
+<p>[foo <bar attr="](baz)"></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[foo`](/uri)`
+.
+<p>[foo<code>](/uri)</code></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[foo<https://example.com/?search=](uri)>
+.
+<p>[foo<a href="https://example.com/?search=%5D(uri)">https://example.com/?search=](uri)</a></p>
+````````````````````````````````
+
+
+There are three kinds of [reference link](@)s:
+[full](#full-reference-link), [collapsed](#collapsed-reference-link),
+and [shortcut](#shortcut-reference-link).
+
+A [full reference link](@)
+consists of a [link text] immediately followed by a [link label]
+that [matches] a [link reference definition] elsewhere in the document.
+
+A [link label](@) begins with a left bracket (`[`) and ends
+with the first right bracket (`]`) that is not backslash-escaped.
+Between these brackets there must be at least one character that is not a space,
+tab, or line ending.
+Unescaped square bracket characters are not allowed inside the
+opening and closing square brackets of [link labels]. A link
+label can have at most 999 characters inside the square
+brackets.
+
+One label [matches](@)
+another just in case their normalized forms are equal. To normalize a
+label, strip off the opening and closing brackets,
+perform the *Unicode case fold*, strip leading and trailing
+spaces, tabs, and line endings, and collapse consecutive internal
+spaces, tabs, and line endings to a single space. If there are multiple
+matching reference link definitions, the one that comes first in the
+document is used. (It is desirable in such cases to emit a warning.)
+
+The link's URI and title are provided by the matching [link
+reference definition].
+
+Here is a simple example:
+
+```````````````````````````````` example
+[foo][bar]
+
+[bar]: /url "title"
+.
+<p><a href="/url" title="title">foo</a></p>
+````````````````````````````````
+
+
+The rules for the [link text] are the same as with
+[inline links]. Thus:
+
+The link text may contain balanced brackets, but not unbalanced ones,
+unless they are escaped:
+
+```````````````````````````````` example
+[link [foo [bar]]][ref]
+
+[ref]: /uri
+.
+<p><a href="/uri">link [foo [bar]]</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[link \[bar][ref]
+
+[ref]: /uri
+.
+<p><a href="/uri">link [bar</a></p>
+````````````````````````````````
+
+
+The link text may contain inline content:
+
+```````````````````````````````` example
+[link *foo **bar** `#`*][ref]
+
+[ref]: /uri
+.
+<p><a href="/uri">link <em>foo <strong>bar</strong> <code>#</code></em></a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[![moon](moon.jpg)][ref]
+
+[ref]: /uri
+.
+<p><a href="/uri"><img src="moon.jpg" alt="moon" /></a></p>
+````````````````````````````````
+
+
+However, links may not contain other links, at any level of nesting.
+
+```````````````````````````````` example
+[foo [bar](/uri)][ref]
+
+[ref]: /uri
+.
+<p>[foo <a href="/uri">bar</a>]<a href="/uri">ref</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[foo *bar [baz][ref]*][ref]
+
+[ref]: /uri
+.
+<p>[foo <em>bar <a href="/uri">baz</a></em>]<a href="/uri">ref</a></p>
+````````````````````````````````
+
+
+(In the examples above, we have two [shortcut reference links]
+instead of one [full reference link].)
+
+The following cases illustrate the precedence of link text grouping over
+emphasis grouping:
+
+```````````````````````````````` example
+*[foo*][ref]
+
+[ref]: /uri
+.
+<p>*<a href="/uri">foo*</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[foo *bar][ref]*
+
+[ref]: /uri
+.
+<p><a href="/uri">foo *bar</a>*</p>
+````````````````````````````````
+
+
+These cases illustrate the precedence of HTML tags, code spans,
+and autolinks over link grouping:
+
+```````````````````````````````` example
+[foo <bar attr="][ref]">
+
+[ref]: /uri
+.
+<p>[foo <bar attr="][ref]"></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[foo`][ref]`
+
+[ref]: /uri
+.
+<p>[foo<code>][ref]</code></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[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>
+````````````````````````````````
+
+
+Matching is case-insensitive:
+
+```````````````````````````````` example
+[foo][BaR]
+
+[bar]: /url "title"
+.
+<p><a href="/url" title="title">foo</a></p>
+````````````````````````````````
+
+
+Unicode case fold is used:
+
+```````````````````````````````` example
+[ẞ]
+
+[SS]: /url
+.
+<p><a href="/url">ẞ</a></p>
+````````````````````````````````
+
+
+Consecutive internal spaces, tabs, and line endings are treated as one space for
+purposes of determining matching:
+
+```````````````````````````````` example
+[Foo
+ bar]: /url
+
+[Baz][Foo bar]
+.
+<p><a href="/url">Baz</a></p>
+````````````````````````````````
+
+
+No spaces, tabs, or line endings are allowed between the [link text] and the
+[link label]:
+
+```````````````````````````````` example
+[foo] [bar]
+
+[bar]: /url "title"
+.
+<p>[foo] <a href="/url" title="title">bar</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[foo]
+[bar]
+
+[bar]: /url "title"
+.
+<p>[foo]
+<a href="/url" title="title">bar</a></p>
+````````````````````````````````
+
+
+This is a departure from John Gruber's original Markdown syntax
+description, which explicitly allows whitespace between the link
+text and the link label. It brings reference links in line with
+[inline links], which (according to both original Markdown and
+this spec) cannot have whitespace after the link text. More
+importantly, it prevents inadvertent capture of consecutive
+[shortcut reference links]. If whitespace is allowed between the
+link text and the link label, then in the following we will have
+a single reference link, not two shortcut reference links, as
+intended:
+
+``` markdown
+[foo]
+[bar]
+
+[foo]: /url1
+[bar]: /url2
+```
+
+(Note that [shortcut reference links] were introduced by Gruber
+himself in a beta version of `Markdown.pl`, but never included
+in the official syntax description. Without shortcut reference
+links, it is harmless to allow space between the link text and
+link label; but once shortcut references are introduced, it is
+too dangerous to allow this, as it frequently leads to
+unintended results.)
+
+When there are multiple matching [link reference definitions],
+the first is used:
+
+```````````````````````````````` example
+[foo]: /url1
+
+[foo]: /url2
+
+[bar][foo]
+.
+<p><a href="/url1">bar</a></p>
+````````````````````````````````
+
+
+Note that matching is performed on normalized strings, not parsed
+inline content. So the following does not match, even though the
+labels define equivalent inline content:
+
+```````````````````````````````` example
+[bar][foo\!]
+
+[foo!]: /url
+.
+<p>[bar][foo!]</p>
+````````````````````````````````
+
+
+[Link labels] cannot contain brackets, unless they are
+backslash-escaped:
+
+```````````````````````````````` example
+[foo][ref[]
+
+[ref[]: /uri
+.
+<p>[foo][ref[]</p>
+<p>[ref[]: /uri</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[foo][ref[bar]]
+
+[ref[bar]]: /uri
+.
+<p>[foo][ref[bar]]</p>
+<p>[ref[bar]]: /uri</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[[[foo]]]
+
+[[[foo]]]: /url
+.
+<p>[[[foo]]]</p>
+<p>[[[foo]]]: /url</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[foo][ref\[]
+
+[ref\[]: /uri
+.
+<p><a href="/uri">foo</a></p>
+````````````````````````````````
+
+
+Note that in this example `]` is not backslash-escaped:
+
+```````````````````````````````` example
+[bar\\]: /uri
+
+[bar\\]
+.
+<p><a href="/uri">bar\</a></p>
+````````````````````````````````
+
+
+A [link label] must contain at least one character that is not a space, tab, or
+line ending:
+
+```````````````````````````````` example
+[]
+
+[]: /uri
+.
+<p>[]</p>
+<p>[]: /uri</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[
+ ]
+
+[
+ ]: /uri
+.
+<p>[
+]</p>
+<p>[
+]: /uri</p>
+````````````````````````````````
+
+
+A [collapsed reference link](@)
+consists of a [link label] that [matches] a
+[link reference definition] elsewhere in the
+document, followed by the string `[]`.
+The contents of the link label are parsed as inlines,
+which are used as the link's text. The link's URI and title are
+provided by the matching reference link definition. Thus,
+`[foo][]` is equivalent to `[foo][foo]`.
+
+```````````````````````````````` example
+[foo][]
+
+[foo]: /url "title"
+.
+<p><a href="/url" title="title">foo</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[*foo* bar][]
+
+[*foo* bar]: /url "title"
+.
+<p><a href="/url" title="title"><em>foo</em> bar</a></p>
+````````````````````````````````
+
+
+The link labels are case-insensitive:
+
+```````````````````````````````` example
+[Foo][]
+
+[foo]: /url "title"
+.
+<p><a href="/url" title="title">Foo</a></p>
+````````````````````````````````
+
+
+
+As with full reference links, spaces, tabs, or line endings are not
+allowed between the two sets of brackets:
+
+```````````````````````````````` example
+[foo]
+[]
+
+[foo]: /url "title"
+.
+<p><a href="/url" title="title">foo</a>
+[]</p>
+````````````````````````````````
+
+
+A [shortcut reference link](@)
+consists of a [link label] that [matches] a
+[link reference definition] elsewhere in the
+document and is not followed by `[]` or a link label.
+The contents of the link label are parsed as inlines,
+which are used as the link's text. The link's URI and title
+are provided by the matching link reference definition.
+Thus, `[foo]` is equivalent to `[foo][]`.
+
+```````````````````````````````` example
+[foo]
+
+[foo]: /url "title"
+.
+<p><a href="/url" title="title">foo</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[*foo* bar]
+
+[*foo* bar]: /url "title"
+.
+<p><a href="/url" title="title"><em>foo</em> bar</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[[*foo* bar]]
+
+[*foo* bar]: /url "title"
+.
+<p>[<a href="/url" title="title"><em>foo</em> bar</a>]</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[[bar [foo]
+
+[foo]: /url
+.
+<p>[[bar <a href="/url">foo</a></p>
+````````````````````````````````
+
+
+The link labels are case-insensitive:
+
+```````````````````````````````` example
+[Foo]
+
+[foo]: /url "title"
+.
+<p><a href="/url" title="title">Foo</a></p>
+````````````````````````````````
+
+
+A space after the link text should be preserved:
+
+```````````````````````````````` example
+[foo] bar
+
+[foo]: /url
+.
+<p><a href="/url">foo</a> bar</p>
+````````````````````````````````
+
+
+If you just want bracketed text, you can backslash-escape the
+opening bracket to avoid links:
+
+```````````````````````````````` example
+\[foo]
+
+[foo]: /url "title"
+.
+<p>[foo]</p>
+````````````````````````````````
+
+
+Note that this is a link, because a link label ends with the first
+following closing bracket:
+
+```````````````````````````````` example
+[foo*]: /url
+
+*[foo*]
+.
+<p>*<a href="/url">foo*</a></p>
+````````````````````````````````
+
+
+Full and collapsed references take precedence over shortcut
+references:
+
+```````````````````````````````` example
+[foo][bar]
+
+[foo]: /url1
+[bar]: /url2
+.
+<p><a href="/url2">foo</a></p>
+````````````````````````````````
+
+```````````````````````````````` example
+[foo][]
+
+[foo]: /url1
+.
+<p><a href="/url1">foo</a></p>
+````````````````````````````````
+
+Inline links also take precedence:
+
+```````````````````````````````` example
+[foo]()
+
+[foo]: /url1
+.
+<p><a href="">foo</a></p>
+````````````````````````````````
+
+```````````````````````````````` example
+[foo](not a link)
+
+[foo]: /url1
+.
+<p><a href="/url1">foo</a>(not a link)</p>
+````````````````````````````````
+
+In the following case `[bar][baz]` is parsed as a reference,
+`[foo]` as normal text:
+
+```````````````````````````````` example
+[foo][bar][baz]
+
+[baz]: /url
+.
+<p>[foo]<a href="/url">bar</a></p>
+````````````````````````````````
+
+
+Here, though, `[foo][bar]` is parsed as a reference, since
+`[bar]` is defined:
+
+```````````````````````````````` example
+[foo][bar][baz]
+
+[baz]: /url1
+[bar]: /url2
+.
+<p><a href="/url2">foo</a><a href="/url1">baz</a></p>
+````````````````````````````````
+
+
+Here `[foo]` is not parsed as a shortcut reference, because it
+is followed by a link label (even though `[bar]` is not defined):
+
+```````````````````````````````` example
+[foo][bar][baz]
+
+[baz]: /url1
+[foo]: /url2
+.
+<p>[foo]<a href="/url1">bar</a></p>
+````````````````````````````````
+
+
+
+## Images
+
+Syntax for images is like the syntax for links, with one
+difference. Instead of [link text], we have an
+[image description](@). The rules for this are the
+same as for [link text], except that (a) an
+image description starts with `![` rather than `[`, and
+(b) an image description may contain links.
+An image description has inline elements
+as its contents. When an image is rendered to HTML,
+this is standardly used as the image's `alt` attribute.
+
+```````````````````````````````` example
+![foo](/url "title")
+.
+<p><img src="/url" alt="foo" title="title" /></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+![foo *bar*]
+
+[foo *bar*]: train.jpg "train & tracks"
+.
+<p><img src="train.jpg" alt="foo bar" title="train &amp; tracks" /></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+![foo ![bar](/url)](/url2)
+.
+<p><img src="/url2" alt="foo bar" /></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+![foo [bar](/url)](/url2)
+.
+<p><img src="/url2" alt="foo bar" /></p>
+````````````````````````````````
+
+
+Though this spec is concerned with parsing, not rendering, it is
+recommended that in rendering to HTML, only the plain string content
+of the [image description] be used. Note that in
+the above example, the alt attribute's value is `foo bar`, not `foo
+[bar](/url)` or `foo <a href="/url">bar</a>`. Only the plain string
+content is rendered, without formatting.
+
+```````````````````````````````` example
+![foo *bar*][]
+
+[foo *bar*]: train.jpg "train & tracks"
+.
+<p><img src="train.jpg" alt="foo bar" title="train &amp; tracks" /></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+![foo *bar*][foobar]
+
+[FOOBAR]: train.jpg "train & tracks"
+.
+<p><img src="train.jpg" alt="foo bar" title="train &amp; tracks" /></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+![foo](train.jpg)
+.
+<p><img src="train.jpg" alt="foo" /></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+My ![foo bar](/path/to/train.jpg "title" )
+.
+<p>My <img src="/path/to/train.jpg" alt="foo bar" title="title" /></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+![foo](<url>)
+.
+<p><img src="url" alt="foo" /></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+![](/url)
+.
+<p><img src="/url" alt="" /></p>
+````````````````````````````````
+
+
+Reference-style:
+
+```````````````````````````````` example
+![foo][bar]
+
+[bar]: /url
+.
+<p><img src="/url" alt="foo" /></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+![foo][bar]
+
+[BAR]: /url
+.
+<p><img src="/url" alt="foo" /></p>
+````````````````````````````````
+
+
+Collapsed:
+
+```````````````````````````````` example
+![foo][]
+
+[foo]: /url "title"
+.
+<p><img src="/url" alt="foo" title="title" /></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+![*foo* bar][]
+
+[*foo* bar]: /url "title"
+.
+<p><img src="/url" alt="foo bar" title="title" /></p>
+````````````````````````````````
+
+
+The labels are case-insensitive:
+
+```````````````````````````````` example
+![Foo][]
+
+[foo]: /url "title"
+.
+<p><img src="/url" alt="Foo" title="title" /></p>
+````````````````````````````````
+
+
+As with reference links, spaces, tabs, and line endings, are not allowed
+between the two sets of brackets:
+
+```````````````````````````````` example
+![foo]
+[]
+
+[foo]: /url "title"
+.
+<p><img src="/url" alt="foo" title="title" />
+[]</p>
+````````````````````````````````
+
+
+Shortcut:
+
+```````````````````````````````` example
+![foo]
+
+[foo]: /url "title"
+.
+<p><img src="/url" alt="foo" title="title" /></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+![*foo* bar]
+
+[*foo* bar]: /url "title"
+.
+<p><img src="/url" alt="foo bar" title="title" /></p>
+````````````````````````````````
+
+
+Note that link labels cannot contain unescaped brackets:
+
+```````````````````````````````` example
+![[foo]]
+
+[[foo]]: /url "title"
+.
+<p>![[foo]]</p>
+<p>[[foo]]: /url &quot;title&quot;</p>
+````````````````````````````````
+
+
+The link labels are case-insensitive:
+
+```````````````````````````````` example
+![Foo]
+
+[foo]: /url "title"
+.
+<p><img src="/url" alt="Foo" title="title" /></p>
+````````````````````````````````
+
+
+If you just want a literal `!` followed by bracketed text, you can
+backslash-escape the opening `[`:
+
+```````````````````````````````` example
+!\[foo]
+
+[foo]: /url "title"
+.
+<p>![foo]</p>
+````````````````````````````````
+
+
+If you want a link after a literal `!`, backslash-escape the
+`!`:
+
+```````````````````````````````` example
+\![foo]
+
+[foo]: /url "title"
+.
+<p>!<a href="/url" title="title">foo</a></p>
+````````````````````````````````
+
+
+## Autolinks
+
+[Autolink](@)s are absolute URIs and email addresses inside
+`<` and `>`. They are parsed as links, with the URL or email address
+as the link label.
+
+A [URI autolink](@) consists of `<`, followed by an
+[absolute URI] followed by `>`. It is parsed as
+a link to the URI, with the URI as the link's label.
+
+An [absolute URI](@),
+for these purposes, consists of a [scheme] followed by a colon (`:`)
+followed by zero or more characters other than [ASCII control
+characters][ASCII control character], [space], `<`, and `>`.
+If the URI includes these characters, they must be percent-encoded
+(e.g. `%20` for a space).
+
+For purposes of this spec, a [scheme](@) is any sequence
+of 2--32 characters beginning with an ASCII letter and followed
+by any combination of ASCII letters, digits, or the symbols plus
+("+"), period ("."), or hyphen ("-").
+
+Here are some valid autolinks:
+
+```````````````````````````````` example
+<http://foo.bar.baz>
+.
+<p><a href="http://foo.bar.baz">http://foo.bar.baz</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+<https://foo.bar.baz/test?q=hello&id=22&boolean>
+.
+<p><a href="https://foo.bar.baz/test?q=hello&amp;id=22&amp;boolean">https://foo.bar.baz/test?q=hello&amp;id=22&amp;boolean</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+<irc://foo.bar:2233/baz>
+.
+<p><a href="irc://foo.bar:2233/baz">irc://foo.bar:2233/baz</a></p>
+````````````````````````````````
+
+
+Uppercase is also fine:
+
+```````````````````````````````` example
+<MAILTO:FOO@BAR.BAZ>
+.
+<p><a href="MAILTO:FOO@BAR.BAZ">MAILTO:FOO@BAR.BAZ</a></p>
+````````````````````````````````
+
+
+Note that many strings that count as [absolute URIs] for
+purposes of this spec are not valid URIs, because their
+schemes are not registered or because of other problems
+with their syntax:
+
+```````````````````````````````` example
+<a+b+c:d>
+.
+<p><a href="a+b+c:d">a+b+c:d</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+<made-up-scheme://foo,bar>
+.
+<p><a href="made-up-scheme://foo,bar">made-up-scheme://foo,bar</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+<https://../>
+.
+<p><a href="https://../">https://../</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+<localhost:5001/foo>
+.
+<p><a href="localhost:5001/foo">localhost:5001/foo</a></p>
+````````````````````````````````
+
+
+Spaces are not allowed in autolinks:
+
+```````````````````````````````` example
+<https://foo.bar/baz bim>
+.
+<p>&lt;https://foo.bar/baz bim&gt;</p>
+````````````````````````````````
+
+
+Backslash-escapes do not work inside autolinks:
+
+```````````````````````````````` example
+<https://example.com/\[\>
+.
+<p><a href="https://example.com/%5C%5B%5C">https://example.com/\[\</a></p>
+````````````````````````````````
+
+
+An [email autolink](@)
+consists of `<`, followed by an [email address],
+followed by `>`. The link's label is the email address,
+and the URL is `mailto:` followed by the email address.
+
+An [email address](@),
+for these purposes, is anything that matches
+the [non-normative regex from the HTML5
+spec](https://html.spec.whatwg.org/multipage/forms.html#e-mail-state-(type=email)):
+
+ /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?
+ (?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/
+
+Examples of email autolinks:
+
+```````````````````````````````` example
+<foo@bar.example.com>
+.
+<p><a href="mailto:foo@bar.example.com">foo@bar.example.com</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+<foo+special@Bar.baz-bar0.com>
+.
+<p><a href="mailto:foo+special@Bar.baz-bar0.com">foo+special@Bar.baz-bar0.com</a></p>
+````````````````````````````````
+
+
+Backslash-escapes do not work inside email autolinks:
+
+```````````````````````````````` example
+<foo\+@bar.example.com>
+.
+<p>&lt;foo+@bar.example.com&gt;</p>
+````````````````````````````````
+
+
+These are not autolinks:
+
+```````````````````````````````` example
+<>
+.
+<p>&lt;&gt;</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+< https://foo.bar >
+.
+<p>&lt; https://foo.bar &gt;</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+<m:abc>
+.
+<p>&lt;m:abc&gt;</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+<foo.bar.baz>
+.
+<p>&lt;foo.bar.baz&gt;</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+https://example.com
+.
+<p>https://example.com</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+foo@bar.example.com
+.
+<p>foo@bar.example.com</p>
+````````````````````````````````
+
+
+## Raw HTML
+
+Text between `<` and `>` that looks like an HTML tag is parsed as a
+raw HTML tag and will be rendered in HTML without escaping.
+Tag and attribute names are not limited to current HTML tags,
+so custom tags (and even, say, DocBook tags) may be used.
+
+Here is the grammar for tags:
+
+A [tag name](@) consists of an ASCII letter
+followed by zero or more ASCII letters, digits, or
+hyphens (`-`).
+
+An [attribute](@) consists of spaces, tabs, and up to one line ending,
+an [attribute name], and an optional
+[attribute value specification].
+
+An [attribute name](@)
+consists of an ASCII letter, `_`, or `:`, followed by zero or more ASCII
+letters, digits, `_`, `.`, `:`, or `-`. (Note: This is the XML
+specification restricted to ASCII. HTML5 is laxer.)
+
+An [attribute value specification](@)
+consists of optional spaces, tabs, and up to one line ending,
+a `=` character, optional spaces, tabs, and up to one line ending,
+and an [attribute value].
+
+An [attribute value](@)
+consists of an [unquoted attribute value],
+a [single-quoted attribute value], or a [double-quoted attribute value].
+
+An [unquoted attribute value](@)
+is a nonempty string of characters not
+including spaces, tabs, line endings, `"`, `'`, `=`, `<`, `>`, or `` ` ``.
+
+A [single-quoted attribute value](@)
+consists of `'`, zero or more
+characters not including `'`, and a final `'`.
+
+A [double-quoted attribute value](@)
+consists of `"`, zero or more
+characters not including `"`, and a final `"`.
+
+An [open tag](@) consists of a `<` character, a [tag name],
+zero or more [attributes], optional spaces, tabs, and up to one line ending,
+an optional `/` character, and a `>` character.
+
+A [closing tag](@) consists of the string `</`, a
+[tag name], optional spaces, tabs, and up to one line ending, and the character
+`>`.
+
+An [HTML comment](@) consists of `<!-->`, `<!--->`, or `<!--`, a string of
+characters not including the string `-->`, and `-->` (see the
+[HTML spec](https://html.spec.whatwg.org/multipage/parsing.html#markup-declaration-open-state)).
+
+A [processing instruction](@)
+consists of the string `<?`, a string
+of characters not including the string `?>`, and the string
+`?>`.
+
+A [declaration](@) consists of the string `<!`, an ASCII letter, zero or more
+characters not including the character `>`, and the character `>`.
+
+A [CDATA section](@) consists of
+the string `<![CDATA[`, a string of characters not including the string
+`]]>`, and the string `]]>`.
+
+An [HTML tag](@) consists of an [open tag], a [closing tag],
+an [HTML comment], a [processing instruction], a [declaration],
+or a [CDATA section].
+
+Here are some simple open tags:
+
+```````````````````````````````` example
+<a><bab><c2c>
+.
+<p><a><bab><c2c></p>
+````````````````````````````````
+
+
+Empty elements:
+
+```````````````````````````````` example
+<a/><b2/>
+.
+<p><a/><b2/></p>
+````````````````````````````````
+
+
+Whitespace is allowed:
+
+```````````````````````````````` example
+<a /><b2
+data="foo" >
+.
+<p><a /><b2
+data="foo" ></p>
+````````````````````````````````
+
+
+With attributes:
+
+```````````````````````````````` example
+<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>
+````````````````````````````````
+
+
+Custom tag names can be used:
+
+```````````````````````````````` example
+Foo <responsive-image src="foo.jpg" />
+.
+<p>Foo <responsive-image src="foo.jpg" /></p>
+````````````````````````````````
+
+
+Illegal tag names, not parsed as HTML:
+
+```````````````````````````````` example
+<33> <__>
+.
+<p>&lt;33&gt; &lt;__&gt;</p>
+````````````````````````````````
+
+
+Illegal attribute names:
+
+```````````````````````````````` example
+<a h*#ref="hi">
+.
+<p>&lt;a h*#ref=&quot;hi&quot;&gt;</p>
+````````````````````````````````
+
+
+Illegal attribute values:
+
+```````````````````````````````` example
+<a href="hi'> <a href=hi'>
+.
+<p>&lt;a href=&quot;hi'&gt; &lt;a href=hi'&gt;</p>
+````````````````````````````````
+
+
+Illegal whitespace:
+
+```````````````````````````````` example
+< a><
+foo><bar/ >
+<foo bar=baz
+bim!bop />
+.
+<p>&lt; a&gt;&lt;
+foo&gt;&lt;bar/ &gt;
+&lt;foo bar=baz
+bim!bop /&gt;</p>
+````````````````````````````````
+
+
+Missing whitespace:
+
+```````````````````````````````` example
+<a href='bar'title=title>
+.
+<p>&lt;a href='bar'title=title&gt;</p>
+````````````````````````````````
+
+
+Closing tags:
+
+```````````````````````````````` example
+</a></foo >
+.
+<p></a></foo ></p>
+````````````````````````````````
+
+
+Illegal attributes in closing tag:
+
+```````````````````````````````` example
+</a href="foo">
+.
+<p>&lt;/a href=&quot;foo&quot;&gt;</p>
+````````````````````````````````
+
+
+Comments:
+
+```````````````````````````````` example
+foo <!-- this is a --
+comment - with hyphens -->
+.
+<p>foo <!-- this is a --
+comment - with hyphens --></p>
+````````````````````````````````
+
+```````````````````````````````` example
+foo <!--> foo -->
+
+foo <!---> foo -->
+.
+<p>foo <!--> foo --&gt;</p>
+<p>foo <!---> foo --&gt;</p>
+````````````````````````````````
+
+
+Processing instructions:
+
+```````````````````````````````` example
+foo <?php echo $a; ?>
+.
+<p>foo <?php echo $a; ?></p>
+````````````````````````````````
+
+
+Declarations:
+
+```````````````````````````````` example
+foo <!ELEMENT br EMPTY>
+.
+<p>foo <!ELEMENT br EMPTY></p>
+````````````````````````````````
+
+
+CDATA sections:
+
+```````````````````````````````` example
+foo <![CDATA[>&<]]>
+.
+<p>foo <![CDATA[>&<]]></p>
+````````````````````````````````
+
+
+Entity and numeric character references are preserved in HTML
+attributes:
+
+```````````````````````````````` example
+foo <a href="&ouml;">
+.
+<p>foo <a href="&ouml;"></p>
+````````````````````````````````
+
+
+Backslash escapes do not work in HTML attributes:
+
+```````````````````````````````` example
+foo <a href="\*">
+.
+<p>foo <a href="\*"></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+<a href="\"">
+.
+<p>&lt;a href=&quot;&quot;&quot;&gt;</p>
+````````````````````````````````
+
+
+## Hard line breaks
+
+A line ending (not in a code span or HTML tag) that is preceded
+by two or more spaces and does not occur at the end of a block
+is parsed as a [hard line break](@) (rendered
+in HTML as a `<br />` tag):
+
+```````````````````````````````` example
+foo
+baz
+.
+<p>foo<br />
+baz</p>
+````````````````````````````````
+
+
+For a more visible alternative, a backslash before the
+[line ending] may be used instead of two or more spaces:
+
+```````````````````````````````` example
+foo\
+baz
+.
+<p>foo<br />
+baz</p>
+````````````````````````````````
+
+
+More than two spaces can be used:
+
+```````````````````````````````` example
+foo
+baz
+.
+<p>foo<br />
+baz</p>
+````````````````````````````````
+
+
+Leading spaces at the beginning of the next line are ignored:
+
+```````````````````````````````` example
+foo
+ bar
+.
+<p>foo<br />
+bar</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+foo\
+ bar
+.
+<p>foo<br />
+bar</p>
+````````````````````````````````
+
+
+Hard line breaks can occur inside emphasis, links, and other constructs
+that allow inline content:
+
+```````````````````````````````` example
+*foo
+bar*
+.
+<p><em>foo<br />
+bar</em></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+*foo\
+bar*
+.
+<p><em>foo<br />
+bar</em></p>
+````````````````````````````````
+
+
+Hard line breaks do not occur inside code spans
+
+```````````````````````````````` example
+`code
+span`
+.
+<p><code>code span</code></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+`code\
+span`
+.
+<p><code>code\ span</code></p>
+````````````````````````````````
+
+
+or HTML tags:
+
+```````````````````````````````` example
+<a href="foo
+bar">
+.
+<p><a href="foo
+bar"></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+<a href="foo\
+bar">
+.
+<p><a href="foo\
+bar"></p>
+````````````````````````````````
+
+
+Hard line breaks are for separating inline content within a block.
+Neither syntax for hard line breaks works at the end of a paragraph or
+other block element:
+
+```````````````````````````````` example
+foo\
+.
+<p>foo\</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+foo
+.
+<p>foo</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+### foo\
+.
+<h3>foo\</h3>
+````````````````````````````````
+
+
+```````````````````````````````` example
+### foo
+.
+<h3>foo</h3>
+````````````````````````````````
+
+
+## Soft line breaks
+
+A regular line ending (not in a code span or HTML tag) that is not
+preceded by two or more spaces or a backslash is parsed as a
+[softbreak](@). (A soft line break may be rendered in HTML either as a
+[line ending] or as a space. The result will be the same in
+browsers. In the examples here, a [line ending] will be used.)
+
+```````````````````````````````` example
+foo
+baz
+.
+<p>foo
+baz</p>
+````````````````````````````````
+
+
+Spaces at the end of the line and beginning of the next line are
+removed:
+
+```````````````````````````````` example
+foo
+ baz
+.
+<p>foo
+baz</p>
+````````````````````````````````
+
+
+A conforming parser may render a soft line break in HTML either as a
+line ending or as a space.
+
+A renderer may also provide an option to render soft line breaks
+as hard line breaks.
+
+## Textual content
+
+Any characters not given an interpretation by the above rules will
+be parsed as plain textual content.
+
+```````````````````````````````` example
+hello $.;'there
+.
+<p>hello $.;'there</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+Foo χρῆν
+.
+<p>Foo χρῆν</p>
+````````````````````````````````
+
+
+Internal spaces are preserved verbatim:
+
+```````````````````````````````` example
+Multiple spaces
+.
+<p>Multiple spaces</p>
+````````````````````````````````
+
+
+<!-- END TESTS -->
+
+# Appendix: A parsing strategy
+
+In this appendix we describe some features of the parsing strategy
+used in the CommonMark reference implementations.
+
+## Overview
+
+Parsing has two phases:
+
+1. In the first phase, lines of input are consumed and the block
+structure of the document---its division into paragraphs, block quotes,
+list items, and so on---is constructed. Text is assigned to these
+blocks but not parsed. Link reference definitions are parsed and a
+map of links is constructed.
+
+2. In the second phase, the raw text contents of paragraphs and headings
+are parsed into sequences of Markdown inline elements (strings,
+code spans, links, emphasis, and so on), using the map of link
+references constructed in phase 1.
+
+At each point in processing, the document is represented as a tree of
+**blocks**. The root of the tree is a `document` block. The `document`
+may have any number of other blocks as **children**. These children
+may, in turn, have other blocks as children. The last child of a block
+is normally considered **open**, meaning that subsequent lines of input
+can alter its contents. (Blocks that are not open are **closed**.)
+Here, for example, is a possible document tree, with the open blocks
+marked by arrows:
+
+``` tree
+-> document
+ -> block_quote
+ paragraph
+ "Lorem ipsum dolor\nsit amet."
+ -> list (type=bullet tight=true bullet_char=-)
+ list_item
+ paragraph
+ "Qui *quodsi iracundia*"
+ -> list_item
+ -> paragraph
+ "aliquando id"
+```
+
+## Phase 1: block structure
+
+Each line that is processed has an effect on this tree. The line is
+analyzed and, depending on its contents, the document may be altered
+in one or more of the following ways:
+
+1. One or more open blocks may be closed.
+2. One or more new blocks may be created as children of the
+ last open block.
+3. Text may be added to the last (deepest) open block remaining
+ on the tree.
+
+Once a line has been incorporated into the tree in this way,
+it can be discarded, so input can be read in a stream.
+
+For each line, we follow this procedure:
+
+1. First we iterate through the open blocks, starting with the
+root document, and descending through last children down to the last
+open block. Each block imposes a condition that the line must satisfy
+if the block is to remain open. For example, a block quote requires a
+`>` character. A paragraph requires a non-blank line.
+In this phase we may match all or just some of the open
+blocks. But we cannot close unmatched blocks yet, because we may have a
+[lazy continuation line].
+
+2. Next, after consuming the continuation markers for existing
+blocks, we look for new block starts (e.g. `>` for a block quote).
+If we encounter a new block start, we close any blocks unmatched
+in step 1 before creating the new block as a child of the last
+matched container block.
+
+3. Finally, we look at the remainder of the line (after block
+markers like `>`, list markers, and indentation have been consumed).
+This is text that can be incorporated into the last open
+block (a paragraph, code block, heading, or raw HTML).
+
+Setext headings are formed when we see a line of a paragraph
+that is a [setext heading underline].
+
+Reference link definitions are detected when a paragraph is closed;
+the accumulated text lines are parsed to see if they begin with
+one or more reference link definitions. Any remainder becomes a
+normal paragraph.
+
+We can see how this works by considering how the tree above is
+generated by four lines of Markdown:
+
+``` markdown
+> Lorem ipsum dolor
+sit amet.
+> - Qui *quodsi iracundia*
+> - aliquando id
+```
+
+At the outset, our document model is just
+
+``` tree
+-> document
+```
+
+The first line of our text,
+
+``` markdown
+> Lorem ipsum dolor
+```
+
+causes a `block_quote` block to be created as a child of our
+open `document` block, and a `paragraph` block as a child of
+the `block_quote`. Then the text is added to the last open
+block, the `paragraph`:
+
+``` tree
+-> document
+ -> block_quote
+ -> paragraph
+ "Lorem ipsum dolor"
+```
+
+The next line,
+
+``` markdown
+sit amet.
+```
+
+is a "lazy continuation" of the open `paragraph`, so it gets added
+to the paragraph's text:
+
+``` tree
+-> document
+ -> block_quote
+ -> paragraph
+ "Lorem ipsum dolor\nsit amet."
+```
+
+The third line,
+
+``` markdown
+> - Qui *quodsi iracundia*
+```
+
+causes the `paragraph` block to be closed, and a new `list` block
+opened as a child of the `block_quote`. A `list_item` is also
+added as a child of the `list`, and a `paragraph` as a child of
+the `list_item`. The text is then added to the new `paragraph`:
+
+``` tree
+-> document
+ -> block_quote
+ paragraph
+ "Lorem ipsum dolor\nsit amet."
+ -> list (type=bullet tight=true bullet_char=-)
+ -> list_item
+ -> paragraph
+ "Qui *quodsi iracundia*"
+```
+
+The fourth line,
+
+``` markdown
+> - aliquando id
+```
+
+causes the `list_item` (and its child the `paragraph`) to be closed,
+and a new `list_item` opened up as child of the `list`. A `paragraph`
+is added as a child of the new `list_item`, to contain the text.
+We thus obtain the final tree:
+
+``` tree
+-> document
+ -> block_quote
+ paragraph
+ "Lorem ipsum dolor\nsit amet."
+ -> list (type=bullet tight=true bullet_char=-)
+ list_item
+ paragraph
+ "Qui *quodsi iracundia*"
+ -> list_item
+ -> paragraph
+ "aliquando id"
+```
+
+## Phase 2: inline structure
+
+Once all of the input has been parsed, all open blocks are closed.
+
+We then "walk the tree," visiting every node, and parse raw
+string contents of paragraphs and headings as inlines. At this
+point we have seen all the link reference definitions, so we can
+resolve reference links as we go.
+
+``` tree
+document
+ block_quote
+ paragraph
+ str "Lorem ipsum dolor"
+ softbreak
+ str "sit amet."
+ list (type=bullet tight=true bullet_char=-)
+ list_item
+ paragraph
+ str "Qui "
+ emph
+ str "quodsi iracundia"
+ list_item
+ paragraph
+ str "aliquando id"
+```
+
+Notice how the [line ending] in the first paragraph has
+been parsed as a `softbreak`, and the asterisks in the first list item
+have become an `emph`.
+
+### An algorithm for parsing nested emphasis and links
+
+By far the trickiest part of inline parsing is handling emphasis,
+strong emphasis, links, and images. This is done using the following
+algorithm.
+
+When we're parsing inlines and we hit either
+
+- a run of `*` or `_` characters, or
+- a `[` or `![`
+
+we insert a text node with these symbols as its literal content, and we
+add a pointer to this text node to the [delimiter stack](@).
+
+The [delimiter stack] is a doubly linked list. Each
+element contains a pointer to a text node, plus information about
+
+- the type of delimiter (`[`, `![`, `*`, `_`)
+- the number of delimiters,
+- whether the delimiter is "active" (all are active to start), and
+- whether the delimiter is a potential opener, a potential closer,
+ or both (which depends on what sort of characters precede
+ and follow the delimiters).
+
+When we hit a `]` character, we call the *look for link or image*
+procedure (see below).
+
+When we hit the end of the input, we call the *process emphasis*
+procedure (see below), with `stack_bottom` = NULL.
+
+#### *look for link or image*
+
+Starting at the top of the delimiter stack, we look backwards
+through the stack for an opening `[` or `![` delimiter.
+
+- If we don't find one, we return a literal text node `]`.
+
+- If we do find one, but it's not *active*, we remove the inactive
+ delimiter from the stack, and return a literal text node `]`.
+
+- If we find one and it's active, then we parse ahead to see if
+ we have an inline link/image, reference link/image, collapsed reference
+ link/image, or shortcut reference link/image.
+
+ + If we don't, then we remove the opening delimiter from the
+ delimiter stack and return a literal text node `]`.
+
+ + If we do, then
+
+ * We return a link or image node whose children are the inlines
+ after the text node pointed to by the opening delimiter.
+
+ * We run *process emphasis* on these inlines, with the `[` opener
+ as `stack_bottom`.
+
+ * We remove the opening delimiter.
+
+ * If we have a link (and not an image), we also set all
+ `[` delimiters before the opening delimiter to *inactive*. (This
+ will prevent us from getting links within links.)
+
+#### *process emphasis*
+
+Parameter `stack_bottom` sets a lower bound to how far we
+descend in the [delimiter stack]. If it is NULL, we can
+go all the way to the bottom. Otherwise, we stop before
+visiting `stack_bottom`.
+
+Let `current_position` point to the element on the [delimiter stack]
+just above `stack_bottom` (or the first element if `stack_bottom`
+is NULL).
+
+We keep track of the `openers_bottom` for each delimiter
+type (`*`, `_`), indexed to the length of the closing delimiter run
+(modulo 3) and to whether the closing delimiter can also be an
+opener. Initialize this to `stack_bottom`.
+
+Then we repeat the following until we run out of potential
+closers:
+
+- Move `current_position` forward in the delimiter stack (if needed)
+ until we find the first potential closer with delimiter `*` or `_`.
+ (This will be the potential closer closest
+ to the beginning of the input -- the first one in parse order.)
+
+- Now, look back in the stack (staying above `stack_bottom` and
+ the `openers_bottom` for this delimiter type) for the
+ first matching potential opener ("matching" means same delimiter).
+
+- If one is found:
+
+ + Figure out whether we have emphasis or strong emphasis:
+ if both closer and opener spans have length >= 2, we have
+ strong, otherwise regular.
+
+ + Insert an emph or strong emph node accordingly, after
+ the text node corresponding to the opener.
+
+ + Remove any delimiters between the opener and closer from
+ the delimiter stack.
+
+ + Remove 1 (for regular emph) or 2 (for strong emph) delimiters
+ from the opening and closing text nodes. If they become empty
+ as a result, remove them and remove the corresponding element
+ of the delimiter stack. If the closing node is removed, reset
+ `current_position` to the next element in the stack.
+
+- If none is found:
+
+ + Set `openers_bottom` to the element before `current_position`.
+ (We know that there are no openers for this kind of closer up to and
+ including this point, so this puts a lower bound on future searches.)
+
+ + If the closer at `current_position` is not a potential opener,
+ remove it from the delimiter stack (since we know it can't
+ be a closer either).
+
+ + Advance `current_position` to the next element in the stack.
+
+After we're done, we remove all delimiters above `stack_bottom` from the
+delimiter stack.
diff --git a/cmark/test/spec_tests.py b/cmark/test/spec_tests.py
new file mode 100755
index 0000000000..ab0503df36
--- /dev/null
+++ b/cmark/test/spec_tests.py
@@ -0,0 +1,158 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+import sys
+from difflib import unified_diff
+import argparse
+import re
+import json
+import os
+from cmark import CMark
+from normalize import normalize_html
+
+parser = argparse.ArgumentParser(description='Run cmark tests.')
+parser.add_argument('-p', '--program', dest='program', nargs='?', default=None,
+ help='program to test')
+parser.add_argument('-s', '--spec', dest='spec', nargs='?', default='spec.txt',
+ help='path to spec')
+parser.add_argument('-P', '--pattern', dest='pattern', nargs='?',
+ default=None, help='limit to sections matching regex pattern')
+parser.add_argument('--library-dir', dest='library_dir', nargs='?',
+ default=None, help='directory containing dynamic library')
+parser.add_argument('--no-normalize', dest='normalize',
+ action='store_const', const=False, default=True,
+ help='do not normalize HTML')
+parser.add_argument('-d', '--dump-tests', dest='dump_tests',
+ action='store_const', const=True, default=False,
+ help='dump tests in JSON format')
+parser.add_argument('--debug-normalization', dest='debug_normalization',
+ action='store_const', const=True,
+ default=False, help='filter stdin through normalizer for testing')
+parser.add_argument('-n', '--number', type=int, default=None,
+ help='only consider the test with the given number')
+parser.add_argument('--fuzz-corpus',
+ help='convert test cases to fuzz corpus')
+args = parser.parse_args(sys.argv[1:])
+
+def out(str):
+ sys.stdout.buffer.write(str.encode('utf-8'))
+
+def print_test_header(headertext, example_number, start_line, end_line):
+ out("Example %d (lines %d-%d) %s\n" % (example_number,start_line,end_line,headertext))
+
+def do_test(converter, test, normalize, result_counts):
+ [retcode, actual_html, err] = converter(test['markdown'])
+ if retcode == 0:
+ expected_html = test['html']
+ unicode_error = None
+ if normalize:
+ try:
+ passed = normalize_html(actual_html) == normalize_html(expected_html)
+ except UnicodeDecodeError as e:
+ unicode_error = e
+ passed = False
+ else:
+ passed = actual_html == expected_html
+ if passed:
+ result_counts['pass'] += 1
+ else:
+ print_test_header(test['section'], test['example'], test['start_line'], test['end_line'])
+ out(test['markdown'] + '\n')
+ if unicode_error:
+ out("Unicode error: " + str(unicode_error) + '\n')
+ out("Expected: " + repr(expected_html) + '\n')
+ out("Got: " + repr(actual_html) + '\n')
+ else:
+ expected_html_lines = expected_html.splitlines(True)
+ actual_html_lines = actual_html.splitlines(True)
+ for diffline in unified_diff(expected_html_lines, actual_html_lines,
+ "expected HTML", "actual HTML"):
+ out(diffline)
+ out('\n')
+ result_counts['fail'] += 1
+ else:
+ print_test_header(test['section'], test['example'], test['start_line'], test['end_line'])
+ out("program returned error code %d\n" % retcode)
+ sys.stdout.buffer.write(err)
+ result_counts['error'] += 1
+
+def get_tests(specfile):
+ line_number = 0
+ start_line = 0
+ end_line = 0
+ example_number = 0
+ markdown_lines = []
+ html_lines = []
+ state = 0 # 0 regular text, 1 markdown example, 2 html output
+ headertext = ''
+ tests = []
+
+ header_re = re.compile('#+ ')
+
+ with open(specfile, 'r', encoding='utf-8', newline='\n') as specf:
+ for line in specf:
+ line_number = line_number + 1
+ l = line.strip()
+ if l == "`" * 32 + " example":
+ state = 1
+ elif l == "`" * 32:
+ state = 0
+ example_number = example_number + 1
+ end_line = line_number
+ tests.append({
+ "markdown":''.join(markdown_lines).replace('→',"\t"),
+ "html":''.join(html_lines).replace('→',"\t"),
+ "example": example_number,
+ "start_line": start_line,
+ "end_line": end_line,
+ "section": headertext})
+ start_line = 0
+ markdown_lines = []
+ html_lines = []
+ elif l == ".":
+ state = 2
+ elif state == 1:
+ if start_line == 0:
+ start_line = line_number - 1
+ markdown_lines.append(line)
+ elif state == 2:
+ html_lines.append(line)
+ elif state == 0 and re.match(header_re, line):
+ headertext = header_re.sub('', line).strip()
+ return tests
+
+if __name__ == "__main__":
+ if args.debug_normalization:
+ out(normalize_html(sys.stdin.read()))
+ exit(0)
+
+ all_tests = get_tests(args.spec)
+
+ if args.fuzz_corpus:
+ i = 1
+ base = os.path.basename(args.spec)
+ (name, ext) = os.path.splitext(base)
+ for test in all_tests:
+ filename = os.path.join(args.fuzz_corpus, '%s.%d' % (name, i))
+ with open(filename, 'wb') as f:
+ f.write(b'\0' * 8) # options header
+ f.write(test['markdown'].encode())
+ i += 1
+ exit(0)
+
+ if args.pattern:
+ pattern_re = re.compile(args.pattern, re.IGNORECASE)
+ else:
+ pattern_re = re.compile('.')
+ tests = [ test for test in all_tests if re.search(pattern_re, test['section']) and (not args.number or test['example'] == args.number) ]
+ if args.dump_tests:
+ out(json.dumps(tests, ensure_ascii=False, indent=2))
+ exit(0)
+ else:
+ skipped = len(all_tests) - len(tests)
+ converter = CMark(prog=args.program, library_dir=args.library_dir).to_html
+ result_counts = {'pass': 0, 'fail': 0, 'error': 0, 'skip': skipped}
+ for test in tests:
+ do_test(converter, test, args.normalize, result_counts)
+ out("{pass} passed, {fail} failed, {error} errored, {skip} skipped\n".format(**result_counts))
+ exit(result_counts['fail'] + result_counts['error'])
diff --git a/cmark/toolchain-mingw32.cmake b/cmark/toolchain-mingw32.cmake
new file mode 100644
index 0000000000..ad84aad675
--- /dev/null
+++ b/cmark/toolchain-mingw32.cmake
@@ -0,0 +1,17 @@
+# the name of the target operating system
+SET(CMAKE_SYSTEM_NAME Windows)
+
+# which compilers to use for C and C++
+SET(CMAKE_C_COMPILER i686-w64-mingw32-gcc)
+SET(CMAKE_CXX_COMPILER i686-w64-mingw32-g++)
+SET(CMAKE_RC_COMPILER i686-w64-mingw32-windres)
+
+# here is the target environment located
+SET(CMAKE_FIND_ROOT_PATH /usr/i686-w64-mingw32/ "${CMAKE_SOURCE_DIR}/windows")
+
+# adjust the default behaviour of the FIND_XXX() commands:
+# search headers and libraries in the target environment, search
+# programs in the host environment
+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
diff --git a/cmark/tools/appveyor-build.bat b/cmark/tools/appveyor-build.bat
new file mode 100644
index 0000000000..73d555b52b
--- /dev/null
+++ b/cmark/tools/appveyor-build.bat
@@ -0,0 +1,13 @@
+@echo off
+
+if "%MSVC_VERSION%" == "10" goto msvc10
+
+call "C:\Program Files (x86)\Microsoft Visual Studio %MSVC_VERSION%.0\VC\vcvarsall.bat" amd64
+goto build
+
+:msvc10
+call "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.cmd" /x64
+
+:build
+nmake
+
diff --git a/cmark/tools/make_case_fold_inc.py b/cmark/tools/make_case_fold_inc.py
new file mode 100644
index 0000000000..3347d291b9
--- /dev/null
+++ b/cmark/tools/make_case_fold_inc.py
@@ -0,0 +1,96 @@
+# Creates a C lookup table for Unicode case folding (https://unicode.org/Public/UCD/latest/ucd/CaseFolding.txt).
+# Usage: python3 tools/make_case_fold_inc.py < data/CaseFolding.txt > src/case_fold.inc
+
+import sys, re
+
+prog = re.compile('([0-9A-F]+); [CF];((?: [0-9A-F]+)+);')
+main_table = []
+repl_table = []
+repl_idx = 0
+test = ''
+test_result = ''
+
+for line in sys.stdin:
+ m = prog.match(line)
+ if m is None:
+ continue
+
+ cp = int(m[1], 16);
+ if cp < 0x80:
+ continue
+
+ repl = b''
+ for x in m[2].split():
+ repl += chr(int(x, 16)).encode('UTF-8')
+
+ # Generate test case
+ if len(main_table) % 20 == 0:
+ test += chr(cp)
+ test_result += repl.decode('UTF-8')
+
+ # 17 bits for code point
+ if cp >= (1 << 17):
+ raise Exception("code point too large")
+
+ # 12 bits for upper bits of replacement index
+ # The lowest bit is always zero.
+ if repl_idx // 2 >= (1 << 12):
+ raise Exception("too many replacements")
+
+ # 3 bits for size of replacement
+ repl_size = len(repl)
+ if repl_size >= (1 << 3):
+ raise Exception("too many replacement chars")
+
+ main_table += [ cp | repl_idx // 2 << 17 | repl_size << 29 ]
+ repl_table += repl
+ repl_idx += repl_size
+
+ # Make sure that repl_idx is even
+ if repl_idx % 2 != 0:
+ repl_table += [0]
+ repl_idx += 1
+
+# Print test case
+if False:
+ print("test:", test)
+ print("test_result:", test_result)
+ sys.exit(0)
+
+print("""// Generated by tools/make_case_fold_inc.py
+
+#define CF_MAX (1 << 17)
+#define CF_TABLE_SIZE %d
+#define CF_CODE_POINT(x) ((x) & 0x1FFFF)
+#define CF_REPL_IDX(x) ((((x) >> 17) & 0xFFF) * 2)
+#define CF_REPL_SIZE(x) ((x) >> 29)
+
+static const uint32_t cf_table[%d] = {""" % (len(main_table), len(main_table)))
+
+i = 0
+size = len(main_table)
+for value in main_table:
+ if i % 6 == 0:
+ print(" ", end="")
+ print("0x%X" % value, end="")
+ i += 1
+ if i == size: print()
+ elif i % 6 == 0: print(",")
+ else: print(", ", end="")
+
+print("""};
+
+static const unsigned char cf_repl[%d] = {""" % len(repl_table))
+
+i = 0
+size = len(repl_table)
+for value in repl_table:
+ if i % 12 == 0:
+ print(" ", end="")
+ print("0x%02X" % value, end="")
+ i += 1
+ if i == size: print()
+ elif i % 12 == 0: print(",")
+ else: print(", ", end="")
+
+print("};")
diff --git a/cmark/tools/make_entities_inc.py b/cmark/tools/make_entities_inc.py
new file mode 100644
index 0000000000..25c65d99d6
--- /dev/null
+++ b/cmark/tools/make_entities_inc.py
@@ -0,0 +1,72 @@
+# Creates C data structures for binary lookup table of entities,
+# using python's html5 entity data.
+# Usage: python3 tools/make_entities_inc.py > src/entities.inc
+
+import html
+
+entities5 = html.entities.html5
+
+# Remove keys without semicolons. HTML5 allows some named character
+# references without a trailing semicolon.
+entities = sorted([(k[:-1], entities5[k]) for k in entities5.keys() if k[-1] == ';'])
+
+main_table = []
+text_table = b''
+text_idx = 0
+
+for (ent, repl) in entities:
+ ent_bytes = ent.encode('UTF-8')
+ ent_size = len(ent_bytes)
+ repl_bytes = repl.encode('UTF-8')
+ repl_size = len(repl_bytes)
+
+ if text_idx >= (1 << 15):
+ raise Exception("text index too large")
+ if ent_size >= (1 << 5):
+ raise Exception("entity name too long")
+ if repl_size >= (1 << 3):
+ raise Exception("entity replacement too long")
+
+ main_table += [ text_idx | ent_size << 15 | repl_size << 20 ]
+
+ text_table += ent_bytes + repl_bytes
+ text_idx += ent_size + repl_size
+
+print("""/* Autogenerated by tools/make_headers_inc.py */
+
+#define ENT_MIN_LENGTH 2
+#define ENT_MAX_LENGTH 32
+#define ENT_TABLE_SIZE %d
+#define ENT_TEXT_IDX(x) ((x) & 0x7FFF)
+#define ENT_NAME_SIZE(x) (((x) >> 15) & 0x1F)
+#define ENT_REPL_SIZE(x) ((x) >> 20)
+
+static const uint32_t cmark_entities[%d] = {""" % (len(main_table), len(main_table)));
+
+i = 0
+size = len(main_table)
+for value in main_table:
+ if i % 6 == 0:
+ print(" ", end="")
+ print("0x%X" % value, end="")
+ i += 1
+ if i == size: print()
+ elif i % 6 == 0: print(",")
+ else: print(", ", end="")
+
+print("""};
+
+static const unsigned char cmark_entity_text[%d] = {""" % len(text_table))
+
+i = 0
+size = len(text_table)
+for value in text_table:
+ if i % 12 == 0:
+ print(" ", end="")
+ print("0x%02X" % value, end="")
+ i += 1
+ if i == size: print()
+ elif i % 12 == 0: print(",")
+ else: print(", ", end="")
+
+print("};")
diff --git a/cmark/tools/xml2md.xsl b/cmark/tools/xml2md.xsl
new file mode 100644
index 0000000000..0122e5f712
--- /dev/null
+++ b/cmark/tools/xml2md.xsl
@@ -0,0 +1,319 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+
+xml2md.xsl
+==========
+
+This XSLT stylesheet transforms the cmark XML format back to Commonmark.
+Since the XML output is lossy, a lossless MD->XML->MD roundtrip isn't
+possible. The XML->MD->XML roundtrip should produce the original XML,
+though.
+
+Example usage with xsltproc:
+
+ cmark -t xml doc.md | xsltproc -novalid xml2md.xsl -
+
+-->
+
+<xsl:stylesheet
+ version="1.0"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:md="http://commonmark.org/xml/1.0">
+
+<xsl:output method="text" encoding="utf-8"/>
+
+<!-- Generic templates -->
+
+<xsl:template match="/ | md:document | md:list">
+ <xsl:apply-templates select="md:*"/>
+</xsl:template>
+
+<xsl:template match="md:*">
+ <xsl:message>Unsupported element '<xsl:value-of select="local-name()"/>'</xsl:message>
+</xsl:template>
+
+<xsl:template match="md:*" mode="indent"/>
+
+<!-- Indent blocks -->
+
+<xsl:template match="md:*" mode="indent-block">
+ <xsl:if test="preceding-sibling::md:*">
+ <xsl:if test="not(ancestor::md:list[1][@tight='true'])">
+ <xsl:apply-templates select="ancestor::md:*" mode="indent"/>
+ <xsl:text>&#10;</xsl:text>
+ </xsl:if>
+ <xsl:apply-templates select="ancestor::md:*" mode="indent"/>
+ </xsl:if>
+</xsl:template>
+
+<!-- Heading -->
+
+<xsl:template match="md:heading">
+ <xsl:apply-templates select="." mode="indent-block"/>
+ <xsl:value-of select="substring('###### ', 7 - @level)"/>
+ <xsl:apply-templates select="md:*"/>
+ <xsl:text>&#10;</xsl:text>
+</xsl:template>
+
+<!-- Paragraph -->
+
+<xsl:template match="md:paragraph">
+ <xsl:apply-templates select="." mode="indent-block"/>
+ <xsl:apply-templates select="md:*"/>
+ <xsl:text>&#10;</xsl:text>
+</xsl:template>
+
+<!-- Thematic break -->
+
+<xsl:template match="md:thematic_break">
+ <xsl:apply-templates select="." mode="indent-block"/>
+ <xsl:text>***&#10;</xsl:text>
+</xsl:template>
+
+<!-- List -->
+
+<xsl:template match="md:list">
+ <xsl:apply-templates select="." mode="indent-block"/>
+ <xsl:apply-templates select="md:*"/>
+</xsl:template>
+
+<xsl:template match="md:item">
+ <xsl:apply-templates select="." mode="indent-block"/>
+ <xsl:choose>
+ <xsl:when test="../@type = 'bullet'">-</xsl:when>
+ <xsl:when test="../@type = 'ordered'">
+ <xsl:value-of select="../@start + position() - 1"/>
+ <xsl:choose>
+ <xsl:when test="../@delim = 'period'">.</xsl:when>
+ <xsl:when test="../@delim = 'paren'">)</xsl:when>
+ </xsl:choose>
+ </xsl:when>
+ </xsl:choose>
+ <xsl:text> </xsl:text>
+ <xsl:apply-templates select="md:*"/>
+</xsl:template>
+
+<xsl:template match="md:item" mode="indent">
+ <xsl:choose>
+ <xsl:when test="../@type = 'bullet'">
+ <xsl:text> </xsl:text>
+ </xsl:when>
+ <xsl:when test="../@type = 'ordered'">
+ <xsl:text> </xsl:text>
+ </xsl:when>
+ </xsl:choose>
+</xsl:template>
+
+<!-- Block quote -->
+
+<xsl:template match="md:block_quote">
+ <xsl:apply-templates select="." mode="indent-block"/>
+ <xsl:text>&gt; </xsl:text>
+ <xsl:apply-templates select="md:*"/>
+</xsl:template>
+
+<xsl:template match="md:block_quote" mode="indent">
+ <xsl:text>&gt; </xsl:text>
+</xsl:template>
+
+<!-- Code block -->
+
+<xsl:template match="md:code_block">
+ <xsl:apply-templates select="." mode="indent-block"/>
+
+ <xsl:variable name="t" select="string(.)"/>
+ <xsl:variable name="delim">
+ <xsl:call-template name="code-delim">
+ <xsl:with-param name="text" select="$t"/>
+ <xsl:with-param name="delim" select="'```'"/>
+ </xsl:call-template>
+ </xsl:variable>
+
+ <xsl:value-of select="$delim"/>
+ <xsl:value-of select="@info"/>
+ <xsl:text>&#10;</xsl:text>
+ <xsl:call-template name="indent-lines">
+ <xsl:with-param name="code" select="$t"/>
+ </xsl:call-template>
+ <xsl:apply-templates select="ancestor::md:*" mode="indent"/>
+ <xsl:value-of select="$delim"/>
+ <xsl:text>&#10;</xsl:text>
+</xsl:template>
+
+<!-- Inline HTML -->
+
+<xsl:template match="md:html_block">
+ <xsl:apply-templates select="." mode="indent-block"/>
+ <xsl:value-of select="substring-before(., '&#10;')"/>
+ <xsl:text>&#10;</xsl:text>
+ <xsl:call-template name="indent-lines">
+ <xsl:with-param name="code" select="substring-after(., '&#10;')"/>
+ </xsl:call-template>
+</xsl:template>
+
+<!-- Indent multiple lines -->
+
+<xsl:template name="indent-lines">
+ <xsl:param name="code"/>
+ <xsl:if test="contains($code, '&#10;')">
+ <xsl:apply-templates select="ancestor::md:*" mode="indent"/>
+ <xsl:value-of select="substring-before($code, '&#10;')"/>
+ <xsl:text>&#10;</xsl:text>
+ <xsl:call-template name="indent-lines">
+ <xsl:with-param name="code" select="substring-after($code, '&#10;')"/>
+ </xsl:call-template>
+ </xsl:if>
+</xsl:template>
+
+<!-- Text -->
+
+<xsl:template match="md:text">
+ <xsl:variable name="t" select="string(.)"/>
+ <xsl:variable name="first" select="substring($t, 1, 1)"/>
+ <xsl:variable name="marker-check" select="translate(substring($t, 1, 10), '0123456789', '')"/>
+ <xsl:choose>
+ <!-- Escape ordered list markers -->
+ <xsl:when test="starts-with($marker-check, '.') and $first != '.'">
+ <xsl:value-of select="substring-before($t, '.')"/>
+ <xsl:text>\.</xsl:text>
+ <xsl:call-template name="escape-text">
+ <xsl:with-param name="text" select="substring-after($t, '.')"/>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:when test="starts-with($marker-check, ')') and $first != ')'">
+ <xsl:value-of select="substring-before($t, ')')"/>
+ <xsl:text>\)</xsl:text>
+ <xsl:call-template name="escape-text">
+ <xsl:with-param name="text" select="substring-after($t, ')')"/>
+ </xsl:call-template>
+ </xsl:when>
+ <!-- Escape leading block characters -->
+ <xsl:when test="contains('-+>#=~', $first)">
+ <xsl:text>\</xsl:text>
+ <xsl:value-of select="$first"/>
+ <xsl:call-template name="escape-text">
+ <xsl:with-param name="text" select="substring($t, 2)"/>
+ </xsl:call-template>
+ </xsl:when>
+ <!-- Otherwise -->
+ <xsl:otherwise>
+ <xsl:call-template name="escape-text">
+ <xsl:with-param name="text" select="$t"/>
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<!-- Breaks -->
+
+<xsl:template match="md:softbreak">
+ <xsl:text>&#10;</xsl:text>
+ <xsl:apply-templates select="ancestor::md:*" mode="indent"/>
+</xsl:template>
+
+<xsl:template match="md:linebreak">
+ <xsl:text> &#10;</xsl:text>
+ <xsl:apply-templates select="ancestor::md:*" mode="indent"/>
+</xsl:template>
+
+<!-- Emphasis -->
+
+<xsl:template match="md:emph">
+ <xsl:text>*</xsl:text>
+ <xsl:apply-templates select="md:*"/>
+ <xsl:text>*</xsl:text>
+</xsl:template>
+
+<xsl:template match="md:strong">
+ <xsl:text>**</xsl:text>
+ <xsl:apply-templates select="md:*"/>
+ <xsl:text>**</xsl:text>
+</xsl:template>
+
+<!-- Inline code -->
+
+<xsl:template match="md:code">
+ <xsl:variable name="t" select="string(.)"/>
+ <xsl:variable name="delim">
+ <xsl:call-template name="code-delim">
+ <xsl:with-param name="text" select="$t"/>
+ <xsl:with-param name="delim" select="'`'"/>
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:value-of select="$delim"/>
+ <xsl:value-of select="$t"/>
+ <xsl:value-of select="$delim"/>
+</xsl:template>
+
+<!-- Links and images -->
+
+<xsl:template match="md:link | md:image">
+ <xsl:if test="self::md:image">!</xsl:if>
+ <xsl:text>[</xsl:text>
+ <xsl:apply-templates select="md:*"/>
+ <xsl:text>](</xsl:text>
+ <xsl:call-template name="escape-text">
+ <xsl:with-param name="text" select="string(@destination)"/>
+ <xsl:with-param name="escape" select="'()'"/>
+ </xsl:call-template>
+ <xsl:if test="string(@title)">
+ <xsl:text> "</xsl:text>
+ <xsl:call-template name="escape-text">
+ <xsl:with-param name="text" select="string(@title)"/>
+ <xsl:with-param name="escape" select="'&quot;'"/>
+ </xsl:call-template>
+ <xsl:text>"</xsl:text>
+ </xsl:if>
+ <xsl:text>)</xsl:text>
+</xsl:template>
+
+<!-- Inline HTML -->
+
+<xsl:template match="md:html_inline">
+ <xsl:value-of select="."/>
+</xsl:template>
+
+<!-- Escaping helpers -->
+
+<xsl:template name="escape-text">
+ <xsl:param name="text"/>
+ <xsl:param name="escape" select="'*_`&lt;[]&amp;'"/>
+
+ <xsl:variable name="trans" select="translate($text, $escape, '\\\\\\\')"/>
+ <xsl:choose>
+ <xsl:when test="contains($trans, '\')">
+ <xsl:variable name="safe" select="substring-before($trans, '\')"/>
+ <xsl:variable name="l" select="string-length($safe)"/>
+ <xsl:value-of select="$safe"/>
+ <xsl:text>\</xsl:text>
+ <xsl:value-of select="substring($text, $l + 1, 1)"/>
+ <xsl:call-template name="escape-text">
+ <xsl:with-param name="text" select="substring($text, $l + 2)"/>
+ <xsl:with-param name="escape" select="$escape"/>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$text"/>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<xsl:template name="code-delim">
+ <xsl:param name="text"/>
+ <xsl:param name="delim"/>
+
+ <xsl:choose>
+ <xsl:when test="contains($text, $delim)">
+ <xsl:call-template name="code-delim">
+ <xsl:with-param name="text" select="$text"/>
+ <xsl:with-param name="delim" select="concat($delim, '`')"/>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$delim"/>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/cmark/why-cmark-and-not-x.md b/cmark/why-cmark-and-not-x.md
new file mode 100644
index 0000000000..3fdb4e57a9
--- /dev/null
+++ b/cmark/why-cmark-and-not-x.md
@@ -0,0 +1,104 @@
+Why use `cmark` and not X?
+==========================
+
+`hoedown`
+---------
+
+`hoedown` (which derives from `sundown`) is slightly faster
+than `cmark` in our benchmarks (0.21s vs. 0.29s). But both
+are much faster than any other available implementations.
+
+`hoedown` boasts of including "protection against all possible
+DOS attacks," but there are some chinks in the armor:
+
+ % time python -c 'print(("[" * 50000) + "a" + ("]" * 50000))' | cmark
+ ...
+ user 0m0.073s
+ % time python -c 'print(("[" * 50000) + "a" + ("]" * 50000))' | hoedown
+ ...
+ 0m17.84s
+
+`hoedown` has many parsing bugs. Here is a selection (as of
+v3.0.3):
+
+ % hoedown
+ - one
+ - two
+ 1. three
+ ^D
+ <ul>
+ <li>one
+
+ <ul>
+ <li>two</li>
+ <li>three</li>
+ </ul></li>
+ </ul>
+
+
+ % hoedown
+ ## hi\###
+ ^D
+ <h2>hi\</h2>
+
+
+ % hoedown
+ [ΑΓΩ]: /φου
+
+ [αγω]
+ ^D
+ <p>[αγω]</p>
+
+
+ % hoedown
+ ```
+ [foo]: /url
+ ```
+
+ [foo]
+ ^D
+ <p>```</p>
+
+ <p>```</p>
+
+ <p><a href="/url">foo</a></p>
+
+
+ % hoedown
+ [foo](url "ti\*tle")
+ ^D
+ <p><a href="url" title="ti\*tle">foo</a></p>
+
+
+ % ./hoedown
+ - one
+ - two
+ - three
+ - four
+ ^D
+ <ul>
+ <li>one
+
+ <ul>
+ <li>two</li>
+ <li>three</li>
+ <li>four</li>
+ </ul></li>
+ </ul>
+
+
+`discount`
+----------
+
+`cmark` is about six times faster.
+
+`kramdown`
+----------
+
+`cmark` is about a hundred times faster.
+
+`kramdown` also gets tied in knots by pathological input like
+
+ python -c 'print(("[" * 50000) + "a" + ("]" * 50000))'
+
+
diff --git a/cmark/wrappers/wrapper.php b/cmark/wrappers/wrapper.php
new file mode 100644
index 0000000000..4b68e2dc6a
--- /dev/null
+++ b/cmark/wrappers/wrapper.php
@@ -0,0 +1,26 @@
+<?php
+
+function markdownToHtml(string $markdown): string
+{
+ $ffi = FFI::cdef(
+ 'char *cmark_markdown_to_html(const char *text, size_t len, int options);',
+ 'libcmark.so'
+ );
+
+ $pointerReturn = $ffi->cmark_markdown_to_html($markdown, strlen($markdown), 0);
+ $html = FFI::string($pointerReturn);
+ FFI::free($pointerReturn);
+
+ return $html;
+}
+
+$markdown = <<<'md'
+# First level title
+
+## Second level title
+
+Paragraph
+
+md;
+
+echo markdownToHtml($markdown) . PHP_EOL;
diff --git a/cmark/wrappers/wrapper.py b/cmark/wrappers/wrapper.py
new file mode 100755
index 0000000000..be9d79e9b7
--- /dev/null
+++ b/cmark/wrappers/wrapper.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+
+# Example for using the shared library from python
+# Will work with either python 2 or python 3
+# Requires cmark library to be installed
+
+from ctypes import *
+import sys
+import platform
+
+sysname = platform.system()
+
+if sysname == 'Darwin':
+ libname = "libcmark.dylib"
+elif sysname == 'Windows':
+ libname = "cmark.dll"
+else:
+ libname = "libcmark.so"
+cmark = CDLL(libname)
+
+class cmark_mem(Structure):
+ _fields_ = [("calloc", c_void_p),
+ ("realloc", c_void_p),
+ ("free", CFUNCTYPE(None, c_void_p))]
+
+get_alloc = cmark.cmark_get_default_mem_allocator
+get_alloc.restype = POINTER(cmark_mem)
+free_func = get_alloc().contents.free
+
+markdown = cmark.cmark_markdown_to_html
+markdown.restype = POINTER(c_char)
+markdown.argtypes = [c_char_p, c_size_t, c_int]
+
+opts = 0 # defaults
+
+def md2html(text):
+ text = text.encode('utf-8')
+ cstring = markdown(text, len(text), opts)
+ result = string_at(cstring).decode('utf-8')
+ free_func(cstring)
+ return result
+
+sys.stdout.write(md2html(sys.stdin.read()))
diff --git a/cmark/wrappers/wrapper.rb b/cmark/wrappers/wrapper.rb
new file mode 100755
index 0000000000..597e234749
--- /dev/null
+++ b/cmark/wrappers/wrapper.rb
@@ -0,0 +1,27 @@
+#!/usr/bin/env ruby
+require 'ffi'
+
+module CMark
+ extend FFI::Library
+
+ class Mem < FFI::Struct
+ layout :calloc, :pointer,
+ :realloc, :pointer,
+ :free, callback([:pointer], :void)
+ end
+
+ ffi_lib ['libcmark', 'cmark']
+ attach_function :cmark_get_default_mem_allocator, [], :pointer
+ attach_function :cmark_markdown_to_html, [:string, :size_t, :int], :pointer
+end
+
+def markdown_to_html(s)
+ len = s.bytesize
+ cstring = CMark::cmark_markdown_to_html(s, len, 0)
+ result = cstring.get_string(0)
+ mem = CMark::cmark_get_default_mem_allocator
+ CMark::Mem.new(mem)[:free].call(cstring)
+ result
+end
+
+STDOUT.write(markdown_to_html(ARGF.read()))
diff --git a/cmark/wrappers/wrapper.rkt b/cmark/wrappers/wrapper.rkt
new file mode 100644
index 0000000000..776adb4add
--- /dev/null
+++ b/cmark/wrappers/wrapper.rkt
@@ -0,0 +1,210 @@
+#lang racket/base
+
+;; requires racket >= 5.3 because of submodules
+
+;; Lowlevel interface
+
+(module low-level racket/base
+
+ (require ffi/unsafe ffi/unsafe/define)
+
+ (provide (all-defined-out))
+
+ (define-ffi-definer defcmark (ffi-lib "libcmark"))
+
+ (define _cmark_node_type
+ (_enum '(;; Error status
+ none
+ ;; Block
+ document block-quote list item code-block
+ html-block custom-block
+ paragraph heading thematic-break
+ ;; ?? first-block = document
+ ;; ?? last-block = thematic-break
+ ;; Inline
+ text softbreak linebreak code html-inline custom-inline
+ emph strong link image
+ ;; ?? first-inline = text
+ ;; ?? last-inline = image
+ )))
+ (define _cmark_list_type
+ (_enum '(no_list bullet_list ordered_list)))
+ (define _cmark_delim_type
+ (_enum '(no_delim period_delim paren_delim)))
+ (define _cmark_opts
+ (let ([opts '([sourcepos 1] ; include sourcepos attribute on block elements
+ [hardbreaks 2] ; render `softbreak` elements as hard line breaks
+ [safe 3] ; defined here for API compatibility (on by default)
+ [unsafe 17] ; render raw HTML and unsafe links
+ [nobreaks 4] ; render `softbreak` elements as spaces
+ [normalize 8] ; legacy (no effect)
+ [validate-utf8 9] ; validate UTF-8 in the input
+ [smart 10] ; straight quotes to curly, ---/-- to em/en dashes
+ )])
+ (_bitmask (apply append (map (λ(o) `(,(car o) = ,(expt 2 (cadr o))))
+ opts)))))
+
+ (define-cpointer-type _node)
+
+ (defcmark cmark_markdown_to_html
+ (_fun [bs : _bytes] [_int = (bytes-length bs)] _cmark_opts
+ -> [r : _bytes] -> (begin0 (bytes->string/utf-8 r) (free r))))
+
+ (defcmark cmark_parse_document
+ (_fun [bs : _bytes] [_int = (bytes-length bs)] _cmark_opts
+ -> _node))
+
+ (defcmark cmark_render_html
+ (_fun _node _cmark_opts
+ -> [r : _bytes] -> (begin0 (bytes->string/utf-8 r) (free r))))
+
+ (defcmark cmark_node_new (_fun _cmark_node_type -> _node))
+ (defcmark cmark_node_free (_fun _node -> _void))
+
+ (defcmark cmark_node_next (_fun _node -> _node/null))
+ (defcmark cmark_node_previous (_fun _node -> _node/null))
+ (defcmark cmark_node_parent (_fun _node -> _node/null))
+ (defcmark cmark_node_first_child (_fun _node -> _node/null))
+ (defcmark cmark_node_last_child (_fun _node -> _node/null))
+
+ (defcmark cmark_node_get_user_data (_fun _node -> _racket))
+ (defcmark cmark_node_set_user_data (_fun _node _racket -> _bool))
+ (defcmark cmark_node_get_type (_fun _node -> _cmark_node_type))
+ (defcmark cmark_node_get_type_string (_fun _node -> _bytes))
+ (defcmark cmark_node_get_literal (_fun _node -> _string))
+ (defcmark cmark_node_set_literal (_fun _node _string -> _bool))
+ (defcmark cmark_node_get_heading_level (_fun _node -> _int))
+ (defcmark cmark_node_set_heading_level (_fun _node _int -> _bool))
+ (defcmark cmark_node_get_list_type (_fun _node -> _cmark_list_type))
+ (defcmark cmark_node_set_list_type (_fun _node _cmark_list_type -> _bool))
+ (defcmark cmark_node_get_list_delim (_fun _node -> _cmark_delim_type))
+ (defcmark cmark_node_set_list_delim (_fun _node _cmark_delim_type -> _bool))
+ (defcmark cmark_node_get_list_start (_fun _node -> _int))
+ (defcmark cmark_node_set_list_start (_fun _node _int -> _bool))
+ (defcmark cmark_node_get_list_tight (_fun _node -> _bool))
+ (defcmark cmark_node_set_list_tight (_fun _node _bool -> _bool))
+ (defcmark cmark_node_get_fence_info (_fun _node -> _string))
+ (defcmark cmark_node_set_fence_info (_fun _node _string -> _bool))
+ (defcmark cmark_node_get_url (_fun _node -> _string))
+ (defcmark cmark_node_set_url (_fun _node _string -> _bool))
+ (defcmark cmark_node_get_title (_fun _node -> _string))
+ (defcmark cmark_node_set_title (_fun _node _string -> _bool))
+ (defcmark cmark_node_get_start_line (_fun _node -> _int))
+ (defcmark cmark_node_get_start_column (_fun _node -> _int))
+ (defcmark cmark_node_get_end_line (_fun _node -> _int))
+ (defcmark cmark_node_get_end_column (_fun _node -> _int))
+
+ (defcmark cmark_node_unlink (_fun _node -> _void))
+ (defcmark cmark_node_insert_before (_fun _node _node -> _bool))
+ (defcmark cmark_node_insert_after (_fun _node _node -> _bool))
+ (defcmark cmark_node_prepend_child (_fun _node _node -> _bool))
+ (defcmark cmark_node_append_child (_fun _node _node -> _bool))
+ (defcmark cmark_consolidate_text_nodes (_fun _node -> _void))
+
+ (defcmark cmark_version (_fun -> _int))
+ (defcmark cmark_version_string (_fun -> _string))
+
+ )
+
+;; Rackety interface
+
+(module high-level racket/base
+
+ (require (submod ".." low-level) ffi/unsafe)
+
+ (provide cmark-markdown-to-html)
+ (define (cmark-markdown-to-html str [options '(normalize smart)])
+ (cmark_markdown_to_html (if (bytes? str) str (string->bytes/utf-8 str))
+ options))
+
+ (require (for-syntax racket/base racket/syntax))
+ (define-syntax (make-getter+setter stx)
+ (syntax-case stx ()
+ [(_ name) (with-syntax ([(getter setter)
+ (map (λ(op) (format-id #'name "cmark_node_~a_~a"
+ op #'name))
+ '(get set))])
+ #'(cons getter setter))]))
+ (define-syntax-rule (define-getters+setters name [type field ...] ...)
+ (define name (list (list 'type (make-getter+setter field) ...) ...)))
+ (define-getters+setters getters+setters
+ [heading heading_level] [code-block fence_info]
+ [link url title] [image url title]
+ [list list_type list_delim list_start list_tight])
+
+ (provide cmark->sexpr)
+ (define (cmark->sexpr node)
+ (define text (cmark_node_get_literal node))
+ (define type (cmark_node_get_type node))
+ (define children
+ (let loop ([node (cmark_node_first_child node)])
+ (if (not node) '()
+ (cons (cmark->sexpr node) (loop (cmark_node_next node))))))
+ (define info
+ (cond [(assq type getters+setters)
+ => (λ(gss) (map (λ(gs) ((car gs) node)) (cdr gss)))]
+ [else '()]))
+ (define (assert-no what-not b)
+ (when b (error 'cmark->sexpr "unexpected ~a in ~s" what-not type)))
+ (cond [(memq type '(document paragraph heading block-quote list item
+ emph strong link image))
+ (assert-no 'text text)
+ (list type info children)]
+ [(memq type '(text code code-block html-block html-inline
+ softbreak linebreak thematic-break))
+ (assert-no 'children (pair? children))
+ (list type info text)]
+ [else (error 'cmark->sexpr "unknown type: ~s" type)]))
+
+ (provide sexpr->cmark)
+ (define (sexpr->cmark sexpr) ; assumes valid input, as generated by the above
+ (define (loop sexpr)
+ (define type (car sexpr))
+ (define info (cadr sexpr))
+ (define data (caddr sexpr))
+ (define node (cmark_node_new type))
+ (let ([gss (assq type getters+setters)])
+ (when gss
+ (unless (= (length (cdr gss)) (length info))
+ (error 'sexpr->cmark "bad number of info values in ~s" sexpr))
+ (for-each (λ(gs x) ((cdr gs) node x)) (cdr gss) info)))
+ (cond [(string? data) (cmark_node_set_literal node data)]
+ [(not data) (void)]
+ [(list? data)
+ (for ([child (in-list data)])
+ (cmark_node_append_child node (sexpr->cmark child)))]
+ [else (error 'sexpr->cmark "bad data in ~s" sexpr)])
+ node)
+ (define root (loop sexpr))
+ (register-finalizer root cmark_node_free)
+ root)
+
+ ;; Registers a `cmark_node_free` finalizer
+ (provide cmark-parse-document)
+ (define (cmark-parse-document str [options '(normalize smart)])
+ (define root (cmark_parse_document
+ (if (bytes? str) str (string->bytes/utf-8 str))
+ options))
+ (register-finalizer root cmark_node_free)
+ root)
+
+ (provide cmark-render-html)
+ (define (cmark-render-html root [options '(normalize smart)])
+ (cmark_render_html root options)))
+
+#; ;; sample use
+(begin
+ (require 'high-level racket/string)
+ (cmark-render-html
+ (cmark-parse-document
+ (string-join '("foo"
+ "==="
+ ""
+ "> blah"
+ ">"
+ "> blah *blah* `bar()` blah:"
+ ">"
+ "> function foo() {"
+ "> bar();"
+ "> }")
+ "\n"))))